/******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of version 2 of the GNU General * * Public License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful. * * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * * TO BE LEGALLY INVALID. See the GNU General Public License for * * more details, a copy of which can be found in the file COPYING * * included with this package. * *******************************************************************/ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/kthread.h> #include <linux/interrupt.h> #include <linux/lockdep.h> #include <linux/utsname.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fs.h> #include "lpfc_hw4.h" #include "lpfc_hw.h" #include "lpfc_nl.h" #include "lpfc_disc.h" #include "lpfc_sli.h" #include "lpfc_sli4.h" #include "lpfc.h" #include "lpfc_scsi.h" #include "lpfc_nvme.h" #include "lpfc_logmsg.h" #include "lpfc_crtn.h" #include "lpfc_vport.h" #include "lpfc_debugfs.h" /* AlpaArray for assignment of scsid for scan-down and bind_method */ static uint8_t lpfcAlpaArray[] = …; static void lpfc_disc_timeout_handler(struct lpfc_vport *); static void lpfc_disc_flush_list(struct lpfc_vport *vport); static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); static int lpfc_fcf_inuse(struct lpfc_hba *); static void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *); static void lpfc_check_inactive_vmid(struct lpfc_hba *phba); static void lpfc_check_vmid_qfpa_issue(struct lpfc_hba *phba); static int lpfc_valid_xpt_node(struct lpfc_nodelist *ndlp) { … } /* The source of a terminate rport I/O is either a dev_loss_tmo * event or a call to fc_remove_host. While the rport should be * valid during these downcalls, the transport can call twice * in a single event. This routine provides somoe protection * as the NDLP isn't really free, just released to the pool. */ static int lpfc_rport_invalid(struct fc_rport *rport) { … } void lpfc_terminate_rport_io(struct fc_rport *rport) { … } /* * This function will be called when dev_loss_tmo fire. */ void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) { … } /** * lpfc_check_inactive_vmid_one - VMID inactivity checker for a vport * @vport: Pointer to vport context object. * * This function checks for idle VMID entries related to a particular vport. If * found unused/idle, free them accordingly. **/ static void lpfc_check_inactive_vmid_one(struct lpfc_vport *vport) { … } /** * lpfc_check_inactive_vmid - VMID inactivity checker * @phba: Pointer to hba context object. * * This function is called from the worker thread to determine if an entry in * the VMID table can be released since there was no I/O activity seen from that * particular VM for the specified time. When this happens, the entry in the * table is released and also the resources on the switch cleared. **/ static void lpfc_check_inactive_vmid(struct lpfc_hba *phba) { … } /** * lpfc_check_nlp_post_devloss - Check to restore ndlp refcnt after devloss * @vport: Pointer to vport object. * @ndlp: Pointer to remote node object. * * If NLP_IN_RECOV_POST_DEV_LOSS flag was set due to outstanding recovery of * node during dev_loss_tmo processing, then this function restores the nlp_put * kref decrement from lpfc_dev_loss_tmo_handler. **/ void lpfc_check_nlp_post_devloss(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { … } /** * lpfc_dev_loss_tmo_handler - Remote node devloss timeout handler * @ndlp: Pointer to remote node object. * * This function is called from the worker thread when devloss timeout timer * expires. For SLI4 host, this routine shall return 1 when at lease one * remote node, including this @ndlp, is still in use of FCF; otherwise, this * routine shall return 0 when there is no remote node is still in use of FCF * when devloss timeout happened to this @ndlp. **/ static int lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) { … } static void lpfc_check_vmid_qfpa_issue(struct lpfc_hba *phba) { … } /** * lpfc_sli4_post_dev_loss_tmo_handler - SLI4 post devloss timeout handler * @phba: Pointer to hba context object. * @fcf_inuse: SLI4 FCF in-use state reported from devloss timeout handler. * @nlp_did: remote node identifer with devloss timeout. * * This function is called from the worker thread after invoking devloss * timeout handler and releasing the reference count for the ndlp with * which the devloss timeout was handled for SLI4 host. For the devloss * timeout of the last remote node which had been in use of FCF, when this * routine is invoked, it shall be guaranteed that none of the remote are * in-use of FCF. When devloss timeout to the last remote using the FCF, * if the FIP engine is neither in FCF table scan process nor roundrobin * failover process, the in-use FCF shall be unregistered. If the FIP * engine is in FCF discovery process, the devloss timeout state shall * be set for either the FCF table scan process or roundrobin failover * process to unregister the in-use FCF. **/ static void lpfc_sli4_post_dev_loss_tmo_handler(struct lpfc_hba *phba, int fcf_inuse, uint32_t nlp_did) { … } /** * lpfc_alloc_fast_evt - Allocates data structure for posting event * @phba: Pointer to hba context object. * * This function is called from the functions which need to post * events from interrupt context. This function allocates data * structure required for posting event. It also keeps track of * number of events pending and prevent event storm when there are * too many events. **/ struct lpfc_fast_path_event * lpfc_alloc_fast_evt(struct lpfc_hba *phba) { … } /** * lpfc_free_fast_evt - Frees event data structure * @phba: Pointer to hba context object. * @evt: Event object which need to be freed. * * This function frees the data structure required for posting * events. **/ void lpfc_free_fast_evt(struct lpfc_hba *phba, struct lpfc_fast_path_event *evt) { … } /** * lpfc_send_fastpath_evt - Posts events generated from fast path * @phba: Pointer to hba context object. * @evtp: Event data structure. * * This function is called from worker thread, when the interrupt * context need to post an event. This function posts the event * to fc transport netlink interface. **/ static void lpfc_send_fastpath_evt(struct lpfc_hba *phba, struct lpfc_work_evt *evtp) { … } static void lpfc_work_list_done(struct lpfc_hba *phba) { … } static void lpfc_work_done(struct lpfc_hba *phba) { … } int lpfc_do_work(void *p) { … } /* * This is only called to handle FC worker events. Since this a rare * occurrence, we allocate a struct lpfc_work_evt structure here instead of * embedding it in the IOCB. */ int lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, uint32_t evt) { … } void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) { … } void lpfc_port_link_failure(struct lpfc_vport *vport) { … } void lpfc_linkdown_port(struct lpfc_vport *vport) { … } int lpfc_linkdown(struct lpfc_hba *phba) { … } static void lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport) { … } static void lpfc_linkup_port(struct lpfc_vport *vport) { … } static int lpfc_linkup(struct lpfc_hba *phba) { … } /* * This routine handles processing a CLEAR_LA mailbox * command upon completion. It is setup in the LPFC_MBOXQ * as the completion routine when the command is * handed off to the SLI layer. SLI3 only. */ static void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { … } void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { … } /** * lpfc_sli4_clear_fcf_rr_bmask * @phba: pointer to the struct lpfc_hba for this port. * This fucnction resets the round robin bit mask and clears the * fcf priority list. The list deletions are done while holding the * hbalock. The ON_LIST flag and the FLOGI_FAILED flags are cleared * from the lpfc_fcf_pri record. **/ void lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *phba) { … } static void lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { … } /** * lpfc_fab_name_match - Check if the fcf fabric name match. * @fab_name: pointer to fabric name. * @new_fcf_record: pointer to fcf record. * * This routine compare the fcf record's fabric name with provided * fabric name. If the fabric name are identical this function * returns 1 else return 0. **/ static uint32_t lpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record) { … } /** * lpfc_sw_name_match - Check if the fcf switch name match. * @sw_name: pointer to switch name. * @new_fcf_record: pointer to fcf record. * * This routine compare the fcf record's switch name with provided * switch name. If the switch name are identical this function * returns 1 else return 0. **/ static uint32_t lpfc_sw_name_match(uint8_t *sw_name, struct fcf_record *new_fcf_record) { … } /** * lpfc_mac_addr_match - Check if the fcf mac address match. * @mac_addr: pointer to mac address. * @new_fcf_record: pointer to fcf record. * * This routine compare the fcf record's mac address with HBA's * FCF mac address. If the mac addresses are identical this function * returns 1 else return 0. **/ static uint32_t lpfc_mac_addr_match(uint8_t *mac_addr, struct fcf_record *new_fcf_record) { … } static bool lpfc_vlan_id_match(uint16_t curr_vlan_id, uint16_t new_vlan_id) { … } /** * __lpfc_update_fcf_record_pri - update the lpfc_fcf_pri record. * @phba: pointer to lpfc hba data structure. * @fcf_index: Index for the lpfc_fcf_record. * @new_fcf_record: pointer to hba fcf record. * * This routine updates the driver FCF priority record from the new HBA FCF * record. The hbalock is asserted held in the code path calling this * routine. **/ static void __lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index, struct fcf_record *new_fcf_record ) { … } /** * lpfc_copy_fcf_record - Copy fcf information to lpfc_hba. * @fcf_rec: pointer to driver fcf record. * @new_fcf_record: pointer to fcf record. * * This routine copies the FCF information from the FCF * record to lpfc_hba data structure. **/ static void lpfc_copy_fcf_record(struct lpfc_fcf_rec *fcf_rec, struct fcf_record *new_fcf_record) { … } /** * __lpfc_update_fcf_record - Update driver fcf record * @phba: pointer to lpfc hba data structure. * @fcf_rec: pointer to driver fcf record. * @new_fcf_record: pointer to hba fcf record. * @addr_mode: address mode to be set to the driver fcf record. * @vlan_id: vlan tag to be set to the driver fcf record. * @flag: flag bits to be set to the driver fcf record. * * This routine updates the driver FCF record from the new HBA FCF record * together with the address mode, vlan_id, and other informations. This * routine is called with the hbalock held. **/ static void __lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec, struct fcf_record *new_fcf_record, uint32_t addr_mode, uint16_t vlan_id, uint32_t flag) { … } /** * lpfc_register_fcf - Register the FCF with hba. * @phba: pointer to lpfc hba data structure. * * This routine issues a register fcfi mailbox command to register * the fcf with HBA. **/ static void lpfc_register_fcf(struct lpfc_hba *phba) { … } /** * lpfc_match_fcf_conn_list - Check if the FCF record can be used for discovery. * @phba: pointer to lpfc hba data structure. * @new_fcf_record: pointer to fcf record. * @boot_flag: Indicates if this record used by boot bios. * @addr_mode: The address mode to be used by this FCF * @vlan_id: The vlan id to be used as vlan tagging by this FCF. * * This routine compare the fcf record with connect list obtained from the * config region to decide if this FCF can be used for SAN discovery. It returns * 1 if this record can be used for SAN discovery else return zero. If this FCF * record can be used for SAN discovery, the boot_flag will indicate if this FCF * is used by boot bios and addr_mode will indicate the addressing mode to be * used for this FCF when the function returns. * If the FCF record need to be used with a particular vlan id, the vlan is * set in the vlan_id on return of the function. If not VLAN tagging need to * be used with the FCF vlan_id will be set to LPFC_FCOE_NULL_VID; **/ static int lpfc_match_fcf_conn_list(struct lpfc_hba *phba, struct fcf_record *new_fcf_record, uint32_t *boot_flag, uint32_t *addr_mode, uint16_t *vlan_id) { … } /** * lpfc_check_pending_fcoe_event - Check if there is pending fcoe event. * @phba: pointer to lpfc hba data structure. * @unreg_fcf: Unregister FCF if FCF table need to be re-scaned. * * This function check if there is any fcoe event pending while driver * scan FCF entries. If there is any pending event, it will restart the * FCF saning and return 1 else return 0. */ int lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf) { … } /** * lpfc_sli4_new_fcf_random_select - Randomly select an eligible new fcf record * @phba: pointer to lpfc hba data structure. * @fcf_cnt: number of eligible fcf record seen so far. * * This function makes an running random selection decision on FCF record to * use through a sequence of @fcf_cnt eligible FCF records with equal * probability. To perform integer manunipulation of random numbers with * size unit32_t, a 16-bit random number returned from get_random_u16() is * taken as the random random number generated. * * Returns true when outcome is for the newly read FCF record should be * chosen; otherwise, return false when outcome is for keeping the previously * chosen FCF record. **/ static bool lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt) { … } /** * lpfc_sli4_fcf_rec_mbox_parse - Parse read_fcf mbox command. * @phba: pointer to lpfc hba data structure. * @mboxq: pointer to mailbox object. * @next_fcf_index: pointer to holder of next fcf index. * * This routine parses the non-embedded fcf mailbox command by performing the * necessarily error checking, non-embedded read FCF record mailbox command * SGE parsing, and endianness swapping. * * Returns the pointer to the new FCF record in the non-embedded mailbox * command DMA memory if successfully, other NULL. */ static struct fcf_record * lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, uint16_t *next_fcf_index) { … } /** * lpfc_sli4_log_fcf_record_info - Log the information of a fcf record * @phba: pointer to lpfc hba data structure. * @fcf_record: pointer to the fcf record. * @vlan_id: the lowest vlan identifier associated to this fcf record. * @next_fcf_index: the index to the next fcf record in hba's fcf table. * * This routine logs the detailed FCF record if the LOG_FIP loggin is * enabled. **/ static void lpfc_sli4_log_fcf_record_info(struct lpfc_hba *phba, struct fcf_record *fcf_record, uint16_t vlan_id, uint16_t next_fcf_index) { … } /** * lpfc_sli4_fcf_record_match - testing new FCF record for matching existing FCF * @phba: pointer to lpfc hba data structure. * @fcf_rec: pointer to an existing FCF record. * @new_fcf_record: pointer to a new FCF record. * @new_vlan_id: vlan id from the new FCF record. * * This function performs matching test of a new FCF record against an existing * FCF record. If the new_vlan_id passed in is LPFC_FCOE_IGNORE_VID, vlan id * will not be used as part of the FCF record matching criteria. * * Returns true if all the fields matching, otherwise returns false. */ static bool lpfc_sli4_fcf_record_match(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec, struct fcf_record *new_fcf_record, uint16_t new_vlan_id) { … } /** * lpfc_sli4_fcf_rr_next_proc - processing next roundrobin fcf * @vport: Pointer to vport object. * @fcf_index: index to next fcf. * * This function processing the roundrobin fcf failover to next fcf index. * When this function is invoked, there will be a current fcf registered * for flogi. * Return: 0 for continue retrying flogi on currently registered fcf; * 1 for stop flogi on currently registered fcf; */ int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *vport, uint16_t fcf_index) { … } /** * lpfc_sli4_fcf_pri_list_del * @phba: pointer to lpfc hba data structure. * @fcf_index: the index of the fcf record to delete * This routine checks the on list flag of the fcf_index to be deleted. * If it is one the list then it is removed from the list, and the flag * is cleared. This routine grab the hbalock before removing the fcf * record from the list. **/ static void lpfc_sli4_fcf_pri_list_del(struct lpfc_hba *phba, uint16_t fcf_index) { … } /** * lpfc_sli4_set_fcf_flogi_fail * @phba: pointer to lpfc hba data structure. * @fcf_index: the index of the fcf record to update * This routine acquires the hbalock and then set the LPFC_FCF_FLOGI_FAILED * flag so the round robin selection for the particular priority level * will try a different fcf record that does not have this bit set. * If the fcf record is re-read for any reason this flag is cleared brfore * adding it to the priority list. **/ void lpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *phba, uint16_t fcf_index) { … } /** * lpfc_sli4_fcf_pri_list_add * @phba: pointer to lpfc hba data structure. * @fcf_index: the index of the fcf record to add * @new_fcf_record: pointer to a new FCF record. * This routine checks the priority of the fcf_index to be added. * If it is a lower priority than the current head of the fcf_pri list * then it is added to the list in the right order. * If it is the same priority as the current head of the list then it * is added to the head of the list and its bit in the rr_bmask is set. * If the fcf_index to be added is of a higher priority than the current * head of the list then the rr_bmask is cleared, its bit is set in the * rr_bmask and it is added to the head of the list. * returns: * 0=success 1=failure **/ static int lpfc_sli4_fcf_pri_list_add(struct lpfc_hba *phba, uint16_t fcf_index, struct fcf_record *new_fcf_record) { … } /** * lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler. * @phba: pointer to lpfc hba data structure. * @mboxq: pointer to mailbox object. * * This function iterates through all the fcf records available in * HBA and chooses the optimal FCF record for discovery. After finding * the FCF for discovery it registers the FCF record and kicks start * discovery. * If FCF_IN_USE flag is set in currently used FCF, the routine tries to * use an FCF record which matches fabric name and mac address of the * currently used FCF record. * If the driver supports only one FCF, it will try to use the FCF record * used by BOOT_BIOS. */ void lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { … } /** * lpfc_mbx_cmpl_fcf_rr_read_fcf_rec - fcf roundrobin read_fcf mbox cmpl hdler * @phba: pointer to lpfc hba data structure. * @mboxq: pointer to mailbox object. * * This is the callback function for FLOGI failure roundrobin FCF failover * read FCF record mailbox command from the eligible FCF record bmask for * performing the failover. If the FCF read back is not valid/available, it * fails through to retrying FLOGI to the currently registered FCF again. * Otherwise, if the FCF read back is valid and available, it will set the * newly read FCF record to the failover FCF record, unregister currently * registered FCF record, copy the failover FCF record to the current * FCF record, and then register the current FCF record before proceeding * to trying FLOGI on the new failover FCF. */ void lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { … } /** * lpfc_mbx_cmpl_read_fcf_rec - read fcf completion handler. * @phba: pointer to lpfc hba data structure. * @mboxq: pointer to mailbox object. * * This is the callback function of read FCF record mailbox command for * updating the eligible FCF bmask for FLOGI failure roundrobin FCF * failover when a new FCF event happened. If the FCF read back is * valid/available and it passes the connection list check, it updates * the bmask for the eligible FCF record for roundrobin failover. */ void lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { … } /** * lpfc_init_vfi_cmpl - Completion handler for init_vfi mbox command. * @phba: pointer to lpfc hba data structure. * @mboxq: pointer to mailbox data structure. * * This function handles completion of init vfi mailbox command. */ static void lpfc_init_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { … } /** * lpfc_issue_init_vfi - Issue init_vfi mailbox command. * @vport: pointer to lpfc_vport data structure. * * This function issue a init_vfi mailbox command to initialize the VFI and * VPI for the physical port. */ void lpfc_issue_init_vfi(struct lpfc_vport *vport) { … } /** * lpfc_init_vpi_cmpl - Completion handler for init_vpi mbox command. * @phba: pointer to lpfc hba data structure. * @mboxq: pointer to mailbox data structure. * * This function handles completion of init vpi mailbox command. */ void lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { … } /** * lpfc_issue_init_vpi - Issue init_vpi mailbox command. * @vport: pointer to lpfc_vport data structure. * * This function issue a init_vpi mailbox command to initialize * VPI for the vport. */ void lpfc_issue_init_vpi(struct lpfc_vport *vport) { … } /** * lpfc_start_fdiscs - send fdiscs for each vports on this port. * @phba: pointer to lpfc hba data structure. * * This function loops through the list of vports on the @phba and issues an * FDISC if possible. */ void lpfc_start_fdiscs(struct lpfc_hba *phba) { … } void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { … } static void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { … } static void lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) { … } static void lpfc_enable_la(struct lpfc_hba *phba) { … } static void lpfc_mbx_issue_link_down(struct lpfc_hba *phba) { … } /* * This routine handles processing a READ_TOPOLOGY mailbox * command upon completion. It is setup in the LPFC_MBOXQ * as the completion routine when the command is * handed off to the SLI layer. SLI4 only. */ void lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { … } /* * This routine handles processing a REG_LOGIN mailbox * command upon completion. It is setup in the LPFC_MBOXQ * as the completion routine when the command is * handed off to the SLI layer. */ void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { … } static void lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { … } int lpfc_mbx_unreg_vpi(struct lpfc_vport *vport) { … } static void lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { … } /** * lpfc_create_static_vport - Read HBA config region to create static vports. * @phba: pointer to lpfc hba data structure. * * This routine issue a DUMP mailbox command for config region 22 to get * the list of static vports to be created. The function create vports * based on the information returned from the HBA. **/ void lpfc_create_static_vport(struct lpfc_hba *phba) { … } /* * This routine handles processing a Fabric REG_LOGIN mailbox * command upon completion. It is setup in the LPFC_MBOXQ * as the completion routine when the command is * handed off to the SLI layer. */ void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { … } /* * This routine will issue a GID_FT for each FC4 Type supported * by the driver. ALL GID_FTs must complete before discovery is started. */ int lpfc_issue_gidft(struct lpfc_vport *vport) { … } /** * lpfc_issue_gidpt - issue a GID_PT for all N_Ports * @vport: The virtual port for which this call is being executed. * * This routine will issue a GID_PT to get a list of all N_Ports * * Return value : * 0 - Failure to issue a GID_PT * 1 - GID_PT issued **/ int lpfc_issue_gidpt(struct lpfc_vport *vport) { … } /* * This routine handles processing a NameServer REG_LOGIN mailbox * command upon completion. It is setup in the LPFC_MBOXQ * as the completion routine when the command is * handed off to the SLI layer. */ void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { … } /* * This routine handles processing a Fabric Controller REG_LOGIN mailbox * command upon completion. It is setup in the LPFC_MBOXQ * as the completion routine when the command is handed off to the SLI layer. */ void lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { … } static void lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { … } static void lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) { … } static void lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count) { … } /* Register a node with backend if not already done */ void lpfc_nlp_reg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { … } /* Unregister a node with backend if not already done */ void lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { … } /* * Adisc state change handling */ static void lpfc_handle_adisc_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int new_state) { … } static void lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int old_state, int new_state) { … } static char * lpfc_nlp_state_name(char *buffer, size_t size, int state) { … } void lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int state) { … } void lpfc_enqueue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { … } void lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { … } /** * lpfc_initialize_node - Initialize all fields of node object * @vport: Pointer to Virtual Port object. * @ndlp: Pointer to FC node object. * @did: FC_ID of the node. * * This function is always called when node object need to be initialized. * It initializes all the fields of the node object. Although the reference * to phba from @ndlp can be obtained indirectly through it's reference to * @vport, a direct reference to phba is taken here by @ndlp. This is due * to the life-span of the @ndlp might go beyond the existence of @vport as * the final release of ndlp is determined by its reference count. And, the * operation on @ndlp needs the reference to phba. **/ static inline void lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint32_t did) { … } void lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { … } /* * Start / ReStart rescue timer for Discovery / RSCN handling */ void lpfc_set_disctmo(struct lpfc_vport *vport) { … } /* * Cancel rescue timer for Discovery / RSCN handling */ int lpfc_can_disctmo(struct lpfc_vport *vport) { … } /* * Check specified ring for outstanding IOCB on the SLI queue * Return true if iocb matches the specified nport */ int lpfc_check_sli_ndlp(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *iocb, struct lpfc_nodelist *ndlp) { … } static void __lpfc_dequeue_nport_iocbs(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct lpfc_sli_ring *pring, struct list_head *dequeue_list) { … } static void lpfc_sli3_dequeue_nport_iocbs(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct list_head *dequeue_list) { … } static void lpfc_sli4_dequeue_nport_iocbs(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, struct list_head *dequeue_list) { … } /* * Free resources / clean up outstanding I/Os * associated with nlp_rpi in the LPFC_NODELIST entry. */ static int lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { … } /** * lpfc_nlp_logo_unreg - Unreg mailbox completion handler before LOGO * @phba: Pointer to HBA context object. * @pmb: Pointer to mailbox object. * * This function will issue an ELS LOGO command after completing * the UNREG_RPI. **/ static void lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { … } /* * Sets the mailbox completion handler to be used for the * unreg_rpi command. The handler varies based on the state of * the port and what will be happening to the rpi next. */ static void lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, LPFC_MBOXQ_t *mbox) { … } /* * Free rpi associated with LPFC_NODELIST entry. * This routine is called from lpfc_freenode(), when we are removing * a LPFC_NODELIST entry. It is also called if the driver initiates a * LOGO that completes successfully, and we are waiting to PLOGI back * to the remote NPort. In addition, it is called after we receive * and unsolicated ELS cmd, send back a rsp, the rsp completes and * we are waiting to PLOGI back to the remote NPort. */ int lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { … } /** * lpfc_unreg_hba_rpis - Unregister rpis registered to the hba. * @phba: pointer to lpfc hba data structure. * * This routine is invoked to unregister all the currently registered RPIs * to the HBA. **/ void lpfc_unreg_hba_rpis(struct lpfc_hba *phba) { … } void lpfc_unreg_all_rpis(struct lpfc_vport *vport) { … } void lpfc_unreg_default_rpis(struct lpfc_vport *vport) { … } /* * Free resources associated with LPFC_NODELIST entry * so it can be freed. */ static int lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { … } static int lpfc_matchdid(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint32_t did) { … } /* Search for a nodelist entry */ static struct lpfc_nodelist * __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) { … } struct lpfc_nodelist * lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) { … } struct lpfc_nodelist * lpfc_findnode_mapped(struct lpfc_vport *vport) { … } struct lpfc_nodelist * lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) { … } /* Build a list of nodes to discover based on the loopmap */ void lpfc_disc_list_loopmap(struct lpfc_vport *vport) { … } /* SLI3 only */ void lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport) { … } /* Reg_vpi to tell firmware to resume normal operations */ void lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport) { … } /* Start Link up / RSCN discovery on NPR nodes */ void lpfc_disc_start(struct lpfc_vport *vport) { … } /* * Ignore completion for all IOCBs on tx and txcmpl queue for ELS * ring the match the sppecified nodelist. */ static void lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { … } static void lpfc_disc_flush_list(struct lpfc_vport *vport) { … } /* * lpfc_notify_xport_npr - notifies xport of node disappearance * @vport: Pointer to Virtual Port object. * * Transitions all ndlps to NPR state. When lpfc_nlp_set_state * calls lpfc_nlp_state_cleanup, the ndlp->rport is unregistered * and transport notified that the node is gone. * Return Code: * none */ static void lpfc_notify_xport_npr(struct lpfc_vport *vport) { … } void lpfc_cleanup_discovery_resources(struct lpfc_vport *vport) { … } /*****************************************************************************/ /* * NAME: lpfc_disc_timeout * * FUNCTION: Fibre Channel driver discovery timeout routine. * * EXECUTION ENVIRONMENT: interrupt only * * CALLED FROM: * Timer function * * RETURNS: * none */ /*****************************************************************************/ void lpfc_disc_timeout(struct timer_list *t) { … } static void lpfc_disc_timeout_handler(struct lpfc_vport *vport) { … } /* * This routine handles processing a NameServer REG_LOGIN mailbox * command upon completion. It is setup in the LPFC_MBOXQ * as the completion routine when the command is * handed off to the SLI layer. */ void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { … } static int lpfc_filter_by_rpi(struct lpfc_nodelist *ndlp, void *param) { … } static int lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param) { … } static struct lpfc_nodelist * __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) { … } /* * This routine looks up the ndlp lists for the given RPI. If rpi found it * returns the node list element pointer else return NULL. */ struct lpfc_nodelist * __lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) { … } /* * This routine looks up the ndlp lists for the given WWPN. If WWPN found it * returns the node element list pointer else return NULL. */ struct lpfc_nodelist * lpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn) { … } /* * This routine looks up the ndlp lists for the given RPI. If the rpi * is found, the routine returns the node element list pointer else * return NULL. */ struct lpfc_nodelist * lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) { … } /** * lpfc_find_vport_by_vpid - Find a vport on a HBA through vport identifier * @phba: pointer to lpfc hba data structure. * @vpi: the physical host virtual N_Port identifier. * * This routine finds a vport on a HBA (referred by @phba) through a * @vpi. The function walks the HBA's vport list and returns the address * of the vport with the matching @vpi. * * Return code * NULL - No vport with the matching @vpi found * Otherwise - Address to the vport with the matching @vpi. **/ struct lpfc_vport * lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) { … } struct lpfc_nodelist * lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did) { … } /* This routine releases all resources associated with a specifc NPort's ndlp * and mempool_free's the nodelist. */ static void lpfc_nlp_release(struct kref *kref) { … } /* This routine bumps the reference count for a ndlp structure to ensure * that one discovery thread won't free a ndlp while another discovery thread * is using it. */ struct lpfc_nodelist * lpfc_nlp_get(struct lpfc_nodelist *ndlp) { … } /* This routine decrements the reference count for a ndlp structure. If the * count goes to 0, this indicates the associated nodelist should be freed. */ int lpfc_nlp_put(struct lpfc_nodelist *ndlp) { … } /** * lpfc_fcf_inuse - Check if FCF can be unregistered. * @phba: Pointer to hba context object. * * This function iterate through all FC nodes associated * will all vports to check if there is any node with * fc_rports associated with it. If there is an fc_rport * associated with the node, then the node is either in * discovered state or its devloss_timer is pending. */ static int lpfc_fcf_inuse(struct lpfc_hba *phba) { … } /** * lpfc_unregister_vfi_cmpl - Completion handler for unreg vfi. * @phba: Pointer to hba context object. * @mboxq: Pointer to mailbox object. * * This function frees memory associated with the mailbox command. */ void lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { … } /** * lpfc_unregister_fcfi_cmpl - Completion handler for unreg fcfi. * @phba: Pointer to hba context object. * @mboxq: Pointer to mailbox object. * * This function frees memory associated with the mailbox command. */ static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) { … } /** * lpfc_unregister_fcf_prep - Unregister fcf record preparation * @phba: Pointer to hba context object. * * This function prepare the HBA for unregistering the currently registered * FCF from the HBA. It performs unregistering, in order, RPIs, VPIs, and * VFIs. */ int lpfc_unregister_fcf_prep(struct lpfc_hba *phba) { … } /** * lpfc_sli4_unregister_fcf - Unregister currently registered FCF record * @phba: Pointer to hba context object. * * This function issues synchronous unregister FCF mailbox command to HBA to * unregister the currently registered FCF record. The driver does not reset * the driver FCF usage state flags. * * Return 0 if successfully issued, none-zero otherwise. */ int lpfc_sli4_unregister_fcf(struct lpfc_hba *phba) { … } /** * lpfc_unregister_fcf_rescan - Unregister currently registered fcf and rescan * @phba: Pointer to hba context object. * * This function unregisters the currently reigstered FCF. This function * also tries to find another FCF for discovery by rescan the HBA FCF table. */ void lpfc_unregister_fcf_rescan(struct lpfc_hba *phba) { … } /** * lpfc_unregister_fcf - Unregister the currently registered fcf record * @phba: Pointer to hba context object. * * This function just unregisters the currently reigstered FCF. It does not * try to find another FCF for discovery. */ void lpfc_unregister_fcf(struct lpfc_hba *phba) { … } /** * lpfc_unregister_unused_fcf - Unregister FCF if all devices are disconnected. * @phba: Pointer to hba context object. * * This function check if there are any connected remote port for the FCF and * if all the devices are disconnected, this function unregister FCFI. * This function also tries to use another FCF for discovery. */ void lpfc_unregister_unused_fcf(struct lpfc_hba *phba) { … } /** * lpfc_read_fcf_conn_tbl - Create driver FCF connection table. * @phba: Pointer to hba context object. * @buff: Buffer containing the FCF connection table as in the config * region. * This function create driver data structure for the FCF connection * record table read from config region 23. */ static void lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba, uint8_t *buff) { … } /** * lpfc_read_fcoe_param - Read FCoe parameters from conf region.. * @phba: Pointer to hba context object. * @buff: Buffer containing the FCoE parameter data structure. * * This function update driver data structure with config * parameters read from config region 23. */ static void lpfc_read_fcoe_param(struct lpfc_hba *phba, uint8_t *buff) { … } /** * lpfc_get_rec_conf23 - Get a record type in config region data. * @buff: Buffer containing config region 23 data. * @size: Size of the data buffer. * @rec_type: Record type to be searched. * * This function searches config region data to find the beginning * of the record specified by record_type. If record found, this * function return pointer to the record else return NULL. */ static uint8_t * lpfc_get_rec_conf23(uint8_t *buff, uint32_t size, uint8_t rec_type) { … } /** * lpfc_parse_fcoe_conf - Parse FCoE config data read from config region 23. * @phba: Pointer to lpfc_hba data structure. * @buff: Buffer containing config region 23 data. * @size: Size of the data buffer. * * This function parses the FCoE config parameters in config region 23 and * populate driver data structure with the parameters. */ void lpfc_parse_fcoe_conf(struct lpfc_hba *phba, uint8_t *buff, uint32_t size) { … } /* * lpfc_error_lost_link - IO failure from link event or FW reset check. * * @vport: Pointer to lpfc_vport data structure. * @ulp_status: IO completion status. * @ulp_word4: Reason code for the ulp_status. * * This function evaluates the ulp_status and ulp_word4 values * for specific error values that indicate an internal link fault * or fw reset event for the completing IO. Callers require this * common data to decide next steps on the IO. * * Return: * false - No link or reset error occurred. * true - A link or reset error occurred. */ bool lpfc_error_lost_link(struct lpfc_vport *vport, u32 ulp_status, u32 ulp_word4) { … }