Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[pandora-kernel.git] / drivers / scsi / lpfc / lpfc_ct.c
index e8ed5d7..92441ce 100644 (file)
@@ -19,7 +19,7 @@
  *******************************************************************/
 
 /*
- * Fibre Channel SCSI LAN Device Driver CT support
+ * Fibre Channel SCSI LAN Device Driver CT support: FC Generic Services FC-GS
  */
 
 #include <linux/blkdev.h>
@@ -40,6 +40,8 @@
 #include "lpfc_logmsg.h"
 #include "lpfc_crtn.h"
 #include "lpfc_version.h"
+#include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
 
 #define HBA_PORTSPEED_UNKNOWN               0  /* Unknown - transceiver
                                                 * incapable of reporting */
 
 static char *lpfc_release_version = LPFC_DRIVER_VERSION;
 
-/*
- * lpfc_ct_unsol_event
- */
 static void
-lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
-                    struct lpfc_dmabuf *mp, uint32_t size)
+lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+                         struct lpfc_dmabuf *mp, uint32_t size)
 {
        if (!mp) {
-               printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, "
-                      "piocbq = %p, status = x%x, mp = %p, size = %d\n",
-                      __FUNCTION__, __LINE__,
-                      piocbq, piocbq->iocb.ulpStatus, mp, size);
+               lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+                               "0146 Ignoring unsolicted CT No HBQ "
+                               "status = x%x\n",
+                               piocbq->iocb.ulpStatus);
        }
-
-       printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, "
-              "buffer = %p, size = %d, status = x%x\n",
-              __FUNCTION__, __LINE__,
-              piocbq, mp, size,
-              piocbq->iocb.ulpStatus);
+       lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+                       "0145 Ignoring unsolicted CT HBQ Size:%d "
+                       "status = x%x\n",
+                       size, piocbq->iocb.ulpStatus);
 }
 
 static void
-lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
-                         struct hbq_dmabuf *sp, uint32_t size)
+lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+                    struct lpfc_dmabuf *mp, uint32_t size)
 {
-       struct lpfc_dmabuf *mp = NULL;
-
-       mp = sp ? &sp->dbuf : NULL;
-       if (!mp) {
-               printk(KERN_ERR "%s (%d): Unsolited CT, no "
-                      "HBQ buffer, piocbq = %p, status = x%x\n",
-                      __FUNCTION__, __LINE__,
-                      piocbq, piocbq->iocb.ulpStatus);
-       } else {
-               lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
-               printk(KERN_ERR "%s (%d): Ignoring unsolicted CT "
-                      "piocbq = %p, buffer = %p, size = %d, "
-                      "status = x%x\n",
-                      __FUNCTION__, __LINE__,
-                      piocbq, mp, size, piocbq->iocb.ulpStatus);
-       }
+       lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size);
 }
 
 void
 lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                    struct lpfc_iocbq *piocbq)
 {
+
        struct lpfc_dmabuf *mp = NULL;
-       struct hbq_dmabuf  *sp = NULL;
        IOCB_t *icmd = &piocbq->iocb;
        int i;
        struct lpfc_iocbq *iocbq;
        dma_addr_t paddr;
        uint32_t size;
+       struct list_head head;
+       struct lpfc_dmabuf *bdeBuf;
 
-       if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-           ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
+       if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
+               lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
+       } else 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++;
-               if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
-                       lpfc_sli_hbqbuf_fill_hbq(phba);
-               else
-                       lpfc_post_buffer(phba, pring, 0, 1);
+               if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
+                       lpfc_post_buffer(phba, pring, 2, 1);
                return;
        }
 
@@ -128,47 +112,34 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                return;
 
        if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
-               list_for_each_entry(iocbq, &piocbq->list, list) {
+               INIT_LIST_HEAD(&head);
+               list_add_tail(&head, &piocbq->list);
+               list_for_each_entry(iocbq, &head, list) {
                        icmd = &iocbq->iocb;
-                       if (icmd->ulpBdeCount == 0) {
-                               printk(KERN_ERR "%s (%d): Unsolited CT, no "
-                                      "BDE, iocbq = %p, status = x%x\n",
-                                      __FUNCTION__, __LINE__,
-                                      iocbq, iocbq->iocb.ulpStatus);
+                       if (icmd->ulpBdeCount == 0)
                                continue;
-                       }
-
+                       bdeBuf = iocbq->context2;
+                       iocbq->context2 = NULL;
                        size  = icmd->un.cont64[0].tus.f.bdeSize;
-                       sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[3]);
-                       if (sp)
-                               phba->hbq_buff_count--;
-                       lpfc_ct_ignore_hbq_buffer(phba, iocbq, sp, size);
-                       lpfc_sli_free_hbq(phba, sp);
+                       lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
+                       lpfc_in_buf_free(phba, bdeBuf);
                        if (icmd->ulpBdeCount == 2) {
-                               sp = lpfc_sli_hbqbuf_find(phba,
-                                                         icmd->un.ulpWord[15]);
-                               if (sp)
-                                       phba->hbq_buff_count--;
-                               lpfc_ct_ignore_hbq_buffer(phba, iocbq, sp,
-                                                         size);
-                               lpfc_sli_free_hbq(phba, sp);
+                               bdeBuf = iocbq->context3;
+                               iocbq->context3 = NULL;
+                               size  = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize;
+                               lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf,
+                                                    size);
+                               lpfc_in_buf_free(phba, bdeBuf);
                        }
-
                }
-               lpfc_sli_hbqbuf_fill_hbq(phba);
+               list_del(&head);
        } else {
                struct lpfc_iocbq  *next;
 
                list_for_each_entry_safe(iocbq, next, &piocbq->list, list) {
                        icmd = &iocbq->iocb;
-                       if (icmd->ulpBdeCount == 0) {
-                               printk(KERN_ERR "%s (%d): Unsolited CT, no "
-                                      "BDE, iocbq = %p, status = x%x\n",
-                                      __FUNCTION__, __LINE__,
-                                      iocbq, iocbq->iocb.ulpStatus);
-                               continue;
-                       }
-
+                       if (icmd->ulpBdeCount == 0)
+                               lpfc_ct_unsol_buffer(phba, piocbq, NULL, 0);
                        for (i = 0; i < icmd->ulpBdeCount; i++) {
                                paddr = getPaddr(icmd->un.cont64[i].addrHigh,
                                                 icmd->un.cont64[i].addrLow);
@@ -176,11 +147,11 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                                                              paddr);
                                size = icmd->un.cont64[i].tus.f.bdeSize;
                                lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
-                               lpfc_mbuf_free(phba, mp->virt, mp->phys);
-                               kfree(mp);
+                               lpfc_in_buf_free(phba, mp);
                        }
                        list_del(&iocbq->list);
                        lpfc_sli_release_iocbq(phba, iocbq);
+                       lpfc_post_buffer(phba, pring, i, 1);
                }
        }
 }
@@ -208,7 +179,7 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
        struct lpfc_dmabuf *mp;
        int cnt, i = 0;
 
-       /* We get chucks of FCELSSIZE */
+       /* We get chunks of FCELSSIZE */
        cnt = size > FCELSSIZE ? FCELSSIZE: size;
 
        while (size) {
@@ -222,7 +193,8 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
 
                INIT_LIST_HEAD(&mp->list);
 
-               if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT))
+               if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT) ||
+                   cmdcode == be16_to_cpu(SLI_CTNS_GFF_ID))
                        mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
                else
                        mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys));
@@ -242,8 +214,8 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
 
                bpl->tus.f.bdeFlags = BUFF_USE_RCV;
                /* build buffer ptr list for IOCB */
-               bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) );
-               bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) );
+               bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
+               bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
                bpl->tus.f.bdeSize = (uint16_t) cnt;
                bpl->tus.w = le32_to_cpu(bpl->tus.w);
                bpl++;
@@ -256,19 +228,50 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
        return mlist;
 }
 
+int
+lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
+{
+       struct lpfc_dmabuf *buf_ptr;
+
+       if (ctiocb->context_un.ndlp) {
+               lpfc_nlp_put(ctiocb->context_un.ndlp);
+               ctiocb->context_un.ndlp = NULL;
+       }
+       if (ctiocb->context1) {
+               buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1;
+               lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+               kfree(buf_ptr);
+               ctiocb->context1 = NULL;
+       }
+       if (ctiocb->context2) {
+               lpfc_free_ct_rsp(phba, (struct lpfc_dmabuf *) ctiocb->context2);
+               ctiocb->context2 = NULL;
+       }
+
+       if (ctiocb->context3) {
+               buf_ptr = (struct lpfc_dmabuf *) ctiocb->context3;
+               lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+               kfree(buf_ptr);
+               ctiocb->context1 = NULL;
+       }
+       lpfc_sli_release_iocbq(phba, ctiocb);
+       return 0;
+}
+
 static int
 lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
             struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
             void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
                     struct lpfc_iocbq *),
             struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry,
-            uint32_t tmo)
+            uint32_t tmo, uint8_t retry)
 {
        struct lpfc_hba  *phba = vport->phba;
        struct lpfc_sli  *psli = &phba->sli;
        struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
        IOCB_t *icmd;
        struct lpfc_iocbq *geniocb;
+       int rc;
 
        /* Allocate buffer for  command iocb */
        geniocb = lpfc_sli_get_iocbq(phba);
@@ -291,6 +294,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
        /* Save for completion so we can release these resources */
        geniocb->context1 = (uint8_t *) inp;
        geniocb->context2 = (uint8_t *) outp;
+       geniocb->context_un.ndlp = ndlp;
 
        /* Fill in payload, bp points to frame payload */
        icmd->ulpCommand = CMD_GEN_REQUEST64_CR;
@@ -311,15 +315,25 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
        icmd->ulpClass = CLASS3;
        icmd->ulpContext = ndlp->nlp_rpi;
 
+       if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+               /* For GEN_REQUEST64_CR, use the RPI */
+               icmd->ulpCt_h = 0;
+               icmd->ulpCt_l = 0;
+       }
+
        /* Issue GEN REQ IOCB for NPORT <did> */
-       lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0119 Issue GEN REQ IOCB for NPORT x%x "
-                       "Data: x%x x%x\n", phba->brd_no, icmd->un.ulpWord[5],
-                       icmd->ulpIoTag, vport->port_state);
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+                        "0119 Issue GEN REQ IOCB to NPORT x%x "
+                        "Data: x%x x%x\n",
+                        ndlp->nlp_DID, icmd->ulpIoTag,
+                        vport->port_state);
        geniocb->iocb_cmpl = cmpl;
        geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT;
        geniocb->vport = vport;
-       if (lpfc_sli_issue_iocb(phba, pring, geniocb, 0) == IOCB_ERROR) {
+       geniocb->retry = retry;
+       rc = lpfc_sli_issue_iocb(phba, pring, geniocb, 0);
+
+       if (rc == IOCB_ERROR) {
                lpfc_sli_release_iocbq(phba, geniocb);
                return 1;
        }
@@ -332,7 +346,7 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
            struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp,
            void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
                          struct lpfc_iocbq *),
-           uint32_t rsp_size)
+           uint32_t rsp_size, uint8_t retry)
 {
        struct lpfc_hba  *phba = vport->phba;
        struct ulp_bde64 *bpl = (struct ulp_bde64 *) bmp->virt;
@@ -349,7 +363,7 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
                return -ENOMEM;
 
        status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0,
-                             cnt+1, 0);
+                             cnt+1, 0, retry);
        if (status) {
                lpfc_free_ct_rsp(phba, outmp);
                return -ENOMEM;
@@ -357,10 +371,25 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
        return 0;
 }
 
+struct lpfc_vport *
+lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) {
+       struct lpfc_vport *vport_curr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&phba->hbalock, flags);
+       list_for_each_entry(vport_curr, &phba->port_list, listentry) {
+               if ((vport_curr->fc_myDID) && (vport_curr->fc_myDID == did)) {
+                       spin_unlock_irqrestore(&phba->hbalock, flags);
+                       return vport_curr;
+               }
+       }
+       spin_unlock_irqrestore(&phba->hbalock, flags);
+       return NULL;
+}
+
 static int
 lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
 {
-       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
        struct lpfc_hba  *phba = vport->phba;
        struct lpfc_sli_ct_request *Response =
                (struct lpfc_sli_ct_request *) mp->virt;
@@ -372,6 +401,8 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
        struct list_head head;
 
        lpfc_set_disctmo(vport);
+       vport->num_disc_nodes = 0;
+       vport->fc_ns_retry = 0;
 
 
        list_add_tail(&head, &mp->list);
@@ -392,25 +423,99 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
                        /* Get next DID from NameServer List */
                        CTentry = *ctptr++;
                        Did = ((be32_to_cpu(CTentry)) & Mask_DID);
+
                        ndlp = NULL;
-                       /* Check for rscn processing or not */
-                       if (Did != vport->fc_myDID)
-                               ndlp = lpfc_setup_disc_node(vport, Did);
-                       if (ndlp) {
-                               lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-                                               "%d:0238 Process x%x NameServer"
-                                               " Rsp Data: x%x x%x x%x\n",
-                                               phba->brd_no,
+
+                       /*
+                        * Check for rscn processing or not
+                        * To conserve rpi's, filter out addresses for other
+                        * vports on the same physical HBAs.
+                        */
+                       if ((Did != vport->fc_myDID) &&
+                           ((lpfc_find_vport_by_did(phba, Did) == NULL) ||
+                            vport->cfg_peer_port_login)) {
+                               if ((vport->port_type != LPFC_NPIV_PORT) ||
+                                   (!(vport->ct_flags & FC_CT_RFF_ID)) ||
+                                   (!vport->cfg_restrict_login)) {
+                                       ndlp = lpfc_setup_disc_node(vport, Did);
+                                       if (ndlp) {
+                                               lpfc_debugfs_disc_trc(vport,
+                                               LPFC_DISC_TRC_CT,
+                                               "Parse GID_FTrsp: "
+                                               "did:x%x flg:x%x x%x",
                                                Did, ndlp->nlp_flag,
-                                               vport->fc_flag,
+                                               vport->fc_flag);
+
+                                               lpfc_printf_vlog(vport,
+                                                       KERN_INFO,
+                                                       LOG_DISCOVERY,
+                                                       "0238 Process "
+                                                       "x%x NameServer Rsp"
+                                                       "Data: x%x x%x x%x\n",
+                                                       Did, ndlp->nlp_flag,
+                                                       vport->fc_flag,
+                                                       vport->fc_rscn_id_cnt);
+                                       } else {
+                                               lpfc_debugfs_disc_trc(vport,
+                                               LPFC_DISC_TRC_CT,
+                                               "Skip1 GID_FTrsp: "
+                                               "did:x%x flg:x%x cnt:%d",
+                                               Did, vport->fc_flag,
                                                vport->fc_rscn_id_cnt);
-                       } else {
-                               lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-                                               "%d:0239 Skip x%x NameServer "
-                                               "Rsp Data: x%x x%x x%x\n",
-                                               phba->brd_no,
-                                               Did, Size, vport->fc_flag,
+
+                                               lpfc_printf_vlog(vport,
+                                                       KERN_INFO,
+                                                       LOG_DISCOVERY,
+                                                       "0239 Skip x%x "
+                                                       "NameServer Rsp Data: "
+                                                       "x%x x%x\n",
+                                                       Did, vport->fc_flag,
+                                                       vport->fc_rscn_id_cnt);
+                                       }
+
+                               } else {
+                                       if (!(vport->fc_flag & FC_RSCN_MODE) ||
+                                       (lpfc_rscn_payload_check(vport, Did))) {
+                                               lpfc_debugfs_disc_trc(vport,
+                                               LPFC_DISC_TRC_CT,
+                                               "Query GID_FTrsp: "
+                                               "did:x%x flg:x%x cnt:%d",
+                                               Did, vport->fc_flag,
                                                vport->fc_rscn_id_cnt);
+
+                                               /* This NPortID was previously
+                                                * a FCP target, * Don't even
+                                                * bother to send GFF_ID.
+                                                */
+                                               ndlp = lpfc_findnode_did(vport,
+                                                       Did);
+                                               if (ndlp && (ndlp->nlp_type &
+                                                       NLP_FCP_TARGET))
+                                                       lpfc_setup_disc_node
+                                                               (vport, Did);
+                                               else if (lpfc_ns_cmd(vport,
+                                                       SLI_CTNS_GFF_ID,
+                                                       0, Did) == 0)
+                                                       vport->num_disc_nodes++;
+                                       }
+                                       else {
+                                               lpfc_debugfs_disc_trc(vport,
+                                               LPFC_DISC_TRC_CT,
+                                               "Skip2 GID_FTrsp: "
+                                               "did:x%x flg:x%x cnt:%d",
+                                               Did, vport->fc_flag,
+                                               vport->fc_rscn_id_cnt);
+
+                                               lpfc_printf_vlog(vport,
+                                                       KERN_INFO,
+                                                       LOG_DISCOVERY,
+                                                       "0245 Skip x%x "
+                                                       "NameServer Rsp Data: "
+                                                       "x%x x%x\n",
+                                                       Did, vport->fc_flag,
+                                                       vport->fc_rscn_id_cnt);
+                                       }
+                               }
                        }
                        if (CTentry & (be32_to_cpu(SLI_CT_LAST_ENTRY)))
                                goto nsout1;
@@ -422,145 +527,384 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
 
 nsout1:
        list_del(&head);
-
-       /*
-        * The driver has cycled through all Nports in the RSCN payload.
-        * Complete the handling by cleaning up and marking the
-        * current driver state.
-        */
-       if (vport->port_state == LPFC_VPORT_READY) {
-               lpfc_els_flush_rscn(vport);
-               spin_lock_irq(shost->host_lock);
-               vport->fc_flag |= FC_RSCN_MODE; /* we are still in RSCN mode */
-               spin_unlock_irq(shost->host_lock);
-       }
        return 0;
 }
 
-
-
-
 static void
 lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        struct lpfc_iocbq *rspiocb)
 {
        struct lpfc_vport *vport = cmdiocb->vport;
+       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
        IOCB_t *irsp;
        struct lpfc_dmabuf *bmp;
-       struct lpfc_dmabuf *inp;
        struct lpfc_dmabuf *outp;
-       struct lpfc_nodelist *ndlp;
        struct lpfc_sli_ct_request *CTrsp;
-       int rc;
+       struct lpfc_nodelist *ndlp;
+       int rc, retry;
+
+       /* First save ndlp, before we overwrite it */
+       ndlp = cmdiocb->context_un.ndlp;
 
        /* we pass cmdiocb to state machine which needs rspiocb as well */
        cmdiocb->context_un.rsp_iocb = rspiocb;
 
-       inp = (struct lpfc_dmabuf *) cmdiocb->context1;
        outp = (struct lpfc_dmabuf *) cmdiocb->context2;
        bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
-
        irsp = &rspiocb->iocb;
-       if (irsp->ulpStatus) {
-               if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-                       ((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
-                        (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)))
-                       goto out;
 
+       lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+                "GID_FT cmpl:     status:x%x/x%x rtry:%d",
+               irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry);
+
+       /* Don't bother processing response if vport is being torn down. */
+       if (vport->load_flag & FC_UNLOADING)
+               goto out;
+
+       if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "0216 Link event during NS query\n");
+               lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+               goto out;
+       }
+
+       if (irsp->ulpStatus) {
                /* Check for retry */
                if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
-                       vport->fc_ns_retry++;
-                       /* CT command is being retried */
-                       ndlp = lpfc_findnode_did(vport, NameServer_DID);
-                       if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
-                               rc = lpfc_ns_cmd(vport, ndlp, SLI_CTNS_GID_FT);
-                               if (rc == 0)
+                       retry = 1;
+                       if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+                               switch (irsp->un.ulpWord[4]) {
+                               case IOERR_NO_RESOURCES:
+                                       /* We don't increment the retry
+                                        * count for this case.
+                                        */
+                                       break;
+                               case IOERR_LINK_DOWN:
+                               case IOERR_SLI_ABORTED:
+                               case IOERR_SLI_DOWN:
+                                       retry = 0;
+                                       break;
+                               default:
+                                       vport->fc_ns_retry++;
+                               }
+                       }
+                       else
+                               vport->fc_ns_retry++;
+
+                       if (retry) {
+                               /* CT command is being retried */
+                               rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
+                                        vport->fc_ns_retry, 0);
+                               if (rc == 0) {
+                                       /* success */
                                        goto out;
                                }
                        }
+               }
+               lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                                "0257 GID_FT Query error: 0x%x 0x%x\n",
+                                irsp->ulpStatus, vport->fc_ns_retry);
        } else {
                /* Good status, continue checking */
                CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
                if (CTrsp->CommandResponse.bits.CmdRsp ==
                    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
-                       lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-                                       "%d:0208 NameServer Rsp "
-                                       "Data: x%x\n",
-                                       phba->brd_no,
-                                       vport->fc_flag);
+                       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                        "0208 NameServer Rsp Data: x%x\n",
+                                        vport->fc_flag);
                        lpfc_ns_rsp(vport, outp,
                                    (uint32_t) (irsp->un.genreq64.bdl.bdeSize));
                } else if (CTrsp->CommandResponse.bits.CmdRsp ==
                           be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
                        /* NameServer Rsp Error */
-                       lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-                                       "%d:0240 NameServer Rsp Error "
+                       if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
+                           && (CTrsp->Explanation == SLI_CT_NO_FC4_TYPES)) {
+                               lpfc_printf_vlog(vport, KERN_INFO,
+                                       LOG_DISCOVERY,
+                                       "0269 No NameServer Entries "
+                                       "Data: x%x x%x x%x x%x\n",
+                                       CTrsp->CommandResponse.bits.CmdRsp,
+                                       (uint32_t) CTrsp->ReasonCode,
+                                       (uint32_t) CTrsp->Explanation,
+                                       vport->fc_flag);
+
+                               lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+                               "GID_FT no entry  cmd:x%x rsn:x%x exp:x%x",
+                               (uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
+                               (uint32_t) CTrsp->ReasonCode,
+                               (uint32_t) CTrsp->Explanation);
+                       } else {
+                               lpfc_printf_vlog(vport, KERN_INFO,
+                                       LOG_DISCOVERY,
+                                       "0240 NameServer Rsp Error "
                                        "Data: x%x x%x x%x x%x\n",
-                                       phba->brd_no,
                                        CTrsp->CommandResponse.bits.CmdRsp,
                                        (uint32_t) CTrsp->ReasonCode,
                                        (uint32_t) CTrsp->Explanation,
                                        vport->fc_flag);
+
+                               lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+                               "GID_FT rsp err1  cmd:x%x rsn:x%x exp:x%x",
+                               (uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
+                               (uint32_t) CTrsp->ReasonCode,
+                               (uint32_t) CTrsp->Explanation);
+                       }
+
+
                } else {
                        /* NameServer Rsp Error */
-                       lpfc_printf_log(phba,
-                                       KERN_INFO,
-                                       LOG_DISCOVERY,
-                                       "%d:0241 NameServer Rsp Error "
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+                                       "0241 NameServer Rsp Error "
                                        "Data: x%x x%x x%x x%x\n",
-                                       phba->brd_no,
                                        CTrsp->CommandResponse.bits.CmdRsp,
                                        (uint32_t) CTrsp->ReasonCode,
                                        (uint32_t) CTrsp->Explanation,
                                        vport->fc_flag);
+
+                       lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+                               "GID_FT rsp err2  cmd:x%x rsn:x%x exp:x%x",
+                               (uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
+                               (uint32_t) CTrsp->ReasonCode,
+                               (uint32_t) CTrsp->Explanation);
                }
        }
        /* Link up / RSCN discovery */
-       lpfc_disc_start(vport);
+       if (vport->num_disc_nodes == 0) {
+               /*
+                * The driver has cycled through all Nports in the RSCN payload.
+                * Complete the handling by cleaning up and marking the
+                * current driver state.
+                */
+               if (vport->port_state >= LPFC_DISC_AUTH) {
+                       if (vport->fc_flag & FC_RSCN_MODE) {
+                               lpfc_els_flush_rscn(vport);
+                               spin_lock_irq(shost->host_lock);
+                               vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */
+                               spin_unlock_irq(shost->host_lock);
+                       }
+                       else
+                               lpfc_els_flush_rscn(vport);
+               }
+
+               lpfc_disc_start(vport);
+       }
 out:
-       lpfc_free_ct_rsp(phba, outp);
-       lpfc_mbuf_free(phba, inp->virt, inp->phys);
-       lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-       kfree(inp);
-       kfree(bmp);
-       lpfc_sli_release_iocbq(phba, cmdiocb);
+       cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */
+       lpfc_ct_free_iocb(phba, cmdiocb);
        return;
 }
 
 static void
-lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        struct lpfc_iocbq *rspiocb)
 {
-       struct lpfc_dmabuf *bmp;
+       struct lpfc_vport *vport = cmdiocb->vport;
+       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+       IOCB_t *irsp = &rspiocb->iocb;
+       struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1;
+       struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+       struct lpfc_sli_ct_request *CTrsp;
+       int did, rc, retry;
+       uint8_t fbits;
+       struct lpfc_nodelist *ndlp;
+
+       did = ((struct lpfc_sli_ct_request *) inp->virt)->un.gff.PortId;
+       did = be32_to_cpu(did);
+
+       lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+               "GFF_ID cmpl:     status:x%x/x%x did:x%x",
+               irsp->ulpStatus, irsp->un.ulpWord[4], did);
+
+       if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+               /* Good status, continue checking */
+               CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+               fbits = CTrsp->un.gff_acc.fbits[FCP_TYPE_FEATURE_OFFSET];
+
+               if (CTrsp->CommandResponse.bits.CmdRsp ==
+                   be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
+                       if ((fbits & FC4_FEATURE_INIT) &&
+                           !(fbits & FC4_FEATURE_TARGET)) {
+                               lpfc_printf_vlog(vport, KERN_INFO,
+                                                LOG_DISCOVERY,
+                                                "0270 Skip x%x GFF "
+                                                "NameServer Rsp Data: (init) "
+                                                "x%x x%x\n", did, fbits,
+                                                vport->fc_rscn_id_cnt);
+                               goto out;
+                       }
+               }
+       }
+       else {
+               /* Check for retry */
+               if (cmdiocb->retry < LPFC_MAX_NS_RETRY) {
+                       retry = 1;
+                       if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+                               switch (irsp->un.ulpWord[4]) {
+                               case IOERR_NO_RESOURCES:
+                                       /* We don't increment the retry
+                                        * count for this case.
+                                        */
+                                       break;
+                               case IOERR_LINK_DOWN:
+                               case IOERR_SLI_ABORTED:
+                               case IOERR_SLI_DOWN:
+                                       retry = 0;
+                                       break;
+                               default:
+                                       cmdiocb->retry++;
+                               }
+                       }
+                       else
+                               cmdiocb->retry++;
+
+                       if (retry) {
+                               /* CT command is being retried */
+                               rc = lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID,
+                                        cmdiocb->retry, did);
+                               if (rc == 0) {
+                                       /* success */
+                                       lpfc_ct_free_iocb(phba, cmdiocb);
+                                       return;
+                               }
+                       }
+               }
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+                                "0267 NameServer GFF Rsp "
+                                "x%x Error (%d %d) Data: x%x x%x\n",
+                                did, irsp->ulpStatus, irsp->un.ulpWord[4],
+                                vport->fc_flag, vport->fc_rscn_id_cnt)
+       }
+
+       /* This is a target port, unregistered port, or the GFF_ID failed */
+       ndlp = lpfc_setup_disc_node(vport, did);
+       if (ndlp) {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "0242 Process x%x GFF "
+                                "NameServer Rsp Data: x%x x%x x%x\n",
+                                did, ndlp->nlp_flag, vport->fc_flag,
+                                vport->fc_rscn_id_cnt);
+       } else {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "0243 Skip x%x GFF "
+                                "NameServer Rsp Data: x%x x%x\n", did,
+                                vport->fc_flag, vport->fc_rscn_id_cnt);
+       }
+out:
+       /* Link up / RSCN discovery */
+       if (vport->num_disc_nodes)
+               vport->num_disc_nodes--;
+       if (vport->num_disc_nodes == 0) {
+               /*
+                * The driver has cycled through all Nports in the RSCN payload.
+                * Complete the handling by cleaning up and marking the
+                * current driver state.
+                */
+               if (vport->port_state >= LPFC_DISC_AUTH) {
+                       if (vport->fc_flag & FC_RSCN_MODE) {
+                               lpfc_els_flush_rscn(vport);
+                               spin_lock_irq(shost->host_lock);
+                               vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */
+                               spin_unlock_irq(shost->host_lock);
+                       }
+                       else
+                               lpfc_els_flush_rscn(vport);
+               }
+               lpfc_disc_start(vport);
+       }
+       lpfc_ct_free_iocb(phba, cmdiocb);
+       return;
+}
+
+
+static void
+lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+            struct lpfc_iocbq *rspiocb)
+{
+       struct lpfc_vport *vport = cmdiocb->vport;
        struct lpfc_dmabuf *inp;
        struct lpfc_dmabuf *outp;
        IOCB_t *irsp;
        struct lpfc_sli_ct_request *CTrsp;
+       struct lpfc_nodelist *ndlp;
+       int cmdcode, rc;
+       uint8_t retry;
+       uint32_t latt;
+
+       /* First save ndlp, before we overwrite it */
+       ndlp = cmdiocb->context_un.ndlp;
 
        /* we pass cmdiocb to state machine which needs rspiocb as well */
        cmdiocb->context_un.rsp_iocb = rspiocb;
 
        inp = (struct lpfc_dmabuf *) cmdiocb->context1;
        outp = (struct lpfc_dmabuf *) cmdiocb->context2;
-       bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
        irsp = &rspiocb->iocb;
 
+       cmdcode = be16_to_cpu(((struct lpfc_sli_ct_request *) inp->virt)->
+                                       CommandResponse.bits.CmdRsp);
        CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
 
+       latt = lpfc_els_chk_latt(vport);
+
        /* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
-       lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-                       "%d:0209 RFT request completes ulpStatus x%x "
-                       "CmdRsp x%x, Context x%x, Tag x%x\n",
-                       phba->brd_no, irsp->ulpStatus,
-                       CTrsp->CommandResponse.bits.CmdRsp,
-                       cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag);
-
-       lpfc_free_ct_rsp(phba, outp);
-       lpfc_mbuf_free(phba, inp->virt, inp->phys);
-       lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-       kfree(inp);
-       kfree(bmp);
-       lpfc_sli_release_iocbq(phba, cmdiocb);
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                        "0209 CT Request completes, latt %d, "
+                        "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
+                        latt, irsp->ulpStatus,
+                        CTrsp->CommandResponse.bits.CmdRsp,
+                        cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag);
+
+       lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+               "CT cmd cmpl:     status:x%x/x%x cmd:x%x",
+               irsp->ulpStatus, irsp->un.ulpWord[4], cmdcode);
+
+       if (irsp->ulpStatus) {
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+                                "0268 NS cmd %x Error (%d %d)\n",
+                                cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]);
+
+               if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+                       ((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
+                        (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)))
+                       goto out;
+
+               retry = cmdiocb->retry;
+               if (retry >= LPFC_MAX_NS_RETRY)
+                       goto out;
+
+               retry++;
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "0216 Retrying NS cmd %x\n", cmdcode);
+               rc = lpfc_ns_cmd(vport, cmdcode, retry, 0);
+               if (rc == 0)
+                       goto out;
+       }
+
+out:
+       cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */
+       lpfc_ct_free_iocb(phba, cmdiocb);
+       return;
+}
+
+static void
+lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                       struct lpfc_iocbq *rspiocb)
+{
+       IOCB_t *irsp = &rspiocb->iocb;
+       struct lpfc_vport *vport = cmdiocb->vport;
+
+       if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+               struct lpfc_dmabuf *outp;
+               struct lpfc_sli_ct_request *CTrsp;
+
+               outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+               CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+               if (CTrsp->CommandResponse.bits.CmdRsp ==
+                   be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+                       vport->ct_flags |= FC_CT_RFT_ID;
+       }
+       lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
        return;
 }
 
@@ -568,7 +912,41 @@ static void
 lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        struct lpfc_iocbq *rspiocb)
 {
-       lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+       IOCB_t *irsp = &rspiocb->iocb;
+       struct lpfc_vport *vport = cmdiocb->vport;
+
+       if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+               struct lpfc_dmabuf *outp;
+               struct lpfc_sli_ct_request *CTrsp;
+
+               outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+               CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+               if (CTrsp->CommandResponse.bits.CmdRsp ==
+                   be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+                       vport->ct_flags |= FC_CT_RNN_ID;
+       }
+       lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
+       return;
+}
+
+static void
+lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                        struct lpfc_iocbq *rspiocb)
+{
+       IOCB_t *irsp = &rspiocb->iocb;
+       struct lpfc_vport *vport = cmdiocb->vport;
+
+       if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+               struct lpfc_dmabuf *outp;
+               struct lpfc_sli_ct_request *CTrsp;
+
+               outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+               CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+               if (CTrsp->CommandResponse.bits.CmdRsp ==
+                   be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+                       vport->ct_flags |= FC_CT_RSPN_ID;
+       }
+       lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
        return;
 }
 
@@ -576,28 +954,91 @@ static void
 lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                         struct lpfc_iocbq *rspiocb)
 {
-       lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+       IOCB_t *irsp = &rspiocb->iocb;
+       struct lpfc_vport *vport = cmdiocb->vport;
+
+       if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+               struct lpfc_dmabuf *outp;
+               struct lpfc_sli_ct_request *CTrsp;
+
+               outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+               CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+               if (CTrsp->CommandResponse.bits.CmdRsp ==
+                   be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+                       vport->ct_flags |= FC_CT_RSNN_NN;
+       }
+       lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
+       return;
+}
+
+static void
+lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+       struct lpfc_vport *vport = cmdiocb->vport;
+
+       /* even if it fails we will act as though it succeeded. */
+       vport->ct_flags = 0;
+       lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
        return;
 }
 
 static void
-lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
-                        struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                       struct lpfc_iocbq *rspiocb)
 {
-       lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+       IOCB_t *irsp = &rspiocb->iocb;
+       struct lpfc_vport *vport = cmdiocb->vport;
+
+       if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+               struct lpfc_dmabuf *outp;
+               struct lpfc_sli_ct_request *CTrsp;
+
+               outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+               CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+               if (CTrsp->CommandResponse.bits.CmdRsp ==
+                   be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+                       vport->ct_flags |= FC_CT_RFF_ID;
+       }
+       lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
        return;
 }
 
-void
-lpfc_get_hba_sym_node_name(struct lpfc_hba *phba, uint8_t *symbp)
+static int
+lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol,
+       size_t size)
+{
+       int n;
+       uint8_t *wwn = vport->phba->wwpn;
+
+       n = snprintf(symbol, size,
+                    "Emulex PPN-%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+                    wwn[0], wwn[1], wwn[2], wwn[3],
+                    wwn[4], wwn[5], wwn[6], wwn[7]);
+
+       if (vport->port_type == LPFC_PHYSICAL_PORT)
+               return n;
+
+       if (n < size)
+               n += snprintf(symbol + n, size - n, " VPort-%d", vport->vpi);
+
+       if (n < size && vport->vname)
+               n += snprintf(symbol + n, size - n, " VName-%s", vport->vname);
+       return n;
+}
+
+int
+lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
+       size_t size)
 {
        char fwrev[16];
+       int n;
 
-       lpfc_decode_firmware_rev(phba, fwrev, 0);
+       lpfc_decode_firmware_rev(vport->phba, fwrev, 0);
 
-       sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName,
-               fwrev, lpfc_release_version);
-       return;
+       n = snprintf(symbol, size, "Emulex %s FV%s DV%s",
+               vport->phba->ModelName, fwrev, lpfc_release_version);
+       return n;
 }
 
 /*
@@ -608,8 +1049,10 @@ lpfc_get_hba_sym_node_name(struct lpfc_hba *phba, uint8_t *symbp)
  *       LI_CTNS_RFT_ID
  */
 int
-lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode)
+lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
+           uint8_t retry, uint32_t context)
 {
+       struct lpfc_nodelist * ndlp;
        struct lpfc_hba *phba = vport->phba;
        struct lpfc_dmabuf *mp, *bmp;
        struct lpfc_sli_ct_request *CtReq;
@@ -617,49 +1060,68 @@ lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode)
        void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
                      struct lpfc_iocbq *) = NULL;
        uint32_t rsp_size = 1024;
+       size_t   size;
+       int rc = 0;
+
+       ndlp = lpfc_findnode_did(vport, NameServer_DID);
+       if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) {
+               rc=1;
+               goto ns_cmd_exit;
+       }
 
        /* fill in BDEs for command */
        /* Allocate buffer for command payload */
        mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
-       if (!mp)
+       if (!mp) {
+               rc=2;
                goto ns_cmd_exit;
+       }
 
        INIT_LIST_HEAD(&mp->list);
        mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
-       if (!mp->virt)
+       if (!mp->virt) {
+               rc=3;
                goto ns_cmd_free_mp;
+       }
 
        /* Allocate buffer for Buffer ptr list */
        bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
-       if (!bmp)
+       if (!bmp) {
+               rc=4;
                goto ns_cmd_free_mpvirt;
+       }
 
        INIT_LIST_HEAD(&bmp->list);
        bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(bmp->phys));
-       if (!bmp->virt)
+       if (!bmp->virt) {
+               rc=5;
                goto ns_cmd_free_bmp;
+       }
 
        /* NameServer Req */
-       lpfc_printf_log(phba,
-                       KERN_INFO,
-                       LOG_DISCOVERY,
-                       "%d:0236 NameServer Req Data: x%x x%x x%x\n",
-                       phba->brd_no, cmdcode, vport->fc_flag,
-                       vport->fc_rscn_id_cnt);
+       lpfc_printf_vlog(vport, KERN_INFO ,LOG_DISCOVERY,
+                        "0236 NameServer Req Data: x%x x%x x%x\n",
+                        cmdcode, vport->fc_flag, vport->fc_rscn_id_cnt);
 
        bpl = (struct ulp_bde64 *) bmp->virt;
        memset(bpl, 0, sizeof(struct ulp_bde64));
-       bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) );
-       bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) );
+       bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
+       bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
        bpl->tus.f.bdeFlags = 0;
        if (cmdcode == SLI_CTNS_GID_FT)
                bpl->tus.f.bdeSize = GID_REQUEST_SZ;
+       else if (cmdcode == SLI_CTNS_GFF_ID)
+               bpl->tus.f.bdeSize = GFF_REQUEST_SZ;
        else if (cmdcode == SLI_CTNS_RFT_ID)
                bpl->tus.f.bdeSize = RFT_REQUEST_SZ;
        else if (cmdcode == SLI_CTNS_RNN_ID)
                bpl->tus.f.bdeSize = RNN_REQUEST_SZ;
+       else if (cmdcode == SLI_CTNS_RSPN_ID)
+               bpl->tus.f.bdeSize = RSPN_REQUEST_SZ;
        else if (cmdcode == SLI_CTNS_RSNN_NN)
                bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
+       else if (cmdcode == SLI_CTNS_DA_ID)
+               bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ;
        else if (cmdcode == SLI_CTNS_RFF_ID)
                bpl->tus.f.bdeSize = RFF_REQUEST_SZ;
        else
@@ -678,56 +1140,91 @@ lpfc_ns_cmd(struct lpfc_vport *vport, struct lpfc_nodelist * ndlp, int cmdcode)
                CtReq->CommandResponse.bits.CmdRsp =
                    be16_to_cpu(SLI_CTNS_GID_FT);
                CtReq->un.gid.Fc4Type = SLI_CTPT_FCP;
-               if (vport->port_state < LPFC_VPORT_READY)
+               if (vport->port_state < LPFC_NS_QRY)
                        vport->port_state = LPFC_NS_QRY;
                lpfc_set_disctmo(vport);
                cmpl = lpfc_cmpl_ct_cmd_gid_ft;
                rsp_size = FC_MAX_NS_RSP;
                break;
 
+       case SLI_CTNS_GFF_ID:
+               CtReq->CommandResponse.bits.CmdRsp =
+                       be16_to_cpu(SLI_CTNS_GFF_ID);
+               CtReq->un.gff.PortId = cpu_to_be32(context);
+               cmpl = lpfc_cmpl_ct_cmd_gff_id;
+               break;
+
        case SLI_CTNS_RFT_ID:
+               vport->ct_flags &= ~FC_CT_RFT_ID;
                CtReq->CommandResponse.bits.CmdRsp =
                    be16_to_cpu(SLI_CTNS_RFT_ID);
-               CtReq->un.rft.PortId = be32_to_cpu(vport->fc_myDID);
+               CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID);
                CtReq->un.rft.fcpReg = 1;
                cmpl = lpfc_cmpl_ct_cmd_rft_id;
                break;
 
-       case SLI_CTNS_RFF_ID:
-               CtReq->CommandResponse.bits.CmdRsp =
-                       be16_to_cpu(SLI_CTNS_RFF_ID);
-               CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);
-               CtReq->un.rff.feature_res = 0;
-               CtReq->un.rff.feature_tgt = 0;
-               CtReq->un.rff.type_code = FC_FCP_DATA;
-               CtReq->un.rff.feature_init = 1;
-               cmpl = lpfc_cmpl_ct_cmd_rff_id;
-               break;
-
        case SLI_CTNS_RNN_ID:
+               vport->ct_flags &= ~FC_CT_RNN_ID;
                CtReq->CommandResponse.bits.CmdRsp =
                    be16_to_cpu(SLI_CTNS_RNN_ID);
-               CtReq->un.rnn.PortId = be32_to_cpu(vport->fc_myDID);
+               CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
                memcpy(CtReq->un.rnn.wwnn,  &vport->fc_nodename,
                       sizeof (struct lpfc_name));
                cmpl = lpfc_cmpl_ct_cmd_rnn_id;
                break;
 
+       case SLI_CTNS_RSPN_ID:
+               vport->ct_flags &= ~FC_CT_RSPN_ID;
+               CtReq->CommandResponse.bits.CmdRsp =
+                   be16_to_cpu(SLI_CTNS_RSPN_ID);
+               CtReq->un.rspn.PortId = cpu_to_be32(vport->fc_myDID);
+               size = sizeof(CtReq->un.rspn.symbname);
+               CtReq->un.rspn.len =
+                       lpfc_vport_symbolic_port_name(vport,
+                       CtReq->un.rspn.symbname, size);
+               cmpl = lpfc_cmpl_ct_cmd_rspn_id;
+               break;
        case SLI_CTNS_RSNN_NN:
+               vport->ct_flags &= ~FC_CT_RSNN_NN;
                CtReq->CommandResponse.bits.CmdRsp =
                    be16_to_cpu(SLI_CTNS_RSNN_NN);
                memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
                       sizeof (struct lpfc_name));
-               lpfc_get_hba_sym_node_name(phba, CtReq->un.rsnn.symbname);
-               CtReq->un.rsnn.len = strlen(CtReq->un.rsnn.symbname);
+               size = sizeof(CtReq->un.rsnn.symbname);
+               CtReq->un.rsnn.len =
+                       lpfc_vport_symbolic_node_name(vport,
+                       CtReq->un.rsnn.symbname, size);
                cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
                break;
+       case SLI_CTNS_DA_ID:
+               /* Implement DA_ID Nameserver request */
+               CtReq->CommandResponse.bits.CmdRsp =
+                       be16_to_cpu(SLI_CTNS_DA_ID);
+               CtReq->un.da_id.port_id = cpu_to_be32(vport->fc_myDID);
+               cmpl = lpfc_cmpl_ct_cmd_da_id;
+               break;
+       case SLI_CTNS_RFF_ID:
+               vport->ct_flags &= ~FC_CT_RFF_ID;
+               CtReq->CommandResponse.bits.CmdRsp =
+                   be16_to_cpu(SLI_CTNS_RFF_ID);
+               CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);;
+               CtReq->un.rff.fbits = FC4_FEATURE_INIT;
+               CtReq->un.rff.type_code = FC_FCP_DATA;
+               cmpl = lpfc_cmpl_ct_cmd_rff_id;
+               break;
        }
+       lpfc_nlp_get(ndlp);
 
-       if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size))
+       if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) {
                /* On success, The cmpl function will free the buffers */
+               lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+                       "Issue CT cmd:    cmd:x%x did:x%x",
+                       cmdcode, ndlp->nlp_DID, 0);
                return 0;
+       }
 
+       rc=6;
+       lpfc_nlp_put(ndlp);
        lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
 ns_cmd_free_bmp:
        kfree(bmp);
@@ -736,6 +1233,9 @@ ns_cmd_free_mpvirt:
 ns_cmd_free_mp:
        kfree(mp);
 ns_cmd_exit:
+       lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+                        "0266 Issue NameServer Req x%x err %d Data: x%x x%x\n",
+                        cmdcode, rc, vport->fc_flag, vport->fc_rscn_id_cnt);
        return 1;
 }
 
@@ -743,7 +1243,6 @@ static void
 lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                      struct lpfc_iocbq * rspiocb)
 {
-       struct lpfc_dmabuf *bmp = cmdiocb->context3;
        struct lpfc_dmabuf *inp = cmdiocb->context1;
        struct lpfc_dmabuf *outp = cmdiocb->context2;
        struct lpfc_sli_ct_request *CTrsp = outp->virt;
@@ -752,13 +1251,31 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
        uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
        struct lpfc_vport *vport = cmdiocb->vport;
+       IOCB_t *irsp = &rspiocb->iocb;
+       uint32_t latt;
+
+       latt = lpfc_els_chk_latt(vport);
+
+       lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+               "FDMI cmpl:       status:x%x/x%x latt:%d",
+               irsp->ulpStatus, irsp->un.ulpWord[4], latt);
+
+       if (latt || irsp->ulpStatus) {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "0229 FDMI cmd %04x failed, latt = %d "
+                                "ulpStatus: x%x, rid x%x\n",
+                                be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
+                                irsp->un.ulpWord[4]);
+               lpfc_ct_free_iocb(phba, cmdiocb);
+               return;
+       }
 
        ndlp = lpfc_findnode_did(vport, FDMI_DID);
        if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
                /* FDMI rsp failed */
-               lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-                               "%d:0220 FDMI rsp failed Data: x%x\n",
-                               phba->brd_no, be16_to_cpu(fdmi_cmd));
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "0220 FDMI rsp failed Data: x%x\n",
+                                be16_to_cpu(fdmi_cmd));
        }
 
        switch (be16_to_cpu(fdmi_cmd)) {
@@ -777,13 +1294,7 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
                break;
        }
-
-       lpfc_free_ct_rsp(phba, outp);
-       lpfc_mbuf_free(phba, inp->virt, inp->phys);
-       lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-       kfree(inp);
-       kfree(bmp);
-       lpfc_sli_release_iocbq(phba, cmdiocb);
+       lpfc_ct_free_iocb(phba, cmdiocb);
        return;
 }
 
@@ -827,11 +1338,9 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
        INIT_LIST_HEAD(&bmp->list);
 
        /* FDMI request */
-       lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-                       "%d:0218 FDMI Request Data: x%x x%x x%x\n",
-                       phba->brd_no,
-                       vport->fc_flag, vport->port_state, cmdcode);
-
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                        "0218 FDMI Request Data: x%x x%x x%x\n",
+                        vport->fc_flag, vport->port_state, cmdcode);
        CtReq = (struct lpfc_sli_ct_request *) mp->virt;
 
        memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request));
@@ -1091,7 +1600,7 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
                        pab->ab.EntryCnt++;
                        size += FOURBYTES + len;
 
-                       if (phba->cfg_fdmi_on == 2) {
+                       if (vport->cfg_fdmi_on == 2) {
                                /* #6 Port attribute entry */
                                ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab +
                                                          size);
@@ -1134,17 +1643,19 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
        }
 
        bpl = (struct ulp_bde64 *) bmp->virt;
-       bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) );
-       bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) );
+       bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
+       bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
        bpl->tus.f.bdeFlags = 0;
        bpl->tus.f.bdeSize = size;
        bpl->tus.w = le32_to_cpu(bpl->tus.w);
 
        cmpl = lpfc_cmpl_ct_cmd_fdmi;
+       lpfc_nlp_get(ndlp);
 
-       if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP))
+       if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0))
                return 0;
 
+       lpfc_nlp_put(ndlp);
        lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
 fdmi_cmd_free_bmp:
        kfree(bmp);
@@ -1154,9 +1665,9 @@ fdmi_cmd_free_mp:
        kfree(mp);
 fdmi_cmd_exit:
        /* Issue FDMI request failed */
-       lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-                       "%d:0244 Issue FDMI request failed Data: x%x\n",
-                       phba->brd_no, cmdcode);
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                        "0244 Issue FDMI request failed Data: x%x\n",
+                        cmdcode);
        return 1;
 }
 
@@ -1170,10 +1681,15 @@ lpfc_fdmi_tmo(unsigned long ptr)
        spin_lock_irqsave(&vport->work_port_lock, iflag);
        if (!(vport->work_port_events & WORKER_FDMI_TMO)) {
                vport->work_port_events |= WORKER_FDMI_TMO;
+               spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+
+               spin_lock_irqsave(&phba->hbalock, iflag);
                if (phba->work_wait)
-                       wake_up(phba->work_wait);
+                       lpfc_worker_wake_up(phba);
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
        }
-       spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+       else
+               spin_unlock_irqrestore(&vport->work_port_lock, iflag);
 }
 
 void