linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Adaptec driver suspend bug ahc_dv_0
@ 2004-12-17 16:03 Steven Newbury
  2004-12-17 16:11 ` Nathan Bryant
  2004-12-18  0:05 ` Nathan Bryant
  0 siblings, 2 replies; 3+ messages in thread
From: Steven Newbury @ 2004-12-17 16:03 UTC (permalink / raw)
  To: linux-kernel

(Using current bk linus kernel 20041216)
When attempting to use ACPI sleep states on this system, one of the Adaptec
driver kernel threads fails to stop:

Dec 17 00:32:47 comet kernel:  stopping tasks failed (1 tasks remaining)
Dec 17 00:32:47 comet kernel: Restarting tasks...<6> Strange, ahc_dv_0 not stop

The ahc_dv_0 thread then spins using 100% CPU in System until the computer is
rebooted.

lspci output:

00:00.0 Host bridge: VIA Technologies, Inc. VT82C693A/694x [Apollo PRO133x]
(rev 44)
00:01.0 PCI bridge: VIA Technologies, Inc. VT82C598/694x [Apollo MVP3/Pro133x
AGP]
00:07.0 ISA bridge: VIA Technologies, Inc. VT82C596 ISA [Mobile South] (rev 12)
00:07.1 IDE interface: VIA Technologies, Inc.
VT82C586A/B/VT82C686/A/B/VT823x/A/C PIPC Bus Master IDE (rev 06)
00:07.2 USB Controller: VIA Technologies, Inc. VT82xxxxx UHCI USB 1.1
Controller (rev 08)
00:07.3 Host bridge: VIA Technologies, Inc. VT82C596 Power Management (rev 20)
00:08.0 SCSI storage controller: Adaptec AIC-7892A U160/m (rev 02)
00:09.0 Ethernet controller: Accton Technology Corporation EN-1216 Ethernet
Adapter (rev 11)
00:0b.0 Multimedia audio controller: ESS Technology ES1969 Solo-1 Audiodrive
(rev 01)
01:00.0 VGA compatible controller: Matrox Graphics, Inc. MGA G400 AGP (rev 04)


=====
Steve


	
	
		
___________________________________________________________ 
ALL-NEW Yahoo! Messenger - all new features - even more fun! http://uk.messenger.yahoo.com

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

* Re: Adaptec driver suspend bug ahc_dv_0
  2004-12-17 16:03 Adaptec driver suspend bug ahc_dv_0 Steven Newbury
@ 2004-12-17 16:11 ` Nathan Bryant
  2004-12-18  0:05 ` Nathan Bryant
  1 sibling, 0 replies; 3+ messages in thread
From: Nathan Bryant @ 2004-12-17 16:11 UTC (permalink / raw)
  To: Steven Newbury; +Cc: linux-kernel


The driver has never supported suspend, unfortunately, but I have a 
messy-but-mostly-correct patch for this that I can send you later.

Steven Newbury wrote:

>(Using current bk linus kernel 20041216)
>When attempting to use ACPI sleep states on this system, one of the Adaptec
>driver kernel threads fails to stop:
>
>Dec 17 00:32:47 comet kernel:  stopping tasks failed (1 tasks remaining)
>Dec 17 00:32:47 comet kernel: Restarting tasks...<6> Strange, ahc_dv_0 not stop
>
>The ahc_dv_0 thread then spins using 100% CPU in System until the computer is
>rebooted.
>
>lspci output:
>
>00:00.0 Host bridge: VIA Technologies, Inc. VT82C693A/694x [Apollo PRO133x]
>(rev 44)
>00:01.0 PCI bridge: VIA Technologies, Inc. VT82C598/694x [Apollo MVP3/Pro133x
>AGP]
>00:07.0 ISA bridge: VIA Technologies, Inc. VT82C596 ISA [Mobile South] (rev 12)
>00:07.1 IDE interface: VIA Technologies, Inc.
>VT82C586A/B/VT82C686/A/B/VT823x/A/C PIPC Bus Master IDE (rev 06)
>00:07.2 USB Controller: VIA Technologies, Inc. VT82xxxxx UHCI USB 1.1
>Controller (rev 08)
>00:07.3 Host bridge: VIA Technologies, Inc. VT82C596 Power Management (rev 20)
>00:08.0 SCSI storage controller: Adaptec AIC-7892A U160/m (rev 02)
>00:09.0 Ethernet controller: Accton Technology Corporation EN-1216 Ethernet
>Adapter (rev 11)
>00:0b.0 Multimedia audio controller: ESS Technology ES1969 Solo-1 Audiodrive
>(rev 01)
>01:00.0 VGA compatible controller: Matrox Graphics, Inc. MGA G400 AGP (rev 04)
>
>
>=====
>Steve
>
>
>	
>	
>		
>___________________________________________________________ 
>ALL-NEW Yahoo! Messenger - all new features - even more fun! http://uk.messenger.yahoo.com
>-
>To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
>Please read the FAQ at  http://www.tux.org/lkml/
>
>  
>


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

* Re: Adaptec driver suspend bug ahc_dv_0
  2004-12-17 16:03 Adaptec driver suspend bug ahc_dv_0 Steven Newbury
  2004-12-17 16:11 ` Nathan Bryant
@ 2004-12-18  0:05 ` Nathan Bryant
  1 sibling, 0 replies; 3+ messages in thread
From: Nathan Bryant @ 2004-12-18  0:05 UTC (permalink / raw)
  To: Steven Newbury; +Cc: linux-kernel

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

Steven Newbury wrote:

>(Using current bk linus kernel 20041216)
>When attempting to use ACPI sleep states on this system, one of the Adaptec
>driver kernel threads fails to stop:
>  
>
You can try the attached patch; it is all of the current power 
management fixes that are in my local tree. (Most is my own work, one is 
Shaohua's.) If you are using the -mm tree, you will want to remove the 
3c59x patch before applying this, because that is already in -mm.

These patches are believed to be OK for everything except SCSI removable 
disks that use the sd driver, which need better spinup and media change 
handling.

Nathan

[-- Attachment #2: 2.6.10-rc3-20041017.bigdiff --]
[-- Type: text/plain, Size: 30457 bytes --]

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/12/17 18:33:47-05:00 nbryant@optonline.net 
#   Merge
# 
# drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
#   2004/12/17 18:33:45-05:00 nbryant@optonline.net +0 -0
#   SCCS merged
# 
# drivers/scsi/aic7xxx/aic7xxx_osm.h
#   2004/12/17 18:33:45-05:00 nbryant@optonline.net +0 -0
#   SCCS merged
# 
# ChangeSet
#   2004/12/17 18:28:55-05:00 nbryant@optonline.net 
#   update for new pci_save_state api
# 
# drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
#   2004/12/17 18:28:45-05:00 nbryant@optonline.net +2 -2
#   update for new pci_save_state api
# 
# drivers/scsi/aic7xxx/aic7xxx.h
#   2004/12/17 18:28:45-05:00 nbryant@optonline.net +0 -2
#   update for new pci_save_state api
# 
# ChangeSet
#   2004/12/02 21:47:43-05:00 nbryant@optonline.net 
#   sync up
# 
# drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
#   2004/12/02 21:47:33-05:00 nbryant@optonline.net +1 -1
#   hand merge
# 
# drivers/net/3c59x.c
#   2004/12/02 21:47:33-05:00 nbryant@optonline.net +1 -1
#   hand merge
# 
# drivers/scsi/aic7xxx/aic7xxx_pci.c
#   2004/12/01 21:52:26-05:00 nbryant@optonline.net +0 -0
#   Auto merged
# 
# drivers/scsi/aic7xxx/aic7xxx_osm.h
#   2004/12/01 21:52:26-05:00 nbryant@optonline.net +0 -0
#   Auto merged
# 
# drivers/scsi/aic7xxx/aic7xxx_osm.c
#   2004/12/01 21:52:26-05:00 nbryant@optonline.net +0 -0
#   Auto merged
# 
# drivers/scsi/sd.c
#   2004/12/01 21:52:25-05:00 nbryant@optonline.net +0 -0
#   Auto merged
# 
# drivers/scsi/scsi_sysfs.c
#   2004/12/01 21:52:25-05:00 nbryant@optonline.net +0 -0
#   Auto merged
# 
# drivers/scsi/scsi_priv.h
#   2004/12/01 21:52:25-05:00 nbryant@optonline.net +0 -0
#   Auto merged
# 
# drivers/scsi/scsi.c
#   2004/12/01 21:52:25-05:00 nbryant@optonline.net +0 -0
#   Auto merged
# 
# drivers/scsi/aic7xxx/aic7xxx_core.c
#   2004/12/01 21:52:25-05:00 nbryant@optonline.net +0 -0
#   Auto merged
# 
# drivers/scsi/aic7xxx/aic7xxx.h
#   2004/12/01 21:52:25-05:00 nbryant@optonline.net +0 -0
#   Auto merged
# 
# drivers/scsi/aic7xxx/aic79xx_osm.c
#   2004/12/01 21:52:25-05:00 nbryant@optonline.net +0 -0
#   Auto merged
# 
# drivers/acpi/sleep/main.c
#   2004/12/01 21:52:24-05:00 nbryant@optonline.net +0 -0
#   Auto merged
# 
# drivers/acpi/bus.c
#   2004/12/01 21:52:24-05:00 nbryant@optonline.net +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/20 17:08:12-05:00 nbryant@optonline.net 
#   aic7xxx_acpi.patch7
# 
# drivers/scsi/aic7xxx/aic7xxx_pci.c
#   2004/07/22 20:45:33-04:00 nbryant@optonline.net +181 -173
#   Import patch aic7xxx_acpi.patch7
# 
# drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
#   2004/07/24 10:28:24-04:00 nbryant@optonline.net +58 -1
#   Import patch aic7xxx_acpi.patch7
# 
# drivers/scsi/aic7xxx/aic7xxx_osm.h
#   2004/07/24 10:01:00-04:00 nbryant@optonline.net +1 -0
#   Import patch aic7xxx_acpi.patch7
# 
# drivers/scsi/aic7xxx/aic7xxx_osm.c
#   2004/07/24 09:59:01-04:00 nbryant@optonline.net +1 -2
#   Import patch aic7xxx_acpi.patch7
# 
# drivers/scsi/aic7xxx/aic7xxx_core.c
#   2004/07/24 09:39:45-04:00 nbryant@optonline.net +1 -0
#   Import patch aic7xxx_acpi.patch7
# 
# drivers/scsi/aic7xxx/aic7xxx.h
#   2004/07/21 22:42:46-04:00 nbryant@optonline.net +3 -1
#   Import patch aic7xxx_acpi.patch7
# 
# drivers/scsi/aic7xxx/aic79xx_osm.c
#   2004/07/21 18:30:06-04:00 nbryant@optonline.net +1 -1
#   Import patch aic7xxx_acpi.patch7
# 
# ChangeSet
#   2004/11/20 17:07:48-05:00 nbryant@optonline.net 
#   scsi-powermanage-2.6.9.patch
# 
# include/scsi/scsi_driver.h
#   2004/11/20 16:49:28-05:00 nbryant@optonline.net +4 -0
#   Import patch scsi-powermanage-2.6.9.patch
# 
# drivers/scsi/sd.c
#   2004/11/20 16:49:28-05:00 nbryant@optonline.net +23 -1
#   Import patch scsi-powermanage-2.6.9.patch
# 
# drivers/scsi/scsi_sysfs.c
#   2004/11/20 16:49:28-05:00 nbryant@optonline.net +6 -2
#   Import patch scsi-powermanage-2.6.9.patch
# 
# drivers/scsi/scsi_priv.h
#   2004/11/20 16:49:28-05:00 nbryant@optonline.net +4 -0
#   Import patch scsi-powermanage-2.6.9.patch
# 
# drivers/scsi/scsi.c
#   2004/11/20 16:49:28-05:00 nbryant@optonline.net +35 -0
#   Import patch scsi-powermanage-2.6.9.patch
# 
# ChangeSet
#   2004/11/20 17:05:53-05:00 nbryant@optonline.net 
#   maskevent.patch3
# 
# drivers/acpi/sleep/main.c
#   2004/08/12 20:49:37-04:00 nbryant@optonline.net +3 -1
#   Import patch maskevent.patch3
# 
# drivers/acpi/event.c
#   2004/08/12 20:49:37-04:00 nbryant@optonline.net +2 -1
#   Import patch maskevent.patch3
# 
# drivers/acpi/bus.c
#   2004/08/12 20:49:37-04:00 nbryant@optonline.net +2 -1
#   Import patch maskevent.patch3
# 
# ChangeSet
#   2004/11/20 16:35:11-05:00 nbryant@optonline.net 
#   3c59x-powermanage.patch
# 
# drivers/net/3c59x.c
#   2004/08/11 22:32:58-04:00 nbryant@optonline.net +14 -11
#   Import patch 3c59x-powermanage.patch
# 
diff -Nru a/drivers/acpi/bus.c b/drivers/acpi/bus.c
--- a/drivers/acpi/bus.c	2004-12-17 19:00:30 -05:00
+++ b/drivers/acpi/bus.c	2004-12-17 19:00:30 -05:00
@@ -291,6 +291,7 @@
 DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);
 
 extern int			event_is_open;
+extern int			acpi_event_is_masked;
 
 int
 acpi_bus_generate_event (
@@ -307,7 +308,7 @@
 		return_VALUE(-EINVAL);
 
 	/* drop event on the floor if no one's listening */
-	if (!event_is_open)
+	if (!event_is_open || acpi_event_is_masked)
 		return_VALUE(0);
 
 	event = kmalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
diff -Nru a/drivers/acpi/event.c b/drivers/acpi/event.c
--- a/drivers/acpi/event.c	2004-12-17 19:00:30 -05:00
+++ b/drivers/acpi/event.c	2004-12-17 19:00:30 -05:00
@@ -17,7 +17,8 @@
 
 /* Global vars for handling event proc entry */
 static spinlock_t		acpi_system_event_lock = SPIN_LOCK_UNLOCKED;
-int				event_is_open = 0;
+int				event_is_open;
+int				acpi_event_is_masked;
 extern struct list_head		acpi_bus_event_list;
 extern wait_queue_head_t	acpi_bus_event_queue;
 
diff -Nru a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
--- a/drivers/acpi/sleep/main.c	2004-12-17 19:00:30 -05:00
+++ b/drivers/acpi/sleep/main.c	2004-12-17 19:00:30 -05:00
@@ -76,7 +76,7 @@
  *	arch-specific assembly, which in turn call acpi_enter_sleep_state().
  *	It's unfortunate, but it works. Please fix if you're feeling frisky.
  */
-
+extern int acpi_event_is_masked;
 static int acpi_pm_enter(suspend_state_t pm_state)
 {
 	acpi_status status = AE_OK;
@@ -95,6 +95,7 @@
 
 	local_irq_save(flags);
 	acpi_enable_wakeup_device(acpi_state);
+	acpi_event_is_masked = 1;
 	switch (pm_state)
 	{
 	case PM_SUSPEND_STANDBY:
@@ -145,6 +146,7 @@
 
 	acpi_leave_sleep_state(acpi_state);
 	acpi_disable_wakeup_device(acpi_state);
+	acpi_event_is_masked = 0;
 
 	/* reset firmware waking vector */
 	acpi_set_firmware_waking_vector((acpi_physical_address) 0);
diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c
--- a/drivers/net/3c59x.c	2004-12-17 19:00:30 -05:00
+++ b/drivers/net/3c59x.c	2004-12-17 19:00:30 -05:00
@@ -1491,7 +1491,7 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = poll_vortex; 
 #endif
-	if (pdev && vp->enable_wol) {
+	if (pdev) {
 		vp->pm_state_valid = 1;
  		pci_save_state(VORTEX_PCI(vp));
  		acpi_set_WOL(dev);
@@ -1548,9 +1548,10 @@
 	unsigned int config;
 	int i;
 
-	if (VORTEX_PCI(vp) && vp->enable_wol) {
+	if (VORTEX_PCI(vp)) {
 		pci_set_power_state(VORTEX_PCI(vp), 0);	/* Go active */
 		pci_restore_state(VORTEX_PCI(vp));
+		pci_enable_device(VORTEX_PCI(vp));
 	}
 
 	/* Before initializing select the active media port. */
@@ -2706,7 +2707,7 @@
 	if (vp->full_bus_master_tx)
 		outl(0, ioaddr + DownListPtr);
 
-	if (final_down && VORTEX_PCI(vp) && vp->enable_wol) {
+	if (final_down && VORTEX_PCI(vp)) {
 		pci_save_state(VORTEX_PCI(vp));
 		acpi_set_WOL(dev);
 	}
@@ -3131,15 +3132,17 @@
 	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
-	/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
-	EL3WINDOW(7);
-	outw(2, ioaddr + 0x0c);
-	/* The RxFilter must accept the WOL frames. */
-	outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
-	outw(RxEnable, ioaddr + EL3_CMD);
+	if (vp->enable_wol) {
+		/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
+		EL3WINDOW(7);
+		outw(2, ioaddr + 0x0c);
+		/* The RxFilter must accept the WOL frames. */
+		outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
+		outw(RxEnable, ioaddr + EL3_CMD);
 
+		pci_enable_wake(VORTEX_PCI(vp), 0, 1);
+	}
 	/* Change the power state to D3; RxEnable doesn't take effect. */
-	pci_enable_wake(VORTEX_PCI(vp), 0, 1);
 	pci_set_power_state(VORTEX_PCI(vp), 3);
 }
 
@@ -3162,7 +3165,7 @@
 	 */
 	unregister_netdev(dev);
 
-	if (VORTEX_PCI(vp) && vp->enable_wol) {
+	if (VORTEX_PCI(vp)) {
 		pci_set_power_state(VORTEX_PCI(vp), 0);	/* Go active */
 		if (vp->pm_state_valid)
 			pci_restore_state(VORTEX_PCI(vp));
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c	2004-12-17 19:00:30 -05:00
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c	2004-12-17 19:00:30 -05:00
@@ -2526,7 +2526,7 @@
 	sprintf(current->comm, "ahd_dv_%d", ahd->unit);
 #else
 	daemonize("ahd_dv_%d", ahd->unit);
-	current->flags |= PF_FREEZE;
+	current->flags |= PF_NOFREEZE;
 #endif
 	unlock_kernel();
 
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
--- a/drivers/scsi/aic7xxx/aic7xxx.h	2004-12-17 19:00:30 -05:00
+++ b/drivers/scsi/aic7xxx/aic7xxx.h	2004-12-17 19:00:30 -05:00
@@ -1169,7 +1169,7 @@
 /***************************** PCI Front End *********************************/
 struct ahc_pci_identity	*ahc_find_pci_device(ahc_dev_softc_t);
 int			 ahc_pci_config(struct ahc_softc *,
-					struct ahc_pci_identity *);
+					struct ahc_pci_identity *, int resume);
 int			 ahc_pci_test_register_access(struct ahc_softc *);
 
 /*************************** EISA/VL Front End ********************************/
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c	2004-12-17 19:00:30 -05:00
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c	2004-12-17 19:00:30 -05:00
@@ -4045,6 +4045,7 @@
 
 	ahc = (struct ahc_softc *)arg;
 
+	ahc_intr_enable(ahc, FALSE);
 	/* This will reset most registers to 0, but not all */
 	ahc_reset(ahc, /*reinit*/FALSE);
 	ahc_outb(ahc, SCSISEQ, 0);
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c	2004-12-17 19:00:30 -05:00
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c	2004-12-17 19:00:30 -05:00
@@ -479,7 +479,6 @@
 static void ahc_linux_release_simq(u_long arg);
 static void ahc_linux_dev_timed_unfreeze(u_long arg);
 static int  ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
-static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
 static void ahc_linux_size_nseg(void);
 static void ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc);
 static void ahc_linux_start_dv(struct ahc_softc *ahc);
@@ -2224,7 +2223,7 @@
 	sprintf(current->comm, "ahc_dv_%d", ahc->unit);
 #else
 	daemonize("ahc_dv_%d", ahc->unit);
-	current->flags |= PF_FREEZE;
+	current->flags |= PF_NOFREEZE;
 #endif
 	unlock_kernel();
 
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h	2004-12-17 19:00:30 -05:00
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h	2004-12-17 19:00:30 -05:00
@@ -638,6 +638,7 @@
 					Scsi_Host_Template *);
 
 uint64_t	ahc_linux_get_memsize(void);
+void		ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
 
 /*************************** Pretty Printing **********************************/
 struct info_str {
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c	2004-12-17 19:00:30 -05:00
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c	2004-12-17 19:00:30 -05:00
@@ -55,6 +55,10 @@
 static int	ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
 						 u_long *bus_addr,
 						 uint8_t __iomem **maddr);
+#ifdef CONFIG_PM
+static int	ahc_linux_pci_suspend(struct pci_dev *dev, u32 state);
+static int	ahc_linux_pci_resume(struct pci_dev *dev);
+#endif
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 static void	ahc_linux_pci_dev_remove(struct pci_dev *pdev);
 
@@ -141,6 +145,10 @@
 	.name		= "aic7xxx",
 	.probe		= ahc_linux_pci_dev_probe,
 	.remove		= ahc_linux_pci_dev_remove,
+#ifdef CONFIG_PM
+	.suspend	= ahc_linux_pci_suspend,
+	.resume		= ahc_linux_pci_resume,
+#endif
 	.id_table	= ahc_linux_pci_id_table
 };
 
@@ -240,7 +248,7 @@
 	}
 #endif
 	ahc->dev_softc = pci;
-	error = ahc_pci_config(ahc, entry);
+	error = ahc_pci_config(ahc, entry, /*resume*/FALSE);
 	if (error != 0) {
 		ahc_free(ahc);
 		return (-error);
@@ -290,6 +298,55 @@
 	return (found);
 #endif
 }
+
+#ifdef CONFIG_PM
+int ahc_linux_pci_suspend(struct pci_dev *dev, u32 state)
+{
+	int rval;
+	u32 device_state;
+	struct ahc_softc *ahc =
+		ahc_find_softc((struct ahc_softc *)pci_get_drvdata(dev));
+
+        switch(state)
+        {
+		case PM_SUSPEND_ON:
+			device_state = 0;
+			break;
+		case PM_SUSPEND_STANDBY:
+		case PM_SUSPEND_MEM:
+		case PM_SUSPEND_DISK:
+		case PM_SUSPEND_MAX:
+                default:
+			device_state = 3;
+                        break;
+        }
+
+	rval = ahc->bus_suspend(ahc);
+	if (rval != 0)
+		return rval;
+
+	pci_save_state(dev);
+	pci_disable_device(dev);
+	pci_set_power_state(dev, device_state);
+	return 0;
+	/*return -EAGAIN;*/
+}
+
+int ahc_linux_pci_resume(struct pci_dev *dev)
+{
+	int rval;
+	struct ahc_softc *ahc =
+		ahc_find_softc((struct ahc_softc *)pci_get_drvdata(dev));
+
+        pci_set_power_state(dev, AHC_POWER_STATE_D0);
+        pci_restore_state(dev);
+        pci_enable_device(dev);
+
+	rval = ahc->bus_resume(ahc);
+	ahc_linux_initialize_scsi_bus(ahc);
+	return rval;
+}
+#endif /* CONFIG_PM */
 
 void
 ahc_linux_pci_exit(void)
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c	2004-12-17 19:00:30 -05:00
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c	2004-12-17 19:00:30 -05:00
@@ -702,7 +702,7 @@
 }
 
 int
-ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
+ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry, int resume)
 {
 	u_long	 l;
 	u_int	 command;
@@ -715,60 +715,62 @@
 	uint8_t	 sblkctl;
 
 	our_id = 0;
-	error = entry->setup(ahc);
-	if (error != 0)
-		return (error);
-	ahc->chip |= AHC_PCI;
-	ahc->description = entry->name;
-
-	ahc_power_state_change(ahc, AHC_POWER_STATE_D0);
-
-	error = ahc_pci_map_registers(ahc);
-	if (error != 0)
-		return (error);
-
-	/*
-	 * Before we continue probing the card, ensure that
-	 * its interrupts are *disabled*.  We don't want
-	 * a misstep to hang the machine in an interrupt
-	 * storm.
-	 */
-	ahc_intr_enable(ahc, FALSE);
-
-	devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
-
-	/*
-	 * If we need to support high memory, enable dual
-	 * address cycles.  This bit must be set to enable
-	 * high address bit generation even if we are on a
-	 * 64bit bus (PCI64BIT set in devconfig).
-	 */
-	if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+	if (!resume) {
+		error = entry->setup(ahc);
+		if (error != 0)
+			return (error);
+		
+		ahc->chip |= AHC_PCI;
+		ahc->description = entry->name;
+		
+		ahc_power_state_change(ahc, AHC_POWER_STATE_D0);
+		
+		error = ahc_pci_map_registers(ahc);
+		if (error != 0)
+			return (error);
+		
+		/*
+		 * Before we continue probing the card, ensure that
+		 * its interrupts are *disabled*.  We don't want
+		 * a misstep to hang the machine in an interrupt
+		 * storm.
+		 */
+		ahc_intr_enable(ahc, FALSE);
 
-		if (bootverbose)
-			printf("%s: Enabling 39Bit Addressing\n",
-			       ahc_name(ahc));
-		devconfig |= DACEN;
-	}
+		devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
+		
+		/*
+		 * If we need to support high memory, enable dual
+		 * address cycles.  This bit must be set to enable
+		 * high address bit generation even if we are on a
+		 * 64bit bus (PCI64BIT set in devconfig).
+		 */
+		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+			
+			if (bootverbose)
+				printf("%s: Enabling 39Bit Addressing\n",
+				       ahc_name(ahc));
+			devconfig |= DACEN;
+		}
 	
-	/* Ensure that pci error generation, a test feature, is disabled. */
-	devconfig |= PCIERRGENDIS;
-
-	ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
-
-	/* Ensure busmastering is enabled */
-	command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2);
-	command |= PCIM_CMD_BUSMASTEREN;
-
-	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/2);
-
-	/* On all PCI adapters, we allow SCB paging */
-	ahc->flags |= AHC_PAGESCBS;
-
-	error = ahc_softc_init(ahc);
-	if (error != 0)
-		return (error);
-
+		/* Ensure that pci error generation, a test feature, is disabled. */
+		devconfig |= PCIERRGENDIS;
+		
+		ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
+		
+		/* Ensure busmastering is enabled */
+		command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2);
+		command |= PCIM_CMD_BUSMASTEREN;
+		
+		ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/2);
+		
+		/* On all PCI adapters, we allow SCB paging */
+		ahc->flags |= AHC_PAGESCBS;
+		
+		error = ahc_softc_init(ahc);
+		if (error != 0)
+			return (error);
+	}
 	/*
 	 * Disable PCI parity error checking.  Users typically
 	 * do this to work around broken PCI chipsets that get
@@ -780,30 +782,32 @@
 	if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0)
 		ahc->seqctl |= FAILDIS;
 
-	ahc->bus_intr = ahc_pci_intr;
-	ahc->bus_chip_init = ahc_pci_chip_init;
-	ahc->bus_suspend = ahc_pci_suspend;
-	ahc->bus_resume = ahc_pci_resume;
-
-	/* Remeber how the card was setup in case there is no SEEPROM */
-	if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
-		ahc_pause(ahc);
-		if ((ahc->features & AHC_ULTRA2) != 0)
-			our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;
-		else
-			our_id = ahc_inb(ahc, SCSIID) & OID;
-		sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN;
-		scsiseq = ahc_inb(ahc, SCSISEQ);
-	} else {
-		sxfrctl1 = STPWEN;
-		our_id = 7;
-		scsiseq = 0;
+	if (!resume) {
+		ahc->bus_intr = ahc_pci_intr;
+		ahc->bus_chip_init = ahc_pci_chip_init;
+		ahc->bus_suspend = ahc_pci_suspend;
+		ahc->bus_resume = ahc_pci_resume;
+
+		/* Remeber how the card was setup in case there is no SEEPROM */
+		if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
+			ahc_pause(ahc);
+			if ((ahc->features & AHC_ULTRA2) != 0)
+				our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;
+			else
+				our_id = ahc_inb(ahc, SCSIID) & OID;
+			sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN;
+			scsiseq = ahc_inb(ahc, SCSISEQ);
+		} else {
+			sxfrctl1 = STPWEN;
+			our_id = 7;
+			scsiseq = 0;
+		}
+		
+		error = ahc_reset(ahc, /*reinit*/FALSE);
+		if (error != 0)
+			return (ENXIO);
 	}
 
-	error = ahc_reset(ahc, /*reinit*/FALSE);
-	if (error != 0)
-		return (ENXIO);
-
 	if ((ahc->features & AHC_DT) != 0) {
 		u_int sfunct;
 
@@ -842,30 +846,32 @@
 
 	ahc_outb(ahc, DSCOMMAND0, dscommand0);
 
-	ahc->pci_cachesize =
-	    ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME,
-				/*bytes*/1) & CACHESIZE;
-	ahc->pci_cachesize *= 4;
-
-	if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0
-	 && ahc->pci_cachesize == 4) {
-
-		ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME,
-				     0, /*bytes*/1);
-		ahc->pci_cachesize = 0;
-	}
-
-	/*
-	 * We cannot perform ULTRA speeds without the presense
-	 * of the external precision resistor.
-	 */
-	if ((ahc->features & AHC_ULTRA) != 0) {
-		uint32_t devconfig;
+	if (!resume) {
+		ahc->pci_cachesize =
+			ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME,
+					    /*bytes*/1) & CACHESIZE;
+		ahc->pci_cachesize *= 4;
+
+		if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0
+		    && ahc->pci_cachesize == 4) {
+			
+			ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME,
+					     0, /*bytes*/1);
+			ahc->pci_cachesize = 0;
+		}
 
-		devconfig = ahc_pci_read_config(ahc->dev_softc,
-						DEVCONFIG, /*bytes*/4);
-		if ((devconfig & REXTVALID) == 0)
-			ahc->features &= ~AHC_ULTRA;
+		/*
+		 * We cannot perform ULTRA speeds without the presense
+		 * of the external precision resistor.
+		 */
+		if ((ahc->features & AHC_ULTRA) != 0) {
+			uint32_t devconfig;
+			
+			devconfig = ahc_pci_read_config(ahc->dev_softc,
+							DEVCONFIG, /*bytes*/4);
+			if ((devconfig & REXTVALID) == 0)
+				ahc->features &= ~AHC_ULTRA;
+		}
 	}
 
 	/* See if we have a SEEPROM and perform auto-term */
@@ -883,30 +889,32 @@
 		ahc_outb(ahc, DSPCISTATUS, DFTHRSH_100);
 	}
 
-	if (ahc->flags & AHC_USEDEFAULTS) {
-		/*
-		 * PCI Adapter default setup
-		 * Should only be used if the adapter does not have
-		 * a SEEPROM.
-		 */
-		/* See if someone else set us up already */
-		if ((ahc->flags & AHC_NO_BIOS_INIT) == 0
-		 && scsiseq != 0) {
-			printf("%s: Using left over BIOS settings\n",
-				ahc_name(ahc));
-			ahc->flags &= ~AHC_USEDEFAULTS;
-			ahc->flags |= AHC_BIOS_ENABLED;
-		} else {
+	if (!resume) {
+		if (ahc->flags & AHC_USEDEFAULTS) {
 			/*
-			 * Assume only one connector and always turn
-			 * on termination.
+			 * PCI Adapter default setup
+			 * Should only be used if the adapter does not have
+			 * a SEEPROM.
 			 */
- 			our_id = 0x07;
-			sxfrctl1 = STPWEN;
+			/* See if someone else set us up already */
+			if ((ahc->flags & AHC_NO_BIOS_INIT) == 0
+			    && scsiseq != 0) {
+				printf("%s: Using left over BIOS settings\n",
+				       ahc_name(ahc));
+				ahc->flags &= ~AHC_USEDEFAULTS;
+				ahc->flags |= AHC_BIOS_ENABLED;
+			} else {
+				/*
+				 * Assume only one connector and always turn
+				 * on termination.
+				 */
+				our_id = 0x07;
+				sxfrctl1 = STPWEN;
+			}
+			ahc_outb(ahc, SCSICONF, our_id|ENSPCHK|RESET_SCSI);
+			
+			ahc->our_id = our_id;
 		}
-		ahc_outb(ahc, SCSICONF, our_id|ENSPCHK|RESET_SCSI);
-
-		ahc->our_id = our_id;
 	}
 
 	/*
@@ -923,53 +931,55 @@
 	if ((sxfrctl1 & STPWEN) != 0)
 		ahc->flags |= AHC_TERM_ENB_A;
 
-	/*
-	 * Save chip register configuration data for chip resets
-	 * that occur during runtime and resume events.
-	 */
-	ahc->bus_softc.pci_softc.devconfig =
-	    ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
-	ahc->bus_softc.pci_softc.command =
-	    ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
-	ahc->bus_softc.pci_softc.csize_lattime =
-	    ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1);
-	ahc->bus_softc.pci_softc.dscommand0 = ahc_inb(ahc, DSCOMMAND0);
-	ahc->bus_softc.pci_softc.dspcistatus = ahc_inb(ahc, DSPCISTATUS);
-	if ((ahc->features & AHC_DT) != 0) {
-		u_int sfunct;
+	if (!resume) {
+		/*
+		 * Save chip register configuration data for chip resets
+		 * that occur during runtime and resume events.
+		 */
+		ahc->bus_softc.pci_softc.devconfig =
+			ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
+		ahc->bus_softc.pci_softc.command =
+			ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
+		ahc->bus_softc.pci_softc.csize_lattime =
+			ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1);
+		ahc->bus_softc.pci_softc.dscommand0 = ahc_inb(ahc, DSCOMMAND0);
+		ahc->bus_softc.pci_softc.dspcistatus = ahc_inb(ahc, DSPCISTATUS);
+		if ((ahc->features & AHC_DT) != 0) {
+			u_int sfunct;
+			
+			sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
+			ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
+			ahc->bus_softc.pci_softc.optionmode = ahc_inb(ahc, OPTIONMODE);
+			ahc->bus_softc.pci_softc.targcrccnt = ahc_inw(ahc, TARGCRCCNT);
+			ahc_outb(ahc, SFUNCT, sfunct);
+			ahc->bus_softc.pci_softc.crccontrol1 =
+				ahc_inb(ahc, CRCCONTROL1);
+		}
+		if ((ahc->features & AHC_MULTI_FUNC) != 0)
+			ahc->bus_softc.pci_softc.scbbaddr = ahc_inb(ahc, SCBBADDR);
+		
+		if ((ahc->features & AHC_ULTRA2) != 0)
+			ahc->bus_softc.pci_softc.dff_thrsh = ahc_inb(ahc, DFF_THRSH);
+		
+		/* Core initialization */
+		error = ahc_init(ahc);
+		if (error != 0)
+			return (error);
 
-		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
-		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
-		ahc->bus_softc.pci_softc.optionmode = ahc_inb(ahc, OPTIONMODE);
-		ahc->bus_softc.pci_softc.targcrccnt = ahc_inw(ahc, TARGCRCCNT);
-		ahc_outb(ahc, SFUNCT, sfunct);
-		ahc->bus_softc.pci_softc.crccontrol1 =
-		    ahc_inb(ahc, CRCCONTROL1);
+		/*
+		 * Allow interrupts now that we are completely setup.
+		 */
+		error = ahc_pci_map_int(ahc);
+		if (error != 0)
+			return (error);
+		
+		ahc_list_lock(&l);
+		/*
+		 * Link this softc in with all other ahc instances.
+		 */
+		ahc_softc_insert(ahc);
+		ahc_list_unlock(&l);
 	}
-	if ((ahc->features & AHC_MULTI_FUNC) != 0)
-		ahc->bus_softc.pci_softc.scbbaddr = ahc_inb(ahc, SCBBADDR);
-
-	if ((ahc->features & AHC_ULTRA2) != 0)
-		ahc->bus_softc.pci_softc.dff_thrsh = ahc_inb(ahc, DFF_THRSH);
-
-	/* Core initialization */
-	error = ahc_init(ahc);
-	if (error != 0)
-		return (error);
-
-	/*
-	 * Allow interrupts now that we are completely setup.
-	 */
-	error = ahc_pci_map_int(ahc);
-	if (error != 0)
-		return (error);
-
-	ahc_list_lock(&l);
-	/*
-	 * Link this softc in with all other ahc instances.
-	 */
-	ahc_softc_insert(ahc);
-	ahc_list_unlock(&l);
 	return (0);
 }
 
@@ -2015,21 +2025,18 @@
 static int
 ahc_pci_resume(struct ahc_softc *ahc)
 {
-
-	ahc_power_state_change(ahc, AHC_POWER_STATE_D0);
-
 	/*
 	 * We assume that the OS has restored our register
 	 * mappings, etc.  Just update the config space registers
 	 * that the OS doesn't know about and rely on our chip
 	 * reset handler to handle the rest.
 	 */
-	ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4,
-			     ahc->bus_softc.pci_softc.devconfig);
-	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1,
-			     ahc->bus_softc.pci_softc.command);
-	ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1,
-			     ahc->bus_softc.pci_softc.csize_lattime);
+	ahc_pci_write_config(ahc->dev_softc, DEVCONFIG,
+			     ahc->bus_softc.pci_softc.devconfig, /*bytes*/4);
+	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,
+			     ahc->bus_softc.pci_softc.command, /*bytes*/1);
+	ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME,
+			     ahc->bus_softc.pci_softc.csize_lattime, /*bytes*/1);
 	if ((ahc->flags & AHC_HAS_TERM_LOGIC) != 0) {
 		struct	seeprom_descriptor sd;
 		u_int	sxfrctl1;
@@ -2045,6 +2052,7 @@
 				      &sxfrctl1);
 		ahc_release_seeprom(&sd);
 	}
+	ahc_pci_config(ahc, NULL, /*resume*/TRUE);
 	return (ahc_resume(ahc));
 }
 
diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	2004-12-17 19:00:30 -05:00
+++ b/drivers/scsi/scsi.c	2004-12-17 19:00:30 -05: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>
@@ -1209,6 +1210,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");
diff -Nru a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
--- a/drivers/scsi/scsi_priv.h	2004-12-17 19:00:30 -05:00
+++ b/drivers/scsi/scsi_priv.h	2004-12-17 19:00:30 -05:00
@@ -82,6 +82,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,
diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c	2004-12-17 19:00:30 -05:00
+++ b/drivers/scsi/scsi_sysfs.c	2004-12-17 19:00:30 -05:00
@@ -201,8 +201,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)
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	2004-12-17 19:00:30 -05:00
+++ b/drivers/scsi/sd.c	2004-12-17 19:00:30 -05:00
@@ -117,6 +117,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 *);
@@ -135,6 +139,10 @@
 	.rescan			= sd_rescan,
 	.init_command		= sd_init_command,
 	.issue_flush		= sd_issue_flush,
+#ifdef CONFIG_PM
+	.suspend		= sd_suspend,
+	.resume			= sd_resume,
+#endif
 };
 
 /*
@@ -1572,7 +1580,21 @@
 	printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
 			sdkp->disk->disk_name);
 	sd_sync_cache(sdp);
-}	
+}
+
+#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
diff -Nru a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h
--- a/include/scsi/scsi_driver.h	2004-12-17 19:00:30 -05:00
+++ b/include/scsi/scsi_driver.h	2004-12-17 19:00:30 -05:00
@@ -14,6 +14,10 @@
 	int (*init_command)(struct scsi_cmnd *);
 	void (*rescan)(struct device *);
 	int (*issue_flush)(struct device *, sector_t *);
+#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] 3+ messages in thread

end of thread, other threads:[~2004-12-18  0:07 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-12-17 16:03 Adaptec driver suspend bug ahc_dv_0 Steven Newbury
2004-12-17 16:11 ` Nathan Bryant
2004-12-18  0:05 ` Nathan Bryant

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).