Commit e6451fd3 authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'bonzini/scsi-next' into staging



* bonzini/scsi-next:
  virtio-scsi: Fix subtle (guest) endian bug
  virtio-scsi: Fix some endian bugs with virtio-scsi
  iscsi: do not assume device is zero initialized
  iscsi: fix deadlock during login
  iscsi: fix segfault in url parsing

Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
parents 0a6b2ac0 863d1050
Loading
Loading
Loading
Loading
+77 −183
Original line number Diff line number Diff line
@@ -65,13 +65,6 @@ typedef struct IscsiAIOCB {
#endif
} IscsiAIOCB;

struct IscsiTask {
    IscsiLun *iscsilun;
    BlockDriverState *bs;
    int status;
    int complete;
};

static void
iscsi_bh_cb(void *p)
{
@@ -665,163 +658,6 @@ iscsi_getlength(BlockDriverState *bs)
    return len;
}

static void
iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
                        void *command_data, void *opaque)
{
    struct IscsiTask *itask = opaque;
    struct scsi_readcapacity16 *rc16;
    struct scsi_task *task = command_data;

    if (status != 0) {
        error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
                     iscsi_get_error(iscsi));
        itask->status   = 1;
        itask->complete = 1;
        scsi_free_scsi_task(task);
        return;
    }

    rc16 = scsi_datain_unmarshall(task);
    if (rc16 == NULL) {
        error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
        itask->status   = 1;
        itask->complete = 1;
        scsi_free_scsi_task(task);
        return;
    }

    itask->iscsilun->block_size = rc16->block_length;
    itask->iscsilun->num_blocks = rc16->returned_lba + 1;
    itask->bs->total_sectors    = itask->iscsilun->num_blocks *
                               itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;

    itask->status   = 0;
    itask->complete = 1;
    scsi_free_scsi_task(task);
}

static void
iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
                        void *command_data, void *opaque)
{
    struct IscsiTask *itask = opaque;
    struct scsi_readcapacity10 *rc10;
    struct scsi_task *task = command_data;

    if (status != 0) {
        error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
                     iscsi_get_error(iscsi));
        itask->status   = 1;
        itask->complete = 1;
        scsi_free_scsi_task(task);
        return;
    }

    rc10 = scsi_datain_unmarshall(task);
    if (rc10 == NULL) {
        error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
        itask->status   = 1;
        itask->complete = 1;
        scsi_free_scsi_task(task);
        return;
    }

    itask->iscsilun->block_size = rc10->block_size;
    if (rc10->lba == 0) {
        /* blank disk loaded */
        itask->iscsilun->num_blocks = 0;
    } else {
        itask->iscsilun->num_blocks = rc10->lba + 1;
    }
    itask->bs->total_sectors    = itask->iscsilun->num_blocks *
                               itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;

    itask->status   = 0;
    itask->complete = 1;
    scsi_free_scsi_task(task);
}

static void
iscsi_inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data,
                 void *opaque)
{
    struct IscsiTask *itask = opaque;
    struct scsi_task *task = command_data;
    struct scsi_inquiry_standard *inq;

    if (status != 0) {
        itask->status   = 1;
        itask->complete = 1;
        scsi_free_scsi_task(task);
        return;
    }

    inq = scsi_datain_unmarshall(task);
    if (inq == NULL) {
        error_report("iSCSI: Failed to unmarshall inquiry data.");
        itask->status   = 1;
        itask->complete = 1;
        scsi_free_scsi_task(task);
        return;
    }

    itask->iscsilun->type = inq->periperal_device_type;

    scsi_free_scsi_task(task);

    switch (itask->iscsilun->type) {
    case TYPE_DISK:
        task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun,
                                   iscsi_readcapacity16_cb, opaque);
        if (task == NULL) {
            error_report("iSCSI: failed to send readcapacity16 command.");
            itask->status   = 1;
            itask->complete = 1;
            return;
        }
        break;
    case TYPE_ROM:
        task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun,
                                   0, 0,
                                   iscsi_readcapacity10_cb, opaque);
        if (task == NULL) {
            error_report("iSCSI: failed to send readcapacity16 command.");
            itask->status   = 1;
            itask->complete = 1;
            return;
        }
        break;
    default:
        itask->status   = 0;
        itask->complete = 1;
    }
}

static void
iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
                 void *opaque)
{
    struct IscsiTask *itask = opaque;
    struct scsi_task *task;

    if (status != 0) {
        itask->status   = 1;
        itask->complete = 1;
        return;
    }

    task = iscsi_inquiry_task(iscsi, itask->iscsilun->lun,
                              0, 0, 36,
                              iscsi_inquiry_cb, opaque);
    if (task == NULL) {
        error_report("iSCSI: failed to send inquiry command.");
        itask->status   = 1;
        itask->complete = 1;
        return;
    }
}

static int parse_chap(struct iscsi_context *iscsi, const char *target)
{
    QemuOptsList *list;
@@ -934,7 +770,10 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
    IscsiLun *iscsilun = bs->opaque;
    struct iscsi_context *iscsi = NULL;
    struct iscsi_url *iscsi_url = NULL;
    struct IscsiTask task;
    struct scsi_task *task = NULL;
    struct scsi_inquiry_standard *inq = NULL;
    struct scsi_readcapacity10 *rc10 = NULL;
    struct scsi_readcapacity16 *rc16 = NULL;
    char *initiator_name = NULL;
    int ret;

@@ -947,8 +786,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)

    iscsi_url = iscsi_parse_full_url(iscsi, filename);
    if (iscsi_url == NULL) {
        error_report("Failed to parse URL : %s %s", filename,
                     iscsi_get_error(iscsi));
        error_report("Failed to parse URL : %s", filename);
        ret = -EINVAL;
        goto out;
    }
@@ -998,32 +836,79 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
    /* check if we got HEADER_DIGEST via the options */
    parse_header_digest(iscsi, iscsi_url->target);

    task.iscsilun = iscsilun;
    task.status = 0;
    task.complete = 0;
    task.bs = bs;
    if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
        error_report("iSCSI: Failed to connect to LUN : %s",
            iscsi_get_error(iscsi));
        ret = -EINVAL;
        goto out;
    }

    iscsilun->iscsi = iscsi;
    iscsilun->lun   = iscsi_url->lun;

    if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url->lun,
                                 iscsi_connect_cb, &task)
        != 0) {
        error_report("iSCSI: Failed to start async connect.");
    task = iscsi_inquiry_sync(iscsi, iscsilun->lun, 0, 0, 36);

    if (task == NULL || task->status != SCSI_STATUS_GOOD) {
        error_report("iSCSI: failed to send inquiry command.");
        ret = -EINVAL;
        goto out;
    }

    while (!task.complete) {
        iscsi_set_events(iscsilun);
        qemu_aio_wait();
    inq = scsi_datain_unmarshall(task);
    if (inq == NULL) {
        error_report("iSCSI: Failed to unmarshall inquiry data.");
        ret = -EINVAL;
        goto out;
    }
    if (task.status != 0) {
        error_report("iSCSI: Failed to connect to LUN : %s",
                     iscsi_get_error(iscsi));

    iscsilun->type = inq->periperal_device_type;

    scsi_free_scsi_task(task);

    switch (iscsilun->type) {
    case TYPE_DISK:
        task = iscsi_readcapacity16_sync(iscsi, iscsilun->lun);
        if (task == NULL || task->status != SCSI_STATUS_GOOD) {
            error_report("iSCSI: failed to send readcapacity16 command.");
            ret = -EINVAL;
            goto out;
        }
        rc16 = scsi_datain_unmarshall(task);
        if (rc16 == NULL) {
            error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
            ret = -EINVAL;
            goto out;
        }
        iscsilun->block_size = rc16->block_length;
        iscsilun->num_blocks = rc16->returned_lba + 1;
        break;
    case TYPE_ROM:
        task = iscsi_readcapacity10_sync(iscsi, iscsilun->lun, 0, 0);
        if (task == NULL || task->status != SCSI_STATUS_GOOD) {
            error_report("iSCSI: failed to send readcapacity10 command.");
            ret = -EINVAL;
            goto out;
        }
        rc10 = scsi_datain_unmarshall(task);
        if (rc10 == NULL) {
            error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
            ret = -EINVAL;
            goto out;
        }
        iscsilun->block_size = rc10->block_size;
        if (rc10->lba == 0) {
            /* blank disk loaded */
            iscsilun->num_blocks = 0;
        } else {
            iscsilun->num_blocks = rc10->lba + 1;
        }
        break;
    default:
        break;
    }

    bs->total_sectors    = iscsilun->num_blocks *
                           iscsilun->block_size / BDRV_SECTOR_SIZE ;

    /* Medium changer or tape. We dont have any emulation for this so this must
     * be sg ioctl compatible. We force it to be sg, otherwise qemu will try
@@ -1043,6 +928,9 @@ out:
    if (iscsi_url != NULL) {
        iscsi_destroy_url(iscsi_url);
    }
    if (task != NULL) {
        scsi_free_scsi_task(task);
    }

    if (ret) {
        if (iscsi != NULL) {
@@ -1063,6 +951,11 @@ static void iscsi_close(BlockDriverState *bs)
    memset(iscsilun, 0, sizeof(IscsiLun));
}

static int iscsi_has_zero_init(BlockDriverState *bs)
{
    return 0;
}

static BlockDriver bdrv_iscsi = {
    .format_name     = "iscsi",
    .protocol_name   = "iscsi",
@@ -1078,6 +971,7 @@ static BlockDriver bdrv_iscsi = {
    .bdrv_aio_flush  = iscsi_aio_flush,

    .bdrv_aio_discard = iscsi_aio_discard,
    .bdrv_has_zero_init = iscsi_has_zero_init,

#ifdef __linux__
    .bdrv_ioctl       = iscsi_ioctl,
+7 −5
Original line number Diff line number Diff line
@@ -424,15 +424,17 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
                                         size_t resid)
{
    VirtIOSCSIReq *req = r->hba_private;
    uint32_t sense_len;

    req->resp.cmd->response = VIRTIO_SCSI_S_OK;
    req->resp.cmd->status = status;
    if (req->resp.cmd->status == GOOD) {
        req->resp.cmd->resid = resid;
        req->resp.cmd->resid = tswap32(resid);
    } else {
        req->resp.cmd->resid = 0;
        req->resp.cmd->sense_len =
            scsi_req_get_sense(r, req->resp.cmd->sense, VIRTIO_SCSI_SENSE_SIZE);
        sense_len = scsi_req_get_sense(r, req->resp.cmd->sense,
                                       VIRTIO_SCSI_SENSE_SIZE);
        req->resp.cmd->sense_len = tswap32(sense_len);
    }
    virtio_scsi_complete_req(req);
}
@@ -532,8 +534,8 @@ static void virtio_scsi_get_config(VirtIODevice *vdev,
    stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
    stl_raw(&scsiconf->sense_size, s->sense_size);
    stl_raw(&scsiconf->cdb_size, s->cdb_size);
    stl_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
    stl_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
    stw_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
    stw_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
    stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
}