brintos

brintos / linux-shallow public Read only

0
0
Text · 17.1 KiB · 104d09e Raw
514 lines · plain
1.. SPDX-License-Identifier: GPL-2.02 3=======4SCSI EH5=======6 7This document describes SCSI midlayer error handling infrastructure.8Please refer to Documentation/scsi/scsi_mid_low_api.rst for more9information regarding SCSI midlayer.10 11.. TABLE OF CONTENTS12 13   [1] How SCSI commands travel through the midlayer and to EH14       [1-1] struct scsi_cmnd15       [1-2] How do scmd's get completed?16   	[1-2-1] Completing a scmd w/ scsi_done17   	[1-2-2] Completing a scmd w/ timeout18       [1-3] How EH takes over19   [2] How SCSI EH works20       [2-1] EH through fine-grained callbacks21   	[2-1-1] Overview22   	[2-1-2] Flow of scmds through EH23   	[2-1-3] Flow of control24       [2-2] EH through transportt->eh_strategy_handler()25   	[2-2-1] Pre transportt->eh_strategy_handler() SCSI midlayer conditions26   	[2-2-2] Post transportt->eh_strategy_handler() SCSI midlayer conditions27   	[2-2-3] Things to consider28 29 301. How SCSI commands travel through the midlayer and to EH31==========================================================32 331.1 struct scsi_cmnd34--------------------35 36Each SCSI command is represented with struct scsi_cmnd (== scmd).  A37scmd has two list_head's to link itself into lists.  The two are38scmd->list and scmd->eh_entry.  The former is used for free list or39per-device allocated scmd list and not of much interest to this EH40discussion.  The latter is used for completion and EH lists and unless41otherwise stated scmds are always linked using scmd->eh_entry in this42discussion.43 44 451.2 How do scmd's get completed?46--------------------------------47 48Once LLDD gets hold of a scmd, either the LLDD will complete the49command by calling scsi_done callback passed from midlayer when50invoking hostt->queuecommand() or the block layer will time it out.51 52 531.2.1 Completing a scmd w/ scsi_done54^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^55 56For all non-EH commands, scsi_done() is the completion callback.  It57just calls blk_complete_request() to delete the block layer timer and58raise SCSI_SOFTIRQ59 60SCSI_SOFTIRQ handler scsi_softirq calls scsi_decide_disposition() to61determine what to do with the command.  scsi_decide_disposition()62looks at the scmd->result value and sense data to determine what to do63with the command.64 65 - SUCCESS66 67	scsi_finish_command() is invoked for the command.  The68	function does some maintenance chores and then calls69	scsi_io_completion() to finish the I/O.70	scsi_io_completion() then notifies the block layer on71	the completed request by calling blk_end_request and72	friends or figures out what to do with the remainder73	of the data in case of an error.74 75 - NEEDS_RETRY76 77 - ADD_TO_MLQUEUE78 79	scmd is requeued to blk queue.80 81 - otherwise82 83	scsi_eh_scmd_add(scmd) is invoked for the command.  See84	[1-3] for details of this function.85 86 871.2.2 Completing a scmd w/ timeout88^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^89 90The timeout handler is scsi_timeout().  When a timeout occurs, this function91 92 1. invokes optional hostt->eh_timed_out() callback.  Return value can93    be one of94 95    - SCSI_EH_RESET_TIMER96	This indicates that more time is required to finish the97	command.  Timer is restarted.98 99    - SCSI_EH_NOT_HANDLED100        eh_timed_out() callback did not handle the command.101	Step #2 is taken.102 103    - SCSI_EH_DONE104        eh_timed_out() completed the command.105 106 2. scsi_abort_command() is invoked to schedule an asynchronous abort which may107    issue a retry scmd->allowed + 1 times.  Asynchronous aborts are not invoked108    for commands for which the SCSI_EH_ABORT_SCHEDULED flag is set (this109    indicates that the command already had been aborted once, and this is a110    retry which failed), when retries are exceeded, or when the EH deadline is111    expired. In these cases Step #3 is taken.112 113 3. scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD) is invoked for the114    command.  See [1-4] for more information.115 1161.3 Asynchronous command aborts117-------------------------------118 119 After a timeout occurs a command abort is scheduled from120 scsi_abort_command(). If the abort is successful the command121 will either be retried (if the number of retries is not exhausted)122 or terminated with DID_TIME_OUT.123 124 Otherwise scsi_eh_scmd_add() is invoked for the command.125 See [1-4] for more information.126 1271.4 How EH takes over128---------------------129 130scmds enter EH via scsi_eh_scmd_add(), which does the following.131 132 1. Links scmd->eh_entry to shost->eh_cmd_q133 134 2. Sets SHOST_RECOVERY bit in shost->shost_state135 136 3. Increments shost->host_failed137 138 4. Wakes up SCSI EH thread if shost->host_busy == shost->host_failed139 140As can be seen above, once any scmd is added to shost->eh_cmd_q,141SHOST_RECOVERY shost_state bit is turned on.  This prevents any new142scmd to be issued from blk queue to the host; eventually, all scmds on143the host either complete normally, fail and get added to eh_cmd_q, or144time out and get added to shost->eh_cmd_q.145 146If all scmds either complete or fail, the number of in-flight scmds147becomes equal to the number of failed scmds - i.e. shost->host_busy ==148shost->host_failed.  This wakes up SCSI EH thread.  So, once woken up,149SCSI EH thread can expect that all in-flight commands have failed and150are linked on shost->eh_cmd_q.151 152Note that this does not mean lower layers are quiescent.  If a LLDD153completed a scmd with error status, the LLDD and lower layers are154assumed to forget about the scmd at that point.  However, if a scmd155has timed out, unless hostt->eh_timed_out() made lower layers forget156about the scmd, which currently no LLDD does, the command is still157active as long as lower layers are concerned and completion could158occur at any time.  Of course, all such completions are ignored as the159timer has already expired.160 161We'll talk about how SCSI EH takes actions to abort - make LLDD162forget about - timed out scmds later.163 164 1652. How SCSI EH works166====================167 168LLDD's can implement SCSI EH actions in one of the following two169ways.170 171 - Fine-grained EH callbacks172	LLDD can implement fine-grained EH callbacks and let SCSI173	midlayer drive error handling and call appropriate callbacks.174	This will be discussed further in [2-1].175 176 - eh_strategy_handler() callback177	This is one big callback which should perform whole error178	handling.  As such, it should do all chores the SCSI midlayer179	performs during recovery.  This will be discussed in [2-2].180 181Once recovery is complete, SCSI EH resumes normal operation by182calling scsi_restart_operations(), which183 184 1. Checks if door locking is needed and locks door.185 186 2. Clears SHOST_RECOVERY shost_state bit187 188 3. Wakes up waiters on shost->host_wait.  This occurs if someone189    calls scsi_block_when_processing_errors() on the host.190    (*QUESTION* why is it needed?  All operations will be blocked191    anyway after it reaches blk queue.)192 193 4. Kicks queues in all devices on the host in the asses194 195 1962.1 EH through fine-grained callbacks197-------------------------------------198 1992.1.1 Overview200^^^^^^^^^^^^^^201 202If eh_strategy_handler() is not present, SCSI midlayer takes charge203of driving error handling.  EH's goals are two - make LLDD, host and204device forget about timed out scmds and make them ready for new205commands.  A scmd is said to be recovered if the scmd is forgotten by206lower layers and lower layers are ready to process or fail the scmd207again.208 209To achieve these goals, EH performs recovery actions with increasing210severity.  Some actions are performed by issuing SCSI commands and211others are performed by invoking one of the following fine-grained212hostt EH callbacks.  Callbacks may be omitted and omitted ones are213considered to fail always.214 215::216 217    int (* eh_abort_handler)(struct scsi_cmnd *);218    int (* eh_device_reset_handler)(struct scsi_cmnd *);219    int (* eh_bus_reset_handler)(struct scsi_cmnd *);220    int (* eh_host_reset_handler)(struct scsi_cmnd *);221 222Higher-severity actions are taken only when lower-severity actions223cannot recover some of failed scmds.  Also, note that failure of the224highest-severity action means EH failure and results in offlining of225all unrecovered devices.226 227During recovery, the following rules are followed228 229 - Recovery actions are performed on failed scmds on the to do list,230   eh_work_q.  If a recovery action succeeds for a scmd, recovered231   scmds are removed from eh_work_q.232 233   Note that single recovery action on a scmd can recover multiple234   scmds.  e.g. resetting a device recovers all failed scmds on the235   device.236 237 - Higher severity actions are taken iff eh_work_q is not empty after238   lower severity actions are complete.239 240 - EH reuses failed scmds to issue commands for recovery.  For241   timed-out scmds, SCSI EH ensures that LLDD forgets about a scmd242   before reusing it for EH commands.243 244When a scmd is recovered, the scmd is moved from eh_work_q to EH245local eh_done_q using scsi_eh_finish_cmd().  After all scmds are246recovered (eh_work_q is empty), scsi_eh_flush_done_q() is invoked to247either retry or error-finish (notify upper layer of failure) recovered248scmds.249 250scmds are retried iff its sdev is still online (not offlined during251EH), REQ_FAILFAST is not set and ++scmd->retries is less than252scmd->allowed.253 254 2552.1.2 Flow of scmds through EH256^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^257 258 1. Error completion / time out259 260    :ACTION: scsi_eh_scmd_add() is invoked for scmd261 262	- add scmd to shost->eh_cmd_q263	- set SHOST_RECOVERY264	- shost->host_failed++265 266    :LOCKING: shost->host_lock267 268 2. EH starts269 270    :ACTION: move all scmds to EH's local eh_work_q.  shost->eh_cmd_q271	     is cleared.272 273    :LOCKING: shost->host_lock (not strictly necessary, just for274             consistency)275 276 3. scmd recovered277 278    :ACTION: scsi_eh_finish_cmd() is invoked to EH-finish scmd279 280	- scsi_setup_cmd_retry()281	- move from local eh_work_q to local eh_done_q282 283    :LOCKING: none284 285    :CONCURRENCY: at most one thread per separate eh_work_q to286		  keep queue manipulation lockless287 288 4. EH completes289 290    :ACTION: scsi_eh_flush_done_q() retries scmds or notifies upper291	     layer of failure. May be called concurrently but must have292	     a no more than one thread per separate eh_work_q to293	     manipulate the queue locklessly294 295	     - scmd is removed from eh_done_q and scmd->eh_entry is cleared296	     - if retry is necessary, scmd is requeued using297	       scsi_queue_insert()298	     - otherwise, scsi_finish_command() is invoked for scmd299	     - zero shost->host_failed300 301    :LOCKING: queue or finish function performs appropriate locking302 303 3042.1.3 Flow of control305^^^^^^^^^^^^^^^^^^^^^^306 307 EH through fine-grained callbacks start from scsi_unjam_host().308 309``scsi_unjam_host``310 311    1. Lock shost->host_lock, splice_init shost->eh_cmd_q into local312       eh_work_q and unlock host_lock.  Note that shost->eh_cmd_q is313       cleared by this action.314 315    2. Invoke scsi_eh_get_sense.316 317    ``scsi_eh_get_sense``318 319	This action is taken for each error-completed320	(!SCSI_EH_CANCEL_CMD) commands without valid sense data.  Most321	SCSI transports/LLDDs automatically acquire sense data on322	command failures (autosense).  Autosense is recommended for323	performance reasons and as sense information could get out of324	sync between occurrence of CHECK CONDITION and this action.325 326	Note that if autosense is not supported, scmd->sense_buffer327	contains invalid sense data when error-completing the scmd328	with scsi_done().  scsi_decide_disposition() always returns329	FAILED in such cases thus invoking SCSI EH.  When the scmd330	reaches here, sense data is acquired and331	scsi_decide_disposition() is called again.332 333	1. Invoke scsi_request_sense() which issues REQUEST_SENSE334           command.  If fails, no action.  Note that taking no action335           causes higher-severity recovery to be taken for the scmd.336 337	2. Invoke scsi_decide_disposition() on the scmd338 339	   - SUCCESS340		scmd->retries is set to scmd->allowed preventing341		scsi_eh_flush_done_q() from retrying the scmd and342		scsi_eh_finish_cmd() is invoked.343 344	   - NEEDS_RETRY345		scsi_eh_finish_cmd() invoked346 347	   - otherwise348		No action.349 350    3. If !list_empty(&eh_work_q), invoke scsi_eh_abort_cmds().351 352    ``scsi_eh_abort_cmds``353 354	This action is taken for each timed out command when355	no_async_abort is enabled in the host template.356	hostt->eh_abort_handler() is invoked for each scmd.  The357	handler returns SUCCESS if it has succeeded to make LLDD and358	all related hardware forget about the scmd.359 360	If a timedout scmd is successfully aborted and the sdev is361	either offline or ready, scsi_eh_finish_cmd() is invoked for362	the scmd.  Otherwise, the scmd is left in eh_work_q for363	higher-severity actions.364 365	Note that both offline and ready status mean that the sdev is366	ready to process new scmds, where processing also implies367	immediate failing; thus, if a sdev is in one of the two368	states, no further recovery action is needed.369 370	Device readiness is tested using scsi_eh_tur() which issues371	TEST_UNIT_READY command.  Note that the scmd must have been372	aborted successfully before reusing it for TEST_UNIT_READY.373 374    4. If !list_empty(&eh_work_q), invoke scsi_eh_ready_devs()375 376    ``scsi_eh_ready_devs``377 378	This function takes four increasingly more severe measures to379	make failed sdevs ready for new commands.380 381	1. Invoke scsi_eh_stu()382 383	``scsi_eh_stu``384 385	    For each sdev which has failed scmds with valid sense data386	    of which scsi_check_sense()'s verdict is FAILED,387	    START_STOP_UNIT command is issued w/ start=1.  Note that388	    as we explicitly choose error-completed scmds, it is known389	    that lower layers have forgotten about the scmd and we can390	    reuse it for STU.391 392	    If STU succeeds and the sdev is either offline or ready,393	    all failed scmds on the sdev are EH-finished with394	    scsi_eh_finish_cmd().395 396	    *NOTE* If hostt->eh_abort_handler() isn't implemented or397	    failed, we may still have timed out scmds at this point398	    and STU doesn't make lower layers forget about those399	    scmds.  Yet, this function EH-finish all scmds on the sdev400	    if STU succeeds leaving lower layers in an inconsistent401	    state.  It seems that STU action should be taken only when402	    a sdev has no timed out scmd.403 404	2. If !list_empty(&eh_work_q), invoke scsi_eh_bus_device_reset().405 406	``scsi_eh_bus_device_reset``407 408	    This action is very similar to scsi_eh_stu() except that,409	    instead of issuing STU, hostt->eh_device_reset_handler()410	    is used.  Also, as we're not issuing SCSI commands and411	    resetting clears all scmds on the sdev, there is no need412	    to choose error-completed scmds.413 414	3. If !list_empty(&eh_work_q), invoke scsi_eh_bus_reset()415 416	``scsi_eh_bus_reset``417 418	    hostt->eh_bus_reset_handler() is invoked for each channel419	    with failed scmds.  If bus reset succeeds, all failed420	    scmds on all ready or offline sdevs on the channel are421	    EH-finished.422 423	4. If !list_empty(&eh_work_q), invoke scsi_eh_host_reset()424 425	``scsi_eh_host_reset``426 427	    This is the last resort.  hostt->eh_host_reset_handler()428	    is invoked.  If host reset succeeds, all failed scmds on429	    all ready or offline sdevs on the host are EH-finished.430 431	5. If !list_empty(&eh_work_q), invoke scsi_eh_offline_sdevs()432 433	``scsi_eh_offline_sdevs``434 435	    Take all sdevs which still have unrecovered scmds offline436	    and EH-finish the scmds.437 438    5. Invoke scsi_eh_flush_done_q().439 440	``scsi_eh_flush_done_q``441 442	    At this point all scmds are recovered (or given up) and443	    put on eh_done_q by scsi_eh_finish_cmd().  This function444	    flushes eh_done_q by either retrying or notifying upper445	    layer of failure of the scmds.446 447 4482.2 EH through transportt->eh_strategy_handler()449------------------------------------------------450 451transportt->eh_strategy_handler() is invoked in the place of452scsi_unjam_host() and it is responsible for whole recovery process.453On completion, the handler should have made lower layers forget about454all failed scmds and either ready for new commands or offline.  Also,455it should perform SCSI EH maintenance chores to maintain integrity of456SCSI midlayer.  IOW, of the steps described in [2-1-2], all steps457except for #1 must be implemented by eh_strategy_handler().458 459 4602.2.1 Pre transportt->eh_strategy_handler() SCSI midlayer conditions461^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^462 463 The following conditions are true on entry to the handler.464 465 - Each failed scmd's eh_flags field is set appropriately.466 467 - Each failed scmd is linked on scmd->eh_cmd_q by scmd->eh_entry.468 469 - SHOST_RECOVERY is set.470 471 - shost->host_failed == shost->host_busy472 473 4742.2.2 Post transportt->eh_strategy_handler() SCSI midlayer conditions475^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^476 477 The following conditions must be true on exit from the handler.478 479 - shost->host_failed is zero.480 481 - Each scmd is in such a state that scsi_setup_cmd_retry() on the482   scmd doesn't make any difference.483 484 - shost->eh_cmd_q is cleared.485 486 - Each scmd->eh_entry is cleared.487 488 - Either scsi_queue_insert() or scsi_finish_command() is called on489   each scmd.  Note that the handler is free to use scmd->retries and490   ->allowed to limit the number of retries.491 492 4932.2.3 Things to consider494^^^^^^^^^^^^^^^^^^^^^^^^495 496 - Know that timed out scmds are still active on lower layers.  Make497   lower layers forget about them before doing anything else with498   those scmds.499 500 - For consistency, when accessing/modifying shost data structure,501   grab shost->host_lock.502 503 - On completion, each failed sdev must have forgotten about all504   active scmds.505 506 - On completion, each failed sdev must be ready for new commands or507   offline.508 509 510Tejun Heo511htejun@gmail.com512 51311th September 2005514