aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@srcf.ucam.org>2008-05-19 12:29:34 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-05-19 17:55:18 -0400
commitae6c23c4e1ec9720b99e1e6850fe47c6c7fddbb3 (patch)
tree645210471902a33b044cdf9f9e06620677b01835 /drivers
parent50af2fa1e18d0ab411d06bf727ecadb7e01721e9 (diff)
Fixups to ATA ACPI hotplug
The libata-acpi.c code currently accepts hotplug messages from both the port and the device. This does not match the behaviour of the bay driver, and may result in confusion when two hotplug requests are received for the same device. This patch limits the hotplug notification to removable ACPI devices, which in turn allows it to use the _STA method to determine whether the device has been removed or inserted. On removal, devices are marked as detached. On insertion, a hotplug scan is started. This should avoid lockups caused by the ata layer attempting to scan devices which have been removed. The uevent sending is moved outside the spinlock in order to avoid a warning generated by it firing when interrupts are disabled. Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/libata-acpi.c77
1 files changed, 50 insertions, 27 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 70b77e0899a8..865a552c91e6 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)
118 ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; 118 ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
119} 119}
120 120
121static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, 121static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device
122 u32 event) 122 *dev, u32 event)
123{ 123{
124 char event_string[12]; 124 char event_string[12];
125 char *envp[] = { event_string, NULL }; 125 char *envp[] = { event_string, NULL };
@@ -127,39 +127,67 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
127 struct kobject *kobj = NULL; 127 struct kobject *kobj = NULL;
128 int wait = 0; 128 int wait = 0;
129 unsigned long flags; 129 unsigned long flags;
130 130 acpi_handle handle, tmphandle;
131 unsigned long sta;
132 acpi_status status;
133
131 if (!ap) 134 if (!ap)
132 ap = dev->link->ap; 135 ap = dev->link->ap;
133 ehi = &ap->link.eh_info; 136 ehi = &ap->link.eh_info;
134 137
135 spin_lock_irqsave(ap->lock, flags); 138 spin_lock_irqsave(ap->lock, flags);
136 139
140 if (dev)
141 handle = dev->acpi_handle;
142 else
143 handle = ap->acpi_handle;
144
145 status = acpi_get_handle(handle, "_EJ0", &tmphandle);
146 if (ACPI_FAILURE(status)) {
147 /* This device is not ejectable */
148 spin_unlock_irqrestore(ap->lock, flags);
149 return;
150 }
151
152 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
153 if (ACPI_FAILURE(status)) {
154 printk ("Unable to determine bay status\n");
155 spin_unlock_irqrestore(ap->lock, flags);
156 return;
157 }
158
137 switch (event) { 159 switch (event) {
138 case ACPI_NOTIFY_BUS_CHECK: 160 case ACPI_NOTIFY_BUS_CHECK:
139 case ACPI_NOTIFY_DEVICE_CHECK: 161 case ACPI_NOTIFY_DEVICE_CHECK:
140 ata_ehi_push_desc(ehi, "ACPI event"); 162 ata_ehi_push_desc(ehi, "ACPI event");
141 ata_ehi_hotplugged(ehi); 163 if (!sta) {
142 ata_port_freeze(ap); 164 /* Device has been unplugged */
143 break; 165 if (dev)
144 166 dev->flags |= ATA_DFLAG_DETACH;
145 case ACPI_NOTIFY_EJECT_REQUEST: 167 else {
146 ata_ehi_push_desc(ehi, "ACPI event"); 168 struct ata_link *tlink;
147 if (dev) 169 struct ata_device *tdev;
148 dev->flags |= ATA_DFLAG_DETACH; 170
149 else { 171 ata_port_for_each_link(tlink, ap) {
150 struct ata_link *tlink; 172 ata_link_for_each_dev(tdev, tlink) {
151 struct ata_device *tdev; 173 tdev->flags |=
152 174 ATA_DFLAG_DETACH;
153 ata_port_for_each_link(tlink, ap) 175 }
154 ata_link_for_each_dev(tdev, tlink) 176 }
155 tdev->flags |= ATA_DFLAG_DETACH; 177 }
178 ata_port_schedule_eh(ap);
179 wait = 1;
180 } else {
181 ata_ehi_hotplugged(ehi);
182 ata_port_freeze(ap);
156 } 183 }
157
158 ata_port_schedule_eh(ap);
159 wait = 1;
160 break;
161 } 184 }
162 185
186 spin_unlock_irqrestore(ap->lock, flags);
187
188 if (wait)
189 ata_port_wait_eh(ap);
190
163 if (dev) { 191 if (dev) {
164 if (dev->sdev) 192 if (dev->sdev)
165 kobj = &dev->sdev->sdev_gendev.kobj; 193 kobj = &dev->sdev->sdev_gendev.kobj;
@@ -170,11 +198,6 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
170 sprintf(event_string, "BAY_EVENT=%d", event); 198 sprintf(event_string, "BAY_EVENT=%d", event);
171 kobject_uevent_env(kobj, KOBJ_CHANGE, envp); 199 kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
172 } 200 }
173
174 spin_unlock_irqrestore(ap->lock, flags);
175
176 if (wait)
177 ata_port_wait_eh(ap);
178} 201}
179 202
180static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) 203static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)