patch-2.4.21 linux-2.4.21/drivers/net/e100/e100_main.c

Next file: linux-2.4.21/drivers/net/e100/e100_phy.c
Previous file: linux-2.4.21/drivers/net/e100/e100_eeprom.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/drivers/net/e100/e100_main.c linux-2.4.21/drivers/net/e100/e100_main.c
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   
-  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
   
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by the Free 
@@ -45,32 +45,37 @@
 **********************************************************************/
 
 /* Change Log
+ * 
+ * 2.2.21	02/11/03
+ * o Removed marketing brand strings. Instead, Using generic string 
+ *   "Intel(R) PRO/100 Network Connection" for all adapters.
+ * o Implemented ethtool -S option
+ * o Strip /proc/net/PRO_LAN_Adapters files for kernel driver
+ * o Bug fix: Read wrong byte in EEPROM when offset is odd number
+ * o Bug fix: PHY loopback test fails on ICH devices
+ * o Bug fix: System panic on e100_close when repeating Hot Remove and 
+ *   Add in a team
+ * o Bug fix: Linux Bonding driver claims adapter's link loss because of
+ *   not updating last_rx field
+ * o Bug fix: e100 does not check validity of MAC address
+ * o New feature: added ICH5 support
+ * 
+ * 2.1.27	11/20/02
+ *   o Bug fix: Device command timeout due to SMBus processing during init
+ *   o Bug fix: Not setting/clearing I (Interrupt) bit in tcb correctly
+ *   o Bug fix: Not using EEPROM WoL setting as default in ethtool
+ *   o Bug fix: Not able to set autoneg on using ethtool when interface down
+ *   o Bug fix: Not able to change speed/duplex using ethtool/mii
+ *     when interface up
+ *   o Bug fix: Ethtool shows autoneg on when forced to 100/Full
+ *   o Bug fix: Compiler error when CONFIG_PROC_FS not defined
+ *   o Bug fix: 2.5.44 e100 doesn't load with preemptive kernel enabled
+ *     (sleep while holding spinlock)
+ *   o Bug fix: 2.1.24-k1 doesn't display complete statistics
+ *   o Bug fix: System panic due to NULL watchdog timer dereference during
+ *     ifconfig down, rmmod and insmod
  *
  * 2.1.24       10/7/02
- *   o Bug fix: Wrong files under /proc/net/PRO_LAN_Adapters/ when interface
- *     name is changed
- *   o Bug fix: Rx skb corruption when Rx polling code and Rx interrupt code
- *     are executing during stress traffic at shared interrupt system. 
- *     Removed Rx polling code
- *   o Added detailed printk if selftest failed when insmod
- *   o Removed misleading printks
- *
- * 2.1.12       8/2/02
- *   o Feature: ethtool register dump
- *   o Bug fix: Driver passes wrong name to /proc/interrupts
- *   o Bug fix: Ethernet bridging not working 
- *   o Bug fix: Promiscuous mode is not working
- *   o Bug fix: Checked return value from copy_from_user (William Stinson,
- *     wstinson@infonie.fr)
- *   o Bug fix: ARP wake on LAN fails
- *   o Bug fix: mii-diag does not update driver level's speed, duplex and
- *     re-configure flow control
- *   o Bug fix: Ethtool shows wrong speed/duplex when not connected
- *   o Bug fix: Ethtool shows wrong speed/duplex when reconnected if forced 
- *     speed/duplex
- *   o Bug fix: PHY loopback diagnostic fails
- *
- * 2.1.6        7/5/02
  */
  
 #include <linux/config.h>
@@ -81,15 +86,18 @@
 #include "e100_ucode.h"
 #include "e100_config.h"
 #include "e100_phy.h"
-#include "e100_vendor.h"
 
-#ifdef CONFIG_PROC_FS
-extern int e100_create_proc_subdir(struct e100_private *, char *);
-extern void e100_remove_proc_subdir(struct e100_private *, char *);
-#else
-#define e100_create_proc_subdir(X) 0
-#define e100_remove_proc_subdir(X) do {} while(0)
-#endif
+extern void e100_force_speed_duplex_to_phy(struct e100_private *bdp);
+
+static char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
+	"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+	"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+	"rx_length_errors", "rx_over_errors", "rx_crc_errors",
+	"rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+	"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+	"tx_heartbeat_errors", "tx_window_errors",
+};
+#define E100_STATS_LEN	sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN
 
 static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *);
 static void e100_get_speed_duplex_caps(struct e100_private *);
@@ -125,7 +133,6 @@
 
 static int e100_ethtool_led_blink(struct net_device *, struct ifreq *);
 
-#include <linux/mii.h>
 static int e100_mii_ioctl(struct net_device *, struct ifreq *, int);
 
 static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *,
@@ -134,31 +141,26 @@
 static void e100_non_tx_background(unsigned long);
 
 /* Global Data structures and variables */
-char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-char e100_driver_version[]="2.1.24-k1";
+char e100_copyright[] __devinitdata = "Copyright (c) 2003 Intel Corporation";
+char e100_driver_version[]="2.2.21-k1";
 const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
 char e100_short_driver_name[] = "e100";
 static int e100nics = 0;
+static void e100_vlan_rx_register(struct net_device *netdev, struct vlan_group
+		*grp);
+static void e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
+static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
 
 #ifdef CONFIG_PM
 static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
 static int e100_suspend(struct pci_dev *pcid, u32 state);
 static int e100_resume(struct pci_dev *pcid);
 struct notifier_block e100_notifier_reboot = {
-        notifier_call:  e100_notify_reboot,
-        next:           NULL,
-        priority:       0
+        .notifier_call  = e100_notify_reboot,
+        .next           = NULL,
+        .priority       = 0
 };
 #endif
-static int e100_notify_netdev(struct notifier_block *, unsigned long event, void *ptr);
- 
-struct notifier_block e100_notifier_netdev = {
-	notifier_call:  e100_notify_netdev,
-	next:           NULL,
-	priority:       0
-};
-
-static void e100_get_mdix_status(struct e100_private *bdp);
 
 /*********************************************************************/
 /*! This is a GCC extension to ANSI C.
@@ -193,9 +195,9 @@
 static void e100_set_multi(struct net_device *);
 void e100_set_speed_duplex(struct e100_private *);
 
-char *e100_get_brand_msg(struct e100_private *);
 static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
 static u8 e100_sw_init(struct e100_private *);
+static void e100_tco_workaround(struct e100_private *);
 static unsigned char e100_alloc_space(struct e100_private *);
 static void e100_dealloc_space(struct e100_private *);
 static int e100_alloc_tcb_pool(struct e100_private *);
@@ -213,7 +215,7 @@
 
 static unsigned char e100_clr_cntrs(struct e100_private *);
 static unsigned char e100_load_microcode(struct e100_private *);
-static unsigned char e100_hw_init(struct e100_private *, u32);
+static unsigned char e100_hw_init(struct e100_private *);
 static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *);
 static unsigned char e100_update_stats(struct e100_private *bdp);
 
@@ -224,8 +226,9 @@
 static void e100_set_int_option(int *, int, int, int, int, char *);
 static void e100_set_bool_option(struct e100_private *bdp, int, u32, int,
 				 char *);
-unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8);
+unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8);
 void e100_exec_cmplx(struct e100_private *, u32, u8);
+static unsigned char e100_asf_enabled(struct e100_private *bdp);
 
 /**
  * e100_get_rx_struct - retrieve cell to hold skb buff from the pool
@@ -349,8 +352,6 @@
 u32 e100_rx_srv(struct e100_private *);
 
 void e100_watchdog(struct net_device *);
-static void e100_do_hwi(struct net_device *);
-static void e100_hwi_restore(struct e100_private *);
 void e100_refresh_txthld(struct e100_private *);
 void e100_manage_adaptive_ifs(struct e100_private *);
 void e100_clear_pools(struct e100_private *);
@@ -443,9 +444,21 @@
 	if (!e100_wait_scb(bdp)) {
 		printk(KERN_DEBUG "e100: %s: e100_wait_exec_simple: failed\n",
 		       bdp->device->name);
+#ifdef E100_CU_DEBUG		
+		printk(KERN_ERR "e100: %s: Last command (%x/%x) "
+			"timeout\n", bdp->device->name, 
+			bdp->last_cmd, bdp->last_sub_cmd);
+		printk(KERN_ERR "e100: %s: Current simple command (%x) "
+			"can't be executed\n", 
+			bdp->device->name, scb_cmd_low);
+#endif		
 		return false;
 	}
 	e100_exec_cmd(bdp, scb_cmd_low);
+#ifdef E100_CU_DEBUG	
+	bdp->last_cmd = scb_cmd_low;
+	bdp->last_sub_cmd = 0;
+#endif	
 	return true;
 }
 
@@ -458,12 +471,24 @@
 }
 
 unsigned char
-e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd)
+e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd, u8 sub_cmd)
 {
 	if (!e100_wait_scb(bdp)) {
+#ifdef E100_CU_DEBUG		
+		printk(KERN_ERR "e100: %s: Last command (%x/%x) "
+			"timeout\n", bdp->device->name, 
+			bdp->last_cmd, bdp->last_sub_cmd);
+		printk(KERN_ERR "e100: %s: Current complex command "
+			"(%x/%x) can't be executed\n", 
+			bdp->device->name, cmd, sub_cmd);
+#endif		
 		return false;
 	}
 	e100_exec_cmplx(bdp, phys_addr, cmd);
+#ifdef E100_CU_DEBUG	
+	bdp->last_cmd = cmd;
+	bdp->last_sub_cmd = sub_cmd;
+#endif	
 	return true;
 }
 
@@ -494,18 +519,23 @@
 }
 
 /**
- * e100_dis_intr - disable interrupts
+ * e100_disable_clear_intr - disable and clear/ack interrupts
  * @bdp: atapter's private data struct
  *
  * This routine disables interrupts at the hardware, by setting
  * the M (mask) bit in the adapter's CSR SCB command word.
+ * It also clear/ack interrupts.
  */
 static inline void
-e100_dis_intr(struct e100_private *bdp)
+e100_disable_clear_intr(struct e100_private *bdp)
 {
+	u16 intr_status;
 	/* Disable interrupts on our PCI board by setting the mask bit */
 	writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi);
-	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
+	intr_status = readw(&bdp->scb->scb_status);
+	/* ack and clear intrs */
+	writew(intr_status, &bdp->scb->scb_status);
+	readw(&bdp->scb->scb_status);
 }
 
 /**
@@ -581,16 +611,14 @@
 	bdp->watchdog_timer.data = (unsigned long) dev;
 	bdp->watchdog_timer.function = (void *) &e100_watchdog;
 
-	init_timer(&bdp->hwi_timer);
-	bdp->hwi_timer.data = (unsigned long) dev;
-	bdp->hwi_timer.function = (void *) &e100_do_hwi;
-
 	if ((rc = e100_pci_setup(pcid, bdp)) != 0) {
 		goto err_dealloc;
 	}
 
 	if (((bdp->pdev->device > 0x1030)
-	     && (bdp->pdev->device < 0x103F))
+	       && (bdp->pdev->device < 0x103F))
+	    || ((bdp->pdev->device >= 0x1050)
+	       && (bdp->pdev->device <= 0x1057))
 	    || (bdp->pdev->device == 0x2449)
 	    || (bdp->pdev->device == 0x2459)
 	    || (bdp->pdev->device == 0x245D)) {
@@ -623,12 +651,15 @@
 	cal_checksum = e100_eeprom_calculate_chksum(bdp);
 	read_checksum = e100_eeprom_read(bdp, (bdp->eeprom_size - 1));
 	if (cal_checksum != read_checksum) {
-                printk(KERN_ERR "e100: Corrupted EERPROM on instance #%d\n",
+                printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n",
 		       e100nics);
                 rc = -ENODEV;
                 goto err_pci;
 	}
 	
+	dev->vlan_rx_register = e100_vlan_rx_register;
+	dev->vlan_rx_add_vid = e100_vlan_rx_add_vid;
+	dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid;
 	dev->irq = pcid->irq;
 	dev->open = &e100_open;
 	dev->hard_start_xmit = &e100_xmit_frame;
@@ -638,9 +669,11 @@
 	dev->set_multicast_list = &e100_set_multi;
 	dev->set_mac_address = &e100_set_mac;
 	dev->do_ioctl = &e100_ioctl;
-	if (bdp->flags & USE_IPCB) {
-		dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
-	}
+
+	if (bdp->flags & USE_IPCB)
+	dev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
+			NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+		
 	e100nics++;
 
 	e100_get_speed_duplex_caps(bdp);
@@ -651,35 +684,24 @@
         memcpy(bdp->ifname, dev->name, IFNAMSIZ);
         bdp->ifname[IFNAMSIZ-1] = 0;	
 
-	bdp->device_type = ent->driver_data;
 	printk(KERN_NOTICE
 	       "e100: %s: %s\n", 
-	       bdp->device->name, e100_get_brand_msg(bdp));
+	       bdp->device->name, "Intel(R) PRO/100 Network Connection");
 	e100_print_brd_conf(bdp);
-	bdp->id_string = e100_get_brand_msg(bdp);
-	e100_get_mdix_status(bdp);
 
-	if (netif_carrier_ok(bdp->device)) 
-		bdp->cable_status = "Cable OK";
-	else {
-		if (bdp->rev_id < D102_REV_ID) 
-			bdp->cable_status = "Not supported";
-		else
-			bdp->cable_status = "Not available";
-	}
-
-	if (e100_create_proc_subdir(bdp, bdp->ifname) < 0) {
-		printk(KERN_ERR "e100: Failed to create proc dir for %s\n",
-		       bdp->device->name);
-	}
-
-	/* Disabling all WOLs as initialization */
-	bdp->wolsupported = bdp->wolopts = 0;
-	if (bdp->rev_id >= D101A4_REV_ID) {
-		bdp->wolsupported = WAKE_PHY | WAKE_MAGIC;
+	bdp->wolsupported = 0;
+	bdp->wolopts = 0;
+	
+	/* Check if WoL is enabled on EEPROM */
+	if (e100_eeprom_read(bdp, EEPROM_ID_WORD) & BIT_5) {
+		/* Magic Packet WoL is enabled on device by default */
+		/* if EEPROM WoL bit is TRUE                        */
+		bdp->wolsupported = WAKE_MAGIC;
+		bdp->wolopts = WAKE_MAGIC;
+		if (bdp->rev_id >= D101A4_REV_ID)
+			bdp->wolsupported = WAKE_PHY | WAKE_MAGIC;
 		if (bdp->rev_id >= D101MA_REV_ID)
 			bdp->wolsupported |= WAKE_UCAST | WAKE_ARP;
-		bdp->wolopts = WAKE_MAGIC;
 	}
 
 	printk(KERN_NOTICE "\n");
@@ -732,8 +754,6 @@
 
 	unregister_netdev(dev);
 
-	e100_remove_proc_subdir(bdp, bdp->ifname);
-
 	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
 
 	if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
@@ -747,6 +767,34 @@
 	--e100nics;
 }
 
+static struct pci_device_id e100_id_table[] __devinitdata = {
+	{0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+  	{0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },	
+	{0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, 
+	{0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, 
+	{0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, 
+	{0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x1055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{0,} /* This has to be the last entry*/
+};
 MODULE_DEVICE_TABLE(pci, e100_id_table);
 
 static struct pci_driver e100_driver = {
@@ -770,7 +818,6 @@
 #ifdef CONFIG_PM
 		register_reboot_notifier(&e100_notifier_reboot);
 #endif 
-		register_netdevice_notifier(&e100_notifier_netdev);
 	}
 
 	return ret;
@@ -782,7 +829,6 @@
 #ifdef CONFIG_PM	
 	unregister_reboot_notifier(&e100_notifier_reboot);
 #endif 
-	unregister_netdevice_notifier(&e100_notifier_netdev);
 
 	pci_unregister_driver(&e100_driver);
 }
@@ -935,13 +981,6 @@
 
 	bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-
-	if (bdp->driver_isolated) {
-		rc = -EBUSY;
-		goto exit;
-	}
-
 	/* setup the tcb pool */
 	if (!e100_alloc_tcb_pool(bdp)) {
 		rc = -ENOMEM;
@@ -960,12 +999,12 @@
 		goto err_exit;
 	}
 
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) {
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) {
 		rc = -EAGAIN;
 		goto err_exit;
 	}
 
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) {
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) {
 		rc = -EAGAIN;
 		goto err_exit;
 	}
@@ -990,7 +1029,6 @@
 err_exit:
 	e100_clear_pools(bdp);
 exit:
-	read_unlock(&(bdp->isolate_lock));
 	return rc;
 }
 
@@ -999,18 +1037,16 @@
 {
 	struct e100_private *bdp = dev->priv;
 
+	e100_disable_clear_intr(bdp);
+	free_irq(dev->irq, dev);
 	bdp->intr_mask = SCB_INT_MASK;
 	e100_isolate_driver(bdp);
 
 	netif_carrier_off(bdp->device);
 	bdp->cur_line_speed = 0;
 	bdp->cur_dplx_mode = 0;
-	free_irq(dev->irq, dev);
 	e100_clear_pools(bdp);
 
-	/* set the isolate flag to false, so e100_open can be called */
-	bdp->driver_isolated = false;
-
 	return 0;
 }
 
@@ -1031,13 +1067,6 @@
 	int notify_stop = false;
 	struct e100_private *bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-
-	if (bdp->driver_isolated) {
-		rc = -EBUSY;
-		goto exit2;
-	}
-
 	if (!spin_trylock(&bdp->bd_non_tx_lock)) {
 		notify_stop = true;
 		rc = 1;
@@ -1060,7 +1089,6 @@
 exit1:
 	spin_unlock(&bdp->bd_non_tx_lock);
 exit2:
-	read_unlock(&(bdp->isolate_lock));
 	if (notify_stop) {
 		netif_stop_queue(dev);
 	}
@@ -1113,20 +1141,15 @@
 	int rc = -1;
 	struct sockaddr *p_sockaddr = (struct sockaddr *) addr;
 
+	if (!is_valid_ether_addr(p_sockaddr->sa_data))
+		return -EADDRNOTAVAIL;
 	bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
 	if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) {
 		memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN);
 		rc = 0;
 	}
 
-exit:
-	read_unlock(&(bdp->isolate_lock));
 	return rc;
 }
 
@@ -1180,10 +1203,6 @@
 	unsigned char promisc_enbl;
 	unsigned char mulcast_enbl;
 
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
 	promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC);
 	mulcast_enbl = ((dev->flags & IFF_ALLMULTI) ||
 			(dev->mc_count > MAX_MULTICAST_ADDRS));
@@ -1195,14 +1214,11 @@
 	e100_config(bdp);
 
 	if (promisc_enbl || mulcast_enbl) {
-		goto exit;	/* no need for Multicast Cmd */
+		return;	/* no need for Multicast Cmd */
 	}
 
 	/* get the multicast CB */
 	e100_set_multi_exec(dev);
-
-exit:
-	read_unlock(&(bdp->isolate_lock));
 }
 
 static int
@@ -1261,14 +1277,19 @@
 
 	/* read the MAC address from the eprom */
 	e100_rd_eaddr(bdp);
+	if (!is_valid_ether_addr(bdp->device->dev_addr)) {
+		printk(KERN_ERR "e100: Invalid Ethernet address\n");
+		return false;
+	}
 	/* read NIC's part number */
 	e100_rd_pwa_no(bdp);
 
-	if (!e100_hw_init(bdp, PORT_SOFTWARE_RESET)) {
+	if (!e100_hw_init(bdp)) {
 		printk(KERN_ERR "e100: hw init failed\n");
 		return false;
 	}
-	e100_dis_intr(bdp);
+	/* Interrupts are enabled after device reset */
+	e100_disable_clear_intr(bdp);
 
 	return true;
 }
@@ -1308,16 +1329,50 @@
 	spin_lock_init(&(bdp->bd_non_tx_lock));
 	spin_lock_init(&(bdp->config_lock));
 	spin_lock_init(&(bdp->mdi_access_lock));
-	bdp->isolate_lock = RW_LOCK_UNLOCKED;
-	bdp->driver_isolated = false;
 
 	return 1;
 }
 
+static void __devinit
+e100_tco_workaround(struct e100_private *bdp)
+{
+	int i;
+
+	/* Do software reset */
+	e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
+
+	/* Do a dummy LOAD CU BASE command. */
+	/* This gets us out of pre-driver to post-driver. */
+	e100_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE);
+
+	/* Wait 20 msec for reset to take effect */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ / 50 + 1);
+
+	/* disable interrupts since they are enabled */
+	/* after device reset                        */
+	e100_disable_clear_intr(bdp);
+
+	/* Wait for command to be cleared up to 1 sec */
+	for (i=0; i<100; i++) {
+		if (!readb(&bdp->scb->scb_cmd_low))
+			break;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ / 100 + 1);
+	}
+
+	/* Wait for TCO request bit in PMDR register to be clear */
+	for (i=0; i<50; i++) {
+		if (!(readb(&bdp->scb->scb_ext.d101m_scb.scb_pmdr) & BIT_1))
+			break;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ / 100 + 1);
+	}
+}
+
 /**
  * e100_hw_init - initialized tthe hardware
  * @bdp: atapter's private data struct
- * @reset_cmd: s/w reset or selective reset
  *
  * This routine performs a reset on the adapter, and configures the adapter.
  * This includes configuring the 82557 LAN controller, validating and setting
@@ -1329,19 +1384,22 @@
  *      false - If the adapter failed initialization
  */
 unsigned char __devinit
-e100_hw_init(struct e100_private *bdp, u32 reset_cmd)
+e100_hw_init(struct e100_private *bdp)
 {
 	if (!e100_phy_init(bdp))
 		return false;
 
-	/* Issue a software reset to the e100 */
-	e100_sw_reset(bdp, reset_cmd);
+	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
+
+	/* Only 82559 or above needs TCO workaround */
+	if (bdp->rev_id >= D101MA_REV_ID)
+		e100_tco_workaround(bdp);
 
 	/* Load the CU BASE (set to 0, because we use linear mode) */
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE))
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
 		return false;
 
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE))
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
 		return false;
 
 	/* Load interrupt microcode  */
@@ -1391,6 +1449,7 @@
 	u32 next_phys;		/* the next phys addr */
 	u16 txcommand = CB_S_BIT | CB_TX_SF_BIT;
 
+	bdp->tx_count = 0;
 	if (bdp->flags & USE_IPCB) {
 		txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT;
 	} else if (bdp->flags & IS_BACHELOR) {
@@ -1625,14 +1684,15 @@
 {
 	struct e100_private *bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		goto exit;
+#ifdef E100_CU_DEBUG
+	if (e100_cu_unknown_state(bdp)) {
+		printk(KERN_ERR "e100: %s: CU unknown state in e100_watchdog\n",
+			dev->name);
 	}
+#endif	
 	if (!netif_running(dev)) {
-		goto exit;
+		return;
 	}
-	e100_get_mdix_status(bdp);
 
 	/* check if link state has changed */
 	if (e100_phy_check(bdp)) {
@@ -1645,37 +1705,10 @@
 
 			e100_config_fc(bdp);
 			e100_config(bdp);  
-			bdp->cable_status = "Cable OK";
 
 		} else {
 			printk(KERN_ERR "e100: %s NIC Link is Down\n",
 			       bdp->device->name);
-                	if (bdp->rev_id < D102_REV_ID)
-				bdp->cable_status = "Not supported";
-		        else {				
-				/* Initiate hwi, ie, cable diagnostic */
-				bdp->saved_open_circut = 0xffff;
-				bdp->saved_short_circut = 0xffff;
-				bdp->saved_distance = 0xffff;
-				bdp->saved_i = 0;
-				bdp->saved_same = 0;
-				bdp->hwi_started = 1;
-				
-				/* Disable MDI/MDI-X auto switching */
-                		e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
-		                	MDI_MDIX_RESET_ALL_MASK);
-
-				/* Set to 100 Full as required by hwi test */
-				e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
-				       BMCR_SPEED100 | BMCR_FULLDPLX);
-
-				/* Enable and execute HWI test */
-				e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
-					(HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
-
-				/* Launch hwi timer in 1 msec */
-				mod_timer(&(bdp->hwi_timer), jiffies + (HZ / 1000) );
-			}
 		}
 	}
 
@@ -1685,7 +1718,13 @@
 		if (netif_running(dev))
 			netif_wake_queue(dev);
 	} else {
-		netif_stop_queue(dev);
+		if (netif_running(dev))
+			netif_stop_queue(dev);
+		/* When changing to non-autoneg, device may lose  */
+		/* link with some switches. e100 will try to      */
+		/* revover link by sending command to PHY layer   */
+		if (bdp->params.e100_speed_duplex != E100_AUTONEG)
+			e100_force_speed_duplex_to_phy(bdp);
 	}
 
 	rmb();
@@ -1721,9 +1760,6 @@
 
 	if (list_empty(&bdp->active_rx_list))
 		e100_trigger_SWI(bdp);
-
-exit:
-	read_unlock(&(bdp->isolate_lock));
 }
 
 /**
@@ -1812,15 +1848,13 @@
 	bdp = dev->priv;
 
 	intr_status = readw(&bdp->scb->scb_status);
-	if (!intr_status || (intr_status == 0xffff)) {
+	/* If not my interrupt, just return */
+	if (!(intr_status & SCB_STATUS_ACK_MASK) || (intr_status == 0xffff)) {
 		return;
 	}
 
-	/* disable intr before we ack & after identifying the intr as ours */
-	e100_dis_intr(bdp);
-
-	writew(intr_status, &bdp->scb->scb_status);	/* ack intrs */
-	readw(&bdp->scb->scb_status);
+	/* disable and ack intr */
+	e100_disable_clear_intr(bdp);
 
 	/* the device is closed, don't continue or else bad things may happen. */
 	if (!netif_running(dev)) {
@@ -1828,11 +1862,6 @@
 		return;
 	}
 
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
-
 	/* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */
 	if (intr_status & SCB_STATUS_ACK_SWI) {
 		e100_alloc_skbs(bdp);
@@ -1844,14 +1873,10 @@
 		bdp->drv_stats.rx_intr_pkts += e100_rx_srv(bdp);
 
 	/* clean up after tx'ed packets */
-	if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) {
-		bdp->tx_count = 0;	/* restart tx interrupt batch count */
+	if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX))
 		e100_tx_srv(bdp);
-	}
 
-exit:
 	e100_set_intr_mask(bdp);
-	read_unlock(&(bdp->isolate_lock));
 }
 
 /**
@@ -1861,7 +1886,7 @@
  *
  * This routine frees resources of TX skbs.
  */
-static void inline
+static inline void
 e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb)
 {
 	if (tcb->tcb_skb) {
@@ -1980,7 +2005,7 @@
 		/* to allow manipulation with current skb we need to unlink it */
 		list_del(&(rx_struct->list_elem));
 
-		/* do not free & unmap badly recieved packet.
+		/* do not free & unmap badly received packet.
 		 * move it to the end of skb list for reuse */
 		if (!(rfd_status & RFD_STATUS_OK)) {
 			e100_add_skb_to_end(bdp, rx_struct);
@@ -2024,17 +2049,15 @@
 		} else {
 			skb->ip_summed = CHECKSUM_NONE;
 		}
-		switch (netif_rx(skb)) {
-		case NET_RX_BAD:
-		case NET_RX_DROP:
-		case NET_RX_CN_MOD:
-		case NET_RX_CN_HIGH:
-			break;
-		default:
-			bdp->drv_stats.net_stats.rx_bytes += skb->len;
-			break;
-		}
 
+		if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) {
+			vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid));
+		} else {
+			netif_rx(skb);
+		}
+		dev->last_rx = jiffies;
+		bdp->drv_stats.net_stats.rx_bytes += skb->len;
+		
 		rfd_cnt++;
 	}			/* end of rfd loop */
 
@@ -2102,32 +2125,6 @@
 }
 
 /**
- * e100_pseudo_hdr_csum - compute IP pseudo-header checksum
- * @ip: points to the header of the IP packet
- *
- * Return the 16 bit checksum of the IP pseudo-header.,which is computed
- * on the fields: IP src, IP dst, next protocol, payload length.
- * The checksum vaule is returned in network byte order.
- */
-static inline u16
-e100_pseudo_hdr_csum(const struct iphdr *ip)
-{
-	u32 pseudo = 0;
-	u32 payload_len = 0;
-
-	payload_len = ntohs(ip->tot_len) - (ip->ihl * 4);
-
-	pseudo += htons(payload_len);
-	pseudo += (ip->protocol << 8);
-	pseudo += ip->saddr & 0x0000ffff;
-	pseudo += (ip->saddr & 0xffff0000) >> 16;
-	pseudo += ip->daddr & 0x0000ffff;
-	pseudo += (ip->daddr & 0xffff0000) >> 16;
-
-	return FOLD_CSUM(pseudo);
-}
-
-/**
  * e100_prepare_xmit_buff - prepare a buffer for transmission
  * @bdp: atapter's private data struct
  * @skb: skb to send
@@ -2153,15 +2150,21 @@
 		tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE;
 	}
 
+	if(bdp->vlgrp && vlan_tx_tag_present(skb)) {
+		(tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE;
+		(tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb));
+	}
+	
 	tcb->tcb_hdr.cb_status = 0;
 	tcb->tcb_thrshld = bdp->tx_thld;
 	tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT);
 
-	/* set the I bit on the modulo tcbs, so we will get an interrupt * to
-	 * clean things up */
-	if (!(++bdp->tx_count % TX_FRAME_CNT)) {
+	/* Set I (Interrupt) bit on every (TX_FRAME_CNT)th packet */
+	if (!(++bdp->tx_count % TX_FRAME_CNT))
 		tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT);
-	}
+	else
+		/* Clear I bit on other packets */
+		tcb->tcb_hdr.cb_cmd &= ~__constant_cpu_to_le16(CB_I_BIT);
 
 	tcb->tcb_skb = skb;
 
@@ -2170,27 +2173,14 @@
 
 		if ((ip->protocol == IPPROTO_TCP) ||
 		    (ip->protocol == IPPROTO_UDP)) {
-			u16 *chksum;
 
-			tcb->tcbu.ipcb.ip_activation_high =
+			tcb->tcbu.ipcb.ip_activation_high |=
 				IPCB_HARDWAREPARSING_ENABLE;
 			tcb->tcbu.ipcb.ip_schedule |=
 				IPCB_TCPUDP_CHECKSUM_ENABLE;
 
-			if (ip->protocol == IPPROTO_TCP) {
-				struct tcphdr *tcp;
-
-				tcp = (struct tcphdr *) ((u32 *) ip + ip->ihl);
-				chksum = &(tcp->check);
+			if (ip->protocol == IPPROTO_TCP)
 				tcb->tcbu.ipcb.ip_schedule |= IPCB_TCP_PACKET;
-			} else {
-				struct udphdr *udp;
-
-				udp = (struct udphdr *) ((u32 *) ip + ip->ihl);
-				chksum = &(udp->check);
-			}
-
-			*chksum = e100_pseudo_hdr_csum(ip);
 		}
 	}
 
@@ -2257,15 +2247,16 @@
  *
  * e100_start_cu must be called while holding the tx_lock ! 
  */
-void
+u8
 e100_start_cu(struct e100_private *bdp, tcb_t *tcb)
 {
 	unsigned long lock_flag;
+	u8 ret = true;
 
 	spin_lock_irqsave(&(bdp->bd_lock), lock_flag);
 	switch (bdp->next_cu_cmd) {
 	case RESUME_NO_WAIT:
-		/*last cu command was a CU_RESMUE if this is a 558 or newer we dont need to
+		/*last cu command was a CU_RESMUE if this is a 558 or newer we don't need to
 		 * wait for command word to clear, we reach here only if we are bachlor
 		 */
 		e100_exec_cmd(bdp, SCB_CUC_RESUME);
@@ -2291,12 +2282,13 @@
 			       "e100: %s: cu_start: timeout waiting for cu\n",
 			       bdp->device->name);
 		if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
-					  SCB_CUC_START)) {
+					  SCB_CUC_START, CB_TRANSMIT)) {
 			printk(KERN_DEBUG
 			       "e100: %s: cu_start: timeout waiting for scb\n",
 			       bdp->device->name);
 			e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
 					SCB_CUC_START);
+			ret = false;
 		}
 
 		bdp->next_cu_cmd = RESUME_WAIT;
@@ -2308,6 +2300,7 @@
 	bdp->last_tcb = tcb;
 
 	spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
+	return ret;
 }
 
 /* ====================================================================== */
@@ -2355,8 +2348,9 @@
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ / 100 + 1);
 
-	/* disable interrupts since the're now enabled */
-	e100_dis_intr(bdp);
+	/* disable interrupts since they are enabled */
+	/* after device reset during selftest        */
+	e100_disable_clear_intr(bdp);
 
 	/* if The First Self Test DWORD Still Zero, We've timed out. If the
 	 * second DWORD is not zero then we have an error. */
@@ -2454,7 +2448,7 @@
 
 	spin_lock(&bdp->bd_lock);
 
-	if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START)) {
+	if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START, 0)) {
 		printk(KERN_DEBUG
 		       "e100: %s: start_ru: wait_scb failed\n", 
 		       bdp->device->name);
@@ -2522,7 +2516,7 @@
 	*pcmd_complete = 0;
 	wmb();
 
-	if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR))
+	if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0))
 		return false;
 
 	/* wait 10 microseconds for the command to complete */
@@ -2644,8 +2638,10 @@
 	unsigned long lock_flag;
 	unsigned long expiration_time;
 	unsigned char rc = true;
+	u8 sub_cmd;
 
 	ntcb_hdr = (cb_header_t *) command->non_tx_cmd;	/* get hdr of non tcb cmd */
+	sub_cmd = cpu_to_le16(ntcb_hdr->cb_cmd);
 
 	/* Set the Command Block to be the last command block */
 	ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT);
@@ -2656,7 +2652,7 @@
 	if (in_interrupt())
 		return e100_delayed_exec_non_cu_cmd(bdp, command);
 
-	if (netif_running(bdp->device) && (!bdp->driver_isolated))
+	if (netif_running(bdp->device) && netif_carrier_ok(bdp->device))
 		return e100_delayed_exec_non_cu_cmd(bdp, command);
 
 	spin_lock_bh(&(bdp->bd_non_tx_lock));
@@ -2678,7 +2674,7 @@
 
 	spin_lock_irqsave(&bdp->bd_lock, lock_flag);
 
-	if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START)) {
+	if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START, sub_cmd)) {
 		spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
 		rc = false;
 		goto exit;
@@ -2698,6 +2694,10 @@
 			yield();
 			spin_lock_bh(&(bdp->bd_non_tx_lock));
 		} else {
+#ifdef E100_CU_DEBUG			
+			printk(KERN_ERR "e100: %s: non-TX command (%x) "
+				"timeout\n", bdp->device->name, sub_cmd);
+#endif			
 			rc = false;
 			goto exit;
 		}
@@ -2742,8 +2742,12 @@
 		udelay(20);
 	}
 
-	/* Mask off our interrupt line -- its unmasked after reset */
-	e100_dis_intr(bdp);
+	/* Mask off our interrupt line -- it is unmasked after reset */
+	e100_disable_clear_intr(bdp);
+#ifdef E100_CU_DEBUG	
+	bdp->last_cmd = 0;
+	bdp->last_sub_cmd = 0;
+#endif	
 }
 
 /**
@@ -2943,19 +2947,6 @@
 void __devinit
 e100_print_brd_conf(struct e100_private *bdp)
 {
-	if (netif_carrier_ok(bdp->device)) {
-		printk(KERN_NOTICE
-		       "  Mem:0x%08lx  IRQ:%d  Speed:%d Mbps  Dx:%s\n",
-		       (unsigned long) bdp->device->mem_start,
-		       bdp->device->irq, bdp->cur_line_speed,
-		       (bdp->cur_dplx_mode == FULL_DUPLEX) ? "Full" : "Half");
-	} else {
-		printk(KERN_NOTICE
-		       "  Mem:0x%08lx  IRQ:%d  Speed:%d Mbps  Dx:%s\n",
-		       (unsigned long) bdp->device->mem_start,
-		       bdp->device->irq, 0, "N/A");
-	}
-
 	/* Print the string if checksum Offloading was enabled */
 	if (bdp->flags & DF_CSUM_OFFLOAD)
 		printk(KERN_NOTICE "  Hardware receive checksums enabled\n");
@@ -2969,27 +2960,6 @@
 }
 
 /**
- * e100_get_brand_msg
- * @bdp: atapter's private data struct
- *
- * This routine checks if there is specified branding message for a given board
- * type and returns a pointer to the string containing the branding message.
- */
-char *
-e100_get_brand_msg(struct e100_private *bdp)
-{
-	int i;
-
-	for (i = 0; e100_vendor_info_array[i].idstr != NULL; i++) {
-		if (e100_vendor_info_array[i].device_type == bdp->device_type) {
-			return e100_vendor_info_array[i].idstr;
-		}
-	}
-
-	return e100_vendor_info_array[E100_ALL_BOARDS].idstr;
-}
-
-/**
  * e100_pci_setup - setup the adapter's PCI information
  * @pcid: adapter's pci_dev struct
  * @bdp: atapter's private data struct
@@ -3054,33 +3024,36 @@
 void
 e100_isolate_driver(struct e100_private *bdp)
 {
-	write_lock_irq(&(bdp->isolate_lock));
-	bdp->driver_isolated = true;
-	write_unlock_irq(&(bdp->isolate_lock));
-
-	del_timer_sync(&bdp->watchdog_timer);
-
-	del_timer_sync(&bdp->hwi_timer);
-	/* If in middle of cable diag, */
-	if (bdp->hwi_started) {
-		bdp->hwi_started = 0;
-		e100_hwi_restore(bdp);
-	}
-
-	if (netif_running(bdp->device))
-		netif_stop_queue(bdp->device);
-
-	bdp->last_tcb = NULL;
 
+	/* Check if interface is up                              */
+	/* NOTE: Can't use netif_running(bdp->device) because    */
+	/* dev_close clears __LINK_STATE_START before calling    */
+	/* e100_close (aka dev->stop)                            */
+	if (bdp->device->flags & IFF_UP) {
+		e100_disable_clear_intr(bdp);
+		del_timer_sync(&bdp->watchdog_timer);
+		netif_carrier_off(bdp->device);
+		netif_stop_queue(bdp->device); 
+		bdp->last_tcb = NULL;
+	} 
 	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
 }
 
 void
 e100_set_speed_duplex(struct e100_private *bdp)
 {
+	int carrier_ok;
+	/* Device may lose link with some siwtches when */
+	/* changing speed/duplex to non-autoneg. e100   */
+	/* needs to remember carrier state in order to  */
+	/* start watchdog timer for recovering link     */
+	if ((carrier_ok = netif_carrier_ok(bdp->device)))
+		e100_isolate_driver(bdp);
 	e100_phy_set_speed_duplex(bdp, true);
 	e100_config_fc(bdp);	/* re-config flow-control if necessary */
 	e100_config(bdp);	
+	if (carrier_ok)
+		e100_deisolate_driver(bdp, false);
 }
 
 static void
@@ -3095,63 +3068,51 @@
 }
 
 /* 
- * Procedure:   e100_hw_reset_recover
+ * Procedure:   e100_configure_device
  *
- * Description: This routine will recover the hw after reset.
+ * Description: This routine will configure device
  *
  * Arguments:
  *      bdp - Ptr to this card's e100_bdconfig structure
- *        reset_cmd - s/w reset or selective reset. 
  *
  * Returns:
  *        true upon success
  *        false upon failure
  */
 unsigned char
-e100_hw_reset_recover(struct e100_private *bdp, u32 reset_cmd)
+e100_configure_device(struct e100_private *bdp)
 {
-	bdp->last_tcb = NULL;
-	if (reset_cmd == PORT_SOFTWARE_RESET) {
-
-		/*load CU & RU base */
-		if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) {
-			return false;
-		}
-
-		if (e100_load_microcode(bdp)) {
-			bdp->flags |= DF_UCODE_LOADED;
-		}
+	/*load CU & RU base */
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
+		return false;
 
-		if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) {
-			return false;
-		}
+	if (e100_load_microcode(bdp))
+		bdp->flags |= DF_UCODE_LOADED;
 
-		/* Issue the load dump counters address command */
-		if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys,
-					  SCB_CUC_DUMP_ADDR)) {
-			return false;
-		}
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
+		return false;
 
-		if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) {
-			printk(KERN_ERR
-			       "e100: e100_hw_reset_recover: "
-			       "setup iaaddr failed\n");
-			return false;
-		}
+	/* Issue the load dump counters address command */
+	if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0))
+		return false;
 
-		e100_set_multi_exec(bdp->device);
+	if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) {
+		printk(KERN_ERR "e100: e100_configure_device: "
+			"setup iaaddr failed\n");
+		return false;
+	}
 
-		/* Change for 82558 enhancement */
-		/* If 82558/9 and if the user has enabled flow control, set up * the
-		 * Flow Control Reg. in the CSR */
-		if ((bdp->flags & IS_BACHELOR)
-		    && (bdp->params.b_params & PRM_FC)) {
-			writeb(DFLT_FC_THLD,
-			       &bdp->scb->scb_ext.d101_scb.scb_fc_thld);
-			writeb(DFLT_FC_CMD,
-			       &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
-		}
+	e100_set_multi_exec(bdp->device);
 
+	/* Change for 82558 enhancement                                */
+	/* If 82558/9 and if the user has enabled flow control, set up */
+	/* flow Control Reg. in the CSR                                */
+	if ((bdp->flags & IS_BACHELOR)
+	    && (bdp->params.b_params & PRM_FC)) {
+		writeb(DFLT_FC_THLD,
+			&bdp->scb->scb_ext.d101_scb.scb_fc_thld);
+		writeb(DFLT_FC_CMD,
+			&bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
 	}
 
 	e100_force_config(bdp);
@@ -3160,29 +3121,21 @@
 }
 
 void
-e100_deisolate_driver(struct e100_private *bdp, u8 recover, u8 full_init)
+e100_deisolate_driver(struct e100_private *bdp, u8 full_reset)
 {
-	if (full_init) {
-		e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
-		if (!e100_hw_reset_recover(bdp, PORT_SOFTWARE_RESET))
-			printk(KERN_ERR "e100: e100_deisolate_driver:"
-			       " HW SOFTWARE reset recover failed\n");
-	}
+	u32 cmd = full_reset ? PORT_SOFTWARE_RESET : PORT_SELECTIVE_RESET;
+	e100_sw_reset(bdp, cmd);
+	if (cmd == PORT_SOFTWARE_RESET) {
+		if (!e100_configure_device(bdp))
+			printk(KERN_ERR "e100: e100_deisolate_driver:" 
+		       		" device configuration failed\n");
+	} 
 
-	if (recover) {
+	if (netif_running(bdp->device)) {
 
 		bdp->next_cu_cmd = START_WAIT;
 		bdp->last_tcb = NULL;
 
-		/* lets reset the chip */
-		if (!full_init) {
-			e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
-
-			if (!e100_hw_reset_recover(bdp, PORT_SELECTIVE_RESET)) {
-				printk(KERN_ERR "e100: e100_deisolate_driver:"
-				       " HW reset recover failed\n");
-			}
-		}
 		e100_start_ru(bdp);
 
 		/* relaunch watchdog timer in 2 sec */
@@ -3192,14 +3145,9 @@
 		// or have unsent frames on the tcb chain
 		e100_tcb_add_C_bit(bdp);
 		e100_tx_srv(bdp);
-
+		netif_wake_queue(bdp->device);
 		e100_set_intr_mask(bdp);
-
-		if (netif_running(bdp->device))
-			netif_wake_queue(bdp->device);
 	}
-
-	bdp->driver_isolated = false;
 }
 
 static int
@@ -3234,6 +3182,22 @@
 	case ETHTOOL_SEEPROM:
 		rc = e100_ethtool_eeprom(dev, ifr);
 		break;
+	case ETHTOOL_GSTATS: {
+		struct {
+			struct ethtool_stats cmd;
+			uint64_t data[E100_STATS_LEN];
+		} stats = { {ETHTOOL_GSTATS, E100_STATS_LEN} };
+		struct e100_private *bdp = dev->priv;
+		void *addr = ifr->ifr_data;
+		int i;
+
+		for(i = 0; i < E100_STATS_LEN; i++)
+			stats.data[i] =
+				((unsigned long *)&bdp->drv_stats.net_stats)[i];
+		if(copy_to_user(addr, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
 	case ETHTOOL_GWOL:
 	case ETHTOOL_SWOL:
 		rc = e100_ethtool_wol(dev, ifr);
@@ -3316,10 +3280,8 @@
 e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr)
 {
 	struct e100_private *bdp;
-	int current_duplex;
 	int e100_new_speed_duplex;
 	int ethtool_new_speed_duplex;
-	int speed_duplex_change_required;
 	struct ethtool_cmd ecmd;
 
 	if (!capable(CAP_NET_ADMIN)) {
@@ -3327,64 +3289,48 @@
 	}
 
 	bdp = dev->priv;
-	if (netif_running(dev)) {
-		return -EBUSY;
-	}
 	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) {
 		return -EFAULT;
 	}
-	current_duplex =
-		(bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
-	speed_duplex_change_required = (ecmd.speed != bdp->cur_line_speed)
-		|| (ecmd.duplex != current_duplex);
-
-	if ((ecmd.autoneg == AUTONEG_ENABLE) && speed_duplex_change_required) {
-		return -EINVAL;
-	}
 
 	if ((ecmd.autoneg == AUTONEG_ENABLE)
 	    && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) {
 		bdp->params.e100_speed_duplex = E100_AUTONEG;
 		e100_set_speed_duplex(bdp);
 	} else {
-		if (speed_duplex_change_required) {
-			if (ecmd.speed == SPEED_10) {
-				if (ecmd.duplex == DUPLEX_HALF) {
-					e100_new_speed_duplex =
-						E100_SPEED_10_HALF;
-					ethtool_new_speed_duplex =
-						SUPPORTED_10baseT_Half;
-
-				} else {
-					e100_new_speed_duplex =
-						E100_SPEED_10_FULL;
-					ethtool_new_speed_duplex =
-						SUPPORTED_10baseT_Full;
-				}
-
-			} else {
-				if (ecmd.duplex == DUPLEX_HALF) {
-					e100_new_speed_duplex =
-						E100_SPEED_100_HALF;
-					ethtool_new_speed_duplex =
-						SUPPORTED_100baseT_Half;
-
-				} else {
-					e100_new_speed_duplex =
-						E100_SPEED_100_FULL;
-					ethtool_new_speed_duplex =
-						SUPPORTED_100baseT_Full;
-				}
-			}
-
-			if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) {
-				bdp->params.e100_speed_duplex =
-					e100_new_speed_duplex;
-				e100_set_speed_duplex(bdp);
-			} else {
-				return -EOPNOTSUPP;
-			}
-		}
+		if (ecmd.speed == SPEED_10) {
+			if (ecmd.duplex == DUPLEX_HALF) {
+				e100_new_speed_duplex =
+					E100_SPEED_10_HALF;
+				ethtool_new_speed_duplex =
+					SUPPORTED_10baseT_Half;
+			} else { 
+				e100_new_speed_duplex =
+					E100_SPEED_10_FULL;
+				ethtool_new_speed_duplex =
+					SUPPORTED_10baseT_Full;
+			} 
+		} else { 
+			if (ecmd.duplex == DUPLEX_HALF) {
+				e100_new_speed_duplex =
+					E100_SPEED_100_HALF;
+				ethtool_new_speed_duplex =
+					SUPPORTED_100baseT_Half;
+			} else { 
+				e100_new_speed_duplex =
+					E100_SPEED_100_FULL;
+				ethtool_new_speed_duplex =
+					SUPPORTED_100baseT_Full;
+			} 
+		}
+
+		if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) {
+			bdp->params.e100_speed_duplex =
+				e100_new_speed_duplex;
+			e100_set_speed_duplex(bdp);
+		} else {
+			return -EOPNOTSUPP;
+		} 
 	}
 
 	return 0;
@@ -3503,6 +3449,7 @@
 		sizeof (info.fw_version) - 1);
 	strncpy(info.bus_info, bdp->pdev->slot_name,
 		sizeof (info.bus_info) - 1);
+	info.n_stats = E100_STATS_LEN;
 	info.regdump_len  = E100_REGS_LEN * sizeof(u32);
 	info.eedump_len = (bdp->eeprom_size << 1);	
 	info.testinfo_len = E100_MAX_TEST_RES;
@@ -3522,6 +3469,7 @@
 	u16 first_word, last_word;
 	int i, max_len;
 	void *ptr;
+	u8 *eeprom_data_bytes = (u8 *)eeprom_data;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
@@ -3557,7 +3505,9 @@
 		if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
 			return -EFAULT;
 
-		if (copy_to_user(usr_eeprom_ptr, eeprom_data, ecmd.len))
+		if(ecmd.offset & 1)
+			eeprom_data_bytes++;
+		if (copy_to_user(usr_eeprom_ptr, eeprom_data_bytes, ecmd.len))
 			return -EFAULT;
 	} else {
 		if (ecmd.magic != E100_EEPROM_MAGIC)
@@ -3850,7 +3800,8 @@
 		return -EFAULT;
 
 	switch (info.string_set) {
-	case ETH_SS_TEST:
+	case ETH_SS_TEST: {
+		int ret = 0;
 		if (info.len > E100_MAX_TEST_RES)
 			info.len = E100_MAX_TEST_RES;
 		strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
@@ -3862,19 +3813,29 @@
 			sprintf(strings + i * ETH_GSTRING_LEN, "%-31s",
 				test_strings[i]);
 		}
-		break;
+		if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+			ret = -EFAULT;
+		if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN))
+			ret = -EFAULT;
+		kfree(strings);
+		return ret;
+	}
+	case ETH_SS_STATS: {
+		char *strings = NULL;
+		void *addr = ifr->ifr_data;
+		info.len = E100_STATS_LEN;
+		strings = *e100_gstrings_stats;
+		if(copy_to_user(ifr->ifr_data, &info, sizeof(info)))
+			return -EFAULT;
+		addr += offsetof(struct ethtool_gstrings, data);
+		if(copy_to_user(addr, strings,
+		   info.len * ETH_GSTRING_LEN))
+			return -EFAULT;
+		return 0;
+	}
 	default:
 		return -EOPNOTSUPP;
 	}
-
-	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
-		return -EFAULT;
-
-	if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN))
-		return -EFAULT;
-
-	kfree(strings);
-	return 0;
 }
 
 static int
@@ -3901,9 +3862,6 @@
 	case SIOCSMIIREG:
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		if (netif_running(dev)) {
-			return -EBUSY;
-		}
 		/* If reg = 0 && change speed/duplex */
 		if (data_ptr->reg_num == 0 && 
 			(data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */
@@ -3923,10 +3881,9 @@
 					bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
 				e100_set_speed_duplex(bdp);
 		}
-		else {
-			e100_mdi_write(bdp, data_ptr->reg_num, bdp->phy_addr,
-			       data_ptr->val_in);
-		}
+		else 
+			/* Only allows changing speed/duplex */
+			return -EINVAL;
 		
 		break;
 
@@ -4023,6 +3980,8 @@
 	struct e100_private *bdp = (struct e100_private *) ptr;
 	nxmit_cb_entry_t *active_command;
 	int restart = true;
+	cb_header_t *non_tx_cmd;
+	u8 sub_cmd;
 
 	spin_lock_bh(&(bdp->bd_non_tx_lock));
 
@@ -4050,6 +4009,15 @@
 		    && time_before(jiffies, active_command->expiration_time)) {
 			goto exit;
 		} else {
+			non_tx_cmd = (cb_header_t *) active_command->non_tx_cmd;
+			sub_cmd = CB_CMD_MASK & le16_to_cpu(non_tx_cmd->cb_cmd);
+#ifdef E100_CU_DEBUG			
+			if (!(non_tx_cmd->cb_status 
+			    & __constant_cpu_to_le16(CB_STATUS_COMPLETE)))
+				printk(KERN_ERR "e100: %s: Queued "
+					"command (%x) timeout\n", 
+					bdp->device->name, sub_cmd);
+#endif			
 			list_del(&(active_command->list_elem));
 			e100_free_non_tx_cmd(bdp, active_command);
 		}
@@ -4072,9 +4040,10 @@
 		bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH;
 		active_command = list_entry(bdp->non_tx_cmd_list.next,
 					    nxmit_cb_entry_t, list_elem);
+		sub_cmd = ((cb_header_t *) active_command->non_tx_cmd)->cb_cmd;
 		spin_lock_irq(&(bdp->bd_lock));
 		e100_wait_exec_cmplx(bdp, active_command->dma_addr,
-				     SCB_CUC_START);
+				     SCB_CUC_START, sub_cmd);
 		spin_unlock_irq(&(bdp->bd_lock));
 		active_command->expiration_time = jiffies + HZ;
 		cmd_type = CB_CMD_MASK &
@@ -4093,27 +4062,43 @@
 	spin_unlock_bh(&(bdp->bd_non_tx_lock));
 }
 
-int e100_notify_netdev(struct notifier_block *nb, unsigned long event, void *p)
+static void
+e100_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
 {
-	struct e100_private *bdp;
-	struct net_device *netdev = p;
-	
-	if(netdev == NULL)
-		return NOTIFY_DONE;
-	
-	switch(event) {
-	case NETDEV_CHANGENAME:
-		if(netdev->open == e100_open) {
-			bdp = netdev->priv;
-			/* rename the proc nodes the easy way */
-			e100_remove_proc_subdir(bdp, bdp->ifname);
-			memcpy(bdp->ifname, netdev->name, IFNAMSIZ);
-			bdp->ifname[IFNAMSIZ-1] = 0;
-			e100_create_proc_subdir(bdp, bdp->ifname);
-		}
-		break;
+	struct e100_private *bdp = netdev->priv;
+
+	e100_disable_clear_intr(bdp);
+	bdp->vlgrp = grp;
+
+	if(grp) {
+		/* enable VLAN tag insert/strip */
+		e100_config_vlan_drop(bdp, true);
+
+	} else {
+		/* disable VLAN tag insert/strip */
+		e100_config_vlan_drop(bdp, false);
 	}
-	return NOTIFY_DONE;
+
+	e100_config(bdp);
+	e100_set_intr_mask(bdp);
+}
+
+static void
+e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+	/* We don't do Vlan filtering */
+	return;
+}
+
+static void
+e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+	struct e100_private *bdp = netdev->priv;
+
+	if(bdp->vlgrp)
+		bdp->vlgrp->vlan_devices[vid] = NULL;
+	/* We don't do Vlan filtering */
+	return;
 }
 
 #ifdef CONFIG_PM
@@ -4147,9 +4132,11 @@
 	e100_isolate_driver(bdp);
 	pci_save_state(pcid, bdp->pci_state);
 
+	/* Enable or disable WoL */
+	e100_do_wol(pcid, bdp);
+	
 	/* If wol is enabled */
-	if (bdp->wolopts) {
-		e100_do_wol(pcid, bdp);
+	if (bdp->wolopts || e100_asf_enabled(bdp)) {
 		pci_enable_wake(pcid, 3, 1);	/* Enable PME for power state D3 */
 		pci_set_power_state(pcid, 3);	/* Set power state to D3.        */
 	} else {
@@ -4165,145 +4152,56 @@
 {
 	struct net_device *netdev = pci_get_drvdata(pcid);
 	struct e100_private *bdp = netdev->priv;
-	u8 recover = false;
-	u8 full_init = false;
 
 	pci_set_power_state(pcid, 0);
 	pci_enable_wake(pcid, 0, 0);	/* Clear PME status and disable PME */
 	pci_restore_state(pcid, bdp->pci_state);
 
-	if (netif_running(netdev)) {
-		recover = true;
-	}
-
-	if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) {
-		full_init = true;
-	}
-
-	e100_deisolate_driver(bdp, recover, full_init);
+	/* Also do device full reset because device was in D3 state */
+	e100_deisolate_driver(bdp, true);
 
 	return 0;
 }
 #endif /* CONFIG_PM */
 
-static void
-e100_get_mdix_status(struct e100_private *bdp)
-{	
-	if (bdp->rev_id < D102_REV_ID) {
-		if (netif_carrier_ok(bdp->device))
-			bdp->mdix_status = "MDI";				
-		else			
-			bdp->mdix_status = "None";
-	} else {	
-		u16 ctrl_reg;
-		/* Read the MDIX control register */
-		e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &ctrl_reg);
-		if (ctrl_reg & MDI_MDIX_CONFIG_IS_OK) {
-			if (ctrl_reg & MDI_MDIX_STATUS)
-				bdp->mdix_status = "MDI-X";
-			else
-				bdp->mdix_status = "MDI";
-		} else
-			bdp->mdix_status = "None";
-	}
-}
-
-static void
-e100_do_hwi(struct net_device *dev)
+/**
+ * e100_asf_enabled - checks if ASF is configured on the current adaper
+ *                    by reading registers 0xD and 0x90 in the EEPROM 
+ * @bdp: atapter's private data struct
+ *
+ * Returns: true if ASF is enabled
+ */
+static unsigned char
+e100_asf_enabled(struct e100_private *bdp)
 {
-	struct e100_private *bdp = dev->priv;
-	u16 ctrl_reg;
-	int distance, open_circut, short_circut;
-
-	e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg);
-
-	distance = ctrl_reg & HWI_TEST_DISTANCE;
-	open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM;
-	short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM;
-
-	if ((distance == bdp->saved_distance) &&
-	    (open_circut == bdp->saved_open_circut) &&
-	    (short_circut == bdp->saved_short_circut)) 
-		bdp->saved_same++;
-	else {
-		bdp->saved_same = 0;
-		bdp->saved_distance = distance;
-		bdp->saved_open_circut = open_circut;
-		bdp->saved_short_circut = short_circut;
-	}
-		
-	if (bdp->saved_same == MAX_SAME_RESULTS) {
-		if ((open_circut && !(short_circut)) ||
-		    (!(open_circut) && short_circut)) {
-
-			u8 near_end = ((distance * HWI_REGISTER_GRANULARITY) <
-				       HWI_NEAR_END_BOUNDARY);
-			if (open_circut) {
-				if (near_end) 
-					bdp->cable_status = "Open Circut Near End";
-				else 
-					bdp->cable_status = "Open Circut Far End";
-			} else {
-				if (near_end) 
-					bdp->cable_status = "Short Circut Near End";
-				else 
-					bdp->cable_status = "Short Circut Far End";
-			}
-			goto done;
+	u16 asf_reg;
+	u16 smbus_addr_reg;
+	if ((bdp->pdev->device >= 0x1050) && (bdp->pdev->device <= 0x1055)) {
+		asf_reg = e100_eeprom_read(bdp, EEPROM_CONFIG_ASF);
+		if ((asf_reg & EEPROM_FLAG_ASF)
+		    && !(asf_reg & EEPROM_FLAG_GCL)) {
+			smbus_addr_reg = 
+				e100_eeprom_read(bdp, EEPROM_SMBUS_ADDR);
+			if ((smbus_addr_reg & 0xFF) != 0xFE) 
+				return true;
 		}
 	}
-	else if (bdp->saved_i == HWI_MAX_LOOP) {
-		bdp->cable_status = "Test failed";
-		goto done;
-	}
-		
-	/* Do another hwi test */
-	e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
-		       (HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
-	bdp->saved_i++;
-	/* relaunch hwi timer in 1 msec */
-	mod_timer(&(bdp->hwi_timer), jiffies + (HZ / 1000) );
-	return;
-
-done:
-	e100_hwi_restore(bdp);
-	bdp->hwi_started = 0;
-	return;
+	return false;
 }
 
-static void e100_hwi_restore(struct e100_private *bdp)
+#ifdef E100_CU_DEBUG
+unsigned char
+e100_cu_unknown_state(struct e100_private *bdp)
 {
-	u16 control = 0;
-
-	/* Restore speed, duplex and autoneg before */
-	/* hwi test, i.e., cable diagnostic         */
-	
-	/* Reset hwi test */
-        e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,					       HWI_RESET_ALL_MASK);
-				
-	if ((bdp->params.e100_speed_duplex == E100_AUTONEG) &&
-        	(bdp->rev_id >= D102_REV_ID)) 
-		/* Enable MDI/MDI-X auto switching */
-                e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
-			MDI_MDIX_AUTO_SWITCH_ENABLE);
-
-	switch (bdp->params.e100_speed_duplex) {
-	case E100_SPEED_10_HALF:
-		break;
-	case E100_SPEED_10_FULL:
-		control = BMCR_FULLDPLX;
-		break;
-	case E100_SPEED_100_HALF:
-		control = BMCR_SPEED100;
-		break;
-	case E100_SPEED_100_FULL:
-		control = BMCR_SPEED100 | BMCR_FULLDPLX;
-		break;
-	case E100_AUTONEG:
-		control = BMCR_ANENABLE | BMCR_ANRESTART;
-		break;
-	}
-	/* Restore original speed/duplex */
-	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
-	return;
+	u8 scb_cmd_low;
+	u16 scb_status;
+	scb_cmd_low = bdp->scb->scb_cmd_low;
+	scb_status = le16_to_cpu(bdp->scb->scb_status);
+	/* If CU is active and executing unknown cmd */
+	if (scb_status & SCB_CUS_ACTIVE && scb_cmd_low & SCB_CUC_UNKNOWN)
+		return true;
+	else
+		return false;
 }
+#endif
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)