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 "libqos/libqos-pc.h"
14 #include "libqos/libqos-spapr.h"
15 #include "libqos/virtio.h"
16 #include "libqos/virtio-pci.h"
17 #include "libqos/virtio-mmio.h"
18 #include "libqos/malloc-generic.h"
19 #include "qapi/qmp/qdict.h"
20 #include "qemu/bswap.h"
21 #include "standard-headers/linux/virtio_ids.h"
22 #include "standard-headers/linux/virtio_config.h"
23 #include "standard-headers/linux/virtio_ring.h"
24 #include "standard-headers/linux/virtio_blk.h"
25 #include "standard-headers/linux/virtio_pci.h"
27 /* TODO actually test the results and get rid of this */
28 #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
30 #define TEST_IMAGE_SIZE (64 * 1024 * 1024)
31 #define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
32 #define PCI_SLOT_HP 0x06
36 #define MMIO_PAGE_SIZE 4096
37 #define MMIO_DEV_BASE_ADDR 0x0A003E00
38 #define MMIO_RAM_ADDR 0x40000000
39 #define MMIO_RAM_SIZE 0x20000000
41 typedef struct QVirtioBlkReq
{
49 #ifdef HOST_WORDS_BIGENDIAN
50 const bool host_is_big_endian
= true;
52 const bool host_is_big_endian
; /* false */
55 static char *drive_create(void)
58 char *tmp_path
= g_strdup("/tmp/qtest.XXXXXX");
60 /* Create a temporary raw image */
61 fd
= mkstemp(tmp_path
);
62 g_assert_cmpint(fd
, >=, 0);
63 ret
= ftruncate(fd
, TEST_IMAGE_SIZE
);
64 g_assert_cmpint(ret
, ==, 0);
70 static QOSState
*pci_test_start(void)
73 const char *arch
= qtest_get_arch();
75 const char *cmd
= "-drive if=none,id=drive0,file=%s,format=raw "
76 "-drive if=none,id=drive1,file=null-co://,format=raw "
77 "-device virtio-blk-pci,id=drv0,drive=drive0,"
80 tmp_path
= drive_create();
82 if (strcmp(arch
, "i386") == 0 || strcmp(arch
, "x86_64") == 0) {
83 qs
= qtest_pc_boot(cmd
, tmp_path
, PCI_SLOT
, PCI_FN
);
84 } else if (strcmp(arch
, "ppc64") == 0) {
85 qs
= qtest_spapr_boot(cmd
, tmp_path
, PCI_SLOT
, PCI_FN
);
87 g_printerr("virtio-blk tests are only available on x86 or ppc64\n");
90 global_qtest
= qs
->qts
;
96 static void arm_test_start(void)
100 tmp_path
= drive_create();
102 global_qtest
= qtest_initf("-machine virt "
103 "-drive if=none,id=drive0,file=%s,format=raw "
104 "-device virtio-blk-device,drive=drive0",
110 static void test_end(void)
115 static QVirtioPCIDevice
*virtio_blk_pci_init(QPCIBus
*bus
, int slot
)
117 QVirtioPCIDevice
*dev
;
119 dev
= qvirtio_pci_device_find_slot(bus
, VIRTIO_ID_BLOCK
, slot
);
120 g_assert(dev
!= NULL
);
121 g_assert_cmphex(dev
->vdev
.device_type
, ==, VIRTIO_ID_BLOCK
);
122 g_assert_cmphex(dev
->pdev
->devfn
, ==, ((slot
<< 3) | PCI_FN
));
124 qvirtio_pci_device_enable(dev
);
125 qvirtio_reset(&dev
->vdev
);
126 qvirtio_set_acknowledge(&dev
->vdev
);
127 qvirtio_set_driver(&dev
->vdev
);
132 static inline void virtio_blk_fix_request(QVirtioDevice
*d
, QVirtioBlkReq
*req
)
134 if (qvirtio_is_big_endian(d
) != host_is_big_endian
) {
135 req
->type
= bswap32(req
->type
);
136 req
->ioprio
= bswap32(req
->ioprio
);
137 req
->sector
= bswap64(req
->sector
);
142 static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice
*d
,
143 struct virtio_blk_discard_write_zeroes
*dwz_hdr
)
145 if (qvirtio_is_big_endian(d
) != host_is_big_endian
) {
146 dwz_hdr
->sector
= bswap64(dwz_hdr
->sector
);
147 dwz_hdr
->num_sectors
= bswap32(dwz_hdr
->num_sectors
);
148 dwz_hdr
->flags
= bswap32(dwz_hdr
->flags
);
152 static uint64_t virtio_blk_request(QGuestAllocator
*alloc
, QVirtioDevice
*d
,
153 QVirtioBlkReq
*req
, uint64_t data_size
)
156 uint8_t status
= 0xFF;
159 case VIRTIO_BLK_T_IN
:
160 case VIRTIO_BLK_T_OUT
:
161 g_assert_cmpuint(data_size
% 512, ==, 0);
163 case VIRTIO_BLK_T_DISCARD
:
164 case VIRTIO_BLK_T_WRITE_ZEROES
:
165 g_assert_cmpuint(data_size
%
166 sizeof(struct virtio_blk_discard_write_zeroes
), ==, 0);
169 g_assert_cmpuint(data_size
, ==, 0);
172 addr
= guest_alloc(alloc
, sizeof(*req
) + data_size
);
174 virtio_blk_fix_request(d
, req
);
176 memwrite(addr
, req
, 16);
177 memwrite(addr
+ 16, req
->data
, data_size
);
178 memwrite(addr
+ 16 + data_size
, &status
, sizeof(status
));
183 static void test_basic(QVirtioDevice
*dev
, QGuestAllocator
*alloc
,
194 capacity
= qvirtio_config_readq(dev
, 0);
196 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
198 features
= qvirtio_get_features(dev
);
199 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
200 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
201 (1u << VIRTIO_RING_F_EVENT_IDX
) |
202 (1u << VIRTIO_BLK_F_SCSI
));
203 qvirtio_set_features(dev
, features
);
205 qvirtio_set_driver_ok(dev
);
207 /* Write and read with 3 descriptor layout */
209 req
.type
= VIRTIO_BLK_T_OUT
;
212 req
.data
= g_malloc0(512);
213 strcpy(req
.data
, "TEST");
215 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
219 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
220 qvirtqueue_add(vq
, req_addr
+ 16, 512, false, true);
221 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
223 qvirtqueue_kick(dev
, vq
, free_head
);
225 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
, QVIRTIO_BLK_TIMEOUT_US
);
226 status
= readb(req_addr
+ 528);
227 g_assert_cmpint(status
, ==, 0);
229 guest_free(alloc
, req_addr
);
232 req
.type
= VIRTIO_BLK_T_IN
;
235 req
.data
= g_malloc0(512);
237 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
241 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
242 qvirtqueue_add(vq
, req_addr
+ 16, 512, true, true);
243 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
245 qvirtqueue_kick(dev
, vq
, free_head
);
247 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
, QVIRTIO_BLK_TIMEOUT_US
);
248 status
= readb(req_addr
+ 528);
249 g_assert_cmpint(status
, ==, 0);
251 data
= g_malloc0(512);
252 memread(req_addr
+ 16, data
, 512);
253 g_assert_cmpstr(data
, ==, "TEST");
256 guest_free(alloc
, req_addr
);
258 if (features
& (1u << VIRTIO_BLK_F_WRITE_ZEROES
)) {
259 struct virtio_blk_discard_write_zeroes dwz_hdr
;
263 * WRITE_ZEROES request on the same sector of previous test where
266 req
.type
= VIRTIO_BLK_T_WRITE_ZEROES
;
267 req
.data
= (char *) &dwz_hdr
;
269 dwz_hdr
.num_sectors
= 1;
272 virtio_blk_fix_dwz_hdr(dev
, &dwz_hdr
);
274 req_addr
= virtio_blk_request(alloc
, dev
, &req
, sizeof(dwz_hdr
));
276 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
277 qvirtqueue_add(vq
, req_addr
+ 16, sizeof(dwz_hdr
), false, true);
278 qvirtqueue_add(vq
, req_addr
+ 16 + sizeof(dwz_hdr
), 1, true, false);
280 qvirtqueue_kick(dev
, vq
, free_head
);
282 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
283 QVIRTIO_BLK_TIMEOUT_US
);
284 status
= readb(req_addr
+ 16 + sizeof(dwz_hdr
));
285 g_assert_cmpint(status
, ==, 0);
287 guest_free(alloc
, req_addr
);
289 /* Read request to check if the sector contains all zeroes */
290 req
.type
= VIRTIO_BLK_T_IN
;
293 req
.data
= g_malloc0(512);
295 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
299 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
300 qvirtqueue_add(vq
, req_addr
+ 16, 512, true, true);
301 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
303 qvirtqueue_kick(dev
, vq
, free_head
);
305 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
306 QVIRTIO_BLK_TIMEOUT_US
);
307 status
= readb(req_addr
+ 528);
308 g_assert_cmpint(status
, ==, 0);
310 data
= g_malloc(512);
311 expected
= g_malloc0(512);
312 memread(req_addr
+ 16, data
, 512);
313 g_assert_cmpmem(data
, 512, expected
, 512);
317 guest_free(alloc
, req_addr
);
320 if (features
& (1u << VIRTIO_BLK_F_DISCARD
)) {
321 struct virtio_blk_discard_write_zeroes dwz_hdr
;
323 req
.type
= VIRTIO_BLK_T_DISCARD
;
324 req
.data
= (char *) &dwz_hdr
;
326 dwz_hdr
.num_sectors
= 1;
329 virtio_blk_fix_dwz_hdr(dev
, &dwz_hdr
);
331 req_addr
= virtio_blk_request(alloc
, dev
, &req
, sizeof(dwz_hdr
));
333 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
334 qvirtqueue_add(vq
, req_addr
+ 16, sizeof(dwz_hdr
), false, true);
335 qvirtqueue_add(vq
, req_addr
+ 16 + sizeof(dwz_hdr
), 1, true, false);
337 qvirtqueue_kick(dev
, vq
, free_head
);
339 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
340 QVIRTIO_BLK_TIMEOUT_US
);
341 status
= readb(req_addr
+ 16 + sizeof(dwz_hdr
));
342 g_assert_cmpint(status
, ==, 0);
344 guest_free(alloc
, req_addr
);
347 if (features
& (1u << VIRTIO_F_ANY_LAYOUT
)) {
348 /* Write and read with 2 descriptor layout */
350 req
.type
= VIRTIO_BLK_T_OUT
;
353 req
.data
= g_malloc0(512);
354 strcpy(req
.data
, "TEST");
356 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
360 free_head
= qvirtqueue_add(vq
, req_addr
, 528, false, true);
361 qvirtqueue_add(vq
, req_addr
+ 528, 1, true, false);
362 qvirtqueue_kick(dev
, vq
, free_head
);
364 qvirtio_wait_used_elem(dev
, vq
, free_head
, NULL
,
365 QVIRTIO_BLK_TIMEOUT_US
);
366 status
= readb(req_addr
+ 528);
367 g_assert_cmpint(status
, ==, 0);
369 guest_free(alloc
, req_addr
);
372 req
.type
= VIRTIO_BLK_T_IN
;
375 req
.data
= g_malloc0(512);
377 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
381 free_head
= qvirtqueue_add(vq
, req_addr
, 16, false, true);
382 qvirtqueue_add(vq
, req_addr
+ 16, 513, true, false);
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);
391 data
= g_malloc0(512);
392 memread(req_addr
+ 16, data
, 512);
393 g_assert_cmpstr(data
, ==, "TEST");
396 guest_free(alloc
, req_addr
);
400 static void pci_basic(void)
402 QVirtioPCIDevice
*dev
;
404 QVirtQueuePCI
*vqpci
;
406 qs
= pci_test_start();
407 dev
= virtio_blk_pci_init(qs
->pcibus
, PCI_SLOT
);
409 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&dev
->vdev
, qs
->alloc
, 0);
411 test_basic(&dev
->vdev
, qs
->alloc
, &vqpci
->vq
);
414 qvirtqueue_cleanup(dev
->vdev
.bus
, &vqpci
->vq
, qs
->alloc
);
415 qvirtio_pci_device_disable(dev
);
416 qvirtio_pci_device_free(dev
);
420 static void pci_indirect(void)
422 QVirtioPCIDevice
*dev
;
423 QVirtQueuePCI
*vqpci
;
426 QVRingIndirectDesc
*indirect
;
434 qs
= pci_test_start();
436 dev
= virtio_blk_pci_init(qs
->pcibus
, PCI_SLOT
);
438 capacity
= qvirtio_config_readq(&dev
->vdev
, 0);
439 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
441 features
= qvirtio_get_features(&dev
->vdev
);
442 g_assert_cmphex(features
& (1u << VIRTIO_RING_F_INDIRECT_DESC
), !=, 0);
443 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
444 (1u << VIRTIO_RING_F_EVENT_IDX
) |
445 (1u << VIRTIO_BLK_F_SCSI
));
446 qvirtio_set_features(&dev
->vdev
, features
);
448 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&dev
->vdev
, qs
->alloc
, 0);
449 qvirtio_set_driver_ok(&dev
->vdev
);
452 req
.type
= VIRTIO_BLK_T_OUT
;
455 req
.data
= g_malloc0(512);
456 strcpy(req
.data
, "TEST");
458 req_addr
= virtio_blk_request(qs
->alloc
, &dev
->vdev
, &req
, 512);
462 indirect
= qvring_indirect_desc_setup(&dev
->vdev
, qs
->alloc
, 2);
463 qvring_indirect_desc_add(indirect
, req_addr
, 528, false);
464 qvring_indirect_desc_add(indirect
, req_addr
+ 528, 1, true);
465 free_head
= qvirtqueue_add_indirect(&vqpci
->vq
, indirect
);
466 qvirtqueue_kick(&dev
->vdev
, &vqpci
->vq
, free_head
);
468 qvirtio_wait_used_elem(&dev
->vdev
, &vqpci
->vq
, free_head
, NULL
,
469 QVIRTIO_BLK_TIMEOUT_US
);
470 status
= readb(req_addr
+ 528);
471 g_assert_cmpint(status
, ==, 0);
474 guest_free(qs
->alloc
, req_addr
);
477 req
.type
= VIRTIO_BLK_T_IN
;
480 req
.data
= g_malloc0(512);
481 strcpy(req
.data
, "TEST");
483 req_addr
= virtio_blk_request(qs
->alloc
, &dev
->vdev
, &req
, 512);
487 indirect
= qvring_indirect_desc_setup(&dev
->vdev
, qs
->alloc
, 2);
488 qvring_indirect_desc_add(indirect
, req_addr
, 16, false);
489 qvring_indirect_desc_add(indirect
, req_addr
+ 16, 513, true);
490 free_head
= qvirtqueue_add_indirect(&vqpci
->vq
, indirect
);
491 qvirtqueue_kick(&dev
->vdev
, &vqpci
->vq
, free_head
);
493 qvirtio_wait_used_elem(&dev
->vdev
, &vqpci
->vq
, free_head
, NULL
,
494 QVIRTIO_BLK_TIMEOUT_US
);
495 status
= readb(req_addr
+ 528);
496 g_assert_cmpint(status
, ==, 0);
498 data
= g_malloc0(512);
499 memread(req_addr
+ 16, data
, 512);
500 g_assert_cmpstr(data
, ==, "TEST");
504 guest_free(qs
->alloc
, req_addr
);
507 qvirtqueue_cleanup(dev
->vdev
.bus
, &vqpci
->vq
, qs
->alloc
);
508 qvirtio_pci_device_disable(dev
);
509 qvirtio_pci_device_free(dev
);
513 static void pci_config(void)
515 QVirtioPCIDevice
*dev
;
517 int n_size
= TEST_IMAGE_SIZE
/ 2;
520 qs
= pci_test_start();
522 dev
= virtio_blk_pci_init(qs
->pcibus
, PCI_SLOT
);
524 capacity
= qvirtio_config_readq(&dev
->vdev
, 0);
525 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
527 qvirtio_set_driver_ok(&dev
->vdev
);
529 qmp_discard_response("{ 'execute': 'block_resize', "
530 " 'arguments': { 'device': 'drive0', "
531 " 'size': %d } }", n_size
);
532 qvirtio_wait_config_isr(&dev
->vdev
, QVIRTIO_BLK_TIMEOUT_US
);
534 capacity
= qvirtio_config_readq(&dev
->vdev
, 0);
535 g_assert_cmpint(capacity
, ==, n_size
/ 512);
537 qvirtio_pci_device_disable(dev
);
538 qvirtio_pci_device_free(dev
);
543 static void pci_msix(void)
545 QVirtioPCIDevice
*dev
;
547 QVirtQueuePCI
*vqpci
;
549 int n_size
= TEST_IMAGE_SIZE
/ 2;
557 qs
= pci_test_start();
559 dev
= virtio_blk_pci_init(qs
->pcibus
, PCI_SLOT
);
560 qpci_msix_enable(dev
->pdev
);
562 qvirtio_pci_set_msix_configuration_vector(dev
, qs
->alloc
, 0);
564 capacity
= qvirtio_config_readq(&dev
->vdev
, 0);
565 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
567 features
= qvirtio_get_features(&dev
->vdev
);
568 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
569 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
570 (1u << VIRTIO_RING_F_EVENT_IDX
) |
571 (1u << VIRTIO_BLK_F_SCSI
));
572 qvirtio_set_features(&dev
->vdev
, features
);
574 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&dev
->vdev
, qs
->alloc
, 0);
575 qvirtqueue_pci_msix_setup(dev
, vqpci
, qs
->alloc
, 1);
577 qvirtio_set_driver_ok(&dev
->vdev
);
579 qmp_discard_response("{ 'execute': 'block_resize', "
580 " 'arguments': { 'device': 'drive0', "
581 " 'size': %d } }", n_size
);
583 qvirtio_wait_config_isr(&dev
->vdev
, QVIRTIO_BLK_TIMEOUT_US
);
585 capacity
= qvirtio_config_readq(&dev
->vdev
, 0);
586 g_assert_cmpint(capacity
, ==, n_size
/ 512);
589 req
.type
= VIRTIO_BLK_T_OUT
;
592 req
.data
= g_malloc0(512);
593 strcpy(req
.data
, "TEST");
595 req_addr
= virtio_blk_request(qs
->alloc
, &dev
->vdev
, &req
, 512);
599 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
600 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 512, false, true);
601 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
602 qvirtqueue_kick(&dev
->vdev
, &vqpci
->vq
, free_head
);
604 qvirtio_wait_used_elem(&dev
->vdev
, &vqpci
->vq
, free_head
, NULL
,
605 QVIRTIO_BLK_TIMEOUT_US
);
607 status
= readb(req_addr
+ 528);
608 g_assert_cmpint(status
, ==, 0);
610 guest_free(qs
->alloc
, req_addr
);
613 req
.type
= VIRTIO_BLK_T_IN
;
616 req
.data
= g_malloc0(512);
618 req_addr
= virtio_blk_request(qs
->alloc
, &dev
->vdev
, &req
, 512);
622 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
623 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 512, true, true);
624 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
626 qvirtqueue_kick(&dev
->vdev
, &vqpci
->vq
, free_head
);
629 qvirtio_wait_used_elem(&dev
->vdev
, &vqpci
->vq
, free_head
, NULL
,
630 QVIRTIO_BLK_TIMEOUT_US
);
632 status
= readb(req_addr
+ 528);
633 g_assert_cmpint(status
, ==, 0);
635 data
= g_malloc0(512);
636 memread(req_addr
+ 16, data
, 512);
637 g_assert_cmpstr(data
, ==, "TEST");
640 guest_free(qs
->alloc
, req_addr
);
643 qvirtqueue_cleanup(dev
->vdev
.bus
, &vqpci
->vq
, qs
->alloc
);
644 qpci_msix_disable(dev
->pdev
);
645 qvirtio_pci_device_disable(dev
);
646 qvirtio_pci_device_free(dev
);
650 static void pci_idx(void)
652 QVirtioPCIDevice
*dev
;
654 QVirtQueuePCI
*vqpci
;
665 qs
= pci_test_start();
667 dev
= virtio_blk_pci_init(qs
->pcibus
, PCI_SLOT
);
668 qpci_msix_enable(dev
->pdev
);
670 qvirtio_pci_set_msix_configuration_vector(dev
, qs
->alloc
, 0);
672 capacity
= qvirtio_config_readq(&dev
->vdev
, 0);
673 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
675 features
= qvirtio_get_features(&dev
->vdev
);
676 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
677 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
678 (1u << VIRTIO_F_NOTIFY_ON_EMPTY
) |
679 (1u << VIRTIO_BLK_F_SCSI
));
680 qvirtio_set_features(&dev
->vdev
, features
);
682 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&dev
->vdev
, qs
->alloc
, 0);
683 qvirtqueue_pci_msix_setup(dev
, vqpci
, qs
->alloc
, 1);
685 qvirtio_set_driver_ok(&dev
->vdev
);
688 req
.type
= VIRTIO_BLK_T_OUT
;
691 req
.data
= g_malloc0(512);
692 strcpy(req
.data
, "TEST");
694 req_addr
= virtio_blk_request(qs
->alloc
, &dev
->vdev
, &req
, 512);
698 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
699 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 512, false, true);
700 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
701 qvirtqueue_kick(&dev
->vdev
, &vqpci
->vq
, free_head
);
703 qvirtio_wait_used_elem(&dev
->vdev
, &vqpci
->vq
, free_head
, NULL
,
704 QVIRTIO_BLK_TIMEOUT_US
);
707 req
.type
= VIRTIO_BLK_T_OUT
;
710 req
.data
= g_malloc0(512);
711 strcpy(req
.data
, "TEST");
713 req_addr
= virtio_blk_request(qs
->alloc
, &dev
->vdev
, &req
, 512);
717 /* Notify after processing the third request */
718 qvirtqueue_set_used_event(&vqpci
->vq
, 2);
719 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
720 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 512, false, true);
721 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
722 qvirtqueue_kick(&dev
->vdev
, &vqpci
->vq
, free_head
);
723 write_head
= free_head
;
725 /* No notification expected */
726 status
= qvirtio_wait_status_byte_no_isr(&dev
->vdev
,
727 &vqpci
->vq
, req_addr
+ 528,
728 QVIRTIO_BLK_TIMEOUT_US
);
729 g_assert_cmpint(status
, ==, 0);
731 guest_free(qs
->alloc
, req_addr
);
734 req
.type
= VIRTIO_BLK_T_IN
;
737 req
.data
= g_malloc0(512);
739 req_addr
= virtio_blk_request(qs
->alloc
, &dev
->vdev
, &req
, 512);
743 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
744 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 512, true, true);
745 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
747 qvirtqueue_kick(&dev
->vdev
, &vqpci
->vq
, free_head
);
749 /* We get just one notification for both requests */
750 qvirtio_wait_used_elem(&dev
->vdev
, &vqpci
->vq
, write_head
, NULL
,
751 QVIRTIO_BLK_TIMEOUT_US
);
752 g_assert(qvirtqueue_get_buf(&vqpci
->vq
, &desc_idx
, NULL
));
753 g_assert_cmpint(desc_idx
, ==, free_head
);
755 status
= readb(req_addr
+ 528);
756 g_assert_cmpint(status
, ==, 0);
758 data
= g_malloc0(512);
759 memread(req_addr
+ 16, data
, 512);
760 g_assert_cmpstr(data
, ==, "TEST");
763 guest_free(qs
->alloc
, req_addr
);
766 qvirtqueue_cleanup(dev
->vdev
.bus
, &vqpci
->vq
, qs
->alloc
);
767 qpci_msix_disable(dev
->pdev
);
768 qvirtio_pci_device_disable(dev
);
769 qvirtio_pci_device_free(dev
);
773 static void pci_hotplug(void)
775 QVirtioPCIDevice
*dev
;
777 const char *arch
= qtest_get_arch();
779 qs
= pci_test_start();
781 /* plug secondary disk */
782 qtest_qmp_device_add("virtio-blk-pci", "drv1",
783 "{'addr': %s, 'drive': 'drive1'}",
784 stringify(PCI_SLOT_HP
));
786 dev
= virtio_blk_pci_init(qs
->pcibus
, PCI_SLOT_HP
);
788 qvirtio_pci_device_disable(dev
);
789 qvirtio_pci_device_free(dev
);
791 /* unplug secondary disk */
792 if (strcmp(arch
, "i386") == 0 || strcmp(arch
, "x86_64") == 0) {
793 qpci_unplug_acpi_device_test("drv1", PCI_SLOT_HP
);
799 * Check that setting the vring addr on a non-existent virtqueue does
802 static void test_nonexistent_virtqueue(void)
808 qs
= pci_test_start();
809 dev
= qpci_device_find(qs
->pcibus
, QPCI_DEVFN(4, 0));
810 g_assert(dev
!= NULL
);
812 qpci_device_enable(dev
);
813 bar0
= qpci_iomap(dev
, 0, NULL
);
815 qpci_io_writeb(dev
, bar0
, VIRTIO_PCI_QUEUE_SEL
, 2);
816 qpci_io_writel(dev
, bar0
, VIRTIO_PCI_QUEUE_PFN
, 1);
822 static void mmio_basic(void)
824 QVirtioMMIODevice
*dev
;
826 QGuestAllocator
*alloc
;
827 int n_size
= TEST_IMAGE_SIZE
/ 2;
832 dev
= qvirtio_mmio_init_device(MMIO_DEV_BASE_ADDR
, MMIO_PAGE_SIZE
);
833 g_assert(dev
!= NULL
);
834 g_assert_cmphex(dev
->vdev
.device_type
, ==, VIRTIO_ID_BLOCK
);
836 qvirtio_reset(&dev
->vdev
);
837 qvirtio_set_acknowledge(&dev
->vdev
);
838 qvirtio_set_driver(&dev
->vdev
);
840 alloc
= generic_alloc_init(MMIO_RAM_ADDR
, MMIO_RAM_SIZE
, MMIO_PAGE_SIZE
);
841 vq
= qvirtqueue_setup(&dev
->vdev
, alloc
, 0);
843 test_basic(&dev
->vdev
, alloc
, vq
);
845 qmp_discard_response("{ 'execute': 'block_resize', "
846 " 'arguments': { 'device': 'drive0', "
847 " 'size': %d } }", n_size
);
849 qvirtio_wait_queue_isr(&dev
->vdev
, vq
, QVIRTIO_BLK_TIMEOUT_US
);
851 capacity
= qvirtio_config_readq(&dev
->vdev
, 0);
852 g_assert_cmpint(capacity
, ==, n_size
/ 512);
855 qvirtqueue_cleanup(dev
->vdev
.bus
, vq
, alloc
);
857 generic_alloc_uninit(alloc
);
861 int main(int argc
, char **argv
)
863 const char *arch
= qtest_get_arch();
865 g_test_init(&argc
, &argv
, NULL
);
867 if (strcmp(arch
, "i386") == 0 || strcmp(arch
, "x86_64") == 0 ||
868 strcmp(arch
, "ppc64") == 0) {
869 qtest_add_func("/virtio/blk/pci/basic", pci_basic
);
870 qtest_add_func("/virtio/blk/pci/indirect", pci_indirect
);
871 qtest_add_func("/virtio/blk/pci/config", pci_config
);
872 qtest_add_func("/virtio/blk/pci/nxvirtq", test_nonexistent_virtqueue
);
873 if (strcmp(arch
, "i386") == 0 || strcmp(arch
, "x86_64") == 0) {
874 qtest_add_func("/virtio/blk/pci/msix", pci_msix
);
875 qtest_add_func("/virtio/blk/pci/idx", pci_idx
);
877 qtest_add_func("/virtio/blk/pci/hotplug", pci_hotplug
);
878 } else if (strcmp(arch
, "arm") == 0) {
879 qtest_add_func("/virtio/blk/mmio/basic", mmio_basic
);