virtio-scsi.c 20.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Virtio SCSI HBA
 *
 * Copyright IBM, Corp. 2010
 * Copyright Red Hat, Inc. 2011
 *
 * Authors:
 *   Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
 *   Paolo Bonzini      <pbonzini@redhat.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
 *
 */

P
Paolo Bonzini 已提交
16
#include "hw/virtio/virtio-scsi.h"
17
#include "qemu/error-report.h"
P
Paolo Bonzini 已提交
18 19 20
#include <hw/scsi/scsi.h>
#include <block/scsi.h>
#include <hw/virtio/virtio-bus.h>
21

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
typedef struct VirtIOSCSIReq {
    VirtIOSCSI *dev;
    VirtQueue *vq;
    VirtQueueElement elem;
    QEMUSGList qsgl;
    SCSIRequest *sreq;
    union {
        char                  *buf;
        VirtIOSCSICmdReq      *cmd;
        VirtIOSCSICtrlTMFReq  *tmf;
        VirtIOSCSICtrlANReq   *an;
    } req;
    union {
        char                  *buf;
        VirtIOSCSICmdResp     *cmd;
        VirtIOSCSICtrlTMFResp *tmf;
        VirtIOSCSICtrlANResp  *an;
        VirtIOSCSIEvent       *event;
    } resp;
} VirtIOSCSIReq;

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
static inline int virtio_scsi_get_lun(uint8_t *lun)
{
    return ((lun[2] << 8) | lun[3]) & 0x3FFF;
}

static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun)
{
    if (lun[0] != 1) {
        return NULL;
    }
    if (lun[2] != 0 && !(lun[2] >= 0x40 && lun[2] < 0x80)) {
        return NULL;
    }
    return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun));
}

59 60 61 62
static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
{
    VirtIOSCSI *s = req->dev;
    VirtQueue *vq = req->vq;
63
    VirtIODevice *vdev = VIRTIO_DEVICE(s);
64 65 66 67 68 69 70
    virtqueue_push(vq, &req->elem, req->qsgl.size + req->elem.in_sg[0].iov_len);
    qemu_sglist_destroy(&req->qsgl);
    if (req->sreq) {
        req->sreq->hba_private = NULL;
        scsi_req_unref(req->sreq);
    }
    g_free(req);
71
    virtio_notify(vdev, vq);
72 73 74 75 76 77 78 79 80
}

static void virtio_scsi_bad_req(void)
{
    error_report("wrong size for virtio-scsi headers");
    exit(1);
}

static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg,
A
Avi Kivity 已提交
81
                                   hwaddr *addr, int num)
82
{
P
Paolo Bonzini 已提交
83
    qemu_sglist_init(qsgl, num, &address_space_memory);
84 85 86 87 88 89 90 91
    while (num--) {
        qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len);
    }
}

static void virtio_scsi_parse_req(VirtIOSCSI *s, VirtQueue *vq,
                                  VirtIOSCSIReq *req)
{
92
    assert(req->elem.in_num);
93 94 95
    req->vq = vq;
    req->dev = s;
    req->sreq = NULL;
96 97 98
    if (req->elem.out_num) {
        req->req.buf = req->elem.out_sg[0].iov_base;
    }
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    req->resp.buf = req->elem.in_sg[0].iov_base;

    if (req->elem.out_num > 1) {
        qemu_sgl_init_external(&req->qsgl, &req->elem.out_sg[1],
                               &req->elem.out_addr[1],
                               req->elem.out_num - 1);
    } else {
        qemu_sgl_init_external(&req->qsgl, &req->elem.in_sg[1],
                               &req->elem.in_addr[1],
                               req->elem.in_num - 1);
    }
}

static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
{
    VirtIOSCSIReq *req;
    req = g_malloc(sizeof(*req));
    if (!virtqueue_pop(vq, &req->elem)) {
        g_free(req);
        return NULL;
    }

    virtio_scsi_parse_req(s, vq, req);
    return req;
}

125 126 127
static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
{
    VirtIOSCSIReq *req = sreq->hba_private;
128
    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(req->dev);
129
    uint32_t n = virtio_queue_get_id(req->vq) - 2;
130

131
    assert(n < vs->conf.num_queues);
132
    qemu_put_be32s(f, &n);
133 134 135 136 137 138 139
    qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
}

static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
{
    SCSIBus *bus = sreq->bus;
    VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
140
    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
141
    VirtIOSCSIReq *req;
142
    uint32_t n;
143 144

    req = g_malloc(sizeof(*req));
145
    qemu_get_be32s(f, &n);
146
    assert(n < vs->conf.num_queues);
147
    qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
148
    virtio_scsi_parse_req(s, vs->cmd_vqs[n], req);
149 150 151 152 153 154 155 156 157 158 159 160

    scsi_req_ref(sreq);
    req->sreq = sreq;
    if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
        int req_mode =
            (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV);

        assert(req->sreq->cmd.mode == req_mode);
    }
    return req;
}

161
static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
162
{
163 164
    SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf->lun);
    SCSIRequest *r, *next;
A
Anthony Liguori 已提交
165
    BusChild *kid;
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
    int target;

    /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE".  */
    req->resp.tmf->response = VIRTIO_SCSI_S_OK;

    switch (req->req.tmf->subtype) {
    case VIRTIO_SCSI_T_TMF_ABORT_TASK:
    case VIRTIO_SCSI_T_TMF_QUERY_TASK:
        if (!d) {
            goto fail;
        }
        if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
            goto incorrect_lun;
        }
        QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
181 182
            VirtIOSCSIReq *cmd_req = r->hba_private;
            if (cmd_req && cmd_req->req.cmd->tag == req->req.tmf->tag) {
183 184 185
                break;
            }
        }
186 187 188 189 190 191
        if (r) {
            /*
             * Assert that the request has not been completed yet, we
             * check for it in the loop above.
             */
            assert(r->hba_private);
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
            if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
                /* "If the specified command is present in the task set, then
                 * return a service response set to FUNCTION SUCCEEDED".
                 */
                req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
            } else {
                scsi_req_cancel(r);
            }
        }
        break;

    case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
        if (!d) {
            goto fail;
        }
        if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
            goto incorrect_lun;
        }
        s->resetting++;
        qdev_reset_all(&d->qdev);
        s->resetting--;
        break;

    case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
    case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
    case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET:
        if (!d) {
            goto fail;
        }
        if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
            goto incorrect_lun;
        }
        QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
            if (r->hba_private) {
                if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) {
                    /* "If there is any command present in the task set, then
                     * return a service response set to FUNCTION SUCCEEDED".
                     */
                    req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
                    break;
                } else {
                    scsi_req_cancel(r);
                }
            }
        }
        break;

    case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
        target = req->req.tmf->lun[1];
        s->resetting++;
A
Anthony Liguori 已提交
242 243
        QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
             d = DO_UPCAST(SCSIDevice, qdev, kid->child);
244 245 246 247 248 249 250 251 252 253 254
             if (d->channel == 0 && d->id == target) {
                qdev_reset_all(&d->qdev);
             }
        }
        s->resetting--;
        break;

    case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
    default:
        req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_REJECTED;
        break;
255 256
    }

257 258 259 260 261 262 263 264
    return;

incorrect_lun:
    req->resp.tmf->response = VIRTIO_SCSI_S_INCORRECT_LUN;
    return;

fail:
    req->resp.tmf->response = VIRTIO_SCSI_S_BAD_TARGET;
265 266
}

267 268
static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
{
269 270 271 272
    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
    VirtIOSCSIReq *req;

    while ((req = virtio_scsi_pop_req(s, vq))) {
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
        int out_size, in_size;
        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
            virtio_scsi_bad_req();
            continue;
        }

        out_size = req->elem.out_sg[0].iov_len;
        in_size = req->elem.in_sg[0].iov_len;
        if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) {
            if (out_size < sizeof(VirtIOSCSICtrlTMFReq) ||
                in_size < sizeof(VirtIOSCSICtrlTMFResp)) {
                virtio_scsi_bad_req();
            }
            virtio_scsi_do_tmf(s, req);

        } else if (req->req.tmf->type == VIRTIO_SCSI_T_AN_QUERY ||
                   req->req.tmf->type == VIRTIO_SCSI_T_AN_SUBSCRIBE) {
            if (out_size < sizeof(VirtIOSCSICtrlANReq) ||
                in_size < sizeof(VirtIOSCSICtrlANResp)) {
                virtio_scsi_bad_req();
            }
            req->resp.an->event_actual = 0;
            req->resp.an->response = VIRTIO_SCSI_S_OK;
        }
        virtio_scsi_complete_req(req);
298 299 300
    }
}

301 302 303 304
static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
                                         size_t resid)
{
    VirtIOSCSIReq *req = r->hba_private;
305
    uint32_t sense_len;
306 307 308 309

    req->resp.cmd->response = VIRTIO_SCSI_S_OK;
    req->resp.cmd->status = status;
    if (req->resp.cmd->status == GOOD) {
310
        req->resp.cmd->resid = tswap32(resid);
311 312
    } else {
        req->resp.cmd->resid = 0;
313 314 315
        sense_len = scsi_req_get_sense(r, req->resp.cmd->sense,
                                       VIRTIO_SCSI_SENSE_SIZE);
        req->resp.cmd->sense_len = tswap32(sense_len);
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
    }
    virtio_scsi_complete_req(req);
}

static QEMUSGList *virtio_scsi_get_sg_list(SCSIRequest *r)
{
    VirtIOSCSIReq *req = r->hba_private;

    return &req->qsgl;
}

static void virtio_scsi_request_cancelled(SCSIRequest *r)
{
    VirtIOSCSIReq *req = r->hba_private;

    if (!req) {
        return;
    }
334 335 336 337 338
    if (req->dev->resetting) {
        req->resp.cmd->response = VIRTIO_SCSI_S_RESET;
    } else {
        req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED;
    }
339 340 341 342
    virtio_scsi_complete_req(req);
}

static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req)
343 344 345
{
    req->resp.cmd->response = VIRTIO_SCSI_S_FAILURE;
    virtio_scsi_complete_req(req);
346 347 348 349
}

static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
{
350
    /* use non-QOM casts in the data path */
351
    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
352 353
    VirtIOSCSICommon *vs = &s->parent_obj;

354
    VirtIOSCSIReq *req;
355
    int n;
356 357

    while ((req = virtio_scsi_pop_req(s, vq))) {
358
        SCSIDevice *d;
359 360 361 362 363 364 365
        int out_size, in_size;
        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
            virtio_scsi_bad_req();
        }

        out_size = req->elem.out_sg[0].iov_len;
        in_size = req->elem.in_sg[0].iov_len;
366 367
        if (out_size < sizeof(VirtIOSCSICmdReq) + vs->cdb_size ||
            in_size < sizeof(VirtIOSCSICmdResp) + vs->sense_size) {
368 369 370 371
            virtio_scsi_bad_req();
        }

        if (req->elem.out_num > 1 && req->elem.in_num > 1) {
372
            virtio_scsi_fail_cmd_req(req);
373 374 375
            continue;
        }

376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
        d = virtio_scsi_device_find(s, req->req.cmd->lun);
        if (!d) {
            req->resp.cmd->response = VIRTIO_SCSI_S_BAD_TARGET;
            virtio_scsi_complete_req(req);
            continue;
        }
        req->sreq = scsi_req_new(d, req->req.cmd->tag,
                                 virtio_scsi_get_lun(req->req.cmd->lun),
                                 req->req.cmd->cdb, req);

        if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
            int req_mode =
                (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV);

            if (req->sreq->cmd.mode != req_mode ||
                req->sreq->cmd.xfer > req->qsgl.size) {
                req->resp.cmd->response = VIRTIO_SCSI_S_OVERRUN;
                virtio_scsi_complete_req(req);
                continue;
            }
        }

        n = scsi_req_enqueue(req->sreq);
        if (n) {
            scsi_req_continue(req->sreq);
        }
402
    }
403 404 405 406 407 408
}

static void virtio_scsi_get_config(VirtIODevice *vdev,
                                   uint8_t *config)
{
    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
409
    VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev);
410

411
    stl_raw(&scsiconf->num_queues, s->conf.num_queues);
412
    stl_raw(&scsiconf->seg_max, 128 - 2);
413 414
    stl_raw(&scsiconf->max_sectors, s->conf.max_sectors);
    stl_raw(&scsiconf->cmd_per_lun, s->conf.cmd_per_lun);
415 416 417
    stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
    stl_raw(&scsiconf->sense_size, s->sense_size);
    stl_raw(&scsiconf->cdb_size, s->cdb_size);
418 419
    stw_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
    stw_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
420 421 422 423 424 425 426
    stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
}

static void virtio_scsi_set_config(VirtIODevice *vdev,
                                   const uint8_t *config)
{
    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
427
    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
428 429 430 431 432 433 434

    if ((uint32_t) ldl_raw(&scsiconf->sense_size) >= 65536 ||
        (uint32_t) ldl_raw(&scsiconf->cdb_size) >= 256) {
        error_report("bad data written to virtio-scsi configuration space");
        exit(1);
    }

435 436
    vs->sense_size = ldl_raw(&scsiconf->sense_size);
    vs->cdb_size = ldl_raw(&scsiconf->cdb_size);
437 438 439 440 441 442 443 444 445 446
}

static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
                                         uint32_t requested_features)
{
    return requested_features;
}

static void virtio_scsi_reset(VirtIODevice *vdev)
{
447 448
    VirtIOSCSI *s = VIRTIO_SCSI(vdev);
    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
449

450 451 452 453
    s->resetting++;
    qbus_reset_all(&s->bus.qbus);
    s->resetting--;

454 455
    vs->sense_size = VIRTIO_SCSI_SENSE_SIZE;
    vs->cdb_size = VIRTIO_SCSI_CDB_SIZE;
456
    s->events_dropped = false;
457 458
}

459 460 461 462 463
/* The device does not have anything to save beyond the virtio data.
 * Request data is saved with callbacks from SCSI devices.
 */
static void virtio_scsi_save(QEMUFile *f, void *opaque)
{
464 465
    VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
    virtio_save(vdev, f);
466 467 468 469
}

static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id)
{
470
    VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
471 472
    int ret;

473
    ret = virtio_load(vdev, f);
474 475 476
    if (ret) {
        return ret;
    }
477 478 479
    return 0;
}

480 481 482
static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
                                   uint32_t event, uint32_t reason)
{
483 484
    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
    VirtIOSCSIReq *req = virtio_scsi_pop_req(s, vs->event_vq);
485
    VirtIOSCSIEvent *evt;
486
    VirtIODevice *vdev = VIRTIO_DEVICE(s);
487
    int in_size;
488

489
    if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
490 491 492
        return;
    }

493 494 495 496
    if (!req) {
        s->events_dropped = true;
        return;
    }
497

498 499 500
    if (req->elem.out_num || req->elem.in_num != 1) {
        virtio_scsi_bad_req();
    }
501

502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
    if (s->events_dropped) {
        event |= VIRTIO_SCSI_T_EVENTS_MISSED;
        s->events_dropped = false;
    }

    in_size = req->elem.in_sg[0].iov_len;
    if (in_size < sizeof(VirtIOSCSIEvent)) {
        virtio_scsi_bad_req();
    }

    evt = req->resp.event;
    memset(evt, 0, sizeof(VirtIOSCSIEvent));
    evt->event = event;
    evt->reason = reason;
    if (!dev) {
        assert(event == VIRTIO_SCSI_T_NO_EVENT);
    } else {
519 520 521 522 523 524 525 526
        evt->lun[0] = 1;
        evt->lun[1] = dev->id;

        /* Linux wants us to keep the same encoding we use for REPORT LUNS.  */
        if (dev->lun >= 256) {
            evt->lun[2] = (dev->lun >> 8) | 0x40;
        }
        evt->lun[3] = dev->lun & 0xFF;
527 528 529 530 531 532
    }
    virtio_scsi_complete_req(req);
}

static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
{
533
    VirtIOSCSI *s = VIRTIO_SCSI(vdev);
534 535 536

    if (s->events_dropped) {
        virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
537 538 539
    }
}

540 541 542
static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
{
    VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
543
    VirtIODevice *vdev = VIRTIO_DEVICE(s);
544

545
    if (((vdev->guest_features >> VIRTIO_SCSI_F_CHANGE) & 1) &&
546 547 548 549 550 551
        dev->type != TYPE_ROM) {
        virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
                               sense.asc | (sense.ascq << 8));
    }
}

552 553 554
static void virtio_scsi_hotplug(SCSIBus *bus, SCSIDevice *dev)
{
    VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
555
    VirtIODevice *vdev = VIRTIO_DEVICE(s);
556

557
    if ((vdev->guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) {
558 559 560 561 562 563 564 565
        virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET,
                               VIRTIO_SCSI_EVT_RESET_RESCAN);
    }
}

static void virtio_scsi_hot_unplug(SCSIBus *bus, SCSIDevice *dev)
{
    VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
566
    VirtIODevice *vdev = VIRTIO_DEVICE(s);
567

568
    if ((vdev->guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) {
569 570 571 572 573
        virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET,
                               VIRTIO_SCSI_EVT_RESET_REMOVED);
    }
}

574 575 576 577 578 579 580 581
static struct SCSIBusInfo virtio_scsi_scsi_info = {
    .tcq = true,
    .max_channel = VIRTIO_SCSI_MAX_CHANNEL,
    .max_target = VIRTIO_SCSI_MAX_TARGET,
    .max_lun = VIRTIO_SCSI_MAX_LUN,

    .complete = virtio_scsi_command_complete,
    .cancel = virtio_scsi_request_cancelled,
582
    .change = virtio_scsi_change,
583 584
    .hotplug = virtio_scsi_hotplug,
    .hot_unplug = virtio_scsi_hot_unplug,
585
    .get_sg_list = virtio_scsi_get_sg_list,
586 587
    .save_request = virtio_scsi_save_request,
    .load_request = virtio_scsi_load_request,
588 589
};

590
int virtio_scsi_common_init(VirtIOSCSICommon *s)
591
{
592
    VirtIODevice *vdev = VIRTIO_DEVICE(s);
593
    int i;
594

595 596
    virtio_init(VIRTIO_DEVICE(s), "virtio-scsi", VIRTIO_ID_SCSI,
                sizeof(VirtIOSCSIConfig));
597

598
    s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *));
599 600
    s->sense_size = VIRTIO_SCSI_SENSE_SIZE;
    s->cdb_size = VIRTIO_SCSI_CDB_SIZE;
601

602 603 604
    s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
                                  virtio_scsi_handle_ctrl);
    s->event_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
605
                                   virtio_scsi_handle_event);
606
    for (i = 0; i < s->conf.num_queues; i++) {
607
        s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
608 609
                                         virtio_scsi_handle_cmd);
    }
610

611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
    return 0;
}

static int virtio_scsi_device_init(VirtIODevice *vdev)
{
    DeviceState *qdev = DEVICE(vdev);
    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
    VirtIOSCSI *s = VIRTIO_SCSI(vdev);
    static int virtio_scsi_id;
    int ret;

    ret = virtio_scsi_common_init(vs);
    if (ret < 0) {
        return ret;
    }

627 628
    scsi_bus_new(&s->bus, qdev, &virtio_scsi_scsi_info, vdev->bus_name);

629
    if (!qdev->hotplugged) {
630 631 632
        scsi_bus_legacy_handle_cmdline(&s->bus);
    }

633
    register_savevm(qdev, "virtio-scsi", virtio_scsi_id++, 1,
634
                    virtio_scsi_save, virtio_scsi_load, s);
635

636 637 638
    return 0;
}

639 640 641 642 643
int virtio_scsi_common_exit(VirtIOSCSICommon *vs)
{
    VirtIODevice *vdev = VIRTIO_DEVICE(vs);

    g_free(vs->cmd_vqs);
644
    virtio_cleanup(vdev);
645 646 647
    return 0;
}

648 649 650
static int virtio_scsi_device_exit(DeviceState *qdev)
{
    VirtIOSCSI *s = VIRTIO_SCSI(qdev);
651
    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev);
652 653

    unregister_savevm(qdev, "virtio-scsi", s);
654
    return virtio_scsi_common_exit(vs);
655 656 657
}

static Property virtio_scsi_properties[] = {
658
    DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSI, parent_obj.conf),
659 660 661
    DEFINE_PROP_END_OF_LIST(),
};

662 663 664 665 666 667 668
static void virtio_scsi_common_class_init(ObjectClass *klass, void *data)
{
    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);

    vdc->get_config = virtio_scsi_get_config;
}

669 670 671 672 673 674 675 676 677 678 679 680
static void virtio_scsi_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
    dc->exit = virtio_scsi_device_exit;
    dc->props = virtio_scsi_properties;
    vdc->init = virtio_scsi_device_init;
    vdc->set_config = virtio_scsi_set_config;
    vdc->get_features = virtio_scsi_get_features;
    vdc->reset = virtio_scsi_reset;
}

681 682 683 684 685 686 687
static const TypeInfo virtio_scsi_common_info = {
    .name = TYPE_VIRTIO_SCSI_COMMON,
    .parent = TYPE_VIRTIO_DEVICE,
    .instance_size = sizeof(VirtIOSCSICommon),
    .class_init = virtio_scsi_common_class_init,
};

688 689
static const TypeInfo virtio_scsi_info = {
    .name = TYPE_VIRTIO_SCSI,
690
    .parent = TYPE_VIRTIO_SCSI_COMMON,
691 692 693 694 695 696
    .instance_size = sizeof(VirtIOSCSI),
    .class_init = virtio_scsi_class_init,
};

static void virtio_register_types(void)
{
697
    type_register_static(&virtio_scsi_common_info);
698 699 700 701
    type_register_static(&virtio_scsi_info);
}

type_init(virtio_register_types)