1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
31MODULE_AUTHOR("Open-FCoE.org");
32MODULE_DESCRIPTION("FIP discovery protocol and FCoE transport for FCoE HBAs");
33MODULE_LICENSE("GPL v2");
34
35static int fcoe_transport_create(const char *, struct kernel_param *);
36static int fcoe_transport_destroy(const char *, struct kernel_param *);
37static int fcoe_transport_show(char *buffer, const struct kernel_param *kp);
38static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device);
39static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device);
40static int fcoe_transport_enable(const char *, struct kernel_param *);
41static int fcoe_transport_disable(const char *, struct kernel_param *);
42static int libfcoe_device_notification(struct notifier_block *notifier,
43 ulong event, void *ptr);
44
45static LIST_HEAD(fcoe_transports);
46static DEFINE_MUTEX(ft_mutex);
47static LIST_HEAD(fcoe_netdevs);
48static DEFINE_MUTEX(fn_mutex);
49
50unsigned int libfcoe_debug_logging;
51module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
52MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
53
54module_param_call(show, NULL, fcoe_transport_show, NULL, S_IRUSR);
55__MODULE_PARM_TYPE(show, "string");
56MODULE_PARM_DESC(show, " Show attached FCoE transports");
57
58module_param_call(create, fcoe_transport_create, NULL,
59 (void *)FIP_MODE_FABRIC, S_IWUSR);
60__MODULE_PARM_TYPE(create, "string");
61MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface");
62
63module_param_call(create_vn2vn, fcoe_transport_create, NULL,
64 (void *)FIP_MODE_VN2VN, S_IWUSR);
65__MODULE_PARM_TYPE(create_vn2vn, "string");
66MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance "
67 "on an Ethernet interface");
68
69module_param_call(destroy, fcoe_transport_destroy, NULL, NULL, S_IWUSR);
70__MODULE_PARM_TYPE(destroy, "string");
71MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface");
72
73module_param_call(enable, fcoe_transport_enable, NULL, NULL, S_IWUSR);
74__MODULE_PARM_TYPE(enable, "string");
75MODULE_PARM_DESC(enable, " Enables fcoe on a ethernet interface.");
76
77module_param_call(disable, fcoe_transport_disable, NULL, NULL, S_IWUSR);
78__MODULE_PARM_TYPE(disable, "string");
79MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface.");
80
81
82static struct notifier_block libfcoe_notifier = {
83 .notifier_call = libfcoe_device_notification,
84};
85
86
87
88
89
90
91
92
93int fcoe_link_speed_update(struct fc_lport *lport)
94{
95 struct net_device *netdev = fcoe_get_netdev(lport);
96 struct ethtool_link_ksettings ecmd;
97
98 if (!__ethtool_get_link_ksettings(netdev, &ecmd)) {
99 lport->link_supported_speeds &= ~(FC_PORTSPEED_1GBIT |
100 FC_PORTSPEED_10GBIT |
101 FC_PORTSPEED_20GBIT |
102 FC_PORTSPEED_40GBIT);
103
104 if (ecmd.link_modes.supported[0] & (
105 SUPPORTED_1000baseT_Half |
106 SUPPORTED_1000baseT_Full |
107 SUPPORTED_1000baseKX_Full))
108 lport->link_supported_speeds |= FC_PORTSPEED_1GBIT;
109
110 if (ecmd.link_modes.supported[0] & (
111 SUPPORTED_10000baseT_Full |
112 SUPPORTED_10000baseKX4_Full |
113 SUPPORTED_10000baseKR_Full |
114 SUPPORTED_10000baseR_FEC))
115 lport->link_supported_speeds |= FC_PORTSPEED_10GBIT;
116
117 if (ecmd.link_modes.supported[0] & (
118 SUPPORTED_20000baseMLD2_Full |
119 SUPPORTED_20000baseKR2_Full))
120 lport->link_supported_speeds |= FC_PORTSPEED_20GBIT;
121
122 if (ecmd.link_modes.supported[0] & (
123 SUPPORTED_40000baseKR4_Full |
124 SUPPORTED_40000baseCR4_Full |
125 SUPPORTED_40000baseSR4_Full |
126 SUPPORTED_40000baseLR4_Full))
127 lport->link_supported_speeds |= FC_PORTSPEED_40GBIT;
128
129 switch (ecmd.base.speed) {
130 case SPEED_1000:
131 lport->link_speed = FC_PORTSPEED_1GBIT;
132 break;
133 case SPEED_10000:
134 lport->link_speed = FC_PORTSPEED_10GBIT;
135 break;
136 case 20000:
137 lport->link_speed = FC_PORTSPEED_20GBIT;
138 break;
139 case 40000:
140 lport->link_speed = FC_PORTSPEED_40GBIT;
141 break;
142 default:
143 lport->link_speed = FC_PORTSPEED_UNKNOWN;
144 break;
145 }
146 return 0;
147 }
148 return -1;
149}
150EXPORT_SYMBOL_GPL(fcoe_link_speed_update);
151
152
153
154
155
156
157
158
159
160
161void __fcoe_get_lesb(struct fc_lport *lport,
162 struct fc_els_lesb *fc_lesb,
163 struct net_device *netdev)
164{
165 unsigned int cpu;
166 u32 lfc, vlfc, mdac;
167 struct fc_stats *stats;
168 struct fcoe_fc_els_lesb *lesb;
169 struct rtnl_link_stats64 temp;
170
171 lfc = 0;
172 vlfc = 0;
173 mdac = 0;
174 lesb = (struct fcoe_fc_els_lesb *)fc_lesb;
175 memset(lesb, 0, sizeof(*lesb));
176 for_each_possible_cpu(cpu) {
177 stats = per_cpu_ptr(lport->stats, cpu);
178 lfc += stats->LinkFailureCount;
179 vlfc += stats->VLinkFailureCount;
180 mdac += stats->MissDiscAdvCount;
181 }
182 lesb->lesb_link_fail = htonl(lfc);
183 lesb->lesb_vlink_fail = htonl(vlfc);
184 lesb->lesb_miss_fka = htonl(mdac);
185 lesb->lesb_fcs_error =
186 htonl(dev_get_stats(netdev, &temp)->rx_crc_errors);
187}
188EXPORT_SYMBOL_GPL(__fcoe_get_lesb);
189
190
191
192
193
194
195void fcoe_get_lesb(struct fc_lport *lport,
196 struct fc_els_lesb *fc_lesb)
197{
198 struct net_device *netdev = fcoe_get_netdev(lport);
199
200 __fcoe_get_lesb(lport, fc_lesb, netdev);
201}
202EXPORT_SYMBOL_GPL(fcoe_get_lesb);
203
204
205
206
207
208
209
210void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev)
211{
212 struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev);
213 struct net_device *netdev = fcoe_get_netdev(fip->lp);
214 struct fcoe_fc_els_lesb *fcoe_lesb;
215 struct fc_els_lesb fc_lesb;
216
217 __fcoe_get_lesb(fip->lp, &fc_lesb, netdev);
218 fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb);
219
220 ctlr_dev->lesb.lesb_link_fail =
221 ntohl(fcoe_lesb->lesb_link_fail);
222 ctlr_dev->lesb.lesb_vlink_fail =
223 ntohl(fcoe_lesb->lesb_vlink_fail);
224 ctlr_dev->lesb.lesb_miss_fka =
225 ntohl(fcoe_lesb->lesb_miss_fka);
226 ctlr_dev->lesb.lesb_symb_err =
227 ntohl(fcoe_lesb->lesb_symb_err);
228 ctlr_dev->lesb.lesb_err_block =
229 ntohl(fcoe_lesb->lesb_err_block);
230 ctlr_dev->lesb.lesb_fcs_error =
231 ntohl(fcoe_lesb->lesb_fcs_error);
232}
233EXPORT_SYMBOL_GPL(fcoe_ctlr_get_lesb);
234
235void fcoe_wwn_to_str(u64 wwn, char *buf, int len)
236{
237 u8 wwpn[8];
238
239 u64_to_wwn(wwn, wwpn);
240 snprintf(buf, len, "%02x%02x%02x%02x%02x%02x%02x%02x",
241 wwpn[0], wwpn[1], wwpn[2], wwpn[3],
242 wwpn[4], wwpn[5], wwpn[6], wwpn[7]);
243}
244EXPORT_SYMBOL_GPL(fcoe_wwn_to_str);
245
246
247
248
249
250
251
252
253
254
255int fcoe_validate_vport_create(struct fc_vport *vport)
256{
257 struct Scsi_Host *shost = vport_to_shost(vport);
258 struct fc_lport *n_port = shost_priv(shost);
259 struct fc_lport *vn_port;
260 int rc = 0;
261 char buf[32];
262
263 mutex_lock(&n_port->lp_mutex);
264
265 fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf));
266
267 if (!memcmp(&n_port->wwpn, &vport->port_name, sizeof(u64))) {
268 LIBFCOE_TRANSPORT_DBG("vport WWPN 0x%s is same as that of the "
269 "base port WWPN\n", buf);
270 rc = -EINVAL;
271 goto out;
272 }
273
274
275 list_for_each_entry(vn_port, &n_port->vports, list) {
276 if (!memcmp(&vn_port->wwpn, &vport->port_name, sizeof(u64))) {
277 LIBFCOE_TRANSPORT_DBG("vport with given WWPN 0x%s "
278 "already exists\n", buf);
279 rc = -EINVAL;
280 break;
281 }
282 }
283out:
284 mutex_unlock(&n_port->lp_mutex);
285 return rc;
286}
287EXPORT_SYMBOL_GPL(fcoe_validate_vport_create);
288
289
290
291
292
293
294
295
296
297int fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type)
298{
299 const struct net_device_ops *ops = netdev->netdev_ops;
300
301 if (ops->ndo_fcoe_get_wwn)
302 return ops->ndo_fcoe_get_wwn(netdev, wwn, type);
303 return -EINVAL;
304}
305EXPORT_SYMBOL_GPL(fcoe_get_wwn);
306
307
308
309
310
311
312
313
314
315u32 fcoe_fc_crc(struct fc_frame *fp)
316{
317 struct sk_buff *skb = fp_skb(fp);
318 struct skb_frag_struct *frag;
319 unsigned char *data;
320 unsigned long off, len, clen;
321 u32 crc;
322 unsigned i;
323
324 crc = crc32(~0, skb->data, skb_headlen(skb));
325
326 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
327 frag = &skb_shinfo(skb)->frags[i];
328 off = frag->page_offset;
329 len = skb_frag_size(frag);
330 while (len > 0) {
331 clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK));
332 data = kmap_atomic(
333 skb_frag_page(frag) + (off >> PAGE_SHIFT));
334 crc = crc32(crc, data + (off & ~PAGE_MASK), clen);
335 kunmap_atomic(data);
336 off += clen;
337 len -= clen;
338 }
339 }
340 return crc;
341}
342EXPORT_SYMBOL_GPL(fcoe_fc_crc);
343
344
345
346
347
348
349
350
351
352
353int fcoe_start_io(struct sk_buff *skb)
354{
355 struct sk_buff *nskb;
356 int rc;
357
358 nskb = skb_clone(skb, GFP_ATOMIC);
359 if (!nskb)
360 return -ENOMEM;
361 rc = dev_queue_xmit(nskb);
362 if (rc != 0)
363 return rc;
364 kfree_skb(skb);
365 return 0;
366}
367EXPORT_SYMBOL_GPL(fcoe_start_io);
368
369
370
371
372
373
374void fcoe_clean_pending_queue(struct fc_lport *lport)
375{
376 struct fcoe_port *port = lport_priv(lport);
377 struct sk_buff *skb;
378
379 spin_lock_bh(&port->fcoe_pending_queue.lock);
380 while ((skb = __skb_dequeue(&port->fcoe_pending_queue)) != NULL) {
381 spin_unlock_bh(&port->fcoe_pending_queue.lock);
382 kfree_skb(skb);
383 spin_lock_bh(&port->fcoe_pending_queue.lock);
384 }
385 spin_unlock_bh(&port->fcoe_pending_queue.lock);
386}
387EXPORT_SYMBOL_GPL(fcoe_clean_pending_queue);
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb)
403{
404 struct fcoe_port *port = lport_priv(lport);
405 int rc;
406
407 spin_lock_bh(&port->fcoe_pending_queue.lock);
408
409 if (skb)
410 __skb_queue_tail(&port->fcoe_pending_queue, skb);
411
412 if (port->fcoe_pending_queue_active)
413 goto out;
414 port->fcoe_pending_queue_active = 1;
415
416 while (port->fcoe_pending_queue.qlen) {
417
418 port->fcoe_pending_queue.qlen++;
419 skb = __skb_dequeue(&port->fcoe_pending_queue);
420
421 spin_unlock_bh(&port->fcoe_pending_queue.lock);
422 rc = fcoe_start_io(skb);
423 spin_lock_bh(&port->fcoe_pending_queue.lock);
424
425 if (rc) {
426 __skb_queue_head(&port->fcoe_pending_queue, skb);
427
428 port->fcoe_pending_queue.qlen--;
429 break;
430 }
431
432 port->fcoe_pending_queue.qlen--;
433 }
434
435 if (port->fcoe_pending_queue.qlen < port->min_queue_depth)
436 lport->qfull = 0;
437 if (port->fcoe_pending_queue.qlen && !timer_pending(&port->timer))
438 mod_timer(&port->timer, jiffies + 2);
439 port->fcoe_pending_queue_active = 0;
440out:
441 if (port->fcoe_pending_queue.qlen > port->max_queue_depth)
442 lport->qfull = 1;
443 spin_unlock_bh(&port->fcoe_pending_queue.lock);
444}
445EXPORT_SYMBOL_GPL(fcoe_check_wait_queue);
446
447
448
449
450
451
452
453void fcoe_queue_timer(ulong lport)
454{
455 fcoe_check_wait_queue((struct fc_lport *)lport, NULL);
456}
457EXPORT_SYMBOL_GPL(fcoe_queue_timer);
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen,
474 struct fcoe_percpu_s *fps)
475{
476 struct page *page;
477
478 page = fps->crc_eof_page;
479 if (!page) {
480 page = alloc_page(GFP_ATOMIC);
481 if (!page)
482 return -ENOMEM;
483
484 fps->crc_eof_page = page;
485 fps->crc_eof_offset = 0;
486 }
487
488 get_page(page);
489 skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page,
490 fps->crc_eof_offset, tlen);
491 skb->len += tlen;
492 skb->data_len += tlen;
493 skb->truesize += tlen;
494 fps->crc_eof_offset += sizeof(struct fcoe_crc_eof);
495
496 if (fps->crc_eof_offset >= PAGE_SIZE) {
497 fps->crc_eof_page = NULL;
498 fps->crc_eof_offset = 0;
499 put_page(page);
500 }
501
502 return 0;
503}
504EXPORT_SYMBOL_GPL(fcoe_get_paged_crc_eof);
505
506
507
508
509
510
511
512
513
514
515static struct fcoe_transport *fcoe_transport_lookup(struct net_device *netdev)
516{
517 struct fcoe_transport *ft = NULL;
518
519 list_for_each_entry(ft, &fcoe_transports, list)
520 if (ft->match && ft->match(netdev))
521 return ft;
522 return NULL;
523}
524
525
526
527
528
529
530
531int fcoe_transport_attach(struct fcoe_transport *ft)
532{
533 int rc = 0;
534
535 mutex_lock(&ft_mutex);
536 if (ft->attached) {
537 LIBFCOE_TRANSPORT_DBG("transport %s already attached\n",
538 ft->name);
539 rc = -EEXIST;
540 goto out_attach;
541 }
542
543
544 if (strcmp(ft->name, FCOE_TRANSPORT_DEFAULT))
545 list_add(&ft->list, &fcoe_transports);
546 else
547 list_add_tail(&ft->list, &fcoe_transports);
548
549 ft->attached = true;
550 LIBFCOE_TRANSPORT_DBG("attaching transport %s\n", ft->name);
551
552out_attach:
553 mutex_unlock(&ft_mutex);
554 return rc;
555}
556EXPORT_SYMBOL(fcoe_transport_attach);
557
558
559
560
561
562
563
564int fcoe_transport_detach(struct fcoe_transport *ft)
565{
566 int rc = 0;
567 struct fcoe_netdev_mapping *nm = NULL, *tmp;
568
569 mutex_lock(&ft_mutex);
570 if (!ft->attached) {
571 LIBFCOE_TRANSPORT_DBG("transport %s already detached\n",
572 ft->name);
573 rc = -ENODEV;
574 goto out_attach;
575 }
576
577
578 mutex_lock(&fn_mutex);
579 list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) {
580 if (nm->ft == ft) {
581 LIBFCOE_TRANSPORT_DBG("transport %s going away, "
582 "remove its netdev mapping for %s\n",
583 ft->name, nm->netdev->name);
584 list_del(&nm->list);
585 kfree(nm);
586 }
587 }
588 mutex_unlock(&fn_mutex);
589
590 list_del(&ft->list);
591 ft->attached = false;
592 LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name);
593
594out_attach:
595 mutex_unlock(&ft_mutex);
596 return rc;
597
598}
599EXPORT_SYMBOL(fcoe_transport_detach);
600
601static int fcoe_transport_show(char *buffer, const struct kernel_param *kp)
602{
603 int i, j;
604 struct fcoe_transport *ft = NULL;
605
606 i = j = sprintf(buffer, "Attached FCoE transports:");
607 mutex_lock(&ft_mutex);
608 list_for_each_entry(ft, &fcoe_transports, list) {
609 if (i >= PAGE_SIZE - IFNAMSIZ)
610 break;
611 i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name);
612 }
613 mutex_unlock(&ft_mutex);
614 if (i == j)
615 i += snprintf(&buffer[i], IFNAMSIZ, "none");
616 return i;
617}
618
619static int __init fcoe_transport_init(void)
620{
621 register_netdevice_notifier_rh(&libfcoe_notifier);
622 return 0;
623}
624
625static int fcoe_transport_exit(void)
626{
627 struct fcoe_transport *ft;
628
629 unregister_netdevice_notifier_rh(&libfcoe_notifier);
630 mutex_lock(&ft_mutex);
631 list_for_each_entry(ft, &fcoe_transports, list)
632 printk(KERN_ERR "FCoE transport %s is still attached!\n",
633 ft->name);
634 mutex_unlock(&ft_mutex);
635 return 0;
636}
637
638
639static int fcoe_add_netdev_mapping(struct net_device *netdev,
640 struct fcoe_transport *ft)
641{
642 struct fcoe_netdev_mapping *nm;
643
644 nm = kmalloc(sizeof(*nm), GFP_KERNEL);
645 if (!nm) {
646 printk(KERN_ERR "Unable to allocate netdev_mapping");
647 return -ENOMEM;
648 }
649
650 nm->netdev = netdev;
651 nm->ft = ft;
652
653 mutex_lock(&fn_mutex);
654 list_add(&nm->list, &fcoe_netdevs);
655 mutex_unlock(&fn_mutex);
656 return 0;
657}
658
659
660static void fcoe_del_netdev_mapping(struct net_device *netdev)
661{
662 struct fcoe_netdev_mapping *nm = NULL, *tmp;
663
664 mutex_lock(&fn_mutex);
665 list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) {
666 if (nm->netdev == netdev) {
667 list_del(&nm->list);
668 kfree(nm);
669 mutex_unlock(&fn_mutex);
670 return;
671 }
672 }
673 mutex_unlock(&fn_mutex);
674}
675
676
677
678
679
680
681
682
683
684
685
686static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev)
687{
688 struct fcoe_transport *ft = NULL;
689 struct fcoe_netdev_mapping *nm;
690
691 mutex_lock(&fn_mutex);
692 list_for_each_entry(nm, &fcoe_netdevs, list) {
693 if (netdev == nm->netdev) {
694 ft = nm->ft;
695 mutex_unlock(&fn_mutex);
696 return ft;
697 }
698 }
699
700 mutex_unlock(&fn_mutex);
701 return NULL;
702}
703
704
705
706
707
708
709
710static struct net_device *fcoe_if_to_netdev(const char *buffer)
711{
712 char *cp;
713 char ifname[IFNAMSIZ + 2];
714
715 if (buffer) {
716 strlcpy(ifname, buffer, IFNAMSIZ);
717 cp = ifname + strlen(ifname);
718 while (--cp >= ifname && *cp == '\n')
719 *cp = '\0';
720 return dev_get_by_name(&init_net, ifname);
721 }
722 return NULL;
723}
724
725
726
727
728
729
730
731
732
733
734
735static int libfcoe_device_notification(struct notifier_block *notifier,
736 ulong event, void *ptr)
737{
738 struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
739
740 switch (event) {
741 case NETDEV_UNREGISTER:
742 LIBFCOE_TRANSPORT_DBG("NETDEV_UNREGISTER %s\n",
743 netdev->name);
744 fcoe_del_netdev_mapping(netdev);
745 break;
746 }
747 return NOTIFY_OK;
748}
749
750ssize_t fcoe_ctlr_create_store(struct bus_type *bus,
751 const char *buf, size_t count)
752{
753 struct net_device *netdev = NULL;
754 struct fcoe_transport *ft = NULL;
755 struct fcoe_ctlr_device *ctlr_dev = NULL;
756 int rc = 0;
757 int err;
758
759 mutex_lock(&ft_mutex);
760
761 netdev = fcoe_if_to_netdev(buf);
762 if (!netdev) {
763 LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buf);
764 rc = -ENODEV;
765 goto out_nodev;
766 }
767
768 ft = fcoe_netdev_map_lookup(netdev);
769 if (ft) {
770 LIBFCOE_TRANSPORT_DBG("transport %s already has existing "
771 "FCoE instance on %s.\n",
772 ft->name, netdev->name);
773 rc = -EEXIST;
774 goto out_putdev;
775 }
776
777 ft = fcoe_transport_lookup(netdev);
778 if (!ft) {
779 LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
780 netdev->name);
781 rc = -ENODEV;
782 goto out_putdev;
783 }
784
785
786 err = ft->alloc ? ft->alloc(netdev) : -ENODEV;
787 if (err) {
788 fcoe_del_netdev_mapping(netdev);
789 rc = -ENOMEM;
790 goto out_putdev;
791 }
792
793 err = fcoe_add_netdev_mapping(netdev, ft);
794 if (err) {
795 LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping "
796 "for FCoE transport %s for %s.\n",
797 ft->name, netdev->name);
798 rc = -ENODEV;
799 goto out_putdev;
800 }
801
802 LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n",
803 ft->name, (ctlr_dev) ? "succeeded" : "failed",
804 netdev->name);
805
806out_putdev:
807 dev_put(netdev);
808out_nodev:
809 mutex_unlock(&ft_mutex);
810 if (rc)
811 return rc;
812 return count;
813}
814
815ssize_t fcoe_ctlr_destroy_store(struct bus_type *bus,
816 const char *buf, size_t count)
817{
818 int rc = -ENODEV;
819 struct net_device *netdev = NULL;
820 struct fcoe_transport *ft = NULL;
821
822 mutex_lock(&ft_mutex);
823
824 netdev = fcoe_if_to_netdev(buf);
825 if (!netdev) {
826 LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buf);
827 goto out_nodev;
828 }
829
830 ft = fcoe_netdev_map_lookup(netdev);
831 if (!ft) {
832 LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
833 netdev->name);
834 goto out_putdev;
835 }
836
837
838 rc = ft->destroy(netdev);
839 if (rc)
840 goto out_putdev;
841
842 fcoe_del_netdev_mapping(netdev);
843 LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n",
844 ft->name, (rc) ? "failed" : "succeeded",
845 netdev->name);
846 rc = count;
847out_putdev:
848 dev_put(netdev);
849out_nodev:
850 mutex_unlock(&ft_mutex);
851 return rc;
852}
853EXPORT_SYMBOL(fcoe_ctlr_destroy_store);
854
855
856
857
858
859
860
861
862
863
864
865static int fcoe_transport_create(const char *buffer, struct kernel_param *kp)
866{
867 int rc = -ENODEV;
868 struct net_device *netdev = NULL;
869 struct fcoe_transport *ft = NULL;
870 enum fip_state fip_mode = (enum fip_state)(long)kp->arg;
871
872 mutex_lock(&ft_mutex);
873
874 netdev = fcoe_if_to_netdev(buffer);
875 if (!netdev) {
876 LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buffer);
877 goto out_nodev;
878 }
879
880 ft = fcoe_netdev_map_lookup(netdev);
881 if (ft) {
882 LIBFCOE_TRANSPORT_DBG("transport %s already has existing "
883 "FCoE instance on %s.\n",
884 ft->name, netdev->name);
885 rc = -EEXIST;
886 goto out_putdev;
887 }
888
889 ft = fcoe_transport_lookup(netdev);
890 if (!ft) {
891 LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
892 netdev->name);
893 goto out_putdev;
894 }
895
896 rc = fcoe_add_netdev_mapping(netdev, ft);
897 if (rc) {
898 LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping "
899 "for FCoE transport %s for %s.\n",
900 ft->name, netdev->name);
901 goto out_putdev;
902 }
903
904
905 rc = ft->create ? ft->create(netdev, fip_mode) : -ENODEV;
906 if (rc)
907 fcoe_del_netdev_mapping(netdev);
908
909 LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n",
910 ft->name, (rc) ? "failed" : "succeeded",
911 netdev->name);
912
913out_putdev:
914 dev_put(netdev);
915out_nodev:
916 mutex_unlock(&ft_mutex);
917 return rc;
918}
919
920
921
922
923
924
925
926
927
928
929
930static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp)
931{
932 int rc = -ENODEV;
933 struct net_device *netdev = NULL;
934 struct fcoe_transport *ft = NULL;
935
936 mutex_lock(&ft_mutex);
937
938 netdev = fcoe_if_to_netdev(buffer);
939 if (!netdev) {
940 LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buffer);
941 goto out_nodev;
942 }
943
944 ft = fcoe_netdev_map_lookup(netdev);
945 if (!ft) {
946 LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
947 netdev->name);
948 goto out_putdev;
949 }
950
951
952 rc = ft->destroy ? ft->destroy(netdev) : -ENODEV;
953 fcoe_del_netdev_mapping(netdev);
954 LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n",
955 ft->name, (rc) ? "failed" : "succeeded",
956 netdev->name);
957
958out_putdev:
959 dev_put(netdev);
960out_nodev:
961 mutex_unlock(&ft_mutex);
962 return rc;
963}
964
965
966
967
968
969
970
971
972
973
974static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp)
975{
976 int rc = -ENODEV;
977 struct net_device *netdev = NULL;
978 struct fcoe_transport *ft = NULL;
979
980 mutex_lock(&ft_mutex);
981
982 netdev = fcoe_if_to_netdev(buffer);
983 if (!netdev)
984 goto out_nodev;
985
986 ft = fcoe_netdev_map_lookup(netdev);
987 if (!ft)
988 goto out_putdev;
989
990 rc = ft->disable ? ft->disable(netdev) : -ENODEV;
991
992out_putdev:
993 dev_put(netdev);
994out_nodev:
995 mutex_unlock(&ft_mutex);
996 return rc;
997}
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp)
1009{
1010 int rc = -ENODEV;
1011 struct net_device *netdev = NULL;
1012 struct fcoe_transport *ft = NULL;
1013
1014 mutex_lock(&ft_mutex);
1015
1016 netdev = fcoe_if_to_netdev(buffer);
1017 if (!netdev)
1018 goto out_nodev;
1019
1020 ft = fcoe_netdev_map_lookup(netdev);
1021 if (!ft)
1022 goto out_putdev;
1023
1024 rc = ft->enable ? ft->enable(netdev) : -ENODEV;
1025
1026out_putdev:
1027 dev_put(netdev);
1028out_nodev:
1029 mutex_unlock(&ft_mutex);
1030 return rc;
1031}
1032
1033
1034
1035
1036static int __init libfcoe_init(void)
1037{
1038 int rc = 0;
1039
1040 rc = fcoe_transport_init();
1041 if (rc)
1042 return rc;
1043
1044 rc = fcoe_sysfs_setup();
1045 if (rc)
1046 fcoe_transport_exit();
1047
1048 return rc;
1049}
1050module_init(libfcoe_init);
1051
1052
1053
1054
1055static void __exit libfcoe_exit(void)
1056{
1057 fcoe_sysfs_teardown();
1058 fcoe_transport_exit();
1059}
1060module_exit(libfcoe_exit);
1061