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>
This commit is contained in:
Douglas Gilbert 2018-06-23 12:22:17 +02:00 committed by Martin K. Petersen
parent ab83108460
commit da32baea17
1 changed files with 193 additions and 172 deletions

View File

@ -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;