scsi: introduce sg_io_sense_from_errno

Move more knowledge of SG_IO out of hw/scsi/scsi-generic.c, for
reusability.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2017-08-22 09:43:14 +02:00
parent a3760467c6
commit 1ead6b4e24
3 changed files with 46 additions and 34 deletions

View File

@ -81,6 +81,7 @@ static void scsi_free_request(SCSIRequest *req)
static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
{ {
int status; int status;
SCSISense sense;
assert(r->req.aiocb == NULL); assert(r->req.aiocb == NULL);
@ -88,42 +89,15 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
scsi_req_cancel_complete(&r->req); scsi_req_cancel_complete(&r->req);
goto done; goto done;
} }
status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
if (status == CHECK_CONDITION) {
if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
r->req.sense_len = r->io_header.sb_len_wr; r->req.sense_len = r->io_header.sb_len_wr;
} else {
scsi_req_build_sense(&r->req, sense);
}
} }
if (ret != 0) {
switch (ret) {
case -EDOM:
status = TASK_SET_FULL;
break;
case -ENOMEM:
status = CHECK_CONDITION;
scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
break;
default:
status = CHECK_CONDITION;
scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
break;
}
} else {
if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
(r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
status = BUSY;
BADF("Driver Timeout\n");
} else if (r->io_header.host_status) {
status = CHECK_CONDITION;
scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
} else if (r->io_header.status) {
status = r->io_header.status;
} else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
status = CHECK_CONDITION;
} else {
status = GOOD;
}
}
DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
r, r->req.tag, status); r, r->req.tag, status);

View File

@ -116,6 +116,9 @@ int scsi_cdb_length(uint8_t *buf);
#define SG_ERR_DID_TIME_OUT 0x03 #define SG_ERR_DID_TIME_OUT 0x03
#define SG_ERR_DRIVER_SENSE 0x08 #define SG_ERR_DRIVER_SENSE 0x08
int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
SCSISense *sense);
#endif #endif
#endif #endif

View File

@ -501,3 +501,38 @@ const char *scsi_command_name(uint8_t cmd)
} }
return names[cmd]; return names[cmd];
} }
#ifdef CONFIG_LINUX
int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
SCSISense *sense)
{
if (errno_value != 0) {
switch (errno_value) {
case EDOM:
return TASK_SET_FULL;
case ENOMEM:
*sense = SENSE_CODE(TARGET_FAILURE);
return CHECK_CONDITION;
default:
*sense = SENSE_CODE(IO_ERROR);
return CHECK_CONDITION;
}
} else {
if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT ||
io_hdr->host_status == SG_ERR_DID_BUS_BUSY ||
io_hdr->host_status == SG_ERR_DID_TIME_OUT ||
(io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) {
return BUSY;
} else if (io_hdr->host_status) {
*sense = SENSE_CODE(I_T_NEXUS_LOSS);
return CHECK_CONDITION;
} else if (io_hdr->status) {
return io_hdr->status;
} else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) {
return CHECK_CONDITION;
} else {
return GOOD;
}
}
}
#endif