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