[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 10/10] scsi: move host_status handling into SCSI drivers
From: |
Paolo Bonzini |
Subject: |
[PATCH 10/10] scsi: move host_status handling into SCSI drivers |
Date: |
Wed, 24 Feb 2021 19:24:53 +0100 |
From: Hannes Reinecke <hare@suse.de>
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>
---
hw/scsi/scsi-bus.c | 23 +++++++++++++++++++-
hw/scsi/scsi-disk.c | 7 ++----
hw/scsi/scsi-generic.c | 6 ++----
hw/scsi/virtio-scsi.c | 46 ++++++++++++++++++++++++++++++++++++++++
hw/scsi/vmw_pvscsi.c | 39 ++++++++++++++++++++++++++++++++++
include/hw/scsi/scsi.h | 4 +++-
include/scsi/constants.h | 3 +++
7 files changed, 117 insertions(+), 11 deletions(-)
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index dc4141ec8d..6088601925 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -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,6 +1456,17 @@ void scsi_req_print(SCSIRequest *req)
}
}
+static void scsi_req_complete_failed(SCSIRequest *req)
+{
+ SCSISense sense;
+
+ req->status = scsi_sense_from_host_status(req->host_status, &sense);
+ if (req->status == CHECK_CONDITION) {
+ scsi_req_build_sense(req, sense);
+ }
+ req->bus->info->complete(req, 0);
+}
+
void scsi_req_complete(SCSIRequest *req, int status)
{
assert(req->status == -1);
@@ -1483,7 +1495,16 @@ void scsi_req_complete(SCSIRequest *req, int status)
scsi_req_ref(req);
scsi_req_dequeue(req);
- req->bus->info->complete(req, req->resid);
+ if (status == CHECK_HOST_STATUS) {
+ if (req->bus->info->fail) {
+ req->bus->info->fail(req);
+ } else {
+ scsi_req_complete_failed(req);
+ }
+ } else {
+ req->host_status = SCSI_HOST_OK;
+ req->bus->info->complete(req, req->resid);
+ }
/* Cancelled requests might end up being completed instead of cancelled */
notifier_list_notify(&req->cancel_notifiers, req);
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index ceaf78b423..b7e53b1b6f 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -2704,14 +2704,11 @@ 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);
- }
+ ret = CHECK_HOST_STATUS;
+ r->req.host_status = io_hdr->host_status;
} else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
ret = BUSY;
} else {
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index 716caf0d22..8e26fccf74 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -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);
- }
+ r->req.host_status = io_hdr->host_status;
+ status = CHECK_HOST_STATUS;
} else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
status = BUSY;
} else {
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 358c0e70b0..6d80730287 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -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,
diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
index 0da378ed50..1f30cb020a 100644
--- a/hw/scsi/vmw_pvscsi.c
+++ b/hw/scsi/vmw_pvscsi.c
@@ -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
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
index 5d992e6e1d..ee7876674c 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -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);
diff --git a/include/scsi/constants.h b/include/scsi/constants.h
index 2a32c08b5e..0ee29bfd7d 100644
--- a/include/scsi/constants.h
+++ b/include/scsi/constants.h
@@ -181,6 +181,9 @@
#define STATUS_MASK 0x3e
+/* QEMU only. */
+#define CHECK_HOST_STATUS 0xff
+
/*
* SENSE KEYS
*/
--
2.29.2
- [PATCH 00/11] scsi-generic: error handling overhaul, Paolo Bonzini, 2021/02/24
- [PATCH 02/10] scsi-disk: do not complete requests early for rerror/werror=ignore, Paolo Bonzini, 2021/02/24
- [PATCH 04/10] scsi-disk: pass SCSI status to scsi_handle_rw_error, Paolo Bonzini, 2021/02/24
- [PATCH 03/10] scsi: introduce scsi_sense_from_errno(), Paolo Bonzini, 2021/02/24
- [PATCH 05/10] scsi-disk: pass guest recoverable errors through even for rerror=stop, Paolo Bonzini, 2021/02/24
- [PATCH 07/10] scsi: Rename linux-specific SG_ERR codes to generic SCSI_HOST error codes, Paolo Bonzini, 2021/02/24
- [PATCH 09/10] scsi: inline sg_io_sense_from_errno() into the callers., Paolo Bonzini, 2021/02/24
- [PATCH 10/10] scsi: move host_status handling into SCSI drivers,
Paolo Bonzini <=
- [PATCH 06/10] scsi: drop 'result' argument from command_complete callback, Paolo Bonzini, 2021/02/24
- [PATCH 01/10] scsi-disk: move scsi_handle_rw_error earlier, Paolo Bonzini, 2021/02/24
- [PATCH 08/10] scsi: Add mapping for generic SCSI_HOST status to sense codes, Paolo Bonzini, 2021/02/24
- Re: [PATCH 00/11] scsi-generic: error handling overhaul, Philippe Mathieu-Daudé, 2021/02/24