Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a71d035d authored by Tony Battersby's avatar Tony Battersby Committed by James Bottomley
Browse files

[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: default avatarTony Battersby <tonyb@cybernetics.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent b409063a
Loading
Loading
Loading
Loading
+41 −25
Original line number Diff line number Diff line
@@ -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,11 +1424,12 @@ 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);
	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,8 +1754,11 @@ 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:
	if (do_disable_device)
		pci_disable_device(pdev);
 leave:
	return -ENODEV;