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()
This commit is contained in:
Anthony Liguori 2012-09-25 16:06:16 -05:00
commit d352210aed
4 changed files with 63 additions and 29 deletions

View File

@ -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;
}

View File

@ -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:

View File

@ -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);

View File

@ -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);