if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
icmd->un.elsreq64.bdl.ulpIoTag32) {
ndlp = (struct lpfc_nodelist *)(iocb->context1);
- if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
+ if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
+ (ndlp->nlp_DID == Fabric_DID))
lpfc_sli_issue_abort_iotag(phba, pring, iocb);
- }
}
}
spin_unlock_irq(&phba->hbalock);
struct fc_rport *rport;
struct serv_parm *sp;
uint8_t name[sizeof(struct lpfc_name)];
- uint32_t rc;
+ uint32_t rc, keepDID = 0;
/* Fabric nodes can have the same WWPN so we don't bother searching
* by WWPN. Just return the ndlp that was given to us.
return ndlp;
lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
} else if (!NLP_CHK_NODE_ACT(new_ndlp)) {
+ rc = memcmp(&ndlp->nlp_portname, name,
+ sizeof(struct lpfc_name));
+ if (!rc)
+ return ndlp;
new_ndlp = lpfc_enable_node(vport, new_ndlp,
NLP_STE_UNUSED_NODE);
if (!new_ndlp)
return ndlp;
- }
+ keepDID = new_ndlp->nlp_DID;
+ } else
+ keepDID = new_ndlp->nlp_DID;
lpfc_unreg_rpi(vport, new_ndlp);
new_ndlp->nlp_DID = ndlp->nlp_DID;
}
new_ndlp->nlp_type = ndlp->nlp_type;
}
+ /* We shall actually free the ndlp with both nlp_DID and
+ * nlp_portname fields equals 0 to avoid any ndlp on the
+ * nodelist never to be used.
+ */
+ if (ndlp->nlp_DID == 0) {
+ spin_lock_irq(&phba->ndlp_lock);
+ NLP_SET_FREE_REQ(ndlp);
+ spin_unlock_irq(&phba->ndlp_lock);
+ }
+ /* Two ndlps cannot have the same did on the nodelist */
+ ndlp->nlp_DID = keepDID;
lpfc_drop_node(vport, ndlp);
}
else {
lpfc_unreg_rpi(vport, ndlp);
- ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
+ /* Two ndlps cannot have the same did */
+ ndlp->nlp_DID = keepDID;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
}
return new_ndlp;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_work_evt *evtp;
+ if (!(nlp->nlp_flag & NLP_DELAY_TMO))
+ return;
spin_lock_irq(shost->host_lock);
nlp->nlp_flag &= ~NLP_DELAY_TMO;
spin_unlock_irq(shost->host_lock);
del_timer_sync(&nlp->nlp_delayfunc);
nlp->nlp_last_elscmd = 0;
-
if (!list_empty(&nlp->els_retry_evt.evt_listp)) {
list_del_init(&nlp->els_retry_evt.evt_listp);
/* Decrement nlp reference count held for the delayed retry */
evtp = &nlp->els_retry_evt;
lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1);
}
-
if (nlp->nlp_flag & NLP_NPR_2B_DISC) {
spin_lock_irq(shost->host_lock);
nlp->nlp_flag &= ~NLP_NPR_2B_DISC;
spin_unlock_irq(shost->host_lock);
if (vport->num_disc_nodes) {
- /* Check to see if there are more
- * PLOGIs to be sent
- */
- lpfc_more_plogi(vport);
-
+ if (vport->port_state < LPFC_VPORT_READY) {
+ /* Check if there are more ADISCs to be sent */
+ lpfc_more_adisc(vport);
+ if ((vport->num_disc_nodes == 0) &&
+ (vport->fc_npr_cnt))
+ lpfc_els_disc_plogi(vport);
+ } else {
+ /* Check if there are more PLOGIs to be sent */
+ lpfc_more_plogi(vport);
+ }
if (vport->num_disc_nodes == 0) {
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~FC_NDISC_ACTIVE;
unsigned long flags;
struct lpfc_work_evt *evtp = &ndlp->els_retry_evt;
- ndlp = (struct lpfc_nodelist *) ptr;
- phba = ndlp->vport->phba;
- evtp = &ndlp->els_retry_evt;
-
spin_lock_irqsave(&phba->hbalock, flags);
if (!list_empty(&evtp->evt_listp)) {
spin_unlock_irqrestore(&phba->hbalock, flags);
}
phba->fc_stat.elsXmitRetry++;
- if (ndlp && delay) {
+ if (ndlp && NLP_CHK_NODE_ACT(ndlp) && delay) {
phba->fc_stat.elsDelayRetry++;
ndlp->nlp_retry = cmdiocb->retry;
lpfc_issue_els_fdisc(vport, ndlp, cmdiocb->retry);
return 1;
case ELS_CMD_PLOGI:
- if (ndlp) {
+ if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
lpfc_nlp_set_state(vport, ndlp,
NLP_STE_PLOGI_ISSUE);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool);
- if (ndlp) {
+ if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
lpfc_nlp_put(ndlp);
/* This is the end of the default RPI cleanup logic for this
* ndlp. If no other discovery threads are using this ndlp.
* function can have cmdiocb->contest1 (ndlp) field set to NULL.
*/
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
- if (ndlp && (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) {
+ if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
+ (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) {
/* A LS_RJT associated with Default RPI cleanup has its own
* seperate code path.
*/
}
/* Check to see if link went down during discovery */
- if (!ndlp || lpfc_els_chk_latt(vport)) {
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || lpfc_els_chk_latt(vport)) {
if (mbox) {
mp = (struct lpfc_dmabuf *) mbox->context1;
if (mp) {
}
mempool_free(mbox, phba->mbox_mem_pool);
}
- if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI))
+ if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
+ (ndlp->nlp_flag & NLP_RM_DFLT_RPI))
if (lpfc_nlp_not_used(ndlp)) {
ndlp = NULL;
/* Indicate the node has already released,
mempool_free(mbox, phba->mbox_mem_pool);
}
out:
- if (ndlp) {
+ if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
spin_unlock_irq(shost->host_lock);
npr = (PRLI *) pcmd;
vpd = &phba->vpd;
/*
- * If our firmware version is 3.20 or later,
- * set the following bits for FC-TAPE support.
+ * If the remote port is a target and our firmware version is 3.20 or
+ * later, set the following bits for FC-TAPE support.
*/
- if (vpd->rev.feaLevelHigh >= 0x02) {
+ if ((ndlp->nlp_type & NLP_FCP_TARGET) &&
+ (vpd->rev.feaLevelHigh >= 0x02)) {
npr->ConfmComplAllowed = 1;
npr->Retry = 1;
npr->TaskRetryIdReq = 1;
{
struct lpfc_nodelist *ndlp = NULL;
- /* Look at all nodes effected by pending RSCNs and move
- * them to NPR state.
- */
-
+ /* Move all affected nodes by pending RSCNs to NPR state. */
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (!NLP_CHK_NODE_ACT(ndlp) ||
- ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
- lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0)
+ (ndlp->nlp_state == NLP_STE_UNUSED_NODE) ||
+ !lpfc_rscn_payload_check(vport, ndlp->nlp_DID))
continue;
-
lpfc_disc_state_machine(vport, ndlp, NULL,
- NLP_EVT_DEVICE_RECOVERY);
-
- /*
- * Make sure NLP_DELAY_TMO is NOT running after a device
- * recovery event.
- */
- if (ndlp->nlp_flag & NLP_DELAY_TMO)
- lpfc_cancel_retry_delay_tmo(vport, ndlp);
+ NLP_EVT_DEVICE_RECOVERY);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
}
-
return 0;
}
/* Another thread is walking fc_rscn_id_list on this vport */
spin_unlock_irq(shost->host_lock);
vport->fc_flag |= FC_RSCN_DISCOVERY;
+ /* Send back ACC */
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
return 0;
}
/* Indicate we are walking fc_rscn_id_list on this vport */
lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
struct lpfc_nodelist *fan_ndlp)
{
- struct lpfc_dmabuf *pcmd;
+ struct lpfc_hba *phba = vport->phba;
uint32_t *lp;
- IOCB_t *icmd;
- uint32_t cmd, did;
FAN *fp;
- struct lpfc_nodelist *ndlp, *next_ndlp;
- struct lpfc_hba *phba = vport->phba;
-
- /* FAN received */
- lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
- "0265 FAN received\n");
- icmd = &cmdiocb->iocb;
- did = icmd->un.elsreq64.remoteID;
- pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
- lp = (uint32_t *)pcmd->virt;
-
- cmd = *lp++;
- fp = (FAN *) lp;
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0265 FAN received\n");
+ lp = (uint32_t *)((struct lpfc_dmabuf *)cmdiocb->context2)->virt;
+ fp = (FAN *) ++lp;
/* FAN received; Fan does not have a reply sequence */
-
- if (phba->pport->port_state == LPFC_LOCAL_CFG_LINK) {
+ if ((vport == phba->pport) &&
+ (vport->port_state == LPFC_LOCAL_CFG_LINK)) {
if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName,
- sizeof(struct lpfc_name)) != 0) ||
+ sizeof(struct lpfc_name))) ||
(memcmp(&phba->fc_fabparam.portName, &fp->FportName,
- sizeof(struct lpfc_name)) != 0)) {
- /*
- * This node has switched fabrics. FLOGI is required
- * Clean up the old rpi's
- */
-
- list_for_each_entry_safe(ndlp, next_ndlp,
- &vport->fc_nodes, nlp_listp) {
- if (!NLP_CHK_NODE_ACT(ndlp))
- continue;
- if (ndlp->nlp_state != NLP_STE_NPR_NODE)
- continue;
- if (ndlp->nlp_type & NLP_FABRIC) {
- /*
- * Clean up old Fabric, Nameserver and
- * other NLP_FABRIC logins
- */
- lpfc_drop_node(vport, ndlp);
-
- } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
- /* Fail outstanding I/O now since this
- * device is marked for PLOGI
- */
- lpfc_unreg_rpi(vport, ndlp);
- }
- }
-
+ sizeof(struct lpfc_name)))) {
+ /* This port has switched fabrics. FLOGI is required */
lpfc_initial_flogi(vport);
- return 0;
- }
- /* Discovery not needed,
- * move the nodes to their original state.
- */
- list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
- nlp_listp) {
- if (!NLP_CHK_NODE_ACT(ndlp))
- continue;
- if (ndlp->nlp_state != NLP_STE_NPR_NODE)
- continue;
-
- switch (ndlp->nlp_prev_state) {
- case NLP_STE_UNMAPPED_NODE:
- ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(vport, ndlp,
- NLP_STE_UNMAPPED_NODE);
- break;
-
- case NLP_STE_MAPPED_NODE:
- ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(vport, ndlp,
- NLP_STE_MAPPED_NODE);
- break;
-
- default:
- break;
- }
+ } else {
+ /* FAN verified - skip FLOGI */
+ vport->fc_myDID = vport->fc_prevDID;
+ lpfc_issue_fabric_reglogin(vport);
}
-
- /* Start discovery - this should just do CLEAR_LA */
- lpfc_disc_start(vport);
}
return 0;
}
else {
struct lpfc_nodelist *ndlp;
ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext);
- if (ndlp)
+ if (ndlp && NLP_CHK_NODE_ACT(ndlp))
remote_ID = ndlp->nlp_DID;
}
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
newnode = 1;
if ((did & Fabric_DID_MASK) == Fabric_DID_MASK)
ndlp->nlp_type |= NLP_FABRIC;
- } else {
- if (!NLP_CHK_NODE_ACT(ndlp)) {
- ndlp = lpfc_enable_node(vport, ndlp,
- NLP_STE_UNUSED_NODE);
- if (!ndlp)
- goto dropit;
- }
- if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
- /* This is simular to the new node path */
- ndlp = lpfc_nlp_get(ndlp);
- if (!ndlp)
- goto dropit;
- lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
- newnode = 1;
- }
+ } else if (!NLP_CHK_NODE_ACT(ndlp)) {
+ ndlp = lpfc_enable_node(vport, ndlp,
+ NLP_STE_UNUSED_NODE);
+ if (!ndlp)
+ goto dropit;
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ newnode = 1;
+ if ((did & Fabric_DID_MASK) == Fabric_DID_MASK)
+ ndlp->nlp_type |= NLP_FABRIC;
+ } else if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
+ /* This is similar to the new node path */
+ ndlp = lpfc_nlp_get(ndlp);
+ if (!ndlp)
+ goto dropit;
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ newnode = 1;
}
phba->fc_stat.elsRcvFrame++;
return;
}
lpfc_nlp_init(vport, ndlp, NameServer_DID);
- ndlp->nlp_type |= NLP_FABRIC;
} else if (!NLP_CHK_NODE_ACT(ndlp)) {
ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE);
if (!ndlp) {
return;
}
}
+ ndlp->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
if (ndlp_fdmi) {
lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
ndlp_fdmi->nlp_type |= NLP_FABRIC;
- ndlp_fdmi->nlp_state =
- NLP_STE_PLOGI_ISSUE;
+ lpfc_nlp_set_state(vport, ndlp_fdmi,
+ NLP_STE_PLOGI_ISSUE);
lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID,
0);
}
(piocb->iocb_cmpl) (phba, piocb, piocb);
}
}
-
-
-#if 0
-void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
-{
- LIST_HEAD(completions);
- struct lpfc_iocbq *tmp_iocb, *piocb;
- IOCB_t *cmd;
- struct lpfc_nodelist *ndlp;
-
- spin_lock_irq(&phba->hbalock);
- list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
- list) {
-
- cmd = &piocb->iocb;
- ndlp = (struct lpfc_nodelist *) piocb->context1;
- if (cmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
- ndlp != NULL &&
- ndlp->nlp_DID == Fabric_DID)
- list_move_tail(&piocb->list, &completions);
- }
- spin_unlock_irq(&phba->hbalock);
-
- while (!list_empty(&completions)) {
- piocb = list_get_first(&completions, struct lpfc_iocbq, list);
- list_del_init(&piocb->list);
-
- cmd = &piocb->iocb;
- cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
- cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
- (piocb->iocb_cmpl) (phba, piocb, piocb);
- }
-}
-#endif /* 0 */
-
-