diff options
| author | James Smart <James.Smart@Emulex.Com> | 2008-12-04 22:39:40 -0500 |
|---|---|---|
| committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-12-29 12:24:27 -0500 |
| commit | 9f1e1b50ab43a281dbc75c25f11e1926a9ea367a (patch) | |
| tree | a88f66e6205bd1dbff333b1a9da9fb62cd6f0cd5 /drivers | |
| parent | 5b75da2fa2c9570c3c3dbb2f63cae5b4183e0ca3 (diff) | |
[SCSI] lpfc 8.3.0 : Fix some memory handling issues
- Fix mailbox buffer leak on dump mailbox completion
- Fix mbuf leak in lpfc_pci_probe_one() SLI-2 mode error path
- Don't allocate HBQs in interrupt context
- Use correct size for FCP response buffer so that all available sense
data is copied
- Fix jiffies calculation to prevent crash when collecting statistical
data
Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 7 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 14 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 76 |
3 files changed, 23 insertions, 74 deletions
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index e07f12a0871b..7a216d478a94 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
| @@ -255,8 +255,10 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) | |||
| 255 | /* character array used for decoding dist type. */ | 255 | /* character array used for decoding dist type. */ |
| 256 | char dist_char[] = "nabx"; | 256 | char dist_char[] = "nabx"; |
| 257 | 257 | ||
| 258 | if (pmboxq->mb.mbxStatus != MBX_SUCCESS) | 258 | if (pmboxq->mb.mbxStatus != MBX_SUCCESS) { |
| 259 | mempool_free(pmboxq, phba->mbox_mem_pool); | ||
| 259 | return; | 260 | return; |
| 261 | } | ||
| 260 | 262 | ||
| 261 | prg = (struct prog_id *) &prog_id_word; | 263 | prg = (struct prog_id *) &prog_id_word; |
| 262 | 264 | ||
| @@ -274,6 +276,7 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) | |||
| 274 | sprintf(phba->OptionROMVersion, "%d.%d%d%c%d", | 276 | sprintf(phba->OptionROMVersion, "%d.%d%d%c%d", |
| 275 | prg->ver, prg->rev, prg->lev, | 277 | prg->ver, prg->rev, prg->lev, |
| 276 | dist, prg->num); | 278 | dist, prg->num); |
| 279 | mempool_free(pmboxq, phba->mbox_mem_pool); | ||
| 277 | return; | 280 | return; |
| 278 | } | 281 | } |
| 279 | 282 | ||
| @@ -2889,6 +2892,8 @@ out_remove_device: | |||
| 2889 | lpfc_stop_phba_timers(phba); | 2892 | lpfc_stop_phba_timers(phba); |
| 2890 | phba->pport->work_port_events = 0; | 2893 | phba->pport->work_port_events = 0; |
| 2891 | lpfc_disable_intr(phba); | 2894 | lpfc_disable_intr(phba); |
| 2895 | lpfc_sli_hba_down(phba); | ||
| 2896 | lpfc_sli_brdrestart(phba); | ||
| 2892 | out_free_sysfs_attr: | 2897 | out_free_sysfs_attr: |
| 2893 | lpfc_free_sysfs_attr(vport); | 2898 | lpfc_free_sysfs_attr(vport); |
| 2894 | out_destroy_port: | 2899 | out_destroy_port: |
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 51e6a6394951..5f697ace9706 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
| @@ -66,6 +66,8 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) | |||
| 66 | if (cmd->result) | 66 | if (cmd->result) |
| 67 | return; | 67 | return; |
| 68 | 68 | ||
| 69 | latency = jiffies_to_msecs((long)jiffies - (long)lpfc_cmd->start_time); | ||
| 70 | |||
| 69 | spin_lock_irqsave(shost->host_lock, flags); | 71 | spin_lock_irqsave(shost->host_lock, flags); |
| 70 | if (!vport->stat_data_enabled || | 72 | if (!vport->stat_data_enabled || |
| 71 | vport->stat_data_blocked || | 73 | vport->stat_data_blocked || |
| @@ -74,13 +76,15 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) | |||
| 74 | spin_unlock_irqrestore(shost->host_lock, flags); | 76 | spin_unlock_irqrestore(shost->host_lock, flags); |
| 75 | return; | 77 | return; |
| 76 | } | 78 | } |
| 77 | latency = jiffies_to_msecs(jiffies - lpfc_cmd->start_time); | ||
| 78 | 79 | ||
| 79 | if (phba->bucket_type == LPFC_LINEAR_BUCKET) { | 80 | if (phba->bucket_type == LPFC_LINEAR_BUCKET) { |
| 80 | i = (latency + phba->bucket_step - 1 - phba->bucket_base)/ | 81 | i = (latency + phba->bucket_step - 1 - phba->bucket_base)/ |
| 81 | phba->bucket_step; | 82 | phba->bucket_step; |
| 82 | if (i >= LPFC_MAX_BUCKET_COUNT) | 83 | /* check array subscript bounds */ |
| 83 | i = LPFC_MAX_BUCKET_COUNT; | 84 | if (i < 0) |
| 85 | i = 0; | ||
| 86 | else if (i >= LPFC_MAX_BUCKET_COUNT) | ||
| 87 | i = LPFC_MAX_BUCKET_COUNT - 1; | ||
| 84 | } else { | 88 | } else { |
| 85 | for (i = 0; i < LPFC_MAX_BUCKET_COUNT-1; i++) | 89 | for (i = 0; i < LPFC_MAX_BUCKET_COUNT-1; i++) |
| 86 | if (latency <= (phba->bucket_base + | 90 | if (latency <= (phba->bucket_base + |
| @@ -444,14 +448,14 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport) | |||
| 444 | bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd)); | 448 | bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd)); |
| 445 | bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd); | 449 | bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd); |
| 446 | bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64; | 450 | bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64; |
| 447 | bpl[0].tus.w = le32_to_cpu(bpl->tus.w); | 451 | bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w); |
| 448 | 452 | ||
| 449 | /* Setup the physical region for the FCP RSP */ | 453 | /* Setup the physical region for the FCP RSP */ |
| 450 | bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp)); | 454 | bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp)); |
| 451 | bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp)); | 455 | bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp)); |
| 452 | bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp); | 456 | bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp); |
| 453 | bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64; | 457 | bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64; |
| 454 | bpl[1].tus.w = le32_to_cpu(bpl->tus.w); | 458 | bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w); |
| 455 | 459 | ||
| 456 | /* | 460 | /* |
| 457 | * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf, | 461 | * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf, |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4e5b4ee121f1..632feee233ca 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
| @@ -1259,68 +1259,6 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) | |||
| 1259 | } | 1259 | } |
| 1260 | 1260 | ||
| 1261 | /** | 1261 | /** |
| 1262 | * lpfc_sli_replace_hbqbuff: Replace the HBQ buffer with a new buffer. | ||
| 1263 | * @phba: Pointer to HBA context object. | ||
| 1264 | * @tag: Tag for the HBQ buffer. | ||
| 1265 | * | ||
| 1266 | * This function is called from unsolicited event handler code path to get the | ||
| 1267 | * HBQ buffer associated with an unsolicited iocb. This function is called with | ||
| 1268 | * no lock held. It returns the buffer associated with the given tag and posts | ||
| 1269 | * another buffer to the firmware. Note that the new buffer must be allocated | ||
| 1270 | * before taking the hbalock and that the hba lock must be held until it is | ||
| 1271 | * finished with the hbq entry swap. | ||
| 1272 | **/ | ||
| 1273 | static struct lpfc_dmabuf * | ||
| 1274 | lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) | ||
| 1275 | { | ||
| 1276 | struct hbq_dmabuf *hbq_entry, *new_hbq_entry; | ||
| 1277 | uint32_t hbqno; | ||
| 1278 | void *virt; /* virtual address ptr */ | ||
| 1279 | dma_addr_t phys; /* mapped address */ | ||
| 1280 | unsigned long flags; | ||
| 1281 | |||
| 1282 | hbqno = tag >> 16; | ||
| 1283 | new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); | ||
| 1284 | /* Check whether HBQ is still in use */ | ||
| 1285 | spin_lock_irqsave(&phba->hbalock, flags); | ||
| 1286 | if (!phba->hbq_in_use) { | ||
| 1287 | if (new_hbq_entry) | ||
| 1288 | (phba->hbqs[hbqno].hbq_free_buffer)(phba, | ||
| 1289 | new_hbq_entry); | ||
| 1290 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
| 1291 | return NULL; | ||
| 1292 | } | ||
| 1293 | |||
| 1294 | hbq_entry = lpfc_sli_hbqbuf_find(phba, tag); | ||
| 1295 | if (hbq_entry == NULL) { | ||
| 1296 | if (new_hbq_entry) | ||
| 1297 | (phba->hbqs[hbqno].hbq_free_buffer)(phba, | ||
| 1298 | new_hbq_entry); | ||
| 1299 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
| 1300 | return NULL; | ||
| 1301 | } | ||
| 1302 | list_del(&hbq_entry->dbuf.list); | ||
| 1303 | |||
| 1304 | if (new_hbq_entry == NULL) { | ||
| 1305 | list_add_tail(&hbq_entry->dbuf.list, &phba->hbqbuf_in_list); | ||
| 1306 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
| 1307 | return &hbq_entry->dbuf; | ||
| 1308 | } | ||
| 1309 | new_hbq_entry->tag = -1; | ||
| 1310 | phys = new_hbq_entry->dbuf.phys; | ||
| 1311 | virt = new_hbq_entry->dbuf.virt; | ||
| 1312 | new_hbq_entry->dbuf.phys = hbq_entry->dbuf.phys; | ||
| 1313 | new_hbq_entry->dbuf.virt = hbq_entry->dbuf.virt; | ||
| 1314 | hbq_entry->dbuf.phys = phys; | ||
| 1315 | hbq_entry->dbuf.virt = virt; | ||
| 1316 | lpfc_sli_free_hbq(phba, hbq_entry); | ||
| 1317 | list_add_tail(&new_hbq_entry->dbuf.list, &phba->hbqbuf_in_list); | ||
| 1318 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
| 1319 | |||
| 1320 | return &new_hbq_entry->dbuf; | ||
| 1321 | } | ||
| 1322 | |||
| 1323 | /** | ||
| 1324 | * lpfc_sli_get_buff: Get the buffer associated with the buffer tag. | 1262 | * lpfc_sli_get_buff: Get the buffer associated with the buffer tag. |
| 1325 | * @phba: Pointer to HBA context object. | 1263 | * @phba: Pointer to HBA context object. |
| 1326 | * @pring: Pointer to driver SLI ring object. | 1264 | * @pring: Pointer to driver SLI ring object. |
| @@ -1334,13 +1272,17 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) | |||
| 1334 | **/ | 1272 | **/ |
| 1335 | static struct lpfc_dmabuf * | 1273 | static struct lpfc_dmabuf * |
| 1336 | lpfc_sli_get_buff(struct lpfc_hba *phba, | 1274 | lpfc_sli_get_buff(struct lpfc_hba *phba, |
| 1337 | struct lpfc_sli_ring *pring, | 1275 | struct lpfc_sli_ring *pring, |
| 1338 | uint32_t tag) | 1276 | uint32_t tag) |
| 1339 | { | 1277 | { |
| 1278 | struct hbq_dmabuf *hbq_entry; | ||
| 1279 | |||
| 1340 | if (tag & QUE_BUFTAG_BIT) | 1280 | if (tag & QUE_BUFTAG_BIT) |
| 1341 | return lpfc_sli_ring_taggedbuf_get(phba, pring, tag); | 1281 | return lpfc_sli_ring_taggedbuf_get(phba, pring, tag); |
| 1342 | else | 1282 | hbq_entry = lpfc_sli_hbqbuf_find(phba, tag); |
| 1343 | return lpfc_sli_replace_hbqbuff(phba, tag); | 1283 | if (!hbq_entry) |
| 1284 | return NULL; | ||
| 1285 | return &hbq_entry->dbuf; | ||
| 1344 | } | 1286 | } |
| 1345 | 1287 | ||
| 1346 | 1288 | ||
| @@ -1372,8 +1314,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
| 1372 | match = 0; | 1314 | match = 0; |
| 1373 | irsp = &(saveq->iocb); | 1315 | irsp = &(saveq->iocb); |
| 1374 | 1316 | ||
| 1375 | if (irsp->ulpStatus == IOSTAT_NEED_BUFFER) | ||
| 1376 | return 1; | ||
| 1377 | if (irsp->ulpCommand == CMD_ASYNC_STATUS) { | 1317 | if (irsp->ulpCommand == CMD_ASYNC_STATUS) { |
| 1378 | if (pring->lpfc_sli_rcv_async_status) | 1318 | if (pring->lpfc_sli_rcv_async_status) |
| 1379 | pring->lpfc_sli_rcv_async_status(phba, pring, saveq); | 1319 | pring->lpfc_sli_rcv_async_status(phba, pring, saveq); |
