/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2009 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2011 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
return 0;
/* Read the HBA Host Attention Register */
- ha_copy = readl(phba->HAregaddr);
+ if (lpfc_readl(phba->HAregaddr, &ha_copy))
+ return 1;
if (!(ha_copy & HA_LATT))
return 0;
phba->pport->port_state);
/* CLEAR_LA should re-enable link attention events and
- * we should then imediately take a LATT event. The
+ * we should then immediately take a LATT event. The
* LATT processing should call lpfc_linkdown() which
* will cleanup any left over in-progress discovery
* events.
(elscmd == ELS_CMD_LOGO)))
switch (elscmd) {
case ELS_CMD_FLOGI:
- elsiocb->iocb_flag |= ((ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT)
+ elsiocb->iocb_flag |=
+ ((LPFC_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)
+ elsiocb->iocb_flag |=
+ ((LPFC_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)
+ elsiocb->iocb_flag |=
+ ((LPFC_ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT)
& LPFC_FIP_ELS_ID_MASK);
break;
}
icmd->un.elsreq64.myID = vport->fc_myDID;
/* For ELS_REQUEST64_CR, use the VPI by default */
- icmd->ulpContext = vport->vpi + phba->vpi_base;
+ icmd->ulpContext = phba->vpi_ids[vport->vpi];
icmd->ulpCt_h = 0;
/* The CT field must be 0=INVALID_RPI for the ECHO cmd */
if (elscmd == ELS_CMD_ECHO)
err = 4;
goto fail;
}
- rc = lpfc_reg_rpi(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox, 0);
+ rc = lpfc_reg_rpi(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
+ ndlp->nlp_rpi);
if (rc) {
err = 5;
goto fail_free_mbox;
rc = -ENOMEM;
goto fail_free_dmabuf;
}
+
mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mboxq) {
rc = -ENOMEM;
return rc;
}
+/**
+ * lpfc_check_clean_addr_bit - Check whether assigned FCID is clean.
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @sp: pointer to service parameter data structure.
+ *
+ * This routine is called from FLOGI/FDISC completion handler functions.
+ * lpfc_check_clean_addr_bit return 1 when FCID/Fabric portname/ Fabric
+ * node nodename is changed in the completion service parameter else return
+ * 0. This function also set flag in the vport data structure to delay
+ * NP_Port discovery after the FLOGI/FDISC completion if Clean address bit
+ * in FLOGI/FDISC response is cleared and FCID/Fabric portname/ Fabric
+ * node nodename is changed in the completion service parameter.
+ *
+ * Return code
+ * 0 - FCID and Fabric Nodename and Fabric portname is not changed.
+ * 1 - FCID or Fabric Nodename or Fabric portname is changed.
+ *
+ **/
+static uint8_t
+lpfc_check_clean_addr_bit(struct lpfc_vport *vport,
+ struct serv_parm *sp)
+{
+ uint8_t fabric_param_changed = 0;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ if ((vport->fc_prevDID != vport->fc_myDID) ||
+ memcmp(&vport->fabric_portname, &sp->portName,
+ sizeof(struct lpfc_name)) ||
+ memcmp(&vport->fabric_nodename, &sp->nodeName,
+ sizeof(struct lpfc_name)))
+ fabric_param_changed = 1;
+
+ /*
+ * Word 1 Bit 31 in common service parameter is overloaded.
+ * Word 1 Bit 31 in FLOGI request is multiple NPort request
+ * Word 1 Bit 31 in FLOGI response is clean address bit
+ *
+ * If fabric parameter is changed and clean address bit is
+ * cleared delay nport discovery if
+ * - vport->fc_prevDID != 0 (not initial discovery) OR
+ * - lpfc_delay_discovery module parameter is set.
+ */
+ if (fabric_param_changed && !sp->cmn.clean_address_bit &&
+ (vport->fc_prevDID || lpfc_delay_discovery)) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_DISC_DELAYED;
+ spin_unlock_irq(shost->host_lock);
+ }
+
+ return fabric_param_changed;
+}
+
+
/**
* lpfc_cmpl_els_flogi_fabric - Completion function for flogi to a fabric port
* @vport: pointer to a host virtual N_Port data structure.
struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *np;
struct lpfc_nodelist *next_np;
+ uint8_t fabric_param_changed;
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_FABRIC;
if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */
phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000;
+ phba->fc_edtovResol = sp->cmn.edtovResolution;
phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_PUBLIC_LOOP;
spin_unlock_irq(shost->host_lock);
- } else {
- /*
- * If we are a N-port connected to a Fabric, fixup sparam's so
- * logins to devices on remote loops work.
- */
- vport->fc_sparam.cmn.altBbCredit = 1;
}
vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
ndlp->nlp_class_sup |= FC_COS_CLASS4;
ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
sp->cmn.bbRcvSizeLsb;
+
+ fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp);
+ memcpy(&vport->fabric_portname, &sp->portName,
+ sizeof(struct lpfc_name));
+ memcpy(&vport->fabric_nodename, &sp->nodeName,
+ sizeof(struct lpfc_name));
memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
}
}
- if ((vport->fc_prevDID != vport->fc_myDID) &&
+ if (fabric_param_changed &&
!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
/* If our NportID changed, we need to ensure all
lpfc_unreg_rpi(vport, np);
}
lpfc_cleanup_pending_mbox(vport);
- if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ lpfc_sli4_unreg_all_rpis(vport);
lpfc_mbx_unreg_vpi(vport);
spin_lock_irq(shost->host_lock);
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);
+ /*
+ * If VPI is unreged, driver need to do INIT_VPI
+ * before re-registering
+ */
vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
spin_unlock_irq(shost->host_lock);
}
* Driver needs to re-reg VPI in order for f/w
* to update the MAC address.
*/
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
lpfc_register_new_vport(phba, vport, ndlp);
return 0;
}
if (irsp->ulpStatus) {
/*
- * In case of FIP mode, perform round robin FCF failover
+ * In case of FIP mode, perform roundrobin FCF failover
* due to new FCF discovery
*/
if ((phba->hba_flag & HBA_FIP_SUPPORT) &&
(phba->fcf.fcf_flag & FCF_DISCOVERY) &&
- (irsp->ulpStatus != IOSTAT_LOCAL_REJECT) &&
- (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) {
+ !((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+ (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
- "2611 FLOGI failed on registered "
- "FCF record fcf_index(%d), status: "
- "x%x/x%x, tmo:x%x, trying to perform "
- "round robin failover\n",
+ "2611 FLOGI failed on FCF (x%x), "
+ "status:x%x/x%x, tmo:x%x, perform "
+ "roundrobin FCF failover\n",
phba->fcf.current_rec.fcf_indx,
irsp->ulpStatus, irsp->un.ulpWord[4],
irsp->ulpTimeout);
fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);
- if (fcf_index == LPFC_FCOE_FCF_NEXT_NONE) {
- /*
- * Exhausted the eligible FCF record list,
- * fail through to retry FLOGI on current
- * FCF record.
- */
- lpfc_printf_log(phba, KERN_WARNING,
- LOG_FIP | LOG_ELS,
- "2760 Completed one round "
- "of FLOGI FCF round robin "
- "failover list, retry FLOGI "
- "on currently registered "
- "FCF index:%d\n",
- phba->fcf.current_rec.fcf_indx);
- } else {
- lpfc_printf_log(phba, KERN_INFO,
- LOG_FIP | LOG_ELS,
- "2794 FLOGI FCF round robin "
- "failover to FCF index x%x\n",
- fcf_index);
- rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba,
- fcf_index);
- if (rc)
- lpfc_printf_log(phba, KERN_WARNING,
- LOG_FIP | LOG_ELS,
- "2761 FLOGI round "
- "robin FCF failover "
- "read FCF failed "
- "rc:x%x, fcf_index:"
- "%d\n", rc,
- phba->fcf.current_rec.fcf_indx);
- else
- goto out;
- }
+ rc = lpfc_sli4_fcf_rr_next_proc(vport, fcf_index);
+ if (rc)
+ goto out;
}
/* FLOGI failure */
if (lpfc_els_retry(phba, cmdiocb, rspiocb))
goto out;
+ /* FLOGI failure */
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0100 FLOGI failure Status:x%x/x%x TMO:x%x\n",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout);
+
/* FLOGI failed, so there is no fabric */
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
*/
if (phba->alpa_map[0] == 0) {
vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (!(vport->fc_flag & FC_VFI_REGISTERED) ||
+ (vport->fc_prevDID != vport->fc_myDID))) {
+ if (vport->fc_flag & FC_VFI_REGISTERED)
+ lpfc_sli4_unreg_all_rpis(vport);
+ lpfc_issue_reg_vfi(vport);
+ lpfc_nlp_put(ndlp);
+ goto out;
+ }
}
-
- /* FLOGI failure */
- lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
- "0100 FLOGI failure Status:x%x/x%x TMO:x%x\n",
- irsp->ulpStatus, irsp->un.ulpWord[4],
- irsp->ulpTimeout);
goto flogifail;
}
spin_lock_irq(shost->host_lock);
*/
if (sp->cmn.fPort)
rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
- else if (!(phba->hba_flag & HBA_FCOE_SUPPORT))
+ else if (!(phba->hba_flag & HBA_FCOE_MODE))
rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
else {
lpfc_printf_vlog(vport, KERN_ERR,
lpfc_nlp_put(ndlp);
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+ phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO);
spin_unlock_irq(&phba->hbalock);
goto out;
}
if (phba->hba_flag & HBA_FIP_SUPPORT)
lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP |
LOG_ELS,
- "2769 FLOGI successful on FCF "
- "record: current_fcf_index:"
- "x%x, terminate FCF round "
- "robin failover process\n",
+ "2769 FLOGI to FCF (x%x) "
+ "completed successfully\n",
phba->fcf.current_rec.fcf_indx);
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+ phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO);
spin_unlock_irq(&phba->hbalock);
goto out;
}
sp->cmn.fcphHigh = FC_PH3;
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;
+ if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_0) {
+ 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;
+ } else
+ sp->cmn.request_multiple_Nport = 0;
}
- if (phba->fc_topology != TOPOLOGY_LOOP) {
+ if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) {
icmd->un.elsreq64.myID = 0;
icmd->un.elsreq64.fl = 1;
}
return 0;
}
- if (lpfc_issue_els_flogi(vport, ndlp, 0))
+ if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
/* This decrement of reference count to node shall kick off
* the release of the node.
*/
lpfc_nlp_put(ndlp);
-
+ return 0;
+ }
return 1;
}
uint32_t rc, keepDID = 0;
int put_node;
int put_rport;
+ struct lpfc_node_rrqs rrq;
/* Fabric nodes can have the same WWPN so we don't bother searching
* by WWPN. Just return the ndlp that was given to us.
if (new_ndlp == ndlp && NLP_CHK_NODE_ACT(new_ndlp))
return ndlp;
+ memset(&rrq.xri_bitmap, 0, sizeof(new_ndlp->active_rrqs.xri_bitmap));
if (!new_ndlp) {
rc = memcmp(&ndlp->nlp_portname, name,
if (!new_ndlp)
return ndlp;
keepDID = new_ndlp->nlp_DID;
- } else
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(&rrq.xri_bitmap,
+ &new_ndlp->active_rrqs.xri_bitmap,
+ sizeof(new_ndlp->active_rrqs.xri_bitmap));
+ } else {
keepDID = new_ndlp->nlp_DID;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(&rrq.xri_bitmap,
+ &new_ndlp->active_rrqs.xri_bitmap,
+ sizeof(new_ndlp->active_rrqs.xri_bitmap));
+ }
lpfc_unreg_rpi(vport, new_ndlp);
new_ndlp->nlp_DID = ndlp->nlp_DID;
new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(new_ndlp->active_rrqs.xri_bitmap,
+ &ndlp->active_rrqs.xri_bitmap,
+ sizeof(ndlp->active_rrqs.xri_bitmap));
if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
/* Two ndlps cannot have the same did on the nodelist */
ndlp->nlp_DID = keepDID;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(&ndlp->active_rrqs.xri_bitmap,
+ &rrq.xri_bitmap,
+ sizeof(ndlp->active_rrqs.xri_bitmap));
lpfc_drop_node(vport, ndlp);
}
else {
lpfc_unreg_rpi(vport, ndlp);
/* Two ndlps cannot have the same did */
ndlp->nlp_DID = keepDID;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ memcpy(&ndlp->active_rrqs.xri_bitmap,
+ &rrq.xri_bitmap,
+ sizeof(ndlp->active_rrqs.xri_bitmap));
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
/* Since we are swapping the ndlp passed in with the new one
* and the did has already been swapped, copy over the
}
}
+/**
+ * lpfc_cmpl_els_rrq - Completion handled for els RRQs.
+ * @phba: pointer to lpfc hba data structure.
+ * @cmdiocb: pointer to lpfc command iocb data structure.
+ * @rspiocb: pointer to lpfc response iocb data structure.
+ *
+ * This routine will call the clear rrq function to free the rrq and
+ * clear the xri's bit in the ndlp's xri_bitmap. If the ndlp does not
+ * exist then the clear_rrq is still called because the rrq needs to
+ * be freed.
+ **/
+
+static void
+lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ IOCB_t *irsp;
+ struct lpfc_nodelist *ndlp;
+ struct lpfc_node_rrq *rrq;
+
+ /* we pass cmdiocb to state machine which needs rspiocb as well */
+ rrq = cmdiocb->context_un.rrq;
+ cmdiocb->context_un.rsp_iocb = rspiocb;
+
+ irsp = &rspiocb->iocb;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "RRQ cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->un.elsreq64.remoteID);
+
+ ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || ndlp != rrq->ndlp) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "2882 RRQ completes to NPort x%x "
+ "with no ndlp. Data: x%x x%x x%x\n",
+ irsp->un.elsreq64.remoteID,
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpIoTag);
+ goto out;
+ }
+
+ /* rrq completes to NPort <nlp_DID> */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2880 RRQ completes to NPort x%x "
+ "Data: x%x x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout, rrq->xritag, rrq->rxid);
+
+ if (irsp->ulpStatus) {
+ /* Check for retry */
+ /* RRQ failed Don't print the vport to vport rjts */
+ if (irsp->ulpStatus != IOSTAT_LS_RJT ||
+ (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) &&
+ ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) ||
+ (phba)->pport->cfg_log_verbose & LOG_ELS)
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "2881 RRQ failure DID:%06X Status:x%x/x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
+ }
+out:
+ if (rrq)
+ lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ lpfc_els_free_iocb(phba, cmdiocb);
+ return;
+}
/**
* lpfc_cmpl_els_plogi - Completion callback function for plogi
* @phba: pointer to lpfc hba data structure.
* This routine is the completion callback function for issuing the Port
* Login (PLOGI) command. For PLOGI completion, there must be an active
* ndlp on the vport node list that matches the remote node ID from the
- * PLOGI reponse IOCB. If such ndlp does not exist, the PLOGI is simply
+ * PLOGI response IOCB. If such ndlp does not exist, the PLOGI is simply
* ignored and command IOCB released. The PLOGI response IOCB status is
* checked for error conditons. If there is error status reported, PLOGI
* retry shall be attempted by invoking the lpfc_els_retry() routine.
memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
sp = (struct serv_parm *) pcmd;
+ /*
+ * If we are a N-port connected to a Fabric, fix-up paramm's so logins
+ * to device on remote loops work.
+ */
+ if ((vport->fc_flag & FC_FABRIC) && !(vport->fc_flag & FC_PUBLIC_LOOP))
+ sp->cmn.altBbCredit = 1;
+
if (sp->cmn.fcphLow < FC_PH_4_3)
sp->cmn.fcphLow = FC_PH_4_3;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp;
struct lpfc_sli *psli;
+ struct lpfcMboxq *mbox;
psli = &phba->sli;
/* we pass cmdiocb to state machine which needs rspiocb as well */
NLP_EVT_CMPL_LOGO);
out:
lpfc_els_free_iocb(phba, cmdiocb);
+ /* If we are in pt2pt mode, we could rcv new S_ID on PLOGI */
+ if ((vport->fc_flag & FC_PT2PT) &&
+ !(vport->fc_flag & FC_PT2PT_PLOGI)) {
+ phba->pport->fc_myDID = 0;
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox) {
+ lpfc_config_link(phba, mbox);
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) ==
+ MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
+ }
+ }
return;
}
}
break;
case ELS_CMD_FDISC:
- lpfc_issue_els_fdisc(vport, ndlp, retry);
+ if (!(vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI))
+ lpfc_issue_els_fdisc(vport, ndlp, retry);
break;
}
return;
switch (irsp->ulpStatus) {
case IOSTAT_FCP_RSP_ERROR:
+ break;
case IOSTAT_REMOTE_STOP:
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ /* This IO was aborted by the target, we don't
+ * know the rxid and because we did not send the
+ * ABTS we cannot generate and RRQ.
+ */
+ lpfc_set_rrq_active(phba, ndlp,
+ cmdiocb->sli4_xritag, 0, 0);
+ }
break;
-
case IOSTAT_LOCAL_REJECT:
switch ((irsp->un.ulpWord[4] & 0xff)) {
case IOERR_LOOP_OPEN_FAILURE:
if (cmd == ELS_CMD_FLOGI) {
if (PCI_DEVICE_ID_HORNET ==
phba->pcidev->device) {
- phba->fc_topology = TOPOLOGY_LOOP;
+ phba->fc_topology = LPFC_TOPOLOGY_LOOP;
phba->pport->fc_myDID = 0;
phba->alpa_map[0] = 0;
phba->alpa_map[1] = 0;
retry = 1;
if (((cmd == ELS_CMD_FLOGI) || (cmd == ELS_CMD_FDISC)) &&
- (phba->fc_topology != TOPOLOGY_LOOP) &&
+ (phba->fc_topology != LPFC_TOPOLOGY_LOOP) &&
!lpfc_error_lost_link(irsp)) {
/* FLOGI retry policy */
retry = 1;
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;
+ pmb->context2 = NULL;
+
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool);
}
icmd = &elsiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t);
return 1;
icmd = &elsiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
if (mbox)
return 1;
icmd = &elsiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
icmd = &elsiocb->iocb;
oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
icmd = &elsiocb->iocb;
oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
/* Xmit ADISC ACC response tag <ulpIoTag> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
icmd = &elsiocb->iocb;
oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
+
/* Xmit PRLI ACC response tag <ulpIoTag> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0131 Xmit PRLI ACC response tag x%x xri x%x, "
icmd = &elsiocb->iocb;
oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
+
/* Xmit RNID ACC response tag <ulpIoTag> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0132 Xmit RNID ACC response tag x%x xri x%x\n",
return 0;
}
+/**
+ * lpfc_els_clear_rrq - Clear the rq that this rrq describes.
+ * @vport: pointer to a virtual N_Port data structure.
+ * @iocb: pointer to the lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * Return
+ **/
+static void
+lpfc_els_clear_rrq(struct lpfc_vport *vport,
+ struct lpfc_iocbq *iocb, struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_hba *phba = vport->phba;
+ uint8_t *pcmd;
+ struct RRQ *rrq;
+ uint16_t rxid;
+ uint16_t xri;
+ struct lpfc_node_rrq *prrq;
+
+
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) iocb->context2)->virt);
+ pcmd += sizeof(uint32_t);
+ rrq = (struct RRQ *)pcmd;
+ rrq->rrq_exchg = be32_to_cpu(rrq->rrq_exchg);
+ rxid = bf_get(rrq_rxid, rrq);
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2883 Clear RRQ for SID:x%x OXID:x%x RXID:x%x"
+ " x%x x%x\n",
+ be32_to_cpu(bf_get(rrq_did, rrq)),
+ bf_get(rrq_oxid, rrq),
+ rxid,
+ iocb->iotag, iocb->iocb.ulpContext);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Clear RRQ: did:x%x flg:x%x exchg:x%.08x",
+ ndlp->nlp_DID, ndlp->nlp_flag, rrq->rrq_exchg);
+ if (vport->fc_myDID == be32_to_cpu(bf_get(rrq_did, rrq)))
+ xri = bf_get(rrq_oxid, rrq);
+ else
+ xri = rxid;
+ prrq = lpfc_get_active_rrq(vport, xri, ndlp->nlp_DID);
+ if (prrq)
+ lpfc_clr_rrq_active(phba, xri, prrq);
+ return;
+}
+
+/**
+ * lpfc_els_rsp_echo_acc - Issue echo acc response
+ * @vport: pointer to a virtual N_Port data structure.
+ * @data: pointer to echo data to return in the accept.
+ * @oldiocb: pointer to the original lpfc command iocb data structure.
+ * @ndlp: pointer to a node-list data structure.
+ *
+ * Return code
+ * 0 - Successfully issued acc echo response
+ * 1 - Failed to issue acc echo response
+ **/
+static int
+lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data,
+ struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *elsiocb;
+ struct lpfc_sli *psli;
+ uint8_t *pcmd;
+ uint16_t cmdsize;
+ int rc;
+
+ psli = &phba->sli;
+ cmdsize = oldiocb->iocb.unsli3.rcvsli3.acc_len;
+
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
+ if (!elsiocb)
+ return 1;
+
+ elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext; /* Xri / rx_id */
+ elsiocb->iocb.unsli3.rcvsli3.ox_id = oldiocb->iocb.unsli3.rcvsli3.ox_id;
+
+ /* Xmit ECHO ACC response tag <ulpIoTag> */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2876 Xmit ECHO ACC response tag x%x xri x%x\n",
+ elsiocb->iotag, elsiocb->iocb.ulpContext);
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+ pcmd += sizeof(uint32_t);
+ memcpy(pcmd, data, cmdsize - sizeof(uint32_t));
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC ECHO: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
+ phba->fc_stat.elsXmitACC++;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+ lpfc_nlp_put(ndlp);
+ elsiocb->context1 = NULL; /* Don't need ndlp for cmpl,
+ * it could be freed */
+
+ rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
+ if (rc == IOCB_ERROR) {
+ lpfc_els_free_iocb(phba, elsiocb);
+ return 1;
+ }
+ return 0;
+}
+
/**
* lpfc_els_disc_adisc - Issue remaining adisc iocbs to npr nodes of a vport
* @vport: pointer to a host virtual N_Port data structure.
lpfc_set_disctmo(vport);
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
/* We should never receive a FLOGI in loop mode, ignore it */
did = icmd->un.elsreq64.remoteID;
return 0;
}
+/**
+ * lpfc_els_rcv_echo - Process an unsolicited echo 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.
+ *
+ * Return code
+ * 0 - Successfully processed echo iocb (currently always return 0)
+ **/
+static int
+lpfc_els_rcv_echo(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
+{
+ uint8_t *pcmd;
+
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
+
+ /* skip over first word of echo command to find echo data */
+ pcmd += sizeof(uint32_t);
+
+ lpfc_els_rsp_echo_acc(vport, pcmd, cmdiocb, ndlp);
+ return 0;
+}
+
/**
* lpfc_els_rcv_lirr - Process an unsolicited lirr iocb
* @vport: pointer to a host virtual N_Port data structure.
struct lpfc_nodelist *ndlp)
{
lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
+ if (vport->phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_els_clear_rrq(vport, cmdiocb, ndlp);
}
/**
- * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd
+ * lpfc_els_rsp_rls_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.
*
*
**/
static void
-lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
MAILBOX_t *mb;
IOCB_t *icmd;
- RPS_RSP *rps_rsp;
+ struct RLS_RSP *rls_rsp;
uint8_t *pcmd;
struct lpfc_iocbq *elsiocb;
struct lpfc_nodelist *ndlp;
- uint16_t xri, status;
+ uint16_t oxid;
+ uint16_t rxid;
uint32_t cmdsize;
mb = &pmb->u.mb;
ndlp = (struct lpfc_nodelist *) pmb->context2;
- xri = (uint16_t) ((unsigned long)(pmb->context1));
+ rxid = (uint16_t) ((unsigned long)(pmb->context1) & 0xffff);
+ oxid = (uint16_t) (((unsigned long)(pmb->context1) >> 16) & 0xffff);
pmb->context1 = NULL;
pmb->context2 = NULL;
return;
}
- cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
+ cmdsize = sizeof(struct RLS_RSP) + sizeof(uint32_t);
mempool_free(pmb, phba->mbox_mem_pool);
elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
lpfc_max_els_tries, ndlp,
return;
icmd = &elsiocb->iocb;
- icmd->ulpContext = xri;
+ icmd->ulpContext = rxid;
+ icmd->unsli3.rcvsli3.ox_id = oxid;
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t); /* Skip past command */
- rps_rsp = (RPS_RSP *)pcmd;
+ rls_rsp = (struct RLS_RSP *)pcmd;
- if (phba->fc_topology != TOPOLOGY_LOOP)
- status = 0x10;
- else
- status = 0x8;
- if (phba->pport->fc_flag & FC_FABRIC)
- status |= 0x4;
+ rls_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt);
+ rls_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt);
+ rls_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt);
+ rls_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
+ rls_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
+ rls_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
- rps_rsp->rsvd1 = 0;
- rps_rsp->portStatus = cpu_to_be16(status);
- rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt);
- rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt);
- rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt);
- rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
- rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
- rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
- /* Xmit ELS RPS ACC response tag <ulpIoTag> */
+ /* Xmit ELS RLS ACC response tag <ulpIoTag> */
+ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
+ "2874 Xmit ELS RLS ACC response tag x%x xri x%x, "
+ "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+ elsiocb->iotag, elsiocb->iocb.ulpContext,
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_rpi);
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+ phba->fc_stat.elsXmitACC++;
+ if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR)
+ lpfc_els_free_iocb(phba, elsiocb);
+}
+
+/**
+ * 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.
+ *
+ * This routine is the completion callback function for the MBX_READ_LNK_STAT
+ * mailbox command. This callback function is to actually send the Accept
+ * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It
+ * collects the link statistics from the completion of the MBX_READ_LNK_STAT
+ * mailbox command, constructs the RPS response with the link statistics
+ * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC
+ * response to the RPS.
+ *
+ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp
+ * will be incremented by 1 for holding the ndlp and the reference to ndlp
+ * will be stored into the context1 field of the IOCB for the completion
+ * callback function to the RPS Accept Response ELS IOCB command.
+ *
+ **/
+static void
+lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb;
+ IOCB_t *icmd;
+ RPS_RSP *rps_rsp;
+ uint8_t *pcmd;
+ struct lpfc_iocbq *elsiocb;
+ struct lpfc_nodelist *ndlp;
+ uint16_t status;
+ uint16_t oxid;
+ uint16_t rxid;
+ uint32_t cmdsize;
+
+ mb = &pmb->u.mb;
+
+ ndlp = (struct lpfc_nodelist *) pmb->context2;
+ rxid = (uint16_t) ((unsigned long)(pmb->context1) & 0xffff);
+ oxid = (uint16_t) (((unsigned long)(pmb->context1) >> 16) & 0xffff);
+ pmb->context1 = NULL;
+ pmb->context2 = NULL;
+
+ if (mb->mbxStatus) {
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return;
+ }
+
+ cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
+ mempool_free(pmb, phba->mbox_mem_pool);
+ elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
+ lpfc_max_els_tries, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
+
+ /* Decrement the ndlp reference count from previous mbox command */
+ lpfc_nlp_put(ndlp);
+
+ if (!elsiocb)
+ return;
+
+ icmd = &elsiocb->iocb;
+ icmd->ulpContext = rxid;
+ icmd->unsli3.rcvsli3.ox_id = oxid;
+
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+ pcmd += sizeof(uint32_t); /* Skip past command */
+ rps_rsp = (RPS_RSP *)pcmd;
+
+ if (phba->fc_topology != LPFC_TOPOLOGY_LOOP)
+ status = 0x10;
+ else
+ status = 0x8;
+ if (phba->pport->fc_flag & FC_FABRIC)
+ status |= 0x4;
+
+ rps_rsp->rsvd1 = 0;
+ rps_rsp->portStatus = cpu_to_be16(status);
+ rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt);
+ rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt);
+ rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt);
+ rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
+ rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
+ rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
+ /* Xmit ELS RPS ACC response tag <ulpIoTag> */
lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
"0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
"did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
}
/**
- * lpfc_els_rcv_rps - Process an unsolicited rps iocb
+ * lpfc_els_rcv_rls - Process an unsolicited rls 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 Read Port Status (RPL) IOCB received as an
+ * ELS unsolicited event. It first checks the remote port state. If the
+ * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE
+ * state, it invokes the lpfc_els_rsl_reject() routine to send the reject
+ * response. Otherwise, it issue the MBX_READ_LNK_STAT mailbox command
+ * for reading the HBA link statistics. It is for the callback function,
+ * lpfc_els_rsp_rls_acc(), set to the MBX_READ_LNK_STAT mailbox command
+ * to actually sending out RPL Accept (ACC) response.
+ *
+ * Return codes
+ * 0 - Successfully processed rls iocb (currently always return 0)
+ **/
+static int
+lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mbox;
+ struct lpfc_dmabuf *pcmd;
+ struct ls_rjt stat;
+
+ if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
+ (ndlp->nlp_state != NLP_STE_MAPPED_NODE))
+ /* reject the unsolicited RPS request and done with it */
+ goto reject_out;
+
+ pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
+ if (mbox) {
+ lpfc_read_lnk_stat(phba, mbox);
+ mbox->context1 = (void *)((unsigned long)
+ ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) |
+ cmdiocb->iocb.ulpContext)); /* rx_id */
+ mbox->context2 = lpfc_nlp_get(ndlp);
+ mbox->vport = vport;
+ mbox->mbox_cmpl = lpfc_els_rsp_rls_acc;
+ if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
+ != MBX_NOT_FINISHED)
+ /* Mbox completion will send ELS Response */
+ return 0;
+ /* Decrement reference count used for the failed mbox
+ * command.
+ */
+ lpfc_nlp_put(ndlp);
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
+reject_out:
+ /* issue rejection response */
+ stat.un.b.lsRjtRsvd0 = 0;
+ stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+ stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
+ stat.un.b.vendorUnique = 0;
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
+ return 0;
+}
+
+/**
+ * lpfc_els_rcv_rtv - Process an unsolicited rtv 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 Read Timout Value (RTV) IOCB received as an
+ * ELS unsolicited event. It first checks the remote port state. If the
+ * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE
+ * state, it invokes the lpfc_els_rsl_reject() routine to send the reject
+ * response. Otherwise, it sends the Accept(ACC) response to a Read Timeout
+ * Value (RTV) unsolicited IOCB event.
+ *
+ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp
+ * will be incremented by 1 for holding the ndlp and the reference to ndlp
+ * will be stored into the context1 field of the IOCB for the completion
+ * callback function to the RPS Accept Response ELS IOCB command.
+ *
+ * Return codes
+ * 0 - Successfully processed rtv iocb (currently always return 0)
+ **/
+static int
+lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct ls_rjt stat;
+ struct RTV_RSP *rtv_rsp;
+ uint8_t *pcmd;
+ struct lpfc_iocbq *elsiocb;
+ uint32_t cmdsize;
+
+
+ if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
+ (ndlp->nlp_state != NLP_STE_MAPPED_NODE))
+ /* reject the unsolicited RPS request and done with it */
+ goto reject_out;
+
+ cmdsize = sizeof(struct RTV_RSP) + sizeof(uint32_t);
+ elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
+ lpfc_max_els_tries, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
+
+ if (!elsiocb)
+ return 1;
+
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
+ pcmd += sizeof(uint32_t); /* Skip past command */
+
+ /* use the command's xri in the response */
+ elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext; /* Xri / rx_id */
+ elsiocb->iocb.unsli3.rcvsli3.ox_id = cmdiocb->iocb.unsli3.rcvsli3.ox_id;
+
+ rtv_rsp = (struct RTV_RSP *)pcmd;
+
+ /* populate RTV payload */
+ rtv_rsp->ratov = cpu_to_be32(phba->fc_ratov * 1000); /* report msecs */
+ rtv_rsp->edtov = cpu_to_be32(phba->fc_edtov);
+ bf_set(qtov_edtovres, rtv_rsp, phba->fc_edtovResol ? 1 : 0);
+ bf_set(qtov_rttov, rtv_rsp, 0); /* Field is for FC ONLY */
+ rtv_rsp->qtov = cpu_to_be32(rtv_rsp->qtov);
+
+ /* Xmit ELS RLS ACC response tag <ulpIoTag> */
+ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
+ "2875 Xmit ELS RTV ACC response tag x%x xri x%x, "
+ "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x, "
+ "Data: x%x x%x x%x\n",
+ elsiocb->iotag, elsiocb->iocb.ulpContext,
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_rpi,
+ rtv_rsp->ratov, rtv_rsp->edtov, rtv_rsp->qtov);
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+ phba->fc_stat.elsXmitACC++;
+ if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR)
+ lpfc_els_free_iocb(phba, elsiocb);
+ return 0;
+
+reject_out:
+ /* issue rejection response */
+ stat.un.b.lsRjtRsvd0 = 0;
+ stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+ stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
+ stat.un.b.vendorUnique = 0;
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
+ return 0;
+}
+
+/* lpfc_els_rcv_rps - Process an unsolicited rps 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.
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
if (mbox) {
lpfc_read_lnk_stat(phba, mbox);
- mbox->context1 =
- (void *)((unsigned long) cmdiocb->iocb.ulpContext);
+ mbox->context1 = (void *)((unsigned long)
+ ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) |
+ cmdiocb->iocb.ulpContext)); /* rx_id */
mbox->context2 = lpfc_nlp_get(ndlp);
mbox->vport = vport;
mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
return 0;
}
+/* lpfc_issue_els_rrq - Process an unsolicited rps iocb
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @ndlp: pointer to a node-list data structure.
+ * @did: DID of the target.
+ * @rrq: Pointer to the rrq struct.
+ *
+ * Build a ELS RRQ command and send it to the target. If the issue_iocb is
+ * Successful the the completion handler will clear the RRQ.
+ *
+ * Return codes
+ * 0 - Successfully sent rrq els iocb.
+ * 1 - Failed to send rrq els iocb.
+ **/
+static int
+lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ uint32_t did, struct lpfc_node_rrq *rrq)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct RRQ *els_rrq;
+ IOCB_t *icmd;
+ struct lpfc_iocbq *elsiocb;
+ uint8_t *pcmd;
+ uint16_t cmdsize;
+ int ret;
+
+
+ if (ndlp != rrq->ndlp)
+ ndlp = rrq->ndlp;
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+ return 1;
+
+ /* If ndlp is not NULL, we will bump the reference count on it */
+ cmdsize = (sizeof(uint32_t) + sizeof(struct RRQ));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, did,
+ ELS_CMD_RRQ);
+ if (!elsiocb)
+ return 1;
+
+ icmd = &elsiocb->iocb;
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+
+ /* For RRQ request, remainder of payload is Exchange IDs */
+ *((uint32_t *) (pcmd)) = ELS_CMD_RRQ;
+ pcmd += sizeof(uint32_t);
+ els_rrq = (struct RRQ *) pcmd;
+
+ bf_set(rrq_oxid, els_rrq, rrq->xritag);
+ bf_set(rrq_rxid, els_rrq, rrq->rxid);
+ bf_set(rrq_did, els_rrq, vport->fc_myDID);
+ els_rrq->rrq = cpu_to_be32(els_rrq->rrq);
+ els_rrq->rrq_exchg = cpu_to_be32(els_rrq->rrq_exchg);
+
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue RRQ: did:x%x",
+ did, rrq->xritag, rrq->rxid);
+ elsiocb->context_un.rrq = rrq;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rrq;
+ ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
+
+ if (ret == IOCB_ERROR) {
+ lpfc_els_free_iocb(phba, elsiocb);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * lpfc_send_rrq - Sends ELS RRQ if needed.
+ * @phba: pointer to lpfc hba data structure.
+ * @rrq: pointer to the active rrq.
+ *
+ * This routine will call the lpfc_issue_els_rrq if the rrq is
+ * still active for the xri. If this function returns a failure then
+ * the caller needs to clean up the RRQ by calling lpfc_clr_active_rrq.
+ *
+ * Returns 0 Success.
+ * 1 Failure.
+ **/
+int
+lpfc_send_rrq(struct lpfc_hba *phba, struct lpfc_node_rrq *rrq)
+{
+ struct lpfc_nodelist *ndlp = lpfc_findnode_did(rrq->vport,
+ rrq->nlp_DID);
+ if (lpfc_test_rrq_active(phba, ndlp, rrq->xritag))
+ return lpfc_issue_els_rrq(rrq->vport, ndlp,
+ rrq->nlp_DID, rrq);
+ else
+ return 1;
+}
+
/**
* lpfc_els_rsp_rpl_acc - Issue an accept rpl els command
* @vport: pointer to a host virtual N_Port data structure.
icmd = &elsiocb->iocb;
oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */
+ icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
rpl = (RPL *) (lp + 1);
-
maxsize = be32_to_cpu(rpl->maxsize);
/* We support only one port */
(memcmp(&phba->fc_fabparam.portName, &fp->FportName,
sizeof(struct lpfc_name)))) {
/* This port has switched fabrics. FLOGI is required */
- lpfc_initial_flogi(vport);
+ lpfc_issue_init_vfi(vport);
} else {
/* FAN verified - skip FLOGI */
vport->fc_myDID = vport->fc_prevDID;
if (vport->load_flag & FC_UNLOADING)
goto dropit;
+ /* If NPort discovery is delayed drop incoming ELS */
+ if ((vport->fc_flag & FC_DISC_DELAYED) &&
+ (cmd != ELS_CMD_PLOGI))
+ goto dropit;
+
ndlp = lpfc_findnode_did(vport, did);
if (!ndlp) {
/* Cannot find existing Fabric ndlp, so allocate a new one */
ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp);
lpfc_send_els_event(vport, ndlp, payload);
+
+ /* If Nport discovery is delayed, reject PLOGIs */
+ if (vport->fc_flag & FC_DISC_DELAYED) {
+ rjt_err = LSRJT_UNABLE_TPC;
+ break;
+ }
if (vport->port_state < LPFC_DISC_AUTH) {
if (!(phba->pport->fc_flag & FC_PT2PT) ||
(phba->pport->fc_flag & FC_PT2PT_PLOGI)) {
if (newnode)
lpfc_nlp_put(ndlp);
break;
+ case ELS_CMD_RLS:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RLS: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
+ phba->fc_stat.elsRcvRLS++;
+ lpfc_els_rcv_rls(vport, elsiocb, ndlp);
+ if (newnode)
+ lpfc_nlp_put(ndlp);
+ break;
case ELS_CMD_RPS:
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
"RCV RPS: did:x%x/ste:x%x flg:x%x",
if (newnode)
lpfc_nlp_put(ndlp);
break;
+ case ELS_CMD_RTV:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RTV: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+ phba->fc_stat.elsRcvRTV++;
+ lpfc_els_rcv_rtv(vport, elsiocb, ndlp);
+ 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",
if (newnode)
lpfc_nlp_put(ndlp);
break;
+ case ELS_CMD_ECHO:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV ECHO: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
+ phba->fc_stat.elsRcvECHO++;
+ lpfc_els_rcv_echo(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",
cmd, did, vport->port_state);
/* Unsupported ELS command, reject */
- rjt_err = LSRJT_INVALID_CMD;
+ rjt_err = LSRJT_CMD_UNSUPPORTED;
/* Unknown ELS command <elsCmd> received from NPORT <did> */
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
{
struct lpfc_vport *vport;
unsigned long flags;
+ int i = 0;
+
+ /* The physical ports are always vpi 0 - translate is unnecessary. */
+ if (vpi > 0) {
+ /*
+ * Translate the physical vpi to the logical vpi. The
+ * vport stores the logical vpi.
+ */
+ for (i = 0; i < phba->max_vpi; i++) {
+ if (vpi == phba->vpi_ids[i])
+ break;
+ }
+
+ if (i >= phba->max_vpi) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "2936 Could not find Vport mapped "
+ "to vpi %d\n", vpi);
+ return NULL;
+ }
+ }
spin_lock_irqsave(&phba->hbalock, flags);
list_for_each_entry(vport, &phba->port_list, listentry) {
- if (vport->vpi == vpi) {
+ if (vport->vpi == i) {
spin_unlock_irqrestore(&phba->hbalock, flags);
return vport;
}
vport = phba->pport;
else
vport = lpfc_find_vport_by_vpid(phba,
- icmd->unsli3.rcvsli3.vpi - phba->vpi_base);
+ icmd->unsli3.rcvsli3.vpi);
}
+
/* If there are no BDEs associated
* with this IOCB, there is nothing to do.
*/
lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp, *ndlp_fdmi;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ /*
+ * If lpfc_delay_discovery parameter is set and the clean address
+ * bit is cleared and fc fabric parameters chenged, delay FC NPort
+ * discovery.
+ */
+ spin_lock_irq(shost->host_lock);
+ if (vport->fc_flag & FC_DISC_DELAYED) {
+ spin_unlock_irq(shost->host_lock);
+ mod_timer(&vport->delayed_disc_tmo,
+ jiffies + HZ * phba->fc_ratov);
+ return;
+ }
+ spin_unlock_irq(shost->host_lock);
ndlp = lpfc_findnode_did(vport, NameServer_DID);
if (!ndlp) {
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp) {
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
lpfc_disc_start(vport);
return;
}
} else if (!NLP_CHK_NODE_ACT(ndlp)) {
ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE);
if (!ndlp) {
- if (phba->fc_topology == TOPOLOGY_LOOP) {
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
lpfc_disc_start(vport);
return;
}
}
if (vport->cfg_fdmi_on) {
- ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
- GFP_KERNEL);
+ /* If this is the first time, allocate an ndlp and initialize
+ * it. Otherwise, make sure the node is enabled and then do the
+ * login.
+ */
+ ndlp_fdmi = lpfc_findnode_did(vport, FDMI_DID);
+ if (!ndlp_fdmi) {
+ ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
+ GFP_KERNEL);
+ if (ndlp_fdmi) {
+ lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
+ ndlp_fdmi->nlp_type |= NLP_FABRIC;
+ } else
+ return;
+ }
+ if (!NLP_CHK_NODE_ACT(ndlp_fdmi))
+ ndlp_fdmi = lpfc_enable_node(vport,
+ ndlp_fdmi,
+ NLP_STE_NPR_NODE);
+
if (ndlp_fdmi) {
- lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
- ndlp_fdmi->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp_fdmi,
- NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID,
- 0);
+ NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0);
}
}
- return;
}
/**
default:
/* Try to recover from this error */
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_unreg_all_rpis(vport);
lpfc_mbx_unreg_vpi(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
spin_unlock_irq(shost->host_lock);
if (vport->port_type == LPFC_PHYSICAL_PORT
&& !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))
- lpfc_initial_flogi(vport);
+ lpfc_issue_init_vfi(vport);
else
lpfc_initial_fdisc(vport);
break;
struct lpfc_nodelist *next_np;
IOCB_t *irsp = &rspiocb->iocb;
struct lpfc_iocbq *piocb;
+ struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
+ struct serv_parm *sp;
+ uint8_t fabric_param_changed;
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0123 FDISC completes. x%x/x%x prevDID: x%x\n",
vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
vport->fc_flag &= ~FC_VPORT_LOGO_RCVD;
vport->fc_flag |= FC_FABRIC;
- if (vport->phba->fc_topology == TOPOLOGY_LOOP)
+ if (vport->phba->fc_topology == LPFC_TOPOLOGY_LOOP)
vport->fc_flag |= FC_PUBLIC_LOOP;
spin_unlock_irq(shost->host_lock);
vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
lpfc_vport_set_state(vport, FC_VPORT_ACTIVE);
- if ((vport->fc_prevDID != vport->fc_myDID) &&
+ prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
+ sp = prsp->virt + sizeof(uint32_t);
+ fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp);
+ memcpy(&vport->fabric_portname, &sp->portName,
+ sizeof(struct lpfc_name));
+ memcpy(&vport->fabric_nodename, &sp->nodeName,
+ sizeof(struct lpfc_name));
+ if (fabric_param_changed &&
!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
/* If our NportID changed, we need to ensure all
* remaining NPORTs get unreg_login'ed so we can
lpfc_unreg_rpi(vport, np);
}
lpfc_cleanup_pending_mbox(vport);
+
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_unreg_all_rpis(vport);
+
lpfc_mbx_unreg_vpi(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
* to update the MAC address.
*/
lpfc_register_new_vport(phba, vport, ndlp);
- return ;
+ goto out;
}
if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI)
icmd->un.elsreq64.myID = 0;
icmd->un.elsreq64.fl = 1;
- if (phba->sli_rev == LPFC_SLI_REV4) {
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+ LPFC_SLI_INTF_IF_TYPE_0)) {
/* 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;
+ elsiocb->iocb.ulpContext = phba->vpi_ids[vport->vpi];
} else {
/* For FDISC, Let FDISC rsp set the NPortID for this VPI */
icmd->ulpCt_h = 1;
struct lpfc_vport *vport = cmdiocb->vport;
IOCB_t *irsp;
struct lpfc_nodelist *ndlp;
- ndlp = (struct lpfc_nodelist *)cmdiocb->context1;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ ndlp = (struct lpfc_nodelist *)cmdiocb->context1;
irsp = &rspiocb->iocb;
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
"LOGO npiv cmpl: status:x%x/x%x did:x%x",
/* Trigger the release of the ndlp after logo */
lpfc_nlp_put(ndlp);
+
+ /* NPIV LOGO completes to NPort <nlp_DID> */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2928 NPIV LOGO completes to NPort x%x "
+ "Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout, vport->num_disc_nodes);
+
+ if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_FABRIC;
+ spin_unlock_irq(shost->host_lock);
+ }
}
/**
IOERR_SLI_ABORTED);
}
+/**
+ * lpfc_sli4_vport_delete_els_xri_aborted -Remove all ndlp references for vport
+ * @vport: pointer to lpfc vport data structure.
+ *
+ * This routine is invoked by the vport cleanup for deletions and the cleanup
+ * for an ndlp on removal.
+ **/
+void
+lpfc_sli4_vport_delete_els_xri_aborted(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
+ unsigned long iflag = 0;
+
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ spin_lock(&phba->sli4_hba.abts_sgl_list_lock);
+ list_for_each_entry_safe(sglq_entry, sglq_next,
+ &phba->sli4_hba.lpfc_abts_els_sgl_list, list) {
+ if (sglq_entry->ndlp && sglq_entry->ndlp->vport == vport)
+ sglq_entry->ndlp = NULL;
+ }
+ spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ return;
+}
+
/**
* lpfc_sli4_els_xri_aborted - Slow-path process of els xri abort
* @phba: pointer to lpfc hba data structure.
struct sli4_wcqe_xri_aborted *axri)
{
uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
+ uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri);
+ uint16_t lxri = 0;
+
struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
unsigned long iflag = 0;
+ struct lpfc_nodelist *ndlp;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irqsave(&phba->hbalock, iflag);
&phba->sli4_hba.lpfc_abts_els_sgl_list, list) {
if (sglq_entry->sli4_xritag == xri) {
list_del(&sglq_entry->list);
+ ndlp = sglq_entry->ndlp;
+ sglq_entry->ndlp = NULL;
list_add_tail(&sglq_entry->list,
&phba->sli4_hba.lpfc_sgl_list);
sglq_entry->state = SGL_FREED;
spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
+ lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1);
/* Check if TXQ queue needs to be serviced */
if (pring->txq_cnt)
}
}
spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
- sglq_entry = __lpfc_get_active_sglq(phba, xri);
+ lxri = lpfc_sli4_xri_inrange(phba, xri);
+ if (lxri == NO_XRI) {
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ return;
+ }
+ sglq_entry = __lpfc_get_active_sglq(phba, lxri);
if (!sglq_entry || (sglq_entry->sli4_xritag != xri)) {
spin_unlock_irqrestore(&phba->hbalock, iflag);
return;