xref: /openbmc/linux/drivers/scsi/scsi_error.c (revision ad95028a2e88e59fadda79141e74546d12ba3b4b)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  scsi_error.c Copyright (C) 1997 Eric Youngdale
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  SCSI error/timeout handling
51da177e4SLinus Torvalds  *      Initial versions: Eric Youngdale.  Based upon conversations with
61da177e4SLinus Torvalds  *                        Leonard Zubkoff and David Miller at Linux Expo,
71da177e4SLinus Torvalds  *                        ideas originating from all over the place.
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *	Restructured scsi_unjam_host and associated functions.
101da177e4SLinus Torvalds  *	September 04, 2002 Mike Anderson (andmike@us.ibm.com)
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  *	Forward port of Russell King's (rmk@arm.linux.org.uk) changes and
131da177e4SLinus Torvalds  *	minor cleanups.
141da177e4SLinus Torvalds  *	September 30, 2002 Mike Anderson (andmike@us.ibm.com)
151da177e4SLinus Torvalds  */
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds #include <linux/module.h>
181da177e4SLinus Torvalds #include <linux/sched.h>
195a0e3ad6STejun Heo #include <linux/gfp.h>
201da177e4SLinus Torvalds #include <linux/timer.h>
211da177e4SLinus Torvalds #include <linux/string.h>
221da177e4SLinus Torvalds #include <linux/kernel.h>
2383144186SRafael J. Wysocki #include <linux/freezer.h>
24c5478defSChristoph Hellwig #include <linux/kthread.h>
251da177e4SLinus Torvalds #include <linux/interrupt.h>
261da177e4SLinus Torvalds #include <linux/blkdev.h>
271da177e4SLinus Torvalds #include <linux/delay.h>
28fc73648aSHannes Reinecke #include <linux/jiffies.h>
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #include <scsi/scsi.h>
31beb40487SChristoph Hellwig #include <scsi/scsi_cmnd.h>
321da177e4SLinus Torvalds #include <scsi/scsi_dbg.h>
331da177e4SLinus Torvalds #include <scsi/scsi_device.h>
3418a4d0a2SMartin K. Petersen #include <scsi/scsi_driver.h>
351da177e4SLinus Torvalds #include <scsi/scsi_eh.h>
367708c165SSagi Grimberg #include <scsi/scsi_common.h>
37c829c394SJames Smart #include <scsi/scsi_transport.h>
381da177e4SLinus Torvalds #include <scsi/scsi_host.h>
391da177e4SLinus Torvalds #include <scsi/scsi_ioctl.h>
40ee14c674SChristoph Hellwig #include <scsi/scsi_dh.h>
41176aa9d6SChristoph Hellwig #include <scsi/sg.h>
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds #include "scsi_priv.h"
441da177e4SLinus Torvalds #include "scsi_logging.h"
4579ee8304SAdrian Bunk #include "scsi_transport_api.h"
461da177e4SLinus Torvalds 
47bf816235SKei Tokunaga #include <trace/events/scsi.h>
48bf816235SKei Tokunaga 
492908769cSDamien Le Moal #include <asm/unaligned.h>
502908769cSDamien Le Moal 
5114216561SJames Bottomley static void scsi_eh_done(struct scsi_cmnd *scmd);
5214216561SJames Bottomley 
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);
61e494f6a7SHannes Reinecke static int scsi_try_to_abort_cmd(struct scsi_host_template *,
62e494f6a7SHannes Reinecke 				 struct scsi_cmnd *);
633eef6257SDavid Jeffery 
641da177e4SLinus Torvalds /* called with shost->host_lock held */
651da177e4SLinus Torvalds void scsi_eh_wakeup(struct Scsi_Host *shost)
661da177e4SLinus Torvalds {
6774665016SChristoph Hellwig 	if (atomic_read(&shost->host_busy) == shost->host_failed) {
68bf816235SKei Tokunaga 		trace_scsi_eh_wakeup(shost);
693ed7a470SJames Bottomley 		wake_up_process(shost->ehandler);
7091921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(5, shost_printk(KERN_INFO, shost,
7191921e01SHannes Reinecke 			"Waking error handler thread\n"));
721da177e4SLinus Torvalds 	}
731da177e4SLinus Torvalds }
74f8bbfc24STejun Heo 
75f8bbfc24STejun Heo /**
76f8bbfc24STejun Heo  * scsi_schedule_eh - schedule EH for SCSI host
77f8bbfc24STejun Heo  * @shost:	SCSI host to invoke error handling on.
78f8bbfc24STejun Heo  *
79f8bbfc24STejun Heo  * Schedule SCSI EH without scmd.
80dc8875e1SRandy Dunlap  */
81f8bbfc24STejun Heo void scsi_schedule_eh(struct Scsi_Host *shost)
82f8bbfc24STejun Heo {
83f8bbfc24STejun Heo 	unsigned long flags;
84f8bbfc24STejun Heo 
85f8bbfc24STejun Heo 	spin_lock_irqsave(shost->host_lock, flags);
86f8bbfc24STejun Heo 
87f8bbfc24STejun Heo 	if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 ||
88f8bbfc24STejun Heo 	    scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) {
89f8bbfc24STejun Heo 		shost->host_eh_scheduled++;
90f8bbfc24STejun Heo 		scsi_eh_wakeup(shost);
91f8bbfc24STejun Heo 	}
92f8bbfc24STejun Heo 
93f8bbfc24STejun Heo 	spin_unlock_irqrestore(shost->host_lock, flags);
94f8bbfc24STejun Heo }
95f8bbfc24STejun Heo EXPORT_SYMBOL_GPL(scsi_schedule_eh);
961da177e4SLinus Torvalds 
97b4562022SHannes Reinecke static int scsi_host_eh_past_deadline(struct Scsi_Host *shost)
98b4562022SHannes Reinecke {
99bb3b621aSRen Mingxin 	if (!shost->last_reset || shost->eh_deadline == -1)
100b4562022SHannes Reinecke 		return 0;
101b4562022SHannes Reinecke 
10276ad3e59SHannes Reinecke 	/*
10376ad3e59SHannes Reinecke 	 * 32bit accesses are guaranteed to be atomic
10476ad3e59SHannes Reinecke 	 * (on all supported architectures), so instead
10576ad3e59SHannes Reinecke 	 * of using a spinlock we can as well double check
106bb3b621aSRen Mingxin 	 * if eh_deadline has been set to 'off' during the
10776ad3e59SHannes Reinecke 	 * time_before call.
10876ad3e59SHannes Reinecke 	 */
10976ad3e59SHannes Reinecke 	if (time_before(jiffies, shost->last_reset + shost->eh_deadline) &&
110bb3b621aSRen Mingxin 	    shost->eh_deadline > -1)
111b4562022SHannes Reinecke 		return 0;
112b4562022SHannes Reinecke 
113b4562022SHannes Reinecke 	return 1;
114b4562022SHannes Reinecke }
115b4562022SHannes Reinecke 
1161da177e4SLinus Torvalds /**
117e494f6a7SHannes Reinecke  * scmd_eh_abort_handler - Handle command aborts
118e494f6a7SHannes Reinecke  * @work:	command to be aborted.
119e494f6a7SHannes Reinecke  */
120e494f6a7SHannes Reinecke void
121e494f6a7SHannes Reinecke scmd_eh_abort_handler(struct work_struct *work)
122e494f6a7SHannes Reinecke {
123e494f6a7SHannes Reinecke 	struct scsi_cmnd *scmd =
124e494f6a7SHannes Reinecke 		container_of(work, struct scsi_cmnd, abort_work.work);
125e494f6a7SHannes Reinecke 	struct scsi_device *sdev = scmd->device;
126e494f6a7SHannes Reinecke 	int rtn;
127e494f6a7SHannes Reinecke 
128e494f6a7SHannes Reinecke 	if (scsi_host_eh_past_deadline(sdev->host)) {
129e494f6a7SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
130e494f6a7SHannes Reinecke 			scmd_printk(KERN_INFO, scmd,
131470613b4SHannes Reinecke 				    "eh timeout, not aborting\n"));
132e494f6a7SHannes Reinecke 	} else {
133e494f6a7SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
134e494f6a7SHannes Reinecke 			scmd_printk(KERN_INFO, scmd,
135470613b4SHannes Reinecke 				    "aborting command\n"));
136e494f6a7SHannes Reinecke 		rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd);
137e494f6a7SHannes Reinecke 		if (rtn == SUCCESS) {
1388922a908SUlrich Obergfell 			set_host_byte(scmd, DID_TIME_OUT);
139bb3b621aSRen Mingxin 			if (scsi_host_eh_past_deadline(sdev->host)) {
140bb3b621aSRen Mingxin 				SCSI_LOG_ERROR_RECOVERY(3,
141bb3b621aSRen Mingxin 					scmd_printk(KERN_INFO, scmd,
142470613b4SHannes Reinecke 						    "eh timeout, not retrying "
143470613b4SHannes Reinecke 						    "aborted command\n"));
144bb3b621aSRen Mingxin 			} else if (!scsi_noretry_cmd(scmd) &&
145e494f6a7SHannes Reinecke 			    (++scmd->retries <= scmd->allowed)) {
146e494f6a7SHannes Reinecke 				SCSI_LOG_ERROR_RECOVERY(3,
147e494f6a7SHannes Reinecke 					scmd_printk(KERN_WARNING, scmd,
148470613b4SHannes Reinecke 						    "retry aborted command\n"));
149e494f6a7SHannes Reinecke 				scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
150bb3b621aSRen Mingxin 				return;
151e494f6a7SHannes Reinecke 			} else {
152e494f6a7SHannes Reinecke 				SCSI_LOG_ERROR_RECOVERY(3,
153e494f6a7SHannes Reinecke 					scmd_printk(KERN_WARNING, scmd,
154470613b4SHannes Reinecke 						    "finish aborted command\n"));
155e494f6a7SHannes Reinecke 				scsi_finish_command(scmd);
156e494f6a7SHannes Reinecke 				return;
157e494f6a7SHannes Reinecke 			}
158bb3b621aSRen Mingxin 		} else {
159e494f6a7SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
160e494f6a7SHannes Reinecke 				scmd_printk(KERN_INFO, scmd,
161470613b4SHannes Reinecke 					    "cmd abort %s\n",
162883a030fSHannes Reinecke 					    (rtn == FAST_IO_FAIL) ?
163883a030fSHannes Reinecke 					    "not send" : "failed"));
164e494f6a7SHannes Reinecke 		}
165bb3b621aSRen Mingxin 	}
166e494f6a7SHannes Reinecke 
167a0658632SHannes Reinecke 	scsi_eh_scmd_add(scmd);
168e494f6a7SHannes Reinecke }
169e494f6a7SHannes Reinecke 
170e494f6a7SHannes Reinecke /**
171e494f6a7SHannes Reinecke  * scsi_abort_command - schedule a command abort
172e494f6a7SHannes Reinecke  * @scmd:	scmd to abort.
173e494f6a7SHannes Reinecke  *
174e494f6a7SHannes Reinecke  * We only need to abort commands after a command timeout
175e494f6a7SHannes Reinecke  */
176e494f6a7SHannes Reinecke static int
177e494f6a7SHannes Reinecke scsi_abort_command(struct scsi_cmnd *scmd)
178e494f6a7SHannes Reinecke {
179e494f6a7SHannes Reinecke 	struct scsi_device *sdev = scmd->device;
180e494f6a7SHannes Reinecke 	struct Scsi_Host *shost = sdev->host;
181e494f6a7SHannes Reinecke 	unsigned long flags;
182e494f6a7SHannes Reinecke 
183e494f6a7SHannes Reinecke 	if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) {
184e494f6a7SHannes Reinecke 		/*
185e494f6a7SHannes Reinecke 		 * Retry after abort failed, escalate to next level.
186e494f6a7SHannes Reinecke 		 */
187e494f6a7SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
188e494f6a7SHannes Reinecke 			scmd_printk(KERN_INFO, scmd,
189470613b4SHannes Reinecke 				    "previous abort failed\n"));
190fcc95a76SBart Van Assche 		BUG_ON(delayed_work_pending(&scmd->abort_work));
191e494f6a7SHannes Reinecke 		return FAILED;
192e494f6a7SHannes Reinecke 	}
193e494f6a7SHannes Reinecke 
194e494f6a7SHannes Reinecke 	spin_lock_irqsave(shost->host_lock, flags);
195bb3b621aSRen Mingxin 	if (shost->eh_deadline != -1 && !shost->last_reset)
196e494f6a7SHannes Reinecke 		shost->last_reset = jiffies;
197e494f6a7SHannes Reinecke 	spin_unlock_irqrestore(shost->host_lock, flags);
198e494f6a7SHannes Reinecke 
199e494f6a7SHannes Reinecke 	scmd->eh_eflags |= SCSI_EH_ABORT_SCHEDULED;
200e494f6a7SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3,
201470613b4SHannes Reinecke 		scmd_printk(KERN_INFO, scmd, "abort scheduled\n"));
202e494f6a7SHannes Reinecke 	queue_delayed_work(shost->tmf_work_q, &scmd->abort_work, HZ / 100);
203e494f6a7SHannes Reinecke 	return SUCCESS;
204e494f6a7SHannes Reinecke }
205e494f6a7SHannes Reinecke 
206e494f6a7SHannes Reinecke /**
2077a38dc0bSHannes Reinecke  * scsi_eh_reset - call into ->eh_action to reset internal counters
2087a38dc0bSHannes Reinecke  * @scmd:	scmd to run eh on.
2097a38dc0bSHannes Reinecke  *
2107a38dc0bSHannes Reinecke  * The scsi driver might be carrying internal state about the
2117a38dc0bSHannes Reinecke  * devices, so we need to call into the driver to reset the
2127a38dc0bSHannes Reinecke  * internal state once the error handler is started.
2137a38dc0bSHannes Reinecke  */
2147a38dc0bSHannes Reinecke static void scsi_eh_reset(struct scsi_cmnd *scmd)
2157a38dc0bSHannes Reinecke {
2167a38dc0bSHannes Reinecke 	if (!blk_rq_is_passthrough(scmd->request)) {
2177a38dc0bSHannes Reinecke 		struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd);
2187a38dc0bSHannes Reinecke 		if (sdrv->eh_reset)
2197a38dc0bSHannes Reinecke 			sdrv->eh_reset(scmd);
2207a38dc0bSHannes Reinecke 	}
2217a38dc0bSHannes Reinecke }
2227a38dc0bSHannes Reinecke 
2237a38dc0bSHannes Reinecke /**
2241da177e4SLinus Torvalds  * scsi_eh_scmd_add - add scsi cmd to error handling.
2251da177e4SLinus Torvalds  * @scmd:	scmd to run eh on.
226dc8875e1SRandy Dunlap  */
227a0658632SHannes Reinecke void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
2281da177e4SLinus Torvalds {
2291da177e4SLinus Torvalds 	struct Scsi_Host *shost = scmd->device->host;
2301da177e4SLinus Torvalds 	unsigned long flags;
2312171b6d0SHannes Reinecke 	int ret;
2321da177e4SLinus Torvalds 
2332171b6d0SHannes Reinecke 	WARN_ON_ONCE(!shost->ehandler);
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds 	spin_lock_irqsave(shost->host_lock, flags);
2362171b6d0SHannes Reinecke 	if (scsi_host_set_state(shost, SHOST_RECOVERY)) {
2372171b6d0SHannes Reinecke 		ret = scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY);
2382171b6d0SHannes Reinecke 		WARN_ON_ONCE(ret);
2392171b6d0SHannes Reinecke 	}
240bb3b621aSRen Mingxin 	if (shost->eh_deadline != -1 && !shost->last_reset)
241b4562022SHannes Reinecke 		shost->last_reset = jiffies;
242b4562022SHannes Reinecke 
2437a38dc0bSHannes Reinecke 	scsi_eh_reset(scmd);
2441da177e4SLinus Torvalds 	list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
2451da177e4SLinus Torvalds 	shost->host_failed++;
2461da177e4SLinus Torvalds 	scsi_eh_wakeup(shost);
2471da177e4SLinus Torvalds 	spin_unlock_irqrestore(shost->host_lock, flags);
2481da177e4SLinus Torvalds }
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds /**
2511da177e4SLinus Torvalds  * scsi_times_out - Timeout function for normal scsi commands.
252242f9dcbSJens Axboe  * @req:	request that is timing out.
2531da177e4SLinus Torvalds  *
2541da177e4SLinus Torvalds  * Notes:
2551da177e4SLinus Torvalds  *     We do not need to lock this.  There is the potential for a race
2561da177e4SLinus Torvalds  *     only in that the normal completion handling might run, but if the
2571da177e4SLinus Torvalds  *     normal completion function determines that the timer has already
2581da177e4SLinus Torvalds  *     fired, then it mustn't do anything.
259dc8875e1SRandy Dunlap  */
260242f9dcbSJens Axboe enum blk_eh_timer_return scsi_times_out(struct request *req)
2611da177e4SLinus Torvalds {
262bed2213dSBart Van Assche 	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req);
263242f9dcbSJens Axboe 	enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
2640bf8c869SJesper Juhl 	struct Scsi_Host *host = scmd->device->host;
2656c5f8ce1SJames Bottomley 
266bf816235SKei Tokunaga 	trace_scsi_dispatch_cmd_timeout(scmd);
2671da177e4SLinus Torvalds 	scsi_log_completion(scmd, TIMEOUT_ERROR);
2681da177e4SLinus Torvalds 
269bb3b621aSRen Mingxin 	if (host->eh_deadline != -1 && !host->last_reset)
270b4562022SHannes Reinecke 		host->last_reset = jiffies;
271b4562022SHannes Reinecke 
272b6a05c82SChristoph Hellwig 	if (host->hostt->eh_timed_out)
2730bf8c869SJesper Juhl 		rtn = host->hostt->eh_timed_out(scmd);
2746c5f8ce1SJames Bottomley 
275a33c070bSHannes Reinecke 	if (rtn == BLK_EH_NOT_HANDLED) {
276a0658632SHannes Reinecke 		if (scsi_abort_command(scmd) != SUCCESS) {
2778922a908SUlrich Obergfell 			set_host_byte(scmd, DID_TIME_OUT);
278a0658632SHannes Reinecke 			scsi_eh_scmd_add(scmd);
2792171b6d0SHannes Reinecke 		}
280a33c070bSHannes Reinecke 	}
281242f9dcbSJens Axboe 
282fa990781SChristoph Hellwig 	return rtn;
2831da177e4SLinus Torvalds }
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds /**
2861da177e4SLinus Torvalds  * scsi_block_when_processing_errors - Prevent cmds from being queued.
2871da177e4SLinus Torvalds  * @sdev:	Device on which we are performing recovery.
2881da177e4SLinus Torvalds  *
2891da177e4SLinus Torvalds  * Description:
2901da177e4SLinus Torvalds  *     We block until the host is out of error recovery, and then check to
2911da177e4SLinus Torvalds  *     see whether the host or the device is offline.
2921da177e4SLinus Torvalds  *
2931da177e4SLinus Torvalds  * Return value:
2941da177e4SLinus Torvalds  *     0 when dev was taken offline by error recovery. 1 OK to proceed.
295dc8875e1SRandy Dunlap  */
2961da177e4SLinus Torvalds int scsi_block_when_processing_errors(struct scsi_device *sdev)
2971da177e4SLinus Torvalds {
2981da177e4SLinus Torvalds 	int online;
2991da177e4SLinus Torvalds 
300939647eeSJames Bottomley 	wait_event(sdev->host->host_wait, !scsi_host_in_recovery(sdev->host));
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 	online = scsi_device_online(sdev);
3031da177e4SLinus Torvalds 
30491921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(5, sdev_printk(KERN_INFO, sdev,
30591921e01SHannes Reinecke 		"%s: rtn: %d\n", __func__, online));
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds 	return online;
3081da177e4SLinus Torvalds }
3091da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_block_when_processing_errors);
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds #ifdef CONFIG_SCSI_LOGGING
3121da177e4SLinus Torvalds /**
3131da177e4SLinus Torvalds  * scsi_eh_prt_fail_stats - Log info on failures.
3141da177e4SLinus Torvalds  * @shost:	scsi host being recovered.
3151da177e4SLinus Torvalds  * @work_q:	Queue of scsi cmds to process.
316dc8875e1SRandy Dunlap  */
3171da177e4SLinus Torvalds static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
3181da177e4SLinus Torvalds 					  struct list_head *work_q)
3191da177e4SLinus Torvalds {
3201da177e4SLinus Torvalds 	struct scsi_cmnd *scmd;
3211da177e4SLinus Torvalds 	struct scsi_device *sdev;
3221da177e4SLinus Torvalds 	int total_failures = 0;
3231da177e4SLinus Torvalds 	int cmd_failed = 0;
3241da177e4SLinus Torvalds 	int cmd_cancel = 0;
3251da177e4SLinus Torvalds 	int devices_failed = 0;
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 	shost_for_each_device(sdev, shost) {
3281da177e4SLinus Torvalds 		list_for_each_entry(scmd, work_q, eh_entry) {
3291da177e4SLinus Torvalds 			if (scmd->device == sdev) {
3301da177e4SLinus Torvalds 				++total_failures;
331a0658632SHannes Reinecke 				if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED)
3321da177e4SLinus Torvalds 					++cmd_cancel;
3331da177e4SLinus Torvalds 				else
3341da177e4SLinus Torvalds 					++cmd_failed;
3351da177e4SLinus Torvalds 			}
3361da177e4SLinus Torvalds 		}
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 		if (cmd_cancel || cmd_failed) {
3391da177e4SLinus Torvalds 			SCSI_LOG_ERROR_RECOVERY(3,
340a3a790dcSHannes Reinecke 				shost_printk(KERN_INFO, shost,
3419ccfc756SJames Bottomley 					    "%s: cmds failed: %d, cancel: %d\n",
342cadbd4a5SHarvey Harrison 					    __func__, cmd_failed,
3439ccfc756SJames Bottomley 					    cmd_cancel));
3441da177e4SLinus Torvalds 			cmd_cancel = 0;
3451da177e4SLinus Torvalds 			cmd_failed = 0;
3461da177e4SLinus Torvalds 			++devices_failed;
3471da177e4SLinus Torvalds 		}
3481da177e4SLinus Torvalds 	}
3491da177e4SLinus Torvalds 
35091921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(2, shost_printk(KERN_INFO, shost,
35191921e01SHannes Reinecke 				   "Total of %d commands on %d"
3521da177e4SLinus Torvalds 				   " devices require eh work\n",
3531da177e4SLinus Torvalds 				   total_failures, devices_failed));
3541da177e4SLinus Torvalds }
3551da177e4SLinus Torvalds #endif
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds  /**
358279afdfeSEwan D. Milne  * scsi_report_lun_change - Set flag on all *other* devices on the same target
359279afdfeSEwan D. Milne  *                          to indicate that a UNIT ATTENTION is expected.
360279afdfeSEwan D. Milne  * @sdev:	Device reporting the UNIT ATTENTION
361279afdfeSEwan D. Milne  */
362279afdfeSEwan D. Milne static void scsi_report_lun_change(struct scsi_device *sdev)
363279afdfeSEwan D. Milne {
364279afdfeSEwan D. Milne 	sdev->sdev_target->expecting_lun_change = 1;
365279afdfeSEwan D. Milne }
366279afdfeSEwan D. Milne 
367279afdfeSEwan D. Milne /**
368279afdfeSEwan D. Milne  * scsi_report_sense - Examine scsi sense information and log messages for
369279afdfeSEwan D. Milne  *		       certain conditions, also issue uevents for some of them.
370279afdfeSEwan D. Milne  * @sdev:	Device reporting the sense code
371279afdfeSEwan D. Milne  * @sshdr:	sshdr to be examined
372279afdfeSEwan D. Milne  */
373279afdfeSEwan D. Milne static void scsi_report_sense(struct scsi_device *sdev,
374279afdfeSEwan D. Milne 			      struct scsi_sense_hdr *sshdr)
375279afdfeSEwan D. Milne {
376279afdfeSEwan D. Milne 	enum scsi_device_event evt_type = SDEV_EVT_MAXBITS;	/* i.e. none */
377279afdfeSEwan D. Milne 
378279afdfeSEwan D. Milne 	if (sshdr->sense_key == UNIT_ATTENTION) {
379279afdfeSEwan D. Milne 		if (sshdr->asc == 0x3f && sshdr->ascq == 0x03) {
380279afdfeSEwan D. Milne 			evt_type = SDEV_EVT_INQUIRY_CHANGE_REPORTED;
381279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
382279afdfeSEwan D. Milne 				    "Inquiry data has changed");
383279afdfeSEwan D. Milne 		} else if (sshdr->asc == 0x3f && sshdr->ascq == 0x0e) {
384279afdfeSEwan D. Milne 			evt_type = SDEV_EVT_LUN_CHANGE_REPORTED;
385279afdfeSEwan D. Milne 			scsi_report_lun_change(sdev);
386279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
387279afdfeSEwan D. Milne 				    "Warning! Received an indication that the "
388279afdfeSEwan D. Milne 				    "LUN assignments on this target have "
389279afdfeSEwan D. Milne 				    "changed. The Linux SCSI layer does not "
390279afdfeSEwan D. Milne 				    "automatically remap LUN assignments.\n");
391279afdfeSEwan D. Milne 		} else if (sshdr->asc == 0x3f)
392279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
393279afdfeSEwan D. Milne 				    "Warning! Received an indication that the "
394279afdfeSEwan D. Milne 				    "operating parameters on this target have "
395279afdfeSEwan D. Milne 				    "changed. The Linux SCSI layer does not "
396279afdfeSEwan D. Milne 				    "automatically adjust these parameters.\n");
397279afdfeSEwan D. Milne 
398279afdfeSEwan D. Milne 		if (sshdr->asc == 0x38 && sshdr->ascq == 0x07) {
399279afdfeSEwan D. Milne 			evt_type = SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED;
400279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
401279afdfeSEwan D. Milne 				    "Warning! Received an indication that the "
402279afdfeSEwan D. Milne 				    "LUN reached a thin provisioning soft "
403279afdfeSEwan D. Milne 				    "threshold.\n");
404279afdfeSEwan D. Milne 		}
405279afdfeSEwan D. Milne 
406cf3431bbSHannes Reinecke 		if (sshdr->asc == 0x29) {
407cf3431bbSHannes Reinecke 			evt_type = SDEV_EVT_POWER_ON_RESET_OCCURRED;
408cf3431bbSHannes Reinecke 			sdev_printk(KERN_WARNING, sdev,
409cf3431bbSHannes Reinecke 				    "Power-on or device reset occurred\n");
410cf3431bbSHannes Reinecke 		}
411cf3431bbSHannes Reinecke 
412279afdfeSEwan D. Milne 		if (sshdr->asc == 0x2a && sshdr->ascq == 0x01) {
413279afdfeSEwan D. Milne 			evt_type = SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED;
414279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
415279afdfeSEwan D. Milne 				    "Mode parameters changed");
41614c3e677SHannes Reinecke 		} else if (sshdr->asc == 0x2a && sshdr->ascq == 0x06) {
41714c3e677SHannes Reinecke 			evt_type = SDEV_EVT_ALUA_STATE_CHANGE_REPORTED;
41814c3e677SHannes Reinecke 			sdev_printk(KERN_WARNING, sdev,
41914c3e677SHannes Reinecke 				    "Asymmetric access state changed");
420279afdfeSEwan D. Milne 		} else if (sshdr->asc == 0x2a && sshdr->ascq == 0x09) {
421279afdfeSEwan D. Milne 			evt_type = SDEV_EVT_CAPACITY_CHANGE_REPORTED;
422279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
423279afdfeSEwan D. Milne 				    "Capacity data has changed");
424279afdfeSEwan D. Milne 		} else if (sshdr->asc == 0x2a)
425279afdfeSEwan D. Milne 			sdev_printk(KERN_WARNING, sdev,
426279afdfeSEwan D. Milne 				    "Parameters changed");
427279afdfeSEwan D. Milne 	}
428279afdfeSEwan D. Milne 
429279afdfeSEwan D. Milne 	if (evt_type != SDEV_EVT_MAXBITS) {
430279afdfeSEwan D. Milne 		set_bit(evt_type, sdev->pending_events);
431279afdfeSEwan D. Milne 		schedule_work(&sdev->event_work);
432279afdfeSEwan D. Milne 	}
433279afdfeSEwan D. Milne }
434279afdfeSEwan D. Milne 
435279afdfeSEwan D. Milne /**
4361da177e4SLinus Torvalds  * scsi_check_sense - Examine scsi cmd sense
4371da177e4SLinus Torvalds  * @scmd:	Cmd to have sense checked.
4381da177e4SLinus Torvalds  *
4391da177e4SLinus Torvalds  * Return value:
44087f14e65SHannes Reinecke  *	SUCCESS or FAILED or NEEDS_RETRY or ADD_TO_MLQUEUE
4411da177e4SLinus Torvalds  *
4421da177e4SLinus Torvalds  * Notes:
4431da177e4SLinus Torvalds  *	When a deferred error is detected the current command has
4441da177e4SLinus Torvalds  *	not been executed and needs retrying.
445dc8875e1SRandy Dunlap  */
4463852e373SHannes Reinecke int scsi_check_sense(struct scsi_cmnd *scmd)
4471da177e4SLinus Torvalds {
448a6a8d9f8SChandra Seetharaman 	struct scsi_device *sdev = scmd->device;
4491da177e4SLinus Torvalds 	struct scsi_sense_hdr sshdr;
4501da177e4SLinus Torvalds 
4511da177e4SLinus Torvalds 	if (! scsi_command_normalize_sense(scmd, &sshdr))
4521da177e4SLinus Torvalds 		return FAILED;	/* no valid sense data */
4531da177e4SLinus Torvalds 
454279afdfeSEwan D. Milne 	scsi_report_sense(sdev, &sshdr);
455279afdfeSEwan D. Milne 
4561da177e4SLinus Torvalds 	if (scsi_sense_is_deferred(&sshdr))
4571da177e4SLinus Torvalds 		return NEEDS_RETRY;
4581da177e4SLinus Torvalds 
459ee14c674SChristoph Hellwig 	if (sdev->handler && sdev->handler->check_sense) {
460a6a8d9f8SChandra Seetharaman 		int rc;
461a6a8d9f8SChandra Seetharaman 
462ee14c674SChristoph Hellwig 		rc = sdev->handler->check_sense(sdev, &sshdr);
463a6a8d9f8SChandra Seetharaman 		if (rc != SCSI_RETURN_NOT_HANDLED)
464a6a8d9f8SChandra Seetharaman 			return rc;
465a6a8d9f8SChandra Seetharaman 		/* handler does not care. Drop down to default handling */
466a6a8d9f8SChandra Seetharaman 	}
467a6a8d9f8SChandra Seetharaman 
468e925cc43SChristoph Hellwig 	if (scmd->cmnd[0] == TEST_UNIT_READY && scmd->scsi_done != scsi_eh_done)
469e925cc43SChristoph Hellwig 		/*
470e925cc43SChristoph Hellwig 		 * nasty: for mid-layer issued TURs, we need to return the
471e925cc43SChristoph Hellwig 		 * actual sense data without any recovery attempt.  For eh
472e925cc43SChristoph Hellwig 		 * issued ones, we need to try to recover and interpret
473e925cc43SChristoph Hellwig 		 */
474e925cc43SChristoph Hellwig 		return SUCCESS;
475e925cc43SChristoph Hellwig 
4761da177e4SLinus Torvalds 	/*
4771da177e4SLinus Torvalds 	 * Previous logic looked for FILEMARK, EOM or ILI which are
4781da177e4SLinus Torvalds 	 * mainly associated with tapes and returned SUCCESS.
4791da177e4SLinus Torvalds 	 */
4801da177e4SLinus Torvalds 	if (sshdr.response_code == 0x70) {
4811da177e4SLinus Torvalds 		/* fixed format */
4821da177e4SLinus Torvalds 		if (scmd->sense_buffer[2] & 0xe0)
4831da177e4SLinus Torvalds 			return SUCCESS;
4841da177e4SLinus Torvalds 	} else {
4851da177e4SLinus Torvalds 		/*
4861da177e4SLinus Torvalds 		 * descriptor format: look for "stream commands sense data
4871da177e4SLinus Torvalds 		 * descriptor" (see SSC-3). Assume single sense data
4881da177e4SLinus Torvalds 		 * descriptor. Ignore ILI from SBC-2 READ LONG and WRITE LONG.
4891da177e4SLinus Torvalds 		 */
4901da177e4SLinus Torvalds 		if ((sshdr.additional_length > 3) &&
4911da177e4SLinus Torvalds 		    (scmd->sense_buffer[8] == 0x4) &&
4921da177e4SLinus Torvalds 		    (scmd->sense_buffer[11] & 0xe0))
4931da177e4SLinus Torvalds 			return SUCCESS;
4941da177e4SLinus Torvalds 	}
4951da177e4SLinus Torvalds 
4961da177e4SLinus Torvalds 	switch (sshdr.sense_key) {
4971da177e4SLinus Torvalds 	case NO_SENSE:
4981da177e4SLinus Torvalds 		return SUCCESS;
4991da177e4SLinus Torvalds 	case RECOVERED_ERROR:
5001da177e4SLinus Torvalds 		return /* soft_error */ SUCCESS;
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 	case ABORTED_COMMAND:
503511e44f4SMartin K. Petersen 		if (sshdr.asc == 0x10) /* DIF */
504511e44f4SMartin K. Petersen 			return SUCCESS;
505511e44f4SMartin K. Petersen 
5061da177e4SLinus Torvalds 		return NEEDS_RETRY;
5071da177e4SLinus Torvalds 	case NOT_READY:
5081da177e4SLinus Torvalds 	case UNIT_ATTENTION:
5091da177e4SLinus Torvalds 		/*
5101da177e4SLinus Torvalds 		 * if we are expecting a cc/ua because of a bus reset that we
5111da177e4SLinus Torvalds 		 * performed, treat this just as a retry.  otherwise this is
5121da177e4SLinus Torvalds 		 * information that we should pass up to the upper-level driver
5131da177e4SLinus Torvalds 		 * so that we can deal with it there.
5141da177e4SLinus Torvalds 		 */
5151da177e4SLinus Torvalds 		if (scmd->device->expecting_cc_ua) {
516dfcf7775STARUISI Hiroaki 			/*
517dfcf7775STARUISI Hiroaki 			 * Because some device does not queue unit
518dfcf7775STARUISI Hiroaki 			 * attentions correctly, we carefully check
519dfcf7775STARUISI Hiroaki 			 * additional sense code and qualifier so as
520dfcf7775STARUISI Hiroaki 			 * not to squash media change unit attention.
521dfcf7775STARUISI Hiroaki 			 */
522dfcf7775STARUISI Hiroaki 			if (sshdr.asc != 0x28 || sshdr.ascq != 0x00) {
5231da177e4SLinus Torvalds 				scmd->device->expecting_cc_ua = 0;
5241da177e4SLinus Torvalds 				return NEEDS_RETRY;
5251da177e4SLinus Torvalds 			}
526dfcf7775STARUISI Hiroaki 		}
5271da177e4SLinus Torvalds 		/*
528279afdfeSEwan D. Milne 		 * we might also expect a cc/ua if another LUN on the target
529279afdfeSEwan D. Milne 		 * reported a UA with an ASC/ASCQ of 3F 0E -
530279afdfeSEwan D. Milne 		 * REPORTED LUNS DATA HAS CHANGED.
531279afdfeSEwan D. Milne 		 */
532279afdfeSEwan D. Milne 		if (scmd->device->sdev_target->expecting_lun_change &&
533279afdfeSEwan D. Milne 		    sshdr.asc == 0x3f && sshdr.ascq == 0x0e)
534279afdfeSEwan D. Milne 			return NEEDS_RETRY;
535279afdfeSEwan D. Milne 		/*
5361da177e4SLinus Torvalds 		 * if the device is in the process of becoming ready, we
5371da177e4SLinus Torvalds 		 * should retry.
5381da177e4SLinus Torvalds 		 */
5391da177e4SLinus Torvalds 		if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01))
5401da177e4SLinus Torvalds 			return NEEDS_RETRY;
5411da177e4SLinus Torvalds 		/*
5421da177e4SLinus Torvalds 		 * if the device is not started, we need to wake
5431da177e4SLinus Torvalds 		 * the error handler to start the motor
5441da177e4SLinus Torvalds 		 */
5451da177e4SLinus Torvalds 		if (scmd->device->allow_restart &&
5461da177e4SLinus Torvalds 		    (sshdr.asc == 0x04) && (sshdr.ascq == 0x02))
5471da177e4SLinus Torvalds 			return FAILED;
54877a42297SJames Bottomley 		/*
54902e031cbSChristoph Hellwig 		 * Pass the UA upwards for a determination in the completion
55002e031cbSChristoph Hellwig 		 * functions.
55177a42297SJames Bottomley 		 */
5521da177e4SLinus Torvalds 		return SUCCESS;
5531da177e4SLinus Torvalds 
55463583ccaSHannes Reinecke 		/* these are not supported */
555a9d6ceb8SHannes Reinecke 	case DATA_PROTECT:
556a9d6ceb8SHannes Reinecke 		if (sshdr.asc == 0x27 && sshdr.ascq == 0x07) {
557a9d6ceb8SHannes Reinecke 			/* Thin provisioning hard threshold reached */
558a9d6ceb8SHannes Reinecke 			set_host_byte(scmd, DID_ALLOC_FAILURE);
559a9d6ceb8SHannes Reinecke 			return SUCCESS;
560a9d6ceb8SHannes Reinecke 		}
5613bf2ff67SBart Van Assche 		/* FALLTHROUGH */
5621da177e4SLinus Torvalds 	case COPY_ABORTED:
5631da177e4SLinus Torvalds 	case VOLUME_OVERFLOW:
5641da177e4SLinus Torvalds 	case MISCOMPARE:
56563583ccaSHannes Reinecke 	case BLANK_CHECK:
56687f14e65SHannes Reinecke 		set_host_byte(scmd, DID_TARGET_FAILURE);
56787f14e65SHannes Reinecke 		return SUCCESS;
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 	case MEDIUM_ERROR:
570fd1b494dSLuben Tuikov 		if (sshdr.asc == 0x11 || /* UNRECOVERED READ ERR */
571fd1b494dSLuben Tuikov 		    sshdr.asc == 0x13 || /* AMNF DATA FIELD */
572fd1b494dSLuben Tuikov 		    sshdr.asc == 0x14) { /* RECORD NOT FOUND */
5737e782af5SHannes Reinecke 			set_host_byte(scmd, DID_MEDIUM_ERROR);
57487f14e65SHannes Reinecke 			return SUCCESS;
575fd1b494dSLuben Tuikov 		}
5761da177e4SLinus Torvalds 		return NEEDS_RETRY;
5771da177e4SLinus Torvalds 
5781da177e4SLinus Torvalds 	case HARDWARE_ERROR:
5791da177e4SLinus Torvalds 		if (scmd->device->retry_hwerror)
580bb0003c1SMike Anderson 			return ADD_TO_MLQUEUE;
5811da177e4SLinus Torvalds 		else
58287f14e65SHannes Reinecke 			set_host_byte(scmd, DID_TARGET_FAILURE);
5833bf2ff67SBart Van Assche 		/* FALLTHROUGH */
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds 	case ILLEGAL_REQUEST:
58647ac56dbSMike Snitzer 		if (sshdr.asc == 0x20 || /* Invalid command operation code */
58747ac56dbSMike Snitzer 		    sshdr.asc == 0x21 || /* Logical block address out of range */
588a8bbb2abSHannes Reinecke 		    sshdr.asc == 0x22 || /* Invalid function */
58947ac56dbSMike Snitzer 		    sshdr.asc == 0x24 || /* Invalid field in cdb */
59047ac56dbSMike Snitzer 		    sshdr.asc == 0x26) { /* Parameter value invalid */
59187f14e65SHannes Reinecke 			set_host_byte(scmd, DID_TARGET_FAILURE);
59247ac56dbSMike Snitzer 		}
59347ac56dbSMike Snitzer 		return SUCCESS;
59447ac56dbSMike Snitzer 
5951da177e4SLinus Torvalds 	default:
5961da177e4SLinus Torvalds 		return SUCCESS;
5971da177e4SLinus Torvalds 	}
5981da177e4SLinus Torvalds }
5993852e373SHannes Reinecke EXPORT_SYMBOL_GPL(scsi_check_sense);
6001da177e4SLinus Torvalds 
6014a84067dSVasu Dev static void scsi_handle_queue_ramp_up(struct scsi_device *sdev)
6024a84067dSVasu Dev {
6034a84067dSVasu Dev 	struct scsi_host_template *sht = sdev->host->hostt;
6044a84067dSVasu Dev 	struct scsi_device *tmp_sdev;
6054a84067dSVasu Dev 
606c40ecc12SChristoph Hellwig 	if (!sht->track_queue_depth ||
6074a84067dSVasu Dev 	    sdev->queue_depth >= sdev->max_queue_depth)
6084a84067dSVasu Dev 		return;
6094a84067dSVasu Dev 
6104a84067dSVasu Dev 	if (time_before(jiffies,
6114a84067dSVasu Dev 	    sdev->last_queue_ramp_up + sdev->queue_ramp_up_period))
6124a84067dSVasu Dev 		return;
6134a84067dSVasu Dev 
6144a84067dSVasu Dev 	if (time_before(jiffies,
6154a84067dSVasu Dev 	    sdev->last_queue_full_time + sdev->queue_ramp_up_period))
6164a84067dSVasu Dev 		return;
6174a84067dSVasu Dev 
6184a84067dSVasu Dev 	/*
6194a84067dSVasu Dev 	 * Walk all devices of a target and do
6204a84067dSVasu Dev 	 * ramp up on them.
6214a84067dSVasu Dev 	 */
6224a84067dSVasu Dev 	shost_for_each_device(tmp_sdev, sdev->host) {
6234a84067dSVasu Dev 		if (tmp_sdev->channel != sdev->channel ||
6244a84067dSVasu Dev 		    tmp_sdev->id != sdev->id ||
6254a84067dSVasu Dev 		    tmp_sdev->queue_depth == sdev->max_queue_depth)
6264a84067dSVasu Dev 			continue;
627c40ecc12SChristoph Hellwig 
628db5ed4dfSChristoph Hellwig 		scsi_change_queue_depth(tmp_sdev, tmp_sdev->queue_depth + 1);
6294a84067dSVasu Dev 		sdev->last_queue_ramp_up = jiffies;
6304a84067dSVasu Dev 	}
6314a84067dSVasu Dev }
6324a84067dSVasu Dev 
63342a6a918SMike Christie static void scsi_handle_queue_full(struct scsi_device *sdev)
63442a6a918SMike Christie {
63542a6a918SMike Christie 	struct scsi_host_template *sht = sdev->host->hostt;
63642a6a918SMike Christie 	struct scsi_device *tmp_sdev;
63742a6a918SMike Christie 
638c40ecc12SChristoph Hellwig 	if (!sht->track_queue_depth)
63942a6a918SMike Christie 		return;
64042a6a918SMike Christie 
64142a6a918SMike Christie 	shost_for_each_device(tmp_sdev, sdev->host) {
64242a6a918SMike Christie 		if (tmp_sdev->channel != sdev->channel ||
64342a6a918SMike Christie 		    tmp_sdev->id != sdev->id)
64442a6a918SMike Christie 			continue;
64542a6a918SMike Christie 		/*
64642a6a918SMike Christie 		 * We do not know the number of commands that were at
64742a6a918SMike Christie 		 * the device when we got the queue full so we start
64842a6a918SMike Christie 		 * from the highest possible value and work our way down.
64942a6a918SMike Christie 		 */
650c40ecc12SChristoph Hellwig 		scsi_track_queue_full(tmp_sdev, tmp_sdev->queue_depth - 1);
65142a6a918SMike Christie 	}
65242a6a918SMike Christie }
65342a6a918SMike Christie 
6541da177e4SLinus Torvalds /**
6551da177e4SLinus Torvalds  * scsi_eh_completed_normally - Disposition a eh cmd on return from LLD.
6561da177e4SLinus Torvalds  * @scmd:	SCSI cmd to examine.
6571da177e4SLinus Torvalds  *
6581da177e4SLinus Torvalds  * Notes:
6591da177e4SLinus Torvalds  *    This is *only* called when we are examining the status of commands
6601da177e4SLinus Torvalds  *    queued during error recovery.  the main difference here is that we
6611da177e4SLinus Torvalds  *    don't allow for the possibility of retries here, and we are a lot
6621da177e4SLinus Torvalds  *    more restrictive about what we consider acceptable.
663dc8875e1SRandy Dunlap  */
6641da177e4SLinus Torvalds static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
6651da177e4SLinus Torvalds {
6661da177e4SLinus Torvalds 	/*
6671da177e4SLinus Torvalds 	 * first check the host byte, to see if there is anything in there
6681da177e4SLinus Torvalds 	 * that would indicate what we need to do.
6691da177e4SLinus Torvalds 	 */
6701da177e4SLinus Torvalds 	if (host_byte(scmd->result) == DID_RESET) {
6711da177e4SLinus Torvalds 		/*
6721da177e4SLinus Torvalds 		 * rats.  we are already in the error handler, so we now
6731da177e4SLinus Torvalds 		 * get to try and figure out what to do next.  if the sense
6741da177e4SLinus Torvalds 		 * is valid, we have a pretty good idea of what to do.
6751da177e4SLinus Torvalds 		 * if not, we mark it as FAILED.
6761da177e4SLinus Torvalds 		 */
6771da177e4SLinus Torvalds 		return scsi_check_sense(scmd);
6781da177e4SLinus Torvalds 	}
6791da177e4SLinus Torvalds 	if (host_byte(scmd->result) != DID_OK)
6801da177e4SLinus Torvalds 		return FAILED;
6811da177e4SLinus Torvalds 
6821da177e4SLinus Torvalds 	/*
6831da177e4SLinus Torvalds 	 * next, check the message byte.
6841da177e4SLinus Torvalds 	 */
6851da177e4SLinus Torvalds 	if (msg_byte(scmd->result) != COMMAND_COMPLETE)
6861da177e4SLinus Torvalds 		return FAILED;
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds 	/*
6891da177e4SLinus Torvalds 	 * now, check the status byte to see if this indicates
6901da177e4SLinus Torvalds 	 * anything special.
6911da177e4SLinus Torvalds 	 */
6921da177e4SLinus Torvalds 	switch (status_byte(scmd->result)) {
6931da177e4SLinus Torvalds 	case GOOD:
6944a84067dSVasu Dev 		scsi_handle_queue_ramp_up(scmd->device);
6953bf2ff67SBart Van Assche 		/* FALLTHROUGH */
6961da177e4SLinus Torvalds 	case COMMAND_TERMINATED:
6971da177e4SLinus Torvalds 		return SUCCESS;
6981da177e4SLinus Torvalds 	case CHECK_CONDITION:
6991da177e4SLinus Torvalds 		return scsi_check_sense(scmd);
7001da177e4SLinus Torvalds 	case CONDITION_GOOD:
7011da177e4SLinus Torvalds 	case INTERMEDIATE_GOOD:
7021da177e4SLinus Torvalds 	case INTERMEDIATE_C_GOOD:
7031da177e4SLinus Torvalds 		/*
7041da177e4SLinus Torvalds 		 * who knows?  FIXME(eric)
7051da177e4SLinus Torvalds 		 */
7061da177e4SLinus Torvalds 		return SUCCESS;
7075f91bb05SMichael Reed 	case RESERVATION_CONFLICT:
70867110dfdSJames Bottomley 		if (scmd->cmnd[0] == TEST_UNIT_READY)
70967110dfdSJames Bottomley 			/* it is a success, we probed the device and
71067110dfdSJames Bottomley 			 * found it */
7115f91bb05SMichael Reed 			return SUCCESS;
71267110dfdSJames Bottomley 		/* otherwise, we failed to send the command */
71367110dfdSJames Bottomley 		return FAILED;
7141da177e4SLinus Torvalds 	case QUEUE_FULL:
71542a6a918SMike Christie 		scsi_handle_queue_full(scmd->device);
71642a6a918SMike Christie 		/* fall through */
71742a6a918SMike Christie 	case BUSY:
7183eb3a928SHannes Reinecke 		return NEEDS_RETRY;
7191da177e4SLinus Torvalds 	default:
7201da177e4SLinus Torvalds 		return FAILED;
7211da177e4SLinus Torvalds 	}
7221da177e4SLinus Torvalds 	return FAILED;
7231da177e4SLinus Torvalds }
7241da177e4SLinus Torvalds 
7251da177e4SLinus Torvalds /**
7261da177e4SLinus Torvalds  * scsi_eh_done - Completion function for error handling.
7271da177e4SLinus Torvalds  * @scmd:	Cmd that is done.
728dc8875e1SRandy Dunlap  */
7291da177e4SLinus Torvalds static void scsi_eh_done(struct scsi_cmnd *scmd)
7301da177e4SLinus Torvalds {
73185631672SMichael Reed 	struct completion *eh_action;
73285631672SMichael Reed 
73391921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
734470613b4SHannes Reinecke 			"%s result: %x\n", __func__, scmd->result));
73585631672SMichael Reed 
73685631672SMichael Reed 	eh_action = scmd->device->host->eh_action;
73785631672SMichael Reed 	if (eh_action)
73885631672SMichael Reed 		complete(eh_action);
7391da177e4SLinus Torvalds }
7401da177e4SLinus Torvalds 
7411da177e4SLinus Torvalds /**
742292148f8SBrian King  * scsi_try_host_reset - ask host adapter to reset itself
743c2b3ebd0SGeert Uytterhoeven  * @scmd:	SCSI cmd to send host reset.
744dc8875e1SRandy Dunlap  */
745292148f8SBrian King static int scsi_try_host_reset(struct scsi_cmnd *scmd)
746292148f8SBrian King {
747292148f8SBrian King 	unsigned long flags;
748292148f8SBrian King 	int rtn;
7490bf8c869SJesper Juhl 	struct Scsi_Host *host = scmd->device->host;
7500bf8c869SJesper Juhl 	struct scsi_host_template *hostt = host->hostt;
751292148f8SBrian King 
75291921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3,
75391921e01SHannes Reinecke 		shost_printk(KERN_INFO, host, "Snd Host RST\n"));
754292148f8SBrian King 
7550bf8c869SJesper Juhl 	if (!hostt->eh_host_reset_handler)
756292148f8SBrian King 		return FAILED;
757292148f8SBrian King 
7580bf8c869SJesper Juhl 	rtn = hostt->eh_host_reset_handler(scmd);
759292148f8SBrian King 
760292148f8SBrian King 	if (rtn == SUCCESS) {
7610bf8c869SJesper Juhl 		if (!hostt->skip_settle_delay)
762292148f8SBrian King 			ssleep(HOST_RESET_SETTLE_TIME);
7630bf8c869SJesper Juhl 		spin_lock_irqsave(host->host_lock, flags);
7640bf8c869SJesper Juhl 		scsi_report_bus_reset(host, scmd_channel(scmd));
7650bf8c869SJesper Juhl 		spin_unlock_irqrestore(host->host_lock, flags);
766292148f8SBrian King 	}
767292148f8SBrian King 
768292148f8SBrian King 	return rtn;
769292148f8SBrian King }
770292148f8SBrian King 
771292148f8SBrian King /**
772292148f8SBrian King  * scsi_try_bus_reset - ask host to perform a bus reset
773292148f8SBrian King  * @scmd:	SCSI cmd to send bus reset.
774dc8875e1SRandy Dunlap  */
775292148f8SBrian King static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
776292148f8SBrian King {
777292148f8SBrian King 	unsigned long flags;
778292148f8SBrian King 	int rtn;
7790bf8c869SJesper Juhl 	struct Scsi_Host *host = scmd->device->host;
7800bf8c869SJesper Juhl 	struct scsi_host_template *hostt = host->hostt;
781292148f8SBrian King 
78291921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
78391921e01SHannes Reinecke 		"%s: Snd Bus RST\n", __func__));
784292148f8SBrian King 
7850bf8c869SJesper Juhl 	if (!hostt->eh_bus_reset_handler)
786292148f8SBrian King 		return FAILED;
787292148f8SBrian King 
7880bf8c869SJesper Juhl 	rtn = hostt->eh_bus_reset_handler(scmd);
789292148f8SBrian King 
790292148f8SBrian King 	if (rtn == SUCCESS) {
7910bf8c869SJesper Juhl 		if (!hostt->skip_settle_delay)
792292148f8SBrian King 			ssleep(BUS_RESET_SETTLE_TIME);
7930bf8c869SJesper Juhl 		spin_lock_irqsave(host->host_lock, flags);
7940bf8c869SJesper Juhl 		scsi_report_bus_reset(host, scmd_channel(scmd));
7950bf8c869SJesper Juhl 		spin_unlock_irqrestore(host->host_lock, flags);
796292148f8SBrian King 	}
797292148f8SBrian King 
798292148f8SBrian King 	return rtn;
799292148f8SBrian King }
800292148f8SBrian King 
80130bd7df8SMike Christie static void __scsi_report_device_reset(struct scsi_device *sdev, void *data)
80230bd7df8SMike Christie {
80330bd7df8SMike Christie 	sdev->was_reset = 1;
80430bd7df8SMike Christie 	sdev->expecting_cc_ua = 1;
80530bd7df8SMike Christie }
80630bd7df8SMike Christie 
80730bd7df8SMike Christie /**
80830bd7df8SMike Christie  * scsi_try_target_reset - Ask host to perform a target reset
80930bd7df8SMike Christie  * @scmd:	SCSI cmd used to send a target reset
81030bd7df8SMike Christie  *
81130bd7df8SMike Christie  * Notes:
81230bd7df8SMike Christie  *    There is no timeout for this operation.  if this operation is
81330bd7df8SMike Christie  *    unreliable for a given host, then the host itself needs to put a
81430bd7df8SMike Christie  *    timer on it, and set the host back to a consistent state prior to
81530bd7df8SMike Christie  *    returning.
81630bd7df8SMike Christie  */
81730bd7df8SMike Christie static int scsi_try_target_reset(struct scsi_cmnd *scmd)
81830bd7df8SMike Christie {
81930bd7df8SMike Christie 	unsigned long flags;
82030bd7df8SMike Christie 	int rtn;
8210bf8c869SJesper Juhl 	struct Scsi_Host *host = scmd->device->host;
8220bf8c869SJesper Juhl 	struct scsi_host_template *hostt = host->hostt;
82330bd7df8SMike Christie 
8240bf8c869SJesper Juhl 	if (!hostt->eh_target_reset_handler)
82530bd7df8SMike Christie 		return FAILED;
82630bd7df8SMike Christie 
8270bf8c869SJesper Juhl 	rtn = hostt->eh_target_reset_handler(scmd);
82830bd7df8SMike Christie 	if (rtn == SUCCESS) {
8290bf8c869SJesper Juhl 		spin_lock_irqsave(host->host_lock, flags);
83030bd7df8SMike Christie 		__starget_for_each_device(scsi_target(scmd->device), NULL,
83130bd7df8SMike Christie 					  __scsi_report_device_reset);
8320bf8c869SJesper Juhl 		spin_unlock_irqrestore(host->host_lock, flags);
83330bd7df8SMike Christie 	}
83430bd7df8SMike Christie 
83530bd7df8SMike Christie 	return rtn;
83630bd7df8SMike Christie }
83730bd7df8SMike Christie 
838292148f8SBrian King /**
839292148f8SBrian King  * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev
840292148f8SBrian King  * @scmd:	SCSI cmd used to send BDR
841292148f8SBrian King  *
842292148f8SBrian King  * Notes:
843292148f8SBrian King  *    There is no timeout for this operation.  if this operation is
844292148f8SBrian King  *    unreliable for a given host, then the host itself needs to put a
845292148f8SBrian King  *    timer on it, and set the host back to a consistent state prior to
846292148f8SBrian King  *    returning.
847dc8875e1SRandy Dunlap  */
848292148f8SBrian King static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
849292148f8SBrian King {
850292148f8SBrian King 	int rtn;
8510bf8c869SJesper Juhl 	struct scsi_host_template *hostt = scmd->device->host->hostt;
852292148f8SBrian King 
8530bf8c869SJesper Juhl 	if (!hostt->eh_device_reset_handler)
854292148f8SBrian King 		return FAILED;
855292148f8SBrian King 
8560bf8c869SJesper Juhl 	rtn = hostt->eh_device_reset_handler(scmd);
85730bd7df8SMike Christie 	if (rtn == SUCCESS)
85830bd7df8SMike Christie 		__scsi_report_device_reset(scmd->device, NULL);
859292148f8SBrian King 	return rtn;
860292148f8SBrian King }
861292148f8SBrian King 
862883a030fSHannes Reinecke /**
863883a030fSHannes Reinecke  * scsi_try_to_abort_cmd - Ask host to abort a SCSI command
8646583f6fbSRandy Dunlap  * @hostt:	SCSI driver host template
865883a030fSHannes Reinecke  * @scmd:	SCSI cmd used to send a target reset
866883a030fSHannes Reinecke  *
867883a030fSHannes Reinecke  * Return value:
868883a030fSHannes Reinecke  *	SUCCESS, FAILED, or FAST_IO_FAIL
869883a030fSHannes Reinecke  *
870883a030fSHannes Reinecke  * Notes:
871883a030fSHannes Reinecke  *    SUCCESS does not necessarily indicate that the command
872883a030fSHannes Reinecke  *    has been aborted; it only indicates that the LLDDs
873883a030fSHannes Reinecke  *    has cleared all references to that command.
874883a030fSHannes Reinecke  *    LLDDs should return FAILED only if an abort was required
875883a030fSHannes Reinecke  *    but could not be executed. LLDDs should return FAST_IO_FAIL
876883a030fSHannes Reinecke  *    if the device is temporarily unavailable (eg due to a
877883a030fSHannes Reinecke  *    link down on FibreChannel)
878883a030fSHannes Reinecke  */
879883a030fSHannes Reinecke static int scsi_try_to_abort_cmd(struct scsi_host_template *hostt,
880883a030fSHannes Reinecke 				 struct scsi_cmnd *scmd)
881292148f8SBrian King {
8820bf8c869SJesper Juhl 	if (!hostt->eh_abort_handler)
883292148f8SBrian King 		return FAILED;
884292148f8SBrian King 
8850bf8c869SJesper Juhl 	return hostt->eh_abort_handler(scmd);
886292148f8SBrian King }
887292148f8SBrian King 
888292148f8SBrian King static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
889292148f8SBrian King {
8900bf8c869SJesper Juhl 	if (scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd) != SUCCESS)
891292148f8SBrian King 		if (scsi_try_bus_device_reset(scmd) != SUCCESS)
89230bd7df8SMike Christie 			if (scsi_try_target_reset(scmd) != SUCCESS)
893292148f8SBrian King 				if (scsi_try_bus_reset(scmd) != SUCCESS)
894292148f8SBrian King 					scsi_try_host_reset(scmd);
895292148f8SBrian King }
896292148f8SBrian King 
897292148f8SBrian King /**
8983b729f76SSantosh Y  * scsi_eh_prep_cmnd  - Save a scsi command info as part of error recovery
8992dc611deSChristoph Hellwig  * @scmd:       SCSI command structure to hijack
900e1c23468SBoaz Harrosh  * @ses:        structure to save restore information
90155db6c1bSBoaz Harrosh  * @cmnd:       CDB to send. Can be NULL if no new cmnd is needed
90264a87b24SBoaz Harrosh  * @cmnd_size:  size in bytes of @cmnd (must be <= BLK_MAX_CDB)
90355db6c1bSBoaz Harrosh  * @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored)
9042dc611deSChristoph Hellwig  *
905e1c23468SBoaz Harrosh  * This function is used to save a scsi command information before re-execution
90655db6c1bSBoaz Harrosh  * as part of the error recovery process.  If @sense_bytes is 0 the command
90755db6c1bSBoaz Harrosh  * sent must be one that does not transfer any data.  If @sense_bytes != 0
90855db6c1bSBoaz Harrosh  * @cmnd is ignored and this functions sets up a REQUEST_SENSE command
90955db6c1bSBoaz Harrosh  * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer.
910dc8875e1SRandy Dunlap  */
911e1c23468SBoaz Harrosh void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
912e1c23468SBoaz Harrosh 			unsigned char *cmnd, int cmnd_size, unsigned sense_bytes)
9131da177e4SLinus Torvalds {
914f59114b7S 	struct scsi_device *sdev = scmd->device;
9151da177e4SLinus Torvalds 
916631c228cSChristoph Hellwig 	/*
917631c228cSChristoph Hellwig 	 * We need saved copies of a number of fields - this is because
918631c228cSChristoph Hellwig 	 * error handling may need to overwrite these with different values
919631c228cSChristoph Hellwig 	 * to run different commands, and once error handling is complete,
920631c228cSChristoph Hellwig 	 * we will need to restore these values prior to running the actual
921631c228cSChristoph Hellwig 	 * command.
922631c228cSChristoph Hellwig 	 */
923e1c23468SBoaz Harrosh 	ses->cmd_len = scmd->cmd_len;
92464a87b24SBoaz Harrosh 	ses->cmnd = scmd->cmnd;
925e1c23468SBoaz Harrosh 	ses->data_direction = scmd->sc_data_direction;
92630b0c37bSBoaz Harrosh 	ses->sdb = scmd->sdb;
9276f9a35e2SBoaz Harrosh 	ses->next_rq = scmd->request->next_rq;
928e1c23468SBoaz Harrosh 	ses->result = scmd->result;
92912265709SAlan Stern 	ses->underflow = scmd->underflow;
930db007fc5SMartin K. Petersen 	ses->prot_op = scmd->prot_op;
9318e8c9d01SHannes Reinecke 	ses->eh_eflags = scmd->eh_eflags;
932631c228cSChristoph Hellwig 
933db007fc5SMartin K. Petersen 	scmd->prot_op = SCSI_PROT_NORMAL;
934c69e6f81SJames Bottomley 	scmd->eh_eflags = 0;
93564a87b24SBoaz Harrosh 	scmd->cmnd = ses->eh_cmnd;
93664a87b24SBoaz Harrosh 	memset(scmd->cmnd, 0, BLK_MAX_CDB);
93730b0c37bSBoaz Harrosh 	memset(&scmd->sdb, 0, sizeof(scmd->sdb));
9386f9a35e2SBoaz Harrosh 	scmd->request->next_rq = NULL;
939644373a4SAlan Stern 	scmd->result = 0;
94030b0c37bSBoaz Harrosh 
94155db6c1bSBoaz Harrosh 	if (sense_bytes) {
94230b0c37bSBoaz Harrosh 		scmd->sdb.length = min_t(unsigned, SCSI_SENSE_BUFFERSIZE,
94330b0c37bSBoaz Harrosh 					 sense_bytes);
944e1c23468SBoaz Harrosh 		sg_init_one(&ses->sense_sgl, scmd->sense_buffer,
94530b0c37bSBoaz Harrosh 			    scmd->sdb.length);
94630b0c37bSBoaz Harrosh 		scmd->sdb.table.sgl = &ses->sense_sgl;
94755db6c1bSBoaz Harrosh 		scmd->sc_data_direction = DMA_FROM_DEVICE;
9480c958eccSTony Battersby 		scmd->sdb.table.nents = scmd->sdb.table.orig_nents = 1;
94955db6c1bSBoaz Harrosh 		scmd->cmnd[0] = REQUEST_SENSE;
95030b0c37bSBoaz Harrosh 		scmd->cmnd[4] = scmd->sdb.length;
95155db6c1bSBoaz Harrosh 		scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
952631c228cSChristoph Hellwig 	} else {
953631c228cSChristoph Hellwig 		scmd->sc_data_direction = DMA_NONE;
95455db6c1bSBoaz Harrosh 		if (cmnd) {
95564a87b24SBoaz Harrosh 			BUG_ON(cmnd_size > BLK_MAX_CDB);
95655db6c1bSBoaz Harrosh 			memcpy(scmd->cmnd, cmnd, cmnd_size);
95755db6c1bSBoaz Harrosh 			scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
95855db6c1bSBoaz Harrosh 		}
959631c228cSChristoph Hellwig 	}
960631c228cSChristoph Hellwig 
961631c228cSChristoph Hellwig 	scmd->underflow = 0;
962631c228cSChristoph Hellwig 
96355db6c1bSBoaz Harrosh 	if (sdev->scsi_level <= SCSI_2 && sdev->scsi_level != SCSI_UNKNOWN)
9641da177e4SLinus Torvalds 		scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
965f59114b7S 			(sdev->lun << 5 & 0xe0);
9661da177e4SLinus Torvalds 
967631c228cSChristoph Hellwig 	/*
968631c228cSChristoph Hellwig 	 * Zero the sense buffer.  The scsi spec mandates that any
969631c228cSChristoph Hellwig 	 * untransferred sense data should be interpreted as being zero.
970631c228cSChristoph Hellwig 	 */
971b80ca4f7SFUJITA Tomonori 	memset(scmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
972e1c23468SBoaz Harrosh }
973e1c23468SBoaz Harrosh EXPORT_SYMBOL(scsi_eh_prep_cmnd);
974631c228cSChristoph Hellwig 
975e1c23468SBoaz Harrosh /**
9763b729f76SSantosh Y  * scsi_eh_restore_cmnd  - Restore a scsi command info as part of error recovery
977e1c23468SBoaz Harrosh  * @scmd:       SCSI command structure to restore
978477e608cSBartlomiej Zolnierkiewicz  * @ses:        saved information from a coresponding call to scsi_eh_prep_cmnd
979e1c23468SBoaz Harrosh  *
980477e608cSBartlomiej Zolnierkiewicz  * Undo any damage done by above scsi_eh_prep_cmnd().
981dc8875e1SRandy Dunlap  */
982e1c23468SBoaz Harrosh void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
983e1c23468SBoaz Harrosh {
984e1c23468SBoaz Harrosh 	/*
985e1c23468SBoaz Harrosh 	 * Restore original data
986e1c23468SBoaz Harrosh 	 */
987e1c23468SBoaz Harrosh 	scmd->cmd_len = ses->cmd_len;
98864a87b24SBoaz Harrosh 	scmd->cmnd = ses->cmnd;
989e1c23468SBoaz Harrosh 	scmd->sc_data_direction = ses->data_direction;
99030b0c37bSBoaz Harrosh 	scmd->sdb = ses->sdb;
9916f9a35e2SBoaz Harrosh 	scmd->request->next_rq = ses->next_rq;
992e1c23468SBoaz Harrosh 	scmd->result = ses->result;
99312265709SAlan Stern 	scmd->underflow = ses->underflow;
994db007fc5SMartin K. Petersen 	scmd->prot_op = ses->prot_op;
9958e8c9d01SHannes Reinecke 	scmd->eh_eflags = ses->eh_eflags;
996e1c23468SBoaz Harrosh }
997e1c23468SBoaz Harrosh EXPORT_SYMBOL(scsi_eh_restore_cmnd);
998e1c23468SBoaz Harrosh 
999e1c23468SBoaz Harrosh /**
10003b729f76SSantosh Y  * scsi_send_eh_cmnd  - submit a scsi command as part of error recovery
1001e1c23468SBoaz Harrosh  * @scmd:       SCSI command structure to hijack
1002e1c23468SBoaz Harrosh  * @cmnd:       CDB to send
1003e1c23468SBoaz Harrosh  * @cmnd_size:  size in bytes of @cmnd
1004e1c23468SBoaz Harrosh  * @timeout:    timeout for this request
1005e1c23468SBoaz Harrosh  * @sense_bytes: size of sense data to copy or 0
1006e1c23468SBoaz Harrosh  *
1007e1c23468SBoaz Harrosh  * This function is used to send a scsi command down to a target device
1008e1c23468SBoaz Harrosh  * as part of the error recovery process. See also scsi_eh_prep_cmnd() above.
1009e1c23468SBoaz Harrosh  *
1010e1c23468SBoaz Harrosh  * Return value:
1011e1c23468SBoaz Harrosh  *    SUCCESS or FAILED or NEEDS_RETRY
1012dc8875e1SRandy Dunlap  */
1013e1c23468SBoaz Harrosh static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
1014e1c23468SBoaz Harrosh 			     int cmnd_size, int timeout, unsigned sense_bytes)
1015e1c23468SBoaz Harrosh {
1016e1c23468SBoaz Harrosh 	struct scsi_device *sdev = scmd->device;
1017e1c23468SBoaz Harrosh 	struct Scsi_Host *shost = sdev->host;
1018e1c23468SBoaz Harrosh 	DECLARE_COMPLETION_ONSTACK(done);
1019fc73648aSHannes Reinecke 	unsigned long timeleft = timeout;
1020e1c23468SBoaz Harrosh 	struct scsi_eh_save ses;
1021fc73648aSHannes Reinecke 	const unsigned long stall_for = msecs_to_jiffies(100);
1022e1c23468SBoaz Harrosh 	int rtn;
1023e1c23468SBoaz Harrosh 
1024fc73648aSHannes Reinecke retry:
1025e1c23468SBoaz Harrosh 	scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes);
10267dfdc9a5SChristoph Hellwig 	shost->eh_action = &done;
10271da177e4SLinus Torvalds 
10281da177e4SLinus Torvalds 	scsi_log_send(scmd);
1029f281233dSJeff Garzik 	scmd->scsi_done = scsi_eh_done;
1030fc73648aSHannes Reinecke 	rtn = shost->hostt->queuecommand(shost, scmd);
1031fc73648aSHannes Reinecke 	if (rtn) {
1032fc73648aSHannes Reinecke 		if (timeleft > stall_for) {
1033fc73648aSHannes Reinecke 			scsi_eh_restore_cmnd(scmd, &ses);
1034fc73648aSHannes Reinecke 			timeleft -= stall_for;
1035fc73648aSHannes Reinecke 			msleep(jiffies_to_msecs(stall_for));
1036fc73648aSHannes Reinecke 			goto retry;
1037fc73648aSHannes Reinecke 		}
1038fc73648aSHannes Reinecke 		/* signal not to enter either branch of the if () below */
1039fc73648aSHannes Reinecke 		timeleft = 0;
1040511833acSAlan Stern 		rtn = FAILED;
1041fc73648aSHannes Reinecke 	} else {
10427dfdc9a5SChristoph Hellwig 		timeleft = wait_for_completion_timeout(&done, timeout);
1043ac61d195SHannes Reinecke 		rtn = SUCCESS;
1044fc73648aSHannes Reinecke 	}
10451da177e4SLinus Torvalds 
10467dfdc9a5SChristoph Hellwig 	shost->eh_action = NULL;
10471da177e4SLinus Torvalds 
1048fc73648aSHannes Reinecke 	scsi_log_completion(scmd, rtn);
10497dfdc9a5SChristoph Hellwig 
105091921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
1051470613b4SHannes Reinecke 			"%s timeleft: %ld\n",
1052470613b4SHannes Reinecke 			__func__, timeleft));
10531da177e4SLinus Torvalds 
10541da177e4SLinus Torvalds 	/*
1055fc73648aSHannes Reinecke 	 * If there is time left scsi_eh_done got called, and we will examine
1056fc73648aSHannes Reinecke 	 * the actual status codes to see whether the command actually did
1057fc73648aSHannes Reinecke 	 * complete normally, else if we have a zero return and no time left,
1058fc73648aSHannes Reinecke 	 * the command must still be pending, so abort it and return FAILED.
1059fc73648aSHannes Reinecke 	 * If we never actually managed to issue the command, because
1060fc73648aSHannes Reinecke 	 * ->queuecommand() kept returning non zero, use the rtn = FAILED
1061fc73648aSHannes Reinecke 	 * value above (so don't execute either branch of the if)
10621da177e4SLinus Torvalds 	 */
10637dfdc9a5SChristoph Hellwig 	if (timeleft) {
10641da177e4SLinus Torvalds 		rtn = scsi_eh_completed_normally(scmd);
106591921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
106691921e01SHannes Reinecke 			"%s: scsi_eh_completed_normally %x\n", __func__, rtn));
10677dfdc9a5SChristoph Hellwig 
10681da177e4SLinus Torvalds 		switch (rtn) {
10691da177e4SLinus Torvalds 		case SUCCESS:
10701da177e4SLinus Torvalds 		case NEEDS_RETRY:
10711da177e4SLinus Torvalds 		case FAILED:
10721da177e4SLinus Torvalds 			break;
10736e883b0eSHannes Reinecke 		case ADD_TO_MLQUEUE:
10746e883b0eSHannes Reinecke 			rtn = NEEDS_RETRY;
10756e883b0eSHannes Reinecke 			break;
10761da177e4SLinus Torvalds 		default:
10771da177e4SLinus Torvalds 			rtn = FAILED;
10781da177e4SLinus Torvalds 			break;
10791da177e4SLinus Torvalds 		}
1080511833acSAlan Stern 	} else if (rtn != FAILED) {
1081292148f8SBrian King 		scsi_abort_eh_cmnd(scmd);
10827dfdc9a5SChristoph Hellwig 		rtn = FAILED;
10831da177e4SLinus Torvalds 	}
10841da177e4SLinus Torvalds 
1085e1c23468SBoaz Harrosh 	scsi_eh_restore_cmnd(scmd, &ses);
108618a4d0a2SMartin K. Petersen 
10871da177e4SLinus Torvalds 	return rtn;
10881da177e4SLinus Torvalds }
10891da177e4SLinus Torvalds 
10901da177e4SLinus Torvalds /**
10911da177e4SLinus Torvalds  * scsi_request_sense - Request sense data from a particular target.
10921da177e4SLinus Torvalds  * @scmd:	SCSI cmd for request sense.
10931da177e4SLinus Torvalds  *
10941da177e4SLinus Torvalds  * Notes:
10951da177e4SLinus Torvalds  *    Some hosts automatically obtain this information, others require
10961da177e4SLinus Torvalds  *    that we obtain it on our own. This function will *not* return until
10971da177e4SLinus Torvalds  *    the command either times out, or it completes.
1098dc8875e1SRandy Dunlap  */
10991da177e4SLinus Torvalds static int scsi_request_sense(struct scsi_cmnd *scmd)
11001da177e4SLinus Torvalds {
11010816c925SMartin K. Petersen 	return scsi_send_eh_cmnd(scmd, NULL, 0, scmd->device->eh_timeout, ~0);
11021da177e4SLinus Torvalds }
11031da177e4SLinus Torvalds 
11042451079bSJames Bottomley static int scsi_eh_action(struct scsi_cmnd *scmd, int rtn)
11052451079bSJames Bottomley {
110657292b58SChristoph Hellwig 	if (!blk_rq_is_passthrough(scmd->request)) {
11072451079bSJames Bottomley 		struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd);
11082451079bSJames Bottomley 		if (sdrv->eh_action)
11092451079bSJames Bottomley 			rtn = sdrv->eh_action(scmd, rtn);
11102451079bSJames Bottomley 	}
11112451079bSJames Bottomley 	return rtn;
11122451079bSJames Bottomley }
11132451079bSJames Bottomley 
11141da177e4SLinus Torvalds /**
11151da177e4SLinus Torvalds  * scsi_eh_finish_cmd - Handle a cmd that eh is finished with.
11161da177e4SLinus Torvalds  * @scmd:	Original SCSI cmd that eh has finished.
11171da177e4SLinus Torvalds  * @done_q:	Queue for processed commands.
11181da177e4SLinus Torvalds  *
11191da177e4SLinus Torvalds  * Notes:
11201da177e4SLinus Torvalds  *    We don't want to use the normal command completion while we are are
11211da177e4SLinus Torvalds  *    still handling errors - it may cause other commands to be queued,
1122eb44820cSRob Landley  *    and that would disturb what we are doing.  Thus we really want to
11231da177e4SLinus Torvalds  *    keep a list of pending commands for final completion, and once we
11241da177e4SLinus Torvalds  *    are ready to leave error handling we handle completion for real.
1125dc8875e1SRandy Dunlap  */
1126041c5fc3STejun Heo void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
11271da177e4SLinus Torvalds {
11281da177e4SLinus Torvalds 	list_move_tail(&scmd->eh_entry, done_q);
11291da177e4SLinus Torvalds }
1130041c5fc3STejun Heo EXPORT_SYMBOL(scsi_eh_finish_cmd);
11311da177e4SLinus Torvalds 
11321da177e4SLinus Torvalds /**
11331da177e4SLinus Torvalds  * scsi_eh_get_sense - Get device sense data.
11341da177e4SLinus Torvalds  * @work_q:	Queue of commands to process.
1135eb44820cSRob Landley  * @done_q:	Queue of processed commands.
11361da177e4SLinus Torvalds  *
11371da177e4SLinus Torvalds  * Description:
11381da177e4SLinus Torvalds  *    See if we need to request sense information.  if so, then get it
11391da177e4SLinus Torvalds  *    now, so we have a better idea of what to do.
11401da177e4SLinus Torvalds  *
11411da177e4SLinus Torvalds  * Notes:
11421da177e4SLinus Torvalds  *    This has the unfortunate side effect that if a shost adapter does
1143eb44820cSRob Landley  *    not automatically request sense information, we end up shutting
11441da177e4SLinus Torvalds  *    it down before we request it.
11451da177e4SLinus Torvalds  *
11461da177e4SLinus Torvalds  *    All drivers should request sense information internally these days,
11471da177e4SLinus Torvalds  *    so for now all I have to say is tough noogies if you end up in here.
11481da177e4SLinus Torvalds  *
11491da177e4SLinus Torvalds  *    XXX: Long term this code should go away, but that needs an audit of
11501da177e4SLinus Torvalds  *         all LLDDs first.
1151dc8875e1SRandy Dunlap  */
1152dca84e46SDarrick J. Wong int scsi_eh_get_sense(struct list_head *work_q,
11531da177e4SLinus Torvalds 		      struct list_head *done_q)
11541da177e4SLinus Torvalds {
1155937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *next;
1156b4562022SHannes Reinecke 	struct Scsi_Host *shost;
11571da177e4SLinus Torvalds 	int rtn;
11581da177e4SLinus Torvalds 
1159709c75b5Sjiang.biao2@zte.com.cn 	/*
1160709c75b5Sjiang.biao2@zte.com.cn 	 * If SCSI_EH_ABORT_SCHEDULED has been set, it is timeout IO,
1161709c75b5Sjiang.biao2@zte.com.cn 	 * should not get sense.
1162709c75b5Sjiang.biao2@zte.com.cn 	 */
1163937abeaaSChristoph Hellwig 	list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
1164a0658632SHannes Reinecke 		if ((scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) ||
11651da177e4SLinus Torvalds 		    SCSI_SENSE_VALID(scmd))
11661da177e4SLinus Torvalds 			continue;
11671da177e4SLinus Torvalds 
1168b4562022SHannes Reinecke 		shost = scmd->device->host;
1169b4562022SHannes Reinecke 		if (scsi_host_eh_past_deadline(shost)) {
1170b4562022SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
1171a222b1e2SHannes Reinecke 				scmd_printk(KERN_INFO, scmd,
1172a222b1e2SHannes Reinecke 					    "%s: skip request sense, past eh deadline\n",
1173a222b1e2SHannes Reinecke 					     current->comm));
1174b4562022SHannes Reinecke 			break;
1175b4562022SHannes Reinecke 		}
1176d555a2abSJames Bottomley 		if (status_byte(scmd->result) != CHECK_CONDITION)
1177d555a2abSJames Bottomley 			/*
1178d555a2abSJames Bottomley 			 * don't request sense if there's no check condition
1179d555a2abSJames Bottomley 			 * status because the error we're processing isn't one
1180d555a2abSJames Bottomley 			 * that has a sense code (and some devices get
1181d555a2abSJames Bottomley 			 * confused by sense requests out of the blue)
1182d555a2abSJames Bottomley 			 */
1183d555a2abSJames Bottomley 			continue;
1184d555a2abSJames Bottomley 
11853bf743e7SJeff Garzik 		SCSI_LOG_ERROR_RECOVERY(2, scmd_printk(KERN_INFO, scmd,
11863bf743e7SJeff Garzik 						  "%s: requesting sense\n",
11873bf743e7SJeff Garzik 						  current->comm));
11881da177e4SLinus Torvalds 		rtn = scsi_request_sense(scmd);
11891da177e4SLinus Torvalds 		if (rtn != SUCCESS)
11901da177e4SLinus Torvalds 			continue;
11911da177e4SLinus Torvalds 
119291921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
1193470613b4SHannes Reinecke 			"sense requested, result %x\n", scmd->result));
1194d811b848SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3, scsi_print_sense(scmd));
11951da177e4SLinus Torvalds 
11961da177e4SLinus Torvalds 		rtn = scsi_decide_disposition(scmd);
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds 		/*
11991da177e4SLinus Torvalds 		 * if the result was normal, then just pass it along to the
12001da177e4SLinus Torvalds 		 * upper level.
12011da177e4SLinus Torvalds 		 */
12021da177e4SLinus Torvalds 		if (rtn == SUCCESS)
12031da177e4SLinus Torvalds 			/* we don't want this command reissued, just
12041da177e4SLinus Torvalds 			 * finished with the sense data, so set
12051da177e4SLinus Torvalds 			 * retries to the max allowed to ensure it
12061da177e4SLinus Torvalds 			 * won't get reissued */
12071da177e4SLinus Torvalds 			scmd->retries = scmd->allowed;
12081da177e4SLinus Torvalds 		else if (rtn != NEEDS_RETRY)
12091da177e4SLinus Torvalds 			continue;
12101da177e4SLinus Torvalds 
12111da177e4SLinus Torvalds 		scsi_eh_finish_cmd(scmd, done_q);
12121da177e4SLinus Torvalds 	}
12131da177e4SLinus Torvalds 
12141da177e4SLinus Torvalds 	return list_empty(work_q);
12151da177e4SLinus Torvalds }
1216dca84e46SDarrick J. Wong EXPORT_SYMBOL_GPL(scsi_eh_get_sense);
12171da177e4SLinus Torvalds 
12181da177e4SLinus Torvalds /**
12191da177e4SLinus Torvalds  * scsi_eh_tur - Send TUR to device.
1220eb44820cSRob Landley  * @scmd:	&scsi_cmnd to send TUR
12211da177e4SLinus Torvalds  *
12221da177e4SLinus Torvalds  * Return value:
12231da177e4SLinus Torvalds  *    0 - Device is ready. 1 - Device NOT ready.
1224dc8875e1SRandy Dunlap  */
12251da177e4SLinus Torvalds static int scsi_eh_tur(struct scsi_cmnd *scmd)
12261da177e4SLinus Torvalds {
12271da177e4SLinus Torvalds 	static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
12281da177e4SLinus Torvalds 	int retry_cnt = 1, rtn;
12291da177e4SLinus Torvalds 
12301da177e4SLinus Torvalds retry_tur:
12310816c925SMartin K. Petersen 	rtn = scsi_send_eh_cmnd(scmd, tur_command, 6,
12320816c925SMartin K. Petersen 				scmd->device->eh_timeout, 0);
12331da177e4SLinus Torvalds 
123491921e01SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
1235470613b4SHannes Reinecke 		"%s return: %x\n", __func__, rtn));
1236631c228cSChristoph Hellwig 
1237631c228cSChristoph Hellwig 	switch (rtn) {
1238631c228cSChristoph Hellwig 	case NEEDS_RETRY:
12391da177e4SLinus Torvalds 		if (retry_cnt--)
12401da177e4SLinus Torvalds 			goto retry_tur;
1241631c228cSChristoph Hellwig 		/*FALLTHRU*/
1242631c228cSChristoph Hellwig 	case SUCCESS:
1243e47373ecSAlan Stern 		return 0;
1244631c228cSChristoph Hellwig 	default:
12451da177e4SLinus Torvalds 		return 1;
12461da177e4SLinus Torvalds 	}
1247631c228cSChristoph Hellwig }
12481da177e4SLinus Torvalds 
12491da177e4SLinus Torvalds /**
12503eef6257SDavid Jeffery  * scsi_eh_test_devices - check if devices are responding from error recovery.
12513eef6257SDavid Jeffery  * @cmd_list:	scsi commands in error recovery.
12523eef6257SDavid Jeffery  * @work_q:	queue for commands which still need more error recovery
12533eef6257SDavid Jeffery  * @done_q:	queue for commands which are finished
12543eef6257SDavid Jeffery  * @try_stu:	boolean on if a STU command should be tried in addition to TUR.
12553eef6257SDavid Jeffery  *
12563eef6257SDavid Jeffery  * Decription:
12573eef6257SDavid Jeffery  *    Tests if devices are in a working state.  Commands to devices now in
12583eef6257SDavid Jeffery  *    a working state are sent to the done_q while commands to devices which
12593eef6257SDavid Jeffery  *    are still failing to respond are returned to the work_q for more
12603eef6257SDavid Jeffery  *    processing.
12613eef6257SDavid Jeffery  **/
12623eef6257SDavid Jeffery static int scsi_eh_test_devices(struct list_head *cmd_list,
12633eef6257SDavid Jeffery 				struct list_head *work_q,
12643eef6257SDavid Jeffery 				struct list_head *done_q, int try_stu)
12653eef6257SDavid Jeffery {
12663eef6257SDavid Jeffery 	struct scsi_cmnd *scmd, *next;
12673eef6257SDavid Jeffery 	struct scsi_device *sdev;
12683eef6257SDavid Jeffery 	int finish_cmds;
12693eef6257SDavid Jeffery 
12703eef6257SDavid Jeffery 	while (!list_empty(cmd_list)) {
12713eef6257SDavid Jeffery 		scmd = list_entry(cmd_list->next, struct scsi_cmnd, eh_entry);
12723eef6257SDavid Jeffery 		sdev = scmd->device;
12733eef6257SDavid Jeffery 
1274b4562022SHannes Reinecke 		if (!try_stu) {
1275b4562022SHannes Reinecke 			if (scsi_host_eh_past_deadline(sdev->host)) {
1276b4562022SHannes Reinecke 				/* Push items back onto work_q */
1277b4562022SHannes Reinecke 				list_splice_init(cmd_list, work_q);
1278b4562022SHannes Reinecke 				SCSI_LOG_ERROR_RECOVERY(3,
1279a222b1e2SHannes Reinecke 					sdev_printk(KERN_INFO, sdev,
1280a222b1e2SHannes Reinecke 						    "%s: skip test device, past eh deadline",
1281a222b1e2SHannes Reinecke 						    current->comm));
1282b4562022SHannes Reinecke 				break;
1283b4562022SHannes Reinecke 			}
1284b4562022SHannes Reinecke 		}
1285b4562022SHannes Reinecke 
12863eef6257SDavid Jeffery 		finish_cmds = !scsi_device_online(scmd->device) ||
12873eef6257SDavid Jeffery 			(try_stu && !scsi_eh_try_stu(scmd) &&
12883eef6257SDavid Jeffery 			 !scsi_eh_tur(scmd)) ||
12893eef6257SDavid Jeffery 			!scsi_eh_tur(scmd);
12903eef6257SDavid Jeffery 
12913eef6257SDavid Jeffery 		list_for_each_entry_safe(scmd, next, cmd_list, eh_entry)
12923eef6257SDavid Jeffery 			if (scmd->device == sdev) {
12932451079bSJames Bottomley 				if (finish_cmds &&
12942451079bSJames Bottomley 				    (try_stu ||
12952451079bSJames Bottomley 				     scsi_eh_action(scmd, SUCCESS) == SUCCESS))
12963eef6257SDavid Jeffery 					scsi_eh_finish_cmd(scmd, done_q);
12973eef6257SDavid Jeffery 				else
12983eef6257SDavid Jeffery 					list_move_tail(&scmd->eh_entry, work_q);
12993eef6257SDavid Jeffery 			}
13003eef6257SDavid Jeffery 	}
13013eef6257SDavid Jeffery 	return list_empty(work_q);
13023eef6257SDavid Jeffery }
13033eef6257SDavid Jeffery 
13041da177e4SLinus Torvalds /**
13051da177e4SLinus Torvalds  * scsi_eh_try_stu - Send START_UNIT to device.
1306eb44820cSRob Landley  * @scmd:	&scsi_cmnd to send START_UNIT
13071da177e4SLinus Torvalds  *
13081da177e4SLinus Torvalds  * Return value:
13091da177e4SLinus Torvalds  *    0 - Device is ready. 1 - Device NOT ready.
1310dc8875e1SRandy Dunlap  */
13111da177e4SLinus Torvalds static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
13121da177e4SLinus Torvalds {
13131da177e4SLinus Torvalds 	static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
13141da177e4SLinus Torvalds 
1315631c228cSChristoph Hellwig 	if (scmd->device->allow_restart) {
1316ed773e66SBrian King 		int i, rtn = NEEDS_RETRY;
13171da177e4SLinus Torvalds 
1318ed773e66SBrian King 		for (i = 0; rtn == NEEDS_RETRY && i < 2; i++)
13199728c081SJames Bottomley 			rtn = scsi_send_eh_cmnd(scmd, stu_command, 6, scmd->device->request_queue->rq_timeout, 0);
1320ed773e66SBrian King 
13211da177e4SLinus Torvalds 		if (rtn == SUCCESS)
13221da177e4SLinus Torvalds 			return 0;
1323631c228cSChristoph Hellwig 	}
1324631c228cSChristoph Hellwig 
13251da177e4SLinus Torvalds 	return 1;
13261da177e4SLinus Torvalds }
13271da177e4SLinus Torvalds 
13281da177e4SLinus Torvalds  /**
13291da177e4SLinus Torvalds  * scsi_eh_stu - send START_UNIT if needed
1330eb44820cSRob Landley  * @shost:	&scsi host being recovered.
1331eb44820cSRob Landley  * @work_q:	&list_head for pending commands.
1332eb44820cSRob Landley  * @done_q:	&list_head for processed commands.
13331da177e4SLinus Torvalds  *
13341da177e4SLinus Torvalds  * Notes:
13351da177e4SLinus Torvalds  *    If commands are failing due to not ready, initializing command required,
13361da177e4SLinus Torvalds  *	try revalidating the device, which will end up sending a start unit.
1337dc8875e1SRandy Dunlap  */
13381da177e4SLinus Torvalds static int scsi_eh_stu(struct Scsi_Host *shost,
13391da177e4SLinus Torvalds 			      struct list_head *work_q,
13401da177e4SLinus Torvalds 			      struct list_head *done_q)
13411da177e4SLinus Torvalds {
1342937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *stu_scmd, *next;
13431da177e4SLinus Torvalds 	struct scsi_device *sdev;
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds 	shost_for_each_device(sdev, shost) {
1346b4562022SHannes Reinecke 		if (scsi_host_eh_past_deadline(shost)) {
1347b4562022SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
1348a222b1e2SHannes Reinecke 				sdev_printk(KERN_INFO, sdev,
1349a222b1e2SHannes Reinecke 					    "%s: skip START_UNIT, past eh deadline\n",
1350a222b1e2SHannes Reinecke 					    current->comm));
1351b4562022SHannes Reinecke 			break;
1352b4562022SHannes Reinecke 		}
13531da177e4SLinus Torvalds 		stu_scmd = NULL;
13541da177e4SLinus Torvalds 		list_for_each_entry(scmd, work_q, eh_entry)
13551da177e4SLinus Torvalds 			if (scmd->device == sdev && SCSI_SENSE_VALID(scmd) &&
13561da177e4SLinus Torvalds 			    scsi_check_sense(scmd) == FAILED ) {
13571da177e4SLinus Torvalds 				stu_scmd = scmd;
13581da177e4SLinus Torvalds 				break;
13591da177e4SLinus Torvalds 			}
13601da177e4SLinus Torvalds 
13611da177e4SLinus Torvalds 		if (!stu_scmd)
13621da177e4SLinus Torvalds 			continue;
13631da177e4SLinus Torvalds 
136491921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
1365a222b1e2SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
1366a222b1e2SHannes Reinecke 				     "%s: Sending START_UNIT\n",
1367a222b1e2SHannes Reinecke 				    current->comm));
13681da177e4SLinus Torvalds 
13691da177e4SLinus Torvalds 		if (!scsi_eh_try_stu(stu_scmd)) {
13701da177e4SLinus Torvalds 			if (!scsi_device_online(sdev) ||
13711da177e4SLinus Torvalds 			    !scsi_eh_tur(stu_scmd)) {
1372937abeaaSChristoph Hellwig 				list_for_each_entry_safe(scmd, next,
1373937abeaaSChristoph Hellwig 							  work_q, eh_entry) {
13742451079bSJames Bottomley 					if (scmd->device == sdev &&
13752451079bSJames Bottomley 					    scsi_eh_action(scmd, SUCCESS) == SUCCESS)
13761da177e4SLinus Torvalds 						scsi_eh_finish_cmd(scmd, done_q);
13771da177e4SLinus Torvalds 				}
13781da177e4SLinus Torvalds 			}
13791da177e4SLinus Torvalds 		} else {
13801da177e4SLinus Torvalds 			SCSI_LOG_ERROR_RECOVERY(3,
1381a222b1e2SHannes Reinecke 				sdev_printk(KERN_INFO, sdev,
1382a222b1e2SHannes Reinecke 					    "%s: START_UNIT failed\n",
1383a222b1e2SHannes Reinecke 					    current->comm));
13841da177e4SLinus Torvalds 		}
13851da177e4SLinus Torvalds 	}
13861da177e4SLinus Torvalds 
13871da177e4SLinus Torvalds 	return list_empty(work_q);
13881da177e4SLinus Torvalds }
13891da177e4SLinus Torvalds 
13901da177e4SLinus Torvalds 
13911da177e4SLinus Torvalds /**
13921da177e4SLinus Torvalds  * scsi_eh_bus_device_reset - send bdr if needed
13931da177e4SLinus Torvalds  * @shost:	scsi host being recovered.
1394eb44820cSRob Landley  * @work_q:	&list_head for pending commands.
1395eb44820cSRob Landley  * @done_q:	&list_head for processed commands.
13961da177e4SLinus Torvalds  *
13971da177e4SLinus Torvalds  * Notes:
1398eb44820cSRob Landley  *    Try a bus device reset.  Still, look to see whether we have multiple
13991da177e4SLinus Torvalds  *    devices that are jammed or not - if we have multiple devices, it
14001da177e4SLinus Torvalds  *    makes no sense to try bus_device_reset - we really would need to try
14011da177e4SLinus Torvalds  *    a bus_reset instead.
1402dc8875e1SRandy Dunlap  */
14031da177e4SLinus Torvalds static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
14041da177e4SLinus Torvalds 				    struct list_head *work_q,
14051da177e4SLinus Torvalds 				    struct list_head *done_q)
14061da177e4SLinus Torvalds {
1407937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *bdr_scmd, *next;
14081da177e4SLinus Torvalds 	struct scsi_device *sdev;
14091da177e4SLinus Torvalds 	int rtn;
14101da177e4SLinus Torvalds 
14111da177e4SLinus Torvalds 	shost_for_each_device(sdev, shost) {
1412b4562022SHannes Reinecke 		if (scsi_host_eh_past_deadline(shost)) {
1413b4562022SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
1414a222b1e2SHannes Reinecke 				sdev_printk(KERN_INFO, sdev,
1415a222b1e2SHannes Reinecke 					    "%s: skip BDR, past eh deadline\n",
1416a222b1e2SHannes Reinecke 					     current->comm));
1417b4562022SHannes Reinecke 			break;
1418b4562022SHannes Reinecke 		}
14191da177e4SLinus Torvalds 		bdr_scmd = NULL;
14201da177e4SLinus Torvalds 		list_for_each_entry(scmd, work_q, eh_entry)
14211da177e4SLinus Torvalds 			if (scmd->device == sdev) {
14221da177e4SLinus Torvalds 				bdr_scmd = scmd;
14231da177e4SLinus Torvalds 				break;
14241da177e4SLinus Torvalds 			}
14251da177e4SLinus Torvalds 
14261da177e4SLinus Torvalds 		if (!bdr_scmd)
14271da177e4SLinus Torvalds 			continue;
14281da177e4SLinus Torvalds 
142991921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
1430a222b1e2SHannes Reinecke 			sdev_printk(KERN_INFO, sdev,
1431a222b1e2SHannes Reinecke 				     "%s: Sending BDR\n", current->comm));
14321da177e4SLinus Torvalds 		rtn = scsi_try_bus_device_reset(bdr_scmd);
14332f2eb587SChristof Schmitt 		if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
14341da177e4SLinus Torvalds 			if (!scsi_device_online(sdev) ||
14352f2eb587SChristof Schmitt 			    rtn == FAST_IO_FAIL ||
14361da177e4SLinus Torvalds 			    !scsi_eh_tur(bdr_scmd)) {
1437937abeaaSChristoph Hellwig 				list_for_each_entry_safe(scmd, next,
1438937abeaaSChristoph Hellwig 							 work_q, eh_entry) {
14392451079bSJames Bottomley 					if (scmd->device == sdev &&
14402451079bSJames Bottomley 					    scsi_eh_action(scmd, rtn) != FAILED)
14411da177e4SLinus Torvalds 						scsi_eh_finish_cmd(scmd,
14421da177e4SLinus Torvalds 								   done_q);
14431da177e4SLinus Torvalds 				}
14441da177e4SLinus Torvalds 			}
14451da177e4SLinus Torvalds 		} else {
144691921e01SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
1447a222b1e2SHannes Reinecke 				sdev_printk(KERN_INFO, sdev,
1448a222b1e2SHannes Reinecke 					    "%s: BDR failed\n", current->comm));
14491da177e4SLinus Torvalds 		}
14501da177e4SLinus Torvalds 	}
14511da177e4SLinus Torvalds 
14521da177e4SLinus Torvalds 	return list_empty(work_q);
14531da177e4SLinus Torvalds }
14541da177e4SLinus Torvalds 
14551da177e4SLinus Torvalds /**
145630bd7df8SMike Christie  * scsi_eh_target_reset - send target reset if needed
145730bd7df8SMike Christie  * @shost:	scsi host being recovered.
145830bd7df8SMike Christie  * @work_q:	&list_head for pending commands.
145930bd7df8SMike Christie  * @done_q:	&list_head for processed commands.
146030bd7df8SMike Christie  *
146130bd7df8SMike Christie  * Notes:
146230bd7df8SMike Christie  *    Try a target reset.
146330bd7df8SMike Christie  */
146430bd7df8SMike Christie static int scsi_eh_target_reset(struct Scsi_Host *shost,
146530bd7df8SMike Christie 				struct list_head *work_q,
146630bd7df8SMike Christie 				struct list_head *done_q)
146730bd7df8SMike Christie {
146898db5195SJames Bottomley 	LIST_HEAD(tmp_list);
14693eef6257SDavid Jeffery 	LIST_HEAD(check_list);
147030bd7df8SMike Christie 
147198db5195SJames Bottomley 	list_splice_init(work_q, &tmp_list);
147298db5195SJames Bottomley 
147398db5195SJames Bottomley 	while (!list_empty(&tmp_list)) {
147498db5195SJames Bottomley 		struct scsi_cmnd *next, *scmd;
147598db5195SJames Bottomley 		int rtn;
147698db5195SJames Bottomley 		unsigned int id;
1477b4562022SHannes Reinecke 
1478b4562022SHannes Reinecke 		if (scsi_host_eh_past_deadline(shost)) {
1479b4562022SHannes Reinecke 			/* push back on work queue for further processing */
1480b4562022SHannes Reinecke 			list_splice_init(&check_list, work_q);
1481b4562022SHannes Reinecke 			list_splice_init(&tmp_list, work_q);
1482b4562022SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
1483b4562022SHannes Reinecke 				shost_printk(KERN_INFO, shost,
1484a222b1e2SHannes Reinecke 					    "%s: Skip target reset, past eh deadline\n",
1485a222b1e2SHannes Reinecke 					     current->comm));
1486b4562022SHannes Reinecke 			return list_empty(work_q);
1487b4562022SHannes Reinecke 		}
148898db5195SJames Bottomley 
148998db5195SJames Bottomley 		scmd = list_entry(tmp_list.next, struct scsi_cmnd, eh_entry);
149098db5195SJames Bottomley 		id = scmd_id(scmd);
149130bd7df8SMike Christie 
149291921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
149391921e01SHannes Reinecke 			shost_printk(KERN_INFO, shost,
149491921e01SHannes Reinecke 				     "%s: Sending target reset to target %d\n",
149530bd7df8SMike Christie 				     current->comm, id));
149698db5195SJames Bottomley 		rtn = scsi_try_target_reset(scmd);
149798db5195SJames Bottomley 		if (rtn != SUCCESS && rtn != FAST_IO_FAIL)
149891921e01SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
149991921e01SHannes Reinecke 				shost_printk(KERN_INFO, shost,
150091921e01SHannes Reinecke 					     "%s: Target reset failed"
150191921e01SHannes Reinecke 					     " target: %d\n",
150230bd7df8SMike Christie 					     current->comm, id));
150398db5195SJames Bottomley 		list_for_each_entry_safe(scmd, next, &tmp_list, eh_entry) {
150498db5195SJames Bottomley 			if (scmd_id(scmd) != id)
150598db5195SJames Bottomley 				continue;
150698db5195SJames Bottomley 
15073eef6257SDavid Jeffery 			if (rtn == SUCCESS)
15083eef6257SDavid Jeffery 				list_move_tail(&scmd->eh_entry, &check_list);
15093eef6257SDavid Jeffery 			else if (rtn == FAST_IO_FAIL)
151098db5195SJames Bottomley 				scsi_eh_finish_cmd(scmd, done_q);
151198db5195SJames Bottomley 			else
151298db5195SJames Bottomley 				/* push back on work queue for further processing */
151398db5195SJames Bottomley 				list_move(&scmd->eh_entry, work_q);
151498db5195SJames Bottomley 		}
151598db5195SJames Bottomley 	}
151630bd7df8SMike Christie 
15173eef6257SDavid Jeffery 	return scsi_eh_test_devices(&check_list, work_q, done_q, 0);
151830bd7df8SMike Christie }
151930bd7df8SMike Christie 
152030bd7df8SMike Christie /**
15211da177e4SLinus Torvalds  * scsi_eh_bus_reset - send a bus reset
1522eb44820cSRob Landley  * @shost:	&scsi host being recovered.
1523eb44820cSRob Landley  * @work_q:	&list_head for pending commands.
1524eb44820cSRob Landley  * @done_q:	&list_head for processed commands.
1525dc8875e1SRandy Dunlap  */
15261da177e4SLinus Torvalds static int scsi_eh_bus_reset(struct Scsi_Host *shost,
15271da177e4SLinus Torvalds 			     struct list_head *work_q,
15281da177e4SLinus Torvalds 			     struct list_head *done_q)
15291da177e4SLinus Torvalds {
1530937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *chan_scmd, *next;
15313eef6257SDavid Jeffery 	LIST_HEAD(check_list);
15321da177e4SLinus Torvalds 	unsigned int channel;
15331da177e4SLinus Torvalds 	int rtn;
15341da177e4SLinus Torvalds 
15351da177e4SLinus Torvalds 	/*
15361da177e4SLinus Torvalds 	 * we really want to loop over the various channels, and do this on
15371da177e4SLinus Torvalds 	 * a channel by channel basis.  we should also check to see if any
15381da177e4SLinus Torvalds 	 * of the failed commands are on soft_reset devices, and if so, skip
15391da177e4SLinus Torvalds 	 * the reset.
15401da177e4SLinus Torvalds 	 */
15411da177e4SLinus Torvalds 
15421da177e4SLinus Torvalds 	for (channel = 0; channel <= shost->max_channel; channel++) {
1543b4562022SHannes Reinecke 		if (scsi_host_eh_past_deadline(shost)) {
1544b4562022SHannes Reinecke 			list_splice_init(&check_list, work_q);
1545b4562022SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
1546b4562022SHannes Reinecke 				shost_printk(KERN_INFO, shost,
1547a222b1e2SHannes Reinecke 					    "%s: skip BRST, past eh deadline\n",
1548a222b1e2SHannes Reinecke 					     current->comm));
1549b4562022SHannes Reinecke 			return list_empty(work_q);
1550b4562022SHannes Reinecke 		}
1551b4562022SHannes Reinecke 
15521da177e4SLinus Torvalds 		chan_scmd = NULL;
15531da177e4SLinus Torvalds 		list_for_each_entry(scmd, work_q, eh_entry) {
1554422c0d61SJeff Garzik 			if (channel == scmd_channel(scmd)) {
15551da177e4SLinus Torvalds 				chan_scmd = scmd;
15561da177e4SLinus Torvalds 				break;
15571da177e4SLinus Torvalds 				/*
15581da177e4SLinus Torvalds 				 * FIXME add back in some support for
15591da177e4SLinus Torvalds 				 * soft_reset devices.
15601da177e4SLinus Torvalds 				 */
15611da177e4SLinus Torvalds 			}
15621da177e4SLinus Torvalds 		}
15631da177e4SLinus Torvalds 
15641da177e4SLinus Torvalds 		if (!chan_scmd)
15651da177e4SLinus Torvalds 			continue;
156691921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
156791921e01SHannes Reinecke 			shost_printk(KERN_INFO, shost,
156891921e01SHannes Reinecke 				     "%s: Sending BRST chan: %d\n",
156991921e01SHannes Reinecke 				     current->comm, channel));
15701da177e4SLinus Torvalds 		rtn = scsi_try_bus_reset(chan_scmd);
15712f2eb587SChristof Schmitt 		if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
1572937abeaaSChristoph Hellwig 			list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
15733eef6257SDavid Jeffery 				if (channel == scmd_channel(scmd)) {
15743eef6257SDavid Jeffery 					if (rtn == FAST_IO_FAIL)
15751da177e4SLinus Torvalds 						scsi_eh_finish_cmd(scmd,
15761da177e4SLinus Torvalds 								   done_q);
15773eef6257SDavid Jeffery 					else
15783eef6257SDavid Jeffery 						list_move_tail(&scmd->eh_entry,
15793eef6257SDavid Jeffery 							       &check_list);
15803eef6257SDavid Jeffery 				}
15811da177e4SLinus Torvalds 			}
15821da177e4SLinus Torvalds 		} else {
158391921e01SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
158491921e01SHannes Reinecke 				shost_printk(KERN_INFO, shost,
158591921e01SHannes Reinecke 					     "%s: BRST failed chan: %d\n",
158691921e01SHannes Reinecke 					     current->comm, channel));
15871da177e4SLinus Torvalds 		}
15881da177e4SLinus Torvalds 	}
15893eef6257SDavid Jeffery 	return scsi_eh_test_devices(&check_list, work_q, done_q, 0);
15901da177e4SLinus Torvalds }
15911da177e4SLinus Torvalds 
15921da177e4SLinus Torvalds /**
15931da177e4SLinus Torvalds  * scsi_eh_host_reset - send a host reset
159474cf298fSRandy Dunlap  * @shost:	host to be reset.
159574cf298fSRandy Dunlap  * @work_q:	&list_head for pending commands.
159674cf298fSRandy Dunlap  * @done_q:	&list_head for processed commands.
1597dc8875e1SRandy Dunlap  */
159891921e01SHannes Reinecke static int scsi_eh_host_reset(struct Scsi_Host *shost,
159991921e01SHannes Reinecke 			      struct list_head *work_q,
16001da177e4SLinus Torvalds 			      struct list_head *done_q)
16011da177e4SLinus Torvalds {
1602937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *next;
16033eef6257SDavid Jeffery 	LIST_HEAD(check_list);
16041da177e4SLinus Torvalds 	int rtn;
16051da177e4SLinus Torvalds 
16061da177e4SLinus Torvalds 	if (!list_empty(work_q)) {
16071da177e4SLinus Torvalds 		scmd = list_entry(work_q->next,
16081da177e4SLinus Torvalds 				  struct scsi_cmnd, eh_entry);
16091da177e4SLinus Torvalds 
161091921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(3,
161191921e01SHannes Reinecke 			shost_printk(KERN_INFO, shost,
161291921e01SHannes Reinecke 				     "%s: Sending HRST\n",
161391921e01SHannes Reinecke 				     current->comm));
16141da177e4SLinus Torvalds 
16151da177e4SLinus Torvalds 		rtn = scsi_try_host_reset(scmd);
16163eef6257SDavid Jeffery 		if (rtn == SUCCESS) {
16173eef6257SDavid Jeffery 			list_splice_init(work_q, &check_list);
16183eef6257SDavid Jeffery 		} else if (rtn == FAST_IO_FAIL) {
1619937abeaaSChristoph Hellwig 			list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
16201da177e4SLinus Torvalds 					scsi_eh_finish_cmd(scmd, done_q);
16211da177e4SLinus Torvalds 			}
16221da177e4SLinus Torvalds 		} else {
162391921e01SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
162491921e01SHannes Reinecke 				shost_printk(KERN_INFO, shost,
162591921e01SHannes Reinecke 					     "%s: HRST failed\n",
16261da177e4SLinus Torvalds 					     current->comm));
16271da177e4SLinus Torvalds 		}
16281da177e4SLinus Torvalds 	}
16293eef6257SDavid Jeffery 	return scsi_eh_test_devices(&check_list, work_q, done_q, 1);
16301da177e4SLinus Torvalds }
16311da177e4SLinus Torvalds 
16321da177e4SLinus Torvalds /**
16331da177e4SLinus Torvalds  * scsi_eh_offline_sdevs - offline scsi devices that fail to recover
163474cf298fSRandy Dunlap  * @work_q:	&list_head for pending commands.
163574cf298fSRandy Dunlap  * @done_q:	&list_head for processed commands.
1636dc8875e1SRandy Dunlap  */
16371da177e4SLinus Torvalds static void scsi_eh_offline_sdevs(struct list_head *work_q,
16381da177e4SLinus Torvalds 				  struct list_head *done_q)
16391da177e4SLinus Torvalds {
1640937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *next;
16410db6ca8aSBart Van Assche 	struct scsi_device *sdev;
16421da177e4SLinus Torvalds 
1643937abeaaSChristoph Hellwig 	list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
164431765d7dSMatthew Wilcox 		sdev_printk(KERN_INFO, scmd->device, "Device offlined - "
164531765d7dSMatthew Wilcox 			    "not ready after error recovery\n");
16460db6ca8aSBart Van Assche 		sdev = scmd->device;
16470db6ca8aSBart Van Assche 
16480db6ca8aSBart Van Assche 		mutex_lock(&sdev->state_mutex);
16490db6ca8aSBart Van Assche 		scsi_device_set_state(sdev, SDEV_OFFLINE);
16500db6ca8aSBart Van Assche 		mutex_unlock(&sdev->state_mutex);
16510db6ca8aSBart Van Assche 
16521da177e4SLinus Torvalds 		scsi_eh_finish_cmd(scmd, done_q);
16531da177e4SLinus Torvalds 	}
16541da177e4SLinus Torvalds 	return;
16551da177e4SLinus Torvalds }
16561da177e4SLinus Torvalds 
16571da177e4SLinus Torvalds /**
1658e494f6a7SHannes Reinecke  * scsi_noretry_cmd - determine if command should be failed fast
16594a27446fSMike Christie  * @scmd:	SCSI cmd to examine.
16604a27446fSMike Christie  */
16614a27446fSMike Christie int scsi_noretry_cmd(struct scsi_cmnd *scmd)
16624a27446fSMike Christie {
16634a27446fSMike Christie 	switch (host_byte(scmd->result)) {
16644a27446fSMike Christie 	case DID_OK:
16654a27446fSMike Christie 		break;
1666e494f6a7SHannes Reinecke 	case DID_TIME_OUT:
1667e494f6a7SHannes Reinecke 		goto check_type;
16684a27446fSMike Christie 	case DID_BUS_BUSY:
166933659ebbSChristoph Hellwig 		return (scmd->request->cmd_flags & REQ_FAILFAST_TRANSPORT);
16704a27446fSMike Christie 	case DID_PARITY:
167133659ebbSChristoph Hellwig 		return (scmd->request->cmd_flags & REQ_FAILFAST_DEV);
16724a27446fSMike Christie 	case DID_ERROR:
16734a27446fSMike Christie 		if (msg_byte(scmd->result) == COMMAND_COMPLETE &&
16744a27446fSMike Christie 		    status_byte(scmd->result) == RESERVATION_CONFLICT)
16754a27446fSMike Christie 			return 0;
16764a27446fSMike Christie 		/* fall through */
16774a27446fSMike Christie 	case DID_SOFT_ERROR:
167833659ebbSChristoph Hellwig 		return (scmd->request->cmd_flags & REQ_FAILFAST_DRIVER);
16794a27446fSMike Christie 	}
16804a27446fSMike Christie 
1681e494f6a7SHannes Reinecke 	if (status_byte(scmd->result) != CHECK_CONDITION)
1682e494f6a7SHannes Reinecke 		return 0;
1683e494f6a7SHannes Reinecke 
1684e494f6a7SHannes Reinecke check_type:
16854a27446fSMike Christie 	/*
1686e494f6a7SHannes Reinecke 	 * assume caller has checked sense and determined
16874a27446fSMike Christie 	 * the check condition was retryable.
16884a27446fSMike Christie 	 */
1689e96f6abeSFUJITA Tomonori 	if (scmd->request->cmd_flags & REQ_FAILFAST_DEV ||
169057292b58SChristoph Hellwig 	    blk_rq_is_passthrough(scmd->request))
1691e96f6abeSFUJITA Tomonori 		return 1;
1692e494f6a7SHannes Reinecke 	else
16934a27446fSMike Christie 		return 0;
16944a27446fSMike Christie }
16954a27446fSMike Christie 
16964a27446fSMike Christie /**
16971da177e4SLinus Torvalds  * scsi_decide_disposition - Disposition a cmd on return from LLD.
16981da177e4SLinus Torvalds  * @scmd:	SCSI cmd to examine.
16991da177e4SLinus Torvalds  *
17001da177e4SLinus Torvalds  * Notes:
17011da177e4SLinus Torvalds  *    This is *only* called when we are examining the status after sending
17021da177e4SLinus Torvalds  *    out the actual data command.  any commands that are queued for error
17031da177e4SLinus Torvalds  *    recovery (e.g. test_unit_ready) do *not* come through here.
17041da177e4SLinus Torvalds  *
17051da177e4SLinus Torvalds  *    When this routine returns failed, it means the error handler thread
17061da177e4SLinus Torvalds  *    is woken.  In cases where the error code indicates an error that
17071da177e4SLinus Torvalds  *    doesn't require the error handler read (i.e. we don't need to
17081da177e4SLinus Torvalds  *    abort/reset), this function should return SUCCESS.
1709dc8875e1SRandy Dunlap  */
17101da177e4SLinus Torvalds int scsi_decide_disposition(struct scsi_cmnd *scmd)
17111da177e4SLinus Torvalds {
17121da177e4SLinus Torvalds 	int rtn;
17131da177e4SLinus Torvalds 
17141da177e4SLinus Torvalds 	/*
17151da177e4SLinus Torvalds 	 * if the device is offline, then we clearly just pass the result back
17161da177e4SLinus Torvalds 	 * up to the top level.
17171da177e4SLinus Torvalds 	 */
17181da177e4SLinus Torvalds 	if (!scsi_device_online(scmd->device)) {
171991921e01SHannes Reinecke 		SCSI_LOG_ERROR_RECOVERY(5, scmd_printk(KERN_INFO, scmd,
172091921e01SHannes Reinecke 			"%s: device offline - report as SUCCESS\n", __func__));
17211da177e4SLinus Torvalds 		return SUCCESS;
17221da177e4SLinus Torvalds 	}
17231da177e4SLinus Torvalds 
17241da177e4SLinus Torvalds 	/*
17251da177e4SLinus Torvalds 	 * first check the host byte, to see if there is anything in there
17261da177e4SLinus Torvalds 	 * that would indicate what we need to do.
17271da177e4SLinus Torvalds 	 */
17281da177e4SLinus Torvalds 	switch (host_byte(scmd->result)) {
17291da177e4SLinus Torvalds 	case DID_PASSTHROUGH:
17301da177e4SLinus Torvalds 		/*
17311da177e4SLinus Torvalds 		 * no matter what, pass this through to the upper layer.
17321da177e4SLinus Torvalds 		 * nuke this special code so that it looks like we are saying
17331da177e4SLinus Torvalds 		 * did_ok.
17341da177e4SLinus Torvalds 		 */
17351da177e4SLinus Torvalds 		scmd->result &= 0xff00ffff;
17361da177e4SLinus Torvalds 		return SUCCESS;
17371da177e4SLinus Torvalds 	case DID_OK:
17381da177e4SLinus Torvalds 		/*
17391da177e4SLinus Torvalds 		 * looks good.  drop through, and check the next byte.
17401da177e4SLinus Torvalds 		 */
17411da177e4SLinus Torvalds 		break;
1742e494f6a7SHannes Reinecke 	case DID_ABORT:
1743e494f6a7SHannes Reinecke 		if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) {
17448922a908SUlrich Obergfell 			set_host_byte(scmd, DID_TIME_OUT);
1745e494f6a7SHannes Reinecke 			return SUCCESS;
1746e494f6a7SHannes Reinecke 		}
17473bf2ff67SBart Van Assche 		/* FALLTHROUGH */
17481da177e4SLinus Torvalds 	case DID_NO_CONNECT:
17491da177e4SLinus Torvalds 	case DID_BAD_TARGET:
17501da177e4SLinus Torvalds 		/*
17511da177e4SLinus Torvalds 		 * note - this means that we just report the status back
17521da177e4SLinus Torvalds 		 * to the top level driver, not that we actually think
17531da177e4SLinus Torvalds 		 * that it indicates SUCCESS.
17541da177e4SLinus Torvalds 		 */
17551da177e4SLinus Torvalds 		return SUCCESS;
1756*ad95028aSPetros Koutoupis 	case DID_SOFT_ERROR:
17571da177e4SLinus Torvalds 		/*
17581da177e4SLinus Torvalds 		 * when the low level driver returns did_soft_error,
17591da177e4SLinus Torvalds 		 * it is responsible for keeping an internal retry counter
17601da177e4SLinus Torvalds 		 * in order to avoid endless loops (db)
17611da177e4SLinus Torvalds 		 */
17621da177e4SLinus Torvalds 		goto maybe_retry;
17631da177e4SLinus Torvalds 	case DID_IMM_RETRY:
17641da177e4SLinus Torvalds 		return NEEDS_RETRY;
17651da177e4SLinus Torvalds 
1766bf341919S 	case DID_REQUEUE:
1767bf341919S 		return ADD_TO_MLQUEUE;
1768a4dfaa6fSMike Christie 	case DID_TRANSPORT_DISRUPTED:
1769a4dfaa6fSMike Christie 		/*
1770a4dfaa6fSMike Christie 		 * LLD/transport was disrupted during processing of the IO.
1771a4dfaa6fSMike Christie 		 * The transport class is now blocked/blocking,
1772a4dfaa6fSMike Christie 		 * and the transport will decide what to do with the IO
1773939c2288SMike Christie 		 * based on its timers and recovery capablilities if
1774939c2288SMike Christie 		 * there are enough retries.
1775a4dfaa6fSMike Christie 		 */
1776939c2288SMike Christie 		goto maybe_retry;
1777a4dfaa6fSMike Christie 	case DID_TRANSPORT_FAILFAST:
1778a4dfaa6fSMike Christie 		/*
1779a4dfaa6fSMike Christie 		 * The transport decided to failfast the IO (most likely
1780a4dfaa6fSMike Christie 		 * the fast io fail tmo fired), so send IO directly upwards.
1781a4dfaa6fSMike Christie 		 */
1782a4dfaa6fSMike Christie 		return SUCCESS;
17831da177e4SLinus Torvalds 	case DID_ERROR:
17841da177e4SLinus Torvalds 		if (msg_byte(scmd->result) == COMMAND_COMPLETE &&
17851da177e4SLinus Torvalds 		    status_byte(scmd->result) == RESERVATION_CONFLICT)
17861da177e4SLinus Torvalds 			/*
17871da177e4SLinus Torvalds 			 * execute reservation conflict processing code
17881da177e4SLinus Torvalds 			 * lower down
17891da177e4SLinus Torvalds 			 */
17901da177e4SLinus Torvalds 			break;
17911da177e4SLinus Torvalds 		/* fallthrough */
17921da177e4SLinus Torvalds 	case DID_BUS_BUSY:
17931da177e4SLinus Torvalds 	case DID_PARITY:
17941da177e4SLinus Torvalds 		goto maybe_retry;
17951da177e4SLinus Torvalds 	case DID_TIME_OUT:
17961da177e4SLinus Torvalds 		/*
17971da177e4SLinus Torvalds 		 * when we scan the bus, we get timeout messages for
17981da177e4SLinus Torvalds 		 * these commands if there is no device available.
17991da177e4SLinus Torvalds 		 * other hosts report did_no_connect for the same thing.
18001da177e4SLinus Torvalds 		 */
18011da177e4SLinus Torvalds 		if ((scmd->cmnd[0] == TEST_UNIT_READY ||
18021da177e4SLinus Torvalds 		     scmd->cmnd[0] == INQUIRY)) {
18031da177e4SLinus Torvalds 			return SUCCESS;
18041da177e4SLinus Torvalds 		} else {
18051da177e4SLinus Torvalds 			return FAILED;
18061da177e4SLinus Torvalds 		}
18071da177e4SLinus Torvalds 	case DID_RESET:
18081da177e4SLinus Torvalds 		return SUCCESS;
18091da177e4SLinus Torvalds 	default:
18101da177e4SLinus Torvalds 		return FAILED;
18111da177e4SLinus Torvalds 	}
18121da177e4SLinus Torvalds 
18131da177e4SLinus Torvalds 	/*
18141da177e4SLinus Torvalds 	 * next, check the message byte.
18151da177e4SLinus Torvalds 	 */
18161da177e4SLinus Torvalds 	if (msg_byte(scmd->result) != COMMAND_COMPLETE)
18171da177e4SLinus Torvalds 		return FAILED;
18181da177e4SLinus Torvalds 
18191da177e4SLinus Torvalds 	/*
18201da177e4SLinus Torvalds 	 * check the status byte to see if this indicates anything special.
18211da177e4SLinus Torvalds 	 */
18221da177e4SLinus Torvalds 	switch (status_byte(scmd->result)) {
18231da177e4SLinus Torvalds 	case QUEUE_FULL:
182442a6a918SMike Christie 		scsi_handle_queue_full(scmd->device);
18251da177e4SLinus Torvalds 		/*
18261da177e4SLinus Torvalds 		 * the case of trying to send too many commands to a
18271da177e4SLinus Torvalds 		 * tagged queueing device.
18281da177e4SLinus Torvalds 		 */
18293bf2ff67SBart Van Assche 		/* FALLTHROUGH */
18301da177e4SLinus Torvalds 	case BUSY:
18311da177e4SLinus Torvalds 		/*
18321da177e4SLinus Torvalds 		 * device can't talk to us at the moment.  Should only
18331da177e4SLinus Torvalds 		 * occur (SAM-3) when the task queue is empty, so will cause
18341da177e4SLinus Torvalds 		 * the empty queue handling to trigger a stall in the
18351da177e4SLinus Torvalds 		 * device.
18361da177e4SLinus Torvalds 		 */
18371da177e4SLinus Torvalds 		return ADD_TO_MLQUEUE;
18381da177e4SLinus Torvalds 	case GOOD:
1839279afdfeSEwan D. Milne 		if (scmd->cmnd[0] == REPORT_LUNS)
1840279afdfeSEwan D. Milne 			scmd->device->sdev_target->expecting_lun_change = 0;
18414a84067dSVasu Dev 		scsi_handle_queue_ramp_up(scmd->device);
18423bf2ff67SBart Van Assche 		/* FALLTHROUGH */
18431da177e4SLinus Torvalds 	case COMMAND_TERMINATED:
18441da177e4SLinus Torvalds 		return SUCCESS;
1845a9b589d9SVladislav Bolkhovitin 	case TASK_ABORTED:
1846a9b589d9SVladislav Bolkhovitin 		goto maybe_retry;
18471da177e4SLinus Torvalds 	case CHECK_CONDITION:
18481da177e4SLinus Torvalds 		rtn = scsi_check_sense(scmd);
18491da177e4SLinus Torvalds 		if (rtn == NEEDS_RETRY)
18501da177e4SLinus Torvalds 			goto maybe_retry;
18511da177e4SLinus Torvalds 		/* if rtn == FAILED, we have no sense information;
18521da177e4SLinus Torvalds 		 * returning FAILED will wake the error handler thread
18531da177e4SLinus Torvalds 		 * to collect the sense and redo the decide
18541da177e4SLinus Torvalds 		 * disposition */
18551da177e4SLinus Torvalds 		return rtn;
18561da177e4SLinus Torvalds 	case CONDITION_GOOD:
18571da177e4SLinus Torvalds 	case INTERMEDIATE_GOOD:
18581da177e4SLinus Torvalds 	case INTERMEDIATE_C_GOOD:
18591da177e4SLinus Torvalds 	case ACA_ACTIVE:
18601da177e4SLinus Torvalds 		/*
18611da177e4SLinus Torvalds 		 * who knows?  FIXME(eric)
18621da177e4SLinus Torvalds 		 */
18631da177e4SLinus Torvalds 		return SUCCESS;
18641da177e4SLinus Torvalds 
18651da177e4SLinus Torvalds 	case RESERVATION_CONFLICT:
18669ccfc756SJames Bottomley 		sdev_printk(KERN_INFO, scmd->device,
18679ccfc756SJames Bottomley 			    "reservation conflict\n");
18682082ebc4SMoger, Babu 		set_host_byte(scmd, DID_NEXUS_FAILURE);
18691da177e4SLinus Torvalds 		return SUCCESS; /* causes immediate i/o error */
18701da177e4SLinus Torvalds 	default:
18711da177e4SLinus Torvalds 		return FAILED;
18721da177e4SLinus Torvalds 	}
18731da177e4SLinus Torvalds 	return FAILED;
18741da177e4SLinus Torvalds 
18751da177e4SLinus Torvalds       maybe_retry:
18761da177e4SLinus Torvalds 
18771da177e4SLinus Torvalds 	/* we requeue for retry because the error was retryable, and
18781da177e4SLinus Torvalds 	 * the request was not marked fast fail.  Note that above,
18791da177e4SLinus Torvalds 	 * even if the request is marked fast fail, we still requeue
18801da177e4SLinus Torvalds 	 * for queue congestion conditions (QUEUE_FULL or BUSY) */
18818884efabSBrian King 	if ((++scmd->retries) <= scmd->allowed
18824a27446fSMike Christie 	    && !scsi_noretry_cmd(scmd)) {
18831da177e4SLinus Torvalds 		return NEEDS_RETRY;
18841da177e4SLinus Torvalds 	} else {
18851da177e4SLinus Torvalds 		/*
18861da177e4SLinus Torvalds 		 * no more retries - report this one back to upper level.
18871da177e4SLinus Torvalds 		 */
18881da177e4SLinus Torvalds 		return SUCCESS;
18891da177e4SLinus Torvalds 	}
18901da177e4SLinus Torvalds }
18911da177e4SLinus Torvalds 
18922a842acaSChristoph Hellwig static void eh_lock_door_done(struct request *req, blk_status_t status)
1893f078727bSFUJITA Tomonori {
1894f078727bSFUJITA Tomonori 	__blk_put_request(req->q, req);
1895f078727bSFUJITA Tomonori }
1896f078727bSFUJITA Tomonori 
18971da177e4SLinus Torvalds /**
18981da177e4SLinus Torvalds  * scsi_eh_lock_door - Prevent medium removal for the specified device
18991da177e4SLinus Torvalds  * @sdev:	SCSI device to prevent medium removal
19001da177e4SLinus Torvalds  *
19011da177e4SLinus Torvalds  * Locking:
190291bc31fbSJames Bottomley  * 	We must be called from process context.
19031da177e4SLinus Torvalds  *
19041da177e4SLinus Torvalds  * Notes:
19051da177e4SLinus Torvalds  * 	We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request on the
19061da177e4SLinus Torvalds  * 	head of the devices request queue, and continue.
1907dc8875e1SRandy Dunlap  */
19081da177e4SLinus Torvalds static void scsi_eh_lock_door(struct scsi_device *sdev)
19091da177e4SLinus Torvalds {
1910f078727bSFUJITA Tomonori 	struct request *req;
191182ed4db4SChristoph Hellwig 	struct scsi_request *rq;
19121da177e4SLinus Torvalds 
191391bc31fbSJames Bottomley 	/*
191471baba4bSMel Gorman 	 * blk_get_request with GFP_KERNEL (__GFP_RECLAIM) sleeps until a
191591bc31fbSJames Bottomley 	 * request becomes available
191691bc31fbSJames Bottomley 	 */
1917aebf526bSChristoph Hellwig 	req = blk_get_request(sdev->request_queue, REQ_OP_SCSI_IN, GFP_KERNEL);
1918a492f075SJoe Lawrence 	if (IS_ERR(req))
1919eb571eeaSJoe Lawrence 		return;
192082ed4db4SChristoph Hellwig 	rq = scsi_req(req);
19211da177e4SLinus Torvalds 
192282ed4db4SChristoph Hellwig 	rq->cmd[0] = ALLOW_MEDIUM_REMOVAL;
192382ed4db4SChristoph Hellwig 	rq->cmd[1] = 0;
192482ed4db4SChristoph Hellwig 	rq->cmd[2] = 0;
192582ed4db4SChristoph Hellwig 	rq->cmd[3] = 0;
192682ed4db4SChristoph Hellwig 	rq->cmd[4] = SCSI_REMOVAL_PREVENT;
192782ed4db4SChristoph Hellwig 	rq->cmd[5] = 0;
192882ed4db4SChristoph Hellwig 	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
1929f078727bSFUJITA Tomonori 
1930e8064021SChristoph Hellwig 	req->rq_flags |= RQF_QUIET;
1931f078727bSFUJITA Tomonori 	req->timeout = 10 * HZ;
193264c7f1d1SChristoph Hellwig 	rq->retries = 5;
1933f078727bSFUJITA Tomonori 
1934f078727bSFUJITA Tomonori 	blk_execute_rq_nowait(req->q, NULL, req, 1, eh_lock_door_done);
19351da177e4SLinus Torvalds }
19361da177e4SLinus Torvalds 
19371da177e4SLinus Torvalds /**
19381da177e4SLinus Torvalds  * scsi_restart_operations - restart io operations to the specified host.
19391da177e4SLinus Torvalds  * @shost:	Host we are restarting.
19401da177e4SLinus Torvalds  *
19411da177e4SLinus Torvalds  * Notes:
19421da177e4SLinus Torvalds  *    When we entered the error handler, we blocked all further i/o to
19431da177e4SLinus Torvalds  *    this device.  we need to 'reverse' this process.
1944dc8875e1SRandy Dunlap  */
19451da177e4SLinus Torvalds static void scsi_restart_operations(struct Scsi_Host *shost)
19461da177e4SLinus Torvalds {
19471da177e4SLinus Torvalds 	struct scsi_device *sdev;
1948939647eeSJames Bottomley 	unsigned long flags;
19491da177e4SLinus Torvalds 
19501da177e4SLinus Torvalds 	/*
19511da177e4SLinus Torvalds 	 * If the door was locked, we need to insert a door lock request
19521da177e4SLinus Torvalds 	 * onto the head of the SCSI request queue for the device.  There
19531da177e4SLinus Torvalds 	 * is no point trying to lock the door of an off-line device.
19541da177e4SLinus Torvalds 	 */
19551da177e4SLinus Torvalds 	shost_for_each_device(sdev, shost) {
195648379270SChristoph Hellwig 		if (scsi_device_online(sdev) && sdev->was_reset && sdev->locked) {
19571da177e4SLinus Torvalds 			scsi_eh_lock_door(sdev);
195848379270SChristoph Hellwig 			sdev->was_reset = 0;
195948379270SChristoph Hellwig 		}
19601da177e4SLinus Torvalds 	}
19611da177e4SLinus Torvalds 
19621da177e4SLinus Torvalds 	/*
19631da177e4SLinus Torvalds 	 * next free up anything directly waiting upon the host.  this
19641da177e4SLinus Torvalds 	 * will be requests for character device operations, and also for
19651da177e4SLinus Torvalds 	 * ioctls to queued block devices.
19661da177e4SLinus Torvalds 	 */
1967b4562022SHannes Reinecke 	SCSI_LOG_ERROR_RECOVERY(3,
196891921e01SHannes Reinecke 		shost_printk(KERN_INFO, shost, "waking up host to restart\n"));
19691da177e4SLinus Torvalds 
1970939647eeSJames Bottomley 	spin_lock_irqsave(shost->host_lock, flags);
1971939647eeSJames Bottomley 	if (scsi_host_set_state(shost, SHOST_RUNNING))
1972939647eeSJames Bottomley 		if (scsi_host_set_state(shost, SHOST_CANCEL))
1973939647eeSJames Bottomley 			BUG_ON(scsi_host_set_state(shost, SHOST_DEL));
1974939647eeSJames Bottomley 	spin_unlock_irqrestore(shost->host_lock, flags);
19751da177e4SLinus Torvalds 
19761da177e4SLinus Torvalds 	wake_up(&shost->host_wait);
19771da177e4SLinus Torvalds 
19781da177e4SLinus Torvalds 	/*
19791da177e4SLinus Torvalds 	 * finally we need to re-initiate requests that may be pending.  we will
19801da177e4SLinus Torvalds 	 * have had everything blocked while error handling is taking place, and
19811da177e4SLinus Torvalds 	 * now that error recovery is done, we will need to ensure that these
19821da177e4SLinus Torvalds 	 * requests are started.
19831da177e4SLinus Torvalds 	 */
19841da177e4SLinus Torvalds 	scsi_run_host_queues(shost);
198557fc2e33SDan Williams 
198657fc2e33SDan Williams 	/*
198757fc2e33SDan Williams 	 * if eh is active and host_eh_scheduled is pending we need to re-run
198857fc2e33SDan Williams 	 * recovery.  we do this check after scsi_run_host_queues() to allow
198957fc2e33SDan Williams 	 * everything pent up since the last eh run a chance to make forward
199057fc2e33SDan Williams 	 * progress before we sync again.  Either we'll immediately re-run
199157fc2e33SDan Williams 	 * recovery or scsi_device_unbusy() will wake us again when these
199257fc2e33SDan Williams 	 * pending commands complete.
199357fc2e33SDan Williams 	 */
199457fc2e33SDan Williams 	spin_lock_irqsave(shost->host_lock, flags);
199557fc2e33SDan Williams 	if (shost->host_eh_scheduled)
199657fc2e33SDan Williams 		if (scsi_host_set_state(shost, SHOST_RECOVERY))
199757fc2e33SDan Williams 			WARN_ON(scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY));
199857fc2e33SDan Williams 	spin_unlock_irqrestore(shost->host_lock, flags);
19991da177e4SLinus Torvalds }
20001da177e4SLinus Torvalds 
20011da177e4SLinus Torvalds /**
20021da177e4SLinus Torvalds  * scsi_eh_ready_devs - check device ready state and recover if not.
20031da177e4SLinus Torvalds  * @shost:	host to be recovered.
2004eb44820cSRob Landley  * @work_q:	&list_head for pending commands.
2005eb44820cSRob Landley  * @done_q:	&list_head for processed commands.
2006dc8875e1SRandy Dunlap  */
2007dca84e46SDarrick J. Wong void scsi_eh_ready_devs(struct Scsi_Host *shost,
20081da177e4SLinus Torvalds 			struct list_head *work_q,
20091da177e4SLinus Torvalds 			struct list_head *done_q)
20101da177e4SLinus Torvalds {
20111da177e4SLinus Torvalds 	if (!scsi_eh_stu(shost, work_q, done_q))
20121da177e4SLinus Torvalds 		if (!scsi_eh_bus_device_reset(shost, work_q, done_q))
201330bd7df8SMike Christie 			if (!scsi_eh_target_reset(shost, work_q, done_q))
20141da177e4SLinus Torvalds 				if (!scsi_eh_bus_reset(shost, work_q, done_q))
201591921e01SHannes Reinecke 					if (!scsi_eh_host_reset(shost, work_q, done_q))
201630bd7df8SMike Christie 						scsi_eh_offline_sdevs(work_q,
201730bd7df8SMike Christie 								      done_q);
20181da177e4SLinus Torvalds }
2019dca84e46SDarrick J. Wong EXPORT_SYMBOL_GPL(scsi_eh_ready_devs);
20201da177e4SLinus Torvalds 
20211da177e4SLinus Torvalds /**
20221da177e4SLinus Torvalds  * scsi_eh_flush_done_q - finish processed commands or retry them.
20231da177e4SLinus Torvalds  * @done_q:	list_head of processed commands.
2024dc8875e1SRandy Dunlap  */
2025041c5fc3STejun Heo void scsi_eh_flush_done_q(struct list_head *done_q)
20261da177e4SLinus Torvalds {
2027937abeaaSChristoph Hellwig 	struct scsi_cmnd *scmd, *next;
20281da177e4SLinus Torvalds 
2029937abeaaSChristoph Hellwig 	list_for_each_entry_safe(scmd, next, done_q, eh_entry) {
2030937abeaaSChristoph Hellwig 		list_del_init(&scmd->eh_entry);
20311da177e4SLinus Torvalds 		if (scsi_device_online(scmd->device) &&
20324a27446fSMike Christie 		    !scsi_noretry_cmd(scmd) &&
20338884efabSBrian King 		    (++scmd->retries <= scmd->allowed)) {
203491921e01SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
203591921e01SHannes Reinecke 				scmd_printk(KERN_INFO, scmd,
2036470613b4SHannes Reinecke 					     "%s: flush retry cmd\n",
2037470613b4SHannes Reinecke 					     current->comm));
20381da177e4SLinus Torvalds 				scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
20391da177e4SLinus Torvalds 		} else {
2040793698ceSPatrick Mansfield  			/*
2041793698ceSPatrick Mansfield  			 * If just we got sense for the device (called
2042793698ceSPatrick Mansfield  			 * scsi_eh_get_sense), scmd->result is already
2043793698ceSPatrick Mansfield  			 * set, do not set DRIVER_TIMEOUT.
2044793698ceSPatrick Mansfield  			 */
20451da177e4SLinus Torvalds 			if (!scmd->result)
20461da177e4SLinus Torvalds 				scmd->result |= (DRIVER_TIMEOUT << 24);
204791921e01SHannes Reinecke 			SCSI_LOG_ERROR_RECOVERY(3,
204891921e01SHannes Reinecke 				scmd_printk(KERN_INFO, scmd,
2049470613b4SHannes Reinecke 					     "%s: flush finish cmd\n",
2050470613b4SHannes Reinecke 					     current->comm));
20511da177e4SLinus Torvalds 			scsi_finish_command(scmd);
20521da177e4SLinus Torvalds 		}
20531da177e4SLinus Torvalds 	}
20541da177e4SLinus Torvalds }
2055041c5fc3STejun Heo EXPORT_SYMBOL(scsi_eh_flush_done_q);
20561da177e4SLinus Torvalds 
20571da177e4SLinus Torvalds /**
20581da177e4SLinus Torvalds  * scsi_unjam_host - Attempt to fix a host which has a cmd that failed.
20591da177e4SLinus Torvalds  * @shost:	Host to unjam.
20601da177e4SLinus Torvalds  *
20611da177e4SLinus Torvalds  * Notes:
20621da177e4SLinus Torvalds  *    When we come in here, we *know* that all commands on the bus have
20631da177e4SLinus Torvalds  *    either completed, failed or timed out.  we also know that no further
20641da177e4SLinus Torvalds  *    commands are being sent to the host, so things are relatively quiet
20651da177e4SLinus Torvalds  *    and we have freedom to fiddle with things as we wish.
20661da177e4SLinus Torvalds  *
20671da177e4SLinus Torvalds  *    This is only the *default* implementation.  it is possible for
20681da177e4SLinus Torvalds  *    individual drivers to supply their own version of this function, and
20691da177e4SLinus Torvalds  *    if the maintainer wishes to do this, it is strongly suggested that
20701da177e4SLinus Torvalds  *    this function be taken as a template and modified.  this function
20711da177e4SLinus Torvalds  *    was designed to correctly handle problems for about 95% of the
20721da177e4SLinus Torvalds  *    different cases out there, and it should always provide at least a
20731da177e4SLinus Torvalds  *    reasonable amount of error recovery.
20741da177e4SLinus Torvalds  *
20751da177e4SLinus Torvalds  *    Any command marked 'failed' or 'timeout' must eventually have
20761da177e4SLinus Torvalds  *    scsi_finish_cmd() called for it.  we do all of the retry stuff
20771da177e4SLinus Torvalds  *    here, so when we restart the host after we return it should have an
20781da177e4SLinus Torvalds  *    empty queue.
2079dc8875e1SRandy Dunlap  */
20801da177e4SLinus Torvalds static void scsi_unjam_host(struct Scsi_Host *shost)
20811da177e4SLinus Torvalds {
20821da177e4SLinus Torvalds 	unsigned long flags;
20831da177e4SLinus Torvalds 	LIST_HEAD(eh_work_q);
20841da177e4SLinus Torvalds 	LIST_HEAD(eh_done_q);
20851da177e4SLinus Torvalds 
20861da177e4SLinus Torvalds 	spin_lock_irqsave(shost->host_lock, flags);
20871da177e4SLinus Torvalds 	list_splice_init(&shost->eh_cmd_q, &eh_work_q);
20881da177e4SLinus Torvalds 	spin_unlock_irqrestore(shost->host_lock, flags);
20891da177e4SLinus Torvalds 
20901da177e4SLinus Torvalds 	SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(shost, &eh_work_q));
20911da177e4SLinus Torvalds 
20921da177e4SLinus Torvalds 	if (!scsi_eh_get_sense(&eh_work_q, &eh_done_q))
20931da177e4SLinus Torvalds 		scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q);
20941da177e4SLinus Torvalds 
2095b4562022SHannes Reinecke 	spin_lock_irqsave(shost->host_lock, flags);
2096bb3b621aSRen Mingxin 	if (shost->eh_deadline != -1)
2097b4562022SHannes Reinecke 		shost->last_reset = 0;
2098b4562022SHannes Reinecke 	spin_unlock_irqrestore(shost->host_lock, flags);
20991da177e4SLinus Torvalds 	scsi_eh_flush_done_q(&eh_done_q);
21001da177e4SLinus Torvalds }
21011da177e4SLinus Torvalds 
21021da177e4SLinus Torvalds /**
2103ad42eb1bSChristoph Hellwig  * scsi_error_handler - SCSI error handler thread
21041da177e4SLinus Torvalds  * @data:	Host for which we are running.
21051da177e4SLinus Torvalds  *
21061da177e4SLinus Torvalds  * Notes:
2107ad42eb1bSChristoph Hellwig  *    This is the main error handling loop.  This is run as a kernel thread
2108ad42eb1bSChristoph Hellwig  *    for every SCSI host and handles all error handling activity.
2109dc8875e1SRandy Dunlap  */
21101da177e4SLinus Torvalds int scsi_error_handler(void *data)
21111da177e4SLinus Torvalds {
2112ad42eb1bSChristoph Hellwig 	struct Scsi_Host *shost = data;
21131da177e4SLinus Torvalds 
21141da177e4SLinus Torvalds 	/*
2115ad42eb1bSChristoph Hellwig 	 * We use TASK_INTERRUPTIBLE so that the thread is not
2116ad42eb1bSChristoph Hellwig 	 * counted against the load average as a running process.
2117ad42eb1bSChristoph Hellwig 	 * We never actually get interrupted because kthread_run
2118c03264a7SFrederik Schwarzer 	 * disables signal delivery for the created thread.
21191da177e4SLinus Torvalds 	 */
2120537b604cSMichal Hocko 	while (true) {
2121537b604cSMichal Hocko 		/*
2122537b604cSMichal Hocko 		 * The sequence in kthread_stop() sets the stop flag first
2123537b604cSMichal Hocko 		 * then wakes the process.  To avoid missed wakeups, the task
2124537b604cSMichal Hocko 		 * should always be in a non running state before the stop
2125537b604cSMichal Hocko 		 * flag is checked
2126537b604cSMichal Hocko 		 */
2127b9d5c6b7SDan Williams 		set_current_state(TASK_INTERRUPTIBLE);
2128537b604cSMichal Hocko 		if (kthread_should_stop())
2129537b604cSMichal Hocko 			break;
2130537b604cSMichal Hocko 
2131ee7863bcSTejun Heo 		if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
213274665016SChristoph Hellwig 		    shost->host_failed != atomic_read(&shost->host_busy)) {
2133ad42eb1bSChristoph Hellwig 			SCSI_LOG_ERROR_RECOVERY(1,
213491921e01SHannes Reinecke 				shost_printk(KERN_INFO, shost,
213591921e01SHannes Reinecke 					     "scsi_eh_%d: sleeping\n",
21363ed7a470SJames Bottomley 					     shost->host_no));
21373ed7a470SJames Bottomley 			schedule();
21383ed7a470SJames Bottomley 			continue;
21393ed7a470SJames Bottomley 		}
21401da177e4SLinus Torvalds 
21413ed7a470SJames Bottomley 		__set_current_state(TASK_RUNNING);
2142ad42eb1bSChristoph Hellwig 		SCSI_LOG_ERROR_RECOVERY(1,
214391921e01SHannes Reinecke 			shost_printk(KERN_INFO, shost,
214491921e01SHannes Reinecke 				     "scsi_eh_%d: waking up %d/%d/%d\n",
2145b4562022SHannes Reinecke 				     shost->host_no, shost->host_eh_scheduled,
214674665016SChristoph Hellwig 				     shost->host_failed,
214774665016SChristoph Hellwig 				     atomic_read(&shost->host_busy)));
21481da177e4SLinus Torvalds 
21491da177e4SLinus Torvalds 		/*
21501da177e4SLinus Torvalds 		 * We have a host that is failing for some reason.  Figure out
21511da177e4SLinus Torvalds 		 * what we need to do to get it up and online again (if we can).
21521da177e4SLinus Torvalds 		 * If we fail, we end up taking the thing offline.
21531da177e4SLinus Torvalds 		 */
2154ae0751ffSLin Ming 		if (!shost->eh_noresume && scsi_autopm_get_host(shost) != 0) {
2155bc4f2401SAlan Stern 			SCSI_LOG_ERROR_RECOVERY(1,
2156a222b1e2SHannes Reinecke 				shost_printk(KERN_ERR, shost,
2157a222b1e2SHannes Reinecke 					     "scsi_eh_%d: unable to autoresume\n",
2158bc4f2401SAlan Stern 					     shost->host_no));
2159bc4f2401SAlan Stern 			continue;
2160bc4f2401SAlan Stern 		}
2161bc4f2401SAlan Stern 
21629227c33dSChristoph Hellwig 		if (shost->transportt->eh_strategy_handler)
21639227c33dSChristoph Hellwig 			shost->transportt->eh_strategy_handler(shost);
21641da177e4SLinus Torvalds 		else
21651da177e4SLinus Torvalds 			scsi_unjam_host(shost);
21661da177e4SLinus Torvalds 
216772d8c36eSWei Fang 		/* All scmds have been handled */
216872d8c36eSWei Fang 		shost->host_failed = 0;
216972d8c36eSWei Fang 
21701da177e4SLinus Torvalds 		/*
21711da177e4SLinus Torvalds 		 * Note - if the above fails completely, the action is to take
21721da177e4SLinus Torvalds 		 * individual devices offline and flush the queue of any
21731da177e4SLinus Torvalds 		 * outstanding requests that may have been pending.  When we
21741da177e4SLinus Torvalds 		 * restart, we restart any I/O to any other devices on the bus
21751da177e4SLinus Torvalds 		 * which are still online.
21761da177e4SLinus Torvalds 		 */
21771da177e4SLinus Torvalds 		scsi_restart_operations(shost);
2178ae0751ffSLin Ming 		if (!shost->eh_noresume)
2179bc4f2401SAlan Stern 			scsi_autopm_put_host(shost);
21801da177e4SLinus Torvalds 	}
2181461a0ffbSSteven Rostedt 	__set_current_state(TASK_RUNNING);
2182461a0ffbSSteven Rostedt 
2183ad42eb1bSChristoph Hellwig 	SCSI_LOG_ERROR_RECOVERY(1,
218491921e01SHannes Reinecke 		shost_printk(KERN_INFO, shost,
218591921e01SHannes Reinecke 			     "Error handler scsi_eh_%d exiting\n",
218691921e01SHannes Reinecke 			     shost->host_no));
21873ed7a470SJames Bottomley 	shost->ehandler = NULL;
21881da177e4SLinus Torvalds 	return 0;
21891da177e4SLinus Torvalds }
21901da177e4SLinus Torvalds 
21911da177e4SLinus Torvalds /*
21921da177e4SLinus Torvalds  * Function:    scsi_report_bus_reset()
21931da177e4SLinus Torvalds  *
21941da177e4SLinus Torvalds  * Purpose:     Utility function used by low-level drivers to report that
21951da177e4SLinus Torvalds  *		they have observed a bus reset on the bus being handled.
21961da177e4SLinus Torvalds  *
21971da177e4SLinus Torvalds  * Arguments:   shost       - Host in question
21981da177e4SLinus Torvalds  *		channel     - channel on which reset was observed.
21991da177e4SLinus Torvalds  *
22001da177e4SLinus Torvalds  * Returns:     Nothing
22011da177e4SLinus Torvalds  *
22021da177e4SLinus Torvalds  * Lock status: Host lock must be held.
22031da177e4SLinus Torvalds  *
22041da177e4SLinus Torvalds  * Notes:       This only needs to be called if the reset is one which
22051da177e4SLinus Torvalds  *		originates from an unknown location.  Resets originated
22061da177e4SLinus Torvalds  *		by the mid-level itself don't need to call this, but there
22071da177e4SLinus Torvalds  *		should be no harm.
22081da177e4SLinus Torvalds  *
22091da177e4SLinus Torvalds  *		The main purpose of this is to make sure that a CHECK_CONDITION
22101da177e4SLinus Torvalds  *		is properly treated.
22111da177e4SLinus Torvalds  */
22121da177e4SLinus Torvalds void scsi_report_bus_reset(struct Scsi_Host *shost, int channel)
22131da177e4SLinus Torvalds {
22141da177e4SLinus Torvalds 	struct scsi_device *sdev;
22151da177e4SLinus Torvalds 
22161da177e4SLinus Torvalds 	__shost_for_each_device(sdev, shost) {
221730bd7df8SMike Christie 		if (channel == sdev_channel(sdev))
221830bd7df8SMike Christie 			__scsi_report_device_reset(sdev, NULL);
22191da177e4SLinus Torvalds 	}
22201da177e4SLinus Torvalds }
22211da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_report_bus_reset);
22221da177e4SLinus Torvalds 
22231da177e4SLinus Torvalds /*
22241da177e4SLinus Torvalds  * Function:    scsi_report_device_reset()
22251da177e4SLinus Torvalds  *
22261da177e4SLinus Torvalds  * Purpose:     Utility function used by low-level drivers to report that
22271da177e4SLinus Torvalds  *		they have observed a device reset on the device being handled.
22281da177e4SLinus Torvalds  *
22291da177e4SLinus Torvalds  * Arguments:   shost       - Host in question
22301da177e4SLinus Torvalds  *		channel     - channel on which reset was observed
22311da177e4SLinus Torvalds  *		target	    - target on which reset was observed
22321da177e4SLinus Torvalds  *
22331da177e4SLinus Torvalds  * Returns:     Nothing
22341da177e4SLinus Torvalds  *
22351da177e4SLinus Torvalds  * Lock status: Host lock must be held
22361da177e4SLinus Torvalds  *
22371da177e4SLinus Torvalds  * Notes:       This only needs to be called if the reset is one which
22381da177e4SLinus Torvalds  *		originates from an unknown location.  Resets originated
22391da177e4SLinus Torvalds  *		by the mid-level itself don't need to call this, but there
22401da177e4SLinus Torvalds  *		should be no harm.
22411da177e4SLinus Torvalds  *
22421da177e4SLinus Torvalds  *		The main purpose of this is to make sure that a CHECK_CONDITION
22431da177e4SLinus Torvalds  *		is properly treated.
22441da177e4SLinus Torvalds  */
22451da177e4SLinus Torvalds void scsi_report_device_reset(struct Scsi_Host *shost, int channel, int target)
22461da177e4SLinus Torvalds {
22471da177e4SLinus Torvalds 	struct scsi_device *sdev;
22481da177e4SLinus Torvalds 
22491da177e4SLinus Torvalds 	__shost_for_each_device(sdev, shost) {
2250422c0d61SJeff Garzik 		if (channel == sdev_channel(sdev) &&
225130bd7df8SMike Christie 		    target == sdev_id(sdev))
225230bd7df8SMike Christie 			__scsi_report_device_reset(sdev, NULL);
22531da177e4SLinus Torvalds 	}
22541da177e4SLinus Torvalds }
22551da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_report_device_reset);
22561da177e4SLinus Torvalds 
22571da177e4SLinus Torvalds static void
22581da177e4SLinus Torvalds scsi_reset_provider_done_command(struct scsi_cmnd *scmd)
22591da177e4SLinus Torvalds {
22601da177e4SLinus Torvalds }
22611da177e4SLinus Torvalds 
2262176aa9d6SChristoph Hellwig /**
2263176aa9d6SChristoph Hellwig  * scsi_ioctl_reset: explicitly reset a host/bus/target/device
2264176aa9d6SChristoph Hellwig  * @dev:	scsi_device to operate on
2265176aa9d6SChristoph Hellwig  * @arg:	reset type (see sg.h)
22661da177e4SLinus Torvalds  */
22671da177e4SLinus Torvalds int
2268176aa9d6SChristoph Hellwig scsi_ioctl_reset(struct scsi_device *dev, int __user *arg)
22691da177e4SLinus Torvalds {
2270bc4f2401SAlan Stern 	struct scsi_cmnd *scmd;
2271d7a1bb0aSJames Smart 	struct Scsi_Host *shost = dev->host;
2272e9c787e6SChristoph Hellwig 	struct request *rq;
2273d7a1bb0aSJames Smart 	unsigned long flags;
2274176aa9d6SChristoph Hellwig 	int error = 0, rtn, val;
2275176aa9d6SChristoph Hellwig 
2276176aa9d6SChristoph Hellwig 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2277176aa9d6SChristoph Hellwig 		return -EACCES;
2278176aa9d6SChristoph Hellwig 
2279176aa9d6SChristoph Hellwig 	error = get_user(val, arg);
2280176aa9d6SChristoph Hellwig 	if (error)
2281176aa9d6SChristoph Hellwig 		return error;
22821da177e4SLinus Torvalds 
2283bc4f2401SAlan Stern 	if (scsi_autopm_get_host(shost) < 0)
2284176aa9d6SChristoph Hellwig 		return -EIO;
2285bc4f2401SAlan Stern 
2286176aa9d6SChristoph Hellwig 	error = -EIO;
2287e9c787e6SChristoph Hellwig 	rq = kzalloc(sizeof(struct request) + sizeof(struct scsi_cmnd) +
2288e9c787e6SChristoph Hellwig 			shost->hostt->cmd_size, GFP_KERNEL);
2289e9c787e6SChristoph Hellwig 	if (!rq)
229095eeb5f5SChristoph Hellwig 		goto out_put_autopm_host;
2291e9c787e6SChristoph Hellwig 	blk_rq_init(NULL, rq);
229295eeb5f5SChristoph Hellwig 
2293e9c787e6SChristoph Hellwig 	scmd = (struct scsi_cmnd *)(rq + 1);
2294e9c787e6SChristoph Hellwig 	scsi_init_command(dev, scmd);
2295e9c787e6SChristoph Hellwig 	scmd->request = rq;
229682ed4db4SChristoph Hellwig 	scmd->cmnd = scsi_req(rq)->cmd;
22971da177e4SLinus Torvalds 
22981da177e4SLinus Torvalds 	scmd->scsi_done		= scsi_reset_provider_done_command;
229930b0c37bSBoaz Harrosh 	memset(&scmd->sdb, 0, sizeof(scmd->sdb));
23001da177e4SLinus Torvalds 
23011da177e4SLinus Torvalds 	scmd->cmd_len			= 0;
23021da177e4SLinus Torvalds 
23031da177e4SLinus Torvalds 	scmd->sc_data_direction		= DMA_BIDIRECTIONAL;
23041da177e4SLinus Torvalds 
2305d7a1bb0aSJames Smart 	spin_lock_irqsave(shost->host_lock, flags);
2306d7a1bb0aSJames Smart 	shost->tmf_in_progress = 1;
2307d7a1bb0aSJames Smart 	spin_unlock_irqrestore(shost->host_lock, flags);
2308d7a1bb0aSJames Smart 
2309176aa9d6SChristoph Hellwig 	switch (val & ~SG_SCSI_RESET_NO_ESCALATE) {
2310176aa9d6SChristoph Hellwig 	case SG_SCSI_RESET_NOTHING:
2311176aa9d6SChristoph Hellwig 		rtn = SUCCESS;
2312176aa9d6SChristoph Hellwig 		break;
2313176aa9d6SChristoph Hellwig 	case SG_SCSI_RESET_DEVICE:
23141da177e4SLinus Torvalds 		rtn = scsi_try_bus_device_reset(scmd);
2315176aa9d6SChristoph Hellwig 		if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
23161da177e4SLinus Torvalds 			break;
23171da177e4SLinus Torvalds 		/* FALLTHROUGH */
2318176aa9d6SChristoph Hellwig 	case SG_SCSI_RESET_TARGET:
231930bd7df8SMike Christie 		rtn = scsi_try_target_reset(scmd);
2320176aa9d6SChristoph Hellwig 		if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
232130bd7df8SMike Christie 			break;
232230bd7df8SMike Christie 		/* FALLTHROUGH */
2323176aa9d6SChristoph Hellwig 	case SG_SCSI_RESET_BUS:
23241da177e4SLinus Torvalds 		rtn = scsi_try_bus_reset(scmd);
2325176aa9d6SChristoph Hellwig 		if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
23261da177e4SLinus Torvalds 			break;
23271da177e4SLinus Torvalds 		/* FALLTHROUGH */
2328176aa9d6SChristoph Hellwig 	case SG_SCSI_RESET_HOST:
23291da177e4SLinus Torvalds 		rtn = scsi_try_host_reset(scmd);
2330176aa9d6SChristoph Hellwig 		if (rtn == SUCCESS)
233126cf591eSDouglas Gilbert 			break;
2332176aa9d6SChristoph Hellwig 		/* FALLTHROUGH */
23333bf2ff67SBart Van Assche 	default:
23341da177e4SLinus Torvalds 		rtn = FAILED;
2335176aa9d6SChristoph Hellwig 		break;
23361da177e4SLinus Torvalds 	}
23371da177e4SLinus Torvalds 
2338176aa9d6SChristoph Hellwig 	error = (rtn == SUCCESS) ? 0 : -EIO;
2339176aa9d6SChristoph Hellwig 
2340d7a1bb0aSJames Smart 	spin_lock_irqsave(shost->host_lock, flags);
2341d7a1bb0aSJames Smart 	shost->tmf_in_progress = 0;
2342d7a1bb0aSJames Smart 	spin_unlock_irqrestore(shost->host_lock, flags);
2343d7a1bb0aSJames Smart 
2344d7a1bb0aSJames Smart 	/*
2345d7a1bb0aSJames Smart 	 * be sure to wake up anyone who was sleeping or had their queue
2346d7a1bb0aSJames Smart 	 * suspended while we performed the TMF.
2347d7a1bb0aSJames Smart 	 */
2348d7a1bb0aSJames Smart 	SCSI_LOG_ERROR_RECOVERY(3,
234991921e01SHannes Reinecke 		shost_printk(KERN_INFO, shost,
235091921e01SHannes Reinecke 			     "waking up host to restart after TMF\n"));
2351d7a1bb0aSJames Smart 
2352d7a1bb0aSJames Smart 	wake_up(&shost->host_wait);
2353d7a1bb0aSJames Smart 	scsi_run_host_queues(shost);
2354d7a1bb0aSJames Smart 
23550f121dd8SChristoph Hellwig 	scsi_put_command(scmd);
2356e9c787e6SChristoph Hellwig 	kfree(rq);
23570f121dd8SChristoph Hellwig 
235804796336SChristoph Hellwig out_put_autopm_host:
2359bc4f2401SAlan Stern 	scsi_autopm_put_host(shost);
2360176aa9d6SChristoph Hellwig 	return error;
23611da177e4SLinus Torvalds }
2362176aa9d6SChristoph Hellwig EXPORT_SYMBOL(scsi_ioctl_reset);
23631da177e4SLinus Torvalds 
23644753cbc0SHannes Reinecke bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd,
23651da177e4SLinus Torvalds 				  struct scsi_sense_hdr *sshdr)
23661da177e4SLinus Torvalds {
23671da177e4SLinus Torvalds 	return scsi_normalize_sense(cmd->sense_buffer,
2368b80ca4f7SFUJITA Tomonori 			SCSI_SENSE_BUFFERSIZE, sshdr);
23691da177e4SLinus Torvalds }
23701da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_command_normalize_sense);
23711da177e4SLinus Torvalds 
23721da177e4SLinus Torvalds /**
2373eb44820cSRob Landley  * scsi_get_sense_info_fld - get information field from sense data (either fixed or descriptor format)
23741da177e4SLinus Torvalds  * @sense_buffer:	byte array of sense data
23751da177e4SLinus Torvalds  * @sb_len:		number of valid bytes in sense_buffer
23761da177e4SLinus Torvalds  * @info_out:		pointer to 64 integer where 8 or 4 byte information
23771da177e4SLinus Torvalds  *			field will be placed if found.
23781da177e4SLinus Torvalds  *
23791da177e4SLinus Torvalds  * Return value:
23802908769cSDamien Le Moal  *	true if information field found, false if not found.
2381dc8875e1SRandy Dunlap  */
23822908769cSDamien Le Moal bool scsi_get_sense_info_fld(const u8 *sense_buffer, int sb_len,
23831da177e4SLinus Torvalds 			     u64 *info_out)
23841da177e4SLinus Torvalds {
23851da177e4SLinus Torvalds 	const u8 * ucp;
23861da177e4SLinus Torvalds 
23871da177e4SLinus Torvalds 	if (sb_len < 7)
23882908769cSDamien Le Moal 		return false;
23891da177e4SLinus Torvalds 	switch (sense_buffer[0] & 0x7f) {
23901da177e4SLinus Torvalds 	case 0x70:
23911da177e4SLinus Torvalds 	case 0x71:
23921da177e4SLinus Torvalds 		if (sense_buffer[0] & 0x80) {
23932908769cSDamien Le Moal 			*info_out = get_unaligned_be32(&sense_buffer[3]);
23942908769cSDamien Le Moal 			return true;
23952908769cSDamien Le Moal 		}
23962908769cSDamien Le Moal 		return false;
23971da177e4SLinus Torvalds 	case 0x72:
23981da177e4SLinus Torvalds 	case 0x73:
23991da177e4SLinus Torvalds 		ucp = scsi_sense_desc_find(sense_buffer, sb_len,
24001da177e4SLinus Torvalds 					   0 /* info desc */);
24011da177e4SLinus Torvalds 		if (ucp && (0xa == ucp[1])) {
24022908769cSDamien Le Moal 			*info_out = get_unaligned_be64(&ucp[4]);
24032908769cSDamien Le Moal 			return true;
24041da177e4SLinus Torvalds 		}
24052908769cSDamien Le Moal 		return false;
24061da177e4SLinus Torvalds 	default:
24072908769cSDamien Le Moal 		return false;
24081da177e4SLinus Torvalds 	}
24091da177e4SLinus Torvalds }
24101da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_get_sense_info_fld);
2411