From 8c6d7671937fa581e2c7d1723a0b0e4631706dea Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 15 Apr 2015 17:27:13 +0200 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(). Signed-off-by: Bart Van Assche --- scst/src/dev_handlers/scst_disk.c | 4 +++- scst/src/scst_lib.c | 12 +++++++++--- scst/src/scst_targ.c | 2 ++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/scst/src/dev_handlers/scst_disk.c b/scst/src/dev_handlers/scst_disk.c index 3b85ae15b..7f7f05319 100644 --- a/scst/src/dev_handlers/scst_disk.c +++ b/scst/src/dev_handlers/scst_disk.c @@ -355,7 +355,9 @@ 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); - if (result == SAM_STAT_GOOD) + WARN_ON_ONCE(IS_ERR_VALUE(result)); + + if (status_byte(result) == GOOD) goto out_complete; work->result = result; diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index dcbed6278..b4f648568 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -6740,8 +6740,10 @@ out: static void scsi_end_async(struct request *req, int error) { struct scsi_io_context *sioc = req->end_io_data; + int errors; - TRACE_DBG("sioc %p, cmd %p", sioc, sioc->data); + TRACE_DBG("sioc %p, cmd %p, error %d / %d", sioc, sioc->data, error, + req->errors); #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) lockdep_assert_held(req->q->queue_lock); @@ -6750,11 +6752,15 @@ static void scsi_end_async(struct request *req, int error) lockdep_assert_held(req->q->queue_lock); #endif + errors = req->errors && !IS_ERR_VALUE(req->errors) ? req->errors : + IS_ERR_VALUE(req->errors) || error ? + SAM_STAT_CHECK_CONDITION : 0; + if (sioc->done) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30) - sioc->done(sioc->data, sioc->sense, req->errors, req->data_len); + sioc->done(sioc->data, sioc->sense, errors, req->data_len); #else - sioc->done(sioc->data, sioc->sense, req->errors, req->resid_len); + sioc->done(sioc->data, sioc->sense, errors, req->resid_len); #endif kmem_cache_free(scsi_io_context_cache, sioc); diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index bed46ed5d..79247a4e5 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -1724,6 +1724,8 @@ static void scst_do_cmd_done(struct scst_cmd *cmd, int result, scst_set_exec_time(cmd); + WARN_ON_ONCE(IS_ERR_VALUE(result)); + cmd->status = result & 0xff; cmd->msg_status = msg_byte(result); cmd->host_status = host_byte(result);