Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[pandora-kernel.git] / drivers / ata / libata-sff.c
index c750105..60cd4b1 100644 (file)
@@ -147,7 +147,9 @@ void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
  *     @tf: ATA taskfile register set for storing input
  *
  *     Reads ATA taskfile registers for currently-selected device
- *     into @tf.
+ *     into @tf. Assumes the device has a fully SFF compliant task file
+ *     layout and behaviour. If you device does not (eg has a different
+ *     status method) then you will need to provide a replacement tf_read
  *
  *     LOCKING:
  *     Inherited from caller.
@@ -248,7 +250,7 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc)
  *     LOCKING:
  *     spin_lock_irqsave(host lock)
  */
-void ata_bmdma_start (struct ata_queued_cmd *qc)
+void ata_bmdma_start(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        u8 dmactl;
@@ -415,7 +417,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
        ap->hsm_task_state = HSM_ST_IDLE;
 
        if (qc && (qc->tf.protocol == ATA_PROT_DMA ||
-                  qc->tf.protocol == ATA_PROT_ATAPI_DMA)) {
+                  qc->tf.protocol == ATAPI_PROT_DMA)) {
                u8 host_stat;
 
                host_stat = ap->ops->bmdma_status(ap);
@@ -549,7 +551,7 @@ int ata_pci_init_bmdma(struct ata_host *host)
                return rc;
 
        /* request and iomap DMA region */
-       rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME);
+       rc = pcim_iomap_regions(pdev, 1 << 4, dev_driver_string(gdev));
        if (rc) {
                dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n");
                return -ENOMEM;
@@ -619,7 +621,8 @@ int ata_pci_init_sff_host(struct ata_host *host)
                        continue;
                }
 
-               rc = pcim_iomap_regions(pdev, 0x3 << base, DRV_NAME);
+               rc = pcim_iomap_regions(pdev, 0x3 << base,
+                                       dev_driver_string(gdev));
                if (rc) {
                        dev_printk(KERN_WARNING, gdev,
                                   "failed to request/iomap BARs for port %d "
@@ -710,6 +713,99 @@ int ata_pci_prepare_sff_host(struct pci_dev *pdev,
        return rc;
 }
 
+/**
+ *     ata_pci_activate_sff_host - start SFF host, request IRQ and register it
+ *     @host: target SFF ATA host
+ *     @irq_handler: irq_handler used when requesting IRQ(s)
+ *     @sht: scsi_host_template to use when registering the host
+ *
+ *     This is the counterpart of ata_host_activate() for SFF ATA
+ *     hosts.  This separate helper is necessary because SFF hosts
+ *     use two separate interrupts in legacy mode.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ata_pci_activate_sff_host(struct ata_host *host,
+                             irq_handler_t irq_handler,
+                             struct scsi_host_template *sht)
+{
+       struct device *dev = host->dev;
+       struct pci_dev *pdev = to_pci_dev(dev);
+       const char *drv_name = dev_driver_string(host->dev);
+       int legacy_mode = 0, rc;
+
+       rc = ata_host_start(host);
+       if (rc)
+               return rc;
+
+       if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+               u8 tmp8, mask;
+
+               /* TODO: What if one channel is in native mode ... */
+               pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+               mask = (1 << 2) | (1 << 0);
+               if ((tmp8 & mask) != mask)
+                       legacy_mode = 1;
+#if defined(CONFIG_NO_ATA_LEGACY)
+               /* Some platforms with PCI limits cannot address compat
+                  port space. In that case we punt if their firmware has
+                  left a device in compatibility mode */
+               if (legacy_mode) {
+                       printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
+                       return -EOPNOTSUPP;
+               }
+#endif
+       }
+
+       if (!devres_open_group(dev, NULL, GFP_KERNEL))
+               return -ENOMEM;
+
+       if (!legacy_mode && pdev->irq) {
+               rc = devm_request_irq(dev, pdev->irq, irq_handler,
+                                     IRQF_SHARED, drv_name, host);
+               if (rc)
+                       goto out;
+
+               ata_port_desc(host->ports[0], "irq %d", pdev->irq);
+               ata_port_desc(host->ports[1], "irq %d", pdev->irq);
+       } else if (legacy_mode) {
+               if (!ata_port_is_dummy(host->ports[0])) {
+                       rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
+                                             irq_handler, IRQF_SHARED,
+                                             drv_name, host);
+                       if (rc)
+                               goto out;
+
+                       ata_port_desc(host->ports[0], "irq %d",
+                                     ATA_PRIMARY_IRQ(pdev));
+               }
+
+               if (!ata_port_is_dummy(host->ports[1])) {
+                       rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
+                                             irq_handler, IRQF_SHARED,
+                                             drv_name, host);
+                       if (rc)
+                               goto out;
+
+                       ata_port_desc(host->ports[1], "irq %d",
+                                     ATA_SECONDARY_IRQ(pdev));
+               }
+       }
+
+       rc = ata_host_register(host, sht);
+ out:
+       if (rc == 0)
+               devres_remove_group(dev, NULL);
+       else
+               devres_release_group(dev, NULL);
+
+       return rc;
+}
+
 /**
  *     ata_pci_init_one - Initialize/register PCI IDE host controller
  *     @pdev: Controller to be initialized
@@ -739,8 +835,6 @@ int ata_pci_init_one(struct pci_dev *pdev,
        struct device *dev = &pdev->dev;
        const struct ata_port_info *pi = NULL;
        struct ata_host *host = NULL;
-       u8 mask;
-       int legacy_mode = 0;
        int i, rc;
 
        DPRINTK("ENTER\n");
@@ -762,92 +856,24 @@ int ata_pci_init_one(struct pci_dev *pdev,
        if (!devres_open_group(dev, NULL, GFP_KERNEL))
                return -ENOMEM;
 
-       /* FIXME: Really for ATA it isn't safe because the device may be
-          multi-purpose and we want to leave it alone if it was already
-          enabled. Secondly for shared use as Arjan says we want refcounting
-
-          Checking dev->is_enabled is insufficient as this is not set at
-          boot for the primary video which is BIOS enabled
-         */
-
        rc = pcim_enable_device(pdev);
        if (rc)
-               goto err_out;
-
-       if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-               u8 tmp8;
-
-               /* TODO: What if one channel is in native mode ... */
-               pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
-               mask = (1 << 2) | (1 << 0);
-               if ((tmp8 & mask) != mask)
-                       legacy_mode = 1;
-#if defined(CONFIG_NO_ATA_LEGACY)
-               /* Some platforms with PCI limits cannot address compat
-                  port space. In that case we punt if their firmware has
-                  left a device in compatibility mode */
-               if (legacy_mode) {
-                       printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
-                       rc = -EOPNOTSUPP;
-                       goto err_out;
-               }
-#endif
-       }
+               goto out;
 
-       /* prepare host */
+       /* prepare and activate SFF host */
        rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
        if (rc)
-               goto err_out;
+               goto out;
 
        pci_set_master(pdev);
+       rc = ata_pci_activate_sff_host(host, pi->port_ops->irq_handler,
+                                      pi->sht);
+ out:
+       if (rc == 0)
+               devres_remove_group(&pdev->dev, NULL);
+       else
+               devres_release_group(&pdev->dev, NULL);
 
-       /* start host and request IRQ */
-       rc = ata_host_start(host);
-       if (rc)
-               goto err_out;
-
-       if (!legacy_mode) {
-               rc = devm_request_irq(dev, pdev->irq, pi->port_ops->irq_handler,
-                                     IRQF_SHARED, DRV_NAME, host);
-               if (rc)
-                       goto err_out;
-
-               ata_port_desc(host->ports[0], "irq %d", pdev->irq);
-               ata_port_desc(host->ports[1], "irq %d", pdev->irq);
-       } else {
-               if (!ata_port_is_dummy(host->ports[0])) {
-                       rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
-                                             pi->port_ops->irq_handler,
-                                             IRQF_SHARED, DRV_NAME, host);
-                       if (rc)
-                               goto err_out;
-
-                       ata_port_desc(host->ports[0], "irq %d",
-                                     ATA_PRIMARY_IRQ(pdev));
-               }
-
-               if (!ata_port_is_dummy(host->ports[1])) {
-                       rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
-                                             pi->port_ops->irq_handler,
-                                             IRQF_SHARED, DRV_NAME, host);
-                       if (rc)
-                               goto err_out;
-
-                       ata_port_desc(host->ports[1], "irq %d",
-                                     ATA_SECONDARY_IRQ(pdev));
-               }
-       }
-
-       /* register */
-       rc = ata_host_register(host, pi->sht);
-       if (rc)
-               goto err_out;
-
-       devres_remove_group(dev, NULL);
-       return 0;
-
-err_out:
-       devres_release_group(dev, NULL);
        return rc;
 }
 
@@ -856,7 +882,7 @@ err_out:
  *     @pdev: PCI device
  *
  *     Some PCI ATA devices report simplex mode but in fact can be told to
- *     enter non simplex mode. This implements the neccessary logic to
+ *     enter non simplex mode. This implements the necessary logic to
  *     perform the task on such devices. Calling it on other devices will
  *     have -undefined- behaviour.
  */