Loading Documentation/scsi/scsi_eh.txt +39 −30 Original line number Diff line number Diff line Loading @@ -42,20 +42,14 @@ discussion. Once LLDD gets hold of a scmd, either the LLDD will complete the command by calling scsi_done callback passed from midlayer when invoking hostt->queuecommand() or SCSI midlayer will time it out. invoking hostt->queuecommand() or the block layer will time it out. [1-2-1] Completing a scmd w/ scsi_done For all non-EH commands, scsi_done() is the completion callback. It does the following. 1. Delete timeout timer. If it fails, it means that timeout timer has expired and is going to finish the command. Just return. 2. Link scmd to per-cpu scsi_done_q using scmd->en_entry 3. Raise SCSI_SOFTIRQ just calls blk_complete_request() to delete the block layer timer and raise SCSI_SOFTIRQ SCSI_SOFTIRQ handler scsi_softirq calls scsi_decide_disposition() to determine what to do with the command. scsi_decide_disposition() Loading @@ -64,10 +58,12 @@ with the command. - SUCCESS scsi_finish_command() is invoked for the command. The function does some maintenance choirs and notify completion by calling scmd->done() callback, which, for fs requests, would be HLD completion callback - sd:sd_rw_intr, sr:rw_intr, st:st_intr. function does some maintenance chores and then calls scsi_io_completion() to finish the I/O. scsi_io_completion() then notifies the block layer on the completed request by calling blk_end_request and friends or figures out what to do with the remainder of the data in case of an error. - NEEDS_RETRY - ADD_TO_MLQUEUE Loading @@ -86,33 +82,45 @@ function 1. invokes optional hostt->eh_timed_out() callback. Return value can be one of - EH_HANDLED This indicates that eh_timed_out() dealt with the timeout. The scmd is passed to __scsi_done() and thus linked into per-cpu scsi_done_q. Normal command completion described in [1-2-1] follows. - BLK_EH_HANDLED This indicates that eh_timed_out() dealt with the timeout. The command is passed back to the block layer and completed via __blk_complete_requests(). *NOTE* After returning BLK_EH_HANDLED the SCSI layer is assumed to be finished with the command, and no other functions from the SCSI layer will be called. So this should typically only be returned if the eh_timed_out() handler raced with normal completion. - EH_RESET_TIMER - BLK_EH_RESET_TIMER This indicates that more time is required to finish the command. Timer is restarted. This action is counted as a retry and only allowed scmd->allowed + 1(!) times. Once the limit is reached, action for EH_NOT_HANDLED is taken instead. limit is reached, action for BLK_EH_NOT_HANDLED is taken instead. *NOTE* This action is racy as the LLDD could finish the scmd after the timeout has expired but before it's added back. In such cases, scsi_done() would think that timeout has occurred and return without doing anything. We lose completion and the command will time out again. - EH_NOT_HANDLED This is the same as when eh_timed_out() callback doesn't exist. - BLK_EH_NOT_HANDLED eh_timed_out() callback did not handle the command. Step #2 is taken. 2. If the host supports asynchronous completion (as indicated by the no_async_abort setting in the host template) scsi_abort_command() is invoked to schedule an asynchrous abort. If that fails Step #3 is taken. 2. scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD) is invoked for the command. See [1-3] for more information. [1-3] Asynchronous command aborts [1-3] How EH takes over After a timeout occurs a command abort is scheduled from scsi_abort_command(). If the abort is successful the command will either be retried (if the number of retries is not exhausted) or terminated with DID_TIME_OUT. Otherwise scsi_eh_scmd_add() is invoked for the command. See [1-4] for more information. [1-4] How EH takes over scmds enter EH via scsi_eh_scmd_add(), which does the following. Loading Loading @@ -320,7 +328,8 @@ scmd->allowed. <<scsi_eh_abort_cmds>> This action is taken for each timed out command. This action is taken for each timed out command when no_async_abort is enabled in the host template. hostt->eh_abort_handler() is invoked for each scmd. The handler returns SUCCESS if it has succeeded to make LLDD and all related hardware forget about the scmd. Loading Documentation/scsi/scsi_mid_low_api.txt +7 −2 Original line number Diff line number Diff line Loading @@ -882,8 +882,11 @@ Details: * * Calling context: kernel thread * * Notes: Invoked from scsi_eh thread. No other commands will be * queued on current host during eh. * Notes: If 'no_async_abort' is defined this callback * will be invoked from scsi_eh thread. No other commands * will then be queued on current host during eh. * Otherwise it will be called whenever scsi_times_out() * is called due to a command timeout. * * Optionally defined in: LLD **/ Loading Loading @@ -1257,6 +1260,8 @@ of interest: address space use_clustering - 1=>SCSI commands in mid level's queue can be merged, 0=>disallow SCSI command merging no_async_abort - 1=>Asynchronous aborts are not supported 0=>Timed-out commands will be aborted asynchronously hostt - pointer to driver's struct scsi_host_template from which this struct Scsi_Host instance was spawned hostt->proc_name - name of LLD. This is the driver name that sysfs uses Loading drivers/scsi/scsi.c +2 −4 Original line number Diff line number Diff line Loading @@ -745,15 +745,13 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) } /** * scsi_done - Enqueue the finished SCSI command into the done queue. * scsi_done - Invoke completion on finished SCSI command. * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives * ownership back to SCSI Core -- i.e. the LLDD has finished with it. * * Description: This function is the mid-level's (SCSI Core) interrupt routine, * which regains ownership of the SCSI command (de facto) from a LLDD, and * enqueues the command to the done queue for further processing. * * This is the producer of the done queue who enqueues at the tail. * calls blk_complete_request() for further processing. * * This function is interrupt context safe. */ Loading Loading
Documentation/scsi/scsi_eh.txt +39 −30 Original line number Diff line number Diff line Loading @@ -42,20 +42,14 @@ discussion. Once LLDD gets hold of a scmd, either the LLDD will complete the command by calling scsi_done callback passed from midlayer when invoking hostt->queuecommand() or SCSI midlayer will time it out. invoking hostt->queuecommand() or the block layer will time it out. [1-2-1] Completing a scmd w/ scsi_done For all non-EH commands, scsi_done() is the completion callback. It does the following. 1. Delete timeout timer. If it fails, it means that timeout timer has expired and is going to finish the command. Just return. 2. Link scmd to per-cpu scsi_done_q using scmd->en_entry 3. Raise SCSI_SOFTIRQ just calls blk_complete_request() to delete the block layer timer and raise SCSI_SOFTIRQ SCSI_SOFTIRQ handler scsi_softirq calls scsi_decide_disposition() to determine what to do with the command. scsi_decide_disposition() Loading @@ -64,10 +58,12 @@ with the command. - SUCCESS scsi_finish_command() is invoked for the command. The function does some maintenance choirs and notify completion by calling scmd->done() callback, which, for fs requests, would be HLD completion callback - sd:sd_rw_intr, sr:rw_intr, st:st_intr. function does some maintenance chores and then calls scsi_io_completion() to finish the I/O. scsi_io_completion() then notifies the block layer on the completed request by calling blk_end_request and friends or figures out what to do with the remainder of the data in case of an error. - NEEDS_RETRY - ADD_TO_MLQUEUE Loading @@ -86,33 +82,45 @@ function 1. invokes optional hostt->eh_timed_out() callback. Return value can be one of - EH_HANDLED This indicates that eh_timed_out() dealt with the timeout. The scmd is passed to __scsi_done() and thus linked into per-cpu scsi_done_q. Normal command completion described in [1-2-1] follows. - BLK_EH_HANDLED This indicates that eh_timed_out() dealt with the timeout. The command is passed back to the block layer and completed via __blk_complete_requests(). *NOTE* After returning BLK_EH_HANDLED the SCSI layer is assumed to be finished with the command, and no other functions from the SCSI layer will be called. So this should typically only be returned if the eh_timed_out() handler raced with normal completion. - EH_RESET_TIMER - BLK_EH_RESET_TIMER This indicates that more time is required to finish the command. Timer is restarted. This action is counted as a retry and only allowed scmd->allowed + 1(!) times. Once the limit is reached, action for EH_NOT_HANDLED is taken instead. limit is reached, action for BLK_EH_NOT_HANDLED is taken instead. *NOTE* This action is racy as the LLDD could finish the scmd after the timeout has expired but before it's added back. In such cases, scsi_done() would think that timeout has occurred and return without doing anything. We lose completion and the command will time out again. - EH_NOT_HANDLED This is the same as when eh_timed_out() callback doesn't exist. - BLK_EH_NOT_HANDLED eh_timed_out() callback did not handle the command. Step #2 is taken. 2. If the host supports asynchronous completion (as indicated by the no_async_abort setting in the host template) scsi_abort_command() is invoked to schedule an asynchrous abort. If that fails Step #3 is taken. 2. scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD) is invoked for the command. See [1-3] for more information. [1-3] Asynchronous command aborts [1-3] How EH takes over After a timeout occurs a command abort is scheduled from scsi_abort_command(). If the abort is successful the command will either be retried (if the number of retries is not exhausted) or terminated with DID_TIME_OUT. Otherwise scsi_eh_scmd_add() is invoked for the command. See [1-4] for more information. [1-4] How EH takes over scmds enter EH via scsi_eh_scmd_add(), which does the following. Loading Loading @@ -320,7 +328,8 @@ scmd->allowed. <<scsi_eh_abort_cmds>> This action is taken for each timed out command. This action is taken for each timed out command when no_async_abort is enabled in the host template. hostt->eh_abort_handler() is invoked for each scmd. The handler returns SUCCESS if it has succeeded to make LLDD and all related hardware forget about the scmd. Loading
Documentation/scsi/scsi_mid_low_api.txt +7 −2 Original line number Diff line number Diff line Loading @@ -882,8 +882,11 @@ Details: * * Calling context: kernel thread * * Notes: Invoked from scsi_eh thread. No other commands will be * queued on current host during eh. * Notes: If 'no_async_abort' is defined this callback * will be invoked from scsi_eh thread. No other commands * will then be queued on current host during eh. * Otherwise it will be called whenever scsi_times_out() * is called due to a command timeout. * * Optionally defined in: LLD **/ Loading Loading @@ -1257,6 +1260,8 @@ of interest: address space use_clustering - 1=>SCSI commands in mid level's queue can be merged, 0=>disallow SCSI command merging no_async_abort - 1=>Asynchronous aborts are not supported 0=>Timed-out commands will be aborted asynchronously hostt - pointer to driver's struct scsi_host_template from which this struct Scsi_Host instance was spawned hostt->proc_name - name of LLD. This is the driver name that sysfs uses Loading
drivers/scsi/scsi.c +2 −4 Original line number Diff line number Diff line Loading @@ -745,15 +745,13 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) } /** * scsi_done - Enqueue the finished SCSI command into the done queue. * scsi_done - Invoke completion on finished SCSI command. * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives * ownership back to SCSI Core -- i.e. the LLDD has finished with it. * * Description: This function is the mid-level's (SCSI Core) interrupt routine, * which regains ownership of the SCSI command (de facto) from a LLDD, and * enqueues the command to the done queue for further processing. * * This is the producer of the done queue who enqueues at the tail. * calls blk_complete_request() for further processing. * * This function is interrupt context safe. */ Loading