/* Don't schedule a worker thread event if the vport is going down. */ if (test_bit(FC_UNLOADING, &vport->load_flag) ||
(phba->sli_rev == LPFC_SLI_REV4 &&
!test_bit(HBA_SETUP, &phba->hba_flag))) {
/* Only 1 thread can drop the initial node reference. *IfnotregisteredforNVMEandNLP_DROPPEDflagis *clear,removetheinitialreference.
*/ if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag))
drop_initial_node_ref = true;
/* The scsi_transport is done with the rport so lpfc cannot *calltounregister.
*/ if (ndlp->fc4_xpt_flags & SCSI_XPT_REGD) {
ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD;
/* If NLP_XPT_REGD was cleared in lpfc_nlp_unreg_node, *unregistercallsweremadetothescsiandnvme *transportsandrefcntwasalreadydecremented.Clear *theNLP_XPT_REGDflagonlyiftheNVMEnrportis *confirmedunregistered.
*/ if (ndlp->fc4_xpt_flags & NLP_XPT_REGD) { if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD))
ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD;
spin_unlock_irqrestore(&ndlp->lock, iflags);
if (drop_initial_node_ref)
lpfc_nlp_put(ndlp); return;
}
if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) return;
/* Ignore callback for a mismatched (stale) rport */ if (ndlp->rport != rport) {
lpfc_vlog_msg(vport, KERN_WARNING, LOG_NODE, "6788 fc rport mismatch: d_id x%06x ndlp x%px " "fc rport x%px node rport x%px state x%x " "refcnt %u\n",
ndlp->nlp_DID, ndlp, rport, ndlp->rport,
ndlp->nlp_state, kref_read(&ndlp->kref)); return;
}
if (rport->port_name != wwn_to_u64(ndlp->nlp_portname.u.wwn))
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6789 rport name %llx != node port name %llx",
rport->port_name,
wwn_to_u64(ndlp->nlp_portname.u.wwn));
evtp = &ndlp->dev_loss_evt;
if (!list_empty(&evtp->evt_listp)) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6790 rport name %llx dev_loss_evt pending\n",
rport->port_name); return;
}
set_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag);
spin_lock_irqsave(&ndlp->lock, iflags); /* If there is a PLOGI in progress, and we are in a *NLP_NPR_2B_DISCstate,don'tturnofftheflag.
*/ if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE)
clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag);
if (phba->worker_thread) { /* We need to hold the node by incrementing the reference *countuntilthisqueuedworkisdone
*/
evtp->evt_arg1 = lpfc_nlp_get(ndlp);
spin_lock_irqsave(&phba->hbalock, iflags); if (evtp->evt_arg1) {
evtp->evt = LPFC_EVT_DEV_LOSS;
list_add_tail(&evtp->evt_listp, &phba->work_list);
spin_unlock_irqrestore(&phba->hbalock, iflags);
lpfc_worker_wake_up(phba); return;
}
spin_unlock_irqrestore(&phba->hbalock, iflags);
} else {
lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, "3188 worker thread is stopped %s x%06x, " " rport x%px flg x%lx load_flag x%lx refcnt " "%d\n", __func__, ndlp->nlp_DID,
ndlp->rport, ndlp->nlp_flag,
vport->load_flag, kref_read(&ndlp->kref)); if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) { /* Node is in dev loss. No further transaction. */
clear_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag);
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RM);
}
}
}
/* iterate through the table */
hash_for_each(vport->hash_table, bucket, vmp, hnode) {
keep = 0; if (vmp->flag & LPFC_VMID_REGISTERED) { /* check if the particular VMID is in use */ /* for all available per cpu variable */
for_each_possible_cpu(cpu) { /* if last access time is less than timeout */
lta = per_cpu_ptr(vmp->last_io_time, cpu); if (!lta) continue;
difftime = (jiffies) - (*lta); if ((vport->vmid_inactivity_timeout *
JIFFIES_PER_HR) > difftime) {
keep = 1; break;
}
}
/* if none of the cpus have been used by the vm, */ /* remove the entry if already registered */ if (!keep) { /* mark the entry for deregistration */
vmp->flag = LPFC_VMID_DE_REGISTER;
write_unlock(&vport->vmid_lock); if (vport->vmid_priority_tagging)
r = lpfc_vmid_uvem(vport, vmp, false); else
r = lpfc_vmid_cmd(vport,
SLI_CTAS_DAPP_IDENT,
vmp);
/* decrement number of active vms and mark */ /* entry in slot as free */
write_lock(&vport->vmid_lock); if (!r) { struct lpfc_vmid *ht = vmp;
/* Fabric nodes are done. */ if (ndlp->nlp_type & NLP_FABRIC) {
spin_lock_irqsave(&ndlp->lock, iflags);
/* The driver has to account for a race between any fabric *nodethat'sinrecoverywhendev_loss_tmoexpires.Whenthis *happens,thedriverhastoallownoderecovery.
*/ switch (ndlp->nlp_DID) { case Fabric_DID:
fc_vport = vport->fc_vport; if (fc_vport) { /* NPIV path. */ if (fc_vport->vport_state ==
FC_VPORT_INITIALIZING)
recovering = true;
} else { /* Physical port path. */ if (test_bit(HBA_FLOGI_OUTSTANDING,
&phba->hba_flag))
recovering = true;
} break; case Fabric_Cntl_DID: if (test_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag))
recovering = true; break; case FDMI_DID:
fallthrough; case NameServer_DID: if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE &&
ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE)
recovering = true; break; default: /* Ensure the nlp_DID at least has the correct prefix. *Thefabricdomaincontroller'slastthreenibbles *varysowehandleitinthedefaultcase.
*/ if (ndlp->nlp_DID & Fabric_DID_MASK) { if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE &&
ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE)
recovering = true;
} break;
}
spin_unlock_irqrestore(&ndlp->lock, iflags);
/* Mark an NLP_IN_RECOV_POST_DEV_LOSS flag to know if reversing *thefollowinglpfc_nlp_putisnecessaryafterfabricnodeis *recovered.
*/
clear_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag); if (recovering) {
lpfc_printf_vlog(vport, KERN_INFO,
LOG_DISCOVERY | LOG_NODE, "8436 Devloss timeout marked on " "DID x%x refcnt %d ndlp %p " "flag x%lx port_state = x%x\n",
ndlp->nlp_DID, kref_read(&ndlp->kref),
ndlp, ndlp->nlp_flag,
vport->port_state);
set_bit(NLP_IN_RECOV_POST_DEV_LOSS, &ndlp->save_flags); return fcf_inuse;
} elseif (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { /* Fabric node fully recovered before this dev_loss_tmo *queueworkisprocessed.Thus,ignorethe *dev_loss_tmoevent.
*/
lpfc_printf_vlog(vport, KERN_INFO,
LOG_DISCOVERY | LOG_NODE, "8437 Devloss timeout ignored on " "DID x%x refcnt %d ndlp %p " "flag x%lx port_state = x%x\n",
ndlp->nlp_DID, kref_read(&ndlp->kref),
ndlp, ndlp->nlp_flag,
vport->port_state); return fcf_inuse;
}
/* If we are devloss, but we are in the process of rediscovering the *ndlp,don'tissueaNLP_EVT_DEVICE_RMevent.
*/ if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE &&
ndlp->nlp_state <= NLP_STE_PRLI_ISSUE) { return fcf_inuse;
}
if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD))
lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
/* First, try to post the next mailbox command to SLI4 device */ if (phba->pci_dev_grp == LPFC_PCI_DEV_OC && !hba_pci_err)
lpfc_sli4_post_async_mbox(phba);
if (ha_copy & HA_ERATT) { /* Handle the error attention event */
lpfc_handle_eratt(phba);
if (phba->fw_dump_cmpl) {
complete(phba->fw_dump_cmpl);
phba->fw_dump_cmpl = NULL;
}
}
if (ha_copy & HA_MBATT)
lpfc_sli_handle_mb_event(phba);
/* Process SLI4 events */ if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) { if (test_bit(HBA_RRQ_ACTIVE, &phba->hba_flag))
lpfc_handle_rrq_active(phba); if (test_bit(ELS_XRI_ABORT_EVENT, &phba->hba_flag))
lpfc_sli4_els_xri_abort_event_proc(phba); if (test_bit(ASYNC_EVENT, &phba->hba_flag))
lpfc_sli4_async_event_proc(phba); if (test_and_clear_bit(HBA_POST_RECEIVE_BUFFER,
&phba->hba_flag))
lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); if (phba->fcf.fcf_flag & FCF_REDISC_EVT)
lpfc_sli4_fcf_redisc_event_proc(phba);
}
vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for (i = 0; i <= phba->max_vports; i++) { /* *Wecouldhavenovportsinarrayifunloading,soif *thishappensthenjustusethepport
*/ if (vports[i] == NULL && i == 0)
vport = phba->pport; else
vport = vports[i]; if (vport == NULL) break;
spin_lock_irq(&vport->work_port_lock);
work_port_events = vport->work_port_events;
vport->work_port_events &= ~work_port_events;
spin_unlock_irq(&vport->work_port_lock); if (hba_pci_err) continue; if (work_port_events & WORKER_DISC_TMO)
lpfc_disc_timeout_handler(vport); if (work_port_events & WORKER_ELS_TMO)
lpfc_els_timeout_handler(vport); if (work_port_events & WORKER_HB_TMO)
lpfc_hb_timeout_handler(phba); if (work_port_events & WORKER_MBOX_TMO)
lpfc_mbox_timeout_handler(phba); if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
lpfc_unblock_fabric_iocbs(phba); if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
lpfc_ramp_down_queue_handler(phba); if (work_port_events & WORKER_DELAYED_DISC_TMO)
lpfc_delayed_disc_timeout_handler(vport);
}
lpfc_destroy_vport_work_array(phba, vports);
pring = lpfc_phba_elsring(phba);
status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING)));
status >>= (4*LPFC_ELS_RING); if (pring && (status & HA_RXMASK ||
pring->flag & LPFC_DEFERRED_RING_EVENT ||
test_bit(HBA_SP_QUEUE_EVT, &phba->hba_flag))) { if (pring->flag & LPFC_STOP_IOCB_EVENT) {
pring->flag |= LPFC_DEFERRED_RING_EVENT; /* Preserve legacy behavior. */ if (!test_bit(HBA_SP_QUEUE_EVT, &phba->hba_flag))
set_bit(LPFC_DATA_READY, &phba->data_flags);
} else { /* Driver could have abort request completed in queue *whenlinkgoesdown.Allowforthistransition.
*/ if (phba->link_state >= LPFC_LINK_DOWN ||
phba->link_flag & LS_MDS_LOOPBACK) {
pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
lpfc_sli_handle_slow_ring_event(phba, pring,
(status &
HA_RXMASK));
}
} if (phba->sli_rev == LPFC_SLI_REV4)
lpfc_drain_txq(phba); /* *TurnonRinginterrupts
*/ if (phba->sli_rev <= LPFC_SLI_REV3) {
spin_lock_irq(&phba->hbalock);
control = readl(phba->HCregaddr); if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) {
lpfc_debugfs_slow_ring_trc(phba, "WRK Enable ring: cntl:x%x hacopy:x%x",
control, ha_copy, 0);
/* Leave Fabric nodes alone on link down */ if ((phba->sli_rev < LPFC_SLI_REV4) &&
(!remove && ndlp->nlp_type & NLP_FABRIC)) continue;
/* Notify transport of connectivity loss to trigger cleanup. */ if (phba->nvmet_support &&
ndlp->nlp_state == NLP_STE_UNMAPPED_NODE)
lpfc_nvmet_invalidate_host(phba, ndlp);
/* Decrement the held ndlp if there is a deferred flogi acc */ if (phba->defer_flogi_acc.flag) { if (phba->defer_flogi_acc.ndlp) {
lpfc_nlp_put(phba->defer_flogi_acc.ndlp);
phba->defer_flogi_acc.ndlp = NULL;
}
}
phba->defer_flogi_acc.flag = false;
/* reinitialize initial HBA flag */
clear_bit(HBA_FLOGI_ISSUED, &phba->hba_flag);
clear_bit(HBA_RHBA_CMPL, &phba->hba_flag);
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; if (ndlp->nlp_type & NLP_FABRIC) { /* On Linkup its safe to clean up the ndlp *fromFabricconnections.
*/ if (ndlp->nlp_DID != Fabric_DID)
lpfc_unreg_rpi(vport, ndlp);
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
} elseif (!test_bit(NLP_NPR_ADISC, &ndlp->nlp_flag)) { /* Fail outstanding IO now since device is *markedforPLOGI.
*/
lpfc_unreg_rpi(vport, ndlp);
}
}
}
/* Unblock fabric iocbs if they are blocked */
clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
timer_delete_sync(&phba->fabric_block_timer);
vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
lpfc_linkup_port(vports[i]);
lpfc_destroy_vport_work_array(phba, vports);
/* Clear the pport flogi counter in case the link down was *absorbedwithoutanACQE.Nolockhere-inworkerthread *anddiscoveryissynchronized.
*/
spin_lock_irq(shost->host_lock);
phba->pport->rcv_flogi_cnt = 0;
spin_unlock_irq(shost->host_lock);
/* Since we don't do discovery right now, turn these off here */
psli->sli3_ring[LPFC_EXTRA_RING].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->sli3_ring[LPFC_FCP_RING].flag &= ~LPFC_STOP_IOCB_EVENT;
/* Check for error */ if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) { /* CLEAR_LA mbox error <mbxStatus> state <hba_state> */
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0320 CLEAR_LA mbxStatus error x%x hba " "state x%x\n",
mb->mbxStatus, vport->port_state);
phba->link_state = LPFC_HBA_ERROR; goto out;
}
if (vport->port_type == LPFC_PHYSICAL_PORT)
phba->link_state = LPFC_HBA_READY;
spin_lock_irq(&phba->hbalock);
psli->sli_flag |= LPFC_PROCESS_LA;
control = readl(phba->HCregaddr);
control |= HC_LAINT_ENA;
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
spin_unlock_irq(&phba->hbalock);
mempool_free(pmb, phba->mbox_mem_pool); return;
spin_lock_irq(&phba->hbalock);
psli->sli_flag |= LPFC_PROCESS_LA;
control = readl(phba->HCregaddr);
control |= HC_LAINT_ENA;
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
spin_unlock_irq(&phba->hbalock);
return;
}
void
lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{ struct lpfc_vport *vport = pmb->vport;
LPFC_MBOXQ_t *sparam_mb;
u16 status = pmb->u.mb.mbxStatus; int rc;
mempool_free(pmb, phba->mbox_mem_pool);
if (status) goto out;
/* don't perform discovery for SLI4 loopback diagnostic test */ if ((phba->sli_rev == LPFC_SLI_REV4) &&
!test_bit(HBA_FCOE_MODE, &phba->hba_flag) &&
(phba->link_flag & LS_LOOPBACK_MODE)) return;
if (phba->fc_topology == LPFC_TOPOLOGY_LOOP &&
test_bit(FC_PUBLIC_LOOP, &vport->fc_flag) &&
!test_bit(FC_LBIT, &vport->fc_flag)) { /* Need to wait for FAN - use discovery timer *fortimeout.port_stateisidentically *LPFC_LOCAL_CFG_LINKwhilewaitingforFAN
*/
lpfc_set_disctmo(vport); return;
}
/* Start discovery by sending a FLOGI. port_state is identically *LPFC_FLOGIwhilewaitingforFLOGIcmpl.
*/ if (vport->port_state != LPFC_FLOGI) { /* Issue MBX_READ_SPARAM to update CSPs before FLOGI if *bb-creditrecoveryisinplace.
*/ if (phba->bbcredit_support && phba->cfg_enable_bbcr &&
!(phba->link_flag & LS_LOOPBACK_MODE)) {
sparam_mb = mempool_alloc(phba->mbox_mem_pool,
GFP_KERNEL); if (!sparam_mb) goto sparam_out;
if (mboxq->u.mb.mbxStatus) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2017 REG_FCFI mbxStatus error x%x " "HBA state x%x\n", mboxq->u.mb.mbxStatus,
vport->port_state); goto fail_out;
}
/* Start FCoE discovery by sending a FLOGI. */
phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, &mboxq->u.mqe.un.reg_fcfi); /* Set the FCFI registered flag */
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag |= FCF_REGISTERED;
spin_unlock_irq(&phba->hbalock);
/* If there is a pending FCoE event, restart FCF table scan. */ if (!test_bit(FCF_RR_INPROG, &phba->hba_flag) &&
lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF)) goto fail_out;
/* Mark successful completion of FCF table scan */
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE);
spin_unlock_irq(&phba->hbalock);
clear_bit(FCF_TS_INPROG, &phba->hba_flag); if (vport->port_state != LPFC_FLOGI) {
set_bit(FCF_RR_INPROG, &phba->hba_flag);
lpfc_issue_init_vfi(vport);
} goto out;
spin_lock_irq(&phba->hbalock); /* If the FCF is not available do nothing. */ if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) {
spin_unlock_irq(&phba->hbalock);
clear_bit(FCF_TS_INPROG, &phba->hba_flag);
clear_bit(FCF_RR_INPROG, &phba->hba_flag); return;
}
/* The FCF is already registered, start discovery */ if (phba->fcf.fcf_flag & FCF_REGISTERED) {
phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE);
spin_unlock_irq(&phba->hbalock);
clear_bit(FCF_TS_INPROG, &phba->hba_flag); if (phba->pport->port_state != LPFC_FLOGI &&
test_bit(FC_FABRIC, &phba->pport->fc_flag)) {
set_bit(FCF_RR_INPROG, &phba->hba_flag);
lpfc_initial_flogi(phba->pport); return;
} return;
}
spin_unlock_irq(&phba->hbalock);
/* Find the lowest VLAN id in the FCF record */
for (i = 0; i < 512; i++) {
if (new_fcf_record->vlan_bitmap[i]) {
fcf_vlan_id = i * 8;
j = 0;
while (!((new_fcf_record->vlan_bitmap[i] >> j) & 1)) {
j++;
fcf_vlan_id++;
}
break;
}
}
/* FCF not valid/available or solicitation in progress */
if (!bf_get(lpfc_fcf_record_fcf_avail, new_fcf_record) || !bf_get(lpfc_fcf_record_fcf_valid, new_fcf_record) ||
bf_get(lpfc_fcf_record_fcf_sol, new_fcf_record))
return 0;
/* If matching connect list has a vlan id, use it */
if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID)
*vlan_id = conn_entry->conn_rec.vlan_tag; /* *Ifnovlanidisspecifiedinconnectlist,usethevlanid *intheFCFrecord
*/
else if (fcf_vlan_id)
*vlan_id = fcf_vlan_id;
else
*vlan_id = LPFC_FCOE_NULL_VID;
return 1;
}
return 0;
}
/** *lpfc_check_pending_fcoe_event-Checkifthereispendingfcoeevent. *@phba:pointertolpfchbadatastructure. *@unreg_fcf:UnregisterFCFifFCFtableneedtobere-scaned. * *Thisfunctioncheckifthereisanyfcoeeventworldwidenon-no-charge-freeirrevocable *scanFCFentries.If *FCFsaningandreturn1elsereturn0. / int lpfc_check_pending_fcoe_event(structlpfc_hba*phba,uint8_tunreg_fcf) { /* *IftheLinkisupwithinthirdarchivesjava.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46 *FCFdiscovery,noneedtorestartFCFdiscovery.
*/
if ((phba->link_state >= LPFC_LINK_UP) &&
(phba->fcoe_eventtag == phba->fcoe_eventtag_at_fcf_scan))
return 0;
lpfc_printf_log(phba, KERN_INFO, LOG_FIP, "2768 Pending link or FCF event during current " "handling of the previous event: link_state:x%x, " "evt_tag_at_scan:x%x, evt_tag_current:x%x\n",
phba->link_state, phba->fcoe_eventtag_at_fcf_scan,
phba->fcoe_eventtag);
if (phba->link_state >= LPFC_LINK_UP) {
lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
"2780 Restart FCF table scan due to "
"pending FCF event:evt_tag_at_scan:x%x, "
"evt_tag_current:x%x\n",
phba->fcoe_eventtag_at_fcf_scan,
phba->fcoe_eventtag);
lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
} else {
/*
* Do not continue FCF discovery and clear FCF_TS_INPROG
* flag
*/
lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
"2833 Stop FCF discovery process due to link "
"state change (x%x)\n", phba->link_state);
clear_bit(FCF_TS_INPROG, &phba->hba_flag);
clear_bit(FCF_RR_INPROG, &phba->hba_flag);
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY);
spin_unlock_irq(&phba->hbalock);
}
/* Unregister the currently registered FCF if required */
if (unreg_fcf) {
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_REGISTERED;
spin_unlock_irq(&phba->hbalock);
lpfc_sli4_unregister_fcf(phba);
}
return 1;
}
/**
* lpfc_sli4_new_fcf_random_select - Randomly select an eligible new fcf record
* @phba: pointer to lpfc hba data structure.
* @fcf_cnt: number of eligible fcf record seen so far.
*
* This function makes an running random selection decision on FCF record to
* use through a sequence of @fcf_cnt eligible FCF records with equal
* probability. To perform integer manunipulation of random numbers with
* size unit32_t, a 16-bit random number returned from get_random_u16() is
* taken as the random random number generated.
*
* Returns true when outcome is for the newly read FCF record should be
* chosen; otherwise, return false when outcome is for keeping the previously
* chosen FCF record.
**/
static bool
lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt)
{
uint32_t rand_num;
/* Get 16-bit uniform random number */
rand_num = get_random_u16();
/* Decision with probability 1/fcf_cnt */ if ((fcf_cnt * rand_num) < 0xFFFF) returntrue; else returnfalse;
}
/* Get the first SGE entry from the non-embedded DMA memory. This *routineonlyusesasingleSGE.
*/
lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); if (unlikely(!mboxq->sge_array)) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2524 Failed to get the non-embedded SGE " "virtual address\n"); return NULL;
}
virt_addr = mboxq->sge_array->addr[0];
last_index = find_first_bit(phba->fcf.fcf_rr_bmask,
LPFC_SLI4_FCF_TBL_INDX_MAX); if (last_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
ret = 0; /* Empty rr list */ goto out;
}
current_fcf_pri = phba->fcf.fcf_pri[last_index].fcf_rec.priority; if (new_fcf_pri->fcf_rec.priority <= current_fcf_pri) {
list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list); if (new_fcf_pri->fcf_rec.priority < current_fcf_pri) {
memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask)); /* fcfs_at_this_priority_level = 1; */
phba->fcf.eligible_fcf_cnt = 1;
} else /* fcfs_at_this_priority_level++; */
phba->fcf.eligible_fcf_cnt++;
ret = lpfc_sli4_fcf_rr_index_set(phba,
new_fcf_pri->fcf_rec.fcf_index); goto out;
}
list_for_each_entry_safe(fcf_pri, next_fcf_pri,
&phba->fcf.fcf_pri_list, list) { if (new_fcf_pri->fcf_rec.priority <=
fcf_pri->fcf_rec.priority) { if (fcf_pri->list.prev == &phba->fcf.fcf_pri_list)
list_add(&new_fcf_pri->list,
&phba->fcf.fcf_pri_list); else
list_add(&new_fcf_pri->list,
&((struct lpfc_fcf_pri *)
fcf_pri->list.prev)->list);
ret = 0; goto out;
} elseif (fcf_pri->list.next == &phba->fcf.fcf_pri_list
|| new_fcf_pri->fcf_rec.priority <
next_fcf_pri->fcf_rec.priority) {
list_add(&new_fcf_pri->list, &fcf_pri->list);
ret = 0; goto out;
} if (new_fcf_pri->fcf_rec.priority > fcf_pri->fcf_rec.priority) continue;
}
ret = 1;
out: /* we use = instead of |= to clear the FLOGI_FAILED flag. */
new_fcf_pri->fcf_rec.flag = LPFC_FCF_ON_PRI_LIST;
spin_unlock_irq(&phba->hbalock); return ret;
}
/* If there is pending FCoE event restart FCF table scan */ if (lpfc_check_pending_fcoe_event(phba, LPFC_SKIP_UNREG_FCF)) {
lpfc_sli4_mbox_cmd_free(phba, mboxq); return;
}
/* Parse the FCF record from the non-embedded mailbox command */
new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq,
&next_fcf_index); if (!new_fcf_record) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2765 Mailbox command READ_FCF_RECORD " "failed to retrieve a FCF record.\n"); /* Let next new FCF event trigger fast failover */
clear_bit(FCF_TS_INPROG, &phba->hba_flag);
lpfc_sli4_mbox_cmd_free(phba, mboxq); return;
}
/* Check the FCF record against the connection list */
rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
&addr_mode, &vlan_id);
/* Log the FCF record information if turned on */
lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id,
next_fcf_index);
/* If link state is not up, stop the roundrobin failover process */ if (phba->link_state < LPFC_LINK_UP) {
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
spin_unlock_irq(&phba->hbalock);
clear_bit(FCF_RR_INPROG, &phba->hba_flag); goto out;
}
/* Parse the FCF record from the non-embedded mailbox command */
new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq,
&next_fcf_index); if (!new_fcf_record) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, "2766 Mailbox command READ_FCF_RECORD " "failed to retrieve a FCF record. " "hba_flg x%lx fcf_flg x%x\n", phba->hba_flag,
phba->fcf.fcf_flag);
lpfc_unregister_fcf_rescan(phba); goto out;
}
/* Get the needed parameters from FCF record */
rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
&addr_mode, &vlan_id);
/* Log the FCF record information if turned on */
lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id,
next_fcf_index);
fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); if (!rc) {
lpfc_printf_log(phba, KERN_INFO, LOG_FIP, "2848 Remove ineligible FCF (x%x) from " "from roundrobin bmask\n", fcf_index); /* Clear roundrobin bmask bit for ineligible FCF */
lpfc_sli4_fcf_rr_index_clear(phba, fcf_index); /* Perform next round of roundrobin FCF failover */
fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);
rc = lpfc_sli4_fcf_rr_next_proc(phba->pport, fcf_index); if (rc) goto out; goto error_out;
}
if (fcf_index == phba->fcf.current_rec.fcf_indx) {
lpfc_printf_log(phba, KERN_INFO, LOG_FIP, "2760 Perform FLOGI roundrobin FCF failover: " "FCF (x%x) back to FCF (x%x)\n",
phba->fcf.current_rec.fcf_indx, fcf_index); /* Wait 500 ms before retrying FLOGI to current FCF */
msleep(500);
lpfc_issue_init_vfi(phba->pport); goto out;
}
/* Upload new FCF record to the failover FCF record */
lpfc_printf_log(phba, KERN_INFO, LOG_FIP, "2834 Update current FCF (x%x) with new FCF (x%x)\n",
phba->fcf.failover_rec.fcf_indx, fcf_index);
spin_lock_irq(&phba->hbalock);
__lpfc_update_fcf_record(phba, &phba->fcf.failover_rec,
new_fcf_record, addr_mode, vlan_id,
(boot_flag ? BOOT_ENABLE : 0));
spin_unlock_irq(&phba->hbalock);
/* If this port is physical port or FDISC is done, do reg_vpi */ if ((phba->pport == vport) || (vport->port_state == LPFC_FDISC)) {
ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp)
lpfc_printf_vlog(vport, KERN_ERR,
LOG_TRACE_EVENT, "2731 Cannot find fabric " "controller node\n"); else
lpfc_register_new_vport(phba, vport, ndlp);
mempool_free(mboxq, phba->mbox_mem_pool); return;
}
/* *VFInotsupportedforinterfacetype0,soignoreanymailbox *error(exceptVFIinuse)andcontinuewiththediscovery.
*/ if (mboxq->u.mb.mbxStatus &&
(bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
LPFC_SLI_INTF_IF_TYPE_0) &&
mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "2018 REG_VFI mbxStatus error x%x " "HBA state x%x\n",
mboxq->u.mb.mbxStatus, vport->port_state); if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { /* FLOGI failed, use loop map to make discovery list */
lpfc_disc_list_loopmap(vport); /* Start discovery */
lpfc_disc_start(vport); goto out_free_mem;
}
lpfc_vport_set_state(vport, FC_VPORT_FAILED); goto out_free_mem;
}
/* If the VFI is already registered, there is nothing else to do *UnlessthiswasaVFIupdateandweareinPT2PTmode,then *weshoulddropthroughtosettheportstatetoready.
*/ if (test_bit(FC_VFI_REGISTERED, &vport->fc_flag)) if (!(phba->sli_rev == LPFC_SLI_REV4 &&
test_bit(FC_PT2PT, &vport->fc_flag))) goto out_free_mem;
/* The VPI is implicitly registered when the VFI is registered */
set_bit(FC_VFI_REGISTERED, &vport->fc_flag);
clear_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag);
clear_bit(FC_VPORT_NEEDS_INIT_VPI, &vport->fc_flag);
spin_lock_irq(shost->host_lock);
vport->vpi_state |= LPFC_VPI_REGISTERED;
spin_unlock_irq(shost->host_lock);
/* In case SLI4 FC loopback test, we are ready */ if ((phba->sli_rev == LPFC_SLI_REV4) &&
(phba->link_flag & LS_LOOPBACK_MODE)) {
phba->link_state = LPFC_HBA_READY; goto out_free_mem;
}
/* Check if sending the FLOGI is being deferred to after we get *uptodateCSPsfromMBX_READ_SPARAM.
*/ if (test_bit(HBA_DEFER_FLOGI, &phba->hba_flag)) {
lpfc_initial_flogi(vport);
clear_bit(HBA_DEFER_FLOGI, &phba->hba_flag);
} return;
if (!test_bit(HBA_FCOE_MODE, &phba->hba_flag)) { switch (bf_get(lpfc_mbx_read_top_link_spd, la)) { case LPFC_LINK_SPEED_1GHZ: case LPFC_LINK_SPEED_2GHZ: case LPFC_LINK_SPEED_4GHZ: case LPFC_LINK_SPEED_8GHZ: case LPFC_LINK_SPEED_10GHZ: case LPFC_LINK_SPEED_16GHZ: case LPFC_LINK_SPEED_32GHZ: case LPFC_LINK_SPEED_64GHZ: case LPFC_LINK_SPEED_128GHZ: case LPFC_LINK_SPEED_256GHZ: break; default:
phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN; break;
}
}
if (phba->fc_topology &&
phba->fc_topology != bf_get(lpfc_mbx_read_top_topology, la)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
"3314 Topology changed was 0x%x is 0x%x\n",
phba->fc_topology,
bf_get(lpfc_mbx_read_top_topology, la));
phba->fc_topology_changed = 1;
}
if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
/* if npiv is enabled and this adapter supports npiv log
* a message that npiv is not supported in this topology
*/
if (phba->cfg_enable_npiv && phba->max_vpi)
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"1309 Link Up Event npiv not supported in loop "
"topology\n");
/* Get Loop Map information */
if (bf_get(lpfc_mbx_read_top_il, la))
set_bit(FC_LBIT, &vport->fc_flag);
vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la);
i = la->lilpBde64.tus.f.bdeSize;
if (i == 0) {
phba->alpa_map[0] = 0;
} else {
if (vport->cfg_log_verbose & LOG_LINK_EVENT) {
int numalpa, j, k;
union {
uint8_t pamap[16];
struct {
uint32_t wd1;
uint32_t wd2;
uint32_t wd3;
uint32_t wd4;
} pa;
} un;
numalpa = phba->alpa_map[0];
j = 0;
while (j < numalpa) {
memset(un.pamap, 0, 16);
for (k = 1; j < numalpa; k++) {
un.pamap[k - 1] =
phba->alpa_map[j + 1];
j++;
if (k == 16)
break;
}
/* Link Up Event ALPA map */
lpfc_printf_log(phba,
KERN_WARNING,
LOG_LINK_EVENT,
"1304 Link Up Event "
"ALPA map Data: x%x "
"x%x x%x x%x\n",
un.pa.wd1, un.pa.wd2,
un.pa.wd3, un.pa.wd4);
}
}
}
} else {
if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
if (phba->max_vpi && phba->cfg_enable_npiv &&
(phba->sli_rev >= LPFC_SLI_REV3))
phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
}
vport->fc_myDID = phba->fc_pref_DID;
set_bit(FC_LBIT, &vport->fc_flag);
}
spin_unlock_irqrestore(&phba->hbalock, iflags);
lpfc_linkup(phba);
sparam_mbox = NULL;
sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!sparam_mbox)
goto out;
static void
lpfc_mbx_issue_link_down(struct lpfc_hba *phba)
{
lpfc_linkdown(phba);
lpfc_enable_la(phba);
lpfc_unregister_unused_fcf(phba);
/* turn on Link Attention interrupts - no CLEAR_LA needed */
}
/*
* This routine handles processing a READ_TOPOLOGY mailbox
* command upon completion. It is setup in the LPFC_MBOXQ
* as the completion routine when the command is
* handed off to the SLI layer. SLI4 only.
*/
void
lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
struct lpfc_mbx_read_top *la;
struct lpfc_sli_ring *pring;
MAILBOX_t *mb = &pmb->u.mb;
struct lpfc_dmabuf *mp = pmb->ctx_buf;
uint8_t attn_type;
/* Unblock ELS traffic */
pring = lpfc_phba_elsring(phba);
if (pring)
pring->flag &= ~LPFC_STOP_IOCB_EVENT;
/* Check for error */
if (mb->mbxStatus) {
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
"1307 READ_LA mbox error x%x state x%x\n",
mb->mbxStatus, vport->port_state);
lpfc_mbx_issue_link_down(phba);
phba->link_state = LPFC_HBA_ERROR;
goto lpfc_mbx_cmpl_read_topology_free_mbuf;
}
la = (struct lpfc_mbx_read_top *) &pmb->u.mb.un.varReadTop;
attn_type = bf_get(lpfc_mbx_read_top_att_type, la);
memcpy(&phba->alpa_map[0], mp->virt, 128);
if (bf_get(lpfc_mbx_read_top_pb, la))
set_bit(FC_BYPASSED_MODE, &vport->fc_flag);
else
clear_bit(FC_BYPASSED_MODE, &vport->fc_flag);
if (phba->fc_eventTag <= la->eventTag) {
phba->fc_stat.LinkMultiEvent++;
if (attn_type == LPFC_ATT_LINK_UP)
if (phba->fc_eventTag != 0)
lpfc_linkdown(phba);
}
phba->fc_eventTag = la->eventTag;
phba->link_events++;
if (attn_type == LPFC_ATT_LINK_UP) {
phba->fc_stat.LinkUp++;
if (phba->link_flag & LS_LOOPBACK_MODE) {
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"1306 Link Up Event in loop back mode "
"x%x received Data: x%x x%x x%x x%x\n",
la->eventTag, phba->fc_eventTag,
bf_get(lpfc_mbx_read_top_alpa_granted,
la),
bf_get(lpfc_mbx_read_top_link_spd, la),
phba->alpa_map[0]);
} else {
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"1303 Link Up Event x%x received "
"Data: x%x x%x x%x x%x x%x\n",
la->eventTag, phba->fc_eventTag,
bf_get(lpfc_mbx_read_top_alpa_granted,
la),
bf_get(lpfc_mbx_read_top_link_spd, la),
phba->alpa_map[0],
bf_get(lpfc_mbx_read_top_fa, la));
}
lpfc_mbx_process_link_up(phba, la);
if (phba->cmf_active_mode != LPFC_CFG_OFF)
lpfc_cmf_signal_init(phba);
if (phba->lmt & LMT_64Gb)
lpfc_read_lds_params(phba);
} else if (attn_type == LPFC_ATT_LINK_DOWN ||
attn_type == LPFC_ATT_UNEXP_WWPN) {
phba->fc_stat.LinkDown++;
if (phba->link_flag & LS_LOOPBACK_MODE)
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"1308 Link Down Event in loop back mode "
"x%x received "
"Data: x%x x%x x%lx\n",
la->eventTag, phba->fc_eventTag,
phba->pport->port_state, vport->fc_flag);
else if (attn_type == LPFC_ATT_UNEXP_WWPN)
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"1313 Link Down Unexpected FA WWPN Event x%x "
"received Data: x%x x%x x%lx x%x\n",
la->eventTag, phba->fc_eventTag,
phba->pport->port_state, vport->fc_flag,
bf_get(lpfc_mbx_read_top_fa, la));
else
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"1305 Link Down Event x%x received "
"Data: x%x x%x x%lx x%x\n",
la->eventTag, phba->fc_eventTag,
phba->pport->port_state, vport->fc_flag,
bf_get(lpfc_mbx_read_top_fa, la));
lpfc_mbx_issue_link_down(phba);
}
if ((phba->sli_rev < LPFC_SLI_REV4) &&
bf_get(lpfc_mbx_read_top_fa, la))
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
"1311 fa %d\n",
bf_get(lpfc_mbx_read_top_fa, la));
/*
* This routine handles processing a REG_LOGIN mailbox
* command upon completion. It is setup in the LPFC_MBOXQ
* as the completion routine when the command is
* handed off to the SLI layer.
*/
void
lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
struct lpfc_dmabuf *mp = pmb->ctx_buf;
struct lpfc_nodelist *ndlp = pmb->ctx_ndlp;
/* The driver calls the state machine with the pmb pointer
* but wants to make sure a stale ctx_buf isn't acted on.
* The ctx_buf is restored later and cleaned up.
*/
pmb->ctx_buf = NULL;
pmb->ctx_ndlp = NULL;
if (test_bit(NLP_IGNR_REG_CMPL, &ndlp->nlp_flag) ||
ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) {
/* We rcvd a rscn after issuing this
* mbox reg login, we may have cycled
* back through the state and be
* back at reg login state so this
* mbox needs to be ignored becase
* there is another reg login in
* process.
*/
clear_bit(NLP_IGNR_REG_CMPL, &ndlp->nlp_flag);
/*
* We cannot leave the RPI registered because
* if we go thru discovery again for this ndlp
* a subsequent REG_RPI will fail.
*/
set_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag);
lpfc_unreg_rpi(vport, ndlp);
}
switch (mb->mbxStatus) {
case 0x0011:
case 0x0020:
lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
"0911 cmpl_unreg_vpi, mb status = 0x%x\n",
mb->mbxStatus);
break;
/* If VPI is busy, reset the HBA */
case 0x9700:
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
"2798 Unreg_vpi failed vpi 0x%x, mb status = 0x%x\n",
vport->vpi, mb->mbxStatus);
if (!test_bit(FC_UNLOADING, &phba->pport->load_flag))
lpfc_workq_post_event(phba, NULL, NULL,
LPFC_EVT_RESET_HBA);
}
set_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag);
spin_lock_irq(shost->host_lock);
vport->vpi_state &= ~LPFC_VPI_REGISTERED;
spin_unlock_irq(shost->host_lock);
mempool_free(pmb, phba->mbox_mem_pool);
lpfc_cleanup_vports_rrqs(vport, NULL);
/*
* This shost reference might have been taken at the beginning of
* lpfc_vport_delete()
*/
if (test_bit(FC_UNLOADING, &vport->load_flag) && vport != phba->pport)
scsi_host_put(shost);
}
int
lpfc_mbx_unreg_vpi(struct lpfc_vport *vport)
{
struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *mbox;
int rc;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
return 1;
switch (mb->mbxStatus) {
case 0x0011:
case 0x9601:
case 0x9602:
lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
"0912 cmpl_reg_vpi, mb status = 0x%x\n",
mb->mbxStatus);
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
clear_bit(FC_FABRIC, &vport->fc_flag);
clear_bit(FC_PUBLIC_LOOP, &vport->fc_flag);
vport->fc_myDID = 0;
if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
(vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) {
if (phba->nvmet_support)
lpfc_nvmet_update_targetport(phba);
else
lpfc_nvme_update_localport(vport);
}
goto out;
}
clear_bit(FC_VPORT_NEEDS_REG_VPI, &vport->fc_flag);
spin_lock_irq(shost->host_lock);
vport->vpi_state |= LPFC_VPI_REGISTERED;
spin_unlock_irq(shost->host_lock);
vport->num_disc_nodes = 0;
/* go thru NPR list and issue ELS PLOGIs */
if (atomic_read(&vport->fc_npr_cnt))
lpfc_els_disc_plogi(vport);
if (!vport->num_disc_nodes) {
clear_bit(FC_NDISC_ACTIVE, &vport->fc_flag);
lpfc_can_disctmo(vport);
}
vport->port_state = LPFC_VPORT_READY;
/**
* lpfc_create_static_vport - Read HBA config region to create static vports.
* @phba: pointer to lpfc hba data structure.
*
* This routine issue a DUMP mailbox command for config region 22 to get
* the list of static vports to be created. The function create vports
* based on the information returned from the HBA.
**/
void
lpfc_create_static_vport(struct lpfc_hba *phba)
{
LPFC_MBOXQ_t *pmb = NULL;
MAILBOX_t *mb;
struct static_vport_info *vport_info;
int mbx_wait_rc = 0, i;
struct fc_vport_identifiers vport_id;
struct fc_vport *new_fc_vport;
struct Scsi_Host *shost;
struct lpfc_vport *vport;
uint16_t offset = 0;
uint8_t *vport_buff;
struct lpfc_dmabuf *mp;
uint32_t byte_count = 0;
vport_buff = (uint8_t *) vport_info;
do {
/* While loop iteration forces a free dma buffer from
* the previous loop because the mbox is reused and
* the dump routine is a single-use construct.
*/
if (pmb->ctx_buf) {
mp = pmb->ctx_buf;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
pmb->ctx_buf = NULL;
}
if (lpfc_dump_static_vport(phba, pmb, offset))
goto out;
out:
kfree(vport_info);
if (mbx_wait_rc != MBX_TIMEOUT)
lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
}
/*
* This routine handles processing a Fabric REG_LOGIN mailbox
* command upon completion. It is setup in the LPFC_MBOXQ
* as the completion routine when the command is
* handed off to the SLI layer.
*/
void
lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
MAILBOX_t *mb = &pmb->u.mb;
struct lpfc_nodelist *ndlp = pmb->ctx_ndlp;
pmb->ctx_ndlp = NULL;
if (mb->mbxStatus) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
"0258 Register Fabric login error: 0x%x\n",
mb->mbxStatus);
lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
/* FLOGI failed, use loop map to make discovery list */
lpfc_disc_list_loopmap(vport);
/* Start discovery */
lpfc_disc_start(vport);
/* Decrement the reference count to ndlp after the
* reference to the ndlp are done.
*/
lpfc_nlp_put(ndlp);
return;
}
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
/* Decrement the reference count to ndlp after the reference
* to the ndlp are done.
*/
lpfc_nlp_put(ndlp);
return;
}
if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
/* when physical port receive logo donot start
* vport discovery */
if (!test_and_clear_bit(FC_LOGO_RCVD_DID_CHNG, &vport->fc_flag))
lpfc_start_fdiscs(phba);
lpfc_do_scr_ns_plogi(phba, vport);
}
/* Drop the reference count from the mbox at the end after
* all the current reference to the ndlp have been done.
*/
lpfc_nlp_put(ndlp);
return;
}
/*
* This routine will issue a GID_FT for each FC4 Type supported
* by the driver. ALL GID_FTs must complete before discovery is started.
*/
int
lpfc_issue_gidft(struct lpfc_vport *vport)
{
/* Good status, issue CT Request to NameServer */
if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
(vport->cfg_enable_fc4_type == LPFC_ENABLE_FCP)) {
if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, SLI_CTPT_FCP)) {
/* Cannot issue NameServer FCP Query, so finish up
* discovery
*/
lpfc_printf_vlog(vport, KERN_ERR,
LOG_TRACE_EVENT,
"0604 %s FC TYPE %x %s\n",
"Failed to issue GID_FT to ",
FC_TYPE_FCP,
"Finishing discovery.");
return 0;
}
vport->gidft_inp++;
}
if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
(vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) {
if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, SLI_CTPT_NVME)) {
/* Cannot issue NameServer NVME Query, so finish up
* discovery
*/
lpfc_printf_vlog(vport, KERN_ERR,
LOG_TRACE_EVENT,
"0605 %s FC_TYPE %x %s %d\n",
"Failed to issue GID_FT to ",
FC_TYPE_NVME,
"Finishing discovery: gidftinp ",
vport->gidft_inp);
if (vport->gidft_inp == 0)
return 0;
} else
vport->gidft_inp++;
}
return vport->gidft_inp;
}
/**
* lpfc_issue_gidpt - issue a GID_PT for all N_Ports
* @vport: The virtual port for which this call is being executed.
*
* This routine will issue a GID_PT to get a list of all N_Ports
*
* Return value :
* 0 - Failure to issue a GID_PT
* 1 - GID_PT issued
**/
int
lpfc_issue_gidpt(struct lpfc_vport *vport)
{
/* Good status, issue CT Request to NameServer */
if (lpfc_ns_cmd(vport, SLI_CTNS_GID_PT, 0, GID_PT_N_PORT)) {
/* Cannot issue NameServer FCP Query, so finish up
* discovery
*/
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
"0606 %s Port TYPE %x %s\n",
"Failed to issue GID_PT to ",
GID_PT_N_PORT,
"Finishing discovery.");
return 0;
}
vport->gidft_inp++;
return 1;
}
/*
* This routine handles processing a NameServer REG_LOGIN mailbox
* command upon completion. It is setup in the LPFC_MBOXQ
* as the completion routine when the command is
* handed off to the SLI layer.
*/
void
lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
MAILBOX_t *mb = &pmb->u.mb;
struct lpfc_nodelist *ndlp = pmb->ctx_ndlp;
struct lpfc_vport *vport = pmb->vport;
int rc;
out:
/* decrement the node reference count held for this
* callback function.
*/
lpfc_nlp_put(ndlp);
lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
/* If the node is not registered with the scsi or nvme
* transport, remove the fabric node. The failed reg_login
* is terminal and forces the removal of the last node
* reference.
*/
if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) {
clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag);
lpfc_nlp_put(ndlp);
}
if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
/*
* RegLogin failed, use loop map to make discovery
* list
*/
lpfc_disc_list_loopmap(vport);
/* Issue SCR just before NameServer GID_FT Query */
lpfc_issue_els_scr(vport, 0);
/* Link was bounced or a Fabric LOGO occurred. Start EDC
* with initial FW values provided the congestion mode is
* not off. Note that signals may or may not be supported
* by the adapter but FPIN is provided by default for 1
* or both missing signals support.
*/
if (phba->cmf_active_mode != LPFC_CFG_OFF) {
phba->cgn_reg_fpin = phba->cgn_init_reg_fpin;
phba->cgn_reg_signal = phba->cgn_init_reg_signal;
rc = lpfc_issue_els_edc(vport, 0);
lpfc_printf_log(phba, KERN_INFO,
LOG_INIT | LOG_ELS | LOG_DISCOVERY,
"4220 Issue EDC status x%x Data x%x\n",
rc, phba->cgn_init_reg_signal);
} else if (phba->lmt & LMT_64Gb) {
/* may send link fault capability descriptor */
lpfc_issue_els_edc(vport, 0);
} else {
lpfc_issue_els_rdf(vport, 0);
}
}
vport->fc_ns_retry = 0;
if (lpfc_issue_gidft(vport) == 0)
goto out;
/*
* At this point in time we may need to wait for multiple
* SLI_CTNS_GID_FT CT commands to complete before we start discovery.
*
* decrement the node reference count held for this
* callback function.
*/
lpfc_nlp_put(ndlp);
lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
return;
}
/*
* This routine handles processing a Fabric Controller REG_LOGIN mailbox
* command upon completion. It is setup in the LPFC_MBOXQ
* as the completion routine when the command is handed off to the SLI layer.
*/
void
lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
MAILBOX_t *mb = &pmb->u.mb;
struct lpfc_nodelist *ndlp = pmb->ctx_ndlp;
static void
lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count)
{
switch (state) {
case NLP_STE_UNUSED_NODE:
atomic_add(count, &vport->fc_unused_cnt);
break;
case NLP_STE_PLOGI_ISSUE:
atomic_add(count, &vport->fc_plogi_cnt);
break;
case NLP_STE_ADISC_ISSUE:
atomic_add(count, &vport->fc_adisc_cnt);
break;
case NLP_STE_REG_LOGIN_ISSUE:
atomic_add(count, &vport->fc_reglogin_cnt);
break;
case NLP_STE_PRLI_ISSUE:
atomic_add(count, &vport->fc_prli_cnt);
break;
case NLP_STE_UNMAPPED_NODE:
atomic_add(count, &vport->fc_unmap_cnt);
break;
case NLP_STE_MAPPED_NODE:
atomic_add(count, &vport->fc_map_cnt);
break;
case NLP_STE_NPR_NODE:
if (!atomic_read(&vport->fc_npr_cnt) && count == -1)
atomic_set(&vport->fc_npr_cnt, 0);
else
atomic_add(count, &vport->fc_npr_cnt);
break;
}
}
/* Register a node with backend if not already done */
void
lpfc_nlp_reg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
unsigned long iflags;
lpfc_check_nlp_post_devloss(vport, ndlp);
spin_lock_irqsave(&ndlp->lock, iflags);
if (ndlp->fc4_xpt_flags & NLP_XPT_REGD) {
/* Already registered with backend, trigger rescan */
spin_unlock_irqrestore(&ndlp->lock, iflags);
if (lpfc_valid_xpt_node(ndlp)) {
vport->phba->nport_event_cnt++;
/*
* Tell the fc transport about the port, if we haven't
* already. If we have, and it's a scsi entity, be
*/
lpfc_register_remote_port(vport, ndlp);
}
/* We are done if we do not have any NVME remote node */
if (!(ndlp->nlp_fc4_type & NLP_FC4_NVME))
return;
/* Notify the NVME transport of this new rport. */
if (vport->phba->sli_rev >= LPFC_SLI_REV4 &&
ndlp->nlp_fc4_type & NLP_FC4_NVME) {
if (vport->phba->nvmet_support == 0) {
/* Register this rport with the transport.
* Only NVME Target Rports are registered with
* the transport.
*/
if (ndlp->nlp_type & NLP_NVME_TARGET) {
vport->phba->nport_event_cnt++;
lpfc_nvme_register_port(vport, ndlp);
}
} else {
/* Just take an NDLP ref count since the
* target does not register rports.
*/
lpfc_nlp_get(ndlp);
}
}
}
/* Unregister a node with backend if not already done */
void
lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
unsigned long iflags;
if (ndlp->fc4_xpt_flags & NVME_XPT_REGD) {
vport->phba->nport_event_cnt++;
if (vport->phba->nvmet_support == 0) {
lpfc_nvme_unregister_port(vport, ndlp);
} else {
/* NVMET has no upcall. */
lpfc_nlp_put(ndlp);
}
}
}
/*
* Adisc state change handling
*/
static void
lpfc_handle_adisc_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
int new_state)
{
switch (new_state) {
/*
* Any state to ADISC_ISSUE
* Do nothing, adisc cmpl handling will trigger state changes
*/
case NLP_STE_ADISC_ISSUE:
break;
/*
* ADISC_ISSUE to mapped states
* Trigger a registration with backend, it will be nop if
* already registered
*/
case NLP_STE_UNMAPPED_NODE:
ndlp->nlp_type |= NLP_FC_NODE;
fallthrough;
case NLP_STE_MAPPED_NODE:
clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag);
lpfc_nlp_reg_node(vport, ndlp);
break;
/*
* ADISC_ISSUE to non-mapped states
* We are moving from ADISC_ISSUE to a non-mapped state because
* ADISC failed, we would have skipped unregistering with
* backend, attempt it now
*/
case NLP_STE_NPR_NODE:
clear_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag);
fallthrough;
default:
lpfc_nlp_unreg_node(vport, ndlp);
break;
}
}
static void
lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
int old_state, int new_state)
{
/* Trap ADISC changes here */
if (new_state == NLP_STE_ADISC_ISSUE ||
old_state == NLP_STE_ADISC_ISSUE) {
lpfc_handle_adisc_state(vport, ndlp, new_state);
return;
}
if (new_state == NLP_STE_UNMAPPED_NODE) {
clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag);
ndlp->nlp_type |= NLP_FC_NODE;
}
if (new_state == NLP_STE_MAPPED_NODE)
clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag);
if (new_state == NLP_STE_NPR_NODE)
clear_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag);
/* Reg/Unreg for FCP and NVME Transport interface */
if ((old_state == NLP_STE_MAPPED_NODE ||
old_state == NLP_STE_UNMAPPED_NODE)) {
/* For nodes marked for ADISC, Handle unreg in ADISC cmpl
* if linkup. In linkdown do unreg_node
*/
if (!test_bit(NLP_NPR_ADISC, &ndlp->nlp_flag) ||
!lpfc_is_link_up(vport->phba))
lpfc_nlp_unreg_node(vport, ndlp);
}
if (new_state == NLP_STE_MAPPED_NODE ||
new_state == NLP_STE_UNMAPPED_NODE)
lpfc_nlp_reg_node(vport, ndlp);
/*
* If the node just added to Mapped list was an FCP target,
* but the remote port registration failed or assigned a target
* id outside the presentable range - move the node to the
* Unmapped List.
*/
if ((new_state == NLP_STE_MAPPED_NODE) &&
(ndlp->nlp_type & NLP_FCP_TARGET) &&
(!ndlp->rport ||
ndlp->rport->scsi_target_id == -1 ||
ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) {
set_bit(NLP_TGT_NO_SCSIID, &ndlp->nlp_flag);
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
}
}
/**
* lpfc_initialize_node - Initialize all fields of node object
* @vport: Pointer to Virtual Port object.
* @ndlp: Pointer to FC node object.
* @did: FC_ID of the node.
*
* This function is always called when node object need to be initialized.
* It initializes all the fields of the node object. Although the reference
* to phba from @ndlp can be obtained indirectly through it's reference to
* @vport, a direct reference to phba is taken here by @ndlp. This is due
* to the life-span of the @ndlp might go beyond the existence of @vport as
* the final release of ndlp is determined by its reference count. And, the
* operation on @ndlp needs the reference to phba.
**/
static inline void
lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint32_t did)
{
INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp);
timer_setup(&ndlp->nlp_delayfunc, lpfc_els_retry_delay, 0);
INIT_LIST_HEAD(&ndlp->recovery_evt.evt_listp);
void
lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
/*
* Use of lpfc_drop_node and UNUSED list: lpfc_drop_node should
* be used when lpfc wants to remove the "last" lpfc_nlp_put() to
* release the ndlp from the vport when conditions are correct.
*/
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
return;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
if (vport->phba->sli_rev == LPFC_SLI_REV4) {
lpfc_cleanup_vports_rrqs(vport, ndlp);
lpfc_unreg_rpi(vport, ndlp);
}
/* NLP_DROPPED means another thread already removed the initial
* reference from lpfc_nlp_init. If set, don't drop it again and
* introduce an imbalance.
*/
if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag))
lpfc_nlp_put(ndlp);
}
if (vport->port_state == LPFC_LOCAL_CFG_LINK) {
/* For FAN, timeout should be greater than edtov */
tmo = (((phba->fc_edtov + 999) / 1000) + 1);
} else {
/* Normal discovery timeout should be > than ELS/CT timeout
* FC spec states we need 3 * ratov for CT requests
*/
tmo = ((phba->fc_ratov * 3) + 3);
}
if (pring->ringno == LPFC_ELS_RING) {
switch (ulp_command) {
case CMD_GEN_REQUEST64_CR:
if (iocb->ndlp == ndlp)
return 1;
break;
case CMD_ELS_REQUEST64_CR:
if (remote_id == ndlp->nlp_DID)
return 1;
fallthrough;
case CMD_XMIT_ELS_RSP64_CX:
if (iocb->ndlp == ndlp)
return 1;
}
} else if (pring->ringno == LPFC_FCP_RING) {
/* Skip match check if waiting to relogin to FCP target */
if ((ndlp->nlp_type & NLP_FCP_TARGET) &&
test_bit(NLP_DELAY_TMO, &ndlp->nlp_flag))
return 0;
if (ulp_context == ndlp->nlp_rpi)
return 1;
}
return 0;
}
spin_lock_irq(&phba->hbalock);
for (i = 0; i < psli->num_rings; i++)
__lpfc_dequeue_nport_iocbs(phba, ndlp, &psli->sli3_ring[i],
dequeue_list);
spin_unlock_irq(&phba->hbalock);
}
/*
* Free resources / clean up outstanding I/Os
* associated with nlp_rpi in the LPFC_NODELIST entry.
*/
static int
lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
LIST_HEAD(completions);
lpfc_fabric_abort_nport(ndlp);
/*
* Everything that matches on txcmplq will be returned
* by firmware with a no rpi error.
*/
if (test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag)) {
if (phba->sli_rev != LPFC_SLI_REV4)
lpfc_sli3_dequeue_nport_iocbs(phba, ndlp, &completions);
else
lpfc_sli4_dequeue_nport_iocbs(phba, ndlp, &completions);
}
/* Cancel all the IOCBs from the completions list */
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
IOERR_SLI_ABORTED);
return 0;
}
/**
* lpfc_nlp_logo_unreg - Unreg mailbox completion handler before LOGO
* @phba: Pointer to HBA context object.
* @pmb: Pointer to mailbox object.
*
* This function will issue an ELS LOGO command after completing
* the UNREG_RPI.
**/
static void
lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
struct lpfc_nodelist *ndlp;
ndlp = pmb->ctx_ndlp;
if (!ndlp)
return;
lpfc_issue_els_logo(vport, ndlp, 0);
/* Check to see if there are any deferred events to process */
if (test_bit(NLP_UNREG_INP, &ndlp->nlp_flag) &&
ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
"1434 UNREG cmpl deferred logo x%x "
"on NPort x%x Data: x%x x%px\n",
ndlp->nlp_rpi, ndlp->nlp_DID,
ndlp->nlp_defer_did, ndlp);
/* The node has an outstanding reference for the unreg. Now
* that the LOGO action and cleanup are finished, release
* resources.
*/
lpfc_nlp_put(ndlp);
mempool_free(pmb, phba->mbox_mem_pool);
}
/*
* Sets the mailbox completion handler to be used for the
* unreg_rpi command. The handler varies based on the state of
* the port and what will be happening to the rpi next.
*/
static void
lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp, LPFC_MBOXQ_t *mbox)
{
/* Driver always gets a reference on the mailbox job
* in support of async jobs.
*/
mbox->ctx_ndlp = lpfc_nlp_get(ndlp);
if (!mbox->ctx_ndlp)
return;
/*
* Free rpi associated with LPFC_NODELIST entry.
* This routine is called from lpfc_freenode(), when we are removing
* a LPFC_NODELIST entry. It is also called if the driver initiates a
* LOGO that completes successfully, and we are waiting to PLOGI back
* to the remote NPort. In addition, it is called after we receive
* and unsolicated ELS cmd, send back a rsp, the rsp completes and
* we are waiting to PLOGI back to the remote NPort.
*/
int
lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *mbox;
int rc, acc_plogi = 1;
uint16_t rpi;
if (test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag) ||
test_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag)) {
if (test_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag))
lpfc_printf_vlog(vport, KERN_INFO,
LOG_NODE | LOG_DISCOVERY,
"3366 RPI x%x needs to be "
"unregistered nlp_flag x%lx "
"did x%x\n",
ndlp->nlp_rpi, ndlp->nlp_flag,
ndlp->nlp_DID);
/* If there is already an UNREG in progress for this ndlp,
* no need to queue up another one.
*/
if (test_bit(NLP_UNREG_INP, &ndlp->nlp_flag)) {
lpfc_printf_vlog(vport, KERN_INFO,
LOG_NODE | LOG_DISCOVERY,
"1436 unreg_rpi SKIP UNREG x%x on "
"NPort x%x deferred x%x flg x%lx "
"Data: x%px\n",
ndlp->nlp_rpi, ndlp->nlp_DID,
ndlp->nlp_defer_did,
ndlp->nlp_flag, ndlp);
goto out;
}
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (mbox) {
/* SLI4 ports require the physical rpi value. */
rpi = ndlp->nlp_rpi;
if (phba->sli_rev == LPFC_SLI_REV4)
rpi = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
/* Because mempool_alloc failed, we
* will issue a LOGO here and keep the rpi alive if
* not unloading.
*/
if (!test_bit(FC_UNLOADING, &vport->load_flag)) {
clear_bit(NLP_UNREG_INP, &ndlp->nlp_flag);
lpfc_issue_els_logo(vport, ndlp, 0);
ndlp->nlp_prev_state = ndlp->nlp_state;
lpfc_nlp_set_state(vport, ndlp,
NLP_STE_NPR_NODE);
}
/**
* lpfc_unreg_hba_rpis - Unregister rpis registered to the hba.
* @phba: pointer to lpfc hba data structure.
*
* This routine is invoked to unregister all the currently registered RPIs
* to the HBA.
**/
void
lpfc_unreg_hba_rpis(struct lpfc_hba *phba)
{
struct lpfc_vport **vports;
struct lpfc_nodelist *ndlp;
int i;
unsigned long iflags;
vports = lpfc_create_vport_work_array(phba);
if (!vports) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
"2884 Vport array allocation failed \n");
return;
}
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
spin_lock_irqsave(&vports[i]->fc_nodes_list_lock, iflags);
list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
if (test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag)) {
/* The mempool_alloc might sleep */
spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock,
iflags);
lpfc_unreg_rpi(vports[i], ndlp);
spin_lock_irqsave(&vports[i]->fc_nodes_list_lock,
iflags);
}
}
spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock, iflags);
}
lpfc_destroy_vport_work_array(phba, vports);
}
/* The NVME Target does not want to actively manage an rport. *Thegoalistoallowthetargettoresetitsstateandclear *pendingIOinpreparationfortheinitiatortorecover.
*/
if (test_bit(FC_RSCN_MODE, &vport->fc_flag) && !test_bit(FC_NDISC_ACTIVE, &vport->fc_flag)) {
if (lpfc_rscn_payload_check(vport, did)) {
/* Since this node is marked for discovery, *delaytimeoutisnotneeded.
*/
lpfc_cancel_retry_delay_tmo(vport, ndlp);
/* NVME Target mode waits until rport is known to be *impactedbytheRSCNbeforeittransitions.No *activemanagement-justgotoNPRprovidedthe *nodehadavalidlogin.
*/
if (vport->phba->nvmet_support)
return ndlp;
/* If the initiator received a PLOGI from this NPort or if the *initiatorisalreadyintheprocessofdiscoveryonit, *there'snoneedtotrytodiscoveritagain.
*/
if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
(!vport->phba->nvmet_support &&
test_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag)))
return NULL;
if (vport->phba->nvmet_support)
return ndlp;
/* Moving to NPR state clears unsolicited flags and *allowsforrediscovery
*/
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
set_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag);
}
return ndlp;
}
/* Build a list of nodes to discover based on the loopmap */
void
lpfc_disc_list_loopmap(struct lpfc_vport *vport)
{
struct lpfc_hba *phba = vport->phba;
int j;
uint32_t alpa, index;
if (!lpfc_is_link_up(phba))
return;
if (phba->fc_topology != LPFC_TOPOLOGY_LOOP)
return;
/* Check for loop map present or not */
if (phba->alpa_map[0]) {
for (j = 1; j <= phba->alpa_map[0]; j++) {
alpa = phba->alpa_map[j];
if (((vport->fc_myDID & 0xff) == alpa) || (alpa == 0))
continue;
lpfc_setup_disc_node(vport, alpa);
}
} else { /* No alpamap, so try all alpa's */
for (j = 0; j < FC_MAXLOOP; j++) { /* If cfg_scan_down is set, start from highest *ALPA(0xef)tolowest(0x1).
*/
if (vport->cfg_scan_down)
index = j;
else
index = FC_MAXLOOP - j - 1;
alpa = lpfcAlpaArray[index];
if ((vport->fc_myDID & 0xff) == alpa)
continue;
lpfc_setup_disc_node(vport, alpa);
}
}
return;
}
/* Start Discovery state <hba_state> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0202 Start Discovery port state x%x " "flg x%lx Data: x%x x%x x%x\n",
vport->port_state, vport->fc_flag,
atomic_read(&vport->fc_plogi_cnt),
atomic_read(&vport->fc_adisc_cnt),
atomic_read(&vport->fc_npr_cnt));
/* First do ADISCs - if any */
num_sent = lpfc_els_disc_adisc(vport);
if (num_sent)
return;
/* Register the VPI for SLI3, NPIV only. */
if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && !test_bit(FC_PT2PT, &vport->fc_flag) && !test_bit(FC_RSCN_MODE, &vport->fc_flag) &&
(phba->sli_rev < LPFC_SLI_REV4)) {
lpfc_issue_clear_la(phba, vport);
lpfc_issue_reg_vpi(phba, vport);
return;
}
/* *ForSLI2,weneedtosetport_statetoREADYandcontinue *discovery.
*/
if (vport->port_state < LPFC_VPORT_READY && !clear_la_pending) { /* If we get here, there is nothing to ADISC */
lpfc_issue_clear_la(phba, vport);
if (!test_bit(FC_ABORT_DISCOVERY, &vport->fc_flag)) {
vport->num_disc_nodes = 0; /* go thru NPR nodes and issue ELS PLOGIs */
if (atomic_read(&vport->fc_npr_cnt))
lpfc_els_disc_plogi(vport);
if (!vport->num_disc_nodes) {
clear_bit(FC_NDISC_ACTIVE, &vport->fc_flag);
lpfc_can_disctmo(vport);
}
}
vport->port_state = LPFC_VPORT_READY;
} else { /* Next do PLOGIs - if any */
num_sent = lpfc_els_disc_plogi(vport);
if (num_sent)
return;
if (test_bit(FC_RSCN_MODE, &vport->fc_flag)) { /* Check to see if more RSCNs came in while we *wereprocessingthisone.
*/
if (vport->fc_rscn_id_cnt == 0 && !test_bit(FC_RSCN_DISCOVERY, &vport->fc_flag)) {
clear_bit(FC_RSCN_MODE, &vport->fc_flag);
lpfc_can_disctmo(vport);
} else {
lpfc_els_handle_rscn(vport);
}
}
}
return;
}
case LPFC_LOCAL_CFG_LINK: /* *port_stateisidenticallyLPFC_LOCAL_CFG_LINKwhile *waitingforFANtimeout
*/
lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY, "0221 FAN timeout\n");
/* Start discovery by sending FLOGI, clean up old rpis */
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
nlp_listp) {
if (ndlp->nlp_state != NLP_STE_NPR_NODE)
continue;
if (ndlp->nlp_type & NLP_FABRIC) { /* Clean up the ndlp on Fabric connections */
lpfc_drop_node(vport, ndlp);
} else if (!test_bit(NLP_NPR_ADISC, &ndlp->nlp_flag)) { /* Fail outstanding IO now since device *ismarkedforPLOGI.
*/
lpfc_unreg_rpi(vport, ndlp);
}
}
if (vport->port_state != LPFC_FLOGI) {
if (phba->sli_rev <= LPFC_SLI_REV3)
lpfc_initial_flogi(vport);
else
lpfc_issue_init_vfi(vport);
return;
}
break;
case LPFC_FDISC:
case LPFC_FLOGI: /* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */ /* Initial FLOGI timeout */
lpfc_printf_vlog(vport, KERN_ERR,
LOG_TRACE_EVENT, "0222 Initial %s timeout\n",
vport->vpi ? "FDISC" : "FLOGI");
/* Assume no Fabric and go on with discovery. *CheckforoutstandingELSFLOGItoabort.
*/
/* FLOGI failed, so just use loop map to make discovery list */
lpfc_disc_list_loopmap(vport);
case LPFC_FABRIC_CFG_LINK: /* hba_state is identically LPFC_FABRIC_CFG_LINK while waiting for
NameServer login */
lpfc_printf_vlog(vport, KERN_ERR,
LOG_TRACE_EVENT, "0223 Timeout while waiting for " "NameServer login\n"); /* Next look for NameServer ndlp */
ndlp = lpfc_findnode_did(vport, NameServer_DID);
if (ndlp)
lpfc_els_abort(phba, ndlp);
/* ReStart discovery */
goto restart_disc;
case LPFC_NS_QRY: /* Check for wait for NameServer Rsp timeout */
lpfc_printf_vlog(vport, KERN_ERR,
LOG_TRACE_EVENT, "0224 NameServer Query timeout " "Data: x%x x%x\n",
vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { /* Try it one more time */
vport->fc_ns_retry++;
vport->gidft_inp = 0;
rc = lpfc_issue_gidft(vport);
if (rc == 0)
break;
}
vport->fc_ns_retry = 0;
switch (phba->link_state) {
case LPFC_CLEAR_LA: /* CLEAR LA timeout */
lpfc_printf_vlog(vport, KERN_ERR,
LOG_TRACE_EVENT, "0228 CLEAR LA timeout\n");
clrlaerr = 1;
break;
case LPFC_LINK_UP:
lpfc_issue_clear_la(phba, vport);
fallthrough;
case LPFC_LINK_UNKNOWN:
case LPFC_WARM_START:
case LPFC_INIT_START:
case LPFC_INIT_MBX_CMDS:
case LPFC_LINK_DOWN:
case LPFC_HBA_ERROR:
lpfc_printf_vlog(vport, KERN_ERR,
LOG_TRACE_EVENT, "0230 Unexpected timeout, hba link " "state x%x\n", phba->link_state);
clrlaerr = 1;
break;
/* decrement the node reference count held for this callback *function.
*/
lpfc_nlp_put(ndlp);
lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); return;
}
/* The physical ports are always vpi 0 - translate is unnecessary. */ if (vpi > 0) { /* *Translatethephysicalvpitothelogicalvpi.The *vportstoresthelogicalvpi.
*/ for (i = 0; i <= phba->max_vpi; i++) { if (vpi == phba->vpi_ids[i]) break;
}
if (i > phba->max_vpi) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2936 Could not find Vport mapped " "to vpi %d\n", vpi); return NULL;
}
}
/* remove ndlp from action. */
lpfc_cancel_retry_delay_tmo(vport, ndlp);
lpfc_cleanup_node(vport, ndlp);
/* All nodes are initialized with an RPI that needs to be released *now.Allreferencesaregoneandthenodehasbeendequeued.
*/ if (vport->phba->sli_rev == LPFC_SLI_REV4) {
lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi);
ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
}
/* The node is not freed back to memory, it is released to a pool so *thenodefieldsneedtobecleanedup.
*/
ndlp->vport = NULL;
ndlp->nlp_state = NLP_STE_FREED_NODE;
ndlp->nlp_flag = 0;
ndlp->fc4_xpt_flags = 0;
/* free ndlp memory for final ndlp release */ if (ndlp->phba->sli_rev == LPFC_SLI_REV4)
mempool_free(ndlp->active_rrqs_xri_bitmap,
ndlp->phba->active_rrq_pool);
mempool_free(ndlp, ndlp->phba->nlp_mem_pool);
}
/* This routine bumps the reference count for a ndlp structure to ensure *thatonediscoverythreadwon'tfreeandlpwhileanotherdiscoverythread *isusingit.
*/ struct lpfc_nodelist *
lpfc_nlp_get(struct lpfc_nodelist *ndlp)
{ unsignedlong flags;
/* The check of ndlp usage to prevent incrementing the *ndlpreferencecountthatisintheprocessofbeing *released.
*/
spin_lock_irqsave(&ndlp->lock, flags); if (!kref_get_unless_zero(&ndlp->kref)) {
spin_unlock_irqrestore(&ndlp->lock, flags);
lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, "0276 %s: ndlp:x%px refcnt:%d\n",
__func__, (void *)ndlp, kref_read(&ndlp->kref)); return NULL;
}
spin_unlock_irqrestore(&ndlp->lock, flags);
} else {
WARN_ONCE(!ndlp, "**** %s, get ref on NULL ndlp!", __func__);
}
return ndlp;
}
/* This routine decrements the reference count for a ndlp structure. If the *countgoesto0,thisindicatestheassociatednodelistshouldbefreed.
*/ int
lpfc_nlp_put(struct lpfc_nodelist *ndlp)
{ if (ndlp) {
lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, "node put: did:x%x flg:x%lx refcnt:x%x",
ndlp->nlp_DID, ndlp->nlp_flag,
kref_read(&ndlp->kref));
} else {
WARN_ONCE(!ndlp, "**** %s, put ref on NULL ndlp!", __func__);
}
/* This is considered as the initial FCF discovery scan */
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag |= FCF_INIT_DISC;
spin_unlock_irq(&phba->hbalock);
/* Reset FCF roundrobin bmask for new discovery */
lpfc_sli4_clear_fcf_rr_bmask(phba);
/* Preparation for unregistering fcf */
rc = lpfc_unregister_fcf_prep(phba); if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2749 Failed to prepare for unregistering " "HBA's FCF record: rc=%d\n", rc); return;
}
/* Now, unregister FCF record and reset HBA FCF state */
rc = lpfc_sli4_unregister_fcf(phba); if (rc) return; /* Set proper HBA FCF states after successful unregister FCF */
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_REGISTERED;
spin_unlock_irq(&phba->hbalock);
}
/* *Ifdatasizeislessthan2wordssignatureandversioncannotbe *verified.
*/ if (size < 2*sizeof(uint32_t)) return;
/* Check the region signature first */ if (memcmp(buff, LPFC_REGION23_SIGNATURE, 4)) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2567 Config region 23 has bad signature\n"); return;
}
offset += 4;
/* Check the data structure version */ if (buff[offset] != LPFC_REGION23_VERSION) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2568 Config region 23 has bad version\n"); return;
}
offset += 4;
/* Read FCoE param record */
rec_ptr = lpfc_get_rec_conf23(&buff[offset],
size - offset, FCOE_PARAM_TYPE); if (rec_ptr)
lpfc_read_fcoe_param(phba, rec_ptr);
/* *lpfc_error_lost_link-IOfailurefromlinkeventorFWresetcheck. * *@vport:Pointertolpfc_vportdatastructure. *@ulp_status:IOcompletionstatus. *@ulp_word4:Reasoncodefortheulp_status. * *Thisfunctionevaluatestheulp_statusandulp_word4values *forspecificerrorvaluesthatindicateaninternallinkfault *orfwreseteventforthecompletingIO.Callersrequirethis *commondatatodecidenextstepsontheIO. * *Return: *false-Nolinkorreseterroroccurred. *true-Alinkorreseterroroccurred.
*/ bool
lpfc_error_lost_link(struct lpfc_vport *vport, u32 ulp_status, u32 ulp_word4)
{ /* Mask off the extra port data to get just the reason code. */
u32 rsn_code = IOERR_PARAM_MASK & ulp_word4;