diff options
| author | Al Viro <viro@ftp.linux.org.uk> | 2007-10-29 01:08:38 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-29 10:41:33 -0400 |
| commit | db3a91fe2b425c9adde47069efebdba44e665cef (patch) | |
| tree | 85137ad8531f2dfa667bad11c82116c8f5feed48 | |
| parent | 142956af525002c5378e7d91d81a01189841a785 (diff) | |
deal with resource allocation bugs in arcmsr
a) for type B we should _not_ iounmap() acb->pmu; it's not ioremapped.
b) for type B we should iounmap() two regions we _do_ ioremap.
c) if ioremap() fails, we need to bail out (and clean up).
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | drivers/scsi/arcmsr/arcmsr.h | 9 | ||||
| -rw-r--r-- | drivers/scsi/arcmsr/arcmsr_hba.c | 33 |
2 files changed, 30 insertions, 12 deletions
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index 3c38cd8d7117..a67e29f83ae5 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h | |||
| @@ -348,14 +348,6 @@ struct MessageUnit_B | |||
| 348 | uint32_t __iomem *ioctl_rbuffer_reg; | 348 | uint32_t __iomem *ioctl_rbuffer_reg; |
| 349 | }; | 349 | }; |
| 350 | 350 | ||
| 351 | struct MessageUnit | ||
| 352 | { | ||
| 353 | union | ||
| 354 | { | ||
| 355 | struct MessageUnit_A pmu_A; | ||
| 356 | struct MessageUnit_B pmu_B; | ||
| 357 | } u; | ||
| 358 | }; | ||
| 359 | /* | 351 | /* |
| 360 | ******************************************************************************* | 352 | ******************************************************************************* |
| 361 | ** Adapter Control Block | 353 | ** Adapter Control Block |
| @@ -375,7 +367,6 @@ struct AdapterControlBlock | |||
| 375 | uint32_t outbound_int_enable; | 367 | uint32_t outbound_int_enable; |
| 376 | 368 | ||
| 377 | union { | 369 | union { |
| 378 | struct MessageUnit * pmu; | ||
| 379 | struct MessageUnit_A __iomem * pmuA; | 370 | struct MessageUnit_A __iomem * pmuA; |
| 380 | struct MessageUnit_B * pmuB; | 371 | struct MessageUnit_B * pmuB; |
| 381 | }; | 372 | }; |
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 2f34cdb0bec1..d466a2dac1db 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c | |||
| @@ -240,14 +240,18 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) | |||
| 240 | if (!acb->pmuA) { | 240 | if (!acb->pmuA) { |
| 241 | printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", | 241 | printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", |
| 242 | acb->host->host_no); | 242 | acb->host->host_no); |
| 243 | return -ENOMEM; | ||
| 243 | } | 244 | } |
| 244 | 245 | ||
| 245 | dma_coherent = dma_alloc_coherent(&pdev->dev, | 246 | dma_coherent = dma_alloc_coherent(&pdev->dev, |
| 246 | ARCMSR_MAX_FREECCB_NUM * | 247 | ARCMSR_MAX_FREECCB_NUM * |
| 247 | sizeof (struct CommandControlBlock) + 0x20, | 248 | sizeof (struct CommandControlBlock) + 0x20, |
| 248 | &dma_coherent_handle, GFP_KERNEL); | 249 | &dma_coherent_handle, GFP_KERNEL); |
| 249 | if (!dma_coherent) | 250 | |
| 251 | if (!dma_coherent) { | ||
| 252 | iounmap(acb->pmuA); | ||
| 250 | return -ENOMEM; | 253 | return -ENOMEM; |
| 254 | } | ||
| 251 | 255 | ||
| 252 | acb->dma_coherent = dma_coherent; | 256 | acb->dma_coherent = dma_coherent; |
| 253 | acb->dma_coherent_handle = dma_coherent_handle; | 257 | acb->dma_coherent_handle = dma_coherent_handle; |
| @@ -331,8 +335,16 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) | |||
| 331 | acb->pmuB = reg; | 335 | acb->pmuB = reg; |
| 332 | mem_base0 = ioremap(pci_resource_start(pdev, 0), | 336 | mem_base0 = ioremap(pci_resource_start(pdev, 0), |
| 333 | pci_resource_len(pdev, 0)); | 337 | pci_resource_len(pdev, 0)); |
| 338 | if (!mem_base0) | ||
| 339 | goto out; | ||
| 340 | |||
| 334 | mem_base1 = ioremap(pci_resource_start(pdev, 2), | 341 | mem_base1 = ioremap(pci_resource_start(pdev, 2), |
| 335 | pci_resource_len(pdev, 2)); | 342 | pci_resource_len(pdev, 2)); |
| 343 | if (!mem_base1) { | ||
| 344 | iounmap(mem_base0); | ||
| 345 | goto out; | ||
| 346 | } | ||
| 347 | |||
| 336 | reg->drv2iop_doorbell_reg = mem_base0 + ARCMSR_DRV2IOP_DOORBELL; | 348 | reg->drv2iop_doorbell_reg = mem_base0 + ARCMSR_DRV2IOP_DOORBELL; |
| 337 | reg->drv2iop_doorbell_mask_reg = mem_base0 + | 349 | reg->drv2iop_doorbell_mask_reg = mem_base0 + |
| 338 | ARCMSR_DRV2IOP_DOORBELL_MASK; | 350 | ARCMSR_DRV2IOP_DOORBELL_MASK; |
| @@ -357,6 +369,12 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) | |||
| 357 | break; | 369 | break; |
| 358 | } | 370 | } |
| 359 | return 0; | 371 | return 0; |
| 372 | |||
| 373 | out: | ||
| 374 | dma_free_coherent(&acb->pdev->dev, | ||
| 375 | ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20, | ||
| 376 | acb->dma_coherent, acb->dma_coherent_handle); | ||
| 377 | return -ENOMEM; | ||
| 360 | } | 378 | } |
| 361 | 379 | ||
| 362 | static int arcmsr_probe(struct pci_dev *pdev, | 380 | static int arcmsr_probe(struct pci_dev *pdev, |
| @@ -449,7 +467,6 @@ static int arcmsr_probe(struct pci_dev *pdev, | |||
| 449 | free_irq(pdev->irq, acb); | 467 | free_irq(pdev->irq, acb); |
| 450 | out_free_ccb_pool: | 468 | out_free_ccb_pool: |
| 451 | arcmsr_free_ccb_pool(acb); | 469 | arcmsr_free_ccb_pool(acb); |
| 452 | iounmap(acb->pmu); | ||
| 453 | out_release_regions: | 470 | out_release_regions: |
| 454 | pci_release_regions(pdev); | 471 | pci_release_regions(pdev); |
| 455 | out_host_put: | 472 | out_host_put: |
| @@ -810,7 +827,6 @@ static void arcmsr_remove(struct pci_dev *pdev) | |||
| 810 | } | 827 | } |
| 811 | 828 | ||
| 812 | free_irq(pdev->irq, acb); | 829 | free_irq(pdev->irq, acb); |
| 813 | iounmap(acb->pmu); | ||
| 814 | arcmsr_free_ccb_pool(acb); | 830 | arcmsr_free_ccb_pool(acb); |
| 815 | pci_release_regions(pdev); | 831 | pci_release_regions(pdev); |
| 816 | 832 | ||
| @@ -1018,6 +1034,17 @@ static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) | |||
| 1018 | 1034 | ||
| 1019 | static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) | 1035 | static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) |
| 1020 | { | 1036 | { |
| 1037 | switch (acb->adapter_type) { | ||
| 1038 | case ACB_ADAPTER_TYPE_A: { | ||
| 1039 | iounmap(acb->pmuA); | ||
| 1040 | break; | ||
| 1041 | } | ||
| 1042 | case ACB_ADAPTER_TYPE_B: { | ||
| 1043 | struct MessageUnit_B *reg = acb->pmuB; | ||
| 1044 | iounmap(reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL); | ||
| 1045 | iounmap(reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER); | ||
| 1046 | } | ||
| 1047 | } | ||
| 1021 | dma_free_coherent(&acb->pdev->dev, | 1048 | dma_free_coherent(&acb->pdev->dev, |
| 1022 | ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, | 1049 | ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, |
| 1023 | acb->dma_coherent, | 1050 | acb->dma_coherent, |
