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