From e67aa2d0f627bc3de3d09e6a8ae439b2a1a5627e Mon Sep 17 00:00:00 2001 From: Maxim Uvarov Date: Wed, 9 May 2012 17:37:24 -0700 Subject: [PATCH] qlcnic: driver update to v5.0.28.1 Orabug: 14055720 Update qlcnic driver to v5.0.28.1 Signed-off-by: Maxim Uvarov --- drivers/net/qlcnic/qlcnic.h | 81 ++++++- drivers/net/qlcnic/qlcnic_ctx.c | 76 ++++++- drivers/net/qlcnic/qlcnic_ethtool.c | 164 +++++++++++--- drivers/net/qlcnic/qlcnic_hdr.h | 7 + drivers/net/qlcnic/qlcnic_hw.c | 2 +- drivers/net/qlcnic/qlcnic_init.c | 11 +- drivers/net/qlcnic/qlcnic_main.c | 331 +++++++++++++++++++++++++++- 7 files changed, 613 insertions(+), 59 deletions(-) diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index f2e69beabdd68..7883d761eb260 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -36,8 +36,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 25 -#define QLCNIC_LINUX_VERSIONID "5.0.25.1" +#define _QLCNIC_LINUX_SUBVERSION 28 +#define QLCNIC_LINUX_VERSIONID "5.0.28.1" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) @@ -258,6 +258,8 @@ struct rcv_desc { (((sts_data) >> 52) & 0x1) #define qlcnic_get_lro_sts_seq_number(sts_data) \ ((sts_data) & 0x0FFFFFFFF) +#define qlcnic_get_lro_sts_mss(sts_data1) \ + ((sts_data1 >> 32) & 0x0FFFF) struct status_desc { @@ -431,6 +433,7 @@ struct qlcnic_dump_template_hdr { struct qlcnic_fw_dump { u8 clr; /* flag to indicate if dump is cleared */ + u32 pos; /* position in the dump buffer */ u8 enable; /* enable/disable dump */ u32 size; /* total size of the dump */ void *data; /* dump data area */ @@ -607,6 +610,7 @@ struct qlcnic_recv_context { #define QLCNIC_CDRP_CMD_CONFIG_PORT 0x0000002E #define QLCNIC_CDRP_CMD_TEMP_SIZE 0x0000002f #define QLCNIC_CDRP_CMD_GET_TEMP_HDR 0x00000030 +#define QLCNIC_CDRP_CMD_GET_MAC_STATS 0x00000037 #define QLCNIC_RCODE_SUCCESS 0 #define QLCNIC_RCODE_NOT_SUPPORTED 9 @@ -622,6 +626,7 @@ struct qlcnic_recv_context { #define QLCNIC_CAP0_JUMBO_CONTIGUOUS (1 << 7) #define QLCNIC_CAP0_LRO_CONTIGUOUS (1 << 8) #define QLCNIC_CAP0_VALIDOFF (1 << 11) +#define QLCNIC_CAP0_LRO_MSS (1 << 21) /* * Context state @@ -828,6 +833,9 @@ struct qlcnic_mac_list_s { #define QLCNIC_FW_CAPABILITY_FVLANTX BIT_9 #define QLCNIC_FW_CAPABILITY_HW_LRO BIT_10 #define QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK BIT_27 +#define QLCNIC_FW_CAPABILITY_MORE_CAPS BIT_31 + +#define QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG BIT_2 /* module types */ #define LINKEVENT_MODULE_NOT_PRESENT 1 @@ -917,6 +925,7 @@ struct qlcnic_ipaddr { #define QLCNIC_NEED_FLR 0x1000 #define QLCNIC_FW_RESET_OWNER 0x2000 #define QLCNIC_FW_HANG 0x4000 +#define QLCNIC_FW_LRO_MSS_CAP 0x8000 #define QLCNIC_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) @@ -1180,18 +1189,62 @@ struct qlcnic_esw_func_cfg { #define QLCNIC_STATS_ESWITCH 2 #define QLCNIC_QUERY_RX_COUNTER 0 #define QLCNIC_QUERY_TX_COUNTER 1 -#define QLCNIC_ESW_STATS_NOT_AVAIL 0xffffffffffffffffULL +#define QLCNIC_STATS_NOT_AVAIL 0xffffffffffffffffULL +#define QLCNIC_FILL_STATS(VAL1) \ + (((VAL1) == QLCNIC_STATS_NOT_AVAIL) ? 0 : VAL1) +#define QLCNIC_MAC_STATS 1 +#define QLCNIC_ESW_STATS 2 #define QLCNIC_ADD_ESW_STATS(VAL1, VAL2)\ do { \ - if (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) && \ - ((VAL2) != QLCNIC_ESW_STATS_NOT_AVAIL)) \ + if (((VAL1) == QLCNIC_STATS_NOT_AVAIL) && \ + ((VAL2) != QLCNIC_STATS_NOT_AVAIL)) \ (VAL1) = (VAL2); \ - else if (((VAL1) != QLCNIC_ESW_STATS_NOT_AVAIL) && \ - ((VAL2) != QLCNIC_ESW_STATS_NOT_AVAIL)) \ + else if (((VAL1) != QLCNIC_STATS_NOT_AVAIL) && \ + ((VAL2) != QLCNIC_STATS_NOT_AVAIL)) \ (VAL1) += (VAL2); \ } while (0) +struct qlcnic_mac_statistics{ + __le64 mac_tx_frames; + __le64 mac_tx_bytes; + __le64 mac_tx_mcast_pkts; + __le64 mac_tx_bcast_pkts; + __le64 mac_tx_pause_cnt; + __le64 mac_tx_ctrl_pkt; + __le64 mac_tx_lt_64b_pkts; + __le64 mac_tx_lt_127b_pkts; + __le64 mac_tx_lt_255b_pkts; + __le64 mac_tx_lt_511b_pkts; + __le64 mac_tx_lt_1023b_pkts; + __le64 mac_tx_lt_1518b_pkts; + __le64 mac_tx_gt_1518b_pkts; + __le64 rsvd1[3]; + + __le64 mac_rx_frames; + __le64 mac_rx_bytes; + __le64 mac_rx_mcast_pkts; + __le64 mac_rx_bcast_pkts; + __le64 mac_rx_pause_cnt; + __le64 mac_rx_ctrl_pkt; + __le64 mac_rx_lt_64b_pkts; + __le64 mac_rx_lt_127b_pkts; + __le64 mac_rx_lt_255b_pkts; + __le64 mac_rx_lt_511b_pkts; + __le64 mac_rx_lt_1023b_pkts; + __le64 mac_rx_lt_1518b_pkts; + __le64 mac_rx_gt_1518b_pkts; + __le64 rsvd2[3]; + + __le64 mac_rx_length_error; + __le64 mac_rx_length_small; + __le64 mac_rx_length_large; + __le64 mac_rx_jabber; + __le64 mac_rx_dropped; + __le64 mac_rx_crc_error; + __le64 mac_align_error; +} __packed; + struct __qlcnic_esw_statistics { __le16 context_id; __le16 version; @@ -1352,6 +1405,18 @@ enum op_codes { #define QLCNIC_ENABLE_FW_DUMP 0xaddfeed #define QLCNIC_DISABLE_FW_DUMP 0xbadfeed #define QLCNIC_FORCE_FW_RESET 0xdeaddead +#define QLCNIC_SET_QUIESCENT 0xadd00010 +#define QLCNIC_RESET_QUIESCENT 0xadd00020 + +#define QLCNIC_INVALID_KEY EINVAL + +#ifndef SPEED_UNKNOWN +#define SPEED_UNKNOWN -1 +#endif + +#ifndef DUPLEX_UNKNOWN +#define DUPLEX_UNKNOWN 0xff +#endif struct qlcnic_dump_operations { enum op_codes opcode; @@ -1510,6 +1575,7 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *, const u8, const u8, int qlcnic_get_eswitch_stats(struct qlcnic_adapter *, const u8, u8, struct __qlcnic_esw_statistics *); int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, u8, u8, u8); +int qlcnic_get_mac_stats(struct qlcnic_adapter *, struct qlcnic_mac_statistics *); extern int qlcnic_config_tso; /* @@ -1559,6 +1625,7 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring) } extern const struct ethtool_ops qlcnic_ethtool_ops; +extern const struct ethtool_ops qlcnic_ethtool_failed_ops; struct qlcnic_nic_template { int (*config_bridged_mode) (struct qlcnic_adapter *, u32); diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c index 5be12c633fb1a..188e9ee06f840 100644 --- a/drivers/net/qlcnic/qlcnic_ctx.c +++ b/drivers/net/qlcnic/qlcnic_ctx.c @@ -237,6 +237,9 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter) | QLCNIC_CAP0_VALIDOFF); cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS); + if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP) + cap |= QLCNIC_CAP0_LRO_MSS; + prq->valid_field_offset = offsetof(struct qlcnic_hostrq_rx_ctx, msix_handler); prq->txrx_sds_binding = nsds_rings - 1; @@ -905,6 +908,65 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, return err; } +/* This routine will retrieve the MAC statistics from firmware */ +int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter, + struct qlcnic_mac_statistics *mac_stats) +{ + struct qlcnic_mac_statistics *stats; + struct qlcnic_cmd_args cmd; + size_t stats_size = sizeof(struct qlcnic_mac_statistics); + dma_addr_t stats_dma_t; + void *stats_addr; + int err; + + stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size, + &stats_dma_t, GFP_KERNEL); + if (!stats_addr) { + dev_err(&adapter->pdev->dev, + "%s: Unable to allocate memory.\n", __func__); + return -ENOMEM; + } + memset(stats_addr, 0, stats_size); + memset(&cmd, 0, sizeof(cmd)); + cmd.req.cmd = QLCNIC_CDRP_CMD_GET_MAC_STATS; + cmd.req.arg1 = stats_size << 16; + cmd.req.arg2 = MSD(stats_dma_t); + cmd.req.arg3 = LSD(stats_dma_t); + + qlcnic_issue_cmd(adapter, &cmd); + err = cmd.rsp.cmd; + + if (!err) { + stats = stats_addr; + mac_stats->mac_tx_frames = le64_to_cpu(stats->mac_tx_frames); + mac_stats->mac_tx_bytes = le64_to_cpu(stats->mac_tx_bytes); + mac_stats->mac_tx_mcast_pkts = + le64_to_cpu(stats->mac_tx_mcast_pkts); + mac_stats->mac_tx_bcast_pkts = + le64_to_cpu(stats->mac_tx_bcast_pkts); + mac_stats->mac_rx_frames = le64_to_cpu(stats->mac_rx_frames); + mac_stats->mac_rx_bytes = le64_to_cpu(stats->mac_rx_bytes); + mac_stats->mac_rx_mcast_pkts = + le64_to_cpu(stats->mac_rx_mcast_pkts); + mac_stats->mac_rx_length_error = + le64_to_cpu(stats->mac_rx_length_error); + mac_stats->mac_rx_length_small = + le64_to_cpu(stats->mac_rx_length_small); + mac_stats->mac_rx_length_large = + le64_to_cpu(stats->mac_rx_length_large); + mac_stats->mac_rx_jabber = le64_to_cpu(stats->mac_rx_jabber); + mac_stats->mac_rx_dropped = le64_to_cpu(stats->mac_rx_dropped); + mac_stats->mac_rx_crc_error = le64_to_cpu(stats->mac_rx_crc_error); + } else { + dev_info(&adapter->pdev->dev, + "%s: Get mac stats failed =%d.\n", __func__, err); + } + + dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr, + stats_dma_t); + return err; +} + int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch, const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) { @@ -920,13 +982,13 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch, return -EIO; memset(esw_stats, 0, sizeof(u64)); - esw_stats->unicast_frames = QLCNIC_ESW_STATS_NOT_AVAIL; - esw_stats->multicast_frames = QLCNIC_ESW_STATS_NOT_AVAIL; - esw_stats->broadcast_frames = QLCNIC_ESW_STATS_NOT_AVAIL; - esw_stats->dropped_frames = QLCNIC_ESW_STATS_NOT_AVAIL; - esw_stats->errors = QLCNIC_ESW_STATS_NOT_AVAIL; - esw_stats->local_frames = QLCNIC_ESW_STATS_NOT_AVAIL; - esw_stats->numbytes = QLCNIC_ESW_STATS_NOT_AVAIL; + esw_stats->unicast_frames = QLCNIC_STATS_NOT_AVAIL; + esw_stats->multicast_frames = QLCNIC_STATS_NOT_AVAIL; + esw_stats->broadcast_frames = QLCNIC_STATS_NOT_AVAIL; + esw_stats->dropped_frames = QLCNIC_STATS_NOT_AVAIL; + esw_stats->errors = QLCNIC_STATS_NOT_AVAIL; + esw_stats->local_frames = QLCNIC_STATS_NOT_AVAIL; + esw_stats->numbytes = QLCNIC_STATS_NOT_AVAIL; esw_stats->context_id = eswitch; for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index ba2d92275e67f..83b096c45f38c 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -78,8 +78,46 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = { "tx numbytes", }; -#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats) +static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = { + "mac_tx_frames", + "mac_tx_bytes", + "mac_tx_mcast_pkts", + "mac_tx_bcast_pkts", + "mac_tx_pause_cnt", + "mac_tx_ctrl_pkt", + "mac_tx_lt_64b_pkts", + "mac_tx_lt_127b_pkts", + "mac_tx_lt_255b_pkts", + "mac_tx_lt_511b_pkts", + "mac_tx_lt_1023b_pkts", + "mac_tx_lt_1518b_pkts", + "mac_tx_gt_1518b_pkts", + "mac_rx_frames", + "mac_rx_bytes", + "mac_rx_mcast_pkts", + "mac_rx_bcast_pkts", + "mac_rx_pause_cnt", + "mac_rx_ctrl_pkt", + "mac_rx_lt_64b_pkts", + "mac_rx_lt_127b_pkts", + "mac_rx_lt_255b_pkts", + "mac_rx_lt_511b_pkts", + "mac_rx_lt_1023b_pkts", + "mac_rx_lt_1518b_pkts", + "mac_rx_gt_1518b_pkts", + "mac_rx_length_error", + "mac_rx_length_small", + "mac_rx_length_large", + "mac_rx_jabber", + "mac_rx_dropped", + "mac_rx_crc_error", + "mac_align_error", +}; + +#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats) +#define QLCNIC_MAC_STATS_LEN ARRAY_SIZE(qlcnic_mac_stats_strings) #define QLCNIC_DEVICE_STATS_LEN ARRAY_SIZE(qlcnic_device_gstrings_stats) +#define QLCNIC_TOTAL_STATS_LEN QLCNIC_STATS_LEN + QLCNIC_MAC_STATS_LEN static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { "Register_Test_on_offline", @@ -139,11 +177,14 @@ qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR); fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR); fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB); - sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); - - strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); - strlcpy(drvinfo->driver, qlcnic_driver_name, 32); - strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32); + snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), + "%d.%d.%d", fw_major, fw_minor, fw_build); + + strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), + sizeof(drvinfo->bus_info)); + strlcpy(drvinfo->driver, qlcnic_driver_name, sizeof(drvinfo->driver)); + strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, + sizeof(drvinfo->version)); } static int @@ -151,7 +192,6 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct qlcnic_adapter *adapter = netdev_priv(dev); int check_sfp_module = 0; - u16 pcifn = adapter->ahw->pci_func; /* read which mode */ if (adapter->ahw->port_type == QLCNIC_GBE) { @@ -190,10 +230,8 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) goto skip; } - val = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn)); - ethtool_cmd_speed_set(ecmd, P3P_LINK_SPEED_MHZ * - P3P_LINK_SPEED_VAL(pcifn, val)); - ecmd->duplex = DUPLEX_FULL; + ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN); + ecmd->duplex = DUPLEX_UNKNOWN; ecmd->autoneg = AUTONEG_DISABLE; } else return -EIO; @@ -417,9 +455,6 @@ qlcnic_get_ringparam(struct net_device *dev, ring->rx_max_pending = adapter->max_rxd; ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd; ring->tx_max_pending = MAX_CMD_DESCRIPTORS; - - ring->rx_mini_max_pending = 0; - ring->rx_mini_pending = 0; } static u32 @@ -646,8 +681,8 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset) return QLCNIC_TEST_LEN; case ETH_SS_STATS: if (adapter->flags & QLCNIC_ESWITCH_ENABLED) - return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN; - return QLCNIC_STATS_LEN; + return QLCNIC_TOTAL_STATS_LEN + QLCNIC_DEVICE_STATS_LEN; + return QLCNIC_TOTAL_STATS_LEN; default: return -EOPNOTSUPP; } @@ -848,7 +883,7 @@ static void qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data) { struct qlcnic_adapter *adapter = netdev_priv(dev); - int index, i; + int index, i, j; switch (stringset) { case ETH_SS_TEST: @@ -861,6 +896,11 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data) qlcnic_gstrings_stats[index].stat_string, ETH_GSTRING_LEN); } + for (j = 0; j < QLCNIC_MAC_STATS_LEN; index++, j++) { + memcpy(data + index * ETH_GSTRING_LEN, + qlcnic_mac_stats_strings[j], + ETH_GSTRING_LEN); + } if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) { @@ -871,22 +911,64 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data) } } -#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \ - (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1) - static void -qlcnic_fill_device_stats(int *index, u64 *data, - struct __qlcnic_esw_statistics *stats) +qlcnic_fill_stats(int *index, u64 *data, void *stats, int type) { int ind = *index; - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames); - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames); - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames); - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames); - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors); - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames); - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes); + if (type == QLCNIC_MAC_STATS) { + struct qlcnic_mac_statistics *mac_stats = + (struct qlcnic_mac_statistics *)stats; + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts); + data[ind++] = + QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts); + data[ind++] = + QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts); + data[ind++] = + QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts); + data[ind++] = + QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts); + data[ind++] = + QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts); + data[ind++] = + QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_align_error); + } else if (type == QLCNIC_ESW_STATS) { + struct __qlcnic_esw_statistics *esw_stats = + (struct __qlcnic_esw_statistics *)stats; + data[ind++] = QLCNIC_FILL_STATS(esw_stats->unicast_frames); + data[ind++] = QLCNIC_FILL_STATS(esw_stats->multicast_frames); + data[ind++] = QLCNIC_FILL_STATS(esw_stats->broadcast_frames); + data[ind++] = QLCNIC_FILL_STATS(esw_stats->dropped_frames); + data[ind++] = QLCNIC_FILL_STATS(esw_stats->errors); + data[ind++] = QLCNIC_FILL_STATS(esw_stats->local_frames); + data[ind++] = QLCNIC_FILL_STATS(esw_stats->numbytes); + } *index = ind; } @@ -897,6 +979,7 @@ qlcnic_get_ethtool_stats(struct net_device *dev, { struct qlcnic_adapter *adapter = netdev_priv(dev); struct qlcnic_esw_statistics port_stats; + struct qlcnic_mac_statistics mac_stats; int index, ret; for (index = 0; index < QLCNIC_STATS_LEN; index++) { @@ -908,6 +991,11 @@ qlcnic_get_ethtool_stats(struct net_device *dev, sizeof(u64)) ? *(u64 *)p:(*(u32 *)p); } + /* Retrieve MAC statistics from firmware */ + memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics)); + qlcnic_get_mac_stats(adapter, &mac_stats); + qlcnic_fill_stats(&index, data, &mac_stats, QLCNIC_MAC_STATS); + if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; @@ -917,14 +1005,14 @@ qlcnic_get_ethtool_stats(struct net_device *dev, if (ret) return; - qlcnic_fill_device_stats(&index, data, &port_stats.rx); + qlcnic_fill_stats(&index, data, &port_stats.rx, QLCNIC_ESW_STATS); ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func, QLCNIC_QUERY_TX_COUNTER, &port_stats.tx); if (ret) return; - qlcnic_fill_device_stats(&index, data, &port_stats.tx); + qlcnic_fill_stats(&index, data, &port_stats.tx, QLCNIC_ESW_STATS); } static int qlcnic_set_led(struct net_device *dev, @@ -1149,8 +1237,7 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, if (!fw_dump->clr) { netdev_info(netdev, "Dump not available\n"); - qlcnic_api_unlock(adapter); - return -EINVAL; + return 0; } /* Copy template header first */ copy_sz = fw_dump->tmpl_hdr->size; @@ -1168,7 +1255,7 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, vfree(fw_dump->data); fw_dump->data = NULL; fw_dump->clr = 0; - + netdev_info(netdev, "extracted the FW dump Successfully\n"); return 0; } @@ -1186,7 +1273,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val) return ret; } if (fw_dump->clr) { - dev_info(&adapter->pdev->dev, + netdev_info(netdev, "Previous dump not cleared, not forcing dump\n"); return ret; } @@ -1256,3 +1343,10 @@ const struct ethtool_ops qlcnic_ethtool_ops = { .get_dump_data = qlcnic_get_dump_data, .set_dump = qlcnic_set_dump, }; + +const struct ethtool_ops qlcnic_ethtool_failed_ops = { + .get_settings = qlcnic_get_settings, + .get_drvinfo = qlcnic_get_drvinfo, + .set_msglevel = qlcnic_set_msglevel, + .get_msglevel = qlcnic_get_msglevel, +}; diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h index a52819303d1b2..28a6b28192e30 100644 --- a/drivers/net/qlcnic/qlcnic_hdr.h +++ b/drivers/net/qlcnic/qlcnic_hdr.h @@ -588,6 +588,7 @@ enum { #define CRB_DRIVER_VERSION (QLCNIC_REG(0x2a0)) #define CRB_FW_CAPABILITIES_1 (QLCNIC_CAM_RAM(0x128)) +#define CRB_FW_CAPABILITIES_2 (QLCNIC_CAM_RAM(0x12c)) #define CRB_MAC_BLOCK_START (QLCNIC_CAM_RAM(0x1c0)) /* @@ -704,6 +705,8 @@ enum { #define QLCNIC_DEV_FAILED 0x6 #define QLCNIC_DEV_QUISCENT 0x7 +#define QLCNIC_DEV_BADBAD 0xbad0bad0 + #define QLCNIC_DEV_NPAR_NON_OPER 0 /* NON Operational */ #define QLCNIC_DEV_NPAR_OPER 1 /* NPAR Operational */ #define QLCNIC_DEV_NPAR_OPER_TIMEO 30 /* Operational time out */ @@ -776,6 +779,10 @@ struct qlcnic_legacy_intr_set { #define FLASH_ROM_WINDOW 0x42110030 #define FLASH_ROM_DATA 0x42150000 + +static const u32 FW_DUMP_LEVELS[] = { + 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff }; + static const u32 MIU_TEST_READ_DATA[] = { 0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC, }; diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index bcb81e47543a3..4b1491bf35c5b 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c @@ -1775,7 +1775,7 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) fw_dump->clr = 1; snprintf(mesg, sizeof(mesg), "FW_DUMP=%s", adapter->netdev->name); - dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n", + netdev_info(adapter->netdev, "Dump data, %d bytes captured\n", fw_dump->size); /* Send a udev event to notify availability of FW dump */ kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg); diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 50248e8456d32..ccc01f48a5878 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -1369,7 +1369,13 @@ qlcnic_handle_linkevent(struct qlcnic_adapter *adapter, adapter->module_type = module; adapter->link_autoneg = autoneg; - adapter->link_speed = link_speed; + + if (link_status) { + adapter->link_speed = link_speed; + } else { + adapter->link_speed = SPEED_UNKNOWN; + adapter->link_duplex = DUPLEX_UNKNOWN; + } } static void @@ -1648,6 +1654,9 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, length = skb->len; + if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP) + skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1); + if (vid != 0xffff) __vlan_hwaccel_put_tag(skb, vid); netif_receive_skb(skb); diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 6a0358f480db8..1aa0d4603e97a 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -338,6 +338,10 @@ static const struct net_device_ops qlcnic_netdev_ops = { #endif }; +static const struct net_device_ops qlcnic_netdev_failed_ops = { + .ndo_open = qlcnic_open, +}; + static struct qlcnic_nic_template qlcnic_ops = { .config_bridged_mode = qlcnic_config_bridged_mode, .config_led = qlcnic_config_led, @@ -1130,6 +1134,8 @@ static int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) { int ring; + u32 capab2; + struct qlcnic_host_rds_ring *rds_ring; if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) @@ -1140,6 +1146,12 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) if (qlcnic_set_eswitch_port_config(adapter)) return -EIO; + if (adapter->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) { + capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2); + if (capab2 & QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG) + adapter->flags |= QLCNIC_FW_LRO_MSS_CAP; + } + if (qlcnic_fw_create_ctx(adapter)) return -EIO; @@ -1209,6 +1221,7 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev) qlcnic_napi_disable(adapter); qlcnic_fw_destroy_ctx(adapter); + adapter->flags &= ~QLCNIC_FW_LRO_MSS_CAP; qlcnic_reset_rx_buffers_list(adapter); qlcnic_release_tx_buffers(adapter); @@ -1456,8 +1469,10 @@ qlcnic_reset_context(struct qlcnic_adapter *adapter) if (netif_running(netdev)) { err = qlcnic_attach(adapter); - if (!err) + if (!err) { __qlcnic_up(adapter, netdev); + qlcnic_restore_indev_addr(netdev, NETDEV_UP); + } } netif_device_attach(netdev); @@ -1574,7 +1589,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev = alloc_etherdev(sizeof(struct qlcnic_adapter)); if (!netdev) { - dev_err(&pdev->dev, "failed to allocate net_device\n"); err = -ENOMEM; goto err_out_free_res; } @@ -1620,8 +1634,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = adapter->nic_ops->start_firmware(adapter); if (err) { - dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n"); - goto err_out_decr_ref; + dev_err(&pdev->dev, "Loading fw failed. Please Reboot\n" + "\t\tIf reboot doesn't help, try flashing the card\n"); + goto err_out_maintenance_mode; } if (qlcnic_read_mac_addr(adapter)) @@ -1692,6 +1707,18 @@ err_out_disable_pdev: pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); return err; + +err_out_maintenance_mode: + netdev->netdev_ops = &qlcnic_netdev_failed_ops; + SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops); + err = register_netdev(netdev); + if (err) { + dev_err(&pdev->dev, "failed to register net device\n"); + goto err_out_decr_ref; + } + pci_set_drvdata(pdev, adapter); + qlcnic_create_diag_entries(adapter); + return 0; } static void __devexit qlcnic_remove(struct pci_dev *pdev) @@ -1828,8 +1855,14 @@ done: static int qlcnic_open(struct net_device *netdev) { struct qlcnic_adapter *adapter = netdev_priv(netdev); + u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); int err; + if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) { + netdev_err(netdev, "Device in FAILED state\n"); + return -EIO; + } + netif_carrier_off(netdev); err = qlcnic_attach(adapter); @@ -3015,6 +3048,12 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) return; state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) { + netdev_err(adapter->netdev, + "Device is in FAILED state, Please Reboot\n"); + qlcnic_api_unlock(adapter); + return; + } if (state == QLCNIC_DEV_READY) { QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET); @@ -3058,6 +3097,9 @@ qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter) while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) msleep(10); + if (!adapter->fw_work.work.func) + return; + cancel_delayed_work_sync(&adapter->fw_work); } @@ -3158,7 +3200,7 @@ qlcnic_check_health(struct qlcnic_adapter *adapter) QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c), QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c)); peg_status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1); - if (LSW(MSB(peg_status)) == 0x67) + if (QLCNIC_FWERROR_CODE(peg_status) == 0x67) dev_err(&adapter->pdev->dev, "Firmware aborted with error code 0x00006700. " "Device is being reset.\n"); @@ -3762,6 +3804,237 @@ qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj, return size; } +static ssize_t +qlcnic_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + void *tmp_buf; + int i, copy_sz, pos; + u32 *buf_ptr, *hdr_ptr; + size_t data_sz, ret = 0, tmp_sz = 0; + struct device *dev = container_of(kobj, struct device, kobj); + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; + + if (!fw_dump->tmpl_hdr) { + netdev_err(adapter->netdev, "FW Dump not supported\n"); + return -ENOTSUPP; + } + + if (offset >= size || offset < 0) + return 0; + + if (!fw_dump->clr) { + dev_info(dev, "Dump not available\n"); + return 0; + } + + copy_sz = fw_dump->tmpl_hdr->size - fw_dump->pos; + /* Copy template header first */ + if (copy_sz > 0) { + if (copy_sz < size) + tmp_sz = copy_sz; + else + tmp_sz = size; + tmp_buf = vmalloc(tmp_sz); + if (!tmp_buf) + return -EIO; + memset(tmp_buf, 0, tmp_sz); + buf_ptr = (u32 *) tmp_buf; + hdr_ptr = (u32 *) ((void *) fw_dump->tmpl_hdr + fw_dump->pos); + for (i = 0; i < tmp_sz/sizeof(u32); i++) + *buf_ptr++ = cpu_to_le32(*hdr_ptr++); + + ret = memory_read_from_buffer((void *) buf, tmp_sz, &offset, + (void *) tmp_buf, tmp_sz); + fw_dump->pos += tmp_sz; + data_sz = size - tmp_sz; + vfree(tmp_buf); + tmp_buf = NULL; + } else { + copy_sz = fw_dump->tmpl_hdr->size + fw_dump->size - + fw_dump->pos; + if (copy_sz >= size) + data_sz = size; + else + data_sz = copy_sz; + } + /* Copy captured dump data */ + if (data_sz > 0) { + pos = fw_dump->pos - fw_dump->tmpl_hdr->size; + ret = memory_read_from_buffer((void *) (buf + tmp_sz), data_sz, + &offset, (void *) (fw_dump->data + pos), data_sz); + fw_dump->pos += data_sz; + } + /* free dump area once the whoel dump data has been captured */ + if (fw_dump->pos == fw_dump->size + fw_dump->tmpl_hdr->size) { + vfree(fw_dump->data); + fw_dump->size = 0; + fw_dump->data = NULL; + fw_dump->clr = 0; + fw_dump->pos = 0; + netdev_info(adapter->netdev, + "extracted the FW dump Successfully\n"); + } + return ret; +} + +static ssize_t +qlcnic_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 qlcnic_adapter *adapter = dev_get_drvdata(dev); + struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; + struct net_device *netdev = adapter->netdev; + int err = size; + unsigned long data; + u32 state; + + data = simple_strtoul(buf, NULL, 16); + rtnl_lock(); + switch (data) { + case QLCNIC_FORCE_FW_DUMP_KEY: + if (!fw_dump->tmpl_hdr) { + netdev_err(netdev, "FW dump not supported\n"); + err = -ENOTSUPP; + goto out; + } + + if (!fw_dump->enable) { + netdev_info(netdev, "FW dump not enabled\n"); + goto out; + } + if (fw_dump->clr) { + netdev_info(netdev, + "Previous dump not cleared, not forcing dump\n"); + goto out; + } + netdev_info(netdev, "Forcing a fw dump\n"); + qlcnic_dev_request_reset(adapter); + break; + case QLCNIC_DISABLE_FW_DUMP: + if (fw_dump->enable && fw_dump->tmpl_hdr) { + netdev_info(netdev, "Disabling FW dump\n"); + fw_dump->enable = 0; + } + break; + case QLCNIC_ENABLE_FW_DUMP: + if (!fw_dump->tmpl_hdr) { + netdev_err(netdev, "FW dump not supported\n"); + err = -ENOTSUPP; + goto out; + } + if (!fw_dump->enable) { + netdev_info(netdev, "Enabling FW dump\n"); + fw_dump->enable = 1; + } + break; + case QLCNIC_FORCE_FW_RESET: + netdev_info(netdev, "Forcing a FW reset\n"); + qlcnic_dev_request_reset(adapter); + adapter->flags &= ~QLCNIC_FW_RESET_OWNER; + break; + case QLCNIC_SET_QUIESCENT: + case QLCNIC_RESET_QUIESCENT: + state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) + netdev_info(netdev, "Device in FAILED state\n"); + break; + default: + netdev_err(netdev, "Invalid dump key, 0x%lx\n", data); + err = -QLCNIC_INVALID_KEY; + break; + } +out: + rtnl_unlock(); + return err; +} + +static ssize_t +qlcnic_store_fwdump_level(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int i; + unsigned long int val; + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + struct net_device *netdev = adapter->netdev; + + val = simple_strtoul(buf, NULL, 16); + + for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) { + if (val == FW_DUMP_LEVELS[i]) { + rtnl_lock(); + adapter->ahw->fw_dump.tmpl_hdr->drv_cap_mask = val; + rtnl_unlock(); + netdev_info(netdev, "Driver mask changed to: 0x%x\n", + adapter->ahw->fw_dump.tmpl_hdr->drv_cap_mask); + return size; + } + } + netdev_info(netdev, "Invalid Dump Level: 0x%lx\n", + (unsigned long int) val); + return -EINVAL; +} + +static ssize_t +qlcnic_show_fwdump_level(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + u32 size = adapter->ahw->fw_dump.tmpl_hdr->drv_cap_mask; + return sprintf(buf, "%u\n", size); +} + +static ssize_t +qlcnic_store_fwdump_size(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + return -EIO; +} + +static ssize_t +qlcnic_show_fwdump_size(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + u32 size = 0; + if (adapter->ahw->fw_dump.clr) + size = adapter->ahw->fw_dump.size + + adapter->ahw->fw_dump.tmpl_hdr->size; + return sprintf(buf, "%u\n", size); +} + +static ssize_t +qlcnic_show_fwdump_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qlcnic_adapter *adapter = dev_get_drvdata(dev); + u32 state = adapter->ahw->fw_dump.enable; + return sprintf(buf, "%u\n", state); +} + +static ssize_t +qlcnic_store_fwdump_state(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + return -EIO; +} + +static struct device_attribute dev_attr_fwdump_size = { + .attr = {.name = "fwdump_size", .mode = (S_IRUGO | S_IWUSR)}, + .show = qlcnic_show_fwdump_size, + .store = qlcnic_store_fwdump_size, +}; + +static struct device_attribute dev_attr_fwdump_level = { + .attr = {.name = "fwdump_level", .mode = (S_IRUGO | S_IWUSR)}, + .show = qlcnic_show_fwdump_level, + .store = qlcnic_store_fwdump_level, +}; + static struct bin_attribute bin_attr_crb = { .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)}, .size = 0, @@ -3776,6 +4049,19 @@ static struct bin_attribute bin_attr_mem = { .write = qlcnic_sysfs_write_mem, }; +static struct bin_attribute bin_attr_fw_dump = { + .attr = {.name = "fw_dump", .mode = (S_IRUGO | S_IWUSR)}, + .size = 0, + .read = qlcnic_sysfs_read_fw_dump, + .write = qlcnic_sysfs_write_fw_dump, +}; + +static struct device_attribute dev_attr_fwdump_state = { + .attr = {.name = "fwdump_state", .mode = (S_IRUGO | S_IWUSR)}, + .show = qlcnic_show_fwdump_state, + .store = qlcnic_store_fwdump_state, +}; + static int validate_pm_config(struct qlcnic_adapter *adapter, struct qlcnic_pm_func_cfg *pm_cfg, int count) @@ -4321,6 +4607,7 @@ static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) { struct device *dev = &adapter->pdev->dev; + u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); if (device_create_bin_file(dev, &bin_attr_port_stats)) dev_info(dev, "failed to create port stats sysfs entry"); @@ -4329,16 +4616,32 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) return; if (device_create_file(dev, &dev_attr_diag_mode)) dev_info(dev, "failed to create diag_mode sysfs entry\n"); - if (device_create_file(dev, &dev_attr_beacon)) - dev_info(dev, "failed to create beacon sysfs entry"); if (device_create_file(dev, &dev_attr_elb_mode)) dev_info(dev, "failed to create elb_mode sysfs entry\n"); if (device_create_bin_file(dev, &bin_attr_crb)) dev_info(dev, "failed to create crb sysfs entry\n"); if (device_create_bin_file(dev, &bin_attr_mem)) dev_info(dev, "failed to create mem sysfs entry\n"); + if (device_create_bin_file(dev, &bin_attr_fw_dump)) + dev_info(dev, "failed to create fw_dump sysfs entry"); + if (adapter->ahw->fw_dump.tmpl_hdr) { + if (device_create_file(dev, &dev_attr_fwdump_size)) + dev_info(dev, + "failed to create fwdump_size sysfs entry"); + if (device_create_file(dev, &dev_attr_fwdump_level)) + dev_info(dev, + "failed to create fwdump_level sysfs entry"); + if (device_create_file(dev, &dev_attr_fwdump_state)) + dev_info(dev, "failed to create fwdump_state sysfs entry"); + } + + if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) + return; + if (device_create_file(dev, &dev_attr_beacon)) + dev_info(dev, "failed to create beacon sysfs entry"); if (device_create_bin_file(dev, &bin_attr_pci_config)) dev_info(dev, "failed to create pci config sysfs entry"); + if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; if (device_create_bin_file(dev, &bin_attr_esw_config)) @@ -4357,17 +4660,29 @@ static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) { struct device *dev = &adapter->pdev->dev; + u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); device_remove_bin_file(dev, &bin_attr_port_stats); if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) return; device_remove_file(dev, &dev_attr_diag_mode); - device_remove_file(dev, &dev_attr_beacon); device_remove_file(dev, &dev_attr_elb_mode); device_remove_bin_file(dev, &bin_attr_crb); device_remove_bin_file(dev, &bin_attr_mem); + device_remove_bin_file(dev, &bin_attr_fw_dump); + if (adapter->ahw->fw_dump.tmpl_hdr) { + device_remove_file(dev, &dev_attr_fwdump_size); + device_remove_file(dev, &dev_attr_fwdump_level); + device_remove_file(dev, &dev_attr_fwdump_state); + } + + if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) + return; + + device_remove_file(dev, &dev_attr_beacon); device_remove_bin_file(dev, &bin_attr_pci_config); + if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; device_remove_bin_file(dev, &bin_attr_esw_config); -- 2.50.1