e1000: Dump the eeprom when a user encounters a bad checksum
authorAuke Kok <auke-jan.h.kok@intel.com>
Mon, 17 Dec 2007 21:50:23 +0000 (13:50 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 23:07:18 +0000 (15:07 -0800)
To help supporting users with a bad eeprom checksum, dump the
eeprom info when such a situation is encountered by a user.

Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/net/e1000/e1000_main.c

index 5b129964e832926ac50a2b6e17de84d1fa32a809..7f5b2ae70d5d56cdc056fe2a15daceb63d75a537 100644 (file)
@@ -817,6 +817,64 @@ e1000_reset(struct e1000_adapter *adapter)
        e1000_release_manageability(adapter);
 }
 
+/**
+ *  Dump the eeprom for users having checksum issues
+ **/
+void e1000_dump_eeprom(struct e1000_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct ethtool_eeprom eeprom;
+       const struct ethtool_ops *ops = netdev->ethtool_ops;
+       u8 *data;
+       int i;
+       u16 csum_old, csum_new = 0;
+
+       eeprom.len = ops->get_eeprom_len(netdev);
+       eeprom.offset = 0;
+
+       data = kmalloc(eeprom.len, GFP_KERNEL);
+       if (!data) {
+               printk(KERN_ERR "Unable to allocate memory to dump EEPROM"
+                      " data\n");
+               return;
+       }
+
+       ops->get_eeprom(netdev, &eeprom, data);
+
+       csum_old = (data[EEPROM_CHECKSUM_REG * 2]) +
+                  (data[EEPROM_CHECKSUM_REG * 2 + 1] << 8);
+       for (i = 0; i < EEPROM_CHECKSUM_REG * 2; i += 2)
+               csum_new += data[i] + (data[i + 1] << 8);
+       csum_new = EEPROM_SUM - csum_new;
+
+       printk(KERN_ERR "/*********************/\n");
+       printk(KERN_ERR "Current EEPROM Checksum : 0x%04x\n", csum_old);
+       printk(KERN_ERR "Calculated              : 0x%04x\n", csum_new);
+
+       printk(KERN_ERR "Offset    Values\n");
+       printk(KERN_ERR "========  ======\n");
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 16, 1, data, 128, 0);
+
+       printk(KERN_ERR "Include this output when contacting your support "
+              "provider.\n");
+       printk(KERN_ERR "This is not a software error! Something bad "
+              "happened to your hardware or\n");
+       printk(KERN_ERR "EEPROM image. Ignoring this "
+              "problem could result in further problems,\n");
+       printk(KERN_ERR "possibly loss of data, corruption or system hangs!\n");
+       printk(KERN_ERR "The MAC Address will be reset to 00:00:00:00:00:00, "
+              "which is invalid\n");
+       printk(KERN_ERR "and requires you to set the proper MAC "
+              "address manually before continuing\n");
+       printk(KERN_ERR "to enable this network device.\n");
+       printk(KERN_ERR "Please inspect the EEPROM dump and report the issue "
+              "to your hardware vendor\n");
+       printk(KERN_ERR "or Intel Customer Support: linux-nics@intel.com\n");
+       printk(KERN_ERR "/*********************/\n");
+
+       kfree(data);
+}
+
 /**
  * e1000_probe - Device Initialization Routine
  * @pdev: PCI device information struct
@@ -968,7 +1026,6 @@ e1000_probe(struct pci_dev *pdev,
        adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw);
 
        /* initialize eeprom parameters */
-
        if (e1000_init_eeprom_params(&adapter->hw)) {
                E1000_ERR("EEPROM initialization failed\n");
                goto err_eeprom;
@@ -980,23 +1037,29 @@ e1000_probe(struct pci_dev *pdev,
        e1000_reset_hw(&adapter->hw);
 
        /* make sure the EEPROM is good */
-
        if (e1000_validate_eeprom_checksum(&adapter->hw) < 0) {
                DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n");
-               goto err_eeprom;
+               e1000_dump_eeprom(adapter);
+               /*
+                * set MAC address to all zeroes to invalidate and temporary
+                * disable this device for the user. This blocks regular
+                * traffic while still permitting ethtool ioctls from reaching
+                * the hardware as well as allowing the user to run the
+                * interface after manually setting a hw addr using
+                * `ip set address`
+                */
+               memset(adapter->hw.mac_addr, 0, netdev->addr_len);
+       } else {
+               /* copy the MAC address out of the EEPROM */
+               if (e1000_read_mac_addr(&adapter->hw))
+                       DPRINTK(PROBE, ERR, "EEPROM Read Error\n");
        }
-
-       /* copy the MAC address out of the EEPROM */
-
-       if (e1000_read_mac_addr(&adapter->hw))
-               DPRINTK(PROBE, ERR, "EEPROM Read Error\n");
+       /* don't block initalization here due to bad MAC address */
        memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
        memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
 
-       if (!is_valid_ether_addr(netdev->perm_addr)) {
+       if (!is_valid_ether_addr(netdev->perm_addr))
                DPRINTK(PROBE, ERR, "Invalid MAC Address\n");
-               goto err_eeprom;
-       }
 
        e1000_get_bus_info(&adapter->hw);