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 #define TEST_IMAGE_SIZE (64 * 1024 * 1024)
21 #define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
22 #define PCI_SLOT_HP 0x06
24 typedef struct QVirtioBlkReq
{
34 const bool host_is_big_endian
= true;
36 const bool host_is_big_endian
; /* false */
39 static void drive_destroy(void *path
)
43 qos_invalidate_command_line();
46 static char *drive_create(void)
51 /* Create a temporary raw image */
52 fd
= g_file_open_tmp("qtest.XXXXXX", &t_path
, NULL
);
53 g_assert_cmpint(fd
, >=, 0);
54 ret
= ftruncate(fd
, TEST_IMAGE_SIZE
);
55 g_assert_cmpint(ret
, ==, 0);
58 g_test_queue_destroy(drive_destroy
, t_path
);
62 static inline void virtio_blk_fix_request(QVirtioDevice
*d
, QVirtioBlkReq
*req
)
64 if (qvirtio_is_big_endian(d
) != host_is_big_endian
) {
65 req
->type
= bswap32(req
->type
);
66 req
->ioprio
= bswap32(req
->ioprio
);
67 req
->sector
= bswap64(req
->sector
);
72 static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice
*d
,
73 struct virtio_blk_discard_write_zeroes
*dwz_hdr
)
75 if (qvirtio_is_big_endian(d
) != host_is_big_endian
) {
76 dwz_hdr
->sector
= bswap64(dwz_hdr
->sector
);
77 dwz_hdr
->num_sectors
= bswap32(dwz_hdr
->num_sectors
);
78 dwz_hdr
->flags
= bswap32(dwz_hdr
->flags
);
82 static uint64_t virtio_blk_request(QGuestAllocator
*alloc
, QVirtioDevice
*d
,
83 QVirtioBlkReq
*req
, uint64_t data_size
)
86 uint8_t status
= 0xFF;
90 case VIRTIO_BLK_T_OUT
:
91 g_assert_cmpuint(data_size
% 512, ==, 0);
93 case VIRTIO_BLK_T_DISCARD
:
94 case VIRTIO_BLK_T_WRITE_ZEROES
:
95 g_assert_cmpuint(data_size
%
96 sizeof(struct virtio_blk_discard_write_zeroes
), ==, 0);
99 g_assert_cmpuint(data_size
, ==, 0);
102 addr
= guest_alloc(alloc
, sizeof(*req
) + data_size
);
104 virtio_blk_fix_request(d
, req
);
106 memwrite(addr
, req
, 16);
107 memwrite(addr
+ 16, req
->data
, data_size
);
108 memwrite(addr
+ 16 + data_size
, &status
, sizeof(status
));
113 /* Returns the request virtqueue so the caller can perform further tests */
114 static QVirtQueue
*test_basic(QVirtioDevice
*dev
, QGuestAllocator
*alloc
)
123 QTestState
*qts
= global_qtest
;
126 features
= qvirtio_get_features(dev
);
127 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
128 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
129 (1u << VIRTIO_RING_F_EVENT_IDX
) |
130 (1u << VIRTIO_BLK_F_SCSI
));
131 qvirtio_set_features(dev
, features
);
133 capacity
= qvirtio_config_readq(dev
, 0);
134 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
136 vq
= qvirtqueue_setup(dev
, alloc
, 0);
138 qvirtio_set_driver_ok(dev
);
140 /* Write and read with 3 descriptor layout */
142 req
.type
= VIRTIO_BLK_T_OUT
;
145 req
.data
= g_malloc0(512);
146 strcpy(req
.data
, "TEST");
148 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
152 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
153 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, false, true);
154 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
156 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
158 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
159 QVIRTIO_BLK_TIMEOUT_US
);
160 status
= readb(req_addr
+ 528);
161 g_assert_cmpint(status
, ==, 0);
163 guest_free(alloc
, req_addr
);
166 req
.type
= VIRTIO_BLK_T_IN
;
169 req
.data
= g_malloc0(512);
171 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
175 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
176 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, true, true);
177 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
179 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
181 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
182 QVIRTIO_BLK_TIMEOUT_US
);
183 status
= readb(req_addr
+ 528);
184 g_assert_cmpint(status
, ==, 0);
186 data
= g_malloc0(512);
187 memread(req_addr
+ 16, data
, 512);
188 g_assert_cmpstr(data
, ==, "TEST");
191 guest_free(alloc
, req_addr
);
193 if (features
& (1u << VIRTIO_BLK_F_WRITE_ZEROES
)) {
194 struct virtio_blk_discard_write_zeroes dwz_hdr
;
198 * WRITE_ZEROES request on the same sector of previous test where
201 req
.type
= VIRTIO_BLK_T_WRITE_ZEROES
;
202 req
.data
= (char *) &dwz_hdr
;
204 dwz_hdr
.num_sectors
= 1;
207 virtio_blk_fix_dwz_hdr(dev
, &dwz_hdr
);
209 req_addr
= virtio_blk_request(alloc
, dev
, &req
, sizeof(dwz_hdr
));
211 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
212 qvirtqueue_add(qts
, vq
, req_addr
+ 16, sizeof(dwz_hdr
), false, true);
213 qvirtqueue_add(qts
, vq
, req_addr
+ 16 + sizeof(dwz_hdr
), 1, true,
216 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
218 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
219 QVIRTIO_BLK_TIMEOUT_US
);
220 status
= readb(req_addr
+ 16 + sizeof(dwz_hdr
));
221 g_assert_cmpint(status
, ==, 0);
223 guest_free(alloc
, req_addr
);
225 /* Read request to check if the sector contains all zeroes */
226 req
.type
= VIRTIO_BLK_T_IN
;
229 req
.data
= g_malloc0(512);
231 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
235 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
236 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, true, true);
237 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
239 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
241 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
242 QVIRTIO_BLK_TIMEOUT_US
);
243 status
= readb(req_addr
+ 528);
244 g_assert_cmpint(status
, ==, 0);
246 data
= g_malloc(512);
247 expected
= g_malloc0(512);
248 memread(req_addr
+ 16, data
, 512);
249 g_assert_cmpmem(data
, 512, expected
, 512);
253 guest_free(alloc
, req_addr
);
256 if (features
& (1u << VIRTIO_BLK_F_DISCARD
)) {
257 struct virtio_blk_discard_write_zeroes dwz_hdr
;
259 req
.type
= VIRTIO_BLK_T_DISCARD
;
260 req
.data
= (char *) &dwz_hdr
;
262 dwz_hdr
.num_sectors
= 1;
265 virtio_blk_fix_dwz_hdr(dev
, &dwz_hdr
);
267 req_addr
= virtio_blk_request(alloc
, dev
, &req
, sizeof(dwz_hdr
));
269 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
270 qvirtqueue_add(qts
, vq
, req_addr
+ 16, sizeof(dwz_hdr
), false, true);
271 qvirtqueue_add(qts
, vq
, req_addr
+ 16 + sizeof(dwz_hdr
), 1, true, false);
273 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
275 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
276 QVIRTIO_BLK_TIMEOUT_US
);
277 status
= readb(req_addr
+ 16 + sizeof(dwz_hdr
));
278 g_assert_cmpint(status
, ==, 0);
280 guest_free(alloc
, req_addr
);
283 if (features
& (1u << VIRTIO_F_ANY_LAYOUT
)) {
284 /* Write and read with 2 descriptor layout */
286 req
.type
= VIRTIO_BLK_T_OUT
;
289 req
.data
= g_malloc0(512);
290 strcpy(req
.data
, "TEST");
292 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
296 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 528, false, true);
297 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
298 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
300 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
301 QVIRTIO_BLK_TIMEOUT_US
);
302 status
= readb(req_addr
+ 528);
303 g_assert_cmpint(status
, ==, 0);
305 guest_free(alloc
, req_addr
);
308 req
.type
= VIRTIO_BLK_T_IN
;
311 req
.data
= g_malloc0(512);
313 req_addr
= virtio_blk_request(alloc
, dev
, &req
, 512);
317 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
318 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 513, true, false);
320 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
322 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
323 QVIRTIO_BLK_TIMEOUT_US
);
324 status
= readb(req_addr
+ 528);
325 g_assert_cmpint(status
, ==, 0);
327 data
= g_malloc0(512);
328 memread(req_addr
+ 16, data
, 512);
329 g_assert_cmpstr(data
, ==, "TEST");
332 guest_free(alloc
, req_addr
);
338 static void basic(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
340 QVirtioBlk
*blk_if
= obj
;
343 vq
= test_basic(blk_if
->vdev
, t_alloc
);
344 qvirtqueue_cleanup(blk_if
->vdev
->bus
, vq
, t_alloc
);
348 static void indirect(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
351 QVirtioBlk
*blk_if
= obj
;
352 QVirtioDevice
*dev
= blk_if
->vdev
;
354 QVRingIndirectDesc
*indirect
;
361 QTestState
*qts
= global_qtest
;
363 features
= qvirtio_get_features(dev
);
364 g_assert_cmphex(features
& (1u << VIRTIO_RING_F_INDIRECT_DESC
), !=, 0);
365 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
366 (1u << VIRTIO_RING_F_EVENT_IDX
) |
367 (1u << VIRTIO_BLK_F_SCSI
));
368 qvirtio_set_features(dev
, features
);
370 capacity
= qvirtio_config_readq(dev
, 0);
371 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
373 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
374 qvirtio_set_driver_ok(dev
);
377 req
.type
= VIRTIO_BLK_T_OUT
;
380 req
.data
= g_malloc0(512);
381 strcpy(req
.data
, "TEST");
383 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
387 indirect
= qvring_indirect_desc_setup(qts
, dev
, t_alloc
, 2);
388 qvring_indirect_desc_add(dev
, qts
, indirect
, req_addr
, 528, false);
389 qvring_indirect_desc_add(dev
, qts
, indirect
, req_addr
+ 528, 1, true);
390 free_head
= qvirtqueue_add_indirect(qts
, vq
, indirect
);
391 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
393 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
394 QVIRTIO_BLK_TIMEOUT_US
);
395 status
= readb(req_addr
+ 528);
396 g_assert_cmpint(status
, ==, 0);
399 guest_free(t_alloc
, req_addr
);
402 req
.type
= VIRTIO_BLK_T_IN
;
405 req
.data
= g_malloc0(512);
406 strcpy(req
.data
, "TEST");
408 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
412 indirect
= qvring_indirect_desc_setup(qts
, dev
, t_alloc
, 2);
413 qvring_indirect_desc_add(dev
, qts
, indirect
, req_addr
, 16, false);
414 qvring_indirect_desc_add(dev
, qts
, indirect
, req_addr
+ 16, 513, true);
415 free_head
= qvirtqueue_add_indirect(qts
, vq
, indirect
);
416 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
418 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
419 QVIRTIO_BLK_TIMEOUT_US
);
420 status
= readb(req_addr
+ 528);
421 g_assert_cmpint(status
, ==, 0);
423 data
= g_malloc0(512);
424 memread(req_addr
+ 16, data
, 512);
425 g_assert_cmpstr(data
, ==, "TEST");
429 guest_free(t_alloc
, req_addr
);
430 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
433 static void config(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
435 QVirtioBlk
*blk_if
= obj
;
436 QVirtioDevice
*dev
= blk_if
->vdev
;
437 int n_size
= TEST_IMAGE_SIZE
/ 2;
441 features
= qvirtio_get_features(dev
);
442 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
443 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
444 (1u << VIRTIO_RING_F_EVENT_IDX
) |
445 (1u << VIRTIO_BLK_F_SCSI
));
446 qvirtio_set_features(dev
, features
);
448 capacity
= qvirtio_config_readq(dev
, 0);
449 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
451 qvirtio_set_driver_ok(dev
);
453 qtest_qmp_assert_success(global_qtest
,
454 "{ 'execute': 'block_resize', "
455 " 'arguments': { 'device': 'drive0', "
456 " 'size': %d } }", n_size
);
457 qvirtio_wait_config_isr(dev
, QVIRTIO_BLK_TIMEOUT_US
);
459 capacity
= qvirtio_config_readq(dev
, 0);
460 g_assert_cmpint(capacity
, ==, n_size
/ 512);
463 static void msix(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
466 QVirtioBlkPCI
*blk
= obj
;
467 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
468 QVirtioDevice
*dev
= &pdev
->vdev
;
470 int n_size
= TEST_IMAGE_SIZE
/ 2;
477 QOSGraphObject
*blk_object
= obj
;
478 QPCIDevice
*pci_dev
= blk_object
->get_driver(blk_object
, "pci-device");
479 QTestState
*qts
= global_qtest
;
481 if (qpci_check_buggy_msi(pci_dev
)) {
485 qpci_msix_enable(pdev
->pdev
);
486 qvirtio_pci_set_msix_configuration_vector(pdev
, t_alloc
, 0);
488 features
= qvirtio_get_features(dev
);
489 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
490 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
491 (1u << VIRTIO_RING_F_EVENT_IDX
) |
492 (1u << VIRTIO_BLK_F_SCSI
));
493 qvirtio_set_features(dev
, features
);
495 capacity
= qvirtio_config_readq(dev
, 0);
496 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
498 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
499 qvirtqueue_pci_msix_setup(pdev
, (QVirtQueuePCI
*)vq
, t_alloc
, 1);
501 qvirtio_set_driver_ok(dev
);
503 qtest_qmp_assert_success(global_qtest
,
504 "{ 'execute': 'block_resize', "
505 " 'arguments': { 'device': 'drive0', "
506 " 'size': %d } }", n_size
);
508 qvirtio_wait_config_isr(dev
, QVIRTIO_BLK_TIMEOUT_US
);
510 capacity
= qvirtio_config_readq(dev
, 0);
511 g_assert_cmpint(capacity
, ==, n_size
/ 512);
514 req
.type
= VIRTIO_BLK_T_OUT
;
517 req
.data
= g_malloc0(512);
518 strcpy(req
.data
, "TEST");
520 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
524 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
525 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, false, true);
526 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
527 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
529 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
530 QVIRTIO_BLK_TIMEOUT_US
);
532 status
= readb(req_addr
+ 528);
533 g_assert_cmpint(status
, ==, 0);
535 guest_free(t_alloc
, req_addr
);
538 req
.type
= VIRTIO_BLK_T_IN
;
541 req
.data
= g_malloc0(512);
543 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
547 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
548 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, true, true);
549 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
551 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
554 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
555 QVIRTIO_BLK_TIMEOUT_US
);
557 status
= readb(req_addr
+ 528);
558 g_assert_cmpint(status
, ==, 0);
560 data
= g_malloc0(512);
561 memread(req_addr
+ 16, data
, 512);
562 g_assert_cmpstr(data
, ==, "TEST");
565 guest_free(t_alloc
, req_addr
);
568 qpci_msix_disable(pdev
->pdev
);
569 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
572 static void idx(void *obj
, void *u_data
, QGuestAllocator
*t_alloc
)
575 QVirtioBlkPCI
*blk
= obj
;
576 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
577 QVirtioDevice
*dev
= &pdev
->vdev
;
587 QOSGraphObject
*blk_object
= obj
;
588 QPCIDevice
*pci_dev
= blk_object
->get_driver(blk_object
, "pci-device");
589 QTestState
*qts
= global_qtest
;
591 if (qpci_check_buggy_msi(pci_dev
)) {
595 qpci_msix_enable(pdev
->pdev
);
596 qvirtio_pci_set_msix_configuration_vector(pdev
, t_alloc
, 0);
598 features
= qvirtio_get_features(dev
);
599 features
= features
& ~(QVIRTIO_F_BAD_FEATURE
|
600 (1u << VIRTIO_RING_F_INDIRECT_DESC
) |
601 (1u << VIRTIO_F_NOTIFY_ON_EMPTY
) |
602 (1u << VIRTIO_BLK_F_SCSI
));
603 qvirtio_set_features(dev
, features
);
605 capacity
= qvirtio_config_readq(dev
, 0);
606 g_assert_cmpint(capacity
, ==, TEST_IMAGE_SIZE
/ 512);
608 vq
= qvirtqueue_setup(dev
, t_alloc
, 0);
609 qvirtqueue_pci_msix_setup(pdev
, (QVirtQueuePCI
*)vq
, t_alloc
, 1);
611 qvirtio_set_driver_ok(dev
);
614 req
.type
= VIRTIO_BLK_T_OUT
;
617 req
.data
= g_malloc0(512);
618 strcpy(req
.data
, "TEST");
620 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
624 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
625 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, false, true);
626 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
627 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
629 qvirtio_wait_used_elem(qts
, dev
, vq
, free_head
, NULL
,
630 QVIRTIO_BLK_TIMEOUT_US
);
633 req
.type
= VIRTIO_BLK_T_OUT
;
636 req
.data
= g_malloc0(512);
637 strcpy(req
.data
, "TEST");
639 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
643 /* Notify after processing the third request */
644 qvirtqueue_set_used_event(qts
, vq
, 2);
645 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
646 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, false, true);
647 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
648 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
649 write_head
= free_head
;
651 /* No notification expected */
652 status
= qvirtio_wait_status_byte_no_isr(qts
, dev
,
654 QVIRTIO_BLK_TIMEOUT_US
);
655 g_assert_cmpint(status
, ==, 0);
657 guest_free(t_alloc
, req_addr
);
660 req
.type
= VIRTIO_BLK_T_IN
;
663 req
.data
= g_malloc0(512);
665 req_addr
= virtio_blk_request(t_alloc
, dev
, &req
, 512);
669 free_head
= qvirtqueue_add(qts
, vq
, req_addr
, 16, false, true);
670 qvirtqueue_add(qts
, vq
, req_addr
+ 16, 512, true, true);
671 qvirtqueue_add(qts
, vq
, req_addr
+ 528, 1, true, false);
673 qvirtqueue_kick(qts
, dev
, vq
, free_head
);
675 /* We get just one notification for both requests */
676 qvirtio_wait_used_elem(qts
, dev
, vq
, write_head
, NULL
,
677 QVIRTIO_BLK_TIMEOUT_US
);
678 g_assert(qvirtqueue_get_buf(qts
, vq
, &desc_idx
, NULL
));
679 g_assert_cmpint(desc_idx
, ==, free_head
);
681 status
= readb(req_addr
+ 528);
682 g_assert_cmpint(status
, ==, 0);
684 data
= g_malloc0(512);
685 memread(req_addr
+ 16, data
, 512);
686 g_assert_cmpstr(data
, ==, "TEST");
689 guest_free(t_alloc
, req_addr
);
692 qpci_msix_disable(pdev
->pdev
);
694 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
697 static void pci_hotplug(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
699 QVirtioPCIDevice
*dev1
= obj
;
700 QVirtioPCIDevice
*dev
;
701 QTestState
*qts
= dev1
->pdev
->bus
->qts
;
703 if (dev1
->pdev
->bus
->not_hotpluggable
) {
704 g_test_skip("pci bus does not support hotplug");
708 /* plug secondary disk */
709 qtest_qmp_device_add(qts
, "virtio-blk-pci", "drv1",
710 "{'addr': %s, 'drive': 'drive1'}",
711 stringify(PCI_SLOT_HP
) ".0");
713 dev
= virtio_pci_new(dev1
->pdev
->bus
,
714 &(QPCIAddress
) { .devfn
= QPCI_DEVFN(PCI_SLOT_HP
, 0) });
715 g_assert_nonnull(dev
);
716 g_assert_cmpint(dev
->vdev
.device_type
, ==, VIRTIO_ID_BLOCK
);
717 qvirtio_pci_device_disable(dev
);
718 qos_object_destroy((QOSGraphObject
*)dev
);
720 /* unplug secondary disk */
721 qpci_unplug_acpi_device_test(qts
, "drv1", PCI_SLOT_HP
);
725 * Check that setting the vring addr on a non-existent virtqueue does
728 static void test_nonexistent_virtqueue(void *obj
, void *data
,
729 QGuestAllocator
*t_alloc
)
731 QVirtioBlkPCI
*blk
= obj
;
732 QVirtioPCIDevice
*pdev
= &blk
->pci_vdev
;
736 dev
= qpci_device_find(pdev
->pdev
->bus
, QPCI_DEVFN(4, 0));
737 g_assert(dev
!= NULL
);
738 qpci_device_enable(dev
);
740 bar0
= qpci_iomap(dev
, 0, NULL
);
742 qpci_io_writeb(dev
, bar0
, VIRTIO_PCI_QUEUE_SEL
, 2);
743 qpci_io_writel(dev
, bar0
, VIRTIO_PCI_QUEUE_PFN
, 1);
749 static void resize(void *obj
, void *data
, QGuestAllocator
*t_alloc
)
751 QVirtioBlk
*blk_if
= obj
;
752 QVirtioDevice
*dev
= blk_if
->vdev
;
753 int n_size
= TEST_IMAGE_SIZE
/ 2;
756 QTestState
*qts
= global_qtest
;
758 vq
= test_basic(dev
, t_alloc
);
760 qtest_qmp_assert_success(global_qtest
,
761 "{ 'execute': 'block_resize', "
762 " 'arguments': { 'device': 'drive0', "
763 " 'size': %d } }", n_size
);
765 qvirtio_wait_queue_isr(qts
, dev
, vq
, QVIRTIO_BLK_TIMEOUT_US
);
767 capacity
= qvirtio_config_readq(dev
, 0);
768 g_assert_cmpint(capacity
, ==, n_size
/ 512);
770 qvirtqueue_cleanup(dev
->bus
, vq
, t_alloc
);
774 static void *virtio_blk_test_setup(GString
*cmd_line
, void *arg
)
776 char *tmp_path
= drive_create();
778 g_string_append_printf(cmd_line
,
779 " -drive if=none,id=drive0,file=%s,"
780 "format=raw,auto-read-only=off "
781 "-drive if=none,id=drive1,file=null-co://,"
782 "file.read-zeroes=on,format=raw ",
788 static void register_virtio_blk_test(void)
790 QOSGraphTestOptions opts
= {
791 .before
= virtio_blk_test_setup
,
794 qos_add_test("indirect", "virtio-blk", indirect
, &opts
);
795 qos_add_test("config", "virtio-blk", config
, &opts
);
796 qos_add_test("basic", "virtio-blk", basic
, &opts
);
797 qos_add_test("resize", "virtio-blk", resize
, &opts
);
799 /* tests just for virtio-blk-pci */
800 qos_add_test("msix", "virtio-blk-pci", msix
, &opts
);
801 qos_add_test("idx", "virtio-blk-pci", idx
, &opts
);
802 qos_add_test("nxvirtq", "virtio-blk-pci",
803 test_nonexistent_virtqueue
, &opts
);
804 qos_add_test("hotplug", "virtio-blk-pci", pci_hotplug
, &opts
);
807 libqos_init(register_virtio_blk_test
);