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