Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 3029

kernel-2.6.18-238.el5.src.rpm

From: Marcus Barrow <mbarrow@redhat.com>
Date: Wed, 18 Nov 2009 14:42:10 -0500
Subject: [net] qlge: updates and fixes for RHEL-5.5
Message-id: <20091118144210.23069.16580.sendpatchset@file.bos.redhat.com>
Patchwork-id: 21415
O-Subject: [rhel 5.5 patch] qlge - updates and fixes from upstream or testing.
Bugzilla: 519453
RH-Acked-by: Neil Horman <nhorman@redhat.com>
RH-Acked-by: David S. Miller <davem@redhat.com>
RH-Acked-by: Stanislaw Gruszka <sgruszka@redhat.com>

BZ 519453

This patch provides updates and fixes from upstream or testing for the
QLGE 10 GigE driver.

It applies and builds cleanly on 2.6.18-170 with the QLGE KVM boot
crash patch. It has been tested at QLogic and where possible patches
have been pushed upstream or are being tested for upstream.

 - Fixed WOL
   Do not change frame routing during suspend.
   commit 4fc9b8697cdb42f7df322fb97e635491e182ae65

 - Fixed ethtool loopback test hang issue
   commit 9dfbbaa6b0b9f7c4d6c9dc3a59006f44e6521138

 - Backward compatibility for rh5.3 sles10.2

 - Added standard pause support using ethtool
   commit 1d30df24ec85477368e6e38fe1b4d1b67b3be9d4

 - Showing nic rx fifo drop Per priority transmit receive
   pause frame counters in statistics
   commit 6abd23468deaf3f6215a80b564f85df934209721

 - Added Force Coredump to log file and dumping 64 nic registers
   to ethtool users space

 - Fixed bonding issue by setting Receive Routing bit and make it load param
   commit a3b71939a9c7a942323bfc0c8f97d0fd2bf22f95

 - Fixed bonding mode tlb and alb
   In testing, we don't know if this is required upstream or not yet.

 - Adding new reset functionality stop management traffic and wait for the
   NIC and MGMNT FIFOs to empty
   commit 84087f4d482c5d554e1b26a557d424761213e5dc=

 - Adding New Coredump
   We are currently supporting core dump in distros only.

 - Adding missing bonding fixed
   We are in the process of pushing this upstream now.
   It's just a deletion of 2 lines

 - Fix frame routing for multicast frames
   Multicast should always be routed to the default (zeroeth) rx
   ring.  Broadcast frames are already routed correctly.
   commit e163d7f2775624fcd7d21a060e18171fe006106d

 - Fix RX multicast filter settings
   This adds enable bit to filter write.
   commit 76b26694cc9eb8c7ea1004b0601a5953cfa57b89

 - Fixed bonding mode 5 tlb by saving current
   We are in the process of testing this to see if it's required
   upstream.

 - Fix mailbox timed out error
   The mailbox command process would only process a maximum of 5
   unrelated firmware events while waiting for it's command completion
   status. It should process an unlimited number of events while waiting
   for a maximum of 5 seconds.

 - add dcbx firmware async event handler
   The driver has nothing to do, but this marker prevents the event
   from showing up 'not handled'.

 - Fix WOL issue
   commit 4fc9b8697cdb42f7df322fb97e635491e182ae65

 - Version -> p23

diff --git a/drivers/net/qlge/kcompat.h b/drivers/net/qlge/kcompat.h
index 7606d89..77cc503 100644
--- a/drivers/net/qlge/kcompat.h
+++ b/drivers/net/qlge/kcompat.h
@@ -30,13 +30,13 @@
 #include <asm/io.h>
 
 /*****************************************************************************/
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
 #ifndef NETIF_F_GRO
 #define vlan_gro_receive(_napi, _vlgrp, _vlan, _skb) \
 		vlan_hwaccel_receive_skb(_skb, _vlgrp, _vlan)
 #define napi_gro_receive(_napi, _skb) netif_receive_skb(_skb)
 #endif
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
 #ifndef CHECKSUM_PARTIAL
 #define CHECKSUM_PARTIAL CHECKSUM_HW
 #define CHECKSUM_COMPLETE CHECKSUM_HW
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 9e64f6f..ab2a2d6 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -17,9 +17,9 @@
  */
 #define DRV_NAME	"qlge"
 #define DRV_STRING	"QLogic 10 Gigabit PCI-E Ethernet Driver "
-#define DRV_VERSION	"1.00.00.22"
-#define DIS_VERSION	"2.6.16-2.6.18-p22"
-#define REL_DATE	"090819"
+#define DRV_VERSION	"1.00.00.23"
+#define DIS_VERSION	"2.6.16-2.6.18-p23"
+#define REL_DATE	"091109"
 
 #define PFX "qlge: "
 #define QPRINTK(qdev, nlevel, klevel, fmt, args...) \
@@ -163,9 +163,9 @@ enum {
 	RST_FO_TFO = (1 << 0),
 	RST_FO_RR_MASK = 0x00060000,
 	RST_FO_RR_CQ_CAM = 0x00000000,
-	RST_FO_RR_DROP = 0x00000001,
-	RST_FO_RR_DQ = 0x00000002,
-	RST_FO_RR_RCV_FUNC_CQ = 0x00000003,
+	RST_FO_RR_DROP = 0x00000002,
+	RST_FO_RR_DQ = 0x00000004,
+	RST_FO_RR_RCV_FUNC_CQ = 0x00000006,
 	RST_FO_FRB = (1 << 12),
 	RST_FO_MOP = (1 << 13),
 	RST_FO_REG = (1 << 14),
@@ -841,6 +841,12 @@ enum {
 	MB_CMD_GET_LINK_STS = 0x00000124,
 	MB_CMD_SET_LED_CFG = 0x00000125, /* Set LED Configuration Register */
 	MB_CMD_GET_LED_CFG = 0x00000126, /* Get LED Configuration Register */
+	MB_CMD_SET_MGMNT_TFK_CTL = 0x00000160, /* Set Mgmnt Traffic Control */
+	MB_SET_MPI_TFK_STOP = (1 << 0),
+	MB_SET_MPI_TFK_RESUME = (1 << 1),
+	MB_CMD_GET_MGMNT_TFK_CTL = 0x00000161, /* Get Mgmnt Traffic Control */
+	MB_GET_MPI_TFK_STOPPED = (1 << 0),
+	MB_GET_MPI_TFK_FIFO_EMPTY = (1 << 1),
 	/* Sub-commands for IDC request.
 	 * This describes the reason for the
 	 * IDC request.
@@ -1423,6 +1429,28 @@ struct nic_stats {
 	u64 rx_1024_to_1518_pkts;
 	u64 rx_1519_to_max_pkts;
 	u64 rx_len_err_pkts;
+
+	/*
+	 * These stats come from offset 500h to 5C8h
+	 * in the XGMAC register.
+	 */
+	u64 tx_cbfc_pause_frames0;
+	u64 tx_cbfc_pause_frames1;
+	u64 tx_cbfc_pause_frames2;
+	u64 tx_cbfc_pause_frames3;
+	u64 tx_cbfc_pause_frames4;
+	u64 tx_cbfc_pause_frames5;
+	u64 tx_cbfc_pause_frames6;
+	u64 tx_cbfc_pause_frames7;
+	u64 rx_cbfc_pause_frames0;
+	u64 rx_cbfc_pause_frames1;
+	u64 rx_cbfc_pause_frames2;
+	u64 rx_cbfc_pause_frames3;
+	u64 rx_cbfc_pause_frames4;
+	u64 rx_cbfc_pause_frames5;
+	u64 rx_cbfc_pause_frames6;
+	u64 rx_cbfc_pause_frames7;
+	u64 rx_nic_fifo_drop;
 };
 
 /* Address/Length pairs for the coredump. */
@@ -1518,7 +1546,17 @@ enum {
 	ETS_SEG_NUM = 34,
 	PROBE_DUMP_SEG_NUM = 35,
 	ROUTING_INDEX_SEG_NUM = 36,
-	MAC_PROTOCOL_SEG_NUM = 37
+	MAC_PROTOCOL_SEG_NUM = 37,
+	XAUI2_AN_SEG_NUM = 38,
+	XAUI2_HSS_PCS_SEG_NUM = 39,
+	XFI2_AN_SEG_NUM = 40,
+	XFI2_TRAIN_SEG_NUM = 41,
+	XFI2_HSS_PCS_SEG_NUM = 42,
+	XFI2_HSS_TX_SEG_NUM = 43,
+	XFI2_HSS_RX_SEG_NUM = 44,
+	XFI2_HSS_PLL_SEG_NUM = 45,
+	SEM_REGS_SEG_NUM = 50
+
 };
 
 /* Probe dump constants */
@@ -1532,17 +1570,47 @@ enum {
 
 /* Save both the address and data register */
 #define WORDS_PER_MAC_PROT_ENTRY 2
+#define MAX_SEMAPHORE_FUNCTIONS 5
+#define WQC_WORD_SIZE 6
+#define NUMBER_OF_WQCS 128
+#define CQC_WORD_SIZE 13
+#define NUMBER_OF_CQCS 128
+
+#define MPI_READ 0x00000000
+#define REG_BLOCK 0x00020000
+#define TEST_LOGIC_FUNC_PORT_CONFIG 0x1002
+#define NIC1_FUNCTION_ENABLE 0x00000001
+#define NIC1_FUNCTION_MASK 0x0000000e
+#define NIC1_FUNCTION_SHIFT 1
+#define NIC2_FUNCTION_ENABLE 0x00000010
+#define NIC2_FUNCTION_MASK 0x000000e0
+#define NIC2_FUNCTION_SHIFT 5
+#define FC1_FUNCTION_ENABLE 0x00000100
+#define FC1_FUNCTION_MASK 0x00000e00
+#define FC1_FUNCTION_SHIFT 9
+#define FC2_FUNCTION_ENABLE 0x00001000
+#define FC2_FUNCTION_MASK 0x0000e000
+#define FC2_FUNCTION_SHIFT 13
+#define FUNCTION_SHIFT 6
+
+#define XFI1_POWERED_UP 0x00000005
+#define XFI2_POWERED_UP	0x0000000A
+#define XAUI_POWERED_DOWN 0x00000001
+
+#define RISC_124 0x0003007c
+#define RISC_127 0x0003007f
+#define SHADOW_OFFSET 0xb0000000
 
 #define SYS_CLOCK (0x00)
 #define PCI_CLOCK (0x80)
 #define FC_CLOCK (0x140)
 #define XGM_CLOCK (0x180)
 #define ADDRESS_REGISTER_ENABLE 0x00010000
-#define UP			0x00008000
-#define MAX_MUX			0x40
-#define MAX_MODULES		0x1F
-#define RS_AND_ADR		0x06000000
-#define RS_ONLY			0x04000000
+#define UP 0x00008000
+#define MAX_MUX	0x40
+#define MAX_MODULES 0x1F
+#define RS_AND_ADR 0x06000000
+#define RS_ONLY	0x04000000
 #define NUM_TYPES 10
 
 struct ql_nic_misc {
@@ -1621,9 +1689,25 @@ struct ql_mpi_coredump {
 	struct mpi_coredump_segment_header nic_regs_seg_hdr;
 	u32 nic_regs[64];
 
+	/* segment 17 */
+	struct mpi_coredump_segment_header nic2_regs_seg_hdr;
+	u32 nic2_regs[64];
+
 	/* segment 18 */
 	struct mpi_coredump_segment_header xgmac1_seg_hdr;
-	u32 xgmac1[((XGMAC_REGISTER_END - PAUSE_SRC_LO) >> 2)];
+	u32 xgmac1[XGMAC_REGISTER_END / 4];
+
+	/* segment 19 */
+	struct mpi_coredump_segment_header xgmac2_seg_hdr;
+	u32 xgmac2[XGMAC_REGISTER_END / 4];
+
+	/* segment 20 */
+	struct mpi_coredump_segment_header code_ram_seg_hdr;
+	u32 code_ram[CODE_RAM_CNT];
+
+	/* segment 21 */
+	struct mpi_coredump_segment_header memc_ram_seg_hdr;
+	u32 memc_ram[MEMC_RAM_CNT];
 
 	/* segment 22 */
 	struct mpi_coredump_segment_header xaui_an_hdr;
@@ -1657,7 +1741,7 @@ struct ql_mpi_coredump {
 	struct mpi_coredump_segment_header xfi_hss_pll_hdr;
 	u32 serdes_xfi_hss_pll[32];
 
-	/* segment ?? */
+	/* segment 30 */
 	struct mpi_coredump_segment_header misc_nic_seg_hdr;
 	struct ql_nic_misc misc_nic_info;
 
@@ -1666,12 +1750,14 @@ struct ql_mpi_coredump {
 	struct mpi_coredump_segment_header intr_states_seg_hdr;
 	u32 intr_states[MAX_RX_RINGS];
 
+	/* segment 32 */
 	/* 3 cam words each for 16 unicast,
 	 * 2 cam words for each of 32 multicast.
 	 */
 	struct mpi_coredump_segment_header cam_entries_seg_hdr;
 	u32 cam_entries[(16 * 3) + (32 * 3)];
 
+	/* segment 33 */
 	struct mpi_coredump_segment_header nic_routing_words_seg_hdr;
 	u32 nic_routing_words[16];
 
@@ -1693,13 +1779,54 @@ struct ql_mpi_coredump {
 	u32 mac_prot_regs[MAC_PROTOCOL_REGISTER_WORDS *
 				WORDS_PER_MAC_PROT_ENTRY];
 
-	/* segment 20 */
-	struct mpi_coredump_segment_header code_ram_seg_hdr;
-	u32 code_ram[CODE_RAM_CNT];
+	/* segment 38 */
+	struct mpi_coredump_segment_header xaui2_an_hdr;
+	u32 serdes2_xaui_an[14];
 
-	/* segment 21 */
-	struct mpi_coredump_segment_header memc_ram_seg_hdr;
-	u32 memc_ram[MEMC_RAM_CNT];
+	/* segment 39 */
+	struct mpi_coredump_segment_header xaui2_hss_pcs_hdr;
+	u32 serdes2_xaui_hss_pcs[33];
+
+	/* segment 40 */
+	struct mpi_coredump_segment_header xfi2_an_hdr;
+	u32 serdes2_xfi_an[14];
+
+	/* segment 41 */
+	struct mpi_coredump_segment_header xfi2_train_hdr;
+	u32 serdes2_xfi_train[12];
+
+	/* segment 42 */
+	struct mpi_coredump_segment_header xfi2_hss_pcs_hdr;
+	u32 serdes2_xfi_hss_pcs[15];
+
+	/* segment 43 */
+	struct mpi_coredump_segment_header xfi2_hss_tx_hdr;
+	u32 serdes2_xfi_hss_tx[32];
+
+	/* segment 44 */
+	struct mpi_coredump_segment_header xfi2_hss_rx_hdr;
+	u32 serdes2_xfi_hss_rx[32];
+
+	/* segment 45 */
+	struct mpi_coredump_segment_header xfi2_hss_pll_hdr;
+	u32 serdes2_xfi_hss_pll[32];
+
+	/* segment 50 */
+	/* semaphore register for all 5 functions */
+	struct mpi_coredump_segment_header sem_regs_seg_hdr;
+	u32 sem_regs[MAX_SEMAPHORE_FUNCTIONS]; 
+
+	struct mpi_coredump_segment_header wqc1_seg_hdr;
+	u32 wqc1[WQC_WORD_SIZE * NUMBER_OF_WQCS];
+
+	struct mpi_coredump_segment_header cqc1_seg_hdr;
+	u32 cqc1[CQC_WORD_SIZE * NUMBER_OF_CQCS];
+
+	struct mpi_coredump_segment_header wqc2_seg_hdr;
+	u32 wqc2[WQC_WORD_SIZE * NUMBER_OF_WQCS];
+
+	struct mpi_coredump_segment_header cqc2_seg_hdr;
+	u32 cqc2[CQC_WORD_SIZE * NUMBER_OF_CQCS];
 };
 
 /*
@@ -1738,6 +1865,7 @@ enum {
 	QL_TESTING = 10,
 	QL_IN_FW_RST = 11,
 	QL_SPOOL_LOG = 12,
+	QL_LINK_UP = 13,
 };
 
 /* link_status bit definitions */
@@ -1876,11 +2004,14 @@ struct ql_adapter {
 	struct work_struct mpi_port_cfg_work;
 	struct work_struct mpi_idc_work;
 	struct work_struct mpi_core_to_log;
+	struct work_struct link_work;
 	struct completion ide_completion;
 	struct nic_operations *nic_ops;
 	u16 device_id;
 	struct timer_list eeh_timer;
 	uint32_t *config_space;
+	/* Saving mac addr */
+	char current_mac_addr[6];
 };
 
 /*
@@ -1981,6 +2112,9 @@ int ql_mb_get_port_cfg(struct ql_adapter *qdev);
 int ql_mb_set_port_cfg(struct ql_adapter *qdev);
 int qlge_send(struct sk_buff *skb, struct net_device *ndev);
 void ql_check_receive_frame(struct sk_buff *skb);
+int ql_own_firmware(struct ql_adapter *qdev);
+int ql_wait_fifo_empty(struct ql_adapter *);
+int ql_mb_set_mgmnt_traffic_ctl(struct ql_adapter *, u32);
 
 #if 1
 #define QL_ALL_DUMP
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index 031292c..7740ef2 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -1,142 +1,446 @@
 #include "qlge.h"
 
-/* Read the 400 xgmac control/statistics registers
- * skipping unused locations.
- */
-static int ql_get_xgmac_regs(struct ql_adapter *qdev, u32 * buf)
+unsigned int get_other_func_num(struct ql_adapter *qdev)
 {
-	int status = 0;
-	int i;
+	unsigned int other_function;
+	unsigned int status;
+	unsigned int test_logic;
+	unsigned int nic1_function_num = 0xffffffff;
+	unsigned int nic2_function_num = 0xffffffff;
+	unsigned int fc1_function_num = 0xffffffff;
+	unsigned int fc2_function_num = 0xffffffff;
+
+	QPRINTK_DBG(qdev, DRV, ERR, "Trying to figure out function mapping, "
+				"my function = %d\n", qdev->func);
+	status = ql_read_mpi_reg(qdev, TEST_LOGIC_FUNC_PORT_CONFIG,
+					&test_logic);
+	if (status)
+		return(0xffffffff);
+
+	QPRINTK_DBG(qdev, DRV, ERR, "Test logic 0x%08x = 0x%08x\n", 
+				TEST_LOGIC_FUNC_PORT_CONFIG, test_logic);
+
+	/* First, establish the function number of the other PCI function */
+	if (test_logic & FC1_FUNCTION_ENABLE)
+		fc1_function_num = (test_logic & FC1_FUNCTION_MASK) >> 
+					FC1_FUNCTION_SHIFT;
+	if (test_logic & FC2_FUNCTION_ENABLE)
+		fc2_function_num = (test_logic & FC2_FUNCTION_MASK) >> 
+					FC2_FUNCTION_SHIFT;
+	if (test_logic & NIC1_FUNCTION_ENABLE)
+		nic1_function_num = (test_logic & NIC1_FUNCTION_MASK) >>
+					NIC1_FUNCTION_SHIFT;
+	if (test_logic & NIC2_FUNCTION_ENABLE)
+		nic2_function_num = (test_logic & NIC2_FUNCTION_MASK) >>
+					NIC2_FUNCTION_SHIFT;
+	if (qdev->func == nic1_function_num)
+		other_function = nic2_function_num;
+	else
+		other_function = nic1_function_num;
 
-	for (i = PAUSE_SRC_LO; i < XGMAC_REGISTER_END; i += 4, buf++) {
-		/* We're reading 400 xgmac registers, but we filter out
-		 * serveral locations that are non-responsive to reads.
-		 */
-		if ((i == 0x00000114) ||
-			(i == 0x00000118) ||
-			(i == 0x0000013c) ||
-			(i == 0x00000140) ||
-			(i > 0x00000150 && i < 0x000001fc) ||
-			(i > 0x00000278 && i < 0x000002a0) ||
-			(i > 0x000002c0 && i < 0x000002cf) ||
-			(i > 0x000002dc && i < 0x000002f0) ||
-			(i > 0x000003c8 && i < 0x00000400) ||
-			(i > 0x00000400 && i < 0x00000410) ||
-			(i > 0x00000410 && i < 0x00000420) ||
-			(i > 0x00000420 && i < 0x00000430) ||
-			(i > 0x00000430 && i < 0x00000440) ||
-			(i > 0x00000440 && i < 0x00000450) ||
-			(i > 0x00000450 && i < 0x00000500) ||
-			(i > 0x0000054c && i < 0x00000568) ||
-			(i > 0x000005c8 && i < 0x00000600)) {
-			*buf = 0xdeadbeef;
-			continue;
-		}
+	QPRINTK_DBG(qdev, DRV, ERR, "My function = %d, other NIC function = %d,"
+			"FC1 Func = %d, FC2 Func = %d\n", qdev->func,
+			other_function,	fc1_function_num, fc2_function_num);
+	return(other_function);
+}
 
-		status = ql_read_xgmac_reg(qdev, i, buf);
-		if (status)
-			goto err;
+static unsigned int read_other_function_reg(struct ql_adapter *qdev,
+						unsigned int reg)
+{
+	unsigned int other_function;
+	unsigned int register_to_read;
+	unsigned int reg_val;
+	unsigned int status = 0;
+
+	other_function = get_other_func_num(qdev);
+
+	/* The other function is not enabled so we don't need
+	 * to read anything out of it.
+	 */
+	if (other_function == 0xffffffff)
+		return(other_function);
+
+	/* The other function is there so now we need to
+	 * read the requested register.
+	 */
+	register_to_read = REG_BLOCK | MPI_READ | 
+				(other_function << FUNCTION_SHIFT) | reg;
+	status = ql_read_mpi_reg(qdev, register_to_read, &reg_val);
+	if (status != 0)
+		return(0xffffffff);
+
+	return(reg_val);
+}
+
+static unsigned int write_other_function_reg(struct ql_adapter *qdev,
+					unsigned int reg, unsigned int reg_val)
+{
+	unsigned int other_function;
+	unsigned int register_to_read;
+	unsigned int status = 0;
+
+	other_function = get_other_func_num(qdev);
+
+	/*
+	 * The other function is not enabled so we don't 
+	 * need to read anything out of it.
+	 */
+	if (other_function == 0xffffffff)
+		return(-1);
+
+	/*
+	 * The other function is there so now we need
+	 * to read the requested register.
+	 */
+	register_to_read = REG_BLOCK | MPI_READ | 
+				(other_function << FUNCTION_SHIFT) | reg;
+	status = ql_write_mpi_reg(qdev, register_to_read, reg_val);
+
+	return(status);
+}
+
+int wait_other_function_reg_rdy(struct ql_adapter *qdev, unsigned int reg,
+					unsigned int bit, unsigned int err_bit)
+{
+	unsigned int temp;
+	int count = 10;
+
+	while (count) {
+		temp = read_other_function_reg(qdev, reg);
+
+		/* check for errors */
+		if (temp & err_bit)
+			return -1;
+		else if (temp & bit)
+			 return 0;
+		mdelay(10);
+		count--;
 	}
-err:
+	return -1;
+}
+
+int read_other_function_serdes_reg(struct ql_adapter *qdev, unsigned int reg,
+							unsigned int *data)
+{
+	int status;
+
+	/* wait for reg to come ready */
+	status = wait_other_function_reg_rdy(qdev, XG_SERDES_ADDR / 4,
+						XG_SERDES_ADDR_RDY, 0);
+	if (status)
+		goto exit;
+
+	/* set up for reg read */
+	write_other_function_reg(qdev, XG_SERDES_ADDR / 4, reg | PROC_ADDR_R);
+
+	/* wait for reg to come ready */
+	status = wait_other_function_reg_rdy(qdev, XG_SERDES_ADDR / 4,
+						XG_SERDES_ADDR_RDY, 0);
+	if (status)
+		goto exit;
+	
+	/* get the data */
+	*data = read_other_function_reg(qdev, (XG_SERDES_DATA / 4));
+exit:
 	return status;
 }
 
+int ql_read_other_function_xgmac_reg(struct ql_adapter *qdev, unsigned int reg,
+							unsigned int *data)
+{
+	int status = 0;
+
+	/* wait for reg to come ready */
+	status = wait_other_function_reg_rdy(qdev, XGMAC_ADDR / 4,
+						XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+	if (status)
+		goto exit;
+
+	/* set up for reg read */
+	write_other_function_reg(qdev, XGMAC_ADDR / 4, reg | XGMAC_ADDR_R);
+
+	/* wait for reg to come ready */
+	status = wait_other_function_reg_rdy(qdev, XGMAC_ADDR / 4,
+						XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+	if (status)
+		goto exit;
+
+	/* get the data */
+	*data = read_other_function_reg(qdev, XGMAC_DATA / 4);
+exit:
+	return status;
+}
+
+/* Read out the SERDES registers */
 int ql_read_serdes_reg(struct ql_adapter *qdev, u32 reg, u32 * data)
 {
 	int status;
+
 	/* wait for reg to come ready */
 	status = ql_wait_reg_rdy(qdev, XG_SERDES_ADDR, XG_SERDES_ADDR_RDY, 0);
 	if (status)
 		goto exit;
+
 	/* set up for reg read */
 	ql_write32(qdev, XG_SERDES_ADDR, reg | PROC_ADDR_R);
+
 	/* wait for reg to come ready */
 	status = ql_wait_reg_rdy(qdev, XG_SERDES_ADDR, XG_SERDES_ADDR_RDY, 0);
 	if (status)
 		goto exit;
+
 	/* get the data */
 	*data = ql_read32(qdev, XG_SERDES_DATA);
 exit:
 	return status;
 }
 
+void get_both_serdes(struct ql_adapter *qdev, unsigned int addr,
+			unsigned int *direct_ptr, unsigned int *indirect_ptr,
+			unsigned int direct_valid, unsigned int indirect_valid)
+{
+	unsigned int status;
+
+	status = 0xffffffff;
+	if(direct_valid)
+		status = ql_read_serdes_reg(qdev, addr, direct_ptr);
+
+	if (status)
+		*direct_ptr = 0xDEADBEEF;
+
+	status = 0xffffffff;
+	if(indirect_valid)
+		status = read_other_function_serdes_reg(qdev, addr, indirect_ptr);
+
+	if (status)
+	*indirect_ptr = 0xDEADBEEF;
+}
+
 static int ql_get_serdes_regs(struct ql_adapter *qdev,
 				struct ql_mpi_coredump *mpi_coredump)
 {
-	u32 i, j;
 	int status;
+	unsigned int xfi_direct_valid, xfi_indirect_valid, xaui_direct_valid;
+	unsigned int xaui_indirect_valid, temp, xaui_reg, i;
+	unsigned int *direct_ptr;
+	unsigned int *indirect_ptr;
+
+	xfi_direct_valid = xfi_indirect_valid = 0;
+	xaui_direct_valid = xaui_indirect_valid = 1;
+
+	/* The XAUI needs to be read out per port */
+	xaui_reg = 0x800;
+	if (qdev->func & 1) {
+		/* We are NIC 2	*/
+		status = read_other_function_serdes_reg(qdev, xaui_reg, &temp);
+		if(status)
+			 temp = XAUI_POWERED_DOWN;
+		if((temp & XAUI_POWERED_DOWN) == XAUI_POWERED_DOWN)
+			 xaui_indirect_valid = 0;
+
+		status = ql_read_serdes_reg(qdev, xaui_reg, &temp);
+		if(status)
+			 temp = XAUI_POWERED_DOWN;
+
+		if((temp & XAUI_POWERED_DOWN) == XAUI_POWERED_DOWN)
+			 xaui_direct_valid = 0;
+	} else {
+		/* We are NIC 1	*/
+		status = read_other_function_serdes_reg(qdev, xaui_reg, &temp);
+		if(status)
+			 temp = XAUI_POWERED_DOWN;
+		if((temp & XAUI_POWERED_DOWN) == XAUI_POWERED_DOWN)
+			 xaui_indirect_valid = 0;
+
+		status = ql_read_serdes_reg(qdev, xaui_reg, &temp);
+		if(status)
+			 temp = XAUI_POWERED_DOWN;
+		if((temp & XAUI_POWERED_DOWN) == XAUI_POWERED_DOWN)
+			 xaui_direct_valid = 0;
+	}
 
-	for (i = 0, j = 0; i <= 0x000000034; i += 4) {
-		status = ql_read_serdes_reg(qdev, i,
-					&mpi_coredump->serdes_xaui_an[j++]);
-		if (status)
-			goto err;
-
+	/*
+	 * XFI register is shared so only need to read one 
+	 * functions and then check the bits.
+	 */
+	status = ql_read_serdes_reg(qdev, 0x1E06, &temp);
+	if(status)
+		temp = 0;
+
+	if((temp & XFI1_POWERED_UP) == XFI1_POWERED_UP) {
+		/* now see if i'm NIC 1 or NIC 2 */
+		if(qdev->func & 1)
+			 /* I'm NIC 2, so the indirect (NIC1) xfi is up. */
+			 xfi_indirect_valid = 1;
+		else
+			 xfi_direct_valid = 1;
+	}
+	if((temp & XFI2_POWERED_UP) == XFI2_POWERED_UP) {
+		/* now see if i'm NIC 1 or NIC 2 */
+		if(qdev->func & 1)
+			 /* I'm NIC 2, so the indirect (NIC1) xfi is up. */
+			 xfi_direct_valid = 1;
+		else
+			 xfi_indirect_valid = 1;
 	}
 
-	for (i = 0x800, j = 0; i <= 0x880; i += 4) {
-		status = ql_read_serdes_reg(qdev, i,
-						&mpi_coredump->
-						serdes_xaui_hss_pcs[j++]);
-		if (status)
-			goto err;
+	if (qdev->func & 1) {
+		/* Function 2 is direct	*/
+		direct_ptr = (unsigned int *)(&mpi_coredump->serdes2_xaui_an);
+		indirect_ptr = (unsigned int *)(&mpi_coredump->serdes_xaui_an);
+	} else {
+		/* Function 1 is direct	*/
+		direct_ptr = (unsigned int *)(&mpi_coredump->serdes_xaui_an);
+		indirect_ptr = (unsigned int *)(&mpi_coredump->serdes2_xaui_an);
 	}
 
-	for (i = 0x1000, j = 0; i <= 0x1034; i += 4) {
-		status = ql_read_serdes_reg(qdev, i,
-					&mpi_coredump->serdes_xfi_an[j++]);
-		if (status)
-			goto err;
+	for (i = 0; i <= 0x000000034; i += 4, direct_ptr ++, indirect_ptr ++)
+		get_both_serdes(qdev, i, direct_ptr, indirect_ptr, 
+					xaui_direct_valid, xaui_indirect_valid);
+	if (qdev->func & 1) {
+		direct_ptr =
+			(unsigned int *)(&mpi_coredump->serdes2_xaui_hss_pcs);
+		indirect_ptr =
+			(unsigned int *)(&mpi_coredump->serdes_xaui_hss_pcs);
+	} else {
+		direct_ptr =
+			(unsigned int *)(&mpi_coredump->serdes_xaui_hss_pcs);
+		indirect_ptr =
+			(unsigned int *)(&mpi_coredump->serdes2_xaui_hss_pcs);
 	}
 
-	for (i = 0x1050, j = 0; i <= 0x107c; i += 4) {
-		status = ql_read_serdes_reg(qdev, i,
-						&mpi_coredump->
-						serdes_xfi_train[j++]);
-		if (status)
-			goto err;
+	for (i = 0x800; i <= 0x880; i += 4, direct_ptr ++, indirect_ptr ++)
+		get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+					xaui_direct_valid, xaui_indirect_valid);
+	if (qdev->func & 1) {
+		direct_ptr = (unsigned int *)(&mpi_coredump->serdes2_xfi_an);
+		indirect_ptr = (unsigned int *)(&mpi_coredump->serdes_xfi_an);
+	} else {
+		direct_ptr = (unsigned int *)(&mpi_coredump->serdes_xfi_an);
+		indirect_ptr = (unsigned int *)(&mpi_coredump->serdes2_xfi_an);
 	}
 
-	for (i = 0x1800, j = 0; i <= 0x1838; i += 4) {
-		status = ql_read_serdes_reg(qdev, i,
-						&mpi_coredump->
-						serdes_xfi_hss_pcs[j++]);
-		if (status)
-			goto err;
+	for (i = 0x1000; i <= 0x1034; i += 4, direct_ptr ++, indirect_ptr ++)
+		get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+					xfi_direct_valid, xfi_indirect_valid);
+	if (qdev->func & 1) {
+		direct_ptr = (unsigned int *)(&mpi_coredump->serdes2_xfi_train);
+		indirect_ptr =
+			(unsigned int *)(&mpi_coredump->serdes_xfi_train);
+	} else {
+		direct_ptr = (unsigned int *)(&mpi_coredump->serdes_xfi_train);
+		indirect_ptr =
+			(unsigned int *)(&mpi_coredump->serdes2_xfi_train);
 	}
 
-	for (i = 0x1c00, j = 0; i <= 0x1c1f; i++) {
-		status = ql_read_serdes_reg(qdev, i,
-						&mpi_coredump->
-						serdes_xfi_hss_tx[j++]);
-		if (status)
-			goto err;
+	for (i = 0x1050; i <= 0x107c; i += 4, direct_ptr ++, indirect_ptr ++)
+		get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+					xfi_direct_valid, xfi_indirect_valid);
+	if (qdev->func & 1){
+		direct_ptr =
+			(unsigned int *)(&mpi_coredump->serdes2_xfi_hss_pcs);
+		indirect_ptr =
+			(unsigned int *)(&mpi_coredump->serdes_xfi_hss_pcs);
+	} else {
+		direct_ptr =
+			(unsigned int *)(&mpi_coredump->serdes_xfi_hss_pcs);
+		indirect_ptr =
+			(unsigned int *)(&mpi_coredump->serdes2_xfi_hss_pcs);
 	}
 
-	for (i = 0x1c40, j = 0; i <= 0x1c5f; i++) {
-		status = ql_read_serdes_reg(qdev, i,
-						&mpi_coredump->
-						serdes_xfi_hss_rx[j++]);
-		if (status)
-			goto err;
+	for (i = 0x1800; i <= 0x1838; i += 4, direct_ptr++, indirect_ptr ++)
+		get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+					xfi_direct_valid, xfi_indirect_valid);
+	if (qdev->func & 1) {
+		direct_ptr =
+			(unsigned int *)(&mpi_coredump->serdes2_xfi_hss_tx);
+		indirect_ptr =
+			(unsigned int *)(&mpi_coredump->serdes_xfi_hss_tx);
+	} else {
+		direct_ptr = (unsigned int *)(&mpi_coredump->serdes_xfi_hss_tx);
+		indirect_ptr =
+			(unsigned int *)(&mpi_coredump->serdes2_xfi_hss_tx);
+	}
+	for (i = 0x1c00; i <= 0x1c1f; i++, direct_ptr ++, indirect_ptr ++)
+		get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+					xfi_direct_valid, xfi_indirect_valid);
+	if (qdev->func & 1) {
+		direct_ptr =
+			(unsigned int *)(&mpi_coredump->serdes2_xfi_hss_rx);
+		indirect_ptr =
+			(unsigned int *)(&mpi_coredump->serdes_xfi_hss_rx);
+	} else {
+		direct_ptr = (unsigned int *)(&mpi_coredump->serdes_xfi_hss_rx);
+		indirect_ptr =
+			(unsigned int *)(&mpi_coredump->serdes2_xfi_hss_rx);
 	}
 
-	for (i = 0x1e00, j = 0; i <= 0x1e1f; i++) {
-		status = ql_read_serdes_reg(qdev, i,
-						&mpi_coredump->
-						serdes_xfi_hss_pll[j++]);
-		if (status)
-			goto err;
+	for (i = 0x1c40; i <= 0x1c5f; i++, direct_ptr ++, indirect_ptr ++)
+		get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+					xfi_direct_valid, xfi_indirect_valid);
+
+	if (qdev->func & 1) {
+		direct_ptr =
+			(unsigned int *)(&mpi_coredump->serdes2_xfi_hss_pll);
+		indirect_ptr =
+			(unsigned int *)(&mpi_coredump->serdes_xfi_hss_pll);
+	} else {
+		direct_ptr =
+			(unsigned int *)(&mpi_coredump->serdes_xfi_hss_pll);
+		indirect_ptr =
+			(unsigned int *)(&mpi_coredump->serdes2_xfi_hss_pll);
 	}
+	for (i = 0x1e00; i <= 0x1e1f; i++, direct_ptr ++, indirect_ptr ++)
+		get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+					xfi_direct_valid, xfi_indirect_valid);
+	return(0);
+}
 
-err:
-	if (status)
-		QPRINTK(qdev, DRV, ERR,
-			"Serdes register 0x%.08x access error\n", i);
+/* Read the 400 xgmac control/statistics registers
+ * skipping unused locations.
+ */
+static int ql_get_xgmac_regs(struct ql_adapter *qdev, u32 * buf,
+					unsigned int other_function)
+{
+	int status = 0;
+	int i;
 
+	for (i = PAUSE_SRC_LO; i < XGMAC_REGISTER_END; i += 4, buf++) {
+		/* We're reading 400 xgmac registers, but we filter out
+		 * serveral locations that are non-responsive to reads.
+		 */
+		if ((i == 0x00000114) ||
+			(i == 0x00000118) ||
+			(i == 0x0000013c) ||
+			(i == 0x00000140) ||
+			(i > 0x00000150 && i < 0x000001fc) ||
+			(i > 0x00000278 && i < 0x000002a0) ||
+			(i > 0x000002c0 && i < 0x000002cf) ||
+			(i > 0x000002dc && i < 0x000002f0) ||
+			(i > 0x000003c8 && i < 0x00000400) ||
+			(i > 0x00000400 && i < 0x00000410) ||
+			(i > 0x00000410 && i < 0x00000420) ||
+			(i > 0x00000420 && i < 0x00000430) ||
+			(i > 0x00000430 && i < 0x00000440) ||
+			(i > 0x00000440 && i < 0x00000450) ||
+			(i > 0x00000450 && i < 0x00000500) ||
+			(i > 0x0000054c && i < 0x00000568) ||
+			(i > 0x000005c8 && i < 0x00000600)) {
+			if (other_function)
+				status =
+				ql_read_other_function_xgmac_reg(qdev, i, buf);
+			else
+				status = ql_read_xgmac_reg(qdev, i, buf);
+	
+			if (status)
+				*buf = 0xdeadbeef;
+			break;
+		}
+	}
 	return status;
 }
 
+/* Read out the ETS registers */
 static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf)
 {
 	int status = 0;
@@ -155,6 +459,7 @@ static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf)
 	return status;
 }
 
+/* For each RX Ring, read the interrupt enable register */
 static void ql_get_intr_states(struct ql_adapter *qdev, u32 * buf)
 {
 	int i;
@@ -227,15 +532,12 @@ err:
 	return status;
 }
 
+/* Read the MPI Processor shadow registers */
 static int ql_get_mpi_shadow_regs(struct ql_adapter *qdev, u32 * buf)
 {
 	u32 i;
 	int status;
 
-#define RISC_124 0x0003007c
-#define RISC_127 0x0003007f
-#define SHADOW_OFFSET 0xb0000000
-
 	for (i = 0; i < MPI_CORE_SH_REGS_CNT; i++, buf++) {
 		status = ql_write_mpi_reg(qdev, RISC_124,
 					  (SHADOW_OFFSET | i << 20));
@@ -249,6 +551,7 @@ end:
 	return status;
 }
 
+/* Read the MPI Processor core registers */
 static int ql_get_mpi_regs(struct ql_adapter *qdev, u32 * buf,
 				u32 offset, u32 count)
 {
@@ -261,6 +564,7 @@ static int ql_get_mpi_regs(struct ql_adapter *qdev, u32 * buf,
 	return status;
 }
 
+/* Read the ASIC probe dump */
 static unsigned int *ql_get_probe(struct ql_adapter *qdev, u32 clock,
 					u8 *valid, u32 *buf)
 {
@@ -445,6 +749,7 @@ static int ql_get_probe_dump(struct ql_adapter *qdev, unsigned int *buf)
 
 }
 
+/* Read out the routing index registers */
 static int ql_get_routing_index_registers(struct ql_adapter *qdev, u32 *buf)
 {
 	int status;
@@ -483,6 +788,7 @@ static int ql_get_routing_index_registers(struct ql_adapter *qdev, u32 *buf)
 	return status;
 }
 
+/* Read out the MAC protocol registers */
 void ql_get_mac_protocol_registers(struct ql_adapter *qdev, u32 *buf)
 {
 	u32 result_index, result_data;
@@ -569,6 +875,7 @@ void ql_get_mac_protocol_registers(struct ql_adapter *qdev, u32 *buf)
 	}
 }
 
+/* Create a coredump segment header */
 static void ql_build_coredump_seg_header(
 		struct mpi_coredump_segment_header *seg_hdr,
 		u32 seg_number, u32 seg_size, u8 *desc)
@@ -580,10 +887,18 @@ static void ql_build_coredump_seg_header(
 	memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
 }
 
+/*
+ * This function should be called when a coredump / probedump
+ * is to be extracted from the HBA. It is assumed there is a
+ * qdev structure that contains the base address of the register
+ * space for this function as well as a coredump structure that
+ * will contain the dump.
+ */
 int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
 {
 	int status;
 	int i;
+	unsigned int func_num, reg, reg_val;
 
 	if (!mpi_coredump) {
 		QPRINTK(qdev, DRV, ERR,
@@ -604,6 +919,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
 		goto err;
 	}
 
+	/* Insert the global header */
 	memset(&(mpi_coredump->mpi_global_header), 0,
 		sizeof(struct mpi_coredump_global_header));
 	mpi_coredump->mpi_global_header.cookie = MPI_COREDUMP_COOKIE;
@@ -614,12 +930,166 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
 	memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
 		sizeof(mpi_coredump->mpi_global_header.idString));
 
+	/* Get generic NIC reg dump */
+	ql_build_coredump_seg_header(&mpi_coredump->nic_regs_seg_hdr,
+			NIC1_CONTROL_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->nic_regs), "NIC1 Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->nic2_regs_seg_hdr,
+			NIC2_CONTROL_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->nic2_regs), "NIC2 Registers");
+
+	/* Get XGMac registers. (Segment 18, Rev C. step 21) */
+	ql_build_coredump_seg_header(&mpi_coredump->xgmac1_seg_hdr,
+			NIC1_XGMAC_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->xgmac1), "NIC1 XGMac Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xgmac2_seg_hdr,
+			NIC2_XGMAC_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->xgmac2), "NIC2 XGMac Registers");
+
+	if (qdev->func & 1){
+		/* Odd means our function is NIC 2 */
+		for (i = 0; i < 64; i++)
+			mpi_coredump->nic2_regs[i] =
+					 ql_read32(qdev, i * sizeof(u32));
+
+		for (i = 0; i < 64; i++)
+			mpi_coredump->nic_regs[i] =
+			read_other_function_reg(qdev, (i * sizeof(u32)) / 4);
+
+		ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac2[0], 0);
+		ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac1[0], 1);
+	} else {
+		/* Even means our function is NIC 1 */
+		for (i = 0; i < 64; i++)
+			mpi_coredump->nic_regs[i] =
+					ql_read32(qdev, i * sizeof(u32));
+
+		for (i = 0; i < 64; i++)
+			mpi_coredump->nic2_regs[i] =
+			read_other_function_reg(qdev, (i * sizeof(u32)) / 4);
+
+		ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac1[0], 0);
+		ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac2[0], 1);
+	}
+
+	/* Rev C. Step 20a */
+	ql_build_coredump_seg_header(&mpi_coredump->xaui_an_hdr,
+			XAUI_AN_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes_xaui_an),
+			"XAUI AN Registers");
+
+	/* Rev C. Step 20b */
+	ql_build_coredump_seg_header(&mpi_coredump->xaui_hss_pcs_hdr,
+			XAUI_HSS_PCS_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes_xaui_hss_pcs),
+			"XAUI HSS PCS Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xfi_an_hdr, XFI_AN_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes_xfi_an),
+			"XFI AN Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xfi_train_hdr,
+			XFI_TRAIN_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes_xfi_train),
+			"XFI TRAIN Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pcs_hdr,
+			XFI_HSS_PCS_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes_xfi_hss_pcs),
+			"XFI HSS PCS Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_tx_hdr,
+			XFI_HSS_TX_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes_xfi_hss_tx),
+			"XFI HSS TX Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_rx_hdr,
+			XFI_HSS_RX_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes_xfi_hss_rx),
+			"XFI HSS RX Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pll_hdr,
+			XFI_HSS_PLL_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes_xfi_hss_pll),
+			"XFI HSS PLL Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xaui2_an_hdr,
+			XAUI2_AN_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes2_xaui_an),
+			"XAUI2 AN Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xaui2_hss_pcs_hdr,
+			XAUI2_HSS_PCS_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes2_xaui_hss_pcs),
+			"XAUI2 HSS PCS Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xfi2_an_hdr,
+			XFI2_AN_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes2_xfi_an),
+			"XFI2 AN Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xfi2_train_hdr,
+			XFI2_TRAIN_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes2_xfi_train),
+			"XFI2 TRAIN Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_pcs_hdr,
+			XFI2_HSS_PCS_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes2_xfi_hss_pcs),
+			"XFI2 HSS PCS Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_tx_hdr,
+			XFI2_HSS_TX_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes2_xfi_hss_tx),
+			"XFI2 HSS TX Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_rx_hdr,
+			XFI2_HSS_RX_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes2_xfi_hss_rx),
+			"XFI2 HSS RX Registers");
+
+	ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_pll_hdr,
+			XFI2_HSS_PLL_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) + 
+			sizeof(mpi_coredump->serdes2_xfi_hss_pll),
+			"XFI2 HSS PLL Registers");
+
+	status = ql_get_serdes_regs(qdev, mpi_coredump);
+	if (status) {
+		QPRINTK(qdev, DRV, ERR,
+			"Failed Dump of Serdes Registers. Status = 0x%.08x\n",
+			status);
+		goto err;
+	}
+
 	ql_build_coredump_seg_header(&mpi_coredump->core_regs_seg_hdr,
 				CORE_SEG_NUM,
 				sizeof(mpi_coredump->core_regs_seg_hdr) +
 				sizeof(mpi_coredump->mpi_core_regs) +
 				sizeof(mpi_coredump->mpi_core_sh_regs),
 				"Core Registers");
+	
 	/* Get the MPI Core Registers */
 	status = ql_get_mpi_regs(qdev, &mpi_coredump->mpi_core_regs[0],
 				 MPI_CORE_REGS_ADDR, MPI_CORE_REGS_CNT);
@@ -787,78 +1257,6 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
 	if (status)
 		goto err;
 
-	/* Get generic NIC reg dump */
-	/* Segment 16, Rev C. Step 18 */
-	ql_build_coredump_seg_header(&mpi_coredump->nic_regs_seg_hdr,
-				NIC1_CONTROL_SEG_NUM,
-				sizeof(struct mpi_coredump_segment_header)
-				+ sizeof(mpi_coredump->nic_regs),
-				"NIC Registers");
-
-	for (i = 0; i < 64; i++)
-		mpi_coredump->nic_regs[i] = ql_read32(qdev, i * sizeof(u32));
-
-
-	/* Rev C. Step 19 */
-	/* NIC2_CONTROL_SEG_NUM = 17 */
-
-	/* Rev C. Step 20a */
-	ql_build_coredump_seg_header(&mpi_coredump->xaui_an_hdr,
-				XAUI_AN_SEG_NUM,
-				sizeof(struct mpi_coredump_segment_header)
-				+ sizeof(mpi_coredump->serdes_xaui_an),
-				"XAUI AN Registers");
-
-	/* Rev C. Step 20b */
-	ql_build_coredump_seg_header(&mpi_coredump->xaui_hss_pcs_hdr,
-				XAUI_HSS_PCS_SEG_NUM,
-				sizeof(struct mpi_coredump_segment_header)
-				+ sizeof(mpi_coredump->serdes_xaui_hss_pcs),
-				"XAUI HSS PCS Registers");
-
-	ql_build_coredump_seg_header(&mpi_coredump->xfi_an_hdr, XFI_AN_SEG_NUM,
-				sizeof(struct mpi_coredump_segment_header)
-				+ sizeof(mpi_coredump->serdes_xfi_an),
-				"XFI AN Registers");
-
-	ql_build_coredump_seg_header(&mpi_coredump->xfi_train_hdr,
-				XFI_TRAIN_SEG_NUM,
-				sizeof(struct mpi_coredump_segment_header)
-				+ sizeof(mpi_coredump->serdes_xfi_train),
-				"XFI TRAIN Registers");
-
-	ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pcs_hdr,
-				XFI_HSS_PCS_SEG_NUM,
-				sizeof(struct mpi_coredump_segment_header)
-				+ sizeof(mpi_coredump->serdes_xfi_hss_pcs),
-				"XFI HSS PCS Registers");
-
-	ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_tx_hdr,
-				XFI_HSS_TX_SEG_NUM,
-				sizeof(struct mpi_coredump_segment_header)
-				+ sizeof(mpi_coredump->serdes_xfi_hss_tx),
-				"XFI HSS TX Registers");
-
-	ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_rx_hdr,
-				XFI_HSS_RX_SEG_NUM,
-				sizeof(struct mpi_coredump_segment_header)
-				+ sizeof(mpi_coredump->serdes_xfi_hss_rx),
-				"XFI HSS RX Registers");
-
-	ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pll_hdr,
-				XFI_HSS_PLL_SEG_NUM,
-				sizeof(struct mpi_coredump_segment_header)
-				+ sizeof(mpi_coredump->serdes_xfi_hss_pll),
-				"XFI HSS PLL Registers");
-
-	status = ql_get_serdes_regs(qdev, mpi_coredump);
-	if (status) {
-		QPRINTK(qdev, DRV, ERR,
-			"Failed Dump of Serdes Registers. Status = 0x%.08x\n",
-			status);
-		goto err;
-	}
-
 	ql_build_coredump_seg_header(&mpi_coredump->misc_nic_seg_hdr,
 				MISC_NIC_INFO_SEG_NUM,
 				sizeof(struct mpi_coredump_segment_header)
@@ -869,16 +1267,6 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
 	mpi_coredump->misc_nic_info.intr_count = qdev->intr_count;
 	mpi_coredump->misc_nic_info.function = qdev->func;
 
-	/* Get XGMac registers. (Segment 18, Rev C. step 21) */
-	ql_build_coredump_seg_header(&mpi_coredump->xgmac1_seg_hdr,
-				NIC1_XGMAC_SEG_NUM,
-				sizeof(struct mpi_coredump_segment_header)
-				+ sizeof(mpi_coredump->xgmac1),
-				"NIC core XGMAC Registers port 1");
-	status = ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac1[0]);
-	if (status)
-		goto err;
-
 	/* Segment 31 */
 	/* Get indexed register values. */
 	ql_build_coredump_seg_header(&mpi_coredump->intr_states_seg_hdr,
@@ -941,6 +1329,20 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
 				"MAC Prot Regs");
 	ql_get_mac_protocol_registers(qdev, &mpi_coredump->mac_prot_regs[0]);
 
+	/* Get the semaphore registers for all 5 functions */
+	ql_build_coredump_seg_header(&mpi_coredump->sem_regs_seg_hdr,
+			SEM_REGS_SEG_NUM,
+			sizeof(struct mpi_coredump_segment_header) +
+			sizeof(mpi_coredump->sem_regs),	"Sem Registers");
+
+	for(func_num = 0; func_num < MAX_SEMAPHORE_FUNCTIONS ; func_num ++) {
+		reg = REG_BLOCK | (func_num << FUNCTION_SHIFT) | (SEM / 4);
+		status = ql_read_mpi_reg(qdev, reg, &reg_val);
+		mpi_coredump->sem_regs[func_num] = reg_val;
+		if (status != 0)
+			mpi_coredump->sem_regs[func_num] = 0xdeadbeef;
+	}
+
 	/* not in the spec... but we need to prevent the mpi restarting
 	 * while we dump the memory
 	 */
@@ -975,6 +1377,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
 		goto err;
 	}
 
+	/* Insert the segment header */
 	ql_build_coredump_seg_header(&mpi_coredump->memc_ram_seg_hdr,
 				MEMC_RAM_SEG_NUM,
 				sizeof(struct mpi_coredump_segment_header)
@@ -998,24 +1401,6 @@ static void ql_gen_reg_dump(struct ql_adapter *qdev,
 {
 	int i;
 
-	memset(mpi_coredump, 0, sizeof(struct ql_mpi_coredump));
-	/* Fill in the global dump header. */
-	memset(&(mpi_coredump->mpi_global_header), 0,
-		sizeof(struct mpi_coredump_global_header));
-	mpi_coredump->mpi_global_header.cookie = MPI_COREDUMP_COOKIE;
-	mpi_coredump->mpi_global_header.headerSize =
-		sizeof(struct mpi_coredump_global_header);
-	mpi_coredump->mpi_global_header.imageSize =
-		sizeof(struct ql_mpi_coredump);
-	memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
-		sizeof(mpi_coredump->mpi_global_header.idString));
-
-	/* Fill in the generic dump segment header. */
-	ql_build_coredump_seg_header(&mpi_coredump->nic_regs_seg_hdr,
-				NIC1_CONTROL_SEG_NUM,
-				sizeof(struct mpi_coredump_segment_header)
-				+ sizeof(mpi_coredump->nic_regs),
-				"NIC Registers");
 	/* Get generic reg dump */
 	for (i = 0; i < 64; i++)
 		mpi_coredump->nic_regs[i] = ql_read32(qdev, i * sizeof(u32));
@@ -1028,7 +1413,7 @@ void ql_mpi_core_to_log(struct work_struct *work)
 		container_of(work, struct ql_adapter, mpi_core_to_log);
 	u32 *tmp, count;
 	int i;
-
+	
 	count = sizeof(struct ql_mpi_coredump) / sizeof(u32);
 	tmp = (u32 *)qdev->mpi_coredump;
 	QPRINTK(qdev, DRV, DEBUG, "Core is dumping to log file!\n");
@@ -1044,7 +1429,49 @@ void ql_mpi_core_to_log(struct work_struct *work)
 			tmp[i + 5],
 			tmp[i + 6],
 			tmp[i + 7]);
-		msleep(10);
+		msleep(5);
+	}
+}
+
+static int ql_get_core_dump(struct ql_adapter *qdev)
+{
+	int count = 10;
+	
+	if (!ql_own_firmware(qdev)) {
+		QPRINTK(qdev, DRV, ERR, "%s: Don't own firmware!\n",
+					qdev->ndev->name);
+		return -EINVAL;
+	}
+	if (!netif_running(qdev->ndev)){
+		QPRINTK(qdev, IFUP, ERR,
+			"Force Coredump can only be done from interface "
+			"that is up.\n");
+		return -EINVAL;
+	}
+	if(ql_mb_sys_err(qdev)) {
+		QPRINTK(qdev, IFUP, ERR,
+			"Fail force coredump with ql_mb_sys_err().\n");
+		return -EINVAL;
+	}
+
+	/* Wait for core dump to complete. */
+	do {
+		ssleep(1);
+		QPRINTK_DBG(qdev, IFUP, ERR,
+			"Waiting for force Coredump to complete.\n");
+		if (qdev->core_is_dumped)
+			break;
+		count--;
+	} while (count);
+
+	if (!count) {
+		QPRINTK(qdev, IFUP, ERR, "Force Coredump timed out.\n");
+		return -EINVAL;
+	} else {
+		QPRINTK(qdev, IFUP, ERR,
+			"Force Coredump done, starting spool to log.\n");
+		set_bit(QL_SPOOL_LOG, &qdev->flags);
+		return 0;
 	}
 }
 
@@ -1052,15 +1479,13 @@ void ql_get_dump(struct ql_adapter *qdev, void *buff)
 {
 	/*
 	 * If the dump has already been taken and is stored
-	 * in our internal buffer, then just copy it to
-	 * the user's buffer.  Otherwise, take a snapshot
-	 * of the general regs.
+	 * n our internal buffer, then just start the spool to
+	 * dump it to the log file and also, take a snapshot
+	 * of the general regs to the user's buffer.
 	 */
-	if (qdev->core_is_dumped && qdev->mpi_coredump)
-		memcpy(buff, qdev->mpi_coredump,
-			sizeof(struct ql_mpi_coredump));
-	else
-		ql_gen_reg_dump(qdev, buff);
+	if (test_bit(QL_SPOOL_LOG, &qdev->flags))
+		ql_get_core_dump(qdev);
+	ql_gen_reg_dump(qdev, buff);
 }
 
 #ifdef QL_REG_DUMP
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index fcde5cc..ebc0a4a 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -142,6 +142,41 @@ static void ql_update_stats(struct ql_adapter *qdev)
 		iter++;
 	}
 
+	/*
+	 * Get Per-priority TX pause frame counter statistics.
+	 */
+	for (i = 0x500; i < 0x540; i += 8) {
+		if (ql_read_xgmac_reg64(qdev, i, &data)) {
+			QPRINTK(qdev, DRV, ERR,
+				"Error reading status register 0x%.04x.\n", i);
+			goto end;
+		} else
+			*iter = data;
+		iter++;
+	}
+
+	/*
+	 * Get Per-priority RX pause frame counter statistics.
+	 */
+	for (i = 0x568; i < 0x5a8; i += 8) {
+		if (ql_read_xgmac_reg64(qdev, i, &data)) {
+			QPRINTK(qdev, DRV, ERR,
+				"Error reading status register 0x%.04x.\n", i);
+			goto end;
+		} else
+			*iter = data;
+		iter++;
+	}
+
+	/*
+	 * Get RX NIC FIFO DROP statistics.
+	 */
+	if (ql_read_xgmac_reg64(qdev, 0x5b8, &data)) {
+		QPRINTK(qdev, DRV, ERR,
+			"Error reading status register 0x%.04x.\n", i);
+		goto end;
+	} else
+		*iter = data;
 end:
 	ql_sem_unlock(qdev, qdev->xg_sem_mask);
 quit:
@@ -195,6 +230,23 @@ static char ql_stats_str_arr[][ETH_GSTRING_LEN] = {
 	{"rx_1024_to_1518_pkts"},
 	{"rx_1519_to_max_pkts"},
 	{"rx_len_err_pkts"},
+	{"tx_cbfc_pause_frames0"},
+	{"tx_cbfc_pause_frames1"},
+	{"tx_cbfc_pause_frames2"},
+	{"tx_cbfc_pause_frames3"},
+	{"tx_cbfc_pause_frames4"},
+	{"tx_cbfc_pause_frames5"},
+	{"tx_cbfc_pause_frames6"},
+	{"tx_cbfc_pause_frames7"},
+	{"rx_cbfc_pause_frames0"},
+	{"rx_cbfc_pause_frames1"},
+	{"rx_cbfc_pause_frames2"},
+	{"rx_cbfc_pause_frames3"},
+	{"rx_cbfc_pause_frames4"},
+	{"rx_cbfc_pause_frames5"},
+	{"rx_cbfc_pause_frames6"},
+	{"rx_cbfc_pause_frames7"},
+	{"rx_nic_fifo_drop"},
 };
 
 static void ql_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
@@ -267,6 +319,23 @@ ql_get_ethtool_stats(struct net_device *ndev,
 	*data++ = s->rx_1024_to_1518_pkts;
 	*data++ = s->rx_1519_to_max_pkts;
 	*data++ = s->rx_len_err_pkts;
+	*data++ = s->tx_cbfc_pause_frames0;
+	*data++ = s->tx_cbfc_pause_frames1;
+	*data++ = s->tx_cbfc_pause_frames2;
+	*data++ = s->tx_cbfc_pause_frames3;
+	*data++ = s->tx_cbfc_pause_frames4;
+	*data++ = s->tx_cbfc_pause_frames5;
+	*data++ = s->tx_cbfc_pause_frames6;
+	*data++ = s->tx_cbfc_pause_frames7;
+	*data++ = s->rx_cbfc_pause_frames0;
+	*data++ = s->rx_cbfc_pause_frames1;
+	*data++ = s->rx_cbfc_pause_frames2;
+	*data++ = s->rx_cbfc_pause_frames3;
+	*data++ = s->rx_cbfc_pause_frames4;
+	*data++ = s->rx_cbfc_pause_frames5;
+	*data++ = s->rx_cbfc_pause_frames6;
+	*data++ = s->rx_cbfc_pause_frames7;
+	*data++ = s->rx_nic_fifo_drop;
 }
 
 static int ql_get_settings(struct net_device *ndev,
@@ -308,7 +377,7 @@ static void ql_get_drvinfo(struct net_device *ndev,
 	strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
 	drvinfo->n_stats = ARRAY_SIZE(ql_stats_str_arr);
 	drvinfo->testinfo_len = QLGE_TEST_LEN;
-	drvinfo->regdump_len = sizeof(struct ql_mpi_coredump);
+	drvinfo->regdump_len = 1 * 512;
 	drvinfo->eedump_len = 0;
 }
 
@@ -330,32 +399,12 @@ static int ql_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
 		return -EINVAL;
 	qdev->wol = wol->wolopts;
 
-	QPRINTK(qdev, DRV, DEBUG, "Set wol option 0x%x on %s\n",
+	QPRINTK(qdev, DRV, INFO, "Set wol option 0x%x on %s\n",
 			 qdev->wol, ndev->name);
 	if (!qdev->wol) {
 		u32 wol = 0;
-		u8 zero_mac_addr[6];
-
-		memset(zero_mac_addr, 0, sizeof(zero_mac_addr));
-		/* Disable WOL does not work,
-		 * so enable WOL with Invalid mac address
-		 */
-		status = ql_mb_wol_set_magic(qdev, 0);
-		if (status) {
-			QPRINTK(qdev, IFDOWN, ERR,
-				"Failed to clear magic packet on %s\n",
-				qdev->ndev->name);
-			return status;
-		} else
-			QPRINTK(qdev, DRV, INFO,
-				"Cleared magic packet successfully on %s!\n",
-				qdev->ndev->name);
-
-		wol |= MB_WOL_MAGIC_PKT;
-		wol |= MB_WOL_MODE_ON;
 		status = ql_mb_wol_mode(qdev, wol);
-
-		QPRINTK(qdev, DRV, DEBUG, "WOL %s (wol code 0x%x) on %s\n",
+		QPRINTK(qdev, DRV, ERR, "WOL %s (wol code 0x%x) on %s\n",
 			(status == 0) ? "cleared sucessfully" : "clear failed",
 			wol, qdev->ndev->name);
 	}
@@ -398,8 +447,11 @@ static int ql_setup_loopback_test(struct ql_adapter *qdev)
 	if (status)
 		return status;
 	qdev->link_config |= CFG_LOOPBACK_PCS;
-	if (netif_carrier_ok(qdev->ndev))
+	if (netif_carrier_ok(qdev->ndev)) {
+		set_bit(QL_LINK_UP, &qdev->flags);
 		netif_carrier_off(qdev->ndev);
+	} else 
+		clear_bit(QL_LINK_UP, &qdev->flags);
 
 	status = ql_mb_set_port_cfg(qdev);
 	if (status)
@@ -410,7 +462,7 @@ void ql_loopback_cleanup(struct ql_adapter *qdev)
 {
 	qdev->link_config &= ~CFG_LOOPBACK_PCS;
 	ql_mb_set_port_cfg(qdev);
-	if (!netif_carrier_ok(qdev->ndev))
+	if (test_bit(QL_LINK_UP, &qdev->flags))
 		netif_carrier_on(qdev->ndev);
 
 }
@@ -525,7 +577,7 @@ static void ql_self_test(struct net_device *ndev,
 
 static int ql_get_regs_len(struct net_device *ndev)
 {
-	return sizeof(struct ql_mpi_coredump);
+	return 1 * 512;
 }
 
 static void ql_get_regs(struct net_device *ndev,
@@ -535,7 +587,7 @@ static void ql_get_regs(struct net_device *ndev,
 
 	ql_get_dump(qdev, p);
 	qdev->core_is_dumped = 0;
-	regs->len = sizeof(struct ql_mpi_coredump);
+	regs->len = 1 * 512;
 }
 
 
@@ -592,6 +644,37 @@ static int ql_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *c)
 	return ql_update_ring_coalescing(qdev);
 }
 
+static void ql_get_pauseparam(struct net_device *netdev,
+			struct ethtool_pauseparam *pause)
+{
+	struct ql_adapter *qdev = netdev_priv(netdev);
+	
+	ql_mb_get_port_cfg(qdev);
+	if (qdev->link_config & CFG_PAUSE_STD) {
+		pause->rx_pause = 1;
+		pause->tx_pause = 1;
+	}
+}
+
+static int ql_set_pauseparam(struct net_device *netdev,
+			struct ethtool_pauseparam *pause)
+{
+	struct ql_adapter *qdev = netdev_priv(netdev);
+	int status = 0;
+	
+	if ((pause->rx_pause) || (pause->tx_pause))
+		qdev->link_config |= CFG_PAUSE_STD;
+	else if (!(pause->rx_pause && pause->tx_pause))
+		qdev->link_config &= ~CFG_PAUSE_STD;
+	else
+		return -EINVAL;
+	
+	status = ql_mb_set_port_cfg(qdev);
+	if (status)
+		return status;
+	return status;
+}
+
 static u32 ql_get_rx_csum(struct net_device *netdev)
 {
 	struct ql_adapter *qdev = netdev_priv(netdev);
@@ -661,6 +744,8 @@ struct ethtool_ops qlge_ethtool_ops = {
 	.phys_id		 = ql_phys_id,
 	.self_test_count	 = ql_self_test_count,
 	.self_test		 = ql_self_test,
+	.get_pauseparam		 = ql_get_pauseparam,
+	.set_pauseparam		 = ql_set_pauseparam,
 	.get_rx_csum		 = ql_get_rx_csum,
 	.set_rx_csum		 = ql_set_rx_csum,
 	.get_tx_csum		 = ql_get_tx_csum,
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 274440f..7a5698b 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -82,6 +82,12 @@ MODULE_PARM_DESC(qlge_spool_coredump,
 		"Option to enable spooling of firmware dump. "
 		"to log. Default is 0 - do not spool.");
 
+static int qlge_receive_routing = 1;
+module_param(qlge_receive_routing, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(qlge_receive_routing,
+		"Option to Set/Clear receive routing bit. "
+		"Default is 1 - set receive routing.");
+
 static struct pci_device_id qlge_pci_tbl[] __devinitdata = {
 		{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)},
 		{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)},
@@ -271,8 +277,15 @@ void ql_link_on(struct ql_adapter *qdev)
 				qdev->ndev->name);
 			return;
 		}
+		
+		/* Using the current mac address when link up */
 		spin_lock_irqsave(&qdev->hw_lock, hw_flags);
-		if (ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->dev_addr,
+		QPRINTK_DBG(qdev, DRV, ERR,
+		"Current mac addr %02x:%02x:%02x:%02x:%02x:%02x\n",
+		qdev->current_mac_addr[0], qdev->current_mac_addr[1], qdev->current_mac_addr[2],
+		qdev->current_mac_addr[3], qdev->current_mac_addr[4], qdev->current_mac_addr[5]);
+
+		if (ql_set_mac_addr_reg(qdev, (u8 *) qdev->current_mac_addr,
 				MAC_ADDR_TYPE_CAM_MAC, qdev->func*MAX_CQ)) {
 			QPRINTK(qdev, IFUP, ERR,
 					"Failed to restore mac address.\n");
@@ -392,6 +405,37 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
 
 	switch (type) {
 	case MAC_ADDR_TYPE_MULTI_MAC:
+		{
+			u32 upper = (addr[0] << 8) | addr[1];
+			u32 lower = (addr[2] << 24) | (addr[3] << 16) |
+					(addr[4] << 8) | (addr[5]);
+
+			status =
+				ql_wait_reg_rdy(qdev,
+				MAC_ADDR_IDX, MAC_ADDR_MW, 0);
+			if (status)
+				goto exit;
+			ql_write32(qdev, MAC_ADDR_IDX, (offset++) |
+				(index << MAC_ADDR_IDX_SHIFT) |
+				type | MAC_ADDR_E);
+			ql_write32(qdev, MAC_ADDR_DATA, lower);
+			status =
+				ql_wait_reg_rdy(qdev,
+				MAC_ADDR_IDX, MAC_ADDR_MW, 0);
+			if (status)
+				goto exit;
+			ql_write32(qdev, MAC_ADDR_IDX, (offset++) |
+				(index << MAC_ADDR_IDX_SHIFT) |
+				type | MAC_ADDR_E);
+
+			ql_write32(qdev, MAC_ADDR_DATA, upper);
+			status =
+				ql_wait_reg_rdy(qdev,
+				MAC_ADDR_IDX, MAC_ADDR_MW, 0);
+			if (status)
+				goto exit;
+			break;
+		}
 	case MAC_ADDR_TYPE_CAM_MAC:
 		{
 			u32 cam_output;
@@ -435,15 +479,13 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
 			 * and possibly the function id.  Right now we hardcode
 			 * the route field to NIC core.
 			 */
-			if (type == MAC_ADDR_TYPE_CAM_MAC) {
-				cam_output = (CAM_OUT_ROUTE_NIC |
+			cam_output = (CAM_OUT_ROUTE_NIC |
 					(qdev->func << CAM_OUT_FUNC_SHIFT) |
 					(0 << CAM_OUT_CQ_ID_SHIFT));
-				if (qdev->vlgrp)
-					cam_output |= CAM_OUT_RV;
-				/* route to NIC core */
-				ql_write32(qdev, MAC_ADDR_DATA, cam_output);
-			}
+			if (qdev->vlgrp)
+				cam_output |= CAM_OUT_RV;
+			/* route to NIC core */
+			ql_write32(qdev, MAC_ADDR_DATA, cam_output);
 			break;
 		}
 	case MAC_ADDR_TYPE_VLAN:
@@ -569,7 +611,7 @@ static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask,
 		}
 	case RT_IDX_MCAST:	/* Pass up All Multicast frames. */
 		{
-			value = RT_IDX_DST_CAM_Q | /* dest */
+			value = RT_IDX_DST_DFLT_Q | /* dest */
 				RT_IDX_TYPE_NICQ | /* type */
 				(RT_IDX_ALLMULTI_SLOT <<
 				RT_IDX_IDX_SHIFT); /* index */
@@ -577,7 +619,7 @@ static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask,
 		}
 	case RT_IDX_MCAST_MATCH:	/* Pass up matched Multicast frames. */
 		{
-			value = RT_IDX_DST_CAM_Q | /* dest */
+			value = RT_IDX_DST_DFLT_Q | /* dest */
 				RT_IDX_TYPE_NICQ | /* type */
 				(RT_IDX_MCAST_MATCH_SLOT <<
 				RT_IDX_IDX_SHIFT); /* index */
@@ -696,6 +738,21 @@ static void ql_enable_all_completion_interrupts(struct ql_adapter *qdev)
 	}
 }
 
+/* link state work function. Delaying link up by 2 second because
+ * of bonding mode (tlb/alb) modifies the mac addresses. 
+ */
+static void ql_link_work(struct work_struct *work)
+{
+	struct ql_adapter *qdev = 
+			container_of(work, struct ql_adapter, link_work);
+	
+	if ((ql_read32(qdev, STS) & qdev->port_init) &&
+			(ql_read32(qdev, STS) & qdev->port_link_up))
+		ql_link_on(qdev);
+
+	return;
+}
+
 static int ql_validate_flash(struct ql_adapter *qdev, u32 size, const char *str)
 {
 	int status, i;
@@ -3370,6 +3427,15 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
 		FSC_DBL_MASK | FSC_DBRST_MASK | (value << 16);
 	ql_write32(qdev, FSC, mask | value);
 
+	/* Set Receive Routing bit in reset/failover register to use function
+	 * number and CQ from CAM lookup
+	 */
+	if (qlge_receive_routing)
+		value = RST_FO_RR_RCV_FUNC_CQ;
+	else
+		value = 0;
+	ql_write32(qdev, RST_FO, RST_FO_RR_MASK | value);
+
 	/* Reroute all packets to our Interface.
 	 * They may have been routed to MPI firmware
 	 * due to WOL.
@@ -3382,6 +3448,11 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
 	ql_write32(qdev, MGMT_RCV_CFG, mask);
 	ql_write32(qdev, MGMT_RCV_CFG, mask | value);
 
+	/* Default WOL is enable on Mezz cards */
+	if (qdev->pdev->subsystem_device == 0x0068 ||
+			qdev->pdev->subsystem_device == 0x0180 )
+		qdev->wol = WAKE_MAGIC;
+
 	/* Start up the rx queues. */
 	for (i = 0; i < qdev->rx_ring_count; i++) {
 		status = ql_start_rx_ring(qdev, &qdev->rx_ring[i]);
@@ -3444,6 +3515,11 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
 		QPRINTK(qdev, IFUP, ERR, "Failed to clear Routing tables.\n");
 		return status;
 	}
+	/* Stop management traffic. */
+	ql_mb_set_mgmnt_traffic_ctl(qdev, MB_SET_MPI_TFK_STOP);
+
+	/* Wait for the NIC and MGMNT FIFOs to empty. */
+	ql_wait_fifo_empty(qdev);
 
 	ql_write32(qdev, RST_FO, (RST_FO_FR << 16) | RST_FO_FR);
 
@@ -3460,7 +3536,8 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
 			"ETIMEOUT!!! errored out of resetting the chip!\n");
 		status = -ETIMEDOUT;
 	}
-
+	/* Resume management traffic. */
+	ql_mb_set_mgmnt_traffic_ctl(qdev, MB_SET_MPI_TFK_RESUME);
 	return status;
 }
 
@@ -3487,10 +3564,12 @@ int ql_wol(struct ql_adapter *qdev)
 	 * settings.
 	 */
 
-	if (qdev->wol & WAKE_ARP) {
+	if (qdev->wol & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY | WAKE_UCAST |
+			WAKE_MCAST | WAKE_BCAST)) {
 		QPRINTK(qdev, IFDOWN, ERR,
-			"ARP request WOL not support yet.\n");
-		return status;
+			"Unsupported WOL paramter. qdev->wol = 0x%x.\n",
+			qdev->wol);
+		return -EINVAL;
 	}
 
 	if (qdev->wol & WAKE_MAGIC) {
@@ -3508,28 +3587,7 @@ int ql_wol(struct ql_adapter *qdev)
 		wol |= MB_WOL_MAGIC_PKT;
 	}
 
-	if (qdev->wol & WAKE_MAGICSECURE) {
-		QPRINTK(qdev, IFDOWN, ERR,
-			"Secure Magic packet WOL not support yet.\n");
-		return status;
-	}
-
-	if (qdev->wol & WAKE_PHY)
-		wol |= (MB_WOL_LINK_UP | MB_WOL_LINK_DOWN);
-
-	if (qdev->wol & WAKE_UCAST)
-		wol |= MB_WOL_UCAST;
-
-	if (qdev->wol & WAKE_MCAST)
-		wol |= MB_WOL_MCAST;
-
-	if (qdev->wol & WAKE_BCAST)
-		wol |= MB_WOL_BCAST;
-
 	if (qdev->wol) {
-		/* Reroute all packets to Management Interface */
-		ql_write32(qdev, MGMT_RCV_CFG, (MGMT_RCV_CFG_RM |
-			(MGMT_RCV_CFG_RM << 16)));
 		wol |= MB_WOL_MODE_ON;
 		status = ql_mb_wol_mode(qdev, wol);
 		QPRINTK(qdev, DRV, ERR, "WOL %s (wol code 0x%x) on %s\n",
@@ -3577,6 +3635,7 @@ static int ql_adapter_down(struct ql_adapter *qdev)
 	cancel_delayed_work_sync(&qdev->mpi_idc_work);
 	cancel_delayed_work_sync(&qdev->mpi_core_to_log);
 	cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
+	cancel_delayed_work_sync(&qdev->link_work);
 
 	for (i = 0; i < qdev->tx_ring_count; i++)
 		del_timer_sync(&qdev->tx_ring[i].txq_clean_timer);
@@ -3608,9 +3667,10 @@ static int ql_adapter_up(struct ql_adapter *qdev)
 	ql_enable_napi(qdev);
 	ql_alloc_rx_buffers(qdev);
 	ql_enable_all_completion_interrupts(qdev);
-	if ((ql_read32(qdev, STS) & qdev->port_init) &&
-			(ql_read32(qdev, STS) & qdev->port_link_up))
-		ql_link_on(qdev);
+	
+	/* trigger link work function*/
+	queue_delayed_work(qdev->workqueue, &qdev->link_work,
+					msecs_to_jiffies(2000));
 	ql_enable_interrupts(qdev);
 	return 0;
 err_init:
@@ -3993,12 +4053,6 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p)
 	struct sockaddr *addr = p;
 	unsigned long hw_flags = 0;
 	int status;
-	if (netif_running(ndev)) {
-		QPRINTK(qdev, DRV, ERR,
-			"Interface already active, aborting change mac address "
-			"request !!!\n");
-		return -EBUSY;
-	}
 
 	if (!is_valid_ether_addr(addr->sa_data)) {
 		QPRINTK_DBG(qdev, DRV, ERR,
@@ -4027,7 +4081,9 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p)
 		QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n");
 
 	ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
-
+	/* Saving the current mac address */
+	memcpy(qdev->current_mac_addr, ndev->dev_addr, ndev->addr_len);
+		
 	return status;
 }
 
@@ -4266,6 +4322,8 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
 	}
 
 	memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
+	/* Initializing current mac address */
+	memcpy(qdev->current_mac_addr, ndev->dev_addr, ndev->addr_len);
 
 	/* Set up the default ring sizes. */
 	qdev->tx_ring_size = NUM_TX_RING_ENTRIES;
@@ -4289,6 +4347,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
 	INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work);
 	INIT_DELAYED_WORK(&qdev->mpi_core_to_log, ql_mpi_core_to_log);
 	INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work);
+	INIT_DELAYED_WORK(&qdev->link_work, ql_link_work);
 	init_completion(&qdev->ide_completion);
 	mutex_init(&qdev->mpi_mutex);
 
@@ -4414,9 +4473,11 @@ static int __devinit qlge_probe(struct pci_dev *pdev,
 		return err;
 	}
 
+#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 16)) && \
+	(RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(5, 3)))
 	/* Set EEH reset type to fundamental for this device */
 	pdev->fndmntl_rst_rqd = 1;
-
+#endif
 	qdev = netdev_priv(ndev);
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 	ndev->features = (0
@@ -4535,6 +4596,7 @@ static void ql_eeh_close(struct net_device *ndev)
 	cancel_delayed_work_sync(&qdev->mpi_idc_work);
 	cancel_delayed_work_sync(&qdev->mpi_core_to_log);
 	cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
+	cancel_delayed_work_sync(&qdev->link_work);
 
 	for (i = 0; i < qdev->tx_ring_count; i++)
 		del_timer_sync(&qdev->tx_ring[i].txq_clean_timer);
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 056bc91..ba90141 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -104,7 +104,7 @@ static int ql_soft_reset_mpi_risc(struct ql_adapter *qdev)
  * we are the higher function and the lower function
  * is not enabled.
  */
-static int ql_own_firmware(struct ql_adapter *qdev)
+int ql_own_firmware(struct ql_adapter *qdev)
 {
 	u32 temp;
 
@@ -401,6 +401,29 @@ static void ql_init_fw_done(struct ql_adapter *qdev, struct mbox_params *mbcp)
 	}
 }
 
+/* DCBX firmware async event handler */
+static int ql_dcbx_chg(struct ql_adapter *qdev, struct mbox_params *mbcp)
+{
+	int status, i;
+
+	/* Get the status data and start up a thread to
+	 * handle the request.
+	 */
+	mbcp->out_count = 5;
+	status = ql_get_mb_sts(qdev, mbcp);
+	if (status) {
+		QPRINTK(qdev, DRV, ERR,
+			"Could not read MPI regs!\n");
+	} else	{
+		QPRINTK_DBG(qdev, DRV, INFO,
+			"Got DCBX ANE!\n");
+		for (i = 0; i < mbcp->out_count; i++)
+			QPRINTK_DBG(qdev, DRV, ERR, "mbox_out[%d] = 0x%.08x.\n",
+					i, mbcp->mbox_out[i]);
+	}
+	return status;
+}
+
 /* Process an async event and clear it unless it's an
  * error condition.
  *  This can get called iteratively from the mpi_work thread
@@ -524,7 +547,7 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp)
 		break;
 
 	case AEN_DCBX_CHG:
-		/* Need to support AEN 8110 */
+		ql_dcbx_chg(qdev, mbcp); 
 		break;
 	default:
 		QPRINTK(qdev, DRV, ERR,
@@ -548,7 +571,12 @@ end:
  */
 static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp)
 {
-	int status, count;
+	int status, i;
+	unsigned long count;
+
+	for (i = 0; i < mbcp->in_count; i++) 
+		QPRINTK_DBG(qdev, DRV, DEBUG,
+			"mbcp->mbox_in[%d] = 0x%x. \n", i, mbcp->mbox_in[i]);
 
 	mutex_lock(&qdev->mpi_mutex);
 
@@ -557,9 +585,13 @@ static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp)
 
 	/* Load the mailbox registers and wake up MPI RISC. */
 	status = ql_exec_mb_cmd(qdev, mbcp);
-	if (status)
+	if (status) {
+		QPRINTK(qdev, DRV, ERR,
+			"Failed ql_exec_mb_cmd(),"
+			" status = %d.\n",
+			status);
 		goto end;
-
+	}
 
 	/* If we're generating a system error, then there's nothing
 	 * to wait for.
@@ -570,9 +602,9 @@ static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp)
 	/* Wait for the command to complete. We loop
 	 * here because some AEN might arrive while
 	 * we're waiting for the mailbox command to
-	 * complete. If more than 5 arrive then we can
-	 * assume something is wrong. */
-	count = 5;
+	 * complete. No mailbox command should take
+	 * longer than 5 seconds. */
+	count = jiffies + (HZ * 5);
 	do {
 		/* Wait for the interrupt to come in. */
 		status = ql_wait_mbx_cmd_cmplt(qdev);
@@ -605,15 +637,16 @@ static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp)
 					MB_CMD_STS_GOOD) ||
 			((mbcp->mbox_out[0] & 0x0000f000) ==
 					MB_CMD_STS_INTRMDT))
-			break;
-	} while (--count);
+			goto done;
+	} while (time_before(jiffies, count));
 
 	if (!count) {
 		QPRINTK(qdev, DRV, ERR,
-			"Timed out waiting for mailbox complet.\n");
+			"Timed out waiting for mailbox complete.\n");
 		status = -ETIMEDOUT;
 		goto end;
 	}
+done:
 
 	/* Now we can clear the interrupt condition
 	 * and look at our status.
@@ -630,7 +663,9 @@ end:
 	/* End polled mode for MPI */
 	ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
 	mutex_unlock(&qdev->mpi_mutex);
-
+	for (i = 0; i < mbcp->out_count; i++)
+		QPRINTK_DBG(qdev, DRV, DEBUG, "mbox_out[%d] = 0x%.08x.\n",
+				i, mbcp->mbox_out[i]);
 	return status;
 }
 
@@ -824,6 +859,7 @@ int ql_mb_dump_ram(struct ql_adapter *qdev, u64 req_dma, u32 addr,
 	return status;
 }
 
+/* Issue a mailbox command to dump RISC RAM. */
 int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf,
 		u32 ram_addr, int word_count)
 {
@@ -1000,6 +1036,95 @@ int ql_mb_get_led_cfg(struct ql_adapter *qdev)
 	return status;
 }
 
+int ql_mb_set_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 control)
+{
+	struct mbox_params mbc;
+	struct mbox_params *mbcp = &mbc;
+	int status;
+
+	memset(mbcp, 0, sizeof(struct mbox_params));
+
+	mbcp->in_count = 1;
+	mbcp->out_count = 2;
+
+	mbcp->mbox_in[0] = MB_CMD_SET_MGMNT_TFK_CTL;
+	mbcp->mbox_in[1] = control;
+
+	status = ql_mailbox_command(qdev, mbcp);
+	if (status)
+		return status;
+
+	if (mbcp->mbox_out[0] == MB_CMD_STS_GOOD)
+		return status;
+
+	if (mbcp->mbox_out[0] == MB_CMD_STS_INVLD_CMD) {
+		QPRINTK_DBG(qdev, DRV, ERR,
+			"Command not supported by firmware.\n");
+		status = -EINVAL;
+	} else if (mbcp->mbox_out[0] == MB_CMD_STS_ERR) {
+		/* This indicates that the firmware is
+		 * already in the state we are trying to
+		 * change it to.
+		 */
+		QPRINTK_DBG(qdev, DRV, ERR,
+			"Command parameters make no change.\n");
+	}
+	return status;
+}
+
+/* Returns a negative error code or the mailbox command status. */
+static int ql_mb_get_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 *control)
+{
+	struct mbox_params mbc;
+	struct mbox_params *mbcp = &mbc;
+	int status;
+
+	memset(mbcp, 0, sizeof(struct mbox_params));
+	*control = 0;
+
+	mbcp->in_count = 1;
+	mbcp->out_count = 1;
+
+	mbcp->mbox_in[0] = MB_CMD_GET_MGMNT_TFK_CTL;
+
+	status = ql_mailbox_command(qdev, mbcp);
+	if (status)
+		return status;
+
+	if (mbcp->mbox_out[0] == MB_CMD_STS_GOOD) {
+		*control = mbcp->mbox_in[1];
+		return status;
+	}
+
+	if (mbcp->mbox_out[0] == MB_CMD_STS_INVLD_CMD) {
+		QPRINTK_DBG(qdev, DRV, ERR,
+			"Command not supported by firmware.\n");
+		status = -EINVAL;
+	} else if (mbcp->mbox_out[0] == MB_CMD_STS_ERR) {
+		QPRINTK(qdev, DRV, ERR,
+			"Failed to get MPI traffic control.\n");
+		status = -EIO;
+	}
+	return status;
+}
+
+int ql_wait_fifo_empty(struct ql_adapter *qdev)
+{
+	int count = 5;
+	u32 mgmnt_fifo_empty;
+	u32 nic_fifo_empty;
+
+	do {
+		nic_fifo_empty = ql_read32(qdev, STS) & STS_NFE;
+		ql_mb_get_mgmnt_traffic_ctl(qdev, &mgmnt_fifo_empty);
+		mgmnt_fifo_empty &= MB_GET_MPI_TFK_FIFO_EMPTY;
+		if (nic_fifo_empty && mgmnt_fifo_empty)
+			return 0;
+		msleep(100);
+	} while (count-- > 0);
+	return -ETIMEDOUT;
+}
+
 /* API called in work thread context to set new TX/RX
  * maximum frame size values to match MTU.
  */
@@ -1158,6 +1283,7 @@ void ql_mpi_reset_work(struct work_struct *work)
 	cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
 	cancel_delayed_work_sync(&qdev->mpi_core_to_log);
 	cancel_delayed_work_sync(&qdev->mpi_idc_work);
+	cancel_delayed_work_sync(&qdev->link_work);
 
 	/* If we're not the dominant NIC function,
 	 * then there is nothing to do.
@@ -1177,7 +1303,7 @@ void ql_mpi_reset_work(struct work_struct *work)
 		qdev->core_is_dumped = 1;
 		if (test_bit(QL_SPOOL_LOG, &qdev->flags))
 			queue_delayed_work(qdev->workqueue,
-				&qdev->mpi_core_to_log, 0);
+				&qdev->mpi_core_to_log, 5 * HZ); 
 	}
 	ql_soft_reset_mpi_risc(qdev);
 	clear_bit(QL_IN_FW_RST, &qdev->flags);