From: Christoph Hellwig <hch@lst.de>
To: linux-scsi@vger.kernel.org
Subject: [PATCH 7/8] scsi: split error handling slow path out of scsi_io_completion
Date: Sun, 7 Sep 2014 09:31:08 -0700 [thread overview]
Message-ID: <1410107469-896-8-git-send-email-hch@lst.de> (raw)
In-Reply-To: <1410107469-896-1-git-send-email-hch@lst.de>
Move the error handling path out of scsi_io_completion and into an
out of line helper.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/scsi/scsi_lib.c | 263 +++++++++++++++++++++++++-----------------------
1 file changed, 136 insertions(+), 127 deletions(-)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 2221bf1..cc5d404 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -742,6 +742,132 @@ static int __scsi_error_from_host_byte(struct scsi_cmnd *cmd, int result)
return error;
}
+static noinline bool
+scsi_handle_ioerror(struct scsi_cmnd *cmd, int result,
+ struct scsi_sense_hdr *sshdr)
+{
+ struct request *req = cmd->request;
+ unsigned long wait_for = (cmd->allowed + 1) * req->timeout;
+ int error = 0;
+ enum {
+ ACTION_FAIL,
+ ACTION_REPREP,
+ ACTION_RETRY,
+ ACTION_DELAYED_RETRY,
+ } action = ACTION_FAIL;
+
+ error = __scsi_error_from_host_byte(cmd, result);
+
+ if (host_byte(result) == DID_RESET) {
+ /* Third party bus reset or reset for error recovery
+ * reasons. Just retry the command and see what
+ * happens.
+ */
+ action = ACTION_RETRY;
+ } else if (sshdr) {
+ switch (sshdr->sense_key) {
+ case UNIT_ATTENTION:
+ if (cmd->device->removable) {
+ /* Detected disc change. Set a bit
+ * and quietly refuse further access.
+ */
+ cmd->device->changed = 1;
+ } else {
+ /* Must have been a power glitch, or a
+ * bus reset. Could not have been a
+ * media change, so we just retry the
+ * command and see what happens.
+ */
+ action = ACTION_RETRY;
+ }
+ break;
+ case ILLEGAL_REQUEST:
+ /* If we had an ILLEGAL REQUEST returned, then
+ * we may have performed an unsupported
+ * command. The only thing this should be
+ * would be a ten byte read where only a six
+ * byte read was supported. Also, on a system
+ * where READ CAPACITY failed, we may have
+ * read past the end of the disk.
+ */
+ if ((cmd->device->use_10_for_rw &&
+ sshdr->asc == 0x20 && sshdr->ascq == 0x00) &&
+ (cmd->cmnd[0] == READ_10 ||
+ cmd->cmnd[0] == WRITE_10)) {
+ /* This will issue a new 6-byte command. */
+ cmd->device->use_10_for_rw = 0;
+ action = ACTION_REPREP;
+ } else if (sshdr->asc == 0x10) /* DIX */ {
+ error = -EILSEQ;
+ /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */
+ } else if (sshdr->asc == 0x20 || sshdr->asc == 0x24) {
+ error = -EREMOTEIO;
+ }
+ break;
+ case ABORTED_COMMAND:
+ if (sshdr->asc == 0x10) /* DIF */
+ error = -EILSEQ;
+ break;
+ case NOT_READY:
+ /* If the device is in the process of becoming
+ * ready, or has a temporary blockage, retry.
+ */
+ if (sshdr->asc == 0x04) {
+ switch (sshdr->ascq) {
+ case 0x01: /* becoming ready */
+ case 0x04: /* format in progress */
+ case 0x05: /* rebuild in progress */
+ case 0x06: /* recalculation in progress */
+ case 0x07: /* operation in progress */
+ case 0x08: /* Long write in progress */
+ case 0x09: /* self test in progress */
+ case 0x14: /* space allocation in progress */
+ action = ACTION_DELAYED_RETRY;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case VOLUME_OVERFLOW:
+ /* See SSC3rXX or current. */
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (action != ACTION_FAIL &&
+ time_before(cmd->jiffies_at_alloc + wait_for, jiffies))
+ action = ACTION_FAIL;
+
+ switch (action) {
+ case ACTION_FAIL:
+ /* Give up and fail the remainder of the request */
+ if (!(req->cmd_flags & REQ_QUIET)) {
+ scsi_print_result(cmd);
+ if (driver_byte(result) & DRIVER_SENSE)
+ scsi_print_sense("", cmd);
+ scsi_print_command(cmd);
+ }
+ if (!scsi_end_request(req, error, blk_rq_err_bytes(req), 0))
+ break;
+ /*FALLTHRU*/
+ case ACTION_REPREP:
+ return false;
+ case ACTION_RETRY:
+ /* Retry the same command immediately */
+ __scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY, 0);
+ break;
+ case ACTION_DELAYED_RETRY:
+ /* Retry the same command after a delay */
+ __scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY, 0);
+ break;
+ }
+
+ return true;
+}
+
/*
* Function: scsi_io_completion()
*
@@ -779,9 +905,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
int sense_deferred = 0;
- enum {ACTION_FAIL, ACTION_REPREP, ACTION_RETRY,
- ACTION_DELAYED_RETRY} action;
- unsigned long wait_for = (cmd->allowed + 1) * req->timeout;
if (result) {
sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
@@ -867,7 +990,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
/*
* If we finished all bytes in the request we are done now.
*/
- if (!scsi_end_request(req, error, good_bytes, 0))
+ if (likely(!scsi_end_request(req, error, good_bytes, 0)))
return;
/*
@@ -880,132 +1003,18 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
}
/*
- * If there had been no error, but we have leftover bytes in the
- * requeues just queue the command up again.
+ * Try to handle errors if we got a non-zero result.
*/
- if (result == 0)
- goto requeue;
-
- error = __scsi_error_from_host_byte(cmd, result);
-
- if (host_byte(result) == DID_RESET) {
- /* Third party bus reset or reset for error recovery
- * reasons. Just retry the command and see what
- * happens.
- */
- action = ACTION_RETRY;
- } else if (sense_valid && !sense_deferred) {
- switch (sshdr.sense_key) {
- case UNIT_ATTENTION:
- if (cmd->device->removable) {
- /* Detected disc change. Set a bit
- * and quietly refuse further access.
- */
- cmd->device->changed = 1;
- action = ACTION_FAIL;
- } else {
- /* Must have been a power glitch, or a
- * bus reset. Could not have been a
- * media change, so we just retry the
- * command and see what happens.
- */
- action = ACTION_RETRY;
- }
- break;
- case ILLEGAL_REQUEST:
- /* If we had an ILLEGAL REQUEST returned, then
- * we may have performed an unsupported
- * command. The only thing this should be
- * would be a ten byte read where only a six
- * byte read was supported. Also, on a system
- * where READ CAPACITY failed, we may have
- * read past the end of the disk.
- */
- if ((cmd->device->use_10_for_rw &&
- sshdr.asc == 0x20 && sshdr.ascq == 0x00) &&
- (cmd->cmnd[0] == READ_10 ||
- cmd->cmnd[0] == WRITE_10)) {
- /* This will issue a new 6-byte command. */
- cmd->device->use_10_for_rw = 0;
- action = ACTION_REPREP;
- } else if (sshdr.asc == 0x10) /* DIX */ {
- action = ACTION_FAIL;
- error = -EILSEQ;
- /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */
- } else if (sshdr.asc == 0x20 || sshdr.asc == 0x24) {
- action = ACTION_FAIL;
- error = -EREMOTEIO;
- } else
- action = ACTION_FAIL;
- break;
- case ABORTED_COMMAND:
- action = ACTION_FAIL;
- if (sshdr.asc == 0x10) /* DIF */
- error = -EILSEQ;
- break;
- case NOT_READY:
- /* If the device is in the process of becoming
- * ready, or has a temporary blockage, retry.
- */
- if (sshdr.asc == 0x04) {
- switch (sshdr.ascq) {
- case 0x01: /* becoming ready */
- case 0x04: /* format in progress */
- case 0x05: /* rebuild in progress */
- case 0x06: /* recalculation in progress */
- case 0x07: /* operation in progress */
- case 0x08: /* Long write in progress */
- case 0x09: /* self test in progress */
- case 0x14: /* space allocation in progress */
- action = ACTION_DELAYED_RETRY;
- break;
- default:
- action = ACTION_FAIL;
- break;
- }
- } else
- action = ACTION_FAIL;
- break;
- case VOLUME_OVERFLOW:
- /* See SSC3rXX or current. */
- action = ACTION_FAIL;
- break;
- default:
- action = ACTION_FAIL;
- break;
- }
- } else
- action = ACTION_FAIL;
-
- if (action != ACTION_FAIL &&
- time_before(cmd->jiffies_at_alloc + wait_for, jiffies))
- action = ACTION_FAIL;
-
- switch (action) {
- case ACTION_FAIL:
- /* Give up and fail the remainder of the request */
- if (!(req->cmd_flags & REQ_QUIET)) {
- scsi_print_result(cmd);
- if (driver_byte(result) & DRIVER_SENSE)
- scsi_print_sense("", cmd);
- scsi_print_command(cmd);
- }
- if (!scsi_end_request(req, error, blk_rq_err_bytes(req), 0))
+ if (result != 0) {
+ if (scsi_handle_ioerror(cmd, result,
+ sense_valid && !sense_deferred ? &sshdr : NULL))
return;
- /*FALLTHRU*/
- case ACTION_REPREP:
- requeue:
- scsi_requeue_command(cmd);
- break;
- case ACTION_RETRY:
- /* Retry the same command immediately */
- __scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY, 0);
- break;
- case ACTION_DELAYED_RETRY:
- /* Retry the same command after a delay */
- __scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY, 0);
- break;
}
+
+ /*
+ * Queue up the leftovers again.
+ */
+ scsi_requeue_command(cmd);
}
static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb)
--
1.9.1
next prev parent reply other threads:[~2014-09-07 16:29 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-07 16:31 I/O path cleanup Christoph Hellwig
2014-09-07 16:31 ` [PATCH 1/8] scsi: don't use scsi_next_command in scsi_reset_provider Christoph Hellwig
2014-10-01 12:03 ` Bart Van Assche
2014-09-07 16:31 ` [PATCH 2/8] scsi: remove scsi_next_command Christoph Hellwig
2014-10-01 12:06 ` Bart Van Assche
2014-09-07 16:31 ` [PATCH 3/8] scsi: clean up S/G table freeing Christoph Hellwig
2014-10-01 12:22 ` Bart Van Assche
2014-10-01 21:05 ` Christoph Hellwig
2014-09-07 16:31 ` [PATCH 4/8] scsi: stop passing a gfp_mask argument down the command setup path Christoph Hellwig
2014-10-01 12:28 ` Bart Van Assche
2014-09-07 16:31 ` [PATCH 5/8] scsi: move scsi_dispatch_cmd to scsi_lib.c Christoph Hellwig
2014-10-01 12:30 ` Bart Van Assche
2014-09-07 16:31 ` [PATCH 6/8] scsi: move more requeue handling into scsi_requeue_command Christoph Hellwig
2014-10-01 12:33 ` Bart Van Assche
2014-09-07 16:31 ` Christoph Hellwig [this message]
2014-10-01 12:46 ` [PATCH 7/8] scsi: split error handling slow path out of scsi_io_completion Bart Van Assche
2014-09-07 16:31 ` [PATCH 8/8] scsi: merge scsi_finish_command and scsi_io_completion Christoph Hellwig
2014-10-01 12:55 ` Bart Van Assche
2014-09-08 7:22 ` I/O path cleanup Bart Van Assche
2014-09-08 15:13 ` Christoph Hellwig
2014-09-30 13:31 ` Bart Van Assche
2014-09-30 13:43 ` Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1410107469-896-8-git-send-email-hch@lst.de \
--to=hch@lst.de \
--cc=linux-scsi@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.