xref: /onnv-gate/usr/src/lib/fm/topo/modules/i86pc/chip/chip_label.c (revision 8055:9d7decc340e7)
15068Srobj /*
25068Srobj  * CDDL HEADER START
35068Srobj  *
45068Srobj  * The contents of this file are subject to the terms of the
55068Srobj  * Common Development and Distribution License (the "License").
65068Srobj  * You may not use this file except in compliance with the License.
75068Srobj  *
85068Srobj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95068Srobj  * or http://www.opensolaris.org/os/licensing.
105068Srobj  * See the License for the specific language governing permissions
115068Srobj  * and limitations under the License.
125068Srobj  *
135068Srobj  * When distributing Covered Code, include this CDDL HEADER in each
145068Srobj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155068Srobj  * If applicable, add the following below this CDDL HEADER, with the
165068Srobj  * fields enclosed by brackets "[]" replaced with your own identifying
175068Srobj  * information: Portions Copyright [yyyy] [name of copyright owner]
185068Srobj  *
195068Srobj  * CDDL HEADER END
205068Srobj  */
215068Srobj 
225068Srobj /*
236292Srobj  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
245068Srobj  * Use is subject to license terms.
255068Srobj  */
265068Srobj 
275068Srobj #include <stdio.h>
285068Srobj #include <stdlib.h>
295068Srobj #include <stdarg.h>
305068Srobj #include <string.h>
315068Srobj #include <strings.h>
325068Srobj #include <libnvpair.h>
336292Srobj #include <kstat.h>
346292Srobj #include <unistd.h>
355068Srobj #include <sys/types.h>
365068Srobj #include <fm/topo_mod.h>
377532SSean.Ye@Sun.COM #include <sys/devfm.h>
387532SSean.Ye@Sun.COM #include <fm/fmd_agent.h>
395068Srobj 
405068Srobj #define	BUFSZ	128
415068Srobj 
426292Srobj char *
get_fmtstr(topo_mod_t * mod,nvlist_t * in)435590Srobj get_fmtstr(topo_mod_t *mod, nvlist_t *in)
445068Srobj {
455068Srobj 	char *fmtstr;
465068Srobj 	nvlist_t *args;
475590Srobj 	int ret;
485068Srobj 
495068Srobj 	topo_mod_dprintf(mod, "get_fmtstr() called\n");
505068Srobj 
515590Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
525068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
535590Srobj 		    strerror(ret));
545590Srobj 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
555068Srobj 		return (NULL);
565068Srobj 	}
575590Srobj 	if ((ret = nvlist_lookup_string(args, "format", &fmtstr)) != 0) {
585068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
595590Srobj 		    strerror(ret));
605590Srobj 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
615068Srobj 		return (NULL);
625068Srobj 	}
635068Srobj 	return (fmtstr);
645068Srobj }
655068Srobj 
666292Srobj int
store_prop_val(topo_mod_t * mod,char * buf,char * propname,nvlist_t ** out)675068Srobj store_prop_val(topo_mod_t *mod, char *buf, char *propname, nvlist_t **out)
685068Srobj {
695068Srobj 	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) {
705068Srobj 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
715068Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
725068Srobj 	}
735068Srobj 	if (nvlist_add_string(*out, TOPO_PROP_VAL_NAME, propname) != 0) {
745068Srobj 		topo_mod_dprintf(mod, "Failed to set '%s'\n",
755068Srobj 		    TOPO_PROP_VAL_NAME);
765068Srobj 		nvlist_free(*out);
775068Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
785068Srobj 	}
795068Srobj 	if (nvlist_add_uint32(*out, TOPO_PROP_VAL_TYPE, TOPO_TYPE_STRING)
805068Srobj 	    != 0) {
815068Srobj 		topo_mod_dprintf(mod, "Failed to set '%s'\n",
825068Srobj 		    TOPO_PROP_VAL_TYPE);
835068Srobj 		nvlist_free(*out);
845068Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
855068Srobj 	}
865068Srobj 	if (nvlist_add_string(*out, TOPO_PROP_VAL_VAL, buf) != 0) {
875068Srobj 		topo_mod_dprintf(mod, "Failed to set '%s'\n",
885068Srobj 		    TOPO_PROP_VAL_VAL);
895068Srobj 		nvlist_free(*out);
905068Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
915068Srobj 	}
925068Srobj 	return (0);
935068Srobj }
945068Srobj 
955068Srobj /*
965068Srobj  * This is a somewhat generic property method for labelling the dimm slots on
975068Srobj  * uni-socket x86/x64 platforms.  This method assumes a direct linear
985068Srobj  * correlation between the dimm topo node instance number and the dimm slot
995068Srobj  * label number.  It takes the following two arguments:
1005068Srobj  *
1015068Srobj  * format:	a string containing a printf-like format with a single %d token
1025068Srobj  *              which this method computes
1035068Srobj  *
1045068Srobj  *              i.e.: DIMM %d
1055068Srobj  *
1065068Srobj  * offset:      a numeric offset that we'll number the dimms from.  This is to
1075068Srobj  *              allow for the fact that some systems number the dimm slots
1085068Srobj  *              from zero and others start from one (like the Ultra 20)
1095068Srobj  */
1105068Srobj /* ARGSUSED */
1115068Srobj int
simple_dimm_label(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)1125068Srobj simple_dimm_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1135068Srobj     nvlist_t *in, nvlist_t **out)
1145068Srobj {
1155068Srobj 	char *fmtstr, buf[BUFSZ];
1165590Srobj 	int ret;
1175068Srobj 	uint32_t offset;
1185068Srobj 	nvlist_t *args;
1195068Srobj 
1205068Srobj 	topo_mod_dprintf(mod, "simple_dimm_label() called\n");
1215590Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
1225068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
1235590Srobj 		    strerror(ret));
1245590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1255068Srobj 	}
1265590Srobj 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
1275068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
1285590Srobj 		    strerror(ret));
1295590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1305068Srobj 	}
1315068Srobj 
1325590Srobj 	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
1335590Srobj 		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
1345590Srobj 		/* topo errno already set */
1355590Srobj 		return (-1);
1365068Srobj 	}
1375068Srobj 
1385068Srobj 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
1395068Srobj 	(void) snprintf(buf, BUFSZ, fmtstr,
1405068Srobj 	    (topo_node_instance(node) + offset));
1415068Srobj 
1425590Srobj 	if (store_prop_val(mod, buf, "label", out) != 0) {
1435068Srobj 		topo_mod_dprintf(mod, "Failed to set label\n");
1445590Srobj 		/* topo errno already set */
1455590Srobj 		return (-1);
1465068Srobj 	}
1475068Srobj 
1485068Srobj 	return (0);
1495068Srobj }
1505068Srobj 
1515068Srobj 
1525068Srobj /*
1535068Srobj  * This is a somewhat generic property method for labelling the dimm slots on
1545068Srobj  * multi-socket x86/x64 platforms.  It takes the following two arguments:
1555068Srobj  *
1565068Srobj  * format:	a string containing a printf-like format with a two %d tokens
1575068Srobj  *              for the cpu and dimm slot label numbers, which this method
1585068Srobj  *              computes
1595068Srobj  *
1605068Srobj  *              i.e.: CPU %d DIMM %d
1615068Srobj  *
1625068Srobj  * offset:      a numeric offset that we'll number the dimms from.  This is to
1635068Srobj  *              allow for the fact that some systems number the dimm slots
1645068Srobj  *              from zero while others may start from one
1655068Srobj  *
1665068Srobj  * order:	"reverse" or "forward" - sets the direction of the correlation
1675068Srobj  *              between dimm topo node instance number and DIMM slot number
1685068Srobj  *
1695068Srobj  * dimms_per_chip:  the number of DIMM slots per chip
1705068Srobj  */
1715068Srobj /* ARGSUSED */
1725068Srobj int
simple_dimm_label_mp(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)1735068Srobj simple_dimm_label_mp(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1745068Srobj     nvlist_t *in, nvlist_t **out)
1755068Srobj {
1765068Srobj 	char *fmtstr, *order, buf[BUFSZ];
1775068Srobj 	tnode_t *chip;
1785590Srobj 	int ret;
1795068Srobj 	uint32_t offset, dimms_per_chip;
1805068Srobj 	nvlist_t *args;
1815068Srobj 
1825068Srobj 	topo_mod_dprintf(mod, "simple_dimm_label_mp() called\n");
1835068Srobj 
1845590Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
1855068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
1865590Srobj 		    strerror(ret));
1875590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1885068Srobj 	}
1895590Srobj 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
1905068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
1915590Srobj 		    strerror(ret));
1925590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1935068Srobj 	}
1945590Srobj 	if ((ret = nvlist_lookup_uint32(args, "dimms_per_chip",
1955590Srobj 	    &dimms_per_chip)) != 0) {
1965068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'dimms_per_chip' arg "
1975590Srobj 		    "(%s)\n", strerror(ret));
1985590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1995068Srobj 	}
2005590Srobj 	if ((ret = nvlist_lookup_string(args, "order", &order)) != 0) {
2015068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'order' arg (%s)\n",
2025590Srobj 		    strerror(ret));
2035590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
2045068Srobj 	}
2055590Srobj 	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
2065068Srobj 		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
2075068Srobj 		topo_mod_free(mod, order, BUFSZ);
2085590Srobj 		/* topo errno already set */
2095590Srobj 		return (-1);
2105068Srobj 	}
2115068Srobj 
2125068Srobj 	chip = topo_node_parent(topo_node_parent(node));
2135068Srobj 
2145068Srobj 	if (strcasecmp(order, "forward") == 0)
2155068Srobj 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
2165068Srobj 		(void) snprintf(buf, BUFSZ, fmtstr, topo_node_instance(chip),
2175068Srobj 		    (topo_node_instance(node) + offset));
2185068Srobj 	else if (strcasecmp(order, "reverse") == 0)
2195068Srobj 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
2205068Srobj 		(void) snprintf(buf, BUFSZ, fmtstr, topo_node_instance(chip),
2215068Srobj 		    (((topo_node_instance(chip) + 1) * dimms_per_chip)
2225068Srobj 		    - (topo_node_instance(node)) - 1 + offset));
2235068Srobj 	else {
2245068Srobj 		topo_mod_dprintf(mod, "Invalid value for order arg\n");
2255068Srobj 		topo_mod_free(mod, order, BUFSZ);
2265590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
2275068Srobj 	}
2285068Srobj 
2295590Srobj 	if (store_prop_val(mod, buf, "label", out) != 0) {
2305068Srobj 		topo_mod_dprintf(mod, "Failed to set label\n");
2315068Srobj 		topo_mod_free(mod, order, BUFSZ);
2325590Srobj 		/* topo errno already set */
2335590Srobj 		return (-1);
2345068Srobj 	}
2355068Srobj 
2365068Srobj 	return (0);
2375068Srobj }
2385068Srobj 
2395068Srobj /*
2405068Srobj  * This method assumes a correspondence between the dimm topo node instance
2415068Srobj  * number and the dimm slot label number, but unlike simple_chip_label_mp, the
2425068Srobj  * slot numbers aren't reused between CPU's.  This method assumes there
2435068Srobj  * are 4 DIMM slots per chip.  It takes the following two arguments:
2445068Srobj  *
2455068Srobj  * format:	a string containing a printf-like format with a single %d token
2465068Srobj  *              which this method computes
2475068Srobj  *
2485068Srobj  *              i.e.: DIMM %d
2495068Srobj  *
2505068Srobj  * offset:      a numeric offset that we'll number the dimms from.  This is to
2515068Srobj  *              allow for the fact that some systems number the dimm slots
2525068Srobj  *              from zero and others may start from one
2535068Srobj  *
2545068Srobj  * order:	"reverse" or "forward" - sets the direction of the correlation
2555068Srobj  *              between dimm topo node instance number and DIMM slot number
2565068Srobj  */
2575068Srobj /* ARGSUSED */
2585068Srobj int
seq_dimm_label(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)2595068Srobj seq_dimm_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
2605068Srobj     nvlist_t *in, nvlist_t **out)
2615068Srobj {
2625068Srobj 	char *fmtstr, *order, buf[BUFSZ];
2635590Srobj 	int ret;
2645068Srobj 	uint32_t offset;
2655068Srobj 	nvlist_t *args;
2665068Srobj 	tnode_t *chip;
2675068Srobj 
2685068Srobj 	topo_mod_dprintf(mod, "seq_dimm_label() called\n");
2695590Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
2705068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
2715590Srobj 		    strerror(ret));
2725590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
2735068Srobj 	}
2745590Srobj 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
2755068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
2765590Srobj 		    strerror(ret));
2775590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
2785068Srobj 	}
2795590Srobj 	if ((ret = nvlist_lookup_string(args, "order", &order)) != 0) {
2805068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'order' arg (%s)\n",
2815590Srobj 		    strerror(ret));
2825590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
2835068Srobj 	}
2845068Srobj 
2855590Srobj 	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
2865590Srobj 		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
2875068Srobj 		topo_mod_free(mod, order, BUFSZ);
2885590Srobj 		/* topo errno already set */
2895590Srobj 		return (-1);
2905068Srobj 	}
2915068Srobj 
2925068Srobj 	chip = topo_node_parent(topo_node_parent(node));
2935068Srobj 
2945068Srobj 	if (strcasecmp(order, "forward") == 0)
2955068Srobj 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
2965068Srobj 		(void) snprintf(buf, BUFSZ, fmtstr, ((topo_node_instance(node))
2975068Srobj 		    + (topo_node_instance(chip) * 4) + offset));
2985068Srobj 	else if (strcasecmp(order, "reverse") == 0)
2995068Srobj 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
3005068Srobj 		(void) snprintf(buf, BUFSZ, fmtstr,
3015068Srobj 		    (((topo_node_instance(chip) + 1) * 4)
3025068Srobj 		    - (topo_node_instance(node)) - 1 + offset));
3035068Srobj 	else {
3045068Srobj 		topo_mod_dprintf(mod, "Invalid value for order arg\n");
3055068Srobj 		topo_mod_free(mod, order, BUFSZ);
3065590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
3075068Srobj 	}
3085068Srobj 
3095590Srobj 	if (store_prop_val(mod, buf, "label", out) != 0) {
3105068Srobj 		topo_mod_dprintf(mod, "Failed to set label\n");
3115068Srobj 		topo_mod_free(mod, order, BUFSZ);
3125590Srobj 		/* topo errno already set */
3135590Srobj 		return (-1);
3145068Srobj 	}
3155068Srobj 
3165068Srobj 	return (0);
3175068Srobj }
3185068Srobj 
3195068Srobj 
3205068Srobj /*
3215068Srobj  * This is a somewhat generic property method for labelling the CPU sockets on
3225068Srobj  * x86/x64 platforms.  This method assumes a correspondence between
3235068Srobj  * the chip topo node instance number and the CPU socket label number.  It takes
3245068Srobj  * the following two arguments:
3255068Srobj  *
3265068Srobj  * format:	a string containing a printf-like format with a single %d token
3275068Srobj  *              which this method computes
3285068Srobj  *
3295068Srobj  *              i.e.: CPU %d
3305068Srobj  *
3315068Srobj  * offset:      a numeric offset that we'll number the CPU's from.  This is to
3325068Srobj  *              allow for the fact that some systems number the CPU sockets
3335068Srobj  *              from zero and others start from one (like the X4X00-M2 systems)
3345068Srobj  */
3355068Srobj /* ARGSUSED */
3365068Srobj int
simple_chip_label(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)3375068Srobj simple_chip_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
3385068Srobj     nvlist_t *in, nvlist_t **out)
3395068Srobj {
3405068Srobj 	char *fmtstr, buf[BUFSZ];
3415590Srobj 	int ret;
3425068Srobj 	uint32_t offset;
3435068Srobj 	nvlist_t *args;
3445068Srobj 
3455068Srobj 	topo_mod_dprintf(mod, "simple_chip_label() called\n");
3465590Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
3475068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
3485590Srobj 		    strerror(ret));
3495590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
3505068Srobj 	}
3515590Srobj 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
3525068Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
3535590Srobj 		    strerror(ret));
3545590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
3555068Srobj 	}
3565068Srobj 
3575590Srobj 	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
3585590Srobj 		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
3595590Srobj 		/* topo errno already set */
3605590Srobj 		return (-1);
3615068Srobj 	}
3625068Srobj 
3635068Srobj 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
3645068Srobj 	(void) snprintf(buf, BUFSZ, fmtstr,
3655068Srobj 	    (topo_node_instance(node) + offset));
3665068Srobj 
3675590Srobj 	if (store_prop_val(mod, buf, "label", out) != 0) {
3685068Srobj 		topo_mod_dprintf(mod, "Failed to set label\n");
3695590Srobj 		/* topo errno already set */
3705590Srobj 		return (-1);
3715068Srobj 	}
3725068Srobj 
3735068Srobj 	return (0);
3745068Srobj }
3755068Srobj 
3765068Srobj 
3775068Srobj /*
378*8055SAdrian.Frost@Sun.COM  * This is a somewhat generic property method for labelling the CPU sockets on
379*8055SAdrian.Frost@Sun.COM  * x86/x64 platforms.  This method assumes a correspondence between
380*8055SAdrian.Frost@Sun.COM  * the chip topo node instance number and the CPU socket label number.  It takes
381*8055SAdrian.Frost@Sun.COM  * the following argument:
382*8055SAdrian.Frost@Sun.COM  *
383*8055SAdrian.Frost@Sun.COM  * format:	a string containing a printf-like format with a single %d token
384*8055SAdrian.Frost@Sun.COM  *              which this method computes
385*8055SAdrian.Frost@Sun.COM  *
386*8055SAdrian.Frost@Sun.COM  *              i.e.: CPU %d
387*8055SAdrian.Frost@Sun.COM  *
388*8055SAdrian.Frost@Sun.COM  * offset:      a numeric offset that we'll number the CPU's from.  This is to
389*8055SAdrian.Frost@Sun.COM  *              allow for the fact that some systems number the CPU sockets
390*8055SAdrian.Frost@Sun.COM  *              from zero and others start from one (like the X8450 systems)
391*8055SAdrian.Frost@Sun.COM  */
392*8055SAdrian.Frost@Sun.COM /* ARGSUSED */
393*8055SAdrian.Frost@Sun.COM int
fsb2_chip_label(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)394*8055SAdrian.Frost@Sun.COM fsb2_chip_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
395*8055SAdrian.Frost@Sun.COM     nvlist_t *in, nvlist_t **out)
396*8055SAdrian.Frost@Sun.COM {
397*8055SAdrian.Frost@Sun.COM 	char *fmtstr, buf[BUFSZ];
398*8055SAdrian.Frost@Sun.COM 	int ret;
399*8055SAdrian.Frost@Sun.COM 	uint32_t offset;
400*8055SAdrian.Frost@Sun.COM 	nvlist_t *args;
401*8055SAdrian.Frost@Sun.COM 
402*8055SAdrian.Frost@Sun.COM 	topo_mod_dprintf(mod, "fsb2_chip_label() called\n");
403*8055SAdrian.Frost@Sun.COM 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
404*8055SAdrian.Frost@Sun.COM 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
405*8055SAdrian.Frost@Sun.COM 		    strerror(ret));
406*8055SAdrian.Frost@Sun.COM 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
407*8055SAdrian.Frost@Sun.COM 	}
408*8055SAdrian.Frost@Sun.COM 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
409*8055SAdrian.Frost@Sun.COM 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
410*8055SAdrian.Frost@Sun.COM 		    strerror(ret));
411*8055SAdrian.Frost@Sun.COM 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
412*8055SAdrian.Frost@Sun.COM 	}
413*8055SAdrian.Frost@Sun.COM 
414*8055SAdrian.Frost@Sun.COM 	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
415*8055SAdrian.Frost@Sun.COM 		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
416*8055SAdrian.Frost@Sun.COM 		/* topo errno already set */
417*8055SAdrian.Frost@Sun.COM 		return (-1);
418*8055SAdrian.Frost@Sun.COM 	}
419*8055SAdrian.Frost@Sun.COM 
420*8055SAdrian.Frost@Sun.COM 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
421*8055SAdrian.Frost@Sun.COM 	(void) snprintf(buf, BUFSZ, fmtstr,
422*8055SAdrian.Frost@Sun.COM 	    ((topo_node_instance(node) / 2) + offset));
423*8055SAdrian.Frost@Sun.COM 
424*8055SAdrian.Frost@Sun.COM 	if (store_prop_val(mod, buf, "label", out) != 0) {
425*8055SAdrian.Frost@Sun.COM 		topo_mod_dprintf(mod, "Failed to set label\n");
426*8055SAdrian.Frost@Sun.COM 		/* topo errno already set */
427*8055SAdrian.Frost@Sun.COM 		return (-1);
428*8055SAdrian.Frost@Sun.COM 	}
429*8055SAdrian.Frost@Sun.COM 
430*8055SAdrian.Frost@Sun.COM 	return (0);
431*8055SAdrian.Frost@Sun.COM }
432*8055SAdrian.Frost@Sun.COM 
433*8055SAdrian.Frost@Sun.COM 
434*8055SAdrian.Frost@Sun.COM /*
4355068Srobj  * This is a custom property method for generating the CPU slot label for the
4365068Srobj  * Galaxy 4E/4F platforms.
4375068Srobj  *
4385068Srobj  * format:	a string containing a printf-like format with a single %c token
4395068Srobj  *              which this method computes
4405068Srobj  *
4415068Srobj  *              i.e.: CPU %c
4425068Srobj  */
4435068Srobj /* ARGSUSED */
4445068Srobj int
g4_chip_label(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)4455068Srobj g4_chip_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
4465068Srobj     nvlist_t *in, nvlist_t **out)
4475068Srobj {
4485068Srobj 	char *fmtstr, buf[BUFSZ], slot_id;
4495068Srobj 	int err, htid, mapidx;
4505068Srobj 	uint32_t num_nodes;
4515068Srobj 	/*
4525068Srobj 	 * G4 HT node ID to FRU label translation.  The g4map array
4535068Srobj 	 * is indexed by (number of coherent nodes) / 2 - 1.
4545068Srobj 	 * The value for a given number of nodes is a char array
4555068Srobj 	 * indexed by node ID.
4565068Srobj 	 */
4575068Srobj 	const char *g4map[] = {
4585068Srobj 	    "AB",	/* 2 nodes */
4595068Srobj 	    "ADEH",	/* 4 nodes */
4605068Srobj 	    "ABDEFH",	/* 6 nodes */
4615068Srobj 	    "ACBDEFGH"	/* 8 nodes */
4625068Srobj 	};
4635068Srobj 
4645068Srobj 	topo_mod_dprintf(mod, "g4_chip_label() called\n");
4655590Srobj 	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
4665068Srobj 		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
4675590Srobj 		/* topo errno already set */
4685590Srobj 		return (-1);
4695068Srobj 	}
4705590Srobj 	/*
4715590Srobj 	 * The chip-properties property will not exist if this platform has
4725590Srobj 	 * AMD family 0x10 modules.  In that case we don't want to treat it as a
4735590Srobj 	 * fatal error as that will cause calls like topo_prop_getprops to fail
4745590Srobj 	 * to return any properties on this node.  Therefore, if the topo errno
4755590Srobj 	 * is set to ETOPO_PROP_NOENT, then we'll just set an empty label
4765590Srobj 	 * and return 0.  If the topo errno is set to anything else we'll
4775590Srobj 	 * return -1.
4785590Srobj 	 */
4795068Srobj 	if (topo_prop_get_uint32(node, "chip-properties", "CoherentNodes",
4805068Srobj 	    &num_nodes, &err) != 0) {
4815590Srobj 		if (err == ETOPO_PROP_NOENT) {
4825590Srobj 			if (store_prop_val(mod, "", "label", out) != 0) {
4835590Srobj 				topo_mod_dprintf(mod, "Failed to set label\n");
4845590Srobj 				/* topo errno already set */
4855590Srobj 				return (-1);
4865590Srobj 			}
4875590Srobj 			return (0);
4885590Srobj 		} else {
4895590Srobj 			topo_mod_dprintf(mod, "Failed to lookup 'CoherentNodes'"
4905590Srobj 			    "property\n");
4915590Srobj 			return (topo_mod_seterrno(mod, err));
4925590Srobj 		}
4935068Srobj 	}
4945068Srobj 
4955068Srobj 	mapidx = num_nodes / 2 - 1;
4965068Srobj 	htid = topo_node_instance(node);
4975068Srobj 
4985068Srobj 	/* HT nodes must number 0 .. num_nodes - 1 */
4995068Srobj 	if (htid >= num_nodes) {
5005068Srobj 		topo_mod_dprintf(mod, "chip node instance range check failed:"
5015068Srobj 		    "num_nodes=%d, instance=%d\n", num_nodes, htid);
5025068Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
5035068Srobj 	}
5045068Srobj 
5055068Srobj 	switch (num_nodes) {
5065068Srobj 		case (2):
5075068Srobj 		case (4):
5085068Srobj 		case (6):
5095068Srobj 		case (8):
5105068Srobj 			/* htid is already range-checked */
5115068Srobj 			mapidx = num_nodes / 2 - 1;
5125068Srobj 			slot_id = g4map[mapidx][htid];
5135068Srobj 			break;
5145068Srobj 		default:
5155068Srobj 			topo_mod_dprintf(mod, "Invalid number of CoherentNodes:"
5165068Srobj 			    " %d\n", num_nodes);
5175068Srobj 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
5185068Srobj 	}
5195068Srobj 
5205068Srobj 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
5215068Srobj 	(void) snprintf(buf, BUFSZ, fmtstr, slot_id);
5225068Srobj 
5235590Srobj 	if (store_prop_val(mod, buf, "label", out) != 0) {
5245068Srobj 		topo_mod_dprintf(mod, "Failed to set label\n");
5255590Srobj 		/* topo errno already set */
5265590Srobj 		return (-1);
5275068Srobj 	}
5285068Srobj 
5295068Srobj 	return (0);
5305068Srobj }
5315590Srobj 
5325590Srobj /*
5336292Srobj  * Utility function used by a4fplus_chip_label to determine the number of chips
5347532SSean.Ye@Sun.COM  * (as opposed to processors) that are installed in the system by counting
5357532SSean.Ye@Sun.COM  * the unique chipids.
5366292Srobj  */
5376292Srobj static int
get_num_chips(topo_mod_t * mod)5386292Srobj get_num_chips(topo_mod_t *mod)
5396292Srobj {
5407532SSean.Ye@Sun.COM 	fmd_agent_hdl_t *hdl;
5417532SSean.Ye@Sun.COM 	nvlist_t **cpus;
5427532SSean.Ye@Sun.COM 	uint_t ncpu;
5437532SSean.Ye@Sun.COM 	int i, nchip = 0;
5447532SSean.Ye@Sun.COM 	int32_t chipid;
5457532SSean.Ye@Sun.COM 	uint64_t bitmap = 0;
5466292Srobj 
5477532SSean.Ye@Sun.COM 	if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL)
5486292Srobj 		return (-1);
5497532SSean.Ye@Sun.COM 	if (fmd_agent_physcpu_info(hdl, &cpus, &ncpu) == -1) {
5507532SSean.Ye@Sun.COM 		topo_mod_dprintf(mod, "get physcpu info failed:%s\n",
5517532SSean.Ye@Sun.COM 		    fmd_agent_errmsg(hdl));
5527532SSean.Ye@Sun.COM 		fmd_agent_close(hdl);
5536292Srobj 		return (-1);
5546292Srobj 	}
5557532SSean.Ye@Sun.COM 	fmd_agent_close(hdl);
5567532SSean.Ye@Sun.COM 
5577532SSean.Ye@Sun.COM 	for (i = 0; i < ncpu; i++) {
5587532SSean.Ye@Sun.COM 		if (nvlist_lookup_int32(cpus[i], FM_PHYSCPU_INFO_CHIP_ID,
5597532SSean.Ye@Sun.COM 		    &chipid) != 0 || chipid >= 64) {
5607532SSean.Ye@Sun.COM 			topo_mod_dprintf(mod, "lookup chipid failed\n");
5617532SSean.Ye@Sun.COM 			nchip = -1;
5627532SSean.Ye@Sun.COM 			break;
5637532SSean.Ye@Sun.COM 		}
5647532SSean.Ye@Sun.COM 		if ((bitmap & (1 << chipid)) != 0) {
5657532SSean.Ye@Sun.COM 			bitmap |= (1 << chipid);
5667532SSean.Ye@Sun.COM 			nchip++;
5677532SSean.Ye@Sun.COM 		}
5686292Srobj 	}
5697532SSean.Ye@Sun.COM 
5707532SSean.Ye@Sun.COM 	for (i = 0; i < ncpu; i++)
5717532SSean.Ye@Sun.COM 		nvlist_free(cpus[i]);
5727532SSean.Ye@Sun.COM 	umem_free(cpus, sizeof (nvlist_t *) * ncpu);
5737532SSean.Ye@Sun.COM 
5747532SSean.Ye@Sun.COM 	return (nchip);
5756292Srobj }
5766292Srobj 
5776292Srobj /*
5786292Srobj  * This is a custom property method for generating the CPU slot label for the
5796292Srobj  * Andromeda Fplus platforms.
5806292Srobj  *
5816292Srobj  * format:	a string containing a printf-like format with a single %d token
5826292Srobj  *              which this method computes
5836292Srobj  *
5846292Srobj  *              i.e.: CPU %d
5856292Srobj  */
5866292Srobj /* ARGSUSED */
5876292Srobj int
a4fplus_chip_label(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)5886292Srobj a4fplus_chip_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
5896292Srobj     nvlist_t *in, nvlist_t **out)
5906292Srobj {
5916292Srobj 	char *fmtstr, buf[BUFSZ];
5926292Srobj 	int num_nodes;
5936292Srobj 
5946292Srobj 	topo_mod_dprintf(mod, "a4fplus_chip_label() called\n");
5956292Srobj 	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
5966292Srobj 		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
5976292Srobj 		/* topo errno already set */
5986292Srobj 		return (-1);
5996292Srobj 	}
6006292Srobj 
6016292Srobj 	/*
6026292Srobj 	 * Normally we'd figure out the total number of chip nodes by looking
6036292Srobj 	 * at the CoherentNodes property.  However, due to the lack of a memory
6046292Srobj 	 * controller driver for family 0x10, this property wont exist on the
6056292Srobj 	 * chip nodes on A4Fplus.
6066292Srobj 	 */
6076292Srobj 	if ((num_nodes = get_num_chips(mod)) < 0) {
6086292Srobj 		topo_mod_dprintf(mod, "Failed to determine number of chip "
6096292Srobj 		    "nodes\n");
6106292Srobj 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
6116292Srobj 	}
6126292Srobj 	switch (num_nodes) {
6136292Srobj 		case (2):
6146292Srobj 			/* LINTED: E_SEC_PRINTF_VAR_FMT */
6156292Srobj 			(void) snprintf(buf, BUFSZ, fmtstr,
6166292Srobj 			    topo_node_instance(node) + 2);
6176292Srobj 			break;
6186292Srobj 		case (4):
6196292Srobj 			/* LINTED: E_SEC_PRINTF_VAR_FMT */
6206292Srobj 			(void) snprintf(buf, BUFSZ, fmtstr,
6216292Srobj 			    topo_node_instance(node));
6226292Srobj 			break;
6236292Srobj 		default:
6246292Srobj 			topo_mod_dprintf(mod, "Invalid number of chip nodes:"
6256292Srobj 			    " %d\n", num_nodes);
6266292Srobj 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
6276292Srobj 	}
6286292Srobj 
6296292Srobj 
6306292Srobj 	if (store_prop_val(mod, buf, "label", out) != 0) {
6316292Srobj 		topo_mod_dprintf(mod, "Failed to set label\n");
6326292Srobj 		/* topo errno already set */
6336292Srobj 		return (-1);
6346292Srobj 	}
6356292Srobj 
6366292Srobj 	return (0);
6376292Srobj }
6386292Srobj 
6396292Srobj /*
6405590Srobj  * This is a somewhat generic property method for labelling the chip-select
6415590Srobj  * nodes on multi-socket AMD family 0x10 platforms.  This is necessary because
6425590Srobj  * these platforms are not supported by the current AMD memory controller driver
6435590Srobj  * and therefore we're not able to discover the memory topology on AMD family
6445590Srobj  * 0x10 systems.  As a result, instead of enumerating the installed dimms and
6455590Srobj  * their ranks, the chip enumerator generically enumerates all of the possible
6465590Srobj  * chip-selects beneath each dram channel.
6475590Srobj  *
6485590Srobj  * When we diagnose a dimm fault, the FRU fmri will be for the chip-select node,
6495590Srobj  * so we need to attach FRU labels to the chip-select nodes.
6505590Srobj  *
6515590Srobj  * format:	a string containing a printf-like format with a two %d tokens
6525590Srobj  *              for the cpu and dimm slot label numbers, which this method
6535590Srobj  *              computes
6545590Srobj  *
6555590Srobj  *              i.e.: CPU %d DIMM %d
6565590Srobj  *
6575590Srobj  * offset:      a numeric offset that we'll number the dimms from.  This is to
6585590Srobj  *              allow for the fact that some systems may number the dimm slots
6595590Srobj  *              from zero while others may start from one
6605590Srobj  *
6615590Srobj  * This function computes the DIMM slot number using the following formula:
6625590Srobj  *
6635590Srobj  * 	slot = cs - (cs % 2) + channel + offset
6645590Srobj  */
6655590Srobj /* ARGSUSED */
6665590Srobj int
simple_cs_label_mp(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)6675590Srobj simple_cs_label_mp(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
6685590Srobj     nvlist_t *in, nvlist_t **out)
6695590Srobj {
6705590Srobj 	char *fmtstr, buf[BUFSZ];
6715590Srobj 	tnode_t *chip, *chan;
6725590Srobj 	int dimm_num, ret;
6735590Srobj 	uint32_t offset;
6745590Srobj 	nvlist_t *args;
6755590Srobj 
6765590Srobj 	topo_mod_dprintf(mod, "simple_cs_label_mp() called\n");
6775590Srobj 
6785590Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
6795590Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
6805590Srobj 		    strerror(ret));
6815590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
6825590Srobj 	}
6835590Srobj 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
6845590Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
6855590Srobj 		    strerror(ret));
6865590Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
6875590Srobj 	}
6885590Srobj 	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
6895590Srobj 		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
6905590Srobj 		/* topo errno already set */
6915590Srobj 		return (-1);
6925590Srobj 	}
6935590Srobj 
6945590Srobj 	chip = topo_node_parent(topo_node_parent(topo_node_parent(node)));
6955590Srobj 	chan = topo_node_parent(node);
6965590Srobj 
6975590Srobj 	dimm_num = topo_node_instance(node) - (topo_node_instance(node) % 2)
6985590Srobj 	    + topo_node_instance(chan) + offset;
6995590Srobj 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
7005590Srobj 	(void) snprintf(buf, BUFSZ, fmtstr, topo_node_instance(chip),
7015590Srobj 	    dimm_num);
7025590Srobj 
7035590Srobj 	if (store_prop_val(mod, buf, "label", out) != 0) {
7045590Srobj 		topo_mod_dprintf(mod, "Failed to set label\n");
7055590Srobj 		/* topo errno already set */
7065590Srobj 		return (-1);
7075590Srobj 	}
7085590Srobj 
7095590Srobj 	return (0);
7105590Srobj }
7116292Srobj 
7126292Srobj /* ARGSUSED */
7136292Srobj int
g4_dimm_label(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)7146292Srobj g4_dimm_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
7156292Srobj     nvlist_t *in, nvlist_t **out)
7166292Srobj {
7176292Srobj 	char *fmtstr, *chip_lbl, buf[BUFSZ];
7186292Srobj 	tnode_t *chip;
7196292Srobj 	int ret, err = 0;
7206292Srobj 	uint32_t offset;
7216292Srobj 	nvlist_t *args;
7226292Srobj 
7236292Srobj 	topo_mod_dprintf(mod, "g4_dimm_label() called\n");
7246292Srobj 
7256292Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
7266292Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
7276292Srobj 		    strerror(ret));
7286292Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
7296292Srobj 	}
7306292Srobj 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
7316292Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
7326292Srobj 		    strerror(ret));
7336292Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
7346292Srobj 	}
7356292Srobj 	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
7366292Srobj 		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
7376292Srobj 		/* topo errno already set */
7386292Srobj 		return (-1);
7396292Srobj 	}
7406292Srobj 
7416292Srobj 	/*
7426292Srobj 	 * The 4600/4600M2 have a weird way of labeling the chip nodes, so
7436292Srobj 	 * instead of trying to recompute it, we'll simply look it up and
7446292Srobj 	 * prepend it to our dimm label.
7456292Srobj 	 */
7466292Srobj 	chip = topo_node_parent(topo_node_parent(node));
7476292Srobj 	if (topo_prop_get_string(chip, TOPO_PGROUP_PROTOCOL, "label", &chip_lbl,
7486292Srobj 	    &err) != 0) {
7496292Srobj 		topo_mod_dprintf(mod, "Failed to lookup label prop on %s=%d\n",
7506292Srobj 		    topo_node_name(chip), topo_node_instance(chip),
7516292Srobj 		    topo_strerror(err));
7526292Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
7536292Srobj 	}
7546292Srobj 
7556292Srobj 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
7566292Srobj 	(void) snprintf(buf, BUFSZ, fmtstr, chip_lbl,
7576292Srobj 	    (topo_node_instance(node) + offset));
7586292Srobj 
7596292Srobj 	topo_mod_strfree(mod, chip_lbl);
7606292Srobj 
7616292Srobj 	if (store_prop_val(mod, buf, "label", out) != 0) {
7626292Srobj 		topo_mod_dprintf(mod, "Failed to set label\n");
7636292Srobj 		/* topo errno already set */
7646292Srobj 		return (-1);
7656292Srobj 	}
7666292Srobj 
7676292Srobj 	return (0);
7686292Srobj }
7696360Srobj 
7706360Srobj /*
7716360Srobj  * This method is used to compute the labels for DIMM slots on the Galaxy 1F and
7726360Srobj  * 2F platforms.  It results in following dimm node label assignments:
7736360Srobj  *
7746360Srobj  * chip/dimm instances      label
7756360Srobj  * -------------------      -----
7766360Srobj  * chip=0/dimm=0            CPU 1 DIMM A0
7776360Srobj  * chip=0/dimm=1            CPU 1 DIMM B0
7786360Srobj  * chip=0/dimm=2            CPU 1 DIMM A1
7796360Srobj  * chip=0/dimm=3            CPU 1 DIMM B1
7806360Srobj  *
7816360Srobj  * chip=1/dimm=0            CPU 2 DIMM A0
7826360Srobj  * chip=1/dimm=1            CPU 2 DIMM B0
7836360Srobj  * chip=1/dimm=2            CPU 2 DIMM A1
7846360Srobj  * chip=1/dimm=3            CPU 2 DIMM B1
7856360Srobj  */
7866360Srobj /* ARGSUSED */
7876360Srobj int
g12f_dimm_label(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)7886360Srobj g12f_dimm_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
7896360Srobj     nvlist_t *in, nvlist_t **out)
7906360Srobj {
7916360Srobj 	char *fmtstr, buf[BUFSZ], chan;
7926360Srobj 	tnode_t *chip;
7936360Srobj 	int ret, dimm_inst, slot_num;
7946360Srobj 	nvlist_t *args;
7956360Srobj 
7966360Srobj 	topo_mod_dprintf(mod, "g12f_dimm_label() called\n");
7976360Srobj 
7986360Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
7996360Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
8006360Srobj 		    strerror(ret));
8016360Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
8026360Srobj 	}
8036360Srobj 	if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
8046360Srobj 		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
8056360Srobj 		/* topo errno already set */
8066360Srobj 		return (-1);
8076360Srobj 	}
8086360Srobj 
8096360Srobj 	chip = topo_node_parent(topo_node_parent(node));
8106360Srobj 	dimm_inst = topo_node_instance(node);
8116360Srobj 	chan = dimm_inst == 0 || dimm_inst == 2 ? 'A': 'B';
8126360Srobj 	slot_num = (dimm_inst <= 1 ? 0 : 1);
8136360Srobj 
8146360Srobj 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
8156360Srobj 	(void) snprintf(buf, BUFSZ, fmtstr, topo_node_instance(chip) + 1, chan,
8166360Srobj 	    slot_num);
8176360Srobj 
8186360Srobj 	if (store_prop_val(mod, buf, "label", out) != 0) {
8196360Srobj 		topo_mod_dprintf(mod, "Failed to set label\n");
8206360Srobj 		/* topo errno already set */
8216360Srobj 		return (-1);
8226360Srobj 	}
8236360Srobj 
8246360Srobj 	return (0);
8256360Srobj }
826