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