From 21252377bb2b9f038b4c9d829f69cafca4a4c1c7 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Fri, 6 Feb 2015 08:18:42 -0500 Subject: [PATCH] be2net: process port misconfig async event This patch adds support for processing the port misconfigure async event generated by the FW. This event is generated typically when an optical module is incorrectly installed or is faulty. This patch also moves the port_name field to the adapter struct for logging the event. As the be_cmd_query_port_name() call is now moved to be_get_config(), it is modified to use the mailbox instead of MCCQ Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 6 + drivers/net/ethernet/emulex/benet/be_cmds.c | 119 ++++++++++++++++---- drivers/net/ethernet/emulex/benet/be_cmds.h | 16 ++- drivers/net/ethernet/emulex/benet/be_main.c | 28 ++++- 4 files changed, 139 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 98716e1c7615..27de37aa90af 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -368,6 +368,7 @@ enum vf_state { #define BE_FLAGS_QNQ_ASYNC_EVT_RCVD BIT(7) #define BE_FLAGS_VXLAN_OFFLOADS BIT(8) #define BE_FLAGS_SETUP_DONE BIT(9) +#define BE_FLAGS_EVT_INCOMPATIBLE_SFP BIT(10) #define BE_UC_PMAC_COUNT 30 #define BE_VF_UC_PMAC_COUNT 2 @@ -377,6 +378,8 @@ enum vf_state { #define LANCER_DELETE_FW_DUMP 0x2 struct phy_info { +/* From SFF-8472 spec */ +#define SFP_VENDOR_NAME_LEN 17 u8 transceiver; u8 autoneg; u8 fc_autoneg; @@ -390,6 +393,8 @@ struct phy_info { u32 advertising; u32 supported; u8 cable_type; + u8 vendor_name[SFP_VENDOR_NAME_LEN]; + u8 vendor_pn[SFP_VENDOR_NAME_LEN]; }; struct be_resources { @@ -478,6 +483,7 @@ struct be_adapter { bool hw_error; u32 port_num; + char port_name; u8 mc_type; u32 function_mode; u32 function_caps; diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index ceae6235e707..36916cfa70f9 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -19,6 +19,22 @@ #include "be.h" #include "be_cmds.h" +static char *be_port_misconfig_evt_desc[] = { + "A valid SFP module detected", + "Optics faulted/ incorrectly installed/ not installed.", + "Optics of two types installed.", + "Incompatible optics.", + "Unknown port SFP status" +}; + +static char *be_port_misconfig_remedy_desc[] = { + "", + "Reseat optics. If issue not resolved, replace", + "Remove one optic or install matching pair of optics", + "Replace with compatible optics for card to function", + "" +}; + static struct be_cmd_priv_map cmd_priv_map[] = { { OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, @@ -249,6 +265,29 @@ static void be_async_link_state_process(struct be_adapter *adapter, evt->port_link_status & LINK_STATUS_MASK); } +static void be_async_port_misconfig_event_process(struct be_adapter *adapter, + struct be_mcc_compl *compl) +{ + struct be_async_event_misconfig_port *evt = + (struct be_async_event_misconfig_port *)compl; + u32 sfp_mismatch_evt = le32_to_cpu(evt->event_data_word1); + struct device *dev = &adapter->pdev->dev; + u8 port_misconfig_evt; + + port_misconfig_evt = + ((sfp_mismatch_evt >> (adapter->hba_port_num * 8)) & 0xff); + + /* Log an error message that would allow a user to determine + * whether the SFPs have an issue + */ + dev_info(dev, "Port %c: %s %s", adapter->port_name, + be_port_misconfig_evt_desc[port_misconfig_evt], + be_port_misconfig_remedy_desc[port_misconfig_evt]); + + if (port_misconfig_evt == INCOMPATIBLE_SFP) + adapter->flags |= BE_FLAGS_EVT_INCOMPATIBLE_SFP; +} + /* Grp5 CoS Priority evt */ static void be_async_grp5_cos_priority_process(struct be_adapter *adapter, struct be_mcc_compl *compl) @@ -334,6 +373,16 @@ static void be_async_dbg_evt_process(struct be_adapter *adapter, } } +static void be_async_sliport_evt_process(struct be_adapter *adapter, + struct be_mcc_compl *cmp) +{ + u8 event_type = (cmp->flags >> ASYNC_EVENT_TYPE_SHIFT) & + ASYNC_EVENT_TYPE_MASK; + + if (event_type == ASYNC_EVENT_PORT_MISCONFIG) + be_async_port_misconfig_event_process(adapter, cmp); +} + static inline bool is_link_state_evt(u32 flags) { return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == @@ -352,6 +401,12 @@ static inline bool is_dbg_evt(u32 flags) ASYNC_EVENT_CODE_QNQ; } +static inline bool is_sliport_evt(u32 flags) +{ + return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) == + ASYNC_EVENT_CODE_SLIPORT; +} + static void be_mcc_event_process(struct be_adapter *adapter, struct be_mcc_compl *compl) { @@ -361,6 +416,8 @@ static void be_mcc_event_process(struct be_adapter *adapter, be_async_grp5_evt_process(adapter, compl); else if (is_dbg_evt(compl->flags)) be_async_dbg_evt_process(adapter, compl); + else if (is_sliport_evt(compl->flags)) + be_async_sliport_evt_process(adapter, compl); } static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter) @@ -1171,9 +1228,15 @@ static int be_cmd_mccq_ext_create(struct be_adapter *adapter, ctxt, 1); } - /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */ - req->async_event_bitmap[0] = cpu_to_le32(0x00000022); - req->async_event_bitmap[0] |= cpu_to_le32(1 << ASYNC_EVENT_CODE_QNQ); + /* Subscribe to Link State, Sliport Event and Group 5 Events + * (bits 1, 5 and 17 set) + */ + req->async_event_bitmap[0] = + cpu_to_le32(BIT(ASYNC_EVENT_CODE_LINK_STATE) | + BIT(ASYNC_EVENT_CODE_GRP_5) | + BIT(ASYNC_EVENT_CODE_QNQ) | + BIT(ASYNC_EVENT_CODE_SLIPORT)); + be_dws_cpu_to_le(ctxt, sizeof(req->context)); be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); @@ -2344,6 +2407,24 @@ int be_cmd_query_cable_type(struct be_adapter *adapter) return status; } +int be_cmd_query_sfp_info(struct be_adapter *adapter) +{ + u8 page_data[PAGE_DATA_LEN]; + int status; + + status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, + page_data); + if (!status) { + strlcpy(adapter->phy.vendor_name, page_data + + SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1); + strlcpy(adapter->phy.vendor_pn, + page_data + SFP_VENDOR_PN_OFFSET, + SFP_VENDOR_NAME_LEN - 1); + } + + return status; +} + int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name) { struct lancer_cmd_req_delete_object *req; @@ -3437,42 +3518,34 @@ err: return status; } -int be_cmd_query_port_name(struct be_adapter *adapter, u8 *port_name) +int be_cmd_query_port_name(struct be_adapter *adapter) { - struct be_mcc_wrb *wrb; struct be_cmd_req_get_port_name *req; + struct be_mcc_wrb *wrb; int status; - if (!lancer_chip(adapter)) { - *port_name = adapter->hba_port_num + '0'; - return 0; - } - - spin_lock_bh(&adapter->mcc_lock); - - wrb = wrb_from_mccq(adapter); - if (!wrb) { - status = -EBUSY; - goto err; - } + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_PORT_NAME, sizeof(*req), wrb, NULL); - req->hdr.version = 1; + if (!BEx_chip(adapter)) + req->hdr.version = 1; - status = be_mcc_notify_wait(adapter); + status = be_mbox_notify_wait(adapter); if (!status) { struct be_cmd_resp_get_port_name *resp = embedded_payload(wrb); - *port_name = resp->port_name[adapter->hba_port_num]; + adapter->port_name = resp->port_name[adapter->hba_port_num]; } else { - *port_name = adapter->hba_port_num + '0'; + adapter->port_name = adapter->hba_port_num + '0'; } -err: - spin_unlock_bh(&adapter->mcc_lock); + + mutex_unlock(&adapter->mbox_lock); return status; } diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index cf9d87086546..db761e8e42a3 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -102,6 +102,8 @@ struct be_mcc_compl { #define ASYNC_EVENT_PVID_STATE 0x3 #define ASYNC_EVENT_CODE_QNQ 0x6 #define ASYNC_DEBUG_EVENT_TYPE_QNQ 1 +#define ASYNC_EVENT_CODE_SLIPORT 0x11 +#define ASYNC_EVENT_PORT_MISCONFIG 0x9 enum { LINK_DOWN = 0x0, @@ -169,6 +171,15 @@ struct be_async_event_qnq { u32 flags; } __packed; +#define INCOMPATIBLE_SFP 0x3 +/* async event indicating misconfigured port */ +struct be_async_event_misconfig_port { + u32 event_data_word1; + u32 event_data_word2; + u32 rsvd0; + u32 flags; +} __packed; + struct be_mcc_mailbox { struct be_mcc_wrb wrb; struct be_mcc_compl compl; @@ -1028,6 +1039,8 @@ enum { #define SFP_PLUS_SFF_8472_COMP 0x5E #define SFP_PLUS_CABLE_TYPE_OFFSET 0x8 #define SFP_PLUS_COPPER_CABLE 0x4 +#define SFP_VENDOR_NAME_OFFSET 0x14 +#define SFP_VENDOR_PN_OFFSET 0x28 #define PAGE_DATA_LEN 256 struct be_cmd_resp_port_type { @@ -2259,6 +2272,7 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, int be_cmd_read_port_transceiver_data(struct be_adapter *adapter, u8 page_num, u8 *data); int be_cmd_query_cable_type(struct be_adapter *adapter); +int be_cmd_query_sfp_info(struct be_adapter *adapter); int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 flash_oper, u32 flash_opcode, u32 img_offset, u32 buf_size); @@ -2326,7 +2340,7 @@ int lancer_initiate_dump(struct be_adapter *adapter); int lancer_delete_dump(struct be_adapter *adapter); bool dump_present(struct be_adapter *adapter); int lancer_test_and_set_rdy_state(struct be_adapter *adapter); -int be_cmd_query_port_name(struct be_adapter *adapter, u8 *port_name); +int be_cmd_query_port_name(struct be_adapter *adapter); int be_cmd_get_func_config(struct be_adapter *adapter, struct be_resources *res); int be_cmd_get_profile_config(struct be_adapter *adapter, diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 617038fa92f0..195d357e2f3f 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3682,7 +3682,9 @@ static int be_get_config(struct be_adapter *adapter) if (status) return status; - if (be_physfn(adapter)) { + be_cmd_query_port_name(adapter); + + if (be_physfn(adapter)) { status = be_cmd_get_active_profile(adapter, &profile_id); if (!status) dev_info(&adapter->pdev->dev, @@ -5052,6 +5054,20 @@ static void be_func_recovery_task(struct work_struct *work) msecs_to_jiffies(1000)); } +static void be_log_sfp_info(struct be_adapter *adapter) +{ + int status; + + status = be_cmd_query_sfp_info(adapter); + if (!status) { + dev_err(&adapter->pdev->dev, + "Unqualified SFP+ detected on %c from %s part no: %s", + adapter->port_name, adapter->phy.vendor_name, + adapter->phy.vendor_pn); + } + adapter->flags &= ~BE_FLAGS_EVT_INCOMPATIBLE_SFP; +} + static void be_worker(struct work_struct *work) { struct be_adapter *adapter = @@ -5090,6 +5106,9 @@ static void be_worker(struct work_struct *work) be_eqd_update(adapter); + if (adapter->flags & BE_FLAGS_EVT_INCOMPATIBLE_SFP) + be_log_sfp_info(adapter); + reschedule: adapter->work_counter++; schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); @@ -5158,10 +5177,9 @@ static inline char *nic_name(struct pci_dev *pdev) static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) { - int status = 0; struct be_adapter *adapter; struct net_device *netdev; - char port_name; + int status = 0; dev_info(&pdev->dev, "%s version is %s\n", DRV_NAME, DRV_VER); @@ -5255,10 +5273,8 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) schedule_delayed_work(&adapter->func_recovery_work, msecs_to_jiffies(1000)); - be_cmd_query_port_name(adapter, &port_name); - dev_info(&pdev->dev, "%s: %s %s port %c\n", nic_name(pdev), - func_name(adapter), mc_name(adapter), port_name); + func_name(adapter), mc_name(adapter), adapter->port_name); return 0; -- 2.20.1