aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-core.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-core.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-core.c')
-rw-r--r--drivers/ata/libata-core.c23
1 files changed, 4 insertions, 19 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 1ecc3cb0b722..837fb60a6dcc 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6107,8 +6107,6 @@ int ata_host_activate(struct ata_host *host, int irq,
6107static void ata_port_detach(struct ata_port *ap) 6107static void ata_port_detach(struct ata_port *ap)
6108{ 6108{
6109 unsigned long flags; 6109 unsigned long flags;
6110 struct ata_link *link;
6111 struct ata_device *dev;
6112 6110
6113 if (!ap->ops->error_handler) 6111 if (!ap->ops->error_handler)
6114 goto skip_eh; 6112 goto skip_eh;
@@ -6116,28 +6114,15 @@ static void ata_port_detach(struct ata_port *ap)
6116 /* tell EH we're leaving & flush EH */ 6114 /* tell EH we're leaving & flush EH */
6117 spin_lock_irqsave(ap->lock, flags); 6115 spin_lock_irqsave(ap->lock, flags);
6118 ap->pflags |= ATA_PFLAG_UNLOADING; 6116 ap->pflags |= ATA_PFLAG_UNLOADING;
6117 ata_port_schedule_eh(ap);
6119 spin_unlock_irqrestore(ap->lock, flags); 6118 spin_unlock_irqrestore(ap->lock, flags);
6120 6119
6120 /* wait till EH commits suicide */
6121 ata_port_wait_eh(ap); 6121 ata_port_wait_eh(ap);
6122 6122
6123 /* EH is now guaranteed to see UNLOADING - EH context belongs 6123 /* it better be dead now */
6124 * to us. Restore SControl and disable all existing devices. 6124 WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED));
6125 */
6126 ata_for_each_link(link, ap, PMP_FIRST) {
6127 sata_scr_write(link, SCR_CONTROL, link->saved_scontrol & 0xff0);
6128 ata_for_each_dev(dev, link, ALL)
6129 ata_dev_disable(dev);
6130 }
6131
6132 /* Final freeze & EH. All in-flight commands are aborted. EH
6133 * will be skipped and retrials will be terminated with bad
6134 * target.
6135 */
6136 spin_lock_irqsave(ap->lock, flags);
6137 ata_port_freeze(ap); /* won't be thawed */
6138 spin_unlock_irqrestore(ap->lock, flags);
6139 6125
6140 ata_port_wait_eh(ap);
6141 cancel_rearming_delayed_work(&ap->hotplug_task); 6126 cancel_rearming_delayed_work(&ap->hotplug_task);
6142 6127
6143 skip_eh: 6128 skip_eh: