/* * This file is part of the Chelsio FCoE driver for Linux. * * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/utsname.h> #include <scsi/scsi_device.h> #include <scsi/scsi_transport_fc.h> #include <asm/unaligned.h> #include <scsi/fc/fc_els.h> #include <scsi/fc/fc_fs.h> #include <scsi/fc/fc_gs.h> #include <scsi/fc/fc_ms.h> #include "csio_hw.h" #include "csio_mb.h" #include "csio_lnode.h" #include "csio_rnode.h" int csio_fcoe_rnodes = …; int csio_fdmi_enable = …; #define PORT_ID_PTR(_x) … /* Lnode SM declarations */ static void csio_lns_uninit(struct csio_lnode *, enum csio_ln_ev); static void csio_lns_online(struct csio_lnode *, enum csio_ln_ev); static void csio_lns_ready(struct csio_lnode *, enum csio_ln_ev); static void csio_lns_offline(struct csio_lnode *, enum csio_ln_ev); static int csio_ln_mgmt_submit_req(struct csio_ioreq *, void (*io_cbfn) (struct csio_hw *, struct csio_ioreq *), enum fcoe_cmn_type, struct csio_dma_buf *, uint32_t); /* LN event mapping */ static enum csio_ln_ev fwevt_to_lnevt[] = …; #define CSIO_FWE_TO_LNE(_evt) … #define csio_ct_rsp(cp) … #define csio_ct_reason(cp) … #define csio_ct_expl(cp) … #define csio_ct_get_pld(cp) … /* * csio_ln_match_by_portid - lookup lnode using given portid. * @hw: HW module * @portid: port-id. * * If found, returns lnode matching given portid otherwise returns NULL. */ static struct csio_lnode * csio_ln_lookup_by_portid(struct csio_hw *hw, uint8_t portid) { … } /* * csio_ln_lookup_by_vnpi - Lookup lnode using given vnp id. * @hw - HW module * @vnpi - vnp index. * Returns - If found, returns lnode matching given vnp id * otherwise returns NULL. */ static struct csio_lnode * csio_ln_lookup_by_vnpi(struct csio_hw *hw, uint32_t vnp_id) { … } /** * csio_lnode_lookup_by_wwpn - Lookup lnode using given wwpn. * @hw: HW module. * @wwpn: WWPN. * * If found, returns lnode matching given wwpn, returns NULL otherwise. */ struct csio_lnode * csio_lnode_lookup_by_wwpn(struct csio_hw *hw, uint8_t *wwpn) { … } /* FDMI */ static void csio_fill_ct_iu(void *buf, uint8_t type, uint8_t sub_type, uint16_t op) { … } static int csio_hostname(uint8_t *buf, size_t buf_len) { … } static int csio_osname(uint8_t *buf, size_t buf_len) { … } static inline void csio_append_attrib(uint8_t **ptr, uint16_t type, void *val, size_t val_len) { … } /* * csio_ln_fdmi_done - FDMI registeration completion * @hw: HW context * @fdmi_req: fdmi request */ static void csio_ln_fdmi_done(struct csio_hw *hw, struct csio_ioreq *fdmi_req) { … } /* * csio_ln_fdmi_rhba_cbfn - RHBA completion * @hw: HW context * @fdmi_req: fdmi request */ static void csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) { … } /* * csio_ln_fdmi_dprt_cbfn - DPRT completion * @hw: HW context * @fdmi_req: fdmi request */ static void csio_ln_fdmi_dprt_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) { … } /* * csio_ln_fdmi_dhba_cbfn - DHBA completion * @hw: HW context * @fdmi_req: fdmi request */ static void csio_ln_fdmi_dhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) { … } /** * csio_ln_fdmi_start - Start an FDMI request. * @ln: lnode * @context: session context * * Issued with lock held. */ int csio_ln_fdmi_start(struct csio_lnode *ln, void *context) { … } /* * csio_ln_vnp_read_cbfn - vnp read completion handler. * @hw: HW lnode * @cbfn: Completion handler. * * Reads vnp response and updates ln parameters. */ static void csio_ln_vnp_read_cbfn(struct csio_hw *hw, struct csio_mb *mbp) { … } /* * csio_ln_vnp_read - Read vnp params. * @ln: lnode * @cbfn: Completion handler. * * Issued with lock held. */ static int csio_ln_vnp_read(struct csio_lnode *ln, void (*cbfn) (struct csio_hw *, struct csio_mb *)) { … } /* * csio_fcoe_enable_link - Enable fcoe link. * @ln: lnode * @enable: enable/disable * Issued with lock held. * Issues mbox cmd to bring up FCOE link on port associated with given ln. */ static int csio_fcoe_enable_link(struct csio_lnode *ln, bool enable) { … } /* * csio_ln_read_fcf_cbfn - Read fcf parameters * @ln: lnode * * read fcf response and Update ln fcf information. */ static void csio_ln_read_fcf_cbfn(struct csio_hw *hw, struct csio_mb *mbp) { … } /* * csio_ln_read_fcf_entry - Read fcf entry. * @ln: lnode * @cbfn: Completion handler. * * Issued with lock held. */ static int csio_ln_read_fcf_entry(struct csio_lnode *ln, void (*cbfn) (struct csio_hw *, struct csio_mb *)) { … } /* * csio_handle_link_up - Logical Linkup event. * @hw - HW module. * @portid - Physical port number * @fcfi - FCF index. * @vnpi - VNP index. * Returns - none. * * This event is received from FW, when virtual link is established between * Physical port[ENode] and FCF. If its new vnpi, then local node object is * created on this FCF and set to [ONLINE] state. * Lnode waits for FW_RDEV_CMD event to be received indicating that * Fabric login is completed and lnode moves to [READY] state. * * This called with hw lock held */ static void csio_handle_link_up(struct csio_hw *hw, uint8_t portid, uint32_t fcfi, uint32_t vnpi) { … } /* * csio_post_event_rns * @ln - FCOE lnode * @evt - Given rnode event * Returns - none * * Posts given rnode event to all FCOE rnodes connected with given Lnode. * This routine is invoked when lnode receives LINK_DOWN/DOWN_LINK/CLOSE * event. * * This called with hw lock held */ static void csio_post_event_rns(struct csio_lnode *ln, enum csio_rn_ev evt) { … } /* * csio_cleanup_rns * @ln - FCOE lnode * Returns - none * * Frees all FCOE rnodes connected with given Lnode. * * This called with hw lock held */ static void csio_cleanup_rns(struct csio_lnode *ln) { … } /* * csio_post_event_lns * @ln - FCOE lnode * @evt - Given lnode event * Returns - none * * Posts given lnode event to all FCOE lnodes connected with given Lnode. * This routine is invoked when lnode receives LINK_DOWN/DOWN_LINK/CLOSE * event. * * This called with hw lock held */ static void csio_post_event_lns(struct csio_lnode *ln, enum csio_ln_ev evt) { … } /* * csio_ln_down - Lcoal nport is down * @ln - FCOE Lnode * Returns - none * * Sends LINK_DOWN events to Lnode and its associated NPIVs lnodes. * * This called with hw lock held */ static void csio_ln_down(struct csio_lnode *ln) { … } /* * csio_handle_link_down - Logical Linkdown event. * @hw - HW module. * @portid - Physical port number * @fcfi - FCF index. * @vnpi - VNP index. * Returns - none * * This event is received from FW, when virtual link goes down between * Physical port[ENode] and FCF. Lnode and its associated NPIVs lnode hosted on * this vnpi[VN-Port] will be de-instantiated. * * This called with hw lock held */ static void csio_handle_link_down(struct csio_hw *hw, uint8_t portid, uint32_t fcfi, uint32_t vnpi) { … } /* * csio_is_lnode_ready - Checks FCOE lnode is in ready state. * @ln: Lnode module * * Returns True if FCOE lnode is in ready state. */ int csio_is_lnode_ready(struct csio_lnode *ln) { … } /*****************************************************************************/ /* START: Lnode SM */ /*****************************************************************************/ /* * csio_lns_uninit - The request in uninit state. * @ln - FCOE lnode. * @evt - Event to be processed. * * Process the given lnode event which is currently in "uninit" state. * Invoked with HW lock held. * Return - none. */ static void csio_lns_uninit(struct csio_lnode *ln, enum csio_ln_ev evt) { … } /* * csio_lns_online - The request in online state. * @ln - FCOE lnode. * @evt - Event to be processed. * * Process the given lnode event which is currently in "online" state. * Invoked with HW lock held. * Return - none. */ static void csio_lns_online(struct csio_lnode *ln, enum csio_ln_ev evt) { … } /* * csio_lns_ready - The request in ready state. * @ln - FCOE lnode. * @evt - Event to be processed. * * Process the given lnode event which is currently in "ready" state. * Invoked with HW lock held. * Return - none. */ static void csio_lns_ready(struct csio_lnode *ln, enum csio_ln_ev evt) { … } /* * csio_lns_offline - The request in offline state. * @ln - FCOE lnode. * @evt - Event to be processed. * * Process the given lnode event which is currently in "offline" state. * Invoked with HW lock held. * Return - none. */ static void csio_lns_offline(struct csio_lnode *ln, enum csio_ln_ev evt) { … } /*****************************************************************************/ /* END: Lnode SM */ /*****************************************************************************/ static void csio_free_fcfinfo(struct kref *kref) { … } /* Helper routines for attributes */ /* * csio_lnode_state_to_str - Get current state of FCOE lnode. * @ln - lnode * @str - state of lnode. * */ void csio_lnode_state_to_str(struct csio_lnode *ln, int8_t *str) { … } /* csio_lnode_state_to_str */ int csio_get_phy_port_stats(struct csio_hw *hw, uint8_t portid, struct fw_fcoe_port_stats *port_stats) { … } /* * csio_ln_mgmt_wr_handler -Mgmt Work Request handler. * @wr - WR. * @len - WR len. * This handler is invoked when an outstanding mgmt WR is completed. * Its invoked in the context of FW event worker thread for every * mgmt event received. * Return - none. */ static void csio_ln_mgmt_wr_handler(struct csio_hw *hw, void *wr, uint32_t len) { … } /** * csio_fcoe_fwevt_handler - Event handler for Firmware FCoE events. * @hw: HW module * @cpl_op: CPL opcode * @cmd: FW cmd/WR. * * Process received FCoE cmd/WR event from FW. */ void csio_fcoe_fwevt_handler(struct csio_hw *hw, __u8 cpl_op, __be64 *cmd) { … } /** * csio_lnode_start - Kickstart lnode discovery. * @ln: lnode * * This routine kickstarts the discovery by issuing an FCOE_LINK (up) command. */ int csio_lnode_start(struct csio_lnode *ln) { … } /** * csio_lnode_stop - Stop the lnode. * @ln: lnode * * This routine is invoked by HW module to stop lnode and its associated NPIV * lnodes. */ void csio_lnode_stop(struct csio_lnode *ln) { … } /** * csio_lnode_close - Close an lnode. * @ln: lnode * * This routine is invoked by HW module to close an lnode and its * associated NPIV lnodes. Lnode and its associated NPIV lnodes are * set to uninitialized state. */ void csio_lnode_close(struct csio_lnode *ln) { … } /* * csio_ln_prep_ecwr - Prepare ELS/CT WR. * @io_req - IO request. * @wr_len - WR len * @immd_len - WR immediate data * @sub_op - Sub opcode * @sid - source portid. * @did - destination portid * @flow_id - flowid * @fw_wr - ELS/CT WR to be prepared. * Returns: 0 - on success */ static int csio_ln_prep_ecwr(struct csio_ioreq *io_req, uint32_t wr_len, uint32_t immd_len, uint8_t sub_op, uint32_t sid, uint32_t did, uint32_t flow_id, uint8_t *fw_wr) { … } /* * csio_ln_mgmt_submit_wr - Post elsct work request. * @mgmtm - mgmtm * @io_req - io request. * @sub_op - ELS or CT request type * @pld - Dma Payload buffer * @pld_len - Payload len * Prepares ELSCT Work request and sents it to FW. * Returns: 0 - on success */ static int csio_ln_mgmt_submit_wr(struct csio_mgmtm *mgmtm, struct csio_ioreq *io_req, uint8_t sub_op, struct csio_dma_buf *pld, uint32_t pld_len) { … } /* * csio_ln_mgmt_submit_req - Submit FCOE Mgmt request. * @io_req - IO Request * @io_cbfn - Completion handler. * @req_type - ELS or CT request type * @pld - Dma Payload buffer * @pld_len - Payload len * * * This API used submit managment ELS/CT request. * This called with hw lock held * Returns: 0 - on success * -ENOMEM - on error. */ static int csio_ln_mgmt_submit_req(struct csio_ioreq *io_req, void (*io_cbfn) (struct csio_hw *, struct csio_ioreq *), enum fcoe_cmn_type req_type, struct csio_dma_buf *pld, uint32_t pld_len) { … } /* * csio_ln_fdmi_init - FDMI Init entry point. * @ln: lnode */ static int csio_ln_fdmi_init(struct csio_lnode *ln) { … } /* * csio_ln_fdmi_exit - FDMI exit entry point. * @ln: lnode */ static int csio_ln_fdmi_exit(struct csio_lnode *ln) { … } int csio_scan_done(struct csio_lnode *ln, unsigned long ticks, unsigned long time, unsigned long max_scan_ticks, unsigned long delta_scan_ticks) { … } /* * csio_notify_lnodes: * @hw: HW module * @note: Notification * * Called from the HW SM to fan out notifications to the * Lnode SM. Since the HW SM is entered with lock held, * there is no need to hold locks here. * */ void csio_notify_lnodes(struct csio_hw *hw, enum csio_ln_notify note) { … } /* * csio_disable_lnodes: * @hw: HW module * @portid:port id * @disable: disable/enable flag. * If disable=1, disables all lnode hosted on given physical port. * otherwise enables all the lnodes on given phsysical port. * This routine need to called with hw lock held. */ void csio_disable_lnodes(struct csio_hw *hw, uint8_t portid, bool disable) { … } /* * csio_ln_init - Initialize an lnode. * @ln: lnode * */ static int csio_ln_init(struct csio_lnode *ln) { … } static void csio_ln_exit(struct csio_lnode *ln) { … } /* * csio_lnode_init - Initialize the members of an lnode. * @ln: lnode */ int csio_lnode_init(struct csio_lnode *ln, struct csio_hw *hw, struct csio_lnode *pln) { … } /** * csio_lnode_exit - De-instantiate an lnode. * @ln: lnode * */ void csio_lnode_exit(struct csio_lnode *ln) { … }