qemu/tests/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.h"
  13#include "libqos/libqos-pc.h"
  14#include "libqos/libqos-spapr.h"
  15#include "libqos/virtio.h"
  16#include "libqos/virtio-pci.h"
  17#include "libqos/virtio-mmio.h"
  18#include "libqos/malloc-generic.h"
  19#include "qemu/bswap.h"
  20#include "standard-headers/linux/virtio_ids.h"
  21#include "standard-headers/linux/virtio_config.h"
  22#include "standard-headers/linux/virtio_ring.h"
  23#include "standard-headers/linux/virtio_blk.h"
  24#include "standard-headers/linux/virtio_pci.h"
  25
  26#define TEST_IMAGE_SIZE         (64 * 1024 * 1024)
  27#define QVIRTIO_BLK_TIMEOUT_US  (30 * 1000 * 1000)
  28#define PCI_SLOT_HP             0x06
  29#define PCI_SLOT                0x04
  30#define PCI_FN                  0x00
  31
  32#define MMIO_PAGE_SIZE          4096
  33#define MMIO_DEV_BASE_ADDR      0x0A003E00
  34#define MMIO_RAM_ADDR           0x40000000
  35#define MMIO_RAM_SIZE           0x20000000
  36
  37typedef struct QVirtioBlkReq {
  38    uint32_t type;
  39    uint32_t ioprio;
  40    uint64_t sector;
  41    char *data;
  42    uint8_t status;
  43} QVirtioBlkReq;
  44
  45static char *drive_create(void)
  46{
  47    int fd, ret;
  48    char *tmp_path = g_strdup("/tmp/qtest.XXXXXX");
  49
  50    /* Create a temporary raw image */
  51    fd = mkstemp(tmp_path);
  52    g_assert_cmpint(fd, >=, 0);
  53    ret = ftruncate(fd, TEST_IMAGE_SIZE);
  54    g_assert_cmpint(ret, ==, 0);
  55    close(fd);
  56
  57    return tmp_path;
  58}
  59
  60static QOSState *pci_test_start(void)
  61{
  62    QOSState *qs;
  63    const char *arch = qtest_get_arch();
  64    char *tmp_path;
  65    const char *cmd = "-drive if=none,id=drive0,file=%s,format=raw "
  66                      "-drive if=none,id=drive1,file=null-co://,format=raw "
  67                      "-device virtio-blk-pci,id=drv0,drive=drive0,"
  68                      "addr=%x.%x";
  69
  70    tmp_path = drive_create();
  71
  72    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
  73        qs = qtest_pc_boot(cmd, tmp_path, PCI_SLOT, PCI_FN);
  74    } else if (strcmp(arch, "ppc64") == 0) {
  75        qs = qtest_spapr_boot(cmd, tmp_path, PCI_SLOT, PCI_FN);
  76    } else {
  77        g_printerr("virtio-blk tests are only available on x86 or ppc64\n");
  78        exit(EXIT_FAILURE);
  79    }
  80    unlink(tmp_path);
  81    g_free(tmp_path);
  82    return qs;
  83}
  84
  85static void arm_test_start(void)
  86{
  87    char *tmp_path;
  88
  89    tmp_path = drive_create();
  90
  91    global_qtest = qtest_startf("-machine virt "
  92                                "-drive if=none,id=drive0,file=%s,format=raw "
  93                                "-device virtio-blk-device,drive=drive0",
  94                                tmp_path);
  95    unlink(tmp_path);
  96    g_free(tmp_path);
  97}
  98
  99static void test_end(void)
 100{
 101    qtest_end();
 102}
 103
 104static QVirtioPCIDevice *virtio_blk_pci_init(QPCIBus *bus, int slot)
 105{
 106    QVirtioPCIDevice *dev;
 107
 108    dev = qvirtio_pci_device_find_slot(bus, VIRTIO_ID_BLOCK, slot);
 109    g_assert(dev != NULL);
 110    g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
 111    g_assert_cmphex(dev->pdev->devfn, ==, ((slot << 3) | PCI_FN));
 112
 113    qvirtio_pci_device_enable(dev);
 114    qvirtio_reset(&dev->vdev);
 115    qvirtio_set_acknowledge(&dev->vdev);
 116    qvirtio_set_driver(&dev->vdev);
 117
 118    return dev;
 119}
 120
 121static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
 122{
 123#ifdef HOST_WORDS_BIGENDIAN
 124    const bool host_is_big_endian = true;
 125#else
 126    const bool host_is_big_endian = false;
 127#endif
 128
 129    if (qvirtio_is_big_endian(d) != host_is_big_endian) {
 130        req->type = bswap32(req->type);
 131        req->ioprio = bswap32(req->ioprio);
 132        req->sector = bswap64(req->sector);
 133    }
 134}
 135
 136static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
 137                                   QVirtioBlkReq *req, uint64_t data_size)
 138{
 139    uint64_t addr;
 140    uint8_t status = 0xFF;
 141
 142    g_assert_cmpuint(data_size % 512, ==, 0);
 143    addr = guest_alloc(alloc, sizeof(*req) + data_size);
 144
 145    virtio_blk_fix_request(d, req);
 146
 147    memwrite(addr, req, 16);
 148    memwrite(addr + 16, req->data, data_size);
 149    memwrite(addr + 16 + data_size, &status, sizeof(status));
 150
 151    return addr;
 152}
 153
 154static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
 155                       QVirtQueue *vq)
 156{
 157    QVirtioBlkReq req;
 158    uint64_t req_addr;
 159    uint64_t capacity;
 160    uint32_t features;
 161    uint32_t free_head;
 162    uint8_t status;
 163    char *data;
 164
 165    capacity = qvirtio_config_readq(dev, 0);
 166
 167    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
 168
 169    features = qvirtio_get_features(dev);
 170    features = features & ~(QVIRTIO_F_BAD_FEATURE |
 171                    (1u << VIRTIO_RING_F_INDIRECT_DESC) |
 172                    (1u << VIRTIO_RING_F_EVENT_IDX) |
 173                    (1u << VIRTIO_BLK_F_SCSI));
 174    qvirtio_set_features(dev, features);
 175
 176    qvirtio_set_driver_ok(dev);
 177
 178    /* Write and read with 3 descriptor layout */
 179    /* Write request */
 180    req.type = VIRTIO_BLK_T_OUT;
 181    req.ioprio = 1;
 182    req.sector = 0;
 183    req.data = g_malloc0(512);
 184    strcpy(req.data, "TEST");
 185
 186    req_addr = virtio_blk_request(alloc, dev, &req, 512);
 187
 188    g_free(req.data);
 189
 190    free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
 191    qvirtqueue_add(vq, req_addr + 16, 512, false, true);
 192    qvirtqueue_add(vq, req_addr + 528, 1, true, false);
 193
 194    qvirtqueue_kick(dev, vq, free_head);
 195
 196    qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_BLK_TIMEOUT_US);
 197    status = readb(req_addr + 528);
 198    g_assert_cmpint(status, ==, 0);
 199
 200    guest_free(alloc, req_addr);
 201
 202    /* Read request */
 203    req.type = VIRTIO_BLK_T_IN;
 204    req.ioprio = 1;
 205    req.sector = 0;
 206    req.data = g_malloc0(512);
 207
 208    req_addr = virtio_blk_request(alloc, dev, &req, 512);
 209
 210    g_free(req.data);
 211
 212    free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
 213    qvirtqueue_add(vq, req_addr + 16, 512, true, true);
 214    qvirtqueue_add(vq, req_addr + 528, 1, true, false);
 215
 216    qvirtqueue_kick(dev, vq, free_head);
 217
 218    qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_BLK_TIMEOUT_US);
 219    status = readb(req_addr + 528);
 220    g_assert_cmpint(status, ==, 0);
 221
 222    data = g_malloc0(512);
 223    memread(req_addr + 16, data, 512);
 224    g_assert_cmpstr(data, ==, "TEST");
 225    g_free(data);
 226
 227    guest_free(alloc, req_addr);
 228
 229    if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
 230        /* Write and read with 2 descriptor layout */
 231        /* Write request */
 232        req.type = VIRTIO_BLK_T_OUT;
 233        req.ioprio = 1;
 234        req.sector = 1;
 235        req.data = g_malloc0(512);
 236        strcpy(req.data, "TEST");
 237
 238        req_addr = virtio_blk_request(alloc, dev, &req, 512);
 239
 240        g_free(req.data);
 241
 242        free_head = qvirtqueue_add(vq, req_addr, 528, false, true);
 243        qvirtqueue_add(vq, req_addr + 528, 1, true, false);
 244        qvirtqueue_kick(dev, vq, free_head);
 245
 246        qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_BLK_TIMEOUT_US);
 247        status = readb(req_addr + 528);
 248        g_assert_cmpint(status, ==, 0);
 249
 250        guest_free(alloc, req_addr);
 251
 252        /* Read request */
 253        req.type = VIRTIO_BLK_T_IN;
 254        req.ioprio = 1;
 255        req.sector = 1;
 256        req.data = g_malloc0(512);
 257
 258        req_addr = virtio_blk_request(alloc, dev, &req, 512);
 259
 260        g_free(req.data);
 261
 262        free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
 263        qvirtqueue_add(vq, req_addr + 16, 513, true, false);
 264
 265        qvirtqueue_kick(dev, vq, free_head);
 266
 267        qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_BLK_TIMEOUT_US);
 268        status = readb(req_addr + 528);
 269        g_assert_cmpint(status, ==, 0);
 270
 271        data = g_malloc0(512);
 272        memread(req_addr + 16, data, 512);
 273        g_assert_cmpstr(data, ==, "TEST");
 274        g_free(data);
 275
 276        guest_free(alloc, req_addr);
 277    }
 278}
 279
 280static void pci_basic(void)
 281{
 282    QVirtioPCIDevice *dev;
 283    QOSState *qs;
 284    QVirtQueuePCI *vqpci;
 285
 286    qs = pci_test_start();
 287    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
 288
 289    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
 290
 291    test_basic(&dev->vdev, qs->alloc, &vqpci->vq);
 292
 293    /* End test */
 294    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
 295    qvirtio_pci_device_disable(dev);
 296    qvirtio_pci_device_free(dev);
 297    qtest_shutdown(qs);
 298}
 299
 300static void pci_indirect(void)
 301{
 302    QVirtioPCIDevice *dev;
 303    QVirtQueuePCI *vqpci;
 304    QOSState *qs;
 305    QVirtioBlkReq req;
 306    QVRingIndirectDesc *indirect;
 307    uint64_t req_addr;
 308    uint64_t capacity;
 309    uint32_t features;
 310    uint32_t free_head;
 311    uint8_t status;
 312    char *data;
 313
 314    qs = pci_test_start();
 315
 316    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
 317
 318    capacity = qvirtio_config_readq(&dev->vdev, 0);
 319    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
 320
 321    features = qvirtio_get_features(&dev->vdev);
 322    g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
 323    features = features & ~(QVIRTIO_F_BAD_FEATURE |
 324                            (1u << VIRTIO_RING_F_EVENT_IDX) |
 325                            (1u << VIRTIO_BLK_F_SCSI));
 326    qvirtio_set_features(&dev->vdev, features);
 327
 328    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
 329    qvirtio_set_driver_ok(&dev->vdev);
 330
 331    /* Write request */
 332    req.type = VIRTIO_BLK_T_OUT;
 333    req.ioprio = 1;
 334    req.sector = 0;
 335    req.data = g_malloc0(512);
 336    strcpy(req.data, "TEST");
 337
 338    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
 339
 340    g_free(req.data);
 341
 342    indirect = qvring_indirect_desc_setup(&dev->vdev, qs->alloc, 2);
 343    qvring_indirect_desc_add(indirect, req_addr, 528, false);
 344    qvring_indirect_desc_add(indirect, req_addr + 528, 1, true);
 345    free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
 346    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
 347
 348    qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head,
 349                           QVIRTIO_BLK_TIMEOUT_US);
 350    status = readb(req_addr + 528);
 351    g_assert_cmpint(status, ==, 0);
 352
 353    g_free(indirect);
 354    guest_free(qs->alloc, req_addr);
 355
 356    /* Read request */
 357    req.type = VIRTIO_BLK_T_IN;
 358    req.ioprio = 1;
 359    req.sector = 0;
 360    req.data = g_malloc0(512);
 361    strcpy(req.data, "TEST");
 362
 363    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
 364
 365    g_free(req.data);
 366
 367    indirect = qvring_indirect_desc_setup(&dev->vdev, qs->alloc, 2);
 368    qvring_indirect_desc_add(indirect, req_addr, 16, false);
 369    qvring_indirect_desc_add(indirect, req_addr + 16, 513, true);
 370    free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect);
 371    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
 372
 373    qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head,
 374                           QVIRTIO_BLK_TIMEOUT_US);
 375    status = readb(req_addr + 528);
 376    g_assert_cmpint(status, ==, 0);
 377
 378    data = g_malloc0(512);
 379    memread(req_addr + 16, data, 512);
 380    g_assert_cmpstr(data, ==, "TEST");
 381    g_free(data);
 382
 383    g_free(indirect);
 384    guest_free(qs->alloc, req_addr);
 385
 386    /* End test */
 387    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
 388    qvirtio_pci_device_disable(dev);
 389    qvirtio_pci_device_free(dev);
 390    qtest_shutdown(qs);
 391}
 392
 393static void pci_config(void)
 394{
 395    QVirtioPCIDevice *dev;
 396    QOSState *qs;
 397    int n_size = TEST_IMAGE_SIZE / 2;
 398    uint64_t capacity;
 399
 400    qs = pci_test_start();
 401
 402    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
 403
 404    capacity = qvirtio_config_readq(&dev->vdev, 0);
 405    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
 406
 407    qvirtio_set_driver_ok(&dev->vdev);
 408
 409    qmp_discard_response("{ 'execute': 'block_resize', "
 410                         " 'arguments': { 'device': 'drive0', "
 411                         " 'size': %d } }", n_size);
 412    qvirtio_wait_config_isr(&dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
 413
 414    capacity = qvirtio_config_readq(&dev->vdev, 0);
 415    g_assert_cmpint(capacity, ==, n_size / 512);
 416
 417    qvirtio_pci_device_disable(dev);
 418    qvirtio_pci_device_free(dev);
 419
 420    qtest_shutdown(qs);
 421}
 422
 423static void pci_msix(void)
 424{
 425    QVirtioPCIDevice *dev;
 426    QOSState *qs;
 427    QVirtQueuePCI *vqpci;
 428    QVirtioBlkReq req;
 429    int n_size = TEST_IMAGE_SIZE / 2;
 430    uint64_t req_addr;
 431    uint64_t capacity;
 432    uint32_t features;
 433    uint32_t free_head;
 434    uint8_t status;
 435    char *data;
 436
 437    qs = pci_test_start();
 438
 439    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
 440    qpci_msix_enable(dev->pdev);
 441
 442    qvirtio_pci_set_msix_configuration_vector(dev, qs->alloc, 0);
 443
 444    capacity = qvirtio_config_readq(&dev->vdev, 0);
 445    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
 446
 447    features = qvirtio_get_features(&dev->vdev);
 448    features = features & ~(QVIRTIO_F_BAD_FEATURE |
 449                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
 450                            (1u << VIRTIO_RING_F_EVENT_IDX) |
 451                            (1u << VIRTIO_BLK_F_SCSI));
 452    qvirtio_set_features(&dev->vdev, features);
 453
 454    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
 455    qvirtqueue_pci_msix_setup(dev, vqpci, qs->alloc, 1);
 456
 457    qvirtio_set_driver_ok(&dev->vdev);
 458
 459    qmp_discard_response("{ 'execute': 'block_resize', "
 460                         " 'arguments': { 'device': 'drive0', "
 461                         " 'size': %d } }", n_size);
 462
 463    qvirtio_wait_config_isr(&dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
 464
 465    capacity = qvirtio_config_readq(&dev->vdev, 0);
 466    g_assert_cmpint(capacity, ==, n_size / 512);
 467
 468    /* Write request */
 469    req.type = VIRTIO_BLK_T_OUT;
 470    req.ioprio = 1;
 471    req.sector = 0;
 472    req.data = g_malloc0(512);
 473    strcpy(req.data, "TEST");
 474
 475    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
 476
 477    g_free(req.data);
 478
 479    free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
 480    qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
 481    qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
 482    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
 483
 484    qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head,
 485                           QVIRTIO_BLK_TIMEOUT_US);
 486
 487    status = readb(req_addr + 528);
 488    g_assert_cmpint(status, ==, 0);
 489
 490    guest_free(qs->alloc, req_addr);
 491
 492    /* Read request */
 493    req.type = VIRTIO_BLK_T_IN;
 494    req.ioprio = 1;
 495    req.sector = 0;
 496    req.data = g_malloc0(512);
 497
 498    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
 499
 500    g_free(req.data);
 501
 502    free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
 503    qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, true, true);
 504    qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
 505
 506    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
 507
 508
 509    qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head,
 510                           QVIRTIO_BLK_TIMEOUT_US);
 511
 512    status = readb(req_addr + 528);
 513    g_assert_cmpint(status, ==, 0);
 514
 515    data = g_malloc0(512);
 516    memread(req_addr + 16, data, 512);
 517    g_assert_cmpstr(data, ==, "TEST");
 518    g_free(data);
 519
 520    guest_free(qs->alloc, req_addr);
 521
 522    /* End test */
 523    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
 524    qpci_msix_disable(dev->pdev);
 525    qvirtio_pci_device_disable(dev);
 526    qvirtio_pci_device_free(dev);
 527    qtest_shutdown(qs);
 528}
 529
 530static void pci_idx(void)
 531{
 532    QVirtioPCIDevice *dev;
 533    QOSState *qs;
 534    QVirtQueuePCI *vqpci;
 535    QVirtioBlkReq req;
 536    uint64_t req_addr;
 537    uint64_t capacity;
 538    uint32_t features;
 539    uint32_t free_head;
 540    uint32_t write_head;
 541    uint32_t desc_idx;
 542    uint8_t status;
 543    char *data;
 544
 545    qs = pci_test_start();
 546
 547    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT);
 548    qpci_msix_enable(dev->pdev);
 549
 550    qvirtio_pci_set_msix_configuration_vector(dev, qs->alloc, 0);
 551
 552    capacity = qvirtio_config_readq(&dev->vdev, 0);
 553    g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
 554
 555    features = qvirtio_get_features(&dev->vdev);
 556    features = features & ~(QVIRTIO_F_BAD_FEATURE |
 557                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
 558                            (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
 559                            (1u << VIRTIO_BLK_F_SCSI));
 560    qvirtio_set_features(&dev->vdev, features);
 561
 562    vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&dev->vdev, qs->alloc, 0);
 563    qvirtqueue_pci_msix_setup(dev, vqpci, qs->alloc, 1);
 564
 565    qvirtio_set_driver_ok(&dev->vdev);
 566
 567    /* Write request */
 568    req.type = VIRTIO_BLK_T_OUT;
 569    req.ioprio = 1;
 570    req.sector = 0;
 571    req.data = g_malloc0(512);
 572    strcpy(req.data, "TEST");
 573
 574    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
 575
 576    g_free(req.data);
 577
 578    free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
 579    qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
 580    qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
 581    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
 582
 583    qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head,
 584                           QVIRTIO_BLK_TIMEOUT_US);
 585
 586    /* Write request */
 587    req.type = VIRTIO_BLK_T_OUT;
 588    req.ioprio = 1;
 589    req.sector = 1;
 590    req.data = g_malloc0(512);
 591    strcpy(req.data, "TEST");
 592
 593    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
 594
 595    g_free(req.data);
 596
 597    /* Notify after processing the third request */
 598    qvirtqueue_set_used_event(&vqpci->vq, 2);
 599    free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
 600    qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
 601    qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
 602    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
 603    write_head = free_head;
 604
 605    /* No notification expected */
 606    status = qvirtio_wait_status_byte_no_isr(&dev->vdev,
 607                                             &vqpci->vq, req_addr + 528,
 608                                             QVIRTIO_BLK_TIMEOUT_US);
 609    g_assert_cmpint(status, ==, 0);
 610
 611    guest_free(qs->alloc, req_addr);
 612
 613    /* Read request */
 614    req.type = VIRTIO_BLK_T_IN;
 615    req.ioprio = 1;
 616    req.sector = 1;
 617    req.data = g_malloc0(512);
 618
 619    req_addr = virtio_blk_request(qs->alloc, &dev->vdev, &req, 512);
 620
 621    g_free(req.data);
 622
 623    free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
 624    qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, true, true);
 625    qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
 626
 627    qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head);
 628
 629    /* We get just one notification for both requests */
 630    qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, write_head,
 631                           QVIRTIO_BLK_TIMEOUT_US);
 632    g_assert(qvirtqueue_get_buf(&vqpci->vq, &desc_idx));
 633    g_assert_cmpint(desc_idx, ==, free_head);
 634
 635    status = readb(req_addr + 528);
 636    g_assert_cmpint(status, ==, 0);
 637
 638    data = g_malloc0(512);
 639    memread(req_addr + 16, data, 512);
 640    g_assert_cmpstr(data, ==, "TEST");
 641    g_free(data);
 642
 643    guest_free(qs->alloc, req_addr);
 644
 645    /* End test */
 646    qvirtqueue_cleanup(dev->vdev.bus, &vqpci->vq, qs->alloc);
 647    qpci_msix_disable(dev->pdev);
 648    qvirtio_pci_device_disable(dev);
 649    qvirtio_pci_device_free(dev);
 650    qtest_shutdown(qs);
 651}
 652
 653static void pci_hotplug(void)
 654{
 655    QVirtioPCIDevice *dev;
 656    QOSState *qs;
 657    const char *arch = qtest_get_arch();
 658
 659    qs = pci_test_start();
 660
 661    /* plug secondary disk */
 662    qpci_plug_device_test("virtio-blk-pci", "drv1", PCI_SLOT_HP,
 663                          "'drive': 'drive1'");
 664
 665    dev = virtio_blk_pci_init(qs->pcibus, PCI_SLOT_HP);
 666    g_assert(dev);
 667    qvirtio_pci_device_disable(dev);
 668    qvirtio_pci_device_free(dev);
 669
 670    /* unplug secondary disk */
 671    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
 672        qpci_unplug_acpi_device_test("drv1", PCI_SLOT_HP);
 673    }
 674    qtest_shutdown(qs);
 675}
 676
 677static void mmio_basic(void)
 678{
 679    QVirtioMMIODevice *dev;
 680    QVirtQueue *vq;
 681    QGuestAllocator *alloc;
 682    int n_size = TEST_IMAGE_SIZE / 2;
 683    uint64_t capacity;
 684
 685    arm_test_start();
 686
 687    dev = qvirtio_mmio_init_device(MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);
 688    g_assert(dev != NULL);
 689    g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
 690
 691    qvirtio_reset(&dev->vdev);
 692    qvirtio_set_acknowledge(&dev->vdev);
 693    qvirtio_set_driver(&dev->vdev);
 694
 695    alloc = generic_alloc_init(MMIO_RAM_ADDR, MMIO_RAM_SIZE, MMIO_PAGE_SIZE);
 696    vq = qvirtqueue_setup(&dev->vdev, alloc, 0);
 697
 698    test_basic(&dev->vdev, alloc, vq);
 699
 700    qmp_discard_response("{ 'execute': 'block_resize', "
 701                         " 'arguments': { 'device': 'drive0', "
 702                         " 'size': %d } }", n_size);
 703
 704    qvirtio_wait_queue_isr(&dev->vdev, vq, QVIRTIO_BLK_TIMEOUT_US);
 705
 706    capacity = qvirtio_config_readq(&dev->vdev, 0);
 707    g_assert_cmpint(capacity, ==, n_size / 512);
 708
 709    /* End test */
 710    qvirtqueue_cleanup(dev->vdev.bus, vq, alloc);
 711    g_free(dev);
 712    generic_alloc_uninit(alloc);
 713    test_end();
 714}
 715
 716int main(int argc, char **argv)
 717{
 718    const char *arch = qtest_get_arch();
 719
 720    g_test_init(&argc, &argv, NULL);
 721
 722    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0 ||
 723        strcmp(arch, "ppc64") == 0) {
 724        qtest_add_func("/virtio/blk/pci/basic", pci_basic);
 725        qtest_add_func("/virtio/blk/pci/indirect", pci_indirect);
 726        qtest_add_func("/virtio/blk/pci/config", pci_config);
 727        if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
 728            qtest_add_func("/virtio/blk/pci/msix", pci_msix);
 729            qtest_add_func("/virtio/blk/pci/idx", pci_idx);
 730        }
 731        qtest_add_func("/virtio/blk/pci/hotplug", pci_hotplug);
 732    } else if (strcmp(arch, "arm") == 0) {
 733        qtest_add_func("/virtio/blk/mmio/basic", mmio_basic);
 734    }
 735
 736    return g_test_run();
 737}
 738