Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / scsi / lpfc / lpfc_els.c
index 427f68b..283b7d8 100644 (file)
@@ -1,42 +1,40 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
- * Enterprise Fibre Channel Host Bus Adapters.                     *
- * Refer to the README file included with this package for         *
- * driver version and adapter support.                             *
- * Copyright (C) 2004 Emulex Corporation.                          *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
+ * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
  *                                                                 *
  * This program is free software; you can redistribute it and/or   *
- * modify it under the terms of the GNU General Public License     *
- * as published by the Free Software Foundation; either version 2  *
- * of the License, or (at your option) any later version.          *
- *                                                                 *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of  *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *
- * GNU General Public License for more details, a copy of which    *
- * can be found in the file COPYING included with this package.    *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
  *******************************************************************/
 
-/*
- * $Id: lpfc_els.c 1.152 2004/11/18 18:27:53EST sf_support Exp  $
- */
-#include <linux/version.h>
 #include <linux/blkdev.h>
-#include <linux/dma-mapping.h>
 #include <linux/pci.h>
-#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+
+#include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "lpfc_hw.h"
 #include "lpfc_sli.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
 #include "lpfc.h"
-#include "lpfc_crtn.h"
-#include "lpfc_hw.h"
 #include "lpfc_logmsg.h"
-#include "lpfc_mem.h"
-
+#include "lpfc_crtn.h"
 
 static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
                          struct lpfc_iocbq *);
@@ -48,93 +46,91 @@ lpfc_els_chk_latt(struct lpfc_hba * phba)
        struct lpfc_sli *psli;
        LPFC_MBOXQ_t *mbox;
        uint32_t ha_copy;
+       int rc;
 
        psli = &phba->sli;
 
-       if ((phba->hba_state < LPFC_HBA_READY) &&
-               (phba->hba_state != LPFC_LINK_DOWN)) {
-
-               /* Read the HBA Host Attention Register */
-               ha_copy = readl(phba->HAregaddr);
-
-               if (ha_copy & HA_LATT) {        /* Link Attention interrupt */
-
-                       /* Pending Link Event during Discovery */
-                       lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY,
-                                       "%d:0237 Pending Link Event during "
-                                       "Discovery: State x%x\n",
-                                       phba->brd_no, phba->hba_state);
-
-                       /* CLEAR_LA should re-enable link attention events and
-                        * we should then imediately take a LATT event. The 
-                        * LATT processing should call lpfc_linkdown() which
-                        * will cleanup any left over in-progress discovery
-                        * events.
-                        */
-                       phba->fc_flag |= FC_ABORT_DISCOVERY;
-
-                       if (phba->hba_state != LPFC_CLEAR_LA) {
-                               if ((mbox = mempool_alloc(phba->mbox_mem_pool,
-                                                         GFP_ATOMIC))) {
-                                       phba->hba_state = LPFC_CLEAR_LA;
-                                       lpfc_clear_la(phba, mbox);
-                                       mbox->mbox_cmpl =
-                                           lpfc_mbx_cmpl_clear_la;
-                                       if (lpfc_sli_issue_mbox
-                                           (phba, mbox,
-                                            (MBX_NOWAIT | MBX_STOP_IOCB))
-                                           == MBX_NOT_FINISHED) {
-                                               mempool_free(mbox,
-                                                    phba->mbox_mem_pool);
-                                               phba->hba_state =
-                                                   LPFC_HBA_ERROR;
-                                       }
-                               }
+       if ((phba->hba_state >= LPFC_HBA_READY) ||
+           (phba->hba_state == LPFC_LINK_DOWN))
+               return 0;
+
+       /* Read the HBA Host Attention Register */
+       spin_lock_irq(phba->host->host_lock);
+       ha_copy = readl(phba->HAregaddr);
+       spin_unlock_irq(phba->host->host_lock);
+
+       if (!(ha_copy & HA_LATT))
+               return 0;
+
+       /* Pending Link Event during Discovery */
+       lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY,
+                       "%d:0237 Pending Link Event during "
+                       "Discovery: State x%x\n",
+                       phba->brd_no, phba->hba_state);
+
+       /* CLEAR_LA should re-enable link attention events and
+        * we should then imediately take a LATT event. The
+        * LATT processing should call lpfc_linkdown() which
+        * will cleanup any left over in-progress discovery
+        * events.
+        */
+       spin_lock_irq(phba->host->host_lock);
+       phba->fc_flag |= FC_ABORT_DISCOVERY;
+       spin_unlock_irq(phba->host->host_lock);
+
+       if (phba->hba_state != LPFC_CLEAR_LA) {
+               if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
+                       phba->hba_state = LPFC_CLEAR_LA;
+                       lpfc_clear_la(phba, mbox);
+                       mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
+                       rc = lpfc_sli_issue_mbox (phba, mbox,
+                                                 (MBX_NOWAIT | MBX_STOP_IOCB));
+                       if (rc == MBX_NOT_FINISHED) {
+                               mempool_free(mbox, phba->mbox_mem_pool);
+                               phba->hba_state = LPFC_HBA_ERROR;
                        }
-                       return (1);
                }
        }
 
-       return (0);
+       return 1;
+
 }
 
-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)
+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 did, uint32_t elscmd)
 {
-       struct lpfc_sli *psli;
        struct lpfc_sli_ring *pring;
        struct lpfc_iocbq *elsiocb;
        struct lpfc_dmabuf *pcmd, *prsp, *pbuflist;
        struct ulp_bde64 *bpl;
        IOCB_t *icmd;
-       uint32_t tag;
 
-       psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
+       pring = &phba->sli.ring[LPFC_ELS_RING];
 
        if (phba->hba_state < LPFC_LINK_UP)
                return  NULL;
 
-
        /* Allocate buffer for  command iocb */
-       elsiocb = mempool_alloc(phba->iocb_mem_pool, GFP_ATOMIC);
-       if (!elsiocb)
-               return NULL;
+       spin_lock_irq(phba->host->host_lock);
+       elsiocb = lpfc_sli_get_iocbq(phba);
+       spin_unlock_irq(phba->host->host_lock);
 
-       memset(elsiocb, 0, sizeof (struct lpfc_iocbq));
+       if (elsiocb == NULL)
+               return NULL;
        icmd = &elsiocb->iocb;
 
        /* fill in BDEs for command */
        /* Allocate buffer for command payload */
-       if (((pcmd = kmalloc(sizeof (struct lpfc_dmabuf), GFP_ATOMIC)) == 0) ||
+       if (((pcmd = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
            ((pcmd->virt = lpfc_mbuf_alloc(phba,
                                           MEM_PRI, &(pcmd->phys))) == 0)) {
-               if (pcmd)
-                       kfree(pcmd);
-               mempool_free( elsiocb, phba->iocb_mem_pool);
+               kfree(pcmd);
+
+               spin_lock_irq(phba->host->host_lock);
+               lpfc_sli_release_iocbq(phba, elsiocb);
+               spin_unlock_irq(phba->host->host_lock);
                return NULL;
        }
 
@@ -142,16 +138,17 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba,
 
        /* Allocate buffer for response payload */
        if (expectRsp) {
-               prsp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_ATOMIC);
+               prsp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
                if (prsp)
                        prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
                                                     &prsp->phys);
                if (prsp == 0 || prsp->virt == 0) {
-                       if (prsp)
-                               kfree(prsp);
+                       kfree(prsp);
                        lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
                        kfree(pcmd);
-                       mempool_free( elsiocb, phba->iocb_mem_pool);
+                       spin_lock_irq(phba->host->host_lock);
+                       lpfc_sli_release_iocbq(phba, elsiocb);
+                       spin_unlock_irq(phba->host->host_lock);
                        return NULL;
                }
                INIT_LIST_HEAD(&prsp->list);
@@ -160,18 +157,19 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba,
        }
 
        /* Allocate buffer for Buffer ptr list */
-       pbuflist = kmalloc(sizeof (struct lpfc_dmabuf), GFP_ATOMIC);
+       pbuflist = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
        if (pbuflist)
            pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
                                             &pbuflist->phys);
        if (pbuflist == 0 || pbuflist->virt == 0) {
-               mempool_free( elsiocb, phba->iocb_mem_pool);
+               spin_lock_irq(phba->host->host_lock);
+               lpfc_sli_release_iocbq(phba, elsiocb);
+               spin_unlock_irq(phba->host->host_lock);
                lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
                lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
                kfree(pcmd);
                kfree(prsp);
-               if (pbuflist)
-                       kfree(pbuflist);
+               kfree(pbuflist);
                return NULL;
        }
 
@@ -182,17 +180,13 @@ 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);
                icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
        }
 
-       /* NOTE: we don't use ulpIoTag0 because it is a t2 structure */
-       tag = lpfc_sli_next_iotag(phba, pring);
-       icmd->ulpIoTag = (uint16_t)(tag & 0xffff);
-       icmd->un.elsreq64.bdl.ulpIoTag32 = tag;
        icmd->ulpBdeCount = 1;
        icmd->ulpLe = 1;
        icmd->ulpClass = CLASS3;
@@ -224,21 +218,13 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba,
                list_add(&prsp->list, &pcmd->list);
        }
 
-       /* The els iocb is fully initialize.  Flush it to main store for the
-        * HBA.  Note that all els iocb context buffer are from the driver's
-        * dma pool and have length LPFC_BPL_SIZE. Get a short-hand pointer to
-        * the physical address.
-        */
-       pci_dma_sync_single_for_device(phba->pcidev, pbuflist->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        if (expectRsp) {
                /* Xmit ELS command <elsCmd> to remote NPORT <did> */
                lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                                "%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,
@@ -248,27 +234,183 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba,
                                ndlp->nlp_DID, icmd->ulpIoTag, cmdSize);
        }
 
-       return (elsiocb);
+       return elsiocb;
+}
+
+
+static int
+lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+               struct serv_parm *sp, IOCB_t *irsp)
+{
+       LPFC_MBOXQ_t *mbox;
+       int rc;
+
+       spin_lock_irq(phba->host->host_lock);
+       phba->fc_flag |= FC_FABRIC;
+       spin_unlock_irq(phba->host->host_lock);
+
+       phba->fc_edtov = be32_to_cpu(sp->cmn.e_d_tov);
+       if (sp->cmn.edtovResolution)    /* E_D_TOV ticks are in nanoseconds */
+               phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000;
+
+       phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;
+
+       if (phba->fc_topology == TOPOLOGY_LOOP) {
+               spin_lock_irq(phba->host->host_lock);
+               phba->fc_flag |= FC_PUBLIC_LOOP;
+               spin_unlock_irq(phba->host->host_lock);
+       } else {
+               /*
+                * If we are a N-port connected to a Fabric, fixup sparam's so
+                * logins to devices on remote loops work.
+                */
+               phba->fc_sparam.cmn.altBbCredit = 1;
+       }
+
+       phba->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
+       memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name));
+       memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
+       ndlp->nlp_class_sup = 0;
+       if (sp->cls1.classValid)
+               ndlp->nlp_class_sup |= FC_COS_CLASS1;
+       if (sp->cls2.classValid)
+               ndlp->nlp_class_sup |= FC_COS_CLASS2;
+       if (sp->cls3.classValid)
+               ndlp->nlp_class_sup |= FC_COS_CLASS3;
+       if (sp->cls4.classValid)
+               ndlp->nlp_class_sup |= FC_COS_CLASS4;
+       ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
+                               sp->cmn.bbRcvSizeLsb;
+       memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               goto fail;
+
+       phba->hba_state = LPFC_FABRIC_CFG_LINK;
+       lpfc_config_link(phba, mbox);
+       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
+       if (rc == MBX_NOT_FINISHED)
+               goto fail_free_mbox;
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               goto fail;
+
+       if (lpfc_reg_login(phba, Fabric_DID, (uint8_t *) sp, mbox, 0))
+               goto fail_free_mbox;
+
+       mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
+       mbox->context2 = ndlp;
+
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
+       if (rc == MBX_NOT_FINISHED)
+               goto fail_free_mbox;
+
+       return 0;
+
+ fail_free_mbox:
+       mempool_free(mbox, phba->mbox_mem_pool);
+ fail:
+       return -ENXIO;
+}
+
+/*
+ * We FLOGIed into an NPort, initiate pt2pt protocol
+ */
+static int
+lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+               struct serv_parm *sp)
+{
+       LPFC_MBOXQ_t *mbox;
+       int rc;
+
+       spin_lock_irq(phba->host->host_lock);
+       phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+       spin_unlock_irq(phba->host->host_lock);
+
+       phba->fc_edtov = FF_DEF_EDTOV;
+       phba->fc_ratov = FF_DEF_RATOV;
+       rc = memcmp(&phba->fc_portname, &sp->portName,
+                       sizeof(struct lpfc_name));
+       if (rc >= 0) {
+               /* This side will initiate the PLOGI */
+               spin_lock_irq(phba->host->host_lock);
+               phba->fc_flag |= FC_PT2PT_PLOGI;
+               spin_unlock_irq(phba->host->host_lock);
+
+               /*
+                * N_Port ID cannot be 0, set our to LocalID the other
+                * side will be RemoteID.
+                */
+
+               /* not equal */
+               if (rc)
+                       phba->fc_myDID = PT2PT_LocalID;
+
+               mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+               if (!mbox)
+                       goto fail;
+
+               lpfc_config_link(phba, mbox);
+
+               mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+               rc = lpfc_sli_issue_mbox(phba, mbox,
+                               MBX_NOWAIT | MBX_STOP_IOCB);
+               if (rc == MBX_NOT_FINISHED) {
+                       mempool_free(mbox, phba->mbox_mem_pool);
+                       goto fail;
+               }
+               mempool_free(ndlp, phba->nlp_mem_pool);
+
+               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, PT2PT_RemoteID);
+               if (!ndlp) {
+                       /*
+                        * Cannot find existing Fabric ndlp, so allocate a
+                        * new one
+                        */
+                       ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+                       if (!ndlp)
+                               goto fail;
+
+                       lpfc_nlp_init(phba, ndlp, PT2PT_RemoteID);
+               }
+
+               memcpy(&ndlp->nlp_portname, &sp->portName,
+                               sizeof(struct lpfc_name));
+               memcpy(&ndlp->nlp_nodename, &sp->nodeName,
+                               sizeof(struct lpfc_name));
+               ndlp->nlp_state = NLP_STE_NPR_NODE;
+               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+       } else {
+               /* This side will wait for the PLOGI */
+               mempool_free( ndlp, phba->nlp_mem_pool);
+       }
+
+       spin_lock_irq(phba->host->host_lock);
+       phba->fc_flag |= FC_PT2PT;
+       spin_unlock_irq(phba->host->host_lock);
+
+       /* Start discovery - this should just do CLEAR_LA */
+       lpfc_disc_start(phba);
+       return 0;
+ fail:
+       return -ENXIO;
 }
 
 static void
 lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
                    struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb)
 {
-       IOCB_t *irsp;
-       struct lpfc_dmabuf *pcmd, *prsp;
+       IOCB_t *irsp = &rspiocb->iocb;
+       struct lpfc_nodelist *ndlp = cmdiocb->context1;
+       struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
        struct serv_parm *sp;
-       uint32_t *lp;
-       LPFC_MBOXQ_t *mbox;
-       struct lpfc_sli *psli;
-       struct lpfc_nodelist *ndlp;
        int rc;
 
-       psli = &phba->sli;
-       irsp = &(rspiocb->iocb);
-       ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
-       pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
-
        /* Check to see if link went down during discovery */
        if (lpfc_els_chk_latt(phba)) {
                lpfc_nlp_remove(phba, ndlp);
@@ -282,7 +424,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
                        goto out;
                }
                /* FLOGI failed, so there is no fabric */
+               spin_lock_irq(phba->host->host_lock);
                phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+               spin_unlock_irq(phba->host->host_lock);
 
                /* If private loop, then allow max outstandting els to be
                 * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
@@ -297,195 +441,49 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
                lpfc_printf_log(phba,
                                KERN_INFO,
                                LOG_ELS,
-                               "%d:0100 FLOGI failure Data: x%x x%x\n",
-                               phba->brd_no,
-                               irsp->ulpStatus, irsp->un.ulpWord[4]);
-       } else {
-               /* The FLogI succeeded.  Sync the data for the CPU before
-                * accessing it.
-                */
-               prsp = (struct lpfc_dmabuf *) pcmd->list.next;
-               lp = (uint32_t *) prsp->virt;
-
-               /* The HBA populated the response buffer.  Flush cpu cache to
-                * before the driver touches this memory.
-                */
-               pci_dma_sync_single_for_cpu(phba->pcidev, prsp->phys,
-                       LPFC_BPL_SIZE, PCI_DMA_FROMDEVICE);
-               sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
-
-               /* FLOGI completes successfully */
-               lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                               "%d:0101 FLOGI completes sucessfully "
-                               "Data: x%x x%x x%x x%x\n",
+                               "%d:0100 FLOGI failure Data: x%x x%x x%x\n",
                                phba->brd_no,
-                               irsp->un.ulpWord[4], sp->cmn.e_d_tov,
-                               sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
-
-               if (phba->hba_state == LPFC_FLOGI) {
-                       /* If Common Service Parameters indicate Nport
-                        * we are point to point, if Fport we are Fabric.
-                        */
-                       if (sp->cmn.fPort) {
-                               phba->fc_flag |= FC_FABRIC;
-                               if (sp->cmn.edtovResolution) {
-                                       /* E_D_TOV ticks are in nanoseconds */
-                                       phba->fc_edtov =
-                                           (be32_to_cpu(sp->cmn.e_d_tov) +
-                                            999999) / 1000000;
-                               } else {
-                                       /* E_D_TOV ticks are in milliseconds */
-                                       phba->fc_edtov =
-                                           be32_to_cpu(sp->cmn.e_d_tov);
-                               }
-                               phba->fc_ratov =
-                                   (be32_to_cpu(sp->cmn.w2.r_a_tov) +
-                                    999) / 1000;
-
-                               if (phba->fc_topology == TOPOLOGY_LOOP) {
-                                       phba->fc_flag |= FC_PUBLIC_LOOP;
-                               } else {
-                                       /* If we are a N-port connected to a
-                                        * Fabric, fixup sparam's so logins to
-                                        * devices on remote loops work.
-                                        */
-                                       phba->fc_sparam.cmn.altBbCredit = 1;
-                               }
-
-                               phba->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
-
-                               memcpy(&ndlp->nlp_portname, &sp->portName,
-                                      sizeof (struct lpfc_name));
-                               memcpy(&ndlp->nlp_nodename, &sp->nodeName,
-                                      sizeof (struct lpfc_name));
-                               memcpy(&phba->fc_fabparam, sp,
-                                      sizeof (struct serv_parm));
-                               if ((mbox = mempool_alloc(phba->mbox_mem_pool,
-                                                         GFP_ATOMIC)) == 0) {
-                                       goto flogifail;
-                               }
-                               phba->hba_state = LPFC_FABRIC_CFG_LINK;
-                               lpfc_config_link(phba, mbox);
-                               if (lpfc_sli_issue_mbox
-                                   (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB))
-                                   == MBX_NOT_FINISHED) {
-                                       mempool_free(mbox, phba->mbox_mem_pool);
-                                       goto flogifail;
-                               }
+                               irsp->ulpStatus, irsp->un.ulpWord[4],
+                               irsp->ulpTimeout);
+               goto flogifail;
+       }
 
-                               if ((mbox = mempool_alloc(phba->mbox_mem_pool,
-                                                         GFP_ATOMIC)) == 0) {
-                                       goto flogifail;
-                               }
-                               if (lpfc_reg_login(phba, Fabric_DID,
-                                                  (uint8_t *) sp, mbox,
-                                                  0) == 0) {
-                                       /* 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;
-                                       if (lpfc_sli_issue_mbox
-                                           (phba, mbox,
-                                            (MBX_NOWAIT | MBX_STOP_IOCB))
-                                           == MBX_NOT_FINISHED) {
-                                               mempool_free(mbox,
-                                                    phba->mbox_mem_pool);
-                                               goto flogifail;
-                                       }
-                               } else {
-                                       mempool_free(mbox, phba->mbox_mem_pool);
-                                       goto flogifail;
-                               }
-                       } else {
-                               /* We FLOGIed into an NPort, initiate pt2pt
-                                  protocol */
-                               phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
-                               phba->fc_edtov = FF_DEF_EDTOV;
-                               phba->fc_ratov = FF_DEF_RATOV;
-                               rc = memcmp(&phba->fc_portname, &sp->portName,
-                                           sizeof(struct lpfc_name));
-                               if (rc >= 0) {
-                                       /* This side will initiate the PLOGI */
-                                       phba->fc_flag |= FC_PT2PT_PLOGI;
-
-                                       /* N_Port ID cannot be 0, set our to
-                                        * LocalID the other side will be
-                                        * RemoteID.
-                                        */
+       /*
+        * The FLogI succeeded.  Sync the data for the CPU before
+        * accessing it.
+        */
+       prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
 
-                                       /* not equal */
-                                       if (rc)
-                                               phba->fc_myDID = PT2PT_LocalID;
+       sp = prsp->virt + sizeof(uint32_t);
 
-                                       if ((mbox =
-                                            mempool_alloc(phba->mbox_mem_pool,
-                                                          GFP_ATOMIC))
-                                           == 0) {
-                                               goto flogifail;
-                                       }
-                                       lpfc_config_link(phba, mbox);
-                                       if (lpfc_sli_issue_mbox
-                                           (phba, mbox,
-                                            (MBX_NOWAIT | MBX_STOP_IOCB))
-                                           == MBX_NOT_FINISHED) {
-                                               mempool_free(mbox,
-                                                    phba->mbox_mem_pool);
-                                               goto flogifail;
-                                       }
-                                       mempool_free( ndlp, phba->nlp_mem_pool);
-
-                                       if ((ndlp =
-                                            lpfc_findnode_did(phba,
-                                                              NLP_SEARCH_ALL,
-                                                              PT2PT_RemoteID))
-                                           == 0) {
-                                               /* Cannot find existing Fabric
-                                                  ndlp, so allocate a new
-                                                  one */
-                                               if ((ndlp =
-                                                    mempool_alloc(
-                                                          phba->nlp_mem_pool,
-                                                          GFP_ATOMIC)) == 0) {
-                                                       goto flogifail;
-                                               }
-                                               lpfc_nlp_init(phba, ndlp,
-                                                       PT2PT_RemoteID);
-                                       }
-                                       memcpy(&ndlp->nlp_portname,
-                                              &sp->portName,
-                                              sizeof (struct lpfc_name));
-                                       memcpy(&ndlp->nlp_nodename,
-                                              &sp->nodeName,
-                                              sizeof (struct lpfc_name));
-                                       ndlp->nlp_state = NLP_STE_NPR_NODE;
-                                       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
-                                       ndlp->nlp_flag |= NLP_NPR_2B_DISC;
-                               }
-                               else {
-                                       /* This side will wait for the PLOGI */
-                                       mempool_free( ndlp, phba->nlp_mem_pool);
-                               }
+       /* FLOGI completes successfully */
+       lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+                       "%d:0101 FLOGI completes sucessfully "
+                       "Data: x%x x%x x%x x%x\n",
+                       phba->brd_no,
+                       irsp->un.ulpWord[4], sp->cmn.e_d_tov,
+                       sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
 
-                               phba->fc_flag |= FC_PT2PT;
+       if (phba->hba_state == LPFC_FLOGI) {
+               /*
+                * If Common Service Parameters indicate Nport
+                * we are point to point, if Fport we are Fabric.
+                */
+               if (sp->cmn.fPort)
+                       rc = lpfc_cmpl_els_flogi_fabric(phba, ndlp, sp, irsp);
+               else
+                       rc = lpfc_cmpl_els_flogi_nport(phba, ndlp, sp);
 
-                               /* Start discovery - this should just do
-                                  CLEAR_LA */
-                               lpfc_disc_start(phba);
-                       }
+               if (!rc)
                        goto out;
-               }
        }
 
 flogifail:
        lpfc_nlp_remove(phba, ndlp);
 
-       if((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
-          ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
-          (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) {
-
+       if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
+           (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED &&
+            irsp->un.ulpWord[4] != IOERR_SLI_DOWN)) {
                /* FLOGI failed, so just use loop map to make discovery list */
                lpfc_disc_list_loopmap(phba);
 
@@ -495,7 +493,6 @@ flogifail:
 
 out:
        lpfc_els_free_iocb(phba, cmdiocb);
-       return;
 }
 
 static int
@@ -506,20 +503,18 @@ lpfc_issue_els_flogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        IOCB_t *icmd;
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
-       struct lpfc_sli *psli;
-       struct lpfc_dmabuf *bmp;
        uint8_t *pcmd;
        uint16_t cmdsize;
        uint32_t tmo;
+       int rc;
 
-       psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
+       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) {
-               return (1);
-       }
+       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);
@@ -546,72 +541,65 @@ lpfc_issue_els_flogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        lpfc_set_disctmo(phba);
        phba->fc_ratov = tmo;
 
-       /* Flush the els buffer to main store for the HBA.  This context always
-        * comes from the driver's dma pool and is always LPFC_BPL_SIZE.
-        */
-       bmp = (struct lpfc_dmabuf *) (elsiocb->context2);
-       pci_dma_sync_single_for_device(phba->pcidev, bmp->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        phba->fc_stat.elsXmitFLOGI++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi;
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+       spin_lock_irq(phba->host->host_lock);
+       rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       spin_unlock_irq(phba->host->host_lock);
+       if (rc == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
-               return (1);
+               return 1;
        }
-       return (0);
+       return 0;
 }
 
 int
 lpfc_els_abort_flogi(struct lpfc_hba * phba)
 {
-       struct lpfc_sli *psli;
        struct lpfc_sli_ring *pring;
        struct lpfc_iocbq *iocb, *next_iocb;
        struct lpfc_nodelist *ndlp;
        IOCB_t *icmd;
-       struct list_head *curr, *next;
 
        /* Abort outstanding I/O on NPort <nlp_DID> */
        lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
                        "%d:0201 Abort outstanding I/O on NPort x%x\n",
                        phba->brd_no, Fabric_DID);
 
-       psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];
+       pring = &phba->sli.ring[LPFC_ELS_RING];
 
-       /* check the txcmplq */
-       list_for_each_safe(curr, next, &pring->txcmplq) {
-               next_iocb = list_entry(curr, struct lpfc_iocbq, list);
-               iocb = next_iocb;
-               /* Check to see if iocb matches the nport we are
-                  looking for */
+       /*
+        * Check the txcmplq for an iocb that matches the nport the driver is
+        * searching for.
+        */
+       spin_lock_irq(phba->host->host_lock);
+       list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
                icmd = &iocb->iocb;
                if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) {
                        ndlp = (struct lpfc_nodelist *)(iocb->context1);
-                       if(ndlp && (ndlp->nlp_DID == Fabric_DID)) {
-                               /* It matches, so deque and call compl
-                                  with an error */
+                       if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
                                list_del(&iocb->list);
                                pring->txcmplq_cnt--;
 
                                if ((icmd->un.elsreq64.bdl.ulpIoTag32)) {
                                        lpfc_sli_issue_abort_iotag32
-                                           (phba, pring, iocb);
+                                               (phba, pring, iocb);
                                }
                                if (iocb->iocb_cmpl) {
-                                       icmd->ulpStatus =
-                                           IOSTAT_LOCAL_REJECT;
+                                       icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
                                        icmd->un.ulpWord[4] =
                                            IOERR_SLI_ABORTED;
+                                       spin_unlock_irq(phba->host->host_lock);
                                        (iocb->iocb_cmpl) (phba, iocb, iocb);
-                               } else {
-                                       mempool_free(iocb, phba->iocb_mem_pool);
-                               }
+                                       spin_lock_irq(phba->host->host_lock);
+                               } else
+                                       lpfc_sli_release_iocbq(phba, iocb);
                        }
                }
        }
-       return (0);
+       spin_unlock_irq(phba->host->host_lock);
+
+       return 0;
 }
 
 int
@@ -619,27 +607,21 @@ lpfc_initial_flogi(struct lpfc_hba * phba)
 {
        struct lpfc_nodelist *ndlp;
 
-       /* First look for Fabric ndlp on the unmapped list */
-
-       if ((ndlp =
-            lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
-                              Fabric_DID)) == 0) {
+       /* First look for the Fabric ndlp */
+       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, Fabric_DID);
+       if (!ndlp) {
                /* Cannot find existing Fabric ndlp, so allocate a new one */
-               if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC))
-                   == 0) {
-                       return (0);
-               }
+               ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+               if (!ndlp)
+                       return 0;
                lpfc_nlp_init(phba, ndlp, Fabric_DID);
-       }
-       else {
-               phba->fc_unmap_cnt--;
-               list_del(&ndlp->nlp_listp);
-               ndlp->nlp_flag &= ~NLP_LIST_MASK;
+       } else {
+               lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ);
        }
        if (lpfc_issue_els_flogi(phba, ndlp, 0)) {
                mempool_free( ndlp, phba->nlp_mem_pool);
        }
-       return (1);
+       return 1;
 }
 
 static void
@@ -665,40 +647,96 @@ lpfc_more_plogi(struct lpfc_hba * phba)
        return;
 }
 
+static struct lpfc_nodelist *
+lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+                        struct lpfc_nodelist *ndlp)
+{
+       struct lpfc_nodelist *new_ndlp;
+       struct lpfc_dmabuf *pcmd, *prsp;
+       uint32_t *lp;
+       struct serv_parm *sp;
+       uint8_t name[sizeof (struct lpfc_name)];
+       uint32_t rc;
+
+       pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+       prsp = (struct lpfc_dmabuf *) pcmd->list.next;
+       lp = (uint32_t *) prsp->virt;
+       sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+
+       /* 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);
+
+       memset(name, 0, sizeof (struct lpfc_name));
+       rc =  memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name));
+       if (!rc || (new_ndlp == ndlp)) {
+               return ndlp;
+       }
+
+       if (!new_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_prev_state = ndlp->nlp_state;
+       new_ndlp->nlp_DID = ndlp->nlp_DID;
+       new_ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+       lpfc_nlp_list(phba, new_ndlp, NLP_PLOGI_LIST);
+
+       /* Move this back to NPR list */
+       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;
        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->nlp_flag &= ~NLP_PLOGI_SND;
+       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_NPR_2B_DISC;
+       spin_unlock_irq(phba->host->host_lock);
        rc   = 0;
 
        /* PLOGI completes to NPort <nlp_DID> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                        "%d:0102 PLOGI completes to NPort x%x "
-                       "Data: x%x x%x x%x x%x\n",
+                       "Data: x%x x%x x%x x%x x%x\n",
                        phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
-                       irsp->un.ulpWord[4], disc, phba->num_disc_nodes);
+                       irsp->un.ulpWord[4], irsp->ulpTimeout, disc,
+                       phba->num_disc_nodes);
 
        /* Check to see if link went down during discovery */
        if (lpfc_els_chk_latt(phba)) {
+               spin_lock_irq(phba->host->host_lock);
                ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+               spin_unlock_irq(phba->host->host_lock);
                goto out;
        }
 
@@ -711,55 +749,54 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
                        /* ELS command is being retried */
                        if (disc) {
+                               spin_lock_irq(phba->host->host_lock);
                                ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+                               spin_unlock_irq(phba->host->host_lock);
                        }
                        goto out;
                }
 
                /* PLOGI failed */
                /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
-               if((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+               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))) {
-                       disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
-               }
-               else {
+                       rc = NLP_STE_FREED_NODE;
+               } else {
                        rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb,
                                        NLP_EVT_CMPL_PLOGI);
                }
        } else {
                /* Good status, call state machine */
+               ndlp = lpfc_plogi_confirm_nport(phba, cmdiocb, 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 (rc != NLP_STE_FREED_NODE)
-               ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
-
-       if (phba->num_disc_nodes == 0) {
-               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))) {
-                               lpfc_els_flush_rscn(phba);
-                       } else {
-                               lpfc_els_handle_rscn(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);
+
+                       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);
+                               }
                        }
                }
        }
@@ -770,15 +807,13 @@ 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;
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
-       struct lpfc_dmabuf *bmp;
        uint8_t *pcmd;
        uint16_t cmdsize;
 
@@ -786,10 +821,10 @@ 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));
-       if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry,
-                                         ndlp, ELS_CMD_PLOGI)) == 0) {
-               return (1);
-       }
+       elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, 0, did,
+                                                               ELS_CMD_PLOGI);
+       if (!elsiocb)
+               return 1;
 
        icmd = &elsiocb->iocb;
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
@@ -806,23 +841,16 @@ lpfc_issue_els_plogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        if (sp->cmn.fcphHigh < FC_PH3)
                sp->cmn.fcphHigh = FC_PH3;
 
-       /* The lpfc iocb is fully initialize.  Flush it to main store for the
-        * HBA.  Note that all els iocb context buffer are from the driver's
-        * dma pool and have length LPFC_BPL_SIZE.
-        */
-       bmp = (struct lpfc_dmabuf *) (elsiocb->context2);
-       pci_dma_sync_single_for_device(phba->pcidev, bmp->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        phba->fc_stat.elsXmitPLOGI++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
-       ndlp->nlp_flag |= NLP_PLOGI_SND;
+       spin_lock_irq(phba->host->host_lock);
        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);
+               return 1;
        }
-       return (0);
+       spin_unlock_irq(phba->host->host_lock);
+       return 0;
 }
 
 static void
@@ -839,14 +867,17 @@ lpfc_cmpl_els_prli(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 
        irsp = &(rspiocb->iocb);
        ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+       spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~NLP_PRLI_SND;
+       spin_unlock_irq(phba->host->host_lock);
 
        /* PRLI completes to NPort <nlp_DID> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                        "%d:0103 PRLI completes to NPort x%x "
-                       "Data: x%x x%x x%x\n",
+                       "Data: x%x x%x x%x x%x\n",
                        phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
-                       irsp->un.ulpWord[4], phba->num_disc_nodes);
+                       irsp->un.ulpWord[4], irsp->ulpTimeout,
+                       phba->num_disc_nodes);
 
        phba->fc_prli_sent--;
        /* Check to see if link went down during discovery */
@@ -861,12 +892,12 @@ lpfc_cmpl_els_prli(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                }
                /* PRLI failed */
                /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
-               if((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+               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))) {
                        goto out;
-               }
-               else {
+               } else {
                        lpfc_disc_state_machine(phba, ndlp, cmdiocb,
                                        NLP_EVT_CMPL_PRLI);
                }
@@ -889,7 +920,6 @@ lpfc_issue_els_prli(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
-       struct lpfc_dmabuf *bmp;
        uint8_t *pcmd;
        uint16_t cmdsize;
 
@@ -897,10 +927,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) {
-               return (1);
-       }
+       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);
@@ -928,24 +958,19 @@ lpfc_issue_els_prli(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        npr->prliType = PRLI_FCP_TYPE;
        npr->initiatorFunc = 1;
 
-       /* The lpfc iocb is fully initialize.  Flush it to main store for the
-        * HBA.  Note that all els iocb context buffer are from the driver's
-        * dma pool and have length LPFC_BPL_SIZE.
-        */
-       bmp = (struct lpfc_dmabuf *) (elsiocb->context2);
-       pci_dma_sync_single_for_device(phba->pcidev, bmp->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        phba->fc_stat.elsXmitPRLI++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_prli;
+       spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag |= NLP_PRLI_SND;
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
                ndlp->nlp_flag &= ~NLP_PRLI_SND;
+               spin_unlock_irq(phba->host->host_lock);
                lpfc_els_free_iocb(phba, elsiocb);
-               return (1);
+               return 1;
        }
+       spin_unlock_irq(phba->host->host_lock);
        phba->fc_prli_sent++;
-       return (0);
+       return 0;
 }
 
 static void
@@ -979,8 +1004,8 @@ lpfc_rscn_disc(struct lpfc_hba * phba)
        /* RSCN discovery */
        /* go thru NPR list and issue ELS PLOGIs */
        if (phba->fc_npr_cnt) {
-               lpfc_els_disc_plogi(phba);
-               return;
+               if (lpfc_els_disc_plogi(phba))
+                       return;
        }
        if (phba->fc_flag & FC_RSCN_MODE) {
                /* Check to see if more RSCNs came in while we were
@@ -988,7 +1013,9 @@ lpfc_rscn_disc(struct lpfc_hba * phba)
                 */
                if ((phba->fc_rscn_id_cnt == 0) &&
                    (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
-                       lpfc_els_flush_rscn(phba);
+                       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);
                }
@@ -1003,7 +1030,7 @@ lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        struct lpfc_sli *psli;
        struct lpfc_nodelist *ndlp;
        LPFC_MBOXQ_t *mbox;
-       int disc;
+       int disc, rc;
 
        psli = &phba->sli;
 
@@ -1012,23 +1039,28 @@ lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 
        irsp = &(rspiocb->iocb);
        ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
-       ndlp->nlp_flag &= ~NLP_ADISC_SND;
 
        /* 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_ADISC_SND | NLP_NPR_2B_DISC);
+       spin_unlock_irq(phba->host->host_lock);
 
        /* ADISC completes to NPort <nlp_DID> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                        "%d:0104 ADISC completes to NPort x%x "
-                       "Data: x%x x%x x%x x%x\n",
+                       "Data: x%x x%x x%x x%x x%x\n",
                        phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
-                       irsp->un.ulpWord[4], disc, phba->num_disc_nodes);
+                       irsp->un.ulpWord[4], irsp->ulpTimeout, disc,
+                       phba->num_disc_nodes);
 
        /* Check to see if link went down during discovery */
        if (lpfc_els_chk_latt(phba)) {
+               spin_lock_irq(phba->host->host_lock);
                ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+               spin_unlock_irq(phba->host->host_lock);
                goto out;
        }
 
@@ -1037,19 +1069,19 @@ lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
                        /* ELS command is being retried */
                        if (disc) {
+                               spin_lock_irq(phba->host->host_lock);
                                ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+                               spin_unlock_irq(phba->host->host_lock);
                                lpfc_set_disctmo(phba);
                        }
                        goto out;
                }
                /* ADISC failed */
                /* Do not call DSM 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_SLI_DOWN))) {
-                       disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
-               }
-               else {
+               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))) {
                        lpfc_disc_state_machine(phba, ndlp, cmdiocb,
                                        NLP_EVT_CMPL_ADISC);
                }
@@ -1065,20 +1097,21 @@ lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 
                /* Check to see if we are done with ADISC authentication */
                if (phba->num_disc_nodes == 0) {
+                       lpfc_can_disctmo(phba);
                        /* If we get here, there is nothing left to wait for */
                        if ((phba->hba_state < LPFC_HBA_READY) &&
                            (phba->hba_state != LPFC_CLEAR_LA)) {
                                /* Link up discovery */
                                if ((mbox = mempool_alloc(phba->mbox_mem_pool,
-                                                         GFP_ATOMIC))) {
+                                                         GFP_KERNEL))) {
                                        phba->hba_state = LPFC_CLEAR_LA;
                                        lpfc_clear_la(phba, mbox);
                                        mbox->mbox_cmpl =
                                            lpfc_mbx_cmpl_clear_la;
-                                       if (lpfc_sli_issue_mbox
-                                           (phba, mbox,
-                                            (MBX_NOWAIT | MBX_STOP_IOCB))
-                                           == MBX_NOT_FINISHED) {
+                                       rc = lpfc_sli_issue_mbox
+                                               (phba, mbox,
+                                                (MBX_NOWAIT | MBX_STOP_IOCB));
+                                       if (rc == MBX_NOT_FINISHED) {
                                                mempool_free(mbox,
                                                     phba->mbox_mem_pool);
                                                lpfc_disc_flush_list(phba);
@@ -1100,7 +1133,6 @@ lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                        }
                }
        }
-       ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
 out:
        lpfc_els_free_iocb(phba, cmdiocb);
        return;
@@ -1115,7 +1147,6 @@ lpfc_issue_els_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
-       struct lpfc_dmabuf *bmp;
        uint8_t *pcmd;
        uint16_t cmdsize;
 
@@ -1123,10 +1154,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) {
-               return (1);
-       }
+       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);
@@ -1142,24 +1173,18 @@ lpfc_issue_els_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        memcpy(&ap->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
        ap->DID = be32_to_cpu(phba->fc_myDID);
 
-       /* The lpfc iocb is fully initialize.  Flush it to main store for the
-        * HBA.  Note that all els iocb context buffer are from the driver's
-        * dma pool and have length LPFC_BPL_SIZE. Get a short-hand pointer to
-        * the physical address.
-        */
-       bmp = (struct lpfc_dmabuf *) (elsiocb->context2);
-       pci_dma_sync_single_for_device(phba->pcidev, bmp->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        phba->fc_stat.elsXmitADISC++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc;
+       spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag |= NLP_ADISC_SND;
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
                ndlp->nlp_flag &= ~NLP_ADISC_SND;
+               spin_unlock_irq(phba->host->host_lock);
                lpfc_els_free_iocb(phba, elsiocb);
-               return (1);
+               return 1;
        }
-       return (0);
+       spin_unlock_irq(phba->host->host_lock);
+       return 0;
 }
 
 static void
@@ -1176,14 +1201,17 @@ lpfc_cmpl_els_logo(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 
        irsp = &(rspiocb->iocb);
        ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+       spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~NLP_LOGO_SND;
+       spin_unlock_irq(phba->host->host_lock);
 
        /* LOGO completes to NPort <nlp_DID> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                        "%d:0105 LOGO completes to NPort x%x "
-                       "Data: x%x x%x x%x\n",
+                       "Data: x%x x%x x%x x%x\n",
                        phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
-                       irsp->un.ulpWord[4], phba->num_disc_nodes);
+                       irsp->un.ulpWord[4], irsp->ulpTimeout,
+                       phba->num_disc_nodes);
 
        /* Check to see if link went down during discovery */
        if (lpfc_els_chk_latt(phba))
@@ -1197,22 +1225,20 @@ lpfc_cmpl_els_logo(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                }
                /* LOGO failed */
                /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
-               if((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+               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))) {
                        goto out;
-               }
-               else {
+               } else {
                        lpfc_disc_state_machine(phba, ndlp, cmdiocb,
                                        NLP_EVT_CMPL_LOGO);
                }
        } else {
-               /* Good status, call state machine */
+               /* Good status, call state machine.
+                * This will unregister the rpi if needed.
+                */
                lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_LOGO);
-
-               if(ndlp->nlp_flag & NLP_DELAY_TMO) {
-                       lpfc_unreg_rpi(phba, ndlp);
-               }
        }
 
 out:
@@ -1228,18 +1254,17 @@ lpfc_issue_els_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
-       struct lpfc_dmabuf *bmp;
        uint8_t *pcmd;
        uint16_t cmdsize;
 
        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) {
-               return (1);
-       }
+       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);
@@ -1251,24 +1276,18 @@ lpfc_issue_els_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        pcmd += sizeof (uint32_t);
        memcpy(pcmd, &phba->fc_portname, sizeof (struct lpfc_name));
 
-       /* The els iocb is fully initialize.  Flush it to main store for the
-        * HBA.  Note that all els iocb context buffer are from the driver's
-        * dma pool and have length LPFC_BPL_SIZE. Get a short-hand pointer to
-        * the physical address.
-        */
-       bmp = (struct lpfc_dmabuf *) (elsiocb->context2);
-       pci_dma_sync_single_for_device(phba->pcidev, bmp->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        phba->fc_stat.elsXmitLOGO++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_logo;
+       spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag |= NLP_LOGO_SND;
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
                ndlp->nlp_flag &= ~NLP_LOGO_SND;
+               spin_unlock_irq(phba->host->host_lock);
                lpfc_els_free_iocb(phba, elsiocb);
-               return (1);
+               return 1;
        }
-       return (0);
+       spin_unlock_irq(phba->host->host_lock);
+       return 0;
 }
 
 static void
@@ -1283,9 +1302,10 @@ lpfc_cmpl_els_cmd(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        lpfc_printf_log(phba,
                        KERN_INFO,
                        LOG_ELS,
-                       "%d:0106 ELS cmd tag x%x completes Data: x%x x%x\n",
+                       "%d:0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n",
                        phba->brd_no,
-                       irsp->ulpIoTag, irsp->ulpStatus, irsp->un.ulpWord[4]);
+                       irsp->ulpIoTag, irsp->ulpStatus,
+                       irsp->un.ulpWord[4], irsp->ulpTimeout);
 
        /* Check to see if link went down during discovery */
        lpfc_els_chk_latt(phba);
@@ -1300,7 +1320,6 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
-       struct lpfc_dmabuf *bmp;
        uint8_t *pcmd;
        uint16_t cmdsize;
        struct lpfc_nodelist *ndlp;
@@ -1308,16 +1327,17 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        psli = &phba->sli;
        pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
        cmdsize = (sizeof (uint32_t) + sizeof (SCR));
-       if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC)) == 0) {
-               return (1);
-       }
+       ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+       if (!ndlp)
+               return 1;
 
        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);
+               return 1;
        }
 
        icmd = &elsiocb->iocb;
@@ -1330,24 +1350,18 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        memset(pcmd, 0, sizeof (SCR));
        ((SCR *) pcmd)->Function = SCR_FUNC_FULL;
 
-       /* The els iocb is fully initialize.  Flush it to main store for the
-        * HBA.  Note that all els iocb context buffer are from the driver's
-        * dma pool and have length LPFC_BPL_SIZE. Get a short-hand pointer to
-        * the physical address.
-        */
-       bmp = (struct lpfc_dmabuf *) (elsiocb->context2);
-       pci_dma_sync_single_for_device(phba->pcidev, bmp->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        phba->fc_stat.elsXmitSCR++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
+       spin_lock_irq(phba->host->host_lock);
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+               spin_unlock_irq(phba->host->host_lock);
                mempool_free( ndlp, phba->nlp_mem_pool);
                lpfc_els_free_iocb(phba, elsiocb);
-               return (1);
+               return 1;
        }
+       spin_unlock_irq(phba->host->host_lock);
        mempool_free( ndlp, phba->nlp_mem_pool);
-       return (0);
+       return 0;
 }
 
 static int
@@ -1357,7 +1371,6 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
-       struct lpfc_dmabuf *bmp;
        FARP *fp;
        uint8_t *pcmd;
        uint32_t *lp;
@@ -1368,15 +1381,16 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        psli = &phba->sli;
        pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
        cmdsize = (sizeof (uint32_t) + sizeof (FARP));
-       if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC)) == 0) {
-               return (1);
-       }
+       ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+       if (!ndlp)
+               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);
+               return 1;
        }
 
        icmd = &elsiocb->iocb;
@@ -1403,43 +1417,116 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
                       sizeof (struct lpfc_name));
        }
 
-       /* The els iocb is fully initialize.  Flush it to main store for the
-        * HBA.  Note that all els iocb context buffer are from the driver's
-        * dma pool and have length LPFC_BPL_SIZE. Get a short-hand pointer to
-        * the physical address.
-        */
-       bmp = (struct lpfc_dmabuf *) (elsiocb->context2);
-       pci_dma_sync_single_for_device(phba->pcidev, bmp->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        phba->fc_stat.elsXmitFARPR++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
+       spin_lock_irq(phba->host->host_lock);
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+               spin_unlock_irq(phba->host->host_lock);
                mempool_free( ndlp, phba->nlp_mem_pool);
                lpfc_els_free_iocb(phba, elsiocb);
-               return (1);
+               return 1;
        }
+       spin_unlock_irq(phba->host->host_lock);
        mempool_free( ndlp, phba->nlp_mem_pool);
-       return (0);
+       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)
 {
-       struct lpfc_hba *phba;
        struct lpfc_nodelist *ndlp;
-       uint32_t cmd;
-       uint32_t did;
-       uint8_t retry;
+       struct lpfc_hba *phba;
        unsigned long iflag;
+       struct lpfc_work_evt  *evtp;
 
        ndlp = (struct lpfc_nodelist *)ptr;
        phba = ndlp->nlp_phba;
+       evtp = &ndlp->els_retry_evt;
+
        spin_lock_irqsave(phba->host->host_lock, iflag);
-       did = (uint32_t) (ndlp->nlp_DID);
-       cmd = (uint32_t) (ndlp->nlp_last_elscmd);
+       if (!list_empty(&evtp->evt_listp)) {
+               spin_unlock_irqrestore(phba->host->host_lock, iflag);
+               return;
+       }
+
+       evtp->evt_arg1  = ndlp;
+       evtp->evt       = LPFC_EVT_ELS_RETRY;
+       list_add_tail(&evtp->evt_listp, &phba->work_list);
+       if (phba->work_wait)
+               wake_up(phba->work_wait);
+
+       spin_unlock_irqrestore(phba->host->host_lock, iflag);
+       return;
+}
+
+void
+lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
+{
+       struct lpfc_hba *phba;
+       uint32_t cmd;
+       uint32_t did;
+       uint8_t retry;
+
+       phba = ndlp->nlp_phba;
+       spin_lock_irq(phba->host->host_lock);
+       did = ndlp->nlp_DID;
+       cmd = ndlp->nlp_last_elscmd;
+       ndlp->nlp_last_elscmd = 0;
+
+       if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
+               spin_unlock_irq(phba->host->host_lock);
+               return;
+       }
 
        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) {
@@ -1447,27 +1534,34 @@ lpfc_els_retry_delay(unsigned long ptr)
                lpfc_issue_els_flogi(phba, ndlp, retry);
                break;
        case ELS_CMD_PLOGI:
-               ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-               lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
-               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);
+               }
                break;
        case ELS_CMD_ADISC:
-               ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-               lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
-               lpfc_issue_els_adisc(phba, ndlp, retry);
+               if (!lpfc_issue_els_adisc(phba, ndlp, retry)) {
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
+                       ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
+                       lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+               }
                break;
        case ELS_CMD_PRLI:
-               ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
-               lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
-               lpfc_issue_els_prli(phba, ndlp, retry);
+               if (!lpfc_issue_els_prli(phba, ndlp, retry)) {
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
+                       ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
+                       lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+               }
                break;
        case ELS_CMD_LOGO:
-               ndlp->nlp_state = NLP_STE_NPR_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
-               lpfc_issue_els_logo(phba, ndlp, retry);
+               if (!lpfc_issue_els_logo(phba, ndlp, retry)) {
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
+                       ndlp->nlp_state = NLP_STE_NPR_NODE;
+                       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               }
                break;
        }
-       spin_unlock_irqrestore(phba->host->host_lock, iflag);
        return;
 }
 
@@ -1483,6 +1577,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;
@@ -1491,6 +1586,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.
         */
@@ -1500,6 +1596,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:
@@ -1518,11 +1624,6 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 
                case IOERR_SEQUENCE_TIMEOUT:
                        retry = 1;
-                       if ((cmd == ELS_CMD_FLOGI)
-                           && (phba->fc_topology != TOPOLOGY_LOOP)) {
-                               delay = 1;
-                               maxretry = 48;
-                       }
                        break;
 
                case IOERR_NO_RESOURCES:
@@ -1593,9 +1694,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++;
@@ -1609,7 +1709,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 */
@@ -1620,54 +1720,61 @@ 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;
 
                        mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
                        ndlp->nlp_flag |= NLP_DELAY_TMO;
 
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
                        ndlp->nlp_state = NLP_STE_NPR_NODE;
                        lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
                        ndlp->nlp_last_elscmd = cmd;
 
-                       return (1);
+                       return 1;
                }
                switch (cmd) {
                case ELS_CMD_FLOGI:
                        lpfc_issue_els_flogi(phba, ndlp, cmdiocb->retry);
-                       return (1);
+                       return 1;
                case ELS_CMD_PLOGI:
-                       ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
-                       lpfc_issue_els_plogi(phba, ndlp, cmdiocb->retry);
-                       return (1);
+                       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;
                        ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
                        lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
                        lpfc_issue_els_adisc(phba, ndlp, cmdiocb->retry);
-                       return (1);
+                       return 1;
                case ELS_CMD_PRLI:
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
                        ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
                        lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
                        lpfc_issue_els_prli(phba, ndlp, cmdiocb->retry);
-                       return (1);
+                       return 1;
                case ELS_CMD_LOGO:
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
                        ndlp->nlp_state = NLP_STE_NPR_NODE;
                        lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
                        lpfc_issue_els_logo(phba, ndlp, cmdiocb->retry);
-                       return (1);
+                       return 1;
                }
        }
 
        /* 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);
+       return 0;
 }
 
 int
@@ -1680,8 +1787,9 @@ lpfc_els_free_iocb(struct lpfc_hba * phba, struct lpfc_iocbq * elsiocb)
                buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
                /* Free the response before processing the command.  */
                if (!list_empty(&buf_ptr1->list)) {
-                       buf_ptr = list_entry(buf_ptr1->list.next,
-                                            struct lpfc_dmabuf, list);
+                       list_remove_head(&buf_ptr1->list, buf_ptr,
+                                        struct lpfc_dmabuf,
+                                        list);
                        lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
                        kfree(buf_ptr);
                }
@@ -1694,8 +1802,9 @@ lpfc_els_free_iocb(struct lpfc_hba * phba, struct lpfc_iocbq * elsiocb)
                lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
                kfree(buf_ptr);
        }
-
-       mempool_free( elsiocb, phba->iocb_mem_pool);
+       spin_lock_irq(phba->host->host_lock);
+       lpfc_sli_release_iocbq(phba, elsiocb);
+       spin_unlock_irq(phba->host->host_lock);
        return 0;
 }
 
@@ -1714,8 +1823,6 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                        phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
                        ndlp->nlp_state, ndlp->nlp_rpi);
 
-       ndlp->nlp_flag &= ~NLP_LOGO_ACC;
-
        switch (ndlp->nlp_state) {
        case NLP_STE_UNUSED_NODE:       /* node is just allocated */
                lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
@@ -1753,21 +1860,20 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        /* ELS response tag <ulpIoTag> completes */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                        "%d:0110 ELS response tag x%x completes "
-                       "Data: x%x x%x x%x x%x x%x x%x\n",
+                       "Data: x%x x%x x%x x%x x%x x%x x%x\n",
                        phba->brd_no,
                        cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
-                       rspiocb->iocb.un.ulpWord[4], ndlp->nlp_DID,
-                       ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+                       rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
+                       ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+                       ndlp->nlp_rpi);
 
        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;
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
                        ndlp->nlp_state = NLP_STE_REG_LOGIN_ISSUE;
                        lpfc_nlp_list(phba, ndlp, NLP_REGLOGIN_LIST);
                        if (lpfc_sli_issue_mbox(phba, mbox,
@@ -1782,12 +1888,16 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                        mempool_free( mbox, phba->mbox_mem_pool);
                        if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
                                lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                               ndlp = NULL;
                        }
                }
        }
 out:
-       if(ndlp)
+       if (ndlp) {
+               spin_lock_irq(phba->host->host_lock);
                ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN;
+               spin_unlock_irq(phba->host->host_lock);
+       }
        lpfc_els_free_iocb(phba, cmdiocb);
        return;
 }
@@ -1802,9 +1912,10 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
-       struct lpfc_dmabuf *bmp;
        uint8_t *pcmd;
        uint16_t cmdsize;
+       int rc;
+       ELS_PKT *els_pkt_ptr;
 
        psli = &phba->sli;
        pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
@@ -1813,10 +1924,11 @@ 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) {
-                       return (1);
+               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;
                }
                icmd = &elsiocb->iocb;
                icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
@@ -1826,11 +1938,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) {
-                       return (1);
-               }
+               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);
@@ -1842,8 +1954,25 @@ 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);
+               return 1;
        }
 
        if (newnode)
@@ -1858,22 +1987,24 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
-       bmp = (struct lpfc_dmabuf *) (elsiocb->context2);
-       pci_dma_sync_single_for_device(phba->pcidev, bmp->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        if (ndlp->nlp_flag & NLP_LOGO_ACC) {
+               spin_lock_irq(phba->host->host_lock);
+               ndlp->nlp_flag &= ~NLP_LOGO_ACC;
+               spin_unlock_irq(phba->host->host_lock);
                elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc;
        } else {
                elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
        }
 
        phba->fc_stat.elsXmitACC++;
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+       spin_lock_irq(phba->host->host_lock);
+       rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       spin_unlock_irq(phba->host->host_lock);
+       if (rc == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
-               return (1);
+               return 1;
        }
-       return (0);
+       return 0;
 }
 
 int
@@ -1885,18 +2016,18 @@ lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
-       struct lpfc_dmabuf *bmp;
        uint8_t *pcmd;
        uint16_t cmdsize;
+       int rc;
 
        psli = &phba->sli;
        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) {
-               return (1);
-       }
+       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;
@@ -1907,15 +2038,6 @@ lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
        pcmd += sizeof (uint32_t);
        *((uint32_t *) (pcmd)) = rejectError;
 
-       /* The els iocb is fully initialize.  Flush it to main store for the
-        * HBA.  Note that all els iocb context buffer are from the driver's
-        * dma pool and have length LPFC_BPL_SIZE. Get a short-hand pointer to
-        * the physical address.
-        */
-       bmp = (struct lpfc_dmabuf *) (elsiocb->context2);
-       pci_dma_sync_single_for_device(phba->pcidev, bmp->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        /* Xmit ELS RJT <err> response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                        "%d:0129 Xmit ELS RJT x%x response tag x%x "
@@ -1927,12 +2049,14 @@ lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
 
        phba->fc_stat.elsXmitLSRJT++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
-
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+       spin_lock_irq(phba->host->host_lock);
+       rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       spin_unlock_irq(phba->host->host_lock);
+       if (rc == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
-               return (1);
+               return 1;
        }
-       return (0);
+       return 0;
 }
 
 int
@@ -1945,18 +2069,18 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
-       struct lpfc_dmabuf *bmp;
        uint8_t *pcmd;
        uint16_t cmdsize;
+       int rc;
 
        psli = &phba->sli;
        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) {
-               return (1);
-       }
+       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,
@@ -1981,23 +2105,16 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
        memcpy(&ap->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
        ap->DID = be32_to_cpu(phba->fc_myDID);
 
-       /* The els iocb is fully initialize.  Flush it to main store for the
-        * HBA.  Note that all els iocb context buffer are from the driver's
-        * dma pool and have length LPFC_BPL_SIZE. Get a short-hand pointer to
-        * the physical address.
-        */
-       bmp = (struct lpfc_dmabuf *) (elsiocb->context2);
-       pci_dma_sync_single_for_device(phba->pcidev, bmp->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        phba->fc_stat.elsXmitACC++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
-
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+       spin_lock_irq(phba->host->host_lock);
+       rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       spin_unlock_irq(phba->host->host_lock);
+       if (rc == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
-               return (1);
+               return 1;
        }
-       return (0);
+       return 0;
 }
 
 int
@@ -2011,21 +2128,18 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
-       struct lpfc_dmabuf *bmp;
        uint8_t *pcmd;
        uint16_t cmdsize;
+       int rc;
 
        psli = &phba->sli;
        pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
 
        cmdsize = sizeof (uint32_t) + sizeof (PRLI);
-       if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
-                                         ndlp,
-                                         (ELS_CMD_ACC |
-                                          (ELS_CMD_PRLI & ~ELS_RSP_MASK)))) ==
-           0) {
-               return (1);
-       }
+       elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, ndlp,
+               ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
+       if (!elsiocb)
+               return 1;
 
        /* Xmit PRLI ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
@@ -2067,23 +2181,17 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
        npr->prliType = PRLI_FCP_TYPE;
        npr->initiatorFunc = 1;
 
-       /* The els iocb is fully initialize.  Flush it to main store for the
-        * HBA.  Note that all els iocb context buffer are from the driver's
-        * dma pool and have length LPFC_BPL_SIZE. Get a short-hand pointer to
-        * the physical address.
-        */
-       bmp = (struct lpfc_dmabuf *) (elsiocb->context2);
-       pci_dma_sync_single_for_device(phba->pcidev, bmp->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        phba->fc_stat.elsXmitACC++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
 
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+       spin_lock_irq(phba->host->host_lock);
+       rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       spin_unlock_irq(phba->host->host_lock);
+       if (rc == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
-               return (1);
+               return 1;
        }
-       return (0);
+       return 0;
 }
 
 static int
@@ -2097,9 +2205,9 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
        struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
-       struct lpfc_dmabuf *bmp;
        uint8_t *pcmd;
        uint16_t cmdsize;
+       int rc;
 
        psli = &phba->sli;
        pring = &psli->ring[LPFC_ELS_RING];
@@ -2109,10 +2217,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) {
-               return (1);
-       }
+       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,
@@ -2154,25 +2262,19 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
                break;
        }
 
-       /* The els iocb is fully initialize.  Flush it to main store for the
-        * HBA.  Note that all els iocb context buffer are from the driver's
-        * dma pool and have length LPFC_BPL_SIZE. Get a short-hand pointer to
-        * the physical address.
-        */
-       bmp = (struct lpfc_dmabuf *) (elsiocb->context2);
-       pci_dma_sync_single_for_device(phba->pcidev, bmp->phys,
-               LPFC_BPL_SIZE, PCI_DMA_TODEVICE);
-
        phba->fc_stat.elsXmitACC++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
        elsiocb->context1 = NULL;  /* Don't need ndlp for cmpl,
                                    * it could be freed */
 
-       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+       spin_lock_irq(phba->host->host_lock);
+       rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+       spin_unlock_irq(phba->host->host_lock);
+       if (rc == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
-               return (1);
+               return 1;
        }
-       return (0);
+       return 0;
 }
 
 int
@@ -2185,9 +2287,10 @@ lpfc_els_disc_adisc(struct lpfc_hba * phba)
        /* go thru NPR list and issue any remaining ELS ADISCs */
        list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
                        nlp_listp) {
-               if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
-                       if(ndlp->nlp_flag & NLP_NPR_ADISC) {
+               if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+                       if (ndlp->nlp_flag & NLP_NPR_ADISC) {
                                ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+                               ndlp->nlp_prev_state = ndlp->nlp_state;
                                ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
                                lpfc_nlp_list(phba, ndlp,
                                        NLP_ADISC_LIST);
@@ -2196,16 +2299,20 @@ lpfc_els_disc_adisc(struct lpfc_hba * phba)
                                phba->num_disc_nodes++;
                                if (phba->num_disc_nodes >=
                                    phba->cfg_discovery_threads) {
+                                       spin_lock_irq(phba->host->host_lock);
                                        phba->fc_flag |= FC_NLP_MORE;
+                                       spin_unlock_irq(phba->host->host_lock);
                                        break;
                                }
                        }
                }
        }
        if (sentadisc == 0) {
+               spin_lock_irq(phba->host->host_lock);
                phba->fc_flag &= ~FC_NLP_MORE;
+               spin_unlock_irq(phba->host->host_lock);
        }
-       return(sentadisc);
+       return sentadisc;
 }
 
 int
@@ -2218,26 +2325,31 @@ lpfc_els_disc_plogi(struct lpfc_hba * phba)
        /* go thru NPR list and issue any remaining ELS PLOGIs */
        list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
                                nlp_listp) {
-               if((ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
+               if ((ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
                   (!(ndlp->nlp_flag & NLP_DELAY_TMO))) {
-                       if(!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
+                       if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
+                               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 >=
                                    phba->cfg_discovery_threads) {
+                                       spin_lock_irq(phba->host->host_lock);
                                        phba->fc_flag |= FC_NLP_MORE;
+                                       spin_unlock_irq(phba->host->host_lock);
                                        break;
                                }
                        }
                }
        }
        if (sentplogi == 0) {
+               spin_lock_irq(phba->host->host_lock);
                phba->fc_flag &= ~FC_NLP_MORE;
+               spin_unlock_irq(phba->host->host_lock);
        }
-       return(sentplogi);
+       return sentplogi;
 }
 
 int
@@ -2253,9 +2365,11 @@ lpfc_els_flush_rscn(struct lpfc_hba * phba)
                phba->fc_rscn_id_list[i] = NULL;
        }
        phba->fc_rscn_id_cnt = 0;
+       spin_lock_irq(phba->host->host_lock);
        phba->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY);
+       spin_unlock_irq(phba->host->host_lock);
        lpfc_can_disctmo(phba);
-       return (0);
+       return 0;
 }
 
 int
@@ -2270,9 +2384,13 @@ lpfc_rscn_payload_check(struct lpfc_hba * phba, uint32_t did)
        ns_did.un.word = did;
        match = 0;
 
+       /* Never match fabric nodes for RSCNs */
+       if ((did & Fabric_DID_MASK) == Fabric_DID_MASK)
+               return(0);
+
        /* If we are doing a FULL RSCN rediscovery, match everything */
        if (phba->fc_flag & FC_RSCN_DISCOVERY) {
-               return (did);
+               return did;
        }
 
        for (i = 0; i < phba->fc_rscn_id_cnt; i++) {
@@ -2320,7 +2438,7 @@ lpfc_rscn_payload_check(struct lpfc_hba * phba, uint32_t did)
                        }
                }
        }
-       return (match);
+       return match;
 }
 
 static int
@@ -2347,22 +2465,20 @@ lpfc_rscn_recovery_check(struct lpfc_hba * phba)
                        continue;
 
                list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
-                       if((lpfc_rscn_payload_check(phba, ndlp->nlp_DID))) {
-                               /* part of RSCN, process this entry */
-                               lpfc_set_failmask(phba, ndlp,
-                                       LPFC_DEV_DISCOVERY_INP,
-                                       LPFC_SET_BITMASK);
-
-                               lpfc_disc_state_machine(phba, ndlp, NULL,
-                                               NLP_EVT_DEVICE_RECOVERY);
-                               if(ndlp->nlp_flag & NLP_DELAY_TMO) {
-                                       ndlp->nlp_flag &= ~NLP_DELAY_TMO;
-                                       del_timer_sync(&ndlp->nlp_delayfunc);
-                               }
-                       }
+                       if (!(lpfc_rscn_payload_check(phba, ndlp->nlp_DID)))
+                               continue;
+
+                       lpfc_disc_state_machine(phba, ndlp, NULL,
+                                       NLP_EVT_DEVICE_RECOVERY);
+
+                       /* Make sure NLP_DELAY_TMO is NOT running
+                        * after a device recovery event.
+                        */
+                       if (ndlp->nlp_flag & NLP_DELAY_TMO)
+                               lpfc_cancel_retry_delay_tmo(phba, ndlp);
                }
        }
-       return (0);
+       return 0;
 }
 
 static int
@@ -2379,13 +2495,6 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba,
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
        lp = (uint32_t *) pcmd->virt;
 
-       /* The response iocb was populated by the HBA.  Flush it to main store
-        * for the driver.  Note that all iocb context buffers are from the
-        * driver's dma pool and have length LPFC_BPL_SIZE.
-        */
-       pci_dma_sync_single_for_device(phba->pcidev, pcmd->phys,
-               LPFC_BPL_SIZE, PCI_DMA_FROMDEVICE);
-
        cmd = *lp++;
        payload_len = be32_to_cpu(cmd) & 0xffff;        /* payload length */
        payload_len -= sizeof (uint32_t);       /* take off word 0 */
@@ -2399,16 +2508,31 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba,
                        phba->brd_no,
                        phba->fc_flag, payload_len, *lp, phba->fc_rscn_id_cnt);
 
-       /* if we are already processing an RSCN, save the received
+       /* If we are about to begin discovery, just ACC the RSCN.
+        * Discovery processing will satisfy it.
+        */
+       if (phba->hba_state <= LPFC_NS_QRY) {
+               lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
+                                                               newnode);
+               return 0;
+       }
+
+       /* If we are already processing an RSCN, save the received
         * RSCN payload buffer, cmdiocb->context2 to process later.
-        * If we zero, cmdiocb->context2, the calling routine will
-        * not try to free it.
         */
-       if (phba->fc_flag & FC_RSCN_MODE) {
+       if (phba->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
                if ((phba->fc_rscn_id_cnt < FC_MAX_HOLD_RSCN) &&
                    !(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);
                        phba->fc_rscn_id_list[phba->fc_rscn_id_cnt++] = pcmd;
+
+                       /* If we zero, cmdiocb->context2, the calling
+                        * routine will not try to free it.
+                        */
                        cmdiocb->context2 = NULL;
+
                        /* Deferred RSCN */
                        lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
                                        "%d:0235 Deferred RSCN "
@@ -2416,7 +2540,9 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba,
                                        phba->brd_no, phba->fc_rscn_id_cnt,
                                        phba->fc_flag, phba->hba_state);
                } else {
+                       spin_lock_irq(phba->host->host_lock);
                        phba->fc_flag |= FC_RSCN_DISCOVERY;
+                       spin_unlock_irq(phba->host->host_lock);
                        /* ReDiscovery RSCN */
                        lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
                                        "%d:0234 ReDiscovery RSCN "
@@ -2430,7 +2556,7 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba,
 
                /* send RECOVERY event for ALL nodes that match RSCN payload */
                lpfc_rscn_recovery_check(phba);
-               return (0);
+               return 0;
        }
 
        phba->fc_flag |= FC_RSCN_MODE;
@@ -2449,7 +2575,7 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba,
        /* send RECOVERY event for ALL nodes that match RSCN payload */
        lpfc_rscn_recovery_check(phba);
 
-       return (lpfc_els_handle_rscn(phba));
+       return lpfc_els_handle_rscn(phba);
 }
 
 int
@@ -2457,9 +2583,6 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
 {
        struct lpfc_nodelist *ndlp;
 
-       lpfc_put_event(phba, HBA_EVENT_RSCN, phba->fc_myDID,
-                         (void *)(unsigned long)(phba->fc_myDID), 0, 0);
-
        /* Start timer for RSCN processing */
        lpfc_set_disctmo(phba);
 
@@ -2474,40 +2597,41 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
 
        /* To process RSCN, first compare RSCN data with NameServer */
        phba->fc_ns_retry = 0;
-       if ((ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
-                                     NameServer_DID))) {
+       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED, NameServer_DID);
+       if (ndlp) {
                /* Good ndlp, issue CT Request to NameServer */
                if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) == 0) {
                        /* Wait for NameServer query cmpl before we can
                           continue */
-                       return (1);
+                       return 1;
                }
        } else {
                /* If login to NameServer does not exist, issue one */
                /* Good status, issue PLOGI to NameServer */
-               if ((ndlp =
-                    lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID))) {
+               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+               if (ndlp) {
                        /* Wait for NameServer login cmpl before we can
                           continue */
-                       return (1);
+                       return 1;
                }
-               if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC))
-                   == 0) {
+               ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+               if (!ndlp) {
                        lpfc_els_flush_rscn(phba);
-                       return (0);
+                       return 0;
                } else {
                        lpfc_nlp_init(phba, ndlp, NameServer_DID);
                        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);
+                       return 1;
                }
        }
 
        lpfc_els_flush_rscn(phba);
-       return (0);
+       return 0;
 }
 
 static int
@@ -2522,14 +2646,7 @@ lpfc_els_rcv_flogi(struct lpfc_hba * phba,
        LPFC_MBOXQ_t *mbox;
        struct ls_rjt stat;
        uint32_t cmd, did;
-
-
-       /* The response iocb was populated by the HBA.  Flush it to main store
-        * for the driver.  Note that all iocb context buffers are from the
-        * driver's dma pool and have length LPFC_BPL_SIZE.
-        */
-       pci_dma_sync_single_for_device(phba->pcidev, pcmd->phys,
-               LPFC_BPL_SIZE, PCI_DMA_FROMDEVICE);
+       int rc;
 
        cmd = *lp++;
        sp = (struct serv_parm *) lp;
@@ -2548,7 +2665,7 @@ lpfc_els_rcv_flogi(struct lpfc_hba * phba,
                                "%d:0113 An FLOGI ELS command x%x was received "
                                "from DID x%x in Loop Mode\n",
                                phba->brd_no, cmd, did);
-               return (1);
+               return 1;
        }
 
        did = Fabric_DID;
@@ -2557,31 +2674,31 @@ lpfc_els_rcv_flogi(struct lpfc_hba * phba,
                /* For a FLOGI we accept, then if our portname is greater
                 * then the remote portname we initiate Nport login.
                 */
-               int rc;
 
                rc = memcmp(&phba->fc_portname, &sp->portName,
                            sizeof (struct lpfc_name));
 
                if (!rc) {
                        if ((mbox = mempool_alloc(phba->mbox_mem_pool,
-                                                 GFP_ATOMIC)) == 0) {
-                               return (1);
+                                                 GFP_KERNEL)) == 0) {
+                               return 1;
                        }
                        lpfc_linkdown(phba);
                        lpfc_init_link(phba, mbox,
                                       phba->cfg_topology,
                                       phba->cfg_link_speed);
                        mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
-                       if (lpfc_sli_issue_mbox
-                           (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB))
-                           == MBX_NOT_FINISHED) {
+                       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+                       rc = lpfc_sli_issue_mbox
+                               (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+                       if (rc == MBX_NOT_FINISHED) {
                                mempool_free( mbox, phba->mbox_mem_pool);
                        }
-                       return (1);
-               }
-
-               else if (rc > 0) {      /* greater than */
+                       return 1;
+               } else if (rc > 0) {    /* greater than */
+                       spin_lock_irq(phba->host->host_lock);
                        phba->fc_flag |= FC_PT2PT_PLOGI;
+                       spin_unlock_irq(phba->host->host_lock);
                }
                phba->fc_flag |= FC_PT2PT;
                phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
@@ -2592,13 +2709,13 @@ lpfc_els_rcv_flogi(struct lpfc_hba * phba,
                stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
                stat.un.b.vendorUnique = 0;
                lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
-               return (1);
+               return 1;
        }
 
        /* Send back ACC */
        lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, newnode);
 
-       return (0);
+       return 0;
 }
 
 static int
@@ -2617,13 +2734,6 @@ lpfc_els_rcv_rnid(struct lpfc_hba * phba,
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
        lp = (uint32_t *) pcmd->virt;
 
-       /* The response iocb was populated by the HBA.  Flush it to main store
-        * for the driver.  Note that all iocb context buffers are from the
-        * driver's dma pool and have length LPFC_BPL_SIZE.
-        */
-       pci_dma_sync_single_for_device(phba->pcidev, pcmd->phys,
-               LPFC_BPL_SIZE, PCI_DMA_FROMDEVICE);
-
        cmd = *lp++;
        rn = (RNID *) lp;
 
@@ -2643,47 +2753,246 @@ lpfc_els_rcv_rnid(struct lpfc_hba * phba,
                stat.un.b.vendorUnique = 0;
                lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
        }
-       return (0);
+       return 0;
 }
 
 static int
-lpfc_els_rcv_rrq(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+lpfc_els_rcv_lirr(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+                struct lpfc_nodelist * ndlp)
+{
+       struct ls_rjt stat;
+
+       /* For now, unconditionally reject this command */
+       stat.un.b.lsRjtRsvd0 = 0;
+       stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+       stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
+       stat.un.b.vendorUnique = 0;
+       lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+       return 0;
+}
+
+static void
+lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+       struct lpfc_sli *psli;
+       struct lpfc_sli_ring *pring;
+       MAILBOX_t *mb;
+       IOCB_t *icmd;
+       RPS_RSP *rps_rsp;
+       uint8_t *pcmd;
+       struct lpfc_iocbq *elsiocb;
+       struct lpfc_nodelist *ndlp;
+       uint16_t xri, status;
+       uint32_t cmdsize;
+
+       psli = &phba->sli;
+       pring = &psli->ring[LPFC_ELS_RING];
+       mb = &pmb->mb;
+
+       ndlp = (struct lpfc_nodelist *) pmb->context2;
+       xri = (uint16_t) ((unsigned long)(pmb->context1));
+       pmb->context1 = 0;
+       pmb->context2 = 0;
+
+       if (mb->mbxStatus) {
+               mempool_free( pmb, phba->mbox_mem_pool);
+               return;
+       }
+
+       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,
+                                               ndlp->nlp_DID, ELS_CMD_ACC);
+       if (!elsiocb)
+               return;
+
+       icmd = &elsiocb->iocb;
+       icmd->ulpContext = xri;
+
+       pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+       *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+       pcmd += sizeof (uint32_t); /* Skip past command */
+       rps_rsp = (RPS_RSP *)pcmd;
+
+       if (phba->fc_topology != TOPOLOGY_LOOP)
+               status = 0x10;
+       else
+               status = 0x8;
+       if (phba->fc_flag & FC_FABRIC)
+               status |= 0x4;
+
+       rps_rsp->rsvd1 = 0;
+       rps_rsp->portStatus = be16_to_cpu(status);
+       rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt);
+       rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt);
+       rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt);
+       rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
+       rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
+       rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
+
+       /* 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 "
+                       "Data: x%x x%x x%x x%x x%x\n",
+                       phba->brd_no,
+                       elsiocb->iocb.ulpIoTag,
+                       elsiocb->iocb.ulpContext, ndlp->nlp_DID,
+                       ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+
+       elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+       phba->fc_stat.elsXmitACC++;
+       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+               lpfc_els_free_iocb(phba, elsiocb);
+       }
+       return;
+}
+
+static int
+lpfc_els_rcv_rps(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                 struct lpfc_nodelist * ndlp)
 {
-       struct lpfc_dmabuf *pcmd;
        uint32_t *lp;
+       uint8_t flag;
+       LPFC_MBOXQ_t *mbox;
+       struct lpfc_dmabuf *pcmd;
+       RPS *rps;
+       struct ls_rjt stat;
+
+       if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
+           (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
+               stat.un.b.lsRjtRsvd0 = 0;
+               stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+               stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
+               stat.un.b.vendorUnique = 0;
+               lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+       }
+
+       pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+       lp = (uint32_t *) pcmd->virt;
+       flag = (be32_to_cpu(*lp++) & 0xf);
+       rps = (RPS *) lp;
+
+       if ((flag == 0) ||
+           ((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) ||
+           ((flag == 2) && (memcmp(&rps->un.portName, &phba->fc_portname,
+                          sizeof (struct lpfc_name)) == 0))) {
+               if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC))) {
+                       lpfc_read_lnk_stat(phba, mbox);
+                       mbox->context1 =
+                           (void *)((unsigned long)cmdiocb->iocb.ulpContext);
+                       mbox->context2 = ndlp;
+                       mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
+                       if (lpfc_sli_issue_mbox (phba, mbox,
+                           (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) {
+                               /* Mbox completion will send ELS Response */
+                               return 0;
+                       }
+                       mempool_free(mbox, phba->mbox_mem_pool);
+               }
+       }
+       stat.un.b.lsRjtRsvd0 = 0;
+       stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+       stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
+       stat.un.b.vendorUnique = 0;
+       lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+       return 0;
+}
+
+static int
+lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
+                struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+{
        IOCB_t *icmd;
+       IOCB_t *oldcmd;
+       RPL_RSP rpl_rsp;
+       struct lpfc_iocbq *elsiocb;
        struct lpfc_sli_ring *pring;
        struct lpfc_sli *psli;
-       RRQ *rrq;
-       uint32_t cmd, did;
+       uint8_t *pcmd;
 
        psli = &phba->sli;
-       pring = &psli->ring[LPFC_FCP_RING];
-       icmd = &cmdiocb->iocb;
-       did = icmd->un.elsreq64.remoteID;
+       pring = &psli->ring[LPFC_ELS_RING];     /* ELS ring */
+
+       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 */
+
+       pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+       *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+       pcmd += sizeof (uint16_t);
+       *((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize);
+       pcmd += sizeof(uint16_t);
+
+       /* Setup the RPL ACC payload */
+       rpl_rsp.listLen = be32_to_cpu(1);
+       rpl_rsp.index = 0;
+       rpl_rsp.port_num_blk.portNum = 0;
+       rpl_rsp.port_num_blk.portID = be32_to_cpu(phba->fc_myDID);
+       memcpy(&rpl_rsp.port_num_blk.portName, &phba->fc_portname,
+           sizeof(struct lpfc_name));
+
+       memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t));
+
+
+       /* 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 "
+                       "Data: x%x x%x x%x x%x x%x\n",
+                       phba->brd_no,
+                       elsiocb->iocb.ulpIoTag,
+                       elsiocb->iocb.ulpContext, ndlp->nlp_DID,
+                       ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+
+       elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+
+       phba->fc_stat.elsXmitACC++;
+       if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+               lpfc_els_free_iocb(phba, elsiocb);
+               return 1;
+       }
+       return 0;
+}
+
+static int
+lpfc_els_rcv_rpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+                struct lpfc_nodelist * ndlp)
+{
+       struct lpfc_dmabuf *pcmd;
+       uint32_t *lp;
+       uint32_t maxsize;
+       uint16_t cmdsize;
+       RPL *rpl;
+       struct ls_rjt stat;
+
+       if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
+           (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
+               stat.un.b.lsRjtRsvd0 = 0;
+               stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+               stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
+               stat.un.b.vendorUnique = 0;
+               lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+       }
+
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
        lp = (uint32_t *) pcmd->virt;
+       rpl = (RPL *) (lp + 1);
 
-       /* The response iocb was populated by the HBA.  Flush it to main store
-        * for the driver.  Note that all iocb context buffers are from the
-        * driver's dma pool and have length LPFC_BPL_SIZE.
-        */
-       pci_dma_sync_single_for_cpu(phba->pcidev, pcmd->phys,
-               LPFC_BPL_SIZE, PCI_DMA_FROMDEVICE);
+       maxsize = be32_to_cpu(rpl->maxsize);
 
-       cmd = *lp++;
-       rrq = (RRQ *) lp;
-
-       /* RRQ received */
-       /* Get oxid / rxid from payload and abort it */
-       if ((rrq->SID == be32_to_cpu(phba->fc_myDID))) {
-               lpfc_sli_abort_iocb_ctx(phba, pring, rrq->Oxid);
+       /* We support only one port */
+       if ((rpl->index == 0) &&
+           ((maxsize == 0) ||
+            ((maxsize * sizeof(uint32_t)) >= sizeof(RPL_RSP)))) {
+               cmdsize = sizeof(uint32_t) + sizeof(RPL_RSP);
        } else {
-               lpfc_sli_abort_iocb_ctx(phba, pring, rrq->Rxid);
+               cmdsize = sizeof(uint32_t) + maxsize * sizeof(uint32_t);
        }
-       /* ACCEPT the rrq request */
-       lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+       lpfc_els_rsp_rpl_acc(phba, cmdsize, cmdiocb, ndlp);
 
        return 0;
 }
@@ -2703,13 +3012,6 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
        lp = (uint32_t *) pcmd->virt;
 
-       /* The response iocb was populated by the HBA.  Flush it to main store
-        * for the driver.  Note that all iocb context buffers are from the
-        * driver's dma pool and have length LPFC_BPL_SIZE.
-        */
-       pci_dma_sync_single_for_cpu(phba->pcidev, pcmd->phys,
-               LPFC_BPL_SIZE, PCI_DMA_FROMDEVICE);
-
        cmd = *lp++;
        fp = (FARP *) lp;
 
@@ -2722,7 +3024,7 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
 
        /* We will only support match on WWPN or WWNN */
        if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) {
-               return (0);
+               return 0;
        }
 
        cnt = 0;
@@ -2741,13 +3043,14 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
        }
 
        if (cnt) {
-               if((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ||
+               if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ||
                   (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) {
                        /* Log back into the node before sending the FARP. */
                        if (fp->Rflags & FARP_REQUEST_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, 0);
+                               lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
                        }
 
                        /* Send a FARP response to that node */
@@ -2756,7 +3059,7 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
                        }
                }
        }
-       return (0);
+       return 0;
 }
 
 static int
@@ -2773,13 +3076,6 @@ lpfc_els_rcv_farpr(struct lpfc_hba * phba,
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
        lp = (uint32_t *) pcmd->virt;
 
-       /* The response iocb was populated by the HBA.  Flush it to main store
-        * for the driver.  Note that all iocb context buffers are from the
-        * driver's dma pool and have length LPFC_BPL_SIZE.
-        */
-       pci_dma_sync_single_for_cpu(phba->pcidev, pcmd->phys,
-               LPFC_BPL_SIZE, PCI_DMA_FROMDEVICE);
-
        cmd = *lp++;
        /* FARP-RSP received from DID <did> */
        lpfc_printf_log(phba,
@@ -2796,61 +3092,113 @@ lpfc_els_rcv_farpr(struct lpfc_hba * phba,
 
 static int
 lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
-                struct lpfc_nodelist * ndlp)
+                struct lpfc_nodelist * fan_ndlp)
 {
        struct lpfc_dmabuf *pcmd;
        uint32_t *lp;
        IOCB_t *icmd;
-       FAN *fp;
        uint32_t cmd, did;
+       FAN *fp;
+       struct lpfc_nodelist *ndlp, *next_ndlp;
+
+       /* FAN received */
+       lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:265 FAN received\n",
+                                                               phba->brd_no);
 
        icmd = &cmdiocb->iocb;
        did = icmd->un.elsreq64.remoteID;
-       pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
-       lp = (uint32_t *) pcmd->virt;
-
-       /* The response iocb was populated by the HBA.  Flush it to main store
-        * for the driver.  Note that all iocb context buffers are from the
-        * driver's dma pool and have length LPFC_BPL_SIZE.
-        */
-       pci_dma_sync_single_for_cpu(phba->pcidev, pcmd->phys,
-               LPFC_BPL_SIZE, PCI_DMA_FROMDEVICE);
+       pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
+       lp = (uint32_t *)pcmd->virt;
 
        cmd = *lp++;
-       fp = (FAN *) lp;
+       fp = (FAN *)lp;
 
-       /* FAN received */
-
-       /* ACCEPT the FAN request */
-       lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+       /* FAN received; Fan does not have a reply sequence */
 
        if (phba->hba_state == LPFC_LOCAL_CFG_LINK) {
-               /* The discovery state machine needs to take a different
-                * action if this node has switched fabrics
-                */
-               if ((memcmp(&fp->FportName, &phba->fc_fabparam.portName,
-                           sizeof (struct lpfc_name)) != 0)
-                   ||
-                   (memcmp(&fp->FnodeName, &phba->fc_fabparam.nodeName,
-                           sizeof (struct lpfc_name)) != 0)) {
-                       /* This node has switched fabrics.  An FLOGI is required
-                        * after the timeout
+               if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName,
+                       sizeof(struct lpfc_name)) != 0) ||
+                   (memcmp(&phba->fc_fabparam.portName, &fp->FportName,
+                       sizeof(struct lpfc_name)) != 0)) {
+                       /*
+                        * This node has switched fabrics.  FLOGI is required
+                        * Clean up the old rpi's
                         */
-                       return (0);
+
+                       list_for_each_entry_safe(ndlp, next_ndlp,
+                               &phba->fc_npr_list, nlp_listp) {
+
+                               if (ndlp->nlp_type & NLP_FABRIC) {
+                                       /*
+                                        * Clean up old Fabric, Nameserver and
+                                        * other NLP_FABRIC logins
+                                        */
+                                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                               } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
+                                       /* Fail outstanding I/O now since this
+                                        * device is marked for PLOGI
+                                        */
+                                       lpfc_unreg_rpi(phba, ndlp);
+                               }
+                       }
+
+                       phba->hba_state = LPFC_FLOGI;
+                       lpfc_set_disctmo(phba);
+                       lpfc_initial_flogi(phba);
+                       return 0;
                }
+               /* Discovery not needed,
+                * move the nodes to their original state.
+                */
+               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
+                       nlp_listp) {
 
-               /* Start discovery */
+                       switch (ndlp->nlp_prev_state) {
+                       case NLP_STE_UNMAPPED_NODE:
+                               ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
+                               ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
+                               lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+                               break;
+
+                       case NLP_STE_MAPPED_NODE:
+                               ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
+                               ndlp->nlp_state = NLP_STE_MAPPED_NODE;
+                               lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+                               break;
+
+                       default:
+                               break;
+                       }
+               }
+
+               /* Start discovery - this should just do CLEAR_LA */
                lpfc_disc_start(phba);
        }
-
-       return (0);
+       return 0;
 }
 
 void
-lpfc_els_timeout_handler(unsigned long ptr)
+lpfc_els_timeout(unsigned long ptr)
 {
        struct lpfc_hba *phba;
-       struct lpfc_sli *psli;
+       unsigned long iflag;
+
+       phba = (struct lpfc_hba *)ptr;
+       if (phba == 0)
+               return;
+       spin_lock_irqsave(phba->host->host_lock, iflag);
+       if (!(phba->work_hba_events & WORKER_ELS_TMO)) {
+               phba->work_hba_events |= WORKER_ELS_TMO;
+               if (phba->work_wait)
+                       wake_up(phba->work_wait);
+       }
+       spin_unlock_irqrestore(phba->host->host_lock, iflag);
+       return;
+}
+
+void
+lpfc_els_timeout_handler(struct lpfc_hba *phba)
+{
        struct lpfc_sli_ring *pring;
        struct lpfc_iocbq *tmp_iocb, *piocb;
        IOCB_t *cmd = NULL;
@@ -2860,16 +3208,18 @@ lpfc_els_timeout_handler(unsigned long ptr)
        uint32_t els_command;
        uint32_t timeout;
        uint32_t remote_ID;
-       unsigned long iflag;
 
-       phba = (struct lpfc_hba *)ptr;
-       if(phba == 0)
+       if (phba == 0)
                return;
-       spin_lock_irqsave(phba->host->host_lock, iflag);
+       spin_lock_irq(phba->host->host_lock);
+       /* If the timer is already canceled do nothing */
+       if (!(phba->work_hba_events & WORKER_ELS_TMO)) {
+               spin_unlock_irq(phba->host->host_lock);
+               return;
+       }
        timeout = (uint32_t)(phba->fc_ratov << 1);
 
-       psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];
+       pring = &phba->sli.ring[LPFC_ELS_RING];
        dlp = &pring->txcmplq;
 
        list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
@@ -2901,8 +3251,9 @@ lpfc_els_timeout_handler(unsigned long ptr)
 
                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,
@@ -2925,32 +3276,31 @@ lpfc_els_timeout_handler(unsigned long ptr)
                if (piocb->iocb_cmpl) {
                        cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
                        cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+                       spin_unlock_irq(phba->host->host_lock);
                        (piocb->iocb_cmpl) (phba, piocb, piocb);
-               } else {
-                       mempool_free(piocb, phba->iocb_mem_pool);
-               }
+                       spin_lock_irq(phba->host->host_lock);
+               } else
+                       lpfc_sli_release_iocbq(phba, piocb);
        }
-
-       phba->els_tmofunc.expires = jiffies + HZ * timeout;
-       add_timer(&phba->els_tmofunc);
-       spin_unlock_irqrestore(phba->host->host_lock, iflag);
+       if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) {
+               phba->els_tmofunc.expires = jiffies + HZ * timeout;
+               add_timer(&phba->els_tmofunc);
+       }
+       spin_unlock_irq(phba->host->host_lock);
 }
 
 void
 lpfc_els_flush_cmd(struct lpfc_hba * phba)
 {
-       struct lpfc_sli *psli;
        struct lpfc_sli_ring *pring;
        struct lpfc_iocbq *tmp_iocb, *piocb;
        IOCB_t *cmd = NULL;
        struct lpfc_dmabuf *pcmd;
        uint32_t *elscmd;
        uint32_t els_command;
-       uint32_t remote_ID;
-
-       psli = &phba->sli;
-       pring = &psli->ring[LPFC_ELS_RING];
 
+       pring = &phba->sli.ring[LPFC_ELS_RING];
+       spin_lock_irq(phba->host->host_lock);
        list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
                cmd = &piocb->iocb;
 
@@ -2970,18 +3320,6 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
                elscmd = (uint32_t *) (pcmd->virt);
                els_command = *elscmd;
 
-               if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
-                       struct lpfc_nodelist *ndlp;
-
-                       ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext);
-                       remote_ID = ndlp->nlp_DID;
-                       if (phba->hba_state == LPFC_HBA_READY) {
-                               continue;
-                       }
-               } else {
-                       remote_ID = cmd->un.elsreq64.remoteID;
-               }
-
                list_del(&piocb->list);
                pring->txcmplq_cnt--;
 
@@ -2989,10 +3327,11 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
                cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
 
                if (piocb->iocb_cmpl) {
+                       spin_unlock_irq(phba->host->host_lock);
                        (piocb->iocb_cmpl) (phba, piocb, piocb);
-               } else {
-                       mempool_free( piocb, phba->iocb_mem_pool);
-               }
+                       spin_lock_irq(phba->host->host_lock);
+               } else
+                       lpfc_sli_release_iocbq(phba, piocb);
        }
 
        list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
@@ -3005,18 +3344,6 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
                elscmd = (uint32_t *) (pcmd->virt);
                els_command = *elscmd;
 
-               if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
-                       struct lpfc_nodelist *ndlp;
-
-                       ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext);
-                       remote_ID = ndlp->nlp_DID;
-                       if (phba->hba_state == LPFC_HBA_READY) {
-                               continue;
-                       }
-               } else {
-                       remote_ID = cmd->un.elsreq64.remoteID;
-               }
-
                list_del(&piocb->list);
                pring->txcmplq_cnt--;
 
@@ -3024,11 +3351,13 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
                cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
 
                if (piocb->iocb_cmpl) {
+                       spin_unlock_irq(phba->host->host_lock);
                        (piocb->iocb_cmpl) (phba, piocb, piocb);
-               } else {
-                       mempool_free( piocb, phba->iocb_mem_pool);
-               }
+                       spin_lock_irq(phba->host->host_lock);
+               } else
+                       lpfc_sli_release_iocbq(phba, piocb);
        }
+       spin_unlock_irq(phba->host->host_lock);
        return;
 }
 
@@ -3051,6 +3380,20 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
        psli = &phba->sli;
        icmd = &elsiocb->iocb;
 
+       if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+               ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
+               /* Not enough posted buffers; Try posting more buffers */
+               phba->fc_stat.NoRcvBuf++;
+               lpfc_post_buffer(phba, pring, 0, 1);
+               return;
+       }
+
+       /* If there are no BDEs associated with this IOCB,
+        * there is nothing to do.
+        */
+       if (icmd->ulpBdeCount == 0)
+               return;
+
        /* type of ELS cmd is first 32bit word in packet */
        mp = lpfc_sli_ringpostbuf_get(phba, pring, getPaddr(icmd->un.
                                                            cont64[0].
@@ -3083,10 +3426,11 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
        }
 
        did = icmd->un.rcvels.remoteID;
-       if ((ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did)) == 0) {
+       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+       if (!ndlp) {
                /* Cannot find existing Fabric ndlp, so allocate a new one */
-               if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC))
-                   == 0) {
+               ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+               if (!ndlp) {
                        lpfc_mbuf_free(phba, mp->virt, mp->phys);
                        kfree(mp);
                        drop_cmd = 1;
@@ -3115,8 +3459,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
        switch (cmd) {
        case ELS_CMD_PLOGI:
                phba->fc_stat.elsRcvPLOGI++;
-               if(phba->hba_state < LPFC_DISC_AUTH) {
-                       rjt_err = LSEXP_NOTHING_MORE;
+               if (phba->hba_state < LPFC_DISC_AUTH) {
+                       rjt_err = 1;
                        break;
                }
                lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PLOGI);
@@ -3130,16 +3474,16 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                break;
        case ELS_CMD_LOGO:
                phba->fc_stat.elsRcvLOGO++;
-               if(phba->hba_state < LPFC_DISC_AUTH) {
-                       rjt_err = LSEXP_NOTHING_MORE;
+               if (phba->hba_state < LPFC_DISC_AUTH) {
+                       rjt_err = 1;
                        break;
                }
                lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
                break;
        case ELS_CMD_PRLO:
                phba->fc_stat.elsRcvPRLO++;
-               if(phba->hba_state < LPFC_DISC_AUTH) {
-                       rjt_err = LSEXP_NOTHING_MORE;
+               if (phba->hba_state < LPFC_DISC_AUTH) {
+                       rjt_err = 1;
                        break;
                }
                lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
@@ -3153,16 +3497,16 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                break;
        case ELS_CMD_ADISC:
                phba->fc_stat.elsRcvADISC++;
-               if(phba->hba_state < LPFC_DISC_AUTH) {
-                       rjt_err = LSEXP_NOTHING_MORE;
+               if (phba->hba_state < LPFC_DISC_AUTH) {
+                       rjt_err = 1;
                        break;
                }
                lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_ADISC);
                break;
        case ELS_CMD_PDISC:
                phba->fc_stat.elsRcvPDISC++;
-               if(phba->hba_state < LPFC_DISC_AUTH) {
-                       rjt_err = LSEXP_NOTHING_MORE;
+               if (phba->hba_state < LPFC_DISC_AUTH) {
+                       rjt_err = 1;
                        break;
                }
                lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PDISC);
@@ -3179,25 +3523,45 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                phba->fc_stat.elsRcvFAN++;
                lpfc_els_rcv_fan(phba, elsiocb, ndlp);
                break;
-       case ELS_CMD_RRQ:
-               phba->fc_stat.elsRcvRRQ++;
-               lpfc_els_rcv_rrq(phba, elsiocb, ndlp);
-               break;
        case ELS_CMD_PRLI:
                phba->fc_stat.elsRcvPRLI++;
-               if(phba->hba_state < LPFC_DISC_AUTH) {
-                       rjt_err = LSEXP_NOTHING_MORE;
+               if (phba->hba_state < LPFC_DISC_AUTH) {
+                       rjt_err = 1;
                        break;
                }
                lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
                break;
+       case ELS_CMD_LIRR:
+               phba->fc_stat.elsRcvLIRR++;
+               lpfc_els_rcv_lirr(phba, elsiocb, ndlp);
+               if (newnode) {
+                       mempool_free( ndlp, phba->nlp_mem_pool);
+               }
+               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);
+               }
+               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);
+               }
+               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);
+               }
                break;
        default:
                /* Unsupported ELS command, reject */
-               rjt_err = LSEXP_NOTHING_MORE;
+               rjt_err = 1;
 
                /* Unknown ELS command <elsCmd> received from NPORT <did> */
                lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
@@ -3213,7 +3577,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
        if (rjt_err) {
                stat.un.b.lsRjtRsvd0 = 0;
                stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
-               stat.un.b.lsRjtRsnCodeExp = rjt_err;
+               stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
                stat.un.b.vendorUnique = 0;
                lpfc_els_rsp_reject(phba, stat.un.lsRjtError, elsiocb, ndlp);
        }
@@ -3227,8 +3591,9 @@ dropit:
        if (drop_cmd == 1) {
                lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
                                "%d:0111 Dropping received ELS cmd "
-                               "Data: x%x x%x\n", phba->brd_no,
-                               icmd->ulpStatus, icmd->un.ulpWord[4]);
+                               "Data: x%x x%x x%x\n", phba->brd_no,
+                               icmd->ulpStatus, icmd->un.ulpWord[4],
+                               icmd->ulpTimeout);
                phba->fc_stat.elsRcvDrop++;
        }
        return;