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