qlge: Restore promiscuous setting after reset.
[linux-2.6.git] / drivers / net / qlge / qlge_dbg.c
index 1812813..68a1c9b 100644 (file)
@@ -1,3 +1,5 @@
+#include <linux/slab.h>
+
 #include "qlge.h"
 
 /* Read a NIC register from the alternate function. */
@@ -19,6 +21,388 @@ static u32 ql_read_other_func_reg(struct ql_adapter *qdev,
        return reg_val;
 }
 
+/* Write a NIC register from the alternate function. */
+static int ql_write_other_func_reg(struct ql_adapter *qdev,
+                                       u32 reg, u32 reg_val)
+{
+       u32 register_to_read;
+       int status = 0;
+
+       register_to_read = MPI_NIC_REG_BLOCK
+                               | MPI_NIC_READ
+                               | (qdev->alt_func << MPI_NIC_FUNCTION_SHIFT)
+                               | reg;
+       status = ql_write_mpi_reg(qdev, register_to_read, reg_val);
+
+       return status;
+}
+
+static int ql_wait_other_func_reg_rdy(struct ql_adapter *qdev, u32 reg,
+                                       u32 bit, u32 err_bit)
+{
+       u32 temp;
+       int count = 10;
+
+       while (count) {
+               temp = ql_read_other_func_reg(qdev, reg);
+
+               /* check for errors */
+               if (temp & err_bit)
+                       return -1;
+               else if (temp & bit)
+                       return 0;
+               mdelay(10);
+               count--;
+       }
+       return -1;
+}
+
+static int ql_read_other_func_serdes_reg(struct ql_adapter *qdev, u32 reg,
+                                                       u32 *data)
+{
+       int status;
+
+       /* wait for reg to come ready */
+       status = ql_wait_other_func_reg_rdy(qdev, XG_SERDES_ADDR / 4,
+                                               XG_SERDES_ADDR_RDY, 0);
+       if (status)
+               goto exit;
+
+       /* set up for reg read */
+       ql_write_other_func_reg(qdev, XG_SERDES_ADDR/4, reg | PROC_ADDR_R);
+
+       /* wait for reg to come ready */
+       status = ql_wait_other_func_reg_rdy(qdev, XG_SERDES_ADDR / 4,
+                                               XG_SERDES_ADDR_RDY, 0);
+       if (status)
+               goto exit;
+
+       /* get the data */
+       *data = ql_read_other_func_reg(qdev, (XG_SERDES_DATA / 4));
+exit:
+       return status;
+}
+
+/* Read out the SERDES registers */
+static 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;
+}
+
+static void ql_get_both_serdes(struct ql_adapter *qdev, u32 addr,
+                       u32 *direct_ptr, u32 *indirect_ptr,
+                       unsigned int direct_valid, unsigned int indirect_valid)
+{
+       unsigned int status;
+
+       status = 1;
+       if (direct_valid)
+               status = ql_read_serdes_reg(qdev, addr, direct_ptr);
+       /* Dead fill any failures or invalids. */
+       if (status)
+               *direct_ptr = 0xDEADBEEF;
+
+       status = 1;
+       if (indirect_valid)
+               status = ql_read_other_func_serdes_reg(
+                                               qdev, addr, indirect_ptr);
+       /* Dead fill any failures or invalids. */
+       if (status)
+               *indirect_ptr = 0xDEADBEEF;
+}
+
+static int ql_get_serdes_regs(struct ql_adapter *qdev,
+                               struct ql_mpi_coredump *mpi_coredump)
+{
+       int status;
+       unsigned int xfi_direct_valid, xfi_indirect_valid, xaui_direct_valid;
+       unsigned int xaui_indirect_valid, i;
+       u32 *direct_ptr, temp;
+       u32 *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 */
+       if (qdev->func & 1) {
+               /* We are NIC 2 */
+               status = ql_read_other_func_serdes_reg(qdev,
+                               XG_SERDES_XAUI_HSS_PCS_START, &temp);
+               if (status)
+                       temp = XG_SERDES_ADDR_XAUI_PWR_DOWN;
+               if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) ==
+                                       XG_SERDES_ADDR_XAUI_PWR_DOWN)
+                       xaui_indirect_valid = 0;
+
+               status = ql_read_serdes_reg(qdev,
+                               XG_SERDES_XAUI_HSS_PCS_START, &temp);
+               if (status)
+                       temp = XG_SERDES_ADDR_XAUI_PWR_DOWN;
+
+               if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) ==
+                                       XG_SERDES_ADDR_XAUI_PWR_DOWN)
+                       xaui_direct_valid = 0;
+       } else {
+               /* We are NIC 1 */
+               status = ql_read_other_func_serdes_reg(qdev,
+                               XG_SERDES_XAUI_HSS_PCS_START, &temp);
+               if (status)
+                       temp = XG_SERDES_ADDR_XAUI_PWR_DOWN;
+               if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) ==
+                                       XG_SERDES_ADDR_XAUI_PWR_DOWN)
+                       xaui_indirect_valid = 0;
+
+               status = ql_read_serdes_reg(qdev,
+                               XG_SERDES_XAUI_HSS_PCS_START, &temp);
+               if (status)
+                       temp = XG_SERDES_ADDR_XAUI_PWR_DOWN;
+               if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) ==
+                                       XG_SERDES_ADDR_XAUI_PWR_DOWN)
+                       xaui_direct_valid = 0;
+       }
+
+       /*
+        * XFI register is shared so only need to read one
+        * functions and then check the bits.
+        */
+       status = ql_read_serdes_reg(qdev, XG_SERDES_ADDR_STS, &temp);
+       if (status)
+               temp = 0;
+
+       if ((temp & XG_SERDES_ADDR_XFI1_PWR_UP) ==
+                                       XG_SERDES_ADDR_XFI1_PWR_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 & XG_SERDES_ADDR_XFI2_PWR_UP) ==
+                                       XG_SERDES_ADDR_XFI2_PWR_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;
+       }
+
+       /* Get XAUI_AN register block. */
+       if (qdev->func & 1) {
+               /* Function 2 is direct */
+               direct_ptr = mpi_coredump->serdes2_xaui_an;
+               indirect_ptr = mpi_coredump->serdes_xaui_an;
+       } else {
+               /* Function 1 is direct */
+               direct_ptr = mpi_coredump->serdes_xaui_an;
+               indirect_ptr = mpi_coredump->serdes2_xaui_an;
+       }
+
+       for (i = 0; i <= 0x000000034; i += 4, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xaui_direct_valid, xaui_indirect_valid);
+
+       /* Get XAUI_HSS_PCS register block. */
+       if (qdev->func & 1) {
+               direct_ptr =
+                       mpi_coredump->serdes2_xaui_hss_pcs;
+               indirect_ptr =
+                       mpi_coredump->serdes_xaui_hss_pcs;
+       } else {
+               direct_ptr =
+                       mpi_coredump->serdes_xaui_hss_pcs;
+               indirect_ptr =
+                       mpi_coredump->serdes2_xaui_hss_pcs;
+       }
+
+       for (i = 0x800; i <= 0x880; i += 4, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xaui_direct_valid, xaui_indirect_valid);
+
+       /* Get XAUI_XFI_AN register block. */
+       if (qdev->func & 1) {
+               direct_ptr = mpi_coredump->serdes2_xfi_an;
+               indirect_ptr = mpi_coredump->serdes_xfi_an;
+       } else {
+               direct_ptr = mpi_coredump->serdes_xfi_an;
+               indirect_ptr = mpi_coredump->serdes2_xfi_an;
+       }
+
+       for (i = 0x1000; i <= 0x1034; i += 4, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xfi_direct_valid, xfi_indirect_valid);
+
+       /* Get XAUI_XFI_TRAIN register block. */
+       if (qdev->func & 1) {
+               direct_ptr = mpi_coredump->serdes2_xfi_train;
+               indirect_ptr =
+                       mpi_coredump->serdes_xfi_train;
+       } else {
+               direct_ptr = mpi_coredump->serdes_xfi_train;
+               indirect_ptr =
+                       mpi_coredump->serdes2_xfi_train;
+       }
+
+       for (i = 0x1050; i <= 0x107c; i += 4, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xfi_direct_valid, xfi_indirect_valid);
+
+       /* Get XAUI_XFI_HSS_PCS register block. */
+       if (qdev->func & 1) {
+               direct_ptr =
+                       mpi_coredump->serdes2_xfi_hss_pcs;
+               indirect_ptr =
+                       mpi_coredump->serdes_xfi_hss_pcs;
+       } else {
+               direct_ptr =
+                       mpi_coredump->serdes_xfi_hss_pcs;
+               indirect_ptr =
+                       mpi_coredump->serdes2_xfi_hss_pcs;
+       }
+
+       for (i = 0x1800; i <= 0x1838; i += 4, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xfi_direct_valid, xfi_indirect_valid);
+
+       /* Get XAUI_XFI_HSS_TX register block. */
+       if (qdev->func & 1) {
+               direct_ptr =
+                       mpi_coredump->serdes2_xfi_hss_tx;
+               indirect_ptr =
+                       mpi_coredump->serdes_xfi_hss_tx;
+       } else {
+               direct_ptr = mpi_coredump->serdes_xfi_hss_tx;
+               indirect_ptr =
+                       mpi_coredump->serdes2_xfi_hss_tx;
+       }
+       for (i = 0x1c00; i <= 0x1c1f; i++, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xfi_direct_valid, xfi_indirect_valid);
+
+       /* Get XAUI_XFI_HSS_RX register block. */
+       if (qdev->func & 1) {
+               direct_ptr =
+                       mpi_coredump->serdes2_xfi_hss_rx;
+               indirect_ptr =
+                       mpi_coredump->serdes_xfi_hss_rx;
+       } else {
+               direct_ptr = mpi_coredump->serdes_xfi_hss_rx;
+               indirect_ptr =
+                       mpi_coredump->serdes2_xfi_hss_rx;
+       }
+
+       for (i = 0x1c40; i <= 0x1c5f; i++, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xfi_direct_valid, xfi_indirect_valid);
+
+
+       /* Get XAUI_XFI_HSS_PLL register block. */
+       if (qdev->func & 1) {
+               direct_ptr =
+                       mpi_coredump->serdes2_xfi_hss_pll;
+               indirect_ptr =
+                       mpi_coredump->serdes_xfi_hss_pll;
+       } else {
+               direct_ptr =
+                       mpi_coredump->serdes_xfi_hss_pll;
+               indirect_ptr =
+                       mpi_coredump->serdes2_xfi_hss_pll;
+       }
+       for (i = 0x1e00; i <= 0x1e1f; i++, direct_ptr++, indirect_ptr++)
+               ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+                                       xfi_direct_valid, xfi_indirect_valid);
+       return 0;
+}
+
+static int ql_read_other_func_xgmac_reg(struct ql_adapter *qdev, u32 reg,
+                                                       u32 *data)
+{
+       int status = 0;
+
+       /* wait for reg to come ready */
+       status = ql_wait_other_func_reg_rdy(qdev, XGMAC_ADDR / 4,
+                                               XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+       if (status)
+               goto exit;
+
+       /* set up for reg read */
+       ql_write_other_func_reg(qdev, XGMAC_ADDR / 4, reg | XGMAC_ADDR_R);
+
+       /* wait for reg to come ready */
+       status = ql_wait_other_func_reg_rdy(qdev, XGMAC_ADDR / 4,
+                                               XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+       if (status)
+               goto exit;
+
+       /* get the data */
+       *data = ql_read_other_func_reg(qdev, XGMAC_DATA / 4);
+exit:
+       return status;
+}
+
+/* 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_func_xgmac_reg(qdev, i, buf);
+                       else
+                               status = ql_read_xgmac_reg(qdev, i, buf);
+
+                       if (status)
+                               *buf = 0xdeadbeef;
+                       break;
+               }
+       }
+       return status;
+}
+
 static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf)
 {
        int status = 0;
@@ -61,8 +445,8 @@ static int ql_get_cam_entries(struct ql_adapter *qdev, u32 * buf)
                status = ql_get_mac_addr_reg(qdev,
                                        MAC_ADDR_TYPE_CAM_MAC, i, value);
                if (status) {
-                       QPRINTK(qdev, DRV, ERR,
-                               "Failed read of mac index register.\n");
+                       netif_err(qdev, drv, qdev->ndev,
+                                 "Failed read of mac index register.\n");
                        goto err;
                }
                *buf++ = value[0];      /* lower MAC address */
@@ -73,8 +457,8 @@ static int ql_get_cam_entries(struct ql_adapter *qdev, u32 * buf)
                status = ql_get_mac_addr_reg(qdev,
                                        MAC_ADDR_TYPE_MULTI_MAC, i, value);
                if (status) {
-                       QPRINTK(qdev, DRV, ERR,
-                               "Failed read of mac index register.\n");
+                       netif_err(qdev, drv, qdev->ndev,
+                                 "Failed read of mac index register.\n");
                        goto err;
                }
                *buf++ = value[0];      /* lower Mcast address */
@@ -97,8 +481,8 @@ static int ql_get_routing_entries(struct ql_adapter *qdev, u32 * buf)
        for (i = 0; i < 16; i++) {
                status = ql_get_routing_reg(qdev, i, &value);
                if (status) {
-                       QPRINTK(qdev, DRV, ERR,
-                               "Failed read of routing index register.\n");
+                       netif_err(qdev, drv, qdev->ndev,
+                                 "Failed read of routing index register.\n");
                        goto err;
                } else {
                        *buf++ = value;
@@ -354,8 +738,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
        int i;
 
        if (!mpi_coredump) {
-               QPRINTK(qdev, DRV, ERR,
-                       "No memory available.\n");
+               netif_err(qdev, drv, qdev->ndev, "No memory available.\n");
                return -ENOMEM;
        }
 
@@ -367,8 +750,8 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
 
        status = ql_pause_mpi_risc(qdev);
        if (status) {
-               QPRINTK(qdev, DRV, ERR,
-                       "Failed RISC pause. Status = 0x%.08x\n", status);
+               netif_err(qdev, drv, qdev->ndev,
+                         "Failed RISC pause. Status = 0x%.08x\n", status);
                goto err;
        }
 
@@ -394,6 +777,17 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
                        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 < NIC_REGS_DUMP_WORD_COUNT; i++)
@@ -403,6 +797,9 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
                for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++)
                        mpi_coredump->nic_regs[i] =
                        ql_read_other_func_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 < NIC_REGS_DUMP_WORD_COUNT; i++)
@@ -411,6 +808,114 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
                for (i = 0; i < NIC_REGS_DUMP_WORD_COUNT; i++)
                        mpi_coredump->nic2_regs[i] =
                        ql_read_other_func_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) {
+               netif_err(qdev, drv, qdev->ndev,
+                         "Failed Dump of Serdes Registers. Status = 0x%.08x\n",
+                         status);
+               goto err;
        }
 
        ql_build_coredump_seg_header(&mpi_coredump->core_regs_seg_hdr,
@@ -673,16 +1178,16 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
        /* clear the pause */
        status = ql_unpause_mpi_risc(qdev);
        if (status) {
-               QPRINTK(qdev, DRV, ERR,
-                       "Failed RISC unpause. Status = 0x%.08x\n", status);
+               netif_err(qdev, drv, qdev->ndev,
+                         "Failed RISC unpause. Status = 0x%.08x\n", status);
                goto err;
        }
 
        /* Reset the RISC so we can dump RAM */
        status = ql_hard_reset_mpi_risc(qdev);
        if (status) {
-               QPRINTK(qdev, DRV, ERR,
-                       "Failed RISC reset. Status = 0x%.08x\n", status);
+               netif_err(qdev, drv, qdev->ndev,
+                         "Failed RISC reset. Status = 0x%.08x\n", status);
                goto err;
        }
 
@@ -694,8 +1199,9 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
        status = ql_dump_risc_ram_area(qdev, &mpi_coredump->code_ram[0],
                                        CODE_RAM_ADDR, CODE_RAM_CNT);
        if (status) {
-               QPRINTK(qdev, DRV, ERR,
-                       "Failed Dump of CODE RAM. Status = 0x%.08x\n", status);
+               netif_err(qdev, drv, qdev->ndev,
+                         "Failed Dump of CODE RAM. Status = 0x%.08x\n",
+                         status);
                goto err;
        }
 
@@ -708,8 +1214,9 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
        status = ql_dump_risc_ram_area(qdev, &mpi_coredump->memc_ram[0],
                                        MEMC_RAM_ADDR, MEMC_RAM_CNT);
        if (status) {
-               QPRINTK(qdev, DRV, ERR,
-                       "Failed Dump of MEMC RAM. Status = 0x%.08x\n", status);
+               netif_err(qdev, drv, qdev->ndev,
+                         "Failed Dump of MEMC RAM. Status = 0x%.08x\n",
+                         status);
                goto err;
        }
 err:
@@ -718,6 +1225,26 @@ err:
 
 }
 
+static void ql_get_core_dump(struct ql_adapter *qdev)
+{
+       if (!ql_own_firmware(qdev)) {
+               netif_err(qdev, drv, qdev->ndev, "Don't own firmware!\n");
+               return;
+       }
+
+       if (!netif_running(qdev->ndev)) {
+               netif_err(qdev, ifup, qdev->ndev,
+                         "Force Coredump can only be done from interface that is up.\n");
+               return;
+       }
+
+       if (ql_mb_sys_err(qdev)) {
+               netif_err(qdev, ifup, qdev->ndev,
+                         "Fail force coredump with ql_mb_sys_err().\n");
+               return;
+       }
+}
+
 void ql_gen_reg_dump(struct ql_adapter *qdev,
                        struct ql_reg_dump *mpi_coredump)
 {
@@ -793,6 +1320,9 @@ void ql_gen_reg_dump(struct ql_adapter *qdev,
        status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]);
        if (status)
                return;
+
+       if (test_bit(QL_FRC_COREDUMP, &qdev->flags))
+               ql_get_core_dump(qdev);
 }
 
 /* Coredump to messages log file using separate worker thread */
@@ -805,11 +1335,12 @@ void ql_mpi_core_to_log(struct work_struct *work)
 
        count = sizeof(struct ql_mpi_coredump) / sizeof(u32);
        tmp = (u32 *)qdev->mpi_coredump;
-       QPRINTK(qdev, DRV, DEBUG, "Core is dumping to log file!\n");
+       netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev,
+                    "Core is dumping to log file!\n");
 
        for (i = 0; i < count; i += 8) {
                printk(KERN_ERR "%.08x: %.08x %.08x %.08x %.08x %.08x "
-                       "%.08x %.08x %.08x \n", i,
+                       "%.08x %.08x %.08x\n", i,
                        tmp[i + 0],
                        tmp[i + 1],
                        tmp[i + 2],
@@ -1527,7 +2058,7 @@ void ql_dump_ob_mac_iocb(struct ob_mac_iocb_req *ob_mac_iocb)
               ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_LSO ? "LSO" : "",
               ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_UC ? "UC" : "",
               ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_TC ? "TC" : "");
-       printk(KERN_ERR PFX "flags3          = %s %s %s \n",
+       printk(KERN_ERR PFX "flags3          = %s %s %s\n",
               ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_IC ? "IC" : "",
               ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_DFP ? "DFP" : "",
               ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_V ? "V" : "");