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