aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-eh.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2008-11-03 06:04:37 -0500
committerJeff Garzik <jgarzik@redhat.com>2008-12-28 22:43:21 -0500
commitece180d1cfe5fa751eaa85bf796cf28b2150af15 (patch)
treeaca9d485036858ed3f1859e679473cebd3476845 /drivers/ata/libata-eh.c
parentad74e4c18d0962397314460d0da312e72c8bd02d (diff)
libata: perform port detach in EH
ata_port_detach() first made sure EH saw ATA_PFLAG_UNLOADING and then assumed EH context belongs to it and performed detach operation itself. However, UNLOADING doesn't disable all of EH and this could lead to problems including triggering WARN_ON()'s in EH path. This patch makes port detach behave more like other EH actions such that ata_port_detach() requests EH to detach and waits for completion. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r--drivers/ata/libata-eh.c32
1 files changed, 31 insertions, 1 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index d673f3712bdc..8147a8386370 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -491,6 +491,31 @@ enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
491 return ret; 491 return ret;
492} 492}
493 493
494static void ata_eh_unload(struct ata_port *ap)
495{
496 struct ata_link *link;
497 struct ata_device *dev;
498 unsigned long flags;
499
500 /* Restore SControl IPM and SPD for the next driver and
501 * disable attached devices.
502 */
503 ata_for_each_link(link, ap, PMP_FIRST) {
504 sata_scr_write(link, SCR_CONTROL, link->saved_scontrol & 0xff0);
505 ata_for_each_dev(dev, link, ALL)
506 ata_dev_disable(dev);
507 }
508
509 /* freeze and set UNLOADED */
510 spin_lock_irqsave(ap->lock, flags);
511
512 ata_port_freeze(ap); /* won't be thawed */
513 ap->pflags &= ~ATA_PFLAG_EH_PENDING; /* clear pending from freeze */
514 ap->pflags |= ATA_PFLAG_UNLOADED;
515
516 spin_unlock_irqrestore(ap->lock, flags);
517}
518
494/** 519/**
495 * ata_scsi_error - SCSI layer error handler callback 520 * ata_scsi_error - SCSI layer error handler callback
496 * @host: SCSI host on which error occurred 521 * @host: SCSI host on which error occurred
@@ -618,8 +643,13 @@ void ata_scsi_error(struct Scsi_Host *host)
618 /* invoke EH, skip if unloading or suspended */ 643 /* invoke EH, skip if unloading or suspended */
619 if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED))) 644 if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
620 ap->ops->error_handler(ap); 645 ap->ops->error_handler(ap);
621 else 646 else {
647 /* if unloading, commence suicide */
648 if ((ap->pflags & ATA_PFLAG_UNLOADING) &&
649 !(ap->pflags & ATA_PFLAG_UNLOADED))
650 ata_eh_unload(ap);
622 ata_eh_finish(ap); 651 ata_eh_finish(ap);
652 }
623 653
624 /* process port suspend request */ 654 /* process port suspend request */
625 ata_eh_handle_port_suspend(ap); 655 ata_eh_handle_port_suspend(ap);