[SCSI] sym53c8xx: unmap pci memory after probe errors

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>
This commit is contained in:
Tony Battersby 2009-01-08 12:55:52 -05:00 committed by James Bottomley
parent b409063a9b
commit a71d035de8
1 changed files with 41 additions and 25 deletions

View File

@ -1235,6 +1235,20 @@ static int sym53c8xx_proc_info(struct Scsi_Host *shost, char *buffer,
} }
#endif /* SYM_LINUX_PROC_INFO_SUPPORT */ #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. * 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_data *sym_data;
struct sym_hcb *np = NULL; struct sym_hcb *np = NULL;
struct Scsi_Host *shost; struct Scsi_Host *shost = NULL;
struct pci_dev *pdev = dev->pdev; struct pci_dev *pdev = dev->pdev;
unsigned long flags; unsigned long flags;
struct sym_fw *fw; 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); fw = sym_find_firmware(&dev->chip);
if (!fw) if (!fw)
return NULL; goto attach_failed;
shost = scsi_host_alloc(tpnt, sizeof(*sym_data)); shost = scsi_host_alloc(tpnt, sizeof(*sym_data));
if (!shost) if (!shost)
return NULL; goto attach_failed;
sym_data = shost_priv(shost); 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->maxoffs = dev->chip.offset_max;
np->maxburst = dev->chip.burst_max; np->maxburst = dev->chip.burst_max;
np->myaddr = dev->host_id; 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. * Edit its name.
@ -1336,22 +1357,6 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
goto attach_failed; 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)) if (sym_hcb_attach(shost, fw, dev->nvram))
goto attach_failed; 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)); "TERMINATION, DEVICE POWER etc.!\n", sym_name(np));
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
attach_failed: attach_failed:
if (!shost)
return NULL;
printf_info("sym%d: giving up ...\n", unit); printf_info("sym%d: giving up ...\n", unit);
if (np) if (np)
sym_free_resources(np, pdev, do_free_irq); 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; return NULL;
} }
@ -1700,6 +1706,8 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
struct sym_device sym_dev; struct sym_device sym_dev;
struct sym_nvram nvram; struct sym_nvram nvram;
struct Scsi_Host *shost; struct Scsi_Host *shost;
int do_iounmap = 0;
int do_disable_device = 1;
memset(&sym_dev, 0, sizeof(sym_dev)); memset(&sym_dev, 0, sizeof(sym_dev));
memset(&nvram, 0, sizeof(nvram)); memset(&nvram, 0, sizeof(nvram));
@ -1713,11 +1721,15 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
goto disable; goto disable;
sym_init_device(pdev, &sym_dev); sym_init_device(pdev, &sym_dev);
do_iounmap = 1;
if (sym_check_supported(&sym_dev)) if (sym_check_supported(&sym_dev))
goto free; goto free;
if (sym_check_raid(&sym_dev)) if (sym_check_raid(&sym_dev)) {
goto leave; /* Don't disable the device */ do_disable_device = 0; /* Don't disable the device */
goto free;
}
if (sym_set_workarounds(&sym_dev)) if (sym_set_workarounds(&sym_dev))
goto free; goto free;
@ -1726,6 +1738,7 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
sym_get_nvram(&sym_dev, &nvram); 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); shost = sym_attach(&sym2_template, attach_count, &sym_dev);
if (!shost) if (!shost)
goto free; goto free;
@ -1741,9 +1754,12 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
detach: detach:
sym_detach(pci_get_drvdata(pdev), pdev); sym_detach(pci_get_drvdata(pdev), pdev);
free: free:
if (do_iounmap)
sym_iounmap_device(&sym_dev);
pci_release_regions(pdev); pci_release_regions(pdev);
disable: disable:
pci_disable_device(pdev); if (do_disable_device)
pci_disable_device(pdev);
leave: leave:
return -ENODEV; return -ENODEV;
} }