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

Commit 9a908c1a authored by Herton Ronaldo Krzesinski's avatar Herton Ronaldo Krzesinski Committed by James Bottomley
Browse files

[SCSI] advansys: fix narrow board error path



Error handling on advansys_board_found is fixed, because it's buggy in
the case we have an ASC_NARROW_BOARD set and failure happens on
AscInitAsc1000Driver step: it was freeing items of wrong struct in the
dvc_var union of struct asc_board, which could lead to an oops in the
case we set some of the fields in struct of narrow board as code was
choosing to always freeing wide board fields, and not everything was
being freed/released properly.

Signed-off-by: default avatarHerton Ronaldo Krzesinski <herton@mandriva.com.br>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent be1066bb
Loading
Loading
Loading
Loading
+36 −14
Original line number Diff line number Diff line
@@ -4724,6 +4724,10 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
	BUG_ON((unsigned long)asc_dvc->overrun_buf & 7);
	asc_dvc->overrun_dma = dma_map_single(board->dev, asc_dvc->overrun_buf,
					ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
	if (dma_mapping_error(board->dev, asc_dvc->overrun_dma)) {
		warn_code = -ENOMEM;
		goto err_dma_map;
	}
	phy_addr = cpu_to_le32(asc_dvc->overrun_dma);
	AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
				 (uchar *)&phy_addr, 1);
@@ -4739,14 +4743,23 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
	AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
	if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
		asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
		return warn_code;
		warn_code = UW_ERR;
		goto err_mcode_start;
	}
	if (AscStartChip(iop_base) != 1) {
		asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
		return warn_code;
		warn_code = UW_ERR;
		goto err_mcode_start;
	}

	return warn_code;

err_mcode_start:
	dma_unmap_single(board->dev, asc_dvc->overrun_dma,
			 ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
err_dma_map:
	asc_dvc->overrun_dma = 0;
	return warn_code;
}

static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
@@ -4802,6 +4815,8 @@ static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
	}
	release_firmware(fw);
	warn_code |= AscInitMicroCodeVar(asc_dvc);
	if (!asc_dvc->overrun_dma)
		return warn_code;
	asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
	AscEnableInterrupt(iop_base);
	return warn_code;
@@ -7978,9 +7993,10 @@ static int advansys_reset(struct scsi_cmnd *scp)
		status = AscInitAsc1000Driver(asc_dvc);

		/* Refer to ASC_IERR_* definitions for meaning of 'err_code'. */
		if (asc_dvc->err_code) {
		if (asc_dvc->err_code || !asc_dvc->overrun_dma) {
			scmd_printk(KERN_INFO, scp, "SCSI bus reset error: "
				    "0x%x\n", asc_dvc->err_code);
				    "0x%x, status: 0x%x\n", asc_dvc->err_code,
				    status);
			ret = FAILED;
		} else if (status) {
			scmd_printk(KERN_INFO, scp, "SCSI bus reset warning: "
@@ -12311,7 +12327,7 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost,
		asc_dvc_varp->overrun_buf = kzalloc(ASC_OVERRUN_BSIZE, GFP_KERNEL);
		if (!asc_dvc_varp->overrun_buf) {
			ret = -ENOMEM;
			goto err_free_wide_mem;
			goto err_free_irq;
		}
		warn_code = AscInitAsc1000Driver(asc_dvc_varp);

@@ -12320,30 +12336,36 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost,
					"warn 0x%x, error 0x%x\n",
					asc_dvc_varp->init_state, warn_code,
					asc_dvc_varp->err_code);
			if (asc_dvc_varp->err_code) {
			if (!asc_dvc_varp->overrun_dma) {
				ret = -ENODEV;
				kfree(asc_dvc_varp->overrun_buf);
				goto err_free_mem;
			}
		}
	} else {
		if (advansys_wide_init_chip(shost))
		if (advansys_wide_init_chip(shost)) {
			ret = -ENODEV;
			goto err_free_mem;
		}
	}

	if (ret)
		goto err_free_wide_mem;

	ASC_DBG_PRT_SCSI_HOST(2, shost);

	ret = scsi_add_host(shost, boardp->dev);
	if (ret)
		goto err_free_wide_mem;
		goto err_free_mem;

	scsi_scan_host(shost);
	return 0;

 err_free_wide_mem:
 err_free_mem:
	if (ASC_NARROW_BOARD(boardp)) {
		if (asc_dvc_varp->overrun_dma)
			dma_unmap_single(boardp->dev, asc_dvc_varp->overrun_dma,
					 ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
		kfree(asc_dvc_varp->overrun_buf);
	} else
		advansys_wide_free_mem(boardp);
 err_free_irq:
	free_irq(boardp->irq, shost);
 err_free_dma:
#ifdef CONFIG_ISA