diff options
Diffstat (limited to 'drivers/scsi/fcoe')
-rw-r--r-- | drivers/scsi/fcoe/fcoe.c | 212 | ||||
-rw-r--r-- | drivers/scsi/fcoe/libfcoe.c | 111 |
2 files changed, 190 insertions, 133 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index f01b9b44e8aa..9276121db1ef 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -74,6 +74,7 @@ static int fcoe_rcv(struct sk_buff *, struct net_device *, static int fcoe_percpu_receive_thread(void *); static void fcoe_clean_pending_queue(struct fc_lport *); static void fcoe_percpu_clean(struct fc_lport *); +static int fcoe_link_speed_update(struct fc_lport *); static int fcoe_link_ok(struct fc_lport *); static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *); @@ -146,6 +147,7 @@ static int fcoe_vport_destroy(struct fc_vport *); static int fcoe_vport_create(struct fc_vport *, bool disabled); static int fcoe_vport_disable(struct fc_vport *, bool disable); static void fcoe_set_vport_symbolic_name(struct fc_vport *); +static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *); static struct libfc_function_template fcoe_libfc_fcn_templ = { .frame_send = fcoe_xmit, @@ -153,6 +155,7 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { .ddp_done = fcoe_ddp_done, .elsct_send = fcoe_elsct_send, .get_lesb = fcoe_get_lesb, + .lport_set_port_id = fcoe_set_port_id, }; struct fc_function_template fcoe_transport_function = { @@ -309,10 +312,10 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe, * for multiple unicast MACs. */ memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_add(netdev, flogi_maddr); + dev_uc_add(netdev, flogi_maddr); if (fip->spma) - dev_unicast_add(netdev, fip->ctl_src_addr); - dev_mc_add(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); + dev_uc_add(netdev, fip->ctl_src_addr); + dev_mc_add(netdev, FIP_ALL_ENODE_MACS); /* * setup the receive function from ethernet driver @@ -395,10 +398,10 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) /* Delete secondary MAC addresses */ memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_unicast_delete(netdev, flogi_maddr); + dev_uc_del(netdev, flogi_maddr); if (fip->spma) - dev_unicast_delete(netdev, fip->ctl_src_addr); - dev_mc_delete(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0); + dev_uc_del(netdev, fip->ctl_src_addr); + dev_mc_del(netdev, FIP_ALL_ENODE_MACS); /* Tell the LLD we are done w/ FCoE */ ops = netdev->netdev_ops; @@ -491,9 +494,9 @@ static void fcoe_update_src_mac(struct fc_lport *lport, u8 *addr) rtnl_lock(); if (!is_zero_ether_addr(port->data_src_addr)) - dev_unicast_delete(fcoe->netdev, port->data_src_addr); + dev_uc_del(fcoe->netdev, port->data_src_addr); if (!is_zero_ether_addr(addr)) - dev_unicast_add(fcoe->netdev, addr); + dev_uc_add(fcoe->netdev, addr); memcpy(port->data_src_addr, addr, ETH_ALEN); rtnl_unlock(); } @@ -629,6 +632,8 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) port->fcoe_pending_queue_active = 0; setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport); + fcoe_link_speed_update(lport); + if (!lport->vport) { /* * Use NAA 1&2 (FC-FS Rev. 2.0, Sec. 15) to generate WWNN/WWPN: @@ -653,15 +658,13 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) /** * fcoe_shost_config() - Set up the SCSI host associated with a local port * @lport: The local port - * @shost: The SCSI host to associate with the local port * @dev: The device associated with the SCSI host * * Must be called after fcoe_lport_config() and fcoe_netdev_config() * * Returns: 0 for success */ -static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost, - struct device *dev) +static int fcoe_shost_config(struct fc_lport *lport, struct device *dev) { int rc = 0; @@ -669,6 +672,8 @@ static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost, lport->host->max_lun = FCOE_MAX_LUN; lport->host->max_id = FCOE_MAX_FCP_TARGET; lport->host->max_channel = 0; + lport->host->max_cmd_len = FCOE_MAX_CMD_LEN; + if (lport->vport) lport->host->transportt = fcoe_vport_transport_template; else @@ -796,6 +801,12 @@ skip_oem: /** * fcoe_if_destroy() - Tear down a SW FCoE instance * @lport: The local port to be destroyed + * + * Locking: must be called with the RTNL mutex held and RTNL mutex + * needed to be dropped by this function since not dropping RTNL + * would cause circular locking warning on synchronous fip worker + * cancelling thru fcoe_interface_put invoked by this function. + * */ static void fcoe_if_destroy(struct fc_lport *lport) { @@ -818,9 +829,8 @@ static void fcoe_if_destroy(struct fc_lport *lport) /* Free existing transmit skbs */ fcoe_clean_pending_queue(lport); - rtnl_lock(); if (!is_zero_ether_addr(port->data_src_addr)) - dev_unicast_delete(netdev, port->data_src_addr); + dev_uc_del(netdev, port->data_src_addr); rtnl_unlock(); /* receives may not be stopped until after this */ @@ -841,6 +851,7 @@ static void fcoe_if_destroy(struct fc_lport *lport) /* Release the Scsi_Host */ scsi_host_put(lport->host); + module_put(THIS_MODULE); } /** @@ -897,7 +908,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, struct net_device *netdev = fcoe->netdev; struct fc_lport *lport = NULL; struct fcoe_port *port; - struct Scsi_Host *shost; int rc; /* * parent is only a vport if npiv is 1, @@ -919,7 +929,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, rc = -ENOMEM; goto out; } - shost = lport->host; port = lport_priv(lport); port->lport = lport; port->fcoe = fcoe; @@ -934,7 +943,8 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, } if (npiv) { - FCOE_NETDEV_DBG(netdev, "Setting vport names, 0x%llX 0x%llX\n", + FCOE_NETDEV_DBG(netdev, "Setting vport names, " + "%16.16llx %16.16llx\n", vport->node_name, vport->port_name); fc_set_wwnn(lport, vport->node_name); fc_set_wwpn(lport, vport->port_name); @@ -949,7 +959,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, } /* configure lport scsi host properties */ - rc = fcoe_shost_config(lport, shost, parent); + rc = fcoe_shost_config(lport, parent); if (rc) { FCOE_NETDEV_DBG(netdev, "Could not configure shost for the " "interface\n"); @@ -1073,7 +1083,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu) struct sk_buff *skb; #ifdef CONFIG_SMP struct fcoe_percpu_s *p0; - unsigned targ_cpu = smp_processor_id(); + unsigned targ_cpu = get_cpu(); #endif /* CONFIG_SMP */ FCOE_DBG("Destroying receive thread for CPU %d\n", cpu); @@ -1129,6 +1139,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu) kfree_skb(skb); spin_unlock_bh(&p->fcoe_rx_list.lock); } + put_cpu(); #else /* * This a non-SMP scenario where the singular Rx thread is @@ -1297,8 +1308,8 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, return 0; err: - fc_lport_get_stats(lport)->ErrorFrames++; - + per_cpu_ptr(lport->dev_stats, get_cpu())->ErrorFrames++; + put_cpu(); err2: kfree_skb(skb); return -1; @@ -1444,7 +1455,7 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) return 0; } - if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) && + if (unlikely(fh->fh_type == FC_TYPE_ELS) && fcoe_ctlr_els_send(&fcoe->ctlr, lport, skb)) return 0; @@ -1527,9 +1538,10 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) skb_shinfo(skb)->gso_size = 0; } /* update tx stats: regardless if LLD fails */ - stats = fc_lport_get_stats(lport); + stats = per_cpu_ptr(lport->dev_stats, get_cpu()); stats->TxFrames++; stats->TxWords += wlen; + put_cpu(); /* send down to lld */ fr_dev(fp) = lport; @@ -1563,7 +1575,6 @@ static void fcoe_recv_frame(struct sk_buff *skb) struct fc_frame_header *fh; struct fcoe_crc_eof crc_eof; struct fc_frame *fp; - u8 *mac = NULL; struct fcoe_port *port; struct fcoe_hdr *hp; @@ -1583,13 +1594,9 @@ static void fcoe_recv_frame(struct sk_buff *skb) skb_end_pointer(skb), skb->csum, skb->dev ? skb->dev->name : "<NULL>"); - /* - * Save source MAC address before discarding header. - */ port = lport_priv(lport); if (skb_is_nonlinear(skb)) skb_linearize(skb); /* not ideal */ - mac = eth_hdr(skb)->h_source; /* * Frame length checks and setting up the header pointers @@ -1598,7 +1605,7 @@ static void fcoe_recv_frame(struct sk_buff *skb) hp = (struct fcoe_hdr *) skb_network_header(skb); fh = (struct fc_frame_header *) skb_transport_header(skb); - stats = fc_lport_get_stats(lport); + stats = per_cpu_ptr(lport->dev_stats, get_cpu()); if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { if (stats->ErrorFrames < 5) printk(KERN_WARNING "fcoe: FCoE version " @@ -1607,9 +1614,7 @@ static void fcoe_recv_frame(struct sk_buff *skb) "initiator supports version " "%x\n", FC_FCOE_DECAPS_VER(hp), FC_FCOE_VER); - stats->ErrorFrames++; - kfree_skb(skb); - return; + goto drop; } skb_pull(skb, sizeof(struct fcoe_hdr)); @@ -1624,16 +1629,12 @@ static void fcoe_recv_frame(struct sk_buff *skb) fr_sof(fp) = hp->fcoe_sof; /* Copy out the CRC and EOF trailer for access */ - if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) { - kfree_skb(skb); - return; - } + if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) + goto drop; fr_eof(fp) = crc_eof.fcoe_eof; fr_crc(fp) = crc_eof.fcoe_crc32; - if (pskb_trim(skb, fr_len)) { - kfree_skb(skb); - return; - } + if (pskb_trim(skb, fr_len)) + goto drop; /* * We only check CRC if no offload is available and if it is @@ -1647,25 +1648,27 @@ static void fcoe_recv_frame(struct sk_buff *skb) fr_flags(fp) |= FCPHF_CRC_UNCHECKED; fh = fc_frame_header_get(fp); - if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && - fh->fh_type == FC_TYPE_FCP) { - fc_exch_recv(lport, fp); - return; - } - if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { + if ((fh->fh_r_ctl != FC_RCTL_DD_SOL_DATA || + fh->fh_type != FC_TYPE_FCP) && + (fr_flags(fp) & FCPHF_CRC_UNCHECKED)) { if (le32_to_cpu(fr_crc(fp)) != ~crc32(~0, skb->data, fr_len)) { if (stats->InvalidCRCCount < 5) printk(KERN_WARNING "fcoe: dropping " "frame with CRC error\n"); stats->InvalidCRCCount++; - stats->ErrorFrames++; - fc_frame_free(fp); - return; + goto drop; } fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; } + put_cpu(); fc_exch_recv(lport, fp); + return; + +drop: + stats->ErrorFrames++; + put_cpu(); + kfree_skb(skb); } /** @@ -1835,11 +1838,15 @@ static int fcoe_device_notification(struct notifier_block *notifier, FCOE_NETDEV_DBG(netdev, "Unknown event %ld " "from netdev netlink\n", event); } + + fcoe_link_speed_update(lport); + if (link_possible && !fcoe_link_ok(lport)) fcoe_ctlr_link_up(&fcoe->ctlr); else if (fcoe_ctlr_link_down(&fcoe->ctlr)) { - stats = fc_lport_get_stats(lport); + stats = per_cpu_ptr(lport->dev_stats, get_cpu()); stats->LinkFailureCount++; + put_cpu(); fcoe_clean_pending_queue(lport); } out: @@ -1901,13 +1908,19 @@ static int fcoe_disable(const char *buffer, struct kernel_param *kp) goto out_nodev; } - rtnl_lock(); + if (!rtnl_trylock()) { + dev_put(netdev); + mutex_unlock(&fcoe_config_mutex); + return restart_syscall(); + } + fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock(); - if (fcoe) + if (fcoe) { fc_fabric_logoff(fcoe->ctlr.lp); - else + fcoe_ctlr_link_down(&fcoe->ctlr); + } else rc = -ENODEV; dev_put(netdev); @@ -1950,13 +1963,20 @@ static int fcoe_enable(const char *buffer, struct kernel_param *kp) goto out_nodev; } - rtnl_lock(); + if (!rtnl_trylock()) { + dev_put(netdev); + mutex_unlock(&fcoe_config_mutex); + return restart_syscall(); + } + fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock(); - if (fcoe) + if (fcoe) { + if (!fcoe_link_ok(fcoe->ctlr.lp)) + fcoe_ctlr_link_up(&fcoe->ctlr); rc = fc_fabric_login(fcoe->ctlr.lp); - else + } else rc = -ENODEV; dev_put(netdev); @@ -1999,7 +2019,12 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) goto out_nodev; } - rtnl_lock(); + if (!rtnl_trylock()) { + dev_put(netdev); + mutex_unlock(&fcoe_config_mutex); + return restart_syscall(); + } + fcoe = fcoe_hostlist_lookup_port(netdev); if (!fcoe) { rtnl_unlock(); @@ -2008,9 +2033,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) } list_del(&fcoe->list); fcoe_interface_cleanup(fcoe); - rtnl_unlock(); + /* RTNL mutex is dropped by fcoe_if_destroy */ fcoe_if_destroy(fcoe->ctlr.lp); - module_put(THIS_MODULE); out_putdev: dev_put(netdev); @@ -2029,6 +2053,8 @@ static void fcoe_destroy_work(struct work_struct *work) port = container_of(work, struct fcoe_port, destroy_work); mutex_lock(&fcoe_config_mutex); + rtnl_lock(); + /* RTNL mutex is dropped by fcoe_if_destroy */ fcoe_if_destroy(port->lport); mutex_unlock(&fcoe_config_mutex); } @@ -2050,6 +2076,12 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) struct net_device *netdev; mutex_lock(&fcoe_config_mutex); + + if (!rtnl_trylock()) { + mutex_unlock(&fcoe_config_mutex); + return restart_syscall(); + } + #ifdef CONFIG_FCOE_MODULE /* * Make sure the module has been initialized, and is not about to be @@ -2058,7 +2090,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) */ if (THIS_MODULE->state != MODULE_STATE_LIVE) { rc = -ENODEV; - goto out_nodev; + goto out_nomod; } #endif @@ -2067,7 +2099,6 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) goto out_nomod; } - rtnl_lock(); netdev = fcoe_if_to_netdev(buffer); if (!netdev) { rc = -ENODEV; @@ -2122,35 +2153,27 @@ out_free: out_putdev: dev_put(netdev); out_nodev: - rtnl_unlock(); module_put(THIS_MODULE); out_nomod: + rtnl_unlock(); mutex_unlock(&fcoe_config_mutex); return rc; } /** - * fcoe_link_ok() - Check if the link is OK for a local port - * @lport: The local port to check link on - * - * Any permanently-disqualifying conditions have been previously checked. - * This also updates the speed setting, which may change with link for 100/1000. - * - * This function should probably be checking for PAUSE support at some point - * in the future. Currently Per-priority-pause is not determinable using - * ethtool, so we shouldn't be restrictive until that problem is resolved. - * - * Returns: 0 if link is OK for use by FCoE. + * fcoe_link_speed_update() - Update the supported and actual link speeds + * @lport: The local port to update speeds for * + * Returns: 0 if the ethtool query was successful + * -1 if the ethtool query failed */ -int fcoe_link_ok(struct fc_lport *lport) +int fcoe_link_speed_update(struct fc_lport *lport) { struct fcoe_port *port = lport_priv(lport); struct net_device *netdev = port->fcoe->netdev; struct ethtool_cmd ecmd = { ETHTOOL_GSET }; - if ((netdev->flags & IFF_UP) && netif_carrier_ok(netdev) && - (!dev_ethtool_get_settings(netdev, &ecmd))) { + if (!dev_ethtool_get_settings(netdev, &ecmd)) { lport->link_supported_speeds &= ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); if (ecmd.supported & (SUPPORTED_1000baseT_Half | @@ -2170,6 +2193,23 @@ int fcoe_link_ok(struct fc_lport *lport) } /** + * fcoe_link_ok() - Check if the link is OK for a local port + * @lport: The local port to check link on + * + * Returns: 0 if link is UP and OK, -1 if not + * + */ +int fcoe_link_ok(struct fc_lport *lport) +{ + struct fcoe_port *port = lport_priv(lport); + struct net_device *netdev = port->fcoe->netdev; + + if (netif_oper_up(netdev)) + return 0; + return -1; +} + +/** * fcoe_percpu_clean() - Clear all pending skbs for an local port * @lport: The local port whose skbs are to be cleared * @@ -2631,3 +2671,25 @@ static void fcoe_get_lesb(struct fc_lport *lport, lesb->lesb_miss_fka = htonl(mdac); lesb->lesb_fcs_error = htonl(dev_get_stats(netdev)->rx_crc_errors); } + +/** + * fcoe_set_port_id() - Callback from libfc when Port_ID is set. + * @lport: the local port + * @port_id: the port ID + * @fp: the received frame, if any, that caused the port_id to be set. + * + * This routine handles the case where we received a FLOGI and are + * entering point-to-point mode. We need to call fcoe_ctlr_recv_flogi() + * so it can set the non-mapped mode and gateway address. + * + * The FLOGI LS_ACC is handled by fcoe_flogi_resp(). + */ +static void fcoe_set_port_id(struct fc_lport *lport, + u32 port_id, struct fc_frame *fp) +{ + struct fcoe_port *port = lport_priv(lport); + struct fcoe_interface *fcoe = port->fcoe; + + if (fp && fc_frame_payload_op(fp) == ELS_FLOGI) + fcoe_ctlr_recv_flogi(&fcoe->ctlr, lport, fp); +} diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 3440da48d169..50aaa4bcfc50 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -51,7 +51,7 @@ MODULE_LICENSE("GPL v2"); #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_timer_work(struct work_struct *); static void fcoe_ctlr_recv_work(struct work_struct *); static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS; @@ -116,7 +116,7 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip) 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->timer_work, fcoe_ctlr_timer_work); INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work); skb_queue_head_init(&fip->fip_recv_list); } @@ -164,7 +164,7 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip) fcoe_ctlr_reset_fcfs(fip); spin_unlock_bh(&fip->lock); del_timer_sync(&fip->timer); - cancel_work_sync(&fip->link_work); + cancel_work_sync(&fip->timer_work); } EXPORT_SYMBOL(fcoe_ctlr_destroy); @@ -257,14 +257,10 @@ 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"); @@ -306,9 +302,7 @@ int fcoe_ctlr_link_down(struct fcoe_ctlr *fip) 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; + link_dropped = fip->state != FIP_ST_LINK_WAIT; fip->state = FIP_ST_LINK_WAIT; spin_unlock_bh(&fip->lock); @@ -349,7 +343,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, fcf = fip->sel_fcf; lp = fip->lp; - if (!fcf || !fc_host_port_id(lp->host)) + if (!fcf || !lp->port_id) return; len = sizeof(*kal) + ports * sizeof(*vn); @@ -380,8 +374,8 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, 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); + hton24(vn->fd_fc_id, lport->port_id); + put_unaligned_be64(lport->wwpn, &vn->fd_wwpn); } skb_put(skb, len); skb->protocol = htons(ETH_P_FIP); @@ -445,13 +439,18 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW; mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac)); - memset(mac, 0, 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) + if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) { memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN); - else if (fip->spma) + } else if (fip_flags & FIP_FL_SPMA) { + LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n"); memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN); + } else { + LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n"); + /* FPMA only FLOGI must leave the MAC desc set to all 0s */ + } skb->protocol = htons(ETH_P_FIP); skb_reset_mac_header(skb); @@ -556,7 +555,7 @@ 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. + * Called with lock held and preemption disabled. * * An FCF is considered old if we have missed three advertisements. * That is, there have been no valid advertisement from it for three @@ -573,17 +572,20 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) struct fcoe_fcf *next; unsigned long sel_time = 0; unsigned long mda_time = 0; + struct fcoe_dev_stats *stats; 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++; + stats = per_cpu_ptr(fip->lp->dev_stats, + smp_processor_id()); + stats->MissDiscAdvCount++; printk(KERN_INFO "libfcoe: host%d: Missing Discovery " - "Advertisement for fab %llx count %lld\n", + "Advertisement for fab %16.16llx count %lld\n", fip->lp->host->host_no, fcf->fabric_name, - fc_lport_get_stats(fip->lp)->MissDiscAdvCount); + stats->MissDiscAdvCount); } if (time_after(jiffies, fcf->time + fcf->fka_period * 3 + msecs_to_jiffies(FIP_FCF_FUZZ * 3))) { @@ -593,7 +595,9 @@ 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++; + stats = per_cpu_ptr(fip->lp->dev_stats, + smp_processor_id()); + stats->VLinkFailureCount++; } else if (fcoe_ctlr_mtu_valid(fcf) && (!sel_time || time_before(sel_time, fcf->time))) { sel_time = fcf->time; @@ -776,7 +780,8 @@ 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(fip, "New FCF for fab %llx map %x val %d\n", + LIBFCOE_FIP_DBG(fip, "New FCF for fab %16.16llx " + "map %x val %d\n", fcf->fabric_name, fcf->fc_map, mtu_valid); } @@ -906,9 +911,10 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) fr_eof(fp) = FC_EOF_T; fr_dev(fp) = lport; - stats = fc_lport_get_stats(lport); + stats = per_cpu_ptr(lport->dev_stats, get_cpu()); stats->RxFrames++; stats->RxWords += skb->len / FIP_BPW; + put_cpu(); fc_exch_recv(lport, fp); return; @@ -942,9 +948,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, u32 desc_mask; LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n"); - if (!fcf) - return; - if (!fcf || !fc_host_port_id(lport->host)) + + if (!fcf || !lport->port_id) return; /* @@ -982,8 +987,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, 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)) + ntoh24(vp->fd_fc_id) == lport->port_id) desc_mask &= ~BIT(FIP_DT_VN_ID); break; default: @@ -1006,7 +1010,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n"); spin_lock_bh(&fip->lock); - fc_lport_get_stats(lport)->VLinkFailureCount++; + per_cpu_ptr(lport->dev_stats, + smp_processor_id())->VLinkFailureCount++; fcoe_ctlr_reset(fip); spin_unlock_bh(&fip->lock); @@ -1102,15 +1107,17 @@ 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(fip, "consider FCF for fab %llx VFID %d map %x " - "val %d\n", fcf->fabric_name, fcf->vfid, + LIBFCOE_FIP_DBG(fip, "consider FCF for fab %16.16llx " + "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"); + LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx " + "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) { @@ -1175,7 +1182,7 @@ static void fcoe_ctlr_timeout(unsigned long arg) "Starting FCF discovery.\n", fip->lp->host->host_no); fip->reset_req = 1; - schedule_work(&fip->link_work); + schedule_work(&fip->timer_work); } } @@ -1201,43 +1208,31 @@ static void fcoe_ctlr_timeout(unsigned long arg) mod_timer(&fip->timer, next_timer); } if (fip->send_ctlr_ka || fip->send_port_ka) - schedule_work(&fip->link_work); + schedule_work(&fip->timer_work); spin_unlock_bh(&fip->lock); } /** - * fcoe_ctlr_link_work() - Worker thread function for link changes + * fcoe_ctlr_timer_work() - Worker thread function for timer work * @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 + * Sends keep-alives and resets which must not * be called from the timer directly, since they use a mutex. */ -static void fcoe_ctlr_link_work(struct work_struct *work) +static void fcoe_ctlr_timer_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); + fip = container_of(work, struct fcoe_ctlr, timer_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) + if (reset) fc_lport_reset(fip->lp); if (fip->send_ctlr_ka) { @@ -1334,9 +1329,9 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport, 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"); + if (fip->state == FIP_ST_AUTO) + LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. " + "Setting non-FIP mode\n"); fip->state = FIP_ST_NON_FIP; } spin_unlock_bh(&fip->lock); |