Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:15-SP2
qemu
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
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 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: Bruce Rogers <brogers@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 32875bedaedf25e7b0cea8363887..b3ea492beedc2a075157957e0595 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: @@ -235,6 +236,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 13babd26dff43d5052886cf955a5..bce865c2222b0ece52d16ab1d90a 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -330,7 +330,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 de25a1c21d84f38eca9aaf1114d4..3155658db33f95a572a4c7ff495e 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -496,9 +496,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 38c273de19573ad8421da6439153..3c474bdd5688fe9d6e2b64e53637 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 c50e81fdb87f535e6f49dd31699e..c09f4aff21e34860c1b41612cd0d 100644 --- a/scsi/utils.c +++ b/scsi/utils.c @@ -565,7 +565,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) { @@ -580,21 +580,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