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

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

* bonzini/scsi-next:
  SCSI: Standard INQUIRY data should report HiSup flag as set.
  scsi-disk: use scsi_data_cdb_length
  scsi: introduce scsi_cdb_length and scsi_data_cdb_length
  scsi-disk: fix check for out-of-range LBA
  scsi-disk: introduce check_lba_range
  iSCSI: We dont need to explicitely call qemu_notify_event() any more
  iSCSI: We need to support SG_IO also from iscsi_ioctl()
parents 09d0726c 1109c894
Loading
Loading
Loading
Loading
+17 −6
Original line number Diff line number Diff line
@@ -167,12 +167,6 @@ iscsi_set_events(IscsiLun *iscsilun)

    }

    /* If we just added an event, the callback might be delayed
     * unless we call qemu_notify_event().
     */
    if (ev & ~iscsilun->events) {
        qemu_notify_event();
    }
    iscsilun->events = ev;
}

@@ -628,9 +622,17 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
    return &acb->common;
}


static void ioctl_cb(void *opaque, int status)
{
    int *p_status = opaque;
    *p_status = status;
}

static int iscsi_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
{
    IscsiLun *iscsilun = bs->opaque;
    int status;

    switch (req) {
    case SG_GET_VERSION_NUM:
@@ -639,6 +641,15 @@ static int iscsi_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
    case SG_GET_SCSI_ID:
        ((struct sg_scsi_id *)buf)->scsi_type = iscsilun->type;
        break;
    case SG_IO:
        status = -EINPROGRESS;
        iscsi_aio_ioctl(bs, req, buf, ioctl_cb, &status);

        while (status == -EINPROGRESS) {
            qemu_aio_wait();
        }

        return 0;
    default:
        return -1;
    }
+18 −5
Original line number Diff line number Diff line
@@ -801,26 +801,39 @@ static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf)
    return xfer * unit;
}

static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
uint32_t scsi_data_cdb_length(uint8_t *buf)
{
    if ((buf[0] >> 5) == 0 && buf[4] == 0) {
        return 256;
    } else {
        return scsi_cdb_length(buf);
    }
}

uint32_t scsi_cdb_length(uint8_t *buf)
{
    switch (buf[0] >> 5) {
    case 0:
        cmd->xfer = buf[4];
        return buf[4];
        break;
    case 1:
    case 2:
        cmd->xfer = lduw_be_p(&buf[7]);
        return lduw_be_p(&buf[7]);
        break;
    case 4:
        cmd->xfer = ldl_be_p(&buf[10]) & 0xffffffffULL;
        return ldl_be_p(&buf[10]) & 0xffffffffULL;
        break;
    case 5:
        cmd->xfer = ldl_be_p(&buf[6]) & 0xffffffffULL;
        return ldl_be_p(&buf[6]) & 0xffffffffULL;
        break;
    default:
        return -1;
    }
}

static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
{
    cmd->xfer = scsi_cdb_length(buf);
    switch (buf[0]) {
    case TEST_UNIT_READY:
    case REWIND:
+26 −18
Original line number Diff line number Diff line
@@ -678,7 +678,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
     * is actually implemented, but we're good enough.
     */
    outbuf[2] = 5;
    outbuf[3] = 2; /* Format 2 */
    outbuf[3] = 2 | 0x10; /* Format 2, HiSup */

    if (buflen > 36) {
        outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
@@ -1449,6 +1449,22 @@ invalid_field:
    return;
}

static inline bool check_lba_range(SCSIDiskState *s,
                                   uint64_t sector_num, uint32_t nb_sectors)
{
    /*
     * The first line tests that no overflow happens when computing the last
     * sector.  The second line tests that the last accessed sector is in
     * range.
     *
     * Careful, the computations should not underflow for nb_sectors == 0,
     * and a 0-block read to the first LBA beyond the end of device is
     * valid.
     */
    return (sector_num <= sector_num + nb_sectors &&
            sector_num + nb_sectors <= s->qdev.max_lba + 1);
}

typedef struct UnmapCBData {
    SCSIDiskReq *r;
    uint8_t *inbuf;
@@ -1473,8 +1489,7 @@ static void scsi_unmap_complete(void *opaque, int ret)
    if (data->count > 0 && !r->req.io_canceled) {
        sector_num = ldq_be_p(&data->inbuf[0]);
        nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
        if (sector_num > sector_num + nb_sectors ||
            sector_num + nb_sectors - 1 > s->qdev.max_lba) {
        if (!check_lba_range(s, sector_num, nb_sectors)) {
            scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
            goto done;
        }
@@ -1793,17 +1808,13 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
        DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer);
        break;
    case WRITE_SAME_10:
        nb_sectors = lduw_be_p(&req->cmd.buf[7]);
        goto write_same;
    case WRITE_SAME_16:
        nb_sectors = ldl_be_p(&req->cmd.buf[10]) & 0xffffffffULL;
    write_same:
        nb_sectors = scsi_data_cdb_length(r->req.cmd.buf);
        if (bdrv_is_read_only(s->qdev.conf.bs)) {
            scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
            return 0;
        }
        if (r->req.cmd.lba > r->req.cmd.lba + nb_sectors ||
            r->req.cmd.lba + nb_sectors - 1 > s->qdev.max_lba) {
        if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
            goto illegal_lba;
        }

@@ -1858,7 +1869,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
{
    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
    int32_t len;
    uint32_t len;
    uint8_t command;

    command = buf[0];
@@ -1868,18 +1879,17 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
        return 0;
    }

    len = scsi_data_cdb_length(r->req.cmd.buf);
    switch (command) {
    case READ_6:
    case READ_10:
    case READ_12:
    case READ_16:
        len = r->req.cmd.xfer / s->qdev.blocksize;
        DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
        DPRINTF("Read (sector %" PRId64 ", count %u)\n", r->req.cmd.lba, len);
        if (r->req.cmd.buf[1] & 0xe0) {
            goto illegal_request;
        }
        if (r->req.cmd.lba > r->req.cmd.lba + len ||
            r->req.cmd.lba + len - 1 > s->qdev.max_lba) {
        if (!check_lba_range(s, r->req.cmd.lba, len)) {
            goto illegal_lba;
        }
        r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
@@ -1900,15 +1910,13 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
    case VERIFY_10:
    case VERIFY_12:
    case VERIFY_16:
        len = r->req.cmd.xfer / s->qdev.blocksize;
        DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
        DPRINTF("Write %s(sector %" PRId64 ", count %u)\n",
                (command & 0xe) == 0xe ? "And Verify " : "",
                r->req.cmd.lba, len);
        if (r->req.cmd.buf[1] & 0xe0) {
            goto illegal_request;
        }
        if (r->req.cmd.lba > r->req.cmd.lba + len ||
            r->req.cmd.lba + len - 1 > s->qdev.max_lba) {
        if (!check_lba_range(s, r->req.cmd.lba, len)) {
            goto illegal_lba;
        }
        r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
+2 −0
Original line number Diff line number Diff line
@@ -218,6 +218,8 @@ extern const struct SCSISense sense_code_WRITE_PROTECTED;

#define SENSE_CODE(x) sense_code_ ## x

uint32_t scsi_data_cdb_length(uint8_t *buf);
uint32_t scsi_cdb_length(uint8_t *buf);
int scsi_sense_valid(SCSISense sense);
int scsi_build_sense(uint8_t *in_buf, int in_len,
                     uint8_t *buf, int len, bool fixed);