Commit 1a145558 authored by James Smart's avatar James Smart Committed by Greg Kroah-Hartman

lpfc: Fix the FLOGI discovery logic to comply with T11 standards

[ Upstream commit d6de08cc ]

Fix the FLOGI discovery logic to comply with T11 standards

We weren't properly setting fabric parameters, such as R_A_TOV and E_D_TOV,
when we registered the vfi object in default configs and pt2pt configs.
Revise to now pass service params with the values to the firmware and
ensure they are reset on link bounce. Required reworking the call sequence
in the discovery threads.
Signed-off-by: default avatarDick Kennedy <dick.kennedy@avagotech.com>
Signed-off-by: default avatarJames Smart <james.smart@avagotech.com>
Reviewed-by: default avatarHannes Reinicke <hare@suse.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3f499a42
...@@ -72,6 +72,7 @@ void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *); ...@@ -72,6 +72,7 @@ void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
void lpfc_retry_pport_discovery(struct lpfc_hba *); void lpfc_retry_pport_discovery(struct lpfc_hba *);
void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t); void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);
void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
......
...@@ -455,9 +455,9 @@ int ...@@ -455,9 +455,9 @@ int
lpfc_issue_reg_vfi(struct lpfc_vport *vport) lpfc_issue_reg_vfi(struct lpfc_vport *vport)
{ {
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *mboxq; LPFC_MBOXQ_t *mboxq = NULL;
struct lpfc_nodelist *ndlp; struct lpfc_nodelist *ndlp;
struct lpfc_dmabuf *dmabuf; struct lpfc_dmabuf *dmabuf = NULL;
int rc = 0; int rc = 0;
/* move forward in case of SLI4 FC port loopback test and pt2pt mode */ /* move forward in case of SLI4 FC port loopback test and pt2pt mode */
...@@ -471,25 +471,33 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) ...@@ -471,25 +471,33 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
} }
} }
dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!dmabuf) { if (!mboxq) {
rc = -ENOMEM; rc = -ENOMEM;
goto fail; 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); /* Supply CSP's only if we are fabric connect or pt-to-pt connect */
if (!mboxq) { if ((vport->fc_flag & FC_FABRIC) || (vport->fc_flag & FC_PT2PT)) {
rc = -ENOMEM; dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
goto fail_free_coherent; if (!dmabuf) {
rc = -ENOMEM;
goto fail;
}
dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
if (!dmabuf->virt) {
rc = -ENOMEM;
goto fail;
}
memcpy(dmabuf->virt, &phba->fc_fabparam,
sizeof(struct serv_parm));
} }
vport->port_state = LPFC_FABRIC_CFG_LINK; vport->port_state = LPFC_FABRIC_CFG_LINK;
memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam)); if (dmabuf)
lpfc_reg_vfi(mboxq, vport, dmabuf->phys); lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
else
lpfc_reg_vfi(mboxq, vport, 0);
mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi; mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
mboxq->vport = vport; mboxq->vport = vport;
...@@ -497,17 +505,19 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) ...@@ -497,17 +505,19 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) { if (rc == MBX_NOT_FINISHED) {
rc = -ENXIO; rc = -ENXIO;
goto fail_free_mbox; goto fail;
} }
return 0; 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: fail:
if (mboxq)
mempool_free(mboxq, phba->mbox_mem_pool);
if (dmabuf) {
if (dmabuf->virt)
lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
kfree(dmabuf);
}
lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_vport_set_state(vport, FC_VPORT_FAILED);
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"0289 Issue Register VFI failed: Err %d\n", rc); "0289 Issue Register VFI failed: Err %d\n", rc);
...@@ -711,9 +721,10 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -711,9 +721,10 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
* For FC we need to do some special processing because of the SLI * For FC we need to do some special processing because of the SLI
* Port's default settings of the Common Service Parameters. * Port's default settings of the Common Service Parameters.
*/ */
if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) { if ((phba->sli_rev == LPFC_SLI_REV4) &&
(phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC)) {
/* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */ /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
if ((phba->sli_rev == LPFC_SLI_REV4) && fabric_param_changed) if (fabric_param_changed)
lpfc_unregister_fcf_prep(phba); lpfc_unregister_fcf_prep(phba);
/* This should just update the VFI CSPs*/ /* This should just update the VFI CSPs*/
...@@ -824,13 +835,21 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -824,13 +835,21 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
vport->fc_flag |= FC_PT2PT;
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
phba->fc_edtov = FF_DEF_EDTOV; /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
phba->fc_ratov = FF_DEF_RATOV; if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
lpfc_unregister_fcf_prep(phba);
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~FC_VFI_REGISTERED;
spin_unlock_irq(shost->host_lock);
phba->fc_topology_changed = 0;
}
rc = memcmp(&vport->fc_portname, &sp->portName, rc = memcmp(&vport->fc_portname, &sp->portName,
sizeof(vport->fc_portname)); sizeof(vport->fc_portname));
memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
if (rc >= 0) { if (rc >= 0) {
/* This side will initiate the PLOGI */ /* This side will initiate the PLOGI */
...@@ -839,38 +858,14 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -839,38 +858,14 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
/* /*
* N_Port ID cannot be 0, set our to LocalID the other * N_Port ID cannot be 0, set our Id to LocalID
* side will be RemoteID. * the other side will be RemoteID.
*/ */
/* not equal */ /* not equal */
if (rc) if (rc)
vport->fc_myDID = PT2PT_LocalID; vport->fc_myDID = PT2PT_LocalID;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
goto fail;
lpfc_config_link(phba, mbox);
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
mbox->vport = vport;
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
mempool_free(mbox, phba->mbox_mem_pool);
goto fail;
}
/*
* For SLI4, the VFI/VPI are registered AFTER the
* Nport with the higher WWPN sends the PLOGI with
* an assigned NPortId.
*/
/* not equal */
if ((phba->sli_rev == LPFC_SLI_REV4) && rc)
lpfc_issue_reg_vfi(vport);
/* Decrement ndlp reference count indicating that ndlp can be /* Decrement ndlp reference count indicating that ndlp can be
* safely released when other references to it are done. * safely released when other references to it are done.
*/ */
...@@ -912,29 +907,20 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -912,29 +907,20 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* If we are pt2pt with another NPort, force NPIV off! */ /* If we are pt2pt with another NPort, force NPIV off! */
phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
spin_lock_irq(shost->host_lock); mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
vport->fc_flag |= FC_PT2PT; if (!mbox)
spin_unlock_irq(shost->host_lock); goto fail;
/* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
lpfc_unregister_fcf_prep(phba);
/* The FC_VFI_REGISTERED flag will get clear in the cmpl lpfc_config_link(phba, mbox);
* handler for unreg_vfi, but if we don't force the
* FC_VFI_REGISTERED flag then the reg_vfi mailbox could be mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
* built with the update bit set instead of just the vp bit to mbox->vport = vport;
* change the Nport ID. We need to have the vp set and the rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
* Upd cleared on topology changes. if (rc == MBX_NOT_FINISHED) {
*/ mempool_free(mbox, phba->mbox_mem_pool);
spin_lock_irq(shost->host_lock); goto fail;
vport->fc_flag &= ~FC_VFI_REGISTERED;
spin_unlock_irq(shost->host_lock);
phba->fc_topology_changed = 0;
lpfc_issue_reg_vfi(vport);
} }
/* Start discovery - this should just do CLEAR_LA */
lpfc_disc_start(vport);
return 0; return 0;
fail: fail:
return -ENXIO; return -ENXIO;
...@@ -1157,6 +1143,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ...@@ -1157,6 +1143,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
spin_lock_irq(&phba->hbalock); spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_DISCOVERY; phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
spin_unlock_irq(&phba->hbalock); spin_unlock_irq(&phba->hbalock);
lpfc_nlp_put(ndlp); lpfc_nlp_put(ndlp);
if (!lpfc_error_lost_link(irsp)) { if (!lpfc_error_lost_link(irsp)) {
...@@ -3898,6 +3885,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, ...@@ -3898,6 +3885,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
IOCB_t *oldcmd; IOCB_t *oldcmd;
struct lpfc_iocbq *elsiocb; struct lpfc_iocbq *elsiocb;
uint8_t *pcmd; uint8_t *pcmd;
struct serv_parm *sp;
uint16_t cmdsize; uint16_t cmdsize;
int rc; int rc;
ELS_PKT *els_pkt_ptr; ELS_PKT *els_pkt_ptr;
...@@ -3927,6 +3915,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, ...@@ -3927,6 +3915,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
"Issue ACC: did:x%x flg:x%x", "Issue ACC: did:x%x flg:x%x",
ndlp->nlp_DID, ndlp->nlp_flag, 0); ndlp->nlp_DID, ndlp->nlp_flag, 0);
break; break;
case ELS_CMD_FLOGI:
case ELS_CMD_PLOGI: case ELS_CMD_PLOGI:
cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t)); cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
...@@ -3944,10 +3933,34 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, ...@@ -3944,10 +3933,34 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
*((uint32_t *) (pcmd)) = ELS_CMD_ACC; *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t); pcmd += sizeof(uint32_t);
memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm)); sp = (struct serv_parm *)pcmd;
if (flag == ELS_CMD_FLOGI) {
/* Copy the received service parameters back */
memcpy(sp, &phba->fc_fabparam,
sizeof(struct serv_parm));
/* Clear the F_Port bit */
sp->cmn.fPort = 0;
/* Mark all class service parameters as invalid */
sp->cls1.classValid = 0;
sp->cls2.classValid = 0;
sp->cls3.classValid = 0;
sp->cls4.classValid = 0;
/* Copy our worldwide names */
memcpy(&sp->portName, &vport->fc_sparam.portName,
sizeof(struct lpfc_name));
memcpy(&sp->nodeName, &vport->fc_sparam.nodeName,
sizeof(struct lpfc_name));
} else {
memcpy(pcmd, &vport->fc_sparam,
sizeof(struct serv_parm));
}
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
"Issue ACC PLOGI: did:x%x flg:x%x", "Issue ACC FLOGI/PLOGI: did:x%x flg:x%x",
ndlp->nlp_DID, ndlp->nlp_flag, 0); ndlp->nlp_DID, ndlp->nlp_flag, 0);
break; break;
case ELS_CMD_PRLO: case ELS_CMD_PRLO:
...@@ -5739,7 +5752,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, ...@@ -5739,7 +5752,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
IOCB_t *icmd = &cmdiocb->iocb; IOCB_t *icmd = &cmdiocb->iocb;
struct serv_parm *sp; struct serv_parm *sp;
LPFC_MBOXQ_t *mbox; LPFC_MBOXQ_t *mbox;
struct ls_rjt stat;
uint32_t cmd, did; uint32_t cmd, did;
int rc; int rc;
uint32_t fc_flag = 0; uint32_t fc_flag = 0;
...@@ -5765,135 +5777,92 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, ...@@ -5765,135 +5777,92 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
return 1; return 1;
} }
if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) { (void) 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.
*/
rc = memcmp(&vport->fc_portname, &sp->portName,
sizeof(struct lpfc_name));
if (!rc) { /*
if (phba->sli_rev < LPFC_SLI_REV4) { * If our portname is greater than the remote portname,
mbox = mempool_alloc(phba->mbox_mem_pool, * then we initiate Nport login.
GFP_KERNEL); */
if (!mbox)
return 1;
lpfc_linkdown(phba);
lpfc_init_link(phba, mbox,
phba->cfg_topology,
phba->cfg_link_speed);
mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
mbox->vport = vport;
rc = lpfc_sli_issue_mbox(phba, mbox,
MBX_NOWAIT);
lpfc_set_loopback_flag(phba);
if (rc == MBX_NOT_FINISHED)
mempool_free(mbox, phba->mbox_mem_pool);
return 1;
} else {
/* abort the flogi coming back to ourselves
* due to external loopback on the port.
*/
lpfc_els_abort_flogi(phba);
return 0;
}
} else if (rc > 0) { /* greater than */
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_PT2PT_PLOGI;
spin_unlock_irq(shost->host_lock);
/* If we have the high WWPN we can assign our own rc = memcmp(&vport->fc_portname, &sp->portName,
* myDID; otherwise, we have to WAIT for a PLOGI sizeof(struct lpfc_name));
* from the remote NPort to find out what it
* will be.
*/
vport->fc_myDID = PT2PT_LocalID;
} else
vport->fc_myDID = PT2PT_RemoteID;
/* if (!rc) {
* The vport state should go to LPFC_FLOGI only if (phba->sli_rev < LPFC_SLI_REV4) {
* AFTER we issue a FLOGI, not receive one. mbox = mempool_alloc(phba->mbox_mem_pool,
GFP_KERNEL);
if (!mbox)
return 1;
lpfc_linkdown(phba);
lpfc_init_link(phba, mbox,
phba->cfg_topology,
phba->cfg_link_speed);
mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
mbox->vport = vport;
rc = lpfc_sli_issue_mbox(phba, mbox,
MBX_NOWAIT);
lpfc_set_loopback_flag(phba);
if (rc == MBX_NOT_FINISHED)
mempool_free(mbox, phba->mbox_mem_pool);
return 1;
}
/* abort the flogi coming back to ourselves
* due to external loopback on the port.
*/ */
lpfc_els_abort_flogi(phba);
return 0;
} else if (rc > 0) { /* greater than */
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
fc_flag = vport->fc_flag; vport->fc_flag |= FC_PT2PT_PLOGI;
port_state = vport->port_state;
vport->fc_flag |= FC_PT2PT;
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"3311 Rcv Flogi PS x%x new PS x%x "
"fc_flag x%x new fc_flag x%x\n",
port_state, vport->port_state,
fc_flag, vport->fc_flag);
/* /* If we have the high WWPN we can assign our own
* We temporarily set fc_myDID to make it look like we are * myDID; otherwise, we have to WAIT for a PLOGI
* a Fabric. This is done just so we end up with the right * from the remote NPort to find out what it
* did / sid on the FLOGI ACC rsp. * will be.
*/ */
did = vport->fc_myDID; vport->fc_myDID = PT2PT_LocalID;
vport->fc_myDID = Fabric_DID;
} else { } else {
/* Reject this request because invalid parameters */ vport->fc_myDID = PT2PT_RemoteID;
stat.un.b.lsRjtRsvd0 = 0; }
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
stat.un.b.vendorUnique = 0;
/*
* We temporarily set fc_myDID to make it look like we are
* a Fabric. This is done just so we end up with the right
* did / sid on the FLOGI LS_RJT rsp.
*/
did = vport->fc_myDID;
vport->fc_myDID = Fabric_DID;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
NULL);
/* Now lets put fc_myDID back to what its supposed to be */ /*
vport->fc_myDID = did; * The vport state should go to LPFC_FLOGI only
* AFTER we issue a FLOGI, not receive one.
*/
spin_lock_irq(shost->host_lock);
fc_flag = vport->fc_flag;
port_state = vport->port_state;
vport->fc_flag |= FC_PT2PT;
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
spin_unlock_irq(shost->host_lock);
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"3311 Rcv Flogi PS x%x new PS x%x "
"fc_flag x%x new fc_flag x%x\n",
port_state, vport->port_state,
fc_flag, vport->fc_flag);
return 1; /*
} * We temporarily set fc_myDID to make it look like we are
* a Fabric. This is done just so we end up with the right
* did / sid on the FLOGI ACC rsp.
*/
did = vport->fc_myDID;
vport->fc_myDID = Fabric_DID;
/* send our FLOGI first */ memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
if (vport->port_state < LPFC_FLOGI) {
vport->fc_myDID = 0;
lpfc_initial_flogi(vport);
vport->fc_myDID = Fabric_DID;
}
/* Send back ACC */ /* Send back ACC */
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, cmdiocb, ndlp, NULL);
/* Now lets put fc_myDID back to what its supposed to be */ /* Now lets put fc_myDID back to what its supposed to be */
vport->fc_myDID = did; vport->fc_myDID = did;
if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
goto fail;
lpfc_config_link(phba, mbox);
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
mbox->vport = vport;
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
mempool_free(mbox, phba->mbox_mem_pool);
goto fail;
}
}
return 0; return 0;
fail:
return 1;
} }
/** /**
...@@ -7345,7 +7314,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ...@@ -7345,7 +7314,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/* reject till our FLOGI completes */ /* reject till our FLOGI completes */
if ((vport->port_state < LPFC_FABRIC_CFG_LINK) && if ((vport->port_state < LPFC_FABRIC_CFG_LINK) &&
(cmd != ELS_CMD_FLOGI)) { (cmd != ELS_CMD_FLOGI)) {
rjt_err = LSRJT_UNABLE_TPC; rjt_err = LSRJT_UNABLE_TPC;
rjt_exp = LSEXP_NOTHING_MORE; rjt_exp = LSEXP_NOTHING_MORE;
goto lsrjt; goto lsrjt;
...@@ -7381,6 +7350,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ...@@ -7381,6 +7350,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
rjt_exp = LSEXP_NOTHING_MORE; rjt_exp = LSEXP_NOTHING_MORE;
break; break;
} }
if (vport->port_state < LPFC_DISC_AUTH) { if (vport->port_state < LPFC_DISC_AUTH) {
if (!(phba->pport->fc_flag & FC_PT2PT) || if (!(phba->pport->fc_flag & FC_PT2PT) ||
(phba->pport->fc_flag & FC_PT2PT_PLOGI)) { (phba->pport->fc_flag & FC_PT2PT_PLOGI)) {
......
...@@ -1083,7 +1083,7 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ...@@ -1083,7 +1083,7 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
} }
static void void
lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{ {
struct lpfc_vport *vport = pmb->vport; struct lpfc_vport *vport = pmb->vport;
...@@ -1113,8 +1113,10 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ...@@ -1113,8 +1113,10 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Start discovery by sending a FLOGI. port_state is identically /* Start discovery by sending a FLOGI. port_state is identically
* LPFC_FLOGI while waiting for FLOGI cmpl * LPFC_FLOGI while waiting for FLOGI cmpl
*/ */
if (vport->port_state != LPFC_FLOGI || vport->fc_flag & FC_PT2PT_PLOGI) if (vport->port_state != LPFC_FLOGI)
lpfc_initial_flogi(vport); lpfc_initial_flogi(vport);
else if (vport->fc_flag & FC_PT2PT)
lpfc_disc_start(vport);
return; return;
out: out:
...@@ -2963,8 +2965,10 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) ...@@ -2963,8 +2965,10 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
out_free_mem: out_free_mem:
mempool_free(mboxq, phba->mbox_mem_pool); mempool_free(mboxq, phba->mbox_mem_pool);
lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); if (dmabuf) {
kfree(dmabuf); lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
kfree(dmabuf);
}
return; return;
} }
......
...@@ -280,38 +280,12 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -280,38 +280,12 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint32_t *lp; uint32_t *lp;
IOCB_t *icmd; IOCB_t *icmd;
struct serv_parm *sp; struct serv_parm *sp;
uint32_t ed_tov;
LPFC_MBOXQ_t *mbox; LPFC_MBOXQ_t *mbox;
struct ls_rjt stat; struct ls_rjt stat;
int rc; int rc;
memset(&stat, 0, sizeof (struct ls_rjt)); memset(&stat, 0, sizeof (struct ls_rjt));
if (vport->port_state <= LPFC_FDISC) {
/* Before responding to PLOGI, check for pt2pt mode.
* If we are pt2pt, with an outstanding FLOGI, abort
* the FLOGI and resend it first.
*/
if (vport->fc_flag & FC_PT2PT) {
lpfc_els_abort_flogi(phba);
if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
/* If the other side is supposed to initiate
* the PLOGI anyway, just ACC it now and
* move on with discovery.
*/
phba->fc_edtov = FF_DEF_EDTOV;
phba->fc_ratov = FF_DEF_RATOV;
/* Start discovery - this should just do
CLEAR_LA */
lpfc_disc_start(vport);
} else
lpfc_initial_flogi(vport);
} else {
stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
ndlp, NULL);
return 0;
}
}
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt; lp = (uint32_t *) pcmd->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
...@@ -404,30 +378,46 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -404,30 +378,46 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* Check for Nport to NPort pt2pt protocol */ /* Check for Nport to NPort pt2pt protocol */
if ((vport->fc_flag & FC_PT2PT) && if ((vport->fc_flag & FC_PT2PT) &&
!(vport->fc_flag & FC_PT2PT_PLOGI)) { !(vport->fc_flag & FC_PT2PT_PLOGI)) {
/* rcv'ed PLOGI decides what our NPortId will be */ /* rcv'ed PLOGI decides what our NPortId will be */
vport->fc_myDID = icmd->un.rcvels.parmRo; vport->fc_myDID = icmd->un.rcvels.parmRo;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (mbox == NULL) ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
goto out; if (sp->cmn.edtovResolution) {
lpfc_config_link(phba, mbox); /* E_D_TOV ticks are in nanoseconds */
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; ed_tov = (phba->fc_edtov + 999999) / 1000000;
mbox->vport = vport;
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
mempool_free(mbox, phba->mbox_mem_pool);
goto out;
} }
/* /*
* For SLI4, the VFI/VPI are registered AFTER the * For pt-to-pt, use the larger EDTOV
* Nport with the higher WWPN sends us a PLOGI with * RATOV = 2 * EDTOV
* our assigned NPortId.
*/ */
if (ed_tov > phba->fc_edtov)
phba->fc_edtov = ed_tov;
phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
/* Issue config_link / reg_vfi to account for updated TOV's */
if (phba->sli_rev == LPFC_SLI_REV4) if (phba->sli_rev == LPFC_SLI_REV4)
lpfc_issue_reg_vfi(vport); lpfc_issue_reg_vfi(vport);
else {
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (mbox == NULL)
goto out;
lpfc_config_link(phba, mbox);
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
mbox->vport = vport;
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
mempool_free(mbox, phba->mbox_mem_pool);
goto out;
}
}
lpfc_can_disctmo(vport); lpfc_can_disctmo(vport);
} }
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox) if (!mbox)
goto out; goto out;
...@@ -1038,7 +1028,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ...@@ -1038,7 +1028,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
uint32_t *lp; uint32_t *lp;
IOCB_t *irsp; IOCB_t *irsp;
struct serv_parm *sp; struct serv_parm *sp;
uint32_t ed_tov;
LPFC_MBOXQ_t *mbox; LPFC_MBOXQ_t *mbox;
int rc;
cmdiocb = (struct lpfc_iocbq *) arg; cmdiocb = (struct lpfc_iocbq *) arg;
rspiocb = cmdiocb->context_un.rsp_iocb; rspiocb = cmdiocb->context_un.rsp_iocb;
...@@ -1053,6 +1045,16 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ...@@ -1053,6 +1045,16 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
if (irsp->ulpStatus) if (irsp->ulpStatus)
goto out; goto out;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"0133 PLOGI: no memory for reg_login "
"Data: x%x x%x x%x x%x\n",
ndlp->nlp_DID, ndlp->nlp_state,
ndlp->nlp_flag, ndlp->nlp_rpi);
goto out;
}
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
...@@ -1094,14 +1096,38 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ...@@ -1094,14 +1096,38 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
ndlp->nlp_maxframe = ndlp->nlp_maxframe =
((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if ((vport->fc_flag & FC_PT2PT) &&
if (!mbox) { (vport->fc_flag & FC_PT2PT_PLOGI)) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
"0133 PLOGI: no memory for reg_login " if (sp->cmn.edtovResolution) {
"Data: x%x x%x x%x x%x\n", /* E_D_TOV ticks are in nanoseconds */
ndlp->nlp_DID, ndlp->nlp_state, ed_tov = (phba->fc_edtov + 999999) / 1000000;
ndlp->nlp_flag, ndlp->nlp_rpi); }
goto out;
/*
* Use the larger EDTOV
* RATOV = 2 * EDTOV for pt-to-pt
*/
if (ed_tov > phba->fc_edtov)
phba->fc_edtov = ed_tov;
phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
/* Issue config_link / reg_vfi to account for updated TOV's */
if (phba->sli_rev == LPFC_SLI_REV4) {
lpfc_issue_reg_vfi(vport);
} else {
lpfc_config_link(phba, mbox);
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
mbox->vport = vport;
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
mempool_free(mbox, phba->mbox_mem_pool);
goto out;
}
}
} }
lpfc_unreg_rpi(vport, ndlp); lpfc_unreg_rpi(vport, ndlp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment