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"
12 #include "libqtest-single.h"
13 #include "qemu/bswap.h"
14 #include "qemu/module.h"
15 #include "standard-headers/linux/virtio_blk.h"
16 #include "standard-headers/linux/virtio_pci.h"
17 #include "libqos/qgraph.h"
18 #include "libqos/virtio-blk.h"
20 /* TODO actually test the results and get rid of this */
21 #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
23 #define TEST_IMAGE_SIZE (64 * 1024 * 1024)
24 #define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
25 #define PCI_SLOT_HP 0x06
27 typedef struct QVirtioBlkReq
{
36 #ifdef HOST_WORDS_BIGENDIAN
37 const bool host_is_big_endian
= true;
39 const bool host_is_big_endian
; /* false */
42 static void drive_destroy(void *path
)
46 qos_invalidate_command_line();
49 static char *drive_create(void)
52 char *t_path
= g_strdup("/tmp/qtest.XXXXXX");
54 /* Create a temporary raw image */
56 g_assert_cmpint(fd
, >=, 0);
57 ret
= ftruncate(fd
, TEST_IMAGE_SIZE
);
58 g_assert_cmpint(ret
, ==, 0);
61 g_test_queue_destroy(drive_destroy
, t_path
);
65 static inline void virtio_blk_fix_request(QVirtioDevice
*d
, QVirtioBlkReq
*req
)
67 if (qvirtio_is_big_endian(d
) != host_is_big_endian
) {
68 req
->type
= bswap32(req
->type
);
69 req
->ioprio
= bswap32(req
->ioprio
);
70 req
->sector
= bswap64(req
->sector
);
75 static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice
*d
,
76 struct virtio_blk_discard_write_zeroes
*dwz_hdr
)
78 if (qvirtio_is_big_endian(d
) != host_is_big_endian
) {
79 dwz_hdr
->sector
= bswap64(dwz_hdr
->sector
);
80 dwz_hdr
->num_sectors
= bswap32(dwz_hdr
->num_sectors
);
81 dwz_hdr
->flags
= bswap32(dwz_hdr
->flags
);
85 static uint64_t virtio_blk_request(QGuestAllocator
*alloc
, QVirtioDevice
*d
,
86 QVirtioBlkReq
*req
, uint64_t data_size
)
89 uint8_t status
= 0xFF;
93 case VIRTIO_BLK_T_OUT
:
94 g_assert_cmpuint(data_size
% 512, ==, 0);
96 case VIRTIO_BLK_T_DISCARD
:
97 case VIRTIO_BLK_T_WRITE_ZEROES
:
98 g_assert_cmpuint(data_size
%
99 sizeof(struct virtio_blk_discard_write_zeroes
), ==, 0);
102 g_assert_cmpuint(data_size
, ==, 0);
105 addr
= guest_alloc(alloc
, sizeof(*req
) + data_size
);
107 virtio_blk_fix_request(d
, req
);
109 memwrite(addr
, req
, 16);
110 memwrite(addr
+ 16, req
->data
, data_size
);
111 memwrite(addr
+ 16 + data_size
, &status
, sizeof(status
));
116 /* Returns the request virtqueue so the caller can perform further tests */
117 static QVirtQueue
*test_basic(QVirtioDevice
*dev
, QGuestAllocator
*alloc
)
126 QTestState
*qts
= global_qtest
;
129 features
= qvirtio_get_features(dev
);
130 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
131 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
132 (1u << VIRTIO_RING_F_EVENT_IDX
) |
133 (1u << VIRTIO_BLK_F_SCSI
));
134 qvirtio_set_features(dev
, features
);
136 capacity
= qvirtio_config_readq(dev
, 0);
137 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
139 vq
= qvirtqueue_setup(dev
, alloc
, 0);
141 qvirtio_set_driver_ok(dev
);
143 /* Write and read with 3 descriptor layout */
145 req
.type
= VIRTIO_BLK_T_OUT
;
148 req
.data
= g_malloc0(512);
149 strcpy(req
.data
, "TEST");
151 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
155 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
156 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, false, true);
157 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
159 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
161 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
162 QVIRTIO_BLK_TIMEOUT_US
);
163 status
= readb(req_addr
+ 528);
164 g_assert_cmpint(status
, ==, 0);
166 guest_free(alloc
, req_addr
);
169 req
.type
= VIRTIO_BLK_T_IN
;
172 req
.data
= g_malloc0(512);
174 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
178 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
179 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, true, true);
180 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
182 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
184 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
185 QVIRTIO_BLK_TIMEOUT_US
);
186 status
= readb(req_addr
+ 528);
187 g_assert_cmpint(status
, ==, 0);
189 data
= g_malloc0(512);
190 memread(req_addr
+ 16, data
, 512);
191 g_assert_cmpstr(data
, ==, "TEST");
194 guest_free(alloc
, req_addr
);
196 if (features
& (1u << VIRTIO_BLK_F_WRITE_ZEROES
)) {
197 struct virtio_blk_discard_write_zeroes dwz_hdr
;
201 * WRITE_ZEROES request on the same sector of previous test where
204 req
.type
= VIRTIO_BLK_T_WRITE_ZEROES
;
205 req
.data
= (char *) &dwz_hdr
;
207 dwz_hdr
.num_sectors
= 1;
210 virtio_blk_fix_dwz_hdr(dev
, &dwz_hdr
);
212 req_addr
= virtio_blk_request(alloc
, dev
, &req
, sizeof(dwz_hdr
));
214 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
215 qvirtqueue_add(qts
, vq
, req_addr
+ 16, sizeof(dwz_hdr
), false, true);
216 qvirtqueue_add(qts
, vq
, req_addr
+ 16 + sizeof(dwz_hdr
), 1, true,
219 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
221 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
222 QVIRTIO_BLK_TIMEOUT_US
);
223 status
= readb(req_addr
+ 16 + sizeof(dwz_hdr
));
224 g_assert_cmpint(status
, ==, 0);
226 guest_free(alloc
, req_addr
);
228 /* Read request to check if the sector contains all zeroes */
229 req
.type
= VIRTIO_BLK_T_IN
;
232 req
.data
= g_malloc0(512);
234 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
238 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
239 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, true, true);
240 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
242 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
244 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
245 QVIRTIO_BLK_TIMEOUT_US
);
246 status
= readb(req_addr
+ 528);
247 g_assert_cmpint(status
, ==, 0);
249 data
= g_malloc(512);
250 expected
= g_malloc0(512);
251 memread(req_addr
+ 16, data
, 512);
252 g_assert_cmpmem(data
, 512, expected
, 512);
256 guest_free(alloc
, req_addr
);
259 if (features
& (1u << VIRTIO_BLK_F_DISCARD
)) {
260 struct virtio_blk_discard_write_zeroes dwz_hdr
;
262 req
.type
= VIRTIO_BLK_T_DISCARD
;
263 req
.data
= (char *) &dwz_hdr
;
265 dwz_hdr
.num_sectors
= 1;
268 virtio_blk_fix_dwz_hdr(dev
, &dwz_hdr
);
270 req_addr
= virtio_blk_request(alloc
, dev
, &req
, sizeof(dwz_hdr
));
272 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
273 qvirtqueue_add(qts
, vq
, req_addr
+ 16, sizeof(dwz_hdr
), false, true);
274 qvirtqueue_add(qts
, vq
, req_addr
+ 16 + sizeof(dwz_hdr
), 1, true, false);
276 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
278 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
279 QVIRTIO_BLK_TIMEOUT_US
);
280 status
= readb(req_addr
+ 16 + sizeof(dwz_hdr
));
281 g_assert_cmpint(status
, ==, 0);
283 guest_free(alloc
, req_addr
);
286 if (features
& (1u << VIRTIO_F_ANY_LAYOUT
)) {
287 /* Write and read with 2 descriptor layout */
289 req
.type
= VIRTIO_BLK_T_OUT
;
292 req
.data
= g_malloc0(512);
293 strcpy(req
.data
, "TEST");
295 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
299 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 528, false, true);
300 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
301 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
303 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
304 QVIRTIO_BLK_TIMEOUT_US
);
305 status
= readb(req_addr
+ 528);
306 g_assert_cmpint(status
, ==, 0);
308 guest_free(alloc
, req_addr
);
311 req
.type
= VIRTIO_BLK_T_IN
;
314 req
.data
= g_malloc0(512);
316 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
320 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
321 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 513, true, false);
323 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
325 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
326 QVIRTIO_BLK_TIMEOUT_US
);
327 status
= readb(req_addr
+ 528);
328 g_assert_cmpint(status
, ==, 0);
330 data
= g_malloc0(512);
331 memread(req_addr
+ 16, data
, 512);
332 g_assert_cmpstr(data
, ==, "TEST");
335 guest_free(alloc
, req_addr
);
341 static void basic(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
343 QVirtioBlk
*blk_if
= obj
;
346 vq
= test_basic(blk_if
->vdev
, t_alloc
);
347 qvirtqueue_cleanup(blk_if
->vdev
->bus
, vq
, t_alloc
);
351 static void indirect(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
354 QVirtioBlk
*blk_if
= obj
;
355 QVirtioDevice
*dev
= blk_if
->vdev
;
357 QVRingIndirectDesc
*indirect
;
364 QTestState
*qts
= global_qtest
;
366 features
= qvirtio_get_features(dev
);
367 g_assert_cmphex(features
& (1u << VIRTIO_RING_F_INDIRECT_DESC
), !=, 0);
368 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
369 (1u << VIRTIO_RING_F_EVENT_IDX
) |
370 (1u << VIRTIO_BLK_F_SCSI
));
371 qvirtio_set_features(dev
, features
);
373 capacity
= qvirtio_config_readq(dev
, 0);
374 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
376 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
377 qvirtio_set_driver_ok(dev
);
380 req
.type
= VIRTIO_BLK_T_OUT
;
383 req
.data
= g_malloc0(512);
384 strcpy(req
.data
, "TEST");
386 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
390 indirect
= qvring_indirect_desc_setup(qts
, dev
, t_alloc
, 2);
391 qvring_indirect_desc_add(dev
, qts
, indirect
, req_addr
, 528, false);
392 qvring_indirect_desc_add(dev
, qts
, indirect
, req_addr
+ 528, 1, true);
393 free_head
= qvirtqueue_add_indirect(qts
, vq
, indirect
);
394 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
396 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
397 QVIRTIO_BLK_TIMEOUT_US
);
398 status
= readb(req_addr
+ 528);
399 g_assert_cmpint(status
, ==, 0);
402 guest_free(t_alloc
, req_addr
);
405 req
.type
= VIRTIO_BLK_T_IN
;
408 req
.data
= g_malloc0(512);
409 strcpy(req
.data
, "TEST");
411 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
415 indirect
= qvring_indirect_desc_setup(qts
, dev
, t_alloc
, 2);
416 qvring_indirect_desc_add(dev
, qts
, indirect
, req_addr
, 16, false);
417 qvring_indirect_desc_add(dev
, qts
, indirect
, req_addr
+ 16, 513, true);
418 free_head
= qvirtqueue_add_indirect(qts
, vq
, indirect
);
419 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
421 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
422 QVIRTIO_BLK_TIMEOUT_US
);
423 status
= readb(req_addr
+ 528);
424 g_assert_cmpint(status
, ==, 0);
426 data
= g_malloc0(512);
427 memread(req_addr
+ 16, data
, 512);
428 g_assert_cmpstr(data
, ==, "TEST");
432 guest_free(t_alloc
, req_addr
);
433 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
436 static void config(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
438 QVirtioBlk
*blk_if
= obj
;
439 QVirtioDevice
*dev
= blk_if
->vdev
;
440 int n_size
= TEST_IMAGE_SIZE
/ 2;
444 features
= qvirtio_get_features(dev
);
445 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
446 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
447 (1u << VIRTIO_RING_F_EVENT_IDX
) |
448 (1u << VIRTIO_BLK_F_SCSI
));
449 qvirtio_set_features(dev
, features
);
451 capacity
= qvirtio_config_readq(dev
, 0);
452 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
454 qvirtio_set_driver_ok(dev
);
456 qmp_discard_response("{ 'execute': 'block_resize', "
457 " 'arguments': { 'device': 'drive0', "
458 " 'size': %d } }", n_size
);
459 qvirtio_wait_config_isr(dev
, QVIRTIO_BLK_TIMEOUT_US
);
461 capacity
= qvirtio_config_readq(dev
, 0);
462 g_assert_cmpint(capacity
, ==, n_size
/ 512);
465 static void msix(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
468 QVirtioBlkPCI
*blk
= obj
;
469 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
470 QVirtioDevice
*dev
= &pdev
->vdev
;
472 int n_size
= TEST_IMAGE_SIZE
/ 2;
479 QOSGraphObject
*blk_object
= obj
;
480 QPCIDevice
*pci_dev
= blk_object
->get_driver(blk_object
, "pci-device");
481 QTestState
*qts
= global_qtest
;
483 if (qpci_check_buggy_msi(pci_dev
)) {
487 qpci_msix_enable(pdev
->pdev
);
488 qvirtio_pci_set_msix_configuration_vector(pdev
, t_alloc
, 0);
490 features
= qvirtio_get_features(dev
);
491 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
492 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
493 (1u << VIRTIO_RING_F_EVENT_IDX
) |
494 (1u << VIRTIO_BLK_F_SCSI
));
495 qvirtio_set_features(dev
, features
);
497 capacity
= qvirtio_config_readq(dev
, 0);
498 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
500 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
501 qvirtqueue_pci_msix_setup(pdev
, (QVirtQueuePCI
*)vq
, t_alloc
, 1);
503 qvirtio_set_driver_ok(dev
);
505 qmp_discard_response("{ 'execute': 'block_resize', "
506 " 'arguments': { 'device': 'drive0', "
507 " 'size': %d } }", n_size
);
509 qvirtio_wait_config_isr(dev
, QVIRTIO_BLK_TIMEOUT_US
);
511 capacity
= qvirtio_config_readq(dev
, 0);
512 g_assert_cmpint(capacity
, ==, n_size
/ 512);
515 req
.type
= VIRTIO_BLK_T_OUT
;
518 req
.data
= g_malloc0(512);
519 strcpy(req
.data
, "TEST");
521 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
525 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
526 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, false, true);
527 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
528 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
530 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
531 QVIRTIO_BLK_TIMEOUT_US
);
533 status
= readb(req_addr
+ 528);
534 g_assert_cmpint(status
, ==, 0);
536 guest_free(t_alloc
, req_addr
);
539 req
.type
= VIRTIO_BLK_T_IN
;
542 req
.data
= g_malloc0(512);
544 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
548 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
549 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, true, true);
550 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
552 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
555 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
556 QVIRTIO_BLK_TIMEOUT_US
);
558 status
= readb(req_addr
+ 528);
559 g_assert_cmpint(status
, ==, 0);
561 data
= g_malloc0(512);
562 memread(req_addr
+ 16, data
, 512);
563 g_assert_cmpstr(data
, ==, "TEST");
566 guest_free(t_alloc
, req_addr
);
569 qpci_msix_disable(pdev
->pdev
);
570 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
573 static void idx(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
576 QVirtioBlkPCI
*blk
= obj
;
577 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
578 QVirtioDevice
*dev
= &pdev
->vdev
;
588 QOSGraphObject
*blk_object
= obj
;
589 QPCIDevice
*pci_dev
= blk_object
->get_driver(blk_object
, "pci-device");
590 QTestState
*qts
= global_qtest
;
592 if (qpci_check_buggy_msi(pci_dev
)) {
596 qpci_msix_enable(pdev
->pdev
);
597 qvirtio_pci_set_msix_configuration_vector(pdev
, t_alloc
, 0);
599 features
= qvirtio_get_features(dev
);
600 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
601 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
602 (1u << VIRTIO_F_NOTIFY_ON_EMPTY
) |
603 (1u << VIRTIO_BLK_F_SCSI
));
604 qvirtio_set_features(dev
, features
);
606 capacity
= qvirtio_config_readq(dev
, 0);
607 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
609 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
610 qvirtqueue_pci_msix_setup(pdev
, (QVirtQueuePCI
*)vq
, t_alloc
, 1);
612 qvirtio_set_driver_ok(dev
);
615 req
.type
= VIRTIO_BLK_T_OUT
;
618 req
.data
= g_malloc0(512);
619 strcpy(req
.data
, "TEST");
621 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
625 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
626 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, false, true);
627 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
628 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
630 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
631 QVIRTIO_BLK_TIMEOUT_US
);
634 req
.type
= VIRTIO_BLK_T_OUT
;
637 req
.data
= g_malloc0(512);
638 strcpy(req
.data
, "TEST");
640 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
644 /* Notify after processing the third request */
645 qvirtqueue_set_used_event(qts
, vq
, 2);
646 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
647 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, false, true);
648 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
649 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
650 write_head
= free_head
;
652 /* No notification expected */
653 status
= qvirtio_wait_status_byte_no_isr(qts
, dev
,
655 QVIRTIO_BLK_TIMEOUT_US
);
656 g_assert_cmpint(status
, ==, 0);
658 guest_free(t_alloc
, req_addr
);
661 req
.type
= VIRTIO_BLK_T_IN
;
664 req
.data
= g_malloc0(512);
666 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
670 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
671 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, true, true);
672 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
674 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
676 /* We get just one notification for both requests */
677 qvirtio_wait_used_elem(qts
, dev
, vq
, write_head
, NULL
,
678 QVIRTIO_BLK_TIMEOUT_US
);
679 g_assert(qvirtqueue_get_buf(qts
, vq
, &desc_idx
, NULL
));
680 g_assert_cmpint(desc_idx
, ==, free_head
);
682 status
= readb(req_addr
+ 528);
683 g_assert_cmpint(status
, ==, 0);
685 data
= g_malloc0(512);
686 memread(req_addr
+ 16, data
, 512);
687 g_assert_cmpstr(data
, ==, "TEST");
690 guest_free(t_alloc
, req_addr
);
693 qpci_msix_disable(pdev
->pdev
);
695 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
698 static void pci_hotplug(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
700 QVirtioPCIDevice
*dev1
= obj
;
701 QVirtioPCIDevice
*dev
;
702 QTestState
*qts
= dev1
->pdev
->bus
->qts
;
704 /* plug secondary disk */
705 qtest_qmp_device_add(qts
, "virtio-blk-pci", "drv1",
706 "{'addr': %s, 'drive': 'drive1'}",
707 stringify(PCI_SLOT_HP
) ".0");
709 dev
= virtio_pci_new(dev1
->pdev
->bus
,
710 &(QPCIAddress
) { .devfn
= QPCI_DEVFN(PCI_SLOT_HP
, 0) });
711 g_assert_nonnull(dev
);
712 g_assert_cmpint(dev
->vdev
.device_type
, ==, VIRTIO_ID_BLOCK
);
713 qvirtio_pci_device_disable(dev
);
714 qos_object_destroy((QOSGraphObject
*)dev
);
716 /* unplug secondary disk */
717 qpci_unplug_acpi_device_test(qts
, "drv1", PCI_SLOT_HP
);
721 * Check that setting the vring addr on a non-existent virtqueue does
724 static void test_nonexistent_virtqueue(void *obj
, void *data
,
725 QGuestAllocator
*t_alloc
)
727 QVirtioBlkPCI
*blk
= obj
;
728 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
732 dev
= qpci_device_find(pdev
->pdev
->bus
, QPCI_DEVFN(4, 0));
733 g_assert(dev
!= NULL
);
734 qpci_device_enable(dev
);
736 bar0
= qpci_iomap(dev
, 0, NULL
);
738 qpci_io_writeb(dev
, bar0
, VIRTIO_PCI_QUEUE_SEL
, 2);
739 qpci_io_writel(dev
, bar0
, VIRTIO_PCI_QUEUE_PFN
, 1);
745 static void resize(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
747 QVirtioBlk
*blk_if
= obj
;
748 QVirtioDevice
*dev
= blk_if
->vdev
;
749 int n_size
= TEST_IMAGE_SIZE
/ 2;
752 QTestState
*qts
= global_qtest
;
754 vq
= test_basic(dev
, t_alloc
);
756 qmp_discard_response("{ 'execute': 'block_resize', "
757 " 'arguments': { 'device': 'drive0', "
758 " 'size': %d } }", n_size
);
760 qvirtio_wait_queue_isr(qts
, dev
, vq
, QVIRTIO_BLK_TIMEOUT_US
);
762 capacity
= qvirtio_config_readq(dev
, 0);
763 g_assert_cmpint(capacity
, ==, n_size
/ 512);
765 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
769 static void *virtio_blk_test_setup(GString
*cmd_line
, void *arg
)
771 char *tmp_path
= drive_create();
773 g_string_append_printf(cmd_line
,
774 " -drive if=none,id=drive0,file=%s,"
775 "format=raw,auto-read-only=off "
776 "-drive if=none,id=drive1,file=null-co://,"
777 "file.read-zeroes=on,format=raw ",
783 static void register_virtio_blk_test(void)
785 QOSGraphTestOptions opts
= {
786 .before
= virtio_blk_test_setup
,
789 qos_add_test("indirect", "virtio-blk", indirect
, &opts
);
790 qos_add_test("config", "virtio-blk", config
, &opts
);
791 qos_add_test("basic", "virtio-blk", basic
, &opts
);
792 qos_add_test("resize", "virtio-blk", resize
, &opts
);
794 /* tests just for virtio-blk-pci */
795 qos_add_test("msix", "virtio-blk-pci", msix
, &opts
);
796 qos_add_test("idx", "virtio-blk-pci", idx
, &opts
);
797 qos_add_test("nxvirtq", "virtio-blk-pci",
798 test_nonexistent_virtqueue
, &opts
);
799 qos_add_test("hotplug", "virtio-blk-pci", pci_hotplug
, &opts
);
802 libqos_init(register_virtio_blk_test
);