void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
 void lpfc_retry_pport_discovery(struct lpfc_hba *);
-void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);
 int lpfc_init_iocb_list(struct lpfc_hba *phba, int cnt);
 void lpfc_free_iocb_list(struct lpfc_hba *phba);
 int lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
 
                                        i, ndlp->cmd_qdepth);
                        outio += i;
                }
+               len += snprintf(buf + len, size - len, "defer:%x ",
+                       ndlp->nlp_defer_did);
                len +=  snprintf(buf+len, size-len, "\n");
        }
        spin_unlock_irq(shost->host_lock);
 
 
        uint32_t nvme_fb_size; /* NVME target's supported byte cnt */
 #define NVME_FB_BIT_SHIFT 9    /* PRLI Rsp first burst in 512B units. */
+       uint32_t nlp_defer_did;
 };
 struct lpfc_node_rrq {
        struct list_head list;
 #define NLP_ELS_SND_MASK   0x000007e0  /* sent ELS request for this entry */
 #define NLP_NVMET_RECOV    0x00001000   /* NVMET auditing node for recovery. */
 #define NLP_FCP_PRLI_RJT   0x00002000   /* Rport does not support FCP PRLI. */
+#define NLP_UNREG_INP      0x00008000  /* UNREG_RPI cmd is in progress */
 #define NLP_DEFER_RM       0x00010000  /* Remove this ndlp if no longer used */
 #define NLP_DELAY_TMO      0x00020000  /* delay timeout is running for node */
 #define NLP_NPR_2B_DISC    0x00040000  /* node is included in num_disc_nodes */
 #define NLP_EVT_DEVICE_RM         0xb  /* Device not found in NS / ALPAmap */
 #define NLP_EVT_DEVICE_RECOVERY   0xc  /* Device existence unknown */
 #define NLP_EVT_MAX_EVENT         0xd
-
+#define NLP_EVT_NOTHING_PENDING   0xff
 
                /* Xmit ELS command <elsCmd> to remote NPORT <did> */
                lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
                                 "0116 Xmit ELS command x%x to remote "
-                                "NPORT x%x I/O tag: x%x, port state:x%x"
-                                " fc_flag:x%x\n",
+                                "NPORT x%x I/O tag: x%x, port state:x%x "
+                                "rpi x%x fc_flag:x%x\n",
                                 elscmd, did, elsiocb->iotag,
-                                vport->port_state,
+                                vport->port_state, ndlp->nlp_rpi,
                                 vport->fc_flag);
        } else {
                /* Xmit ELS response <elsCmd> to remote NPORT <did> */
                lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
                                 "0117 Xmit ELS response x%x to remote "
                                 "NPORT x%x I/O tag: x%x, size: x%x "
-                                "port_state x%x fc_flag x%x\n",
+                                "port_state x%x  rpi x%x fc_flag x%x\n",
                                 elscmd, ndlp->nlp_DID, elsiocb->iotag,
                                 cmdSize, vport->port_state,
-                                vport->fc_flag);
+                                ndlp->nlp_rpi, vport->fc_flag);
        }
        return elsiocb;
 
        spin_lock_irq(shost->host_lock);
        keep_nlp_flag = new_ndlp->nlp_flag;
        new_ndlp->nlp_flag = ndlp->nlp_flag;
-       ndlp->nlp_flag = keep_nlp_flag;
+
+       /* if new_ndlp had NLP_UNREG_INP set, keep it */
+       if (keep_nlp_flag & NLP_UNREG_INP)
+               new_ndlp->nlp_flag |= NLP_UNREG_INP;
+       else
+               new_ndlp->nlp_flag &= ~NLP_UNREG_INP;
+
+       /* if ndlp had NLP_UNREG_INP set, keep it */
+       if (ndlp->nlp_flag & NLP_UNREG_INP)
+               ndlp->nlp_flag = keep_nlp_flag | NLP_UNREG_INP;
+       else
+               ndlp->nlp_flag = keep_nlp_flag & ~NLP_UNREG_INP;
+
        spin_unlock_irq(shost->host_lock);
 
        /* Set nlp_states accordingly */
        disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
        ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
        spin_unlock_irq(shost->host_lock);
-       rc   = 0;
+       rc = 0;
 
        /* PLOGI completes to NPort <nlp_DID> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
        int ret;
 
        ndlp = lpfc_findnode_did(vport, did);
-       if (ndlp && !NLP_CHK_NODE_ACT(ndlp))
-               ndlp = NULL;
+
+       if (ndlp) {
+               /* Defer the processing of the issue PLOGI until after the
+                * outstanding UNREG_RPI mbox command completes, unless we
+                * are going offline. This logic does not apply for Fabric DIDs
+                */
+               if ((ndlp->nlp_flag & NLP_UNREG_INP) &&
+                   ((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) &&
+                   !(vport->fc_flag & FC_OFFLINE_MODE)) {
+                       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                        "4110 Issue PLOGI x%x deferred "
+                                        "on NPort x%x rpi x%x Data: %p\n",
+                                        ndlp->nlp_defer_did, ndlp->nlp_DID,
+                                        ndlp->nlp_rpi, ndlp);
+
+                       /* We can only defer 1st PLOGI */
+                       if (ndlp->nlp_defer_did == NLP_EVT_NOTHING_PENDING)
+                               ndlp->nlp_defer_did = did;
+                       return 0;
+               }
+               if (!NLP_CHK_NODE_ACT(ndlp))
+                       ndlp = NULL;
+       }
 
        /* If ndlp is not NULL, we will bump the reference count on it */
        cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
                else
                        lpfc_disc_state_machine(vport, ndlp, cmdiocb,
                                                NLP_EVT_CMPL_PRLI);
-       } else
+       } else {
                /* Good status, call state machine.  However, if another
                 * PRLI is outstanding, don't call the state machine
                 * because final disposition to Mapped or Unmapped is
                 */
                lpfc_disc_state_machine(vport, ndlp, cmdiocb,
                                        NLP_EVT_CMPL_PRLI);
+       }
 
 out:
        lpfc_els_free_iocb(phba, cmdiocb);
        ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
        ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR);
        ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
-       ndlp->nlp_flag &= ~NLP_FIRSTBURST;
+       ndlp->nlp_flag &= ~(NLP_FIRSTBURST | NLP_NPR_2B_DISC);
        ndlp->nvme_fb_size = 0;
 
  send_next_prli:
                if (vport->phba->nvmet_support)
                        continue;
 
+               /* If we are in the process of doing discovery on this
+                * NPort, let it continue on its own.
+                */
+               switch (ndlp->nlp_state) {
+               case  NLP_STE_PLOGI_ISSUE:
+               case  NLP_STE_ADISC_ISSUE:
+               case  NLP_STE_REG_LOGIN_ISSUE:
+               case  NLP_STE_PRLI_ISSUE:
+               case  NLP_STE_LOGO_ISSUE:
+                       continue;
+               }
+
+
                lpfc_disc_state_machine(vport, ndlp, NULL,
                                        NLP_EVT_DEVICE_RECOVERY);
                lpfc_cancel_retry_delay_tmo(vport, ndlp);
 
        NLP_INT_NODE_ACT(ndlp);
        atomic_set(&ndlp->cmd_pending, 0);
        ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
+       ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING;
 }
 
 struct lpfc_nodelist *
                 int state)
 {
        struct lpfc_hba *phba = vport->phba;
-       uint32_t did;
+       uint32_t did, flag;
        unsigned long flags;
        unsigned long *active_rrqs_xri_bitmap = NULL;
        int rpi = LPFC_RPI_ALLOC_ERROR;
+       uint32_t defer_did = 0;
 
        if (!ndlp)
                return NULL;
                goto free_rpi;
        }
 
-       /* Keep the original DID */
+       /* First preserve the orginal DID, xri_bitmap and some flags */
        did = ndlp->nlp_DID;
+       flag = (ndlp->nlp_flag & NLP_UNREG_INP);
+       if (flag & NLP_UNREG_INP)
+               defer_did = ndlp->nlp_defer_did;
        if (phba->sli_rev == LPFC_SLI_REV4)
                active_rrqs_xri_bitmap = ndlp->active_rrqs_xri_bitmap;
 
-       /* re-initialize ndlp except of ndlp linked list pointer */
+       /* Zero ndlp except of ndlp linked list pointer */
        memset((((char *)ndlp) + sizeof (struct list_head)), 0,
                sizeof (struct lpfc_nodelist) - sizeof (struct list_head));
-       lpfc_initialize_node(vport, ndlp, did);
 
+       /* Next reinitialize and restore saved objects */
+       lpfc_initialize_node(vport, ndlp, did);
+       ndlp->nlp_flag |= flag;
+       if (flag & NLP_UNREG_INP)
+               ndlp->nlp_defer_did = defer_did;
        if (phba->sli_rev == LPFC_SLI_REV4)
                ndlp->active_rrqs_xri_bitmap = active_rrqs_xri_bitmap;
 
                return;
        lpfc_issue_els_logo(vport, ndlp, 0);
        mempool_free(pmb, phba->mbox_mem_pool);
+
+       /* Check to see if there are any deferred events to process */
+       if ((ndlp->nlp_flag & NLP_UNREG_INP) &&
+           (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "1434 UNREG cmpl deferred logo x%x "
+                                "on NPort x%x Data: x%x %p\n",
+                                ndlp->nlp_rpi, ndlp->nlp_DID,
+                                ndlp->nlp_defer_did, ndlp);
+
+               ndlp->nlp_flag &= ~NLP_UNREG_INP;
+               ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING;
+               lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
+       }
 }
 
 /*
                                         "did x%x\n",
                                         ndlp->nlp_rpi, ndlp->nlp_flag,
                                         ndlp->nlp_DID);
+
+               /* If there is already an UNREG in progress for this ndlp,
+                * no need to queue up another one.
+                */
+               if (ndlp->nlp_flag & NLP_UNREG_INP) {
+                       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                        "1436 unreg_rpi SKIP UNREG x%x on "
+                                        "NPort x%x deferred x%x  flg x%x "
+                                        "Data: %p\n",
+                                        ndlp->nlp_rpi, ndlp->nlp_DID,
+                                        ndlp->nlp_defer_did,
+                                        ndlp->nlp_flag, ndlp);
+                       goto out;
+               }
+
                mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
                if (mbox) {
                        /* SLI4 ports require the physical rpi value. */
                                         * accept PLOGIs after unreg_rpi_cmpl
                                         */
                                        acc_plogi = 0;
-                               } else
+                               } else {
+                                       mbox->ctx_ndlp = ndlp;
                                        mbox->mbox_cmpl =
                                                lpfc_sli_def_mbox_cmpl;
+                               }
                        }
+                       if (((ndlp->nlp_DID & Fabric_DID_MASK) !=
+                           Fabric_DID_MASK) &&
+                           (!(vport->fc_flag & FC_OFFLINE_MODE)))
+                               ndlp->nlp_flag |= NLP_UNREG_INP;
+
+                       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                        "1433 unreg_rpi UNREG x%x on "
+                                        "NPort x%x deferred flg x%x Data:%p\n",
+                                        ndlp->nlp_rpi, ndlp->nlp_DID,
+                                        ndlp->nlp_flag, ndlp);
 
                        rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
                        if (rc == MBX_NOT_FINISHED) {
                        }
                }
                lpfc_no_rpi(phba, ndlp);
-
+out:
                if (phba->sli_rev != LPFC_SLI_REV4)
                        ndlp->nlp_rpi = 0;
                ndlp->nlp_flag &= ~NLP_RPI_REGISTERED;
 
  * to release a rpi.
  **/
 void
-lpfc_release_rpi(struct lpfc_hba *phba,
-               struct lpfc_vport *vport,
-               uint16_t rpi)
+lpfc_release_rpi(struct lpfc_hba *phba, struct lpfc_vport *vport,
+                struct lpfc_nodelist *ndlp, uint16_t rpi)
 {
        LPFC_MBOXQ_t *pmb;
        int rc;
 
+       /* If there is already an UNREG in progress for this ndlp,
+        * no need to queue up another one.
+        */
+       if (ndlp->nlp_flag & NLP_UNREG_INP) {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "1435 release_rpi SKIP UNREG x%x on "
+                                "NPort x%x deferred x%x  flg x%x "
+                                "Data: %p\n",
+                                ndlp->nlp_rpi, ndlp->nlp_DID,
+                                ndlp->nlp_defer_did,
+                                ndlp->nlp_flag, ndlp);
+               return;
+       }
+
        pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
                        GFP_KERNEL);
        if (!pmb)
        else {
                lpfc_unreg_login(phba, vport->vpi, rpi, pmb);
                pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+               pmb->vport = vport;
+               pmb->ctx_ndlp = ndlp;
+
+               if (((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) &&
+                   (!(vport->fc_flag & FC_OFFLINE_MODE)))
+                       ndlp->nlp_flag |= NLP_UNREG_INP;
+
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "1437 release_rpi UNREG x%x "
+                                "on NPort x%x flg x%x\n",
+                                ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag);
+
                rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
                if (rc == MBX_NOT_FINISHED)
                        mempool_free(pmb, phba->mbox_mem_pool);
                (evt == NLP_EVT_CMPL_REG_LOGIN) &&
                (!pmb->u.mb.mbxStatus)) {
                rpi = pmb->u.mb.un.varWords[0];
-               lpfc_release_rpi(phba, vport, rpi);
+               lpfc_release_rpi(phba, vport, ndlp, rpi);
        }
        lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
                         "0271 Illegal State Transition: node x%x "
        if (!(phba->pport->load_flag & FC_UNLOADING) &&
                !mb->mbxStatus) {
                rpi = pmb->u.mb.un.varWords[0];
-               lpfc_release_rpi(phba, vport, rpi);
+               lpfc_release_rpi(phba, vport, ndlp, rpi);
        }
        return ndlp->nlp_state;
 }
        /* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
                         "0211 DSM in event x%x on NPort x%x in "
-                        "state %d Data: x%x x%x\n",
-                        evt, ndlp->nlp_DID, cur_state,
+                        "state %d rpi x%x Data: x%x x%x\n",
+                        evt, ndlp->nlp_DID, cur_state, ndlp->nlp_rpi,
                         ndlp->nlp_flag, ndlp->nlp_fc4_type);
 
        lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
        /* DSM out state <rc> on NPort <nlp_DID> */
        if (got_ndlp) {
                lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
-                        "0212 DSM out state %d on NPort x%x Data: x%x\n",
-                        rc, ndlp->nlp_DID, ndlp->nlp_flag);
+                        "0212 DSM out state %d on NPort x%x "
+                        "rpi x%x Data: x%x\n",
+                        rc, ndlp->nlp_DID, ndlp->nlp_rpi, ndlp->nlp_flag);
 
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
                        "DSM out:         ste:%d did:x%x flg:x%x",
 
        if (pmb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
                ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
                lpfc_nlp_put(ndlp);
+               pmb->ctx_buf = NULL;
+               pmb->ctx_ndlp = NULL;
+       }
+
+       if (pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) {
+               ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
+
+               /* Check to see if there are any deferred events to process */
+               if (ndlp) {
+                       lpfc_printf_vlog(
+                               vport,
+                               KERN_INFO, LOG_MBOX | LOG_DISCOVERY,
+                               "1438 UNREG cmpl deferred mbox x%x "
+                               "on NPort x%x Data: x%x x%x %p\n",
+                               ndlp->nlp_rpi, ndlp->nlp_DID,
+                               ndlp->nlp_flag, ndlp->nlp_defer_did, ndlp);
+
+                       if ((ndlp->nlp_flag & NLP_UNREG_INP) &&
+                           (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) {
+                               ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING;
+                               lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
+                       }
+                       ndlp->nlp_flag &= ~NLP_UNREG_INP;
+               }
                pmb->ctx_ndlp = NULL;
        }
 
                     &phba->sli4_hba.sli_intf) >=
                     LPFC_SLI_INTF_IF_TYPE_2)) {
                        if (ndlp) {
-                               lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
-                                                "0010 UNREG_LOGIN vpi:%x "
-                                                "rpi:%x DID:%x map:%x %p\n",
-                                                vport->vpi, ndlp->nlp_rpi,
-                                                ndlp->nlp_DID,
-                                                ndlp->nlp_usg_map, ndlp);
+                               lpfc_printf_vlog(
+                                       vport, KERN_INFO, LOG_MBOX | LOG_SLI,
+                                        "0010 UNREG_LOGIN vpi:%x "
+                                        "rpi:%x DID:%x defer x%x flg x%x "
+                                        "map:%x %p\n",
+                                        vport->vpi, ndlp->nlp_rpi,
+                                        ndlp->nlp_DID, ndlp->nlp_defer_did,
+                                        ndlp->nlp_flag,
+                                        ndlp->nlp_usg_map, ndlp);
                                ndlp->nlp_flag &= ~NLP_LOGO_ACC;
                                lpfc_nlp_put(ndlp);
+
+                               /* Check to see if there are any deferred
+                                * events to process
+                                */
+                               if ((ndlp->nlp_flag & NLP_UNREG_INP) &&
+                                   (ndlp->nlp_defer_did !=
+                                   NLP_EVT_NOTHING_PENDING)) {
+                                       lpfc_printf_vlog(
+                                               vport, KERN_INFO, LOG_DISCOVERY,
+                                               "4111 UNREG cmpl deferred "
+                                               "clr x%x on "
+                                               "NPort x%x Data: x%x %p\n",
+                                               ndlp->nlp_rpi, ndlp->nlp_DID,
+                                               ndlp->nlp_defer_did, ndlp);
+                                       ndlp->nlp_defer_did =
+                                               NLP_EVT_NOTHING_PENDING;
+                                       lpfc_issue_els_plogi(
+                                               vport, ndlp->nlp_DID, 0);
+                               }
+                               ndlp->nlp_flag &= ~NLP_UNREG_INP;
                        }
                }
        }