Merge branch 'tj-upstream-pci_register_driver' of git://htj.dyndns.org/libata-tj...
[cascardo/linux.git] / drivers / scsi / libata-core.c
index d1c1c30..3f963f2 100644 (file)
@@ -32,7 +32,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -62,9 +61,9 @@
 #include "libata.h"
 
 /* debounce timing parameters in msecs { interval, duration, timeout } */
-const unsigned long sata_deb_timing_boot[]             = {   5,  100, 2000 };
-const unsigned long sata_deb_timing_eh[]               = {  25,  500, 2000 };
-const unsigned long sata_deb_timing_before_fsrst[]     = { 100, 2000, 5000 };
+const unsigned long sata_deb_timing_normal[]           = {   5,  100, 2000 };
+const unsigned long sata_deb_timing_hotplug[]          = {  25,  500, 2000 };
+const unsigned long sata_deb_timing_long[]             = { 100, 2000, 5000 };
 
 static unsigned int ata_dev_init_params(struct ata_device *dev,
                                        u16 heads, u16 sectors);
@@ -908,7 +907,7 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
 {
        int rc;
 
-       if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK)
+       if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
                return;
 
        PREPARE_WORK(&ap->port_task, fn, data);
@@ -939,7 +938,7 @@ void ata_port_flush_task(struct ata_port *ap)
        DPRINTK("ENTER\n");
 
        spin_lock_irqsave(ap->lock, flags);
-       ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
+       ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK;
        spin_unlock_irqrestore(ap->lock, flags);
 
        DPRINTK("flush #1\n");
@@ -958,7 +957,7 @@ void ata_port_flush_task(struct ata_port *ap)
        }
 
        spin_lock_irqsave(ap->lock, flags);
-       ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
+       ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK;
        spin_unlock_irqrestore(ap->lock, flags);
 
        if (ata_msg_ctl(ap))
@@ -1002,7 +1001,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
        struct ata_queued_cmd *qc;
        unsigned int tag, preempted_tag;
        u32 preempted_sactive, preempted_qc_active;
-       DECLARE_COMPLETION(wait);
+       DECLARE_COMPLETION_ONSTACK(wait);
        unsigned long flags;
        unsigned int err_mask;
        int rc;
@@ -1010,7 +1009,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
        spin_lock_irqsave(ap->lock, flags);
 
        /* no internal command while frozen */
-       if (ap->flags & ATA_FLAG_FROZEN) {
+       if (ap->pflags & ATA_PFLAG_FROZEN) {
                spin_unlock_irqrestore(ap->lock, flags);
                return AC_ERR_SYSTEM;
        }
@@ -1326,6 +1325,19 @@ static void ata_dev_config_ncq(struct ata_device *dev,
                snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
 }
 
+static void ata_set_port_max_cmd_len(struct ata_port *ap)
+{
+       int i;
+
+       if (ap->host) {
+               ap->host->max_cmd_len = 0;
+               for (i = 0; i < ATA_MAX_DEVICES; i++)
+                       ap->host->max_cmd_len = max_t(unsigned int,
+                                                     ap->host->max_cmd_len,
+                                                     ap->device[i].cdb_len);
+       }
+}
+
 /**
  *     ata_dev_configure - Configure the specified ATA/ATAPI device
  *     @dev: Target device to configure
@@ -1345,7 +1357,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
        struct ata_port *ap = dev->ap;
        const u16 *id = dev->id;
        unsigned int xfer_mask;
-       int i, rc;
+       int rc;
 
        if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
                ata_dev_printk(dev, KERN_INFO,
@@ -1405,7 +1417,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
                        ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
 
                        /* print device info to dmesg */
-                       if (ata_msg_info(ap))
+                       if (ata_msg_drv(ap) && print_info)
                                ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
                                        "max %s, %Lu sectors: %s %s\n",
                                        ata_id_major_version(id),
@@ -1428,7 +1440,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
                        }
 
                        /* print device info to dmesg */
-                       if (ata_msg_info(ap))
+                       if (ata_msg_drv(ap) && print_info)
                                ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
                                        "max %s, %Lu sectors: CHS %u/%u/%u\n",
                                        ata_id_major_version(id),
@@ -1440,7 +1452,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
 
                if (dev->id[59] & 0x100) {
                        dev->multi_count = dev->id[59] & 0xff;
-                       if (ata_msg_info(ap))
+                       if (ata_msg_drv(ap) && print_info)
                                ata_dev_printk(dev, KERN_INFO,
                                        "ata%u: dev %u multi count %u\n",
                                        ap->id, dev->devno, dev->multi_count);
@@ -1469,21 +1481,17 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
                }
 
                /* print device info to dmesg */
-               if (ata_msg_info(ap))
+               if (ata_msg_drv(ap) && print_info)
                        ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
                                       ata_mode_string(xfer_mask),
                                       cdb_intr_string);
        }
 
-       ap->host->max_cmd_len = 0;
-       for (i = 0; i < ATA_MAX_DEVICES; i++)
-               ap->host->max_cmd_len = max_t(unsigned int,
-                                             ap->host->max_cmd_len,
-                                             ap->device[i].cdb_len);
+       ata_set_port_max_cmd_len(ap);
 
        /* limit bridge transfers to udma5, 200 sectors */
        if (ata_dev_knobble(dev)) {
-               if (ata_msg_info(ap))
+               if (ata_msg_drv(ap) && print_info)
                        ata_dev_printk(dev, KERN_INFO,
                                       "applying bridge limits\n");
                dev->udma_mask &= ATA_UDMA5;
@@ -1520,7 +1528,7 @@ err_out_nosup:
  *     Zero on success, negative errno otherwise.
  */
 
-static int ata_bus_probe(struct ata_port *ap)
+int ata_bus_probe(struct ata_port *ap)
 {
        unsigned int classes[ATA_MAX_DEVICES];
        int tries[ATA_MAX_DEVICES];
@@ -2138,7 +2146,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
                 * return error code and failing device on failure.
                 */
                for (i = 0; i < ATA_MAX_DEVICES; i++) {
-                       if (ata_dev_enabled(&ap->device[i])) {
+                       if (ata_dev_ready(&ap->device[i])) {
                                ap->ops->set_mode(ap);
                                break;
                        }
@@ -2204,7 +2212,8 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
                dev = &ap->device[i];
 
-               if (!ata_dev_enabled(dev))
+               /* don't udpate suspended devices' xfer mode */
+               if (!ata_dev_ready(dev))
                        continue;
 
                rc = ata_dev_set_mode(dev);
@@ -2580,7 +2589,7 @@ static void ata_wait_spinup(struct ata_port *ap)
 
        /* first, debounce phy if SATA */
        if (ap->cbl == ATA_CBL_SATA) {
-               rc = sata_phy_debounce(ap, sata_deb_timing_eh);
+               rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
 
                /* if debounced successfully and offline, no need to wait */
                if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
@@ -2616,16 +2625,17 @@ static void ata_wait_spinup(struct ata_port *ap)
 int ata_std_prereset(struct ata_port *ap)
 {
        struct ata_eh_context *ehc = &ap->eh_context;
-       const unsigned long *timing;
+       const unsigned long *timing = sata_ehc_deb_timing(ehc);
        int rc;
 
-       /* hotplug? */
-       if (ehc->i.flags & ATA_EHI_HOTPLUGGED) {
-               if (ap->flags & ATA_FLAG_HRST_TO_RESUME)
-                       ehc->i.action |= ATA_EH_HARDRESET;
-               if (ap->flags & ATA_FLAG_SKIP_D2H_BSY)
-                       ata_wait_spinup(ap);
-       }
+       /* handle link resume & hotplug spinup */
+       if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+           (ap->flags & ATA_FLAG_HRST_TO_RESUME))
+               ehc->i.action |= ATA_EH_HARDRESET;
+
+       if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
+           (ap->flags & ATA_FLAG_SKIP_D2H_BSY))
+               ata_wait_spinup(ap);
 
        /* if we're about to do hardreset, nothing more to do */
        if (ehc->i.action & ATA_EH_HARDRESET)
@@ -2633,11 +2643,6 @@ int ata_std_prereset(struct ata_port *ap)
 
        /* if SATA, resume phy */
        if (ap->cbl == ATA_CBL_SATA) {
-               if (ap->flags & ATA_FLAG_LOADING)
-                       timing = sata_deb_timing_boot;
-               else
-                       timing = sata_deb_timing_eh;
-
                rc = sata_phy_resume(ap, timing);
                if (rc && rc != -EOPNOTSUPP) {
                        /* phy resume failed */
@@ -2725,6 +2730,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
  */
 int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
 {
+       struct ata_eh_context *ehc = &ap->eh_context;
+       const unsigned long *timing = sata_ehc_deb_timing(ehc);
        u32 scontrol;
        int rc;
 
@@ -2762,7 +2769,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
        msleep(1);
 
        /* bring phy back */
-       sata_phy_resume(ap, sata_deb_timing_eh);
+       sata_phy_resume(ap, timing);
 
        /* TODO: phy layer with polling, timeouts, etc. */
        if (ata_port_offline(ap)) {
@@ -3033,10 +3040,6 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
  *     known limits including host controller limits, device
  *     blacklist, etc...
  *
- *     FIXME: The current implementation limits all transfer modes to
- *     the fastest of the lowested device on the port.  This is not
- *     required on most controllers.
- *
  *     LOCKING:
  *     None.
  */
@@ -3045,8 +3048,8 @@ static void ata_dev_xfermask(struct ata_device *dev)
        struct ata_port *ap = dev->ap;
        struct ata_host_set *hs = ap->host_set;
        unsigned long xfer_mask;
-       int i;
 
+       /* controller modes available */
        xfer_mask = ata_pack_xfermask(ap->pio_mask,
                                      ap->mwdma_mask, ap->udma_mask);
 
@@ -3056,34 +3059,20 @@ static void ata_dev_xfermask(struct ata_device *dev)
        if (ap->cbl == ATA_CBL_PATA40)
                xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
 
-       /* FIXME: Use port-wide xfermask for now */
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *d = &ap->device[i];
-
-               if (ata_dev_absent(d))
-                       continue;
-
-               if (ata_dev_disabled(d)) {
-                       /* to avoid violating device selection timing */
-                       xfer_mask &= ata_pack_xfermask(d->pio_mask,
-                                                      UINT_MAX, UINT_MAX);
-                       continue;
-               }
-
-               xfer_mask &= ata_pack_xfermask(d->pio_mask,
-                                              d->mwdma_mask, d->udma_mask);
-               xfer_mask &= ata_id_xfermask(d->id);
-               if (ata_dma_blacklisted(d))
-                       xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
-       }
+       xfer_mask &= ata_pack_xfermask(dev->pio_mask,
+                                      dev->mwdma_mask, dev->udma_mask);
+       xfer_mask &= ata_id_xfermask(dev->id);
 
-       if (ata_dma_blacklisted(dev))
+       if (ata_dma_blacklisted(dev)) {
+               xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
                ata_dev_printk(dev, KERN_WARNING,
                               "device is on DMA blacklist, disabling DMA\n");
+       }
 
-       if (hs->flags & ATA_HOST_SIMPLEX) {
-               if (hs->simplex_claimed)
-                       xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+       if ((hs->flags & ATA_HOST_SIMPLEX) && hs->simplex_claimed) {
+               xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+               ata_dev_printk(dev, KERN_WARNING, "simplex DMA is claimed by "
+                              "other device, disabling DMA\n");
        }
 
        if (ap->ops->mode_filter)
@@ -4286,7 +4275,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
        unsigned int i;
 
        /* no command while frozen */
-       if (unlikely(ap->flags & ATA_FLAG_FROZEN))
+       if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
                return NULL;
 
        /* the last tag is reserved for internal command. */
@@ -4408,7 +4397,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
         * taken care of.
         */
        if (ap->ops->error_handler) {
-               WARN_ON(ap->flags & ATA_FLAG_FROZEN);
+               WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
 
                if (unlikely(qc->err_mask))
                        qc->flags |= ATA_QCFLAG_FAILED;
@@ -5002,86 +4991,120 @@ int ata_flush_cache(struct ata_device *dev)
        return 0;
 }
 
-static int ata_standby_drive(struct ata_device *dev)
+static int ata_host_set_request_pm(struct ata_host_set *host_set,
+                                  pm_message_t mesg, unsigned int action,
+                                  unsigned int ehi_flags, int wait)
 {
-       unsigned int err_mask;
+       unsigned long flags;
+       int i, rc;
 
-       err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
-       if (err_mask) {
-               ata_dev_printk(dev, KERN_ERR, "failed to standby drive "
-                              "(err_mask=0x%x)\n", err_mask);
-               return -EIO;
-       }
+       for (i = 0; i < host_set->n_ports; i++) {
+               struct ata_port *ap = host_set->ports[i];
 
-       return 0;
-}
+               /* Previous resume operation might still be in
+                * progress.  Wait for PM_PENDING to clear.
+                */
+               if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+                       ata_port_wait_eh(ap);
+                       WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+               }
 
-static int ata_start_drive(struct ata_device *dev)
-{
-       unsigned int err_mask;
+               /* request PM ops to EH */
+               spin_lock_irqsave(ap->lock, flags);
 
-       err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
-       if (err_mask) {
-               ata_dev_printk(dev, KERN_ERR, "failed to start drive "
-                              "(err_mask=0x%x)\n", err_mask);
-               return -EIO;
+               ap->pm_mesg = mesg;
+               if (wait) {
+                       rc = 0;
+                       ap->pm_result = &rc;
+               }
+
+               ap->pflags |= ATA_PFLAG_PM_PENDING;
+               ap->eh_info.action |= action;
+               ap->eh_info.flags |= ehi_flags;
+
+               ata_port_schedule_eh(ap);
+
+               spin_unlock_irqrestore(ap->lock, flags);
+
+               /* wait and check result */
+               if (wait) {
+                       ata_port_wait_eh(ap);
+                       WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+                       if (rc)
+                               return rc;
+               }
        }
 
        return 0;
 }
 
 /**
- *     ata_device_resume - wakeup a previously suspended devices
- *     @dev: the device to resume
+ *     ata_host_set_suspend - suspend host_set
+ *     @host_set: host_set to suspend
+ *     @mesg: PM message
  *
- *     Kick the drive back into action, by sending it an idle immediate
- *     command and making sure its transfer mode matches between drive
- *     and host.
+ *     Suspend @host_set.  Actual operation is performed by EH.  This
+ *     function requests EH to perform PM operations and waits for EH
+ *     to finish.
  *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
  */
-int ata_device_resume(struct ata_device *dev)
+int ata_host_set_suspend(struct ata_host_set *host_set, pm_message_t mesg)
 {
-       struct ata_port *ap = dev->ap;
+       int i, j, rc;
 
-       if (ap->flags & ATA_FLAG_SUSPENDED) {
-               struct ata_device *failed_dev;
+       rc = ata_host_set_request_pm(host_set, mesg, 0, ATA_EHI_QUIET, 1);
+       if (rc)
+               goto fail;
 
-               ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
-               ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
+       /* EH is quiescent now.  Fail if we have any ready device.
+        * This happens if hotplug occurs between completion of device
+        * suspension and here.
+        */
+       for (i = 0; i < host_set->n_ports; i++) {
+               struct ata_port *ap = host_set->ports[i];
+
+               for (j = 0; j < ATA_MAX_DEVICES; j++) {
+                       struct ata_device *dev = &ap->device[j];
 
-               ap->flags &= ~ATA_FLAG_SUSPENDED;
-               while (ata_set_mode(ap, &failed_dev))
-                       ata_dev_disable(failed_dev);
+                       if (ata_dev_ready(dev)) {
+                               ata_port_printk(ap, KERN_WARNING,
+                                               "suspend failed, device %d "
+                                               "still active\n", dev->devno);
+                               rc = -EBUSY;
+                               goto fail;
+                       }
+               }
        }
-       if (!ata_dev_enabled(dev))
-               return 0;
-       if (dev->class == ATA_DEV_ATA)
-               ata_start_drive(dev);
 
+       host_set->dev->power.power_state = mesg;
        return 0;
+
+ fail:
+       ata_host_set_resume(host_set);
+       return rc;
 }
 
 /**
- *     ata_device_suspend - prepare a device for suspend
- *     @dev: the device to suspend
- *     @state: target power management state
+ *     ata_host_set_resume - resume host_set
+ *     @host_set: host_set to resume
+ *
+ *     Resume @host_set.  Actual operation is performed by EH.  This
+ *     function requests EH to perform PM operations and returns.
+ *     Note that all resume operations are performed parallely.
  *
- *     Flush the cache on the drive, if appropriate, then issue a
- *     standbynow command.
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
  */
-int ata_device_suspend(struct ata_device *dev, pm_message_t state)
+void ata_host_set_resume(struct ata_host_set *host_set)
 {
-       struct ata_port *ap = dev->ap;
-
-       if (!ata_dev_enabled(dev))
-               return 0;
-       if (dev->class == ATA_DEV_ATA)
-               ata_flush_cache(dev);
-
-       if (state.event != PM_EVENT_FREEZE)
-               ata_standby_drive(dev);
-       ap->flags |= ATA_FLAG_SUSPENDED;
-       return 0;
+       ata_host_set_request_pm(host_set, PMSG_ON, ATA_EH_SOFTRESET,
+                               ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
+       host_set->dev->power.power_state = PMSG_ON;
 }
 
 /**
@@ -5144,28 +5167,6 @@ void ata_host_stop (struct ata_host_set *host_set)
                iounmap(host_set->mmio_base);
 }
 
-
-/**
- *     ata_host_remove - Unregister SCSI host structure with upper layers
- *     @ap: Port to unregister
- *     @do_unregister: 1 if we fully unregister, 0 to just stop the port
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-
-static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister)
-{
-       struct Scsi_Host *sh = ap->host;
-
-       DPRINTK("ENTER\n");
-
-       if (do_unregister)
-               scsi_remove_host(sh);
-
-       ap->ops->port_stop(ap);
-}
-
 /**
  *     ata_dev_init - Initialize an ata_device structure
  *     @dev: Device structure to initialize
@@ -5199,41 +5200,29 @@ void ata_dev_init(struct ata_device *dev)
 }
 
 /**
- *     ata_host_init - Initialize an ata_port structure
+ *     ata_port_init - Initialize an ata_port structure
  *     @ap: Structure to initialize
- *     @host: associated SCSI mid-layer structure
  *     @host_set: Collection of hosts to which @ap belongs
  *     @ent: Probe information provided by low-level driver
  *     @port_no: Port number associated with this ata_port
  *
- *     Initialize a new ata_port structure, and its associated
- *     scsi_host.
+ *     Initialize a new ata_port structure.
  *
  *     LOCKING:
  *     Inherited from caller.
  */
-static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
-                         struct ata_host_set *host_set,
-                         const struct ata_probe_ent *ent, unsigned int port_no)
+void ata_port_init(struct ata_port *ap, struct ata_host_set *host_set,
+                  const struct ata_probe_ent *ent, unsigned int port_no)
 {
        unsigned int i;
 
-       host->max_id = 16;
-       host->max_lun = 1;
-       host->max_channel = 1;
-       host->unique_id = ata_unique_id++;
-       host->max_cmd_len = 12;
-
        ap->lock = &host_set->lock;
        ap->flags = ATA_FLAG_DISABLED;
-       ap->id = host->unique_id;
-       ap->host = host;
+       ap->id = ata_unique_id++;
        ap->ctl = ATA_DEVCTL_OBS;
        ap->host_set = host_set;
        ap->dev = ent->dev;
        ap->port_no = port_no;
-       ap->hard_port_no =
-               ent->legacy_mode ? ent->hard_port_no : port_no;
        ap->pio_mask = ent->pio_mask;
        ap->mwdma_mask = ent->mwdma_mask;
        ap->udma_mask = ent->udma_mask;
@@ -5279,7 +5268,28 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
 }
 
 /**
- *     ata_host_add - Attach low-level ATA driver to system
+ *     ata_port_init_shost - Initialize SCSI host associated with ATA port
+ *     @ap: ATA port to initialize SCSI host for
+ *     @shost: SCSI host associated with @ap
+ *
+ *     Initialize SCSI host @shost associated with ATA port @ap.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+static void ata_port_init_shost(struct ata_port *ap, struct Scsi_Host *shost)
+{
+       ap->host = shost;
+
+       shost->unique_id = ap->id;
+       shost->max_id = 16;
+       shost->max_lun = 1;
+       shost->max_channel = 1;
+       shost->max_cmd_len = 12;
+}
+
+/**
+ *     ata_port_add - Attach low-level ATA driver to system
  *     @ent: Information provided by low-level driver
  *     @host_set: Collections of ports to which we add
  *     @port_no: Port number associated with this host
@@ -5292,14 +5302,12 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
  *     RETURNS:
  *     New ata_port on success, for NULL on error.
  */
-
-static struct ata_port * ata_host_add(const struct ata_probe_ent *ent,
+static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
                                      struct ata_host_set *host_set,
                                      unsigned int port_no)
 {
-       struct Scsi_Host *host;
+       struct Scsi_Host *shost;
        struct ata_port *ap;
-       int rc;
 
        DPRINTK("ENTER\n");
 
@@ -5310,25 +5318,40 @@ static struct ata_port * ata_host_add(const struct ata_probe_ent *ent,
                return NULL;
        }
 
-       host = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
-       if (!host)
+       shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
+       if (!shost)
                return NULL;
 
-       host->transportt = &ata_scsi_transport_template;
+       shost->transportt = &ata_scsi_transport_template;
 
-       ap = ata_shost_to_port(host);
+       ap = ata_shost_to_port(shost);
 
-       ata_host_init(ap, host, host_set, ent, port_no);
-
-       rc = ap->ops->port_start(ap);
-       if (rc)
-               goto err_out;
+       ata_port_init(ap, host_set, ent, port_no);
+       ata_port_init_shost(ap, shost);
 
        return ap;
+}
 
-err_out:
-       scsi_host_put(host);
-       return NULL;
+/**
+ *     ata_sas_host_init - Initialize a host_set struct
+ *     @host_set:      host_set to initialize
+ *     @dev:           device host_set is attached to
+ *     @flags: host_set flags
+ *     @ops:           port_ops
+ *
+ *     LOCKING:
+ *     PCI/etc. bus probe sem.
+ *
+ */
+
+void ata_host_set_init(struct ata_host_set *host_set,
+                      struct device *dev, unsigned long flags,
+                      const struct ata_port_operations *ops)
+{
+       spin_lock_init(&host_set->lock);
+       host_set->dev = dev;
+       host_set->flags = flags;
+       host_set->ops = ops;
 }
 
 /**
@@ -5351,7 +5374,7 @@ err_out:
  */
 int ata_device_add(const struct ata_probe_ent *ent)
 {
-       unsigned int count = 0, i;
+       unsigned int i;
        struct device *dev = ent->dev;
        struct ata_host_set *host_set;
        int rc;
@@ -5362,50 +5385,65 @@ int ata_device_add(const struct ata_probe_ent *ent)
                           (ent->n_ports * sizeof(void *)), GFP_KERNEL);
        if (!host_set)
                return 0;
-       spin_lock_init(&host_set->lock);
 
-       host_set->dev = dev;
+       ata_host_set_init(host_set, dev, ent->host_set_flags, ent->port_ops);
        host_set->n_ports = ent->n_ports;
        host_set->irq = ent->irq;
+       host_set->irq2 = ent->irq2;
        host_set->mmio_base = ent->mmio_base;
        host_set->private_data = ent->private_data;
-       host_set->ops = ent->port_ops;
-       host_set->flags = ent->host_set_flags;
 
        /* register each port bound to this device */
-       for (i = 0; i < ent->n_ports; i++) {
+       for (i = 0; i < host_set->n_ports; i++) {
                struct ata_port *ap;
                unsigned long xfer_mode_mask;
+               int irq_line = ent->irq;
 
-               ap = ata_host_add(ent, host_set, i);
+               ap = ata_port_add(ent, host_set, i);
                if (!ap)
                        goto err_out;
 
                host_set->ports[i] = ap;
+
+               /* dummy? */
+               if (ent->dummy_port_mask & (1 << i)) {
+                       ata_port_printk(ap, KERN_INFO, "DUMMY\n");
+                       ap->ops = &ata_dummy_port_ops;
+                       continue;
+               }
+
+               /* start port */
+               rc = ap->ops->port_start(ap);
+               if (rc) {
+                       host_set->ports[i] = NULL;
+                       scsi_host_put(ap->host);
+                       goto err_out;
+               }
+
+               /* Report the secondary IRQ for second channel legacy */
+               if (i == 1 && ent->irq2)
+                       irq_line = ent->irq2;
+
                xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
                                (ap->mwdma_mask << ATA_SHIFT_MWDMA) |
                                (ap->pio_mask << ATA_SHIFT_PIO);
 
                /* print per-port info to dmesg */
                ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX "
-                               "ctl 0x%lX bmdma 0x%lX irq %lu\n",
+                               "ctl 0x%lX bmdma 0x%lX irq %d\n",
                                ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
                                ata_mode_string(xfer_mode_mask),
                                ap->ioaddr.cmd_addr,
                                ap->ioaddr.ctl_addr,
                                ap->ioaddr.bmdma_addr,
-                               ent->irq);
+                               irq_line);
 
                ata_chk_status(ap);
                host_set->ops->irq_clear(ap);
                ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */
-               count++;
        }
 
-       if (!count)
-               goto err_free_ret;
-
-       /* obtain irq, that is shared between channels */
+       /* obtain irq, that may be shared between channels */
        rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
                         DRV_NAME, host_set);
        if (rc) {
@@ -5414,15 +5452,28 @@ int ata_device_add(const struct ata_probe_ent *ent)
                goto err_out;
        }
 
+       /* do we have a second IRQ for the other channel, eg legacy mode */
+       if (ent->irq2) {
+               /* We will get weird core code crashes later if this is true
+                  so trap it now */
+               BUG_ON(ent->irq == ent->irq2);
+
+               rc = request_irq(ent->irq2, ent->port_ops->irq_handler, ent->irq_flags,
+                        DRV_NAME, host_set);
+               if (rc) {
+                       dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
+                                  ent->irq2, rc);
+                       goto err_out_free_irq;
+               }
+       }
+
        /* perform each probe synchronously */
        DPRINTK("probe begin\n");
-       for (i = 0; i < count; i++) {
-               struct ata_port *ap;
+       for (i = 0; i < host_set->n_ports; i++) {
+               struct ata_port *ap = host_set->ports[i];
                u32 scontrol;
                int rc;
 
-               ap = host_set->ports[i];
-
                /* init sata_spd_limit to the current value */
                if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
                        int spd = (scontrol >> 4) & 0xf;
@@ -5441,6 +5492,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
                }
 
                if (ap->ops->error_handler) {
+                       struct ata_eh_info *ehi = &ap->eh_info;
                        unsigned long flags;
 
                        ata_port_probe(ap);
@@ -5448,10 +5500,11 @@ int ata_device_add(const struct ata_probe_ent *ent)
                        /* kick EH for boot probing */
                        spin_lock_irqsave(ap->lock, flags);
 
-                       ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1;
-                       ap->eh_info.action |= ATA_EH_SOFTRESET;
+                       ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+                       ehi->action |= ATA_EH_SOFTRESET;
+                       ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
 
-                       ap->flags |= ATA_FLAG_LOADING;
+                       ap->pflags |= ATA_PFLAG_LOADING;
                        ata_port_schedule_eh(ap);
 
                        spin_unlock_irqrestore(ap->lock, flags);
@@ -5476,7 +5529,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
 
        /* probes are done, now scan each port's disk(s) */
        DPRINTK("host probe begin\n");
-       for (i = 0; i < count; i++) {
+       for (i = 0; i < host_set->n_ports; i++) {
                struct ata_port *ap = host_set->ports[i];
 
                ata_scsi_scan_host(ap);
@@ -5487,12 +5540,17 @@ int ata_device_add(const struct ata_probe_ent *ent)
        VPRINTK("EXIT, returning %u\n", ent->n_ports);
        return ent->n_ports; /* success */
 
+err_out_free_irq:
+       free_irq(ent->irq, host_set);
 err_out:
-       for (i = 0; i < count; i++) {
-               ata_host_remove(host_set->ports[i], 1);
-               scsi_host_put(host_set->ports[i]->host);
+       for (i = 0; i < host_set->n_ports; i++) {
+               struct ata_port *ap = host_set->ports[i];
+               if (ap) {
+                       ap->ops->port_stop(ap);
+                       scsi_host_put(ap->host);
+               }
        }
-err_free_ret:
+
        kfree(host_set);
        VPRINTK("EXIT, returning 0\n");
        return 0;
@@ -5515,11 +5573,11 @@ void ata_port_detach(struct ata_port *ap)
        int i;
 
        if (!ap->ops->error_handler)
-               return;
+               goto skip_eh;
 
        /* tell EH we're leaving & flush EH */
        spin_lock_irqsave(ap->lock, flags);
-       ap->flags |= ATA_FLAG_UNLOADING;
+       ap->pflags |= ATA_PFLAG_UNLOADING;
        spin_unlock_irqrestore(ap->lock, flags);
 
        ata_port_wait_eh(ap);
@@ -5551,6 +5609,7 @@ void ata_port_detach(struct ata_port *ap)
        cancel_delayed_work(&ap->hotplug_task);
        flush_workqueue(ata_aux_wq);
 
+ skip_eh:
        /* remove the associated SCSI host */
        scsi_remove_host(ap->host);
 }
@@ -5574,6 +5633,8 @@ void ata_host_set_remove(struct ata_host_set *host_set)
                ata_port_detach(host_set->ports[i]);
 
        free_irq(host_set->irq, host_set);
+       if (host_set->irq2)
+               free_irq(host_set->irq2, host_set);
 
        for (i = 0; i < host_set->n_ports; i++) {
                struct ata_port *ap = host_set->ports[i];
@@ -5583,10 +5644,11 @@ void ata_host_set_remove(struct ata_host_set *host_set)
                if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
                        struct ata_ioports *ioaddr = &ap->ioaddr;
 
-                       if (ioaddr->cmd_addr == 0x1f0)
-                               release_region(0x1f0, 8);
-                       else if (ioaddr->cmd_addr == 0x170)
-                               release_region(0x170, 8);
+                       /* FIXME: Add -ac IDE pci mods to remove these special cases */
+                       if (ioaddr->cmd_addr == ATA_PRIMARY_CMD)
+                               release_region(ATA_PRIMARY_CMD, 8);
+                       else if (ioaddr->cmd_addr == ATA_SECONDARY_CMD)
+                               release_region(ATA_SECONDARY_CMD, 8);
                }
 
                scsi_host_put(ap->host);
@@ -5619,12 +5681,37 @@ int ata_scsi_release(struct Scsi_Host *host)
        DPRINTK("ENTER\n");
 
        ap->ops->port_disable(ap);
-       ata_host_remove(ap, 0);
+       ap->ops->port_stop(ap);
 
        DPRINTK("EXIT\n");
        return 1;
 }
 
+struct ata_probe_ent *
+ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
+{
+       struct ata_probe_ent *probe_ent;
+
+       probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+       if (!probe_ent) {
+               printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+                      kobject_name(&(dev->kobj)));
+               return NULL;
+       }
+
+       INIT_LIST_HEAD(&probe_ent->node);
+       probe_ent->dev = dev;
+
+       probe_ent->sht = port->sht;
+       probe_ent->host_flags = port->host_flags;
+       probe_ent->pio_mask = port->pio_mask;
+       probe_ent->mwdma_mask = port->mwdma_mask;
+       probe_ent->udma_mask = port->udma_mask;
+       probe_ent->port_ops = port->port_ops;
+
+       return probe_ent;
+}
+
 /**
  *     ata_std_ports - initialize ioaddr with standard port offsets.
  *     @ioaddr: IO address structure to be initialized
@@ -5679,11 +5766,8 @@ void ata_pci_remove_one (struct pci_dev *pdev)
 {
        struct device *dev = pci_dev_to_dev(pdev);
        struct ata_host_set *host_set = dev_get_drvdata(dev);
-       struct ata_host_set *host_set2 = host_set->next;
 
        ata_host_set_remove(host_set);
-       if (host_set2)
-               ata_host_set_remove(host_set2);
 
        pci_release_regions(pdev);
        pci_disable_device(pdev);
@@ -5724,20 +5808,44 @@ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
        return (tmp == bits->val) ? 1 : 0;
 }
 
-int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
+void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
        pci_save_state(pdev);
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
-       return 0;
+
+       if (mesg.event == PM_EVENT_SUSPEND) {
+               pci_disable_device(pdev);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
 }
 
-int ata_pci_device_resume(struct pci_dev *pdev)
+void ata_pci_device_do_resume(struct pci_dev *pdev)
 {
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
        pci_enable_device(pdev);
        pci_set_master(pdev);
+}
+
+int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+       struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+       int rc = 0;
+
+       rc = ata_host_set_suspend(host_set, mesg);
+       if (rc)
+               return rc;
+
+       ata_pci_device_do_suspend(pdev, mesg);
+
+       return 0;
+}
+
+int ata_pci_device_resume(struct pci_dev *pdev)
+{
+       struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+
+       ata_pci_device_do_resume(pdev);
+       ata_host_set_resume(host_set);
        return 0;
 }
 #endif /* CONFIG_PCI */
@@ -5836,6 +5944,39 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
        return tmp;
 }
 
+/*
+ * Dummy port_ops
+ */
+static void ata_dummy_noret(struct ata_port *ap)       { }
+static int ata_dummy_ret0(struct ata_port *ap)         { return 0; }
+static void ata_dummy_qc_noret(struct ata_queued_cmd *qc) { }
+
+static u8 ata_dummy_check_status(struct ata_port *ap)
+{
+       return ATA_DRDY;
+}
+
+static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc)
+{
+       return AC_ERR_SYSTEM;
+}
+
+const struct ata_port_operations ata_dummy_port_ops = {
+       .port_disable           = ata_port_disable,
+       .check_status           = ata_dummy_check_status,
+       .check_altstatus        = ata_dummy_check_status,
+       .dev_select             = ata_noop_dev_select,
+       .qc_prep                = ata_noop_qc_prep,
+       .qc_issue               = ata_dummy_qc_issue,
+       .freeze                 = ata_dummy_noret,
+       .thaw                   = ata_dummy_noret,
+       .error_handler          = ata_dummy_noret,
+       .post_internal_cmd      = ata_dummy_qc_noret,
+       .irq_clear              = ata_dummy_noret,
+       .port_start             = ata_dummy_ret0,
+       .port_stop              = ata_dummy_noret,
+};
+
 /*
  * libata is essentially a library of internal helper functions for
  * low-level ATA host controller drivers.  As such, the API/ABI is
@@ -5843,11 +5984,13 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
  * Do not depend on ABI/API stability.
  */
 
-EXPORT_SYMBOL_GPL(sata_deb_timing_boot);
-EXPORT_SYMBOL_GPL(sata_deb_timing_eh);
-EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst);
+EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
+EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
+EXPORT_SYMBOL_GPL(sata_deb_timing_long);
+EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
 EXPORT_SYMBOL_GPL(ata_std_bios_param);
 EXPORT_SYMBOL_GPL(ata_std_ports);
+EXPORT_SYMBOL_GPL(ata_host_set_init);
 EXPORT_SYMBOL_GPL(ata_device_add);
 EXPORT_SYMBOL_GPL(ata_port_detach);
 EXPORT_SYMBOL_GPL(ata_host_set_remove);
@@ -5917,6 +6060,8 @@ EXPORT_SYMBOL_GPL(sata_scr_write);
 EXPORT_SYMBOL_GPL(sata_scr_write_flush);
 EXPORT_SYMBOL_GPL(ata_port_online);
 EXPORT_SYMBOL_GPL(ata_port_offline);
+EXPORT_SYMBOL_GPL(ata_host_set_suspend);
+EXPORT_SYMBOL_GPL(ata_host_set_resume);
 EXPORT_SYMBOL_GPL(ata_id_string);
 EXPORT_SYMBOL_GPL(ata_id_c_string);
 EXPORT_SYMBOL_GPL(ata_scsi_simulate);
@@ -5931,14 +6076,14 @@ EXPORT_SYMBOL_GPL(ata_pci_host_stop);
 EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
 EXPORT_SYMBOL_GPL(ata_pci_remove_one);
+EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
+EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
 EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
 EXPORT_SYMBOL_GPL(ata_pci_device_resume);
 EXPORT_SYMBOL_GPL(ata_pci_default_filter);
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 #endif /* CONFIG_PCI */
 
-EXPORT_SYMBOL_GPL(ata_device_suspend);
-EXPORT_SYMBOL_GPL(ata_device_resume);
 EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
 EXPORT_SYMBOL_GPL(ata_scsi_device_resume);