162306a36Sopenharmony_ci/******************************************************************* 262306a36Sopenharmony_ci * This file is part of the Emulex Linux Device Driver for * 362306a36Sopenharmony_ci * Fibre Channel Host Bus Adapters. * 462306a36Sopenharmony_ci * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * 562306a36Sopenharmony_ci * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * 662306a36Sopenharmony_ci * Copyright (C) 2004-2016 Emulex. All rights reserved. * 762306a36Sopenharmony_ci * EMULEX and SLI are trademarks of Emulex. * 862306a36Sopenharmony_ci * www.broadcom.com * 962306a36Sopenharmony_ci * Portions Copyright (C) 2004-2005 Christoph Hellwig * 1062306a36Sopenharmony_ci * * 1162306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or * 1262306a36Sopenharmony_ci * modify it under the terms of version 2 of the GNU General * 1362306a36Sopenharmony_ci * Public License as published by the Free Software Foundation. * 1462306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful. * 1562306a36Sopenharmony_ci * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * 1662306a36Sopenharmony_ci * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * 1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * 1862306a36Sopenharmony_ci * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * 1962306a36Sopenharmony_ci * TO BE LEGALLY INVALID. See the GNU General Public License for * 2062306a36Sopenharmony_ci * more details, a copy of which can be found in the file COPYING * 2162306a36Sopenharmony_ci * included with this package. * 2262306a36Sopenharmony_ci *******************************************************************/ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/blkdev.h> 2562306a36Sopenharmony_ci#include <linux/delay.h> 2662306a36Sopenharmony_ci#include <linux/slab.h> 2762306a36Sopenharmony_ci#include <linux/pci.h> 2862306a36Sopenharmony_ci#include <linux/kthread.h> 2962306a36Sopenharmony_ci#include <linux/interrupt.h> 3062306a36Sopenharmony_ci#include <linux/lockdep.h> 3162306a36Sopenharmony_ci#include <linux/utsname.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <scsi/scsi.h> 3462306a36Sopenharmony_ci#include <scsi/scsi_device.h> 3562306a36Sopenharmony_ci#include <scsi/scsi_host.h> 3662306a36Sopenharmony_ci#include <scsi/scsi_transport_fc.h> 3762306a36Sopenharmony_ci#include <scsi/fc/fc_fs.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "lpfc_hw4.h" 4062306a36Sopenharmony_ci#include "lpfc_hw.h" 4162306a36Sopenharmony_ci#include "lpfc_nl.h" 4262306a36Sopenharmony_ci#include "lpfc_disc.h" 4362306a36Sopenharmony_ci#include "lpfc_sli.h" 4462306a36Sopenharmony_ci#include "lpfc_sli4.h" 4562306a36Sopenharmony_ci#include "lpfc.h" 4662306a36Sopenharmony_ci#include "lpfc_scsi.h" 4762306a36Sopenharmony_ci#include "lpfc_nvme.h" 4862306a36Sopenharmony_ci#include "lpfc_logmsg.h" 4962306a36Sopenharmony_ci#include "lpfc_crtn.h" 5062306a36Sopenharmony_ci#include "lpfc_vport.h" 5162306a36Sopenharmony_ci#include "lpfc_debugfs.h" 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* AlpaArray for assignment of scsid for scan-down and bind_method */ 5462306a36Sopenharmony_cistatic uint8_t lpfcAlpaArray[] = { 5562306a36Sopenharmony_ci 0xEF, 0xE8, 0xE4, 0xE2, 0xE1, 0xE0, 0xDC, 0xDA, 0xD9, 0xD6, 5662306a36Sopenharmony_ci 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 5762306a36Sopenharmony_ci 0xC9, 0xC7, 0xC6, 0xC5, 0xC3, 0xBC, 0xBA, 0xB9, 0xB6, 0xB5, 5862306a36Sopenharmony_ci 0xB4, 0xB3, 0xB2, 0xB1, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 5962306a36Sopenharmony_ci 0xA7, 0xA6, 0xA5, 0xA3, 0x9F, 0x9E, 0x9D, 0x9B, 0x98, 0x97, 6062306a36Sopenharmony_ci 0x90, 0x8F, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7C, 0x7A, 0x79, 6162306a36Sopenharmony_ci 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6E, 0x6D, 0x6C, 0x6B, 6262306a36Sopenharmony_ci 0x6A, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5C, 0x5A, 0x59, 0x56, 6362306a36Sopenharmony_ci 0x55, 0x54, 0x53, 0x52, 0x51, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 6462306a36Sopenharmony_ci 0x49, 0x47, 0x46, 0x45, 0x43, 0x3C, 0x3A, 0x39, 0x36, 0x35, 6562306a36Sopenharmony_ci 0x34, 0x33, 0x32, 0x31, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 6662306a36Sopenharmony_ci 0x27, 0x26, 0x25, 0x23, 0x1F, 0x1E, 0x1D, 0x1B, 0x18, 0x17, 6762306a36Sopenharmony_ci 0x10, 0x0F, 0x08, 0x04, 0x02, 0x01 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic void lpfc_disc_timeout_handler(struct lpfc_vport *); 7162306a36Sopenharmony_cistatic void lpfc_disc_flush_list(struct lpfc_vport *vport); 7262306a36Sopenharmony_cistatic void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); 7362306a36Sopenharmony_cistatic int lpfc_fcf_inuse(struct lpfc_hba *); 7462306a36Sopenharmony_cistatic void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *); 7562306a36Sopenharmony_cistatic void lpfc_check_inactive_vmid(struct lpfc_hba *phba); 7662306a36Sopenharmony_cistatic void lpfc_check_vmid_qfpa_issue(struct lpfc_hba *phba); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int 7962306a36Sopenharmony_cilpfc_valid_xpt_node(struct lpfc_nodelist *ndlp) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci if (ndlp->nlp_fc4_type || 8262306a36Sopenharmony_ci ndlp->nlp_type & NLP_FABRIC) 8362306a36Sopenharmony_ci return 1; 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci/* The source of a terminate rport I/O is either a dev_loss_tmo 8762306a36Sopenharmony_ci * event or a call to fc_remove_host. While the rport should be 8862306a36Sopenharmony_ci * valid during these downcalls, the transport can call twice 8962306a36Sopenharmony_ci * in a single event. This routine provides somoe protection 9062306a36Sopenharmony_ci * as the NDLP isn't really free, just released to the pool. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_cistatic int 9362306a36Sopenharmony_cilpfc_rport_invalid(struct fc_rport *rport) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct lpfc_rport_data *rdata; 9662306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (!rport) { 9962306a36Sopenharmony_ci pr_err("**** %s: NULL rport, exit.\n", __func__); 10062306a36Sopenharmony_ci return -EINVAL; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci rdata = rport->dd_data; 10462306a36Sopenharmony_ci if (!rdata) { 10562306a36Sopenharmony_ci pr_err("**** %s: NULL dd_data on rport x%px SID x%x\n", 10662306a36Sopenharmony_ci __func__, rport, rport->scsi_target_id); 10762306a36Sopenharmony_ci return -EINVAL; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci ndlp = rdata->pnode; 11162306a36Sopenharmony_ci if (!rdata->pnode) { 11262306a36Sopenharmony_ci pr_info("**** %s: NULL ndlp on rport x%px SID x%x\n", 11362306a36Sopenharmony_ci __func__, rport, rport->scsi_target_id); 11462306a36Sopenharmony_ci return -EINVAL; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (!ndlp->vport) { 11862306a36Sopenharmony_ci pr_err("**** %s: Null vport on ndlp x%px, DID x%x rport x%px " 11962306a36Sopenharmony_ci "SID x%x\n", __func__, ndlp, ndlp->nlp_DID, rport, 12062306a36Sopenharmony_ci rport->scsi_target_id); 12162306a36Sopenharmony_ci return -EINVAL; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci return 0; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_civoid 12762306a36Sopenharmony_cilpfc_terminate_rport_io(struct fc_rport *rport) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct lpfc_rport_data *rdata; 13062306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 13162306a36Sopenharmony_ci struct lpfc_vport *vport; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (lpfc_rport_invalid(rport)) 13462306a36Sopenharmony_ci return; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci rdata = rport->dd_data; 13762306a36Sopenharmony_ci ndlp = rdata->pnode; 13862306a36Sopenharmony_ci vport = ndlp->vport; 13962306a36Sopenharmony_ci lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, 14062306a36Sopenharmony_ci "rport terminate: sid:x%x did:x%x flg:x%x", 14162306a36Sopenharmony_ci ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (ndlp->nlp_sid != NLP_NO_SID) 14462306a36Sopenharmony_ci lpfc_sli_abort_iocb(vport, ndlp->nlp_sid, 0, LPFC_CTX_TGT); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* 14862306a36Sopenharmony_ci * This function will be called when dev_loss_tmo fire. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_civoid 15162306a36Sopenharmony_cilpfc_dev_loss_tmo_callbk(struct fc_rport *rport) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 15462306a36Sopenharmony_ci struct lpfc_vport *vport; 15562306a36Sopenharmony_ci struct lpfc_hba *phba; 15662306a36Sopenharmony_ci struct lpfc_work_evt *evtp; 15762306a36Sopenharmony_ci unsigned long iflags; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci ndlp = ((struct lpfc_rport_data *)rport->dd_data)->pnode; 16062306a36Sopenharmony_ci if (!ndlp) 16162306a36Sopenharmony_ci return; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci vport = ndlp->vport; 16462306a36Sopenharmony_ci phba = vport->phba; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, 16762306a36Sopenharmony_ci "rport devlosscb: sid:x%x did:x%x flg:x%x", 16862306a36Sopenharmony_ci ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, 17162306a36Sopenharmony_ci "3181 dev_loss_callbk x%06x, rport x%px flg x%x " 17262306a36Sopenharmony_ci "load_flag x%x refcnt %u state %d xpt x%x\n", 17362306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag, 17462306a36Sopenharmony_ci vport->load_flag, kref_read(&ndlp->kref), 17562306a36Sopenharmony_ci ndlp->nlp_state, ndlp->fc4_xpt_flags); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* Don't schedule a worker thread event if the vport is going down. */ 17862306a36Sopenharmony_ci if (vport->load_flag & FC_UNLOADING) { 17962306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 18062306a36Sopenharmony_ci ndlp->rport = NULL; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* The scsi_transport is done with the rport so lpfc cannot 18362306a36Sopenharmony_ci * call to unregister. Remove the scsi transport reference 18462306a36Sopenharmony_ci * and clean up the SCSI transport node details. 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci if (ndlp->fc4_xpt_flags & (NLP_XPT_REGD | SCSI_XPT_REGD)) { 18762306a36Sopenharmony_ci ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* NVME transport-registered rports need the 19062306a36Sopenharmony_ci * NLP_XPT_REGD flag to complete an unregister. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ci if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) 19362306a36Sopenharmony_ci ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD; 19462306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 19562306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 19662306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Only 1 thread can drop the initial node reference. If 20062306a36Sopenharmony_ci * another thread has set NLP_DROPPED, this thread is done. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD) && 20362306a36Sopenharmony_ci !(ndlp->nlp_flag & NLP_DROPPED)) { 20462306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_DROPPED; 20562306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 20662306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 20762306a36Sopenharmony_ci return; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 21162306a36Sopenharmony_ci return; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) 21562306a36Sopenharmony_ci return; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (rport->port_name != wwn_to_u64(ndlp->nlp_portname.u.wwn)) 21862306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 21962306a36Sopenharmony_ci "6789 rport name %llx != node port name %llx", 22062306a36Sopenharmony_ci rport->port_name, 22162306a36Sopenharmony_ci wwn_to_u64(ndlp->nlp_portname.u.wwn)); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci evtp = &ndlp->dev_loss_evt; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (!list_empty(&evtp->evt_listp)) { 22662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 22762306a36Sopenharmony_ci "6790 rport name %llx dev_loss_evt pending\n", 22862306a36Sopenharmony_ci rport->port_name); 22962306a36Sopenharmony_ci return; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 23362306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_IN_DEV_LOSS; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* If there is a PLOGI in progress, and we are in a 23662306a36Sopenharmony_ci * NLP_NPR_2B_DISC state, don't turn off the flag. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE) 23962306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* 24262306a36Sopenharmony_ci * The backend does not expect any more calls associated with this 24362306a36Sopenharmony_ci * rport. Remove the association between rport and ndlp. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD; 24662306a36Sopenharmony_ci ((struct lpfc_rport_data *)rport->dd_data)->pnode = NULL; 24762306a36Sopenharmony_ci ndlp->rport = NULL; 24862306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (phba->worker_thread) { 25162306a36Sopenharmony_ci /* We need to hold the node by incrementing the reference 25262306a36Sopenharmony_ci * count until this queued work is done 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci evtp->evt_arg1 = lpfc_nlp_get(ndlp); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci spin_lock_irqsave(&phba->hbalock, iflags); 25762306a36Sopenharmony_ci if (evtp->evt_arg1) { 25862306a36Sopenharmony_ci evtp->evt = LPFC_EVT_DEV_LOSS; 25962306a36Sopenharmony_ci list_add_tail(&evtp->evt_listp, &phba->work_list); 26062306a36Sopenharmony_ci lpfc_worker_wake_up(phba); 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci spin_unlock_irqrestore(&phba->hbalock, iflags); 26362306a36Sopenharmony_ci } else { 26462306a36Sopenharmony_ci lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, 26562306a36Sopenharmony_ci "3188 worker thread is stopped %s x%06x, " 26662306a36Sopenharmony_ci " rport x%px flg x%x load_flag x%x refcnt " 26762306a36Sopenharmony_ci "%d\n", __func__, ndlp->nlp_DID, 26862306a36Sopenharmony_ci ndlp->rport, ndlp->nlp_flag, 26962306a36Sopenharmony_ci vport->load_flag, kref_read(&ndlp->kref)); 27062306a36Sopenharmony_ci if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) { 27162306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 27262306a36Sopenharmony_ci /* Node is in dev loss. No further transaction. */ 27362306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; 27462306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 27562306a36Sopenharmony_ci lpfc_disc_state_machine(vport, ndlp, NULL, 27662306a36Sopenharmony_ci NLP_EVT_DEVICE_RM); 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/** 28562306a36Sopenharmony_ci * lpfc_check_inactive_vmid_one - VMID inactivity checker for a vport 28662306a36Sopenharmony_ci * @vport: Pointer to vport context object. 28762306a36Sopenharmony_ci * 28862306a36Sopenharmony_ci * This function checks for idle VMID entries related to a particular vport. If 28962306a36Sopenharmony_ci * found unused/idle, free them accordingly. 29062306a36Sopenharmony_ci **/ 29162306a36Sopenharmony_cistatic void lpfc_check_inactive_vmid_one(struct lpfc_vport *vport) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci u16 keep; 29462306a36Sopenharmony_ci u32 difftime = 0, r, bucket; 29562306a36Sopenharmony_ci u64 *lta; 29662306a36Sopenharmony_ci int cpu; 29762306a36Sopenharmony_ci struct lpfc_vmid *vmp; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci write_lock(&vport->vmid_lock); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (!vport->cur_vmid_cnt) 30262306a36Sopenharmony_ci goto out; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* iterate through the table */ 30562306a36Sopenharmony_ci hash_for_each(vport->hash_table, bucket, vmp, hnode) { 30662306a36Sopenharmony_ci keep = 0; 30762306a36Sopenharmony_ci if (vmp->flag & LPFC_VMID_REGISTERED) { 30862306a36Sopenharmony_ci /* check if the particular VMID is in use */ 30962306a36Sopenharmony_ci /* for all available per cpu variable */ 31062306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 31162306a36Sopenharmony_ci /* if last access time is less than timeout */ 31262306a36Sopenharmony_ci lta = per_cpu_ptr(vmp->last_io_time, cpu); 31362306a36Sopenharmony_ci if (!lta) 31462306a36Sopenharmony_ci continue; 31562306a36Sopenharmony_ci difftime = (jiffies) - (*lta); 31662306a36Sopenharmony_ci if ((vport->vmid_inactivity_timeout * 31762306a36Sopenharmony_ci JIFFIES_PER_HR) > difftime) { 31862306a36Sopenharmony_ci keep = 1; 31962306a36Sopenharmony_ci break; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* if none of the cpus have been used by the vm, */ 32462306a36Sopenharmony_ci /* remove the entry if already registered */ 32562306a36Sopenharmony_ci if (!keep) { 32662306a36Sopenharmony_ci /* mark the entry for deregistration */ 32762306a36Sopenharmony_ci vmp->flag = LPFC_VMID_DE_REGISTER; 32862306a36Sopenharmony_ci write_unlock(&vport->vmid_lock); 32962306a36Sopenharmony_ci if (vport->vmid_priority_tagging) 33062306a36Sopenharmony_ci r = lpfc_vmid_uvem(vport, vmp, false); 33162306a36Sopenharmony_ci else 33262306a36Sopenharmony_ci r = lpfc_vmid_cmd(vport, 33362306a36Sopenharmony_ci SLI_CTAS_DAPP_IDENT, 33462306a36Sopenharmony_ci vmp); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* decrement number of active vms and mark */ 33762306a36Sopenharmony_ci /* entry in slot as free */ 33862306a36Sopenharmony_ci write_lock(&vport->vmid_lock); 33962306a36Sopenharmony_ci if (!r) { 34062306a36Sopenharmony_ci struct lpfc_vmid *ht = vmp; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci vport->cur_vmid_cnt--; 34362306a36Sopenharmony_ci ht->flag = LPFC_VMID_SLOT_FREE; 34462306a36Sopenharmony_ci free_percpu(ht->last_io_time); 34562306a36Sopenharmony_ci ht->last_io_time = NULL; 34662306a36Sopenharmony_ci hash_del(&ht->hnode); 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci out: 35262306a36Sopenharmony_ci write_unlock(&vport->vmid_lock); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci/** 35662306a36Sopenharmony_ci * lpfc_check_inactive_vmid - VMID inactivity checker 35762306a36Sopenharmony_ci * @phba: Pointer to hba context object. 35862306a36Sopenharmony_ci * 35962306a36Sopenharmony_ci * This function is called from the worker thread to determine if an entry in 36062306a36Sopenharmony_ci * the VMID table can be released since there was no I/O activity seen from that 36162306a36Sopenharmony_ci * particular VM for the specified time. When this happens, the entry in the 36262306a36Sopenharmony_ci * table is released and also the resources on the switch cleared. 36362306a36Sopenharmony_ci **/ 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic void lpfc_check_inactive_vmid(struct lpfc_hba *phba) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci struct lpfc_vport *vport; 36862306a36Sopenharmony_ci struct lpfc_vport **vports; 36962306a36Sopenharmony_ci int i; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci vports = lpfc_create_vport_work_array(phba); 37262306a36Sopenharmony_ci if (!vports) 37362306a36Sopenharmony_ci return; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci for (i = 0; i <= phba->max_vports; i++) { 37662306a36Sopenharmony_ci if ((!vports[i]) && (i == 0)) 37762306a36Sopenharmony_ci vport = phba->pport; 37862306a36Sopenharmony_ci else 37962306a36Sopenharmony_ci vport = vports[i]; 38062306a36Sopenharmony_ci if (!vport) 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci lpfc_check_inactive_vmid_one(vport); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci lpfc_destroy_vport_work_array(phba, vports); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci/** 38962306a36Sopenharmony_ci * lpfc_check_nlp_post_devloss - Check to restore ndlp refcnt after devloss 39062306a36Sopenharmony_ci * @vport: Pointer to vport object. 39162306a36Sopenharmony_ci * @ndlp: Pointer to remote node object. 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * If NLP_IN_RECOV_POST_DEV_LOSS flag was set due to outstanding recovery of 39462306a36Sopenharmony_ci * node during dev_loss_tmo processing, then this function restores the nlp_put 39562306a36Sopenharmony_ci * kref decrement from lpfc_dev_loss_tmo_handler. 39662306a36Sopenharmony_ci **/ 39762306a36Sopenharmony_civoid 39862306a36Sopenharmony_cilpfc_check_nlp_post_devloss(struct lpfc_vport *vport, 39962306a36Sopenharmony_ci struct lpfc_nodelist *ndlp) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci unsigned long iflags; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 40462306a36Sopenharmony_ci if (ndlp->save_flags & NLP_IN_RECOV_POST_DEV_LOSS) { 40562306a36Sopenharmony_ci ndlp->save_flags &= ~NLP_IN_RECOV_POST_DEV_LOSS; 40662306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 40762306a36Sopenharmony_ci lpfc_nlp_get(ndlp); 40862306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_NODE, 40962306a36Sopenharmony_ci "8438 Devloss timeout reversed on DID x%x " 41062306a36Sopenharmony_ci "refcnt %d ndlp %p flag x%x " 41162306a36Sopenharmony_ci "port_state = x%x\n", 41262306a36Sopenharmony_ci ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp, 41362306a36Sopenharmony_ci ndlp->nlp_flag, vport->port_state); 41462306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/** 42062306a36Sopenharmony_ci * lpfc_dev_loss_tmo_handler - Remote node devloss timeout handler 42162306a36Sopenharmony_ci * @ndlp: Pointer to remote node object. 42262306a36Sopenharmony_ci * 42362306a36Sopenharmony_ci * This function is called from the worker thread when devloss timeout timer 42462306a36Sopenharmony_ci * expires. For SLI4 host, this routine shall return 1 when at lease one 42562306a36Sopenharmony_ci * remote node, including this @ndlp, is still in use of FCF; otherwise, this 42662306a36Sopenharmony_ci * routine shall return 0 when there is no remote node is still in use of FCF 42762306a36Sopenharmony_ci * when devloss timeout happened to this @ndlp. 42862306a36Sopenharmony_ci **/ 42962306a36Sopenharmony_cistatic int 43062306a36Sopenharmony_cilpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct lpfc_vport *vport; 43362306a36Sopenharmony_ci struct lpfc_hba *phba; 43462306a36Sopenharmony_ci uint8_t *name; 43562306a36Sopenharmony_ci int warn_on = 0; 43662306a36Sopenharmony_ci int fcf_inuse = 0; 43762306a36Sopenharmony_ci bool recovering = false; 43862306a36Sopenharmony_ci struct fc_vport *fc_vport = NULL; 43962306a36Sopenharmony_ci unsigned long iflags; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci vport = ndlp->vport; 44262306a36Sopenharmony_ci name = (uint8_t *)&ndlp->nlp_portname; 44362306a36Sopenharmony_ci phba = vport->phba; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4) 44662306a36Sopenharmony_ci fcf_inuse = lpfc_fcf_inuse(phba); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, 44962306a36Sopenharmony_ci "rport devlosstmo:did:x%x type:x%x id:x%x", 45062306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_type, ndlp->nlp_sid); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, 45362306a36Sopenharmony_ci "3182 %s x%06x, nflag x%x xflags x%x refcnt %d\n", 45462306a36Sopenharmony_ci __func__, ndlp->nlp_DID, ndlp->nlp_flag, 45562306a36Sopenharmony_ci ndlp->fc4_xpt_flags, kref_read(&ndlp->kref)); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* If the driver is recovering the rport, ignore devloss. */ 45862306a36Sopenharmony_ci if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) { 45962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 46062306a36Sopenharmony_ci "0284 Devloss timeout Ignored on " 46162306a36Sopenharmony_ci "WWPN %x:%x:%x:%x:%x:%x:%x:%x " 46262306a36Sopenharmony_ci "NPort x%x\n", 46362306a36Sopenharmony_ci *name, *(name+1), *(name+2), *(name+3), 46462306a36Sopenharmony_ci *(name+4), *(name+5), *(name+6), *(name+7), 46562306a36Sopenharmony_ci ndlp->nlp_DID); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 46862306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; 46962306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 47062306a36Sopenharmony_ci return fcf_inuse; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* Fabric nodes are done. */ 47462306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_FABRIC) { 47562306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* The driver has to account for a race between any fabric 47862306a36Sopenharmony_ci * node that's in recovery when dev_loss_tmo expires. When this 47962306a36Sopenharmony_ci * happens, the driver has to allow node recovery. 48062306a36Sopenharmony_ci */ 48162306a36Sopenharmony_ci switch (ndlp->nlp_DID) { 48262306a36Sopenharmony_ci case Fabric_DID: 48362306a36Sopenharmony_ci fc_vport = vport->fc_vport; 48462306a36Sopenharmony_ci if (fc_vport) { 48562306a36Sopenharmony_ci /* NPIV path. */ 48662306a36Sopenharmony_ci if (fc_vport->vport_state == 48762306a36Sopenharmony_ci FC_VPORT_INITIALIZING) 48862306a36Sopenharmony_ci recovering = true; 48962306a36Sopenharmony_ci } else { 49062306a36Sopenharmony_ci /* Physical port path. */ 49162306a36Sopenharmony_ci if (phba->hba_flag & HBA_FLOGI_OUTSTANDING) 49262306a36Sopenharmony_ci recovering = true; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci case Fabric_Cntl_DID: 49662306a36Sopenharmony_ci if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) 49762306a36Sopenharmony_ci recovering = true; 49862306a36Sopenharmony_ci break; 49962306a36Sopenharmony_ci case FDMI_DID: 50062306a36Sopenharmony_ci fallthrough; 50162306a36Sopenharmony_ci case NameServer_DID: 50262306a36Sopenharmony_ci if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE && 50362306a36Sopenharmony_ci ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE) 50462306a36Sopenharmony_ci recovering = true; 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci default: 50762306a36Sopenharmony_ci /* Ensure the nlp_DID at least has the correct prefix. 50862306a36Sopenharmony_ci * The fabric domain controller's last three nibbles 50962306a36Sopenharmony_ci * vary so we handle it in the default case. 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_ci if (ndlp->nlp_DID & Fabric_DID_MASK) { 51262306a36Sopenharmony_ci if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE && 51362306a36Sopenharmony_ci ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE) 51462306a36Sopenharmony_ci recovering = true; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Mark an NLP_IN_RECOV_POST_DEV_LOSS flag to know if reversing 52162306a36Sopenharmony_ci * the following lpfc_nlp_put is necessary after fabric node is 52262306a36Sopenharmony_ci * recovered. 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_ci if (recovering) { 52562306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, 52662306a36Sopenharmony_ci LOG_DISCOVERY | LOG_NODE, 52762306a36Sopenharmony_ci "8436 Devloss timeout marked on " 52862306a36Sopenharmony_ci "DID x%x refcnt %d ndlp %p " 52962306a36Sopenharmony_ci "flag x%x port_state = x%x\n", 53062306a36Sopenharmony_ci ndlp->nlp_DID, kref_read(&ndlp->kref), 53162306a36Sopenharmony_ci ndlp, ndlp->nlp_flag, 53262306a36Sopenharmony_ci vport->port_state); 53362306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 53462306a36Sopenharmony_ci ndlp->save_flags |= NLP_IN_RECOV_POST_DEV_LOSS; 53562306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 53662306a36Sopenharmony_ci } else if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { 53762306a36Sopenharmony_ci /* Fabric node fully recovered before this dev_loss_tmo 53862306a36Sopenharmony_ci * queue work is processed. Thus, ignore the 53962306a36Sopenharmony_ci * dev_loss_tmo event. 54062306a36Sopenharmony_ci */ 54162306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, 54262306a36Sopenharmony_ci LOG_DISCOVERY | LOG_NODE, 54362306a36Sopenharmony_ci "8437 Devloss timeout ignored on " 54462306a36Sopenharmony_ci "DID x%x refcnt %d ndlp %p " 54562306a36Sopenharmony_ci "flag x%x port_state = x%x\n", 54662306a36Sopenharmony_ci ndlp->nlp_DID, kref_read(&ndlp->kref), 54762306a36Sopenharmony_ci ndlp, ndlp->nlp_flag, 54862306a36Sopenharmony_ci vport->port_state); 54962306a36Sopenharmony_ci return fcf_inuse; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 55362306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; 55462306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 55562306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 55662306a36Sopenharmony_ci return fcf_inuse; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (ndlp->nlp_sid != NLP_NO_SID) { 56062306a36Sopenharmony_ci warn_on = 1; 56162306a36Sopenharmony_ci lpfc_sli_abort_iocb(vport, ndlp->nlp_sid, 0, LPFC_CTX_TGT); 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (warn_on) { 56562306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 56662306a36Sopenharmony_ci "0203 Devloss timeout on " 56762306a36Sopenharmony_ci "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " 56862306a36Sopenharmony_ci "NPort x%06x Data: x%x x%x x%x refcnt %d\n", 56962306a36Sopenharmony_ci *name, *(name+1), *(name+2), *(name+3), 57062306a36Sopenharmony_ci *(name+4), *(name+5), *(name+6), *(name+7), 57162306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_flag, 57262306a36Sopenharmony_ci ndlp->nlp_state, ndlp->nlp_rpi, 57362306a36Sopenharmony_ci kref_read(&ndlp->kref)); 57462306a36Sopenharmony_ci } else { 57562306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_TRACE_EVENT, 57662306a36Sopenharmony_ci "0204 Devloss timeout on " 57762306a36Sopenharmony_ci "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " 57862306a36Sopenharmony_ci "NPort x%06x Data: x%x x%x x%x\n", 57962306a36Sopenharmony_ci *name, *(name+1), *(name+2), *(name+3), 58062306a36Sopenharmony_ci *(name+4), *(name+5), *(name+6), *(name+7), 58162306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_flag, 58262306a36Sopenharmony_ci ndlp->nlp_state, ndlp->nlp_rpi); 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 58562306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; 58662306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* If we are devloss, but we are in the process of rediscovering the 58962306a36Sopenharmony_ci * ndlp, don't issue a NLP_EVT_DEVICE_RM event. 59062306a36Sopenharmony_ci */ 59162306a36Sopenharmony_ci if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE && 59262306a36Sopenharmony_ci ndlp->nlp_state <= NLP_STE_PRLI_ISSUE) { 59362306a36Sopenharmony_ci return fcf_inuse; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) 59762306a36Sopenharmony_ci lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return fcf_inuse; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic void lpfc_check_vmid_qfpa_issue(struct lpfc_hba *phba) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct lpfc_vport *vport; 60562306a36Sopenharmony_ci struct lpfc_vport **vports; 60662306a36Sopenharmony_ci int i; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci vports = lpfc_create_vport_work_array(phba); 60962306a36Sopenharmony_ci if (!vports) 61062306a36Sopenharmony_ci return; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci for (i = 0; i <= phba->max_vports; i++) { 61362306a36Sopenharmony_ci if ((!vports[i]) && (i == 0)) 61462306a36Sopenharmony_ci vport = phba->pport; 61562306a36Sopenharmony_ci else 61662306a36Sopenharmony_ci vport = vports[i]; 61762306a36Sopenharmony_ci if (!vport) 61862306a36Sopenharmony_ci break; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (vport->vmid_flag & LPFC_VMID_ISSUE_QFPA) { 62162306a36Sopenharmony_ci if (!lpfc_issue_els_qfpa(vport)) 62262306a36Sopenharmony_ci vport->vmid_flag &= ~LPFC_VMID_ISSUE_QFPA; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci lpfc_destroy_vport_work_array(phba, vports); 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci/** 62962306a36Sopenharmony_ci * lpfc_sli4_post_dev_loss_tmo_handler - SLI4 post devloss timeout handler 63062306a36Sopenharmony_ci * @phba: Pointer to hba context object. 63162306a36Sopenharmony_ci * @fcf_inuse: SLI4 FCF in-use state reported from devloss timeout handler. 63262306a36Sopenharmony_ci * @nlp_did: remote node identifer with devloss timeout. 63362306a36Sopenharmony_ci * 63462306a36Sopenharmony_ci * This function is called from the worker thread after invoking devloss 63562306a36Sopenharmony_ci * timeout handler and releasing the reference count for the ndlp with 63662306a36Sopenharmony_ci * which the devloss timeout was handled for SLI4 host. For the devloss 63762306a36Sopenharmony_ci * timeout of the last remote node which had been in use of FCF, when this 63862306a36Sopenharmony_ci * routine is invoked, it shall be guaranteed that none of the remote are 63962306a36Sopenharmony_ci * in-use of FCF. When devloss timeout to the last remote using the FCF, 64062306a36Sopenharmony_ci * if the FIP engine is neither in FCF table scan process nor roundrobin 64162306a36Sopenharmony_ci * failover process, the in-use FCF shall be unregistered. If the FIP 64262306a36Sopenharmony_ci * engine is in FCF discovery process, the devloss timeout state shall 64362306a36Sopenharmony_ci * be set for either the FCF table scan process or roundrobin failover 64462306a36Sopenharmony_ci * process to unregister the in-use FCF. 64562306a36Sopenharmony_ci **/ 64662306a36Sopenharmony_cistatic void 64762306a36Sopenharmony_cilpfc_sli4_post_dev_loss_tmo_handler(struct lpfc_hba *phba, int fcf_inuse, 64862306a36Sopenharmony_ci uint32_t nlp_did) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci /* If devloss timeout happened to a remote node when FCF had no 65162306a36Sopenharmony_ci * longer been in-use, do nothing. 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_ci if (!fcf_inuse) 65462306a36Sopenharmony_ci return; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if ((phba->hba_flag & HBA_FIP_SUPPORT) && !lpfc_fcf_inuse(phba)) { 65762306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 65862306a36Sopenharmony_ci if (phba->fcf.fcf_flag & FCF_DISCOVERY) { 65962306a36Sopenharmony_ci if (phba->hba_flag & HBA_DEVLOSS_TMO) { 66062306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 66162306a36Sopenharmony_ci return; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci phba->hba_flag |= HBA_DEVLOSS_TMO; 66462306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 66562306a36Sopenharmony_ci "2847 Last remote node (x%x) using " 66662306a36Sopenharmony_ci "FCF devloss tmo\n", nlp_did); 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci if (phba->fcf.fcf_flag & FCF_REDISC_PROG) { 66962306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 67062306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 67162306a36Sopenharmony_ci "2868 Devloss tmo to FCF rediscovery " 67262306a36Sopenharmony_ci "in progress\n"); 67362306a36Sopenharmony_ci return; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci if (!(phba->hba_flag & (FCF_TS_INPROG | FCF_RR_INPROG))) { 67662306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 67762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 67862306a36Sopenharmony_ci "2869 Devloss tmo to idle FIP engine, " 67962306a36Sopenharmony_ci "unreg in-use FCF and rescan.\n"); 68062306a36Sopenharmony_ci /* Unregister in-use FCF and rescan */ 68162306a36Sopenharmony_ci lpfc_unregister_fcf_rescan(phba); 68262306a36Sopenharmony_ci return; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 68562306a36Sopenharmony_ci if (phba->hba_flag & FCF_TS_INPROG) 68662306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 68762306a36Sopenharmony_ci "2870 FCF table scan in progress\n"); 68862306a36Sopenharmony_ci if (phba->hba_flag & FCF_RR_INPROG) 68962306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 69062306a36Sopenharmony_ci "2871 FLOGI roundrobin FCF failover " 69162306a36Sopenharmony_ci "in progress\n"); 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci lpfc_unregister_unused_fcf(phba); 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci/** 69762306a36Sopenharmony_ci * lpfc_alloc_fast_evt - Allocates data structure for posting event 69862306a36Sopenharmony_ci * @phba: Pointer to hba context object. 69962306a36Sopenharmony_ci * 70062306a36Sopenharmony_ci * This function is called from the functions which need to post 70162306a36Sopenharmony_ci * events from interrupt context. This function allocates data 70262306a36Sopenharmony_ci * structure required for posting event. It also keeps track of 70362306a36Sopenharmony_ci * number of events pending and prevent event storm when there are 70462306a36Sopenharmony_ci * too many events. 70562306a36Sopenharmony_ci **/ 70662306a36Sopenharmony_cistruct lpfc_fast_path_event * 70762306a36Sopenharmony_cilpfc_alloc_fast_evt(struct lpfc_hba *phba) { 70862306a36Sopenharmony_ci struct lpfc_fast_path_event *ret; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* If there are lot of fast event do not exhaust memory due to this */ 71162306a36Sopenharmony_ci if (atomic_read(&phba->fast_event_count) > LPFC_MAX_EVT_COUNT) 71262306a36Sopenharmony_ci return NULL; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci ret = kzalloc(sizeof(struct lpfc_fast_path_event), 71562306a36Sopenharmony_ci GFP_ATOMIC); 71662306a36Sopenharmony_ci if (ret) { 71762306a36Sopenharmony_ci atomic_inc(&phba->fast_event_count); 71862306a36Sopenharmony_ci INIT_LIST_HEAD(&ret->work_evt.evt_listp); 71962306a36Sopenharmony_ci ret->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci return ret; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci/** 72562306a36Sopenharmony_ci * lpfc_free_fast_evt - Frees event data structure 72662306a36Sopenharmony_ci * @phba: Pointer to hba context object. 72762306a36Sopenharmony_ci * @evt: Event object which need to be freed. 72862306a36Sopenharmony_ci * 72962306a36Sopenharmony_ci * This function frees the data structure required for posting 73062306a36Sopenharmony_ci * events. 73162306a36Sopenharmony_ci **/ 73262306a36Sopenharmony_civoid 73362306a36Sopenharmony_cilpfc_free_fast_evt(struct lpfc_hba *phba, 73462306a36Sopenharmony_ci struct lpfc_fast_path_event *evt) { 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci atomic_dec(&phba->fast_event_count); 73762306a36Sopenharmony_ci kfree(evt); 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci/** 74162306a36Sopenharmony_ci * lpfc_send_fastpath_evt - Posts events generated from fast path 74262306a36Sopenharmony_ci * @phba: Pointer to hba context object. 74362306a36Sopenharmony_ci * @evtp: Event data structure. 74462306a36Sopenharmony_ci * 74562306a36Sopenharmony_ci * This function is called from worker thread, when the interrupt 74662306a36Sopenharmony_ci * context need to post an event. This function posts the event 74762306a36Sopenharmony_ci * to fc transport netlink interface. 74862306a36Sopenharmony_ci **/ 74962306a36Sopenharmony_cistatic void 75062306a36Sopenharmony_cilpfc_send_fastpath_evt(struct lpfc_hba *phba, 75162306a36Sopenharmony_ci struct lpfc_work_evt *evtp) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci unsigned long evt_category, evt_sub_category; 75462306a36Sopenharmony_ci struct lpfc_fast_path_event *fast_evt_data; 75562306a36Sopenharmony_ci char *evt_data; 75662306a36Sopenharmony_ci uint32_t evt_data_size; 75762306a36Sopenharmony_ci struct Scsi_Host *shost; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci fast_evt_data = container_of(evtp, struct lpfc_fast_path_event, 76062306a36Sopenharmony_ci work_evt); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci evt_category = (unsigned long) fast_evt_data->un.fabric_evt.event_type; 76362306a36Sopenharmony_ci evt_sub_category = (unsigned long) fast_evt_data->un. 76462306a36Sopenharmony_ci fabric_evt.subcategory; 76562306a36Sopenharmony_ci shost = lpfc_shost_from_vport(fast_evt_data->vport); 76662306a36Sopenharmony_ci if (evt_category == FC_REG_FABRIC_EVENT) { 76762306a36Sopenharmony_ci if (evt_sub_category == LPFC_EVENT_FCPRDCHKERR) { 76862306a36Sopenharmony_ci evt_data = (char *) &fast_evt_data->un.read_check_error; 76962306a36Sopenharmony_ci evt_data_size = sizeof(fast_evt_data->un. 77062306a36Sopenharmony_ci read_check_error); 77162306a36Sopenharmony_ci } else if ((evt_sub_category == LPFC_EVENT_FABRIC_BUSY) || 77262306a36Sopenharmony_ci (evt_sub_category == LPFC_EVENT_PORT_BUSY)) { 77362306a36Sopenharmony_ci evt_data = (char *) &fast_evt_data->un.fabric_evt; 77462306a36Sopenharmony_ci evt_data_size = sizeof(fast_evt_data->un.fabric_evt); 77562306a36Sopenharmony_ci } else { 77662306a36Sopenharmony_ci lpfc_free_fast_evt(phba, fast_evt_data); 77762306a36Sopenharmony_ci return; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci } else if (evt_category == FC_REG_SCSI_EVENT) { 78062306a36Sopenharmony_ci switch (evt_sub_category) { 78162306a36Sopenharmony_ci case LPFC_EVENT_QFULL: 78262306a36Sopenharmony_ci case LPFC_EVENT_DEVBSY: 78362306a36Sopenharmony_ci evt_data = (char *) &fast_evt_data->un.scsi_evt; 78462306a36Sopenharmony_ci evt_data_size = sizeof(fast_evt_data->un.scsi_evt); 78562306a36Sopenharmony_ci break; 78662306a36Sopenharmony_ci case LPFC_EVENT_CHECK_COND: 78762306a36Sopenharmony_ci evt_data = (char *) &fast_evt_data->un.check_cond_evt; 78862306a36Sopenharmony_ci evt_data_size = sizeof(fast_evt_data->un. 78962306a36Sopenharmony_ci check_cond_evt); 79062306a36Sopenharmony_ci break; 79162306a36Sopenharmony_ci case LPFC_EVENT_VARQUEDEPTH: 79262306a36Sopenharmony_ci evt_data = (char *) &fast_evt_data->un.queue_depth_evt; 79362306a36Sopenharmony_ci evt_data_size = sizeof(fast_evt_data->un. 79462306a36Sopenharmony_ci queue_depth_evt); 79562306a36Sopenharmony_ci break; 79662306a36Sopenharmony_ci default: 79762306a36Sopenharmony_ci lpfc_free_fast_evt(phba, fast_evt_data); 79862306a36Sopenharmony_ci return; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci } else { 80162306a36Sopenharmony_ci lpfc_free_fast_evt(phba, fast_evt_data); 80262306a36Sopenharmony_ci return; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (phba->cfg_enable_fc4_type != LPFC_ENABLE_NVME) 80662306a36Sopenharmony_ci fc_host_post_vendor_event(shost, 80762306a36Sopenharmony_ci fc_get_event_number(), 80862306a36Sopenharmony_ci evt_data_size, 80962306a36Sopenharmony_ci evt_data, 81062306a36Sopenharmony_ci LPFC_NL_VENDOR_ID); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci lpfc_free_fast_evt(phba, fast_evt_data); 81362306a36Sopenharmony_ci return; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic void 81762306a36Sopenharmony_cilpfc_work_list_done(struct lpfc_hba *phba) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci struct lpfc_work_evt *evtp = NULL; 82062306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 82162306a36Sopenharmony_ci int free_evt; 82262306a36Sopenharmony_ci int fcf_inuse; 82362306a36Sopenharmony_ci uint32_t nlp_did; 82462306a36Sopenharmony_ci bool hba_pci_err; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 82762306a36Sopenharmony_ci while (!list_empty(&phba->work_list)) { 82862306a36Sopenharmony_ci list_remove_head((&phba->work_list), evtp, typeof(*evtp), 82962306a36Sopenharmony_ci evt_listp); 83062306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 83162306a36Sopenharmony_ci hba_pci_err = test_bit(HBA_PCI_ERR, &phba->bit_flags); 83262306a36Sopenharmony_ci free_evt = 1; 83362306a36Sopenharmony_ci switch (evtp->evt) { 83462306a36Sopenharmony_ci case LPFC_EVT_ELS_RETRY: 83562306a36Sopenharmony_ci ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); 83662306a36Sopenharmony_ci if (!hba_pci_err) { 83762306a36Sopenharmony_ci lpfc_els_retry_delay_handler(ndlp); 83862306a36Sopenharmony_ci free_evt = 0; /* evt is part of ndlp */ 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci /* decrement the node reference count held 84162306a36Sopenharmony_ci * for this queued work 84262306a36Sopenharmony_ci */ 84362306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 84462306a36Sopenharmony_ci break; 84562306a36Sopenharmony_ci case LPFC_EVT_DEV_LOSS: 84662306a36Sopenharmony_ci ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); 84762306a36Sopenharmony_ci fcf_inuse = lpfc_dev_loss_tmo_handler(ndlp); 84862306a36Sopenharmony_ci free_evt = 0; 84962306a36Sopenharmony_ci /* decrement the node reference count held for 85062306a36Sopenharmony_ci * this queued work 85162306a36Sopenharmony_ci */ 85262306a36Sopenharmony_ci nlp_did = ndlp->nlp_DID; 85362306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 85462306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4) 85562306a36Sopenharmony_ci lpfc_sli4_post_dev_loss_tmo_handler(phba, 85662306a36Sopenharmony_ci fcf_inuse, 85762306a36Sopenharmony_ci nlp_did); 85862306a36Sopenharmony_ci break; 85962306a36Sopenharmony_ci case LPFC_EVT_RECOVER_PORT: 86062306a36Sopenharmony_ci ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); 86162306a36Sopenharmony_ci if (!hba_pci_err) { 86262306a36Sopenharmony_ci lpfc_sli_abts_recover_port(ndlp->vport, ndlp); 86362306a36Sopenharmony_ci free_evt = 0; 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci /* decrement the node reference count held for 86662306a36Sopenharmony_ci * this queued work 86762306a36Sopenharmony_ci */ 86862306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 86962306a36Sopenharmony_ci break; 87062306a36Sopenharmony_ci case LPFC_EVT_ONLINE: 87162306a36Sopenharmony_ci if (phba->link_state < LPFC_LINK_DOWN) 87262306a36Sopenharmony_ci *(int *) (evtp->evt_arg1) = lpfc_online(phba); 87362306a36Sopenharmony_ci else 87462306a36Sopenharmony_ci *(int *) (evtp->evt_arg1) = 0; 87562306a36Sopenharmony_ci complete((struct completion *)(evtp->evt_arg2)); 87662306a36Sopenharmony_ci break; 87762306a36Sopenharmony_ci case LPFC_EVT_OFFLINE_PREP: 87862306a36Sopenharmony_ci if (phba->link_state >= LPFC_LINK_DOWN) 87962306a36Sopenharmony_ci lpfc_offline_prep(phba, LPFC_MBX_WAIT); 88062306a36Sopenharmony_ci *(int *)(evtp->evt_arg1) = 0; 88162306a36Sopenharmony_ci complete((struct completion *)(evtp->evt_arg2)); 88262306a36Sopenharmony_ci break; 88362306a36Sopenharmony_ci case LPFC_EVT_OFFLINE: 88462306a36Sopenharmony_ci lpfc_offline(phba); 88562306a36Sopenharmony_ci lpfc_sli_brdrestart(phba); 88662306a36Sopenharmony_ci *(int *)(evtp->evt_arg1) = 88762306a36Sopenharmony_ci lpfc_sli_brdready(phba, HS_FFRDY | HS_MBRDY); 88862306a36Sopenharmony_ci lpfc_unblock_mgmt_io(phba); 88962306a36Sopenharmony_ci complete((struct completion *)(evtp->evt_arg2)); 89062306a36Sopenharmony_ci break; 89162306a36Sopenharmony_ci case LPFC_EVT_WARM_START: 89262306a36Sopenharmony_ci lpfc_offline(phba); 89362306a36Sopenharmony_ci lpfc_reset_barrier(phba); 89462306a36Sopenharmony_ci lpfc_sli_brdreset(phba); 89562306a36Sopenharmony_ci lpfc_hba_down_post(phba); 89662306a36Sopenharmony_ci *(int *)(evtp->evt_arg1) = 89762306a36Sopenharmony_ci lpfc_sli_brdready(phba, HS_MBRDY); 89862306a36Sopenharmony_ci lpfc_unblock_mgmt_io(phba); 89962306a36Sopenharmony_ci complete((struct completion *)(evtp->evt_arg2)); 90062306a36Sopenharmony_ci break; 90162306a36Sopenharmony_ci case LPFC_EVT_KILL: 90262306a36Sopenharmony_ci lpfc_offline(phba); 90362306a36Sopenharmony_ci *(int *)(evtp->evt_arg1) 90462306a36Sopenharmony_ci = (phba->pport->stopped) 90562306a36Sopenharmony_ci ? 0 : lpfc_sli_brdkill(phba); 90662306a36Sopenharmony_ci lpfc_unblock_mgmt_io(phba); 90762306a36Sopenharmony_ci complete((struct completion *)(evtp->evt_arg2)); 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci case LPFC_EVT_FASTPATH_MGMT_EVT: 91062306a36Sopenharmony_ci lpfc_send_fastpath_evt(phba, evtp); 91162306a36Sopenharmony_ci free_evt = 0; 91262306a36Sopenharmony_ci break; 91362306a36Sopenharmony_ci case LPFC_EVT_RESET_HBA: 91462306a36Sopenharmony_ci if (!(phba->pport->load_flag & FC_UNLOADING)) 91562306a36Sopenharmony_ci lpfc_reset_hba(phba); 91662306a36Sopenharmony_ci break; 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci if (free_evt) 91962306a36Sopenharmony_ci kfree(evtp); 92062306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_cistatic void 92762306a36Sopenharmony_cilpfc_work_done(struct lpfc_hba *phba) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci struct lpfc_sli_ring *pring; 93062306a36Sopenharmony_ci uint32_t ha_copy, status, control, work_port_events; 93162306a36Sopenharmony_ci struct lpfc_vport **vports; 93262306a36Sopenharmony_ci struct lpfc_vport *vport; 93362306a36Sopenharmony_ci int i; 93462306a36Sopenharmony_ci bool hba_pci_err; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci hba_pci_err = test_bit(HBA_PCI_ERR, &phba->bit_flags); 93762306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 93862306a36Sopenharmony_ci ha_copy = phba->work_ha; 93962306a36Sopenharmony_ci phba->work_ha = 0; 94062306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 94162306a36Sopenharmony_ci if (hba_pci_err) 94262306a36Sopenharmony_ci ha_copy = 0; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* First, try to post the next mailbox command to SLI4 device */ 94562306a36Sopenharmony_ci if (phba->pci_dev_grp == LPFC_PCI_DEV_OC && !hba_pci_err) 94662306a36Sopenharmony_ci lpfc_sli4_post_async_mbox(phba); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci if (ha_copy & HA_ERATT) { 94962306a36Sopenharmony_ci /* Handle the error attention event */ 95062306a36Sopenharmony_ci lpfc_handle_eratt(phba); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci if (phba->fw_dump_cmpl) { 95362306a36Sopenharmony_ci complete(phba->fw_dump_cmpl); 95462306a36Sopenharmony_ci phba->fw_dump_cmpl = NULL; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (ha_copy & HA_MBATT) 95962306a36Sopenharmony_ci lpfc_sli_handle_mb_event(phba); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (ha_copy & HA_LATT) 96262306a36Sopenharmony_ci lpfc_handle_latt(phba); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* Handle VMID Events */ 96562306a36Sopenharmony_ci if (lpfc_is_vmid_enabled(phba) && !hba_pci_err) { 96662306a36Sopenharmony_ci if (phba->pport->work_port_events & 96762306a36Sopenharmony_ci WORKER_CHECK_VMID_ISSUE_QFPA) { 96862306a36Sopenharmony_ci lpfc_check_vmid_qfpa_issue(phba); 96962306a36Sopenharmony_ci phba->pport->work_port_events &= 97062306a36Sopenharmony_ci ~WORKER_CHECK_VMID_ISSUE_QFPA; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci if (phba->pport->work_port_events & 97362306a36Sopenharmony_ci WORKER_CHECK_INACTIVE_VMID) { 97462306a36Sopenharmony_ci lpfc_check_inactive_vmid(phba); 97562306a36Sopenharmony_ci phba->pport->work_port_events &= 97662306a36Sopenharmony_ci ~WORKER_CHECK_INACTIVE_VMID; 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci /* Process SLI4 events */ 98162306a36Sopenharmony_ci if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) { 98262306a36Sopenharmony_ci if (phba->hba_flag & HBA_RRQ_ACTIVE) 98362306a36Sopenharmony_ci lpfc_handle_rrq_active(phba); 98462306a36Sopenharmony_ci if (phba->hba_flag & ELS_XRI_ABORT_EVENT) 98562306a36Sopenharmony_ci lpfc_sli4_els_xri_abort_event_proc(phba); 98662306a36Sopenharmony_ci if (phba->hba_flag & ASYNC_EVENT) 98762306a36Sopenharmony_ci lpfc_sli4_async_event_proc(phba); 98862306a36Sopenharmony_ci if (phba->hba_flag & HBA_POST_RECEIVE_BUFFER) { 98962306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 99062306a36Sopenharmony_ci phba->hba_flag &= ~HBA_POST_RECEIVE_BUFFER; 99162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 99262306a36Sopenharmony_ci lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci if (phba->fcf.fcf_flag & FCF_REDISC_EVT) 99562306a36Sopenharmony_ci lpfc_sli4_fcf_redisc_event_proc(phba); 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci vports = lpfc_create_vport_work_array(phba); 99962306a36Sopenharmony_ci if (vports != NULL) 100062306a36Sopenharmony_ci for (i = 0; i <= phba->max_vports; i++) { 100162306a36Sopenharmony_ci /* 100262306a36Sopenharmony_ci * We could have no vports in array if unloading, so if 100362306a36Sopenharmony_ci * this happens then just use the pport 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_ci if (vports[i] == NULL && i == 0) 100662306a36Sopenharmony_ci vport = phba->pport; 100762306a36Sopenharmony_ci else 100862306a36Sopenharmony_ci vport = vports[i]; 100962306a36Sopenharmony_ci if (vport == NULL) 101062306a36Sopenharmony_ci break; 101162306a36Sopenharmony_ci spin_lock_irq(&vport->work_port_lock); 101262306a36Sopenharmony_ci work_port_events = vport->work_port_events; 101362306a36Sopenharmony_ci vport->work_port_events &= ~work_port_events; 101462306a36Sopenharmony_ci spin_unlock_irq(&vport->work_port_lock); 101562306a36Sopenharmony_ci if (hba_pci_err) 101662306a36Sopenharmony_ci continue; 101762306a36Sopenharmony_ci if (work_port_events & WORKER_DISC_TMO) 101862306a36Sopenharmony_ci lpfc_disc_timeout_handler(vport); 101962306a36Sopenharmony_ci if (work_port_events & WORKER_ELS_TMO) 102062306a36Sopenharmony_ci lpfc_els_timeout_handler(vport); 102162306a36Sopenharmony_ci if (work_port_events & WORKER_HB_TMO) 102262306a36Sopenharmony_ci lpfc_hb_timeout_handler(phba); 102362306a36Sopenharmony_ci if (work_port_events & WORKER_MBOX_TMO) 102462306a36Sopenharmony_ci lpfc_mbox_timeout_handler(phba); 102562306a36Sopenharmony_ci if (work_port_events & WORKER_FABRIC_BLOCK_TMO) 102662306a36Sopenharmony_ci lpfc_unblock_fabric_iocbs(phba); 102762306a36Sopenharmony_ci if (work_port_events & WORKER_RAMP_DOWN_QUEUE) 102862306a36Sopenharmony_ci lpfc_ramp_down_queue_handler(phba); 102962306a36Sopenharmony_ci if (work_port_events & WORKER_DELAYED_DISC_TMO) 103062306a36Sopenharmony_ci lpfc_delayed_disc_timeout_handler(vport); 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci lpfc_destroy_vport_work_array(phba, vports); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci pring = lpfc_phba_elsring(phba); 103562306a36Sopenharmony_ci status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING))); 103662306a36Sopenharmony_ci status >>= (4*LPFC_ELS_RING); 103762306a36Sopenharmony_ci if (pring && (status & HA_RXMASK || 103862306a36Sopenharmony_ci pring->flag & LPFC_DEFERRED_RING_EVENT || 103962306a36Sopenharmony_ci phba->hba_flag & HBA_SP_QUEUE_EVT)) { 104062306a36Sopenharmony_ci if (pring->flag & LPFC_STOP_IOCB_EVENT) { 104162306a36Sopenharmony_ci pring->flag |= LPFC_DEFERRED_RING_EVENT; 104262306a36Sopenharmony_ci /* Preserve legacy behavior. */ 104362306a36Sopenharmony_ci if (!(phba->hba_flag & HBA_SP_QUEUE_EVT)) 104462306a36Sopenharmony_ci set_bit(LPFC_DATA_READY, &phba->data_flags); 104562306a36Sopenharmony_ci } else { 104662306a36Sopenharmony_ci /* Driver could have abort request completed in queue 104762306a36Sopenharmony_ci * when link goes down. Allow for this transition. 104862306a36Sopenharmony_ci */ 104962306a36Sopenharmony_ci if (phba->link_state >= LPFC_LINK_DOWN || 105062306a36Sopenharmony_ci phba->link_flag & LS_MDS_LOOPBACK) { 105162306a36Sopenharmony_ci pring->flag &= ~LPFC_DEFERRED_RING_EVENT; 105262306a36Sopenharmony_ci lpfc_sli_handle_slow_ring_event(phba, pring, 105362306a36Sopenharmony_ci (status & 105462306a36Sopenharmony_ci HA_RXMASK)); 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4) 105862306a36Sopenharmony_ci lpfc_drain_txq(phba); 105962306a36Sopenharmony_ci /* 106062306a36Sopenharmony_ci * Turn on Ring interrupts 106162306a36Sopenharmony_ci */ 106262306a36Sopenharmony_ci if (phba->sli_rev <= LPFC_SLI_REV3) { 106362306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 106462306a36Sopenharmony_ci control = readl(phba->HCregaddr); 106562306a36Sopenharmony_ci if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) { 106662306a36Sopenharmony_ci lpfc_debugfs_slow_ring_trc(phba, 106762306a36Sopenharmony_ci "WRK Enable ring: cntl:x%x hacopy:x%x", 106862306a36Sopenharmony_ci control, ha_copy, 0); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci control |= (HC_R0INT_ENA << LPFC_ELS_RING); 107162306a36Sopenharmony_ci writel(control, phba->HCregaddr); 107262306a36Sopenharmony_ci readl(phba->HCregaddr); /* flush */ 107362306a36Sopenharmony_ci } else { 107462306a36Sopenharmony_ci lpfc_debugfs_slow_ring_trc(phba, 107562306a36Sopenharmony_ci "WRK Ring ok: cntl:x%x hacopy:x%x", 107662306a36Sopenharmony_ci control, ha_copy, 0); 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci lpfc_work_list_done(phba); 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ciint 108562306a36Sopenharmony_cilpfc_do_work(void *p) 108662306a36Sopenharmony_ci{ 108762306a36Sopenharmony_ci struct lpfc_hba *phba = p; 108862306a36Sopenharmony_ci int rc; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci set_user_nice(current, MIN_NICE); 109162306a36Sopenharmony_ci current->flags |= PF_NOFREEZE; 109262306a36Sopenharmony_ci phba->data_flags = 0; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci while (!kthread_should_stop()) { 109562306a36Sopenharmony_ci /* wait and check worker queue activities */ 109662306a36Sopenharmony_ci rc = wait_event_interruptible(phba->work_waitq, 109762306a36Sopenharmony_ci (test_and_clear_bit(LPFC_DATA_READY, 109862306a36Sopenharmony_ci &phba->data_flags) 109962306a36Sopenharmony_ci || kthread_should_stop())); 110062306a36Sopenharmony_ci /* Signal wakeup shall terminate the worker thread */ 110162306a36Sopenharmony_ci if (rc) { 110262306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 110362306a36Sopenharmony_ci "0433 Wakeup on signal: rc=x%x\n", rc); 110462306a36Sopenharmony_ci break; 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci /* Attend pending lpfc data processing */ 110862306a36Sopenharmony_ci lpfc_work_done(phba); 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci phba->worker_thread = NULL; 111162306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_ELS, 111262306a36Sopenharmony_ci "0432 Worker thread stopped.\n"); 111362306a36Sopenharmony_ci return 0; 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci/* 111762306a36Sopenharmony_ci * This is only called to handle FC worker events. Since this a rare 111862306a36Sopenharmony_ci * occurrence, we allocate a struct lpfc_work_evt structure here instead of 111962306a36Sopenharmony_ci * embedding it in the IOCB. 112062306a36Sopenharmony_ci */ 112162306a36Sopenharmony_ciint 112262306a36Sopenharmony_cilpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, 112362306a36Sopenharmony_ci uint32_t evt) 112462306a36Sopenharmony_ci{ 112562306a36Sopenharmony_ci struct lpfc_work_evt *evtp; 112662306a36Sopenharmony_ci unsigned long flags; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci /* 112962306a36Sopenharmony_ci * All Mailbox completions and LPFC_ELS_RING rcv ring IOCB events will 113062306a36Sopenharmony_ci * be queued to worker thread for processing 113162306a36Sopenharmony_ci */ 113262306a36Sopenharmony_ci evtp = kmalloc(sizeof(struct lpfc_work_evt), GFP_ATOMIC); 113362306a36Sopenharmony_ci if (!evtp) 113462306a36Sopenharmony_ci return 0; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci evtp->evt_arg1 = arg1; 113762306a36Sopenharmony_ci evtp->evt_arg2 = arg2; 113862306a36Sopenharmony_ci evtp->evt = evt; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci spin_lock_irqsave(&phba->hbalock, flags); 114162306a36Sopenharmony_ci list_add_tail(&evtp->evt_listp, &phba->work_list); 114262306a36Sopenharmony_ci spin_unlock_irqrestore(&phba->hbalock, flags); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci lpfc_worker_wake_up(phba); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci return 1; 114762306a36Sopenharmony_ci} 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_civoid 115062306a36Sopenharmony_cilpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) 115162306a36Sopenharmony_ci{ 115262306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 115362306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 115462306a36Sopenharmony_ci struct lpfc_nodelist *ndlp, *next_ndlp; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { 115762306a36Sopenharmony_ci if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) || 115862306a36Sopenharmony_ci ((vport->port_type == LPFC_NPIV_PORT) && 115962306a36Sopenharmony_ci ((ndlp->nlp_DID == NameServer_DID) || 116062306a36Sopenharmony_ci (ndlp->nlp_DID == FDMI_DID) || 116162306a36Sopenharmony_ci (ndlp->nlp_DID == Fabric_Cntl_DID)))) 116262306a36Sopenharmony_ci lpfc_unreg_rpi(vport, ndlp); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* Leave Fabric nodes alone on link down */ 116562306a36Sopenharmony_ci if ((phba->sli_rev < LPFC_SLI_REV4) && 116662306a36Sopenharmony_ci (!remove && ndlp->nlp_type & NLP_FABRIC)) 116762306a36Sopenharmony_ci continue; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci /* Notify transport of connectivity loss to trigger cleanup. */ 117062306a36Sopenharmony_ci if (phba->nvmet_support && 117162306a36Sopenharmony_ci ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) 117262306a36Sopenharmony_ci lpfc_nvmet_invalidate_host(phba, ndlp); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci lpfc_disc_state_machine(vport, ndlp, NULL, 117562306a36Sopenharmony_ci remove 117662306a36Sopenharmony_ci ? NLP_EVT_DEVICE_RM 117762306a36Sopenharmony_ci : NLP_EVT_DEVICE_RECOVERY); 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) { 118062306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4) 118162306a36Sopenharmony_ci lpfc_sli4_unreg_all_rpis(vport); 118262306a36Sopenharmony_ci lpfc_mbx_unreg_vpi(vport); 118362306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 118462306a36Sopenharmony_ci vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; 118562306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci} 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_civoid 119062306a36Sopenharmony_cilpfc_port_link_failure(struct lpfc_vport *vport) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci /* Cleanup any outstanding received buffers */ 119562306a36Sopenharmony_ci lpfc_cleanup_rcv_buffers(vport); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci /* Cleanup any outstanding RSCN activity */ 119862306a36Sopenharmony_ci lpfc_els_flush_rscn(vport); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci /* Cleanup any outstanding ELS commands */ 120162306a36Sopenharmony_ci lpfc_els_flush_cmd(vport); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci lpfc_cleanup_rpis(vport, 0); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci /* Turn off discovery timer if its running */ 120662306a36Sopenharmony_ci lpfc_can_disctmo(vport); 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_civoid 121062306a36Sopenharmony_cilpfc_linkdown_port(struct lpfc_vport *vport) 121162306a36Sopenharmony_ci{ 121262306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 121362306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci if (vport->cfg_enable_fc4_type != LPFC_ENABLE_NVME) 121662306a36Sopenharmony_ci fc_host_post_event(shost, fc_get_event_number(), 121762306a36Sopenharmony_ci FCH_EVT_LINKDOWN, 0); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, 122062306a36Sopenharmony_ci "Link Down: state:x%x rtry:x%x flg:x%x", 122162306a36Sopenharmony_ci vport->port_state, vport->fc_ns_retry, vport->fc_flag); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci lpfc_port_link_failure(vport); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci /* Stop delayed Nport discovery */ 122662306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 122762306a36Sopenharmony_ci vport->fc_flag &= ~FC_DISC_DELAYED; 122862306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 122962306a36Sopenharmony_ci del_timer_sync(&vport->delayed_disc_tmo); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4 && 123262306a36Sopenharmony_ci vport->port_type == LPFC_PHYSICAL_PORT && 123362306a36Sopenharmony_ci phba->sli4_hba.fawwpn_flag & LPFC_FAWWPN_CONFIG) { 123462306a36Sopenharmony_ci /* Assume success on link up */ 123562306a36Sopenharmony_ci phba->sli4_hba.fawwpn_flag |= LPFC_FAWWPN_FABRIC; 123662306a36Sopenharmony_ci } 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ciint 124062306a36Sopenharmony_cilpfc_linkdown(struct lpfc_hba *phba) 124162306a36Sopenharmony_ci{ 124262306a36Sopenharmony_ci struct lpfc_vport *vport = phba->pport; 124362306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 124462306a36Sopenharmony_ci struct lpfc_vport **vports; 124562306a36Sopenharmony_ci LPFC_MBOXQ_t *mb; 124662306a36Sopenharmony_ci int i; 124762306a36Sopenharmony_ci int offline; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci if (phba->link_state == LPFC_LINK_DOWN) 125062306a36Sopenharmony_ci return 0; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* Block all SCSI stack I/Os */ 125362306a36Sopenharmony_ci lpfc_scsi_dev_block(phba); 125462306a36Sopenharmony_ci offline = pci_channel_offline(phba->pcidev); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci phba->defer_flogi_acc_flag = false; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci /* Clear external loopback plug detected flag */ 125962306a36Sopenharmony_ci phba->link_flag &= ~LS_EXTERNAL_LOOPBACK; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 126262306a36Sopenharmony_ci phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE); 126362306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 126462306a36Sopenharmony_ci if (phba->link_state > LPFC_LINK_DOWN) { 126562306a36Sopenharmony_ci phba->link_state = LPFC_LINK_DOWN; 126662306a36Sopenharmony_ci if (phba->sli4_hba.conf_trunk) { 126762306a36Sopenharmony_ci phba->trunk_link.link0.state = 0; 126862306a36Sopenharmony_ci phba->trunk_link.link1.state = 0; 126962306a36Sopenharmony_ci phba->trunk_link.link2.state = 0; 127062306a36Sopenharmony_ci phba->trunk_link.link3.state = 0; 127162306a36Sopenharmony_ci phba->trunk_link.phy_lnk_speed = 127262306a36Sopenharmony_ci LPFC_LINK_SPEED_UNKNOWN; 127362306a36Sopenharmony_ci phba->sli4_hba.link_state.logical_speed = 127462306a36Sopenharmony_ci LPFC_LINK_SPEED_UNKNOWN; 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 127762306a36Sopenharmony_ci phba->pport->fc_flag &= ~FC_LBIT; 127862306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci vports = lpfc_create_vport_work_array(phba); 128162306a36Sopenharmony_ci if (vports != NULL) { 128262306a36Sopenharmony_ci for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { 128362306a36Sopenharmony_ci /* Issue a LINK DOWN event to all nodes */ 128462306a36Sopenharmony_ci lpfc_linkdown_port(vports[i]); 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci vports[i]->fc_myDID = 0; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || 128962306a36Sopenharmony_ci (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) { 129062306a36Sopenharmony_ci if (phba->nvmet_support) 129162306a36Sopenharmony_ci lpfc_nvmet_update_targetport(phba); 129262306a36Sopenharmony_ci else 129362306a36Sopenharmony_ci lpfc_nvme_update_localport(vports[i]); 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci lpfc_destroy_vport_work_array(phba, vports); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci /* Clean up any SLI3 firmware default rpi's */ 130062306a36Sopenharmony_ci if (phba->sli_rev > LPFC_SLI_REV3 || offline) 130162306a36Sopenharmony_ci goto skip_unreg_did; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 130462306a36Sopenharmony_ci if (mb) { 130562306a36Sopenharmony_ci lpfc_unreg_did(phba, 0xffff, LPFC_UNREG_ALL_DFLT_RPIS, mb); 130662306a36Sopenharmony_ci mb->vport = vport; 130762306a36Sopenharmony_ci mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; 130862306a36Sopenharmony_ci if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT) 130962306a36Sopenharmony_ci == MBX_NOT_FINISHED) { 131062306a36Sopenharmony_ci mempool_free(mb, phba->mbox_mem_pool); 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci skip_unreg_did: 131562306a36Sopenharmony_ci /* Setup myDID for link up if we are in pt2pt mode */ 131662306a36Sopenharmony_ci if (phba->pport->fc_flag & FC_PT2PT) { 131762306a36Sopenharmony_ci mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 131862306a36Sopenharmony_ci if (mb) { 131962306a36Sopenharmony_ci lpfc_config_link(phba, mb); 132062306a36Sopenharmony_ci mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; 132162306a36Sopenharmony_ci mb->vport = vport; 132262306a36Sopenharmony_ci if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT) 132362306a36Sopenharmony_ci == MBX_NOT_FINISHED) { 132462306a36Sopenharmony_ci mempool_free(mb, phba->mbox_mem_pool); 132562306a36Sopenharmony_ci } 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 132862306a36Sopenharmony_ci phba->pport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI); 132962306a36Sopenharmony_ci phba->pport->rcv_flogi_cnt = 0; 133062306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci return 0; 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_cistatic void 133662306a36Sopenharmony_cilpfc_linkup_cleanup_nodes(struct lpfc_vport *vport) 133762306a36Sopenharmony_ci{ 133862306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { 134162306a36Sopenharmony_ci ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) 134462306a36Sopenharmony_ci continue; 134562306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_FABRIC) { 134662306a36Sopenharmony_ci /* On Linkup its safe to clean up the ndlp 134762306a36Sopenharmony_ci * from Fabric connections. 134862306a36Sopenharmony_ci */ 134962306a36Sopenharmony_ci if (ndlp->nlp_DID != Fabric_DID) 135062306a36Sopenharmony_ci lpfc_unreg_rpi(vport, ndlp); 135162306a36Sopenharmony_ci lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); 135262306a36Sopenharmony_ci } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { 135362306a36Sopenharmony_ci /* Fail outstanding IO now since device is 135462306a36Sopenharmony_ci * marked for PLOGI. 135562306a36Sopenharmony_ci */ 135662306a36Sopenharmony_ci lpfc_unreg_rpi(vport, ndlp); 135762306a36Sopenharmony_ci } 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_cistatic void 136262306a36Sopenharmony_cilpfc_linkup_port(struct lpfc_vport *vport) 136362306a36Sopenharmony_ci{ 136462306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 136562306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci if ((vport->load_flag & FC_UNLOADING) != 0) 136862306a36Sopenharmony_ci return; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, 137162306a36Sopenharmony_ci "Link Up: top:x%x speed:x%x flg:x%x", 137262306a36Sopenharmony_ci phba->fc_topology, phba->fc_linkspeed, phba->link_flag); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci /* If NPIV is not enabled, only bring the physical port up */ 137562306a36Sopenharmony_ci if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && 137662306a36Sopenharmony_ci (vport != phba->pport)) 137762306a36Sopenharmony_ci return; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci if (vport->cfg_enable_fc4_type != LPFC_ENABLE_NVME) 138062306a36Sopenharmony_ci fc_host_post_event(shost, fc_get_event_number(), 138162306a36Sopenharmony_ci FCH_EVT_LINKUP, 0); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 138462306a36Sopenharmony_ci if (phba->defer_flogi_acc_flag) 138562306a36Sopenharmony_ci vport->fc_flag &= ~(FC_ABORT_DISCOVERY | FC_RSCN_MODE | 138662306a36Sopenharmony_ci FC_NLP_MORE | FC_RSCN_DISCOVERY); 138762306a36Sopenharmony_ci else 138862306a36Sopenharmony_ci vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | 138962306a36Sopenharmony_ci FC_ABORT_DISCOVERY | FC_RSCN_MODE | 139062306a36Sopenharmony_ci FC_NLP_MORE | FC_RSCN_DISCOVERY); 139162306a36Sopenharmony_ci vport->fc_flag |= FC_NDISC_ACTIVE; 139262306a36Sopenharmony_ci vport->fc_ns_retry = 0; 139362306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 139462306a36Sopenharmony_ci lpfc_setup_fdmi_mask(vport); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci lpfc_linkup_cleanup_nodes(vport); 139762306a36Sopenharmony_ci} 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_cistatic int 140062306a36Sopenharmony_cilpfc_linkup(struct lpfc_hba *phba) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci struct lpfc_vport **vports; 140362306a36Sopenharmony_ci int i; 140462306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci phba->link_state = LPFC_LINK_UP; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci /* Unblock fabric iocbs if they are blocked */ 140962306a36Sopenharmony_ci clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags); 141062306a36Sopenharmony_ci del_timer_sync(&phba->fabric_block_timer); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci vports = lpfc_create_vport_work_array(phba); 141362306a36Sopenharmony_ci if (vports != NULL) 141462306a36Sopenharmony_ci for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) 141562306a36Sopenharmony_ci lpfc_linkup_port(vports[i]); 141662306a36Sopenharmony_ci lpfc_destroy_vport_work_array(phba, vports); 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci /* Clear the pport flogi counter in case the link down was 141962306a36Sopenharmony_ci * absorbed without an ACQE. No lock here - in worker thread 142062306a36Sopenharmony_ci * and discovery is synchronized. 142162306a36Sopenharmony_ci */ 142262306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 142362306a36Sopenharmony_ci phba->pport->rcv_flogi_cnt = 0; 142462306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci /* reinitialize initial HBA flag */ 142762306a36Sopenharmony_ci phba->hba_flag &= ~(HBA_FLOGI_ISSUED | HBA_RHBA_CMPL); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci return 0; 143062306a36Sopenharmony_ci} 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci/* 143362306a36Sopenharmony_ci * This routine handles processing a CLEAR_LA mailbox 143462306a36Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ 143562306a36Sopenharmony_ci * as the completion routine when the command is 143662306a36Sopenharmony_ci * handed off to the SLI layer. SLI3 only. 143762306a36Sopenharmony_ci */ 143862306a36Sopenharmony_cistatic void 143962306a36Sopenharmony_cilpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci struct lpfc_vport *vport = pmb->vport; 144262306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 144362306a36Sopenharmony_ci struct lpfc_sli *psli = &phba->sli; 144462306a36Sopenharmony_ci MAILBOX_t *mb = &pmb->u.mb; 144562306a36Sopenharmony_ci uint32_t control; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci /* Since we don't do discovery right now, turn these off here */ 144862306a36Sopenharmony_ci psli->sli3_ring[LPFC_EXTRA_RING].flag &= ~LPFC_STOP_IOCB_EVENT; 144962306a36Sopenharmony_ci psli->sli3_ring[LPFC_FCP_RING].flag &= ~LPFC_STOP_IOCB_EVENT; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci /* Check for error */ 145262306a36Sopenharmony_ci if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) { 145362306a36Sopenharmony_ci /* CLEAR_LA mbox error <mbxStatus> state <hba_state> */ 145462306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 145562306a36Sopenharmony_ci "0320 CLEAR_LA mbxStatus error x%x hba " 145662306a36Sopenharmony_ci "state x%x\n", 145762306a36Sopenharmony_ci mb->mbxStatus, vport->port_state); 145862306a36Sopenharmony_ci phba->link_state = LPFC_HBA_ERROR; 145962306a36Sopenharmony_ci goto out; 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if (vport->port_type == LPFC_PHYSICAL_PORT) 146362306a36Sopenharmony_ci phba->link_state = LPFC_HBA_READY; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 146662306a36Sopenharmony_ci psli->sli_flag |= LPFC_PROCESS_LA; 146762306a36Sopenharmony_ci control = readl(phba->HCregaddr); 146862306a36Sopenharmony_ci control |= HC_LAINT_ENA; 146962306a36Sopenharmony_ci writel(control, phba->HCregaddr); 147062306a36Sopenharmony_ci readl(phba->HCregaddr); /* flush */ 147162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 147262306a36Sopenharmony_ci mempool_free(pmb, phba->mbox_mem_pool); 147362306a36Sopenharmony_ci return; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ciout: 147662306a36Sopenharmony_ci /* Device Discovery completes */ 147762306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 147862306a36Sopenharmony_ci "0225 Device Discovery completes\n"); 147962306a36Sopenharmony_ci mempool_free(pmb, phba->mbox_mem_pool); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 148262306a36Sopenharmony_ci vport->fc_flag &= ~FC_ABORT_DISCOVERY; 148362306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci lpfc_can_disctmo(vport); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci /* turn on Link Attention interrupts */ 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 149062306a36Sopenharmony_ci psli->sli_flag |= LPFC_PROCESS_LA; 149162306a36Sopenharmony_ci control = readl(phba->HCregaddr); 149262306a36Sopenharmony_ci control |= HC_LAINT_ENA; 149362306a36Sopenharmony_ci writel(control, phba->HCregaddr); 149462306a36Sopenharmony_ci readl(phba->HCregaddr); /* flush */ 149562306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci return; 149862306a36Sopenharmony_ci} 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_civoid 150162306a36Sopenharmony_cilpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci struct lpfc_vport *vport = pmb->vport; 150462306a36Sopenharmony_ci LPFC_MBOXQ_t *sparam_mb; 150562306a36Sopenharmony_ci u16 status = pmb->u.mb.mbxStatus; 150662306a36Sopenharmony_ci int rc; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci mempool_free(pmb, phba->mbox_mem_pool); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci if (status) 151162306a36Sopenharmony_ci goto out; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci /* don't perform discovery for SLI4 loopback diagnostic test */ 151462306a36Sopenharmony_ci if ((phba->sli_rev == LPFC_SLI_REV4) && 151562306a36Sopenharmony_ci !(phba->hba_flag & HBA_FCOE_MODE) && 151662306a36Sopenharmony_ci (phba->link_flag & LS_LOOPBACK_MODE)) 151762306a36Sopenharmony_ci return; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci if (phba->fc_topology == LPFC_TOPOLOGY_LOOP && 152062306a36Sopenharmony_ci vport->fc_flag & FC_PUBLIC_LOOP && 152162306a36Sopenharmony_ci !(vport->fc_flag & FC_LBIT)) { 152262306a36Sopenharmony_ci /* Need to wait for FAN - use discovery timer 152362306a36Sopenharmony_ci * for timeout. port_state is identically 152462306a36Sopenharmony_ci * LPFC_LOCAL_CFG_LINK while waiting for FAN 152562306a36Sopenharmony_ci */ 152662306a36Sopenharmony_ci lpfc_set_disctmo(vport); 152762306a36Sopenharmony_ci return; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci /* Start discovery by sending a FLOGI. port_state is identically 153162306a36Sopenharmony_ci * LPFC_FLOGI while waiting for FLOGI cmpl. 153262306a36Sopenharmony_ci */ 153362306a36Sopenharmony_ci if (vport->port_state != LPFC_FLOGI) { 153462306a36Sopenharmony_ci /* Issue MBX_READ_SPARAM to update CSPs before FLOGI if 153562306a36Sopenharmony_ci * bb-credit recovery is in place. 153662306a36Sopenharmony_ci */ 153762306a36Sopenharmony_ci if (phba->bbcredit_support && phba->cfg_enable_bbcr && 153862306a36Sopenharmony_ci !(phba->link_flag & LS_LOOPBACK_MODE)) { 153962306a36Sopenharmony_ci sparam_mb = mempool_alloc(phba->mbox_mem_pool, 154062306a36Sopenharmony_ci GFP_KERNEL); 154162306a36Sopenharmony_ci if (!sparam_mb) 154262306a36Sopenharmony_ci goto sparam_out; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci rc = lpfc_read_sparam(phba, sparam_mb, 0); 154562306a36Sopenharmony_ci if (rc) { 154662306a36Sopenharmony_ci mempool_free(sparam_mb, phba->mbox_mem_pool); 154762306a36Sopenharmony_ci goto sparam_out; 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci sparam_mb->vport = vport; 155062306a36Sopenharmony_ci sparam_mb->mbox_cmpl = lpfc_mbx_cmpl_read_sparam; 155162306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox(phba, sparam_mb, MBX_NOWAIT); 155262306a36Sopenharmony_ci if (rc == MBX_NOT_FINISHED) { 155362306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, sparam_mb, 155462306a36Sopenharmony_ci MBOX_THD_UNLOCKED); 155562306a36Sopenharmony_ci goto sparam_out; 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci phba->hba_flag |= HBA_DEFER_FLOGI; 155962306a36Sopenharmony_ci } else { 156062306a36Sopenharmony_ci lpfc_initial_flogi(vport); 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci } else { 156362306a36Sopenharmony_ci if (vport->fc_flag & FC_PT2PT) 156462306a36Sopenharmony_ci lpfc_disc_start(vport); 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci return; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ciout: 156962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 157062306a36Sopenharmony_ci "0306 CONFIG_LINK mbxStatus error x%x HBA state x%x\n", 157162306a36Sopenharmony_ci status, vport->port_state); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_cisparam_out: 157462306a36Sopenharmony_ci lpfc_linkdown(phba); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 157762306a36Sopenharmony_ci "0200 CONFIG_LINK bad hba state x%x\n", 157862306a36Sopenharmony_ci vport->port_state); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci lpfc_issue_clear_la(phba, vport); 158162306a36Sopenharmony_ci return; 158262306a36Sopenharmony_ci} 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci/** 158562306a36Sopenharmony_ci * lpfc_sli4_clear_fcf_rr_bmask 158662306a36Sopenharmony_ci * @phba: pointer to the struct lpfc_hba for this port. 158762306a36Sopenharmony_ci * This fucnction resets the round robin bit mask and clears the 158862306a36Sopenharmony_ci * fcf priority list. The list deletions are done while holding the 158962306a36Sopenharmony_ci * hbalock. The ON_LIST flag and the FLOGI_FAILED flags are cleared 159062306a36Sopenharmony_ci * from the lpfc_fcf_pri record. 159162306a36Sopenharmony_ci **/ 159262306a36Sopenharmony_civoid 159362306a36Sopenharmony_cilpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *phba) 159462306a36Sopenharmony_ci{ 159562306a36Sopenharmony_ci struct lpfc_fcf_pri *fcf_pri; 159662306a36Sopenharmony_ci struct lpfc_fcf_pri *next_fcf_pri; 159762306a36Sopenharmony_ci memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask)); 159862306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 159962306a36Sopenharmony_ci list_for_each_entry_safe(fcf_pri, next_fcf_pri, 160062306a36Sopenharmony_ci &phba->fcf.fcf_pri_list, list) { 160162306a36Sopenharmony_ci list_del_init(&fcf_pri->list); 160262306a36Sopenharmony_ci fcf_pri->fcf_rec.flag = 0; 160362306a36Sopenharmony_ci } 160462306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 160562306a36Sopenharmony_ci} 160662306a36Sopenharmony_cistatic void 160762306a36Sopenharmony_cilpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) 160862306a36Sopenharmony_ci{ 160962306a36Sopenharmony_ci struct lpfc_vport *vport = mboxq->vport; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci if (mboxq->u.mb.mbxStatus) { 161262306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 161362306a36Sopenharmony_ci "2017 REG_FCFI mbxStatus error x%x " 161462306a36Sopenharmony_ci "HBA state x%x\n", mboxq->u.mb.mbxStatus, 161562306a36Sopenharmony_ci vport->port_state); 161662306a36Sopenharmony_ci goto fail_out; 161762306a36Sopenharmony_ci } 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci /* Start FCoE discovery by sending a FLOGI. */ 162062306a36Sopenharmony_ci phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, &mboxq->u.mqe.un.reg_fcfi); 162162306a36Sopenharmony_ci /* Set the FCFI registered flag */ 162262306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 162362306a36Sopenharmony_ci phba->fcf.fcf_flag |= FCF_REGISTERED; 162462306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci /* If there is a pending FCoE event, restart FCF table scan. */ 162762306a36Sopenharmony_ci if ((!(phba->hba_flag & FCF_RR_INPROG)) && 162862306a36Sopenharmony_ci lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF)) 162962306a36Sopenharmony_ci goto fail_out; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci /* Mark successful completion of FCF table scan */ 163262306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 163362306a36Sopenharmony_ci phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE); 163462306a36Sopenharmony_ci phba->hba_flag &= ~FCF_TS_INPROG; 163562306a36Sopenharmony_ci if (vport->port_state != LPFC_FLOGI) { 163662306a36Sopenharmony_ci phba->hba_flag |= FCF_RR_INPROG; 163762306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 163862306a36Sopenharmony_ci lpfc_issue_init_vfi(vport); 163962306a36Sopenharmony_ci goto out; 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 164262306a36Sopenharmony_ci goto out; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_cifail_out: 164562306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 164662306a36Sopenharmony_ci phba->hba_flag &= ~FCF_RR_INPROG; 164762306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 164862306a36Sopenharmony_ciout: 164962306a36Sopenharmony_ci mempool_free(mboxq, phba->mbox_mem_pool); 165062306a36Sopenharmony_ci} 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci/** 165362306a36Sopenharmony_ci * lpfc_fab_name_match - Check if the fcf fabric name match. 165462306a36Sopenharmony_ci * @fab_name: pointer to fabric name. 165562306a36Sopenharmony_ci * @new_fcf_record: pointer to fcf record. 165662306a36Sopenharmony_ci * 165762306a36Sopenharmony_ci * This routine compare the fcf record's fabric name with provided 165862306a36Sopenharmony_ci * fabric name. If the fabric name are identical this function 165962306a36Sopenharmony_ci * returns 1 else return 0. 166062306a36Sopenharmony_ci **/ 166162306a36Sopenharmony_cistatic uint32_t 166262306a36Sopenharmony_cilpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record) 166362306a36Sopenharmony_ci{ 166462306a36Sopenharmony_ci if (fab_name[0] != bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record)) 166562306a36Sopenharmony_ci return 0; 166662306a36Sopenharmony_ci if (fab_name[1] != bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record)) 166762306a36Sopenharmony_ci return 0; 166862306a36Sopenharmony_ci if (fab_name[2] != bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record)) 166962306a36Sopenharmony_ci return 0; 167062306a36Sopenharmony_ci if (fab_name[3] != bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record)) 167162306a36Sopenharmony_ci return 0; 167262306a36Sopenharmony_ci if (fab_name[4] != bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record)) 167362306a36Sopenharmony_ci return 0; 167462306a36Sopenharmony_ci if (fab_name[5] != bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record)) 167562306a36Sopenharmony_ci return 0; 167662306a36Sopenharmony_ci if (fab_name[6] != bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record)) 167762306a36Sopenharmony_ci return 0; 167862306a36Sopenharmony_ci if (fab_name[7] != bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record)) 167962306a36Sopenharmony_ci return 0; 168062306a36Sopenharmony_ci return 1; 168162306a36Sopenharmony_ci} 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci/** 168462306a36Sopenharmony_ci * lpfc_sw_name_match - Check if the fcf switch name match. 168562306a36Sopenharmony_ci * @sw_name: pointer to switch name. 168662306a36Sopenharmony_ci * @new_fcf_record: pointer to fcf record. 168762306a36Sopenharmony_ci * 168862306a36Sopenharmony_ci * This routine compare the fcf record's switch name with provided 168962306a36Sopenharmony_ci * switch name. If the switch name are identical this function 169062306a36Sopenharmony_ci * returns 1 else return 0. 169162306a36Sopenharmony_ci **/ 169262306a36Sopenharmony_cistatic uint32_t 169362306a36Sopenharmony_cilpfc_sw_name_match(uint8_t *sw_name, struct fcf_record *new_fcf_record) 169462306a36Sopenharmony_ci{ 169562306a36Sopenharmony_ci if (sw_name[0] != bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record)) 169662306a36Sopenharmony_ci return 0; 169762306a36Sopenharmony_ci if (sw_name[1] != bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record)) 169862306a36Sopenharmony_ci return 0; 169962306a36Sopenharmony_ci if (sw_name[2] != bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record)) 170062306a36Sopenharmony_ci return 0; 170162306a36Sopenharmony_ci if (sw_name[3] != bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record)) 170262306a36Sopenharmony_ci return 0; 170362306a36Sopenharmony_ci if (sw_name[4] != bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record)) 170462306a36Sopenharmony_ci return 0; 170562306a36Sopenharmony_ci if (sw_name[5] != bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record)) 170662306a36Sopenharmony_ci return 0; 170762306a36Sopenharmony_ci if (sw_name[6] != bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record)) 170862306a36Sopenharmony_ci return 0; 170962306a36Sopenharmony_ci if (sw_name[7] != bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record)) 171062306a36Sopenharmony_ci return 0; 171162306a36Sopenharmony_ci return 1; 171262306a36Sopenharmony_ci} 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci/** 171562306a36Sopenharmony_ci * lpfc_mac_addr_match - Check if the fcf mac address match. 171662306a36Sopenharmony_ci * @mac_addr: pointer to mac address. 171762306a36Sopenharmony_ci * @new_fcf_record: pointer to fcf record. 171862306a36Sopenharmony_ci * 171962306a36Sopenharmony_ci * This routine compare the fcf record's mac address with HBA's 172062306a36Sopenharmony_ci * FCF mac address. If the mac addresses are identical this function 172162306a36Sopenharmony_ci * returns 1 else return 0. 172262306a36Sopenharmony_ci **/ 172362306a36Sopenharmony_cistatic uint32_t 172462306a36Sopenharmony_cilpfc_mac_addr_match(uint8_t *mac_addr, struct fcf_record *new_fcf_record) 172562306a36Sopenharmony_ci{ 172662306a36Sopenharmony_ci if (mac_addr[0] != bf_get(lpfc_fcf_record_mac_0, new_fcf_record)) 172762306a36Sopenharmony_ci return 0; 172862306a36Sopenharmony_ci if (mac_addr[1] != bf_get(lpfc_fcf_record_mac_1, new_fcf_record)) 172962306a36Sopenharmony_ci return 0; 173062306a36Sopenharmony_ci if (mac_addr[2] != bf_get(lpfc_fcf_record_mac_2, new_fcf_record)) 173162306a36Sopenharmony_ci return 0; 173262306a36Sopenharmony_ci if (mac_addr[3] != bf_get(lpfc_fcf_record_mac_3, new_fcf_record)) 173362306a36Sopenharmony_ci return 0; 173462306a36Sopenharmony_ci if (mac_addr[4] != bf_get(lpfc_fcf_record_mac_4, new_fcf_record)) 173562306a36Sopenharmony_ci return 0; 173662306a36Sopenharmony_ci if (mac_addr[5] != bf_get(lpfc_fcf_record_mac_5, new_fcf_record)) 173762306a36Sopenharmony_ci return 0; 173862306a36Sopenharmony_ci return 1; 173962306a36Sopenharmony_ci} 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_cistatic bool 174262306a36Sopenharmony_cilpfc_vlan_id_match(uint16_t curr_vlan_id, uint16_t new_vlan_id) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci return (curr_vlan_id == new_vlan_id); 174562306a36Sopenharmony_ci} 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci/** 174862306a36Sopenharmony_ci * __lpfc_update_fcf_record_pri - update the lpfc_fcf_pri record. 174962306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 175062306a36Sopenharmony_ci * @fcf_index: Index for the lpfc_fcf_record. 175162306a36Sopenharmony_ci * @new_fcf_record: pointer to hba fcf record. 175262306a36Sopenharmony_ci * 175362306a36Sopenharmony_ci * This routine updates the driver FCF priority record from the new HBA FCF 175462306a36Sopenharmony_ci * record. The hbalock is asserted held in the code path calling this 175562306a36Sopenharmony_ci * routine. 175662306a36Sopenharmony_ci **/ 175762306a36Sopenharmony_cistatic void 175862306a36Sopenharmony_ci__lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index, 175962306a36Sopenharmony_ci struct fcf_record *new_fcf_record 176062306a36Sopenharmony_ci ) 176162306a36Sopenharmony_ci{ 176262306a36Sopenharmony_ci struct lpfc_fcf_pri *fcf_pri; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci fcf_pri = &phba->fcf.fcf_pri[fcf_index]; 176562306a36Sopenharmony_ci fcf_pri->fcf_rec.fcf_index = fcf_index; 176662306a36Sopenharmony_ci /* FCF record priority */ 176762306a36Sopenharmony_ci fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority; 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci} 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci/** 177262306a36Sopenharmony_ci * lpfc_copy_fcf_record - Copy fcf information to lpfc_hba. 177362306a36Sopenharmony_ci * @fcf_rec: pointer to driver fcf record. 177462306a36Sopenharmony_ci * @new_fcf_record: pointer to fcf record. 177562306a36Sopenharmony_ci * 177662306a36Sopenharmony_ci * This routine copies the FCF information from the FCF 177762306a36Sopenharmony_ci * record to lpfc_hba data structure. 177862306a36Sopenharmony_ci **/ 177962306a36Sopenharmony_cistatic void 178062306a36Sopenharmony_cilpfc_copy_fcf_record(struct lpfc_fcf_rec *fcf_rec, 178162306a36Sopenharmony_ci struct fcf_record *new_fcf_record) 178262306a36Sopenharmony_ci{ 178362306a36Sopenharmony_ci /* Fabric name */ 178462306a36Sopenharmony_ci fcf_rec->fabric_name[0] = 178562306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record); 178662306a36Sopenharmony_ci fcf_rec->fabric_name[1] = 178762306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record); 178862306a36Sopenharmony_ci fcf_rec->fabric_name[2] = 178962306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record); 179062306a36Sopenharmony_ci fcf_rec->fabric_name[3] = 179162306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record); 179262306a36Sopenharmony_ci fcf_rec->fabric_name[4] = 179362306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record); 179462306a36Sopenharmony_ci fcf_rec->fabric_name[5] = 179562306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record); 179662306a36Sopenharmony_ci fcf_rec->fabric_name[6] = 179762306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record); 179862306a36Sopenharmony_ci fcf_rec->fabric_name[7] = 179962306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record); 180062306a36Sopenharmony_ci /* Mac address */ 180162306a36Sopenharmony_ci fcf_rec->mac_addr[0] = bf_get(lpfc_fcf_record_mac_0, new_fcf_record); 180262306a36Sopenharmony_ci fcf_rec->mac_addr[1] = bf_get(lpfc_fcf_record_mac_1, new_fcf_record); 180362306a36Sopenharmony_ci fcf_rec->mac_addr[2] = bf_get(lpfc_fcf_record_mac_2, new_fcf_record); 180462306a36Sopenharmony_ci fcf_rec->mac_addr[3] = bf_get(lpfc_fcf_record_mac_3, new_fcf_record); 180562306a36Sopenharmony_ci fcf_rec->mac_addr[4] = bf_get(lpfc_fcf_record_mac_4, new_fcf_record); 180662306a36Sopenharmony_ci fcf_rec->mac_addr[5] = bf_get(lpfc_fcf_record_mac_5, new_fcf_record); 180762306a36Sopenharmony_ci /* FCF record index */ 180862306a36Sopenharmony_ci fcf_rec->fcf_indx = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); 180962306a36Sopenharmony_ci /* FCF record priority */ 181062306a36Sopenharmony_ci fcf_rec->priority = new_fcf_record->fip_priority; 181162306a36Sopenharmony_ci /* Switch name */ 181262306a36Sopenharmony_ci fcf_rec->switch_name[0] = 181362306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record); 181462306a36Sopenharmony_ci fcf_rec->switch_name[1] = 181562306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record); 181662306a36Sopenharmony_ci fcf_rec->switch_name[2] = 181762306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record); 181862306a36Sopenharmony_ci fcf_rec->switch_name[3] = 181962306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record); 182062306a36Sopenharmony_ci fcf_rec->switch_name[4] = 182162306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record); 182262306a36Sopenharmony_ci fcf_rec->switch_name[5] = 182362306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record); 182462306a36Sopenharmony_ci fcf_rec->switch_name[6] = 182562306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record); 182662306a36Sopenharmony_ci fcf_rec->switch_name[7] = 182762306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record); 182862306a36Sopenharmony_ci} 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci/** 183162306a36Sopenharmony_ci * __lpfc_update_fcf_record - Update driver fcf record 183262306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 183362306a36Sopenharmony_ci * @fcf_rec: pointer to driver fcf record. 183462306a36Sopenharmony_ci * @new_fcf_record: pointer to hba fcf record. 183562306a36Sopenharmony_ci * @addr_mode: address mode to be set to the driver fcf record. 183662306a36Sopenharmony_ci * @vlan_id: vlan tag to be set to the driver fcf record. 183762306a36Sopenharmony_ci * @flag: flag bits to be set to the driver fcf record. 183862306a36Sopenharmony_ci * 183962306a36Sopenharmony_ci * This routine updates the driver FCF record from the new HBA FCF record 184062306a36Sopenharmony_ci * together with the address mode, vlan_id, and other informations. This 184162306a36Sopenharmony_ci * routine is called with the hbalock held. 184262306a36Sopenharmony_ci **/ 184362306a36Sopenharmony_cistatic void 184462306a36Sopenharmony_ci__lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec, 184562306a36Sopenharmony_ci struct fcf_record *new_fcf_record, uint32_t addr_mode, 184662306a36Sopenharmony_ci uint16_t vlan_id, uint32_t flag) 184762306a36Sopenharmony_ci{ 184862306a36Sopenharmony_ci lockdep_assert_held(&phba->hbalock); 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci /* Copy the fields from the HBA's FCF record */ 185162306a36Sopenharmony_ci lpfc_copy_fcf_record(fcf_rec, new_fcf_record); 185262306a36Sopenharmony_ci /* Update other fields of driver FCF record */ 185362306a36Sopenharmony_ci fcf_rec->addr_mode = addr_mode; 185462306a36Sopenharmony_ci fcf_rec->vlan_id = vlan_id; 185562306a36Sopenharmony_ci fcf_rec->flag |= (flag | RECORD_VALID); 185662306a36Sopenharmony_ci __lpfc_update_fcf_record_pri(phba, 185762306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_index, new_fcf_record), 185862306a36Sopenharmony_ci new_fcf_record); 185962306a36Sopenharmony_ci} 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci/** 186262306a36Sopenharmony_ci * lpfc_register_fcf - Register the FCF with hba. 186362306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 186462306a36Sopenharmony_ci * 186562306a36Sopenharmony_ci * This routine issues a register fcfi mailbox command to register 186662306a36Sopenharmony_ci * the fcf with HBA. 186762306a36Sopenharmony_ci **/ 186862306a36Sopenharmony_cistatic void 186962306a36Sopenharmony_cilpfc_register_fcf(struct lpfc_hba *phba) 187062306a36Sopenharmony_ci{ 187162306a36Sopenharmony_ci LPFC_MBOXQ_t *fcf_mbxq; 187262306a36Sopenharmony_ci int rc; 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 187562306a36Sopenharmony_ci /* If the FCF is not available do nothing. */ 187662306a36Sopenharmony_ci if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) { 187762306a36Sopenharmony_ci phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG); 187862306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 187962306a36Sopenharmony_ci return; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci /* The FCF is already registered, start discovery */ 188362306a36Sopenharmony_ci if (phba->fcf.fcf_flag & FCF_REGISTERED) { 188462306a36Sopenharmony_ci phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE); 188562306a36Sopenharmony_ci phba->hba_flag &= ~FCF_TS_INPROG; 188662306a36Sopenharmony_ci if (phba->pport->port_state != LPFC_FLOGI && 188762306a36Sopenharmony_ci phba->pport->fc_flag & FC_FABRIC) { 188862306a36Sopenharmony_ci phba->hba_flag |= FCF_RR_INPROG; 188962306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 189062306a36Sopenharmony_ci lpfc_initial_flogi(phba->pport); 189162306a36Sopenharmony_ci return; 189262306a36Sopenharmony_ci } 189362306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 189462306a36Sopenharmony_ci return; 189562306a36Sopenharmony_ci } 189662306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci fcf_mbxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 189962306a36Sopenharmony_ci if (!fcf_mbxq) { 190062306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 190162306a36Sopenharmony_ci phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG); 190262306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 190362306a36Sopenharmony_ci return; 190462306a36Sopenharmony_ci } 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci lpfc_reg_fcfi(phba, fcf_mbxq); 190762306a36Sopenharmony_ci fcf_mbxq->vport = phba->pport; 190862306a36Sopenharmony_ci fcf_mbxq->mbox_cmpl = lpfc_mbx_cmpl_reg_fcfi; 190962306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox(phba, fcf_mbxq, MBX_NOWAIT); 191062306a36Sopenharmony_ci if (rc == MBX_NOT_FINISHED) { 191162306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 191262306a36Sopenharmony_ci phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG); 191362306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 191462306a36Sopenharmony_ci mempool_free(fcf_mbxq, phba->mbox_mem_pool); 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci return; 191862306a36Sopenharmony_ci} 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci/** 192162306a36Sopenharmony_ci * lpfc_match_fcf_conn_list - Check if the FCF record can be used for discovery. 192262306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 192362306a36Sopenharmony_ci * @new_fcf_record: pointer to fcf record. 192462306a36Sopenharmony_ci * @boot_flag: Indicates if this record used by boot bios. 192562306a36Sopenharmony_ci * @addr_mode: The address mode to be used by this FCF 192662306a36Sopenharmony_ci * @vlan_id: The vlan id to be used as vlan tagging by this FCF. 192762306a36Sopenharmony_ci * 192862306a36Sopenharmony_ci * This routine compare the fcf record with connect list obtained from the 192962306a36Sopenharmony_ci * config region to decide if this FCF can be used for SAN discovery. It returns 193062306a36Sopenharmony_ci * 1 if this record can be used for SAN discovery else return zero. If this FCF 193162306a36Sopenharmony_ci * record can be used for SAN discovery, the boot_flag will indicate if this FCF 193262306a36Sopenharmony_ci * is used by boot bios and addr_mode will indicate the addressing mode to be 193362306a36Sopenharmony_ci * used for this FCF when the function returns. 193462306a36Sopenharmony_ci * If the FCF record need to be used with a particular vlan id, the vlan is 193562306a36Sopenharmony_ci * set in the vlan_id on return of the function. If not VLAN tagging need to 193662306a36Sopenharmony_ci * be used with the FCF vlan_id will be set to LPFC_FCOE_NULL_VID; 193762306a36Sopenharmony_ci **/ 193862306a36Sopenharmony_cistatic int 193962306a36Sopenharmony_cilpfc_match_fcf_conn_list(struct lpfc_hba *phba, 194062306a36Sopenharmony_ci struct fcf_record *new_fcf_record, 194162306a36Sopenharmony_ci uint32_t *boot_flag, uint32_t *addr_mode, 194262306a36Sopenharmony_ci uint16_t *vlan_id) 194362306a36Sopenharmony_ci{ 194462306a36Sopenharmony_ci struct lpfc_fcf_conn_entry *conn_entry; 194562306a36Sopenharmony_ci int i, j, fcf_vlan_id = 0; 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci /* Find the lowest VLAN id in the FCF record */ 194862306a36Sopenharmony_ci for (i = 0; i < 512; i++) { 194962306a36Sopenharmony_ci if (new_fcf_record->vlan_bitmap[i]) { 195062306a36Sopenharmony_ci fcf_vlan_id = i * 8; 195162306a36Sopenharmony_ci j = 0; 195262306a36Sopenharmony_ci while (!((new_fcf_record->vlan_bitmap[i] >> j) & 1)) { 195362306a36Sopenharmony_ci j++; 195462306a36Sopenharmony_ci fcf_vlan_id++; 195562306a36Sopenharmony_ci } 195662306a36Sopenharmony_ci break; 195762306a36Sopenharmony_ci } 195862306a36Sopenharmony_ci } 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci /* FCF not valid/available or solicitation in progress */ 196162306a36Sopenharmony_ci if (!bf_get(lpfc_fcf_record_fcf_avail, new_fcf_record) || 196262306a36Sopenharmony_ci !bf_get(lpfc_fcf_record_fcf_valid, new_fcf_record) || 196362306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_sol, new_fcf_record)) 196462306a36Sopenharmony_ci return 0; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci if (!(phba->hba_flag & HBA_FIP_SUPPORT)) { 196762306a36Sopenharmony_ci *boot_flag = 0; 196862306a36Sopenharmony_ci *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, 196962306a36Sopenharmony_ci new_fcf_record); 197062306a36Sopenharmony_ci if (phba->valid_vlan) 197162306a36Sopenharmony_ci *vlan_id = phba->vlan_id; 197262306a36Sopenharmony_ci else 197362306a36Sopenharmony_ci *vlan_id = LPFC_FCOE_NULL_VID; 197462306a36Sopenharmony_ci return 1; 197562306a36Sopenharmony_ci } 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci /* 197862306a36Sopenharmony_ci * If there are no FCF connection table entry, driver connect to all 197962306a36Sopenharmony_ci * FCFs. 198062306a36Sopenharmony_ci */ 198162306a36Sopenharmony_ci if (list_empty(&phba->fcf_conn_rec_list)) { 198262306a36Sopenharmony_ci *boot_flag = 0; 198362306a36Sopenharmony_ci *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, 198462306a36Sopenharmony_ci new_fcf_record); 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci /* 198762306a36Sopenharmony_ci * When there are no FCF connect entries, use driver's default 198862306a36Sopenharmony_ci * addressing mode - FPMA. 198962306a36Sopenharmony_ci */ 199062306a36Sopenharmony_ci if (*addr_mode & LPFC_FCF_FPMA) 199162306a36Sopenharmony_ci *addr_mode = LPFC_FCF_FPMA; 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci /* If FCF record report a vlan id use that vlan id */ 199462306a36Sopenharmony_ci if (fcf_vlan_id) 199562306a36Sopenharmony_ci *vlan_id = fcf_vlan_id; 199662306a36Sopenharmony_ci else 199762306a36Sopenharmony_ci *vlan_id = LPFC_FCOE_NULL_VID; 199862306a36Sopenharmony_ci return 1; 199962306a36Sopenharmony_ci } 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci list_for_each_entry(conn_entry, 200262306a36Sopenharmony_ci &phba->fcf_conn_rec_list, list) { 200362306a36Sopenharmony_ci if (!(conn_entry->conn_rec.flags & FCFCNCT_VALID)) 200462306a36Sopenharmony_ci continue; 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci if ((conn_entry->conn_rec.flags & FCFCNCT_FBNM_VALID) && 200762306a36Sopenharmony_ci !lpfc_fab_name_match(conn_entry->conn_rec.fabric_name, 200862306a36Sopenharmony_ci new_fcf_record)) 200962306a36Sopenharmony_ci continue; 201062306a36Sopenharmony_ci if ((conn_entry->conn_rec.flags & FCFCNCT_SWNM_VALID) && 201162306a36Sopenharmony_ci !lpfc_sw_name_match(conn_entry->conn_rec.switch_name, 201262306a36Sopenharmony_ci new_fcf_record)) 201362306a36Sopenharmony_ci continue; 201462306a36Sopenharmony_ci if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) { 201562306a36Sopenharmony_ci /* 201662306a36Sopenharmony_ci * If the vlan bit map does not have the bit set for the 201762306a36Sopenharmony_ci * vlan id to be used, then it is not a match. 201862306a36Sopenharmony_ci */ 201962306a36Sopenharmony_ci if (!(new_fcf_record->vlan_bitmap 202062306a36Sopenharmony_ci [conn_entry->conn_rec.vlan_tag / 8] & 202162306a36Sopenharmony_ci (1 << (conn_entry->conn_rec.vlan_tag % 8)))) 202262306a36Sopenharmony_ci continue; 202362306a36Sopenharmony_ci } 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci /* 202662306a36Sopenharmony_ci * If connection record does not support any addressing mode, 202762306a36Sopenharmony_ci * skip the FCF record. 202862306a36Sopenharmony_ci */ 202962306a36Sopenharmony_ci if (!(bf_get(lpfc_fcf_record_mac_addr_prov, new_fcf_record) 203062306a36Sopenharmony_ci & (LPFC_FCF_FPMA | LPFC_FCF_SPMA))) 203162306a36Sopenharmony_ci continue; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci /* 203462306a36Sopenharmony_ci * Check if the connection record specifies a required 203562306a36Sopenharmony_ci * addressing mode. 203662306a36Sopenharmony_ci */ 203762306a36Sopenharmony_ci if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && 203862306a36Sopenharmony_ci !(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED)) { 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci /* 204162306a36Sopenharmony_ci * If SPMA required but FCF not support this continue. 204262306a36Sopenharmony_ci */ 204362306a36Sopenharmony_ci if ((conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && 204462306a36Sopenharmony_ci !(bf_get(lpfc_fcf_record_mac_addr_prov, 204562306a36Sopenharmony_ci new_fcf_record) & LPFC_FCF_SPMA)) 204662306a36Sopenharmony_ci continue; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci /* 204962306a36Sopenharmony_ci * If FPMA required but FCF not support this continue. 205062306a36Sopenharmony_ci */ 205162306a36Sopenharmony_ci if (!(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && 205262306a36Sopenharmony_ci !(bf_get(lpfc_fcf_record_mac_addr_prov, 205362306a36Sopenharmony_ci new_fcf_record) & LPFC_FCF_FPMA)) 205462306a36Sopenharmony_ci continue; 205562306a36Sopenharmony_ci } 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci /* 205862306a36Sopenharmony_ci * This fcf record matches filtering criteria. 205962306a36Sopenharmony_ci */ 206062306a36Sopenharmony_ci if (conn_entry->conn_rec.flags & FCFCNCT_BOOT) 206162306a36Sopenharmony_ci *boot_flag = 1; 206262306a36Sopenharmony_ci else 206362306a36Sopenharmony_ci *boot_flag = 0; 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci /* 206662306a36Sopenharmony_ci * If user did not specify any addressing mode, or if the 206762306a36Sopenharmony_ci * preferred addressing mode specified by user is not supported 206862306a36Sopenharmony_ci * by FCF, allow fabric to pick the addressing mode. 206962306a36Sopenharmony_ci */ 207062306a36Sopenharmony_ci *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, 207162306a36Sopenharmony_ci new_fcf_record); 207262306a36Sopenharmony_ci /* 207362306a36Sopenharmony_ci * If the user specified a required address mode, assign that 207462306a36Sopenharmony_ci * address mode 207562306a36Sopenharmony_ci */ 207662306a36Sopenharmony_ci if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && 207762306a36Sopenharmony_ci (!(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED))) 207862306a36Sopenharmony_ci *addr_mode = (conn_entry->conn_rec.flags & 207962306a36Sopenharmony_ci FCFCNCT_AM_SPMA) ? 208062306a36Sopenharmony_ci LPFC_FCF_SPMA : LPFC_FCF_FPMA; 208162306a36Sopenharmony_ci /* 208262306a36Sopenharmony_ci * If the user specified a preferred address mode, use the 208362306a36Sopenharmony_ci * addr mode only if FCF support the addr_mode. 208462306a36Sopenharmony_ci */ 208562306a36Sopenharmony_ci else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && 208662306a36Sopenharmony_ci (conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED) && 208762306a36Sopenharmony_ci (conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && 208862306a36Sopenharmony_ci (*addr_mode & LPFC_FCF_SPMA)) 208962306a36Sopenharmony_ci *addr_mode = LPFC_FCF_SPMA; 209062306a36Sopenharmony_ci else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && 209162306a36Sopenharmony_ci (conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED) && 209262306a36Sopenharmony_ci !(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && 209362306a36Sopenharmony_ci (*addr_mode & LPFC_FCF_FPMA)) 209462306a36Sopenharmony_ci *addr_mode = LPFC_FCF_FPMA; 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci /* If matching connect list has a vlan id, use it */ 209762306a36Sopenharmony_ci if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) 209862306a36Sopenharmony_ci *vlan_id = conn_entry->conn_rec.vlan_tag; 209962306a36Sopenharmony_ci /* 210062306a36Sopenharmony_ci * If no vlan id is specified in connect list, use the vlan id 210162306a36Sopenharmony_ci * in the FCF record 210262306a36Sopenharmony_ci */ 210362306a36Sopenharmony_ci else if (fcf_vlan_id) 210462306a36Sopenharmony_ci *vlan_id = fcf_vlan_id; 210562306a36Sopenharmony_ci else 210662306a36Sopenharmony_ci *vlan_id = LPFC_FCOE_NULL_VID; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci return 1; 210962306a36Sopenharmony_ci } 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci return 0; 211262306a36Sopenharmony_ci} 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci/** 211562306a36Sopenharmony_ci * lpfc_check_pending_fcoe_event - Check if there is pending fcoe event. 211662306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 211762306a36Sopenharmony_ci * @unreg_fcf: Unregister FCF if FCF table need to be re-scaned. 211862306a36Sopenharmony_ci * 211962306a36Sopenharmony_ci * This function check if there is any fcoe event pending while driver 212062306a36Sopenharmony_ci * scan FCF entries. If there is any pending event, it will restart the 212162306a36Sopenharmony_ci * FCF saning and return 1 else return 0. 212262306a36Sopenharmony_ci */ 212362306a36Sopenharmony_ciint 212462306a36Sopenharmony_cilpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf) 212562306a36Sopenharmony_ci{ 212662306a36Sopenharmony_ci /* 212762306a36Sopenharmony_ci * If the Link is up and no FCoE events while in the 212862306a36Sopenharmony_ci * FCF discovery, no need to restart FCF discovery. 212962306a36Sopenharmony_ci */ 213062306a36Sopenharmony_ci if ((phba->link_state >= LPFC_LINK_UP) && 213162306a36Sopenharmony_ci (phba->fcoe_eventtag == phba->fcoe_eventtag_at_fcf_scan)) 213262306a36Sopenharmony_ci return 0; 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 213562306a36Sopenharmony_ci "2768 Pending link or FCF event during current " 213662306a36Sopenharmony_ci "handling of the previous event: link_state:x%x, " 213762306a36Sopenharmony_ci "evt_tag_at_scan:x%x, evt_tag_current:x%x\n", 213862306a36Sopenharmony_ci phba->link_state, phba->fcoe_eventtag_at_fcf_scan, 213962306a36Sopenharmony_ci phba->fcoe_eventtag); 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 214262306a36Sopenharmony_ci phba->fcf.fcf_flag &= ~FCF_AVAILABLE; 214362306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci if (phba->link_state >= LPFC_LINK_UP) { 214662306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, 214762306a36Sopenharmony_ci "2780 Restart FCF table scan due to " 214862306a36Sopenharmony_ci "pending FCF event:evt_tag_at_scan:x%x, " 214962306a36Sopenharmony_ci "evt_tag_current:x%x\n", 215062306a36Sopenharmony_ci phba->fcoe_eventtag_at_fcf_scan, 215162306a36Sopenharmony_ci phba->fcoe_eventtag); 215262306a36Sopenharmony_ci lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); 215362306a36Sopenharmony_ci } else { 215462306a36Sopenharmony_ci /* 215562306a36Sopenharmony_ci * Do not continue FCF discovery and clear FCF_TS_INPROG 215662306a36Sopenharmony_ci * flag 215762306a36Sopenharmony_ci */ 215862306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, 215962306a36Sopenharmony_ci "2833 Stop FCF discovery process due to link " 216062306a36Sopenharmony_ci "state change (x%x)\n", phba->link_state); 216162306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 216262306a36Sopenharmony_ci phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG); 216362306a36Sopenharmony_ci phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY); 216462306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 216562306a36Sopenharmony_ci } 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci /* Unregister the currently registered FCF if required */ 216862306a36Sopenharmony_ci if (unreg_fcf) { 216962306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 217062306a36Sopenharmony_ci phba->fcf.fcf_flag &= ~FCF_REGISTERED; 217162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 217262306a36Sopenharmony_ci lpfc_sli4_unregister_fcf(phba); 217362306a36Sopenharmony_ci } 217462306a36Sopenharmony_ci return 1; 217562306a36Sopenharmony_ci} 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci/** 217862306a36Sopenharmony_ci * lpfc_sli4_new_fcf_random_select - Randomly select an eligible new fcf record 217962306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 218062306a36Sopenharmony_ci * @fcf_cnt: number of eligible fcf record seen so far. 218162306a36Sopenharmony_ci * 218262306a36Sopenharmony_ci * This function makes an running random selection decision on FCF record to 218362306a36Sopenharmony_ci * use through a sequence of @fcf_cnt eligible FCF records with equal 218462306a36Sopenharmony_ci * probability. To perform integer manunipulation of random numbers with 218562306a36Sopenharmony_ci * size unit32_t, a 16-bit random number returned from get_random_u16() is 218662306a36Sopenharmony_ci * taken as the random random number generated. 218762306a36Sopenharmony_ci * 218862306a36Sopenharmony_ci * Returns true when outcome is for the newly read FCF record should be 218962306a36Sopenharmony_ci * chosen; otherwise, return false when outcome is for keeping the previously 219062306a36Sopenharmony_ci * chosen FCF record. 219162306a36Sopenharmony_ci **/ 219262306a36Sopenharmony_cistatic bool 219362306a36Sopenharmony_cilpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt) 219462306a36Sopenharmony_ci{ 219562306a36Sopenharmony_ci uint32_t rand_num; 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci /* Get 16-bit uniform random number */ 219862306a36Sopenharmony_ci rand_num = get_random_u16(); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci /* Decision with probability 1/fcf_cnt */ 220162306a36Sopenharmony_ci if ((fcf_cnt * rand_num) < 0xFFFF) 220262306a36Sopenharmony_ci return true; 220362306a36Sopenharmony_ci else 220462306a36Sopenharmony_ci return false; 220562306a36Sopenharmony_ci} 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci/** 220862306a36Sopenharmony_ci * lpfc_sli4_fcf_rec_mbox_parse - Parse read_fcf mbox command. 220962306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 221062306a36Sopenharmony_ci * @mboxq: pointer to mailbox object. 221162306a36Sopenharmony_ci * @next_fcf_index: pointer to holder of next fcf index. 221262306a36Sopenharmony_ci * 221362306a36Sopenharmony_ci * This routine parses the non-embedded fcf mailbox command by performing the 221462306a36Sopenharmony_ci * necessarily error checking, non-embedded read FCF record mailbox command 221562306a36Sopenharmony_ci * SGE parsing, and endianness swapping. 221662306a36Sopenharmony_ci * 221762306a36Sopenharmony_ci * Returns the pointer to the new FCF record in the non-embedded mailbox 221862306a36Sopenharmony_ci * command DMA memory if successfully, other NULL. 221962306a36Sopenharmony_ci */ 222062306a36Sopenharmony_cistatic struct fcf_record * 222162306a36Sopenharmony_cilpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, 222262306a36Sopenharmony_ci uint16_t *next_fcf_index) 222362306a36Sopenharmony_ci{ 222462306a36Sopenharmony_ci void *virt_addr; 222562306a36Sopenharmony_ci struct lpfc_mbx_sge sge; 222662306a36Sopenharmony_ci struct lpfc_mbx_read_fcf_tbl *read_fcf; 222762306a36Sopenharmony_ci uint32_t shdr_status, shdr_add_status, if_type; 222862306a36Sopenharmony_ci union lpfc_sli4_cfg_shdr *shdr; 222962306a36Sopenharmony_ci struct fcf_record *new_fcf_record; 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci /* Get the first SGE entry from the non-embedded DMA memory. This 223262306a36Sopenharmony_ci * routine only uses a single SGE. 223362306a36Sopenharmony_ci */ 223462306a36Sopenharmony_ci lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); 223562306a36Sopenharmony_ci if (unlikely(!mboxq->sge_array)) { 223662306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 223762306a36Sopenharmony_ci "2524 Failed to get the non-embedded SGE " 223862306a36Sopenharmony_ci "virtual address\n"); 223962306a36Sopenharmony_ci return NULL; 224062306a36Sopenharmony_ci } 224162306a36Sopenharmony_ci virt_addr = mboxq->sge_array->addr[0]; 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci shdr = (union lpfc_sli4_cfg_shdr *)virt_addr; 224462306a36Sopenharmony_ci lpfc_sli_pcimem_bcopy(shdr, shdr, 224562306a36Sopenharmony_ci sizeof(union lpfc_sli4_cfg_shdr)); 224662306a36Sopenharmony_ci shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); 224762306a36Sopenharmony_ci if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); 224862306a36Sopenharmony_ci shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); 224962306a36Sopenharmony_ci if (shdr_status || shdr_add_status) { 225062306a36Sopenharmony_ci if (shdr_status == STATUS_FCF_TABLE_EMPTY || 225162306a36Sopenharmony_ci if_type == LPFC_SLI_INTF_IF_TYPE_2) 225262306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, 225362306a36Sopenharmony_ci LOG_TRACE_EVENT, 225462306a36Sopenharmony_ci "2726 READ_FCF_RECORD Indicates empty " 225562306a36Sopenharmony_ci "FCF table.\n"); 225662306a36Sopenharmony_ci else 225762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 225862306a36Sopenharmony_ci "2521 READ_FCF_RECORD mailbox failed " 225962306a36Sopenharmony_ci "with status x%x add_status x%x, " 226062306a36Sopenharmony_ci "mbx\n", shdr_status, shdr_add_status); 226162306a36Sopenharmony_ci return NULL; 226262306a36Sopenharmony_ci } 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci /* Interpreting the returned information of the FCF record */ 226562306a36Sopenharmony_ci read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr; 226662306a36Sopenharmony_ci lpfc_sli_pcimem_bcopy(read_fcf, read_fcf, 226762306a36Sopenharmony_ci sizeof(struct lpfc_mbx_read_fcf_tbl)); 226862306a36Sopenharmony_ci *next_fcf_index = bf_get(lpfc_mbx_read_fcf_tbl_nxt_vindx, read_fcf); 226962306a36Sopenharmony_ci new_fcf_record = (struct fcf_record *)(virt_addr + 227062306a36Sopenharmony_ci sizeof(struct lpfc_mbx_read_fcf_tbl)); 227162306a36Sopenharmony_ci lpfc_sli_pcimem_bcopy(new_fcf_record, new_fcf_record, 227262306a36Sopenharmony_ci offsetof(struct fcf_record, vlan_bitmap)); 227362306a36Sopenharmony_ci new_fcf_record->word137 = le32_to_cpu(new_fcf_record->word137); 227462306a36Sopenharmony_ci new_fcf_record->word138 = le32_to_cpu(new_fcf_record->word138); 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci return new_fcf_record; 227762306a36Sopenharmony_ci} 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci/** 228062306a36Sopenharmony_ci * lpfc_sli4_log_fcf_record_info - Log the information of a fcf record 228162306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 228262306a36Sopenharmony_ci * @fcf_record: pointer to the fcf record. 228362306a36Sopenharmony_ci * @vlan_id: the lowest vlan identifier associated to this fcf record. 228462306a36Sopenharmony_ci * @next_fcf_index: the index to the next fcf record in hba's fcf table. 228562306a36Sopenharmony_ci * 228662306a36Sopenharmony_ci * This routine logs the detailed FCF record if the LOG_FIP loggin is 228762306a36Sopenharmony_ci * enabled. 228862306a36Sopenharmony_ci **/ 228962306a36Sopenharmony_cistatic void 229062306a36Sopenharmony_cilpfc_sli4_log_fcf_record_info(struct lpfc_hba *phba, 229162306a36Sopenharmony_ci struct fcf_record *fcf_record, 229262306a36Sopenharmony_ci uint16_t vlan_id, 229362306a36Sopenharmony_ci uint16_t next_fcf_index) 229462306a36Sopenharmony_ci{ 229562306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 229662306a36Sopenharmony_ci "2764 READ_FCF_RECORD:\n" 229762306a36Sopenharmony_ci "\tFCF_Index : x%x\n" 229862306a36Sopenharmony_ci "\tFCF_Avail : x%x\n" 229962306a36Sopenharmony_ci "\tFCF_Valid : x%x\n" 230062306a36Sopenharmony_ci "\tFCF_SOL : x%x\n" 230162306a36Sopenharmony_ci "\tFIP_Priority : x%x\n" 230262306a36Sopenharmony_ci "\tMAC_Provider : x%x\n" 230362306a36Sopenharmony_ci "\tLowest VLANID : x%x\n" 230462306a36Sopenharmony_ci "\tFCF_MAC Addr : x%x:%x:%x:%x:%x:%x\n" 230562306a36Sopenharmony_ci "\tFabric_Name : x%x:%x:%x:%x:%x:%x:%x:%x\n" 230662306a36Sopenharmony_ci "\tSwitch_Name : x%x:%x:%x:%x:%x:%x:%x:%x\n" 230762306a36Sopenharmony_ci "\tNext_FCF_Index: x%x\n", 230862306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_index, fcf_record), 230962306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_avail, fcf_record), 231062306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_valid, fcf_record), 231162306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_sol, fcf_record), 231262306a36Sopenharmony_ci fcf_record->fip_priority, 231362306a36Sopenharmony_ci bf_get(lpfc_fcf_record_mac_addr_prov, fcf_record), 231462306a36Sopenharmony_ci vlan_id, 231562306a36Sopenharmony_ci bf_get(lpfc_fcf_record_mac_0, fcf_record), 231662306a36Sopenharmony_ci bf_get(lpfc_fcf_record_mac_1, fcf_record), 231762306a36Sopenharmony_ci bf_get(lpfc_fcf_record_mac_2, fcf_record), 231862306a36Sopenharmony_ci bf_get(lpfc_fcf_record_mac_3, fcf_record), 231962306a36Sopenharmony_ci bf_get(lpfc_fcf_record_mac_4, fcf_record), 232062306a36Sopenharmony_ci bf_get(lpfc_fcf_record_mac_5, fcf_record), 232162306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_0, fcf_record), 232262306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_1, fcf_record), 232362306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_2, fcf_record), 232462306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_3, fcf_record), 232562306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_4, fcf_record), 232662306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_5, fcf_record), 232762306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_6, fcf_record), 232862306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fab_name_7, fcf_record), 232962306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_0, fcf_record), 233062306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_1, fcf_record), 233162306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_2, fcf_record), 233262306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_3, fcf_record), 233362306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_4, fcf_record), 233462306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_5, fcf_record), 233562306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_6, fcf_record), 233662306a36Sopenharmony_ci bf_get(lpfc_fcf_record_switch_name_7, fcf_record), 233762306a36Sopenharmony_ci next_fcf_index); 233862306a36Sopenharmony_ci} 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci/** 234162306a36Sopenharmony_ci * lpfc_sli4_fcf_record_match - testing new FCF record for matching existing FCF 234262306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 234362306a36Sopenharmony_ci * @fcf_rec: pointer to an existing FCF record. 234462306a36Sopenharmony_ci * @new_fcf_record: pointer to a new FCF record. 234562306a36Sopenharmony_ci * @new_vlan_id: vlan id from the new FCF record. 234662306a36Sopenharmony_ci * 234762306a36Sopenharmony_ci * This function performs matching test of a new FCF record against an existing 234862306a36Sopenharmony_ci * FCF record. If the new_vlan_id passed in is LPFC_FCOE_IGNORE_VID, vlan id 234962306a36Sopenharmony_ci * will not be used as part of the FCF record matching criteria. 235062306a36Sopenharmony_ci * 235162306a36Sopenharmony_ci * Returns true if all the fields matching, otherwise returns false. 235262306a36Sopenharmony_ci */ 235362306a36Sopenharmony_cistatic bool 235462306a36Sopenharmony_cilpfc_sli4_fcf_record_match(struct lpfc_hba *phba, 235562306a36Sopenharmony_ci struct lpfc_fcf_rec *fcf_rec, 235662306a36Sopenharmony_ci struct fcf_record *new_fcf_record, 235762306a36Sopenharmony_ci uint16_t new_vlan_id) 235862306a36Sopenharmony_ci{ 235962306a36Sopenharmony_ci if (new_vlan_id != LPFC_FCOE_IGNORE_VID) 236062306a36Sopenharmony_ci if (!lpfc_vlan_id_match(fcf_rec->vlan_id, new_vlan_id)) 236162306a36Sopenharmony_ci return false; 236262306a36Sopenharmony_ci if (!lpfc_mac_addr_match(fcf_rec->mac_addr, new_fcf_record)) 236362306a36Sopenharmony_ci return false; 236462306a36Sopenharmony_ci if (!lpfc_sw_name_match(fcf_rec->switch_name, new_fcf_record)) 236562306a36Sopenharmony_ci return false; 236662306a36Sopenharmony_ci if (!lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record)) 236762306a36Sopenharmony_ci return false; 236862306a36Sopenharmony_ci if (fcf_rec->priority != new_fcf_record->fip_priority) 236962306a36Sopenharmony_ci return false; 237062306a36Sopenharmony_ci return true; 237162306a36Sopenharmony_ci} 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci/** 237462306a36Sopenharmony_ci * lpfc_sli4_fcf_rr_next_proc - processing next roundrobin fcf 237562306a36Sopenharmony_ci * @vport: Pointer to vport object. 237662306a36Sopenharmony_ci * @fcf_index: index to next fcf. 237762306a36Sopenharmony_ci * 237862306a36Sopenharmony_ci * This function processing the roundrobin fcf failover to next fcf index. 237962306a36Sopenharmony_ci * When this function is invoked, there will be a current fcf registered 238062306a36Sopenharmony_ci * for flogi. 238162306a36Sopenharmony_ci * Return: 0 for continue retrying flogi on currently registered fcf; 238262306a36Sopenharmony_ci * 1 for stop flogi on currently registered fcf; 238362306a36Sopenharmony_ci */ 238462306a36Sopenharmony_ciint lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *vport, uint16_t fcf_index) 238562306a36Sopenharmony_ci{ 238662306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 238762306a36Sopenharmony_ci int rc; 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci if (fcf_index == LPFC_FCOE_FCF_NEXT_NONE) { 239062306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 239162306a36Sopenharmony_ci if (phba->hba_flag & HBA_DEVLOSS_TMO) { 239262306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 239362306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 239462306a36Sopenharmony_ci "2872 Devloss tmo with no eligible " 239562306a36Sopenharmony_ci "FCF, unregister in-use FCF (x%x) " 239662306a36Sopenharmony_ci "and rescan FCF table\n", 239762306a36Sopenharmony_ci phba->fcf.current_rec.fcf_indx); 239862306a36Sopenharmony_ci lpfc_unregister_fcf_rescan(phba); 239962306a36Sopenharmony_ci goto stop_flogi_current_fcf; 240062306a36Sopenharmony_ci } 240162306a36Sopenharmony_ci /* Mark the end to FLOGI roundrobin failover */ 240262306a36Sopenharmony_ci phba->hba_flag &= ~FCF_RR_INPROG; 240362306a36Sopenharmony_ci /* Allow action to new fcf asynchronous event */ 240462306a36Sopenharmony_ci phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE); 240562306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 240662306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 240762306a36Sopenharmony_ci "2865 No FCF available, stop roundrobin FCF " 240862306a36Sopenharmony_ci "failover and change port state:x%x/x%x\n", 240962306a36Sopenharmony_ci phba->pport->port_state, LPFC_VPORT_UNKNOWN); 241062306a36Sopenharmony_ci phba->pport->port_state = LPFC_VPORT_UNKNOWN; 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci if (!phba->fcf.fcf_redisc_attempted) { 241362306a36Sopenharmony_ci lpfc_unregister_fcf(phba); 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci rc = lpfc_sli4_redisc_fcf_table(phba); 241662306a36Sopenharmony_ci if (!rc) { 241762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 241862306a36Sopenharmony_ci "3195 Rediscover FCF table\n"); 241962306a36Sopenharmony_ci phba->fcf.fcf_redisc_attempted = 1; 242062306a36Sopenharmony_ci lpfc_sli4_clear_fcf_rr_bmask(phba); 242162306a36Sopenharmony_ci } else { 242262306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, 242362306a36Sopenharmony_ci "3196 Rediscover FCF table " 242462306a36Sopenharmony_ci "failed. Status:x%x\n", rc); 242562306a36Sopenharmony_ci } 242662306a36Sopenharmony_ci } else { 242762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, 242862306a36Sopenharmony_ci "3197 Already rediscover FCF table " 242962306a36Sopenharmony_ci "attempted. No more retry\n"); 243062306a36Sopenharmony_ci } 243162306a36Sopenharmony_ci goto stop_flogi_current_fcf; 243262306a36Sopenharmony_ci } else { 243362306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_ELS, 243462306a36Sopenharmony_ci "2794 Try FLOGI roundrobin FCF failover to " 243562306a36Sopenharmony_ci "(x%x)\n", fcf_index); 243662306a36Sopenharmony_ci rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba, fcf_index); 243762306a36Sopenharmony_ci if (rc) 243862306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS, 243962306a36Sopenharmony_ci "2761 FLOGI roundrobin FCF failover " 244062306a36Sopenharmony_ci "failed (rc:x%x) to read FCF (x%x)\n", 244162306a36Sopenharmony_ci rc, phba->fcf.current_rec.fcf_indx); 244262306a36Sopenharmony_ci else 244362306a36Sopenharmony_ci goto stop_flogi_current_fcf; 244462306a36Sopenharmony_ci } 244562306a36Sopenharmony_ci return 0; 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_cistop_flogi_current_fcf: 244862306a36Sopenharmony_ci lpfc_can_disctmo(vport); 244962306a36Sopenharmony_ci return 1; 245062306a36Sopenharmony_ci} 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci/** 245362306a36Sopenharmony_ci * lpfc_sli4_fcf_pri_list_del 245462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 245562306a36Sopenharmony_ci * @fcf_index: the index of the fcf record to delete 245662306a36Sopenharmony_ci * This routine checks the on list flag of the fcf_index to be deleted. 245762306a36Sopenharmony_ci * If it is one the list then it is removed from the list, and the flag 245862306a36Sopenharmony_ci * is cleared. This routine grab the hbalock before removing the fcf 245962306a36Sopenharmony_ci * record from the list. 246062306a36Sopenharmony_ci **/ 246162306a36Sopenharmony_cistatic void lpfc_sli4_fcf_pri_list_del(struct lpfc_hba *phba, 246262306a36Sopenharmony_ci uint16_t fcf_index) 246362306a36Sopenharmony_ci{ 246462306a36Sopenharmony_ci struct lpfc_fcf_pri *new_fcf_pri; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci new_fcf_pri = &phba->fcf.fcf_pri[fcf_index]; 246762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 246862306a36Sopenharmony_ci "3058 deleting idx x%x pri x%x flg x%x\n", 246962306a36Sopenharmony_ci fcf_index, new_fcf_pri->fcf_rec.priority, 247062306a36Sopenharmony_ci new_fcf_pri->fcf_rec.flag); 247162306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 247262306a36Sopenharmony_ci if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST) { 247362306a36Sopenharmony_ci if (phba->fcf.current_rec.priority == 247462306a36Sopenharmony_ci new_fcf_pri->fcf_rec.priority) 247562306a36Sopenharmony_ci phba->fcf.eligible_fcf_cnt--; 247662306a36Sopenharmony_ci list_del_init(&new_fcf_pri->list); 247762306a36Sopenharmony_ci new_fcf_pri->fcf_rec.flag &= ~LPFC_FCF_ON_PRI_LIST; 247862306a36Sopenharmony_ci } 247962306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 248062306a36Sopenharmony_ci} 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci/** 248362306a36Sopenharmony_ci * lpfc_sli4_set_fcf_flogi_fail 248462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 248562306a36Sopenharmony_ci * @fcf_index: the index of the fcf record to update 248662306a36Sopenharmony_ci * This routine acquires the hbalock and then set the LPFC_FCF_FLOGI_FAILED 248762306a36Sopenharmony_ci * flag so the round robin selection for the particular priority level 248862306a36Sopenharmony_ci * will try a different fcf record that does not have this bit set. 248962306a36Sopenharmony_ci * If the fcf record is re-read for any reason this flag is cleared brfore 249062306a36Sopenharmony_ci * adding it to the priority list. 249162306a36Sopenharmony_ci **/ 249262306a36Sopenharmony_civoid 249362306a36Sopenharmony_cilpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *phba, uint16_t fcf_index) 249462306a36Sopenharmony_ci{ 249562306a36Sopenharmony_ci struct lpfc_fcf_pri *new_fcf_pri; 249662306a36Sopenharmony_ci new_fcf_pri = &phba->fcf.fcf_pri[fcf_index]; 249762306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 249862306a36Sopenharmony_ci new_fcf_pri->fcf_rec.flag |= LPFC_FCF_FLOGI_FAILED; 249962306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 250062306a36Sopenharmony_ci} 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci/** 250362306a36Sopenharmony_ci * lpfc_sli4_fcf_pri_list_add 250462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 250562306a36Sopenharmony_ci * @fcf_index: the index of the fcf record to add 250662306a36Sopenharmony_ci * @new_fcf_record: pointer to a new FCF record. 250762306a36Sopenharmony_ci * This routine checks the priority of the fcf_index to be added. 250862306a36Sopenharmony_ci * If it is a lower priority than the current head of the fcf_pri list 250962306a36Sopenharmony_ci * then it is added to the list in the right order. 251062306a36Sopenharmony_ci * If it is the same priority as the current head of the list then it 251162306a36Sopenharmony_ci * is added to the head of the list and its bit in the rr_bmask is set. 251262306a36Sopenharmony_ci * If the fcf_index to be added is of a higher priority than the current 251362306a36Sopenharmony_ci * head of the list then the rr_bmask is cleared, its bit is set in the 251462306a36Sopenharmony_ci * rr_bmask and it is added to the head of the list. 251562306a36Sopenharmony_ci * returns: 251662306a36Sopenharmony_ci * 0=success 1=failure 251762306a36Sopenharmony_ci **/ 251862306a36Sopenharmony_cistatic int lpfc_sli4_fcf_pri_list_add(struct lpfc_hba *phba, 251962306a36Sopenharmony_ci uint16_t fcf_index, 252062306a36Sopenharmony_ci struct fcf_record *new_fcf_record) 252162306a36Sopenharmony_ci{ 252262306a36Sopenharmony_ci uint16_t current_fcf_pri; 252362306a36Sopenharmony_ci uint16_t last_index; 252462306a36Sopenharmony_ci struct lpfc_fcf_pri *fcf_pri; 252562306a36Sopenharmony_ci struct lpfc_fcf_pri *next_fcf_pri; 252662306a36Sopenharmony_ci struct lpfc_fcf_pri *new_fcf_pri; 252762306a36Sopenharmony_ci int ret; 252862306a36Sopenharmony_ci 252962306a36Sopenharmony_ci new_fcf_pri = &phba->fcf.fcf_pri[fcf_index]; 253062306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 253162306a36Sopenharmony_ci "3059 adding idx x%x pri x%x flg x%x\n", 253262306a36Sopenharmony_ci fcf_index, new_fcf_record->fip_priority, 253362306a36Sopenharmony_ci new_fcf_pri->fcf_rec.flag); 253462306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 253562306a36Sopenharmony_ci if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST) 253662306a36Sopenharmony_ci list_del_init(&new_fcf_pri->list); 253762306a36Sopenharmony_ci new_fcf_pri->fcf_rec.fcf_index = fcf_index; 253862306a36Sopenharmony_ci new_fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority; 253962306a36Sopenharmony_ci if (list_empty(&phba->fcf.fcf_pri_list)) { 254062306a36Sopenharmony_ci list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list); 254162306a36Sopenharmony_ci ret = lpfc_sli4_fcf_rr_index_set(phba, 254262306a36Sopenharmony_ci new_fcf_pri->fcf_rec.fcf_index); 254362306a36Sopenharmony_ci goto out; 254462306a36Sopenharmony_ci } 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci last_index = find_first_bit(phba->fcf.fcf_rr_bmask, 254762306a36Sopenharmony_ci LPFC_SLI4_FCF_TBL_INDX_MAX); 254862306a36Sopenharmony_ci if (last_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { 254962306a36Sopenharmony_ci ret = 0; /* Empty rr list */ 255062306a36Sopenharmony_ci goto out; 255162306a36Sopenharmony_ci } 255262306a36Sopenharmony_ci current_fcf_pri = phba->fcf.fcf_pri[last_index].fcf_rec.priority; 255362306a36Sopenharmony_ci if (new_fcf_pri->fcf_rec.priority <= current_fcf_pri) { 255462306a36Sopenharmony_ci list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list); 255562306a36Sopenharmony_ci if (new_fcf_pri->fcf_rec.priority < current_fcf_pri) { 255662306a36Sopenharmony_ci memset(phba->fcf.fcf_rr_bmask, 0, 255762306a36Sopenharmony_ci sizeof(*phba->fcf.fcf_rr_bmask)); 255862306a36Sopenharmony_ci /* fcfs_at_this_priority_level = 1; */ 255962306a36Sopenharmony_ci phba->fcf.eligible_fcf_cnt = 1; 256062306a36Sopenharmony_ci } else 256162306a36Sopenharmony_ci /* fcfs_at_this_priority_level++; */ 256262306a36Sopenharmony_ci phba->fcf.eligible_fcf_cnt++; 256362306a36Sopenharmony_ci ret = lpfc_sli4_fcf_rr_index_set(phba, 256462306a36Sopenharmony_ci new_fcf_pri->fcf_rec.fcf_index); 256562306a36Sopenharmony_ci goto out; 256662306a36Sopenharmony_ci } 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci list_for_each_entry_safe(fcf_pri, next_fcf_pri, 256962306a36Sopenharmony_ci &phba->fcf.fcf_pri_list, list) { 257062306a36Sopenharmony_ci if (new_fcf_pri->fcf_rec.priority <= 257162306a36Sopenharmony_ci fcf_pri->fcf_rec.priority) { 257262306a36Sopenharmony_ci if (fcf_pri->list.prev == &phba->fcf.fcf_pri_list) 257362306a36Sopenharmony_ci list_add(&new_fcf_pri->list, 257462306a36Sopenharmony_ci &phba->fcf.fcf_pri_list); 257562306a36Sopenharmony_ci else 257662306a36Sopenharmony_ci list_add(&new_fcf_pri->list, 257762306a36Sopenharmony_ci &((struct lpfc_fcf_pri *) 257862306a36Sopenharmony_ci fcf_pri->list.prev)->list); 257962306a36Sopenharmony_ci ret = 0; 258062306a36Sopenharmony_ci goto out; 258162306a36Sopenharmony_ci } else if (fcf_pri->list.next == &phba->fcf.fcf_pri_list 258262306a36Sopenharmony_ci || new_fcf_pri->fcf_rec.priority < 258362306a36Sopenharmony_ci next_fcf_pri->fcf_rec.priority) { 258462306a36Sopenharmony_ci list_add(&new_fcf_pri->list, &fcf_pri->list); 258562306a36Sopenharmony_ci ret = 0; 258662306a36Sopenharmony_ci goto out; 258762306a36Sopenharmony_ci } 258862306a36Sopenharmony_ci if (new_fcf_pri->fcf_rec.priority > fcf_pri->fcf_rec.priority) 258962306a36Sopenharmony_ci continue; 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci } 259262306a36Sopenharmony_ci ret = 1; 259362306a36Sopenharmony_ciout: 259462306a36Sopenharmony_ci /* we use = instead of |= to clear the FLOGI_FAILED flag. */ 259562306a36Sopenharmony_ci new_fcf_pri->fcf_rec.flag = LPFC_FCF_ON_PRI_LIST; 259662306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 259762306a36Sopenharmony_ci return ret; 259862306a36Sopenharmony_ci} 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci/** 260162306a36Sopenharmony_ci * lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler. 260262306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 260362306a36Sopenharmony_ci * @mboxq: pointer to mailbox object. 260462306a36Sopenharmony_ci * 260562306a36Sopenharmony_ci * This function iterates through all the fcf records available in 260662306a36Sopenharmony_ci * HBA and chooses the optimal FCF record for discovery. After finding 260762306a36Sopenharmony_ci * the FCF for discovery it registers the FCF record and kicks start 260862306a36Sopenharmony_ci * discovery. 260962306a36Sopenharmony_ci * If FCF_IN_USE flag is set in currently used FCF, the routine tries to 261062306a36Sopenharmony_ci * use an FCF record which matches fabric name and mac address of the 261162306a36Sopenharmony_ci * currently used FCF record. 261262306a36Sopenharmony_ci * If the driver supports only one FCF, it will try to use the FCF record 261362306a36Sopenharmony_ci * used by BOOT_BIOS. 261462306a36Sopenharmony_ci */ 261562306a36Sopenharmony_civoid 261662306a36Sopenharmony_cilpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) 261762306a36Sopenharmony_ci{ 261862306a36Sopenharmony_ci struct fcf_record *new_fcf_record; 261962306a36Sopenharmony_ci uint32_t boot_flag, addr_mode; 262062306a36Sopenharmony_ci uint16_t fcf_index, next_fcf_index; 262162306a36Sopenharmony_ci struct lpfc_fcf_rec *fcf_rec = NULL; 262262306a36Sopenharmony_ci uint16_t vlan_id = LPFC_FCOE_NULL_VID; 262362306a36Sopenharmony_ci bool select_new_fcf; 262462306a36Sopenharmony_ci int rc; 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci /* If there is pending FCoE event restart FCF table scan */ 262762306a36Sopenharmony_ci if (lpfc_check_pending_fcoe_event(phba, LPFC_SKIP_UNREG_FCF)) { 262862306a36Sopenharmony_ci lpfc_sli4_mbox_cmd_free(phba, mboxq); 262962306a36Sopenharmony_ci return; 263062306a36Sopenharmony_ci } 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci /* Parse the FCF record from the non-embedded mailbox command */ 263362306a36Sopenharmony_ci new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq, 263462306a36Sopenharmony_ci &next_fcf_index); 263562306a36Sopenharmony_ci if (!new_fcf_record) { 263662306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 263762306a36Sopenharmony_ci "2765 Mailbox command READ_FCF_RECORD " 263862306a36Sopenharmony_ci "failed to retrieve a FCF record.\n"); 263962306a36Sopenharmony_ci /* Let next new FCF event trigger fast failover */ 264062306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 264162306a36Sopenharmony_ci phba->hba_flag &= ~FCF_TS_INPROG; 264262306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 264362306a36Sopenharmony_ci lpfc_sli4_mbox_cmd_free(phba, mboxq); 264462306a36Sopenharmony_ci return; 264562306a36Sopenharmony_ci } 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_ci /* Check the FCF record against the connection list */ 264862306a36Sopenharmony_ci rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag, 264962306a36Sopenharmony_ci &addr_mode, &vlan_id); 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci /* Log the FCF record information if turned on */ 265262306a36Sopenharmony_ci lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id, 265362306a36Sopenharmony_ci next_fcf_index); 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci /* 265662306a36Sopenharmony_ci * If the fcf record does not match with connect list entries 265762306a36Sopenharmony_ci * read the next entry; otherwise, this is an eligible FCF 265862306a36Sopenharmony_ci * record for roundrobin FCF failover. 265962306a36Sopenharmony_ci */ 266062306a36Sopenharmony_ci if (!rc) { 266162306a36Sopenharmony_ci lpfc_sli4_fcf_pri_list_del(phba, 266262306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_index, 266362306a36Sopenharmony_ci new_fcf_record)); 266462306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, 266562306a36Sopenharmony_ci "2781 FCF (x%x) failed connection " 266662306a36Sopenharmony_ci "list check: (x%x/x%x/%x)\n", 266762306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_index, 266862306a36Sopenharmony_ci new_fcf_record), 266962306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_avail, 267062306a36Sopenharmony_ci new_fcf_record), 267162306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_valid, 267262306a36Sopenharmony_ci new_fcf_record), 267362306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_sol, 267462306a36Sopenharmony_ci new_fcf_record)); 267562306a36Sopenharmony_ci if ((phba->fcf.fcf_flag & FCF_IN_USE) && 267662306a36Sopenharmony_ci lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec, 267762306a36Sopenharmony_ci new_fcf_record, LPFC_FCOE_IGNORE_VID)) { 267862306a36Sopenharmony_ci if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) != 267962306a36Sopenharmony_ci phba->fcf.current_rec.fcf_indx) { 268062306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, 268162306a36Sopenharmony_ci LOG_TRACE_EVENT, 268262306a36Sopenharmony_ci "2862 FCF (x%x) matches property " 268362306a36Sopenharmony_ci "of in-use FCF (x%x)\n", 268462306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_index, 268562306a36Sopenharmony_ci new_fcf_record), 268662306a36Sopenharmony_ci phba->fcf.current_rec.fcf_indx); 268762306a36Sopenharmony_ci goto read_next_fcf; 268862306a36Sopenharmony_ci } 268962306a36Sopenharmony_ci /* 269062306a36Sopenharmony_ci * In case the current in-use FCF record becomes 269162306a36Sopenharmony_ci * invalid/unavailable during FCF discovery that 269262306a36Sopenharmony_ci * was not triggered by fast FCF failover process, 269362306a36Sopenharmony_ci * treat it as fast FCF failover. 269462306a36Sopenharmony_ci */ 269562306a36Sopenharmony_ci if (!(phba->fcf.fcf_flag & FCF_REDISC_PEND) && 269662306a36Sopenharmony_ci !(phba->fcf.fcf_flag & FCF_REDISC_FOV)) { 269762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, 269862306a36Sopenharmony_ci "2835 Invalid in-use FCF " 269962306a36Sopenharmony_ci "(x%x), enter FCF failover " 270062306a36Sopenharmony_ci "table scan.\n", 270162306a36Sopenharmony_ci phba->fcf.current_rec.fcf_indx); 270262306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 270362306a36Sopenharmony_ci phba->fcf.fcf_flag |= FCF_REDISC_FOV; 270462306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 270562306a36Sopenharmony_ci lpfc_sli4_mbox_cmd_free(phba, mboxq); 270662306a36Sopenharmony_ci lpfc_sli4_fcf_scan_read_fcf_rec(phba, 270762306a36Sopenharmony_ci LPFC_FCOE_FCF_GET_FIRST); 270862306a36Sopenharmony_ci return; 270962306a36Sopenharmony_ci } 271062306a36Sopenharmony_ci } 271162306a36Sopenharmony_ci goto read_next_fcf; 271262306a36Sopenharmony_ci } else { 271362306a36Sopenharmony_ci fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); 271462306a36Sopenharmony_ci rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index, 271562306a36Sopenharmony_ci new_fcf_record); 271662306a36Sopenharmony_ci if (rc) 271762306a36Sopenharmony_ci goto read_next_fcf; 271862306a36Sopenharmony_ci } 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ci /* 272162306a36Sopenharmony_ci * If this is not the first FCF discovery of the HBA, use last 272262306a36Sopenharmony_ci * FCF record for the discovery. The condition that a rescan 272362306a36Sopenharmony_ci * matches the in-use FCF record: fabric name, switch name, mac 272462306a36Sopenharmony_ci * address, and vlan_id. 272562306a36Sopenharmony_ci */ 272662306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 272762306a36Sopenharmony_ci if (phba->fcf.fcf_flag & FCF_IN_USE) { 272862306a36Sopenharmony_ci if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV && 272962306a36Sopenharmony_ci lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec, 273062306a36Sopenharmony_ci new_fcf_record, vlan_id)) { 273162306a36Sopenharmony_ci if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) == 273262306a36Sopenharmony_ci phba->fcf.current_rec.fcf_indx) { 273362306a36Sopenharmony_ci phba->fcf.fcf_flag |= FCF_AVAILABLE; 273462306a36Sopenharmony_ci if (phba->fcf.fcf_flag & FCF_REDISC_PEND) 273562306a36Sopenharmony_ci /* Stop FCF redisc wait timer */ 273662306a36Sopenharmony_ci __lpfc_sli4_stop_fcf_redisc_wait_timer( 273762306a36Sopenharmony_ci phba); 273862306a36Sopenharmony_ci else if (phba->fcf.fcf_flag & FCF_REDISC_FOV) 273962306a36Sopenharmony_ci /* Fast failover, mark completed */ 274062306a36Sopenharmony_ci phba->fcf.fcf_flag &= ~FCF_REDISC_FOV; 274162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 274262306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 274362306a36Sopenharmony_ci "2836 New FCF matches in-use " 274462306a36Sopenharmony_ci "FCF (x%x), port_state:x%x, " 274562306a36Sopenharmony_ci "fc_flag:x%x\n", 274662306a36Sopenharmony_ci phba->fcf.current_rec.fcf_indx, 274762306a36Sopenharmony_ci phba->pport->port_state, 274862306a36Sopenharmony_ci phba->pport->fc_flag); 274962306a36Sopenharmony_ci goto out; 275062306a36Sopenharmony_ci } else 275162306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 275262306a36Sopenharmony_ci "2863 New FCF (x%x) matches " 275362306a36Sopenharmony_ci "property of in-use FCF (x%x)\n", 275462306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_index, 275562306a36Sopenharmony_ci new_fcf_record), 275662306a36Sopenharmony_ci phba->fcf.current_rec.fcf_indx); 275762306a36Sopenharmony_ci } 275862306a36Sopenharmony_ci /* 275962306a36Sopenharmony_ci * Read next FCF record from HBA searching for the matching 276062306a36Sopenharmony_ci * with in-use record only if not during the fast failover 276162306a36Sopenharmony_ci * period. In case of fast failover period, it shall try to 276262306a36Sopenharmony_ci * determine whether the FCF record just read should be the 276362306a36Sopenharmony_ci * next candidate. 276462306a36Sopenharmony_ci */ 276562306a36Sopenharmony_ci if (!(phba->fcf.fcf_flag & FCF_REDISC_FOV)) { 276662306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 276762306a36Sopenharmony_ci goto read_next_fcf; 276862306a36Sopenharmony_ci } 276962306a36Sopenharmony_ci } 277062306a36Sopenharmony_ci /* 277162306a36Sopenharmony_ci * Update on failover FCF record only if it's in FCF fast-failover 277262306a36Sopenharmony_ci * period; otherwise, update on current FCF record. 277362306a36Sopenharmony_ci */ 277462306a36Sopenharmony_ci if (phba->fcf.fcf_flag & FCF_REDISC_FOV) 277562306a36Sopenharmony_ci fcf_rec = &phba->fcf.failover_rec; 277662306a36Sopenharmony_ci else 277762306a36Sopenharmony_ci fcf_rec = &phba->fcf.current_rec; 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci if (phba->fcf.fcf_flag & FCF_AVAILABLE) { 278062306a36Sopenharmony_ci /* 278162306a36Sopenharmony_ci * If the driver FCF record does not have boot flag 278262306a36Sopenharmony_ci * set and new hba fcf record has boot flag set, use 278362306a36Sopenharmony_ci * the new hba fcf record. 278462306a36Sopenharmony_ci */ 278562306a36Sopenharmony_ci if (boot_flag && !(fcf_rec->flag & BOOT_ENABLE)) { 278662306a36Sopenharmony_ci /* Choose this FCF record */ 278762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 278862306a36Sopenharmony_ci "2837 Update current FCF record " 278962306a36Sopenharmony_ci "(x%x) with new FCF record (x%x)\n", 279062306a36Sopenharmony_ci fcf_rec->fcf_indx, 279162306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_index, 279262306a36Sopenharmony_ci new_fcf_record)); 279362306a36Sopenharmony_ci __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record, 279462306a36Sopenharmony_ci addr_mode, vlan_id, BOOT_ENABLE); 279562306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 279662306a36Sopenharmony_ci goto read_next_fcf; 279762306a36Sopenharmony_ci } 279862306a36Sopenharmony_ci /* 279962306a36Sopenharmony_ci * If the driver FCF record has boot flag set and the 280062306a36Sopenharmony_ci * new hba FCF record does not have boot flag, read 280162306a36Sopenharmony_ci * the next FCF record. 280262306a36Sopenharmony_ci */ 280362306a36Sopenharmony_ci if (!boot_flag && (fcf_rec->flag & BOOT_ENABLE)) { 280462306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 280562306a36Sopenharmony_ci goto read_next_fcf; 280662306a36Sopenharmony_ci } 280762306a36Sopenharmony_ci /* 280862306a36Sopenharmony_ci * If the new hba FCF record has lower priority value 280962306a36Sopenharmony_ci * than the driver FCF record, use the new record. 281062306a36Sopenharmony_ci */ 281162306a36Sopenharmony_ci if (new_fcf_record->fip_priority < fcf_rec->priority) { 281262306a36Sopenharmony_ci /* Choose the new FCF record with lower priority */ 281362306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 281462306a36Sopenharmony_ci "2838 Update current FCF record " 281562306a36Sopenharmony_ci "(x%x) with new FCF record (x%x)\n", 281662306a36Sopenharmony_ci fcf_rec->fcf_indx, 281762306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_index, 281862306a36Sopenharmony_ci new_fcf_record)); 281962306a36Sopenharmony_ci __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record, 282062306a36Sopenharmony_ci addr_mode, vlan_id, 0); 282162306a36Sopenharmony_ci /* Reset running random FCF selection count */ 282262306a36Sopenharmony_ci phba->fcf.eligible_fcf_cnt = 1; 282362306a36Sopenharmony_ci } else if (new_fcf_record->fip_priority == fcf_rec->priority) { 282462306a36Sopenharmony_ci /* Update running random FCF selection count */ 282562306a36Sopenharmony_ci phba->fcf.eligible_fcf_cnt++; 282662306a36Sopenharmony_ci select_new_fcf = lpfc_sli4_new_fcf_random_select(phba, 282762306a36Sopenharmony_ci phba->fcf.eligible_fcf_cnt); 282862306a36Sopenharmony_ci if (select_new_fcf) { 282962306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 283062306a36Sopenharmony_ci "2839 Update current FCF record " 283162306a36Sopenharmony_ci "(x%x) with new FCF record (x%x)\n", 283262306a36Sopenharmony_ci fcf_rec->fcf_indx, 283362306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_index, 283462306a36Sopenharmony_ci new_fcf_record)); 283562306a36Sopenharmony_ci /* Choose the new FCF by random selection */ 283662306a36Sopenharmony_ci __lpfc_update_fcf_record(phba, fcf_rec, 283762306a36Sopenharmony_ci new_fcf_record, 283862306a36Sopenharmony_ci addr_mode, vlan_id, 0); 283962306a36Sopenharmony_ci } 284062306a36Sopenharmony_ci } 284162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 284262306a36Sopenharmony_ci goto read_next_fcf; 284362306a36Sopenharmony_ci } 284462306a36Sopenharmony_ci /* 284562306a36Sopenharmony_ci * This is the first suitable FCF record, choose this record for 284662306a36Sopenharmony_ci * initial best-fit FCF. 284762306a36Sopenharmony_ci */ 284862306a36Sopenharmony_ci if (fcf_rec) { 284962306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 285062306a36Sopenharmony_ci "2840 Update initial FCF candidate " 285162306a36Sopenharmony_ci "with FCF (x%x)\n", 285262306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_index, 285362306a36Sopenharmony_ci new_fcf_record)); 285462306a36Sopenharmony_ci __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record, 285562306a36Sopenharmony_ci addr_mode, vlan_id, (boot_flag ? 285662306a36Sopenharmony_ci BOOT_ENABLE : 0)); 285762306a36Sopenharmony_ci phba->fcf.fcf_flag |= FCF_AVAILABLE; 285862306a36Sopenharmony_ci /* Setup initial running random FCF selection count */ 285962306a36Sopenharmony_ci phba->fcf.eligible_fcf_cnt = 1; 286062306a36Sopenharmony_ci } 286162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 286262306a36Sopenharmony_ci goto read_next_fcf; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ciread_next_fcf: 286562306a36Sopenharmony_ci lpfc_sli4_mbox_cmd_free(phba, mboxq); 286662306a36Sopenharmony_ci if (next_fcf_index == LPFC_FCOE_FCF_NEXT_NONE || next_fcf_index == 0) { 286762306a36Sopenharmony_ci if (phba->fcf.fcf_flag & FCF_REDISC_FOV) { 286862306a36Sopenharmony_ci /* 286962306a36Sopenharmony_ci * Case of FCF fast failover scan 287062306a36Sopenharmony_ci */ 287162306a36Sopenharmony_ci 287262306a36Sopenharmony_ci /* 287362306a36Sopenharmony_ci * It has not found any suitable FCF record, cancel 287462306a36Sopenharmony_ci * FCF scan inprogress, and do nothing 287562306a36Sopenharmony_ci */ 287662306a36Sopenharmony_ci if (!(phba->fcf.failover_rec.flag & RECORD_VALID)) { 287762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, 287862306a36Sopenharmony_ci "2782 No suitable FCF found: " 287962306a36Sopenharmony_ci "(x%x/x%x)\n", 288062306a36Sopenharmony_ci phba->fcoe_eventtag_at_fcf_scan, 288162306a36Sopenharmony_ci bf_get(lpfc_fcf_record_fcf_index, 288262306a36Sopenharmony_ci new_fcf_record)); 288362306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 288462306a36Sopenharmony_ci if (phba->hba_flag & HBA_DEVLOSS_TMO) { 288562306a36Sopenharmony_ci phba->hba_flag &= ~FCF_TS_INPROG; 288662306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 288762306a36Sopenharmony_ci /* Unregister in-use FCF and rescan */ 288862306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, 288962306a36Sopenharmony_ci LOG_FIP, 289062306a36Sopenharmony_ci "2864 On devloss tmo " 289162306a36Sopenharmony_ci "unreg in-use FCF and " 289262306a36Sopenharmony_ci "rescan FCF table\n"); 289362306a36Sopenharmony_ci lpfc_unregister_fcf_rescan(phba); 289462306a36Sopenharmony_ci return; 289562306a36Sopenharmony_ci } 289662306a36Sopenharmony_ci /* 289762306a36Sopenharmony_ci * Let next new FCF event trigger fast failover 289862306a36Sopenharmony_ci */ 289962306a36Sopenharmony_ci phba->hba_flag &= ~FCF_TS_INPROG; 290062306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 290162306a36Sopenharmony_ci return; 290262306a36Sopenharmony_ci } 290362306a36Sopenharmony_ci /* 290462306a36Sopenharmony_ci * It has found a suitable FCF record that is not 290562306a36Sopenharmony_ci * the same as in-use FCF record, unregister the 290662306a36Sopenharmony_ci * in-use FCF record, replace the in-use FCF record 290762306a36Sopenharmony_ci * with the new FCF record, mark FCF fast failover 290862306a36Sopenharmony_ci * completed, and then start register the new FCF 290962306a36Sopenharmony_ci * record. 291062306a36Sopenharmony_ci */ 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci /* Unregister the current in-use FCF record */ 291362306a36Sopenharmony_ci lpfc_unregister_fcf(phba); 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci /* Replace in-use record with the new record */ 291662306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 291762306a36Sopenharmony_ci "2842 Replace in-use FCF (x%x) " 291862306a36Sopenharmony_ci "with failover FCF (x%x)\n", 291962306a36Sopenharmony_ci phba->fcf.current_rec.fcf_indx, 292062306a36Sopenharmony_ci phba->fcf.failover_rec.fcf_indx); 292162306a36Sopenharmony_ci memcpy(&phba->fcf.current_rec, 292262306a36Sopenharmony_ci &phba->fcf.failover_rec, 292362306a36Sopenharmony_ci sizeof(struct lpfc_fcf_rec)); 292462306a36Sopenharmony_ci /* 292562306a36Sopenharmony_ci * Mark the fast FCF failover rediscovery completed 292662306a36Sopenharmony_ci * and the start of the first round of the roundrobin 292762306a36Sopenharmony_ci * FCF failover. 292862306a36Sopenharmony_ci */ 292962306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 293062306a36Sopenharmony_ci phba->fcf.fcf_flag &= ~FCF_REDISC_FOV; 293162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 293262306a36Sopenharmony_ci /* Register to the new FCF record */ 293362306a36Sopenharmony_ci lpfc_register_fcf(phba); 293462306a36Sopenharmony_ci } else { 293562306a36Sopenharmony_ci /* 293662306a36Sopenharmony_ci * In case of transaction period to fast FCF failover, 293762306a36Sopenharmony_ci * do nothing when search to the end of the FCF table. 293862306a36Sopenharmony_ci */ 293962306a36Sopenharmony_ci if ((phba->fcf.fcf_flag & FCF_REDISC_EVT) || 294062306a36Sopenharmony_ci (phba->fcf.fcf_flag & FCF_REDISC_PEND)) 294162306a36Sopenharmony_ci return; 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV && 294462306a36Sopenharmony_ci phba->fcf.fcf_flag & FCF_IN_USE) { 294562306a36Sopenharmony_ci /* 294662306a36Sopenharmony_ci * In case the current in-use FCF record no 294762306a36Sopenharmony_ci * longer existed during FCF discovery that 294862306a36Sopenharmony_ci * was not triggered by fast FCF failover 294962306a36Sopenharmony_ci * process, treat it as fast FCF failover. 295062306a36Sopenharmony_ci */ 295162306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 295262306a36Sopenharmony_ci "2841 In-use FCF record (x%x) " 295362306a36Sopenharmony_ci "not reported, entering fast " 295462306a36Sopenharmony_ci "FCF failover mode scanning.\n", 295562306a36Sopenharmony_ci phba->fcf.current_rec.fcf_indx); 295662306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 295762306a36Sopenharmony_ci phba->fcf.fcf_flag |= FCF_REDISC_FOV; 295862306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 295962306a36Sopenharmony_ci lpfc_sli4_fcf_scan_read_fcf_rec(phba, 296062306a36Sopenharmony_ci LPFC_FCOE_FCF_GET_FIRST); 296162306a36Sopenharmony_ci return; 296262306a36Sopenharmony_ci } 296362306a36Sopenharmony_ci /* Register to the new FCF record */ 296462306a36Sopenharmony_ci lpfc_register_fcf(phba); 296562306a36Sopenharmony_ci } 296662306a36Sopenharmony_ci } else 296762306a36Sopenharmony_ci lpfc_sli4_fcf_scan_read_fcf_rec(phba, next_fcf_index); 296862306a36Sopenharmony_ci return; 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ciout: 297162306a36Sopenharmony_ci lpfc_sli4_mbox_cmd_free(phba, mboxq); 297262306a36Sopenharmony_ci lpfc_register_fcf(phba); 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci return; 297562306a36Sopenharmony_ci} 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci/** 297862306a36Sopenharmony_ci * lpfc_mbx_cmpl_fcf_rr_read_fcf_rec - fcf roundrobin read_fcf mbox cmpl hdler 297962306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 298062306a36Sopenharmony_ci * @mboxq: pointer to mailbox object. 298162306a36Sopenharmony_ci * 298262306a36Sopenharmony_ci * This is the callback function for FLOGI failure roundrobin FCF failover 298362306a36Sopenharmony_ci * read FCF record mailbox command from the eligible FCF record bmask for 298462306a36Sopenharmony_ci * performing the failover. If the FCF read back is not valid/available, it 298562306a36Sopenharmony_ci * fails through to retrying FLOGI to the currently registered FCF again. 298662306a36Sopenharmony_ci * Otherwise, if the FCF read back is valid and available, it will set the 298762306a36Sopenharmony_ci * newly read FCF record to the failover FCF record, unregister currently 298862306a36Sopenharmony_ci * registered FCF record, copy the failover FCF record to the current 298962306a36Sopenharmony_ci * FCF record, and then register the current FCF record before proceeding 299062306a36Sopenharmony_ci * to trying FLOGI on the new failover FCF. 299162306a36Sopenharmony_ci */ 299262306a36Sopenharmony_civoid 299362306a36Sopenharmony_cilpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) 299462306a36Sopenharmony_ci{ 299562306a36Sopenharmony_ci struct fcf_record *new_fcf_record; 299662306a36Sopenharmony_ci uint32_t boot_flag, addr_mode; 299762306a36Sopenharmony_ci uint16_t next_fcf_index, fcf_index; 299862306a36Sopenharmony_ci uint16_t current_fcf_index; 299962306a36Sopenharmony_ci uint16_t vlan_id = LPFC_FCOE_NULL_VID; 300062306a36Sopenharmony_ci int rc; 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci /* If link state is not up, stop the roundrobin failover process */ 300362306a36Sopenharmony_ci if (phba->link_state < LPFC_LINK_UP) { 300462306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 300562306a36Sopenharmony_ci phba->fcf.fcf_flag &= ~FCF_DISCOVERY; 300662306a36Sopenharmony_ci phba->hba_flag &= ~FCF_RR_INPROG; 300762306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 300862306a36Sopenharmony_ci goto out; 300962306a36Sopenharmony_ci } 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_ci /* Parse the FCF record from the non-embedded mailbox command */ 301262306a36Sopenharmony_ci new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq, 301362306a36Sopenharmony_ci &next_fcf_index); 301462306a36Sopenharmony_ci if (!new_fcf_record) { 301562306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, 301662306a36Sopenharmony_ci "2766 Mailbox command READ_FCF_RECORD " 301762306a36Sopenharmony_ci "failed to retrieve a FCF record. " 301862306a36Sopenharmony_ci "hba_flg x%x fcf_flg x%x\n", phba->hba_flag, 301962306a36Sopenharmony_ci phba->fcf.fcf_flag); 302062306a36Sopenharmony_ci lpfc_unregister_fcf_rescan(phba); 302162306a36Sopenharmony_ci goto out; 302262306a36Sopenharmony_ci } 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_ci /* Get the needed parameters from FCF record */ 302562306a36Sopenharmony_ci rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag, 302662306a36Sopenharmony_ci &addr_mode, &vlan_id); 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci /* Log the FCF record information if turned on */ 302962306a36Sopenharmony_ci lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id, 303062306a36Sopenharmony_ci next_fcf_index); 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); 303362306a36Sopenharmony_ci if (!rc) { 303462306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 303562306a36Sopenharmony_ci "2848 Remove ineligible FCF (x%x) from " 303662306a36Sopenharmony_ci "from roundrobin bmask\n", fcf_index); 303762306a36Sopenharmony_ci /* Clear roundrobin bmask bit for ineligible FCF */ 303862306a36Sopenharmony_ci lpfc_sli4_fcf_rr_index_clear(phba, fcf_index); 303962306a36Sopenharmony_ci /* Perform next round of roundrobin FCF failover */ 304062306a36Sopenharmony_ci fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba); 304162306a36Sopenharmony_ci rc = lpfc_sli4_fcf_rr_next_proc(phba->pport, fcf_index); 304262306a36Sopenharmony_ci if (rc) 304362306a36Sopenharmony_ci goto out; 304462306a36Sopenharmony_ci goto error_out; 304562306a36Sopenharmony_ci } 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci if (fcf_index == phba->fcf.current_rec.fcf_indx) { 304862306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 304962306a36Sopenharmony_ci "2760 Perform FLOGI roundrobin FCF failover: " 305062306a36Sopenharmony_ci "FCF (x%x) back to FCF (x%x)\n", 305162306a36Sopenharmony_ci phba->fcf.current_rec.fcf_indx, fcf_index); 305262306a36Sopenharmony_ci /* Wait 500 ms before retrying FLOGI to current FCF */ 305362306a36Sopenharmony_ci msleep(500); 305462306a36Sopenharmony_ci lpfc_issue_init_vfi(phba->pport); 305562306a36Sopenharmony_ci goto out; 305662306a36Sopenharmony_ci } 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci /* Upload new FCF record to the failover FCF record */ 305962306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 306062306a36Sopenharmony_ci "2834 Update current FCF (x%x) with new FCF (x%x)\n", 306162306a36Sopenharmony_ci phba->fcf.failover_rec.fcf_indx, fcf_index); 306262306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 306362306a36Sopenharmony_ci __lpfc_update_fcf_record(phba, &phba->fcf.failover_rec, 306462306a36Sopenharmony_ci new_fcf_record, addr_mode, vlan_id, 306562306a36Sopenharmony_ci (boot_flag ? BOOT_ENABLE : 0)); 306662306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci current_fcf_index = phba->fcf.current_rec.fcf_indx; 306962306a36Sopenharmony_ci 307062306a36Sopenharmony_ci /* Unregister the current in-use FCF record */ 307162306a36Sopenharmony_ci lpfc_unregister_fcf(phba); 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci /* Replace in-use record with the new record */ 307462306a36Sopenharmony_ci memcpy(&phba->fcf.current_rec, &phba->fcf.failover_rec, 307562306a36Sopenharmony_ci sizeof(struct lpfc_fcf_rec)); 307662306a36Sopenharmony_ci 307762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 307862306a36Sopenharmony_ci "2783 Perform FLOGI roundrobin FCF failover: FCF " 307962306a36Sopenharmony_ci "(x%x) to FCF (x%x)\n", current_fcf_index, fcf_index); 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_cierror_out: 308262306a36Sopenharmony_ci lpfc_register_fcf(phba); 308362306a36Sopenharmony_ciout: 308462306a36Sopenharmony_ci lpfc_sli4_mbox_cmd_free(phba, mboxq); 308562306a36Sopenharmony_ci} 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci/** 308862306a36Sopenharmony_ci * lpfc_mbx_cmpl_read_fcf_rec - read fcf completion handler. 308962306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 309062306a36Sopenharmony_ci * @mboxq: pointer to mailbox object. 309162306a36Sopenharmony_ci * 309262306a36Sopenharmony_ci * This is the callback function of read FCF record mailbox command for 309362306a36Sopenharmony_ci * updating the eligible FCF bmask for FLOGI failure roundrobin FCF 309462306a36Sopenharmony_ci * failover when a new FCF event happened. If the FCF read back is 309562306a36Sopenharmony_ci * valid/available and it passes the connection list check, it updates 309662306a36Sopenharmony_ci * the bmask for the eligible FCF record for roundrobin failover. 309762306a36Sopenharmony_ci */ 309862306a36Sopenharmony_civoid 309962306a36Sopenharmony_cilpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) 310062306a36Sopenharmony_ci{ 310162306a36Sopenharmony_ci struct fcf_record *new_fcf_record; 310262306a36Sopenharmony_ci uint32_t boot_flag, addr_mode; 310362306a36Sopenharmony_ci uint16_t fcf_index, next_fcf_index; 310462306a36Sopenharmony_ci uint16_t vlan_id = LPFC_FCOE_NULL_VID; 310562306a36Sopenharmony_ci int rc; 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_ci /* If link state is not up, no need to proceed */ 310862306a36Sopenharmony_ci if (phba->link_state < LPFC_LINK_UP) 310962306a36Sopenharmony_ci goto out; 311062306a36Sopenharmony_ci 311162306a36Sopenharmony_ci /* If FCF discovery period is over, no need to proceed */ 311262306a36Sopenharmony_ci if (!(phba->fcf.fcf_flag & FCF_DISCOVERY)) 311362306a36Sopenharmony_ci goto out; 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci /* Parse the FCF record from the non-embedded mailbox command */ 311662306a36Sopenharmony_ci new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq, 311762306a36Sopenharmony_ci &next_fcf_index); 311862306a36Sopenharmony_ci if (!new_fcf_record) { 311962306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP, 312062306a36Sopenharmony_ci "2767 Mailbox command READ_FCF_RECORD " 312162306a36Sopenharmony_ci "failed to retrieve a FCF record.\n"); 312262306a36Sopenharmony_ci goto out; 312362306a36Sopenharmony_ci } 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_ci /* Check the connection list for eligibility */ 312662306a36Sopenharmony_ci rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag, 312762306a36Sopenharmony_ci &addr_mode, &vlan_id); 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci /* Log the FCF record information if turned on */ 313062306a36Sopenharmony_ci lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id, 313162306a36Sopenharmony_ci next_fcf_index); 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_ci if (!rc) 313462306a36Sopenharmony_ci goto out; 313562306a36Sopenharmony_ci 313662306a36Sopenharmony_ci /* Update the eligible FCF record index bmask */ 313762306a36Sopenharmony_ci fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index, new_fcf_record); 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_ciout: 314262306a36Sopenharmony_ci lpfc_sli4_mbox_cmd_free(phba, mboxq); 314362306a36Sopenharmony_ci} 314462306a36Sopenharmony_ci 314562306a36Sopenharmony_ci/** 314662306a36Sopenharmony_ci * lpfc_init_vfi_cmpl - Completion handler for init_vfi mbox command. 314762306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 314862306a36Sopenharmony_ci * @mboxq: pointer to mailbox data structure. 314962306a36Sopenharmony_ci * 315062306a36Sopenharmony_ci * This function handles completion of init vfi mailbox command. 315162306a36Sopenharmony_ci */ 315262306a36Sopenharmony_cistatic void 315362306a36Sopenharmony_cilpfc_init_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) 315462306a36Sopenharmony_ci{ 315562306a36Sopenharmony_ci struct lpfc_vport *vport = mboxq->vport; 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_ci /* 315862306a36Sopenharmony_ci * VFI not supported on interface type 0, just do the flogi 315962306a36Sopenharmony_ci * Also continue if the VFI is in use - just use the same one. 316062306a36Sopenharmony_ci */ 316162306a36Sopenharmony_ci if (mboxq->u.mb.mbxStatus && 316262306a36Sopenharmony_ci (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != 316362306a36Sopenharmony_ci LPFC_SLI_INTF_IF_TYPE_0) && 316462306a36Sopenharmony_ci mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) { 316562306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 316662306a36Sopenharmony_ci "2891 Init VFI mailbox failed 0x%x\n", 316762306a36Sopenharmony_ci mboxq->u.mb.mbxStatus); 316862306a36Sopenharmony_ci mempool_free(mboxq, phba->mbox_mem_pool); 316962306a36Sopenharmony_ci lpfc_vport_set_state(vport, FC_VPORT_FAILED); 317062306a36Sopenharmony_ci return; 317162306a36Sopenharmony_ci } 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci lpfc_initial_flogi(vport); 317462306a36Sopenharmony_ci mempool_free(mboxq, phba->mbox_mem_pool); 317562306a36Sopenharmony_ci return; 317662306a36Sopenharmony_ci} 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci/** 317962306a36Sopenharmony_ci * lpfc_issue_init_vfi - Issue init_vfi mailbox command. 318062306a36Sopenharmony_ci * @vport: pointer to lpfc_vport data structure. 318162306a36Sopenharmony_ci * 318262306a36Sopenharmony_ci * This function issue a init_vfi mailbox command to initialize the VFI and 318362306a36Sopenharmony_ci * VPI for the physical port. 318462306a36Sopenharmony_ci */ 318562306a36Sopenharmony_civoid 318662306a36Sopenharmony_cilpfc_issue_init_vfi(struct lpfc_vport *vport) 318762306a36Sopenharmony_ci{ 318862306a36Sopenharmony_ci LPFC_MBOXQ_t *mboxq; 318962306a36Sopenharmony_ci int rc; 319062306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 319362306a36Sopenharmony_ci if (!mboxq) { 319462306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 319562306a36Sopenharmony_ci LOG_TRACE_EVENT, "2892 Failed to allocate " 319662306a36Sopenharmony_ci "init_vfi mailbox\n"); 319762306a36Sopenharmony_ci return; 319862306a36Sopenharmony_ci } 319962306a36Sopenharmony_ci lpfc_init_vfi(mboxq, vport); 320062306a36Sopenharmony_ci mboxq->mbox_cmpl = lpfc_init_vfi_cmpl; 320162306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); 320262306a36Sopenharmony_ci if (rc == MBX_NOT_FINISHED) { 320362306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 320462306a36Sopenharmony_ci "2893 Failed to issue init_vfi mailbox\n"); 320562306a36Sopenharmony_ci mempool_free(mboxq, vport->phba->mbox_mem_pool); 320662306a36Sopenharmony_ci } 320762306a36Sopenharmony_ci} 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ci/** 321062306a36Sopenharmony_ci * lpfc_init_vpi_cmpl - Completion handler for init_vpi mbox command. 321162306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 321262306a36Sopenharmony_ci * @mboxq: pointer to mailbox data structure. 321362306a36Sopenharmony_ci * 321462306a36Sopenharmony_ci * This function handles completion of init vpi mailbox command. 321562306a36Sopenharmony_ci */ 321662306a36Sopenharmony_civoid 321762306a36Sopenharmony_cilpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) 321862306a36Sopenharmony_ci{ 321962306a36Sopenharmony_ci struct lpfc_vport *vport = mboxq->vport; 322062306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 322162306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci if (mboxq->u.mb.mbxStatus) { 322462306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 322562306a36Sopenharmony_ci "2609 Init VPI mailbox failed 0x%x\n", 322662306a36Sopenharmony_ci mboxq->u.mb.mbxStatus); 322762306a36Sopenharmony_ci mempool_free(mboxq, phba->mbox_mem_pool); 322862306a36Sopenharmony_ci lpfc_vport_set_state(vport, FC_VPORT_FAILED); 322962306a36Sopenharmony_ci return; 323062306a36Sopenharmony_ci } 323162306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 323262306a36Sopenharmony_ci vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI; 323362306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci /* If this port is physical port or FDISC is done, do reg_vpi */ 323662306a36Sopenharmony_ci if ((phba->pport == vport) || (vport->port_state == LPFC_FDISC)) { 323762306a36Sopenharmony_ci ndlp = lpfc_findnode_did(vport, Fabric_DID); 323862306a36Sopenharmony_ci if (!ndlp) 323962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 324062306a36Sopenharmony_ci LOG_TRACE_EVENT, 324162306a36Sopenharmony_ci "2731 Cannot find fabric " 324262306a36Sopenharmony_ci "controller node\n"); 324362306a36Sopenharmony_ci else 324462306a36Sopenharmony_ci lpfc_register_new_vport(phba, vport, ndlp); 324562306a36Sopenharmony_ci mempool_free(mboxq, phba->mbox_mem_pool); 324662306a36Sopenharmony_ci return; 324762306a36Sopenharmony_ci } 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) 325062306a36Sopenharmony_ci lpfc_initial_fdisc(vport); 325162306a36Sopenharmony_ci else { 325262306a36Sopenharmony_ci lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); 325362306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 325462306a36Sopenharmony_ci "2606 No NPIV Fabric support\n"); 325562306a36Sopenharmony_ci } 325662306a36Sopenharmony_ci mempool_free(mboxq, phba->mbox_mem_pool); 325762306a36Sopenharmony_ci return; 325862306a36Sopenharmony_ci} 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci/** 326162306a36Sopenharmony_ci * lpfc_issue_init_vpi - Issue init_vpi mailbox command. 326262306a36Sopenharmony_ci * @vport: pointer to lpfc_vport data structure. 326362306a36Sopenharmony_ci * 326462306a36Sopenharmony_ci * This function issue a init_vpi mailbox command to initialize 326562306a36Sopenharmony_ci * VPI for the vport. 326662306a36Sopenharmony_ci */ 326762306a36Sopenharmony_civoid 326862306a36Sopenharmony_cilpfc_issue_init_vpi(struct lpfc_vport *vport) 326962306a36Sopenharmony_ci{ 327062306a36Sopenharmony_ci LPFC_MBOXQ_t *mboxq; 327162306a36Sopenharmony_ci int rc, vpi; 327262306a36Sopenharmony_ci 327362306a36Sopenharmony_ci if ((vport->port_type != LPFC_PHYSICAL_PORT) && (!vport->vpi)) { 327462306a36Sopenharmony_ci vpi = lpfc_alloc_vpi(vport->phba); 327562306a36Sopenharmony_ci if (!vpi) { 327662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 327762306a36Sopenharmony_ci "3303 Failed to obtain vport vpi\n"); 327862306a36Sopenharmony_ci lpfc_vport_set_state(vport, FC_VPORT_FAILED); 327962306a36Sopenharmony_ci return; 328062306a36Sopenharmony_ci } 328162306a36Sopenharmony_ci vport->vpi = vpi; 328262306a36Sopenharmony_ci } 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_ci mboxq = mempool_alloc(vport->phba->mbox_mem_pool, GFP_KERNEL); 328562306a36Sopenharmony_ci if (!mboxq) { 328662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 328762306a36Sopenharmony_ci LOG_TRACE_EVENT, "2607 Failed to allocate " 328862306a36Sopenharmony_ci "init_vpi mailbox\n"); 328962306a36Sopenharmony_ci return; 329062306a36Sopenharmony_ci } 329162306a36Sopenharmony_ci lpfc_init_vpi(vport->phba, mboxq, vport->vpi); 329262306a36Sopenharmony_ci mboxq->vport = vport; 329362306a36Sopenharmony_ci mboxq->mbox_cmpl = lpfc_init_vpi_cmpl; 329462306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox(vport->phba, mboxq, MBX_NOWAIT); 329562306a36Sopenharmony_ci if (rc == MBX_NOT_FINISHED) { 329662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 329762306a36Sopenharmony_ci "2608 Failed to issue init_vpi mailbox\n"); 329862306a36Sopenharmony_ci mempool_free(mboxq, vport->phba->mbox_mem_pool); 329962306a36Sopenharmony_ci } 330062306a36Sopenharmony_ci} 330162306a36Sopenharmony_ci 330262306a36Sopenharmony_ci/** 330362306a36Sopenharmony_ci * lpfc_start_fdiscs - send fdiscs for each vports on this port. 330462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 330562306a36Sopenharmony_ci * 330662306a36Sopenharmony_ci * This function loops through the list of vports on the @phba and issues an 330762306a36Sopenharmony_ci * FDISC if possible. 330862306a36Sopenharmony_ci */ 330962306a36Sopenharmony_civoid 331062306a36Sopenharmony_cilpfc_start_fdiscs(struct lpfc_hba *phba) 331162306a36Sopenharmony_ci{ 331262306a36Sopenharmony_ci struct lpfc_vport **vports; 331362306a36Sopenharmony_ci int i; 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci vports = lpfc_create_vport_work_array(phba); 331662306a36Sopenharmony_ci if (vports != NULL) { 331762306a36Sopenharmony_ci for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { 331862306a36Sopenharmony_ci if (vports[i]->port_type == LPFC_PHYSICAL_PORT) 331962306a36Sopenharmony_ci continue; 332062306a36Sopenharmony_ci /* There are no vpi for this vport */ 332162306a36Sopenharmony_ci if (vports[i]->vpi > phba->max_vpi) { 332262306a36Sopenharmony_ci lpfc_vport_set_state(vports[i], 332362306a36Sopenharmony_ci FC_VPORT_FAILED); 332462306a36Sopenharmony_ci continue; 332562306a36Sopenharmony_ci } 332662306a36Sopenharmony_ci if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { 332762306a36Sopenharmony_ci lpfc_vport_set_state(vports[i], 332862306a36Sopenharmony_ci FC_VPORT_LINKDOWN); 332962306a36Sopenharmony_ci continue; 333062306a36Sopenharmony_ci } 333162306a36Sopenharmony_ci if (vports[i]->fc_flag & FC_VPORT_NEEDS_INIT_VPI) { 333262306a36Sopenharmony_ci lpfc_issue_init_vpi(vports[i]); 333362306a36Sopenharmony_ci continue; 333462306a36Sopenharmony_ci } 333562306a36Sopenharmony_ci if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) 333662306a36Sopenharmony_ci lpfc_initial_fdisc(vports[i]); 333762306a36Sopenharmony_ci else { 333862306a36Sopenharmony_ci lpfc_vport_set_state(vports[i], 333962306a36Sopenharmony_ci FC_VPORT_NO_FABRIC_SUPP); 334062306a36Sopenharmony_ci lpfc_printf_vlog(vports[i], KERN_ERR, 334162306a36Sopenharmony_ci LOG_TRACE_EVENT, 334262306a36Sopenharmony_ci "0259 No NPIV " 334362306a36Sopenharmony_ci "Fabric support\n"); 334462306a36Sopenharmony_ci } 334562306a36Sopenharmony_ci } 334662306a36Sopenharmony_ci } 334762306a36Sopenharmony_ci lpfc_destroy_vport_work_array(phba, vports); 334862306a36Sopenharmony_ci} 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_civoid 335162306a36Sopenharmony_cilpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) 335262306a36Sopenharmony_ci{ 335362306a36Sopenharmony_ci struct lpfc_vport *vport = mboxq->vport; 335462306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_ci /* 335762306a36Sopenharmony_ci * VFI not supported for interface type 0, so ignore any mailbox 335862306a36Sopenharmony_ci * error (except VFI in use) and continue with the discovery. 335962306a36Sopenharmony_ci */ 336062306a36Sopenharmony_ci if (mboxq->u.mb.mbxStatus && 336162306a36Sopenharmony_ci (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != 336262306a36Sopenharmony_ci LPFC_SLI_INTF_IF_TYPE_0) && 336362306a36Sopenharmony_ci mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) { 336462306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 336562306a36Sopenharmony_ci "2018 REG_VFI mbxStatus error x%x " 336662306a36Sopenharmony_ci "HBA state x%x\n", 336762306a36Sopenharmony_ci mboxq->u.mb.mbxStatus, vport->port_state); 336862306a36Sopenharmony_ci if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { 336962306a36Sopenharmony_ci /* FLOGI failed, use loop map to make discovery list */ 337062306a36Sopenharmony_ci lpfc_disc_list_loopmap(vport); 337162306a36Sopenharmony_ci /* Start discovery */ 337262306a36Sopenharmony_ci lpfc_disc_start(vport); 337362306a36Sopenharmony_ci goto out_free_mem; 337462306a36Sopenharmony_ci } 337562306a36Sopenharmony_ci lpfc_vport_set_state(vport, FC_VPORT_FAILED); 337662306a36Sopenharmony_ci goto out_free_mem; 337762306a36Sopenharmony_ci } 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_ci /* If the VFI is already registered, there is nothing else to do 338062306a36Sopenharmony_ci * Unless this was a VFI update and we are in PT2PT mode, then 338162306a36Sopenharmony_ci * we should drop through to set the port state to ready. 338262306a36Sopenharmony_ci */ 338362306a36Sopenharmony_ci if (vport->fc_flag & FC_VFI_REGISTERED) 338462306a36Sopenharmony_ci if (!(phba->sli_rev == LPFC_SLI_REV4 && 338562306a36Sopenharmony_ci vport->fc_flag & FC_PT2PT)) 338662306a36Sopenharmony_ci goto out_free_mem; 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci /* The VPI is implicitly registered when the VFI is registered */ 338962306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 339062306a36Sopenharmony_ci vport->vpi_state |= LPFC_VPI_REGISTERED; 339162306a36Sopenharmony_ci vport->fc_flag |= FC_VFI_REGISTERED; 339262306a36Sopenharmony_ci vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; 339362306a36Sopenharmony_ci vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI; 339462306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_ci /* In case SLI4 FC loopback test, we are ready */ 339762306a36Sopenharmony_ci if ((phba->sli_rev == LPFC_SLI_REV4) && 339862306a36Sopenharmony_ci (phba->link_flag & LS_LOOPBACK_MODE)) { 339962306a36Sopenharmony_ci phba->link_state = LPFC_HBA_READY; 340062306a36Sopenharmony_ci goto out_free_mem; 340162306a36Sopenharmony_ci } 340262306a36Sopenharmony_ci 340362306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, 340462306a36Sopenharmony_ci "3313 cmpl reg vfi port_state:%x fc_flag:%x myDid:%x " 340562306a36Sopenharmony_ci "alpacnt:%d LinkState:%x topology:%x\n", 340662306a36Sopenharmony_ci vport->port_state, vport->fc_flag, vport->fc_myDID, 340762306a36Sopenharmony_ci vport->phba->alpa_map[0], 340862306a36Sopenharmony_ci phba->link_state, phba->fc_topology); 340962306a36Sopenharmony_ci 341062306a36Sopenharmony_ci if (vport->port_state == LPFC_FABRIC_CFG_LINK) { 341162306a36Sopenharmony_ci /* 341262306a36Sopenharmony_ci * For private loop or for NPort pt2pt, 341362306a36Sopenharmony_ci * just start discovery and we are done. 341462306a36Sopenharmony_ci */ 341562306a36Sopenharmony_ci if ((vport->fc_flag & FC_PT2PT) || 341662306a36Sopenharmony_ci ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && 341762306a36Sopenharmony_ci !(vport->fc_flag & FC_PUBLIC_LOOP))) { 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_ci /* Use loop map to make discovery list */ 342062306a36Sopenharmony_ci lpfc_disc_list_loopmap(vport); 342162306a36Sopenharmony_ci /* Start discovery */ 342262306a36Sopenharmony_ci if (vport->fc_flag & FC_PT2PT) 342362306a36Sopenharmony_ci vport->port_state = LPFC_VPORT_READY; 342462306a36Sopenharmony_ci else 342562306a36Sopenharmony_ci lpfc_disc_start(vport); 342662306a36Sopenharmony_ci } else { 342762306a36Sopenharmony_ci lpfc_start_fdiscs(phba); 342862306a36Sopenharmony_ci lpfc_do_scr_ns_plogi(phba, vport); 342962306a36Sopenharmony_ci } 343062306a36Sopenharmony_ci } 343162306a36Sopenharmony_ci 343262306a36Sopenharmony_ciout_free_mem: 343362306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED); 343462306a36Sopenharmony_ci} 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_cistatic void 343762306a36Sopenharmony_cilpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) 343862306a36Sopenharmony_ci{ 343962306a36Sopenharmony_ci MAILBOX_t *mb = &pmb->u.mb; 344062306a36Sopenharmony_ci struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)pmb->ctx_buf; 344162306a36Sopenharmony_ci struct lpfc_vport *vport = pmb->vport; 344262306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 344362306a36Sopenharmony_ci struct serv_parm *sp = &vport->fc_sparam; 344462306a36Sopenharmony_ci uint32_t ed_tov; 344562306a36Sopenharmony_ci 344662306a36Sopenharmony_ci /* Check for error */ 344762306a36Sopenharmony_ci if (mb->mbxStatus) { 344862306a36Sopenharmony_ci /* READ_SPARAM mbox error <mbxStatus> state <hba_state> */ 344962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 345062306a36Sopenharmony_ci "0319 READ_SPARAM mbxStatus error x%x " 345162306a36Sopenharmony_ci "hba state x%x>\n", 345262306a36Sopenharmony_ci mb->mbxStatus, vport->port_state); 345362306a36Sopenharmony_ci lpfc_linkdown(phba); 345462306a36Sopenharmony_ci goto out; 345562306a36Sopenharmony_ci } 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_ci memcpy((uint8_t *) &vport->fc_sparam, (uint8_t *) mp->virt, 345862306a36Sopenharmony_ci sizeof (struct serv_parm)); 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci ed_tov = be32_to_cpu(sp->cmn.e_d_tov); 346162306a36Sopenharmony_ci if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */ 346262306a36Sopenharmony_ci ed_tov = (ed_tov + 999999) / 1000000; 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci phba->fc_edtov = ed_tov; 346562306a36Sopenharmony_ci phba->fc_ratov = (2 * ed_tov) / 1000; 346662306a36Sopenharmony_ci if (phba->fc_ratov < FF_DEF_RATOV) { 346762306a36Sopenharmony_ci /* RA_TOV should be atleast 10sec for initial flogi */ 346862306a36Sopenharmony_ci phba->fc_ratov = FF_DEF_RATOV; 346962306a36Sopenharmony_ci } 347062306a36Sopenharmony_ci 347162306a36Sopenharmony_ci lpfc_update_vport_wwn(vport); 347262306a36Sopenharmony_ci fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn); 347362306a36Sopenharmony_ci if (vport->port_type == LPFC_PHYSICAL_PORT) { 347462306a36Sopenharmony_ci memcpy(&phba->wwnn, &vport->fc_nodename, sizeof(phba->wwnn)); 347562306a36Sopenharmony_ci memcpy(&phba->wwpn, &vport->fc_portname, sizeof(phba->wwnn)); 347662306a36Sopenharmony_ci } 347762306a36Sopenharmony_ci 347862306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci /* Check if sending the FLOGI is being deferred to after we get 348162306a36Sopenharmony_ci * up to date CSPs from MBX_READ_SPARAM. 348262306a36Sopenharmony_ci */ 348362306a36Sopenharmony_ci if (phba->hba_flag & HBA_DEFER_FLOGI) { 348462306a36Sopenharmony_ci lpfc_initial_flogi(vport); 348562306a36Sopenharmony_ci phba->hba_flag &= ~HBA_DEFER_FLOGI; 348662306a36Sopenharmony_ci } 348762306a36Sopenharmony_ci return; 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_ciout: 349062306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); 349162306a36Sopenharmony_ci lpfc_issue_clear_la(phba, vport); 349262306a36Sopenharmony_ci} 349362306a36Sopenharmony_ci 349462306a36Sopenharmony_cistatic void 349562306a36Sopenharmony_cilpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) 349662306a36Sopenharmony_ci{ 349762306a36Sopenharmony_ci struct lpfc_vport *vport = phba->pport; 349862306a36Sopenharmony_ci LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL; 349962306a36Sopenharmony_ci struct Scsi_Host *shost; 350062306a36Sopenharmony_ci int i; 350162306a36Sopenharmony_ci int rc; 350262306a36Sopenharmony_ci struct fcf_record *fcf_record; 350362306a36Sopenharmony_ci uint32_t fc_flags = 0; 350462306a36Sopenharmony_ci unsigned long iflags; 350562306a36Sopenharmony_ci 350662306a36Sopenharmony_ci spin_lock_irqsave(&phba->hbalock, iflags); 350762306a36Sopenharmony_ci phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la); 350862306a36Sopenharmony_ci 350962306a36Sopenharmony_ci if (!(phba->hba_flag & HBA_FCOE_MODE)) { 351062306a36Sopenharmony_ci switch (bf_get(lpfc_mbx_read_top_link_spd, la)) { 351162306a36Sopenharmony_ci case LPFC_LINK_SPEED_1GHZ: 351262306a36Sopenharmony_ci case LPFC_LINK_SPEED_2GHZ: 351362306a36Sopenharmony_ci case LPFC_LINK_SPEED_4GHZ: 351462306a36Sopenharmony_ci case LPFC_LINK_SPEED_8GHZ: 351562306a36Sopenharmony_ci case LPFC_LINK_SPEED_10GHZ: 351662306a36Sopenharmony_ci case LPFC_LINK_SPEED_16GHZ: 351762306a36Sopenharmony_ci case LPFC_LINK_SPEED_32GHZ: 351862306a36Sopenharmony_ci case LPFC_LINK_SPEED_64GHZ: 351962306a36Sopenharmony_ci case LPFC_LINK_SPEED_128GHZ: 352062306a36Sopenharmony_ci case LPFC_LINK_SPEED_256GHZ: 352162306a36Sopenharmony_ci break; 352262306a36Sopenharmony_ci default: 352362306a36Sopenharmony_ci phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN; 352462306a36Sopenharmony_ci break; 352562306a36Sopenharmony_ci } 352662306a36Sopenharmony_ci } 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci if (phba->fc_topology && 352962306a36Sopenharmony_ci phba->fc_topology != bf_get(lpfc_mbx_read_top_topology, la)) { 353062306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, 353162306a36Sopenharmony_ci "3314 Toplogy changed was 0x%x is 0x%x\n", 353262306a36Sopenharmony_ci phba->fc_topology, 353362306a36Sopenharmony_ci bf_get(lpfc_mbx_read_top_topology, la)); 353462306a36Sopenharmony_ci phba->fc_topology_changed = 1; 353562306a36Sopenharmony_ci } 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci phba->fc_topology = bf_get(lpfc_mbx_read_top_topology, la); 353862306a36Sopenharmony_ci phba->link_flag &= ~(LS_NPIV_FAB_SUPPORTED | LS_CT_VEN_RPA); 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci shost = lpfc_shost_from_vport(vport); 354162306a36Sopenharmony_ci if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { 354262306a36Sopenharmony_ci phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; 354362306a36Sopenharmony_ci 354462306a36Sopenharmony_ci /* if npiv is enabled and this adapter supports npiv log 354562306a36Sopenharmony_ci * a message that npiv is not supported in this topology 354662306a36Sopenharmony_ci */ 354762306a36Sopenharmony_ci if (phba->cfg_enable_npiv && phba->max_vpi) 354862306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, 354962306a36Sopenharmony_ci "1309 Link Up Event npiv not supported in loop " 355062306a36Sopenharmony_ci "topology\n"); 355162306a36Sopenharmony_ci /* Get Loop Map information */ 355262306a36Sopenharmony_ci if (bf_get(lpfc_mbx_read_top_il, la)) 355362306a36Sopenharmony_ci fc_flags |= FC_LBIT; 355462306a36Sopenharmony_ci 355562306a36Sopenharmony_ci vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la); 355662306a36Sopenharmony_ci i = la->lilpBde64.tus.f.bdeSize; 355762306a36Sopenharmony_ci 355862306a36Sopenharmony_ci if (i == 0) { 355962306a36Sopenharmony_ci phba->alpa_map[0] = 0; 356062306a36Sopenharmony_ci } else { 356162306a36Sopenharmony_ci if (vport->cfg_log_verbose & LOG_LINK_EVENT) { 356262306a36Sopenharmony_ci int numalpa, j, k; 356362306a36Sopenharmony_ci union { 356462306a36Sopenharmony_ci uint8_t pamap[16]; 356562306a36Sopenharmony_ci struct { 356662306a36Sopenharmony_ci uint32_t wd1; 356762306a36Sopenharmony_ci uint32_t wd2; 356862306a36Sopenharmony_ci uint32_t wd3; 356962306a36Sopenharmony_ci uint32_t wd4; 357062306a36Sopenharmony_ci } pa; 357162306a36Sopenharmony_ci } un; 357262306a36Sopenharmony_ci numalpa = phba->alpa_map[0]; 357362306a36Sopenharmony_ci j = 0; 357462306a36Sopenharmony_ci while (j < numalpa) { 357562306a36Sopenharmony_ci memset(un.pamap, 0, 16); 357662306a36Sopenharmony_ci for (k = 1; j < numalpa; k++) { 357762306a36Sopenharmony_ci un.pamap[k - 1] = 357862306a36Sopenharmony_ci phba->alpa_map[j + 1]; 357962306a36Sopenharmony_ci j++; 358062306a36Sopenharmony_ci if (k == 16) 358162306a36Sopenharmony_ci break; 358262306a36Sopenharmony_ci } 358362306a36Sopenharmony_ci /* Link Up Event ALPA map */ 358462306a36Sopenharmony_ci lpfc_printf_log(phba, 358562306a36Sopenharmony_ci KERN_WARNING, 358662306a36Sopenharmony_ci LOG_LINK_EVENT, 358762306a36Sopenharmony_ci "1304 Link Up Event " 358862306a36Sopenharmony_ci "ALPA map Data: x%x " 358962306a36Sopenharmony_ci "x%x x%x x%x\n", 359062306a36Sopenharmony_ci un.pa.wd1, un.pa.wd2, 359162306a36Sopenharmony_ci un.pa.wd3, un.pa.wd4); 359262306a36Sopenharmony_ci } 359362306a36Sopenharmony_ci } 359462306a36Sopenharmony_ci } 359562306a36Sopenharmony_ci } else { 359662306a36Sopenharmony_ci if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { 359762306a36Sopenharmony_ci if (phba->max_vpi && phba->cfg_enable_npiv && 359862306a36Sopenharmony_ci (phba->sli_rev >= LPFC_SLI_REV3)) 359962306a36Sopenharmony_ci phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED; 360062306a36Sopenharmony_ci } 360162306a36Sopenharmony_ci vport->fc_myDID = phba->fc_pref_DID; 360262306a36Sopenharmony_ci fc_flags |= FC_LBIT; 360362306a36Sopenharmony_ci } 360462306a36Sopenharmony_ci spin_unlock_irqrestore(&phba->hbalock, iflags); 360562306a36Sopenharmony_ci 360662306a36Sopenharmony_ci if (fc_flags) { 360762306a36Sopenharmony_ci spin_lock_irqsave(shost->host_lock, iflags); 360862306a36Sopenharmony_ci vport->fc_flag |= fc_flags; 360962306a36Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, iflags); 361062306a36Sopenharmony_ci } 361162306a36Sopenharmony_ci 361262306a36Sopenharmony_ci lpfc_linkup(phba); 361362306a36Sopenharmony_ci sparam_mbox = NULL; 361462306a36Sopenharmony_ci 361562306a36Sopenharmony_ci sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 361662306a36Sopenharmony_ci if (!sparam_mbox) 361762306a36Sopenharmony_ci goto out; 361862306a36Sopenharmony_ci 361962306a36Sopenharmony_ci rc = lpfc_read_sparam(phba, sparam_mbox, 0); 362062306a36Sopenharmony_ci if (rc) { 362162306a36Sopenharmony_ci mempool_free(sparam_mbox, phba->mbox_mem_pool); 362262306a36Sopenharmony_ci goto out; 362362306a36Sopenharmony_ci } 362462306a36Sopenharmony_ci sparam_mbox->vport = vport; 362562306a36Sopenharmony_ci sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam; 362662306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT); 362762306a36Sopenharmony_ci if (rc == MBX_NOT_FINISHED) { 362862306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, sparam_mbox, MBOX_THD_UNLOCKED); 362962306a36Sopenharmony_ci goto out; 363062306a36Sopenharmony_ci } 363162306a36Sopenharmony_ci 363262306a36Sopenharmony_ci if (!(phba->hba_flag & HBA_FCOE_MODE)) { 363362306a36Sopenharmony_ci cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 363462306a36Sopenharmony_ci if (!cfglink_mbox) 363562306a36Sopenharmony_ci goto out; 363662306a36Sopenharmony_ci vport->port_state = LPFC_LOCAL_CFG_LINK; 363762306a36Sopenharmony_ci lpfc_config_link(phba, cfglink_mbox); 363862306a36Sopenharmony_ci cfglink_mbox->vport = vport; 363962306a36Sopenharmony_ci cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; 364062306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT); 364162306a36Sopenharmony_ci if (rc == MBX_NOT_FINISHED) { 364262306a36Sopenharmony_ci mempool_free(cfglink_mbox, phba->mbox_mem_pool); 364362306a36Sopenharmony_ci goto out; 364462306a36Sopenharmony_ci } 364562306a36Sopenharmony_ci } else { 364662306a36Sopenharmony_ci vport->port_state = LPFC_VPORT_UNKNOWN; 364762306a36Sopenharmony_ci /* 364862306a36Sopenharmony_ci * Add the driver's default FCF record at FCF index 0 now. This 364962306a36Sopenharmony_ci * is phase 1 implementation that support FCF index 0 and driver 365062306a36Sopenharmony_ci * defaults. 365162306a36Sopenharmony_ci */ 365262306a36Sopenharmony_ci if (!(phba->hba_flag & HBA_FIP_SUPPORT)) { 365362306a36Sopenharmony_ci fcf_record = kzalloc(sizeof(struct fcf_record), 365462306a36Sopenharmony_ci GFP_KERNEL); 365562306a36Sopenharmony_ci if (unlikely(!fcf_record)) { 365662306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, 365762306a36Sopenharmony_ci LOG_TRACE_EVENT, 365862306a36Sopenharmony_ci "2554 Could not allocate memory for " 365962306a36Sopenharmony_ci "fcf record\n"); 366062306a36Sopenharmony_ci rc = -ENODEV; 366162306a36Sopenharmony_ci goto out; 366262306a36Sopenharmony_ci } 366362306a36Sopenharmony_ci 366462306a36Sopenharmony_ci lpfc_sli4_build_dflt_fcf_record(phba, fcf_record, 366562306a36Sopenharmony_ci LPFC_FCOE_FCF_DEF_INDEX); 366662306a36Sopenharmony_ci rc = lpfc_sli4_add_fcf_record(phba, fcf_record); 366762306a36Sopenharmony_ci if (unlikely(rc)) { 366862306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, 366962306a36Sopenharmony_ci LOG_TRACE_EVENT, 367062306a36Sopenharmony_ci "2013 Could not manually add FCF " 367162306a36Sopenharmony_ci "record 0, status %d\n", rc); 367262306a36Sopenharmony_ci rc = -ENODEV; 367362306a36Sopenharmony_ci kfree(fcf_record); 367462306a36Sopenharmony_ci goto out; 367562306a36Sopenharmony_ci } 367662306a36Sopenharmony_ci kfree(fcf_record); 367762306a36Sopenharmony_ci } 367862306a36Sopenharmony_ci /* 367962306a36Sopenharmony_ci * The driver is expected to do FIP/FCF. Call the port 368062306a36Sopenharmony_ci * and get the FCF Table. 368162306a36Sopenharmony_ci */ 368262306a36Sopenharmony_ci spin_lock_irqsave(&phba->hbalock, iflags); 368362306a36Sopenharmony_ci if (phba->hba_flag & FCF_TS_INPROG) { 368462306a36Sopenharmony_ci spin_unlock_irqrestore(&phba->hbalock, iflags); 368562306a36Sopenharmony_ci return; 368662306a36Sopenharmony_ci } 368762306a36Sopenharmony_ci /* This is the initial FCF discovery scan */ 368862306a36Sopenharmony_ci phba->fcf.fcf_flag |= FCF_INIT_DISC; 368962306a36Sopenharmony_ci spin_unlock_irqrestore(&phba->hbalock, iflags); 369062306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, 369162306a36Sopenharmony_ci "2778 Start FCF table scan at linkup\n"); 369262306a36Sopenharmony_ci rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, 369362306a36Sopenharmony_ci LPFC_FCOE_FCF_GET_FIRST); 369462306a36Sopenharmony_ci if (rc) { 369562306a36Sopenharmony_ci spin_lock_irqsave(&phba->hbalock, iflags); 369662306a36Sopenharmony_ci phba->fcf.fcf_flag &= ~FCF_INIT_DISC; 369762306a36Sopenharmony_ci spin_unlock_irqrestore(&phba->hbalock, iflags); 369862306a36Sopenharmony_ci goto out; 369962306a36Sopenharmony_ci } 370062306a36Sopenharmony_ci /* Reset FCF roundrobin bmask for new discovery */ 370162306a36Sopenharmony_ci lpfc_sli4_clear_fcf_rr_bmask(phba); 370262306a36Sopenharmony_ci } 370362306a36Sopenharmony_ci 370462306a36Sopenharmony_ci /* Prepare for LINK up registrations */ 370562306a36Sopenharmony_ci memset(phba->os_host_name, 0, sizeof(phba->os_host_name)); 370662306a36Sopenharmony_ci scnprintf(phba->os_host_name, sizeof(phba->os_host_name), "%s", 370762306a36Sopenharmony_ci init_utsname()->nodename); 370862306a36Sopenharmony_ci return; 370962306a36Sopenharmony_ciout: 371062306a36Sopenharmony_ci lpfc_vport_set_state(vport, FC_VPORT_FAILED); 371162306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 371262306a36Sopenharmony_ci "0263 Discovery Mailbox error: state: 0x%x : x%px x%px\n", 371362306a36Sopenharmony_ci vport->port_state, sparam_mbox, cfglink_mbox); 371462306a36Sopenharmony_ci lpfc_issue_clear_la(phba, vport); 371562306a36Sopenharmony_ci return; 371662306a36Sopenharmony_ci} 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_cistatic void 371962306a36Sopenharmony_cilpfc_enable_la(struct lpfc_hba *phba) 372062306a36Sopenharmony_ci{ 372162306a36Sopenharmony_ci uint32_t control; 372262306a36Sopenharmony_ci struct lpfc_sli *psli = &phba->sli; 372362306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 372462306a36Sopenharmony_ci psli->sli_flag |= LPFC_PROCESS_LA; 372562306a36Sopenharmony_ci if (phba->sli_rev <= LPFC_SLI_REV3) { 372662306a36Sopenharmony_ci control = readl(phba->HCregaddr); 372762306a36Sopenharmony_ci control |= HC_LAINT_ENA; 372862306a36Sopenharmony_ci writel(control, phba->HCregaddr); 372962306a36Sopenharmony_ci readl(phba->HCregaddr); /* flush */ 373062306a36Sopenharmony_ci } 373162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 373262306a36Sopenharmony_ci} 373362306a36Sopenharmony_ci 373462306a36Sopenharmony_cistatic void 373562306a36Sopenharmony_cilpfc_mbx_issue_link_down(struct lpfc_hba *phba) 373662306a36Sopenharmony_ci{ 373762306a36Sopenharmony_ci lpfc_linkdown(phba); 373862306a36Sopenharmony_ci lpfc_enable_la(phba); 373962306a36Sopenharmony_ci lpfc_unregister_unused_fcf(phba); 374062306a36Sopenharmony_ci /* turn on Link Attention interrupts - no CLEAR_LA needed */ 374162306a36Sopenharmony_ci} 374262306a36Sopenharmony_ci 374362306a36Sopenharmony_ci 374462306a36Sopenharmony_ci/* 374562306a36Sopenharmony_ci * This routine handles processing a READ_TOPOLOGY mailbox 374662306a36Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ 374762306a36Sopenharmony_ci * as the completion routine when the command is 374862306a36Sopenharmony_ci * handed off to the SLI layer. SLI4 only. 374962306a36Sopenharmony_ci */ 375062306a36Sopenharmony_civoid 375162306a36Sopenharmony_cilpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) 375262306a36Sopenharmony_ci{ 375362306a36Sopenharmony_ci struct lpfc_vport *vport = pmb->vport; 375462306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 375562306a36Sopenharmony_ci struct lpfc_mbx_read_top *la; 375662306a36Sopenharmony_ci struct lpfc_sli_ring *pring; 375762306a36Sopenharmony_ci MAILBOX_t *mb = &pmb->u.mb; 375862306a36Sopenharmony_ci struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf); 375962306a36Sopenharmony_ci uint8_t attn_type; 376062306a36Sopenharmony_ci unsigned long iflags; 376162306a36Sopenharmony_ci 376262306a36Sopenharmony_ci /* Unblock ELS traffic */ 376362306a36Sopenharmony_ci pring = lpfc_phba_elsring(phba); 376462306a36Sopenharmony_ci if (pring) 376562306a36Sopenharmony_ci pring->flag &= ~LPFC_STOP_IOCB_EVENT; 376662306a36Sopenharmony_ci 376762306a36Sopenharmony_ci /* Check for error */ 376862306a36Sopenharmony_ci if (mb->mbxStatus) { 376962306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, 377062306a36Sopenharmony_ci "1307 READ_LA mbox error x%x state x%x\n", 377162306a36Sopenharmony_ci mb->mbxStatus, vport->port_state); 377262306a36Sopenharmony_ci lpfc_mbx_issue_link_down(phba); 377362306a36Sopenharmony_ci phba->link_state = LPFC_HBA_ERROR; 377462306a36Sopenharmony_ci goto lpfc_mbx_cmpl_read_topology_free_mbuf; 377562306a36Sopenharmony_ci } 377662306a36Sopenharmony_ci 377762306a36Sopenharmony_ci la = (struct lpfc_mbx_read_top *) &pmb->u.mb.un.varReadTop; 377862306a36Sopenharmony_ci attn_type = bf_get(lpfc_mbx_read_top_att_type, la); 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci memcpy(&phba->alpa_map[0], mp->virt, 128); 378162306a36Sopenharmony_ci 378262306a36Sopenharmony_ci spin_lock_irqsave(shost->host_lock, iflags); 378362306a36Sopenharmony_ci if (bf_get(lpfc_mbx_read_top_pb, la)) 378462306a36Sopenharmony_ci vport->fc_flag |= FC_BYPASSED_MODE; 378562306a36Sopenharmony_ci else 378662306a36Sopenharmony_ci vport->fc_flag &= ~FC_BYPASSED_MODE; 378762306a36Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, iflags); 378862306a36Sopenharmony_ci 378962306a36Sopenharmony_ci if (phba->fc_eventTag <= la->eventTag) { 379062306a36Sopenharmony_ci phba->fc_stat.LinkMultiEvent++; 379162306a36Sopenharmony_ci if (attn_type == LPFC_ATT_LINK_UP) 379262306a36Sopenharmony_ci if (phba->fc_eventTag != 0) 379362306a36Sopenharmony_ci lpfc_linkdown(phba); 379462306a36Sopenharmony_ci } 379562306a36Sopenharmony_ci 379662306a36Sopenharmony_ci phba->fc_eventTag = la->eventTag; 379762306a36Sopenharmony_ci phba->link_events++; 379862306a36Sopenharmony_ci if (attn_type == LPFC_ATT_LINK_UP) { 379962306a36Sopenharmony_ci phba->fc_stat.LinkUp++; 380062306a36Sopenharmony_ci if (phba->link_flag & LS_LOOPBACK_MODE) { 380162306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, 380262306a36Sopenharmony_ci "1306 Link Up Event in loop back mode " 380362306a36Sopenharmony_ci "x%x received Data: x%x x%x x%x x%x\n", 380462306a36Sopenharmony_ci la->eventTag, phba->fc_eventTag, 380562306a36Sopenharmony_ci bf_get(lpfc_mbx_read_top_alpa_granted, 380662306a36Sopenharmony_ci la), 380762306a36Sopenharmony_ci bf_get(lpfc_mbx_read_top_link_spd, la), 380862306a36Sopenharmony_ci phba->alpa_map[0]); 380962306a36Sopenharmony_ci } else { 381062306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, 381162306a36Sopenharmony_ci "1303 Link Up Event x%x received " 381262306a36Sopenharmony_ci "Data: x%x x%x x%x x%x x%x\n", 381362306a36Sopenharmony_ci la->eventTag, phba->fc_eventTag, 381462306a36Sopenharmony_ci bf_get(lpfc_mbx_read_top_alpa_granted, 381562306a36Sopenharmony_ci la), 381662306a36Sopenharmony_ci bf_get(lpfc_mbx_read_top_link_spd, la), 381762306a36Sopenharmony_ci phba->alpa_map[0], 381862306a36Sopenharmony_ci bf_get(lpfc_mbx_read_top_fa, la)); 381962306a36Sopenharmony_ci } 382062306a36Sopenharmony_ci lpfc_mbx_process_link_up(phba, la); 382162306a36Sopenharmony_ci 382262306a36Sopenharmony_ci if (phba->cmf_active_mode != LPFC_CFG_OFF) 382362306a36Sopenharmony_ci lpfc_cmf_signal_init(phba); 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci if (phba->lmt & LMT_64Gb) 382662306a36Sopenharmony_ci lpfc_read_lds_params(phba); 382762306a36Sopenharmony_ci 382862306a36Sopenharmony_ci } else if (attn_type == LPFC_ATT_LINK_DOWN || 382962306a36Sopenharmony_ci attn_type == LPFC_ATT_UNEXP_WWPN) { 383062306a36Sopenharmony_ci phba->fc_stat.LinkDown++; 383162306a36Sopenharmony_ci if (phba->link_flag & LS_LOOPBACK_MODE) 383262306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, 383362306a36Sopenharmony_ci "1308 Link Down Event in loop back mode " 383462306a36Sopenharmony_ci "x%x received " 383562306a36Sopenharmony_ci "Data: x%x x%x x%x\n", 383662306a36Sopenharmony_ci la->eventTag, phba->fc_eventTag, 383762306a36Sopenharmony_ci phba->pport->port_state, vport->fc_flag); 383862306a36Sopenharmony_ci else if (attn_type == LPFC_ATT_UNEXP_WWPN) 383962306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, 384062306a36Sopenharmony_ci "1313 Link Down Unexpected FA WWPN Event x%x " 384162306a36Sopenharmony_ci "received Data: x%x x%x x%x x%x\n", 384262306a36Sopenharmony_ci la->eventTag, phba->fc_eventTag, 384362306a36Sopenharmony_ci phba->pport->port_state, vport->fc_flag, 384462306a36Sopenharmony_ci bf_get(lpfc_mbx_read_top_fa, la)); 384562306a36Sopenharmony_ci else 384662306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, 384762306a36Sopenharmony_ci "1305 Link Down Event x%x received " 384862306a36Sopenharmony_ci "Data: x%x x%x x%x x%x\n", 384962306a36Sopenharmony_ci la->eventTag, phba->fc_eventTag, 385062306a36Sopenharmony_ci phba->pport->port_state, vport->fc_flag, 385162306a36Sopenharmony_ci bf_get(lpfc_mbx_read_top_fa, la)); 385262306a36Sopenharmony_ci lpfc_mbx_issue_link_down(phba); 385362306a36Sopenharmony_ci } 385462306a36Sopenharmony_ci 385562306a36Sopenharmony_ci if ((phba->sli_rev < LPFC_SLI_REV4) && 385662306a36Sopenharmony_ci bf_get(lpfc_mbx_read_top_fa, la)) 385762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, 385862306a36Sopenharmony_ci "1311 fa %d\n", 385962306a36Sopenharmony_ci bf_get(lpfc_mbx_read_top_fa, la)); 386062306a36Sopenharmony_ci 386162306a36Sopenharmony_cilpfc_mbx_cmpl_read_topology_free_mbuf: 386262306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); 386362306a36Sopenharmony_ci} 386462306a36Sopenharmony_ci 386562306a36Sopenharmony_ci/* 386662306a36Sopenharmony_ci * This routine handles processing a REG_LOGIN mailbox 386762306a36Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ 386862306a36Sopenharmony_ci * as the completion routine when the command is 386962306a36Sopenharmony_ci * handed off to the SLI layer. 387062306a36Sopenharmony_ci */ 387162306a36Sopenharmony_civoid 387262306a36Sopenharmony_cilpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) 387362306a36Sopenharmony_ci{ 387462306a36Sopenharmony_ci struct lpfc_vport *vport = pmb->vport; 387562306a36Sopenharmony_ci struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)pmb->ctx_buf; 387662306a36Sopenharmony_ci struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; 387762306a36Sopenharmony_ci 387862306a36Sopenharmony_ci /* The driver calls the state machine with the pmb pointer 387962306a36Sopenharmony_ci * but wants to make sure a stale ctx_buf isn't acted on. 388062306a36Sopenharmony_ci * The ctx_buf is restored later and cleaned up. 388162306a36Sopenharmony_ci */ 388262306a36Sopenharmony_ci pmb->ctx_buf = NULL; 388362306a36Sopenharmony_ci pmb->ctx_ndlp = NULL; 388462306a36Sopenharmony_ci 388562306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI | LOG_NODE | LOG_DISCOVERY, 388662306a36Sopenharmony_ci "0002 rpi:%x DID:%x flg:%x %d x%px\n", 388762306a36Sopenharmony_ci ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, 388862306a36Sopenharmony_ci kref_read(&ndlp->kref), 388962306a36Sopenharmony_ci ndlp); 389062306a36Sopenharmony_ci if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) 389162306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; 389262306a36Sopenharmony_ci 389362306a36Sopenharmony_ci if (ndlp->nlp_flag & NLP_IGNR_REG_CMPL || 389462306a36Sopenharmony_ci ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) { 389562306a36Sopenharmony_ci /* We rcvd a rscn after issuing this 389662306a36Sopenharmony_ci * mbox reg login, we may have cycled 389762306a36Sopenharmony_ci * back through the state and be 389862306a36Sopenharmony_ci * back at reg login state so this 389962306a36Sopenharmony_ci * mbox needs to be ignored becase 390062306a36Sopenharmony_ci * there is another reg login in 390162306a36Sopenharmony_ci * process. 390262306a36Sopenharmony_ci */ 390362306a36Sopenharmony_ci spin_lock_irq(&ndlp->lock); 390462306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; 390562306a36Sopenharmony_ci spin_unlock_irq(&ndlp->lock); 390662306a36Sopenharmony_ci 390762306a36Sopenharmony_ci /* 390862306a36Sopenharmony_ci * We cannot leave the RPI registered because 390962306a36Sopenharmony_ci * if we go thru discovery again for this ndlp 391062306a36Sopenharmony_ci * a subsequent REG_RPI will fail. 391162306a36Sopenharmony_ci */ 391262306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_RPI_REGISTERED; 391362306a36Sopenharmony_ci lpfc_unreg_rpi(vport, ndlp); 391462306a36Sopenharmony_ci } 391562306a36Sopenharmony_ci 391662306a36Sopenharmony_ci /* Call state machine */ 391762306a36Sopenharmony_ci lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN); 391862306a36Sopenharmony_ci pmb->ctx_buf = mp; 391962306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); 392062306a36Sopenharmony_ci 392162306a36Sopenharmony_ci /* decrement the node reference count held for this callback 392262306a36Sopenharmony_ci * function. 392362306a36Sopenharmony_ci */ 392462306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 392562306a36Sopenharmony_ci 392662306a36Sopenharmony_ci return; 392762306a36Sopenharmony_ci} 392862306a36Sopenharmony_ci 392962306a36Sopenharmony_cistatic void 393062306a36Sopenharmony_cilpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) 393162306a36Sopenharmony_ci{ 393262306a36Sopenharmony_ci MAILBOX_t *mb = &pmb->u.mb; 393362306a36Sopenharmony_ci struct lpfc_vport *vport = pmb->vport; 393462306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci switch (mb->mbxStatus) { 393762306a36Sopenharmony_ci case 0x0011: 393862306a36Sopenharmony_ci case 0x0020: 393962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 394062306a36Sopenharmony_ci "0911 cmpl_unreg_vpi, mb status = 0x%x\n", 394162306a36Sopenharmony_ci mb->mbxStatus); 394262306a36Sopenharmony_ci break; 394362306a36Sopenharmony_ci /* If VPI is busy, reset the HBA */ 394462306a36Sopenharmony_ci case 0x9700: 394562306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 394662306a36Sopenharmony_ci "2798 Unreg_vpi failed vpi 0x%x, mb status = 0x%x\n", 394762306a36Sopenharmony_ci vport->vpi, mb->mbxStatus); 394862306a36Sopenharmony_ci if (!(phba->pport->load_flag & FC_UNLOADING)) 394962306a36Sopenharmony_ci lpfc_workq_post_event(phba, NULL, NULL, 395062306a36Sopenharmony_ci LPFC_EVT_RESET_HBA); 395162306a36Sopenharmony_ci } 395262306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 395362306a36Sopenharmony_ci vport->vpi_state &= ~LPFC_VPI_REGISTERED; 395462306a36Sopenharmony_ci vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; 395562306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 395662306a36Sopenharmony_ci mempool_free(pmb, phba->mbox_mem_pool); 395762306a36Sopenharmony_ci lpfc_cleanup_vports_rrqs(vport, NULL); 395862306a36Sopenharmony_ci /* 395962306a36Sopenharmony_ci * This shost reference might have been taken at the beginning of 396062306a36Sopenharmony_ci * lpfc_vport_delete() 396162306a36Sopenharmony_ci */ 396262306a36Sopenharmony_ci if ((vport->load_flag & FC_UNLOADING) && (vport != phba->pport)) 396362306a36Sopenharmony_ci scsi_host_put(shost); 396462306a36Sopenharmony_ci} 396562306a36Sopenharmony_ci 396662306a36Sopenharmony_ciint 396762306a36Sopenharmony_cilpfc_mbx_unreg_vpi(struct lpfc_vport *vport) 396862306a36Sopenharmony_ci{ 396962306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 397062306a36Sopenharmony_ci LPFC_MBOXQ_t *mbox; 397162306a36Sopenharmony_ci int rc; 397262306a36Sopenharmony_ci 397362306a36Sopenharmony_ci mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 397462306a36Sopenharmony_ci if (!mbox) 397562306a36Sopenharmony_ci return 1; 397662306a36Sopenharmony_ci 397762306a36Sopenharmony_ci lpfc_unreg_vpi(phba, vport->vpi, mbox); 397862306a36Sopenharmony_ci mbox->vport = vport; 397962306a36Sopenharmony_ci mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi; 398062306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); 398162306a36Sopenharmony_ci if (rc == MBX_NOT_FINISHED) { 398262306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 398362306a36Sopenharmony_ci "1800 Could not issue unreg_vpi\n"); 398462306a36Sopenharmony_ci mempool_free(mbox, phba->mbox_mem_pool); 398562306a36Sopenharmony_ci return rc; 398662306a36Sopenharmony_ci } 398762306a36Sopenharmony_ci return 0; 398862306a36Sopenharmony_ci} 398962306a36Sopenharmony_ci 399062306a36Sopenharmony_cistatic void 399162306a36Sopenharmony_cilpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) 399262306a36Sopenharmony_ci{ 399362306a36Sopenharmony_ci struct lpfc_vport *vport = pmb->vport; 399462306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 399562306a36Sopenharmony_ci MAILBOX_t *mb = &pmb->u.mb; 399662306a36Sopenharmony_ci 399762306a36Sopenharmony_ci switch (mb->mbxStatus) { 399862306a36Sopenharmony_ci case 0x0011: 399962306a36Sopenharmony_ci case 0x9601: 400062306a36Sopenharmony_ci case 0x9602: 400162306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 400262306a36Sopenharmony_ci "0912 cmpl_reg_vpi, mb status = 0x%x\n", 400362306a36Sopenharmony_ci mb->mbxStatus); 400462306a36Sopenharmony_ci lpfc_vport_set_state(vport, FC_VPORT_FAILED); 400562306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 400662306a36Sopenharmony_ci vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); 400762306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 400862306a36Sopenharmony_ci vport->fc_myDID = 0; 400962306a36Sopenharmony_ci 401062306a36Sopenharmony_ci if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || 401162306a36Sopenharmony_ci (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) { 401262306a36Sopenharmony_ci if (phba->nvmet_support) 401362306a36Sopenharmony_ci lpfc_nvmet_update_targetport(phba); 401462306a36Sopenharmony_ci else 401562306a36Sopenharmony_ci lpfc_nvme_update_localport(vport); 401662306a36Sopenharmony_ci } 401762306a36Sopenharmony_ci goto out; 401862306a36Sopenharmony_ci } 401962306a36Sopenharmony_ci 402062306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 402162306a36Sopenharmony_ci vport->vpi_state |= LPFC_VPI_REGISTERED; 402262306a36Sopenharmony_ci vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; 402362306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 402462306a36Sopenharmony_ci vport->num_disc_nodes = 0; 402562306a36Sopenharmony_ci /* go thru NPR list and issue ELS PLOGIs */ 402662306a36Sopenharmony_ci if (vport->fc_npr_cnt) 402762306a36Sopenharmony_ci lpfc_els_disc_plogi(vport); 402862306a36Sopenharmony_ci 402962306a36Sopenharmony_ci if (!vport->num_disc_nodes) { 403062306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 403162306a36Sopenharmony_ci vport->fc_flag &= ~FC_NDISC_ACTIVE; 403262306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 403362306a36Sopenharmony_ci lpfc_can_disctmo(vport); 403462306a36Sopenharmony_ci } 403562306a36Sopenharmony_ci vport->port_state = LPFC_VPORT_READY; 403662306a36Sopenharmony_ci 403762306a36Sopenharmony_ciout: 403862306a36Sopenharmony_ci mempool_free(pmb, phba->mbox_mem_pool); 403962306a36Sopenharmony_ci return; 404062306a36Sopenharmony_ci} 404162306a36Sopenharmony_ci 404262306a36Sopenharmony_ci/** 404362306a36Sopenharmony_ci * lpfc_create_static_vport - Read HBA config region to create static vports. 404462306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 404562306a36Sopenharmony_ci * 404662306a36Sopenharmony_ci * This routine issue a DUMP mailbox command for config region 22 to get 404762306a36Sopenharmony_ci * the list of static vports to be created. The function create vports 404862306a36Sopenharmony_ci * based on the information returned from the HBA. 404962306a36Sopenharmony_ci **/ 405062306a36Sopenharmony_civoid 405162306a36Sopenharmony_cilpfc_create_static_vport(struct lpfc_hba *phba) 405262306a36Sopenharmony_ci{ 405362306a36Sopenharmony_ci LPFC_MBOXQ_t *pmb = NULL; 405462306a36Sopenharmony_ci MAILBOX_t *mb; 405562306a36Sopenharmony_ci struct static_vport_info *vport_info; 405662306a36Sopenharmony_ci int mbx_wait_rc = 0, i; 405762306a36Sopenharmony_ci struct fc_vport_identifiers vport_id; 405862306a36Sopenharmony_ci struct fc_vport *new_fc_vport; 405962306a36Sopenharmony_ci struct Scsi_Host *shost; 406062306a36Sopenharmony_ci struct lpfc_vport *vport; 406162306a36Sopenharmony_ci uint16_t offset = 0; 406262306a36Sopenharmony_ci uint8_t *vport_buff; 406362306a36Sopenharmony_ci struct lpfc_dmabuf *mp; 406462306a36Sopenharmony_ci uint32_t byte_count = 0; 406562306a36Sopenharmony_ci 406662306a36Sopenharmony_ci pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 406762306a36Sopenharmony_ci if (!pmb) { 406862306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 406962306a36Sopenharmony_ci "0542 lpfc_create_static_vport failed to" 407062306a36Sopenharmony_ci " allocate mailbox memory\n"); 407162306a36Sopenharmony_ci return; 407262306a36Sopenharmony_ci } 407362306a36Sopenharmony_ci memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); 407462306a36Sopenharmony_ci mb = &pmb->u.mb; 407562306a36Sopenharmony_ci 407662306a36Sopenharmony_ci vport_info = kzalloc(sizeof(struct static_vport_info), GFP_KERNEL); 407762306a36Sopenharmony_ci if (!vport_info) { 407862306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 407962306a36Sopenharmony_ci "0543 lpfc_create_static_vport failed to" 408062306a36Sopenharmony_ci " allocate vport_info\n"); 408162306a36Sopenharmony_ci mempool_free(pmb, phba->mbox_mem_pool); 408262306a36Sopenharmony_ci return; 408362306a36Sopenharmony_ci } 408462306a36Sopenharmony_ci 408562306a36Sopenharmony_ci vport_buff = (uint8_t *) vport_info; 408662306a36Sopenharmony_ci do { 408762306a36Sopenharmony_ci /* While loop iteration forces a free dma buffer from 408862306a36Sopenharmony_ci * the previous loop because the mbox is reused and 408962306a36Sopenharmony_ci * the dump routine is a single-use construct. 409062306a36Sopenharmony_ci */ 409162306a36Sopenharmony_ci if (pmb->ctx_buf) { 409262306a36Sopenharmony_ci mp = (struct lpfc_dmabuf *)pmb->ctx_buf; 409362306a36Sopenharmony_ci lpfc_mbuf_free(phba, mp->virt, mp->phys); 409462306a36Sopenharmony_ci kfree(mp); 409562306a36Sopenharmony_ci pmb->ctx_buf = NULL; 409662306a36Sopenharmony_ci } 409762306a36Sopenharmony_ci if (lpfc_dump_static_vport(phba, pmb, offset)) 409862306a36Sopenharmony_ci goto out; 409962306a36Sopenharmony_ci 410062306a36Sopenharmony_ci pmb->vport = phba->pport; 410162306a36Sopenharmony_ci mbx_wait_rc = lpfc_sli_issue_mbox_wait(phba, pmb, 410262306a36Sopenharmony_ci LPFC_MBOX_TMO); 410362306a36Sopenharmony_ci 410462306a36Sopenharmony_ci if ((mbx_wait_rc != MBX_SUCCESS) || mb->mbxStatus) { 410562306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, 410662306a36Sopenharmony_ci "0544 lpfc_create_static_vport failed to" 410762306a36Sopenharmony_ci " issue dump mailbox command ret 0x%x " 410862306a36Sopenharmony_ci "status 0x%x\n", 410962306a36Sopenharmony_ci mbx_wait_rc, mb->mbxStatus); 411062306a36Sopenharmony_ci goto out; 411162306a36Sopenharmony_ci } 411262306a36Sopenharmony_ci 411362306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4) { 411462306a36Sopenharmony_ci byte_count = pmb->u.mqe.un.mb_words[5]; 411562306a36Sopenharmony_ci mp = (struct lpfc_dmabuf *)pmb->ctx_buf; 411662306a36Sopenharmony_ci if (byte_count > sizeof(struct static_vport_info) - 411762306a36Sopenharmony_ci offset) 411862306a36Sopenharmony_ci byte_count = sizeof(struct static_vport_info) 411962306a36Sopenharmony_ci - offset; 412062306a36Sopenharmony_ci memcpy(vport_buff + offset, mp->virt, byte_count); 412162306a36Sopenharmony_ci offset += byte_count; 412262306a36Sopenharmony_ci } else { 412362306a36Sopenharmony_ci if (mb->un.varDmp.word_cnt > 412462306a36Sopenharmony_ci sizeof(struct static_vport_info) - offset) 412562306a36Sopenharmony_ci mb->un.varDmp.word_cnt = 412662306a36Sopenharmony_ci sizeof(struct static_vport_info) 412762306a36Sopenharmony_ci - offset; 412862306a36Sopenharmony_ci byte_count = mb->un.varDmp.word_cnt; 412962306a36Sopenharmony_ci lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, 413062306a36Sopenharmony_ci vport_buff + offset, 413162306a36Sopenharmony_ci byte_count); 413262306a36Sopenharmony_ci 413362306a36Sopenharmony_ci offset += byte_count; 413462306a36Sopenharmony_ci } 413562306a36Sopenharmony_ci 413662306a36Sopenharmony_ci } while (byte_count && 413762306a36Sopenharmony_ci offset < sizeof(struct static_vport_info)); 413862306a36Sopenharmony_ci 413962306a36Sopenharmony_ci 414062306a36Sopenharmony_ci if ((le32_to_cpu(vport_info->signature) != VPORT_INFO_SIG) || 414162306a36Sopenharmony_ci ((le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK) 414262306a36Sopenharmony_ci != VPORT_INFO_REV)) { 414362306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 414462306a36Sopenharmony_ci "0545 lpfc_create_static_vport bad" 414562306a36Sopenharmony_ci " information header 0x%x 0x%x\n", 414662306a36Sopenharmony_ci le32_to_cpu(vport_info->signature), 414762306a36Sopenharmony_ci le32_to_cpu(vport_info->rev) & 414862306a36Sopenharmony_ci VPORT_INFO_REV_MASK); 414962306a36Sopenharmony_ci 415062306a36Sopenharmony_ci goto out; 415162306a36Sopenharmony_ci } 415262306a36Sopenharmony_ci 415362306a36Sopenharmony_ci shost = lpfc_shost_from_vport(phba->pport); 415462306a36Sopenharmony_ci 415562306a36Sopenharmony_ci for (i = 0; i < MAX_STATIC_VPORT_COUNT; i++) { 415662306a36Sopenharmony_ci memset(&vport_id, 0, sizeof(vport_id)); 415762306a36Sopenharmony_ci vport_id.port_name = wwn_to_u64(vport_info->vport_list[i].wwpn); 415862306a36Sopenharmony_ci vport_id.node_name = wwn_to_u64(vport_info->vport_list[i].wwnn); 415962306a36Sopenharmony_ci if (!vport_id.port_name || !vport_id.node_name) 416062306a36Sopenharmony_ci continue; 416162306a36Sopenharmony_ci 416262306a36Sopenharmony_ci vport_id.roles = FC_PORT_ROLE_FCP_INITIATOR; 416362306a36Sopenharmony_ci vport_id.vport_type = FC_PORTTYPE_NPIV; 416462306a36Sopenharmony_ci vport_id.disable = false; 416562306a36Sopenharmony_ci new_fc_vport = fc_vport_create(shost, 0, &vport_id); 416662306a36Sopenharmony_ci 416762306a36Sopenharmony_ci if (!new_fc_vport) { 416862306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, 416962306a36Sopenharmony_ci "0546 lpfc_create_static_vport failed to" 417062306a36Sopenharmony_ci " create vport\n"); 417162306a36Sopenharmony_ci continue; 417262306a36Sopenharmony_ci } 417362306a36Sopenharmony_ci 417462306a36Sopenharmony_ci vport = *(struct lpfc_vport **)new_fc_vport->dd_data; 417562306a36Sopenharmony_ci vport->vport_flag |= STATIC_VPORT; 417662306a36Sopenharmony_ci } 417762306a36Sopenharmony_ci 417862306a36Sopenharmony_ciout: 417962306a36Sopenharmony_ci kfree(vport_info); 418062306a36Sopenharmony_ci if (mbx_wait_rc != MBX_TIMEOUT) 418162306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); 418262306a36Sopenharmony_ci} 418362306a36Sopenharmony_ci 418462306a36Sopenharmony_ci/* 418562306a36Sopenharmony_ci * This routine handles processing a Fabric REG_LOGIN mailbox 418662306a36Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ 418762306a36Sopenharmony_ci * as the completion routine when the command is 418862306a36Sopenharmony_ci * handed off to the SLI layer. 418962306a36Sopenharmony_ci */ 419062306a36Sopenharmony_civoid 419162306a36Sopenharmony_cilpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) 419262306a36Sopenharmony_ci{ 419362306a36Sopenharmony_ci struct lpfc_vport *vport = pmb->vport; 419462306a36Sopenharmony_ci MAILBOX_t *mb = &pmb->u.mb; 419562306a36Sopenharmony_ci struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; 419662306a36Sopenharmony_ci struct Scsi_Host *shost; 419762306a36Sopenharmony_ci 419862306a36Sopenharmony_ci pmb->ctx_ndlp = NULL; 419962306a36Sopenharmony_ci 420062306a36Sopenharmony_ci if (mb->mbxStatus) { 420162306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 420262306a36Sopenharmony_ci "0258 Register Fabric login error: 0x%x\n", 420362306a36Sopenharmony_ci mb->mbxStatus); 420462306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); 420562306a36Sopenharmony_ci if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { 420662306a36Sopenharmony_ci /* FLOGI failed, use loop map to make discovery list */ 420762306a36Sopenharmony_ci lpfc_disc_list_loopmap(vport); 420862306a36Sopenharmony_ci 420962306a36Sopenharmony_ci /* Start discovery */ 421062306a36Sopenharmony_ci lpfc_disc_start(vport); 421162306a36Sopenharmony_ci /* Decrement the reference count to ndlp after the 421262306a36Sopenharmony_ci * reference to the ndlp are done. 421362306a36Sopenharmony_ci */ 421462306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 421562306a36Sopenharmony_ci return; 421662306a36Sopenharmony_ci } 421762306a36Sopenharmony_ci 421862306a36Sopenharmony_ci lpfc_vport_set_state(vport, FC_VPORT_FAILED); 421962306a36Sopenharmony_ci /* Decrement the reference count to ndlp after the reference 422062306a36Sopenharmony_ci * to the ndlp are done. 422162306a36Sopenharmony_ci */ 422262306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 422362306a36Sopenharmony_ci return; 422462306a36Sopenharmony_ci } 422562306a36Sopenharmony_ci 422662306a36Sopenharmony_ci if (phba->sli_rev < LPFC_SLI_REV4) 422762306a36Sopenharmony_ci ndlp->nlp_rpi = mb->un.varWords[0]; 422862306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_RPI_REGISTERED; 422962306a36Sopenharmony_ci ndlp->nlp_type |= NLP_FABRIC; 423062306a36Sopenharmony_ci lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); 423162306a36Sopenharmony_ci 423262306a36Sopenharmony_ci if (vport->port_state == LPFC_FABRIC_CFG_LINK) { 423362306a36Sopenharmony_ci /* when physical port receive logo donot start 423462306a36Sopenharmony_ci * vport discovery */ 423562306a36Sopenharmony_ci if (!(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG)) 423662306a36Sopenharmony_ci lpfc_start_fdiscs(phba); 423762306a36Sopenharmony_ci else { 423862306a36Sopenharmony_ci shost = lpfc_shost_from_vport(vport); 423962306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 424062306a36Sopenharmony_ci vport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG ; 424162306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 424262306a36Sopenharmony_ci } 424362306a36Sopenharmony_ci lpfc_do_scr_ns_plogi(phba, vport); 424462306a36Sopenharmony_ci } 424562306a36Sopenharmony_ci 424662306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); 424762306a36Sopenharmony_ci 424862306a36Sopenharmony_ci /* Drop the reference count from the mbox at the end after 424962306a36Sopenharmony_ci * all the current reference to the ndlp have been done. 425062306a36Sopenharmony_ci */ 425162306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 425262306a36Sopenharmony_ci return; 425362306a36Sopenharmony_ci} 425462306a36Sopenharmony_ci 425562306a36Sopenharmony_ci /* 425662306a36Sopenharmony_ci * This routine will issue a GID_FT for each FC4 Type supported 425762306a36Sopenharmony_ci * by the driver. ALL GID_FTs must complete before discovery is started. 425862306a36Sopenharmony_ci */ 425962306a36Sopenharmony_ciint 426062306a36Sopenharmony_cilpfc_issue_gidft(struct lpfc_vport *vport) 426162306a36Sopenharmony_ci{ 426262306a36Sopenharmony_ci /* Good status, issue CT Request to NameServer */ 426362306a36Sopenharmony_ci if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || 426462306a36Sopenharmony_ci (vport->cfg_enable_fc4_type == LPFC_ENABLE_FCP)) { 426562306a36Sopenharmony_ci if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, SLI_CTPT_FCP)) { 426662306a36Sopenharmony_ci /* Cannot issue NameServer FCP Query, so finish up 426762306a36Sopenharmony_ci * discovery 426862306a36Sopenharmony_ci */ 426962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 427062306a36Sopenharmony_ci LOG_TRACE_EVENT, 427162306a36Sopenharmony_ci "0604 %s FC TYPE %x %s\n", 427262306a36Sopenharmony_ci "Failed to issue GID_FT to ", 427362306a36Sopenharmony_ci FC_TYPE_FCP, 427462306a36Sopenharmony_ci "Finishing discovery."); 427562306a36Sopenharmony_ci return 0; 427662306a36Sopenharmony_ci } 427762306a36Sopenharmony_ci vport->gidft_inp++; 427862306a36Sopenharmony_ci } 427962306a36Sopenharmony_ci 428062306a36Sopenharmony_ci if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || 428162306a36Sopenharmony_ci (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) { 428262306a36Sopenharmony_ci if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, SLI_CTPT_NVME)) { 428362306a36Sopenharmony_ci /* Cannot issue NameServer NVME Query, so finish up 428462306a36Sopenharmony_ci * discovery 428562306a36Sopenharmony_ci */ 428662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 428762306a36Sopenharmony_ci LOG_TRACE_EVENT, 428862306a36Sopenharmony_ci "0605 %s FC_TYPE %x %s %d\n", 428962306a36Sopenharmony_ci "Failed to issue GID_FT to ", 429062306a36Sopenharmony_ci FC_TYPE_NVME, 429162306a36Sopenharmony_ci "Finishing discovery: gidftinp ", 429262306a36Sopenharmony_ci vport->gidft_inp); 429362306a36Sopenharmony_ci if (vport->gidft_inp == 0) 429462306a36Sopenharmony_ci return 0; 429562306a36Sopenharmony_ci } else 429662306a36Sopenharmony_ci vport->gidft_inp++; 429762306a36Sopenharmony_ci } 429862306a36Sopenharmony_ci return vport->gidft_inp; 429962306a36Sopenharmony_ci} 430062306a36Sopenharmony_ci 430162306a36Sopenharmony_ci/** 430262306a36Sopenharmony_ci * lpfc_issue_gidpt - issue a GID_PT for all N_Ports 430362306a36Sopenharmony_ci * @vport: The virtual port for which this call is being executed. 430462306a36Sopenharmony_ci * 430562306a36Sopenharmony_ci * This routine will issue a GID_PT to get a list of all N_Ports 430662306a36Sopenharmony_ci * 430762306a36Sopenharmony_ci * Return value : 430862306a36Sopenharmony_ci * 0 - Failure to issue a GID_PT 430962306a36Sopenharmony_ci * 1 - GID_PT issued 431062306a36Sopenharmony_ci **/ 431162306a36Sopenharmony_ciint 431262306a36Sopenharmony_cilpfc_issue_gidpt(struct lpfc_vport *vport) 431362306a36Sopenharmony_ci{ 431462306a36Sopenharmony_ci /* Good status, issue CT Request to NameServer */ 431562306a36Sopenharmony_ci if (lpfc_ns_cmd(vport, SLI_CTNS_GID_PT, 0, GID_PT_N_PORT)) { 431662306a36Sopenharmony_ci /* Cannot issue NameServer FCP Query, so finish up 431762306a36Sopenharmony_ci * discovery 431862306a36Sopenharmony_ci */ 431962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 432062306a36Sopenharmony_ci "0606 %s Port TYPE %x %s\n", 432162306a36Sopenharmony_ci "Failed to issue GID_PT to ", 432262306a36Sopenharmony_ci GID_PT_N_PORT, 432362306a36Sopenharmony_ci "Finishing discovery."); 432462306a36Sopenharmony_ci return 0; 432562306a36Sopenharmony_ci } 432662306a36Sopenharmony_ci vport->gidft_inp++; 432762306a36Sopenharmony_ci return 1; 432862306a36Sopenharmony_ci} 432962306a36Sopenharmony_ci 433062306a36Sopenharmony_ci/* 433162306a36Sopenharmony_ci * This routine handles processing a NameServer REG_LOGIN mailbox 433262306a36Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ 433362306a36Sopenharmony_ci * as the completion routine when the command is 433462306a36Sopenharmony_ci * handed off to the SLI layer. 433562306a36Sopenharmony_ci */ 433662306a36Sopenharmony_civoid 433762306a36Sopenharmony_cilpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) 433862306a36Sopenharmony_ci{ 433962306a36Sopenharmony_ci MAILBOX_t *mb = &pmb->u.mb; 434062306a36Sopenharmony_ci struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; 434162306a36Sopenharmony_ci struct lpfc_vport *vport = pmb->vport; 434262306a36Sopenharmony_ci int rc; 434362306a36Sopenharmony_ci 434462306a36Sopenharmony_ci pmb->ctx_ndlp = NULL; 434562306a36Sopenharmony_ci vport->gidft_inp = 0; 434662306a36Sopenharmony_ci 434762306a36Sopenharmony_ci if (mb->mbxStatus) { 434862306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 434962306a36Sopenharmony_ci "0260 Register NameServer error: 0x%x\n", 435062306a36Sopenharmony_ci mb->mbxStatus); 435162306a36Sopenharmony_ci 435262306a36Sopenharmony_ciout: 435362306a36Sopenharmony_ci /* decrement the node reference count held for this 435462306a36Sopenharmony_ci * callback function. 435562306a36Sopenharmony_ci */ 435662306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 435762306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); 435862306a36Sopenharmony_ci 435962306a36Sopenharmony_ci /* If the node is not registered with the scsi or nvme 436062306a36Sopenharmony_ci * transport, remove the fabric node. The failed reg_login 436162306a36Sopenharmony_ci * is terminal and forces the removal of the last node 436262306a36Sopenharmony_ci * reference. 436362306a36Sopenharmony_ci */ 436462306a36Sopenharmony_ci if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { 436562306a36Sopenharmony_ci spin_lock_irq(&ndlp->lock); 436662306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; 436762306a36Sopenharmony_ci spin_unlock_irq(&ndlp->lock); 436862306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 436962306a36Sopenharmony_ci } 437062306a36Sopenharmony_ci 437162306a36Sopenharmony_ci if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { 437262306a36Sopenharmony_ci /* 437362306a36Sopenharmony_ci * RegLogin failed, use loop map to make discovery 437462306a36Sopenharmony_ci * list 437562306a36Sopenharmony_ci */ 437662306a36Sopenharmony_ci lpfc_disc_list_loopmap(vport); 437762306a36Sopenharmony_ci 437862306a36Sopenharmony_ci /* Start discovery */ 437962306a36Sopenharmony_ci lpfc_disc_start(vport); 438062306a36Sopenharmony_ci return; 438162306a36Sopenharmony_ci } 438262306a36Sopenharmony_ci lpfc_vport_set_state(vport, FC_VPORT_FAILED); 438362306a36Sopenharmony_ci return; 438462306a36Sopenharmony_ci } 438562306a36Sopenharmony_ci 438662306a36Sopenharmony_ci if (phba->sli_rev < LPFC_SLI_REV4) 438762306a36Sopenharmony_ci ndlp->nlp_rpi = mb->un.varWords[0]; 438862306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_RPI_REGISTERED; 438962306a36Sopenharmony_ci ndlp->nlp_type |= NLP_FABRIC; 439062306a36Sopenharmony_ci lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); 439162306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, 439262306a36Sopenharmony_ci "0003 rpi:%x DID:%x flg:%x %d x%px\n", 439362306a36Sopenharmony_ci ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, 439462306a36Sopenharmony_ci kref_read(&ndlp->kref), 439562306a36Sopenharmony_ci ndlp); 439662306a36Sopenharmony_ci 439762306a36Sopenharmony_ci if (vport->port_state < LPFC_VPORT_READY) { 439862306a36Sopenharmony_ci /* Link up discovery requires Fabric registration. */ 439962306a36Sopenharmony_ci lpfc_ns_cmd(vport, SLI_CTNS_RNN_ID, 0, 0); 440062306a36Sopenharmony_ci lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0); 440162306a36Sopenharmony_ci lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0); 440262306a36Sopenharmony_ci lpfc_ns_cmd(vport, SLI_CTNS_RFT_ID, 0, 0); 440362306a36Sopenharmony_ci 440462306a36Sopenharmony_ci if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || 440562306a36Sopenharmony_ci (vport->cfg_enable_fc4_type == LPFC_ENABLE_FCP)) 440662306a36Sopenharmony_ci lpfc_ns_cmd(vport, SLI_CTNS_RFF_ID, 0, FC_TYPE_FCP); 440762306a36Sopenharmony_ci 440862306a36Sopenharmony_ci if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || 440962306a36Sopenharmony_ci (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) 441062306a36Sopenharmony_ci lpfc_ns_cmd(vport, SLI_CTNS_RFF_ID, 0, 441162306a36Sopenharmony_ci FC_TYPE_NVME); 441262306a36Sopenharmony_ci 441362306a36Sopenharmony_ci /* Issue SCR just before NameServer GID_FT Query */ 441462306a36Sopenharmony_ci lpfc_issue_els_scr(vport, 0); 441562306a36Sopenharmony_ci 441662306a36Sopenharmony_ci /* Link was bounced or a Fabric LOGO occurred. Start EDC 441762306a36Sopenharmony_ci * with initial FW values provided the congestion mode is 441862306a36Sopenharmony_ci * not off. Note that signals may or may not be supported 441962306a36Sopenharmony_ci * by the adapter but FPIN is provided by default for 1 442062306a36Sopenharmony_ci * or both missing signals support. 442162306a36Sopenharmony_ci */ 442262306a36Sopenharmony_ci if (phba->cmf_active_mode != LPFC_CFG_OFF) { 442362306a36Sopenharmony_ci phba->cgn_reg_fpin = phba->cgn_init_reg_fpin; 442462306a36Sopenharmony_ci phba->cgn_reg_signal = phba->cgn_init_reg_signal; 442562306a36Sopenharmony_ci rc = lpfc_issue_els_edc(vport, 0); 442662306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, 442762306a36Sopenharmony_ci LOG_INIT | LOG_ELS | LOG_DISCOVERY, 442862306a36Sopenharmony_ci "4220 Issue EDC status x%x Data x%x\n", 442962306a36Sopenharmony_ci rc, phba->cgn_init_reg_signal); 443062306a36Sopenharmony_ci } else if (phba->lmt & LMT_64Gb) { 443162306a36Sopenharmony_ci /* may send link fault capability descriptor */ 443262306a36Sopenharmony_ci lpfc_issue_els_edc(vport, 0); 443362306a36Sopenharmony_ci } else { 443462306a36Sopenharmony_ci lpfc_issue_els_rdf(vport, 0); 443562306a36Sopenharmony_ci } 443662306a36Sopenharmony_ci } 443762306a36Sopenharmony_ci 443862306a36Sopenharmony_ci vport->fc_ns_retry = 0; 443962306a36Sopenharmony_ci if (lpfc_issue_gidft(vport) == 0) 444062306a36Sopenharmony_ci goto out; 444162306a36Sopenharmony_ci 444262306a36Sopenharmony_ci /* 444362306a36Sopenharmony_ci * At this point in time we may need to wait for multiple 444462306a36Sopenharmony_ci * SLI_CTNS_GID_FT CT commands to complete before we start discovery. 444562306a36Sopenharmony_ci * 444662306a36Sopenharmony_ci * decrement the node reference count held for this 444762306a36Sopenharmony_ci * callback function. 444862306a36Sopenharmony_ci */ 444962306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 445062306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); 445162306a36Sopenharmony_ci return; 445262306a36Sopenharmony_ci} 445362306a36Sopenharmony_ci 445462306a36Sopenharmony_ci/* 445562306a36Sopenharmony_ci * This routine handles processing a Fabric Controller REG_LOGIN mailbox 445662306a36Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ 445762306a36Sopenharmony_ci * as the completion routine when the command is handed off to the SLI layer. 445862306a36Sopenharmony_ci */ 445962306a36Sopenharmony_civoid 446062306a36Sopenharmony_cilpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) 446162306a36Sopenharmony_ci{ 446262306a36Sopenharmony_ci struct lpfc_vport *vport = pmb->vport; 446362306a36Sopenharmony_ci MAILBOX_t *mb = &pmb->u.mb; 446462306a36Sopenharmony_ci struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; 446562306a36Sopenharmony_ci 446662306a36Sopenharmony_ci pmb->ctx_ndlp = NULL; 446762306a36Sopenharmony_ci if (mb->mbxStatus) { 446862306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 446962306a36Sopenharmony_ci "0933 %s: Register FC login error: 0x%x\n", 447062306a36Sopenharmony_ci __func__, mb->mbxStatus); 447162306a36Sopenharmony_ci goto out; 447262306a36Sopenharmony_ci } 447362306a36Sopenharmony_ci 447462306a36Sopenharmony_ci lpfc_check_nlp_post_devloss(vport, ndlp); 447562306a36Sopenharmony_ci 447662306a36Sopenharmony_ci if (phba->sli_rev < LPFC_SLI_REV4) 447762306a36Sopenharmony_ci ndlp->nlp_rpi = mb->un.varWords[0]; 447862306a36Sopenharmony_ci 447962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 448062306a36Sopenharmony_ci "0934 %s: Complete FC x%x RegLogin rpi x%x ste x%x\n", 448162306a36Sopenharmony_ci __func__, ndlp->nlp_DID, ndlp->nlp_rpi, 448262306a36Sopenharmony_ci ndlp->nlp_state); 448362306a36Sopenharmony_ci 448462306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_RPI_REGISTERED; 448562306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; 448662306a36Sopenharmony_ci ndlp->nlp_type |= NLP_FABRIC; 448762306a36Sopenharmony_ci lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci out: 449062306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); 449162306a36Sopenharmony_ci 449262306a36Sopenharmony_ci /* Drop the reference count from the mbox at the end after 449362306a36Sopenharmony_ci * all the current reference to the ndlp have been done. 449462306a36Sopenharmony_ci */ 449562306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 449662306a36Sopenharmony_ci} 449762306a36Sopenharmony_ci 449862306a36Sopenharmony_cistatic void 449962306a36Sopenharmony_cilpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) 450062306a36Sopenharmony_ci{ 450162306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 450262306a36Sopenharmony_ci struct fc_rport *rport; 450362306a36Sopenharmony_ci struct lpfc_rport_data *rdata; 450462306a36Sopenharmony_ci struct fc_rport_identifiers rport_ids; 450562306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 450662306a36Sopenharmony_ci unsigned long flags; 450762306a36Sopenharmony_ci 450862306a36Sopenharmony_ci if (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME) 450962306a36Sopenharmony_ci return; 451062306a36Sopenharmony_ci 451162306a36Sopenharmony_ci /* Remote port has reappeared. Re-register w/ FC transport */ 451262306a36Sopenharmony_ci rport_ids.node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn); 451362306a36Sopenharmony_ci rport_ids.port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn); 451462306a36Sopenharmony_ci rport_ids.port_id = ndlp->nlp_DID; 451562306a36Sopenharmony_ci rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; 451662306a36Sopenharmony_ci 451762306a36Sopenharmony_ci 451862306a36Sopenharmony_ci lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, 451962306a36Sopenharmony_ci "rport add: did:x%x flg:x%x type x%x", 452062306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); 452162306a36Sopenharmony_ci 452262306a36Sopenharmony_ci /* Don't add the remote port if unloading. */ 452362306a36Sopenharmony_ci if (vport->load_flag & FC_UNLOADING) 452462306a36Sopenharmony_ci return; 452562306a36Sopenharmony_ci 452662306a36Sopenharmony_ci ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids); 452762306a36Sopenharmony_ci if (!rport) { 452862306a36Sopenharmony_ci dev_printk(KERN_WARNING, &phba->pcidev->dev, 452962306a36Sopenharmony_ci "Warning: fc_remote_port_add failed\n"); 453062306a36Sopenharmony_ci return; 453162306a36Sopenharmony_ci } 453262306a36Sopenharmony_ci 453362306a36Sopenharmony_ci /* Successful port add. Complete initializing node data */ 453462306a36Sopenharmony_ci rport->maxframe_size = ndlp->nlp_maxframe; 453562306a36Sopenharmony_ci rport->supported_classes = ndlp->nlp_class_sup; 453662306a36Sopenharmony_ci rdata = rport->dd_data; 453762306a36Sopenharmony_ci rdata->pnode = lpfc_nlp_get(ndlp); 453862306a36Sopenharmony_ci if (!rdata->pnode) { 453962306a36Sopenharmony_ci dev_warn(&phba->pcidev->dev, 454062306a36Sopenharmony_ci "Warning - node ref failed. Unreg rport\n"); 454162306a36Sopenharmony_ci fc_remote_port_delete(rport); 454262306a36Sopenharmony_ci ndlp->rport = NULL; 454362306a36Sopenharmony_ci return; 454462306a36Sopenharmony_ci } 454562306a36Sopenharmony_ci 454662306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, flags); 454762306a36Sopenharmony_ci ndlp->fc4_xpt_flags |= SCSI_XPT_REGD; 454862306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, flags); 454962306a36Sopenharmony_ci 455062306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_FCP_TARGET) 455162306a36Sopenharmony_ci rport_ids.roles |= FC_PORT_ROLE_FCP_TARGET; 455262306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_FCP_INITIATOR) 455362306a36Sopenharmony_ci rport_ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; 455462306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_NVME_INITIATOR) 455562306a36Sopenharmony_ci rport_ids.roles |= FC_PORT_ROLE_NVME_INITIATOR; 455662306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_NVME_TARGET) 455762306a36Sopenharmony_ci rport_ids.roles |= FC_PORT_ROLE_NVME_TARGET; 455862306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_NVME_DISCOVERY) 455962306a36Sopenharmony_ci rport_ids.roles |= FC_PORT_ROLE_NVME_DISCOVERY; 456062306a36Sopenharmony_ci 456162306a36Sopenharmony_ci if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN) 456262306a36Sopenharmony_ci fc_remote_port_rolechg(rport, rport_ids.roles); 456362306a36Sopenharmony_ci 456462306a36Sopenharmony_ci lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, 456562306a36Sopenharmony_ci "3183 %s rport x%px DID x%x, role x%x refcnt %d\n", 456662306a36Sopenharmony_ci __func__, rport, rport->port_id, rport->roles, 456762306a36Sopenharmony_ci kref_read(&ndlp->kref)); 456862306a36Sopenharmony_ci 456962306a36Sopenharmony_ci if ((rport->scsi_target_id != -1) && 457062306a36Sopenharmony_ci (rport->scsi_target_id < LPFC_MAX_TARGET)) { 457162306a36Sopenharmony_ci ndlp->nlp_sid = rport->scsi_target_id; 457262306a36Sopenharmony_ci } 457362306a36Sopenharmony_ci 457462306a36Sopenharmony_ci return; 457562306a36Sopenharmony_ci} 457662306a36Sopenharmony_ci 457762306a36Sopenharmony_cistatic void 457862306a36Sopenharmony_cilpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) 457962306a36Sopenharmony_ci{ 458062306a36Sopenharmony_ci struct fc_rport *rport = ndlp->rport; 458162306a36Sopenharmony_ci struct lpfc_vport *vport = ndlp->vport; 458262306a36Sopenharmony_ci 458362306a36Sopenharmony_ci if (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME) 458462306a36Sopenharmony_ci return; 458562306a36Sopenharmony_ci 458662306a36Sopenharmony_ci lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, 458762306a36Sopenharmony_ci "rport delete: did:x%x flg:x%x type x%x", 458862306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); 458962306a36Sopenharmony_ci 459062306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 459162306a36Sopenharmony_ci "3184 rport unregister x%06x, rport x%px " 459262306a36Sopenharmony_ci "xptflg x%x refcnt %d\n", 459362306a36Sopenharmony_ci ndlp->nlp_DID, rport, ndlp->fc4_xpt_flags, 459462306a36Sopenharmony_ci kref_read(&ndlp->kref)); 459562306a36Sopenharmony_ci 459662306a36Sopenharmony_ci fc_remote_port_delete(rport); 459762306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 459862306a36Sopenharmony_ci} 459962306a36Sopenharmony_ci 460062306a36Sopenharmony_cistatic void 460162306a36Sopenharmony_cilpfc_nlp_counters(struct lpfc_vport *vport, int state, int count) 460262306a36Sopenharmony_ci{ 460362306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 460462306a36Sopenharmony_ci unsigned long iflags; 460562306a36Sopenharmony_ci 460662306a36Sopenharmony_ci spin_lock_irqsave(shost->host_lock, iflags); 460762306a36Sopenharmony_ci switch (state) { 460862306a36Sopenharmony_ci case NLP_STE_UNUSED_NODE: 460962306a36Sopenharmony_ci vport->fc_unused_cnt += count; 461062306a36Sopenharmony_ci break; 461162306a36Sopenharmony_ci case NLP_STE_PLOGI_ISSUE: 461262306a36Sopenharmony_ci vport->fc_plogi_cnt += count; 461362306a36Sopenharmony_ci break; 461462306a36Sopenharmony_ci case NLP_STE_ADISC_ISSUE: 461562306a36Sopenharmony_ci vport->fc_adisc_cnt += count; 461662306a36Sopenharmony_ci break; 461762306a36Sopenharmony_ci case NLP_STE_REG_LOGIN_ISSUE: 461862306a36Sopenharmony_ci vport->fc_reglogin_cnt += count; 461962306a36Sopenharmony_ci break; 462062306a36Sopenharmony_ci case NLP_STE_PRLI_ISSUE: 462162306a36Sopenharmony_ci vport->fc_prli_cnt += count; 462262306a36Sopenharmony_ci break; 462362306a36Sopenharmony_ci case NLP_STE_UNMAPPED_NODE: 462462306a36Sopenharmony_ci vport->fc_unmap_cnt += count; 462562306a36Sopenharmony_ci break; 462662306a36Sopenharmony_ci case NLP_STE_MAPPED_NODE: 462762306a36Sopenharmony_ci vport->fc_map_cnt += count; 462862306a36Sopenharmony_ci break; 462962306a36Sopenharmony_ci case NLP_STE_NPR_NODE: 463062306a36Sopenharmony_ci if (vport->fc_npr_cnt == 0 && count == -1) 463162306a36Sopenharmony_ci vport->fc_npr_cnt = 0; 463262306a36Sopenharmony_ci else 463362306a36Sopenharmony_ci vport->fc_npr_cnt += count; 463462306a36Sopenharmony_ci break; 463562306a36Sopenharmony_ci } 463662306a36Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, iflags); 463762306a36Sopenharmony_ci} 463862306a36Sopenharmony_ci 463962306a36Sopenharmony_ci/* Register a node with backend if not already done */ 464062306a36Sopenharmony_civoid 464162306a36Sopenharmony_cilpfc_nlp_reg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) 464262306a36Sopenharmony_ci{ 464362306a36Sopenharmony_ci unsigned long iflags; 464462306a36Sopenharmony_ci 464562306a36Sopenharmony_ci lpfc_check_nlp_post_devloss(vport, ndlp); 464662306a36Sopenharmony_ci 464762306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 464862306a36Sopenharmony_ci if (ndlp->fc4_xpt_flags & NLP_XPT_REGD) { 464962306a36Sopenharmony_ci /* Already registered with backend, trigger rescan */ 465062306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 465162306a36Sopenharmony_ci 465262306a36Sopenharmony_ci if (ndlp->fc4_xpt_flags & NVME_XPT_REGD && 465362306a36Sopenharmony_ci ndlp->nlp_type & (NLP_NVME_TARGET | NLP_NVME_DISCOVERY)) { 465462306a36Sopenharmony_ci lpfc_nvme_rescan_port(vport, ndlp); 465562306a36Sopenharmony_ci } 465662306a36Sopenharmony_ci return; 465762306a36Sopenharmony_ci } 465862306a36Sopenharmony_ci 465962306a36Sopenharmony_ci ndlp->fc4_xpt_flags |= NLP_XPT_REGD; 466062306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 466162306a36Sopenharmony_ci 466262306a36Sopenharmony_ci if (lpfc_valid_xpt_node(ndlp)) { 466362306a36Sopenharmony_ci vport->phba->nport_event_cnt++; 466462306a36Sopenharmony_ci /* 466562306a36Sopenharmony_ci * Tell the fc transport about the port, if we haven't 466662306a36Sopenharmony_ci * already. If we have, and it's a scsi entity, be 466762306a36Sopenharmony_ci */ 466862306a36Sopenharmony_ci lpfc_register_remote_port(vport, ndlp); 466962306a36Sopenharmony_ci } 467062306a36Sopenharmony_ci 467162306a36Sopenharmony_ci /* We are done if we do not have any NVME remote node */ 467262306a36Sopenharmony_ci if (!(ndlp->nlp_fc4_type & NLP_FC4_NVME)) 467362306a36Sopenharmony_ci return; 467462306a36Sopenharmony_ci 467562306a36Sopenharmony_ci /* Notify the NVME transport of this new rport. */ 467662306a36Sopenharmony_ci if (vport->phba->sli_rev >= LPFC_SLI_REV4 && 467762306a36Sopenharmony_ci ndlp->nlp_fc4_type & NLP_FC4_NVME) { 467862306a36Sopenharmony_ci if (vport->phba->nvmet_support == 0) { 467962306a36Sopenharmony_ci /* Register this rport with the transport. 468062306a36Sopenharmony_ci * Only NVME Target Rports are registered with 468162306a36Sopenharmony_ci * the transport. 468262306a36Sopenharmony_ci */ 468362306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_NVME_TARGET) { 468462306a36Sopenharmony_ci vport->phba->nport_event_cnt++; 468562306a36Sopenharmony_ci lpfc_nvme_register_port(vport, ndlp); 468662306a36Sopenharmony_ci } 468762306a36Sopenharmony_ci } else { 468862306a36Sopenharmony_ci /* Just take an NDLP ref count since the 468962306a36Sopenharmony_ci * target does not register rports. 469062306a36Sopenharmony_ci */ 469162306a36Sopenharmony_ci lpfc_nlp_get(ndlp); 469262306a36Sopenharmony_ci } 469362306a36Sopenharmony_ci } 469462306a36Sopenharmony_ci} 469562306a36Sopenharmony_ci 469662306a36Sopenharmony_ci/* Unregister a node with backend if not already done */ 469762306a36Sopenharmony_civoid 469862306a36Sopenharmony_cilpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) 469962306a36Sopenharmony_ci{ 470062306a36Sopenharmony_ci unsigned long iflags; 470162306a36Sopenharmony_ci 470262306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 470362306a36Sopenharmony_ci if (!(ndlp->fc4_xpt_flags & NLP_XPT_REGD)) { 470462306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 470562306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, 470662306a36Sopenharmony_ci LOG_ELS | LOG_NODE | LOG_DISCOVERY, 470762306a36Sopenharmony_ci "0999 %s Not regd: ndlp x%px rport x%px DID " 470862306a36Sopenharmony_ci "x%x FLG x%x XPT x%x\n", 470962306a36Sopenharmony_ci __func__, ndlp, ndlp->rport, ndlp->nlp_DID, 471062306a36Sopenharmony_ci ndlp->nlp_flag, ndlp->fc4_xpt_flags); 471162306a36Sopenharmony_ci return; 471262306a36Sopenharmony_ci } 471362306a36Sopenharmony_ci 471462306a36Sopenharmony_ci ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD; 471562306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 471662306a36Sopenharmony_ci 471762306a36Sopenharmony_ci if (ndlp->rport && 471862306a36Sopenharmony_ci ndlp->fc4_xpt_flags & SCSI_XPT_REGD) { 471962306a36Sopenharmony_ci vport->phba->nport_event_cnt++; 472062306a36Sopenharmony_ci lpfc_unregister_remote_port(ndlp); 472162306a36Sopenharmony_ci } else if (!ndlp->rport) { 472262306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, 472362306a36Sopenharmony_ci LOG_ELS | LOG_NODE | LOG_DISCOVERY, 472462306a36Sopenharmony_ci "1999 %s NDLP in devloss x%px DID x%x FLG x%x" 472562306a36Sopenharmony_ci " XPT x%x refcnt %u\n", 472662306a36Sopenharmony_ci __func__, ndlp, ndlp->nlp_DID, ndlp->nlp_flag, 472762306a36Sopenharmony_ci ndlp->fc4_xpt_flags, 472862306a36Sopenharmony_ci kref_read(&ndlp->kref)); 472962306a36Sopenharmony_ci } 473062306a36Sopenharmony_ci 473162306a36Sopenharmony_ci if (ndlp->fc4_xpt_flags & NVME_XPT_REGD) { 473262306a36Sopenharmony_ci vport->phba->nport_event_cnt++; 473362306a36Sopenharmony_ci if (vport->phba->nvmet_support == 0) { 473462306a36Sopenharmony_ci /* Start devloss if target. */ 473562306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_NVME_TARGET) 473662306a36Sopenharmony_ci lpfc_nvme_unregister_port(vport, ndlp); 473762306a36Sopenharmony_ci } else { 473862306a36Sopenharmony_ci /* NVMET has no upcall. */ 473962306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 474062306a36Sopenharmony_ci } 474162306a36Sopenharmony_ci } 474262306a36Sopenharmony_ci 474362306a36Sopenharmony_ci} 474462306a36Sopenharmony_ci 474562306a36Sopenharmony_ci/* 474662306a36Sopenharmony_ci * Adisc state change handling 474762306a36Sopenharmony_ci */ 474862306a36Sopenharmony_cistatic void 474962306a36Sopenharmony_cilpfc_handle_adisc_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, 475062306a36Sopenharmony_ci int new_state) 475162306a36Sopenharmony_ci{ 475262306a36Sopenharmony_ci switch (new_state) { 475362306a36Sopenharmony_ci /* 475462306a36Sopenharmony_ci * Any state to ADISC_ISSUE 475562306a36Sopenharmony_ci * Do nothing, adisc cmpl handling will trigger state changes 475662306a36Sopenharmony_ci */ 475762306a36Sopenharmony_ci case NLP_STE_ADISC_ISSUE: 475862306a36Sopenharmony_ci break; 475962306a36Sopenharmony_ci 476062306a36Sopenharmony_ci /* 476162306a36Sopenharmony_ci * ADISC_ISSUE to mapped states 476262306a36Sopenharmony_ci * Trigger a registration with backend, it will be nop if 476362306a36Sopenharmony_ci * already registered 476462306a36Sopenharmony_ci */ 476562306a36Sopenharmony_ci case NLP_STE_UNMAPPED_NODE: 476662306a36Sopenharmony_ci ndlp->nlp_type |= NLP_FC_NODE; 476762306a36Sopenharmony_ci fallthrough; 476862306a36Sopenharmony_ci case NLP_STE_MAPPED_NODE: 476962306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; 477062306a36Sopenharmony_ci lpfc_nlp_reg_node(vport, ndlp); 477162306a36Sopenharmony_ci break; 477262306a36Sopenharmony_ci 477362306a36Sopenharmony_ci /* 477462306a36Sopenharmony_ci * ADISC_ISSUE to non-mapped states 477562306a36Sopenharmony_ci * We are moving from ADISC_ISSUE to a non-mapped state because 477662306a36Sopenharmony_ci * ADISC failed, we would have skipped unregistering with 477762306a36Sopenharmony_ci * backend, attempt it now 477862306a36Sopenharmony_ci */ 477962306a36Sopenharmony_ci case NLP_STE_NPR_NODE: 478062306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_RCV_PLOGI; 478162306a36Sopenharmony_ci fallthrough; 478262306a36Sopenharmony_ci default: 478362306a36Sopenharmony_ci lpfc_nlp_unreg_node(vport, ndlp); 478462306a36Sopenharmony_ci break; 478562306a36Sopenharmony_ci } 478662306a36Sopenharmony_ci 478762306a36Sopenharmony_ci} 478862306a36Sopenharmony_ci 478962306a36Sopenharmony_cistatic void 479062306a36Sopenharmony_cilpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, 479162306a36Sopenharmony_ci int old_state, int new_state) 479262306a36Sopenharmony_ci{ 479362306a36Sopenharmony_ci /* Trap ADISC changes here */ 479462306a36Sopenharmony_ci if (new_state == NLP_STE_ADISC_ISSUE || 479562306a36Sopenharmony_ci old_state == NLP_STE_ADISC_ISSUE) { 479662306a36Sopenharmony_ci lpfc_handle_adisc_state(vport, ndlp, new_state); 479762306a36Sopenharmony_ci return; 479862306a36Sopenharmony_ci } 479962306a36Sopenharmony_ci 480062306a36Sopenharmony_ci if (new_state == NLP_STE_UNMAPPED_NODE) { 480162306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; 480262306a36Sopenharmony_ci ndlp->nlp_type |= NLP_FC_NODE; 480362306a36Sopenharmony_ci } 480462306a36Sopenharmony_ci if (new_state == NLP_STE_MAPPED_NODE) 480562306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; 480662306a36Sopenharmony_ci if (new_state == NLP_STE_NPR_NODE) 480762306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_RCV_PLOGI; 480862306a36Sopenharmony_ci 480962306a36Sopenharmony_ci /* Reg/Unreg for FCP and NVME Transport interface */ 481062306a36Sopenharmony_ci if ((old_state == NLP_STE_MAPPED_NODE || 481162306a36Sopenharmony_ci old_state == NLP_STE_UNMAPPED_NODE)) { 481262306a36Sopenharmony_ci /* For nodes marked for ADISC, Handle unreg in ADISC cmpl 481362306a36Sopenharmony_ci * if linkup. In linkdown do unreg_node 481462306a36Sopenharmony_ci */ 481562306a36Sopenharmony_ci if (!(ndlp->nlp_flag & NLP_NPR_ADISC) || 481662306a36Sopenharmony_ci !lpfc_is_link_up(vport->phba)) 481762306a36Sopenharmony_ci lpfc_nlp_unreg_node(vport, ndlp); 481862306a36Sopenharmony_ci } 481962306a36Sopenharmony_ci 482062306a36Sopenharmony_ci if (new_state == NLP_STE_MAPPED_NODE || 482162306a36Sopenharmony_ci new_state == NLP_STE_UNMAPPED_NODE) 482262306a36Sopenharmony_ci lpfc_nlp_reg_node(vport, ndlp); 482362306a36Sopenharmony_ci 482462306a36Sopenharmony_ci /* 482562306a36Sopenharmony_ci * If the node just added to Mapped list was an FCP target, 482662306a36Sopenharmony_ci * but the remote port registration failed or assigned a target 482762306a36Sopenharmony_ci * id outside the presentable range - move the node to the 482862306a36Sopenharmony_ci * Unmapped List. 482962306a36Sopenharmony_ci */ 483062306a36Sopenharmony_ci if ((new_state == NLP_STE_MAPPED_NODE) && 483162306a36Sopenharmony_ci (ndlp->nlp_type & NLP_FCP_TARGET) && 483262306a36Sopenharmony_ci (!ndlp->rport || 483362306a36Sopenharmony_ci ndlp->rport->scsi_target_id == -1 || 483462306a36Sopenharmony_ci ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) { 483562306a36Sopenharmony_ci spin_lock_irq(&ndlp->lock); 483662306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_TGT_NO_SCSIID; 483762306a36Sopenharmony_ci spin_unlock_irq(&ndlp->lock); 483862306a36Sopenharmony_ci lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); 483962306a36Sopenharmony_ci } 484062306a36Sopenharmony_ci} 484162306a36Sopenharmony_ci 484262306a36Sopenharmony_cistatic char * 484362306a36Sopenharmony_cilpfc_nlp_state_name(char *buffer, size_t size, int state) 484462306a36Sopenharmony_ci{ 484562306a36Sopenharmony_ci static char *states[] = { 484662306a36Sopenharmony_ci [NLP_STE_UNUSED_NODE] = "UNUSED", 484762306a36Sopenharmony_ci [NLP_STE_PLOGI_ISSUE] = "PLOGI", 484862306a36Sopenharmony_ci [NLP_STE_ADISC_ISSUE] = "ADISC", 484962306a36Sopenharmony_ci [NLP_STE_REG_LOGIN_ISSUE] = "REGLOGIN", 485062306a36Sopenharmony_ci [NLP_STE_PRLI_ISSUE] = "PRLI", 485162306a36Sopenharmony_ci [NLP_STE_LOGO_ISSUE] = "LOGO", 485262306a36Sopenharmony_ci [NLP_STE_UNMAPPED_NODE] = "UNMAPPED", 485362306a36Sopenharmony_ci [NLP_STE_MAPPED_NODE] = "MAPPED", 485462306a36Sopenharmony_ci [NLP_STE_NPR_NODE] = "NPR", 485562306a36Sopenharmony_ci }; 485662306a36Sopenharmony_ci 485762306a36Sopenharmony_ci if (state < NLP_STE_MAX_STATE && states[state]) 485862306a36Sopenharmony_ci strscpy(buffer, states[state], size); 485962306a36Sopenharmony_ci else 486062306a36Sopenharmony_ci snprintf(buffer, size, "unknown (%d)", state); 486162306a36Sopenharmony_ci return buffer; 486262306a36Sopenharmony_ci} 486362306a36Sopenharmony_ci 486462306a36Sopenharmony_civoid 486562306a36Sopenharmony_cilpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, 486662306a36Sopenharmony_ci int state) 486762306a36Sopenharmony_ci{ 486862306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 486962306a36Sopenharmony_ci int old_state = ndlp->nlp_state; 487062306a36Sopenharmony_ci int node_dropped = ndlp->nlp_flag & NLP_DROPPED; 487162306a36Sopenharmony_ci char name1[16], name2[16]; 487262306a36Sopenharmony_ci 487362306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 487462306a36Sopenharmony_ci "0904 NPort state transition x%06x, %s -> %s\n", 487562306a36Sopenharmony_ci ndlp->nlp_DID, 487662306a36Sopenharmony_ci lpfc_nlp_state_name(name1, sizeof(name1), old_state), 487762306a36Sopenharmony_ci lpfc_nlp_state_name(name2, sizeof(name2), state)); 487862306a36Sopenharmony_ci 487962306a36Sopenharmony_ci lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, 488062306a36Sopenharmony_ci "node statechg did:x%x old:%d ste:%d", 488162306a36Sopenharmony_ci ndlp->nlp_DID, old_state, state); 488262306a36Sopenharmony_ci 488362306a36Sopenharmony_ci if (node_dropped && old_state == NLP_STE_UNUSED_NODE && 488462306a36Sopenharmony_ci state != NLP_STE_UNUSED_NODE) { 488562306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_DROPPED; 488662306a36Sopenharmony_ci lpfc_nlp_get(ndlp); 488762306a36Sopenharmony_ci } 488862306a36Sopenharmony_ci 488962306a36Sopenharmony_ci if (old_state == NLP_STE_NPR_NODE && 489062306a36Sopenharmony_ci state != NLP_STE_NPR_NODE) 489162306a36Sopenharmony_ci lpfc_cancel_retry_delay_tmo(vport, ndlp); 489262306a36Sopenharmony_ci if (old_state == NLP_STE_UNMAPPED_NODE) { 489362306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_TGT_NO_SCSIID; 489462306a36Sopenharmony_ci ndlp->nlp_type &= ~NLP_FC_NODE; 489562306a36Sopenharmony_ci } 489662306a36Sopenharmony_ci 489762306a36Sopenharmony_ci if (list_empty(&ndlp->nlp_listp)) { 489862306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 489962306a36Sopenharmony_ci list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); 490062306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 490162306a36Sopenharmony_ci } else if (old_state) 490262306a36Sopenharmony_ci lpfc_nlp_counters(vport, old_state, -1); 490362306a36Sopenharmony_ci 490462306a36Sopenharmony_ci ndlp->nlp_state = state; 490562306a36Sopenharmony_ci lpfc_nlp_counters(vport, state, 1); 490662306a36Sopenharmony_ci lpfc_nlp_state_cleanup(vport, ndlp, old_state, state); 490762306a36Sopenharmony_ci} 490862306a36Sopenharmony_ci 490962306a36Sopenharmony_civoid 491062306a36Sopenharmony_cilpfc_enqueue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) 491162306a36Sopenharmony_ci{ 491262306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 491362306a36Sopenharmony_ci 491462306a36Sopenharmony_ci if (list_empty(&ndlp->nlp_listp)) { 491562306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 491662306a36Sopenharmony_ci list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); 491762306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 491862306a36Sopenharmony_ci } 491962306a36Sopenharmony_ci} 492062306a36Sopenharmony_ci 492162306a36Sopenharmony_civoid 492262306a36Sopenharmony_cilpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) 492362306a36Sopenharmony_ci{ 492462306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 492562306a36Sopenharmony_ci 492662306a36Sopenharmony_ci lpfc_cancel_retry_delay_tmo(vport, ndlp); 492762306a36Sopenharmony_ci if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) 492862306a36Sopenharmony_ci lpfc_nlp_counters(vport, ndlp->nlp_state, -1); 492962306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 493062306a36Sopenharmony_ci list_del_init(&ndlp->nlp_listp); 493162306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 493262306a36Sopenharmony_ci lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, 493362306a36Sopenharmony_ci NLP_STE_UNUSED_NODE); 493462306a36Sopenharmony_ci} 493562306a36Sopenharmony_ci 493662306a36Sopenharmony_ci/** 493762306a36Sopenharmony_ci * lpfc_initialize_node - Initialize all fields of node object 493862306a36Sopenharmony_ci * @vport: Pointer to Virtual Port object. 493962306a36Sopenharmony_ci * @ndlp: Pointer to FC node object. 494062306a36Sopenharmony_ci * @did: FC_ID of the node. 494162306a36Sopenharmony_ci * 494262306a36Sopenharmony_ci * This function is always called when node object need to be initialized. 494362306a36Sopenharmony_ci * It initializes all the fields of the node object. Although the reference 494462306a36Sopenharmony_ci * to phba from @ndlp can be obtained indirectly through it's reference to 494562306a36Sopenharmony_ci * @vport, a direct reference to phba is taken here by @ndlp. This is due 494662306a36Sopenharmony_ci * to the life-span of the @ndlp might go beyond the existence of @vport as 494762306a36Sopenharmony_ci * the final release of ndlp is determined by its reference count. And, the 494862306a36Sopenharmony_ci * operation on @ndlp needs the reference to phba. 494962306a36Sopenharmony_ci **/ 495062306a36Sopenharmony_cistatic inline void 495162306a36Sopenharmony_cilpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, 495262306a36Sopenharmony_ci uint32_t did) 495362306a36Sopenharmony_ci{ 495462306a36Sopenharmony_ci INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); 495562306a36Sopenharmony_ci INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); 495662306a36Sopenharmony_ci timer_setup(&ndlp->nlp_delayfunc, lpfc_els_retry_delay, 0); 495762306a36Sopenharmony_ci INIT_LIST_HEAD(&ndlp->recovery_evt.evt_listp); 495862306a36Sopenharmony_ci 495962306a36Sopenharmony_ci ndlp->nlp_DID = did; 496062306a36Sopenharmony_ci ndlp->vport = vport; 496162306a36Sopenharmony_ci ndlp->phba = vport->phba; 496262306a36Sopenharmony_ci ndlp->nlp_sid = NLP_NO_SID; 496362306a36Sopenharmony_ci ndlp->nlp_fc4_type = NLP_FC4_NONE; 496462306a36Sopenharmony_ci kref_init(&ndlp->kref); 496562306a36Sopenharmony_ci atomic_set(&ndlp->cmd_pending, 0); 496662306a36Sopenharmony_ci ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth; 496762306a36Sopenharmony_ci ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING; 496862306a36Sopenharmony_ci} 496962306a36Sopenharmony_ci 497062306a36Sopenharmony_civoid 497162306a36Sopenharmony_cilpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) 497262306a36Sopenharmony_ci{ 497362306a36Sopenharmony_ci /* 497462306a36Sopenharmony_ci * Use of lpfc_drop_node and UNUSED list: lpfc_drop_node should 497562306a36Sopenharmony_ci * be used when lpfc wants to remove the "last" lpfc_nlp_put() to 497662306a36Sopenharmony_ci * release the ndlp from the vport when conditions are correct. 497762306a36Sopenharmony_ci */ 497862306a36Sopenharmony_ci if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) 497962306a36Sopenharmony_ci return; 498062306a36Sopenharmony_ci lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); 498162306a36Sopenharmony_ci if (vport->phba->sli_rev == LPFC_SLI_REV4) { 498262306a36Sopenharmony_ci lpfc_cleanup_vports_rrqs(vport, ndlp); 498362306a36Sopenharmony_ci lpfc_unreg_rpi(vport, ndlp); 498462306a36Sopenharmony_ci } 498562306a36Sopenharmony_ci 498662306a36Sopenharmony_ci /* NLP_DROPPED means another thread already removed the initial 498762306a36Sopenharmony_ci * reference from lpfc_nlp_init. If set, don't drop it again and 498862306a36Sopenharmony_ci * introduce an imbalance. 498962306a36Sopenharmony_ci */ 499062306a36Sopenharmony_ci spin_lock_irq(&ndlp->lock); 499162306a36Sopenharmony_ci if (!(ndlp->nlp_flag & NLP_DROPPED)) { 499262306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_DROPPED; 499362306a36Sopenharmony_ci spin_unlock_irq(&ndlp->lock); 499462306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 499562306a36Sopenharmony_ci return; 499662306a36Sopenharmony_ci } 499762306a36Sopenharmony_ci spin_unlock_irq(&ndlp->lock); 499862306a36Sopenharmony_ci} 499962306a36Sopenharmony_ci 500062306a36Sopenharmony_ci/* 500162306a36Sopenharmony_ci * Start / ReStart rescue timer for Discovery / RSCN handling 500262306a36Sopenharmony_ci */ 500362306a36Sopenharmony_civoid 500462306a36Sopenharmony_cilpfc_set_disctmo(struct lpfc_vport *vport) 500562306a36Sopenharmony_ci{ 500662306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 500762306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 500862306a36Sopenharmony_ci uint32_t tmo; 500962306a36Sopenharmony_ci 501062306a36Sopenharmony_ci if (vport->port_state == LPFC_LOCAL_CFG_LINK) { 501162306a36Sopenharmony_ci /* For FAN, timeout should be greater than edtov */ 501262306a36Sopenharmony_ci tmo = (((phba->fc_edtov + 999) / 1000) + 1); 501362306a36Sopenharmony_ci } else { 501462306a36Sopenharmony_ci /* Normal discovery timeout should be > than ELS/CT timeout 501562306a36Sopenharmony_ci * FC spec states we need 3 * ratov for CT requests 501662306a36Sopenharmony_ci */ 501762306a36Sopenharmony_ci tmo = ((phba->fc_ratov * 3) + 3); 501862306a36Sopenharmony_ci } 501962306a36Sopenharmony_ci 502062306a36Sopenharmony_ci 502162306a36Sopenharmony_ci if (!timer_pending(&vport->fc_disctmo)) { 502262306a36Sopenharmony_ci lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, 502362306a36Sopenharmony_ci "set disc timer: tmo:x%x state:x%x flg:x%x", 502462306a36Sopenharmony_ci tmo, vport->port_state, vport->fc_flag); 502562306a36Sopenharmony_ci } 502662306a36Sopenharmony_ci 502762306a36Sopenharmony_ci mod_timer(&vport->fc_disctmo, jiffies + msecs_to_jiffies(1000 * tmo)); 502862306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 502962306a36Sopenharmony_ci vport->fc_flag |= FC_DISC_TMO; 503062306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 503162306a36Sopenharmony_ci 503262306a36Sopenharmony_ci /* Start Discovery Timer state <hba_state> */ 503362306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 503462306a36Sopenharmony_ci "0247 Start Discovery Timer state x%x " 503562306a36Sopenharmony_ci "Data: x%x x%lx x%x x%x\n", 503662306a36Sopenharmony_ci vport->port_state, tmo, 503762306a36Sopenharmony_ci (unsigned long)&vport->fc_disctmo, vport->fc_plogi_cnt, 503862306a36Sopenharmony_ci vport->fc_adisc_cnt); 503962306a36Sopenharmony_ci 504062306a36Sopenharmony_ci return; 504162306a36Sopenharmony_ci} 504262306a36Sopenharmony_ci 504362306a36Sopenharmony_ci/* 504462306a36Sopenharmony_ci * Cancel rescue timer for Discovery / RSCN handling 504562306a36Sopenharmony_ci */ 504662306a36Sopenharmony_ciint 504762306a36Sopenharmony_cilpfc_can_disctmo(struct lpfc_vport *vport) 504862306a36Sopenharmony_ci{ 504962306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 505062306a36Sopenharmony_ci unsigned long iflags; 505162306a36Sopenharmony_ci 505262306a36Sopenharmony_ci lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, 505362306a36Sopenharmony_ci "can disc timer: state:x%x rtry:x%x flg:x%x", 505462306a36Sopenharmony_ci vport->port_state, vport->fc_ns_retry, vport->fc_flag); 505562306a36Sopenharmony_ci 505662306a36Sopenharmony_ci /* Turn off discovery timer if its running */ 505762306a36Sopenharmony_ci if (vport->fc_flag & FC_DISC_TMO || 505862306a36Sopenharmony_ci timer_pending(&vport->fc_disctmo)) { 505962306a36Sopenharmony_ci spin_lock_irqsave(shost->host_lock, iflags); 506062306a36Sopenharmony_ci vport->fc_flag &= ~FC_DISC_TMO; 506162306a36Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, iflags); 506262306a36Sopenharmony_ci del_timer_sync(&vport->fc_disctmo); 506362306a36Sopenharmony_ci spin_lock_irqsave(&vport->work_port_lock, iflags); 506462306a36Sopenharmony_ci vport->work_port_events &= ~WORKER_DISC_TMO; 506562306a36Sopenharmony_ci spin_unlock_irqrestore(&vport->work_port_lock, iflags); 506662306a36Sopenharmony_ci } 506762306a36Sopenharmony_ci 506862306a36Sopenharmony_ci /* Cancel Discovery Timer state <hba_state> */ 506962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 507062306a36Sopenharmony_ci "0248 Cancel Discovery Timer state x%x " 507162306a36Sopenharmony_ci "Data: x%x x%x x%x\n", 507262306a36Sopenharmony_ci vport->port_state, vport->fc_flag, 507362306a36Sopenharmony_ci vport->fc_plogi_cnt, vport->fc_adisc_cnt); 507462306a36Sopenharmony_ci return 0; 507562306a36Sopenharmony_ci} 507662306a36Sopenharmony_ci 507762306a36Sopenharmony_ci/* 507862306a36Sopenharmony_ci * Check specified ring for outstanding IOCB on the SLI queue 507962306a36Sopenharmony_ci * Return true if iocb matches the specified nport 508062306a36Sopenharmony_ci */ 508162306a36Sopenharmony_ciint 508262306a36Sopenharmony_cilpfc_check_sli_ndlp(struct lpfc_hba *phba, 508362306a36Sopenharmony_ci struct lpfc_sli_ring *pring, 508462306a36Sopenharmony_ci struct lpfc_iocbq *iocb, 508562306a36Sopenharmony_ci struct lpfc_nodelist *ndlp) 508662306a36Sopenharmony_ci{ 508762306a36Sopenharmony_ci struct lpfc_vport *vport = ndlp->vport; 508862306a36Sopenharmony_ci u8 ulp_command; 508962306a36Sopenharmony_ci u16 ulp_context; 509062306a36Sopenharmony_ci u32 remote_id; 509162306a36Sopenharmony_ci 509262306a36Sopenharmony_ci if (iocb->vport != vport) 509362306a36Sopenharmony_ci return 0; 509462306a36Sopenharmony_ci 509562306a36Sopenharmony_ci ulp_command = get_job_cmnd(phba, iocb); 509662306a36Sopenharmony_ci ulp_context = get_job_ulpcontext(phba, iocb); 509762306a36Sopenharmony_ci remote_id = get_job_els_rsp64_did(phba, iocb); 509862306a36Sopenharmony_ci 509962306a36Sopenharmony_ci if (pring->ringno == LPFC_ELS_RING) { 510062306a36Sopenharmony_ci switch (ulp_command) { 510162306a36Sopenharmony_ci case CMD_GEN_REQUEST64_CR: 510262306a36Sopenharmony_ci if (iocb->ndlp == ndlp) 510362306a36Sopenharmony_ci return 1; 510462306a36Sopenharmony_ci fallthrough; 510562306a36Sopenharmony_ci case CMD_ELS_REQUEST64_CR: 510662306a36Sopenharmony_ci if (remote_id == ndlp->nlp_DID) 510762306a36Sopenharmony_ci return 1; 510862306a36Sopenharmony_ci fallthrough; 510962306a36Sopenharmony_ci case CMD_XMIT_ELS_RSP64_CX: 511062306a36Sopenharmony_ci if (iocb->ndlp == ndlp) 511162306a36Sopenharmony_ci return 1; 511262306a36Sopenharmony_ci } 511362306a36Sopenharmony_ci } else if (pring->ringno == LPFC_FCP_RING) { 511462306a36Sopenharmony_ci /* Skip match check if waiting to relogin to FCP target */ 511562306a36Sopenharmony_ci if ((ndlp->nlp_type & NLP_FCP_TARGET) && 511662306a36Sopenharmony_ci (ndlp->nlp_flag & NLP_DELAY_TMO)) { 511762306a36Sopenharmony_ci return 0; 511862306a36Sopenharmony_ci } 511962306a36Sopenharmony_ci if (ulp_context == ndlp->nlp_rpi) 512062306a36Sopenharmony_ci return 1; 512162306a36Sopenharmony_ci } 512262306a36Sopenharmony_ci return 0; 512362306a36Sopenharmony_ci} 512462306a36Sopenharmony_ci 512562306a36Sopenharmony_cistatic void 512662306a36Sopenharmony_ci__lpfc_dequeue_nport_iocbs(struct lpfc_hba *phba, 512762306a36Sopenharmony_ci struct lpfc_nodelist *ndlp, struct lpfc_sli_ring *pring, 512862306a36Sopenharmony_ci struct list_head *dequeue_list) 512962306a36Sopenharmony_ci{ 513062306a36Sopenharmony_ci struct lpfc_iocbq *iocb, *next_iocb; 513162306a36Sopenharmony_ci 513262306a36Sopenharmony_ci list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { 513362306a36Sopenharmony_ci /* Check to see if iocb matches the nport */ 513462306a36Sopenharmony_ci if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) 513562306a36Sopenharmony_ci /* match, dequeue */ 513662306a36Sopenharmony_ci list_move_tail(&iocb->list, dequeue_list); 513762306a36Sopenharmony_ci } 513862306a36Sopenharmony_ci} 513962306a36Sopenharmony_ci 514062306a36Sopenharmony_cistatic void 514162306a36Sopenharmony_cilpfc_sli3_dequeue_nport_iocbs(struct lpfc_hba *phba, 514262306a36Sopenharmony_ci struct lpfc_nodelist *ndlp, struct list_head *dequeue_list) 514362306a36Sopenharmony_ci{ 514462306a36Sopenharmony_ci struct lpfc_sli *psli = &phba->sli; 514562306a36Sopenharmony_ci uint32_t i; 514662306a36Sopenharmony_ci 514762306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 514862306a36Sopenharmony_ci for (i = 0; i < psli->num_rings; i++) 514962306a36Sopenharmony_ci __lpfc_dequeue_nport_iocbs(phba, ndlp, &psli->sli3_ring[i], 515062306a36Sopenharmony_ci dequeue_list); 515162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 515262306a36Sopenharmony_ci} 515362306a36Sopenharmony_ci 515462306a36Sopenharmony_cistatic void 515562306a36Sopenharmony_cilpfc_sli4_dequeue_nport_iocbs(struct lpfc_hba *phba, 515662306a36Sopenharmony_ci struct lpfc_nodelist *ndlp, struct list_head *dequeue_list) 515762306a36Sopenharmony_ci{ 515862306a36Sopenharmony_ci struct lpfc_sli_ring *pring; 515962306a36Sopenharmony_ci struct lpfc_queue *qp = NULL; 516062306a36Sopenharmony_ci 516162306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 516262306a36Sopenharmony_ci list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) { 516362306a36Sopenharmony_ci pring = qp->pring; 516462306a36Sopenharmony_ci if (!pring) 516562306a36Sopenharmony_ci continue; 516662306a36Sopenharmony_ci spin_lock(&pring->ring_lock); 516762306a36Sopenharmony_ci __lpfc_dequeue_nport_iocbs(phba, ndlp, pring, dequeue_list); 516862306a36Sopenharmony_ci spin_unlock(&pring->ring_lock); 516962306a36Sopenharmony_ci } 517062306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 517162306a36Sopenharmony_ci} 517262306a36Sopenharmony_ci 517362306a36Sopenharmony_ci/* 517462306a36Sopenharmony_ci * Free resources / clean up outstanding I/Os 517562306a36Sopenharmony_ci * associated with nlp_rpi in the LPFC_NODELIST entry. 517662306a36Sopenharmony_ci */ 517762306a36Sopenharmony_cistatic int 517862306a36Sopenharmony_cilpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) 517962306a36Sopenharmony_ci{ 518062306a36Sopenharmony_ci LIST_HEAD(completions); 518162306a36Sopenharmony_ci 518262306a36Sopenharmony_ci lpfc_fabric_abort_nport(ndlp); 518362306a36Sopenharmony_ci 518462306a36Sopenharmony_ci /* 518562306a36Sopenharmony_ci * Everything that matches on txcmplq will be returned 518662306a36Sopenharmony_ci * by firmware with a no rpi error. 518762306a36Sopenharmony_ci */ 518862306a36Sopenharmony_ci if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { 518962306a36Sopenharmony_ci if (phba->sli_rev != LPFC_SLI_REV4) 519062306a36Sopenharmony_ci lpfc_sli3_dequeue_nport_iocbs(phba, ndlp, &completions); 519162306a36Sopenharmony_ci else 519262306a36Sopenharmony_ci lpfc_sli4_dequeue_nport_iocbs(phba, ndlp, &completions); 519362306a36Sopenharmony_ci } 519462306a36Sopenharmony_ci 519562306a36Sopenharmony_ci /* Cancel all the IOCBs from the completions list */ 519662306a36Sopenharmony_ci lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, 519762306a36Sopenharmony_ci IOERR_SLI_ABORTED); 519862306a36Sopenharmony_ci 519962306a36Sopenharmony_ci return 0; 520062306a36Sopenharmony_ci} 520162306a36Sopenharmony_ci 520262306a36Sopenharmony_ci/** 520362306a36Sopenharmony_ci * lpfc_nlp_logo_unreg - Unreg mailbox completion handler before LOGO 520462306a36Sopenharmony_ci * @phba: Pointer to HBA context object. 520562306a36Sopenharmony_ci * @pmb: Pointer to mailbox object. 520662306a36Sopenharmony_ci * 520762306a36Sopenharmony_ci * This function will issue an ELS LOGO command after completing 520862306a36Sopenharmony_ci * the UNREG_RPI. 520962306a36Sopenharmony_ci **/ 521062306a36Sopenharmony_cistatic void 521162306a36Sopenharmony_cilpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) 521262306a36Sopenharmony_ci{ 521362306a36Sopenharmony_ci struct lpfc_vport *vport = pmb->vport; 521462306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 521562306a36Sopenharmony_ci 521662306a36Sopenharmony_ci ndlp = (struct lpfc_nodelist *)(pmb->ctx_ndlp); 521762306a36Sopenharmony_ci if (!ndlp) 521862306a36Sopenharmony_ci return; 521962306a36Sopenharmony_ci lpfc_issue_els_logo(vport, ndlp, 0); 522062306a36Sopenharmony_ci 522162306a36Sopenharmony_ci /* Check to see if there are any deferred events to process */ 522262306a36Sopenharmony_ci if ((ndlp->nlp_flag & NLP_UNREG_INP) && 522362306a36Sopenharmony_ci (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) { 522462306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 522562306a36Sopenharmony_ci "1434 UNREG cmpl deferred logo x%x " 522662306a36Sopenharmony_ci "on NPort x%x Data: x%x x%px\n", 522762306a36Sopenharmony_ci ndlp->nlp_rpi, ndlp->nlp_DID, 522862306a36Sopenharmony_ci ndlp->nlp_defer_did, ndlp); 522962306a36Sopenharmony_ci 523062306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_UNREG_INP; 523162306a36Sopenharmony_ci ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING; 523262306a36Sopenharmony_ci lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); 523362306a36Sopenharmony_ci } else { 523462306a36Sopenharmony_ci /* NLP_RELEASE_RPI is only set for SLI4 ports. */ 523562306a36Sopenharmony_ci if (ndlp->nlp_flag & NLP_RELEASE_RPI) { 523662306a36Sopenharmony_ci lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); 523762306a36Sopenharmony_ci spin_lock_irq(&ndlp->lock); 523862306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_RELEASE_RPI; 523962306a36Sopenharmony_ci ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; 524062306a36Sopenharmony_ci spin_unlock_irq(&ndlp->lock); 524162306a36Sopenharmony_ci } 524262306a36Sopenharmony_ci spin_lock_irq(&ndlp->lock); 524362306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_UNREG_INP; 524462306a36Sopenharmony_ci spin_unlock_irq(&ndlp->lock); 524562306a36Sopenharmony_ci } 524662306a36Sopenharmony_ci 524762306a36Sopenharmony_ci /* The node has an outstanding reference for the unreg. Now 524862306a36Sopenharmony_ci * that the LOGO action and cleanup are finished, release 524962306a36Sopenharmony_ci * resources. 525062306a36Sopenharmony_ci */ 525162306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 525262306a36Sopenharmony_ci mempool_free(pmb, phba->mbox_mem_pool); 525362306a36Sopenharmony_ci} 525462306a36Sopenharmony_ci 525562306a36Sopenharmony_ci/* 525662306a36Sopenharmony_ci * Sets the mailbox completion handler to be used for the 525762306a36Sopenharmony_ci * unreg_rpi command. The handler varies based on the state of 525862306a36Sopenharmony_ci * the port and what will be happening to the rpi next. 525962306a36Sopenharmony_ci */ 526062306a36Sopenharmony_cistatic void 526162306a36Sopenharmony_cilpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, 526262306a36Sopenharmony_ci struct lpfc_nodelist *ndlp, LPFC_MBOXQ_t *mbox) 526362306a36Sopenharmony_ci{ 526462306a36Sopenharmony_ci unsigned long iflags; 526562306a36Sopenharmony_ci 526662306a36Sopenharmony_ci /* Driver always gets a reference on the mailbox job 526762306a36Sopenharmony_ci * in support of async jobs. 526862306a36Sopenharmony_ci */ 526962306a36Sopenharmony_ci mbox->ctx_ndlp = lpfc_nlp_get(ndlp); 527062306a36Sopenharmony_ci if (!mbox->ctx_ndlp) 527162306a36Sopenharmony_ci return; 527262306a36Sopenharmony_ci 527362306a36Sopenharmony_ci if (ndlp->nlp_flag & NLP_ISSUE_LOGO) { 527462306a36Sopenharmony_ci mbox->mbox_cmpl = lpfc_nlp_logo_unreg; 527562306a36Sopenharmony_ci 527662306a36Sopenharmony_ci } else if (phba->sli_rev == LPFC_SLI_REV4 && 527762306a36Sopenharmony_ci (!(vport->load_flag & FC_UNLOADING)) && 527862306a36Sopenharmony_ci (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= 527962306a36Sopenharmony_ci LPFC_SLI_INTF_IF_TYPE_2) && 528062306a36Sopenharmony_ci (kref_read(&ndlp->kref) > 0)) { 528162306a36Sopenharmony_ci mbox->mbox_cmpl = lpfc_sli4_unreg_rpi_cmpl_clr; 528262306a36Sopenharmony_ci } else { 528362306a36Sopenharmony_ci if (vport->load_flag & FC_UNLOADING) { 528462306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4) { 528562306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, iflags); 528662306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_RELEASE_RPI; 528762306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, iflags); 528862306a36Sopenharmony_ci } 528962306a36Sopenharmony_ci } 529062306a36Sopenharmony_ci mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; 529162306a36Sopenharmony_ci } 529262306a36Sopenharmony_ci} 529362306a36Sopenharmony_ci 529462306a36Sopenharmony_ci/* 529562306a36Sopenharmony_ci * Free rpi associated with LPFC_NODELIST entry. 529662306a36Sopenharmony_ci * This routine is called from lpfc_freenode(), when we are removing 529762306a36Sopenharmony_ci * a LPFC_NODELIST entry. It is also called if the driver initiates a 529862306a36Sopenharmony_ci * LOGO that completes successfully, and we are waiting to PLOGI back 529962306a36Sopenharmony_ci * to the remote NPort. In addition, it is called after we receive 530062306a36Sopenharmony_ci * and unsolicated ELS cmd, send back a rsp, the rsp completes and 530162306a36Sopenharmony_ci * we are waiting to PLOGI back to the remote NPort. 530262306a36Sopenharmony_ci */ 530362306a36Sopenharmony_ciint 530462306a36Sopenharmony_cilpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) 530562306a36Sopenharmony_ci{ 530662306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 530762306a36Sopenharmony_ci LPFC_MBOXQ_t *mbox; 530862306a36Sopenharmony_ci int rc, acc_plogi = 1; 530962306a36Sopenharmony_ci uint16_t rpi; 531062306a36Sopenharmony_ci 531162306a36Sopenharmony_ci if (ndlp->nlp_flag & NLP_RPI_REGISTERED || 531262306a36Sopenharmony_ci ndlp->nlp_flag & NLP_REG_LOGIN_SEND) { 531362306a36Sopenharmony_ci if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) 531462306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, 531562306a36Sopenharmony_ci LOG_NODE | LOG_DISCOVERY, 531662306a36Sopenharmony_ci "3366 RPI x%x needs to be " 531762306a36Sopenharmony_ci "unregistered nlp_flag x%x " 531862306a36Sopenharmony_ci "did x%x\n", 531962306a36Sopenharmony_ci ndlp->nlp_rpi, ndlp->nlp_flag, 532062306a36Sopenharmony_ci ndlp->nlp_DID); 532162306a36Sopenharmony_ci 532262306a36Sopenharmony_ci /* If there is already an UNREG in progress for this ndlp, 532362306a36Sopenharmony_ci * no need to queue up another one. 532462306a36Sopenharmony_ci */ 532562306a36Sopenharmony_ci if (ndlp->nlp_flag & NLP_UNREG_INP) { 532662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, 532762306a36Sopenharmony_ci LOG_NODE | LOG_DISCOVERY, 532862306a36Sopenharmony_ci "1436 unreg_rpi SKIP UNREG x%x on " 532962306a36Sopenharmony_ci "NPort x%x deferred x%x flg x%x " 533062306a36Sopenharmony_ci "Data: x%px\n", 533162306a36Sopenharmony_ci ndlp->nlp_rpi, ndlp->nlp_DID, 533262306a36Sopenharmony_ci ndlp->nlp_defer_did, 533362306a36Sopenharmony_ci ndlp->nlp_flag, ndlp); 533462306a36Sopenharmony_ci goto out; 533562306a36Sopenharmony_ci } 533662306a36Sopenharmony_ci 533762306a36Sopenharmony_ci mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 533862306a36Sopenharmony_ci if (mbox) { 533962306a36Sopenharmony_ci /* SLI4 ports require the physical rpi value. */ 534062306a36Sopenharmony_ci rpi = ndlp->nlp_rpi; 534162306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4) 534262306a36Sopenharmony_ci rpi = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; 534362306a36Sopenharmony_ci 534462306a36Sopenharmony_ci lpfc_unreg_login(phba, vport->vpi, rpi, mbox); 534562306a36Sopenharmony_ci mbox->vport = vport; 534662306a36Sopenharmony_ci lpfc_set_unreg_login_mbx_cmpl(phba, vport, ndlp, mbox); 534762306a36Sopenharmony_ci if (!mbox->ctx_ndlp) { 534862306a36Sopenharmony_ci mempool_free(mbox, phba->mbox_mem_pool); 534962306a36Sopenharmony_ci return 1; 535062306a36Sopenharmony_ci } 535162306a36Sopenharmony_ci 535262306a36Sopenharmony_ci if (mbox->mbox_cmpl == lpfc_sli4_unreg_rpi_cmpl_clr) 535362306a36Sopenharmony_ci /* 535462306a36Sopenharmony_ci * accept PLOGIs after unreg_rpi_cmpl 535562306a36Sopenharmony_ci */ 535662306a36Sopenharmony_ci acc_plogi = 0; 535762306a36Sopenharmony_ci if (((ndlp->nlp_DID & Fabric_DID_MASK) != 535862306a36Sopenharmony_ci Fabric_DID_MASK) && 535962306a36Sopenharmony_ci (!(vport->fc_flag & FC_OFFLINE_MODE))) 536062306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_UNREG_INP; 536162306a36Sopenharmony_ci 536262306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, 536362306a36Sopenharmony_ci LOG_NODE | LOG_DISCOVERY, 536462306a36Sopenharmony_ci "1433 unreg_rpi UNREG x%x on " 536562306a36Sopenharmony_ci "NPort x%x deferred flg x%x " 536662306a36Sopenharmony_ci "Data:x%px\n", 536762306a36Sopenharmony_ci ndlp->nlp_rpi, ndlp->nlp_DID, 536862306a36Sopenharmony_ci ndlp->nlp_flag, ndlp); 536962306a36Sopenharmony_ci 537062306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); 537162306a36Sopenharmony_ci if (rc == MBX_NOT_FINISHED) { 537262306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_UNREG_INP; 537362306a36Sopenharmony_ci mempool_free(mbox, phba->mbox_mem_pool); 537462306a36Sopenharmony_ci acc_plogi = 1; 537562306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 537662306a36Sopenharmony_ci } 537762306a36Sopenharmony_ci } else { 537862306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, 537962306a36Sopenharmony_ci LOG_NODE | LOG_DISCOVERY, 538062306a36Sopenharmony_ci "1444 Failed to allocate mempool " 538162306a36Sopenharmony_ci "unreg_rpi UNREG x%x, " 538262306a36Sopenharmony_ci "DID x%x, flag x%x, " 538362306a36Sopenharmony_ci "ndlp x%px\n", 538462306a36Sopenharmony_ci ndlp->nlp_rpi, ndlp->nlp_DID, 538562306a36Sopenharmony_ci ndlp->nlp_flag, ndlp); 538662306a36Sopenharmony_ci 538762306a36Sopenharmony_ci /* Because mempool_alloc failed, we 538862306a36Sopenharmony_ci * will issue a LOGO here and keep the rpi alive if 538962306a36Sopenharmony_ci * not unloading. 539062306a36Sopenharmony_ci */ 539162306a36Sopenharmony_ci if (!(vport->load_flag & FC_UNLOADING)) { 539262306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_UNREG_INP; 539362306a36Sopenharmony_ci lpfc_issue_els_logo(vport, ndlp, 0); 539462306a36Sopenharmony_ci ndlp->nlp_prev_state = ndlp->nlp_state; 539562306a36Sopenharmony_ci lpfc_nlp_set_state(vport, ndlp, 539662306a36Sopenharmony_ci NLP_STE_NPR_NODE); 539762306a36Sopenharmony_ci } 539862306a36Sopenharmony_ci 539962306a36Sopenharmony_ci return 1; 540062306a36Sopenharmony_ci } 540162306a36Sopenharmony_ci lpfc_no_rpi(phba, ndlp); 540262306a36Sopenharmony_ciout: 540362306a36Sopenharmony_ci if (phba->sli_rev != LPFC_SLI_REV4) 540462306a36Sopenharmony_ci ndlp->nlp_rpi = 0; 540562306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_RPI_REGISTERED; 540662306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_NPR_ADISC; 540762306a36Sopenharmony_ci if (acc_plogi) 540862306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_LOGO_ACC; 540962306a36Sopenharmony_ci return 1; 541062306a36Sopenharmony_ci } 541162306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_LOGO_ACC; 541262306a36Sopenharmony_ci return 0; 541362306a36Sopenharmony_ci} 541462306a36Sopenharmony_ci 541562306a36Sopenharmony_ci/** 541662306a36Sopenharmony_ci * lpfc_unreg_hba_rpis - Unregister rpis registered to the hba. 541762306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 541862306a36Sopenharmony_ci * 541962306a36Sopenharmony_ci * This routine is invoked to unregister all the currently registered RPIs 542062306a36Sopenharmony_ci * to the HBA. 542162306a36Sopenharmony_ci **/ 542262306a36Sopenharmony_civoid 542362306a36Sopenharmony_cilpfc_unreg_hba_rpis(struct lpfc_hba *phba) 542462306a36Sopenharmony_ci{ 542562306a36Sopenharmony_ci struct lpfc_vport **vports; 542662306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 542762306a36Sopenharmony_ci struct Scsi_Host *shost; 542862306a36Sopenharmony_ci int i; 542962306a36Sopenharmony_ci 543062306a36Sopenharmony_ci vports = lpfc_create_vport_work_array(phba); 543162306a36Sopenharmony_ci if (!vports) { 543262306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 543362306a36Sopenharmony_ci "2884 Vport array allocation failed \n"); 543462306a36Sopenharmony_ci return; 543562306a36Sopenharmony_ci } 543662306a36Sopenharmony_ci for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { 543762306a36Sopenharmony_ci shost = lpfc_shost_from_vport(vports[i]); 543862306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 543962306a36Sopenharmony_ci list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) { 544062306a36Sopenharmony_ci if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { 544162306a36Sopenharmony_ci /* The mempool_alloc might sleep */ 544262306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 544362306a36Sopenharmony_ci lpfc_unreg_rpi(vports[i], ndlp); 544462306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 544562306a36Sopenharmony_ci } 544662306a36Sopenharmony_ci } 544762306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 544862306a36Sopenharmony_ci } 544962306a36Sopenharmony_ci lpfc_destroy_vport_work_array(phba, vports); 545062306a36Sopenharmony_ci} 545162306a36Sopenharmony_ci 545262306a36Sopenharmony_civoid 545362306a36Sopenharmony_cilpfc_unreg_all_rpis(struct lpfc_vport *vport) 545462306a36Sopenharmony_ci{ 545562306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 545662306a36Sopenharmony_ci LPFC_MBOXQ_t *mbox; 545762306a36Sopenharmony_ci int rc; 545862306a36Sopenharmony_ci 545962306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4) { 546062306a36Sopenharmony_ci lpfc_sli4_unreg_all_rpis(vport); 546162306a36Sopenharmony_ci return; 546262306a36Sopenharmony_ci } 546362306a36Sopenharmony_ci 546462306a36Sopenharmony_ci mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 546562306a36Sopenharmony_ci if (mbox) { 546662306a36Sopenharmony_ci lpfc_unreg_login(phba, vport->vpi, LPFC_UNREG_ALL_RPIS_VPORT, 546762306a36Sopenharmony_ci mbox); 546862306a36Sopenharmony_ci mbox->vport = vport; 546962306a36Sopenharmony_ci mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; 547062306a36Sopenharmony_ci mbox->ctx_ndlp = NULL; 547162306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); 547262306a36Sopenharmony_ci if (rc != MBX_TIMEOUT) 547362306a36Sopenharmony_ci mempool_free(mbox, phba->mbox_mem_pool); 547462306a36Sopenharmony_ci 547562306a36Sopenharmony_ci if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED)) 547662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 547762306a36Sopenharmony_ci "1836 Could not issue " 547862306a36Sopenharmony_ci "unreg_login(all_rpis) status %d\n", 547962306a36Sopenharmony_ci rc); 548062306a36Sopenharmony_ci } 548162306a36Sopenharmony_ci} 548262306a36Sopenharmony_ci 548362306a36Sopenharmony_civoid 548462306a36Sopenharmony_cilpfc_unreg_default_rpis(struct lpfc_vport *vport) 548562306a36Sopenharmony_ci{ 548662306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 548762306a36Sopenharmony_ci LPFC_MBOXQ_t *mbox; 548862306a36Sopenharmony_ci int rc; 548962306a36Sopenharmony_ci 549062306a36Sopenharmony_ci /* Unreg DID is an SLI3 operation. */ 549162306a36Sopenharmony_ci if (phba->sli_rev > LPFC_SLI_REV3) 549262306a36Sopenharmony_ci return; 549362306a36Sopenharmony_ci 549462306a36Sopenharmony_ci mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 549562306a36Sopenharmony_ci if (mbox) { 549662306a36Sopenharmony_ci lpfc_unreg_did(phba, vport->vpi, LPFC_UNREG_ALL_DFLT_RPIS, 549762306a36Sopenharmony_ci mbox); 549862306a36Sopenharmony_ci mbox->vport = vport; 549962306a36Sopenharmony_ci mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; 550062306a36Sopenharmony_ci mbox->ctx_ndlp = NULL; 550162306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); 550262306a36Sopenharmony_ci if (rc != MBX_TIMEOUT) 550362306a36Sopenharmony_ci mempool_free(mbox, phba->mbox_mem_pool); 550462306a36Sopenharmony_ci 550562306a36Sopenharmony_ci if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED)) 550662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, 550762306a36Sopenharmony_ci "1815 Could not issue " 550862306a36Sopenharmony_ci "unreg_did (default rpis) status %d\n", 550962306a36Sopenharmony_ci rc); 551062306a36Sopenharmony_ci } 551162306a36Sopenharmony_ci} 551262306a36Sopenharmony_ci 551362306a36Sopenharmony_ci/* 551462306a36Sopenharmony_ci * Free resources associated with LPFC_NODELIST entry 551562306a36Sopenharmony_ci * so it can be freed. 551662306a36Sopenharmony_ci */ 551762306a36Sopenharmony_cistatic int 551862306a36Sopenharmony_cilpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) 551962306a36Sopenharmony_ci{ 552062306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 552162306a36Sopenharmony_ci LPFC_MBOXQ_t *mb, *nextmb; 552262306a36Sopenharmony_ci 552362306a36Sopenharmony_ci /* Cleanup node for NPort <nlp_DID> */ 552462306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 552562306a36Sopenharmony_ci "0900 Cleanup node for NPort x%x " 552662306a36Sopenharmony_ci "Data: x%x x%x x%x\n", 552762306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_flag, 552862306a36Sopenharmony_ci ndlp->nlp_state, ndlp->nlp_rpi); 552962306a36Sopenharmony_ci lpfc_dequeue_node(vport, ndlp); 553062306a36Sopenharmony_ci 553162306a36Sopenharmony_ci /* Don't need to clean up REG_LOGIN64 cmds for Default RPI cleanup */ 553262306a36Sopenharmony_ci 553362306a36Sopenharmony_ci /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ 553462306a36Sopenharmony_ci if ((mb = phba->sli.mbox_active)) { 553562306a36Sopenharmony_ci if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && 553662306a36Sopenharmony_ci !(mb->mbox_flag & LPFC_MBX_IMED_UNREG) && 553762306a36Sopenharmony_ci (ndlp == (struct lpfc_nodelist *)mb->ctx_ndlp)) { 553862306a36Sopenharmony_ci mb->ctx_ndlp = NULL; 553962306a36Sopenharmony_ci mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; 554062306a36Sopenharmony_ci } 554162306a36Sopenharmony_ci } 554262306a36Sopenharmony_ci 554362306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 554462306a36Sopenharmony_ci /* Cleanup REG_LOGIN completions which are not yet processed */ 554562306a36Sopenharmony_ci list_for_each_entry(mb, &phba->sli.mboxq_cmpl, list) { 554662306a36Sopenharmony_ci if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) || 554762306a36Sopenharmony_ci (mb->mbox_flag & LPFC_MBX_IMED_UNREG) || 554862306a36Sopenharmony_ci (ndlp != (struct lpfc_nodelist *)mb->ctx_ndlp)) 554962306a36Sopenharmony_ci continue; 555062306a36Sopenharmony_ci 555162306a36Sopenharmony_ci mb->ctx_ndlp = NULL; 555262306a36Sopenharmony_ci mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; 555362306a36Sopenharmony_ci } 555462306a36Sopenharmony_ci 555562306a36Sopenharmony_ci list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { 555662306a36Sopenharmony_ci if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && 555762306a36Sopenharmony_ci !(mb->mbox_flag & LPFC_MBX_IMED_UNREG) && 555862306a36Sopenharmony_ci (ndlp == (struct lpfc_nodelist *)mb->ctx_ndlp)) { 555962306a36Sopenharmony_ci list_del(&mb->list); 556062306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, mb, MBOX_THD_LOCKED); 556162306a36Sopenharmony_ci 556262306a36Sopenharmony_ci /* Don't invoke lpfc_nlp_put. The driver is in 556362306a36Sopenharmony_ci * lpfc_nlp_release context. 556462306a36Sopenharmony_ci */ 556562306a36Sopenharmony_ci } 556662306a36Sopenharmony_ci } 556762306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 556862306a36Sopenharmony_ci 556962306a36Sopenharmony_ci lpfc_els_abort(phba, ndlp); 557062306a36Sopenharmony_ci 557162306a36Sopenharmony_ci spin_lock_irq(&ndlp->lock); 557262306a36Sopenharmony_ci ndlp->nlp_flag &= ~NLP_DELAY_TMO; 557362306a36Sopenharmony_ci spin_unlock_irq(&ndlp->lock); 557462306a36Sopenharmony_ci 557562306a36Sopenharmony_ci ndlp->nlp_last_elscmd = 0; 557662306a36Sopenharmony_ci del_timer_sync(&ndlp->nlp_delayfunc); 557762306a36Sopenharmony_ci 557862306a36Sopenharmony_ci list_del_init(&ndlp->els_retry_evt.evt_listp); 557962306a36Sopenharmony_ci list_del_init(&ndlp->dev_loss_evt.evt_listp); 558062306a36Sopenharmony_ci list_del_init(&ndlp->recovery_evt.evt_listp); 558162306a36Sopenharmony_ci lpfc_cleanup_vports_rrqs(vport, ndlp); 558262306a36Sopenharmony_ci 558362306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4) 558462306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_RELEASE_RPI; 558562306a36Sopenharmony_ci 558662306a36Sopenharmony_ci return 0; 558762306a36Sopenharmony_ci} 558862306a36Sopenharmony_ci 558962306a36Sopenharmony_cistatic int 559062306a36Sopenharmony_cilpfc_matchdid(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, 559162306a36Sopenharmony_ci uint32_t did) 559262306a36Sopenharmony_ci{ 559362306a36Sopenharmony_ci D_ID mydid, ndlpdid, matchdid; 559462306a36Sopenharmony_ci 559562306a36Sopenharmony_ci if (did == Bcast_DID) 559662306a36Sopenharmony_ci return 0; 559762306a36Sopenharmony_ci 559862306a36Sopenharmony_ci /* First check for Direct match */ 559962306a36Sopenharmony_ci if (ndlp->nlp_DID == did) 560062306a36Sopenharmony_ci return 1; 560162306a36Sopenharmony_ci 560262306a36Sopenharmony_ci /* Next check for area/domain identically equals 0 match */ 560362306a36Sopenharmony_ci mydid.un.word = vport->fc_myDID; 560462306a36Sopenharmony_ci if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) { 560562306a36Sopenharmony_ci return 0; 560662306a36Sopenharmony_ci } 560762306a36Sopenharmony_ci 560862306a36Sopenharmony_ci matchdid.un.word = did; 560962306a36Sopenharmony_ci ndlpdid.un.word = ndlp->nlp_DID; 561062306a36Sopenharmony_ci if (matchdid.un.b.id == ndlpdid.un.b.id) { 561162306a36Sopenharmony_ci if ((mydid.un.b.domain == matchdid.un.b.domain) && 561262306a36Sopenharmony_ci (mydid.un.b.area == matchdid.un.b.area)) { 561362306a36Sopenharmony_ci /* This code is supposed to match the ID 561462306a36Sopenharmony_ci * for a private loop device that is 561562306a36Sopenharmony_ci * connect to fl_port. But we need to 561662306a36Sopenharmony_ci * check that the port did not just go 561762306a36Sopenharmony_ci * from pt2pt to fabric or we could end 561862306a36Sopenharmony_ci * up matching ndlp->nlp_DID 000001 to 561962306a36Sopenharmony_ci * fabric DID 0x20101 562062306a36Sopenharmony_ci */ 562162306a36Sopenharmony_ci if ((ndlpdid.un.b.domain == 0) && 562262306a36Sopenharmony_ci (ndlpdid.un.b.area == 0)) { 562362306a36Sopenharmony_ci if (ndlpdid.un.b.id && 562462306a36Sopenharmony_ci vport->phba->fc_topology == 562562306a36Sopenharmony_ci LPFC_TOPOLOGY_LOOP) 562662306a36Sopenharmony_ci return 1; 562762306a36Sopenharmony_ci } 562862306a36Sopenharmony_ci return 0; 562962306a36Sopenharmony_ci } 563062306a36Sopenharmony_ci 563162306a36Sopenharmony_ci matchdid.un.word = ndlp->nlp_DID; 563262306a36Sopenharmony_ci if ((mydid.un.b.domain == ndlpdid.un.b.domain) && 563362306a36Sopenharmony_ci (mydid.un.b.area == ndlpdid.un.b.area)) { 563462306a36Sopenharmony_ci if ((matchdid.un.b.domain == 0) && 563562306a36Sopenharmony_ci (matchdid.un.b.area == 0)) { 563662306a36Sopenharmony_ci if (matchdid.un.b.id) 563762306a36Sopenharmony_ci return 1; 563862306a36Sopenharmony_ci } 563962306a36Sopenharmony_ci } 564062306a36Sopenharmony_ci } 564162306a36Sopenharmony_ci return 0; 564262306a36Sopenharmony_ci} 564362306a36Sopenharmony_ci 564462306a36Sopenharmony_ci/* Search for a nodelist entry */ 564562306a36Sopenharmony_cistatic struct lpfc_nodelist * 564662306a36Sopenharmony_ci__lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) 564762306a36Sopenharmony_ci{ 564862306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 564962306a36Sopenharmony_ci uint32_t data1; 565062306a36Sopenharmony_ci 565162306a36Sopenharmony_ci list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { 565262306a36Sopenharmony_ci if (lpfc_matchdid(vport, ndlp, did)) { 565362306a36Sopenharmony_ci data1 = (((uint32_t)ndlp->nlp_state << 24) | 565462306a36Sopenharmony_ci ((uint32_t)ndlp->nlp_xri << 16) | 565562306a36Sopenharmony_ci ((uint32_t)ndlp->nlp_type << 8) 565662306a36Sopenharmony_ci ); 565762306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 565862306a36Sopenharmony_ci "0929 FIND node DID " 565962306a36Sopenharmony_ci "Data: x%px x%x x%x x%x x%x x%px\n", 566062306a36Sopenharmony_ci ndlp, ndlp->nlp_DID, 566162306a36Sopenharmony_ci ndlp->nlp_flag, data1, ndlp->nlp_rpi, 566262306a36Sopenharmony_ci ndlp->active_rrqs_xri_bitmap); 566362306a36Sopenharmony_ci return ndlp; 566462306a36Sopenharmony_ci } 566562306a36Sopenharmony_ci } 566662306a36Sopenharmony_ci 566762306a36Sopenharmony_ci /* FIND node did <did> NOT FOUND */ 566862306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 566962306a36Sopenharmony_ci "0932 FIND node did x%x NOT FOUND.\n", did); 567062306a36Sopenharmony_ci return NULL; 567162306a36Sopenharmony_ci} 567262306a36Sopenharmony_ci 567362306a36Sopenharmony_cistruct lpfc_nodelist * 567462306a36Sopenharmony_cilpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) 567562306a36Sopenharmony_ci{ 567662306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 567762306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 567862306a36Sopenharmony_ci unsigned long iflags; 567962306a36Sopenharmony_ci 568062306a36Sopenharmony_ci spin_lock_irqsave(shost->host_lock, iflags); 568162306a36Sopenharmony_ci ndlp = __lpfc_findnode_did(vport, did); 568262306a36Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, iflags); 568362306a36Sopenharmony_ci return ndlp; 568462306a36Sopenharmony_ci} 568562306a36Sopenharmony_ci 568662306a36Sopenharmony_cistruct lpfc_nodelist * 568762306a36Sopenharmony_cilpfc_findnode_mapped(struct lpfc_vport *vport) 568862306a36Sopenharmony_ci{ 568962306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 569062306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 569162306a36Sopenharmony_ci uint32_t data1; 569262306a36Sopenharmony_ci unsigned long iflags; 569362306a36Sopenharmony_ci 569462306a36Sopenharmony_ci spin_lock_irqsave(shost->host_lock, iflags); 569562306a36Sopenharmony_ci 569662306a36Sopenharmony_ci list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { 569762306a36Sopenharmony_ci if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE || 569862306a36Sopenharmony_ci ndlp->nlp_state == NLP_STE_MAPPED_NODE) { 569962306a36Sopenharmony_ci data1 = (((uint32_t)ndlp->nlp_state << 24) | 570062306a36Sopenharmony_ci ((uint32_t)ndlp->nlp_xri << 16) | 570162306a36Sopenharmony_ci ((uint32_t)ndlp->nlp_type << 8) | 570262306a36Sopenharmony_ci ((uint32_t)ndlp->nlp_rpi & 0xff)); 570362306a36Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, iflags); 570462306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 570562306a36Sopenharmony_ci "2025 FIND node DID " 570662306a36Sopenharmony_ci "Data: x%px x%x x%x x%x x%px\n", 570762306a36Sopenharmony_ci ndlp, ndlp->nlp_DID, 570862306a36Sopenharmony_ci ndlp->nlp_flag, data1, 570962306a36Sopenharmony_ci ndlp->active_rrqs_xri_bitmap); 571062306a36Sopenharmony_ci return ndlp; 571162306a36Sopenharmony_ci } 571262306a36Sopenharmony_ci } 571362306a36Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, iflags); 571462306a36Sopenharmony_ci 571562306a36Sopenharmony_ci /* FIND node did <did> NOT FOUND */ 571662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 571762306a36Sopenharmony_ci "2026 FIND mapped did NOT FOUND.\n"); 571862306a36Sopenharmony_ci return NULL; 571962306a36Sopenharmony_ci} 572062306a36Sopenharmony_ci 572162306a36Sopenharmony_cistruct lpfc_nodelist * 572262306a36Sopenharmony_cilpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) 572362306a36Sopenharmony_ci{ 572462306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 572562306a36Sopenharmony_ci 572662306a36Sopenharmony_ci ndlp = lpfc_findnode_did(vport, did); 572762306a36Sopenharmony_ci if (!ndlp) { 572862306a36Sopenharmony_ci if (vport->phba->nvmet_support) 572962306a36Sopenharmony_ci return NULL; 573062306a36Sopenharmony_ci if ((vport->fc_flag & FC_RSCN_MODE) != 0 && 573162306a36Sopenharmony_ci lpfc_rscn_payload_check(vport, did) == 0) 573262306a36Sopenharmony_ci return NULL; 573362306a36Sopenharmony_ci ndlp = lpfc_nlp_init(vport, did); 573462306a36Sopenharmony_ci if (!ndlp) 573562306a36Sopenharmony_ci return NULL; 573662306a36Sopenharmony_ci lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); 573762306a36Sopenharmony_ci 573862306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 573962306a36Sopenharmony_ci "6453 Setup New Node 2B_DISC x%x " 574062306a36Sopenharmony_ci "Data:x%x x%x x%x\n", 574162306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_flag, 574262306a36Sopenharmony_ci ndlp->nlp_state, vport->fc_flag); 574362306a36Sopenharmony_ci 574462306a36Sopenharmony_ci spin_lock_irq(&ndlp->lock); 574562306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_NPR_2B_DISC; 574662306a36Sopenharmony_ci spin_unlock_irq(&ndlp->lock); 574762306a36Sopenharmony_ci return ndlp; 574862306a36Sopenharmony_ci } 574962306a36Sopenharmony_ci 575062306a36Sopenharmony_ci /* The NVME Target does not want to actively manage an rport. 575162306a36Sopenharmony_ci * The goal is to allow the target to reset its state and clear 575262306a36Sopenharmony_ci * pending IO in preparation for the initiator to recover. 575362306a36Sopenharmony_ci */ 575462306a36Sopenharmony_ci if ((vport->fc_flag & FC_RSCN_MODE) && 575562306a36Sopenharmony_ci !(vport->fc_flag & FC_NDISC_ACTIVE)) { 575662306a36Sopenharmony_ci if (lpfc_rscn_payload_check(vport, did)) { 575762306a36Sopenharmony_ci 575862306a36Sopenharmony_ci /* Since this node is marked for discovery, 575962306a36Sopenharmony_ci * delay timeout is not needed. 576062306a36Sopenharmony_ci */ 576162306a36Sopenharmony_ci lpfc_cancel_retry_delay_tmo(vport, ndlp); 576262306a36Sopenharmony_ci 576362306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 576462306a36Sopenharmony_ci "6455 Setup RSCN Node 2B_DISC x%x " 576562306a36Sopenharmony_ci "Data:x%x x%x x%x\n", 576662306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_flag, 576762306a36Sopenharmony_ci ndlp->nlp_state, vport->fc_flag); 576862306a36Sopenharmony_ci 576962306a36Sopenharmony_ci /* NVME Target mode waits until rport is known to be 577062306a36Sopenharmony_ci * impacted by the RSCN before it transitions. No 577162306a36Sopenharmony_ci * active management - just go to NPR provided the 577262306a36Sopenharmony_ci * node had a valid login. 577362306a36Sopenharmony_ci */ 577462306a36Sopenharmony_ci if (vport->phba->nvmet_support) 577562306a36Sopenharmony_ci return ndlp; 577662306a36Sopenharmony_ci 577762306a36Sopenharmony_ci /* If we've already received a PLOGI from this NPort 577862306a36Sopenharmony_ci * we don't need to try to discover it again. 577962306a36Sopenharmony_ci */ 578062306a36Sopenharmony_ci if (ndlp->nlp_flag & NLP_RCV_PLOGI && 578162306a36Sopenharmony_ci !(ndlp->nlp_type & 578262306a36Sopenharmony_ci (NLP_FCP_TARGET | NLP_NVME_TARGET))) 578362306a36Sopenharmony_ci return NULL; 578462306a36Sopenharmony_ci 578562306a36Sopenharmony_ci if (ndlp->nlp_state > NLP_STE_UNUSED_NODE && 578662306a36Sopenharmony_ci ndlp->nlp_state < NLP_STE_PRLI_ISSUE) { 578762306a36Sopenharmony_ci lpfc_disc_state_machine(vport, ndlp, NULL, 578862306a36Sopenharmony_ci NLP_EVT_DEVICE_RECOVERY); 578962306a36Sopenharmony_ci } 579062306a36Sopenharmony_ci 579162306a36Sopenharmony_ci spin_lock_irq(&ndlp->lock); 579262306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_NPR_2B_DISC; 579362306a36Sopenharmony_ci spin_unlock_irq(&ndlp->lock); 579462306a36Sopenharmony_ci } else { 579562306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 579662306a36Sopenharmony_ci "6456 Skip Setup RSCN Node x%x " 579762306a36Sopenharmony_ci "Data:x%x x%x x%x\n", 579862306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_flag, 579962306a36Sopenharmony_ci ndlp->nlp_state, vport->fc_flag); 580062306a36Sopenharmony_ci ndlp = NULL; 580162306a36Sopenharmony_ci } 580262306a36Sopenharmony_ci } else { 580362306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 580462306a36Sopenharmony_ci "6457 Setup Active Node 2B_DISC x%x " 580562306a36Sopenharmony_ci "Data:x%x x%x x%x\n", 580662306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_flag, 580762306a36Sopenharmony_ci ndlp->nlp_state, vport->fc_flag); 580862306a36Sopenharmony_ci 580962306a36Sopenharmony_ci /* If the initiator received a PLOGI from this NPort or if the 581062306a36Sopenharmony_ci * initiator is already in the process of discovery on it, 581162306a36Sopenharmony_ci * there's no need to try to discover it again. 581262306a36Sopenharmony_ci */ 581362306a36Sopenharmony_ci if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE || 581462306a36Sopenharmony_ci ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || 581562306a36Sopenharmony_ci (!vport->phba->nvmet_support && 581662306a36Sopenharmony_ci ndlp->nlp_flag & NLP_RCV_PLOGI)) 581762306a36Sopenharmony_ci return NULL; 581862306a36Sopenharmony_ci 581962306a36Sopenharmony_ci if (vport->phba->nvmet_support) 582062306a36Sopenharmony_ci return ndlp; 582162306a36Sopenharmony_ci 582262306a36Sopenharmony_ci /* Moving to NPR state clears unsolicited flags and 582362306a36Sopenharmony_ci * allows for rediscovery 582462306a36Sopenharmony_ci */ 582562306a36Sopenharmony_ci lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); 582662306a36Sopenharmony_ci 582762306a36Sopenharmony_ci spin_lock_irq(&ndlp->lock); 582862306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_NPR_2B_DISC; 582962306a36Sopenharmony_ci spin_unlock_irq(&ndlp->lock); 583062306a36Sopenharmony_ci } 583162306a36Sopenharmony_ci return ndlp; 583262306a36Sopenharmony_ci} 583362306a36Sopenharmony_ci 583462306a36Sopenharmony_ci/* Build a list of nodes to discover based on the loopmap */ 583562306a36Sopenharmony_civoid 583662306a36Sopenharmony_cilpfc_disc_list_loopmap(struct lpfc_vport *vport) 583762306a36Sopenharmony_ci{ 583862306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 583962306a36Sopenharmony_ci int j; 584062306a36Sopenharmony_ci uint32_t alpa, index; 584162306a36Sopenharmony_ci 584262306a36Sopenharmony_ci if (!lpfc_is_link_up(phba)) 584362306a36Sopenharmony_ci return; 584462306a36Sopenharmony_ci 584562306a36Sopenharmony_ci if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) 584662306a36Sopenharmony_ci return; 584762306a36Sopenharmony_ci 584862306a36Sopenharmony_ci /* Check for loop map present or not */ 584962306a36Sopenharmony_ci if (phba->alpa_map[0]) { 585062306a36Sopenharmony_ci for (j = 1; j <= phba->alpa_map[0]; j++) { 585162306a36Sopenharmony_ci alpa = phba->alpa_map[j]; 585262306a36Sopenharmony_ci if (((vport->fc_myDID & 0xff) == alpa) || (alpa == 0)) 585362306a36Sopenharmony_ci continue; 585462306a36Sopenharmony_ci lpfc_setup_disc_node(vport, alpa); 585562306a36Sopenharmony_ci } 585662306a36Sopenharmony_ci } else { 585762306a36Sopenharmony_ci /* No alpamap, so try all alpa's */ 585862306a36Sopenharmony_ci for (j = 0; j < FC_MAXLOOP; j++) { 585962306a36Sopenharmony_ci /* If cfg_scan_down is set, start from highest 586062306a36Sopenharmony_ci * ALPA (0xef) to lowest (0x1). 586162306a36Sopenharmony_ci */ 586262306a36Sopenharmony_ci if (vport->cfg_scan_down) 586362306a36Sopenharmony_ci index = j; 586462306a36Sopenharmony_ci else 586562306a36Sopenharmony_ci index = FC_MAXLOOP - j - 1; 586662306a36Sopenharmony_ci alpa = lpfcAlpaArray[index]; 586762306a36Sopenharmony_ci if ((vport->fc_myDID & 0xff) == alpa) 586862306a36Sopenharmony_ci continue; 586962306a36Sopenharmony_ci lpfc_setup_disc_node(vport, alpa); 587062306a36Sopenharmony_ci } 587162306a36Sopenharmony_ci } 587262306a36Sopenharmony_ci return; 587362306a36Sopenharmony_ci} 587462306a36Sopenharmony_ci 587562306a36Sopenharmony_ci/* SLI3 only */ 587662306a36Sopenharmony_civoid 587762306a36Sopenharmony_cilpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport) 587862306a36Sopenharmony_ci{ 587962306a36Sopenharmony_ci LPFC_MBOXQ_t *mbox; 588062306a36Sopenharmony_ci struct lpfc_sli *psli = &phba->sli; 588162306a36Sopenharmony_ci struct lpfc_sli_ring *extra_ring = &psli->sli3_ring[LPFC_EXTRA_RING]; 588262306a36Sopenharmony_ci struct lpfc_sli_ring *fcp_ring = &psli->sli3_ring[LPFC_FCP_RING]; 588362306a36Sopenharmony_ci int rc; 588462306a36Sopenharmony_ci 588562306a36Sopenharmony_ci /* 588662306a36Sopenharmony_ci * if it's not a physical port or if we already send 588762306a36Sopenharmony_ci * clear_la then don't send it. 588862306a36Sopenharmony_ci */ 588962306a36Sopenharmony_ci if ((phba->link_state >= LPFC_CLEAR_LA) || 589062306a36Sopenharmony_ci (vport->port_type != LPFC_PHYSICAL_PORT) || 589162306a36Sopenharmony_ci (phba->sli_rev == LPFC_SLI_REV4)) 589262306a36Sopenharmony_ci return; 589362306a36Sopenharmony_ci 589462306a36Sopenharmony_ci /* Link up discovery */ 589562306a36Sopenharmony_ci if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) != NULL) { 589662306a36Sopenharmony_ci phba->link_state = LPFC_CLEAR_LA; 589762306a36Sopenharmony_ci lpfc_clear_la(phba, mbox); 589862306a36Sopenharmony_ci mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; 589962306a36Sopenharmony_ci mbox->vport = vport; 590062306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); 590162306a36Sopenharmony_ci if (rc == MBX_NOT_FINISHED) { 590262306a36Sopenharmony_ci mempool_free(mbox, phba->mbox_mem_pool); 590362306a36Sopenharmony_ci lpfc_disc_flush_list(vport); 590462306a36Sopenharmony_ci extra_ring->flag &= ~LPFC_STOP_IOCB_EVENT; 590562306a36Sopenharmony_ci fcp_ring->flag &= ~LPFC_STOP_IOCB_EVENT; 590662306a36Sopenharmony_ci phba->link_state = LPFC_HBA_ERROR; 590762306a36Sopenharmony_ci } 590862306a36Sopenharmony_ci } 590962306a36Sopenharmony_ci} 591062306a36Sopenharmony_ci 591162306a36Sopenharmony_ci/* Reg_vpi to tell firmware to resume normal operations */ 591262306a36Sopenharmony_civoid 591362306a36Sopenharmony_cilpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport) 591462306a36Sopenharmony_ci{ 591562306a36Sopenharmony_ci LPFC_MBOXQ_t *regvpimbox; 591662306a36Sopenharmony_ci 591762306a36Sopenharmony_ci regvpimbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 591862306a36Sopenharmony_ci if (regvpimbox) { 591962306a36Sopenharmony_ci lpfc_reg_vpi(vport, regvpimbox); 592062306a36Sopenharmony_ci regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi; 592162306a36Sopenharmony_ci regvpimbox->vport = vport; 592262306a36Sopenharmony_ci if (lpfc_sli_issue_mbox(phba, regvpimbox, MBX_NOWAIT) 592362306a36Sopenharmony_ci == MBX_NOT_FINISHED) { 592462306a36Sopenharmony_ci mempool_free(regvpimbox, phba->mbox_mem_pool); 592562306a36Sopenharmony_ci } 592662306a36Sopenharmony_ci } 592762306a36Sopenharmony_ci} 592862306a36Sopenharmony_ci 592962306a36Sopenharmony_ci/* Start Link up / RSCN discovery on NPR nodes */ 593062306a36Sopenharmony_civoid 593162306a36Sopenharmony_cilpfc_disc_start(struct lpfc_vport *vport) 593262306a36Sopenharmony_ci{ 593362306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 593462306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 593562306a36Sopenharmony_ci uint32_t num_sent; 593662306a36Sopenharmony_ci uint32_t clear_la_pending; 593762306a36Sopenharmony_ci 593862306a36Sopenharmony_ci if (!lpfc_is_link_up(phba)) { 593962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, 594062306a36Sopenharmony_ci "3315 Link is not up %x\n", 594162306a36Sopenharmony_ci phba->link_state); 594262306a36Sopenharmony_ci return; 594362306a36Sopenharmony_ci } 594462306a36Sopenharmony_ci 594562306a36Sopenharmony_ci if (phba->link_state == LPFC_CLEAR_LA) 594662306a36Sopenharmony_ci clear_la_pending = 1; 594762306a36Sopenharmony_ci else 594862306a36Sopenharmony_ci clear_la_pending = 0; 594962306a36Sopenharmony_ci 595062306a36Sopenharmony_ci if (vport->port_state < LPFC_VPORT_READY) 595162306a36Sopenharmony_ci vport->port_state = LPFC_DISC_AUTH; 595262306a36Sopenharmony_ci 595362306a36Sopenharmony_ci lpfc_set_disctmo(vport); 595462306a36Sopenharmony_ci 595562306a36Sopenharmony_ci vport->fc_prevDID = vport->fc_myDID; 595662306a36Sopenharmony_ci vport->num_disc_nodes = 0; 595762306a36Sopenharmony_ci 595862306a36Sopenharmony_ci /* Start Discovery state <hba_state> */ 595962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 596062306a36Sopenharmony_ci "0202 Start Discovery port state x%x " 596162306a36Sopenharmony_ci "flg x%x Data: x%x x%x x%x\n", 596262306a36Sopenharmony_ci vport->port_state, vport->fc_flag, vport->fc_plogi_cnt, 596362306a36Sopenharmony_ci vport->fc_adisc_cnt, vport->fc_npr_cnt); 596462306a36Sopenharmony_ci 596562306a36Sopenharmony_ci /* First do ADISCs - if any */ 596662306a36Sopenharmony_ci num_sent = lpfc_els_disc_adisc(vport); 596762306a36Sopenharmony_ci 596862306a36Sopenharmony_ci if (num_sent) 596962306a36Sopenharmony_ci return; 597062306a36Sopenharmony_ci 597162306a36Sopenharmony_ci /* Register the VPI for SLI3, NPIV only. */ 597262306a36Sopenharmony_ci if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && 597362306a36Sopenharmony_ci !(vport->fc_flag & FC_PT2PT) && 597462306a36Sopenharmony_ci !(vport->fc_flag & FC_RSCN_MODE) && 597562306a36Sopenharmony_ci (phba->sli_rev < LPFC_SLI_REV4)) { 597662306a36Sopenharmony_ci lpfc_issue_clear_la(phba, vport); 597762306a36Sopenharmony_ci lpfc_issue_reg_vpi(phba, vport); 597862306a36Sopenharmony_ci return; 597962306a36Sopenharmony_ci } 598062306a36Sopenharmony_ci 598162306a36Sopenharmony_ci /* 598262306a36Sopenharmony_ci * For SLI2, we need to set port_state to READY and continue 598362306a36Sopenharmony_ci * discovery. 598462306a36Sopenharmony_ci */ 598562306a36Sopenharmony_ci if (vport->port_state < LPFC_VPORT_READY && !clear_la_pending) { 598662306a36Sopenharmony_ci /* If we get here, there is nothing to ADISC */ 598762306a36Sopenharmony_ci lpfc_issue_clear_la(phba, vport); 598862306a36Sopenharmony_ci 598962306a36Sopenharmony_ci if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { 599062306a36Sopenharmony_ci vport->num_disc_nodes = 0; 599162306a36Sopenharmony_ci /* go thru NPR nodes and issue ELS PLOGIs */ 599262306a36Sopenharmony_ci if (vport->fc_npr_cnt) 599362306a36Sopenharmony_ci lpfc_els_disc_plogi(vport); 599462306a36Sopenharmony_ci 599562306a36Sopenharmony_ci if (!vport->num_disc_nodes) { 599662306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 599762306a36Sopenharmony_ci vport->fc_flag &= ~FC_NDISC_ACTIVE; 599862306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 599962306a36Sopenharmony_ci lpfc_can_disctmo(vport); 600062306a36Sopenharmony_ci } 600162306a36Sopenharmony_ci } 600262306a36Sopenharmony_ci vport->port_state = LPFC_VPORT_READY; 600362306a36Sopenharmony_ci } else { 600462306a36Sopenharmony_ci /* Next do PLOGIs - if any */ 600562306a36Sopenharmony_ci num_sent = lpfc_els_disc_plogi(vport); 600662306a36Sopenharmony_ci 600762306a36Sopenharmony_ci if (num_sent) 600862306a36Sopenharmony_ci return; 600962306a36Sopenharmony_ci 601062306a36Sopenharmony_ci if (vport->fc_flag & FC_RSCN_MODE) { 601162306a36Sopenharmony_ci /* Check to see if more RSCNs came in while we 601262306a36Sopenharmony_ci * were processing this one. 601362306a36Sopenharmony_ci */ 601462306a36Sopenharmony_ci if ((vport->fc_rscn_id_cnt == 0) && 601562306a36Sopenharmony_ci (!(vport->fc_flag & FC_RSCN_DISCOVERY))) { 601662306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 601762306a36Sopenharmony_ci vport->fc_flag &= ~FC_RSCN_MODE; 601862306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 601962306a36Sopenharmony_ci lpfc_can_disctmo(vport); 602062306a36Sopenharmony_ci } else 602162306a36Sopenharmony_ci lpfc_els_handle_rscn(vport); 602262306a36Sopenharmony_ci } 602362306a36Sopenharmony_ci } 602462306a36Sopenharmony_ci return; 602562306a36Sopenharmony_ci} 602662306a36Sopenharmony_ci 602762306a36Sopenharmony_ci/* 602862306a36Sopenharmony_ci * Ignore completion for all IOCBs on tx and txcmpl queue for ELS 602962306a36Sopenharmony_ci * ring the match the sppecified nodelist. 603062306a36Sopenharmony_ci */ 603162306a36Sopenharmony_cistatic void 603262306a36Sopenharmony_cilpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) 603362306a36Sopenharmony_ci{ 603462306a36Sopenharmony_ci LIST_HEAD(completions); 603562306a36Sopenharmony_ci struct lpfc_iocbq *iocb, *next_iocb; 603662306a36Sopenharmony_ci struct lpfc_sli_ring *pring; 603762306a36Sopenharmony_ci u32 ulp_command; 603862306a36Sopenharmony_ci 603962306a36Sopenharmony_ci pring = lpfc_phba_elsring(phba); 604062306a36Sopenharmony_ci if (unlikely(!pring)) 604162306a36Sopenharmony_ci return; 604262306a36Sopenharmony_ci 604362306a36Sopenharmony_ci /* Error matching iocb on txq or txcmplq 604462306a36Sopenharmony_ci * First check the txq. 604562306a36Sopenharmony_ci */ 604662306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 604762306a36Sopenharmony_ci list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { 604862306a36Sopenharmony_ci if (iocb->ndlp != ndlp) 604962306a36Sopenharmony_ci continue; 605062306a36Sopenharmony_ci 605162306a36Sopenharmony_ci ulp_command = get_job_cmnd(phba, iocb); 605262306a36Sopenharmony_ci 605362306a36Sopenharmony_ci if (ulp_command == CMD_ELS_REQUEST64_CR || 605462306a36Sopenharmony_ci ulp_command == CMD_XMIT_ELS_RSP64_CX) { 605562306a36Sopenharmony_ci 605662306a36Sopenharmony_ci list_move_tail(&iocb->list, &completions); 605762306a36Sopenharmony_ci } 605862306a36Sopenharmony_ci } 605962306a36Sopenharmony_ci 606062306a36Sopenharmony_ci /* Next check the txcmplq */ 606162306a36Sopenharmony_ci list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { 606262306a36Sopenharmony_ci if (iocb->ndlp != ndlp) 606362306a36Sopenharmony_ci continue; 606462306a36Sopenharmony_ci 606562306a36Sopenharmony_ci ulp_command = get_job_cmnd(phba, iocb); 606662306a36Sopenharmony_ci 606762306a36Sopenharmony_ci if (ulp_command == CMD_ELS_REQUEST64_CR || 606862306a36Sopenharmony_ci ulp_command == CMD_XMIT_ELS_RSP64_CX) { 606962306a36Sopenharmony_ci lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); 607062306a36Sopenharmony_ci } 607162306a36Sopenharmony_ci } 607262306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 607362306a36Sopenharmony_ci 607462306a36Sopenharmony_ci /* Make sure HBA is alive */ 607562306a36Sopenharmony_ci lpfc_issue_hb_tmo(phba); 607662306a36Sopenharmony_ci 607762306a36Sopenharmony_ci /* Cancel all the IOCBs from the completions list */ 607862306a36Sopenharmony_ci lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, 607962306a36Sopenharmony_ci IOERR_SLI_ABORTED); 608062306a36Sopenharmony_ci} 608162306a36Sopenharmony_ci 608262306a36Sopenharmony_cistatic void 608362306a36Sopenharmony_cilpfc_disc_flush_list(struct lpfc_vport *vport) 608462306a36Sopenharmony_ci{ 608562306a36Sopenharmony_ci struct lpfc_nodelist *ndlp, *next_ndlp; 608662306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 608762306a36Sopenharmony_ci 608862306a36Sopenharmony_ci if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) { 608962306a36Sopenharmony_ci list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, 609062306a36Sopenharmony_ci nlp_listp) { 609162306a36Sopenharmony_ci if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || 609262306a36Sopenharmony_ci ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { 609362306a36Sopenharmony_ci lpfc_free_tx(phba, ndlp); 609462306a36Sopenharmony_ci } 609562306a36Sopenharmony_ci } 609662306a36Sopenharmony_ci } 609762306a36Sopenharmony_ci} 609862306a36Sopenharmony_ci 609962306a36Sopenharmony_ci/* 610062306a36Sopenharmony_ci * lpfc_notify_xport_npr - notifies xport of node disappearance 610162306a36Sopenharmony_ci * @vport: Pointer to Virtual Port object. 610262306a36Sopenharmony_ci * 610362306a36Sopenharmony_ci * Transitions all ndlps to NPR state. When lpfc_nlp_set_state 610462306a36Sopenharmony_ci * calls lpfc_nlp_state_cleanup, the ndlp->rport is unregistered 610562306a36Sopenharmony_ci * and transport notified that the node is gone. 610662306a36Sopenharmony_ci * Return Code: 610762306a36Sopenharmony_ci * none 610862306a36Sopenharmony_ci */ 610962306a36Sopenharmony_cistatic void 611062306a36Sopenharmony_cilpfc_notify_xport_npr(struct lpfc_vport *vport) 611162306a36Sopenharmony_ci{ 611262306a36Sopenharmony_ci struct lpfc_nodelist *ndlp, *next_ndlp; 611362306a36Sopenharmony_ci 611462306a36Sopenharmony_ci list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, 611562306a36Sopenharmony_ci nlp_listp) { 611662306a36Sopenharmony_ci lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); 611762306a36Sopenharmony_ci } 611862306a36Sopenharmony_ci} 611962306a36Sopenharmony_civoid 612062306a36Sopenharmony_cilpfc_cleanup_discovery_resources(struct lpfc_vport *vport) 612162306a36Sopenharmony_ci{ 612262306a36Sopenharmony_ci lpfc_els_flush_rscn(vport); 612362306a36Sopenharmony_ci lpfc_els_flush_cmd(vport); 612462306a36Sopenharmony_ci lpfc_disc_flush_list(vport); 612562306a36Sopenharmony_ci if (pci_channel_offline(vport->phba->pcidev)) 612662306a36Sopenharmony_ci lpfc_notify_xport_npr(vport); 612762306a36Sopenharmony_ci} 612862306a36Sopenharmony_ci 612962306a36Sopenharmony_ci/*****************************************************************************/ 613062306a36Sopenharmony_ci/* 613162306a36Sopenharmony_ci * NAME: lpfc_disc_timeout 613262306a36Sopenharmony_ci * 613362306a36Sopenharmony_ci * FUNCTION: Fibre Channel driver discovery timeout routine. 613462306a36Sopenharmony_ci * 613562306a36Sopenharmony_ci * EXECUTION ENVIRONMENT: interrupt only 613662306a36Sopenharmony_ci * 613762306a36Sopenharmony_ci * CALLED FROM: 613862306a36Sopenharmony_ci * Timer function 613962306a36Sopenharmony_ci * 614062306a36Sopenharmony_ci * RETURNS: 614162306a36Sopenharmony_ci * none 614262306a36Sopenharmony_ci */ 614362306a36Sopenharmony_ci/*****************************************************************************/ 614462306a36Sopenharmony_civoid 614562306a36Sopenharmony_cilpfc_disc_timeout(struct timer_list *t) 614662306a36Sopenharmony_ci{ 614762306a36Sopenharmony_ci struct lpfc_vport *vport = from_timer(vport, t, fc_disctmo); 614862306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 614962306a36Sopenharmony_ci uint32_t tmo_posted; 615062306a36Sopenharmony_ci unsigned long flags = 0; 615162306a36Sopenharmony_ci 615262306a36Sopenharmony_ci if (unlikely(!phba)) 615362306a36Sopenharmony_ci return; 615462306a36Sopenharmony_ci 615562306a36Sopenharmony_ci spin_lock_irqsave(&vport->work_port_lock, flags); 615662306a36Sopenharmony_ci tmo_posted = vport->work_port_events & WORKER_DISC_TMO; 615762306a36Sopenharmony_ci if (!tmo_posted) 615862306a36Sopenharmony_ci vport->work_port_events |= WORKER_DISC_TMO; 615962306a36Sopenharmony_ci spin_unlock_irqrestore(&vport->work_port_lock, flags); 616062306a36Sopenharmony_ci 616162306a36Sopenharmony_ci if (!tmo_posted) 616262306a36Sopenharmony_ci lpfc_worker_wake_up(phba); 616362306a36Sopenharmony_ci return; 616462306a36Sopenharmony_ci} 616562306a36Sopenharmony_ci 616662306a36Sopenharmony_cistatic void 616762306a36Sopenharmony_cilpfc_disc_timeout_handler(struct lpfc_vport *vport) 616862306a36Sopenharmony_ci{ 616962306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 617062306a36Sopenharmony_ci struct lpfc_hba *phba = vport->phba; 617162306a36Sopenharmony_ci struct lpfc_sli *psli = &phba->sli; 617262306a36Sopenharmony_ci struct lpfc_nodelist *ndlp, *next_ndlp; 617362306a36Sopenharmony_ci LPFC_MBOXQ_t *initlinkmbox; 617462306a36Sopenharmony_ci int rc, clrlaerr = 0; 617562306a36Sopenharmony_ci 617662306a36Sopenharmony_ci if (!(vport->fc_flag & FC_DISC_TMO)) 617762306a36Sopenharmony_ci return; 617862306a36Sopenharmony_ci 617962306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 618062306a36Sopenharmony_ci vport->fc_flag &= ~FC_DISC_TMO; 618162306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 618262306a36Sopenharmony_ci 618362306a36Sopenharmony_ci lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, 618462306a36Sopenharmony_ci "disc timeout: state:x%x rtry:x%x flg:x%x", 618562306a36Sopenharmony_ci vport->port_state, vport->fc_ns_retry, vport->fc_flag); 618662306a36Sopenharmony_ci 618762306a36Sopenharmony_ci switch (vport->port_state) { 618862306a36Sopenharmony_ci 618962306a36Sopenharmony_ci case LPFC_LOCAL_CFG_LINK: 619062306a36Sopenharmony_ci /* 619162306a36Sopenharmony_ci * port_state is identically LPFC_LOCAL_CFG_LINK while 619262306a36Sopenharmony_ci * waiting for FAN timeout 619362306a36Sopenharmony_ci */ 619462306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY, 619562306a36Sopenharmony_ci "0221 FAN timeout\n"); 619662306a36Sopenharmony_ci 619762306a36Sopenharmony_ci /* Start discovery by sending FLOGI, clean up old rpis */ 619862306a36Sopenharmony_ci list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, 619962306a36Sopenharmony_ci nlp_listp) { 620062306a36Sopenharmony_ci if (ndlp->nlp_state != NLP_STE_NPR_NODE) 620162306a36Sopenharmony_ci continue; 620262306a36Sopenharmony_ci if (ndlp->nlp_type & NLP_FABRIC) { 620362306a36Sopenharmony_ci /* Clean up the ndlp on Fabric connections */ 620462306a36Sopenharmony_ci lpfc_drop_node(vport, ndlp); 620562306a36Sopenharmony_ci 620662306a36Sopenharmony_ci } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { 620762306a36Sopenharmony_ci /* Fail outstanding IO now since device 620862306a36Sopenharmony_ci * is marked for PLOGI. 620962306a36Sopenharmony_ci */ 621062306a36Sopenharmony_ci lpfc_unreg_rpi(vport, ndlp); 621162306a36Sopenharmony_ci } 621262306a36Sopenharmony_ci } 621362306a36Sopenharmony_ci if (vport->port_state != LPFC_FLOGI) { 621462306a36Sopenharmony_ci if (phba->sli_rev <= LPFC_SLI_REV3) 621562306a36Sopenharmony_ci lpfc_initial_flogi(vport); 621662306a36Sopenharmony_ci else 621762306a36Sopenharmony_ci lpfc_issue_init_vfi(vport); 621862306a36Sopenharmony_ci return; 621962306a36Sopenharmony_ci } 622062306a36Sopenharmony_ci break; 622162306a36Sopenharmony_ci 622262306a36Sopenharmony_ci case LPFC_FDISC: 622362306a36Sopenharmony_ci case LPFC_FLOGI: 622462306a36Sopenharmony_ci /* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */ 622562306a36Sopenharmony_ci /* Initial FLOGI timeout */ 622662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 622762306a36Sopenharmony_ci LOG_TRACE_EVENT, 622862306a36Sopenharmony_ci "0222 Initial %s timeout\n", 622962306a36Sopenharmony_ci vport->vpi ? "FDISC" : "FLOGI"); 623062306a36Sopenharmony_ci 623162306a36Sopenharmony_ci /* Assume no Fabric and go on with discovery. 623262306a36Sopenharmony_ci * Check for outstanding ELS FLOGI to abort. 623362306a36Sopenharmony_ci */ 623462306a36Sopenharmony_ci 623562306a36Sopenharmony_ci /* FLOGI failed, so just use loop map to make discovery list */ 623662306a36Sopenharmony_ci lpfc_disc_list_loopmap(vport); 623762306a36Sopenharmony_ci 623862306a36Sopenharmony_ci /* Start discovery */ 623962306a36Sopenharmony_ci lpfc_disc_start(vport); 624062306a36Sopenharmony_ci break; 624162306a36Sopenharmony_ci 624262306a36Sopenharmony_ci case LPFC_FABRIC_CFG_LINK: 624362306a36Sopenharmony_ci /* hba_state is identically LPFC_FABRIC_CFG_LINK while waiting for 624462306a36Sopenharmony_ci NameServer login */ 624562306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 624662306a36Sopenharmony_ci LOG_TRACE_EVENT, 624762306a36Sopenharmony_ci "0223 Timeout while waiting for " 624862306a36Sopenharmony_ci "NameServer login\n"); 624962306a36Sopenharmony_ci /* Next look for NameServer ndlp */ 625062306a36Sopenharmony_ci ndlp = lpfc_findnode_did(vport, NameServer_DID); 625162306a36Sopenharmony_ci if (ndlp) 625262306a36Sopenharmony_ci lpfc_els_abort(phba, ndlp); 625362306a36Sopenharmony_ci 625462306a36Sopenharmony_ci /* ReStart discovery */ 625562306a36Sopenharmony_ci goto restart_disc; 625662306a36Sopenharmony_ci 625762306a36Sopenharmony_ci case LPFC_NS_QRY: 625862306a36Sopenharmony_ci /* Check for wait for NameServer Rsp timeout */ 625962306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 626062306a36Sopenharmony_ci LOG_TRACE_EVENT, 626162306a36Sopenharmony_ci "0224 NameServer Query timeout " 626262306a36Sopenharmony_ci "Data: x%x x%x\n", 626362306a36Sopenharmony_ci vport->fc_ns_retry, LPFC_MAX_NS_RETRY); 626462306a36Sopenharmony_ci 626562306a36Sopenharmony_ci if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { 626662306a36Sopenharmony_ci /* Try it one more time */ 626762306a36Sopenharmony_ci vport->fc_ns_retry++; 626862306a36Sopenharmony_ci vport->gidft_inp = 0; 626962306a36Sopenharmony_ci rc = lpfc_issue_gidft(vport); 627062306a36Sopenharmony_ci if (rc == 0) 627162306a36Sopenharmony_ci break; 627262306a36Sopenharmony_ci } 627362306a36Sopenharmony_ci vport->fc_ns_retry = 0; 627462306a36Sopenharmony_ci 627562306a36Sopenharmony_cirestart_disc: 627662306a36Sopenharmony_ci /* 627762306a36Sopenharmony_ci * Discovery is over. 627862306a36Sopenharmony_ci * set port_state to PORT_READY if SLI2. 627962306a36Sopenharmony_ci * cmpl_reg_vpi will set port_state to READY for SLI3. 628062306a36Sopenharmony_ci */ 628162306a36Sopenharmony_ci if (phba->sli_rev < LPFC_SLI_REV4) { 628262306a36Sopenharmony_ci if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) 628362306a36Sopenharmony_ci lpfc_issue_reg_vpi(phba, vport); 628462306a36Sopenharmony_ci else { 628562306a36Sopenharmony_ci lpfc_issue_clear_la(phba, vport); 628662306a36Sopenharmony_ci vport->port_state = LPFC_VPORT_READY; 628762306a36Sopenharmony_ci } 628862306a36Sopenharmony_ci } 628962306a36Sopenharmony_ci 629062306a36Sopenharmony_ci /* Setup and issue mailbox INITIALIZE LINK command */ 629162306a36Sopenharmony_ci initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 629262306a36Sopenharmony_ci if (!initlinkmbox) { 629362306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 629462306a36Sopenharmony_ci LOG_TRACE_EVENT, 629562306a36Sopenharmony_ci "0206 Device Discovery " 629662306a36Sopenharmony_ci "completion error\n"); 629762306a36Sopenharmony_ci phba->link_state = LPFC_HBA_ERROR; 629862306a36Sopenharmony_ci break; 629962306a36Sopenharmony_ci } 630062306a36Sopenharmony_ci 630162306a36Sopenharmony_ci lpfc_linkdown(phba); 630262306a36Sopenharmony_ci lpfc_init_link(phba, initlinkmbox, phba->cfg_topology, 630362306a36Sopenharmony_ci phba->cfg_link_speed); 630462306a36Sopenharmony_ci initlinkmbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0; 630562306a36Sopenharmony_ci initlinkmbox->vport = vport; 630662306a36Sopenharmony_ci initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; 630762306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox(phba, initlinkmbox, MBX_NOWAIT); 630862306a36Sopenharmony_ci lpfc_set_loopback_flag(phba); 630962306a36Sopenharmony_ci if (rc == MBX_NOT_FINISHED) 631062306a36Sopenharmony_ci mempool_free(initlinkmbox, phba->mbox_mem_pool); 631162306a36Sopenharmony_ci 631262306a36Sopenharmony_ci break; 631362306a36Sopenharmony_ci 631462306a36Sopenharmony_ci case LPFC_DISC_AUTH: 631562306a36Sopenharmony_ci /* Node Authentication timeout */ 631662306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 631762306a36Sopenharmony_ci LOG_TRACE_EVENT, 631862306a36Sopenharmony_ci "0227 Node Authentication timeout\n"); 631962306a36Sopenharmony_ci lpfc_disc_flush_list(vport); 632062306a36Sopenharmony_ci 632162306a36Sopenharmony_ci /* 632262306a36Sopenharmony_ci * set port_state to PORT_READY if SLI2. 632362306a36Sopenharmony_ci * cmpl_reg_vpi will set port_state to READY for SLI3. 632462306a36Sopenharmony_ci */ 632562306a36Sopenharmony_ci if (phba->sli_rev < LPFC_SLI_REV4) { 632662306a36Sopenharmony_ci if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) 632762306a36Sopenharmony_ci lpfc_issue_reg_vpi(phba, vport); 632862306a36Sopenharmony_ci else { /* NPIV Not enabled */ 632962306a36Sopenharmony_ci lpfc_issue_clear_la(phba, vport); 633062306a36Sopenharmony_ci vport->port_state = LPFC_VPORT_READY; 633162306a36Sopenharmony_ci } 633262306a36Sopenharmony_ci } 633362306a36Sopenharmony_ci break; 633462306a36Sopenharmony_ci 633562306a36Sopenharmony_ci case LPFC_VPORT_READY: 633662306a36Sopenharmony_ci if (vport->fc_flag & FC_RSCN_MODE) { 633762306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 633862306a36Sopenharmony_ci LOG_TRACE_EVENT, 633962306a36Sopenharmony_ci "0231 RSCN timeout Data: x%x " 634062306a36Sopenharmony_ci "x%x x%x x%x\n", 634162306a36Sopenharmony_ci vport->fc_ns_retry, LPFC_MAX_NS_RETRY, 634262306a36Sopenharmony_ci vport->port_state, vport->gidft_inp); 634362306a36Sopenharmony_ci 634462306a36Sopenharmony_ci /* Cleanup any outstanding ELS commands */ 634562306a36Sopenharmony_ci lpfc_els_flush_cmd(vport); 634662306a36Sopenharmony_ci 634762306a36Sopenharmony_ci lpfc_els_flush_rscn(vport); 634862306a36Sopenharmony_ci lpfc_disc_flush_list(vport); 634962306a36Sopenharmony_ci } 635062306a36Sopenharmony_ci break; 635162306a36Sopenharmony_ci 635262306a36Sopenharmony_ci default: 635362306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 635462306a36Sopenharmony_ci LOG_TRACE_EVENT, 635562306a36Sopenharmony_ci "0273 Unexpected discovery timeout, " 635662306a36Sopenharmony_ci "vport State x%x\n", vport->port_state); 635762306a36Sopenharmony_ci break; 635862306a36Sopenharmony_ci } 635962306a36Sopenharmony_ci 636062306a36Sopenharmony_ci switch (phba->link_state) { 636162306a36Sopenharmony_ci case LPFC_CLEAR_LA: 636262306a36Sopenharmony_ci /* CLEAR LA timeout */ 636362306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 636462306a36Sopenharmony_ci LOG_TRACE_EVENT, 636562306a36Sopenharmony_ci "0228 CLEAR LA timeout\n"); 636662306a36Sopenharmony_ci clrlaerr = 1; 636762306a36Sopenharmony_ci break; 636862306a36Sopenharmony_ci 636962306a36Sopenharmony_ci case LPFC_LINK_UP: 637062306a36Sopenharmony_ci lpfc_issue_clear_la(phba, vport); 637162306a36Sopenharmony_ci fallthrough; 637262306a36Sopenharmony_ci case LPFC_LINK_UNKNOWN: 637362306a36Sopenharmony_ci case LPFC_WARM_START: 637462306a36Sopenharmony_ci case LPFC_INIT_START: 637562306a36Sopenharmony_ci case LPFC_INIT_MBX_CMDS: 637662306a36Sopenharmony_ci case LPFC_LINK_DOWN: 637762306a36Sopenharmony_ci case LPFC_HBA_ERROR: 637862306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_ERR, 637962306a36Sopenharmony_ci LOG_TRACE_EVENT, 638062306a36Sopenharmony_ci "0230 Unexpected timeout, hba link " 638162306a36Sopenharmony_ci "state x%x\n", phba->link_state); 638262306a36Sopenharmony_ci clrlaerr = 1; 638362306a36Sopenharmony_ci break; 638462306a36Sopenharmony_ci 638562306a36Sopenharmony_ci case LPFC_HBA_READY: 638662306a36Sopenharmony_ci break; 638762306a36Sopenharmony_ci } 638862306a36Sopenharmony_ci 638962306a36Sopenharmony_ci if (clrlaerr) { 639062306a36Sopenharmony_ci lpfc_disc_flush_list(vport); 639162306a36Sopenharmony_ci if (phba->sli_rev != LPFC_SLI_REV4) { 639262306a36Sopenharmony_ci psli->sli3_ring[(LPFC_EXTRA_RING)].flag &= 639362306a36Sopenharmony_ci ~LPFC_STOP_IOCB_EVENT; 639462306a36Sopenharmony_ci psli->sli3_ring[LPFC_FCP_RING].flag &= 639562306a36Sopenharmony_ci ~LPFC_STOP_IOCB_EVENT; 639662306a36Sopenharmony_ci } 639762306a36Sopenharmony_ci vport->port_state = LPFC_VPORT_READY; 639862306a36Sopenharmony_ci } 639962306a36Sopenharmony_ci return; 640062306a36Sopenharmony_ci} 640162306a36Sopenharmony_ci 640262306a36Sopenharmony_ci/* 640362306a36Sopenharmony_ci * This routine handles processing a NameServer REG_LOGIN mailbox 640462306a36Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ 640562306a36Sopenharmony_ci * as the completion routine when the command is 640662306a36Sopenharmony_ci * handed off to the SLI layer. 640762306a36Sopenharmony_ci */ 640862306a36Sopenharmony_civoid 640962306a36Sopenharmony_cilpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) 641062306a36Sopenharmony_ci{ 641162306a36Sopenharmony_ci MAILBOX_t *mb = &pmb->u.mb; 641262306a36Sopenharmony_ci struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp; 641362306a36Sopenharmony_ci struct lpfc_vport *vport = pmb->vport; 641462306a36Sopenharmony_ci 641562306a36Sopenharmony_ci pmb->ctx_ndlp = NULL; 641662306a36Sopenharmony_ci 641762306a36Sopenharmony_ci if (phba->sli_rev < LPFC_SLI_REV4) 641862306a36Sopenharmony_ci ndlp->nlp_rpi = mb->un.varWords[0]; 641962306a36Sopenharmony_ci ndlp->nlp_flag |= NLP_RPI_REGISTERED; 642062306a36Sopenharmony_ci ndlp->nlp_type |= NLP_FABRIC; 642162306a36Sopenharmony_ci lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); 642262306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, 642362306a36Sopenharmony_ci "0004 rpi:%x DID:%x flg:%x %d x%px\n", 642462306a36Sopenharmony_ci ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, 642562306a36Sopenharmony_ci kref_read(&ndlp->kref), 642662306a36Sopenharmony_ci ndlp); 642762306a36Sopenharmony_ci /* 642862306a36Sopenharmony_ci * Start issuing Fabric-Device Management Interface (FDMI) command to 642962306a36Sopenharmony_ci * 0xfffffa (FDMI well known port). 643062306a36Sopenharmony_ci * DHBA -> DPRT -> RHBA -> RPA (physical port) 643162306a36Sopenharmony_ci * DPRT -> RPRT (vports) 643262306a36Sopenharmony_ci */ 643362306a36Sopenharmony_ci if (vport->port_type == LPFC_PHYSICAL_PORT) { 643462306a36Sopenharmony_ci phba->link_flag &= ~LS_CT_VEN_RPA; /* For extra Vendor RPA */ 643562306a36Sopenharmony_ci lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0); 643662306a36Sopenharmony_ci } else { 643762306a36Sopenharmony_ci lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0); 643862306a36Sopenharmony_ci } 643962306a36Sopenharmony_ci 644062306a36Sopenharmony_ci 644162306a36Sopenharmony_ci /* decrement the node reference count held for this callback 644262306a36Sopenharmony_ci * function. 644362306a36Sopenharmony_ci */ 644462306a36Sopenharmony_ci lpfc_nlp_put(ndlp); 644562306a36Sopenharmony_ci lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED); 644662306a36Sopenharmony_ci return; 644762306a36Sopenharmony_ci} 644862306a36Sopenharmony_ci 644962306a36Sopenharmony_cistatic int 645062306a36Sopenharmony_cilpfc_filter_by_rpi(struct lpfc_nodelist *ndlp, void *param) 645162306a36Sopenharmony_ci{ 645262306a36Sopenharmony_ci uint16_t *rpi = param; 645362306a36Sopenharmony_ci 645462306a36Sopenharmony_ci return ndlp->nlp_rpi == *rpi; 645562306a36Sopenharmony_ci} 645662306a36Sopenharmony_ci 645762306a36Sopenharmony_cistatic int 645862306a36Sopenharmony_cilpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param) 645962306a36Sopenharmony_ci{ 646062306a36Sopenharmony_ci return memcmp(&ndlp->nlp_portname, param, 646162306a36Sopenharmony_ci sizeof(ndlp->nlp_portname)) == 0; 646262306a36Sopenharmony_ci} 646362306a36Sopenharmony_ci 646462306a36Sopenharmony_cistatic struct lpfc_nodelist * 646562306a36Sopenharmony_ci__lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) 646662306a36Sopenharmony_ci{ 646762306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 646862306a36Sopenharmony_ci 646962306a36Sopenharmony_ci list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { 647062306a36Sopenharmony_ci if (filter(ndlp, param)) { 647162306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 647262306a36Sopenharmony_ci "3185 FIND node filter %ps DID " 647362306a36Sopenharmony_ci "ndlp x%px did x%x flg x%x st x%x " 647462306a36Sopenharmony_ci "xri x%x type x%x rpi x%x\n", 647562306a36Sopenharmony_ci filter, ndlp, ndlp->nlp_DID, 647662306a36Sopenharmony_ci ndlp->nlp_flag, ndlp->nlp_state, 647762306a36Sopenharmony_ci ndlp->nlp_xri, ndlp->nlp_type, 647862306a36Sopenharmony_ci ndlp->nlp_rpi); 647962306a36Sopenharmony_ci return ndlp; 648062306a36Sopenharmony_ci } 648162306a36Sopenharmony_ci } 648262306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 648362306a36Sopenharmony_ci "3186 FIND node filter %ps NOT FOUND.\n", filter); 648462306a36Sopenharmony_ci return NULL; 648562306a36Sopenharmony_ci} 648662306a36Sopenharmony_ci 648762306a36Sopenharmony_ci/* 648862306a36Sopenharmony_ci * This routine looks up the ndlp lists for the given RPI. If rpi found it 648962306a36Sopenharmony_ci * returns the node list element pointer else return NULL. 649062306a36Sopenharmony_ci */ 649162306a36Sopenharmony_cistruct lpfc_nodelist * 649262306a36Sopenharmony_ci__lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) 649362306a36Sopenharmony_ci{ 649462306a36Sopenharmony_ci return __lpfc_find_node(vport, lpfc_filter_by_rpi, &rpi); 649562306a36Sopenharmony_ci} 649662306a36Sopenharmony_ci 649762306a36Sopenharmony_ci/* 649862306a36Sopenharmony_ci * This routine looks up the ndlp lists for the given WWPN. If WWPN found it 649962306a36Sopenharmony_ci * returns the node element list pointer else return NULL. 650062306a36Sopenharmony_ci */ 650162306a36Sopenharmony_cistruct lpfc_nodelist * 650262306a36Sopenharmony_cilpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn) 650362306a36Sopenharmony_ci{ 650462306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 650562306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 650662306a36Sopenharmony_ci 650762306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 650862306a36Sopenharmony_ci ndlp = __lpfc_find_node(vport, lpfc_filter_by_wwpn, wwpn); 650962306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 651062306a36Sopenharmony_ci return ndlp; 651162306a36Sopenharmony_ci} 651262306a36Sopenharmony_ci 651362306a36Sopenharmony_ci/* 651462306a36Sopenharmony_ci * This routine looks up the ndlp lists for the given RPI. If the rpi 651562306a36Sopenharmony_ci * is found, the routine returns the node element list pointer else 651662306a36Sopenharmony_ci * return NULL. 651762306a36Sopenharmony_ci */ 651862306a36Sopenharmony_cistruct lpfc_nodelist * 651962306a36Sopenharmony_cilpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) 652062306a36Sopenharmony_ci{ 652162306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 652262306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 652362306a36Sopenharmony_ci unsigned long flags; 652462306a36Sopenharmony_ci 652562306a36Sopenharmony_ci spin_lock_irqsave(shost->host_lock, flags); 652662306a36Sopenharmony_ci ndlp = __lpfc_findnode_rpi(vport, rpi); 652762306a36Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, flags); 652862306a36Sopenharmony_ci return ndlp; 652962306a36Sopenharmony_ci} 653062306a36Sopenharmony_ci 653162306a36Sopenharmony_ci/** 653262306a36Sopenharmony_ci * lpfc_find_vport_by_vpid - Find a vport on a HBA through vport identifier 653362306a36Sopenharmony_ci * @phba: pointer to lpfc hba data structure. 653462306a36Sopenharmony_ci * @vpi: the physical host virtual N_Port identifier. 653562306a36Sopenharmony_ci * 653662306a36Sopenharmony_ci * This routine finds a vport on a HBA (referred by @phba) through a 653762306a36Sopenharmony_ci * @vpi. The function walks the HBA's vport list and returns the address 653862306a36Sopenharmony_ci * of the vport with the matching @vpi. 653962306a36Sopenharmony_ci * 654062306a36Sopenharmony_ci * Return code 654162306a36Sopenharmony_ci * NULL - No vport with the matching @vpi found 654262306a36Sopenharmony_ci * Otherwise - Address to the vport with the matching @vpi. 654362306a36Sopenharmony_ci **/ 654462306a36Sopenharmony_cistruct lpfc_vport * 654562306a36Sopenharmony_cilpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) 654662306a36Sopenharmony_ci{ 654762306a36Sopenharmony_ci struct lpfc_vport *vport; 654862306a36Sopenharmony_ci unsigned long flags; 654962306a36Sopenharmony_ci int i = 0; 655062306a36Sopenharmony_ci 655162306a36Sopenharmony_ci /* The physical ports are always vpi 0 - translate is unnecessary. */ 655262306a36Sopenharmony_ci if (vpi > 0) { 655362306a36Sopenharmony_ci /* 655462306a36Sopenharmony_ci * Translate the physical vpi to the logical vpi. The 655562306a36Sopenharmony_ci * vport stores the logical vpi. 655662306a36Sopenharmony_ci */ 655762306a36Sopenharmony_ci for (i = 0; i <= phba->max_vpi; i++) { 655862306a36Sopenharmony_ci if (vpi == phba->vpi_ids[i]) 655962306a36Sopenharmony_ci break; 656062306a36Sopenharmony_ci } 656162306a36Sopenharmony_ci 656262306a36Sopenharmony_ci if (i > phba->max_vpi) { 656362306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 656462306a36Sopenharmony_ci "2936 Could not find Vport mapped " 656562306a36Sopenharmony_ci "to vpi %d\n", vpi); 656662306a36Sopenharmony_ci return NULL; 656762306a36Sopenharmony_ci } 656862306a36Sopenharmony_ci } 656962306a36Sopenharmony_ci 657062306a36Sopenharmony_ci spin_lock_irqsave(&phba->port_list_lock, flags); 657162306a36Sopenharmony_ci list_for_each_entry(vport, &phba->port_list, listentry) { 657262306a36Sopenharmony_ci if (vport->vpi == i) { 657362306a36Sopenharmony_ci spin_unlock_irqrestore(&phba->port_list_lock, flags); 657462306a36Sopenharmony_ci return vport; 657562306a36Sopenharmony_ci } 657662306a36Sopenharmony_ci } 657762306a36Sopenharmony_ci spin_unlock_irqrestore(&phba->port_list_lock, flags); 657862306a36Sopenharmony_ci return NULL; 657962306a36Sopenharmony_ci} 658062306a36Sopenharmony_ci 658162306a36Sopenharmony_cistruct lpfc_nodelist * 658262306a36Sopenharmony_cilpfc_nlp_init(struct lpfc_vport *vport, uint32_t did) 658362306a36Sopenharmony_ci{ 658462306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 658562306a36Sopenharmony_ci int rpi = LPFC_RPI_ALLOC_ERROR; 658662306a36Sopenharmony_ci 658762306a36Sopenharmony_ci if (vport->phba->sli_rev == LPFC_SLI_REV4) { 658862306a36Sopenharmony_ci rpi = lpfc_sli4_alloc_rpi(vport->phba); 658962306a36Sopenharmony_ci if (rpi == LPFC_RPI_ALLOC_ERROR) 659062306a36Sopenharmony_ci return NULL; 659162306a36Sopenharmony_ci } 659262306a36Sopenharmony_ci 659362306a36Sopenharmony_ci ndlp = mempool_alloc(vport->phba->nlp_mem_pool, GFP_KERNEL); 659462306a36Sopenharmony_ci if (!ndlp) { 659562306a36Sopenharmony_ci if (vport->phba->sli_rev == LPFC_SLI_REV4) 659662306a36Sopenharmony_ci lpfc_sli4_free_rpi(vport->phba, rpi); 659762306a36Sopenharmony_ci return NULL; 659862306a36Sopenharmony_ci } 659962306a36Sopenharmony_ci 660062306a36Sopenharmony_ci memset(ndlp, 0, sizeof (struct lpfc_nodelist)); 660162306a36Sopenharmony_ci 660262306a36Sopenharmony_ci spin_lock_init(&ndlp->lock); 660362306a36Sopenharmony_ci 660462306a36Sopenharmony_ci lpfc_initialize_node(vport, ndlp, did); 660562306a36Sopenharmony_ci INIT_LIST_HEAD(&ndlp->nlp_listp); 660662306a36Sopenharmony_ci if (vport->phba->sli_rev == LPFC_SLI_REV4) { 660762306a36Sopenharmony_ci ndlp->nlp_rpi = rpi; 660862306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, 660962306a36Sopenharmony_ci "0007 Init New ndlp x%px, rpi:x%x DID:%x " 661062306a36Sopenharmony_ci "flg:x%x refcnt:%d\n", 661162306a36Sopenharmony_ci ndlp, ndlp->nlp_rpi, ndlp->nlp_DID, 661262306a36Sopenharmony_ci ndlp->nlp_flag, kref_read(&ndlp->kref)); 661362306a36Sopenharmony_ci 661462306a36Sopenharmony_ci ndlp->active_rrqs_xri_bitmap = 661562306a36Sopenharmony_ci mempool_alloc(vport->phba->active_rrq_pool, 661662306a36Sopenharmony_ci GFP_KERNEL); 661762306a36Sopenharmony_ci if (ndlp->active_rrqs_xri_bitmap) 661862306a36Sopenharmony_ci memset(ndlp->active_rrqs_xri_bitmap, 0, 661962306a36Sopenharmony_ci ndlp->phba->cfg_rrq_xri_bitmap_sz); 662062306a36Sopenharmony_ci } 662162306a36Sopenharmony_ci 662262306a36Sopenharmony_ci 662362306a36Sopenharmony_ci 662462306a36Sopenharmony_ci lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, 662562306a36Sopenharmony_ci "node init: did:x%x", 662662306a36Sopenharmony_ci ndlp->nlp_DID, 0, 0); 662762306a36Sopenharmony_ci 662862306a36Sopenharmony_ci return ndlp; 662962306a36Sopenharmony_ci} 663062306a36Sopenharmony_ci 663162306a36Sopenharmony_ci/* This routine releases all resources associated with a specifc NPort's ndlp 663262306a36Sopenharmony_ci * and mempool_free's the nodelist. 663362306a36Sopenharmony_ci */ 663462306a36Sopenharmony_cistatic void 663562306a36Sopenharmony_cilpfc_nlp_release(struct kref *kref) 663662306a36Sopenharmony_ci{ 663762306a36Sopenharmony_ci struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, 663862306a36Sopenharmony_ci kref); 663962306a36Sopenharmony_ci struct lpfc_vport *vport = ndlp->vport; 664062306a36Sopenharmony_ci 664162306a36Sopenharmony_ci lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, 664262306a36Sopenharmony_ci "node release: did:x%x flg:x%x type:x%x", 664362306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); 664462306a36Sopenharmony_ci 664562306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, 664662306a36Sopenharmony_ci "0279 %s: ndlp: x%px did %x refcnt:%d rpi:%x\n", 664762306a36Sopenharmony_ci __func__, ndlp, ndlp->nlp_DID, 664862306a36Sopenharmony_ci kref_read(&ndlp->kref), ndlp->nlp_rpi); 664962306a36Sopenharmony_ci 665062306a36Sopenharmony_ci /* remove ndlp from action. */ 665162306a36Sopenharmony_ci lpfc_cancel_retry_delay_tmo(vport, ndlp); 665262306a36Sopenharmony_ci lpfc_cleanup_node(vport, ndlp); 665362306a36Sopenharmony_ci 665462306a36Sopenharmony_ci /* Not all ELS transactions have registered the RPI with the port. 665562306a36Sopenharmony_ci * In these cases the rpi usage is temporary and the node is 665662306a36Sopenharmony_ci * released when the WQE is completed. Catch this case to free the 665762306a36Sopenharmony_ci * RPI to the pool. Because this node is in the release path, a lock 665862306a36Sopenharmony_ci * is unnecessary. All references are gone and the node has been 665962306a36Sopenharmony_ci * dequeued. 666062306a36Sopenharmony_ci */ 666162306a36Sopenharmony_ci if (ndlp->nlp_flag & NLP_RELEASE_RPI) { 666262306a36Sopenharmony_ci if (ndlp->nlp_rpi != LPFC_RPI_ALLOC_ERROR && 666362306a36Sopenharmony_ci !(ndlp->nlp_flag & (NLP_RPI_REGISTERED | NLP_UNREG_INP))) { 666462306a36Sopenharmony_ci lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); 666562306a36Sopenharmony_ci ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; 666662306a36Sopenharmony_ci } 666762306a36Sopenharmony_ci } 666862306a36Sopenharmony_ci 666962306a36Sopenharmony_ci /* The node is not freed back to memory, it is released to a pool so 667062306a36Sopenharmony_ci * the node fields need to be cleaned up. 667162306a36Sopenharmony_ci */ 667262306a36Sopenharmony_ci ndlp->vport = NULL; 667362306a36Sopenharmony_ci ndlp->nlp_state = NLP_STE_FREED_NODE; 667462306a36Sopenharmony_ci ndlp->nlp_flag = 0; 667562306a36Sopenharmony_ci ndlp->fc4_xpt_flags = 0; 667662306a36Sopenharmony_ci 667762306a36Sopenharmony_ci /* free ndlp memory for final ndlp release */ 667862306a36Sopenharmony_ci if (ndlp->phba->sli_rev == LPFC_SLI_REV4) 667962306a36Sopenharmony_ci mempool_free(ndlp->active_rrqs_xri_bitmap, 668062306a36Sopenharmony_ci ndlp->phba->active_rrq_pool); 668162306a36Sopenharmony_ci mempool_free(ndlp, ndlp->phba->nlp_mem_pool); 668262306a36Sopenharmony_ci} 668362306a36Sopenharmony_ci 668462306a36Sopenharmony_ci/* This routine bumps the reference count for a ndlp structure to ensure 668562306a36Sopenharmony_ci * that one discovery thread won't free a ndlp while another discovery thread 668662306a36Sopenharmony_ci * is using it. 668762306a36Sopenharmony_ci */ 668862306a36Sopenharmony_cistruct lpfc_nodelist * 668962306a36Sopenharmony_cilpfc_nlp_get(struct lpfc_nodelist *ndlp) 669062306a36Sopenharmony_ci{ 669162306a36Sopenharmony_ci unsigned long flags; 669262306a36Sopenharmony_ci 669362306a36Sopenharmony_ci if (ndlp) { 669462306a36Sopenharmony_ci lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, 669562306a36Sopenharmony_ci "node get: did:x%x flg:x%x refcnt:x%x", 669662306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_flag, 669762306a36Sopenharmony_ci kref_read(&ndlp->kref)); 669862306a36Sopenharmony_ci 669962306a36Sopenharmony_ci /* The check of ndlp usage to prevent incrementing the 670062306a36Sopenharmony_ci * ndlp reference count that is in the process of being 670162306a36Sopenharmony_ci * released. 670262306a36Sopenharmony_ci */ 670362306a36Sopenharmony_ci spin_lock_irqsave(&ndlp->lock, flags); 670462306a36Sopenharmony_ci if (!kref_get_unless_zero(&ndlp->kref)) { 670562306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, flags); 670662306a36Sopenharmony_ci lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, 670762306a36Sopenharmony_ci "0276 %s: ndlp:x%px refcnt:%d\n", 670862306a36Sopenharmony_ci __func__, (void *)ndlp, kref_read(&ndlp->kref)); 670962306a36Sopenharmony_ci return NULL; 671062306a36Sopenharmony_ci } 671162306a36Sopenharmony_ci spin_unlock_irqrestore(&ndlp->lock, flags); 671262306a36Sopenharmony_ci } else { 671362306a36Sopenharmony_ci WARN_ONCE(!ndlp, "**** %s, get ref on NULL ndlp!", __func__); 671462306a36Sopenharmony_ci } 671562306a36Sopenharmony_ci 671662306a36Sopenharmony_ci return ndlp; 671762306a36Sopenharmony_ci} 671862306a36Sopenharmony_ci 671962306a36Sopenharmony_ci/* This routine decrements the reference count for a ndlp structure. If the 672062306a36Sopenharmony_ci * count goes to 0, this indicates the associated nodelist should be freed. 672162306a36Sopenharmony_ci */ 672262306a36Sopenharmony_ciint 672362306a36Sopenharmony_cilpfc_nlp_put(struct lpfc_nodelist *ndlp) 672462306a36Sopenharmony_ci{ 672562306a36Sopenharmony_ci if (ndlp) { 672662306a36Sopenharmony_ci lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, 672762306a36Sopenharmony_ci "node put: did:x%x flg:x%x refcnt:x%x", 672862306a36Sopenharmony_ci ndlp->nlp_DID, ndlp->nlp_flag, 672962306a36Sopenharmony_ci kref_read(&ndlp->kref)); 673062306a36Sopenharmony_ci } else { 673162306a36Sopenharmony_ci WARN_ONCE(!ndlp, "**** %s, put ref on NULL ndlp!", __func__); 673262306a36Sopenharmony_ci } 673362306a36Sopenharmony_ci 673462306a36Sopenharmony_ci return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0; 673562306a36Sopenharmony_ci} 673662306a36Sopenharmony_ci 673762306a36Sopenharmony_ci/** 673862306a36Sopenharmony_ci * lpfc_fcf_inuse - Check if FCF can be unregistered. 673962306a36Sopenharmony_ci * @phba: Pointer to hba context object. 674062306a36Sopenharmony_ci * 674162306a36Sopenharmony_ci * This function iterate through all FC nodes associated 674262306a36Sopenharmony_ci * will all vports to check if there is any node with 674362306a36Sopenharmony_ci * fc_rports associated with it. If there is an fc_rport 674462306a36Sopenharmony_ci * associated with the node, then the node is either in 674562306a36Sopenharmony_ci * discovered state or its devloss_timer is pending. 674662306a36Sopenharmony_ci */ 674762306a36Sopenharmony_cistatic int 674862306a36Sopenharmony_cilpfc_fcf_inuse(struct lpfc_hba *phba) 674962306a36Sopenharmony_ci{ 675062306a36Sopenharmony_ci struct lpfc_vport **vports; 675162306a36Sopenharmony_ci int i, ret = 0; 675262306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 675362306a36Sopenharmony_ci struct Scsi_Host *shost; 675462306a36Sopenharmony_ci 675562306a36Sopenharmony_ci vports = lpfc_create_vport_work_array(phba); 675662306a36Sopenharmony_ci 675762306a36Sopenharmony_ci /* If driver cannot allocate memory, indicate fcf is in use */ 675862306a36Sopenharmony_ci if (!vports) 675962306a36Sopenharmony_ci return 1; 676062306a36Sopenharmony_ci 676162306a36Sopenharmony_ci for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { 676262306a36Sopenharmony_ci shost = lpfc_shost_from_vport(vports[i]); 676362306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 676462306a36Sopenharmony_ci /* 676562306a36Sopenharmony_ci * IF the CVL_RCVD bit is not set then we have sent the 676662306a36Sopenharmony_ci * flogi. 676762306a36Sopenharmony_ci * If dev_loss fires while we are waiting we do not want to 676862306a36Sopenharmony_ci * unreg the fcf. 676962306a36Sopenharmony_ci */ 677062306a36Sopenharmony_ci if (!(vports[i]->fc_flag & FC_VPORT_CVL_RCVD)) { 677162306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 677262306a36Sopenharmony_ci ret = 1; 677362306a36Sopenharmony_ci goto out; 677462306a36Sopenharmony_ci } 677562306a36Sopenharmony_ci list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) { 677662306a36Sopenharmony_ci if (ndlp->rport && 677762306a36Sopenharmony_ci (ndlp->rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { 677862306a36Sopenharmony_ci ret = 1; 677962306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 678062306a36Sopenharmony_ci goto out; 678162306a36Sopenharmony_ci } else if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { 678262306a36Sopenharmony_ci ret = 1; 678362306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, 678462306a36Sopenharmony_ci LOG_NODE | LOG_DISCOVERY, 678562306a36Sopenharmony_ci "2624 RPI %x DID %x flag %x " 678662306a36Sopenharmony_ci "still logged in\n", 678762306a36Sopenharmony_ci ndlp->nlp_rpi, ndlp->nlp_DID, 678862306a36Sopenharmony_ci ndlp->nlp_flag); 678962306a36Sopenharmony_ci } 679062306a36Sopenharmony_ci } 679162306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 679262306a36Sopenharmony_ci } 679362306a36Sopenharmony_ciout: 679462306a36Sopenharmony_ci lpfc_destroy_vport_work_array(phba, vports); 679562306a36Sopenharmony_ci return ret; 679662306a36Sopenharmony_ci} 679762306a36Sopenharmony_ci 679862306a36Sopenharmony_ci/** 679962306a36Sopenharmony_ci * lpfc_unregister_vfi_cmpl - Completion handler for unreg vfi. 680062306a36Sopenharmony_ci * @phba: Pointer to hba context object. 680162306a36Sopenharmony_ci * @mboxq: Pointer to mailbox object. 680262306a36Sopenharmony_ci * 680362306a36Sopenharmony_ci * This function frees memory associated with the mailbox command. 680462306a36Sopenharmony_ci */ 680562306a36Sopenharmony_civoid 680662306a36Sopenharmony_cilpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) 680762306a36Sopenharmony_ci{ 680862306a36Sopenharmony_ci struct lpfc_vport *vport = mboxq->vport; 680962306a36Sopenharmony_ci struct Scsi_Host *shost = lpfc_shost_from_vport(vport); 681062306a36Sopenharmony_ci 681162306a36Sopenharmony_ci if (mboxq->u.mb.mbxStatus) { 681262306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 681362306a36Sopenharmony_ci "2555 UNREG_VFI mbxStatus error x%x " 681462306a36Sopenharmony_ci "HBA state x%x\n", 681562306a36Sopenharmony_ci mboxq->u.mb.mbxStatus, vport->port_state); 681662306a36Sopenharmony_ci } 681762306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 681862306a36Sopenharmony_ci phba->pport->fc_flag &= ~FC_VFI_REGISTERED; 681962306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 682062306a36Sopenharmony_ci mempool_free(mboxq, phba->mbox_mem_pool); 682162306a36Sopenharmony_ci return; 682262306a36Sopenharmony_ci} 682362306a36Sopenharmony_ci 682462306a36Sopenharmony_ci/** 682562306a36Sopenharmony_ci * lpfc_unregister_fcfi_cmpl - Completion handler for unreg fcfi. 682662306a36Sopenharmony_ci * @phba: Pointer to hba context object. 682762306a36Sopenharmony_ci * @mboxq: Pointer to mailbox object. 682862306a36Sopenharmony_ci * 682962306a36Sopenharmony_ci * This function frees memory associated with the mailbox command. 683062306a36Sopenharmony_ci */ 683162306a36Sopenharmony_cistatic void 683262306a36Sopenharmony_cilpfc_unregister_fcfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) 683362306a36Sopenharmony_ci{ 683462306a36Sopenharmony_ci struct lpfc_vport *vport = mboxq->vport; 683562306a36Sopenharmony_ci 683662306a36Sopenharmony_ci if (mboxq->u.mb.mbxStatus) { 683762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 683862306a36Sopenharmony_ci "2550 UNREG_FCFI mbxStatus error x%x " 683962306a36Sopenharmony_ci "HBA state x%x\n", 684062306a36Sopenharmony_ci mboxq->u.mb.mbxStatus, vport->port_state); 684162306a36Sopenharmony_ci } 684262306a36Sopenharmony_ci mempool_free(mboxq, phba->mbox_mem_pool); 684362306a36Sopenharmony_ci return; 684462306a36Sopenharmony_ci} 684562306a36Sopenharmony_ci 684662306a36Sopenharmony_ci/** 684762306a36Sopenharmony_ci * lpfc_unregister_fcf_prep - Unregister fcf record preparation 684862306a36Sopenharmony_ci * @phba: Pointer to hba context object. 684962306a36Sopenharmony_ci * 685062306a36Sopenharmony_ci * This function prepare the HBA for unregistering the currently registered 685162306a36Sopenharmony_ci * FCF from the HBA. It performs unregistering, in order, RPIs, VPIs, and 685262306a36Sopenharmony_ci * VFIs. 685362306a36Sopenharmony_ci */ 685462306a36Sopenharmony_ciint 685562306a36Sopenharmony_cilpfc_unregister_fcf_prep(struct lpfc_hba *phba) 685662306a36Sopenharmony_ci{ 685762306a36Sopenharmony_ci struct lpfc_vport **vports; 685862306a36Sopenharmony_ci struct lpfc_nodelist *ndlp; 685962306a36Sopenharmony_ci struct Scsi_Host *shost; 686062306a36Sopenharmony_ci int i = 0, rc; 686162306a36Sopenharmony_ci 686262306a36Sopenharmony_ci /* Unregister RPIs */ 686362306a36Sopenharmony_ci if (lpfc_fcf_inuse(phba)) 686462306a36Sopenharmony_ci lpfc_unreg_hba_rpis(phba); 686562306a36Sopenharmony_ci 686662306a36Sopenharmony_ci /* At this point, all discovery is aborted */ 686762306a36Sopenharmony_ci phba->pport->port_state = LPFC_VPORT_UNKNOWN; 686862306a36Sopenharmony_ci 686962306a36Sopenharmony_ci /* Unregister VPIs */ 687062306a36Sopenharmony_ci vports = lpfc_create_vport_work_array(phba); 687162306a36Sopenharmony_ci if (vports && (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) 687262306a36Sopenharmony_ci for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { 687362306a36Sopenharmony_ci /* Stop FLOGI/FDISC retries */ 687462306a36Sopenharmony_ci ndlp = lpfc_findnode_did(vports[i], Fabric_DID); 687562306a36Sopenharmony_ci if (ndlp) 687662306a36Sopenharmony_ci lpfc_cancel_retry_delay_tmo(vports[i], ndlp); 687762306a36Sopenharmony_ci lpfc_cleanup_pending_mbox(vports[i]); 687862306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4) 687962306a36Sopenharmony_ci lpfc_sli4_unreg_all_rpis(vports[i]); 688062306a36Sopenharmony_ci lpfc_mbx_unreg_vpi(vports[i]); 688162306a36Sopenharmony_ci shost = lpfc_shost_from_vport(vports[i]); 688262306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 688362306a36Sopenharmony_ci vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; 688462306a36Sopenharmony_ci vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED; 688562306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 688662306a36Sopenharmony_ci } 688762306a36Sopenharmony_ci lpfc_destroy_vport_work_array(phba, vports); 688862306a36Sopenharmony_ci if (i == 0 && (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED))) { 688962306a36Sopenharmony_ci ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); 689062306a36Sopenharmony_ci if (ndlp) 689162306a36Sopenharmony_ci lpfc_cancel_retry_delay_tmo(phba->pport, ndlp); 689262306a36Sopenharmony_ci lpfc_cleanup_pending_mbox(phba->pport); 689362306a36Sopenharmony_ci if (phba->sli_rev == LPFC_SLI_REV4) 689462306a36Sopenharmony_ci lpfc_sli4_unreg_all_rpis(phba->pport); 689562306a36Sopenharmony_ci lpfc_mbx_unreg_vpi(phba->pport); 689662306a36Sopenharmony_ci shost = lpfc_shost_from_vport(phba->pport); 689762306a36Sopenharmony_ci spin_lock_irq(shost->host_lock); 689862306a36Sopenharmony_ci phba->pport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; 689962306a36Sopenharmony_ci phba->pport->vpi_state &= ~LPFC_VPI_REGISTERED; 690062306a36Sopenharmony_ci spin_unlock_irq(shost->host_lock); 690162306a36Sopenharmony_ci } 690262306a36Sopenharmony_ci 690362306a36Sopenharmony_ci /* Cleanup any outstanding ELS commands */ 690462306a36Sopenharmony_ci lpfc_els_flush_all_cmd(phba); 690562306a36Sopenharmony_ci 690662306a36Sopenharmony_ci /* Unregister the physical port VFI */ 690762306a36Sopenharmony_ci rc = lpfc_issue_unreg_vfi(phba->pport); 690862306a36Sopenharmony_ci return rc; 690962306a36Sopenharmony_ci} 691062306a36Sopenharmony_ci 691162306a36Sopenharmony_ci/** 691262306a36Sopenharmony_ci * lpfc_sli4_unregister_fcf - Unregister currently registered FCF record 691362306a36Sopenharmony_ci * @phba: Pointer to hba context object. 691462306a36Sopenharmony_ci * 691562306a36Sopenharmony_ci * This function issues synchronous unregister FCF mailbox command to HBA to 691662306a36Sopenharmony_ci * unregister the currently registered FCF record. The driver does not reset 691762306a36Sopenharmony_ci * the driver FCF usage state flags. 691862306a36Sopenharmony_ci * 691962306a36Sopenharmony_ci * Return 0 if successfully issued, none-zero otherwise. 692062306a36Sopenharmony_ci */ 692162306a36Sopenharmony_ciint 692262306a36Sopenharmony_cilpfc_sli4_unregister_fcf(struct lpfc_hba *phba) 692362306a36Sopenharmony_ci{ 692462306a36Sopenharmony_ci LPFC_MBOXQ_t *mbox; 692562306a36Sopenharmony_ci int rc; 692662306a36Sopenharmony_ci 692762306a36Sopenharmony_ci mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 692862306a36Sopenharmony_ci if (!mbox) { 692962306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 693062306a36Sopenharmony_ci "2551 UNREG_FCFI mbox allocation failed" 693162306a36Sopenharmony_ci "HBA state x%x\n", phba->pport->port_state); 693262306a36Sopenharmony_ci return -ENOMEM; 693362306a36Sopenharmony_ci } 693462306a36Sopenharmony_ci lpfc_unreg_fcfi(mbox, phba->fcf.fcfi); 693562306a36Sopenharmony_ci mbox->vport = phba->pport; 693662306a36Sopenharmony_ci mbox->mbox_cmpl = lpfc_unregister_fcfi_cmpl; 693762306a36Sopenharmony_ci rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); 693862306a36Sopenharmony_ci 693962306a36Sopenharmony_ci if (rc == MBX_NOT_FINISHED) { 694062306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 694162306a36Sopenharmony_ci "2552 Unregister FCFI command failed rc x%x " 694262306a36Sopenharmony_ci "HBA state x%x\n", 694362306a36Sopenharmony_ci rc, phba->pport->port_state); 694462306a36Sopenharmony_ci return -EINVAL; 694562306a36Sopenharmony_ci } 694662306a36Sopenharmony_ci return 0; 694762306a36Sopenharmony_ci} 694862306a36Sopenharmony_ci 694962306a36Sopenharmony_ci/** 695062306a36Sopenharmony_ci * lpfc_unregister_fcf_rescan - Unregister currently registered fcf and rescan 695162306a36Sopenharmony_ci * @phba: Pointer to hba context object. 695262306a36Sopenharmony_ci * 695362306a36Sopenharmony_ci * This function unregisters the currently reigstered FCF. This function 695462306a36Sopenharmony_ci * also tries to find another FCF for discovery by rescan the HBA FCF table. 695562306a36Sopenharmony_ci */ 695662306a36Sopenharmony_civoid 695762306a36Sopenharmony_cilpfc_unregister_fcf_rescan(struct lpfc_hba *phba) 695862306a36Sopenharmony_ci{ 695962306a36Sopenharmony_ci int rc; 696062306a36Sopenharmony_ci 696162306a36Sopenharmony_ci /* Preparation for unregistering fcf */ 696262306a36Sopenharmony_ci rc = lpfc_unregister_fcf_prep(phba); 696362306a36Sopenharmony_ci if (rc) { 696462306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 696562306a36Sopenharmony_ci "2748 Failed to prepare for unregistering " 696662306a36Sopenharmony_ci "HBA's FCF record: rc=%d\n", rc); 696762306a36Sopenharmony_ci return; 696862306a36Sopenharmony_ci } 696962306a36Sopenharmony_ci 697062306a36Sopenharmony_ci /* Now, unregister FCF record and reset HBA FCF state */ 697162306a36Sopenharmony_ci rc = lpfc_sli4_unregister_fcf(phba); 697262306a36Sopenharmony_ci if (rc) 697362306a36Sopenharmony_ci return; 697462306a36Sopenharmony_ci /* Reset HBA FCF states after successful unregister FCF */ 697562306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 697662306a36Sopenharmony_ci phba->fcf.fcf_flag = 0; 697762306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 697862306a36Sopenharmony_ci phba->fcf.current_rec.flag = 0; 697962306a36Sopenharmony_ci 698062306a36Sopenharmony_ci /* 698162306a36Sopenharmony_ci * If driver is not unloading, check if there is any other 698262306a36Sopenharmony_ci * FCF record that can be used for discovery. 698362306a36Sopenharmony_ci */ 698462306a36Sopenharmony_ci if ((phba->pport->load_flag & FC_UNLOADING) || 698562306a36Sopenharmony_ci (phba->link_state < LPFC_LINK_UP)) 698662306a36Sopenharmony_ci return; 698762306a36Sopenharmony_ci 698862306a36Sopenharmony_ci /* This is considered as the initial FCF discovery scan */ 698962306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 699062306a36Sopenharmony_ci phba->fcf.fcf_flag |= FCF_INIT_DISC; 699162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 699262306a36Sopenharmony_ci 699362306a36Sopenharmony_ci /* Reset FCF roundrobin bmask for new discovery */ 699462306a36Sopenharmony_ci lpfc_sli4_clear_fcf_rr_bmask(phba); 699562306a36Sopenharmony_ci 699662306a36Sopenharmony_ci rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); 699762306a36Sopenharmony_ci 699862306a36Sopenharmony_ci if (rc) { 699962306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 700062306a36Sopenharmony_ci phba->fcf.fcf_flag &= ~FCF_INIT_DISC; 700162306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 700262306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 700362306a36Sopenharmony_ci "2553 lpfc_unregister_unused_fcf failed " 700462306a36Sopenharmony_ci "to read FCF record HBA state x%x\n", 700562306a36Sopenharmony_ci phba->pport->port_state); 700662306a36Sopenharmony_ci } 700762306a36Sopenharmony_ci} 700862306a36Sopenharmony_ci 700962306a36Sopenharmony_ci/** 701062306a36Sopenharmony_ci * lpfc_unregister_fcf - Unregister the currently registered fcf record 701162306a36Sopenharmony_ci * @phba: Pointer to hba context object. 701262306a36Sopenharmony_ci * 701362306a36Sopenharmony_ci * This function just unregisters the currently reigstered FCF. It does not 701462306a36Sopenharmony_ci * try to find another FCF for discovery. 701562306a36Sopenharmony_ci */ 701662306a36Sopenharmony_civoid 701762306a36Sopenharmony_cilpfc_unregister_fcf(struct lpfc_hba *phba) 701862306a36Sopenharmony_ci{ 701962306a36Sopenharmony_ci int rc; 702062306a36Sopenharmony_ci 702162306a36Sopenharmony_ci /* Preparation for unregistering fcf */ 702262306a36Sopenharmony_ci rc = lpfc_unregister_fcf_prep(phba); 702362306a36Sopenharmony_ci if (rc) { 702462306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 702562306a36Sopenharmony_ci "2749 Failed to prepare for unregistering " 702662306a36Sopenharmony_ci "HBA's FCF record: rc=%d\n", rc); 702762306a36Sopenharmony_ci return; 702862306a36Sopenharmony_ci } 702962306a36Sopenharmony_ci 703062306a36Sopenharmony_ci /* Now, unregister FCF record and reset HBA FCF state */ 703162306a36Sopenharmony_ci rc = lpfc_sli4_unregister_fcf(phba); 703262306a36Sopenharmony_ci if (rc) 703362306a36Sopenharmony_ci return; 703462306a36Sopenharmony_ci /* Set proper HBA FCF states after successful unregister FCF */ 703562306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 703662306a36Sopenharmony_ci phba->fcf.fcf_flag &= ~FCF_REGISTERED; 703762306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 703862306a36Sopenharmony_ci} 703962306a36Sopenharmony_ci 704062306a36Sopenharmony_ci/** 704162306a36Sopenharmony_ci * lpfc_unregister_unused_fcf - Unregister FCF if all devices are disconnected. 704262306a36Sopenharmony_ci * @phba: Pointer to hba context object. 704362306a36Sopenharmony_ci * 704462306a36Sopenharmony_ci * This function check if there are any connected remote port for the FCF and 704562306a36Sopenharmony_ci * if all the devices are disconnected, this function unregister FCFI. 704662306a36Sopenharmony_ci * This function also tries to use another FCF for discovery. 704762306a36Sopenharmony_ci */ 704862306a36Sopenharmony_civoid 704962306a36Sopenharmony_cilpfc_unregister_unused_fcf(struct lpfc_hba *phba) 705062306a36Sopenharmony_ci{ 705162306a36Sopenharmony_ci /* 705262306a36Sopenharmony_ci * If HBA is not running in FIP mode, if HBA does not support 705362306a36Sopenharmony_ci * FCoE, if FCF discovery is ongoing, or if FCF has not been 705462306a36Sopenharmony_ci * registered, do nothing. 705562306a36Sopenharmony_ci */ 705662306a36Sopenharmony_ci spin_lock_irq(&phba->hbalock); 705762306a36Sopenharmony_ci if (!(phba->hba_flag & HBA_FCOE_MODE) || 705862306a36Sopenharmony_ci !(phba->fcf.fcf_flag & FCF_REGISTERED) || 705962306a36Sopenharmony_ci !(phba->hba_flag & HBA_FIP_SUPPORT) || 706062306a36Sopenharmony_ci (phba->fcf.fcf_flag & FCF_DISCOVERY) || 706162306a36Sopenharmony_ci (phba->pport->port_state == LPFC_FLOGI)) { 706262306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 706362306a36Sopenharmony_ci return; 706462306a36Sopenharmony_ci } 706562306a36Sopenharmony_ci spin_unlock_irq(&phba->hbalock); 706662306a36Sopenharmony_ci 706762306a36Sopenharmony_ci if (lpfc_fcf_inuse(phba)) 706862306a36Sopenharmony_ci return; 706962306a36Sopenharmony_ci 707062306a36Sopenharmony_ci lpfc_unregister_fcf_rescan(phba); 707162306a36Sopenharmony_ci} 707262306a36Sopenharmony_ci 707362306a36Sopenharmony_ci/** 707462306a36Sopenharmony_ci * lpfc_read_fcf_conn_tbl - Create driver FCF connection table. 707562306a36Sopenharmony_ci * @phba: Pointer to hba context object. 707662306a36Sopenharmony_ci * @buff: Buffer containing the FCF connection table as in the config 707762306a36Sopenharmony_ci * region. 707862306a36Sopenharmony_ci * This function create driver data structure for the FCF connection 707962306a36Sopenharmony_ci * record table read from config region 23. 708062306a36Sopenharmony_ci */ 708162306a36Sopenharmony_cistatic void 708262306a36Sopenharmony_cilpfc_read_fcf_conn_tbl(struct lpfc_hba *phba, 708362306a36Sopenharmony_ci uint8_t *buff) 708462306a36Sopenharmony_ci{ 708562306a36Sopenharmony_ci struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry; 708662306a36Sopenharmony_ci struct lpfc_fcf_conn_hdr *conn_hdr; 708762306a36Sopenharmony_ci struct lpfc_fcf_conn_rec *conn_rec; 708862306a36Sopenharmony_ci uint32_t record_count; 708962306a36Sopenharmony_ci int i; 709062306a36Sopenharmony_ci 709162306a36Sopenharmony_ci /* Free the current connect table */ 709262306a36Sopenharmony_ci list_for_each_entry_safe(conn_entry, next_conn_entry, 709362306a36Sopenharmony_ci &phba->fcf_conn_rec_list, list) { 709462306a36Sopenharmony_ci list_del_init(&conn_entry->list); 709562306a36Sopenharmony_ci kfree(conn_entry); 709662306a36Sopenharmony_ci } 709762306a36Sopenharmony_ci 709862306a36Sopenharmony_ci conn_hdr = (struct lpfc_fcf_conn_hdr *) buff; 709962306a36Sopenharmony_ci record_count = conn_hdr->length * sizeof(uint32_t)/ 710062306a36Sopenharmony_ci sizeof(struct lpfc_fcf_conn_rec); 710162306a36Sopenharmony_ci 710262306a36Sopenharmony_ci conn_rec = (struct lpfc_fcf_conn_rec *) 710362306a36Sopenharmony_ci (buff + sizeof(struct lpfc_fcf_conn_hdr)); 710462306a36Sopenharmony_ci 710562306a36Sopenharmony_ci for (i = 0; i < record_count; i++) { 710662306a36Sopenharmony_ci if (!(conn_rec[i].flags & FCFCNCT_VALID)) 710762306a36Sopenharmony_ci continue; 710862306a36Sopenharmony_ci conn_entry = kzalloc(sizeof(struct lpfc_fcf_conn_entry), 710962306a36Sopenharmony_ci GFP_KERNEL); 711062306a36Sopenharmony_ci if (!conn_entry) { 711162306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 711262306a36Sopenharmony_ci "2566 Failed to allocate connection" 711362306a36Sopenharmony_ci " table entry\n"); 711462306a36Sopenharmony_ci return; 711562306a36Sopenharmony_ci } 711662306a36Sopenharmony_ci 711762306a36Sopenharmony_ci memcpy(&conn_entry->conn_rec, &conn_rec[i], 711862306a36Sopenharmony_ci sizeof(struct lpfc_fcf_conn_rec)); 711962306a36Sopenharmony_ci list_add_tail(&conn_entry->list, 712062306a36Sopenharmony_ci &phba->fcf_conn_rec_list); 712162306a36Sopenharmony_ci } 712262306a36Sopenharmony_ci 712362306a36Sopenharmony_ci if (!list_empty(&phba->fcf_conn_rec_list)) { 712462306a36Sopenharmony_ci i = 0; 712562306a36Sopenharmony_ci list_for_each_entry(conn_entry, &phba->fcf_conn_rec_list, 712662306a36Sopenharmony_ci list) { 712762306a36Sopenharmony_ci conn_rec = &conn_entry->conn_rec; 712862306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_INFO, LOG_INIT, 712962306a36Sopenharmony_ci "3345 FCF connection list rec[%02d]: " 713062306a36Sopenharmony_ci "flags:x%04x, vtag:x%04x, " 713162306a36Sopenharmony_ci "fabric_name:x%02x:%02x:%02x:%02x:" 713262306a36Sopenharmony_ci "%02x:%02x:%02x:%02x, " 713362306a36Sopenharmony_ci "switch_name:x%02x:%02x:%02x:%02x:" 713462306a36Sopenharmony_ci "%02x:%02x:%02x:%02x\n", i++, 713562306a36Sopenharmony_ci conn_rec->flags, conn_rec->vlan_tag, 713662306a36Sopenharmony_ci conn_rec->fabric_name[0], 713762306a36Sopenharmony_ci conn_rec->fabric_name[1], 713862306a36Sopenharmony_ci conn_rec->fabric_name[2], 713962306a36Sopenharmony_ci conn_rec->fabric_name[3], 714062306a36Sopenharmony_ci conn_rec->fabric_name[4], 714162306a36Sopenharmony_ci conn_rec->fabric_name[5], 714262306a36Sopenharmony_ci conn_rec->fabric_name[6], 714362306a36Sopenharmony_ci conn_rec->fabric_name[7], 714462306a36Sopenharmony_ci conn_rec->switch_name[0], 714562306a36Sopenharmony_ci conn_rec->switch_name[1], 714662306a36Sopenharmony_ci conn_rec->switch_name[2], 714762306a36Sopenharmony_ci conn_rec->switch_name[3], 714862306a36Sopenharmony_ci conn_rec->switch_name[4], 714962306a36Sopenharmony_ci conn_rec->switch_name[5], 715062306a36Sopenharmony_ci conn_rec->switch_name[6], 715162306a36Sopenharmony_ci conn_rec->switch_name[7]); 715262306a36Sopenharmony_ci } 715362306a36Sopenharmony_ci } 715462306a36Sopenharmony_ci} 715562306a36Sopenharmony_ci 715662306a36Sopenharmony_ci/** 715762306a36Sopenharmony_ci * lpfc_read_fcoe_param - Read FCoe parameters from conf region.. 715862306a36Sopenharmony_ci * @phba: Pointer to hba context object. 715962306a36Sopenharmony_ci * @buff: Buffer containing the FCoE parameter data structure. 716062306a36Sopenharmony_ci * 716162306a36Sopenharmony_ci * This function update driver data structure with config 716262306a36Sopenharmony_ci * parameters read from config region 23. 716362306a36Sopenharmony_ci */ 716462306a36Sopenharmony_cistatic void 716562306a36Sopenharmony_cilpfc_read_fcoe_param(struct lpfc_hba *phba, 716662306a36Sopenharmony_ci uint8_t *buff) 716762306a36Sopenharmony_ci{ 716862306a36Sopenharmony_ci struct lpfc_fip_param_hdr *fcoe_param_hdr; 716962306a36Sopenharmony_ci struct lpfc_fcoe_params *fcoe_param; 717062306a36Sopenharmony_ci 717162306a36Sopenharmony_ci fcoe_param_hdr = (struct lpfc_fip_param_hdr *) 717262306a36Sopenharmony_ci buff; 717362306a36Sopenharmony_ci fcoe_param = (struct lpfc_fcoe_params *) 717462306a36Sopenharmony_ci (buff + sizeof(struct lpfc_fip_param_hdr)); 717562306a36Sopenharmony_ci 717662306a36Sopenharmony_ci if ((fcoe_param_hdr->parm_version != FIPP_VERSION) || 717762306a36Sopenharmony_ci (fcoe_param_hdr->length != FCOE_PARAM_LENGTH)) 717862306a36Sopenharmony_ci return; 717962306a36Sopenharmony_ci 718062306a36Sopenharmony_ci if (fcoe_param_hdr->parm_flags & FIPP_VLAN_VALID) { 718162306a36Sopenharmony_ci phba->valid_vlan = 1; 718262306a36Sopenharmony_ci phba->vlan_id = le16_to_cpu(fcoe_param->vlan_tag) & 718362306a36Sopenharmony_ci 0xFFF; 718462306a36Sopenharmony_ci } 718562306a36Sopenharmony_ci 718662306a36Sopenharmony_ci phba->fc_map[0] = fcoe_param->fc_map[0]; 718762306a36Sopenharmony_ci phba->fc_map[1] = fcoe_param->fc_map[1]; 718862306a36Sopenharmony_ci phba->fc_map[2] = fcoe_param->fc_map[2]; 718962306a36Sopenharmony_ci return; 719062306a36Sopenharmony_ci} 719162306a36Sopenharmony_ci 719262306a36Sopenharmony_ci/** 719362306a36Sopenharmony_ci * lpfc_get_rec_conf23 - Get a record type in config region data. 719462306a36Sopenharmony_ci * @buff: Buffer containing config region 23 data. 719562306a36Sopenharmony_ci * @size: Size of the data buffer. 719662306a36Sopenharmony_ci * @rec_type: Record type to be searched. 719762306a36Sopenharmony_ci * 719862306a36Sopenharmony_ci * This function searches config region data to find the beginning 719962306a36Sopenharmony_ci * of the record specified by record_type. If record found, this 720062306a36Sopenharmony_ci * function return pointer to the record else return NULL. 720162306a36Sopenharmony_ci */ 720262306a36Sopenharmony_cistatic uint8_t * 720362306a36Sopenharmony_cilpfc_get_rec_conf23(uint8_t *buff, uint32_t size, uint8_t rec_type) 720462306a36Sopenharmony_ci{ 720562306a36Sopenharmony_ci uint32_t offset = 0, rec_length; 720662306a36Sopenharmony_ci 720762306a36Sopenharmony_ci if ((buff[0] == LPFC_REGION23_LAST_REC) || 720862306a36Sopenharmony_ci (size < sizeof(uint32_t))) 720962306a36Sopenharmony_ci return NULL; 721062306a36Sopenharmony_ci 721162306a36Sopenharmony_ci rec_length = buff[offset + 1]; 721262306a36Sopenharmony_ci 721362306a36Sopenharmony_ci /* 721462306a36Sopenharmony_ci * One TLV record has one word header and number of data words 721562306a36Sopenharmony_ci * specified in the rec_length field of the record header. 721662306a36Sopenharmony_ci */ 721762306a36Sopenharmony_ci while ((offset + rec_length * sizeof(uint32_t) + sizeof(uint32_t)) 721862306a36Sopenharmony_ci <= size) { 721962306a36Sopenharmony_ci if (buff[offset] == rec_type) 722062306a36Sopenharmony_ci return &buff[offset]; 722162306a36Sopenharmony_ci 722262306a36Sopenharmony_ci if (buff[offset] == LPFC_REGION23_LAST_REC) 722362306a36Sopenharmony_ci return NULL; 722462306a36Sopenharmony_ci 722562306a36Sopenharmony_ci offset += rec_length * sizeof(uint32_t) + sizeof(uint32_t); 722662306a36Sopenharmony_ci rec_length = buff[offset + 1]; 722762306a36Sopenharmony_ci } 722862306a36Sopenharmony_ci return NULL; 722962306a36Sopenharmony_ci} 723062306a36Sopenharmony_ci 723162306a36Sopenharmony_ci/** 723262306a36Sopenharmony_ci * lpfc_parse_fcoe_conf - Parse FCoE config data read from config region 23. 723362306a36Sopenharmony_ci * @phba: Pointer to lpfc_hba data structure. 723462306a36Sopenharmony_ci * @buff: Buffer containing config region 23 data. 723562306a36Sopenharmony_ci * @size: Size of the data buffer. 723662306a36Sopenharmony_ci * 723762306a36Sopenharmony_ci * This function parses the FCoE config parameters in config region 23 and 723862306a36Sopenharmony_ci * populate driver data structure with the parameters. 723962306a36Sopenharmony_ci */ 724062306a36Sopenharmony_civoid 724162306a36Sopenharmony_cilpfc_parse_fcoe_conf(struct lpfc_hba *phba, 724262306a36Sopenharmony_ci uint8_t *buff, 724362306a36Sopenharmony_ci uint32_t size) 724462306a36Sopenharmony_ci{ 724562306a36Sopenharmony_ci uint32_t offset = 0; 724662306a36Sopenharmony_ci uint8_t *rec_ptr; 724762306a36Sopenharmony_ci 724862306a36Sopenharmony_ci /* 724962306a36Sopenharmony_ci * If data size is less than 2 words signature and version cannot be 725062306a36Sopenharmony_ci * verified. 725162306a36Sopenharmony_ci */ 725262306a36Sopenharmony_ci if (size < 2*sizeof(uint32_t)) 725362306a36Sopenharmony_ci return; 725462306a36Sopenharmony_ci 725562306a36Sopenharmony_ci /* Check the region signature first */ 725662306a36Sopenharmony_ci if (memcmp(buff, LPFC_REGION23_SIGNATURE, 4)) { 725762306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 725862306a36Sopenharmony_ci "2567 Config region 23 has bad signature\n"); 725962306a36Sopenharmony_ci return; 726062306a36Sopenharmony_ci } 726162306a36Sopenharmony_ci 726262306a36Sopenharmony_ci offset += 4; 726362306a36Sopenharmony_ci 726462306a36Sopenharmony_ci /* Check the data structure version */ 726562306a36Sopenharmony_ci if (buff[offset] != LPFC_REGION23_VERSION) { 726662306a36Sopenharmony_ci lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, 726762306a36Sopenharmony_ci "2568 Config region 23 has bad version\n"); 726862306a36Sopenharmony_ci return; 726962306a36Sopenharmony_ci } 727062306a36Sopenharmony_ci offset += 4; 727162306a36Sopenharmony_ci 727262306a36Sopenharmony_ci /* Read FCoE param record */ 727362306a36Sopenharmony_ci rec_ptr = lpfc_get_rec_conf23(&buff[offset], 727462306a36Sopenharmony_ci size - offset, FCOE_PARAM_TYPE); 727562306a36Sopenharmony_ci if (rec_ptr) 727662306a36Sopenharmony_ci lpfc_read_fcoe_param(phba, rec_ptr); 727762306a36Sopenharmony_ci 727862306a36Sopenharmony_ci /* Read FCF connection table */ 727962306a36Sopenharmony_ci rec_ptr = lpfc_get_rec_conf23(&buff[offset], 728062306a36Sopenharmony_ci size - offset, FCOE_CONN_TBL_TYPE); 728162306a36Sopenharmony_ci if (rec_ptr) 728262306a36Sopenharmony_ci lpfc_read_fcf_conn_tbl(phba, rec_ptr); 728362306a36Sopenharmony_ci 728462306a36Sopenharmony_ci} 728562306a36Sopenharmony_ci 728662306a36Sopenharmony_ci/* 728762306a36Sopenharmony_ci * lpfc_error_lost_link - IO failure from link event or FW reset check. 728862306a36Sopenharmony_ci * 728962306a36Sopenharmony_ci * @vport: Pointer to lpfc_vport data structure. 729062306a36Sopenharmony_ci * @ulp_status: IO completion status. 729162306a36Sopenharmony_ci * @ulp_word4: Reason code for the ulp_status. 729262306a36Sopenharmony_ci * 729362306a36Sopenharmony_ci * This function evaluates the ulp_status and ulp_word4 values 729462306a36Sopenharmony_ci * for specific error values that indicate an internal link fault 729562306a36Sopenharmony_ci * or fw reset event for the completing IO. Callers require this 729662306a36Sopenharmony_ci * common data to decide next steps on the IO. 729762306a36Sopenharmony_ci * 729862306a36Sopenharmony_ci * Return: 729962306a36Sopenharmony_ci * false - No link or reset error occurred. 730062306a36Sopenharmony_ci * true - A link or reset error occurred. 730162306a36Sopenharmony_ci */ 730262306a36Sopenharmony_cibool 730362306a36Sopenharmony_cilpfc_error_lost_link(struct lpfc_vport *vport, u32 ulp_status, u32 ulp_word4) 730462306a36Sopenharmony_ci{ 730562306a36Sopenharmony_ci /* Mask off the extra port data to get just the reason code. */ 730662306a36Sopenharmony_ci u32 rsn_code = IOERR_PARAM_MASK & ulp_word4; 730762306a36Sopenharmony_ci 730862306a36Sopenharmony_ci if (ulp_status == IOSTAT_LOCAL_REJECT && 730962306a36Sopenharmony_ci (rsn_code == IOERR_SLI_ABORTED || 731062306a36Sopenharmony_ci rsn_code == IOERR_LINK_DOWN || 731162306a36Sopenharmony_ci rsn_code == IOERR_SLI_DOWN)) { 731262306a36Sopenharmony_ci lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI | LOG_ELS, 731362306a36Sopenharmony_ci "0408 Report link error true: <x%x:x%x>\n", 731462306a36Sopenharmony_ci ulp_status, ulp_word4); 731562306a36Sopenharmony_ci return true; 731662306a36Sopenharmony_ci } 731762306a36Sopenharmony_ci 731862306a36Sopenharmony_ci return false; 731962306a36Sopenharmony_ci} 7320