Commit 9e119469 authored by Mike Anderson's avatar Mike Anderson Committed by James Bottomley

[PATCH] scsi_error update take 2

This is an update of a previous patch I posted.
http://marc.theaimsgroup.com/?l=linux-scsi&m=104495114103628&w=2

This patch is against scsi-misc-2.5

The updates from the last patch include:
	- Names changes:
		eh_cmd_list => eh_cmd_q
		eh_list => eh_entry

	- Move shost->in_recovery = 0

	- Switch from scsi_retry_command to scsi_queue_insert for retry
	  to solve fast completions / serial start of retries.

	- Use list_splice_init in scsi_unjam_host.
parent 0dba89dc
...@@ -397,7 +397,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes) ...@@ -397,7 +397,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
spin_lock_init(&shost->default_lock); spin_lock_init(&shost->default_lock);
scsi_assign_lock(shost, &shost->default_lock); scsi_assign_lock(shost, &shost->default_lock);
INIT_LIST_HEAD(&shost->my_devices); INIT_LIST_HEAD(&shost->my_devices);
INIT_LIST_HEAD(&shost->eh_cmd_list); INIT_LIST_HEAD(&shost->eh_cmd_q);
init_waitqueue_head(&shost->host_wait); init_waitqueue_head(&shost->host_wait);
shost->dma_channel = 0xff; shost->dma_channel = 0xff;
...@@ -635,7 +635,9 @@ void scsi_host_busy_dec_and_test(struct Scsi_Host *shost, Scsi_Device *sdev) ...@@ -635,7 +635,9 @@ void scsi_host_busy_dec_and_test(struct Scsi_Host *shost, Scsi_Device *sdev)
spin_lock_irqsave(shost->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
shost->host_busy--; shost->host_busy--;
sdev->device_busy--; sdev->device_busy--;
if (shost->in_recovery && (shost->host_busy == shost->host_failed)) { if (shost->in_recovery && shost->host_failed &&
(shost->host_busy == shost->host_failed))
{
up(shost->eh_wait); up(shost->eh_wait);
SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler" SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler"
" thread\n")); " thread\n"));
......
...@@ -384,7 +384,7 @@ struct Scsi_Host ...@@ -384,7 +384,7 @@ struct Scsi_Host
spinlock_t default_lock; spinlock_t default_lock;
spinlock_t *host_lock; spinlock_t *host_lock;
struct list_head eh_cmd_list; struct list_head eh_cmd_q;
struct task_struct * ehandler; /* Error recovery thread. */ struct task_struct * ehandler; /* Error recovery thread. */
struct semaphore * eh_wait; /* The error recovery thread waits on struct semaphore * eh_wait; /* The error recovery thread waits on
this. */ this. */
......
...@@ -727,7 +727,7 @@ struct scsi_cmnd { ...@@ -727,7 +727,7 @@ struct scsi_cmnd {
struct list_head list; /* scsi_cmnd participates in queue lists */ struct list_head list; /* scsi_cmnd participates in queue lists */
struct list_head eh_list; /* Used to place us on the host eh list */ struct list_head eh_entry; /* entry for the host eh_cmd_q */
int eh_state; /* Used for state tracking in error handlr */ int eh_state; /* Used for state tracking in error handlr */
int eh_eflags; /* Used by error handlr */ int eh_eflags; /* Used by error handlr */
void (*done) (struct scsi_cmnd *); /* Mid-level done function */ void (*done) (struct scsi_cmnd *); /* Mid-level done function */
...@@ -852,6 +852,7 @@ struct scsi_cmnd { ...@@ -852,6 +852,7 @@ struct scsi_cmnd {
*/ */
#define SCSI_MLQUEUE_HOST_BUSY 0x1055 #define SCSI_MLQUEUE_HOST_BUSY 0x1055
#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 #define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
#define SCSI_MLQUEUE_EH_RETRY 0x1057
/* /*
* old style reset request from external source * old style reset request from external source
......
...@@ -84,7 +84,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) ...@@ -84,7 +84,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
* serial_number * serial_number
*/ */
scmd->serial_number_at_timeout = scmd->serial_number; scmd->serial_number_at_timeout = scmd->serial_number;
list_add_tail(&scmd->eh_list, &shost->eh_cmd_list); list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
shost->in_recovery = 1; shost->in_recovery = 1;
shost->host_failed++; shost->host_failed++;
if (shost->host_busy == shost->host_failed) { if (shost->host_busy == shost->host_failed) {
...@@ -208,10 +208,11 @@ int scsi_block_when_processing_errors(Scsi_Device *sdev) ...@@ -208,10 +208,11 @@ int scsi_block_when_processing_errors(Scsi_Device *sdev)
#if CONFIG_SCSI_LOGGING #if CONFIG_SCSI_LOGGING
/** /**
* scsi_eh_prt_fail_stats - Log info on failures. * scsi_eh_prt_fail_stats - Log info on failures.
* @sc_list: List for failed cmds.
* @shost: scsi host being recovered. * @shost: scsi host being recovered.
* @work_q: Queue of scsi cmds to process.
**/ **/
static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost) static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
struct list_head *work_q)
{ {
struct scsi_cmnd *scmd; struct scsi_cmnd *scmd;
struct scsi_device *sdev; struct scsi_device *sdev;
...@@ -222,7 +223,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost) ...@@ -222,7 +223,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost)
list_for_each_entry(sdev, &shost->my_devices, siblings) { list_for_each_entry(sdev, &shost->my_devices, siblings) {
list_for_each_entry(scmd, &shost->eh_cmd_list, eh_list) { list_for_each_entry(scmd, work_q, eh_entry) {
if (scmd->device == sdev) { if (scmd->device == sdev) {
++total_failures; ++total_failures;
if (scsi_eh_eflags_chk(scmd, if (scsi_eh_eflags_chk(scmd,
...@@ -650,8 +651,7 @@ static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd) ...@@ -650,8 +651,7 @@ static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd)
/** /**
* scsi_eh_finish_cmd - Handle a cmd that eh is finished with. * scsi_eh_finish_cmd - Handle a cmd that eh is finished with.
* @scmd: Original SCSI cmd that eh has finished. * @scmd: Original SCSI cmd that eh has finished.
* @shost: SCSI host that cmd originally failed on. * @done_q: Queue for processed commands.
* @done_list: list_head for processed commands.
* *
* Notes: * Notes:
* We don't want to use the normal command completion while we are are * We don't want to use the normal command completion while we are are
...@@ -660,10 +660,10 @@ static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd) ...@@ -660,10 +660,10 @@ static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd)
* keep a list of pending commands for final completion, and once we * keep a list of pending commands for final completion, and once we
* are ready to leave error handling we handle completion for real. * are ready to leave error handling we handle completion for real.
**/ **/
static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd, struct Scsi_Host *shost, static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd,
struct list_head *done_list ) struct list_head *done_q )
{ {
shost->host_failed--; scmd->device->host->host_failed--;
scmd->state = SCSI_STATE_BHQUEUE; scmd->state = SCSI_STATE_BHQUEUE;
scsi_eh_eflags_clr_all(scmd); scsi_eh_eflags_clr_all(scmd);
...@@ -673,13 +673,13 @@ static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd, struct Scsi_Host *shost, ...@@ -673,13 +673,13 @@ static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd, struct Scsi_Host *shost,
*/ */
scsi_setup_cmd_retry(scmd); scsi_setup_cmd_retry(scmd);
list_move_tail(&scmd->eh_list, done_list); list_move_tail(&scmd->eh_entry, done_q);
} }
/** /**
* scsi_eh_get_sense - Get device sense data. * scsi_eh_get_sense - Get device sense data.
* @shost: scsi host being recovered. * @work_q: Queue of commands to process.
* @done_list: list_head for processed commands. * @done_q: Queue of proccessed commands..
* *
* Description: * Description:
* See if we need to request sense information. if so, then get it * See if we need to request sense information. if so, then get it
...@@ -697,15 +697,15 @@ static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd, struct Scsi_Host *shost, ...@@ -697,15 +697,15 @@ static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd, struct Scsi_Host *shost,
* *
* In 2.5 this capability will be going away. * In 2.5 this capability will be going away.
**/ **/
static int scsi_eh_get_sense(struct Scsi_Host *shost, static int scsi_eh_get_sense(struct list_head *work_q,
struct list_head *done_list) struct list_head *done_q)
{ {
int rtn; int rtn;
struct list_head *lh, *lh_sf; struct list_head *lh, *lh_sf;
Scsi_Cmnd *scmd; Scsi_Cmnd *scmd;
list_for_each_safe(lh, lh_sf, &shost->eh_cmd_list) { list_for_each_safe(lh, lh_sf, work_q) {
scmd = list_entry(lh, struct scsi_cmnd, eh_list); scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
if (scsi_eh_eflags_chk(scmd, SCSI_EH_CANCEL_CMD) || if (scsi_eh_eflags_chk(scmd, SCSI_EH_CANCEL_CMD) ||
SCSI_SENSE_VALID(scmd)) SCSI_SENSE_VALID(scmd))
continue; continue;
...@@ -730,7 +730,7 @@ static int scsi_eh_get_sense(struct Scsi_Host *shost, ...@@ -730,7 +730,7 @@ static int scsi_eh_get_sense(struct Scsi_Host *shost,
* upper level. * upper level.
*/ */
if (rtn == SUCCESS) if (rtn == SUCCESS)
scsi_eh_finish_cmd(scmd, shost, done_list); scsi_eh_finish_cmd(scmd, done_q);
if (rtn != NEEDS_RETRY) if (rtn != NEEDS_RETRY)
continue; continue;
...@@ -749,10 +749,10 @@ static int scsi_eh_get_sense(struct Scsi_Host *shost, ...@@ -749,10 +749,10 @@ static int scsi_eh_get_sense(struct Scsi_Host *shost,
/* /*
* we eventually hand this one back to the top level. * we eventually hand this one back to the top level.
*/ */
scsi_eh_finish_cmd(scmd, shost, done_list); scsi_eh_finish_cmd(scmd, done_q);
} }
return list_empty(&shost->eh_cmd_list); return list_empty(work_q);
} }
/** /**
...@@ -844,7 +844,7 @@ static int scsi_eh_tur(Scsi_Cmnd *scmd) ...@@ -844,7 +844,7 @@ static int scsi_eh_tur(Scsi_Cmnd *scmd)
/** /**
* scsi_eh_abort_cmds - abort canceled commands. * scsi_eh_abort_cmds - abort canceled commands.
* @shost: scsi host being recovered. * @shost: scsi host being recovered.
* @done_list: list_head for processed commands. * @eh_done_q: list_head for processed commands.
* *
* Decription: * Decription:
* Try and see whether or not it makes sense to try and abort the * Try and see whether or not it makes sense to try and abort the
...@@ -853,15 +853,15 @@ static int scsi_eh_tur(Scsi_Cmnd *scmd) ...@@ -853,15 +853,15 @@ static int scsi_eh_tur(Scsi_Cmnd *scmd)
* no sense to try and abort the command, since as far as the shost * no sense to try and abort the command, since as far as the shost
* adapter is concerned, it isn't running. * adapter is concerned, it isn't running.
**/ **/
static int scsi_eh_abort_cmds(struct Scsi_Host *shost, static int scsi_eh_abort_cmds(struct list_head *work_q,
struct list_head *done_list) struct list_head *done_q)
{ {
int rtn; int rtn;
struct list_head *lh, *lh_sf; struct list_head *lh, *lh_sf;
struct scsi_cmnd *scmd; struct scsi_cmnd *scmd;
list_for_each_safe(lh, lh_sf, &shost->eh_cmd_list) { list_for_each_safe(lh, lh_sf, work_q) {
scmd = list_entry(lh, struct scsi_cmnd, eh_list); scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CANCEL_CMD)) if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CANCEL_CMD))
continue; continue;
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting cmd:" SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting cmd:"
...@@ -871,7 +871,7 @@ static int scsi_eh_abort_cmds(struct Scsi_Host *shost, ...@@ -871,7 +871,7 @@ static int scsi_eh_abort_cmds(struct Scsi_Host *shost,
if (rtn == SUCCESS) { if (rtn == SUCCESS) {
scsi_eh_eflags_clr(scmd, SCSI_EH_CANCEL_CMD); scsi_eh_eflags_clr(scmd, SCSI_EH_CANCEL_CMD);
if (!scmd->device->online || !scsi_eh_tur(scmd)) { if (!scmd->device->online || !scsi_eh_tur(scmd)) {
scsi_eh_finish_cmd(scmd, shost, done_list); scsi_eh_finish_cmd(scmd, done_q);
} }
} else } else
...@@ -882,7 +882,7 @@ static int scsi_eh_abort_cmds(struct Scsi_Host *shost, ...@@ -882,7 +882,7 @@ static int scsi_eh_abort_cmds(struct Scsi_Host *shost,
scmd)); scmd));
} }
return list_empty(&shost->eh_cmd_list); return list_empty(work_q);
} }
/** /**
...@@ -920,7 +920,7 @@ static int scsi_try_bus_device_reset(Scsi_Cmnd *scmd) ...@@ -920,7 +920,7 @@ static int scsi_try_bus_device_reset(Scsi_Cmnd *scmd)
/** /**
* scsi_eh_bus_device_reset - send bdr if needed * scsi_eh_bus_device_reset - send bdr if needed
* @shost: scsi host being recovered. * @shost: scsi host being recovered.
* @done_list: list_head for processed commands. * @eh_done_q: list_head for processed commands.
* *
* Notes: * Notes:
* Try a bus device reset. still, look to see whether we have multiple * Try a bus device reset. still, look to see whether we have multiple
...@@ -929,7 +929,8 @@ static int scsi_try_bus_device_reset(Scsi_Cmnd *scmd) ...@@ -929,7 +929,8 @@ static int scsi_try_bus_device_reset(Scsi_Cmnd *scmd)
* a bus_reset instead. * a bus_reset instead.
**/ **/
static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
struct list_head *done_list) struct list_head *work_q,
struct list_head *done_q)
{ {
int rtn; int rtn;
struct list_head *lh, *lh_sf; struct list_head *lh, *lh_sf;
...@@ -938,7 +939,7 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, ...@@ -938,7 +939,7 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
list_for_each_entry(sdev, &shost->my_devices, siblings) { list_for_each_entry(sdev, &shost->my_devices, siblings) {
bdr_scmd = NULL; bdr_scmd = NULL;
list_for_each_entry(scmd, &shost->eh_cmd_list, eh_list) list_for_each_entry(scmd, work_q, eh_entry)
if (scmd->device == sdev) { if (scmd->device == sdev) {
bdr_scmd = scmd; bdr_scmd = scmd;
break; break;
...@@ -954,14 +955,13 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, ...@@ -954,14 +955,13 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
if (rtn == SUCCESS) { if (rtn == SUCCESS) {
if (!sdev->online || !scsi_eh_tur(bdr_scmd)) { if (!sdev->online || !scsi_eh_tur(bdr_scmd)) {
list_for_each_safe(lh, lh_sf, list_for_each_safe(lh, lh_sf,
&shost->eh_cmd_list) { work_q) {
scmd = list_entry(lh, struct scmd = list_entry(lh, struct
scsi_cmnd, scsi_cmnd,
eh_list); eh_entry);
if (scmd->device == sdev) if (scmd->device == sdev)
scsi_eh_finish_cmd(scmd, scsi_eh_finish_cmd(scmd,
shost, done_q);
done_list);
} }
} }
} else { } else {
...@@ -973,7 +973,7 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, ...@@ -973,7 +973,7 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
} }
} }
return list_empty(&shost->eh_cmd_list); return list_empty(work_q);
} }
/** /**
...@@ -1053,10 +1053,11 @@ static int scsi_try_host_reset(Scsi_Cmnd *scmd) ...@@ -1053,10 +1053,11 @@ static int scsi_try_host_reset(Scsi_Cmnd *scmd)
/** /**
* scsi_eh_bus_reset - send a bus reset * scsi_eh_bus_reset - send a bus reset
* @shost: scsi host being recovered. * @shost: scsi host being recovered.
* @done_list: list_head for processed commands. * @eh_done_q: list_head for processed commands.
**/ **/
static int scsi_eh_bus_reset(struct Scsi_Host *shost, static int scsi_eh_bus_reset(struct Scsi_Host *shost,
struct list_head *done_list) struct list_head *work_q,
struct list_head *done_q)
{ {
int rtn; int rtn;
struct list_head *lh, *lh_sf; struct list_head *lh, *lh_sf;
...@@ -1073,7 +1074,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost, ...@@ -1073,7 +1074,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
for (channel = 0; channel <= shost->max_channel; channel++) { for (channel = 0; channel <= shost->max_channel; channel++) {
chan_scmd = NULL; chan_scmd = NULL;
list_for_each_entry(scmd, &shost->eh_cmd_list, eh_list) { list_for_each_entry(scmd, work_q, eh_entry) {
if (channel == scmd->device->channel) { if (channel == scmd->device->channel) {
chan_scmd = scmd; chan_scmd = scmd;
break; break;
...@@ -1091,15 +1092,14 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost, ...@@ -1091,15 +1092,14 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
channel)); channel));
rtn = scsi_try_bus_reset(chan_scmd); rtn = scsi_try_bus_reset(chan_scmd);
if (rtn == SUCCESS) { if (rtn == SUCCESS) {
list_for_each_safe(lh, lh_sf, &shost->eh_cmd_list) { list_for_each_safe(lh, lh_sf, work_q) {
scmd = list_entry(lh, struct scsi_cmnd, scmd = list_entry(lh, struct scsi_cmnd,
eh_list); eh_entry);
if (channel == scmd->device->channel) if (channel == scmd->device->channel)
if (!scmd->device->online || if (!scmd->device->online ||
!scsi_eh_tur(scmd)) !scsi_eh_tur(scmd))
scsi_eh_finish_cmd(scmd, scsi_eh_finish_cmd(scmd,
shost, done_q);
done_list);
} }
} else { } else {
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: BRST" SCSI_LOG_ERROR_RECOVERY(3, printk("%s: BRST"
...@@ -1108,35 +1108,34 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost, ...@@ -1108,35 +1108,34 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
channel)); channel));
} }
} }
return list_empty(&shost->eh_cmd_list); return list_empty(work_q);
} }
/** /**
* scsi_eh_host_reset - send a host reset * scsi_eh_host_reset - send a host reset
* @shost: scsi host being recovered. * @work_q: list_head for processed commands.
* @done_list: list_head for processed commands. * @done_q: list_head for processed commands.
**/ **/
static int scsi_eh_host_reset(struct Scsi_Host *shost, static int scsi_eh_host_reset(struct list_head *work_q,
struct list_head *done_list) struct list_head *done_q)
{ {
int rtn; int rtn;
struct list_head *lh, *lh_sf; struct list_head *lh, *lh_sf;
Scsi_Cmnd *scmd; Scsi_Cmnd *scmd;
if (!list_empty(&shost->eh_cmd_list)) { if (!list_empty(work_q)) {
scmd = list_entry(shost->eh_cmd_list.next, scmd = list_entry(work_q->next,
struct scsi_cmnd, eh_list); struct scsi_cmnd, eh_entry);
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending HRST\n" SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending HRST\n"
, current->comm)); , current->comm));
rtn = scsi_try_host_reset(scmd); rtn = scsi_try_host_reset(scmd);
if (rtn == SUCCESS) { if (rtn == SUCCESS) {
list_for_each_safe(lh, lh_sf, &shost->eh_cmd_list) { list_for_each_safe(lh, lh_sf, work_q) {
scmd = list_entry(lh, struct scsi_cmnd, eh_list); scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
if (!scmd->device->online || !scsi_eh_tur(scmd)) if (!scmd->device->online || !scsi_eh_tur(scmd))
scsi_eh_finish_cmd(scmd, shost, scsi_eh_finish_cmd(scmd, done_q);
done_list);
} }
} else { } else {
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: HRST" SCSI_LOG_ERROR_RECOVERY(3, printk("%s: HRST"
...@@ -1144,27 +1143,27 @@ static int scsi_eh_host_reset(struct Scsi_Host *shost, ...@@ -1144,27 +1143,27 @@ static int scsi_eh_host_reset(struct Scsi_Host *shost,
current->comm)); current->comm));
} }
} }
return list_empty(&shost->eh_cmd_list); return list_empty(work_q);
} }
/** /**
* scsi_eh_offline_sdevs - offline scsi devices that fail to recover * scsi_eh_offline_sdevs - offline scsi devices that fail to recover
* @shost: scsi host being recovered. * @work_q: list_head for processed commands.
* @done_list: list_head for processed commands. * @done_q: list_head for processed commands.
* *
**/ **/
static void scsi_eh_offline_sdevs(struct Scsi_Host *shost, static void scsi_eh_offline_sdevs(struct list_head *work_q,
struct list_head *done_list) struct list_head *done_q)
{ {
struct list_head *lh, *lh_sf; struct list_head *lh, *lh_sf;
Scsi_Cmnd *scmd; Scsi_Cmnd *scmd;
list_for_each_safe(lh, lh_sf, &shost->eh_cmd_list) { list_for_each_safe(lh, lh_sf, work_q) {
scmd = list_entry(lh, struct scsi_cmnd, eh_list); scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
printk(KERN_INFO "scsi: Device offlined - not" printk(KERN_INFO "scsi: Device offlined - not"
" ready after error recovery: host" " ready after error recovery: host"
" %d channel %d id %d lun %d\n", " %d channel %d id %d lun %d\n",
shost->host_no, scmd->device->host->host_no,
scmd->device->channel, scmd->device->channel,
scmd->device->id, scmd->device->id,
scmd->device->lun); scmd->device->lun);
...@@ -1174,7 +1173,7 @@ static void scsi_eh_offline_sdevs(struct Scsi_Host *shost, ...@@ -1174,7 +1173,7 @@ static void scsi_eh_offline_sdevs(struct Scsi_Host *shost,
* FIXME: Handle lost cmds. * FIXME: Handle lost cmds.
*/ */
} }
scsi_eh_finish_cmd(scmd, shost, done_list); scsi_eh_finish_cmd(scmd, done_q);
} }
return; return;
} }
...@@ -1469,8 +1468,6 @@ static void scsi_restart_operations(struct Scsi_Host *shost) ...@@ -1469,8 +1468,6 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
ASSERT_LOCK(shost->host_lock, 0); ASSERT_LOCK(shost->host_lock, 0);
shost->in_recovery = 0;
/* /*
* If the door was locked, we need to insert a door lock request * If the door was locked, we need to insert a door lock request
* onto the head of the SCSI request queue for the device. There * onto the head of the SCSI request queue for the device. There
...@@ -1488,6 +1485,8 @@ static void scsi_restart_operations(struct Scsi_Host *shost) ...@@ -1488,6 +1485,8 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n", SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n",
__FUNCTION__)); __FUNCTION__));
shost->in_recovery = 0;
wake_up(&shost->host_wait); wake_up(&shost->host_wait);
/* /*
...@@ -1513,32 +1512,31 @@ static void scsi_restart_operations(struct Scsi_Host *shost) ...@@ -1513,32 +1512,31 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
/** /**
* scsi_eh_ready_devs - check device ready state and recover if not. * scsi_eh_ready_devs - check device ready state and recover if not.
* @shost: host to be recovered. * @shost: host to be recovered.
* @done_list: list_head for processed commands. * @eh_done_q: list_head for processed commands.
* *
**/ **/
static void scsi_eh_ready_devs(struct Scsi_Host *shost, static void scsi_eh_ready_devs(struct Scsi_Host *shost,
struct list_head *done_list) struct list_head *work_q,
struct list_head *done_q)
{ {
if (scsi_eh_bus_device_reset(shost, done_list)) if (scsi_eh_bus_device_reset(shost, work_q, done_q))
if (scsi_eh_bus_reset(shost, done_list)) if (scsi_eh_bus_reset(shost, work_q, done_q))
if (scsi_eh_host_reset(shost, done_list)) if (scsi_eh_host_reset(work_q, done_q))
scsi_eh_offline_sdevs(shost, done_list); scsi_eh_offline_sdevs(work_q, done_q);
} }
/** /**
* scsi_eh_flush_done_list - finish processed commands or retry them. * scsi_eh_flush_done_q - finish processed commands or retry them.
* @shost: host to be recovered. * @done_q: list_head of processed commands.
* @done_list: list_head of processed commands.
* *
**/ **/
static void scsi_eh_flush_done_list(struct Scsi_Host *shost, static void scsi_eh_flush_done_q(struct list_head *done_q)
struct list_head *done_list)
{ {
struct list_head *lh, *lh_sf; struct list_head *lh, *lh_sf;
Scsi_Cmnd *scmd; Scsi_Cmnd *scmd;
list_for_each_safe(lh, lh_sf, done_list) { list_for_each_safe(lh, lh_sf, done_q) {
scmd = list_entry(lh, struct scsi_cmnd, eh_list); scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
list_del_init(lh); list_del_init(lh);
if (!scmd->device->online) { if (!scmd->device->online) {
scmd->result |= (DRIVER_TIMEOUT << 24); scmd->result |= (DRIVER_TIMEOUT << 24);
...@@ -1549,7 +1547,7 @@ static void scsi_eh_flush_done_list(struct Scsi_Host *shost, ...@@ -1549,7 +1547,7 @@ static void scsi_eh_flush_done_list(struct Scsi_Host *shost,
" cmd: %p\n", " cmd: %p\n",
current->comm, current->comm,
scmd)); scmd));
scsi_retry_command(scmd); scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
continue; continue;
} }
} }
...@@ -1585,15 +1583,21 @@ static void scsi_eh_flush_done_list(struct Scsi_Host *shost, ...@@ -1585,15 +1583,21 @@ static void scsi_eh_flush_done_list(struct Scsi_Host *shost,
**/ **/
static void scsi_unjam_host(struct Scsi_Host *shost) static void scsi_unjam_host(struct Scsi_Host *shost)
{ {
LIST_HEAD(done_list); unsigned long flags;
LIST_HEAD(eh_work_q);
LIST_HEAD(eh_done_q);
spin_lock_irqsave(shost->host_lock, flags);
list_splice_init(&shost->eh_cmd_q, &eh_work_q);
spin_unlock_irqrestore(shost->host_lock, flags);
SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(shost)); SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(shost, &eh_work_q));
if (!scsi_eh_get_sense(shost, &done_list)) if (!scsi_eh_get_sense(&eh_work_q, &eh_done_q))
if (!scsi_eh_abort_cmds(shost, &done_list)) if (!scsi_eh_abort_cmds(&eh_work_q, &eh_done_q))
scsi_eh_ready_devs(shost, &done_list); scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q);
scsi_eh_flush_done_list(shost, &done_list); scsi_eh_flush_done_q(&eh_done_q);
} }
/** /**
......
...@@ -117,7 +117,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) ...@@ -117,7 +117,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
*/ */
if (reason == SCSI_MLQUEUE_HOST_BUSY) if (reason == SCSI_MLQUEUE_HOST_BUSY)
host->host_blocked = host->max_host_blocked; host->host_blocked = host->max_host_blocked;
else else if (reason == SCSI_MLQUEUE_DEVICE_BUSY)
device->device_blocked = device->max_device_blocked; device->device_blocked = device->max_device_blocked;
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment