diff options
Diffstat (limited to 'drivers/scsi/fcoe/libfcoe.c')
-rw-r--r-- | drivers/scsi/fcoe/libfcoe.c | 433 |
1 files changed, 236 insertions, 197 deletions
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 11ae5c94608..9823291395a 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -59,26 +59,30 @@ 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_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); \ +#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(fmt, args...) \ +#define LIBFCOE_FIP_DBG(fip, fmt, args...) \ LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING, \ - printk(KERN_INFO "fip: " fmt, ##args);) + 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) @@ -86,7 +90,10 @@ 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) @@ -97,12 +104,13 @@ static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf) } /** - * fcoe_ctlr_init() - Initialize the FCoE Controller instance. - * @fip: FCoE controller. + * 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; @@ -114,8 +122,8 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip) EXPORT_SYMBOL(fcoe_ctlr_init); /** - * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller. - * @fip: FCoE controller. + * 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. */ @@ -134,8 +142,8 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip) } /** - * fcoe_ctlr_destroy() - Disable and tear-down the FCoE controller. - * @fip: FCoE controller. + * 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. * @@ -148,9 +156,7 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip) void fcoe_ctlr_destroy(struct fcoe_ctlr *fip) { cancel_work_sync(&fip->recv_work); - spin_lock_bh(&fip->fip_recv_list.lock); - __skb_queue_purge(&fip->fip_recv_list); - spin_unlock_bh(&fip->fip_recv_list.lock); + skb_queue_purge(&fip->fip_recv_list); spin_lock_bh(&fip->lock); fip->state = FIP_ST_DISABLED; @@ -162,8 +168,8 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip) EXPORT_SYMBOL(fcoe_ctlr_destroy); /** - * fcoe_ctlr_fcoe_size() - Return the maximum FCoE size required for VN_Port. - * @fip: FCoE controller. + * 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. @@ -180,9 +186,9 @@ static inline u32 fcoe_ctlr_fcoe_size(struct fcoe_ctlr *fip) } /** - * fcoe_ctlr_solicit() - Send a solicitation. - * @fip: FCoE controller. - * @fcf: Destination FCF. If NULL, a multicast solicitation is sent. + * 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) { @@ -241,8 +247,8 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf) } /** - * fcoe_ctlr_link_up() - Start FCoE controller. - * @fip: FCoE controller. + * fcoe_ctlr_link_up() - Start FCoE controller + * @fip: The FCoE controller to start * * Called from the LLD when the network link is ready. */ @@ -255,11 +261,12 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip) spin_unlock_bh(&fip->lock); fc_linkup(fip->lp); } else if (fip->state == FIP_ST_LINK_WAIT) { - fip->state = FIP_ST_AUTO; + fip->state = fip->mode; fip->last_link = 1; fip->link = 1; spin_unlock_bh(&fip->lock); - LIBFCOE_FIP_DBG("%s", "setting AUTO mode.\n"); + 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 @@ -268,45 +275,23 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip) EXPORT_SYMBOL(fcoe_ctlr_link_up); /** - * fcoe_ctlr_reset() - Reset FIP. - * @fip: FCoE controller. - * @new_state: FIP state to be entered. - * - * Returns non-zero if the link was up and now isn't. + * fcoe_ctlr_reset() - Reset a FCoE controller + * @fip: The FCoE controller to reset */ -static int fcoe_ctlr_reset(struct fcoe_ctlr *fip, enum fip_state new_state) +static void fcoe_ctlr_reset(struct fcoe_ctlr *fip) { - struct fc_lport *lp = fip->lp; - int link_dropped; - - spin_lock_bh(&fip->lock); fcoe_ctlr_reset_fcfs(fip); del_timer(&fip->timer); - fip->state = new_state; fip->ctlr_ka_time = 0; fip->port_ka_time = 0; fip->sol_time = 0; fip->flogi_oxid = FC_XID_UNKNOWN; fip->map_dest = 0; - fip->last_link = 0; - link_dropped = fip->link; - fip->link = 0; - spin_unlock_bh(&fip->lock); - - if (link_dropped) - fc_linkdown(lp); - - if (new_state == FIP_ST_ENABLED) { - fcoe_ctlr_solicit(fip, NULL); - fc_linkup(lp); - link_dropped = 0; - } - return link_dropped; } /** - * fcoe_ctlr_link_down() - Stop FCoE controller. - * @fip: FCoE controller. + * 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. * @@ -315,15 +300,29 @@ static int fcoe_ctlr_reset(struct fcoe_ctlr *fip, enum fip_state new_state) */ int fcoe_ctlr_link_down(struct fcoe_ctlr *fip) { - return fcoe_ctlr_reset(fip, FIP_ST_LINK_WAIT); + 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: FCoE controller. - * @ports: 0 for controller keep-alive, 1 for port keep-alive. - * @sa: source MAC address. + * 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. @@ -332,7 +331,9 @@ EXPORT_SYMBOL(fcoe_ctlr_link_down); * 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, int ports, u8 *sa) +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 { @@ -350,8 +351,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa) if (!fcf || !fc_host_port_id(lp->host)) return; - len = fcoe_ctlr_fcoe_size(fip) + sizeof(struct ethhdr); - BUG_ON(len < sizeof(*kal) + sizeof(*vn)); + len = sizeof(*kal) + ports * sizeof(*vn); skb = dev_alloc_skb(len); if (!skb) return; @@ -366,7 +366,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa) 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); + ports * sizeof(*vn)) / FIP_BPW); kal->fip.fip_flags = htons(FIP_FL_FPMA); if (fip->spma) kal->fip.fip_flags |= htons(FIP_FL_SPMA); @@ -374,16 +374,14 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa) 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->data_src_addr, ETH_ALEN); + 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); @@ -392,10 +390,10 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa) } /** - * fcoe_ctlr_encaps() - Encapsulate an ELS frame for FIP, without sending it. - * @fip: FCoE controller. - * @dtype: FIP descriptor type for the frame. - * @skb: FCoE ELS frame including FC header but no FCoE headers. + * 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. * @@ -405,7 +403,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, int ports, u8 *sa) * 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, +static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, u8 dtype, struct sk_buff *skb) { struct fip_encaps_head { @@ -449,8 +447,8 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, 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) - memcpy(mac->fd_mac, fip->data_src_addr, ETH_ALEN); + 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); @@ -463,6 +461,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, /** * 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. @@ -471,11 +470,13 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, * 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 sk_buff *skb) +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); @@ -498,6 +499,8 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct sk_buff *skb) if (fip->state == FIP_ST_NON_FIP) return 0; + if (!fip->sel_fcf) + goto drop; switch (op) { case ELS_FLOGI: @@ -530,14 +533,15 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct sk_buff *skb) * FLOGI. */ fip->flogi_oxid = FC_XID_UNKNOWN; - fc_fcoe_set_mac(fip->data_src_addr, fh->fh_s_id); + 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, op, skb)) + if (fcoe_ctlr_encaps(fip, lport, op, skb)) goto drop; fip->send(fip, skb); return -EINPROGRESS; @@ -547,9 +551,9 @@ drop: } EXPORT_SYMBOL(fcoe_ctlr_els_send); -/* - * fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller. - * @fip: FCoE controller. +/** + * 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. * @@ -558,14 +562,28 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send); * 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) @@ -574,6 +592,7 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) 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; @@ -590,14 +609,16 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) } /** - * fcoe_ctlr_parse_adv() - Decode a FIP advertisement into a new FCF entry. - * @skb: received FIP advertisement frame - * @fcf: resulting FCF entry. + * 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 sk_buff *skb, struct fcoe_fcf *fcf) +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; @@ -636,7 +657,7 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf) ((struct fip_mac_desc *)desc)->fd_mac, ETH_ALEN); if (!is_valid_ether_addr(fcf->fcf_mac)) { - LIBFCOE_FIP_DBG("Invalid MAC address " + LIBFCOE_FIP_DBG(fip, "Invalid MAC address " "in FIP adv\n"); return -EINVAL; } @@ -659,6 +680,8 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf) 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); @@ -670,7 +693,7 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf) case FIP_DT_LOGO: case FIP_DT_ELP: default: - LIBFCOE_FIP_DBG("unexpected descriptor type %x " + 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) @@ -687,15 +710,15 @@ static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf) return 0; len_err: - LIBFCOE_FIP_DBG("FIP length error in descriptor type %x len %zu\n", + 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: FCoE controller. - * @skb: Received FIP packet. + * 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) { @@ -706,7 +729,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) int first = 0; int mtu_valid; - if (fcoe_ctlr_parse_adv(skb, &new)) + if (fcoe_ctlr_parse_adv(fip, skb, &new)) return; spin_lock_bh(&fip->lock); @@ -752,7 +775,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) mtu_valid = fcoe_ctlr_mtu_valid(fcf); fcf->time = jiffies; if (!found) { - LIBFCOE_FIP_DBG("New FCF for fab %llx map %x val %d\n", + LIBFCOE_FIP_DBG(fip, "New FCF for fab %llx map %x val %d\n", fcf->fabric_name, fcf->fc_map, mtu_valid); } @@ -778,7 +801,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) */ if (mtu_valid && !fip->sel_time && fcoe_ctlr_fcf_usable(fcf)) { fip->sel_time = jiffies + - msecs_to_jiffies(FCOE_CTLR_START_DELAY); + 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); @@ -788,15 +811,15 @@ out: } /** - * fcoe_ctlr_recv_els() - Handle an incoming FIP-encapsulated ELS frame. - * @fip: FCoE controller. - * @skb: Received FIP packet. + * 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 *lp = fip->lp; + struct fc_lport *lport = fip->lp; struct fip_header *fiph; - struct fc_frame *fp; + struct fc_frame *fp = (struct fc_frame *)skb; struct fc_frame_header *fh = NULL; struct fip_desc *desc; struct fip_encaps *els; @@ -831,10 +854,11 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) ((struct fip_mac_desc *)desc)->fd_mac, ETH_ALEN); if (!is_valid_ether_addr(granted_mac)) { - LIBFCOE_FIP_DBG("Invalid MAC address " + 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: @@ -850,7 +874,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) els_dtype = desc->fip_dtype; break; default: - LIBFCOE_FIP_DBG("unexpected descriptor type %x " + 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) @@ -867,11 +891,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) 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)) { + els_op == ELS_LS_ACC && is_valid_ether_addr(granted_mac)) fip->flogi_oxid = FC_XID_UNKNOWN; - fip->update_mac(fip, fip->data_src_addr, granted_mac); - memcpy(fip->data_src_addr, granted_mac, ETH_ALEN); - } /* * Convert skb into an fc_frame containing only the ELS. @@ -882,32 +903,32 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) fc_frame_init(fp); fr_sof(fp) = FC_SOF_I3; fr_eof(fp) = FC_EOF_T; - fr_dev(fp) = lp; + fr_dev(fp) = lport; - stats = fc_lport_get_stats(lp); + stats = fc_lport_get_stats(lport); stats->RxFrames++; stats->RxWords += skb->len / FIP_BPW; - fc_exch_recv(lp, fp); + fc_exch_recv(lport, fp); return; len_err: - LIBFCOE_FIP_DBG("FIP length error in descriptor type %x len %zu\n", + 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: FCoE controller. - * @fh: Received FIP header. + * 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_header *fh) { struct fip_desc *desc; struct fip_mac_desc *mp; @@ -916,13 +937,13 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, size_t rlen; size_t dlen; struct fcoe_fcf *fcf = fip->sel_fcf; - struct fc_lport *lp = fip->lp; + struct fc_lport *lport = fip->lp; u32 desc_mask; - LIBFCOE_FIP_DBG("Clear Virtual Link received\n"); + LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n"); if (!fcf) return; - if (!fcf || !fc_host_port_id(lp->host)) + if (!fcf || !fc_host_port_id(lport->host)) return; /* @@ -958,9 +979,10 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, if (dlen < sizeof(*vp)) return; if (compare_ether_addr(vp->fd_mac, - fip->data_src_addr) == 0 && - get_unaligned_be64(&vp->fd_wwpn) == lp->wwpn && - ntoh24(vp->fd_fc_id) == fc_host_port_id(lp->host)) + 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: @@ -977,33 +999,39 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, * reset only if all required descriptors were present and valid. */ if (desc_mask) { - LIBFCOE_FIP_DBG("missing descriptors mask %x\n", desc_mask); + LIBFCOE_FIP_DBG(fip, "missing descriptors mask %x\n", + desc_mask); } else { - LIBFCOE_FIP_DBG("performing Clear Virtual Link\n"); - fcoe_ctlr_reset(fip, FIP_ST_ENABLED); + 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 frame. - * @fip: FCoE controller. - * @skb: Received FIP packet. + * fcoe_ctlr_recv() - Receive a FIP packet + * @fip: The FCoE controller that received the packet + * @skb: The received FIP packet * - * This is called from NET_RX_SOFTIRQ. + * This may be called from either NET_RX_SOFTIRQ or IRQ. */ void fcoe_ctlr_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) { - spin_lock_bh(&fip->fip_recv_list.lock); - __skb_queue_tail(&fip->fip_recv_list, skb); - spin_unlock_bh(&fip->fip_recv_list.lock); + 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: FCoE controller. - * @skb: Received FIP packet. + * 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. */ @@ -1038,7 +1066,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) fip->map_dest = 0; fip->state = FIP_ST_ENABLED; state = FIP_ST_ENABLED; - LIBFCOE_FIP_DBG("Using FIP mode\n"); + LIBFCOE_FIP_DBG(fip, "Using FIP mode\n"); } spin_unlock_bh(&fip->lock); if (state != FIP_ST_ENABLED) @@ -1060,8 +1088,8 @@ drop: } /** - * fcoe_ctlr_select() - Select the best FCF, if possible. - * @fip: FCoE controller. + * fcoe_ctlr_select() - Select the best FCF (if possible) + * @fip: The FCoE controller * * If there are conflicting advertisements, no FCF can be chosen. * @@ -1073,11 +1101,11 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip) struct fcoe_fcf *best = NULL; list_for_each_entry(fcf, &fip->fcfs, list) { - LIBFCOE_FIP_DBG("consider FCF for fab %llx VFID %d map %x " + 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("FCF for fab %llx map %x %svalid " + 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) @@ -1091,7 +1119,7 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip) if (fcf->fabric_name != best->fabric_name || fcf->vfid != best->vfid || fcf->fc_map != best->fc_map) { - LIBFCOE_FIP_DBG("Conflicting fabric, VFID, " + LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, " "or FC-MAP\n"); return; } @@ -1102,8 +1130,8 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip) } /** - * fcoe_ctlr_timeout() - FIP timer function. - * @arg: &fcoe_ctlr pointer. + * fcoe_ctlr_timeout() - FIP timeout handler + * @arg: The FCoE controller that timed out * * Ages FCFs. Triggers FCF selection if possible. Sends keep-alives. */ @@ -1113,8 +1141,6 @@ static void fcoe_ctlr_timeout(unsigned long arg) struct fcoe_fcf *sel; struct fcoe_fcf *fcf; unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); - u8 send_ctlr_ka; - u8 send_port_ka; spin_lock_bh(&fip->lock); if (fip->state == FIP_ST_DISABLED) { @@ -1140,53 +1166,47 @@ static void fcoe_ctlr_timeout(unsigned long arg) 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); + msecs_to_jiffies(FIP_VN_KA_PERIOD); fip->ctlr_ka_time = jiffies + sel->fka_period; - fip->link = 1; } else { printk(KERN_NOTICE "libfcoe: host%d: " - "FIP Fibre-Channel Forwarder timed out. " + "FIP Fibre-Channel Forwarder timed out. " "Starting FCF discovery.\n", fip->lp->host->host_no); - fip->link = 0; + fip->reset_req = 1; + schedule_work(&fip->link_work); } - schedule_work(&fip->link_work); } - send_ctlr_ka = 0; - send_port_ka = 0; - if (sel) { + if (sel && !sel->fd_flags) { if (time_after_eq(jiffies, fip->ctlr_ka_time)) { fip->ctlr_ka_time = jiffies + sel->fka_period; - send_ctlr_ka = 1; + 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); - send_port_ka = 1; + 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); + 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); - - if (send_ctlr_ka) - fcoe_ctlr_send_keep_alive(fip, 0, fip->ctl_src_addr); - if (send_port_ka) - fcoe_ctlr_send_keep_alive(fip, 1, fip->data_src_addr); } /** - * fcoe_ctlr_link_work() - worker thread function for link changes. - * @work: pointer to link_work member inside &fcoe_ctlr. + * 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. * @@ -1196,27 +1216,49 @@ static void fcoe_ctlr_timeout(unsigned long arg) 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 - fcoe_ctlr_reset(fip, FIP_ST_LINK_WAIT); + 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: pointer to recv_work member inside &fcoe_ctlr. + * 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) { @@ -1224,20 +1266,14 @@ static void fcoe_ctlr_recv_work(struct work_struct *recv_work) struct sk_buff *skb; fip = container_of(recv_work, struct fcoe_ctlr, recv_work); - spin_lock_bh(&fip->fip_recv_list.lock); - while ((skb = __skb_dequeue(&fip->fip_recv_list))) { - spin_unlock_bh(&fip->fip_recv_list.lock); + while ((skb = skb_dequeue(&fip->fip_recv_list))) fcoe_ctlr_recv_handler(fip, skb); - spin_lock_bh(&fip->fip_recv_list.lock); - } - spin_unlock_bh(&fip->fip_recv_list.lock); } /** - * fcoe_ctlr_recv_flogi() - snoop Pre-FIP receipt of FLOGI response or request. - * @fip: FCoE controller. - * @fp: FC frame. - * @sa: Ethernet source MAC address from received FCoE frame. + * 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. * @@ -1245,15 +1281,18 @@ static void fcoe_ctlr_recv_work(struct work_struct *recv_work) * 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_frame *fp, u8 *sa) +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 mac[ETH_ALEN]; + u8 *sa; + sa = eth_hdr(&fp->skb)->h_source; fh = fc_frame_header_get(fp); if (fh->fh_type != FC_TYPE_ELS) return 0; @@ -1268,7 +1307,8 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa) return -EINVAL; } fip->state = FIP_ST_NON_FIP; - LIBFCOE_FIP_DBG("received FLOGI LS_ACC using non-FIP mode\n"); + LIBFCOE_FIP_DBG(fip, + "received FLOGI LS_ACC using non-FIP mode\n"); /* * FLOGI accepted. @@ -1283,11 +1323,8 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa) fip->map_dest = 0; } fip->flogi_oxid = FC_XID_UNKNOWN; - memcpy(mac, fip->data_src_addr, ETH_ALEN); - fc_fcoe_set_mac(fip->data_src_addr, fh->fh_d_id); spin_unlock_bh(&fip->lock); - - fip->update_mac(fip, mac, fip->data_src_addr); + 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. @@ -1297,7 +1334,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa) memcpy(fip->dest_addr, sa, ETH_ALEN); fip->map_dest = 0; if (fip->state == FIP_ST_NON_FIP) - LIBFCOE_FIP_DBG("received FLOGI REQ, " + LIBFCOE_FIP_DBG(fip, "received FLOGI REQ, " "using non-FIP mode\n"); fip->state = FIP_ST_NON_FIP; } @@ -1308,10 +1345,10 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_frame *fp, u8 *sa) EXPORT_SYMBOL(fcoe_ctlr_recv_flogi); /** - * fcoe_wwn_from_mac() - Converts 48-bit IEEE MAC address to 64-bit FC WWN. - * @mac: mac address - * @scheme: check port - * @port: port indicator for converting + * 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 */ @@ -1349,24 +1386,26 @@ u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac); /** - * fcoe_libfc_config() - sets up libfc related properties for lport - * @lp: ptr to the fc_lport - * @tt: libfc function template + * 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 *lp, struct libfc_function_template *tt) +int fcoe_libfc_config(struct fc_lport *lport, + struct libfc_function_template *tt) { /* Set the function pointers set by the LLDD */ - memcpy(&lp->tt, tt, sizeof(*tt)); - if (fc_fcp_init(lp)) + memcpy(&lport->tt, tt, sizeof(*tt)); + if (fc_fcp_init(lport)) return -ENOMEM; - fc_exch_init(lp); - fc_elsct_init(lp); - fc_lport_init(lp); - fc_rport_init(lp); - fc_disc_init(lp); + 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); + |