diff options
author | Tony Battersby <tonyb@cybernetics.com> | 2009-01-08 12:55:52 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-03-12 13:58:16 -0400 |
commit | a71d035de835caa7d14ef69928e0fde9fc241cc0 (patch) | |
tree | eb44f1a045b1d7d8b762c19520437ce9e3a12179 /drivers | |
parent | b409063a9b7a56c0d658feaffedeb74ad71edce7 (diff) |
[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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/sym53c8xx_2/sym_glue.c | 66 |
1 files changed, 41 insertions, 25 deletions
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index a8ac60caadc0..8e69b5c35f58 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c | |||
@@ -1236,6 +1236,20 @@ static int sym53c8xx_proc_info(struct Scsi_Host *shost, char *buffer, | |||
1236 | #endif /* SYM_LINUX_PROC_INFO_SUPPORT */ | 1236 | #endif /* SYM_LINUX_PROC_INFO_SUPPORT */ |
1237 | 1237 | ||
1238 | /* | 1238 | /* |
1239 | * Free resources claimed by sym_init_device(). Note that | ||
1240 | * sym_free_resources() should be used instead of this function after calling | ||
1241 | * sym_attach(). | ||
1242 | */ | ||
1243 | static void __devinit | ||
1244 | sym_iounmap_device(struct sym_device *device) | ||
1245 | { | ||
1246 | if (device->s.ioaddr) | ||
1247 | pci_iounmap(device->pdev, device->s.ioaddr); | ||
1248 | if (device->s.ramaddr) | ||
1249 | pci_iounmap(device->pdev, device->s.ramaddr); | ||
1250 | } | ||
1251 | |||
1252 | /* | ||
1239 | * Free controller resources. | 1253 | * Free controller resources. |
1240 | */ | 1254 | */ |
1241 | static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev, | 1255 | static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev, |
@@ -1272,7 +1286,7 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, | |||
1272 | { | 1286 | { |
1273 | struct sym_data *sym_data; | 1287 | struct sym_data *sym_data; |
1274 | struct sym_hcb *np = NULL; | 1288 | struct sym_hcb *np = NULL; |
1275 | struct Scsi_Host *shost; | 1289 | struct Scsi_Host *shost = NULL; |
1276 | struct pci_dev *pdev = dev->pdev; | 1290 | struct pci_dev *pdev = dev->pdev; |
1277 | unsigned long flags; | 1291 | unsigned long flags; |
1278 | struct sym_fw *fw; | 1292 | struct sym_fw *fw; |
@@ -1287,11 +1301,11 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, | |||
1287 | */ | 1301 | */ |
1288 | fw = sym_find_firmware(&dev->chip); | 1302 | fw = sym_find_firmware(&dev->chip); |
1289 | if (!fw) | 1303 | if (!fw) |
1290 | return NULL; | 1304 | goto attach_failed; |
1291 | 1305 | ||
1292 | shost = scsi_host_alloc(tpnt, sizeof(*sym_data)); | 1306 | shost = scsi_host_alloc(tpnt, sizeof(*sym_data)); |
1293 | if (!shost) | 1307 | if (!shost) |
1294 | return NULL; | 1308 | goto attach_failed; |
1295 | sym_data = shost_priv(shost); | 1309 | sym_data = shost_priv(shost); |
1296 | 1310 | ||
1297 | /* | 1311 | /* |
@@ -1321,6 +1335,13 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, | |||
1321 | np->maxoffs = dev->chip.offset_max; | 1335 | np->maxoffs = dev->chip.offset_max; |
1322 | np->maxburst = dev->chip.burst_max; | 1336 | np->maxburst = dev->chip.burst_max; |
1323 | np->myaddr = dev->host_id; | 1337 | np->myaddr = dev->host_id; |
1338 | np->mmio_ba = (u32)dev->mmio_base; | ||
1339 | np->s.ioaddr = dev->s.ioaddr; | ||
1340 | np->s.ramaddr = dev->s.ramaddr; | ||
1341 | if (!(np->features & FE_RAM)) | ||
1342 | dev->ram_base = 0; | ||
1343 | if (dev->ram_base) | ||
1344 | np->ram_ba = (u32)dev->ram_base; | ||
1324 | 1345 | ||
1325 | /* | 1346 | /* |
1326 | * Edit its name. | 1347 | * Edit its name. |
@@ -1336,22 +1357,6 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, | |||
1336 | goto attach_failed; | 1357 | goto attach_failed; |
1337 | } | 1358 | } |
1338 | 1359 | ||
1339 | /* | ||
1340 | * Try to map the controller chip to | ||
1341 | * virtual and physical memory. | ||
1342 | */ | ||
1343 | np->mmio_ba = (u32)dev->mmio_base; | ||
1344 | np->s.ioaddr = dev->s.ioaddr; | ||
1345 | np->s.ramaddr = dev->s.ramaddr; | ||
1346 | |||
1347 | /* | ||
1348 | * Map on-chip RAM if present and supported. | ||
1349 | */ | ||
1350 | if (!(np->features & FE_RAM)) | ||
1351 | dev->ram_base = 0; | ||
1352 | if (dev->ram_base) | ||
1353 | np->ram_ba = (u32)dev->ram_base; | ||
1354 | |||
1355 | if (sym_hcb_attach(shost, fw, dev->nvram)) | 1360 | if (sym_hcb_attach(shost, fw, dev->nvram)) |
1356 | goto attach_failed; | 1361 | goto attach_failed; |
1357 | 1362 | ||
@@ -1419,12 +1424,13 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, | |||
1419 | "TERMINATION, DEVICE POWER etc.!\n", sym_name(np)); | 1424 | "TERMINATION, DEVICE POWER etc.!\n", sym_name(np)); |
1420 | spin_unlock_irqrestore(shost->host_lock, flags); | 1425 | spin_unlock_irqrestore(shost->host_lock, flags); |
1421 | attach_failed: | 1426 | attach_failed: |
1422 | if (!shost) | ||
1423 | return NULL; | ||
1424 | printf_info("sym%d: giving up ...\n", unit); | 1427 | printf_info("sym%d: giving up ...\n", unit); |
1425 | if (np) | 1428 | if (np) |
1426 | sym_free_resources(np, pdev, do_free_irq); | 1429 | sym_free_resources(np, pdev, do_free_irq); |
1427 | scsi_host_put(shost); | 1430 | else |
1431 | sym_iounmap_device(dev); | ||
1432 | if (shost) | ||
1433 | scsi_host_put(shost); | ||
1428 | 1434 | ||
1429 | return NULL; | 1435 | return NULL; |
1430 | } | 1436 | } |
@@ -1700,6 +1706,8 @@ static int __devinit sym2_probe(struct pci_dev *pdev, | |||
1700 | struct sym_device sym_dev; | 1706 | struct sym_device sym_dev; |
1701 | struct sym_nvram nvram; | 1707 | struct sym_nvram nvram; |
1702 | struct Scsi_Host *shost; | 1708 | struct Scsi_Host *shost; |
1709 | int do_iounmap = 0; | ||
1710 | int do_disable_device = 1; | ||
1703 | 1711 | ||
1704 | memset(&sym_dev, 0, sizeof(sym_dev)); | 1712 | memset(&sym_dev, 0, sizeof(sym_dev)); |
1705 | memset(&nvram, 0, sizeof(nvram)); | 1713 | memset(&nvram, 0, sizeof(nvram)); |
@@ -1713,11 +1721,15 @@ static int __devinit sym2_probe(struct pci_dev *pdev, | |||
1713 | goto disable; | 1721 | goto disable; |
1714 | 1722 | ||
1715 | sym_init_device(pdev, &sym_dev); | 1723 | sym_init_device(pdev, &sym_dev); |
1724 | do_iounmap = 1; | ||
1725 | |||
1716 | if (sym_check_supported(&sym_dev)) | 1726 | if (sym_check_supported(&sym_dev)) |
1717 | goto free; | 1727 | goto free; |
1718 | 1728 | ||
1719 | if (sym_check_raid(&sym_dev)) | 1729 | if (sym_check_raid(&sym_dev)) { |
1720 | goto leave; /* Don't disable the device */ | 1730 | do_disable_device = 0; /* Don't disable the device */ |
1731 | goto free; | ||
1732 | } | ||
1721 | 1733 | ||
1722 | if (sym_set_workarounds(&sym_dev)) | 1734 | if (sym_set_workarounds(&sym_dev)) |
1723 | goto free; | 1735 | goto free; |
@@ -1726,6 +1738,7 @@ static int __devinit sym2_probe(struct pci_dev *pdev, | |||
1726 | 1738 | ||
1727 | sym_get_nvram(&sym_dev, &nvram); | 1739 | sym_get_nvram(&sym_dev, &nvram); |
1728 | 1740 | ||
1741 | do_iounmap = 0; /* Don't sym_iounmap_device() after sym_attach(). */ | ||
1729 | shost = sym_attach(&sym2_template, attach_count, &sym_dev); | 1742 | shost = sym_attach(&sym2_template, attach_count, &sym_dev); |
1730 | if (!shost) | 1743 | if (!shost) |
1731 | goto free; | 1744 | goto free; |
@@ -1741,9 +1754,12 @@ static int __devinit sym2_probe(struct pci_dev *pdev, | |||
1741 | detach: | 1754 | detach: |
1742 | sym_detach(pci_get_drvdata(pdev), pdev); | 1755 | sym_detach(pci_get_drvdata(pdev), pdev); |
1743 | free: | 1756 | free: |
1757 | if (do_iounmap) | ||
1758 | sym_iounmap_device(&sym_dev); | ||
1744 | pci_release_regions(pdev); | 1759 | pci_release_regions(pdev); |
1745 | disable: | 1760 | disable: |
1746 | pci_disable_device(pdev); | 1761 | if (do_disable_device) |
1762 | pci_disable_device(pdev); | ||
1747 | leave: | 1763 | leave: |
1748 | return -ENODEV; | 1764 | return -ENODEV; |
1749 | } | 1765 | } |