diff options
Diffstat (limited to 'drivers/scsi/fcoe/libfcoe.c')
| -rw-r--r-- | drivers/scsi/fcoe/libfcoe.c | 1411 |
1 files changed, 0 insertions, 1411 deletions
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c deleted file mode 100644 index 9823291395a..00000000000 --- a/drivers/scsi/fcoe/libfcoe.c +++ /dev/null @@ -1,1411 +0,0 @@ -/* - * Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/spinlock.h> -#include <linux/timer.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/if_ether.h> -#include <linux/if_vlan.h> -#include <linux/errno.h> -#include <linux/bitops.h> -#include <net/rtnetlink.h> - -#include <scsi/fc/fc_els.h> -#include <scsi/fc/fc_fs.h> -#include <scsi/fc/fc_fip.h> -#include <scsi/fc/fc_encaps.h> -#include <scsi/fc/fc_fcoe.h> - -#include <scsi/libfc.h> -#include <scsi/libfcoe.h> - -MODULE_AUTHOR("Open-FCoE.org"); -MODULE_DESCRIPTION("FIP discovery protocol support for FCoE HBAs"); -MODULE_LICENSE("GPL v2"); - -#define FCOE_CTLR_MIN_FKA 500 /* min keep alive (mS) */ -#define FCOE_CTLR_DEF_FKA FIP_DEF_FKA /* default keep alive (mS) */ - -static void fcoe_ctlr_timeout(unsigned long); -static void fcoe_ctlr_link_work(struct work_struct *); -static void fcoe_ctlr_recv_work(struct work_struct *); - -static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS; - -unsigned int libfcoe_debug_logging; -module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); - -#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */ -#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */ - -#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \ -do { \ - if (unlikely(libfcoe_debug_logging & LEVEL)) \ - do { \ - CMD; \ - } while (0); \ -} while (0) - -#define LIBFCOE_DBG(fmt, args...) \ - LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \ - printk(KERN_INFO "libfcoe: " fmt, ##args);) - -#define LIBFCOE_FIP_DBG(fip, fmt, args...) \ - LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING, \ - printk(KERN_INFO "host%d: fip: " fmt, \ - (fip)->lp->host->host_no, ##args);) - -/** - * fcoe_ctlr_mtu_valid() - Check if a FCF's MTU is valid - * @fcf: The FCF to check - * - * Return non-zero if FCF fcoe_size has been validated. - */ -static inline int fcoe_ctlr_mtu_valid(const struct fcoe_fcf *fcf) -{ - return (fcf->flags & FIP_FL_SOL) != 0; -} - -/** - * fcoe_ctlr_fcf_usable() - Check if a FCF is usable - * @fcf: The FCF to check - * - * Return non-zero if the FCF is usable. - */ -static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf) -{ - u16 flags = FIP_FL_SOL | FIP_FL_AVAIL; - - return (fcf->flags & flags) == flags; -} - -/** - * fcoe_ctlr_init() - Initialize the FCoE Controller instance - * @fip: The FCoE controller to initialize - */ -void fcoe_ctlr_init(struct fcoe_ctlr *fip) -{ - fip->state = FIP_ST_LINK_WAIT; - fip->mode = FIP_ST_AUTO; - INIT_LIST_HEAD(&fip->fcfs); - spin_lock_init(&fip->lock); - fip->flogi_oxid = FC_XID_UNKNOWN; - setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip); - INIT_WORK(&fip->link_work, fcoe_ctlr_link_work); - INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work); - skb_queue_head_init(&fip->fip_recv_list); -} -EXPORT_SYMBOL(fcoe_ctlr_init); - -/** - * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller - * @fip: The FCoE controller whose FCFs are to be reset - * - * Called with &fcoe_ctlr lock held. - */ -static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip) -{ - struct fcoe_fcf *fcf; - struct fcoe_fcf *next; - - fip->sel_fcf = NULL; - list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { - list_del(&fcf->list); - kfree(fcf); - } - fip->fcf_count = 0; - fip->sel_time = 0; -} - -/** - * fcoe_ctlr_destroy() - Disable and tear down a FCoE controller - * @fip: The FCoE controller to tear down - * - * This is called by FCoE drivers before freeing the &fcoe_ctlr. - * - * The receive handler will have been deleted before this to guarantee - * that no more recv_work will be scheduled. - * - * The timer routine will simply return once we set FIP_ST_DISABLED. - * This guarantees that no further timeouts or work will be scheduled. - */ -void fcoe_ctlr_destroy(struct fcoe_ctlr *fip) -{ - cancel_work_sync(&fip->recv_work); - skb_queue_purge(&fip->fip_recv_list); - - spin_lock_bh(&fip->lock); - fip->state = FIP_ST_DISABLED; - fcoe_ctlr_reset_fcfs(fip); - spin_unlock_bh(&fip->lock); - del_timer_sync(&fip->timer); - cancel_work_sync(&fip->link_work); -} -EXPORT_SYMBOL(fcoe_ctlr_destroy); - -/** - * fcoe_ctlr_fcoe_size() - Return the maximum FCoE size required for VN_Port - * @fip: The FCoE controller to get the maximum FCoE size from - * - * Returns the maximum packet size including the FCoE header and trailer, - * but not including any Ethernet or VLAN headers. - */ -static inline u32 fcoe_ctlr_fcoe_size(struct fcoe_ctlr *fip) -{ - /* - * Determine the max FCoE frame size allowed, including - * FCoE header and trailer. - * Note: lp->mfs is currently the payload size, not the frame size. - */ - return fip->lp->mfs + sizeof(struct fc_frame_header) + - sizeof(struct fcoe_hdr) + sizeof(struct fcoe_crc_eof); -} - -/** - * fcoe_ctlr_solicit() - Send a FIP solicitation - * @fip: The FCoE controller to send the solicitation on - * @fcf: The destination FCF (if NULL, a multicast solicitation is sent) - */ -static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf) -{ - struct sk_buff *skb; - struct fip_sol { - struct ethhdr eth; - struct fip_header fip; - struct { - struct fip_mac_desc mac; - struct fip_wwn_desc wwnn; - struct fip_size_desc size; - } __attribute__((packed)) desc; - } __attribute__((packed)) *sol; - u32 fcoe_size; - - skb = dev_alloc_skb(sizeof(*sol)); - if (!skb) - return; - - sol = (struct fip_sol *)skb->data; - - memset(sol, 0, sizeof(*sol)); - memcpy(sol->eth.h_dest, fcf ? fcf->fcf_mac : fcoe_all_fcfs, ETH_ALEN); - memcpy(sol->eth.h_source, fip->ctl_src_addr, ETH_ALEN); - sol->eth.h_proto = htons(ETH_P_FIP); - - sol->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); - sol->fip.fip_op = htons(FIP_OP_DISC); - sol->fip.fip_subcode = FIP_SC_SOL; - sol->fip.fip_dl_len = htons(sizeof(sol->desc) / FIP_BPW); - sol->fip.fip_flags = htons(FIP_FL_FPMA); - if (fip->spma) - sol->fip.fip_flags |= htons(FIP_FL_SPMA); - - sol->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC; - sol->desc.mac.fd_desc.fip_dlen = sizeof(sol->desc.mac) / FIP_BPW; - memcpy(sol->desc.mac.fd_mac, fip->ctl_src_addr, ETH_ALEN); - - sol->desc.wwnn.fd_desc.fip_dtype = FIP_DT_NAME; - sol->desc.wwnn.fd_desc.fip_dlen = sizeof(sol->desc.wwnn) / FIP_BPW; - put_unaligned_be64(fip->lp->wwnn, &sol->desc.wwnn.fd_wwn); - - fcoe_size = fcoe_ctlr_fcoe_size(fip); - sol->desc.size.fd_desc.fip_dtype = FIP_DT_FCOE_SIZE; - sol->desc.size.fd_desc.fip_dlen = sizeof(sol->desc.size) / FIP_BPW; - sol->desc.size.fd_size = htons(fcoe_size); - - skb_put(skb, sizeof(*sol)); - skb->protocol = htons(ETH_P_FIP); - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - fip->send(fip, skb); - - if (!fcf) - fip->sol_time = jiffies; -} - -/** - * fcoe_ctlr_link_up() - Start FCoE controller - * @fip: The FCoE controller to start - * - * Called from the LLD when the network link is ready. - */ -void fcoe_ctlr_link_up(struct fcoe_ctlr *fip) -{ - spin_lock_bh(&fip->lock); - if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) { - fip->last_link = 1; - fip->link = 1; - spin_unlock_bh(&fip->lock); - fc_linkup(fip->lp); - } else if (fip->state == FIP_ST_LINK_WAIT) { - fip->state = fip->mode; - fip->last_link = 1; - fip->link = 1; - spin_unlock_bh(&fip->lock); - if (fip->state == FIP_ST_AUTO) - LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n"); - fc_linkup(fip->lp); - fcoe_ctlr_solicit(fip, NULL); - } else - spin_unlock_bh(&fip->lock); -} -EXPORT_SYMBOL(fcoe_ctlr_link_up); - -/** - * fcoe_ctlr_reset() - Reset a FCoE controller - * @fip: The FCoE controller to reset - */ -static void fcoe_ctlr_reset(struct fcoe_ctlr *fip) -{ - fcoe_ctlr_reset_fcfs(fip); - del_timer(&fip->timer); - fip->ctlr_ka_time = 0; - fip->port_ka_time = 0; - fip->sol_time = 0; - fip->flogi_oxid = FC_XID_UNKNOWN; - fip->map_dest = 0; -} - -/** - * fcoe_ctlr_link_down() - Stop a FCoE controller - * @fip: The FCoE controller to be stopped - * - * Returns non-zero if the link was up and now isn't. - * - * Called from the LLD when the network link is not ready. - * There may be multiple calls while the link is down. - */ -int fcoe_ctlr_link_down(struct fcoe_ctlr *fip) -{ - int link_dropped; - - LIBFCOE_FIP_DBG(fip, "link down.\n"); - spin_lock_bh(&fip->lock); - fcoe_ctlr_reset(fip); - link_dropped = fip->link; - fip->link = 0; - fip->last_link = 0; - fip->state = FIP_ST_LINK_WAIT; - spin_unlock_bh(&fip->lock); - - if (link_dropped) - fc_linkdown(fip->lp); - return link_dropped; -} -EXPORT_SYMBOL(fcoe_ctlr_link_down); - -/** - * fcoe_ctlr_send_keep_alive() - Send a keep-alive to the selected FCF - * @fip: The FCoE controller to send the FKA on - * @lport: libfc fc_lport to send from - * @ports: 0 for controller keep-alive, 1 for port keep-alive - * @sa: The source MAC address - * - * A controller keep-alive is sent every fka_period (typically 8 seconds). - * The source MAC is the native MAC address. - * - * A port keep-alive is sent every 90 seconds while logged in. - * The source MAC is the assigned mapped source address. - * The destination is the FCF's F-port. - */ -static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, - struct fc_lport *lport, - int ports, u8 *sa) -{ - struct sk_buff *skb; - struct fip_kal { - struct ethhdr eth; - struct fip_header fip; - struct fip_mac_desc mac; - } __attribute__((packed)) *kal; - struct fip_vn_desc *vn; - u32 len; - struct fc_lport *lp; - struct fcoe_fcf *fcf; - - fcf = fip->sel_fcf; - lp = fip->lp; - if (!fcf || !fc_host_port_id(lp->host)) - return; - - len = sizeof(*kal) + ports * sizeof(*vn); - skb = dev_alloc_skb(len); - if (!skb) - return; - - kal = (struct fip_kal *)skb->data; - memset(kal, 0, len); - memcpy(kal->eth.h_dest, fcf->fcf_mac, ETH_ALEN); - memcpy(kal->eth.h_source, sa, ETH_ALEN); - kal->eth.h_proto = htons(ETH_P_FIP); - - kal->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); - kal->fip.fip_op = htons(FIP_OP_CTRL); - kal->fip.fip_subcode = FIP_SC_KEEP_ALIVE; - kal->fip.fip_dl_len = htons((sizeof(kal->mac) + - ports * sizeof(*vn)) / FIP_BPW); - kal->fip.fip_flags = htons(FIP_FL_FPMA); - if (fip->spma) - kal->fip.fip_flags |= htons(FIP_FL_SPMA); - - kal->mac.fd_desc.fip_dtype = FIP_DT_MAC; - kal->mac.fd_desc.fip_dlen = sizeof(kal->mac) / FIP_BPW; - memcpy(kal->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN); - if (ports) { - vn = (struct fip_vn_desc *)(kal + 1); - vn->fd_desc.fip_dtype = FIP_DT_VN_ID; - vn->fd_desc.fip_dlen = sizeof(*vn) / FIP_BPW; - memcpy(vn->fd_mac, fip->get_src_addr(lport), ETH_ALEN); - hton24(vn->fd_fc_id, fc_host_port_id(lp->host)); - put_unaligned_be64(lp->wwpn, &vn->fd_wwpn); - } - skb_put(skb, len); - skb->protocol = htons(ETH_P_FIP); - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - fip->send(fip, skb); -} - -/** - * fcoe_ctlr_encaps() - Encapsulate an ELS frame for FIP, without sending it - * @fip: The FCoE controller for the ELS frame - * @dtype: The FIP descriptor type for the frame - * @skb: The FCoE ELS frame including FC header but no FCoE headers - * - * Returns non-zero error code on failure. - * - * The caller must check that the length is a multiple of 4. - * - * The @skb must have enough headroom (28 bytes) and tailroom (8 bytes). - * Headroom includes the FIP encapsulation description, FIP header, and - * Ethernet header. The tailroom is for the FIP MAC descriptor. - */ -static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, - u8 dtype, struct sk_buff *skb) -{ - struct fip_encaps_head { - struct ethhdr eth; - struct fip_header fip; - struct fip_encaps encaps; - } __attribute__((packed)) *cap; - struct fip_mac_desc *mac; - struct fcoe_fcf *fcf; - size_t dlen; - u16 fip_flags; - - fcf = fip->sel_fcf; - if (!fcf) - return -ENODEV; - - /* set flags according to both FCF and lport's capability on SPMA */ - fip_flags = fcf->flags; - fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA : FIP_FL_FPMA; - if (!fip_flags) - return -ENODEV; - - dlen = sizeof(struct fip_encaps) + skb->len; /* len before push */ - cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap)); - - memset(cap, 0, sizeof(*cap)); - memcpy(cap->eth.h_dest, fcf->fcf_mac, ETH_ALEN); - memcpy(cap->eth.h_source, fip->ctl_src_addr, ETH_ALEN); - cap->eth.h_proto = htons(ETH_P_FIP); - - cap->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); - cap->fip.fip_op = htons(FIP_OP_LS); - cap->fip.fip_subcode = FIP_SC_REQ; - cap->fip.fip_dl_len = htons((dlen + sizeof(*mac)) / FIP_BPW); - cap->fip.fip_flags = htons(fip_flags); - - cap->encaps.fd_desc.fip_dtype = dtype; - cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW; - - mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac)); - memset(mac, 0, sizeof(mac)); - mac->fd_desc.fip_dtype = FIP_DT_MAC; - mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW; - if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) - memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN); - else if (fip->spma) - memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN); - - skb->protocol = htons(ETH_P_FIP); - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - return 0; -} - -/** - * fcoe_ctlr_els_send() - Send an ELS frame encapsulated by FIP if appropriate. - * @fip: FCoE controller. - * @lport: libfc fc_lport to send from - * @skb: FCoE ELS frame including FC header but no FCoE headers. - * - * Returns a non-zero error code if the frame should not be sent. - * Returns zero if the caller should send the frame with FCoE encapsulation. - * - * The caller must check that the length is a multiple of 4. - * The SKB must have enough headroom (28 bytes) and tailroom (8 bytes). - */ -int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, - struct sk_buff *skb) -{ - struct fc_frame_header *fh; - u16 old_xid; - u8 op; - u8 mac[ETH_ALEN]; - - fh = (struct fc_frame_header *)skb->data; - op = *(u8 *)(fh + 1); - - if (op == ELS_FLOGI) { - old_xid = fip->flogi_oxid; - fip->flogi_oxid = ntohs(fh->fh_ox_id); - if (fip->state == FIP_ST_AUTO) { - if (old_xid == FC_XID_UNKNOWN) - fip->flogi_count = 0; - fip->flogi_count++; - if (fip->flogi_count < 3) - goto drop; - fip->map_dest = 1; - return 0; - } - if (fip->state == FIP_ST_NON_FIP) - fip->map_dest = 1; - } - - if (fip->state == FIP_ST_NON_FIP) - return 0; - if (!fip->sel_fcf) - goto drop; - - switch (op) { - case ELS_FLOGI: - op = FIP_DT_FLOGI; - break; - case ELS_FDISC: - if (ntoh24(fh->fh_s_id)) - return 0; - op = FIP_DT_FDISC; - break; - case ELS_LOGO: - if (fip->state != FIP_ST_ENABLED) - return 0; - if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI) - return 0; - op = FIP_DT_LOGO; - break; - case ELS_LS_ACC: - if (fip->flogi_oxid == FC_XID_UNKNOWN) - return 0; - if (!ntoh24(fh->fh_s_id)) - return 0; - if (fip->state == FIP_ST_AUTO) - return 0; - /* - * Here we must've gotten an SID by accepting an FLOGI - * from a point-to-point connection. Switch to using - * the source mac based on the SID. The destination - * MAC in this case would have been set by receving the - * FLOGI. - */ - fip->flogi_oxid = FC_XID_UNKNOWN; - fc_fcoe_set_mac(mac, fh->fh_d_id); - fip->update_mac(lport, mac); - return 0; - default: - if (fip->state != FIP_ST_ENABLED) - goto drop; - return 0; - } - if (fcoe_ctlr_encaps(fip, lport, op, skb)) - goto drop; - fip->send(fip, skb); - return -EINPROGRESS; -drop: - kfree_skb(skb); - return -EINVAL; -} -EXPORT_SYMBOL(fcoe_ctlr_els_send); - -/** - * fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller - * @fip: The FCoE controller to free FCFs on - * - * Called with lock held. - * - * An FCF is considered old if we have missed three advertisements. - * That is, there have been no valid advertisement from it for three - * times its keep-alive period including fuzz. - * - * In addition, determine the time when an FCF selection can occur. - * - * Also, increment the MissDiscAdvCount when no advertisement is received - * for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB). - */ -static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) -{ - struct fcoe_fcf *fcf; - struct fcoe_fcf *next; - unsigned long sel_time = 0; - unsigned long mda_time = 0; - - list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { - mda_time = fcf->fka_period + (fcf->fka_period >> 1); - if ((fip->sel_fcf == fcf) && - (time_after(jiffies, fcf->time + mda_time))) { - mod_timer(&fip->timer, jiffies + mda_time); - fc_lport_get_stats(fip->lp)->MissDiscAdvCount++; - printk(KERN_INFO "libfcoe: host%d: Missing Discovery " - "Advertisement for fab %llx count %lld\n", - fip->lp->host->host_no, fcf->fabric_name, - fc_lport_get_stats(fip->lp)->MissDiscAdvCount); - } - if (time_after(jiffies, fcf->time + fcf->fka_period * 3 + - msecs_to_jiffies(FIP_FCF_FUZZ * 3))) { - if (fip->sel_fcf == fcf) - fip->sel_fcf = NULL; - list_del(&fcf->list); - WARN_ON(!fip->fcf_count); - fip->fcf_count--; - kfree(fcf); - fc_lport_get_stats(fip->lp)->VLinkFailureCount++; - } else if (fcoe_ctlr_mtu_valid(fcf) && - (!sel_time || time_before(sel_time, fcf->time))) { - sel_time = fcf->time; - } - } - if (sel_time) { - sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); - fip->sel_time = sel_time; - if (time_before(sel_time, fip->timer.expires)) - mod_timer(&fip->timer, sel_time); - } else { - fip->sel_time = 0; - } -} - -/** - * fcoe_ctlr_parse_adv() - Decode a FIP advertisement into a new FCF entry - * @fip: The FCoE controller receiving the advertisement - * @skb: The received FIP advertisement frame - * @fcf: The resulting FCF entry - * - * Returns zero on a valid parsed advertisement, - * otherwise returns non zero value. - */ -static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, - struct sk_buff *skb, struct fcoe_fcf *fcf) -{ - struct fip_header *fiph; - struct fip_desc *desc = NULL; - struct fip_wwn_desc *wwn; - struct fip_fab_desc *fab; - struct fip_fka_desc *fka; - unsigned long t; - size_t rlen; - size_t dlen; - - memset(fcf, 0, sizeof(*fcf)); - fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA); - - fiph = (struct fip_header *)skb->data; - fcf->flags = ntohs(fiph->fip_flags); - - rlen = ntohs(fiph->fip_dl_len) * 4; - if (rlen + sizeof(*fiph) > skb->len) - return -EINVAL; - - desc = (struct fip_desc *)(fiph + 1); - while (rlen > 0) { - dlen = desc->fip_dlen * FIP_BPW; - if (dlen < sizeof(*desc) || dlen > rlen) - return -EINVAL; - switch (desc->fip_dtype) { - case FIP_DT_PRI: - if (dlen != sizeof(struct fip_pri_desc)) - goto len_err; - fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri; - break; - case FIP_DT_MAC: - if (dlen != sizeof(struct fip_mac_desc)) - goto len_err; - memcpy(fcf->fcf_mac, - ((struct fip_mac_desc *)desc)->fd_mac, - ETH_ALEN); - if (!is_valid_ether_addr(fcf->fcf_mac)) { - LIBFCOE_FIP_DBG(fip, "Invalid MAC address " - "in FIP adv\n"); - return -EINVAL; - } - break; - case FIP_DT_NAME: - if (dlen != sizeof(struct fip_wwn_desc)) - goto len_err; - wwn = (struct fip_wwn_desc *)desc; - fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn); - break; - case FIP_DT_FAB: - if (dlen != sizeof(struct fip_fab_desc)) - goto len_err; - fab = (struct fip_fab_desc *)desc; - fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn); - fcf->vfid = ntohs(fab->fd_vfid); - fcf->fc_map = ntoh24(fab->fd_map); - break; - case FIP_DT_FKA: - if (dlen != sizeof(struct fip_fka_desc)) - goto len_err; - fka = (struct fip_fka_desc *)desc; - if (fka->fd_flags & FIP_FKA_ADV_D) - fcf->fd_flags = 1; - t = ntohl(fka->fd_fka_period); - if (t >= FCOE_CTLR_MIN_FKA) - fcf->fka_period = msecs_to_jiffies(t); - break; - case FIP_DT_MAP_OUI: - case FIP_DT_FCOE_SIZE: - case FIP_DT_FLOGI: - case FIP_DT_FDISC: - case FIP_DT_LOGO: - case FIP_DT_ELP: - default: - LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x " - "in FIP adv\n", desc->fip_dtype); - /* standard says ignore unknown descriptors >= 128 */ - if (desc->fip_dtype < FIP_DT_VENDOR_BASE) - return -EINVAL; - continue; - } - desc = (struct fip_desc *)((char *)desc + dlen); - rlen -= dlen; - } - if (!fcf->fc_map || (fcf->fc_map & 0x10000)) - return -EINVAL; - if (!fcf->switch_name || !fcf->fabric_name) - return -EINVAL; - return 0; - -len_err: - LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n", - desc->fip_dtype, dlen); - return -EINVAL; -} - -/** - * fcoe_ctlr_recv_adv() - Handle an incoming advertisement - * @fip: The FCoE controller receiving the advertisement - * @skb: The received FIP packet - */ -static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - struct fcoe_fcf *fcf; - struct fcoe_fcf new; - struct fcoe_fcf *found; - unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV); - int first = 0; - int mtu_valid; - - if (fcoe_ctlr_parse_adv(fip, skb, &new)) - return; - - spin_lock_bh(&fip->lock); - first = list_empty(&fip->fcfs); - found = NULL; - list_for_each_entry(fcf, &fip->fcfs, list) { - if (fcf->switch_name == new.switch_name && - fcf->fabric_name == new.fabric_name && - fcf->fc_map == new.fc_map && - compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) { - found = fcf; - break; - } - } - if (!found) { - if (fip->fcf_count >= FCOE_CTLR_FCF_LIMIT) - goto out; - - fcf = kmalloc(sizeof(*fcf), GFP_ATOMIC); - if (!fcf) - goto out; - - fip->fcf_count++; - memcpy(fcf, &new, sizeof(new)); - list_add(&fcf->list, &fip->fcfs); - } else { - /* - * Flags in advertisements are ignored once the FCF is - * selected. Flags in unsolicited advertisements are - * ignored after a usable solicited advertisement - * has been received. - */ - if (fcf == fip->sel_fcf) { - fip->ctlr_ka_time -= fcf->fka_period; - fip->ctlr_ka_time += new.fka_period; - if (time_before(fip->ctlr_ka_time, fip->timer.expires)) - mod_timer(&fip->timer, fip->ctlr_ka_time); - } else if (!fcoe_ctlr_fcf_usable(fcf)) - fcf->flags = new.flags; - fcf->fka_period = new.fka_period; - memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN); - } - mtu_valid = fcoe_ctlr_mtu_valid(fcf); - fcf->time = jiffies; - if (!found) { - LIBFCOE_FIP_DBG(fip, "New FCF for fab %llx map %x val %d\n", - fcf->fabric_name, fcf->fc_map, mtu_valid); - } - - /* - * If this advertisement is not solicited and our max receive size - * hasn't been verified, send a solicited advertisement. - */ - if (!mtu_valid) - fcoe_ctlr_solicit(fip, fcf); - - /* - * If its been a while since we did a solicit, and this is - * the first advertisement we've received, do a multicast - * solicitation to gather as many advertisements as we can - * before selection occurs. - */ - if (first && time_after(jiffies, fip->sol_time + sol_tov)) - fcoe_ctlr_solicit(fip, NULL); - - /* - * If this is the first validated FCF, note the time and - * set a timer to trigger selection. - */ - if (mtu_valid && !fip->sel_time && fcoe_ctlr_fcf_usable(fcf)) { - fip->sel_time = jiffies + - msecs_to_jiffies(FCOE_CTLR_START_DELAY); - if (!timer_pending(&fip->timer) || - time_before(fip->sel_time, fip->timer.expires)) - mod_timer(&fip->timer, fip->sel_time); - } -out: - spin_unlock_bh(&fip->lock); -} - -/** - * fcoe_ctlr_recv_els() - Handle an incoming FIP encapsulated ELS frame - * @fip: The FCoE controller which received the packet - * @skb: The received FIP packet - */ -static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - struct fc_lport *lport = fip->lp; - struct fip_header *fiph; - struct fc_frame *fp = (struct fc_frame *)skb; - struct fc_frame_header *fh = NULL; - struct fip_desc *desc; - struct fip_encaps *els; - struct fcoe_dev_stats *stats; - enum fip_desc_type els_dtype = 0; - u8 els_op; - u8 sub; - u8 granted_mac[ETH_ALEN] = { 0 }; - size_t els_len = 0; - size_t rlen; - size_t dlen; - - fiph = (struct fip_header *)skb->data; - sub = fiph->fip_subcode; - if (sub != FIP_SC_REQ && sub != FIP_SC_REP) - goto drop; - - rlen = ntohs(fiph->fip_dl_len) * 4; - if (rlen + sizeof(*fiph) > skb->len) - goto drop; - - desc = (struct fip_desc *)(fiph + 1); - while (rlen > 0) { - dlen = desc->fip_dlen * FIP_BPW; - if (dlen < sizeof(*desc) || dlen > rlen) - goto drop; - switch (desc->fip_dtype) { - case FIP_DT_MAC: - if (dlen != sizeof(struct fip_mac_desc)) - goto len_err; - memcpy(granted_mac, - ((struct fip_mac_desc *)desc)->fd_mac, - ETH_ALEN); - if (!is_valid_ether_addr(granted_mac)) { - LIBFCOE_FIP_DBG(fip, "Invalid MAC address " - "in FIP ELS\n"); - goto drop; - } - memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN); - break; - case FIP_DT_FLOGI: - case FIP_DT_FDISC: - case FIP_DT_LOGO: - case FIP_DT_ELP: - if (fh) - goto drop; - if (dlen < sizeof(*els) + sizeof(*fh) + 1) - goto len_err; - els_len = dlen - sizeof(*els); - els = (struct fip_encaps *)desc; - fh = (struct fc_frame_header *)(els + 1); - els_dtype = desc->fip_dtype; - break; - default: - LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x " - "in FIP adv\n", desc->fip_dtype); - /* standard says ignore unknown descriptors >= 128 */ - if (desc->fip_dtype < FIP_DT_VENDOR_BASE) - goto drop; - continue; - } - desc = (struct fip_desc *)((char *)desc + dlen); - rlen -= dlen; - } - - if (!fh) - goto drop; - els_op = *(u8 *)(fh + 1); - - if (els_dtype == FIP_DT_FLOGI && sub == FIP_SC_REP && - fip->flogi_oxid == ntohs(fh->fh_ox_id) && - els_op == ELS_LS_ACC && is_valid_ether_addr(granted_mac)) - fip->flogi_oxid = FC_XID_UNKNOWN; - - /* - * Convert skb into an fc_frame containing only the ELS. - */ - skb_pull(skb, (u8 *)fh - skb->data); - skb_trim(skb, els_len); - fp = (struct fc_frame *)skb; - fc_frame_init(fp); - fr_sof(fp) = FC_SOF_I3; - fr_eof(fp) = FC_EOF_T; - fr_dev(fp) = lport; - - stats = fc_lport_get_stats(lport); - stats->RxFrames++; - stats->RxWords += skb->len / FIP_BPW; - - fc_exch_recv(lport, fp); - return; - -len_err: - LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n", - desc->fip_dtype, dlen); -drop: - kfree_skb(skb); -} - -/** - * fcoe_ctlr_recv_els() - Handle an incoming link reset frame - * @fip: The FCoE controller that received the frame - * @fh: The received FIP header - * - * There may be multiple VN_Port descriptors. - * The overall length has already been checked. - */ -static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, - struct fip_header *fh) -{ - struct fip_desc *desc; - struct fip_mac_desc *mp; - struct fip_wwn_desc *wp; - struct fip_vn_desc *vp; - size_t rlen; - size_t dlen; - struct fcoe_fcf *fcf = fip->sel_fcf; - struct fc_lport *lport = fip->lp; - u32 desc_mask; - - LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n"); - if (!fcf) - return; - if (!fcf || !fc_host_port_id(lport->host)) - return; - - /* - * mask of required descriptors. Validating each one clears its bit. - */ - desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) | BIT(FIP_DT_VN_ID); - - rlen = ntohs(fh->fip_dl_len) * FIP_BPW; - desc = (struct fip_desc *)(fh + 1); - while (rlen >= sizeof(*desc)) { - dlen = desc->fip_dlen * FIP_BPW; - if (dlen > rlen) - return; - switch (desc->fip_dtype) { - case FIP_DT_MAC: - mp = (struct fip_mac_desc *)desc; - if (dlen < sizeof(*mp)) - return; - if (compare_ether_addr(mp->fd_mac, fcf->fcf_mac)) - return; - desc_mask &= ~BIT(FIP_DT_MAC); - break; - case FIP_DT_NAME: - wp = (struct fip_wwn_desc *)desc; - if (dlen < sizeof(*wp)) - return; - if (get_unaligned_be64(&wp->fd_wwn) != fcf->switch_name) - return; - desc_mask &= ~BIT(FIP_DT_NAME); - break; - case FIP_DT_VN_ID: - vp = (struct fip_vn_desc *)desc; - if (dlen < sizeof(*vp)) - return; - if (compare_ether_addr(vp->fd_mac, - fip->get_src_addr(lport)) == 0 && - get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn && - ntoh24(vp->fd_fc_id) == - fc_host_port_id(lport->host)) - desc_mask &= ~BIT(FIP_DT_VN_ID); - break; - default: - /* standard says ignore unknown descriptors >= 128 */ - if (desc->fip_dtype < FIP_DT_VENDOR_BASE) - return; - break; - } - desc = (struct fip_desc *)((char *)desc + dlen); - rlen -= dlen; - } - - /* - * reset only if all required descriptors were present and valid. - */ - if (desc_mask) { - LIBFCOE_FIP_DBG(fip, "missing descriptors mask %x\n", - desc_mask); - } else { - LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n"); - - spin_lock_bh(&fip->lock); - fc_lport_get_stats(lport)->VLinkFailureCount++; - fcoe_ctlr_reset(fip); - spin_unlock_bh(&fip->lock); - - fc_lport_reset(fip->lp); - fcoe_ctlr_solicit(fip, NULL); - } -} - -/** - * fcoe_ctlr_recv() - Receive a FIP packet - * @fip: The FCoE controller that received the packet - * @skb: The received FIP packet - * - * This may be called from either NET_RX_SOFTIRQ or IRQ. - */ -void fcoe_ctlr_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - skb_queue_tail(&fip->fip_recv_list, skb); - schedule_work(&fip->recv_work); -} -EXPORT_SYMBOL(fcoe_ctlr_recv); - -/** - * fcoe_ctlr_recv_handler() - Receive a FIP frame - * @fip: The FCoE controller that received the frame - * @skb: The received FIP frame - * - * Returns non-zero if the frame is dropped. - */ -static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - struct fip_header *fiph; - struct ethhdr *eh; - enum fip_state state; - u16 op; - u8 sub; - - if (skb_linearize(skb)) - goto drop; - if (skb->len < sizeof(*fiph)) - goto drop; - eh = eth_hdr(skb); - if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) && - compare_ether_addr(eh->h_dest, FIP_ALL_ENODE_MACS)) - goto drop; - fiph = (struct fip_header *)skb->data; - op = ntohs(fiph->fip_op); - sub = fiph->fip_subcode; - - if (FIP_VER_DECAPS(fiph->fip_ver) != FIP_VER) - goto drop; - if (ntohs(fiph->fip_dl_len) * FIP_BPW + sizeof(*fiph) > skb->len) - goto drop; - - spin_lock_bh(&fip->lock); - state = fip->state; - if (state == FIP_ST_AUTO) { - fip->map_dest = 0; - fip->state = FIP_ST_ENABLED; - state = FIP_ST_ENABLED; - LIBFCOE_FIP_DBG(fip, "Using FIP mode\n"); - } - spin_unlock_bh(&fip->lock); - if (state != FIP_ST_ENABLED) - goto drop; - - if (op == FIP_OP_LS) { - fcoe_ctlr_recv_els(fip, skb); /* consumes skb */ - return 0; - } - if (op == FIP_OP_DISC && sub == FIP_SC_ADV) - fcoe_ctlr_recv_adv(fip, skb); - else if (op == FIP_OP_CTRL && sub == FIP_SC_CLR_VLINK) - fcoe_ctlr_recv_clr_vlink(fip, fiph); - kfree_skb(skb); - return 0; -drop: - kfree_skb(skb); - return -1; -} - -/** - * fcoe_ctlr_select() - Select the best FCF (if possible) - * @fip: The FCoE controller - * - * If there are conflicting advertisements, no FCF can be chosen. - * - * Called with lock held. - */ -static void fcoe_ctlr_select(struct fcoe_ctlr *fip) -{ - struct fcoe_fcf *fcf; - struct fcoe_fcf *best = NULL; - - list_for_each_entry(fcf, &fip->fcfs, list) { - LIBFCOE_FIP_DBG(fip, "consider FCF for fab %llx VFID %d map %x " - "val %d\n", fcf->fabric_name, fcf->vfid, - fcf->fc_map, fcoe_ctlr_mtu_valid(fcf)); - if (!fcoe_ctlr_fcf_usable(fcf)) { - LIBFCOE_FIP_DBG(fip, "FCF for fab %llx map %x %svalid " - "%savailable\n", fcf->fabric_name, - fcf->fc_map, (fcf->flags & FIP_FL_SOL) - ? "" : "in", (fcf->flags & FIP_FL_AVAIL) - ? "" : "un"); - continue; - } - if (!best) { - best = fcf; - continue; - } - if (fcf->fabric_name != best->fabric_name || - fcf->vfid != best->vfid || - fcf->fc_map != best->fc_map) { - LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, " - "or FC-MAP\n"); - return; - } - if (fcf->pri < best->pri) - best = fcf; - } - fip->sel_fcf = best; -} - -/** - * fcoe_ctlr_timeout() - FIP timeout handler - * @arg: The FCoE controller that timed out - * - * Ages FCFs. Triggers FCF selection if possible. Sends keep-alives. - */ -static void fcoe_ctlr_timeout(unsigned long arg) -{ - struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg; - struct fcoe_fcf *sel; - struct fcoe_fcf *fcf; - unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); - - spin_lock_bh(&fip->lock); - if (fip->state == FIP_ST_DISABLED) { - spin_unlock_bh(&fip->lock); - return; - } - - fcf = fip->sel_fcf; - fcoe_ctlr_age_fcfs(fip); - - sel = fip->sel_fcf; - if (!sel && fip->sel_time && time_after_eq(jiffies, fip->sel_time)) { - fcoe_ctlr_select(fip); - sel = fip->sel_fcf; - fip->sel_time = 0; - } - - if (sel != fcf) { - fcf = sel; /* the old FCF may have been freed */ - if (sel) { - printk(KERN_INFO "libfcoe: host%d: FIP selected " - "Fibre-Channel Forwarder MAC %pM\n", - fip->lp->host->host_no, sel->fcf_mac); - memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN); - fip->port_ka_time = jiffies + - msecs_to_jiffies(FIP_VN_KA_PERIOD); - fip->ctlr_ka_time = jiffies + sel->fka_period; - } else { - printk(KERN_NOTICE "libfcoe: host%d: " - "FIP Fibre-Channel Forwarder timed out. " - "Starting FCF discovery.\n", - fip->lp->host->host_no); - fip->reset_req = 1; - schedule_work(&fip->link_work); - } - } - - if (sel && !sel->fd_flags) { - if (time_after_eq(jiffies, fip->ctlr_ka_time)) { - fip->ctlr_ka_time = jiffies + sel->fka_period; - fip->send_ctlr_ka = 1; - } - if (time_after(next_timer, fip->ctlr_ka_time)) - next_timer = fip->ctlr_ka_time; - - if (time_after_eq(jiffies, fip->port_ka_time)) { - fip->port_ka_time += jiffies + - msecs_to_jiffies(FIP_VN_KA_PERIOD); - fip->send_port_ka = 1; - } - if (time_after(next_timer, fip->port_ka_time)) - next_timer = fip->port_ka_time; - mod_timer(&fip->timer, next_timer); - } else if (fip->sel_time) { - next_timer = fip->sel_time + - msecs_to_jiffies(FCOE_CTLR_START_DELAY); - mod_timer(&fip->timer, next_timer); - } - if (fip->send_ctlr_ka || fip->send_port_ka) - schedule_work(&fip->link_work); - spin_unlock_bh(&fip->lock); -} - -/** - * fcoe_ctlr_link_work() - Worker thread function for link changes - * @work: Handle to a FCoE controller - * - * See if the link status has changed and if so, report it. - * - * This is here because fc_linkup() and fc_linkdown() must not - * be called from the timer directly, since they use a mutex. - */ -static void fcoe_ctlr_link_work(struct work_struct *work) -{ - struct fcoe_ctlr *fip; - struct fc_lport *vport; - u8 *mac; - int link; - int last_link; - int reset; - - fip = container_of(work, struct fcoe_ctlr, link_work); - spin_lock_bh(&fip->lock); - last_link = fip->last_link; - link = fip->link; - fip->last_link = link; - reset = fip->reset_req; - fip->reset_req = 0; - spin_unlock_bh(&fip->lock); - - if (last_link != link) { - if (link) - fc_linkup(fip->lp); - else - fc_linkdown(fip->lp); - } else if (reset && link) - fc_lport_reset(fip->lp); - - if (fip->send_ctlr_ka) { - fip->send_ctlr_ka = 0; - fcoe_ctlr_send_keep_alive(fip, NULL, 0, fip->ctl_src_addr); - } - if (fip->send_port_ka) { - fip->send_port_ka = 0; - mutex_lock(&fip->lp->lp_mutex); - mac = fip->get_src_addr(fip->lp); - fcoe_ctlr_send_keep_alive(fip, fip->lp, 1, mac); - list_for_each_entry(vport, &fip->lp->vports, list) { - mac = fip->get_src_addr(vport); - fcoe_ctlr_send_keep_alive(fip, vport, 1, mac); - } - mutex_unlock(&fip->lp->lp_mutex); - } -} - -/** - * fcoe_ctlr_recv_work() - Worker thread function for receiving FIP frames - * @recv_work: Handle to a FCoE controller - */ -static void fcoe_ctlr_recv_work(struct work_struct *recv_work) -{ - struct fcoe_ctlr *fip; - struct sk_buff *skb; - - fip = container_of(recv_work, struct fcoe_ctlr, recv_work); - while ((skb = skb_dequeue(&fip->fip_recv_list))) - fcoe_ctlr_recv_handler(fip, skb); -} - -/** - * fcoe_ctlr_recv_flogi() - Snoop pre-FIP receipt of FLOGI response - * @fip: The FCoE controller - * @fp: The FC frame to snoop - * - * Snoop potential response to FLOGI or even incoming FLOGI. - * - * The caller has checked that we are waiting for login as indicated - * by fip->flogi_oxid != FC_XID_UNKNOWN. - * - * The caller is responsible for freeing the frame. - * Fill in the granted_mac address. - * - * Return non-zero if the frame should not be delivered to libfc. - */ -int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport, - struct fc_frame *fp) -{ - struct fc_frame_header *fh; - u8 op; - u8 *sa; - - sa = eth_hdr(&fp->skb)->h_source; - fh = fc_frame_header_get(fp); - if (fh->fh_type != FC_TYPE_ELS) - return 0; - - op = fc_frame_payload_op(fp); - if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP && - fip->flogi_oxid == ntohs(fh->fh_ox_id)) { - - spin_lock_bh(&fip->lock); - if (fip->state != FIP_ST_AUTO && fip->state != FIP_ST_NON_FIP) { - spin_unlock_bh(&fip->lock); - return -EINVAL; - } - fip->state = FIP_ST_NON_FIP; - LIBFCOE_FIP_DBG(fip, - "received FLOGI LS_ACC using non-FIP mode\n"); - - /* - * FLOGI accepted. - * If the src mac addr is FC_OUI-based, then we mark the - * address_mode flag to use FC_OUI-based Ethernet DA. - * Otherwise we use the FCoE gateway addr - */ - if (!compare_ether_addr(sa, (u8[6])FC_FCOE_FLOGI_MAC)) { - fip->map_dest = 1; - } else { - memcpy(fip->dest_addr, sa, ETH_ALEN); - fip->map_dest = 0; - } - fip->flogi_oxid = FC_XID_UNKNOWN; - spin_unlock_bh(&fip->lock); - fc_fcoe_set_mac(fr_cb(fp)->granted_mac, fh->fh_d_id); - } else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) { - /* - * Save source MAC for point-to-point responses. - */ - spin_lock_bh(&fip->lock); - if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) { - memcpy(fip->dest_addr, sa, ETH_ALEN); - fip->map_dest = 0; - if (fip->state == FIP_ST_NON_FIP) - LIBFCOE_FIP_DBG(fip, "received FLOGI REQ, " - "using non-FIP mode\n"); - fip->state = FIP_ST_NON_FIP; - } - spin_unlock_bh(&fip->lock); - } - return 0; -} -EXPORT_SYMBOL(fcoe_ctlr_recv_flogi); - -/** - * fcoe_wwn_from_mac() - Converts a 48-bit IEEE MAC address to a 64-bit FC WWN - * @mac: The MAC address to convert - * @scheme: The scheme to use when converting - * @port: The port indicator for converting - * - * Returns: u64 fc world wide name - */ -u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], - unsigned int scheme, unsigned int port) -{ - u64 wwn; - u64 host_mac; - - /* The MAC is in NO, so flip only the low 48 bits */ - host_mac = ((u64) mac[0] << 40) | - ((u64) mac[1] << 32) | - ((u64) mac[2] << 24) | - ((u64) mac[3] << 16) | - ((u64) mac[4] << 8) | - (u64) mac[5]; - - WARN_ON(host_mac >= (1ULL << 48)); - wwn = host_mac | ((u64) scheme << 60); - switch (scheme) { - case 1: - WARN_ON(port != 0); - break; - case 2: - WARN_ON(port >= 0xfff); - wwn |= (u64) port << 48; - break; - default: - WARN_ON(1); - break; - } - - return wwn; -} -EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac); - -/** - * fcoe_libfc_config() - Sets up libfc related properties for local port - * @lp: The local port to configure libfc for - * @tt: The libfc function template - * - * Returns : 0 for success - */ -int fcoe_libfc_config(struct fc_lport *lport, - struct libfc_function_template *tt) -{ - /* Set the function pointers set by the LLDD */ - memcpy(&lport->tt, tt, sizeof(*tt)); - if (fc_fcp_init(lport)) - return -ENOMEM; - fc_exch_init(lport); - fc_elsct_init(lport); - fc_lport_init(lport); - fc_rport_init(lport); - fc_disc_init(lport); - - return 0; -} -EXPORT_SYMBOL_GPL(fcoe_libfc_config); - |
