xref: /openbmc/linux/drivers/scsi/fcoe/fcoe.c (revision af7f85d9)
1a703e490SVasu Dev /*
2af7f85d9SChris Leech  * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
3a703e490SVasu Dev  *
4a703e490SVasu Dev  * This program is free software; you can redistribute it and/or modify it
5a703e490SVasu Dev  * under the terms and conditions of the GNU General Public License,
6a703e490SVasu Dev  * version 2, as published by the Free Software Foundation.
7a703e490SVasu Dev  *
8a703e490SVasu Dev  * This program is distributed in the hope it will be useful, but WITHOUT
9a703e490SVasu Dev  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10a703e490SVasu Dev  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11a703e490SVasu Dev  * more details.
12a703e490SVasu Dev  *
13a703e490SVasu Dev  * You should have received a copy of the GNU General Public License along with
14a703e490SVasu Dev  * this program; if not, write to the Free Software Foundation, Inc.,
15a703e490SVasu Dev  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16a703e490SVasu Dev  *
17a703e490SVasu Dev  * Maintained at www.Open-FCoE.org
18a703e490SVasu Dev  */
19a703e490SVasu Dev 
20a703e490SVasu Dev #include <linux/module.h>
21a703e490SVasu Dev #include <linux/version.h>
22a703e490SVasu Dev #include <linux/spinlock.h>
23a703e490SVasu Dev #include <linux/netdevice.h>
24a703e490SVasu Dev #include <linux/etherdevice.h>
25a703e490SVasu Dev #include <linux/ethtool.h>
26a703e490SVasu Dev #include <linux/if_ether.h>
27a703e490SVasu Dev #include <linux/if_vlan.h>
28a703e490SVasu Dev #include <linux/crc32.h>
29a703e490SVasu Dev #include <linux/cpu.h>
30a703e490SVasu Dev #include <linux/fs.h>
31a703e490SVasu Dev #include <linux/sysfs.h>
32a703e490SVasu Dev #include <linux/ctype.h>
33a703e490SVasu Dev #include <scsi/scsi_tcq.h>
34a703e490SVasu Dev #include <scsi/scsicam.h>
35a703e490SVasu Dev #include <scsi/scsi_transport.h>
36a703e490SVasu Dev #include <scsi/scsi_transport_fc.h>
37a703e490SVasu Dev #include <net/rtnetlink.h>
38a703e490SVasu Dev 
39a703e490SVasu Dev #include <scsi/fc/fc_encaps.h>
4097c8389dSJoe Eykholt #include <scsi/fc/fc_fip.h>
41a703e490SVasu Dev 
42a703e490SVasu Dev #include <scsi/libfc.h>
43a703e490SVasu Dev #include <scsi/fc_frame.h>
44a703e490SVasu Dev #include <scsi/libfcoe.h>
45a703e490SVasu Dev 
46fdd78027SVasu Dev #include "fcoe.h"
47fdd78027SVasu Dev 
48a703e490SVasu Dev MODULE_AUTHOR("Open-FCoE.org");
49a703e490SVasu Dev MODULE_DESCRIPTION("FCoE");
509b34ecffSVasu Dev MODULE_LICENSE("GPL v2");
51a703e490SVasu Dev 
5205cc7390SYi Zou /* Performance tuning parameters for fcoe */
5305cc7390SYi Zou static unsigned int fcoe_ddp_min;
5405cc7390SYi Zou module_param_named(ddp_min, fcoe_ddp_min, uint, S_IRUGO | S_IWUSR);
5505cc7390SYi Zou MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for "	\
5605cc7390SYi Zou 		 "Direct Data Placement (DDP).");
5705cc7390SYi Zou 
58a703e490SVasu Dev /* fcoe host list */
59a703e490SVasu Dev LIST_HEAD(fcoe_hostlist);
60a703e490SVasu Dev DEFINE_RWLOCK(fcoe_hostlist_lock);
61a703e490SVasu Dev DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu);
62a703e490SVasu Dev 
63dd3fd72eSChris Leech /* Function Prototypes */
64fdd78027SVasu Dev static int fcoe_reset(struct Scsi_Host *shost);
65fdd78027SVasu Dev static int fcoe_xmit(struct fc_lport *, struct fc_frame *);
66fdd78027SVasu Dev static int fcoe_rcv(struct sk_buff *, struct net_device *,
67fdd78027SVasu Dev 		    struct packet_type *, struct net_device *);
68fdd78027SVasu Dev static int fcoe_percpu_receive_thread(void *arg);
69fdd78027SVasu Dev static void fcoe_clean_pending_queue(struct fc_lport *lp);
70fdd78027SVasu Dev static void fcoe_percpu_clean(struct fc_lport *lp);
71fdd78027SVasu Dev static int fcoe_link_ok(struct fc_lport *lp);
72fdd78027SVasu Dev 
73fdd78027SVasu Dev static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *);
74fdd78027SVasu Dev static int fcoe_hostlist_add(const struct fc_lport *);
75fdd78027SVasu Dev static int fcoe_hostlist_remove(const struct fc_lport *);
76fdd78027SVasu Dev 
774bb6b515SVasu Dev static void fcoe_check_wait_queue(struct fc_lport *, struct sk_buff *);
78a703e490SVasu Dev static int fcoe_device_notification(struct notifier_block *, ulong, void *);
79a703e490SVasu Dev static void fcoe_dev_setup(void);
80a703e490SVasu Dev static void fcoe_dev_cleanup(void);
81a703e490SVasu Dev 
82a703e490SVasu Dev /* notification function from net device */
83a703e490SVasu Dev static struct notifier_block fcoe_notifier = {
84a703e490SVasu Dev 	.notifier_call = fcoe_device_notification,
85a703e490SVasu Dev };
86a703e490SVasu Dev 
87a703e490SVasu Dev static struct scsi_transport_template *scsi_transport_fcoe_sw;
88a703e490SVasu Dev 
89a703e490SVasu Dev struct fc_function_template fcoe_transport_function = {
90a703e490SVasu Dev 	.show_host_node_name = 1,
91a703e490SVasu Dev 	.show_host_port_name = 1,
92a703e490SVasu Dev 	.show_host_supported_classes = 1,
93a703e490SVasu Dev 	.show_host_supported_fc4s = 1,
94a703e490SVasu Dev 	.show_host_active_fc4s = 1,
95a703e490SVasu Dev 	.show_host_maxframe_size = 1,
96a703e490SVasu Dev 
97a703e490SVasu Dev 	.show_host_port_id = 1,
98a703e490SVasu Dev 	.show_host_supported_speeds = 1,
99a703e490SVasu Dev 	.get_host_speed = fc_get_host_speed,
100a703e490SVasu Dev 	.show_host_speed = 1,
101a703e490SVasu Dev 	.show_host_port_type = 1,
102a703e490SVasu Dev 	.get_host_port_state = fc_get_host_port_state,
103a703e490SVasu Dev 	.show_host_port_state = 1,
104a703e490SVasu Dev 	.show_host_symbolic_name = 1,
105a703e490SVasu Dev 
106a703e490SVasu Dev 	.dd_fcrport_size = sizeof(struct fc_rport_libfc_priv),
107a703e490SVasu Dev 	.show_rport_maxframe_size = 1,
108a703e490SVasu Dev 	.show_rport_supported_classes = 1,
109a703e490SVasu Dev 
110a703e490SVasu Dev 	.show_host_fabric_name = 1,
111a703e490SVasu Dev 	.show_starget_node_name = 1,
112a703e490SVasu Dev 	.show_starget_port_name = 1,
113a703e490SVasu Dev 	.show_starget_port_id = 1,
114a703e490SVasu Dev 	.set_rport_dev_loss_tmo = fc_set_rport_loss_tmo,
115a703e490SVasu Dev 	.show_rport_dev_loss_tmo = 1,
116a703e490SVasu Dev 	.get_fc_host_stats = fc_get_host_stats,
117a703e490SVasu Dev 	.issue_fc_host_lip = fcoe_reset,
118a703e490SVasu Dev 
119a703e490SVasu Dev 	.terminate_rport_io = fc_rport_terminate_io,
120a703e490SVasu Dev };
121a703e490SVasu Dev 
122a703e490SVasu Dev static struct scsi_host_template fcoe_shost_template = {
123a703e490SVasu Dev 	.module = THIS_MODULE,
124a703e490SVasu Dev 	.name = "FCoE Driver",
125a703e490SVasu Dev 	.proc_name = FCOE_NAME,
126a703e490SVasu Dev 	.queuecommand = fc_queuecommand,
127a703e490SVasu Dev 	.eh_abort_handler = fc_eh_abort,
128a703e490SVasu Dev 	.eh_device_reset_handler = fc_eh_device_reset,
129a703e490SVasu Dev 	.eh_host_reset_handler = fc_eh_host_reset,
130a703e490SVasu Dev 	.slave_alloc = fc_slave_alloc,
131a703e490SVasu Dev 	.change_queue_depth = fc_change_queue_depth,
132a703e490SVasu Dev 	.change_queue_type = fc_change_queue_type,
133a703e490SVasu Dev 	.this_id = -1,
134a703e490SVasu Dev 	.cmd_per_lun = 32,
135a703e490SVasu Dev 	.can_queue = FCOE_MAX_OUTSTANDING_COMMANDS,
136a703e490SVasu Dev 	.use_clustering = ENABLE_CLUSTERING,
137a703e490SVasu Dev 	.sg_tablesize = SG_ALL,
138a703e490SVasu Dev 	.max_sectors = 0xffff,
139a703e490SVasu Dev };
140a703e490SVasu Dev 
141a703e490SVasu Dev /**
142ab6b85c1SVasu Dev  * fcoe_fip_recv - handle a received FIP frame.
143ab6b85c1SVasu Dev  * @skb: the receive skb
144ab6b85c1SVasu Dev  * @dev: associated &net_device
145ab6b85c1SVasu Dev  * @ptype: the &packet_type structure which was used to register this handler.
146ab6b85c1SVasu Dev  * @orig_dev: original receive &net_device, in case @dev is a bond.
147ab6b85c1SVasu Dev  *
148ab6b85c1SVasu Dev  * Returns: 0 for success
149ab6b85c1SVasu Dev  */
150ab6b85c1SVasu Dev static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,
151ab6b85c1SVasu Dev 			 struct packet_type *ptype,
152ab6b85c1SVasu Dev 			 struct net_device *orig_dev)
153ab6b85c1SVasu Dev {
154ab6b85c1SVasu Dev 	struct fcoe_softc *fc;
155ab6b85c1SVasu Dev 
156ab6b85c1SVasu Dev 	fc = container_of(ptype, struct fcoe_softc, fip_packet_type);
157ab6b85c1SVasu Dev 	fcoe_ctlr_recv(&fc->ctlr, skb);
158ab6b85c1SVasu Dev 	return 0;
159ab6b85c1SVasu Dev }
160ab6b85c1SVasu Dev 
161ab6b85c1SVasu Dev /**
162ab6b85c1SVasu Dev  * fcoe_fip_send() - send an Ethernet-encapsulated FIP frame.
163ab6b85c1SVasu Dev  * @fip: FCoE controller.
164ab6b85c1SVasu Dev  * @skb: FIP Packet.
165ab6b85c1SVasu Dev  */
166ab6b85c1SVasu Dev static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
167ab6b85c1SVasu Dev {
1681d1b88dcSVasu Dev 	skb->dev = fcoe_from_ctlr(fip)->netdev;
169ab6b85c1SVasu Dev 	dev_queue_xmit(skb);
170ab6b85c1SVasu Dev }
171ab6b85c1SVasu Dev 
172ab6b85c1SVasu Dev /**
173ab6b85c1SVasu Dev  * fcoe_update_src_mac() - Update Ethernet MAC filters.
174ab6b85c1SVasu Dev  * @fip: FCoE controller.
175ab6b85c1SVasu Dev  * @old: Unicast MAC address to delete if the MAC is non-zero.
176ab6b85c1SVasu Dev  * @new: Unicast MAC address to add.
177ab6b85c1SVasu Dev  *
178ab6b85c1SVasu Dev  * Remove any previously-set unicast MAC filter.
179ab6b85c1SVasu Dev  * Add secondary FCoE MAC address filter for our OUI.
180ab6b85c1SVasu Dev  */
181ab6b85c1SVasu Dev static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new)
182ab6b85c1SVasu Dev {
183ab6b85c1SVasu Dev 	struct fcoe_softc *fc;
184ab6b85c1SVasu Dev 
185ab6b85c1SVasu Dev 	fc = fcoe_from_ctlr(fip);
186ab6b85c1SVasu Dev 	rtnl_lock();
187ab6b85c1SVasu Dev 	if (!is_zero_ether_addr(old))
1881d1b88dcSVasu Dev 		dev_unicast_delete(fc->netdev, old);
1891d1b88dcSVasu Dev 	dev_unicast_add(fc->netdev, new);
190ab6b85c1SVasu Dev 	rtnl_unlock();
191ab6b85c1SVasu Dev }
192ab6b85c1SVasu Dev 
193ab6b85c1SVasu Dev /**
194a703e490SVasu Dev  * fcoe_lport_config() - sets up the fc_lport
195a703e490SVasu Dev  * @lp: ptr to the fc_lport
196a703e490SVasu Dev  *
197a703e490SVasu Dev  * Returns: 0 for success
198a703e490SVasu Dev  */
199a703e490SVasu Dev static int fcoe_lport_config(struct fc_lport *lp)
200a703e490SVasu Dev {
201a703e490SVasu Dev 	lp->link_up = 0;
202a703e490SVasu Dev 	lp->qfull = 0;
203a703e490SVasu Dev 	lp->max_retry_count = 3;
204a3666955SAbhijeet Joglekar 	lp->max_rport_retry_count = 3;
205a703e490SVasu Dev 	lp->e_d_tov = 2 * 1000;	/* FC-FS default */
206a703e490SVasu Dev 	lp->r_a_tov = 2 * 2 * 1000;
207a703e490SVasu Dev 	lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
208a703e490SVasu Dev 			      FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL);
209a703e490SVasu Dev 
210a703e490SVasu Dev 	fc_lport_init_stats(lp);
211a703e490SVasu Dev 
212a703e490SVasu Dev 	/* lport fc_lport related configuration */
213a703e490SVasu Dev 	fc_lport_config(lp);
214a703e490SVasu Dev 
215a703e490SVasu Dev 	/* offload related configuration */
216a703e490SVasu Dev 	lp->crc_offload = 0;
217a703e490SVasu Dev 	lp->seq_offload = 0;
218a703e490SVasu Dev 	lp->lro_enabled = 0;
219a703e490SVasu Dev 	lp->lro_xid = 0;
220a703e490SVasu Dev 	lp->lso_max = 0;
221a703e490SVasu Dev 
222a703e490SVasu Dev 	return 0;
223a703e490SVasu Dev }
224a703e490SVasu Dev 
225a703e490SVasu Dev /**
226ab6b85c1SVasu Dev  * fcoe_netdev_cleanup() - clean up netdev configurations
227ab6b85c1SVasu Dev  * @fc: ptr to the fcoe_softc
228ab6b85c1SVasu Dev  */
229ab6b85c1SVasu Dev void fcoe_netdev_cleanup(struct fcoe_softc *fc)
230ab6b85c1SVasu Dev {
231ab6b85c1SVasu Dev 	u8 flogi_maddr[ETH_ALEN];
232ab6b85c1SVasu Dev 
233ab6b85c1SVasu Dev 	/* Don't listen for Ethernet packets anymore */
234ab6b85c1SVasu Dev 	dev_remove_pack(&fc->fcoe_packet_type);
235ab6b85c1SVasu Dev 	dev_remove_pack(&fc->fip_packet_type);
236ab6b85c1SVasu Dev 
237ab6b85c1SVasu Dev 	/* Delete secondary MAC addresses */
238ab6b85c1SVasu Dev 	rtnl_lock();
239ab6b85c1SVasu Dev 	memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
2401d1b88dcSVasu Dev 	dev_unicast_delete(fc->netdev, flogi_maddr);
241ab6b85c1SVasu Dev 	if (!is_zero_ether_addr(fc->ctlr.data_src_addr))
2421d1b88dcSVasu Dev 		dev_unicast_delete(fc->netdev, fc->ctlr.data_src_addr);
243184dd345SVasu Dev 	if (fc->ctlr.spma)
2441d1b88dcSVasu Dev 		dev_unicast_delete(fc->netdev, fc->ctlr.ctl_src_addr);
2451d1b88dcSVasu Dev 	dev_mc_delete(fc->netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
246ab6b85c1SVasu Dev 	rtnl_unlock();
247ab6b85c1SVasu Dev }
248ab6b85c1SVasu Dev 
249ab6b85c1SVasu Dev /**
2501047f221SVasu Dev  * fcoe_queue_timer() - fcoe queue timer
2511047f221SVasu Dev  * @lp: the fc_lport pointer
2521047f221SVasu Dev  *
2531047f221SVasu Dev  * Calls fcoe_check_wait_queue on timeout
2541047f221SVasu Dev  *
2551047f221SVasu Dev  */
2561047f221SVasu Dev static void fcoe_queue_timer(ulong lp)
2571047f221SVasu Dev {
2581047f221SVasu Dev 	fcoe_check_wait_queue((struct fc_lport *)lp, NULL);
2591047f221SVasu Dev }
2601047f221SVasu Dev 
2611047f221SVasu Dev /**
262a703e490SVasu Dev  * fcoe_netdev_config() - Set up netdev for SW FCoE
263a703e490SVasu Dev  * @lp : ptr to the fc_lport
264a703e490SVasu Dev  * @netdev : ptr to the associated netdevice struct
265a703e490SVasu Dev  *
266a703e490SVasu Dev  * Must be called after fcoe_lport_config() as it will use lport mutex
267a703e490SVasu Dev  *
268a703e490SVasu Dev  * Returns : 0 for success
269a703e490SVasu Dev  */
270a703e490SVasu Dev static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
271a703e490SVasu Dev {
272a703e490SVasu Dev 	u32 mfs;
273a703e490SVasu Dev 	u64 wwnn, wwpn;
274a703e490SVasu Dev 	struct fcoe_softc *fc;
275a703e490SVasu Dev 	u8 flogi_maddr[ETH_ALEN];
276184dd345SVasu Dev 	struct netdev_hw_addr *ha;
277a703e490SVasu Dev 
278a703e490SVasu Dev 	/* Setup lport private data to point to fcoe softc */
279a703e490SVasu Dev 	fc = lport_priv(lp);
28097c8389dSJoe Eykholt 	fc->ctlr.lp = lp;
2811d1b88dcSVasu Dev 	fc->netdev = netdev;
282a703e490SVasu Dev 
283a703e490SVasu Dev 	/* Do not support for bonding device */
2841d1b88dcSVasu Dev 	if ((netdev->priv_flags & IFF_MASTER_ALB) ||
2851d1b88dcSVasu Dev 	    (netdev->priv_flags & IFF_SLAVE_INACTIVE) ||
2861d1b88dcSVasu Dev 	    (netdev->priv_flags & IFF_MASTER_8023AD)) {
287a703e490SVasu Dev 		return -EOPNOTSUPP;
288a703e490SVasu Dev 	}
289a703e490SVasu Dev 
290a703e490SVasu Dev 	/*
291a703e490SVasu Dev 	 * Determine max frame size based on underlying device and optional
292a703e490SVasu Dev 	 * user-configured limit.  If the MFS is too low, fcoe_link_ok()
293a703e490SVasu Dev 	 * will return 0, so do this first.
294a703e490SVasu Dev 	 */
2951d1b88dcSVasu Dev 	mfs = netdev->mtu - (sizeof(struct fcoe_hdr) +
296a703e490SVasu Dev 			     sizeof(struct fcoe_crc_eof));
297a703e490SVasu Dev 	if (fc_set_mfs(lp, mfs))
298a703e490SVasu Dev 		return -EINVAL;
299a703e490SVasu Dev 
300a703e490SVasu Dev 	/* offload features support */
3011d1b88dcSVasu Dev 	if (netdev->features & NETIF_F_SG)
302a703e490SVasu Dev 		lp->sg_supp = 1;
303a703e490SVasu Dev 
304a703e490SVasu Dev 	if (netdev->features & NETIF_F_FCOE_CRC) {
305a703e490SVasu Dev 		lp->crc_offload = 1;
306d5488eb9SRobert Love 		FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n");
307a703e490SVasu Dev 	}
308a703e490SVasu Dev 	if (netdev->features & NETIF_F_FSO) {
309a703e490SVasu Dev 		lp->seq_offload = 1;
310a703e490SVasu Dev 		lp->lso_max = netdev->gso_max_size;
311d5488eb9SRobert Love 		FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n",
312d5488eb9SRobert Love 				lp->lso_max);
313a703e490SVasu Dev 	}
314a703e490SVasu Dev 	if (netdev->fcoe_ddp_xid) {
315a703e490SVasu Dev 		lp->lro_enabled = 1;
316a703e490SVasu Dev 		lp->lro_xid = netdev->fcoe_ddp_xid;
317d5488eb9SRobert Love 		FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n",
318d5488eb9SRobert Love 				lp->lro_xid);
319a703e490SVasu Dev 	}
320a703e490SVasu Dev 	skb_queue_head_init(&fc->fcoe_pending_queue);
321a703e490SVasu Dev 	fc->fcoe_pending_queue_active = 0;
3221047f221SVasu Dev 	setup_timer(&fc->timer, fcoe_queue_timer, (unsigned long)lp);
323a703e490SVasu Dev 
324184dd345SVasu Dev 	/* look for SAN MAC address, if multiple SAN MACs exist, only
325184dd345SVasu Dev 	 * use the first one for SPMA */
326184dd345SVasu Dev 	rcu_read_lock();
327184dd345SVasu Dev 	for_each_dev_addr(netdev, ha) {
328184dd345SVasu Dev 		if ((ha->type == NETDEV_HW_ADDR_T_SAN) &&
3297a7f0c7fSYi Zou 		    (is_valid_ether_addr(ha->addr))) {
330184dd345SVasu Dev 			memcpy(fc->ctlr.ctl_src_addr, ha->addr, ETH_ALEN);
331184dd345SVasu Dev 			fc->ctlr.spma = 1;
332184dd345SVasu Dev 			break;
333184dd345SVasu Dev 		}
334184dd345SVasu Dev 	}
335184dd345SVasu Dev 	rcu_read_unlock();
336184dd345SVasu Dev 
337a703e490SVasu Dev 	/* setup Source Mac Address */
338184dd345SVasu Dev 	if (!fc->ctlr.spma)
3391d1b88dcSVasu Dev 		memcpy(fc->ctlr.ctl_src_addr, netdev->dev_addr,
3401d1b88dcSVasu Dev 		       fc->netdev->addr_len);
341a703e490SVasu Dev 
3421d1b88dcSVasu Dev 	wwnn = fcoe_wwn_from_mac(netdev->dev_addr, 1, 0);
343a703e490SVasu Dev 	fc_set_wwnn(lp, wwnn);
344a703e490SVasu Dev 	/* XXX - 3rd arg needs to be vlan id */
3451d1b88dcSVasu Dev 	wwpn = fcoe_wwn_from_mac(netdev->dev_addr, 2, 0);
346a703e490SVasu Dev 	fc_set_wwpn(lp, wwpn);
347a703e490SVasu Dev 
348a703e490SVasu Dev 	/*
349a703e490SVasu Dev 	 * Add FCoE MAC address as second unicast MAC address
350a703e490SVasu Dev 	 * or enter promiscuous mode if not capable of listening
351a703e490SVasu Dev 	 * for multiple unicast MACs.
352a703e490SVasu Dev 	 */
353a703e490SVasu Dev 	rtnl_lock();
354a703e490SVasu Dev 	memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
3551d1b88dcSVasu Dev 	dev_unicast_add(netdev, flogi_maddr);
356184dd345SVasu Dev 	if (fc->ctlr.spma)
3571d1b88dcSVasu Dev 		dev_unicast_add(netdev, fc->ctlr.ctl_src_addr);
3581d1b88dcSVasu Dev 	dev_mc_add(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
359a703e490SVasu Dev 	rtnl_unlock();
360a703e490SVasu Dev 
361a703e490SVasu Dev 	/*
362a703e490SVasu Dev 	 * setup the receive function from ethernet driver
363a703e490SVasu Dev 	 * on the ethertype for the given device
364a703e490SVasu Dev 	 */
365a703e490SVasu Dev 	fc->fcoe_packet_type.func = fcoe_rcv;
366a703e490SVasu Dev 	fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE);
3671d1b88dcSVasu Dev 	fc->fcoe_packet_type.dev = netdev;
368a703e490SVasu Dev 	dev_add_pack(&fc->fcoe_packet_type);
369a703e490SVasu Dev 
370ab6b85c1SVasu Dev 	fc->fip_packet_type.func = fcoe_fip_recv;
371ab6b85c1SVasu Dev 	fc->fip_packet_type.type = htons(ETH_P_FIP);
3721d1b88dcSVasu Dev 	fc->fip_packet_type.dev = netdev;
373ab6b85c1SVasu Dev 	dev_add_pack(&fc->fip_packet_type);
374ab6b85c1SVasu Dev 
375a703e490SVasu Dev 	return 0;
376a703e490SVasu Dev }
377a703e490SVasu Dev 
378a703e490SVasu Dev /**
379a703e490SVasu Dev  * fcoe_shost_config() - Sets up fc_lport->host
380a703e490SVasu Dev  * @lp : ptr to the fc_lport
381a703e490SVasu Dev  * @shost : ptr to the associated scsi host
382a703e490SVasu Dev  * @dev : device associated to scsi host
383a703e490SVasu Dev  *
384a703e490SVasu Dev  * Must be called after fcoe_lport_config() and fcoe_netdev_config()
385a703e490SVasu Dev  *
386a703e490SVasu Dev  * Returns : 0 for success
387a703e490SVasu Dev  */
388a703e490SVasu Dev static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,
389a703e490SVasu Dev 				struct device *dev)
390a703e490SVasu Dev {
391a703e490SVasu Dev 	int rc = 0;
392a703e490SVasu Dev 
393a703e490SVasu Dev 	/* lport scsi host config */
394a703e490SVasu Dev 	lp->host = shost;
395a703e490SVasu Dev 
396a703e490SVasu Dev 	lp->host->max_lun = FCOE_MAX_LUN;
397a703e490SVasu Dev 	lp->host->max_id = FCOE_MAX_FCP_TARGET;
398a703e490SVasu Dev 	lp->host->max_channel = 0;
399a703e490SVasu Dev 	lp->host->transportt = scsi_transport_fcoe_sw;
400a703e490SVasu Dev 
401a703e490SVasu Dev 	/* add the new host to the SCSI-ml */
402a703e490SVasu Dev 	rc = scsi_add_host(lp->host, dev);
403a703e490SVasu Dev 	if (rc) {
404d5488eb9SRobert Love 		FCOE_NETDEV_DBG(fcoe_netdev(lp), "fcoe_shost_config: "
405d5488eb9SRobert Love 				"error on scsi_add_host\n");
406a703e490SVasu Dev 		return rc;
407a703e490SVasu Dev 	}
408a703e490SVasu Dev 	sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s",
409a703e490SVasu Dev 		FCOE_NAME, FCOE_VERSION,
410a703e490SVasu Dev 		fcoe_netdev(lp)->name);
411a703e490SVasu Dev 
412a703e490SVasu Dev 	return 0;
413a703e490SVasu Dev }
414a703e490SVasu Dev 
415d7179680SVasu Dev /*
416d7179680SVasu Dev  * fcoe_oem_match() - match for read types IO
417d7179680SVasu Dev  * @fp: the fc_frame for new IO.
418d7179680SVasu Dev  *
419d7179680SVasu Dev  * Returns : true for read types IO, otherwise returns false.
420d7179680SVasu Dev  */
421d7179680SVasu Dev bool fcoe_oem_match(struct fc_frame *fp)
422d7179680SVasu Dev {
42305cc7390SYi Zou 	return fc_fcp_is_read(fr_fsp(fp)) &&
42405cc7390SYi Zou 		(fr_fsp(fp)->data_len > fcoe_ddp_min);
425d7179680SVasu Dev }
426d7179680SVasu Dev 
427a703e490SVasu Dev /**
428a703e490SVasu Dev  * fcoe_em_config() - allocates em for this lport
429a703e490SVasu Dev  * @lp: the port that em is to allocated for
430a703e490SVasu Dev  *
431e8af4d43SVasu Dev  * Called with write fcoe_hostlist_lock held.
432e8af4d43SVasu Dev  *
433a703e490SVasu Dev  * Returns : 0 on success
434a703e490SVasu Dev  */
435a703e490SVasu Dev static inline int fcoe_em_config(struct fc_lport *lp)
436a703e490SVasu Dev {
437d7179680SVasu Dev 	struct fcoe_softc *fc = lport_priv(lp);
438d7179680SVasu Dev 	struct fcoe_softc *oldfc = NULL;
4391d1b88dcSVasu Dev 	struct net_device *old_real_dev, *cur_real_dev;
440d7179680SVasu Dev 	u16 min_xid = FCOE_MIN_XID;
441d7179680SVasu Dev 	u16 max_xid = FCOE_MAX_XID;
442d7179680SVasu Dev 
443d7179680SVasu Dev 	/*
444d7179680SVasu Dev 	 * Check if need to allocate an em instance for
445d7179680SVasu Dev 	 * offload exchange ids to be shared across all VN_PORTs/lport.
446d7179680SVasu Dev 	 */
447d7179680SVasu Dev 	if (!lp->lro_enabled || !lp->lro_xid || (lp->lro_xid >= max_xid)) {
448d7179680SVasu Dev 		lp->lro_xid = 0;
449d7179680SVasu Dev 		goto skip_oem;
450d7179680SVasu Dev 	}
451d7179680SVasu Dev 
452d7179680SVasu Dev 	/*
453d7179680SVasu Dev 	 * Reuse existing offload em instance in case
4541d1b88dcSVasu Dev 	 * it is already allocated on real eth device
455d7179680SVasu Dev 	 */
4561d1b88dcSVasu Dev 	if (fc->netdev->priv_flags & IFF_802_1Q_VLAN)
4571d1b88dcSVasu Dev 		cur_real_dev = vlan_dev_real_dev(fc->netdev);
4581d1b88dcSVasu Dev 	else
4591d1b88dcSVasu Dev 		cur_real_dev = fc->netdev;
4601d1b88dcSVasu Dev 
461d7179680SVasu Dev 	list_for_each_entry(oldfc, &fcoe_hostlist, list) {
4621d1b88dcSVasu Dev 		if (oldfc->netdev->priv_flags & IFF_802_1Q_VLAN)
4631d1b88dcSVasu Dev 			old_real_dev = vlan_dev_real_dev(oldfc->netdev);
4641d1b88dcSVasu Dev 		else
4651d1b88dcSVasu Dev 			old_real_dev = oldfc->netdev;
4661d1b88dcSVasu Dev 
4671d1b88dcSVasu Dev 		if (cur_real_dev == old_real_dev) {
468d7179680SVasu Dev 			fc->oem = oldfc->oem;
469d7179680SVasu Dev 			break;
470d7179680SVasu Dev 		}
471d7179680SVasu Dev 	}
472d7179680SVasu Dev 
473d7179680SVasu Dev 	if (fc->oem) {
474d7179680SVasu Dev 		if (!fc_exch_mgr_add(lp, fc->oem, fcoe_oem_match)) {
475d7179680SVasu Dev 			printk(KERN_ERR "fcoe_em_config: failed to add "
476d7179680SVasu Dev 			       "offload em:%p on interface:%s\n",
4771d1b88dcSVasu Dev 			       fc->oem, fc->netdev->name);
478a703e490SVasu Dev 			return -ENOMEM;
479d7179680SVasu Dev 		}
480d7179680SVasu Dev 	} else {
481d7179680SVasu Dev 		fc->oem = fc_exch_mgr_alloc(lp, FC_CLASS_3,
482d7179680SVasu Dev 					    FCOE_MIN_XID, lp->lro_xid,
483d7179680SVasu Dev 					    fcoe_oem_match);
484d7179680SVasu Dev 		if (!fc->oem) {
485d7179680SVasu Dev 			printk(KERN_ERR "fcoe_em_config: failed to allocate "
486d7179680SVasu Dev 			       "em for offload exches on interface:%s\n",
4871d1b88dcSVasu Dev 			       fc->netdev->name);
488d7179680SVasu Dev 			return -ENOMEM;
489d7179680SVasu Dev 		}
490d7179680SVasu Dev 	}
491d7179680SVasu Dev 
492d7179680SVasu Dev 	/*
493d7179680SVasu Dev 	 * Exclude offload EM xid range from next EM xid range.
494d7179680SVasu Dev 	 */
495d7179680SVasu Dev 	min_xid += lp->lro_xid + 1;
496d7179680SVasu Dev 
497d7179680SVasu Dev skip_oem:
498d7179680SVasu Dev 	if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, min_xid, max_xid, NULL)) {
499d7179680SVasu Dev 		printk(KERN_ERR "fcoe_em_config: failed to "
5001d1b88dcSVasu Dev 		       "allocate em on interface %s\n", fc->netdev->name);
501d7179680SVasu Dev 		return -ENOMEM;
502d7179680SVasu Dev 	}
503a703e490SVasu Dev 
504a703e490SVasu Dev 	return 0;
505a703e490SVasu Dev }
506a703e490SVasu Dev 
507a703e490SVasu Dev /**
508a703e490SVasu Dev  * fcoe_if_destroy() - FCoE software HBA tear-down function
509af7f85d9SChris Leech  * @lport: fc_lport to destroy
510a703e490SVasu Dev  */
511af7f85d9SChris Leech static void fcoe_if_destroy(struct fc_lport *lport)
512a703e490SVasu Dev {
513af7f85d9SChris Leech 	struct fcoe_softc *fc = lport_priv(lport);
514af7f85d9SChris Leech 	struct net_device *netdev = fc->netdev;
515a703e490SVasu Dev 
516d5488eb9SRobert Love 	FCOE_NETDEV_DBG(netdev, "Destroying interface\n");
517a703e490SVasu Dev 
518a703e490SVasu Dev 	/* Logout of the fabric */
519af7f85d9SChris Leech 	fc_fabric_logoff(lport);
520a703e490SVasu Dev 
521a703e490SVasu Dev 	/* Remove the instance from fcoe's list */
522af7f85d9SChris Leech 	fcoe_hostlist_remove(lport);
523a703e490SVasu Dev 
524ab6b85c1SVasu Dev 	/* clean up netdev configurations */
525ab6b85c1SVasu Dev 	fcoe_netdev_cleanup(fc);
526ab6b85c1SVasu Dev 
527ab6b85c1SVasu Dev 	/* tear-down the FCoE controller */
52897c8389dSJoe Eykholt 	fcoe_ctlr_destroy(&fc->ctlr);
529a703e490SVasu Dev 
530f161fb72SJoe Eykholt 	/* Free queued packets for the per-CPU receive threads */
531af7f85d9SChris Leech 	fcoe_percpu_clean(lport);
532f161fb72SJoe Eykholt 
533a703e490SVasu Dev 	/* Cleanup the fc_lport */
534af7f85d9SChris Leech 	fc_lport_destroy(lport);
535af7f85d9SChris Leech 	fc_fcp_destroy(lport);
536a703e490SVasu Dev 
537a703e490SVasu Dev 	/* Detach from the scsi-ml */
538af7f85d9SChris Leech 	fc_remove_host(lport->host);
539af7f85d9SChris Leech 	scsi_remove_host(lport->host);
540a703e490SVasu Dev 
541a703e490SVasu Dev 	/* There are no more rports or I/O, free the EM */
542af7f85d9SChris Leech 	fc_exch_mgr_free(lport);
543a703e490SVasu Dev 
544a703e490SVasu Dev 	/* Free existing skbs */
545af7f85d9SChris Leech 	fcoe_clean_pending_queue(lport);
546a703e490SVasu Dev 
5471047f221SVasu Dev 	/* Stop the timer */
5481047f221SVasu Dev 	del_timer_sync(&fc->timer);
5491047f221SVasu Dev 
550a703e490SVasu Dev 	/* Free memory used by statistical counters */
551af7f85d9SChris Leech 	fc_lport_free_stats(lport);
552a703e490SVasu Dev 
553a703e490SVasu Dev 	/* Release the net_device and Scsi_Host */
5541d1b88dcSVasu Dev 	dev_put(netdev);
555af7f85d9SChris Leech 	scsi_host_put(lport->host);
556a703e490SVasu Dev }
557a703e490SVasu Dev 
558a703e490SVasu Dev /*
559a703e490SVasu Dev  * fcoe_ddp_setup - calls LLD's ddp_setup through net_device
560a703e490SVasu Dev  * @lp:	the corresponding fc_lport
561a703e490SVasu Dev  * @xid: the exchange id for this ddp transfer
562a703e490SVasu Dev  * @sgl: the scatterlist describing this transfer
563a703e490SVasu Dev  * @sgc: number of sg items
564a703e490SVasu Dev  *
565a703e490SVasu Dev  * Returns : 0 no ddp
566a703e490SVasu Dev  */
567a703e490SVasu Dev static int fcoe_ddp_setup(struct fc_lport *lp, u16 xid,
568a703e490SVasu Dev 			     struct scatterlist *sgl, unsigned int sgc)
569a703e490SVasu Dev {
570a703e490SVasu Dev 	struct net_device *n = fcoe_netdev(lp);
571a703e490SVasu Dev 
572a703e490SVasu Dev 	if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_setup)
573a703e490SVasu Dev 		return n->netdev_ops->ndo_fcoe_ddp_setup(n, xid, sgl, sgc);
574a703e490SVasu Dev 
575a703e490SVasu Dev 	return 0;
576a703e490SVasu Dev }
577a703e490SVasu Dev 
578a703e490SVasu Dev /*
579a703e490SVasu Dev  * fcoe_ddp_done - calls LLD's ddp_done through net_device
580a703e490SVasu Dev  * @lp:	the corresponding fc_lport
581a703e490SVasu Dev  * @xid: the exchange id for this ddp transfer
582a703e490SVasu Dev  *
583a703e490SVasu Dev  * Returns : the length of data that have been completed by ddp
584a703e490SVasu Dev  */
585a703e490SVasu Dev static int fcoe_ddp_done(struct fc_lport *lp, u16 xid)
586a703e490SVasu Dev {
587a703e490SVasu Dev 	struct net_device *n = fcoe_netdev(lp);
588a703e490SVasu Dev 
589a703e490SVasu Dev 	if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_done)
590a703e490SVasu Dev 		return n->netdev_ops->ndo_fcoe_ddp_done(n, xid);
591a703e490SVasu Dev 	return 0;
592a703e490SVasu Dev }
593a703e490SVasu Dev 
594a703e490SVasu Dev static struct libfc_function_template fcoe_libfc_fcn_templ = {
595a703e490SVasu Dev 	.frame_send = fcoe_xmit,
596a703e490SVasu Dev 	.ddp_setup = fcoe_ddp_setup,
597a703e490SVasu Dev 	.ddp_done = fcoe_ddp_done,
598a703e490SVasu Dev };
599a703e490SVasu Dev 
600a703e490SVasu Dev /**
601a703e490SVasu Dev  * fcoe_if_create() - this function creates the fcoe interface
602a703e490SVasu Dev  * @netdev: pointer the associated netdevice
603af7f85d9SChris Leech  * @parent: device pointer to be the parent in sysfs for the SCSI host
604a703e490SVasu Dev  *
605a703e490SVasu Dev  * Creates fc_lport struct and scsi_host for lport, configures lport
606a703e490SVasu Dev  * and starts fabric login.
607a703e490SVasu Dev  *
608af7f85d9SChris Leech  * Returns : The allocated fc_lport or an error pointer
609a703e490SVasu Dev  */
610af7f85d9SChris Leech static struct fc_lport *fcoe_if_create(struct net_device *netdev,
611af7f85d9SChris Leech 				       struct device *parent)
612a703e490SVasu Dev {
613a703e490SVasu Dev 	int rc;
614af7f85d9SChris Leech 	struct fc_lport *lport = NULL;
615a703e490SVasu Dev 	struct fcoe_softc *fc;
616a703e490SVasu Dev 	struct Scsi_Host *shost;
617a703e490SVasu Dev 
618d5488eb9SRobert Love 	FCOE_NETDEV_DBG(netdev, "Create Interface\n");
619a703e490SVasu Dev 
620a0a25da2SVasu Dev 	shost = libfc_host_alloc(&fcoe_shost_template,
621a703e490SVasu Dev 				 sizeof(struct fcoe_softc));
622a703e490SVasu Dev 	if (!shost) {
623d5488eb9SRobert Love 		FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n");
624af7f85d9SChris Leech 		rc = -ENOMEM;
625af7f85d9SChris Leech 		goto out;
626a703e490SVasu Dev 	}
627af7f85d9SChris Leech 	lport = shost_priv(shost);
628af7f85d9SChris Leech 	fc = lport_priv(lport);
629a703e490SVasu Dev 
630a703e490SVasu Dev 	/* configure fc_lport, e.g., em */
631af7f85d9SChris Leech 	rc = fcoe_lport_config(lport);
632a703e490SVasu Dev 	if (rc) {
633d5488eb9SRobert Love 		FCOE_NETDEV_DBG(netdev, "Could not configure lport for the "
634d5488eb9SRobert Love 				"interface\n");
635a703e490SVasu Dev 		goto out_host_put;
636a703e490SVasu Dev 	}
637a703e490SVasu Dev 
63897c8389dSJoe Eykholt 	/*
63997c8389dSJoe Eykholt 	 * Initialize FIP.
64097c8389dSJoe Eykholt 	 */
64197c8389dSJoe Eykholt 	fcoe_ctlr_init(&fc->ctlr);
64297c8389dSJoe Eykholt 	fc->ctlr.send = fcoe_fip_send;
64397c8389dSJoe Eykholt 	fc->ctlr.update_mac = fcoe_update_src_mac;
64497c8389dSJoe Eykholt 
645ab6b85c1SVasu Dev 	/* configure lport network properties */
646af7f85d9SChris Leech 	rc = fcoe_netdev_config(lport, netdev);
647ab6b85c1SVasu Dev 	if (rc) {
648d5488eb9SRobert Love 		FCOE_NETDEV_DBG(netdev, "Could not configure netdev for the "
649d5488eb9SRobert Love 				"interface\n");
650ab6b85c1SVasu Dev 		goto out_netdev_cleanup;
651ab6b85c1SVasu Dev 	}
65297c8389dSJoe Eykholt 
653a703e490SVasu Dev 	/* configure lport scsi host properties */
654af7f85d9SChris Leech 	rc = fcoe_shost_config(lport, shost, parent);
655a703e490SVasu Dev 	if (rc) {
656d5488eb9SRobert Love 		FCOE_NETDEV_DBG(netdev, "Could not configure shost for the "
657d5488eb9SRobert Love 				"interface\n");
658ab6b85c1SVasu Dev 		goto out_netdev_cleanup;
659a703e490SVasu Dev 	}
660a703e490SVasu Dev 
661a703e490SVasu Dev 	/* Initialize the library */
662af7f85d9SChris Leech 	rc = fcoe_libfc_config(lport, &fcoe_libfc_fcn_templ);
663a703e490SVasu Dev 	if (rc) {
664d5488eb9SRobert Love 		FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the "
665d5488eb9SRobert Love 				"interface\n");
666a703e490SVasu Dev 		goto out_lp_destroy;
667a703e490SVasu Dev 	}
668a703e490SVasu Dev 
669e8af4d43SVasu Dev 	/*
670e8af4d43SVasu Dev 	 * fcoe_em_alloc() and fcoe_hostlist_add() both
671e8af4d43SVasu Dev 	 * need to be atomic under fcoe_hostlist_lock
672e8af4d43SVasu Dev 	 * since fcoe_em_alloc() looks for an existing EM
673e8af4d43SVasu Dev 	 * instance on host list updated by fcoe_hostlist_add().
674e8af4d43SVasu Dev 	 */
675e8af4d43SVasu Dev 	write_lock(&fcoe_hostlist_lock);
67696316099SVasu Dev 	/* lport exch manager allocation */
677af7f85d9SChris Leech 	rc = fcoe_em_config(lport);
67896316099SVasu Dev 	if (rc) {
67996316099SVasu Dev 		FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the "
68096316099SVasu Dev 				"interface\n");
68196316099SVasu Dev 		goto out_lp_destroy;
68296316099SVasu Dev 	}
68396316099SVasu Dev 
684a703e490SVasu Dev 	/* add to lports list */
685af7f85d9SChris Leech 	fcoe_hostlist_add(lport);
686e8af4d43SVasu Dev 	write_unlock(&fcoe_hostlist_lock);
687a703e490SVasu Dev 
688af7f85d9SChris Leech 	lport->boot_time = jiffies;
689a703e490SVasu Dev 
690af7f85d9SChris Leech 	fc_fabric_login(lport);
691a703e490SVasu Dev 
692af7f85d9SChris Leech 	if (!fcoe_link_ok(lport))
69397c8389dSJoe Eykholt 		fcoe_ctlr_link_up(&fc->ctlr);
69497c8389dSJoe Eykholt 
695a703e490SVasu Dev 	dev_hold(netdev);
696a703e490SVasu Dev 
697af7f85d9SChris Leech 	return lport;
698a703e490SVasu Dev 
699a703e490SVasu Dev out_lp_destroy:
700af7f85d9SChris Leech 	fc_exch_mgr_free(lport);
701ab6b85c1SVasu Dev out_netdev_cleanup:
702ab6b85c1SVasu Dev 	fcoe_netdev_cleanup(fc);
703a703e490SVasu Dev out_host_put:
704af7f85d9SChris Leech 	scsi_host_put(lport->host);
705af7f85d9SChris Leech out:
706af7f85d9SChris Leech 	return ERR_PTR(rc);
707a703e490SVasu Dev }
708a703e490SVasu Dev 
709a703e490SVasu Dev /**
710a703e490SVasu Dev  * fcoe_if_init() - attach to scsi transport
711a703e490SVasu Dev  *
712a703e490SVasu Dev  * Returns : 0 on success
713a703e490SVasu Dev  */
714a703e490SVasu Dev static int __init fcoe_if_init(void)
715a703e490SVasu Dev {
716a703e490SVasu Dev 	/* attach to scsi transport */
717a703e490SVasu Dev 	scsi_transport_fcoe_sw =
718a703e490SVasu Dev 		fc_attach_transport(&fcoe_transport_function);
719a703e490SVasu Dev 
720a703e490SVasu Dev 	if (!scsi_transport_fcoe_sw) {
721d5488eb9SRobert Love 		printk(KERN_ERR "fcoe: Failed to attach to the FC transport\n");
722a703e490SVasu Dev 		return -ENODEV;
723a703e490SVasu Dev 	}
724a703e490SVasu Dev 
725a703e490SVasu Dev 	return 0;
726a703e490SVasu Dev }
727a703e490SVasu Dev 
728a703e490SVasu Dev /**
729a703e490SVasu Dev  * fcoe_if_exit() - detach from scsi transport
730a703e490SVasu Dev  *
731a703e490SVasu Dev  * Returns : 0 on success
732a703e490SVasu Dev  */
733a703e490SVasu Dev int __exit fcoe_if_exit(void)
734a703e490SVasu Dev {
735a703e490SVasu Dev 	fc_release_transport(scsi_transport_fcoe_sw);
736a703e490SVasu Dev 	return 0;
737a703e490SVasu Dev }
738a703e490SVasu Dev 
739a703e490SVasu Dev /**
740a703e490SVasu Dev  * fcoe_percpu_thread_create() - Create a receive thread for an online cpu
741a703e490SVasu Dev  * @cpu: cpu index for the online cpu
742a703e490SVasu Dev  */
743a703e490SVasu Dev static void fcoe_percpu_thread_create(unsigned int cpu)
744a703e490SVasu Dev {
745a703e490SVasu Dev 	struct fcoe_percpu_s *p;
746a703e490SVasu Dev 	struct task_struct *thread;
747a703e490SVasu Dev 
748a703e490SVasu Dev 	p = &per_cpu(fcoe_percpu, cpu);
749a703e490SVasu Dev 
750a703e490SVasu Dev 	thread = kthread_create(fcoe_percpu_receive_thread,
751a703e490SVasu Dev 				(void *)p, "fcoethread/%d", cpu);
752a703e490SVasu Dev 
753a703e490SVasu Dev 	if (likely(!IS_ERR(p->thread))) {
754a703e490SVasu Dev 		kthread_bind(thread, cpu);
755a703e490SVasu Dev 		wake_up_process(thread);
756a703e490SVasu Dev 
757a703e490SVasu Dev 		spin_lock_bh(&p->fcoe_rx_list.lock);
758a703e490SVasu Dev 		p->thread = thread;
759a703e490SVasu Dev 		spin_unlock_bh(&p->fcoe_rx_list.lock);
760a703e490SVasu Dev 	}
761a703e490SVasu Dev }
762a703e490SVasu Dev 
763a703e490SVasu Dev /**
764a703e490SVasu Dev  * fcoe_percpu_thread_destroy() - removes the rx thread for the given cpu
765a703e490SVasu Dev  * @cpu: cpu index the rx thread is to be removed
766a703e490SVasu Dev  *
767a703e490SVasu Dev  * Destroys a per-CPU Rx thread. Any pending skbs are moved to the
768a703e490SVasu Dev  * current CPU's Rx thread. If the thread being destroyed is bound to
769a703e490SVasu Dev  * the CPU processing this context the skbs will be freed.
770a703e490SVasu Dev  */
771a703e490SVasu Dev static void fcoe_percpu_thread_destroy(unsigned int cpu)
772a703e490SVasu Dev {
773a703e490SVasu Dev 	struct fcoe_percpu_s *p;
774a703e490SVasu Dev 	struct task_struct *thread;
775a703e490SVasu Dev 	struct page *crc_eof;
776a703e490SVasu Dev 	struct sk_buff *skb;
777a703e490SVasu Dev #ifdef CONFIG_SMP
778a703e490SVasu Dev 	struct fcoe_percpu_s *p0;
779a703e490SVasu Dev 	unsigned targ_cpu = smp_processor_id();
780a703e490SVasu Dev #endif /* CONFIG_SMP */
781a703e490SVasu Dev 
782d5488eb9SRobert Love 	FCOE_DBG("Destroying receive thread for CPU %d\n", cpu);
783a703e490SVasu Dev 
784a703e490SVasu Dev 	/* Prevent any new skbs from being queued for this CPU. */
785a703e490SVasu Dev 	p = &per_cpu(fcoe_percpu, cpu);
786a703e490SVasu Dev 	spin_lock_bh(&p->fcoe_rx_list.lock);
787a703e490SVasu Dev 	thread = p->thread;
788a703e490SVasu Dev 	p->thread = NULL;
789a703e490SVasu Dev 	crc_eof = p->crc_eof_page;
790a703e490SVasu Dev 	p->crc_eof_page = NULL;
791a703e490SVasu Dev 	p->crc_eof_offset = 0;
792a703e490SVasu Dev 	spin_unlock_bh(&p->fcoe_rx_list.lock);
793a703e490SVasu Dev 
794a703e490SVasu Dev #ifdef CONFIG_SMP
795a703e490SVasu Dev 	/*
796a703e490SVasu Dev 	 * Don't bother moving the skb's if this context is running
797a703e490SVasu Dev 	 * on the same CPU that is having its thread destroyed. This
798a703e490SVasu Dev 	 * can easily happen when the module is removed.
799a703e490SVasu Dev 	 */
800a703e490SVasu Dev 	if (cpu != targ_cpu) {
801a703e490SVasu Dev 		p0 = &per_cpu(fcoe_percpu, targ_cpu);
802a703e490SVasu Dev 		spin_lock_bh(&p0->fcoe_rx_list.lock);
803a703e490SVasu Dev 		if (p0->thread) {
804d5488eb9SRobert Love 			FCOE_DBG("Moving frames from CPU %d to CPU %d\n",
805a703e490SVasu Dev 				 cpu, targ_cpu);
806a703e490SVasu Dev 
807a703e490SVasu Dev 			while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL)
808a703e490SVasu Dev 				__skb_queue_tail(&p0->fcoe_rx_list, skb);
809a703e490SVasu Dev 			spin_unlock_bh(&p0->fcoe_rx_list.lock);
810a703e490SVasu Dev 		} else {
811a703e490SVasu Dev 			/*
812a703e490SVasu Dev 			 * The targeted CPU is not initialized and cannot accept
813a703e490SVasu Dev 			 * new  skbs. Unlock the targeted CPU and drop the skbs
814a703e490SVasu Dev 			 * on the CPU that is going offline.
815a703e490SVasu Dev 			 */
816a703e490SVasu Dev 			while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL)
817a703e490SVasu Dev 				kfree_skb(skb);
818a703e490SVasu Dev 			spin_unlock_bh(&p0->fcoe_rx_list.lock);
819a703e490SVasu Dev 		}
820a703e490SVasu Dev 	} else {
821a703e490SVasu Dev 		/*
822a703e490SVasu Dev 		 * This scenario occurs when the module is being removed
823a703e490SVasu Dev 		 * and all threads are being destroyed. skbs will continue
824a703e490SVasu Dev 		 * to be shifted from the CPU thread that is being removed
825a703e490SVasu Dev 		 * to the CPU thread associated with the CPU that is processing
826a703e490SVasu Dev 		 * the module removal. Once there is only one CPU Rx thread it
827a703e490SVasu Dev 		 * will reach this case and we will drop all skbs and later
828a703e490SVasu Dev 		 * stop the thread.
829a703e490SVasu Dev 		 */
830a703e490SVasu Dev 		spin_lock_bh(&p->fcoe_rx_list.lock);
831a703e490SVasu Dev 		while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL)
832a703e490SVasu Dev 			kfree_skb(skb);
833a703e490SVasu Dev 		spin_unlock_bh(&p->fcoe_rx_list.lock);
834a703e490SVasu Dev 	}
835a703e490SVasu Dev #else
836a703e490SVasu Dev 	/*
837dd3fd72eSChris Leech 	 * This a non-SMP scenario where the singular Rx thread is
838a703e490SVasu Dev 	 * being removed. Free all skbs and stop the thread.
839a703e490SVasu Dev 	 */
840a703e490SVasu Dev 	spin_lock_bh(&p->fcoe_rx_list.lock);
841a703e490SVasu Dev 	while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL)
842a703e490SVasu Dev 		kfree_skb(skb);
843a703e490SVasu Dev 	spin_unlock_bh(&p->fcoe_rx_list.lock);
844a703e490SVasu Dev #endif
845a703e490SVasu Dev 
846a703e490SVasu Dev 	if (thread)
847a703e490SVasu Dev 		kthread_stop(thread);
848a703e490SVasu Dev 
849a703e490SVasu Dev 	if (crc_eof)
850a703e490SVasu Dev 		put_page(crc_eof);
851a703e490SVasu Dev }
852a703e490SVasu Dev 
853a703e490SVasu Dev /**
854a703e490SVasu Dev  * fcoe_cpu_callback() - fcoe cpu hotplug event callback
855a703e490SVasu Dev  * @nfb: callback data block
856a703e490SVasu Dev  * @action: event triggering the callback
857a703e490SVasu Dev  * @hcpu: index for the cpu of this event
858a703e490SVasu Dev  *
859a703e490SVasu Dev  * This creates or destroys per cpu data for fcoe
860a703e490SVasu Dev  *
861a703e490SVasu Dev  * Returns NOTIFY_OK always.
862a703e490SVasu Dev  */
863a703e490SVasu Dev static int fcoe_cpu_callback(struct notifier_block *nfb,
864a703e490SVasu Dev 			     unsigned long action, void *hcpu)
865a703e490SVasu Dev {
866a703e490SVasu Dev 	unsigned cpu = (unsigned long)hcpu;
867a703e490SVasu Dev 
868a703e490SVasu Dev 	switch (action) {
869a703e490SVasu Dev 	case CPU_ONLINE:
870a703e490SVasu Dev 	case CPU_ONLINE_FROZEN:
871d5488eb9SRobert Love 		FCOE_DBG("CPU %x online: Create Rx thread\n", cpu);
872a703e490SVasu Dev 		fcoe_percpu_thread_create(cpu);
873a703e490SVasu Dev 		break;
874a703e490SVasu Dev 	case CPU_DEAD:
875a703e490SVasu Dev 	case CPU_DEAD_FROZEN:
876d5488eb9SRobert Love 		FCOE_DBG("CPU %x offline: Remove Rx thread\n", cpu);
877a703e490SVasu Dev 		fcoe_percpu_thread_destroy(cpu);
878a703e490SVasu Dev 		break;
879a703e490SVasu Dev 	default:
880a703e490SVasu Dev 		break;
881a703e490SVasu Dev 	}
882a703e490SVasu Dev 	return NOTIFY_OK;
883a703e490SVasu Dev }
884a703e490SVasu Dev 
885a703e490SVasu Dev static struct notifier_block fcoe_cpu_notifier = {
886a703e490SVasu Dev 	.notifier_call = fcoe_cpu_callback,
887a703e490SVasu Dev };
888a703e490SVasu Dev 
889a703e490SVasu Dev /**
890a703e490SVasu Dev  * fcoe_rcv() - this is the fcoe receive function called by NET_RX_SOFTIRQ
891a703e490SVasu Dev  * @skb: the receive skb
892a703e490SVasu Dev  * @dev: associated net device
893a703e490SVasu Dev  * @ptype: context
894dd3fd72eSChris Leech  * @olddev: last device
895a703e490SVasu Dev  *
896a703e490SVasu Dev  * this function will receive the packet and build fc frame and pass it up
897a703e490SVasu Dev  *
898a703e490SVasu Dev  * Returns: 0 for success
899a703e490SVasu Dev  */
900a703e490SVasu Dev int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,
901a703e490SVasu Dev 	     struct packet_type *ptype, struct net_device *olddev)
902a703e490SVasu Dev {
903a703e490SVasu Dev 	struct fc_lport *lp;
904a703e490SVasu Dev 	struct fcoe_rcv_info *fr;
905a703e490SVasu Dev 	struct fcoe_softc *fc;
906a703e490SVasu Dev 	struct fc_frame_header *fh;
907a703e490SVasu Dev 	struct fcoe_percpu_s *fps;
908b2f0091fSVasu Dev 	unsigned int cpu;
909a703e490SVasu Dev 
910a703e490SVasu Dev 	fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type);
91197c8389dSJoe Eykholt 	lp = fc->ctlr.lp;
912a703e490SVasu Dev 	if (unlikely(lp == NULL)) {
913d5488eb9SRobert Love 		FCOE_NETDEV_DBG(dev, "Cannot find hba structure");
914a703e490SVasu Dev 		goto err2;
915a703e490SVasu Dev 	}
91697c8389dSJoe Eykholt 	if (!lp->link_up)
91797c8389dSJoe Eykholt 		goto err2;
918a703e490SVasu Dev 
919d5488eb9SRobert Love 	FCOE_NETDEV_DBG(dev, "skb_info: len:%d data_len:%d head:%p "
920d5488eb9SRobert Love 			"data:%p tail:%p end:%p sum:%d dev:%s",
921d5488eb9SRobert Love 			skb->len, skb->data_len, skb->head, skb->data,
922d5488eb9SRobert Love 			skb_tail_pointer(skb), skb_end_pointer(skb),
923d5488eb9SRobert Love 			skb->csum, skb->dev ? skb->dev->name : "<NULL>");
924a703e490SVasu Dev 
925a703e490SVasu Dev 	/* check for FCOE packet type */
926a703e490SVasu Dev 	if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
927d5488eb9SRobert Love 		FCOE_NETDEV_DBG(dev, "Wrong FC type frame");
928a703e490SVasu Dev 		goto err;
929a703e490SVasu Dev 	}
930a703e490SVasu Dev 
931a703e490SVasu Dev 	/*
932a703e490SVasu Dev 	 * Check for minimum frame length, and make sure required FCoE
933a703e490SVasu Dev 	 * and FC headers are pulled into the linear data area.
934a703e490SVasu Dev 	 */
935a703e490SVasu Dev 	if (unlikely((skb->len < FCOE_MIN_FRAME) ||
936a703e490SVasu Dev 	    !pskb_may_pull(skb, FCOE_HEADER_LEN)))
937a703e490SVasu Dev 		goto err;
938a703e490SVasu Dev 
939a703e490SVasu Dev 	skb_set_transport_header(skb, sizeof(struct fcoe_hdr));
940a703e490SVasu Dev 	fh = (struct fc_frame_header *) skb_transport_header(skb);
941a703e490SVasu Dev 
942a703e490SVasu Dev 	fr = fcoe_dev_from_skb(skb);
943a703e490SVasu Dev 	fr->fr_dev = lp;
944a703e490SVasu Dev 	fr->ptype = ptype;
945a703e490SVasu Dev 
946a703e490SVasu Dev 	/*
947b2f0091fSVasu Dev 	 * In case the incoming frame's exchange is originated from
948b2f0091fSVasu Dev 	 * the initiator, then received frame's exchange id is ANDed
949b2f0091fSVasu Dev 	 * with fc_cpu_mask bits to get the same cpu on which exchange
950b2f0091fSVasu Dev 	 * was originated, otherwise just use the current cpu.
951a703e490SVasu Dev 	 */
952b2f0091fSVasu Dev 	if (ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX)
953b2f0091fSVasu Dev 		cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask;
954b2f0091fSVasu Dev 	else
955b2f0091fSVasu Dev 		cpu = smp_processor_id();
956a703e490SVasu Dev 
957a703e490SVasu Dev 	fps = &per_cpu(fcoe_percpu, cpu);
958a703e490SVasu Dev 	spin_lock_bh(&fps->fcoe_rx_list.lock);
959a703e490SVasu Dev 	if (unlikely(!fps->thread)) {
960a703e490SVasu Dev 		/*
961a703e490SVasu Dev 		 * The targeted CPU is not ready, let's target
962a703e490SVasu Dev 		 * the first CPU now. For non-SMP systems this
963a703e490SVasu Dev 		 * will check the same CPU twice.
964a703e490SVasu Dev 		 */
965d5488eb9SRobert Love 		FCOE_NETDEV_DBG(dev, "CPU is online, but no receive thread "
966d5488eb9SRobert Love 				"ready for incoming skb- using first online "
967d5488eb9SRobert Love 				"CPU.\n");
968a703e490SVasu Dev 
969a703e490SVasu Dev 		spin_unlock_bh(&fps->fcoe_rx_list.lock);
970a703e490SVasu Dev 		cpu = first_cpu(cpu_online_map);
971a703e490SVasu Dev 		fps = &per_cpu(fcoe_percpu, cpu);
972a703e490SVasu Dev 		spin_lock_bh(&fps->fcoe_rx_list.lock);
973a703e490SVasu Dev 		if (!fps->thread) {
974a703e490SVasu Dev 			spin_unlock_bh(&fps->fcoe_rx_list.lock);
975a703e490SVasu Dev 			goto err;
976a703e490SVasu Dev 		}
977a703e490SVasu Dev 	}
978a703e490SVasu Dev 
979a703e490SVasu Dev 	/*
980a703e490SVasu Dev 	 * We now have a valid CPU that we're targeting for
981a703e490SVasu Dev 	 * this skb. We also have this receive thread locked,
982a703e490SVasu Dev 	 * so we're free to queue skbs into it's queue.
983a703e490SVasu Dev 	 */
984a703e490SVasu Dev 	__skb_queue_tail(&fps->fcoe_rx_list, skb);
985a703e490SVasu Dev 	if (fps->fcoe_rx_list.qlen == 1)
986a703e490SVasu Dev 		wake_up_process(fps->thread);
987a703e490SVasu Dev 
988a703e490SVasu Dev 	spin_unlock_bh(&fps->fcoe_rx_list.lock);
989a703e490SVasu Dev 
990a703e490SVasu Dev 	return 0;
991a703e490SVasu Dev err:
992a703e490SVasu Dev 	fc_lport_get_stats(lp)->ErrorFrames++;
993a703e490SVasu Dev 
994a703e490SVasu Dev err2:
995a703e490SVasu Dev 	kfree_skb(skb);
996a703e490SVasu Dev 	return -1;
997a703e490SVasu Dev }
998a703e490SVasu Dev 
999a703e490SVasu Dev /**
1000a703e490SVasu Dev  * fcoe_start_io() - pass to netdev to start xmit for fcoe
1001a703e490SVasu Dev  * @skb: the skb to be xmitted
1002a703e490SVasu Dev  *
1003a703e490SVasu Dev  * Returns: 0 for success
1004a703e490SVasu Dev  */
1005a703e490SVasu Dev static inline int fcoe_start_io(struct sk_buff *skb)
1006a703e490SVasu Dev {
1007a703e490SVasu Dev 	int rc;
1008a703e490SVasu Dev 
1009a703e490SVasu Dev 	skb_get(skb);
1010a703e490SVasu Dev 	rc = dev_queue_xmit(skb);
1011a703e490SVasu Dev 	if (rc != 0)
1012a703e490SVasu Dev 		return rc;
1013a703e490SVasu Dev 	kfree_skb(skb);
1014a703e490SVasu Dev 	return 0;
1015a703e490SVasu Dev }
1016a703e490SVasu Dev 
1017a703e490SVasu Dev /**
1018dd3fd72eSChris Leech  * fcoe_get_paged_crc_eof() - in case we need to alloc a page for crc_eof
1019a703e490SVasu Dev  * @skb: the skb to be xmitted
1020a703e490SVasu Dev  * @tlen: total len
1021a703e490SVasu Dev  *
1022a703e490SVasu Dev  * Returns: 0 for success
1023a703e490SVasu Dev  */
1024a703e490SVasu Dev static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen)
1025a703e490SVasu Dev {
1026a703e490SVasu Dev 	struct fcoe_percpu_s *fps;
1027a703e490SVasu Dev 	struct page *page;
1028a703e490SVasu Dev 
1029a703e490SVasu Dev 	fps = &get_cpu_var(fcoe_percpu);
1030a703e490SVasu Dev 	page = fps->crc_eof_page;
1031a703e490SVasu Dev 	if (!page) {
1032a703e490SVasu Dev 		page = alloc_page(GFP_ATOMIC);
1033a703e490SVasu Dev 		if (!page) {
1034a703e490SVasu Dev 			put_cpu_var(fcoe_percpu);
1035a703e490SVasu Dev 			return -ENOMEM;
1036a703e490SVasu Dev 		}
1037a703e490SVasu Dev 		fps->crc_eof_page = page;
1038a703e490SVasu Dev 		fps->crc_eof_offset = 0;
1039a703e490SVasu Dev 	}
1040a703e490SVasu Dev 
1041a703e490SVasu Dev 	get_page(page);
1042a703e490SVasu Dev 	skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page,
1043a703e490SVasu Dev 			   fps->crc_eof_offset, tlen);
1044a703e490SVasu Dev 	skb->len += tlen;
1045a703e490SVasu Dev 	skb->data_len += tlen;
1046a703e490SVasu Dev 	skb->truesize += tlen;
1047a703e490SVasu Dev 	fps->crc_eof_offset += sizeof(struct fcoe_crc_eof);
1048a703e490SVasu Dev 
1049a703e490SVasu Dev 	if (fps->crc_eof_offset >= PAGE_SIZE) {
1050a703e490SVasu Dev 		fps->crc_eof_page = NULL;
1051a703e490SVasu Dev 		fps->crc_eof_offset = 0;
1052a703e490SVasu Dev 		put_page(page);
1053a703e490SVasu Dev 	}
1054a703e490SVasu Dev 	put_cpu_var(fcoe_percpu);
1055a703e490SVasu Dev 	return 0;
1056a703e490SVasu Dev }
1057a703e490SVasu Dev 
1058a703e490SVasu Dev /**
1059a703e490SVasu Dev  * fcoe_fc_crc() - calculates FC CRC in this fcoe skb
1060dd3fd72eSChris Leech  * @fp: the fc_frame containing data to be checksummed
1061a703e490SVasu Dev  *
1062a703e490SVasu Dev  * This uses crc32() to calculate the crc for fc frame
1063a703e490SVasu Dev  * Return   : 32 bit crc
1064a703e490SVasu Dev  */
1065a703e490SVasu Dev u32 fcoe_fc_crc(struct fc_frame *fp)
1066a703e490SVasu Dev {
1067a703e490SVasu Dev 	struct sk_buff *skb = fp_skb(fp);
1068a703e490SVasu Dev 	struct skb_frag_struct *frag;
1069a703e490SVasu Dev 	unsigned char *data;
1070a703e490SVasu Dev 	unsigned long off, len, clen;
1071a703e490SVasu Dev 	u32 crc;
1072a703e490SVasu Dev 	unsigned i;
1073a703e490SVasu Dev 
1074a703e490SVasu Dev 	crc = crc32(~0, skb->data, skb_headlen(skb));
1075a703e490SVasu Dev 
1076a703e490SVasu Dev 	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
1077a703e490SVasu Dev 		frag = &skb_shinfo(skb)->frags[i];
1078a703e490SVasu Dev 		off = frag->page_offset;
1079a703e490SVasu Dev 		len = frag->size;
1080a703e490SVasu Dev 		while (len > 0) {
1081a703e490SVasu Dev 			clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK));
1082a703e490SVasu Dev 			data = kmap_atomic(frag->page + (off >> PAGE_SHIFT),
1083a703e490SVasu Dev 					   KM_SKB_DATA_SOFTIRQ);
1084a703e490SVasu Dev 			crc = crc32(crc, data + (off & ~PAGE_MASK), clen);
1085a703e490SVasu Dev 			kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ);
1086a703e490SVasu Dev 			off += clen;
1087a703e490SVasu Dev 			len -= clen;
1088a703e490SVasu Dev 		}
1089a703e490SVasu Dev 	}
1090a703e490SVasu Dev 	return crc;
1091a703e490SVasu Dev }
1092a703e490SVasu Dev 
1093a703e490SVasu Dev /**
1094a703e490SVasu Dev  * fcoe_xmit() - FCoE frame transmit function
1095a703e490SVasu Dev  * @lp:	the associated local port
1096a703e490SVasu Dev  * @fp: the fc_frame to be transmitted
1097a703e490SVasu Dev  *
1098a703e490SVasu Dev  * Return   : 0 for success
1099a703e490SVasu Dev  */
1100a703e490SVasu Dev int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
1101a703e490SVasu Dev {
11024bb6b515SVasu Dev 	int wlen;
1103a703e490SVasu Dev 	u32 crc;
1104a703e490SVasu Dev 	struct ethhdr *eh;
1105a703e490SVasu Dev 	struct fcoe_crc_eof *cp;
1106a703e490SVasu Dev 	struct sk_buff *skb;
1107a703e490SVasu Dev 	struct fcoe_dev_stats *stats;
1108a703e490SVasu Dev 	struct fc_frame_header *fh;
1109a703e490SVasu Dev 	unsigned int hlen;		/* header length implies the version */
1110a703e490SVasu Dev 	unsigned int tlen;		/* trailer length */
1111a703e490SVasu Dev 	unsigned int elen;		/* eth header, may include vlan */
1112a703e490SVasu Dev 	struct fcoe_softc *fc;
1113a703e490SVasu Dev 	u8 sof, eof;
1114a703e490SVasu Dev 	struct fcoe_hdr *hp;
1115a703e490SVasu Dev 
1116a703e490SVasu Dev 	WARN_ON((fr_len(fp) % sizeof(u32)) != 0);
1117a703e490SVasu Dev 
1118a703e490SVasu Dev 	fc = lport_priv(lp);
1119a703e490SVasu Dev 	fh = fc_frame_header_get(fp);
112097c8389dSJoe Eykholt 	skb = fp_skb(fp);
112197c8389dSJoe Eykholt 	wlen = skb->len / FCOE_WORD_TO_BYTE;
112297c8389dSJoe Eykholt 
112397c8389dSJoe Eykholt 	if (!lp->link_up) {
11243caf02eeSDan Carpenter 		kfree_skb(skb);
112597c8389dSJoe Eykholt 		return 0;
1126a703e490SVasu Dev 	}
1127a703e490SVasu Dev 
112897c8389dSJoe Eykholt 	if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) &&
112997c8389dSJoe Eykholt 	    fcoe_ctlr_els_send(&fc->ctlr, skb))
113097c8389dSJoe Eykholt 		return 0;
113197c8389dSJoe Eykholt 
1132a703e490SVasu Dev 	sof = fr_sof(fp);
1133a703e490SVasu Dev 	eof = fr_eof(fp);
1134a703e490SVasu Dev 
11354e57e1cbSVasu Dev 	elen = sizeof(struct ethhdr);
1136a703e490SVasu Dev 	hlen = sizeof(struct fcoe_hdr);
1137a703e490SVasu Dev 	tlen = sizeof(struct fcoe_crc_eof);
1138a703e490SVasu Dev 	wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE;
1139a703e490SVasu Dev 
1140a703e490SVasu Dev 	/* crc offload */
1141a703e490SVasu Dev 	if (likely(lp->crc_offload)) {
1142a703e490SVasu Dev 		skb->ip_summed = CHECKSUM_PARTIAL;
1143a703e490SVasu Dev 		skb->csum_start = skb_headroom(skb);
1144a703e490SVasu Dev 		skb->csum_offset = skb->len;
1145a703e490SVasu Dev 		crc = 0;
1146a703e490SVasu Dev 	} else {
1147a703e490SVasu Dev 		skb->ip_summed = CHECKSUM_NONE;
1148a703e490SVasu Dev 		crc = fcoe_fc_crc(fp);
1149a703e490SVasu Dev 	}
1150a703e490SVasu Dev 
1151a703e490SVasu Dev 	/* copy fc crc and eof to the skb buff */
1152a703e490SVasu Dev 	if (skb_is_nonlinear(skb)) {
1153a703e490SVasu Dev 		skb_frag_t *frag;
1154a703e490SVasu Dev 		if (fcoe_get_paged_crc_eof(skb, tlen)) {
1155a703e490SVasu Dev 			kfree_skb(skb);
1156a703e490SVasu Dev 			return -ENOMEM;
1157a703e490SVasu Dev 		}
1158a703e490SVasu Dev 		frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1];
1159a703e490SVasu Dev 		cp = kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ)
1160a703e490SVasu Dev 			+ frag->page_offset;
1161a703e490SVasu Dev 	} else {
1162a703e490SVasu Dev 		cp = (struct fcoe_crc_eof *)skb_put(skb, tlen);
1163a703e490SVasu Dev 	}
1164a703e490SVasu Dev 
1165a703e490SVasu Dev 	memset(cp, 0, sizeof(*cp));
1166a703e490SVasu Dev 	cp->fcoe_eof = eof;
1167a703e490SVasu Dev 	cp->fcoe_crc32 = cpu_to_le32(~crc);
1168a703e490SVasu Dev 
1169a703e490SVasu Dev 	if (skb_is_nonlinear(skb)) {
1170a703e490SVasu Dev 		kunmap_atomic(cp, KM_SKB_DATA_SOFTIRQ);
1171a703e490SVasu Dev 		cp = NULL;
1172a703e490SVasu Dev 	}
1173a703e490SVasu Dev 
1174dd3fd72eSChris Leech 	/* adjust skb network/transport offsets to match mac/fcoe/fc */
1175a703e490SVasu Dev 	skb_push(skb, elen + hlen);
1176a703e490SVasu Dev 	skb_reset_mac_header(skb);
1177a703e490SVasu Dev 	skb_reset_network_header(skb);
1178a703e490SVasu Dev 	skb->mac_len = elen;
1179a703e490SVasu Dev 	skb->protocol = htons(ETH_P_FCOE);
11801d1b88dcSVasu Dev 	skb->dev = fc->netdev;
1181a703e490SVasu Dev 
1182a703e490SVasu Dev 	/* fill up mac and fcoe headers */
1183a703e490SVasu Dev 	eh = eth_hdr(skb);
1184a703e490SVasu Dev 	eh->h_proto = htons(ETH_P_FCOE);
118597c8389dSJoe Eykholt 	if (fc->ctlr.map_dest)
1186a703e490SVasu Dev 		fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id);
1187a703e490SVasu Dev 	else
1188a703e490SVasu Dev 		/* insert GW address */
118997c8389dSJoe Eykholt 		memcpy(eh->h_dest, fc->ctlr.dest_addr, ETH_ALEN);
1190a703e490SVasu Dev 
119197c8389dSJoe Eykholt 	if (unlikely(fc->ctlr.flogi_oxid != FC_XID_UNKNOWN))
119297c8389dSJoe Eykholt 		memcpy(eh->h_source, fc->ctlr.ctl_src_addr, ETH_ALEN);
1193a703e490SVasu Dev 	else
119497c8389dSJoe Eykholt 		memcpy(eh->h_source, fc->ctlr.data_src_addr, ETH_ALEN);
1195a703e490SVasu Dev 
1196a703e490SVasu Dev 	hp = (struct fcoe_hdr *)(eh + 1);
1197a703e490SVasu Dev 	memset(hp, 0, sizeof(*hp));
1198a703e490SVasu Dev 	if (FC_FCOE_VER)
1199a703e490SVasu Dev 		FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER);
1200a703e490SVasu Dev 	hp->fcoe_sof = sof;
1201a703e490SVasu Dev 
1202a703e490SVasu Dev 	/* fcoe lso, mss is in max_payload which is non-zero for FCP data */
1203a703e490SVasu Dev 	if (lp->seq_offload && fr_max_payload(fp)) {
1204a703e490SVasu Dev 		skb_shinfo(skb)->gso_type = SKB_GSO_FCOE;
1205a703e490SVasu Dev 		skb_shinfo(skb)->gso_size = fr_max_payload(fp);
1206a703e490SVasu Dev 	} else {
1207a703e490SVasu Dev 		skb_shinfo(skb)->gso_type = 0;
1208a703e490SVasu Dev 		skb_shinfo(skb)->gso_size = 0;
1209a703e490SVasu Dev 	}
1210a703e490SVasu Dev 	/* update tx stats: regardless if LLD fails */
1211a703e490SVasu Dev 	stats = fc_lport_get_stats(lp);
1212a703e490SVasu Dev 	stats->TxFrames++;
1213a703e490SVasu Dev 	stats->TxWords += wlen;
1214a703e490SVasu Dev 
1215a703e490SVasu Dev 	/* send down to lld */
1216a703e490SVasu Dev 	fr_dev(fp) = lp;
1217a703e490SVasu Dev 	if (fc->fcoe_pending_queue.qlen)
12184bb6b515SVasu Dev 		fcoe_check_wait_queue(lp, skb);
12194bb6b515SVasu Dev 	else if (fcoe_start_io(skb))
12204bb6b515SVasu Dev 		fcoe_check_wait_queue(lp, skb);
1221a703e490SVasu Dev 
1222a703e490SVasu Dev 	return 0;
1223a703e490SVasu Dev }
1224a703e490SVasu Dev 
1225a703e490SVasu Dev /**
1226a703e490SVasu Dev  * fcoe_percpu_receive_thread() - recv thread per cpu
1227a703e490SVasu Dev  * @arg: ptr to the fcoe per cpu struct
1228a703e490SVasu Dev  *
1229a703e490SVasu Dev  * Return: 0 for success
1230a703e490SVasu Dev  */
1231a703e490SVasu Dev int fcoe_percpu_receive_thread(void *arg)
1232a703e490SVasu Dev {
1233a703e490SVasu Dev 	struct fcoe_percpu_s *p = arg;
1234a703e490SVasu Dev 	u32 fr_len;
1235a703e490SVasu Dev 	struct fc_lport *lp;
1236a703e490SVasu Dev 	struct fcoe_rcv_info *fr;
1237a703e490SVasu Dev 	struct fcoe_dev_stats *stats;
1238a703e490SVasu Dev 	struct fc_frame_header *fh;
1239a703e490SVasu Dev 	struct sk_buff *skb;
1240a703e490SVasu Dev 	struct fcoe_crc_eof crc_eof;
1241a703e490SVasu Dev 	struct fc_frame *fp;
1242a703e490SVasu Dev 	u8 *mac = NULL;
1243a703e490SVasu Dev 	struct fcoe_softc *fc;
1244a703e490SVasu Dev 	struct fcoe_hdr *hp;
1245a703e490SVasu Dev 
1246a703e490SVasu Dev 	set_user_nice(current, -20);
1247a703e490SVasu Dev 
1248a703e490SVasu Dev 	while (!kthread_should_stop()) {
1249a703e490SVasu Dev 
1250a703e490SVasu Dev 		spin_lock_bh(&p->fcoe_rx_list.lock);
1251a703e490SVasu Dev 		while ((skb = __skb_dequeue(&p->fcoe_rx_list)) == NULL) {
1252a703e490SVasu Dev 			set_current_state(TASK_INTERRUPTIBLE);
1253a703e490SVasu Dev 			spin_unlock_bh(&p->fcoe_rx_list.lock);
1254a703e490SVasu Dev 			schedule();
1255a703e490SVasu Dev 			set_current_state(TASK_RUNNING);
1256a703e490SVasu Dev 			if (kthread_should_stop())
1257a703e490SVasu Dev 				return 0;
1258a703e490SVasu Dev 			spin_lock_bh(&p->fcoe_rx_list.lock);
1259a703e490SVasu Dev 		}
1260a703e490SVasu Dev 		spin_unlock_bh(&p->fcoe_rx_list.lock);
1261a703e490SVasu Dev 		fr = fcoe_dev_from_skb(skb);
1262a703e490SVasu Dev 		lp = fr->fr_dev;
1263a703e490SVasu Dev 		if (unlikely(lp == NULL)) {
1264d5488eb9SRobert Love 			FCOE_NETDEV_DBG(skb->dev, "Invalid HBA Structure");
1265a703e490SVasu Dev 			kfree_skb(skb);
1266a703e490SVasu Dev 			continue;
1267a703e490SVasu Dev 		}
1268a703e490SVasu Dev 
1269d5488eb9SRobert Love 		FCOE_NETDEV_DBG(skb->dev, "skb_info: len:%d data_len:%d "
1270d5488eb9SRobert Love 				"head:%p data:%p tail:%p end:%p sum:%d dev:%s",
1271a703e490SVasu Dev 				skb->len, skb->data_len,
1272a703e490SVasu Dev 				skb->head, skb->data, skb_tail_pointer(skb),
1273a703e490SVasu Dev 				skb_end_pointer(skb), skb->csum,
1274a703e490SVasu Dev 				skb->dev ? skb->dev->name : "<NULL>");
1275a703e490SVasu Dev 
1276a703e490SVasu Dev 		/*
1277a703e490SVasu Dev 		 * Save source MAC address before discarding header.
1278a703e490SVasu Dev 		 */
1279a703e490SVasu Dev 		fc = lport_priv(lp);
1280a703e490SVasu Dev 		if (skb_is_nonlinear(skb))
1281a703e490SVasu Dev 			skb_linearize(skb);	/* not ideal */
128297c8389dSJoe Eykholt 		mac = eth_hdr(skb)->h_source;
1283a703e490SVasu Dev 
1284a703e490SVasu Dev 		/*
1285a703e490SVasu Dev 		 * Frame length checks and setting up the header pointers
1286a703e490SVasu Dev 		 * was done in fcoe_rcv already.
1287a703e490SVasu Dev 		 */
1288a703e490SVasu Dev 		hp = (struct fcoe_hdr *) skb_network_header(skb);
1289a703e490SVasu Dev 		fh = (struct fc_frame_header *) skb_transport_header(skb);
1290a703e490SVasu Dev 
1291a703e490SVasu Dev 		stats = fc_lport_get_stats(lp);
1292a703e490SVasu Dev 		if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
1293a703e490SVasu Dev 			if (stats->ErrorFrames < 5)
1294d5488eb9SRobert Love 				printk(KERN_WARNING "fcoe: FCoE version "
1295a703e490SVasu Dev 				       "mismatch: The frame has "
1296a703e490SVasu Dev 				       "version %x, but the "
1297a703e490SVasu Dev 				       "initiator supports version "
1298a703e490SVasu Dev 				       "%x\n", FC_FCOE_DECAPS_VER(hp),
1299a703e490SVasu Dev 				       FC_FCOE_VER);
1300a703e490SVasu Dev 			stats->ErrorFrames++;
1301a703e490SVasu Dev 			kfree_skb(skb);
1302a703e490SVasu Dev 			continue;
1303a703e490SVasu Dev 		}
1304a703e490SVasu Dev 
1305a703e490SVasu Dev 		skb_pull(skb, sizeof(struct fcoe_hdr));
1306a703e490SVasu Dev 		fr_len = skb->len - sizeof(struct fcoe_crc_eof);
1307a703e490SVasu Dev 
1308a703e490SVasu Dev 		stats->RxFrames++;
1309a703e490SVasu Dev 		stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
1310a703e490SVasu Dev 
1311a703e490SVasu Dev 		fp = (struct fc_frame *)skb;
1312a703e490SVasu Dev 		fc_frame_init(fp);
1313a703e490SVasu Dev 		fr_dev(fp) = lp;
1314a703e490SVasu Dev 		fr_sof(fp) = hp->fcoe_sof;
1315a703e490SVasu Dev 
1316a703e490SVasu Dev 		/* Copy out the CRC and EOF trailer for access */
1317a703e490SVasu Dev 		if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) {
1318a703e490SVasu Dev 			kfree_skb(skb);
1319a703e490SVasu Dev 			continue;
1320a703e490SVasu Dev 		}
1321a703e490SVasu Dev 		fr_eof(fp) = crc_eof.fcoe_eof;
1322a703e490SVasu Dev 		fr_crc(fp) = crc_eof.fcoe_crc32;
1323a703e490SVasu Dev 		if (pskb_trim(skb, fr_len)) {
1324a703e490SVasu Dev 			kfree_skb(skb);
1325a703e490SVasu Dev 			continue;
1326a703e490SVasu Dev 		}
1327a703e490SVasu Dev 
1328a703e490SVasu Dev 		/*
1329a703e490SVasu Dev 		 * We only check CRC if no offload is available and if it is
1330a703e490SVasu Dev 		 * it's solicited data, in which case, the FCP layer would
1331a703e490SVasu Dev 		 * check it during the copy.
1332a703e490SVasu Dev 		 */
1333a703e490SVasu Dev 		if (lp->crc_offload && skb->ip_summed == CHECKSUM_UNNECESSARY)
1334a703e490SVasu Dev 			fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
1335a703e490SVasu Dev 		else
1336a703e490SVasu Dev 			fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
1337a703e490SVasu Dev 
1338a703e490SVasu Dev 		fh = fc_frame_header_get(fp);
1339a703e490SVasu Dev 		if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
1340a703e490SVasu Dev 		    fh->fh_type == FC_TYPE_FCP) {
134152ff878cSVasu Dev 			fc_exch_recv(lp, fp);
1342a703e490SVasu Dev 			continue;
1343a703e490SVasu Dev 		}
1344a703e490SVasu Dev 		if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
1345a703e490SVasu Dev 			if (le32_to_cpu(fr_crc(fp)) !=
1346a703e490SVasu Dev 			    ~crc32(~0, skb->data, fr_len)) {
1347d5488eb9SRobert Love 				if (stats->InvalidCRCCount < 5)
1348a703e490SVasu Dev 					printk(KERN_WARNING "fcoe: dropping "
1349a703e490SVasu Dev 					       "frame with CRC error\n");
1350a703e490SVasu Dev 				stats->InvalidCRCCount++;
1351a703e490SVasu Dev 				stats->ErrorFrames++;
1352a703e490SVasu Dev 				fc_frame_free(fp);
1353a703e490SVasu Dev 				continue;
1354a703e490SVasu Dev 			}
1355a703e490SVasu Dev 			fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
1356a703e490SVasu Dev 		}
135797c8389dSJoe Eykholt 		if (unlikely(fc->ctlr.flogi_oxid != FC_XID_UNKNOWN) &&
135897c8389dSJoe Eykholt 		    fcoe_ctlr_recv_flogi(&fc->ctlr, fp, mac)) {
135997c8389dSJoe Eykholt 			fc_frame_free(fp);
136097c8389dSJoe Eykholt 			continue;
136197c8389dSJoe Eykholt 		}
136252ff878cSVasu Dev 		fc_exch_recv(lp, fp);
1363a703e490SVasu Dev 	}
1364a703e490SVasu Dev 	return 0;
1365a703e490SVasu Dev }
1366a703e490SVasu Dev 
1367a703e490SVasu Dev /**
1368dd3fd72eSChris Leech  * fcoe_check_wait_queue() - attempt to clear the transmit backlog
1369dd3fd72eSChris Leech  * @lp: the fc_lport
1370a703e490SVasu Dev  *
1371a703e490SVasu Dev  * This empties the wait_queue, dequeue the head of the wait_queue queue
1372a703e490SVasu Dev  * and calls fcoe_start_io() for each packet, if all skb have been
1373a703e490SVasu Dev  * transmitted, return qlen or -1 if a error occurs, then restore
1374a703e490SVasu Dev  * wait_queue and try again later.
1375a703e490SVasu Dev  *
1376a703e490SVasu Dev  * The wait_queue is used when the skb transmit fails. skb will go
1377dd3fd72eSChris Leech  * in the wait_queue which will be emptied by the timer function or
1378a703e490SVasu Dev  * by the next skb transmit.
1379a703e490SVasu Dev  */
13804bb6b515SVasu Dev static void fcoe_check_wait_queue(struct fc_lport *lp, struct sk_buff *skb)
1381a703e490SVasu Dev {
1382a703e490SVasu Dev 	struct fcoe_softc *fc = lport_priv(lp);
13834bb6b515SVasu Dev 	int rc;
1384a703e490SVasu Dev 
1385a703e490SVasu Dev 	spin_lock_bh(&fc->fcoe_pending_queue.lock);
13864bb6b515SVasu Dev 
13874bb6b515SVasu Dev 	if (skb)
13884bb6b515SVasu Dev 		__skb_queue_tail(&fc->fcoe_pending_queue, skb);
13894bb6b515SVasu Dev 
1390a703e490SVasu Dev 	if (fc->fcoe_pending_queue_active)
1391a703e490SVasu Dev 		goto out;
1392a703e490SVasu Dev 	fc->fcoe_pending_queue_active = 1;
1393a703e490SVasu Dev 
1394a703e490SVasu Dev 	while (fc->fcoe_pending_queue.qlen) {
1395a703e490SVasu Dev 		/* keep qlen > 0 until fcoe_start_io succeeds */
1396a703e490SVasu Dev 		fc->fcoe_pending_queue.qlen++;
1397a703e490SVasu Dev 		skb = __skb_dequeue(&fc->fcoe_pending_queue);
1398a703e490SVasu Dev 
1399a703e490SVasu Dev 		spin_unlock_bh(&fc->fcoe_pending_queue.lock);
1400a703e490SVasu Dev 		rc = fcoe_start_io(skb);
1401a703e490SVasu Dev 		spin_lock_bh(&fc->fcoe_pending_queue.lock);
1402a703e490SVasu Dev 
1403a703e490SVasu Dev 		if (rc) {
1404a703e490SVasu Dev 			__skb_queue_head(&fc->fcoe_pending_queue, skb);
1405a703e490SVasu Dev 			/* undo temporary increment above */
1406a703e490SVasu Dev 			fc->fcoe_pending_queue.qlen--;
1407a703e490SVasu Dev 			break;
1408a703e490SVasu Dev 		}
1409a703e490SVasu Dev 		/* undo temporary increment above */
1410a703e490SVasu Dev 		fc->fcoe_pending_queue.qlen--;
1411a703e490SVasu Dev 	}
1412a703e490SVasu Dev 
1413a703e490SVasu Dev 	if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH)
1414a703e490SVasu Dev 		lp->qfull = 0;
14151047f221SVasu Dev 	if (fc->fcoe_pending_queue.qlen && !timer_pending(&fc->timer))
14161047f221SVasu Dev 		mod_timer(&fc->timer, jiffies + 2);
1417a703e490SVasu Dev 	fc->fcoe_pending_queue_active = 0;
1418a703e490SVasu Dev out:
14194bb6b515SVasu Dev 	if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
14204bb6b515SVasu Dev 		lp->qfull = 1;
1421a703e490SVasu Dev 	spin_unlock_bh(&fc->fcoe_pending_queue.lock);
14224bb6b515SVasu Dev 	return;
1423a703e490SVasu Dev }
1424a703e490SVasu Dev 
1425a703e490SVasu Dev /**
1426a703e490SVasu Dev  * fcoe_dev_setup() - setup link change notification interface
1427a703e490SVasu Dev  */
1428b0d428adSRandy Dunlap static void fcoe_dev_setup(void)
1429a703e490SVasu Dev {
1430a703e490SVasu Dev 	register_netdevice_notifier(&fcoe_notifier);
1431a703e490SVasu Dev }
1432a703e490SVasu Dev 
1433a703e490SVasu Dev /**
1434b0d428adSRandy Dunlap  * fcoe_dev_cleanup() - cleanup link change notification interface
1435a703e490SVasu Dev  */
1436a703e490SVasu Dev static void fcoe_dev_cleanup(void)
1437a703e490SVasu Dev {
1438a703e490SVasu Dev 	unregister_netdevice_notifier(&fcoe_notifier);
1439a703e490SVasu Dev }
1440a703e490SVasu Dev 
1441a703e490SVasu Dev /**
1442a703e490SVasu Dev  * fcoe_device_notification() - netdev event notification callback
1443a703e490SVasu Dev  * @notifier: context of the notification
1444a703e490SVasu Dev  * @event: type of event
1445a703e490SVasu Dev  * @ptr: fixed array for output parsed ifname
1446a703e490SVasu Dev  *
1447a703e490SVasu Dev  * This function is called by the ethernet driver in case of link change event
1448a703e490SVasu Dev  *
1449a703e490SVasu Dev  * Returns: 0 for success
1450a703e490SVasu Dev  */
1451a703e490SVasu Dev static int fcoe_device_notification(struct notifier_block *notifier,
1452a703e490SVasu Dev 				    ulong event, void *ptr)
1453a703e490SVasu Dev {
1454a703e490SVasu Dev 	struct fc_lport *lp = NULL;
14551d1b88dcSVasu Dev 	struct net_device *netdev = ptr;
1456a703e490SVasu Dev 	struct fcoe_softc *fc;
1457a703e490SVasu Dev 	struct fcoe_dev_stats *stats;
145897c8389dSJoe Eykholt 	u32 link_possible = 1;
1459a703e490SVasu Dev 	u32 mfs;
1460a703e490SVasu Dev 	int rc = NOTIFY_OK;
1461a703e490SVasu Dev 
1462a703e490SVasu Dev 	read_lock(&fcoe_hostlist_lock);
1463a703e490SVasu Dev 	list_for_each_entry(fc, &fcoe_hostlist, list) {
14641d1b88dcSVasu Dev 		if (fc->netdev == netdev) {
146597c8389dSJoe Eykholt 			lp = fc->ctlr.lp;
1466a703e490SVasu Dev 			break;
1467a703e490SVasu Dev 		}
1468a703e490SVasu Dev 	}
1469a703e490SVasu Dev 	read_unlock(&fcoe_hostlist_lock);
1470a703e490SVasu Dev 	if (lp == NULL) {
1471a703e490SVasu Dev 		rc = NOTIFY_DONE;
1472a703e490SVasu Dev 		goto out;
1473a703e490SVasu Dev 	}
1474a703e490SVasu Dev 
1475a703e490SVasu Dev 	switch (event) {
1476a703e490SVasu Dev 	case NETDEV_DOWN:
1477a703e490SVasu Dev 	case NETDEV_GOING_DOWN:
147897c8389dSJoe Eykholt 		link_possible = 0;
1479a703e490SVasu Dev 		break;
1480a703e490SVasu Dev 	case NETDEV_UP:
1481a703e490SVasu Dev 	case NETDEV_CHANGE:
1482a703e490SVasu Dev 		break;
1483a703e490SVasu Dev 	case NETDEV_CHANGEMTU:
14841d1b88dcSVasu Dev 		mfs = netdev->mtu - (sizeof(struct fcoe_hdr) +
1485a703e490SVasu Dev 				     sizeof(struct fcoe_crc_eof));
1486a703e490SVasu Dev 		if (mfs >= FC_MIN_MAX_FRAME)
1487a703e490SVasu Dev 			fc_set_mfs(lp, mfs);
1488a703e490SVasu Dev 		break;
1489a703e490SVasu Dev 	case NETDEV_REGISTER:
1490a703e490SVasu Dev 		break;
1491a703e490SVasu Dev 	default:
14921d1b88dcSVasu Dev 		FCOE_NETDEV_DBG(netdev, "Unknown event %ld "
1493d5488eb9SRobert Love 				"from netdev netlink\n", event);
1494a703e490SVasu Dev 	}
149597c8389dSJoe Eykholt 	if (link_possible && !fcoe_link_ok(lp))
149697c8389dSJoe Eykholt 		fcoe_ctlr_link_up(&fc->ctlr);
149797c8389dSJoe Eykholt 	else if (fcoe_ctlr_link_down(&fc->ctlr)) {
1498a703e490SVasu Dev 		stats = fc_lport_get_stats(lp);
1499a703e490SVasu Dev 		stats->LinkFailureCount++;
1500a703e490SVasu Dev 		fcoe_clean_pending_queue(lp);
1501a703e490SVasu Dev 	}
1502a703e490SVasu Dev out:
1503a703e490SVasu Dev 	return rc;
1504a703e490SVasu Dev }
1505a703e490SVasu Dev 
1506a703e490SVasu Dev /**
1507a703e490SVasu Dev  * fcoe_if_to_netdev() - parse a name buffer to get netdev
1508a703e490SVasu Dev  * @buffer: incoming buffer to be copied
1509a703e490SVasu Dev  *
1510dd3fd72eSChris Leech  * Returns: NULL or ptr to net_device
1511a703e490SVasu Dev  */
1512a703e490SVasu Dev static struct net_device *fcoe_if_to_netdev(const char *buffer)
1513a703e490SVasu Dev {
1514a703e490SVasu Dev 	char *cp;
1515a703e490SVasu Dev 	char ifname[IFNAMSIZ + 2];
1516a703e490SVasu Dev 
1517a703e490SVasu Dev 	if (buffer) {
1518a703e490SVasu Dev 		strlcpy(ifname, buffer, IFNAMSIZ);
1519a703e490SVasu Dev 		cp = ifname + strlen(ifname);
1520a703e490SVasu Dev 		while (--cp >= ifname && *cp == '\n')
1521a703e490SVasu Dev 			*cp = '\0';
1522a703e490SVasu Dev 		return dev_get_by_name(&init_net, ifname);
1523a703e490SVasu Dev 	}
1524a703e490SVasu Dev 	return NULL;
1525a703e490SVasu Dev }
1526a703e490SVasu Dev 
1527a703e490SVasu Dev /**
1528dd3fd72eSChris Leech  * fcoe_netdev_to_module_owner() - finds out the driver module of the netdev
1529a703e490SVasu Dev  * @netdev: the target netdev
1530a703e490SVasu Dev  *
1531a703e490SVasu Dev  * Returns: ptr to the struct module, NULL for failure
1532a703e490SVasu Dev  */
1533a703e490SVasu Dev static struct module *
1534a703e490SVasu Dev fcoe_netdev_to_module_owner(const struct net_device *netdev)
1535a703e490SVasu Dev {
1536a703e490SVasu Dev 	struct device *dev;
1537a703e490SVasu Dev 
1538a703e490SVasu Dev 	if (!netdev)
1539a703e490SVasu Dev 		return NULL;
1540a703e490SVasu Dev 
1541a703e490SVasu Dev 	dev = netdev->dev.parent;
1542a703e490SVasu Dev 	if (!dev)
1543a703e490SVasu Dev 		return NULL;
1544a703e490SVasu Dev 
1545a703e490SVasu Dev 	if (!dev->driver)
1546a703e490SVasu Dev 		return NULL;
1547a703e490SVasu Dev 
1548a703e490SVasu Dev 	return dev->driver->owner;
1549a703e490SVasu Dev }
1550a703e490SVasu Dev 
1551a703e490SVasu Dev /**
1552a703e490SVasu Dev  * fcoe_ethdrv_get() - Hold the Ethernet driver
1553a703e490SVasu Dev  * @netdev: the target netdev
1554a703e490SVasu Dev  *
1555a703e490SVasu Dev  * Holds the Ethernet driver module by try_module_get() for
1556a703e490SVasu Dev  * the corresponding netdev.
1557a703e490SVasu Dev  *
1558dd3fd72eSChris Leech  * Returns: 0 for success
1559a703e490SVasu Dev  */
1560a703e490SVasu Dev static int fcoe_ethdrv_get(const struct net_device *netdev)
1561a703e490SVasu Dev {
1562a703e490SVasu Dev 	struct module *owner;
1563a703e490SVasu Dev 
1564a703e490SVasu Dev 	owner = fcoe_netdev_to_module_owner(netdev);
1565a703e490SVasu Dev 	if (owner) {
1566d5488eb9SRobert Love 		FCOE_NETDEV_DBG(netdev, "Hold driver module %s\n",
1567d5488eb9SRobert Love 				module_name(owner));
1568a703e490SVasu Dev 		return  try_module_get(owner);
1569a703e490SVasu Dev 	}
1570a703e490SVasu Dev 	return -ENODEV;
1571a703e490SVasu Dev }
1572a703e490SVasu Dev 
1573a703e490SVasu Dev /**
1574a703e490SVasu Dev  * fcoe_ethdrv_put() - Release the Ethernet driver
1575a703e490SVasu Dev  * @netdev: the target netdev
1576a703e490SVasu Dev  *
1577a703e490SVasu Dev  * Releases the Ethernet driver module by module_put for
1578a703e490SVasu Dev  * the corresponding netdev.
1579a703e490SVasu Dev  *
1580dd3fd72eSChris Leech  * Returns: 0 for success
1581a703e490SVasu Dev  */
1582a703e490SVasu Dev static int fcoe_ethdrv_put(const struct net_device *netdev)
1583a703e490SVasu Dev {
1584a703e490SVasu Dev 	struct module *owner;
1585a703e490SVasu Dev 
1586a703e490SVasu Dev 	owner = fcoe_netdev_to_module_owner(netdev);
1587a703e490SVasu Dev 	if (owner) {
1588d5488eb9SRobert Love 		FCOE_NETDEV_DBG(netdev, "Release driver module %s\n",
1589d5488eb9SRobert Love 				module_name(owner));
1590a703e490SVasu Dev 		module_put(owner);
1591a703e490SVasu Dev 		return 0;
1592a703e490SVasu Dev 	}
1593a703e490SVasu Dev 	return -ENODEV;
1594a703e490SVasu Dev }
1595a703e490SVasu Dev 
1596a703e490SVasu Dev /**
1597a703e490SVasu Dev  * fcoe_destroy() - handles the destroy from sysfs
1598dd3fd72eSChris Leech  * @buffer: expected to be an eth if name
1599a703e490SVasu Dev  * @kp: associated kernel param
1600a703e490SVasu Dev  *
1601a703e490SVasu Dev  * Returns: 0 for success
1602a703e490SVasu Dev  */
1603a703e490SVasu Dev static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
1604a703e490SVasu Dev {
1605a703e490SVasu Dev 	struct net_device *netdev;
1606af7f85d9SChris Leech 	struct fc_lport *lport;
1607af7f85d9SChris Leech 	int rc;
1608a703e490SVasu Dev 
1609a703e490SVasu Dev 	netdev = fcoe_if_to_netdev(buffer);
1610a703e490SVasu Dev 	if (!netdev) {
1611a703e490SVasu Dev 		rc = -ENODEV;
1612a703e490SVasu Dev 		goto out_nodev;
1613a703e490SVasu Dev 	}
1614a703e490SVasu Dev 	/* look for existing lport */
1615af7f85d9SChris Leech 	lport = fcoe_hostlist_lookup(netdev);
1616af7f85d9SChris Leech 	if (!lport) {
1617a703e490SVasu Dev 		rc = -ENODEV;
1618a703e490SVasu Dev 		goto out_putdev;
1619a703e490SVasu Dev 	}
1620af7f85d9SChris Leech 	fcoe_if_destroy(lport);
1621a703e490SVasu Dev 	fcoe_ethdrv_put(netdev);
1622a703e490SVasu Dev 	rc = 0;
1623a703e490SVasu Dev out_putdev:
1624a703e490SVasu Dev 	dev_put(netdev);
1625a703e490SVasu Dev out_nodev:
1626a703e490SVasu Dev 	return rc;
1627a703e490SVasu Dev }
1628a703e490SVasu Dev 
1629a703e490SVasu Dev /**
1630a703e490SVasu Dev  * fcoe_create() - Handles the create call from sysfs
1631dd3fd72eSChris Leech  * @buffer: expected to be an eth if name
1632a703e490SVasu Dev  * @kp: associated kernel param
1633a703e490SVasu Dev  *
1634a703e490SVasu Dev  * Returns: 0 for success
1635a703e490SVasu Dev  */
1636a703e490SVasu Dev static int fcoe_create(const char *buffer, struct kernel_param *kp)
1637a703e490SVasu Dev {
1638a703e490SVasu Dev 	int rc;
1639af7f85d9SChris Leech 	struct fc_lport *lport;
1640a703e490SVasu Dev 	struct net_device *netdev;
1641a703e490SVasu Dev 
1642a703e490SVasu Dev 	netdev = fcoe_if_to_netdev(buffer);
1643a703e490SVasu Dev 	if (!netdev) {
1644a703e490SVasu Dev 		rc = -ENODEV;
1645a703e490SVasu Dev 		goto out_nodev;
1646a703e490SVasu Dev 	}
1647a703e490SVasu Dev 	/* look for existing lport */
1648a703e490SVasu Dev 	if (fcoe_hostlist_lookup(netdev)) {
1649a703e490SVasu Dev 		rc = -EEXIST;
1650a703e490SVasu Dev 		goto out_putdev;
1651a703e490SVasu Dev 	}
1652a703e490SVasu Dev 	fcoe_ethdrv_get(netdev);
1653a703e490SVasu Dev 
1654af7f85d9SChris Leech 	lport = fcoe_if_create(netdev, &netdev->dev);
1655af7f85d9SChris Leech 	if (IS_ERR(lport)) {
1656d5488eb9SRobert Love 		printk(KERN_ERR "fcoe: Failed to create interface (%s)\n",
1657a703e490SVasu Dev 		       netdev->name);
1658a703e490SVasu Dev 		fcoe_ethdrv_put(netdev);
1659a703e490SVasu Dev 		rc = -EIO;
1660a703e490SVasu Dev 		goto out_putdev;
1661a703e490SVasu Dev 	}
1662a703e490SVasu Dev 	rc = 0;
1663a703e490SVasu Dev out_putdev:
1664a703e490SVasu Dev 	dev_put(netdev);
1665a703e490SVasu Dev out_nodev:
1666a703e490SVasu Dev 	return rc;
1667a703e490SVasu Dev }
1668a703e490SVasu Dev 
1669a703e490SVasu Dev module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR);
1670a703e490SVasu Dev __MODULE_PARM_TYPE(create, "string");
1671a703e490SVasu Dev MODULE_PARM_DESC(create, "Create fcoe port using net device passed in.");
1672a703e490SVasu Dev module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR);
1673a703e490SVasu Dev __MODULE_PARM_TYPE(destroy, "string");
1674a703e490SVasu Dev MODULE_PARM_DESC(destroy, "Destroy fcoe port");
1675a703e490SVasu Dev 
1676a703e490SVasu Dev /**
1677a703e490SVasu Dev  * fcoe_link_ok() - Check if link is ok for the fc_lport
1678a703e490SVasu Dev  * @lp: ptr to the fc_lport
1679a703e490SVasu Dev  *
1680a703e490SVasu Dev  * Any permanently-disqualifying conditions have been previously checked.
1681a703e490SVasu Dev  * This also updates the speed setting, which may change with link for 100/1000.
1682a703e490SVasu Dev  *
1683a703e490SVasu Dev  * This function should probably be checking for PAUSE support at some point
1684a703e490SVasu Dev  * in the future. Currently Per-priority-pause is not determinable using
1685a703e490SVasu Dev  * ethtool, so we shouldn't be restrictive until that problem is resolved.
1686a703e490SVasu Dev  *
1687a703e490SVasu Dev  * Returns: 0 if link is OK for use by FCoE.
1688a703e490SVasu Dev  *
1689a703e490SVasu Dev  */
1690a703e490SVasu Dev int fcoe_link_ok(struct fc_lport *lp)
1691a703e490SVasu Dev {
1692a703e490SVasu Dev 	struct fcoe_softc *fc = lport_priv(lp);
16931d1b88dcSVasu Dev 	struct net_device *dev = fc->netdev;
1694a703e490SVasu Dev 	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
1695a703e490SVasu Dev 
16962f718d64SYi Zou 	if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
16972f718d64SYi Zou 	    (!dev_ethtool_get_settings(dev, &ecmd))) {
1698a703e490SVasu Dev 		lp->link_supported_speeds &=
1699a703e490SVasu Dev 			~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
1700a703e490SVasu Dev 		if (ecmd.supported & (SUPPORTED_1000baseT_Half |
1701a703e490SVasu Dev 				      SUPPORTED_1000baseT_Full))
1702a703e490SVasu Dev 			lp->link_supported_speeds |= FC_PORTSPEED_1GBIT;
1703a703e490SVasu Dev 		if (ecmd.supported & SUPPORTED_10000baseT_Full)
1704a703e490SVasu Dev 			lp->link_supported_speeds |=
1705a703e490SVasu Dev 				FC_PORTSPEED_10GBIT;
1706a703e490SVasu Dev 		if (ecmd.speed == SPEED_1000)
1707a703e490SVasu Dev 			lp->link_speed = FC_PORTSPEED_1GBIT;
1708a703e490SVasu Dev 		if (ecmd.speed == SPEED_10000)
1709a703e490SVasu Dev 			lp->link_speed = FC_PORTSPEED_10GBIT;
1710a703e490SVasu Dev 
17112f718d64SYi Zou 		return 0;
17122f718d64SYi Zou 	}
17132f718d64SYi Zou 	return -1;
1714a703e490SVasu Dev }
1715a703e490SVasu Dev 
1716a703e490SVasu Dev /**
1717a703e490SVasu Dev  * fcoe_percpu_clean() - Clear the pending skbs for an lport
1718a703e490SVasu Dev  * @lp: the fc_lport
1719a703e490SVasu Dev  */
1720a703e490SVasu Dev void fcoe_percpu_clean(struct fc_lport *lp)
1721a703e490SVasu Dev {
1722a703e490SVasu Dev 	struct fcoe_percpu_s *pp;
1723a703e490SVasu Dev 	struct fcoe_rcv_info *fr;
1724a703e490SVasu Dev 	struct sk_buff_head *list;
1725a703e490SVasu Dev 	struct sk_buff *skb, *next;
1726a703e490SVasu Dev 	struct sk_buff *head;
1727a703e490SVasu Dev 	unsigned int cpu;
1728a703e490SVasu Dev 
1729a703e490SVasu Dev 	for_each_possible_cpu(cpu) {
1730a703e490SVasu Dev 		pp = &per_cpu(fcoe_percpu, cpu);
1731a703e490SVasu Dev 		spin_lock_bh(&pp->fcoe_rx_list.lock);
1732a703e490SVasu Dev 		list = &pp->fcoe_rx_list;
1733a703e490SVasu Dev 		head = list->next;
1734a703e490SVasu Dev 		for (skb = head; skb != (struct sk_buff *)list;
1735a703e490SVasu Dev 		     skb = next) {
1736a703e490SVasu Dev 			next = skb->next;
1737a703e490SVasu Dev 			fr = fcoe_dev_from_skb(skb);
1738a703e490SVasu Dev 			if (fr->fr_dev == lp) {
1739a703e490SVasu Dev 				__skb_unlink(skb, list);
1740a703e490SVasu Dev 				kfree_skb(skb);
1741a703e490SVasu Dev 			}
1742a703e490SVasu Dev 		}
1743a703e490SVasu Dev 		spin_unlock_bh(&pp->fcoe_rx_list.lock);
1744a703e490SVasu Dev 	}
1745a703e490SVasu Dev }
1746a703e490SVasu Dev 
1747a703e490SVasu Dev /**
1748a703e490SVasu Dev  * fcoe_clean_pending_queue() - Dequeue a skb and free it
1749a703e490SVasu Dev  * @lp: the corresponding fc_lport
1750a703e490SVasu Dev  *
1751a703e490SVasu Dev  * Returns: none
1752a703e490SVasu Dev  */
1753a703e490SVasu Dev void fcoe_clean_pending_queue(struct fc_lport *lp)
1754a703e490SVasu Dev {
1755a703e490SVasu Dev 	struct fcoe_softc  *fc = lport_priv(lp);
1756a703e490SVasu Dev 	struct sk_buff *skb;
1757a703e490SVasu Dev 
1758a703e490SVasu Dev 	spin_lock_bh(&fc->fcoe_pending_queue.lock);
1759a703e490SVasu Dev 	while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) {
1760a703e490SVasu Dev 		spin_unlock_bh(&fc->fcoe_pending_queue.lock);
1761a703e490SVasu Dev 		kfree_skb(skb);
1762a703e490SVasu Dev 		spin_lock_bh(&fc->fcoe_pending_queue.lock);
1763a703e490SVasu Dev 	}
1764a703e490SVasu Dev 	spin_unlock_bh(&fc->fcoe_pending_queue.lock);
1765a703e490SVasu Dev }
1766a703e490SVasu Dev 
1767a703e490SVasu Dev /**
1768a703e490SVasu Dev  * fcoe_reset() - Resets the fcoe
1769a703e490SVasu Dev  * @shost: shost the reset is from
1770a703e490SVasu Dev  *
1771a703e490SVasu Dev  * Returns: always 0
1772a703e490SVasu Dev  */
1773a703e490SVasu Dev int fcoe_reset(struct Scsi_Host *shost)
1774a703e490SVasu Dev {
1775a703e490SVasu Dev 	struct fc_lport *lport = shost_priv(shost);
1776a703e490SVasu Dev 	fc_lport_reset(lport);
1777a703e490SVasu Dev 	return 0;
1778a703e490SVasu Dev }
1779a703e490SVasu Dev 
1780a703e490SVasu Dev /**
1781a703e490SVasu Dev  * fcoe_hostlist_lookup_softc() - find the corresponding lport by a given device
1782dd3fd72eSChris Leech  * @dev: this is currently ptr to net_device
1783a703e490SVasu Dev  *
1784e8af4d43SVasu Dev  * Called with fcoe_hostlist_lock held.
1785e8af4d43SVasu Dev  *
1786a703e490SVasu Dev  * Returns: NULL or the located fcoe_softc
1787a703e490SVasu Dev  */
1788a703e490SVasu Dev static struct fcoe_softc *
1789a703e490SVasu Dev fcoe_hostlist_lookup_softc(const struct net_device *dev)
1790a703e490SVasu Dev {
1791a703e490SVasu Dev 	struct fcoe_softc *fc;
1792a703e490SVasu Dev 
1793a703e490SVasu Dev 	list_for_each_entry(fc, &fcoe_hostlist, list) {
17941d1b88dcSVasu Dev 		if (fc->netdev == dev)
1795a703e490SVasu Dev 			return fc;
1796a703e490SVasu Dev 	}
1797a703e490SVasu Dev 	return NULL;
1798a703e490SVasu Dev }
1799a703e490SVasu Dev 
1800a703e490SVasu Dev /**
1801a703e490SVasu Dev  * fcoe_hostlist_lookup() - Find the corresponding lport by netdev
1802a703e490SVasu Dev  * @netdev: ptr to net_device
1803a703e490SVasu Dev  *
1804a703e490SVasu Dev  * Returns: 0 for success
1805a703e490SVasu Dev  */
1806a703e490SVasu Dev struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev)
1807a703e490SVasu Dev {
1808a703e490SVasu Dev 	struct fcoe_softc *fc;
1809a703e490SVasu Dev 
1810e8af4d43SVasu Dev 	read_lock(&fcoe_hostlist_lock);
1811a703e490SVasu Dev 	fc = fcoe_hostlist_lookup_softc(netdev);
1812e8af4d43SVasu Dev 	read_unlock(&fcoe_hostlist_lock);
1813a703e490SVasu Dev 
181497c8389dSJoe Eykholt 	return (fc) ? fc->ctlr.lp : NULL;
1815a703e490SVasu Dev }
1816a703e490SVasu Dev 
1817a703e490SVasu Dev /**
1818a703e490SVasu Dev  * fcoe_hostlist_add() - Add a lport to lports list
1819dd3fd72eSChris Leech  * @lp: ptr to the fc_lport to be added
1820a703e490SVasu Dev  *
1821e8af4d43SVasu Dev  * Called with write fcoe_hostlist_lock held.
1822e8af4d43SVasu Dev  *
1823a703e490SVasu Dev  * Returns: 0 for success
1824a703e490SVasu Dev  */
1825a703e490SVasu Dev int fcoe_hostlist_add(const struct fc_lport *lp)
1826a703e490SVasu Dev {
1827a703e490SVasu Dev 	struct fcoe_softc *fc;
1828a703e490SVasu Dev 
1829a703e490SVasu Dev 	fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp));
1830a703e490SVasu Dev 	if (!fc) {
1831a703e490SVasu Dev 		fc = lport_priv(lp);
1832a703e490SVasu Dev 		list_add_tail(&fc->list, &fcoe_hostlist);
1833a703e490SVasu Dev 	}
1834a703e490SVasu Dev 	return 0;
1835a703e490SVasu Dev }
1836a703e490SVasu Dev 
1837a703e490SVasu Dev /**
1838a703e490SVasu Dev  * fcoe_hostlist_remove() - remove a lport from lports list
1839dd3fd72eSChris Leech  * @lp: ptr to the fc_lport to be removed
1840a703e490SVasu Dev  *
1841a703e490SVasu Dev  * Returns: 0 for success
1842a703e490SVasu Dev  */
1843a703e490SVasu Dev int fcoe_hostlist_remove(const struct fc_lport *lp)
1844a703e490SVasu Dev {
1845a703e490SVasu Dev 	struct fcoe_softc *fc;
1846a703e490SVasu Dev 
1847e8af4d43SVasu Dev 	write_lock_bh(&fcoe_hostlist_lock);
1848a703e490SVasu Dev 	fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp));
1849a703e490SVasu Dev 	BUG_ON(!fc);
1850a703e490SVasu Dev 	list_del(&fc->list);
1851a703e490SVasu Dev 	write_unlock_bh(&fcoe_hostlist_lock);
1852a703e490SVasu Dev 
1853a703e490SVasu Dev 	return 0;
1854a703e490SVasu Dev }
1855a703e490SVasu Dev 
1856a703e490SVasu Dev /**
1857a703e490SVasu Dev  * fcoe_init() - fcoe module loading initialization
1858a703e490SVasu Dev  *
1859a703e490SVasu Dev  * Returns 0 on success, negative on failure
1860a703e490SVasu Dev  */
1861a703e490SVasu Dev static int __init fcoe_init(void)
1862a703e490SVasu Dev {
1863a703e490SVasu Dev 	unsigned int cpu;
1864a703e490SVasu Dev 	int rc = 0;
1865a703e490SVasu Dev 	struct fcoe_percpu_s *p;
1866a703e490SVasu Dev 
1867a703e490SVasu Dev 	for_each_possible_cpu(cpu) {
1868a703e490SVasu Dev 		p = &per_cpu(fcoe_percpu, cpu);
1869a703e490SVasu Dev 		skb_queue_head_init(&p->fcoe_rx_list);
1870a703e490SVasu Dev 	}
1871a703e490SVasu Dev 
1872a703e490SVasu Dev 	for_each_online_cpu(cpu)
1873a703e490SVasu Dev 		fcoe_percpu_thread_create(cpu);
1874a703e490SVasu Dev 
1875a703e490SVasu Dev 	/* Initialize per CPU interrupt thread */
1876a703e490SVasu Dev 	rc = register_hotcpu_notifier(&fcoe_cpu_notifier);
1877a703e490SVasu Dev 	if (rc)
1878a703e490SVasu Dev 		goto out_free;
1879a703e490SVasu Dev 
1880a703e490SVasu Dev 	/* Setup link change notification */
1881a703e490SVasu Dev 	fcoe_dev_setup();
1882a703e490SVasu Dev 
18835892c32fSChris Leech 	rc = fcoe_if_init();
18845892c32fSChris Leech 	if (rc)
18855892c32fSChris Leech 		goto out_free;
1886a703e490SVasu Dev 
1887a703e490SVasu Dev 	return 0;
1888a703e490SVasu Dev 
1889a703e490SVasu Dev out_free:
1890a703e490SVasu Dev 	for_each_online_cpu(cpu) {
1891a703e490SVasu Dev 		fcoe_percpu_thread_destroy(cpu);
1892a703e490SVasu Dev 	}
1893a703e490SVasu Dev 
1894a703e490SVasu Dev 	return rc;
1895a703e490SVasu Dev }
1896a703e490SVasu Dev module_init(fcoe_init);
1897a703e490SVasu Dev 
1898a703e490SVasu Dev /**
1899a703e490SVasu Dev  * fcoe_exit() - fcoe module unloading cleanup
1900a703e490SVasu Dev  *
1901a703e490SVasu Dev  * Returns 0 on success, negative on failure
1902a703e490SVasu Dev  */
1903a703e490SVasu Dev static void __exit fcoe_exit(void)
1904a703e490SVasu Dev {
1905a703e490SVasu Dev 	unsigned int cpu;
1906a703e490SVasu Dev 	struct fcoe_softc *fc, *tmp;
1907a703e490SVasu Dev 
1908a703e490SVasu Dev 	fcoe_dev_cleanup();
1909a703e490SVasu Dev 
1910a703e490SVasu Dev 	/* releases the associated fcoe hosts */
1911a703e490SVasu Dev 	list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list)
1912af7f85d9SChris Leech 		fcoe_if_destroy(fc->ctlr.lp);
1913a703e490SVasu Dev 
1914a703e490SVasu Dev 	unregister_hotcpu_notifier(&fcoe_cpu_notifier);
1915a703e490SVasu Dev 
1916a703e490SVasu Dev 	for_each_online_cpu(cpu) {
1917a703e490SVasu Dev 		fcoe_percpu_thread_destroy(cpu);
1918a703e490SVasu Dev 	}
1919a703e490SVasu Dev 
1920a703e490SVasu Dev 	/* detach from scsi transport */
1921a703e490SVasu Dev 	fcoe_if_exit();
1922a703e490SVasu Dev }
1923a703e490SVasu Dev module_exit(fcoe_exit);
1924