scsi: inline sg_io_sense_from_errno() into the callers.
Currently sg_io_sense_from_errno() converts the two input parameters 'errno' and 'io_hdr' into sense code and SCSI status. Having split the function off into scsi_sense_from_errno() and scsi_sense_from_host_status(), both of which are available generically, we now inline the logic in the callers so that scsi-disk and scsi-generic will be able to pass host_status to the HBA. Signed-off-by: Hannes Reinecke <hare@suse.de> Message-Id: <20201116184041.60465-7-hare@suse.de> [Put together from "scsi-disk: Add sg_io callback to evaluate status" and what remains of "scsi: split sg_io_sense_from_errno() in two functions", with many other fixes. - Paolo] Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
9738c65720
commit
a108557bbf
@ -77,7 +77,6 @@ typedef struct SCSIDiskReq {
|
|||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
QEMUIOVector qiov;
|
QEMUIOVector qiov;
|
||||||
BlockAcctCookie acct;
|
BlockAcctCookie acct;
|
||||||
unsigned char *status;
|
|
||||||
} SCSIDiskReq;
|
} SCSIDiskReq;
|
||||||
|
|
||||||
#define SCSI_DISK_F_REMOVABLE 0
|
#define SCSI_DISK_F_REMOVABLE 0
|
||||||
@ -261,8 +260,6 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed)
|
|||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return scsi_handle_rw_error(r, ret, acct_failed);
|
return scsi_handle_rw_error(r, ret, acct_failed);
|
||||||
} else if (r->status && *r->status) {
|
|
||||||
return scsi_handle_rw_error(r, *r->status, acct_failed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -2697,8 +2694,47 @@ typedef struct SCSIBlockReq {
|
|||||||
|
|
||||||
/* CDB passed to SG_IO. */
|
/* CDB passed to SG_IO. */
|
||||||
uint8_t cdb[16];
|
uint8_t cdb[16];
|
||||||
|
BlockCompletionFunc *cb;
|
||||||
|
void *cb_opaque;
|
||||||
} SCSIBlockReq;
|
} SCSIBlockReq;
|
||||||
|
|
||||||
|
static void scsi_block_sgio_complete(void *opaque, int ret)
|
||||||
|
{
|
||||||
|
SCSIBlockReq *req = (SCSIBlockReq *)opaque;
|
||||||
|
SCSIDiskReq *r = &req->req;
|
||||||
|
SCSIDevice *s = r->req.dev;
|
||||||
|
sg_io_hdr_t *io_hdr = &req->io_header;
|
||||||
|
SCSISense sense;
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
if (io_hdr->host_status != SCSI_HOST_OK) {
|
||||||
|
ret = scsi_sense_from_host_status(io_hdr->host_status, &sense);
|
||||||
|
if (ret == CHECK_CONDITION) {
|
||||||
|
scsi_req_build_sense(&r->req, sense);
|
||||||
|
}
|
||||||
|
} else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
||||||
|
ret = BUSY;
|
||||||
|
} else {
|
||||||
|
ret = io_hdr->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret > 0) {
|
||||||
|
aio_context_acquire(blk_get_aio_context(s->conf.blk));
|
||||||
|
if (scsi_handle_rw_error(r, ret, true)) {
|
||||||
|
aio_context_release(blk_get_aio_context(s->conf.blk));
|
||||||
|
scsi_req_unref(&r->req);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
aio_context_release(blk_get_aio_context(s->conf.blk));
|
||||||
|
|
||||||
|
/* Ignore error. */
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req->cb(req->cb_opaque, ret);
|
||||||
|
}
|
||||||
|
|
||||||
static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
|
static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
|
||||||
int64_t offset, QEMUIOVector *iov,
|
int64_t offset, QEMUIOVector *iov,
|
||||||
int direction,
|
int direction,
|
||||||
@ -2777,9 +2813,11 @@ static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
|
|||||||
io_header->timeout = s->qdev.io_timeout * 1000;
|
io_header->timeout = s->qdev.io_timeout * 1000;
|
||||||
io_header->usr_ptr = r;
|
io_header->usr_ptr = r;
|
||||||
io_header->flags |= SG_FLAG_DIRECT_IO;
|
io_header->flags |= SG_FLAG_DIRECT_IO;
|
||||||
|
req->cb = cb;
|
||||||
|
req->cb_opaque = opaque;
|
||||||
trace_scsi_disk_aio_sgio_command(r->req.tag, req->cdb[0], lba,
|
trace_scsi_disk_aio_sgio_command(r->req.tag, req->cdb[0], lba,
|
||||||
nb_logical_blocks, io_header->timeout);
|
nb_logical_blocks, io_header->timeout);
|
||||||
aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, cb, opaque);
|
aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, scsi_block_sgio_complete, req);
|
||||||
assert(aiocb != NULL);
|
assert(aiocb != NULL);
|
||||||
return aiocb;
|
return aiocb;
|
||||||
}
|
}
|
||||||
@ -2893,7 +2931,6 @@ static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r->req.status = &r->io_header.status;
|
|
||||||
return scsi_disk_dma_command(req, buf);
|
return scsi_disk_dma_command(req, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
|
|||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
SCSISense sense;
|
SCSISense sense;
|
||||||
|
sg_io_hdr_t *io_hdr = &r->io_header;
|
||||||
|
|
||||||
assert(r->req.aiocb == NULL);
|
assert(r->req.aiocb == NULL);
|
||||||
|
|
||||||
@ -82,15 +83,24 @@ 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 (ret < 0) {
|
||||||
if (status == CHECK_CONDITION) {
|
status = scsi_sense_from_errno(-ret, &sense);
|
||||||
if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
|
if (status == CHECK_CONDITION) {
|
||||||
r->req.sense_len = r->io_header.sb_len_wr;
|
|
||||||
} else {
|
|
||||||
scsi_req_build_sense(&r->req, sense);
|
scsi_req_build_sense(&r->req, sense);
|
||||||
}
|
}
|
||||||
|
} else if (io_hdr->host_status != SCSI_HOST_OK) {
|
||||||
|
status = scsi_sense_from_host_status(io_hdr->host_status, &sense);
|
||||||
|
if (status == CHECK_CONDITION) {
|
||||||
|
scsi_req_build_sense(&r->req, sense);
|
||||||
|
}
|
||||||
|
} else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
||||||
|
status = BUSY;
|
||||||
|
} else {
|
||||||
|
status = io_hdr->status;
|
||||||
|
if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) {
|
||||||
|
r->req.sense_len = io_hdr->sb_len_wr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_scsi_generic_command_complete_noio(r, r->req.tag, status);
|
trace_scsi_generic_command_complete_noio(r, r->req.tag, status);
|
||||||
|
|
||||||
scsi_req_complete(&r->req, status);
|
scsi_req_complete(&r->req, status);
|
||||||
|
@ -139,9 +139,6 @@ int scsi_cdb_length(uint8_t *buf);
|
|||||||
#ifdef CONFIG_LINUX
|
#ifdef CONFIG_LINUX
|
||||||
#define SG_ERR_DRIVER_TIMEOUT 0x06
|
#define SG_ERR_DRIVER_TIMEOUT 0x06
|
||||||
#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
|
||||||
|
|
||||||
int scsi_sense_from_errno(int errno_value, SCSISense *sense);
|
int scsi_sense_from_errno(int errno_value, SCSISense *sense);
|
||||||
|
@ -149,19 +149,29 @@ static int do_sgio_worker(void *opaque)
|
|||||||
io_hdr.dxferp = (char *)data->buf;
|
io_hdr.dxferp = (char *)data->buf;
|
||||||
io_hdr.dxfer_len = data->sz;
|
io_hdr.dxfer_len = data->sz;
|
||||||
ret = ioctl(data->fd, SG_IO, &io_hdr);
|
ret = ioctl(data->fd, SG_IO, &io_hdr);
|
||||||
status = sg_io_sense_from_errno(ret < 0 ? errno : 0, &io_hdr,
|
|
||||||
&sense_code);
|
if (ret < 0) {
|
||||||
|
status = scsi_sense_from_errno(errno, &sense_code);
|
||||||
|
if (status == CHECK_CONDITION) {
|
||||||
|
scsi_build_sense(data->sense, sense_code);
|
||||||
|
}
|
||||||
|
} else if (io_hdr.host_status != SCSI_HOST_OK) {
|
||||||
|
status = scsi_sense_from_host_status(io_hdr.host_status, &sense_code);
|
||||||
|
if (status == CHECK_CONDITION) {
|
||||||
|
scsi_build_sense(data->sense, sense_code);
|
||||||
|
}
|
||||||
|
} else if (io_hdr.driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
||||||
|
status = BUSY;
|
||||||
|
} else {
|
||||||
|
status = io_hdr.status;
|
||||||
|
}
|
||||||
|
|
||||||
if (status == GOOD) {
|
if (status == GOOD) {
|
||||||
data->sz -= io_hdr.resid;
|
data->sz -= io_hdr.resid;
|
||||||
} else {
|
} else {
|
||||||
data->sz = 0;
|
data->sz = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == CHECK_CONDITION &&
|
|
||||||
!(io_hdr.driver_status & SG_ERR_DRIVER_SENSE)) {
|
|
||||||
scsi_build_sense(data->sense, sense_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
23
scsi/utils.c
23
scsi/utils.c
@ -658,26 +658,3 @@ int scsi_sense_from_host_status(uint8_t host_status,
|
|||||||
}
|
}
|
||||||
return GOOD;
|
return GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_LINUX
|
|
||||||
int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
|
|
||||||
SCSISense *sense)
|
|
||||||
{
|
|
||||||
if (errno_value != 0) {
|
|
||||||
return scsi_sense_from_errno(errno_value, sense);
|
|
||||||
} else {
|
|
||||||
int status = scsi_sense_from_host_status(io_hdr->host_status, sense);
|
|
||||||
if (status) {
|
|
||||||
return status;
|
|
||||||
} else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
|
||||||
return BUSY;
|
|
||||||
} 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
|
|
||||||
|
Loading…
Reference in New Issue
Block a user