2 * QTest testcase for VirtIO Block Device
4 * Copyright (c) 2014 SUSE LINUX Products GmbH
5 * Copyright (c) 2014 Marc MarĂ
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.
11 #include "qemu/osdep.h"
13 #include "qemu/bswap.h"
14 #include "standard-headers/linux/virtio_blk.h"
15 #include "standard-headers/linux/virtio_pci.h"
16 #include "libqos/qgraph.h"
17 #include "libqos/virtio-blk.h"
19 /* TODO actually test the results and get rid of this */
20 #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
22 #define TEST_IMAGE_SIZE (64 * 1024 * 1024)
23 #define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
24 #define PCI_SLOT_HP 0x06
26 typedef struct QVirtioBlkReq
{
35 #ifdef HOST_WORDS_BIGENDIAN
36 const bool host_is_big_endian
= true;
38 const bool host_is_big_endian
; /* false */
41 static void drive_destroy(void *path
)
45 qos_invalidate_command_line();
48 static char *drive_create(void)
51 char *t_path
= g_strdup("/tmp/qtest.XXXXXX");
53 /* Create a temporary raw image */
55 g_assert_cmpint(fd
, >=, 0);
56 ret
= ftruncate(fd
, TEST_IMAGE_SIZE
);
57 g_assert_cmpint(ret
, ==, 0);
60 g_test_queue_destroy(drive_destroy
, t_path
);
64 static inline void virtio_blk_fix_request(QVirtioDevice
*d
, QVirtioBlkReq
*req
)
66 if (qvirtio_is_big_endian(d
) != host_is_big_endian
) {
67 req
->type
= bswap32(req
->type
);
68 req
->ioprio
= bswap32(req
->ioprio
);
69 req
->sector
= bswap64(req
->sector
);
74 static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice
*d
,
75 struct virtio_blk_discard_write_zeroes
*dwz_hdr
)
77 if (qvirtio_is_big_endian(d
) != host_is_big_endian
) {
78 dwz_hdr
->sector
= bswap64(dwz_hdr
->sector
);
79 dwz_hdr
->num_sectors
= bswap32(dwz_hdr
->num_sectors
);
80 dwz_hdr
->flags
= bswap32(dwz_hdr
->flags
);
84 static uint64_t virtio_blk_request(QGuestAllocator
*alloc
, QVirtioDevice
*d
,
85 QVirtioBlkReq
*req
, uint64_t data_size
)
88 uint8_t status
= 0xFF;
92 case VIRTIO_BLK_T_OUT
:
93 g_assert_cmpuint(data_size
% 512, ==, 0);
95 case VIRTIO_BLK_T_DISCARD
:
96 case VIRTIO_BLK_T_WRITE_ZEROES
:
97 g_assert_cmpuint(data_size
%
98 sizeof(struct virtio_blk_discard_write_zeroes
), ==, 0);
101 g_assert_cmpuint(data_size
, ==, 0);
104 addr
= guest_alloc(alloc
, sizeof(*req
) + data_size
);
106 virtio_blk_fix_request(d
, req
);
108 memwrite(addr
, req
, 16);
109 memwrite(addr
+ 16, req
->data
, data_size
);
110 memwrite(addr
+ 16 + data_size
, &status
, sizeof(status
));
115 static void test_basic(QVirtioDevice
*dev
, QGuestAllocator
*alloc
,
126 capacity
= qvirtio_config_readq(dev
, 0);
128 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
130 features
= qvirtio_get_features(dev
);
131 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
132 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
133 (1u << VIRTIO_RING_F_EVENT_IDX
) |
134 (1u << VIRTIO_BLK_F_SCSI
));
135 qvirtio_set_features(dev
, features
);
137 qvirtio_set_driver_ok(dev
);
139 /* Write and read with 3 descriptor layout */
141 req
.type
= VIRTIO_BLK_T_OUT
;
144 req
.data
= g_malloc0(512);
145 strcpy(req
.data
, "TEST");
147 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
151 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
152 qvirtqueue_add(vq
, req_addr
+ 16, 512, false, true);
153 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
155 qvirtqueue_kick(dev
, vq
, free_head
);
157 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
, QVIRTIO_BLK_TIMEOUT_US
);
158 status
= readb(req_addr
+ 528);
159 g_assert_cmpint(status
, ==, 0);
161 guest_free(alloc
, req_addr
);
164 req
.type
= VIRTIO_BLK_T_IN
;
167 req
.data
= g_malloc0(512);
169 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
173 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
174 qvirtqueue_add(vq
, req_addr
+ 16, 512, true, true);
175 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
177 qvirtqueue_kick(dev
, vq
, free_head
);
179 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
, QVIRTIO_BLK_TIMEOUT_US
);
180 status
= readb(req_addr
+ 528);
181 g_assert_cmpint(status
, ==, 0);
183 data
= g_malloc0(512);
184 memread(req_addr
+ 16, data
, 512);
185 g_assert_cmpstr(data
, ==, "TEST");
188 guest_free(alloc
, req_addr
);
190 if (features
& (1u << VIRTIO_BLK_F_WRITE_ZEROES
)) {
191 struct virtio_blk_discard_write_zeroes dwz_hdr
;
195 * WRITE_ZEROES request on the same sector of previous test where
198 req
.type
= VIRTIO_BLK_T_WRITE_ZEROES
;
199 req
.data
= (char *) &dwz_hdr
;
201 dwz_hdr
.num_sectors
= 1;
204 virtio_blk_fix_dwz_hdr(dev
, &dwz_hdr
);
206 req_addr
= virtio_blk_request(alloc
, dev
, &req
, sizeof(dwz_hdr
));
208 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
209 qvirtqueue_add(vq
, req_addr
+ 16, sizeof(dwz_hdr
), false, true);
210 qvirtqueue_add(vq
, req_addr
+ 16 + sizeof(dwz_hdr
), 1, true, false);
212 qvirtqueue_kick(dev
, vq
, free_head
);
214 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
215 QVIRTIO_BLK_TIMEOUT_US
);
216 status
= readb(req_addr
+ 16 + sizeof(dwz_hdr
));
217 g_assert_cmpint(status
, ==, 0);
219 guest_free(alloc
, req_addr
);
221 /* Read request to check if the sector contains all zeroes */
222 req
.type
= VIRTIO_BLK_T_IN
;
225 req
.data
= g_malloc0(512);
227 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
231 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
232 qvirtqueue_add(vq
, req_addr
+ 16, 512, true, true);
233 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
235 qvirtqueue_kick(dev
, vq
, free_head
);
237 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
238 QVIRTIO_BLK_TIMEOUT_US
);
239 status
= readb(req_addr
+ 528);
240 g_assert_cmpint(status
, ==, 0);
242 data
= g_malloc(512);
243 expected
= g_malloc0(512);
244 memread(req_addr
+ 16, data
, 512);
245 g_assert_cmpmem(data
, 512, expected
, 512);
249 guest_free(alloc
, req_addr
);
252 if (features
& (1u << VIRTIO_BLK_F_DISCARD
)) {
253 struct virtio_blk_discard_write_zeroes dwz_hdr
;
255 req
.type
= VIRTIO_BLK_T_DISCARD
;
256 req
.data
= (char *) &dwz_hdr
;
258 dwz_hdr
.num_sectors
= 1;
261 virtio_blk_fix_dwz_hdr(dev
, &dwz_hdr
);
263 req_addr
= virtio_blk_request(alloc
, dev
, &req
, sizeof(dwz_hdr
));
265 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
266 qvirtqueue_add(vq
, req_addr
+ 16, sizeof(dwz_hdr
), false, true);
267 qvirtqueue_add(vq
, req_addr
+ 16 + sizeof(dwz_hdr
), 1, true, false);
269 qvirtqueue_kick(dev
, vq
, free_head
);
271 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
272 QVIRTIO_BLK_TIMEOUT_US
);
273 status
= readb(req_addr
+ 16 + sizeof(dwz_hdr
));
274 g_assert_cmpint(status
, ==, 0);
276 guest_free(alloc
, req_addr
);
279 if (features
& (1u << VIRTIO_F_ANY_LAYOUT
)) {
280 /* Write and read with 2 descriptor layout */
282 req
.type
= VIRTIO_BLK_T_OUT
;
285 req
.data
= g_malloc0(512);
286 strcpy(req
.data
, "TEST");
288 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
292 free_head
= qvirtqueue_add(vq
, req_addr
, 528, false, true);
293 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
294 qvirtqueue_kick(dev
, vq
, free_head
);
296 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
297 QVIRTIO_BLK_TIMEOUT_US
);
298 status
= readb(req_addr
+ 528);
299 g_assert_cmpint(status
, ==, 0);
301 guest_free(alloc
, req_addr
);
304 req
.type
= VIRTIO_BLK_T_IN
;
307 req
.data
= g_malloc0(512);
309 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
313 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
314 qvirtqueue_add(vq
, req_addr
+ 16, 513, true, false);
316 qvirtqueue_kick(dev
, vq
, free_head
);
318 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
319 QVIRTIO_BLK_TIMEOUT_US
);
320 status
= readb(req_addr
+ 528);
321 g_assert_cmpint(status
, ==, 0);
323 data
= g_malloc0(512);
324 memread(req_addr
+ 16, data
, 512);
325 g_assert_cmpstr(data
, ==, "TEST");
328 guest_free(alloc
, req_addr
);
332 static void basic(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
334 QVirtioBlk
*blk_if
= obj
;
336 vq
= qvirtqueue_setup(blk_if
->vdev
, t_alloc
, 0);
337 test_basic(blk_if
->vdev
, t_alloc
, vq
);
338 qvirtqueue_cleanup(blk_if
->vdev
->bus
, vq
, t_alloc
);
342 static void indirect(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
345 QVirtioBlk
*blk_if
= obj
;
346 QVirtioDevice
*dev
= blk_if
->vdev
;
348 QVRingIndirectDesc
*indirect
;
356 capacity
= qvirtio_config_readq(dev
, 0);
357 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
359 features
= qvirtio_get_features(dev
);
360 g_assert_cmphex(features
& (1u << VIRTIO_RING_F_INDIRECT_DESC
), !=, 0);
361 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
362 (1u << VIRTIO_RING_F_EVENT_IDX
) |
363 (1u << VIRTIO_BLK_F_SCSI
));
364 qvirtio_set_features(dev
, features
);
366 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
367 qvirtio_set_driver_ok(dev
);
370 req
.type
= VIRTIO_BLK_T_OUT
;
373 req
.data
= g_malloc0(512);
374 strcpy(req
.data
, "TEST");
376 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
380 indirect
= qvring_indirect_desc_setup(dev
, t_alloc
, 2);
381 qvring_indirect_desc_add(indirect
, req_addr
, 528, false);
382 qvring_indirect_desc_add(indirect
, req_addr
+ 528, 1, true);
383 free_head
= qvirtqueue_add_indirect(vq
, indirect
);
384 qvirtqueue_kick(dev
, vq
, free_head
);
386 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
387 QVIRTIO_BLK_TIMEOUT_US
);
388 status
= readb(req_addr
+ 528);
389 g_assert_cmpint(status
, ==, 0);
392 guest_free(t_alloc
, req_addr
);
395 req
.type
= VIRTIO_BLK_T_IN
;
398 req
.data
= g_malloc0(512);
399 strcpy(req
.data
, "TEST");
401 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
405 indirect
= qvring_indirect_desc_setup(dev
, t_alloc
, 2);
406 qvring_indirect_desc_add(indirect
, req_addr
, 16, false);
407 qvring_indirect_desc_add(indirect
, req_addr
+ 16, 513, true);
408 free_head
= qvirtqueue_add_indirect(vq
, indirect
);
409 qvirtqueue_kick(dev
, vq
, free_head
);
411 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
412 QVIRTIO_BLK_TIMEOUT_US
);
413 status
= readb(req_addr
+ 528);
414 g_assert_cmpint(status
, ==, 0);
416 data
= g_malloc0(512);
417 memread(req_addr
+ 16, data
, 512);
418 g_assert_cmpstr(data
, ==, "TEST");
422 guest_free(t_alloc
, req_addr
);
423 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
426 static void config(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
428 QVirtioBlk
*blk_if
= obj
;
429 QVirtioDevice
*dev
= blk_if
->vdev
;
430 int n_size
= TEST_IMAGE_SIZE
/ 2;
433 capacity
= qvirtio_config_readq(dev
, 0);
434 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
436 qvirtio_set_driver_ok(dev
);
438 qmp_discard_response("{ 'execute': 'block_resize', "
439 " 'arguments': { 'device': 'drive0', "
440 " 'size': %d } }", n_size
);
441 qvirtio_wait_config_isr(dev
, QVIRTIO_BLK_TIMEOUT_US
);
443 capacity
= qvirtio_config_readq(dev
, 0);
444 g_assert_cmpint(capacity
, ==, n_size
/ 512);
447 static void msix(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
450 QVirtioBlkPCI
*blk
= obj
;
451 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
452 QVirtioDevice
*dev
= &pdev
->vdev
;
454 int n_size
= TEST_IMAGE_SIZE
/ 2;
461 QOSGraphObject
*blk_object
= obj
;
462 QPCIDevice
*pci_dev
= blk_object
->get_driver(blk_object
, "pci-device");
464 if (qpci_check_buggy_msi(pci_dev
)) {
468 qpci_msix_enable(pdev
->pdev
);
469 qvirtio_pci_set_msix_configuration_vector(pdev
, t_alloc
, 0);
471 capacity
= qvirtio_config_readq(dev
, 0);
472 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
474 features
= qvirtio_get_features(dev
);
475 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
476 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
477 (1u << VIRTIO_RING_F_EVENT_IDX
) |
478 (1u << VIRTIO_BLK_F_SCSI
));
479 qvirtio_set_features(dev
, features
);
481 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
482 qvirtqueue_pci_msix_setup(pdev
, (QVirtQueuePCI
*)vq
, t_alloc
, 1);
484 qvirtio_set_driver_ok(dev
);
486 qmp_discard_response("{ 'execute': 'block_resize', "
487 " 'arguments': { 'device': 'drive0', "
488 " 'size': %d } }", n_size
);
490 qvirtio_wait_config_isr(dev
, QVIRTIO_BLK_TIMEOUT_US
);
492 capacity
= qvirtio_config_readq(dev
, 0);
493 g_assert_cmpint(capacity
, ==, n_size
/ 512);
496 req
.type
= VIRTIO_BLK_T_OUT
;
499 req
.data
= g_malloc0(512);
500 strcpy(req
.data
, "TEST");
502 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
506 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
507 qvirtqueue_add(vq
, req_addr
+ 16, 512, false, true);
508 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
509 qvirtqueue_kick(dev
, vq
, free_head
);
511 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
512 QVIRTIO_BLK_TIMEOUT_US
);
514 status
= readb(req_addr
+ 528);
515 g_assert_cmpint(status
, ==, 0);
517 guest_free(t_alloc
, req_addr
);
520 req
.type
= VIRTIO_BLK_T_IN
;
523 req
.data
= g_malloc0(512);
525 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
529 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
530 qvirtqueue_add(vq
, req_addr
+ 16, 512, true, true);
531 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
533 qvirtqueue_kick(dev
, vq
, free_head
);
536 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
537 QVIRTIO_BLK_TIMEOUT_US
);
539 status
= readb(req_addr
+ 528);
540 g_assert_cmpint(status
, ==, 0);
542 data
= g_malloc0(512);
543 memread(req_addr
+ 16, data
, 512);
544 g_assert_cmpstr(data
, ==, "TEST");
547 guest_free(t_alloc
, req_addr
);
550 qpci_msix_disable(pdev
->pdev
);
551 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
554 static void idx(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
557 QVirtioBlkPCI
*blk
= obj
;
558 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
559 QVirtioDevice
*dev
= &pdev
->vdev
;
569 QOSGraphObject
*blk_object
= obj
;
570 QPCIDevice
*pci_dev
= blk_object
->get_driver(blk_object
, "pci-device");
572 if (qpci_check_buggy_msi(pci_dev
)) {
576 qpci_msix_enable(pdev
->pdev
);
577 qvirtio_pci_set_msix_configuration_vector(pdev
, t_alloc
, 0);
579 capacity
= qvirtio_config_readq(dev
, 0);
580 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
582 features
= qvirtio_get_features(dev
);
583 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
584 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
585 (1u << VIRTIO_F_NOTIFY_ON_EMPTY
) |
586 (1u << VIRTIO_BLK_F_SCSI
));
587 qvirtio_set_features(dev
, features
);
589 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
590 qvirtqueue_pci_msix_setup(pdev
, (QVirtQueuePCI
*)vq
, t_alloc
, 1);
592 qvirtio_set_driver_ok(dev
);
595 req
.type
= VIRTIO_BLK_T_OUT
;
598 req
.data
= g_malloc0(512);
599 strcpy(req
.data
, "TEST");
601 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
605 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
606 qvirtqueue_add(vq
, req_addr
+ 16, 512, false, true);
607 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
608 qvirtqueue_kick(dev
, vq
, free_head
);
610 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
611 QVIRTIO_BLK_TIMEOUT_US
);
614 req
.type
= VIRTIO_BLK_T_OUT
;
617 req
.data
= g_malloc0(512);
618 strcpy(req
.data
, "TEST");
620 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
624 /* Notify after processing the third request */
625 qvirtqueue_set_used_event(vq
, 2);
626 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
627 qvirtqueue_add(vq
, req_addr
+ 16, 512, false, true);
628 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
629 qvirtqueue_kick(dev
, vq
, free_head
);
630 write_head
= free_head
;
632 /* No notification expected */
633 status
= qvirtio_wait_status_byte_no_isr(dev
,
635 QVIRTIO_BLK_TIMEOUT_US
);
636 g_assert_cmpint(status
, ==, 0);
638 guest_free(t_alloc
, req_addr
);
641 req
.type
= VIRTIO_BLK_T_IN
;
644 req
.data
= g_malloc0(512);
646 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
650 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
651 qvirtqueue_add(vq
, req_addr
+ 16, 512, true, true);
652 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
654 qvirtqueue_kick(dev
, vq
, free_head
);
656 /* We get just one notification for both requests */
657 qvirtio_wait_used_elem(dev
, vq
, write_head
, NULL
,
658 QVIRTIO_BLK_TIMEOUT_US
);
659 g_assert(qvirtqueue_get_buf(vq
, &desc_idx
, NULL
));
660 g_assert_cmpint(desc_idx
, ==, free_head
);
662 status
= readb(req_addr
+ 528);
663 g_assert_cmpint(status
, ==, 0);
665 data
= g_malloc0(512);
666 memread(req_addr
+ 16, data
, 512);
667 g_assert_cmpstr(data
, ==, "TEST");
670 guest_free(t_alloc
, req_addr
);
673 qpci_msix_disable(pdev
->pdev
);
675 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
678 static void pci_hotplug(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
680 QVirtioPCIDevice
*dev1
= obj
;
681 QVirtioPCIDevice
*dev
;
682 QTestState
*qts
= dev1
->pdev
->bus
->qts
;
684 /* plug secondary disk */
685 qtest_qmp_device_add("virtio-blk-pci", "drv1",
686 "{'addr': %s, 'drive': 'drive1'}",
687 stringify(PCI_SLOT_HP
) ".0");
689 dev
= virtio_pci_new(dev1
->pdev
->bus
,
690 &(QPCIAddress
) { .devfn
= QPCI_DEVFN(PCI_SLOT_HP
, 0) });
691 g_assert_nonnull(dev
);
692 g_assert_cmpint(dev
->vdev
.device_type
, ==, VIRTIO_ID_BLOCK
);
693 qvirtio_pci_device_disable(dev
);
694 qos_object_destroy((QOSGraphObject
*)dev
);
696 /* unplug secondary disk */
697 qpci_unplug_acpi_device_test(qts
, "drv1", PCI_SLOT_HP
);
701 * Check that setting the vring addr on a non-existent virtqueue does
704 static void test_nonexistent_virtqueue(void *obj
, void *data
,
705 QGuestAllocator
*t_alloc
)
707 QVirtioBlkPCI
*blk
= obj
;
708 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
712 dev
= qpci_device_find(pdev
->pdev
->bus
, QPCI_DEVFN(4, 0));
713 g_assert(dev
!= NULL
);
714 qpci_device_enable(dev
);
716 bar0
= qpci_iomap(dev
, 0, NULL
);
718 qpci_io_writeb(dev
, bar0
, VIRTIO_PCI_QUEUE_SEL
, 2);
719 qpci_io_writel(dev
, bar0
, VIRTIO_PCI_QUEUE_PFN
, 1);
725 static void resize(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
727 QVirtioBlk
*blk_if
= obj
;
728 QVirtioDevice
*dev
= blk_if
->vdev
;
729 int n_size
= TEST_IMAGE_SIZE
/ 2;
733 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
735 test_basic(dev
, t_alloc
, vq
);
737 qmp_discard_response("{ 'execute': 'block_resize', "
738 " 'arguments': { 'device': 'drive0', "
739 " 'size': %d } }", n_size
);
741 qvirtio_wait_queue_isr(dev
, vq
, QVIRTIO_BLK_TIMEOUT_US
);
743 capacity
= qvirtio_config_readq(dev
, 0);
744 g_assert_cmpint(capacity
, ==, n_size
/ 512);
746 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
750 static void *virtio_blk_test_setup(GString
*cmd_line
, void *arg
)
752 char *tmp_path
= drive_create();
754 g_string_append_printf(cmd_line
,
755 " -drive if=none,id=drive0,file=%s,format=raw,auto-read-only=off "
756 "-drive if=none,id=drive1,file=null-co://,format=raw ",
762 static void register_virtio_blk_test(void)
764 QOSGraphTestOptions opts
= {
765 .before
= virtio_blk_test_setup
,
768 qos_add_test("indirect", "virtio-blk", indirect
, &opts
);
769 qos_add_test("config", "virtio-blk", config
, &opts
);
770 qos_add_test("basic", "virtio-blk", basic
, &opts
);
771 qos_add_test("resize", "virtio-blk", resize
, &opts
);
773 /* tests just for virtio-blk-pci */
774 qos_add_test("msix", "virtio-blk-pci", msix
, &opts
);
775 qos_add_test("idx", "virtio-blk-pci", idx
, &opts
);
776 qos_add_test("nxvirtq", "virtio-blk-pci",
777 test_nonexistent_virtqueue
, &opts
);
778 qos_add_test("hotplug", "virtio-blk-pci", pci_hotplug
, &opts
);
781 libqos_init(register_virtio_blk_test
);