📄 lpfc_els.c
字号:
/* Start discovery */ lpfc_disc_start(phba); }out: lpfc_els_free_iocb(phba, cmdiocb);}static intlpfc_issue_els_flogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint8_t retry){ struct serv_parm *sp; IOCB_t *icmd; struct lpfc_iocbq *elsiocb; struct lpfc_sli_ring *pring; uint8_t *pcmd; uint16_t cmdsize; uint32_t tmo; int rc; pring = &phba->sli.ring[LPFC_ELS_RING]; cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm)); if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp, ELS_CMD_FLOGI)) == 0) { return (1); } icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For FLOGI request, remainder of payload is service parameters */ *((uint32_t *) (pcmd)) = ELS_CMD_FLOGI; pcmd += sizeof (uint32_t); memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm)); sp = (struct serv_parm *) pcmd; /* Setup CSPs accordingly for Fabric */ sp->cmn.e_d_tov = 0; sp->cmn.w2.r_a_tov = 0; sp->cls1.classValid = 0; sp->cls2.seqDelivery = 1; sp->cls3.seqDelivery = 1; if (sp->cmn.fcphLow < FC_PH3) sp->cmn.fcphLow = FC_PH3; if (sp->cmn.fcphHigh < FC_PH3) sp->cmn.fcphHigh = FC_PH3; tmo = phba->fc_ratov; phba->fc_ratov = LPFC_DISC_FLOGI_TMO; lpfc_set_disctmo(phba); phba->fc_ratov = tmo; phba->fc_stat.elsXmitFLOGI++; elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi; spin_lock_irq(phba->host->host_lock); rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); spin_unlock_irq(phba->host->host_lock); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); return (1); } return (0);}intlpfc_els_abort_flogi(struct lpfc_hba * phba){ struct lpfc_sli_ring *pring; struct lpfc_iocbq *iocb, *next_iocb; struct lpfc_nodelist *ndlp; IOCB_t *icmd; /* Abort outstanding I/O on NPort <nlp_DID> */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0201 Abort outstanding I/O on NPort x%x\n", phba->brd_no, Fabric_DID); pring = &phba->sli.ring[LPFC_ELS_RING]; /* * Check the txcmplq for an iocb that matches the nport the driver is * searching for. */ spin_lock_irq(phba->host->host_lock); list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { icmd = &iocb->iocb; if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) { ndlp = (struct lpfc_nodelist *)(iocb->context1); if (ndlp && (ndlp->nlp_DID == Fabric_DID)) { list_del(&iocb->list); pring->txcmplq_cnt--; if ((icmd->un.elsreq64.bdl.ulpIoTag32)) { lpfc_sli_issue_abort_iotag32 (phba, pring, iocb); } if (iocb->iocb_cmpl) { icmd->ulpStatus = IOSTAT_LOCAL_REJECT; icmd->un.ulpWord[4] = IOERR_SLI_ABORTED; spin_unlock_irq(phba->host->host_lock); (iocb->iocb_cmpl) (phba, iocb, iocb); spin_lock_irq(phba->host->host_lock); } else lpfc_sli_release_iocbq(phba, iocb); } } } spin_unlock_irq(phba->host->host_lock); return 0;}intlpfc_initial_flogi(struct lpfc_hba * phba){ struct lpfc_nodelist *ndlp; /* First look for Fabric ndlp on the unmapped list */ if ((ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED, Fabric_DID)) == 0) { /* Cannot find existing Fabric ndlp, so allocate a new one */ if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL)) == 0) { return (0); } lpfc_nlp_init(phba, ndlp, Fabric_DID); } else { phba->fc_unmap_cnt--; list_del(&ndlp->nlp_listp); spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag &= ~NLP_LIST_MASK; spin_unlock_irq(phba->host->host_lock); } if (lpfc_issue_els_flogi(phba, ndlp, 0)) { mempool_free( ndlp, phba->nlp_mem_pool); } return (1);}static voidlpfc_more_plogi(struct lpfc_hba * phba){ int sentplogi; if (phba->num_disc_nodes) phba->num_disc_nodes--; /* Continue discovery with <num_disc_nodes> PLOGIs to go */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0232 Continue discovery with %d PLOGIs to go " "Data: x%x x%x x%x\n", phba->brd_no, phba->num_disc_nodes, phba->fc_plogi_cnt, phba->fc_flag, phba->hba_state); /* Check to see if there are more PLOGIs to be sent */ if (phba->fc_flag & FC_NLP_MORE) { /* go thru NPR list and issue any remaining ELS PLOGIs */ sentplogi = lpfc_els_disc_plogi(phba); } return;}static voidlpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb){ IOCB_t *irsp; struct lpfc_sli *psli; struct lpfc_nodelist *ndlp; int disc, rc, did, type; psli = &phba->sli; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; irsp = &rspiocb->iocb; ndlp = (struct lpfc_nodelist *) cmdiocb->context1; spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag &= ~NLP_PLOGI_SND; spin_unlock_irq(phba->host->host_lock); /* Since ndlp can be freed in the disc state machine, note if this node * is being used during discovery. */ disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); rc = 0; /* PLOGI completes to NPort <nlp_DID> */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0102 PLOGI completes to NPort x%x " "Data: x%x x%x x%x x%x\n", phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], disc, phba->num_disc_nodes); /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(phba)) { spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(phba->host->host_lock); goto out; } /* ndlp could be freed in DSM, save these values now */ type = ndlp->nlp_type; did = ndlp->nlp_DID; if (irsp->ulpStatus) { /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { /* ELS command is being retried */ if (disc) { spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(phba->host->host_lock); } goto out; } /* PLOGI failed */ /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) || (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) { disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); } else { rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_PLOGI); } } else { /* Good status, call state machine */ rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_PLOGI); } if (type & NLP_FABRIC) { /* If we cannot login to Nameserver, kick off discovery now */ if ((did == NameServer_DID) && (rc == NLP_STE_FREED_NODE)) { lpfc_disc_start(phba); } goto out; } if (disc && phba->num_disc_nodes) { /* Check to see if there are more PLOGIs to be sent */ lpfc_more_plogi(phba); } if (rc != NLP_STE_FREED_NODE) { spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; spin_unlock_irq(phba->host->host_lock); } if (phba->num_disc_nodes == 0) { if(disc) { spin_lock_irq(phba->host->host_lock); phba->fc_flag &= ~FC_NDISC_ACTIVE; spin_unlock_irq(phba->host->host_lock); } lpfc_can_disctmo(phba); if (phba->fc_flag & FC_RSCN_MODE) { /* Check to see if more RSCNs came in while we were * processing this one. */ if ((phba->fc_rscn_id_cnt == 0) && (!(phba->fc_flag & FC_RSCN_DISCOVERY))) { spin_lock_irq(phba->host->host_lock); phba->fc_flag &= ~FC_RSCN_MODE; spin_unlock_irq(phba->host->host_lock); } else { lpfc_els_handle_rscn(phba); } } }out: lpfc_els_free_iocb(phba, cmdiocb); return;}intlpfc_issue_els_plogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint8_t retry){ struct serv_parm *sp; IOCB_t *icmd; struct lpfc_iocbq *elsiocb; struct lpfc_sli_ring *pring; struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm)); if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp, ELS_CMD_PLOGI)) == 0) { return (1); } icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For PLOGI request, remainder of payload is service parameters */ *((uint32_t *) (pcmd)) = ELS_CMD_PLOGI; pcmd += sizeof (uint32_t); memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm)); sp = (struct serv_parm *) pcmd; if (sp->cmn.fcphLow < FC_PH_4_3) sp->cmn.fcphLow = FC_PH_4_3; if (sp->cmn.fcphHigh < FC_PH3) sp->cmn.fcphHigh = FC_PH3; phba->fc_stat.elsXmitPLOGI++; elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi; spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag |= NLP_PLOGI_SND; if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { ndlp->nlp_flag &= ~NLP_PLOGI_SND; spin_unlock_irq(phba->host->host_lock); lpfc_els_free_iocb(phba, elsiocb); return (1); } spin_unlock_irq(phba->host->host_lock); return (0);}static voidlpfc_cmpl_els_prli(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb){ IOCB_t *irsp; struct lpfc_sli *psli; struct lpfc_nodelist *ndlp; psli = &phba->sli; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; irsp = &(rspiocb->iocb); ndlp = (struct lpfc_nodelist *) cmdiocb->context1; spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag &= ~NLP_PRLI_SND; spin_unlock_irq(phba->host->host_lock); /* PRLI completes to NPort <nlp_DID> */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0103 PRLI completes to NPort x%x " "Data: x%x x%x x%x\n", phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], phba->num_disc_nodes); phba->fc_prli_sent--; /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(phba)) goto out; if (irsp->ulpStatus) { /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { /* ELS command is being retried */ goto out; } /* PRLI failed */ /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) || (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) { goto out; } else { lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_PRLI); } } else { /* Good status, call state machine */ lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_PRLI); }out: lpfc_els_free_iocb(phba, cmdiocb); return;}intlpfc_issue_els_prli(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint8_t retry){ PRLI *npr; IOCB_t *icmd; struct lpfc_iocbq *elsiocb; struct lpfc_sli_ring *pring; struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = (sizeof (uint32_t) + sizeof (PRLI)); if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp, ELS_CMD_PRLI)) == 0) { return (1); } icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For PRLI request, remainder of payload is service parameters */ memset(pcmd, 0, (sizeof (PRLI) + sizeof (uint32_t))); *((uint32_t *) (pcmd)) = ELS_CMD_PRLI; pcmd += sizeof (uint32_t); /* For PRLI, remainder of payload is PRLI parameter page */ npr = (PRLI *) pcmd; /* * If our firmware version is 3.20 or later, * set the following bits for FC-TAPE support. */ if (phba->vpd.rev.feaLevelHigh >= 0x02) { npr->ConfmComplAllowed = 1; npr->Retry = 1; npr->TaskRetryIdReq = 1; } npr->estabImagePair = 1; npr->readXferRdyDis = 1; /* For FCP support */ npr->prliType = PRLI_FCP_TYPE; npr->initiatorFunc = 1; phba->fc_stat.elsXmitPRLI++; elsiocb->iocb_cmpl = lpfc_cmpl_els_prli; spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag |= NLP_PRLI_SND; if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { ndlp->nlp_flag &= ~NLP_PRLI_SND; spin_unlock_irq(phba->host->host_lock); lpfc_els_free_iocb(phba, elsiocb); return (1); } spin_unlock_irq(phba->host->host_lock); phba->fc_prli_sent++; return (0);}static voidlpfc_more_adisc(struct lpfc_hba * phba){ int sentadisc; if (phba->num_disc_nodes) phba->num_disc_nodes--; /* Continue discovery with <num_disc_nodes> ADISCs to go */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0210 Continue discovery with %d ADISCs to go " "Data: x%x x%x x%x\n", phba->brd_no, phba->num_disc_nodes, phba->fc_adisc_cnt, phba->fc_flag, phba->hba_state); /* Check to see if there are more ADISCs to be sent */ if (phba->fc_flag & FC_NLP_MORE) { lpfc_set_disctmo(phba); /* go thru NPR list and issue any remaining ELS ADISCs */ sentadisc = lpfc_els_disc_adisc(phba); } return;}static voidlpfc_rscn_disc(struct lpfc_hba * phba){ /* RSCN discovery */ /* go thru NPR list and issue ELS PLOGIs */ if (phba->fc_npr_cnt) { if (lpfc_els_disc_plogi(phba)) return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -