/*******************************************************************
* 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 *
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;
* 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,
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 */
}
/**
+ * 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.
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.
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
/* 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);
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;
* 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)
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)) {
* 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;
}
*/
del_timer_sync(&ndlp->nlp_delayfunc);
retry = ndlp->nlp_retry;
+ ndlp->nlp_retry = 0;
switch (cmd) {
case ELS_CMD_FLOGI:
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;
}
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);
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;
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:
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;
/* 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.
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.
*/
}
/**
+ * 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.
} 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;
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;
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",
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++;
}
* 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;
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.
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;
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);
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);
}
* 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)
{
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;
}
/**
+ * 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.
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;
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;
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);
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);
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;
return 1;
}
lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING);
- vport->port_state = LPFC_FDISC;
return 0;
}
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);
+}