public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] SCSI midlayer power management
@ 2004-08-10 23:58 Nathan Bryant
  2004-08-11  8:09 ` Pavel Machek
  0 siblings, 1 reply; 41+ messages in thread
From: Nathan Bryant @ 2004-08-10 23:58 UTC (permalink / raw)
  To: 'James Bottomley'
  Cc: Linux SCSI Reflector, Linux Kernel list, Pavel Machek, jgarzik

[-- Attachment #1: Type: text/plain, Size: 1389 bytes --]


[resend] oops, sorry, forgot to send the patch!

Hi,

This proposed patch implements enough power-management support within
the SCSI midlayer to get ACPI S3 working on my system. Changes as follows:

* Add generic_scsi_{suspend,resume} methods to scsi.c
* Add suspend and resume callbacks to the scsi_driver structure, and
implement those callbacks in sd.c
* In sd.c, we call sd_shutdown on suspend, in order to synchronize the
write-back cache.
* In sd.c, we call sd_rescan from sd_resume in order to ensure that
drives have spun up and avoid passing not ready errors back to the block
layer.
* In generic_scsi_suspend, we call scsi_device_quiesce before calling
the scsi_driver suspend callback. We resume from quiesce state in
reverse order in generic_scsi_resume.

ACPI S1 and S4/swsusp are untested, but I think there should be no
regressions with S1. To do S1 properly, we probably need to tell the
drive to spin down, and I don't know what the SCSI command is for
that... For S4, the call to scsi_device_quiesce might pose a problem for
the subsequent state dump to disk. But I'm not sure swsusp ever worked
for SCSI.

This might help SATA drives, too, but I seem to remember that the SATA
layer doesn't properly emulate the SYNCHRONIZE_CACHE command.

Comments, anybody? Can this be applied upstream? I think it's a step in
the right direction.

Applies to scsi-misc-2.6

Nathan


[-- Attachment #2: scsi-powermanage.patch --]
[-- Type: text/x-patch, Size: 3765 bytes --]

===== drivers/scsi/scsi.c 1.145 vs edited =====
--- 1.145/drivers/scsi/scsi.c	2004-06-19 10:38:34 -04:00
+++ edited/drivers/scsi/scsi.c	2004-08-10 19:31:45 -04:00
@@ -60,6 +60,7 @@
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_dbg.h>
 #include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
@@ -1175,6 +1176,40 @@
 #define register_scsi_cpu()
 #define unregister_scsi_cpu()
 #endif /* CONFIG_HOTPLUG_CPU */
+
+#ifdef CONFIG_PM
+int generic_scsi_suspend(struct device *dev, u32 state)
+{
+	int err;
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct scsi_driver *drv = to_scsi_driver(dev->driver);
+
+	err = scsi_device_quiesce(sdev);
+	if (err)
+		return err;
+
+	if (drv->suspend)
+		return drv->suspend(dev, state);
+
+	return 0;
+}
+
+int generic_scsi_resume(struct device *dev)
+{
+	int err;
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct scsi_driver *drv = to_scsi_driver(dev->driver);
+
+	if (drv->resume) {
+		err = drv->resume(dev);
+		if (err)
+			return err;
+	}
+
+	scsi_device_resume(sdev);
+	return 0;
+}
+#endif /*CONFIG_PM*/
 
 MODULE_DESCRIPTION("SCSI core");
 MODULE_LICENSE("GPL");
===== drivers/scsi/scsi_priv.h 1.33 vs edited =====
--- 1.33/drivers/scsi/scsi_priv.h	2004-06-16 11:45:44 -04:00
+++ edited/drivers/scsi/scsi_priv.h	2004-08-09 20:07:35 -04:00
@@ -92,6 +92,10 @@
 static inline void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
 	{ };
 #endif
+#ifdef CONFIG_PM
+extern int generic_scsi_suspend(struct device *dev, u32 state);
+extern int generic_scsi_resume(struct device *dev);
+#endif
 
 /* scsi_devinfo.c */
 extern int scsi_get_device_flags(struct scsi_device *sdev,
===== drivers/scsi/scsi_sysfs.c 1.52 vs edited =====
--- 1.52/drivers/scsi/scsi_sysfs.c	2004-07-28 23:59:10 -04:00
+++ edited/drivers/scsi/scsi_sysfs.c	2004-08-10 17:43:04 -04:00
@@ -187,8 +187,12 @@
 }
 
 struct bus_type scsi_bus_type = {
-        .name		= "scsi",
-        .match		= scsi_bus_match,
+	.name		= "scsi",
+	.match		= scsi_bus_match,
+#ifdef CONFIG_PM
+	.suspend	= generic_scsi_suspend,
+	.resume		= generic_scsi_resume,
+#endif
 };
 
 int scsi_sysfs_register(void)
===== drivers/scsi/sd.c 1.154 vs edited =====
--- 1.154/drivers/scsi/sd.c	2004-06-19 10:38:40 -04:00
+++ edited/drivers/scsi/sd.c	2004-08-10 19:33:15 -04:00
@@ -110,6 +110,10 @@
 
 static int sd_probe(struct device *);
 static int sd_remove(struct device *);
+#ifdef CONFIG_PM
+static int sd_suspend(struct device *, u32);
+static int sd_resume(struct device *);
+#endif
 static void sd_shutdown(struct device *dev);
 static void sd_rescan(struct device *);
 static int sd_init_command(struct scsi_cmnd *);
@@ -126,6 +130,10 @@
 	},
 	.rescan			= sd_rescan,
 	.init_command		= sd_init_command,
+#ifdef CONFIG_PM
+	.suspend		= sd_suspend,
+	.resume			= sd_resume,
+#endif
 };
 
 /* Device no to disk mapping:
@@ -1549,7 +1557,21 @@
 	
 	scsi_release_request(sreq);
 	printk("\n");
-}	
+}
+
+#ifdef CONFIG_PM
+static int sd_suspend(struct device *dev, u32 state)
+{
+	sd_shutdown(dev);
+	return 0;
+}
+
+static int sd_resume(struct device *dev)
+{
+	sd_rescan(dev);
+	return 0;
+}
+#endif /*CONFIG_PM*/
 
 /**
  *	init_sd - entry point for this driver (both when built in or when
===== include/scsi/scsi_driver.h 1.2 vs edited =====
--- 1.2/include/scsi/scsi_driver.h	2003-11-12 09:15:46 -05:00
+++ edited/include/scsi/scsi_driver.h	2004-08-10 18:02:45 -04:00
@@ -13,6 +13,10 @@
 
 	int (*init_command)(struct scsi_cmnd *);
 	void (*rescan)(struct device *);
+#ifdef CONFIG_PM
+	int (*suspend)(struct device *dev, u32 state);
+	int (*resume)(struct device *dev);
+#endif
 };
 #define to_scsi_driver(drv) \
 	container_of((drv), struct scsi_driver, gendrv)

^ permalink raw reply	[flat|nested] 41+ messages in thread
* RE: [PATCH] SCSI midlayer power management
@ 2004-08-16 13:29 James.Smart
  0 siblings, 0 replies; 41+ messages in thread
From: James.Smart @ 2004-08-16 13:29 UTC (permalink / raw)
  To: pavel, James.Bottomley; +Cc: benh, nbryant, linux-scsi, linux-kernel, jgarzik

Glad to see where this thread ended up...

Suspend, for scsi hosts, essentially has to end up being an unattach. You can't make assumptions on DMA use, etc based on just quiescing host i/o flow or no target for multi-initiators. There's too much variance in adapters design that depend on adapter-pull functionality - rings, ring pointers, host-based contexts, host-based firmware (scripts), and so on. There's also lots of potential asynchronous traffic that can occur outside of just host-requested io : for FC, there's ELS/BLS's; for iSCSI there's non-io PDU's (NOPs, AENs). Posted buffers to the adapter must be killed, and so on.  Ultimately, the scsi class drivers must quiesce the devices, then the LLDD's must "suspend", essentially saving software state and resetting hardware.

For Resume, given that the MMIO state isn't restored, and given the above argument of "detach" on suspend - the LLDD must essentially restart the hardware, reprogramming dma addresses, reposting buffers, reinstantiating contexts, etc.  As indicated, easier on some hardware, harder on others.

So, as Pavel indicates - powermanagement for the LLDD should look very similar to rmmod/insmod. The question usually comes down to whether the overhead of a suspend/resume, where the driver has to participate to save/restore software state, is worth the extra complexity vs. whether you are better off just having the LLDD fully detach/reattach. Latter usually wins as it supports hot-plug well, and moves the complexities out of each driver and into the infrastructure.

-- James S


> -----Original Message-----
> From: linux-scsi-owner@vger.kernel.org
> [mailto:linux-scsi-owner@vger.kernel.org]On Behalf Of Pavel Machek
> Sent: Thursday, August 12, 2004 4:49 PM
> To: James Bottomley
> Cc: Benjamin Herrenschmidt; Nathan Bryant; Linux SCSI Reflector; Linux
> Kernel list; Jeff Garzik
> Subject: Re: [PATCH] SCSI midlayer power management
> 
> 
> Hi!
> 
> > > Can't you simply reuse bootup code? It will no longer be __init,
> > > but it should make suspend/resume functions quite simple.
> > 
> > Unfortunately, no that simply.
> > 
> > Bootup is all about allocating these areas and initialising 
> the card. 
> > Resume will be about initialising the card knowing the 
> existing areas
> > (and the data about the existing areas will have to be part of our
> > persistent data on suspend).
> 
> You can simply free those areas during suspend, so that resume will be
> same as powerup....
> 
> Essentially if you can do insmod and rmmod, you can "simply" emulate
> rmmod during suspend and emulate "insmod" during resume...
> 
> > > > to pick three drivers to do this for, that would be 
> aic7xxx, aic79xx and
> > > > sym_2?
> > > 
> > > No idea, only SCSI host I owned was some 8-bit isa thing....
> > 
> > Well, someone who's interested needs to pick a driver.  It's usually
> > easier to persuade everyone to add the feature if there's 
> an example to
> > copy...
> 
> Make it aic7xxx then... Someone already worked on that one.
> 
> 								
> 	Pavel
> -- 
> People were complaining that M$ turns users into beta-testers...
> ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
> -
> To unsubscribe from this list: send the line "unsubscribe 
> linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 41+ messages in thread
* [PATCH] SCSI midlayer power management
@ 2004-08-10 23:56 Nathan Bryant
  2004-08-11  9:53 ` Alan Cox
  0 siblings, 1 reply; 41+ messages in thread
From: Nathan Bryant @ 2004-08-10 23:56 UTC (permalink / raw)
  To: 'James Bottomley'
  Cc: Linux SCSI Reflector, Linux Kernel list, Pavel Machek, jgarzik


Hi,

This proposed patch implements enough power-management support within 
the SCSI midlayer to get ACPI S3 working on my system. Changes as follows:

* Add generic_scsi_{suspend,resume} methods to scsi.c
* Add suspend and resume callbacks to the scsi_driver structure, and 
implement those callbacks in sd.c
* In sd.c, we call sd_shutdown on suspend, in order to synchronize the 
write-back cache.
* In sd.c, we call sd_rescan from sd_resume in order to ensure that 
drives have spun up and avoid passing not ready errors back to the block 
layer.
* In generic_scsi_suspend, we call scsi_device_quiesce before calling 
the scsi_driver suspend callback. We resume from quiesce state in 
reverse order in generic_scsi_resume.

ACPI S1 and S4/swsusp are untested, but I think there should be no 
regressions with S1. To do S1 properly, we probably need to tell the 
drive to spin down, and I don't know what the SCSI command is for 
that... For S4, the call to scsi_device_quiesce might pose a problem for 
the subsequent state dump to disk. But I'm not sure swsusp ever worked 
for SCSI.

This might help SATA drives, too, but I seem to remember that the SATA 
layer doesn't properly emulate the SYNCHRONIZE_CACHE command.

Comments, anybody? Can this be applied upstream? I think it's a step in 
the right direction.

Applies to scsi-misc-2.6

Nathan

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

end of thread, other threads:[~2004-08-16 13:31 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-08-10 23:58 [PATCH] SCSI midlayer power management Nathan Bryant
2004-08-11  8:09 ` Pavel Machek
2004-08-11 13:13   ` Nathan Bryant
2004-08-11 13:37     ` James Bottomley
2004-08-11 15:21       ` Alan Cox
2004-08-11 16:28         ` James Bottomley
2004-08-11 16:43           ` Nathan Bryant
2004-08-11 23:36       ` Benjamin Herrenschmidt
2004-08-12  7:45         ` Pavel Machek
2004-08-12 10:38           ` Benjamin Herrenschmidt
2004-08-12 12:48         ` James Bottomley
2004-08-12 13:14           ` Pavel Machek
2004-08-12 16:29             ` James Bottomley
2004-08-12 19:11               ` Pavel Machek
2004-08-12 19:34                 ` James Bottomley
2004-08-12 20:26                   ` Pavel Machek
2004-08-12 20:31                     ` James Bottomley
2004-08-12 20:37                       ` Pavel Machek
2004-08-12 20:42                         ` James Bottomley
2004-08-12 20:48                           ` Pavel Machek
2004-08-12 20:52                           ` Nathan Bryant
2004-08-12 20:40                       ` Nathan Bryant
2004-08-12 23:05                       ` Benjamin Herrenschmidt
2004-08-12 22:36                   ` Nigel Cunningham
2004-08-12 22:43                     ` Nigel Cunningham
2004-08-12 23:04                   ` Benjamin Herrenschmidt
2004-08-12 13:41           ` Nathan Bryant
2004-08-12 16:45             ` Patrick Mansfield
2004-08-12 23:02           ` Benjamin Herrenschmidt
2004-08-11 20:19     ` Pavel Machek
2004-08-11 20:50       ` Nathan Bryant
2004-08-11 22:16     ` Nigel Cunningham
2004-08-11 22:48       ` Nathan Bryant
2004-08-12  7:43         ` Pavel Machek
2004-08-12  9:39         ` Nigel Cunningham
2004-08-12 13:43           ` Nathan Bryant
  -- strict thread matches above, loose matches on Subject: below --
2004-08-16 13:29 James.Smart
2004-08-10 23:56 Nathan Bryant
2004-08-11  9:53 ` Alan Cox
2004-08-11 12:55   ` Nathan Bryant
2004-08-11 13:39   ` James Bottomley

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