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 "qemu/bswap.h"
20 #include "standard-headers/linux/virtio_ids.h"
21 #include "standard-headers/linux/virtio_config.h"
22 #include "standard-headers/linux/virtio_ring.h"
23 #include "standard-headers/linux/virtio_blk.h"
24 #include "standard-headers/linux/virtio_pci.h"
26 #define TEST_IMAGE_SIZE (64 * 1024 * 1024)
27 #define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
28 #define PCI_SLOT_HP 0x06
32 #define MMIO_PAGE_SIZE 4096
33 #define MMIO_DEV_BASE_ADDR 0x0A003E00
34 #define MMIO_RAM_ADDR 0x40000000
35 #define MMIO_RAM_SIZE 0x20000000
37 typedef struct QVirtioBlkReq {
45 static char *drive_create(void)
48 char *tmp_path = g_strdup("/tmp/qtest.XXXXXX");
50 /* Create a temporary raw image */
51 fd = mkstemp(tmp_path);
52 g_assert_cmpint(fd, >=, 0);
53 ret = ftruncate(fd, TEST_IMAGE_SIZE);
54 g_assert_cmpint(ret, ==, 0);
60 static QOSState *pci_test_start(void)
63 const char *arch = qtest_get_arch();
65 const char *cmd = "-drive if=none,id=drive0,file=%s,format=raw "
66 "-drive if=none,id=drive1,file=/dev/null,format=raw "
67 "-device virtio-blk-pci,id=drv0,drive=drive0,"
70 tmp_path = drive_create();
72 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
73 qs = qtest_pc_boot(cmd, tmp_path, PCI_SLOT, PCI_FN);
74 } else if (strcmp(arch, "ppc64") == 0) {
75 qs = qtest_spapr_boot(cmd, tmp_path, PCI_SLOT, PCI_FN);
77 g_printerr("virtio-blk tests are only available on x86 or ppc64\n");
85 static void arm_test_start(void)
90 tmp_path = drive_create();
92 cmdline = g_strdup_printf("-machine virt "
93 "-drive if=none,id=drive0,file=%s,format=raw "
94 "-device virtio-blk-device,drive=drive0",
102 static void test_end(void)
107 static QVirtioPCIDevice *virtio_blk_pci_init(QPCIBus *bus, int slot)
109 QVirtioPCIDevice *dev;
111 dev = qvirtio_pci_device_find(bus, VIRTIO_ID_BLOCK);
112 g_assert(dev != NULL);
113 g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
114 g_assert_cmphex(dev->pdev->devfn, ==, ((slot << 3) | PCI_FN));
116 qvirtio_pci_device_enable(dev);
117 qvirtio_reset(&dev->vdev);
118 qvirtio_set_acknowledge(&dev->vdev);
119 qvirtio_set_driver(&dev->vdev);
124 static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
126 #ifdef HOST_WORDS_BIGENDIAN
127 const bool host_is_big_endian = true;
129 const bool host_is_big_endian = false;
132 if (qvirtio_is_big_endian(d) != host_is_big_endian) {
133 req->type = bswap32(req->type);
134 req->ioprio = bswap32(req->ioprio);
135 req->sector = bswap64(req->sector);
139 static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
140 QVirtioBlkReq *req, uint64_t data_size)
143 uint8_t status = 0xFF;
145 g_assert_cmpuint(data_size % 512, ==, 0);
146 addr = guest_alloc(alloc, sizeof(*req) + data_size);
148 virtio_blk_fix_request(d, req);
150 memwrite(addr, req, 16);
151 memwrite(addr + 16, req->data, data_size);
152 memwrite(addr + 16 + data_size, &status, sizeof(status));
157 static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
168 capacity = qvirtio_config_readq(dev, 0);
170 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
172 features = qvirtio_get_features(dev);
173 features = features & ~(QVIRTIO_F_BAD_FEATURE |
174 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
175 (1u << VIRTIO_RING_F_EVENT_IDX) |
176 (1u << VIRTIO_BLK_F_SCSI));
177 qvirtio_set_features(dev, features);
179 qvirtio_set_driver_ok(dev);
181 /* Write and read with 3 descriptor layout */
183 req.type = VIRTIO_BLK_T_OUT;
186 req.data = g_malloc0(512);
187 strcpy(req.data, "TEST");
189 req_addr = virtio_blk_request(alloc, dev, &req, 512);
193 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
194 qvirtqueue_add(vq, req_addr + 16, 512, false, true);
195 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
197 qvirtqueue_kick(dev, vq, free_head);
199 qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
200 status = readb(req_addr + 528);
201 g_assert_cmpint(status, ==, 0);
203 guest_free(alloc, req_addr);
206 req.type = VIRTIO_BLK_T_IN;
209 req.data = g_malloc0(512);
211 req_addr = virtio_blk_request(alloc, dev, &req, 512);
215 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
216 qvirtqueue_add(vq, req_addr + 16, 512, true, true);
217 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
219 qvirtqueue_kick(dev, vq, free_head);
221 qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
222 status = readb(req_addr + 528);
223 g_assert_cmpint(status, ==, 0);
225 data = g_malloc0(512);
226 memread(req_addr + 16, data, 512);
227 g_assert_cmpstr(data, ==, "TEST");
230 guest_free(alloc, req_addr);
232 if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
233 /* Write and read with 2 descriptor layout */
235 req.type = VIRTIO_BLK_T_OUT;
238 req.data = g_malloc0(512);
239 strcpy(req.data, "TEST");
241 req_addr = virtio_blk_request(alloc, dev, &req, 512);
245 free_head = qvirtqueue_add(vq, req_addr, 528, false, true);
246 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
247 qvirtqueue_kick(dev, vq, free_head);
249 qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
250 status = readb(req_addr + 528);
251 g_assert_cmpint(status, ==, 0);
253 guest_free(alloc, req_addr);
256 req.type = VIRTIO_BLK_T_IN;
259 req.data = g_malloc0(512);
261 req_addr = virtio_blk_request(alloc, dev, &req, 512);
265 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
266 qvirtqueue_add(vq, req_addr + 16, 513, true, false);
268 qvirtqueue_kick(dev, vq, free_head);
270 qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
271 status = readb(req_addr + 528);
272 g_assert_cmpint(status, ==, 0);
274 data = g_malloc0(512);
275 memread(req_addr + 16, data, 512);
276 g_assert_cmpstr(data, ==, "TEST");
279 guest_free(alloc, req_addr);
283 static void pci_basic(void)
285 QVirtioPCIDevice *dev;
287 QVirtQueuePCI *vqpci;
289 qs = pci_test_start();
290 dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
292 vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
294 test_basic(&dev->vdev, qs->alloc, &vqpci->vq);
297 qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
298 qvirtio_pci_device_disable(dev);
303 static void pci_indirect(void)
305 QVirtioPCIDevice *dev;
306 QVirtQueuePCI *vqpci;
309 QVRingIndirectDesc *indirect;
317 qs = pci_test_start();
319 dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
321 capacity = qvirtio_config_readq(&dev->vdev, 0);
322 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
324 features = qvirtio_get_features(&dev->vdev);
325 g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
326 features = features & ~(QVIRTIO_F_BAD_FEATURE |
327 (1u << VIRTIO_RING_F_EVENT_IDX) |
328 (1u << VIRTIO_BLK_F_SCSI));
329 qvirtio_set_features(&dev->vdev, features);
331 vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
332 qvirtio_set_driver_ok(&dev->vdev);
335 req.type = VIRTIO_BLK_T_OUT;
338 req.data = g_malloc0(512);
339 strcpy(req.data, "TEST");
341 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
345 indirect = qvring_indirect_desc_setup(&dev->vdev, qs->alloc, 2);
346 qvring_indirect_desc_add(indirect, req_addr, 528, false);
347 qvring_indirect_desc_add(indirect, req_addr + 528, 1, true);
348 free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
349 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
351 qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
352 QVIRTIO_BLK_TIMEOUT_US);
353 status = readb(req_addr + 528);
354 g_assert_cmpint(status, ==, 0);
357 guest_free(qs->alloc, req_addr);
360 req.type = VIRTIO_BLK_T_IN;
363 req.data = g_malloc0(512);
364 strcpy(req.data, "TEST");
366 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
370 indirect = qvring_indirect_desc_setup(&dev->vdev, qs->alloc, 2);
371 qvring_indirect_desc_add(indirect, req_addr, 16, false);
372 qvring_indirect_desc_add(indirect, req_addr + 16, 513, true);
373 free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
374 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
376 qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
377 QVIRTIO_BLK_TIMEOUT_US);
378 status = readb(req_addr + 528);
379 g_assert_cmpint(status, ==, 0);
381 data = g_malloc0(512);
382 memread(req_addr + 16, data, 512);
383 g_assert_cmpstr(data, ==, "TEST");
387 guest_free(qs->alloc, req_addr);
390 qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
391 qvirtio_pci_device_disable(dev);
396 static void pci_config(void)
398 QVirtioPCIDevice *dev;
400 int n_size = TEST_IMAGE_SIZE / 2;
403 qs = pci_test_start();
405 dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
407 capacity = qvirtio_config_readq(&dev->vdev, 0);
408 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
410 qvirtio_set_driver_ok(&dev->vdev);
412 qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
413 " 'size': %d } }", n_size);
414 qvirtio_wait_config_isr(&dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
416 capacity = qvirtio_config_readq(&dev->vdev, 0);
417 g_assert_cmpint(capacity, ==, n_size / 512);
419 qvirtio_pci_device_disable(dev);
425 static void pci_msix(void)
427 QVirtioPCIDevice *dev;
429 QVirtQueuePCI *vqpci;
431 int n_size = TEST_IMAGE_SIZE / 2;
439 qs = pci_test_start();
441 dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
442 qpci_msix_enable(dev->pdev);
444 qvirtio_pci_set_msix_configuration_vector(dev, qs->alloc, 0);
446 capacity = qvirtio_config_readq(&dev->vdev, 0);
447 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
449 features = qvirtio_get_features(&dev->vdev);
450 features = features & ~(QVIRTIO_F_BAD_FEATURE |
451 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
452 (1u << VIRTIO_RING_F_EVENT_IDX) |
453 (1u << VIRTIO_BLK_F_SCSI));
454 qvirtio_set_features(&dev->vdev, features);
456 vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
457 qvirtqueue_pci_msix_setup(dev, vqpci, qs->alloc, 1);
459 qvirtio_set_driver_ok(&dev->vdev);
461 qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
462 " 'size': %d } }", n_size);
464 qvirtio_wait_config_isr(&dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
466 capacity = qvirtio_config_readq(&dev->vdev, 0);
467 g_assert_cmpint(capacity, ==, n_size / 512);
470 req.type = VIRTIO_BLK_T_OUT;
473 req.data = g_malloc0(512);
474 strcpy(req.data, "TEST");
476 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
480 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
481 qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
482 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
483 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
485 qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
486 QVIRTIO_BLK_TIMEOUT_US);
488 status = readb(req_addr + 528);
489 g_assert_cmpint(status, ==, 0);
491 guest_free(qs->alloc, req_addr);
494 req.type = VIRTIO_BLK_T_IN;
497 req.data = g_malloc0(512);
499 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
503 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
504 qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, true, true);
505 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
507 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
510 qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
511 QVIRTIO_BLK_TIMEOUT_US);
513 status = readb(req_addr + 528);
514 g_assert_cmpint(status, ==, 0);
516 data = g_malloc0(512);
517 memread(req_addr + 16, data, 512);
518 g_assert_cmpstr(data, ==, "TEST");
521 guest_free(qs->alloc, req_addr);
524 qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
525 qpci_msix_disable(dev->pdev);
526 qvirtio_pci_device_disable(dev);
531 static void pci_idx(void)
533 QVirtioPCIDevice *dev;
535 QVirtQueuePCI *vqpci;
544 qs = pci_test_start();
546 dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
547 qpci_msix_enable(dev->pdev);
549 qvirtio_pci_set_msix_configuration_vector(dev, qs->alloc, 0);
551 capacity = qvirtio_config_readq(&dev->vdev, 0);
552 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
554 features = qvirtio_get_features(&dev->vdev);
555 features = features & ~(QVIRTIO_F_BAD_FEATURE |
556 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
557 (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
558 (1u << VIRTIO_BLK_F_SCSI));
559 qvirtio_set_features(&dev->vdev, features);
561 vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
562 qvirtqueue_pci_msix_setup(dev, vqpci, qs->alloc, 1);
564 qvirtio_set_driver_ok(&dev->vdev);
567 req.type = VIRTIO_BLK_T_OUT;
570 req.data = g_malloc0(512);
571 strcpy(req.data, "TEST");
573 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
577 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
578 qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
579 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
580 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
582 qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq, QVIRTIO_BLK_TIMEOUT_US);
585 req.type = VIRTIO_BLK_T_OUT;
588 req.data = g_malloc0(512);
589 strcpy(req.data, "TEST");
591 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
595 /* Notify after processing the third request */
596 qvirtqueue_set_used_event(&vqpci->vq, 2);
597 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
598 qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
599 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
600 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
602 /* No notification expected */
603 status = qvirtio_wait_status_byte_no_isr(&dev->vdev,
604 &vqpci->vq, req_addr + 528,
605 QVIRTIO_BLK_TIMEOUT_US);
606 g_assert_cmpint(status, ==, 0);
608 guest_free(qs->alloc, req_addr);
611 req.type = VIRTIO_BLK_T_IN;
614 req.data = g_malloc0(512);
616 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
620 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
621 qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, true, true);
622 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
624 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
626 qvirtio_wait_queue_isr(&dev->vdev, &vqpci->vq,
627 QVIRTIO_BLK_TIMEOUT_US);
629 status = readb(req_addr + 528);
630 g_assert_cmpint(status, ==, 0);
632 data = g_malloc0(512);
633 memread(req_addr + 16, data, 512);
634 g_assert_cmpstr(data, ==, "TEST");
637 guest_free(qs->alloc, req_addr);
640 qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
641 qpci_msix_disable(dev->pdev);
642 qvirtio_pci_device_disable(dev);
647 static void pci_hotplug(void)
649 QVirtioPCIDevice *dev;
651 const char *arch = qtest_get_arch();
653 qs = pci_test_start();
655 /* plug secondary disk */
656 qpci_plug_device_test("virtio-blk-pci", "drv1", PCI_SLOT_HP,
657 "'drive': 'drive1'");
659 dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT_HP);
661 qvirtio_pci_device_disable(dev);
664 /* unplug secondary disk */
665 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
666 qpci_unplug_acpi_device_test("drv1", PCI_SLOT_HP);
671 static void mmio_basic(void)
673 QVirtioMMIODevice *dev;
675 QGuestAllocator *alloc;
676 int n_size = TEST_IMAGE_SIZE / 2;
681 dev = qvirtio_mmio_init_device(MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);
682 g_assert(dev != NULL);
683 g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
685 qvirtio_reset(&dev->vdev);
686 qvirtio_set_acknowledge(&dev->vdev);
687 qvirtio_set_driver(&dev->vdev);
689 alloc = generic_alloc_init(MMIO_RAM_ADDR, MMIO_RAM_SIZE, MMIO_PAGE_SIZE);
690 vq = qvirtqueue_setup(&dev->vdev, alloc, 0);
692 test_basic(&dev->vdev, alloc, vq);
694 qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
695 " 'size': %d } }", n_size);
697 qvirtio_wait_queue_isr(&dev->vdev, vq, QVIRTIO_BLK_TIMEOUT_US);
699 capacity = qvirtio_config_readq(&dev->vdev, 0);
700 g_assert_cmpint(capacity, ==, n_size / 512);
703 qvirtqueue_cleanup(dev->vdev.bus, vq, alloc);
705 generic_alloc_uninit(alloc);
709 int main(int argc, char **argv)
711 const char *arch = qtest_get_arch();
713 g_test_init(&argc, &argv, NULL);
715 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0 ||
716 strcmp(arch, "ppc64") == 0) {
717 qtest_add_func("/virtio/blk/pci/basic", pci_basic);
718 qtest_add_func("/virtio/blk/pci/indirect", pci_indirect);
719 qtest_add_func("/virtio/blk/pci/config", pci_config);
720 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
721 qtest_add_func("/virtio/blk/pci/msix", pci_msix);
722 qtest_add_func("/virtio/blk/pci/idx", pci_idx);
724 qtest_add_func("/virtio/blk/pci/hotplug", pci_hotplug);
725 } else if (strcmp(arch, "arm") == 0) {
726 qtest_add_func("/virtio/blk/mmio/basic", mmio_basic);