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

[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
...@@ -4724,6 +4724,10 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc) ...@@ -4724,6 +4724,10 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
BUG_ON((unsigned long)asc_dvc->overrun_buf & 7); BUG_ON((unsigned long)asc_dvc->overrun_buf & 7);
asc_dvc->overrun_dma = dma_map_single(board->dev, asc_dvc->overrun_buf, asc_dvc->overrun_dma = dma_map_single(board->dev, asc_dvc->overrun_buf,
ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE); 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); phy_addr = cpu_to_le32(asc_dvc->overrun_dma);
AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D, AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
(uchar *)&phy_addr, 1); (uchar *)&phy_addr, 1);
...@@ -4739,14 +4743,23 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc) ...@@ -4739,14 +4743,23 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
asc_dvc->err_code |= ASC_IERR_SET_PC_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) { if (AscStartChip(iop_base) != 1) {
asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
return warn_code; warn_code = UW_ERR;
goto err_mcode_start;
} }
return warn_code; 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) static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
...@@ -4802,6 +4815,8 @@ static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc) ...@@ -4802,6 +4815,8 @@ static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
} }
release_firmware(fw); release_firmware(fw);
warn_code |= AscInitMicroCodeVar(asc_dvc); warn_code |= AscInitMicroCodeVar(asc_dvc);
if (!asc_dvc->overrun_dma)
return warn_code;
asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC; asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
AscEnableInterrupt(iop_base); AscEnableInterrupt(iop_base);
return warn_code; return warn_code;
...@@ -7978,9 +7993,10 @@ static int advansys_reset(struct scsi_cmnd *scp) ...@@ -7978,9 +7993,10 @@ static int advansys_reset(struct scsi_cmnd *scp)
status = AscInitAsc1000Driver(asc_dvc); status = AscInitAsc1000Driver(asc_dvc);
/* Refer to ASC_IERR_* definitions for meaning of 'err_code'. */ /* 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: " 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; ret = FAILED;
} else if (status) { } else if (status) {
scmd_printk(KERN_INFO, scp, "SCSI bus reset warning: " scmd_printk(KERN_INFO, scp, "SCSI bus reset warning: "
...@@ -12311,7 +12327,7 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost, ...@@ -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); asc_dvc_varp->overrun_buf = kzalloc(ASC_OVERRUN_BSIZE, GFP_KERNEL);
if (!asc_dvc_varp->overrun_buf) { if (!asc_dvc_varp->overrun_buf) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_free_wide_mem; goto err_free_irq;
} }
warn_code = AscInitAsc1000Driver(asc_dvc_varp); warn_code = AscInitAsc1000Driver(asc_dvc_varp);
...@@ -12320,30 +12336,36 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost, ...@@ -12320,30 +12336,36 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost,
"warn 0x%x, error 0x%x\n", "warn 0x%x, error 0x%x\n",
asc_dvc_varp->init_state, warn_code, asc_dvc_varp->init_state, warn_code,
asc_dvc_varp->err_code); asc_dvc_varp->err_code);
if (asc_dvc_varp->err_code) { if (!asc_dvc_varp->overrun_dma) {
ret = -ENODEV; ret = -ENODEV;
kfree(asc_dvc_varp->overrun_buf); goto err_free_mem;
} }
} }
} else { } else {
if (advansys_wide_init_chip(shost)) if (advansys_wide_init_chip(shost)) {
ret = -ENODEV; ret = -ENODEV;
goto err_free_mem;
}
} }
if (ret)
goto err_free_wide_mem;
ASC_DBG_PRT_SCSI_HOST(2, shost); ASC_DBG_PRT_SCSI_HOST(2, shost);
ret = scsi_add_host(shost, boardp->dev); ret = scsi_add_host(shost, boardp->dev);
if (ret) if (ret)
goto err_free_wide_mem; goto err_free_mem;
scsi_scan_host(shost); scsi_scan_host(shost);
return 0; 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); advansys_wide_free_mem(boardp);
err_free_irq:
free_irq(boardp->irq, shost); free_irq(boardp->irq, shost);
err_free_dma: err_free_dma:
#ifdef CONFIG_ISA #ifdef CONFIG_ISA
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment