|
@@ -1,7 +1,7 @@
|
|
|
/*******************************************************************
|
|
|
* 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 *
|
|
@@ -484,6 +484,59 @@ fail:
|
|
|
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.
|
|
@@ -512,6 +565,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|
|
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;
|
|
@@ -544,6 +598,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|
|
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) {
|
|
@@ -565,7 +625,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- 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
|
|
@@ -2203,6 +2263,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
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 */
|
|
@@ -2260,6 +2321,21 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
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;
|
|
|
}
|
|
|
|
|
@@ -6181,6 +6257,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
|
|
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 */
|
|
@@ -6233,6 +6314,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
|
|
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)) {
|
|
@@ -6611,6 +6698,21 @@ void
|
|
|
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) {
|
|
@@ -6953,6 +7055,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
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",
|
|
@@ -6996,7 +7101,14 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
|
|
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
|