All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hannes Reinecke <hare@suse.de>
To: Christoph Hellwig <hch@infradead.org>
Cc: James Bottomley <James.Bottomley@SteelEye.com>,
	linux-scsi@vger.kernel.org
Subject: Re: [PATCH 1/4] aic7xxx: Add suspend/resume support
Date: Fri, 19 Oct 2007 15:45:13 +0200	[thread overview]
Message-ID: <4718B4E9.3080000@suse.de> (raw)
In-Reply-To: <20071019130246.GA30198@infradead.org>

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

Christoph Hellwig wrote:
> On Fri, Oct 19, 2007 at 02:35:35PM +0200, Hannes Reinecke wrote:
[ .. ]
>> Ok. Done.
>> Updated patch attached.
>> More to your liking?
> 
> Much better.  There's still some if ((rc = fo())) left, but it's probably
> not worth to delay the patch further because of that.  Just clean it up
> in a followon patch.
> 
Might as well do it now. Fixed patch attached.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Markus Rex, HRB 16746 (AG Nürnberg)

[-- Attachment #2: 0001-aic7xxx-Add-suspend-resume-support.patch --]
[-- Type: text/x-patch, Size: 20409 bytes --]

>From 2dc1cdee053846fafc98a819bdad1533ac7c2f04 Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <hare@suse.de>
Date: Fri, 19 Oct 2007 09:13:17 +0200
Subject: [PATCH 1/4] aic7xxx: Add suspend/resume support

The aic7xxx driver already contains fragments for suspend/resume
support. So we only need to update them to the current interface
and have full PCI suspend/resume.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Tested-by: Jens Axboe <jens.axboe@oracle.com>
---
 drivers/scsi/aic7xxx/aic7770.c         |   16 -----
 drivers/scsi/aic7xxx/aic79xx.h         |    9 +++
 drivers/scsi/aic7xxx/aic79xx_core.c    |   33 +---------
 drivers/scsi/aic7xxx/aic79xx_osm_pci.c |  112 ++++++++++++++++++++++++++------
 drivers/scsi/aic7xxx/aic79xx_pci.c     |   24 -------
 drivers/scsi/aic7xxx/aic79xx_pci.h     |   25 +++++++
 drivers/scsi/aic7xxx/aic7xxx.h         |   18 +----
 drivers/scsi/aic7xxx/aic7xxx_core.c    |   41 +-----------
 drivers/scsi/aic7xxx/aic7xxx_osm_pci.c |   91 +++++++++++++++++++++-----
 drivers/scsi/aic7xxx/aic7xxx_pci.c     |   16 +----
 10 files changed, 208 insertions(+), 177 deletions(-)

diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
index c4d1723..6d86a9b 100644
--- a/drivers/scsi/aic7xxx/aic7770.c
+++ b/drivers/scsi/aic7xxx/aic7770.c
@@ -60,8 +60,6 @@
 #define	ID_OLV_274xD	0x04907783 /* Olivetti OEM (Differential) */
 
 static int aic7770_chip_init(struct ahc_softc *ahc);
-static int aic7770_suspend(struct ahc_softc *ahc);
-static int aic7770_resume(struct ahc_softc *ahc);
 static int aha2840_load_seeprom(struct ahc_softc *ahc);
 static ahc_device_setup_t ahc_aic7770_VL_setup;
 static ahc_device_setup_t ahc_aic7770_EISA_setup;
@@ -155,8 +153,6 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
 		return (error);
 
 	ahc->bus_chip_init = aic7770_chip_init;
-	ahc->bus_suspend = aic7770_suspend;
-	ahc->bus_resume = aic7770_resume;
 
 	error = ahc_reset(ahc, /*reinit*/FALSE);
 	if (error != 0)
@@ -272,18 +268,6 @@ aic7770_chip_init(struct ahc_softc *ahc)
 	return (ahc_chip_init(ahc));
 }
 
-static int
-aic7770_suspend(struct ahc_softc *ahc)
-{
-	return (ahc_suspend(ahc));
-}
-
-static int
-aic7770_resume(struct ahc_softc *ahc)
-{
-	return (ahc_resume(ahc));
-}
-
 /*
  * Read the 284x SEEPROM.
  */
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index 27adbb2..a96a2ff 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -1003,8 +1003,15 @@ struct ahd_suspend_channel_state {
 	uint8_t	seqctl;
 };
 
+struct ahd_suspend_pci_state {
+	uint32_t  devconfig;
+	uint8_t   command;
+	uint8_t   csize_lattime;
+};
+
 struct ahd_suspend_state {
 	struct	ahd_suspend_channel_state channel[2];
+	struct  ahd_suspend_pci_state pci_state;
 	uint8_t	optionmode;
 	uint8_t	dscommand0;
 	uint8_t	dspcistatus;
@@ -1343,6 +1350,8 @@ struct ahd_softc	*ahd_alloc(void *platform_arg, char *name);
 int			 ahd_softc_init(struct ahd_softc *);
 void			 ahd_controller_info(struct ahd_softc *ahd, char *buf);
 int			 ahd_init(struct ahd_softc *ahd);
+void			 ahd_shutdown(void *arg);
+void			 ahd_restart(struct ahd_softc *ahd);
 int			 ahd_default_config(struct ahd_softc *ahd);
 int			 ahd_parse_vpddata(struct ahd_softc *ahd,
 					   struct vpd_config *vpd);
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 05f692b..91f6f4f 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -255,7 +255,6 @@ static void		ahd_freeze_devq(struct ahd_softc *ahd,
 static void		ahd_handle_scb_status(struct ahd_softc *ahd,
 					      struct scb *scb);
 static struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase);
-static void		ahd_shutdown(void *arg);
 static void		ahd_update_coalescing_values(struct ahd_softc *ahd,
 						     u_int timer,
 						     u_int maxcmds,
@@ -357,7 +356,7 @@ ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
 /*
  * Restart the sequencer program from address zero
  */
-static void
+void
 ahd_restart(struct ahd_softc *ahd)
 {
 
@@ -5456,7 +5455,7 @@ ahd_free(struct ahd_softc *ahd)
 	return;
 }
 
-static void
+void
 ahd_shutdown(void *arg)
 {
 	struct	ahd_softc *ahd;
@@ -7175,34 +7174,6 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
 	ahd->flags &= ~AHD_ALL_INTERRUPTS;
 }
 
-#if 0
-int
-ahd_suspend(struct ahd_softc *ahd)
-{
-
-	ahd_pause_and_flushwork(ahd);
-
-	if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
-		ahd_unpause(ahd);
-		return (EBUSY);
-	}
-	ahd_shutdown(ahd);
-	return (0);
-}
-#endif  /*  0  */
-
-#if 0
-int
-ahd_resume(struct ahd_softc *ahd)
-{
-
-	ahd_reset(ahd, /*reinit*/TRUE);
-	ahd_intr_enable(ahd, TRUE); 
-	ahd_restart(ahd);
-	return (0);
-}
-#endif  /*  0  */
-
 /************************** Busy Target Table *********************************/
 /*
  * Set SCBPTR to the SCB that contains the busy
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index c62ce41..8aa6302 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -43,15 +43,6 @@
 #include "aic79xx_inline.h"
 #include "aic79xx_pci.h"
 
-static int	ahd_linux_pci_dev_probe(struct pci_dev *pdev,
-					const struct pci_device_id *ent);
-static int	ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd,
-						 u_long *base, u_long *base2);
-static int	ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
-						 u_long *bus_addr,
-						 uint8_t __iomem **maddr);
-static void	ahd_linux_pci_dev_remove(struct pci_dev *pdev);
-
 /* Define the macro locally since it's different for different class of chips.
  */
 #define ID(x)            \
@@ -83,12 +74,82 @@ static struct pci_device_id ahd_linux_pci_id_table[] = {
 
 MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table);
 
-static struct pci_driver aic79xx_pci_driver = {
-	.name		= "aic79xx",
-	.probe		= ahd_linux_pci_dev_probe,
-	.remove		= ahd_linux_pci_dev_remove,
-	.id_table	= ahd_linux_pci_id_table
-};
+#ifdef CONFIG_PM
+int
+ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+	struct ahd_softc *ahd = pci_get_drvdata(pdev);
+
+	/*
+	 * Shutdown the HBA
+	 */
+	ahd_pause_and_flushwork(ahd);
+
+	if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
+		ahd_unpause(ahd);
+		return -EBUSY;
+	}
+
+	ahd_shutdown(ahd);
+
+	/*
+	 * Save chip register configuration data for chip resets
+	 * that occur during runtime and resume events.
+	 */
+	pci_read_config_dword(ahd->dev_softc, DEVCONFIG,
+			      &ahd->suspend_state.pci_state.devconfig);
+	pci_read_config_byte(ahd->dev_softc, PCIR_COMMAND,
+			     &ahd->suspend_state.pci_state.command);
+	pci_read_config_byte(ahd->dev_softc, CSIZE_LATTIME,
+			     &ahd->suspend_state.pci_state.csize_lattime);
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+
+	if (mesg.event == PM_EVENT_SUSPEND)
+		pci_set_power_state(pdev, PCI_D3hot);
+
+	return 0;
+}
+
+int
+ahd_linux_pci_dev_resume(struct pci_dev *pdev)
+{
+	struct ahd_softc *ahd = pci_get_drvdata(pdev);
+	int rc;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		dev_printk(KERN_ERR, &pdev->dev,
+			   "failed to enable device after resume (%d)\n", rc);
+		return rc;
+	}
+
+	pci_set_master(pdev);
+
+	/*
+	 * Restore additional PCI registers
+	 */
+	pci_write_config_dword(ahd->dev_softc, DEVCONFIG,
+			       ahd->suspend_state.pci_state.devconfig);
+	pci_write_config_byte(ahd->dev_softc, PCIR_COMMAND,
+			      ahd->suspend_state.pci_state.command);
+	pci_write_config_byte(ahd->dev_softc, CSIZE_LATTIME,
+			 ahd->suspend_state.pci_state.csize_lattime);
+
+	/*
+	 * Restart the HBA
+	 */
+	ahd_reset(ahd, /*reinit*/TRUE);
+	ahd_intr_enable(ahd, TRUE); 
+	ahd_restart(ahd);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
 
 static void
 ahd_linux_pci_dev_remove(struct pci_dev *pdev)
@@ -97,7 +158,7 @@ ahd_linux_pci_dev_remove(struct pci_dev *pdev)
 	u_long s;
 
 	if (ahd->platform_data && ahd->platform_data->host)
-			scsi_remove_host(ahd->platform_data->host);
+		scsi_remove_host(ahd->platform_data->host);
 
 	ahd_lock(ahd, &s);
 	ahd_intr_enable(ahd, FALSE);
@@ -195,6 +256,17 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	return (0);
 }
 
+static struct pci_driver aic79xx_pci_driver = {
+	.name		= "aic79xx",
+	.probe		= ahd_linux_pci_dev_probe,
+#ifdef CONFIG_PM
+	.suspend	= ahd_linux_pci_dev_suspend,
+	.resume		= ahd_linux_pci_dev_resume,
+#endif
+	.remove		= ahd_linux_pci_dev_remove,
+	.id_table	= ahd_linux_pci_id_table
+};
+
 int
 ahd_linux_pci_init(void)
 {
@@ -276,7 +348,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
 	/*
 	 * If its allowed, we prefer memory mapped access.
 	 */
-	command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, 4);
+	pci_read_config_dword(ahd->dev_softc, PCIR_COMMAND, &command);
 	command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN);
 	base = 0;
 	maddr = NULL;
@@ -287,8 +359,8 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
 		ahd->bshs[0].maddr = maddr;
 		ahd->tags[1] = BUS_SPACE_MEMIO;
 		ahd->bshs[1].maddr = maddr + 0x100;
-		ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
-				     command | PCIM_CMD_MEMEN, 4);
+		pci_write_config_dword(ahd->dev_softc, PCIR_COMMAND,
+				       command | PCIM_CMD_MEMEN);
 
 		if (ahd_pci_test_register_access(ahd) != 0) {
 
@@ -332,7 +404,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
 			       base, base2);
 		}
 	}
-	ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, 4);
+	pci_write_config_dword(ahd->dev_softc, PCIR_COMMAND, command);
 	return (error);
 }
 
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 0bada00..c8617e0 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -209,12 +209,6 @@ static struct ahd_pci_identity ahd_pci_ident_table [] =
 
 static const u_int ahd_num_pci_devs = ARRAY_SIZE(ahd_pci_ident_table);
 		
-#define	DEVCONFIG		0x40
-#define		PCIXINITPAT	0x0000E000ul
-#define			PCIXINIT_PCI33_66	0x0000E000ul
-#define			PCIXINIT_PCIX50_66	0x0000C000ul
-#define			PCIXINIT_PCIX66_100	0x0000A000ul
-#define			PCIXINIT_PCIX100_133	0x00008000ul
 #define	PCI_BUS_MODES_INDEX(devconfig)	\
 	(((devconfig) & PCIXINITPAT) >> 13)
 static const char *pci_bus_modes[] =
@@ -229,24 +223,6 @@ static const char *pci_bus_modes[] =
 	"PCI 33 or 66Mhz"
 };
 
-#define		TESTMODE	0x00000800ul
-#define		IRDY_RST	0x00000200ul
-#define		FRAME_RST	0x00000100ul
-#define		PCI64BIT	0x00000080ul
-#define		MRDCEN		0x00000040ul
-#define		ENDIANSEL	0x00000020ul
-#define		MIXQWENDIANEN	0x00000008ul
-#define		DACEN		0x00000004ul
-#define		STPWLEVEL	0x00000002ul
-#define		QWENDIANSEL	0x00000001ul
-
-#define	DEVCONFIG1		0x44
-#define		PREQDIS		0x01
-
-#define	CSIZE_LATTIME		0x0c
-#define		CACHESIZE	0x000000fful
-#define		LATTIME		0x0000ff00ul
-
 static int	ahd_check_extport(struct ahd_softc *ahd);
 static void	ahd_configure_termination(struct ahd_softc *ahd,
 					  u_int adapter_control);
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.h b/drivers/scsi/aic7xxx/aic79xx_pci.h
index 16b7c70..67ea5ae 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.h
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.h
@@ -69,4 +69,29 @@
 #define ID_AHA_39320D_HP		0x8011900500AC0E11ull
 #define ID_AHA_39320D_B_HP		0x801C900500AC0E11ull
 
+#define	DEVCONFIG		0x40
+#define		PCIXINITPAT	0x0000E000ul
+#define			PCIXINIT_PCI33_66	0x0000E000ul
+#define			PCIXINIT_PCIX50_66	0x0000C000ul
+#define			PCIXINIT_PCIX66_100	0x0000A000ul
+#define			PCIXINIT_PCIX100_133	0x00008000ul
+
+#define		TESTMODE	0x00000800ul
+#define		IRDY_RST	0x00000200ul
+#define		FRAME_RST	0x00000100ul
+#define		PCI64BIT	0x00000080ul
+#define		MRDCEN		0x00000040ul
+#define		ENDIANSEL	0x00000020ul
+#define		MIXQWENDIANEN	0x00000008ul
+#define		DACEN		0x00000004ul
+#define		STPWLEVEL	0x00000002ul
+#define		QWENDIANSEL	0x00000001ul
+
+#define	DEVCONFIG1		0x44
+#define		PREQDIS		0x01
+
+#define	CSIZE_LATTIME		0x0c
+#define		CACHESIZE	0x000000fful
+#define		LATTIME		0x0000ff00ul
+
 #endif /* _AIC79XX_PCI_H_ */
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index e1bd57b..80ceeaf 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -899,8 +899,6 @@ union ahc_bus_softc {
 
 typedef void (*ahc_bus_intr_t)(struct ahc_softc *);
 typedef int (*ahc_bus_chip_init_t)(struct ahc_softc *);
-typedef int (*ahc_bus_suspend_t)(struct ahc_softc *);
-typedef int (*ahc_bus_resume_t)(struct ahc_softc *);
 typedef void ahc_callback_t (void *);
 
 struct ahc_softc {
@@ -962,16 +960,6 @@ struct ahc_softc {
 	ahc_bus_chip_init_t	  bus_chip_init;
 
 	/*
-	 * Bus specific suspend routine.
-	 */
-	ahc_bus_suspend_t	  bus_suspend;
-
-	/*
-	 * Bus specific resume routine.
-	 */
-	ahc_bus_resume_t	  bus_resume;
-
-	/*
 	 * Target mode related state kept on a per enabled lun basis.
 	 * Targets that are not enabled will have null entries.
 	 * As an initiator, we keep one target entry for our initiator
@@ -1153,6 +1141,7 @@ struct ahc_pci_identity	*ahc_find_pci_device(ahc_dev_softc_t);
 int			 ahc_pci_config(struct ahc_softc *,
 					struct ahc_pci_identity *);
 int			 ahc_pci_test_register_access(struct ahc_softc *);
+void			 ahc_pci_resume(struct ahc_softc *ahc);
 
 /*************************** EISA/VL Front End ********************************/
 struct aic7770_identity *aic7770_find_device(uint32_t);
@@ -1179,14 +1168,13 @@ int			 ahc_chip_init(struct ahc_softc *ahc);
 int			 ahc_init(struct ahc_softc *ahc);
 void			 ahc_intr_enable(struct ahc_softc *ahc, int enable);
 void			 ahc_pause_and_flushwork(struct ahc_softc *ahc);
-int			 ahc_suspend(struct ahc_softc *ahc); 
-int			 ahc_resume(struct ahc_softc *ahc);
 void			 ahc_set_unit(struct ahc_softc *, int);
 void			 ahc_set_name(struct ahc_softc *, char *);
 void			 ahc_alloc_scbs(struct ahc_softc *ahc);
 void			 ahc_free(struct ahc_softc *ahc);
 int			 ahc_reset(struct ahc_softc *ahc, int reinit);
-void			 ahc_shutdown(void *arg);
+void			 ahc_restart(struct ahc_softc *ahc);
+void			 ahc_shutdown(struct ahc_softc *ahc); 
 
 /*************************** Interrupt Services *******************************/
 void			ahc_clear_intstat(struct ahc_softc *ahc);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index f350b5e..40f7072 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -3984,13 +3984,10 @@ ahc_free(struct ahc_softc *ahc)
 }
 
 void
-ahc_shutdown(void *arg)
+ahc_shutdown(struct ahc_softc *ahc)
 {
-	struct	ahc_softc *ahc;
 	int	i;
 
-	ahc = (struct ahc_softc *)arg;
-
 	/* This will reset most registers to 0, but not all */
 	ahc_reset(ahc, /*reinit*/FALSE);
 	ahc_outb(ahc, SCSISEQ, 0);
@@ -5078,42 +5075,6 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
 	ahc->flags &= ~AHC_ALL_INTERRUPTS;
 }
 
-int
-ahc_suspend(struct ahc_softc *ahc)
-{
-
-	ahc_pause_and_flushwork(ahc);
-
-	if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
-		ahc_unpause(ahc);
-		return (EBUSY);
-	}
-
-#ifdef AHC_TARGET_MODE
-	/*
-	 * XXX What about ATIOs that have not yet been serviced?
-	 * Perhaps we should just refuse to be suspended if we
-	 * are acting in a target role.
-	 */
-	if (ahc->pending_device != NULL) {
-		ahc_unpause(ahc);
-		return (EBUSY);
-	}
-#endif
-	ahc_shutdown(ahc);
-	return (0);
-}
-
-int
-ahc_resume(struct ahc_softc *ahc)
-{
-
-	ahc_reset(ahc, /*reinit*/TRUE);
-	ahc_intr_enable(ahc, TRUE); 
-	ahc_restart(ahc);
-	return (0);
-}
-
 /************************** Busy Target Table *********************************/
 /*
  * Return the untagged transaction id for a given target/channel lun.
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index ea5687d..847485f 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -41,15 +41,7 @@
 
 #include "aic7xxx_osm.h"
 #include "aic7xxx_pci.h"
-
-static int	ahc_linux_pci_dev_probe(struct pci_dev *pdev,
-					const struct pci_device_id *ent);
-static int	ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc,
-						u_long *base);
-static int	ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
-						 u_long *bus_addr,
-						 uint8_t __iomem **maddr);
-static void	ahc_linux_pci_dev_remove(struct pci_dev *pdev);
+#include "aic7xxx_inline.h"
 
 /* Define the macro locally since it's different for different class of chips.
 */
@@ -130,12 +122,68 @@ static struct pci_device_id ahc_linux_pci_id_table[] = {
 
 MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
 
-static struct pci_driver aic7xxx_pci_driver = {
-	.name		= "aic7xxx",
-	.probe		= ahc_linux_pci_dev_probe,
-	.remove		= ahc_linux_pci_dev_remove,
-	.id_table	= ahc_linux_pci_id_table
-};
+#ifdef CONFIG_PM
+static int
+ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+	struct ahc_softc *ahc = pci_get_drvdata(pdev);
+
+	ahc_pause_and_flushwork(ahc);
+
+	if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
+		ahc_unpause(ahc);
+		return -EBUSY;
+	}
+
+#ifdef AHC_TARGET_MODE
+	/*
+	 * XXX What about ATIOs that have not yet been serviced?
+	 * Perhaps we should just refuse to be suspended if we
+	 * are acting in a target role.
+	 */
+	if (ahc->pending_device != NULL) {
+		ahc_unpause(ahc);
+		return -EBUSY;
+	}
+#endif
+	ahc_shutdown(ahc);
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+
+	if (mesg.event == PM_EVENT_SUSPEND)
+		pci_set_power_state(pdev, PCI_D3hot);
+
+	return 0;
+}
+
+static int
+ahc_linux_pci_dev_resume(struct pci_dev *pdev)
+{
+	struct ahc_softc *ahc = pci_get_drvdata(pdev);
+	int rc;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		dev_printk(KERN_ERR, &pdev->dev,
+			   "failed to enable device after resume (%d)\n", rc);
+		return rc;
+	}
+
+	pci_set_master(pdev);
+
+	ahc_pci_resume(ahc);
+
+	ahc_reset(ahc, /*reinit*/TRUE);
+	ahc_intr_enable(ahc, TRUE); 
+	ahc_restart(ahc);
+
+	return rc;
+}
+#endif /* CONFIG_PM */
 
 static void
 ahc_linux_pci_dev_remove(struct pci_dev *pdev)
@@ -144,7 +192,7 @@ ahc_linux_pci_dev_remove(struct pci_dev *pdev)
 	u_long s;
 
 	if (ahc->platform_data && ahc->platform_data->host)
-			scsi_remove_host(ahc->platform_data->host);
+		scsi_remove_host(ahc->platform_data->host);
 
 	ahc_lock(ahc, &s);
 	ahc_intr_enable(ahc, FALSE);
@@ -243,6 +291,17 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	return (0);
 }
 
+static struct pci_driver aic7xxx_pci_driver = {
+	.name		= "aic7xxx",
+	.probe		= ahc_linux_pci_dev_probe,
+#ifdef CONFIG_PM
+	.suspend	= ahc_linux_pci_dev_suspend,
+	.resume		= ahc_linux_pci_dev_resume,
+#endif
+	.remove		= ahc_linux_pci_dev_remove,
+	.id_table	= ahc_linux_pci_id_table
+};
+
 int
 ahc_linux_pci_init(void)
 {
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index 09c8172..ae35937 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -633,8 +633,6 @@ static void    write_brdctl(struct ahc_softc *ahc, uint8_t value);
 static uint8_t read_brdctl(struct ahc_softc *ahc);
 static void ahc_pci_intr(struct ahc_softc *ahc);
 static int  ahc_pci_chip_init(struct ahc_softc *ahc);
-static int  ahc_pci_suspend(struct ahc_softc *ahc);
-static int  ahc_pci_resume(struct ahc_softc *ahc);
 
 static int
 ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor,
@@ -791,8 +789,6 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
 
 	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) {
@@ -2024,18 +2020,9 @@ ahc_pci_chip_init(struct ahc_softc *ahc)
 	return (ahc_chip_init(ahc));
 }
 
-static int
-ahc_pci_suspend(struct ahc_softc *ahc)
-{
-	return (ahc_suspend(ahc));
-}
-
-static int
+void
 ahc_pci_resume(struct ahc_softc *ahc)
 {
-
-	pci_set_power_state(ahc->dev_softc, AHC_POWER_STATE_D0);
-
 	/*
 	 * We assume that the OS has restored our register
 	 * mappings, etc.  Just update the config space registers
@@ -2063,7 +2050,6 @@ ahc_pci_resume(struct ahc_softc *ahc)
 				      &sxfrctl1);
 		ahc_release_seeprom(&sd);
 	}
-	return (ahc_resume(ahc));
 }
 
 static int

      reply	other threads:[~2007-10-19 13:45 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-10-19  8:32 [PATCH 1/4] aic7xxx: Add suspend/resume support Hannes Reinecke
2007-10-19  8:44 ` Christoph Hellwig
2007-10-19 12:35   ` Hannes Reinecke
2007-10-19 13:02     ` Christoph Hellwig
2007-10-19 13:45       ` Hannes Reinecke [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4718B4E9.3080000@suse.de \
    --to=hare@suse.de \
    --cc=James.Bottomley@SteelEye.com \
    --cc=hch@infradead.org \
    --cc=linux-scsi@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.