diff options
author | Tejun Heo <htejun@gmail.com> | 2006-05-15 07:58:05 -0400 |
---|---|---|
committer | Tejun Heo <htejun@gmail.com> | 2006-05-15 07:58:05 -0400 |
commit | f686bcb8078ac7505ec88818886c2c72639f4fc5 (patch) | |
tree | 7c563e0032b2d85b631b617b8bb2a7a648607468 /drivers/scsi/libata-eh.c | |
parent | f69499f42caf74194df678c9c293f2ee0fe90bc3 (diff) |
[PATCH] libata-eh-fw: implement new EH scheduling via error completion
There are several ways a qc can get schedule for EH in new EH. This
patch implements one of them - completing a qc with ATA_QCFLAG_FAILED
set or with non-zero qc->err_mask. ALL such qc's are examined by EH.
New EH schedules a qc for EH from completion iff ->error_handler is
implemented, qc is marked as failed or qc->err_mask is non-zero and
the command is not an internal command (internal cmd is handled via
->post_internal_cmd). The EH scheduling itself is performed by asking
SCSI midlayer to schedule EH for the specified scmd.
For drivers implementing old-EH, nothing changes. As this change
makes ata_qc_complete() rather large, it's not inlined anymore and
__ata_qc_complete() is exported to other parts of libata for later
use.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/scsi/libata-eh.c')
-rw-r--r-- | drivers/scsi/libata-eh.c | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 959a1cdffac2..471846fe4b73 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c | |||
@@ -210,6 +210,33 @@ void ata_eng_timeout(struct ata_port *ap) | |||
210 | DPRINTK("EXIT\n"); | 210 | DPRINTK("EXIT\n"); |
211 | } | 211 | } |
212 | 212 | ||
213 | /** | ||
214 | * ata_qc_schedule_eh - schedule qc for error handling | ||
215 | * @qc: command to schedule error handling for | ||
216 | * | ||
217 | * Schedule error handling for @qc. EH will kick in as soon as | ||
218 | * other commands are drained. | ||
219 | * | ||
220 | * LOCKING: | ||
221 | * spin_lock_irqsave(host_set lock) | ||
222 | */ | ||
223 | void ata_qc_schedule_eh(struct ata_queued_cmd *qc) | ||
224 | { | ||
225 | struct ata_port *ap = qc->ap; | ||
226 | |||
227 | WARN_ON(!ap->ops->error_handler); | ||
228 | |||
229 | qc->flags |= ATA_QCFLAG_FAILED; | ||
230 | qc->ap->flags |= ATA_FLAG_EH_PENDING; | ||
231 | |||
232 | /* The following will fail if timeout has already expired. | ||
233 | * ata_scsi_error() takes care of such scmds on EH entry. | ||
234 | * Note that ATA_QCFLAG_FAILED is unconditionally set after | ||
235 | * this function completes. | ||
236 | */ | ||
237 | scsi_req_abort_cmd(qc->scsicmd); | ||
238 | } | ||
239 | |||
213 | static void ata_eh_scsidone(struct scsi_cmnd *scmd) | 240 | static void ata_eh_scsidone(struct scsi_cmnd *scmd) |
214 | { | 241 | { |
215 | /* nada */ | 242 | /* nada */ |