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); |