Skip to content

Commit

Permalink
scsi: lpfc: Fix error handling for mailboxes completed in MBX_POLL mode
Browse files Browse the repository at this point in the history
[ Upstream commit 304ee43 ]

In SLI-4, when performing a mailbox command with MBX_POLL, the driver uses
the BMBX register to send the command rather than the MQ. A flag is set
indicating the BMBX register is active and saves the mailbox job struct
(mboxq) in the mbox_active element of the adapter. The routine then waits
for completion or timeout. The mailbox job struct is not freed by the
routine. In cases of timeout, the adapter will be reset. The
lpfc_sli_mbox_sys_flush() routine will clean up the mbox in preparation for
the reset. It clears the BMBX active flag and marks the job structure as
MBX_NOT_FINISHED. But, it never frees the mboxq job structure. Expectation
in both normal completion and timeout cases is that the issuer of the mbx
command will free the structure.  Unfortunately, not all calling paths are
freeing the memory in cases of error.

All calling paths were looked at and updated, if missing, to free the mboxq
memory regardless of completion status.

Link: https://lore.kernel.org/r/20210412013127.2387-7-jsmart2021@gmail.com
Co-developed-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
jsmart-gh authored and gregkh committed May 12, 2021
1 parent d30a8a2 commit 49bff90
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 56 deletions.
75 changes: 45 additions & 30 deletions drivers/scsi/lpfc/lpfc_attr.c
Expand Up @@ -1687,8 +1687,7 @@ lpfc_set_trunking(struct lpfc_hba *phba, char *buff_out)
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
"0071 Set trunk mode failed with status: %d",
rc);
if (rc != MBX_TIMEOUT)
mempool_free(mbox, phba->mbox_mem_pool);
mempool_free(mbox, phba->mbox_mem_pool);

return 0;
}
Expand Down Expand Up @@ -6793,15 +6792,19 @@ lpfc_get_stats(struct Scsi_Host *shost)
pmboxq->ctx_buf = NULL;
pmboxq->vport = vport;

if (vport->fc_flag & FC_OFFLINE_MODE)
if (vport->fc_flag & FC_OFFLINE_MODE) {
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);

if (rc != MBX_SUCCESS) {
if (rc != MBX_TIMEOUT)
if (rc != MBX_SUCCESS) {
mempool_free(pmboxq, phba->mbox_mem_pool);
return NULL;
return NULL;
}
} else {
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
if (rc != MBX_TIMEOUT)
mempool_free(pmboxq, phba->mbox_mem_pool);
return NULL;
}
}

memset(hs, 0, sizeof (struct fc_host_statistics));
Expand All @@ -6825,15 +6828,19 @@ lpfc_get_stats(struct Scsi_Host *shost)
pmboxq->ctx_buf = NULL;
pmboxq->vport = vport;

if (vport->fc_flag & FC_OFFLINE_MODE)
if (vport->fc_flag & FC_OFFLINE_MODE) {
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);

if (rc != MBX_SUCCESS) {
if (rc != MBX_TIMEOUT)
if (rc != MBX_SUCCESS) {
mempool_free(pmboxq, phba->mbox_mem_pool);
return NULL;
return NULL;
}
} else {
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
if (rc != MBX_TIMEOUT)
mempool_free(pmboxq, phba->mbox_mem_pool);
return NULL;
}
}

hs->link_failure_count = pmb->un.varRdLnk.linkFailureCnt;
Expand Down Expand Up @@ -6906,15 +6913,19 @@ lpfc_reset_stats(struct Scsi_Host *shost)
pmboxq->vport = vport;

if ((vport->fc_flag & FC_OFFLINE_MODE) ||
(!(psli->sli_flag & LPFC_SLI_ACTIVE)))
(!(psli->sli_flag & LPFC_SLI_ACTIVE))) {
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);

if (rc != MBX_SUCCESS) {
if (rc != MBX_TIMEOUT)
if (rc != MBX_SUCCESS) {
mempool_free(pmboxq, phba->mbox_mem_pool);
return;
return;
}
} else {
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
if (rc != MBX_TIMEOUT)
mempool_free(pmboxq, phba->mbox_mem_pool);
return;
}
}

memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
Expand All @@ -6924,15 +6935,19 @@ lpfc_reset_stats(struct Scsi_Host *shost)
pmboxq->vport = vport;

if ((vport->fc_flag & FC_OFFLINE_MODE) ||
(!(psli->sli_flag & LPFC_SLI_ACTIVE)))
(!(psli->sli_flag & LPFC_SLI_ACTIVE))) {
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
if (rc != MBX_SUCCESS) {
mempool_free(pmboxq, phba->mbox_mem_pool);
return;
}
} else {
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);

if (rc != MBX_SUCCESS) {
if (rc != MBX_TIMEOUT)
mempool_free( pmboxq, phba->mbox_mem_pool);
return;
if (rc != MBX_SUCCESS) {
if (rc != MBX_TIMEOUT)
mempool_free(pmboxq, phba->mbox_mem_pool);
return;
}
}

lso->link_failure_count = pmb->un.varRdLnk.linkFailureCnt;
Expand Down
9 changes: 3 additions & 6 deletions drivers/scsi/lpfc/lpfc_init.c
Expand Up @@ -9660,8 +9660,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
"3250 QUERY_FW_CFG mailbox failed with status "
"x%x add_status x%x, mbx status x%x\n",
shdr_status, shdr_add_status, rc);
if (rc != MBX_TIMEOUT)
mempool_free(mboxq, phba->mbox_mem_pool);
mempool_free(mboxq, phba->mbox_mem_pool);
rc = -ENXIO;
goto out_error;
}
Expand All @@ -9677,8 +9676,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
"ulp1_mode:x%x\n", phba->sli4_hba.fw_func_mode,
phba->sli4_hba.ulp0_mode, phba->sli4_hba.ulp1_mode);

if (rc != MBX_TIMEOUT)
mempool_free(mboxq, phba->mbox_mem_pool);
mempool_free(mboxq, phba->mbox_mem_pool);

/*
* Set up HBA Event Queues (EQs)
Expand Down Expand Up @@ -10276,8 +10274,7 @@ lpfc_pci_function_reset(struct lpfc_hba *phba)
shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
&shdr->response);
if (rc != MBX_TIMEOUT)
mempool_free(mboxq, phba->mbox_mem_pool);
mempool_free(mboxq, phba->mbox_mem_pool);
if (shdr_status || shdr_add_status || rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
"0495 SLI_FUNCTION_RESET mailbox "
Expand Down
42 changes: 22 additions & 20 deletions drivers/scsi/lpfc/lpfc_sli.c
Expand Up @@ -5683,12 +5683,10 @@ lpfc_sli4_get_ctl_attr(struct lpfc_hba *phba)
phba->sli4_hba.lnk_info.lnk_no,
phba->BIOSVersion);
out_free_mboxq:
if (rc != MBX_TIMEOUT) {
if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG)
lpfc_sli4_mbox_cmd_free(phba, mboxq);
else
mempool_free(mboxq, phba->mbox_mem_pool);
}
if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG)
lpfc_sli4_mbox_cmd_free(phba, mboxq);
else
mempool_free(mboxq, phba->mbox_mem_pool);
return rc;
}

Expand Down Expand Up @@ -5789,12 +5787,10 @@ lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba)
}

out_free_mboxq:
if (rc != MBX_TIMEOUT) {
if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG)
lpfc_sli4_mbox_cmd_free(phba, mboxq);
else
mempool_free(mboxq, phba->mbox_mem_pool);
}
if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG)
lpfc_sli4_mbox_cmd_free(phba, mboxq);
else
mempool_free(mboxq, phba->mbox_mem_pool);
return rc;
}

Expand Down Expand Up @@ -17082,8 +17078,7 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq,
"2509 RQ_DESTROY mailbox failed with "
"status x%x add_status x%x, mbx status x%x\n",
shdr_status, shdr_add_status, rc);
if (rc != MBX_TIMEOUT)
mempool_free(mbox, hrq->phba->mbox_mem_pool);
mempool_free(mbox, hrq->phba->mbox_mem_pool);
return -ENXIO;
}
bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request,
Expand Down Expand Up @@ -17180,7 +17175,9 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba,
shdr = (union lpfc_sli4_cfg_shdr *) &post_sgl_pages->header.cfg_shdr;
shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
if (rc != MBX_TIMEOUT)
if (!phba->sli4_hba.intr_enable)
mempool_free(mbox, phba->mbox_mem_pool);
else if (rc != MBX_TIMEOUT)
mempool_free(mbox, phba->mbox_mem_pool);
if (shdr_status || shdr_add_status || rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
Expand Down Expand Up @@ -17377,7 +17374,9 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba,
shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr;
shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
if (rc != MBX_TIMEOUT)
if (!phba->sli4_hba.intr_enable)
lpfc_sli4_mbox_cmd_free(phba, mbox);
else if (rc != MBX_TIMEOUT)
lpfc_sli4_mbox_cmd_free(phba, mbox);
if (shdr_status || shdr_add_status || rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
Expand Down Expand Up @@ -17490,7 +17489,9 @@ lpfc_sli4_post_io_sgl_block(struct lpfc_hba *phba, struct list_head *nblist,
shdr = (union lpfc_sli4_cfg_shdr *)&sgl->cfg_shdr;
shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
if (rc != MBX_TIMEOUT)
if (!phba->sli4_hba.intr_enable)
lpfc_sli4_mbox_cmd_free(phba, mbox);
else if (rc != MBX_TIMEOUT)
lpfc_sli4_mbox_cmd_free(phba, mbox);
if (shdr_status || shdr_add_status || rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
Expand Down Expand Up @@ -18840,8 +18841,7 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)
shdr = (union lpfc_sli4_cfg_shdr *) &hdr_tmpl->header.cfg_shdr;
shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
if (rc != MBX_TIMEOUT)
mempool_free(mboxq, phba->mbox_mem_pool);
mempool_free(mboxq, phba->mbox_mem_pool);
if (shdr_status || shdr_add_status || rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
"2514 POST_RPI_HDR mailbox failed with "
Expand Down Expand Up @@ -20085,7 +20085,9 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list,
break;
}
}
if (rc != MBX_TIMEOUT)
if (!phba->sli4_hba.intr_enable)
mempool_free(mbox, phba->mbox_mem_pool);
else if (rc != MBX_TIMEOUT)
mempool_free(mbox, phba->mbox_mem_pool);
if (shdr_status || shdr_add_status || rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
Expand Down

0 comments on commit 49bff90

Please sign in to comment.