blob: ead3911e28db9a669e82da3c17e27d7245986281 [file] [log] [blame]
Andreas Färberc7a59be2014-02-09 04:32:55 +01001/*
2 * QTest testcase for VirtIO Block Device
3 *
4 * Copyright (c) 2014 SUSE LINUX Products GmbH
Marc Marí311e6662014-09-01 12:07:54 +02005 * Copyright (c) 2014 Marc Marí
Andreas Färberc7a59be2014-02-09 04:32:55 +01006 *
7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 * See the COPYING file in the top-level directory.
9 */
10
11#include <glib.h>
12#include <string.h>
Marc Marí311e6662014-09-01 12:07:54 +020013#include <stdlib.h>
14#include <unistd.h>
15#include <stdio.h>
Andreas Färberc7a59be2014-02-09 04:32:55 +010016#include "libqtest.h"
Marc Marí311e6662014-09-01 12:07:54 +020017#include "libqos/virtio.h"
18#include "libqos/virtio-pci.h"
19#include "libqos/pci-pc.h"
Marc Maríbf3c63d2014-09-01 12:07:56 +020020#include "libqos/malloc.h"
21#include "libqos/malloc-pc.h"
22#include "qemu/bswap.h"
Andreas Färberc7a59be2014-02-09 04:32:55 +010023
Marc Maríbf3c63d2014-09-01 12:07:56 +020024#define QVIRTIO_BLK_F_BARRIER 0x00000001
25#define QVIRTIO_BLK_F_SIZE_MAX 0x00000002
26#define QVIRTIO_BLK_F_SEG_MAX 0x00000004
27#define QVIRTIO_BLK_F_GEOMETRY 0x00000010
28#define QVIRTIO_BLK_F_RO 0x00000020
29#define QVIRTIO_BLK_F_BLK_SIZE 0x00000040
30#define QVIRTIO_BLK_F_SCSI 0x00000080
31#define QVIRTIO_BLK_F_WCE 0x00000200
32#define QVIRTIO_BLK_F_TOPOLOGY 0x00000400
33#define QVIRTIO_BLK_F_CONFIG_WCE 0x00000800
34
35#define QVIRTIO_BLK_T_IN 0
36#define QVIRTIO_BLK_T_OUT 1
37#define QVIRTIO_BLK_T_SCSI_CMD 2
38#define QVIRTIO_BLK_T_SCSI_CMD_OUT 3
39#define QVIRTIO_BLK_T_FLUSH 4
40#define QVIRTIO_BLK_T_FLUSH_OUT 5
41#define QVIRTIO_BLK_T_GET_ID 8
42
43#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
Stefan Hajnoczie8c81b42014-09-29 16:40:11 +010044#define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
Marc Maríbf3c63d2014-09-01 12:07:56 +020045#define PCI_SLOT 0x04
46#define PCI_FN 0x00
47
Igor Mammedovaaf36072014-09-26 09:28:11 +000048#define PCI_SLOT_HP 0x06
49
Marc Maríbf3c63d2014-09-01 12:07:56 +020050typedef struct QVirtioBlkReq {
51 uint32_t type;
52 uint32_t ioprio;
53 uint64_t sector;
54 char *data;
55 uint8_t status;
56} QVirtioBlkReq;
Marc Marí311e6662014-09-01 12:07:54 +020057
58static QPCIBus *test_start(void)
Andreas Färberc7a59be2014-02-09 04:32:55 +010059{
Igor Mammedovaaf36072014-09-26 09:28:11 +000060 char *cmdline;
Marc Marí311e6662014-09-01 12:07:54 +020061 char tmp_path[] = "/tmp/qtest.XXXXXX";
62 int fd, ret;
63
64 /* Create a temporary raw image */
65 fd = mkstemp(tmp_path);
66 g_assert_cmpint(fd, >=, 0);
67 ret = ftruncate(fd, TEST_IMAGE_SIZE);
68 g_assert_cmpint(ret, ==, 0);
69 close(fd);
70
Igor Mammedovaaf36072014-09-26 09:28:11 +000071 cmdline = g_strdup_printf("-drive if=none,id=drive0,file=%s "
72 "-drive if=none,id=drive1,file=/dev/null "
73 "-device virtio-blk-pci,id=drv0,drive=drive0,"
74 "addr=%x.%x",
75 tmp_path, PCI_SLOT, PCI_FN);
Marc Marí311e6662014-09-01 12:07:54 +020076 qtest_start(cmdline);
77 unlink(tmp_path);
Igor Mammedovaaf36072014-09-26 09:28:11 +000078 g_free(cmdline);
Marc Marí311e6662014-09-01 12:07:54 +020079
80 return qpci_init_pc();
81}
82
83static void test_end(void)
84{
85 qtest_end();
86}
87
Igor Mammedovaaf36072014-09-26 09:28:11 +000088static QVirtioPCIDevice *virtio_blk_init(QPCIBus *bus, int slot)
Marc Marí311e6662014-09-01 12:07:54 +020089{
90 QVirtioPCIDevice *dev;
Marc Marí311e6662014-09-01 12:07:54 +020091
92 dev = qvirtio_pci_device_find(bus, QVIRTIO_BLK_DEVICE_ID);
93 g_assert(dev != NULL);
94 g_assert_cmphex(dev->vdev.device_type, ==, QVIRTIO_BLK_DEVICE_ID);
Igor Mammedovaaf36072014-09-26 09:28:11 +000095 g_assert_cmphex(dev->pdev->devfn, ==, ((slot << 3) | PCI_FN));
Marc Marí311e6662014-09-01 12:07:54 +020096
Marc Marí46e0cf72014-09-01 12:07:55 +020097 qvirtio_pci_device_enable(dev);
98 qvirtio_reset(&qvirtio_pci, &dev->vdev);
99 qvirtio_set_acknowledge(&qvirtio_pci, &dev->vdev);
100 qvirtio_set_driver(&qvirtio_pci, &dev->vdev);
101
102 return dev;
103}
104
Marc Maríbf3c63d2014-09-01 12:07:56 +0200105static inline void virtio_blk_fix_request(QVirtioBlkReq *req)
106{
107#ifdef HOST_WORDS_BIGENDIAN
108 bool host_endian = true;
109#else
110 bool host_endian = false;
111#endif
112
113 if (qtest_big_endian() != host_endian) {
114 req->type = bswap32(req->type);
115 req->ioprio = bswap32(req->ioprio);
116 req->sector = bswap64(req->sector);
117 }
118}
119
120static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioBlkReq *req,
121 uint64_t data_size)
122{
123 uint64_t addr;
124 uint8_t status = 0xFF;
125
126 g_assert_cmpuint(data_size % 512, ==, 0);
127 addr = guest_alloc(alloc, sizeof(*req) + data_size);
128
129 virtio_blk_fix_request(req);
130
131 memwrite(addr, req, 16);
132 memwrite(addr + 16, req->data, data_size);
133 memwrite(addr + 16 + data_size, &status, sizeof(status));
134
135 return addr;
136}
137
Marc Marí46e0cf72014-09-01 12:07:55 +0200138static void pci_basic(void)
139{
140 QVirtioPCIDevice *dev;
141 QPCIBus *bus;
Marc Marí58368112014-09-01 12:07:59 +0200142 QVirtQueuePCI *vqpci;
Marc Maríbf3c63d2014-09-01 12:07:56 +0200143 QGuestAllocator *alloc;
144 QVirtioBlkReq req;
Marc Marí46e0cf72014-09-01 12:07:55 +0200145 void *addr;
Marc Maríbf3c63d2014-09-01 12:07:56 +0200146 uint64_t req_addr;
Marc Marí46e0cf72014-09-01 12:07:55 +0200147 uint64_t capacity;
Marc Maríbf3c63d2014-09-01 12:07:56 +0200148 uint32_t features;
149 uint32_t free_head;
150 uint8_t status;
151 char *data;
Marc Marí46e0cf72014-09-01 12:07:55 +0200152
153 bus = test_start();
154
Igor Mammedovaaf36072014-09-26 09:28:11 +0000155 dev = virtio_blk_init(bus, PCI_SLOT);
Marc Marí46e0cf72014-09-01 12:07:55 +0200156
157 /* MSI-X is not enabled */
158 addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX;
159
160 capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
161 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
162
Marc Maríbf3c63d2014-09-01 12:07:56 +0200163 features = qvirtio_get_features(&qvirtio_pci, &dev->vdev);
164 features = features & ~(QVIRTIO_F_BAD_FEATURE |
165 QVIRTIO_F_RING_INDIRECT_DESC | QVIRTIO_F_RING_EVENT_IDX |
166 QVIRTIO_BLK_F_SCSI);
167 qvirtio_set_features(&qvirtio_pci, &dev->vdev, features);
168
169 alloc = pc_alloc_init();
Marc Marí58368112014-09-01 12:07:59 +0200170 vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&qvirtio_pci, &dev->vdev,
171 alloc, 0);
Marc Maríbf3c63d2014-09-01 12:07:56 +0200172
173 qvirtio_set_driver_ok(&qvirtio_pci, &dev->vdev);
174
175 /* Write and read with 2 descriptor layout */
176 /* Write request */
177 req.type = QVIRTIO_BLK_T_OUT;
178 req.ioprio = 1;
179 req.sector = 0;
180 req.data = g_malloc0(512);
181 strcpy(req.data, "TEST");
182
183 req_addr = virtio_blk_request(alloc, &req, 512);
184
185 g_free(req.data);
186
Marc Marí58368112014-09-01 12:07:59 +0200187 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 528, false, true);
188 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
189 qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
Marc Maríbf3c63d2014-09-01 12:07:56 +0200190
Stefan Hajnoczi70556262014-09-29 16:40:12 +0100191 qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
192 QVIRTIO_BLK_TIMEOUT_US);
Marc Maríbf3c63d2014-09-01 12:07:56 +0200193 status = readb(req_addr + 528);
194 g_assert_cmpint(status, ==, 0);
195
196 guest_free(alloc, req_addr);
197
198 /* Read request */
199 req.type = QVIRTIO_BLK_T_IN;
200 req.ioprio = 1;
201 req.sector = 0;
202 req.data = g_malloc0(512);
203
204 req_addr = virtio_blk_request(alloc, &req, 512);
205
206 g_free(req.data);
207
Marc Marí58368112014-09-01 12:07:59 +0200208 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
209 qvirtqueue_add(&vqpci->vq, req_addr + 16, 513, true, false);
Marc Maríbf3c63d2014-09-01 12:07:56 +0200210
Marc Marí58368112014-09-01 12:07:59 +0200211 qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
Marc Maríbf3c63d2014-09-01 12:07:56 +0200212
Stefan Hajnoczi70556262014-09-29 16:40:12 +0100213 qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
214 QVIRTIO_BLK_TIMEOUT_US);
Marc Maríbf3c63d2014-09-01 12:07:56 +0200215 status = readb(req_addr + 528);
216 g_assert_cmpint(status, ==, 0);
217
218 data = g_malloc0(512);
219 memread(req_addr + 16, data, 512);
220 g_assert_cmpstr(data, ==, "TEST");
221 g_free(data);
222
223 guest_free(alloc, req_addr);
224
225 /* Write and read with 3 descriptor layout */
226 /* Write request */
227 req.type = QVIRTIO_BLK_T_OUT;
228 req.ioprio = 1;
229 req.sector = 1;
230 req.data = g_malloc0(512);
231 strcpy(req.data, "TEST");
232
233 req_addr = virtio_blk_request(alloc, &req, 512);
234
Marc Marí58368112014-09-01 12:07:59 +0200235 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
236 qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
237 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
Marc Maríbf3c63d2014-09-01 12:07:56 +0200238
Marc Marí58368112014-09-01 12:07:59 +0200239 qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
Marc Maríbf3c63d2014-09-01 12:07:56 +0200240
Stefan Hajnoczi70556262014-09-29 16:40:12 +0100241 qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
242 QVIRTIO_BLK_TIMEOUT_US);
Marc Maríbf3c63d2014-09-01 12:07:56 +0200243 status = readb(req_addr + 528);
244 g_assert_cmpint(status, ==, 0);
245
246 guest_free(alloc, req_addr);
247
248 /* Read request */
249 req.type = QVIRTIO_BLK_T_IN;
250 req.ioprio = 1;
251 req.sector = 1;
252 req.data = g_malloc0(512);
253
254 req_addr = virtio_blk_request(alloc, &req, 512);
255
256 g_free(req.data);
257
Marc Marí58368112014-09-01 12:07:59 +0200258 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
259 qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, true, true);
260 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
Marc Maríbf3c63d2014-09-01 12:07:56 +0200261
Marc Marí58368112014-09-01 12:07:59 +0200262 qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
Marc Maríbf3c63d2014-09-01 12:07:56 +0200263
Stefan Hajnoczi70556262014-09-29 16:40:12 +0100264 qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
265 QVIRTIO_BLK_TIMEOUT_US);
Marc Maríbf3c63d2014-09-01 12:07:56 +0200266 status = readb(req_addr + 528);
267 g_assert_cmpint(status, ==, 0);
268
Marc Maríbf3c63d2014-09-01 12:07:56 +0200269 data = g_malloc0(512);
270 memread(req_addr + 16, data, 512);
271 g_assert_cmpstr(data, ==, "TEST");
272 g_free(data);
273
274 guest_free(alloc, req_addr);
275
276 /* End test */
Marc Marí58368112014-09-01 12:07:59 +0200277 guest_free(alloc, vqpci->vq.desc);
Marc Marí46e0cf72014-09-01 12:07:55 +0200278 qvirtio_pci_device_disable(dev);
Marc Marí311e6662014-09-01 12:07:54 +0200279 g_free(dev);
280 test_end();
Andreas Färberc7a59be2014-02-09 04:32:55 +0100281}
282
Marc Maríf294b022014-09-01 12:07:57 +0200283static void pci_indirect(void)
284{
285 QVirtioPCIDevice *dev;
286 QPCIBus *bus;
Marc Marí58368112014-09-01 12:07:59 +0200287 QVirtQueuePCI *vqpci;
Marc Maríf294b022014-09-01 12:07:57 +0200288 QGuestAllocator *alloc;
289 QVirtioBlkReq req;
290 QVRingIndirectDesc *indirect;
291 void *addr;
292 uint64_t req_addr;
293 uint64_t capacity;
294 uint32_t features;
295 uint32_t free_head;
296 uint8_t status;
297 char *data;
298
299 bus = test_start();
300
Igor Mammedovaaf36072014-09-26 09:28:11 +0000301 dev = virtio_blk_init(bus, PCI_SLOT);
Marc Maríf294b022014-09-01 12:07:57 +0200302
303 /* MSI-X is not enabled */
304 addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX;
305
306 capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
307 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
308
309 features = qvirtio_get_features(&qvirtio_pci, &dev->vdev);
310 g_assert_cmphex(features & QVIRTIO_F_RING_INDIRECT_DESC, !=, 0);
311 features = features & ~(QVIRTIO_F_BAD_FEATURE | QVIRTIO_F_RING_EVENT_IDX |
312 QVIRTIO_BLK_F_SCSI);
313 qvirtio_set_features(&qvirtio_pci, &dev->vdev, features);
314
315 alloc = pc_alloc_init();
Marc Marí58368112014-09-01 12:07:59 +0200316 vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&qvirtio_pci, &dev->vdev,
317 alloc, 0);
Marc Maríf294b022014-09-01 12:07:57 +0200318 qvirtio_set_driver_ok(&qvirtio_pci, &dev->vdev);
319
320 /* Write request */
321 req.type = QVIRTIO_BLK_T_OUT;
322 req.ioprio = 1;
323 req.sector = 0;
324 req.data = g_malloc0(512);
325 strcpy(req.data, "TEST");
326
327 req_addr = virtio_blk_request(alloc, &req, 512);
328
329 g_free(req.data);
330
331 indirect = qvring_indirect_desc_setup(&dev->vdev, alloc, 2);
332 qvring_indirect_desc_add(indirect, req_addr, 528, false);
333 qvring_indirect_desc_add(indirect, req_addr + 528, 1, true);
Marc Marí58368112014-09-01 12:07:59 +0200334 free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
335 qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
Marc Maríf294b022014-09-01 12:07:57 +0200336
Stefan Hajnoczi70556262014-09-29 16:40:12 +0100337 qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
338 QVIRTIO_BLK_TIMEOUT_US);
Marc Maríf294b022014-09-01 12:07:57 +0200339 status = readb(req_addr + 528);
340 g_assert_cmpint(status, ==, 0);
341
342 g_free(indirect);
343 guest_free(alloc, req_addr);
344
345 /* Read request */
346 req.type = QVIRTIO_BLK_T_IN;
347 req.ioprio = 1;
348 req.sector = 0;
349 req.data = g_malloc0(512);
350 strcpy(req.data, "TEST");
351
352 req_addr = virtio_blk_request(alloc, &req, 512);
353
354 g_free(req.data);
355
356 indirect = qvring_indirect_desc_setup(&dev->vdev, alloc, 2);
357 qvring_indirect_desc_add(indirect, req_addr, 16, false);
358 qvring_indirect_desc_add(indirect, req_addr + 16, 513, true);
Marc Marí58368112014-09-01 12:07:59 +0200359 free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
360 qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
Marc Maríf294b022014-09-01 12:07:57 +0200361
Stefan Hajnoczi70556262014-09-29 16:40:12 +0100362 qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
363 QVIRTIO_BLK_TIMEOUT_US);
Marc Maríf294b022014-09-01 12:07:57 +0200364 status = readb(req_addr + 528);
365 g_assert_cmpint(status, ==, 0);
366
367 data = g_malloc0(512);
368 memread(req_addr + 16, data, 512);
369 g_assert_cmpstr(data, ==, "TEST");
370 g_free(data);
371
372 g_free(indirect);
373 guest_free(alloc, req_addr);
374
375 /* End test */
Marc Marí58368112014-09-01 12:07:59 +0200376 guest_free(alloc, vqpci->vq.desc);
Marc Maríf294b022014-09-01 12:07:57 +0200377 qvirtio_pci_device_disable(dev);
378 g_free(dev);
379 test_end();
380}
381
Marc Maríe1119952014-09-01 12:07:58 +0200382static void pci_config(void)
383{
384 QVirtioPCIDevice *dev;
385 QPCIBus *bus;
386 int n_size = TEST_IMAGE_SIZE / 2;
387 void *addr;
388 uint64_t capacity;
389
390 bus = test_start();
391
Igor Mammedovaaf36072014-09-26 09:28:11 +0000392 dev = virtio_blk_init(bus, PCI_SLOT);
Marc Maríe1119952014-09-01 12:07:58 +0200393
394 /* MSI-X is not enabled */
395 addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX;
396
397 capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
398 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
399
400 qvirtio_set_driver_ok(&qvirtio_pci, &dev->vdev);
401
402 qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
403 " 'size': %d } }", n_size);
Stefan Hajnoczi70556262014-09-29 16:40:12 +0100404 qvirtio_wait_config_isr(&qvirtio_pci, &dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
Marc Maríe1119952014-09-01 12:07:58 +0200405
406 capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
407 g_assert_cmpint(capacity, ==, n_size / 512);
408
409 qvirtio_pci_device_disable(dev);
410 g_free(dev);
411 test_end();
412}
413
Marc Marí58368112014-09-01 12:07:59 +0200414static void pci_msix(void)
415{
416 QVirtioPCIDevice *dev;
417 QPCIBus *bus;
418 QVirtQueuePCI *vqpci;
419 QGuestAllocator *alloc;
420 QVirtioBlkReq req;
421 int n_size = TEST_IMAGE_SIZE / 2;
422 void *addr;
423 uint64_t req_addr;
424 uint64_t capacity;
425 uint32_t features;
426 uint32_t free_head;
427 uint8_t status;
428 char *data;
429
430 bus = test_start();
431 alloc = pc_alloc_init();
432
Igor Mammedovaaf36072014-09-26 09:28:11 +0000433 dev = virtio_blk_init(bus, PCI_SLOT);
Marc Marí58368112014-09-01 12:07:59 +0200434 qpci_msix_enable(dev->pdev);
435
436 qvirtio_pci_set_msix_configuration_vector(dev, alloc, 0);
437
438 /* MSI-X is enabled */
439 addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_MSIX;
440
441 capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
442 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
443
444 features = qvirtio_get_features(&qvirtio_pci, &dev->vdev);
445 features = features & ~(QVIRTIO_F_BAD_FEATURE |
446 QVIRTIO_F_RING_INDIRECT_DESC |
447 QVIRTIO_F_RING_EVENT_IDX | QVIRTIO_BLK_F_SCSI);
448 qvirtio_set_features(&qvirtio_pci, &dev->vdev, features);
449
450 vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&qvirtio_pci, &dev->vdev,
451 alloc, 0);
452 qvirtqueue_pci_msix_setup(dev, vqpci, alloc, 1);
453
454 qvirtio_set_driver_ok(&qvirtio_pci, &dev->vdev);
455
456 qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
457 " 'size': %d } }", n_size);
458
Stefan Hajnoczi70556262014-09-29 16:40:12 +0100459 qvirtio_wait_config_isr(&qvirtio_pci, &dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
Marc Marí58368112014-09-01 12:07:59 +0200460
461 capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
462 g_assert_cmpint(capacity, ==, n_size / 512);
463
464 /* Write request */
465 req.type = QVIRTIO_BLK_T_OUT;
466 req.ioprio = 1;
467 req.sector = 0;
468 req.data = g_malloc0(512);
469 strcpy(req.data, "TEST");
470
471 req_addr = virtio_blk_request(alloc, &req, 512);
472
473 g_free(req.data);
474
475 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 528, false, true);
476 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
477 qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
478
Stefan Hajnoczi70556262014-09-29 16:40:12 +0100479 qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
480 QVIRTIO_BLK_TIMEOUT_US);
Marc Marí58368112014-09-01 12:07:59 +0200481
482 status = readb(req_addr + 528);
483 g_assert_cmpint(status, ==, 0);
484
485 guest_free(alloc, req_addr);
486
487 /* Read request */
488 req.type = QVIRTIO_BLK_T_IN;
489 req.ioprio = 1;
490 req.sector = 0;
491 req.data = g_malloc0(512);
492
493 req_addr = virtio_blk_request(alloc, &req, 512);
494
495 g_free(req.data);
496
497 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
498 qvirtqueue_add(&vqpci->vq, req_addr + 16, 513, true, false);
499
500 qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
501
Marc Marí10535872014-09-01 12:08:00 +0200502
Stefan Hajnoczi70556262014-09-29 16:40:12 +0100503 qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
504 QVIRTIO_BLK_TIMEOUT_US);
Marc Marí10535872014-09-01 12:08:00 +0200505
506 status = readb(req_addr + 528);
507 g_assert_cmpint(status, ==, 0);
508
509 data = g_malloc0(512);
510 memread(req_addr + 16, data, 512);
511 g_assert_cmpstr(data, ==, "TEST");
512 g_free(data);
513
514 guest_free(alloc, req_addr);
515
516 /* End test */
517 guest_free(alloc, (uint64_t)vqpci->vq.desc);
518 qpci_msix_disable(dev->pdev);
519 qvirtio_pci_device_disable(dev);
520 g_free(dev);
521 test_end();
522}
523
524static void pci_idx(void)
525{
526 QVirtioPCIDevice *dev;
527 QPCIBus *bus;
528 QVirtQueuePCI *vqpci;
529 QGuestAllocator *alloc;
530 QVirtioBlkReq req;
531 void *addr;
532 uint64_t req_addr;
533 uint64_t capacity;
534 uint32_t features;
535 uint32_t free_head;
536 uint8_t status;
537 char *data;
538
539 bus = test_start();
540 alloc = pc_alloc_init();
541
Igor Mammedovaaf36072014-09-26 09:28:11 +0000542 dev = virtio_blk_init(bus, PCI_SLOT);
Marc Marí10535872014-09-01 12:08:00 +0200543 qpci_msix_enable(dev->pdev);
544
545 qvirtio_pci_set_msix_configuration_vector(dev, alloc, 0);
546
547 /* MSI-X is enabled */
548 addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_MSIX;
549
550 capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
551 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
552
553 features = qvirtio_get_features(&qvirtio_pci, &dev->vdev);
554 features = features & ~(QVIRTIO_F_BAD_FEATURE |
555 QVIRTIO_F_RING_INDIRECT_DESC |
556 QVIRTIO_F_NOTIFY_ON_EMPTY | QVIRTIO_BLK_F_SCSI);
557 qvirtio_set_features(&qvirtio_pci, &dev->vdev, features);
558
559 vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&qvirtio_pci, &dev->vdev,
560 alloc, 0);
561 qvirtqueue_pci_msix_setup(dev, vqpci, alloc, 1);
562
563 qvirtio_set_driver_ok(&qvirtio_pci, &dev->vdev);
564
565 /* Write request */
566 req.type = QVIRTIO_BLK_T_OUT;
567 req.ioprio = 1;
568 req.sector = 0;
569 req.data = g_malloc0(512);
570 strcpy(req.data, "TEST");
571
572 req_addr = virtio_blk_request(alloc, &req, 512);
573
574 g_free(req.data);
575
576 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 528, false, true);
577 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
578 qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
579
Stefan Hajnoczi70556262014-09-29 16:40:12 +0100580 qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
581 QVIRTIO_BLK_TIMEOUT_US);
Marc Marí10535872014-09-01 12:08:00 +0200582
583 /* Write request */
584 req.type = QVIRTIO_BLK_T_OUT;
585 req.ioprio = 1;
586 req.sector = 1;
587 req.data = g_malloc0(512);
588 strcpy(req.data, "TEST");
589
590 req_addr = virtio_blk_request(alloc, &req, 512);
591
592 g_free(req.data);
593
594 /* Notify after processing the third request */
595 qvirtqueue_set_used_event(&vqpci->vq, 2);
596 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 528, false, true);
597 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
598 qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
599
600 /* No notification expected */
Stefan Hajnoczie8c81b42014-09-29 16:40:11 +0100601 status = qvirtio_wait_status_byte_no_isr(&qvirtio_pci, &dev->vdev,
602 &vqpci->vq, req_addr + 528,
603 QVIRTIO_BLK_TIMEOUT_US);
Marc Marí10535872014-09-01 12:08:00 +0200604 g_assert_cmpint(status, ==, 0);
605
606 guest_free(alloc, req_addr);
607
608 /* Read request */
609 req.type = QVIRTIO_BLK_T_IN;
610 req.ioprio = 1;
611 req.sector = 1;
612 req.data = g_malloc0(512);
613
614 req_addr = virtio_blk_request(alloc, &req, 512);
615
616 g_free(req.data);
617
618 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
619 qvirtqueue_add(&vqpci->vq, req_addr + 16, 513, true, false);
620
621 qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
622
623
Stefan Hajnoczi70556262014-09-29 16:40:12 +0100624 qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
625 QVIRTIO_BLK_TIMEOUT_US);
Marc Marí58368112014-09-01 12:07:59 +0200626
627 status = readb(req_addr + 528);
628 g_assert_cmpint(status, ==, 0);
629
630 data = g_malloc0(512);
631 memread(req_addr + 16, data, 512);
632 g_assert_cmpstr(data, ==, "TEST");
633 g_free(data);
634
635 guest_free(alloc, req_addr);
636
637 /* End test */
638 guest_free(alloc, vqpci->vq.desc);
639 qpci_msix_disable(dev->pdev);
640 qvirtio_pci_device_disable(dev);
641 g_free(dev);
642 test_end();
643}
644
Igor Mammedovaaf36072014-09-26 09:28:11 +0000645static void hotplug(void)
646{
647 QPCIBus *bus;
648 QVirtioPCIDevice *dev;
649
650 bus = test_start();
651
652 /* plug secondary disk */
653 qpci_plug_device_test("virtio-blk-pci", "drv1", PCI_SLOT_HP,
654 "'drive': 'drive1'");
655
656 dev = virtio_blk_init(bus, PCI_SLOT_HP);
657 g_assert(dev);
658 qvirtio_pci_device_disable(dev);
659 g_free(dev);
660
661 /* unplug secondary disk */
662 qpci_unplug_acpi_device_test("drv1", PCI_SLOT_HP);
663 test_end();
664}
665
Andreas Färberc7a59be2014-02-09 04:32:55 +0100666int main(int argc, char **argv)
667{
668 int ret;
669
670 g_test_init(&argc, &argv, NULL);
Andreas Färberc7a59be2014-02-09 04:32:55 +0100671
Marc Marí311e6662014-09-01 12:07:54 +0200672 g_test_add_func("/virtio/blk/pci/basic", pci_basic);
Marc Maríf294b022014-09-01 12:07:57 +0200673 g_test_add_func("/virtio/blk/pci/indirect", pci_indirect);
Marc Maríe1119952014-09-01 12:07:58 +0200674 g_test_add_func("/virtio/blk/pci/config", pci_config);
Marc Marí58368112014-09-01 12:07:59 +0200675 g_test_add_func("/virtio/blk/pci/msix", pci_msix);
Marc Marí10535872014-09-01 12:08:00 +0200676 g_test_add_func("/virtio/blk/pci/idx", pci_idx);
Igor Mammedovaaf36072014-09-26 09:28:11 +0000677 g_test_add_func("/virtio/blk/pci/hotplug", hotplug);
Marc Marí311e6662014-09-01 12:07:54 +0200678
Andreas Färberc7a59be2014-02-09 04:32:55 +0100679 ret = g_test_run();
680
Andreas Färberc7a59be2014-02-09 04:32:55 +0100681 return ret;
682}