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->hba_private = hba_private;
|
||||
req->status = -1;
|
||||
req->host_status = -1;
|
||||
req->ops = reqops;
|
||||
object_ref(OBJECT(d));
|
||||
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)
|
||||
{
|
||||
assert(req->status == -1);
|
||||
assert(req->status == -1 && req->host_status == -1);
|
||||
req->status = status;
|
||||
req->host_status = SCSI_HOST_OK;
|
||||
|
||||
assert(req->sense_len <= sizeof(req->sense));
|
||||
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) {
|
||||
assert(!req->io_canceled);
|
||||
assert(req->status == -1);
|
||||
assert(req->status == -1 && req->host_status == -1);
|
||||
assert(req->enqueued);
|
||||
|
||||
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;
|
||||
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);
|
||||
scsi_req_complete_failed(&r->req, io_hdr->host_status);
|
||||
scsi_req_unref(&r->req);
|
||||
return;
|
||||
}
|
||||
} else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
||||
|
||||
if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
||||
ret = BUSY;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
scsi_req_complete_failed(&r->req, io_hdr->host_status);
|
||||
goto done;
|
||||
} else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
||||
status = BUSY;
|
||||
} else {
|
||||
|
@ -500,6 +500,51 @@ static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *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)
|
||||
{
|
||||
VirtIOSCSIReq *req = r->hba_private;
|
||||
@ -908,6 +953,7 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
|
||||
.max_lun = VIRTIO_SCSI_MAX_LUN,
|
||||
|
||||
.complete = virtio_scsi_command_complete,
|
||||
.fail = virtio_scsi_command_failed,
|
||||
.cancel = virtio_scsi_request_cancelled,
|
||||
.change = virtio_scsi_change,
|
||||
.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);
|
||||
}
|
||||
|
||||
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
|
||||
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,
|
||||
.complete = pvscsi_command_complete,
|
||||
.cancel = pvscsi_request_cancelled,
|
||||
.fail = pvscsi_command_failed,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -27,7 +27,8 @@ struct SCSIRequest {
|
||||
uint32_t refcount;
|
||||
uint32_t tag;
|
||||
uint32_t lun;
|
||||
uint32_t status;
|
||||
int16_t status;
|
||||
int16_t host_status;
|
||||
void *hba_private;
|
||||
size_t resid;
|
||||
SCSICommand cmd;
|
||||
@ -123,6 +124,7 @@ struct SCSIBusInfo {
|
||||
int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
|
||||
void *hba_private);
|
||||
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
|
||||
void (*fail)(SCSIRequest *req);
|
||||
void (*complete)(SCSIRequest *req, size_t resid);
|
||||
void (*cancel)(SCSIRequest *req);
|
||||
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_data(SCSIRequest *req, int len);
|
||||
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);
|
||||
int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
|
||||
void scsi_req_cancel_complete(SCSIRequest *req);
|
||||
|
Loading…
Reference in New Issue
Block a user