public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] libata: Handle bay devices in dock stations
@ 2008-05-28 14:38 Holger Macht
  2008-05-28 14:39 ` Tejun Heo
                   ` (4 more replies)
  0 siblings, 5 replies; 34+ messages in thread
From: Holger Macht @ 2008-05-28 14:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: Tejun Heo, linux-ide, Jeff Garzik, linux-acpi, Matthew Garrett,
	akpm

* Differentiate between bay devices in dock stations and others:

 - When an ACPI_NOTIFY_EJECT_REQUEST appears, just signal uevent to
   userspace (that is when the optional eject button on a bay device is
   pressed/pulled) giving the possibility to unmount file systems and to
   clean up. Also, only send uevent in case we get an EJECT_REQUEST
   without doing anything else. In other cases, you'll get an add/remove
   event because libata attaches/detaches the device.

 - In case of a dock event, which in turn signals an
   ACPI_NOTIFY_EJECT_REQUEST, immediately detach the device, because it
   may already have been gone

* In case of an ACPI_NOTIFY_DEVICE/BUS_CHECK, evaluate _STA to check if
  the device has been plugged or unplugged. If plugged, hotplug it, if
  unplugged, just signal event to userspace
  (initial patch by Matthew Garrett <mjg59@srcf.ucam.org>)

* Call ACPI _EJ0 for detached devices

Signed-off-by: Holger Macht <hmacht@suse.de>
---

Changes regarding the previous patch:

 * Make sure kobj does not go away outside locking
 * Coding style cleanups
 * Call _EJ0 for detached devices

diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index dbf6ca7..e0e49fd 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -118,8 +118,40 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
 		ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
 }
 
+static void ata_acpi_eject_device(acpi_handle handle)
+{
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
+
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	arg.type = ACPI_TYPE_INTEGER;
+	arg.integer.value = 1;
+
+	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
+					      &arg_list, NULL)))
+		printk(KERN_ERR "Failed to evaluate _EJ0!\n");
+}
+
+static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
+{
+	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_freeze(ap);
+	ata_port_schedule_eh(ap);
+}
+
 static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device
-				    *dev, u32 event)
+				    *dev, u32 event, int is_dock_event)
 {
 	char event_string[12];
 	char *envp[] = { event_string, NULL };
@@ -135,83 +167,98 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device
 		ap = dev->link->ap;
 	ehi = &ap->link.eh_info;
 
-	spin_lock_irqsave(ap->lock, flags);
-
-	if (dev)
+	if (dev) {
+		if (dev->sdev)
+			kobj = &dev->sdev->sdev_gendev.kobj;
 		handle = dev->acpi_handle;
-	else
+	} else {
+		kobj = &ap->dev->kobj;
 		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);
+	if (ACPI_FAILURE(status))
+		/* This device does not support hotplug */
 		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;
-	}
+	spin_lock_irqsave(ap->lock, flags);
 
 	switch (event) {
 	case ACPI_NOTIFY_BUS_CHECK:
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		ata_ehi_push_desc(ehi, "ACPI event");
-		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 {
+
+		status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+		if (ACPI_FAILURE(status)) {
+			printk(KERN_ERR "Unable to determine bay status\n");
+			break;
+		}
+
+		if (sta) {
 			ata_ehi_hotplugged(ehi);
 			ata_port_freeze(ap);
+		} else {
+			/* The device has gone - unplug it */
+			ata_acpi_detach_device(ap, dev);
+			wait = 1;
 		}
-	}
+		break;
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		ata_ehi_push_desc(ehi, "ACPI event");
 
-	spin_unlock_irqrestore(ap->lock, flags);
+		if (!is_dock_event)
+			break;
 
-	if (wait)
-		ata_port_wait_eh(ap);
+		/* undock event - immediate unplug */
+		ata_acpi_detach_device(ap, dev);
+		wait = 1;
+		break;
+	}
 
-	if (dev) {
-		if (dev->sdev)
-			kobj = &dev->sdev->sdev_gendev.kobj;
-	} else
-		kobj = &ap->dev->kobj;
+	/* make sure kobj doesn't go away while ap->lock is released */
+	kobject_get(kobj);
+
+	spin_unlock_irqrestore(ap->lock, flags);
 
-	if (kobj) {
+	if (kobj && !is_dock_event) {
 		sprintf(event_string, "BAY_EVENT=%d", event);
 		kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
 	}
+
+	kobject_put(kobj);
+
+	if (wait) {
+		ata_port_wait_eh(ap);
+		ata_acpi_eject_device(handle);
+	}
+}
+
+static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
+{
+	struct ata_device *dev = data;
+
+	ata_acpi_handle_hotplug(NULL, dev, event, 1);
+}
+
+static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
+{
+	struct ata_port *ap = data;
+
+	ata_acpi_handle_hotplug(ap, NULL, event, 1);
 }
 
 static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
 {
 	struct ata_device *dev = data;
 
-	ata_acpi_handle_hotplug(NULL, dev, event);
+	ata_acpi_handle_hotplug(NULL, dev, event, 0);
 }
 
 static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
 {
 	struct ata_port *ap = data;
 
-	ata_acpi_handle_hotplug(ap, NULL, event);
+	ata_acpi_handle_hotplug(ap, NULL, event, 0);
 }
 
 /**
@@ -252,7 +299,7 @@ void ata_acpi_associate(struct ata_host *host)
 						    ata_acpi_ap_notify, ap);
 			/* we might be on a docking station */
 			register_hotplug_dock_device(ap->acpi_handle,
-						     ata_acpi_ap_notify, ap);
+					     ata_acpi_ap_notify_dock, ap);
 		}
 
 		for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
@@ -264,7 +311,7 @@ void ata_acpi_associate(struct ata_host *host)
 						ata_acpi_dev_notify, dev);
 				/* we might be on a docking station */
 				register_hotplug_dock_device(dev->acpi_handle,
-						ata_acpi_dev_notify, dev);
+					     ata_acpi_dev_notify_dock, dev);
 			}
 		}
 	}


^ permalink raw reply related	[flat|nested] 34+ messages in thread
* Re: [PATCH] libata: Handle bay devices in dock stations
@ 2008-05-31  0:01 Pascal Brückner
  0 siblings, 0 replies; 34+ messages in thread
From: Pascal Brückner @ 2008-05-31  0:01 UTC (permalink / raw)
  To: linux-kernel

tom@dbservic ... wrote:
> Will this patch or the other bay/dock related patches you send in the
> past days allow me to undock my laptop and still be able to
> suspend/resume without locking the laptop up? And without having to 
> run any userspace scripts?

I'm using a ThinkPad X31 with the Ultrabase X3, containing an Ultrabay,
which sends events on removal or undocking thanks to the "dock" and
"bay" modules. Unfortunately, hibernate/suspend to disk doesn't work
with any patch to libata seen here (i'm using the ata_piix module), if
the cd drive in my Ultrabay was removed before suspending.

Ejecting and reinserting during the running system works great, when the
bay module is loaded before ata_piix (via initrd) or with
"libata.noacpi=1" boot parameter. For these tasks i'm using the example
scripts listed on thinkwiki [1] and udev.

For example, removing looks like the following in syslog (on 2.6.24):
  ACPI: \_SB_.PCI0.IDE0.SCND.MSTR: Bay event
  ata2.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x2
  ata2.00: waking up from sleep
  ata2: soft resetting link
  ata2.00: configured for UDMA/33
  ata2: EH complete
  ata2.00: disabled
  ACPI: \_SB_.PCI0.IDE0.SCND.MSTR: Ejecting device

After this, undocking works by pressing the "undock" button on my Ultrabase:
  ACPI: \_SB_.GDCK - undocking

Reinserting the ThinkPad into the docking station just sends a dock event:
  ACPI: \_SB_.GDCK - docking

So i need to trigger the cd device recognition via udev (and the switch
on the Ultrabay):
  ACPI: \_SB_.PCI0.IDE0.SCND.MSTR: Bay event
  ata2: soft resetting link
  ata2.00: ATAPI: MATSHITADVD-ROM SR-8177, NB21, max UDMA/33
  ata2.00: configured for UDMA/33
  ata2: EH complete
  scsi 1:0:0:0: CD-ROM            MATSHITA DVD-ROM SR-8177  NB21 PQ: 0
ANSI: 5
  sr0: scsi3-mmc drive: 24x/24x cd/rw xa/form2 cdda tray
  sr 1:0:0:0: Attached scsi CD-ROM sr0
  sr 1:0:0:0: Attached scsi generic sg1 type 5

So ejecting and reinserting of the bay devices and docking/undocking
works, as long as - to come to my problem - i don't try to hibernate.
Hibernating (tried plain echo disk > /sys/power/state, too) just freezes
the entire system without leaving a message anywhere. When using
tuxonice/suspend2, it hangs at "Doing atomic copy".
I discovered a new strange behaviour with recent 2.6.26 kernel and your
attached patch, too: If i remove the Ultrabay device via script, leaving
the device plugged in, it is discovered and spinning up again
automatically on hibernation (which works in this case, because the
device is present).

Seems like the device isn't completely removed in the driver (/dev/*
block device not present and hald not running) and on hibernation
something tries to access the nonexistent device and locks up the
system. I tried stable 2.6.24, 2.6.25 and plain 2.6.26, 2.6.26 from
zen-sources git, 2.6.26 patched with the patches in this thread and in [2].

Hope this helps,
Pascal

[1] http://www.thinkwiki.org/wiki/How_to_hotswap_UltraBay_devices
[2] http://lkml.org/lkml/2008/2/14/123


^ permalink raw reply	[flat|nested] 34+ messages in thread
* Re: [PATCH] libata: Handle bay devices in dock stations
@ 2008-05-31 10:28 Pascal Brückner
  0 siblings, 0 replies; 34+ messages in thread
From: Pascal Brückner @ 2008-05-31 10:28 UTC (permalink / raw)
  To: linux-kernel; +Cc: Matthew Garrett

I'm using a ThinkPad X31 with the Ultrabase X3, containing an Ultrabay,
which sends events on removal or undocking thanks to the "dock" and
"bay" modules. Unfortunately, hibernate/suspend to disk doesn't work
with any patch to libata seen here (i'm using the ata_piix module), if
the cd drive in my Ultrabay was removed before suspending.

Ejecting and reinserting during the running system works great, when the
bay module is loaded before ata_piix (via initrd) or with
"libata.noacpi=1" boot parameter. For these tasks i'm using the example
scripts listed on thinkwiki [1] and udev.

For example, removing looks like the following in syslog (on 2.6.24):
  ACPI: \_SB_.PCI0.IDE0.SCND.MSTR: Bay event
  ata2.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x2
  ata2.00: waking up from sleep
  ata2: soft resetting link
  ata2.00: configured for UDMA/33
  ata2: EH complete
  ata2.00: disabled
  ACPI: \_SB_.PCI0.IDE0.SCND.MSTR: Ejecting device

After this, undocking works by pressing the "undock" button on my Ultrabase:
  ACPI: \_SB_.GDCK - undocking

Reinserting the ThinkPad into the docking station just sends a dock event:
  ACPI: \_SB_.GDCK - docking

So i need to trigger the cd device recognition via udev (and the switch
on the Ultrabay):
  ACPI: \_SB_.PCI0.IDE0.SCND.MSTR: Bay event
  ata2: soft resetting link
  ata2.00: ATAPI: MATSHITADVD-ROM SR-8177, NB21, max UDMA/33
  ata2.00: configured for UDMA/33
  ata2: EH complete
  scsi 1:0:0:0: CD-ROM            MATSHITA DVD-ROM SR-8177  NB21 PQ: 0
ANSI: 5
  sr0: scsi3-mmc drive: 24x/24x cd/rw xa/form2 cdda tray
  sr 1:0:0:0: Attached scsi CD-ROM sr0
  sr 1:0:0:0: Attached scsi generic sg1 type 5

So ejecting and reinserting of the bay devices and docking/undocking
works, as long as - to come to my problem - i don't try to hibernate.
Hibernating (tried plain echo disk > /sys/power/state, too) just freezes
the entire system without leaving a message anywhere. When using
tuxonice/suspend2, it hangs at "Doing atomic copy".
I discovered a new strange behaviour with recent 2.6.26 kernel and your
attached patch, too: If i remove the Ultrabay device via script, leaving
the device plugged in, it is discovered and spinning up again
automatically on hibernation (which works in this case, because the
device is present).

Seems like the device isn't completely removed in the driver (/dev/*
block device not present and hald not running) and on hibernation
something tries to access the nonexistent device and locks up the
system. I tried stable 2.6.24, 2.6.25 and plain 2.6.26, 2.6.26 from
zen-sources git, 2.6.26 patched with the patches in this thread and in [2].

Hope this helps,
Pascal

[1] http://www.thinkwiki.org/wiki/How_to_hotswap_UltraBay_devices
[2] http://lkml.org/lkml/2008/2/14/123



^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2008-06-09  4:56 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-28 14:38 [PATCH] libata: Handle bay devices in dock stations Holger Macht
2008-05-28 14:39 ` Tejun Heo
2008-05-29  3:02 ` Andrew Morton
2008-05-29  3:08   ` Tejun Heo
2008-05-29 13:22 ` Matthew Garrett
2008-05-29 13:33   ` Holger Macht
2008-05-29 13:32     ` Matthew Garrett
2008-05-29 13:39       ` Holger Macht
2008-05-29 13:40         ` Matthew Garrett
2008-05-29 13:44   ` Tejun Heo
2008-05-29 14:02     ` Matthew Garrett
2008-05-29 14:14       ` Holger Macht
2008-05-29 14:35         ` Matthew Garrett
2008-05-29 14:37           ` Tejun Heo
2008-05-29 14:49             ` Matthew Garrett
2008-05-29 16:32               ` Holger Macht
2008-05-29 16:40                 ` Tejun Heo
2008-06-01 16:05                   ` Holger Macht
2008-05-29 16:46                 ` Holger Macht
2008-05-29 17:51                 ` Henrique de Moraes Holschuh
2008-05-30 11:07 ` tom
2008-06-01 16:06   ` Holger Macht
2008-06-03 18:07 ` Jeff Garzik
2008-06-03 18:13   ` Matthew Garrett
2008-06-03 18:23     ` Holger Macht
2008-06-09  1:44     ` Tejun Heo
2008-06-09  1:48       ` Matthew Garrett
2008-06-09  4:56         ` Tejun Heo
2008-06-03 18:27   ` Holger Macht
2008-06-03 18:29     ` Matthew Garrett
2008-06-03 18:54       ` Jeff Garzik
2008-06-04 10:29     ` Jeff Garzik
  -- strict thread matches above, loose matches on Subject: below --
2008-05-31  0:01 Pascal Brückner
2008-05-31 10:28 Pascal Brückner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox