aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/lpfc/lpfc_hbadisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c67
1 files changed, 65 insertions, 2 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index f64ce88e8a0..371f41e886d 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -108,6 +108,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
struct lpfc_vport *vport;
struct lpfc_hba *phba;
struct lpfc_work_evt *evtp;
+ int put_node;
+ int put_rport;
rdata = rport->dd_data;
ndlp = rdata->pnode;
@@ -128,6 +130,25 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
"rport devlosscb: sid:x%x did:x%x flg:x%x",
ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
+ /* Don't defer this if we are in the process of deleting the vport
+ * or unloading the driver. The unload will cleanup the node
+ * appropriately we just need to cleanup the ndlp rport info here.
+ */
+ if (vport->load_flag & FC_UNLOADING) {
+ put_node = rdata->pnode != NULL;
+ put_rport = ndlp->rport != NULL;
+ rdata->pnode = NULL;
+ ndlp->rport = NULL;
+ if (put_node)
+ lpfc_nlp_put(ndlp);
+ if (put_rport)
+ put_device(&rport->dev);
+ return;
+ }
+
+ if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+ return;
+
evtp = &ndlp->dev_loss_evt;
if (!list_empty(&evtp->evt_listp))
@@ -175,8 +196,23 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
"rport devlosstmo:did:x%x type:x%x id:x%x",
ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id);
- if (!(vport->load_flag & FC_UNLOADING) &&
- ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+ /* Don't defer this if we are in the process of deleting the vport
+ * or unloading the driver. The unload will cleanup the node
+ * appropriately we just need to cleanup the ndlp rport info here.
+ */
+ if (vport->load_flag & FC_UNLOADING) {
+ put_node = rdata->pnode != NULL;
+ put_rport = ndlp->rport != NULL;
+ rdata->pnode = NULL;
+ ndlp->rport = NULL;
+ if (put_node)
+ lpfc_nlp_put(ndlp);
+ if (put_rport)
+ put_device(&rport->dev);
+ return;
+ }
+
+ if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
return;
if (ndlp->nlp_type & NLP_FABRIC) {
@@ -1965,12 +2001,39 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
static void
lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_rport_data *rdata;
+ LPFC_MBOXQ_t *mbox;
+ int rc;
if (ndlp->nlp_flag & NLP_DELAY_TMO) {
lpfc_cancel_retry_delay_tmo(vport, ndlp);
}
+ if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) {
+ /* For this case we need to cleanup the default rpi
+ * allocated by the firmware.
+ */
+ if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))
+ != NULL) {
+ rc = lpfc_reg_login(phba, vport->vpi, ndlp->nlp_DID,
+ (uint8_t *) &vport->fc_sparam, mbox, 0);
+ if (rc) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
+ else {
+ mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
+ mbox->vport = vport;
+ mbox->context2 = 0;
+ rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
+ }
+ }
+ }
+
lpfc_cleanup_node(vport, ndlp);
/*