[SCSI] sym53c8xx: unmap pci memory after probe errors
authorTony Battersby <tonyb@cybernetics.com>
Thu, 8 Jan 2009 17:55:52 +0000 (12:55 -0500)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Thu, 12 Mar 2009 17:58:16 +0000 (12:58 -0500)
During sym2_probe(), sym_init_device() does pci_iomap(), but there is
no corresponding pci_iounmap() if an error occurs before sym_attach()
copies sym_device::s.{ioaddr,ramaddr} to np.
1) Add the sym_iounmap_device() function.
2) Call sym_iounmap_device() if an error occurs between
   sym_init_device() and the time sym_attach() allocates np.
3) Make sym_attach() copy sym_device::s.{ioaddr,ramaddr} to np before
   calling any function that can fail so that sym_free_resources()
   will do the unmap instead of sym_iounmap_device().

Also fixed by this patch:
During sym2_probe(), if sym_check_raid() returns nonzero, then
pci_release_regions() is never called.

Signed-off-by: Tony Battersby <tonyb@cybernetics.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
drivers/scsi/sym53c8xx_2/sym_glue.c

index a8ac60caadc0af4850a1265f33e7256fbf2bf45c..8e69b5c35f5842b56ca2456a0423b4f8209be20a 100644 (file)
@@ -1235,6 +1235,20 @@ static int sym53c8xx_proc_info(struct Scsi_Host *shost, char *buffer,
 }
 #endif /* SYM_LINUX_PROC_INFO_SUPPORT */
 
+/*
+ * Free resources claimed by sym_init_device().  Note that
+ * sym_free_resources() should be used instead of this function after calling
+ * sym_attach().
+ */
+static void __devinit
+sym_iounmap_device(struct sym_device *device)
+{
+       if (device->s.ioaddr)
+               pci_iounmap(device->pdev, device->s.ioaddr);
+       if (device->s.ramaddr)
+               pci_iounmap(device->pdev, device->s.ramaddr);
+}
+
 /*
  *     Free controller resources.
  */
@@ -1272,7 +1286,7 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
 {
        struct sym_data *sym_data;
        struct sym_hcb *np = NULL;
-       struct Scsi_Host *shost;
+       struct Scsi_Host *shost = NULL;
        struct pci_dev *pdev = dev->pdev;
        unsigned long flags;
        struct sym_fw *fw;
@@ -1287,11 +1301,11 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
         */
        fw = sym_find_firmware(&dev->chip);
        if (!fw)
-               return NULL;
+               goto attach_failed;
 
        shost = scsi_host_alloc(tpnt, sizeof(*sym_data));
        if (!shost)
-               return NULL;
+               goto attach_failed;
        sym_data = shost_priv(shost);
 
        /*
@@ -1321,6 +1335,13 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
        np->maxoffs     = dev->chip.offset_max;
        np->maxburst    = dev->chip.burst_max;
        np->myaddr      = dev->host_id;
+       np->mmio_ba     = (u32)dev->mmio_base;
+       np->s.ioaddr    = dev->s.ioaddr;
+       np->s.ramaddr   = dev->s.ramaddr;
+       if (!(np->features & FE_RAM))
+               dev->ram_base = 0;
+       if (dev->ram_base)
+               np->ram_ba = (u32)dev->ram_base;
 
        /*
         *  Edit its name.
@@ -1336,22 +1357,6 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
                goto attach_failed;
        }
 
-       /*
-        *  Try to map the controller chip to
-        *  virtual and physical memory.
-        */
-       np->mmio_ba = (u32)dev->mmio_base;
-       np->s.ioaddr    = dev->s.ioaddr;
-       np->s.ramaddr   = dev->s.ramaddr;
-
-       /*
-        *  Map on-chip RAM if present and supported.
-        */
-       if (!(np->features & FE_RAM))
-               dev->ram_base = 0;
-       if (dev->ram_base)
-               np->ram_ba = (u32)dev->ram_base;
-
        if (sym_hcb_attach(shost, fw, dev->nvram))
                goto attach_failed;
 
@@ -1419,12 +1424,13 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
                   "TERMINATION, DEVICE POWER etc.!\n", sym_name(np));
        spin_unlock_irqrestore(shost->host_lock, flags);
  attach_failed:
-       if (!shost)
-               return NULL;
        printf_info("sym%d: giving up ...\n", unit);
        if (np)
                sym_free_resources(np, pdev, do_free_irq);
-       scsi_host_put(shost);
+       else
+               sym_iounmap_device(dev);
+       if (shost)
+               scsi_host_put(shost);
 
        return NULL;
  }
@@ -1700,6 +1706,8 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
        struct sym_device sym_dev;
        struct sym_nvram nvram;
        struct Scsi_Host *shost;
+       int do_iounmap = 0;
+       int do_disable_device = 1;
 
        memset(&sym_dev, 0, sizeof(sym_dev));
        memset(&nvram, 0, sizeof(nvram));
@@ -1713,11 +1721,15 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
                goto disable;
 
        sym_init_device(pdev, &sym_dev);
+       do_iounmap = 1;
+
        if (sym_check_supported(&sym_dev))
                goto free;
 
-       if (sym_check_raid(&sym_dev))
-               goto leave;     /* Don't disable the device */
+       if (sym_check_raid(&sym_dev)) {
+               do_disable_device = 0;  /* Don't disable the device */
+               goto free;
+       }
 
        if (sym_set_workarounds(&sym_dev))
                goto free;
@@ -1726,6 +1738,7 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
 
        sym_get_nvram(&sym_dev, &nvram);
 
+       do_iounmap = 0; /* Don't sym_iounmap_device() after sym_attach(). */
        shost = sym_attach(&sym2_template, attach_count, &sym_dev);
        if (!shost)
                goto free;
@@ -1741,9 +1754,12 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
  detach:
        sym_detach(pci_get_drvdata(pdev), pdev);
  free:
+       if (do_iounmap)
+               sym_iounmap_device(&sym_dev);
        pci_release_regions(pdev);
  disable:
-       pci_disable_device(pdev);
+       if (do_disable_device)
+               pci_disable_device(pdev);
  leave:
        return -ENODEV;
 }