xref: /openbmc/linux/drivers/scsi/scsi_error.c (revision dee7121e8c0a3ce41af2b02d516f54eaec32abcd)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  scsi_error.c Copyright (C) 1997 Eric Youngdale
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  SCSI error/timeout handling
61da177e4SLinus Torvalds  *      Initial versions: Eric Youngdale.  Based upon conversations with
71da177e4SLinus Torvalds  *                        Leonard Zubkoff and David Miller at Linux Expo,
81da177e4SLinus Torvalds  *                        ideas originating from all over the place.
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  *	Restructured scsi_unjam_host and associated functions.
111da177e4SLinus Torvalds  *	September 04, 2002 Mike Anderson (andmike@us.ibm.com)
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  *	Forward port of Russell King's (rmk@arm.linux.org.uk) changes and
141da177e4SLinus Torvalds  *	minor cleanups.
151da177e4SLinus Torvalds  *	September 30, 2002 Mike Anderson (andmike@us.ibm.com)
161da177e4SLinus Torvalds  */
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds #include <linux/module.h>
191da177e4SLinus Torvalds #include <linux/sched.h>
205a0e3ad6STejun Heo #include <linux/gfp.h>
211da177e4SLinus Torvalds #include <linux/timer.h>
221da177e4SLinus Torvalds #include <linux/string.h>
231da177e4SLinus Torvalds #include <linux/kernel.h>
2483144186SRafael J. Wysocki #include <linux/freezer.h>
25c5478defSChristoph Hellwig #include <linux/kthread.h>
261da177e4SLinus Torvalds #include <linux/interrupt.h>
271da177e4SLinus Torvalds #include <linux/blkdev.h>
281da177e4SLinus Torvalds #include <linux/delay.h>
29fc73648aSHannes Reinecke #include <linux/jiffies.h>
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds #include <scsi/scsi.h>
32beb40487SChristoph Hellwig #include <scsi/scsi_cmnd.h>
331da177e4SLinus Torvalds #include <scsi/scsi_dbg.h>
341da177e4SLinus Torvalds #include <scsi/scsi_device.h>
3518a4d0a2SMartin K. Petersen #include <scsi/scsi_driver.h>
361da177e4SLinus Torvalds #include <scsi/scsi_eh.h>
377708c165SSagi Grimberg #include <scsi/scsi_common.h>
38c829c394SJames Smart #include <scsi/scsi_transport.h>
391da177e4SLinus Torvalds #include <scsi/scsi_host.h>
401da177e4SLinus Torvalds #include <scsi/scsi_ioctl.h>
41ee14c674SChristoph Hellwig #include <scsi/scsi_dh.h>
4229cfc2abSMartin Wilck #include <scsi/scsi_devinfo.h>
43176aa9d6SChristoph Hellwig #include <scsi/sg.h>
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds #include "scsi_priv.h"
461da177e4SLinus Torvalds #include "scsi_logging.h"
4779ee8304SAdrian Bunk #include "scsi_transport_api.h"
481da177e4SLinus Torvalds 
49bf816235SKei Tokunaga #include <trace/events/scsi.h>
50bf816235SKei Tokunaga 
512908769cSDamien Le Moal #include <asm/unaligned.h>
522908769cSDamien Le Moal 
531da177e4SLinus Torvalds /*
541da177e4SLinus Torvalds  * These should *probably* be handled by the host itself.
551da177e4SLinus Torvalds  * Since it is allowed to sleep, it probably should.
561da177e4SLinus Torvalds  */
571da177e4SLinus Torvalds #define BUS_RESET_SETTLE_TIME   (10)
581da177e4SLinus Torvalds #define HOST_RESET_SETTLE_TIME  (10)
591da177e4SLinus Torvalds 
603eef6257SDavid Jeffery static int scsi_eh_try_stu(struct scsi_cmnd *scmd);
61b8e162f9SBart Van Assche static enum scsi_disposition scsi_try_to_abort_cmd(struct scsi_host_template *,
62e494f6a7SHannes Reinecke 						   struct scsi_cmnd *);
633eef6257SDavid Jeffery 
641da177e4SLinus Torvalds void scsi_eh_wakeup(struct Scsi_Host *shost)
651da177e4SLinus Torvalds {
66f0317e88SBart Van Assche 	lockdep_assert_held(shost->host_lock);
67f0317e88SBart Van Assche 
68c84b023aSMing Lei 	if (scsi_host_busy(shost) == shost->host_failed) {
69bf816235SKei Tokunaga 		trace_scsi_eh_wakeup(shost);
703ed7a470SJames Bottomley 		wake_up_process(shost->ehandler);
7191921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(5, shost_printk(KERN_INFO, shost,
7291921e01SHannes Reinecke 			"Waking error handler thread\n"));
731da177e4SLinus Torvalds 	}
741da177e4SLinus Torvalds }
75f8bbfc24STejun Heo 
76f8bbfc24STejun Heo /**
77f8bbfc24STejun Heo  * scsi_schedule_eh - schedule EH for SCSI host
78f8bbfc24STejun Heo  * @shost:	SCSI host to invoke error handling on.
79f8bbfc24STejun Heo  *
80f8bbfc24STejun Heo  * Schedule SCSI EH without scmd.
81dc8875e1SRandy Dunlap  */
82f8bbfc24STejun Heo void scsi_schedule_eh(struct Scsi_Host *shost)
83f8bbfc24STejun Heo {
84f8bbfc24STejun Heo 	unsigned long flags;
85f8bbfc24STejun Heo 
86f8bbfc24STejun Heo 	spin_lock_irqsave(shost->host_lock, flags);
87f8bbfc24STejun Heo 
88f8bbfc24STejun Heo 	if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 ||
89f8bbfc24STejun Heo 	    scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) {
90f8bbfc24STejun Heo 		shost->host_eh_scheduled++;
91f8bbfc24STejun Heo 		scsi_eh_wakeup(shost);
92f8bbfc24STejun Heo 	}
93f8bbfc24STejun Heo 
94f8bbfc24STejun Heo 	spin_unlock_irqrestore(shost->host_lock, flags);
95f8bbfc24STejun Heo }
96f8bbfc24STejun Heo EXPORT_SYMBOL_GPL(scsi_schedule_eh);
971da177e4SLinus Torvalds 
98b4562022SHannes Reinecke static int scsi_host_eh_past_deadline(struct Scsi_Host *shost)
99b4562022SHannes Reinecke {
100bb3b621aSRen Mingxin 	if (!shost->last_reset || shost->eh_deadline == -1)
101b4562022SHannes Reinecke 		return 0;
102b4562022SHannes Reinecke 
10376ad3e59SHannes Reinecke 	/*
10476ad3e59SHannes Reinecke 	 * 32bit accesses are guaranteed to be atomic
10576ad3e59SHannes Reinecke 	 * (on all supported architectures), so instead
10676ad3e59SHannes Reinecke 	 * of using a spinlock we can as well double check
107bb3b621aSRen Mingxin 	 * if eh_deadline has been set to 'off' during the
10876ad3e59SHannes Reinecke 	 * time_before call.
10976ad3e59SHannes Reinecke 	 */
11076ad3e59SHannes Reinecke 	if (time_before(jiffies, shost->last_reset + shost->eh_deadline) &&
111bb3b621aSRen Mingxin 	    shost->eh_deadline > -1)
112b4562022SHannes Reinecke 		return 0;
113b4562022SHannes Reinecke 
114b4562022SHannes Reinecke 	return 1;
115b4562022SHannes Reinecke }
116b4562022SHannes Reinecke 
1172a242d59SMike Christie static bool scsi_cmd_retry_allowed(struct scsi_cmnd *cmd)
1182a242d59SMike Christie {
1192a242d59SMike Christie 	if (cmd->allowed == SCSI_CMD_RETRIES_NO_LIMIT)
1202a242d59SMike Christie 		return true;
1212a242d59SMike Christie 
1222a242d59SMike Christie 	return ++cmd->retries <= cmd->allowed;
1232a242d59SMike Christie }
1242a242d59SMike Christie 
12560bee27bSMuneendra Kumar static bool scsi_eh_should_retry_cmd(struct scsi_cmnd *cmd)
12660bee27bSMuneendra Kumar {
12760bee27bSMuneendra Kumar 	struct scsi_device *sdev = cmd->device;
12860bee27bSMuneendra Kumar 	struct Scsi_Host *host = sdev->host;
12960bee27bSMuneendra Kumar 
13060bee27bSMuneendra Kumar 	if (host->hostt->eh_should_retry_cmd)
13160bee27bSMuneendra Kumar 		return  host->hostt->eh_should_retry_cmd(cmd);
13260bee27bSMuneendra Kumar 
13360bee27bSMuneendra Kumar 	return true;
13460bee27bSMuneendra Kumar }
13560bee27bSMuneendra Kumar 
1361da177e4SLinus Torvalds /**
137e494f6a7SHannes Reinecke  * scmd_eh_abort_handler - Handle command aborts
138e494f6a7SHannes Reinecke  * @work:	command to be aborted.
139923f46f9SBart Van Assche  *
140923f46f9SBart Van Assche  * Note: this function must be called only for a command that has timed out.
141923f46f9SBart Van Assche  * Because the block layer marks a request as complete before it calls
142deef1be1SJohn Garry  * scsi_timeout(), a .scsi_done() call from the LLD for a command that has
143923f46f9SBart Van Assche  * timed out do not have any effect. Hence it is safe to call
144923f46f9SBart Van Assche  * scsi_finish_command() from this function.
145e494f6a7SHannes Reinecke  */
146e494f6a7SHannes Reinecke void
147e494f6a7SHannes Reinecke scmd_eh_abort_handler(struct work_struct *work)
148e494f6a7SHannes Reinecke {
149e494f6a7SHannes Reinecke 	struct scsi_cmnd *scmd =
150e494f6a7SHannes Reinecke 		container_of(work, struct scsi_cmnd, abort_work.work);
151e494f6a7SHannes Reinecke 	struct scsi_device *sdev = scmd->device;
15254d816d3SEwan D. Milne 	struct Scsi_Host *shost = sdev->host;
153b8e162f9SBart Van Assche 	enum scsi_disposition rtn;
1545ae17501SEwan D. Milne 	unsigned long flags;
155e494f6a7SHannes Reinecke 
15654d816d3SEwan D. Milne 	if (scsi_host_eh_past_deadline(shost)) {
157e494f6a7SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
158e494f6a7SHannes Reinecke 			scmd_printk(KERN_INFO, scmd,
159470613b4SHannes Reinecke 				    "eh timeout, not aborting\n"));
16054d816d3SEwan D. Milne 		goto out;
16154d816d3SEwan D. Milne 	}
16254d816d3SEwan D. Milne 
163e494f6a7SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3,
164e494f6a7SHannes Reinecke 			scmd_printk(KERN_INFO, scmd,
165470613b4SHannes Reinecke 				    "aborting command\n"));
16654d816d3SEwan D. Milne 	rtn = scsi_try_to_abort_cmd(shost->hostt, scmd);
16754d816d3SEwan D. Milne 	if (rtn != SUCCESS) {
168e494f6a7SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
169e494f6a7SHannes Reinecke 			scmd_printk(KERN_INFO, scmd,
170470613b4SHannes Reinecke 				    "cmd abort %s\n",
171883a030fSHannes Reinecke 				    (rtn == FAST_IO_FAIL) ?
172883a030fSHannes Reinecke 				    "not send" : "failed"));
17354d816d3SEwan D. Milne 		goto out;
174e494f6a7SHannes Reinecke 	}
17554d816d3SEwan D. Milne 	set_host_byte(scmd, DID_TIME_OUT);
17654d816d3SEwan D. Milne 	if (scsi_host_eh_past_deadline(shost)) {
17754d816d3SEwan D. Milne 		SCSI_LOG_ERROR_RECOVERY(3,
17854d816d3SEwan D. Milne 			scmd_printk(KERN_INFO, scmd,
17954d816d3SEwan D. Milne 				    "eh timeout, not retrying "
18054d816d3SEwan D. Milne 				    "aborted command\n"));
18154d816d3SEwan D. Milne 		goto out;
182bb3b621aSRen Mingxin 	}
183e494f6a7SHannes Reinecke 
18454d816d3SEwan D. Milne 	spin_lock_irqsave(shost->host_lock, flags);
1855ae17501SEwan D. Milne 	list_del_init(&scmd->eh_entry);
18654d816d3SEwan D. Milne 
18754d816d3SEwan D. Milne 	/*
18854d816d3SEwan D. Milne 	 * If the abort succeeds, and there is no further
18954d816d3SEwan D. Milne 	 * EH action, clear the ->last_reset time.
19054d816d3SEwan D. Milne 	 */
19154d816d3SEwan D. Milne 	if (list_empty(&shost->eh_abort_list) &&
19254d816d3SEwan D. Milne 	    list_empty(&shost->eh_cmd_q))
19354d816d3SEwan D. Milne 		if (shost->eh_deadline != -1)
19454d816d3SEwan D. Milne 			shost->last_reset = 0;
19554d816d3SEwan D. Milne 
19654d816d3SEwan D. Milne 	spin_unlock_irqrestore(shost->host_lock, flags);
19754d816d3SEwan D. Milne 
19854d816d3SEwan D. Milne 	if (!scsi_noretry_cmd(scmd) &&
19954d816d3SEwan D. Milne 	    scsi_cmd_retry_allowed(scmd) &&
20054d816d3SEwan D. Milne 	    scsi_eh_should_retry_cmd(scmd)) {
20154d816d3SEwan D. Milne 		SCSI_LOG_ERROR_RECOVERY(3,
20254d816d3SEwan D. Milne 			scmd_printk(KERN_WARNING, scmd,
20354d816d3SEwan D. Milne 				    "retry aborted command\n"));
20454d816d3SEwan D. Milne 		scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
20554d816d3SEwan D. Milne 	} else {
20654d816d3SEwan D. Milne 		SCSI_LOG_ERROR_RECOVERY(3,
20754d816d3SEwan D. Milne 			scmd_printk(KERN_WARNING, scmd,
20854d816d3SEwan D. Milne 				    "finish aborted command\n"));
20954d816d3SEwan D. Milne 		scsi_finish_command(scmd);
21054d816d3SEwan D. Milne 	}
21154d816d3SEwan D. Milne 	return;
21254d816d3SEwan D. Milne 
21354d816d3SEwan D. Milne out:
21454d816d3SEwan D. Milne 	spin_lock_irqsave(shost->host_lock, flags);
21554d816d3SEwan D. Milne 	list_del_init(&scmd->eh_entry);
21654d816d3SEwan D. Milne 	spin_unlock_irqrestore(shost->host_lock, flags);
21754d816d3SEwan D. Milne 
218a0658632SHannes Reinecke 	scsi_eh_scmd_add(scmd);
219e494f6a7SHannes Reinecke }
220e494f6a7SHannes Reinecke 
221e494f6a7SHannes Reinecke /**
222e494f6a7SHannes Reinecke  * scsi_abort_command - schedule a command abort
223e494f6a7SHannes Reinecke  * @scmd:	scmd to abort.
224e494f6a7SHannes Reinecke  *
225e494f6a7SHannes Reinecke  * We only need to abort commands after a command timeout
226e494f6a7SHannes Reinecke  */
227e494f6a7SHannes Reinecke static int
228e494f6a7SHannes Reinecke scsi_abort_command(struct scsi_cmnd *scmd)
229e494f6a7SHannes Reinecke {
230e494f6a7SHannes Reinecke 	struct scsi_device *sdev = scmd->device;
231e494f6a7SHannes Reinecke 	struct Scsi_Host *shost = sdev->host;
232e494f6a7SHannes Reinecke 	unsigned long flags;
233e494f6a7SHannes Reinecke 
234e494f6a7SHannes Reinecke 	if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) {
235e494f6a7SHannes Reinecke 		/*
236e494f6a7SHannes Reinecke 		 * Retry after abort failed, escalate to next level.
237e494f6a7SHannes Reinecke 		 */
238e494f6a7SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
239e494f6a7SHannes Reinecke 			scmd_printk(KERN_INFO, scmd,
240470613b4SHannes Reinecke 				    "previous abort failed\n"));
241fcc95a76SBart Van Assche 		BUG_ON(delayed_work_pending(&scmd->abort_work));
242e494f6a7SHannes Reinecke 		return FAILED;
243e494f6a7SHannes Reinecke 	}
244e494f6a7SHannes Reinecke 
245e494f6a7SHannes Reinecke 	spin_lock_irqsave(shost->host_lock, flags);
246bb3b621aSRen Mingxin 	if (shost->eh_deadline != -1 && !shost->last_reset)
247e494f6a7SHannes Reinecke 		shost->last_reset = jiffies;
2485ae17501SEwan D. Milne 	BUG_ON(!list_empty(&scmd->eh_entry));
2495ae17501SEwan D. Milne 	list_add_tail(&scmd->eh_entry, &shost->eh_abort_list);
250e494f6a7SHannes Reinecke 	spin_unlock_irqrestore(shost->host_lock, flags);
251e494f6a7SHannes Reinecke 
252e494f6a7SHannes Reinecke 	scmd->eh_eflags |= SCSI_EH_ABORT_SCHEDULED;
253e494f6a7SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3,
254470613b4SHannes Reinecke 		scmd_printk(KERN_INFO, scmd, "abort scheduled\n"));
255e494f6a7SHannes Reinecke 	queue_delayed_work(shost->tmf_work_q, &scmd->abort_work, HZ / 100);
256e494f6a7SHannes Reinecke 	return SUCCESS;
257e494f6a7SHannes Reinecke }
258e494f6a7SHannes Reinecke 
259e494f6a7SHannes Reinecke /**
2607a38dc0bSHannes Reinecke  * scsi_eh_reset - call into ->eh_action to reset internal counters
2617a38dc0bSHannes Reinecke  * @scmd:	scmd to run eh on.
2627a38dc0bSHannes Reinecke  *
2637a38dc0bSHannes Reinecke  * The scsi driver might be carrying internal state about the
2647a38dc0bSHannes Reinecke  * devices, so we need to call into the driver to reset the
2657a38dc0bSHannes Reinecke  * internal state once the error handler is started.
2667a38dc0bSHannes Reinecke  */
2677a38dc0bSHannes Reinecke static void scsi_eh_reset(struct scsi_cmnd *scmd)
2687a38dc0bSHannes Reinecke {
269aa8e25e5SBart Van Assche 	if (!blk_rq_is_passthrough(scsi_cmd_to_rq(scmd))) {
2707a38dc0bSHannes Reinecke 		struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd);
2717a38dc0bSHannes Reinecke 		if (sdrv->eh_reset)
2727a38dc0bSHannes Reinecke 			sdrv->eh_reset(scmd);
2737a38dc0bSHannes Reinecke 	}
2747a38dc0bSHannes Reinecke }
2757a38dc0bSHannes Reinecke 
2763bd6f43fSBart Van Assche static void scsi_eh_inc_host_failed(struct rcu_head *head)
2773bd6f43fSBart Van Assche {
2783be8828fSBart Van Assche 	struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu);
2793be8828fSBart Van Assche 	struct Scsi_Host *shost = scmd->device->host;
2803bd6f43fSBart Van Assche 	unsigned long flags;
2813bd6f43fSBart Van Assche 
2823bd6f43fSBart Van Assche 	spin_lock_irqsave(shost->host_lock, flags);
2833bd6f43fSBart Van Assche 	shost->host_failed++;
2843bd6f43fSBart Van Assche 	scsi_eh_wakeup(shost);
2853bd6f43fSBart Van Assche 	spin_unlock_irqrestore(shost->host_lock, flags);
2863bd6f43fSBart Van Assche }
2873bd6f43fSBart Van Assche 
2887a38dc0bSHannes Reinecke /**
2891da177e4SLinus Torvalds  * scsi_eh_scmd_add - add scsi cmd to error handling.
2901da177e4SLinus Torvalds  * @scmd:	scmd to run eh on.
291dc8875e1SRandy Dunlap  */
292a0658632SHannes Reinecke void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
2931da177e4SLinus Torvalds {
2941da177e4SLinus Torvalds 	struct Scsi_Host *shost = scmd->device->host;
2951da177e4SLinus Torvalds 	unsigned long flags;
2962171b6d0SHannes Reinecke 	int ret;
2971da177e4SLinus Torvalds 
2982171b6d0SHannes Reinecke 	WARN_ON_ONCE(!shost->ehandler);
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 	spin_lock_irqsave(shost->host_lock, flags);
3012171b6d0SHannes Reinecke 	if (scsi_host_set_state(shost, SHOST_RECOVERY)) {
3022171b6d0SHannes Reinecke 		ret = scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY);
3032171b6d0SHannes Reinecke 		WARN_ON_ONCE(ret);
3042171b6d0SHannes Reinecke 	}
305bb3b621aSRen Mingxin 	if (shost->eh_deadline != -1 && !shost->last_reset)
306b4562022SHannes Reinecke 		shost->last_reset = jiffies;
307b4562022SHannes Reinecke 
3087a38dc0bSHannes Reinecke 	scsi_eh_reset(scmd);
3091da177e4SLinus Torvalds 	list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
3101da177e4SLinus Torvalds 	spin_unlock_irqrestore(shost->host_lock, flags);
3113bd6f43fSBart Van Assche 	/*
3123bd6f43fSBart Van Assche 	 * Ensure that all tasks observe the host state change before the
3133bd6f43fSBart Van Assche 	 * host_failed change.
3143bd6f43fSBart Van Assche 	 */
3153be8828fSBart Van Assche 	call_rcu(&scmd->rcu, scsi_eh_inc_host_failed);
3161da177e4SLinus Torvalds }
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds /**
319deef1be1SJohn Garry  * scsi_timeout - Timeout function for normal scsi commands.
320242f9dcbSJens Axboe  * @req:	request that is timing out.
3211da177e4SLinus Torvalds  *
3221da177e4SLinus Torvalds  * Notes:
3231da177e4SLinus Torvalds  *     We do not need to lock this.  There is the potential for a race
3241da177e4SLinus Torvalds  *     only in that the normal completion handling might run, but if the
3251da177e4SLinus Torvalds  *     normal completion function determines that the timer has already
3261da177e4SLinus Torvalds  *     fired, then it mustn't do anything.
327dc8875e1SRandy Dunlap  */
3289bdb4833SJohn Garry enum blk_eh_timer_return scsi_timeout(struct request *req)
3291da177e4SLinus Torvalds {
330bed2213dSBart Van Assche 	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req);
3310bf8c869SJesper Juhl 	struct Scsi_Host *host = scmd->device->host;
3326c5f8ce1SJames Bottomley 
333bf816235SKei Tokunaga 	trace_scsi_dispatch_cmd_timeout(scmd);
3341da177e4SLinus Torvalds 	scsi_log_completion(scmd, TIMEOUT_ERROR);
3351da177e4SLinus Torvalds 
33648517eefSWu Bo 	atomic_inc(&scmd->device->iotmo_cnt);
337bb3b621aSRen Mingxin 	if (host->eh_deadline != -1 && !host->last_reset)
338b4562022SHannes Reinecke 		host->last_reset = jiffies;
339b4562022SHannes Reinecke 
340*dee7121eSBart Van Assche 	if (host->hostt->eh_timed_out) {
341*dee7121eSBart Van Assche 		switch (host->hostt->eh_timed_out(scmd)) {
342*dee7121eSBart Van Assche 		case SCSI_EH_DONE:
343*dee7121eSBart Van Assche 			return BLK_EH_DONE;
344*dee7121eSBart Van Assche 		case SCSI_EH_RESET_TIMER:
345*dee7121eSBart Van Assche 			return BLK_EH_RESET_TIMER;
346*dee7121eSBart Van Assche 		case SCSI_EH_NOT_HANDLED:
347*dee7121eSBart Van Assche 			break;
348*dee7121eSBart Van Assche 		}
349*dee7121eSBart Van Assche 	}
3506c5f8ce1SJames Bottomley 
351065990bdSKeith Busch 	/*
352*dee7121eSBart Van Assche 	 * If scsi_done() has already set SCMD_STATE_COMPLETE, do not modify
353*dee7121eSBart Van Assche 	 * *scmd.
354065990bdSKeith Busch 	 */
355f1342709SKeith Busch 	if (test_and_set_bit(SCMD_STATE_COMPLETE, &scmd->state))
356978b7922SBart Van Assche 		return BLK_EH_DONE;
357a0658632SHannes Reinecke 	if (scsi_abort_command(scmd) != SUCCESS) {
3588922a908SUlrich Obergfell 		set_host_byte(scmd, DID_TIME_OUT);
359a0658632SHannes Reinecke 		scsi_eh_scmd_add(scmd);
3602171b6d0SHannes Reinecke 	}
361242f9dcbSJens Axboe 
362*dee7121eSBart Van Assche 	return BLK_EH_DONE;
3631da177e4SLinus Torvalds }
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds /**
3661da177e4SLinus Torvalds  * scsi_block_when_processing_errors - Prevent cmds from being queued.
3671da177e4SLinus Torvalds  * @sdev:	Device on which we are performing recovery.
3681da177e4SLinus Torvalds  *
3691da177e4SLinus Torvalds  * Description:
3701da177e4SLinus Torvalds  *     We block until the host is out of error recovery, and then check to
3711da177e4SLinus Torvalds  *     see whether the host or the device is offline.
3721da177e4SLinus Torvalds  *
3731da177e4SLinus Torvalds  * Return value:
3741da177e4SLinus Torvalds  *     0 when dev was taken offline by error recovery. 1 OK to proceed.
375dc8875e1SRandy Dunlap  */
3761da177e4SLinus Torvalds int scsi_block_when_processing_errors(struct scsi_device *sdev)
3771da177e4SLinus Torvalds {
3781da177e4SLinus Torvalds 	int online;
3791da177e4SLinus Torvalds 
380939647eeSJames Bottomley 	wait_event(sdev->host->host_wait, !scsi_host_in_recovery(sdev->host));
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	online = scsi_device_online(sdev);
3831da177e4SLinus Torvalds 
3841da177e4SLinus Torvalds 	return online;
3851da177e4SLinus Torvalds }
3861da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_block_when_processing_errors);
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds #ifdef CONFIG_SCSI_LOGGING
3891da177e4SLinus Torvalds /**
3901da177e4SLinus Torvalds  * scsi_eh_prt_fail_stats - Log info on failures.
3911da177e4SLinus Torvalds  * @shost:	scsi host being recovered.
3921da177e4SLinus Torvalds  * @work_q:	Queue of scsi cmds to process.
393dc8875e1SRandy Dunlap  */
3941da177e4SLinus Torvalds static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
3951da177e4SLinus Torvalds 					  struct list_head *work_q)
3961da177e4SLinus Torvalds {
3971da177e4SLinus Torvalds 	struct scsi_cmnd *scmd;
3981da177e4SLinus Torvalds 	struct scsi_device *sdev;
3991da177e4SLinus Torvalds 	int total_failures = 0;
4001da177e4SLinus Torvalds 	int cmd_failed = 0;
4011da177e4SLinus Torvalds 	int cmd_cancel = 0;
4021da177e4SLinus Torvalds 	int devices_failed = 0;
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds 	shost_for_each_device(sdev, shost) {
4051da177e4SLinus Torvalds 		list_for_each_entry(scmd, work_q, eh_entry) {
4061da177e4SLinus Torvalds 			if (scmd->device == sdev) {
4071da177e4SLinus Torvalds 				++total_failures;
408a0658632SHannes Reinecke 				if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED)
4091da177e4SLinus Torvalds 					++cmd_cancel;
4101da177e4SLinus Torvalds 				else
4111da177e4SLinus Torvalds 					++cmd_failed;
4121da177e4SLinus Torvalds 			}
4131da177e4SLinus Torvalds 		}
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds 		if (cmd_cancel || cmd_failed) {
4161da177e4SLinus Torvalds 			SCSI_LOG_ERROR_RECOVERY(3,
417a3a790dcSHannes Reinecke 				shost_printk(KERN_INFO, shost,
4189ccfc756SJames Bottomley 					    "%s: cmds failed: %d, cancel: %d\n",
419cadbd4a5SHarvey Harrison 					    __func__, cmd_failed,
4209ccfc756SJames Bottomley 					    cmd_cancel));
4211da177e4SLinus Torvalds 			cmd_cancel = 0;
4221da177e4SLinus Torvalds 			cmd_failed = 0;
4231da177e4SLinus Torvalds 			++devices_failed;
4241da177e4SLinus Torvalds 		}
4251da177e4SLinus Torvalds 	}
4261da177e4SLinus Torvalds 
42791921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(2, shost_printk(KERN_INFO, shost,
42891921e01SHannes Reinecke 				   "Total of %d commands on %d"
4291da177e4SLinus Torvalds 				   " devices require eh work\n",
4301da177e4SLinus Torvalds 				   total_failures, devices_failed));
4311da177e4SLinus Torvalds }
4321da177e4SLinus Torvalds #endif
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds  /**
435279afdfeSEwan D. Milne  * scsi_report_lun_change - Set flag on all *other* devices on the same target
436279afdfeSEwan D. Milne  *                          to indicate that a UNIT ATTENTION is expected.
437279afdfeSEwan D. Milne  * @sdev:	Device reporting the UNIT ATTENTION
438279afdfeSEwan D. Milne  */
439279afdfeSEwan D. Milne static void scsi_report_lun_change(struct scsi_device *sdev)
440279afdfeSEwan D. Milne {
441279afdfeSEwan D. Milne 	sdev->sdev_target->expecting_lun_change = 1;
442279afdfeSEwan D. Milne }
443279afdfeSEwan D. Milne 
444279afdfeSEwan D. Milne /**
445279afdfeSEwan D. Milne  * scsi_report_sense - Examine scsi sense information and log messages for
446279afdfeSEwan D. Milne  *		       certain conditions, also issue uevents for some of them.
447279afdfeSEwan D. Milne  * @sdev:	Device reporting the sense code
448279afdfeSEwan D. Milne  * @sshdr:	sshdr to be examined
449279afdfeSEwan D. Milne  */
450279afdfeSEwan D. Milne static void scsi_report_sense(struct scsi_device *sdev,
451279afdfeSEwan D. Milne 			      struct scsi_sense_hdr *sshdr)
452279afdfeSEwan D. Milne {
453279afdfeSEwan D. Milne 	enum scsi_device_event evt_type = SDEV_EVT_MAXBITS;	/* i.e. none */
454279afdfeSEwan D. Milne 
455279afdfeSEwan D. Milne 	if (sshdr->sense_key == UNIT_ATTENTION) {
456279afdfeSEwan D. Milne 		if (sshdr->asc == 0x3f && sshdr->ascq == 0x03) {
457279afdfeSEwan D. Milne 			evt_type = SDEV_EVT_INQUIRY_CHANGE_REPORTED;
458279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
459279afdfeSEwan D. Milne 				    "Inquiry data has changed");
460279afdfeSEwan D. Milne 		} else if (sshdr->asc == 0x3f && sshdr->ascq == 0x0e) {
461279afdfeSEwan D. Milne 			evt_type = SDEV_EVT_LUN_CHANGE_REPORTED;
462279afdfeSEwan D. Milne 			scsi_report_lun_change(sdev);
463279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
464279afdfeSEwan D. Milne 				    "LUN assignments on this target have "
465279afdfeSEwan D. Milne 				    "changed. The Linux SCSI layer does not "
466279afdfeSEwan D. Milne 				    "automatically remap LUN assignments.\n");
467279afdfeSEwan D. Milne 		} else if (sshdr->asc == 0x3f)
468279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
469a2417db3SLi Zhijian 				    "Operating parameters on this target have "
470279afdfeSEwan D. Milne 				    "changed. The Linux SCSI layer does not "
471279afdfeSEwan D. Milne 				    "automatically adjust these parameters.\n");
472279afdfeSEwan D. Milne 
473279afdfeSEwan D. Milne 		if (sshdr->asc == 0x38 && sshdr->ascq == 0x07) {
474279afdfeSEwan D. Milne 			evt_type = SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED;
475279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
476279afdfeSEwan D. Milne 				    "Warning! Received an indication that the "
477279afdfeSEwan D. Milne 				    "LUN reached a thin provisioning soft "
478279afdfeSEwan D. Milne 				    "threshold.\n");
479279afdfeSEwan D. Milne 		}
480279afdfeSEwan D. Milne 
481cf3431bbSHannes Reinecke 		if (sshdr->asc == 0x29) {
482cf3431bbSHannes Reinecke 			evt_type = SDEV_EVT_POWER_ON_RESET_OCCURRED;
483af4edb1dSAdrian Hunter 			/*
484af4edb1dSAdrian Hunter 			 * Do not print message if it is an expected side-effect
485af4edb1dSAdrian Hunter 			 * of runtime PM.
486af4edb1dSAdrian Hunter 			 */
487af4edb1dSAdrian Hunter 			if (!sdev->silence_suspend)
488cf3431bbSHannes Reinecke 				sdev_printk(KERN_WARNING, sdev,
489cf3431bbSHannes Reinecke 					    "Power-on or device reset occurred\n");
490cf3431bbSHannes Reinecke 		}
491cf3431bbSHannes Reinecke 
492279afdfeSEwan D. Milne 		if (sshdr->asc == 0x2a && sshdr->ascq == 0x01) {
493279afdfeSEwan D. Milne 			evt_type = SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED;
494279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
495279afdfeSEwan D. Milne 				    "Mode parameters changed");
49614c3e677SHannes Reinecke 		} else if (sshdr->asc == 0x2a && sshdr->ascq == 0x06) {
49714c3e677SHannes Reinecke 			evt_type = SDEV_EVT_ALUA_STATE_CHANGE_REPORTED;
49814c3e677SHannes Reinecke 			sdev_printk(KERN_WARNING, sdev,
49914c3e677SHannes Reinecke 				    "Asymmetric access state changed");
500279afdfeSEwan D. Milne 		} else if (sshdr->asc == 0x2a && sshdr->ascq == 0x09) {
501279afdfeSEwan D. Milne 			evt_type = SDEV_EVT_CAPACITY_CHANGE_REPORTED;
502279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
503279afdfeSEwan D. Milne 				    "Capacity data has changed");
504279afdfeSEwan D. Milne 		} else if (sshdr->asc == 0x2a)
505279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
506279afdfeSEwan D. Milne 				    "Parameters changed");
507279afdfeSEwan D. Milne 	}
508279afdfeSEwan D. Milne 
509279afdfeSEwan D. Milne 	if (evt_type != SDEV_EVT_MAXBITS) {
510279afdfeSEwan D. Milne 		set_bit(evt_type, sdev->pending_events);
511279afdfeSEwan D. Milne 		schedule_work(&sdev->event_work);
512279afdfeSEwan D. Milne 	}
513279afdfeSEwan D. Milne }
514279afdfeSEwan D. Milne 
51536ebf1e2SMike Christie static inline void set_scsi_ml_byte(struct scsi_cmnd *cmd, u8 status)
51636ebf1e2SMike Christie {
51736ebf1e2SMike Christie 	cmd->result = (cmd->result & 0xffff00ff) | (status << 8);
51836ebf1e2SMike Christie }
51936ebf1e2SMike Christie 
520279afdfeSEwan D. Milne /**
5211da177e4SLinus Torvalds  * scsi_check_sense - Examine scsi cmd sense
5221da177e4SLinus Torvalds  * @scmd:	Cmd to have sense checked.
5231da177e4SLinus Torvalds  *
5241da177e4SLinus Torvalds  * Return value:
52587f14e65SHannes Reinecke  *	SUCCESS or FAILED or NEEDS_RETRY or ADD_TO_MLQUEUE
5261da177e4SLinus Torvalds  *
5271da177e4SLinus Torvalds  * Notes:
5281da177e4SLinus Torvalds  *	When a deferred error is detected the current command has
5291da177e4SLinus Torvalds  *	not been executed and needs retrying.
530dc8875e1SRandy Dunlap  */
531b8e162f9SBart Van Assche enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
5321da177e4SLinus Torvalds {
533a6a8d9f8SChandra Seetharaman 	struct scsi_device *sdev = scmd->device;
5341da177e4SLinus Torvalds 	struct scsi_sense_hdr sshdr;
5351da177e4SLinus Torvalds 
5361da177e4SLinus Torvalds 	if (! scsi_command_normalize_sense(scmd, &sshdr))
5371da177e4SLinus Torvalds 		return FAILED;	/* no valid sense data */
5381da177e4SLinus Torvalds 
539279afdfeSEwan D. Milne 	scsi_report_sense(sdev, &sshdr);
540279afdfeSEwan D. Milne 
5411da177e4SLinus Torvalds 	if (scsi_sense_is_deferred(&sshdr))
5421da177e4SLinus Torvalds 		return NEEDS_RETRY;
5431da177e4SLinus Torvalds 
544ee14c674SChristoph Hellwig 	if (sdev->handler && sdev->handler->check_sense) {
545b8e162f9SBart Van Assche 		enum scsi_disposition rc;
546a6a8d9f8SChandra Seetharaman 
547ee14c674SChristoph Hellwig 		rc = sdev->handler->check_sense(sdev, &sshdr);
548a6a8d9f8SChandra Seetharaman 		if (rc != SCSI_RETURN_NOT_HANDLED)
549a6a8d9f8SChandra Seetharaman 			return rc;
550a6a8d9f8SChandra Seetharaman 		/* handler does not care. Drop down to default handling */
551a6a8d9f8SChandra Seetharaman 	}
552a6a8d9f8SChandra Seetharaman 
553bf23e619SBart Van Assche 	if (scmd->cmnd[0] == TEST_UNIT_READY &&
554bf23e619SBart Van Assche 	    scmd->submitter != SUBMITTED_BY_SCSI_ERROR_HANDLER)
555e925cc43SChristoph Hellwig 		/*
556e925cc43SChristoph Hellwig 		 * nasty: for mid-layer issued TURs, we need to return the
557e925cc43SChristoph Hellwig 		 * actual sense data without any recovery attempt.  For eh
558e925cc43SChristoph Hellwig 		 * issued ones, we need to try to recover and interpret
559e925cc43SChristoph Hellwig 		 */
560e925cc43SChristoph Hellwig 		return SUCCESS;
561e925cc43SChristoph Hellwig 
5621da177e4SLinus Torvalds 	/*
5631da177e4SLinus Torvalds 	 * Previous logic looked for FILEMARK, EOM or ILI which are
5641da177e4SLinus Torvalds 	 * mainly associated with tapes and returned SUCCESS.
5651da177e4SLinus Torvalds 	 */
5661da177e4SLinus Torvalds 	if (sshdr.response_code == 0x70) {
5671da177e4SLinus Torvalds 		/* fixed format */
5681da177e4SLinus Torvalds 		if (scmd->sense_buffer[2] & 0xe0)
5691da177e4SLinus Torvalds 			return SUCCESS;
5701da177e4SLinus Torvalds 	} else {
5711da177e4SLinus Torvalds 		/*
5721da177e4SLinus Torvalds 		 * descriptor format: look for "stream commands sense data
5731da177e4SLinus Torvalds 		 * descriptor" (see SSC-3). Assume single sense data
5741da177e4SLinus Torvalds 		 * descriptor. Ignore ILI from SBC-2 READ LONG and WRITE LONG.
5751da177e4SLinus Torvalds 		 */
5761da177e4SLinus Torvalds 		if ((sshdr.additional_length > 3) &&
5771da177e4SLinus Torvalds 		    (scmd->sense_buffer[8] == 0x4) &&
5781da177e4SLinus Torvalds 		    (scmd->sense_buffer[11] & 0xe0))
5791da177e4SLinus Torvalds 			return SUCCESS;
5801da177e4SLinus Torvalds 	}
5811da177e4SLinus Torvalds 
5821da177e4SLinus Torvalds 	switch (sshdr.sense_key) {
5831da177e4SLinus Torvalds 	case NO_SENSE:
5841da177e4SLinus Torvalds 		return SUCCESS;
5851da177e4SLinus Torvalds 	case RECOVERED_ERROR:
5861da177e4SLinus Torvalds 		return /* soft_error */ SUCCESS;
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds 	case ABORTED_COMMAND:
589511e44f4SMartin K. Petersen 		if (sshdr.asc == 0x10) /* DIF */
590511e44f4SMartin K. Petersen 			return SUCCESS;
591511e44f4SMartin K. Petersen 
59229cfc2abSMartin Wilck 		if (sshdr.asc == 0x44 && sdev->sdev_bflags & BLIST_RETRY_ITF)
59329cfc2abSMartin Wilck 			return ADD_TO_MLQUEUE;
594c3606520SMartin Wilck 		if (sshdr.asc == 0xc1 && sshdr.ascq == 0x01 &&
595c3606520SMartin Wilck 		    sdev->sdev_bflags & BLIST_RETRY_ASC_C1)
596c3606520SMartin Wilck 			return ADD_TO_MLQUEUE;
59729cfc2abSMartin Wilck 
5981da177e4SLinus Torvalds 		return NEEDS_RETRY;
5991da177e4SLinus Torvalds 	case NOT_READY:
6001da177e4SLinus Torvalds 	case UNIT_ATTENTION:
6011da177e4SLinus Torvalds 		/*
6021da177e4SLinus Torvalds 		 * if we are expecting a cc/ua because of a bus reset that we
6031da177e4SLinus Torvalds 		 * performed, treat this just as a retry.  otherwise this is
6041da177e4SLinus Torvalds 		 * information that we should pass up to the upper-level driver
6051da177e4SLinus Torvalds 		 * so that we can deal with it there.
6061da177e4SLinus Torvalds 		 */
6071da177e4SLinus Torvalds 		if (scmd->device->expecting_cc_ua) {
608dfcf7775STARUISI Hiroaki 			/*
609dfcf7775STARUISI Hiroaki 			 * Because some device does not queue unit
610dfcf7775STARUISI Hiroaki 			 * attentions correctly, we carefully check
611dfcf7775STARUISI Hiroaki 			 * additional sense code and qualifier so as
612dfcf7775STARUISI Hiroaki 			 * not to squash media change unit attention.
613dfcf7775STARUISI Hiroaki 			 */
614dfcf7775STARUISI Hiroaki 			if (sshdr.asc != 0x28 || sshdr.ascq != 0x00) {
6151da177e4SLinus Torvalds 				scmd->device->expecting_cc_ua = 0;
6161da177e4SLinus Torvalds 				return NEEDS_RETRY;
6171da177e4SLinus Torvalds 			}
618dfcf7775STARUISI Hiroaki 		}
6191da177e4SLinus Torvalds 		/*
620279afdfeSEwan D. Milne 		 * we might also expect a cc/ua if another LUN on the target
621279afdfeSEwan D. Milne 		 * reported a UA with an ASC/ASCQ of 3F 0E -
622279afdfeSEwan D. Milne 		 * REPORTED LUNS DATA HAS CHANGED.
623279afdfeSEwan D. Milne 		 */
624279afdfeSEwan D. Milne 		if (scmd->device->sdev_target->expecting_lun_change &&
625279afdfeSEwan D. Milne 		    sshdr.asc == 0x3f && sshdr.ascq == 0x0e)
626279afdfeSEwan D. Milne 			return NEEDS_RETRY;
627279afdfeSEwan D. Milne 		/*
6281da177e4SLinus Torvalds 		 * if the device is in the process of becoming ready, we
6291da177e4SLinus Torvalds 		 * should retry.
6301da177e4SLinus Torvalds 		 */
6311da177e4SLinus Torvalds 		if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01))
6321da177e4SLinus Torvalds 			return NEEDS_RETRY;
6331da177e4SLinus Torvalds 		/*
6341da177e4SLinus Torvalds 		 * if the device is not started, we need to wake
6351da177e4SLinus Torvalds 		 * the error handler to start the motor
6361da177e4SLinus Torvalds 		 */
6371da177e4SLinus Torvalds 		if (scmd->device->allow_restart &&
6381da177e4SLinus Torvalds 		    (sshdr.asc == 0x04) && (sshdr.ascq == 0x02))
6391da177e4SLinus Torvalds 			return FAILED;
64077a42297SJames Bottomley 		/*
64102e031cbSChristoph Hellwig 		 * Pass the UA upwards for a determination in the completion
64202e031cbSChristoph Hellwig 		 * functions.
64377a42297SJames Bottomley 		 */
6441da177e4SLinus Torvalds 		return SUCCESS;
6451da177e4SLinus Torvalds 
64663583ccaSHannes Reinecke 		/* these are not supported */
647a9d6ceb8SHannes Reinecke 	case DATA_PROTECT:
648a9d6ceb8SHannes Reinecke 		if (sshdr.asc == 0x27 && sshdr.ascq == 0x07) {
649a9d6ceb8SHannes Reinecke 			/* Thin provisioning hard threshold reached */
6507dfaae6aSMike Christie 			set_scsi_ml_byte(scmd, SCSIML_STAT_NOSPC);
651a9d6ceb8SHannes Reinecke 			return SUCCESS;
652a9d6ceb8SHannes Reinecke 		}
653df561f66SGustavo A. R. Silva 		fallthrough;
6541da177e4SLinus Torvalds 	case COPY_ABORTED:
6551da177e4SLinus Torvalds 	case VOLUME_OVERFLOW:
6561da177e4SLinus Torvalds 	case MISCOMPARE:
65763583ccaSHannes Reinecke 	case BLANK_CHECK:
6587dfaae6aSMike Christie 		set_scsi_ml_byte(scmd, SCSIML_STAT_TGT_FAILURE);
65987f14e65SHannes Reinecke 		return SUCCESS;
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 	case MEDIUM_ERROR:
662fd1b494dSLuben Tuikov 		if (sshdr.asc == 0x11 || /* UNRECOVERED READ ERR */
663fd1b494dSLuben Tuikov 		    sshdr.asc == 0x13 || /* AMNF DATA FIELD */
664fd1b494dSLuben Tuikov 		    sshdr.asc == 0x14) { /* RECORD NOT FOUND */
6657dfaae6aSMike Christie 			set_scsi_ml_byte(scmd, SCSIML_STAT_MED_ERROR);
66687f14e65SHannes Reinecke 			return SUCCESS;
667fd1b494dSLuben Tuikov 		}
6681da177e4SLinus Torvalds 		return NEEDS_RETRY;
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds 	case HARDWARE_ERROR:
6711da177e4SLinus Torvalds 		if (scmd->device->retry_hwerror)
672bb0003c1SMike Anderson 			return ADD_TO_MLQUEUE;
6731da177e4SLinus Torvalds 		else
6747dfaae6aSMike Christie 			set_scsi_ml_byte(scmd, SCSIML_STAT_TGT_FAILURE);
675df561f66SGustavo A. R. Silva 		fallthrough;
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds 	case ILLEGAL_REQUEST:
67847ac56dbSMike Snitzer 		if (sshdr.asc == 0x20 || /* Invalid command operation code */
67947ac56dbSMike Snitzer 		    sshdr.asc == 0x21 || /* Logical block address out of range */
680a8bbb2abSHannes Reinecke 		    sshdr.asc == 0x22 || /* Invalid function */
68147ac56dbSMike Snitzer 		    sshdr.asc == 0x24 || /* Invalid field in cdb */
682d0b7a909SMartin Wilck 		    sshdr.asc == 0x26 || /* Parameter value invalid */
683d0b7a909SMartin Wilck 		    sshdr.asc == 0x27) { /* Write protected */
6847dfaae6aSMike Christie 			set_scsi_ml_byte(scmd, SCSIML_STAT_TGT_FAILURE);
68547ac56dbSMike Snitzer 		}
68647ac56dbSMike Snitzer 		return SUCCESS;
68747ac56dbSMike Snitzer 
6881da177e4SLinus Torvalds 	default:
6891da177e4SLinus Torvalds 		return SUCCESS;
6901da177e4SLinus Torvalds 	}
6911da177e4SLinus Torvalds }
6923852e373SHannes Reinecke EXPORT_SYMBOL_GPL(scsi_check_sense);
6931da177e4SLinus Torvalds 
6944a84067dSVasu Dev static void scsi_handle_queue_ramp_up(struct scsi_device *sdev)
6954a84067dSVasu Dev {
6964a84067dSVasu Dev 	struct scsi_host_template *sht = sdev->host->hostt;
6974a84067dSVasu Dev 	struct scsi_device *tmp_sdev;
6984a84067dSVasu Dev 
699c40ecc12SChristoph Hellwig 	if (!sht->track_queue_depth ||
7004a84067dSVasu Dev 	    sdev->queue_depth >= sdev->max_queue_depth)
7014a84067dSVasu Dev 		return;
7024a84067dSVasu Dev 
7034a84067dSVasu Dev 	if (time_before(jiffies,
7044a84067dSVasu Dev 	    sdev->last_queue_ramp_up + sdev->queue_ramp_up_period))
7054a84067dSVasu Dev 		return;
7064a84067dSVasu Dev 
7074a84067dSVasu Dev 	if (time_before(jiffies,
7084a84067dSVasu Dev 	    sdev->last_queue_full_time + sdev->queue_ramp_up_period))
7094a84067dSVasu Dev 		return;
7104a84067dSVasu Dev 
7114a84067dSVasu Dev 	/*
7124a84067dSVasu Dev 	 * Walk all devices of a target and do
7134a84067dSVasu Dev 	 * ramp up on them.
7144a84067dSVasu Dev 	 */
7154a84067dSVasu Dev 	shost_for_each_device(tmp_sdev, sdev->host) {
7164a84067dSVasu Dev 		if (tmp_sdev->channel != sdev->channel ||
7174a84067dSVasu Dev 		    tmp_sdev->id != sdev->id ||
7184a84067dSVasu Dev 		    tmp_sdev->queue_depth == sdev->max_queue_depth)
7194a84067dSVasu Dev 			continue;
720c40ecc12SChristoph Hellwig 
721db5ed4dfSChristoph Hellwig 		scsi_change_queue_depth(tmp_sdev, tmp_sdev->queue_depth + 1);
7224a84067dSVasu Dev 		sdev->last_queue_ramp_up = jiffies;
7234a84067dSVasu Dev 	}
7244a84067dSVasu Dev }
7254a84067dSVasu Dev 
72642a6a918SMike Christie static void scsi_handle_queue_full(struct scsi_device *sdev)
72742a6a918SMike Christie {
72842a6a918SMike Christie 	struct scsi_host_template *sht = sdev->host->hostt;
72942a6a918SMike Christie 	struct scsi_device *tmp_sdev;
73042a6a918SMike Christie 
731c40ecc12SChristoph Hellwig 	if (!sht->track_queue_depth)
73242a6a918SMike Christie 		return;
73342a6a918SMike Christie 
73442a6a918SMike Christie 	shost_for_each_device(tmp_sdev, sdev->host) {
73542a6a918SMike Christie 		if (tmp_sdev->channel != sdev->channel ||
73642a6a918SMike Christie 		    tmp_sdev->id != sdev->id)
73742a6a918SMike Christie 			continue;
73842a6a918SMike Christie 		/*
73942a6a918SMike Christie 		 * We do not know the number of commands that were at
74042a6a918SMike Christie 		 * the device when we got the queue full so we start
74142a6a918SMike Christie 		 * from the highest possible value and work our way down.
74242a6a918SMike Christie 		 */
743c40ecc12SChristoph Hellwig 		scsi_track_queue_full(tmp_sdev, tmp_sdev->queue_depth - 1);
74442a6a918SMike Christie 	}
74542a6a918SMike Christie }
74642a6a918SMike Christie 
7471da177e4SLinus Torvalds /**
7481da177e4SLinus Torvalds  * scsi_eh_completed_normally - Disposition a eh cmd on return from LLD.
7491da177e4SLinus Torvalds  * @scmd:	SCSI cmd to examine.
7501da177e4SLinus Torvalds  *
7511da177e4SLinus Torvalds  * Notes:
7521da177e4SLinus Torvalds  *    This is *only* called when we are examining the status of commands
7531da177e4SLinus Torvalds  *    queued during error recovery.  the main difference here is that we
7541da177e4SLinus Torvalds  *    don't allow for the possibility of retries here, and we are a lot
7551da177e4SLinus Torvalds  *    more restrictive about what we consider acceptable.
756dc8875e1SRandy Dunlap  */
757b8e162f9SBart Van Assche static enum scsi_disposition scsi_eh_completed_normally(struct scsi_cmnd *scmd)
7581da177e4SLinus Torvalds {
7591da177e4SLinus Torvalds 	/*
7601da177e4SLinus Torvalds 	 * first check the host byte, to see if there is anything in there
7611da177e4SLinus Torvalds 	 * that would indicate what we need to do.
7621da177e4SLinus Torvalds 	 */
7631da177e4SLinus Torvalds 	if (host_byte(scmd->result) == DID_RESET) {
7641da177e4SLinus Torvalds 		/*
7651da177e4SLinus Torvalds 		 * rats.  we are already in the error handler, so we now
7661da177e4SLinus Torvalds 		 * get to try and figure out what to do next.  if the sense
7671da177e4SLinus Torvalds 		 * is valid, we have a pretty good idea of what to do.
7681da177e4SLinus Torvalds 		 * if not, we mark it as FAILED.
7691da177e4SLinus Torvalds 		 */
7701da177e4SLinus Torvalds 		return scsi_check_sense(scmd);
7711da177e4SLinus Torvalds 	}
7721da177e4SLinus Torvalds 	if (host_byte(scmd->result) != DID_OK)
7731da177e4SLinus Torvalds 		return FAILED;
7741da177e4SLinus Torvalds 
7751da177e4SLinus Torvalds 	/*
7761da177e4SLinus Torvalds 	 * now, check the status byte to see if this indicates
7771da177e4SLinus Torvalds 	 * anything special.
7781da177e4SLinus Torvalds 	 */
7793d45cefcSHannes Reinecke 	switch (get_status_byte(scmd)) {
7803d45cefcSHannes Reinecke 	case SAM_STAT_GOOD:
7814a84067dSVasu Dev 		scsi_handle_queue_ramp_up(scmd->device);
782df561f66SGustavo A. R. Silva 		fallthrough;
7833d45cefcSHannes Reinecke 	case SAM_STAT_COMMAND_TERMINATED:
7841da177e4SLinus Torvalds 		return SUCCESS;
7853d45cefcSHannes Reinecke 	case SAM_STAT_CHECK_CONDITION:
7861da177e4SLinus Torvalds 		return scsi_check_sense(scmd);
7873d45cefcSHannes Reinecke 	case SAM_STAT_CONDITION_MET:
7883d45cefcSHannes Reinecke 	case SAM_STAT_INTERMEDIATE:
7893d45cefcSHannes Reinecke 	case SAM_STAT_INTERMEDIATE_CONDITION_MET:
7901da177e4SLinus Torvalds 		/*
7911da177e4SLinus Torvalds 		 * who knows?  FIXME(eric)
7921da177e4SLinus Torvalds 		 */
7931da177e4SLinus Torvalds 		return SUCCESS;
7943d45cefcSHannes Reinecke 	case SAM_STAT_RESERVATION_CONFLICT:
79567110dfdSJames Bottomley 		if (scmd->cmnd[0] == TEST_UNIT_READY)
79667110dfdSJames Bottomley 			/* it is a success, we probed the device and
79767110dfdSJames Bottomley 			 * found it */
7985f91bb05SMichael Reed 			return SUCCESS;
79967110dfdSJames Bottomley 		/* otherwise, we failed to send the command */
80067110dfdSJames Bottomley 		return FAILED;
8013d45cefcSHannes Reinecke 	case SAM_STAT_TASK_SET_FULL:
80242a6a918SMike Christie 		scsi_handle_queue_full(scmd->device);
803df561f66SGustavo A. R. Silva 		fallthrough;
8043d45cefcSHannes Reinecke 	case SAM_STAT_BUSY:
8053eb3a928SHannes Reinecke 		return NEEDS_RETRY;
8061da177e4SLinus Torvalds 	default:
8071da177e4SLinus Torvalds 		return FAILED;
8081da177e4SLinus Torvalds 	}
8091da177e4SLinus Torvalds 	return FAILED;
8101da177e4SLinus Torvalds }
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds /**
8131da177e4SLinus Torvalds  * scsi_eh_done - Completion function for error handling.
8141da177e4SLinus Torvalds  * @scmd:	Cmd that is done.
815dc8875e1SRandy Dunlap  */
816bf23e619SBart Van Assche void scsi_eh_done(struct scsi_cmnd *scmd)
8171da177e4SLinus Torvalds {
81885631672SMichael Reed 	struct completion *eh_action;
81985631672SMichael Reed 
82091921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
821470613b4SHannes Reinecke 			"%s result: %x\n", __func__, scmd->result));
82285631672SMichael Reed 
82385631672SMichael Reed 	eh_action = scmd->device->host->eh_action;
82485631672SMichael Reed 	if (eh_action)
82585631672SMichael Reed 		complete(eh_action);
8261da177e4SLinus Torvalds }
8271da177e4SLinus Torvalds 
8281da177e4SLinus Torvalds /**
829292148f8SBrian King  * scsi_try_host_reset - ask host adapter to reset itself
830c2b3ebd0SGeert Uytterhoeven  * @scmd:	SCSI cmd to send host reset.
831dc8875e1SRandy Dunlap  */
832b8e162f9SBart Van Assche static enum scsi_disposition scsi_try_host_reset(struct scsi_cmnd *scmd)
833292148f8SBrian King {
834292148f8SBrian King 	unsigned long flags;
835b8e162f9SBart Van Assche 	enum scsi_disposition rtn;
8360bf8c869SJesper Juhl 	struct Scsi_Host *host = scmd->device->host;
8370bf8c869SJesper Juhl 	struct scsi_host_template *hostt = host->hostt;
838292148f8SBrian King 
83991921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3,
84091921e01SHannes Reinecke 		shost_printk(KERN_INFO, host, "Snd Host RST\n"));
841292148f8SBrian King 
8420bf8c869SJesper Juhl 	if (!hostt->eh_host_reset_handler)
843292148f8SBrian King 		return FAILED;
844292148f8SBrian King 
8450bf8c869SJesper Juhl 	rtn = hostt->eh_host_reset_handler(scmd);
846292148f8SBrian King 
847292148f8SBrian King 	if (rtn == SUCCESS) {
8480bf8c869SJesper Juhl 		if (!hostt->skip_settle_delay)
849292148f8SBrian King 			ssleep(HOST_RESET_SETTLE_TIME);
8500bf8c869SJesper Juhl 		spin_lock_irqsave(host->host_lock, flags);
8510bf8c869SJesper Juhl 		scsi_report_bus_reset(host, scmd_channel(scmd));
8520bf8c869SJesper Juhl 		spin_unlock_irqrestore(host->host_lock, flags);
853292148f8SBrian King 	}
854292148f8SBrian King 
855292148f8SBrian King 	return rtn;
856292148f8SBrian King }
857292148f8SBrian King 
858292148f8SBrian King /**
859292148f8SBrian King  * scsi_try_bus_reset - ask host to perform a bus reset
860292148f8SBrian King  * @scmd:	SCSI cmd to send bus reset.
861dc8875e1SRandy Dunlap  */
862b8e162f9SBart Van Assche static enum scsi_disposition scsi_try_bus_reset(struct scsi_cmnd *scmd)
863292148f8SBrian King {
864292148f8SBrian King 	unsigned long flags;
865b8e162f9SBart Van Assche 	enum scsi_disposition rtn;
8660bf8c869SJesper Juhl 	struct Scsi_Host *host = scmd->device->host;
8670bf8c869SJesper Juhl 	struct scsi_host_template *hostt = host->hostt;
868292148f8SBrian King 
86991921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
87091921e01SHannes Reinecke 		"%s: Snd Bus RST\n", __func__));
871292148f8SBrian King 
8720bf8c869SJesper Juhl 	if (!hostt->eh_bus_reset_handler)
873292148f8SBrian King 		return FAILED;
874292148f8SBrian King 
8750bf8c869SJesper Juhl 	rtn = hostt->eh_bus_reset_handler(scmd);
876292148f8SBrian King 
877292148f8SBrian King 	if (rtn == SUCCESS) {
8780bf8c869SJesper Juhl 		if (!hostt->skip_settle_delay)
879292148f8SBrian King 			ssleep(BUS_RESET_SETTLE_TIME);
8800bf8c869SJesper Juhl 		spin_lock_irqsave(host->host_lock, flags);
8810bf8c869SJesper Juhl 		scsi_report_bus_reset(host, scmd_channel(scmd));
8820bf8c869SJesper Juhl 		spin_unlock_irqrestore(host->host_lock, flags);
883292148f8SBrian King 	}
884292148f8SBrian King 
885292148f8SBrian King 	return rtn;
886292148f8SBrian King }
887292148f8SBrian King 
88830bd7df8SMike Christie static void __scsi_report_device_reset(struct scsi_device *sdev, void *data)
88930bd7df8SMike Christie {
89030bd7df8SMike Christie 	sdev->was_reset = 1;
89130bd7df8SMike Christie 	sdev->expecting_cc_ua = 1;
89230bd7df8SMike Christie }
89330bd7df8SMike Christie 
89430bd7df8SMike Christie /**
89530bd7df8SMike Christie  * scsi_try_target_reset - Ask host to perform a target reset
89630bd7df8SMike Christie  * @scmd:	SCSI cmd used to send a target reset
89730bd7df8SMike Christie  *
89830bd7df8SMike Christie  * Notes:
89930bd7df8SMike Christie  *    There is no timeout for this operation.  if this operation is
90030bd7df8SMike Christie  *    unreliable for a given host, then the host itself needs to put a
90130bd7df8SMike Christie  *    timer on it, and set the host back to a consistent state prior to
90230bd7df8SMike Christie  *    returning.
90330bd7df8SMike Christie  */
904b8e162f9SBart Van Assche static enum scsi_disposition scsi_try_target_reset(struct scsi_cmnd *scmd)
90530bd7df8SMike Christie {
90630bd7df8SMike Christie 	unsigned long flags;
907b8e162f9SBart Van Assche 	enum scsi_disposition rtn;
9080bf8c869SJesper Juhl 	struct Scsi_Host *host = scmd->device->host;
9090bf8c869SJesper Juhl 	struct scsi_host_template *hostt = host->hostt;
91030bd7df8SMike Christie 
9110bf8c869SJesper Juhl 	if (!hostt->eh_target_reset_handler)
91230bd7df8SMike Christie 		return FAILED;
91330bd7df8SMike Christie 
9140bf8c869SJesper Juhl 	rtn = hostt->eh_target_reset_handler(scmd);
91530bd7df8SMike Christie 	if (rtn == SUCCESS) {
9160bf8c869SJesper Juhl 		spin_lock_irqsave(host->host_lock, flags);
91730bd7df8SMike Christie 		__starget_for_each_device(scsi_target(scmd->device), NULL,
91830bd7df8SMike Christie 					  __scsi_report_device_reset);
9190bf8c869SJesper Juhl 		spin_unlock_irqrestore(host->host_lock, flags);
92030bd7df8SMike Christie 	}
92130bd7df8SMike Christie 
92230bd7df8SMike Christie 	return rtn;
92330bd7df8SMike Christie }
92430bd7df8SMike Christie 
925292148f8SBrian King /**
926292148f8SBrian King  * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev
927292148f8SBrian King  * @scmd:	SCSI cmd used to send BDR
928292148f8SBrian King  *
929292148f8SBrian King  * Notes:
930292148f8SBrian King  *    There is no timeout for this operation.  if this operation is
931292148f8SBrian King  *    unreliable for a given host, then the host itself needs to put a
932292148f8SBrian King  *    timer on it, and set the host back to a consistent state prior to
933292148f8SBrian King  *    returning.
934dc8875e1SRandy Dunlap  */
935b8e162f9SBart Van Assche static enum scsi_disposition scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
936292148f8SBrian King {
937b8e162f9SBart Van Assche 	enum scsi_disposition rtn;
9380bf8c869SJesper Juhl 	struct scsi_host_template *hostt = scmd->device->host->hostt;
939292148f8SBrian King 
9400bf8c869SJesper Juhl 	if (!hostt->eh_device_reset_handler)
941292148f8SBrian King 		return FAILED;
942292148f8SBrian King 
9430bf8c869SJesper Juhl 	rtn = hostt->eh_device_reset_handler(scmd);
94430bd7df8SMike Christie 	if (rtn == SUCCESS)
94530bd7df8SMike Christie 		__scsi_report_device_reset(scmd->device, NULL);
946292148f8SBrian King 	return rtn;
947292148f8SBrian King }
948292148f8SBrian King 
949883a030fSHannes Reinecke /**
950883a030fSHannes Reinecke  * scsi_try_to_abort_cmd - Ask host to abort a SCSI command
9516583f6fbSRandy Dunlap  * @hostt:	SCSI driver host template
952883a030fSHannes Reinecke  * @scmd:	SCSI cmd used to send a target reset
953883a030fSHannes Reinecke  *
954883a030fSHannes Reinecke  * Return value:
955883a030fSHannes Reinecke  *	SUCCESS, FAILED, or FAST_IO_FAIL
956883a030fSHannes Reinecke  *
957883a030fSHannes Reinecke  * Notes:
958883a030fSHannes Reinecke  *    SUCCESS does not necessarily indicate that the command
959883a030fSHannes Reinecke  *    has been aborted; it only indicates that the LLDDs
960883a030fSHannes Reinecke  *    has cleared all references to that command.
961883a030fSHannes Reinecke  *    LLDDs should return FAILED only if an abort was required
962883a030fSHannes Reinecke  *    but could not be executed. LLDDs should return FAST_IO_FAIL
963883a030fSHannes Reinecke  *    if the device is temporarily unavailable (eg due to a
964883a030fSHannes Reinecke  *    link down on FibreChannel)
965883a030fSHannes Reinecke  */
966b8e162f9SBart Van Assche static enum scsi_disposition
967b8e162f9SBart Van Assche scsi_try_to_abort_cmd(struct scsi_host_template *hostt, struct scsi_cmnd *scmd)
968292148f8SBrian King {
9690bf8c869SJesper Juhl 	if (!hostt->eh_abort_handler)
970292148f8SBrian King 		return FAILED;
971292148f8SBrian King 
9720bf8c869SJesper Juhl 	return hostt->eh_abort_handler(scmd);
973292148f8SBrian King }
974292148f8SBrian King 
975292148f8SBrian King static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
976292148f8SBrian King {
9770bf8c869SJesper Juhl 	if (scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd) != SUCCESS)
978292148f8SBrian King 		if (scsi_try_bus_device_reset(scmd) != SUCCESS)
97930bd7df8SMike Christie 			if (scsi_try_target_reset(scmd) != SUCCESS)
980292148f8SBrian King 				if (scsi_try_bus_reset(scmd) != SUCCESS)
981292148f8SBrian King 					scsi_try_host_reset(scmd);
982292148f8SBrian King }
983292148f8SBrian King 
984292148f8SBrian King /**
9853b729f76SSantosh Y  * scsi_eh_prep_cmnd  - Save a scsi command info as part of error recovery
9862dc611deSChristoph Hellwig  * @scmd:       SCSI command structure to hijack
987e1c23468SBoaz Harrosh  * @ses:        structure to save restore information
98855db6c1bSBoaz Harrosh  * @cmnd:       CDB to send. Can be NULL if no new cmnd is needed
989ce70fd9aSChristoph Hellwig  * @cmnd_size:  size in bytes of @cmnd (must be <= MAX_COMMAND_SIZE)
99055db6c1bSBoaz Harrosh  * @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored)
9912dc611deSChristoph Hellwig  *
992e1c23468SBoaz Harrosh  * This function is used to save a scsi command information before re-execution
99355db6c1bSBoaz Harrosh  * as part of the error recovery process.  If @sense_bytes is 0 the command
99455db6c1bSBoaz Harrosh  * sent must be one that does not transfer any data.  If @sense_bytes != 0
99555db6c1bSBoaz Harrosh  * @cmnd is ignored and this functions sets up a REQUEST_SENSE command
99655db6c1bSBoaz Harrosh  * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer.
997dc8875e1SRandy Dunlap  */
998e1c23468SBoaz Harrosh void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
999e1c23468SBoaz Harrosh 			unsigned char *cmnd, int cmnd_size, unsigned sense_bytes)
10001da177e4SLinus Torvalds {
1001f59114b7S 	struct scsi_device *sdev = scmd->device;
10021da177e4SLinus Torvalds 
1003631c228cSChristoph Hellwig 	/*
1004631c228cSChristoph Hellwig 	 * We need saved copies of a number of fields - this is because
1005631c228cSChristoph Hellwig 	 * error handling may need to overwrite these with different values
1006631c228cSChristoph Hellwig 	 * to run different commands, and once error handling is complete,
1007631c228cSChristoph Hellwig 	 * we will need to restore these values prior to running the actual
1008631c228cSChristoph Hellwig 	 * command.
1009631c228cSChristoph Hellwig 	 */
1010e1c23468SBoaz Harrosh 	ses->cmd_len = scmd->cmd_len;
1011e1c23468SBoaz Harrosh 	ses->data_direction = scmd->sc_data_direction;
101230b0c37bSBoaz Harrosh 	ses->sdb = scmd->sdb;
1013e1c23468SBoaz Harrosh 	ses->result = scmd->result;
1014a9a4ea11SChristoph Hellwig 	ses->resid_len = scmd->resid_len;
101512265709SAlan Stern 	ses->underflow = scmd->underflow;
1016db007fc5SMartin K. Petersen 	ses->prot_op = scmd->prot_op;
10178e8c9d01SHannes Reinecke 	ses->eh_eflags = scmd->eh_eflags;
1018631c228cSChristoph Hellwig 
1019db007fc5SMartin K. Petersen 	scmd->prot_op = SCSI_PROT_NORMAL;
1020c69e6f81SJames Bottomley 	scmd->eh_eflags = 0;
1021ce70fd9aSChristoph Hellwig 	memcpy(ses->cmnd, scmd->cmnd, sizeof(ses->cmnd));
1022ce70fd9aSChristoph Hellwig 	memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
102330b0c37bSBoaz Harrosh 	memset(&scmd->sdb, 0, sizeof(scmd->sdb));
1024644373a4SAlan Stern 	scmd->result = 0;
1025a9a4ea11SChristoph Hellwig 	scmd->resid_len = 0;
102630b0c37bSBoaz Harrosh 
102755db6c1bSBoaz Harrosh 	if (sense_bytes) {
102830b0c37bSBoaz Harrosh 		scmd->sdb.length = min_t(unsigned, SCSI_SENSE_BUFFERSIZE,
102930b0c37bSBoaz Harrosh 					 sense_bytes);
1030e1c23468SBoaz Harrosh 		sg_init_one(&ses->sense_sgl, scmd->sense_buffer,
103130b0c37bSBoaz Harrosh 			    scmd->sdb.length);
103230b0c37bSBoaz Harrosh 		scmd->sdb.table.sgl = &ses->sense_sgl;
103355db6c1bSBoaz Harrosh 		scmd->sc_data_direction = DMA_FROM_DEVICE;
10340c958eccSTony Battersby 		scmd->sdb.table.nents = scmd->sdb.table.orig_nents = 1;
103555db6c1bSBoaz Harrosh 		scmd->cmnd[0] = REQUEST_SENSE;
103630b0c37bSBoaz Harrosh 		scmd->cmnd[4] = scmd->sdb.length;
103755db6c1bSBoaz Harrosh 		scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
1038631c228cSChristoph Hellwig 	} else {
1039631c228cSChristoph Hellwig 		scmd->sc_data_direction = DMA_NONE;
104055db6c1bSBoaz Harrosh 		if (cmnd) {
1041ce70fd9aSChristoph Hellwig 			BUG_ON(cmnd_size > sizeof(scmd->cmnd));
104255db6c1bSBoaz Harrosh 			memcpy(scmd->cmnd, cmnd, cmnd_size);
104355db6c1bSBoaz Harrosh 			scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
104455db6c1bSBoaz Harrosh 		}
1045631c228cSChristoph Hellwig 	}
1046631c228cSChristoph Hellwig 
1047631c228cSChristoph Hellwig 	scmd->underflow = 0;
1048631c228cSChristoph Hellwig 
104955db6c1bSBoaz Harrosh 	if (sdev->scsi_level <= SCSI_2 && sdev->scsi_level != SCSI_UNKNOWN)
10501da177e4SLinus Torvalds 		scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
1051f59114b7S 			(sdev->lun << 5 & 0xe0);
10521da177e4SLinus Torvalds 
1053631c228cSChristoph Hellwig 	/*
1054631c228cSChristoph Hellwig 	 * Zero the sense buffer.  The scsi spec mandates that any
1055631c228cSChristoph Hellwig 	 * untransferred sense data should be interpreted as being zero.
1056631c228cSChristoph Hellwig 	 */
1057b80ca4f7SFUJITA Tomonori 	memset(scmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
1058e1c23468SBoaz Harrosh }
1059e1c23468SBoaz Harrosh EXPORT_SYMBOL(scsi_eh_prep_cmnd);
1060631c228cSChristoph Hellwig 
1061e1c23468SBoaz Harrosh /**
10623b729f76SSantosh Y  * scsi_eh_restore_cmnd  - Restore a scsi command info as part of error recovery
1063e1c23468SBoaz Harrosh  * @scmd:       SCSI command structure to restore
1064477e608cSBartlomiej Zolnierkiewicz  * @ses:        saved information from a coresponding call to scsi_eh_prep_cmnd
1065e1c23468SBoaz Harrosh  *
1066477e608cSBartlomiej Zolnierkiewicz  * Undo any damage done by above scsi_eh_prep_cmnd().
1067dc8875e1SRandy Dunlap  */
1068e1c23468SBoaz Harrosh void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
1069e1c23468SBoaz Harrosh {
1070e1c23468SBoaz Harrosh 	/*
1071e1c23468SBoaz Harrosh 	 * Restore original data
1072e1c23468SBoaz Harrosh 	 */
1073e1c23468SBoaz Harrosh 	scmd->cmd_len = ses->cmd_len;
1074ce70fd9aSChristoph Hellwig 	memcpy(scmd->cmnd, ses->cmnd, sizeof(ses->cmnd));
1075e1c23468SBoaz Harrosh 	scmd->sc_data_direction = ses->data_direction;
107630b0c37bSBoaz Harrosh 	scmd->sdb = ses->sdb;
1077e1c23468SBoaz Harrosh 	scmd->result = ses->result;
1078a9a4ea11SChristoph Hellwig 	scmd->resid_len = ses->resid_len;
107912265709SAlan Stern 	scmd->underflow = ses->underflow;
1080db007fc5SMartin K. Petersen 	scmd->prot_op = ses->prot_op;
10818e8c9d01SHannes Reinecke 	scmd->eh_eflags = ses->eh_eflags;
1082e1c23468SBoaz Harrosh }
1083e1c23468SBoaz Harrosh EXPORT_SYMBOL(scsi_eh_restore_cmnd);
1084e1c23468SBoaz Harrosh 
1085e1c23468SBoaz Harrosh /**
10863b729f76SSantosh Y  * scsi_send_eh_cmnd  - submit a scsi command as part of error recovery
1087e1c23468SBoaz Harrosh  * @scmd:       SCSI command structure to hijack
1088e1c23468SBoaz Harrosh  * @cmnd:       CDB to send
1089e1c23468SBoaz Harrosh  * @cmnd_size:  size in bytes of @cmnd
1090e1c23468SBoaz Harrosh  * @timeout:    timeout for this request
1091e1c23468SBoaz Harrosh  * @sense_bytes: size of sense data to copy or 0
1092e1c23468SBoaz Harrosh  *
1093e1c23468SBoaz Harrosh  * This function is used to send a scsi command down to a target device
1094e1c23468SBoaz Harrosh  * as part of the error recovery process. See also scsi_eh_prep_cmnd() above.
1095e1c23468SBoaz Harrosh  *
1096e1c23468SBoaz Harrosh  * Return value:
1097e1c23468SBoaz Harrosh  *    SUCCESS or FAILED or NEEDS_RETRY
1098dc8875e1SRandy Dunlap  */
1099b8e162f9SBart Van Assche static enum scsi_disposition scsi_send_eh_cmnd(struct scsi_cmnd *scmd,
1100b8e162f9SBart Van Assche 	unsigned char *cmnd, int cmnd_size, int timeout, unsigned sense_bytes)
1101e1c23468SBoaz Harrosh {
1102e1c23468SBoaz Harrosh 	struct scsi_device *sdev = scmd->device;
1103e1c23468SBoaz Harrosh 	struct Scsi_Host *shost = sdev->host;
1104e1c23468SBoaz Harrosh 	DECLARE_COMPLETION_ONSTACK(done);
1105bbe9fb0dSBart Van Assche 	unsigned long timeleft = timeout, delay;
1106e1c23468SBoaz Harrosh 	struct scsi_eh_save ses;
1107fc73648aSHannes Reinecke 	const unsigned long stall_for = msecs_to_jiffies(100);
1108e1c23468SBoaz Harrosh 	int rtn;
1109e1c23468SBoaz Harrosh 
1110fc73648aSHannes Reinecke retry:
1111e1c23468SBoaz Harrosh 	scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes);
11127dfdc9a5SChristoph Hellwig 	shost->eh_action = &done;
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds 	scsi_log_send(scmd);
1115bf23e619SBart Van Assche 	scmd->submitter = SUBMITTED_BY_SCSI_ERROR_HANDLER;
1116bbe9fb0dSBart Van Assche 
1117bbe9fb0dSBart Van Assche 	/*
1118bbe9fb0dSBart Van Assche 	 * Lock sdev->state_mutex to avoid that scsi_device_quiesce() can
1119bbe9fb0dSBart Van Assche 	 * change the SCSI device state after we have examined it and before
1120bbe9fb0dSBart Van Assche 	 * .queuecommand() is called.
1121bbe9fb0dSBart Van Assche 	 */
1122bbe9fb0dSBart Van Assche 	mutex_lock(&sdev->state_mutex);
1123bbe9fb0dSBart Van Assche 	while (sdev->sdev_state == SDEV_BLOCK && timeleft > 0) {
1124bbe9fb0dSBart Van Assche 		mutex_unlock(&sdev->state_mutex);
1125bbe9fb0dSBart Van Assche 		SCSI_LOG_ERROR_RECOVERY(5, sdev_printk(KERN_DEBUG, sdev,
1126bbe9fb0dSBart Van Assche 			"%s: state %d <> %d\n", __func__, sdev->sdev_state,
1127bbe9fb0dSBart Van Assche 			SDEV_BLOCK));
1128bbe9fb0dSBart Van Assche 		delay = min(timeleft, stall_for);
1129bbe9fb0dSBart Van Assche 		timeleft -= delay;
1130bbe9fb0dSBart Van Assche 		msleep(jiffies_to_msecs(delay));
1131bbe9fb0dSBart Van Assche 		mutex_lock(&sdev->state_mutex);
1132bbe9fb0dSBart Van Assche 	}
1133bbe9fb0dSBart Van Assche 	if (sdev->sdev_state != SDEV_BLOCK)
1134fc73648aSHannes Reinecke 		rtn = shost->hostt->queuecommand(shost, scmd);
1135bbe9fb0dSBart Van Assche 	else
1136280e91b0SBart Van Assche 		rtn = FAILED;
1137bbe9fb0dSBart Van Assche 	mutex_unlock(&sdev->state_mutex);
1138bbe9fb0dSBart Van Assche 
1139fc73648aSHannes Reinecke 	if (rtn) {
1140fc73648aSHannes Reinecke 		if (timeleft > stall_for) {
1141fc73648aSHannes Reinecke 			scsi_eh_restore_cmnd(scmd, &ses);
1142bf23e619SBart Van Assche 
1143fc73648aSHannes Reinecke 			timeleft -= stall_for;
1144fc73648aSHannes Reinecke 			msleep(jiffies_to_msecs(stall_for));
1145fc73648aSHannes Reinecke 			goto retry;
1146fc73648aSHannes Reinecke 		}
1147fc73648aSHannes Reinecke 		/* signal not to enter either branch of the if () below */
1148fc73648aSHannes Reinecke 		timeleft = 0;
1149511833acSAlan Stern 		rtn = FAILED;
1150fc73648aSHannes Reinecke 	} else {
11517dfdc9a5SChristoph Hellwig 		timeleft = wait_for_completion_timeout(&done, timeout);
1152ac61d195SHannes Reinecke 		rtn = SUCCESS;
1153fc73648aSHannes Reinecke 	}
11541da177e4SLinus Torvalds 
11557dfdc9a5SChristoph Hellwig 	shost->eh_action = NULL;
11561da177e4SLinus Torvalds 
1157fc73648aSHannes Reinecke 	scsi_log_completion(scmd, rtn);
11587dfdc9a5SChristoph Hellwig 
115991921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
1160470613b4SHannes Reinecke 			"%s timeleft: %ld\n",
1161470613b4SHannes Reinecke 			__func__, timeleft));
11621da177e4SLinus Torvalds 
11631da177e4SLinus Torvalds 	/*
1164fc73648aSHannes Reinecke 	 * If there is time left scsi_eh_done got called, and we will examine
1165fc73648aSHannes Reinecke 	 * the actual status codes to see whether the command actually did
1166fc73648aSHannes Reinecke 	 * complete normally, else if we have a zero return and no time left,
1167fc73648aSHannes Reinecke 	 * the command must still be pending, so abort it and return FAILED.
1168fc73648aSHannes Reinecke 	 * If we never actually managed to issue the command, because
1169fc73648aSHannes Reinecke 	 * ->queuecommand() kept returning non zero, use the rtn = FAILED
1170fc73648aSHannes Reinecke 	 * value above (so don't execute either branch of the if)
11711da177e4SLinus Torvalds 	 */
11727dfdc9a5SChristoph Hellwig 	if (timeleft) {
11731da177e4SLinus Torvalds 		rtn = scsi_eh_completed_normally(scmd);
117491921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
117591921e01SHannes Reinecke 			"%s: scsi_eh_completed_normally %x\n", __func__, rtn));
11767dfdc9a5SChristoph Hellwig 
11771da177e4SLinus Torvalds 		switch (rtn) {
11781da177e4SLinus Torvalds 		case SUCCESS:
11791da177e4SLinus Torvalds 		case NEEDS_RETRY:
11801da177e4SLinus Torvalds 		case FAILED:
11811da177e4SLinus Torvalds 			break;
11826e883b0eSHannes Reinecke 		case ADD_TO_MLQUEUE:
11836e883b0eSHannes Reinecke 			rtn = NEEDS_RETRY;
11846e883b0eSHannes Reinecke 			break;
11851da177e4SLinus Torvalds 		default:
11861da177e4SLinus Torvalds 			rtn = FAILED;
11871da177e4SLinus Torvalds 			break;
11881da177e4SLinus Torvalds 		}
1189511833acSAlan Stern 	} else if (rtn != FAILED) {
1190292148f8SBrian King 		scsi_abort_eh_cmnd(scmd);
11917dfdc9a5SChristoph Hellwig 		rtn = FAILED;
11921da177e4SLinus Torvalds 	}
11931da177e4SLinus Torvalds 
1194e1c23468SBoaz Harrosh 	scsi_eh_restore_cmnd(scmd, &ses);
119518a4d0a2SMartin K. Petersen 
11961da177e4SLinus Torvalds 	return rtn;
11971da177e4SLinus Torvalds }
11981da177e4SLinus Torvalds 
11991da177e4SLinus Torvalds /**
12001da177e4SLinus Torvalds  * scsi_request_sense - Request sense data from a particular target.
12011da177e4SLinus Torvalds  * @scmd:	SCSI cmd for request sense.
12021da177e4SLinus Torvalds  *
12031da177e4SLinus Torvalds  * Notes:
12041da177e4SLinus Torvalds  *    Some hosts automatically obtain this information, others require
12051da177e4SLinus Torvalds  *    that we obtain it on our own. This function will *not* return until
12061da177e4SLinus Torvalds  *    the command either times out, or it completes.
1207dc8875e1SRandy Dunlap  */
1208b8e162f9SBart Van Assche static enum scsi_disposition scsi_request_sense(struct scsi_cmnd *scmd)
12091da177e4SLinus Torvalds {
12100816c925SMartin K. Petersen 	return scsi_send_eh_cmnd(scmd, NULL, 0, scmd->device->eh_timeout, ~0);
12111da177e4SLinus Torvalds }
12121da177e4SLinus Torvalds 
1213b8e162f9SBart Van Assche static enum scsi_disposition
1214b8e162f9SBart Van Assche scsi_eh_action(struct scsi_cmnd *scmd, enum scsi_disposition rtn)
12152451079bSJames Bottomley {
1216aa8e25e5SBart Van Assche 	if (!blk_rq_is_passthrough(scsi_cmd_to_rq(scmd))) {
12172451079bSJames Bottomley 		struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd);
12182451079bSJames Bottomley 		if (sdrv->eh_action)
12192451079bSJames Bottomley 			rtn = sdrv->eh_action(scmd, rtn);
12202451079bSJames Bottomley 	}
12212451079bSJames Bottomley 	return rtn;
12222451079bSJames Bottomley }
12232451079bSJames Bottomley 
12241da177e4SLinus Torvalds /**
12251da177e4SLinus Torvalds  * scsi_eh_finish_cmd - Handle a cmd that eh is finished with.
12261da177e4SLinus Torvalds  * @scmd:	Original SCSI cmd that eh has finished.
12271da177e4SLinus Torvalds  * @done_q:	Queue for processed commands.
12281da177e4SLinus Torvalds  *
12291da177e4SLinus Torvalds  * Notes:
12301da177e4SLinus Torvalds  *    We don't want to use the normal command completion while we are are
12311da177e4SLinus Torvalds  *    still handling errors - it may cause other commands to be queued,
1232eb44820cSRob Landley  *    and that would disturb what we are doing.  Thus we really want to
12331da177e4SLinus Torvalds  *    keep a list of pending commands for final completion, and once we
12341da177e4SLinus Torvalds  *    are ready to leave error handling we handle completion for real.
1235dc8875e1SRandy Dunlap  */
1236041c5fc3STejun Heo void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
12371da177e4SLinus Torvalds {
12381da177e4SLinus Torvalds 	list_move_tail(&scmd->eh_entry, done_q);
12391da177e4SLinus Torvalds }
1240041c5fc3STejun Heo EXPORT_SYMBOL(scsi_eh_finish_cmd);
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds /**
12431da177e4SLinus Torvalds  * scsi_eh_get_sense - Get device sense data.
12441da177e4SLinus Torvalds  * @work_q:	Queue of commands to process.
1245eb44820cSRob Landley  * @done_q:	Queue of processed commands.
12461da177e4SLinus Torvalds  *
12471da177e4SLinus Torvalds  * Description:
12481da177e4SLinus Torvalds  *    See if we need to request sense information.  if so, then get it
12491da177e4SLinus Torvalds  *    now, so we have a better idea of what to do.
12501da177e4SLinus Torvalds  *
12511da177e4SLinus Torvalds  * Notes:
12521da177e4SLinus Torvalds  *    This has the unfortunate side effect that if a shost adapter does
1253eb44820cSRob Landley  *    not automatically request sense information, we end up shutting
12541da177e4SLinus Torvalds  *    it down before we request it.
12551da177e4SLinus Torvalds  *
12561da177e4SLinus Torvalds  *    All drivers should request sense information internally these days,
12571da177e4SLinus Torvalds  *    so for now all I have to say is tough noogies if you end up in here.
12581da177e4SLinus Torvalds  *
12591da177e4SLinus Torvalds  *    XXX: Long term this code should go away, but that needs an audit of
12601da177e4SLinus Torvalds  *         all LLDDs first.
1261dc8875e1SRandy Dunlap  */
1262dca84e46SDarrick J. Wong int scsi_eh_get_sense(struct list_head *work_q,
12631da177e4SLinus Torvalds 		      struct list_head *done_q)
12641da177e4SLinus Torvalds {
1265937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *next;
1266b4562022SHannes Reinecke 	struct Scsi_Host *shost;
1267b8e162f9SBart Van Assche 	enum scsi_disposition rtn;
12681da177e4SLinus Torvalds 
1269709c75b5Sjiang.biao2@zte.com.cn 	/*
1270709c75b5Sjiang.biao2@zte.com.cn 	 * If SCSI_EH_ABORT_SCHEDULED has been set, it is timeout IO,
1271709c75b5Sjiang.biao2@zte.com.cn 	 * should not get sense.
1272709c75b5Sjiang.biao2@zte.com.cn 	 */
1273937abeaaSChristoph Hellwig 	list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
1274a0658632SHannes Reinecke 		if ((scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) ||
12751da177e4SLinus Torvalds 		    SCSI_SENSE_VALID(scmd))
12761da177e4SLinus Torvalds 			continue;
12771da177e4SLinus Torvalds 
1278b4562022SHannes Reinecke 		shost = scmd->device->host;
1279b4562022SHannes Reinecke 		if (scsi_host_eh_past_deadline(shost)) {
1280b4562022SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
1281a222b1e2SHannes Reinecke 				scmd_printk(KERN_INFO, scmd,
1282a222b1e2SHannes Reinecke 					    "%s: skip request sense, past eh deadline\n",
1283a222b1e2SHannes Reinecke 					     current->comm));
1284b4562022SHannes Reinecke 			break;
1285b4562022SHannes Reinecke 		}
1286d0672a03SHannes Reinecke 		if (!scsi_status_is_check_condition(scmd->result))
1287d555a2abSJames Bottomley 			/*
1288d555a2abSJames Bottomley 			 * don't request sense if there's no check condition
1289d555a2abSJames Bottomley 			 * status because the error we're processing isn't one
1290d555a2abSJames Bottomley 			 * that has a sense code (and some devices get
1291d555a2abSJames Bottomley 			 * confused by sense requests out of the blue)
1292d555a2abSJames Bottomley 			 */
1293d555a2abSJames Bottomley 			continue;
1294d555a2abSJames Bottomley 
12953bf743e7SJeff Garzik 		SCSI_LOG_ERROR_RECOVERY(2, scmd_printk(KERN_INFO, scmd,
12963bf743e7SJeff Garzik 						  "%s: requesting sense\n",
12973bf743e7SJeff Garzik 						  current->comm));
12981da177e4SLinus Torvalds 		rtn = scsi_request_sense(scmd);
12991da177e4SLinus Torvalds 		if (rtn != SUCCESS)
13001da177e4SLinus Torvalds 			continue;
13011da177e4SLinus Torvalds 
130291921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
1303470613b4SHannes Reinecke 			"sense requested, result %x\n", scmd->result));
1304d811b848SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3, scsi_print_sense(scmd));
13051da177e4SLinus Torvalds 
13061da177e4SLinus Torvalds 		rtn = scsi_decide_disposition(scmd);
13071da177e4SLinus Torvalds 
13081da177e4SLinus Torvalds 		/*
13091da177e4SLinus Torvalds 		 * if the result was normal, then just pass it along to the
13101da177e4SLinus Torvalds 		 * upper level.
13111da177e4SLinus Torvalds 		 */
13121da177e4SLinus Torvalds 		if (rtn == SUCCESS)
13132a242d59SMike Christie 			/*
13142a242d59SMike Christie 			 * We don't want this command reissued, just finished
13152a242d59SMike Christie 			 * with the sense data, so set retries to the max
13162a242d59SMike Christie 			 * allowed to ensure it won't get reissued. If the user
13172a242d59SMike Christie 			 * has requested infinite retries, we also want to
13182a242d59SMike Christie 			 * finish this command, so force completion by setting
13192a242d59SMike Christie 			 * retries and allowed to the same value.
13202a242d59SMike Christie 			 */
13212a242d59SMike Christie 			if (scmd->allowed == SCSI_CMD_RETRIES_NO_LIMIT)
13222a242d59SMike Christie 				scmd->retries = scmd->allowed = 1;
13232a242d59SMike Christie 			else
13241da177e4SLinus Torvalds 				scmd->retries = scmd->allowed;
13251da177e4SLinus Torvalds 		else if (rtn != NEEDS_RETRY)
13261da177e4SLinus Torvalds 			continue;
13271da177e4SLinus Torvalds 
13281da177e4SLinus Torvalds 		scsi_eh_finish_cmd(scmd, done_q);
13291da177e4SLinus Torvalds 	}
13301da177e4SLinus Torvalds 
13311da177e4SLinus Torvalds 	return list_empty(work_q);
13321da177e4SLinus Torvalds }
1333dca84e46SDarrick J. Wong EXPORT_SYMBOL_GPL(scsi_eh_get_sense);
13341da177e4SLinus Torvalds 
13351da177e4SLinus Torvalds /**
13361da177e4SLinus Torvalds  * scsi_eh_tur - Send TUR to device.
1337eb44820cSRob Landley  * @scmd:	&scsi_cmnd to send TUR
13381da177e4SLinus Torvalds  *
13391da177e4SLinus Torvalds  * Return value:
13401da177e4SLinus Torvalds  *    0 - Device is ready. 1 - Device NOT ready.
1341dc8875e1SRandy Dunlap  */
13421da177e4SLinus Torvalds static int scsi_eh_tur(struct scsi_cmnd *scmd)
13431da177e4SLinus Torvalds {
13441da177e4SLinus Torvalds 	static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
1345b8e162f9SBart Van Assche 	int retry_cnt = 1;
1346b8e162f9SBart Van Assche 	enum scsi_disposition rtn;
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds retry_tur:
13490816c925SMartin K. Petersen 	rtn = scsi_send_eh_cmnd(scmd, tur_command, 6,
13500816c925SMartin K. Petersen 				scmd->device->eh_timeout, 0);
13511da177e4SLinus Torvalds 
135291921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
1353470613b4SHannes Reinecke 		"%s return: %x\n", __func__, rtn));
1354631c228cSChristoph Hellwig 
1355631c228cSChristoph Hellwig 	switch (rtn) {
1356631c228cSChristoph Hellwig 	case NEEDS_RETRY:
13571da177e4SLinus Torvalds 		if (retry_cnt--)
13581da177e4SLinus Torvalds 			goto retry_tur;
1359df561f66SGustavo A. R. Silva 		fallthrough;
1360631c228cSChristoph Hellwig 	case SUCCESS:
1361e47373ecSAlan Stern 		return 0;
1362631c228cSChristoph Hellwig 	default:
13631da177e4SLinus Torvalds 		return 1;
13641da177e4SLinus Torvalds 	}
1365631c228cSChristoph Hellwig }
13661da177e4SLinus Torvalds 
13671da177e4SLinus Torvalds /**
13683eef6257SDavid Jeffery  * scsi_eh_test_devices - check if devices are responding from error recovery.
13693eef6257SDavid Jeffery  * @cmd_list:	scsi commands in error recovery.
13703eef6257SDavid Jeffery  * @work_q:	queue for commands which still need more error recovery
13713eef6257SDavid Jeffery  * @done_q:	queue for commands which are finished
13723eef6257SDavid Jeffery  * @try_stu:	boolean on if a STU command should be tried in addition to TUR.
13733eef6257SDavid Jeffery  *
13743eef6257SDavid Jeffery  * Decription:
13753eef6257SDavid Jeffery  *    Tests if devices are in a working state.  Commands to devices now in
13763eef6257SDavid Jeffery  *    a working state are sent to the done_q while commands to devices which
13773eef6257SDavid Jeffery  *    are still failing to respond are returned to the work_q for more
13783eef6257SDavid Jeffery  *    processing.
13793eef6257SDavid Jeffery  **/
13803eef6257SDavid Jeffery static int scsi_eh_test_devices(struct list_head *cmd_list,
13813eef6257SDavid Jeffery 				struct list_head *work_q,
13823eef6257SDavid Jeffery 				struct list_head *done_q, int try_stu)
13833eef6257SDavid Jeffery {
13843eef6257SDavid Jeffery 	struct scsi_cmnd *scmd, *next;
13853eef6257SDavid Jeffery 	struct scsi_device *sdev;
13863eef6257SDavid Jeffery 	int finish_cmds;
13873eef6257SDavid Jeffery 
13883eef6257SDavid Jeffery 	while (!list_empty(cmd_list)) {
13893eef6257SDavid Jeffery 		scmd = list_entry(cmd_list->next, struct scsi_cmnd, eh_entry);
13903eef6257SDavid Jeffery 		sdev = scmd->device;
13913eef6257SDavid Jeffery 
1392b4562022SHannes Reinecke 		if (!try_stu) {
1393b4562022SHannes Reinecke 			if (scsi_host_eh_past_deadline(sdev->host)) {
1394b4562022SHannes Reinecke 				/* Push items back onto work_q */
1395b4562022SHannes Reinecke 				list_splice_init(cmd_list, work_q);
1396b4562022SHannes Reinecke 				SCSI_LOG_ERROR_RECOVERY(3,
1397a222b1e2SHannes Reinecke 					sdev_printk(KERN_INFO, sdev,
1398a222b1e2SHannes Reinecke 						    "%s: skip test device, past eh deadline",
1399a222b1e2SHannes Reinecke 						    current->comm));
1400b4562022SHannes Reinecke 				break;
1401b4562022SHannes Reinecke 			}
1402b4562022SHannes Reinecke 		}
1403b4562022SHannes Reinecke 
14043eef6257SDavid Jeffery 		finish_cmds = !scsi_device_online(scmd->device) ||
14053eef6257SDavid Jeffery 			(try_stu && !scsi_eh_try_stu(scmd) &&
14063eef6257SDavid Jeffery 			 !scsi_eh_tur(scmd)) ||
14073eef6257SDavid Jeffery 			!scsi_eh_tur(scmd);
14083eef6257SDavid Jeffery 
14093eef6257SDavid Jeffery 		list_for_each_entry_safe(scmd, next, cmd_list, eh_entry)
14103eef6257SDavid Jeffery 			if (scmd->device == sdev) {
14112451079bSJames Bottomley 				if (finish_cmds &&
14122451079bSJames Bottomley 				    (try_stu ||
14132451079bSJames Bottomley 				     scsi_eh_action(scmd, SUCCESS) == SUCCESS))
14143eef6257SDavid Jeffery 					scsi_eh_finish_cmd(scmd, done_q);
14153eef6257SDavid Jeffery 				else
14163eef6257SDavid Jeffery 					list_move_tail(&scmd->eh_entry, work_q);
14173eef6257SDavid Jeffery 			}
14183eef6257SDavid Jeffery 	}
14193eef6257SDavid Jeffery 	return list_empty(work_q);
14203eef6257SDavid Jeffery }
14213eef6257SDavid Jeffery 
14221da177e4SLinus Torvalds /**
14231da177e4SLinus Torvalds  * scsi_eh_try_stu - Send START_UNIT to device.
1424eb44820cSRob Landley  * @scmd:	&scsi_cmnd to send START_UNIT
14251da177e4SLinus Torvalds  *
14261da177e4SLinus Torvalds  * Return value:
14271da177e4SLinus Torvalds  *    0 - Device is ready. 1 - Device NOT ready.
1428dc8875e1SRandy Dunlap  */
14291da177e4SLinus Torvalds static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
14301da177e4SLinus Torvalds {
14311da177e4SLinus Torvalds 	static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
14321da177e4SLinus Torvalds 
1433631c228cSChristoph Hellwig 	if (scmd->device->allow_restart) {
1434b8e162f9SBart Van Assche 		int i;
1435b8e162f9SBart Van Assche 		enum scsi_disposition rtn = NEEDS_RETRY;
14361da177e4SLinus Torvalds 
1437ed773e66SBrian King 		for (i = 0; rtn == NEEDS_RETRY && i < 2; i++)
1438adcc796bSChunguang Xu 			rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
1439adcc796bSChunguang Xu 						scmd->device->eh_timeout, 0);
1440ed773e66SBrian King 
14411da177e4SLinus Torvalds 		if (rtn == SUCCESS)
14421da177e4SLinus Torvalds 			return 0;
1443631c228cSChristoph Hellwig 	}
1444631c228cSChristoph Hellwig 
14451da177e4SLinus Torvalds 	return 1;
14461da177e4SLinus Torvalds }
14471da177e4SLinus Torvalds 
14481da177e4SLinus Torvalds  /**
14491da177e4SLinus Torvalds  * scsi_eh_stu - send START_UNIT if needed
1450eb44820cSRob Landley  * @shost:	&scsi host being recovered.
1451eb44820cSRob Landley  * @work_q:	&list_head for pending commands.
1452eb44820cSRob Landley  * @done_q:	&list_head for processed commands.
14531da177e4SLinus Torvalds  *
14541da177e4SLinus Torvalds  * Notes:
14551da177e4SLinus Torvalds  *    If commands are failing due to not ready, initializing command required,
14561da177e4SLinus Torvalds  *	try revalidating the device, which will end up sending a start unit.
1457dc8875e1SRandy Dunlap  */
14581da177e4SLinus Torvalds static int scsi_eh_stu(struct Scsi_Host *shost,
14591da177e4SLinus Torvalds 			      struct list_head *work_q,
14601da177e4SLinus Torvalds 			      struct list_head *done_q)
14611da177e4SLinus Torvalds {
1462937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *stu_scmd, *next;
14631da177e4SLinus Torvalds 	struct scsi_device *sdev;
14641da177e4SLinus Torvalds 
14651da177e4SLinus Torvalds 	shost_for_each_device(sdev, shost) {
1466b4562022SHannes Reinecke 		if (scsi_host_eh_past_deadline(shost)) {
1467b4562022SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
1468a222b1e2SHannes Reinecke 				sdev_printk(KERN_INFO, sdev,
1469a222b1e2SHannes Reinecke 					    "%s: skip START_UNIT, past eh deadline\n",
1470a222b1e2SHannes Reinecke 					    current->comm));
14714dea170fSYe Bin 			scsi_device_put(sdev);
1472b4562022SHannes Reinecke 			break;
1473b4562022SHannes Reinecke 		}
14741da177e4SLinus Torvalds 		stu_scmd = NULL;
14751da177e4SLinus Torvalds 		list_for_each_entry(scmd, work_q, eh_entry)
14761da177e4SLinus Torvalds 			if (scmd->device == sdev && SCSI_SENSE_VALID(scmd) &&
14771da177e4SLinus Torvalds 			    scsi_check_sense(scmd) == FAILED ) {
14781da177e4SLinus Torvalds 				stu_scmd = scmd;
14791da177e4SLinus Torvalds 				break;
14801da177e4SLinus Torvalds 			}
14811da177e4SLinus Torvalds 
14821da177e4SLinus Torvalds 		if (!stu_scmd)
14831da177e4SLinus Torvalds 			continue;
14841da177e4SLinus Torvalds 
148591921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
1486a222b1e2SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
1487a222b1e2SHannes Reinecke 				     "%s: Sending START_UNIT\n",
1488a222b1e2SHannes Reinecke 				    current->comm));
14891da177e4SLinus Torvalds 
14901da177e4SLinus Torvalds 		if (!scsi_eh_try_stu(stu_scmd)) {
14911da177e4SLinus Torvalds 			if (!scsi_device_online(sdev) ||
14921da177e4SLinus Torvalds 			    !scsi_eh_tur(stu_scmd)) {
1493937abeaaSChristoph Hellwig 				list_for_each_entry_safe(scmd, next,
1494937abeaaSChristoph Hellwig 							  work_q, eh_entry) {
14952451079bSJames Bottomley 					if (scmd->device == sdev &&
14962451079bSJames Bottomley 					    scsi_eh_action(scmd, SUCCESS) == SUCCESS)
14971da177e4SLinus Torvalds 						scsi_eh_finish_cmd(scmd, done_q);
14981da177e4SLinus Torvalds 				}
14991da177e4SLinus Torvalds 			}
15001da177e4SLinus Torvalds 		} else {
15011da177e4SLinus Torvalds 			SCSI_LOG_ERROR_RECOVERY(3,
1502a222b1e2SHannes Reinecke 				sdev_printk(KERN_INFO, sdev,
1503a222b1e2SHannes Reinecke 					    "%s: START_UNIT failed\n",
1504a222b1e2SHannes Reinecke 					    current->comm));
15051da177e4SLinus Torvalds 		}
15061da177e4SLinus Torvalds 	}
15071da177e4SLinus Torvalds 
15081da177e4SLinus Torvalds 	return list_empty(work_q);
15091da177e4SLinus Torvalds }
15101da177e4SLinus Torvalds 
15111da177e4SLinus Torvalds 
15121da177e4SLinus Torvalds /**
15131da177e4SLinus Torvalds  * scsi_eh_bus_device_reset - send bdr if needed
15141da177e4SLinus Torvalds  * @shost:	scsi host being recovered.
1515eb44820cSRob Landley  * @work_q:	&list_head for pending commands.
1516eb44820cSRob Landley  * @done_q:	&list_head for processed commands.
15171da177e4SLinus Torvalds  *
15181da177e4SLinus Torvalds  * Notes:
1519eb44820cSRob Landley  *    Try a bus device reset.  Still, look to see whether we have multiple
15201da177e4SLinus Torvalds  *    devices that are jammed or not - if we have multiple devices, it
15211da177e4SLinus Torvalds  *    makes no sense to try bus_device_reset - we really would need to try
15221da177e4SLinus Torvalds  *    a bus_reset instead.
1523dc8875e1SRandy Dunlap  */
15241da177e4SLinus Torvalds static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
15251da177e4SLinus Torvalds 				    struct list_head *work_q,
15261da177e4SLinus Torvalds 				    struct list_head *done_q)
15271da177e4SLinus Torvalds {
1528937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *bdr_scmd, *next;
15291da177e4SLinus Torvalds 	struct scsi_device *sdev;
1530b8e162f9SBart Van Assche 	enum scsi_disposition rtn;
15311da177e4SLinus Torvalds 
15321da177e4SLinus Torvalds 	shost_for_each_device(sdev, shost) {
1533b4562022SHannes Reinecke 		if (scsi_host_eh_past_deadline(shost)) {
1534b4562022SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
1535a222b1e2SHannes Reinecke 				sdev_printk(KERN_INFO, sdev,
1536a222b1e2SHannes Reinecke 					    "%s: skip BDR, past eh deadline\n",
1537a222b1e2SHannes Reinecke 					     current->comm));
15384dea170fSYe Bin 			scsi_device_put(sdev);
1539b4562022SHannes Reinecke 			break;
1540b4562022SHannes Reinecke 		}
15411da177e4SLinus Torvalds 		bdr_scmd = NULL;
15421da177e4SLinus Torvalds 		list_for_each_entry(scmd, work_q, eh_entry)
15431da177e4SLinus Torvalds 			if (scmd->device == sdev) {
15441da177e4SLinus Torvalds 				bdr_scmd = scmd;
15451da177e4SLinus Torvalds 				break;
15461da177e4SLinus Torvalds 			}
15471da177e4SLinus Torvalds 
15481da177e4SLinus Torvalds 		if (!bdr_scmd)
15491da177e4SLinus Torvalds 			continue;
15501da177e4SLinus Torvalds 
155191921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
1552a222b1e2SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
1553a222b1e2SHannes Reinecke 				     "%s: Sending BDR\n", current->comm));
15541da177e4SLinus Torvalds 		rtn = scsi_try_bus_device_reset(bdr_scmd);
15552f2eb587SChristof Schmitt 		if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
15561da177e4SLinus Torvalds 			if (!scsi_device_online(sdev) ||
15572f2eb587SChristof Schmitt 			    rtn == FAST_IO_FAIL ||
15581da177e4SLinus Torvalds 			    !scsi_eh_tur(bdr_scmd)) {
1559937abeaaSChristoph Hellwig 				list_for_each_entry_safe(scmd, next,
1560937abeaaSChristoph Hellwig 							 work_q, eh_entry) {
15612451079bSJames Bottomley 					if (scmd->device == sdev &&
15622451079bSJames Bottomley 					    scsi_eh_action(scmd, rtn) != FAILED)
15631da177e4SLinus Torvalds 						scsi_eh_finish_cmd(scmd,
15641da177e4SLinus Torvalds 								   done_q);
15651da177e4SLinus Torvalds 				}
15661da177e4SLinus Torvalds 			}
15671da177e4SLinus Torvalds 		} else {
156891921e01SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
1569a222b1e2SHannes Reinecke 				sdev_printk(KERN_INFO, sdev,
1570a222b1e2SHannes Reinecke 					    "%s: BDR failed\n", current->comm));
15711da177e4SLinus Torvalds 		}
15721da177e4SLinus Torvalds 	}
15731da177e4SLinus Torvalds 
15741da177e4SLinus Torvalds 	return list_empty(work_q);
15751da177e4SLinus Torvalds }
15761da177e4SLinus Torvalds 
15771da177e4SLinus Torvalds /**
157830bd7df8SMike Christie  * scsi_eh_target_reset - send target reset if needed
157930bd7df8SMike Christie  * @shost:	scsi host being recovered.
158030bd7df8SMike Christie  * @work_q:	&list_head for pending commands.
158130bd7df8SMike Christie  * @done_q:	&list_head for processed commands.
158230bd7df8SMike Christie  *
158330bd7df8SMike Christie  * Notes:
158430bd7df8SMike Christie  *    Try a target reset.
158530bd7df8SMike Christie  */
158630bd7df8SMike Christie static int scsi_eh_target_reset(struct Scsi_Host *shost,
158730bd7df8SMike Christie 				struct list_head *work_q,
158830bd7df8SMike Christie 				struct list_head *done_q)
158930bd7df8SMike Christie {
159098db5195SJames Bottomley 	LIST_HEAD(tmp_list);
15913eef6257SDavid Jeffery 	LIST_HEAD(check_list);
159230bd7df8SMike Christie 
159398db5195SJames Bottomley 	list_splice_init(work_q, &tmp_list);
159498db5195SJames Bottomley 
159598db5195SJames Bottomley 	while (!list_empty(&tmp_list)) {
159698db5195SJames Bottomley 		struct scsi_cmnd *next, *scmd;
1597b8e162f9SBart Van Assche 		enum scsi_disposition rtn;
159898db5195SJames Bottomley 		unsigned int id;
1599b4562022SHannes Reinecke 
1600b4562022SHannes Reinecke 		if (scsi_host_eh_past_deadline(shost)) {
1601b4562022SHannes Reinecke 			/* push back on work queue for further processing */
1602b4562022SHannes Reinecke 			list_splice_init(&check_list, work_q);
1603b4562022SHannes Reinecke 			list_splice_init(&tmp_list, work_q);
1604b4562022SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
1605b4562022SHannes Reinecke 				shost_printk(KERN_INFO, shost,
1606a222b1e2SHannes Reinecke 					    "%s: Skip target reset, past eh deadline\n",
1607a222b1e2SHannes Reinecke 					     current->comm));
1608b4562022SHannes Reinecke 			return list_empty(work_q);
1609b4562022SHannes Reinecke 		}
161098db5195SJames Bottomley 
161198db5195SJames Bottomley 		scmd = list_entry(tmp_list.next, struct scsi_cmnd, eh_entry);
161298db5195SJames Bottomley 		id = scmd_id(scmd);
161330bd7df8SMike Christie 
161491921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
161591921e01SHannes Reinecke 			shost_printk(KERN_INFO, shost,
161691921e01SHannes Reinecke 				     "%s: Sending target reset to target %d\n",
161730bd7df8SMike Christie 				     current->comm, id));
161898db5195SJames Bottomley 		rtn = scsi_try_target_reset(scmd);
161998db5195SJames Bottomley 		if (rtn != SUCCESS && rtn != FAST_IO_FAIL)
162091921e01SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
162191921e01SHannes Reinecke 				shost_printk(KERN_INFO, shost,
162291921e01SHannes Reinecke 					     "%s: Target reset failed"
162391921e01SHannes Reinecke 					     " target: %d\n",
162430bd7df8SMike Christie 					     current->comm, id));
162598db5195SJames Bottomley 		list_for_each_entry_safe(scmd, next, &tmp_list, eh_entry) {
162698db5195SJames Bottomley 			if (scmd_id(scmd) != id)
162798db5195SJames Bottomley 				continue;
162898db5195SJames Bottomley 
16293eef6257SDavid Jeffery 			if (rtn == SUCCESS)
16303eef6257SDavid Jeffery 				list_move_tail(&scmd->eh_entry, &check_list);
16313eef6257SDavid Jeffery 			else if (rtn == FAST_IO_FAIL)
163298db5195SJames Bottomley 				scsi_eh_finish_cmd(scmd, done_q);
163398db5195SJames Bottomley 			else
163498db5195SJames Bottomley 				/* push back on work queue for further processing */
163598db5195SJames Bottomley 				list_move(&scmd->eh_entry, work_q);
163698db5195SJames Bottomley 		}
163798db5195SJames Bottomley 	}
163830bd7df8SMike Christie 
16393eef6257SDavid Jeffery 	return scsi_eh_test_devices(&check_list, work_q, done_q, 0);
164030bd7df8SMike Christie }
164130bd7df8SMike Christie 
164230bd7df8SMike Christie /**
16431da177e4SLinus Torvalds  * scsi_eh_bus_reset - send a bus reset
1644eb44820cSRob Landley  * @shost:	&scsi host being recovered.
1645eb44820cSRob Landley  * @work_q:	&list_head for pending commands.
1646eb44820cSRob Landley  * @done_q:	&list_head for processed commands.
1647dc8875e1SRandy Dunlap  */
16481da177e4SLinus Torvalds static int scsi_eh_bus_reset(struct Scsi_Host *shost,
16491da177e4SLinus Torvalds 			     struct list_head *work_q,
16501da177e4SLinus Torvalds 			     struct list_head *done_q)
16511da177e4SLinus Torvalds {
1652937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *chan_scmd, *next;
16533eef6257SDavid Jeffery 	LIST_HEAD(check_list);
16541da177e4SLinus Torvalds 	unsigned int channel;
1655b8e162f9SBart Van Assche 	enum scsi_disposition rtn;
16561da177e4SLinus Torvalds 
16571da177e4SLinus Torvalds 	/*
16581da177e4SLinus Torvalds 	 * we really want to loop over the various channels, and do this on
16591da177e4SLinus Torvalds 	 * a channel by channel basis.  we should also check to see if any
16601da177e4SLinus Torvalds 	 * of the failed commands are on soft_reset devices, and if so, skip
16611da177e4SLinus Torvalds 	 * the reset.
16621da177e4SLinus Torvalds 	 */
16631da177e4SLinus Torvalds 
16641da177e4SLinus Torvalds 	for (channel = 0; channel <= shost->max_channel; channel++) {
1665b4562022SHannes Reinecke 		if (scsi_host_eh_past_deadline(shost)) {
1666b4562022SHannes Reinecke 			list_splice_init(&check_list, work_q);
1667b4562022SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
1668b4562022SHannes Reinecke 				shost_printk(KERN_INFO, shost,
1669a222b1e2SHannes Reinecke 					    "%s: skip BRST, past eh deadline\n",
1670a222b1e2SHannes Reinecke 					     current->comm));
1671b4562022SHannes Reinecke 			return list_empty(work_q);
1672b4562022SHannes Reinecke 		}
1673b4562022SHannes Reinecke 
16741da177e4SLinus Torvalds 		chan_scmd = NULL;
16751da177e4SLinus Torvalds 		list_for_each_entry(scmd, work_q, eh_entry) {
1676422c0d61SJeff Garzik 			if (channel == scmd_channel(scmd)) {
16771da177e4SLinus Torvalds 				chan_scmd = scmd;
16781da177e4SLinus Torvalds 				break;
16791da177e4SLinus Torvalds 				/*
16801da177e4SLinus Torvalds 				 * FIXME add back in some support for
16811da177e4SLinus Torvalds 				 * soft_reset devices.
16821da177e4SLinus Torvalds 				 */
16831da177e4SLinus Torvalds 			}
16841da177e4SLinus Torvalds 		}
16851da177e4SLinus Torvalds 
16861da177e4SLinus Torvalds 		if (!chan_scmd)
16871da177e4SLinus Torvalds 			continue;
168891921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
168991921e01SHannes Reinecke 			shost_printk(KERN_INFO, shost,
169091921e01SHannes Reinecke 				     "%s: Sending BRST chan: %d\n",
169191921e01SHannes Reinecke 				     current->comm, channel));
16921da177e4SLinus Torvalds 		rtn = scsi_try_bus_reset(chan_scmd);
16932f2eb587SChristof Schmitt 		if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
1694937abeaaSChristoph Hellwig 			list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
16953eef6257SDavid Jeffery 				if (channel == scmd_channel(scmd)) {
16963eef6257SDavid Jeffery 					if (rtn == FAST_IO_FAIL)
16971da177e4SLinus Torvalds 						scsi_eh_finish_cmd(scmd,
16981da177e4SLinus Torvalds 								   done_q);
16993eef6257SDavid Jeffery 					else
17003eef6257SDavid Jeffery 						list_move_tail(&scmd->eh_entry,
17013eef6257SDavid Jeffery 							       &check_list);
17023eef6257SDavid Jeffery 				}
17031da177e4SLinus Torvalds 			}
17041da177e4SLinus Torvalds 		} else {
170591921e01SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
170691921e01SHannes Reinecke 				shost_printk(KERN_INFO, shost,
170791921e01SHannes Reinecke 					     "%s: BRST failed chan: %d\n",
170891921e01SHannes Reinecke 					     current->comm, channel));
17091da177e4SLinus Torvalds 		}
17101da177e4SLinus Torvalds 	}
17113eef6257SDavid Jeffery 	return scsi_eh_test_devices(&check_list, work_q, done_q, 0);
17121da177e4SLinus Torvalds }
17131da177e4SLinus Torvalds 
17141da177e4SLinus Torvalds /**
17151da177e4SLinus Torvalds  * scsi_eh_host_reset - send a host reset
171674cf298fSRandy Dunlap  * @shost:	host to be reset.
171774cf298fSRandy Dunlap  * @work_q:	&list_head for pending commands.
171874cf298fSRandy Dunlap  * @done_q:	&list_head for processed commands.
1719dc8875e1SRandy Dunlap  */
172091921e01SHannes Reinecke static int scsi_eh_host_reset(struct Scsi_Host *shost,
172191921e01SHannes Reinecke 			      struct list_head *work_q,
17221da177e4SLinus Torvalds 			      struct list_head *done_q)
17231da177e4SLinus Torvalds {
1724937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *next;
17253eef6257SDavid Jeffery 	LIST_HEAD(check_list);
1726b8e162f9SBart Van Assche 	enum scsi_disposition rtn;
17271da177e4SLinus Torvalds 
17281da177e4SLinus Torvalds 	if (!list_empty(work_q)) {
17291da177e4SLinus Torvalds 		scmd = list_entry(work_q->next,
17301da177e4SLinus Torvalds 				  struct scsi_cmnd, eh_entry);
17311da177e4SLinus Torvalds 
173291921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
173391921e01SHannes Reinecke 			shost_printk(KERN_INFO, shost,
173491921e01SHannes Reinecke 				     "%s: Sending HRST\n",
173591921e01SHannes Reinecke 				     current->comm));
17361da177e4SLinus Torvalds 
17371da177e4SLinus Torvalds 		rtn = scsi_try_host_reset(scmd);
17383eef6257SDavid Jeffery 		if (rtn == SUCCESS) {
17393eef6257SDavid Jeffery 			list_splice_init(work_q, &check_list);
17403eef6257SDavid Jeffery 		} else if (rtn == FAST_IO_FAIL) {
1741937abeaaSChristoph Hellwig 			list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
17421da177e4SLinus Torvalds 					scsi_eh_finish_cmd(scmd, done_q);
17431da177e4SLinus Torvalds 			}
17441da177e4SLinus Torvalds 		} else {
174591921e01SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
174691921e01SHannes Reinecke 				shost_printk(KERN_INFO, shost,
174791921e01SHannes Reinecke 					     "%s: HRST failed\n",
17481da177e4SLinus Torvalds 					     current->comm));
17491da177e4SLinus Torvalds 		}
17501da177e4SLinus Torvalds 	}
17513eef6257SDavid Jeffery 	return scsi_eh_test_devices(&check_list, work_q, done_q, 1);
17521da177e4SLinus Torvalds }
17531da177e4SLinus Torvalds 
17541da177e4SLinus Torvalds /**
17551da177e4SLinus Torvalds  * scsi_eh_offline_sdevs - offline scsi devices that fail to recover
175674cf298fSRandy Dunlap  * @work_q:	&list_head for pending commands.
175774cf298fSRandy Dunlap  * @done_q:	&list_head for processed commands.
1758dc8875e1SRandy Dunlap  */
17591da177e4SLinus Torvalds static void scsi_eh_offline_sdevs(struct list_head *work_q,
17601da177e4SLinus Torvalds 				  struct list_head *done_q)
17611da177e4SLinus Torvalds {
1762937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *next;
17630db6ca8aSBart Van Assche 	struct scsi_device *sdev;
17641da177e4SLinus Torvalds 
1765937abeaaSChristoph Hellwig 	list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
176631765d7dSMatthew Wilcox 		sdev_printk(KERN_INFO, scmd->device, "Device offlined - "
176731765d7dSMatthew Wilcox 			    "not ready after error recovery\n");
17680db6ca8aSBart Van Assche 		sdev = scmd->device;
17690db6ca8aSBart Van Assche 
17700db6ca8aSBart Van Assche 		mutex_lock(&sdev->state_mutex);
17710db6ca8aSBart Van Assche 		scsi_device_set_state(sdev, SDEV_OFFLINE);
17720db6ca8aSBart Van Assche 		mutex_unlock(&sdev->state_mutex);
17730db6ca8aSBart Van Assche 
17741da177e4SLinus Torvalds 		scsi_eh_finish_cmd(scmd, done_q);
17751da177e4SLinus Torvalds 	}
17761da177e4SLinus Torvalds 	return;
17771da177e4SLinus Torvalds }
17781da177e4SLinus Torvalds 
17791da177e4SLinus Torvalds /**
1780e494f6a7SHannes Reinecke  * scsi_noretry_cmd - determine if command should be failed fast
17814a27446fSMike Christie  * @scmd:	SCSI cmd to examine.
17824a27446fSMike Christie  */
178388b32c3cSBart Van Assche bool scsi_noretry_cmd(struct scsi_cmnd *scmd)
17844a27446fSMike Christie {
1785aa8e25e5SBart Van Assche 	struct request *req = scsi_cmd_to_rq(scmd);
1786aa8e25e5SBart Van Assche 
17874a27446fSMike Christie 	switch (host_byte(scmd->result)) {
17884a27446fSMike Christie 	case DID_OK:
17894a27446fSMike Christie 		break;
1790e494f6a7SHannes Reinecke 	case DID_TIME_OUT:
1791e494f6a7SHannes Reinecke 		goto check_type;
17924a27446fSMike Christie 	case DID_BUS_BUSY:
179388b32c3cSBart Van Assche 		return !!(req->cmd_flags & REQ_FAILFAST_TRANSPORT);
17944a27446fSMike Christie 	case DID_PARITY:
179588b32c3cSBart Van Assche 		return !!(req->cmd_flags & REQ_FAILFAST_DEV);
17964a27446fSMike Christie 	case DID_ERROR:
17973d45cefcSHannes Reinecke 		if (get_status_byte(scmd) == SAM_STAT_RESERVATION_CONFLICT)
179888b32c3cSBart Van Assche 			return false;
1799df561f66SGustavo A. R. Silva 		fallthrough;
18004a27446fSMike Christie 	case DID_SOFT_ERROR:
180188b32c3cSBart Van Assche 		return !!(req->cmd_flags & REQ_FAILFAST_DRIVER);
18024a27446fSMike Christie 	}
18034a27446fSMike Christie 
1804d0672a03SHannes Reinecke 	if (!scsi_status_is_check_condition(scmd->result))
180588b32c3cSBart Van Assche 		return false;
1806e494f6a7SHannes Reinecke 
1807e494f6a7SHannes Reinecke check_type:
18084a27446fSMike Christie 	/*
1809e494f6a7SHannes Reinecke 	 * assume caller has checked sense and determined
18104a27446fSMike Christie 	 * the check condition was retryable.
18114a27446fSMike Christie 	 */
1812aa8e25e5SBart Van Assche 	if (req->cmd_flags & REQ_FAILFAST_DEV || blk_rq_is_passthrough(req))
181388b32c3cSBart Van Assche 		return true;
1814342c81eeSDamien Le Moal 
181588b32c3cSBart Van Assche 	return false;
18164a27446fSMike Christie }
18174a27446fSMike Christie 
18184a27446fSMike Christie /**
18191da177e4SLinus Torvalds  * scsi_decide_disposition - Disposition a cmd on return from LLD.
18201da177e4SLinus Torvalds  * @scmd:	SCSI cmd to examine.
18211da177e4SLinus Torvalds  *
18221da177e4SLinus Torvalds  * Notes:
18231da177e4SLinus Torvalds  *    This is *only* called when we are examining the status after sending
18241da177e4SLinus Torvalds  *    out the actual data command.  any commands that are queued for error
18251da177e4SLinus Torvalds  *    recovery (e.g. test_unit_ready) do *not* come through here.
18261da177e4SLinus Torvalds  *
18271da177e4SLinus Torvalds  *    When this routine returns failed, it means the error handler thread
18281da177e4SLinus Torvalds  *    is woken.  In cases where the error code indicates an error that
18291da177e4SLinus Torvalds  *    doesn't require the error handler read (i.e. we don't need to
18301da177e4SLinus Torvalds  *    abort/reset), this function should return SUCCESS.
1831dc8875e1SRandy Dunlap  */
1832b8e162f9SBart Van Assche enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *scmd)
18331da177e4SLinus Torvalds {
1834b8e162f9SBart Van Assche 	enum scsi_disposition rtn;
18351da177e4SLinus Torvalds 
18361da177e4SLinus Torvalds 	/*
18371da177e4SLinus Torvalds 	 * if the device is offline, then we clearly just pass the result back
18381da177e4SLinus Torvalds 	 * up to the top level.
18391da177e4SLinus Torvalds 	 */
18401da177e4SLinus Torvalds 	if (!scsi_device_online(scmd->device)) {
184191921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(5, scmd_printk(KERN_INFO, scmd,
184291921e01SHannes Reinecke 			"%s: device offline - report as SUCCESS\n", __func__));
18431da177e4SLinus Torvalds 		return SUCCESS;
18441da177e4SLinus Torvalds 	}
18451da177e4SLinus Torvalds 
18461da177e4SLinus Torvalds 	/*
18471da177e4SLinus Torvalds 	 * first check the host byte, to see if there is anything in there
18481da177e4SLinus Torvalds 	 * that would indicate what we need to do.
18491da177e4SLinus Torvalds 	 */
18501da177e4SLinus Torvalds 	switch (host_byte(scmd->result)) {
18511da177e4SLinus Torvalds 	case DID_PASSTHROUGH:
18521da177e4SLinus Torvalds 		/*
18531da177e4SLinus Torvalds 		 * no matter what, pass this through to the upper layer.
18541da177e4SLinus Torvalds 		 * nuke this special code so that it looks like we are saying
18551da177e4SLinus Torvalds 		 * did_ok.
18561da177e4SLinus Torvalds 		 */
18571da177e4SLinus Torvalds 		scmd->result &= 0xff00ffff;
18581da177e4SLinus Torvalds 		return SUCCESS;
18591da177e4SLinus Torvalds 	case DID_OK:
18601da177e4SLinus Torvalds 		/*
18611da177e4SLinus Torvalds 		 * looks good.  drop through, and check the next byte.
18621da177e4SLinus Torvalds 		 */
18631da177e4SLinus Torvalds 		break;
1864e494f6a7SHannes Reinecke 	case DID_ABORT:
1865e494f6a7SHannes Reinecke 		if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) {
18668922a908SUlrich Obergfell 			set_host_byte(scmd, DID_TIME_OUT);
1867e494f6a7SHannes Reinecke 			return SUCCESS;
1868e494f6a7SHannes Reinecke 		}
1869df561f66SGustavo A. R. Silva 		fallthrough;
18701da177e4SLinus Torvalds 	case DID_NO_CONNECT:
18711da177e4SLinus Torvalds 	case DID_BAD_TARGET:
18721da177e4SLinus Torvalds 		/*
18731da177e4SLinus Torvalds 		 * note - this means that we just report the status back
18741da177e4SLinus Torvalds 		 * to the top level driver, not that we actually think
18751da177e4SLinus Torvalds 		 * that it indicates SUCCESS.
18761da177e4SLinus Torvalds 		 */
18771da177e4SLinus Torvalds 		return SUCCESS;
1878ad95028aSPetros Koutoupis 	case DID_SOFT_ERROR:
18791da177e4SLinus Torvalds 		/*
18801da177e4SLinus Torvalds 		 * when the low level driver returns did_soft_error,
18811da177e4SLinus Torvalds 		 * it is responsible for keeping an internal retry counter
18821da177e4SLinus Torvalds 		 * in order to avoid endless loops (db)
18831da177e4SLinus Torvalds 		 */
18841da177e4SLinus Torvalds 		goto maybe_retry;
18851da177e4SLinus Torvalds 	case DID_IMM_RETRY:
18861da177e4SLinus Torvalds 		return NEEDS_RETRY;
18871da177e4SLinus Torvalds 
1888bf341919S 	case DID_REQUEUE:
1889bf341919S 		return ADD_TO_MLQUEUE;
1890a4dfaa6fSMike Christie 	case DID_TRANSPORT_DISRUPTED:
1891a4dfaa6fSMike Christie 		/*
1892a4dfaa6fSMike Christie 		 * LLD/transport was disrupted during processing of the IO.
1893a4dfaa6fSMike Christie 		 * The transport class is now blocked/blocking,
1894a4dfaa6fSMike Christie 		 * and the transport will decide what to do with the IO
1895939c2288SMike Christie 		 * based on its timers and recovery capablilities if
1896939c2288SMike Christie 		 * there are enough retries.
1897a4dfaa6fSMike Christie 		 */
1898939c2288SMike Christie 		goto maybe_retry;
1899a4dfaa6fSMike Christie 	case DID_TRANSPORT_FAILFAST:
1900a4dfaa6fSMike Christie 		/*
1901a4dfaa6fSMike Christie 		 * The transport decided to failfast the IO (most likely
1902a4dfaa6fSMike Christie 		 * the fast io fail tmo fired), so send IO directly upwards.
1903a4dfaa6fSMike Christie 		 */
1904a4dfaa6fSMike Christie 		return SUCCESS;
1905962c8dcdSMuneendra Kumar 	case DID_TRANSPORT_MARGINAL:
1906962c8dcdSMuneendra Kumar 		/*
1907962c8dcdSMuneendra Kumar 		 * caller has decided not to do retries on
1908962c8dcdSMuneendra Kumar 		 * abort success, so send IO directly upwards
1909962c8dcdSMuneendra Kumar 		 */
1910962c8dcdSMuneendra Kumar 		return SUCCESS;
19111da177e4SLinus Torvalds 	case DID_ERROR:
19123d45cefcSHannes Reinecke 		if (get_status_byte(scmd) == SAM_STAT_RESERVATION_CONFLICT)
19131da177e4SLinus Torvalds 			/*
19141da177e4SLinus Torvalds 			 * execute reservation conflict processing code
19151da177e4SLinus Torvalds 			 * lower down
19161da177e4SLinus Torvalds 			 */
19171da177e4SLinus Torvalds 			break;
1918df561f66SGustavo A. R. Silva 		fallthrough;
19191da177e4SLinus Torvalds 	case DID_BUS_BUSY:
19201da177e4SLinus Torvalds 	case DID_PARITY:
19211da177e4SLinus Torvalds 		goto maybe_retry;
19221da177e4SLinus Torvalds 	case DID_TIME_OUT:
19231da177e4SLinus Torvalds 		/*
19241da177e4SLinus Torvalds 		 * when we scan the bus, we get timeout messages for
19251da177e4SLinus Torvalds 		 * these commands if there is no device available.
19261da177e4SLinus Torvalds 		 * other hosts report did_no_connect for the same thing.
19271da177e4SLinus Torvalds 		 */
19281da177e4SLinus Torvalds 		if ((scmd->cmnd[0] == TEST_UNIT_READY ||
19291da177e4SLinus Torvalds 		     scmd->cmnd[0] == INQUIRY)) {
19301da177e4SLinus Torvalds 			return SUCCESS;
19311da177e4SLinus Torvalds 		} else {
19321da177e4SLinus Torvalds 			return FAILED;
19331da177e4SLinus Torvalds 		}
19341da177e4SLinus Torvalds 	case DID_RESET:
19351da177e4SLinus Torvalds 		return SUCCESS;
19361da177e4SLinus Torvalds 	default:
19371da177e4SLinus Torvalds 		return FAILED;
19381da177e4SLinus Torvalds 	}
19391da177e4SLinus Torvalds 
19401da177e4SLinus Torvalds 	/*
19411da177e4SLinus Torvalds 	 * check the status byte to see if this indicates anything special.
19421da177e4SLinus Torvalds 	 */
19433d45cefcSHannes Reinecke 	switch (get_status_byte(scmd)) {
19443d45cefcSHannes Reinecke 	case SAM_STAT_TASK_SET_FULL:
194542a6a918SMike Christie 		scsi_handle_queue_full(scmd->device);
19461da177e4SLinus Torvalds 		/*
19471da177e4SLinus Torvalds 		 * the case of trying to send too many commands to a
19481da177e4SLinus Torvalds 		 * tagged queueing device.
19491da177e4SLinus Torvalds 		 */
1950df561f66SGustavo A. R. Silva 		fallthrough;
19513d45cefcSHannes Reinecke 	case SAM_STAT_BUSY:
19521da177e4SLinus Torvalds 		/*
19531da177e4SLinus Torvalds 		 * device can't talk to us at the moment.  Should only
19541da177e4SLinus Torvalds 		 * occur (SAM-3) when the task queue is empty, so will cause
19551da177e4SLinus Torvalds 		 * the empty queue handling to trigger a stall in the
19561da177e4SLinus Torvalds 		 * device.
19571da177e4SLinus Torvalds 		 */
19581da177e4SLinus Torvalds 		return ADD_TO_MLQUEUE;
19593d45cefcSHannes Reinecke 	case SAM_STAT_GOOD:
1960279afdfeSEwan D. Milne 		if (scmd->cmnd[0] == REPORT_LUNS)
1961279afdfeSEwan D. Milne 			scmd->device->sdev_target->expecting_lun_change = 0;
19624a84067dSVasu Dev 		scsi_handle_queue_ramp_up(scmd->device);
1963df561f66SGustavo A. R. Silva 		fallthrough;
19643d45cefcSHannes Reinecke 	case SAM_STAT_COMMAND_TERMINATED:
19651da177e4SLinus Torvalds 		return SUCCESS;
19663d45cefcSHannes Reinecke 	case SAM_STAT_TASK_ABORTED:
1967a9b589d9SVladislav Bolkhovitin 		goto maybe_retry;
19683d45cefcSHannes Reinecke 	case SAM_STAT_CHECK_CONDITION:
19691da177e4SLinus Torvalds 		rtn = scsi_check_sense(scmd);
19701da177e4SLinus Torvalds 		if (rtn == NEEDS_RETRY)
19711da177e4SLinus Torvalds 			goto maybe_retry;
19721da177e4SLinus Torvalds 		/* if rtn == FAILED, we have no sense information;
19731da177e4SLinus Torvalds 		 * returning FAILED will wake the error handler thread
19741da177e4SLinus Torvalds 		 * to collect the sense and redo the decide
19751da177e4SLinus Torvalds 		 * disposition */
19761da177e4SLinus Torvalds 		return rtn;
19773d45cefcSHannes Reinecke 	case SAM_STAT_CONDITION_MET:
19783d45cefcSHannes Reinecke 	case SAM_STAT_INTERMEDIATE:
19793d45cefcSHannes Reinecke 	case SAM_STAT_INTERMEDIATE_CONDITION_MET:
19803d45cefcSHannes Reinecke 	case SAM_STAT_ACA_ACTIVE:
19811da177e4SLinus Torvalds 		/*
19821da177e4SLinus Torvalds 		 * who knows?  FIXME(eric)
19831da177e4SLinus Torvalds 		 */
19841da177e4SLinus Torvalds 		return SUCCESS;
19851da177e4SLinus Torvalds 
19863d45cefcSHannes Reinecke 	case SAM_STAT_RESERVATION_CONFLICT:
19879ccfc756SJames Bottomley 		sdev_printk(KERN_INFO, scmd->device,
19889ccfc756SJames Bottomley 			    "reservation conflict\n");
19897dfaae6aSMike Christie 		set_scsi_ml_byte(scmd, SCSIML_STAT_RESV_CONFLICT);
19901da177e4SLinus Torvalds 		return SUCCESS; /* causes immediate i/o error */
19911da177e4SLinus Torvalds 	}
19921da177e4SLinus Torvalds 	return FAILED;
19931da177e4SLinus Torvalds 
19941da177e4SLinus Torvalds maybe_retry:
19951da177e4SLinus Torvalds 
19961da177e4SLinus Torvalds 	/* we requeue for retry because the error was retryable, and
19971da177e4SLinus Torvalds 	 * the request was not marked fast fail.  Note that above,
19981da177e4SLinus Torvalds 	 * even if the request is marked fast fail, we still requeue
19991da177e4SLinus Torvalds 	 * for queue congestion conditions (QUEUE_FULL or BUSY) */
20002a242d59SMike Christie 	if (scsi_cmd_retry_allowed(scmd) && !scsi_noretry_cmd(scmd)) {
20011da177e4SLinus Torvalds 		return NEEDS_RETRY;
20021da177e4SLinus Torvalds 	} else {
20031da177e4SLinus Torvalds 		/*
20041da177e4SLinus Torvalds 		 * no more retries - report this one back to upper level.
20051da177e4SLinus Torvalds 		 */
20061da177e4SLinus Torvalds 		return SUCCESS;
20071da177e4SLinus Torvalds 	}
20081da177e4SLinus Torvalds }
20091da177e4SLinus Torvalds 
2010de671d61SJens Axboe static enum rq_end_io_ret eh_lock_door_done(struct request *req,
2011de671d61SJens Axboe 					    blk_status_t status)
2012f078727bSFUJITA Tomonori {
20130bf6d96cSChristoph Hellwig 	blk_mq_free_request(req);
2014de671d61SJens Axboe 	return RQ_END_IO_NONE;
2015f078727bSFUJITA Tomonori }
2016f078727bSFUJITA Tomonori 
20171da177e4SLinus Torvalds /**
20181da177e4SLinus Torvalds  * scsi_eh_lock_door - Prevent medium removal for the specified device
20191da177e4SLinus Torvalds  * @sdev:	SCSI device to prevent medium removal
20201da177e4SLinus Torvalds  *
20211da177e4SLinus Torvalds  * Locking:
202291bc31fbSJames Bottomley  * 	We must be called from process context.
20231da177e4SLinus Torvalds  *
20241da177e4SLinus Torvalds  * Notes:
20251da177e4SLinus Torvalds  * 	We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request on the
20261da177e4SLinus Torvalds  * 	head of the devices request queue, and continue.
2027dc8875e1SRandy Dunlap  */
20281da177e4SLinus Torvalds static void scsi_eh_lock_door(struct scsi_device *sdev)
20291da177e4SLinus Torvalds {
2030ce70fd9aSChristoph Hellwig 	struct scsi_cmnd *scmd;
2031f078727bSFUJITA Tomonori 	struct request *req;
20321da177e4SLinus Torvalds 
203368ec3b81SChristoph Hellwig 	req = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN, 0);
2034a492f075SJoe Lawrence 	if (IS_ERR(req))
2035eb571eeaSJoe Lawrence 		return;
2036ce70fd9aSChristoph Hellwig 	scmd = blk_mq_rq_to_pdu(req);
20371da177e4SLinus Torvalds 
2038ce70fd9aSChristoph Hellwig 	scmd->cmnd[0] = ALLOW_MEDIUM_REMOVAL;
2039ce70fd9aSChristoph Hellwig 	scmd->cmnd[1] = 0;
2040ce70fd9aSChristoph Hellwig 	scmd->cmnd[2] = 0;
2041ce70fd9aSChristoph Hellwig 	scmd->cmnd[3] = 0;
2042ce70fd9aSChristoph Hellwig 	scmd->cmnd[4] = SCSI_REMOVAL_PREVENT;
2043ce70fd9aSChristoph Hellwig 	scmd->cmnd[5] = 0;
2044ce70fd9aSChristoph Hellwig 	scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
2045e2e53086SChristoph Hellwig 	scmd->allowed = 5;
2046f078727bSFUJITA Tomonori 
2047e8064021SChristoph Hellwig 	req->rq_flags |= RQF_QUIET;
2048f078727bSFUJITA Tomonori 	req->timeout = 10 * HZ;
2049e2e53086SChristoph Hellwig 	req->end_io = eh_lock_door_done;
2050f078727bSFUJITA Tomonori 
2051e2e53086SChristoph Hellwig 	blk_execute_rq_nowait(req, true);
20521da177e4SLinus Torvalds }
20531da177e4SLinus Torvalds 
20541da177e4SLinus Torvalds /**
20551da177e4SLinus Torvalds  * scsi_restart_operations - restart io operations to the specified host.
20561da177e4SLinus Torvalds  * @shost:	Host we are restarting.
20571da177e4SLinus Torvalds  *
20581da177e4SLinus Torvalds  * Notes:
20591da177e4SLinus Torvalds  *    When we entered the error handler, we blocked all further i/o to
20601da177e4SLinus Torvalds  *    this device.  we need to 'reverse' this process.
2061dc8875e1SRandy Dunlap  */
20621da177e4SLinus Torvalds static void scsi_restart_operations(struct Scsi_Host *shost)
20631da177e4SLinus Torvalds {
20641da177e4SLinus Torvalds 	struct scsi_device *sdev;
2065939647eeSJames Bottomley 	unsigned long flags;
20661da177e4SLinus Torvalds 
20671da177e4SLinus Torvalds 	/*
20681da177e4SLinus Torvalds 	 * If the door was locked, we need to insert a door lock request
20691da177e4SLinus Torvalds 	 * onto the head of the SCSI request queue for the device.  There
20701da177e4SLinus Torvalds 	 * is no point trying to lock the door of an off-line device.
20711da177e4SLinus Torvalds 	 */
20721da177e4SLinus Torvalds 	shost_for_each_device(sdev, shost) {
207348379270SChristoph Hellwig 		if (scsi_device_online(sdev) && sdev->was_reset && sdev->locked) {
20741da177e4SLinus Torvalds 			scsi_eh_lock_door(sdev);
207548379270SChristoph Hellwig 			sdev->was_reset = 0;
207648379270SChristoph Hellwig 		}
20771da177e4SLinus Torvalds 	}
20781da177e4SLinus Torvalds 
20791da177e4SLinus Torvalds 	/*
20801da177e4SLinus Torvalds 	 * next free up anything directly waiting upon the host.  this
20811da177e4SLinus Torvalds 	 * will be requests for character device operations, and also for
20821da177e4SLinus Torvalds 	 * ioctls to queued block devices.
20831da177e4SLinus Torvalds 	 */
2084b4562022SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3,
208591921e01SHannes Reinecke 		shost_printk(KERN_INFO, shost, "waking up host to restart\n"));
20861da177e4SLinus Torvalds 
2087939647eeSJames Bottomley 	spin_lock_irqsave(shost->host_lock, flags);
2088939647eeSJames Bottomley 	if (scsi_host_set_state(shost, SHOST_RUNNING))
2089939647eeSJames Bottomley 		if (scsi_host_set_state(shost, SHOST_CANCEL))
2090939647eeSJames Bottomley 			BUG_ON(scsi_host_set_state(shost, SHOST_DEL));
2091939647eeSJames Bottomley 	spin_unlock_irqrestore(shost->host_lock, flags);
20921da177e4SLinus Torvalds 
20931da177e4SLinus Torvalds 	wake_up(&shost->host_wait);
20941da177e4SLinus Torvalds 
20951da177e4SLinus Torvalds 	/*
20961da177e4SLinus Torvalds 	 * finally we need to re-initiate requests that may be pending.  we will
20971da177e4SLinus Torvalds 	 * have had everything blocked while error handling is taking place, and
20981da177e4SLinus Torvalds 	 * now that error recovery is done, we will need to ensure that these
20991da177e4SLinus Torvalds 	 * requests are started.
21001da177e4SLinus Torvalds 	 */
21011da177e4SLinus Torvalds 	scsi_run_host_queues(shost);
210257fc2e33SDan Williams 
210357fc2e33SDan Williams 	/*
210457fc2e33SDan Williams 	 * if eh is active and host_eh_scheduled is pending we need to re-run
210557fc2e33SDan Williams 	 * recovery.  we do this check after scsi_run_host_queues() to allow
210657fc2e33SDan Williams 	 * everything pent up since the last eh run a chance to make forward
210757fc2e33SDan Williams 	 * progress before we sync again.  Either we'll immediately re-run
210857fc2e33SDan Williams 	 * recovery or scsi_device_unbusy() will wake us again when these
210957fc2e33SDan Williams 	 * pending commands complete.
211057fc2e33SDan Williams 	 */
211157fc2e33SDan Williams 	spin_lock_irqsave(shost->host_lock, flags);
211257fc2e33SDan Williams 	if (shost->host_eh_scheduled)
211357fc2e33SDan Williams 		if (scsi_host_set_state(shost, SHOST_RECOVERY))
211457fc2e33SDan Williams 			WARN_ON(scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY));
211557fc2e33SDan Williams 	spin_unlock_irqrestore(shost->host_lock, flags);
21161da177e4SLinus Torvalds }
21171da177e4SLinus Torvalds 
21181da177e4SLinus Torvalds /**
21191da177e4SLinus Torvalds  * scsi_eh_ready_devs - check device ready state and recover if not.
21201da177e4SLinus Torvalds  * @shost:	host to be recovered.
2121eb44820cSRob Landley  * @work_q:	&list_head for pending commands.
2122eb44820cSRob Landley  * @done_q:	&list_head for processed commands.
2123dc8875e1SRandy Dunlap  */
2124dca84e46SDarrick J. Wong void scsi_eh_ready_devs(struct Scsi_Host *shost,
21251da177e4SLinus Torvalds 			struct list_head *work_q,
21261da177e4SLinus Torvalds 			struct list_head *done_q)
21271da177e4SLinus Torvalds {
21281da177e4SLinus Torvalds 	if (!scsi_eh_stu(shost, work_q, done_q))
21291da177e4SLinus Torvalds 		if (!scsi_eh_bus_device_reset(shost, work_q, done_q))
213030bd7df8SMike Christie 			if (!scsi_eh_target_reset(shost, work_q, done_q))
21311da177e4SLinus Torvalds 				if (!scsi_eh_bus_reset(shost, work_q, done_q))
213291921e01SHannes Reinecke 					if (!scsi_eh_host_reset(shost, work_q, done_q))
213330bd7df8SMike Christie 						scsi_eh_offline_sdevs(work_q,
213430bd7df8SMike Christie 								      done_q);
21351da177e4SLinus Torvalds }
2136dca84e46SDarrick J. Wong EXPORT_SYMBOL_GPL(scsi_eh_ready_devs);
21371da177e4SLinus Torvalds 
21381da177e4SLinus Torvalds /**
21391da177e4SLinus Torvalds  * scsi_eh_flush_done_q - finish processed commands or retry them.
21401da177e4SLinus Torvalds  * @done_q:	list_head of processed commands.
2141dc8875e1SRandy Dunlap  */
2142041c5fc3STejun Heo void scsi_eh_flush_done_q(struct list_head *done_q)
21431da177e4SLinus Torvalds {
2144937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *next;
21451da177e4SLinus Torvalds 
2146937abeaaSChristoph Hellwig 	list_for_each_entry_safe(scmd, next, done_q, eh_entry) {
2147937abeaaSChristoph Hellwig 		list_del_init(&scmd->eh_entry);
21481da177e4SLinus Torvalds 		if (scsi_device_online(scmd->device) &&
214960bee27bSMuneendra Kumar 		    !scsi_noretry_cmd(scmd) && scsi_cmd_retry_allowed(scmd) &&
215060bee27bSMuneendra Kumar 			scsi_eh_should_retry_cmd(scmd)) {
215191921e01SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
215291921e01SHannes Reinecke 				scmd_printk(KERN_INFO, scmd,
2153470613b4SHannes Reinecke 					     "%s: flush retry cmd\n",
2154470613b4SHannes Reinecke 					     current->comm));
21551da177e4SLinus Torvalds 				scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
21561da177e4SLinus Torvalds 		} else {
2157793698ceSPatrick Mansfield  			/*
2158793698ceSPatrick Mansfield  			 * If just we got sense for the device (called
2159793698ceSPatrick Mansfield  			 * scsi_eh_get_sense), scmd->result is already
21604bd51e54SHannes Reinecke 			 * set, do not set DID_TIME_OUT.
2161793698ceSPatrick Mansfield  			 */
21621da177e4SLinus Torvalds 			if (!scmd->result)
21634bd51e54SHannes Reinecke 				scmd->result |= (DID_TIME_OUT << 16);
216491921e01SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
216591921e01SHannes Reinecke 				scmd_printk(KERN_INFO, scmd,
2166470613b4SHannes Reinecke 					     "%s: flush finish cmd\n",
2167470613b4SHannes Reinecke 					     current->comm));
21681da177e4SLinus Torvalds 			scsi_finish_command(scmd);
21691da177e4SLinus Torvalds 		}
21701da177e4SLinus Torvalds 	}
21711da177e4SLinus Torvalds }
2172041c5fc3STejun Heo EXPORT_SYMBOL(scsi_eh_flush_done_q);
21731da177e4SLinus Torvalds 
21741da177e4SLinus Torvalds /**
21751da177e4SLinus Torvalds  * scsi_unjam_host - Attempt to fix a host which has a cmd that failed.
21761da177e4SLinus Torvalds  * @shost:	Host to unjam.
21771da177e4SLinus Torvalds  *
21781da177e4SLinus Torvalds  * Notes:
21791da177e4SLinus Torvalds  *    When we come in here, we *know* that all commands on the bus have
21801da177e4SLinus Torvalds  *    either completed, failed or timed out.  we also know that no further
21811da177e4SLinus Torvalds  *    commands are being sent to the host, so things are relatively quiet
21821da177e4SLinus Torvalds  *    and we have freedom to fiddle with things as we wish.
21831da177e4SLinus Torvalds  *
21841da177e4SLinus Torvalds  *    This is only the *default* implementation.  it is possible for
21851da177e4SLinus Torvalds  *    individual drivers to supply their own version of this function, and
21861da177e4SLinus Torvalds  *    if the maintainer wishes to do this, it is strongly suggested that
21871da177e4SLinus Torvalds  *    this function be taken as a template and modified.  this function
21881da177e4SLinus Torvalds  *    was designed to correctly handle problems for about 95% of the
21891da177e4SLinus Torvalds  *    different cases out there, and it should always provide at least a
21901da177e4SLinus Torvalds  *    reasonable amount of error recovery.
21911da177e4SLinus Torvalds  *
21921da177e4SLinus Torvalds  *    Any command marked 'failed' or 'timeout' must eventually have
21931da177e4SLinus Torvalds  *    scsi_finish_cmd() called for it.  we do all of the retry stuff
21941da177e4SLinus Torvalds  *    here, so when we restart the host after we return it should have an
21951da177e4SLinus Torvalds  *    empty queue.
2196dc8875e1SRandy Dunlap  */
21971da177e4SLinus Torvalds static void scsi_unjam_host(struct Scsi_Host *shost)
21981da177e4SLinus Torvalds {
21991da177e4SLinus Torvalds 	unsigned long flags;
22001da177e4SLinus Torvalds 	LIST_HEAD(eh_work_q);
22011da177e4SLinus Torvalds 	LIST_HEAD(eh_done_q);
22021da177e4SLinus Torvalds 
22031da177e4SLinus Torvalds 	spin_lock_irqsave(shost->host_lock, flags);
22041da177e4SLinus Torvalds 	list_splice_init(&shost->eh_cmd_q, &eh_work_q);
22051da177e4SLinus Torvalds 	spin_unlock_irqrestore(shost->host_lock, flags);
22061da177e4SLinus Torvalds 
22071da177e4SLinus Torvalds 	SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(shost, &eh_work_q));
22081da177e4SLinus Torvalds 
22091da177e4SLinus Torvalds 	if (!scsi_eh_get_sense(&eh_work_q, &eh_done_q))
22101da177e4SLinus Torvalds 		scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q);
22111da177e4SLinus Torvalds 
2212b4562022SHannes Reinecke 	spin_lock_irqsave(shost->host_lock, flags);
2213bb3b621aSRen Mingxin 	if (shost->eh_deadline != -1)
2214b4562022SHannes Reinecke 		shost->last_reset = 0;
2215b4562022SHannes Reinecke 	spin_unlock_irqrestore(shost->host_lock, flags);
22161da177e4SLinus Torvalds 	scsi_eh_flush_done_q(&eh_done_q);
22171da177e4SLinus Torvalds }
22181da177e4SLinus Torvalds 
22191da177e4SLinus Torvalds /**
2220ad42eb1bSChristoph Hellwig  * scsi_error_handler - SCSI error handler thread
22211da177e4SLinus Torvalds  * @data:	Host for which we are running.
22221da177e4SLinus Torvalds  *
22231da177e4SLinus Torvalds  * Notes:
2224ad42eb1bSChristoph Hellwig  *    This is the main error handling loop.  This is run as a kernel thread
2225ad42eb1bSChristoph Hellwig  *    for every SCSI host and handles all error handling activity.
2226dc8875e1SRandy Dunlap  */
22271da177e4SLinus Torvalds int scsi_error_handler(void *data)
22281da177e4SLinus Torvalds {
2229ad42eb1bSChristoph Hellwig 	struct Scsi_Host *shost = data;
22301da177e4SLinus Torvalds 
22311da177e4SLinus Torvalds 	/*
2232ad42eb1bSChristoph Hellwig 	 * We use TASK_INTERRUPTIBLE so that the thread is not
2233ad42eb1bSChristoph Hellwig 	 * counted against the load average as a running process.
2234ad42eb1bSChristoph Hellwig 	 * We never actually get interrupted because kthread_run
2235c03264a7SFrederik Schwarzer 	 * disables signal delivery for the created thread.
22361da177e4SLinus Torvalds 	 */
2237537b604cSMichal Hocko 	while (true) {
2238537b604cSMichal Hocko 		/*
2239537b604cSMichal Hocko 		 * The sequence in kthread_stop() sets the stop flag first
2240537b604cSMichal Hocko 		 * then wakes the process.  To avoid missed wakeups, the task
2241537b604cSMichal Hocko 		 * should always be in a non running state before the stop
2242537b604cSMichal Hocko 		 * flag is checked
2243537b604cSMichal Hocko 		 */
2244b9d5c6b7SDan Williams 		set_current_state(TASK_INTERRUPTIBLE);
2245537b604cSMichal Hocko 		if (kthread_should_stop())
2246537b604cSMichal Hocko 			break;
2247537b604cSMichal Hocko 
2248ee7863bcSTejun Heo 		if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
2249c84b023aSMing Lei 		    shost->host_failed != scsi_host_busy(shost)) {
2250ad42eb1bSChristoph Hellwig 			SCSI_LOG_ERROR_RECOVERY(1,
225191921e01SHannes Reinecke 				shost_printk(KERN_INFO, shost,
225291921e01SHannes Reinecke 					     "scsi_eh_%d: sleeping\n",
22533ed7a470SJames Bottomley 					     shost->host_no));
22543ed7a470SJames Bottomley 			schedule();
22553ed7a470SJames Bottomley 			continue;
22563ed7a470SJames Bottomley 		}
22571da177e4SLinus Torvalds 
22583ed7a470SJames Bottomley 		__set_current_state(TASK_RUNNING);
2259ad42eb1bSChristoph Hellwig 		SCSI_LOG_ERROR_RECOVERY(1,
226091921e01SHannes Reinecke 			shost_printk(KERN_INFO, shost,
226191921e01SHannes Reinecke 				     "scsi_eh_%d: waking up %d/%d/%d\n",
2262b4562022SHannes Reinecke 				     shost->host_no, shost->host_eh_scheduled,
226374665016SChristoph Hellwig 				     shost->host_failed,
2264c84b023aSMing Lei 				     scsi_host_busy(shost)));
22651da177e4SLinus Torvalds 
22661da177e4SLinus Torvalds 		/*
22671da177e4SLinus Torvalds 		 * We have a host that is failing for some reason.  Figure out
22681da177e4SLinus Torvalds 		 * what we need to do to get it up and online again (if we can).
22691da177e4SLinus Torvalds 		 * If we fail, we end up taking the thing offline.
22701da177e4SLinus Torvalds 		 */
2271ae0751ffSLin Ming 		if (!shost->eh_noresume && scsi_autopm_get_host(shost) != 0) {
2272bc4f2401SAlan Stern 			SCSI_LOG_ERROR_RECOVERY(1,
2273a222b1e2SHannes Reinecke 				shost_printk(KERN_ERR, shost,
2274a222b1e2SHannes Reinecke 					     "scsi_eh_%d: unable to autoresume\n",
2275bc4f2401SAlan Stern 					     shost->host_no));
2276bc4f2401SAlan Stern 			continue;
2277bc4f2401SAlan Stern 		}
2278bc4f2401SAlan Stern 
22799227c33dSChristoph Hellwig 		if (shost->transportt->eh_strategy_handler)
22809227c33dSChristoph Hellwig 			shost->transportt->eh_strategy_handler(shost);
22811da177e4SLinus Torvalds 		else
22821da177e4SLinus Torvalds 			scsi_unjam_host(shost);
22831da177e4SLinus Torvalds 
228472d8c36eSWei Fang 		/* All scmds have been handled */
228572d8c36eSWei Fang 		shost->host_failed = 0;
228672d8c36eSWei Fang 
22871da177e4SLinus Torvalds 		/*
22881da177e4SLinus Torvalds 		 * Note - if the above fails completely, the action is to take
22891da177e4SLinus Torvalds 		 * individual devices offline and flush the queue of any
22901da177e4SLinus Torvalds 		 * outstanding requests that may have been pending.  When we
22911da177e4SLinus Torvalds 		 * restart, we restart any I/O to any other devices on the bus
22921da177e4SLinus Torvalds 		 * which are still online.
22931da177e4SLinus Torvalds 		 */
22941da177e4SLinus Torvalds 		scsi_restart_operations(shost);
2295ae0751ffSLin Ming 		if (!shost->eh_noresume)
2296bc4f2401SAlan Stern 			scsi_autopm_put_host(shost);
22971da177e4SLinus Torvalds 	}
2298461a0ffbSSteven Rostedt 	__set_current_state(TASK_RUNNING);
2299461a0ffbSSteven Rostedt 
2300ad42eb1bSChristoph Hellwig 	SCSI_LOG_ERROR_RECOVERY(1,
230191921e01SHannes Reinecke 		shost_printk(KERN_INFO, shost,
230291921e01SHannes Reinecke 			     "Error handler scsi_eh_%d exiting\n",
230391921e01SHannes Reinecke 			     shost->host_no));
23043ed7a470SJames Bottomley 	shost->ehandler = NULL;
23051da177e4SLinus Torvalds 	return 0;
23061da177e4SLinus Torvalds }
23071da177e4SLinus Torvalds 
23081da177e4SLinus Torvalds /*
23091da177e4SLinus Torvalds  * Function:    scsi_report_bus_reset()
23101da177e4SLinus Torvalds  *
23111da177e4SLinus Torvalds  * Purpose:     Utility function used by low-level drivers to report that
23121da177e4SLinus Torvalds  *		they have observed a bus reset on the bus being handled.
23131da177e4SLinus Torvalds  *
23141da177e4SLinus Torvalds  * Arguments:   shost       - Host in question
23151da177e4SLinus Torvalds  *		channel     - channel on which reset was observed.
23161da177e4SLinus Torvalds  *
23171da177e4SLinus Torvalds  * Returns:     Nothing
23181da177e4SLinus Torvalds  *
23191da177e4SLinus Torvalds  * Lock status: Host lock must be held.
23201da177e4SLinus Torvalds  *
23211da177e4SLinus Torvalds  * Notes:       This only needs to be called if the reset is one which
23221da177e4SLinus Torvalds  *		originates from an unknown location.  Resets originated
23231da177e4SLinus Torvalds  *		by the mid-level itself don't need to call this, but there
23241da177e4SLinus Torvalds  *		should be no harm.
23251da177e4SLinus Torvalds  *
23261da177e4SLinus Torvalds  *		The main purpose of this is to make sure that a CHECK_CONDITION
23271da177e4SLinus Torvalds  *		is properly treated.
23281da177e4SLinus Torvalds  */
23291da177e4SLinus Torvalds void scsi_report_bus_reset(struct Scsi_Host *shost, int channel)
23301da177e4SLinus Torvalds {
23311da177e4SLinus Torvalds 	struct scsi_device *sdev;
23321da177e4SLinus Torvalds 
23331da177e4SLinus Torvalds 	__shost_for_each_device(sdev, shost) {
233430bd7df8SMike Christie 		if (channel == sdev_channel(sdev))
233530bd7df8SMike Christie 			__scsi_report_device_reset(sdev, NULL);
23361da177e4SLinus Torvalds 	}
23371da177e4SLinus Torvalds }
23381da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_report_bus_reset);
23391da177e4SLinus Torvalds 
23401da177e4SLinus Torvalds /*
23411da177e4SLinus Torvalds  * Function:    scsi_report_device_reset()
23421da177e4SLinus Torvalds  *
23431da177e4SLinus Torvalds  * Purpose:     Utility function used by low-level drivers to report that
23441da177e4SLinus Torvalds  *		they have observed a device reset on the device being handled.
23451da177e4SLinus Torvalds  *
23461da177e4SLinus Torvalds  * Arguments:   shost       - Host in question
23471da177e4SLinus Torvalds  *		channel     - channel on which reset was observed
23481da177e4SLinus Torvalds  *		target	    - target on which reset was observed
23491da177e4SLinus Torvalds  *
23501da177e4SLinus Torvalds  * Returns:     Nothing
23511da177e4SLinus Torvalds  *
23521da177e4SLinus Torvalds  * Lock status: Host lock must be held
23531da177e4SLinus Torvalds  *
23541da177e4SLinus Torvalds  * Notes:       This only needs to be called if the reset is one which
23551da177e4SLinus Torvalds  *		originates from an unknown location.  Resets originated
23561da177e4SLinus Torvalds  *		by the mid-level itself don't need to call this, but there
23571da177e4SLinus Torvalds  *		should be no harm.
23581da177e4SLinus Torvalds  *
23591da177e4SLinus Torvalds  *		The main purpose of this is to make sure that a CHECK_CONDITION
23601da177e4SLinus Torvalds  *		is properly treated.
23611da177e4SLinus Torvalds  */
23621da177e4SLinus Torvalds void scsi_report_device_reset(struct Scsi_Host *shost, int channel, int target)
23631da177e4SLinus Torvalds {
23641da177e4SLinus Torvalds 	struct scsi_device *sdev;
23651da177e4SLinus Torvalds 
23661da177e4SLinus Torvalds 	__shost_for_each_device(sdev, shost) {
2367422c0d61SJeff Garzik 		if (channel == sdev_channel(sdev) &&
236830bd7df8SMike Christie 		    target == sdev_id(sdev))
236930bd7df8SMike Christie 			__scsi_report_device_reset(sdev, NULL);
23701da177e4SLinus Torvalds 	}
23711da177e4SLinus Torvalds }
23721da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_report_device_reset);
23731da177e4SLinus Torvalds 
2374176aa9d6SChristoph Hellwig /**
2375176aa9d6SChristoph Hellwig  * scsi_ioctl_reset: explicitly reset a host/bus/target/device
2376176aa9d6SChristoph Hellwig  * @dev:	scsi_device to operate on
2377176aa9d6SChristoph Hellwig  * @arg:	reset type (see sg.h)
23781da177e4SLinus Torvalds  */
23791da177e4SLinus Torvalds int
2380176aa9d6SChristoph Hellwig scsi_ioctl_reset(struct scsi_device *dev, int __user *arg)
23811da177e4SLinus Torvalds {
2382bc4f2401SAlan Stern 	struct scsi_cmnd *scmd;
2383d7a1bb0aSJames Smart 	struct Scsi_Host *shost = dev->host;
2384e9c787e6SChristoph Hellwig 	struct request *rq;
2385d7a1bb0aSJames Smart 	unsigned long flags;
2386b8e162f9SBart Van Assche 	int error = 0, val;
2387b8e162f9SBart Van Assche 	enum scsi_disposition rtn;
2388176aa9d6SChristoph Hellwig 
2389176aa9d6SChristoph Hellwig 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2390176aa9d6SChristoph Hellwig 		return -EACCES;
2391176aa9d6SChristoph Hellwig 
2392176aa9d6SChristoph Hellwig 	error = get_user(val, arg);
2393176aa9d6SChristoph Hellwig 	if (error)
2394176aa9d6SChristoph Hellwig 		return error;
23951da177e4SLinus Torvalds 
2396bc4f2401SAlan Stern 	if (scsi_autopm_get_host(shost) < 0)
2397176aa9d6SChristoph Hellwig 		return -EIO;
2398bc4f2401SAlan Stern 
2399176aa9d6SChristoph Hellwig 	error = -EIO;
2400e9c787e6SChristoph Hellwig 	rq = kzalloc(sizeof(struct request) + sizeof(struct scsi_cmnd) +
2401e9c787e6SChristoph Hellwig 			shost->hostt->cmd_size, GFP_KERNEL);
2402e9c787e6SChristoph Hellwig 	if (!rq)
240395eeb5f5SChristoph Hellwig 		goto out_put_autopm_host;
2404e9c787e6SChristoph Hellwig 	blk_rq_init(NULL, rq);
240595eeb5f5SChristoph Hellwig 
2406e9c787e6SChristoph Hellwig 	scmd = (struct scsi_cmnd *)(rq + 1);
2407e9c787e6SChristoph Hellwig 	scsi_init_command(dev, scmd);
24081da177e4SLinus Torvalds 
2409bf23e619SBart Van Assche 	scmd->submitter = SUBMITTED_BY_SCSI_RESET_IOCTL;
241030b0c37bSBoaz Harrosh 	memset(&scmd->sdb, 0, sizeof(scmd->sdb));
24111da177e4SLinus Torvalds 
24121da177e4SLinus Torvalds 	scmd->cmd_len			= 0;
24131da177e4SLinus Torvalds 
24141da177e4SLinus Torvalds 	scmd->sc_data_direction		= DMA_BIDIRECTIONAL;
24151da177e4SLinus Torvalds 
2416d7a1bb0aSJames Smart 	spin_lock_irqsave(shost->host_lock, flags);
2417d7a1bb0aSJames Smart 	shost->tmf_in_progress = 1;
2418d7a1bb0aSJames Smart 	spin_unlock_irqrestore(shost->host_lock, flags);
2419d7a1bb0aSJames Smart 
2420176aa9d6SChristoph Hellwig 	switch (val & ~SG_SCSI_RESET_NO_ESCALATE) {
2421176aa9d6SChristoph Hellwig 	case SG_SCSI_RESET_NOTHING:
2422176aa9d6SChristoph Hellwig 		rtn = SUCCESS;
2423176aa9d6SChristoph Hellwig 		break;
2424176aa9d6SChristoph Hellwig 	case SG_SCSI_RESET_DEVICE:
24251da177e4SLinus Torvalds 		rtn = scsi_try_bus_device_reset(scmd);
2426176aa9d6SChristoph Hellwig 		if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
24271da177e4SLinus Torvalds 			break;
2428df561f66SGustavo A. R. Silva 		fallthrough;
2429176aa9d6SChristoph Hellwig 	case SG_SCSI_RESET_TARGET:
243030bd7df8SMike Christie 		rtn = scsi_try_target_reset(scmd);
2431176aa9d6SChristoph Hellwig 		if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
243230bd7df8SMike Christie 			break;
2433df561f66SGustavo A. R. Silva 		fallthrough;
2434176aa9d6SChristoph Hellwig 	case SG_SCSI_RESET_BUS:
24351da177e4SLinus Torvalds 		rtn = scsi_try_bus_reset(scmd);
2436176aa9d6SChristoph Hellwig 		if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
24371da177e4SLinus Torvalds 			break;
2438df561f66SGustavo A. R. Silva 		fallthrough;
2439176aa9d6SChristoph Hellwig 	case SG_SCSI_RESET_HOST:
24401da177e4SLinus Torvalds 		rtn = scsi_try_host_reset(scmd);
2441176aa9d6SChristoph Hellwig 		if (rtn == SUCCESS)
244226cf591eSDouglas Gilbert 			break;
2443df561f66SGustavo A. R. Silva 		fallthrough;
24443bf2ff67SBart Van Assche 	default:
24451da177e4SLinus Torvalds 		rtn = FAILED;
2446176aa9d6SChristoph Hellwig 		break;
24471da177e4SLinus Torvalds 	}
24481da177e4SLinus Torvalds 
2449176aa9d6SChristoph Hellwig 	error = (rtn == SUCCESS) ? 0 : -EIO;
2450176aa9d6SChristoph Hellwig 
2451d7a1bb0aSJames Smart 	spin_lock_irqsave(shost->host_lock, flags);
2452d7a1bb0aSJames Smart 	shost->tmf_in_progress = 0;
2453d7a1bb0aSJames Smart 	spin_unlock_irqrestore(shost->host_lock, flags);
2454d7a1bb0aSJames Smart 
2455d7a1bb0aSJames Smart 	/*
2456d7a1bb0aSJames Smart 	 * be sure to wake up anyone who was sleeping or had their queue
2457d7a1bb0aSJames Smart 	 * suspended while we performed the TMF.
2458d7a1bb0aSJames Smart 	 */
2459d7a1bb0aSJames Smart 	SCSI_LOG_ERROR_RECOVERY(3,
246091921e01SHannes Reinecke 		shost_printk(KERN_INFO, shost,
246191921e01SHannes Reinecke 			     "waking up host to restart after TMF\n"));
2462d7a1bb0aSJames Smart 
2463d7a1bb0aSJames Smart 	wake_up(&shost->host_wait);
2464d7a1bb0aSJames Smart 	scsi_run_host_queues(shost);
2465d7a1bb0aSJames Smart 
2466e9c787e6SChristoph Hellwig 	kfree(rq);
24670f121dd8SChristoph Hellwig 
246804796336SChristoph Hellwig out_put_autopm_host:
2469bc4f2401SAlan Stern 	scsi_autopm_put_host(shost);
2470176aa9d6SChristoph Hellwig 	return error;
24711da177e4SLinus Torvalds }
24721da177e4SLinus Torvalds 
24734753cbc0SHannes Reinecke bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd,
24741da177e4SLinus Torvalds 				  struct scsi_sense_hdr *sshdr)
24751da177e4SLinus Torvalds {
24761da177e4SLinus Torvalds 	return scsi_normalize_sense(cmd->sense_buffer,
2477b80ca4f7SFUJITA Tomonori 			SCSI_SENSE_BUFFERSIZE, sshdr);
24781da177e4SLinus Torvalds }
24791da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_command_normalize_sense);
24801da177e4SLinus Torvalds 
24811da177e4SLinus Torvalds /**
2482eb44820cSRob Landley  * scsi_get_sense_info_fld - get information field from sense data (either fixed or descriptor format)
24831da177e4SLinus Torvalds  * @sense_buffer:	byte array of sense data
24841da177e4SLinus Torvalds  * @sb_len:		number of valid bytes in sense_buffer
24851da177e4SLinus Torvalds  * @info_out:		pointer to 64 integer where 8 or 4 byte information
24861da177e4SLinus Torvalds  *			field will be placed if found.
24871da177e4SLinus Torvalds  *
24881da177e4SLinus Torvalds  * Return value:
24892908769cSDamien Le Moal  *	true if information field found, false if not found.
2490dc8875e1SRandy Dunlap  */
24912908769cSDamien Le Moal bool scsi_get_sense_info_fld(const u8 *sense_buffer, int sb_len,
24921da177e4SLinus Torvalds 			     u64 *info_out)
24931da177e4SLinus Torvalds {
24941da177e4SLinus Torvalds 	const u8 * ucp;
24951da177e4SLinus Torvalds 
24961da177e4SLinus Torvalds 	if (sb_len < 7)
24972908769cSDamien Le Moal 		return false;
24981da177e4SLinus Torvalds 	switch (sense_buffer[0] & 0x7f) {
24991da177e4SLinus Torvalds 	case 0x70:
25001da177e4SLinus Torvalds 	case 0x71:
25011da177e4SLinus Torvalds 		if (sense_buffer[0] & 0x80) {
25022908769cSDamien Le Moal 			*info_out = get_unaligned_be32(&sense_buffer[3]);
25032908769cSDamien Le Moal 			return true;
25042908769cSDamien Le Moal 		}
25052908769cSDamien Le Moal 		return false;
25061da177e4SLinus Torvalds 	case 0x72:
25071da177e4SLinus Torvalds 	case 0x73:
25081da177e4SLinus Torvalds 		ucp = scsi_sense_desc_find(sense_buffer, sb_len,
25091da177e4SLinus Torvalds 					   0 /* info desc */);
25101da177e4SLinus Torvalds 		if (ucp && (0xa == ucp[1])) {
25112908769cSDamien Le Moal 			*info_out = get_unaligned_be64(&ucp[4]);
25122908769cSDamien Le Moal 			return true;
25131da177e4SLinus Torvalds 		}
25142908769cSDamien Le Moal 		return false;
25151da177e4SLinus Torvalds 	default:
25162908769cSDamien Le Moal 		return false;
25171da177e4SLinus Torvalds 	}
25181da177e4SLinus Torvalds }
25191da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_get_sense_info_fld);
2520