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 14:35:35 +0200 [thread overview]
Message-ID: <4718A497.1010106@suse.de> (raw)
In-Reply-To: <20071019084407.GA23211@infradead.org>
[-- Attachment #1: Type: text/plain, Size: 1687 bytes --]
Christoph Hellwig wrote:
> I think this needs a little restructuring. ahd_pci_suspend/ahd_pci_resume
> should be merged into their callers and use the normal Linux pci accessors,
> and ahd_suspend/ahd_resume are tiny enough to merged into the caller aswell.
>
Yes, partially. ahc_pci_resume() has to stay there as it uses quite some
functions from aic7xxx_pci.c. And I'd rather keep the overall structure
(ie split between linux-specific and generic pci access) for now.
In the long run it should be restructured as we don't do cross-compilation
with ***BSD anymore.
>> +#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
>> };
>>
>> +static int
>> +ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
>
> I think this needsa #ifdef CONFIG_PM aswell. Also any chance you
> could implement functions before their use so we can avoid forward
> declarations.
>
Yes, no problem.
>> +{
>> + struct ahd_softc *ahd = pci_get_drvdata(pdev);
>> + int rc;
>> +
>> + if ((rc = ahd_suspend(ahd)))
>> + return rc;
>
> rc = ahd_suspend(ahd)
> if (rc)
> return rc;
>
> but as I mentioned above better just inline the content of ahd_suspend
> into this function. That would also catch that ahd_suspend returns
> positive errno values and we'd have to invert them here.
>
Ok. Done.
Updated patch attached.
More to your liking?
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: 19837 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 | 109 ++++++++++++++++++++++++++------
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 | 88 +++++++++++++++++++++-----
drivers/scsi/aic7xxx/aic7xxx_pci.c | 16 +-----
10 files changed, 204 insertions(+), 175 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..d93d488 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,81 @@ 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);
+
+ if ((rc = pci_enable_device(pdev))) {
+ 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)
@@ -195,6 +255,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 +347,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 +358,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 +403,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..75b3d5a 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,67 @@ 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);
+
+ if ((rc = pci_enable_device(pdev))) {
+ 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)
@@ -243,6 +290,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
next prev parent reply other threads:[~2007-10-19 12:35 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 [this message]
2007-10-19 13:02 ` Christoph Hellwig
2007-10-19 13:45 ` Hannes Reinecke
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=4718A497.1010106@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.