[OpenFCoE PATCH] Don't use netdev for FCoE if pause is not correctly set, even for VLANs.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Don't use netdev for FCoE if pause is not correctly set, even for VLANs.

This modifies the previous tests to require that the underlying net-dev
supports the ethtool get_pauseparam operation.

NICs that are 10/100/1000 must have pause autonegotiation turned on.
All NICs must have RX and TX pause on.  If not, they are treated as if
there is no link.

Signed-off-by: Joe Eykholt <fcoe@xxxxxxxxxxx>

---
 drivers/scsi/ofc/fcoe/fcoe_def.h |    1 
 drivers/scsi/ofc/fcoe/fcoe_if.c  |   90 ++++++++++++++++++++++----------------
 drivers/scsi/ofc/fcoe/fcoeinit.c |   66 ++++++++--------------------
 3 files changed, 71 insertions(+), 86 deletions(-)

diff --git a/drivers/scsi/ofc/fcoe/fcoe_def.h b/drivers/scsi/ofc/fcoe/fcoe_def.h
index 0c71dc7..6550c73 100644
--- a/drivers/scsi/ofc/fcoe/fcoe_def.h
+++ b/drivers/scsi/ofc/fcoe/fcoe_def.h
@@ -109,6 +109,7 @@ int		fcoe_create_interface(struct fcoe_info *, void *);
 int		fcoe_xmit(struct fcdev *, struct fc_frame *);
 int		fcoe_rcv(struct sk_buff *, struct net_device *,
 			 struct packet_type *, struct net_device *);
+int		fcoe_link_ok(struct fcdev *);
 struct fc_frame *fcoe_frame_alloc(size_t);
 void fcoe_put_dev(struct fcdev *dev);
 struct fcoe_softc *fcoe_find_fcdev(char *);
diff --git a/drivers/scsi/ofc/fcoe/fcoe_if.c b/drivers/scsi/ofc/fcoe/fcoe_if.c
index d87ede1..fd3c7a7 100644
--- a/drivers/scsi/ofc/fcoe/fcoe_if.c
+++ b/drivers/scsi/ofc/fcoe/fcoe_if.c
@@ -160,6 +160,48 @@ int fcoe_destroy_interface(struct fcdev *fd)
 }
 
 /*
+ * Return non-zero if link is OK for use by FCoE.
+ * Any permanently-disqualifying conditions have been previously checked.
+ * This checks pause settings, which can change with link.
+ * This also updates the speed setting, which may change with link for 100/1000.
+ */
+int fcoe_link_ok(struct fcdev *fdev)
+{
+	struct fcoe_softc *fc = (struct fcoe_softc *)fdev->drv_priv;
+	struct net_device *dev = fc->real_dev;
+	struct ethtool_pauseparam pause = { ETHTOOL_GPAUSEPARAM };
+	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+	int rc = 0;
+
+	if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) {
+		dev->ethtool_ops->get_pauseparam(dev, &pause);
+		if (dev->ethtool_ops->get_settings) {
+			dev->ethtool_ops->get_settings(dev, &ecmd);
+			fdev->fd_speed_support &=
+			    ~(OFC_SPEED_1GBIT | OFC_SPEED_10GBIT);
+			if (ecmd.supported & (SUPPORTED_1000baseT_Half |
+					      SUPPORTED_1000baseT_Full))
+				fdev->fd_speed_support |= OFC_SPEED_1GBIT;
+			if (ecmd.supported & SUPPORTED_10000baseT_Full)
+				fdev->fd_speed_support |= OFC_SPEED_10GBIT;
+			if (ecmd.speed == SPEED_1000)
+				fdev->fd_speed = OFC_SPEED_1GBIT;
+			if (ecmd.speed == SPEED_10000)
+				fdev->fd_speed = OFC_SPEED_10GBIT;
+
+			/*
+			 * for 10 G (and faster), ignore autoneg requirement.
+			 */
+			if (ecmd.speed >= SPEED_10000)
+				pause.autoneg = 1;
+		}
+		if (pause.autoneg && pause.tx_pause && pause.rx_pause)
+			rc = 1;
+	}
+	return rc;
+}
+
+/*
  * This function creates the fcoe interface
  * create struct fcdev which is a shared structure between opefc
  * and transport level protocol.
@@ -171,8 +213,6 @@ int fcoe_create_interface(struct fcoe_info *fci, void *ptr)
 	struct fcoe_cfg *cfg = ptr;
 	struct fcoe_softc *fc;
 	struct fcoe_dev_stats *p;
-	struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };
-	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
 	int rc = 0;
 	int i;
 #ifdef HAVE_SET_RX_MODE
@@ -207,12 +247,6 @@ int fcoe_create_interface(struct fcoe_info *fci, void *ptr)
 		goto out;
 	}
 
-	fdev->fd_link_status = TRANS_LINK_DOWN;
-	if ((fc->real_dev->flags & IFF_UP) != 0 &&
-	    netif_carrier_ok(fc->real_dev)) {
-		fdev->fd_link_status = TRANS_LINK_UP;
-	}
-
 	/*
 	 * Do not support for bonding device
 	 */
@@ -224,38 +258,16 @@ int fcoe_create_interface(struct fcoe_info *fci, void *ptr)
 	}
 
 	/*
-	 * if it is not a vlan driver then do more check */
-	if (!(fc->real_dev->priv_flags & IFF_802_1Q_VLAN)) {
-
-		if (!fc->real_dev->ethtool_ops) {
-			rc = -EOPNOTSUPP;
-			goto out;
-		}
-		if (!fc->real_dev->ethtool_ops->get_pauseparam) {
-			rc = -EOPNOTSUPP;
-			goto out;
-		}
-		fc->real_dev->ethtool_ops->get_pauseparam(fc->real_dev,
-							  &pauseparam);
-		if (!pauseparam.rx_pause || !pauseparam.tx_pause) {
-			rc = -EOPNOTSUPP;
-			goto out;
-		}
-		if (fc->real_dev->ethtool_ops->get_settings) {
-			fc->real_dev->ethtool_ops->get_settings(fc->real_dev,
-								&ecmd);
-			if (ecmd.
-			    supported & (SUPPORTED_1000baseT_Half |
-					 SUPPORTED_1000baseT_Full))
-				fdev->fd_speed_support |= OFC_SPEED_1GBIT;
-			if (ecmd.supported & SUPPORTED_10000baseT_Full)
-				fdev->fd_speed_support |= OFC_SPEED_10GBIT;
-			if (ecmd.speed == SPEED_1000)
-				fdev->fd_speed = OFC_SPEED_1GBIT;
-			if (ecmd.speed == SPEED_10000)
-				fdev->fd_speed = OFC_SPEED_10GBIT;
-		}
+	 * Require support for get_pauseparam ethtool op.
+	 */
+	if (!fc->real_dev->ethtool_ops ||
+	    !fc->real_dev->ethtool_ops->get_pauseparam) {
+		rc = -EOPNOTSUPP;
+		goto out;
 	}
+	fdev->fd_link_status = TRANS_LINK_DOWN;
+	if (fcoe_link_ok(fdev))
+		fdev->fd_link_status = TRANS_LINK_UP;
 
 	if (fc->real_dev->features & NETIF_F_SG)
 		fdev->capabilities = TRANS_C_SG;
diff --git a/drivers/scsi/ofc/fcoe/fcoeinit.c b/drivers/scsi/ofc/fcoe/fcoeinit.c
index 182a9b1..3b80946 100644
--- a/drivers/scsi/ofc/fcoe/fcoeinit.c
+++ b/drivers/scsi/ofc/fcoe/fcoeinit.c
@@ -170,7 +170,6 @@ static void fcoe_dev_cleanup(void)
  * This function is called by the ethernet driver
  * this is called in case of link change event
  */
-
 static int fcoe_device_notification(struct notifier_block *notifier,
 				    ulong event, void *ptr)
 {
@@ -179,7 +178,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 	struct fcdev *fc_dev = NULL;
 	struct fcoe_dev_stats *stats;
 	struct fcoe_info *fci = &fcoei;
-	struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };
+	int new_status;
 	int rc;
 
 	read_lock(&fci->fcoe_hostlist_lock);
@@ -190,67 +189,40 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 		}
 	}
 	read_unlock(&fci->fcoe_hostlist_lock);
-
 	if (fc_dev == NULL) {
 		rc = NOTIFY_DONE;
 		goto out;
 	}
+	new_status = fc_dev->fd_link_status;
 	switch (event) {
 	case NETDEV_DOWN:
-		fc_dev->fd_link_status = TRANS_LINK_DOWN;
-		/* notify upper layer about link down */
-		openfc_linkdown(fc_dev);
-		stats = fc_dev->dev_stats[smp_processor_id()];
-		stats->LinkFailureCount++;
-		fcoe_clean_pending_queue(fc_dev);
-		rc = NOTIFY_OK;
+	case NETDEV_GOING_DOWN:
+		new_status = TRANS_LINK_DOWN;
 		break;
 	case NETDEV_UP:
-		fc_dev->fd_link_status = TRANS_LINK_UP;
-		/* notify upper layer about link up */
-		if (netif_carrier_ok(real_dev)) {
-			if ((real_dev->priv_flags & IFF_802_1Q_VLAN) == 0) {
-				real_dev->ethtool_ops->get_pauseparam(fc->
-								      real_dev,
-								      &pauseparam);
-				if (!pauseparam.rx_pause
-				    || !pauseparam.tx_pause) {
-					rc = NOTIFY_OK;
-					goto out;
-				}
-			}
-			openfc_linkup(fc_dev);
-		}
-		rc = NOTIFY_OK;
-		break;
 	case NETDEV_CHANGE:
-		if (netif_carrier_ok(real_dev)) {
-			if ((real_dev->priv_flags & IFF_802_1Q_VLAN) == 0) {
-				real_dev->ethtool_ops->get_pauseparam(fc->
-								      real_dev,
-								      &pauseparam);
-				if (!pauseparam.rx_pause
-				    || !pauseparam.tx_pause) {
-					rc = NOTIFY_OK;
-					goto out;
-				}
-			}
-			if (fc->real_dev->flags & IFF_UP)
-				openfc_linkup(fc_dev);
-		} else {
-			openfc_linkdown(fc_dev);
-			fcoe_clean_pending_queue(fc_dev);
-		}
-		rc = NOTIFY_OK;
+		new_status = TRANS_LINK_DOWN;
+		if (fcoe_link_ok(fc_dev))
+			new_status = TRANS_LINK_UP;
 		break;
 	case NETDEV_REGISTER:
-	case NETDEV_GOING_DOWN:
 		rc = NOTIFY_OK;
 		break;
 	default:
-		SA_LOG("unknow event %d call", event);
+		SA_LOG("unknown event %d call", event);
 		rc = NOTIFY_OK;
 	}
+	if (fc_dev->fd_link_status != new_status) {
+		fc_dev->fd_link_status = new_status;
+		if (new_status == TRANS_LINK_UP) {
+			openfc_linkup(fc_dev);
+		} else {
+			stats = fc_dev->dev_stats[smp_processor_id()];
+			stats->LinkFailureCount++;
+			openfc_linkdown(fc_dev);
+			fcoe_clean_pending_queue(fc_dev);
+		}
+	}
 out:
 	return rc;
 }


-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux