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