scsi: move host_status handling into SCSI drivers
Some SCSI drivers like virtio have an internal mapping for the host_status. This patch moves the host_status translation into the SCSI drivers to allow those drivers to set up the correct values. Signed-off-by: Hannes Reinecke <hare@suse.de>. [Added default handling to avoid touching all drivers. - Paolo] Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
a108557bbf
commit
f3126d65b3
@ -692,6 +692,7 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
|
|||||||
req->lun = lun;
|
req->lun = lun;
|
||||||
req->hba_private = hba_private;
|
req->hba_private = hba_private;
|
||||||
req->status = -1;
|
req->status = -1;
|
||||||
|
req->host_status = -1;
|
||||||
req->ops = reqops;
|
req->ops = reqops;
|
||||||
object_ref(OBJECT(d));
|
object_ref(OBJECT(d));
|
||||||
object_ref(OBJECT(qbus->parent));
|
object_ref(OBJECT(qbus->parent));
|
||||||
@ -1455,10 +1456,38 @@ void scsi_req_print(SCSIRequest *req)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void scsi_req_complete_failed(SCSIRequest *req, int host_status)
|
||||||
|
{
|
||||||
|
SCSISense sense;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
assert(req->status == -1 && req->host_status == -1);
|
||||||
|
assert(req->ops != &reqops_unit_attention);
|
||||||
|
|
||||||
|
if (!req->bus->info->fail) {
|
||||||
|
status = scsi_sense_from_host_status(req->host_status, &sense);
|
||||||
|
if (status == CHECK_CONDITION) {
|
||||||
|
scsi_req_build_sense(req, sense);
|
||||||
|
}
|
||||||
|
scsi_req_complete(req, status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
req->host_status = host_status;
|
||||||
|
scsi_req_ref(req);
|
||||||
|
scsi_req_dequeue(req);
|
||||||
|
req->bus->info->fail(req);
|
||||||
|
|
||||||
|
/* Cancelled requests might end up being completed instead of cancelled */
|
||||||
|
notifier_list_notify(&req->cancel_notifiers, req);
|
||||||
|
scsi_req_unref(req);
|
||||||
|
}
|
||||||
|
|
||||||
void scsi_req_complete(SCSIRequest *req, int status)
|
void scsi_req_complete(SCSIRequest *req, int status)
|
||||||
{
|
{
|
||||||
assert(req->status == -1);
|
assert(req->status == -1 && req->host_status == -1);
|
||||||
req->status = status;
|
req->status = status;
|
||||||
|
req->host_status = SCSI_HOST_OK;
|
||||||
|
|
||||||
assert(req->sense_len <= sizeof(req->sense));
|
assert(req->sense_len <= sizeof(req->sense));
|
||||||
if (status == GOOD) {
|
if (status == GOOD) {
|
||||||
@ -1646,7 +1675,7 @@ static int put_scsi_requests(QEMUFile *f, void *pv, size_t size,
|
|||||||
|
|
||||||
QTAILQ_FOREACH(req, &s->requests, next) {
|
QTAILQ_FOREACH(req, &s->requests, next) {
|
||||||
assert(!req->io_canceled);
|
assert(!req->io_canceled);
|
||||||
assert(req->status == -1);
|
assert(req->status == -1 && req->host_status == -1);
|
||||||
assert(req->enqueued);
|
assert(req->enqueued);
|
||||||
|
|
||||||
qemu_put_sbyte(f, req->retry ? 1 : 2);
|
qemu_put_sbyte(f, req->retry ? 1 : 2);
|
||||||
|
@ -2704,15 +2704,15 @@ static void scsi_block_sgio_complete(void *opaque, int ret)
|
|||||||
SCSIDiskReq *r = &req->req;
|
SCSIDiskReq *r = &req->req;
|
||||||
SCSIDevice *s = r->req.dev;
|
SCSIDevice *s = r->req.dev;
|
||||||
sg_io_hdr_t *io_hdr = &req->io_header;
|
sg_io_hdr_t *io_hdr = &req->io_header;
|
||||||
SCSISense sense;
|
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
if (io_hdr->host_status != SCSI_HOST_OK) {
|
if (io_hdr->host_status != SCSI_HOST_OK) {
|
||||||
ret = scsi_sense_from_host_status(io_hdr->host_status, &sense);
|
scsi_req_complete_failed(&r->req, io_hdr->host_status);
|
||||||
if (ret == CHECK_CONDITION) {
|
scsi_req_unref(&r->req);
|
||||||
scsi_req_build_sense(&r->req, sense);
|
return;
|
||||||
}
|
}
|
||||||
} else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
|
||||||
|
if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
||||||
ret = BUSY;
|
ret = BUSY;
|
||||||
} else {
|
} else {
|
||||||
ret = io_hdr->status;
|
ret = io_hdr->status;
|
||||||
|
@ -89,10 +89,8 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
|
|||||||
scsi_req_build_sense(&r->req, sense);
|
scsi_req_build_sense(&r->req, sense);
|
||||||
}
|
}
|
||||||
} else if (io_hdr->host_status != SCSI_HOST_OK) {
|
} else if (io_hdr->host_status != SCSI_HOST_OK) {
|
||||||
status = scsi_sense_from_host_status(io_hdr->host_status, &sense);
|
scsi_req_complete_failed(&r->req, io_hdr->host_status);
|
||||||
if (status == CHECK_CONDITION) {
|
goto done;
|
||||||
scsi_req_build_sense(&r->req, sense);
|
|
||||||
}
|
|
||||||
} else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
} else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
||||||
status = BUSY;
|
status = BUSY;
|
||||||
} else {
|
} else {
|
||||||
|
@ -500,6 +500,51 @@ static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req)
|
|||||||
virtio_scsi_complete_req(req);
|
virtio_scsi_complete_req(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void virtio_scsi_command_failed(SCSIRequest *r)
|
||||||
|
{
|
||||||
|
VirtIOSCSIReq *req = r->hba_private;
|
||||||
|
|
||||||
|
if (r->io_canceled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
req->resp.cmd.status = GOOD;
|
||||||
|
switch (r->host_status) {
|
||||||
|
case SCSI_HOST_NO_LUN:
|
||||||
|
req->resp.cmd.response = VIRTIO_SCSI_S_INCORRECT_LUN;
|
||||||
|
break;
|
||||||
|
case SCSI_HOST_BUSY:
|
||||||
|
req->resp.cmd.response = VIRTIO_SCSI_S_BUSY;
|
||||||
|
break;
|
||||||
|
case SCSI_HOST_TIME_OUT:
|
||||||
|
case SCSI_HOST_ABORTED:
|
||||||
|
req->resp.cmd.response = VIRTIO_SCSI_S_ABORTED;
|
||||||
|
break;
|
||||||
|
case SCSI_HOST_BAD_RESPONSE:
|
||||||
|
req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
|
||||||
|
break;
|
||||||
|
case SCSI_HOST_RESET:
|
||||||
|
req->resp.cmd.response = VIRTIO_SCSI_S_RESET;
|
||||||
|
break;
|
||||||
|
case SCSI_HOST_TRANSPORT_DISRUPTED:
|
||||||
|
req->resp.cmd.response = VIRTIO_SCSI_S_TRANSPORT_FAILURE;
|
||||||
|
break;
|
||||||
|
case SCSI_HOST_TARGET_FAILURE:
|
||||||
|
req->resp.cmd.response = VIRTIO_SCSI_S_TARGET_FAILURE;
|
||||||
|
break;
|
||||||
|
case SCSI_HOST_RESERVATION_ERROR:
|
||||||
|
req->resp.cmd.response = VIRTIO_SCSI_S_NEXUS_FAILURE;
|
||||||
|
break;
|
||||||
|
case SCSI_HOST_ALLOCATION_FAILURE:
|
||||||
|
case SCSI_HOST_MEDIUM_ERROR:
|
||||||
|
case SCSI_HOST_ERROR:
|
||||||
|
default:
|
||||||
|
req->resp.cmd.response = VIRTIO_SCSI_S_FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
virtio_scsi_complete_cmd_req(req);
|
||||||
|
}
|
||||||
|
|
||||||
static void virtio_scsi_command_complete(SCSIRequest *r, size_t resid)
|
static void virtio_scsi_command_complete(SCSIRequest *r, size_t resid)
|
||||||
{
|
{
|
||||||
VirtIOSCSIReq *req = r->hba_private;
|
VirtIOSCSIReq *req = r->hba_private;
|
||||||
@ -908,6 +953,7 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
|
|||||||
.max_lun = VIRTIO_SCSI_MAX_LUN,
|
.max_lun = VIRTIO_SCSI_MAX_LUN,
|
||||||
|
|
||||||
.complete = virtio_scsi_command_complete,
|
.complete = virtio_scsi_command_complete,
|
||||||
|
.fail = virtio_scsi_command_failed,
|
||||||
.cancel = virtio_scsi_request_cancelled,
|
.cancel = virtio_scsi_request_cancelled,
|
||||||
.change = virtio_scsi_change,
|
.change = virtio_scsi_change,
|
||||||
.parse_cdb = virtio_scsi_parse_cdb,
|
.parse_cdb = virtio_scsi_parse_cdb,
|
||||||
|
@ -510,6 +510,44 @@ pvscsi_write_sense(PVSCSIRequest *r, uint8_t *sense, int len)
|
|||||||
cpu_physical_memory_write(r->req.senseAddr, sense, r->cmp.senseLen);
|
cpu_physical_memory_write(r->req.senseAddr, sense, r->cmp.senseLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pvscsi_command_failed(SCSIRequest *req)
|
||||||
|
{
|
||||||
|
PVSCSIRequest *pvscsi_req = req->hba_private;
|
||||||
|
PVSCSIState *s;
|
||||||
|
|
||||||
|
if (!pvscsi_req) {
|
||||||
|
trace_pvscsi_command_complete_not_found(req->tag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s = pvscsi_req->dev;
|
||||||
|
|
||||||
|
switch (req->host_status) {
|
||||||
|
case SCSI_HOST_NO_LUN:
|
||||||
|
pvscsi_req->cmp.hostStatus = BTSTAT_LUNMISMATCH;
|
||||||
|
break;
|
||||||
|
case SCSI_HOST_BUSY:
|
||||||
|
pvscsi_req->cmp.hostStatus = BTSTAT_ABORTQUEUE;
|
||||||
|
break;
|
||||||
|
case SCSI_HOST_TIME_OUT:
|
||||||
|
case SCSI_HOST_ABORTED:
|
||||||
|
pvscsi_req->cmp.hostStatus = BTSTAT_SENTRST;
|
||||||
|
break;
|
||||||
|
case SCSI_HOST_BAD_RESPONSE:
|
||||||
|
pvscsi_req->cmp.hostStatus = BTSTAT_SELTIMEO;
|
||||||
|
break;
|
||||||
|
case SCSI_HOST_RESET:
|
||||||
|
pvscsi_req->cmp.hostStatus = BTSTAT_BUSRESET;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pvscsi_req->cmp.hostStatus = BTSTAT_HASOFTWARE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pvscsi_req->cmp.scsiStatus = GOOD;
|
||||||
|
qemu_sglist_destroy(&pvscsi_req->sgl);
|
||||||
|
pvscsi_complete_request(s, pvscsi_req);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pvscsi_command_complete(SCSIRequest *req, size_t resid)
|
pvscsi_command_complete(SCSIRequest *req, size_t resid)
|
||||||
{
|
{
|
||||||
@ -1103,6 +1141,7 @@ static const struct SCSIBusInfo pvscsi_scsi_info = {
|
|||||||
.get_sg_list = pvscsi_get_sg_list,
|
.get_sg_list = pvscsi_get_sg_list,
|
||||||
.complete = pvscsi_command_complete,
|
.complete = pvscsi_command_complete,
|
||||||
.cancel = pvscsi_request_cancelled,
|
.cancel = pvscsi_request_cancelled,
|
||||||
|
.fail = pvscsi_command_failed,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -27,7 +27,8 @@ struct SCSIRequest {
|
|||||||
uint32_t refcount;
|
uint32_t refcount;
|
||||||
uint32_t tag;
|
uint32_t tag;
|
||||||
uint32_t lun;
|
uint32_t lun;
|
||||||
uint32_t status;
|
int16_t status;
|
||||||
|
int16_t host_status;
|
||||||
void *hba_private;
|
void *hba_private;
|
||||||
size_t resid;
|
size_t resid;
|
||||||
SCSICommand cmd;
|
SCSICommand cmd;
|
||||||
@ -123,6 +124,7 @@ struct SCSIBusInfo {
|
|||||||
int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
|
int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
|
||||||
void *hba_private);
|
void *hba_private);
|
||||||
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
|
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
|
||||||
|
void (*fail)(SCSIRequest *req);
|
||||||
void (*complete)(SCSIRequest *req, size_t resid);
|
void (*complete)(SCSIRequest *req, size_t resid);
|
||||||
void (*cancel)(SCSIRequest *req);
|
void (*cancel)(SCSIRequest *req);
|
||||||
void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense);
|
void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense);
|
||||||
@ -177,6 +179,7 @@ void scsi_req_print(SCSIRequest *req);
|
|||||||
void scsi_req_continue(SCSIRequest *req);
|
void scsi_req_continue(SCSIRequest *req);
|
||||||
void scsi_req_data(SCSIRequest *req, int len);
|
void scsi_req_data(SCSIRequest *req, int len);
|
||||||
void scsi_req_complete(SCSIRequest *req, int status);
|
void scsi_req_complete(SCSIRequest *req, int status);
|
||||||
|
void scsi_req_complete_failed(SCSIRequest *req, int host_status);
|
||||||
uint8_t *scsi_req_get_buf(SCSIRequest *req);
|
uint8_t *scsi_req_get_buf(SCSIRequest *req);
|
||||||
int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
|
int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
|
||||||
void scsi_req_cancel_complete(SCSIRequest *req);
|
void scsi_req_cancel_complete(SCSIRequest *req);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user