aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorbrking@us.ibm.com <brking@us.ibm.com>2005-11-01 18:01:27 -0500
committerJames Bottomley <jejb@mulgrave.(none)>2005-11-06 14:04:18 -0500
commit12baa4202d74d799f4f8a4bd0455b485e4f8e876 (patch)
tree71601a7098f67c43c2642f32948a4ff01c492e6b /drivers
parent0bc42e35c74c0baab414cf623d6fe1e94cee4ca3 (diff)
[SCSI] ipr: Fix adapter microcode update DMA mapping leak
If the write buffer command that is issued to the ipr adapter to update its microcode fails for some reason, the DMA buffer will never get unmapped. Move the pci_map/unmap out of the IOA reset job so that the buffer is always clearly mapped and unmapped. Signed-off-by: Brian King <brking@us.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/ipr.c104
-rw-r--r--drivers/scsi/ipr.h1
2 files changed, 56 insertions, 49 deletions
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index ad13ae11e2e6..72b588d65562 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -2351,31 +2351,24 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
2351} 2351}
2352 2352
2353/** 2353/**
2354 * ipr_map_ucode_buffer - Map a microcode download buffer 2354 * ipr_build_ucode_ioadl - Build a microcode download IOADL
2355 * @ipr_cmd: ipr command struct 2355 * @ipr_cmd: ipr command struct
2356 * @sglist: scatter/gather list 2356 * @sglist: scatter/gather list
2357 * @len: total length of download buffer
2358 * 2357 *
2359 * Maps a microcode download scatter/gather list for DMA and 2358 * Builds a microcode download IOA data list (IOADL).
2360 * builds the IOADL.
2361 * 2359 *
2362 * Return value:
2363 * 0 on success / -EIO on failure
2364 **/ 2360 **/
2365static int ipr_map_ucode_buffer(struct ipr_cmnd *ipr_cmd, 2361static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd,
2366 struct ipr_sglist *sglist, int len) 2362 struct ipr_sglist *sglist)
2367{ 2363{
2368 struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
2369 struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; 2364 struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
2370 struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; 2365 struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
2371 struct scatterlist *scatterlist = sglist->scatterlist; 2366 struct scatterlist *scatterlist = sglist->scatterlist;
2372 int i; 2367 int i;
2373 2368
2374 ipr_cmd->dma_use_sg = pci_map_sg(ioa_cfg->pdev, scatterlist, 2369 ipr_cmd->dma_use_sg = sglist->num_dma_sg;
2375 sglist->num_sg, DMA_TO_DEVICE);
2376
2377 ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; 2370 ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
2378 ioarcb->write_data_transfer_length = cpu_to_be32(len); 2371 ioarcb->write_data_transfer_length = cpu_to_be32(sglist->buffer_len);
2379 ioarcb->write_ioadl_len = 2372 ioarcb->write_ioadl_len =
2380 cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); 2373 cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
2381 2374
@@ -2386,15 +2379,52 @@ static int ipr_map_ucode_buffer(struct ipr_cmnd *ipr_cmd,
2386 cpu_to_be32(sg_dma_address(&scatterlist[i])); 2379 cpu_to_be32(sg_dma_address(&scatterlist[i]));
2387 } 2380 }
2388 2381
2389 if (likely(ipr_cmd->dma_use_sg)) { 2382 ioadl[i-1].flags_and_data_len |=
2390 ioadl[i-1].flags_and_data_len |= 2383 cpu_to_be32(IPR_IOADL_FLAGS_LAST);
2391 cpu_to_be32(IPR_IOADL_FLAGS_LAST); 2384}
2385
2386/**
2387 * ipr_update_ioa_ucode - Update IOA's microcode
2388 * @ioa_cfg: ioa config struct
2389 * @sglist: scatter/gather list
2390 *
2391 * Initiate an adapter reset to update the IOA's microcode
2392 *
2393 * Return value:
2394 * 0 on success / -EIO on failure
2395 **/
2396static int ipr_update_ioa_ucode(struct ipr_ioa_cfg *ioa_cfg,
2397 struct ipr_sglist *sglist)
2398{
2399 unsigned long lock_flags;
2400
2401 spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
2402
2403 if (ioa_cfg->ucode_sglist) {
2404 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
2405 dev_err(&ioa_cfg->pdev->dev,
2406 "Microcode download already in progress\n");
2407 return -EIO;
2392 } 2408 }
2393 else { 2409
2394 dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n"); 2410 sglist->num_dma_sg = pci_map_sg(ioa_cfg->pdev, sglist->scatterlist,
2411 sglist->num_sg, DMA_TO_DEVICE);
2412
2413 if (!sglist->num_dma_sg) {
2414 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
2415 dev_err(&ioa_cfg->pdev->dev,
2416 "Failed to map microcode download buffer!\n");
2395 return -EIO; 2417 return -EIO;
2396 } 2418 }
2397 2419
2420 ioa_cfg->ucode_sglist = sglist;
2421 ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
2422 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
2423 wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
2424
2425 spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
2426 ioa_cfg->ucode_sglist = NULL;
2427 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
2398 return 0; 2428 return 0;
2399} 2429}
2400 2430
@@ -2417,7 +2447,6 @@ static ssize_t ipr_store_update_fw(struct class_device *class_dev,
2417 struct ipr_ucode_image_header *image_hdr; 2447 struct ipr_ucode_image_header *image_hdr;
2418 const struct firmware *fw_entry; 2448 const struct firmware *fw_entry;
2419 struct ipr_sglist *sglist; 2449 struct ipr_sglist *sglist;
2420 unsigned long lock_flags;
2421 char fname[100]; 2450 char fname[100];
2422 char *src; 2451 char *src;
2423 int len, result, dnld_size; 2452 int len, result, dnld_size;
@@ -2458,35 +2487,17 @@ static ssize_t ipr_store_update_fw(struct class_device *class_dev,
2458 if (result) { 2487 if (result) {
2459 dev_err(&ioa_cfg->pdev->dev, 2488 dev_err(&ioa_cfg->pdev->dev,
2460 "Microcode buffer copy to DMA buffer failed\n"); 2489 "Microcode buffer copy to DMA buffer failed\n");
2461 ipr_free_ucode_buffer(sglist); 2490 goto out;
2462 release_firmware(fw_entry);
2463 return result;
2464 }
2465
2466 spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
2467
2468 if (ioa_cfg->ucode_sglist) {
2469 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
2470 dev_err(&ioa_cfg->pdev->dev,
2471 "Microcode download already in progress\n");
2472 ipr_free_ucode_buffer(sglist);
2473 release_firmware(fw_entry);
2474 return -EIO;
2475 } 2491 }
2476 2492
2477 ioa_cfg->ucode_sglist = sglist; 2493 result = ipr_update_ioa_ucode(ioa_cfg, sglist);
2478 ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
2479 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
2480 wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
2481
2482 spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
2483 ioa_cfg->ucode_sglist = NULL;
2484 spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
2485 2494
2495 if (!result)
2496 result = count;
2497out:
2486 ipr_free_ucode_buffer(sglist); 2498 ipr_free_ucode_buffer(sglist);
2487 release_firmware(fw_entry); 2499 release_firmware(fw_entry);
2488 2500 return result;
2489 return count;
2490} 2501}
2491 2502
2492static struct class_device_attribute ipr_update_fw_attr = { 2503static struct class_device_attribute ipr_update_fw_attr = {
@@ -5291,12 +5302,7 @@ static int ipr_reset_ucode_download(struct ipr_cmnd *ipr_cmd)
5291 ipr_cmd->ioarcb.cmd_pkt.cdb[7] = (sglist->buffer_len & 0x00ff00) >> 8; 5302 ipr_cmd->ioarcb.cmd_pkt.cdb[7] = (sglist->buffer_len & 0x00ff00) >> 8;
5292 ipr_cmd->ioarcb.cmd_pkt.cdb[8] = sglist->buffer_len & 0x0000ff; 5303 ipr_cmd->ioarcb.cmd_pkt.cdb[8] = sglist->buffer_len & 0x0000ff;
5293 5304
5294 if (ipr_map_ucode_buffer(ipr_cmd, sglist, sglist->buffer_len)) { 5305 ipr_build_ucode_ioadl(ipr_cmd, sglist);
5295 dev_err(&ioa_cfg->pdev->dev,
5296 "Failed to map microcode download buffer\n");
5297 return IPR_RC_JOB_CONTINUE;
5298 }
5299
5300 ipr_cmd->job_step = ipr_reset_ucode_download_done; 5306 ipr_cmd->job_step = ipr_reset_ucode_download_done;
5301 5307
5302 ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, 5308 ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout,
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 6d9aef001fe7..1a29eb865b0b 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -811,6 +811,7 @@ struct ipr_trace_entry {
811struct ipr_sglist { 811struct ipr_sglist {
812 u32 order; 812 u32 order;
813 u32 num_sg; 813 u32 num_sg;
814 u32 num_dma_sg;
814 u32 buffer_len; 815 u32 buffer_len;
815 struct scatterlist scatterlist[1]; 816 struct scatterlist scatterlist[1];
816}; 817};