changeset 5082:988308a14072 onnv_74

6480448 Sunvts netlbtest external loopback failed on 82546 chipset 6521984 Sunvts netlbtest failed on Northstar QGE cards 6531842 e1000g link goes down and up frequently on T2000 systems 6540535 Sunvts netlbtest internal loopback failed on ophir devices 6579605 Sunvts netlbtest internal loopback failed on Northstar fiber card 6595668 e1000g postinstall script missed 5 device ids which had been supported by shared code
author yy150190
date Mon, 17 Sep 2007 22:52:13 -0700
parents ed68bde17499
children 97b4b5418ec9
files usr/src/pkgdefs/SUNWintgige/postinstall usr/src/uts/common/io/e1000g/README usr/src/uts/common/io/e1000g/e1000_osdep.c usr/src/uts/common/io/e1000g/e1000g_debug.c usr/src/uts/common/io/e1000g/e1000g_debug.h usr/src/uts/common/io/e1000g/e1000g_main.c usr/src/uts/common/io/e1000g/e1000g_ndd.c usr/src/uts/common/io/e1000g/e1000g_stat.c usr/src/uts/common/io/e1000g/e1000g_sw.h
diffstat 9 files changed, 715 insertions(+), 218 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/pkgdefs/SUNWintgige/postinstall	Mon Sep 17 22:41:56 2007 -0700
+++ b/usr/src/pkgdefs/SUNWintgige/postinstall	Mon Sep 17 22:52:13 2007 -0700
@@ -132,6 +132,7 @@
 	"pci8086,1004"
 	"pci8086,1008"
 	"pci8086,1009"
+	"pci8086,100c"
 	"pci8086,100d"
 	"pci8086,100e"
 	"pci8086,100f"
@@ -168,6 +169,7 @@
 	"pci8086,1075"
 	"pci8086,1076"
 	"pci8086,1077"
+	"pci8086,1078"
 	"pci8086,1079"
 	"pci8086,107a"
 	"pci8086,107b"
@@ -183,6 +185,7 @@
 	"pci8086,1099"
 	"pci8086,109a"
 	"pci8086,10a4"
+	"pci8086,10a5"
 	"pci8086,10b5"
 	"pci8086,10b9"
 	"pci8086,10ba"
@@ -197,6 +200,8 @@
 	"pci8086,10c4"
 	"pci8086,10c5"
 	"pci8086,10d5"
+	"pci8086,10d9"
+	"pci8086,10da"
 	"pci8086,294c"
 	"pciex8086,1049"
 	"pciex8086,104a"
@@ -215,6 +220,7 @@
 	"pciex8086,1098"
 	"pciex8086,109a"
 	"pciex8086,10a4"
+	"pciex8086,10a5"
 	"pciex8086,10b9"
 	"pciex8086,10ba"
 	"pciex8086,10bb"
@@ -228,5 +234,7 @@
 	"pciex8086,10c4"
 	"pciex8086,10c5" 
 	"pciex8086,10d5"
+	"pciex8086,10d9"
+	"pciex8086,10da"
 	"pciex8086,294c"' \
 	-m '* 0666 root root' e1000g
--- a/usr/src/uts/common/io/e1000g/README	Mon Sep 17 22:41:56 2007 -0700
+++ b/usr/src/uts/common/io/e1000g/README	Mon Sep 17 22:52:13 2007 -0700
@@ -533,3 +533,13 @@
   This version has the following fix:
    6594676 e1000g should free private dips while no rx buffers are held by upper layer
 
+5.2.2
+======
+  This version has the following fix:
+   6480448 Sunvts netlbtest external loopback failed on 82546 chipset
+   6521984 Sunvts netlbtest failed on Northstar QGE cards
+   6531842 e1000g link goes down and up frequently on T2000 systems
+   6540535 Sunvts netlbtest internal loopback failed on ophir devices
+   6579605 Sunvts netlbtest internal loopback failed on Northstar fiber card
+   6595668 e1000g postinstall script missed 5 device ids which had been supported by shared code
+
--- a/usr/src/uts/common/io/e1000g/e1000_osdep.c	Mon Sep 17 22:41:56 2007 -0700
+++ b/usr/src/uts/common/io/e1000g/e1000_osdep.c	Mon Sep 17 22:52:13 2007 -0700
@@ -151,3 +151,33 @@
 	ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE;
 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
 }
+
+/*
+ * e1000g_get_driver_control - tell manageability firmware that the driver
+ * has control.
+ */
+void
+e1000g_get_driver_control(struct e1000_hw *hw)
+{
+	uint32_t ctrl_ext;
+	uint32_t swsm;
+
+	/* tell manageability firmware the driver has taken over */
+	switch (hw->mac.type) {
+	case e1000_82573:
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_DRV_LOAD);
+		break;
+	case e1000_82571:
+	case e1000_82572:
+	case e1000_80003es2lan:
+	case e1000_ich8lan:
+	case e1000_ich9lan:
+		ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+		E1000_WRITE_REG(hw, E1000_CTRL_EXT,
+		    ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+		break;
+	default:
+		break;
+	}
+}
--- a/usr/src/uts/common/io/e1000g/e1000g_debug.c	Mon Sep 17 22:41:56 2007 -0700
+++ b/usr/src/uts/common/io/e1000g/e1000g_debug.c	Mon Sep 17 22:52:13 2007 -0700
@@ -47,8 +47,17 @@
 
 #include "e1000g_debug.h"
 #include "e1000g_sw.h"
+#ifdef E1000G_DEBUG
+#include <sys/pcie.h>
+#endif
 
 #ifdef E1000G_DEBUG
+#define	WPL		8	/* 8 16-bit words per line */
+#define	NUM_REGS	185	/* must match the array initializer */
+typedef struct {
+	char		name[10];
+	uint32_t	offset;
+} Regi_t;
 int e1000g_debug = E1000G_WARN_LEVEL;
 #endif
 int e1000g_log_mode = E1000G_LOG_PRINT;
@@ -145,3 +154,403 @@
 	else /* if they are not set properly then do both */
 		cmn_err(level, "%s: %s", name, buf);
 }
+
+
+
+#ifdef E1000G_DEBUG
+void
+eeprom_dump(void *instance)
+{
+	struct e1000g *Adapter = (struct e1000g *)instance;
+	struct e1000_hw *hw = &Adapter->shared;
+	uint16_t eeprom[WPL], size_field;
+	int i, ret, sign, size, lines, offset = 0;
+	int ee_size[] =
+	    {128, 256, 512, 1024, 2048, 4096, 16 * 1024, 32 * 1024, 64 * 1024};
+
+	if (ret = e1000_read_nvm(hw, 0x12, 1, &size_field)) {
+		e1000g_log(Adapter, CE_WARN,
+		    "e1000_read_nvm failed to read size: %d", ret);
+		return;
+	}
+
+	sign = (size_field & 0xc000) >> 14;
+	if (sign != 1) {
+		e1000g_log(Adapter, CE_WARN,
+		    "eeprom_dump invalid signature: %d", sign);
+	}
+
+	size = (size_field & 0x3c00) >> 10;
+	if (size < 0 || size > 11) {
+		e1000g_log(Adapter, CE_WARN,
+		    "eeprom_dump invalid size: %d", size);
+	}
+
+	e1000g_log(Adapter, CE_CONT,
+	    "eeprom_dump size field: %d  eeprom bytes: %d\n",
+	    size, ee_size[size]);
+
+	e1000g_log(Adapter, CE_CONT,
+	    "e1000_read_nvm hebs: %d\n", ((size_field & 0x000f) >> 10));
+
+	lines = ee_size[size] / WPL / 2;
+	e1000g_log(Adapter, CE_CONT,
+	    "dump eeprom %d lines of %d words per line\n", lines, WPL);
+
+	for (i = 0; i < lines; i++) {
+		if (ret = e1000_read_nvm(hw, offset, WPL, eeprom)) {
+			e1000g_log(Adapter, CE_WARN,
+			    "e1000_read_nvm failed: %d", ret);
+			return;
+		}
+
+		e1000g_log(Adapter, CE_CONT,
+		    "0x%04x    %04x %04x %04x %04x %04x %04x %04x %04x\n",
+		    offset,
+		    eeprom[0], eeprom[1], eeprom[2], eeprom[3],
+		    eeprom[4], eeprom[5], eeprom[6], eeprom[7]);
+		offset += WPL;
+	}
+}
+
+/*
+ * phy_dump - dump important phy registers
+ */
+void
+phy_dump(void *instance)
+{
+	struct e1000g *Adapter = (struct e1000g *)instance;
+	struct e1000_hw *hw = &Adapter->shared;
+	/* offset to each phy register */
+	int32_t offset[] =
+	    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+	    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+	    30, 31, 0x1796, 0x187A, 0x1895, 0x1F30, 0x1F35, 0x1F3E, 0x1F54,
+	    0x1F55, 0x1F56, 0x1F72, 0x1F76, 0x1F77, 0x1F78, 0x1F79, 0x1F98,
+	    0x2010, 0x2011, 0x20DC, 0x20DD, 0x20DE, 0x28B4, 0x2F52, 0x2F5B,
+	    0x2F70, 0x2F90, 0x2FB1, 0x2FB2 };
+	uint16_t value;	/* register value */
+	uint32_t stat;	/* status from e1000_read_phy_reg */
+	int i;
+
+	e1000g_log(Adapter, CE_CONT, "Begin PHY dump\n");
+	for (i = 0; i < ((sizeof (offset)) / sizeof (offset[0])); i++) {
+
+		stat = e1000_read_phy_reg(hw, offset[i], &value);
+		if (stat == 0) {
+			e1000g_log(Adapter, CE_CONT,
+			    "phyreg offset: %d   value: 0x%x\n",
+			    offset[i], value);
+		} else {
+			e1000g_log(Adapter, CE_WARN,
+			    "phyreg offset: %d   ERROR: 0x%x\n",
+			    offset[i], stat);
+		}
+	}
+}
+
+uint32_t
+e1000_read_reg(struct e1000_hw *hw, uint32_t offset)
+{
+	return (ddi_get32(((struct e1000g_osdep *)(hw)->back)->reg_handle,
+	    (uint32_t *)((hw)->hw_addr + offset)));
+}
+
+
+/*
+ * mac_dump - dump important mac registers
+ */
+void
+mac_dump(void *instance)
+{
+	struct e1000g *Adapter = (struct e1000g *)instance;
+	struct e1000_hw *hw = &Adapter->shared;
+	int i;
+
+	/* {name, offset} for each mac register */
+	Regi_t macreg[NUM_REGS] = {
+	    {"CTRL",	E1000_CTRL},	{"STATUS",	E1000_STATUS},
+	    {"EECD",	E1000_EECD},	{"EERD",	E1000_EERD},
+	    {"CTRL_EXT", E1000_CTRL_EXT}, {"FLA",	E1000_FLA},
+	    {"MDIC",	E1000_MDIC},	{"SCTL",	E1000_SCTL},
+	    {"FCAL",	E1000_FCAL},	{"FCAH",	E1000_FCAH},
+	    {"FCT",	E1000_FCT},	{"VET",		E1000_VET},
+	    {"ICR",	E1000_ICR},	{"ITR",		E1000_ITR},
+	    {"ICS",	E1000_ICS},	{"IMS",		E1000_IMS},
+	    {"IMC",	E1000_IMC},	{"IAM",		E1000_IAM},
+	    {"RCTL",	E1000_RCTL},	{"FCTTV",	E1000_FCTTV},
+	    {"TXCW",	E1000_TXCW},	{"RXCW",	E1000_RXCW},
+	    {"TCTL",	E1000_TCTL},	{"TIPG",	E1000_TIPG},
+	    {"AIT",	E1000_AIT},	{"LEDCTL",	E1000_LEDCTL},
+	    {"PBA",	E1000_PBA},	{"PBS",		E1000_PBS},
+	    {"EEMNGCTL", E1000_EEMNGCTL}, {"ERT",	E1000_ERT},
+	    {"FCRTL",	E1000_FCRTL},	{"FCRTH",	E1000_FCRTH},
+	    {"PSRCTL",	E1000_PSRCTL},	{"RDBAL",	E1000_RDBAL},
+	    {"RDBAH",	E1000_RDBAH},	{"RDLEN",	E1000_RDLEN},
+	    {"RDH",	E1000_RDH},	{"RDT",		E1000_RDT},
+	    {"RDTR",	E1000_RDTR},	{"RXDCTL",	E1000_RXDCTL},
+	    {"RADV",	E1000_RADV},	{"RDBAL1",	E1000_RDBAL1},
+	    {"RDBAH1",	E1000_RDBAH1},	{"RDLEN1",	E1000_RDLEN1},
+	    {"RDH1",	E1000_RDH1},	{"RDT1",	E1000_RDT1},
+	    {"RXDCTL1",	E1000_RXDCTL1},	{"RSRPD",	E1000_RSRPD},
+	    {"RAID",	E1000_RAID},	{"CPUVEC",	E1000_CPUVEC},
+	    {"TDFH",	E1000_TDFH},	{"TDFT",	E1000_TDFT},
+	    {"TDFHS",	E1000_TDFHS},	{"TDFTS",	E1000_TDFTS},
+	    {"TDFPC",	E1000_TDFPC},	{"TDBAL",	E1000_TDBAL},
+	    {"TDBAH",	E1000_TDBAH},	{"TDLEN",	E1000_TDLEN},
+	    {"TDH",	E1000_TDH},	{"TDT",		E1000_TDT},
+	    {"TIDV",	E1000_TIDV},	{"TXDCTL",	E1000_TXDCTL},
+	    {"TADV",	E1000_TADV},	{"TARC0",	E1000_TARC0},
+	    {"TDBAL1",	E1000_TDBAL1},	{"TDBAH1",	E1000_TDBAH1},
+	    {"TDLEN1",	E1000_TDLEN1},	{"TDH1",	E1000_TDH1},
+	    {"TDT1",	E1000_TDT1},	{"TXDCTL1",	E1000_TXDCTL1},
+	    {"TARC1",	E1000_TARC1},	{"ALGNERRC",	E1000_ALGNERRC},
+	    {"RXERRC",	E1000_RXERRC},	{"MPC",		E1000_MPC},
+	    {"SCC",	E1000_SCC},	{"ECOL",	E1000_ECOL},
+	    {"MCC",	E1000_MCC},	{"LATECOL",	E1000_LATECOL},
+	    {"COLC",	E1000_COLC},	{"DC",		E1000_DC},
+	    {"TNCRS",	E1000_TNCRS},	{"SEC",		E1000_SEC},
+	    {"CEXTERR",	E1000_CEXTERR},	{"RLEC",	E1000_RLEC},
+	    {"XONRXC",	E1000_XONRXC},	{"XONTXC",	E1000_XONTXC},
+	    {"XOFFRXC",	E1000_XOFFRXC},	{"XOFFTXC",	E1000_XOFFTXC},
+	    {"FCRUC",	E1000_FCRUC},	{"PRC64",	E1000_PRC64},
+	    {"PRC127",	E1000_PRC127},	{"PRC255",	E1000_PRC255},
+	    {"PRC511",	E1000_PRC511},	{"PRC1023",	E1000_PRC1023},
+	    {"PRC1522",	E1000_PRC1522},	{"GPRC",	E1000_GPRC},
+	    {"BPRC",	E1000_BPRC},	{"MPRC",	E1000_MPRC},
+	    {"GPTC",	E1000_GPTC},	{"GORCL",	E1000_GORCL},
+	    {"GORCH",	E1000_GORCH},	{"GOTCL",	E1000_GOTCL},
+	    {"GOTCH",	E1000_GOTCH},	{"RNBC",	E1000_RNBC},
+	    {"RUC",	E1000_RUC},	{"RFC",		E1000_RFC},
+	    {"ROC",	E1000_ROC},	{"RJC",		E1000_RJC},
+	    {"MGTPRC",	E1000_MGTPRC},	{"MGTPDC",	E1000_MGTPDC},
+	    {"MGTPTC",	E1000_MGTPTC},	{"TORL",	E1000_TORL},
+	    {"TORH",	E1000_TORH},	{"TOTL",	E1000_TOTL},
+	    {"TOTH",	E1000_TOTH},	{"TPR",		E1000_TPR},
+	    {"TPT",	E1000_TPT},	{"PTC64",	E1000_PTC64},
+	    {"PTC127",	E1000_PTC127},	{"PTC255",	E1000_PTC255},
+	    {"PTC511",	E1000_PTC511},	{"PTC1023",	E1000_PTC1023},
+	    {"PTC1522",	E1000_PTC1522},	{"MPTC",	E1000_MPTC},
+	    {"BPTC",	E1000_BPTC},	{"TSCTC",	E1000_TSCTC},
+	    {"TSCTFC",	E1000_TSCTFC},	{"IAC",		E1000_IAC},
+	    {"ICRXPTC",	E1000_ICRXPTC},	{"ICRXATC",	E1000_ICRXATC},
+	    {"ICTXPTC",	E1000_ICTXPTC},	{"ICTXATC",	E1000_ICTXATC},
+	    {"ICTXQEC",	E1000_ICTXQEC},	{"ICTXQMTC",	E1000_ICTXQMTC},
+	    {"ICRXDMTC", E1000_ICRXDMTC}, {"ICRXOC",	E1000_ICRXOC},
+	    {"RXCSUM",	E1000_RXCSUM},	{"RFCTL",	E1000_RFCTL},
+	    {"WUC",	E1000_WUC},	{"WUFC",	E1000_WUFC},
+	    {"WUS",	E1000_WUS},	{"MRQC",	E1000_MRQC},
+	    {"MANC",	E1000_MANC},	{"IPAV",	E1000_IPAV},
+	    {"MANC2H",	E1000_MANC2H},	{"RSSIM",	E1000_RSSIM},
+	    {"RSSIR",	E1000_RSSIR},	{"WUPL",	E1000_WUPL},
+	    {"GCR",	E1000_GCR},	{"GSCL_1",	E1000_GSCL_1},
+	    {"GSCL_2",	E1000_GSCL_2},	{"GSCL_3",	E1000_GSCL_3},
+	    {"GSCL_4",	E1000_GSCL_4},	{"FACTPS",	E1000_FACTPS},
+	    {"FWSM",	E1000_FWSM},
+
+	    {"CTRL",	E1000_CTRL},	{"STATUS",	E1000_STATUS},
+	    {"RCTL",	E1000_RCTL},	{"RDLEN",	E1000_RDLEN},
+	    {"RDH",	E1000_RDH},	{"RDT",		E1000_RDT},
+	    {"RDTR",	E1000_RDTR},	{"TCTL",	E1000_TCTL},
+	    {"TDBAL",	E1000_TDBAL},	{"TDBAH",	E1000_TDBAH},
+	    {"TDLEN",	E1000_TDLEN},	{"TDH",		E1000_TDH},
+	    {"TDT",	E1000_TDT},	{"TIDV",	E1000_TIDV},
+	    {"TXDCTL",	E1000_TXDCTL},	{"TADV",	E1000_TADV},
+	    {"TARC0",	E1000_TARC0},	{"TDBAL1",	E1000_TDBAL1},
+	    {"TDBAH1",	E1000_TDBAH1},	{"TDLEN1",	E1000_TDLEN1},
+	    {"TDH1",	E1000_TDH1},	{"TDT1",	E1000_TDT1},
+	    {"TXDCTL1",	E1000_TXDCTL1}, {"TARC1",	E1000_TARC1},
+	    {"CTRL_EXT", E1000_CTRL_EXT}, {"ERT",	E1000_ERT},
+	    {"RDBAL",	E1000_RDBAL},	{"RDBAH",	E1000_RDBAH},
+	    {"RXDCTL",	E1000_RXDCTL},	{"TXDMAC",	E1000_TXDMAC},
+	};
+
+	e1000g_log(Adapter, CE_CONT, "Begin MAC dump\n");
+
+	for (i = 0; i < NUM_REGS; i++) {
+		e1000g_log(Adapter, CE_CONT,
+		    "macreg %10s offset: 0x%x   value: 0x%x\n",
+		    macreg[i].name, macreg[i].offset,
+		    e1000_read_reg(hw, macreg[i].offset));
+	}
+}
+
+void
+pciconfig_dump(void *instance)
+{
+	struct e1000g *Adapter = (struct e1000g *)instance;
+	ddi_acc_handle_t handle;
+	uint8_t cap_ptr;
+	uint8_t next_ptr;
+	off_t offset;
+
+	handle = Adapter->osdep.cfg_handle;
+
+	e1000g_log(Adapter, CE_CONT, "Begin dump PCI config space\n");
+
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_VENID:\t0x%x\n",
+	    pci_config_get16(handle, PCI_CONF_VENID));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_DEVID:\t0x%x\n",
+	    pci_config_get16(handle, PCI_CONF_DEVID));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_COMMAND:\t0x%x\n",
+	    pci_config_get16(handle, PCI_CONF_COMM));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_STATUS:\t0x%x\n",
+	    pci_config_get16(handle, PCI_CONF_STAT));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_REVID:\t0x%x\n",
+	    pci_config_get8(handle, PCI_CONF_REVID));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_PROG_CLASS:\t0x%x\n",
+	    pci_config_get8(handle, PCI_CONF_PROGCLASS));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_SUB_CLASS:\t0x%x\n",
+	    pci_config_get8(handle, PCI_CONF_SUBCLASS));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_BAS_CLASS:\t0x%x\n",
+	    pci_config_get8(handle, PCI_CONF_BASCLASS));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_CACHE_LINESZ:\t0x%x\n",
+	    pci_config_get8(handle, PCI_CONF_CACHE_LINESZ));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_LATENCY_TIMER:\t0x%x\n",
+	    pci_config_get8(handle, PCI_CONF_LATENCY_TIMER));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_HEADER_TYPE:\t0x%x\n",
+	    pci_config_get8(handle, PCI_CONF_HEADER));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_BIST:\t0x%x\n",
+	    pci_config_get8(handle, PCI_CONF_BIST));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_BASE0:\t0x%x\n",
+	    pci_config_get32(handle, PCI_CONF_BASE0));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_BASE1:\t0x%x\n",
+	    pci_config_get32(handle, PCI_CONF_BASE1));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_BASE2:\t0x%x\n",
+	    pci_config_get32(handle, PCI_CONF_BASE2));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_BASE3:\t0x%x\n",
+	    pci_config_get32(handle, PCI_CONF_BASE3));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_BASE4:\t0x%x\n",
+	    pci_config_get32(handle, PCI_CONF_BASE4));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_BASE5:\t0x%x\n",
+	    pci_config_get32(handle, PCI_CONF_BASE5));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_CIS:\t0x%x\n",
+	    pci_config_get32(handle, PCI_CONF_CIS));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_SUBVENID:\t0x%x\n",
+	    pci_config_get16(handle, PCI_CONF_SUBVENID));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_SUBSYSID:\t0x%x\n",
+	    pci_config_get16(handle, PCI_CONF_SUBSYSID));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_ROM:\t0x%x\n",
+	    pci_config_get32(handle, PCI_CONF_ROM));
+
+	cap_ptr = pci_config_get8(handle, PCI_CONF_CAP_PTR);
+
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_CAP_PTR:\t0x%x\n", cap_ptr);
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_ILINE:\t0x%x\n",
+	    pci_config_get8(handle, PCI_CONF_ILINE));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_IPIN:\t0x%x\n",
+	    pci_config_get8(handle, PCI_CONF_IPIN));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_MIN_G:\t0x%x\n",
+	    pci_config_get8(handle, PCI_CONF_MIN_G));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_CONF_MAX_L:\t0x%x\n",
+	    pci_config_get8(handle, PCI_CONF_MAX_L));
+
+	/* Power Management */
+	offset = cap_ptr;
+
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_PM_CAP_ID:\t0x%x\n",
+	    pci_config_get8(handle, offset));
+
+	next_ptr = pci_config_get8(handle, offset + 1);
+
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_PM_NEXT_PTR:\t0x%x\n", next_ptr);
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_PM_CAP:\t0x%x\n",
+	    pci_config_get16(handle, offset + PCI_PMCAP));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_PM_CSR:\t0x%x\n",
+	    pci_config_get16(handle, offset + PCI_PMCSR));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_PM_CSR_BSE:\t0x%x\n",
+	    pci_config_get8(handle, offset + PCI_PMCSR_BSE));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_PM_DATA:\t0x%x\n",
+	    pci_config_get8(handle, offset + PCI_PMDATA));
+
+	/* MSI Configuration */
+	offset = next_ptr;
+
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_MSI_CAP_ID:\t0x%x\n",
+	    pci_config_get8(handle, offset));
+
+	next_ptr = pci_config_get8(handle, offset + 1);
+
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_MSI_NEXT_PTR:\t0x%x\n", next_ptr);
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_MSI_CTRL:\t0x%x\n",
+	    pci_config_get16(handle, offset + PCI_MSI_CTRL));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_MSI_ADDR:\t0x%x\n",
+	    pci_config_get32(handle, offset + PCI_MSI_ADDR_OFFSET));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_MSI_ADDR_HI:\t0x%x\n",
+	    pci_config_get32(handle, offset + 0x8));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCI_MSI_DATA:\t0x%x\n",
+	    pci_config_get16(handle, offset + 0xC));
+
+	/* PCI Express Configuration */
+	offset = next_ptr;
+
+	e1000g_log(Adapter, CE_CONT,
+	    "PCIE_CAP_ID:\t0x%x\n",
+	    pci_config_get8(handle, offset + PCIE_CAP_ID));
+
+	next_ptr = pci_config_get8(handle, offset + PCIE_CAP_NEXT_PTR);
+
+	e1000g_log(Adapter, CE_CONT,
+	    "PCIE_CAP_NEXT_PTR:\t0x%x\n", next_ptr);
+	e1000g_log(Adapter, CE_CONT,
+	    "PCIE_PCIECAP:\t0x%x\n",
+	    pci_config_get16(handle, offset + PCIE_PCIECAP));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCIE_DEVCAP:\t0x%x\n",
+	    pci_config_get32(handle, offset + PCIE_DEVCAP));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCIE_DEVCTL:\t0x%x\n",
+	    pci_config_get16(handle, offset + PCIE_DEVCTL));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCIE_DEVSTS:\t0x%x\n",
+	    pci_config_get16(handle, offset + PCIE_DEVSTS));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCIE_LINKCAP:\t0x%x\n",
+	    pci_config_get32(handle, offset + PCIE_LINKCAP));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCIE_LINKCTL:\t0x%x\n",
+	    pci_config_get16(handle, offset + PCIE_LINKCTL));
+	e1000g_log(Adapter, CE_CONT,
+	    "PCIE_LINKSTS:\t0x%x\n",
+	    pci_config_get16(handle, offset + PCIE_LINKSTS));
+}
+#endif
--- a/usr/src/uts/common/io/e1000g/e1000g_debug.h	Mon Sep 17 22:41:56 2007 -0700
+++ b/usr/src/uts/common/io/e1000g/e1000g_debug.h	Mon Sep 17 22:52:13 2007 -0700
@@ -113,7 +113,14 @@
 
 #define	E1000G_STAT(val)	(val)++;
 
-void e1000g_log(void *instance, int level, char *fmt, ...);
+void e1000g_log(void *, int, char *, ...);
+
+#ifdef E1000G_DEBUG
+void eeprom_dump(void *);
+void phy_dump(void *);
+void mac_dump(void *);
+void pciconfig_dump(void *);
+#endif
 
 #ifdef E1000G_DEBUG
 extern int e1000g_debug;
--- a/usr/src/uts/common/io/e1000g/e1000g_main.c	Mon Sep 17 22:41:56 2007 -0700
+++ b/usr/src/uts/common/io/e1000g/e1000g_main.c	Mon Sep 17 22:52:13 2007 -0700
@@ -49,9 +49,9 @@
 #define	E1000_RX_INTPT_TIME	128
 #define	E1000_RX_PKT_CNT	8
 
-static char ident[] = "Intel PRO/1000 Ethernet 5.2.1";
+static char ident[] = "Intel PRO/1000 Ethernet 5.2.2";
 static char e1000g_string[] = "Intel(R) PRO/1000 Network Connection";
-static char e1000g_version[] = "Driver Ver. 5.2.1";
+static char e1000g_version[] = "Driver Ver. 5.2.2";
 
 /*
  * Proto types for DDI entry points
@@ -142,6 +142,7 @@
 #ifdef __sparc
 static boolean_t e1000g_find_mac_address(struct e1000g *);
 #endif
+static void e1000g_get_phy_state(struct e1000g *);
 static void e1000g_free_priv_devi_node(struct e1000g *, boolean_t);
 
 static struct cb_ops cb_ws_ops = {
@@ -1248,6 +1249,9 @@
 	/* Disable Smart Power Down */
 	phy_spd_state(hw, B_FALSE);
 
+	/* Make sure driver has control */
+	e1000g_get_driver_control(hw);
+
 	/*
 	 * Initialize unicast addresses.
 	 */
@@ -1289,6 +1293,9 @@
 		e1000_enable_pciex_master(hw);
 	}
 
+	/* Save the state of the phy */
+	e1000g_get_phy_state(Adapter);
+
 	Adapter->init_count++;
 
 	rw_exit(&Adapter->chip_lock);
@@ -1311,9 +1318,6 @@
 
 	hw = &Adapter->shared;
 
-	/* Ensure this is set to get accurate copper link status */
-	hw->mac.get_link_status = B_TRUE;
-
 	e1000_check_for_link(hw);
 
 	if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU) ||
@@ -1814,23 +1818,36 @@
 
 		stop_watchdog_timer(Adapter);
 
-		mutex_enter(&Adapter->link_lock);
+		rw_enter(&Adapter->chip_lock, RW_WRITER);
+
+		/*
+		 * Because we got a link-status-change interrupt, force
+		 * e1000_check_for_link() to look at phy
+		 */
+		Adapter->shared.mac.get_link_status = B_TRUE;
+
 		/* e1000g_link_check takes care of link status change */
 		link_changed = e1000g_link_check(Adapter);
+
+		/* Get new phy state */
+		e1000g_get_phy_state(Adapter);
+
 		/*
 		 * If the link timer has not timed out, we'll not notify
 		 * the upper layer with any link state until the link is up.
 		 */
 		if (link_changed && !Adapter->link_complete) {
 			if (Adapter->link_state == LINK_STATE_UP) {
+				mutex_enter(&Adapter->link_lock);
 				Adapter->link_complete = B_TRUE;
 				tid = Adapter->link_tid;
 				Adapter->link_tid = 0;
+				mutex_exit(&Adapter->link_lock);
 			} else {
 				link_changed = B_FALSE;
 			}
 		}
-		mutex_exit(&Adapter->link_lock);
+		rw_exit(&Adapter->chip_lock);
 
 		if (link_changed) {
 			if (tid != 0)
@@ -2705,9 +2722,7 @@
 				Adapter->tx_link_down_timeout++;
 			} else if (Adapter->tx_link_down_timeout ==
 			    MAX_TX_LINK_DOWN_TIMEOUT) {
-				rw_enter(&Adapter->chip_lock, RW_WRITER);
 				e1000g_tx_clean(Adapter);
-				rw_exit(&Adapter->chip_lock);
 				Adapter->tx_link_down_timeout++;
 			}
 		}
@@ -2736,10 +2751,10 @@
 	}
 
 	link_changed = B_FALSE;
-	mutex_enter(&Adapter->link_lock);
+	rw_enter(&Adapter->chip_lock, RW_READER);
 	if (Adapter->link_complete)
 		link_changed = e1000g_link_check(Adapter);
-	mutex_exit(&Adapter->link_lock);
+	rw_exit(&Adapter->chip_lock);
 
 	if (link_changed) {
 		/*
@@ -3452,8 +3467,6 @@
 	uint32_t *lbmp;
 	uint32_t size;
 	uint32_t value;
-	uint16_t phy_status;
-	uint16_t phy_ext_status;
 
 	hw = &Adapter->shared;
 
@@ -3469,12 +3482,22 @@
 		if (iocp->ioc_count != size)
 			return (IOC_INVAL);
 
-		e1000_read_phy_reg(hw, PHY_EXT_STATUS, &phy_ext_status);
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
+		rw_enter(&Adapter->chip_lock, RW_WRITER);
+		e1000g_get_phy_state(Adapter);
+
+		/*
+		 * Workaround for hardware faults. In order to get a stable
+		 * state of phy, we will wait for a specific interval and
+		 * try again. The time delay is an experiential value based
+		 * on our testing.
+		 */
+		msec_delay(100);
+		e1000g_get_phy_state(Adapter);
+		rw_exit(&Adapter->chip_lock);
 
 		value = sizeof (lb_normal);
-		if ((phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
-		    (phy_ext_status & IEEE_ESR_1000X_FD_CAPS) ||
+		if ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
+		    (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS) ||
 		    (hw->media_type == e1000_media_type_fiber) ||
 		    (hw->media_type == e1000_media_type_internal_serdes)) {
 			value += sizeof (lb_phy);
@@ -3485,10 +3508,10 @@
 				break;
 			}
 		}
-		if ((phy_status & MII_SR_100X_FD_CAPS) ||
-		    (phy_status & MII_SR_100T2_FD_CAPS))
+		if ((Adapter->phy_status & MII_SR_100X_FD_CAPS) ||
+		    (Adapter->phy_status & MII_SR_100T2_FD_CAPS))
 			value += sizeof (lb_external100);
-		if (phy_status & MII_SR_10T_FD_CAPS)
+		if (Adapter->phy_status & MII_SR_10T_FD_CAPS)
 			value += sizeof (lb_external10);
 
 		lbsp = (lb_info_sz_t *)mp->b_cont->b_rptr;
@@ -3496,12 +3519,9 @@
 		break;
 
 	case LB_GET_INFO:
-		e1000_read_phy_reg(hw, PHY_EXT_STATUS, &phy_ext_status);
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_status);
-
 		value = sizeof (lb_normal);
-		if ((phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
-		    (phy_ext_status & IEEE_ESR_1000X_FD_CAPS) ||
+		if ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
+		    (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS) ||
 		    (hw->media_type == e1000_media_type_fiber) ||
 		    (hw->media_type == e1000_media_type_internal_serdes)) {
 			value += sizeof (lb_phy);
@@ -3512,10 +3532,10 @@
 				break;
 			}
 		}
-		if ((phy_status & MII_SR_100X_FD_CAPS) ||
-		    (phy_status & MII_SR_100T2_FD_CAPS))
+		if ((Adapter->phy_status & MII_SR_100X_FD_CAPS) ||
+		    (Adapter->phy_status & MII_SR_100T2_FD_CAPS))
 			value += sizeof (lb_external100);
-		if (phy_status & MII_SR_10T_FD_CAPS)
+		if (Adapter->phy_status & MII_SR_10T_FD_CAPS)
 			value += sizeof (lb_external10);
 
 		size = value;
@@ -3525,8 +3545,8 @@
 		value = 0;
 		lbpp = (lb_property_t *)mp->b_cont->b_rptr;
 		lbpp[value++] = lb_normal;
-		if ((phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
-		    (phy_ext_status & IEEE_ESR_1000X_FD_CAPS) ||
+		if ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
+		    (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS) ||
 		    (hw->media_type == e1000_media_type_fiber) ||
 		    (hw->media_type == e1000_media_type_internal_serdes)) {
 			lbpp[value++] = lb_phy;
@@ -3537,10 +3557,10 @@
 				break;
 			}
 		}
-		if ((phy_status & MII_SR_100X_FD_CAPS) ||
-		    (phy_status & MII_SR_100T2_FD_CAPS))
+		if ((Adapter->phy_status & MII_SR_100X_FD_CAPS) ||
+		    (Adapter->phy_status & MII_SR_100T2_FD_CAPS))
 			lbpp[value++] = lb_external100;
-		if (phy_status & MII_SR_10T_FD_CAPS)
+		if (Adapter->phy_status & MII_SR_10T_FD_CAPS)
 			lbpp[value++] = lb_external10;
 		break;
 
@@ -3574,10 +3594,8 @@
 e1000g_set_loopback_mode(struct e1000g *Adapter, uint32_t mode)
 {
 	struct e1000_hw *hw;
-#ifndef __sparc
-	uint32_t reg_rctl;
-#endif
 	int i, times;
+	boolean_t link_up;
 
 	if (mode == Adapter->loopback_mode)
 		return (B_TRUE);
@@ -3585,19 +3603,26 @@
 	hw = &Adapter->shared;
 	times = 0;
 
-again:
-	switch (mode) {
-	default:
-		return (B_FALSE);
-
-	case E1000G_LB_NONE:
-		/* Get original speed and duplex settings */
-		e1000g_force_speed_duplex(Adapter);
+	Adapter->loopback_mode = mode;
+
+	if (mode == E1000G_LB_NONE) {
 		/* Reset the chip */
 		hw->phy.wait_for_link = B_TRUE;
 		(void) e1000g_reset(Adapter);
 		hw->phy.wait_for_link = B_FALSE;
-		break;
+		return (B_TRUE);
+	}
+
+again:
+
+	(void) e1000g_reset(Adapter);
+
+	rw_enter(&Adapter->chip_lock, RW_WRITER);
+
+	switch (mode) {
+	default:
+		rw_exit(&Adapter->chip_lock);
+		return (B_FALSE);
 
 	case E1000G_LB_EXTERNAL_1000:
 		e1000g_set_external_loopback_1000(Adapter);
@@ -3618,31 +3643,26 @@
 
 	times++;
 
-	switch (mode) {
-	case E1000G_LB_EXTERNAL_1000:
-	case E1000G_LB_EXTERNAL_100:
-	case E1000G_LB_EXTERNAL_10:
-	case E1000G_LB_INTERNAL_PHY:
-		/* Wait for link up */
-		for (i = (PHY_FORCE_LIMIT * 2); i > 0; i--)
-			msec_delay(100);
-
-		if (!e1000g_link_up(Adapter)) {
+	/* Wait for link up */
+	for (i = (PHY_FORCE_LIMIT * 2); i > 0; i--)
+		msec_delay(100);
+
+	link_up = e1000g_link_up(Adapter);
+
+	rw_exit(&Adapter->chip_lock);
+
+	if (!link_up) {
+		E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
+		    "Failed to get the link up");
+		if (times < 2) {
+			/* Reset the link */
 			E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
-			    "Failed to get the link up");
-			if (times < 2) {
-				/* Reset the link */
-				E1000G_DEBUGLOG_0(Adapter, E1000G_INFO_LEVEL,
-				    "Reset the link ...");
-				(void) e1000g_reset(Adapter);
-				goto again;
-			}
+			    "Reset the link ...");
+			(void) e1000g_reset(Adapter);
+			goto again;
 		}
-		break;
 	}
 
-	Adapter->loopback_mode = mode;
-
 	return (B_TRUE);
 }
 
@@ -3659,6 +3679,7 @@
 	uint32_t ctrl;
 	uint32_t status;
 	uint16_t phy_ctrl;
+	uint32_t txcw;
 
 	hw = &Adapter->shared;
 
@@ -3684,6 +3705,15 @@
 		/* Reset PHY to auto-neg off and force 1000 */
 		e1000_write_phy_reg(hw, PHY_CONTROL,
 		    phy_ctrl | MII_CR_RESET);
+		/*
+		 * Disable PHY receiver for 82540/545/546 and 82573 Family.
+		 * See comments above e1000g_set_internal_loopback() for the
+		 * background.
+		 */
+		e1000_write_phy_reg(hw, 29, 0x001F);
+		e1000_write_phy_reg(hw, 30, 0x8FFC);
+		e1000_write_phy_reg(hw, 29, 0x001A);
+		e1000_write_phy_reg(hw, 30, 0x8FF0);
 		break;
 	}
 
@@ -3729,11 +3759,31 @@
 
 	case e1000_82571:
 	case e1000_82572:
+		/*
+		 * The fiber/SerDes versions of this adapter do not contain an
+		 * accessible PHY. Therefore, loopback beyond MAC must be done
+		 * using SerDes analog loopback.
+		 */
 		if (hw->media_type != e1000_media_type_copper) {
-			/* Set ILOS on fiber nic if half duplex is detected */
 			status = E1000_READ_REG(hw, E1000_STATUS);
-			if ((status & E1000_STATUS_FD) == 0)
+			/* Set ILOS on fiber nic if half duplex is detected */
+			if (((status & E1000_STATUS_LU) == 0) ||
+			    ((status & E1000_STATUS_FD) == 0) ||
+			    (hw->media_type ==
+			    e1000_media_type_internal_serdes))
 				ctrl |= E1000_CTRL_ILOS | E1000_CTRL_SLU;
+
+			/* Disable autoneg by setting bit 31 of TXCW to zero */
+			txcw = E1000_READ_REG(hw, E1000_TXCW);
+			txcw &= ~((uint32_t)1 << 31);
+			E1000_WRITE_REG(hw, E1000_TXCW, txcw);
+
+			/*
+			 * Write 0x410 to Serdes Control register
+			 * to enable Serdes analog loopback
+			 */
+			E1000_WRITE_REG(hw, E1000_SCTL, 0x0410);
+			msec_delay(10);
 		}
 		break;
 
@@ -3744,23 +3794,6 @@
 
 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
 
-	/*
-	 * Disable PHY receiver for 82540/545/546 and 82573 Family.
-	 * For background, see comments above e1000g_set_internal_loopback().
-	 */
-	switch (hw->mac.type) {
-	case e1000_82540:
-	case e1000_82545:
-	case e1000_82545_rev_3:
-	case e1000_82546:
-	case e1000_82546_rev_3:
-	case e1000_82573:
-		e1000_write_phy_reg(hw, 29, 0x001F);
-		e1000_write_phy_reg(hw, 30, 0x8FFC);
-		e1000_write_phy_reg(hw, 29, 0x001A);
-		e1000_write_phy_reg(hw, 30, 0x8FF0);
-		break;
-	}
 }
 
 static void
@@ -4278,3 +4311,21 @@
 
 	return (DDI_SUCCESS);
 }
+
+/*
+ * e1000g_get_phy_state - get the state of PHY registers, save in the adapter
+ */
+static void
+e1000g_get_phy_state(struct e1000g *Adapter)
+{
+	struct e1000_hw *hw = &Adapter->shared;
+
+	e1000_read_phy_reg(hw, PHY_CONTROL, &Adapter->phy_ctrl);
+	e1000_read_phy_reg(hw, PHY_STATUS, &Adapter->phy_status);
+	e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &Adapter->phy_an_adv);
+	e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &Adapter->phy_an_exp);
+	e1000_read_phy_reg(hw, PHY_EXT_STATUS, &Adapter->phy_ext_status);
+	e1000_read_phy_reg(hw, PHY_1000T_CTRL, &Adapter->phy_1000t_ctrl);
+	e1000_read_phy_reg(hw, PHY_1000T_STATUS, &Adapter->phy_1000t_status);
+	e1000_read_phy_reg(hw, PHY_LP_ABILITY, &Adapter->phy_lp_able);
+}
--- a/usr/src/uts/common/io/e1000g/e1000g_ndd.c	Mon Sep 17 22:41:56 2007 -0700
+++ b/usr/src/uts/common/io/e1000g/e1000g_ndd.c	Mon Sep 17 22:52:13 2007 -0700
@@ -269,57 +269,58 @@
 {
 	struct e1000g *Adapter;
 	struct e1000_hw *hw;
-	uint16_t phy_reg;
 
 	Adapter = ndp->ndp_instance;
 	ASSERT(Adapter);
 	hw = &Adapter->shared;
 
+	rw_enter(&Adapter->chip_lock, RW_READER);
+
 	switch (ndp->ndp_info) {
 	/* Hardware Capabilities */
 	case PARAM_AUTONEG_CAP:
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
-		ndp->ndp_val = (phy_reg & MII_SR_AUTONEG_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_status & MII_SR_AUTONEG_CAPS) ? 1 : 0;
 		break;
 	case PARAM_PAUSE_CAP:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_AR_PAUSE) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0;
 		break;
 	case PARAM_ASYM_PAUSE_CAP:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_AR_ASM_DIR) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0;
 		break;
 	case PARAM_1000FDX_CAP:
-		e1000_read_phy_reg(hw, PHY_EXT_STATUS, &phy_reg);
-		ndp->ndp_val = ((phy_reg & IEEE_ESR_1000T_FD_CAPS) ||
-		    (phy_reg & IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0;
+		ndp->ndp_val =
+		    ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
+		    (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0;
 		break;
 	case PARAM_1000HDX_CAP:
-		e1000_read_phy_reg(hw, PHY_EXT_STATUS, &phy_reg);
-		ndp->ndp_val = ((phy_reg & IEEE_ESR_1000T_HD_CAPS) ||
-		    (phy_reg & IEEE_ESR_1000X_HD_CAPS)) ? 1 : 0;
+		ndp->ndp_val =
+		    ((Adapter->phy_ext_status & IEEE_ESR_1000T_HD_CAPS) ||
+		    (Adapter->phy_ext_status & IEEE_ESR_1000X_HD_CAPS)) ? 1 : 0;
 		break;
 	case PARAM_100T4_CAP:
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
-		ndp->ndp_val = (phy_reg & MII_SR_100T4_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_status & MII_SR_100T4_CAPS) ? 1 : 0;
 		break;
 	case PARAM_100FDX_CAP:
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
-		ndp->ndp_val = ((phy_reg & MII_SR_100X_FD_CAPS) ||
-		    (phy_reg & MII_SR_100T2_FD_CAPS)) ? 1 : 0;
+		ndp->ndp_val =
+		    ((Adapter->phy_status & MII_SR_100X_FD_CAPS) ||
+		    (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) ? 1 : 0;
 		break;
 	case PARAM_100HDX_CAP:
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
-		ndp->ndp_val = ((phy_reg & MII_SR_100X_HD_CAPS) ||
-		    (phy_reg & MII_SR_100T2_HD_CAPS)) ? 1 : 0;
+		ndp->ndp_val =
+		    ((Adapter->phy_status & MII_SR_100X_HD_CAPS) ||
+		    (Adapter->phy_status & MII_SR_100T2_HD_CAPS)) ? 1 : 0;
 		break;
 	case PARAM_10FDX_CAP:
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
-		ndp->ndp_val = (phy_reg & MII_SR_10T_FD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_status & MII_SR_10T_FD_CAPS) ? 1 : 0;
 		break;
 	case PARAM_10HDX_CAP:
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
-		ndp->ndp_val = (phy_reg & MII_SR_10T_HD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_status & MII_SR_10T_HD_CAPS) ? 1 : 0;
 		break;
 
 	/* Auto-Negotiation Advertisement Capabilities */
@@ -327,82 +328,82 @@
 		ndp->ndp_val = hw->mac.autoneg;
 		break;
 	case PARAM_ADV_PAUSE_CAP:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_AR_PAUSE) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0;
 		break;
 	case PARAM_ADV_ASYM_PAUSE_CAP:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_AR_ASM_DIR) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0;
 		break;
 	case PARAM_ADV_1000FDX_CAP:
-		e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_reg);
-		ndp->ndp_val = (phy_reg & CR_1000T_FD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_1000t_ctrl & CR_1000T_FD_CAPS) ? 1 : 0;
 		break;
 	case PARAM_ADV_1000HDX_CAP:
-		e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_reg);
-		ndp->ndp_val = (phy_reg & CR_1000T_HD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_1000t_ctrl & CR_1000T_HD_CAPS) ? 1 : 0;
 		break;
 	case PARAM_ADV_100T4_CAP:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_AR_100T4_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_an_adv & NWAY_AR_100T4_CAPS) ? 1 : 0;
 		break;
 	case PARAM_ADV_100FDX_CAP:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_AR_100TX_FD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_an_adv & NWAY_AR_100TX_FD_CAPS) ? 1 : 0;
 		break;
 	case PARAM_ADV_100HDX_CAP:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_AR_100TX_HD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_an_adv & NWAY_AR_100TX_HD_CAPS) ? 1 : 0;
 		break;
 	case PARAM_ADV_10FDX_CAP:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_AR_10T_FD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_an_adv & NWAY_AR_10T_FD_CAPS) ? 1 : 0;
 		break;
 	case PARAM_ADV_10HDX_CAP:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_AR_10T_HD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_an_adv & NWAY_AR_10T_HD_CAPS) ? 1 : 0;
 		break;
 
 	/* Link-Partner's Advertisement Capabilities */
 	case PARAM_LP_AUTONEG_CAP:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_ER_LP_NWAY_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_an_exp & NWAY_ER_LP_NWAY_CAPS) ? 1 : 0;
 		break;
 	case PARAM_LP_PAUSE_CAP:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_LPAR_PAUSE) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_lp_able & NWAY_LPAR_PAUSE) ? 1 : 0;
 		break;
 	case PARAM_LP_ASYM_PAUSE_CAP:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_LPAR_ASM_DIR) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_lp_able & NWAY_LPAR_ASM_DIR) ? 1 : 0;
 		break;
 	case PARAM_LP_1000FDX_CAP:
-		e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_reg);
-		ndp->ndp_val = (phy_reg & SR_1000T_LP_FD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_1000t_status & SR_1000T_LP_FD_CAPS) ? 1 : 0;
 		break;
 	case PARAM_LP_1000HDX_CAP:
-		e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_reg);
-		ndp->ndp_val = (phy_reg & SR_1000T_LP_HD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_1000t_status & SR_1000T_LP_HD_CAPS) ? 1 : 0;
 		break;
 	case PARAM_LP_100T4_CAP:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_LPAR_100T4_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_lp_able & NWAY_LPAR_100T4_CAPS) ? 1 : 0;
 		break;
 	case PARAM_LP_100FDX_CAP:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_LPAR_100TX_FD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_lp_able & NWAY_LPAR_100TX_FD_CAPS) ? 1 : 0;
 		break;
 	case PARAM_LP_100HDX_CAP:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_LPAR_100TX_HD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_lp_able & NWAY_LPAR_100TX_HD_CAPS) ? 1 : 0;
 		break;
 	case PARAM_LP_10FDX_CAP:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_LPAR_10T_FD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_lp_able & NWAY_LPAR_10T_FD_CAPS) ? 1 : 0;
 		break;
 	case PARAM_LP_10HDX_CAP:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		ndp->ndp_val = (phy_reg & NWAY_LPAR_10T_HD_CAPS) ? 1 : 0;
+		ndp->ndp_val =
+		    (Adapter->phy_lp_able & NWAY_LPAR_10T_HD_CAPS) ? 1 : 0;
 		break;
 
 	/* Force Speed and Duplex Parameter */
@@ -475,6 +476,8 @@
 	default:
 		break;
 	}
+
+	rw_exit(&Adapter->chip_lock);
 }
 
 static void
--- a/usr/src/uts/common/io/e1000g/e1000g_stat.c	Mon Sep 17 22:41:56 2007 -0700
+++ b/usr/src/uts/common/io/e1000g/e1000g_stat.c	Mon Sep 17 22:52:13 2007 -0700
@@ -312,11 +312,10 @@
 	struct e1000_hw *hw = &Adapter->shared;
 	p_e1000g_stat_t e1000g_ksp;
 	uint32_t low_val, high_val;
-	uint16_t phy_reg, phy_reg_2;
 
 	e1000g_ksp = (p_e1000g_stat_t)Adapter->e1000g_ksp->ks_data;
 
-	rw_enter(&Adapter->chip_lock, RW_WRITER);
+	rw_enter(&Adapter->chip_lock, RW_READER);
 
 	switch (stat) {
 	case MAC_STAT_IFSPEED:
@@ -509,13 +508,10 @@
 		break;
 
 	case ETHER_STAT_XCVR_ID:
-		e1000_read_phy_reg(hw, PHY_ID1, &phy_reg);
-		e1000_read_phy_reg(hw, PHY_ID2, &phy_reg_2);
-		*val = (uint32_t)((phy_reg << 16) | phy_reg_2);
+		*val = hw->phy.id | hw->phy.revision;
 		break;
 
 	case ETHER_STAT_XCVR_INUSE:
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
 		switch (Adapter->link_speed) {
 		case SPEED_1000:
 			*val =
@@ -525,7 +521,7 @@
 		case SPEED_100:
 			*val =
 			    (hw->media_type == e1000_media_type_copper) ?
-			    (phy_reg & MII_SR_100T4_CAPS) ?
+			    (Adapter->phy_status & MII_SR_100T4_CAPS) ?
 			    XCVR_100T4 : XCVR_100T2 : XCVR_100X;
 			break;
 		case SPEED_10:
@@ -538,92 +534,75 @@
 		break;
 
 	case ETHER_STAT_CAP_1000FDX:
-		e1000_read_phy_reg(hw, PHY_EXT_STATUS, &phy_reg);
-		*val = ((phy_reg & IEEE_ESR_1000T_FD_CAPS) ||
-		    (phy_reg & IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0;
+		*val = ((Adapter->phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
+		    (Adapter->phy_ext_status & IEEE_ESR_1000X_FD_CAPS)) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_CAP_1000HDX:
-		e1000_read_phy_reg(hw, PHY_EXT_STATUS, &phy_reg);
-		*val = ((phy_reg & IEEE_ESR_1000T_HD_CAPS) ||
-		    (phy_reg & IEEE_ESR_1000X_HD_CAPS)) ? 1 : 0;
+		*val = ((Adapter->phy_ext_status & IEEE_ESR_1000T_HD_CAPS) ||
+		    (Adapter->phy_ext_status & IEEE_ESR_1000X_HD_CAPS)) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_CAP_100FDX:
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
-		*val = ((phy_reg & MII_SR_100X_FD_CAPS) ||
-		    (phy_reg & MII_SR_100T2_FD_CAPS)) ? 1 : 0;
+		*val = ((Adapter->phy_status & MII_SR_100X_FD_CAPS) ||
+		    (Adapter->phy_status & MII_SR_100T2_FD_CAPS)) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_CAP_100HDX:
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
-		*val = ((phy_reg & MII_SR_100X_HD_CAPS) ||
-		    (phy_reg & MII_SR_100T2_HD_CAPS)) ? 1 : 0;
+		*val = ((Adapter->phy_status & MII_SR_100X_HD_CAPS) ||
+		    (Adapter->phy_status & MII_SR_100T2_HD_CAPS)) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_CAP_10FDX:
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
-		*val = (phy_reg & MII_SR_10T_FD_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_status & MII_SR_10T_FD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_CAP_10HDX:
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
-		*val = (phy_reg & MII_SR_10T_HD_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_status & MII_SR_10T_HD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_CAP_ASMPAUSE:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		*val = (phy_reg & NWAY_AR_ASM_DIR) ? 1 : 0;
+		*val = (Adapter->phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_CAP_PAUSE:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		*val = (phy_reg & NWAY_AR_PAUSE) ? 1 : 0;
+		*val = (Adapter->phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_CAP_AUTONEG:
-		e1000_read_phy_reg(hw, PHY_STATUS, &phy_reg);
-		*val = (phy_reg & MII_SR_AUTONEG_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_status & MII_SR_AUTONEG_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_ADV_CAP_1000FDX:
-		e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_reg);
-		*val = (phy_reg & CR_1000T_FD_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_1000t_ctrl & CR_1000T_FD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_ADV_CAP_1000HDX:
-		e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_reg);
-		*val = (phy_reg & CR_1000T_HD_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_1000t_ctrl & CR_1000T_HD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_ADV_CAP_100FDX:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		*val = (phy_reg & NWAY_AR_100TX_FD_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_an_adv & NWAY_AR_100TX_FD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_ADV_CAP_100HDX:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		*val = (phy_reg & NWAY_AR_100TX_HD_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_an_adv & NWAY_AR_100TX_HD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_ADV_CAP_10FDX:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		*val = (phy_reg & NWAY_AR_10T_FD_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_an_adv & NWAY_AR_10T_FD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_ADV_CAP_10HDX:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		*val = (phy_reg & NWAY_AR_10T_HD_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_an_adv & NWAY_AR_10T_HD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		*val = (phy_reg & NWAY_AR_ASM_DIR) ? 1 : 0;
+		*val = (Adapter->phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_ADV_CAP_PAUSE:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		*val = (phy_reg & NWAY_AR_PAUSE) ? 1 : 0;
+		*val = (Adapter->phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_ADV_CAP_AUTONEG:
@@ -631,63 +610,53 @@
 		break;
 
 	case ETHER_STAT_LP_CAP_1000FDX:
-		e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_reg);
-		*val = (phy_reg & SR_1000T_LP_FD_CAPS) ? 1 : 0;
+		*val =
+		    (Adapter->phy_1000t_status & SR_1000T_LP_FD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_LP_CAP_1000HDX:
-		e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_reg);
-		*val = (phy_reg & SR_1000T_LP_HD_CAPS) ? 1 : 0;
+		*val =
+		    (Adapter->phy_1000t_status & SR_1000T_LP_HD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_LP_CAP_100FDX:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		*val = (phy_reg & NWAY_LPAR_100TX_FD_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_lp_able & NWAY_LPAR_100TX_FD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_LP_CAP_100HDX:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		*val = (phy_reg & NWAY_LPAR_100TX_HD_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_lp_able & NWAY_LPAR_100TX_HD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_LP_CAP_10FDX:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		*val = (phy_reg & NWAY_LPAR_10T_FD_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_lp_able & NWAY_LPAR_10T_FD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_LP_CAP_10HDX:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		*val = (phy_reg & NWAY_LPAR_10T_HD_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_lp_able & NWAY_LPAR_10T_HD_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_LP_CAP_ASMPAUSE:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		*val = (phy_reg & NWAY_LPAR_ASM_DIR) ? 1 : 0;
+		*val = (Adapter->phy_lp_able & NWAY_LPAR_ASM_DIR) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_LP_CAP_PAUSE:
-		e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_reg);
-		*val = (phy_reg & NWAY_LPAR_PAUSE) ? 1 : 0;
+		*val = (Adapter->phy_lp_able & NWAY_LPAR_PAUSE) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_LP_CAP_AUTONEG:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_reg);
-		*val = (phy_reg & NWAY_ER_LP_NWAY_CAPS) ? 1 : 0;
+		*val = (Adapter->phy_an_exp & NWAY_ER_LP_NWAY_CAPS) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_LINK_ASMPAUSE:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		*val = (phy_reg & NWAY_AR_ASM_DIR) ? 1 : 0;
+		*val = (Adapter->phy_an_adv & NWAY_AR_ASM_DIR) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_LINK_PAUSE:
-		e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &phy_reg);
-		*val = (phy_reg & NWAY_AR_PAUSE) ? 1 : 0;
+		*val = (Adapter->phy_an_adv & NWAY_AR_PAUSE) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_LINK_AUTONEG:
-		e1000_read_phy_reg(hw, PHY_CONTROL, &phy_reg);
-		*val = (phy_reg & MII_CR_AUTO_NEG_EN) ? 1 : 0;
+		*val = (Adapter->phy_ctrl & MII_CR_AUTO_NEG_EN) ? 1 : 0;
 		break;
 
 	case ETHER_STAT_LINK_DUPLEX:
--- a/usr/src/uts/common/io/e1000g/e1000g_sw.h	Mon Sep 17 22:41:56 2007 -0700
+++ b/usr/src/uts/common/io/e1000g/e1000g_sw.h	Mon Sep 17 22:52:13 2007 -0700
@@ -935,6 +935,15 @@
 	caddr_t nd_data;
 	nd_param_t nd_params[PARAM_COUNT];
 
+	uint16_t phy_ctrl;		/* contents of PHY_CTRL */
+	uint16_t phy_status;		/* contents of PHY_STATUS */
+	uint16_t phy_an_adv;		/* contents of PHY_AUTONEG_ADV */
+	uint16_t phy_an_exp;		/* contents of PHY_AUTONEG_EXP */
+	uint16_t phy_ext_status;	/* contents of PHY_EXT_STATUS */
+	uint16_t phy_1000t_ctrl;	/* contents of PHY_1000T_CTRL */
+	uint16_t phy_1000t_status;	/* contents of PHY_1000T_STATUS */
+	uint16_t phy_lp_able;		/* contents of PHY_LP_ABILITY */
+
 } e1000g_t;
 
 
@@ -973,6 +982,7 @@
 void e1000g_mask_tx_interrupt(struct e1000g *Adapter);
 void phy_spd_state(struct e1000_hw *hw, boolean_t enable);
 void e1000_enable_pciex_master(struct e1000_hw *hw);
+void e1000g_get_driver_control(struct e1000_hw *hw);
 
 #pragma inline(e1000_rar_set)