summaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-acpi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-05-19 16:29:29 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-05-19 16:29:29 -0700
commit88e6c9499f959cdac9ef120a1a1e857da5944052 (patch)
tree282eaabe299f084db582668a16b2f86e0cfbdfec /drivers/ata/libata-acpi.c
parent8c4bab3a1aadaf4e38b2bfaf557eab74322a9fd4 (diff)
parentc85665ffa8e351a5b38f8e4ceaec527d8783c970 (diff)
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev: (28 commits) drivers/ata: trim trailing whitespace Fixups to ATA ACPI hotplug libata: ignore SIMG4726 config pseudo device sata_sil24: don't use NCQ if marvell 4140 PMP is attached libata: don't schedule LPM action seperately during probing libata: make sure PMP notification is turned off during recovery libata: increase PMP register access timeout to 3s libata: ignore recovered PHY errors libata: kill hotplug related race condition libata: move reset freeze/thaw handling into ata_eh_reset() libata: reorganize ata_eh_reset() no reset method path libata: fix sata_link_hardreset() @online out parameter handling sata_promise: other cleanups sata_promise: mmio access cleanups sata_promise: fix irq clearing buglets ata: remove FIT() macro sata_mv: ensure empty request queue for FBS-NCQ EH sata_mv: cache main_irq_mask register in hpriv sata_mv: disregard masked irqs sata_mv: fix pmp drives not found ...
Diffstat (limited to 'drivers/ata/libata-acpi.c')
-rw-r--r--drivers/ata/libata-acpi.c75
1 files changed, 49 insertions, 26 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 70b77e0899a..dbf6ca781f6 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -118,8 +118,8 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
}
-static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
- u32 event)
+static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device
+ *dev, u32 event)
{
char event_string[12];
char *envp[] = { event_string, NULL };
@@ -127,6 +127,9 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
struct kobject *kobj = NULL;
int wait = 0;
unsigned long flags;
+ acpi_handle handle, tmphandle;
+ unsigned long sta;
+ acpi_status status;
if (!ap)
ap = dev->link->ap;
@@ -134,32 +137,57 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
spin_lock_irqsave(ap->lock, flags);
+ if (dev)
+ handle = dev->acpi_handle;
+ else
+ handle = ap->acpi_handle;
+
+ status = acpi_get_handle(handle, "_EJ0", &tmphandle);
+ if (ACPI_FAILURE(status)) {
+ /* This device is not ejectable */
+ spin_unlock_irqrestore(ap->lock, flags);
+ return;
+ }
+
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status)) {
+ printk ("Unable to determine bay status\n");
+ spin_unlock_irqrestore(ap->lock, flags);
+ return;
+ }
+
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
ata_ehi_push_desc(ehi, "ACPI event");
- ata_ehi_hotplugged(ehi);
- ata_port_freeze(ap);
- break;
-
- case ACPI_NOTIFY_EJECT_REQUEST:
- ata_ehi_push_desc(ehi, "ACPI event");
- if (dev)
- dev->flags |= ATA_DFLAG_DETACH;
- else {
- struct ata_link *tlink;
- struct ata_device *tdev;
-
- ata_port_for_each_link(tlink, ap)
- ata_link_for_each_dev(tdev, tlink)
- tdev->flags |= ATA_DFLAG_DETACH;
+ if (!sta) {
+ /* Device has been unplugged */
+ if (dev)
+ dev->flags |= ATA_DFLAG_DETACH;
+ else {
+ struct ata_link *tlink;
+ struct ata_device *tdev;
+
+ ata_port_for_each_link(tlink, ap) {
+ ata_link_for_each_dev(tdev, tlink) {
+ tdev->flags |=
+ ATA_DFLAG_DETACH;
+ }
+ }
+ }
+ ata_port_schedule_eh(ap);
+ wait = 1;
+ } else {
+ ata_ehi_hotplugged(ehi);
+ ata_port_freeze(ap);
}
-
- ata_port_schedule_eh(ap);
- wait = 1;
- break;
}
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ if (wait)
+ ata_port_wait_eh(ap);
+
if (dev) {
if (dev->sdev)
kobj = &dev->sdev->sdev_gendev.kobj;
@@ -170,11 +198,6 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
sprintf(event_string, "BAY_EVENT=%d", event);
kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
}
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- if (wait)
- ata_port_wait_eh(ap);
}
static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)