[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>
This commit is contained in:
Родитель
5b75da2fa2
Коммит
9f1e1b50ab
|
@ -255,8 +255,10 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
|
||||||
/* character array used for decoding dist type. */
|
/* character array used for decoding dist type. */
|
||||||
char dist_char[] = "nabx";
|
char dist_char[] = "nabx";
|
||||||
|
|
||||||
if (pmboxq->mb.mbxStatus != MBX_SUCCESS)
|
if (pmboxq->mb.mbxStatus != MBX_SUCCESS) {
|
||||||
|
mempool_free(pmboxq, phba->mbox_mem_pool);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
prg = (struct prog_id *) &prog_id_word;
|
prg = (struct prog_id *) &prog_id_word;
|
||||||
|
|
||||||
|
@ -274,6 +276,7 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
|
||||||
sprintf(phba->OptionROMVersion, "%d.%d%d%c%d",
|
sprintf(phba->OptionROMVersion, "%d.%d%d%c%d",
|
||||||
prg->ver, prg->rev, prg->lev,
|
prg->ver, prg->rev, prg->lev,
|
||||||
dist, prg->num);
|
dist, prg->num);
|
||||||
|
mempool_free(pmboxq, phba->mbox_mem_pool);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2889,6 +2892,8 @@ out_remove_device:
|
||||||
lpfc_stop_phba_timers(phba);
|
lpfc_stop_phba_timers(phba);
|
||||||
phba->pport->work_port_events = 0;
|
phba->pport->work_port_events = 0;
|
||||||
lpfc_disable_intr(phba);
|
lpfc_disable_intr(phba);
|
||||||
|
lpfc_sli_hba_down(phba);
|
||||||
|
lpfc_sli_brdrestart(phba);
|
||||||
out_free_sysfs_attr:
|
out_free_sysfs_attr:
|
||||||
lpfc_free_sysfs_attr(vport);
|
lpfc_free_sysfs_attr(vport);
|
||||||
out_destroy_port:
|
out_destroy_port:
|
||||||
|
|
|
@ -66,6 +66,8 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
|
||||||
if (cmd->result)
|
if (cmd->result)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
latency = jiffies_to_msecs((long)jiffies - (long)lpfc_cmd->start_time);
|
||||||
|
|
||||||
spin_lock_irqsave(shost->host_lock, flags);
|
spin_lock_irqsave(shost->host_lock, flags);
|
||||||
if (!vport->stat_data_enabled ||
|
if (!vport->stat_data_enabled ||
|
||||||
vport->stat_data_blocked ||
|
vport->stat_data_blocked ||
|
||||||
|
@ -74,13 +76,15 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
|
||||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
latency = jiffies_to_msecs(jiffies - lpfc_cmd->start_time);
|
|
||||||
|
|
||||||
if (phba->bucket_type == LPFC_LINEAR_BUCKET) {
|
if (phba->bucket_type == LPFC_LINEAR_BUCKET) {
|
||||||
i = (latency + phba->bucket_step - 1 - phba->bucket_base)/
|
i = (latency + phba->bucket_step - 1 - phba->bucket_base)/
|
||||||
phba->bucket_step;
|
phba->bucket_step;
|
||||||
if (i >= LPFC_MAX_BUCKET_COUNT)
|
/* check array subscript bounds */
|
||||||
i = LPFC_MAX_BUCKET_COUNT;
|
if (i < 0)
|
||||||
|
i = 0;
|
||||||
|
else if (i >= LPFC_MAX_BUCKET_COUNT)
|
||||||
|
i = LPFC_MAX_BUCKET_COUNT - 1;
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < LPFC_MAX_BUCKET_COUNT-1; i++)
|
for (i = 0; i < LPFC_MAX_BUCKET_COUNT-1; i++)
|
||||||
if (latency <= (phba->bucket_base +
|
if (latency <= (phba->bucket_base +
|
||||||
|
@ -444,14 +448,14 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport)
|
||||||
bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd));
|
bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd));
|
||||||
bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd);
|
bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd);
|
||||||
bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
|
bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
|
||||||
bpl[0].tus.w = le32_to_cpu(bpl->tus.w);
|
bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w);
|
||||||
|
|
||||||
/* Setup the physical region for the FCP RSP */
|
/* Setup the physical region for the FCP RSP */
|
||||||
bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp));
|
bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp));
|
||||||
bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp));
|
bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp));
|
||||||
bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp);
|
bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp);
|
||||||
bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
|
bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
|
||||||
bpl[1].tus.w = le32_to_cpu(bpl->tus.w);
|
bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf,
|
* Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf,
|
||||||
|
|
|
@ -1258,68 +1258,6 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* lpfc_sli_replace_hbqbuff: Replace the HBQ buffer with a new buffer.
|
|
||||||
* @phba: Pointer to HBA context object.
|
|
||||||
* @tag: Tag for the HBQ buffer.
|
|
||||||
*
|
|
||||||
* This function is called from unsolicited event handler code path to get the
|
|
||||||
* HBQ buffer associated with an unsolicited iocb. This function is called with
|
|
||||||
* no lock held. It returns the buffer associated with the given tag and posts
|
|
||||||
* another buffer to the firmware. Note that the new buffer must be allocated
|
|
||||||
* before taking the hbalock and that the hba lock must be held until it is
|
|
||||||
* finished with the hbq entry swap.
|
|
||||||
**/
|
|
||||||
static struct lpfc_dmabuf *
|
|
||||||
lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
|
|
||||||
{
|
|
||||||
struct hbq_dmabuf *hbq_entry, *new_hbq_entry;
|
|
||||||
uint32_t hbqno;
|
|
||||||
void *virt; /* virtual address ptr */
|
|
||||||
dma_addr_t phys; /* mapped address */
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
hbqno = tag >> 16;
|
|
||||||
new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
|
|
||||||
/* Check whether HBQ is still in use */
|
|
||||||
spin_lock_irqsave(&phba->hbalock, flags);
|
|
||||||
if (!phba->hbq_in_use) {
|
|
||||||
if (new_hbq_entry)
|
|
||||||
(phba->hbqs[hbqno].hbq_free_buffer)(phba,
|
|
||||||
new_hbq_entry);
|
|
||||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
|
|
||||||
if (hbq_entry == NULL) {
|
|
||||||
if (new_hbq_entry)
|
|
||||||
(phba->hbqs[hbqno].hbq_free_buffer)(phba,
|
|
||||||
new_hbq_entry);
|
|
||||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
list_del(&hbq_entry->dbuf.list);
|
|
||||||
|
|
||||||
if (new_hbq_entry == NULL) {
|
|
||||||
list_add_tail(&hbq_entry->dbuf.list, &phba->hbqbuf_in_list);
|
|
||||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
|
||||||
return &hbq_entry->dbuf;
|
|
||||||
}
|
|
||||||
new_hbq_entry->tag = -1;
|
|
||||||
phys = new_hbq_entry->dbuf.phys;
|
|
||||||
virt = new_hbq_entry->dbuf.virt;
|
|
||||||
new_hbq_entry->dbuf.phys = hbq_entry->dbuf.phys;
|
|
||||||
new_hbq_entry->dbuf.virt = hbq_entry->dbuf.virt;
|
|
||||||
hbq_entry->dbuf.phys = phys;
|
|
||||||
hbq_entry->dbuf.virt = virt;
|
|
||||||
lpfc_sli_free_hbq(phba, hbq_entry);
|
|
||||||
list_add_tail(&new_hbq_entry->dbuf.list, &phba->hbqbuf_in_list);
|
|
||||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
|
||||||
|
|
||||||
return &new_hbq_entry->dbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lpfc_sli_get_buff: Get the buffer associated with the buffer tag.
|
* lpfc_sli_get_buff: Get the buffer associated with the buffer tag.
|
||||||
* @phba: Pointer to HBA context object.
|
* @phba: Pointer to HBA context object.
|
||||||
|
@ -1337,10 +1275,14 @@ lpfc_sli_get_buff(struct lpfc_hba *phba,
|
||||||
struct lpfc_sli_ring *pring,
|
struct lpfc_sli_ring *pring,
|
||||||
uint32_t tag)
|
uint32_t tag)
|
||||||
{
|
{
|
||||||
|
struct hbq_dmabuf *hbq_entry;
|
||||||
|
|
||||||
if (tag & QUE_BUFTAG_BIT)
|
if (tag & QUE_BUFTAG_BIT)
|
||||||
return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
|
return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
|
||||||
else
|
hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
|
||||||
return lpfc_sli_replace_hbqbuff(phba, tag);
|
if (!hbq_entry)
|
||||||
|
return NULL;
|
||||||
|
return &hbq_entry->dbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1372,8 +1314,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
||||||
match = 0;
|
match = 0;
|
||||||
irsp = &(saveq->iocb);
|
irsp = &(saveq->iocb);
|
||||||
|
|
||||||
if (irsp->ulpStatus == IOSTAT_NEED_BUFFER)
|
|
||||||
return 1;
|
|
||||||
if (irsp->ulpCommand == CMD_ASYNC_STATUS) {
|
if (irsp->ulpCommand == CMD_ASYNC_STATUS) {
|
||||||
if (pring->lpfc_sli_rcv_async_status)
|
if (pring->lpfc_sli_rcv_async_status)
|
||||||
pring->lpfc_sli_rcv_async_status(phba, pring, saveq);
|
pring->lpfc_sli_rcv_async_status(phba, pring, saveq);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче