Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 1 Feb 2019 20:42:49 +0000 (UTC)
From:      Navdeep Parhar <np@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r343666 - in head/sys/dev/cxgbe: . common
Message-ID:  <201902012042.x11Kgner081445@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: np
Date: Fri Feb  1 20:42:49 2019
New Revision: 343666
URL: https://svnweb.freebsd.org/changeset/base/343666

Log:
  cxgbe(4): Improved error reporting and diagnostics.
  
  "slow" interrupt handler:
  - Expand the list of INT_CAUSE registers known to the driver.
  - Add decode information for many more bits but decouple it from the
    rest of intr_info so that it is entirely optional.
  - Call t4_fatal_err exactly once, and from the top level PL intr handler.
  
  t4_fatal_err:
  - Use t4_shutdown_adapter from the common code to stop the adapter.
  - Stop servicing slow interrupts after the first fatal one.
  
  Driver/firmware interaction:
  - CH_DUMP_MBOX: note whether the mailbox being dumped is a command or a
    reply or something else.
  - Log the raw value of pcie_fw for some errors.
  - Use correct log levels (debug vs. error).
  
  Sponsored by:	Chelsio Communications

Modified:
  head/sys/dev/cxgbe/adapter.h
  head/sys/dev/cxgbe/common/common.h
  head/sys/dev/cxgbe/common/t4_hw.c
  head/sys/dev/cxgbe/t4_main.c
  head/sys/dev/cxgbe/t4_sge.c

Modified: head/sys/dev/cxgbe/adapter.h
==============================================================================
--- head/sys/dev/cxgbe/adapter.h	Fri Feb  1 20:28:15 2019	(r343665)
+++ head/sys/dev/cxgbe/adapter.h	Fri Feb  1 20:42:49 2019	(r343666)
@@ -155,7 +155,7 @@ enum {
 	CHK_MBOX_ACCESS	= (1 << 2),
 	MASTER_PF	= (1 << 3),
 	ADAP_SYSCTL_CTX	= (1 << 4),
-	/* TOM_INIT_DONE= (1 << 5),	No longer used */
+	ADAP_ERR	= (1 << 5),
 	BUF_PACKING_OK	= (1 << 6),
 	IS_VF		= (1 << 7),
 
@@ -175,6 +175,7 @@ enum {
 	DF_LOAD_FW_ANYTIME	= (1 << 1),	/* Allow LOAD_FW after init */
 	DF_DISABLE_TCB_CACHE	= (1 << 2),	/* Disable TCB cache (T6+) */
 	DF_DISABLE_CFG_RETRY	= (1 << 3),	/* Disable fallback config */
+	DF_VERBOSE_SLOWINTR	= (1 << 4),	/* Chatty slow intr handler */
 };
 
 #define IS_DOOMED(vi)	((vi)->flags & DOOMED)
@@ -932,24 +933,6 @@ struct adapter {
 #define TXQ_LOCK_ASSERT_OWNED(txq)	EQ_LOCK_ASSERT_OWNED(&(txq)->eq)
 #define TXQ_LOCK_ASSERT_NOTOWNED(txq)	EQ_LOCK_ASSERT_NOTOWNED(&(txq)->eq)
 
-#define CH_DUMP_MBOX(sc, mbox, data_reg) \
-	do { \
-		if (sc->debug_flags & DF_DUMP_MBOX) { \
-			log(LOG_NOTICE, \
-			    "%s mbox %u: %016llx %016llx %016llx %016llx " \
-			    "%016llx %016llx %016llx %016llx\n", \
-			    device_get_nameunit(sc->dev), mbox, \
-			    (unsigned long long)t4_read_reg64(sc, data_reg), \
-			    (unsigned long long)t4_read_reg64(sc, data_reg + 8), \
-			    (unsigned long long)t4_read_reg64(sc, data_reg + 16), \
-			    (unsigned long long)t4_read_reg64(sc, data_reg + 24), \
-			    (unsigned long long)t4_read_reg64(sc, data_reg + 32), \
-			    (unsigned long long)t4_read_reg64(sc, data_reg + 40), \
-			    (unsigned long long)t4_read_reg64(sc, data_reg + 48), \
-			    (unsigned long long)t4_read_reg64(sc, data_reg + 56)); \
-		} \
-	} while (0)
-
 #define for_each_txq(vi, iter, q) \
 	for (q = &vi->pi->adapter->sge.txq[vi->first_txq], iter = 0; \
 	    iter < vi->ntxq; ++iter, ++q)
@@ -1103,6 +1086,38 @@ t4_use_ldst(struct adapter *sc)
 #else
 	return (0);
 #endif
+}
+
+static inline void
+CH_DUMP_MBOX(struct adapter *sc, int mbox, const int reg,
+    const char *msg, const __be64 *const p, const bool err)
+{
+
+	if (!(sc->debug_flags & DF_DUMP_MBOX) && !err)
+		return;
+	if (p != NULL) {
+		log(err ? LOG_ERR : LOG_DEBUG,
+		    "%s: mbox %u %s %016llx %016llx %016llx %016llx "
+		    "%016llx %016llx %016llx %016llx\n",
+		    device_get_nameunit(sc->dev), mbox, msg,
+		    (long long)be64_to_cpu(p[0]), (long long)be64_to_cpu(p[1]),
+		    (long long)be64_to_cpu(p[2]), (long long)be64_to_cpu(p[3]),
+		    (long long)be64_to_cpu(p[4]), (long long)be64_to_cpu(p[5]),
+		    (long long)be64_to_cpu(p[6]), (long long)be64_to_cpu(p[7]));
+	} else {
+		log(err ? LOG_ERR : LOG_DEBUG,
+		    "%s: mbox %u %s %016llx %016llx %016llx %016llx "
+		    "%016llx %016llx %016llx %016llx\n",
+		    device_get_nameunit(sc->dev), mbox, msg,
+		    (long long)t4_read_reg64(sc, reg),
+		    (long long)t4_read_reg64(sc, reg + 8),
+		    (long long)t4_read_reg64(sc, reg + 16),
+		    (long long)t4_read_reg64(sc, reg + 24),
+		    (long long)t4_read_reg64(sc, reg + 32),
+		    (long long)t4_read_reg64(sc, reg + 40),
+		    (long long)t4_read_reg64(sc, reg + 48),
+		    (long long)t4_read_reg64(sc, reg + 56));
+	}
 }
 
 /* t4_main.c */

Modified: head/sys/dev/cxgbe/common/common.h
==============================================================================
--- head/sys/dev/cxgbe/common/common.h	Fri Feb  1 20:28:15 2019	(r343665)
+++ head/sys/dev/cxgbe/common/common.h	Fri Feb  1 20:42:49 2019	(r343666)
@@ -34,10 +34,6 @@
 
 #include "t4_hw.h"
 
-#define GLBL_INTR_MASK (F_CIM | F_MPS | F_PL | F_PCIE | F_MC0 | F_EDC0 | \
-		F_EDC1 | F_LE | F_TP | F_MA | F_PM_TX | F_PM_RX | F_ULP_RX | \
-		F_CPL_SWITCH | F_SGE | F_ULP_TX)
-
 enum {
 	MAX_NPORTS     = 4,     /* max # of ports */
 	SERNUM_LEN     = 24,    /* Serial # length */
@@ -581,7 +577,7 @@ struct fw_filter_wr;
 void t4_intr_enable(struct adapter *adapter);
 void t4_intr_disable(struct adapter *adapter);
 void t4_intr_clear(struct adapter *adapter);
-int t4_slow_intr_handler(struct adapter *adapter);
+int t4_slow_intr_handler(struct adapter *adapter, bool verbose);
 
 int t4_hash_mac_addr(const u8 *addr);
 int t4_link_l1cfg(struct adapter *adap, unsigned int mbox, unsigned int port,
@@ -621,9 +617,7 @@ int t4_init_sge_params(struct adapter *adapter);
 int t4_init_tp_params(struct adapter *adap, bool sleep_ok);
 int t4_filter_field_shift(const struct adapter *adap, int filter_sel);
 int t4_port_init(struct adapter *adap, int mbox, int pf, int vf, int port_id);
-void t4_fatal_err(struct adapter *adapter);
-void t4_db_full(struct adapter *adapter);
-void t4_db_dropped(struct adapter *adapter);
+void t4_fatal_err(struct adapter *adapter, bool fw_error);
 int t4_set_trace_filter(struct adapter *adapter, const struct trace_params *tp,
 			int filter_index, int enable);
 void t4_get_trace_filter(struct adapter *adapter, struct trace_params *tp,

Modified: head/sys/dev/cxgbe/common/t4_hw.c
==============================================================================
--- head/sys/dev/cxgbe/common/t4_hw.c	Fri Feb  1 20:28:15 2019	(r343665)
+++ head/sys/dev/cxgbe/common/t4_hw.c	Fri Feb  1 20:42:49 2019	(r343666)
@@ -212,8 +212,8 @@ static void t4_report_fw_error(struct adapter *adap)
 
 	pcie_fw = t4_read_reg(adap, A_PCIE_FW);
 	if (pcie_fw & F_PCIE_FW_ERR) {
-		CH_ERR(adap, "Firmware reports adapter error: %s\n",
-			reason[G_PCIE_FW_EVAL(pcie_fw)]);
+		CH_ERR(adap, "firmware reports adapter error: %s (0x%08x)\n",
+		    reason[G_PCIE_FW_EVAL(pcie_fw)], pcie_fw);
 		adap->flags &= ~FW_OK;
 	}
 }
@@ -340,7 +340,6 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int 
 	u32 v;
 	u64 res;
 	int i, ms, delay_idx, ret, next_tx_check;
-	const __be64 *p = cmd;
 	u32 data_reg = PF_REG(mbox, A_CIM_PF_MAILBOX_DATA);
 	u32 ctl_reg = PF_REG(mbox, A_CIM_PF_MAILBOX_CTRL);
 	u32 ctl;
@@ -351,7 +350,7 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int 
 	if (adap->flags & CHK_MBOX_ACCESS)
 		ASSERT_SYNCHRONIZED_OP(adap);
 
-	if ((size & 15) || size > MBOX_LEN)
+	if (size <= 0 || (size & 15) || size > MBOX_LEN)
 		return -EINVAL;
 
 	if (adap->flags & IS_VF) {
@@ -381,8 +380,7 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int 
 	}
 
 	/*
-	 * If we were unable to gain access, dequeue ourselves from the
-	 * mailbox atomic access list and report the error to our caller.
+	 * If we were unable to gain access, report the error to our caller.
 	 */
 	if (v != X_MBOWNER_PL) {
 		t4_report_fw_error(adap);
@@ -398,23 +396,17 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int 
 	 * presaged the firmware crashing ...
 	 */
 	if (ctl & F_MBMSGVALID) {
-		CH_ERR(adap, "found VALID command in mbox %u: %016llx %016llx "
-		       "%016llx %016llx %016llx %016llx %016llx %016llx\n",
-		       mbox, (unsigned long long)t4_read_reg64(adap, data_reg),
-		       (unsigned long long)t4_read_reg64(adap, data_reg + 8),
-		       (unsigned long long)t4_read_reg64(adap, data_reg + 16),
-		       (unsigned long long)t4_read_reg64(adap, data_reg + 24),
-		       (unsigned long long)t4_read_reg64(adap, data_reg + 32),
-		       (unsigned long long)t4_read_reg64(adap, data_reg + 40),
-		       (unsigned long long)t4_read_reg64(adap, data_reg + 48),
-		       (unsigned long long)t4_read_reg64(adap, data_reg + 56));
+		CH_DUMP_MBOX(adap, mbox, data_reg, "VLD", NULL, true);
 	}
 
 	/*
 	 * Copy in the new mailbox command and send it on its way ...
 	 */
-	for (i = 0; i < size; i += 8, p++)
-		t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p));
+	memset(cmd_rpl, 0, sizeof(cmd_rpl));
+	memcpy(cmd_rpl, cmd, size);
+	CH_DUMP_MBOX(adap, mbox, 0, "cmd", cmd_rpl, false);
+	for (i = 0; i < ARRAY_SIZE(cmd_rpl); i++)
+		t4_write_reg64(adap, data_reg + i * 8, be64_to_cpu(cmd_rpl[i]));
 
 	if (adap->flags & IS_VF) {
 		/*
@@ -432,8 +424,6 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int 
 		t4_read_reg(adap, data_reg);
 	}
 
-	CH_DUMP_MBOX(adap, mbox, data_reg);
-
 	t4_write_reg(adap, ctl_reg, F_MBMSGVALID | V_MBOWNER(X_MBOWNER_FW));
 	read_tx_state(adap, &tx_state[0]);	/* also flushes the write_reg */
 	next_tx_check = 1000;
@@ -480,10 +470,9 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int 
 			 * Retrieve the command reply and release the mailbox.
 			 */
 			get_mbox_rpl(adap, cmd_rpl, MBOX_LEN/8, data_reg);
+			CH_DUMP_MBOX(adap, mbox, 0, "rpl", cmd_rpl, false);
 			t4_write_reg(adap, ctl_reg, V_MBOWNER(X_MBOWNER_NONE));
 
-			CH_DUMP_MBOX(adap, mbox, data_reg);
-
 			res = be64_to_cpu(cmd_rpl[0]);
 			if (G_FW_CMD_OP(res >> 32) == FW_DEBUG_CMD) {
 				fw_asrt(adap, (struct fw_debug_cmd *)cmd_rpl);
@@ -500,26 +489,13 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int 
 	 * errors ...
 	 */
 	ret = (pcie_fw & F_PCIE_FW_ERR) ? -ENXIO : -ETIMEDOUT;
-	CH_ERR(adap, "command %#x in mailbox %d timed out\n",
-	       *(const u8 *)cmd, mbox);
+	CH_ERR(adap, "command %#x in mbox %d timed out (0x%08x).\n",
+	    *(const u8 *)cmd, mbox, pcie_fw);
+	CH_DUMP_MBOX(adap, mbox, 0, "cmdsent", cmd_rpl, true);
+	CH_DUMP_MBOX(adap, mbox, data_reg, "current", NULL, true);
 
-	/* If DUMP_MBOX is set the mbox has already been dumped */
-	if ((adap->debug_flags & DF_DUMP_MBOX) == 0) {
-		p = cmd;
-		CH_ERR(adap, "mbox: %016llx %016llx %016llx %016llx "
-		    "%016llx %016llx %016llx %016llx\n",
-		    (unsigned long long)be64_to_cpu(p[0]),
-		    (unsigned long long)be64_to_cpu(p[1]),
-		    (unsigned long long)be64_to_cpu(p[2]),
-		    (unsigned long long)be64_to_cpu(p[3]),
-		    (unsigned long long)be64_to_cpu(p[4]),
-		    (unsigned long long)be64_to_cpu(p[5]),
-		    (unsigned long long)be64_to_cpu(p[6]),
-		    (unsigned long long)be64_to_cpu(p[7]));
-	}
-
 	t4_report_fw_error(adap);
-	t4_fatal_err(adap);
+	t4_fatal_err(adap, true);
 	return ret;
 }
 
@@ -3965,785 +3941,1330 @@ int t4_restart_aneg(struct adapter *adap, unsigned int
 	return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
 }
 
-typedef void (*int_handler_t)(struct adapter *adap);
+struct intr_details {
+	u32 mask;
+	const char *msg;
+};
 
+struct intr_action {
+	u32 mask;
+	int arg;
+	bool (*action)(struct adapter *, int, bool);
+};
+
 struct intr_info {
-	unsigned int mask;	/* bits to check in interrupt status */
-	const char *msg;	/* message to print or NULL */
-	short stat_idx;		/* stat counter to increment or -1 */
-	unsigned short fatal;	/* whether the condition reported is fatal */
-	int_handler_t int_handler;	/* platform-specific int handler */
+	const char *name;	/* name of the INT_CAUSE register */
+	int cause_reg;		/* INT_CAUSE register */
+	int enable_reg;		/* INT_ENABLE register */
+	u32 fatal;		/* bits that are fatal */
+	const struct intr_details *details;
+	const struct intr_action *actions;
 };
 
-/**
- *	t4_handle_intr_status - table driven interrupt handler
- *	@adapter: the adapter that generated the interrupt
- *	@reg: the interrupt status register to process
- *	@acts: table of interrupt actions
- *
- *	A table driven interrupt handler that applies a set of masks to an
- *	interrupt status word and performs the corresponding actions if the
- *	interrupts described by the mask have occurred.  The actions include
- *	optionally emitting a warning or alert message.  The table is terminated
- *	by an entry specifying mask 0.  Returns the number of fatal interrupt
- *	conditions.
+static inline char
+intr_alert_char(u32 cause, u32 enable, u32 fatal)
+{
+
+	if (cause & fatal)
+		return ('!');
+	if (cause & enable)
+		return ('*');
+	return ('-');
+}
+
+static void
+t4_show_intr_info(struct adapter *adap, const struct intr_info *ii, u32 cause)
+{
+	u32 enable, leftover;
+	const struct intr_details *details;
+	char alert;
+
+	enable = t4_read_reg(adap, ii->enable_reg);
+	alert = intr_alert_char(cause, enable, ii->fatal);
+	CH_ALERT(adap, "%c %s 0x%x = 0x%08x, E 0x%08x, F 0x%08x\n",
+	    alert, ii->name, ii->cause_reg, cause, enable, ii->fatal);
+
+	leftover = cause;
+	for (details = ii->details; details && details->mask != 0; details++) {
+		u32 msgbits = details->mask & cause;
+		if (msgbits == 0)
+			continue;
+		alert = intr_alert_char(msgbits, enable, ii->fatal);
+		CH_ALERT(adap, "  %c [0x%08x] %s\n", alert, msgbits,
+		    details->msg);
+		leftover &= ~msgbits;
+	}
+	if (leftover != 0 && leftover != cause)
+		CH_ALERT(adap, "  ? [0x%08x]\n", leftover);
+}
+
+/*
+ * Returns true for fatal error.
  */
-static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg,
-				 const struct intr_info *acts)
+static bool
+t4_handle_intr(struct adapter *adap, const struct intr_info *ii,
+    u32 additional_cause, bool verbose)
 {
-	int fatal = 0;
-	unsigned int mask = 0;
-	unsigned int status = t4_read_reg(adapter, reg);
+	u32 cause;
+	bool fatal;
+	const struct intr_action *action;
 
-	for ( ; acts->mask; ++acts) {
-		if (!(status & acts->mask))
+	/* read and display cause. */
+	cause = t4_read_reg(adap, ii->cause_reg);
+	if (verbose || cause != 0)
+		t4_show_intr_info(adap, ii, cause);
+	fatal = (cause & ii->fatal) != 0;
+	cause |= additional_cause;
+	if (cause == 0)
+		return (false);
+
+	for (action = ii->actions; action && action->mask != 0; action++) {
+		if (!(action->mask & cause))
 			continue;
-		if (acts->fatal) {
-			fatal++;
-			CH_ALERT(adapter, "%s (0x%x)\n", acts->msg,
-				  status & acts->mask);
-		} else if (acts->msg)
-			CH_WARN_RATELIMIT(adapter, "%s (0x%x)\n", acts->msg,
-				 status & acts->mask);
-		if (acts->int_handler)
-			acts->int_handler(adapter);
-		mask |= acts->mask;
+		fatal |= (action->action)(adap, action->arg, verbose);
 	}
-	status &= mask;
-	if (status)	/* clear processed interrupts */
-		t4_write_reg(adapter, reg, status);
-	return fatal;
+
+	/* clear */
+	t4_write_reg(adap, ii->cause_reg, cause);
+	(void)t4_read_reg(adap, ii->cause_reg);
+
+	return (fatal);
 }
 
 /*
  * Interrupt handler for the PCIE module.
  */
-static void pcie_intr_handler(struct adapter *adapter)
+static bool pcie_intr_handler(struct adapter *adap, int arg, bool verbose)
 {
-	static const struct intr_info sysbus_intr_info[] = {
-		{ F_RNPP, "RXNP array parity error", -1, 1 },
-		{ F_RPCP, "RXPC array parity error", -1, 1 },
-		{ F_RCIP, "RXCIF array parity error", -1, 1 },
-		{ F_RCCP, "Rx completions control array parity error", -1, 1 },
-		{ F_RFTP, "RXFT array parity error", -1, 1 },
+	static const struct intr_details sysbus_intr_details[] = {
+		{ F_RNPP, "RXNP array parity error" },
+		{ F_RPCP, "RXPC array parity error" },
+		{ F_RCIP, "RXCIF array parity error" },
+		{ F_RCCP, "Rx completions control array parity error" },
+		{ F_RFTP, "RXFT array parity error" },
 		{ 0 }
 	};
-	static const struct intr_info pcie_port_intr_info[] = {
-		{ F_TPCP, "TXPC array parity error", -1, 1 },
-		{ F_TNPP, "TXNP array parity error", -1, 1 },
-		{ F_TFTP, "TXFT array parity error", -1, 1 },
-		{ F_TCAP, "TXCA array parity error", -1, 1 },
-		{ F_TCIP, "TXCIF array parity error", -1, 1 },
-		{ F_RCAP, "RXCA array parity error", -1, 1 },
-		{ F_OTDD, "outbound request TLP discarded", -1, 1 },
-		{ F_RDPE, "Rx data parity error", -1, 1 },
-		{ F_TDUE, "Tx uncorrectable data error", -1, 1 },
+	static const struct intr_info sysbus_intr_info = {
+		.name = "PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS",
+		.cause_reg = A_PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
+		.enable_reg = A_PCIE_CORE_UTL_SYSTEM_BUS_AGENT_INTERRUPT_ENABLE,
+		.fatal = F_RFTP | F_RCCP | F_RCIP | F_RPCP | F_RNPP,
+		.details = sysbus_intr_details,
+		.actions = NULL,
+	};
+	static const struct intr_details pcie_port_intr_details[] = {
+		{ F_TPCP, "TXPC array parity error" },
+		{ F_TNPP, "TXNP array parity error" },
+		{ F_TFTP, "TXFT array parity error" },
+		{ F_TCAP, "TXCA array parity error" },
+		{ F_TCIP, "TXCIF array parity error" },
+		{ F_RCAP, "RXCA array parity error" },
+		{ F_OTDD, "outbound request TLP discarded" },
+		{ F_RDPE, "Rx data parity error" },
+		{ F_TDUE, "Tx uncorrectable data error" },
 		{ 0 }
 	};
-	static const struct intr_info pcie_intr_info[] = {
-		{ F_MSIADDRLPERR, "MSI AddrL parity error", -1, 1 },
-		{ F_MSIADDRHPERR, "MSI AddrH parity error", -1, 1 },
-		{ F_MSIDATAPERR, "MSI data parity error", -1, 1 },
-		{ F_MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
-		{ F_MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
-		{ F_MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
-		{ F_MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
-		{ F_PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 },
-		{ F_PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 },
-		{ F_TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
-		{ F_CCNTPERR, "PCI CMD channel count parity error", -1, 1 },
-		{ F_CREQPERR, "PCI CMD channel request parity error", -1, 1 },
-		{ F_CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
-		{ F_DCNTPERR, "PCI DMA channel count parity error", -1, 1 },
-		{ F_DREQPERR, "PCI DMA channel request parity error", -1, 1 },
-		{ F_DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
-		{ F_HCNTPERR, "PCI HMA channel count parity error", -1, 1 },
-		{ F_HREQPERR, "PCI HMA channel request parity error", -1, 1 },
-		{ F_HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
-		{ F_CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
-		{ F_FIDPERR, "PCI FID parity error", -1, 1 },
-		{ F_INTXCLRPERR, "PCI INTx clear parity error", -1, 1 },
-		{ F_MATAGPERR, "PCI MA tag parity error", -1, 1 },
-		{ F_PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
-		{ F_RXCPLPERR, "PCI Rx completion parity error", -1, 1 },
-		{ F_RXWRPERR, "PCI Rx write parity error", -1, 1 },
-		{ F_RPLPERR, "PCI replay buffer parity error", -1, 1 },
-		{ F_PCIESINT, "PCI core secondary fault", -1, 1 },
-		{ F_PCIEPINT, "PCI core primary fault", -1, 1 },
-		{ F_UNXSPLCPLERR, "PCI unexpected split completion error", -1,
-		  0 },
+	static const struct intr_info pcie_port_intr_info = {
+		.name = "PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS",
+		.cause_reg = A_PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
+		.enable_reg = A_PCIE_CORE_UTL_PCI_EXPRESS_PORT_INTERRUPT_ENABLE,
+		.fatal = F_TPCP | F_TNPP | F_TFTP | F_TCAP | F_TCIP | F_RCAP |
+		    F_OTDD | F_RDPE | F_TDUE,
+		.details = pcie_port_intr_details,
+		.actions = NULL,
+	};
+	static const struct intr_details pcie_intr_details[] = {
+		{ F_MSIADDRLPERR, "MSI AddrL parity error" },
+		{ F_MSIADDRHPERR, "MSI AddrH parity error" },
+		{ F_MSIDATAPERR, "MSI data parity error" },
+		{ F_MSIXADDRLPERR, "MSI-X AddrL parity error" },
+		{ F_MSIXADDRHPERR, "MSI-X AddrH parity error" },
+		{ F_MSIXDATAPERR, "MSI-X data parity error" },
+		{ F_MSIXDIPERR, "MSI-X DI parity error" },
+		{ F_PIOCPLPERR, "PCIe PIO completion FIFO parity error" },
+		{ F_PIOREQPERR, "PCIe PIO request FIFO parity error" },
+		{ F_TARTAGPERR, "PCIe target tag FIFO parity error" },
+		{ F_CCNTPERR, "PCIe CMD channel count parity error" },
+		{ F_CREQPERR, "PCIe CMD channel request parity error" },
+		{ F_CRSPPERR, "PCIe CMD channel response parity error" },
+		{ F_DCNTPERR, "PCIe DMA channel count parity error" },
+		{ F_DREQPERR, "PCIe DMA channel request parity error" },
+		{ F_DRSPPERR, "PCIe DMA channel response parity error" },
+		{ F_HCNTPERR, "PCIe HMA channel count parity error" },
+		{ F_HREQPERR, "PCIe HMA channel request parity error" },
+		{ F_HRSPPERR, "PCIe HMA channel response parity error" },
+		{ F_CFGSNPPERR, "PCIe config snoop FIFO parity error" },
+		{ F_FIDPERR, "PCIe FID parity error" },
+		{ F_INTXCLRPERR, "PCIe INTx clear parity error" },
+		{ F_MATAGPERR, "PCIe MA tag parity error" },
+		{ F_PIOTAGPERR, "PCIe PIO tag parity error" },
+		{ F_RXCPLPERR, "PCIe Rx completion parity error" },
+		{ F_RXWRPERR, "PCIe Rx write parity error" },
+		{ F_RPLPERR, "PCIe replay buffer parity error" },
+		{ F_PCIESINT, "PCIe core secondary fault" },
+		{ F_PCIEPINT, "PCIe core primary fault" },
+		{ F_UNXSPLCPLERR, "PCIe unexpected split completion error" },
 		{ 0 }
 	};
-
-	static const struct intr_info t5_pcie_intr_info[] = {
-		{ F_MSTGRPPERR, "Master Response Read Queue parity error",
-		  -1, 1 },
-		{ F_MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 },
-		{ F_MSIXSTIPERR, "MSI-X STI SRAM parity error", -1, 1 },
-		{ F_MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
-		{ F_MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
-		{ F_MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
-		{ F_MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
-		{ F_PIOCPLGRPPERR, "PCI PIO completion Group FIFO parity error",
-		  -1, 1 },
-		{ F_PIOREQGRPPERR, "PCI PIO request Group FIFO parity error",
-		  -1, 1 },
-		{ F_TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
-		{ F_MSTTAGQPERR, "PCI master tag queue parity error", -1, 1 },
-		{ F_CREQPERR, "PCI CMD channel request parity error", -1, 1 },
-		{ F_CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
-		{ F_DREQWRPERR, "PCI DMA channel write request parity error",
-		  -1, 1 },
-		{ F_DREQPERR, "PCI DMA channel request parity error", -1, 1 },
-		{ F_DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
-		{ F_HREQWRPERR, "PCI HMA channel count parity error", -1, 1 },
-		{ F_HREQPERR, "PCI HMA channel request parity error", -1, 1 },
-		{ F_HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
-		{ F_CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
-		{ F_FIDPERR, "PCI FID parity error", -1, 1 },
-		{ F_VFIDPERR, "PCI INTx clear parity error", -1, 1 },
-		{ F_MAGRPPERR, "PCI MA group FIFO parity error", -1, 1 },
-		{ F_PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
-		{ F_IPRXHDRGRPPERR, "PCI IP Rx header group parity error",
-		  -1, 1 },
-		{ F_IPRXDATAGRPPERR, "PCI IP Rx data group parity error",
-		  -1, 1 },
-		{ F_RPLPERR, "PCI IP replay buffer parity error", -1, 1 },
-		{ F_IPSOTPERR, "PCI IP SOT buffer parity error", -1, 1 },
-		{ F_TRGT1GRPPERR, "PCI TRGT1 group FIFOs parity error", -1, 1 },
-		{ F_READRSPERR, "Outbound read error", -1,
-		  0 },
+	static const struct intr_details t5_pcie_intr_details[] = {
+		{ F_IPGRPPERR, "Parity errors observed by IP" },
+		{ F_NONFATALERR, "PCIe non-fatal error" },
+		{ F_READRSPERR, "Outbound read error" },
+		{ F_TRGT1GRPPERR, "PCIe TRGT1 group FIFOs parity error" },
+		{ F_IPSOTPERR, "PCIe IP SOT buffer SRAM parity error" },
+		{ F_IPRETRYPERR, "PCIe IP replay buffer parity error" },
+		{ F_IPRXDATAGRPPERR, "PCIe IP Rx data group SRAMs parity error" },
+		{ F_IPRXHDRGRPPERR, "PCIe IP Rx header group SRAMs parity error" },
+		{ F_PIOTAGQPERR, "PIO tag queue FIFO parity error" },
+		{ F_MAGRPPERR, "MA group FIFO parity error" },
+		{ F_VFIDPERR, "VFID SRAM parity error" },
+		{ F_FIDPERR, "FID SRAM parity error" },
+		{ F_CFGSNPPERR, "config snoop FIFO parity error" },
+		{ F_HRSPPERR, "HMA channel response data SRAM parity error" },
+		{ F_HREQRDPERR, "HMA channel read request SRAM parity error" },
+		{ F_HREQWRPERR, "HMA channel write request SRAM parity error" },
+		{ F_DRSPPERR, "DMA channel response data SRAM parity error" },
+		{ F_DREQRDPERR, "DMA channel write request SRAM parity error" },
+		{ F_CRSPPERR, "CMD channel response data SRAM parity error" },
+		{ F_CREQRDPERR, "CMD channel read request SRAM parity error" },
+		{ F_MSTTAGQPERR, "PCIe master tag queue SRAM parity error" },
+		{ F_TGTTAGQPERR, "PCIe target tag queue FIFO parity error" },
+		{ F_PIOREQGRPPERR, "PIO request group FIFOs parity error" },
+		{ F_PIOCPLGRPPERR, "PIO completion group FIFOs parity error" },
+		{ F_MSIXDIPERR, "MSI-X DI SRAM parity error" },
+		{ F_MSIXDATAPERR, "MSI-X data SRAM parity error" },
+		{ F_MSIXADDRHPERR, "MSI-X AddrH SRAM parity error" },
+		{ F_MSIXADDRLPERR, "MSI-X AddrL SRAM parity error" },
+		{ F_MSIXSTIPERR, "MSI-X STI SRAM parity error" },
+		{ F_MSTTIMEOUTPERR, "Master timeout FIFO parity error" },
+		{ F_MSTGRPPERR, "Master response read queue SRAM parity error" },
 		{ 0 }
 	};
+	struct intr_info pcie_intr_info = {
+		.name = "PCIE_INT_CAUSE",
+		.cause_reg = A_PCIE_INT_CAUSE,
+		.enable_reg = A_PCIE_INT_ENABLE,
+		.fatal = 0,
+		.details = NULL,
+		.actions = NULL,
+	};
+	bool fatal = false;
 
-	int fat;
+	if (is_t4(adap)) {
+		fatal |= t4_handle_intr(adap, &sysbus_intr_info, 0, verbose);
+		fatal |= t4_handle_intr(adap, &pcie_port_intr_info, 0, verbose);
 
-	if (is_t4(adapter))
-		fat = t4_handle_intr_status(adapter,
-				A_PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
-				sysbus_intr_info) +
-			t4_handle_intr_status(adapter,
-					A_PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
-					pcie_port_intr_info) +
-			t4_handle_intr_status(adapter, A_PCIE_INT_CAUSE,
-					      pcie_intr_info);
-	else
-		fat = t4_handle_intr_status(adapter, A_PCIE_INT_CAUSE,
-					    t5_pcie_intr_info);
-	if (fat)
-		t4_fatal_err(adapter);
+		pcie_intr_info.fatal =  0x3fffffc0;
+		pcie_intr_info.details = pcie_intr_details;
+	} else {
+		pcie_intr_info.fatal = is_t5(adap) ? 0xbfffff40 : 0x9fffff40;
+		pcie_intr_info.details = t5_pcie_intr_details;
+	}
+	fatal |= t4_handle_intr(adap, &pcie_intr_info, 0, verbose);
+
+	return (fatal);
 }
 
 /*
  * TP interrupt handler.
  */
-static void tp_intr_handler(struct adapter *adapter)
+static bool tp_intr_handler(struct adapter *adap, int arg, bool verbose)
 {
-	static const struct intr_info tp_intr_info[] = {
-		{ 0x3fffffff, "TP parity error", -1, 1 },
-		{ F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 },
+	static const struct intr_details tp_intr_details[] = {
+		{ 0x3fffffff, "TP parity error" },
+		{ F_FLMTXFLSTEMPTY, "TP out of Tx pages" },
 		{ 0 }
 	};
+	static const struct intr_info tp_intr_info = {
+		.name = "TP_INT_CAUSE",
+		.cause_reg = A_TP_INT_CAUSE,
+		.enable_reg = A_TP_INT_ENABLE,
+		.fatal = 0x7fffffff,
+		.details = tp_intr_details,
+		.actions = NULL,
+	};
 
-	if (t4_handle_intr_status(adapter, A_TP_INT_CAUSE, tp_intr_info))
-		t4_fatal_err(adapter);
+	return (t4_handle_intr(adap, &tp_intr_info, 0, verbose));
 }
 
 /*
  * SGE interrupt handler.
  */
-static void sge_intr_handler(struct adapter *adapter)
+static bool sge_intr_handler(struct adapter *adap, int arg, bool verbose)
 {
-	u64 v;
-	u32 err;
-
-	static const struct intr_info sge_intr_info[] = {
+	static const struct intr_info sge_int1_info = {
+		.name = "SGE_INT_CAUSE1",
+		.cause_reg = A_SGE_INT_CAUSE1,
+		.enable_reg = A_SGE_INT_ENABLE1,
+		.fatal = 0xffffffff,
+		.details = NULL,
+		.actions = NULL,
+	};
+	static const struct intr_info sge_int2_info = {
+		.name = "SGE_INT_CAUSE2",
+		.cause_reg = A_SGE_INT_CAUSE2,
+		.enable_reg = A_SGE_INT_ENABLE2,
+		.fatal = 0xffffffff,
+		.details = NULL,
+		.actions = NULL,
+	};
+	static const struct intr_details sge_int3_details[] = {
+		{ F_ERR_FLM_DBP,
+			"DBP pointer delivery for invalid context or QID" },
+		{ F_ERR_FLM_IDMA1 | F_ERR_FLM_IDMA0,
+			"Invalid QID or header request by IDMA" },
+		{ F_ERR_FLM_HINT, "FLM hint is for invalid context or QID" },
+		{ F_ERR_PCIE_ERROR3, "SGE PCIe error for DBP thread 3" },
+		{ F_ERR_PCIE_ERROR2, "SGE PCIe error for DBP thread 2" },
+		{ F_ERR_PCIE_ERROR1, "SGE PCIe error for DBP thread 1" },
+		{ F_ERR_PCIE_ERROR0, "SGE PCIe error for DBP thread 0" },
+		{ F_ERR_TIMER_ABOVE_MAX_QID,
+			"SGE GTS with timer 0-5 for IQID > 1023" },
 		{ F_ERR_CPL_EXCEED_IQE_SIZE,
-		  "SGE received CPL exceeding IQE size", -1, 1 },
-		{ F_ERR_INVALID_CIDX_INC,
-		  "SGE GTS CIDX increment too large", -1, 0 },
-		{ F_ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 },
-		{ F_DBFIFO_LP_INT, NULL, -1, 0, t4_db_full },
+			"SGE received CPL exceeding IQE size" },
+		{ F_ERR_INVALID_CIDX_INC, "SGE GTS CIDX increment too large" },
+		{ F_ERR_ITP_TIME_PAUSED, "SGE ITP error" },
+		{ F_ERR_CPL_OPCODE_0, "SGE received 0-length CPL" },
+		{ F_ERR_DROPPED_DB, "SGE DB dropped" },
 		{ F_ERR_DATA_CPL_ON_HIGH_QID1 | F_ERR_DATA_CPL_ON_HIGH_QID0,
-		  "SGE IQID > 1023 received CPL for FL", -1, 0 },
-		{ F_ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1,
-		  0 },
-		{ F_ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1,
-		  0 },
-		{ F_ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1,
-		  0 },
-		{ F_ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1,
-		  0 },
+		  "SGE IQID > 1023 received CPL for FL" },
+		{ F_ERR_BAD_DB_PIDX3 | F_ERR_BAD_DB_PIDX2 | F_ERR_BAD_DB_PIDX1 |
+			F_ERR_BAD_DB_PIDX0, "SGE DBP pidx increment too large" },
+		{ F_ERR_ING_PCIE_CHAN, "SGE Ingress PCIe channel mismatch" },
 		{ F_ERR_ING_CTXT_PRIO,
-		  "SGE too many priority ingress contexts", -1, 0 },
-		{ F_INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 },
-		{ F_EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 },
-		{ F_ERR_PCIE_ERROR0 | F_ERR_PCIE_ERROR1 |
-		  F_ERR_PCIE_ERROR2 | F_ERR_PCIE_ERROR3,
-		  "SGE PCIe error for a DBP thread", -1, 0 },
-		{ 0 }
-	};
-
-	static const struct intr_info t4t5_sge_intr_info[] = {
-		{ F_ERR_DROPPED_DB, NULL, -1, 0, t4_db_dropped },
-		{ F_DBFIFO_HP_INT, NULL, -1, 0, t4_db_full },
+			"Ingress context manager priority user error" },
 		{ F_ERR_EGR_CTXT_PRIO,
-		  "SGE too many priority egress contexts", -1, 0 },
+			"Egress context manager priority user error" },
+		{ F_DBFIFO_HP_INT, "High priority DB FIFO threshold reached" },
+		{ F_DBFIFO_LP_INT, "Low priority DB FIFO threshold reached" },
+		{ F_REG_ADDRESS_ERR, "Undefined SGE register accessed" },
+		{ F_INGRESS_SIZE_ERR, "SGE illegal ingress QID" },
+		{ F_EGRESS_SIZE_ERR, "SGE illegal egress QID" },
+		{ 0x0000000f, "SGE context access for invalid queue" },
 		{ 0 }
 	};
-
-	/*
- 	* For now, treat below interrupts as fatal so that we disable SGE and
- 	* get better debug */
-	static const struct intr_info t6_sge_intr_info[] = {
+	static const struct intr_details t6_sge_int3_details[] = {
+		{ F_ERR_FLM_DBP,
+			"DBP pointer delivery for invalid context or QID" },
+		{ F_ERR_FLM_IDMA1 | F_ERR_FLM_IDMA0,
+			"Invalid QID or header request by IDMA" },
+		{ F_ERR_FLM_HINT, "FLM hint is for invalid context or QID" },
+		{ F_ERR_PCIE_ERROR3, "SGE PCIe error for DBP thread 3" },
+		{ F_ERR_PCIE_ERROR2, "SGE PCIe error for DBP thread 2" },
+		{ F_ERR_PCIE_ERROR1, "SGE PCIe error for DBP thread 1" },
+		{ F_ERR_PCIE_ERROR0, "SGE PCIe error for DBP thread 0" },
+		{ F_ERR_TIMER_ABOVE_MAX_QID,
+			"SGE GTS with timer 0-5 for IQID > 1023" },
+		{ F_ERR_CPL_EXCEED_IQE_SIZE,
+			"SGE received CPL exceeding IQE size" },
+		{ F_ERR_INVALID_CIDX_INC, "SGE GTS CIDX increment too large" },
+		{ F_ERR_ITP_TIME_PAUSED, "SGE ITP error" },
+		{ F_ERR_CPL_OPCODE_0, "SGE received 0-length CPL" },
+		{ F_ERR_DROPPED_DB, "SGE DB dropped" },
+		{ F_ERR_DATA_CPL_ON_HIGH_QID1 | F_ERR_DATA_CPL_ON_HIGH_QID0,
+			"SGE IQID > 1023 received CPL for FL" },
+		{ F_ERR_BAD_DB_PIDX3 | F_ERR_BAD_DB_PIDX2 | F_ERR_BAD_DB_PIDX1 |
+			F_ERR_BAD_DB_PIDX0, "SGE DBP pidx increment too large" },
+		{ F_ERR_ING_PCIE_CHAN, "SGE Ingress PCIe channel mismatch" },
+		{ F_ERR_ING_CTXT_PRIO,
+			"Ingress context manager priority user error" },
+		{ F_ERR_EGR_CTXT_PRIO,
+			"Egress context manager priority user error" },
+		{ F_DBP_TBUF_FULL, "SGE DBP tbuf full" },
 		{ F_FATAL_WRE_LEN,
-		  "SGE Actual WRE packet is less than advertized length",
-		  -1, 1 },
+			"SGE WRE packet less than advertized length" },
+		{ F_REG_ADDRESS_ERR, "Undefined SGE register accessed" },
+		{ F_INGRESS_SIZE_ERR, "SGE illegal ingress QID" },
+		{ F_EGRESS_SIZE_ERR, "SGE illegal egress QID" },
+		{ 0x0000000f, "SGE context access for invalid queue" },
 		{ 0 }
 	};
+	struct intr_info sge_int3_info = {
+		.name = "SGE_INT_CAUSE3",
+		.cause_reg = A_SGE_INT_CAUSE3,
+		.enable_reg = A_SGE_INT_ENABLE3,
+		.fatal = F_ERR_CPL_EXCEED_IQE_SIZE,
+		.details = NULL,
+		.actions = NULL,
+	};
+	static const struct intr_info sge_int4_info = {
+		.name = "SGE_INT_CAUSE4",
+		.cause_reg = A_SGE_INT_CAUSE4,
+		.enable_reg = A_SGE_INT_ENABLE4,
+		.fatal = 0,
+		.details = NULL,
+		.actions = NULL,
+	};
+	static const struct intr_info sge_int5_info = {
+		.name = "SGE_INT_CAUSE5",
+		.cause_reg = A_SGE_INT_CAUSE5,
+		.enable_reg = A_SGE_INT_ENABLE5,
+		.fatal = 0xffffffff,
+		.details = NULL,
+		.actions = NULL,
+	};
+	static const struct intr_info sge_int6_info = {
+		.name = "SGE_INT_CAUSE6",
+		.cause_reg = A_SGE_INT_CAUSE6,
+		.enable_reg = A_SGE_INT_ENABLE6,
+		.fatal = 0,
+		.details = NULL,
+		.actions = NULL,
+	};
 
-	v = (u64)t4_read_reg(adapter, A_SGE_INT_CAUSE1) |
-		((u64)t4_read_reg(adapter, A_SGE_INT_CAUSE2) << 32);
-	if (v) {
-		CH_ALERT(adapter, "SGE parity error (%#llx)\n",
-				(unsigned long long)v);
-		t4_write_reg(adapter, A_SGE_INT_CAUSE1, v);
-		t4_write_reg(adapter, A_SGE_INT_CAUSE2, v >> 32);
+	bool fatal;
+	u32 v;
+
+	if (chip_id(adap) <= CHELSIO_T5) {
+		sge_int3_info.details = sge_int3_details;
+	} else {
+		sge_int3_info.details = t6_sge_int3_details;
 	}
 
-	v |= t4_handle_intr_status(adapter, A_SGE_INT_CAUSE3, sge_intr_info);
-	if (chip_id(adapter) <= CHELSIO_T5)
-		v |= t4_handle_intr_status(adapter, A_SGE_INT_CAUSE3,
-					   t4t5_sge_intr_info);
-	else
-		v |= t4_handle_intr_status(adapter, A_SGE_INT_CAUSE3,
-					   t6_sge_intr_info);
+	fatal = false;
+	fatal |= t4_handle_intr(adap, &sge_int1_info, 0, verbose);
+	fatal |= t4_handle_intr(adap, &sge_int2_info, 0, verbose);
+	fatal |= t4_handle_intr(adap, &sge_int3_info, 0, verbose);
+	fatal |= t4_handle_intr(adap, &sge_int4_info, 0, verbose);
+	if (chip_id(adap) >= CHELSIO_T5)
+		fatal |= t4_handle_intr(adap, &sge_int5_info, 0, verbose);
+	if (chip_id(adap) >= CHELSIO_T6)
+		fatal |= t4_handle_intr(adap, &sge_int6_info, 0, verbose);
 
-	err = t4_read_reg(adapter, A_SGE_ERROR_STATS);
-	if (err & F_ERROR_QID_VALID) {
-		CH_ERR(adapter, "SGE error for queue %u\n", G_ERROR_QID(err));
-		if (err & F_UNCAPTURED_ERROR)
-			CH_ERR(adapter, "SGE UNCAPTURED_ERROR set (clearing)\n");
-		t4_write_reg(adapter, A_SGE_ERROR_STATS, F_ERROR_QID_VALID |
-			     F_UNCAPTURED_ERROR);
+	v = t4_read_reg(adap, A_SGE_ERROR_STATS);
+	if (v & F_ERROR_QID_VALID) {
+		CH_ERR(adap, "SGE error for QID %u\n", G_ERROR_QID(v));
+		if (v & F_UNCAPTURED_ERROR)
+			CH_ERR(adap, "SGE UNCAPTURED_ERROR set (clearing)\n");
+		t4_write_reg(adap, A_SGE_ERROR_STATS,
+		    F_ERROR_QID_VALID | F_UNCAPTURED_ERROR);
 	}
 
-	if (v != 0)
-		t4_fatal_err(adapter);
+	return (fatal);
 }
 
-#define CIM_OBQ_INTR (F_OBQULP0PARERR | F_OBQULP1PARERR | F_OBQULP2PARERR |\
-		      F_OBQULP3PARERR | F_OBQSGEPARERR | F_OBQNCSIPARERR)
-#define CIM_IBQ_INTR (F_IBQTP0PARERR | F_IBQTP1PARERR | F_IBQULPPARERR |\
-		      F_IBQSGEHIPARERR | F_IBQSGELOPARERR | F_IBQNCSIPARERR)
-
 /*
  * CIM interrupt handler.
  */
-static void cim_intr_handler(struct adapter *adapter)
+static bool cim_intr_handler(struct adapter *adap, int arg, bool verbose)
 {
-	static const struct intr_info cim_intr_info[] = {
-		{ F_PREFDROPINT, "CIM control register prefetch drop", -1, 1 },
-		{ CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 },
-		{ CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 },
-		{ F_MBUPPARERR, "CIM mailbox uP parity error", -1, 1 },
-		{ F_MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 },
-		{ F_TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 },
-		{ F_TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 },
-		{ F_TIMER0INT, "CIM TIMER0 interrupt", -1, 1 },
-		{ 0 }
+	static const struct intr_details cim_host_intr_details[] = {
+		/* T6+ */
+		{ F_PCIE2CIMINTFPARERR, "CIM IBQ PCIe interface parity error" },
+
+		/* T5+ */
+		{ F_MA_CIM_INTFPERR, "MA2CIM interface parity error" },
+		{ F_PLCIM_MSTRSPDATAPARERR,
+			"PL2CIM master response data parity error" },
+		{ F_NCSI2CIMINTFPARERR, "CIM IBQ NC-SI interface parity error" },
+		{ F_SGE2CIMINTFPARERR, "CIM IBQ SGE interface parity error" },
+		{ F_ULP2CIMINTFPARERR, "CIM IBQ ULP_TX interface parity error" },
+		{ F_TP2CIMINTFPARERR, "CIM IBQ TP interface parity error" },
+		{ F_OBQSGERX1PARERR, "CIM OBQ SGE1_RX parity error" },
+		{ F_OBQSGERX0PARERR, "CIM OBQ SGE0_RX parity error" },
+
+		/* T4+ */
+		{ F_TIEQOUTPARERRINT, "CIM TIEQ outgoing FIFO parity error" },
+		{ F_TIEQINPARERRINT, "CIM TIEQ incoming FIFO parity error" },
+		{ F_MBHOSTPARERR, "CIM mailbox host read parity error" },
+		{ F_MBUPPARERR, "CIM mailbox uP parity error" },
+		{ F_IBQTP0PARERR, "CIM IBQ TP0 parity error" },
+		{ F_IBQTP1PARERR, "CIM IBQ TP1 parity error" },
+		{ F_IBQULPPARERR, "CIM IBQ ULP parity error" },
+		{ F_IBQSGELOPARERR, "CIM IBQ SGE_LO parity error" },
+		{ F_IBQSGEHIPARERR | F_IBQPCIEPARERR,	/* same bit */
+			"CIM IBQ PCIe/SGE_HI parity error" },
+		{ F_IBQNCSIPARERR, "CIM IBQ NC-SI parity error" },
+		{ F_OBQULP0PARERR, "CIM OBQ ULP0 parity error" },
+		{ F_OBQULP1PARERR, "CIM OBQ ULP1 parity error" },
+		{ F_OBQULP2PARERR, "CIM OBQ ULP2 parity error" },
+		{ F_OBQULP3PARERR, "CIM OBQ ULP3 parity error" },
+		{ F_OBQSGEPARERR, "CIM OBQ SGE parity error" },
+		{ F_OBQNCSIPARERR, "CIM OBQ NC-SI parity error" },
+		{ F_TIMER1INT, "CIM TIMER0 interrupt" },
+		{ F_TIMER0INT, "CIM TIMER0 interrupt" },
+		{ F_PREFDROPINT, "CIM control register prefetch drop" },
+		{ 0}
 	};
-	static const struct intr_info cim_upintr_info[] = {
-		{ F_RSVDSPACEINT, "CIM reserved space access", -1, 1 },
-		{ F_ILLTRANSINT, "CIM illegal transaction", -1, 1 },
-		{ F_ILLWRINT, "CIM illegal write", -1, 1 },
-		{ F_ILLRDINT, "CIM illegal read", -1, 1 },
-		{ F_ILLRDBEINT, "CIM illegal read BE", -1, 1 },
-		{ F_ILLWRBEINT, "CIM illegal write BE", -1, 1 },
-		{ F_SGLRDBOOTINT, "CIM single read from boot space", -1, 1 },
-		{ F_SGLWRBOOTINT, "CIM single write to boot space", -1, 1 },
-		{ F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1 },
-		{ F_SGLRDFLASHINT, "CIM single read from flash space", -1, 1 },
-		{ F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1 },
-		{ F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1 },
-		{ F_SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 },
-		{ F_SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 },
-		{ F_BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 },
-		{ F_BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 },
-		{ F_SGLRDCTLINT , "CIM single read from CTL space", -1, 1 },
-		{ F_SGLWRCTLINT , "CIM single write to CTL space", -1, 1 },
-		{ F_BLKRDCTLINT , "CIM block read from CTL space", -1, 1 },
-		{ F_BLKWRCTLINT , "CIM block write to CTL space", -1, 1 },
-		{ F_SGLRDPLINT , "CIM single read from PL space", -1, 1 },
-		{ F_SGLWRPLINT , "CIM single write to PL space", -1, 1 },
-		{ F_BLKRDPLINT , "CIM block read from PL space", -1, 1 },
-		{ F_BLKWRPLINT , "CIM block write to PL space", -1, 1 },
-		{ F_REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 },
-		{ F_RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 },
-		{ F_TIMEOUTINT , "CIM PIF timeout", -1, 1 },
-		{ F_TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 },
-		{ 0 }
+	struct intr_info cim_host_intr_info = {
+		.name = "CIM_HOST_INT_CAUSE",
+		.cause_reg = A_CIM_HOST_INT_CAUSE,
+		.enable_reg = A_CIM_HOST_INT_ENABLE,
+		.fatal = 0,
+		.details = cim_host_intr_details,
+		.actions = NULL,
 	};
+	static const struct intr_details cim_host_upacc_intr_details[] = {
+		{ F_EEPROMWRINT, "CIM EEPROM came out of busy state" },
+		{ F_TIMEOUTMAINT, "CIM PIF MA timeout" },
+		{ F_TIMEOUTINT, "CIM PIF timeout" },
+		{ F_RSPOVRLOOKUPINT, "CIM response FIFO overwrite" },
+		{ F_REQOVRLOOKUPINT, "CIM request FIFO overwrite" },
+		{ F_BLKWRPLINT, "CIM block write to PL space" },
+		{ F_BLKRDPLINT, "CIM block read from PL space" },
+		{ F_SGLWRPLINT,
+			"CIM single write to PL space with illegal BEs" },
+		{ F_SGLRDPLINT,
+			"CIM single read from PL space with illegal BEs" },
+		{ F_BLKWRCTLINT, "CIM block write to CTL space" },
+		{ F_BLKRDCTLINT, "CIM block read from CTL space" },
+		{ F_SGLWRCTLINT,
+			"CIM single write to CTL space with illegal BEs" },
+		{ F_SGLRDCTLINT,
+			"CIM single read from CTL space with illegal BEs" },
+		{ F_BLKWREEPROMINT, "CIM block write to EEPROM space" },
+		{ F_BLKRDEEPROMINT, "CIM block read from EEPROM space" },
+		{ F_SGLWREEPROMINT,
+			"CIM single write to EEPROM space with illegal BEs" },
+		{ F_SGLRDEEPROMINT,
+			"CIM single read from EEPROM space with illegal BEs" },
+		{ F_BLKWRFLASHINT, "CIM block write to flash space" },
+		{ F_BLKRDFLASHINT, "CIM block read from flash space" },
+		{ F_SGLWRFLASHINT, "CIM single write to flash space" },
+		{ F_SGLRDFLASHINT,
+			"CIM single read from flash space with illegal BEs" },
+		{ F_BLKWRBOOTINT, "CIM block write to boot space" },
+		{ F_BLKRDBOOTINT, "CIM block read from boot space" },
+		{ F_SGLWRBOOTINT, "CIM single write to boot space" },
+		{ F_SGLRDBOOTINT,
+			"CIM single read from boot space with illegal BEs" },
+		{ F_ILLWRBEINT, "CIM illegal write BEs" },
+		{ F_ILLRDBEINT, "CIM illegal read BEs" },
+		{ F_ILLRDINT, "CIM illegal read" },
+		{ F_ILLWRINT, "CIM illegal write" },
+		{ F_ILLTRANSINT, "CIM illegal transaction" },
+		{ F_RSVDSPACEINT, "CIM reserved space access" },
+		{0}
+	};
+	static const struct intr_info cim_host_upacc_intr_info = {
+		.name = "CIM_HOST_UPACC_INT_CAUSE",
+		.cause_reg = A_CIM_HOST_UPACC_INT_CAUSE,
+		.enable_reg = A_CIM_HOST_UPACC_INT_ENABLE,
+		.fatal = 0x3fffeeff,
+		.details = cim_host_upacc_intr_details,

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201902012042.x11Kgner081445>