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 "qemu/module.h"
15 #include "standard-headers/linux/virtio_blk.h"
16 #include "standard-headers/linux/virtio_pci.h"
17 #include "libqos/qgraph.h"
18 #include "libqos/virtio-blk.h"
20 /* TODO actually test the results and get rid of this */
21 #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
23 #define TEST_IMAGE_SIZE (64 * 1024 * 1024)
24 #define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
25 #define PCI_SLOT_HP 0x06
27 typedef struct QVirtioBlkReq
{
36 #ifdef HOST_WORDS_BIGENDIAN
37 const bool host_is_big_endian
= true;
39 const bool host_is_big_endian
; /* false */
42 static void drive_destroy(void *path
)
46 qos_invalidate_command_line();
49 static char *drive_create(void)
52 char *t_path
= g_strdup("/tmp/qtest.XXXXXX");
54 /* Create a temporary raw image */
56 g_assert_cmpint(fd
, >=, 0);
57 ret
= ftruncate(fd
, TEST_IMAGE_SIZE
);
58 g_assert_cmpint(ret
, ==, 0);
61 g_test_queue_destroy(drive_destroy
, t_path
);
65 static inline void virtio_blk_fix_request(QVirtioDevice
*d
, QVirtioBlkReq
*req
)
67 if (qvirtio_is_big_endian(d
) != host_is_big_endian
) {
68 req
->type
= bswap32(req
->type
);
69 req
->ioprio
= bswap32(req
->ioprio
);
70 req
->sector
= bswap64(req
->sector
);
75 static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice
*d
,
76 struct virtio_blk_discard_write_zeroes
*dwz_hdr
)
78 if (qvirtio_is_big_endian(d
) != host_is_big_endian
) {
79 dwz_hdr
->sector
= bswap64(dwz_hdr
->sector
);
80 dwz_hdr
->num_sectors
= bswap32(dwz_hdr
->num_sectors
);
81 dwz_hdr
->flags
= bswap32(dwz_hdr
->flags
);
85 static uint64_t virtio_blk_request(QGuestAllocator
*alloc
, QVirtioDevice
*d
,
86 QVirtioBlkReq
*req
, uint64_t data_size
)
89 uint8_t status
= 0xFF;
93 case VIRTIO_BLK_T_OUT
:
94 g_assert_cmpuint(data_size
% 512, ==, 0);
96 case VIRTIO_BLK_T_DISCARD
:
97 case VIRTIO_BLK_T_WRITE_ZEROES
:
98 g_assert_cmpuint(data_size
%
99 sizeof(struct virtio_blk_discard_write_zeroes
), ==, 0);
102 g_assert_cmpuint(data_size
, ==, 0);
105 addr
= guest_alloc(alloc
, sizeof(*req
) + data_size
);
107 virtio_blk_fix_request(d
, req
);
109 memwrite(addr
, req
, 16);
110 memwrite(addr
+ 16, req
->data
, data_size
);
111 memwrite(addr
+ 16 + data_size
, &status
, sizeof(status
));
116 static void test_basic(QVirtioDevice
*dev
, QGuestAllocator
*alloc
,
127 capacity
= qvirtio_config_readq(dev
, 0);
129 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
131 features
= qvirtio_get_features(dev
);
132 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
133 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
134 (1u << VIRTIO_RING_F_EVENT_IDX
) |
135 (1u << VIRTIO_BLK_F_SCSI
));
136 qvirtio_set_features(dev
, features
);
138 qvirtio_set_driver_ok(dev
);
140 /* Write and read with 3 descriptor layout */
142 req
.type
= VIRTIO_BLK_T_OUT
;
145 req
.data
= g_malloc0(512);
146 strcpy(req
.data
, "TEST");
148 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
152 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
153 qvirtqueue_add(vq
, req_addr
+ 16, 512, false, true);
154 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
156 qvirtqueue_kick(dev
, vq
, free_head
);
158 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
, QVIRTIO_BLK_TIMEOUT_US
);
159 status
= readb(req_addr
+ 528);
160 g_assert_cmpint(status
, ==, 0);
162 guest_free(alloc
, req_addr
);
165 req
.type
= VIRTIO_BLK_T_IN
;
168 req
.data
= g_malloc0(512);
170 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
174 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
175 qvirtqueue_add(vq
, req_addr
+ 16, 512, true, true);
176 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
178 qvirtqueue_kick(dev
, vq
, free_head
);
180 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
, QVIRTIO_BLK_TIMEOUT_US
);
181 status
= readb(req_addr
+ 528);
182 g_assert_cmpint(status
, ==, 0);
184 data
= g_malloc0(512);
185 memread(req_addr
+ 16, data
, 512);
186 g_assert_cmpstr(data
, ==, "TEST");
189 guest_free(alloc
, req_addr
);
191 if (features
& (1u << VIRTIO_BLK_F_WRITE_ZEROES
)) {
192 struct virtio_blk_discard_write_zeroes dwz_hdr
;
196 * WRITE_ZEROES request on the same sector of previous test where
199 req
.type
= VIRTIO_BLK_T_WRITE_ZEROES
;
200 req
.data
= (char *) &dwz_hdr
;
202 dwz_hdr
.num_sectors
= 1;
205 virtio_blk_fix_dwz_hdr(dev
, &dwz_hdr
);
207 req_addr
= virtio_blk_request(alloc
, dev
, &req
, sizeof(dwz_hdr
));
209 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
210 qvirtqueue_add(vq
, req_addr
+ 16, sizeof(dwz_hdr
), false, true);
211 qvirtqueue_add(vq
, req_addr
+ 16 + sizeof(dwz_hdr
), 1, true, false);
213 qvirtqueue_kick(dev
, vq
, free_head
);
215 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
216 QVIRTIO_BLK_TIMEOUT_US
);
217 status
= readb(req_addr
+ 16 + sizeof(dwz_hdr
));
218 g_assert_cmpint(status
, ==, 0);
220 guest_free(alloc
, req_addr
);
222 /* Read request to check if the sector contains all zeroes */
223 req
.type
= VIRTIO_BLK_T_IN
;
226 req
.data
= g_malloc0(512);
228 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
232 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
233 qvirtqueue_add(vq
, req_addr
+ 16, 512, true, true);
234 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
236 qvirtqueue_kick(dev
, vq
, free_head
);
238 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
239 QVIRTIO_BLK_TIMEOUT_US
);
240 status
= readb(req_addr
+ 528);
241 g_assert_cmpint(status
, ==, 0);
243 data
= g_malloc(512);
244 expected
= g_malloc0(512);
245 memread(req_addr
+ 16, data
, 512);
246 g_assert_cmpmem(data
, 512, expected
, 512);
250 guest_free(alloc
, req_addr
);
253 if (features
& (1u << VIRTIO_BLK_F_DISCARD
)) {
254 struct virtio_blk_discard_write_zeroes dwz_hdr
;
256 req
.type
= VIRTIO_BLK_T_DISCARD
;
257 req
.data
= (char *) &dwz_hdr
;
259 dwz_hdr
.num_sectors
= 1;
262 virtio_blk_fix_dwz_hdr(dev
, &dwz_hdr
);
264 req_addr
= virtio_blk_request(alloc
, dev
, &req
, sizeof(dwz_hdr
));
266 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
267 qvirtqueue_add(vq
, req_addr
+ 16, sizeof(dwz_hdr
), false, true);
268 qvirtqueue_add(vq
, req_addr
+ 16 + sizeof(dwz_hdr
), 1, true, false);
270 qvirtqueue_kick(dev
, vq
, free_head
);
272 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
273 QVIRTIO_BLK_TIMEOUT_US
);
274 status
= readb(req_addr
+ 16 + sizeof(dwz_hdr
));
275 g_assert_cmpint(status
, ==, 0);
277 guest_free(alloc
, req_addr
);
280 if (features
& (1u << VIRTIO_F_ANY_LAYOUT
)) {
281 /* Write and read with 2 descriptor layout */
283 req
.type
= VIRTIO_BLK_T_OUT
;
286 req
.data
= g_malloc0(512);
287 strcpy(req
.data
, "TEST");
289 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
293 free_head
= qvirtqueue_add(vq
, req_addr
, 528, false, true);
294 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
295 qvirtqueue_kick(dev
, vq
, free_head
);
297 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
298 QVIRTIO_BLK_TIMEOUT_US
);
299 status
= readb(req_addr
+ 528);
300 g_assert_cmpint(status
, ==, 0);
302 guest_free(alloc
, req_addr
);
305 req
.type
= VIRTIO_BLK_T_IN
;
308 req
.data
= g_malloc0(512);
310 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
314 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
315 qvirtqueue_add(vq
, req_addr
+ 16, 513, true, false);
317 qvirtqueue_kick(dev
, vq
, free_head
);
319 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
320 QVIRTIO_BLK_TIMEOUT_US
);
321 status
= readb(req_addr
+ 528);
322 g_assert_cmpint(status
, ==, 0);
324 data
= g_malloc0(512);
325 memread(req_addr
+ 16, data
, 512);
326 g_assert_cmpstr(data
, ==, "TEST");
329 guest_free(alloc
, req_addr
);
333 static void basic(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
335 QVirtioBlk
*blk_if
= obj
;
337 vq
= qvirtqueue_setup(blk_if
->vdev
, t_alloc
, 0);
338 test_basic(blk_if
->vdev
, t_alloc
, vq
);
339 qvirtqueue_cleanup(blk_if
->vdev
->bus
, vq
, t_alloc
);
343 static void indirect(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
346 QVirtioBlk
*blk_if
= obj
;
347 QVirtioDevice
*dev
= blk_if
->vdev
;
349 QVRingIndirectDesc
*indirect
;
357 capacity
= qvirtio_config_readq(dev
, 0);
358 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
360 features
= qvirtio_get_features(dev
);
361 g_assert_cmphex(features
& (1u << VIRTIO_RING_F_INDIRECT_DESC
), !=, 0);
362 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
363 (1u << VIRTIO_RING_F_EVENT_IDX
) |
364 (1u << VIRTIO_BLK_F_SCSI
));
365 qvirtio_set_features(dev
, features
);
367 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
368 qvirtio_set_driver_ok(dev
);
371 req
.type
= VIRTIO_BLK_T_OUT
;
374 req
.data
= g_malloc0(512);
375 strcpy(req
.data
, "TEST");
377 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
381 indirect
= qvring_indirect_desc_setup(dev
, t_alloc
, 2);
382 qvring_indirect_desc_add(indirect
, req_addr
, 528, false);
383 qvring_indirect_desc_add(indirect
, req_addr
+ 528, 1, true);
384 free_head
= qvirtqueue_add_indirect(vq
, indirect
);
385 qvirtqueue_kick(dev
, vq
, free_head
);
387 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
388 QVIRTIO_BLK_TIMEOUT_US
);
389 status
= readb(req_addr
+ 528);
390 g_assert_cmpint(status
, ==, 0);
393 guest_free(t_alloc
, req_addr
);
396 req
.type
= VIRTIO_BLK_T_IN
;
399 req
.data
= g_malloc0(512);
400 strcpy(req
.data
, "TEST");
402 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
406 indirect
= qvring_indirect_desc_setup(dev
, t_alloc
, 2);
407 qvring_indirect_desc_add(indirect
, req_addr
, 16, false);
408 qvring_indirect_desc_add(indirect
, req_addr
+ 16, 513, true);
409 free_head
= qvirtqueue_add_indirect(vq
, indirect
);
410 qvirtqueue_kick(dev
, vq
, free_head
);
412 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
413 QVIRTIO_BLK_TIMEOUT_US
);
414 status
= readb(req_addr
+ 528);
415 g_assert_cmpint(status
, ==, 0);
417 data
= g_malloc0(512);
418 memread(req_addr
+ 16, data
, 512);
419 g_assert_cmpstr(data
, ==, "TEST");
423 guest_free(t_alloc
, req_addr
);
424 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
427 static void config(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
429 QVirtioBlk
*blk_if
= obj
;
430 QVirtioDevice
*dev
= blk_if
->vdev
;
431 int n_size
= TEST_IMAGE_SIZE
/ 2;
434 capacity
= qvirtio_config_readq(dev
, 0);
435 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
437 qvirtio_set_driver_ok(dev
);
439 qmp_discard_response("{ 'execute': 'block_resize', "
440 " 'arguments': { 'device': 'drive0', "
441 " 'size': %d } }", n_size
);
442 qvirtio_wait_config_isr(dev
, QVIRTIO_BLK_TIMEOUT_US
);
444 capacity
= qvirtio_config_readq(dev
, 0);
445 g_assert_cmpint(capacity
, ==, n_size
/ 512);
448 static void msix(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
451 QVirtioBlkPCI
*blk
= obj
;
452 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
453 QVirtioDevice
*dev
= &pdev
->vdev
;
455 int n_size
= TEST_IMAGE_SIZE
/ 2;
462 QOSGraphObject
*blk_object
= obj
;
463 QPCIDevice
*pci_dev
= blk_object
->get_driver(blk_object
, "pci-device");
465 if (qpci_check_buggy_msi(pci_dev
)) {
469 qpci_msix_enable(pdev
->pdev
);
470 qvirtio_pci_set_msix_configuration_vector(pdev
, t_alloc
, 0);
472 capacity
= qvirtio_config_readq(dev
, 0);
473 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
475 features
= qvirtio_get_features(dev
);
476 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
477 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
478 (1u << VIRTIO_RING_F_EVENT_IDX
) |
479 (1u << VIRTIO_BLK_F_SCSI
));
480 qvirtio_set_features(dev
, features
);
482 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
483 qvirtqueue_pci_msix_setup(pdev
, (QVirtQueuePCI
*)vq
, t_alloc
, 1);
485 qvirtio_set_driver_ok(dev
);
487 qmp_discard_response("{ 'execute': 'block_resize', "
488 " 'arguments': { 'device': 'drive0', "
489 " 'size': %d } }", n_size
);
491 qvirtio_wait_config_isr(dev
, QVIRTIO_BLK_TIMEOUT_US
);
493 capacity
= qvirtio_config_readq(dev
, 0);
494 g_assert_cmpint(capacity
, ==, n_size
/ 512);
497 req
.type
= VIRTIO_BLK_T_OUT
;
500 req
.data
= g_malloc0(512);
501 strcpy(req
.data
, "TEST");
503 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
507 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
508 qvirtqueue_add(vq
, req_addr
+ 16, 512, false, true);
509 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
510 qvirtqueue_kick(dev
, vq
, free_head
);
512 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
513 QVIRTIO_BLK_TIMEOUT_US
);
515 status
= readb(req_addr
+ 528);
516 g_assert_cmpint(status
, ==, 0);
518 guest_free(t_alloc
, req_addr
);
521 req
.type
= VIRTIO_BLK_T_IN
;
524 req
.data
= g_malloc0(512);
526 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
530 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
531 qvirtqueue_add(vq
, req_addr
+ 16, 512, true, true);
532 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
534 qvirtqueue_kick(dev
, vq
, free_head
);
537 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
538 QVIRTIO_BLK_TIMEOUT_US
);
540 status
= readb(req_addr
+ 528);
541 g_assert_cmpint(status
, ==, 0);
543 data
= g_malloc0(512);
544 memread(req_addr
+ 16, data
, 512);
545 g_assert_cmpstr(data
, ==, "TEST");
548 guest_free(t_alloc
, req_addr
);
551 qpci_msix_disable(pdev
->pdev
);
552 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
555 static void idx(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
558 QVirtioBlkPCI
*blk
= obj
;
559 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
560 QVirtioDevice
*dev
= &pdev
->vdev
;
570 QOSGraphObject
*blk_object
= obj
;
571 QPCIDevice
*pci_dev
= blk_object
->get_driver(blk_object
, "pci-device");
573 if (qpci_check_buggy_msi(pci_dev
)) {
577 qpci_msix_enable(pdev
->pdev
);
578 qvirtio_pci_set_msix_configuration_vector(pdev
, t_alloc
, 0);
580 capacity
= qvirtio_config_readq(dev
, 0);
581 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
583 features
= qvirtio_get_features(dev
);
584 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
585 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
586 (1u << VIRTIO_F_NOTIFY_ON_EMPTY
) |
587 (1u << VIRTIO_BLK_F_SCSI
));
588 qvirtio_set_features(dev
, features
);
590 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
591 qvirtqueue_pci_msix_setup(pdev
, (QVirtQueuePCI
*)vq
, t_alloc
, 1);
593 qvirtio_set_driver_ok(dev
);
596 req
.type
= VIRTIO_BLK_T_OUT
;
599 req
.data
= g_malloc0(512);
600 strcpy(req
.data
, "TEST");
602 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
606 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
607 qvirtqueue_add(vq
, req_addr
+ 16, 512, false, true);
608 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
609 qvirtqueue_kick(dev
, vq
, free_head
);
611 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
612 QVIRTIO_BLK_TIMEOUT_US
);
615 req
.type
= VIRTIO_BLK_T_OUT
;
618 req
.data
= g_malloc0(512);
619 strcpy(req
.data
, "TEST");
621 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
625 /* Notify after processing the third request */
626 qvirtqueue_set_used_event(vq
, 2);
627 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
628 qvirtqueue_add(vq
, req_addr
+ 16, 512, false, true);
629 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
630 qvirtqueue_kick(dev
, vq
, free_head
);
631 write_head
= free_head
;
633 /* No notification expected */
634 status
= qvirtio_wait_status_byte_no_isr(dev
,
636 QVIRTIO_BLK_TIMEOUT_US
);
637 g_assert_cmpint(status
, ==, 0);
639 guest_free(t_alloc
, req_addr
);
642 req
.type
= VIRTIO_BLK_T_IN
;
645 req
.data
= g_malloc0(512);
647 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
651 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
652 qvirtqueue_add(vq
, req_addr
+ 16, 512, true, true);
653 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
655 qvirtqueue_kick(dev
, vq
, free_head
);
657 /* We get just one notification for both requests */
658 qvirtio_wait_used_elem(dev
, vq
, write_head
, NULL
,
659 QVIRTIO_BLK_TIMEOUT_US
);
660 g_assert(qvirtqueue_get_buf(vq
, &desc_idx
, NULL
));
661 g_assert_cmpint(desc_idx
, ==, free_head
);
663 status
= readb(req_addr
+ 528);
664 g_assert_cmpint(status
, ==, 0);
666 data
= g_malloc0(512);
667 memread(req_addr
+ 16, data
, 512);
668 g_assert_cmpstr(data
, ==, "TEST");
671 guest_free(t_alloc
, req_addr
);
674 qpci_msix_disable(pdev
->pdev
);
676 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
679 static void pci_hotplug(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
681 QVirtioPCIDevice
*dev1
= obj
;
682 QVirtioPCIDevice
*dev
;
683 QTestState
*qts
= dev1
->pdev
->bus
->qts
;
685 /* plug secondary disk */
686 qtest_qmp_device_add("virtio-blk-pci", "drv1",
687 "{'addr': %s, 'drive': 'drive1'}",
688 stringify(PCI_SLOT_HP
) ".0");
690 dev
= virtio_pci_new(dev1
->pdev
->bus
,
691 &(QPCIAddress
) { .devfn
= QPCI_DEVFN(PCI_SLOT_HP
, 0) });
692 g_assert_nonnull(dev
);
693 g_assert_cmpint(dev
->vdev
.device_type
, ==, VIRTIO_ID_BLOCK
);
694 qvirtio_pci_device_disable(dev
);
695 qos_object_destroy((QOSGraphObject
*)dev
);
697 /* unplug secondary disk */
698 qpci_unplug_acpi_device_test(qts
, "drv1", PCI_SLOT_HP
);
702 * Check that setting the vring addr on a non-existent virtqueue does
705 static void test_nonexistent_virtqueue(void *obj
, void *data
,
706 QGuestAllocator
*t_alloc
)
708 QVirtioBlkPCI
*blk
= obj
;
709 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
713 dev
= qpci_device_find(pdev
->pdev
->bus
, QPCI_DEVFN(4, 0));
714 g_assert(dev
!= NULL
);
715 qpci_device_enable(dev
);
717 bar0
= qpci_iomap(dev
, 0, NULL
);
719 qpci_io_writeb(dev
, bar0
, VIRTIO_PCI_QUEUE_SEL
, 2);
720 qpci_io_writel(dev
, bar0
, VIRTIO_PCI_QUEUE_PFN
, 1);
726 static void resize(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
728 QVirtioBlk
*blk_if
= obj
;
729 QVirtioDevice
*dev
= blk_if
->vdev
;
730 int n_size
= TEST_IMAGE_SIZE
/ 2;
734 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
736 test_basic(dev
, t_alloc
, vq
);
738 qmp_discard_response("{ 'execute': 'block_resize', "
739 " 'arguments': { 'device': 'drive0', "
740 " 'size': %d } }", n_size
);
742 qvirtio_wait_queue_isr(dev
, vq
, QVIRTIO_BLK_TIMEOUT_US
);
744 capacity
= qvirtio_config_readq(dev
, 0);
745 g_assert_cmpint(capacity
, ==, n_size
/ 512);
747 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
751 static void *virtio_blk_test_setup(GString
*cmd_line
, void *arg
)
753 char *tmp_path
= drive_create();
755 g_string_append_printf(cmd_line
,
756 " -drive if=none,id=drive0,file=%s,format=raw,auto-read-only=off "
757 "-drive if=none,id=drive1,file=null-co://,format=raw ",
763 static void register_virtio_blk_test(void)
765 QOSGraphTestOptions opts
= {
766 .before
= virtio_blk_test_setup
,
769 qos_add_test("indirect", "virtio-blk", indirect
, &opts
);
770 qos_add_test("config", "virtio-blk", config
, &opts
);
771 qos_add_test("basic", "virtio-blk", basic
, &opts
);
772 qos_add_test("resize", "virtio-blk", resize
, &opts
);
774 /* tests just for virtio-blk-pci */
775 qos_add_test("msix", "virtio-blk-pci", msix
, &opts
);
776 qos_add_test("idx", "virtio-blk-pci", idx
, &opts
);
777 qos_add_test("nxvirtq", "virtio-blk-pci",
778 test_nonexistent_virtqueue
, &opts
);
779 qos_add_test("hotplug", "virtio-blk-pci", pci_hotplug
, &opts
);
782 libqos_init(register_virtio_blk_test
);