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.
17 #include "libqos/virtio.h"
18 #include "libqos/virtio-pci.h"
19 #include "libqos/pci-pc.h"
20 #include "libqos/malloc.h"
21 #include "libqos/malloc-pc.h"
22 #include "qemu/bswap.h"
24 #define QVIRTIO_BLK_F_BARRIER 0x00000001
25 #define QVIRTIO_BLK_F_SIZE_MAX 0x00000002
26 #define QVIRTIO_BLK_F_SEG_MAX 0x00000004
27 #define QVIRTIO_BLK_F_GEOMETRY 0x00000010
28 #define QVIRTIO_BLK_F_RO 0x00000020
29 #define QVIRTIO_BLK_F_BLK_SIZE 0x00000040
30 #define QVIRTIO_BLK_F_SCSI 0x00000080
31 #define QVIRTIO_BLK_F_WCE 0x00000200
32 #define QVIRTIO_BLK_F_TOPOLOGY 0x00000400
33 #define QVIRTIO_BLK_F_CONFIG_WCE 0x00000800
35 #define QVIRTIO_BLK_T_IN 0
36 #define QVIRTIO_BLK_T_OUT 1
37 #define QVIRTIO_BLK_T_SCSI_CMD 2
38 #define QVIRTIO_BLK_T_SCSI_CMD_OUT 3
39 #define QVIRTIO_BLK_T_FLUSH 4
40 #define QVIRTIO_BLK_T_FLUSH_OUT 5
41 #define QVIRTIO_BLK_T_GET_ID 8
43 #define TEST_IMAGE_SIZE (64 * 1024 * 1024)
44 #define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
48 #define PCI_SLOT_HP 0x06
50 typedef struct QVirtioBlkReq
{
58 static QPCIBus
*test_start(void)
61 char tmp_path
[] = "/tmp/qtest.XXXXXX";
64 /* Create a temporary raw image */
65 fd
= mkstemp(tmp_path
);
66 g_assert_cmpint(fd
, >=, 0);
67 ret
= ftruncate(fd
, TEST_IMAGE_SIZE
);
68 g_assert_cmpint(ret
, ==, 0);
71 cmdline
= g_strdup_printf("-drive if=none,id=drive0,file=%s,format=raw "
72 "-drive if=none,id=drive1,file=/dev/null,format=raw "
73 "-device virtio-blk-pci,id=drv0,drive=drive0,"
75 tmp_path
, PCI_SLOT
, PCI_FN
);
80 return qpci_init_pc();
83 static void test_end(void)
88 static QVirtioPCIDevice
*virtio_blk_init(QPCIBus
*bus
, int slot
)
90 QVirtioPCIDevice
*dev
;
92 dev
= qvirtio_pci_device_find(bus
, QVIRTIO_BLK_DEVICE_ID
);
93 g_assert(dev
!= NULL
);
94 g_assert_cmphex(dev
->vdev
.device_type
, ==, QVIRTIO_BLK_DEVICE_ID
);
95 g_assert_cmphex(dev
->pdev
->devfn
, ==, ((slot
<< 3) | PCI_FN
));
97 qvirtio_pci_device_enable(dev
);
98 qvirtio_reset(&qvirtio_pci
, &dev
->vdev
);
99 qvirtio_set_acknowledge(&qvirtio_pci
, &dev
->vdev
);
100 qvirtio_set_driver(&qvirtio_pci
, &dev
->vdev
);
105 static inline void virtio_blk_fix_request(QVirtioBlkReq
*req
)
107 #ifdef HOST_WORDS_BIGENDIAN
108 bool host_endian
= true;
110 bool host_endian
= false;
113 if (qtest_big_endian() != host_endian
) {
114 req
->type
= bswap32(req
->type
);
115 req
->ioprio
= bswap32(req
->ioprio
);
116 req
->sector
= bswap64(req
->sector
);
120 static uint64_t virtio_blk_request(QGuestAllocator
*alloc
, QVirtioBlkReq
*req
,
124 uint8_t status
= 0xFF;
126 g_assert_cmpuint(data_size
% 512, ==, 0);
127 addr
= guest_alloc(alloc
, sizeof(*req
) + data_size
);
129 virtio_blk_fix_request(req
);
131 memwrite(addr
, req
, 16);
132 memwrite(addr
+ 16, req
->data
, data_size
);
133 memwrite(addr
+ 16 + data_size
, &status
, sizeof(status
));
138 static void pci_basic(void)
140 QVirtioPCIDevice
*dev
;
142 QVirtQueuePCI
*vqpci
;
143 QGuestAllocator
*alloc
;
155 dev
= virtio_blk_init(bus
, PCI_SLOT
);
157 /* MSI-X is not enabled */
158 addr
= dev
->addr
+ QVIRTIO_DEVICE_SPECIFIC_NO_MSIX
;
160 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
161 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
163 features
= qvirtio_get_features(&qvirtio_pci
, &dev
->vdev
);
164 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
165 QVIRTIO_F_RING_INDIRECT_DESC
| QVIRTIO_F_RING_EVENT_IDX
|
167 qvirtio_set_features(&qvirtio_pci
, &dev
->vdev
, features
);
169 alloc
= pc_alloc_init();
170 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&qvirtio_pci
, &dev
->vdev
,
173 qvirtio_set_driver_ok(&qvirtio_pci
, &dev
->vdev
);
175 /* Write and read with 2 descriptor layout */
177 req
.type
= QVIRTIO_BLK_T_OUT
;
180 req
.data
= g_malloc0(512);
181 strcpy(req
.data
, "TEST");
183 req_addr
= virtio_blk_request(alloc
, &req
, 512);
187 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 528, false, true);
188 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
189 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
191 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
192 QVIRTIO_BLK_TIMEOUT_US
);
193 status
= readb(req_addr
+ 528);
194 g_assert_cmpint(status
, ==, 0);
196 guest_free(alloc
, req_addr
);
199 req
.type
= QVIRTIO_BLK_T_IN
;
202 req
.data
= g_malloc0(512);
204 req_addr
= virtio_blk_request(alloc
, &req
, 512);
208 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
209 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 513, true, false);
211 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
213 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
214 QVIRTIO_BLK_TIMEOUT_US
);
215 status
= readb(req_addr
+ 528);
216 g_assert_cmpint(status
, ==, 0);
218 data
= g_malloc0(512);
219 memread(req_addr
+ 16, data
, 512);
220 g_assert_cmpstr(data
, ==, "TEST");
223 guest_free(alloc
, req_addr
);
225 /* Write and read with 3 descriptor layout */
227 req
.type
= QVIRTIO_BLK_T_OUT
;
230 req
.data
= g_malloc0(512);
231 strcpy(req
.data
, "TEST");
233 req_addr
= virtio_blk_request(alloc
, &req
, 512);
235 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
236 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 512, false, true);
237 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
239 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
241 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
242 QVIRTIO_BLK_TIMEOUT_US
);
243 status
= readb(req_addr
+ 528);
244 g_assert_cmpint(status
, ==, 0);
246 guest_free(alloc
, req_addr
);
249 req
.type
= QVIRTIO_BLK_T_IN
;
252 req
.data
= g_malloc0(512);
254 req_addr
= virtio_blk_request(alloc
, &req
, 512);
258 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
259 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 512, true, true);
260 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
262 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
264 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
265 QVIRTIO_BLK_TIMEOUT_US
);
266 status
= readb(req_addr
+ 528);
267 g_assert_cmpint(status
, ==, 0);
269 data
= g_malloc0(512);
270 memread(req_addr
+ 16, data
, 512);
271 g_assert_cmpstr(data
, ==, "TEST");
274 guest_free(alloc
, req_addr
);
277 guest_free(alloc
, vqpci
->vq
.desc
);
278 qvirtio_pci_device_disable(dev
);
283 static void pci_indirect(void)
285 QVirtioPCIDevice
*dev
;
287 QVirtQueuePCI
*vqpci
;
288 QGuestAllocator
*alloc
;
290 QVRingIndirectDesc
*indirect
;
301 dev
= virtio_blk_init(bus
, PCI_SLOT
);
303 /* MSI-X is not enabled */
304 addr
= dev
->addr
+ QVIRTIO_DEVICE_SPECIFIC_NO_MSIX
;
306 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
307 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
309 features
= qvirtio_get_features(&qvirtio_pci
, &dev
->vdev
);
310 g_assert_cmphex(features
& QVIRTIO_F_RING_INDIRECT_DESC
, !=, 0);
311 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
| QVIRTIO_F_RING_EVENT_IDX
|
313 qvirtio_set_features(&qvirtio_pci
, &dev
->vdev
, features
);
315 alloc
= pc_alloc_init();
316 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&qvirtio_pci
, &dev
->vdev
,
318 qvirtio_set_driver_ok(&qvirtio_pci
, &dev
->vdev
);
321 req
.type
= QVIRTIO_BLK_T_OUT
;
324 req
.data
= g_malloc0(512);
325 strcpy(req
.data
, "TEST");
327 req_addr
= virtio_blk_request(alloc
, &req
, 512);
331 indirect
= qvring_indirect_desc_setup(&dev
->vdev
, alloc
, 2);
332 qvring_indirect_desc_add(indirect
, req_addr
, 528, false);
333 qvring_indirect_desc_add(indirect
, req_addr
+ 528, 1, true);
334 free_head
= qvirtqueue_add_indirect(&vqpci
->vq
, indirect
);
335 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
337 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
338 QVIRTIO_BLK_TIMEOUT_US
);
339 status
= readb(req_addr
+ 528);
340 g_assert_cmpint(status
, ==, 0);
343 guest_free(alloc
, req_addr
);
346 req
.type
= QVIRTIO_BLK_T_IN
;
349 req
.data
= g_malloc0(512);
350 strcpy(req
.data
, "TEST");
352 req_addr
= virtio_blk_request(alloc
, &req
, 512);
356 indirect
= qvring_indirect_desc_setup(&dev
->vdev
, alloc
, 2);
357 qvring_indirect_desc_add(indirect
, req_addr
, 16, false);
358 qvring_indirect_desc_add(indirect
, req_addr
+ 16, 513, true);
359 free_head
= qvirtqueue_add_indirect(&vqpci
->vq
, indirect
);
360 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
362 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
363 QVIRTIO_BLK_TIMEOUT_US
);
364 status
= readb(req_addr
+ 528);
365 g_assert_cmpint(status
, ==, 0);
367 data
= g_malloc0(512);
368 memread(req_addr
+ 16, data
, 512);
369 g_assert_cmpstr(data
, ==, "TEST");
373 guest_free(alloc
, req_addr
);
376 guest_free(alloc
, vqpci
->vq
.desc
);
377 qvirtio_pci_device_disable(dev
);
382 static void pci_config(void)
384 QVirtioPCIDevice
*dev
;
386 int n_size
= TEST_IMAGE_SIZE
/ 2;
392 dev
= virtio_blk_init(bus
, PCI_SLOT
);
394 /* MSI-X is not enabled */
395 addr
= dev
->addr
+ QVIRTIO_DEVICE_SPECIFIC_NO_MSIX
;
397 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
398 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
400 qvirtio_set_driver_ok(&qvirtio_pci
, &dev
->vdev
);
402 qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
403 " 'size': %d } }", n_size
);
404 qvirtio_wait_config_isr(&qvirtio_pci
, &dev
->vdev
, QVIRTIO_BLK_TIMEOUT_US
);
406 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
407 g_assert_cmpint(capacity
, ==, n_size
/ 512);
409 qvirtio_pci_device_disable(dev
);
414 static void pci_msix(void)
416 QVirtioPCIDevice
*dev
;
418 QVirtQueuePCI
*vqpci
;
419 QGuestAllocator
*alloc
;
421 int n_size
= TEST_IMAGE_SIZE
/ 2;
431 alloc
= pc_alloc_init();
433 dev
= virtio_blk_init(bus
, PCI_SLOT
);
434 qpci_msix_enable(dev
->pdev
);
436 qvirtio_pci_set_msix_configuration_vector(dev
, alloc
, 0);
438 /* MSI-X is enabled */
439 addr
= dev
->addr
+ QVIRTIO_DEVICE_SPECIFIC_MSIX
;
441 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
442 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
444 features
= qvirtio_get_features(&qvirtio_pci
, &dev
->vdev
);
445 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
446 QVIRTIO_F_RING_INDIRECT_DESC
|
447 QVIRTIO_F_RING_EVENT_IDX
| QVIRTIO_BLK_F_SCSI
);
448 qvirtio_set_features(&qvirtio_pci
, &dev
->vdev
, features
);
450 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&qvirtio_pci
, &dev
->vdev
,
452 qvirtqueue_pci_msix_setup(dev
, vqpci
, alloc
, 1);
454 qvirtio_set_driver_ok(&qvirtio_pci
, &dev
->vdev
);
456 qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
457 " 'size': %d } }", n_size
);
459 qvirtio_wait_config_isr(&qvirtio_pci
, &dev
->vdev
, QVIRTIO_BLK_TIMEOUT_US
);
461 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
462 g_assert_cmpint(capacity
, ==, n_size
/ 512);
465 req
.type
= QVIRTIO_BLK_T_OUT
;
468 req
.data
= g_malloc0(512);
469 strcpy(req
.data
, "TEST");
471 req_addr
= virtio_blk_request(alloc
, &req
, 512);
475 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 528, false, true);
476 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
477 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
479 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
480 QVIRTIO_BLK_TIMEOUT_US
);
482 status
= readb(req_addr
+ 528);
483 g_assert_cmpint(status
, ==, 0);
485 guest_free(alloc
, req_addr
);
488 req
.type
= QVIRTIO_BLK_T_IN
;
491 req
.data
= g_malloc0(512);
493 req_addr
= virtio_blk_request(alloc
, &req
, 512);
497 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
498 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 513, true, false);
500 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
503 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
504 QVIRTIO_BLK_TIMEOUT_US
);
506 status
= readb(req_addr
+ 528);
507 g_assert_cmpint(status
, ==, 0);
509 data
= g_malloc0(512);
510 memread(req_addr
+ 16, data
, 512);
511 g_assert_cmpstr(data
, ==, "TEST");
514 guest_free(alloc
, req_addr
);
517 guest_free(alloc
, (uint64_t)vqpci
->vq
.desc
);
518 qpci_msix_disable(dev
->pdev
);
519 qvirtio_pci_device_disable(dev
);
524 static void pci_idx(void)
526 QVirtioPCIDevice
*dev
;
528 QVirtQueuePCI
*vqpci
;
529 QGuestAllocator
*alloc
;
540 alloc
= pc_alloc_init();
542 dev
= virtio_blk_init(bus
, PCI_SLOT
);
543 qpci_msix_enable(dev
->pdev
);
545 qvirtio_pci_set_msix_configuration_vector(dev
, alloc
, 0);
547 /* MSI-X is enabled */
548 addr
= dev
->addr
+ QVIRTIO_DEVICE_SPECIFIC_MSIX
;
550 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
551 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
553 features
= qvirtio_get_features(&qvirtio_pci
, &dev
->vdev
);
554 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
555 QVIRTIO_F_RING_INDIRECT_DESC
|
556 QVIRTIO_F_NOTIFY_ON_EMPTY
| QVIRTIO_BLK_F_SCSI
);
557 qvirtio_set_features(&qvirtio_pci
, &dev
->vdev
, features
);
559 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&qvirtio_pci
, &dev
->vdev
,
561 qvirtqueue_pci_msix_setup(dev
, vqpci
, alloc
, 1);
563 qvirtio_set_driver_ok(&qvirtio_pci
, &dev
->vdev
);
566 req
.type
= QVIRTIO_BLK_T_OUT
;
569 req
.data
= g_malloc0(512);
570 strcpy(req
.data
, "TEST");
572 req_addr
= virtio_blk_request(alloc
, &req
, 512);
576 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 528, false, true);
577 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
578 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
580 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
581 QVIRTIO_BLK_TIMEOUT_US
);
584 req
.type
= QVIRTIO_BLK_T_OUT
;
587 req
.data
= g_malloc0(512);
588 strcpy(req
.data
, "TEST");
590 req_addr
= virtio_blk_request(alloc
, &req
, 512);
594 /* Notify after processing the third request */
595 qvirtqueue_set_used_event(&vqpci
->vq
, 2);
596 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 528, false, true);
597 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
598 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
600 /* No notification expected */
601 status
= qvirtio_wait_status_byte_no_isr(&qvirtio_pci
, &dev
->vdev
,
602 &vqpci
->vq
, req_addr
+ 528,
603 QVIRTIO_BLK_TIMEOUT_US
);
604 g_assert_cmpint(status
, ==, 0);
606 guest_free(alloc
, req_addr
);
609 req
.type
= QVIRTIO_BLK_T_IN
;
612 req
.data
= g_malloc0(512);
614 req_addr
= virtio_blk_request(alloc
, &req
, 512);
618 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
619 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 513, true, false);
621 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
624 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
625 QVIRTIO_BLK_TIMEOUT_US
);
627 status
= readb(req_addr
+ 528);
628 g_assert_cmpint(status
, ==, 0);
630 data
= g_malloc0(512);
631 memread(req_addr
+ 16, data
, 512);
632 g_assert_cmpstr(data
, ==, "TEST");
635 guest_free(alloc
, req_addr
);
638 guest_free(alloc
, vqpci
->vq
.desc
);
639 qpci_msix_disable(dev
->pdev
);
640 qvirtio_pci_device_disable(dev
);
645 static void hotplug(void)
648 QVirtioPCIDevice
*dev
;
652 /* plug secondary disk */
653 qpci_plug_device_test("virtio-blk-pci", "drv1", PCI_SLOT_HP
,
654 "'drive': 'drive1'");
656 dev
= virtio_blk_init(bus
, PCI_SLOT_HP
);
658 qvirtio_pci_device_disable(dev
);
661 /* unplug secondary disk */
662 qpci_unplug_acpi_device_test("drv1", PCI_SLOT_HP
);
666 int main(int argc
, char **argv
)
670 g_test_init(&argc
, &argv
, NULL
);
672 g_test_add_func("/virtio/blk/pci/basic", pci_basic
);
673 g_test_add_func("/virtio/blk/pci/indirect", pci_indirect
);
674 g_test_add_func("/virtio/blk/pci/config", pci_config
);
675 g_test_add_func("/virtio/blk/pci/msix", pci_msix
);
676 g_test_add_func("/virtio/blk/pci/idx", pci_idx
);
677 g_test_add_func("/virtio/blk/pci/hotplug", hotplug
);