diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2005-09-18 16:05:20 -0400 |
---|---|---|
committer | James Bottomley <jejb@titanic.(none)> | 2005-09-19 10:24:52 -0400 |
commit | 939647ee308e0ad924e776657704c7bedd498664 (patch) | |
tree | cfff68b8f65a53e186fd1e7443aa370885ac1ed9 /drivers/scsi/scsi_error.c | |
parent | a64358db1253b35d508a411e80a3ad23b859ec88 (diff) |
[SCSI] fix oops on usb storage device disconnect
We fix the oops by enforcing the host state model. There have also
been two extra states added: SHOST_CANCEL_RECOVERY and
SHOST_DEL_RECOVERY so we can take the model through host removal while
the recovery thread is active.
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/scsi_error.c')
-rw-r--r-- | drivers/scsi/scsi_error.c | 23 |
1 files changed, 16 insertions, 7 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 895c9452be4c..af589fac814d 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c | |||
@@ -68,19 +68,24 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) | |||
68 | { | 68 | { |
69 | struct Scsi_Host *shost = scmd->device->host; | 69 | struct Scsi_Host *shost = scmd->device->host; |
70 | unsigned long flags; | 70 | unsigned long flags; |
71 | int ret = 0; | ||
71 | 72 | ||
72 | if (shost->eh_wait == NULL) | 73 | if (shost->eh_wait == NULL) |
73 | return 0; | 74 | return 0; |
74 | 75 | ||
75 | spin_lock_irqsave(shost->host_lock, flags); | 76 | spin_lock_irqsave(shost->host_lock, flags); |
77 | if (scsi_host_set_state(shost, SHOST_RECOVERY)) | ||
78 | if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) | ||
79 | goto out_unlock; | ||
76 | 80 | ||
81 | ret = 1; | ||
77 | scmd->eh_eflags |= eh_flag; | 82 | scmd->eh_eflags |= eh_flag; |
78 | list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); | 83 | list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); |
79 | scsi_host_set_state(shost, SHOST_RECOVERY); | ||
80 | shost->host_failed++; | 84 | shost->host_failed++; |
81 | scsi_eh_wakeup(shost); | 85 | scsi_eh_wakeup(shost); |
86 | out_unlock: | ||
82 | spin_unlock_irqrestore(shost->host_lock, flags); | 87 | spin_unlock_irqrestore(shost->host_lock, flags); |
83 | return 1; | 88 | return ret; |
84 | } | 89 | } |
85 | 90 | ||
86 | /** | 91 | /** |
@@ -176,8 +181,8 @@ void scsi_times_out(struct scsi_cmnd *scmd) | |||
176 | } | 181 | } |
177 | 182 | ||
178 | if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) { | 183 | if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) { |
179 | panic("Error handler thread not present at %p %p %s %d", | 184 | scmd->result |= DID_TIME_OUT << 16; |
180 | scmd, scmd->device->host, __FILE__, __LINE__); | 185 | __scsi_done(scmd); |
181 | } | 186 | } |
182 | } | 187 | } |
183 | 188 | ||
@@ -196,8 +201,7 @@ int scsi_block_when_processing_errors(struct scsi_device *sdev) | |||
196 | { | 201 | { |
197 | int online; | 202 | int online; |
198 | 203 | ||
199 | wait_event(sdev->host->host_wait, (sdev->host->shost_state != | 204 | wait_event(sdev->host->host_wait, !scsi_host_in_recovery(sdev->host)); |
200 | SHOST_RECOVERY)); | ||
201 | 205 | ||
202 | online = scsi_device_online(sdev); | 206 | online = scsi_device_online(sdev); |
203 | 207 | ||
@@ -1441,6 +1445,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) | |||
1441 | static void scsi_restart_operations(struct Scsi_Host *shost) | 1445 | static void scsi_restart_operations(struct Scsi_Host *shost) |
1442 | { | 1446 | { |
1443 | struct scsi_device *sdev; | 1447 | struct scsi_device *sdev; |
1448 | unsigned long flags; | ||
1444 | 1449 | ||
1445 | /* | 1450 | /* |
1446 | * If the door was locked, we need to insert a door lock request | 1451 | * If the door was locked, we need to insert a door lock request |
@@ -1460,7 +1465,11 @@ static void scsi_restart_operations(struct Scsi_Host *shost) | |||
1460 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n", | 1465 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n", |
1461 | __FUNCTION__)); | 1466 | __FUNCTION__)); |
1462 | 1467 | ||
1463 | scsi_host_set_state(shost, SHOST_RUNNING); | 1468 | spin_lock_irqsave(shost->host_lock, flags); |
1469 | if (scsi_host_set_state(shost, SHOST_RUNNING)) | ||
1470 | if (scsi_host_set_state(shost, SHOST_CANCEL)) | ||
1471 | BUG_ON(scsi_host_set_state(shost, SHOST_DEL)); | ||
1472 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1464 | 1473 | ||
1465 | wake_up(&shost->host_wait); | 1474 | wake_up(&shost->host_wait); |
1466 | 1475 | ||