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/libata-eh.c | |
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/libata-eh.c')
-rw-r--r-- | drivers/scsi/libata-eh.c | 54 |
1 files changed, 54 insertions, 0 deletions
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 */ |