1 From: Hannes Reinecke <hare@suse.de>
2 Date: Wed, 17 Sep 2008 16:25:23 +0200
3 Subject: fcoe: Fibre Channel over Ethernet driver
4 References: FATE#303913
6 Encapsulation protocol for running Fibre Channel over Ethernet interfaces.
7 Creates virtual Fibre Channel host adapters using libfc.
9 Signed-off-by: Robert Love <robert.w.love@intel.com>
10 Signed-off-by: Chris Leech <christopher.leech@intel.com>
11 Signed-off-by: Vasu Dev <vasu.dev@intel.com>
12 Signed-off-by: Yi Zou <yi.zou@intel.com>
13 Signed-off-by: Steve Ma <steve.ma@intel.com>
14 Signed-off-by: Hannes Reinecke <hare@suse.de>
16 drivers/scsi/Kconfig | 6 +
17 drivers/scsi/Makefile | 1 +
18 drivers/scsi/fcoe/Makefile | 8 +
19 drivers/scsi/fcoe/fcoe_def.h | 100 +++++++
20 drivers/scsi/fcoe/fcoe_dev.c | 633 ++++++++++++++++++++++++++++++++++++++++++
21 drivers/scsi/fcoe/fcoe_if.c | 497 +++++++++++++++++++++++++++++++++
22 drivers/scsi/fcoe/fcoeinit.c | 440 +++++++++++++++++++++++++++++
23 7 files changed, 1685 insertions(+), 0 deletions(-)
24 create mode 100644 drivers/scsi/fcoe/Makefile
25 create mode 100644 drivers/scsi/fcoe/fcoe_def.h
26 create mode 100644 drivers/scsi/fcoe/fcoe_dev.c
27 create mode 100644 drivers/scsi/fcoe/fcoe_if.c
28 create mode 100644 drivers/scsi/fcoe/fcoeinit.c
30 diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
31 index bd480d2..f382eea 100644
32 --- a/drivers/scsi/Kconfig
33 +++ b/drivers/scsi/Kconfig
34 @@ -334,6 +334,12 @@ config LIBFC
36 Fibre Channel library module
39 + tristate "FCoE module"
42 + Fibre Channel over Ethernet module
45 tristate "iSCSI Initiator over TCP/IP"
46 depends on SCSI && INET
47 diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
48 index 9158dc6..22c01e5 100644
49 --- a/drivers/scsi/Makefile
50 +++ b/drivers/scsi/Makefile
51 @@ -37,6 +37,7 @@ obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o
52 obj-$(CONFIG_SCSI_DH) += device_handler/
54 obj-$(CONFIG_LIBFC) += libfc/
55 +obj-$(CONFIG_FCOE) += fcoe/
56 obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o
57 obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
58 obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o
59 diff --git a/drivers/scsi/fcoe/Makefile b/drivers/scsi/fcoe/Makefile
61 index 0000000..342e2ad
63 +++ b/drivers/scsi/fcoe/Makefile
67 +obj-$(CONFIG_FCOE) += fcoe.o
73 diff --git a/drivers/scsi/fcoe/fcoe_def.h b/drivers/scsi/fcoe/fcoe_def.h
75 index 0000000..12bf69c
77 +++ b/drivers/scsi/fcoe/fcoe_def.h
80 + * Copyright(c) 2007 Intel Corporation. All rights reserved.
82 + * This program is free software; you can redistribute it and/or modify it
83 + * under the terms and conditions of the GNU General Public License,
84 + * version 2, as published by the Free Software Foundation.
86 + * This program is distributed in the hope it will be useful, but WITHOUT
87 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
88 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
91 + * You should have received a copy of the GNU General Public License along with
92 + * this program; if not, write to the Free Software Foundation, Inc.,
93 + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
95 + * Maintained at www.Open-FCoE.org
101 +#include <linux/etherdevice.h>
102 +#include <linux/if_ether.h>
104 +#include <scsi/libfc/libfc.h>
106 +#include <scsi/fc/fc_fcoe.h>
108 +#define FCOE_DRIVER_NAME "fcoe" /* driver name for ioctls */
109 +#define FCOE_DRIVER_VENDOR "Open-FC.org" /* vendor name for ioctls */
111 +#define FCOE_MIN_FRAME 36
112 +#define FCOE_WORD_TO_BYTE 4
115 + * this is the main common structure across all instance of fcoe driver.
116 + * There is one to one mapping between hba struct and ethernet nic.
117 + * list of hbas contains pointer to the hba struct, these structures are
118 + * stored in this array using there corresponding if_index.
121 +struct fcoe_percpu_s {
123 + struct task_struct *thread;
124 + struct sk_buff_head fcoe_rx_list;
125 + struct page *crc_eof_page;
126 + int crc_eof_offset;
130 + struct timer_list timer;
132 + * fcoe host list is protected by the following read/write lock
134 + rwlock_t fcoe_hostlist_lock;
135 + struct list_head fcoe_hostlist;
137 + struct fcoe_percpu_s *fcoe_percpu[NR_CPUS];
141 + struct list_head list;
142 + struct fc_lport *lp;
143 + struct net_device *real_dev;
144 + struct net_device *phys_dev; /* device with ethtool_ops */
145 + struct packet_type fcoe_packet_type;
146 + struct sk_buff_head fcoe_pending_queue;
147 + u16 user_mfs; /* configured max frame size */
149 + u8 dest_addr[ETH_ALEN];
150 + u8 ctl_src_addr[ETH_ALEN];
151 + u8 data_src_addr[ETH_ALEN];
153 + * fcoe protocol address learning related stuff
160 +extern int debug_fcoe;
161 +extern struct fcoe_percpu_s *fcoe_percpu[];
162 +extern struct scsi_transport_template *fcoe_transport_template;
163 +int fcoe_percpu_receive_thread(void *arg);
166 + * HBA transport ops prototypes
168 +extern struct fcoe_info fcoei;
170 +void fcoe_clean_pending_queue(struct fc_lport *fd);
171 +void fcoe_watchdog(ulong vp);
172 +int fcoe_destroy_interface(const char *ifname);
173 +int fcoe_create_interface(const char *ifname);
174 +int fcoe_xmit(struct fc_lport *, struct fc_frame *);
175 +int fcoe_rcv(struct sk_buff *, struct net_device *,
176 + struct packet_type *, struct net_device *);
177 +int fcoe_link_ok(struct fc_lport *);
178 +#endif /* _FCOE_DEF_H_ */
179 diff --git a/drivers/scsi/fcoe/fcoe_dev.c b/drivers/scsi/fcoe/fcoe_dev.c
181 index 0000000..d5a354f
183 +++ b/drivers/scsi/fcoe/fcoe_dev.c
186 + * Copyright(c) 2007 Intel Corporation. All rights reserved.
188 + * This program is free software; you can redistribute it and/or modify it
189 + * under the terms and conditions of the GNU General Public License,
190 + * version 2, as published by the Free Software Foundation.
192 + * This program is distributed in the hope it will be useful, but WITHOUT
193 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
194 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
197 + * You should have received a copy of the GNU General Public License along with
198 + * this program; if not, write to the Free Software Foundation, Inc.,
199 + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
201 + * Maintained at www.Open-FCoE.org
205 + * FCOE protocol file
208 +#include <linux/module.h>
209 +#include <linux/version.h>
210 +#include <linux/kernel.h>
211 +#include <linux/spinlock.h>
212 +#include <linux/skbuff.h>
213 +#include <linux/netdevice.h>
214 +#include <linux/etherdevice.h>
215 +#include <linux/if_ether.h>
216 +#include <linux/kthread.h>
217 +#include <linux/crc32.h>
218 +#include <scsi/scsi_tcq.h>
219 +#include <scsi/scsicam.h>
220 +#include <scsi/scsi_transport.h>
221 +#include <scsi/scsi_transport_fc.h>
222 +#include <net/rtnetlink.h>
224 +#include <scsi/fc/fc_encaps.h>
226 +#include <scsi/libfc/libfc.h>
227 +#include <scsi/libfc/fc_frame.h>
229 +#include <scsi/fc/fc_fcoe.h>
230 +#include "fcoe_def.h"
232 +#define FCOE_MAX_QUEUE_DEPTH 256
234 +/* destination address mode */
235 +#define FCOE_GW_ADDR_MODE 0x00
236 +#define FCOE_FCOUI_ADDR_MODE 0x01
238 +/* Function Prototyes */
239 +static int fcoe_check_wait_queue(struct fc_lport *);
240 +static void fcoe_insert_wait_queue_head(struct fc_lport *, struct sk_buff *);
241 +static void fcoe_insert_wait_queue(struct fc_lport *, struct sk_buff *);
242 +static void fcoe_recv_flogi(struct fcoe_softc *, struct fc_frame *, u8 *);
245 + * this is the fcoe receive function
246 + * called by NET_RX_SOFTIRQ
247 + * this function will receive the packet and
248 + * build fc frame and pass it up
250 +int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,
251 + struct packet_type *ptype, struct net_device *olddev)
253 + struct fc_lport *lp;
254 + struct fcoe_rcv_info *fr;
255 + struct fcoe_softc *fc;
256 + struct fcoe_dev_stats *stats;
258 + struct fc_frame_header *fh;
259 + unsigned short oxid;
261 + struct fcoe_percpu_s *fps;
262 + struct fcoe_info *fci = &fcoei;
264 + fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type);
266 + if (unlikely(lp == NULL)) {
267 + FC_DBG("cannot find hba structure");
271 + if (unlikely(debug_fcoe)) {
272 + FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p tail:%p "
273 + "end:%p sum:%d dev:%s", skb->len, skb->data_len,
274 + skb->head, skb->data, skb_tail_pointer(skb),
275 + skb_end_pointer(skb), skb->csum,
276 + skb->dev ? skb->dev->name : "<NULL>");
280 + /* check for FCOE packet type */
281 + if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
282 + FC_DBG("wrong FC type frame");
286 + data += sizeof(struct fcoe_hdr);
287 + fh = (struct fc_frame_header *)data;
288 + oxid = ntohs(fh->fh_ox_id);
290 + fr = fcoe_dev_from_skb(skb);
296 + * The exchange ID are ANDed with num of online CPUs,
297 + * so that will have the least lock contention in
298 + * handling the exchange. if there is no thread
299 + * for a given idx then use first online cpu.
301 + cpu_idx = oxid & (num_online_cpus() >> 1);
302 + if (fci->fcoe_percpu[cpu_idx] == NULL)
303 + cpu_idx = first_cpu(cpu_online_map);
305 + fps = fci->fcoe_percpu[cpu_idx];
307 + spin_lock_bh(&fps->fcoe_rx_list.lock);
308 + __skb_queue_tail(&fps->fcoe_rx_list, skb);
309 + if (fps->fcoe_rx_list.qlen == 1)
310 + wake_up_process(fps->thread);
312 + spin_unlock_bh(&fps->fcoe_rx_list.lock);
317 + stats = lp->dev_stats[smp_processor_id()];
319 + stats = lp->dev_stats[0];
321 + stats->ErrorFrames++;
328 +static inline int fcoe_start_io(struct sk_buff *skb)
333 + rc = dev_queue_xmit(skb);
340 +static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen)
342 + struct fcoe_info *fci = &fcoei;
343 + struct fcoe_percpu_s *fps;
347 + cpu_idx = get_cpu();
348 + fps = fci->fcoe_percpu[cpu_idx];
349 + page = fps->crc_eof_page;
351 + page = alloc_page(GFP_ATOMIC);
356 + fps->crc_eof_page = page;
357 + WARN_ON(fps->crc_eof_offset != 0);
361 + skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page,
362 + fps->crc_eof_offset, tlen);
364 + skb->data_len += tlen;
365 + skb->truesize += tlen;
366 + fps->crc_eof_offset += sizeof(struct fcoe_crc_eof);
368 + if (fps->crc_eof_offset >= PAGE_SIZE) {
369 + fps->crc_eof_page = NULL;
370 + fps->crc_eof_offset = 0;
378 + * this is the frame xmit routine
380 +int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
386 + struct fcoe_crc_eof *cp;
387 + struct sk_buff *skb;
388 + struct fcoe_dev_stats *stats;
389 + struct fc_frame_header *fh;
390 + unsigned int hlen; /* header length implies the version */
391 + unsigned int tlen; /* trailer length */
392 + int flogi_in_progress = 0;
393 + struct fcoe_softc *fc;
396 + struct fcoe_hdr *hp;
398 + WARN_ON((fr_len(fp) % sizeof(u32)) != 0);
400 + fc = (struct fcoe_softc *)lp->drv_priv;
402 + * if it is a flogi then we need to learn gw-addr
405 + fh = fc_frame_header_get(fp);
406 + if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) {
407 + if (fc_frame_payload_op(fp) == ELS_FLOGI) {
408 + fc->flogi_oxid = ntohs(fh->fh_ox_id);
409 + fc->address_mode = FCOE_FCOUI_ADDR_MODE;
410 + fc->flogi_progress = 1;
411 + flogi_in_progress = 1;
412 + } else if (fc->flogi_progress && ntoh24(fh->fh_s_id) != 0) {
414 + * Here we must've gotten an SID by accepting an FLOGI
415 + * from a point-to-point connection. Switch to using
416 + * the source mac based on the SID. The destination
417 + * MAC in this case would have been set by receving the
420 + fc_fcoe_set_mac(fc->data_src_addr, fh->fh_s_id);
421 + fc->flogi_progress = 0;
430 + crc = crc32(crc, skb->data, skb_headlen(skb));
432 + for (indx = 0; indx < skb_shinfo(skb)->nr_frags; indx++) {
433 + skb_frag_t *frag = &skb_shinfo(skb)->frags[indx];
434 + unsigned long off = frag->page_offset;
435 + unsigned long len = frag->size;
438 + unsigned long clen;
440 + clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK));
441 + data = kmap_atomic(frag->page + (off >> PAGE_SHIFT),
442 + KM_SKB_DATA_SOFTIRQ);
443 + crc = crc32(crc, data + (off & ~PAGE_MASK),
445 + kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ);
452 + * Get header and trailer lengths.
453 + * This is temporary code until we get rid of the old protocol.
454 + * Both versions have essentially the same trailer layout but T11
455 + * has padding afterwards.
457 + hlen = sizeof(struct fcoe_hdr);
458 + tlen = sizeof(struct fcoe_crc_eof);
461 + * copy fc crc and eof to the skb buff
462 + * Use utility buffer in the fc_frame part of the sk_buff for the
464 + * We don't do a get_page for this frag, since that page may not be
465 + * managed that way. So that skb_free() doesn't do that either, we
466 + * setup the destructor to remove this frag.
468 + if (skb_is_nonlinear(skb)) {
470 + if (fcoe_get_paged_crc_eof(skb, tlen)) {
474 + frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1];
475 + cp = kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ)
476 + + frag->page_offset;
478 + cp = (struct fcoe_crc_eof *)skb_put(skb, tlen);
481 + cp->fcoe_eof = eof;
482 + cp->fcoe_crc32 = cpu_to_le32(~crc);
483 + if (tlen == sizeof(*cp))
484 + memset(cp->fcoe_resvd, 0, sizeof(cp->fcoe_resvd));
485 + wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE;
487 + if (skb_is_nonlinear(skb)) {
488 + kunmap_atomic(cp, KM_SKB_DATA_SOFTIRQ);
493 + * Fill in the control structures
495 + skb->ip_summed = CHECKSUM_NONE;
496 + eh = (struct ethhdr *)skb_push(skb, hlen + sizeof(struct ethhdr));
497 + if (fc->address_mode == FCOE_FCOUI_ADDR_MODE)
498 + fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id);
500 + /* insert GW address */
501 + memcpy(eh->h_dest, fc->dest_addr, ETH_ALEN);
503 + if (unlikely(flogi_in_progress))
504 + memcpy(eh->h_source, fc->ctl_src_addr, ETH_ALEN);
506 + memcpy(eh->h_source, fc->data_src_addr, ETH_ALEN);
508 + eh->h_proto = htons(ETH_P_FCOE);
509 + skb->protocol = htons(ETH_P_802_3);
510 + skb_reset_mac_header(skb);
511 + skb_reset_network_header(skb);
513 + hp = (struct fcoe_hdr *)(eh + 1);
514 + memset(hp, 0, sizeof(*hp));
516 + FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER);
517 + hp->fcoe_sof = sof;
519 + stats = lp->dev_stats[smp_processor_id()];
521 + stats->TxWords += wlen;
522 + skb->dev = fc->real_dev;
525 + if (fc->fcoe_pending_queue.qlen)
526 + rc = fcoe_check_wait_queue(lp);
529 + rc = fcoe_start_io(skb);
532 + fcoe_insert_wait_queue(lp, skb);
533 + if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
540 +int fcoe_percpu_receive_thread(void *arg)
542 + struct fcoe_percpu_s *p = arg;
546 + struct fc_lport *lp;
547 + struct fcoe_rcv_info *fr;
548 + struct fcoe_dev_stats *stats;
549 + struct fc_frame_header *fh;
550 + struct sk_buff *skb;
551 + struct fcoe_crc_eof *cp;
553 + struct fc_frame *fp;
555 + struct fcoe_softc *fc;
556 + struct fcoe_hdr *hp;
558 + set_user_nice(current, 19);
560 + while (!kthread_should_stop()) {
562 + spin_lock_bh(&p->fcoe_rx_list.lock);
563 + while ((skb = __skb_dequeue(&p->fcoe_rx_list)) == NULL) {
564 + set_current_state(TASK_INTERRUPTIBLE);
565 + spin_unlock_bh(&p->fcoe_rx_list.lock);
567 + set_current_state(TASK_RUNNING);
568 + if (kthread_should_stop())
570 + spin_lock_bh(&p->fcoe_rx_list.lock);
572 + spin_unlock_bh(&p->fcoe_rx_list.lock);
573 + fr = fcoe_dev_from_skb(skb);
575 + if (unlikely(lp == NULL)) {
576 + FC_DBG("invalid HBA Structure");
581 + stats = lp->dev_stats[smp_processor_id()];
583 + if (unlikely(debug_fcoe)) {
584 + FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p "
585 + "tail:%p end:%p sum:%d dev:%s",
586 + skb->len, skb->data_len,
587 + skb->head, skb->data, skb_tail_pointer(skb),
588 + skb_end_pointer(skb), skb->csum,
589 + skb->dev ? skb->dev->name : "<NULL>");
593 + * Save source MAC address before discarding header.
596 + if (unlikely(fc->flogi_progress))
597 + mac = eth_hdr(skb)->h_source;
599 + if (skb_is_nonlinear(skb))
600 + skb_linearize(skb); /* not ideal */
603 + * Check the header and pull it off.
605 + hlen = sizeof(struct fcoe_hdr);
607 + hp = (struct fcoe_hdr *)skb->data;
608 + if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
609 + if (stats->ErrorFrames < 5)
610 + FC_DBG("unknown FCoE version %x",
611 + FC_FCOE_DECAPS_VER(hp));
612 + stats->ErrorFrames++;
616 + sof = hp->fcoe_sof;
617 + skb_pull(skb, sizeof(*hp));
618 + fr_len = skb->len - sizeof(struct fcoe_crc_eof);
619 + skb_trim(skb, fr_len);
620 + tlen = sizeof(struct fcoe_crc_eof);
622 + if (unlikely(fr_len > skb->len)) {
623 + if (stats->ErrorFrames < 5)
624 + FC_DBG("length error fr_len 0x%x skb->len 0x%x",
626 + stats->ErrorFrames++;
631 + stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
633 + fp = (struct fc_frame *) skb;
635 + cp = (struct fcoe_crc_eof *)(skb->data + fr_len);
636 + fr_eof(fp) = cp->fcoe_eof;
641 + * Check the CRC here, unless it's solicited data for SCSI.
642 + * In that case, the SCSI layer can check it during the copy,
643 + * and it'll be more cache-efficient.
645 + fh = fc_frame_header_get(fp);
646 + if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
647 + fh->fh_type == FC_TYPE_FCP) {
648 + fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
649 + fc_exch_recv(lp, lp->emp, fp);
650 + } else if (le32_to_cpu(cp->fcoe_crc32) ==
651 + ~crc32(~0, skb->data, fr_len)) {
652 + if (unlikely(fc->flogi_progress))
653 + fcoe_recv_flogi(fc, fp, mac);
654 + fc_exch_recv(lp, lp->emp, fp);
656 + if (debug_fcoe || stats->InvalidCRCCount < 5) {
657 + printk(KERN_WARNING \
658 + "fcoe: dropping frame with CRC error");
660 + stats->InvalidCRCCount++;
661 + stats->ErrorFrames++;
669 + * Snoop potential response to FLOGI or even incoming FLOGI.
671 +static void fcoe_recv_flogi(struct fcoe_softc *fc, struct fc_frame *fp, u8 *sa)
673 + struct fc_frame_header *fh;
676 + fh = fc_frame_header_get(fp);
677 + if (fh->fh_type != FC_TYPE_ELS)
679 + op = fc_frame_payload_op(fp);
680 + if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP &&
681 + fc->flogi_oxid == ntohs(fh->fh_ox_id)) {
684 + * If the src mac addr is FC_OUI-based, then we mark the
685 + * address_mode flag to use FC_OUI-based Ethernet DA.
686 + * Otherwise we use the FCoE gateway addr
688 + if (!compare_ether_addr(sa, (u8[6]) FC_FCOE_FLOGI_MAC)) {
689 + fc->address_mode = FCOE_FCOUI_ADDR_MODE;
691 + memcpy(fc->dest_addr, sa, ETH_ALEN);
692 + fc->address_mode = FCOE_GW_ADDR_MODE;
696 + * Remove any previously-set unicast MAC filter.
697 + * Add secondary FCoE MAC address filter for our OUI.
700 + if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 }))
701 + dev_unicast_delete(fc->real_dev, fc->data_src_addr,
703 + fc_fcoe_set_mac(fc->data_src_addr, fh->fh_d_id);
704 + dev_unicast_add(fc->real_dev, fc->data_src_addr, ETH_ALEN);
707 + fc->flogi_progress = 0;
708 + } else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) {
710 + * Save source MAC for point-to-point responses.
712 + memcpy(fc->dest_addr, sa, ETH_ALEN);
713 + fc->address_mode = FCOE_GW_ADDR_MODE;
717 +void fcoe_watchdog(ulong vp)
719 + struct fc_lport *lp;
720 + struct fcoe_softc *fc;
721 + struct fcoe_info *fci = &fcoei;
724 + read_lock(&fci->fcoe_hostlist_lock);
725 + list_for_each_entry(fc, &fci->fcoe_hostlist, list) {
728 + if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
730 + if (fcoe_check_wait_queue(lp) < FCOE_MAX_QUEUE_DEPTH) {
736 + read_unlock(&fci->fcoe_hostlist_lock);
738 + fci->timer.expires = jiffies + (1 * HZ);
739 + add_timer(&fci->timer);
743 + * the wait_queue is used when the skb transmit fails. skb will go
744 + * in the wait_queue which will be emptied by the time function OR
745 + * by the next skb transmit.
750 + * Function name : fcoe_check_wait_queue()
752 + * Return Values : 0 or error
754 + * Description : empties the wait_queue
755 + * dequeue the head of the wait_queue queue and
756 + * calls fcoe_start_io() for each packet
757 + * if all skb have been transmitted, return 0
758 + * if a error occurs, then restore wait_queue and try again
763 +static int fcoe_check_wait_queue(struct fc_lport *lp)
765 + int rc, unpause = 0;
767 + struct sk_buff *skb;
768 + struct fcoe_softc *fc;
770 + fc = (struct fcoe_softc *)lp->drv_priv;
771 + spin_lock_bh(&fc->fcoe_pending_queue.lock);
774 + * is this interface paused?
776 + if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
778 + if (fc->fcoe_pending_queue.qlen) {
779 + while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) {
780 + spin_unlock_bh(&fc->fcoe_pending_queue.lock);
781 + rc = fcoe_start_io(skb);
783 + fcoe_insert_wait_queue_head(lp, skb);
786 + spin_lock_bh(&fc->fcoe_pending_queue.lock);
788 + if (fc->fcoe_pending_queue.qlen < FCOE_MAX_QUEUE_DEPTH)
791 + spin_unlock_bh(&fc->fcoe_pending_queue.lock);
792 + if ((unpause) && (paused))
794 + return fc->fcoe_pending_queue.qlen;
797 +static void fcoe_insert_wait_queue_head(struct fc_lport *lp,
798 + struct sk_buff *skb)
800 + struct fcoe_softc *fc;
802 + fc = (struct fcoe_softc *)lp->drv_priv;
803 + spin_lock_bh(&fc->fcoe_pending_queue.lock);
804 + __skb_queue_head(&fc->fcoe_pending_queue, skb);
805 + spin_unlock_bh(&fc->fcoe_pending_queue.lock);
808 +static void fcoe_insert_wait_queue(struct fc_lport *lp,
809 + struct sk_buff *skb)
811 + struct fcoe_softc *fc;
813 + fc = (struct fcoe_softc *)lp->drv_priv;
814 + spin_lock_bh(&fc->fcoe_pending_queue.lock);
815 + __skb_queue_tail(&fc->fcoe_pending_queue, skb);
816 + spin_unlock_bh(&fc->fcoe_pending_queue.lock);
818 diff --git a/drivers/scsi/fcoe/fcoe_if.c b/drivers/scsi/fcoe/fcoe_if.c
820 index 0000000..7f983e2
822 +++ b/drivers/scsi/fcoe/fcoe_if.c
825 + * Copyright(c) 2007 Intel Corporation. All rights reserved.
827 + * This program is free software; you can redistribute it and/or modify it
828 + * under the terms and conditions of the GNU General Public License,
829 + * version 2, as published by the Free Software Foundation.
831 + * This program is distributed in the hope it will be useful, but WITHOUT
832 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
833 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
836 + * You should have received a copy of the GNU General Public License along with
837 + * this program; if not, write to the Free Software Foundation, Inc.,
838 + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
840 + * Maintained at www.Open-FCoE.org
844 + * FCOE protocol file
847 +#include <linux/module.h>
848 +#include <linux/version.h>
849 +#include <linux/kernel.h>
850 +#include <linux/init.h>
851 +#include <linux/spinlock.h>
852 +#include <linux/netdevice.h>
853 +#include <linux/etherdevice.h>
854 +#include <linux/ethtool.h>
855 +#include <linux/if_ether.h>
856 +#include <linux/if_vlan.h>
857 +#include <net/rtnetlink.h>
859 +#include <scsi/fc/fc_els.h>
860 +#include <scsi/fc/fc_encaps.h>
861 +#include <scsi/fc/fc_fs.h>
862 +#include <scsi/scsi_transport.h>
863 +#include <scsi/scsi_transport_fc.h>
865 +#include <scsi/libfc/libfc.h>
867 +#include <scsi/fc/fc_fcoe.h>
868 +#include "fcoe_def.h"
870 +#define FCOE_VERSION "0.1"
872 +#define FCOE_MAX_LUN 255
873 +#define FCOE_MAX_FCP_TARGET 256
875 +#define FCOE_MIN_XID 0x0004
876 +#define FCOE_MAX_XID 0x07ef
880 +struct fcoe_info fcoei = {
881 + .fcoe_hostlist = LIST_HEAD_INIT(fcoei.fcoe_hostlist),
884 +static struct fcoe_softc *fcoe_find_fc_lport(const char *name)
886 + struct fcoe_softc *fc;
887 + struct fc_lport *lp;
888 + struct fcoe_info *fci = &fcoei;
890 + read_lock(&fci->fcoe_hostlist_lock);
891 + list_for_each_entry(fc, &fci->fcoe_hostlist, list) {
893 + if (!strncmp(name, lp->ifname, IFNAMSIZ)) {
894 + read_unlock(&fci->fcoe_hostlist_lock);
898 + read_unlock(&fci->fcoe_hostlist_lock);
903 + * Convert 48-bit IEEE MAC address to 64-bit FC WWN.
905 +static u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN],
906 + unsigned int scheme, unsigned int port)
911 + /* The MAC is in NO, so flip only the low 48 bits */
912 + host_mac = ((u64) mac[0] << 40) |
913 + ((u64) mac[1] << 32) |
914 + ((u64) mac[2] << 24) |
915 + ((u64) mac[3] << 16) |
916 + ((u64) mac[4] << 8) |
919 + WARN_ON(host_mac >= (1ULL << 48));
920 + wwn = host_mac | ((u64) scheme << 60);
923 + WARN_ON(port != 0);
926 + WARN_ON(port >= 0xfff);
927 + wwn |= (u64) port << 48;
937 +static struct scsi_host_template fcoe_driver_template = {
938 + .module = THIS_MODULE,
939 + .name = "FCoE Driver",
940 + .proc_name = FCOE_DRIVER_NAME,
941 + .queuecommand = fc_queuecommand,
942 + .eh_abort_handler = fc_eh_abort,
943 + .eh_device_reset_handler = fc_eh_device_reset,
944 + .eh_host_reset_handler = fc_eh_host_reset,
945 + .slave_alloc = fc_slave_alloc,
946 + .change_queue_depth = fc_change_queue_depth,
947 + .change_queue_type = fc_change_queue_type,
950 + .can_queue = FC_MAX_OUTSTANDING_COMMANDS,
951 + .use_clustering = ENABLE_CLUSTERING,
953 + .max_sectors = 0xffff,
956 +int fcoe_destroy_interface(const char *ifname)
959 + struct fcoe_dev_stats *p;
960 + struct fcoe_percpu_s *pp;
961 + struct fcoe_softc *fc;
962 + struct fcoe_rcv_info *fr;
963 + struct fcoe_info *fci = &fcoei;
964 + struct sk_buff_head *list;
965 + struct sk_buff *skb, *next;
966 + struct sk_buff *head;
967 + struct fc_lport *lp;
968 + u8 flogi_maddr[ETH_ALEN];
970 + fc = fcoe_find_fc_lport(ifname);
976 + /* Remove the instance from fcoe's list */
977 + write_lock_bh(&fci->fcoe_hostlist_lock);
978 + list_del(&fc->list);
979 + write_unlock_bh(&fci->fcoe_hostlist_lock);
981 + /* Cleanup the fc_lport */
982 + fc_lport_destroy(lp);
983 + fc_fcp_destroy(lp);
985 + fc_exch_mgr_free(lp->emp);
987 + /* Detach from the scsi-ml */
988 + fc_remove_host(lp->host);
989 + scsi_remove_host(lp->host);
991 + /* Don't listen for Ethernet packets anymore */
992 + dev_remove_pack(&fc->fcoe_packet_type);
994 + /* Delete secondary MAC addresses */
996 + memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
997 + dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN);
998 + if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 }))
999 + dev_unicast_delete(fc->real_dev, fc->data_src_addr, ETH_ALEN);
1002 + /* Free the per-CPU revieve threads */
1003 + for (idx = 0; idx < NR_CPUS; idx++) {
1004 + if (fci->fcoe_percpu[idx]) {
1005 + pp = fci->fcoe_percpu[idx];
1006 + spin_lock_bh(&pp->fcoe_rx_list.lock);
1007 + list = &pp->fcoe_rx_list;
1008 + head = list->next;
1009 + for (skb = head; skb != (struct sk_buff *)list;
1012 + fr = fcoe_dev_from_skb(skb);
1013 + if (fr->fr_dev == fc->lp) {
1014 + __skb_unlink(skb, list);
1018 + spin_unlock_bh(&pp->fcoe_rx_list.lock);
1022 + /* Free existing skbs */
1023 + fcoe_clean_pending_queue(lp);
1025 + /* Free memory used by statistical counters */
1026 + for_each_online_cpu(cpu) {
1027 + p = lp->dev_stats[cpu];
1029 + lp->dev_stats[cpu] = NULL;
1034 + /* Release the net_device and Scsi_Host */
1035 + dev_put(fc->real_dev);
1036 + scsi_host_put(lp->host);
1041 + * Return zero if link is OK for use by FCoE.
1042 + * Any permanently-disqualifying conditions have been previously checked.
1043 + * This also updates the speed setting, which may change with link for 100/1000.
1045 + * This function should probably be checking for PAUSE support at some point
1046 + * in the future. Currently Per-priority-pause is not determinable using
1047 + * ethtool, so we shouldn't be restrictive until that problem is resolved.
1049 +int fcoe_link_ok(struct fc_lport *lp)
1051 + struct fcoe_softc *fc = (struct fcoe_softc *)lp->drv_priv;
1052 + struct net_device *dev = fc->real_dev;
1053 + struct ethtool_cmd ecmd = { ETHTOOL_GSET };
1056 + if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) {
1057 + dev = fc->phys_dev;
1058 + if (dev->ethtool_ops->get_settings) {
1059 + dev->ethtool_ops->get_settings(dev, &ecmd);
1060 + lp->link_supported_speeds &=
1061 + ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
1062 + if (ecmd.supported & (SUPPORTED_1000baseT_Half |
1063 + SUPPORTED_1000baseT_Full))
1064 + lp->link_supported_speeds |= FC_PORTSPEED_1GBIT;
1065 + if (ecmd.supported & SUPPORTED_10000baseT_Full)
1066 + lp->link_supported_speeds |=
1067 + FC_PORTSPEED_10GBIT;
1068 + if (ecmd.speed == SPEED_1000)
1069 + lp->link_speed = FC_PORTSPEED_1GBIT;
1070 + if (ecmd.speed == SPEED_10000)
1071 + lp->link_speed = FC_PORTSPEED_10GBIT;
1079 +static struct libfc_function_template fcoe_libfc_fcn_templ = {
1080 + .frame_send = fcoe_xmit,
1083 +static int lport_config(struct fc_lport *lp, struct Scsi_Host *shost)
1086 + struct fcoe_dev_stats *p;
1089 + lp->drv_priv = (void *)(lp + 1);
1091 + lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3,
1092 + FCOE_MIN_XID, FCOE_MAX_XID);
1096 + lp->link_status = 0;
1097 + lp->max_retry_count = 3;
1098 + lp->e_d_tov = 2 * 1000; /* FC-FS default */
1099 + lp->r_a_tov = 2 * 2 * 1000;
1100 + lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
1101 + FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL);
1104 + * allocate per cpu stats block
1106 + for_each_online_cpu(i) {
1107 + p = kzalloc(sizeof(struct fcoe_dev_stats), GFP_KERNEL);
1109 + lp->dev_stats[i] = p;
1112 + /* Finish fc_lport configuration */
1113 + fc_lport_config(lp);
1118 +static int net_config(struct fc_lport *lp)
1122 + struct net_device *net_dev;
1123 + struct fcoe_softc *fc = (struct fcoe_softc *)lp->drv_priv;
1124 + u8 flogi_maddr[ETH_ALEN];
1126 + /* Require support for get_pauseparam ethtool op. */
1127 + net_dev = fc->real_dev;
1128 + if (!net_dev->ethtool_ops && (net_dev->priv_flags & IFF_802_1Q_VLAN))
1129 + net_dev = vlan_dev_real_dev(net_dev);
1130 + if (!net_dev->ethtool_ops || !net_dev->ethtool_ops->get_pauseparam)
1131 + return -EOPNOTSUPP;
1133 + fc->phys_dev = net_dev;
1135 + /* Do not support for bonding device */
1136 + if ((fc->real_dev->priv_flags & IFF_MASTER_ALB) ||
1137 + (fc->real_dev->priv_flags & IFF_SLAVE_INACTIVE) ||
1138 + (fc->real_dev->priv_flags & IFF_MASTER_8023AD)) {
1139 + return -EOPNOTSUPP;
1143 + * Determine max frame size based on underlying device and optional
1144 + * user-configured limit. If the MFS is too low, fcoe_link_ok()
1145 + * will return 0, so do this first.
1147 + mfs = fc->real_dev->mtu - (sizeof(struct fcoe_hdr) +
1148 + sizeof(struct fcoe_crc_eof));
1149 + fc_set_mfs(lp, mfs);
1151 + lp->link_status = ~FC_PAUSE & ~FC_LINK_UP;
1152 + if (!fcoe_link_ok(lp))
1153 + lp->link_status |= FC_LINK_UP;
1155 + if (fc->real_dev->features & NETIF_F_SG)
1156 + lp->capabilities = TRANS_C_SG;
1159 + skb_queue_head_init(&fc->fcoe_pending_queue);
1161 + memcpy(lp->ifname, fc->real_dev->name, IFNAMSIZ);
1163 + /* setup Source Mac Address */
1164 + memcpy(fc->ctl_src_addr, fc->real_dev->dev_addr,
1165 + fc->real_dev->addr_len);
1167 + wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0);
1168 + fc_set_wwnn(lp, wwnn);
1169 + /* XXX - 3rd arg needs to be vlan id */
1170 + wwpn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 2, 0);
1171 + fc_set_wwpn(lp, wwpn);
1174 + * Add FCoE MAC address as second unicast MAC address
1175 + * or enter promiscuous mode if not capable of listening
1176 + * for multiple unicast MACs.
1179 + memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
1180 + dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN);
1184 + * setup the receive function from ethernet driver
1185 + * on the ethertype for the given device
1187 + fc->fcoe_packet_type.func = fcoe_rcv;
1188 + fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE);
1189 + fc->fcoe_packet_type.dev = fc->real_dev;
1190 + dev_add_pack(&fc->fcoe_packet_type);
1195 +static void shost_config(struct fc_lport *lp)
1197 + lp->host->max_lun = FCOE_MAX_LUN;
1198 + lp->host->max_id = FCOE_MAX_FCP_TARGET;
1199 + lp->host->max_channel = 0;
1200 + lp->host->transportt = fcoe_transport_template;
1203 +static int libfc_config(struct fc_lport *lp)
1205 + /* Set the function pointers set by the LLDD */
1206 + memcpy(&lp->tt, &fcoe_libfc_fcn_templ,
1207 + sizeof(struct libfc_function_template));
1209 + if (fc_fcp_init(lp))
1212 + fc_lport_init(lp);
1213 + fc_rport_init(lp);
1221 + * This function creates the fcoe interface
1222 + * create struct fcdev which is a shared structure between opefc
1223 + * and transport level protocol.
1225 +int fcoe_create_interface(const char *ifname)
1227 + struct fc_lport *lp = NULL;
1228 + struct fcoe_softc *fc;
1229 + struct net_device *net_dev;
1230 + struct Scsi_Host *shost;
1231 + struct fcoe_info *fci = &fcoei;
1234 + net_dev = dev_get_by_name(&init_net, ifname);
1235 + if (net_dev == NULL) {
1236 + FC_DBG("could not get network device for %s",
1241 + if (fcoe_find_fc_lport(net_dev->name) != NULL) {
1246 + shost = scsi_host_alloc(&fcoe_driver_template,
1247 + sizeof(struct fc_lport) +
1248 + sizeof(struct fcoe_softc));
1251 + FC_DBG("Could not allocate host structure\n");
1256 + lp = shost_priv(shost);
1257 + rc = lport_config(lp, shost);
1259 + goto out_host_put;
1261 + /* Configure the fcoe_softc */
1262 + fc = (struct fcoe_softc *)lp->drv_priv;
1264 + fc->real_dev = net_dev;
1268 + /* Add the new host to the SCSI-ml */
1269 + rc = scsi_add_host(lp->host, NULL);
1271 + FC_DBG("error on scsi_add_host\n");
1272 + goto out_lp_destroy;
1275 + sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s",
1276 + FCOE_DRIVER_NAME, FCOE_VERSION,
1279 + /* Configure netdev and networking properties of the lp */
1280 + rc = net_config(lp);
1282 + goto out_lp_destroy;
1284 + /* Initialize the library */
1285 + rc = libfc_config(lp);
1287 + goto out_lp_destroy;
1289 + write_lock_bh(&fci->fcoe_hostlist_lock);
1290 + list_add_tail(&fc->list, &fci->fcoe_hostlist);
1291 + write_unlock_bh(&fci->fcoe_hostlist_lock);
1293 + lp->boot_time = jiffies;
1295 + fc_fabric_login(lp);
1300 + fc_exch_mgr_free(lp->emp); /* Free the EM */
1302 + scsi_host_put(lp->host);
1308 +void fcoe_clean_pending_queue(struct fc_lport *lp)
1310 + struct fcoe_softc *fc = lp->drv_priv;
1311 + struct sk_buff *skb;
1313 + spin_lock_bh(&fc->fcoe_pending_queue.lock);
1314 + while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) {
1315 + spin_unlock_bh(&fc->fcoe_pending_queue.lock);
1317 + spin_lock_bh(&fc->fcoe_pending_queue.lock);
1319 + spin_unlock_bh(&fc->fcoe_pending_queue.lock);
1321 diff --git a/drivers/scsi/fcoe/fcoeinit.c b/drivers/scsi/fcoe/fcoeinit.c
1322 new file mode 100644
1323 index 0000000..e069835
1325 +++ b/drivers/scsi/fcoe/fcoeinit.c
1328 + * Copyright(c) 2007 Intel Corporation. All rights reserved.
1330 + * This program is free software; you can redistribute it and/or modify it
1331 + * under the terms and conditions of the GNU General Public License,
1332 + * version 2, as published by the Free Software Foundation.
1334 + * This program is distributed in the hope it will be useful, but WITHOUT
1335 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1336 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
1339 + * You should have received a copy of the GNU General Public License along with
1340 + * this program; if not, write to the Free Software Foundation, Inc.,
1341 + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
1343 + * Maintained at www.Open-FCoE.org
1346 +#include <linux/module.h>
1347 +#include <linux/version.h>
1348 +#include <linux/kernel.h>
1349 +#include <linux/kthread.h>
1350 +#include <linux/spinlock.h>
1351 +#include <linux/cpu.h>
1352 +#include <linux/netdevice.h>
1353 +#include <linux/etherdevice.h>
1354 +#include <linux/ethtool.h>
1355 +#include <linux/if_ether.h>
1356 +#include <linux/fs.h>
1357 +#include <linux/sysfs.h>
1358 +#include <linux/ctype.h>
1360 +#include <scsi/libfc/libfc.h>
1362 +#include "fcoe_def.h"
1364 +MODULE_AUTHOR("Open-FCoE.org");
1365 +MODULE_DESCRIPTION("FCoE");
1366 +MODULE_LICENSE("GPL");
1369 + * Static functions and variables definations
1371 +#ifdef CONFIG_HOTPLUG_CPU
1372 +static int fcoe_cpu_callback(struct notifier_block *, ulong, void *);
1373 +#endif /* CONFIG_HOTPLUG_CPU */
1374 +static int fcoe_device_notification(struct notifier_block *, ulong, void *);
1375 +static void fcoe_dev_setup(void);
1376 +static void fcoe_dev_cleanup(void);
1378 +struct scsi_transport_template *fcoe_transport_template;
1380 +static int fcoe_reset(struct Scsi_Host *shost)
1382 + struct fc_lport *lp = shost_priv(shost);
1383 + fc_lport_enter_reset(lp);
1387 +struct fc_function_template fcoe_transport_function = {
1388 + .show_host_node_name = 1,
1389 + .show_host_port_name = 1,
1390 + .show_host_supported_classes = 1,
1391 + .show_host_supported_fc4s = 1,
1392 + .show_host_active_fc4s = 1,
1393 + .show_host_maxframe_size = 1,
1395 + .get_host_port_id = fc_get_host_port_id,
1396 + .show_host_port_id = 1,
1397 + .get_host_speed = fc_get_host_speed,
1398 + .show_host_speed = 1,
1399 + .get_host_port_type = fc_get_host_port_type,
1400 + .show_host_port_type = 1,
1401 + .get_host_port_state = fc_get_host_port_state,
1402 + .show_host_port_state = 1,
1403 + .show_host_symbolic_name = 1,
1405 + .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv),
1406 + .show_rport_maxframe_size = 1,
1407 + .show_rport_supported_classes = 1,
1409 + .get_host_fabric_name = fc_get_host_fabric_name,
1410 + .show_host_fabric_name = 1,
1411 + .show_starget_node_name = 1,
1412 + .show_starget_port_name = 1,
1413 + .show_starget_port_id = 1,
1414 + .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo,
1415 + .show_rport_dev_loss_tmo = 1,
1416 + .get_fc_host_stats = fc_get_host_stats,
1417 + .issue_fc_host_lip = fcoe_reset,
1420 +struct fcoe_percpu_s *fcoe_percpu[NR_CPUS];
1422 +#ifdef CONFIG_HOTPLUG_CPU
1423 +static struct notifier_block fcoe_cpu_notifier = {
1424 + .notifier_call = fcoe_cpu_callback,
1426 +#endif /* CONFIG_HOTPLUG_CPU */
1429 + * notification function from net device
1431 +static struct notifier_block fcoe_notifier = {
1432 + .notifier_call = fcoe_device_notification,
1435 +#ifdef CONFIG_HOTPLUG_CPU
1437 + * create percpu stats block
1438 + * called by cpu add/remove notifier
1440 +static void fcoe_create_percpu_data(int cpu)
1442 + struct fc_lport *lp;
1443 + struct fcoe_softc *fc;
1444 + struct fcoe_dev_stats *p;
1445 + struct fcoe_info *fci = &fcoei;
1447 + write_lock_bh(&fci->fcoe_hostlist_lock);
1448 + list_for_each_entry(fc, &fci->fcoe_hostlist, list) {
1450 + if (lp->dev_stats[cpu] == NULL) {
1451 + p = kzalloc(sizeof(struct fcoe_dev_stats), GFP_KERNEL);
1453 + lp->dev_stats[cpu] = p;
1456 + write_unlock_bh(&fci->fcoe_hostlist_lock);
1460 + * destroy percpu stats block
1461 + * called by cpu add/remove notifier
1463 +static void fcoe_destroy_percpu_data(int cpu)
1465 + struct fcoe_dev_stats *p;
1466 + struct fc_lport *lp;
1467 + struct fcoe_softc *fc;
1468 + struct fcoe_info *fci = &fcoei;
1470 + write_lock_bh(&fci->fcoe_hostlist_lock);
1471 + list_for_each_entry(fc, &fci->fcoe_hostlist, list) {
1473 + p = lp->dev_stats[cpu];
1475 + lp->dev_stats[cpu] = NULL;
1479 + write_unlock_bh(&fci->fcoe_hostlist_lock);
1483 + * Get notified when a cpu comes on/off. Be hotplug friendly.
1485 +static int fcoe_cpu_callback(struct notifier_block *nfb, unsigned long action,
1488 + unsigned int cpu = (unsigned long)hcpu;
1492 + fcoe_create_percpu_data(cpu);
1495 + fcoe_destroy_percpu_data(cpu);
1502 +#endif /* CONFIG_HOTPLUG_CPU */
1505 + * function to setup link change notification interface
1507 +static void fcoe_dev_setup(void)
1510 + * here setup a interface specific wd time to
1511 + * monitor the link state
1513 + register_netdevice_notifier(&fcoe_notifier);
1517 + * function to cleanup link change notification interface
1519 +static void fcoe_dev_cleanup(void)
1521 + unregister_netdevice_notifier(&fcoe_notifier);
1525 + * This function is called by the ethernet driver
1526 + * this is called in case of link change event
1528 +static int fcoe_device_notification(struct notifier_block *notifier,
1529 + ulong event, void *ptr)
1531 + struct fc_lport *lp = NULL;
1532 + struct net_device *real_dev = ptr;
1533 + struct fcoe_softc *fc;
1534 + struct fcoe_dev_stats *stats;
1535 + struct fcoe_info *fci = &fcoei;
1538 + int rc = NOTIFY_OK;
1540 + read_lock(&fci->fcoe_hostlist_lock);
1541 + list_for_each_entry(fc, &fci->fcoe_hostlist, list) {
1542 + if (fc->real_dev == real_dev) {
1547 + read_unlock(&fci->fcoe_hostlist_lock);
1553 + new_status = lp->link_status;
1556 + case NETDEV_GOING_DOWN:
1557 + new_status &= ~FC_LINK_UP;
1560 + case NETDEV_CHANGE:
1561 + new_status &= ~FC_LINK_UP;
1562 + if (!fcoe_link_ok(lp))
1563 + new_status |= FC_LINK_UP;
1565 + case NETDEV_CHANGEMTU:
1566 + mfs = fc->real_dev->mtu -
1567 + (sizeof(struct fcoe_hdr) +
1568 + sizeof(struct fcoe_crc_eof));
1569 + if (fc->user_mfs && fc->user_mfs < mfs)
1570 + mfs = fc->user_mfs;
1571 + if (mfs >= FC_MIN_MAX_FRAME)
1572 + fc_set_mfs(lp, mfs);
1573 + new_status &= ~FC_LINK_UP;
1574 + if (!fcoe_link_ok(lp))
1575 + new_status |= FC_LINK_UP;
1577 + case NETDEV_REGISTER:
1580 + FC_DBG("unknown event %ld call", event);
1582 + if (lp->link_status != new_status) {
1583 + if ((new_status & FC_LINK_UP) == FC_LINK_UP)
1586 + stats = lp->dev_stats[smp_processor_id()];
1587 + stats->LinkFailureCount++;
1589 + fcoe_clean_pending_queue(lp);
1596 +static void trimstr(char *str, int len)
1598 + char *cp = str + len;
1599 + while (--cp >= str && *cp == '\n')
1603 +static ssize_t fcoe_destroy(struct kobject *kobj, struct kobj_attribute *attr,
1604 + const char *buffer, size_t size)
1607 + strcpy(ifname, buffer);
1608 + trimstr(ifname, strlen(ifname));
1609 + fcoe_destroy_interface(ifname);
1613 +static ssize_t fcoe_create(struct kobject *kobj, struct kobj_attribute *attr,
1614 + const char *buffer, size_t size)
1617 + strcpy(ifname, buffer);
1618 + trimstr(ifname, strlen(ifname));
1619 + fcoe_create_interface(ifname);
1623 +static const struct kobj_attribute fcoe_destroyattr = \
1624 + __ATTR(destroy, S_IWUSR, NULL, fcoe_destroy);
1625 +static const struct kobj_attribute fcoe_createattr = \
1626 + __ATTR(create, S_IWUSR, NULL, fcoe_create);
1629 + * Initialization routine
1630 + * 1. Will create fc transport software structure
1631 + * 2. initialize the link list of port information structure
1633 +static int __init fcoeinit(void)
1637 + struct fcoe_percpu_s *p;
1638 + struct fcoe_info *fci = &fcoei;
1640 + rc = sysfs_create_file(&THIS_MODULE->mkobj.kobj,
1641 + &fcoe_destroyattr.attr);
1643 + rc = sysfs_create_file(&THIS_MODULE->mkobj.kobj,
1644 + &fcoe_createattr.attr);
1649 + rwlock_init(&fci->fcoe_hostlist_lock);
1651 +#ifdef CONFIG_HOTPLUG_CPU
1652 + register_cpu_notifier(&fcoe_cpu_notifier);
1653 +#endif /* CONFIG_HOTPLUG_CPU */
1656 + * initialize per CPU interrupt thread
1658 + for_each_online_cpu(cpu) {
1659 + p = kzalloc(sizeof(struct fcoe_percpu_s), GFP_KERNEL);
1661 + p->thread = kthread_create(fcoe_percpu_receive_thread,
1663 + "fcoethread/%d", cpu);
1666 + * if there is no error then bind the thread to the cpu
1667 + * initialize the semaphore and skb queue head
1669 + if (likely(!IS_ERR(p->thread))) {
1671 + fci->fcoe_percpu[cpu] = p;
1672 + skb_queue_head_init(&p->fcoe_rx_list);
1673 + kthread_bind(p->thread, cpu);
1674 + wake_up_process(p->thread);
1676 + fci->fcoe_percpu[cpu] = NULL;
1683 + FC_DBG("failed to initialize proc intrerface\n");
1689 + * setup link change notification
1693 + init_timer(&fci->timer);
1694 + fci->timer.data = (ulong) fci;
1695 + fci->timer.function = fcoe_watchdog;
1696 + fci->timer.expires = (jiffies + (10 * HZ));
1697 + add_timer(&fci->timer);
1699 + fcoe_transport_template =
1700 + fc_attach_transport(&fcoe_transport_function);
1702 + if (fcoe_transport_template == NULL) {
1703 + FC_DBG("fail to attach fc transport");
1710 +#ifdef CONFIG_HOTPLUG_CPU
1711 + unregister_cpu_notifier(&fcoe_cpu_notifier);
1712 +#endif /* CONFIG_HOTPLUG_CPU */
1716 +static void __exit fcoe_exit(void)
1719 + struct fcoe_softc *fc, *tmp;
1720 + struct fc_lport *lp;
1721 + struct fcoe_info *fci = &fcoei;
1722 + struct fcoe_percpu_s *p;
1723 + struct sk_buff *skb;
1726 + * Stop all call back interfaces
1728 +#ifdef CONFIG_HOTPLUG_CPU
1729 + unregister_cpu_notifier(&fcoe_cpu_notifier);
1730 +#endif /* CONFIG_HOTPLUG_CPU */
1731 + fcoe_dev_cleanup();
1736 + del_timer_sync(&fci->timer);
1739 + * assuming that at this time there will be no
1740 + * ioctl in prograss, therefore we do not need to lock the
1743 + list_for_each_entry_safe(fc, tmp, &fci->fcoe_hostlist, list) {
1745 + fcoe_destroy_interface(lp->ifname);
1748 + for (idx = 0; idx < NR_CPUS; idx++) {
1749 + if (fci->fcoe_percpu[idx]) {
1750 + kthread_stop(fci->fcoe_percpu[idx]->thread);
1751 + p = fci->fcoe_percpu[idx];
1752 + spin_lock_bh(&p->fcoe_rx_list.lock);
1753 + while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL)
1755 + spin_unlock_bh(&p->fcoe_rx_list.lock);
1756 + if (fci->fcoe_percpu[idx]->crc_eof_page)
1757 + put_page(fci->fcoe_percpu[idx]->crc_eof_page);
1758 + kfree(fci->fcoe_percpu[idx]);
1762 + fc_release_transport(fcoe_transport_template);
1765 +module_init(fcoeinit);
1766 +module_exit(fcoe_exit);