]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/scsi/fcoe/fcoe_transport.c
Merge remote-tracking branch 'net/master'
[karo-tx-linux.git] / drivers / scsi / fcoe / fcoe_transport.c
1 /*
2  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16  *
17  * Maintained at www.Open-FCoE.org
18  */
19
20 #include <linux/types.h>
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <linux/list.h>
24 #include <linux/netdevice.h>
25 #include <linux/errno.h>
26 #include <linux/crc32.h>
27 #include <scsi/libfcoe.h>
28
29 #include "libfcoe.h"
30
31 MODULE_AUTHOR("Open-FCoE.org");
32 MODULE_DESCRIPTION("FIP discovery protocol and FCoE transport for FCoE HBAs");
33 MODULE_LICENSE("GPL v2");
34
35 static int fcoe_transport_create(const char *, struct kernel_param *);
36 static int fcoe_transport_destroy(const char *, struct kernel_param *);
37 static int fcoe_transport_show(char *buffer, const struct kernel_param *kp);
38 static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device);
39 static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device);
40 static int fcoe_transport_enable(const char *, struct kernel_param *);
41 static int fcoe_transport_disable(const char *, struct kernel_param *);
42 static int libfcoe_device_notification(struct notifier_block *notifier,
43                                     ulong event, void *ptr);
44
45 static LIST_HEAD(fcoe_transports);
46 static DEFINE_MUTEX(ft_mutex);
47 static LIST_HEAD(fcoe_netdevs);
48 static DEFINE_MUTEX(fn_mutex);
49
50 unsigned int libfcoe_debug_logging;
51 module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
52 MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
53
54 module_param_call(show, NULL, fcoe_transport_show, NULL, S_IRUSR);
55 __MODULE_PARM_TYPE(show, "string");
56 MODULE_PARM_DESC(show, " Show attached FCoE transports");
57
58 module_param_call(create, fcoe_transport_create, NULL,
59                   (void *)FIP_MODE_FABRIC, S_IWUSR);
60 __MODULE_PARM_TYPE(create, "string");
61 MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface");
62
63 module_param_call(create_vn2vn, fcoe_transport_create, NULL,
64                   (void *)FIP_MODE_VN2VN, S_IWUSR);
65 __MODULE_PARM_TYPE(create_vn2vn, "string");
66 MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance "
67                  "on an Ethernet interface");
68
69 module_param_call(destroy, fcoe_transport_destroy, NULL, NULL, S_IWUSR);
70 __MODULE_PARM_TYPE(destroy, "string");
71 MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface");
72
73 module_param_call(enable, fcoe_transport_enable, NULL, NULL, S_IWUSR);
74 __MODULE_PARM_TYPE(enable, "string");
75 MODULE_PARM_DESC(enable, " Enables fcoe on a ethernet interface.");
76
77 module_param_call(disable, fcoe_transport_disable, NULL, NULL, S_IWUSR);
78 __MODULE_PARM_TYPE(disable, "string");
79 MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface.");
80
81 /* notification function for packets from net device */
82 static struct notifier_block libfcoe_notifier = {
83         .notifier_call = libfcoe_device_notification,
84 };
85
86 void fcoe_wwn_to_str(u64 wwn, char *buf, int len)
87 {
88         u8 wwpn[8];
89
90         u64_to_wwn(wwn, wwpn);
91         snprintf(buf, len, "%02x%02x%02x%02x%02x%02x%02x%02x",
92                  wwpn[0], wwpn[1], wwpn[2], wwpn[3],
93                  wwpn[4], wwpn[5], wwpn[6], wwpn[7]);
94 }
95 EXPORT_SYMBOL_GPL(fcoe_wwn_to_str);
96
97 /**
98  * fcoe_validate_vport_create() - Validate a vport before creating it
99  * @vport: NPIV port to be created
100  *
101  * This routine is meant to add validation for a vport before creating it
102  * via fcoe_vport_create().
103  * Current validations are:
104  *      - WWPN supplied is unique for given lport
105  */
106 int fcoe_validate_vport_create(struct fc_vport *vport)
107 {
108         struct Scsi_Host *shost = vport_to_shost(vport);
109         struct fc_lport *n_port = shost_priv(shost);
110         struct fc_lport *vn_port;
111         int rc = 0;
112         char buf[32];
113
114         mutex_lock(&n_port->lp_mutex);
115
116         fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf));
117         /* Check if the wwpn is not same as that of the lport */
118         if (!memcmp(&n_port->wwpn, &vport->port_name, sizeof(u64))) {
119                 LIBFCOE_TRANSPORT_DBG("vport WWPN 0x%s is same as that of the "
120                                       "base port WWPN\n", buf);
121                 rc = -EINVAL;
122                 goto out;
123         }
124
125         /* Check if there is any existing vport with same wwpn */
126         list_for_each_entry(vn_port, &n_port->vports, list) {
127                 if (!memcmp(&vn_port->wwpn, &vport->port_name, sizeof(u64))) {
128                         LIBFCOE_TRANSPORT_DBG("vport with given WWPN 0x%s "
129                                               "already exists\n", buf);
130                         rc = -EINVAL;
131                         break;
132                 }
133         }
134 out:
135         mutex_unlock(&n_port->lp_mutex);
136         return rc;
137 }
138 EXPORT_SYMBOL_GPL(fcoe_validate_vport_create);
139
140 /**
141  * fcoe_get_wwn() - Get the world wide name from LLD if it supports it
142  * @netdev: the associated net device
143  * @wwn: the output WWN
144  * @type: the type of WWN (WWPN or WWNN)
145  *
146  * Returns: 0 for success
147  */
148 int fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type)
149 {
150         const struct net_device_ops *ops = netdev->netdev_ops;
151
152         if (ops->ndo_fcoe_get_wwn)
153                 return ops->ndo_fcoe_get_wwn(netdev, wwn, type);
154         return -EINVAL;
155 }
156 EXPORT_SYMBOL_GPL(fcoe_get_wwn);
157
158 /**
159  * fcoe_fc_crc() - Calculates the CRC for a given frame
160  * @fp: The frame to be checksumed
161  *
162  * This uses crc32() routine to calculate the CRC for a frame
163  *
164  * Return: The 32 bit CRC value
165  */
166 u32 fcoe_fc_crc(struct fc_frame *fp)
167 {
168         struct sk_buff *skb = fp_skb(fp);
169         struct skb_frag_struct *frag;
170         unsigned char *data;
171         unsigned long off, len, clen;
172         u32 crc;
173         unsigned i;
174
175         crc = crc32(~0, skb->data, skb_headlen(skb));
176
177         for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
178                 frag = &skb_shinfo(skb)->frags[i];
179                 off = frag->page_offset;
180                 len = frag->size;
181                 while (len > 0) {
182                         clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK));
183                         data = kmap_atomic(
184                                 skb_frag_page(frag) + (off >> PAGE_SHIFT),
185                                 KM_SKB_DATA_SOFTIRQ);
186                         crc = crc32(crc, data + (off & ~PAGE_MASK), clen);
187                         kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ);
188                         off += clen;
189                         len -= clen;
190                 }
191         }
192         return crc;
193 }
194 EXPORT_SYMBOL_GPL(fcoe_fc_crc);
195
196 /**
197  * fcoe_start_io() - Start FCoE I/O
198  * @skb: The packet to be transmitted
199  *
200  * This routine is called from the net device to start transmitting
201  * FCoE packets.
202  *
203  * Returns: 0 for success
204  */
205 int fcoe_start_io(struct sk_buff *skb)
206 {
207         struct sk_buff *nskb;
208         int rc;
209
210         nskb = skb_clone(skb, GFP_ATOMIC);
211         if (!nskb)
212                 return -ENOMEM;
213         rc = dev_queue_xmit(nskb);
214         if (rc != 0)
215                 return rc;
216         kfree_skb(skb);
217         return 0;
218 }
219 EXPORT_SYMBOL_GPL(fcoe_start_io);
220
221
222 /**
223  * fcoe_clean_pending_queue() - Dequeue a skb and free it
224  * @lport: The local port to dequeue a skb on
225  */
226 void fcoe_clean_pending_queue(struct fc_lport *lport)
227 {
228         struct fcoe_port  *port = lport_priv(lport);
229         struct sk_buff *skb;
230
231         spin_lock_bh(&port->fcoe_pending_queue.lock);
232         while ((skb = __skb_dequeue(&port->fcoe_pending_queue)) != NULL) {
233                 spin_unlock_bh(&port->fcoe_pending_queue.lock);
234                 kfree_skb(skb);
235                 spin_lock_bh(&port->fcoe_pending_queue.lock);
236         }
237         spin_unlock_bh(&port->fcoe_pending_queue.lock);
238 }
239 EXPORT_SYMBOL_GPL(fcoe_clean_pending_queue);
240
241 /**
242  * fcoe_check_wait_queue() - Attempt to clear the transmit backlog
243  * @lport: The local port whose backlog is to be cleared
244  *
245  * This empties the wait_queue, dequeues the head of the wait_queue queue
246  * and calls fcoe_start_io() for each packet. If all skb have been
247  * transmitted it returns the qlen. If an error occurs it restores
248  * wait_queue (to try again later) and returns -1.
249  *
250  * The wait_queue is used when the skb transmit fails. The failed skb
251  * will go in the wait_queue which will be emptied by the timer function or
252  * by the next skb transmit.
253  */
254 void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb)
255 {
256         struct fcoe_port *port = lport_priv(lport);
257         int rc;
258
259         spin_lock_bh(&port->fcoe_pending_queue.lock);
260
261         if (skb)
262                 __skb_queue_tail(&port->fcoe_pending_queue, skb);
263
264         if (port->fcoe_pending_queue_active)
265                 goto out;
266         port->fcoe_pending_queue_active = 1;
267
268         while (port->fcoe_pending_queue.qlen) {
269                 /* keep qlen > 0 until fcoe_start_io succeeds */
270                 port->fcoe_pending_queue.qlen++;
271                 skb = __skb_dequeue(&port->fcoe_pending_queue);
272
273                 spin_unlock_bh(&port->fcoe_pending_queue.lock);
274                 rc = fcoe_start_io(skb);
275                 spin_lock_bh(&port->fcoe_pending_queue.lock);
276
277                 if (rc) {
278                         __skb_queue_head(&port->fcoe_pending_queue, skb);
279                         /* undo temporary increment above */
280                         port->fcoe_pending_queue.qlen--;
281                         break;
282                 }
283                 /* undo temporary increment above */
284                 port->fcoe_pending_queue.qlen--;
285         }
286
287         if (port->fcoe_pending_queue.qlen < port->min_queue_depth)
288                 lport->qfull = 0;
289         if (port->fcoe_pending_queue.qlen && !timer_pending(&port->timer))
290                 mod_timer(&port->timer, jiffies + 2);
291         port->fcoe_pending_queue_active = 0;
292 out:
293         if (port->fcoe_pending_queue.qlen > port->max_queue_depth)
294                 lport->qfull = 1;
295         spin_unlock_bh(&port->fcoe_pending_queue.lock);
296 }
297 EXPORT_SYMBOL_GPL(fcoe_check_wait_queue);
298
299 /**
300  * fcoe_queue_timer() - The fcoe queue timer
301  * @lport: The local port
302  *
303  * Calls fcoe_check_wait_queue on timeout
304  */
305 void fcoe_queue_timer(ulong lport)
306 {
307         fcoe_check_wait_queue((struct fc_lport *)lport, NULL);
308 }
309 EXPORT_SYMBOL_GPL(fcoe_queue_timer);
310
311 /**
312  * fcoe_get_paged_crc_eof() - Allocate a page to be used for the trailer CRC
313  * @skb:  The packet to be transmitted
314  * @tlen: The total length of the trailer
315  * @fps:  The fcoe context
316  *
317  * This routine allocates a page for frame trailers. The page is re-used if
318  * there is enough room left on it for the current trailer. If there isn't
319  * enough buffer left a new page is allocated for the trailer. Reference to
320  * the page from this function as well as the skbs using the page fragments
321  * ensure that the page is freed at the appropriate time.
322  *
323  * Returns: 0 for success
324  */
325 int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen,
326                            struct fcoe_percpu_s *fps)
327 {
328         struct page *page;
329
330         page = fps->crc_eof_page;
331         if (!page) {
332                 page = alloc_page(GFP_ATOMIC);
333                 if (!page)
334                         return -ENOMEM;
335
336                 fps->crc_eof_page = page;
337                 fps->crc_eof_offset = 0;
338         }
339
340         get_page(page);
341         skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page,
342                            fps->crc_eof_offset, tlen);
343         skb->len += tlen;
344         skb->data_len += tlen;
345         skb->truesize += tlen;
346         fps->crc_eof_offset += sizeof(struct fcoe_crc_eof);
347
348         if (fps->crc_eof_offset >= PAGE_SIZE) {
349                 fps->crc_eof_page = NULL;
350                 fps->crc_eof_offset = 0;
351                 put_page(page);
352         }
353
354         return 0;
355 }
356 EXPORT_SYMBOL_GPL(fcoe_get_paged_crc_eof);
357
358 /**
359  * fcoe_transport_lookup - find an fcoe transport that matches a netdev
360  * @netdev: The netdev to look for from all attached transports
361  *
362  * Returns : ptr to the fcoe transport that supports this netdev or NULL
363  * if not found.
364  *
365  * The ft_mutex should be held when this is called
366  */
367 static struct fcoe_transport *fcoe_transport_lookup(struct net_device *netdev)
368 {
369         struct fcoe_transport *ft = NULL;
370
371         list_for_each_entry(ft, &fcoe_transports, list)
372                 if (ft->match && ft->match(netdev))
373                         return ft;
374         return NULL;
375 }
376
377 /**
378  * fcoe_transport_attach - Attaches an FCoE transport
379  * @ft: The fcoe transport to be attached
380  *
381  * Returns : 0 for success
382  */
383 int fcoe_transport_attach(struct fcoe_transport *ft)
384 {
385         int rc = 0;
386
387         mutex_lock(&ft_mutex);
388         if (ft->attached) {
389                 LIBFCOE_TRANSPORT_DBG("transport %s already attached\n",
390                                        ft->name);
391                 rc = -EEXIST;
392                 goto out_attach;
393         }
394
395         /* Add default transport to the tail */
396         if (strcmp(ft->name, FCOE_TRANSPORT_DEFAULT))
397                 list_add(&ft->list, &fcoe_transports);
398         else
399                 list_add_tail(&ft->list, &fcoe_transports);
400
401         ft->attached = true;
402         LIBFCOE_TRANSPORT_DBG("attaching transport %s\n", ft->name);
403
404 out_attach:
405         mutex_unlock(&ft_mutex);
406         return rc;
407 }
408 EXPORT_SYMBOL(fcoe_transport_attach);
409
410 /**
411  * fcoe_transport_detach - Detaches an FCoE transport
412  * @ft: The fcoe transport to be attached
413  *
414  * Returns : 0 for success
415  */
416 int fcoe_transport_detach(struct fcoe_transport *ft)
417 {
418         int rc = 0;
419         struct fcoe_netdev_mapping *nm = NULL, *tmp;
420
421         mutex_lock(&ft_mutex);
422         if (!ft->attached) {
423                 LIBFCOE_TRANSPORT_DBG("transport %s already detached\n",
424                         ft->name);
425                 rc = -ENODEV;
426                 goto out_attach;
427         }
428
429         /* remove netdev mapping for this transport as it is going away */
430         mutex_lock(&fn_mutex);
431         list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) {
432                 if (nm->ft == ft) {
433                         LIBFCOE_TRANSPORT_DBG("transport %s going away, "
434                                 "remove its netdev mapping for %s\n",
435                                 ft->name, nm->netdev->name);
436                         list_del(&nm->list);
437                         kfree(nm);
438                 }
439         }
440         mutex_unlock(&fn_mutex);
441
442         list_del(&ft->list);
443         ft->attached = false;
444         LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name);
445
446 out_attach:
447         mutex_unlock(&ft_mutex);
448         return rc;
449
450 }
451 EXPORT_SYMBOL(fcoe_transport_detach);
452
453 static int fcoe_transport_show(char *buffer, const struct kernel_param *kp)
454 {
455         int i, j;
456         struct fcoe_transport *ft = NULL;
457
458         i = j = sprintf(buffer, "Attached FCoE transports:");
459         mutex_lock(&ft_mutex);
460         list_for_each_entry(ft, &fcoe_transports, list) {
461                 if (i >= PAGE_SIZE - IFNAMSIZ)
462                         break;
463                 i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name);
464         }
465         mutex_unlock(&ft_mutex);
466         if (i == j)
467                 i += snprintf(&buffer[i], IFNAMSIZ, "none");
468         return i;
469 }
470
471 static int __init fcoe_transport_init(void)
472 {
473         register_netdevice_notifier(&libfcoe_notifier);
474         return 0;
475 }
476
477 static int __exit fcoe_transport_exit(void)
478 {
479         struct fcoe_transport *ft;
480
481         unregister_netdevice_notifier(&libfcoe_notifier);
482         mutex_lock(&ft_mutex);
483         list_for_each_entry(ft, &fcoe_transports, list)
484                 printk(KERN_ERR "FCoE transport %s is still attached!\n",
485                       ft->name);
486         mutex_unlock(&ft_mutex);
487         return 0;
488 }
489
490
491 static int fcoe_add_netdev_mapping(struct net_device *netdev,
492                                         struct fcoe_transport *ft)
493 {
494         struct fcoe_netdev_mapping *nm;
495
496         nm = kmalloc(sizeof(*nm), GFP_KERNEL);
497         if (!nm) {
498                 printk(KERN_ERR "Unable to allocate netdev_mapping");
499                 return -ENOMEM;
500         }
501
502         nm->netdev = netdev;
503         nm->ft = ft;
504
505         mutex_lock(&fn_mutex);
506         list_add(&nm->list, &fcoe_netdevs);
507         mutex_unlock(&fn_mutex);
508         return 0;
509 }
510
511
512 static void fcoe_del_netdev_mapping(struct net_device *netdev)
513 {
514         struct fcoe_netdev_mapping *nm = NULL, *tmp;
515
516         mutex_lock(&fn_mutex);
517         list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) {
518                 if (nm->netdev == netdev) {
519                         list_del(&nm->list);
520                         kfree(nm);
521                         mutex_unlock(&fn_mutex);
522                         return;
523                 }
524         }
525         mutex_unlock(&fn_mutex);
526 }
527
528
529 /**
530  * fcoe_netdev_map_lookup - find the fcoe transport that matches the netdev on which
531  * it was created
532  *
533  * Returns : ptr to the fcoe transport that supports this netdev or NULL
534  * if not found.
535  *
536  * The ft_mutex should be held when this is called
537  */
538 static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev)
539 {
540         struct fcoe_transport *ft = NULL;
541         struct fcoe_netdev_mapping *nm;
542
543         mutex_lock(&fn_mutex);
544         list_for_each_entry(nm, &fcoe_netdevs, list) {
545                 if (netdev == nm->netdev) {
546                         ft = nm->ft;
547                         mutex_unlock(&fn_mutex);
548                         return ft;
549                 }
550         }
551
552         mutex_unlock(&fn_mutex);
553         return NULL;
554 }
555
556 /**
557  * fcoe_if_to_netdev() - Parse a name buffer to get a net device
558  * @buffer: The name of the net device
559  *
560  * Returns: NULL or a ptr to net_device
561  */
562 static struct net_device *fcoe_if_to_netdev(const char *buffer)
563 {
564         char *cp;
565         char ifname[IFNAMSIZ + 2];
566
567         if (buffer) {
568                 strlcpy(ifname, buffer, IFNAMSIZ);
569                 cp = ifname + strlen(ifname);
570                 while (--cp >= ifname && *cp == '\n')
571                         *cp = '\0';
572                 return dev_get_by_name(&init_net, ifname);
573         }
574         return NULL;
575 }
576
577 /**
578  * libfcoe_device_notification() - Handler for net device events
579  * @notifier: The context of the notification
580  * @event:    The type of event
581  * @ptr:      The net device that the event was on
582  *
583  * This function is called by the Ethernet driver in case of link change event.
584  *
585  * Returns: 0 for success
586  */
587 static int libfcoe_device_notification(struct notifier_block *notifier,
588                                     ulong event, void *ptr)
589 {
590         struct net_device *netdev = ptr;
591
592         switch (event) {
593         case NETDEV_UNREGISTER:
594                 printk(KERN_ERR "libfcoe_device_notification: NETDEV_UNREGISTER %s\n",
595                                 netdev->name);
596                 fcoe_del_netdev_mapping(netdev);
597                 break;
598         }
599         return NOTIFY_OK;
600 }
601
602
603 /**
604  * fcoe_transport_create() - Create a fcoe interface
605  * @buffer: The name of the Ethernet interface to create on
606  * @kp:     The associated kernel param
607  *
608  * Called from sysfs. This holds the ft_mutex while calling the
609  * registered fcoe transport's create function.
610  *
611  * Returns: 0 for success
612  */
613 static int fcoe_transport_create(const char *buffer, struct kernel_param *kp)
614 {
615         int rc = -ENODEV;
616         struct net_device *netdev = NULL;
617         struct fcoe_transport *ft = NULL;
618         enum fip_state fip_mode = (enum fip_state)(long)kp->arg;
619
620         mutex_lock(&ft_mutex);
621
622         netdev = fcoe_if_to_netdev(buffer);
623         if (!netdev) {
624                 LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buffer);
625                 goto out_nodev;
626         }
627
628         ft = fcoe_netdev_map_lookup(netdev);
629         if (ft) {
630                 LIBFCOE_TRANSPORT_DBG("transport %s already has existing "
631                                       "FCoE instance on %s.\n",
632                                       ft->name, netdev->name);
633                 rc = -EEXIST;
634                 goto out_putdev;
635         }
636
637         ft = fcoe_transport_lookup(netdev);
638         if (!ft) {
639                 LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
640                                       netdev->name);
641                 goto out_putdev;
642         }
643
644         rc = fcoe_add_netdev_mapping(netdev, ft);
645         if (rc) {
646                 LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping "
647                                       "for FCoE transport %s for %s.\n",
648                                       ft->name, netdev->name);
649                 goto out_putdev;
650         }
651
652         /* pass to transport create */
653         rc = ft->create ? ft->create(netdev, fip_mode) : -ENODEV;
654         if (rc)
655                 fcoe_del_netdev_mapping(netdev);
656
657         LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n",
658                               ft->name, (rc) ? "failed" : "succeeded",
659                               netdev->name);
660
661 out_putdev:
662         dev_put(netdev);
663 out_nodev:
664         mutex_unlock(&ft_mutex);
665         return rc;
666 }
667
668 /**
669  * fcoe_transport_destroy() - Destroy a FCoE interface
670  * @buffer: The name of the Ethernet interface to be destroyed
671  * @kp:     The associated kernel parameter
672  *
673  * Called from sysfs. This holds the ft_mutex while calling the
674  * registered fcoe transport's destroy function.
675  *
676  * Returns: 0 for success
677  */
678 static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp)
679 {
680         int rc = -ENODEV;
681         struct net_device *netdev = NULL;
682         struct fcoe_transport *ft = NULL;
683
684         mutex_lock(&ft_mutex);
685
686         netdev = fcoe_if_to_netdev(buffer);
687         if (!netdev) {
688                 LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buffer);
689                 goto out_nodev;
690         }
691
692         ft = fcoe_netdev_map_lookup(netdev);
693         if (!ft) {
694                 LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
695                                       netdev->name);
696                 goto out_putdev;
697         }
698
699         /* pass to transport destroy */
700         rc = ft->destroy ? ft->destroy(netdev) : -ENODEV;
701         fcoe_del_netdev_mapping(netdev);
702         LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n",
703                               ft->name, (rc) ? "failed" : "succeeded",
704                               netdev->name);
705
706 out_putdev:
707         dev_put(netdev);
708 out_nodev:
709         mutex_unlock(&ft_mutex);
710         return rc;
711 }
712
713 /**
714  * fcoe_transport_disable() - Disables a FCoE interface
715  * @buffer: The name of the Ethernet interface to be disabled
716  * @kp:     The associated kernel parameter
717  *
718  * Called from sysfs.
719  *
720  * Returns: 0 for success
721  */
722 static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp)
723 {
724         int rc = -ENODEV;
725         struct net_device *netdev = NULL;
726         struct fcoe_transport *ft = NULL;
727
728         mutex_lock(&ft_mutex);
729
730         netdev = fcoe_if_to_netdev(buffer);
731         if (!netdev)
732                 goto out_nodev;
733
734         ft = fcoe_netdev_map_lookup(netdev);
735         if (!ft)
736                 goto out_putdev;
737
738         rc = ft->disable ? ft->disable(netdev) : -ENODEV;
739
740 out_putdev:
741         dev_put(netdev);
742 out_nodev:
743         mutex_unlock(&ft_mutex);
744
745         if (rc == -ERESTARTSYS)
746                 return restart_syscall();
747         else
748                 return rc;
749 }
750
751 /**
752  * fcoe_transport_enable() - Enables a FCoE interface
753  * @buffer: The name of the Ethernet interface to be enabled
754  * @kp:     The associated kernel parameter
755  *
756  * Called from sysfs.
757  *
758  * Returns: 0 for success
759  */
760 static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp)
761 {
762         int rc = -ENODEV;
763         struct net_device *netdev = NULL;
764         struct fcoe_transport *ft = NULL;
765
766         mutex_lock(&ft_mutex);
767
768         netdev = fcoe_if_to_netdev(buffer);
769         if (!netdev)
770                 goto out_nodev;
771
772         ft = fcoe_netdev_map_lookup(netdev);
773         if (!ft)
774                 goto out_putdev;
775
776         rc = ft->enable ? ft->enable(netdev) : -ENODEV;
777
778 out_putdev:
779         dev_put(netdev);
780 out_nodev:
781         mutex_unlock(&ft_mutex);
782         return rc;
783 }
784
785 /**
786  * libfcoe_init() - Initialization routine for libfcoe.ko
787  */
788 static int __init libfcoe_init(void)
789 {
790         fcoe_transport_init();
791
792         return 0;
793 }
794 module_init(libfcoe_init);
795
796 /**
797  * libfcoe_exit() - Tear down libfcoe.ko
798  */
799 static void __exit libfcoe_exit(void)
800 {
801         fcoe_transport_exit();
802 }
803 module_exit(libfcoe_exit);