Skip to contentSkip to conversation

FIP feature for 2.6.30 merge window

PATCH New Vasu Dev 1 participant 6 messages Mar 4, 2009

Subsystems (2)
lore
Share & tools
lore

Vasu Dev

author
#0 lore raw

cover FIP feature for 2.6.30 merge window

This patch set implements FCoE initialization protocol (FIP), see patch 2/5 for more details on FIP.

These patches are :

1. built on top of most recently submitted open-fcoe.org patches by Rob at http://marc.info/?l=linux-scsi&m=123576089125544&w=2

2. tested with open-fcoe.org fcoe-fixes git tree which is based on Linus's 2.6.29-rc6 tree, thus should apply to scsi-misc also.

---

Joe Eykholt (3):
fcoe: libfcoe: fix FIP link logic
fcoe: Add support for the FIP discovery and keep-alive protocol.
fcoe: Add a header file defining the FIP protocol for FCoE.

Vasu Dev (2):
fcoe: removes sharing of fcoe_rx_list for both FCoE and FIP frames
fcoe: removed kzalloc from fcoe_ctlr_parse_adv (v3)

 drivers/scsi/Kconfig             |   11 
 drivers/scsi/Makefile            |    1 
 drivers/scsi/fcoe/fcoe_sw.c      |   61 ++
 drivers/scsi/fcoe/libfcoe.c      |  167 ++---
 drivers/scsi/libfcoe/Makefile    |    6 
 drivers/scsi/libfcoe/fcoe_ctlr.c | 1238 ++++++++++++++++++++++++++++++++++++++
 include/scsi/fc/fc_fip.h         |  237 +++++++
 include/scsi/fcoe_ctlr.h         |  105 +++
 include/scsi/libfcoe.h           |   24 -
 9 files changed, 1716 insertions(+), 134 deletions(-)
 create mode 100644 drivers/scsi/libfcoe/Makefile
 create mode 100644 drivers/scsi/libfcoe/fcoe_ctlr.c
 create mode 100644 include/scsi/fc/fc_fip.h
 create mode 100644 include/scsi/fcoe_ctlr.h
Signature · 1 line
	Vasu
author
#1 lore raw

PATCH 1/5 fcoe: Add a header file defining the FIP protocol for FCoE.

From: Joe Eykholt <[email protected]>

---

 include/scsi/fc/fc_fip.h |  237 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 237 insertions(+), 0 deletions(-)
 create mode 100644 include/scsi/fc/fc_fip.h
include/scsi/fc/fc_fip.h new file +237 -0
new file mode 100644
index 0000000..dabf5a7
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2008 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _FC_FIP_H_
+#define _FC_FIP_H_
+
+/*
+ * This version is based on:
+ * http://www.t11.org/ftp/t11/pub/fc/bb-5/08-543v1.pdf
+ */
+
+/*
+ * The FIP ethertype eventually goes in net/if_ether.h.
+ */
+#ifndef ETH_P_FIP
+#define ETH_P_FIP	0x8914	/* FIP Ethertype */
+#endif
+
+#define FIP_DEF_PRI	128	/* default selection priority */
+#define FIP_DEF_FC_MAP	0x0efc00 /* default FCoE MAP (MAC OUI) value */
+#define FIP_DEF_FKA	8000	/* default FCF keep-alive/advert period (mS) */
+#define FIP_VN_KA_PERIOD 90000	/* required VN_port keep-alive period (mS) */
+#define FIP_FCF_FUZZ	100	/* random time added by FCF (mS) */
+
+/*
+ * Multicast MAC addresses.  T11-adopted.
+ */
+#define FIP_ALL_FCOE_MACS	((u8[6]) { 1, 0x10, 0x18, 1, 0, 0 })
+#define FIP_ALL_ENODE_MACS	((u8[6]) { 1, 0x10, 0x18, 1, 0, 1 })
+#define FIP_ALL_FCF_MACS	((u8[6]) { 1, 0x10, 0x18, 1, 0, 2 })
+
+#define FIP_VER		1		/* version for fip_header */
+
+struct fip_header {
+	__u8	fip_ver;		/* upper 4 bits are the version */
+	__u8	fip_resv1;		/* reserved */
+	__be16	fip_op;			/* operation code */
+	__u8	fip_resv2;		/* reserved */
+	__u8	fip_subcode;		/* lower 4 bits are sub-code */
+	__be16	fip_dl_len;		/* length of descriptors in words */
+	__be16	fip_flags;		/* header flags */
+} __attribute__((packed));
+
+#define FIP_VER_SHIFT	4
+#define FIP_VER_ENCAPS(v) ((v) << FIP_VER_SHIFT)
+#define FIP_VER_DECAPS(v) ((v) >> FIP_VER_SHIFT)
+#define FIP_BPW		4		/* bytes per word for lengths */
+
+/*
+ * fip_op.
+ */
+enum fip_opcode {
+	FIP_OP_DISC =	1,		/* discovery, advertisement, etc. */
+	FIP_OP_LS =	2,		/* Link Service request or reply */
+	FIP_OP_CTRL =	3,		/* Keep Alive / Link Reset */
+	FIP_OP_VLAN =	4,		/* VLAN discovery */
+	FIP_OP_VENDOR_MIN = 0xfff8,	/* min vendor-specific opcode */
+	FIP_OP_VENDOR_MAX = 0xfffe,	/* max vendor-specific opcode */
+};
+
+/*
+ * Subcodes for FIP_OP_DISC.
+ */
+enum fip_disc_subcode {
+	FIP_SC_SOL =	1,		/* solicitation */
+	FIP_SC_ADV =	2,		/* advertisement */
+};
+
+/*
+ * Subcodes for FIP_OP_LS.
+ */
+enum fip_trans_subcode {
+	FIP_SC_REQ =	1,		/* request */
+	FIP_SC_REP =	2,		/* reply */
+};
+
+/*
+ * Subcodes for FIP_OP_RESET.
+ */
+enum fip_reset_subcode {
+	FIP_SC_KEEP_ALIVE = 1,		/* keep-alive from VN_Port */
+	FIP_SC_CLR_VLINK = 2,		/* clear virtual link from VF_Port */
+};
+
+/*
+ * Subcodes for FIP_OP_VLAN.
+ */
+enum fip_vlan_subcode {
+	FIP_SC_VL_REQ =	1,		/* request */
+	FIP_SC_VL_REP =	2,		/* reply */
+};
+
+/*
+ * flags in header fip_flags.
+ */
+enum fip_flag {
+	FIP_FL_FPMA =	0x8000,		/* supports FPMA fabric-provided MACs */
+	FIP_FL_SPMA =	0x4000,		/* supports SPMA server-provided MACs */
+	FIP_FL_AVAIL =	0x0004,		/* available for FLOGI/ELP */
+	FIP_FL_SOL =	0x0002,		/* this is a solicited message */
+	FIP_FL_FPORT =	0x0001,		/* sent from an F port */
+};
+
+/*
+ * Common descriptor header format.
+ */
+struct fip_desc {
+	__u8	fip_dtype;		/* type - see below */
+	__u8	fip_dlen;		/* length - in 32-bit words */
+};
+
+enum fip_desc_type {
+	FIP_DT_PRI =	1,		/* priority for forwarder selection */
+	FIP_DT_MAC =	2,		/* MAC address */
+	FIP_DT_MAP_OUI = 3,		/* FC-MAP OUI */
+	FIP_DT_NAME =	4,		/* switch name or node name */
+	FIP_DT_FAB =	5,		/* fabric descriptor */
+	FIP_DT_FCOE_SIZE = 6,		/* max FCoE frame size */
+	FIP_DT_FLOGI =	7,		/* FLOGI request or response */
+	FIP_DT_FDISC =	8,		/* FDISC request or response */
+	FIP_DT_LOGO =	9,		/* LOGO request or response */
+	FIP_DT_ELP =	10,		/* ELP request or response */
+	FIP_DT_VN_ID =	11,		/* VN_Node Identifier */
+	FIP_DT_FKA =	12,		/* advertisement keep-alive period */
+	FIP_DT_VENDOR =	13,		/* vendor ID */
+	FIP_DT_VLAN =	14,		/* vlan number */
+	FIP_DT_LIMIT,			/* max defined desc_type + 1 */
+	FIP_DT_VENDOR_BASE = 128,	/* first vendor-specific desc_type */
+};
+
+/*
+ * FIP_DT_PRI - priority descriptor.
+ */
+struct fip_pri_desc {
+	struct fip_desc fd_desc;
+	__u8		fd_resvd;
+	__u8		fd_pri;		/* FCF priority:  higher is better */
+} __attribute__((packed));
+
+/*
+ * FIP_DT_MAC - MAC address descriptor.
+ */
+struct fip_mac_desc {
+	struct fip_desc fd_desc;
+	__u8		fd_mac[ETH_ALEN];
+} __attribute__((packed));
+
+/*
+ * FIP_DT_MAP - descriptor.
+ */
+struct fip_map_desc {
+	struct fip_desc fd_desc;
+	__u8		fd_resvd[3];
+	__u8		fd_map[3];
+} __attribute__((packed));
+
+/*
+ * FIP_DT_NAME descriptor.
+ */
+struct fip_wwn_desc {
+	struct fip_desc fd_desc;
+	__u8		fd_resvd[2];
+	__be32		fd_wwn[2];	/* 64-bit value, only 32-bit aligned */
+} __attribute__((packed));
+
+/*
+ * FIP_DT_FAB descriptor.
+ */
+struct fip_fab_desc {
+	struct fip_desc fd_desc;
+	__be16		fd_vfid;	/* virtual fabric ID */
+	__u8		fd_resvd;
+	__u8		fd_map[3];	/* FC-MAP value */
+	__be32		fd_wwn[2];	/* fabric name */
+} __attribute__((packed));
+
+/*
+ * FIP_DT_FCOE_SIZE descriptor.
+ */
+struct fip_size_desc {
+	struct fip_desc fd_desc;
+	__be16		fd_size;
+} __attribute__((packed));
+
+/*
+ * Descriptor that encapsulates an ELS or ILS frame.
+ * The encapsulated frame immediately follows this header, without
+ * SOF, EOF, or CRC.
+ */
+struct fip_encaps {
+	struct fip_desc fd_desc;
+	__u8		fd_resvd[2];
+} __attribute__((packed));
+
+/*
+ * FIP_DT_VN_ID - VN_Node Identifier descriptor.
+ */
+struct fip_vn_desc {
+	struct fip_desc fd_desc;
+	__u8		fd_mac[ETH_ALEN];
+	__u8		fd_resvd;
+	__u8		fd_fc_id[3];
+	__be32		fd_wwpn[2];
+} __attribute__((packed));
+
+/*
+ * FIP_DT_FKA - Advertisement keep-alive period.
+ */
+struct fip_fka_desc {
+	struct fip_desc fd_desc;
+	__u8		fd_resvd[2];
+	__be32		fd_fka_period;	/* adv./keep-alive period in mS */
+} __attribute__((packed));
+
+/*
+ * FIP_DT_VENDOR descriptor.
+ */
+struct fip_vendor_desc {
+	struct fip_desc fd_desc;
+	__u8		fd_resvd[2];
+	__u8		fd_vendor_id[8];
+} __attribute__((packed));
+
+#endif /* _FC_FIP_H_ */
author
#2 lore raw

PATCH 2/5 fcoe: Add support for the FIP discovery and keep-alive protocol.

In reply to Vasu Dev

From: Joe Eykholt <[email protected]>

FIP is the new standard way to discover Fibre-Channel Forwarders (FCFs). It involves sending solicitations and listening for advertisements from FCFs. It also provides for keep-alives and period advertisements so that both parties know they have connectivity. If the FCF loses connectivity to the storage fabric, it can send a Link Reset to inform the E_node.

This version is also compatible with pre-FIP implementations, so no configured selection between FIP mode and non-FIP mode is required.

We wait a couple seconds after sending the initial solicitation and then send an old-style FLOGI. If we receive any FIP frames, we use FIP only mode. If the old FLOGI receives a response, we disable FIP mode. After every reset or link up, this determination is repeated.

---

 drivers/scsi/Kconfig             |   11 
 drivers/scsi/Makefile            |    1 
 drivers/scsi/fcoe/fcoe_sw.c      |   61 ++
 drivers/scsi/fcoe/libfcoe.c      |  159 ++---
 drivers/scsi/libfcoe/Makefile    |    6 
 drivers/scsi/libfcoe/fcoe_ctlr.c | 1206 ++++++++++++++++++++++++++++++++++++++
 include/scsi/fc_frame.h          |    1 
 include/scsi/fcoe_ctlr.h         |  103 +++
 include/scsi/libfcoe.h           |   24 -
 9 files changed, 1453 insertions(+), 119 deletions(-)
 create mode 100644 drivers/scsi/libfcoe/Makefile
 create mode 100644 drivers/scsi/libfcoe/fcoe_ctlr.c
 create mode 100644 include/scsi/fcoe_ctlr.h
drivers/scsi/Kconfig +10 -1
index 256c7be..2e7c05e 100644
@@ -611,10 +611,19 @@ config LIBFC
 	---help---
 	  Fibre Channel library module
 
+config LIBFCOE
+	tristate "LibFCoE module"
+	depends on SCSI
+	select LIBFC
+	---help---
+	  This contains support routines needed for FCoE HBAs and the
+	  FCoE module.  It is normally unnecessary to configure this separately,
+	  it is selected by the modules that require it.
+
 config FCOE
 	tristate "FCoE module"
 	depends on PCI
-	select LIBFC
+	select LIBFCOE
 	---help---
 	  Fibre Channel over Ethernet module
 
drivers/scsi/Makefile +1 -0
index 7461eb0..95e2bc0 100644
@@ -37,6 +37,7 @@ obj-$(CONFIG_SCSI_SRP_ATTRS)	+= scsi_transport_srp.o
 obj-$(CONFIG_SCSI_DH)		+= device_handler/
 
 obj-$(CONFIG_LIBFC)		+= libfc/
+obj-$(CONFIG_LIBFCOE)		+= libfcoe/
 obj-$(CONFIG_FCOE)		+= fcoe/
 obj-$(CONFIG_ISCSI_TCP) 	+= libiscsi.o	libiscsi_tcp.o iscsi_tcp.o
 obj-$(CONFIG_INFINIBAND_ISER) 	+= libiscsi.o
drivers/scsi/fcoe/fcoe_sw.c +52 -9

124 lines not on this page · raw message

drivers/scsi/fcoe/libfcoe.c +61 -98

279 lines not on this page · raw message

drivers/scsi/libfcoe/Makefile new file +6 -0
new file mode 100644
index 0000000..46e91da
@@ -0,0 +1,6 @@
+# $Id: Makefile
+
+obj-$(CONFIG_LIBFCOE) += libfcoe.o
+
+libfcoe-y := \
+	fcoe_ctlr.o
drivers/scsi/libfcoe/fcoe_ctlr.c new file +1206 -0

1,206 lines not on this page · raw message

include/scsi/fc_frame.h +1 -0
index 04d34a7..0c982a4 100644
@@ -88,6 +88,7 @@ static inline struct fcoe_rcv_info *fcoe_dev_from_skb(const struct sk_buff *skb)
  * fr_flags.
  */
 #define	FCPHF_CRC_UNCHECKED	0x01	/* CRC not computed, still appended */
+#define	FCPHF_FIP		0x02	/* FIP protocol not FC */
 
 /*
  * Initialize a frame.
include/scsi/fcoe_ctlr.h new file +103 -0

103 lines not on this page · raw message

include/scsi/libfcoe.h +13 -11
index 941818f..0c10982 100644
@@ -24,6 +24,7 @@
 #include <linux/skbuff.h>
 #include <scsi/fc/fc_fcoe.h>
 #include <scsi/libfc.h>
+#include <scsi/fcoe_ctlr.h>
 
 /*
  * this percpu struct for fcoe
@@ -41,24 +42,23 @@ struct fcoe_percpu_s {
  */
 struct fcoe_softc {
 	struct list_head list;
-	struct fc_lport *lp;
 	struct net_device *real_dev;
 	struct net_device *phys_dev;		/* device with ethtool_ops */
 	struct packet_type  fcoe_packet_type;
+	struct packet_type fip_packet_type;
 	struct sk_buff_head fcoe_pending_queue;
 	u8	fcoe_pending_queue_active;
-
-	u8 dest_addr[ETH_ALEN];
-	u8 ctl_src_addr[ETH_ALEN];
-	u8 data_src_addr[ETH_ALEN];
-	/*
-	 * fcoe protocol address learning related stuff
-	 */
-	u16 flogi_oxid;
-	u8 flogi_progress;
-	u8 address_mode;
+	struct fcoe_ctlr ctlr;
 };
 
+#define fcoe_from_ctlr(fc) container_of(fc, struct fcoe_softc, ctlr)
+
+static inline struct fcoe_softc *fcoe_softc(
+	const struct fc_lport *lp)
+{
+	return (struct fcoe_softc *)lport_priv(lp);
+}
+
 static inline struct net_device *fcoe_netdev(
 	const struct fc_lport *lp)
 {
@@ -156,6 +156,8 @@ int fcoe_percpu_receive_thread(void *arg);
 void fcoe_clean_pending_queue(struct fc_lport *lp);
 void fcoe_percpu_clean(struct fc_lport *lp);
 void fcoe_watchdog(ulong vp);
+int fcoe_fip_recv(struct sk_buff *, struct net_device *,
+	     struct packet_type *, struct net_device *);
 int fcoe_link_ok(struct fc_lport *lp);
 
 struct fc_lport *fcoe_hostlist_lookup(const struct net_device *);
author
#3 lore raw

PATCH 3/5 fcoe: libfcoe: fix FIP link logic

In reply to Vasu Dev

From: Joe Eykholt <[email protected]>

FIP now controls whether the lport sees the link as up or not, since the fabric connectivity not may exist even if the link is up. So, the LLD (fcoe) should not depend on the lport->link_up info to decide whether to report a link change to FIP.

The logic to control the link change has been moved into FIP and under the fcoe_ctlr lock. So that only true link changes cause statistics increments, fcoe_ctlr_stop() returns non-zero if it is a "true" link drop so that the LLD can increment statistics appropriately.

---

 drivers/scsi/fcoe/libfcoe.c |   26 ++++++++++----------------
 1 files changed, 10 insertions(+), 16 deletions(-)
drivers/scsi/fcoe/libfcoe.c +10 -16
index 42aa7d5..90d0136 100644
@@ -793,7 +793,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 	struct net_device *real_dev = ptr;
 	struct fcoe_softc *fc;
 	struct fcoe_dev_stats *stats;
-	u32 new_link_up;
+	u32 link_possible = 1;
 	u32 mfs;
 	int rc = NOTIFY_OK;
 
@@ -810,15 +810,13 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 		goto out;
 	}
 
-	new_link_up = lp->link_up;
 	switch (event) {
 	case NETDEV_DOWN:
 	case NETDEV_GOING_DOWN:
-		new_link_up = 0;
+		link_possible = 0;
 		break;
 	case NETDEV_UP:
 	case NETDEV_CHANGE:
-		new_link_up = !fcoe_link_ok(lp);
 		break;
 	case NETDEV_CHANGEMTU:
 		mfs = fc->real_dev->mtu -
@@ -826,23 +824,19 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 			 sizeof(struct fcoe_crc_eof));
 		if (mfs >= FC_MIN_MAX_FRAME)
 			fc_set_mfs(lp, mfs);
-		new_link_up = !fcoe_link_ok(lp);
 		break;
 	case NETDEV_REGISTER:
 		break;
 	default:
-		FC_DBG("unknown event %ld call", event);
+		FC_DBG("Unknown event %ld from netdev netlink\n", event);
 	}
-	if (lp->link_up != new_link_up) {
-		if (new_link_up)
-			fcoe_ctlr_start(&fc->ctlr);
-		else {
-			stats = lp->dev_stats[smp_processor_id()];
-			if (stats)
-				stats->LinkFailureCount++;
-			fcoe_ctlr_stop(&fc->ctlr);
-			fcoe_clean_pending_queue(lp);
-		}
+	if (link_possible && !fcoe_link_ok(lp))
+		fcoe_ctlr_start(&fc->ctlr);
+	else if (fcoe_ctlr_stop(&fc->ctlr)) {
+		stats = lp->dev_stats[smp_processor_id()];
+		if (stats)
+			stats->LinkFailureCount++;
+		fcoe_clean_pending_queue(lp);
 	}
 out:
 	return rc;
author
#4 lore raw

PATCH 4/5 fcoe: removed kzalloc from fcoe_ctlr_parse_adv (v3)

In reply to Vasu Dev

This patch eliminates fcoe_fcf memory allocation in fcoe_ctlr_parse_adv for each incoming advertisement by having fcoe_ctlr_parse_adv caller provide the fcoe_fcf pointer for parsing. The only current caller fcoe_ctlr_recv_adv allocates fcoe_fcf memory only when a new FCF needs to be added to the FCFs list.

Modified fcoe_ctlr_parse_adv ret value to int and fcoe_ctlr_recv_adv call
flow accordingly around fcoe_ctlr_parse_adv calling.

---

 drivers/scsi/libfcoe/fcoe_ctlr.c |   67 +++++++++++++++++++-------------------
 1 files changed, 33 insertions(+), 34 deletions(-)
drivers/scsi/libfcoe/fcoe_ctlr.c +33 -34
index 42a67e0..d5a411b 100644
@@ -558,11 +558,13 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
 
 /*
  * Decode a FIP advertisement into a new FCF entry.
+ *
+ * Returns zero on a valid parsed advertisement,
+ * otherwise returns non zero value.
  */
-static struct fcoe_fcf *fcoe_ctlr_parse_adv(struct sk_buff *skb)
+static int fcoe_ctlr_parse_adv(struct sk_buff *skb, struct fcoe_fcf *fcf)
 {
 	struct fip_header *fiph;
-	struct fcoe_fcf *fcf;
 	struct fip_desc *desc = NULL;
 	struct fip_wwn_desc *wwn;
 	struct fip_fab_desc *fab;
@@ -571,9 +573,7 @@ static struct fcoe_fcf *fcoe_ctlr_parse_adv(struct sk_buff *skb)
 	size_t rlen;
 	size_t dlen;
 
-	fcf = kzalloc(sizeof(*fcf), GFP_ATOMIC);
-	if (!fcf)
-		return fcf;
+	memset(fcf, 0, sizeof(*fcf));
 	fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA);
 
 	fiph = (struct fip_header *)skb->data;
@@ -581,13 +581,13 @@ static struct fcoe_fcf *fcoe_ctlr_parse_adv(struct sk_buff *skb)
 
 	rlen = ntohs(fiph->fip_dl_len) * 4;
 	if (rlen + sizeof(*fiph) > skb->len)
-		goto bad_adv;
+		return -EINVAL;
 
 	desc = (struct fip_desc *)(fiph + 1);
 	while (rlen > 0) {
 		dlen = desc->fip_dlen * FIP_BPW;
 		if (dlen < sizeof(*desc) || dlen > rlen)
-			goto bad_adv;
+			return -EINVAL;
 		switch (desc->fip_dtype) {
 		case FIP_DT_PRI:
 			if (dlen != sizeof(struct fip_pri_desc))
@@ -602,7 +602,7 @@ static struct fcoe_fcf *fcoe_ctlr_parse_adv(struct sk_buff *skb)
 			       ETH_ALEN);
 			if (!is_valid_ether_addr(fcf->fcf_mac)) {
 				FIP_DBG("invalid MAC addr in FIP adv\n");
-				goto bad_adv;
+				return -EINVAL;
 			}
 			break;
 		case FIP_DT_NAME:
@@ -638,24 +638,22 @@ static struct fcoe_fcf *fcoe_ctlr_parse_adv(struct sk_buff *skb)
 				  desc->fip_dtype);
 			/* standard says ignore unknown descriptors >= 128 */
 			if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
-				goto bad_adv;
+				return -EINVAL;
 			continue;
 		}
 		desc = (struct fip_desc *)((char *)desc + dlen);
 		rlen -= dlen;
 	}
 	if (!fcf->fc_map || (fcf->fc_map & 0x10000))
-		goto bad_adv;
+		return -EINVAL;
 	if (!fcf->switch_name || !fcf->fabric_name)
-		goto bad_adv;
-	return fcf;
+		return -EINVAL;
+	return 0;
 
 len_err:
 	FIP_DBG("FIP length error in descriptor type %x len %zu\n",
 		  desc->fip_dtype, dlen);
-bad_adv:
-	kfree(fcf);
-	return NULL;
+	return -EINVAL;
 }
 
 /*
@@ -664,54 +662,54 @@ bad_adv:
 static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
 {
 	struct fcoe_fcf *fcf;
-	struct fcoe_fcf *new;
+	struct fcoe_fcf new;
 	struct fcoe_fcf *found;
 	unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV);
 	int first = 0;
 	int mtu_valid;
 
-	new = fcoe_ctlr_parse_adv(skb);
-	if (!new)
+	if (fcoe_ctlr_parse_adv(skb, &new))
 		return;
 
 	spin_lock_bh(&fip->lock);
 	first = list_empty(&fip->fcfs);
 	found = NULL;
 	list_for_each_entry(fcf, &fip->fcfs, list) {
-		if (fcf->switch_name == new->switch_name &&
-		    fcf->fabric_name == new->fabric_name &&
-		    fcf->fc_map == new->fc_map &&
-		    compare_ether_addr(fcf->fcf_mac, new->fcf_mac) == 0) {
+		if (fcf->switch_name == new.switch_name &&
+		    fcf->fabric_name == new.fabric_name &&
+		    fcf->fc_map == new.fc_map &&
+		    compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) {
 			found = fcf;
 			break;
 		}
 	}
 	if (!found) {
-		if (fip->fcf_count >= FCOE_CTLR_FCF_LIMIT) {
-			spin_unlock_bh(&fip->lock);
-			kfree(new);
-			return;
-		}
+		if (fip->fcf_count >= FCOE_CTLR_FCF_LIMIT)
+			goto out;
+
+		fcf = kmalloc(sizeof(*fcf), GFP_ATOMIC);
+		if (!fcf)
+			goto out;
+
 		fip->fcf_count++;
-		fcf = new;
+		memcpy(fcf, &new, sizeof(new));
 		list_add(&fcf->list, &fip->fcfs);
 	} else {
 		/*
 		 * Once we've received a solicited advertisement, we should
 		 * ignore the flags from multicast advertisments.
 		 */
-		if ((new->flags & FIP_FL_SOL) || !(fcf->flags & FIP_FL_SOL))
-			fcf->flags = new->flags;
+		if ((new.flags & FIP_FL_SOL) || !(fcf->flags & FIP_FL_SOL))
+			fcf->flags = new.flags;
 
 		if (fcf == fip->sel_fcf) {
 			fip->ctlr_ka_time -= fcf->fka_period;
-			fip->ctlr_ka_time += new->fka_period;
+			fip->ctlr_ka_time += new.fka_period;
 			if (time_before(fip->ctlr_ka_time, fip->timer.expires))
 				mod_timer(&fip->timer, fip->ctlr_ka_time);
 		}
-		fcf->fka_period = new->fka_period;
-		memcpy(fcf->fcf_mac, new->fcf_mac, ETH_ALEN);
-		kfree(new);
+		fcf->fka_period = new.fka_period;
+		memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN);
 	}
 	mtu_valid = fcoe_ctlr_mtu_valid(fcf);
 	fcf->time = jiffies;
@@ -746,6 +744,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
 		    time_before(fip->sel_time, fip->timer.expires))
 			mod_timer(&fip->timer, fip->sel_time);
 	}
+out:
 	spin_unlock_bh(&fip->lock);
 }
 
author
#5 lore raw

PATCH 5/5 fcoe: removes sharing of fcoe_rx_list for both FCoE and FIP frames

In reply to Vasu Dev

Creates separate recv path for incoming FIP frames instead sharing same fcoe_rx_list for both FCoE and FIP incoming frames and then catching FIP frames from fcoe_percpu_receive_thread using FCPHF_FIP flag to call fcoe_ctlr_recv.

Removed FCPHF_FIP and its checking in fast path.

Instead added separate fip_recv_list and modified fcoe_ctlr_recv to only add incoming FIP frames to this list and then schedule added new recv_work function fcoe_ctlr_recv_work to do rest of the incoming frame processing same as what older fcoe_ctlr_recv use to do, added fcoe_ctlr_recv_handler is called from fcoe_ctlr_recv_work for each incoming FIP frame in work thread context for rest of the incoming FIP frame processing.

Now fcoe_ctlr_recv is directly called from fcoe_fip_recv function and modified fcoe_fip_recv simply calls fcoe_ctlr_recv after retrieving fcoe_ctlr, so fcoe_fip_recv could be completely removed later if similar to this func or fcoe_ctlr_recv is directly registered by FIP code.

Any pending fcoe_ctlr_recv_work is flushed when interface is destroyed.

---

 drivers/scsi/fcoe/libfcoe.c      |   20 ++------------------
 drivers/scsi/libfcoe/fcoe_ctlr.c |   37 +++++++++++++++++++++++++++++++++++--
 include/scsi/fc_frame.h          |    1 -
 include/scsi/fcoe_ctlr.h         |    4 +++-
 4 files changed, 40 insertions(+), 22 deletions(-)
drivers/scsi/fcoe/libfcoe.c +2 -18
index 90d0136..34b41a9 100644
@@ -270,20 +270,9 @@ int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,
 		  struct net_device *orig_dev)
 {
 	struct fcoe_softc *fc;
-	struct fcoe_rcv_info *fr;
-	struct fcoe_percpu_s *fps;
 
 	fc = container_of(ptype, struct fcoe_softc, fip_packet_type);
-	fr = fcoe_dev_from_skb(skb);
-	fr->fr_dev = fc->ctlr.lp;
-	fr->fr_flags = FCPHF_FIP;
-
-	fps = fcoe_percpu[smp_processor_id()];
-	spin_lock_bh(&fps->fcoe_rx_list.lock);
-	__skb_queue_tail(&fps->fcoe_rx_list, skb);
-	if (fps->fcoe_rx_list.qlen == 1)
-		wake_up_process(fps->thread);
-	spin_unlock_bh(&fps->fcoe_rx_list.lock);
+	fcoe_ctlr_recv(&fc->ctlr, skb);
 	return 0;
 }
 
@@ -568,12 +557,6 @@ int fcoe_percpu_receive_thread(void *arg)
 			kfree_skb(skb);
 			continue;
 		}
-		fc = fcoe_softc(lp);
-		if (fr->fr_flags & FCPHF_FIP) {
-			fcoe_ctlr_recv(&fc->ctlr, skb);
-			continue;
-		}
-
 		stats = lp->dev_stats[smp_processor_id()];
 
 		if (unlikely(debug_fcoe)) {
@@ -664,6 +647,7 @@ int fcoe_percpu_receive_thread(void *arg)
 			}
 			fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
 		}
+		fc = fcoe_softc(lp);
 		if (unlikely(fc->ctlr.flogi_oxid != FC_XID_UNKNOWN) &&
 		    fcoe_ctlr_recv_flogi(&fc->ctlr, fp, mac)) {
 			fc_frame_free(fp);
drivers/scsi/libfcoe/fcoe_ctlr.c +35 -2
index d5a411b..9956083 100644
@@ -49,6 +49,7 @@ MODULE_LICENSE("GPL");
 
 static void fcoe_ctlr_timeout(unsigned long);
 static void fcoe_ctlr_work(struct work_struct *);
+static void fcoe_ctlr_recv_work(struct work_struct *);
 
 static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS;
 
@@ -101,6 +102,8 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip)
 	fip->flogi_oxid = FC_XID_UNKNOWN;
 	setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
 	INIT_WORK(&fip->work, fcoe_ctlr_work);
+	INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work);
+	skb_queue_head_init(&fip->fip_recv_list);
 }
 EXPORT_SYMBOL(fcoe_ctlr_init);
 
@@ -127,6 +130,7 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip)
  */
 void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
 {
+	flush_work(&fip->recv_work);
 	spin_lock_bh(&fip->lock);
 	fip->state = FIP_ST_DISABLED;
 	fcoe_ctlr_reset_fcfs(fip);
@@ -939,7 +943,19 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
  * Receive a FIP frame.
  * This is called from NET_RX_SOFTIRQ.
  */
-int fcoe_ctlr_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
+void fcoe_ctlr_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
+{
+	spin_lock_bh(&fip->fip_recv_list.lock);
+	__skb_queue_tail(&fip->fip_recv_list, skb);
+	spin_unlock_bh(&fip->fip_recv_list.lock);
+	schedule_work(&fip->recv_work);
+}
+EXPORT_SYMBOL(fcoe_ctlr_recv);
+
+/*
+ * Receive a FIP frame.
+ */
+static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
 {
 	struct fip_header *fiph;
 	struct ethhdr *eh;
@@ -994,7 +1010,6 @@ drop:
 	kfree_skb(skb);
 	return -1;
 }
-EXPORT_SYMBOL(fcoe_ctlr_recv);
 
 /*
  * Choose the best FCF, if possible.
@@ -1139,6 +1154,24 @@ static void fcoe_ctlr_work(struct work_struct *work)
 }
 
 /*
+ * Worker function to process received FIP frames.
+ */
+static void fcoe_ctlr_recv_work(struct work_struct *recv_work)
+{
+	struct fcoe_ctlr *fip;
+	struct sk_buff *skb;
+
+	fip = container_of(recv_work, struct fcoe_ctlr, recv_work);
+	spin_lock_bh(&fip->fip_recv_list.lock);
+	while ((skb = __skb_dequeue(&fip->fip_recv_list))) {
+		spin_unlock_bh(&fip->fip_recv_list.lock);
+		fcoe_ctlr_recv_handler(fip, skb);
+		spin_lock_bh(&fip->fip_recv_list.lock);
+	}
+	spin_unlock_bh(&fip->fip_recv_list.lock);
+}
+
+/*
  * Pre-FIP FCoE-encapsulated FLOGI receive.
  *
  * Snoop potential response to FLOGI or even incoming FLOGI.
include/scsi/fc_frame.h +0 -1
index 0c982a4..04d34a7 100644
@@ -88,7 +88,6 @@ static inline struct fcoe_rcv_info *fcoe_dev_from_skb(const struct sk_buff *skb)
  * fr_flags.
  */
 #define	FCPHF_CRC_UNCHECKED	0x01	/* CRC not computed, still appended */
-#define	FCPHF_FIP		0x02	/* FIP protocol not FC */
 
 /*
  * Initialize a frame.
include/scsi/fcoe_ctlr.h +3 -1
index 6312f60..954110c 100644
@@ -56,6 +56,8 @@ struct fcoe_ctlr {
 	unsigned long ctlr_ka_time;	/* time of next ctlr keep-alive */
 	struct timer_list timer;
 	struct work_struct work;
+	struct work_struct recv_work;
+	struct sk_buff_head fip_recv_list;
 	u16 user_mfs;			/* configured max frame size */
 	u16 flogi_oxid;			/* FLOGI OX_ID */
 	u8 flogi_count;			/* number of FLOGI attempts */
@@ -97,7 +99,7 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *);
 void fcoe_ctlr_start(struct fcoe_ctlr *);
 int fcoe_ctlr_stop(struct fcoe_ctlr *);
 int fcoe_ctlr_els_send(struct fcoe_ctlr *, struct sk_buff *);
-int fcoe_ctlr_recv(struct fcoe_ctlr *, struct sk_buff *);
+void fcoe_ctlr_recv(struct fcoe_ctlr *, struct sk_buff *);
 int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *, struct fc_frame *fp, u8 *sa);
 
 #endif /* _FCOE_CTLR_H_ */