diff options
Diffstat (limited to 'drivers/scsi/scsi_error.c')
-rw-r--r-- | drivers/scsi/scsi_error.c | 78 |
1 files changed, 39 insertions, 39 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 895c9452be4c..ad5342165079 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c | |||
@@ -50,7 +50,7 @@ | |||
50 | void scsi_eh_wakeup(struct Scsi_Host *shost) | 50 | void scsi_eh_wakeup(struct Scsi_Host *shost) |
51 | { | 51 | { |
52 | if (shost->host_busy == shost->host_failed) { | 52 | if (shost->host_busy == shost->host_failed) { |
53 | up(shost->eh_wait); | 53 | wake_up_process(shost->ehandler); |
54 | SCSI_LOG_ERROR_RECOVERY(5, | 54 | SCSI_LOG_ERROR_RECOVERY(5, |
55 | printk("Waking error handler thread\n")); | 55 | printk("Waking error handler thread\n")); |
56 | } | 56 | } |
@@ -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->ehandler) |
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 | ||
@@ -1582,40 +1591,31 @@ int scsi_error_handler(void *data) | |||
1582 | { | 1591 | { |
1583 | struct Scsi_Host *shost = (struct Scsi_Host *) data; | 1592 | struct Scsi_Host *shost = (struct Scsi_Host *) data; |
1584 | int rtn; | 1593 | int rtn; |
1585 | DECLARE_MUTEX_LOCKED(sem); | ||
1586 | 1594 | ||
1587 | current->flags |= PF_NOFREEZE; | 1595 | current->flags |= PF_NOFREEZE; |
1588 | shost->eh_wait = &sem; | ||
1589 | 1596 | ||
1597 | |||
1590 | /* | 1598 | /* |
1591 | * Wake up the thread that created us. | 1599 | * Note - we always use TASK_INTERRUPTIBLE even if the module |
1600 | * was loaded as part of the kernel. The reason is that | ||
1601 | * UNINTERRUPTIBLE would cause this thread to be counted in | ||
1602 | * the load average as a running process, and an interruptible | ||
1603 | * wait doesn't. | ||
1592 | */ | 1604 | */ |
1593 | SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent of" | 1605 | set_current_state(TASK_INTERRUPTIBLE); |
1594 | " scsi_eh_%d\n",shost->host_no)); | 1606 | while (!kthread_should_stop()) { |
1595 | 1607 | if (shost->host_failed == 0 || | |
1596 | while (1) { | 1608 | shost->host_failed != shost->host_busy) { |
1597 | /* | 1609 | SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler" |
1598 | * If we get a signal, it means we are supposed to go | 1610 | " scsi_eh_%d" |
1599 | * away and die. This typically happens if the user is | 1611 | " sleeping\n", |
1600 | * trying to unload a module. | 1612 | shost->host_no)); |
1601 | */ | 1613 | schedule(); |
1602 | SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler" | 1614 | set_current_state(TASK_INTERRUPTIBLE); |
1603 | " scsi_eh_%d" | 1615 | continue; |
1604 | " sleeping\n",shost->host_no)); | 1616 | } |
1605 | |||
1606 | /* | ||
1607 | * Note - we always use down_interruptible with the semaphore | ||
1608 | * even if the module was loaded as part of the kernel. The | ||
1609 | * reason is that down() will cause this thread to be counted | ||
1610 | * in the load average as a running process, and down | ||
1611 | * interruptible doesn't. Given that we need to allow this | ||
1612 | * thread to die if the driver was loaded as a module, using | ||
1613 | * semaphores isn't unreasonable. | ||
1614 | */ | ||
1615 | down_interruptible(&sem); | ||
1616 | if (kthread_should_stop()) | ||
1617 | break; | ||
1618 | 1617 | ||
1618 | __set_current_state(TASK_RUNNING); | ||
1619 | SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler" | 1619 | SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler" |
1620 | " scsi_eh_%d waking" | 1620 | " scsi_eh_%d waking" |
1621 | " up\n",shost->host_no)); | 1621 | " up\n",shost->host_no)); |
@@ -1642,7 +1642,7 @@ int scsi_error_handler(void *data) | |||
1642 | * which are still online. | 1642 | * which are still online. |
1643 | */ | 1643 | */ |
1644 | scsi_restart_operations(shost); | 1644 | scsi_restart_operations(shost); |
1645 | 1645 | set_current_state(TASK_INTERRUPTIBLE); | |
1646 | } | 1646 | } |
1647 | 1647 | ||
1648 | SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler scsi_eh_%d" | 1648 | SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler scsi_eh_%d" |
@@ -1651,7 +1651,7 @@ int scsi_error_handler(void *data) | |||
1651 | /* | 1651 | /* |
1652 | * Make sure that nobody tries to wake us up again. | 1652 | * Make sure that nobody tries to wake us up again. |
1653 | */ | 1653 | */ |
1654 | shost->eh_wait = NULL; | 1654 | shost->ehandler = NULL; |
1655 | return 0; | 1655 | return 0; |
1656 | } | 1656 | } |
1657 | 1657 | ||