changeset 10049:b4b11e684225

6764337 CP3250 needs level 2 FMA compliance for MCU diagnosis
author Vuong Nguyen <Vuong.Nguyen@Sun.COM>
date Tue, 07 Jul 2009 06:31:07 -0400
parents 1eb2b3160451
children 09746c0f5a44
files usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc usr/src/lib/fm/topo/modules/i86pc/chip/chip_intel.c usr/src/uts/intel/io/intel_nb5000/dimm_addr.c usr/src/uts/intel/io/intel_nb5000/intel_nb5000.c usr/src/uts/intel/io/intel_nb5000/intel_nbdrv.c usr/src/uts/intel/io/intel_nb5000/nb5000.h usr/src/uts/intel/io/intel_nb5000/nb5000_init.c usr/src/uts/intel/io/intel_nb5000/nb_log.h usr/src/uts/intel/io/intel_nb5000/nb_pci_cfg.c usr/src/uts/intel/os/driver_aliases usr/src/uts/intel/sys/mc_intel.h
diffstat 11 files changed, 1012 insertions(+), 79 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc	Mon Jul 06 23:01:22 2009 -0700
+++ b/usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc	Tue Jul 07 06:31:07 2009 -0400
@@ -223,6 +223,8 @@
 engine stat.ce_pgflt@memory-controller/dram-channel/dimm;
 
 event ereport.cpu.intel.nb.mem_ue@motherboard/memory-controller{within(12s)};
+event ereport.cpu.intel.nb.ddr2_mem_ue@
+    motherboard/memory-controller{within(12s)};
 event ereport.cpu.intel.nb.fbd.ma@motherboard/memory-controller{within(12s)};
 event fault.memory.intel.page_ue@
     motherboard/memory-controller/dram-channel/dimm/rank,
@@ -236,18 +238,21 @@
     (payloadprop_defined("physaddr") || payloadprop_defined("offset")) &&
     SET_ADDR && SET_OFFSET } (1)->
     ereport.cpu.intel.nb.mem_ue@motherboard/memory-controller,
+    ereport.cpu.intel.nb.ddr2_mem_ue@motherboard/memory-controller,
     ereport.cpu.intel.nb.fbd.ma@motherboard/memory-controller;
 
 prop fault.memory.intel.dimm_ue@
     motherboard/memory-controller/dram-channel<channel_num>/dimm/rank[rank_num]
     { payloadprop_defined("rank") && rank_num == payloadprop("rank") } (1)->
     ereport.cpu.intel.nb.mem_ue@motherboard/memory-controller,
+    ereport.cpu.intel.nb.ddr2_mem_ue@motherboard/memory-controller,
     ereport.cpu.intel.nb.fbd.ma@motherboard/memory-controller;
 
 event upset.memory.intel.discard@motherboard/memory-controller{within(1s)};
 
 prop upset.memory.intel.discard@motherboard/memory-controller (0)->
     ereport.cpu.intel.nb.mem_ue@motherboard/memory-controller,
+    ereport.cpu.intel.nb.ddr2_mem_ue@motherboard/memory-controller,
     ereport.cpu.intel.nb.fbd.ma@motherboard/memory-controller;
 
 prop upset.memory.intel.discard@motherboard/memory-controller (0)->
@@ -260,6 +265,9 @@
 
 #define MBDIMM motherboard/memory-controller/dram-channel/dimm
 event ereport.cpu.intel.nb.mem_ce@MBDIMM/rank{within(12s)};
+event ereport.cpu.intel.nb.ddr2_mem_ce@MBDIMM/rank{within(12s)};
+event ereport.cpu.intel.nb.ddr2_mem_ce@
+    motherboard/memory-controller{within(12s)};
 
 engine serd.memory.intel.page_ce@MBDIMM/rank, N=PAGE_CE_COUNT, T=PAGE_CE_TIME;
 event fault.memory.intel.page_ce@MBDIMM/rank, message=0, response=0,
@@ -267,7 +275,8 @@
 prop fault.memory.intel.page_ce@MBDIMM/rank
     { (payloadprop_defined("physaddr") || payloadprop_defined("offset")) &&
     SET_ADDR && SET_OFFSET } (0)->
-    ereport.cpu.intel.nb.mem_ce@MBDIMM/rank;
+    ereport.cpu.intel.nb.mem_ce@MBDIMM/rank,
+    ereport.cpu.intel.nb.ddr2_mem_ce@MBDIMM/rank;
 
 engine serd.memory.intel.dimm_ce@MBDIMM/rank, N=DIMM_CE_COUNT, T=DIMM_CE_TIME;
 event fault.memory.intel.dimm_ce@MBDIMM/rank,
@@ -275,14 +284,15 @@
 prop fault.memory.intel.dimm_ce@MBDIMM/rank
     { !confprop_defined(MBDIMM, "dimm-size") &&
     count(stat.ce_pgflt@MBDIMM) > 512 } (1)->
-    ereport.cpu.intel.nb.mem_ce@MBDIMM/rank;
-
+    ereport.cpu.intel.nb.mem_ce@MBDIMM/rank,
+    ereport.cpu.intel.nb.ddr2_mem_ce@MBDIMM/rank;
 #define DIMM_CE(dimm_size, n, t, fault_rate) \
 	prop fault.memory.intel.dimm_ce@MBDIMM/rank { \
 	    confprop(MBDIMM, "dimm-size") == dimm_size && \
 	    count(stat.ce_pgflt@MBDIMM) > fault_rate && \
 	    setserdn(n) & setserdt(t) } (1)-> \
-    	    ereport.cpu.intel.nb.mem_ce@MBDIMM/rank;
+    	    ereport.cpu.intel.nb.mem_ce@MBDIMM/rank, \
+	    ereport.cpu.intel.nb.ddr2_mem_ce@MBDIMM/rank;
 	
 DIMM_CE("8G", 8, 1week, 2000)
 DIMM_CE("4G", 4, 1week, 1500)
@@ -291,6 +301,9 @@
 DIMM_CE("512M", 4, 8week, 250)
 DIMM_CE("256M", 4, 16week, 125)
 
+prop upset.memory.intel.discard@motherboard/memory-controller (0)->
+    ereport.cpu.intel.nb.ddr2_mem_ce@motherboard/memory-controller;
+
 event ereport.cpu.intel.nb.fbd.alert@rank{within(12s)};
 event fault.memory.intel.fbd.alert@rank, retire=0;
 
@@ -345,21 +358,26 @@
 event ereport.cpu.intel.nb.unknown@memory-controller {within(12s)};
 event ereport.cpu.intel.nb.unknown@memory-controller/dram-channel {within(12s)};
 event ereport.cpu.intel.nb.spd@memory-controller/dram-channel {within(12s)};
+event ereport.cpu.intel.nb.ddr2_spd@
+    memory-controller/dram-channel {within(12s)};
 event upset.discard@memory-controller;
 
 prop upset.discard@memory-controller (0)->
     ereport.cpu.intel.nb.unknown@memory-controller,
     ereport.cpu.intel.nb.unknown@memory-controller/dram-channel,
-    ereport.cpu.intel.nb.spd@memory-controller/dram-channel;
+    ereport.cpu.intel.nb.spd@memory-controller/dram-channel,
+    ereport.cpu.intel.nb.ddr2_spd@memory-controller/dram-channel;
 
 event ereport.cpu.intel.nb.mem_ds@memory-controller{within(30s)};
+event ereport.cpu.intel.nb.ddr2_mem_ds@memory-controller{within(30s)};
 event fault.memory.intel.fbd.mem_ds@memory-controller/dram-channel/dimm/rank,
     retire=0;
 
 prop fault.memory.intel.fbd.mem_ds@
     memory-controller/dram-channel/dimm/rank[rank_num]
     { payloadprop_defined("rank") && rank_num == payloadprop("rank") } (1)->
-    ereport.cpu.intel.nb.mem_ds@memory-controller;
+    ereport.cpu.intel.nb.mem_ds@memory-controller,
+    ereport.cpu.intel.nb.ddr2_mem_ds@memory-controller;
 
 event ereport.cpu.intel.nb.fsb@chip{within(12s)};
 event fault.cpu.intel.nb.fsb@chip, retire=0;
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip_intel.c	Mon Jul 06 23:01:22 2009 -0700
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_intel.c	Tue Jul 07 06:31:07 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -94,10 +94,10 @@
 	return (mc_fd != -1);
 }
 
-void
+static void
 mc_add_ranks(topo_mod_t *mod, tnode_t *dnode, nvlist_t *auth, int dimm,
-    nvlist_t **ranks_nvp, int nranks, char *serial, char *part, char *rev,
-    int maxranks)
+    nvlist_t **ranks_nvp, int start_rank, int nranks, char *serial, char *part,
+    char *rev, int maxranks)
 {
 	int i;
 	int rank;
@@ -106,10 +106,14 @@
 	nvlist_t *fmri;
 	int err = 0;
 
-	rank = dimm * maxranks;
+	/*
+	 * If start_rank is defined, it is assigned to the first rank of this
+	 * dimm.
+	 */
+	rank = start_rank >= 0 ? start_rank : dimm * maxranks;
 	if (topo_node_range_create(mod, dnode, RANK, rank,
 	    rank + nranks - 1) < 0) {
-		whinge(mod, NULL, "mc_add_dimms: node range create failed"
+		whinge(mod, NULL, "mc_add_ranks: node range create failed"
 		    " for rank\n");
 		return;
 	}
@@ -162,6 +166,7 @@
 	nvpair_t *nvp;
 	int err;
 	nvlist_t **ranks_nvp;
+	int32_t start_rank = -1;
 	uint_t nranks = 0;
 	char *serial = NULL;
 	char *part = NULL;
@@ -181,6 +186,8 @@
 			if (strcmp(name, MCINTEL_NVLIST_RANKS) == 0) {
 				(void) nvpair_value_nvlist_array(nvp,
 				    &ranks_nvp, &nranks);
+			} else if (strcmp(name, MCINTEL_NVLIST_1ST_RANK) == 0) {
+				(void) nvpair_value_int32(nvp, &start_rank);
 			} else if (strcmp(name, FM_FMRI_HC_SERIAL_ID) == 0) {
 				(void) nvpair_value_string(nvp, &serial);
 			} else if (strcmp(name, FM_FMRI_HC_PART) == 0) {
@@ -219,7 +226,8 @@
 		    nvp = nvlist_next_nvpair(nvl[i], nvp)) {
 			name = nvpair_name(nvp);
 			if (strcmp(name, MCINTEL_NVLIST_RANKS) != 0 &&
-			    strcmp(name, FM_FAULT_FRU_LABEL) != 0) {
+			    strcmp(name, FM_FAULT_FRU_LABEL) != 0 &&
+			    strcmp(name, MCINTEL_NVLIST_1ST_RANK) != 0) {
 				(void) nvprop_add(mod, nvp, PGNAME(DIMM),
 				    dnode);
 			}
@@ -228,8 +236,8 @@
 			(void) topo_node_label_set(dnode, label, &err);
 
 		if (nranks) {
-			mc_add_ranks(mod, dnode, auth, i, ranks_nvp, nranks,
-			    serial, part, rev, maxranks);
+			mc_add_ranks(mod, dnode, auth, i, ranks_nvp, start_rank,
+			    nranks, serial, part, rev, maxranks);
 		}
 	}
 }
@@ -297,7 +305,13 @@
 		    "mc_nb_create: failed to find channel information\n");
 		return (-1);
 	}
-	if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_NMEM, &nmc) != 0) {
+	if (nvlist_lookup_uint8(nvl, MCINTEL_NVLIST_NMEM, &nmc) == 0) {
+		/*
+		 * Assume channels are evenly divided among the controllers.
+		 * Convert nchannels to channels per controller
+		 */
+		nchannels = nchannels / nmc;
+	} else {
 		/*
 		 * if number of memory controllers is not specified then there
 		 * are two channels per controller and the nchannels is total
--- a/usr/src/uts/intel/io/intel_nb5000/dimm_addr.c	Mon Jul 06 23:01:22 2009 -0700
+++ b/usr/src/uts/intel/io/intel_nb5000/dimm_addr.c	Tue Jul 07 06:31:07 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -45,13 +45,18 @@
 dimm_getphys(int branch, int rank, int bank, int ras, int cas)
 {
 	uint8_t i;
+	int num_ranks_per_branch;
 	uint64_t m;
 	uint64_t pa;
 	struct rank_base *rp;
 	struct rank_geometry *rgp;
 
-	ASSERT(rank < nb_dimms_per_channel * 2);
-	rp = &rank_base[(branch * nb_dimms_per_channel * 2) + rank];
+	/* max number of ranks per branch */
+	num_ranks_per_branch = (nb_chipset == INTEL_NB_5100) ?
+	    NB_5100_RANKS_PER_CHANNEL :
+	    nb_dimms_per_channel * nb_channels_per_branch;
+	ASSERT(rank < num_ranks_per_branch);
+	rp = &rank_base[(branch * num_ranks_per_branch) + rank];
 	rgp = (struct rank_geometry *)rp->rank_geometry;
 	if (rgp == NULL)
 		return (-1LL);
@@ -98,6 +103,7 @@
 dimm_getoffset(int branch, int rank, int bank, int ras, int cas)
 {
 	uint8_t i;
+	int num_ranks_per_branch;
 	uint64_t m;
 	uint64_t offset;
 	struct dimm_geometry *dgp;
@@ -106,9 +112,14 @@
 	uint64_t pa;
 	uint64_t cal_pa;
 
-	ASSERT(rank < nb_dimms_per_channel * 2);
-	rp = &rank_base[(branch * nb_dimms_per_channel * 2) + rank];
-	dgp = dimm_geometry[(branch * nb_dimms_per_channel) + rank/2];
+	/* max number of ranks per branch */
+	num_ranks_per_branch = (nb_chipset == INTEL_NB_5100) ?
+	    NB_5100_RANKS_PER_CHANNEL :
+	    nb_dimms_per_channel * nb_channels_per_branch;
+	ASSERT(rank < num_ranks_per_branch);
+	rp = &rank_base[(branch * num_ranks_per_branch) + rank];
+	dgp = dimm_geometry[(branch * nb_dimms_per_channel) +
+	    nb_rank2dimm(branch, rank)];
 	if (dgp == NULL)
 		return (TCODE_OFFSET(rank, bank, ras, cas));
 	rgp = (struct rank_geometry *)&dgp->rank_geometry[0];
@@ -224,6 +235,7 @@
 static cmi_errno_t
 inb_unumtopa(void *arg, mc_unum_t *unump, nvlist_t *nvl, uint64_t *pap)
 {
+	int num_ranks_per_branch;
 	mc_unum_t unum;
 	uint64_t pa;
 	struct rank_base *rp;
@@ -244,7 +256,13 @@
 		*pap = pa;
 		return (CMI_SUCCESS);
 	}
-	rp = &rank_base[(unump->unum_mc * nb_dimms_per_channel * 2) +
+
+
+	/* max number of ranks per branch */
+	num_ranks_per_branch = (nb_chipset == INTEL_NB_5100) ?
+	    NB_5100_RANKS_PER_CHANNEL :
+	    nb_dimms_per_channel * nb_channels_per_branch;
+	rp = &rank_base[(unump->unum_mc * num_ranks_per_branch) +
 	    unump->unum_rank];
 	pa = rp->base + (unump->unum_offset * rp->interleave);
 
@@ -257,20 +275,36 @@
 void
 dimm_init()
 {
+	int num_ranks_per_branch;
+
 	dimm_geometry = kmem_zalloc(sizeof (void *) *
 	    nb_number_memory_controllers * nb_dimms_per_channel, KM_SLEEP);
+
+	/* max number of ranks per branch */
+	num_ranks_per_branch = (nb_chipset == INTEL_NB_5100) ?
+	    NB_5100_RANKS_PER_CHANNEL :
+	    nb_dimms_per_channel * nb_channels_per_branch;
+
 	rank_base = kmem_zalloc(sizeof (struct rank_base) *
-	    nb_number_memory_controllers * nb_dimms_per_channel * 2, KM_SLEEP);
+	    nb_number_memory_controllers * num_ranks_per_branch, KM_SLEEP);
 }
 
 void
 dimm_fini()
 {
+	int num_ranks_per_branch;
+
 	kmem_free(dimm_geometry, sizeof (void *) *
 	    nb_number_memory_controllers * nb_dimms_per_channel);
 	dimm_geometry = 0;
+
+	/* max number of ranks per branch */
+	num_ranks_per_branch = (nb_chipset == INTEL_NB_5100) ?
+	    NB_5100_RANKS_PER_CHANNEL :
+	    nb_dimms_per_channel * nb_channels_per_branch;
+
 	kmem_free(rank_base, sizeof (struct rank_base) *
-	    nb_number_memory_controllers * nb_dimms_per_channel * 2);
+	    nb_number_memory_controllers * num_ranks_per_branch);
 	rank_base = 0;
 }
 
@@ -299,9 +333,16 @@
 	struct dimm_geometry *dimm;
 	struct rank_base *rp;
 	int interleave_nbits;
+	int num_ranks_per_branch;
 
-	dimm = dimm_geometry[(branch * nb_dimms_per_channel) + (rank / 2)];
-	rp = &rank_base[(branch * nb_dimms_per_channel * 2) + rank];
+	dimm = dimm_geometry[(branch * nb_dimms_per_channel) +
+	    nb_rank2dimm(branch, rank)];
+
+	/* max number of ranks per branch */
+	num_ranks_per_branch = (nb_chipset == INTEL_NB_5100) ?
+	    NB_5100_RANKS_PER_CHANNEL :
+	    nb_dimms_per_channel * nb_channels_per_branch;
+	rp = &rank_base[(branch * num_ranks_per_branch) + rank];
 	if (interleave == 1)
 		interleave_nbits = 0;
 	else if (interleave == 2)
--- a/usr/src/uts/intel/io/intel_nb5000/intel_nb5000.c	Mon Jul 06 23:01:22 2009 -0700
+++ b/usr/src/uts/intel/io/intel_nb5000/intel_nb5000.c	Tue Jul 07 06:31:07 2009 -0400
@@ -44,6 +44,8 @@
 #include "nb_log.h"
 #include "dimm_phys.h"
 
+int nb_check_validlog = 1;
+
 static uint32_t uerrcnt[2];
 static uint32_t cerrcnta[2][2];
 static uint32_t cerrcntb[2][2];
@@ -306,6 +308,156 @@
 	return (intr);
 }
 
+static struct mch_error_code nf_mem_error_code[] = {
+	{ 21, EMASK_MEM_M21, ERR_NF_MEM_M21 },
+	{ 20, EMASK_MEM_M20, ERR_NF_MEM_M20 },
+	{ 18, EMASK_MEM_M18, ERR_NF_MEM_M18 },
+	{ 16, EMASK_MEM_M16, ERR_NF_MEM_M16 },
+	{ 15, EMASK_MEM_M15, ERR_NF_MEM_M15 },
+	{ 14, EMASK_MEM_M14, ERR_NF_MEM_M14 },
+	{ 12, EMASK_MEM_M12, ERR_NF_MEM_M12 },
+	{ 11, EMASK_MEM_M11, ERR_NF_MEM_M11 },
+	{ 10, EMASK_MEM_M10, ERR_NF_MEM_M10 },
+	{ 6, EMASK_MEM_M6, ERR_NF_MEM_M6 },
+	{ 5, EMASK_MEM_M5, ERR_NF_MEM_M5 },
+	{ 4, EMASK_MEM_M4, ERR_NF_MEM_M4 },
+	{ 1, EMASK_MEM_M1, ERR_NF_MEM_M1 }
+};
+
+static int
+intel_nf_mem_err(uint32_t nf_mem)
+{
+	int rt = -1;
+	int nerr = 0;
+	uint32_t emask_mem = 0;
+	int i;
+	int sz;
+
+	sz = sizeof (nf_mem_error_code) / sizeof (struct mch_error_code);
+
+	for (i = 0; i < sz; i++) {
+		if (nf_mem & nf_mem_error_code[i].error_bit) {
+			rt = nf_mem_error_code[i].intel_error_list;
+			emask_mem |= nf_mem_error_code[i].emask;
+			nerr++;
+		}
+	}
+	if (emask_mem)
+		nb_mem_mask_mc(emask_mem);
+	if (nerr > 1)
+		rt = -1;
+	return (rt);
+}
+
+static char *
+nf_mem_error(const nb_regs_t *rp, void *data)
+{
+	uint32_t ferr_nf_mem, recmema, recmemb;
+	uint32_t nrecmema, nrecmemb, validlog;
+	int channel;
+	char *intr = "nb.unknown";
+	nb_mem_scatchpad_t *sp = &((nb_scatchpad_t *)data)->ms;
+
+	sp->rank = -1;
+	sp->dimm = -1;
+	sp->bank = -1;
+	sp->cas = -1;
+	sp->ras = -1LL;
+	sp->pa = -1LL;
+	sp->offset = -1;
+	ferr_nf_mem = rp->nb.nf_mem_regs.ferr_nf_mem;
+	if ((ferr_nf_mem & ERR_NF_MEM_MASK) == 0) {
+		/* no first error found */
+		sp->branch = -1;
+		sp->channel = -1;
+		sp->intel_error_list =
+		    intel_nf_mem_err(rp->nb.nf_mem_regs.nerr_nf_mem);
+		return (intr);
+	}
+	sp->intel_error_list = intel_nf_mem_err(ferr_nf_mem);
+
+	channel = (ferr_nf_mem >> ERR_MEM_CH_SHIFT) & 0x1;
+	sp->branch = channel;
+	sp->channel = -1;
+	if (ferr_nf_mem & ERR_NF_MEM_MASK) {
+		if (ferr_nf_mem & ERR_NF_MEM_ECC_UE) {
+			/*
+			 * uncorrectable ECC M1,M4-M6,M10-M12
+			 * There is only channel per branch
+			 * Invalidate the channel number so the mem ereport
+			 * has the same detector with existing 5000 ereports.
+			 * so we can leverage the existing Everhsolt rule.
+			 */
+			validlog = rp->nb.nf_mem_regs.validlog;
+			if (ferr_nf_mem & ERR_NF_MEM_M1) {
+				nrecmema = rp->nb.nf_mem_regs.nrecmema;
+				nrecmemb = rp->nb.nf_mem_regs.nrecmemb;
+				/* check if the nrecmem log is valid */
+				if (validlog & 0x1 || nb_check_validlog == 0) {
+					sp->rank = (nrecmema >> 8) & RANK_MASK;
+					sp->bank = (nrecmema >> 12) & BANK_MASK;
+					sp->cas = (nrecmemb >> 16) & CAS_MASK;
+					sp->ras = nrecmemb & RAS_MASK;
+				}
+			} else {
+				recmema = rp->nb.nf_mem_regs.recmema;
+				recmemb = rp->nb.nf_mem_regs.recmemb;
+				/* check if the recmem log is valid */
+				if (validlog & 0x2 || nb_check_validlog == 0) {
+					sp->rank = (recmema >> 8) & RANK_MASK;
+					sp->bank = (recmema >> 12) & BANK_MASK;
+					sp->cas = (recmemb >> 16) & CAS_MASK;
+					sp->ras = recmemb & RAS_MASK;
+				}
+			}
+			intr = "nb.ddr2_mem_ue";
+		} else if ((ferr_nf_mem & ERR_NF_MEM_ECC_CE) != 0) {
+			/* correctable ECC M14-M16 */
+			recmema = rp->nb.nf_mem_regs.recmema;
+			recmemb = rp->nb.nf_mem_regs.recmemb;
+			validlog = rp->nb.nf_mem_regs.validlog;
+			/* check if the recmem log is valid */
+			if (validlog & 0x2 || nb_check_validlog == 0) {
+				sp->channel = channel;
+				sp->rank = (recmema >> 8) & RANK_MASK;
+				sp->dimm = nb_rank2dimm(sp->channel, sp->rank);
+				sp->bank = (recmema >> 12) & BANK_MASK;
+				sp->cas = (recmemb >> 16) & CAS_MASK;
+				sp->ras = recmemb & RAS_MASK;
+			}
+			intr = "nb.ddr2_mem_ce";
+		} else if ((ferr_nf_mem & ERR_NF_MEM_SPARE) != 0) {
+			/* spare dimm M20, M21 */
+			intr = "nb.ddr2_mem_ds";
+
+			/*
+			 * The channel can be valid here.
+			 * However, there is only one channel per branch and
+			 * to leverage the eversolt rules of other chipsets,
+			 * the channel is ignored and let the rule find it out
+			 * from the topology.
+			 */
+			if (rp->nb.nf_mem_regs.spcps & SPCPS_SPARE_DEPLOYED) {
+				sp->rank =
+				    SPCPS_FAILED_RANK(rp->nb.nf_mem_regs.spcps);
+				nb_used_spare_rank(sp->branch, sp->rank);
+				nb_config_gen++;
+			}
+		} else if ((ferr_nf_mem & ERR_NF_MEM_M18) != 0) {
+			sp->channel = channel;
+			intr = "nb.ddr2_spd";	/* SPD protocol */
+
+		}
+	}
+	if (sp->ras != -1) {
+		sp->pa = dimm_getphys(sp->branch, sp->rank, sp->bank, sp->ras,
+		    sp->cas);
+		sp->offset = dimm_getoffset(sp->branch, sp->rank, sp->bank,
+		    sp->ras, sp->cas);
+	}
+	return (intr);
+}
+
 static struct mch_error_code fat_int_error_code[] = {
 	{ 14, EMASK_INT_B14, ERR_FAT_INT_B14 },
 	{ 12, EMASK_INT_B12, ERR_FAT_INT_B12 },
@@ -1053,6 +1205,63 @@
 }
 
 static void
+log_nf_mem_err(nb_regs_t *rp, int willpanic, int *interpose)
+{
+	int channel, branch;
+	int t = 0;
+
+	rp->flag = NB_REG_LOG_NF_MEM;
+
+	/* Memmory err registers */
+	rp->nb.nf_mem_regs.ferr_nf_mem = FERR_NF_MEM_RD(interpose);
+	channel = (rp->nb.nf_mem_regs.ferr_nf_mem >> 28) & 0x1;
+	branch = channel;
+	rp->nb.nf_mem_regs.nerr_nf_mem = NERR_NF_MEM_RD(&t);
+	*interpose |= t;
+	rp->nb.nf_mem_regs.redmema = MEM_REDMEMA_RD(branch);
+	rp->nb.nf_mem_regs.redmemb = MEM_REDMEMB_RD(branch);
+	rp->nb.nf_mem_regs.recmema = MEM_RECMEMA_RD(branch);
+	rp->nb.nf_mem_regs.recmemb = MEM_RECMEMB_RD(branch);
+	rp->nb.nf_mem_regs.nrecmema = MEM_NRECMEMA_RD(branch);
+	rp->nb.nf_mem_regs.nrecmemb = MEM_NRECMEMB_RD(branch);
+
+	/* spare rank */
+	rp->nb.nf_mem_regs.spcps = SPCPS_RD(branch);
+	rp->nb.nf_mem_regs.spcpc = SPCPC_RD(branch);
+
+	/* RAS registers */
+	rp->nb.nf_mem_regs.cerrcnt = MEM_CERRCNT_RD(branch);
+	rp->nb.nf_mem_regs.cerrcnt_ext = (uint32_t)MEM_CERRCNT_EXT_RD(branch);
+	rp->nb.nf_mem_regs.cerrcnt_last = cerrcnta[branch][channel & 1];
+	rp->nb.nf_mem_regs.cerrcnt_ext_last = cerrcntb[branch][channel & 1];
+	cerrcnta[branch][channel & 1] = rp->nb.nf_mem_regs.cerrcnt;
+	cerrcntb[branch][channel & 1] = rp->nb.nf_mem_regs.cerrcnt_ext;
+	rp->nb.nf_mem_regs.badram = BADRAMA_RD(branch);
+	rp->nb.nf_mem_regs.badcnt = BADCNT_RD(branch);
+	rp->nb.nf_mem_regs.validlog = VALIDLOG_RD(branch);
+
+	if (!willpanic) {
+		if (rp->nb.nf_mem_regs.ferr_nf_mem || *interpose)
+			FERR_NF_MEM_WR(rp->nb.nf_mem_regs.ferr_nf_mem);
+		if (rp->nb.nf_mem_regs.nerr_nf_mem)
+			NERR_NF_MEM_WR(rp->nb.nf_mem_regs.nerr_nf_mem);
+		/*
+		 * if interpose, write read-only registers to clear from pci
+		 * cache
+		 */
+		if (*interpose) {
+			MEM_NRECMEMA_WR(branch);
+			MEM_NRECMEMB_WR(branch);
+			MEM_REDMEMA_WR(branch);
+			MEM_REDMEMB_WR(branch);
+			MEM_RECMEMA_WR(branch);
+			MEM_RECMEMB_WR(branch);
+			SPCPS_WR(branch);
+		}
+	}
+}
+
+static void
 log_ferr(uint64_t ferr, uint32_t *nerrp, nb_logout_t *log, int willpanic)
 {
 	nb_regs_t *rp = &log->nb_regs;
@@ -1070,6 +1279,9 @@
 	} else if ((ferr & GE_FBD_NF) != 0) {
 		log_nf_fbd_err(rp, willpanic, &interpose);
 		*nerrp = nerr & ~GE_NERR_FBD_NF;
+	} else if ((ferr & GE_MEM_NF) != 0) {
+		log_nf_mem_err(rp, willpanic, &interpose);
+		*nerrp = nerr & ~GE_NERR_MEM_NF;
 	} else if ((ferr & (GE_FERR_FSB_FATAL | GE_FERR_FSB_NF)) != 0) {
 		log_fsb_err(ferr, rp, willpanic, &interpose);
 		*nerrp = nerr & ~(GE_NERR_FSB_FATAL | GE_NERR_FSB_NF);
@@ -1113,6 +1325,9 @@
 	} else if ((err & GE_NERR_FBD_NF) != 0) {
 		log_nf_fbd_err(rp, willpanic, &interpose);
 		*errp = err & ~GE_NERR_FBD_NF;
+	} else if ((err & GE_NERR_MEM_NF) != 0) {
+		log_nf_mem_err(rp, willpanic, &interpose);
+		*errp = err & ~GE_NERR_MEM_NF;
 	} else if ((err & (GE_NERR_FSB_FATAL | GE_NERR_FSB_NF)) != 0) {
 		log_fsb_err(GE_NERR_TO_FERR_FSB(err), rp, willpanic,
 		    &interpose);
@@ -1453,6 +1668,78 @@
 }
 
 static void
+nb_nf_mem_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload,
+    nb_scatchpad_t *data)
+{
+	nb_mem_scatchpad_t *sp;
+	char buf[32];
+
+	sp = &((nb_scatchpad_t *)data)->ms;
+
+	if (sp->dimm == -1 && sp->rank != -1) {
+		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RANK,
+		    DATA_TYPE_INT32, sp->rank, NULL);
+	}
+	if (sp->ras != -1) {
+		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK,
+		    DATA_TYPE_INT32, sp->bank, NULL);
+		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CAS,
+		    DATA_TYPE_INT32, sp->cas, NULL);
+		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RAS,
+		    DATA_TYPE_INT32, sp->ras, NULL);
+		if (sp->offset != -1LL) {
+			fm_payload_set(payload, FM_FMRI_MEM_OFFSET,
+			    DATA_TYPE_UINT64, sp->offset, NULL);
+		}
+		if (sp->pa != -1LL) {
+			fm_payload_set(payload, FM_FMRI_MEM_PHYSADDR,
+			    DATA_TYPE_UINT64, sp->pa, NULL);
+		}
+	}
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_NF_MEM,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.ferr_nf_mem, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NERR_NF_MEM,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.nerr_nf_mem, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECMEMA,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.recmema, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RECMEMB,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.recmemb, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_REDMEMA,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.redmema, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_REDMEMB,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.redmemb, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECMEMA,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.nrecmema, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_NRECMEMB,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.nrecmemb, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPS,
+	    DATA_TYPE_UINT8, nb_regs->nb.nf_mem_regs.spcps, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SPCPC,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.spcpc, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.cerrcnt, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT_LAST,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.cerrcnt_last, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT_EXT,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.cerrcnt_ext, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_CERRCNT_EXT_LAST,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.cerrcnt_ext_last, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADRAM,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.badram, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BADCNT,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.badcnt, NULL);
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_VALIDLOG,
+	    DATA_TYPE_UINT32, nb_regs->nb.nf_mem_regs.validlog, NULL);
+
+	if (sp->intel_error_list >= 0)
+		(void) snprintf(buf, sizeof (buf), "M%d", sp->intel_error_list);
+	else
+		(void) snprintf(buf, sizeof (buf), "Multiple or unknown error");
+	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ERROR_NO,
+	    DATA_TYPE_STRING, buf, NULL);
+}
+
+static void
 nb_dma_err_payload(const nb_regs_t *nb_regs, nvlist_t *payload)
 {
 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PCISTS,
@@ -1519,6 +1806,9 @@
 	case NB_REG_LOG_THR:
 		nb_thr_err_payload(nb_regs, payload, data);
 		break;
+	case NB_REG_LOG_NF_MEM:
+		nb_nf_mem_err_payload(nb_regs, payload, data);
+		break;
 	default:
 		fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FERR_GLOBAL,
 		    DATA_TYPE_UINT64, nb_regs->ferr, NULL);
@@ -1720,6 +2010,41 @@
 	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, "nb", "otf");
 }
 
+void
+nb_nf_mem_report(const nb_regs_t *nb_regs, char *class, nvlist_t *detector,
+    void *data)
+{
+	char *intr;
+	nb_mem_scatchpad_t *sp;
+
+	intr = nf_mem_error(nb_regs, data);
+	sp = &((nb_scatchpad_t *)data)->ms;
+
+	if (sp->dimm != -1) {
+		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 5,
+		    "motherboard", 0,
+		    "memory-controller", sp->branch,
+		    "dram-channel", sp->channel,
+		    "dimm", sp->dimm,
+		    "rank", sp->rank);
+	} else if (sp->channel != -1) {
+		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 3,
+		    "motherboard", 0,
+		    "memory-controller", sp->branch,
+		    "dram-channel", sp->channel);
+	} else if (sp->branch != -1) {
+		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 2,
+		    "motherboard", 0,
+		    "memory-controller", sp->branch);
+	} else {
+		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
+		    "motherboard", 0);
+	}
+
+	(void) snprintf(class, FM_MAX_CLASS, "%s.%s.%s",
+	    FM_ERROR_CPU, FM_EREPORT_CPU_INTEL, intr);
+}
+
 
 nvlist_t *
 nb_report(const nb_regs_t *nb_regs, char *class, nv_alloc_t *nva, void *scratch)
@@ -1748,6 +2073,9 @@
 	case NB_REG_LOG_THR:
 		nb_thr_report(nb_regs, class, detector, scratch);
 		break;
+	case NB_REG_LOG_NF_MEM:
+		nb_nf_mem_report(nb_regs, class, detector, scratch);
+		break;
 	default:
 		fm_fmri_hc_set(detector, FM_HC_SCHEME_VERSION, NULL, NULL, 1,
 		    "motherboard", 0);
--- a/usr/src/uts/intel/io/intel_nb5000/intel_nbdrv.c	Mon Jul 06 23:01:22 2009 -0700
+++ b/usr/src/uts/intel/io/intel_nb5000/intel_nbdrv.c	Tue Jul 07 06:31:07 2009 -0400
@@ -106,6 +106,7 @@
 	return (base);
 }
 
+/*ARGSUSED*/
 void
 inb_rank(nvlist_t *newdimm, nb_dimm_t *nb_dimm, uint8_t channel, uint32_t dimm)
 {
@@ -122,7 +123,8 @@
 		uint64_t hole_base;
 		uint64_t hole_size;
 
-		dimm_base = rank_to_base(channel/2, dimm*2 + i, &interleave,
+		dimm_base = rank_to_base(channel/nb_channels_per_branch,
+		    nb_dimm->start_rank + i, &interleave,
 		    &limit, &hole_base, &hole_size, &way, &branch_interleave);
 		(void) nvlist_alloc(&newrank[i], NV_UNIQUE_NAME, KM_SLEEP);
 
@@ -178,6 +180,8 @@
 	    (uint32_t)nb_dimm->ncolumn);
 	(void) nvlist_add_uint32(newdimm, "nrow", (uint32_t)nb_dimm->nrow);
 	(void) nvlist_add_uint32(newdimm, "width", (uint32_t)nb_dimm->width);
+	(void) nvlist_add_int32(newdimm, MCINTEL_NVLIST_1ST_RANK,
+	    (int32_t)nb_dimm->start_rank);
 	(void) nvlist_add_uint32(newdimm, "ranks", (uint32_t)nb_dimm->nranks);
 	inb_rank(newdimm, nb_dimm, channel, dimm);
 	(void) nvlist_add_uint32(newdimm, "manufacture-id",
@@ -220,7 +224,7 @@
 {
 	nvlist_t **dimmlist;
 	nvlist_t **newchannel;
-	int nchannels = nb_number_memory_controllers * 2;
+	int nchannels = nb_number_memory_controllers * nb_channels_per_branch;
 	int nd;
 	uint8_t i, j;
 	nb_dimm_t **dimmpp;
@@ -274,6 +278,9 @@
 	case INTEL_NB_5400B:
 		mc = "Intel 5400B";
 		break;
+	case INTEL_NB_5100:
+		mc = "Intel 5100";
+		break;
 	case INTEL_NB_5000P:
 		mc = "Intel 5000P";
 		break;
@@ -302,6 +309,9 @@
 	(void) nvlist_add_uint8(nvl, MCINTEL_NVLIST_VERSTR,
 	    MCINTEL_NVLIST_VERS);
 	(void) nvlist_add_string(nvl, "memory-controller", inb_mc_name());
+	if (nb_chipset == INTEL_NB_5100)
+		(void) nvlist_add_uint8(nvl, MCINTEL_NVLIST_NMEM,
+		    (uint8_t)nb_number_memory_controllers);
 	inb_dimmlist(nvl);
 
 	if (inb_mc_nvl)
--- a/usr/src/uts/intel/io/intel_nb5000/nb5000.h	Mon Jul 06 23:01:22 2009 -0700
+++ b/usr/src/uts/intel/io/intel_nb5000/nb5000.h	Tue Jul 07 06:31:07 2009 -0400
@@ -34,8 +34,12 @@
 #include <sys/cpu_module.h>
 
 #define	NB_5000_MAX_MEM_CONTROLLERS	2
-#define	NB_MAX_DIMMS_PER_CHANNEL	(nb_chipset == INTEL_NB_7300 ? 8 : 4)
-#define	NB_MEM_BRANCH_SELECT		(nb_chipset == INTEL_NB_5400 ? 2 : 3)
+#define	NB_MAX_DIMMS_PER_CHANNEL	(nb_chipset == INTEL_NB_5100 ? 3 : \
+	(nb_chipset == INTEL_NB_7300 ? 8 : 4))
+#define	NB_MAX_CHANNELS_PER_BRANCH	2
+#define	NB_5100_RANKS_PER_CHANNEL	6
+#define	NB_MEM_BRANCH_SELECT \
+	(nb_chipset == INTEL_NB_5400 || nb_chipset == INTEL_NB_5100 ? 2 : 3)
 #define	NB_MAX_MEM_BRANCH_SELECT	3
 #define	NB_MEM_RANK_SELECT		(nb_chipset == INTEL_NB_7300 ? 7 : 5)
 #define	NB_MAX_MEM_RANK_SELECT		7
@@ -64,20 +68,29 @@
 #define	TLOW_MAX	0x100000000ULL
 
 #define	MTR_PRESENT(mtr) \
-	((mtr) & (nb_chipset == INTEL_NB_5400 ? 0x0400 : 0x0100))
+	((mtr) & (nb_chipset == INTEL_NB_5400 || nb_chipset == INTEL_NB_5100 ? \
+	0x0400 : 0x0100))
 #define	MTR_ETHROTTLE(mtr) \
-	((mtr) & (nb_chipset == INTEL_NB_5400 ? 0x0200 : 0x0080))
+	((mtr) & (nb_chipset == INTEL_NB_5400 || nb_chipset == INTEL_NB_5100 ? \
+	? 0x0200 : 0x0080))
 #define	MTR_WIDTH(mtr) \
-	(((mtr) & (nb_chipset == INTEL_NB_5400 ? 0x0100 : 0x0040)) ? 8 : 4)
+	((mtr) & (nb_chipset == INTEL_NB_5400 || nb_chipset == INTEL_NB_5100 ? \
+	0x0100 : 0x0040) ? 8 : 4)
 #define	MTR_NUMBANK(mtr) \
-	(((mtr) & (nb_chipset == INTEL_NB_5400 ? 0x0040 : 0x0020)) ? 8 : 4)
-#define	MTR_NUMRANK(mtr) \
-	(((mtr) & (nb_chipset == INTEL_NB_5400 ? 0x0020 : 0x0010)) ? 2 : 1)
+	((mtr) & (nb_chipset == INTEL_NB_5400 || nb_chipset == INTEL_NB_5100 ? \
+	0x0040 : 0x0020) ? 8 : 4)
+#define	MTR_NUMRANK(mtr) (nb_chipset == INTEL_NB_5100 ? 1 : \
+	(((mtr) & (nb_chipset == INTEL_NB_5400 ? 0x0020 : 0x0010)) ? 2 : 1))
 #define	MTR_NUMROW(mtr) ((((mtr) >> 2) & 3) + 13)
 #define	MTR_NUMCOL(mtr) (((mtr) & 3) + 10)
 
 #define	MTR_DIMMSIZE(mtr) 	((1ULL << (MTR_NUMCOL(mtr) + MTR_NUMROW(mtr))) \
 	* MTR_NUMRANK(mtr) * MTR_NUMBANK(mtr) * MTR_WIDTH(mtr))
+#define	DIMMSIZE(nrow, ncol, nrank, nbank, width) \
+	((1ULL << ((ncol) + (nrow))) * (nrank) * (nbank) * (width))
+#define	MTR_DDR2_DIMMSIZE(mtr, nrank) \
+	((1ULL << (MTR_NUMCOL(mtr) + MTR_NUMROW(mtr))) \
+	* (nrank) * MTR_NUMBANK(mtr) * MTR_WIDTH(mtr))
 
 /* FERR_GLOBAL and NERR_GLOBAL */
 #define	GE_FERR_FSB3_FATAL	0x800000000ULL	/* FSB3 Fatal Error */
@@ -114,6 +127,8 @@
 #define	GE_FERR_FBD1_NF	0x00000200	/* FBD channel 1 Non-Fatal Error */
 #define	GE_FERR_FBD0_NF	0x00000100	/* FBD channel 0 Non-Fatal Error */
 #define	GE_FERR_FBD_NF	0x00000800	/* FBD channel Non-Fatal Error */
+#define	GE_FERR_MEM1_NF	0x00000200	/* DDR channel 1 Non-Fatal Error */
+#define	GE_FERR_MEM0_NF	0x00000100	/* DDR channel 0 Non-Fatal Error */
 #define	GE_FERR_THERMAL_NF 0x00000400	/* Thermal Non-Fatal Error */
 #define	GE_PCIEX9_NF	0x00000200	/* PCI Express dev 9 Non-Fatal Error */
 #define	GE_PCIEX8_NF	0x00000100	/* PCI Express dev 8 Non-Fatal Error */
@@ -128,11 +143,14 @@
 
 #define	GE_NERR_FSB2_FATAL	0x08000000 /* FSB2 Fatal Error */
 #define	GE_NERR_FSB3_FATAL	0x04000000 /* FSB3 Fatal Error */
-#define	GE_NERR_FBD_FATAL	0x01000000 /* FBD channel Fatal Error */
+#define	GE_NERR_FBD_FATAL	(nb_chipset == INTEL_NB_5100 ? 0 : 0x01000000)
+					/* FBD channel Fatal Error */
 #define	GE_NERR_FSB2_NF		0x00000800 /* FSB2 Non-Fatal Error */
 #define	GE_NERR_FSB3_NF		0x00000400 /* FSB3 Non-Fatal Error */
-#define	GE_NERR_FBD_NF		0x00000100 /* FBD channel Non-Fatal Error */
-
+#define	GE_NERR_FBD_NF		(nb_chipset == INTEL_NB_5100 ? 0 : 0x00000100)
+					/* FBD channel Non-Fatal Error */
+#define	GE_NERR_MEM_NF		(nb_chipset == INTEL_NB_5100 ? 0x00000100 : 0)
+					/* DDR channel0,1 Non-Fatal Error */
 #define	ERR_FAT_FSB_F9		0x20	/* F9Msk FSB Protocol */
 #define	ERR_FAT_FSB_F2		0x08	/* F2Msk Unsupported Bus Transaction */
 #define	ERR_FAT_FSB_F1		0x01 	/* F1Msk Request/Address Parity */
@@ -287,6 +305,47 @@
 	EMASK_FBD_M11|EMASK_FBD_M10|EMASK_FBD_M9|EMASK_FBD_M8|EMASK_FBD_M7| \
 	EMASK_FBD_M6|EMASK_FBD_M5|EMASK_FBD_M4)
 
+/* FERR_NF_MEM: MC First non-fatal errors */
+#define	ERR_MEM_CH_SHIFT	28	/* channel index in nf_mem */
+
+#define	ERR_NF_MEM_M21	0x00200000	/* M21Err Spare Copy Completed */
+#define	ERR_NF_MEM_M20	0x00100000	/* M20Err Spare Copy Initiated */
+#define	ERR_NF_MEM_M18	0x00040000	/* M18Err SPD protocal */
+#define	ERR_NF_MEM_M16	0x00010000	/* M16Err Correctable Patrol Data ECC */
+#define	ERR_NF_MEM_M15	0x00008000	/* M15Err Correctable Spare-copy ECC */
+#define	ERR_NF_MEM_M14	0x00004000	/* M14Err Correctable demand data ECC */
+#define	ERR_NF_MEM_M12	0x00001000	/* M12Err non-aliased ue Patrol ECC */
+#define	ERR_NF_MEM_M11	0x00000800	/* M11Err non-aliased ue  Spare-copy */
+#define	ERR_NF_MEM_M10	0x00000400	/* M10Err non-aliased ue demand data */
+#define	ERR_NF_MEM_M6	0x00000040	/* M6Err aliased ue Patrol Data ECC */
+#define	ERR_NF_MEM_M5	0x00000020	/* M5Err aliased ue Spare-copy ECC */
+#define	ERR_NF_MEM_M4	0x00000010	/* M4Err aliased ue demand data ECC */
+#define	ERR_NF_MEM_M1	0x00000002	/* M1Err ue data ECC on replay */
+
+#define	ERR_NF_MEM_MASK 0x0003fffff
+#define	ERR_NF_MEM_ECC_UE	(ERR_NF_MEM_M12|ERR_NF_MEM_M11|ERR_NF_MEM_M10| \
+    ERR_NF_MEM_M6|ERR_NF_MEM_M5|ERR_NF_MEM_M4|ERR_NF_MEM_M1)
+#define	ERR_NF_MEM_ECC_CE	(ERR_NF_MEM_M16|ERR_NF_MEM_M15|ERR_NF_MEM_M14)
+#define	ERR_NF_MEM_SPARE	(ERR_NF_MEM_M21|ERR_NF_MEM_M20)
+
+#define	EMASK_MEM_M21	ERR_NF_MEM_M21
+#define	EMASK_MEM_M20	ERR_NF_MEM_M20
+#define	EMASK_MEM_M18	ERR_NF_MEM_M18
+#define	EMASK_MEM_M16	ERR_NF_MEM_M16
+#define	EMASK_MEM_M15	ERR_NF_MEM_M15
+#define	EMASK_MEM_M14	ERR_NF_MEM_M14
+#define	EMASK_MEM_M12	ERR_NF_MEM_M12
+#define	EMASK_MEM_M11	ERR_NF_MEM_M11
+#define	EMASK_MEM_M10	ERR_NF_MEM_M10
+#define	EMASK_MEM_M6	ERR_NF_MEM_M6
+#define	EMASK_MEM_M5	ERR_NF_MEM_M5
+#define	EMASK_MEM_M4	ERR_NF_MEM_M4
+#define	EMASK_MEM_M1	ERR_NF_MEM_M1
+
+#define	EMASK_MEM_NF (EMASK_FBD_M21|EMASK_FBD_M20|EMASK_FBD_M18|EMASK_FBD_M16| \
+	EMASK_FBD_M15|EMASK_FBD_M14|EMASK_FBD_M12|EMASK_FBD_M11|EMASK_FBD_M10| \
+	EMASK_MEM_M6|EMASK_MEM_M5|EMASK_MEM_M4|EMASK_MEM_M1)
+
 #define	ERR_INT_ALL	(nb_chipset == INTEL_NB_5400 ? 0xffffffff : 0xff)
 
 #define	ERR_FAT_INT_B14	0x0400	/* B14Msk SF Scrub DBE */
@@ -354,10 +413,14 @@
 	EMASK_INT_B1)
 #define	EMASK_INT_NF	(EMASK_INT_B8|EMASK_INT_B6|EMASK_INT_B5)
 #define	GE_FBD_FATAL ((nb_chipset == INTEL_NB_5400) ? GE_FERR_FBD_FATAL : \
+	(nb_chipset == INTEL_NB_5100) ? 0 : \
 	(GE_FERR_FBD0_FATAL|GE_FERR_FBD1_FATAL|GE_FERR_FBD2_FATAL| \
 	GE_FERR_FBD3_FATAL))
 #define	GE_FBD_NF ((nb_chipset == INTEL_NB_5400) ? GE_FERR_FBD_NF : \
+	(nb_chipset == INTEL_NB_5100) ? 0 : \
 	(GE_FERR_FBD0_NF|GE_FERR_FBD1_NF|GE_FERR_FBD2_NF|GE_FERR_FBD3_NF))
+#define	GE_MEM_NF	((nb_chipset == INTEL_NB_5100) ? \
+	(GE_FERR_MEM0_NF|GE_FERR_MEM1_NF) : 0)
 
 #define	EMASK_UNCOR_PEX_IO18	0x00200000	/* ESI Reset timeout */
 #define	EMASK_UNCOR_PEX_IO2	0x00100000	/* Received an unsupported */
@@ -807,11 +870,16 @@
 					nb_pci_putb(0, 16, 2, 0xd3, val); \
 				}
 
-#define	NRECINT_RD()		nb_pci_getl(0, 16, 2, 0xc4, 0)
-#define	RECINT_RD()		nb_pci_getl(0, 16, 2, 0xc8, 0)
+#define	NRECINT_RD()		nb_pci_getl(0, 16, 2, \
+	nb_chipset == INTEL_NB_5400 ? 0xc8 : 0xc4, 0)
+#define	RECINT_RD()		nb_pci_getl(0, 16, 2, \
+	nb_chipset == INTEL_NB_5400 ? 0xcc : 0xc8, 0)
 
-#define	NRECINT_WR()		nb_pci_putl(0, 16, 2, 0xc4, 0)
-#define	RECINT_WR()		nb_pci_putl(0, 16, 2, 0xc8, 0)
+#define	NRECINT_WR()		nb_pci_putl(0, 16, 2, \
+	nb_chipset == INTEL_NB_5400 ? 0xc8 : 0xc4, 0)
+#define	RECINT_WR()		nb_pci_putl(0, 16, 2, \
+	nb_chipset == INTEL_NB_5400 ? 0xcc : 0xc8, 0)
+
 
 #define	FERR_FAT_FBD_RD(ip)	nb_pci_getl(0, 16, 1, 0x98, ip)
 #define	NERR_FAT_FBD_RD(ip)	nb_pci_getl(0, 16, 1, 0x9c, ip)
@@ -1008,12 +1076,69 @@
 	else if (nb_chipset == INTEL_NB_7300) \
 		nb_pci_putw(0, 16, 1, 0xf8, 0); \
 
+#define	FERR_NF_MEM_RD(ip)	nb_pci_getl(0, 16, 1, 0xa0, ip)
+#define	NERR_NF_MEM_RD(ip)	nb_pci_getl(0, 16, 1, 0xa4, ip)
+#define	EMASK_MEM_RD()		nb_pci_getl(0, 16, 1, 0xa8, 0)
+#define	ERR0_MEM_RD()		nb_pci_getl(0, 16, 1, 0xac, 0)
+#define	ERR1_MEM_RD()		nb_pci_getl(0, 16, 1, 0xb0, 0)
+#define	ERR2_MEM_RD()		nb_pci_getl(0, 16, 1, 0xb4, 0)
+#define	MCERR_MEM_RD()		nb_pci_getl(0, 16, 1, 0xb8, 0)
+#define	FERR_NF_MEM_WR(val)	\
+	nb_pci_putl(0, 16, 1, 0xa0, (val))
+#define	NERR_NF_MEM_WR(val)	\
+	nb_pci_putl(0, 16, 1, 0xa4, (val))
+#define	EMASK_MEM_WR(val)	\
+	nb_pci_putl(0, 16, 1, 0xa8, (val))
+#define	ERR0_MEM_WR(val)	\
+	nb_pci_putl(0, 16, 1, 0xac, (val))
+#define	ERR1_MEM_WR(val)	\
+	nb_pci_putl(0, 16, 1, 0xb0, (val))
+#define	ERR2_MEM_WR(val)	\
+	nb_pci_putl(0, 16, 1, 0xb4, (val))
+#define	MCERR_MEM_WR(val)	\
+	nb_pci_putl(0, 16, 1, 0xb8, (val))
+#define	VALIDLOG_RD(branch)	\
+	nb_pci_getl(0, (branch) ? 22 : 21, 0, 0x18c, 0)
+#define	MEM_NRECMEMA_RD(branch) \
+	nb_pci_getl(0, (branch) ? 22 : 21, 0, 0x190, 0)
+#define	MEM_NRECMEMB_RD(branch) \
+	nb_pci_getl(0, (branch) ? 22 : 21, 0, 0x194, 0)
+#define	MEM_REDMEMA_RD(branch) \
+	nb_pci_getl(0, (branch) ? 22 : 21, 0, 0x198, 0)
+#define	MEM_REDMEMB_RD(branch) \
+	nb_pci_getl(0, (branch) ? 22 : 21, 0, 0x19c, 0)
+#define	MEM_RECMEMA_RD(branch) \
+	nb_pci_getl(0, (branch) ? 22 : 21, 0, 0x1a0, 0)
+#define	MEM_RECMEMB_RD(branch) \
+	nb_pci_getl(0, (branch) ? 22 : 21, 0, 0x1a4, 0)
+#define	MEM_CERRCNT_RD(branch) nb_pci_getl(0, 21, 0, 0x180, 0)
+#define	MEM_CERRCNT_EXT_RD(branch) nb_pci_getw(0, 21, 0, 0x184, 0)
+#define	MEM_NRECMEMA_WR(branch) \
+	nb_pci_putl(0, (branch) ? 22 : 21, 0, 0x190, 0)
+#define	MEM_NRECMEMB_WR(branch) \
+	nb_pci_putl(0, (branch) ? 22 : 21, 0, 0x194, 0)
+#define	MEM_REDMEMA_WR(branch) \
+	nb_pci_putl(0, (branch) ? 22 : 21, 0, 0x198, 0)
+#define	MEM_REDMEMB_WR(branch) \
+	nb_pci_putl(0, (branch) ? 22 : 21, 0, 0x19c, 0)
+#define	MEM_RECMEMA_WR(branch) \
+	nb_pci_putl(0, (branch) ? 22 : 21, 0, 0x1a0, 0)
+#define	MEM_RECMEMB_WR(branch) \
+	nb_pci_putl(0, (branch) ? 22 : 21, 0, 0x1a4, 0)
+
 #define	MC_RD()		nb_pci_getl(0, 16, 1, 0x40, 0)
 #define	MC_WR(val)	nb_pci_putl(0, 16, 1, 0x40, val)
 #define	MCA_RD()	nb_pci_getl(0, 16, 1, 0x58, 0)
 #define	TOLM_RD()	nb_pci_getw(0, 16, 1, 0x6c, 0)
 
-#define	MTR_RD(branch, dimm) (nb_chipset == INTEL_NB_5400 ? \
+#define	MTR_5100_RD(channel, rank) ((rank) < 4 ? \
+	nb_pci_getw(0, (channel) == 0 ? 21 : 22, 0, 0x154 + ((rank) * 2), 0) : \
+	nb_pci_getw(0, (channel) == 0 ? 21 : 22, 0, 0x1b0 + (((rank) & 3) * 2),\
+	0))
+
+#define	MTR_RD(branch, dimm) (nb_chipset == INTEL_NB_5100 ? \
+	MTR_5100_RD(branch, dimm) : \
+	nb_chipset == INTEL_NB_5400 ? \
 	nb_pci_getw(0, (branch) == 0 ? 21 : 22, 0, 0x80 + dimm * 2, 0) : \
 	((branch) == 0) ? \
 	nb_pci_getw(0, 21, 0, \
@@ -1024,6 +1149,8 @@
 #define	MIR_RD(reg)	nb_pci_getw(0, 16, 1, 0x80 + ((reg)*4), 0)
 
 #define	DMIR_RD(branch, reg) \
+	nb_chipset == INTEL_NB_5100 ? \
+	nb_pci_getl(0, ((branch) == 0) ? 21 : 22, 0, 0x15c + ((reg)*4), 0) : \
 	((branch) == 0) ? nb_pci_getl(0, 21, 0, 0x90 + ((reg)*4), 0) : \
 	(nb_number_memory_controllers == 2) ? \
 	nb_pci_getl(0, 22, 0, 0x90 + ((reg)*4), 0) : 0
@@ -1131,7 +1258,9 @@
 	(nb_number_memory_controllers == 2) ? \
 	nb_pci_putl(0, 22, 0, 0xb4, val) : 0
 
-#define	SPD_RD(branch, channel)	((branch) == 0) ? \
+#define	SPD_RD(branch, channel) \
+	nb_chipset == INTEL_NB_5100 ? nb_pci_getw(0, 16, 1, 0x48, 0) : \
+	((branch) == 0) ? \
 	nb_pci_getw(0, 21, 0, 0x74 + ((channel) * 2), 0) : \
 	(nb_number_memory_controllers == 2) ? \
 	nb_pci_getw(0, 22, 0, 0x74 + ((channel) * 2), 0) : 0
@@ -1142,7 +1271,9 @@
 
 #define	SPDCMD1_1_WR(val)	nb_pci_putl(0, 21, 0, 0x7c, val)
 #define	SPDCMD_WR(branch, channel, val)	\
-	if ((branch) == 0) \
+	if (nb_chipset == INTEL_NB_5100) \
+	nb_pci_putl(0, 16, 1, 0x4c, val); \
+	else if ((branch) == 0) \
 	nb_pci_putl(0, 21, 0, 0x78 + ((channel) * 4), val); \
 	else if (nb_number_memory_controllers == 2) \
 	nb_pci_putl(0, 22, 0, 0x78 + ((channel) * 4), val)
@@ -1211,7 +1342,8 @@
 
 #define	DMIR_RANKS(dmir, rank0, rank1, rank2, rank3) \
 	if (nb_chipset == INTEL_NB_5000P || nb_chipset == INTEL_NB_5000X || \
-	    nb_chipset == INTEL_NB_5000V || nb_chipset == INTEL_NB_5000Z) { \
+	    nb_chipset == INTEL_NB_5000V || nb_chipset == INTEL_NB_5000Z || \
+	    nb_chipset == INTEL_NB_5100) { \
 		rank0 = (dmir) & 3; \
 		rank1 = ((dmir) >> 3) & 3; \
 		rank2 = ((dmir) >> 6) & 3; \
@@ -1265,6 +1397,11 @@
 				/* throttling disabled */
 #define	EMASK_THR_F1	0x0001	/* catastrophic on-die thermal event */
 
+/* dimm type */
+#define	SPD_MEM_TYPE	2
+#define	SPD_DDR2	8
+#define	SPD_FBDIMM	9
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/uts/intel/io/intel_nb5000/nb5000_init.c	Mon Jul 06 23:01:22 2009 -0700
+++ b/usr/src/uts/intel/io/intel_nb5000/nb5000_init.c	Tue Jul 07 06:31:07 2009 -0400
@@ -52,6 +52,7 @@
 
 int nb_5000_memory_controller = 0;
 int nb_number_memory_controllers = NB_5000_MAX_MEM_CONTROLLERS;
+int nb_channels_per_branch = NB_MAX_CHANNELS_PER_BRANCH;
 int nb_dimms_per_channel = 0;
 
 nb_dimm_t **nb_dimms;
@@ -82,6 +83,12 @@
 static uint32_t nb_mcerr_fbd;
 static uint32_t nb_emask_fbd;
 
+static uint32_t nb_err0_mem;
+static uint32_t nb_err1_mem;
+static uint32_t nb_err2_mem;
+static uint32_t nb_mcerr_mem;
+static uint32_t nb_emask_mem;
+
 static uint16_t nb_err0_fsb;
 static uint16_t nb_err1_fsb;
 static uint16_t nb_err2_fsb;
@@ -102,6 +109,7 @@
 
 static uint32_t l_mcerr_int;
 static uint32_t l_mcerr_fbd;
+static uint32_t l_mcerr_mem;
 static uint16_t l_mcerr_fsb;
 static uint16_t l_mcerr_thr;
 
@@ -113,6 +121,9 @@
 uint_t nb5400_mask_poll_fbd = EMASK_5400_FBD_NF;
 uint_t nb5400_mask_bios_fbd = EMASK_5400_FBD_FATAL;
 
+int nb5100_reset_emask_mem = 1;
+uint_t nb5100_mask_poll_mem = EMASK_MEM_NF;
+
 uint_t nb5000_emask_fsb = 0;
 int nb5000_reset_emask_fsb = 1;
 uint_t nb5000_mask_poll_fsb = EMASK_FSB_NF;
@@ -143,6 +154,7 @@
 } find_dimm_label_t;
 
 static void x8450_dimm_label(int, char *, int);
+static void cp3250_dimm_label(int, char *, int);
 
 static struct platform_label {
 	const char *sys_vendor;		/* SMB_TYPE_SYSTEM vendor prefix */
@@ -152,6 +164,7 @@
 } platform_label[] = {
 	{ "SUN MICROSYSTEMS", "SUN BLADE X8450 SERVER MODULE",
 	    x8450_dimm_label, 8 },
+	{ "MiTAC,Shunde", "CP3250", cp3250_dimm_label, 0 },
 	{ NULL, NULL, NULL, 0 }
 };
 
@@ -225,7 +238,7 @@
 nb_fini()
 {
 	int i, j;
-	int nchannels = nb_number_memory_controllers * 2;
+	int nchannels = nb_number_memory_controllers * nb_channels_per_branch;
 	nb_dimm_t **dimmpp;
 	nb_dimm_t *dimmp;
 
@@ -264,22 +277,12 @@
 		cmi_mc_sw_memscrub_disable();
 }
 
-static nb_dimm_t *
-nb_dimm_init(int channel, int dimm, uint16_t mtr)
+static void
+fbd_eeprom(int channel, int dimm, nb_dimm_t *dp)
 {
-	nb_dimm_t *dp;
 	int i, t;
 	int spd_sz;
 
-	if (MTR_PRESENT(mtr) == 0)
-		return (NULL);
-	t = read_spd_eeprom(channel, dimm, 2) & 0xf;
-
-	if (t != 9)
-		return (NULL);
-
-	dp = kmem_zalloc(sizeof (nb_dimm_t), KM_SLEEP);
-
 	t = read_spd_eeprom(channel, dimm, 0) & 0xf;
 	if (t == 1)
 		spd_sz = 128;
@@ -308,7 +311,126 @@
 			    read_spd_eeprom(channel, dimm, 146 + i);
 		}
 	}
+}
+
+/* read the manR of the DDR2 dimm */
+static void
+ddr2_eeprom(int channel, int dimm, nb_dimm_t *dp)
+{
+	int i, t;
+	int slave;
+
+	slave = channel & 0x1 ? dimm + 4 : dimm;
+
+	/* byte[3]: number of row addresses */
+	dp->nrow = read_spd_eeprom(channel, slave, 3) & 0x1f;
+
+	/* byte[4]: number of column addresses */
+	dp->ncolumn = read_spd_eeprom(channel, slave, 4) & 0xf;
+
+	/* byte[5]: numranks; 0 means one rank */
+	dp->nranks = (read_spd_eeprom(channel, slave, 5) & 0x3) + 1;
+
+	/* byte[6]: data width */
+	dp->width = (read_spd_eeprom(channel, slave, 6) >> 5) << 2;
+
+	/* byte[17]: number of banks */
+	dp->nbanks = read_spd_eeprom(channel, slave, 17);
+
+	dp->dimm_size = DIMMSIZE(dp->nrow, dp->ncolumn, dp->nranks, dp->nbanks,
+	    dp->width);
+
+	/* manufacture-id - byte[64-65] */
+	dp->manufacture_id = read_spd_eeprom(channel, slave, 64) |
+	    (read_spd_eeprom(channel, dimm, 65) << 8);
+
+	/* location - byte[72] */
+	dp->manufacture_location = read_spd_eeprom(channel, slave, 72);
+
+	/* serial number - byte[95-98] */
+	dp->serial_number =
+	    (read_spd_eeprom(channel, slave, 98) << 24) |
+	    (read_spd_eeprom(channel, slave, 97) << 16) |
+	    (read_spd_eeprom(channel, slave, 96) << 8) |
+	    read_spd_eeprom(channel, slave, 95);
+
+	/* week - byte[94] */
+	t = read_spd_eeprom(channel, slave, 94);
+	dp->manufacture_week = (t >> 4) * 10 + (t & 0xf);
+	/* week - byte[93] */
+	t = read_spd_eeprom(channel, slave, 93);
+	dp->manufacture_year = (t >> 4) * 10 + (t & 0xf) + 2000;
+
+	/* part number - byte[73-81] */
+	for (i = 0; i < 8; i++) {
+		dp->part_number[i] = read_spd_eeprom(channel, slave, 73 + i);
+	}
+
+	/* revision - byte[91-92] */
+	for (i = 0; i < 2; i++) {
+		dp->revision[i] = read_spd_eeprom(channel, slave, 91 + i);
+	}
+}
+
+static boolean_t
+nb_dimm_present(int channel, int dimm)
+{
+	boolean_t rc = B_FALSE;
+
+	if (nb_chipset == INTEL_NB_5100) {
+		int t, slave;
+		slave = channel & 0x1 ? dimm + 4 : dimm;
+		/* read the type field from the dimm and check for DDR2 type */
+		if ((t = read_spd_eeprom(channel, slave, SPD_MEM_TYPE)) == -1)
+			return (B_FALSE);
+		rc = (t & 0xf) == SPD_DDR2;
+	} else {
+		rc = MTR_PRESENT(MTR_RD(channel, dimm)) != 0;
+	}
+
+	return (rc);
+}
+
+static nb_dimm_t *
+nb_ddr2_dimm_init(int channel, int dimm, int start_rank)
+{
+	nb_dimm_t *dp;
+
+	if (nb_dimm_present(channel, dimm) == B_FALSE)
+		return (NULL);
+
+	dp = kmem_zalloc(sizeof (nb_dimm_t), KM_SLEEP);
+
+	ddr2_eeprom(channel, dimm, dp);
+
+	/* The 1st rank of the dimm takes on this value */
+	dp->start_rank = (uint8_t)start_rank;
+
+	dp->mtr_present = 1;
+
+	return (dp);
+}
+
+static nb_dimm_t *
+nb_fbd_dimm_init(int channel, int dimm, uint16_t mtr)
+{
+	nb_dimm_t *dp;
+	int t;
+
+	if (MTR_PRESENT(mtr) == 0)
+		return (NULL);
+	t = read_spd_eeprom(channel, dimm, SPD_MEM_TYPE) & 0xf;
+
+	/* check for the dimm type */
+	if (t != SPD_FBDIMM)
+		return (NULL);
+
+	dp = kmem_zalloc(sizeof (nb_dimm_t), KM_SLEEP);
+
+	fbd_eeprom(channel, dimm, dp);
+
 	dp->mtr_present = MTR_PRESENT(mtr);
+	dp->start_rank = dimm << 1;
 	dp->nranks = MTR_NUMRANK(mtr);
 	dp->nbanks = MTR_NUMBANK(mtr);
 	dp->ncolumn = MTR_NUMCOL(mtr);
@@ -429,9 +551,6 @@
 			nb_ranks[i][j].hole_base = hole_base;
 			nb_ranks[i][j].hole_size = hole_size;
 			if (limit > base) {
-				dimm_add_rank(i, rank0, branch_interleave, 0,
-				    base, hole_base, hole_size, interleave,
-				    limit);
 				if (rank0 != rank1) {
 					dimm_add_rank(i, rank1,
 					    branch_interleave, 1, base,
@@ -480,7 +599,6 @@
 	smbios_system_t sy;
 	id_t id;
 	int i, j;
-	uint16_t mtr;
 	find_dimm_label_t *rt = NULL;
 
 	if (ksmbios != NULL && nb_no_smbios == 0) {
@@ -509,8 +627,7 @@
 		for (i = 0; i < nb_number_memory_controllers; i++) {
 			for (j = nb_dimms_per_channel;
 			    j < NB_MAX_DIMMS_PER_CHANNEL; j++) {
-				mtr = MTR_RD(i, j);
-				if (MTR_PRESENT(mtr))
+				if (nb_dimm_present(i, j))
 					nb_dimms_per_channel = j + 1;
 			}
 		}
@@ -615,8 +732,114 @@
 	(void) snprintf(label, label_sz, "D%d", (dimm * 4) + channel);
 }
 
+/*
+ * CP3250 DIMM labels
+ * Channel   Dimm   Label
+ *       0      0      A0
+ *       1      0      B0
+ *       0      1      A1
+ *       1      1      B1
+ *       0      2      A2
+ *       1      2      B2
+ */
 static void
-nb_dimms_init(find_dimm_label_t *label_function)
+cp3250_dimm_label(int dimm, char *label, int label_sz)
+{
+	int channel = dimm / nb_dimms_per_channel;
+
+	dimm = dimm % nb_dimms_per_channel;
+	(void) snprintf(label, label_sz, "%c%d", channel == 0 ? 'A' : 'B',
+	    dimm);
+}
+
+/*
+ * Map the rank id to dimm id of a channel
+ * For the 5100 chipset, walk through the dimm list of channel the check if
+ * the given rank id is within the rank range assigned to the dimm.
+ * For other chipsets, the dimm is rank/2.
+ */
+int
+nb_rank2dimm(int channel, int rank)
+{
+	int i;
+	nb_dimm_t **dimmpp = nb_dimms;
+
+	if (nb_chipset != INTEL_NB_5100)
+		return (rank >> 1);
+
+	dimmpp += channel * nb_dimms_per_channel;
+	for (i = 0; i < nb_dimms_per_channel; i++) {
+		if ((rank >= dimmpp[i]->start_rank) &&
+		    (rank < dimmpp[i]->start_rank + dimmpp[i]->nranks)) {
+			return (i);
+		}
+	}
+	return (-1);
+}
+
+static void
+nb_ddr2_dimms_init(find_dimm_label_t *label_function)
+{
+	int i, j;
+	int start_rank;
+	uint32_t spcpc;
+	uint8_t spcps;
+	nb_dimm_t **dimmpp;
+
+	nb_dimm_slots = nb_number_memory_controllers * nb_channels_per_branch *
+	    nb_dimms_per_channel;
+	nb_dimms = (nb_dimm_t **)kmem_zalloc(sizeof (nb_dimm_t *) *
+	    nb_dimm_slots, KM_SLEEP);
+	dimmpp = nb_dimms;
+	nb_mode = NB_MEMORY_NORMAL;
+	for (i = 0; i < nb_number_memory_controllers; i++) {
+		if (nb_mode == NB_MEMORY_NORMAL) {
+			spcpc = SPCPC_RD(i);
+			spcps = SPCPS_RD(i);
+			if ((spcpc & SPCPC_SPARE_ENABLE) != 0 &&
+			    (spcps & SPCPS_SPARE_DEPLOYED) != 0)
+				nb_mode = NB_MEMORY_SPARE_RANK;
+			spare_rank[i] = SPCPC_SPRANK(spcpc);
+		}
+
+		/* The 1st dimm of a channel starts at rank 0 */
+		start_rank = 0;
+
+		for (j = 0; j < nb_dimms_per_channel; j++) {
+			dimmpp[j] = nb_ddr2_dimm_init(i, j, start_rank);
+			if (dimmpp[j]) {
+				nb_ndimm ++;
+				dimm_add_geometry(i, j, dimmpp[j]->nbanks,
+				    dimmpp[j]->width, dimmpp[j]->ncolumn,
+				    dimmpp[j]->nrow);
+				if (label_function) {
+					label_function->label_function(
+					    (i * nb_dimms_per_channel) + j,
+					    dimmpp[j]->label,
+					    sizeof (dimmpp[j]->label));
+				}
+				start_rank += dimmpp[j]->nranks;
+				/*
+				 * add an extra rank because
+				 * single-ranked dimm still takes on two ranks.
+				 */
+				if (dimmpp[j]->nranks & 0x1)
+					start_rank++;
+				}
+		}
+		dimmpp += nb_dimms_per_channel;
+	}
+
+	/*
+	 * single channel is supported.
+	 */
+	if (nb_ndimm > 0 && nb_ndimm <= nb_dimms_per_channel) {
+		nb_mode = NB_MEMORY_SINGLE_CHANNEL;
+	}
+}
+
+static void
+nb_fbd_dimms_init(find_dimm_label_t *label_function)
 {
 	int i, j, k, l;
 	uint16_t mtr;
@@ -649,7 +872,7 @@
 		for (j = 0; j < nb_dimms_per_channel; j++) {
 			mtr = MTR_RD(i, j);
 			k = i * 2;
-			dimmpp[j] = nb_dimm_init(k, j, mtr);
+			dimmpp[j] = nb_fbd_dimm_init(k, j, mtr);
 			if (dimmpp[j]) {
 				nb_ndimm ++;
 				dimm_add_geometry(i, j, dimmpp[j]->nbanks,
@@ -663,7 +886,7 @@
 				}
 			}
 			dimmpp[j + nb_dimms_per_channel] =
-			    nb_dimm_init(k + 1, j, mtr);
+			    nb_fbd_dimm_init(k + 1, j, mtr);
 			l = j + nb_dimms_per_channel;
 			if (dimmpp[l]) {
 				if (label_function) {
@@ -677,11 +900,20 @@
 		}
 		dimmpp += nb_dimms_per_channel * 2;
 	}
+}
+
+static void
+nb_dimms_init(find_dimm_label_t *label_function)
+{
+	if (nb_chipset == INTEL_NB_5100)
+		nb_ddr2_dimms_init(label_function);
+	else
+		nb_fbd_dimms_init(label_function);
+
 	if (label_function == NULL)
 		nb_smbios();
 }
 
-
 /* Setup the ESI port registers to enable SERR for southbridge */
 static void
 nb_pex_init()
@@ -822,7 +1054,7 @@
 	}
 }
 
-void
+static void
 nb_fbd_init()
 {
 	uint32_t err0_fbd;
@@ -897,7 +1129,7 @@
 	}
 }
 
-void
+static void
 nb_fbd_fini()
 {
 	ERR0_FBD_WR(0xffffffff);
@@ -914,6 +1146,80 @@
 }
 
 static void
+nb_mem_init()
+{
+	uint32_t err0_mem;
+	uint32_t err1_mem;
+	uint32_t err2_mem;
+	uint32_t mcerr_mem;
+	uint32_t emask_mem;
+	uint32_t emask_poll_mem;
+
+	err0_mem = ERR0_MEM_RD();
+	err1_mem = ERR1_MEM_RD();
+	err2_mem = ERR2_MEM_RD();
+	mcerr_mem = MCERR_MEM_RD();
+	emask_mem = EMASK_MEM_RD();
+
+	nb_err0_mem = err0_mem;
+	nb_err1_mem = err1_mem;
+	nb_err2_mem = err2_mem;
+	nb_mcerr_mem = mcerr_mem;
+	nb_emask_mem = emask_mem;
+
+	ERR0_MEM_WR(0xffffffff);
+	ERR1_MEM_WR(0xffffffff);
+	ERR2_MEM_WR(0xffffffff);
+	MCERR_MEM_WR(0xffffffff);
+	EMASK_MEM_WR(0xffffffff);
+
+	emask_poll_mem = nb5100_mask_poll_mem;
+	mcerr_mem |= emask_poll_mem;
+	err0_mem |= emask_poll_mem;
+	err1_mem |= emask_poll_mem;
+	err2_mem |= emask_poll_mem;
+
+	l_mcerr_mem = mcerr_mem;
+	ERR0_MEM_WR(err0_mem);
+	ERR1_MEM_WR(err1_mem);
+	ERR2_MEM_WR(err2_mem);
+	MCERR_MEM_WR(mcerr_mem);
+	if (nb5100_reset_emask_mem) {
+		EMASK_MEM_WR(~nb5100_mask_poll_mem);
+	} else {
+		EMASK_MEM_WR(nb_emask_mem);
+	}
+}
+
+void
+nb_mem_mask_mc(uint32_t mc_mask_mem)
+{
+	uint32_t emask_mem;
+
+	emask_mem = MCERR_MEM_RD();
+	if ((emask_mem & mc_mask_mem) != mc_mask_mem) {
+		MCERR_MEM_WR(emask_mem|mc_mask_mem);
+		nb_mask_mc_set = 1;
+	}
+}
+
+static void
+nb_mem_fini()
+{
+	ERR0_MEM_WR(0xffffffff);
+	ERR1_MEM_WR(0xffffffff);
+	ERR2_MEM_WR(0xffffffff);
+	MCERR_MEM_WR(0xffffffff);
+	EMASK_MEM_WR(0xffffffff);
+
+	ERR0_MEM_WR(nb_err0_mem);
+	ERR1_MEM_WR(nb_err1_mem);
+	ERR2_MEM_WR(nb_err2_mem);
+	MCERR_MEM_WR(nb_mcerr_mem);
+	EMASK_MEM_WR(nb_emask_mem);
+}
+
+static void
 nb_fsb_init()
 {
 	uint16_t err0_fsb;
@@ -1152,7 +1458,10 @@
 void
 nb_mask_mc_reset()
 {
-	MCERR_FBD_WR(l_mcerr_fbd);
+	if (nb_chipset == INTEL_NB_5100)
+		MCERR_MEM_WR(l_mcerr_mem);
+	else
+		MCERR_FBD_WR(l_mcerr_fbd);
 	MCERR_INT_WR(l_mcerr_int);
 	MCERR_FSB_WR(0, l_mcerr_fsb);
 	MCERR_FSB_WR(1, l_mcerr_fsb);
@@ -1184,7 +1493,10 @@
 	nb_dimms_init(label_function_p);
 	nb_mc_init();
 	nb_pex_init();
-	nb_fbd_init();
+	if (nb_chipset == INTEL_NB_5100)
+		nb_mem_init();
+	else
+		nb_fbd_init();
 	nb_fsb_init();
 	nb_scrubber_enable();
 	return (0);
@@ -1212,6 +1524,9 @@
 	case INTEL_NB_5000Z:
 		nb_number_memory_controllers = 1;
 		break;
+	case INTEL_NB_5100:
+		nb_channels_per_branch = 1;
+		break;
 	case INTEL_NB_5400:
 	case INTEL_NB_5400A:
 	case INTEL_NB_5400B:
@@ -1245,7 +1560,10 @@
 	nb_pex_init();
 	nb_int_init();
 	nb_thr_init();
-	nb_fbd_init();
+	if (nb_chipset == INTEL_NB_5100)
+		nb_mem_init();
+	else
+		nb_fbd_init();
 	nb_fsb_init();
 	nb_scrubber_enable();
 
@@ -1271,7 +1589,10 @@
 	mutex_destroy(&nb_mutex);
 	nb_int_fini();
 	nb_thr_fini();
-	nb_fbd_fini();
+	if (nb_chipset == INTEL_NB_5100)
+		nb_mem_fini();
+	else
+		nb_fbd_fini();
 	nb_fsb_fini();
 	nb_pex_fini();
 	nb_fini();
--- a/usr/src/uts/intel/io/intel_nb5000/nb_log.h	Mon Jul 06 23:01:22 2009 -0700
+++ b/usr/src/uts/intel/io/intel_nb5000/nb_log.h	Tue Jul 07 06:31:07 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -130,6 +130,31 @@
 	uint32_t badcnt;	/* bad dram counter */
 } nb_nf_fbd_t;
 
+typedef struct nb_nf_mem {
+				/* Memory registers */
+	uint32_t ferr_nf_mem;	/* MC first non-fatal error */
+	uint32_t nerr_nf_mem;	/* MC next non-fatal error */
+	uint32_t nrecmema;	/* non-recoverable memory error log A */
+	uint32_t nrecmemb;	/* non-recoverable memory error log B */
+	uint32_t redmema;	/* recoverable memory data error log A */
+	uint32_t redmemb;	/* recoverable memory data error log B */
+	uint32_t recmema;	/* recoverable memory error log A */
+	uint32_t recmemb;	/* recoverable memory error log B */
+
+				/* Spare rank */
+	uint32_t spcpc;		/* spare copy control */
+	uint8_t spcps;		/* spare copy status */
+
+				/* RAS */
+	uint32_t cerrcnt;	/* correctable error count A */
+	uint32_t cerrcnt_ext;	/* correctable error count B */
+	uint32_t cerrcnt_last;	/* correctable error count A */
+	uint32_t cerrcnt_ext_last;	/* correctable error count B */
+	uint32_t badram;	/* bad dram marker */
+	uint32_t badcnt;	/* bad dram counter */
+	uint32_t validlog;	/* valid log markers */
+} nb_nf_mem_t;
+
 typedef struct nb_dma {
 	uint16_t pcists;
 	uint16_t pexdevsts;
@@ -155,6 +180,7 @@
 		nb_int_t int_regs;
 		nb_fat_fbd_t fat_fbd_regs;
 		nb_nf_fbd_t nf_fbd_regs;
+		nb_nf_mem_t nf_mem_regs;
 		nb_dma_t dma_regs;
 		nb_thr_t thr_regs;
 	} nb;
@@ -168,6 +194,7 @@
 #define	NB_REG_LOG_NF_FBD	5
 #define	NB_REG_LOG_DMA		6
 #define	NB_REG_LOG_THR		7
+#define	NB_REG_LOG_NF_MEM	8
 
 typedef struct nb_logout {
 	uint64_t acl_timestamp;
@@ -196,7 +223,8 @@
 typedef struct nb_dimm {
 	uint64_t dimm_size;
 	uint8_t mtr_present;
-	uint8_t nranks;
+	uint8_t start_rank;		/* id of the 1st rank */
+	uint8_t nranks;			/* number of ranks */
 	uint8_t nbanks;
 	uint8_t ncolumn;
 	uint8_t nrow;
@@ -232,6 +260,7 @@
 
 extern int nb_5000_memory_controller;
 extern int nb_number_memory_controllers;
+extern int nb_channels_per_branch;
 extern int nb_dimms_per_channel;
 
 extern nb_dimm_t **nb_dimms;
@@ -248,6 +277,7 @@
 	[NB_MAX_MEM_RANK_SELECT];
 extern uint8_t spare_rank[NB_5000_MAX_MEM_CONTROLLERS];
 extern enum nb_memory_mode nb_mode;
+extern int nb_rank2dimm(int, int);
 
 extern int inb_mc_register(cmi_hdl_t, void *, void *, void *);
 extern void nb_scrubber_enable(void);
@@ -267,6 +297,7 @@
 
 extern void nb_fsb_mask_mc(int, uint16_t);
 extern void nb_fbd_mask_mc(uint32_t);
+extern void nb_mem_mask_mc(uint32_t);
 extern void nb_int_mask_mc(uint32_t);
 extern void nb_thr_mask_mc(uint16_t);
 extern void nb_mask_mc_reset(void);
--- a/usr/src/uts/intel/io/intel_nb5000/nb_pci_cfg.c	Mon Jul 06 23:01:22 2009 -0700
+++ b/usr/src/uts/intel/io/intel_nb5000/nb_pci_cfg.c	Tue Jul 07 06:31:07 2009 -0400
@@ -39,6 +39,8 @@
 
 static ddi_acc_handle_t dev_16_hdl[NB_PCI_NFUNC];
 static ddi_acc_handle_t dev_17_hdl[NB_PCI_NFUNC];
+static ddi_acc_handle_t dev_21_hdl;
+static ddi_acc_handle_t dev_22_hdl;
 static ddi_acc_handle_t dev_pci_hdl[NB_PCI_DEV];
 
 void
@@ -76,6 +78,20 @@
 			    "intel_nb5000: pci_config_setup failed");
 		reg.pci_phys_hi += 1 << PCI_REG_FUNC_SHIFT;
 	}
+	reg.pci_phys_hi = 21 << PCI_REG_DEV_SHIFT; /* Bus=0, Dev=21, Func=0 */
+	if (ddi_prop_update_int_array(DDI_MAJOR_T_UNKNOWN, dip, "reg",
+	    (int *)&reg, sizeof (reg)/sizeof (int)) != DDI_PROP_SUCCESS)
+		cmn_err(CE_WARN,
+		    "nb_pci_cfg_setup: cannot create reg property");
+	if (pci_config_setup(dip, &dev_21_hdl) != DDI_SUCCESS)
+		cmn_err(CE_WARN, "intel_nb5000: pci_config_setup failed");
+	reg.pci_phys_hi = 22 << PCI_REG_DEV_SHIFT; /* Bus=0, Dev=22, Func=0 */
+	if (ddi_prop_update_int_array(DDI_MAJOR_T_UNKNOWN, dip, "reg",
+	    (int *)&reg, sizeof (reg)/sizeof (int)) != DDI_PROP_SUCCESS)
+		cmn_err(CE_WARN,
+		    "nb_pci_cfg_setup: cannot create reg property");
+	if (pci_config_setup(dip, &dev_22_hdl) != DDI_SUCCESS)
+		cmn_err(CE_WARN, "intel_nb5000: pci_config_setup failed");
 	reg.pci_phys_hi = 0;		/* Bus=0, Dev=0, Func=0 */
 	for (i = 0; i < NB_PCI_DEV; i++) {
 		if (ddi_prop_update_int_array(DDI_MAJOR_T_UNKNOWN, dip, "reg",
@@ -102,6 +118,8 @@
 	for (i = 0; i < NB_PCI_NFUNC; i++) {
 		pci_config_teardown(&dev_17_hdl[i]);
 	}
+	pci_config_teardown(&dev_21_hdl);
+	pci_config_teardown(&dev_22_hdl);
 	for (i = 0; i < NB_PCI_DEV; i++)
 		pci_config_teardown(&dev_pci_hdl[i]);
 }
@@ -117,6 +135,10 @@
 		hdl = dev_17_hdl[func];
 	} else if (bus == 0 && dev < NB_PCI_DEV && func == 0) {
 		hdl = dev_pci_hdl[dev];
+	} else if (bus == 0 && dev == 21 && func == 0) {
+		hdl = dev_21_hdl;
+	} else if (bus == 0 && dev == 22 && func == 0) {
+		hdl = dev_22_hdl;
 	} else {
 		hdl = 0;
 	}
--- a/usr/src/uts/intel/os/driver_aliases	Mon Jul 06 23:01:22 2009 -0700
+++ b/usr/src/uts/intel/os/driver_aliases	Tue Jul 07 06:31:07 2009 -0400
@@ -45,6 +45,7 @@
 intel_nb5000 "pci8086,4000"
 intel_nb5000 "pci8086,4001"
 intel_nb5000 "pci8086,4003"
+intel_nb5000 "pci8086,65c0"
 intel_nhm "pci8086,3423"
 xpv "pci5853,1.1"
 amd_iommu "pci1022,11ff"
--- a/usr/src/uts/intel/sys/mc_intel.h	Mon Jul 06 23:01:22 2009 -0700
+++ b/usr/src/uts/intel/sys/mc_intel.h	Tue Jul 07 06:31:07 2009 -0400
@@ -45,6 +45,7 @@
 #define	MCINTEL_NVLIST_DIMMSZ	"memory-dimm-size"
 #define	MCINTEL_NVLIST_NRANKS	"dimm-max-ranks"
 #define	MCINTEL_NVLIST_RANKS	"dimm-ranks"
+#define	MCINTEL_NVLIST_1ST_RANK	"dimm-start-rank"
 #define	MCINTEL_NVLIST_ROWS	"dimm-rows"
 #define	MCINTEL_NVLIST_COL	"dimm-column"
 #define	MCINTEL_NVLIST_BANK	"dimm-banks"
@@ -93,6 +94,7 @@
 #define	FM_EREPORT_PAYLOAD_NAME_RAS			"ras"
 #define	FM_EREPORT_PAYLOAD_NAME_FERR_FAT_FBD		"ferr_fat_fbd"
 #define	FM_EREPORT_PAYLOAD_NAME_NERR_FAT_FBD		"nerr_fat_fbd"
+#define	FM_EREPORT_PAYLOAD_NAME_VALIDLOG		"validlog"
 #define	FM_EREPORT_PAYLOAD_NAME_NRECMEMA		"nrecmema"
 #define	FM_EREPORT_PAYLOAD_NAME_NRECMEMB		"nrecmemb"
 #define	FM_EREPORT_PAYLOAD_NAME_NRECFGLOG		"nrecfglog"
@@ -106,6 +108,7 @@
 #define	FM_EREPORT_PAYLOAD_NAME_SPCPS			"spcps"
 #define	FM_EREPORT_PAYLOAD_NAME_UERRCNT			"uerrcnt"
 #define	FM_EREPORT_PAYLOAD_NAME_UERRCNT_LAST		"uerrcnt_last"
+#define	FM_EREPORT_PAYLOAD_NAME_BADRAM			"badram"
 #define	FM_EREPORT_PAYLOAD_NAME_BADRAMA			"badrama"
 #define	FM_EREPORT_PAYLOAD_NAME_BADRAMB			"badramb"
 #define	FM_EREPORT_PAYLOAD_NAME_BADCNT			"badcnt"
@@ -117,8 +120,12 @@
 #define	FM_EREPORT_PAYLOAD_NAME_DMIR			"dmir"
 #define	FM_EREPORT_PAYLOAD_NAME_FERR_NF_FBD		"ferr_nf_fbd"
 #define	FM_EREPORT_PAYLOAD_NAME_NERR_NF_FBD		"nerr_nf_fbd"
+#define	FM_EREPORT_PAYLOAD_NAME_FERR_NF_MEM		"ferr_nf_mem"
+#define	FM_EREPORT_PAYLOAD_NAME_NERR_NF_MEM		"nerr_nf_mem"
 #define	FM_EREPORT_PAYLOAD_NAME_RECMEMA			"recmema"
 #define	FM_EREPORT_PAYLOAD_NAME_RECMEMB			"recmemb"
+#define	FM_EREPORT_PAYLOAD_NAME_REDMEMA			"redmema"
+#define	FM_EREPORT_PAYLOAD_NAME_REDMEMB			"redmemb"
 #define	FM_EREPORT_PAYLOAD_NAME_RECFGLOG		"recfglog"
 #define	FM_EREPORT_PAYLOAD_NAME_RECFBDA			"recfbda"
 #define	FM_EREPORT_PAYLOAD_NAME_RECFBDB			"recfbdb"
@@ -128,6 +135,8 @@
 #define	FM_EREPORT_PAYLOAD_NAME_RECFBDF			"recfbdf"
 #define	FM_EREPORT_PAYLOAD_NAME_CERRCNT			"cerrcnt"
 #define	FM_EREPORT_PAYLOAD_NAME_CERRCNT_LAST		"cerrcnt_last"
+#define	FM_EREPORT_PAYLOAD_NAME_CERRCNT_EXT		"cerrcnt_ext"
+#define	FM_EREPORT_PAYLOAD_NAME_CERRCNT_EXT_LAST	"cerrcnt_ext_last"
 #define	FM_EREPORT_PAYLOAD_NAME_CERRCNTA		"cerrcnta"
 #define	FM_EREPORT_PAYLOAD_NAME_CERRCNTB		"cerrcntb"
 #define	FM_EREPORT_PAYLOAD_NAME_CERRCNTC		"cerrcntc"
@@ -199,6 +208,7 @@
 #define	INTEL_NB_5000V	0x25d48086
 #define	INTEL_NB_5000X	0x25c08086
 #define	INTEL_NB_5000Z	0x25d08086
+#define	INTEL_NB_5100	0x65c08086
 #define	INTEL_NB_5400	0x40008086
 #define	INTEL_NB_5400A	0x40018086
 #define	INTEL_NB_5400B	0x40038086