6593380 topology for Sun x64 platforms should include serial numbers for dimms
authorrobj
Wed, 26 Mar 2008 13:39:54 -0700
changeset 6292 964ff070e569
parent 6291 a919a9cd71a0
child 6293 a2353cc6ff6b
6593380 topology for Sun x64 platforms should include serial numbers for dimms 6671247 missing DIMM FRU labels on 4600/4600M2 platforms with family 15 modules 6672188 chip FRU labels computed incorrectly on 2-socket AF4+ blades 6675806 libipmi: ipmi_fru_read() can leak memory on failure
usr/src/cmd/fm/eversholt/files/i386/i86pc/amd64.esc
usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc
usr/src/cmd/fm/fmd/common/fmd_api.c
usr/src/cmd/fm/schemes/mem/mem.c
usr/src/lib/fm/topo/libtopo/common/libtopo.h
usr/src/lib/fm/topo/libtopo/common/mapfile-vers
usr/src/lib/fm/topo/libtopo/common/topo_fmri.c
usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml
usr/src/lib/fm/topo/modules/i86pc/chip/Makefile
usr/src/lib/fm/topo/modules/i86pc/chip/chip.c
usr/src/lib/fm/topo/modules/i86pc/chip/chip.h
usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c
usr/src/lib/fm/topo/modules/i86pc/chip/chip_label.c
usr/src/lib/fm/topo/modules/i86pc/chip/chip_serial.c
usr/src/lib/fm/topo/modules/i86pc/chip/chip_subr.c
usr/src/lib/libipmi/common/ipmi_fru.c
--- a/usr/src/cmd/fm/eversholt/files/i386/i86pc/amd64.esc	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/cmd/fm/eversholt/files/i386/i86pc/amd64.esc	Wed Mar 26 13:39:54 2008 -0700
@@ -20,7 +20,7 @@
  */
 
 /* 
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved. 
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved. 
  * Use is subject to license terms. 
  */ 
  
@@ -224,14 +224,14 @@
 engine stat.ckpgflt@chip/memory-controller/dimm/rank;
 
 event fault.memory.page_sb@chip/memory-controller/dimm/rank,
-    FITrate=PAGE_FIT, ASRU=dimm/rank, message=0,
+    FITrate=PAGE_FIT, FRU=dimm, ASRU=dimm/rank, message=0,
     count=stat.sbpgflt@chip/memory-controller/dimm/rank,
     action=confcall("rewrite-ASRU"); /* rewrite ASRU to identify page in rank */
 
 #define	SB_PGFLTS (count(stat.sbpgflt@chip/memory-controller/dimm/rank))
 
 event fault.memory.page_ck@chip/memory-controller/dimm/rank,
-    FITrate=PAGE_FIT, ASRU=dimm/rank, message=0,
+    FITrate=PAGE_FIT, FRU=dimm, ASRU=dimm/rank, message=0,
     count=stat.ckpgflt@chip/memory-controller/dimm/rank,
     action=confcall("rewrite-ASRU"); /* rewrite ASRU to identify page in rank */
 
@@ -434,7 +434,7 @@
     action=confcall("rewrite-ASRU"); /* rewrite non-leaf ASRU in mem scheme */
 
 event fault.memory.page_ue@chip/memory-controller/dimm/rank,
-    FITrate=PAGE_FIT, ASRU=dimm/rank, message=0,
+    FITrate=PAGE_FIT, FRU=dimm, ASRU=dimm/rank, message=0,
     action=confcall("rewrite-ASRU"); /* rewrite ASRU to identify page in rank */
 
 event ereport.memory.dimm_ue_trip@chip/memory-controller/dimm/rank{within(5s)};
--- a/usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/cmd/fm/eversholt/files/i386/i86pc/intel.esc	Wed Mar 26 13:39:54 2008 -0700
@@ -20,7 +20,7 @@
  */
 
 /* 
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved. 
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved. 
  * Use is subject to license terms. 
  */ 
  
@@ -315,6 +315,7 @@
 event fault.memory.intel.page_ue@
     motherboard/memory-controller/dram-channel/dimm/rank,
     FITrate=PAGE_FIT,
+    FRU=motherboard/memory-controller/dram-channel/dimm,
     ASRU=motherboard/memory-controller/dram-channel/dimm/rank, message=0,
     action=confcall("rewrite-ASRU"); /* rewrite ASRU to identify page in rank */
 event ereport.memory.page_ue_trip@motherboard/memory-controller{within(12s)};
@@ -442,6 +443,7 @@
 event fault.memory.intel.page_ce@
     motherboard/memory-controller/dram-channel/dimm/rank,
     FITrate=PAGE_FIT,
+    FRU=motherboard/memory-controller/dram-channel/dimm,
     ASRU=motherboard/memory-controller/dram-channel/dimm/rank, message=0,
     count=stat.ce_pgflt@motherboard/memory-controller/dram-channel/dimm,
     action=confcall("rewrite-ASRU"); /* rewrite ASRU to identify page in rank */
--- a/usr/src/cmd/fm/fmd/common/fmd_api.c	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/cmd/fm/fmd/common/fmd_api.c	Wed Mar 26 13:39:54 2008 -0700
@@ -1684,7 +1684,7 @@
 	fmd_module_t *mp;
 	topo_hdl_t *thp;
 	nvlist_t *nvl;
-	char *loc = NULL;
+	char *loc = NULL, *serial = NULL;
 	int err;
 
 	mp = fmd_api_module_lock(hdl);
@@ -1698,6 +1698,21 @@
 	 */
 	(void) topo_fmri_label(thp, fru, &loc, &err);
 
+	/*
+	 * In some cases, serial information for the resource will not be
+	 * available at enumeration but may instead be available by invoking
+	 * a dynamic property method on the FRU.  In order to ensure the serial
+	 * number is persisted properly in the ASRU cache, we'll fetch the
+	 * property, if it exists, and add it to the resource and fru fmris.
+	 */
+	if (fru != NULL) {
+		(void) topo_fmri_serial(thp, fru, &serial, &err);
+		if (serial != NULL) {
+			(void) nvlist_add_string(rsrc, "serial", serial);
+			(void) nvlist_add_string(fru, "serial", serial);
+			topo_hdl_strfree(thp, serial);
+		}
+	}
 	nvl = fmd_protocol_fault(class, certainty, asru, fru, rsrc, loc);
 
 	if (loc != NULL)
--- a/usr/src/cmd/fm/schemes/mem/mem.c	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/cmd/fm/schemes/mem/mem.c	Wed Mar 26 13:39:54 2008 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -36,6 +36,8 @@
 #ifdef	sparc
 #include <sys/fm/ldom.h>
 ldom_hdl_t *mem_scheme_lhp;
+#else
+#include <fm/libtopo.h>
 #endif	/* sparc */
 
 mem_t mem;
@@ -169,6 +171,7 @@
 		return (0);
 }
 
+#ifdef sparc
 static int
 serids_eq(char **serids1, uint_t nserids1, char **serids2, uint_t nserids2)
 {
@@ -184,19 +187,28 @@
 
 	return (1);
 }
+#endif /* sparc */
 
 int
 fmd_fmri_present(nvlist_t *nvl)
 {
-	char *unum, **nvlserids, **serids;
+	char *unum = NULL;
+	int rc;
+#ifdef sparc
+	char **nvlserids, **serids;
 	uint_t nnvlserids;
 	size_t nserids;
 	uint64_t memconfig;
-	int rc;
+#else
+	struct topo_hdl *thp;
+	nvlist_t *unum_nvl;
+	int err;
+#endif /* sparc */
 
 	if (mem_fmri_get_unum(nvl, &unum) < 0)
 		return (-1); /* errno is set for us */
 
+#ifdef sparc
 	if (nvlist_lookup_string_array(nvl, FM_FMRI_MEM_SERIAL_ID, &nvlserids,
 	    &nnvlserids) != 0) {
 		/*
@@ -246,7 +258,27 @@
 	rc = serids_eq(serids, nserids, nvlserids, nnvlserids);
 
 	mem_strarray_free(serids, nserids);
+#else
+	/*
+	 * On X86 we will invoke the topo is_present method passing in the
+	 * unum, which is in hc scheme.  The libtopo hc-scheme is_present method
+	 * will invoke the node-specific is_present method, which is implemented
+	 * by the chip enumerator for rank nodes.  The rank node's is_present
+	 * method will compare the serial number in the unum with the current
+	 * serial to determine if the same DIMM is present.
+	 */
+	if ((thp = fmd_fmri_topo_hold(TOPO_VERSION)) == NULL) {
+		fmd_fmri_warn("failed to get handle to topology");
+		return (-1);
+	}
+	if (topo_fmri_str2nvl(thp, unum, &unum_nvl, &err) == 0) {
+		rc = topo_fmri_present(thp, unum_nvl, &err);
+		nvlist_free(unum_nvl);
+	} else
+		rc = fmd_fmri_set_errno(EINVAL);
+	fmd_fmri_topo_rele(thp);
 
+#endif	/* sparc */
 	return (rc);
 }
 
--- a/usr/src/lib/fm/topo/libtopo/common/libtopo.h	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/libtopo.h	Wed Mar 26 13:39:54 2008 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -89,6 +89,7 @@
 extern int topo_fmri_fru(topo_hdl_t *, nvlist_t *, nvlist_t **,
     int *);
 extern int topo_fmri_label(topo_hdl_t *, nvlist_t *, char **, int *);
+extern int topo_fmri_serial(topo_hdl_t *, nvlist_t *, char **, int *);
 extern int topo_fmri_compare(topo_hdl_t *, nvlist_t *, nvlist_t *, int *);
 
 /*
--- a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers	Wed Mar 26 13:39:54 2008 -0700
@@ -40,6 +40,7 @@
 	topo_fmri_label;
 	topo_fmri_nvl2str;
 	topo_fmri_present;
+	topo_fmri_serial;
 	topo_fmri_setprop;
 	topo_fmri_str2nvl;
 	topo_fmri_unusable;
--- a/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c	Wed Mar 26 13:39:54 2008 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -399,6 +399,29 @@
 	return (0);
 }
 
+int
+topo_fmri_serial(topo_hdl_t *thp, nvlist_t *nvl, char **serial, int *err)
+{
+	nvlist_t *prop = NULL;
+	char *sp;
+
+	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, FM_FMRI_HC_SERIAL_ID,
+	    NULL, &prop, err) < 0)
+		return (set_error(thp, *err, err, "topo_fmri_serial", NULL));
+
+	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &sp) != 0)
+		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_serial",
+		    prop));
+
+	if ((*serial = topo_hdl_strdup(thp, sp)) == NULL)
+		return (set_error(thp, ETOPO_PROP_NOMEM, err,
+		    "topo_fmri_serial", prop));
+
+	nvlist_free(prop);
+
+	return (0);
+}
+
 int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
     const char *pname, nvlist_t *args,  nvlist_t **prop,
     int *err)
--- a/usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml	Wed Mar 26 13:39:54 2008 -0700
@@ -48,7 +48,7 @@
 
         </set> 
         <set type='product'
-	    setlist='Sun-Fire(TM)-X2100|Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4200E|Sun-Fire-X4500|X2100-M2|Sun-Blade-X8440-Server-Module|Sun-Fire-X4140|Sun-Fire-X4240|Sun-Fire-X4440'>
+	    setlist='Sun-Fire(TM)-X2100|Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4200E|Sun-Fire-X4500|X2100-M2|Sun-Fire-X4140|Sun-Fire-X4240|Sun-Fire-X4440'>
 	    
             <propgroup name='protocol' version='1'
                 name-stability='Private' data-stability='Private' >
@@ -97,6 +97,22 @@
             </propgroup>
 
         </set> 
+        <set type='product'
+	    setlist='Sun-Blade-X8420-Server-Module|Sun-Blade-X8440-Server-Module|SUN-BLADE-X8440-SERVER-MODULE'>
+	    
+            <propgroup name='protocol' version='1'
+                name-stability='Private' data-stability='Private' >
+
+                <propmethod name='a4fplus_chip_label' version='0'
+		            propname='label' proptype='string' >
+              
+                    <argval name='format' type='string' value='CPU %d' />
+
+                </propmethod>
+
+            </propgroup>
+
+        </set> 
 
     <dependents grouping='children'>
 
@@ -167,7 +183,36 @@
                     </propgroup>
 
                 </set> 
-                <set type='product' setlist='Sun-Fire-V20z|Sun-Fire-V40z|Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4200E'>
+                <set type='product' setlist='Sun-Fire-V20z|Sun-Fire-V40z'>
+		    
+                    <propgroup name='protocol' version='1'
+                               name-stability='Private'
+			       data-stability='Private' >
+
+                        <propmethod name='simple_dimm_label_mp' version='0'
+			            propname='label' proptype='string' >
+              
+                            <argval name='format' type='string'
+			        value='CPU %d DIMM %d' />
+                            <argval name='offset' type='uint32' value='0' />
+                            <argval name='order' type='string'
+			        value='forward' />
+                            <argval name='dimms_per_chip' type='uint32'
+			        value='4' />
+
+                        </propmethod>
+                        <propmethod name='get_dimm_serial' version='0'
+			            propname='serial' proptype='string' >
+              
+                            <argval name='format' type='string'
+			        value='cpu%d.mem%d.vpd' />
+                            <argval name='offset' type='uint32' value='0' />
+
+                        </propmethod>
+
+                    </propgroup>
+                </set>
+                <set type='product' setlist='Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4200E|Sun-Fire-X4500'>
 		    
                     <propgroup name='protocol' version='1'
                                name-stability='Private'
@@ -185,6 +230,58 @@
 			        value='4' />
 
                         </propmethod>
+                        <propmethod name='get_dimm_serial' version='0'
+			            propname='serial' proptype='string' >
+              
+                            <argval name='format' type='string'
+			        value='p%d.d%d.fru' />
+                            <argval name='offset' type='uint32' value='0' />
+
+                        </propmethod>
+
+                    </propgroup>
+
+                </set>
+                <set type='product' setlist='Sun-Fire-X4100-M2|Sun-Fire-X4200-M2'>
+		    
+                    <propgroup name='protocol' version='1'
+                               name-stability='Private'
+			       data-stability='Private' >
+
+                        <propmethod name='get_dimm_serial' version='0'
+			            propname='serial' proptype='string' >
+              
+                            <argval name='format' type='string'
+			        value='p%d.d%d.fru' />
+                            <argval name='offset' type='uint32' value='0' />
+
+                        </propmethod>
+
+                    </propgroup>
+
+                </set>
+                <set type='product' setlist='Sun-Fire-X4600|Sun-Fire-X4600-M2'>
+		    
+                    <propgroup name='protocol' version='1'
+                               name-stability='Private'
+			       data-stability='Private' >
+
+                        <propmethod name='g4_dimm_label' version='0'
+			            propname='label' proptype='string' >
+              
+                            <argval name='format' type='string'
+			        value='%s DIMM %d' />
+                            <argval name='offset' type='uint32' value='0' />
+
+                        </propmethod>
+                        <propmethod name='get_dimm_serial' version='0'
+			            propname='serial' proptype='string' >
+              
+                            <argval name='format' type='string'
+			        value='p%d.d%d.fru' />
+                            <argval name='offset' type='uint32' value='0' />
+
+                        </propmethod>
 
                     </propgroup>
 
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/Makefile	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/Makefile	Wed Mar 26 13:39:54 2008 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -27,8 +27,9 @@
 MODULE = chip
 ARCH = i86pc
 CLASS = arch
-MODULESRCS = chip.c chip_label.c chip_subr.c chip_amd.c chip_intel.c
+MODULESRCS = chip.c chip_label.c chip_subr.c chip_amd.c chip_intel.c\
+chip_serial.c
 
 include ../../Makefile.plugin
 
-LDLIBS += -lkstat
+LDLIBS += -lkstat -lipmi
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c	Wed Mar 26 13:39:54 2008 -0700
@@ -77,6 +77,8 @@
 	    TOPO_STABILITY_INTERNAL, simple_chip_label},
 	{ G4_CHIP_LBL, "Property method", 0,
 	    TOPO_STABILITY_INTERNAL, g4_chip_label},
+	{ A4FPLUS_CHIP_LBL, "Property method", 0,
+	    TOPO_STABILITY_INTERNAL, a4fplus_chip_label},
 	{ NULL }
 };
 
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h	Wed Mar 26 13:39:54 2008 -0700
@@ -71,10 +71,17 @@
 #define	SIMPLE_DIMM_LBL		"simple_dimm_label"
 #define	SIMPLE_DIMM_LBL_MP	"simple_dimm_label_mp"
 #define	SEQ_DIMM_LBL		"seq_dimm_label"
+#define	G4_DIMM_LBL		"g4_dimm_label"
 #define	SIMPLE_CHIP_LBL		"simple_chip_label"
 #define	G4_CHIP_LBL		"g4_chip_label"
+#define	A4FPLUS_CHIP_LBL	"a4fplus_chip_label"
 #define	SIMPLE_CS_LBL_MP	"simple_cs_label_mp"
 
+/*
+ * DIMM serial number property methods
+ */
+#define	GET_DIMM_SERIAL		"get_dimm_serial"
+
 typedef struct chip {
 	kstat_ctl_t *chip_kc;
 	kstat_t **chip_cpustats;
@@ -90,15 +97,24 @@
 extern int seq_dimm_label(topo_mod_t *, tnode_t *, topo_version_t,
     nvlist_t *, nvlist_t **);
 
+extern int g4_dimm_label(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
+    nvlist_t **);
+
 extern int simple_chip_label(topo_mod_t *, tnode_t *, topo_version_t,
     nvlist_t *, nvlist_t **);
 
 extern int g4_chip_label(topo_mod_t *, tnode_t *, topo_version_t,
     nvlist_t *, nvlist_t **);
 
+extern int a4fplus_chip_label(topo_mod_t *, tnode_t *, topo_version_t,
+    nvlist_t *, nvlist_t **);
+
 extern int simple_cs_label_mp(topo_mod_t *, tnode_t *, topo_version_t,
     nvlist_t *, nvlist_t **);
 
+extern int get_dimm_serial(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
+    nvlist_t **);
+
 /*
  * Support functions of chip_subr.c
  */
@@ -116,6 +132,8 @@
 extern nvlist_t *mem_fmri_create(topo_mod_t *, const char *);
 extern int mem_asru_compute(topo_mod_t *, tnode_t *, topo_version_t,
     nvlist_t *, nvlist_t **);
+extern int rank_fmri_present(topo_mod_t *, tnode_t *, topo_version_t,
+    nvlist_t *, nvlist_t **);
 extern int mem_asru_create(topo_mod_t *, nvlist_t *, nvlist_t **);
 
 /*
@@ -130,6 +148,10 @@
 extern int mc_offchip_open(void);
 extern int mc_offchip_create(topo_mod_t *, tnode_t *, const char *, nvlist_t *);
 
+extern char *get_fmtstr(topo_mod_t *, nvlist_t *);
+extern int store_prop_val(topo_mod_t *, char *, char *, nvlist_t **out);
+
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c	Wed Mar 26 13:39:54 2008 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -65,6 +65,10 @@
 	    TOPO_STABILITY_INTERNAL, simple_dimm_label_mp},
 	{ SEQ_DIMM_LBL, "Property method", 0,
 	    TOPO_STABILITY_INTERNAL, seq_dimm_label},
+	{ G4_DIMM_LBL, "Property method", 0,
+	    TOPO_STABILITY_INTERNAL, g4_dimm_label},
+	{ GET_DIMM_SERIAL, "Property method", 0,
+	    TOPO_STABILITY_INTERNAL, get_dimm_serial},
 	{ NULL }
 };
 
@@ -72,6 +76,9 @@
 	{ TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
 	    TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
 	    mem_asru_compute },
+	{ TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC,
+	    TOPO_METH_PRESENT_VERSION, TOPO_STABILITY_INTERNAL,
+	    rank_fmri_present },
 	{ NULL }
 };
 
@@ -391,7 +398,7 @@
 		}
 
 		if (topo_method_register(mod, dimmnode, dimm_methods) < 0)
-			whinge(mod, &nerr, "dimm_create: "
+			whinge(mod, &nerr, "amd_dimm_create: "
 			    "topo_method_register failed");
 
 		/*
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip_label.c	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_label.c	Wed Mar 26 13:39:54 2008 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -32,12 +32,14 @@
 #include <string.h>
 #include <strings.h>
 #include <libnvpair.h>
+#include <kstat.h>
+#include <unistd.h>
 #include <sys/types.h>
 #include <fm/topo_mod.h>
 
 #define	BUFSZ	128
 
-static char *
+char *
 get_fmtstr(topo_mod_t *mod, nvlist_t *in)
 {
 	char *fmtstr;
@@ -61,7 +63,7 @@
 	return (fmtstr);
 }
 
-static int
+int
 store_prop_val(topo_mod_t *mod, char *buf, char *propname, nvlist_t **out)
 {
 	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) {
@@ -471,6 +473,110 @@
 }
 
 /*
+ * Utility function used by a4fplus_chip_label to determine the number of chips
+ * (as opposed to processors) that are installed in the system by dividing the
+ * number of installed processors (cores) by the number of cores per chip
+ * (from kstat).  This assumes that an an A4F+ blade won't have some weird
+ * configuration of mixed chip models with differing numbers of cores per chip,
+ * which I think is a relatively safe assumption here.
+ */
+static int
+get_num_chips(topo_mod_t *mod)
+{
+	kstat_t *ksp;
+	kstat_ctl_t *kctl;
+	kstat_named_t *k;
+
+	if ((kctl = kstat_open()) == NULL) {
+		topo_mod_dprintf(mod, NULL, "kstat_open failed (%s)\n",
+		    strerror(errno));
+		return (-1);
+	}
+	if ((ksp = kstat_lookup(kctl, "cpu_info", -1, NULL)) == NULL) {
+		topo_mod_dprintf(mod, NULL, "kstat_lookup failed (%s)\n",
+		    strerror(errno));
+		(void) kstat_close(kctl);
+		return (-1);
+	}
+	if (kstat_read(kctl, ksp, NULL) < 0) {
+		topo_mod_dprintf(mod, NULL, "kstat_read failed (%s)\n",
+		    strerror(errno));
+		(void) kstat_close(kctl);
+		return (-1);
+	}
+	if ((k = kstat_data_lookup(ksp, "ncore_per_chip")) == NULL) {
+		topo_mod_dprintf(mod, NULL, "kstat_data_lookup failed (%s)\n",
+		    strerror(errno));
+		(void) kstat_close(kctl);
+		return (-1);
+	}
+	(void) kstat_close(kctl);
+	return (sysconf(_SC_NPROCESSORS_CONF) / k->value.l);
+}
+
+/*
+ * This is a custom property method for generating the CPU slot label for the
+ * Andromeda Fplus platforms.
+ *
+ * format:	a string containing a printf-like format with a single %d token
+ *              which this method computes
+ *
+ *              i.e.: CPU %d
+ */
+/* ARGSUSED */
+int
+a4fplus_chip_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
+    nvlist_t *in, nvlist_t **out)
+{
+	char *fmtstr, buf[BUFSZ];
+	int num_nodes;
+
+	topo_mod_dprintf(mod, "a4fplus_chip_label() called\n");
+	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
+		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
+		/* topo errno already set */
+		return (-1);
+	}
+
+	/*
+	 * Normally we'd figure out the total number of chip nodes by looking
+	 * at the CoherentNodes property.  However, due to the lack of a memory
+	 * controller driver for family 0x10, this property wont exist on the
+	 * chip nodes on A4Fplus.
+	 */
+	if ((num_nodes = get_num_chips(mod)) < 0) {
+		topo_mod_dprintf(mod, "Failed to determine number of chip "
+		    "nodes\n");
+		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
+	}
+	switch (num_nodes) {
+		case (2):
+			/* LINTED: E_SEC_PRINTF_VAR_FMT */
+			(void) snprintf(buf, BUFSZ, fmtstr,
+			    topo_node_instance(node) + 2);
+			break;
+		case (4):
+			/* LINTED: E_SEC_PRINTF_VAR_FMT */
+			(void) snprintf(buf, BUFSZ, fmtstr,
+			    topo_node_instance(node));
+			break;
+		default:
+			topo_mod_dprintf(mod, "Invalid number of chip nodes:"
+			    " %d\n", num_nodes);
+			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+
+
+	if (store_prop_val(mod, buf, "label", out) != 0) {
+		topo_mod_dprintf(mod, "Failed to set label\n");
+		/* topo errno already set */
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
  * This is a somewhat generic property method for labelling the chip-select
  * nodes on multi-socket AMD family 0x10 platforms.  This is necessary because
  * these platforms are not supported by the current AMD memory controller driver
@@ -542,3 +648,61 @@
 
 	return (0);
 }
+
+/* ARGSUSED */
+int
+g4_dimm_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
+    nvlist_t *in, nvlist_t **out)
+{
+	char *fmtstr, *chip_lbl, buf[BUFSZ];
+	tnode_t *chip;
+	int ret, err = 0;
+	uint32_t offset;
+	nvlist_t *args;
+
+	topo_mod_dprintf(mod, "g4_dimm_label() called\n");
+
+	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
+		    strerror(ret));
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
+		    strerror(ret));
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
+		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
+		/* topo errno already set */
+		return (-1);
+	}
+
+	/*
+	 * The 4600/4600M2 have a weird way of labeling the chip nodes, so
+	 * instead of trying to recompute it, we'll simply look it up and
+	 * prepend it to our dimm label.
+	 */
+	chip = topo_node_parent(topo_node_parent(node));
+	if (topo_prop_get_string(chip, TOPO_PGROUP_PROTOCOL, "label", &chip_lbl,
+	    &err) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup label prop on %s=%d\n",
+		    topo_node_name(chip), topo_node_instance(chip),
+		    topo_strerror(err));
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+
+	/* LINTED: E_SEC_PRINTF_VAR_FMT */
+	(void) snprintf(buf, BUFSZ, fmtstr, chip_lbl,
+	    (topo_node_instance(node) + offset));
+
+	topo_mod_strfree(mod, chip_lbl);
+
+	if (store_prop_val(mod, buf, "label", out) != 0) {
+		topo_mod_dprintf(mod, "Failed to set label\n");
+		/* topo errno already set */
+		return (-1);
+	}
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_serial.c	Wed Mar 26 13:39:54 2008 -0700
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <strings.h>
+#include <libnvpair.h>
+#include <sys/types.h>
+#include <libipmi.h>
+#include <fm/topo_mod.h>
+#include <ctype.h>
+#include "chip.h"
+
+#define	BUFSZ	128
+#define	JEDEC_TBL_SZ	4
+
+/*
+ * The following table maps DIMM manufacturer names to a JEDEC ID as sourced
+ * from JEDEC publication JEP106W.  This is (obviously) a sparse table which
+ * only contains entries for manufacturers whose DIMM's have been qualified
+ * for use on Sun platforms.
+ */
+static const char *jedec_tbl[JEDEC_TBL_SZ][2] =
+{
+	{ "INFINEON", "00C1" },
+	{ "MICRON TECHNOLOGY", "002C" },
+	{ "QIMONDA", "7F51" },
+	{ "SAMSUNG", "00CE" },
+};
+
+static int
+ipmi_serial_lookup(topo_mod_t *mod, char *ipmi_tag, char *buf)
+{
+	char *fru_data;
+	int i, found_id = 0, serial_len;
+	ipmi_handle_t *hdl;
+	ipmi_sdr_fru_locator_t *fru_loc;
+	ipmi_fru_prod_info_t prod_info;
+
+	topo_mod_dprintf(mod, "ipmi_serial_lookup() called\n");
+	if ((hdl = topo_mod_ipmi(mod)) == NULL) {
+		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
+		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
+	}
+
+	topo_mod_dprintf(mod, "Looking up FRU data for %s ...\n", ipmi_tag);
+	if ((fru_loc = ipmi_sdr_lookup_fru(hdl, (const char *)ipmi_tag))
+	    == NULL) {
+		topo_mod_dprintf(mod, "Failed to lookup %s (%s)\n", ipmi_tag,
+		    ipmi_errmsg(hdl));
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+
+
+	topo_mod_dprintf(mod, "Reading FRU data ...\n");
+	if (ipmi_fru_read(hdl, fru_loc, &fru_data) < 0) {
+		topo_mod_dprintf(mod, "Failed to read FRU data (%s)\n",
+		    ipmi_errmsg(hdl));
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+
+	topo_mod_dprintf(mod, "Parsing product info area ...\n");
+	if (ipmi_fru_parse_product(hdl, fru_data, &prod_info) < 0) {
+		topo_mod_dprintf(mod, "Failed to read FRU product info (%s)\n",
+		    ipmi_errmsg(hdl));
+		free(fru_data);
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+	free(fru_data);
+
+	topo_mod_dprintf(mod, "FRU Product Serial: %s\n",
+	    prod_info.ifpi_product_serial);
+	topo_mod_dprintf(mod, "Manufacturer Name: \"%s\"\n",
+	    prod_info.ifpi_manuf_name);
+
+	serial_len = strnlen(prod_info.ifpi_product_serial, FRU_INFO_MAXLEN);
+
+	/*
+	 * Newer ILOM software that has the fix for CR 6607996 will have
+	 * an 18-character serial number that has been synthesized using
+	 * the recipe from the Sun SPD JEDEC DIMM specification.  If we
+	 * find an 18-character then we'll simply use it, as-is, and
+	 * return.
+	 */
+	if (serial_len == 18) {
+		(void) memcpy(buf, prod_info.ifpi_product_serial, 18);
+		*(buf+18) = '\0';
+		return (0);
+	}
+	/*
+	 * Older ILOM software that DOESN'T have the fix for CR 6607996 will
+	 * only provide the 8 character manufacturer serial number.
+	 *
+	 * However, if for some reason the product info area doesn't have the
+	 * serial information or if the serial isn't 8 characters (we may
+	 * encounter SP's that don't populate the serial field or are buggy and
+	 * populate it with garbage), then we'll stop right now and just set the
+	 * buf to an empty string.
+	 */
+	if (serial_len != 8) {
+		*buf = '\0';
+		return (0);
+	}
+
+	/*
+	 * What follows is a very crude adaptation of the recipe from the
+	 * Sun SPD JEDEC DIMM specification for synthesizing globally unique
+	 * serial numbers from the 8 character manufacturer serial number.
+	 *
+	 * The Sun serial number takes the following form:
+	 *
+	 * jjjjllyywwssssssss
+	 *
+	 * The components are:
+	 *
+	 * yyyy: JEDEC ID in hex (2 byte manufacture ID, 2 byte continuation
+	 * 		code).
+	 *
+	 * ll:   The memory module's manufacturing location.
+	 *
+	 * yyww: The module's manufacturing date (2-digit year/2-digit week)
+	 *
+	 * ssssssss: The 8 character maufacturer serial number
+	 */
+	/*
+	 * First we need to normalize the manufacturer name we pulled out of
+	 * the FRU product info area.  Our normalization algorithm is fairly
+	 * simple:
+	 *   - convert all alpha chars to uppercase
+	 *   - convert non-alphanumeric characters to a single space
+	 *
+	 * We use the normalized name to lookup the JEDEC ID from a static
+	 * table.  If the FRU area didn't have a manufacturer name or if the ID
+	 * lookup fails we'll set jjjj to 0000.
+	 */
+	for (i = 0; prod_info.ifpi_manuf_name[i]; i++) {
+		prod_info.ifpi_manuf_name[i] =
+		    toupper(prod_info.ifpi_manuf_name[i]);
+		if (!isalpha(prod_info.ifpi_manuf_name[i]) &&
+		    !isdigit(prod_info.ifpi_manuf_name[i]))
+			prod_info.ifpi_manuf_name[i] = (char)0x20;
+	}
+	topo_mod_dprintf(mod, "Normalized Manufacturer Name \"%s\"\n",
+	    prod_info.ifpi_manuf_name);
+
+	for (i = 0; i < JEDEC_TBL_SZ; i++)
+		if (strcmp(prod_info.ifpi_manuf_name, jedec_tbl[i][0]) == 0) {
+			found_id = 1;
+			break;
+		}
+
+	if (found_id)
+		(void) memcpy(buf, jedec_tbl[i][1], 4);
+	else
+		(void) memcpy(buf, (char *)("0000"), 4);
+
+	/*
+	 * The manufacturing location and date is not available via IPMI on
+	 * Sun platforms, so we simply set these six digits to zeros.
+	 */
+	(void) memcpy((buf+4), (char *)("000000"), 6);
+
+	/*
+	 * Finally, we just copy the 8 character product serial straight over
+	 * and then NULL terminate the string.
+	 */
+	(void) memcpy((buf+10), prod_info.ifpi_product_serial, 8);
+	*(buf+18) = '\0';
+
+	return (0);
+}
+
+/* ARGSUSED */
+int
+get_dimm_serial(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
+    nvlist_t *in, nvlist_t **out)
+{
+	char *fmtstr, ipmi_tag[BUFSZ], fru_serial[FRU_INFO_MAXLEN];
+	tnode_t *chip;
+	int ret;
+	uint32_t offset;
+	nvlist_t *args;
+
+	topo_mod_dprintf(mod, "get_dimm_serial() called\n");
+	if ((ret = nvlist_lookup_nvlist(in, "args", &args)) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
+		    strerror(ret));
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
+		    strerror(ret));
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
+		/* topo errno set */
+		topo_mod_dprintf(mod, "Failed to retrieve format arg\n");
+		return (-1);
+	}
+
+	chip = topo_node_parent(topo_node_parent(node));
+
+	/* LINTED: E_SEC_PRINTF_VAR_FMT */
+	(void) snprintf(ipmi_tag, BUFSZ, fmtstr, topo_node_instance(chip),
+	    (topo_node_instance(node) + offset));
+
+	if (ipmi_serial_lookup(mod, ipmi_tag, fru_serial) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup serial for %s\n",
+		    ipmi_tag);
+		(void) strcpy(fru_serial, "");
+	}
+
+	if (store_prop_val(mod, fru_serial, "serial", out) != 0) {
+		topo_mod_dprintf(mod, "Failed to set serial\n");
+		/* topo errno already set */
+		return (-1);
+	}
+	return (0);
+}
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip_subr.c	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_subr.c	Wed Mar 26 13:39:54 2008 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -390,3 +390,67 @@
 
 	return (0);
 }
+
+/*
+ * If we're getting called then the question of whether this dimm is plugged
+ * in has already been answered.  What we don't know for sure is whether it's
+ * the same dimm or a different one plugged in the same slot.  To check, we
+ * try and compare the serial numbers on the dimm in the current topology with
+ * the serial num from the unum fmri that got passed into this function as the
+ * argument.
+ *
+ * In the event we encounter problems comparing serials or if a comparison isn't
+ * possible, we err on the side of caution and set is_present to TRUE.
+ */
+/* ARGSUSED */
+int
+rank_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version,
+    nvlist_t *in, nvlist_t **out)
+{
+	tnode_t *dimmnode;
+	int err, is_present = 1;
+	nvlist_t *unum;
+	char *curr_serial, *old_serial = NULL;
+
+	/*
+	 * If a serial number for the dimm was available at the time of the
+	 * fault, it will have been added as a string to the unum nvlist
+	 */
+	unum = in;
+	if (nvlist_lookup_string(unum, FM_FMRI_HC_SERIAL_ID, &old_serial) != 0)
+		goto done;
+
+	/*
+	 * If the current serial number is available for the DIMM that this rank
+	 * belongs to, it will be accessible as a property on the parent (dimm)
+	 * node.
+	 */
+	dimmnode = topo_node_parent(node);
+	if (topo_prop_get_string(dimmnode, TOPO_PGROUP_PROTOCOL,
+	    FM_FMRI_HC_SERIAL_ID, &curr_serial, &err) != 0) {
+		if (err != ETOPO_PROP_NOENT) {
+			whinge(mod, &err, "rank_fmri_present: Unexpected error "
+			    "retrieving serial from node");
+			return (topo_mod_seterrno(mod,  EMOD_NVL_INVAL));
+		} else
+			goto done;
+	}
+
+	if (strcmp(old_serial, curr_serial) != 0)
+		is_present = 0;
+
+	topo_mod_strfree(mod, curr_serial);
+done:
+	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) {
+		whinge(mod, &err,
+		    "rank_fmri_present: failed to allocate nvlist!");
+		return (topo_mod_seterrno(mod, EMOD_NOMEM));
+	}
+
+	if (nvlist_add_uint32(*out, TOPO_METH_PRESENT_RET, is_present) != 0) {
+		nvlist_free(*out);
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+
+	return (0);
+}
--- a/usr/src/lib/libipmi/common/ipmi_fru.c	Wed Mar 26 11:58:25 2008 -0700
+++ b/usr/src/lib/libipmi/common/ipmi_fru.c	Wed Mar 26 13:39:54 2008 -0700
@@ -55,6 +55,7 @@
 	uint8_t count, devid;
 	uint16_t sz, offset = 0;
 	ipmi_fru_read_t cmd_data_in;
+	char *tmp;
 
 	devid = fru_loc->_devid_or_slaveaddr._logical._is_fl_devid;
 	/*
@@ -76,7 +77,7 @@
 	}
 
 	(void) memcpy(&sz, resp->ic_data, sizeof (uint16_t));
-	if ((*buf = malloc(sz)) == NULL) {
+	if ((tmp = malloc(sz)) == NULL) {
 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
 		return (-1);
 	}
@@ -96,18 +97,22 @@
 		cmd.ic_dlen = sizeof (ipmi_fru_read_t);
 		cmd.ic_lun = 0;
 
-		if ((resp = ipmi_send(ihp, &cmd)) == NULL)
+		if ((resp = ipmi_send(ihp, &cmd)) == NULL) {
+			free(tmp);
 			return (-1);
+		}
 
 		(void) memcpy(&count, resp->ic_data, sizeof (uint8_t));
 		if (count != cmd_data_in.ifr_count) {
 			(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH,
 			    NULL);
+			free(tmp);
 			return (-1);
 		}
-		(void) memcpy((*buf)+offset, (char *)(resp->ic_data)+1, count);
+		(void) memcpy(tmp+offset, (char *)(resp->ic_data)+1, count);
 		offset += count;
 	}
+	*buf = tmp;
 	return (sz);
 }
 
@@ -136,35 +141,35 @@
 	tmp = fru_area + (fru_hdr.ifh_product_info_off * 8) + 3;
 
 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
-	len = BITX(typelen, 4, 0);
+	len = BITX(typelen, 5, 0);
 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_manuf_name);
 	tmp += len + 1;
 
 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
-	len = BITX(typelen, 4, 0);
+	len = BITX(typelen, 5, 0);
 	ipmi_decode_string((typelen >> 6), len, tmp+1,
 	    buf->ifpi_product_name);
 	tmp += len + 1;
 
 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
-	len = BITX(typelen, 4, 0);
+	len = BITX(typelen, 5, 0);
 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_part_number);
 	tmp += len + 1;
 
 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
-	len = BITX(typelen, 4, 0);
+	len = BITX(typelen, 5, 0);
 	ipmi_decode_string((typelen >> 6), len, tmp+1,
 	    buf->ifpi_product_version);
 	tmp += len + 1;
 
 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
-	len = BITX(typelen, 4, 0);
+	len = BITX(typelen, 5, 0);
 	ipmi_decode_string((typelen >> 6), len, tmp+1,
 	    buf->ifpi_product_serial);
 	tmp += len + 1;
 
 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
-	len = BITX(typelen, 4, 0);
+	len = BITX(typelen, 5, 0);
 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_asset_tag);
 
 	return (0);
@@ -202,23 +207,23 @@
 	tmp += 3;
 
 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
-	len = BITX(typelen, 4, 0);
+	len = BITX(typelen, 5, 0);
 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_manuf_name);
 	tmp += len + 1;
 
 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
-	len = BITX(typelen, 4, 0);
+	len = BITX(typelen, 5, 0);
 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_board_name);
 	tmp += len + 1;
 
 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
-	len = BITX(typelen, 4, 0);
+	len = BITX(typelen, 5, 0);
 	ipmi_decode_string((typelen >> 6), len, tmp+1,
 	    buf->ifbi_product_serial);
 	tmp += len + 1;
 
 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
-	len = BITX(typelen, 4, 0);
+	len = BITX(typelen, 5, 0);
 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_part_number);
 
 	return (0);