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"
12 #include "libqtest-single.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
,
126 QTestState
*qts
= global_qtest
;
128 capacity
= qvirtio_config_readq(dev
, 0);
130 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
132 features
= qvirtio_get_features(dev
);
133 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
134 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
135 (1u << VIRTIO_RING_F_EVENT_IDX
) |
136 (1u << VIRTIO_BLK_F_SCSI
));
137 qvirtio_set_features(dev
, features
);
139 qvirtio_set_driver_ok(dev
);
141 /* Write and read with 3 descriptor layout */
143 req
.type
= VIRTIO_BLK_T_OUT
;
146 req
.data
= g_malloc0(512);
147 strcpy(req
.data
, "TEST");
149 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
153 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
154 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, false, true);
155 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
157 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
159 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
160 QVIRTIO_BLK_TIMEOUT_US
);
161 status
= readb(req_addr
+ 528);
162 g_assert_cmpint(status
, ==, 0);
164 guest_free(alloc
, req_addr
);
167 req
.type
= VIRTIO_BLK_T_IN
;
170 req
.data
= g_malloc0(512);
172 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
176 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
177 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, true, true);
178 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
180 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
182 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
183 QVIRTIO_BLK_TIMEOUT_US
);
184 status
= readb(req_addr
+ 528);
185 g_assert_cmpint(status
, ==, 0);
187 data
= g_malloc0(512);
188 memread(req_addr
+ 16, data
, 512);
189 g_assert_cmpstr(data
, ==, "TEST");
192 guest_free(alloc
, req_addr
);
194 if (features
& (1u << VIRTIO_BLK_F_WRITE_ZEROES
)) {
195 struct virtio_blk_discard_write_zeroes dwz_hdr
;
199 * WRITE_ZEROES request on the same sector of previous test where
202 req
.type
= VIRTIO_BLK_T_WRITE_ZEROES
;
203 req
.data
= (char *) &dwz_hdr
;
205 dwz_hdr
.num_sectors
= 1;
208 virtio_blk_fix_dwz_hdr(dev
, &dwz_hdr
);
210 req_addr
= virtio_blk_request(alloc
, dev
, &req
, sizeof(dwz_hdr
));
212 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
213 qvirtqueue_add(qts
, vq
, req_addr
+ 16, sizeof(dwz_hdr
), false, true);
214 qvirtqueue_add(qts
, vq
, req_addr
+ 16 + sizeof(dwz_hdr
), 1, true,
217 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
219 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
220 QVIRTIO_BLK_TIMEOUT_US
);
221 status
= readb(req_addr
+ 16 + sizeof(dwz_hdr
));
222 g_assert_cmpint(status
, ==, 0);
224 guest_free(alloc
, req_addr
);
226 /* Read request to check if the sector contains all zeroes */
227 req
.type
= VIRTIO_BLK_T_IN
;
230 req
.data
= g_malloc0(512);
232 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
236 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
237 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, true, true);
238 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
240 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
242 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
243 QVIRTIO_BLK_TIMEOUT_US
);
244 status
= readb(req_addr
+ 528);
245 g_assert_cmpint(status
, ==, 0);
247 data
= g_malloc(512);
248 expected
= g_malloc0(512);
249 memread(req_addr
+ 16, data
, 512);
250 g_assert_cmpmem(data
, 512, expected
, 512);
254 guest_free(alloc
, req_addr
);
257 if (features
& (1u << VIRTIO_BLK_F_DISCARD
)) {
258 struct virtio_blk_discard_write_zeroes dwz_hdr
;
260 req
.type
= VIRTIO_BLK_T_DISCARD
;
261 req
.data
= (char *) &dwz_hdr
;
263 dwz_hdr
.num_sectors
= 1;
266 virtio_blk_fix_dwz_hdr(dev
, &dwz_hdr
);
268 req_addr
= virtio_blk_request(alloc
, dev
, &req
, sizeof(dwz_hdr
));
270 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
271 qvirtqueue_add(qts
, vq
, req_addr
+ 16, sizeof(dwz_hdr
), false, true);
272 qvirtqueue_add(qts
, vq
, req_addr
+ 16 + sizeof(dwz_hdr
), 1, true, false);
274 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
276 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
277 QVIRTIO_BLK_TIMEOUT_US
);
278 status
= readb(req_addr
+ 16 + sizeof(dwz_hdr
));
279 g_assert_cmpint(status
, ==, 0);
281 guest_free(alloc
, req_addr
);
284 if (features
& (1u << VIRTIO_F_ANY_LAYOUT
)) {
285 /* Write and read with 2 descriptor layout */
287 req
.type
= VIRTIO_BLK_T_OUT
;
290 req
.data
= g_malloc0(512);
291 strcpy(req
.data
, "TEST");
293 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
297 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 528, false, true);
298 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
299 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
301 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
302 QVIRTIO_BLK_TIMEOUT_US
);
303 status
= readb(req_addr
+ 528);
304 g_assert_cmpint(status
, ==, 0);
306 guest_free(alloc
, req_addr
);
309 req
.type
= VIRTIO_BLK_T_IN
;
312 req
.data
= g_malloc0(512);
314 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
318 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
319 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 513, true, false);
321 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
323 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
324 QVIRTIO_BLK_TIMEOUT_US
);
325 status
= readb(req_addr
+ 528);
326 g_assert_cmpint(status
, ==, 0);
328 data
= g_malloc0(512);
329 memread(req_addr
+ 16, data
, 512);
330 g_assert_cmpstr(data
, ==, "TEST");
333 guest_free(alloc
, req_addr
);
337 static void basic(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
339 QVirtioBlk
*blk_if
= obj
;
341 vq
= qvirtqueue_setup(blk_if
->vdev
, t_alloc
, 0);
342 test_basic(blk_if
->vdev
, t_alloc
, vq
);
343 qvirtqueue_cleanup(blk_if
->vdev
->bus
, vq
, t_alloc
);
347 static void indirect(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
350 QVirtioBlk
*blk_if
= obj
;
351 QVirtioDevice
*dev
= blk_if
->vdev
;
353 QVRingIndirectDesc
*indirect
;
360 QTestState
*qts
= global_qtest
;
362 capacity
= qvirtio_config_readq(dev
, 0);
363 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
365 features
= qvirtio_get_features(dev
);
366 g_assert_cmphex(features
& (1u << VIRTIO_RING_F_INDIRECT_DESC
), !=, 0);
367 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
368 (1u << VIRTIO_RING_F_EVENT_IDX
) |
369 (1u << VIRTIO_BLK_F_SCSI
));
370 qvirtio_set_features(dev
, features
);
372 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
373 qvirtio_set_driver_ok(dev
);
376 req
.type
= VIRTIO_BLK_T_OUT
;
379 req
.data
= g_malloc0(512);
380 strcpy(req
.data
, "TEST");
382 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
386 indirect
= qvring_indirect_desc_setup(qts
, dev
, t_alloc
, 2);
387 qvring_indirect_desc_add(qts
, indirect
, req_addr
, 528, false);
388 qvring_indirect_desc_add(qts
, indirect
, req_addr
+ 528, 1, true);
389 free_head
= qvirtqueue_add_indirect(qts
, vq
, indirect
);
390 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
392 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
393 QVIRTIO_BLK_TIMEOUT_US
);
394 status
= readb(req_addr
+ 528);
395 g_assert_cmpint(status
, ==, 0);
398 guest_free(t_alloc
, req_addr
);
401 req
.type
= VIRTIO_BLK_T_IN
;
404 req
.data
= g_malloc0(512);
405 strcpy(req
.data
, "TEST");
407 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
411 indirect
= qvring_indirect_desc_setup(qts
, dev
, t_alloc
, 2);
412 qvring_indirect_desc_add(qts
, indirect
, req_addr
, 16, false);
413 qvring_indirect_desc_add(qts
, indirect
, req_addr
+ 16, 513, true);
414 free_head
= qvirtqueue_add_indirect(qts
, vq
, indirect
);
415 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
417 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
418 QVIRTIO_BLK_TIMEOUT_US
);
419 status
= readb(req_addr
+ 528);
420 g_assert_cmpint(status
, ==, 0);
422 data
= g_malloc0(512);
423 memread(req_addr
+ 16, data
, 512);
424 g_assert_cmpstr(data
, ==, "TEST");
428 guest_free(t_alloc
, req_addr
);
429 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
432 static void config(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
434 QVirtioBlk
*blk_if
= obj
;
435 QVirtioDevice
*dev
= blk_if
->vdev
;
436 int n_size
= TEST_IMAGE_SIZE
/ 2;
439 capacity
= qvirtio_config_readq(dev
, 0);
440 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
442 qvirtio_set_driver_ok(dev
);
444 qmp_discard_response("{ 'execute': 'block_resize', "
445 " 'arguments': { 'device': 'drive0', "
446 " 'size': %d } }", n_size
);
447 qvirtio_wait_config_isr(dev
, QVIRTIO_BLK_TIMEOUT_US
);
449 capacity
= qvirtio_config_readq(dev
, 0);
450 g_assert_cmpint(capacity
, ==, n_size
/ 512);
453 static void msix(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
456 QVirtioBlkPCI
*blk
= obj
;
457 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
458 QVirtioDevice
*dev
= &pdev
->vdev
;
460 int n_size
= TEST_IMAGE_SIZE
/ 2;
467 QOSGraphObject
*blk_object
= obj
;
468 QPCIDevice
*pci_dev
= blk_object
->get_driver(blk_object
, "pci-device");
469 QTestState
*qts
= global_qtest
;
471 if (qpci_check_buggy_msi(pci_dev
)) {
475 qpci_msix_enable(pdev
->pdev
);
476 qvirtio_pci_set_msix_configuration_vector(pdev
, t_alloc
, 0);
478 capacity
= qvirtio_config_readq(dev
, 0);
479 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
481 features
= qvirtio_get_features(dev
);
482 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
483 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
484 (1u << VIRTIO_RING_F_EVENT_IDX
) |
485 (1u << VIRTIO_BLK_F_SCSI
));
486 qvirtio_set_features(dev
, features
);
488 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
489 qvirtqueue_pci_msix_setup(pdev
, (QVirtQueuePCI
*)vq
, t_alloc
, 1);
491 qvirtio_set_driver_ok(dev
);
493 qmp_discard_response("{ 'execute': 'block_resize', "
494 " 'arguments': { 'device': 'drive0', "
495 " 'size': %d } }", n_size
);
497 qvirtio_wait_config_isr(dev
, QVIRTIO_BLK_TIMEOUT_US
);
499 capacity
= qvirtio_config_readq(dev
, 0);
500 g_assert_cmpint(capacity
, ==, n_size
/ 512);
503 req
.type
= VIRTIO_BLK_T_OUT
;
506 req
.data
= g_malloc0(512);
507 strcpy(req
.data
, "TEST");
509 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
513 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
514 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, false, true);
515 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
516 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
518 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
519 QVIRTIO_BLK_TIMEOUT_US
);
521 status
= readb(req_addr
+ 528);
522 g_assert_cmpint(status
, ==, 0);
524 guest_free(t_alloc
, req_addr
);
527 req
.type
= VIRTIO_BLK_T_IN
;
530 req
.data
= g_malloc0(512);
532 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
536 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
537 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, true, true);
538 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
540 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
543 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
544 QVIRTIO_BLK_TIMEOUT_US
);
546 status
= readb(req_addr
+ 528);
547 g_assert_cmpint(status
, ==, 0);
549 data
= g_malloc0(512);
550 memread(req_addr
+ 16, data
, 512);
551 g_assert_cmpstr(data
, ==, "TEST");
554 guest_free(t_alloc
, req_addr
);
557 qpci_msix_disable(pdev
->pdev
);
558 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
561 static void idx(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
564 QVirtioBlkPCI
*blk
= obj
;
565 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
566 QVirtioDevice
*dev
= &pdev
->vdev
;
576 QOSGraphObject
*blk_object
= obj
;
577 QPCIDevice
*pci_dev
= blk_object
->get_driver(blk_object
, "pci-device");
578 QTestState
*qts
= global_qtest
;
580 if (qpci_check_buggy_msi(pci_dev
)) {
584 qpci_msix_enable(pdev
->pdev
);
585 qvirtio_pci_set_msix_configuration_vector(pdev
, t_alloc
, 0);
587 capacity
= qvirtio_config_readq(dev
, 0);
588 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
590 features
= qvirtio_get_features(dev
);
591 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
592 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
593 (1u << VIRTIO_F_NOTIFY_ON_EMPTY
) |
594 (1u << VIRTIO_BLK_F_SCSI
));
595 qvirtio_set_features(dev
, features
);
597 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
598 qvirtqueue_pci_msix_setup(pdev
, (QVirtQueuePCI
*)vq
, t_alloc
, 1);
600 qvirtio_set_driver_ok(dev
);
603 req
.type
= VIRTIO_BLK_T_OUT
;
606 req
.data
= g_malloc0(512);
607 strcpy(req
.data
, "TEST");
609 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
613 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
614 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, false, true);
615 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
616 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
618 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
619 QVIRTIO_BLK_TIMEOUT_US
);
622 req
.type
= VIRTIO_BLK_T_OUT
;
625 req
.data
= g_malloc0(512);
626 strcpy(req
.data
, "TEST");
628 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
632 /* Notify after processing the third request */
633 qvirtqueue_set_used_event(qts
, vq
, 2);
634 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
635 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, false, true);
636 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
637 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
638 write_head
= free_head
;
640 /* No notification expected */
641 status
= qvirtio_wait_status_byte_no_isr(qts
, dev
,
643 QVIRTIO_BLK_TIMEOUT_US
);
644 g_assert_cmpint(status
, ==, 0);
646 guest_free(t_alloc
, req_addr
);
649 req
.type
= VIRTIO_BLK_T_IN
;
652 req
.data
= g_malloc0(512);
654 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
658 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
659 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, true, true);
660 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
662 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
664 /* We get just one notification for both requests */
665 qvirtio_wait_used_elem(qts
, dev
, vq
, write_head
, NULL
,
666 QVIRTIO_BLK_TIMEOUT_US
);
667 g_assert(qvirtqueue_get_buf(qts
, vq
, &desc_idx
, NULL
));
668 g_assert_cmpint(desc_idx
, ==, free_head
);
670 status
= readb(req_addr
+ 528);
671 g_assert_cmpint(status
, ==, 0);
673 data
= g_malloc0(512);
674 memread(req_addr
+ 16, data
, 512);
675 g_assert_cmpstr(data
, ==, "TEST");
678 guest_free(t_alloc
, req_addr
);
681 qpci_msix_disable(pdev
->pdev
);
683 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
686 static void pci_hotplug(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
688 QVirtioPCIDevice
*dev1
= obj
;
689 QVirtioPCIDevice
*dev
;
690 QTestState
*qts
= dev1
->pdev
->bus
->qts
;
692 /* plug secondary disk */
693 qtest_qmp_device_add(qts
, "virtio-blk-pci", "drv1",
694 "{'addr': %s, 'drive': 'drive1'}",
695 stringify(PCI_SLOT_HP
) ".0");
697 dev
= virtio_pci_new(dev1
->pdev
->bus
,
698 &(QPCIAddress
) { .devfn
= QPCI_DEVFN(PCI_SLOT_HP
, 0) });
699 g_assert_nonnull(dev
);
700 g_assert_cmpint(dev
->vdev
.device_type
, ==, VIRTIO_ID_BLOCK
);
701 qvirtio_pci_device_disable(dev
);
702 qos_object_destroy((QOSGraphObject
*)dev
);
704 /* unplug secondary disk */
705 qpci_unplug_acpi_device_test(qts
, "drv1", PCI_SLOT_HP
);
709 * Check that setting the vring addr on a non-existent virtqueue does
712 static void test_nonexistent_virtqueue(void *obj
, void *data
,
713 QGuestAllocator
*t_alloc
)
715 QVirtioBlkPCI
*blk
= obj
;
716 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
720 dev
= qpci_device_find(pdev
->pdev
->bus
, QPCI_DEVFN(4, 0));
721 g_assert(dev
!= NULL
);
722 qpci_device_enable(dev
);
724 bar0
= qpci_iomap(dev
, 0, NULL
);
726 qpci_io_writeb(dev
, bar0
, VIRTIO_PCI_QUEUE_SEL
, 2);
727 qpci_io_writel(dev
, bar0
, VIRTIO_PCI_QUEUE_PFN
, 1);
733 static void resize(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
735 QVirtioBlk
*blk_if
= obj
;
736 QVirtioDevice
*dev
= blk_if
->vdev
;
737 int n_size
= TEST_IMAGE_SIZE
/ 2;
740 QTestState
*qts
= global_qtest
;
742 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
744 test_basic(dev
, t_alloc
, vq
);
746 qmp_discard_response("{ 'execute': 'block_resize', "
747 " 'arguments': { 'device': 'drive0', "
748 " 'size': %d } }", n_size
);
750 qvirtio_wait_queue_isr(qts
, dev
, vq
, QVIRTIO_BLK_TIMEOUT_US
);
752 capacity
= qvirtio_config_readq(dev
, 0);
753 g_assert_cmpint(capacity
, ==, n_size
/ 512);
755 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
759 static void *virtio_blk_test_setup(GString
*cmd_line
, void *arg
)
761 char *tmp_path
= drive_create();
763 g_string_append_printf(cmd_line
,
764 " -drive if=none,id=drive0,file=%s,"
765 "format=raw,auto-read-only=off "
766 "-drive if=none,id=drive1,file=null-co://,"
767 "file.read-zeroes=on,format=raw ",
773 static void register_virtio_blk_test(void)
775 QOSGraphTestOptions opts
= {
776 .before
= virtio_blk_test_setup
,
779 qos_add_test("indirect", "virtio-blk", indirect
, &opts
);
780 qos_add_test("config", "virtio-blk", config
, &opts
);
781 qos_add_test("basic", "virtio-blk", basic
, &opts
);
782 qos_add_test("resize", "virtio-blk", resize
, &opts
);
784 /* tests just for virtio-blk-pci */
785 qos_add_test("msix", "virtio-blk-pci", msix
, &opts
);
786 qos_add_test("idx", "virtio-blk-pci", idx
, &opts
);
787 qos_add_test("nxvirtq", "virtio-blk-pci",
788 test_nonexistent_virtqueue
, &opts
);
789 qos_add_test("hotplug", "virtio-blk-pci", pci_hotplug
, &opts
);
792 libqos_init(register_virtio_blk_test
);