xref: /openbmc/qemu/tests/qtest/virtio-blk-test.c (revision 49f95221)
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 /* TODO actually test the results and get rid of this */
21 #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
22 
23 #define TEST_IMAGE_SIZE         (64 * 1024 * 1024)
24 #define QVIRTIO_BLK_TIMEOUT_US  (30 * 1000 * 1000)
25 #define PCI_SLOT_HP             0x06
26 
27 typedef struct QVirtioBlkReq {
28     uint32_t type;
29     uint32_t ioprio;
30     uint64_t sector;
31     char *data;
32     uint8_t status;
33 } QVirtioBlkReq;
34 
35 
36 #if HOST_BIG_ENDIAN
37 const bool host_is_big_endian = true;
38 #else
39 const bool host_is_big_endian; /* false */
40 #endif
41 
42 static void drive_destroy(void *path)
43 {
44     unlink(path);
45     g_free(path);
46     qos_invalidate_command_line();
47 }
48 
49 static char *drive_create(void)
50 {
51     int fd, ret;
52     char *t_path = g_strdup("/tmp/qtest.XXXXXX");
53 
54     /* Create a temporary raw image */
55     fd = mkstemp(t_path);
56     g_assert_cmpint(fd, >=, 0);
57     ret = ftruncate(fd, TEST_IMAGE_SIZE);
58     g_assert_cmpint(ret, ==, 0);
59     close(fd);
60 
61     g_test_queue_destroy(drive_destroy, t_path);
62     return t_path;
63 }
64 
65 static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
66 {
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);
71     }
72 }
73 
74 
75 static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
76     struct virtio_blk_discard_write_zeroes *dwz_hdr)
77 {
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);
82     }
83 }
84 
85 static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
86                                    QVirtioBlkReq *req, uint64_t data_size)
87 {
88     uint64_t addr;
89     uint8_t status = 0xFF;
90 
91     switch (req->type) {
92     case VIRTIO_BLK_T_IN:
93     case VIRTIO_BLK_T_OUT:
94         g_assert_cmpuint(data_size % 512, ==, 0);
95         break;
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);
100         break;
101     default:
102         g_assert_cmpuint(data_size, ==, 0);
103     }
104 
105     addr = guest_alloc(alloc, sizeof(*req) + data_size);
106 
107     virtio_blk_fix_request(d, req);
108 
109     memwrite(addr, req, 16);
110     memwrite(addr + 16, req->data, data_size);
111     memwrite(addr + 16 + data_size, &status, sizeof(status));
112 
113     return addr;
114 }
115 
116 /* Returns the request virtqueue so the caller can perform further tests */
117 static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
118 {
119     QVirtioBlkReq req;
120     uint64_t req_addr;
121     uint64_t capacity;
122     uint64_t features;
123     uint32_t free_head;
124     uint8_t status;
125     char *data;
126     QTestState *qts = global_qtest;
127     QVirtQueue *vq;
128 
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);
135 
136     capacity = qvirtio_config_readq(dev, 0);
137     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
138 
139     vq = qvirtqueue_setup(dev, alloc, 0);
140 
141     qvirtio_set_driver_ok(dev);
142 
143     /* Write and read with 3 descriptor layout */
144     /* Write request */
145     req.type = VIRTIO_BLK_T_OUT;
146     req.ioprio = 1;
147     req.sector = 0;
148     req.data = g_malloc0(512);
149     strcpy(req.data, "TEST");
150 
151     req_addr = virtio_blk_request(alloc, dev, &req, 512);
152 
153     g_free(req.data);
154 
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);
158 
159     qvirtqueue_kick(qts, dev, vq, free_head);
160 
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);
165 
166     guest_free(alloc, req_addr);
167 
168     /* Read request */
169     req.type = VIRTIO_BLK_T_IN;
170     req.ioprio = 1;
171     req.sector = 0;
172     req.data = g_malloc0(512);
173 
174     req_addr = virtio_blk_request(alloc, dev, &req, 512);
175 
176     g_free(req.data);
177 
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);
181 
182     qvirtqueue_kick(qts, dev, vq, free_head);
183 
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);
188 
189     data = g_malloc0(512);
190     memread(req_addr + 16, data, 512);
191     g_assert_cmpstr(data, ==, "TEST");
192     g_free(data);
193 
194     guest_free(alloc, req_addr);
195 
196     if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
197         struct virtio_blk_discard_write_zeroes dwz_hdr;
198         void *expected;
199 
200         /*
201          * WRITE_ZEROES request on the same sector of previous test where
202          * we wrote "TEST".
203          */
204         req.type = VIRTIO_BLK_T_WRITE_ZEROES;
205         req.data = (char *) &dwz_hdr;
206         dwz_hdr.sector = 0;
207         dwz_hdr.num_sectors = 1;
208         dwz_hdr.flags = 0;
209 
210         virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
211 
212         req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
213 
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,
217                        false);
218 
219         qvirtqueue_kick(qts, dev, vq, free_head);
220 
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);
225 
226         guest_free(alloc, req_addr);
227 
228         /* Read request to check if the sector contains all zeroes */
229         req.type = VIRTIO_BLK_T_IN;
230         req.ioprio = 1;
231         req.sector = 0;
232         req.data = g_malloc0(512);
233 
234         req_addr = virtio_blk_request(alloc, dev, &req, 512);
235 
236         g_free(req.data);
237 
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);
241 
242         qvirtqueue_kick(qts, dev, vq, free_head);
243 
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);
248 
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);
253         g_free(expected);
254         g_free(data);
255 
256         guest_free(alloc, req_addr);
257     }
258 
259     if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
260         struct virtio_blk_discard_write_zeroes dwz_hdr;
261 
262         req.type = VIRTIO_BLK_T_DISCARD;
263         req.data = (char *) &dwz_hdr;
264         dwz_hdr.sector = 0;
265         dwz_hdr.num_sectors = 1;
266         dwz_hdr.flags = 0;
267 
268         virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
269 
270         req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
271 
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);
275 
276         qvirtqueue_kick(qts, dev, vq, free_head);
277 
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);
282 
283         guest_free(alloc, req_addr);
284     }
285 
286     if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
287         /* Write and read with 2 descriptor layout */
288         /* Write request */
289         req.type = VIRTIO_BLK_T_OUT;
290         req.ioprio = 1;
291         req.sector = 1;
292         req.data = g_malloc0(512);
293         strcpy(req.data, "TEST");
294 
295         req_addr = virtio_blk_request(alloc, dev, &req, 512);
296 
297         g_free(req.data);
298 
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);
302 
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);
307 
308         guest_free(alloc, req_addr);
309 
310         /* Read request */
311         req.type = VIRTIO_BLK_T_IN;
312         req.ioprio = 1;
313         req.sector = 1;
314         req.data = g_malloc0(512);
315 
316         req_addr = virtio_blk_request(alloc, dev, &req, 512);
317 
318         g_free(req.data);
319 
320         free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
321         qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
322 
323         qvirtqueue_kick(qts, dev, vq, free_head);
324 
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);
329 
330         data = g_malloc0(512);
331         memread(req_addr + 16, data, 512);
332         g_assert_cmpstr(data, ==, "TEST");
333         g_free(data);
334 
335         guest_free(alloc, req_addr);
336     }
337 
338     return vq;
339 }
340 
341 static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
342 {
343     QVirtioBlk *blk_if = obj;
344     QVirtQueue *vq;
345 
346     vq = test_basic(blk_if->vdev, t_alloc);
347     qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
348 
349 }
350 
351 static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
352 {
353     QVirtQueue *vq;
354     QVirtioBlk *blk_if = obj;
355     QVirtioDevice *dev = blk_if->vdev;
356     QVirtioBlkReq req;
357     QVRingIndirectDesc *indirect;
358     uint64_t req_addr;
359     uint64_t capacity;
360     uint64_t features;
361     uint32_t free_head;
362     uint8_t status;
363     char *data;
364     QTestState *qts = global_qtest;
365 
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);
372 
373     capacity = qvirtio_config_readq(dev, 0);
374     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
375 
376     vq = qvirtqueue_setup(dev, t_alloc, 0);
377     qvirtio_set_driver_ok(dev);
378 
379     /* Write request */
380     req.type = VIRTIO_BLK_T_OUT;
381     req.ioprio = 1;
382     req.sector = 0;
383     req.data = g_malloc0(512);
384     strcpy(req.data, "TEST");
385 
386     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
387 
388     g_free(req.data);
389 
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);
395 
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);
400 
401     g_free(indirect);
402     guest_free(t_alloc, req_addr);
403 
404     /* Read request */
405     req.type = VIRTIO_BLK_T_IN;
406     req.ioprio = 1;
407     req.sector = 0;
408     req.data = g_malloc0(512);
409     strcpy(req.data, "TEST");
410 
411     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
412 
413     g_free(req.data);
414 
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);
420 
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);
425 
426     data = g_malloc0(512);
427     memread(req_addr + 16, data, 512);
428     g_assert_cmpstr(data, ==, "TEST");
429     g_free(data);
430 
431     g_free(indirect);
432     guest_free(t_alloc, req_addr);
433     qvirtqueue_cleanup(dev->bus, vq, t_alloc);
434 }
435 
436 static void config(void *obj, void *data, QGuestAllocator *t_alloc)
437 {
438     QVirtioBlk *blk_if = obj;
439     QVirtioDevice *dev = blk_if->vdev;
440     int n_size = TEST_IMAGE_SIZE / 2;
441     uint64_t features;
442     uint64_t capacity;
443 
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);
450 
451     capacity = qvirtio_config_readq(dev, 0);
452     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
453 
454     qvirtio_set_driver_ok(dev);
455 
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);
460 
461     capacity = qvirtio_config_readq(dev, 0);
462     g_assert_cmpint(capacity, ==, n_size / 512);
463 }
464 
465 static void msix(void *obj, void *u_data, QGuestAllocator *t_alloc)
466 {
467     QVirtQueue *vq;
468     QVirtioBlkPCI *blk = obj;
469     QVirtioPCIDevice *pdev = &blk->pci_vdev;
470     QVirtioDevice *dev = &pdev->vdev;
471     QVirtioBlkReq req;
472     int n_size = TEST_IMAGE_SIZE / 2;
473     uint64_t req_addr;
474     uint64_t capacity;
475     uint64_t features;
476     uint32_t free_head;
477     uint8_t status;
478     char *data;
479     QOSGraphObject *blk_object = obj;
480     QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
481     QTestState *qts = global_qtest;
482 
483     if (qpci_check_buggy_msi(pci_dev)) {
484         return;
485     }
486 
487     qpci_msix_enable(pdev->pdev);
488     qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
489 
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);
496 
497     capacity = qvirtio_config_readq(dev, 0);
498     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
499 
500     vq = qvirtqueue_setup(dev, t_alloc, 0);
501     qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
502 
503     qvirtio_set_driver_ok(dev);
504 
505     qmp_discard_response("{ 'execute': 'block_resize', "
506                          " 'arguments': { 'device': 'drive0', "
507                          " 'size': %d } }", n_size);
508 
509     qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
510 
511     capacity = qvirtio_config_readq(dev, 0);
512     g_assert_cmpint(capacity, ==, n_size / 512);
513 
514     /* Write request */
515     req.type = VIRTIO_BLK_T_OUT;
516     req.ioprio = 1;
517     req.sector = 0;
518     req.data = g_malloc0(512);
519     strcpy(req.data, "TEST");
520 
521     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
522 
523     g_free(req.data);
524 
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);
529 
530     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
531                            QVIRTIO_BLK_TIMEOUT_US);
532 
533     status = readb(req_addr + 528);
534     g_assert_cmpint(status, ==, 0);
535 
536     guest_free(t_alloc, req_addr);
537 
538     /* Read request */
539     req.type = VIRTIO_BLK_T_IN;
540     req.ioprio = 1;
541     req.sector = 0;
542     req.data = g_malloc0(512);
543 
544     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
545 
546     g_free(req.data);
547 
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);
551 
552     qvirtqueue_kick(qts, dev, vq, free_head);
553 
554 
555     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
556                            QVIRTIO_BLK_TIMEOUT_US);
557 
558     status = readb(req_addr + 528);
559     g_assert_cmpint(status, ==, 0);
560 
561     data = g_malloc0(512);
562     memread(req_addr + 16, data, 512);
563     g_assert_cmpstr(data, ==, "TEST");
564     g_free(data);
565 
566     guest_free(t_alloc, req_addr);
567 
568     /* End test */
569     qpci_msix_disable(pdev->pdev);
570     qvirtqueue_cleanup(dev->bus, vq, t_alloc);
571 }
572 
573 static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
574 {
575     QVirtQueue *vq;
576     QVirtioBlkPCI *blk = obj;
577     QVirtioPCIDevice *pdev = &blk->pci_vdev;
578     QVirtioDevice *dev = &pdev->vdev;
579     QVirtioBlkReq req;
580     uint64_t req_addr;
581     uint64_t capacity;
582     uint64_t features;
583     uint32_t free_head;
584     uint32_t write_head;
585     uint32_t desc_idx;
586     uint8_t status;
587     char *data;
588     QOSGraphObject *blk_object = obj;
589     QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
590     QTestState *qts = global_qtest;
591 
592     if (qpci_check_buggy_msi(pci_dev)) {
593         return;
594     }
595 
596     qpci_msix_enable(pdev->pdev);
597     qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
598 
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);
605 
606     capacity = qvirtio_config_readq(dev, 0);
607     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
608 
609     vq = qvirtqueue_setup(dev, t_alloc, 0);
610     qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
611 
612     qvirtio_set_driver_ok(dev);
613 
614     /* Write request */
615     req.type = VIRTIO_BLK_T_OUT;
616     req.ioprio = 1;
617     req.sector = 0;
618     req.data = g_malloc0(512);
619     strcpy(req.data, "TEST");
620 
621     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
622 
623     g_free(req.data);
624 
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);
629 
630     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
631                            QVIRTIO_BLK_TIMEOUT_US);
632 
633     /* Write request */
634     req.type = VIRTIO_BLK_T_OUT;
635     req.ioprio = 1;
636     req.sector = 1;
637     req.data = g_malloc0(512);
638     strcpy(req.data, "TEST");
639 
640     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
641 
642     g_free(req.data);
643 
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;
651 
652     /* No notification expected */
653     status = qvirtio_wait_status_byte_no_isr(qts, dev,
654                                              vq, req_addr + 528,
655                                              QVIRTIO_BLK_TIMEOUT_US);
656     g_assert_cmpint(status, ==, 0);
657 
658     guest_free(t_alloc, req_addr);
659 
660     /* Read request */
661     req.type = VIRTIO_BLK_T_IN;
662     req.ioprio = 1;
663     req.sector = 1;
664     req.data = g_malloc0(512);
665 
666     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
667 
668     g_free(req.data);
669 
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);
673 
674     qvirtqueue_kick(qts, dev, vq, free_head);
675 
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);
681 
682     status = readb(req_addr + 528);
683     g_assert_cmpint(status, ==, 0);
684 
685     data = g_malloc0(512);
686     memread(req_addr + 16, data, 512);
687     g_assert_cmpstr(data, ==, "TEST");
688     g_free(data);
689 
690     guest_free(t_alloc, req_addr);
691 
692     /* End test */
693     qpci_msix_disable(pdev->pdev);
694 
695     qvirtqueue_cleanup(dev->bus, vq, t_alloc);
696 }
697 
698 static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
699 {
700     QVirtioPCIDevice *dev1 = obj;
701     QVirtioPCIDevice *dev;
702     QTestState *qts = dev1->pdev->bus->qts;
703 
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");
708 
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);
715 
716     /* unplug secondary disk */
717     qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
718 }
719 
720 /*
721  * Check that setting the vring addr on a non-existent virtqueue does
722  * not crash.
723  */
724 static void test_nonexistent_virtqueue(void *obj, void *data,
725                                        QGuestAllocator *t_alloc)
726 {
727     QVirtioBlkPCI *blk = obj;
728     QVirtioPCIDevice *pdev = &blk->pci_vdev;
729     QPCIBar bar0;
730     QPCIDevice *dev;
731 
732     dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
733     g_assert(dev != NULL);
734     qpci_device_enable(dev);
735 
736     bar0 = qpci_iomap(dev, 0, NULL);
737 
738     qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
739     qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
740 
741 
742     g_free(dev);
743 }
744 
745 static void resize(void *obj, void *data, QGuestAllocator *t_alloc)
746 {
747     QVirtioBlk *blk_if = obj;
748     QVirtioDevice *dev = blk_if->vdev;
749     int n_size = TEST_IMAGE_SIZE / 2;
750     uint64_t capacity;
751     QVirtQueue *vq;
752     QTestState *qts = global_qtest;
753 
754     vq = test_basic(dev, t_alloc);
755 
756     qmp_discard_response("{ 'execute': 'block_resize', "
757                          " 'arguments': { 'device': 'drive0', "
758                          " 'size': %d } }", n_size);
759 
760     qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
761 
762     capacity = qvirtio_config_readq(dev, 0);
763     g_assert_cmpint(capacity, ==, n_size / 512);
764 
765     qvirtqueue_cleanup(dev->bus, vq, t_alloc);
766 
767 }
768 
769 static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
770 {
771     char *tmp_path = drive_create();
772 
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 ",
778                            tmp_path);
779 
780     return arg;
781 }
782 
783 static void register_virtio_blk_test(void)
784 {
785     QOSGraphTestOptions opts = {
786         .before = virtio_blk_test_setup,
787     };
788 
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);
793 
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);
800 }
801 
802 libqos_init(register_virtio_blk_test);
803