scsi: lpfc: Fix odd recovery in duplicate FLOGIs in point-to-point

Testing a point-to-point topology and a case of re-FLOGI without
intervening link bouncing, showed an odd interaction with firmware and
a resulting scenario where the driver no longer probed after accepting
the new FLOGI.

Work around the firmware issue by issuing a link bounce if a FLOGI is
received after the link is already up and FLOGI's accepted.

While debugging the issue, realized that some debug traces should be
clarified to help in the future.

Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
James Smart 2018-10-23 13:41:08 -07:00 committed by Martin K. Petersen
parent b114d9009d
commit d496b9a724
3 changed files with 64 additions and 12 deletions

View File

@ -490,6 +490,7 @@ struct lpfc_vport {
struct nvme_fc_local_port *localport; struct nvme_fc_local_port *localport;
uint8_t nvmei_support; /* driver supports NVME Initiator */ uint8_t nvmei_support; /* driver supports NVME Initiator */
uint32_t last_fcp_wqidx; uint32_t last_fcp_wqidx;
uint32_t rcv_flogi_cnt; /* How many unsol FLOGIs ACK'd. */
}; };
struct hbq_s { struct hbq_s {

View File

@ -1057,9 +1057,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
goto flogifail; goto flogifail;
lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS,
"0150 FLOGI failure Status:x%x/x%x TMO:x%x\n", "0150 FLOGI failure Status:x%x/x%x xri x%x TMO:x%x\n",
irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpStatus, irsp->un.ulpWord[4],
irsp->ulpTimeout); cmdiocb->sli4_xritag, irsp->ulpTimeout);
/* FLOGI failed, so there is no fabric */ /* FLOGI failed, so there is no fabric */
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
@ -1113,7 +1113,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* FLOGI completes successfully */ /* FLOGI completes successfully */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0101 FLOGI completes successfully, I/O tag:x%x, " "0101 FLOGI completes successfully, I/O tag:x%x, "
"Data: x%x x%x x%x x%x x%x x%x\n", cmdiocb->iotag, "xri x%x Data: x%x x%x x%x x%x x%x %x\n",
cmdiocb->iotag, cmdiocb->sli4_xritag,
irsp->un.ulpWord[4], sp->cmn.e_d_tov, irsp->un.ulpWord[4], sp->cmn.e_d_tov,
sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution, sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution,
vport->port_state, vport->fc_flag); vport->port_state, vport->fc_flag);
@ -4347,14 +4348,6 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
default: default:
return 1; return 1;
} }
/* Xmit ELS ACC response tag <ulpIoTag> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
"DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x "
"fc_flag x%x\n",
elsiocb->iotag, elsiocb->iocb.ulpContext,
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi, vport->fc_flag);
if (ndlp->nlp_flag & NLP_LOGO_ACC) { if (ndlp->nlp_flag & NLP_LOGO_ACC) {
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED || if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED ||
@ -4523,6 +4516,15 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
lpfc_els_free_iocb(phba, elsiocb); lpfc_els_free_iocb(phba, elsiocb);
return 1; return 1;
} }
/* Xmit ELS ACC response tag <ulpIoTag> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0128 Xmit ELS ACC response Status: x%x, IoTag: x%x, "
"XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x "
"RPI: x%x, fc_flag x%x\n",
rc, elsiocb->iotag, elsiocb->sli4_xritag,
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi, vport->fc_flag);
return 0; return 0;
} }
@ -6533,6 +6535,11 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
port_state = vport->port_state; port_state = vport->port_state;
vport->fc_flag |= FC_PT2PT; vport->fc_flag |= FC_PT2PT;
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
/* Acking an unsol FLOGI. Count 1 for link bounce
* work-around.
*/
vport->rcv_flogi_cnt++;
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"3311 Rcv Flogi PS x%x new PS x%x " "3311 Rcv Flogi PS x%x new PS x%x "
@ -7930,8 +7937,9 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct ls_rjt stat; struct ls_rjt stat;
uint32_t *payload; uint32_t *payload;
uint32_t cmd, did, newnode; uint32_t cmd, did, newnode;
uint8_t rjt_exp, rjt_err = 0; uint8_t rjt_exp, rjt_err = 0, init_link = 0;
IOCB_t *icmd = &elsiocb->iocb; IOCB_t *icmd = &elsiocb->iocb;
LPFC_MBOXQ_t *mbox;
if (!vport || !(elsiocb->context2)) if (!vport || !(elsiocb->context2))
goto dropit; goto dropit;
@ -8080,6 +8088,19 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
did, vport->port_state, ndlp->nlp_flag); did, vport->port_state, ndlp->nlp_flag);
phba->fc_stat.elsRcvFLOGI++; phba->fc_stat.elsRcvFLOGI++;
/* If the driver believes fabric discovery is done and is ready,
* bounce the link. There is some descrepancy.
*/
if (vport->port_state >= LPFC_LOCAL_CFG_LINK &&
vport->fc_flag & FC_PT2PT &&
vport->rcv_flogi_cnt >= 1) {
rjt_err = LSRJT_LOGICAL_BSY;
rjt_exp = LSEXP_NOTHING_MORE;
init_link++;
goto lsrjt;
}
lpfc_els_rcv_flogi(vport, elsiocb, ndlp); lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
if (newnode) if (newnode)
lpfc_nlp_put(ndlp); lpfc_nlp_put(ndlp);
@ -8308,6 +8329,27 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
lpfc_nlp_put(elsiocb->context1); lpfc_nlp_put(elsiocb->context1);
elsiocb->context1 = NULL; elsiocb->context1 = NULL;
/* Special case. Driver received an unsolicited command that
* unsupportable given the driver's current state. Reset the
* link and start over.
*/
if (init_link) {
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
return;
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;
if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) ==
MBX_NOT_FINISHED)
mempool_free(mbox, phba->mbox_mem_pool);
}
return; return;
dropit: dropit:

View File

@ -947,6 +947,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
} }
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
phba->pport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI); phba->pport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI);
phba->pport->rcv_flogi_cnt = 0;
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
} }
return 0; return 0;
@ -1018,6 +1019,7 @@ lpfc_linkup(struct lpfc_hba *phba)
{ {
struct lpfc_vport **vports; struct lpfc_vport **vports;
int i; int i;
struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport);
phba->link_state = LPFC_LINK_UP; phba->link_state = LPFC_LINK_UP;
@ -1031,6 +1033,13 @@ lpfc_linkup(struct lpfc_hba *phba)
lpfc_linkup_port(vports[i]); lpfc_linkup_port(vports[i]);
lpfc_destroy_vport_work_array(phba, vports); lpfc_destroy_vport_work_array(phba, vports);
/* Clear the pport flogi counter in case the link down was
* absorbed without an ACQE. No lock here - in worker thread
* and discovery is synchronized.
*/
spin_lock_irq(shost->host_lock);
phba->pport->rcv_flogi_cnt = 0;
spin_unlock_irq(shost->host_lock);
return 0; return 0;
} }