[SCSI] convert to the new PM framework

This patch (as1397b) converts the SCSI midlayer to use the new PM
callbacks (struct dev_pm_ops).  A new source file, scsi_pm.c, is
created to hold the new callback routines, and the existing
suspend/resume code is moved there.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 1c7ac49..2a3fca2 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -163,6 +163,7 @@
 scsi_mod-$(CONFIG_SYSCTL)	+= scsi_sysctl.o
 scsi_mod-$(CONFIG_SCSI_PROC_FS)	+= scsi_proc.o
 scsi_mod-y			+= scsi_trace.o
+scsi_mod-$(CONFIG_PM_OPS)	+= scsi_pm.o
 
 scsi_tgt-y			+= scsi_tgt_lib.o scsi_tgt_if.o
 
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
new file mode 100644
index 0000000..cd83758
--- /dev/null
+++ b/drivers/scsi/scsi_pm.c
@@ -0,0 +1,96 @@
+/*
+ *	scsi_pm.c	Copyright (C) 2010 Alan Stern
+ *
+ *	SCSI dynamic Power Management
+ *		Initial version: Alan Stern <stern@rowland.harvard.edu>
+ */
+
+#include <linux/pm_runtime.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_host.h>
+
+#include "scsi_priv.h"
+
+static int scsi_dev_type_suspend(struct device *dev, pm_message_t msg)
+{
+	struct device_driver *drv;
+	int err;
+
+	err = scsi_device_quiesce(to_scsi_device(dev));
+	if (err == 0) {
+		drv = dev->driver;
+		if (drv && drv->suspend)
+			err = drv->suspend(dev, msg);
+	}
+	dev_dbg(dev, "scsi suspend: %d\n", err);
+	return err;
+}
+
+static int scsi_dev_type_resume(struct device *dev)
+{
+	struct device_driver *drv;
+	int err = 0;
+
+	drv = dev->driver;
+	if (drv && drv->resume)
+		err = drv->resume(dev);
+	scsi_device_resume(to_scsi_device(dev));
+	dev_dbg(dev, "scsi resume: %d\n", err);
+	return err;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int scsi_bus_suspend_common(struct device *dev, pm_message_t msg)
+{
+	int err = 0;
+
+	if (scsi_is_sdev_device(dev))
+		err = scsi_dev_type_suspend(dev, msg);
+	return err;
+}
+
+static int scsi_bus_resume_common(struct device *dev)
+{
+	int err = 0;
+
+	if (scsi_is_sdev_device(dev))
+		err = scsi_dev_type_resume(dev);
+	return err;
+}
+
+static int scsi_bus_suspend(struct device *dev)
+{
+	return scsi_bus_suspend_common(dev, PMSG_SUSPEND);
+}
+
+static int scsi_bus_freeze(struct device *dev)
+{
+	return scsi_bus_suspend_common(dev, PMSG_FREEZE);
+}
+
+static int scsi_bus_poweroff(struct device *dev)
+{
+	return scsi_bus_suspend_common(dev, PMSG_HIBERNATE);
+}
+
+#else /* CONFIG_PM_SLEEP */
+
+#define scsi_bus_resume_common		NULL
+#define scsi_bus_suspend		NULL
+#define scsi_bus_freeze			NULL
+#define scsi_bus_poweroff		NULL
+
+#endif /* CONFIG_PM_SLEEP */
+
+const struct dev_pm_ops scsi_bus_pm_ops = {
+	.suspend =		scsi_bus_suspend,
+	.resume =		scsi_bus_resume_common,
+	.freeze =		scsi_bus_freeze,
+	.thaw =			scsi_bus_resume_common,
+	.poweroff =		scsi_bus_poweroff,
+	.restore =		scsi_bus_resume_common,
+};
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 1fbf7c7..dddacc7 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -144,6 +144,13 @@
 static inline void scsi_netlink_exit(void) {}
 #endif
 
+/* scsi_pm.c */
+#ifdef CONFIG_PM_OPS
+extern const struct dev_pm_ops scsi_bus_pm_ops;
+#else
+#define scsi_bus_pm_ops		(*NULL)
+#endif
+
 /* 
  * internal scsi timeout functions: for use by mid-layer and transport
  * classes.
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index c23ab97..5f85f8e 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -376,57 +376,11 @@
 	return 0;
 }
 
-static int scsi_bus_suspend(struct device * dev, pm_message_t state)
-{
-	struct device_driver *drv;
-	struct scsi_device *sdev;
-	int err;
-
-	if (dev->type != &scsi_dev_type)
-		return 0;
-
-	drv = dev->driver;
-	sdev = to_scsi_device(dev);
-
-	err = scsi_device_quiesce(sdev);
-	if (err)
-		return err;
-
-	if (drv && drv->suspend) {
-		err = drv->suspend(dev, state);
-		if (err)
-			return err;
-	}
-
-	return 0;
-}
-
-static int scsi_bus_resume(struct device * dev)
-{
-	struct device_driver *drv;
-	struct scsi_device *sdev;
-	int err = 0;
-
-	if (dev->type != &scsi_dev_type)
-		return 0;
-
-	drv = dev->driver;
-	sdev = to_scsi_device(dev);
-
-	if (drv && drv->resume)
-		err = drv->resume(dev);
-
-	scsi_device_resume(sdev);
-
-	return err;
-}
-
 struct bus_type scsi_bus_type = {
         .name		= "scsi",
         .match		= scsi_bus_match,
 	.uevent		= scsi_bus_uevent,
-	.suspend	= scsi_bus_suspend,
-	.resume		= scsi_bus_resume,
+	.pm		= &scsi_bus_pm_ops,
 };
 EXPORT_SYMBOL_GPL(scsi_bus_type);