Re: Adaptec driver suspend bug ahc_dv_0

From: Nathan Bryant (nbryant_at_optonline.net)
Date: 12/18/04

  • Next message: Greg KH: "Re: [PATCH]PCI Express Port Bus Driver"
    Date:	Fri, 17 Dec 2004 19:05:17 -0500
    To: Steven Newbury <s_j_newbury@yahoo.co.uk>
    
    
    

    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

    
    

    # 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)

    -
    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/


  • Next message: Greg KH: "Re: [PATCH]PCI Express Port Bus Driver"

    Relevant Pages