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