Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[pandora-kernel.git] / drivers / scsi / lpfc / lpfc_els.c
index 6e1a516..3567de6 100644 (file)
@@ -97,10 +97,9 @@ lpfc_els_chk_latt(struct lpfc_hba * phba)
 }
 
 static struct lpfc_iocbq *
-lpfc_prep_els_iocb(struct lpfc_hba * phba,
-                  uint8_t expectRsp,
-                  uint16_t cmdSize,
-                  uint8_t retry, struct lpfc_nodelist * ndlp, uint32_t elscmd)
+lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
+                  uint16_t cmdSize, uint8_t retry, struct lpfc_nodelist * ndlp,
+                  uint32_t did, uint32_t elscmd)
 {
        struct lpfc_sli_ring *pring;
        struct lpfc_iocbq *elsiocb;
@@ -181,7 +180,7 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba,
        icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL;
        if (expectRsp) {
                icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
-               icmd->un.elsreq64.remoteID = ndlp->nlp_DID;     /* DID */
+               icmd->un.elsreq64.remoteID = did;       /* DID */
                icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
        } else {
                icmd->un.elsreq64.bdl.bdeSize = sizeof (struct ulp_bde64);
@@ -225,7 +224,7 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba,
                                "%d:0116 Xmit ELS command x%x to remote "
                                "NPORT x%x Data: x%x x%x\n",
                                phba->brd_no, elscmd,
-                               ndlp->nlp_DID, icmd->ulpIoTag, phba->hba_state);
+                               did, icmd->ulpIoTag, phba->hba_state);
        } else {
                /* Xmit ELS response <elsCmd> to remote NPORT <did> */
                lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
@@ -303,10 +302,6 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
        if (lpfc_reg_login(phba, Fabric_DID, (uint8_t *) sp, mbox, 0))
                goto fail_free_mbox;
 
-       /*
-        * set_slim mailbox command needs to execute first,
-        * queue this command to be processed later.
-        */
        mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
        mbox->context2 = ndlp;
 
@@ -516,10 +511,10 @@ lpfc_issue_els_flogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        pring = &phba->sli.ring[LPFC_ELS_RING];
 
        cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
-       if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
-                                         ndlp, ELS_CMD_FLOGI)) == 0) {
+       elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
+                                                ndlp->nlp_DID, ELS_CMD_FLOGI);
+       if (!elsiocb)
                return 1;
-       }
 
        icmd = &elsiocb->iocb;
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
@@ -652,29 +647,84 @@ lpfc_more_plogi(struct lpfc_hba * phba)
        return;
 }
 
+static struct lpfc_nodelist *
+lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
+                        struct lpfc_nodelist *ndlp)
+{
+       struct lpfc_nodelist *new_ndlp;
+       uint32_t *lp;
+       struct serv_parm *sp;
+       uint8_t name[sizeof (struct lpfc_name)];
+       uint32_t rc;
+
+       lp = (uint32_t *) prsp->virt;
+       sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+       memset(name, 0, sizeof (struct lpfc_name));
+
+       /* Now we to find out if the NPort we are logging into, matches the WWPN
+        * we have for that ndlp. If not, we have some work to do.
+        */
+       new_ndlp = lpfc_findnode_wwpn(phba, NLP_SEARCH_ALL, &sp->portName);
+
+       if (new_ndlp == ndlp)
+               return ndlp;
+
+       if (!new_ndlp) {
+               rc =
+                  memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name));
+               if (!rc)
+                       return ndlp;
+               new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
+               if (!new_ndlp)
+                       return ndlp;
+
+               lpfc_nlp_init(phba, new_ndlp, ndlp->nlp_DID);
+       }
+
+       lpfc_unreg_rpi(phba, new_ndlp);
+       new_ndlp->nlp_DID = ndlp->nlp_DID;
+       new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
+       new_ndlp->nlp_state = ndlp->nlp_state;
+       lpfc_nlp_list(phba, new_ndlp, ndlp->nlp_flag & NLP_LIST_MASK);
+
+       /* Move this back to NPR list */
+       if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
+               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       }
+       else {
+               lpfc_unreg_rpi(phba, ndlp);
+               ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
+               ndlp->nlp_state = NLP_STE_NPR_NODE;
+               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+       }
+       return new_ndlp;
+}
+
 static void
 lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                    struct lpfc_iocbq * rspiocb)
 {
        IOCB_t *irsp;
-       struct lpfc_sli *psli;
        struct lpfc_nodelist *ndlp;
+       struct lpfc_dmabuf *prsp;
        int disc, rc, did, type;
 
-       psli = &phba->sli;
 
        /* we pass cmdiocb to state machine which needs rspiocb as well */
        cmdiocb->context_un.rsp_iocb = rspiocb;
 
        irsp = &rspiocb->iocb;
-       ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL,
+                                               irsp->un.elsreq64.remoteID);
+       if (!ndlp)
+               goto out;
 
        /* Since ndlp can be freed in the disc state machine, note if this node
         * is being used during discovery.
         */
        disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
        spin_lock_irq(phba->host->host_lock);
-       ndlp->nlp_flag &= ~(NLP_PLOGI_SND | NLP_NPR_2B_DISC);
+       ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
        spin_unlock_irq(phba->host->host_lock);
        rc   = 0;
 
@@ -723,40 +773,37 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                }
        } else {
                /* Good status, call state machine */
+               prsp = list_entry(((struct lpfc_dmabuf *)
+                       cmdiocb->context2)->list.next,
+                       struct lpfc_dmabuf, list);
+               ndlp = lpfc_plogi_confirm_nport(phba, prsp, ndlp);
                rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb,
                                        NLP_EVT_CMPL_PLOGI);
        }
 
-       if (type & NLP_FABRIC) {
-               /* If we cannot login to Nameserver, kick off discovery now */
-               if ((did == NameServer_DID) && (rc == NLP_STE_FREED_NODE)) {
-                       lpfc_disc_start(phba);
-               }
-               goto out;
-       }
-
        if (disc && phba->num_disc_nodes) {
                /* Check to see if there are more PLOGIs to be sent */
                lpfc_more_plogi(phba);
-       }
 
-       if (phba->num_disc_nodes == 0) {
-               spin_lock_irq(phba->host->host_lock);
-               phba->fc_flag &= ~FC_NDISC_ACTIVE;
-               spin_unlock_irq(phba->host->host_lock);
+               if (phba->num_disc_nodes == 0) {
+                       spin_lock_irq(phba->host->host_lock);
+                       phba->fc_flag &= ~FC_NDISC_ACTIVE;
+                       spin_unlock_irq(phba->host->host_lock);
 
-               lpfc_can_disctmo(phba);
-               if (phba->fc_flag & FC_RSCN_MODE) {
-                       /* Check to see if more RSCNs came in while we were
-                        * processing this one.
-                        */
-                       if ((phba->fc_rscn_id_cnt == 0) &&
-                           (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
-                               spin_lock_irq(phba->host->host_lock);
-                               phba->fc_flag &= ~FC_RSCN_MODE;
-                               spin_unlock_irq(phba->host->host_lock);
-                       } else {
-                               lpfc_els_handle_rscn(phba);
+                       lpfc_can_disctmo(phba);
+                       if (phba->fc_flag & FC_RSCN_MODE) {
+                               /*
+                                * Check to see if more RSCNs came in while
+                                * we were processing this one.
+                                */
+                               if ((phba->fc_rscn_id_cnt == 0) &&
+                               (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
+                                       spin_lock_irq(phba->host->host_lock);
+                                       phba->fc_flag &= ~FC_RSCN_MODE;
+                                       spin_unlock_irq(phba->host->host_lock);
+                               } else {
+                                       lpfc_els_handle_rscn(phba);
+                               }
                        }
                }
        }
@@ -767,8 +814,7 @@ out:
 }
 
 int
-lpfc_issue_els_plogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
-                    uint8_t retry)
+lpfc_issue_els_plogi(struct lpfc_hba * phba, uint32_t did, uint8_t retry)
 {
        struct serv_parm *sp;
        IOCB_t *icmd;
@@ -782,7 +828,7 @@ lpfc_issue_els_plogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
 
        cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
-       elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
+       elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, NULL, did,
                                                                ELS_CMD_PLOGI);
        if (!elsiocb)
                return 1;
@@ -805,9 +851,7 @@ lpfc_issue_els_plogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        phba->fc_stat.elsXmitPLOGI++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
        spin_lock_irq(phba->host->host_lock);
-       ndlp->nlp_flag |= NLP_PLOGI_SND;
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
-               ndlp->nlp_flag &= ~NLP_PLOGI_SND;
                spin_unlock_irq(phba->host->host_lock);
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
@@ -890,10 +934,10 @@ lpfc_issue_els_prli(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
 
        cmdsize = (sizeof (uint32_t) + sizeof (PRLI));
-       if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
-                                         ndlp, ELS_CMD_PRLI)) == 0) {
+       elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
+                                       ndlp->nlp_DID, ELS_CMD_PRLI);
+       if (!elsiocb)
                return 1;
-       }
 
        icmd = &elsiocb->iocb;
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
@@ -1117,10 +1161,10 @@ lpfc_issue_els_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
 
        cmdsize = (sizeof (uint32_t) + sizeof (ADISC));
-       if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
-                                         ndlp, ELS_CMD_ADISC)) == 0) {
+       elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
+                                               ndlp->nlp_DID, ELS_CMD_ADISC);
+       if (!elsiocb)
                return 1;
-       }
 
        icmd = &elsiocb->iocb;
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
@@ -1223,11 +1267,11 @@ lpfc_issue_els_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        psli = &phba->sli;
        pring = &psli->ring[LPFC_ELS_RING];
 
-       cmdsize = 2 * (sizeof (uint32_t) + sizeof (struct lpfc_name));
-       if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
-                                         ndlp, ELS_CMD_LOGO)) == 0) {
+       cmdsize = (2 * sizeof (uint32_t)) + sizeof (struct lpfc_name);
+       elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
+                                               ndlp->nlp_DID, ELS_CMD_LOGO);
+       if (!elsiocb)
                return 1;
-       }
 
        icmd = &elsiocb->iocb;
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
@@ -1296,8 +1340,9 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
 
        lpfc_nlp_init(phba, ndlp, nportid);
 
-       if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
-                                         ndlp, ELS_CMD_SCR)) == 0) {
+       elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
+                                               ndlp->nlp_DID, ELS_CMD_SCR);
+       if (!elsiocb) {
                mempool_free( ndlp, phba->nlp_mem_pool);
                return 1;
        }
@@ -1348,8 +1393,9 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
                return 1;
        lpfc_nlp_init(phba, ndlp, nportid);
 
-       if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
-                                         ndlp, ELS_CMD_RNID)) == 0) {
+       elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
+                                               ndlp->nlp_DID, ELS_CMD_RNID);
+       if (!elsiocb) {
                mempool_free( ndlp, phba->nlp_mem_pool);
                return 1;
        }
@@ -1392,6 +1438,47 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        return 0;
 }
 
+void
+lpfc_cancel_retry_delay_tmo(struct lpfc_hba *phba, struct lpfc_nodelist * nlp)
+{
+       nlp->nlp_flag &= ~NLP_DELAY_TMO;
+       del_timer_sync(&nlp->nlp_delayfunc);
+       nlp->nlp_last_elscmd = 0;
+
+       if (!list_empty(&nlp->els_retry_evt.evt_listp))
+               list_del_init(&nlp->els_retry_evt.evt_listp);
+
+       if (nlp->nlp_flag & NLP_NPR_2B_DISC) {
+               nlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+               if (phba->num_disc_nodes) {
+                       /* Check to see if there are more
+                        * PLOGIs to be sent
+                        */
+                       lpfc_more_plogi(phba);
+
+                       if (phba->num_disc_nodes == 0) {
+                               phba->fc_flag &= ~FC_NDISC_ACTIVE;
+                               lpfc_can_disctmo(phba);
+                               if (phba->fc_flag & FC_RSCN_MODE) {
+                                       /*
+                                        * Check to see if more RSCNs
+                                        * came in while we were
+                                        * processing this one.
+                                        */
+                                       if((phba->fc_rscn_id_cnt==0) &&
+                                        !(phba->fc_flag & FC_RSCN_DISCOVERY)) {
+                                               phba->fc_flag &= ~FC_RSCN_MODE;
+                                       }
+                                       else {
+                                               lpfc_els_handle_rscn(phba);
+                                       }
+                               }
+                       }
+               }
+       }
+       return;
+}
+
 void
 lpfc_els_retry_delay(unsigned long ptr)
 {
@@ -1441,6 +1528,12 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
 
        ndlp->nlp_flag &= ~NLP_DELAY_TMO;
        spin_unlock_irq(phba->host->host_lock);
+       /*
+        * If a discovery event readded nlp_delayfunc after timer
+        * firing and before processing the timer, cancel the
+        * nlp_delayfunc.
+        */
+       del_timer_sync(&ndlp->nlp_delayfunc);
        retry = ndlp->nlp_retry;
 
        switch (cmd) {
@@ -1448,7 +1541,7 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
                lpfc_issue_els_flogi(phba, ndlp, retry);
                break;
        case ELS_CMD_PLOGI:
-               if (!lpfc_issue_els_plogi(phba, ndlp, retry)) {
+               if(!lpfc_issue_els_plogi(phba, ndlp->nlp_DID, retry)) {
                        ndlp->nlp_prev_state = ndlp->nlp_state;
                        ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
                        lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
@@ -1491,6 +1584,7 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        int retry, maxretry;
        int delay;
        uint32_t cmd;
+       uint32_t did;
 
        retry = 0;
        delay = 0;
@@ -1499,6 +1593,7 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
        cmd = 0;
+
        /* Note: context2 may be 0 for internal driver abort
         * of delays ELS command.
         */
@@ -1508,6 +1603,16 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                cmd = *elscmd++;
        }
 
+       if(ndlp)
+               did = ndlp->nlp_DID;
+       else {
+               /* We should only hit this case for retrying PLOGI */
+               did = irsp->un.elsreq64.remoteID;
+               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+               if (!ndlp && (cmd != ELS_CMD_PLOGI))
+                       return 1;
+       }
+
        switch (irsp->ulpStatus) {
        case IOSTAT_FCP_RSP_ERROR:
        case IOSTAT_REMOTE_STOP:
@@ -1596,9 +1701,8 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                break;
        }
 
-       if (ndlp->nlp_DID == FDMI_DID) {
+       if (did == FDMI_DID)
                retry = 1;
-       }
 
        if ((++cmdiocb->retry) >= maxretry) {
                phba->fc_stat.elsRetryExceeded++;
@@ -1612,7 +1716,7 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                                "%d:0107 Retry ELS command x%x to remote "
                                "NPORT x%x Data: x%x x%x\n",
                                phba->brd_no,
-                               cmd, ndlp->nlp_DID, cmdiocb->retry, delay);
+                               cmd, did, cmdiocb->retry, delay);
 
                if ((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) {
                        /* If discovery / RSCN timer is running, reset it */
@@ -1623,7 +1727,7 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                }
 
                phba->fc_stat.elsXmitRetry++;
-               if (delay) {
+               if (ndlp && delay) {
                        phba->fc_stat.elsDelayRetry++;
                        ndlp->nlp_retry = cmdiocb->retry;
 
@@ -1642,10 +1746,12 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                        lpfc_issue_els_flogi(phba, ndlp, cmdiocb->retry);
                        return 1;
                case ELS_CMD_PLOGI:
-                       ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
-                       lpfc_issue_els_plogi(phba, ndlp, cmdiocb->retry);
+                       if (ndlp) {
+                               ndlp->nlp_prev_state = ndlp->nlp_state;
+                               ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+                               lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+                       }
+                       lpfc_issue_els_plogi(phba, did, cmdiocb->retry);
                        return 1;
                case ELS_CMD_ADISC:
                        ndlp->nlp_prev_state = ndlp->nlp_state;
@@ -1671,9 +1777,9 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        /* No retry ELS command <elsCmd> to remote NPORT <did> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                        "%d:0108 No retry ELS command x%x to remote NPORT x%x "
-                       "Data: x%x x%x\n",
+                       "Data: x%x\n",
                        phba->brd_no,
-                       cmd, ndlp->nlp_DID, cmdiocb->retry, ndlp->nlp_flag);
+                       cmd, did, cmdiocb->retry);
 
        return 0;
 }
@@ -1742,9 +1848,12 @@ static void
 lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                  struct lpfc_iocbq * rspiocb)
 {
+       IOCB_t *irsp;
        struct lpfc_nodelist *ndlp;
        LPFC_MBOXQ_t *mbox = NULL;
 
+       irsp = &rspiocb->iocb;
+
        ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
        if (cmdiocb->context_un.mbox)
                mbox = cmdiocb->context_un.mbox;
@@ -1771,9 +1880,6 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        if (mbox) {
                if ((rspiocb->iocb.ulpStatus == 0)
                    && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
-                       /* set_slim mailbox command needs to execute first,
-                        * queue this command to be processed later.
-                        */
                        lpfc_unreg_rpi(phba, ndlp);
                        mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
                        mbox->context2 = ndlp;
@@ -1790,9 +1896,15 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                        mempool_free( mbox, phba->mbox_mem_pool);
                } else {
                        mempool_free( mbox, phba->mbox_mem_pool);
-                       if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
-                               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-                               ndlp = NULL;
+                       /* Do not call NO_LIST for lpfc_els_abort'ed ELS cmds */
+                       if (!((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+                             ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
+                              (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
+                              (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) {
+                               if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
+                                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                                       ndlp = NULL;
+                               }
                        }
                }
        }
@@ -1819,6 +1931,7 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
        uint8_t *pcmd;
        uint16_t cmdsize;
        int rc;
+       ELS_PKT *els_pkt_ptr;
 
        psli = &phba->sli;
        pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
@@ -1827,9 +1940,9 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
        switch (flag) {
        case ELS_CMD_ACC:
                cmdsize = sizeof (uint32_t);
-               if ((elsiocb =
-                    lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
-                                       ndlp, ELS_CMD_ACC)) == 0) {
+               elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+                                       ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+               if (!elsiocb) {
                        ndlp->nlp_flag &= ~NLP_LOGO_ACC;
                        return 1;
                }
@@ -1841,11 +1954,11 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
                break;
        case ELS_CMD_PLOGI:
                cmdsize = (sizeof (struct serv_parm) + sizeof (uint32_t));
-               if ((elsiocb =
-                    lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
-                                       ndlp, ELS_CMD_ACC)) == 0) {
+               elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+                                       ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+               if (!elsiocb)
                        return 1;
-               }
+
                icmd = &elsiocb->iocb;
                icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
                pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
@@ -1857,6 +1970,23 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
                pcmd += sizeof (uint32_t);
                memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm));
                break;
+       case ELS_CMD_PRLO:
+               cmdsize = sizeof (uint32_t) + sizeof (PRLO);
+               elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+                                            ndlp, ndlp->nlp_DID, ELS_CMD_PRLO);
+               if (!elsiocb)
+                       return 1;
+
+               icmd = &elsiocb->iocb;
+               icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+               pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+               memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
+                      sizeof (uint32_t) + sizeof (PRLO));
+               *((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC;
+               els_pkt_ptr = (ELS_PKT *) pcmd;
+               els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED;
+               break;
        default:
                return 1;
        }
@@ -1910,10 +2040,10 @@ lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
        pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
 
        cmdsize = 2 * sizeof (uint32_t);
-       if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
-                                         ndlp, ELS_CMD_LS_RJT)) == 0) {
+       elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+                                       ndlp, ndlp->nlp_DID, ELS_CMD_LS_RJT);
+       if (!elsiocb)
                return 1;
-       }
 
        icmd = &elsiocb->iocb;
        oldcmd = &oldiocb->iocb;
@@ -1963,10 +2093,10 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
        pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
 
        cmdsize = sizeof (uint32_t) + sizeof (ADISC);
-       if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
-                                         ndlp, ELS_CMD_ACC)) == 0) {
+       elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+                                       ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+       if (!elsiocb)
                return 1;
-       }
 
        /* Xmit ADISC ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
@@ -2023,7 +2153,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
 
        cmdsize = sizeof (uint32_t) + sizeof (PRLI);
        elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, ndlp,
-                               (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
+               ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
        if (!elsiocb)
                return 1;
 
@@ -2103,10 +2233,10 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
        if (format)
                cmdsize += sizeof (RNID_TOP_DISC);
 
-       if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
-                                         ndlp, ELS_CMD_ACC)) == 0) {
+       elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+                                       ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+       if (!elsiocb)
                return 1;
-       }
 
        /* Xmit RNID ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
@@ -2217,7 +2347,7 @@ lpfc_els_disc_plogi(struct lpfc_hba * phba)
                                ndlp->nlp_prev_state = ndlp->nlp_state;
                                ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
                                lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
-                               lpfc_issue_els_plogi(phba, ndlp, 0);
+                               lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
                                sentplogi++;
                                phba->num_disc_nodes++;
                                if (phba->num_disc_nodes >=
@@ -2360,15 +2490,8 @@ lpfc_rscn_recovery_check(struct lpfc_hba * phba)
                        /* Make sure NLP_DELAY_TMO is NOT running
                         * after a device recovery event.
                         */
-                       if (ndlp->nlp_flag & NLP_DELAY_TMO) {
-                               ndlp->nlp_flag &= ~NLP_DELAY_TMO;
-                               ndlp->nlp_last_elscmd = 0;
-                               del_timer_sync(&ndlp->nlp_delayfunc);
-                               if (!list_empty(&ndlp->
-                                               els_retry_evt.evt_listp))
-                                       list_del_init(&ndlp->
-                                               els_retry_evt.evt_listp);
-                       }
+                       if (ndlp->nlp_flag & NLP_DELAY_TMO)
+                               lpfc_cancel_retry_delay_tmo(phba, ndlp);
                }
        }
        return 0;
@@ -2404,7 +2527,7 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba,
        /* If we are about to begin discovery, just ACC the RSCN.
         * Discovery processing will satisfy it.
         */
-       if (phba->hba_state < LPFC_NS_QRY) {
+       if (phba->hba_state <= LPFC_NS_QRY) {
                lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
                                                                newnode);
                return 0;
@@ -2516,7 +2639,7 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
                        ndlp->nlp_type |= NLP_FABRIC;
                        ndlp->nlp_prev_state = ndlp->nlp_state;
                        ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                       lpfc_issue_els_plogi(phba, ndlp, 0);
+                       lpfc_issue_els_plogi(phba, NameServer_DID, 0);
                        /* Wait for NameServer login cmpl before we can
                           continue */
                        return 1;
@@ -2684,8 +2807,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        ndlp = (struct lpfc_nodelist *) pmb->context2;
        xri = (uint16_t) ((unsigned long)(pmb->context1));
-       pmb->context1 = 0;
-       pmb->context2 = 0;
+       pmb->context1 = NULL;
+       pmb->context2 = NULL;
 
        if (mb->mbxStatus) {
                mempool_free( pmb, phba->mbox_mem_pool);
@@ -2694,8 +2817,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
        mempool_free( pmb, phba->mbox_mem_pool);
-       elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, lpfc_max_els_tries,
-                                                       ndlp, ELS_CMD_ACC);
+       elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, lpfc_max_els_tries, ndlp,
+                                               ndlp->nlp_DID, ELS_CMD_ACC);
        if (!elsiocb)
                return;
 
@@ -2725,7 +2848,7 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        /* Xmit ELS RPS ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0128 Xmit ELS RPS ACC response tag x%x "
+                       "%d:0118 Xmit ELS RPS ACC response tag x%x "
                        "Data: x%x x%x x%x x%x x%x\n",
                        phba->brd_no,
                        elsiocb->iocb.ulpIoTag,
@@ -2806,11 +2929,11 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
        psli = &phba->sli;
        pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
 
-       if ((elsiocb =
-            lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
-                               ndlp, ELS_CMD_ACC)) == 0) {
+       elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+                                       ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+       if (!elsiocb)
                return 1;
-       }
+
        icmd = &elsiocb->iocb;
        oldcmd = &oldiocb->iocb;
        icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
@@ -2834,7 +2957,7 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
 
        /* Xmit ELS RPL ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0128 Xmit ELS RPL ACC response tag x%x "
+                       "%d:0120 Xmit ELS RPL ACC response tag x%x "
                        "Data: x%x x%x x%x x%x x%x\n",
                        phba->brd_no,
                        elsiocb->iocb.ulpIoTag,
@@ -2943,7 +3066,7 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
                                ndlp->nlp_prev_state = ndlp->nlp_state;
                                ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
                                lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
-                               lpfc_issue_els_plogi(phba, ndlp, 0);
+                               lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
                        }
 
                        /* Send a FARP response to that node */
@@ -2995,7 +3118,7 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        struct lpfc_nodelist *ndlp, *next_ndlp;
 
        /* FAN received */
-       lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:265 FAN received\n",
+       lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0265 FAN received\n",
                                                                phba->brd_no);
 
        icmd = &cmdiocb->iocb;
@@ -3144,8 +3267,9 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
 
                if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
                        struct lpfc_nodelist *ndlp;
-
+                       spin_unlock_irq(phba->host->host_lock);
                        ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext);
+                       spin_lock_irq(phba->host->host_lock);
                        remote_ID = ndlp->nlp_DID;
                        if (cmd->un.elsreq64.bdl.ulpIoTag32) {
                                lpfc_sli_issue_abort_iotag32(phba,
@@ -3174,10 +3298,9 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
                } else
                        lpfc_sli_release_iocbq(phba, piocb);
        }
-       if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) {
-               phba->els_tmofunc.expires = jiffies + HZ * timeout;
-               add_timer(&phba->els_tmofunc);
-       }
+       if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
+               mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
+
        spin_unlock_irq(phba->host->host_lock);
 }
 
@@ -3334,6 +3457,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
                        ndlp->nlp_type |= NLP_FABRIC;
                }
+               ndlp->nlp_state = NLP_STE_UNUSED_NODE;
+               lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
        }
 
        phba->fc_stat.elsRcvFrame++;
@@ -3355,13 +3480,14 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                        rjt_err = 1;
                        break;
                }
+               ndlp = lpfc_plogi_confirm_nport(phba, mp, ndlp);
                lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PLOGI);
                break;
        case ELS_CMD_FLOGI:
                phba->fc_stat.elsRcvFLOGI++;
                lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode);
                if (newnode) {
-                       mempool_free( ndlp, phba->nlp_mem_pool);
+                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
                }
                break;
        case ELS_CMD_LOGO:
@@ -3384,7 +3510,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                phba->fc_stat.elsRcvRSCN++;
                lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode);
                if (newnode) {
-                       mempool_free( ndlp, phba->nlp_mem_pool);
+                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
                }
                break;
        case ELS_CMD_ADISC:
@@ -3427,28 +3553,28 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                phba->fc_stat.elsRcvLIRR++;
                lpfc_els_rcv_lirr(phba, elsiocb, ndlp);
                if (newnode) {
-                       mempool_free( ndlp, phba->nlp_mem_pool);
+                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
                }
                break;
        case ELS_CMD_RPS:
                phba->fc_stat.elsRcvRPS++;
                lpfc_els_rcv_rps(phba, elsiocb, ndlp);
                if (newnode) {
-                       mempool_free( ndlp, phba->nlp_mem_pool);
+                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
                }
                break;
        case ELS_CMD_RPL:
                phba->fc_stat.elsRcvRPL++;
                lpfc_els_rcv_rpl(phba, elsiocb, ndlp);
                if (newnode) {
-                       mempool_free( ndlp, phba->nlp_mem_pool);
+                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
                }
                break;
        case ELS_CMD_RNID:
                phba->fc_stat.elsRcvRNID++;
                lpfc_els_rcv_rnid(phba, elsiocb, ndlp);
                if (newnode) {
-                       mempool_free( ndlp, phba->nlp_mem_pool);
+                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
                }
                break;
        default:
@@ -3460,7 +3586,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                                "%d:0115 Unknown ELS command x%x received from "
                                "NPORT x%x\n", phba->brd_no, cmd, did);
                if (newnode) {
-                       mempool_free( ndlp, phba->nlp_mem_pool);
+                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
                }
                break;
        }