📄 lpfc_els.c
字号:
cmdsize = sizeof (uint32_t) + sizeof (ADISC); if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, ndlp, ELS_CMD_ACC)) == 0) { return (1); } /* Xmit ADISC ACC response tag <ulpIoTag> */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0130 Xmit ADISC ACC response tag x%x " "Data: x%x x%x x%x x%x x%x\n", phba->brd_no, elsiocb->iocb.ulpIoTag, elsiocb->iocb.ulpContext, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); icmd = &elsiocb->iocb; oldcmd = &oldiocb->iocb; icmd->ulpContext = oldcmd->ulpContext; /* Xri */ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_ACC; pcmd += sizeof (uint32_t); 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.elsXmitACC++; elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; 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_rsp_prli_acc(struct lpfc_hba * phba, struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp){ PRLI *npr; lpfc_vpd_t *vpd; IOCB_t *icmd; IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; struct lpfc_sli_ring *pring; struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = sizeof (uint32_t) + sizeof (PRLI); if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, ndlp, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)))) == 0) { return (1); } /* Xmit PRLI ACC response tag <ulpIoTag> */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0131 Xmit PRLI ACC response tag x%x " "Data: x%x x%x x%x x%x x%x\n", phba->brd_no, elsiocb->iocb.ulpIoTag, elsiocb->iocb.ulpContext, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); icmd = &elsiocb->iocb; oldcmd = &oldiocb->iocb; icmd->ulpContext = oldcmd->ulpContext; /* Xri */ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)); pcmd += sizeof (uint32_t); /* For PRLI, remainder of payload is PRLI parameter page */ memset(pcmd, 0, sizeof (PRLI)); npr = (PRLI *) pcmd; vpd = &phba->vpd; /* * If our firmware version is 3.20 or later, * set the following bits for FC-TAPE support. */ if (vpd->rev.feaLevelHigh >= 0x02) { npr->ConfmComplAllowed = 1; npr->Retry = 1; npr->TaskRetryIdReq = 1; } npr->acceptRspCode = PRLI_REQ_EXECUTED; npr->estabImagePair = 1; npr->readXferRdyDis = 1; npr->ConfmComplAllowed = 1; npr->prliType = PRLI_FCP_TYPE; npr->initiatorFunc = 1; phba->fc_stat.elsXmitACC++; elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; 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);}static intlpfc_els_rsp_rnid_acc(struct lpfc_hba * phba, uint8_t format, struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp){ RNID *rn; IOCB_t *icmd; IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; struct lpfc_sli_ring *pring; struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; cmdsize = sizeof (uint32_t) + sizeof (uint32_t) + (2 * sizeof (struct lpfc_name)); if (format) cmdsize += sizeof (RNID_TOP_DISC); if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, ndlp, ELS_CMD_ACC)) == 0) { return (1); } /* Xmit RNID ACC response tag <ulpIoTag> */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0132 Xmit RNID ACC response tag x%x " "Data: x%x\n", phba->brd_no, elsiocb->iocb.ulpIoTag, elsiocb->iocb.ulpContext); icmd = &elsiocb->iocb; oldcmd = &oldiocb->iocb; icmd->ulpContext = oldcmd->ulpContext; /* Xri */ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_ACC; pcmd += sizeof (uint32_t); memset(pcmd, 0, sizeof (RNID)); rn = (RNID *) (pcmd); rn->Format = format; rn->CommonLen = (2 * sizeof (struct lpfc_name)); memcpy(&rn->portName, &phba->fc_portname, sizeof (struct lpfc_name)); memcpy(&rn->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name)); switch (format) { case 0: rn->SpecificLen = 0; break; case RNID_TOPOLOGY_DISC: rn->SpecificLen = sizeof (RNID_TOP_DISC); memcpy(&rn->un.topologyDisc.portName, &phba->fc_portname, sizeof (struct lpfc_name)); rn->un.topologyDisc.unitType = RNID_HBA; rn->un.topologyDisc.physPort = 0; rn->un.topologyDisc.attachedNodes = 0; break; default: rn->CommonLen = 0; rn->SpecificLen = 0; break; } phba->fc_stat.elsXmitACC++; elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; elsiocb->context1 = NULL; /* Don't need ndlp for cmpl, * it could be freed */ 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_disc_adisc(struct lpfc_hba * phba){ int sentadisc; struct lpfc_nodelist *ndlp, *next_ndlp; sentadisc = 0; /* go thru NPR list and issue any remaining ELS ADISCs */ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, nlp_listp) { if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { if (ndlp->nlp_flag & NLP_NPR_ADISC) { ndlp->nlp_flag &= ~NLP_NPR_ADISC; ndlp->nlp_state = NLP_STE_ADISC_ISSUE; lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST); lpfc_issue_els_adisc(phba, ndlp, 0); sentadisc++; phba->num_disc_nodes++; if (phba->num_disc_nodes >= phba->cfg_discovery_threads) { spin_lock_irq(phba->host->host_lock); phba->fc_flag |= FC_NLP_MORE; spin_unlock_irq(phba->host->host_lock); break; } } } } if (sentadisc == 0) { spin_lock_irq(phba->host->host_lock); phba->fc_flag &= ~FC_NLP_MORE; spin_unlock_irq(phba->host->host_lock); } return(sentadisc);}intlpfc_els_disc_plogi(struct lpfc_hba * phba){ int sentplogi; struct lpfc_nodelist *ndlp, *next_ndlp; sentplogi = 0; /* go thru NPR list and issue any remaining ELS PLOGIs */ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, nlp_listp) { if ((ndlp->nlp_flag & NLP_NPR_2B_DISC) && (!(ndlp->nlp_flag & NLP_DELAY_TMO))) { if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); lpfc_issue_els_plogi(phba, ndlp, 0); sentplogi++; phba->num_disc_nodes++; if (phba->num_disc_nodes >= phba->cfg_discovery_threads) { spin_lock_irq(phba->host->host_lock); phba->fc_flag |= FC_NLP_MORE; spin_unlock_irq(phba->host->host_lock); break; } } } } if (sentplogi == 0) { spin_lock_irq(phba->host->host_lock); phba->fc_flag &= ~FC_NLP_MORE; spin_unlock_irq(phba->host->host_lock); } return(sentplogi);}intlpfc_els_flush_rscn(struct lpfc_hba * phba){ struct lpfc_dmabuf *mp; int i; for (i = 0; i < phba->fc_rscn_id_cnt; i++) { mp = phba->fc_rscn_id_list[i]; lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); phba->fc_rscn_id_list[i] = NULL; } phba->fc_rscn_id_cnt = 0; spin_lock_irq(phba->host->host_lock); phba->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY); spin_unlock_irq(phba->host->host_lock); lpfc_can_disctmo(phba); return (0);}intlpfc_rscn_payload_check(struct lpfc_hba * phba, uint32_t did){ D_ID ns_did; D_ID rscn_did; struct lpfc_dmabuf *mp; uint32_t *lp; uint32_t payload_len, cmd, i, match; ns_did.un.word = did; match = 0; /* Never match fabric nodes for RSCNs */ if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) return(0); /* If we are doing a FULL RSCN rediscovery, match everything */ if (phba->fc_flag & FC_RSCN_DISCOVERY) { return (did); } for (i = 0; i < phba->fc_rscn_id_cnt; i++) { mp = phba->fc_rscn_id_list[i]; lp = (uint32_t *) mp->virt; cmd = *lp++; payload_len = be32_to_cpu(cmd) & 0xffff; /* payload length */ payload_len -= sizeof (uint32_t); /* take off word 0 */ while (payload_len) { rscn_did.un.word = *lp++; rscn_did.un.word = be32_to_cpu(rscn_did.un.word); payload_len -= sizeof (uint32_t); switch (rscn_did.un.b.resv) { case 0: /* Single N_Port ID effected */ if (ns_did.un.word == rscn_did.un.word) { match = did; } break; case 1: /* Whole N_Port Area effected */ if ((ns_did.un.b.domain == rscn_did.un.b.domain) && (ns_did.un.b.area == rscn_did.un.b.area)) { match = did; } break; case 2: /* Whole N_Port Domain effected */ if (ns_did.un.b.domain == rscn_did.un.b.domain) { match = did; } break; case 3: /* Whole Fabric effected */ match = did; break; default: /* Unknown Identifier in RSCN list */ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0217 Unknown Identifier in " "RSCN payload Data: x%x\n", phba->brd_no, rscn_did.un.word); break; } if (match) { break; } } } return (match);}static intlpfc_rscn_recovery_check(struct lpfc_hba * phba){ struct lpfc_nodelist *ndlp = NULL, *next_ndlp; struct list_head *listp; struct list_head *node_list[7]; int i; /* Look at all nodes effected by pending RSCNs and move * them to NPR list. */ node_list[0] = &phba->fc_npr_list; /* MUST do this list first */ node_list[1] = &phba->fc_nlpmap_list; node_list[2] = &phba->fc_nlpunmap_list; node_list[3] = &phba->fc_prli_list; node_list[4] = &phba->fc_reglogin_list; node_list[5] = &phba->fc_adisc_list; node_list[6] = &phba->fc_plogi_list; for (i = 0; i < 7; i++) { listp = node_list[i]; if (list_empty(listp)) continue; list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) { if (!(lpfc_rscn_payload_check(phba, ndlp->nlp_DID))) continue; lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); if (ndlp->nlp_flag & NLP_DELAY_TMO) { ndlp->nlp_flag &= ~NLP_DELAY_TMO; del_timer_sync(&ndlp->nlp_delayfunc); if (!list_empty(&ndlp-> els_retry_evt.evt_listp)) list_del_init(&ndlp-> els_retry_evt.evt_listp); } } } return (0);}static intlpfc_els_rcv_rscn(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp, uint8_t newnode){ struct lpfc_dmabuf *pcmd; uint32_t *lp; IOCB_t *icmd; uint32_t payload_len, cmd; icmd = &cmdiocb->iocb; pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; lp = (uint32_t *) pcmd->virt; cmd = *lp++; payload_len = be32_to_cpu(cmd) & 0xffff; /* payload length */ payload_len -= sizeof (uint32_t); /* take off word 0 */ cmd &= ELS_CMD_MASK; /* RSCN received */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0214 RSCN received Data: x%x x%x x%x x%x\n", phba->brd_no, phba->fc_flag, payload_len, *lp, phba->fc_rscn_id_cnt); /* If we are about to begin discovery, just ACC the RSCN. * Discovery processing will satisfy it. */ if (phba->hba_state < LPFC_NS_QRY) { lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode); return (0); } /* If we are already processing an RSCN, save the received * RSCN payload buffer, cmdiocb->context2 to process later. */ if (phba->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) { if ((phba->fc_rscn_id_cnt < FC_MAX_HOLD_RSCN) && !(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); phba->fc_rscn_id_list[phba->fc_rscn_id_cnt++] = pcmd; /* If we zero, cmdiocb->context2, the calling * routine will not try to free it. */ cmdiocb->context2 = NULL; /* Deferred RSCN */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0235 Deferred RSCN " "Data: x%x x%x x%x\n", phba->brd_no, phba->fc_rscn_id_cnt, phba->fc_flag, phba->hba_state); } else { spin_lock_irq(phba->host->host_lock); phba->fc_flag |= FC_RSCN_DISCOVERY; spin_unlock_irq(phba->host->host_lock); /* ReDiscovery RSCN */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0234 ReDiscovery RSCN " "Data: x%x x%x x%x\n", phba->brd_no, phba->fc_rscn_id_cnt, phba->fc_flag, phba->hba_state); } /* Send back ACC */ lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode); /* send RECOVERY event for ALL nodes that match RSCN payload */ lpfc_rscn_recovery_check(phba); return (0); } phba->fc_flag |= FC_RSCN_MODE; phba->fc_rscn_id_list[phba->fc_rscn_id_cnt++] = pcmd; /* * If we zero, cmdiocb->context2, the calling routine will * not t
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -