Merge tag 'v9.1.0'
[qemu/ar7.git] / tests / qtest / virtio-blk-test.c
blob98c906ebb4ad4541d05cc660d791dde0961bac4d
1 /*
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.
9 */
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 {
25 uint32_t type;
26 uint32_t ioprio;
27 uint64_t sector;
28 char *data;
29 uint8_t status;
30 } QVirtioBlkReq;
33 #if HOST_BIG_ENDIAN
34 const bool host_is_big_endian = true;
35 #else
36 const bool host_is_big_endian; /* false */
37 #endif
39 static void drive_destroy(void *path)
41 unlink(path);
42 g_free(path);
43 qos_invalidate_command_line();
46 static char *drive_create(void)
48 int fd, ret;
49 char *t_path;
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);
56 close(fd);
58 g_test_queue_destroy(drive_destroy, t_path);
59 return 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)
85 uint64_t addr;
86 uint8_t status = 0xFF;
88 switch (req->type) {
89 case VIRTIO_BLK_T_IN:
90 case VIRTIO_BLK_T_OUT:
91 g_assert_cmpuint(data_size % 512, ==, 0);
92 break;
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);
97 break;
98 default:
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));
110 return addr;
113 /* Returns the request virtqueue so the caller can perform further tests */
114 static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
116 QVirtioBlkReq req;
117 uint64_t req_addr;
118 uint64_t capacity;
119 uint64_t features;
120 uint32_t free_head;
121 uint8_t status;
122 char *data;
123 QTestState *qts = global_qtest;
124 QVirtQueue *vq;
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 */
141 /* Write request */
142 req.type = VIRTIO_BLK_T_OUT;
143 req.ioprio = 1;
144 req.sector = 0;
145 req.data = g_malloc0(512);
146 strcpy(req.data, "TEST");
148 req_addr = virtio_blk_request(alloc, dev, &req, 512);
150 g_free(req.data);
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);
165 /* Read request */
166 req.type = VIRTIO_BLK_T_IN;
167 req.ioprio = 1;
168 req.sector = 0;
169 req.data = g_malloc0(512);
171 req_addr = virtio_blk_request(alloc, dev, &req, 512);
173 g_free(req.data);
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");
189 g_free(data);
191 guest_free(alloc, req_addr);
193 if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
194 struct virtio_blk_discard_write_zeroes dwz_hdr;
195 void *expected;
198 * WRITE_ZEROES request on the same sector of previous test where
199 * we wrote "TEST".
201 req.type = VIRTIO_BLK_T_WRITE_ZEROES;
202 req.data = (char *) &dwz_hdr;
203 dwz_hdr.sector = 0;
204 dwz_hdr.num_sectors = 1;
205 dwz_hdr.flags = 0;
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,
214 false);
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;
227 req.ioprio = 1;
228 req.sector = 0;
229 req.data = g_malloc0(512);
231 req_addr = virtio_blk_request(alloc, dev, &req, 512);
233 g_free(req.data);
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);
250 g_free(expected);
251 g_free(data);
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;
261 dwz_hdr.sector = 0;
262 dwz_hdr.num_sectors = 1;
263 dwz_hdr.flags = 0;
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 */
285 /* Write request */
286 req.type = VIRTIO_BLK_T_OUT;
287 req.ioprio = 1;
288 req.sector = 1;
289 req.data = g_malloc0(512);
290 strcpy(req.data, "TEST");
292 req_addr = virtio_blk_request(alloc, dev, &req, 512);
294 g_free(req.data);
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);
307 /* Read request */
308 req.type = VIRTIO_BLK_T_IN;
309 req.ioprio = 1;
310 req.sector = 1;
311 req.data = g_malloc0(512);
313 req_addr = virtio_blk_request(alloc, dev, &req, 512);
315 g_free(req.data);
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");
330 g_free(data);
332 guest_free(alloc, req_addr);
335 return vq;
338 static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
340 QVirtioBlk *blk_if = obj;
341 QVirtQueue *vq;
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)
350 QVirtQueue *vq;
351 QVirtioBlk *blk_if = obj;
352 QVirtioDevice *dev = blk_if->vdev;
353 QVirtioBlkReq req;
354 QVRingIndirectDesc *indirect;
355 uint64_t req_addr;
356 uint64_t capacity;
357 uint64_t features;
358 uint32_t free_head;
359 uint8_t status;
360 char *data;
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);
376 /* Write request */
377 req.type = VIRTIO_BLK_T_OUT;
378 req.ioprio = 1;
379 req.sector = 0;
380 req.data = g_malloc0(512);
381 strcpy(req.data, "TEST");
383 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
385 g_free(req.data);
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);
398 g_free(indirect);
399 guest_free(t_alloc, req_addr);
401 /* Read request */
402 req.type = VIRTIO_BLK_T_IN;
403 req.ioprio = 1;
404 req.sector = 0;
405 req.data = g_malloc0(512);
406 strcpy(req.data, "TEST");
408 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
410 g_free(req.data);
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");
426 g_free(data);
428 g_free(indirect);
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;
438 uint64_t features;
439 uint64_t capacity;
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)
465 QVirtQueue *vq;
466 QVirtioBlkPCI *blk = obj;
467 QVirtioPCIDevice *pdev = &blk->pci_vdev;
468 QVirtioDevice *dev = &pdev->vdev;
469 QVirtioBlkReq req;
470 int n_size = TEST_IMAGE_SIZE / 2;
471 uint64_t req_addr;
472 uint64_t capacity;
473 uint64_t features;
474 uint32_t free_head;
475 uint8_t status;
476 char *data;
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)) {
482 return;
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);
513 /* Write request */
514 req.type = VIRTIO_BLK_T_OUT;
515 req.ioprio = 1;
516 req.sector = 0;
517 req.data = g_malloc0(512);
518 strcpy(req.data, "TEST");
520 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
522 g_free(req.data);
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);
537 /* Read request */
538 req.type = VIRTIO_BLK_T_IN;
539 req.ioprio = 1;
540 req.sector = 0;
541 req.data = g_malloc0(512);
543 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
545 g_free(req.data);
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");
563 g_free(data);
565 guest_free(t_alloc, req_addr);
567 /* End test */
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)
574 QVirtQueue *vq;
575 QVirtioBlkPCI *blk = obj;
576 QVirtioPCIDevice *pdev = &blk->pci_vdev;
577 QVirtioDevice *dev = &pdev->vdev;
578 QVirtioBlkReq req;
579 uint64_t req_addr;
580 uint64_t capacity;
581 uint64_t features;
582 uint32_t free_head;
583 uint32_t write_head;
584 uint32_t desc_idx;
585 uint8_t status;
586 char *data;
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)) {
592 return;
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);
613 /* Write request */
614 req.type = VIRTIO_BLK_T_OUT;
615 req.ioprio = 1;
616 req.sector = 0;
617 req.data = g_malloc0(512);
618 strcpy(req.data, "TEST");
620 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
622 g_free(req.data);
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);
632 /* Write request */
633 req.type = VIRTIO_BLK_T_OUT;
634 req.ioprio = 1;
635 req.sector = 1;
636 req.data = g_malloc0(512);
637 strcpy(req.data, "TEST");
639 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
641 g_free(req.data);
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,
653 vq, req_addr + 528,
654 QVIRTIO_BLK_TIMEOUT_US);
655 g_assert_cmpint(status, ==, 0);
657 guest_free(t_alloc, req_addr);
659 /* Read request */
660 req.type = VIRTIO_BLK_T_IN;
661 req.ioprio = 1;
662 req.sector = 1;
663 req.data = g_malloc0(512);
665 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
667 g_free(req.data);
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");
687 g_free(data);
689 guest_free(t_alloc, req_addr);
691 /* End test */
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");
705 return;
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
726 * not crash.
728 static void test_nonexistent_virtqueue(void *obj, void *data,
729 QGuestAllocator *t_alloc)
731 QVirtioBlkPCI *blk = obj;
732 QVirtioPCIDevice *pdev = &blk->pci_vdev;
733 QPCIBar bar0;
734 QPCIDevice *dev;
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);
746 g_free(dev);
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;
754 uint64_t capacity;
755 QVirtQueue *vq;
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 ",
783 tmp_path);
785 return arg;
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);