📄 lpfc_els.c
字号:
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); } }}static voidlpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb){ IOCB_t *irsp; struct lpfc_sli *psli; struct lpfc_nodelist *ndlp; LPFC_MBOXQ_t *mbox; int disc, rc; 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_ADISC_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); /* ADISC completes to NPort <nlp_DID> */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0104 ADISC 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; } 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); lpfc_set_disctmo(phba); } goto out; } /* ADISC 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 { lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_ADISC); } } else { /* Good status, call state machine */ lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_ADISC); } if (disc && phba->num_disc_nodes) { /* Check to see if there are more ADISCs to be sent */ lpfc_more_adisc(phba); /* Check to see if we are done with ADISC authentication */ if (phba->num_disc_nodes == 0) { lpfc_can_disctmo(phba); /* If we get here, there is nothing left to wait for */ if ((phba->hba_state < LPFC_HBA_READY) && (phba->hba_state != LPFC_CLEAR_LA)) { /* Link up discovery */ if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) { phba->hba_state = LPFC_CLEAR_LA; lpfc_clear_la(phba, mbox); mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; rc = lpfc_sli_issue_mbox (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); lpfc_disc_flush_list(phba); psli->ring[(psli->ip_ring)]. flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->fcp_ring)]. flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->next_ring)]. flag &= ~LPFC_STOP_IOCB_EVENT; phba->hba_state = LPFC_HBA_READY; } } } else { lpfc_rscn_disc(phba); } } } spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; spin_unlock_irq(phba->host->host_lock);out: lpfc_els_free_iocb(phba, cmdiocb); return;}intlpfc_issue_els_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint8_t retry){ ADISC *ap; 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 (ADISC)); if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp, ELS_CMD_ADISC)) == 0) { return (1); } icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For ADISC request, remainder of payload is service parameters */ *((uint32_t *) (pcmd)) = ELS_CMD_ADISC; pcmd += sizeof (uint32_t); /* Fill in ADISC payload */ ap = (ADISC *) pcmd; ap->hardAL_PA = phba->fc_pref_ALPA; memcpy(&ap->portName, &phba->fc_portname, sizeof (struct lpfc_name)); memcpy(&ap->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name)); ap->DID = be32_to_cpu(phba->fc_myDID); phba->fc_stat.elsXmitADISC++; elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc; spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag |= NLP_ADISC_SND; if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { ndlp->nlp_flag &= ~NLP_ADISC_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_logo(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_LOGO_SND; spin_unlock_irq(phba->host->host_lock); /* LOGO completes to NPort <nlp_DID> */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0105 LOGO 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); /* 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; } /* LOGO 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_LOGO); } } else { /* Good status, call state machine */ lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_LOGO); if (ndlp->nlp_flag & NLP_DELAY_TMO) { lpfc_unreg_rpi(phba, ndlp); } }out: lpfc_els_free_iocb(phba, cmdiocb); return;}intlpfc_issue_els_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint8_t retry){ 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]; cmdsize = 2 * (sizeof (uint32_t) + sizeof (struct lpfc_name)); if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp, ELS_CMD_LOGO)) == 0) { return (1); } icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_LOGO; pcmd += sizeof (uint32_t); /* Fill in LOGO payload */ *((uint32_t *) (pcmd)) = be32_to_cpu(phba->fc_myDID); pcmd += sizeof (uint32_t); memcpy(pcmd, &phba->fc_portname, sizeof (struct lpfc_name)); phba->fc_stat.elsXmitLOGO++; elsiocb->iocb_cmpl = lpfc_cmpl_els_logo; spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag |= NLP_LOGO_SND; if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { ndlp->nlp_flag &= ~NLP_LOGO_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_cmd(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb){ IOCB_t *irsp; irsp = &rspiocb->iocb; /* ELS cmd tag <ulpIoTag> completes */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0106 ELS cmd tag x%x completes Data: x%x x%x\n", phba->brd_no, irsp->ulpIoTag, irsp->ulpStatus, irsp->un.ulpWord[4]); /* Check to see if link went down during discovery */ lpfc_els_chk_latt(phba); lpfc_els_free_iocb(phba, cmdiocb); return;}intlpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry){ IOCB_t *icmd; struct lpfc_iocbq *elsiocb; struct lpfc_sli_ring *pring; struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; struct lpfc_nodelist *ndlp; psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = (sizeof (uint32_t) + sizeof (SCR)); if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL)) == 0) { return (1); } lpfc_nlp_init(phba, ndlp, nportid); if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp, ELS_CMD_SCR)) == 0) { mempool_free( ndlp, phba->nlp_mem_pool); return (1); } icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_SCR; pcmd += sizeof (uint32_t); /* For SCR, remainder of payload is SCR parameter page */ memset(pcmd, 0, sizeof (SCR)); ((SCR *) pcmd)->Function = SCR_FUNC_FULL; phba->fc_stat.elsXmitSCR++; elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; spin_lock_irq(phba->host->host_lock); if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { spin_unlock_irq(phba->host->host_lock); mempool_free( ndlp, phba->nlp_mem_pool); lpfc_els_free_iocb(phba, elsiocb); return (1); } spin_unlock_irq(phba->host->host_lock); mempool_free( ndlp, phba->nlp_mem_pool); return (0);}static intlpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry){ IOCB_t *icmd; struct lpfc_iocbq *elsiocb; struct lpfc_sli_ring *pring; struct lpfc_sli *psli; FARP *fp; uint8_t *pcmd; uint32_t *lp; uint16_t cmdsize; struct lpfc_nodelist *ondlp; struct lpfc_nodelist *ndlp; psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = (sizeof (uint32_t) + sizeof (FARP)); if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL)) == 0) { return (1); } lpfc_nlp_init(phba, ndlp, nportid); if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp, ELS_CMD_RNID)) == 0) { mempool_free( ndlp, phba->nlp_mem_pool); return (1); } icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_FARPR; pcmd += sizeof (uint32_t); /* Fill in FARPR payload */ fp = (FARP *) (pcmd); memset(fp, 0, sizeof (FARP)); lp = (uint32_t *) pcmd; *lp++ = be32_to_cpu(nportid); *lp++ = be32_to_cpu(phba->fc_myDID); fp->Rflags = 0; fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE); memcpy(&fp->RportName, &phba->fc_portname, sizeof (struct lpfc_name)); memcpy(&fp->RnodeName, &phba->fc_nodename, sizeof (struct lpfc_name)); if ((ondlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, nportid))) { memcpy(&fp->OportName, &ondlp->nlp_portname, sizeof (struct lpfc_name)); memcpy(&fp->OnodeName, &ondlp->nlp_nodename, sizeof (struct lpfc_name)); } phba->fc_stat.elsXmitFARPR++; elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; spin_lock_irq(phba->host->host_lock); if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { spin_unlock_irq(phba->host->host_lock); mempool_free( ndlp, phba->nlp_mem_pool); lpfc_els_free_iocb(phba, elsiocb); return (1); } spin_unlock_irq(phba->host->host_lock); mempool_free( ndlp, phba->nlp_mem_pool); return (0);}voidlpfc_els_retry_delay(unsigned long ptr){ struct lpfc_nodelist *ndlp; struct lpfc_hba *phba; unsigned long iflag; struct lpfc_work_evt *evtp; ndlp = (struct lpfc_nodelist *)ptr; phba = ndlp->nlp_phba; evtp = &ndlp->els_retry_evt; spin_lock_irqsave(phba->host->host_lock, iflag); if (!list_empty(&evtp->evt_listp)) { spin_unlock_irqrestore(phba->host->host_lock, iflag); return; } evtp->evt_arg1 = ndlp; evtp->evt = LPFC_EVT_ELS_RETRY; list_add_tail(&evtp->evt_listp, &phba->work_list); if (phba->work_wait) wake_up(phba->work_wait); spin_unlock_irqrestore(phba->host->host_lock, iflag); return;}voidlpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp){ struct lpfc_hba *phba; uint32_t cmd; uint32_t did; uint8_t retry; phba = ndlp->nlp_phba; spin_lock_irq(phba->host->host_lock); did = (uint32_t) (ndlp->nlp_DID); cmd = (uint32_t) (ndlp->nlp_last_elscmd); if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { spin_unlock_irq(phba->host->host_lock); return; } ndlp->nlp_flag &= ~NLP_DELAY_TMO; spin_unlock_irq(phba->host->host_lock); retry = ndlp->nlp_retry; switch (cmd) { case ELS_CMD_FLOGI: lpfc_issue_els_flogi(phba, ndlp, retry); break; case ELS_CMD_PLOGI: ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); lpfc_issue_els_plogi(phba, ndlp, retry); break; case ELS_CMD_ADISC: ndlp->nlp_state = NLP_STE_ADISC_ISSUE; lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST); lpfc_issue_els_adisc(phba, ndlp, retry); break; case ELS_CMD_PRLI: ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -