From 656931dfcea0abb61fa8179eefabaadf5f3bff0d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sat, 5 Jan 2019 21:55:26 +0000 Subject: [PATCH] scst_lib: Fix SCSI pass-through error handling Some but not all SCSI LLD drivers set req->errors. Some SCSI LLD drivers set req->errors to a negative Unix error code and others assign the result of make_status_bytes() to req->errors. The SCSI core finishes failed pass-through requests by calling blk_finish_request(). That function calls req->end_io() without setting req->errors. Hence check both the error argument and req->errors before calling sioc->done(). git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7861 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/src/dev_handlers/scst_disk.c | 6 ++++-- scst/src/scst_lib.c | 9 ++++++++- scst/src/scst_targ.c | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/scst/src/dev_handlers/scst_disk.c b/scst/src/dev_handlers/scst_disk.c index 222630ca8..01120b90b 100644 --- a/scst/src/dev_handlers/scst_disk.c +++ b/scst/src/dev_handlers/scst_disk.c @@ -377,11 +377,13 @@ static void disk_cmd_done(void *data, char *sense, int result, int resid) TRACE_DBG("work %p, cmd %p, left %d, result %d, sense %p, resid %d", work, work->cmd, work->left, result, sense, resid); - work->result = result; + WARN_ON_ONCE(IS_ERR_VALUE((long)result)); - if (result == SAM_STAT_GOOD) + if (status_byte(result) == GOOD) goto out_complete; + work->result = result; + disk_restore_sg(work); scst_pass_through_cmd_done(work->cmd, sense, result, resid + work->left); diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 58974cfcd..4210ac811 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -8411,13 +8411,20 @@ static void scsi_end_async(struct request *req, blk_status_t error) #endif if (sioc->done) { - int result, resid_len; + int resid_len; + long result; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) result = scsi_req(req)->result; #else result = req->errors; #endif + TRACE_DBG("error %d / %ld", error, result); + + result = result && !IS_ERR_VALUE(result) ? result : + IS_ERR_VALUE(result) || error ? + SAM_STAT_CHECK_CONDITION : 0; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) resid_len = scsi_req(req)->resid_len; #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 6d48f1163..31d73c41e 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -2132,6 +2132,8 @@ static void scst_do_cmd_done(struct scst_cmd *cmd, int result, { TRACE_ENTRY(); + WARN_ON_ONCE(IS_ERR_VALUE((long)result)); + cmd->status = result & 0xff; cmd->msg_status = msg_byte(result); cmd->host_status = host_byte(result);