aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2008-03-12 01:24:43 -0400
committerJeff Garzik <jeff@garzik.org>2008-03-17 08:26:42 -0400
commit233f112042d0b50170212dbff99c3b34b8773cd3 (patch)
tree2b40ce227755dbbbe3ece6acd161bc7619f19f85 /drivers/ata
parenta978b30af3bab0dd9af9350eeda25e76123fa28e (diff)
libata-acpi: improve dock event handling
Improve ACPI hotplug handling such that dock event is handled properly. * Register handlers for dock events. * Directly detach device on EJECT_REQUEST instead of signaling hotplug event. This prevents libata from accessing severed controller and/or device. * While at it, use named constants for ACPI events and move uevent signaling inside host lock. Original patch and testing by Holger Macht. Signed-off-by: Tejun Heo <htejun@gmail.com> Cc: Holger Macht <hmacht@suse.de> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-acpi.c96
1 files changed, 69 insertions, 27 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 0770cb7391a4..bf98a566adac 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -118,45 +118,77 @@ 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 kobject *kobj, 121static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
122 u32 event) 122 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 };
126 struct ata_eh_info *ehi = &ap->link.eh_info; 126 struct ata_eh_info *ehi;
127 127 struct kobject *kobj = NULL;
128 if (event == 0 || event == 1) { 128 int wait = 0;
129 unsigned long flags; 129 unsigned long flags;
130 spin_lock_irqsave(ap->lock, flags); 130
131 ata_ehi_clear_desc(ehi); 131 if (!ap)
132 ata_ehi_push_desc(ehi, "ACPI event"); 132 ap = dev->link->ap;
133 ata_ehi_hotplugged(ehi); 133 ehi = &ap->link.eh_info;
134 ata_port_freeze(ap); 134
135 spin_unlock_irqrestore(ap->lock, flags); 135 spin_lock_irqsave(ap->lock, flags);
136
137 switch (event) {
138 case ACPI_NOTIFY_BUS_CHECK:
139 case ACPI_NOTIFY_DEVICE_CHECK:
140 ata_ehi_push_desc(ehi, "ACPI event");
141 ata_ehi_hotplugged(ehi);
142 ata_port_freeze(ap);
143 break;
144
145 case ACPI_NOTIFY_EJECT_REQUEST:
146 ata_ehi_push_desc(ehi, "ACPI event");
147 if (dev)
148 dev->flags |= ATA_DFLAG_DETACH;
149 else {
150 struct ata_link *tlink;
151 struct ata_device *tdev;
152
153 ata_port_for_each_link(tlink, ap)
154 ata_link_for_each_dev(tdev, tlink)
155 tdev->flags |= ATA_DFLAG_DETACH;
156 }
157
158 ata_port_schedule_eh(ap);
159 wait = 1;
160 break;
136 } 161 }
137 162
163 if (dev) {
164 if (dev->sdev)
165 kobj = &dev->sdev->sdev_gendev.kobj;
166 } else
167 kobj = &ap->dev->kobj;
168
138 if (kobj) { 169 if (kobj) {
139 sprintf(event_string, "BAY_EVENT=%d", event); 170 sprintf(event_string, "BAY_EVENT=%d", event);
140 kobject_uevent_env(kobj, KOBJ_CHANGE, envp); 171 kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
141 } 172 }
173
174 spin_unlock_irqrestore(ap->lock, flags);
175
176 if (wait)
177 ata_port_wait_eh(ap);
142} 178}
143 179
144static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) 180static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
145{ 181{
146 struct ata_device *dev = data; 182 struct ata_device *dev = data;
147 struct kobject *kobj = NULL;
148 183
149 if (dev->sdev) 184 ata_acpi_handle_hotplug(NULL, dev, event);
150 kobj = &dev->sdev->sdev_gendev.kobj;
151
152 ata_acpi_handle_hotplug(dev->link->ap, kobj, event);
153} 185}
154 186
155static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) 187static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
156{ 188{
157 struct ata_port *ap = data; 189 struct ata_port *ap = data;
158 190
159 ata_acpi_handle_hotplug(ap, &ap->dev->kobj, event); 191 ata_acpi_handle_hotplug(ap, NULL, event);
160} 192}
161 193
162/** 194/**
@@ -191,20 +223,30 @@ void ata_acpi_associate(struct ata_host *host)
191 else 223 else
192 ata_acpi_associate_ide_port(ap); 224 ata_acpi_associate_ide_port(ap);
193 225
194 if (ap->acpi_handle) 226 if (ap->acpi_handle) {
195 acpi_install_notify_handler (ap->acpi_handle, 227 acpi_install_notify_handler(ap->acpi_handle,
196 ACPI_SYSTEM_NOTIFY, 228 ACPI_SYSTEM_NOTIFY,
197 ata_acpi_ap_notify, 229 ata_acpi_ap_notify, ap);
198 ap); 230#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
231 /* we might be on a docking station */
232 register_hotplug_dock_device(ap->acpi_handle,
233 ata_acpi_ap_notify, ap);
234#endif
235 }
199 236
200 for (j = 0; j < ata_link_max_devices(&ap->link); j++) { 237 for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
201 struct ata_device *dev = &ap->link.device[j]; 238 struct ata_device *dev = &ap->link.device[j];
202 239
203 if (dev->acpi_handle) 240 if (dev->acpi_handle) {
204 acpi_install_notify_handler (dev->acpi_handle, 241 acpi_install_notify_handler(dev->acpi_handle,
205 ACPI_SYSTEM_NOTIFY, 242 ACPI_SYSTEM_NOTIFY,
206 ata_acpi_dev_notify, 243 ata_acpi_dev_notify, dev);
207 dev); 244#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
245 /* we might be on a docking station */
246 register_hotplug_dock_device(dev->acpi_handle,
247 ata_acpi_dev_notify, dev);
248#endif
249 }
208 } 250 }
209 } 251 }
210} 252}