changeset 25235:cb6c7dac98cb

12966 imc driver blew up on missing channel Reviewed by: Andy Fiddaman <andy@omniosce.org> Reviewed by: Igor Kozhukhov <igor@dilos.org> Reviewed by: Paul Winder <paul@winder.uk.net> Approved by: Dan McDonald <danmcd@joyent.com>
author Robert Mustacchi <rm@fingolfin.org>
date Thu, 09 Jul 2020 18:33:59 -0700
parents 75715aa4fe66
children 7459e8d6f008 5748e58a37bf
files usr/src/uts/i86pc/io/imc/imc.c usr/src/uts/i86pc/io/imc/imc.h
diffstat 2 files changed, 42 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/i86pc/io/imc/imc.c	Fri Nov 01 12:39:34 2019 -0700
+++ b/usr/src/uts/i86pc/io/imc/imc.c	Thu Jul 09 18:33:59 2020 -0700
@@ -932,6 +932,40 @@
 }
 
 /*
+ * In the wild we've hit a few odd cases where not all devices are exposed that
+ * we might expect by firmware. In particular we've seen and validate the
+ * following cases:
+ *
+ *  o We don't find all of the channel devices that we expect, e.g. we have the
+ *    stubs for channels 1-3, but not 0. That has been seen on an Intel S2600CW
+ *    with an E5-2630v3.
+ */
+static boolean_t
+imc_validate_stubs(imc_t *imc)
+{
+	for (uint_t sock = 0; sock < imc->imc_nsockets; sock++) {
+		imc_socket_t *socket = &imc->imc_sockets[sock];
+
+		for (uint_t mc = 0; mc < socket->isock_nimc; mc++) {
+			imc_mc_t *mcp = &socket->isock_imcs[mc];
+
+			for (uint_t chan = 0; chan < mcp->icn_nchannels;
+			    chan++) {
+				if (mcp->icn_channels[chan].ich_desc == NULL) {
+					dev_err(imc->imc_dip, CE_WARN,
+					    "!missing device for socket %u/"
+					    "imc %u/channel %u", sock, mc,
+					    chan);
+					return (B_FALSE);
+				}
+			}
+		}
+	}
+
+	return (B_TRUE);
+}
+
+/*
  * Attempt to map all of the discovered sockets to the corresponding APIC based
  * socket. We do these mappings by getting the node id of the socket and
  * adjusting it to make sure that no home agent is present in it. We use the
@@ -2194,6 +2228,11 @@
 		goto done;
 	}
 
+	if (!imc_validate_stubs(imc)) {
+		imc->imc_flags |= IMC_F_VALIDATE_FAILED;
+		goto done;
+	}
+
 	imc_fixup_stubs(imc);
 	imc_map_sockets(imc);
 
--- a/usr/src/uts/i86pc/io/imc/imc.h	Fri Nov 01 12:39:34 2019 -0700
+++ b/usr/src/uts/i86pc/io/imc/imc.h	Thu Jul 09 18:33:59 2020 -0700
@@ -500,12 +500,13 @@
 	IMC_F_SCAN_COMPLETE	= (1 << 2),
 	IMC_F_ATTACH_DISPATCHED	= (1 << 3),
 	IMC_F_ATTACH_COMPLETE	= (1 << 4),
-	IMC_F_MCREG_FAILED	= (1 << 5)
+	IMC_F_MCREG_FAILED	= (1 << 5),
+	IMC_F_VALIDATE_FAILED	= (1 << 6)
 } imc_flags_t;
 
 #define	IMC_F_ALL_FLAGS	(IMC_F_UNSUP_PLATFORM | IMC_F_SCAN_DISPATCHED | \
     IMC_F_SCAN_COMPLETE | IMC_F_ATTACH_DISPATCHED | IMC_F_ATTACH_COMPLETE | \
-    IMC_F_MCREG_FAILED)
+    IMC_F_MCREG_FAILED | IMC_F_VALIDATE_FAILED)
 
 typedef enum imc_dimm_type {
 	IMC_DIMM_UNKNOWN,