1fdecf31bSYi Zou /*
2fdecf31bSYi Zou  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
3fdecf31bSYi Zou  *
4fdecf31bSYi Zou  * This program is free software; you can redistribute it and/or modify it
5fdecf31bSYi Zou  * under the terms and conditions of the GNU General Public License,
6fdecf31bSYi Zou  * version 2, as published by the Free Software Foundation.
7fdecf31bSYi Zou  *
8fdecf31bSYi Zou  * This program is distributed in the hope it will be useful, but WITHOUT
9fdecf31bSYi Zou  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10fdecf31bSYi Zou  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11fdecf31bSYi Zou  * more details.
12fdecf31bSYi Zou  *
13fdecf31bSYi Zou  * You should have received a copy of the GNU General Public License along with
14fdecf31bSYi Zou  * this program; if not, write to the Free Software Foundation, Inc.,
15fdecf31bSYi Zou  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16fdecf31bSYi Zou  *
17fdecf31bSYi Zou  * Maintained at www.Open-FCoE.org
18fdecf31bSYi Zou  */
19fdecf31bSYi Zou 
20fdecf31bSYi Zou #include <linux/types.h>
21fdecf31bSYi Zou #include <linux/module.h>
22fdecf31bSYi Zou #include <linux/kernel.h>
23fdecf31bSYi Zou #include <linux/list.h>
24fdecf31bSYi Zou #include <linux/netdevice.h>
25fdecf31bSYi Zou #include <linux/errno.h>
26fdecf31bSYi Zou #include <scsi/libfcoe.h>
27fdecf31bSYi Zou 
28fdecf31bSYi Zou #include "libfcoe.h"
29fdecf31bSYi Zou 
30fdecf31bSYi Zou static int fcoe_transport_create(const char *, struct kernel_param *);
31fdecf31bSYi Zou static int fcoe_transport_destroy(const char *, struct kernel_param *);
32fdecf31bSYi Zou static int fcoe_transport_show(char *buffer, const struct kernel_param *kp);
33fdecf31bSYi Zou static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device);
34fdecf31bSYi Zou static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device);
35fdecf31bSYi Zou static int fcoe_transport_enable(const char *, struct kernel_param *);
36fdecf31bSYi Zou static int fcoe_transport_disable(const char *, struct kernel_param *);
37fdecf31bSYi Zou 
38fdecf31bSYi Zou static LIST_HEAD(fcoe_transports);
39fdecf31bSYi Zou static LIST_HEAD(fcoe_netdevs);
40fdecf31bSYi Zou static DEFINE_MUTEX(ft_mutex);
41fdecf31bSYi Zou 
42fdecf31bSYi Zou module_param_call(show, NULL, fcoe_transport_show, NULL, S_IRUSR);
43fdecf31bSYi Zou __MODULE_PARM_TYPE(show, "string");
44fdecf31bSYi Zou MODULE_PARM_DESC(show, " Show attached FCoE transports");
45fdecf31bSYi Zou 
46fdecf31bSYi Zou module_param_call(create, fcoe_transport_create, NULL,
47fdecf31bSYi Zou 		  (void *)FIP_MODE_FABRIC, S_IWUSR);
48fdecf31bSYi Zou __MODULE_PARM_TYPE(create, "string");
49fdecf31bSYi Zou MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface");
50fdecf31bSYi Zou 
51fdecf31bSYi Zou module_param_call(create_vn2vn, fcoe_transport_create, NULL,
52fdecf31bSYi Zou 		  (void *)FIP_MODE_VN2VN, S_IWUSR);
53fdecf31bSYi Zou __MODULE_PARM_TYPE(create_vn2vn, "string");
54fdecf31bSYi Zou MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance "
55fdecf31bSYi Zou 		 "on an Ethernet interface");
56fdecf31bSYi Zou 
57fdecf31bSYi Zou module_param_call(destroy, fcoe_transport_destroy, NULL, NULL, S_IWUSR);
58fdecf31bSYi Zou __MODULE_PARM_TYPE(destroy, "string");
59fdecf31bSYi Zou MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface");
60fdecf31bSYi Zou 
61fdecf31bSYi Zou module_param_call(enable, fcoe_transport_enable, NULL, NULL, S_IWUSR);
62fdecf31bSYi Zou __MODULE_PARM_TYPE(enable, "string");
63fdecf31bSYi Zou MODULE_PARM_DESC(enable, " Enables fcoe on a ethernet interface.");
64fdecf31bSYi Zou 
65fdecf31bSYi Zou module_param_call(disable, fcoe_transport_disable, NULL, NULL, S_IWUSR);
66fdecf31bSYi Zou __MODULE_PARM_TYPE(disable, "string");
67fdecf31bSYi Zou MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface.");
68fdecf31bSYi Zou 
69fdecf31bSYi Zou /**
70fdecf31bSYi Zou  * fcoe_transport_lookup - find an fcoe transport that matches a netdev
71fdecf31bSYi Zou  * @netdev: The netdev to look for from all attached transports
72fdecf31bSYi Zou  *
73fdecf31bSYi Zou  * Returns : ptr to the fcoe transport that supports this netdev or NULL
74fdecf31bSYi Zou  * if not found.
75fdecf31bSYi Zou  *
76fdecf31bSYi Zou  * The ft_mutex should be held when this is called
77fdecf31bSYi Zou  */
78fdecf31bSYi Zou static struct fcoe_transport *fcoe_transport_lookup(struct net_device *netdev)
79fdecf31bSYi Zou {
80fdecf31bSYi Zou 	struct fcoe_transport *ft = NULL;
81fdecf31bSYi Zou 
82fdecf31bSYi Zou 	list_for_each_entry(ft, &fcoe_transports, list)
83fdecf31bSYi Zou 		if (ft->match && ft->match(netdev))
84fdecf31bSYi Zou 			return ft;
85fdecf31bSYi Zou 	return NULL;
86fdecf31bSYi Zou }
87fdecf31bSYi Zou 
88fdecf31bSYi Zou /**
89fdecf31bSYi Zou  * fcoe_transport_attach - Attaches an FCoE transport
90fdecf31bSYi Zou  * @ft: The fcoe transport to be attached
91fdecf31bSYi Zou  *
92fdecf31bSYi Zou  * Returns : 0 for success
93fdecf31bSYi Zou  */
94fdecf31bSYi Zou int fcoe_transport_attach(struct fcoe_transport *ft)
95fdecf31bSYi Zou {
96fdecf31bSYi Zou 	int rc = 0;
97fdecf31bSYi Zou 
98fdecf31bSYi Zou 	mutex_lock(&ft_mutex);
99fdecf31bSYi Zou 	if (ft->attached) {
100fdecf31bSYi Zou 		LIBFCOE_TRANSPORT_DBG("transport %s already attached\n",
101fdecf31bSYi Zou 				       ft->name);
102fdecf31bSYi Zou 		rc = -EEXIST;
103fdecf31bSYi Zou 		goto out_attach;
104fdecf31bSYi Zou 	}
105fdecf31bSYi Zou 
106fdecf31bSYi Zou 	/* Add default transport to the tail */
107fdecf31bSYi Zou 	if (strcmp(ft->name, FCOE_TRANSPORT_DEFAULT))
108fdecf31bSYi Zou 		list_add(&ft->list, &fcoe_transports);
109fdecf31bSYi Zou 	else
110fdecf31bSYi Zou 		list_add_tail(&ft->list, &fcoe_transports);
111fdecf31bSYi Zou 
112fdecf31bSYi Zou 	ft->attached = true;
113fdecf31bSYi Zou 	LIBFCOE_TRANSPORT_DBG("attaching transport %s\n", ft->name);
114fdecf31bSYi Zou 
115fdecf31bSYi Zou out_attach:
116fdecf31bSYi Zou 	mutex_unlock(&ft_mutex);
117fdecf31bSYi Zou 	return rc;
118fdecf31bSYi Zou }
119fdecf31bSYi Zou EXPORT_SYMBOL(fcoe_transport_attach);
120fdecf31bSYi Zou 
121fdecf31bSYi Zou /**
122fdecf31bSYi Zou  * fcoe_transport_attach - Detaches an FCoE transport
123fdecf31bSYi Zou  * @ft: The fcoe transport to be attached
124fdecf31bSYi Zou  *
125fdecf31bSYi Zou  * Returns : 0 for success
126fdecf31bSYi Zou  */
127fdecf31bSYi Zou int fcoe_transport_detach(struct fcoe_transport *ft)
128fdecf31bSYi Zou {
129fdecf31bSYi Zou 	int rc = 0;
130fdecf31bSYi Zou 
131fdecf31bSYi Zou 	mutex_lock(&ft_mutex);
132fdecf31bSYi Zou 	if (!ft->attached) {
133fdecf31bSYi Zou 		LIBFCOE_TRANSPORT_DBG("transport %s already detached\n",
134fdecf31bSYi Zou 			ft->name);
135fdecf31bSYi Zou 		rc = -ENODEV;
136fdecf31bSYi Zou 		goto out_attach;
137fdecf31bSYi Zou 	}
138fdecf31bSYi Zou 
139fdecf31bSYi Zou 	list_del(&ft->list);
140fdecf31bSYi Zou 	ft->attached = false;
141fdecf31bSYi Zou 	LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name);
142fdecf31bSYi Zou 
143fdecf31bSYi Zou out_attach:
144fdecf31bSYi Zou 	mutex_unlock(&ft_mutex);
145fdecf31bSYi Zou 	return rc;
146fdecf31bSYi Zou 
147fdecf31bSYi Zou }
148fdecf31bSYi Zou EXPORT_SYMBOL(fcoe_transport_detach);
149fdecf31bSYi Zou 
150fdecf31bSYi Zou static int fcoe_transport_show(char *buffer, const struct kernel_param *kp)
151fdecf31bSYi Zou {
152fdecf31bSYi Zou 	int i, j;
153fdecf31bSYi Zou 	struct fcoe_transport *ft = NULL;
154fdecf31bSYi Zou 
155fdecf31bSYi Zou 	i = j = sprintf(buffer, "Attached FCoE transports:");
156fdecf31bSYi Zou 	mutex_lock(&ft_mutex);
157fdecf31bSYi Zou 	list_for_each_entry(ft, &fcoe_transports, list) {
158fdecf31bSYi Zou 		i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name);
159fdecf31bSYi Zou 		if (i >= PAGE_SIZE)
160fdecf31bSYi Zou 			break;
161fdecf31bSYi Zou 	}
162fdecf31bSYi Zou 	mutex_unlock(&ft_mutex);
163fdecf31bSYi Zou 	if (i == j)
164fdecf31bSYi Zou 		i += snprintf(&buffer[i], IFNAMSIZ, "none");
165fdecf31bSYi Zou 	return i;
166fdecf31bSYi Zou }
167fdecf31bSYi Zou 
168fdecf31bSYi Zou static int __init fcoe_transport_init(void)
169fdecf31bSYi Zou {
170fdecf31bSYi Zou 	return 0;
171fdecf31bSYi Zou }
172fdecf31bSYi Zou 
173fdecf31bSYi Zou static int __exit fcoe_transport_exit(void)
174fdecf31bSYi Zou {
175fdecf31bSYi Zou 	struct fcoe_transport *ft;
176fdecf31bSYi Zou 
177fdecf31bSYi Zou 	mutex_lock(&ft_mutex);
178fdecf31bSYi Zou 	list_for_each_entry(ft, &fcoe_transports, list)
179fdecf31bSYi Zou 		printk(KERN_ERR "FCoE transport %s is still attached!\n",
180fdecf31bSYi Zou 		      ft->name);
181fdecf31bSYi Zou 	mutex_unlock(&ft_mutex);
182fdecf31bSYi Zou 	return 0;
183fdecf31bSYi Zou }
184fdecf31bSYi Zou 
185fdecf31bSYi Zou 
186fdecf31bSYi Zou static int fcoe_add_netdev_mapping(struct net_device *netdev,
187fdecf31bSYi Zou 					struct fcoe_transport *ft)
188fdecf31bSYi Zou {
189fdecf31bSYi Zou 	struct fcoe_netdev_mapping *nm;
190fdecf31bSYi Zou 
191fdecf31bSYi Zou 	nm = kmalloc(sizeof(*nm), GFP_KERNEL);
192fdecf31bSYi Zou 	if (!nm) {
193fdecf31bSYi Zou 		printk(KERN_ERR "Unable to allocate netdev_mapping");
194fdecf31bSYi Zou 		return -ENOMEM;
195fdecf31bSYi Zou 	}
196fdecf31bSYi Zou 
197fdecf31bSYi Zou 	nm->netdev = netdev;
198fdecf31bSYi Zou 	nm->ft = ft;
199fdecf31bSYi Zou 
200fdecf31bSYi Zou 	list_add(&nm->list, &fcoe_netdevs);
201fdecf31bSYi Zou 	return 0;
202fdecf31bSYi Zou }
203fdecf31bSYi Zou 
204fdecf31bSYi Zou 
205fdecf31bSYi Zou static void fcoe_del_netdev_mapping(struct net_device *netdev)
206fdecf31bSYi Zou {
207fdecf31bSYi Zou 	struct fcoe_netdev_mapping *nm = NULL, *tmp;
208fdecf31bSYi Zou 
209fdecf31bSYi Zou 	list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) {
210fdecf31bSYi Zou 		if (nm->netdev == netdev) {
211fdecf31bSYi Zou 			list_del(&nm->list);
212fdecf31bSYi Zou 			kfree(nm);
213fdecf31bSYi Zou 			return;
214fdecf31bSYi Zou 		}
215fdecf31bSYi Zou 	}
216fdecf31bSYi Zou }
217fdecf31bSYi Zou 
218fdecf31bSYi Zou 
219fdecf31bSYi Zou /**
220fdecf31bSYi Zou  * fcoe_netdev_map_lookup - find the fcoe transport that matches the netdev on which
221fdecf31bSYi Zou  * it was created
222fdecf31bSYi Zou  *
223fdecf31bSYi Zou  * Returns : ptr to the fcoe transport that supports this netdev or NULL
224fdecf31bSYi Zou  * if not found.
225fdecf31bSYi Zou  *
226fdecf31bSYi Zou  * The ft_mutex should be held when this is called
227fdecf31bSYi Zou  */
228fdecf31bSYi Zou static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev)
229fdecf31bSYi Zou {
230fdecf31bSYi Zou 	struct fcoe_transport *ft = NULL;
231fdecf31bSYi Zou 	struct fcoe_netdev_mapping *nm;
232fdecf31bSYi Zou 
233fdecf31bSYi Zou 	list_for_each_entry(nm, &fcoe_netdevs, list) {
234fdecf31bSYi Zou 		if (netdev == nm->netdev) {
235fdecf31bSYi Zou 			ft = nm->ft;
236fdecf31bSYi Zou 			return ft;
237fdecf31bSYi Zou 		}
238fdecf31bSYi Zou 	}
239fdecf31bSYi Zou 
240fdecf31bSYi Zou 	return NULL;
241fdecf31bSYi Zou }
242fdecf31bSYi Zou 
243fdecf31bSYi Zou /**
244fdecf31bSYi Zou  * fcoe_if_to_netdev() - Parse a name buffer to get a net device
245fdecf31bSYi Zou  * @buffer: The name of the net device
246fdecf31bSYi Zou  *
247fdecf31bSYi Zou  * Returns: NULL or a ptr to net_device
248fdecf31bSYi Zou  */
249fdecf31bSYi Zou static struct net_device *fcoe_if_to_netdev(const char *buffer)
250fdecf31bSYi Zou {
251fdecf31bSYi Zou 	char *cp;
252fdecf31bSYi Zou 	char ifname[IFNAMSIZ + 2];
253fdecf31bSYi Zou 
254fdecf31bSYi Zou 	if (buffer) {
255fdecf31bSYi Zou 		strlcpy(ifname, buffer, IFNAMSIZ);
256fdecf31bSYi Zou 		cp = ifname + strlen(ifname);
257fdecf31bSYi Zou 		while (--cp >= ifname && *cp == '\n')
258fdecf31bSYi Zou 			*cp = '\0';
259fdecf31bSYi Zou 		return dev_get_by_name(&init_net, ifname);
260fdecf31bSYi Zou 	}
261fdecf31bSYi Zou 	return NULL;
262fdecf31bSYi Zou }
263fdecf31bSYi Zou 
264fdecf31bSYi Zou /**
265fdecf31bSYi Zou  * fcoe_transport_create() - Create a fcoe interface
266fdecf31bSYi Zou  * @buffer: The name of the Ethernet interface to create on
267fdecf31bSYi Zou  * @kp:	    The associated kernel param
268fdecf31bSYi Zou  *
269fdecf31bSYi Zou  * Called from sysfs. This holds the ft_mutex while calling the
270fdecf31bSYi Zou  * registered fcoe transport's create function.
271fdecf31bSYi Zou  *
272fdecf31bSYi Zou  * Returns: 0 for success
273fdecf31bSYi Zou  */
274fdecf31bSYi Zou static int fcoe_transport_create(const char *buffer, struct kernel_param *kp)
275fdecf31bSYi Zou {
276fdecf31bSYi Zou 	int rc = -ENODEV;
277fdecf31bSYi Zou 	struct net_device *netdev = NULL;
278fdecf31bSYi Zou 	struct fcoe_transport *ft = NULL;
279fdecf31bSYi Zou 	enum fip_state fip_mode = (enum fip_state)(long)kp->arg;
280fdecf31bSYi Zou 
281fdecf31bSYi Zou 	if (!mutex_trylock(&ft_mutex))
282fdecf31bSYi Zou 		return restart_syscall();
283fdecf31bSYi Zou 
284fdecf31bSYi Zou #ifdef CONFIG_LIBFCOE_MODULE
285fdecf31bSYi Zou 	/*
286fdecf31bSYi Zou 	 * Make sure the module has been initialized, and is not about to be
287fdecf31bSYi Zou 	 * removed.  Module parameter sysfs files are writable before the
288fdecf31bSYi Zou 	 * module_init function is called and after module_exit.
289fdecf31bSYi Zou 	 */
290fdecf31bSYi Zou 	if (THIS_MODULE->state != MODULE_STATE_LIVE)
291fdecf31bSYi Zou 		goto out_nodev;
292fdecf31bSYi Zou #endif
293fdecf31bSYi Zou 
294fdecf31bSYi Zou 	netdev = fcoe_if_to_netdev(buffer);
295fdecf31bSYi Zou 	if (!netdev) {
296fdecf31bSYi Zou 		LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buffer);
297fdecf31bSYi Zou 		goto out_nodev;
298fdecf31bSYi Zou 	}
299fdecf31bSYi Zou 
300fdecf31bSYi Zou 	ft = fcoe_netdev_map_lookup(netdev);
301fdecf31bSYi Zou 	if (ft) {
302fdecf31bSYi Zou 		LIBFCOE_TRANSPORT_DBG("transport %s already has existing "
303fdecf31bSYi Zou 				      "FCoE instance on %s.\n",
304fdecf31bSYi Zou 				      ft->name, netdev->name);
305fdecf31bSYi Zou 		rc = -EEXIST;
306fdecf31bSYi Zou 		goto out_putdev;
307fdecf31bSYi Zou 	}
308fdecf31bSYi Zou 
309fdecf31bSYi Zou 	ft = fcoe_transport_lookup(netdev);
310fdecf31bSYi Zou 	if (!ft) {
311fdecf31bSYi Zou 		LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
312fdecf31bSYi Zou 				      netdev->name);
313fdecf31bSYi Zou 		goto out_putdev;
314fdecf31bSYi Zou 	}
315fdecf31bSYi Zou 
316fdecf31bSYi Zou 	rc = fcoe_add_netdev_mapping(netdev, ft);
317fdecf31bSYi Zou 	if (rc) {
318fdecf31bSYi Zou 		LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping "
319fdecf31bSYi Zou 				      "for FCoE transport %s for %s.\n",
320fdecf31bSYi Zou 				      ft->name, netdev->name);
321fdecf31bSYi Zou 		goto out_putdev;
322fdecf31bSYi Zou 	}
323fdecf31bSYi Zou 
324fdecf31bSYi Zou 	/* pass to transport create */
325fdecf31bSYi Zou 	rc = ft->create ? ft->create(netdev, fip_mode) : -ENODEV;
326fdecf31bSYi Zou 	if (rc)
327fdecf31bSYi Zou 		fcoe_del_netdev_mapping(netdev);
328fdecf31bSYi Zou 
329fdecf31bSYi Zou 	LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n",
330fdecf31bSYi Zou 			      ft->name, (rc) ? "failed" : "succeeded",
331fdecf31bSYi Zou 			      netdev->name);
332fdecf31bSYi Zou 
333fdecf31bSYi Zou out_putdev:
334fdecf31bSYi Zou 	dev_put(netdev);
335fdecf31bSYi Zou out_nodev:
336fdecf31bSYi Zou 	mutex_unlock(&ft_mutex);
337fdecf31bSYi Zou 	if (rc == -ERESTARTSYS)
338fdecf31bSYi Zou 		return restart_syscall();
339fdecf31bSYi Zou 	else
340fdecf31bSYi Zou 		return rc;
341fdecf31bSYi Zou }
342fdecf31bSYi Zou 
343fdecf31bSYi Zou /**
344fdecf31bSYi Zou  * fcoe_transport_destroy() - Destroy a FCoE interface
345fdecf31bSYi Zou  * @buffer: The name of the Ethernet interface to be destroyed
346fdecf31bSYi Zou  * @kp:	    The associated kernel parameter
347fdecf31bSYi Zou  *
348fdecf31bSYi Zou  * Called from sysfs. This holds the ft_mutex while calling the
349fdecf31bSYi Zou  * registered fcoe transport's destroy function.
350fdecf31bSYi Zou  *
351fdecf31bSYi Zou  * Returns: 0 for success
352fdecf31bSYi Zou  */
353fdecf31bSYi Zou static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp)
354fdecf31bSYi Zou {
355fdecf31bSYi Zou 	int rc = -ENODEV;
356fdecf31bSYi Zou 	struct net_device *netdev = NULL;
357fdecf31bSYi Zou 	struct fcoe_transport *ft = NULL;
358fdecf31bSYi Zou 
359fdecf31bSYi Zou 	if (!mutex_trylock(&ft_mutex))
360fdecf31bSYi Zou 		return restart_syscall();
361fdecf31bSYi Zou 
362fdecf31bSYi Zou #ifdef CONFIG_LIBFCOE_MODULE
363fdecf31bSYi Zou 	/*
364fdecf31bSYi Zou 	 * Make sure the module has been initialized, and is not about to be
365fdecf31bSYi Zou 	 * removed.  Module parameter sysfs files are writable before the
366fdecf31bSYi Zou 	 * module_init function is called and after module_exit.
367fdecf31bSYi Zou 	 */
368fdecf31bSYi Zou 	if (THIS_MODULE->state != MODULE_STATE_LIVE)
369fdecf31bSYi Zou 		goto out_nodev;
370fdecf31bSYi Zou #endif
371fdecf31bSYi Zou 
372fdecf31bSYi Zou 	netdev = fcoe_if_to_netdev(buffer);
373fdecf31bSYi Zou 	if (!netdev) {
374fdecf31bSYi Zou 		LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buffer);
375fdecf31bSYi Zou 		goto out_nodev;
376fdecf31bSYi Zou 	}
377fdecf31bSYi Zou 
378fdecf31bSYi Zou 	ft = fcoe_netdev_map_lookup(netdev);
379fdecf31bSYi Zou 	if (!ft) {
380fdecf31bSYi Zou 		LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
381fdecf31bSYi Zou 				      netdev->name);
382fdecf31bSYi Zou 		goto out_putdev;
383fdecf31bSYi Zou 	}
384fdecf31bSYi Zou 
385fdecf31bSYi Zou 	/* pass to transport destroy */
386fdecf31bSYi Zou 	rc = ft->destroy ? ft->destroy(netdev) : -ENODEV;
387fdecf31bSYi Zou 	fcoe_del_netdev_mapping(netdev);
388fdecf31bSYi Zou 	LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n",
389fdecf31bSYi Zou 			      ft->name, (rc) ? "failed" : "succeeded",
390fdecf31bSYi Zou 			      netdev->name);
391fdecf31bSYi Zou 
392fdecf31bSYi Zou out_putdev:
393fdecf31bSYi Zou 	dev_put(netdev);
394fdecf31bSYi Zou out_nodev:
395fdecf31bSYi Zou 	mutex_unlock(&ft_mutex);
396fdecf31bSYi Zou 
397fdecf31bSYi Zou 	if (rc == -ERESTARTSYS)
398fdecf31bSYi Zou 		return restart_syscall();
399fdecf31bSYi Zou 	else
400fdecf31bSYi Zou 		return rc;
401fdecf31bSYi Zou }
402fdecf31bSYi Zou 
403fdecf31bSYi Zou /**
404fdecf31bSYi Zou  * fcoe_transport_disable() - Disables a FCoE interface
405fdecf31bSYi Zou  * @buffer: The name of the Ethernet interface to be disabled
406fdecf31bSYi Zou  * @kp:	    The associated kernel parameter
407fdecf31bSYi Zou  *
408fdecf31bSYi Zou  * Called from sysfs.
409fdecf31bSYi Zou  *
410fdecf31bSYi Zou  * Returns: 0 for success
411fdecf31bSYi Zou  */
412fdecf31bSYi Zou static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp)
413fdecf31bSYi Zou {
414fdecf31bSYi Zou 	int rc = -ENODEV;
415fdecf31bSYi Zou 	struct net_device *netdev = NULL;
416fdecf31bSYi Zou 	struct fcoe_transport *ft = NULL;
417fdecf31bSYi Zou 
418fdecf31bSYi Zou 	if (!mutex_trylock(&ft_mutex))
419fdecf31bSYi Zou 		return restart_syscall();
420fdecf31bSYi Zou 
421fdecf31bSYi Zou #ifdef CONFIG_LIBFCOE_MODULE
422fdecf31bSYi Zou 	/*
423fdecf31bSYi Zou 	 * Make sure the module has been initialized, and is not about to be
424fdecf31bSYi Zou 	 * removed.  Module parameter sysfs files are writable before the
425fdecf31bSYi Zou 	 * module_init function is called and after module_exit.
426fdecf31bSYi Zou 	 */
427fdecf31bSYi Zou 	if (THIS_MODULE->state != MODULE_STATE_LIVE)
428fdecf31bSYi Zou 		goto out_nodev;
429fdecf31bSYi Zou #endif
430fdecf31bSYi Zou 
431fdecf31bSYi Zou 	netdev = fcoe_if_to_netdev(buffer);
432fdecf31bSYi Zou 	if (!netdev)
433fdecf31bSYi Zou 		goto out_nodev;
434fdecf31bSYi Zou 
435fdecf31bSYi Zou 	ft = fcoe_netdev_map_lookup(netdev);
436fdecf31bSYi Zou 	if (!ft)
437fdecf31bSYi Zou 		goto out_putdev;
438fdecf31bSYi Zou 
439fdecf31bSYi Zou 	rc = ft->disable ? ft->disable(netdev) : -ENODEV;
440fdecf31bSYi Zou 
441fdecf31bSYi Zou out_putdev:
442fdecf31bSYi Zou 	dev_put(netdev);
443fdecf31bSYi Zou out_nodev:
444fdecf31bSYi Zou 	mutex_unlock(&ft_mutex);
445fdecf31bSYi Zou 
446fdecf31bSYi Zou 	if (rc == -ERESTARTSYS)
447fdecf31bSYi Zou 		return restart_syscall();
448fdecf31bSYi Zou 	else
449fdecf31bSYi Zou 		return rc;
450fdecf31bSYi Zou }
451fdecf31bSYi Zou 
452fdecf31bSYi Zou /**
453fdecf31bSYi Zou  * fcoe_transport_enable() - Enables a FCoE interface
454fdecf31bSYi Zou  * @buffer: The name of the Ethernet interface to be enabled
455fdecf31bSYi Zou  * @kp:     The associated kernel parameter
456fdecf31bSYi Zou  *
457fdecf31bSYi Zou  * Called from sysfs.
458fdecf31bSYi Zou  *
459fdecf31bSYi Zou  * Returns: 0 for success
460fdecf31bSYi Zou  */
461fdecf31bSYi Zou static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp)
462fdecf31bSYi Zou {
463fdecf31bSYi Zou 	int rc = -ENODEV;
464fdecf31bSYi Zou 	struct net_device *netdev = NULL;
465fdecf31bSYi Zou 	struct fcoe_transport *ft = NULL;
466fdecf31bSYi Zou 
467fdecf31bSYi Zou 	if (!mutex_trylock(&ft_mutex))
468fdecf31bSYi Zou 		return restart_syscall();
469fdecf31bSYi Zou 
470fdecf31bSYi Zou #ifdef CONFIG_LIBFCOE_MODULE
471fdecf31bSYi Zou 	/*
472fdecf31bSYi Zou 	 * Make sure the module has been initialized, and is not about to be
473fdecf31bSYi Zou 	 * removed.  Module parameter sysfs files are writable before the
474fdecf31bSYi Zou 	 * module_init function is called and after module_exit.
475fdecf31bSYi Zou 	 */
476fdecf31bSYi Zou 	if (THIS_MODULE->state != MODULE_STATE_LIVE)
477fdecf31bSYi Zou 		goto out_nodev;
478fdecf31bSYi Zou #endif
479fdecf31bSYi Zou 
480fdecf31bSYi Zou 	netdev = fcoe_if_to_netdev(buffer);
481fdecf31bSYi Zou 	if (!netdev)
482fdecf31bSYi Zou 		goto out_nodev;
483fdecf31bSYi Zou 
484fdecf31bSYi Zou 	ft = fcoe_netdev_map_lookup(netdev);
485fdecf31bSYi Zou 	if (!ft)
486fdecf31bSYi Zou 		goto out_putdev;
487fdecf31bSYi Zou 
488fdecf31bSYi Zou 	rc = ft->enable ? ft->enable(netdev) : -ENODEV;
489fdecf31bSYi Zou 
490fdecf31bSYi Zou out_putdev:
491fdecf31bSYi Zou 	dev_put(netdev);
492fdecf31bSYi Zou out_nodev:
493fdecf31bSYi Zou 	mutex_unlock(&ft_mutex);
494fdecf31bSYi Zou 	if (rc == -ERESTARTSYS)
495fdecf31bSYi Zou 		return restart_syscall();
496fdecf31bSYi Zou 	else
497fdecf31bSYi Zou 		return rc;
498fdecf31bSYi Zou }
499fdecf31bSYi Zou 
500fdecf31bSYi Zou /**
501fdecf31bSYi Zou  * libfcoe_init() - Initialization routine for libfcoe.ko
502fdecf31bSYi Zou  */
503fdecf31bSYi Zou static int __init libfcoe_init(void)
504fdecf31bSYi Zou {
505fdecf31bSYi Zou 	fcoe_transport_init();
506fdecf31bSYi Zou 
507fdecf31bSYi Zou 	return 0;
508fdecf31bSYi Zou }
509fdecf31bSYi Zou module_init(libfcoe_init);
510fdecf31bSYi Zou 
511fdecf31bSYi Zou /**
512fdecf31bSYi Zou  * libfcoe_exit() - Tear down libfcoe.ko
513fdecf31bSYi Zou  */
514fdecf31bSYi Zou static void __exit libfcoe_exit(void)
515fdecf31bSYi Zou {
516fdecf31bSYi Zou 	fcoe_transport_exit();
517fdecf31bSYi Zou }
518fdecf31bSYi Zou module_exit(libfcoe_exit);
519