On Mon, Sep 24, 2012 at 11:46:03PM +0200, Rafael J. Wysocki wrote:
> On Monday, September 24, 2012, Aaron Lu wrote:
> > On Mon, Sep 24, 2012 at 03:06:11PM +0200, Rafael J. Wysocki wrote:
> > > On Monday, September 24, 2012, Aaron Lu wrote:
> > > > need_eject:
> > > > First consider how the device will be runtime resumed:
> > > > 1 Some program opens the block device;
> > > > 2 Events checking poll when it's not powered off yet;
> > > > 3 User presses the eject button or inserts a disc into the slot when the
> > > >   device is in powered off state.
> > > > And the need_eject flag is for case 3, when the device is in powered off
> > > > state and user presses the eject button, it will be powered on(through
> > > > acpi wake notification function) and runtime resumed. In its runtime
> > > > resume callback, its tray needs to be ejected since user just presses
> > > > the eject button. The whole process of ZPODD is opaque to the user,
> > > > he/she doesn't know the ODD lost power so the ODD has to behave exactly
> > > > like it doesn't lose power.
> > > 
> > > Do you think it can be useful for other types of devices, not necessarily
> > > handled through ACPI?
> > 
> > I can only say that it is useful for ZPODD, if ZPODD someday is used on
> > another platform that does not use ACPI, the need_eject flag should
> > still be needed.
> > 
> > As for other scsi devices, I'm not sure.
> 
> I see.  This means we don't really have good arguments for putting that flag
> into struct scsi_device ...

OK.

I'm thinking of moving the acpi wake notification code from ata to scsi,
so that the notification function lives in sr module and then I do not
need to set this need_eject flag in scsi_device and scsi_cd structure
needs to host this flag.

A example patch would be something like the following, I didn't seperate
these ACPI calls in sr.c as this is just a concept proof, if this is the
right thing to do, I will separate them into another file sr-acpi.c and
make empty stubs for them in sr.h for systems do not have ACPI configured.


diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index ef72682..94d17f1 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -46,6 +46,7 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+#include <linux/acpi.h>
 #include <asm/uaccess.h>
 
 #include <scsi/scsi.h>
@@ -57,6 +58,8 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_ioctl.h>   /* For the door lock/unlock commands */
 
+#include <acpi/acpi_bus.h>
+
 #include "scsi_logging.h"
 #include "sr.h"
 
@@ -212,8 +220,8 @@ static int sr_resume(struct device *dev)
        scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr);
 
        /* If user wakes up the ODD, eject the tray */
-       if (cd->device->need_eject) {
-               cd->device->need_eject = 0;
+       if (cd->need_eject) {
+               cd->need_eject = false;
                /* But only for tray type ODD when door is not locked */
                if (!(cd->cdi.mask & CDC_CLOSE_TRAY) && !cd->door_locked)
                        sr_tray_move(&cd->cdi, 1);
@@ -704,6 +711,58 @@ static void sr_release(struct cdrom_device_info *cdi)
 
 }
 
+static void sr_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
+{
+       struct device *dev = context;
+       struct scsi_cd *cd = dev_get_drvdata(dev);
+
+       if (event == ACPI_NOTIFY_DEVICE_WAKE && pm_runtime_suspended(dev)) {
+               cd->need_eject = true;
+               pm_runtime_resume(dev);
+       }
+}
+
+static void sr_acpi_add_pm_notifier(struct device *dev)
+{
+       struct acpi_device *acpi_dev;
+       acpi_handle handle;
+       acpi_status status;
+
+       handle = dev->archdata.acpi_handle;
+       if (!handle)
+               return;
+
+       status = acpi_bus_get_device(handle, &acpi_dev);
+       if (ACPI_FAILURE(status))
+               return;
+
+       acpi_power_resource_register_device(dev, handle);
+       acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+                                       sr_acpi_wake_dev, dev);
+       device_set_run_wake(dev, true);
+}
+
+static void sr_acpi_remove_pm_notifier(struct device *dev)
+{
+       struct acpi_device *acpi_dev;
+       acpi_handle handle;
+       acpi_status status;
+
+       handle = dev->archdata.acpi_handle;
+       if (!handle)
+               return;
+
+       status = acpi_bus_get_device(handle, &acpi_dev);
+       if (ACPI_FAILURE(status))
+               return;
+
+       acpi_power_resource_unregister_device(dev, handle);
+       device_set_run_wake(dev, false);
+       acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 
sr_acpi_wake_dev);
+}
+
 static int sr_probe(struct device *dev)
 {
        struct scsi_device *sdev = to_scsi_device(dev);
@@ -786,7 +845,9 @@ static int sr_probe(struct device *dev)
        sdev_printk(KERN_DEBUG, sdev,
                    "Attached scsi CD-ROM %s\n", cd->cdi.name);
 
-       /* enable runtime pm */
+       if (sdev->can_power_off)
+               sr_acpi_add_pm_notifier(dev);
+
        scsi_autopm_put_device(cd->device);
 
        return 0;
@@ -1036,8 +1097,9 @@ static int sr_remove(struct device *dev)
 {
        struct scsi_cd *cd = dev_get_drvdata(dev);
 
-       /* disable runtime pm */
        scsi_autopm_get_device(cd->device);
+       if (cd->device->can_power_off)
+               sr_acpi_remove_pm_notifier(dev);
 
        blk_queue_prep_rq(cd->device->request_queue, scsi_prep_fn);
        del_gendisk(cd->disk);


Thanks,
Aaron

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to