]> git.proxmox.com Git - mirror_qemu.git/blob - tests/virtio-blk-test.c
Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-next-050719-3' into...
[mirror_qemu.git] / tests / virtio-blk-test.c
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.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 #ifdef HOST_WORDS_BIGENDIAN
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 static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
117 QVirtQueue *vq)
118 {
119 QVirtioBlkReq req;
120 uint64_t req_addr;
121 uint64_t capacity;
122 uint32_t features;
123 uint32_t free_head;
124 uint8_t status;
125 char *data;
126
127 capacity = qvirtio_config_readq(dev, 0);
128
129 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
130
131 features = qvirtio_get_features(dev);
132 features = features & ~(QVIRTIO_F_BAD_FEATURE |
133 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
134 (1u << VIRTIO_RING_F_EVENT_IDX) |
135 (1u << VIRTIO_BLK_F_SCSI));
136 qvirtio_set_features(dev, features);
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(vq, req_addr, 16, false, true);
153 qvirtqueue_add(vq, req_addr + 16, 512, false, true);
154 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
155
156 qvirtqueue_kick(dev, vq, free_head);
157
158 qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US);
159 status = readb(req_addr + 528);
160 g_assert_cmpint(status, ==, 0);
161
162 guest_free(alloc, req_addr);
163
164 /* Read request */
165 req.type = VIRTIO_BLK_T_IN;
166 req.ioprio = 1;
167 req.sector = 0;
168 req.data = g_malloc0(512);
169
170 req_addr = virtio_blk_request(alloc, dev, &req, 512);
171
172 g_free(req.data);
173
174 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
175 qvirtqueue_add(vq, req_addr + 16, 512, true, true);
176 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
177
178 qvirtqueue_kick(dev, vq, free_head);
179
180 qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US);
181 status = readb(req_addr + 528);
182 g_assert_cmpint(status, ==, 0);
183
184 data = g_malloc0(512);
185 memread(req_addr + 16, data, 512);
186 g_assert_cmpstr(data, ==, "TEST");
187 g_free(data);
188
189 guest_free(alloc, req_addr);
190
191 if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
192 struct virtio_blk_discard_write_zeroes dwz_hdr;
193 void *expected;
194
195 /*
196 * WRITE_ZEROES request on the same sector of previous test where
197 * we wrote "TEST".
198 */
199 req.type = VIRTIO_BLK_T_WRITE_ZEROES;
200 req.data = (char *) &dwz_hdr;
201 dwz_hdr.sector = 0;
202 dwz_hdr.num_sectors = 1;
203 dwz_hdr.flags = 0;
204
205 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
206
207 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
208
209 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
210 qvirtqueue_add(vq, req_addr + 16, sizeof(dwz_hdr), false, true);
211 qvirtqueue_add(vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false);
212
213 qvirtqueue_kick(dev, vq, free_head);
214
215 qvirtio_wait_used_elem(dev, vq, free_head, NULL,
216 QVIRTIO_BLK_TIMEOUT_US);
217 status = readb(req_addr + 16 + sizeof(dwz_hdr));
218 g_assert_cmpint(status, ==, 0);
219
220 guest_free(alloc, req_addr);
221
222 /* Read request to check if the sector contains all zeroes */
223 req.type = VIRTIO_BLK_T_IN;
224 req.ioprio = 1;
225 req.sector = 0;
226 req.data = g_malloc0(512);
227
228 req_addr = virtio_blk_request(alloc, dev, &req, 512);
229
230 g_free(req.data);
231
232 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
233 qvirtqueue_add(vq, req_addr + 16, 512, true, true);
234 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
235
236 qvirtqueue_kick(dev, vq, free_head);
237
238 qvirtio_wait_used_elem(dev, vq, free_head, NULL,
239 QVIRTIO_BLK_TIMEOUT_US);
240 status = readb(req_addr + 528);
241 g_assert_cmpint(status, ==, 0);
242
243 data = g_malloc(512);
244 expected = g_malloc0(512);
245 memread(req_addr + 16, data, 512);
246 g_assert_cmpmem(data, 512, expected, 512);
247 g_free(expected);
248 g_free(data);
249
250 guest_free(alloc, req_addr);
251 }
252
253 if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
254 struct virtio_blk_discard_write_zeroes dwz_hdr;
255
256 req.type = VIRTIO_BLK_T_DISCARD;
257 req.data = (char *) &dwz_hdr;
258 dwz_hdr.sector = 0;
259 dwz_hdr.num_sectors = 1;
260 dwz_hdr.flags = 0;
261
262 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
263
264 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
265
266 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
267 qvirtqueue_add(vq, req_addr + 16, sizeof(dwz_hdr), false, true);
268 qvirtqueue_add(vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false);
269
270 qvirtqueue_kick(dev, vq, free_head);
271
272 qvirtio_wait_used_elem(dev, vq, free_head, NULL,
273 QVIRTIO_BLK_TIMEOUT_US);
274 status = readb(req_addr + 16 + sizeof(dwz_hdr));
275 g_assert_cmpint(status, ==, 0);
276
277 guest_free(alloc, req_addr);
278 }
279
280 if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
281 /* Write and read with 2 descriptor layout */
282 /* Write request */
283 req.type = VIRTIO_BLK_T_OUT;
284 req.ioprio = 1;
285 req.sector = 1;
286 req.data = g_malloc0(512);
287 strcpy(req.data, "TEST");
288
289 req_addr = virtio_blk_request(alloc, dev, &req, 512);
290
291 g_free(req.data);
292
293 free_head = qvirtqueue_add(vq, req_addr, 528, false, true);
294 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
295 qvirtqueue_kick(dev, vq, free_head);
296
297 qvirtio_wait_used_elem(dev, vq, free_head, NULL,
298 QVIRTIO_BLK_TIMEOUT_US);
299 status = readb(req_addr + 528);
300 g_assert_cmpint(status, ==, 0);
301
302 guest_free(alloc, req_addr);
303
304 /* Read request */
305 req.type = VIRTIO_BLK_T_IN;
306 req.ioprio = 1;
307 req.sector = 1;
308 req.data = g_malloc0(512);
309
310 req_addr = virtio_blk_request(alloc, dev, &req, 512);
311
312 g_free(req.data);
313
314 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
315 qvirtqueue_add(vq, req_addr + 16, 513, true, false);
316
317 qvirtqueue_kick(dev, vq, free_head);
318
319 qvirtio_wait_used_elem(dev, vq, free_head, NULL,
320 QVIRTIO_BLK_TIMEOUT_US);
321 status = readb(req_addr + 528);
322 g_assert_cmpint(status, ==, 0);
323
324 data = g_malloc0(512);
325 memread(req_addr + 16, data, 512);
326 g_assert_cmpstr(data, ==, "TEST");
327 g_free(data);
328
329 guest_free(alloc, req_addr);
330 }
331 }
332
333 static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
334 {
335 QVirtioBlk *blk_if = obj;
336 QVirtQueue *vq;
337 vq = qvirtqueue_setup(blk_if->vdev, t_alloc, 0);
338 test_basic(blk_if->vdev, t_alloc, vq);
339 qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
340
341 }
342
343 static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
344 {
345 QVirtQueue *vq;
346 QVirtioBlk *blk_if = obj;
347 QVirtioDevice *dev = blk_if->vdev;
348 QVirtioBlkReq req;
349 QVRingIndirectDesc *indirect;
350 uint64_t req_addr;
351 uint64_t capacity;
352 uint32_t features;
353 uint32_t free_head;
354 uint8_t status;
355 char *data;
356
357 capacity = qvirtio_config_readq(dev, 0);
358 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
359
360 features = qvirtio_get_features(dev);
361 g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
362 features = features & ~(QVIRTIO_F_BAD_FEATURE |
363 (1u << VIRTIO_RING_F_EVENT_IDX) |
364 (1u << VIRTIO_BLK_F_SCSI));
365 qvirtio_set_features(dev, features);
366
367 vq = qvirtqueue_setup(dev, t_alloc, 0);
368 qvirtio_set_driver_ok(dev);
369
370 /* Write request */
371 req.type = VIRTIO_BLK_T_OUT;
372 req.ioprio = 1;
373 req.sector = 0;
374 req.data = g_malloc0(512);
375 strcpy(req.data, "TEST");
376
377 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
378
379 g_free(req.data);
380
381 indirect = qvring_indirect_desc_setup(dev, t_alloc, 2);
382 qvring_indirect_desc_add(indirect, req_addr, 528, false);
383 qvring_indirect_desc_add(indirect, req_addr + 528, 1, true);
384 free_head = qvirtqueue_add_indirect(vq, indirect);
385 qvirtqueue_kick(dev, vq, free_head);
386
387 qvirtio_wait_used_elem(dev, vq, free_head, NULL,
388 QVIRTIO_BLK_TIMEOUT_US);
389 status = readb(req_addr + 528);
390 g_assert_cmpint(status, ==, 0);
391
392 g_free(indirect);
393 guest_free(t_alloc, req_addr);
394
395 /* Read request */
396 req.type = VIRTIO_BLK_T_IN;
397 req.ioprio = 1;
398 req.sector = 0;
399 req.data = g_malloc0(512);
400 strcpy(req.data, "TEST");
401
402 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
403
404 g_free(req.data);
405
406 indirect = qvring_indirect_desc_setup(dev, t_alloc, 2);
407 qvring_indirect_desc_add(indirect, req_addr, 16, false);
408 qvring_indirect_desc_add(indirect, req_addr + 16, 513, true);
409 free_head = qvirtqueue_add_indirect(vq, indirect);
410 qvirtqueue_kick(dev, vq, free_head);
411
412 qvirtio_wait_used_elem(dev, vq, free_head, NULL,
413 QVIRTIO_BLK_TIMEOUT_US);
414 status = readb(req_addr + 528);
415 g_assert_cmpint(status, ==, 0);
416
417 data = g_malloc0(512);
418 memread(req_addr + 16, data, 512);
419 g_assert_cmpstr(data, ==, "TEST");
420 g_free(data);
421
422 g_free(indirect);
423 guest_free(t_alloc, req_addr);
424 qvirtqueue_cleanup(dev->bus, vq, t_alloc);
425 }
426
427 static void config(void *obj, void *data, QGuestAllocator *t_alloc)
428 {
429 QVirtioBlk *blk_if = obj;
430 QVirtioDevice *dev = blk_if->vdev;
431 int n_size = TEST_IMAGE_SIZE / 2;
432 uint64_t capacity;
433
434 capacity = qvirtio_config_readq(dev, 0);
435 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
436
437 qvirtio_set_driver_ok(dev);
438
439 qmp_discard_response("{ 'execute': 'block_resize', "
440 " 'arguments': { 'device': 'drive0', "
441 " 'size': %d } }", n_size);
442 qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
443
444 capacity = qvirtio_config_readq(dev, 0);
445 g_assert_cmpint(capacity, ==, n_size / 512);
446 }
447
448 static void msix(void *obj, void *u_data, QGuestAllocator *t_alloc)
449 {
450 QVirtQueue *vq;
451 QVirtioBlkPCI *blk = obj;
452 QVirtioPCIDevice *pdev = &blk->pci_vdev;
453 QVirtioDevice *dev = &pdev->vdev;
454 QVirtioBlkReq req;
455 int n_size = TEST_IMAGE_SIZE / 2;
456 uint64_t req_addr;
457 uint64_t capacity;
458 uint32_t features;
459 uint32_t free_head;
460 uint8_t status;
461 char *data;
462 QOSGraphObject *blk_object = obj;
463 QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
464
465 if (qpci_check_buggy_msi(pci_dev)) {
466 return;
467 }
468
469 qpci_msix_enable(pdev->pdev);
470 qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
471
472 capacity = qvirtio_config_readq(dev, 0);
473 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
474
475 features = qvirtio_get_features(dev);
476 features = features & ~(QVIRTIO_F_BAD_FEATURE |
477 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
478 (1u << VIRTIO_RING_F_EVENT_IDX) |
479 (1u << VIRTIO_BLK_F_SCSI));
480 qvirtio_set_features(dev, features);
481
482 vq = qvirtqueue_setup(dev, t_alloc, 0);
483 qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
484
485 qvirtio_set_driver_ok(dev);
486
487 qmp_discard_response("{ 'execute': 'block_resize', "
488 " 'arguments': { 'device': 'drive0', "
489 " 'size': %d } }", n_size);
490
491 qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
492
493 capacity = qvirtio_config_readq(dev, 0);
494 g_assert_cmpint(capacity, ==, n_size / 512);
495
496 /* Write request */
497 req.type = VIRTIO_BLK_T_OUT;
498 req.ioprio = 1;
499 req.sector = 0;
500 req.data = g_malloc0(512);
501 strcpy(req.data, "TEST");
502
503 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
504
505 g_free(req.data);
506
507 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
508 qvirtqueue_add(vq, req_addr + 16, 512, false, true);
509 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
510 qvirtqueue_kick(dev, vq, free_head);
511
512 qvirtio_wait_used_elem(dev, vq, free_head, NULL,
513 QVIRTIO_BLK_TIMEOUT_US);
514
515 status = readb(req_addr + 528);
516 g_assert_cmpint(status, ==, 0);
517
518 guest_free(t_alloc, req_addr);
519
520 /* Read request */
521 req.type = VIRTIO_BLK_T_IN;
522 req.ioprio = 1;
523 req.sector = 0;
524 req.data = g_malloc0(512);
525
526 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
527
528 g_free(req.data);
529
530 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
531 qvirtqueue_add(vq, req_addr + 16, 512, true, true);
532 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
533
534 qvirtqueue_kick(dev, vq, free_head);
535
536
537 qvirtio_wait_used_elem(dev, vq, free_head, NULL,
538 QVIRTIO_BLK_TIMEOUT_US);
539
540 status = readb(req_addr + 528);
541 g_assert_cmpint(status, ==, 0);
542
543 data = g_malloc0(512);
544 memread(req_addr + 16, data, 512);
545 g_assert_cmpstr(data, ==, "TEST");
546 g_free(data);
547
548 guest_free(t_alloc, req_addr);
549
550 /* End test */
551 qpci_msix_disable(pdev->pdev);
552 qvirtqueue_cleanup(dev->bus, vq, t_alloc);
553 }
554
555 static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
556 {
557 QVirtQueue *vq;
558 QVirtioBlkPCI *blk = obj;
559 QVirtioPCIDevice *pdev = &blk->pci_vdev;
560 QVirtioDevice *dev = &pdev->vdev;
561 QVirtioBlkReq req;
562 uint64_t req_addr;
563 uint64_t capacity;
564 uint32_t features;
565 uint32_t free_head;
566 uint32_t write_head;
567 uint32_t desc_idx;
568 uint8_t status;
569 char *data;
570 QOSGraphObject *blk_object = obj;
571 QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
572
573 if (qpci_check_buggy_msi(pci_dev)) {
574 return;
575 }
576
577 qpci_msix_enable(pdev->pdev);
578 qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
579
580 capacity = qvirtio_config_readq(dev, 0);
581 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
582
583 features = qvirtio_get_features(dev);
584 features = features & ~(QVIRTIO_F_BAD_FEATURE |
585 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
586 (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
587 (1u << VIRTIO_BLK_F_SCSI));
588 qvirtio_set_features(dev, features);
589
590 vq = qvirtqueue_setup(dev, t_alloc, 0);
591 qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
592
593 qvirtio_set_driver_ok(dev);
594
595 /* Write request */
596 req.type = VIRTIO_BLK_T_OUT;
597 req.ioprio = 1;
598 req.sector = 0;
599 req.data = g_malloc0(512);
600 strcpy(req.data, "TEST");
601
602 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
603
604 g_free(req.data);
605
606 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
607 qvirtqueue_add(vq, req_addr + 16, 512, false, true);
608 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
609 qvirtqueue_kick(dev, vq, free_head);
610
611 qvirtio_wait_used_elem(dev, vq, free_head, NULL,
612 QVIRTIO_BLK_TIMEOUT_US);
613
614 /* Write request */
615 req.type = VIRTIO_BLK_T_OUT;
616 req.ioprio = 1;
617 req.sector = 1;
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 /* Notify after processing the third request */
626 qvirtqueue_set_used_event(vq, 2);
627 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
628 qvirtqueue_add(vq, req_addr + 16, 512, false, true);
629 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
630 qvirtqueue_kick(dev, vq, free_head);
631 write_head = free_head;
632
633 /* No notification expected */
634 status = qvirtio_wait_status_byte_no_isr(dev,
635 vq, req_addr + 528,
636 QVIRTIO_BLK_TIMEOUT_US);
637 g_assert_cmpint(status, ==, 0);
638
639 guest_free(t_alloc, req_addr);
640
641 /* Read request */
642 req.type = VIRTIO_BLK_T_IN;
643 req.ioprio = 1;
644 req.sector = 1;
645 req.data = g_malloc0(512);
646
647 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
648
649 g_free(req.data);
650
651 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
652 qvirtqueue_add(vq, req_addr + 16, 512, true, true);
653 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
654
655 qvirtqueue_kick(dev, vq, free_head);
656
657 /* We get just one notification for both requests */
658 qvirtio_wait_used_elem(dev, vq, write_head, NULL,
659 QVIRTIO_BLK_TIMEOUT_US);
660 g_assert(qvirtqueue_get_buf(vq, &desc_idx, NULL));
661 g_assert_cmpint(desc_idx, ==, free_head);
662
663 status = readb(req_addr + 528);
664 g_assert_cmpint(status, ==, 0);
665
666 data = g_malloc0(512);
667 memread(req_addr + 16, data, 512);
668 g_assert_cmpstr(data, ==, "TEST");
669 g_free(data);
670
671 guest_free(t_alloc, req_addr);
672
673 /* End test */
674 qpci_msix_disable(pdev->pdev);
675
676 qvirtqueue_cleanup(dev->bus, vq, t_alloc);
677 }
678
679 static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
680 {
681 QVirtioPCIDevice *dev1 = obj;
682 QVirtioPCIDevice *dev;
683 QTestState *qts = dev1->pdev->bus->qts;
684
685 /* plug secondary disk */
686 qtest_qmp_device_add("virtio-blk-pci", "drv1",
687 "{'addr': %s, 'drive': 'drive1'}",
688 stringify(PCI_SLOT_HP) ".0");
689
690 dev = virtio_pci_new(dev1->pdev->bus,
691 &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0) });
692 g_assert_nonnull(dev);
693 g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
694 qvirtio_pci_device_disable(dev);
695 qos_object_destroy((QOSGraphObject *)dev);
696
697 /* unplug secondary disk */
698 qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
699 }
700
701 /*
702 * Check that setting the vring addr on a non-existent virtqueue does
703 * not crash.
704 */
705 static void test_nonexistent_virtqueue(void *obj, void *data,
706 QGuestAllocator *t_alloc)
707 {
708 QVirtioBlkPCI *blk = obj;
709 QVirtioPCIDevice *pdev = &blk->pci_vdev;
710 QPCIBar bar0;
711 QPCIDevice *dev;
712
713 dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
714 g_assert(dev != NULL);
715 qpci_device_enable(dev);
716
717 bar0 = qpci_iomap(dev, 0, NULL);
718
719 qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
720 qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
721
722
723 g_free(dev);
724 }
725
726 static void resize(void *obj, void *data, QGuestAllocator *t_alloc)
727 {
728 QVirtioBlk *blk_if = obj;
729 QVirtioDevice *dev = blk_if->vdev;
730 int n_size = TEST_IMAGE_SIZE / 2;
731 uint64_t capacity;
732 QVirtQueue *vq;
733
734 vq = qvirtqueue_setup(dev, t_alloc, 0);
735
736 test_basic(dev, t_alloc, vq);
737
738 qmp_discard_response("{ 'execute': 'block_resize', "
739 " 'arguments': { 'device': 'drive0', "
740 " 'size': %d } }", n_size);
741
742 qvirtio_wait_queue_isr(dev, vq, QVIRTIO_BLK_TIMEOUT_US);
743
744 capacity = qvirtio_config_readq(dev, 0);
745 g_assert_cmpint(capacity, ==, n_size / 512);
746
747 qvirtqueue_cleanup(dev->bus, vq, t_alloc);
748
749 }
750
751 static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
752 {
753 char *tmp_path = drive_create();
754
755 g_string_append_printf(cmd_line,
756 " -drive if=none,id=drive0,file=%s,format=raw,auto-read-only=off "
757 "-drive if=none,id=drive1,file=null-co://,format=raw ",
758 tmp_path);
759
760 return arg;
761 }
762
763 static void register_virtio_blk_test(void)
764 {
765 QOSGraphTestOptions opts = {
766 .before = virtio_blk_test_setup,
767 };
768
769 qos_add_test("indirect", "virtio-blk", indirect, &opts);
770 qos_add_test("config", "virtio-blk", config, &opts);
771 qos_add_test("basic", "virtio-blk", basic, &opts);
772 qos_add_test("resize", "virtio-blk", resize, &opts);
773
774 /* tests just for virtio-blk-pci */
775 qos_add_test("msix", "virtio-blk-pci", msix, &opts);
776 qos_add_test("idx", "virtio-blk-pci", idx, &opts);
777 qos_add_test("nxvirtq", "virtio-blk-pci",
778 test_nonexistent_virtqueue, &opts);
779 qos_add_test("hotplug", "virtio-blk-pci", pci_hotplug, &opts);
780 }
781
782 libqos_init(register_virtio_blk_test);