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