]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
netxen: driver update to v4.0.78
authorMaxim Uvarov <maxim.uvarov@oracle.com>
Thu, 10 May 2012 00:41:15 +0000 (17:41 -0700)
committerMaxim Uvarov <maxim.uvarov@oracle.com>
Fri, 11 May 2012 00:08:36 +0000 (17:08 -0700)
Orabug: 14045367
Signed-off-by: Maxim Uvarov <maxim.uvarov@oracle.com>
drivers/net/netxen/netxen_nic.h
drivers/net/netxen/netxen_nic_ctx.c
drivers/net/netxen/netxen_nic_ethtool.c
drivers/net/netxen/netxen_nic_hdr.h
drivers/net/netxen/netxen_nic_hw.c
drivers/net/netxen/netxen_nic_init.c
drivers/net/netxen/netxen_nic_main.c

index a876dffd71011cf59fb195da2343ef2549092b15..a539e28ad847b4ce7a4aaf7d573ecd1e438ac2f3 100644 (file)
 #ifndef _NETXEN_NIC_H_
 #define _NETXEN_NIC_H_
 
+#ifndef SPEED_UNKNOWN
+#define SPEED_UNKNOWN 0x0
+#endif
+
+#ifndef DUPLEX_UNKNOWN
+#define DUPLEX_UNKNOWN 0xff
+#endif
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -53,8 +61,8 @@
 
 #define _NETXEN_NIC_LINUX_MAJOR 4
 #define _NETXEN_NIC_LINUX_MINOR 0
-#define _NETXEN_NIC_LINUX_SUBVERSION 77
-#define NETXEN_NIC_LINUX_VERSIONID  "4.0.77"
+#define _NETXEN_NIC_LINUX_SUBVERSION 78
+#define NETXEN_NIC_LINUX_VERSIONID  "4.0.78"
 
 #define NETXEN_VERSION_CODE(a, b, c)   (((a) << 24) + ((b) << 16) + (c))
 #define _major(v)      (((v) >> 24) & 0xff)
@@ -686,6 +694,18 @@ struct netxen_recv_context {
        dma_addr_t phys_addr;
 };
 
+struct _cdrp_cmd {
+       u32 cmd;
+       u32 arg1;
+       u32 arg2;
+       u32 arg3;
+};
+
+struct netxen_cmd_args {
+       struct _cdrp_cmd req;
+       struct _cdrp_cmd rsp;
+};
+
 /* New HW context creation */
 
 #define NX_OS_CRB_RETRY_COUNT  4000
@@ -1142,6 +1162,7 @@ typedef struct {
 #define NETXEN_NIC_LRO_DISABLED                0x00
 #define NETXEN_NIC_BRIDGE_ENABLED       0X10
 #define NETXEN_NIC_DIAG_ENABLED                0x20
+#define NETXEN_FW_RESET_OWNER           0x40
 #define NETXEN_IS_MSI_FAMILY(adapter) \
        ((adapter)->flags & (NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED))
 
@@ -1159,6 +1180,419 @@ typedef struct {
 #define __NX_DEV_UP                    1
 #define __NX_RESETTING                 2
 
+/* Mini Coredump FW supported version */
+#define NX_MD_SUPPORT_MAJOR            4
+#define NX_MD_SUPPORT_MINOR            0
+#define NX_MD_SUPPORT_SUBVERSION       579
+
+#define LSW(x)  ((uint16_t)(x))
+#define LSD(x)  ((uint32_t)((uint64_t)(x)))
+#define MSD(x)  ((uint32_t)((((uint64_t)(x)) >> 16) >> 16))
+
+/* Mini Coredump mask level */
+#define        NX_DUMP_MASK_MIN        0x03
+#define        NX_DUMP_MASK_DEF        0x1f
+#define        NX_DUMP_MASK_MAX        0xff
+
+/* Mini Coredump CDRP commands */
+#define NX_CDRP_CMD_TEMP_SIZE           0x0000002f
+#define NX_CDRP_CMD_GET_TEMP_HDR        0x00000030
+
+
+#define NX_DUMP_STATE_ARRAY_LEN                16
+#define NX_DUMP_CAP_SIZE_ARRAY_LEN     8
+
+/* Mini Coredump sysfs entries flags*/
+#define NX_FORCE_FW_DUMP_KEY           0xdeadfeed
+#define NX_ENABLE_FW_DUMP               0xaddfeed
+#define NX_DISABLE_FW_DUMP              0xbadfeed
+#define NX_FORCE_FW_RESET               0xdeaddead
+
+
+/* Flash read/write address */
+#define NX_FW_DUMP_REG1         0x00130060
+#define NX_FW_DUMP_REG2         0x001e0000
+#define NX_FLASH_SEM2_LK        0x0013C010
+#define NX_FLASH_SEM2_ULK       0x0013C014
+#define NX_FLASH_LOCK_ID        0x001B2100
+#define FLASH_ROM_WINDOW        0x42110030
+#define FLASH_ROM_DATA          0x42150000
+
+/* Mini Coredump register read/write routine */
+#define NX_RD_DUMP_REG(addr, bar0, data) do {                   \
+       writel((addr & 0xFFFF0000), (void __iomem *) (bar0 +            \
+               NX_FW_DUMP_REG1));                                      \
+       readl((void __iomem *) (bar0 + NX_FW_DUMP_REG1));               \
+       *data = readl((void __iomem *) (bar0 + NX_FW_DUMP_REG2 +        \
+               LSW(addr)));                                            \
+} while (0)
+
+#define NX_WR_DUMP_REG(addr, bar0, data) do {                   \
+       writel((addr & 0xFFFF0000), (void __iomem *) (bar0 +            \
+               NX_FW_DUMP_REG1));                                      \
+       readl((void __iomem *) (bar0 + NX_FW_DUMP_REG1));                \
+       writel(data, (void __iomem *) (bar0 + NX_FW_DUMP_REG2 + LSW(addr)));\
+       readl((void __iomem *) (bar0 + NX_FW_DUMP_REG2 + LSW(addr)));  \
+} while (0)
+
+
+/*
+Entry Type Defines
+*/
+
+#define RDNOP  0
+#define RDCRB  1
+#define RDMUX  2
+#define QUEUE  3
+#define BOARD  4
+#define RDSRE  5
+#define RDOCM  6
+#define PREGS  7
+#define L1DTG  8
+#define L1ITG  9
+#define CACHE  10
+
+#define L1DAT  11
+#define L1INS  12
+#define RDSTK  13
+#define RDCON  14
+
+#define L2DTG  21
+#define L2ITG  22
+#define L2DAT  23
+#define L2INS  24
+#define RDOC3  25
+
+#define MEMBK  32
+
+#define RDROM  71
+#define RDMEM  72
+#define RDMN   73
+
+#define INFOR  81
+#define CNTRL  98
+
+#define TLHDR  99
+#define RDEND  255
+
+#define PRIMQ  103
+#define SQG2Q  104
+#define SQG3Q  105
+
+/*
+* Opcodes for Control Entries.
+* These Flags are bit fields.
+*/
+#define NX_DUMP_WCRB           0x01
+#define NX_DUMP_RWCRB          0x02
+#define NX_DUMP_ANDCRB         0x04
+#define NX_DUMP_ORCRB          0x08
+#define NX_DUMP_POLLCRB                0x10
+#define NX_DUMP_RD_SAVE                0x20
+#define NX_DUMP_WRT_SAVED      0x40
+#define NX_DUMP_MOD_SAVE_ST    0x80
+
+/* Driver Flags */
+#define NX_DUMP_SKIP           0x80    /*  driver skipped this entry  */
+#define NX_DUMP_SIZE_ERR 0x40  /*entry size vs capture size mismatch*/
+
+#define NX_PCI_READ_32(ADDR)                   readl((ADDR))
+#define NX_PCI_WRITE_32(DATA, ADDR)    writel(DATA, (ADDR))
+
+
+
+struct netxen_minidump {
+       u32 pos;                        /* position in the dump buffer */
+       u8  fw_supports_md;             /* FW supports Mini cordump */
+       u8  has_valid_dump;             /* indicates valid dump */
+       u8  md_capture_mask;            /* driver capture mask */
+       u8  md_enabled;                 /* Turn Mini Coredump on/off */
+       u32 md_dump_size;               /* Total FW Mini Coredump size */
+       u32 md_capture_size;            /* FW dump capture size */
+       u32 md_template_size;           /* FW template size */
+       u32 md_template_ver;            /* FW template version */
+       u64 md_timestamp;               /* FW Mini dump timestamp */
+       void *md_template;              /* FW template will be stored */
+       void *md_capture_buff;          /* FW dump will be stored */
+};
+
+
+
+struct netxen_minidump_template_hdr {
+       u32 entry_type;
+       u32 first_entry_offset;
+       u32 size_of_template;
+       u32 capture_mask;
+       u32 num_of_entries;
+       u32 version;
+       u32 driver_timestamp;
+       u32 checksum;
+       u32 driver_capture_mask;
+       u32 driver_info_word2;
+       u32 driver_info_word3;
+       u32 driver_info_word4;
+       u32 saved_state_array[NX_DUMP_STATE_ARRAY_LEN];
+       u32 capture_size_array[NX_DUMP_CAP_SIZE_ARRAY_LEN];
+       u32 rsvd[0];
+};
+
+/* Common Entry Header:  Common to All Entry Types */
+/*
+ * Driver Code is for driver to write some info about the entry.
+ * Currently not used.
+ */
+
+struct netxen_common_entry_hdr {
+       u32 entry_type;
+       u32 entry_size;
+       u32 entry_capture_size;
+       union {
+               struct {
+                       u8 entry_capture_mask;
+                       u8 entry_code;
+                       u8 driver_code;
+                       u8 driver_flags;
+               };
+               u32 entry_ctrl_word;
+       };
+};
+
+
+/* Generic Entry Including Header */
+struct netxen_minidump_entry {
+       struct netxen_common_entry_hdr hdr;
+       u32 entry_data00;
+       u32 entry_data01;
+       u32 entry_data02;
+       u32 entry_data03;
+       u32 entry_data04;
+       u32 entry_data05;
+       u32 entry_data06;
+       u32 entry_data07;
+};
+
+/* Read ROM Header */
+struct netxen_minidump_entry_rdrom {
+       struct netxen_common_entry_hdr h;
+       union {
+               struct {
+                       u32 select_addr_reg;
+               };
+               u32 rsvd_0;
+       };
+       union {
+               struct {
+                       u8 addr_stride;
+                       u8 addr_cnt;
+                       u16 data_size;
+               };
+               u32 rsvd_1;
+       };
+       union {
+               struct {
+                       u32 op_count;
+               };
+               u32 rsvd_2;
+       };
+       union {
+               struct {
+                       u32 read_addr_reg;
+               };
+               u32 rsvd_3;
+       };
+       union {
+               struct {
+                       u32 write_mask;
+               };
+               u32 rsvd_4;
+       };
+       union {
+               struct {
+                       u32 read_mask;
+               };
+               u32 rsvd_5;
+       };
+       u32 read_addr;
+       u32 read_data_size;
+};
+
+
+/* Read CRB and Control Entry Header */
+struct netxen_minidump_entry_crb {
+       struct netxen_common_entry_hdr h;
+       u32 addr;
+       union {
+               struct {
+                       u8 addr_stride;
+                       u8 state_index_a;
+                       u16 poll_timeout;
+                       };
+               u32 addr_cntrl;
+       };
+       u32 data_size;
+       u32 op_count;
+       union {
+               struct {
+                       u8 opcode;
+                       u8 state_index_v;
+                       u8 shl;
+                       u8 shr;
+                       };
+               u32 control_value;
+       };
+       u32 value_1;
+       u32 value_2;
+       u32 value_3;
+};
+
+/* Read Memory and MN Header */
+struct netxen_minidump_entry_rdmem {
+       struct netxen_common_entry_hdr h;
+       union {
+               struct {
+                       u32 select_addr_reg;
+               };
+               u32 rsvd_0;
+       };
+       union {
+               struct {
+                       u8 addr_stride;
+                       u8 addr_cnt;
+                       u16 data_size;
+               };
+               u32 rsvd_1;
+       };
+       union {
+               struct {
+                       u32 op_count;
+               };
+               u32 rsvd_2;
+       };
+       union {
+               struct {
+                       u32 read_addr_reg;
+               };
+               u32 rsvd_3;
+       };
+       union {
+               struct {
+                       u32 cntrl_addr_reg;
+               };
+               u32 rsvd_4;
+       };
+       union {
+               struct {
+                       u8 wr_byte0;
+                       u8 wr_byte1;
+                       u8 poll_mask;
+                       u8 poll_cnt;
+               };
+               u32 rsvd_5;
+       };
+       u32 read_addr;
+       u32 read_data_size;
+};
+
+/* Read Cache L1 and L2 Header */
+struct netxen_minidump_entry_cache {
+       struct netxen_common_entry_hdr h;
+       u32 tag_reg_addr;
+       union {
+               struct {
+                       u16 tag_value_stride;
+                       u16 init_tag_value;
+               };
+               u32 select_addr_cntrl;
+       };
+       u32 data_size;
+       u32 op_count;
+       u32 control_addr;
+       union {
+               struct {
+                       u16 write_value;
+                       u8 poll_mask;
+                       u8 poll_wait;
+               };
+               u32 control_value;
+       };
+       u32 read_addr;
+       union {
+               struct {
+                       u8 read_addr_stride;
+                       u8 read_addr_cnt;
+                       u16 rsvd_1;
+               };
+               u32 read_addr_cntrl;
+       };
+};
+
+/* Read OCM Header */
+struct netxen_minidump_entry_rdocm {
+       struct netxen_common_entry_hdr h;
+       u32 rsvd_0;
+       union {
+               struct {
+                       u32 rsvd_1;
+               };
+               u32 select_addr_cntrl;
+       };
+       u32 data_size;
+       u32 op_count;
+       u32 rsvd_2;
+       u32 rsvd_3;
+       u32 read_addr;
+       union {
+               struct {
+                       u32 read_addr_stride;
+               };
+               u32 read_addr_cntrl;
+       };
+};
+
+/* Read MUX Header */
+struct netxen_minidump_entry_mux {
+       struct netxen_common_entry_hdr h;
+       u32 select_addr;
+       union {
+               struct {
+                       u32 rsvd_0;
+               };
+               u32 select_addr_cntrl;
+       };
+       u32 data_size;
+       u32 op_count;
+       u32 select_value;
+       u32 select_value_stride;
+       u32 read_addr;
+       u32 rsvd_1;
+};
+
+/* Read Queue Header */
+struct netxen_minidump_entry_queue {
+       struct netxen_common_entry_hdr h;
+       u32 select_addr;
+       union {
+               struct {
+                       u16 queue_id_stride;
+                       u16 rsvd_0;
+               };
+               u32 select_addr_cntrl;
+       };
+       u32 data_size;
+       u32 op_count;
+       u32 rsvd_1;
+       u32 rsvd_2;
+       u32 read_addr;
+       union {
+               struct {
+                       u8 read_addr_stride;
+                       u8 read_addr_cnt;
+                       u16 rsvd_3;
+               };
+               u32 read_addr_cntrl;
+       };
+};
+
 struct netxen_dummy_dma {
        void *addr;
        dma_addr_t phys_addr;
@@ -1263,6 +1697,8 @@ struct netxen_adapter {
        __le32 file_prd_off;    /*File fw product offset*/
        u32 fw_version;
        const struct firmware *fw;
+       struct netxen_minidump mdump;   /* mdump ptr */
+       int fw_mdump_rdy;       /* for mdump ready */
 };
 
 int nx_fw_cmd_query_phy(struct netxen_adapter *adapter, u32 reg, u32 *val);
@@ -1365,13 +1801,16 @@ int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu);
 int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable);
 int netxen_config_bridged_mode(struct netxen_adapter *adapter, int enable);
 int netxen_send_lro_cleanup(struct netxen_adapter *adapter);
-
+int netxen_setup_minidump(struct netxen_adapter *adapter);
+void netxen_dump_fw(struct netxen_adapter *adapter);
 void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
                struct nx_host_tx_ring *tx_ring);
 
 /* Functions from netxen_nic_main.c */
 int netxen_nic_reset_context(struct netxen_adapter *);
 
+int nx_dev_request_reset(struct netxen_adapter *adapter);
+
 /*
  * NetXen Board information
  */
index a925392abd6fff5f0d9c77ae859210814f0bde34..f3c0057a802b1464cbfeb65782d01186046ff600 100644 (file)
@@ -48,28 +48,27 @@ netxen_poll_rsp(struct netxen_adapter *adapter)
 }
 
 static u32
-netxen_issue_cmd(struct netxen_adapter *adapter,
-       u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd)
+netxen_issue_cmd(struct netxen_adapter *adapter, struct netxen_cmd_args *cmd)
 {
        u32 rsp;
        u32 signature = 0;
        u32 rcode = NX_RCODE_SUCCESS;
 
-       signature = NX_CDRP_SIGNATURE_MAKE(pci_fn, version);
-
+       signature = NX_CDRP_SIGNATURE_MAKE(adapter->ahw.pci_func,
+                                               NXHAL_VERSION);
        /* Acquire semaphore before accessing CRB */
        if (netxen_api_lock(adapter))
                return NX_RCODE_TIMEOUT;
 
        NXWR32(adapter, NX_SIGN_CRB_OFFSET, signature);
 
-       NXWR32(adapter, NX_ARG1_CRB_OFFSET, arg1);
+       NXWR32(adapter, NX_ARG1_CRB_OFFSET, cmd->req.arg1);
 
-       NXWR32(adapter, NX_ARG2_CRB_OFFSET, arg2);
+       NXWR32(adapter, NX_ARG2_CRB_OFFSET, cmd->req.arg2);
 
-       NXWR32(adapter, NX_ARG3_CRB_OFFSET, arg3);
+       NXWR32(adapter, NX_ARG3_CRB_OFFSET, cmd->req.arg3);
 
-       NXWR32(adapter, NX_CDRP_CRB_OFFSET, NX_CDRP_FORM_CMD(cmd));
+       NXWR32(adapter, NX_CDRP_CRB_OFFSET, NX_CDRP_FORM_CMD(cmd->req.cmd));
 
        rsp = netxen_poll_rsp(adapter);
 
@@ -83,28 +82,179 @@ netxen_issue_cmd(struct netxen_adapter *adapter,
 
                printk(KERN_ERR "%s: failed card response code:0x%x\n",
                                netxen_nic_driver_name, rcode);
+       } else if (rsp == NX_CDRP_RSP_OK) {
+               cmd->rsp.cmd = NX_RCODE_SUCCESS;
+               if (cmd->rsp.arg2)
+                       cmd->rsp.arg2 = NXRD32(adapter, NX_ARG2_CRB_OFFSET);
+               if (cmd->rsp.arg3)
+                       cmd->rsp.arg3 = NXRD32(adapter, NX_ARG3_CRB_OFFSET);
        }
 
+       if (cmd->rsp.arg1)
+               cmd->rsp.arg1 = NXRD32(adapter, NX_ARG1_CRB_OFFSET);
        /* Release semaphore */
        netxen_api_unlock(adapter);
 
        return rcode;
 }
 
+static int
+netxen_get_minidump_template_size(struct netxen_adapter *adapter)
+{
+       struct netxen_cmd_args cmd;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.req.cmd = NX_CDRP_CMD_TEMP_SIZE;
+       memset(&cmd.rsp, 1, sizeof(struct _cdrp_cmd));
+       netxen_issue_cmd(adapter, &cmd);
+       if (cmd.rsp.cmd != NX_RCODE_SUCCESS) {
+               dev_info(&adapter->pdev->dev,
+                       "Can't get template size %d\n", cmd.rsp.cmd);
+               return -EIO;
+       }
+       adapter->mdump.md_template_size = cmd.rsp.arg2;
+       adapter->mdump.md_template_ver = cmd.rsp.arg3;
+       return 0;
+}
+
+static int
+netxen_get_minidump_template(struct netxen_adapter *adapter)
+{
+       dma_addr_t md_template_addr;
+       void *addr;
+       u32 size;
+       struct netxen_cmd_args cmd;
+       size = adapter->mdump.md_template_size;
+
+       if (size == 0) {
+               dev_err(&adapter->pdev->dev, "Can not capture Minidump "
+                       "template. Invalid template size.\n");
+               return NX_RCODE_INVALID_ARGS;
+       }
+
+       addr = pci_alloc_consistent(adapter->pdev, size, &md_template_addr);
+
+       if (!addr) {
+               dev_err(&adapter->pdev->dev, "Unable to allocate dmable memory for template.\n");
+               return -ENOMEM;
+       }
+
+       memset(addr, 0, size);
+       memset(&cmd, 0, sizeof(cmd));
+       memset(&cmd.rsp, 1, sizeof(struct _cdrp_cmd));
+       cmd.req.cmd = NX_CDRP_CMD_GET_TEMP_HDR;
+       cmd.req.arg1 = LSD(md_template_addr);
+       cmd.req.arg2 = MSD(md_template_addr);
+       cmd.req.arg3 |= size;
+       netxen_issue_cmd(adapter, &cmd);
+
+       if ((cmd.rsp.cmd == NX_RCODE_SUCCESS) && (size == cmd.rsp.arg2)) {
+               memcpy(adapter->mdump.md_template, addr, size);
+       } else {
+               dev_err(&adapter->pdev->dev, "Failed to get minidump template, "
+                       "err_code : %d, requested_size : %d, actual_size : %d\n ",
+                       cmd.rsp.cmd, size, cmd.rsp.arg2);
+       }
+       pci_free_consistent(adapter->pdev, size, addr, md_template_addr);
+       return 0;
+}
+
+static u32
+netxen_check_template_checksum(struct netxen_adapter *adapter)
+{
+       u64 sum =  0 ;
+       u32 *buff = adapter->mdump.md_template;
+       int count =  adapter->mdump.md_template_size/sizeof(uint32_t) ;
+
+       while (count-- > 0)
+               sum += *buff++ ;
+       while (sum >> 32)
+               sum = (sum & 0xFFFFFFFF) +  (sum >> 32) ;
+
+       return ~sum;
+}
+
+int
+netxen_setup_minidump(struct netxen_adapter *adapter)
+{
+       int err = 0, i;
+       u32 *template, *tmp_buf;
+       struct netxen_minidump_template_hdr *hdr;
+       err = netxen_get_minidump_template_size(adapter);
+       if (err) {
+               adapter->mdump.fw_supports_md = 0;
+               if ((err == NX_RCODE_CMD_INVALID) ||
+                       (err == NX_RCODE_CMD_NOT_IMPL)) {
+                       dev_info(&adapter->pdev->dev,
+                               "Flashed firmware version does not support minidump, "
+                               "minimum version required is [ %u.%u.%u ].\n ",
+                               NX_MD_SUPPORT_MAJOR, NX_MD_SUPPORT_MINOR,
+                               NX_MD_SUPPORT_SUBVERSION);
+               }
+               return err;
+       }
+
+       if (!adapter->mdump.md_template_size) {
+               dev_err(&adapter->pdev->dev, "Error : Invalid template size "
+               ",should be non-zero.\n");
+               return -EIO;
+       }
+       adapter->mdump.md_template =
+               kmalloc(adapter->mdump.md_template_size, GFP_KERNEL);
+
+       if (!adapter->mdump.md_template) {
+               dev_err(&adapter->pdev->dev, "Unable to allocate memory "
+                       "for minidump template.\n");
+               return -ENOMEM;
+       }
+
+       err = netxen_get_minidump_template(adapter);
+       if (err) {
+               if (err == NX_RCODE_CMD_NOT_IMPL)
+                       adapter->mdump.fw_supports_md = 0;
+               goto free_template;
+       }
+
+       if (netxen_check_template_checksum(adapter)) {
+               dev_err(&adapter->pdev->dev, "Minidump template checksum Error\n");
+               err = -EIO;
+               goto free_template;
+       }
+
+       adapter->mdump.md_capture_mask = NX_DUMP_MASK_DEF;
+       tmp_buf = (u32 *) adapter->mdump.md_template;
+       template = (u32 *) adapter->mdump.md_template;
+       for (i = 0; i < adapter->mdump.md_template_size/sizeof(u32); i++)
+               *template++ = __le32_to_cpu(*tmp_buf++);
+       hdr = (struct netxen_minidump_template_hdr *)
+                               adapter->mdump.md_template;
+       adapter->mdump.md_capture_buff = NULL;
+       adapter->mdump.fw_supports_md = 1;
+       adapter->mdump.md_enabled = 1;
+
+       return err;
+
+free_template:
+       kfree(adapter->mdump.md_template);
+       adapter->mdump.md_template = NULL;
+       return err;
+}
+
+
 int
 nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu)
 {
        u32 rcode = NX_RCODE_SUCCESS;
        struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
+       struct netxen_cmd_args cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.req.cmd = NX_CDRP_CMD_SET_MTU;
+       cmd.req.arg1 = recv_ctx->context_id;
+       cmd.req.arg2 = mtu;
+       cmd.req.arg3 = 0;
 
        if (recv_ctx->state == NX_HOST_CTX_STATE_ACTIVE)
-               rcode = netxen_issue_cmd(adapter,
-                               adapter->ahw.pci_func,
-                               NXHAL_VERSION,
-                               recv_ctx->context_id,
-                               mtu,
-                               0,
-                               NX_CDRP_CMD_SET_MTU);
+               netxen_issue_cmd(adapter, &cmd);
 
        if (rcode != NX_RCODE_SUCCESS)
                return -EIO;
@@ -116,15 +266,14 @@ int
 nx_fw_cmd_set_gbe_port(struct netxen_adapter *adapter,
                        u32 speed, u32 duplex, u32 autoneg)
 {
-
-       return netxen_issue_cmd(adapter,
-                               adapter->ahw.pci_func,
-                               NXHAL_VERSION,
-                               speed,
-                               duplex,
-                               autoneg,
-                               NX_CDRP_CMD_CONFIG_GBE_PORT);
-
+       struct netxen_cmd_args cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.req.cmd = NX_CDRP_CMD_CONFIG_GBE_PORT;
+       cmd.req.arg1 = speed;
+       cmd.req.arg2 = duplex;
+       cmd.req.arg3 = autoneg;
+       return netxen_issue_cmd(adapter, &cmd);
 }
 
 static int
@@ -139,6 +288,7 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
        nx_cardrsp_sds_ring_t *prsp_sds;
        struct nx_host_rds_ring *rds_ring;
        struct nx_host_sds_ring *sds_ring;
+       struct netxen_cmd_args cmd;
 
        dma_addr_t hostrq_phys_addr, cardrsp_phys_addr;
        u64 phys_addr;
@@ -218,13 +368,12 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
        }
 
        phys_addr = hostrq_phys_addr;
-       err = netxen_issue_cmd(adapter,
-                       adapter->ahw.pci_func,
-                       NXHAL_VERSION,
-                       (u32)(phys_addr >> 32),
-                       (u32)(phys_addr & 0xffffffff),
-                       rq_size,
-                       NX_CDRP_CMD_CREATE_RX_CTX);
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.req.arg1 = (u32)(phys_addr >> 32);
+       cmd.req.arg2 = (u32)(phys_addr & 0xffffffff);
+       cmd.req.arg3 = rq_size;
+       cmd.req.cmd = NX_CDRP_CMD_CREATE_RX_CTX;
+       err = netxen_issue_cmd(adapter, &cmd);
        if (err) {
                printk(KERN_WARNING
                        "Failed to create rx ctx in firmware%d\n", err);
@@ -273,15 +422,15 @@ static void
 nx_fw_cmd_destroy_rx_ctx(struct netxen_adapter *adapter)
 {
        struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
+       struct netxen_cmd_args cmd;
 
-       if (netxen_issue_cmd(adapter,
-                       adapter->ahw.pci_func,
-                       NXHAL_VERSION,
-                       recv_ctx->context_id,
-                       NX_DESTROY_CTX_RESET,
-                       0,
-                       NX_CDRP_CMD_DESTROY_RX_CTX)) {
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.req.arg1 = recv_ctx->context_id;
+       cmd.req.arg2 = NX_DESTROY_CTX_RESET;
+       cmd.req.arg3 = 0;
+       cmd.req.cmd = NX_CDRP_CMD_DESTROY_RX_CTX;
 
+       if (netxen_issue_cmd(adapter, &cmd)) {
                printk(KERN_WARNING
                        "%s: Failed to destroy rx ctx in firmware\n",
                        netxen_nic_driver_name);
@@ -302,6 +451,7 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter)
        dma_addr_t      rq_phys_addr, rsp_phys_addr;
        struct nx_host_tx_ring *tx_ring = adapter->tx_ring;
        struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
+       struct netxen_cmd_args cmd;
 
        rq_size = SIZEOF_HOSTRQ_TX(nx_hostrq_tx_ctx_t);
        rq_addr = pci_alloc_consistent(adapter->pdev,
@@ -345,13 +495,12 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter)
        prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc);
 
        phys_addr = rq_phys_addr;
-       err = netxen_issue_cmd(adapter,
-                       adapter->ahw.pci_func,
-                       NXHAL_VERSION,
-                       (u32)(phys_addr >> 32),
-                       ((u32)phys_addr & 0xffffffff),
-                       rq_size,
-                       NX_CDRP_CMD_CREATE_TX_CTX);
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.req.arg1 = (u32)(phys_addr >> 32);
+       cmd.req.arg2 = ((u32)phys_addr & 0xffffffff);
+       cmd.req.arg3 = rq_size;
+       cmd.req.cmd = NX_CDRP_CMD_CREATE_TX_CTX;
+       err = netxen_issue_cmd(adapter, &cmd);
 
        if (err == NX_RCODE_SUCCESS) {
                temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
@@ -380,14 +529,14 @@ out_free_rq:
 static void
 nx_fw_cmd_destroy_tx_ctx(struct netxen_adapter *adapter)
 {
-       if (netxen_issue_cmd(adapter,
-                       adapter->ahw.pci_func,
-                       NXHAL_VERSION,
-                       adapter->tx_context_id,
-                       NX_DESTROY_CTX_RESET,
-                       0,
-                       NX_CDRP_CMD_DESTROY_TX_CTX)) {
-
+       struct netxen_cmd_args cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.req.arg1 = adapter->tx_context_id;
+       cmd.req.arg2 = NX_DESTROY_CTX_RESET;
+       cmd.req.arg3 = 0;
+       cmd.req.cmd = NX_CDRP_CMD_DESTROY_TX_CTX;
+       if (netxen_issue_cmd(adapter, &cmd)) {
                printk(KERN_WARNING
                        "%s: Failed to destroy tx ctx in firmware\n",
                        netxen_nic_driver_name);
@@ -398,34 +547,37 @@ int
 nx_fw_cmd_query_phy(struct netxen_adapter *adapter, u32 reg, u32 *val)
 {
        u32 rcode;
-
-       rcode = netxen_issue_cmd(adapter,
-                       adapter->ahw.pci_func,
-                       NXHAL_VERSION,
-                       reg,
-                       0,
-                       0,
-                       NX_CDRP_CMD_READ_PHY);
-
+       struct netxen_cmd_args cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.req.arg1 = reg;
+       cmd.req.arg2 = 0;
+       cmd.req.arg3 = 0;
+       cmd.req.cmd = NX_CDRP_CMD_READ_PHY;
+       cmd.rsp.arg1 = 1;
+       rcode = netxen_issue_cmd(adapter, &cmd);
        if (rcode != NX_RCODE_SUCCESS)
                return -EIO;
 
-       return NXRD32(adapter, NX_ARG1_CRB_OFFSET);
+       if (val == NULL)
+               return -EIO;
+
+       *val = cmd.rsp.arg1;
+       return 0;
 }
 
 int
 nx_fw_cmd_set_phy(struct netxen_adapter *adapter, u32 reg, u32 val)
 {
        u32 rcode;
-
-       rcode = netxen_issue_cmd(adapter,
-                       adapter->ahw.pci_func,
-                       NXHAL_VERSION,
-                       reg,
-                       val,
-                       0,
-                       NX_CDRP_CMD_WRITE_PHY);
-
+       struct netxen_cmd_args cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.req.arg1 = reg;
+       cmd.req.arg2 = val;
+       cmd.req.arg3 = 0;
+       cmd.req.cmd = NX_CDRP_CMD_WRITE_PHY;
+       rcode = netxen_issue_cmd(adapter, &cmd);
        if (rcode != NX_RCODE_SUCCESS)
                return -EIO;
 
index b34fb74d07e3b4f91ad027d914ab3b2fbd260a14..d19e41063f3611fe7a93595b5bc9310cff168f52 100644 (file)
@@ -83,14 +83,18 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
        u32 fw_minor = 0;
        u32 fw_build = 0;
 
-       strncpy(drvinfo->driver, netxen_nic_driver_name, 32);
-       strncpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID, 32);
+       strlcpy(drvinfo->driver, netxen_nic_driver_name,
+               sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID,
+               sizeof(drvinfo->version));
        fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR);
        fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
        fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
-       sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+               "%d.%d.%d", fw_major, fw_minor, fw_build);
 
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = NETXEN_NIC_REGS_LEN;
        drvinfo->eedump_len = netxen_nic_get_eeprom_len(dev);
 }
@@ -244,6 +248,11 @@ skip:
                }
        }
 
+       if (!netif_running(dev) || !adapter->ahw.linkup) {
+               ecmd->duplex = DUPLEX_UNKNOWN;
+               ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
+       }
+
        return 0;
 }
 
@@ -413,9 +422,6 @@ netxen_nic_get_ringparam(struct net_device *dev,
        }
 
        ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
-
-       ring->rx_mini_max_pending = 0;
-       ring->rx_mini_pending = 0;
 }
 
 static u32
@@ -811,6 +817,107 @@ static int netxen_get_intr_coalesce(struct net_device *netdev,
        return 0;
 }
 
+static int
+netxen_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
+{
+       struct netxen_adapter *adapter = netdev_priv(netdev);
+       struct netxen_minidump *mdump = &adapter->mdump;
+       if (adapter->fw_mdump_rdy)
+               dump->len = mdump->md_dump_size;
+       else
+               dump->len = 0;
+       dump->flag = mdump->md_capture_mask;
+       dump->version = adapter->fw_version;
+       return 0;
+}
+
+static int
+netxen_set_dump(struct net_device *netdev, struct ethtool_dump *val)
+{
+       int ret = 0;
+       struct netxen_adapter *adapter = netdev_priv(netdev);
+       struct netxen_minidump *mdump = &adapter->mdump;
+
+       switch (val->flag) {
+       case NX_FORCE_FW_DUMP_KEY:
+               if (!mdump->md_enabled)
+                       mdump->md_enabled = 1;
+               if (adapter->fw_mdump_rdy) {
+                       netdev_info(netdev, "Previous dump not cleared, not forcing dump\n");
+                       return ret;
+               }
+               netdev_info(netdev, "Forcing a fw dump\n");
+               nx_dev_request_reset(adapter);
+               break;
+       case NX_DISABLE_FW_DUMP:
+               if (mdump->md_enabled) {
+                       netdev_info(netdev, "Disabling FW Dump\n");
+                       mdump->md_enabled = 0;
+               }
+               break;
+       case NX_ENABLE_FW_DUMP:
+               if (!mdump->md_enabled) {
+                       netdev_info(netdev, "Enabling FW dump\n");
+                       mdump->md_enabled = 1;
+               }
+               break;
+       case NX_FORCE_FW_RESET:
+               netdev_info(netdev, "Forcing FW reset\n");
+               nx_dev_request_reset(adapter);
+               adapter->flags &= ~NETXEN_FW_RESET_OWNER;
+               break;
+       default:
+               if (val->flag <= NX_DUMP_MASK_MAX &&
+                       val->flag >= NX_DUMP_MASK_MIN) {
+                       mdump->md_capture_mask = val->flag & 0xff;
+                       netdev_info(netdev, "Driver mask changed to: 0x%x\n",
+                                       mdump->md_capture_mask);
+                       break;
+               }
+               netdev_info(netdev,
+                       "Invalid dump level: 0x%x\n", val->flag);
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+static int
+netxen_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
+                       void *buffer)
+{
+       int i, copy_sz;
+       u32 *hdr_ptr, *data;
+       struct netxen_adapter *adapter = netdev_priv(netdev);
+       struct netxen_minidump *mdump = &adapter->mdump;
+
+
+       if (!adapter->fw_mdump_rdy) {
+               netdev_info(netdev, "Dump not available\n");
+               return 0;
+       }
+       /* Copy template header first */
+       copy_sz = mdump->md_template_size;
+       hdr_ptr = (u32 *) mdump->md_template;
+       data = buffer;
+       for (i = 0; i < copy_sz/sizeof(u32); i++)
+               *data++ = cpu_to_le32(*hdr_ptr++);
+
+       /* Copy captured dump data */
+       memcpy(buffer + copy_sz,
+               mdump->md_capture_buff + mdump->md_template_size,
+                       mdump->md_capture_size);
+       dump->len = copy_sz + mdump->md_capture_size;
+       dump->flag = mdump->md_capture_mask;
+
+       /* Free dump area once data has been captured */
+       vfree(mdump->md_capture_buff);
+       mdump->md_capture_buff = NULL;
+       adapter->fw_mdump_rdy = 0;
+       netdev_info(netdev, "extracted the fw dump Successfully\n");
+       return 0;
+}
+
 const struct ethtool_ops netxen_nic_ethtool_ops = {
        .get_settings = netxen_nic_get_settings,
        .set_settings = netxen_nic_set_settings,
@@ -832,4 +939,7 @@ const struct ethtool_ops netxen_nic_ethtool_ops = {
        .get_sset_count = netxen_get_sset_count,
        .get_coalesce = netxen_get_intr_coalesce,
        .set_coalesce = netxen_set_intr_coalesce,
+       .get_dump_flag = netxen_get_dump_flag,
+       .get_dump_data = netxen_get_dump_data,
+       .set_dump = netxen_set_dump,
 };
index dc1967c1f312497e7d680c501a8c71d2091c4b2e..b1a897cd9a8d54366b39dcd46bcb943dae575356 100644 (file)
@@ -969,6 +969,7 @@ enum {
 #define NX_RCODE_FATAL_ERROR           0x80000000
 #define NX_FWERROR_PEGNUM(code)                ((code) & 0xff)
 #define NX_FWERROR_CODE(code)          ((code >> 8) & 0xfffff)
+#define NX_FWERROR_PEGSTAT1(code)      ((code >> 8) & 0x1fffff)
 
 #define FW_POLL_DELAY                  (2 * HZ)
 #define FW_FAIL_THRESH                 3
index 3f89e57cae5018f6cff62ef2ec7fc1c66c4ddc39..6f37470750f30c9b9de63f590ba02b6dfa4a1dfa 100644 (file)
@@ -46,7 +46,6 @@ static void netxen_nic_io_write_128M(struct netxen_adapter *adapter,
                void __iomem *addr, u32 data);
 static u32 netxen_nic_io_read_128M(struct netxen_adapter *adapter,
                void __iomem *addr);
-
 #ifndef readq
 static inline u64 readq(void __iomem *addr)
 {
@@ -1974,3 +1973,631 @@ netxen_nic_wol_supported(struct netxen_adapter *adapter)
 
        return 0;
 }
+
+static u32 netxen_md_cntrl(struct netxen_adapter *adapter,
+                       struct netxen_minidump_template_hdr *template_hdr,
+                       struct netxen_minidump_entry_crb *crtEntry)
+{
+       int loop_cnt, i, rv = 0, timeout_flag;
+       u32 op_count, stride;
+       u32 opcode, read_value, addr;
+       unsigned long timeout, timeout_jiffies;
+       addr = crtEntry->addr;
+       op_count = crtEntry->op_count;
+       stride = crtEntry->addr_stride;
+
+       for (loop_cnt = 0; loop_cnt < op_count; loop_cnt++) {
+               for (i = 0; i < sizeof(crtEntry->opcode) * 8; i++) {
+                       opcode = (crtEntry->opcode & (0x1 << i));
+                       if (opcode) {
+                               switch (opcode) {
+                               case NX_DUMP_WCRB:
+                                       NX_WR_DUMP_REG(addr,
+                                               adapter->ahw.pci_base0,
+                                                       crtEntry->value_1);
+                                       break;
+                               case NX_DUMP_RWCRB:
+                                       NX_RD_DUMP_REG(addr,
+                                               adapter->ahw.pci_base0,
+                                                               &read_value);
+                                       NX_WR_DUMP_REG(addr,
+                                               adapter->ahw.pci_base0,
+                                                               read_value);
+                                       break;
+                               case NX_DUMP_ANDCRB:
+                                       NX_RD_DUMP_REG(addr,
+                                               adapter->ahw.pci_base0,
+                                                               &read_value);
+                                       read_value &= crtEntry->value_2;
+                                       NX_WR_DUMP_REG(addr,
+                                               adapter->ahw.pci_base0,
+                                                               read_value);
+                                       break;
+                               case NX_DUMP_ORCRB:
+                                       NX_RD_DUMP_REG(addr,
+                                               adapter->ahw.pci_base0,
+                                                               &read_value);
+                                       read_value |= crtEntry->value_3;
+                                       NX_WR_DUMP_REG(addr,
+                                               adapter->ahw.pci_base0,
+                                                               read_value);
+                                       break;
+                               case NX_DUMP_POLLCRB:
+                                       timeout = crtEntry->poll_timeout;
+                                       NX_RD_DUMP_REG(addr,
+                                               adapter->ahw.pci_base0,
+                                                               &read_value);
+                                       timeout_jiffies =
+                                       msecs_to_jiffies(timeout) + jiffies;
+                                       for (timeout_flag = 0;
+                                               !timeout_flag
+                                       && ((read_value & crtEntry->value_2)
+                                       != crtEntry->value_1);) {
+                                               if (time_after(jiffies,
+                                                       timeout_jiffies))
+                                                       timeout_flag = 1;
+                                       NX_RD_DUMP_REG(addr,
+                                                       adapter->ahw.pci_base0,
+                                                               &read_value);
+                                       }
+
+                                       if (timeout_flag) {
+                                               dev_err(&adapter->pdev->dev, "%s : "
+                                                       "Timeout in poll_crb control operation.\n"
+                                                               , __func__);
+                                               return -1;
+                                       }
+                                       break;
+                               case NX_DUMP_RD_SAVE:
+                                       /* Decide which address to use */
+                                       if (crtEntry->state_index_a)
+                                               addr =
+                                               template_hdr->saved_state_array
+                                               [crtEntry->state_index_a];
+                                       NX_RD_DUMP_REG(addr,
+                                               adapter->ahw.pci_base0,
+                                                               &read_value);
+                                       template_hdr->saved_state_array
+                                       [crtEntry->state_index_v]
+                                               = read_value;
+                                       break;
+                               case NX_DUMP_WRT_SAVED:
+                                       /* Decide which value to use */
+                                       if (crtEntry->state_index_v)
+                                               read_value =
+                                               template_hdr->saved_state_array
+                                               [crtEntry->state_index_v];
+                                       else
+                                               read_value = crtEntry->value_1;
+
+                                       /* Decide which address to use */
+                                       if (crtEntry->state_index_a)
+                                               addr =
+                                               template_hdr->saved_state_array
+                                               [crtEntry->state_index_a];
+
+                                       NX_WR_DUMP_REG(addr,
+                                               adapter->ahw.pci_base0,
+                                                               read_value);
+                                       break;
+                               case NX_DUMP_MOD_SAVE_ST:
+                                       read_value =
+                                       template_hdr->saved_state_array
+                                               [crtEntry->state_index_v];
+                                       read_value <<= crtEntry->shl;
+                                       read_value >>= crtEntry->shr;
+                                       if (crtEntry->value_2)
+                                               read_value &=
+                                               crtEntry->value_2;
+                                       read_value |= crtEntry->value_3;
+                                       read_value += crtEntry->value_1;
+                                       /* Write value back to state area.*/
+                                       template_hdr->saved_state_array
+                                               [crtEntry->state_index_v]
+                                                       = read_value;
+                                       break;
+                               default:
+                                       rv = 1;
+                                       break;
+                               }
+                       }
+               }
+               addr = addr + stride;
+       }
+       return rv;
+}
+
+/* Read memory or MN */
+static u32
+netxen_md_rdmem(struct netxen_adapter *adapter,
+               struct netxen_minidump_entry_rdmem
+                       *memEntry, u64 *data_buff)
+{
+       u64 addr, value = 0;
+       int i = 0, loop_cnt;
+
+       addr = (u64)memEntry->read_addr;
+       loop_cnt = memEntry->read_data_size;    /* This is size in bytes */
+       loop_cnt /= sizeof(value);
+
+       for (i = 0; i < loop_cnt; i++) {
+               if (netxen_nic_pci_mem_read_2M(adapter, addr, &value))
+                       goto out;
+               *data_buff++ = value;
+               addr += sizeof(value);
+       }
+out:
+       return i * sizeof(value);
+}
+
+/* Read CRB operation */
+static u32 netxen_md_rd_crb(struct netxen_adapter *adapter,
+                       struct netxen_minidump_entry_crb
+                               *crbEntry, u32 *data_buff)
+{
+       int loop_cnt;
+       u32 op_count, addr, stride, value;
+
+       addr = crbEntry->addr;
+       op_count = crbEntry->op_count;
+       stride = crbEntry->addr_stride;
+
+       for (loop_cnt = 0; loop_cnt < op_count; loop_cnt++) {
+               NX_RD_DUMP_REG(addr, adapter->ahw.pci_base0, &value);
+               *data_buff++ = addr;
+               *data_buff++ = value;
+               addr = addr + stride;
+       }
+       return loop_cnt * (2 * sizeof(u32));
+}
+
+/* Read ROM */
+static u32
+netxen_md_rdrom(struct netxen_adapter *adapter,
+                       struct netxen_minidump_entry_rdrom
+                               *romEntry, u32 *data_buff)
+{
+       int i, count = 0;
+       u32 size, lck_val;
+       u32 val;
+       u32 fl_addr, waddr, raddr;
+       fl_addr = romEntry->read_addr;
+       size = romEntry->read_data_size/4;
+lock_try:
+       lck_val = readl((void __iomem *)(adapter->ahw.pci_base0 +
+                                                       NX_FLASH_SEM2_LK));
+       if (!lck_val && count < MAX_CTL_CHECK) {
+               msleep(20);
+               count++;
+               goto lock_try;
+       }
+       writel(adapter->ahw.pci_func, (void __iomem *)(adapter->ahw.pci_base0 +
+                                                       NX_FLASH_LOCK_ID));
+       for (i = 0; i < size; i++) {
+               waddr = fl_addr & 0xFFFF0000;
+               NX_WR_DUMP_REG(FLASH_ROM_WINDOW, adapter->ahw.pci_base0, waddr);
+               raddr = FLASH_ROM_DATA + (fl_addr & 0x0000FFFF);
+               NX_RD_DUMP_REG(raddr, adapter->ahw.pci_base0, &val);
+               *data_buff++ = cpu_to_le32(val);
+               fl_addr += sizeof(val);
+       }
+       readl((void __iomem *)(adapter->ahw.pci_base0 + NX_FLASH_SEM2_ULK));
+       return romEntry->read_data_size;
+}
+
+/* Handle L2 Cache */
+static u32
+netxen_md_L2Cache(struct netxen_adapter *adapter,
+                               struct netxen_minidump_entry_cache
+                                       *cacheEntry, u32 *data_buff)
+{
+       int loop_cnt, i, k, timeout_flag = 0;
+       u32 addr, read_addr, read_value, cntrl_addr, tag_reg_addr;
+       u32 tag_value, read_cnt;
+       u8 cntl_value_w, cntl_value_r;
+       unsigned long timeout, timeout_jiffies;
+
+       loop_cnt = cacheEntry->op_count;
+       read_addr = cacheEntry->read_addr;
+       cntrl_addr = cacheEntry->control_addr;
+       cntl_value_w = (u32) cacheEntry->write_value;
+       tag_reg_addr = cacheEntry->tag_reg_addr;
+       tag_value = cacheEntry->init_tag_value;
+       read_cnt = cacheEntry->read_addr_cnt;
+
+       for (i = 0; i < loop_cnt; i++) {
+               NX_WR_DUMP_REG(tag_reg_addr, adapter->ahw.pci_base0, tag_value);
+               if (cntl_value_w)
+                       NX_WR_DUMP_REG(cntrl_addr, adapter->ahw.pci_base0,
+                                       (u32)cntl_value_w);
+               if (cacheEntry->poll_mask) {
+                       timeout = cacheEntry->poll_wait;
+                       NX_RD_DUMP_REG(cntrl_addr, adapter->ahw.pci_base0,
+                                                       &cntl_value_r);
+                       timeout_jiffies = msecs_to_jiffies(timeout) + jiffies;
+                       for (timeout_flag = 0; !timeout_flag &&
+                       ((cntl_value_r & cacheEntry->poll_mask) != 0);) {
+                               if (time_after(jiffies, timeout_jiffies))
+                                       timeout_flag = 1;
+                               NX_RD_DUMP_REG(cntrl_addr,
+                                       adapter->ahw.pci_base0,
+                                                       &cntl_value_r);
+                       }
+                       if (timeout_flag) {
+                               dev_err(&adapter->pdev->dev,
+                                               "Timeout in processing L2 Tag poll.\n");
+                               return -1;
+                       }
+               }
+               addr = read_addr;
+               for (k = 0; k < read_cnt; k++) {
+                       NX_RD_DUMP_REG(addr, adapter->ahw.pci_base0,
+                                       &read_value);
+                       *data_buff++ = read_value;
+                       addr += cacheEntry->read_addr_stride;
+               }
+               tag_value += cacheEntry->tag_value_stride;
+       }
+       return read_cnt * loop_cnt * sizeof(read_value);
+}
+
+
+/* Handle L1 Cache */
+static u32 netxen_md_L1Cache(struct netxen_adapter *adapter,
+                               struct netxen_minidump_entry_cache
+                                       *cacheEntry, u32 *data_buff)
+{
+       int i, k, loop_cnt;
+       u32 addr, read_addr, read_value, cntrl_addr, tag_reg_addr;
+       u32 tag_value, read_cnt;
+       u8 cntl_value_w;
+
+       loop_cnt = cacheEntry->op_count;
+       read_addr = cacheEntry->read_addr;
+       cntrl_addr = cacheEntry->control_addr;
+       cntl_value_w = (u32) cacheEntry->write_value;
+       tag_reg_addr = cacheEntry->tag_reg_addr;
+       tag_value = cacheEntry->init_tag_value;
+       read_cnt = cacheEntry->read_addr_cnt;
+
+       for (i = 0; i < loop_cnt; i++) {
+               NX_WR_DUMP_REG(tag_reg_addr, adapter->ahw.pci_base0, tag_value);
+               NX_WR_DUMP_REG(cntrl_addr, adapter->ahw.pci_base0,
+                                               (u32) cntl_value_w);
+               addr = read_addr;
+               for (k = 0; k < read_cnt; k++) {
+                       NX_RD_DUMP_REG(addr,
+                               adapter->ahw.pci_base0,
+                                               &read_value);
+                       *data_buff++ = read_value;
+                       addr += cacheEntry->read_addr_stride;
+               }
+               tag_value += cacheEntry->tag_value_stride;
+       }
+       return read_cnt * loop_cnt * sizeof(read_value);
+}
+
+/* Reading OCM memory */
+static u32
+netxen_md_rdocm(struct netxen_adapter *adapter,
+                               struct netxen_minidump_entry_rdocm
+                                       *ocmEntry, u32 *data_buff)
+{
+       int i, loop_cnt;
+       u32 value;
+       void __iomem *addr;
+       addr = (ocmEntry->read_addr + adapter->ahw.pci_base0);
+       loop_cnt = ocmEntry->op_count;
+
+       for (i = 0; i < loop_cnt; i++) {
+               value = readl(addr);
+               *data_buff++ = value;
+               addr += ocmEntry->read_addr_stride;
+       }
+       return i * sizeof(u32);
+}
+
+/* Read MUX data */
+static u32
+netxen_md_rdmux(struct netxen_adapter *adapter, struct netxen_minidump_entry_mux
+                                       *muxEntry, u32 *data_buff)
+{
+       int loop_cnt = 0;
+       u32 read_addr, read_value, select_addr, sel_value;
+
+       read_addr = muxEntry->read_addr;
+       sel_value = muxEntry->select_value;
+       select_addr = muxEntry->select_addr;
+
+       for (loop_cnt = 0; loop_cnt < muxEntry->op_count; loop_cnt++) {
+               NX_WR_DUMP_REG(select_addr, adapter->ahw.pci_base0, sel_value);
+               NX_RD_DUMP_REG(read_addr, adapter->ahw.pci_base0, &read_value);
+               *data_buff++ = sel_value;
+               *data_buff++ = read_value;
+               sel_value += muxEntry->select_value_stride;
+       }
+       return loop_cnt * (2 * sizeof(u32));
+}
+
+/* Handling Queue State Reads */
+static u32
+netxen_md_rdqueue(struct netxen_adapter *adapter,
+                               struct netxen_minidump_entry_queue
+                                       *queueEntry, u32 *data_buff)
+{
+       int loop_cnt, k;
+       u32 queue_id, read_addr, read_value, read_stride, select_addr, read_cnt;
+
+       read_cnt = queueEntry->read_addr_cnt;
+       read_stride = queueEntry->read_addr_stride;
+       select_addr = queueEntry->select_addr;
+
+       for (loop_cnt = 0, queue_id = 0; loop_cnt < queueEntry->op_count;
+                                loop_cnt++) {
+               NX_WR_DUMP_REG(select_addr, adapter->ahw.pci_base0, queue_id);
+               read_addr = queueEntry->read_addr;
+               for (k = 0; k < read_cnt; k--) {
+                       NX_RD_DUMP_REG(read_addr, adapter->ahw.pci_base0,
+                                                       &read_value);
+                       *data_buff++ = read_value;
+                       read_addr += read_stride;
+               }
+               queue_id += queueEntry->queue_id_stride;
+       }
+       return loop_cnt * (read_cnt * sizeof(read_value));
+}
+
+
+/*
+* We catch an error where driver does not read
+* as much data as we expect from the entry.
+*/
+
+static int netxen_md_entry_err_chk(struct netxen_adapter *adapter,
+                               struct netxen_minidump_entry *entry, int esize)
+{
+       if (esize < 0) {
+               entry->hdr.driver_flags |= NX_DUMP_SKIP;
+               return esize;
+       }
+       if (esize != entry->hdr.entry_capture_size) {
+               entry->hdr.entry_capture_size = esize;
+               entry->hdr.driver_flags |= NX_DUMP_SIZE_ERR;
+               dev_info(&adapter->pdev->dev,
+                       "Invalidate dump, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
+                       entry->hdr.entry_type, entry->hdr.entry_capture_mask,
+                       esize, entry->hdr.entry_capture_size);
+               dev_info(&adapter->pdev->dev, "Aborting further dump capture\n");
+       }
+       return 0;
+}
+
+static int netxen_parse_md_template(struct netxen_adapter *adapter)
+{
+       int num_of_entries, buff_level, e_cnt, esize;
+       int end_cnt = 0, rv = 0, sane_start = 0, sane_end = 0;
+       char *dbuff;
+       void *template_buff = adapter->mdump.md_template;
+       char *dump_buff = adapter->mdump.md_capture_buff;
+       int capture_mask = adapter->mdump.md_capture_mask;
+       struct netxen_minidump_template_hdr *template_hdr;
+       struct netxen_minidump_entry *entry;
+
+       if ((capture_mask & 0x3) != 0x3) {
+               dev_err(&adapter->pdev->dev, "Capture mask %02x below minimum needed "
+                       "for valid firmware dump\n", capture_mask);
+               return -EINVAL;
+       }
+       template_hdr = (struct netxen_minidump_template_hdr *) template_buff;
+       num_of_entries = template_hdr->num_of_entries;
+       entry = (struct netxen_minidump_entry *) ((char *) template_buff +
+                               template_hdr->first_entry_offset);
+       memcpy(dump_buff, template_buff, adapter->mdump.md_template_size);
+       dump_buff = dump_buff + adapter->mdump.md_template_size;
+
+       if (template_hdr->entry_type == TLHDR)
+               sane_start = 1;
+
+       for (e_cnt = 0, buff_level = 0; e_cnt < num_of_entries; e_cnt++) {
+               if (!(entry->hdr.entry_capture_mask & capture_mask)) {
+                       entry->hdr.driver_flags |= NX_DUMP_SKIP;
+                       entry = (struct netxen_minidump_entry *)
+                               ((char *) entry + entry->hdr.entry_size);
+                       continue;
+               }
+               switch (entry->hdr.entry_type) {
+               case RDNOP:
+                       entry->hdr.driver_flags |= NX_DUMP_SKIP;
+                       break;
+               case RDEND:
+                       entry->hdr.driver_flags |= NX_DUMP_SKIP;
+                       if (!sane_end)
+                               end_cnt = e_cnt;
+                       sane_end += 1;
+                       break;
+               case CNTRL:
+                       rv = netxen_md_cntrl(adapter,
+                               template_hdr, (void *)entry);
+                       if (rv)
+                               entry->hdr.driver_flags |= NX_DUMP_SKIP;
+                       break;
+               case RDCRB:
+                       dbuff = dump_buff + buff_level;
+                       esize = netxen_md_rd_crb(adapter,
+                                       (void *) entry, (void *) dbuff);
+                       rv = netxen_md_entry_err_chk
+                               (adapter, entry, esize);
+                       if (rv < 0)
+                               break;
+                       buff_level += esize;
+                       break;
+               case RDMN:
+               case RDMEM:
+                       dbuff = dump_buff + buff_level;
+                       esize = netxen_md_rdmem(adapter,
+                               (void *) entry, (void *) dbuff);
+                       rv = netxen_md_entry_err_chk
+                               (adapter, entry, esize);
+                       if (rv < 0)
+                               break;
+                       buff_level += esize;
+                       break;
+               case BOARD:
+               case RDROM:
+                       dbuff = dump_buff + buff_level;
+                       esize = netxen_md_rdrom(adapter,
+                               (void *) entry, (void *) dbuff);
+                       rv = netxen_md_entry_err_chk
+                               (adapter, entry, esize);
+                       if (rv < 0)
+                               break;
+                       buff_level += esize;
+                       break;
+               case L2ITG:
+               case L2DTG:
+               case L2DAT:
+               case L2INS:
+                       dbuff = dump_buff + buff_level;
+                       esize = netxen_md_L2Cache(adapter,
+                               (void *) entry, (void *) dbuff);
+                       rv = netxen_md_entry_err_chk
+                               (adapter, entry, esize);
+                       if (rv < 0)
+                               break;
+                       buff_level += esize;
+                       break;
+               case L1DAT:
+               case L1INS:
+                       dbuff = dump_buff + buff_level;
+                       esize = netxen_md_L1Cache(adapter,
+                               (void *) entry, (void *) dbuff);
+                       rv = netxen_md_entry_err_chk
+                               (adapter, entry, esize);
+                       if (rv < 0)
+                               break;
+                       buff_level += esize;
+                       break;
+               case RDOCM:
+                       dbuff = dump_buff + buff_level;
+                       esize = netxen_md_rdocm(adapter,
+                               (void *) entry, (void *) dbuff);
+                       rv = netxen_md_entry_err_chk
+                               (adapter, entry, esize);
+                       if (rv < 0)
+                               break;
+                       buff_level += esize;
+                       break;
+               case RDMUX:
+                       dbuff = dump_buff + buff_level;
+                       esize = netxen_md_rdmux(adapter,
+                               (void *) entry, (void *) dbuff);
+                       rv = netxen_md_entry_err_chk
+                               (adapter, entry, esize);
+                       if (rv < 0)
+                               break;
+                       buff_level += esize;
+                       break;
+               case QUEUE:
+                       dbuff = dump_buff + buff_level;
+                       esize = netxen_md_rdqueue(adapter,
+                               (void *) entry, (void *) dbuff);
+                       rv = netxen_md_entry_err_chk
+                               (adapter, entry, esize);
+                       if (rv  < 0)
+                               break;
+                       buff_level += esize;
+                       break;
+               default:
+                       entry->hdr.driver_flags |= NX_DUMP_SKIP;
+                       break;
+               }
+               /* Next entry in the template */
+               entry = (struct netxen_minidump_entry *)
+                       ((char *) entry + entry->hdr.entry_size);
+       }
+       if (!sane_start || sane_end > 1) {
+               dev_err(&adapter->pdev->dev,
+                               "Firmware minidump template configuration error.\n");
+       }
+       return 0;
+}
+
+static int
+netxen_collect_minidump(struct netxen_adapter *adapter)
+{
+       int ret = 0;
+       struct netxen_minidump_template_hdr *hdr;
+       struct timespec val;
+       hdr = (struct netxen_minidump_template_hdr *)
+                               adapter->mdump.md_template;
+       hdr->driver_capture_mask = adapter->mdump.md_capture_mask;
+       jiffies_to_timespec(jiffies, &val);
+       hdr->driver_timestamp = (u32) val.tv_sec;
+       hdr->driver_info_word2 = adapter->fw_version;
+       hdr->driver_info_word3 = NXRD32(adapter, CRB_DRIVER_VERSION);
+       ret = netxen_parse_md_template(adapter);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+
+void
+netxen_dump_fw(struct netxen_adapter *adapter)
+{
+       struct netxen_minidump_template_hdr *hdr;
+       int i, k, data_size = 0;
+       u32 capture_mask;
+       hdr = (struct netxen_minidump_template_hdr *)
+                               adapter->mdump.md_template;
+       capture_mask = adapter->mdump.md_capture_mask;
+
+       for (i = 0x2, k = 1; (i & NX_DUMP_MASK_MAX); i <<= 1, k++) {
+               if (i & capture_mask)
+                       data_size += hdr->capture_size_array[k];
+       }
+       if (!data_size) {
+               dev_err(&adapter->pdev->dev,
+                               "Invalid cap sizes for capture_mask=0x%x\n",
+                       adapter->mdump.md_capture_mask);
+               return;
+       }
+       adapter->mdump.md_capture_size = data_size;
+       adapter->mdump.md_dump_size = adapter->mdump.md_template_size +
+                                       adapter->mdump.md_capture_size;
+       if (!adapter->mdump.md_capture_buff) {
+               adapter->mdump.md_capture_buff =
+                               vmalloc(adapter->mdump.md_dump_size);
+               if (!adapter->mdump.md_capture_buff) {
+                       dev_info(&adapter->pdev->dev,
+                               "Unable to allocate memory for minidump "
+                               "capture_buffer(%d bytes).\n",
+                                       adapter->mdump.md_dump_size);
+                       return;
+               }
+               memset(adapter->mdump.md_capture_buff, 0,
+                               adapter->mdump.md_dump_size);
+               if (netxen_collect_minidump(adapter)) {
+                       adapter->mdump.has_valid_dump = 0;
+                       adapter->mdump.md_dump_size = 0;
+                       vfree(adapter->mdump.md_capture_buff);
+                       adapter->mdump.md_capture_buff = NULL;
+                       dev_err(&adapter->pdev->dev,
+                               "Error in collecting firmware minidump.\n");
+               } else {
+                       adapter->mdump.md_timestamp = jiffies;
+                       adapter->mdump.has_valid_dump = 1;
+                       adapter->fw_mdump_rdy = 1;
+                       dev_info(&adapter->pdev->dev, "%s Successfully "
+                               "collected fw dump.\n", adapter->netdev->name);
+               }
+
+       } else {
+               dev_info(&adapter->pdev->dev,
+                                       "Cannot overwrite previously collected "
+                                                       "firmware minidump.\n");
+               adapter->fw_mdump_rdy = 1;
+               return;
+       }
+}
index a8259cc19a63484e7eefc609514fffd6ac88f0bb..55e6b4d5e361ab2d17a0c57b68189386871e7e6b 100644 (file)
@@ -449,7 +449,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter)
 
        /* resetall */
        netxen_rom_lock(adapter);
-       NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0xffffffff);
+       NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0xfeffffff);
        netxen_rom_unlock(adapter);
 
        if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
@@ -1353,7 +1353,6 @@ int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
 
        do {
                val = NXRD32(adapter, CRB_CMDPEG_STATE);
-
                switch (val) {
                case PHAN_INITIALIZE_COMPLETE:
                case PHAN_INITIALIZE_ACK:
index 35b745eb5746ae3d21f2cbb9b84e137aea227a23..0e3fa33057544a8af28adab5e127e7ca470f3f6b 100644 (file)
@@ -82,7 +82,6 @@ static void netxen_create_sysfs_entries(struct netxen_adapter *adapter);
 static void netxen_remove_sysfs_entries(struct netxen_adapter *adapter);
 static void netxen_create_diag_entries(struct netxen_adapter *adapter);
 static void netxen_remove_diag_entries(struct netxen_adapter *adapter);
-
 static int nx_dev_request_aer(struct netxen_adapter *adapter);
 static int nx_decr_dev_ref_cnt(struct netxen_adapter *adapter);
 static int netxen_can_start_firmware(struct netxen_adapter *adapter);
@@ -96,6 +95,7 @@ static void netxen_restore_indev_addr(struct net_device *dev, unsigned long);
 static struct rtnl_link_stats64 *netxen_nic_get_stats(struct net_device *dev,
                                                      struct rtnl_link_stats64 *stats);
 static int netxen_nic_set_mac(struct net_device *netdev, void *p);
+int nx_dev_request_reset(struct netxen_adapter *adapter);
 
 /*  PCI Device ID Table  */
 #define ENTRY(device) \
@@ -800,10 +800,10 @@ err_out:
 static void
 netxen_check_options(struct netxen_adapter *adapter)
 {
-       u32 fw_major, fw_minor, fw_build;
+       u32 fw_major, fw_minor, fw_build, prev_fw_version;
        char brd_name[NETXEN_MAX_SHORT_NAME];
        char serial_num[32];
-       int i, offset, val;
+       int i, offset, val, err;
        int *ptr32;
        struct pci_dev *pdev = adapter->pdev;
 
@@ -824,9 +824,22 @@ netxen_check_options(struct netxen_adapter *adapter)
        fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR);
        fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
        fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
-
+       prev_fw_version = adapter->fw_version;
        adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build);
 
+       /* Get FW Mini Coredump template and store it */
+        if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+               if (adapter->mdump.md_template == NULL ||
+                               adapter->fw_version > prev_fw_version) {
+                       kfree(adapter->mdump.md_template);
+                       adapter->mdump.md_template = NULL;
+                       err = netxen_setup_minidump(adapter);
+                       if (err)
+                               dev_err(&adapter->pdev->dev,
+                               "Failed to setup minidump rcode = %d\n", err);
+               }
+       }
+
        if (adapter->portnum == 0) {
                get_brd_name_by_type(adapter->ahw.board_type, brd_name);
 
@@ -899,7 +912,7 @@ netxen_check_options(struct netxen_adapter *adapter)
 static int
 netxen_start_firmware(struct netxen_adapter *adapter)
 {
-       int val, err, first_boot;
+       int val, err, first_boot, state;
        struct pci_dev *pdev = adapter->pdev;
 
        /* required for NX2031 dummy dma */
@@ -907,7 +920,12 @@ netxen_start_firmware(struct netxen_adapter *adapter)
        if (err)
                return err;
 
-       if (!netxen_can_start_firmware(adapter))
+       err = netxen_can_start_firmware(adapter);
+
+       if (err < 0)
+               return err;
+
+       if (!err)
                goto wait_init;
 
        first_boot = NXRD32(adapter, NETXEN_CAM_RAM(0x1fc));
@@ -979,7 +997,15 @@ wait_init:
                goto err_out;
        }
 
+       if (netxen_api_lock(adapter))
+               return -EIO;
+       state = NXRD32(adapter, NX_CRB_DEV_STATE);
+
+       if (state == NX_DEV_FAILED)
+               return 1;
+
        NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_READY);
+       netxen_api_unlock(adapter);
 
        nx_update_dma_mask(adapter);
 
@@ -1401,7 +1427,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        netdev = alloc_etherdev(sizeof(struct netxen_adapter));
        if(!netdev) {
-               dev_err(&pdev->dev, "failed to allocate net_device\n");
                err = -ENOMEM;
                goto err_out_free_res;
        }
@@ -1527,6 +1552,18 @@ err_out_disable_pdev:
        return err;
 }
 
+static
+void netxen_cleanup_minidump(struct netxen_adapter *adapter)
+{
+       kfree(adapter->mdump.md_template);
+       adapter->mdump.md_template = NULL;
+
+       if (adapter->mdump.md_capture_buff) {
+               vfree(adapter->mdump.md_capture_buff);
+               adapter->mdump.md_capture_buff = NULL;
+       }
+}
+
 static void __devexit netxen_nic_remove(struct pci_dev *pdev)
 {
        struct netxen_adapter *adapter;
@@ -1562,8 +1599,10 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
 
        netxen_release_firmware(adapter);
 
-       if (NX_IS_REVISION_P3(pdev->revision))
+       if (NX_IS_REVISION_P3(pdev->revision)) {
+               netxen_cleanup_minidump(adapter);
                pci_disable_pcie_error_reporting(pdev);
+       }
 
        pci_release_regions(pdev);
        pci_disable_device(pdev);
@@ -2315,7 +2354,7 @@ nx_incr_dev_ref_cnt(struct netxen_adapter *adapter)
 static int
 nx_decr_dev_ref_cnt(struct netxen_adapter *adapter)
 {
-       int count;
+       int count, state;
        if (netxen_api_lock(adapter))
                return -EIO;
 
@@ -2323,8 +2362,9 @@ nx_decr_dev_ref_cnt(struct netxen_adapter *adapter)
        WARN_ON(count == 0);
 
        NXWR32(adapter, NX_CRB_DEV_REF_COUNT, --count);
+       state = NXRD32(adapter, NX_CRB_DEV_STATE);
 
-       if (count == 0)
+       if (count == 0 && state != NX_DEV_FAILED)
                NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_COLD);
 
        netxen_api_unlock(adapter);
@@ -2353,7 +2393,7 @@ nx_dev_request_aer(struct netxen_adapter *adapter)
        return ret;
 }
 
-static int
+int
 nx_dev_request_reset(struct netxen_adapter *adapter)
 {
        u32 state;
@@ -2364,10 +2404,11 @@ nx_dev_request_reset(struct netxen_adapter *adapter)
 
        state = NXRD32(adapter, NX_CRB_DEV_STATE);
 
-       if (state == NX_DEV_NEED_RESET)
+       if (state == NX_DEV_NEED_RESET || state == NX_DEV_FAILED)
                ret = 0;
        else if (state != NX_DEV_INITALIZING && state != NX_DEV_NEED_AER) {
                NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_NEED_RESET);
+               adapter->flags |= NETXEN_FW_RESET_OWNER;
                ret = 0;
        }
 
@@ -2382,8 +2423,10 @@ netxen_can_start_firmware(struct netxen_adapter *adapter)
        int count;
        int can_start = 0;
 
-       if (netxen_api_lock(adapter))
-               return 0;
+       if (netxen_api_lock(adapter)) {
+               nx_incr_dev_ref_cnt(adapter);
+               return -1;
+       }
 
        count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT);
 
@@ -2455,8 +2498,31 @@ netxen_fwinit_work(struct work_struct *work)
        struct netxen_adapter *adapter = container_of(work,
                                struct netxen_adapter, fw_work.work);
        int dev_state;
-
+       int count;
        dev_state = NXRD32(adapter, NX_CRB_DEV_STATE);
+       if (adapter->flags & NETXEN_FW_RESET_OWNER) {
+               count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT);
+               WARN_ON(count == 0);
+               if (count == 1) {
+                       if (adapter->mdump.md_enabled) {
+                               rtnl_lock();
+                               netxen_dump_fw(adapter);
+                               rtnl_unlock();
+                       }
+                       adapter->flags &= ~NETXEN_FW_RESET_OWNER;
+                       if (netxen_api_lock(adapter)) {
+                               clear_bit(__NX_RESETTING, &adapter->state);
+                               NXWR32(adapter, NX_CRB_DEV_STATE,
+                                               NX_DEV_FAILED);
+                               return;
+                       }
+                       count = NXRD32(adapter, NX_CRB_DEV_REF_COUNT);
+                       NXWR32(adapter, NX_CRB_DEV_REF_COUNT, --count);
+                       NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_COLD);
+                       dev_state = NX_DEV_COLD;
+                       netxen_api_unlock(adapter);
+               }
+       }
 
        switch (dev_state) {
        case NX_DEV_COLD:
@@ -2469,11 +2535,9 @@ netxen_fwinit_work(struct work_struct *work)
 
        case NX_DEV_NEED_RESET:
        case NX_DEV_INITALIZING:
-               if (++adapter->fw_wait_cnt < FW_POLL_THRESH) {
                        netxen_schedule_work(adapter,
                                        netxen_fwinit_work, 2 * FW_POLL_DELAY);
                        return;
-               }
 
        case NX_DEV_FAILED:
        default:
@@ -2481,6 +2545,15 @@ netxen_fwinit_work(struct work_struct *work)
                break;
        }
 
+       if (netxen_api_lock(adapter)) {
+               clear_bit(__NX_RESETTING, &adapter->state);
+               return;
+       }
+       NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_FAILED);
+       netxen_api_unlock(adapter);
+       dev_err(&adapter->pdev->dev, "%s: Device initialization Failed\n",
+                               adapter->netdev->name);
+
        clear_bit(__NX_RESETTING, &adapter->state);
 }
 
@@ -2490,7 +2563,7 @@ netxen_detach_work(struct work_struct *work)
        struct netxen_adapter *adapter = container_of(work,
                                struct netxen_adapter, fw_work.work);
        struct net_device *netdev = adapter->netdev;
-       int ref_cnt, delay;
+       int ref_cnt = 0, delay;
        u32 status;
 
        netif_device_detach(netdev);
@@ -2509,7 +2582,8 @@ netxen_detach_work(struct work_struct *work)
        if (adapter->temp == NX_TEMP_PANIC)
                goto err_ret;
 
-       ref_cnt = nx_decr_dev_ref_cnt(adapter);
+       if (!(adapter->flags & NETXEN_FW_RESET_OWNER))
+               ref_cnt = nx_decr_dev_ref_cnt(adapter);
 
        if (ref_cnt == -EIO)
                goto err_ret;
@@ -2529,6 +2603,7 @@ static int
 netxen_check_health(struct netxen_adapter *adapter)
 {
        u32 state, heartbit;
+       u32 peg_status;
        struct net_device *netdev = adapter->netdev;
 
        state = NXRD32(adapter, NX_CRB_DEV_STATE);
@@ -2549,7 +2624,7 @@ netxen_check_health(struct netxen_adapter *adapter)
         * Send request to destroy context in case of tx timeout only
         * and doesn't required in case of Fw hang
         */
-       if (state == NX_DEV_NEED_RESET) {
+       if (state == NX_DEV_NEED_RESET || state == NX_DEV_FAILED) {
                adapter->need_fw_reset = 1;
                if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
                        goto detach;
@@ -2575,8 +2650,24 @@ netxen_check_health(struct netxen_adapter *adapter)
 
        clear_bit(__NX_FW_ATTACHED, &adapter->state);
 
-       dev_info(&netdev->dev, "firmware hang detected\n");
-
+       dev_err(&netdev->dev, "firmware hang detected\n");
+       peg_status = NXRD32(adapter, NETXEN_PEG_HALT_STATUS1);
+       dev_err(&adapter->pdev->dev, "Dumping hw/fw registers\n"
+                       "PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
+                       "PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
+                       "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
+                       "PEG_NET_4_PC: 0x%x\n",
+                       peg_status,
+                       NXRD32(adapter, NETXEN_PEG_HALT_STATUS2),
+                       NXRD32(adapter, NETXEN_CRB_PEG_NET_0 + 0x3c),
+                       NXRD32(adapter, NETXEN_CRB_PEG_NET_1 + 0x3c),
+                       NXRD32(adapter, NETXEN_CRB_PEG_NET_2 + 0x3c),
+                       NXRD32(adapter, NETXEN_CRB_PEG_NET_3 + 0x3c),
+                       NXRD32(adapter, NETXEN_CRB_PEG_NET_4 + 0x3c));
+       if (NX_FWERROR_PEGSTAT1(peg_status) == 0x67)
+               dev_err(&adapter->pdev->dev,
+                       "Firmware aborted with error code 0x00006700. "
+                               "Device is being reset.\n");
 detach:
        if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) &&
                        !test_and_set_bit(__NX_RESETTING, &adapter->state))
@@ -2683,6 +2774,183 @@ netxen_show_diag_mode(struct device *dev,
                        !!(adapter->flags & NETXEN_NIC_DIAG_ENABLED));
 }
 
+static ssize_t
+netxen_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj,
+                       struct bin_attribute *attr,
+                       char *buf, loff_t offset, size_t size)
+{
+       int ret;
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct netxen_adapter *adapter = dev_get_drvdata(dev);
+
+       if ((!adapter->fw_mdump_rdy) || (!adapter->mdump.md_capture_buff))
+               return 0;
+
+       ret = memory_read_from_buffer(buf, size, &offset,
+                               adapter->mdump.md_capture_buff,
+                                       adapter->mdump.md_dump_size);
+       if (offset == adapter->mdump.md_dump_size) {
+               adapter->mdump.md_dump_size = 0;
+               adapter->fw_mdump_rdy = 0;
+               if (adapter->mdump.md_capture_buff) {
+                       vfree(adapter->mdump.md_capture_buff);
+                       adapter->mdump.md_capture_buff = NULL;
+               }
+
+       dev_info(&adapter->pdev->dev, "%s: extracted the Fw Dump successfully\n",
+                       adapter->netdev->name);
+       }
+       return ret;
+}
+
+
+static ssize_t
+netxen_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
+                       struct bin_attribute *attr,
+                       char *buf, loff_t offset, size_t size)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct netxen_adapter *adapter = dev_get_drvdata(dev);
+       struct netxen_minidump *mdump = &adapter->mdump;
+       unsigned long data;
+
+       data = simple_strtoul(buf, NULL, 16);
+       rtnl_lock();
+       switch (data) {
+       case NX_FORCE_FW_DUMP_KEY:
+               if (!mdump->md_enabled)
+                       mdump->md_enabled = 1;
+               if (adapter->fw_mdump_rdy) {
+                       dev_info(&adapter->pdev->dev, "%s: Previous dump not "
+                               "cleared, not forcing dump\n",
+                                       adapter->netdev->name);
+                       goto out;
+               }
+               dev_info(&adapter->pdev->dev, "%s: Forcing a fw dump\n",
+                               adapter->netdev->name);
+               nx_dev_request_reset(adapter);
+               break;
+       case NX_DISABLE_FW_DUMP:
+               if (mdump->md_enabled) {
+                       dev_info(&adapter->pdev->dev, "%s: Disabling FW Dump\n",
+                               adapter->netdev->name);
+                       mdump->md_enabled = 0;
+               }
+               break;
+       case NX_ENABLE_FW_DUMP:
+               if (!mdump->md_enabled) {
+                       dev_info(&adapter->pdev->dev, "%s: Enabling FW dump\n",
+                               adapter->netdev->name);
+                       mdump->md_enabled = 1;
+               }
+               break;
+       case NX_FORCE_FW_RESET:
+               dev_info(&adapter->pdev->dev, "%s: Forcing FW reset\n",
+                               adapter->netdev->name);
+               nx_dev_request_reset(adapter);
+               adapter->flags &= ~NETXEN_FW_RESET_OWNER;
+               break;
+       default:
+               dev_info(dev, "Invalid dump key, 0x%lx\n", data);
+               break;
+       }
+
+out:
+       rtnl_unlock();
+       return size;
+}
+
+static ssize_t
+netxen_show_fwdump_size(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct netxen_adapter *adapter = dev_get_drvdata(dev);
+       u32 size = 0;
+
+       if (adapter->fw_mdump_rdy)
+               size = adapter->mdump.md_dump_size;
+       return sprintf(buf, "%u\n", size);
+}
+
+static ssize_t
+netxen_store_fwdump_size(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       return -EIO;
+}
+
+static ssize_t
+netxen_show_fwdump_level(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct netxen_adapter *adapter = dev_get_drvdata(dev);
+       u32 size = adapter->mdump.md_capture_mask;
+       return sprintf(buf, "%u\n", size);
+}
+
+static ssize_t
+netxen_store_fwdump_level(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+       unsigned long int val;
+       struct netxen_adapter *adapter = dev_get_drvdata(dev);
+
+       val = simple_strtoul(buf, NULL, 16);
+
+       if (val <= NX_DUMP_MASK_MAX && val >= NX_DUMP_MASK_MIN) {
+               rtnl_lock();
+               adapter->mdump.md_capture_mask = val & 0xff;
+               rtnl_unlock();
+               dev_info(&adapter->pdev->dev, "%s: Driver mask changed to: 0x%x\n",
+                                adapter->netdev->name,
+                                       adapter->mdump.md_capture_mask);
+       } else
+               dev_info(dev, "Invalid Dump Level: 0x%lx\n",
+                               (unsigned long int) val);
+       return size;
+}
+
+static ssize_t
+netxen_show_fwdump_state(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct netxen_adapter *adapter = dev_get_drvdata(dev);
+       u32 state = adapter->mdump.md_enabled;
+       return sprintf(buf, "%u\n", state);
+}
+
+static ssize_t
+netxen_store_fwdump_state(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       return -EIO;
+}
+
+static struct bin_attribute bin_attr_fw_dump = {
+       .attr = {.name = "fw_dump", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = netxen_sysfs_read_fw_dump,
+       .write = netxen_sysfs_write_fw_dump,
+};
+
+static struct device_attribute dev_attr_fwdump_size = {
+       .attr = {.name = "fwdump_size", .mode = (S_IRUGO | S_IWUSR)},
+       .show = netxen_show_fwdump_size,
+       .store = netxen_store_fwdump_size,
+};
+
+static struct device_attribute dev_attr_fwdump_level = {
+       .attr = {.name = "fwdump_level", .mode = (S_IRUGO | S_IWUSR)},
+       .show = netxen_show_fwdump_level,
+       .store = netxen_store_fwdump_level,
+};
+
+static struct device_attribute dev_attr_fwdump_state = {
+       .attr = {.name = "fwdump_state", .mode = (S_IRUGO | S_IWUSR)},
+       .show = netxen_show_fwdump_state,
+       .store = netxen_store_fwdump_state,
+};
+
 static struct device_attribute dev_attr_diag_mode = {
        .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
        .show = netxen_show_diag_mode,
@@ -2846,13 +3114,12 @@ static struct bin_attribute bin_attr_mem = {
 static void
 netxen_create_sysfs_entries(struct netxen_adapter *adapter)
 {
-       struct net_device *netdev = adapter->netdev;
-       struct device *dev = &netdev->dev;
+       struct device *dev = &adapter->pdev->dev;
 
        if (adapter->capabilities & NX_FW_CAPABILITY_BDG) {
                /* bridged_mode control */
                if (device_create_file(dev, &dev_attr_bridged_mode)) {
-                       dev_warn(&netdev->dev,
+                       dev_warn(dev,
                                "failed to create bridged_mode sysfs entry\n");
                }
        }
@@ -2861,8 +3128,7 @@ netxen_create_sysfs_entries(struct netxen_adapter *adapter)
 static void
 netxen_remove_sysfs_entries(struct netxen_adapter *adapter)
 {
-       struct net_device *netdev = adapter->netdev;
-       struct device *dev = &netdev->dev;
+       struct device *dev = &adapter->pdev->dev;
 
        if (adapter->capabilities & NX_FW_CAPABILITY_BDG)
                device_remove_file(dev, &dev_attr_bridged_mode);
@@ -2875,6 +3141,18 @@ netxen_create_diag_entries(struct netxen_adapter *adapter)
        struct device *dev;
 
        dev = &pdev->dev;
+       if (adapter->mdump.md_template) {
+               dev_info(&pdev->dev, "%s: Supports Fw Dump Capability\n",
+                               adapter->netdev->name);
+               if (device_create_file(dev, &dev_attr_fwdump_state))
+                       dev_info(dev, "failed to create fwdump_state sysfs entry\n");
+               if (device_create_bin_file(dev, &bin_attr_fw_dump))
+                       dev_info(dev, "failed to create fw_dump sysfs entry\n");
+               if (device_create_file(dev, &dev_attr_fwdump_size))
+                       dev_info(dev, "failed to create fwdump_size sysfs entry\n");
+               if (device_create_file(dev, &dev_attr_fwdump_level))
+                       dev_info(dev, "failed to create fwdump_level sysfs entry\n");
+       }
        if (device_create_file(dev, &dev_attr_diag_mode))
                dev_info(dev, "failed to create diag_mode sysfs entry\n");
        if (device_create_bin_file(dev, &bin_attr_crb))
@@ -2893,6 +3171,13 @@ netxen_remove_diag_entries(struct netxen_adapter *adapter)
        device_remove_file(dev, &dev_attr_diag_mode);
        device_remove_bin_file(dev, &bin_attr_crb);
        device_remove_bin_file(dev, &bin_attr_mem);
+
+       if (adapter->mdump.md_template) {
+               device_remove_bin_file(dev, &bin_attr_fw_dump);
+               device_remove_file(dev, &dev_attr_fwdump_size);
+               device_remove_file(dev, &dev_attr_fwdump_level);
+               device_remove_file(dev, &dev_attr_fwdump_state);
+       }
 }
 
 #ifdef CONFIG_INET