Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.5:Update
qemu.35260
virtio-scsi-translate-SG_IO-host-status.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File virtio-scsi-translate-SG_IO-host-status.patch of Package qemu.35260
From: Hannes Reinecke <hare@suse.de> Date: Tue, 10 Nov 2020 10:41:55 +0100 Subject: virtio-scsi: translate SG_IO host status References: bsc#1178049,bsc#1194938 when running with an SG_IO backend we might be getting a SCSI host status back, which should be translated into a virtio scsi status to avoid having a silent data corruption if the status isn't translated properly. Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Lin Ma <lma@suse.com> --- hw/scsi/scsi-generic.c | 8 +++++--- hw/scsi/trace-events | 2 +- hw/scsi/virtio-scsi.c | 43 +++++++++++++++++++++++++++++++++++++++--- include/scsi/utils.h | 12 +++++++++--- scsi/qemu-pr-helper.c | 6 +++--- scsi/utils.c | 23 +++++++++------------- 6 files changed, 67 insertions(+), 27 deletions(-) diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 0f780b08933439575c7b8a961317..63b13e80d819c7cbf9ed44675267 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -72,7 +72,7 @@ static void scsi_free_request(SCSIRequest *req) /* Helper function for command completion. */ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) { - int status; + uint32_t status; SCSISense sense; assert(r->req.aiocb == NULL); @@ -82,7 +82,7 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) goto done; } status = sg_io_sense_from_errno(-ret, &r->io_header, &sense); - if (status == CHECK_CONDITION) { + if ((status & 0xff) == CHECK_CONDITION) { if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { r->req.sense_len = r->io_header.sb_len_wr; } else { @@ -90,7 +90,8 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) } } - trace_scsi_generic_command_complete_noio(r, r->req.tag, status); + trace_scsi_generic_command_complete_noio(r, r->req.tag, status & 0xff, + (status >> 8) & 0xff); scsi_req_complete(&r->req, status); done: @@ -238,6 +239,7 @@ static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s) * the hardware in scsi_command_complete_noio. Clean * up the io_header to avoid reporting it. */ + r->io_header.host_status = 0; r->io_header.driver_status = 0; r->io_header.status = 0; diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index 53ae160531d4d62a4d0942f4649d..92e3819b5c3ee30df7a9400d6abd 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -331,7 +331,7 @@ scsi_disk_new_request(uint32_t lun, uint32_t tag, const char *line) "Command: lu scsi_disk_aio_sgio_command(uint32_t tag, uint8_t cmd, uint64_t lba, int len, uint32_t timeout) "disk aio sgio: tag=0x%x cmd 0x%x (sector %" PRId64 ", count %d) timeout %u" # scsi-generic.c -scsi_generic_command_complete_noio(void *req, uint32_t tag, int statuc) "Command complete %p tag=0x%x status=%d" +scsi_generic_command_complete_noio(void *req, uint32_t tag, uint8_t status, uint8_t host_status) "Command complete %p tag=0x%x status=0x%x host_status=0x%x" scsi_generic_read_complete(uint32_t tag, int len) "Data ready tag=0x%x len=%d" scsi_generic_read_data(uint32_t tag, uint32_t timeout) "scsi_read_data tag=0x%x timeout %u" scsi_generic_write_complete(int ret) "scsi_write_complete() ret = %d" diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 132fc8e693b5c9ab913db6960877..b8c1fe9eef907f4b90397bf98a1a 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -503,9 +503,46 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, return; } - req->resp.cmd.response = VIRTIO_SCSI_S_OK; - req->resp.cmd.status = status; - if (req->resp.cmd.status == GOOD) { + switch ((status >> 8) & 0xff) { + case SG_ERR_DID_OK: + req->resp.cmd.response = VIRTIO_SCSI_S_OK; + break; + case SG_ERR_DID_ERROR: + req->resp.cmd.response = VIRTIO_SCSI_S_OVERRUN; + break; + case SG_ERR_DID_NO_CONNECT: + req->resp.cmd.response = VIRTIO_SCSI_S_INCORRECT_LUN; + break; + case SG_ERR_DID_ABORT: + case SG_ERR_DID_TIME_OUT: + req->resp.cmd.response = VIRTIO_SCSI_S_ABORTED; + break; + case SG_ERR_DID_BAD_TARGET: + req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; + break; + case SG_ERR_DID_RESET: + req->resp.cmd.response = VIRTIO_SCSI_S_RESET; + break; + case SG_ERR_DID_BUS_BUSY: + req->resp.cmd.response = VIRTIO_SCSI_S_BUSY; + break; + case SG_ERR_DID_TRANSPORT_DISRUPTED: + req->resp.cmd.response = VIRTIO_SCSI_S_TRANSPORT_FAILURE; + break; + case SG_ERR_DID_TARGET_FAILURE: + req->resp.cmd.response = VIRTIO_SCSI_S_TARGET_FAILURE; + break; + case SG_ERR_DID_NEXUS_FAILURE: + req->resp.cmd.response = VIRTIO_SCSI_S_NEXUS_FAILURE; + break; + default: + req->resp.cmd.response = VIRTIO_SCSI_S_FAILURE; + break; + } + + req->resp.cmd.status = (status & 0xff); + if (req->resp.cmd.status == GOOD && + req->resp.cmd.response == VIRTIO_SCSI_S_OK) { req->resp.cmd.resid = virtio_tswap32(vdev, resid); } else { req->resp.cmd.resid = 0; diff --git a/include/scsi/utils.h b/include/scsi/utils.h index fbc5588279939d70a5e31627bd2a..92f6c47944cfd1fb6284b4e2b210 100644 --- a/include/scsi/utils.h +++ b/include/scsi/utils.h @@ -126,11 +126,17 @@ int scsi_cdb_length(uint8_t *buf); #define SG_ERR_DID_NO_CONNECT 0x01 #define SG_ERR_DID_BUS_BUSY 0x02 #define SG_ERR_DID_TIME_OUT 0x03 - +#define SG_ERR_DID_BAD_TARGET 0x04 +#define SG_ERR_DID_ABORT 0x05 +#define SG_ERR_DID_ERROR 0x07 +#define SG_ERR_DID_RESET 0x08 +#define SG_ERR_DID_TRANSPORT_DISRUPTED 0x0e +#define SG_ERR_DID_TARGET_FAILURE 0x10 +#define SG_ERR_DID_NEXUS_FAILURE 0x11 #define SG_ERR_DRIVER_SENSE 0x08 -int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, - SCSISense *sense); +uint32_t sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, + SCSISense *sense); #endif #endif diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index 2733d92f2d814d42d91b25877d7d..dde9e844c30b3e3c6bce6c38338e 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -134,7 +134,7 @@ static int do_sgio_worker(void *opaque) PRHelperSGIOData *data = opaque; struct sg_io_hdr io_hdr; int ret; - int status; + uint32_t status; SCSISense sense_code; memset(data->sense, 0, PR_HELPER_SENSE_SIZE); @@ -151,13 +151,13 @@ static int do_sgio_worker(void *opaque) ret = ioctl(data->fd, SG_IO, &io_hdr); status = sg_io_sense_from_errno(ret < 0 ? errno : 0, &io_hdr, &sense_code); - if (status == GOOD) { + if ((status & 0xff) == GOOD) { data->sz -= io_hdr.resid; } else { data->sz = 0; } - if (status == CHECK_CONDITION && + if ((status & 0xff) == CHECK_CONDITION && !(io_hdr.driver_status & SG_ERR_DRIVER_SENSE)) { scsi_build_sense(data->sense, sense_code); } diff --git a/scsi/utils.c b/scsi/utils.c index b37c283014899c7b3a9ff98e04a0..81198dd7e5e99c336ed0b08f313d 100644 --- a/scsi/utils.c +++ b/scsi/utils.c @@ -561,7 +561,7 @@ const char *scsi_command_name(uint8_t cmd) } #ifdef CONFIG_LINUX -int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, +uint32_t sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, SCSISense *sense) { if (errno_value != 0) { @@ -576,21 +576,16 @@ int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, 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; + uint32_t status = GOOD; + + if (io_hdr->status) { + status = io_hdr->status; } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) { - return CHECK_CONDITION; - } else { - return GOOD; + status = CHECK_CONDITION; } + if (io_hdr->host_status) + status |= (io_hdr->host_status << 8); + return status; } } #endif
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor