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 100
48 typedef struct QVirtioBlkReq
{
56 static QPCIBus
*test_start(void)
59 char tmp_path
[] = "/tmp/qtest.XXXXXX";
62 /* Create a temporary raw image */
63 fd
= mkstemp(tmp_path
);
64 g_assert_cmpint(fd
, >=, 0);
65 ret
= ftruncate(fd
, TEST_IMAGE_SIZE
);
66 g_assert_cmpint(ret
, ==, 0);
69 snprintf(cmdline
, 100, "-drive if=none,id=drive0,file=%s "
70 "-device virtio-blk-pci,drive=drive0,addr=%x.%x",
71 tmp_path
, PCI_SLOT
, PCI_FN
);
75 return qpci_init_pc();
78 static void test_end(void)
83 static QVirtioPCIDevice
*virtio_blk_init(QPCIBus
*bus
)
85 QVirtioPCIDevice
*dev
;
87 dev
= qvirtio_pci_device_find(bus
, QVIRTIO_BLK_DEVICE_ID
);
88 g_assert(dev
!= NULL
);
89 g_assert_cmphex(dev
->vdev
.device_type
, ==, QVIRTIO_BLK_DEVICE_ID
);
90 g_assert_cmphex(dev
->pdev
->devfn
, ==, ((PCI_SLOT
<< 3) | PCI_FN
));
92 qvirtio_pci_device_enable(dev
);
93 qvirtio_reset(&qvirtio_pci
, &dev
->vdev
);
94 qvirtio_set_acknowledge(&qvirtio_pci
, &dev
->vdev
);
95 qvirtio_set_driver(&qvirtio_pci
, &dev
->vdev
);
100 static inline void virtio_blk_fix_request(QVirtioBlkReq
*req
)
102 #ifdef HOST_WORDS_BIGENDIAN
103 bool host_endian
= true;
105 bool host_endian
= false;
108 if (qtest_big_endian() != host_endian
) {
109 req
->type
= bswap32(req
->type
);
110 req
->ioprio
= bswap32(req
->ioprio
);
111 req
->sector
= bswap64(req
->sector
);
115 static uint64_t virtio_blk_request(QGuestAllocator
*alloc
, QVirtioBlkReq
*req
,
119 uint8_t status
= 0xFF;
121 g_assert_cmpuint(data_size
% 512, ==, 0);
122 addr
= guest_alloc(alloc
, sizeof(*req
) + data_size
);
124 virtio_blk_fix_request(req
);
126 memwrite(addr
, req
, 16);
127 memwrite(addr
+ 16, req
->data
, data_size
);
128 memwrite(addr
+ 16 + data_size
, &status
, sizeof(status
));
133 static void pci_basic(void)
135 QVirtioPCIDevice
*dev
;
137 QVirtQueuePCI
*vqpci
;
138 QGuestAllocator
*alloc
;
150 dev
= virtio_blk_init(bus
);
152 /* MSI-X is not enabled */
153 addr
= dev
->addr
+ QVIRTIO_DEVICE_SPECIFIC_NO_MSIX
;
155 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
156 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
158 features
= qvirtio_get_features(&qvirtio_pci
, &dev
->vdev
);
159 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
160 QVIRTIO_F_RING_INDIRECT_DESC
| QVIRTIO_F_RING_EVENT_IDX
|
162 qvirtio_set_features(&qvirtio_pci
, &dev
->vdev
, features
);
164 alloc
= pc_alloc_init();
165 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&qvirtio_pci
, &dev
->vdev
,
168 qvirtio_set_driver_ok(&qvirtio_pci
, &dev
->vdev
);
170 /* Write and read with 2 descriptor layout */
172 req
.type
= QVIRTIO_BLK_T_OUT
;
175 req
.data
= g_malloc0(512);
176 strcpy(req
.data
, "TEST");
178 req_addr
= virtio_blk_request(alloc
, &req
, 512);
182 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 528, false, true);
183 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
184 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
186 g_assert(qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
187 QVIRTIO_BLK_TIMEOUT
));
188 status
= readb(req_addr
+ 528);
189 g_assert_cmpint(status
, ==, 0);
191 guest_free(alloc
, req_addr
);
194 req
.type
= QVIRTIO_BLK_T_IN
;
197 req
.data
= g_malloc0(512);
199 req_addr
= virtio_blk_request(alloc
, &req
, 512);
203 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
204 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 513, true, false);
206 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
208 g_assert(qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
209 QVIRTIO_BLK_TIMEOUT
));
210 status
= readb(req_addr
+ 528);
211 g_assert_cmpint(status
, ==, 0);
213 data
= g_malloc0(512);
214 memread(req_addr
+ 16, data
, 512);
215 g_assert_cmpstr(data
, ==, "TEST");
218 guest_free(alloc
, req_addr
);
220 /* Write and read with 3 descriptor layout */
222 req
.type
= QVIRTIO_BLK_T_OUT
;
225 req
.data
= g_malloc0(512);
226 strcpy(req
.data
, "TEST");
228 req_addr
= virtio_blk_request(alloc
, &req
, 512);
230 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
231 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 512, false, true);
232 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
234 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
236 g_assert(qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
237 QVIRTIO_BLK_TIMEOUT
));
238 status
= readb(req_addr
+ 528);
239 g_assert_cmpint(status
, ==, 0);
241 guest_free(alloc
, req_addr
);
244 req
.type
= QVIRTIO_BLK_T_IN
;
247 req
.data
= g_malloc0(512);
249 req_addr
= virtio_blk_request(alloc
, &req
, 512);
253 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
254 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 512, true, true);
255 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
257 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
259 g_assert(qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
260 QVIRTIO_BLK_TIMEOUT
));
261 status
= readb(req_addr
+ 528);
262 g_assert_cmpint(status
, ==, 0);
264 data
= g_malloc0(512);
265 memread(req_addr
+ 16, data
, 512);
266 g_assert_cmpstr(data
, ==, "TEST");
269 guest_free(alloc
, req_addr
);
272 guest_free(alloc
, vqpci
->vq
.desc
);
273 qvirtio_pci_device_disable(dev
);
278 static void pci_indirect(void)
280 QVirtioPCIDevice
*dev
;
282 QVirtQueuePCI
*vqpci
;
283 QGuestAllocator
*alloc
;
285 QVRingIndirectDesc
*indirect
;
296 dev
= virtio_blk_init(bus
);
298 /* MSI-X is not enabled */
299 addr
= dev
->addr
+ QVIRTIO_DEVICE_SPECIFIC_NO_MSIX
;
301 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
302 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
304 features
= qvirtio_get_features(&qvirtio_pci
, &dev
->vdev
);
305 g_assert_cmphex(features
& QVIRTIO_F_RING_INDIRECT_DESC
, !=, 0);
306 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
| QVIRTIO_F_RING_EVENT_IDX
|
308 qvirtio_set_features(&qvirtio_pci
, &dev
->vdev
, features
);
310 alloc
= pc_alloc_init();
311 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&qvirtio_pci
, &dev
->vdev
,
313 qvirtio_set_driver_ok(&qvirtio_pci
, &dev
->vdev
);
316 req
.type
= QVIRTIO_BLK_T_OUT
;
319 req
.data
= g_malloc0(512);
320 strcpy(req
.data
, "TEST");
322 req_addr
= virtio_blk_request(alloc
, &req
, 512);
326 indirect
= qvring_indirect_desc_setup(&dev
->vdev
, alloc
, 2);
327 qvring_indirect_desc_add(indirect
, req_addr
, 528, false);
328 qvring_indirect_desc_add(indirect
, req_addr
+ 528, 1, true);
329 free_head
= qvirtqueue_add_indirect(&vqpci
->vq
, indirect
);
330 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
332 g_assert(qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
333 QVIRTIO_BLK_TIMEOUT
));
334 status
= readb(req_addr
+ 528);
335 g_assert_cmpint(status
, ==, 0);
338 guest_free(alloc
, req_addr
);
341 req
.type
= QVIRTIO_BLK_T_IN
;
344 req
.data
= g_malloc0(512);
345 strcpy(req
.data
, "TEST");
347 req_addr
= virtio_blk_request(alloc
, &req
, 512);
351 indirect
= qvring_indirect_desc_setup(&dev
->vdev
, alloc
, 2);
352 qvring_indirect_desc_add(indirect
, req_addr
, 16, false);
353 qvring_indirect_desc_add(indirect
, req_addr
+ 16, 513, true);
354 free_head
= qvirtqueue_add_indirect(&vqpci
->vq
, indirect
);
355 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
357 g_assert(qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
358 QVIRTIO_BLK_TIMEOUT
));
359 status
= readb(req_addr
+ 528);
360 g_assert_cmpint(status
, ==, 0);
362 data
= g_malloc0(512);
363 memread(req_addr
+ 16, data
, 512);
364 g_assert_cmpstr(data
, ==, "TEST");
368 guest_free(alloc
, req_addr
);
371 guest_free(alloc
, vqpci
->vq
.desc
);
372 qvirtio_pci_device_disable(dev
);
377 static void pci_config(void)
379 QVirtioPCIDevice
*dev
;
381 int n_size
= TEST_IMAGE_SIZE
/ 2;
387 dev
= virtio_blk_init(bus
);
389 /* MSI-X is not enabled */
390 addr
= dev
->addr
+ QVIRTIO_DEVICE_SPECIFIC_NO_MSIX
;
392 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
393 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
395 qvirtio_set_driver_ok(&qvirtio_pci
, &dev
->vdev
);
397 qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
398 " 'size': %d } }", n_size
);
399 g_assert(qvirtio_wait_config_isr(&qvirtio_pci
, &dev
->vdev
,
400 QVIRTIO_BLK_TIMEOUT
));
402 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
403 g_assert_cmpint(capacity
, ==, n_size
/ 512);
405 qvirtio_pci_device_disable(dev
);
410 static void pci_msix(void)
412 QVirtioPCIDevice
*dev
;
414 QVirtQueuePCI
*vqpci
;
415 QGuestAllocator
*alloc
;
417 int n_size
= TEST_IMAGE_SIZE
/ 2;
427 alloc
= pc_alloc_init();
429 dev
= virtio_blk_init(bus
);
430 qpci_msix_enable(dev
->pdev
);
432 qvirtio_pci_set_msix_configuration_vector(dev
, alloc
, 0);
434 /* MSI-X is enabled */
435 addr
= dev
->addr
+ QVIRTIO_DEVICE_SPECIFIC_MSIX
;
437 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
438 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
440 features
= qvirtio_get_features(&qvirtio_pci
, &dev
->vdev
);
441 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
442 QVIRTIO_F_RING_INDIRECT_DESC
|
443 QVIRTIO_F_RING_EVENT_IDX
| QVIRTIO_BLK_F_SCSI
);
444 qvirtio_set_features(&qvirtio_pci
, &dev
->vdev
, features
);
446 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&qvirtio_pci
, &dev
->vdev
,
448 qvirtqueue_pci_msix_setup(dev
, vqpci
, alloc
, 1);
450 qvirtio_set_driver_ok(&qvirtio_pci
, &dev
->vdev
);
452 qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
453 " 'size': %d } }", n_size
);
455 g_assert(qvirtio_wait_config_isr(&qvirtio_pci
, &dev
->vdev
,
456 QVIRTIO_BLK_TIMEOUT
));
458 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
459 g_assert_cmpint(capacity
, ==, n_size
/ 512);
462 req
.type
= QVIRTIO_BLK_T_OUT
;
465 req
.data
= g_malloc0(512);
466 strcpy(req
.data
, "TEST");
468 req_addr
= virtio_blk_request(alloc
, &req
, 512);
472 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 528, false, true);
473 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
474 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
476 g_assert(qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
477 QVIRTIO_BLK_TIMEOUT
));
479 status
= readb(req_addr
+ 528);
480 g_assert_cmpint(status
, ==, 0);
482 guest_free(alloc
, req_addr
);
485 req
.type
= QVIRTIO_BLK_T_IN
;
488 req
.data
= g_malloc0(512);
490 req_addr
= virtio_blk_request(alloc
, &req
, 512);
494 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
495 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 513, true, false);
497 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
500 g_assert(qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
501 QVIRTIO_BLK_TIMEOUT
));
503 status
= readb(req_addr
+ 528);
504 g_assert_cmpint(status
, ==, 0);
506 data
= g_malloc0(512);
507 memread(req_addr
+ 16, data
, 512);
508 g_assert_cmpstr(data
, ==, "TEST");
511 guest_free(alloc
, req_addr
);
514 guest_free(alloc
, (uint64_t)vqpci
->vq
.desc
);
515 qpci_msix_disable(dev
->pdev
);
516 qvirtio_pci_device_disable(dev
);
521 static void pci_idx(void)
523 QVirtioPCIDevice
*dev
;
525 QVirtQueuePCI
*vqpci
;
526 QGuestAllocator
*alloc
;
537 alloc
= pc_alloc_init();
539 dev
= virtio_blk_init(bus
);
540 qpci_msix_enable(dev
->pdev
);
542 qvirtio_pci_set_msix_configuration_vector(dev
, alloc
, 0);
544 /* MSI-X is enabled */
545 addr
= dev
->addr
+ QVIRTIO_DEVICE_SPECIFIC_MSIX
;
547 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
548 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
550 features
= qvirtio_get_features(&qvirtio_pci
, &dev
->vdev
);
551 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
552 QVIRTIO_F_RING_INDIRECT_DESC
|
553 QVIRTIO_F_NOTIFY_ON_EMPTY
| QVIRTIO_BLK_F_SCSI
);
554 qvirtio_set_features(&qvirtio_pci
, &dev
->vdev
, features
);
556 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&qvirtio_pci
, &dev
->vdev
,
558 qvirtqueue_pci_msix_setup(dev
, vqpci
, alloc
, 1);
560 qvirtio_set_driver_ok(&qvirtio_pci
, &dev
->vdev
);
563 req
.type
= QVIRTIO_BLK_T_OUT
;
566 req
.data
= g_malloc0(512);
567 strcpy(req
.data
, "TEST");
569 req_addr
= virtio_blk_request(alloc
, &req
, 512);
573 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 528, false, true);
574 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
575 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
577 g_assert(qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
578 QVIRTIO_BLK_TIMEOUT
));
581 req
.type
= QVIRTIO_BLK_T_OUT
;
584 req
.data
= g_malloc0(512);
585 strcpy(req
.data
, "TEST");
587 req_addr
= virtio_blk_request(alloc
, &req
, 512);
591 /* Notify after processing the third request */
592 qvirtqueue_set_used_event(&vqpci
->vq
, 2);
593 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 528, false, true);
594 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
595 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
597 /* No notification expected */
598 g_assert(!qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
599 QVIRTIO_BLK_TIMEOUT
));
601 status
= readb(req_addr
+ 528);
602 g_assert_cmpint(status
, ==, 0);
604 guest_free(alloc
, req_addr
);
607 req
.type
= QVIRTIO_BLK_T_IN
;
610 req
.data
= g_malloc0(512);
612 req_addr
= virtio_blk_request(alloc
, &req
, 512);
616 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
617 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 513, true, false);
619 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
622 g_assert(qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
623 QVIRTIO_BLK_TIMEOUT
));
625 status
= readb(req_addr
+ 528);
626 g_assert_cmpint(status
, ==, 0);
628 data
= g_malloc0(512);
629 memread(req_addr
+ 16, data
, 512);
630 g_assert_cmpstr(data
, ==, "TEST");
633 guest_free(alloc
, req_addr
);
636 guest_free(alloc
, vqpci
->vq
.desc
);
637 qpci_msix_disable(dev
->pdev
);
638 qvirtio_pci_device_disable(dev
);
643 int main(int argc
, char **argv
)
647 g_test_init(&argc
, &argv
, NULL
);
649 g_test_add_func("/virtio/blk/pci/basic", pci_basic
);
650 g_test_add_func("/virtio/blk/pci/indirect", pci_indirect
);
651 g_test_add_func("/virtio/blk/pci/config", pci_config
);
652 g_test_add_func("/virtio/blk/pci/msix", pci_msix
);
653 g_test_add_func("/virtio/blk/pci/idx", pci_idx
);