scsi: core: add scsi_io_completion_action helper
Place scsi_io_completion()'s complex error processing associated with a
local enumeration into a static helper function. That enumeration's values
start with "ACTION_" so use the suffix "_action" in the helper function's
name.
Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: Bart Van Assche <bart.vanassche@wdc.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 0289240..16a7e68 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -761,183 +761,23 @@ static blk_status_t scsi_result_to_blk_status(struct scsi_cmnd *cmd, int result)
}
}
-/*
- * Helper for scsi_io_completion() when cmd->result is non-zero. Returns a
- * new result that may suppress further error checking. Also modifies
- * *blk_statp in some cases.
- */
-static int scsi_io_completion_nz_result(struct scsi_cmnd *cmd, int result,
- blk_status_t *blk_statp)
+/* Helper for scsi_io_completion() when special action required. */
+static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
{
- bool sense_valid;
- bool sense_current = true; /* false implies "deferred sense" */
- struct request *req = cmd->request;
- struct scsi_sense_hdr sshdr;
-
- sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
- if (sense_valid)
- sense_current = !scsi_sense_is_deferred(&sshdr);
-
- if (blk_rq_is_passthrough(req)) {
- if (sense_valid) {
- /*
- * SG_IO wants current and deferred errors
- */
- scsi_req(req)->sense_len =
- min(8 + cmd->sense_buffer[7],
- SCSI_SENSE_BUFFERSIZE);
- }
- if (sense_current)
- *blk_statp = scsi_result_to_blk_status(cmd, result);
- } else if (blk_rq_bytes(req) == 0 && sense_current) {
- /*
- * Flush commands do not transfers any data, and thus cannot use
- * good_bytes != blk_rq_bytes(req) as the signal for an error.
- * This sets *blk_statp explicitly for the problem case.
- */
- *blk_statp = scsi_result_to_blk_status(cmd, result);
- }
- /*
- * Recovered errors need reporting, but they're always treated as
- * success, so fiddle the result code here. For passthrough requests
- * we already took a copy of the original into sreq->result which
- * is what gets returned to the user
- */
- if (sense_valid && (sshdr.sense_key == RECOVERED_ERROR)) {
- bool do_print = true;
- /*
- * if ATA PASS-THROUGH INFORMATION AVAILABLE [0x0, 0x1d]
- * skip print since caller wants ATA registers. Only occurs
- * on SCSI ATA PASS_THROUGH commands when CK_COND=1
- */
- if ((sshdr.asc == 0x0) && (sshdr.ascq == 0x1d))
- do_print = false;
- else if (req->rq_flags & RQF_QUIET)
- do_print = false;
- if (do_print)
- scsi_print_sense(cmd);
- result = 0;
- /* for passthrough, *blk_statp may be set */
- *blk_statp = BLK_STS_OK;
- }
- /*
- * Another corner case: the SCSI status byte is non-zero but 'good'.
- * Example: PRE-FETCH command returns SAM_STAT_CONDITION_MET when
- * it is able to fit nominated LBs in its cache (and SAM_STAT_GOOD
- * if it can't fit). Treat SAM_STAT_CONDITION_MET and the related
- * intermediate statuses (both obsolete in SAM-4) as good.
- */
- if (status_byte(result) && scsi_status_is_good(result)) {
- result = 0;
- *blk_statp = BLK_STS_OK;
- }
- return result;
-}
-
-/*
- * Function: scsi_io_completion()
- *
- * Purpose: Completion processing for block device I/O requests.
- *
- * Arguments: cmd - command that is finished.
- *
- * Lock status: Assumed that no lock is held upon entry.
- *
- * Returns: Nothing
- *
- * Notes: We will finish off the specified number of sectors. If we
- * are done, the command block will be released and the queue
- * function will be goosed. If we are not done then we have to
- * figure out what to do next:
- *
- * a) We can call scsi_requeue_command(). The request
- * will be unprepared and put back on the queue. Then
- * a new command will be created for it. This should
- * be used if we made forward progress, or if we want
- * to switch from READ(10) to READ(6) for example.
- *
- * b) We can call __scsi_queue_insert(). The request will
- * be put back on the queue and retried using the same
- * command as before, possibly after a delay.
- *
- * c) We can call scsi_end_request() with blk_stat other than
- * BLK_STS_OK, to fail the remainder of the request.
- */
-void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
-{
- int result = cmd->result;
struct request_queue *q = cmd->device->request_queue;
struct request *req = cmd->request;
- blk_status_t blk_stat = BLK_STS_OK;
- struct scsi_sense_hdr sshdr;
- bool sense_valid = false;
- bool sense_current = true; /* false implies "deferred sense" */
int level = 0;
enum {ACTION_FAIL, ACTION_REPREP, ACTION_RETRY,
ACTION_DELAYED_RETRY} action;
unsigned long wait_for = (cmd->allowed + 1) * req->timeout;
+ struct scsi_sense_hdr sshdr;
+ bool sense_valid;
+ bool sense_current = true; /* false implies "deferred sense" */
+ blk_status_t blk_stat;
- if (result) { /* does not necessarily mean there is an error */
- sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
- if (sense_valid)
- sense_current = !scsi_sense_is_deferred(&sshdr);
- result = scsi_io_completion_nz_result(cmd, result, &blk_stat);
- }
-
- if (blk_rq_is_passthrough(req)) {
- /*
- * scsi_result_to_blk_status may have reset the host_byte
- */
- scsi_req(req)->result = cmd->result;
- scsi_req(req)->resid_len = scsi_get_resid(cmd);
-
- if (scsi_bidi_cmnd(cmd)) {
- /*
- * Bidi commands Must be complete as a whole,
- * both sides at once.
- */
- scsi_req(req->next_rq)->resid_len = scsi_in(cmd)->resid;
- if (scsi_end_request(req, BLK_STS_OK, blk_rq_bytes(req),
- blk_rq_bytes(req->next_rq)))
- BUG();
- return;
- }
- }
-
- /* no bidi support for !blk_rq_is_passthrough yet */
- BUG_ON(blk_bidi_rq(req));
-
- /*
- * Next deal with any sectors which we were able to correctly
- * handle.
- */
- SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, cmd,
- "%u sectors total, %d bytes done.\n",
- blk_rq_sectors(req), good_bytes));
-
- /*
- * Next deal with any sectors which we were able to correctly
- * handle. Failed, zero length commands always need to drop down
- * to retry code. Fast path should return in this block.
- */
- if (blk_rq_bytes(req) > 0 || blk_stat == BLK_STS_OK) {
- if (!scsi_end_request(req, blk_stat, good_bytes, 0))
- return; /* no bytes remaining */
- }
-
- /* Kill remainder if no retries. */
- if (blk_stat && scsi_noretry_cmd(cmd)) {
- if (scsi_end_request(req, blk_stat, blk_rq_bytes(req), 0))
- BUG();
- return;
- }
-
- /*
- * If there had been no error, but we have leftover bytes in the
- * requeues just queue the command up again.
- */
- if (result == 0)
- goto requeue;
+ sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
+ if (sense_valid)
+ sense_current = !scsi_sense_is_deferred(&sshdr);
blk_stat = scsi_result_to_blk_status(cmd, result);
@@ -1047,8 +887,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
DEFAULT_RATELIMIT_BURST);
if (unlikely(scsi_logging_level))
- level = SCSI_LOG_LEVEL(SCSI_LOG_MLCOMPLETE_SHIFT,
- SCSI_LOG_MLCOMPLETE_BITS);
+ level =
+ SCSI_LOG_LEVEL(SCSI_LOG_MLCOMPLETE_SHIFT,
+ SCSI_LOG_MLCOMPLETE_BITS);
/*
* if logging is enabled the failure will be printed
@@ -1065,7 +906,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
return;
/*FALLTHRU*/
case ACTION_REPREP:
- requeue:
/* Unprep the request and put it back at the head of the queue.
* A new command will be prepared and issued.
*/
@@ -1087,6 +927,187 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
}
}
+/*
+ * Helper for scsi_io_completion() when cmd->result is non-zero. Returns a
+ * new result that may suppress further error checking. Also modifies
+ * *blk_statp in some cases.
+ */
+static int scsi_io_completion_nz_result(struct scsi_cmnd *cmd, int result,
+ blk_status_t *blk_statp)
+{
+ bool sense_valid;
+ bool sense_current = true; /* false implies "deferred sense" */
+ struct request *req = cmd->request;
+ struct scsi_sense_hdr sshdr;
+
+ sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
+ if (sense_valid)
+ sense_current = !scsi_sense_is_deferred(&sshdr);
+
+ if (blk_rq_is_passthrough(req)) {
+ if (sense_valid) {
+ /*
+ * SG_IO wants current and deferred errors
+ */
+ scsi_req(req)->sense_len =
+ min(8 + cmd->sense_buffer[7],
+ SCSI_SENSE_BUFFERSIZE);
+ }
+ if (sense_current)
+ *blk_statp = scsi_result_to_blk_status(cmd, result);
+ } else if (blk_rq_bytes(req) == 0 && sense_current) {
+ /*
+ * Flush commands do not transfers any data, and thus cannot use
+ * good_bytes != blk_rq_bytes(req) as the signal for an error.
+ * This sets *blk_statp explicitly for the problem case.
+ */
+ *blk_statp = scsi_result_to_blk_status(cmd, result);
+ }
+ /*
+ * Recovered errors need reporting, but they're always treated as
+ * success, so fiddle the result code here. For passthrough requests
+ * we already took a copy of the original into sreq->result which
+ * is what gets returned to the user
+ */
+ if (sense_valid && (sshdr.sense_key == RECOVERED_ERROR)) {
+ bool do_print = true;
+ /*
+ * if ATA PASS-THROUGH INFORMATION AVAILABLE [0x0, 0x1d]
+ * skip print since caller wants ATA registers. Only occurs
+ * on SCSI ATA PASS_THROUGH commands when CK_COND=1
+ */
+ if ((sshdr.asc == 0x0) && (sshdr.ascq == 0x1d))
+ do_print = false;
+ else if (req->rq_flags & RQF_QUIET)
+ do_print = false;
+ if (do_print)
+ scsi_print_sense(cmd);
+ result = 0;
+ /* for passthrough, *blk_statp may be set */
+ *blk_statp = BLK_STS_OK;
+ }
+ /*
+ * Another corner case: the SCSI status byte is non-zero but 'good'.
+ * Example: PRE-FETCH command returns SAM_STAT_CONDITION_MET when
+ * it is able to fit nominated LBs in its cache (and SAM_STAT_GOOD
+ * if it can't fit). Treat SAM_STAT_CONDITION_MET and the related
+ * intermediate statuses (both obsolete in SAM-4) as good.
+ */
+ if (status_byte(result) && scsi_status_is_good(result)) {
+ result = 0;
+ *blk_statp = BLK_STS_OK;
+ }
+ return result;
+}
+
+/*
+ * Function: scsi_io_completion()
+ *
+ * Purpose: Completion processing for block device I/O requests.
+ *
+ * Arguments: cmd - command that is finished.
+ *
+ * Lock status: Assumed that no lock is held upon entry.
+ *
+ * Returns: Nothing
+ *
+ * Notes: We will finish off the specified number of sectors. If we
+ * are done, the command block will be released and the queue
+ * function will be goosed. If we are not done then we have to
+ * figure out what to do next:
+ *
+ * a) We can call scsi_requeue_command(). The request
+ * will be unprepared and put back on the queue. Then
+ * a new command will be created for it. This should
+ * be used if we made forward progress, or if we want
+ * to switch from READ(10) to READ(6) for example.
+ *
+ * b) We can call __scsi_queue_insert(). The request will
+ * be put back on the queue and retried using the same
+ * command as before, possibly after a delay.
+ *
+ * c) We can call scsi_end_request() with blk_stat other than
+ * BLK_STS_OK, to fail the remainder of the request.
+ */
+void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
+{
+ int result = cmd->result;
+ struct request_queue *q = cmd->device->request_queue;
+ struct request *req = cmd->request;
+ blk_status_t blk_stat = BLK_STS_OK;
+
+ if (result) /* does not necessarily mean there is an error */
+ result = scsi_io_completion_nz_result(cmd, result, &blk_stat);
+
+ if (blk_rq_is_passthrough(req)) {
+ /*
+ * scsi_result_to_blk_status may have reset the host_byte
+ */
+ scsi_req(req)->result = cmd->result;
+ scsi_req(req)->resid_len = scsi_get_resid(cmd);
+
+ if (scsi_bidi_cmnd(cmd)) {
+ /*
+ * Bidi commands Must be complete as a whole,
+ * both sides at once.
+ */
+ scsi_req(req->next_rq)->resid_len = scsi_in(cmd)->resid;
+ if (scsi_end_request(req, BLK_STS_OK, blk_rq_bytes(req),
+ blk_rq_bytes(req->next_rq)))
+ BUG();
+ return;
+ }
+ }
+
+ /* no bidi support for !blk_rq_is_passthrough yet */
+ BUG_ON(blk_bidi_rq(req));
+
+ /*
+ * Next deal with any sectors which we were able to correctly
+ * handle.
+ */
+ SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, cmd,
+ "%u sectors total, %d bytes done.\n",
+ blk_rq_sectors(req), good_bytes));
+
+ /*
+ * Next deal with any sectors which we were able to correctly
+ * handle. Failed, zero length commands always need to drop down
+ * to retry code. Fast path should return in this block.
+ */
+ if (blk_rq_bytes(req) > 0 || blk_stat == BLK_STS_OK) {
+ if (!scsi_end_request(req, blk_stat, good_bytes, 0))
+ return; /* no bytes remaining */
+ }
+
+ /* Kill remainder if no retries. */
+ if (blk_stat && scsi_noretry_cmd(cmd)) {
+ if (scsi_end_request(req, blk_stat, blk_rq_bytes(req), 0))
+ BUG();
+ return;
+ }
+
+ /*
+ * If there had been no error, but we have leftover bytes in the
+ * requeues just queue the command up again.
+ */
+ if (result == 0) {
+ /*
+ * Unprep the request and put it back at the head of the
+ * queue. A new command will be prepared and issued.
+ * This block is the same as case ACTION_REPREP in
+ * scsi_io_completion_action() above.
+ */
+ if (q->mq_ops) {
+ scsi_mq_requeue_cmd(cmd);
+ } else {
+ scsi_release_buffers(cmd);
+ scsi_requeue_command(q, cmd);
+ }
+ } else
+ scsi_io_completion_action(cmd, result);
+}
+
static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb)
{
int count;