changeset 10650:5195e7d7a5f4

6734814 Intel address translation Phase II
author Vuong Nguyen <Vuong.Nguyen@Sun.COM>
date Fri, 25 Sep 2009 14:44:38 -0700
parents ab3ce9d83b84
children 6e737c28ebe6
files usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc usr/src/uts/i86pc/cpu/genuineintel/gintel_main.c usr/src/uts/intel/Makefile.files usr/src/uts/intel/intel_nb5000/Makefile usr/src/uts/intel/intel_nhm/Makefile usr/src/uts/intel/io/intel_nb5000/dimm_addr.c usr/src/uts/intel/io/intel_nb5000/dimm_addr.h usr/src/uts/intel/io/intel_nb5000/dimm_phys.h usr/src/uts/intel/io/intel_nb5000/intel_nb5000.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/rank.h usr/src/uts/intel/io/intel_nhm/intel_nhm.h usr/src/uts/intel/io/intel_nhm/mem_addr.c usr/src/uts/intel/io/intel_nhm/mem_addr.h usr/src/uts/intel/sys/mc_intel.h
diffstat 16 files changed, 509 insertions(+), 381 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc	Fri Sep 25 14:44:38 2009 -0700
@@ -537,17 +537,20 @@
 
 event ereport.cpu.intel.quickpath.mem_addr_parity@motherboard/chip/memory-controller {within(1s)};
 event fault.cpu.intel.quickpath.mem_addr_parity@
-    motherboard/chip/memory-controller/dram-channel/dimm;
-event fault.cpu.intel.quickpath.mem_addr_parity@
     motherboard/chip/memory-controller;
+event fault.cpu.intel.quickpath.mem_addr_parity@CHIPDIMM;
+event fault.cpu.intel.quickpath.mem_addr_parity@CHIPDIMM/rank;
 
 prop fault.cpu.intel.quickpath.mem_addr_parity@
     motherboard/chip/memory-controller (1)->
     ereport.cpu.intel.quickpath.mem_addr_parity@motherboard/chip/memory-controller;
 
-prop fault.cpu.intel.quickpath.mem_addr_parity@
-    motherboard/chip/memory-controller/dram-channel/dimm
-    { payloadprop_contains("resource", asru(motherboard/chip/memory-controller/dram-channel/dimm)) } (1)->
+prop fault.cpu.intel.quickpath.mem_addr_parity@CHIPDIMM
+    { payloadprop_contains("resource", asru(CHIPDIMM)) } (1)->
+    ereport.cpu.intel.quickpath.mem_addr_parity@motherboard/chip/memory-controller;
+
+prop fault.cpu.intel.quickpath.mem_addr_parity@CHIPDIMM/rank
+    { payloadprop_contains("resource", asru(CHIPDIMM/rank)) } (1)->
     ereport.cpu.intel.quickpath.mem_addr_parity@motherboard/chip/memory-controller;
 
 event ereport.cpu.intel.quickpath.mem_bad_addr@motherboard/chip/memory-controller {within(1s)};
@@ -571,18 +574,17 @@
     ereport.cpu.intel.quickpath.mem_bad_id@motherboard/chip/memory-controller;
 
 event ereport.cpu.intel.quickpath.mem_redundant@motherboard/chip/memory-controller {within(1s)};
-engine serd.cpu.intel.quickpath.mem_redundant@
-    motherboard/chip/memory-controller/dram-channel/dimm,
-    N=2, T=72h;
-event fault.cpu.intel.quickpath.mem_redundant@
-    motherboard/chip/memory-controller/dram-channel/dimm,
-    engine=serd.cpu.intel.quickpath.mem_redundant@
-    motherboard/chip/memory-controller/dram-channel/dimm;
+engine serd.cpu.intel.quickpath.mem_redundant@CHIPDIMM, N=2, T=72h;
+event fault.cpu.intel.quickpath.mem_redundant@CHIPDIMM,
+    engine=serd.cpu.intel.quickpath.mem_redundant@CHIPDIMM;
+
+event error.cpu.intel.quickpath.mem_redundant@CHIPDIMM/rank;
 
-prop fault.cpu.intel.quickpath.mem_redundant@
-    motherboard/chip/memory-controller/dram-channel/dimm
-    { payloadprop_contains("resource",
-    asru(motherboard/chip/memory-controller/dram-channel/dimm)) } (1)->
+prop fault.cpu.intel.quickpath.mem_redundant@CHIPDIMM (1)->
+    error.cpu.intel.quickpath.mem_redundant@CHIPDIMM/rank
+    { is_under(CHIPDIMM, CHIPDIMM/rank) };
+prop error.cpu.intel.quickpath.mem_redundant@CHIPDIMM/rank
+    { CONTAINS_RANK } (1)->
     ereport.cpu.intel.quickpath.mem_redundant@
     motherboard/chip/memory-controller;
 
--- a/usr/src/uts/i86pc/cpu/genuineintel/gintel_main.c	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/i86pc/cpu/genuineintel/gintel_main.c	Fri Sep 25 14:44:38 2009 -0700
@@ -382,6 +382,21 @@
 			fm_payload_set(ereport, FM_FMRI_MEM_PHYSADDR,
 			    DATA_TYPE_UINT64, addr, NULL);
 			(void) cmi_mc_patounum(addr, 0, 0, synd, 0, &unum);
+			if (unum.unum_offset != -1ULL &&
+			    (unum.unum_offset & OFFSET_ROW_BANK_COL) != 0) {
+				fm_payload_set(ereport,
+				    FM_EREPORT_PAYLOAD_NAME_BANK,
+				    DATA_TYPE_INT32,
+				    TCODE_OFFSET_BANK(unum.unum_offset), NULL);
+				fm_payload_set(ereport,
+				    FM_EREPORT_PAYLOAD_NAME_CAS,
+				    DATA_TYPE_INT32,
+				    TCODE_OFFSET_CAS(unum.unum_offset), NULL);
+				fm_payload_set(ereport,
+				    FM_EREPORT_PAYLOAD_NAME_RAS,
+				    DATA_TYPE_INT32,
+				    TCODE_OFFSET_RAS(unum.unum_offset), NULL);
+			}
 		}
 		resource = gintel_ereport_create_resource_elem(nva, &unum);
 		fm_payload_set(ereport, FM_EREPORT_PAYLOAD_NAME_RESOURCE,
--- a/usr/src/uts/intel/Makefile.files	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/intel/Makefile.files	Fri Sep 25 14:44:38 2009 -0700
@@ -303,14 +303,3 @@
 	mcamd_dimmcfg.o \
 	mcamd_subr.o \
 	mcamd_pcicfg.o
-
-#
-# Intel 5000/5400/7300 MCH module
-#
-INTEL_NB5000_OBJS += \
-	intel_nb5000.o \
-	intel_nbdrv.o \
-	dimm_addr.o \
-	nb_pci_cfg.o \
-	nb5000_init.o
-
--- a/usr/src/uts/intel/intel_nb5000/Makefile	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/intel/intel_nb5000/Makefile	Fri Sep 25 14:44:38 2009 -0700
@@ -17,22 +17,25 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
 #
+# Intel 5000/5100/5400/7300 chipset memory controller hub (MCH) module
+#
+
+#
 #	Path to the base of the uts directory tree (usually /usr/src/uts).
 #
 UTSBASE = ../..
+UTSCLOSED = ../../../../closed/uts
 
 #
 #       Define the module and object file sets.
 #
 MODULE		= intel_nb5000
 #
-OBJECTS		= $(INTEL_NB5000_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(INTEL_NB5000_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
 SRCDIR		= $(UTSBASE)/intel/io/intel_nb5000
 CONF_SRCDIR	= $(UTSBASE)/intel/io/intel_nb5000
@@ -43,6 +46,23 @@
 include ../Makefile.intel
 
 #
+# The list of object files is defined here, rather than in Makefile.files,
+# because the "$(CLOSED_BUILD)" macro has not been defined at the time
+# Makefile.files is processed.
+#
+INTEL_NB5000_OBJS += \
+	intel_nb5000.o \
+	intel_nbdrv.o \
+	dimm_addr.o \
+	nb_pci_cfg.o \
+	nb5000_init.o
+
+$(CLOSED_BUILD)INTEL_NB5000_OBJS += memtrans.o
+
+OBJECTS		= $(INTEL_NB5000_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(INTEL_NB5000_OBJS:%.o=$(LINTS_DIR)/%.ln)
+
+#
 #       Define targets
 #
 ALL_TARGET      = $(BINARY)
@@ -76,3 +96,4 @@
 #       Include common targets.
 #
 include ../Makefile.targ
+$(CLOSED_BUILD)include $(UTSCLOSED)/intel/Makefile.rules
--- a/usr/src/uts/intel/intel_nhm/Makefile	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/intel/intel_nhm/Makefile	Fri Sep 25 14:44:38 2009 -0700
@@ -22,19 +22,20 @@
 #
 
 #
+# Intel Nehalem memory controller module
+#
+
+#
 #	Path to the base of the uts directory tree (usually /usr/src/uts).
 #
 UTSBASE = ../..
+UTSCLOSED = ../../../../closed/uts
 
 #
 #       Define the module and object file sets.
 #
 MODULE		= intel_nhm
 #
-INTEL_NHM_OBJS = nhm_init.o mem_addr.o intel_nhmdrv.o nhm_pci_cfg.o \
-    dimm_topo.o intel_nhm.o
-OBJECTS		= $(INTEL_NHM_OBJS:%=$(OBJS_DIR)/%)
-LINTS           = $(INTEL_NHM_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE      = $(ROOT_DRV_DIR)/$(MODULE)
 CONF_SRCDIR	= $(UTSBASE)/intel/io/intel_nhm
 
@@ -44,6 +45,25 @@
 include $(UTSBASE)/intel/Makefile.intel
 
 #
+# The list of object files is defined here, rather than in Makefile.files,
+# because the "$(CLOSED_BUILD)" macro has not been defined at the time
+# Makefile.files is processed.
+#
+INTEL_NHM_OBJS += \
+	nhm_init.o \
+	mem_addr.o \
+	intel_nhmdrv.o \
+	nhm_pci_cfg.o \
+	dimm_topo.o \
+	intel_nhm.o
+
+$(CLOSED_BUILD)INTEL_NHM_OBJS += \
+	nhm_dimm_addr.o
+
+OBJECTS		= $(INTEL_NHM_OBJS:%=$(OBJS_DIR)/%)
+LINTS           = $(INTEL_NHM_OBJS:%.o=$(LINTS_DIR)/%.ln)
+
+#
 #       Define targets
 #
 ALL_TARGET      = $(BINARY) $(SRC_CONFFILE)
@@ -78,3 +98,4 @@
 #       Include common targets.
 #
 include ../Makefile.targ
+$(CLOSED_BUILD)include $(UTSCLOSED)/intel/Makefile.rules
--- a/usr/src/uts/intel/io/intel_nb5000/dimm_addr.c	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/intel/io/intel_nb5000/dimm_addr.c	Fri Sep 25 14:44:38 2009 -0700
@@ -32,129 +32,13 @@
 #include <sys/cmn_err.h>
 #include <sys/sunddi.h>
 #include <sys/mc_intel.h>
-#include "dimm_addr.h"
 #include "nb_log.h"
 #include "rank.h"
 #include "dimm_phys.h"
 #include "nb5000.h"
 
-struct dimm_geometry **dimm_geometry;
 struct rank_base *rank_base;
 
-uint64_t
-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;
-
-	/* 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);
-	pa = rp->base;
-
-	for (i = 0, m = 1; bank; i++, m <<= 1) {
-		if ((bank & m) != 0 && rgp->bank[i] != 0xff) {
-			pa += 1 << rgp->bank[i];
-			bank &= ~m;
-		}
-	}
-	for (i = 0, m = 1; cas; i++, m <<= 1) {
-		if ((cas & m) != 0 && rgp->col[i] != 0xff) {
-			pa += 1 << rgp->col[i];
-			cas &= ~m;
-		}
-	}
-	for (i = 0, m = 1; ras; i++, m <<= 1) {
-		if ((ras & m) != 0 && rgp->row[i] != 0xff) {
-			pa += 1 << rgp->row[i];
-			ras &= ~m;
-		}
-	}
-	if (rp->interleave > 1) {
-		i = 0;
-		if (rp->branch_interleave) {
-			if (branch) {
-				pa += 1 << rgp->interleave[i];
-			}
-			i++;
-		}
-		if ((rp->way & 1) != 0)
-			pa += 1 << rgp->interleave[i];
-		i++;
-		if ((rp->way & 2) != 0)
-			pa += 1 << rgp->interleave[i];
-	}
-	if (rp->hole && pa >= rp->hole)
-		pa += rp->hole_size;
-	return (pa);
-}
-
-uint64_t
-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;
-	struct rank_geometry *rgp;
-	struct rank_base *rp;
-	uint64_t pa;
-	uint64_t cal_pa;
-
-	/* 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];
-	offset = 0;
-	pa = dimm_getphys(branch, rank, bank, ras, cas) & PAGEMASK;
-
-	for (i = 0, m = 1; bank; i++, m <<= 1) {
-		if ((bank & m) != 0 && rgp->bank[i] != 0xff) {
-			offset += 1 << rgp->bank[i];
-			bank &= ~m;
-		}
-	}
-	for (i = 0, m = 1; cas; i++, m <<= 1) {
-		if ((cas & m) != 0 && rgp->col[i] != 0xff) {
-			offset += 1 << rgp->col[i];
-			cas &= ~m;
-		}
-	}
-	for (i = 0, m = 1; ras; i++, m <<= 1) {
-		if ((ras & m) != 0 && rgp->row[i] != 0xff) {
-			offset += 1 << rgp->row[i];
-			ras &= ~m;
-		}
-	}
-	cal_pa = rp->base + (offset * rp->interleave);
-	if (rp->hole && cal_pa >= rp->hole)
-		cal_pa += rp->hole_size;
-	cal_pa &= PAGEMASK;
-
-	if (pa != cal_pa) {
-		return (-1LL);
-	}
-	return (offset & PAGEMASK);
-}
-
 static int
 fmri2unum(nvlist_t *nvl, mc_unum_t *unump)
 {
@@ -196,8 +80,6 @@
 			unump->unum_rank = (int)v;
 	}
 
-	unump->unum_offset = offset;
-
 	return (1);
 }
 
@@ -245,14 +127,18 @@
 			return (CMI_SUCCESS);
 		unump = &unum;
 	}
-	if (unump->unum_offset & OFFSET_ROW_BANK_COL) {
-		pa = dimm_getphys(unump->unum_mc,
-		    TCODE_OFFSET_RANK(unump->unum_offset),
-		    TCODE_OFFSET_BANK(unump->unum_offset),
-		    TCODE_OFFSET_RAS(unump->unum_offset),
-		    TCODE_OFFSET_CAS(unump->unum_offset));
-		if (pa == -1LL)
+	if ((unump->unum_offset & OFFSET_ROW_BANK_COL)) {
+		if (&dimm_getphys) {
+			pa = dimm_getphys(unump->unum_mc,
+			    TCODE_OFFSET_RANK(unump->unum_offset),
+			    TCODE_OFFSET_BANK(unump->unum_offset),
+			    TCODE_OFFSET_RAS(unump->unum_offset),
+			    TCODE_OFFSET_CAS(unump->unum_offset));
+			if (pa >= MAXPHYS_ADDR)
+				return (CMIERR_MC_NOADDR);
+		} else {
 			return (CMIERR_MC_NOADDR);
+		}
 		*pap = pa;
 		return (CMI_SUCCESS);
 	}
@@ -277,8 +163,6 @@
 {
 	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) ?
@@ -294,9 +178,6 @@
 {
 	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) ?
@@ -309,48 +190,18 @@
 }
 
 void
-dimm_add_geometry(int branch, int dimm, int nbanks, int width, int ncolumn,
-    int nrow)
-{
-	int i;
-	for (i = 0; i < dimm_types; i++) {
-		if (dimm_data[i].row_nbits == nrow &&
-		    dimm_data[i].col_nbits == ncolumn &&
-		    dimm_data[i].width == width &&
-		    (1 << dimm_data[i].bank_nbits) == nbanks) {
-			dimm_geometry[(branch * nb_dimms_per_channel) + dimm] =
-			    &dimm_data[i];
-			break;
-		}
-	}
-}
-
-void
 dimm_add_rank(int branch, int rank, int branch_interleave, int way,
     uint64_t base, uint32_t hole, uint32_t hole_size, int interleave,
     uint64_t limit)
 {
-	struct dimm_geometry *dimm;
 	struct rank_base *rp;
-	int interleave_nbits;
 	int num_ranks_per_branch;
 
-	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)
-		interleave_nbits = 1;
-	else if (interleave == 4)
-		interleave_nbits = 2;
-	else
-		interleave_nbits = 3;
 	rp->branch_interleave = branch_interleave;
 	rp->way = way;
 	rp->base = base;
@@ -358,10 +209,6 @@
 	rp->hole_size = hole_size;
 	rp->interleave = interleave;
 	rp->limit = limit;
-	if (dimm)
-		rp->rank_geometry = &dimm->rank_geometry[interleave_nbits];
-	else
-		rp->rank_geometry = 0;
 }
 
 static const cmi_mc_ops_t inb_mc_ops = {
--- a/usr/src/uts/intel/io/intel_nb5000/dimm_addr.h	Fri Sep 25 15:00:11 2009 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _DIMM_ADDR_H
-#define	_DIMM_ADDR_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Map for memory address translation for each interleave */
-
-struct rank_geometry {
-	uint8_t row[16];	/* Address bit associated with row bit */
-	uint8_t bank[3];	/* Address bit associated with bank bit */
-	uint8_t col[13];	/* Address bit associated with column bit */
-	uint8_t interleave[3];	/* Address bit associated with interleave bit */
-};
-
-struct dimm_geometry {
-	uint8_t row_nbits;	/* number of row bits */
-	uint8_t col_nbits;	/* number of column bits */
-	uint8_t bank_nbits;	/* number of bank bits */
-	uint8_t width;		/* width */
-	struct rank_geometry rank_geometry[4];	/* for interleave 1,2,4,8 */
-} dimm_data[1];
-
-int dimm_types = sizeof (dimm_data) / sizeof (struct dimm_geometry);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _DIMM_ADDR_H */
--- a/usr/src/uts/intel/io/intel_nb5000/dimm_phys.h	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/intel/io/intel_nb5000/dimm_phys.h	Fri Sep 25 14:44:38 2009 -0700
@@ -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.
  */
 
@@ -31,28 +31,18 @@
 extern "C" {
 #endif
 
-#define	OFFSET_ROW_BANK_COL	0x8000000000000000ULL
-#define	OFFSET_RANK_SHIFT	52
-#define	OFFSET_RAS_SHIFT	32
-#define	OFFSET_BANK_SHIFT	24
-#define	TCODE_OFFSET(rank, bank, ras, cas) (OFFSET_ROW_BANK_COL | \
-	((uint64_t)(rank) << OFFSET_RANK_SHIFT) | \
-	((uint64_t)(ras) << OFFSET_RAS_SHIFT) | \
-	((uint64_t)(bank) << OFFSET_BANK_SHIFT) | (cas))
-
-#define	TCODE_OFFSET_RANK(tcode) (((tcode) >> OFFSET_RANK_SHIFT) & RANK_MASK)
-#define	TCODE_OFFSET_RAS(tcode) (((tcode) >> OFFSET_RAS_SHIFT) & RAS_MASK)
-#define	TCODE_OFFSET_BANK(tcode) (((tcode) >> OFFSET_BANK_SHIFT) & BANK_MASK)
-#define	TCODE_OFFSET_CAS(tcode) ((tcode) & CAS_MASK)
+#define	MAXPHYS_ADDR		0xffffffff00000000ULL
 
 extern void dimm_init(void);
 extern void dimm_fini(void);
 extern void dimm_add_rank(int, int, int, int, uint64_t, uint32_t, uint32_t,
     int, uint64_t);
-extern void dimm_add_geometry(int, int, int, int, int, int);
 
 extern uint64_t dimm_getoffset(int, int, int, int, int);
-extern uint64_t dimm_getphys(int, int, int, int, int);
+extern uint64_t dimm_getphys(uint16_t, uint16_t, uint64_t, uint64_t, uint64_t);
+
+#pragma weak dimm_getoffset
+#pragma weak dimm_getphys
 
 #ifdef __cplusplus
 }
--- a/usr/src/uts/intel/io/intel_nb5000/intel_nb5000.c	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/intel/io/intel_nb5000/intel_nb5000.c	Fri Sep 25 14:44:38 2009 -0700
@@ -132,10 +132,30 @@
 		sp->bank = (nrecmema >> 12) & BANK_MASK;
 		sp->cas = (nrecmemb >> 16) & CAS_MASK;
 		sp->ras = nrecmemb & RAS_MASK;
-		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);
+		/*
+		 * If driver was built with closed tree present then we will
+		 * have Intel proprietary code for finding physaddr
+		 */
+		if (&dimm_getphys) {
+			sp->pa = dimm_getphys((uint16_t)sp->branch,
+			    (uint16_t)sp->rank, (uint64_t)sp->bank,
+			    (uint64_t)sp->ras, (uint64_t)sp->cas);
+			if (sp->pa >= MAXPHYS_ADDR)
+				sp->pa = -1ULL;
+		} else {
+			sp->pa = -1ULL;
+		}
+		/*
+		 * If there is an offset decoder use it otherwise encode
+		 * rank/bank/ras/cas
+		 */
+		if (&dimm_getoffset) {
+			sp->offset = dimm_getoffset(sp->branch, sp->rank,
+			    sp->bank, sp->ras, sp->cas);
+		} else {
+			sp->offset = TCODE_OFFSET(sp->rank, sp->bank, sp->ras,
+			    sp->cas);
+		}
 	} else {
 		if ((ferr_fat_fbd & ERR_FAT_FBD_M3) != 0)
 			intr = "nb.fbd.otf";	/* thermal temp > Tmid M3 */
@@ -300,10 +320,26 @@
 		}
 	}
 	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);
+		/*
+		 * If driver was built with closed tree present then we will
+		 * have Intel proprietary code for finding physaddr
+		 */
+		if (&dimm_getphys) {
+			sp->pa = dimm_getphys((uint16_t)sp->branch,
+			    (uint16_t)sp->rank, (uint64_t)sp->bank,
+			    (uint64_t)sp->ras, (uint64_t)sp->cas);
+			if (sp->pa >= MAXPHYS_ADDR)
+				sp->pa = -1ULL;
+		} else {
+			sp->pa = -1ULL;
+		}
+		if (&dimm_getoffset) {
+			sp->offset = dimm_getoffset(sp->branch, sp->rank,
+			    sp->bank, sp->ras, sp->cas);
+		} else {
+			sp->offset = TCODE_OFFSET(sp->rank, sp->bank, sp->ras,
+			    sp->cas);
+		}
 	}
 	return (intr);
 }
@@ -450,10 +486,26 @@
 		}
 	}
 	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);
+		/*
+		 * If driver was built with closed tree present then we will
+		 * have Intel proprietary code for finding physaddr
+		 */
+		if (&dimm_getphys) {
+			sp->pa = dimm_getphys((uint16_t)sp->branch,
+			    (uint16_t)sp->rank, (uint64_t)sp->bank,
+			    (uint64_t)sp->ras, (uint64_t)sp->cas);
+			if (sp->pa >= MAXPHYS_ADDR)
+				sp->pa = -1ULL;
+		} else {
+			sp->pa = -1ULL;
+		}
+		if (&dimm_getoffset) {
+			sp->offset = dimm_getoffset(sp->branch, sp->rank,
+			    sp->bank, sp->ras, sp->cas);
+		} else {
+			sp->offset = TCODE_OFFSET(sp->rank, sp->bank, sp->ras,
+			    sp->cas);
+		}
 	}
 	return (intr);
 }
--- a/usr/src/uts/intel/io/intel_nb5000/nb5000.h	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/intel/io/intel_nb5000/nb5000.h	Fri Sep 25 14:44:38 2009 -0700
@@ -937,7 +937,7 @@
 	nb_pci_getl(0, 16, 1, 0xc0, 0))
 #define	NRECFGLOG_RD(branch)	(nb_chipset == INTEL_NB_5400 ? \
 	nb_pci_getl(0, (branch) ? 22 : 21, 1, 0x74, 0) : \
-	nb_pci_getl(0, 16, 1, 0xc4, 0))
+	nb_pci_getl(0, 16, 1, nb_chipset == INTEL_NB_7300 ? 0x74 : 0xc4, 0))
 #define	NRECFBDA_RD(branch)	(nb_chipset == INTEL_NB_5400 ? \
 	nb_pci_getl(0, (branch) ? 22 : 21, 1, 0xc4, 0) : \
 	nb_pci_getl(0, 16, 1, nb_chipset == INTEL_NB_7300 ? 0xc4 : 0xc8, 0))
@@ -1370,12 +1370,16 @@
 
 #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_5100) { \
-		rank0 = (dmir) & 3; \
-		rank1 = ((dmir) >> 3) & 3; \
-		rank2 = ((dmir) >> 6) & 3; \
-		rank3 = ((dmir) >> 9) & 3; \
+	    nb_chipset == INTEL_NB_5000V || nb_chipset == INTEL_NB_5000Z) { \
+		rank0 = (dmir) & 0x7; \
+		rank1 = ((dmir) >> 3) & 0x7; \
+		rank2 = ((dmir) >> 6) & 0x7; \
+		rank3 = ((dmir) >> 9) & 0x7; \
+	} else if (nb_chipset == INTEL_NB_5100) { \
+		rank0 = (dmir) & 0x7; \
+		rank1 = ((dmir) >> 4) & 0x7; \
+		rank2 = ((dmir) >> 8) & 0x7; \
+		rank3 = ((dmir) >> 12) & 0x7; \
 	} else { \
 		rank0 = (dmir) & 0xf; \
 		rank1 = ((dmir) >> 4) & 0xf; \
--- a/usr/src/uts/intel/io/intel_nb5000/nb5000_init.c	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/intel/io/intel_nb5000/nb5000_init.c	Fri Sep 25 14:44:38 2009 -0700
@@ -809,9 +809,6 @@
 			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,
@@ -875,9 +872,6 @@
 			dimmpp[j] = nb_fbd_dimm_init(k, j, mtr);
 			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(
 					    (k * nb_dimms_per_channel) + j,
--- a/usr/src/uts/intel/io/intel_nb5000/rank.h	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/intel/io/intel_nb5000/rank.h	Fri Sep 25 14:44:38 2009 -0700
@@ -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.
  */
 
@@ -39,7 +39,6 @@
 	int branch_interleave;
 	int way;
 	int interleave;
-	void *rank_geometry;
 };
 
 extern struct rank_base *rank_base;
--- a/usr/src/uts/intel/io/intel_nhm/intel_nhm.h	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/intel/io/intel_nhm/intel_nhm.h	Fri Sep 25 14:44:38 2009 -0700
@@ -103,6 +103,10 @@
 	((reg) & (1 << (8 + (channel))) != 0)
 #define	MC_CONTROL_ECCEN(reg) (((reg) >> 1) & 1)
 #define	MC_CONTROL_CLOSED_PAGE(reg) ((reg) & 1)
+#define	MC_CONTROL_DIVBY3(reg) ((reg >> 6) &1)
+
+#define	NUM_CACHELINE_BITS	6	/* Cachelines are 64B */
+
 /*
  * MC_STATUS
  */
@@ -137,7 +141,17 @@
 #define	REMOVE_7(reg)	(((reg) >> 25) & 1)
 #define	REMOVE_8(reg)	(((reg) >> 26) & 1)
 #define	CH_ADDRESS_OFFSET(reg) \
-	((int64_t)(((uint64_t)(reg) & 0x00ffffff) << 40) >> 40)
+	(int64_t)((uint64_t)(reg) & 0x00ffffff)
+#define	CH_ADDRESS_SOFFSET(reg) \
+	((int64_t)(((uint64_t)(reg) & 0x00ffffff) << 40) >>40)
+/* SAG offset covers SA[39:16] so granularity is 2^16 = 64KB */
+#define	SAG_OFFSET_GRANULARITY	16
+/* 24-bit mask for TTMAD_CR_SAG_CH*.OFFSET */
+#define	SAG_OFFSET_SIZE_MASK	0xffffffULL
+/* 16-bit mask for lower bits not covered by CREG value (SA[15:0]) */
+#define	SAG_OFFSET_ADDR_MASK	0xffffULL
+#define	CACHELINE_ADDR_MASK	0x3fULL	/* 6-bit mask */
+
 /*
  * MC_RIR_LIMIT_CH
  */
@@ -145,11 +159,23 @@
 /*
  * MC_RIR_WAY_CH
  */
-#define	RIR_OFFSET(reg) ((int64_t)(((uint64_t)(reg) & 0x3ff0) << 50) >> 54)
-#define	RIR_RANK(reg) ((reg) & 0xf)
+#define	RIR_OFFSET(reg)	(int64_t)((uint64_t)(reg >> 4)& 0x3ff)
+#define	RIR_SOFFSET(reg)	((int64_t)(((uint64_t)(reg) & 0x3ff0) << 50) \
+				    >> 54)
+#define	RIR_DIMM_RANK(reg)	((reg) & 0xf)
+#define	RIR_RANK(reg)	((reg) & 0x3)
+#define	RIR_DIMM(reg)	((reg)>>2 & 0x03)
+#define	RIR_OFFSET_SIZE_MASK	0x3ff
 
 #define	MAX_RIR_WAY 4
 
+#define	RIR_LIMIT_GRANULARITY	28
+#define	RIR_OFFSET_ADDR_MASK	0xfffffffULL	/* 28-bit mask */
+#define	RIR_INTLV_PGOPEN_BIT	12	/* Rank interleaving */
+#define	RIR_INTLV_PGOPEN_MASK	0xfffULL	/* 12-bit mask */
+#define	RIR_INTLV_PGCLS_BIT	6	/* Rank interleaving */
+#define	RIR_INTLV_PGCLS_MASK	0x3fULL	/* 6-bit mask */
+#define	RIR_INTLV_SIZE_MASK	0x3ULL
 /*
  * MC_RAS_ENABLES
  */
@@ -198,9 +224,22 @@
 #define	SAD_DRAM_MODE(sad) (((sad) >> 1) & 3)
 #define	SAD_DRAM_RULE_ENABLE(sad) ((sad) & 1)
 
-#define	SAD_INTERLEAVE(list, num) (((list) >> ((num) * 4)) & 0x3)
-#define	INTERLEAVE_NWAY 8
-#define	MAX_SAD_DRAM_RULE 8
+/*
+ * from SAD_DRAM_RULE*.MODE
+ */
+#define	DIRECT	0
+#define	XOR	1
+#define	MOD3	2
+#define	SAD_INTERLEAVE(list, num)	(((list) >> ((num) * 4)) & 0x3)
+#define	INTERLEAVE_NWAY	8
+#define	MAX_SAD_DRAM_RULE	8
+
+#define	SAD_LIMIT_GRANULARITY	26
+#define	SAD_LIMIT_ADDR_MASK	0x3ffffffULL
+#define	SAD_INTLV_DIRECT_BIT	6
+#define	SAD_INTLV_XOR_BIT	16
+#define	SAD_INTLV_SIZE_MASK	0x7ULL
+#define	SAD_INTLV_ADDR_MASK	0x3fULL
 
 /*
  * TAD_DRAM_RULE
@@ -215,6 +254,57 @@
 
 #define	VRANK_SZ 0x40000000
 
+typedef struct sad {
+	uint64_t limit;
+	uint32_t node_list;
+	uint32_t node_tgt[INTERLEAVE_NWAY];
+	char mode;
+	char enable;
+	char interleave;
+} sad_t;
+
+typedef struct tad {
+	uint64_t limit;
+	uint32_t pkg_list;
+	uint32_t pkg_tgt[INTERLEAVE_NWAY];
+	char mode;
+	char enable;
+	char interleave;
+} tad_t;
+
+typedef struct sag_ch {
+	uint32_t offset;
+	int32_t soffset;
+	char divby3;
+	char remove6;
+	char remove7;
+	char remove8;
+} sag_ch_t;
+
+typedef struct rir_way {
+	uint16_t offset;
+	int16_t soffset;
+	uint8_t	rank;
+	uint8_t dimm;
+	uint8_t dimm_rank;
+	uint64_t rlimit;
+} way_t;
+
+typedef struct rir {
+	uint64_t limit;
+	way_t way[MAX_RIR_WAY];
+	char interleave;
+} rir_t;
+
+typedef struct dod_type {
+	int NUMCol;
+	int NUMRow;
+	int NUMRank;
+	int NUMBank;
+	int DIMMPresent;
+	int RankOffset;
+} dod_t;
+
 /*
  * MC_CHANNEL_MAPPER
  */
--- a/usr/src/uts/intel/io/intel_nhm/mem_addr.c	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/intel/io/intel_nhm/mem_addr.c	Fri Sep 25 14:44:38 2009 -0700
@@ -28,48 +28,25 @@
 #include <sys/time.h>
 #include <sys/fm/protocol.h>
 #include <sys/cpu_module_impl.h>
+#include <sys/mc_intel.h>
 #include "intel_nhm.h"
 #include "nhm_log.h"
-
-struct sad {
-	uint64_t limit;
-	uint32_t node_list;
-	char mode;
-	char enable;
-	char interleave;
-} sad[MAX_SAD_DRAM_RULE];
-
-struct tad {
-	uint64_t limit;
-	uint32_t pkg_list;
-	char mode;
-	char enable;
-	char interleave;
-} tad[MAX_CPU_NODES][MAX_TAD_DRAM_RULE];
-
-struct sag_ch {
-	int32_t offset;
-	char divby3;
-	char remove6;
-	char remove7;
-	char remove8;
-} sag_ch[MAX_CPU_NODES][CHANNELS_PER_MEMORY_CONTROLLER][MAX_TAD_DRAM_RULE];
-
-struct rir {
-	uint64_t limit;
-	struct rir_way {
-		int16_t offset;
-		uint8_t	rank;
-		uint64_t rlimit;
-	} way[MAX_RIR_WAY];
-	char interleave;
-} rir[MAX_CPU_NODES][CHANNELS_PER_MEMORY_CONTROLLER][MAX_TAD_DRAM_RULE];
+#include "mem_addr.h"
 
 char closed_page;
 char ecc_enabled;
+char divby3_enabled;
 char lockstep[2];
 char mirror_mode[2];
 char spare_channel[2];
+sad_t sad[MAX_SAD_DRAM_RULE];
+tad_t tad[MAX_CPU_NODES][MAX_TAD_DRAM_RULE];
+sag_ch_t sag_ch[MAX_CPU_NODES][CHANNELS_PER_MEMORY_CONTROLLER]
+	[MAX_TAD_DRAM_RULE];
+rir_t rir[MAX_CPU_NODES][CHANNELS_PER_MEMORY_CONTROLLER]
+	[MAX_TAD_DRAM_RULE];
+dod_t dod_reg[MAX_CPU_NODES][CHANNELS_PER_MEMORY_CONTROLLER]
+	[MAX_DIMMS_PER_CHANNEL];
 
 static int
 channel_in_interleave(int node, int channel, int rule, int *way_p,
@@ -185,7 +162,7 @@
 	if (lockstep[node] || mirror_mode[node])
 		channel = 0;
 	caddr = (((addr >> 16) +
-	    (int64_t)sag_ch[node][channel][rule].offset) << 16) |
+	    (int64_t)sag_ch[node][channel][rule].soffset) << 16) |
 	    (addr & 0xffc0);
 	if (sag_ch[node][channel][rule].remove8) {
 		caddr = ((caddr >> 1) & ~0xff) | (caddr & 0xff);
@@ -205,8 +182,8 @@
 }
 
 int
-address_to_channel(int node, uint64_t addr, int write, uint64_t *channel_addrp,
-    int *interleave_p)
+address_to_channel(int node, uint64_t addr, int write,
+    int *log_chan, uint64_t *channel_addrp, int *interleave_p)
 {
 	int i;
 	int channel = -1;
@@ -233,10 +210,14 @@
 			default:
 				return (-1);
 			}
+			/* get logical channel number */
 			channel = TAD_INTERLEAVE(tad[node][i].pkg_list, way);
+			if (log_chan)
+				*log_chan = channel;
+
 			if (channel_addrp) {
-				*channel_addrp = channel_address(node, channel,
-				    i, addr);
+				*channel_addrp = channel_address(node,
+				    channel, i, addr);
 			}
 			if (interleave_p)
 				*interleave_p = tad[node][i].interleave;
@@ -257,7 +238,7 @@
 		case 4:
 			channel = 2;
 			break;
-		case 3:			/* mirror PCH0 and PCH1 */
+		case 3:		/* mirror PCH0 and PCH1 */
 			if (!write) {
 				if (((addr >> 24) & 1) ^ ((addr >> 12) & 1) ^
 				    ((addr >> 6) & 1))
@@ -266,10 +247,10 @@
 					channel = 0;
 			}
 			break;
-		case 5:			/* sparing PCH0 to PCH2 */
+		case 5:		/* sparing PCH0 to PCH2 */
 			channel = 0;
 			break;
-		case 6:			/* sparing PCH1 to PCH2 */
+		case 6:		/* sparing PCH1 to PCH2 */
 			channel = 1;
 			break;
 		}
@@ -287,20 +268,19 @@
 	node = address_to_node(addr, &sinterleave);
 	if (sinterleave == 1) {
 		channels = 0;
-		(void) address_to_channel(node, addr, 0, 0, &channels);
+		(void) address_to_channel(node, addr, 0, 0, 0, &channels);
 	} else {
 		channels = 0;
 		channels1 = 0;
-		(void) address_to_channel(0, addr, 0, 0, &channels);
-		(void) address_to_channel(1, addr, 0, 0, &channels1);
+		(void) address_to_channel(0, addr, 0, 0, 0, &channels);
+		(void) address_to_channel(1, addr, 0, 0, 0, &channels1);
 		channels += channels1;
 	}
 	return (channels);
 }
 
-
 int
-caddr_to_dimm(int node, int channel, uint64_t caddr, int *rank_p,
+channel_addr_to_dimm(int node, int channel, uint64_t caddr, int *rank_p,
     uint64_t *rank_addr_p)
 {
 	int i;
@@ -449,7 +429,7 @@
 	base = 0;
 	for (i = 0; i < MAX_TAD_DRAM_RULE && found == 0; i++) {
 		for (way = 0; way < MAX_RIR_WAY; way++) {
-			if (rir[node][channel][i].way[way].rank == rank) {
+			if (rir[node][channel][i].way[way].dimm_rank == rank) {
 				rlimit = rir[node][channel][i].way[way].rlimit;
 				if (rlimit && rank_addr >= rlimit)
 					continue;
@@ -457,7 +437,7 @@
 					caddr = (rank_addr & ~0x3f) *
 					    rir[node][channel][i].interleave -
 					    (int64_t)rir[node][channel][i].
-					    way[way].offset * VRANK_SZ;
+					    way[way].soffset * VRANK_SZ;
 					cbaddr = caddr;
 					caddr += way << 6;
 					caddr |= rank_addr & 0x3f;
@@ -465,7 +445,7 @@
 					caddr = (rank_addr & ~0xfff) *
 					    rir[node][channel][i].interleave -
 					    (int64_t)rir[node][channel][i].
-					    way[way].offset * VRANK_SZ;
+					    way[way].soffset * VRANK_SZ;
 					cbaddr = caddr;
 					caddr += way << 12;
 					caddr |= rank_addr & 0xfff;
@@ -519,9 +499,10 @@
 				addr = ((addr & ~0xff) << 1) | (addr & 0xff);
 				baddr = ((baddr & ~0xff) << 1) | (baddr & 0xc0);
 			}
-			addr -= (int64_t)sag_ch[node][lchannel][i].offset << 16;
+			addr -= (int64_t)sag_ch[node][lchannel][i].soffset <<
+			    16;
 			baddr -= (int64_t)
-			    sag_ch[node][lchannel][i].offset << 16;
+			    sag_ch[node][lchannel][i].soffset << 16;
 			if (addr < tad[node][i].limit) {
 				sinterleave = socket_interleave(addr,
 				    node, channel, i, &way);
@@ -620,7 +601,6 @@
 	}
 	return (addr);
 }
-
 /*ARGSUSED*/
 static cmi_errno_t
 nhm_patounum(void *arg, uint64_t pa, uint8_t valid_hi, uint8_t valid_lo,
@@ -630,25 +610,49 @@
 	int channel;
 	int dimm;
 	int rank;
+	int log_chan;
+	uint64_t bank, row, column;
 	uint64_t caddr, raddr;
 
 	node = address_to_node(pa, 0);
-	if (node == -1)
+	if (node == -1) {
+		return (CMIERR_UNKNOWN);
+	}
+	channel = address_to_channel(node, pa, syndtype, &log_chan, &caddr, 0);
+	if (channel == -1) {
 		return (CMIERR_UNKNOWN);
-	channel = address_to_channel(node, pa, syndtype, &caddr, 0);
-	if (channel == -1)
-		return (CMIERR_UNKNOWN);
-	dimm = caddr_to_dimm(node, channel, caddr, &rank, &raddr);
-	if (dimm == -1)
+	}
+	/*
+	 * If driver was built with closed tree present then we will have Intel
+	 * proprietary functions caddr_to_dimm and rankaddr_to_dimm for finding
+	 * dimm/bank/row/column address otherwise we just locate dimm and
+	 * offset.
+	 */
+	if (&caddr_to_dimm)
+		dimm = caddr_to_dimm(node, log_chan, caddr, &rank, &raddr);
+	else
+		dimm = channel_addr_to_dimm(node, log_chan, caddr, &rank,
+		    &raddr);
+	if (dimm == -1) {
 		return (CMIERR_UNKNOWN);
 
+	}
 	unump->unum_board = 0;
 	unump->unum_chip = node;
 	unump->unum_mc = 0;
 	unump->unum_chan = channel;
 	unump->unum_cs = dimm;
 	unump->unum_rank = rank;
-	unump->unum_offset = raddr;
+
+	if (&rankaddr_to_dimm) {
+		if (rankaddr_to_dimm(raddr, node, channel, dimm, 0, &bank, &row,
+		    &column) != DDI_SUCCESS) {
+			return (CMIERR_UNKNOWN);
+		};
+		unump->unum_offset = TCODE_OFFSET(rank, bank, row, column);
+	} else {
+		unump->unum_offset = raddr;
+	}
 
 	return (CMI_SUCCESS);
 }
@@ -661,22 +665,26 @@
 	cmi_errno_t rt;
 	int node;
 	int channel;
+	int log_chan;
 	int rank;
 	int i;
 	nvlist_t **hcl, *hcsp;
 	uint_t npr;
-	uint64_t rank_addr;
+	uint64_t offset;
 	char *hcnm, *hcid;
 	long v;
+	uint64_t row, bank, col;
+	int dimm;
+	uint64_t rank_addr;
 
 	if (unump == NULL) {
 		if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC,
 		    &hcsp) != 0)
 			return (CMIERR_UNKNOWN);
 		if (nvlist_lookup_uint64(hcsp,
-		    "asru-" FM_FMRI_HC_SPECIFIC_OFFSET, &rank_addr) != 0 &&
+		    "asru-" FM_FMRI_HC_SPECIFIC_OFFSET, &offset) != 0 &&
 		    nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET,
-		    &rank_addr) != 0) {
+		    &offset) != 0) {
 			if (nvlist_lookup_uint64(hcsp,
 			    "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR, &pa) == 0 ||
 			    nvlist_lookup_uint64(hcsp,
@@ -691,6 +699,7 @@
 			return (CMIERR_UNKNOWN);
 		node = -1;
 		channel = -1;
+		dimm = -1;
 		rank = -1;
 		for (i = 0; i < npr; i++) {
 			if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME,
@@ -703,19 +712,41 @@
 				node = (int)v;
 			else if (strcmp(hcnm, "dram-channel") == 0)
 				channel = (int)v;
+			else if (strcmp(hcnm, "dimm") == 0)
+				dimm = (int)v;
 			else if (strcmp(hcnm, "rank") == 0)
 				rank = (int)v;
 		}
-		if (node == -1 || channel == -1 || rank == -1)
+		if (node == -1 || channel == -1 || dimm == -1 || rank == -1)
 			return (CMIERR_UNKNOWN);
 	} else {
 		node = unump->unum_chip;
 		channel = unump->unum_chan;
 		rank = unump->unum_rank;
-		rank_addr = unump->unum_offset;
+		dimm = unump->unum_cs;
+		offset = unump->unum_offset;
 	}
-	pa = dimm_to_addr(node, channel, rank, rank_addr, 0, 0, 0, 0, 0, 0, 0,
-	    0);
+
+	/*
+	 * If driver was built with closed tree present then we will have Intel
+	 * proprietary functions dimm_to_rankaddr for finding
+	 * physical address.
+	 */
+	if (&dimm_to_rankaddr && (offset & OFFSET_ROW_BANK_COL) != 0) {
+		row = TCODE_OFFSET_RAS(offset);
+		bank = TCODE_OFFSET_BANK(offset);
+		col = TCODE_OFFSET_CAS(offset);
+		rank_addr = dimm_to_rankaddr(node, channel, dimm, row,
+		    bank, col, &log_chan);
+		pa = rankaddr_to_phyaddr(node, log_chan, dimm, rank,
+		    rank_addr);
+	} else if ((offset & OFFSET_ROW_BANK_COL) == 0) {
+		pa = dimm_to_addr(node, channel, rank, offset, 0, 0, 0, 0, 0,
+		    0, 0, 0);
+	} else {
+		pa = -1LL;
+	}
+
 	if (pa == -1) {
 		rt = CMIERR_UNKNOWN;
 	} else {
@@ -810,7 +841,7 @@
 		return;
 	for (k = 0; k <= rule; k++) {
 		for (l = 0; l < way; l++) {
-			if (rir[socket][channel][k].way[l].rank == rank &&
+			if (rir[socket][channel][k].way[l].dimm_rank == rank &&
 			    rir[socket][channel][k].way[l].rlimit == 0) {
 				rir[socket][channel][k].way[l].rlimit =
 				    rank_addr;
@@ -837,6 +868,7 @@
 	uint8_t	rank;
 	uint64_t base;
 	int ras_dev = 0;
+	uint32_t dod_value;
 
 	nhm_slot = choose_cpu(&nhm_lastslot);
 
@@ -847,6 +879,10 @@
 		sad[i].mode = SAD_DRAM_MODE(sad_dram_rule);
 		sad[i].node_list = SAD_INTERLEAVE_LIST_RD(nhm_slot, i);
 		sad[i].interleave = sad_interleave(sad[i].node_list);
+		for (j = 0; j < INTERLEAVE_NWAY; j++) {
+			sad[i].node_tgt[j] = (sad[i].node_list >>
+			    (j * 4)) & 0x3;
+		}
 	}
 
 	for (i = nhm_slot; i < nhm_lastslot; i++) {
@@ -871,6 +907,10 @@
 			tad[i][j].mode = TAD_DRAM_MODE(tad_dram_rule);
 			tad[i][j].pkg_list =
 			    TAD_INTERLEAVE_LIST_RD(i, j);
+			for (k = 0; k < INTERLEAVE_NWAY; k++) {
+				tad[i][j].pkg_tgt[k] = ((tad[i][j].pkg_list >>
+				    (k * 4)) & 0x3);
+			}
 			if (mirror_mode[i] || lockstep[i]) {
 				tad[i][j].interleave = 1;
 			} else {
@@ -889,6 +929,8 @@
 				sagch = MC_SAG_RD(i, j, k);
 				sag_ch[i][j][k].offset =
 				    CH_ADDRESS_OFFSET(sagch);
+				sag_ch[i][j][k].soffset =
+				    CH_ADDRESS_SOFFSET(sagch);
 				sag_ch[i][j][k].divby3 = DIVBY3(sagch);
 				sag_ch[i][j][k].remove6 = REMOVE_6(sagch);
 				sag_ch[i][j][k].remove7 = REMOVE_7(sagch);
@@ -900,32 +942,50 @@
 					rir_way = MC_RIR_WAY_RD(i, j, m);
 					rir[i][j][k].way[l].offset =
 					    RIR_OFFSET(rir_way);
+					rir[i][j][k].way[l].soffset =
+					    RIR_SOFFSET(rir_way);
 					rir[i][j][k].way[l].rank =
 					    RIR_RANK(rir_way);
+					rir[i][j][k].way[l].dimm =
+					    RIR_DIMM(rir_way);
+					rir[i][j][k].way[l].dimm_rank =
+					    RIR_DIMM_RANK(rir_way);
 					rir[i][j][k].way[l].rlimit = 0;
 					m++;
 				}
-				rank = rir[i][j][k].way[0].rank;
-				if (rank == rir[i][j][k].way[1].rank &&
-				    rank == rir[i][j][k].way[2].rank &&
-				    rank == rir[i][j][k].way[3].rank) {
+				rank = rir[i][j][k].way[0].dimm_rank;
+				if (rank == rir[i][j][k].way[1].dimm_rank &&
+				    rank == rir[i][j][k].way[2].dimm_rank &&
+				    rank == rir[i][j][k].way[3].dimm_rank) {
 					rir[i][j][k].interleave = 1;
-				} else if (rank == rir[i][j][k].way[1].rank ||
-				    rank == rir[i][j][k].way[2].rank ||
-				    rank == rir[i][j][k].way[3].rank) {
+				} else if
+				    (rank == rir[i][j][k].way[1].dimm_rank ||
+				    rank == rir[i][j][k].way[2].dimm_rank ||
+				    rank == rir[i][j][k].way[3].dimm_rank) {
 					rir[i][j][k].interleave = 2;
 				} else {
 					rir[i][j][k].interleave = 4;
 				}
 				for (l = 0; l < MAX_RIR_WAY; l++) {
 					set_rank(i, j, k, l,
-					    rir[i][j][k].way[l].rank,
-					    ((rir[i][j][k].way[l].offset +
+					    rir[i][j][k].way[l].dimm_rank,
+					    ((rir[i][j][k].way[l].soffset +
 					    base) /
 					    rir[i][j][k].interleave));
 				}
 				base = rir[i][j][k].limit;
 			}
+			for (k = 0; k < MAX_DIMMS_PER_CHANNEL; k++) {
+				dod_value = MC_DOD_RD(i, j, k);
+				dod_reg[i][j][k].NUMCol = NUMCOL(dod_value);
+				dod_reg[i][j][k].NUMRow = NUMROW(dod_value);
+				dod_reg[i][j][k].NUMBank = NUMBANK(dod_value);
+				dod_reg[i][j][k].NUMRank = NUMRANK(dod_value);
+				dod_reg[i][j][k].DIMMPresent =
+				    DIMMPRESENT(dod_value);
+				dod_reg[i][j][k].RankOffset =
+				    RANKOFFSET(dod_value);
+			}
 		}
 	}
 	mc_control = MC_CONTROL_RD(nhm_slot);
@@ -934,4 +994,5 @@
 		ecc_enabled = MC_CONTROL_ECCEN(mc_control);
 	else if ((MC_STATUS_RD(nhm_slot) & WS_ECC_ENABLED) != 0)
 		ecc_enabled = 1;
+	divby3_enabled = MC_CONTROL_DIVBY3(mc_control);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/io/intel_nhm/mem_addr.h	Fri Sep 25 14:44:38 2009 -0700
@@ -0,0 +1,80 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MEM_ADDR_H
+#define	_MEM_ADDR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "intel_nhm.h"
+
+#ifdef	_KERNEL
+
+extern uint64_t rankaddr_to_dimm(uint64_t rankaddr, int node,
+    int channel, int dimm, int writing, uint64_t *bank,
+    uint64_t *row, uint64_t *column);
+extern uint64_t dimm_to_rankaddr(int node, int channel,
+    int dimm, uint64_t rowaddr, uint64_t bankaddr,
+    uint64_t coladr, int *log_chan);
+extern uint64_t rankaddr_to_phyaddr(int node, int log_chan,
+    int dimm, int rank, int rankaddr);
+extern uint64_t caddr_to_dimm(int node, int channel, uint64_t caddr,
+    int *rank_p, uint64_t *rank_addr_p);
+
+#pragma weak caddr_to_dimm
+#pragma weak rankaddr_to_dimm
+#pragma weak dimm_to_rankaddr
+#pragma weak rankaddr_to_phyaddr
+
+extern char closed_page;
+extern char ecc_enabled;
+extern char divby3_enabled;
+extern char lockstep[2];
+extern char mirror_mode[2];
+extern char spare_channel[2];
+extern sad_t sad[MAX_SAD_DRAM_RULE];
+extern tad_t tad[MAX_CPU_NODES][MAX_TAD_DRAM_RULE];
+extern sag_ch_t sag_ch[MAX_CPU_NODES][CHANNELS_PER_MEMORY_CONTROLLER]
+	[MAX_TAD_DRAM_RULE];
+extern rir_t rir[MAX_CPU_NODES][CHANNELS_PER_MEMORY_CONTROLLER]
+	[MAX_TAD_DRAM_RULE];
+extern dod_t dod_reg[MAX_CPU_NODES][CHANNELS_PER_MEMORY_CONTROLLER]
+	[MAX_DIMMS_PER_CHANNEL];
+
+#endif	/* _KERNEL */
+
+#define	CAS_MASK	0xFFFFFF
+#define	BANK_MASK	0xFF
+#define	RAS_MASK	0xFFFFF
+#define	RANK_MASK	0x7FF
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MEM_ADDR_H */
--- a/usr/src/uts/intel/sys/mc_intel.h	Fri Sep 25 15:00:11 2009 -0400
+++ b/usr/src/uts/intel/sys/mc_intel.h	Fri Sep 25 14:44:38 2009 -0700
@@ -287,6 +287,26 @@
 #define	MSR_MC_MISC_MEM_SYNDROME	0xffffffff00000000ULL
 #define	MSR_MC_MISC_MEM_SYNDROME_SHIFT	32
 
+#define	OFFSET_ROW_BANK_COL	0x8000000000000000ULL
+#define	OFFSET_RANK_SHIFT	52
+#define	OFFSET_RAS_SHIFT	32
+#define	OFFSET_BANK_SHIFT	24
+#define	TCODE_OFFSET(rank, bank, ras, cas) (OFFSET_ROW_BANK_COL | \
+	((uint64_t)(rank) << OFFSET_RANK_SHIFT) | \
+	((uint64_t)(ras) << OFFSET_RAS_SHIFT) | \
+	((uint64_t)(bank) << OFFSET_BANK_SHIFT) | (cas))
+
+#define	MAX_CAS_MASK	0xFFFFFF
+#define	MAX_BANK_MASK	0xFF
+#define	MAX_RAS_MASK	0xFFFFF
+#define	MAX_RANK_MASK	0x7FF
+#define	TCODE_OFFSET_RANK(tcode) \
+	(((tcode) >> OFFSET_RANK_SHIFT) & MAX_RANK_MASK)
+#define	TCODE_OFFSET_RAS(tcode) (((tcode) >> OFFSET_RAS_SHIFT) & MAX_RAS_MASK)
+#define	TCODE_OFFSET_BANK(tcode) \
+	(((tcode) >> OFFSET_BANK_SHIFT) & MAX_BANK_MASK)
+#define	TCODE_OFFSET_CAS(tcode) ((tcode) & MAX_CAS_MASK)
+
 #ifdef __cplusplus
 }
 #endif