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 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 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
187 QVIRTIO_BLK_TIMEOUT_US
);
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 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
209 QVIRTIO_BLK_TIMEOUT_US
);
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 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
237 QVIRTIO_BLK_TIMEOUT_US
);
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 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
260 QVIRTIO_BLK_TIMEOUT_US
);
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 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
333 QVIRTIO_BLK_TIMEOUT_US
);
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 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
358 QVIRTIO_BLK_TIMEOUT_US
);
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 qvirtio_wait_config_isr(&qvirtio_pci
, &dev
->vdev
, QVIRTIO_BLK_TIMEOUT_US
);
401 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
402 g_assert_cmpint(capacity
, ==, n_size
/ 512);
404 qvirtio_pci_device_disable(dev
);
409 static void pci_msix(void)
411 QVirtioPCIDevice
*dev
;
413 QVirtQueuePCI
*vqpci
;
414 QGuestAllocator
*alloc
;
416 int n_size
= TEST_IMAGE_SIZE
/ 2;
426 alloc
= pc_alloc_init();
428 dev
= virtio_blk_init(bus
);
429 qpci_msix_enable(dev
->pdev
);
431 qvirtio_pci_set_msix_configuration_vector(dev
, alloc
, 0);
433 /* MSI-X is enabled */
434 addr
= dev
->addr
+ QVIRTIO_DEVICE_SPECIFIC_MSIX
;
436 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
437 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
439 features
= qvirtio_get_features(&qvirtio_pci
, &dev
->vdev
);
440 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
441 QVIRTIO_F_RING_INDIRECT_DESC
|
442 QVIRTIO_F_RING_EVENT_IDX
| QVIRTIO_BLK_F_SCSI
);
443 qvirtio_set_features(&qvirtio_pci
, &dev
->vdev
, features
);
445 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&qvirtio_pci
, &dev
->vdev
,
447 qvirtqueue_pci_msix_setup(dev
, vqpci
, alloc
, 1);
449 qvirtio_set_driver_ok(&qvirtio_pci
, &dev
->vdev
);
451 qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
452 " 'size': %d } }", n_size
);
454 qvirtio_wait_config_isr(&qvirtio_pci
, &dev
->vdev
, QVIRTIO_BLK_TIMEOUT_US
);
456 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
457 g_assert_cmpint(capacity
, ==, n_size
/ 512);
460 req
.type
= QVIRTIO_BLK_T_OUT
;
463 req
.data
= g_malloc0(512);
464 strcpy(req
.data
, "TEST");
466 req_addr
= virtio_blk_request(alloc
, &req
, 512);
470 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 528, false, true);
471 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
472 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
474 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
475 QVIRTIO_BLK_TIMEOUT_US
);
477 status
= readb(req_addr
+ 528);
478 g_assert_cmpint(status
, ==, 0);
480 guest_free(alloc
, req_addr
);
483 req
.type
= QVIRTIO_BLK_T_IN
;
486 req
.data
= g_malloc0(512);
488 req_addr
= virtio_blk_request(alloc
, &req
, 512);
492 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
493 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 513, true, false);
495 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
498 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
499 QVIRTIO_BLK_TIMEOUT_US
);
501 status
= readb(req_addr
+ 528);
502 g_assert_cmpint(status
, ==, 0);
504 data
= g_malloc0(512);
505 memread(req_addr
+ 16, data
, 512);
506 g_assert_cmpstr(data
, ==, "TEST");
509 guest_free(alloc
, req_addr
);
512 guest_free(alloc
, (uint64_t)vqpci
->vq
.desc
);
513 qpci_msix_disable(dev
->pdev
);
514 qvirtio_pci_device_disable(dev
);
519 static void pci_idx(void)
521 QVirtioPCIDevice
*dev
;
523 QVirtQueuePCI
*vqpci
;
524 QGuestAllocator
*alloc
;
535 alloc
= pc_alloc_init();
537 dev
= virtio_blk_init(bus
);
538 qpci_msix_enable(dev
->pdev
);
540 qvirtio_pci_set_msix_configuration_vector(dev
, alloc
, 0);
542 /* MSI-X is enabled */
543 addr
= dev
->addr
+ QVIRTIO_DEVICE_SPECIFIC_MSIX
;
545 capacity
= qvirtio_config_readq(&qvirtio_pci
, &dev
->vdev
, addr
);
546 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
548 features
= qvirtio_get_features(&qvirtio_pci
, &dev
->vdev
);
549 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
550 QVIRTIO_F_RING_INDIRECT_DESC
|
551 QVIRTIO_F_NOTIFY_ON_EMPTY
| QVIRTIO_BLK_F_SCSI
);
552 qvirtio_set_features(&qvirtio_pci
, &dev
->vdev
, features
);
554 vqpci
= (QVirtQueuePCI
*)qvirtqueue_setup(&qvirtio_pci
, &dev
->vdev
,
556 qvirtqueue_pci_msix_setup(dev
, vqpci
, alloc
, 1);
558 qvirtio_set_driver_ok(&qvirtio_pci
, &dev
->vdev
);
561 req
.type
= QVIRTIO_BLK_T_OUT
;
564 req
.data
= g_malloc0(512);
565 strcpy(req
.data
, "TEST");
567 req_addr
= virtio_blk_request(alloc
, &req
, 512);
571 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 528, false, true);
572 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
573 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
575 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
576 QVIRTIO_BLK_TIMEOUT_US
);
579 req
.type
= QVIRTIO_BLK_T_OUT
;
582 req
.data
= g_malloc0(512);
583 strcpy(req
.data
, "TEST");
585 req_addr
= virtio_blk_request(alloc
, &req
, 512);
589 /* Notify after processing the third request */
590 qvirtqueue_set_used_event(&vqpci
->vq
, 2);
591 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 528, false, true);
592 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 528, 1, true, false);
593 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
595 /* No notification expected */
596 status
= qvirtio_wait_status_byte_no_isr(&qvirtio_pci
, &dev
->vdev
,
597 &vqpci
->vq
, req_addr
+ 528,
598 QVIRTIO_BLK_TIMEOUT_US
);
599 g_assert_cmpint(status
, ==, 0);
601 guest_free(alloc
, req_addr
);
604 req
.type
= QVIRTIO_BLK_T_IN
;
607 req
.data
= g_malloc0(512);
609 req_addr
= virtio_blk_request(alloc
, &req
, 512);
613 free_head
= qvirtqueue_add(&vqpci
->vq
, req_addr
, 16, false, true);
614 qvirtqueue_add(&vqpci
->vq
, req_addr
+ 16, 513, true, false);
616 qvirtqueue_kick(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
, free_head
);
619 qvirtio_wait_queue_isr(&qvirtio_pci
, &dev
->vdev
, &vqpci
->vq
,
620 QVIRTIO_BLK_TIMEOUT_US
);
622 status
= readb(req_addr
+ 528);
623 g_assert_cmpint(status
, ==, 0);
625 data
= g_malloc0(512);
626 memread(req_addr
+ 16, data
, 512);
627 g_assert_cmpstr(data
, ==, "TEST");
630 guest_free(alloc
, req_addr
);
633 guest_free(alloc
, vqpci
->vq
.desc
);
634 qpci_msix_disable(dev
->pdev
);
635 qvirtio_pci_device_disable(dev
);
640 int main(int argc
, char **argv
)
644 g_test_init(&argc
, &argv
, NULL
);
646 g_test_add_func("/virtio/blk/pci/basic", pci_basic
);
647 g_test_add_func("/virtio/blk/pci/indirect", pci_indirect
);
648 g_test_add_func("/virtio/blk/pci/config", pci_config
);
649 g_test_add_func("/virtio/blk/pci/msix", pci_msix
);
650 g_test_add_func("/virtio/blk/pci/idx", pci_idx
);