]> git.proxmox.com Git - mirror_qemu.git/blob - tests/virtio-blk-test.c
tests/virtio-blk: change assert on data_size in virtio_blk_request()
[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 "libqos/libqos-pc.h"
14 #include "libqos/libqos-spapr.h"
15 #include "libqos/virtio.h"
16 #include "libqos/virtio-pci.h"
17 #include "libqos/virtio-mmio.h"
18 #include "libqos/malloc-generic.h"
19 #include "qapi/qmp/qdict.h"
20 #include "qemu/bswap.h"
21 #include "standard-headers/linux/virtio_ids.h"
22 #include "standard-headers/linux/virtio_config.h"
23 #include "standard-headers/linux/virtio_ring.h"
24 #include "standard-headers/linux/virtio_blk.h"
25 #include "standard-headers/linux/virtio_pci.h"
26
27 /* TODO actually test the results and get rid of this */
28 #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
29
30 #define TEST_IMAGE_SIZE (64 * 1024 * 1024)
31 #define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
32 #define PCI_SLOT_HP 0x06
33 #define PCI_SLOT 0x04
34 #define PCI_FN 0x00
35
36 #define MMIO_PAGE_SIZE 4096
37 #define MMIO_DEV_BASE_ADDR 0x0A003E00
38 #define MMIO_RAM_ADDR 0x40000000
39 #define MMIO_RAM_SIZE 0x20000000
40
41 typedef struct QVirtioBlkReq {
42 uint32_t type;
43 uint32_t ioprio;
44 uint64_t sector;
45 char *data;
46 uint8_t status;
47 } QVirtioBlkReq;
48
49 static char *drive_create(void)
50 {
51 int fd, ret;
52 char *tmp_path = g_strdup("/tmp/qtest.XXXXXX");
53
54 /* Create a temporary raw image */
55 fd = mkstemp(tmp_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 return tmp_path;
62 }
63
64 static QOSState *pci_test_start(void)
65 {
66 QOSState *qs;
67 const char *arch = qtest_get_arch();
68 char *tmp_path;
69 const char *cmd = "-drive if=none,id=drive0,file=%s,format=raw "
70 "-drive if=none,id=drive1,file=null-co://,format=raw "
71 "-device virtio-blk-pci,id=drv0,drive=drive0,"
72 "addr=%x.%x";
73
74 tmp_path = drive_create();
75
76 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
77 qs = qtest_pc_boot(cmd, tmp_path, PCI_SLOT, PCI_FN);
78 } else if (strcmp(arch, "ppc64") == 0) {
79 qs = qtest_spapr_boot(cmd, tmp_path, PCI_SLOT, PCI_FN);
80 } else {
81 g_printerr("virtio-blk tests are only available on x86 or ppc64\n");
82 exit(EXIT_FAILURE);
83 }
84 global_qtest = qs->qts;
85 unlink(tmp_path);
86 g_free(tmp_path);
87 return qs;
88 }
89
90 static void arm_test_start(void)
91 {
92 char *tmp_path;
93
94 tmp_path = drive_create();
95
96 global_qtest = qtest_initf("-machine virt "
97 "-drive if=none,id=drive0,file=%s,format=raw "
98 "-device virtio-blk-device,drive=drive0",
99 tmp_path);
100 unlink(tmp_path);
101 g_free(tmp_path);
102 }
103
104 static void test_end(void)
105 {
106 qtest_end();
107 }
108
109 static QVirtioPCIDevice *virtio_blk_pci_init(QPCIBus *bus, int slot)
110 {
111 QVirtioPCIDevice *dev;
112
113 dev = qvirtio_pci_device_find_slot(bus, VIRTIO_ID_BLOCK, slot);
114 g_assert(dev != NULL);
115 g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
116 g_assert_cmphex(dev->pdev->devfn, ==, ((slot << 3) | PCI_FN));
117
118 qvirtio_pci_device_enable(dev);
119 qvirtio_reset(&dev->vdev);
120 qvirtio_set_acknowledge(&dev->vdev);
121 qvirtio_set_driver(&dev->vdev);
122
123 return dev;
124 }
125
126 static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
127 {
128 #ifdef HOST_WORDS_BIGENDIAN
129 const bool host_is_big_endian = true;
130 #else
131 const bool host_is_big_endian = false;
132 #endif
133
134 if (qvirtio_is_big_endian(d) != host_is_big_endian) {
135 req->type = bswap32(req->type);
136 req->ioprio = bswap32(req->ioprio);
137 req->sector = bswap64(req->sector);
138 }
139 }
140
141 static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
142 QVirtioBlkReq *req, uint64_t data_size)
143 {
144 uint64_t addr;
145 uint8_t status = 0xFF;
146
147 switch (req->type) {
148 case VIRTIO_BLK_T_IN:
149 case VIRTIO_BLK_T_OUT:
150 g_assert_cmpuint(data_size % 512, ==, 0);
151 break;
152 case VIRTIO_BLK_T_DISCARD:
153 case VIRTIO_BLK_T_WRITE_ZEROES:
154 g_assert_cmpuint(data_size %
155 sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
156 break;
157 default:
158 g_assert_cmpuint(data_size, ==, 0);
159 }
160
161 addr = guest_alloc(alloc, sizeof(*req) + data_size);
162
163 virtio_blk_fix_request(d, req);
164
165 memwrite(addr, req, 16);
166 memwrite(addr + 16, req->data, data_size);
167 memwrite(addr + 16 + data_size, &status, sizeof(status));
168
169 return addr;
170 }
171
172 static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
173 QVirtQueue *vq)
174 {
175 QVirtioBlkReq req;
176 uint64_t req_addr;
177 uint64_t capacity;
178 uint32_t features;
179 uint32_t free_head;
180 uint8_t status;
181 char *data;
182
183 capacity = qvirtio_config_readq(dev, 0);
184
185 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
186
187 features = qvirtio_get_features(dev);
188 features = features & ~(QVIRTIO_F_BAD_FEATURE |
189 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
190 (1u << VIRTIO_RING_F_EVENT_IDX) |
191 (1u << VIRTIO_BLK_F_SCSI));
192 qvirtio_set_features(dev, features);
193
194 qvirtio_set_driver_ok(dev);
195
196 /* Write and read with 3 descriptor layout */
197 /* Write request */
198 req.type = VIRTIO_BLK_T_OUT;
199 req.ioprio = 1;
200 req.sector = 0;
201 req.data = g_malloc0(512);
202 strcpy(req.data, "TEST");
203
204 req_addr = virtio_blk_request(alloc, dev, &req, 512);
205
206 g_free(req.data);
207
208 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
209 qvirtqueue_add(vq, req_addr + 16, 512, false, true);
210 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
211
212 qvirtqueue_kick(dev, vq, free_head);
213
214 qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US);
215 status = readb(req_addr + 528);
216 g_assert_cmpint(status, ==, 0);
217
218 guest_free(alloc, req_addr);
219
220 /* Read request */
221 req.type = VIRTIO_BLK_T_IN;
222 req.ioprio = 1;
223 req.sector = 0;
224 req.data = g_malloc0(512);
225
226 req_addr = virtio_blk_request(alloc, dev, &req, 512);
227
228 g_free(req.data);
229
230 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
231 qvirtqueue_add(vq, req_addr + 16, 512, true, true);
232 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
233
234 qvirtqueue_kick(dev, vq, free_head);
235
236 qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US);
237 status = readb(req_addr + 528);
238 g_assert_cmpint(status, ==, 0);
239
240 data = g_malloc0(512);
241 memread(req_addr + 16, data, 512);
242 g_assert_cmpstr(data, ==, "TEST");
243 g_free(data);
244
245 guest_free(alloc, req_addr);
246
247 if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
248 /* Write and read with 2 descriptor layout */
249 /* Write request */
250 req.type = VIRTIO_BLK_T_OUT;
251 req.ioprio = 1;
252 req.sector = 1;
253 req.data = g_malloc0(512);
254 strcpy(req.data, "TEST");
255
256 req_addr = virtio_blk_request(alloc, dev, &req, 512);
257
258 g_free(req.data);
259
260 free_head = qvirtqueue_add(vq, req_addr, 528, false, true);
261 qvirtqueue_add(vq, req_addr + 528, 1, true, false);
262 qvirtqueue_kick(dev, vq, free_head);
263
264 qvirtio_wait_used_elem(dev, vq, free_head, NULL,
265 QVIRTIO_BLK_TIMEOUT_US);
266 status = readb(req_addr + 528);
267 g_assert_cmpint(status, ==, 0);
268
269 guest_free(alloc, req_addr);
270
271 /* Read request */
272 req.type = VIRTIO_BLK_T_IN;
273 req.ioprio = 1;
274 req.sector = 1;
275 req.data = g_malloc0(512);
276
277 req_addr = virtio_blk_request(alloc, dev, &req, 512);
278
279 g_free(req.data);
280
281 free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
282 qvirtqueue_add(vq, req_addr + 16, 513, true, false);
283
284 qvirtqueue_kick(dev, vq, free_head);
285
286 qvirtio_wait_used_elem(dev, vq, free_head, NULL,
287 QVIRTIO_BLK_TIMEOUT_US);
288 status = readb(req_addr + 528);
289 g_assert_cmpint(status, ==, 0);
290
291 data = g_malloc0(512);
292 memread(req_addr + 16, data, 512);
293 g_assert_cmpstr(data, ==, "TEST");
294 g_free(data);
295
296 guest_free(alloc, req_addr);
297 }
298 }
299
300 static void pci_basic(void)
301 {
302 QVirtioPCIDevice *dev;
303 QOSState *qs;
304 QVirtQueuePCI *vqpci;
305
306 qs = pci_test_start();
307 dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
308
309 vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
310
311 test_basic(&dev->vdev, qs->alloc, &vqpci->vq);
312
313 /* End test */
314 qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
315 qvirtio_pci_device_disable(dev);
316 qvirtio_pci_device_free(dev);
317 qtest_shutdown(qs);
318 }
319
320 static void pci_indirect(void)
321 {
322 QVirtioPCIDevice *dev;
323 QVirtQueuePCI *vqpci;
324 QOSState *qs;
325 QVirtioBlkReq req;
326 QVRingIndirectDesc *indirect;
327 uint64_t req_addr;
328 uint64_t capacity;
329 uint32_t features;
330 uint32_t free_head;
331 uint8_t status;
332 char *data;
333
334 qs = pci_test_start();
335
336 dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
337
338 capacity = qvirtio_config_readq(&dev->vdev, 0);
339 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
340
341 features = qvirtio_get_features(&dev->vdev);
342 g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
343 features = features & ~(QVIRTIO_F_BAD_FEATURE |
344 (1u << VIRTIO_RING_F_EVENT_IDX) |
345 (1u << VIRTIO_BLK_F_SCSI));
346 qvirtio_set_features(&dev->vdev, features);
347
348 vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
349 qvirtio_set_driver_ok(&dev->vdev);
350
351 /* Write request */
352 req.type = VIRTIO_BLK_T_OUT;
353 req.ioprio = 1;
354 req.sector = 0;
355 req.data = g_malloc0(512);
356 strcpy(req.data, "TEST");
357
358 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
359
360 g_free(req.data);
361
362 indirect = qvring_indirect_desc_setup(&dev->vdev, qs->alloc, 2);
363 qvring_indirect_desc_add(indirect, req_addr, 528, false);
364 qvring_indirect_desc_add(indirect, req_addr + 528, 1, true);
365 free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
366 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
367
368 qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
369 QVIRTIO_BLK_TIMEOUT_US);
370 status = readb(req_addr + 528);
371 g_assert_cmpint(status, ==, 0);
372
373 g_free(indirect);
374 guest_free(qs->alloc, req_addr);
375
376 /* Read request */
377 req.type = VIRTIO_BLK_T_IN;
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(qs->alloc, &dev->vdev, &req, 512);
384
385 g_free(req.data);
386
387 indirect = qvring_indirect_desc_setup(&dev->vdev, qs->alloc, 2);
388 qvring_indirect_desc_add(indirect, req_addr, 16, false);
389 qvring_indirect_desc_add(indirect, req_addr + 16, 513, true);
390 free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
391 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
392
393 qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
394 QVIRTIO_BLK_TIMEOUT_US);
395 status = readb(req_addr + 528);
396 g_assert_cmpint(status, ==, 0);
397
398 data = g_malloc0(512);
399 memread(req_addr + 16, data, 512);
400 g_assert_cmpstr(data, ==, "TEST");
401 g_free(data);
402
403 g_free(indirect);
404 guest_free(qs->alloc, req_addr);
405
406 /* End test */
407 qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
408 qvirtio_pci_device_disable(dev);
409 qvirtio_pci_device_free(dev);
410 qtest_shutdown(qs);
411 }
412
413 static void pci_config(void)
414 {
415 QVirtioPCIDevice *dev;
416 QOSState *qs;
417 int n_size = TEST_IMAGE_SIZE / 2;
418 uint64_t capacity;
419
420 qs = pci_test_start();
421
422 dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
423
424 capacity = qvirtio_config_readq(&dev->vdev, 0);
425 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
426
427 qvirtio_set_driver_ok(&dev->vdev);
428
429 qmp_discard_response("{ 'execute': 'block_resize', "
430 " 'arguments': { 'device': 'drive0', "
431 " 'size': %d } }", n_size);
432 qvirtio_wait_config_isr(&dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
433
434 capacity = qvirtio_config_readq(&dev->vdev, 0);
435 g_assert_cmpint(capacity, ==, n_size / 512);
436
437 qvirtio_pci_device_disable(dev);
438 qvirtio_pci_device_free(dev);
439
440 qtest_shutdown(qs);
441 }
442
443 static void pci_msix(void)
444 {
445 QVirtioPCIDevice *dev;
446 QOSState *qs;
447 QVirtQueuePCI *vqpci;
448 QVirtioBlkReq req;
449 int n_size = TEST_IMAGE_SIZE / 2;
450 uint64_t req_addr;
451 uint64_t capacity;
452 uint32_t features;
453 uint32_t free_head;
454 uint8_t status;
455 char *data;
456
457 qs = pci_test_start();
458
459 dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
460 qpci_msix_enable(dev->pdev);
461
462 qvirtio_pci_set_msix_configuration_vector(dev, qs->alloc, 0);
463
464 capacity = qvirtio_config_readq(&dev->vdev, 0);
465 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
466
467 features = qvirtio_get_features(&dev->vdev);
468 features = features & ~(QVIRTIO_F_BAD_FEATURE |
469 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
470 (1u << VIRTIO_RING_F_EVENT_IDX) |
471 (1u << VIRTIO_BLK_F_SCSI));
472 qvirtio_set_features(&dev->vdev, features);
473
474 vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
475 qvirtqueue_pci_msix_setup(dev, vqpci, qs->alloc, 1);
476
477 qvirtio_set_driver_ok(&dev->vdev);
478
479 qmp_discard_response("{ 'execute': 'block_resize', "
480 " 'arguments': { 'device': 'drive0', "
481 " 'size': %d } }", n_size);
482
483 qvirtio_wait_config_isr(&dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
484
485 capacity = qvirtio_config_readq(&dev->vdev, 0);
486 g_assert_cmpint(capacity, ==, n_size / 512);
487
488 /* Write request */
489 req.type = VIRTIO_BLK_T_OUT;
490 req.ioprio = 1;
491 req.sector = 0;
492 req.data = g_malloc0(512);
493 strcpy(req.data, "TEST");
494
495 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
496
497 g_free(req.data);
498
499 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
500 qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
501 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
502 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
503
504 qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
505 QVIRTIO_BLK_TIMEOUT_US);
506
507 status = readb(req_addr + 528);
508 g_assert_cmpint(status, ==, 0);
509
510 guest_free(qs->alloc, req_addr);
511
512 /* Read request */
513 req.type = VIRTIO_BLK_T_IN;
514 req.ioprio = 1;
515 req.sector = 0;
516 req.data = g_malloc0(512);
517
518 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
519
520 g_free(req.data);
521
522 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
523 qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, true, true);
524 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
525
526 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
527
528
529 qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
530 QVIRTIO_BLK_TIMEOUT_US);
531
532 status = readb(req_addr + 528);
533 g_assert_cmpint(status, ==, 0);
534
535 data = g_malloc0(512);
536 memread(req_addr + 16, data, 512);
537 g_assert_cmpstr(data, ==, "TEST");
538 g_free(data);
539
540 guest_free(qs->alloc, req_addr);
541
542 /* End test */
543 qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
544 qpci_msix_disable(dev->pdev);
545 qvirtio_pci_device_disable(dev);
546 qvirtio_pci_device_free(dev);
547 qtest_shutdown(qs);
548 }
549
550 static void pci_idx(void)
551 {
552 QVirtioPCIDevice *dev;
553 QOSState *qs;
554 QVirtQueuePCI *vqpci;
555 QVirtioBlkReq req;
556 uint64_t req_addr;
557 uint64_t capacity;
558 uint32_t features;
559 uint32_t free_head;
560 uint32_t write_head;
561 uint32_t desc_idx;
562 uint8_t status;
563 char *data;
564
565 qs = pci_test_start();
566
567 dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
568 qpci_msix_enable(dev->pdev);
569
570 qvirtio_pci_set_msix_configuration_vector(dev, qs->alloc, 0);
571
572 capacity = qvirtio_config_readq(&dev->vdev, 0);
573 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
574
575 features = qvirtio_get_features(&dev->vdev);
576 features = features & ~(QVIRTIO_F_BAD_FEATURE |
577 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
578 (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
579 (1u << VIRTIO_BLK_F_SCSI));
580 qvirtio_set_features(&dev->vdev, features);
581
582 vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
583 qvirtqueue_pci_msix_setup(dev, vqpci, qs->alloc, 1);
584
585 qvirtio_set_driver_ok(&dev->vdev);
586
587 /* Write request */
588 req.type = VIRTIO_BLK_T_OUT;
589 req.ioprio = 1;
590 req.sector = 0;
591 req.data = g_malloc0(512);
592 strcpy(req.data, "TEST");
593
594 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
595
596 g_free(req.data);
597
598 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
599 qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
600 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
601 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
602
603 qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL,
604 QVIRTIO_BLK_TIMEOUT_US);
605
606 /* Write request */
607 req.type = VIRTIO_BLK_T_OUT;
608 req.ioprio = 1;
609 req.sector = 1;
610 req.data = g_malloc0(512);
611 strcpy(req.data, "TEST");
612
613 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
614
615 g_free(req.data);
616
617 /* Notify after processing the third request */
618 qvirtqueue_set_used_event(&vqpci->vq, 2);
619 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
620 qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
621 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
622 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
623 write_head = free_head;
624
625 /* No notification expected */
626 status = qvirtio_wait_status_byte_no_isr(&dev->vdev,
627 &vqpci->vq, req_addr + 528,
628 QVIRTIO_BLK_TIMEOUT_US);
629 g_assert_cmpint(status, ==, 0);
630
631 guest_free(qs->alloc, req_addr);
632
633 /* Read request */
634 req.type = VIRTIO_BLK_T_IN;
635 req.ioprio = 1;
636 req.sector = 1;
637 req.data = g_malloc0(512);
638
639 req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
640
641 g_free(req.data);
642
643 free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
644 qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, true, true);
645 qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
646
647 qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
648
649 /* We get just one notification for both requests */
650 qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, write_head, NULL,
651 QVIRTIO_BLK_TIMEOUT_US);
652 g_assert(qvirtqueue_get_buf(&vqpci->vq, &desc_idx, NULL));
653 g_assert_cmpint(desc_idx, ==, free_head);
654
655 status = readb(req_addr + 528);
656 g_assert_cmpint(status, ==, 0);
657
658 data = g_malloc0(512);
659 memread(req_addr + 16, data, 512);
660 g_assert_cmpstr(data, ==, "TEST");
661 g_free(data);
662
663 guest_free(qs->alloc, req_addr);
664
665 /* End test */
666 qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
667 qpci_msix_disable(dev->pdev);
668 qvirtio_pci_device_disable(dev);
669 qvirtio_pci_device_free(dev);
670 qtest_shutdown(qs);
671 }
672
673 static void pci_hotplug(void)
674 {
675 QVirtioPCIDevice *dev;
676 QOSState *qs;
677 const char *arch = qtest_get_arch();
678
679 qs = pci_test_start();
680
681 /* plug secondary disk */
682 qtest_qmp_device_add("virtio-blk-pci", "drv1",
683 "{'addr': %s, 'drive': 'drive1'}",
684 stringify(PCI_SLOT_HP));
685
686 dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT_HP);
687 g_assert(dev);
688 qvirtio_pci_device_disable(dev);
689 qvirtio_pci_device_free(dev);
690
691 /* unplug secondary disk */
692 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
693 qpci_unplug_acpi_device_test("drv1", PCI_SLOT_HP);
694 }
695 qtest_shutdown(qs);
696 }
697
698 /*
699 * Check that setting the vring addr on a non-existent virtqueue does
700 * not crash.
701 */
702 static void test_nonexistent_virtqueue(void)
703 {
704 QPCIBar bar0;
705 QOSState *qs;
706 QPCIDevice *dev;
707
708 qs = pci_test_start();
709 dev = qpci_device_find(qs->pcibus, QPCI_DEVFN(4, 0));
710 g_assert(dev != NULL);
711
712 qpci_device_enable(dev);
713 bar0 = qpci_iomap(dev, 0, NULL);
714
715 qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
716 qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
717
718 g_free(dev);
719 qtest_shutdown(qs);
720 }
721
722 static void mmio_basic(void)
723 {
724 QVirtioMMIODevice *dev;
725 QVirtQueue *vq;
726 QGuestAllocator *alloc;
727 int n_size = TEST_IMAGE_SIZE / 2;
728 uint64_t capacity;
729
730 arm_test_start();
731
732 dev = qvirtio_mmio_init_device(MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);
733 g_assert(dev != NULL);
734 g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
735
736 qvirtio_reset(&dev->vdev);
737 qvirtio_set_acknowledge(&dev->vdev);
738 qvirtio_set_driver(&dev->vdev);
739
740 alloc = generic_alloc_init(MMIO_RAM_ADDR, MMIO_RAM_SIZE, MMIO_PAGE_SIZE);
741 vq = qvirtqueue_setup(&dev->vdev, alloc, 0);
742
743 test_basic(&dev->vdev, alloc, vq);
744
745 qmp_discard_response("{ 'execute': 'block_resize', "
746 " 'arguments': { 'device': 'drive0', "
747 " 'size': %d } }", n_size);
748
749 qvirtio_wait_queue_isr(&dev->vdev, vq, QVIRTIO_BLK_TIMEOUT_US);
750
751 capacity = qvirtio_config_readq(&dev->vdev, 0);
752 g_assert_cmpint(capacity, ==, n_size / 512);
753
754 /* End test */
755 qvirtqueue_cleanup(dev->vdev.bus, vq, alloc);
756 g_free(dev);
757 generic_alloc_uninit(alloc);
758 test_end();
759 }
760
761 int main(int argc, char **argv)
762 {
763 const char *arch = qtest_get_arch();
764
765 g_test_init(&argc, &argv, NULL);
766
767 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0 ||
768 strcmp(arch, "ppc64") == 0) {
769 qtest_add_func("/virtio/blk/pci/basic", pci_basic);
770 qtest_add_func("/virtio/blk/pci/indirect", pci_indirect);
771 qtest_add_func("/virtio/blk/pci/config", pci_config);
772 qtest_add_func("/virtio/blk/pci/nxvirtq", test_nonexistent_virtqueue);
773 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
774 qtest_add_func("/virtio/blk/pci/msix", pci_msix);
775 qtest_add_func("/virtio/blk/pci/idx", pci_idx);
776 }
777 qtest_add_func("/virtio/blk/pci/hotplug", pci_hotplug);
778 } else if (strcmp(arch, "arm") == 0) {
779 qtest_add_func("/virtio/blk/mmio/basic", mmio_basic);
780 }
781
782 return g_test_run();
783 }