lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1423228723-10919-9-git-send-email-sathya.perla@emulex.com>
Date:	Fri, 6 Feb 2015 08:18:42 -0500
From:	Sathya Perla <sathya.perla@...lex.com>
To:	<netdev@...r.kernel.org>
Subject: [PATCH net-next 8/9] be2net: process port misconfig async event

From: Vasundhara Volam <vasundhara.volam@...lex.com>

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 <sathya.perla@...lex.com>
---
 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 98716e1..27de37a 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 1c85bbf..f0276f5 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 cf9d870..db761e8e 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 fbe7b6f..5936b24 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,
@@ -5051,6 +5053,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 =
@@ -5089,6 +5105,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));
@@ -5157,10 +5176,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);
 
@@ -5254,10 +5272,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.2.0

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ