Merge branch 'for-next' into for-linus
[safe/jmp/linux-2.6] / drivers / scsi / lpfc / lpfc_els.c
index 2c034a5..2a40a6e 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -50,9 +50,6 @@ static int lpfc_issue_els_fdisc(struct lpfc_vport *vport,
                                struct lpfc_nodelist *ndlp, uint8_t retry);
 static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba,
                                  struct lpfc_iocbq *iocb);
-static void lpfc_register_new_vport(struct lpfc_hba *phba,
-                                   struct lpfc_vport *vport,
-                                   struct lpfc_nodelist *ndlp);
 
 static int lpfc_max_els_tries = 3;
 
@@ -146,7 +143,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport)
  *   Pointer to the newly allocated/prepared els iocb data structure
  *   NULL - when els iocb data structure allocation/preparation failed
  **/
-static struct lpfc_iocbq *
+struct lpfc_iocbq *
 lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
                   uint16_t cmdSize, uint8_t retry,
                   struct lpfc_nodelist *ndlp, uint32_t did,
@@ -168,6 +165,32 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
        if (elsiocb == NULL)
                return NULL;
 
+       /*
+        * If this command is for fabric controller and HBA running
+        * in FIP mode send FLOGI, FDISC and LOGO as FIP frames.
+        */
+       if ((did == Fabric_DID) &&
+               (phba->hba_flag & HBA_FIP_SUPPORT) &&
+               ((elscmd == ELS_CMD_FLOGI) ||
+                (elscmd == ELS_CMD_FDISC) ||
+                (elscmd == ELS_CMD_LOGO)))
+               switch (elscmd) {
+               case ELS_CMD_FLOGI:
+               elsiocb->iocb_flag |= ((ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT)
+                                       & LPFC_FIP_ELS_ID_MASK);
+               break;
+               case ELS_CMD_FDISC:
+               elsiocb->iocb_flag |= ((ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT)
+                                       & LPFC_FIP_ELS_ID_MASK);
+               break;
+               case ELS_CMD_LOGO:
+               elsiocb->iocb_flag |= ((ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT)
+                                       & LPFC_FIP_ELS_ID_MASK);
+               break;
+               }
+       else
+               elsiocb->iocb_flag &= ~LPFC_FIP_ELS_ID_MASK;
+
        icmd = &elsiocb->iocb;
 
        /* fill in BDEs for command */
@@ -388,6 +411,75 @@ fail:
 }
 
 /**
+ * lpfc_issue_reg_vfi - Register VFI for this vport's fabric login
+ * @vport: pointer to a host virtual N_Port data structure.
+ *
+ * This routine issues a REG_VFI mailbox for the vfi, vpi, fcfi triplet for
+ * the @vport. This mailbox command is necessary for FCoE only.
+ *
+ * Return code
+ *   0 - successfully issued REG_VFI for @vport
+ *   A failure code otherwise.
+ **/
+static int
+lpfc_issue_reg_vfi(struct lpfc_vport *vport)
+{
+       struct lpfc_hba  *phba = vport->phba;
+       LPFC_MBOXQ_t *mboxq;
+       struct lpfc_nodelist *ndlp;
+       struct serv_parm *sp;
+       struct lpfc_dmabuf *dmabuf;
+       int rc = 0;
+
+       sp = &phba->fc_fabparam;
+       ndlp = lpfc_findnode_did(vport, Fabric_DID);
+       if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
+               rc = -ENODEV;
+               goto fail;
+       }
+
+       dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+       if (!dmabuf) {
+               rc = -ENOMEM;
+               goto fail;
+       }
+       dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
+       if (!dmabuf->virt) {
+               rc = -ENOMEM;
+               goto fail_free_dmabuf;
+       }
+       mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mboxq) {
+               rc = -ENOMEM;
+               goto fail_free_coherent;
+       }
+       vport->port_state = LPFC_FABRIC_CFG_LINK;
+       memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam));
+       lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+       mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
+       mboxq->vport = vport;
+       mboxq->context1 = dmabuf;
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
+       if (rc == MBX_NOT_FINISHED) {
+               rc = -ENXIO;
+               goto fail_free_mbox;
+       }
+       return 0;
+
+fail_free_mbox:
+       mempool_free(mboxq, phba->mbox_mem_pool);
+fail_free_coherent:
+       lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+fail_free_dmabuf:
+       kfree(dmabuf);
+fail:
+       lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+       lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+               "0289 Issue Register VFI failed: Err %d\n", rc);
+       return rc;
+}
+
+/**
  * lpfc_cmpl_els_flogi_fabric - Completion function for flogi to a fabric port
  * @vport: pointer to a host virtual N_Port data structure.
  * @ndlp: pointer to a node-list data structure.
@@ -497,19 +589,38 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
                        spin_unlock_irq(shost->host_lock);
                }
+               /*
+                * If VPI is unreged, driver need to do INIT_VPI
+                * before re-registering
+                */
+               if (phba->sli_rev == LPFC_SLI_REV4) {
+                       spin_lock_irq(shost->host_lock);
+                       vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
+                       spin_unlock_irq(shost->host_lock);
+               }
        }
 
-       lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
-
-       if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
-           vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) {
-               lpfc_register_new_vport(phba, vport, ndlp);
-               return 0;
+       if (phba->sli_rev < LPFC_SLI_REV4) {
+               lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
+               if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
+                   vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
+                       lpfc_register_new_vport(phba, vport, ndlp);
+               else
+                       lpfc_issue_fabric_reglogin(vport);
+       } else {
+               ndlp->nlp_type |= NLP_FABRIC;
+               lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
+               if ((!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) &&
+                       (vport->vpi_state & LPFC_VPI_REGISTERED)) {
+                       lpfc_start_fdiscs(phba);
+                       lpfc_do_scr_ns_plogi(phba, vport);
+               } else if (vport->fc_flag & FC_VFI_REGISTERED)
+                       lpfc_issue_init_vpi(vport);
+               else
+                       lpfc_issue_reg_vfi(vport);
        }
-       lpfc_issue_fabric_reglogin(vport);
        return 0;
 }
-
 /**
  * lpfc_cmpl_els_flogi_nport - Completion function for flogi to an N_Port
  * @vport: pointer to a host virtual N_Port data structure.
@@ -702,6 +813,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                 irsp->ulpTimeout);
                goto flogifail;
        }
+       spin_lock_irq(shost->host_lock);
+       vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
+       spin_unlock_irq(shost->host_lock);
 
        /*
         * The FLogI succeeded.  Sync the data for the CPU before
@@ -713,7 +827,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
        /* FLOGI completes successfully */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
-                        "0101 FLOGI completes sucessfully "
+                        "0101 FLOGI completes successfully "
                         "Data: x%x x%x x%x x%x\n",
                         irsp->un.ulpWord[4], sp->cmn.e_d_tov,
                         sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
@@ -817,9 +931,14 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        if (sp->cmn.fcphHigh < FC_PH3)
                sp->cmn.fcphHigh = FC_PH3;
 
-       if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+       if  (phba->sli_rev == LPFC_SLI_REV4) {
+               elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1);
+               elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1);
+               /* FLOGI needs to be 3 for WQE FCFI */
+               /* Set the fcfi to the fcfi we registered with */
+               elsiocb->iocb.ulpContext = phba->fcf.fcfi;
+       } else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
                sp->cmn.request_multiple_Nport = 1;
-
                /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
                icmd->ulpCt_h = 1;
                icmd->ulpCt_l = 0;
@@ -862,7 +981,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
  * function returns, it does not guarantee all the IOCBs are actually aborted.
  *
  * Return code
- *   0 - Sucessfully issued abort iocb on all outstanding flogis (Always 0)
+ *   0 - Successfully issued abort iocb on all outstanding flogis (Always 0)
  **/
 int
 lpfc_els_abort_flogi(struct lpfc_hba *phba)
@@ -932,6 +1051,8 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
                if (!ndlp)
                        return 0;
                lpfc_nlp_init(vport, ndlp, Fabric_DID);
+               /* Set the node type */
+               ndlp->nlp_type |= NLP_FABRIC;
                /* Put ndlp onto node list */
                lpfc_enqueue_node(vport, ndlp);
        } else if (!NLP_CHK_NODE_ACT(ndlp)) {
@@ -1604,7 +1725,8 @@ lpfc_adisc_done(struct lpfc_vport *vport)
         * and continue discovery.
         */
        if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
-           !(vport->fc_flag & FC_RSCN_MODE)) {
+           !(vport->fc_flag & FC_RSCN_MODE) &&
+           (phba->sli_rev < LPFC_SLI_REV4)) {
                lpfc_issue_reg_vpi(phba, vport);
                return;
        }
@@ -2355,6 +2477,7 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
         */
        del_timer_sync(&ndlp->nlp_delayfunc);
        retry = ndlp->nlp_retry;
+       ndlp->nlp_retry = 0;
 
        switch (cmd) {
        case ELS_CMD_FLOGI:
@@ -2609,17 +2732,21 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        if (did == FDMI_DID)
                retry = 1;
 
-       if ((cmd == ELS_CMD_FLOGI) &&
+       if (((cmd == ELS_CMD_FLOGI) || (cmd == ELS_CMD_FDISC)) &&
            (phba->fc_topology != TOPOLOGY_LOOP) &&
            !lpfc_error_lost_link(irsp)) {
                /* FLOGI retry policy */
                retry = 1;
-               maxretry = 48;
-               if (cmdiocb->retry >= 32)
+               /* retry forever */
+               maxretry = 0;
+               if (cmdiocb->retry >= 100)
+                       delay = 5000;
+               else if (cmdiocb->retry >= 32)
                        delay = 1000;
        }
 
-       if ((++cmdiocb->retry) >= maxretry) {
+       cmdiocb->retry++;
+       if (maxretry && (cmdiocb->retry >= maxretry)) {
                phba->fc_stat.elsRetryExceeded++;
                retry = 0;
        }
@@ -2937,6 +3064,14 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
        struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
 
+       /*
+        * This routine is used to register and unregister in previous SLI
+        * modes.
+        */
+       if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) &&
+           (phba->sli_rev == LPFC_SLI_REV4))
+               lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi);
+
        pmb->context1 = NULL;
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
@@ -2994,7 +3129,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
            (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) {
                /* A LS_RJT associated with Default RPI cleanup has its own
-                * seperate code path.
+                * separate code path.
                 */
                if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI))
                        ls_rjt = 1;
@@ -3816,7 +3951,9 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did)
                        payload_len -= sizeof(uint32_t);
                        switch (rscn_did.un.b.resv & RSCN_ADDRESS_FORMAT_MASK) {
                        case RSCN_ADDRESS_FORMAT_PORT:
-                               if (ns_did.un.word == rscn_did.un.word)
+                               if ((ns_did.un.b.domain == rscn_did.un.b.domain)
+                                   && (ns_did.un.b.area == rscn_did.un.b.area)
+                                   && (ns_did.un.b.id == rscn_did.un.b.id))
                                        goto return_did_out;
                                break;
                        case RSCN_ADDRESS_FORMAT_AREA:
@@ -4017,8 +4154,8 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        spin_lock_irq(shost->host_lock);
        if (vport->fc_rscn_flush) {
                /* Another thread is walking fc_rscn_id_list on this vport */
-               spin_unlock_irq(shost->host_lock);
                vport->fc_flag |= FC_RSCN_DISCOVERY;
+               spin_unlock_irq(shost->host_lock);
                /* Send back ACC */
                lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
                return 0;
@@ -4026,7 +4163,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        /* Indicate we are walking fc_rscn_id_list on this vport */
        vport->fc_rscn_flush = 1;
        spin_unlock_irq(shost->host_lock);
-       /* Get the array count after sucessfully have the token */
+       /* Get the array count after successfully have the token */
        rscn_cnt = vport->fc_rscn_id_cnt;
        /* If we are already processing an RSCN, save the received
         * RSCN payload buffer, cmdiocb->context2 to process later.
@@ -4260,7 +4397,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 
        did = Fabric_DID;
 
-       if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) {
+       if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
                /* For a FLOGI we accept, then if our portname is greater
                 * then the remote portname we initiate Nport login.
                 */
@@ -4396,6 +4533,29 @@ lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 }
 
 /**
+ * lpfc_els_rcv_rrq - Process an unsolicited rrq iocb
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * This routine processes a Reinstate Recovery Qualifier (RRQ) IOCB
+ * received as an ELS unsolicited event. A request to RRQ shall only
+ * be accepted if the Originator Nx_Port N_Port_ID or the Responder
+ * Nx_Port N_Port_ID of the target Exchange is the same as the
+ * N_Port_ID of the Nx_Port that makes the request. If the RRQ is
+ * not accepted, an LS_RJT with reason code "Unable to perform
+ * command request" and reason code explanation "Invalid Originator
+ * S_ID" shall be returned. For now, we just unconditionally accept
+ * RRQ from the target.
+ **/
+static void
+lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+                struct lpfc_nodelist *ndlp)
+{
+       lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
+}
+
+/**
  * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd
  * @phba: pointer to lpfc hba data structure.
  * @pmb: pointer to the driver internal queue element for mailbox command.
@@ -4857,7 +5017,10 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                } else {
                        /* FAN verified - skip FLOGI */
                        vport->fc_myDID = vport->fc_prevDID;
-                       lpfc_issue_fabric_reglogin(vport);
+                       if (phba->sli_rev < LPFC_SLI_REV4)
+                               lpfc_issue_fabric_reglogin(vport);
+                       else
+                               lpfc_issue_reg_vfi(vport);
                }
        }
        return 0;
@@ -5286,7 +5449,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        if (lpfc_els_chk_latt(vport))
                goto dropit;
 
-       /* Ignore traffic recevied during vport shutdown. */
+       /* Ignore traffic received during vport shutdown. */
        if (vport->load_flag & FC_UNLOADING)
                goto dropit;
 
@@ -5508,6 +5671,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                if (newnode)
                        lpfc_nlp_put(ndlp);
                break;
+       case ELS_CMD_RRQ:
+               lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+                       "RCV RRQ:         did:x%x/ste:x%x flg:x%x",
+                       did, vport->port_state, ndlp->nlp_flag);
+
+               phba->fc_stat.elsRcvRRQ++;
+               lpfc_els_rcv_rrq(vport, elsiocb, ndlp);
+               if (newnode)
+                       lpfc_nlp_put(ndlp);
+               break;
        default:
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
                        "RCV ELS cmd:     cmd:x%x did:x%x/ste:x%x",
@@ -5540,11 +5713,10 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
 dropit:
        if (vport && !(vport->load_flag & FC_UNLOADING))
-               lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-                       "(%d):0111 Dropping received ELS cmd "
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                       "0111 Dropping received ELS cmd "
                        "Data: x%x x%x x%x\n",
-                       vport->vpi, icmd->ulpStatus,
-                       icmd->un.ulpWord[4], icmd->ulpTimeout);
+                       icmd->ulpStatus, icmd->un.ulpWord[4], icmd->ulpTimeout);
        phba->fc_stat.elsRcvDrop++;
 }
 
@@ -5561,7 +5733,7 @@ dropit:
  *    NULL - No vport with the matching @vpi found
  *    Otherwise - Address to the vport with the matching @vpi.
  **/
-static struct lpfc_vport *
+struct lpfc_vport *
 lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
 {
        struct lpfc_vport *vport;
@@ -5620,10 +5792,9 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
             icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
                if (icmd->unsli3.rcvsli3.vpi == 0xffff)
                        vport = phba->pport;
-               else {
-                       uint16_t vpi = icmd->unsli3.rcvsli3.vpi;
-                       vport = lpfc_find_vport_by_vpid(phba, vpi);
-               }
+               else
+                       vport = lpfc_find_vport_by_vpid(phba,
+                               icmd->unsli3.rcvsli3.vpi - phba->vpi_base);
        }
        /* If there are no BDEs associated
         * with this IOCB, there is nothing to do.
@@ -5756,6 +5927,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
        struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
        MAILBOX_t *mb = &pmb->u.mb;
+       int rc;
 
        spin_lock_irq(shost->host_lock);
        vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
@@ -5777,6 +5949,26 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                        spin_unlock_irq(shost->host_lock);
                        lpfc_can_disctmo(vport);
                        break;
+               /* If reg_vpi fail with invalid VPI status, re-init VPI */
+               case 0x20:
+                       spin_lock_irq(shost->host_lock);
+                       vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+                       spin_unlock_irq(shost->host_lock);
+                       lpfc_init_vpi(phba, pmb, vport->vpi);
+                       pmb->vport = vport;
+                       pmb->mbox_cmpl = lpfc_init_vpi_cmpl;
+                       rc = lpfc_sli_issue_mbox(phba, pmb,
+                               MBX_NOWAIT);
+                       if (rc == MBX_NOT_FINISHED) {
+                               lpfc_printf_vlog(vport,
+                                       KERN_ERR, LOG_MBOX,
+                                       "2732 Failed to issue INIT_VPI"
+                                       " mailbox command\n");
+                       } else {
+                               lpfc_nlp_put(ndlp);
+                               return;
+                       }
+
                default:
                        /* Try to recover from this error */
                        lpfc_mbx_unreg_vpi(vport);
@@ -5789,11 +5981,18 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                                lpfc_initial_fdisc(vport);
                        break;
                }
-
        } else {
-               if (vport == phba->pport)
-                       lpfc_issue_fabric_reglogin(vport);
-               else
+               spin_lock_irq(shost->host_lock);
+               vport->vpi_state |= LPFC_VPI_REGISTERED;
+               spin_unlock_irq(shost->host_lock);
+               if (vport == phba->pport) {
+                       if (phba->sli_rev < LPFC_SLI_REV4)
+                               lpfc_issue_fabric_reglogin(vport);
+                       else {
+                               lpfc_start_fdiscs(phba);
+                               lpfc_do_scr_ns_plogi(phba, vport);
+                       }
+               } else
                        lpfc_do_scr_ns_plogi(phba, vport);
        }
 
@@ -5815,7 +6014,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
  * This routine registers the @vport as a new virtual port with a HBA.
  * It is done through a registering vpi mailbox command.
  **/
-static void
+void
 lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
                        struct lpfc_nodelist *ndlp)
 {
@@ -5824,7 +6023,7 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
 
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (mbox) {
-               lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, mbox);
+               lpfc_reg_vpi(vport, mbox);
                mbox->vport = vport;
                mbox->context2 = lpfc_nlp_get(ndlp);
                mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
@@ -5856,6 +6055,78 @@ mbox_err_exit:
 }
 
 /**
+ * lpfc_retry_pport_discovery - Start timer to retry FLOGI.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine abort all pending discovery commands and
+ * start a timer to retry FLOGI for the physical port
+ * discovery.
+ **/
+void
+lpfc_retry_pport_discovery(struct lpfc_hba *phba)
+{
+       struct lpfc_vport **vports;
+       struct lpfc_nodelist *ndlp;
+       struct Scsi_Host  *shost;
+       int i;
+       uint32_t link_state;
+
+       /* Treat this failure as linkdown for all vports */
+       link_state = phba->link_state;
+       lpfc_linkdown(phba);
+       phba->link_state = link_state;
+
+       vports = lpfc_create_vport_work_array(phba);
+
+       if (vports) {
+               for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+                       ndlp = lpfc_findnode_did(vports[i], Fabric_DID);
+                       if (ndlp)
+                               lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
+                       lpfc_els_flush_cmd(vports[i]);
+               }
+               lpfc_destroy_vport_work_array(phba, vports);
+       }
+
+       /* If fabric require FLOGI, then re-instantiate physical login */
+       ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+       if (!ndlp)
+               return;
+
+
+       shost = lpfc_shost_from_vport(phba->pport);
+       mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+       spin_lock_irq(shost->host_lock);
+       ndlp->nlp_flag |= NLP_DELAY_TMO;
+       spin_unlock_irq(shost->host_lock);
+       ndlp->nlp_last_elscmd = ELS_CMD_FLOGI;
+       phba->pport->port_state = LPFC_FLOGI;
+       return;
+}
+
+/**
+ * lpfc_fabric_login_reqd - Check if FLOGI required.
+ * @phba: pointer to lpfc hba data structure.
+ * @cmdiocb: pointer to FDISC command iocb.
+ * @rspiocb: pointer to FDISC response iocb.
+ *
+ * This routine checks if a FLOGI is reguired for FDISC
+ * to succeed.
+ **/
+static int
+lpfc_fabric_login_reqd(struct lpfc_hba *phba,
+               struct lpfc_iocbq *cmdiocb,
+               struct lpfc_iocbq *rspiocb)
+{
+
+       if ((rspiocb->iocb.ulpStatus != IOSTAT_FABRIC_RJT) ||
+               (rspiocb->iocb.un.ulpWord[4] != RJT_LOGIN_REQUIRED))
+               return 0;
+       else
+               return 1;
+}
+
+/**
  * lpfc_cmpl_els_fdisc - Completion function for fdisc iocb command
  * @phba: pointer to lpfc hba data structure.
  * @cmdiocb: pointer to lpfc command iocb data structure.
@@ -5904,6 +6175,12 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
 
        if (irsp->ulpStatus) {
+
+               if (lpfc_fabric_login_reqd(phba, cmdiocb, rspiocb)) {
+                       lpfc_retry_pport_discovery(phba);
+                       goto out;
+               }
+
                /* Check for retry */
                if (lpfc_els_retry(phba, cmdiocb, rspiocb))
                        goto out;
@@ -5913,12 +6190,8 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                 irsp->ulpStatus, irsp->un.ulpWord[4]);
                goto fdisc_failed;
        }
-               if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
-                       lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-               lpfc_nlp_put(ndlp);
-               /* giving up on FDISC. Cancel discovery timer */
-               lpfc_can_disctmo(vport);
        spin_lock_irq(shost->host_lock);
+       vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
        vport->fc_flag |= FC_FABRIC;
        if (vport->phba->fc_topology == TOPOLOGY_LOOP)
                vport->fc_flag |=  FC_PUBLIC_LOOP;
@@ -5946,10 +6219,13 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                lpfc_mbx_unreg_vpi(vport);
                spin_lock_irq(shost->host_lock);
                vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+               vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
                spin_unlock_irq(shost->host_lock);
        }
 
-       if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
+       if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI)
+               lpfc_issue_init_vpi(vport);
+       else if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
                lpfc_register_new_vport(phba, vport, ndlp);
        else
                lpfc_do_scr_ns_plogi(phba, vport);
@@ -5996,6 +6272,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        int did = ndlp->nlp_DID;
        int rc;
 
+       vport->port_state = LPFC_FDISC;
        cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
        elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
                                     ELS_CMD_FDISC);
@@ -6010,9 +6287,17 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        icmd->un.elsreq64.myID = 0;
        icmd->un.elsreq64.fl = 1;
 
-       /* For FDISC, Let FDISC rsp set the NPortID for this VPI */
-       icmd->ulpCt_h = 1;
-       icmd->ulpCt_l = 0;
+       if  (phba->sli_rev == LPFC_SLI_REV4) {
+               /* FDISC needs to be 1 for WQE VPI */
+               elsiocb->iocb.ulpCt_h = (SLI4_CT_VPI >> 1) & 1;
+               elsiocb->iocb.ulpCt_l = SLI4_CT_VPI & 1 ;
+               /* Set the ulpContext to the vpi */
+               elsiocb->iocb.ulpContext = vport->vpi + phba->vpi_base;
+       } else {
+               /* For FDISC, Let FDISC rsp set the NPortID for this VPI */
+               icmd->ulpCt_h = 1;
+               icmd->ulpCt_l = 0;
+       }
 
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
        *((uint32_t *) (pcmd)) = ELS_CMD_FDISC;
@@ -6053,7 +6338,6 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                return 1;
        }
        lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING);
-       vport->port_state = LPFC_FDISC;
        return 0;
 }
 
@@ -6496,3 +6780,38 @@ void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
        lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
                              IOERR_SLI_ABORTED);
 }
+
+/**
+ * lpfc_sli4_els_xri_aborted - Slow-path process of els xri abort
+ * @phba: pointer to lpfc hba data structure.
+ * @axri: pointer to the els xri abort wcqe structure.
+ *
+ * This routine is invoked by the worker thread to process a SLI4 slow-path
+ * ELS aborted xri.
+ **/
+void
+lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
+                         struct sli4_wcqe_xri_aborted *axri)
+{
+       uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
+       struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
+       unsigned long iflag = 0;
+
+       spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, iflag);
+       list_for_each_entry_safe(sglq_entry, sglq_next,
+                       &phba->sli4_hba.lpfc_abts_els_sgl_list, list) {
+               if (sglq_entry->sli4_xritag == xri) {
+                       list_del(&sglq_entry->list);
+                       spin_unlock_irqrestore(
+                                       &phba->sli4_hba.abts_sgl_list_lock,
+                                        iflag);
+                       spin_lock_irqsave(&phba->hbalock, iflag);
+
+                       list_add_tail(&sglq_entry->list,
+                               &phba->sli4_hba.lpfc_sgl_list);
+                       spin_unlock_irqrestore(&phba->hbalock, iflag);
+                       return;
+               }
+       }
+       spin_unlock_irqrestore(&phba->sli4_hba.abts_sgl_list_lock, iflag);
+}