]> err.no Git - linux-2.6/commitdiff
libata: update libata core layer to use devres
authorTejun Heo <htejun@gmail.com>
Sat, 20 Jan 2007 07:00:28 +0000 (16:00 +0900)
committerJeff Garzik <jeff@garzik.org>
Fri, 9 Feb 2007 22:39:37 +0000 (17:39 -0500)
Update libata core layer to use devres.

* ata_device_add() acquires all resources in managed mode.

* ata_host is allocated as devres associated with ata_host_release.

* Port attached status is handled as devres associated with
  ata_host_attach_release().

* Initialization failure and host removal is handedl by releasing
  devres group.

* Except for ata_scsi_release() removal, LLD interface remains the
  same.  Some functions use hacky is_managed test to support both
  managed and unmanaged devices.  These will go away once all LLDs are
  updated to use devres.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/ata/ahci.c
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
include/linux/libata.h

index 649dfa57e51c01df3112579f91d86e5d6f26ea2e..d72568392e6c94b041158b84114be86fa004b67f 100644 (file)
@@ -1784,37 +1784,24 @@ err_out:
        return rc;
 }
 
-static void ahci_remove_one (struct pci_dev *pdev)
+static void ahci_remove_one(struct pci_dev *pdev)
 {
        struct device *dev = pci_dev_to_dev(pdev);
        struct ata_host *host = dev_get_drvdata(dev);
        struct ahci_host_priv *hpriv = host->private_data;
-       unsigned int i;
-       int have_msi;
 
-       ata_host_detach(host);
+       ata_host_remove(host);
 
-       have_msi = hpriv->flags & AHCI_FLAG_MSI;
-       free_irq(host->irq, host);
-
-       for (i = 0; i < host->n_ports; i++) {
-               struct ata_port *ap = host->ports[i];
-
-               ata_scsi_release(ap->scsi_host);
-               scsi_host_put(ap->scsi_host);
-       }
-
-       kfree(hpriv);
        pci_iounmap(pdev, host->mmio_base);
-       kfree(host);
 
-       if (have_msi)
+       if (hpriv->flags & AHCI_FLAG_MSI)
                pci_disable_msi(pdev);
        else
                pci_intx(pdev, 0);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        dev_set_drvdata(dev, NULL);
+       kfree(hpriv);
 }
 
 static int __init ahci_init(void)
index a927c4c8bef31a755fe6a95d724105040c6aef3f..20b2409a0d20858b3b99ae668618cdc07a724e9b 100644 (file)
@@ -5486,28 +5486,25 @@ void ata_host_resume(struct ata_host *host)
  *     LOCKING:
  *     Inherited from caller.
  */
-
-int ata_port_start (struct ata_port *ap)
+int ata_port_start(struct ata_port *ap)
 {
        struct device *dev = ap->dev;
        int rc;
 
-       ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL);
+       ap->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma,
+                                     GFP_KERNEL);
        if (!ap->prd)
                return -ENOMEM;
 
        rc = ata_pad_alloc(ap, dev);
-       if (rc) {
-               dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+       if (rc)
                return rc;
-       }
-
-       DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
 
+       DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd,
+               (unsigned long long)ap->prd_dma);
        return 0;
 }
 
-
 /**
  *     ata_port_stop - Undo ata_port_start()
  *     @ap: Port to shut down
@@ -5519,12 +5516,11 @@ int ata_port_start (struct ata_port *ap)
  *     LOCKING:
  *     Inherited from caller.
  */
-
 void ata_port_stop (struct ata_port *ap)
 {
        struct device *dev = ap->dev;
 
-       dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+       dmam_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
        ata_pad_free(ap, dev);
 }
 
@@ -5707,6 +5703,27 @@ static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
        return ap;
 }
 
+static void ata_host_release(struct device *gendev, void *res)
+{
+       struct ata_host *host = dev_get_drvdata(gendev);
+       int i;
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
+
+               if (!ap)
+                       continue;
+
+               if (ap->ops->port_stop)
+                       ap->ops->port_stop(ap);
+
+               scsi_host_put(ap->scsi_host);
+       }
+
+       if (host->ops->host_stop)
+               host->ops->host_stop(host);
+}
+
 /**
  *     ata_sas_host_init - Initialize a host struct
  *     @host:  host to initialize
@@ -5759,11 +5776,17 @@ int ata_device_add(const struct ata_probe_ent *ent)
                dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n");
                return 0;
        }
+
+       if (!devres_open_group(dev, ata_device_add, GFP_KERNEL))
+               return 0;
+
        /* alloc a container for our list of ATA ports (buses) */
-       host = kzalloc(sizeof(struct ata_host) +
-                      (ent->n_ports * sizeof(void *)), GFP_KERNEL);
+       host = devres_alloc(ata_host_release, sizeof(struct ata_host) +
+                           (ent->n_ports * sizeof(void *)), GFP_KERNEL);
        if (!host)
-               return 0;
+               goto err_out;
+       devres_add(dev, host);
+       dev_set_drvdata(dev, host);
 
        ata_host_init(host, dev, ent->_host_flags, ent->port_ops);
        host->n_ports = ent->n_ports;
@@ -5821,8 +5844,8 @@ int ata_device_add(const struct ata_probe_ent *ent)
        }
 
        /* obtain irq, that may be shared between channels */
-       rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
-                        DRV_NAME, host);
+       rc = devm_request_irq(dev, ent->irq, ent->port_ops->irq_handler,
+                             ent->irq_flags, DRV_NAME, host);
        if (rc) {
                dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
                           ent->irq, rc);
@@ -5835,15 +5858,19 @@ int ata_device_add(const struct ata_probe_ent *ent)
                   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);
+               rc = devm_request_irq(dev, ent->irq2,
+                               ent->port_ops->irq_handler, ent->irq_flags,
+                               DRV_NAME, host);
                if (rc) {
                        dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
                                   ent->irq2, rc);
-                       goto err_out_free_irq;
+                       goto err_out;
                }
        }
 
+       /* resource acquisition complete */
+       devres_close_group(dev, ata_device_add);
+
        /* perform each probe synchronously */
        DPRINTK("probe begin\n");
        for (i = 0; i < host->n_ports; i++) {
@@ -5912,24 +5939,13 @@ int ata_device_add(const struct ata_probe_ent *ent)
                ata_scsi_scan_host(ap);
        }
 
-       dev_set_drvdata(dev, host);
-
        VPRINTK("EXIT, returning %u\n", ent->n_ports);
        return ent->n_ports; /* success */
 
-err_out_free_irq:
-       free_irq(ent->irq, host);
-err_out:
-       for (i = 0; i < host->n_ports; i++) {
-               struct ata_port *ap = host->ports[i];
-               if (ap) {
-                       ap->ops->port_stop(ap);
-                       scsi_host_put(ap->scsi_host);
-               }
-       }
-
-       kfree(host);
-       VPRINTK("EXIT, returning 0\n");
+ err_out:
+       devres_release_group(dev, ata_device_add);
+       dev_set_drvdata(dev, NULL);
+       VPRINTK("EXIT, returning %d\n", rc);
        return 0;
 }
 
@@ -6018,66 +6034,10 @@ void ata_host_detach(struct ata_host *host)
  *     LOCKING:
  *     Inherited from calling layer (may sleep).
  */
-
 void ata_host_remove(struct ata_host *host)
 {
-       unsigned int i;
-
        ata_host_detach(host);
-
-       free_irq(host->irq, host);
-       if (host->irq2)
-               free_irq(host->irq2, host);
-
-       for (i = 0; i < host->n_ports; i++) {
-               struct ata_port *ap = host->ports[i];
-
-               ata_scsi_release(ap->scsi_host);
-
-               if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
-                       struct ata_ioports *ioaddr = &ap->ioaddr;
-
-                       /* 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->scsi_host);
-       }
-
-       if (host->ops->host_stop)
-               host->ops->host_stop(host);
-
-       kfree(host);
-}
-
-/**
- *     ata_scsi_release - SCSI layer callback hook for host unload
- *     @shost: libata host to be unloaded
- *
- *     Performs all duties necessary to shut down a libata port...
- *     Kill port kthread, disable port, and release resources.
- *
- *     LOCKING:
- *     Inherited from SCSI layer.
- *
- *     RETURNS:
- *     One.
- */
-
-int ata_scsi_release(struct Scsi_Host *shost)
-{
-       struct ata_port *ap = ata_shost_to_port(shost);
-
-       DPRINTK("ENTER\n");
-
-       ap->ops->port_disable(ap);
-       ap->ops->port_stop(ap);
-
-       DPRINTK("EXIT\n");
-       return 1;
+       devres_release_group(host->dev, ata_device_add);
 }
 
 struct ata_probe_ent *
@@ -6085,7 +6045,11 @@ 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);
+       /* XXX - the following if can go away once all LLDs are managed */
+       if (!list_empty(&dev->devres_head))
+               probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+       else
+               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)));
@@ -6139,7 +6103,11 @@ void ata_pci_host_stop (struct ata_host *host)
 {
        struct pci_dev *pdev = to_pci_dev(host->dev);
 
-       pci_iounmap(pdev, host->mmio_base);
+       /* XXX - the following if can go away once all LLDs are managed */
+       if (!list_empty(&host->dev->devres_head))
+               pcim_iounmap(pdev, host->mmio_base);
+       else
+               pci_iounmap(pdev, host->mmio_base);
 }
 
 /**
@@ -6155,17 +6123,19 @@ void ata_pci_host_stop (struct ata_host *host)
  *     LOCKING:
  *     Inherited from PCI layer (may sleep).
  */
-
-void ata_pci_remove_one (struct pci_dev *pdev)
+void ata_pci_remove_one(struct pci_dev *pdev)
 {
        struct device *dev = pci_dev_to_dev(pdev);
        struct ata_host *host = dev_get_drvdata(dev);
 
-       ata_host_remove(host);
-
-       pci_release_regions(pdev);
-       pci_disable_device(pdev);
-       dev_set_drvdata(dev, NULL);
+       /* XXX - the following if can go away once all LLDs are managed */
+       if (!list_empty(&host->dev->devres_head)) {
+               ata_host_remove(host);
+               pci_release_regions(pdev);
+               pci_disable_device(pdev);
+               dev_set_drvdata(dev, NULL);
+       } else
+               ata_host_detach(host);
 }
 
 /* move to PCI subsystem */
@@ -6219,7 +6189,11 @@ int ata_pci_device_do_resume(struct pci_dev *pdev)
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
 
-       rc = pci_enable_device(pdev);
+       /* XXX - the following if can go away once all LLDs are managed */
+       if (!list_empty(&pdev->dev.devres_head))
+               rc = pcim_enable_device(pdev);
+       else
+               rc = pci_enable_device(pdev);
        if (rc) {
                dev_printk(KERN_ERR, &pdev->dev,
                           "failed to enable device after resume (%d)\n", rc);
@@ -6458,7 +6432,6 @@ EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
 EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
 EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
 EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
-EXPORT_SYMBOL_GPL(ata_scsi_release);
 EXPORT_SYMBOL_GPL(ata_host_intr);
 EXPORT_SYMBOL_GPL(sata_scr_valid);
 EXPORT_SYMBOL_GPL(sata_scr_read);
index cc229e31432f5180a834935e347e64f823da76f6..0009818a4306e7fb5e18c717f81d57256ebda337 100644 (file)
@@ -3305,7 +3305,8 @@ EXPORT_SYMBOL_GPL(ata_sas_port_init);
 
 void ata_sas_port_destroy(struct ata_port *ap)
 {
-       ap->ops->port_stop(ap);
+       if (ap->ops->port_stop)
+               ap->ops->port_stop(ap);
        kfree(ap);
 }
 EXPORT_SYMBOL_GPL(ata_sas_port_destroy);
index 9bbc8749620afc2d668eb96b6eb0577741a204aa..21efe92a713523707ede86d2d33725f29f9d04df 100644 (file)
@@ -1006,15 +1006,18 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
 int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
                      unsigned int n_ports)
 {
+       struct device *dev = &pdev->dev;
        struct ata_probe_ent *probe_ent = NULL;
        struct ata_port_info *port[2];
        u8 mask;
        unsigned int legacy_mode = 0;
-       int disable_dev_on_err = 1;
        int rc;
 
        DPRINTK("ENTER\n");
 
+       if (!devres_open_group(dev, NULL, GFP_KERNEL))
+               return -ENOMEM;
+
        BUG_ON(n_ports < 1 || n_ports > 2);
 
        port[0] = port_info[0];
@@ -1031,9 +1034,9 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
           boot for the primary video which is BIOS enabled
          */
 
-       rc = pci_enable_device(pdev);
+       rc = pcim_enable_device(pdev);
        if (rc)
-               return rc;
+               goto err_out;
 
        if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
                u8 tmp8;
@@ -1049,7 +1052,8 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
                   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;
+                       rc = -EOPNOTSUPP;
+                       goto err_out;
                }
 #endif
        }
@@ -1057,13 +1061,13 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
        if (!legacy_mode) {
                rc = pci_request_regions(pdev, DRV_NAME);
                if (rc) {
-                       disable_dev_on_err = 0;
+                       pcim_pin_device(pdev);
                        goto err_out;
                }
        } else {
                /* Deal with combined mode hack. This side of the logic all
                   goes away once the combined mode hack is killed in 2.6.21 */
-               if (!request_region(ATA_PRIMARY_CMD, 8, "libata")) {
+               if (!devm_request_region(dev, ATA_PRIMARY_CMD, 8, "libata")) {
                        struct resource *conflict, res;
                        res.start = ATA_PRIMARY_CMD;
                        res.end = ATA_PRIMARY_CMD + 8 - 1;
@@ -1073,7 +1077,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
                        if (!strcmp(conflict->name, "libata"))
                                legacy_mode |= ATA_PORT_PRIMARY;
                        else {
-                               disable_dev_on_err = 0;
+                               pcim_pin_device(pdev);
                                printk(KERN_WARNING "ata: 0x%0X IDE port busy\n" \
                                                    "ata: conflict with %s\n",
                                                    ATA_PRIMARY_CMD,
@@ -1082,7 +1086,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
                } else
                        legacy_mode |= ATA_PORT_PRIMARY;
 
-               if (!request_region(ATA_SECONDARY_CMD, 8, "libata")) {
+               if (!devm_request_region(dev, ATA_SECONDARY_CMD, 8, "libata")) {
                        struct resource *conflict, res;
                        res.start = ATA_SECONDARY_CMD;
                        res.end = ATA_SECONDARY_CMD + 8 - 1;
@@ -1092,7 +1096,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
                        if (!strcmp(conflict->name, "libata"))
                                legacy_mode |= ATA_PORT_SECONDARY;
                        else {
-                               disable_dev_on_err = 0;
+                               pcim_pin_device(pdev);
                                printk(KERN_WARNING "ata: 0x%X IDE port busy\n" \
                                                    "ata: conflict with %s\n",
                                                    ATA_SECONDARY_CMD,
@@ -1112,16 +1116,16 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
        /* we have legacy mode, but all ports are unavailable */
        if (legacy_mode == (1 << 3)) {
                rc = -EBUSY;
-               goto err_out_regions;
+               goto err_out;
        }
 
        /* TODO: If we get no DMA mask we should fall back to PIO */
        rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
        if (rc)
-               goto err_out_regions;
+               goto err_out;
        rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
        if (rc)
-               goto err_out_regions;
+               goto err_out;
 
        if (legacy_mode) {
                probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode);
@@ -1133,40 +1137,22 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
        }
        if (!probe_ent) {
                rc = -ENOMEM;
-               goto err_out_regions;
+               goto err_out;
        }
 
        pci_set_master(pdev);
 
        if (!ata_device_add(probe_ent)) {
                rc = -ENODEV;
-               goto err_out_ent;
+               goto err_out;
        }
 
-       kfree(probe_ent);
-
+       devm_kfree(dev, probe_ent);
+       devres_remove_group(dev, NULL);
        return 0;
 
-err_out_ent:
-       kfree(probe_ent);
-err_out_regions:
-       /* All this conditional stuff is needed for the combined mode hack
-          until 2.6.21 when it can go */
-       if (legacy_mode) {
-               pci_release_region(pdev, 4);
-               if (legacy_mode & ATA_PORT_PRIMARY) {
-                       release_region(ATA_PRIMARY_CMD, 8);
-                       pci_release_region(pdev, 1);
-               }
-               if (legacy_mode & ATA_PORT_SECONDARY) {
-                       release_region(ATA_SECONDARY_CMD, 8);
-                       pci_release_region(pdev, 3);
-               }
-       } else
-               pci_release_regions(pdev);
 err_out:
-       if (disable_dev_on_err)
-               pci_disable_device(pdev);
+       devres_release_group(dev, NULL);
        return rc;
 }
 
index e9a0cfdcfe2c529b7f2cfce7810af7375e3ea74c..f96277ed184fd621fdecd4b907d52eb550ec597e 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <asm/scatterlist.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/ata.h>
 #include <linux/workqueue.h>
 #include <scsi/scsi_host.h>
@@ -726,7 +726,6 @@ extern void ata_host_remove(struct ata_host *host);
 extern int ata_scsi_detect(struct scsi_host_template *sht);
 extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
 extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
-extern int ata_scsi_release(struct Scsi_Host *host);
 extern void ata_sas_port_destroy(struct ata_port *);
 extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
                                           struct ata_port_info *, struct Scsi_Host *);
@@ -1227,14 +1226,14 @@ static inline unsigned int __ac_err_mask(u8 status)
 static inline int ata_pad_alloc(struct ata_port *ap, struct device *dev)
 {
        ap->pad_dma = 0;
-       ap->pad = dma_alloc_coherent(dev, ATA_DMA_PAD_BUF_SZ,
-                                    &ap->pad_dma, GFP_KERNEL);
+       ap->pad = dmam_alloc_coherent(dev, ATA_DMA_PAD_BUF_SZ,
+                                     &ap->pad_dma, GFP_KERNEL);
        return (ap->pad == NULL) ? -ENOMEM : 0;
 }
 
 static inline void ata_pad_free(struct ata_port *ap, struct device *dev)
 {
-       dma_free_coherent(dev, ATA_DMA_PAD_BUF_SZ, ap->pad, ap->pad_dma);
+       dmam_free_coherent(dev, ATA_DMA_PAD_BUF_SZ, ap->pad, ap->pad_dma);
 }
 
 static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host)