File scsi-disk-fold-SG_IO-errors-back-into-re.patch of Package qemu.26277
From: Hannes Reinecke <hare@suse.de>
Date: Wed, 11 Nov 2020 17:34:45 +0100
Subject: scsi-disk: fold SG_IO errors back into request status
References: bsc#1178049,bsc#1194938
When SG_IO returns with a non-zero 'host_status' or 'status' we
should be folding these values into the request status to allow
any drivers to signal them back to the guest.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Lin Ma <lma@suse.com>
---
hw/scsi/scsi-disk.c | 37 ++++++++++++++++++++++++++++++-------
hw/scsi/trace-events | 1 +
2 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index e0996c2f5b5a9859697cf8803738..2602941196033e263afe3dacd6bf 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -77,7 +77,7 @@ typedef struct SCSIDiskReq {
struct iovec iov;
QEMUIOVector qiov;
BlockAcctCookie acct;
- unsigned char *status;
+ uint32_t status;
} SCSIDiskReq;
#define SCSI_DISK_F_REMOVABLE 0
@@ -189,7 +189,7 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed)
return true;
}
- if (ret < 0 || (r->status && *r->status)) {
+ if (ret < 0 || r->status) {
return scsi_handle_rw_error(r, -ret, acct_failed);
}
@@ -453,11 +453,12 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
* whether the error has to be handled by the guest or should rather
* pause the host.
*/
- assert(r->status && *r->status);
- if (scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) {
+ assert(r->status);
+ if ((r->status >> 8) ||
+ scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) {
/* These errors are handled by guest. */
sdc->update_sense(&r->req);
- scsi_req_complete(&r->req, *r->status);
+ scsi_req_complete(&r->req, r->status);
return true;
}
error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
@@ -2714,8 +2715,26 @@ typedef struct SCSIBlockReq {
/* CDB passed to SG_IO. */
uint8_t cdb[16];
+ BlockCompletionFunc *cb;
+ void *cb_opaque;
} SCSIBlockReq;
+static void sgio_aio_complete(void *opaque, int ret)
+{
+ SCSIBlockReq *req = (SCSIBlockReq *)opaque;
+ SCSIDiskReq *r = &req->req;
+ SCSISense sense;
+
+ trace_scsi_disk_aio_sgio_done(r->req.tag, ret, req->io_header.status,
+ req->io_header.host_status);
+ r->status = sg_io_sense_from_errno(-ret, &req->io_header, &sense);
+ if ((r->status & 0xff) == CHECK_CONDITION &&
+ req->io_header.status != CHECK_CONDITION)
+ scsi_req_build_sense(&r->req, sense);
+
+ req->cb(req->cb_opaque, ret);
+}
+
static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
int64_t offset, QEMUIOVector *iov,
int direction,
@@ -2796,9 +2815,14 @@ static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
io_header->timeout = 5000;
io_header->usr_ptr = r;
io_header->flags |= SG_FLAG_DIRECT_IO;
+
+ req->cb = cb;
+ req->cb_opaque = opaque;
+
trace_scsi_disk_aio_sgio_command(r->req.tag, req->cdb[0], lba,
nb_logical_blocks, io_header->timeout);
- aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, cb, opaque);
+ aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header,
+ sgio_aio_complete, req);
assert(aiocb != NULL);
return aiocb;
}
@@ -2912,7 +2936,6 @@ static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf)
return 0;
}
- r->req.status = &r->io_header.status;
return scsi_disk_dma_command(req, buf);
}
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
index 92e3819b5c3ee30df7a9400d6abd..0a08147c27d70637ffd9170ae903 100644
--- a/hw/scsi/trace-events
+++ b/hw/scsi/trace-events
@@ -329,6 +329,7 @@ scsi_disk_dma_command_READ(uint64_t lba, uint32_t len) "Read (sector %" PRId64 "
scsi_disk_dma_command_WRITE(const char *cmd, uint64_t lba, int len) "Write %s(sector %" PRId64 ", count %u)"
scsi_disk_new_request(uint32_t lun, uint32_t tag, const char *line) "Command: lun=%d tag=0x%x data=%s"
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_disk_aio_sgio_done(uint32_t tag, int ret, uint8_t status, uint8_t host_status) "disk aio sgio: cmd 0x%x ret %d status 0x%x host_status 0x%x"
# scsi-generic.c
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"