diff options
author | Tejun Heo <htejun@gmail.com> | 2006-05-15 07:58:07 -0400 |
---|---|---|
committer | Tejun Heo <htejun@gmail.com> | 2006-05-15 07:58:07 -0400 |
commit | 7b70fc039824bc7303e4007a5f758f832de56611 (patch) | |
tree | d973a40055dec97fedc5ae87852667ed2d30ea71 /drivers/scsi | |
parent | f686bcb8078ac7505ec88818886c2c72639f4fc5 (diff) |
[PATCH] libata-eh-fw: implement ata_port_schedule_eh() and ata_port_abort()
ata_port_schedule_eh() directly schedules EH for @ap without
associated qc. Once EH scheduled, no further qc is allowed and EH
kicks in as soon as all currently active qc's are drained.
ata_port_abort() schedules all currently active commands for EH by
qc_completing them with ATA_QCFLAG_FAILED set. If ata_port_abort()
doesn't find any qc to abort, it directly schedule EH using
ata_port_schedule_eh().
These two functions provide ways to invoke EH for conditions which
aren't directly related to any specfic qc.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/libata-core.c | 2 | ||||
-rw-r--r-- | drivers/scsi/libata-eh.c | 54 | ||||
-rw-r--r-- | drivers/scsi/libata-scsi.c | 23 | ||||
-rw-r--r-- | drivers/scsi/libata.h | 1 |
4 files changed, 80 insertions, 0 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 1f5c3270992a..9c97783462d6 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -5383,5 +5383,7 @@ EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); | |||
5383 | EXPORT_SYMBOL_GPL(ata_scsi_device_resume); | 5383 | EXPORT_SYMBOL_GPL(ata_scsi_device_resume); |
5384 | 5384 | ||
5385 | EXPORT_SYMBOL_GPL(ata_eng_timeout); | 5385 | EXPORT_SYMBOL_GPL(ata_eng_timeout); |
5386 | EXPORT_SYMBOL_GPL(ata_port_schedule_eh); | ||
5387 | EXPORT_SYMBOL_GPL(ata_port_abort); | ||
5386 | EXPORT_SYMBOL_GPL(ata_eh_qc_complete); | 5388 | EXPORT_SYMBOL_GPL(ata_eh_qc_complete); |
5387 | EXPORT_SYMBOL_GPL(ata_eh_qc_retry); | 5389 | EXPORT_SYMBOL_GPL(ata_eh_qc_retry); |
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 471846fe4b73..037a561809f5 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c | |||
@@ -237,6 +237,60 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) | |||
237 | scsi_req_abort_cmd(qc->scsicmd); | 237 | scsi_req_abort_cmd(qc->scsicmd); |
238 | } | 238 | } |
239 | 239 | ||
240 | /** | ||
241 | * ata_port_schedule_eh - schedule error handling without a qc | ||
242 | * @ap: ATA port to schedule EH for | ||
243 | * | ||
244 | * Schedule error handling for @ap. EH will kick in as soon as | ||
245 | * all commands are drained. | ||
246 | * | ||
247 | * LOCKING: | ||
248 | * spin_lock_irqsave(host_set lock) | ||
249 | */ | ||
250 | void ata_port_schedule_eh(struct ata_port *ap) | ||
251 | { | ||
252 | WARN_ON(!ap->ops->error_handler); | ||
253 | |||
254 | ap->flags |= ATA_FLAG_EH_PENDING; | ||
255 | ata_schedule_scsi_eh(ap->host); | ||
256 | |||
257 | DPRINTK("port EH scheduled\n"); | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * ata_port_abort - abort all qc's on the port | ||
262 | * @ap: ATA port to abort qc's for | ||
263 | * | ||
264 | * Abort all active qc's of @ap and schedule EH. | ||
265 | * | ||
266 | * LOCKING: | ||
267 | * spin_lock_irqsave(host_set lock) | ||
268 | * | ||
269 | * RETURNS: | ||
270 | * Number of aborted qc's. | ||
271 | */ | ||
272 | int ata_port_abort(struct ata_port *ap) | ||
273 | { | ||
274 | int tag, nr_aborted = 0; | ||
275 | |||
276 | WARN_ON(!ap->ops->error_handler); | ||
277 | |||
278 | for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { | ||
279 | struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag); | ||
280 | |||
281 | if (qc) { | ||
282 | qc->flags |= ATA_QCFLAG_FAILED; | ||
283 | ata_qc_complete(qc); | ||
284 | nr_aborted++; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | if (!nr_aborted) | ||
289 | ata_port_schedule_eh(ap); | ||
290 | |||
291 | return nr_aborted; | ||
292 | } | ||
293 | |||
240 | static void ata_eh_scsidone(struct scsi_cmnd *scmd) | 294 | static void ata_eh_scsidone(struct scsi_cmnd *scmd) |
241 | { | 295 | { |
242 | /* nada */ | 296 | /* nada */ |
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index a9b4083a4f67..fd7064b9697d 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c | |||
@@ -2596,3 +2596,26 @@ void ata_scsi_scan_host(struct ata_port *ap) | |||
2596 | } | 2596 | } |
2597 | } | 2597 | } |
2598 | 2598 | ||
2599 | /** | ||
2600 | * ata_schedule_scsi_eh - schedule EH for SCSI host | ||
2601 | * @shost: SCSI host to invoke error handling on. | ||
2602 | * | ||
2603 | * Schedule SCSI EH without scmd. This is a hack. | ||
2604 | * | ||
2605 | * LOCKING: | ||
2606 | * spin_lock_irqsave(host_set lock) | ||
2607 | **/ | ||
2608 | void ata_schedule_scsi_eh(struct Scsi_Host *shost) | ||
2609 | { | ||
2610 | unsigned long flags; | ||
2611 | |||
2612 | spin_lock_irqsave(shost->host_lock, flags); | ||
2613 | |||
2614 | if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 || | ||
2615 | scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) { | ||
2616 | shost->host_eh_scheduled++; | ||
2617 | scsi_eh_wakeup(shost); | ||
2618 | } | ||
2619 | |||
2620 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2621 | } | ||
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 52622b7f8a9e..b76ad7d7062a 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h | |||
@@ -98,6 +98,7 @@ extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, | |||
98 | extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, | 98 | extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, |
99 | unsigned int (*actor) (struct ata_scsi_args *args, | 99 | unsigned int (*actor) (struct ata_scsi_args *args, |
100 | u8 *rbuf, unsigned int buflen)); | 100 | u8 *rbuf, unsigned int buflen)); |
101 | extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); | ||
101 | 102 | ||
102 | /* libata-eh.c */ | 103 | /* libata-eh.c */ |
103 | extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); | 104 | extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); |