Skip to contentSkip to conversation

Open-FCoE Features for 2.6.32

PATCH New Robert Love 1 participant 23 messages Jul 30, 2009

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover Open-FCoE Features for 2.6.32

The following series contains the first set of features for libfc, libfcoe and fcoe.

The largest change is to share an Exchange Manager amongst virtual interfaces (VLANs) on a physical interface. This will change will also help with NPIV support which should come in a later patch set.

Other than that, there are a lot of miscellaneous fixes and improvements to all three modules.

---

Joe Eykholt (10):
libfc: fix: cancel rport retry timer
libfc: fc_rport_logoff should not drop the lock
libfc: rename rport state "NONE" to "DELETE".
libfc: fix WARNING from fc_seq_start_next on closed exchanges
libfc: in fc_lport_destroy, flush rports after turning off link
libfc: stop login after fabric logoff
libfc: rename lport NONE state to DISABLED
fcoe: stop delivery of received frames before doing lport_destroy()
libfc: change debug messages to give host number.
libfc: remove extra semicolons from debug macros

Robert Love (1):
libfc: Remove the FC_EM_DBG macro

Vasu Dev (5):
fcoe: removes phys_dev and renames real_dev to netdev.
fcoe, libfc: adds offload EM per eth device with only single xid range per EM
fcoe: modifies fcoe_hostlist_lock uses as prep work to add shared offload EM fcoe, fnic, libfc: modifies current code paths to use EM anchor list fcoe, libfc: adds exchange manager(EM) anchor list per lport and related APIs

Yi Zou (6):
libfc: Remove page flags check for sglist
libfc: Remove FC_FRAME_SG_LEN in fc_fcp_send_data
fcoe: Remove ifdef for NETIF_F_FCOE_CRC and NETIF_F_FSO
fcoe: Call dev_ethtool_get_settings() in fcoe_link_ok
libfcoe: Set fip_flags according to fcf and lport's capability of SPMA support
fcoe: Fix validation of mac address when checking for spma support

 drivers/scsi/fcoe/fcoe.c      |  250 +++++++++++++++++++-----------
 drivers/scsi/fcoe/fcoe.h      |    8 -
 drivers/scsi/fcoe/libfcoe.c   |   14 +-
 drivers/scsi/fnic/fnic_fcs.c  |    2 
 drivers/scsi/fnic/fnic_main.c |   20 +-
 drivers/scsi/libfc/fc_exch.c  |  337 ++++++++++++++++++++++-------------------
 drivers/scsi/libfc/fc_fcp.c   |   29 ----
 drivers/scsi/libfc/fc_lport.c |   61 ++++++-
 drivers/scsi/libfc/fc_rport.c |   83 ++++++----
 include/scsi/fc_frame.h       |    7 -
 include/scsi/libfc.h          |  126 +++++++--------
 11 files changed, 518 insertions(+), 419 deletions(-)
Signature · 1 line
//Rob
#1 lore raw

PATCH 1/22 fcoe: Fix validation of mac address when checking for spma support

From: Yi Zou <[email protected]>

Fix this bug of validating the wrong mac address while checking for SAN MAC address support from LLD as we should check ha->addr not ctlr.ctl_src_addr.

---

 drivers/scsi/fcoe/fcoe.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/scsi/fcoe/fcoe.c +1 -1
index 0a5609b..b7dfc6e 100644
@@ -329,7 +329,7 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
 	rcu_read_lock();
 	for_each_dev_addr(netdev, ha) {
 		if ((ha->type == NETDEV_HW_ADDR_T_SAN) &&
-		    (is_valid_ether_addr(fc->ctlr.ctl_src_addr))) {
+		    (is_valid_ether_addr(ha->addr))) {
 			memcpy(fc->ctlr.ctl_src_addr, ha->addr, ETH_ALEN);
 			fc->ctlr.spma = 1;
 			break;
#2 lore raw

PATCH 2/22 libfcoe: Set fip_flags according to fcf and lport's capability of SPMA support

In reply to Robert Love

From: Yi Zou <[email protected]>

When encap the els for FIP, set the fip_flags according to the FCF and lport's capability of supporting SPMA or FPMA or both.

---

 drivers/scsi/fcoe/libfcoe.c |   12 +++++++++---
 1 files changed, 9 insertions(+), 3 deletions(-)
drivers/scsi/fcoe/libfcoe.c +9 -3
index d6ed3f8..78caa6b 100644
@@ -413,10 +413,18 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,
 	struct fip_mac_desc *mac;
 	struct fcoe_fcf *fcf;
 	size_t dlen;
+	u16 fip_flags;
 
 	fcf = fip->sel_fcf;
 	if (!fcf)
 		return -ENODEV;
+
+	/* set flags according to both FCF and lport's capability on SPMA */
+	fip_flags = fcf->flags;
+	fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA : FIP_FL_FPMA;
+	if (!fip_flags)
+		return -ENODEV;
+
 	dlen = sizeof(struct fip_encaps) + skb->len;	/* len before push */
 	cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap));
 
@@ -429,9 +437,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,
 	cap->fip.fip_op = htons(FIP_OP_LS);
 	cap->fip.fip_subcode = FIP_SC_REQ;
 	cap->fip.fip_dl_len = htons((dlen + sizeof(*mac)) / FIP_BPW);
-	cap->fip.fip_flags = htons(FIP_FL_FPMA);
-	if (fip->spma)
-		cap->fip.fip_flags |= htons(FIP_FL_SPMA);
+	cap->fip.fip_flags = htons(fip_flags);
 
 	cap->encaps.fd_desc.fip_dtype = dtype;
 	cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;
#3 lore raw

PATCH 3/22 fcoe: Call dev_ethtool_get_settings() in fcoe_link_ok

In reply to Robert Love

From: Yi Zou <[email protected]>

No need to check phys_dev here, just call dev_ethtool_get_settings() directly will take care of this.

---

 drivers/scsi/fcoe/fcoe.c |   38 +++++++++++++++++---------------------
 1 files changed, 17 insertions(+), 21 deletions(-)
drivers/scsi/fcoe/fcoe.c +17 -21
index b7dfc6e..8160126 100644
@@ -1635,29 +1635,25 @@ int fcoe_link_ok(struct fc_lport *lp)
 	struct fcoe_softc *fc = lport_priv(lp);
 	struct net_device *dev = fc->real_dev;
 	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-	int rc = 0;
 
-	if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) {
-		dev = fc->phys_dev;
-		if (dev->ethtool_ops->get_settings) {
-			dev->ethtool_ops->get_settings(dev, &ecmd);
-			lp->link_supported_speeds &=
-				~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
-			if (ecmd.supported & (SUPPORTED_1000baseT_Half |
-					      SUPPORTED_1000baseT_Full))
-				lp->link_supported_speeds |= FC_PORTSPEED_1GBIT;
-			if (ecmd.supported & SUPPORTED_10000baseT_Full)
-				lp->link_supported_speeds |=
-					FC_PORTSPEED_10GBIT;
-			if (ecmd.speed == SPEED_1000)
-				lp->link_speed = FC_PORTSPEED_1GBIT;
-			if (ecmd.speed == SPEED_10000)
-				lp->link_speed = FC_PORTSPEED_10GBIT;
-		}
-	} else
-		rc = -1;
+	if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
+	    (!dev_ethtool_get_settings(dev, &ecmd))) {
+		lp->link_supported_speeds &=
+			~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
+		if (ecmd.supported & (SUPPORTED_1000baseT_Half |
+				      SUPPORTED_1000baseT_Full))
+			lp->link_supported_speeds |= FC_PORTSPEED_1GBIT;
+		if (ecmd.supported & SUPPORTED_10000baseT_Full)
+			lp->link_supported_speeds |=
+				FC_PORTSPEED_10GBIT;
+		if (ecmd.speed == SPEED_1000)
+			lp->link_speed = FC_PORTSPEED_1GBIT;
+		if (ecmd.speed == SPEED_10000)
+			lp->link_speed = FC_PORTSPEED_10GBIT;
 
-	return rc;
+		return 0;
+	}
+	return -1;
 }
 
 /**
#4 lore raw

PATCH 4/22 libfc: remove extra semicolons from debug macros

In reply to Robert Love

From: Joe Eykholt <[email protected]>

This is unlikely to cause any problems, but the libfc debug macros introduce extra undesirable semicolons.

---

 include/scsi/libfc.h |   20 ++++++++++----------
 1 files changed, 10 insertions(+), 10 deletions(-)
include/scsi/libfc.h +10 -10
index b92584a..ef04a2c 100644
@@ -51,22 +51,22 @@ do {								\
 		do {						\
 			CMD;					\
 		} while (0);					\
-} while (0);
+} while (0)
 
 #define FC_LIBFC_DBG(fmt, args...)					\
 	FC_CHECK_LOGGING(FC_LIBFC_LOGGING,				\
-			 printk(KERN_INFO "libfc: " fmt, ##args);)
+			 printk(KERN_INFO "libfc: " fmt, ##args))
 
 #define FC_LPORT_DBG(lport, fmt, args...)				\
 	FC_CHECK_LOGGING(FC_LPORT_LOGGING,				\
 			 printk(KERN_INFO "lport: %6x: " fmt,		\
-				fc_host_port_id(lport->host), ##args);)
+				fc_host_port_id(lport->host), ##args))
 
 #define FC_DISC_DBG(disc, fmt, args...)					\
 	FC_CHECK_LOGGING(FC_DISC_LOGGING,				\
 			 printk(KERN_INFO "disc: %6x: " fmt,		\
 				fc_host_port_id(disc->lport->host),	\
-				##args);)
+				##args))
 
 #define FC_RPORT_DBG(rport, fmt, args...)				\
 do {									\
@@ -75,31 +75,31 @@ do {									\
 	FC_CHECK_LOGGING(FC_RPORT_LOGGING,				\
 			 printk(KERN_INFO "rport: %6x: %6x: " fmt,	\
 				fc_host_port_id(lport->host),		\
-				rport->port_id, ##args);)		\
-} while (0);
+				rport->port_id, ##args));		\
+} while (0)
 
 #define FC_FCP_DBG(pkt, fmt, args...)					\
 	FC_CHECK_LOGGING(FC_FCP_LOGGING,				\
 			 printk(KERN_INFO "fcp: %6x: %6x: " fmt,	\
 				fc_host_port_id(pkt->lp->host),		\
-				pkt->rport->port_id, ##args);)
+				pkt->rport->port_id, ##args))
 
 #define FC_EM_DBG(em, fmt, args...)					\
 	FC_CHECK_LOGGING(FC_EM_LOGGING,					\
 			 printk(KERN_INFO "em: %6x: " fmt,		\
 				fc_host_port_id(em->lp->host),		\
-				##args);)
+				##args))
 
 #define FC_EXCH_DBG(exch, fmt, args...)					\
 	FC_CHECK_LOGGING(FC_EXCH_LOGGING,				\
 			 printk(KERN_INFO "exch: %6x: %4x: " fmt,	\
 				fc_host_port_id(exch->lp->host),	\
-				exch->xid, ##args);)
+				exch->xid, ##args))
 
 #define FC_SCSI_DBG(lport, fmt, args...)				\
 	FC_CHECK_LOGGING(FC_SCSI_LOGGING,                               \
 			 printk(KERN_INFO "scsi: %6x: " fmt,		\
-				fc_host_port_id(lport->host), ##args);)
+				fc_host_port_id(lport->host), ##args))
 
 /*
  * libfc error codes
#5 lore raw

PATCH 5/22 libfc: change debug messages to give host number.

In reply to Robert Love

From: Joe Eykholt <[email protected]>

libfc debug messages currently show 'lport: <fc-id>:' wher <fc-id> is the hex assigned port-id. When the lport is logged off, that will be zero, so its hard to distinguish which instance is involved. The FC-ID can change if the port is re-patched or changes VSANs.

Two lports may even have the same FC-ID if connected to isolated SANs.

Change the debug messages to print the SCSI host number "hostN:", which will not change for the life of the lport.
Still show the FC_ID on lport messages.

Also, add a macro to FC_RPORT_ID_DBG for rport debugging where there's no rdata structure involved. It takes the lport and port_id as parameters. Use this in fc_rport_recv_plogi_req() and fc_rport_recv_logo_req().

---

 include/scsi/libfc.h |   36 ++++++++++++++++++++----------------
 1 files changed, 20 insertions(+), 16 deletions(-)
include/scsi/libfc.h +20 -16
index ef04a2c..efdb6ba 100644
@@ -59,47 +59,51 @@ do {								\
 
 #define FC_LPORT_DBG(lport, fmt, args...)				\
 	FC_CHECK_LOGGING(FC_LPORT_LOGGING,				\
-			 printk(KERN_INFO "lport: %6x: " fmt,		\
-				fc_host_port_id(lport->host), ##args))
+			 printk(KERN_INFO "host%u: lport %6x: " fmt,	\
+				(lport)->host->host_no,			\
+				fc_host_port_id((lport)->host), ##args))
 
 #define FC_DISC_DBG(disc, fmt, args...)					\
 	FC_CHECK_LOGGING(FC_DISC_LOGGING,				\
-			 printk(KERN_INFO "disc: %6x: " fmt,		\
-				fc_host_port_id(disc->lport->host),	\
+			 printk(KERN_INFO "host%u: disc: " fmt,		\
+				(disc)->lport->host->host_no,		\
 				##args))
 
+#define FC_RPORT_ID_DBG(lport, port_id, fmt, args...)			\
+	FC_CHECK_LOGGING(FC_RPORT_LOGGING,				\
+			 printk(KERN_INFO "host%u: rport %6x: " fmt,	\
+				(lport)->host->host_no,			\
+				(port_id), ##args))
+
 #define FC_RPORT_DBG(rport, fmt, args...)				\
 do {									\
 	struct fc_rport_libfc_priv *rdata = rport->dd_data;		\
 	struct fc_lport *lport = rdata->local_port;			\
-	FC_CHECK_LOGGING(FC_RPORT_LOGGING,				\
-			 printk(KERN_INFO "rport: %6x: %6x: " fmt,	\
-				fc_host_port_id(lport->host),		\
-				rport->port_id, ##args));		\
+	FC_RPORT_ID_DBG(lport, rport->port_id, fmt, ##args);		\
 } while (0)
 
 #define FC_FCP_DBG(pkt, fmt, args...)					\
 	FC_CHECK_LOGGING(FC_FCP_LOGGING,				\
-			 printk(KERN_INFO "fcp: %6x: %6x: " fmt,	\
-				fc_host_port_id(pkt->lp->host),		\
+			 printk(KERN_INFO "host%u: fcp: %6x: " fmt,	\
+				(pkt)->lp->host->host_no,		\
 				pkt->rport->port_id, ##args))
 
 #define FC_EM_DBG(em, fmt, args...)					\
 	FC_CHECK_LOGGING(FC_EM_LOGGING,					\
-			 printk(KERN_INFO "em: %6x: " fmt,		\
-				fc_host_port_id(em->lp->host),		\
+			 printk(KERN_INFO "host%u: em: " fmt,		\
+				(em)->lp->host->host_no,		\
 				##args))
 
 #define FC_EXCH_DBG(exch, fmt, args...)					\
 	FC_CHECK_LOGGING(FC_EXCH_LOGGING,				\
-			 printk(KERN_INFO "exch: %6x: %4x: " fmt,	\
-				fc_host_port_id(exch->lp->host),	\
+			 printk(KERN_INFO "host%u: xid %4x: " fmt,	\
+				(exch)->lp->host->host_no,		\
 				exch->xid, ##args))
 
 #define FC_SCSI_DBG(lport, fmt, args...)				\
 	FC_CHECK_LOGGING(FC_SCSI_LOGGING,                               \
-			 printk(KERN_INFO "scsi: %6x: " fmt,		\
-				fc_host_port_id(lport->host), ##args))
+			 printk(KERN_INFO "host%u: scsi: " fmt,		\
+				(lport)->host->host_no,	##args))
 
 /*
  * libfc error codes
#6 lore raw

PATCH 6/22 fcoe: stop delivery of received frames before doing lport_destroy()

In reply to Robert Love

From: Joe Eykholt <[email protected]>

To be more sure that no more input arrives at the local port as it is being destroyed, clean the queues in the per-cpu receive threads.

---

 drivers/scsi/fcoe/fcoe.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
drivers/scsi/fcoe/fcoe.c +3 -3
index 8160126..14a4017 100644
@@ -466,6 +466,9 @@ static int fcoe_if_destroy(struct net_device *netdev)
 	/* tear-down the FCoE controller */
 	fcoe_ctlr_destroy(&fc->ctlr);
 
+	/* Free queued packets for the per-CPU receive threads */
+	fcoe_percpu_clean(lp);
+
 	/* Cleanup the fc_lport */
 	fc_lport_destroy(lp);
 	fc_fcp_destroy(lp);
@@ -478,9 +481,6 @@ static int fcoe_if_destroy(struct net_device *netdev)
 	if (lp->emp)
 		fc_exch_mgr_free(lp->emp);
 
-	/* Free the per-CPU receive threads */
-	fcoe_percpu_clean(lp);
-
 	/* Free existing skbs */
 	fcoe_clean_pending_queue(lp);
 
#7 lore raw

PATCH 7/22 libfc: rename lport NONE state to DISABLED

In reply to Robert Love

From: Joe Eykholt <[email protected]>

The state NONE was meant to be invalid, but has been used as the initial state. Rename it to be DISABLED, as more descriptive. Further patches will make it the like the RESET state, except it won't transition to FLOGI until fc_lport_fabric_login() is called.

---

 drivers/scsi/libfc/fc_exch.c  |    2 +-
 drivers/scsi/libfc/fc_lport.c |   12 ++++++------
 include/scsi/libfc.h          |    2 +-
 3 files changed, 8 insertions(+), 8 deletions(-)
drivers/scsi/libfc/fc_exch.c +1 -1
index 145ab9b..e6d82d7 100644
@@ -1875,7 +1875,7 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp,
 	u32 f_ctl;
 
 	/* lport lock ? */
-	if (!lp || !mp || (lp->state == LPORT_ST_NONE)) {
+	if (!lp || !mp || lp->state == LPORT_ST_DISABLED) {
 		FC_LPORT_DBG(lp, "Receiving frames for an lport that "
 			     "has not been initialized correctly\n");
 		fc_frame_free(fp);
drivers/scsi/libfc/fc_lport.c +6 -6
index 745fa55..3b28190 100644
@@ -113,7 +113,7 @@ static void fc_lport_enter_ready(struct fc_lport *);
 static void fc_lport_enter_logo(struct fc_lport *);
 
 static const char *fc_lport_state_names[] = {
-	[LPORT_ST_NONE] =     "none",
+	[LPORT_ST_DISABLED] = "disabled",
 	[LPORT_ST_FLOGI] =    "FLOGI",
 	[LPORT_ST_DNS] =      "dNS",
 	[LPORT_ST_RPN_ID] =   "RPN_ID",
@@ -550,7 +550,7 @@ int fc_fabric_login(struct fc_lport *lport)
 	int rc = -1;
 
 	mutex_lock(&lport->lp_mutex);
-	if (lport->state == LPORT_ST_NONE) {
+	if (lport->state == LPORT_ST_DISABLED) {
 		fc_lport_enter_reset(lport);
 		rc = 0;
 	}
@@ -637,7 +637,7 @@ EXPORT_SYMBOL(fc_fabric_logoff);
 int fc_lport_destroy(struct fc_lport *lport)
 {
 	mutex_lock(&lport->lp_mutex);
-	lport->state = LPORT_ST_NONE;
+	lport->state = LPORT_ST_DISABLED;
 	lport->link_up = 0;
 	lport->tt.frame_send = fc_frame_drop;
 	mutex_unlock(&lport->lp_mutex);
@@ -992,7 +992,7 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp)
 			schedule_delayed_work(&lport->retry_work, delay);
 		} else {
 			switch (lport->state) {
-			case LPORT_ST_NONE:
+			case LPORT_ST_DISABLED:
 			case LPORT_ST_READY:
 			case LPORT_ST_RESET:
 			case LPORT_ST_RPN_ID:
@@ -1316,7 +1316,7 @@ static void fc_lport_timeout(struct work_struct *work)
 	mutex_lock(&lport->lp_mutex);
 
 	switch (lport->state) {
-	case LPORT_ST_NONE:
+	case LPORT_ST_DISABLED:
 	case LPORT_ST_READY:
 	case LPORT_ST_RESET:
 		WARN_ON(1);
@@ -1550,7 +1550,7 @@ int fc_lport_config(struct fc_lport *lport)
 	INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout);
 	mutex_init(&lport->lp_mutex);
 
-	fc_lport_state_enter(lport, LPORT_ST_NONE);
+	fc_lport_state_enter(lport, LPORT_ST_DISABLED);
 
 	fc_lport_add_fc4_type(lport, FC_TYPE_FCP);
 	fc_lport_add_fc4_type(lport, FC_TYPE_CT);
include/scsi/libfc.h +1 -1
index efdb6ba..b5c9b28 100644
@@ -129,7 +129,7 @@ do {									\
  * FC HBA status
  */
 enum fc_lport_state {
-	LPORT_ST_NONE = 0,
+	LPORT_ST_DISABLED = 0,
 	LPORT_ST_FLOGI,
 	LPORT_ST_DNS,
 	LPORT_ST_RPN_ID,
#8 lore raw

PATCH 8/22 libfc: stop login after fabric logoff

In reply to Robert Love

From: Joe Eykholt <[email protected]>

When removing the fcoe module, several lports were being shut down through fc_lport_fabric_logoff().

Occasionally, one would enter reset state before fc_lport_destroy() was called, and since link_up was still true, it would log back in.

If we just clear link_up earlier, then we wouldn't be accepting LOGO requests from other initiators while we are shutting down.

Fix by changing the LOGO response handler to enter DISABLED instead of RESET. Add an fc_lport_enter_disabled() function which does what fc_lport_enter_reset() did, except it doesn't proceed to FLOGI state.

Move the code that was common between fc_lport_enter_reset() and fc_lport_enter_disabled() into a new fc_lport_reset_locked() function.

---

 drivers/scsi/libfc/fc_lport.c |   42 +++++++++++++++++++++++++++++++++--------
 1 files changed, 34 insertions(+), 8 deletions(-)
drivers/scsi/libfc/fc_lport.c +34 -8
index 3b28190..7bb451a 100644
@@ -930,19 +930,14 @@ int fc_lport_reset(struct fc_lport *lport)
 EXPORT_SYMBOL(fc_lport_reset);
 
 /**
- * fc_rport_enter_reset() - Reset the local port
+ * fc_lport_reset_locked() - Reset the local port
  * @lport: Fibre Channel local port to be reset
  *
  * Locking Note: The lport lock is expected to be held before calling
  * this routine.
  */
-static void fc_lport_enter_reset(struct fc_lport *lport)
+static void fc_lport_reset_locked(struct fc_lport *lport)
 {
-	FC_LPORT_DBG(lport, "Entered RESET state from %s state\n",
-		     fc_lport_state(lport));
-
-	fc_lport_state_enter(lport, LPORT_ST_RESET);
-
 	if (lport->dns_rp)
 		lport->tt.rport_logoff(lport->dns_rp);
 
@@ -956,12 +951,43 @@ static void fc_lport_enter_reset(struct fc_lport *lport)
 	lport->tt.exch_mgr_reset(lport, 0, 0);
 	fc_host_fabric_name(lport->host) = 0;
 	fc_host_port_id(lport->host) = 0;
+}
+
+/**
+ * fc_lport_enter_reset() - Reset the local port
+ * @lport: Fibre Channel local port to be reset
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
+ */
+static void fc_lport_enter_reset(struct fc_lport *lport)
+{
+	FC_LPORT_DBG(lport, "Entered RESET state from %s state\n",
+		     fc_lport_state(lport));
 
+	fc_lport_state_enter(lport, LPORT_ST_RESET);
+	fc_lport_reset_locked(lport);
 	if (lport->link_up)
 		fc_lport_enter_flogi(lport);
 }
 
 /**
+ * fc_lport_enter_disabled() - disable the local port
+ * @lport: Fibre Channel local port to be reset
+ *
+ * Locking Note: The lport lock is expected to be held before calling
+ * this routine.
+ */
+static void fc_lport_enter_disabled(struct fc_lport *lport)
+{
+	FC_LPORT_DBG(lport, "Entered disabled state from %s state\n",
+		     fc_lport_state(lport));
+
+	fc_lport_state_enter(lport, LPORT_ST_DISABLED);
+	fc_lport_reset_locked(lport);
+}
+
+/**
  * fc_lport_error() - Handler for any errors
  * @lport: The fc_lport object
  * @fp: The frame pointer
@@ -1382,7 +1408,7 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
 
 	op = fc_frame_payload_op(fp);
 	if (op == ELS_LS_ACC)
-		fc_lport_enter_reset(lport);
+		fc_lport_enter_disabled(lport);
 	else
 		fc_lport_error(lport, fp);
 
#9 lore raw

PATCH 9/22 libfc: in fc_lport_destroy, flush rports after turning off link

In reply to Robert Love

From: Joe Eykholt <[email protected]>

During an fcoe module unload, we saw a problem where fc_rport_work() finds the lport has been freed. The rdata points to an area containing 0x6b6b6b6b... the pool poison value from kmem_free().

In fcoe_if_destroy() we call fc_fabric_logoff() then fc_lport_destroy(). fc_fabric_logoff() flushes the remote port work, but we're still receiving requests, and an RSCN or PLOGI arrives which creates more rports.

Note that although the LLD also checks link_up, it doesn't do it under the lport mutex, so it can deliver frames to fc_lport_recv_req() even after link_up is cleared.
So, re-check link_up there.

We need to flush the rports by calling disc_stop_final() after we clear link_up.

---

 drivers/scsi/libfc/fc_lport.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)
drivers/scsi/libfc/fc_lport.c +5 -1
index 7bb451a..a430335 100644
@@ -643,6 +643,7 @@ int fc_lport_destroy(struct fc_lport *lport)
 	mutex_unlock(&lport->lp_mutex);
 
 	lport->tt.fcp_abort_io(lport);
+	lport->tt.disc_stop_final(lport);
 	lport->tt.exch_mgr_reset(lport, 0, 0);
 	return 0;
 }
@@ -844,7 +845,10 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
 	 * RSCN here.  These don't require a session.
 	 * Even if we had a session, it might not be ready.
 	 */
-	if (fh->fh_type == FC_TYPE_ELS && fh->fh_r_ctl == FC_RCTL_ELS_REQ) {
+	if (!lport->link_up)
+		fc_frame_free(fp);
+	else if (fh->fh_type == FC_TYPE_ELS &&
+		 fh->fh_r_ctl == FC_RCTL_ELS_REQ) {
 		/*
 		 * Check opcode.
 		 */
#10 lore raw

PATCH 10/22 libfc: fix WARNING from fc_seq_start_next on closed exchanges

In reply to Robert Love

From: Joe Eykholt <[email protected]>

We saw periodic messages like:

WARNING: at drivers/scsi/libfc/fc_exch.c:825 fc_seq_start_next+0x30/0x4b

This was due to trying to allocate a sequence in a request handler when the exchange had been reset.

Delete the WARN_ON.

---

 drivers/scsi/libfc/fc_exch.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)
drivers/scsi/libfc/fc_exch.c +0 -1
index e6d82d7..cab5499 100644
@@ -822,7 +822,6 @@ struct fc_seq *fc_seq_start_next(struct fc_seq *sp)
 	struct fc_exch *ep = fc_seq_exch(sp);
 
 	spin_lock_bh(&ep->ex_lock);
-	WARN_ON((ep->esb_stat & ESB_ST_COMPLETE) != 0);
 	sp = fc_seq_start_next_locked(sp);
 	spin_unlock_bh(&ep->ex_lock);
 
#11 lore raw

PATCH 11/22 libfc: rename rport state "NONE" to "DELETE".

In reply to Robert Love

From: Joe Eykholt <[email protected]>

State RPORT_ST_NONE was intented to be an invalid state (0), never used. This was a misguided attempt to be sure it was always initialized. Having an extra state meaning nothing requires switch statements to have a case covering that state.

State NONE has been used instead to mean the remote port is being deleted. Changing the name to RPORT_ST_DELETE.

---

 drivers/scsi/libfc/fc_rport.c |   28 ++++++++++++++--------------
 include/scsi/libfc.h          |    2 +-
 2 files changed, 15 insertions(+), 15 deletions(-)
drivers/scsi/libfc/fc_rport.c +14 -14
index 7162385..bf7364f 100644
@@ -77,13 +77,13 @@ static void fc_rport_error_retry(struct fc_rport *, struct fc_frame *);
 static void fc_rport_work(struct work_struct *);
 
 static const char *fc_rport_state_names[] = {
-	[RPORT_ST_NONE] = "None",
 	[RPORT_ST_INIT] = "Init",
 	[RPORT_ST_PLOGI] = "PLOGI",
 	[RPORT_ST_PRLI] = "PRLI",
 	[RPORT_ST_RTV] = "RTV",
 	[RPORT_ST_READY] = "Ready",
 	[RPORT_ST_LOGO] = "LOGO",
+	[RPORT_ST_DELETE] = "Delete",
 };
 
 static void fc_rport_rogue_destroy(struct device *dev)
@@ -326,8 +326,8 @@ int fc_rport_logoff(struct fc_rport *rport)
 
 	FC_RPORT_DBG(rport, "Remove port\n");
 
-	if (rdata->rp_state == RPORT_ST_NONE) {
-		FC_RPORT_DBG(rport, "Port in NONE state, not removing\n");
+	if (rdata->rp_state == RPORT_ST_DELETE) {
+		FC_RPORT_DBG(rport, "Port in Delete state, not removing\n");
 		mutex_unlock(&rdata->rp_mutex);
 		goto out;
 	}
@@ -335,10 +335,10 @@ int fc_rport_logoff(struct fc_rport *rport)
 	fc_rport_enter_logo(rport);
 
 	/*
-	 * Change the state to NONE so that we discard
+	 * Change the state to Delete so that we discard
 	 * the response.
 	 */
-	fc_rport_state_enter(rport, RPORT_ST_NONE);
+	fc_rport_state_enter(rport, RPORT_ST_DELETE);
 
 	mutex_unlock(&rdata->rp_mutex);
 
@@ -405,7 +405,7 @@ static void fc_rport_timeout(struct work_struct *work)
 		break;
 	case RPORT_ST_READY:
 	case RPORT_ST_INIT:
-	case RPORT_ST_NONE:
+	case RPORT_ST_DELETE:
 		break;
 	}
 
@@ -433,14 +433,14 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp)
 	case RPORT_ST_PRLI:
 	case RPORT_ST_LOGO:
 		rdata->event = RPORT_EV_FAILED;
-		fc_rport_state_enter(rport, RPORT_ST_NONE);
+		fc_rport_state_enter(rport, RPORT_ST_DELETE);
 		queue_work(rport_event_queue,
 			   &rdata->event_work);
 		break;
 	case RPORT_ST_RTV:
 		fc_rport_enter_ready(rport);
 		break;
-	case RPORT_ST_NONE:
+	case RPORT_ST_DELETE:
 	case RPORT_ST_READY:
 	case RPORT_ST_INIT:
 		break;
@@ -652,7 +652,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
 	} else {
 		FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n");
 		rdata->event = RPORT_EV_FAILED;
-		fc_rport_state_enter(rport, RPORT_ST_NONE);
+		fc_rport_state_enter(rport, RPORT_ST_DELETE);
 		queue_work(rport_event_queue, &rdata->event_work);
 	}
 
@@ -703,7 +703,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
 	} else {
 		FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n");
 		rdata->event = RPORT_EV_LOGO;
-		fc_rport_state_enter(rport, RPORT_ST_NONE);
+		fc_rport_state_enter(rport, RPORT_ST_DELETE);
 		queue_work(rport_event_queue, &rdata->event_work);
 	}
 
@@ -1012,7 +1012,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport,
 			     "- ignored for now\n", rdata->rp_state);
 		/* XXX TBD - should reset */
 		break;
-	case RPORT_ST_NONE:
+	case RPORT_ST_DELETE:
 	default:
 		FC_RPORT_DBG(rport, "Received PLOGI in unexpected "
 			     "state %d\n", rdata->rp_state);
@@ -1238,7 +1238,7 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp,
 	FC_RPORT_DBG(rport, "Received PRLO request while in state %s\n",
 		     fc_rport_state(rport));
 
-	if (rdata->rp_state == RPORT_ST_NONE) {
+	if (rdata->rp_state == RPORT_ST_DELETE) {
 		fc_frame_free(fp);
 		return;
 	}
@@ -1271,13 +1271,13 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp,
 	FC_RPORT_DBG(rport, "Received LOGO request while in state %s\n",
 		     fc_rport_state(rport));
 
-	if (rdata->rp_state == RPORT_ST_NONE) {
+	if (rdata->rp_state == RPORT_ST_DELETE) {
 		fc_frame_free(fp);
 		return;
 	}
 
 	rdata->event = RPORT_EV_LOGO;
-	fc_rport_state_enter(rport, RPORT_ST_NONE);
+	fc_rport_state_enter(rport, RPORT_ST_DELETE);
 	queue_work(rport_event_queue, &rdata->event_work);
 
 	lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
include/scsi/libfc.h +1 -1
index b5c9b28..04db7a9 100644
@@ -147,13 +147,13 @@ enum fc_disc_event {
 };
 
 enum fc_rport_state {
-	RPORT_ST_NONE = 0,
 	RPORT_ST_INIT,		/* initialized */
 	RPORT_ST_PLOGI,		/* waiting for PLOGI completion */
 	RPORT_ST_PRLI,		/* waiting for PRLI completion */
 	RPORT_ST_RTV,		/* waiting for RTV completion */
 	RPORT_ST_READY,		/* ready for use */
 	RPORT_ST_LOGO,		/* port logout sent */
+	RPORT_ST_DELETE,	/* port being deleted */
 };
 
 enum fc_rport_trans_state {
#12 lore raw

PATCH 12/22 libfc: fc_rport_logoff should not drop the lock

In reply to Robert Love

From: Joe Eykholt <[email protected]>

fc_rport_logoff drops the rport lock in order to cancel work that may be pending. This is undesirable as the state can completely change, and the caller may not expect that the lock could've been dropped.

If there is work pending, it will acquire the rdata mutex and so we're protected and can change the event from READY to DELETE. Queue the work only if there is no event already pending.

There were a couple other cases where the state was set to DELETE and work queued, even though the state may have already been DELETE. Fix these using a common function fc_rport_enter_delete().

---

 drivers/scsi/libfc/fc_rport.c |   60 ++++++++++++++++++++++++++---------------
 1 files changed, 38 insertions(+), 22 deletions(-)
drivers/scsi/libfc/fc_rport.c +38 -22
index bf7364f..a86df0b 100644
@@ -230,6 +230,7 @@ static void fc_rport_work(struct work_struct *work)
 		ids.port_name = rport->port_name;
 		ids.node_name = rport->node_name;
 
+		rdata->event = RPORT_EV_NONE;
 		mutex_unlock(&rdata->rp_mutex);
 
 		new_rport = fc_remote_port_add(lport->host, 0, &ids);
@@ -311,6 +312,37 @@ int fc_rport_login(struct fc_rport *rport)
 }
 
 /**
+ * fc_rport_enter_delete() - schedule a remote port to be deleted.
+ * @rport: Fibre Channel remote port
+ * @event: event to report as the reason for deletion
+ *
+ * Locking Note: Called with the rport lock held.
+ *
+ * Allow state change into DELETE only once.
+ *
+ * Call queue_work only if there's no event already pending.
+ * Set the new event so that the old pending event will not occur.
+ * Since we have the mutex, even if fc_rport_work() is already started,
+ * it'll see the new event.
+ */
+static void fc_rport_enter_delete(struct fc_rport *rport,
+				  enum fc_rport_event event)
+{
+	struct fc_rport_libfc_priv *rdata = rport->dd_data;
+
+	if (rdata->rp_state == RPORT_ST_DELETE)
+		return;
+
+	FC_RPORT_DBG(rport, "Delete port\n");
+
+	fc_rport_state_enter(rport, RPORT_ST_DELETE);
+
+	if (rdata->event == RPORT_EV_NONE)
+		queue_work(rport_event_queue, &rdata->event_work);
+	rdata->event = event;
+}
+
+/**
  * fc_rport_logoff() - Logoff and remove an rport
  * @rport: Fibre Channel remote port to be removed
  *
@@ -338,17 +370,7 @@ int fc_rport_logoff(struct fc_rport *rport)
 	 * Change the state to Delete so that we discard
 	 * the response.
 	 */
-	fc_rport_state_enter(rport, RPORT_ST_DELETE);
-
-	mutex_unlock(&rdata->rp_mutex);
-
-	cancel_delayed_work_sync(&rdata->retry_work);
-
-	mutex_lock(&rdata->rp_mutex);
-
-	rdata->event = RPORT_EV_STOP;
-	queue_work(rport_event_queue, &rdata->event_work);
-
+	fc_rport_enter_delete(rport, RPORT_EV_STOP);
 	mutex_unlock(&rdata->rp_mutex);
 
 out:
@@ -370,8 +392,9 @@ static void fc_rport_enter_ready(struct fc_rport *rport)
 
 	FC_RPORT_DBG(rport, "Port is Ready\n");
 
+	if (rdata->event == RPORT_EV_NONE)
+		queue_work(rport_event_queue, &rdata->event_work);
 	rdata->event = RPORT_EV_CREATED;
-	queue_work(rport_event_queue, &rdata->event_work);
 }
 
 /**
@@ -432,10 +455,7 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp)
 	case RPORT_ST_PLOGI:
 	case RPORT_ST_PRLI:
 	case RPORT_ST_LOGO:
-		rdata->event = RPORT_EV_FAILED;
-		fc_rport_state_enter(rport, RPORT_ST_DELETE);
-		queue_work(rport_event_queue,
-			   &rdata->event_work);
+		fc_rport_enter_delete(rport, RPORT_EV_FAILED);
 		break;
 	case RPORT_ST_RTV:
 		fc_rport_enter_ready(rport);
@@ -651,9 +671,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
 
 	} else {
 		FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n");
-		rdata->event = RPORT_EV_FAILED;
-		fc_rport_state_enter(rport, RPORT_ST_DELETE);
-		queue_work(rport_event_queue, &rdata->event_work);
+		fc_rport_enter_delete(rport, RPORT_EV_FAILED);
 	}
 
 out:
@@ -702,9 +720,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
 		fc_rport_enter_rtv(rport);
 	} else {
 		FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n");
-		rdata->event = RPORT_EV_LOGO;
-		fc_rport_state_enter(rport, RPORT_ST_DELETE);
-		queue_work(rport_event_queue, &rdata->event_work);
+		fc_rport_enter_delete(rport, RPORT_EV_LOGO);
 	}
 
 out:
#13 lore raw

PATCH 13/22 libfc: fix: cancel rport retry timer

In reply to Robert Love

From: Joe Eykholt <[email protected]>

The timer for rport retries wasn't getting canceled, and would occasionally go off after the module was unloaded.

Add logic to cancel the timer in fc_rport_work().

Since we cancel the timer before deleting the rdata,
it is no longer necessary to do a get_device() for the pending timer.

---

 drivers/scsi/libfc/fc_rport.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)
drivers/scsi/libfc/fc_rport.c +1 -2
index a86df0b..90cc90d 100644
@@ -276,6 +276,7 @@ static void fc_rport_work(struct work_struct *work)
 		mutex_unlock(&rdata->rp_mutex);
 		if (rport_ops->event_callback)
 			rport_ops->event_callback(lport, rport, event);
+		cancel_delayed_work_sync(&rdata->retry_work);
 		if (trans_state == FC_PORTSTATE_ROGUE)
 			put_device(&rport->dev);
 		else {
@@ -433,7 +434,6 @@ static void fc_rport_timeout(struct work_struct *work)
 	}
 
 	mutex_unlock(&rdata->rp_mutex);
-	put_device(&rport->dev);
 }
 
 /**
@@ -494,7 +494,6 @@ static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp)
 		/* no additional delay on exchange timeouts */
 		if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
 			delay = 0;
-		get_device(&rport->dev);
 		schedule_delayed_work(&rdata->retry_work, delay);
 		return;
 	}
#14 lore raw

PATCH 14/22 fcoe, libfc: adds exchange manager(EM) anchor list per lport and related APIs

In reply to Robert Love

From: Vasu Dev <[email protected]>

Adds EM list using a anchor struct fc_exch_mgr_anchor, anchor is used to allow same EM instance sharing across more than one lport on a eth device, this implementation is per discussed design posted at
http://www.open-fcoe.org/pipermail/devel/2009-June/002566.html.

The shared EM is required for multiple lports on eth device when using multiple VLANs or NPIV.

Adds fc_exch_mgr_add API to add a EM to the lport and fc_exch_mgr_del API to delete previously added EM.

Also adds function fc_exch_mgr_destroy() to destroy allocated EM. The kref is added to the EM to keep track of EM usage count, the EM is destroyed when no longer in use upon kref reaching to zero.

The caller can specify match function to fc_exch_mgr_add, this will be used in determining exchange allocation from its EM or not.

Moved calling of fcoe_em_config below fcoe_libfc_config calling, so that list head lp->ema_list is initialized before configuring EM.

---

 drivers/scsi/fcoe/fcoe.c      |   14 ++++++------
 drivers/scsi/libfc/fc_exch.c  |   48 +++++++++++++++++++++++++++++++++++++++++
 drivers/scsi/libfc/fc_lport.c |    1 +
 include/scsi/libfc.h          |   24 +++++++++++++++++++++
 4 files changed, 80 insertions(+), 7 deletions(-)
drivers/scsi/fcoe/fcoe.c +7 -7
index 14a4017..719a99d 100644
@@ -603,18 +603,18 @@ static int fcoe_if_create(struct net_device *netdev)
 		goto out_netdev_cleanup;
 	}
 
-	/* lport exch manager allocation */
-	rc = fcoe_em_config(lp);
+	/* Initialize the library */
+	rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ);
 	if (rc) {
-		FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the "
+		FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the "
 				"interface\n");
-		goto out_netdev_cleanup;
+		goto out_lp_destroy;
 	}
 
-	/* Initialize the library */
-	rc = fcoe_libfc_config(lp, &fcoe_libfc_fcn_templ);
+	/* lport exch manager allocation */
+	rc = fcoe_em_config(lp);
 	if (rc) {
-		FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the "
+		FCOE_NETDEV_DBG(netdev, "Could not configure the EM for the "
 				"interface\n");
 		goto out_lp_destroy;
 	}
drivers/scsi/libfc/fc_exch.c +48 -0

66 lines not on this page · raw message

drivers/scsi/libfc/fc_lport.c +1 -0
index a430335..ca8ea26 100644
@@ -1618,6 +1618,7 @@ int fc_lport_init(struct fc_lport *lport)
 	if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT)
 		fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT;
 
+	INIT_LIST_HEAD(&lport->ema_list);
 	return 0;
 }
 EXPORT_SYMBOL(fc_lport_init);
include/scsi/libfc.h +24 -0
index 04db7a9..b381b1c 100644
@@ -348,6 +348,7 @@ static inline bool fc_fcp_is_read(const struct fc_fcp_pkt *fsp)
  */
 
 struct fc_exch_mgr;
+struct fc_exch_mgr_anchor;
 
 /*
  * Sequence.
@@ -709,6 +710,7 @@ struct fc_lport {
 	/* Associations */
 	struct Scsi_Host	*host;
 	struct fc_exch_mgr	*emp;
+	struct list_head	ema_list;
 	struct fc_rport		*dns_rp;
 	struct fc_rport		*ptp_rp;
 	void			*scsi_priv;
@@ -964,6 +966,28 @@ int fc_elsct_init(struct fc_lport *lp);
 int fc_exch_init(struct fc_lport *lp);
 
 /*
+ * Adds Exchange Manager (EM) mp to lport.
+ *
+ * Adds specified mp to lport using struct fc_exch_mgr_anchor,
+ * the struct fc_exch_mgr_anchor allows same EM sharing by
+ * more than one lport with their specified match function,
+ * the match function is used in allocating exchange from
+ * added mp.
+ */
+struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport,
+					   struct fc_exch_mgr *mp,
+					   bool (*match)(struct fc_frame *));
+
+/*
+ * Deletes Exchange Manager (EM) from lport by removing
+ * its anchor ema from lport.
+ *
+ * If removed anchor ema was the last user of its associated EM
+ * then also destroys associated EM.
+ */
+void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema);
+
+/*
  * Allocates an Exchange Manager (EM).
  *
  * The EM manages exchanges for their allocation and
#15 lore raw

PATCH 15/22 libfc: Remove the FC_EM_DBG macro

In reply to Robert Love

Currently there is a 1:1 relationship between the lport and exchange manager. This macro takes an EM as an argument and determines the lport from it. However, later patches will use an EM list per lport, so we will no longer have this 1:1 relationship- this macro must change.

The FC_EM_DBG macro is rarely used. There are four callers, two can use FC_LPORT_DBG instead and two can be removed since they're not necessary. This patch makes those changes and removes the macro.

---

 drivers/scsi/libfc/fc_exch.c |   13 ++++++-------
 include/scsi/libfc.h         |    6 ------
 2 files changed, 6 insertions(+), 13 deletions(-)
drivers/scsi/libfc/fc_exch.c +6 -7
index f1fa2b1..3ad7f88 100644
@@ -1129,7 +1129,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp,
 			lp->tt.lport_recv(lp, sp, fp);
 		fc_exch_release(ep);	/* release from lookup */
 	} else {
-		FC_EM_DBG(mp, "exch/seq lookup failed: reject %x\n", reject);
+		FC_LPORT_DBG(lp, "exch/seq lookup failed: reject %x\n", reject);
 		fc_frame_free(fp);
 	}
 }
@@ -1235,13 +1235,12 @@ static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
 	struct fc_seq *sp;
 
 	sp = fc_seq_lookup_orig(mp, fp);	/* doesn't hold sequence */
-	if (!sp) {
+
+	if (!sp)
 		atomic_inc(&mp->stats.xid_not_found);
-		FC_EM_DBG(mp, "seq lookup failed\n");
-	} else {
+	else
 		atomic_inc(&mp->stats.non_bls_resp);
-		FC_EM_DBG(mp, "non-BLS response to sequence");
-	}
+
 	fc_frame_free(fp);
 }
 
@@ -1950,7 +1949,7 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp,
 			fc_exch_recv_req(lp, mp, fp);
 		break;
 	default:
-		FC_EM_DBG(mp, "dropping invalid frame (eof %x)", fr_eof(fp));
+		FC_LPORT_DBG(lp, "dropping invalid frame (eof %x)", fr_eof(fp));
 		fc_frame_free(fp);
 		break;
 	}
include/scsi/libfc.h +0 -6
index b381b1c..f1bde91 100644
@@ -88,12 +88,6 @@ do {									\
 				(pkt)->lp->host->host_no,		\
 				pkt->rport->port_id, ##args))
 
-#define FC_EM_DBG(em, fmt, args...)					\
-	FC_CHECK_LOGGING(FC_EM_LOGGING,					\
-			 printk(KERN_INFO "host%u: em: " fmt,		\
-				(em)->lp->host->host_no,		\
-				##args))
-
 #define FC_EXCH_DBG(exch, fmt, args...)					\
 	FC_CHECK_LOGGING(FC_EXCH_LOGGING,				\
 			 printk(KERN_INFO "host%u: xid %4x: " fmt,	\
#16 lore raw

PATCH 16/22 fcoe, fnic, libfc: modifies current code paths to use EM anchor list

In reply to Robert Love

From: Vasu Dev <[email protected]>

Modifies current code to use EM anchor list in EM allocation, EM free, EM reset, exch allocation and exch lookup code paths.

1. Modifies fc_exch_mgr_alloc to accept EM match function and then have allocated EM added to the lport using fc_exch_mgr_add API while also updating EM kref for newly added EM.

2. Updates fc_exch_mgr_free API to accept only lport pointer instead EM and then have this API free all EMs of the lport from EM anchor list.

3. Removes single lport pointer link from the EM, which was used in associating lport pointer in newly allocated exchange. Instead have lport pointer passed along new exchange allocation call path and then store passed lport pointer in newly allocated exchange, this will allow a single EM instance to be used across more than one lport and used in EM reset to reset only lport specific exchanges.

4. Modifies fc_exch_mgr_reset to reset all EMs from the EM anchor list of the lport, adds additional exch lport pointer (ep->lp) check for shared EM case to reset exchange specific to a lport requested reset.

5. Updates exch allocation API fc_exch_alloc to use EM anchor list and its anchor match func pointer. The fc_exch_alloc will walk the list of EMs until it finds a match, a match will be either null match func pointer or call to match function returning true value.

6. Updates fc_exch_recv to accept incoming frame on local port using only lport pointer and frame pointer without specifying EM instance of incoming frame. Instead modified fc_exch_recv to locate EM for the incoming frame by matching xid of incoming frame against a EM xid range. This change was required to use EM list in libfc Rx path and after this change the lport fc_exch_mgr pointer emp is not needed anymore, so removed emp pointer.

7. Updates fnic for removed lport emp pointer and above modified libfc APIs fc_exch_recv, fc_exch_mgr_alloc and fc_exch_mgr_free.

8. Removes exch_get and exch_put from libfc_function_template as these are no longer needed with EM anchor list and its match function use. Also removes its default function fc_exch_get.

A defect this patch introduced regarding the libfc initialization order in the fnic driver was fixed by Joe Eykholt <[email protected]>.

---

 drivers/scsi/fcoe/fcoe.c      |   16 +--
 drivers/scsi/fcoe/libfcoe.c   |    2 
 drivers/scsi/fnic/fnic_fcs.c  |    2 
 drivers/scsi/fnic/fnic_main.c |   20 ++--
 drivers/scsi/libfc/fc_exch.c  |  191 +++++++++++++++++++++++++----------------
 include/scsi/libfc.h          |   48 ++--------
 6 files changed, 142 insertions(+), 137 deletions(-)
drivers/scsi/fcoe/fcoe.c +6 -10
index 719a99d..ebf2e20 100644
@@ -423,11 +423,8 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,
  */
 static inline int fcoe_em_config(struct fc_lport *lp)
 {
-	BUG_ON(lp->emp);
-
-	lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3,
-				    FCOE_MIN_XID, FCOE_MAX_XID);
-	if (!lp->emp)
+	if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCOE_MIN_XID,
+			       FCOE_MAX_XID, NULL))
 		return -ENOMEM;
 
 	return 0;
@@ -478,8 +475,7 @@ static int fcoe_if_destroy(struct net_device *netdev)
 	scsi_remove_host(lp->host);
 
 	/* There are no more rports or I/O, free the EM */
-	if (lp->emp)
-		fc_exch_mgr_free(lp->emp);
+	fc_exch_mgr_free(lp);
 
 	/* Free existing skbs */
 	fcoe_clean_pending_queue(lp);
@@ -634,7 +630,7 @@ static int fcoe_if_create(struct net_device *netdev)
 	return rc;
 
 out_lp_destroy:
-	fc_exch_mgr_free(lp->emp); /* Free the EM */
+	fc_exch_mgr_free(lp);
 out_netdev_cleanup:
 	fcoe_netdev_cleanup(fc);
 out_host_put:
@@ -1277,7 +1273,7 @@ int fcoe_percpu_receive_thread(void *arg)
 		fh = fc_frame_header_get(fp);
 		if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
 		    fh->fh_type == FC_TYPE_FCP) {
-			fc_exch_recv(lp, lp->emp, fp);
+			fc_exch_recv(lp, fp);
 			continue;
 		}
 		if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
@@ -1298,7 +1294,7 @@ int fcoe_percpu_receive_thread(void *arg)
 			fc_frame_free(fp);
 			continue;
 		}
-		fc_exch_recv(lp, lp->emp, fp);
+		fc_exch_recv(lp, fp);
 	}
 	return 0;
 }
drivers/scsi/fcoe/libfcoe.c +1 -1
index 78caa6b..4db719d 100644
@@ -885,7 +885,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
 	stats->RxFrames++;
 	stats->RxWords += skb->len / FIP_BPW;
 
-	fc_exch_recv(lp, lp->emp, fp);
+	fc_exch_recv(lp, fp);
 	return;
 
 len_err:
drivers/scsi/fnic/fnic_fcs.c +1 -1
index 07e6eed..50db3e3 100644
@@ -115,7 +115,7 @@ void fnic_handle_frame(struct work_struct *work)
 		}
 		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
 
-		fc_exch_recv(lp, lp->emp, fp);
+		fc_exch_recv(lp, fp);
 	}
 
 }
drivers/scsi/fnic/fnic_main.c +9 -11
index 2c266c0..71c7bbe 100644
@@ -671,14 +671,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
 	lp->link_up = 0;
 	lp->tt = fnic_transport_template;
 
-	lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3,
-				    FCPIO_HOST_EXCH_RANGE_START,
-				    FCPIO_HOST_EXCH_RANGE_END);
-	if (!lp->emp) {
-		err = -ENOMEM;
-		goto err_out_remove_scsi_host;
-	}
-
 	lp->max_retry_count = fnic->config.flogi_retries;
 	lp->max_rport_retry_count = fnic->config.plogi_retries;
 	lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
@@ -693,12 +685,18 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
 	fc_set_wwnn(lp, fnic->config.node_wwn);
 	fc_set_wwpn(lp, fnic->config.port_wwn);
 
-	fc_exch_init(lp);
 	fc_lport_init(lp);
+	fc_exch_init(lp);
 	fc_elsct_init(lp);
 	fc_rport_init(lp);
 	fc_disc_init(lp);
 
+	if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START,
+			       FCPIO_HOST_EXCH_RANGE_END, NULL)) {
+		err = -ENOMEM;
+		goto err_out_remove_scsi_host;
+	}
+
 	fc_lport_config(lp);
 
 	if (fc_set_mfs(lp, fnic->config.maxdatafieldsize +
@@ -738,7 +736,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
 	return 0;
 
 err_out_free_exch_mgr:
-	fc_exch_mgr_free(lp->emp);
+	fc_exch_mgr_free(lp);
 err_out_remove_scsi_host:
 	fc_remove_host(fnic->lport->host);
 	scsi_remove_host(fnic->lport->host);
@@ -827,7 +825,7 @@ static void __devexit fnic_remove(struct pci_dev *pdev)
 
 	fc_remove_host(fnic->lport->host);
 	scsi_remove_host(fnic->lport->host);
-	fc_exch_mgr_free(fnic->lport->emp);
+	fc_exch_mgr_free(fnic->lport);
 	vnic_dev_notify_unset(fnic->vdev);
 	fnic_free_vnic_resources(fnic);
 	fnic_free_intr(fnic);
drivers/scsi/libfc/fc_exch.c +117 -74

343 lines not on this page · raw message

include/scsi/libfc.h +8 -40

86 lines not on this page · raw message

#17 lore raw

PATCH 17/22 fcoe: modifies fcoe_hostlist_lock uses as prep work to add shared offload EM

In reply to Robert Love

From: Vasu Dev <[email protected]>

Modifies fcoe_hostlist_lock uses such that a new EM allocation in fcoe_em_config and adding new fcoe_softc using fcoe_hostlist_add are atomic, this is to ensure that a shared offload EM gets allocated only once per eth device for its all lports.

---

 drivers/scsi/fcoe/fcoe.c |   26 ++++++++++++++++++--------
 1 files changed, 18 insertions(+), 8 deletions(-)
drivers/scsi/fcoe/fcoe.c +18 -8
index ebf2e20..86410b9 100644
@@ -419,6 +419,8 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,
  * fcoe_em_config() - allocates em for this lport
  * @lp: the port that em is to allocated for
  *
+ * Called with write fcoe_hostlist_lock held.
+ *
  * Returns : 0 on success
  */
 static inline int fcoe_em_config(struct fc_lport *lp)
@@ -607,6 +609,13 @@ static int fcoe_if_create(struct net_device *netdev)
 		goto out_lp_destroy;
 	}
 
+	/*
+	 * fcoe_em_alloc() and fcoe_hostlist_add() both
+	 * need to be atomic under fcoe_hostlist_lock
+	 * since fcoe_em_alloc() looks for an existing EM
+	 * instance on host list updated by fcoe_hostlist_add().
+	 */
+	write_lock(&fcoe_hostlist_lock);
 	/* lport exch manager allocation */
 	rc = fcoe_em_config(lp);
 	if (rc) {
@@ -617,6 +626,7 @@ static int fcoe_if_create(struct net_device *netdev)
 
 	/* add to lports list */
 	fcoe_hostlist_add(lp);
+	write_unlock(&fcoe_hostlist_lock);
 
 	lp->boot_time = jiffies;
 
@@ -1720,6 +1730,8 @@ int fcoe_reset(struct Scsi_Host *shost)
  * fcoe_hostlist_lookup_softc() - find the corresponding lport by a given device
  * @dev: this is currently ptr to net_device
  *
+ * Called with fcoe_hostlist_lock held.
+ *
  * Returns: NULL or the located fcoe_softc
  */
 static struct fcoe_softc *
@@ -1727,14 +1739,10 @@ fcoe_hostlist_lookup_softc(const struct net_device *dev)
 {
 	struct fcoe_softc *fc;
 
-	read_lock(&fcoe_hostlist_lock);
 	list_for_each_entry(fc, &fcoe_hostlist, list) {
-		if (fc->real_dev == dev) {
-			read_unlock(&fcoe_hostlist_lock);
+		if (fc->real_dev == dev)
 			return fc;
-		}
 	}
-	read_unlock(&fcoe_hostlist_lock);
 	return NULL;
 }
 
@@ -1748,7 +1756,9 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev)
 {
 	struct fcoe_softc *fc;
 
+	read_lock(&fcoe_hostlist_lock);
 	fc = fcoe_hostlist_lookup_softc(netdev);
+	read_unlock(&fcoe_hostlist_lock);
 
 	return (fc) ? fc->ctlr.lp : NULL;
 }
@@ -1757,6 +1767,8 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev)
  * fcoe_hostlist_add() - Add a lport to lports list
  * @lp: ptr to the fc_lport to be added
  *
+ * Called with write fcoe_hostlist_lock held.
+ *
  * Returns: 0 for success
  */
 int fcoe_hostlist_add(const struct fc_lport *lp)
@@ -1766,9 +1778,7 @@ int fcoe_hostlist_add(const struct fc_lport *lp)
 	fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp));
 	if (!fc) {
 		fc = lport_priv(lp);
-		write_lock_bh(&fcoe_hostlist_lock);
 		list_add_tail(&fc->list, &fcoe_hostlist);
-		write_unlock_bh(&fcoe_hostlist_lock);
 	}
 	return 0;
 }
@@ -1783,9 +1793,9 @@ int fcoe_hostlist_remove(const struct fc_lport *lp)
 {
 	struct fcoe_softc *fc;
 
+	write_lock_bh(&fcoe_hostlist_lock);
 	fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp));
 	BUG_ON(!fc);
-	write_lock_bh(&fcoe_hostlist_lock);
 	list_del(&fc->list);
 	write_unlock_bh(&fcoe_hostlist_lock);
 
#18 lore raw

PATCH 18/22 fcoe, libfc: adds offload EM per eth device with only single xid range per EM

In reply to Robert Love

From: Vasu Dev <[email protected]>

Updates fcoe_em_config to allocate a single instance of sharable offload EM for supported lp->lro_xid per eth device, and then share this EM for subsequently more lports creation on same eth device (e.g when using VLAN).

Adds tiny fcoe_oem_match function for offload EM to return true for read types IO to have read IO exchanges allocated from offload shared EM.

Removes fc_em_alloc_xid function completely which was needed to manage two xid ranges within a EM, this is not needed any more with allocation of separate sharable offload EM per eth device. Instead this patch adds simple xid allocation logic to manage single xid range.

Adds fc_exch_em_alloc with mp->next_xid as cursor to allocate new xid from single xid range of EM, uses mp->next_xid instead removed mp->last_xid which slightly increase probability of finding empty xid on exch allocation.

Removes restriction of not allowing use of xid zero along with changing two xid range change to single xid range.

Makes fc_fcp_ddp_setup calling conditional to only xid allocated from shared offload EM.

---

 drivers/scsi/fcoe/fcoe.c     |   67 +++++++++++++++++++++++++++++-
 drivers/scsi/fcoe/fcoe.h     |    3 +
 drivers/scsi/libfc/fc_exch.c |   94 ++++++++----------------------------------
 3 files changed, 85 insertions(+), 79 deletions(-)
drivers/scsi/fcoe/fcoe.c +65 -2
index 86410b9..0306aa9 100644
@@ -415,6 +415,17 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,
 	return 0;
 }
 
+/*
+ * fcoe_oem_match() - match for read types IO
+ * @fp: the fc_frame for new IO.
+ *
+ * Returns : true for read types IO, otherwise returns false.
+ */
+bool fcoe_oem_match(struct fc_frame *fp)
+{
+	return fc_fcp_is_read(fr_fsp(fp));
+}
+
 /**
  * fcoe_em_config() - allocates em for this lport
  * @lp: the port that em is to allocated for
@@ -425,9 +436,61 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,
  */
 static inline int fcoe_em_config(struct fc_lport *lp)
 {
-	if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCOE_MIN_XID,
-			       FCOE_MAX_XID, NULL))
+	struct fcoe_softc *fc = lport_priv(lp);
+	struct fcoe_softc *oldfc = NULL;
+	u16 min_xid = FCOE_MIN_XID;
+	u16 max_xid = FCOE_MAX_XID;
+
+	/*
+	 * Check if need to allocate an em instance for
+	 * offload exchange ids to be shared across all VN_PORTs/lport.
+	 */
+	if (!lp->lro_enabled || !lp->lro_xid || (lp->lro_xid >= max_xid)) {
+		lp->lro_xid = 0;
+		goto skip_oem;
+	}
+
+	/*
+	 * Reuse existing offload em instance in case
+	 * it is already allocated on phys_dev.
+	 */
+	list_for_each_entry(oldfc, &fcoe_hostlist, list) {
+		if (oldfc->phys_dev == fc->phys_dev) {
+			fc->oem = oldfc->oem;
+			break;
+		}
+	}
+
+	if (fc->oem) {
+		if (!fc_exch_mgr_add(lp, fc->oem, fcoe_oem_match)) {
+			printk(KERN_ERR "fcoe_em_config: failed to add "
+			       "offload em:%p on interface:%s\n",
+			       fc->oem, fc->real_dev->name);
+			return -ENOMEM;
+		}
+	} else {
+		fc->oem = fc_exch_mgr_alloc(lp, FC_CLASS_3,
+					    FCOE_MIN_XID, lp->lro_xid,
+					    fcoe_oem_match);
+		if (!fc->oem) {
+			printk(KERN_ERR "fcoe_em_config: failed to allocate "
+			       "em for offload exches on interface:%s\n",
+			       fc->real_dev->name);
+			return -ENOMEM;
+		}
+	}
+
+	/*
+	 * Exclude offload EM xid range from next EM xid range.
+	 */
+	min_xid += lp->lro_xid + 1;
+
+skip_oem:
+	if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, min_xid, max_xid, NULL)) {
+		printk(KERN_ERR "fcoe_em_config: failed to "
+		       "allocate em on interface %s\n", fc->real_dev->name);
 		return -ENOMEM;
+	}
 
 	return 0;
 }
drivers/scsi/fcoe/fcoe.h +2 -1
index 0d724fa..6905efc 100644
@@ -37,7 +37,7 @@
 
 #define FCOE_MAX_OUTSTANDING_COMMANDS	1024
 
-#define FCOE_MIN_XID		0x0001	/* the min xid supported by fcoe_sw */
+#define FCOE_MIN_XID		0x0000	/* the min xid supported by fcoe_sw */
 #define FCOE_MAX_XID		0x07ef	/* the max xid supported by fcoe_sw */
 
 unsigned int fcoe_debug_logging;
@@ -81,6 +81,7 @@ struct fcoe_softc {
 	struct list_head list;
 	struct net_device *real_dev;
 	struct net_device *phys_dev;		/* device with ethtool_ops */
+	struct fc_exch_mgr *oem;		/* offload exchange manger */
 	struct packet_type  fcoe_packet_type;
 	struct packet_type  fip_packet_type;
 	struct sk_buff_head fcoe_pending_queue;
drivers/scsi/libfc/fc_exch.c +18 -76

153 lines not on this page · raw message

#19 lore raw

PATCH 19/22 fcoe: Remove ifdef for NETIF_F_FCOE_CRC and NETIF_F_FSO

In reply to Robert Love

From: Yi Zou <[email protected]>

Remove the extra ifdef for NETIF_F_FSO and NETIF_F_FCOE_CRC since they are already defined in the current kernel as in include/linux/netdevice.h.

---

 drivers/scsi/fcoe/fcoe.c |    6 ------
 1 files changed, 0 insertions(+), 6 deletions(-)
drivers/scsi/fcoe/fcoe.c +0 -6
index 0306aa9..ad21e87 100644
@@ -300,20 +300,16 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
 	if (fc->real_dev->features & NETIF_F_SG)
 		lp->sg_supp = 1;
 
-#ifdef NETIF_F_FCOE_CRC
 	if (netdev->features & NETIF_F_FCOE_CRC) {
 		lp->crc_offload = 1;
 		FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n");
 	}
-#endif
-#ifdef NETIF_F_FSO
 	if (netdev->features & NETIF_F_FSO) {
 		lp->seq_offload = 1;
 		lp->lso_max = netdev->gso_max_size;
 		FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n",
 				lp->lso_max);
 	}
-#endif
 	if (netdev->fcoe_ddp_xid) {
 		lp->lro_enabled = 1;
 		lp->lro_xid = netdev->fcoe_ddp_xid;
@@ -1205,7 +1201,6 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
 		FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER);
 	hp->fcoe_sof = sof;
 
-#ifdef NETIF_F_FSO
 	/* fcoe lso, mss is in max_payload which is non-zero for FCP data */
 	if (lp->seq_offload && fr_max_payload(fp)) {
 		skb_shinfo(skb)->gso_type = SKB_GSO_FCOE;
@@ -1214,7 +1209,6 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
 		skb_shinfo(skb)->gso_type = 0;
 		skb_shinfo(skb)->gso_size = 0;
 	}
-#endif
 	/* update tx stats: regardless if LLD fails */
 	stats = fc_lport_get_stats(lp);
 	stats->TxFrames++;
#20 lore raw

PATCH 20/22 libfc: Remove FC_FRAME_SG_LEN in fc_fcp_send_data

In reply to Robert Love

From: Yi Zou <[email protected]>

FC_FRAME_SG_LEN is 4 which is too small when offload is enabled. Actually, the WARN_ON() in fc_fcp_send_data() should be:

	WARN_ON(skb_shinfo(fp_skb(fp))->nr_frags > MAX_SKB_FRAGS);

But since we will not get anything more than 64K anyway, so there is no need to do this anyway here. Therefore, I am getting rid of FC_FRAME_SG_LEN here and the WARN_ON here.

---

 drivers/scsi/libfc/fc_fcp.c |    2 --
 include/scsi/fc_frame.h     |    7 -------
 2 files changed, 0 insertions(+), 9 deletions(-)
drivers/scsi/libfc/fc_fcp.c +0 -2
index e303e0d..2069edf 100644
@@ -569,8 +569,6 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
 		}
 		sg_bytes = min(tlen, sg->length - offset);
 		if (using_sg) {
-			WARN_ON(skb_shinfo(fp_skb(fp))->nr_frags >
-				FC_FRAME_SG_LEN);
 			get_page(sg_page(sg));
 			skb_fill_page_desc(fp_skb(fp),
 					   skb_shinfo(fp_skb(fp))->nr_frags,
include/scsi/fc_frame.h +0 -7
index 5951105..c35d238 100644
@@ -37,13 +37,6 @@
 #define	FC_FRAME_HEADROOM	32	/* headroom for VLAN + FCoE headers */
 #define	FC_FRAME_TAILROOM	8	/* trailer space for FCoE */
 
-/*
- * Information about an individual fibre channel frame received or to be sent.
- * The buffer may be in up to 4 additional non-contiguous sections,
- * but the linear section must hold the frame header.
- */
-#define FC_FRAME_SG_LEN		4	/* scatter/gather list maximum length */
-
 #define fp_skb(fp)	(&((fp)->skb))
 #define fr_hdr(fp)	((fp)->skb.data)
 #define fr_len(fp)	((fp)->skb.len)
#21 lore raw

PATCH 21/22 libfc: Remove page flags check for sglist

In reply to Robert Love

From: Yi Zou <[email protected]>

I don't believe this check is needed any more in the current kernel, which, if I understand correctly, is for compound page where only the first page is supposed to get ref-counted.

---

 drivers/scsi/libfc/fc_fcp.c |   27 ---------------------------
 1 files changed, 0 insertions(+), 27 deletions(-)
drivers/scsi/libfc/fc_fcp.c +0 -27
index 2069edf..7d5ffcb 100644
@@ -507,33 +507,6 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
 	f_ctl = FC_FC_REL_OFF;
 	WARN_ON(!seq);
 
-	/*
-	 * If a get_page()/put_page() will fail, don't use sg lists
-	 * in the fc_frame structure.
-	 *
-	 * The put_page() may be long after the I/O has completed
-	 * in the case of FCoE, since the network driver does it
-	 * via free_skb().  See the test in free_pages_check().
-	 *
-	 * Test this case with 'dd </dev/zero >/dev/st0 bs=64k'.
-	 */
-	if (using_sg) {
-		for (sg = scsi_sglist(sc); sg; sg = sg_next(sg)) {
-			if (page_count(sg_page(sg)) == 0 ||
-			    (sg_page(sg)->flags & (1 << PG_lru |
-						   1 << PG_private |
-						   1 << PG_locked |
-						   1 << PG_active |
-						   1 << PG_slab |
-						   1 << PG_swapcache |
-						   1 << PG_writeback |
-						   1 << PG_reserved |
-						   1 << PG_buddy))) {
-				using_sg = 0;
-				break;
-			}
-		}
-	}
 	sg = scsi_sglist(sc);
 
 	while (remaining > 0 && sg) {
#22 lore raw

PATCH 22/22 fcoe: removes phys_dev and renames real_dev to netdev.

In reply to Robert Love

From: Vasu Dev <[email protected]>

The phys_dev was used only to locate common offload EM instance for all FCoE instances on a eth devices in function fcoe_em_config, so just updated fcoe_em_config to look for actual real eth device in locating common offload EM instance and then no need to store phys_dev in fcoe_softc, so removes phys_dev from fcoe_softc also.

Renames fcoe_softc real_dev to netdev and updates all its uses to use netdev.

So effectively no functional change, use of single netdev instead phys_dev and real_dev saves one pointer memory in fcoe_softc, also real_dev used here was confusing with vlan driver terminology since real_dev in vlan driver is referred to physical eth device.

---

 drivers/scsi/fcoe/fcoe.c |   93 ++++++++++++++++++++++++----------------------
 drivers/scsi/fcoe/fcoe.h |    5 +-
 2 files changed, 51 insertions(+), 47 deletions(-)
drivers/scsi/fcoe/fcoe.c +49 -44
index ad21e87..757aa28 100644
@@ -159,7 +159,7 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,
  */
 static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
 {
-	skb->dev = fcoe_from_ctlr(fip)->real_dev;
+	skb->dev = fcoe_from_ctlr(fip)->netdev;
 	dev_queue_xmit(skb);
 }
 
@@ -179,8 +179,8 @@ static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new)
 	fc = fcoe_from_ctlr(fip);
 	rtnl_lock();
 	if (!is_zero_ether_addr(old))
-		dev_unicast_delete(fc->real_dev, old);
-	dev_unicast_add(fc->real_dev, new);
+		dev_unicast_delete(fc->netdev, old);
+	dev_unicast_add(fc->netdev, new);
 	rtnl_unlock();
 }
 
@@ -231,12 +231,12 @@ void fcoe_netdev_cleanup(struct fcoe_softc *fc)
 	/* Delete secondary MAC addresses */
 	rtnl_lock();
 	memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
-	dev_unicast_delete(fc->real_dev, flogi_maddr);
+	dev_unicast_delete(fc->netdev, flogi_maddr);
 	if (!is_zero_ether_addr(fc->ctlr.data_src_addr))
-		dev_unicast_delete(fc->real_dev, fc->ctlr.data_src_addr);
+		dev_unicast_delete(fc->netdev, fc->ctlr.data_src_addr);
 	if (fc->ctlr.spma)
-		dev_unicast_delete(fc->real_dev, fc->ctlr.ctl_src_addr);
-	dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
+		dev_unicast_delete(fc->netdev, fc->ctlr.ctl_src_addr);
+	dev_mc_delete(fc->netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
 	rtnl_unlock();
 }
 
@@ -272,17 +272,12 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
 	/* Setup lport private data to point to fcoe softc */
 	fc = lport_priv(lp);
 	fc->ctlr.lp = lp;
-	fc->real_dev = netdev;
-	fc->phys_dev = netdev;
-
-	/* Require support for get_pauseparam ethtool op. */
-	if (netdev->priv_flags & IFF_802_1Q_VLAN)
-		fc->phys_dev = vlan_dev_real_dev(netdev);
+	fc->netdev = netdev;
 
 	/* Do not support for bonding device */
-	if ((fc->real_dev->priv_flags & IFF_MASTER_ALB) ||
-	    (fc->real_dev->priv_flags & IFF_SLAVE_INACTIVE) ||
-	    (fc->real_dev->priv_flags & IFF_MASTER_8023AD)) {
+	if ((netdev->priv_flags & IFF_MASTER_ALB) ||
+	    (netdev->priv_flags & IFF_SLAVE_INACTIVE) ||
+	    (netdev->priv_flags & IFF_MASTER_8023AD)) {
 		return -EOPNOTSUPP;
 	}
 
@@ -291,13 +286,13 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
 	 * user-configured limit.  If the MFS is too low, fcoe_link_ok()
 	 * will return 0, so do this first.
 	 */
-	mfs = fc->real_dev->mtu - (sizeof(struct fcoe_hdr) +
-				   sizeof(struct fcoe_crc_eof));
+	mfs = netdev->mtu - (sizeof(struct fcoe_hdr) +
+			     sizeof(struct fcoe_crc_eof));
 	if (fc_set_mfs(lp, mfs))
 		return -EINVAL;
 
 	/* offload features support */
-	if (fc->real_dev->features & NETIF_F_SG)
+	if (netdev->features & NETIF_F_SG)
 		lp->sg_supp = 1;
 
 	if (netdev->features & NETIF_F_FCOE_CRC) {
@@ -335,13 +330,13 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
 
 	/* setup Source Mac Address */
 	if (!fc->ctlr.spma)
-		memcpy(fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr,
-		       fc->real_dev->addr_len);
+		memcpy(fc->ctlr.ctl_src_addr, netdev->dev_addr,
+		       fc->netdev->addr_len);
 
-	wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0);
+	wwnn = fcoe_wwn_from_mac(netdev->dev_addr, 1, 0);
 	fc_set_wwnn(lp, wwnn);
 	/* XXX - 3rd arg needs to be vlan id */
-	wwpn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 2, 0);
+	wwpn = fcoe_wwn_from_mac(netdev->dev_addr, 2, 0);
 	fc_set_wwpn(lp, wwpn);
 
 	/*
@@ -351,10 +346,10 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
 	 */
 	rtnl_lock();
 	memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
-	dev_unicast_add(fc->real_dev, flogi_maddr);
+	dev_unicast_add(netdev, flogi_maddr);
 	if (fc->ctlr.spma)
-		dev_unicast_add(fc->real_dev, fc->ctlr.ctl_src_addr);
-	dev_mc_add(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
+		dev_unicast_add(netdev, fc->ctlr.ctl_src_addr);
+	dev_mc_add(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
 	rtnl_unlock();
 
 	/*
@@ -363,12 +358,12 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
 	 */
 	fc->fcoe_packet_type.func = fcoe_rcv;
 	fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE);
-	fc->fcoe_packet_type.dev = fc->real_dev;
+	fc->fcoe_packet_type.dev = netdev;
 	dev_add_pack(&fc->fcoe_packet_type);
 
 	fc->fip_packet_type.func = fcoe_fip_recv;
 	fc->fip_packet_type.type = htons(ETH_P_FIP);
-	fc->fip_packet_type.dev = fc->real_dev;
+	fc->fip_packet_type.dev = netdev;
 	dev_add_pack(&fc->fip_packet_type);
 
 	return 0;
@@ -434,6 +429,7 @@ static inline int fcoe_em_config(struct fc_lport *lp)
 {
 	struct fcoe_softc *fc = lport_priv(lp);
 	struct fcoe_softc *oldfc = NULL;
+	struct net_device *old_real_dev, *cur_real_dev;
 	u16 min_xid = FCOE_MIN_XID;
 	u16 max_xid = FCOE_MAX_XID;
 
@@ -448,10 +444,20 @@ static inline int fcoe_em_config(struct fc_lport *lp)
 
 	/*
 	 * Reuse existing offload em instance in case
-	 * it is already allocated on phys_dev.
+	 * it is already allocated on real eth device
 	 */
+	if (fc->netdev->priv_flags & IFF_802_1Q_VLAN)
+		cur_real_dev = vlan_dev_real_dev(fc->netdev);
+	else
+		cur_real_dev = fc->netdev;
+
 	list_for_each_entry(oldfc, &fcoe_hostlist, list) {
-		if (oldfc->phys_dev == fc->phys_dev) {
+		if (oldfc->netdev->priv_flags & IFF_802_1Q_VLAN)
+			old_real_dev = vlan_dev_real_dev(oldfc->netdev);
+		else
+			old_real_dev = oldfc->netdev;
+
+		if (cur_real_dev == old_real_dev) {
 			fc->oem = oldfc->oem;
 			break;
 		}
@@ -461,7 +467,7 @@ static inline int fcoe_em_config(struct fc_lport *lp)
 		if (!fc_exch_mgr_add(lp, fc->oem, fcoe_oem_match)) {
 			printk(KERN_ERR "fcoe_em_config: failed to add "
 			       "offload em:%p on interface:%s\n",
-			       fc->oem, fc->real_dev->name);
+			       fc->oem, fc->netdev->name);
 			return -ENOMEM;
 		}
 	} else {
@@ -471,7 +477,7 @@ static inline int fcoe_em_config(struct fc_lport *lp)
 		if (!fc->oem) {
 			printk(KERN_ERR "fcoe_em_config: failed to allocate "
 			       "em for offload exches on interface:%s\n",
-			       fc->real_dev->name);
+			       fc->netdev->name);
 			return -ENOMEM;
 		}
 	}
@@ -484,7 +490,7 @@ static inline int fcoe_em_config(struct fc_lport *lp)
 skip_oem:
 	if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, min_xid, max_xid, NULL)) {
 		printk(KERN_ERR "fcoe_em_config: failed to "
-		       "allocate em on interface %s\n", fc->real_dev->name);
+		       "allocate em on interface %s\n", fc->netdev->name);
 		return -ENOMEM;
 	}
 
@@ -548,7 +554,7 @@ static int fcoe_if_destroy(struct net_device *netdev)
 	fc_lport_free_stats(lp);
 
 	/* Release the net_device and Scsi_Host */
-	dev_put(fc->real_dev);
+	dev_put(netdev);
 	scsi_host_put(lp->host);
 
 	return 0;
@@ -1179,7 +1185,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
 	skb_reset_network_header(skb);
 	skb->mac_len = elen;
 	skb->protocol = htons(ETH_P_FCOE);
-	skb->dev = fc->real_dev;
+	skb->dev = fc->netdev;
 
 	/* fill up mac and fcoe headers */
 	eh = eth_hdr(skb);
@@ -1454,7 +1460,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 				    ulong event, void *ptr)
 {
 	struct fc_lport *lp = NULL;
-	struct net_device *real_dev = ptr;
+	struct net_device *netdev = ptr;
 	struct fcoe_softc *fc;
 	struct fcoe_dev_stats *stats;
 	u32 link_possible = 1;
@@ -1463,7 +1469,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 
 	read_lock(&fcoe_hostlist_lock);
 	list_for_each_entry(fc, &fcoe_hostlist, list) {
-		if (fc->real_dev == real_dev) {
+		if (fc->netdev == netdev) {
 			lp = fc->ctlr.lp;
 			break;
 		}
@@ -1483,16 +1489,15 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 	case NETDEV_CHANGE:
 		break;
 	case NETDEV_CHANGEMTU:
-		mfs = fc->real_dev->mtu -
-			(sizeof(struct fcoe_hdr) +
-			 sizeof(struct fcoe_crc_eof));
+		mfs = netdev->mtu - (sizeof(struct fcoe_hdr) +
+				     sizeof(struct fcoe_crc_eof));
 		if (mfs >= FC_MIN_MAX_FRAME)
 			fc_set_mfs(lp, mfs);
 		break;
 	case NETDEV_REGISTER:
 		break;
 	default:
-		FCOE_NETDEV_DBG(real_dev, "Unknown event %ld "
+		FCOE_NETDEV_DBG(netdev, "Unknown event %ld "
 				"from netdev netlink\n", event);
 	}
 	if (link_possible && !fcoe_link_ok(lp))
@@ -1696,7 +1701,7 @@ MODULE_PARM_DESC(destroy, "Destroy fcoe port");
 int fcoe_link_ok(struct fc_lport *lp)
 {
 	struct fcoe_softc *fc = lport_priv(lp);
-	struct net_device *dev = fc->real_dev;
+	struct net_device *dev = fc->netdev;
 	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
 
 	if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
@@ -1797,7 +1802,7 @@ fcoe_hostlist_lookup_softc(const struct net_device *dev)
 	struct fcoe_softc *fc;
 
 	list_for_each_entry(fc, &fcoe_hostlist, list) {
-		if (fc->real_dev == dev)
+		if (fc->netdev == dev)
 			return fc;
 	}
 	return NULL;
@@ -1916,7 +1921,7 @@ static void __exit fcoe_exit(void)
 
 	/* releases the associated fcoe hosts */
 	list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list)
-		fcoe_if_destroy(fc->real_dev);
+		fcoe_if_destroy(fc->netdev);
 
 	unregister_hotcpu_notifier(&fcoe_cpu_notifier);
 
drivers/scsi/fcoe/fcoe.h +2 -3
index 6905efc..5ae8ca7 100644
@@ -79,8 +79,7 @@ struct fcoe_percpu_s {
  */
 struct fcoe_softc {
 	struct list_head list;
-	struct net_device *real_dev;
-	struct net_device *phys_dev;		/* device with ethtool_ops */
+	struct net_device *netdev;
 	struct fc_exch_mgr *oem;		/* offload exchange manger */
 	struct packet_type  fcoe_packet_type;
 	struct packet_type  fip_packet_type;
@@ -95,7 +94,7 @@ struct fcoe_softc {
 static inline struct net_device *fcoe_netdev(
 	const struct fc_lport *lp)
 {
-	return ((struct fcoe_softc *)lport_priv(lp))->real_dev;
+	return ((struct fcoe_softc *)lport_priv(lp))->netdev;
 }
 
 #endif /* _FCOE_H_ */