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