Commit d1f525aa authored by James Smart's avatar James Smart Committed by Christoph Hellwig

Fix driver unload/reload operation.

There are couple of different load/unload issues fixed with this patch.
One of the issues was reported by Junichi Nomura, a patch was submitted
by Johannes Thumsrhirn which did fix one of the problems but the fix in
this patch separates the pring free from the queue free and does not set
the parameter passed in to NULL.

issues:
(1) driver could not be unloaded and reloaded without some Oops or
 Panic occurring.
(2) The driver was panicking because of a corruption in the Memory
Manager when the iocb list was getting allocated.

Root cause for the memory corruption was a double free of the Work Queue
ring pointer memory - Freed once in the lpfc_sli4_queue_free when the CQ
was destroyed and again in lpfc_sli4_queue_free when the WQ was destroyed.

The pring free and the queue free were separated, the pring free was moved
to the wq destroy routine because it a better fit logically to delete the
ring with the wq.

The checkpatch flagged several alignmenet issues that were also corrected
with this patch.

The mboxq was never initialed correctly before it was used by the driver
this patch corrects that issue.
Reported-by: default avatarJunichi Nomura <j-nomura@ce.jp.nec.com>
Signed-off-by: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarJames Smart <james.smart@broadcom.com>
Reviewed-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Tested-by: default avatarJunichi Nomura <j-nomura@ce.jp.nec.com>
parent c07f10cd
...@@ -5815,6 +5815,12 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) ...@@ -5815,6 +5815,12 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_vfi_blk_list); INIT_LIST_HEAD(&phba->sli4_hba.lpfc_vfi_blk_list);
INIT_LIST_HEAD(&phba->lpfc_vpi_blk_list); INIT_LIST_HEAD(&phba->lpfc_vpi_blk_list);
/* Initialize mboxq lists. If the early init routines fail
* these lists need to be correctly initialized.
*/
INIT_LIST_HEAD(&phba->sli.mboxq);
INIT_LIST_HEAD(&phba->sli.mboxq_cmpl);
/* initialize optic_state to 0xFF */ /* initialize optic_state to 0xFF */
phba->sli4_hba.lnk_info.optic_state = 0xff; phba->sli4_hba.lnk_info.optic_state = 0xff;
...@@ -5880,6 +5886,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) ...@@ -5880,6 +5886,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
"READ_NV, mbxStatus x%x\n", "READ_NV, mbxStatus x%x\n",
bf_get(lpfc_mqe_command, &mboxq->u.mqe), bf_get(lpfc_mqe_command, &mboxq->u.mqe),
bf_get(lpfc_mqe_status, &mboxq->u.mqe)); bf_get(lpfc_mqe_status, &mboxq->u.mqe));
mempool_free(mboxq, phba->mbox_mem_pool);
rc = -EIO; rc = -EIO;
goto out_free_bsmbx; goto out_free_bsmbx;
} }
...@@ -7836,7 +7843,7 @@ int ...@@ -7836,7 +7843,7 @@ int
lpfc_sli4_queue_create(struct lpfc_hba *phba) lpfc_sli4_queue_create(struct lpfc_hba *phba)
{ {
struct lpfc_queue *qdesc; struct lpfc_queue *qdesc;
int idx, io_channel, max; int idx, io_channel;
/* /*
* Create HBA Record arrays. * Create HBA Record arrays.
...@@ -7997,15 +8004,6 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) ...@@ -7997,15 +8004,6 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
if (lpfc_alloc_nvme_wq_cq(phba, idx)) if (lpfc_alloc_nvme_wq_cq(phba, idx))
goto out_error; goto out_error;
/* allocate MRQ CQs */
max = phba->cfg_nvme_io_channel;
if (max < phba->cfg_nvmet_mrq)
max = phba->cfg_nvmet_mrq;
for (idx = 0; idx < max; idx++)
if (lpfc_alloc_nvme_wq_cq(phba, idx))
goto out_error;
if (phba->nvmet_support) { if (phba->nvmet_support) {
for (idx = 0; idx < phba->cfg_nvmet_mrq; idx++) { for (idx = 0; idx < phba->cfg_nvmet_mrq; idx++) {
qdesc = lpfc_sli4_queue_alloc(phba, qdesc = lpfc_sli4_queue_alloc(phba,
...@@ -10054,9 +10052,14 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) ...@@ -10054,9 +10052,14 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
/* Stop kthread signal shall trigger work_done one more time */ /* Stop kthread signal shall trigger work_done one more time */
kthread_stop(phba->worker_thread); kthread_stop(phba->worker_thread);
/* Unset the queues shared with the hardware then release all
* allocated resources.
*/
lpfc_sli4_queue_unset(phba);
lpfc_sli4_queue_destroy(phba);
/* Reset SLI4 HBA FCoE function */ /* Reset SLI4 HBA FCoE function */
lpfc_pci_function_reset(phba); lpfc_pci_function_reset(phba);
lpfc_sli4_queue_destroy(phba);
/* Stop the SLI4 device port */ /* Stop the SLI4 device port */
phba->pport->work_port_events = 0; phba->pport->work_port_events = 0;
...@@ -10312,6 +10315,7 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -10312,6 +10315,7 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid)
} }
/* Initialize and populate the iocb list per host */ /* Initialize and populate the iocb list per host */
error = lpfc_init_iocb_list(phba, LPFC_IOCB_LIST_CNT); error = lpfc_init_iocb_list(phba, LPFC_IOCB_LIST_CNT);
if (error) { if (error) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT, lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
...@@ -11092,7 +11096,6 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -11092,7 +11096,6 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
} }
/* Initialize and populate the iocb list per host */ /* Initialize and populate the iocb list per host */
lpfc_printf_log(phba, KERN_INFO, LOG_INIT, lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"2821 initialize iocb list %d.\n", "2821 initialize iocb list %d.\n",
phba->cfg_iocb_cnt*1024); phba->cfg_iocb_cnt*1024);
...@@ -11183,7 +11186,9 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -11183,7 +11186,9 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
if ((phba->nvmet_support == 0) && if ((phba->nvmet_support == 0) &&
(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) { (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) {
/* Create NVME binding with nvme_fc_transport. This /* Create NVME binding with nvme_fc_transport. This
* ensures the vport is initialized. * ensures the vport is initialized. If the localport
* create fails, it should not unload the driver to
* support field issues.
*/ */
error = lpfc_nvme_create_localport(vport); error = lpfc_nvme_create_localport(vport);
if (error) { if (error) {
...@@ -11191,7 +11196,6 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -11191,7 +11196,6 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
"6004 NVME registration failed, " "6004 NVME registration failed, "
"error x%x\n", "error x%x\n",
error); error);
goto out_disable_intr;
} }
} }
......
...@@ -13758,7 +13758,10 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue) ...@@ -13758,7 +13758,10 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue)
lpfc_free_rq_buffer(queue->phba, queue); lpfc_free_rq_buffer(queue->phba, queue);
kfree(queue->rqbp); kfree(queue->rqbp);
} }
kfree(queue->pring);
if (!list_empty(&queue->wq_list))
list_del(&queue->wq_list);
kfree(queue); kfree(queue);
return; return;
} }
...@@ -15561,6 +15564,8 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) ...@@ -15561,6 +15564,8 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq)
} }
/* Remove wq from any list */ /* Remove wq from any list */
list_del_init(&wq->list); list_del_init(&wq->list);
kfree(wq->pring);
wq->pring = NULL;
mempool_free(mbox, wq->phba->mbox_mem_pool); mempool_free(mbox, wq->phba->mbox_mem_pool);
return status; return status;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment