xref: /openbmc/qemu/tests/qtest/virtio-blk-test.c (revision 2b74dd91)
1 /*
2  * QTest testcase for VirtIO Block Device
3  *
4  * Copyright (c) 2014 SUSE LINUX Products GmbH
5  * Copyright (c) 2014 Marc Marí
6  *
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  */
10 
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"
19 
20 #define TEST_IMAGE_SIZE         (64 * 1024 * 1024)
21 #define QVIRTIO_BLK_TIMEOUT_US  (30 * 1000 * 1000)
22 #define PCI_SLOT_HP             0x06
23 
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;
31 
32 
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
38 
39 static void drive_destroy(void *path)
40 {
41     unlink(path);
42     g_free(path);
43     qos_invalidate_command_line();
44 }
45 
46 static char *drive_create(void)
47 {
48     int fd, ret;
49     char *t_path;
50 
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);
57 
58     g_test_queue_destroy(drive_destroy, t_path);
59     return t_path;
60 }
61 
62 static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
63 {
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);
68     }
69 }
70 
71 
72 static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
73     struct virtio_blk_discard_write_zeroes *dwz_hdr)
74 {
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);
79     }
80 }
81 
82 static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
83                                    QVirtioBlkReq *req, uint64_t data_size)
84 {
85     uint64_t addr;
86     uint8_t status = 0xFF;
87 
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);
100     }
101 
102     addr = guest_alloc(alloc, sizeof(*req) + data_size);
103 
104     virtio_blk_fix_request(d, req);
105 
106     memwrite(addr, req, 16);
107     memwrite(addr + 16, req->data, data_size);
108     memwrite(addr + 16 + data_size, &status, sizeof(status));
109 
110     return addr;
111 }
112 
113 /* Returns the request virtqueue so the caller can perform further tests */
114 static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
115 {
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;
125 
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);
132 
133     capacity = qvirtio_config_readq(dev, 0);
134     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
135 
136     vq = qvirtqueue_setup(dev, alloc, 0);
137 
138     qvirtio_set_driver_ok(dev);
139 
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");
147 
148     req_addr = virtio_blk_request(alloc, dev, &req, 512);
149 
150     g_free(req.data);
151 
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);
155 
156     qvirtqueue_kick(qts, dev, vq, free_head);
157 
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);
162 
163     guest_free(alloc, req_addr);
164 
165     /* Read request */
166     req.type = VIRTIO_BLK_T_IN;
167     req.ioprio = 1;
168     req.sector = 0;
169     req.data = g_malloc0(512);
170 
171     req_addr = virtio_blk_request(alloc, dev, &req, 512);
172 
173     g_free(req.data);
174 
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);
178 
179     qvirtqueue_kick(qts, dev, vq, free_head);
180 
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);
185 
186     data = g_malloc0(512);
187     memread(req_addr + 16, data, 512);
188     g_assert_cmpstr(data, ==, "TEST");
189     g_free(data);
190 
191     guest_free(alloc, req_addr);
192 
193     if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
194         struct virtio_blk_discard_write_zeroes dwz_hdr;
195         void *expected;
196 
197         /*
198          * WRITE_ZEROES request on the same sector of previous test where
199          * we wrote "TEST".
200          */
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;
206 
207         virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
208 
209         req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
210 
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);
215 
216         qvirtqueue_kick(qts, dev, vq, free_head);
217 
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);
222 
223         guest_free(alloc, req_addr);
224 
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);
230 
231         req_addr = virtio_blk_request(alloc, dev, &req, 512);
232 
233         g_free(req.data);
234 
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);
238 
239         qvirtqueue_kick(qts, dev, vq, free_head);
240 
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);
245 
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);
252 
253         guest_free(alloc, req_addr);
254     }
255 
256     if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
257         struct virtio_blk_discard_write_zeroes dwz_hdr;
258 
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;
264 
265         virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
266 
267         req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
268 
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);
272 
273         qvirtqueue_kick(qts, dev, vq, free_head);
274 
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);
279 
280         guest_free(alloc, req_addr);
281     }
282 
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");
291 
292         req_addr = virtio_blk_request(alloc, dev, &req, 512);
293 
294         g_free(req.data);
295 
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);
299 
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);
304 
305         guest_free(alloc, req_addr);
306 
307         /* Read request */
308         req.type = VIRTIO_BLK_T_IN;
309         req.ioprio = 1;
310         req.sector = 1;
311         req.data = g_malloc0(512);
312 
313         req_addr = virtio_blk_request(alloc, dev, &req, 512);
314 
315         g_free(req.data);
316 
317         free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
318         qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
319 
320         qvirtqueue_kick(qts, dev, vq, free_head);
321 
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);
326 
327         data = g_malloc0(512);
328         memread(req_addr + 16, data, 512);
329         g_assert_cmpstr(data, ==, "TEST");
330         g_free(data);
331 
332         guest_free(alloc, req_addr);
333     }
334 
335     return vq;
336 }
337 
338 static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
339 {
340     QVirtioBlk *blk_if = obj;
341     QVirtQueue *vq;
342 
343     vq = test_basic(blk_if->vdev, t_alloc);
344     qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
345 
346 }
347 
348 static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
349 {
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;
362 
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);
369 
370     capacity = qvirtio_config_readq(dev, 0);
371     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
372 
373     vq = qvirtqueue_setup(dev, t_alloc, 0);
374     qvirtio_set_driver_ok(dev);
375 
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");
382 
383     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
384 
385     g_free(req.data);
386 
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);
392 
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);
397 
398     g_free(indirect);
399     guest_free(t_alloc, req_addr);
400 
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");
407 
408     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
409 
410     g_free(req.data);
411 
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);
417 
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);
422 
423     data = g_malloc0(512);
424     memread(req_addr + 16, data, 512);
425     g_assert_cmpstr(data, ==, "TEST");
426     g_free(data);
427 
428     g_free(indirect);
429     guest_free(t_alloc, req_addr);
430     qvirtqueue_cleanup(dev->bus, vq, t_alloc);
431 }
432 
433 static void config(void *obj, void *data, QGuestAllocator *t_alloc)
434 {
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;
440 
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);
447 
448     capacity = qvirtio_config_readq(dev, 0);
449     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
450 
451     qvirtio_set_driver_ok(dev);
452 
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);
458 
459     capacity = qvirtio_config_readq(dev, 0);
460     g_assert_cmpint(capacity, ==, n_size / 512);
461 }
462 
463 static void msix(void *obj, void *u_data, QGuestAllocator *t_alloc)
464 {
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;
480 
481     if (qpci_check_buggy_msi(pci_dev)) {
482         return;
483     }
484 
485     qpci_msix_enable(pdev->pdev);
486     qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
487 
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);
494 
495     capacity = qvirtio_config_readq(dev, 0);
496     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
497 
498     vq = qvirtqueue_setup(dev, t_alloc, 0);
499     qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
500 
501     qvirtio_set_driver_ok(dev);
502 
503     qtest_qmp_assert_success(global_qtest,
504                              "{ 'execute': 'block_resize', "
505                              " 'arguments': { 'device': 'drive0', "
506                              " 'size': %d } }", n_size);
507 
508     qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
509 
510     capacity = qvirtio_config_readq(dev, 0);
511     g_assert_cmpint(capacity, ==, n_size / 512);
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");
519 
520     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
521 
522     g_free(req.data);
523 
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);
528 
529     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
530                            QVIRTIO_BLK_TIMEOUT_US);
531 
532     status = readb(req_addr + 528);
533     g_assert_cmpint(status, ==, 0);
534 
535     guest_free(t_alloc, req_addr);
536 
537     /* Read request */
538     req.type = VIRTIO_BLK_T_IN;
539     req.ioprio = 1;
540     req.sector = 0;
541     req.data = g_malloc0(512);
542 
543     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
544 
545     g_free(req.data);
546 
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);
550 
551     qvirtqueue_kick(qts, dev, vq, free_head);
552 
553 
554     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
555                            QVIRTIO_BLK_TIMEOUT_US);
556 
557     status = readb(req_addr + 528);
558     g_assert_cmpint(status, ==, 0);
559 
560     data = g_malloc0(512);
561     memread(req_addr + 16, data, 512);
562     g_assert_cmpstr(data, ==, "TEST");
563     g_free(data);
564 
565     guest_free(t_alloc, req_addr);
566 
567     /* End test */
568     qpci_msix_disable(pdev->pdev);
569     qvirtqueue_cleanup(dev->bus, vq, t_alloc);
570 }
571 
572 static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
573 {
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;
590 
591     if (qpci_check_buggy_msi(pci_dev)) {
592         return;
593     }
594 
595     qpci_msix_enable(pdev->pdev);
596     qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
597 
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);
604 
605     capacity = qvirtio_config_readq(dev, 0);
606     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
607 
608     vq = qvirtqueue_setup(dev, t_alloc, 0);
609     qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
610 
611     qvirtio_set_driver_ok(dev);
612 
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");
619 
620     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
621 
622     g_free(req.data);
623 
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);
628 
629     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
630                            QVIRTIO_BLK_TIMEOUT_US);
631 
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");
638 
639     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
640 
641     g_free(req.data);
642 
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;
650 
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);
656 
657     guest_free(t_alloc, req_addr);
658 
659     /* Read request */
660     req.type = VIRTIO_BLK_T_IN;
661     req.ioprio = 1;
662     req.sector = 1;
663     req.data = g_malloc0(512);
664 
665     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
666 
667     g_free(req.data);
668 
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);
672 
673     qvirtqueue_kick(qts, dev, vq, free_head);
674 
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);
680 
681     status = readb(req_addr + 528);
682     g_assert_cmpint(status, ==, 0);
683 
684     data = g_malloc0(512);
685     memread(req_addr + 16, data, 512);
686     g_assert_cmpstr(data, ==, "TEST");
687     g_free(data);
688 
689     guest_free(t_alloc, req_addr);
690 
691     /* End test */
692     qpci_msix_disable(pdev->pdev);
693 
694     qvirtqueue_cleanup(dev->bus, vq, t_alloc);
695 }
696 
697 static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
698 {
699     QVirtioPCIDevice *dev1 = obj;
700     QVirtioPCIDevice *dev;
701     QTestState *qts = dev1->pdev->bus->qts;
702 
703     if (dev1->pdev->bus->not_hotpluggable) {
704         g_test_skip("pci bus does not support hotplug");
705         return;
706     }
707 
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");
712 
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);
719 
720     /* unplug secondary disk */
721     qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
722 }
723 
724 /*
725  * Check that setting the vring addr on a non-existent virtqueue does
726  * not crash.
727  */
728 static void test_nonexistent_virtqueue(void *obj, void *data,
729                                        QGuestAllocator *t_alloc)
730 {
731     QVirtioBlkPCI *blk = obj;
732     QVirtioPCIDevice *pdev = &blk->pci_vdev;
733     QPCIBar bar0;
734     QPCIDevice *dev;
735 
736     dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
737     g_assert(dev != NULL);
738     qpci_device_enable(dev);
739 
740     bar0 = qpci_iomap(dev, 0, NULL);
741 
742     qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
743     qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
744 
745 
746     g_free(dev);
747 }
748 
749 static void resize(void *obj, void *data, QGuestAllocator *t_alloc)
750 {
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;
757 
758     vq = test_basic(dev, t_alloc);
759 
760     qtest_qmp_assert_success(global_qtest,
761                              "{ 'execute': 'block_resize', "
762                              " 'arguments': { 'device': 'drive0', "
763                              " 'size': %d } }", n_size);
764 
765     qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
766 
767     capacity = qvirtio_config_readq(dev, 0);
768     g_assert_cmpint(capacity, ==, n_size / 512);
769 
770     qvirtqueue_cleanup(dev->bus, vq, t_alloc);
771 
772 }
773 
774 static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
775 {
776     char *tmp_path = drive_create();
777 
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);
784 
785     return arg;
786 }
787 
788 static void register_virtio_blk_test(void)
789 {
790     QOSGraphTestOptions opts = {
791         .before = virtio_blk_test_setup,
792     };
793 
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);
798 
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);
805 }
806 
807 libqos_init(register_virtio_blk_test);
808