Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 03 Sep 2019 14:06:50 -0000
From:      Navdeep Parhar <np@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r346188 - in stable/12/sys/dev/cxgbe: . common
Message-ID:  <201904131923.x3DJNBVr004818@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: np
Date: Sat Apr 13 19:23:11 2019
New Revision: 346188
URL: https://svnweb.freebsd.org/changeset/base/346188

Log:
  MFC r343666, r343861-r343862, r343923, r343968, r345660, and r345810.
  
  r343666:
  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
  
  r343861:
  cxgbe(4): Auto-dump the device log on a mailbox timeout or when the
  firmware reports an error in pcie_fw.
  
  Sponsored by:	Chelsio Communications
  
  r343862:
  cxgbe(4): Auto-dump the CIM block's logic analyzer on a TIMER0 interrupt.
  
  Sponsored by:	Chelsio Communications
  
  r343923:
  cxgbe(4): Delay the panic due to a fatal error by 30s.
  
  This lets information logged by the interrupt handler reach the system
  log before the system goes down.
  
  r343968:
  cxgbe(4): Ignore unused interrupts.
  
  Sponsored by:	Chelsio Communications
  
  r345660:
  cxgbe(4): Count and clear interrupts generated at the software's request.
  
  An interrupt can be requested by setting the F_SWINT bit in PL_PF_CTL.
  
  Sponsored by:	Chelsio Communications
  
  r345810:
  cxgbe(4): Add a flag to indicate that bits in interrupt cause but not in
  interrupt enable are not fatal.
  
  The firmware sets up all the interrupt enables based on run time
  configuration, which means the information in the enables is more
  accurate than what's compiled into the driver.  This change also allows
  the fatal bits to be updated without any changes in the driver in some
  cases.
  
  Sponsored by:	Chelsio Communications

Modified:
  stable/12/sys/dev/cxgbe/adapter.h
  stable/12/sys/dev/cxgbe/common/common.h
  stable/12/sys/dev/cxgbe/common/t4_hw.c
  stable/12/sys/dev/cxgbe/t4_main.c
  stable/12/sys/dev/cxgbe/t4_sge.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/dev/cxgbe/adapter.h
==============================================================================
--- stable/12/sys/dev/cxgbe/adapter.h	Sat Apr 13 16:51:48 2019	(r346187)
+++ stable/12/sys/dev/cxgbe/adapter.h	Sat Apr 13 19:23:11 2019	(r346188)
@@ -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)
@@ -893,6 +894,8 @@ struct adapter {
 	const char *last_op;
 	const void *last_op_thr;
 	int last_op_flags;
+
+	int swintr;
 };
 
 #define ADAPTER_LOCK(sc)		mtx_lock(&(sc)->sc_lock)
@@ -933,24 +936,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)
@@ -1106,6 +1091,38 @@ t4_use_ldst(struct adapter *sc)
 #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 */
 extern int t4_ntxq;
 extern int t4_nrxq;
@@ -1150,6 +1167,8 @@ void free_atid(struct adapter *, int);
 void release_tid(struct adapter *, int, struct sge_wrq *);
 int cxgbe_media_change(struct ifnet *);
 void cxgbe_media_status(struct ifnet *, struct ifmediareq *);
+bool t4_os_dump_cimla(struct adapter *, int, bool);
+void t4_os_dump_devlog(struct adapter *);
 
 #ifdef DEV_NETMAP
 /* t4_netmap.c */

Modified: stable/12/sys/dev/cxgbe/common/common.h
==============================================================================
--- stable/12/sys/dev/cxgbe/common/common.h	Sat Apr 13 16:51:48 2019	(r346187)
+++ stable/12/sys/dev/cxgbe/common/common.h	Sat Apr 13 19:23:11 2019	(r346188)
@@ -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 */
@@ -582,7 +578,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,
@@ -622,9 +618,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: stable/12/sys/dev/cxgbe/common/t4_hw.c
==============================================================================
--- stable/12/sys/dev/cxgbe/common/t4_hw.c	Sat Apr 13 16:51:48 2019	(r346187)
+++ stable/12/sys/dev/cxgbe/common/t4_hw.c	Sat Apr 13 19:23:11 2019	(r346188)
@@ -212,9 +212,11 @@ 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)]);
 		adap->flags &= ~FW_OK;
+		CH_ERR(adap, "firmware reports adapter error: %s (0x%08x)\n",
+		    reason[G_PCIE_FW_EVAL(pcie_fw)], pcie_fw);
+		if (pcie_fw != 0xffffffff)
+			t4_os_dump_devlog(adap);
 	}
 }
 
@@ -340,7 +342,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 +352,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 +382,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 +398,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 +426,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 +472,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);
@@ -499,27 +490,20 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int 
 	 * the error and also check to see if the firmware reported any
 	 * 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]));
+	if (pcie_fw & F_PCIE_FW_ERR) {
+		ret = -ENXIO;
+		t4_report_fw_error(adap);
+	} else {
+		ret = -ETIMEDOUT;
+		t4_os_dump_devlog(adap);
 	}
 
-	t4_report_fw_error(adap);
-	t4_fatal_err(adap);
+	t4_fatal_err(adap, true);
 	return ret;
 }
 
@@ -3965,785 +3949,1369 @@ 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);
+};
+
+#define NONFATAL_IF_DISABLED 1
 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 */
+	int flags;		/* hints */
+	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, fatal, leftover;
+	const struct intr_details *details;
+	char alert;
+
+	enable = t4_read_reg(adap, ii->enable_reg);
+	if (ii->flags & NONFATAL_IF_DISABLED)
+		fatal = ii->fatal & t4_read_reg(adap, ii->enable_reg);
+	else
+		fatal = ii->fatal;
+	alert = intr_alert_char(cause, enable, 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, 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, fatal;
+	bool rc;
+	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);
+	/*
+	 * The top level interrupt cause is a bit special and we need to ignore
+	 * the bits that are not in the enable.  Note that we did display them
+	 * above in t4_show_intr_info but will not clear them.
+	 */
+	if (ii->cause_reg == A_PL_INT_CAUSE)
+		cause &= t4_read_reg(adap, ii->enable_reg);
+	fatal = cause & ii->fatal;
+	if (fatal != 0 && ii->flags & NONFATAL_IF_DISABLED)
+		fatal &= t4_read_reg(adap, ii->enable_reg);
+	cause |= additional_cause;
+	if (cause == 0)
+		return (false);
+
+	rc = fatal != 0;
+	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;
+		rc |= (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 (rc);
 }
 
 /*
  * 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,
+		.flags = 0,
+		.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,
+		.flags = 0,
+		.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 = 0xffffffff,
+		.flags = NONFATAL_IF_DISABLED,
+		.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.details = pcie_intr_details;
+	} else {
+		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,
+		.flags = NONFATAL_IF_DISABLED,
+		.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,
+		.flags = NONFATAL_IF_DISABLED,
+		.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,
+		.flags = NONFATAL_IF_DISABLED,
+		.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,
+		.flags = 0,
+		.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,
+		.flags = 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,
+		.flags = NONFATAL_IF_DISABLED,
+		.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,
+		.flags = 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_action cim_host_intr_actions[] = {
+		{ F_TIMER0INT, 0, t4_os_dump_cimla },
+		{ 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 }
+	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}
 	};

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





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