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