diff --git a/block/iscsi.c b/block/iscsi.c index 0b96165ec2fab100f2e26d6b26b7b0d8f79f7f89..fb001b955c5f42e72a57363141196f1dd3a48f6d 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -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; } diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 4981a024365bc7646f60fea6f21225f9897303ed..058d3b237fba918cda53fcfce440358766c90dd3 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -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: diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 1585683bce37b4f8d13411a4e0daebc93f372cca..95e91585e65d2a5c9f4305cba4f95fbe88dba45e 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -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); diff --git a/hw/scsi.h b/hw/scsi.h index 1aeee4659c6fa0599cb0f0286c0bb375dd32c895..b8f73577d32b5ea5150bae74eb53285cecc24c72 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -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);