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

* remotes/bonzini/scsi-next:
  block/iscsi: fix segfault if writesame fails
  scsi-disk: Add support for port WWN and index descriptors in VPD page 83h
  block/iscsi: query for supported VPD pages
  block/iscsi: fix deadlock on scsi check condition
  scsi-bus: Fix transfer length for VERIFY with BYTCHK=11b
  scsi: report thin provisioning errors with werror=report
  scsi: Change scsi sense buf size to 252

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2014-03-04 14:25:34 +00:00
commit 739aa555b8
6 changed files with 113 additions and 71 deletions

View file

@ -145,12 +145,13 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
if (iTask->retries-- > 0 && status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION) {
error_report("iSCSI CheckCondition: %s", iscsi_get_error(iscsi));
iTask->do_retry = 1;
goto out;
}
if (status != SCSI_STATUS_GOOD) {
error_report("iSCSI: Failure. %s", iscsi_get_error(iscsi));
error_report("iSCSI Failure: %s", iscsi_get_error(iscsi));
}
out:
@ -325,6 +326,7 @@ retry:
}
if (iTask.do_retry) {
iTask.complete = 0;
goto retry;
}
@ -399,6 +401,7 @@ retry:
}
if (iTask.do_retry) {
iTask.complete = 0;
goto retry;
}
@ -433,6 +436,7 @@ retry:
}
if (iTask.do_retry) {
iTask.complete = 0;
goto retry;
}
@ -683,6 +687,7 @@ retry:
scsi_free_scsi_task(iTask.task);
iTask.task = NULL;
}
iTask.complete = 0;
goto retry;
}
@ -767,6 +772,7 @@ retry:
}
if (iTask.do_retry) {
iTask.complete = 0;
goto retry;
}
@ -830,24 +836,26 @@ retry:
qemu_coroutine_yield();
}
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
/* WRITE SAME is not supported by the target */
iscsilun->has_write_same = false;
scsi_free_scsi_task(iTask.task);
return -ENOTSUP;
}
if (iTask.task != NULL) {
scsi_free_scsi_task(iTask.task);
iTask.task = NULL;
}
if (iTask.do_retry) {
iTask.complete = 0;
goto retry;
}
if (iTask.status != SCSI_STATUS_GOOD) {
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
/* WRITE SAME is not supported by the target */
iscsilun->has_write_same = false;
return -ENOTSUP;
}
return -EIO;
}
@ -1060,7 +1068,7 @@ static QemuOptsList runtime_opts = {
};
static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
int evpd, int pc, Error **errp)
int evpd, int pc, void **inq, Error **errp)
{
int full_size;
struct scsi_task *task = NULL;
@ -1079,14 +1087,19 @@ static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
}
}
*inq = scsi_datain_unmarshall(task);
if (*inq == NULL) {
error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
goto fail;
}
return task;
fail:
error_setg(errp, "iSCSI: Inquiry command failed : %s",
iscsi_get_error(iscsi));
if (task) {
if (task != NULL) {
scsi_free_scsi_task(task);
return NULL;
}
return NULL;
}
@ -1107,11 +1120,12 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
struct iscsi_url *iscsi_url = NULL;
struct scsi_task *task = NULL;
struct scsi_inquiry_standard *inq = NULL;
struct scsi_inquiry_supported_pages *inq_vpd;
char *initiator_name = NULL;
QemuOpts *opts;
Error *local_err = NULL;
const char *filename;
int ret;
int i, ret;
if ((BDRV_SECTOR_SIZE % 512) != 0) {
error_setg(errp, "iSCSI: Invalid BDRV_SECTOR_SIZE. "
@ -1197,25 +1211,18 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
iscsilun->iscsi = iscsi;
iscsilun->lun = iscsi_url->lun;
task = iscsi_inquiry_sync(iscsi, iscsilun->lun, 0, 0, 36);
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
error_setg(errp, "iSCSI: failed to send inquiry command.");
ret = -EINVAL;
goto out;
}
inq = scsi_datain_unmarshall(task);
if (inq == NULL) {
error_setg(errp, "iSCSI: Failed to unmarshall inquiry data.");
ret = -EINVAL;
goto out;
}
iscsilun->type = inq->periperal_device_type;
iscsilun->has_write_same = true;
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 0, 0,
(void **) &inq, errp);
if (task == NULL) {
ret = -EINVAL;
goto out;
}
iscsilun->type = inq->periperal_device_type;
scsi_free_scsi_task(task);
task = NULL;
iscsi_readcapacity_sync(iscsilun, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
@ -1233,46 +1240,48 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
bs->sg = 1;
}
if (iscsilun->lbpme) {
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES,
(void **) &inq_vpd, errp);
if (task == NULL) {
ret = -EINVAL;
goto out;
}
for (i = 0; i < inq_vpd->num_pages; i++) {
struct scsi_task *inq_task;
struct scsi_inquiry_logical_block_provisioning *inq_lbp;
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING,
errp);
if (task == NULL) {
ret = -EINVAL;
goto out;
}
inq_lbp = scsi_datain_unmarshall(task);
if (inq_lbp == NULL) {
error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
ret = -EINVAL;
goto out;
}
memcpy(&iscsilun->lbp, inq_lbp,
sizeof(struct scsi_inquiry_logical_block_provisioning));
scsi_free_scsi_task(task);
task = NULL;
}
if (iscsilun->lbp.lbpu || iscsilun->lbp.lbpws) {
struct scsi_inquiry_block_limits *inq_bl;
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, errp);
if (task == NULL) {
ret = -EINVAL;
goto out;
switch (inq_vpd->pages[i]) {
case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING:
inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING,
(void **) &inq_lbp, errp);
if (inq_task == NULL) {
ret = -EINVAL;
goto out;
}
memcpy(&iscsilun->lbp, inq_lbp,
sizeof(struct scsi_inquiry_logical_block_provisioning));
scsi_free_scsi_task(inq_task);
break;
case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS:
inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS,
(void **) &inq_bl, errp);
if (inq_task == NULL) {
ret = -EINVAL;
goto out;
}
memcpy(&iscsilun->bl, inq_bl,
sizeof(struct scsi_inquiry_block_limits));
scsi_free_scsi_task(inq_task);
break;
default:
break;
}
inq_bl = scsi_datain_unmarshall(task);
if (inq_bl == NULL) {
error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
ret = -EINVAL;
goto out;
}
memcpy(&iscsilun->bl, inq_bl,
sizeof(struct scsi_inquiry_block_limits));
scsi_free_scsi_task(task);
task = NULL;
}
scsi_free_scsi_task(task);
task = NULL;
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
/* Set up a timer for sending out iSCSI NOPs */

View file

@ -909,7 +909,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
case VERIFY_16:
if ((buf[1] & 2) == 0) {
cmd->xfer = 0;
} else if ((buf[1] & 4) == 1) {
} else if ((buf[1] & 4) != 0) {
cmd->xfer = 1;
}
cmd->xfer *= dev->blocksize;
@ -1367,6 +1367,11 @@ const struct SCSISense sense_code_WRITE_PROTECTED = {
.key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
};
/* Data Protection, Space Allocation Failed Write Protect */
const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
.key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
};
/*
* scsi_build_sense
*

View file

@ -75,6 +75,8 @@ struct SCSIDiskState
bool media_event;
bool eject_request;
uint64_t wwn;
uint64_t port_wwn;
uint16_t port_index;
uint64_t max_unmap_size;
QEMUBH *bh;
char *version;
@ -428,6 +430,9 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
case EINVAL:
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
break;
case ENOSPC:
scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED));
break;
default:
scsi_check_condition(r, SENSE_CODE(IO_ERROR));
break;
@ -617,6 +622,24 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
stq_be_p(&outbuf[buflen], s->wwn);
buflen += 8;
}
if (s->port_wwn) {
outbuf[buflen++] = 0x61; // SAS / Binary
outbuf[buflen++] = 0x93; // PIV / Target port / NAA
outbuf[buflen++] = 0; // reserved
outbuf[buflen++] = 8;
stq_be_p(&outbuf[buflen], s->port_wwn);
buflen += 8;
}
if (s->port_index) {
outbuf[buflen++] = 0x61; // SAS / Binary
outbuf[buflen++] = 0x94; // PIV / Target port / relative target port
outbuf[buflen++] = 0; // reserved
outbuf[buflen++] = 4;
stw_be_p(&outbuf[buflen + 2], s->port_index);
buflen += 4;
}
break;
}
case 0xb0: /* block limits */
@ -2536,6 +2559,8 @@ static Property scsi_hd_properties[] = {
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
SCSI_DISK_F_DPOFUA, false),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
DEFAULT_MAX_UNMAP_SIZE),
DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf),
@ -2584,6 +2609,8 @@ static const TypeInfo scsi_hd_info = {
static Property scsi_cd_properties[] = {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_END_OF_LIST(),
};
@ -2647,6 +2674,8 @@ static Property scsi_disk_properties[] = {
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
SCSI_DISK_F_DPOFUA, false),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
DEFAULT_MAX_UNMAP_SIZE),
DEFINE_PROP_END_OF_LIST(),

View file

@ -37,8 +37,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
#include <scsi/sg.h>
#include "block/scsi.h"
#define SCSI_SENSE_BUF_SIZE 96
#define SG_ERR_DRIVER_TIMEOUT 0x06
#define SG_ERR_DRIVER_SENSE 0x08

View file

@ -60,7 +60,6 @@
#define VSCSI_MAX_SECTORS 4096
#define VSCSI_REQ_LIMIT 24
#define SCSI_SENSE_BUF_SIZE 96
#define SRP_RSP_SENSE_DATA_LEN 18
typedef union vscsi_crq {

View file

@ -31,7 +31,7 @@ typedef struct SCSISense {
uint8_t ascq;
} SCSISense;
#define SCSI_SENSE_BUF_SIZE 96
#define SCSI_SENSE_BUF_SIZE 252
struct SCSICommand {
uint8_t buf[SCSI_CMD_BUF_SIZE];
@ -223,6 +223,8 @@ extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
/* Data Protection, Write Protected */
extern const struct SCSISense sense_code_WRITE_PROTECTED;
/* Data Protection, Space Allocation Failed Write Protect */
extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
#define SENSE_CODE(x) sense_code_ ## x