forked from Minki/linux
[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: Herton Ronaldo Krzesinski <herton@mandriva.com.br> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
parent
be1066bbcd
commit
9a908c1aa4
@ -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:
|
||||
advansys_wide_free_mem(boardp);
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user