120c794b3Sgavinm /*
220c794b3Sgavinm  * CDDL HEADER START
320c794b3Sgavinm  *
420c794b3Sgavinm  * The contents of this file are subject to the terms of the
520c794b3Sgavinm  * Common Development and Distribution License (the "License").
620c794b3Sgavinm  * You may not use this file except in compliance with the License.
720c794b3Sgavinm  *
820c794b3Sgavinm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
920c794b3Sgavinm  * or http://www.opensolaris.org/os/licensing.
1020c794b3Sgavinm  * See the License for the specific language governing permissions
1120c794b3Sgavinm  * and limitations under the License.
1220c794b3Sgavinm  *
1320c794b3Sgavinm  * When distributing Covered Code, include this CDDL HEADER in each
1420c794b3Sgavinm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1520c794b3Sgavinm  * If applicable, add the following below this CDDL HEADER, with the
1620c794b3Sgavinm  * fields enclosed by brackets "[]" replaced with your own identifying
1720c794b3Sgavinm  * information: Portions Copyright [yyyy] [name of copyright owner]
1820c794b3Sgavinm  *
1920c794b3Sgavinm  * CDDL HEADER END
2020c794b3Sgavinm  */
2120c794b3Sgavinm 
2220c794b3Sgavinm /*
236e1fa242SStephen Hanson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2420c794b3Sgavinm  * Use is subject to license terms.
25f2dbfd32SRobert Mustacchi  * Copyright 2019, Joyent, Inc.
26*d0caeb89SRobert Mustacchi  * Copyright 2020 Oxide Computer Company
2720c794b3Sgavinm  */
2820c794b3Sgavinm 
2920c794b3Sgavinm /*
3020c794b3Sgavinm  * Support function for the i86pc chip enumerator
3120c794b3Sgavinm  */
3220c794b3Sgavinm 
3320c794b3Sgavinm #include <sys/types.h>
3420c794b3Sgavinm #include <stdarg.h>
3520c794b3Sgavinm #include <strings.h>
3625c6ff4bSstephh #include <fm/fmd_fmri.h>
37e4b86885SCheng Sean Ye #include <sys/systeminfo.h>
3820c794b3Sgavinm #include <sys/fm/protocol.h>
39e4b86885SCheng Sean Ye #include <fm/topo_mod.h>
40e4b86885SCheng Sean Ye #include <fm/fmd_agent.h>
4120c794b3Sgavinm 
4220c794b3Sgavinm #include "chip.h"
4320c794b3Sgavinm 
441db96d3bSCheng Sean Ye static void fmri_dprint(topo_mod_t *, const char *, uint32_t, nvlist_t *);
451db96d3bSCheng Sean Ye static boolean_t is_page_fmri(nvlist_t *);
461db96d3bSCheng Sean Ye 
4720c794b3Sgavinm /*
4820c794b3Sgavinm  * Whinge a debug message via topo_mod_dprintf and increment the
4920c794b3Sgavinm  * given error counter.
5020c794b3Sgavinm  */
5120c794b3Sgavinm void
whinge(topo_mod_t * mod,int * nerr,const char * fmt,...)5220c794b3Sgavinm whinge(topo_mod_t *mod, int *nerr, const char *fmt, ...)
5320c794b3Sgavinm {
5420c794b3Sgavinm 	va_list ap;
5520c794b3Sgavinm 	char buf[160];
5620c794b3Sgavinm 
5720c794b3Sgavinm 	if (nerr != NULL)
5820c794b3Sgavinm 		++*nerr;
5920c794b3Sgavinm 
6020c794b3Sgavinm 	va_start(ap, fmt);
6120c794b3Sgavinm 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
6220c794b3Sgavinm 	va_end(ap);
6320c794b3Sgavinm 
6420c794b3Sgavinm 	topo_mod_dprintf(mod, "%s", buf);
6520c794b3Sgavinm }
6620c794b3Sgavinm 
6720c794b3Sgavinm /*
6820c794b3Sgavinm  * Given an nvpair of a limited number of data types, extract the property
6920c794b3Sgavinm  * name and value and add that combination to the given node in the
7020c794b3Sgavinm  * specified property group using the corresponding topo_prop_set_* function
7120c794b3Sgavinm  * for the data type.  Return 1 on success, otherwise 0.
7220c794b3Sgavinm  */
7320c794b3Sgavinm int
nvprop_add(topo_mod_t * mod,nvpair_t * nvp,const char * pgname,tnode_t * node)7420c794b3Sgavinm nvprop_add(topo_mod_t *mod, nvpair_t *nvp, const char *pgname, tnode_t *node)
7520c794b3Sgavinm {
7620c794b3Sgavinm 	int success = 0;
7720c794b3Sgavinm 	int err;
7820c794b3Sgavinm 	char *pname = nvpair_name(nvp);
7920c794b3Sgavinm 
8020c794b3Sgavinm 	switch (nvpair_type(nvp)) {
8120c794b3Sgavinm 	case DATA_TYPE_BOOLEAN_VALUE: {
8220c794b3Sgavinm 		boolean_t val;
8320c794b3Sgavinm 
8420c794b3Sgavinm 		if (nvpair_value_boolean_value(nvp, &val) == 0 &&
8520c794b3Sgavinm 		    topo_prop_set_string(node, pgname, pname,
8620c794b3Sgavinm 		    TOPO_PROP_IMMUTABLE, val ? "true" : "false", &err) == 0)
8720c794b3Sgavinm 			success = 1;
8820c794b3Sgavinm 		break;
8920c794b3Sgavinm 	}
9020c794b3Sgavinm 
9120c794b3Sgavinm 	case DATA_TYPE_UINT32: {
9220c794b3Sgavinm 		uint32_t val;
9320c794b3Sgavinm 
9420c794b3Sgavinm 		if (nvpair_value_uint32(nvp, &val) == 0 &&
9520c794b3Sgavinm 		    topo_prop_set_uint32(node, pgname, pname,
9620c794b3Sgavinm 		    TOPO_PROP_IMMUTABLE, val, &err) == 0)
9720c794b3Sgavinm 			success = 1;
9820c794b3Sgavinm 		break;
9920c794b3Sgavinm 	}
10020c794b3Sgavinm 
10120c794b3Sgavinm 	case DATA_TYPE_UINT64: {
10220c794b3Sgavinm 		uint64_t val;
10320c794b3Sgavinm 
10420c794b3Sgavinm 		if (nvpair_value_uint64(nvp, &val) == 0 &&
10520c794b3Sgavinm 		    topo_prop_set_uint64(node, pgname, pname,
10620c794b3Sgavinm 		    TOPO_PROP_IMMUTABLE, val, &err) == 0)
10720c794b3Sgavinm 			success = 1;
10820c794b3Sgavinm 		break;
10920c794b3Sgavinm 	}
11020c794b3Sgavinm 
11120c794b3Sgavinm 	case DATA_TYPE_UINT32_ARRAY: {
11220c794b3Sgavinm 		uint32_t *arrp;
11320c794b3Sgavinm 		uint_t nelem;
11420c794b3Sgavinm 
11520c794b3Sgavinm 		if (nvpair_value_uint32_array(nvp, &arrp, &nelem) == 0 &&
11620c794b3Sgavinm 		    nelem > 0 && topo_prop_set_uint32_array(node, pgname, pname,
11720c794b3Sgavinm 		    TOPO_PROP_IMMUTABLE, arrp, nelem, &err) == 0)
11820c794b3Sgavinm 			success = 1;
11920c794b3Sgavinm 		break;
12020c794b3Sgavinm 	}
12120c794b3Sgavinm 
12220c794b3Sgavinm 	case DATA_TYPE_STRING: {
12320c794b3Sgavinm 		char *str;
12420c794b3Sgavinm 
12520c794b3Sgavinm 		if (nvpair_value_string(nvp, &str) == 0 &&
12620c794b3Sgavinm 		    topo_prop_set_string(node, pgname, pname,
12720c794b3Sgavinm 		    TOPO_PROP_IMMUTABLE, str, &err) == 0)
12820c794b3Sgavinm 			success = 1;
12920c794b3Sgavinm 		break;
13020c794b3Sgavinm 	}
13120c794b3Sgavinm 
13220c794b3Sgavinm 	default:
13320c794b3Sgavinm 		whinge(mod, &err, "nvprop_add: Can't handle type %d for "
13420c794b3Sgavinm 		    "'%s' in property group %s of %s node\n",
13520c794b3Sgavinm 		    nvpair_type(nvp), pname, pgname, topo_node_name(node));
13620c794b3Sgavinm 		break;
13720c794b3Sgavinm 	}
13820c794b3Sgavinm 
13920c794b3Sgavinm 	return (success ? 0 : 1);
14020c794b3Sgavinm }
14120c794b3Sgavinm 
14220c794b3Sgavinm /*
143e4b86885SCheng Sean Ye  * Lookup string data named pname in the given nvlist and add that
14420c794b3Sgavinm  * as property named pname in the given property group pgname on the indicated
14520c794b3Sgavinm  * topo node.  Fill pvalp with a pointer to the string value, valid until
146e4b86885SCheng Sean Ye  * nvlist_free is called.
14720c794b3Sgavinm  */
14820c794b3Sgavinm int
add_nvlist_strprop(topo_mod_t * mod,tnode_t * node,nvlist_t * nvl,const char * pgname,const char * pname,const char ** pvalp)149e4b86885SCheng Sean Ye add_nvlist_strprop(topo_mod_t *mod, tnode_t *node, nvlist_t *nvl,
15020c794b3Sgavinm     const char *pgname, const char *pname, const char **pvalp)
15120c794b3Sgavinm {
152e4b86885SCheng Sean Ye 	char *pval;
15320c794b3Sgavinm 	int err = 0;
15420c794b3Sgavinm 
155e4b86885SCheng Sean Ye 	if (nvlist_lookup_string(nvl, pname, &pval) != 0)
15620c794b3Sgavinm 		return (-1);
15720c794b3Sgavinm 
15820c794b3Sgavinm 	if (topo_prop_set_string(node, pgname, pname,
15920c794b3Sgavinm 	    TOPO_PROP_IMMUTABLE, pval, &err) == 0) {
16020c794b3Sgavinm 		if (pvalp)
16120c794b3Sgavinm 			*pvalp = pval;
16220c794b3Sgavinm 		return (0);
16320c794b3Sgavinm 	} else {
164e4b86885SCheng Sean Ye 		whinge(mod, &err, "add_nvlist_strprop: failed to add '%s'\n",
16520c794b3Sgavinm 		    pname);
16620c794b3Sgavinm 		return (-1);
16720c794b3Sgavinm 	}
16820c794b3Sgavinm }
16920c794b3Sgavinm 
17020c794b3Sgavinm /*
171e4b86885SCheng Sean Ye  * Lookup an int32 item named pname in the given nvlist and add that
17220c794b3Sgavinm  * as property named pname in the given property group pgname on the indicated
17320c794b3Sgavinm  * topo node.  Fill pvalp with the property value.
17420c794b3Sgavinm  */
17520c794b3Sgavinm int
add_nvlist_longprop(topo_mod_t * mod,tnode_t * node,nvlist_t * nvl,const char * pgname,const char * pname,int32_t * pvalp)176e4b86885SCheng Sean Ye add_nvlist_longprop(topo_mod_t *mod, tnode_t *node, nvlist_t *nvl,
17720c794b3Sgavinm     const char *pgname, const char *pname, int32_t *pvalp)
17820c794b3Sgavinm {
17920c794b3Sgavinm 	int32_t pval;
18020c794b3Sgavinm 	int err;
18120c794b3Sgavinm 
182e4b86885SCheng Sean Ye 	if ((nvlist_lookup_int32(nvl, pname, &pval)) != 0)
18320c794b3Sgavinm 		return (-1);
18420c794b3Sgavinm 
18520c794b3Sgavinm 	if (topo_prop_set_int32(node, pgname, pname,
18620c794b3Sgavinm 	    TOPO_PROP_IMMUTABLE, pval, &err) == 0) {
18720c794b3Sgavinm 		if (pvalp)
18820c794b3Sgavinm 			*pvalp = pval;
18920c794b3Sgavinm 		return (0);
19020c794b3Sgavinm 	} else {
191e4b86885SCheng Sean Ye 		whinge(mod, &err, "add_nvlist_longprop: failed to add '%s'\n",
19220c794b3Sgavinm 		    pname);
19320c794b3Sgavinm 		return (-1);
19420c794b3Sgavinm 	}
19520c794b3Sgavinm }
19620c794b3Sgavinm 
19720c794b3Sgavinm /*
198e4b86885SCheng Sean Ye  * In a given nvlist lookup a variable number of int32 properties named in
19920c794b3Sgavinm  * const char * varargs and each each in the given property group on the
20020c794b3Sgavinm  * node.  Fill an array of the retrieved values.
20120c794b3Sgavinm  */
20220c794b3Sgavinm int
add_nvlist_longprops(topo_mod_t * mod,tnode_t * node,nvlist_t * nvl,const char * pgname,int32_t * pvalap,...)203e4b86885SCheng Sean Ye add_nvlist_longprops(topo_mod_t *mod, tnode_t *node, nvlist_t *nvl,
20420c794b3Sgavinm     const char *pgname, int32_t *pvalap, ...)
20520c794b3Sgavinm {
20620c794b3Sgavinm 	const char *pname;
20720c794b3Sgavinm 	va_list ap;
20820c794b3Sgavinm 	int nerr = 0;
20920c794b3Sgavinm 
21020c794b3Sgavinm 	va_start(ap, pvalap);
21120c794b3Sgavinm 	while ((pname = va_arg(ap, const char *)) != NULL) {
212e4b86885SCheng Sean Ye 		if (add_nvlist_longprop(mod, node, nvl, pgname, pname,
21320c794b3Sgavinm 		    pvalap) != 0)
21420c794b3Sgavinm 			nerr++;		/* have whinged elsewhere */
21520c794b3Sgavinm 
21620c794b3Sgavinm 		if (pvalap != NULL)
21720c794b3Sgavinm 			++pvalap;
21820c794b3Sgavinm 	}
21920c794b3Sgavinm 	va_end(ap);
22020c794b3Sgavinm 
22120c794b3Sgavinm 	return (nerr == 0 ? 0 : -1);
22220c794b3Sgavinm }
22320c794b3Sgavinm 
22420c794b3Sgavinm /*
22520c794b3Sgavinm  * Construct an hc scheme resource FMRI for a node named name with
22620c794b3Sgavinm  * instance number inst, parented by the given parent node pnode.
22720c794b3Sgavinm  */
22820c794b3Sgavinm int
mkrsrc(topo_mod_t * mod,tnode_t * pnode,const char * name,int inst,nvlist_t * auth,nvlist_t ** nvl)22920c794b3Sgavinm mkrsrc(topo_mod_t *mod, tnode_t *pnode, const char *name, int inst,
23020c794b3Sgavinm     nvlist_t *auth, nvlist_t **nvl)
23120c794b3Sgavinm {
23220c794b3Sgavinm 	*nvl = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, name,
23320c794b3Sgavinm 	    inst, NULL, auth, NULL, NULL, NULL);
234f2dbfd32SRobert Mustacchi 	return (*nvl != NULL ? 0 : -1);	/* caller must free nvlist */
23520c794b3Sgavinm }
23620c794b3Sgavinm 
23720c794b3Sgavinm /*
23820c794b3Sgavinm  * Construct a cpu scheme FMRI with the given data; the caller must free
23920c794b3Sgavinm  * the allocated nvlist with nvlist_free().
24020c794b3Sgavinm  */
24120c794b3Sgavinm nvlist_t *
cpu_fmri_create(topo_mod_t * mod,uint32_t cpuid,char * s,uint8_t cpumask)24220c794b3Sgavinm cpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *s, uint8_t cpumask)
24320c794b3Sgavinm {
24420c794b3Sgavinm 	int err;
24520c794b3Sgavinm 	nvlist_t *asru;
24620c794b3Sgavinm 
24720c794b3Sgavinm 	if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0)
24820c794b3Sgavinm 		return (NULL);
24920c794b3Sgavinm 
25020c794b3Sgavinm 	err = nvlist_add_uint8(asru, FM_VERSION, FM_CPU_SCHEME_VERSION);
25120c794b3Sgavinm 	err |= nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU);
25220c794b3Sgavinm 	err |= nvlist_add_uint32(asru, FM_FMRI_CPU_ID, cpuid);
25320c794b3Sgavinm 	err |= nvlist_add_uint8(asru, FM_FMRI_CPU_MASK, cpumask);
25420c794b3Sgavinm 	if (s != NULL)
25520c794b3Sgavinm 		err |= nvlist_add_string(asru, FM_FMRI_CPU_SERIAL_ID, s);
25620c794b3Sgavinm 	if (err != 0) {
25720c794b3Sgavinm 		nvlist_free(asru);
25820c794b3Sgavinm 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
25920c794b3Sgavinm 		return (NULL);
26020c794b3Sgavinm 	}
26120c794b3Sgavinm 
26220c794b3Sgavinm 	return (asru);
26320c794b3Sgavinm }
26420c794b3Sgavinm 
26520c794b3Sgavinm /*ARGSUSED*/
26620c794b3Sgavinm int
mem_asru_compute(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)26720c794b3Sgavinm mem_asru_compute(topo_mod_t *mod, tnode_t *node, topo_version_t version,
26820c794b3Sgavinm     nvlist_t *in, nvlist_t **out)
26920c794b3Sgavinm {
270e4b86885SCheng Sean Ye 	nvlist_t *asru, *args, *pargs, *hcsp;
27120c794b3Sgavinm 	int err;
272e4b86885SCheng Sean Ye 	uint64_t pa, offset;
27320c794b3Sgavinm 
27420c794b3Sgavinm 	if (strcmp(topo_node_name(node), RANK_NODE_NAME) != 0 &&
27520c794b3Sgavinm 	    strcmp(topo_node_name(node), DIMM_NODE_NAME) != 0 &&
27620c794b3Sgavinm 	    strcmp(topo_node_name(node), CS_NODE_NAME) != 0)
27720c794b3Sgavinm 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
27820c794b3Sgavinm 
27920c794b3Sgavinm 	if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0)
28020c794b3Sgavinm 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
28120c794b3Sgavinm 
28220c794b3Sgavinm 	if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs)) != 0) {
28320c794b3Sgavinm 		if (err == ENOENT) {
284e4b86885SCheng Sean Ye 			pargs = args;
28520c794b3Sgavinm 		} else {
28620c794b3Sgavinm 			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
28720c794b3Sgavinm 		}
28820c794b3Sgavinm 	}
28920c794b3Sgavinm 
290e4b86885SCheng Sean Ye 	if (topo_mod_nvdup(mod, pargs, &asru) != 0)
291e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
292e4b86885SCheng Sean Ye 
293e4b86885SCheng Sean Ye 	err = 0;
294e4b86885SCheng Sean Ye 
295e4b86885SCheng Sean Ye 	/*
296e4b86885SCheng Sean Ye 	 * if 'in' includes an hc-specific member which specifies asru-physaddr
297e4b86885SCheng Sean Ye 	 * or asru-offset then rename them to asru and physaddr respectively.
298e4b86885SCheng Sean Ye 	 */
299e4b86885SCheng Sean Ye 	if (nvlist_lookup_nvlist(asru, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) {
300e4b86885SCheng Sean Ye 		if (nvlist_lookup_uint64(hcsp,
301e4b86885SCheng Sean Ye 		    "asru-"FM_FMRI_HC_SPECIFIC_PHYSADDR, &pa) == 0) {
302e4b86885SCheng Sean Ye 			err += nvlist_remove(hcsp,
303e4b86885SCheng Sean Ye 			    "asru-"FM_FMRI_HC_SPECIFIC_PHYSADDR,
304e4b86885SCheng Sean Ye 			    DATA_TYPE_UINT64);
305e4b86885SCheng Sean Ye 			err += nvlist_add_uint64(hcsp,
306e4b86885SCheng Sean Ye 			    FM_FMRI_HC_SPECIFIC_PHYSADDR,
307e4b86885SCheng Sean Ye 			    pa);
308e4b86885SCheng Sean Ye 		}
309e4b86885SCheng Sean Ye 
310e4b86885SCheng Sean Ye 		if (nvlist_lookup_uint64(hcsp,
311e4b86885SCheng Sean Ye 		    "asru-"FM_FMRI_HC_SPECIFIC_OFFSET, &offset) == 0) {
312e4b86885SCheng Sean Ye 			err += nvlist_remove(hcsp,
313e4b86885SCheng Sean Ye 			    "asru-"FM_FMRI_HC_SPECIFIC_OFFSET,
314e4b86885SCheng Sean Ye 			    DATA_TYPE_UINT64);
315e4b86885SCheng Sean Ye 			err += nvlist_add_uint64(hcsp,
316e4b86885SCheng Sean Ye 			    FM_FMRI_HC_SPECIFIC_OFFSET,
317e4b86885SCheng Sean Ye 			    offset);
318e4b86885SCheng Sean Ye 		}
319e4b86885SCheng Sean Ye 	}
320e4b86885SCheng Sean Ye 
321e4b86885SCheng Sean Ye 	if (err != 0 || topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) {
32220c794b3Sgavinm 		nvlist_free(asru);
32320c794b3Sgavinm 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
32420c794b3Sgavinm 	}
32520c794b3Sgavinm 
32620c794b3Sgavinm 	err = nvlist_add_string(*out, TOPO_PROP_VAL_NAME, TOPO_PROP_ASRU);
32720c794b3Sgavinm 	err |= nvlist_add_uint32(*out, TOPO_PROP_VAL_TYPE, TOPO_TYPE_FMRI);
32820c794b3Sgavinm 	err |= nvlist_add_nvlist(*out, TOPO_PROP_VAL_VAL, asru);
32920c794b3Sgavinm 	if (err != 0) {
33020c794b3Sgavinm 		nvlist_free(asru);
33120c794b3Sgavinm 		nvlist_free(*out);
33220c794b3Sgavinm 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
33320c794b3Sgavinm 	}
33420c794b3Sgavinm 
33520c794b3Sgavinm 	nvlist_free(asru);
33620c794b3Sgavinm 
33720c794b3Sgavinm 	return (0);
33820c794b3Sgavinm }
3392cb5535aSrobj 
340e4b86885SCheng Sean Ye static int
set_retnvl(topo_mod_t * mod,nvlist_t ** out,const char * retname,uint32_t ret)341e4b86885SCheng Sean Ye set_retnvl(topo_mod_t *mod, nvlist_t **out, const char *retname, uint32_t ret)
342e4b86885SCheng Sean Ye {
343e4b86885SCheng Sean Ye 	nvlist_t *nvl;
344e4b86885SCheng Sean Ye 
345e4b86885SCheng Sean Ye 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) < 0)
346e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
347e4b86885SCheng Sean Ye 
348e4b86885SCheng Sean Ye 	if (nvlist_add_uint32(nvl, retname, ret) != 0) {
349e4b86885SCheng Sean Ye 		nvlist_free(nvl);
350e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
351e4b86885SCheng Sean Ye 	}
352e4b86885SCheng Sean Ye 
353e4b86885SCheng Sean Ye 	*out = nvl;
354e4b86885SCheng Sean Ye 	return (0);
355e4b86885SCheng Sean Ye }
356e4b86885SCheng Sean Ye 
3572cb5535aSrobj /*
3582cb5535aSrobj  * If we're getting called then the question of whether this dimm is plugged
3592cb5535aSrobj  * in has already been answered.  What we don't know for sure is whether it's
3602cb5535aSrobj  * the same dimm or a different one plugged in the same slot.  To check, we
3612cb5535aSrobj  * try and compare the serial numbers on the dimm in the current topology with
3622cb5535aSrobj  * the serial num from the unum fmri that got passed into this function as the
3632cb5535aSrobj  * argument.
3642cb5535aSrobj  *
3652cb5535aSrobj  */
3661db96d3bSCheng Sean Ye static int
fmri_replaced(topo_mod_t * mod,tnode_t * node,nvlist_t * unum,int * errp)3671db96d3bSCheng Sean Ye fmri_replaced(topo_mod_t *mod, tnode_t *node, nvlist_t *unum, int *errp)
3682cb5535aSrobj {
3692cb5535aSrobj 	tnode_t *dimmnode;
3706e1fa242SStephen Hanson 	nvlist_t *resource;
3711db96d3bSCheng Sean Ye 	int rc, err;
3721db96d3bSCheng Sean Ye 	char *old_serial, *curr_serial;
3731db96d3bSCheng Sean Ye 	fmd_agent_hdl_t *hdl;
3741db96d3bSCheng Sean Ye 
3751db96d3bSCheng Sean Ye 	/*
3761db96d3bSCheng Sean Ye 	 * If input is a page, return "replaced" if the offset is invalid.
3771db96d3bSCheng Sean Ye 	 */
3781db96d3bSCheng Sean Ye 	if (is_page_fmri(unum) &&
3791db96d3bSCheng Sean Ye 	    (hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
3801db96d3bSCheng Sean Ye 		rc = fmd_agent_page_isretired(hdl, unum);
3811db96d3bSCheng Sean Ye 		err = fmd_agent_errno(hdl);
3821db96d3bSCheng Sean Ye 		fmd_agent_close(hdl);
3831db96d3bSCheng Sean Ye 
3841db96d3bSCheng Sean Ye 		if (rc == FMD_AGENT_RETIRE_DONE &&
3851db96d3bSCheng Sean Ye 		    err == EINVAL)
3861db96d3bSCheng Sean Ye 			return (FMD_OBJ_STATE_NOT_PRESENT);
3871db96d3bSCheng Sean Ye 	}
3882cb5535aSrobj 
3892cb5535aSrobj 	/*
3902cb5535aSrobj 	 * If a serial number for the dimm was available at the time of the
3912cb5535aSrobj 	 * fault, it will have been added as a string to the unum nvlist
3922cb5535aSrobj 	 */
3931db96d3bSCheng Sean Ye 	if (nvlist_lookup_string(unum, FM_FMRI_HC_SERIAL_ID, &old_serial))
3941db96d3bSCheng Sean Ye 		return (FMD_OBJ_STATE_UNKNOWN);
3952cb5535aSrobj 
3962cb5535aSrobj 	/*
3972cb5535aSrobj 	 * If the current serial number is available for the DIMM that this rank
3982cb5535aSrobj 	 * belongs to, it will be accessible as a property on the parent (dimm)
3996e1fa242SStephen Hanson 	 * node. If there is a serial id in the resource fmri, then use that.
4006e1fa242SStephen Hanson 	 * Otherwise fall back to looking for a serial id property in the
4016e1fa242SStephen Hanson 	 * protocol group.
4022cb5535aSrobj 	 */
4032cb5535aSrobj 	dimmnode = topo_node_parent(node);
4046e1fa242SStephen Hanson 	if (topo_node_resource(dimmnode, &resource, &err) != -1) {
4056e1fa242SStephen Hanson 		if (nvlist_lookup_string(resource, FM_FMRI_HC_SERIAL_ID,
4066e1fa242SStephen Hanson 		    &curr_serial) == 0) {
4076e1fa242SStephen Hanson 			if (strcmp(old_serial, curr_serial) != 0) {
4086e1fa242SStephen Hanson 				nvlist_free(resource);
4096e1fa242SStephen Hanson 				return (FMD_OBJ_STATE_REPLACED);
4106e1fa242SStephen Hanson 			} else {
4116e1fa242SStephen Hanson 				nvlist_free(resource);
4126e1fa242SStephen Hanson 				return (FMD_OBJ_STATE_STILL_PRESENT);
4136e1fa242SStephen Hanson 			}
4146e1fa242SStephen Hanson 		}
4156e1fa242SStephen Hanson 		nvlist_free(resource);
4166e1fa242SStephen Hanson 	}
4172cb5535aSrobj 	if (topo_prop_get_string(dimmnode, TOPO_PGROUP_PROTOCOL,
4182cb5535aSrobj 	    FM_FMRI_HC_SERIAL_ID, &curr_serial, &err) != 0) {
4191db96d3bSCheng Sean Ye 		if (err == ETOPO_PROP_NOENT) {
4201db96d3bSCheng Sean Ye 			return (FMD_OBJ_STATE_UNKNOWN);
4211db96d3bSCheng Sean Ye 		} else {
4221db96d3bSCheng Sean Ye 			*errp = EMOD_NVL_INVAL;
4231db96d3bSCheng Sean Ye 			whinge(mod, NULL, "rank_fmri_present: Unexpected "
4241db96d3bSCheng Sean Ye 			    "error retrieving serial from node");
4251db96d3bSCheng Sean Ye 			return (-1);
4261db96d3bSCheng Sean Ye 		}
4272cb5535aSrobj 	}
4282cb5535aSrobj 
4291db96d3bSCheng Sean Ye 	if (strcmp(old_serial, curr_serial) != 0) {
4301db96d3bSCheng Sean Ye 		topo_mod_strfree(mod, curr_serial);
4311db96d3bSCheng Sean Ye 		return (FMD_OBJ_STATE_REPLACED);
4321db96d3bSCheng Sean Ye 	}
4332cb5535aSrobj 
4342cb5535aSrobj 	topo_mod_strfree(mod, curr_serial);
4352cb5535aSrobj 
4361db96d3bSCheng Sean Ye 	return (FMD_OBJ_STATE_STILL_PRESENT);
4372cb5535aSrobj }
43825c6ff4bSstephh 
43925c6ff4bSstephh /*
44025c6ff4bSstephh  * In the event we encounter problems comparing serials or if a comparison isn't
44125c6ff4bSstephh  * possible, we err on the side of caution and set is_present to TRUE.
44225c6ff4bSstephh  */
44325c6ff4bSstephh int
rank_fmri_present(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)4441db96d3bSCheng Sean Ye rank_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version,
44525c6ff4bSstephh     nvlist_t *in, nvlist_t **out)
44625c6ff4bSstephh {
4471db96d3bSCheng Sean Ye 	int is_present, err;
44825c6ff4bSstephh 
4491db96d3bSCheng Sean Ye 	if (version > TOPO_METH_PRESENT_VERSION)
4501db96d3bSCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
45125c6ff4bSstephh 
4521db96d3bSCheng Sean Ye 	switch (fmri_replaced(mod, node, in, &err)) {
4531db96d3bSCheng Sean Ye 	case FMD_OBJ_STATE_REPLACED:
4541db96d3bSCheng Sean Ye 	case FMD_OBJ_STATE_NOT_PRESENT:
4551db96d3bSCheng Sean Ye 		is_present = 0;
4561db96d3bSCheng Sean Ye 		break;
4571db96d3bSCheng Sean Ye 
4581db96d3bSCheng Sean Ye 	case FMD_OBJ_STATE_UNKNOWN:
4591db96d3bSCheng Sean Ye 	case FMD_OBJ_STATE_STILL_PRESENT:
4601db96d3bSCheng Sean Ye 		is_present = 1;
4611db96d3bSCheng Sean Ye 		break;
4621db96d3bSCheng Sean Ye 
4631db96d3bSCheng Sean Ye 	default:
4641db96d3bSCheng Sean Ye 		return (topo_mod_seterrno(mod,  err));
46525c6ff4bSstephh 	}
46625c6ff4bSstephh 
4671db96d3bSCheng Sean Ye 	fmri_dprint(mod, "rank_fmri_present", is_present, in);
46825c6ff4bSstephh 
4691db96d3bSCheng Sean Ye 	return (set_retnvl(mod, out, TOPO_METH_PRESENT_RET, is_present));
4701db96d3bSCheng Sean Ye }
4711db96d3bSCheng Sean Ye 
4721db96d3bSCheng Sean Ye int
rank_fmri_replaced(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)4731db96d3bSCheng Sean Ye rank_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version,
4741db96d3bSCheng Sean Ye     nvlist_t *in, nvlist_t **out)
4751db96d3bSCheng Sean Ye {
4761db96d3bSCheng Sean Ye 	int is_replaced, err;
4771db96d3bSCheng Sean Ye 
4781db96d3bSCheng Sean Ye 	if (version > TOPO_METH_REPLACED_VERSION)
4791db96d3bSCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
4801db96d3bSCheng Sean Ye 
4811db96d3bSCheng Sean Ye 	is_replaced = fmri_replaced(mod, node, in, &err);
4821db96d3bSCheng Sean Ye 	if (is_replaced == -1)
4831db96d3bSCheng Sean Ye 		return (topo_mod_seterrno(mod,  err));
4841db96d3bSCheng Sean Ye 
4851db96d3bSCheng Sean Ye 	fmri_dprint(mod, "rank_fmri_replaced", is_replaced, in);
4861db96d3bSCheng Sean Ye 
4871db96d3bSCheng Sean Ye 	return (set_retnvl(mod, out, TOPO_METH_REPLACED_RET, is_replaced));
488e4b86885SCheng Sean Ye }
489e4b86885SCheng Sean Ye 
490e4b86885SCheng Sean Ye static void
fmri_dprint(topo_mod_t * mod,const char * op,uint32_t rc,nvlist_t * fmri)491e4b86885SCheng Sean Ye fmri_dprint(topo_mod_t *mod, const char *op, uint32_t rc, nvlist_t *fmri)
492e4b86885SCheng Sean Ye {
493e4b86885SCheng Sean Ye 	char *fmristr;
494e4b86885SCheng Sean Ye 	const char *status;
495e4b86885SCheng Sean Ye 
496e4b86885SCheng Sean Ye 	if (getenv("TOPOCHIPDBG") == NULL)
497e4b86885SCheng Sean Ye 		return;
498e4b86885SCheng Sean Ye 
499e4b86885SCheng Sean Ye 	switch (rc) {
500e4b86885SCheng Sean Ye 	case FMD_AGENT_RETIRE_DONE:
501e4b86885SCheng Sean Ye 		status = "sync success";
502e4b86885SCheng Sean Ye 		break;
503e4b86885SCheng Sean Ye 	case FMD_AGENT_RETIRE_ASYNC:
504e4b86885SCheng Sean Ye 		status = "async retiring";
505e4b86885SCheng Sean Ye 		break;
506e4b86885SCheng Sean Ye 	case FMD_AGENT_RETIRE_FAIL:
507e4b86885SCheng Sean Ye 		status = "not retired";
508e4b86885SCheng Sean Ye 		break;
509e4b86885SCheng Sean Ye 	default:
510e4b86885SCheng Sean Ye 		status = "unknown status";
51125c6ff4bSstephh 	}
512e4b86885SCheng Sean Ye 	if (fmri != NULL && topo_mod_nvl2str(mod, fmri, &fmristr) == 0) {
5131db96d3bSCheng Sean Ye 		topo_mod_dprintf(mod, "[%s]: %s => %d (\"%s\")\n", fmristr,
5141db96d3bSCheng Sean Ye 		    op, rc, status);
515e4b86885SCheng Sean Ye 		topo_mod_strfree(mod, fmristr);
516e4b86885SCheng Sean Ye 	}
517e4b86885SCheng Sean Ye }
51825c6ff4bSstephh 
519e4b86885SCheng Sean Ye struct strand_walk_data {
520e4b86885SCheng Sean Ye 	tnode_t		*parent;
521e4b86885SCheng Sean Ye 	fmd_agent_hdl_t	*hdl;
522e4b86885SCheng Sean Ye 	int		(*func)(fmd_agent_hdl_t *, int, int, int);
523e4b86885SCheng Sean Ye 	int		err;
524e4b86885SCheng Sean Ye 	int		done;
525e4b86885SCheng Sean Ye 	int		fail;
526e4b86885SCheng Sean Ye 	int		async;
527e4b86885SCheng Sean Ye };
528e4b86885SCheng Sean Ye 
529e4b86885SCheng Sean Ye static int
strand_walker(topo_mod_t * mod,tnode_t * node,void * pdata)530e4b86885SCheng Sean Ye strand_walker(topo_mod_t *mod, tnode_t *node, void *pdata)
531e4b86885SCheng Sean Ye {
532e4b86885SCheng Sean Ye 	struct strand_walk_data *swdp = pdata;
533e4b86885SCheng Sean Ye 	int32_t chipid, coreid, strandid;
534e4b86885SCheng Sean Ye 	int err, rc;
535e4b86885SCheng Sean Ye 
536e4b86885SCheng Sean Ye 	/*
537e4b86885SCheng Sean Ye 	 * Terminate the walk if we reach start-node's sibling
538e4b86885SCheng Sean Ye 	 */
539e4b86885SCheng Sean Ye 	if (node != swdp->parent &&
540e4b86885SCheng Sean Ye 	    topo_node_parent(node) == topo_node_parent(swdp->parent))
541e4b86885SCheng Sean Ye 		return (TOPO_WALK_TERMINATE);
542e4b86885SCheng Sean Ye 
543e4b86885SCheng Sean Ye 	if (strcmp(topo_node_name(node), STRAND) != 0)
544e4b86885SCheng Sean Ye 		return (TOPO_WALK_NEXT);
545e4b86885SCheng Sean Ye 
546e4b86885SCheng Sean Ye 	if (topo_prop_get_int32(node, PGNAME(STRAND), STRAND_CHIP_ID,
547e4b86885SCheng Sean Ye 	    &chipid, &err) < 0 ||
548e4b86885SCheng Sean Ye 	    topo_prop_get_int32(node, PGNAME(STRAND), STRAND_CORE_ID,
549e4b86885SCheng Sean Ye 	    &coreid, &err) < 0) {
550e4b86885SCheng Sean Ye 		swdp->err++;
551e4b86885SCheng Sean Ye 		return (TOPO_WALK_NEXT);
552e4b86885SCheng Sean Ye 	}
553e4b86885SCheng Sean Ye 	strandid = topo_node_instance(node);
554e4b86885SCheng Sean Ye 	rc = swdp->func(swdp->hdl, chipid, coreid, strandid);
555e4b86885SCheng Sean Ye 
556e4b86885SCheng Sean Ye 	if (rc == FMD_AGENT_RETIRE_DONE)
557e4b86885SCheng Sean Ye 		swdp->done++;
558e4b86885SCheng Sean Ye 	else if (rc == FMD_AGENT_RETIRE_FAIL)
559e4b86885SCheng Sean Ye 		swdp->fail++;
560e4b86885SCheng Sean Ye 	else if (rc == FMD_AGENT_RETIRE_ASYNC)
561e4b86885SCheng Sean Ye 		swdp->async++;
562e4b86885SCheng Sean Ye 	else
563e4b86885SCheng Sean Ye 		swdp->err++;
564e4b86885SCheng Sean Ye 
565e4b86885SCheng Sean Ye 	if (getenv("TOPOCHIPDBG") != NULL) {
566e4b86885SCheng Sean Ye 		const char *op;
567e4b86885SCheng Sean Ye 
568e4b86885SCheng Sean Ye 		if (swdp->func == fmd_agent_cpu_retire)
569e4b86885SCheng Sean Ye 			op = "retire";
570e4b86885SCheng Sean Ye 		else if (swdp->func == fmd_agent_cpu_unretire)
571e4b86885SCheng Sean Ye 			op = "unretire";
572e4b86885SCheng Sean Ye 		else if (swdp->func == fmd_agent_cpu_isretired)
573e4b86885SCheng Sean Ye 			op = "check status";
574e4b86885SCheng Sean Ye 		else
575e4b86885SCheng Sean Ye 			op = "unknown op";
576e4b86885SCheng Sean Ye 
577e4b86885SCheng Sean Ye 		topo_mod_dprintf(mod, "%s cpu (%d:%d:%d): rc = %d, err = %s\n",
578e4b86885SCheng Sean Ye 		    op, (int)chipid, (int)coreid, (int)strandid, rc,
579e4b86885SCheng Sean Ye 		    fmd_agent_errmsg(swdp->hdl));
580e4b86885SCheng Sean Ye 	}
581e4b86885SCheng Sean Ye 
582e4b86885SCheng Sean Ye 	return (TOPO_WALK_NEXT);
583e4b86885SCheng Sean Ye }
584e4b86885SCheng Sean Ye 
585e4b86885SCheng Sean Ye static int
walk_strands(topo_mod_t * mod,struct strand_walk_data * swdp,tnode_t * parent,int (* func)(fmd_agent_hdl_t *,int,int,int))586e4b86885SCheng Sean Ye walk_strands(topo_mod_t *mod, struct strand_walk_data *swdp, tnode_t *parent,
587e4b86885SCheng Sean Ye     int (*func)(fmd_agent_hdl_t *, int, int, int))
588e4b86885SCheng Sean Ye {
589e4b86885SCheng Sean Ye 	topo_walk_t *twp;
590e4b86885SCheng Sean Ye 	int err;
591e4b86885SCheng Sean Ye 
592e4b86885SCheng Sean Ye 	swdp->parent = parent;
593e4b86885SCheng Sean Ye 	swdp->func = func;
594e4b86885SCheng Sean Ye 	swdp->err = swdp->done = swdp->fail = swdp->async = 0;
595e4b86885SCheng Sean Ye 	if ((swdp->hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL) {
596e4b86885SCheng Sean Ye 		swdp->fail++;
597e4b86885SCheng Sean Ye 		return (0);
598e4b86885SCheng Sean Ye 	}
599e4b86885SCheng Sean Ye 
600e4b86885SCheng Sean Ye 	twp = topo_mod_walk_init(mod, parent, strand_walker, swdp, &err);
601e4b86885SCheng Sean Ye 	if (twp == NULL) {
602e4b86885SCheng Sean Ye 		fmd_agent_close(swdp->hdl);
603e4b86885SCheng Sean Ye 		return (-1);
60425c6ff4bSstephh 	}
60525c6ff4bSstephh 
606e4b86885SCheng Sean Ye 	err = topo_walk_step(twp, TOPO_WALK_CHILD);
607e4b86885SCheng Sean Ye 	topo_walk_fini(twp);
608e4b86885SCheng Sean Ye 	fmd_agent_close(swdp->hdl);
609e4b86885SCheng Sean Ye 
610e4b86885SCheng Sean Ye 	if (err == TOPO_WALK_ERR || swdp->err > 0)
611e4b86885SCheng Sean Ye 		return (-1);
612e4b86885SCheng Sean Ye 
61325c6ff4bSstephh 	return (0);
61425c6ff4bSstephh }
615e4b86885SCheng Sean Ye 
616e4b86885SCheng Sean Ye /* ARGSUSED */
617e4b86885SCheng Sean Ye int
retire_strands(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)618e4b86885SCheng Sean Ye retire_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version,
619e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
620e4b86885SCheng Sean Ye {
621e4b86885SCheng Sean Ye 	struct strand_walk_data swd;
622e4b86885SCheng Sean Ye 	uint32_t rc;
623e4b86885SCheng Sean Ye 
624e4b86885SCheng Sean Ye 	if (version > TOPO_METH_RETIRE_VERSION)
625e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
626e4b86885SCheng Sean Ye 
627e4b86885SCheng Sean Ye 	if (walk_strands(mod, &swd, node, fmd_agent_cpu_retire) == -1)
628e4b86885SCheng Sean Ye 		return (-1);
629e4b86885SCheng Sean Ye 
630e4b86885SCheng Sean Ye 	if (swd.fail > 0)
631e4b86885SCheng Sean Ye 		rc = FMD_AGENT_RETIRE_FAIL;
632e4b86885SCheng Sean Ye 	else if (swd.async > 0)
633e4b86885SCheng Sean Ye 		rc = FMD_AGENT_RETIRE_ASYNC;
634e4b86885SCheng Sean Ye 	else
635e4b86885SCheng Sean Ye 		rc = FMD_AGENT_RETIRE_DONE;
636e4b86885SCheng Sean Ye 
637e4b86885SCheng Sean Ye 	return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc));
638e4b86885SCheng Sean Ye }
639e4b86885SCheng Sean Ye 
640e4b86885SCheng Sean Ye /* ARGSUSED */
641e4b86885SCheng Sean Ye int
unretire_strands(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)642e4b86885SCheng Sean Ye unretire_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version,
643e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
644e4b86885SCheng Sean Ye {
645e4b86885SCheng Sean Ye 	struct strand_walk_data swd;
646e4b86885SCheng Sean Ye 	uint32_t rc;
647e4b86885SCheng Sean Ye 
648e4b86885SCheng Sean Ye 	if (version > TOPO_METH_UNRETIRE_VERSION)
649e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
650e4b86885SCheng Sean Ye 
651e4b86885SCheng Sean Ye 	if (walk_strands(mod, &swd, node, fmd_agent_cpu_unretire) == -1)
652e4b86885SCheng Sean Ye 		return (-1);
653e4b86885SCheng Sean Ye 
654e4b86885SCheng Sean Ye 	if (swd.fail > 0)
655e4b86885SCheng Sean Ye 		rc = FMD_AGENT_RETIRE_FAIL;
656e4b86885SCheng Sean Ye 	else if (swd.async > 0)
657e4b86885SCheng Sean Ye 		rc = FMD_AGENT_RETIRE_ASYNC;
658e4b86885SCheng Sean Ye 	else
659e4b86885SCheng Sean Ye 		rc = FMD_AGENT_RETIRE_DONE;
660e4b86885SCheng Sean Ye 
661e4b86885SCheng Sean Ye 	return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc));
662e4b86885SCheng Sean Ye }
663e4b86885SCheng Sean Ye 
664e4b86885SCheng Sean Ye /* ARGSUSED */
665e4b86885SCheng Sean Ye int
service_state_strands(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)666e4b86885SCheng Sean Ye service_state_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version,
667e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
668e4b86885SCheng Sean Ye {
669e4b86885SCheng Sean Ye 	struct strand_walk_data swd;
670e4b86885SCheng Sean Ye 	uint32_t rc;
671e4b86885SCheng Sean Ye 
672e4b86885SCheng Sean Ye 	if (version > TOPO_METH_SERVICE_STATE_VERSION)
673e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
674e4b86885SCheng Sean Ye 
675e4b86885SCheng Sean Ye 	if (walk_strands(mod, &swd, node, fmd_agent_cpu_isretired) == -1)
676e4b86885SCheng Sean Ye 		return (-1);
677e4b86885SCheng Sean Ye 
678e4b86885SCheng Sean Ye 	if (swd.done > 0)
679e4b86885SCheng Sean Ye 		rc = (swd.fail + swd.async > 0) ? FMD_SERVICE_STATE_DEGRADED :
680e4b86885SCheng Sean Ye 		    FMD_SERVICE_STATE_UNUSABLE;
681e4b86885SCheng Sean Ye 	else if (swd.async > 0)
682e4b86885SCheng Sean Ye 		rc = FMD_SERVICE_STATE_ISOLATE_PENDING;
683e4b86885SCheng Sean Ye 	else if (swd.fail > 0)
684e4b86885SCheng Sean Ye 		rc = FMD_SERVICE_STATE_OK;
685e4b86885SCheng Sean Ye 	else
686e4b86885SCheng Sean Ye 		rc = FMD_SERVICE_STATE_UNKNOWN;
687e4b86885SCheng Sean Ye 
688e4b86885SCheng Sean Ye 	return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc));
689e4b86885SCheng Sean Ye }
690e4b86885SCheng Sean Ye 
691e4b86885SCheng Sean Ye /* ARGSUSED */
692e4b86885SCheng Sean Ye int
unusable_strands(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)693e4b86885SCheng Sean Ye unusable_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version,
694e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
695e4b86885SCheng Sean Ye {
696e4b86885SCheng Sean Ye 	struct strand_walk_data swd;
697e4b86885SCheng Sean Ye 	uint32_t rc;
698e4b86885SCheng Sean Ye 
699e4b86885SCheng Sean Ye 	if (version > TOPO_METH_UNUSABLE_VERSION)
700e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
701e4b86885SCheng Sean Ye 
702e4b86885SCheng Sean Ye 	if (walk_strands(mod, &swd, node, fmd_agent_cpu_isretired) == -1)
703e4b86885SCheng Sean Ye 		return (-1);
704e4b86885SCheng Sean Ye 
705e4b86885SCheng Sean Ye 	rc = (swd.fail + swd.async > 0 || swd.done == 0) ? 0 : 1;
706e4b86885SCheng Sean Ye 
707e4b86885SCheng Sean Ye 	return (set_retnvl(mod, out, TOPO_METH_UNUSABLE_RET, rc));
708e4b86885SCheng Sean Ye }
709e4b86885SCheng Sean Ye 
710e4b86885SCheng Sean Ye static boolean_t
is_page_fmri(nvlist_t * nvl)711e4b86885SCheng Sean Ye is_page_fmri(nvlist_t *nvl)
712e4b86885SCheng Sean Ye {
713e4b86885SCheng Sean Ye 	nvlist_t *hcsp;
714e4b86885SCheng Sean Ye 	uint64_t val;
715e4b86885SCheng Sean Ye 
716e4b86885SCheng Sean Ye 	if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) == 0 &&
717e4b86885SCheng Sean Ye 	    (nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET,
718e4b86885SCheng Sean Ye 	    &val) == 0 ||
719e4b86885SCheng Sean Ye 	    nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_OFFSET,
720e4b86885SCheng Sean Ye 	    &val) == 0 ||
721e4b86885SCheng Sean Ye 	    nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_PHYSADDR,
722e4b86885SCheng Sean Ye 	    &val) == 0 ||
723e4b86885SCheng Sean Ye 	    nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR,
724e4b86885SCheng Sean Ye 	    &val) == 0))
725e4b86885SCheng Sean Ye 		return (B_TRUE);
726e4b86885SCheng Sean Ye 
727e4b86885SCheng Sean Ye 	return (B_FALSE);
728e4b86885SCheng Sean Ye }
729e4b86885SCheng Sean Ye 
730e4b86885SCheng Sean Ye /* ARGSUSED */
731e4b86885SCheng Sean Ye int
ntv_page_retire(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)732e4b86885SCheng Sean Ye ntv_page_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
733e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
734e4b86885SCheng Sean Ye {
735e4b86885SCheng Sean Ye 	fmd_agent_hdl_t *hdl;
736e4b86885SCheng Sean Ye 	uint32_t rc = FMD_AGENT_RETIRE_FAIL;
737e4b86885SCheng Sean Ye 
738e4b86885SCheng Sean Ye 	if (version > TOPO_METH_RETIRE_VERSION)
739e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
740e4b86885SCheng Sean Ye 	if (is_page_fmri(in)) {
741e4b86885SCheng Sean Ye 		if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
742e4b86885SCheng Sean Ye 			rc = fmd_agent_page_retire(hdl, in);
743e4b86885SCheng Sean Ye 			fmd_agent_close(hdl);
744e4b86885SCheng Sean Ye 		}
745e4b86885SCheng Sean Ye 	}
746e4b86885SCheng Sean Ye 	fmri_dprint(mod, "ntv_page_retire", rc, in);
747e4b86885SCheng Sean Ye 	return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc));
748e4b86885SCheng Sean Ye }
749e4b86885SCheng Sean Ye 
750e4b86885SCheng Sean Ye /* ARGSUSED */
751e4b86885SCheng Sean Ye int
ntv_page_unretire(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)752e4b86885SCheng Sean Ye ntv_page_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
753e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
754e4b86885SCheng Sean Ye {
755e4b86885SCheng Sean Ye 	fmd_agent_hdl_t *hdl;
756e4b86885SCheng Sean Ye 	uint32_t rc = FMD_AGENT_RETIRE_FAIL;
757e4b86885SCheng Sean Ye 
758e4b86885SCheng Sean Ye 	if (version > TOPO_METH_UNRETIRE_VERSION)
759e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
760e4b86885SCheng Sean Ye 	if (is_page_fmri(in)) {
761e4b86885SCheng Sean Ye 		if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
762e4b86885SCheng Sean Ye 			rc = fmd_agent_page_unretire(hdl, in);
763e4b86885SCheng Sean Ye 			fmd_agent_close(hdl);
764e4b86885SCheng Sean Ye 		}
765e4b86885SCheng Sean Ye 	}
766e4b86885SCheng Sean Ye 	fmri_dprint(mod, "ntv_page_unretire", rc, in);
767e4b86885SCheng Sean Ye 	return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc));
768e4b86885SCheng Sean Ye }
769e4b86885SCheng Sean Ye 
770e4b86885SCheng Sean Ye /* ARGSUSED */
771e4b86885SCheng Sean Ye int
ntv_page_service_state(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)772e4b86885SCheng Sean Ye ntv_page_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version,
773e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
774e4b86885SCheng Sean Ye {
775e4b86885SCheng Sean Ye 	fmd_agent_hdl_t *hdl;
776e4b86885SCheng Sean Ye 	uint32_t rc = FMD_SERVICE_STATE_UNKNOWN;
777e4b86885SCheng Sean Ye 
778e4b86885SCheng Sean Ye 	if (version > TOPO_METH_SERVICE_STATE_VERSION)
779e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
780e4b86885SCheng Sean Ye 	if (is_page_fmri(in)) {
781e4b86885SCheng Sean Ye 		if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
782e4b86885SCheng Sean Ye 			rc = fmd_agent_page_isretired(hdl, in);
783e4b86885SCheng Sean Ye 			fmd_agent_close(hdl);
784e4b86885SCheng Sean Ye 			if (rc == FMD_AGENT_RETIRE_DONE)
785e4b86885SCheng Sean Ye 				rc = FMD_SERVICE_STATE_UNUSABLE;
786e4b86885SCheng Sean Ye 			else if (rc == FMD_AGENT_RETIRE_FAIL)
787e4b86885SCheng Sean Ye 				rc = FMD_SERVICE_STATE_OK;
788e4b86885SCheng Sean Ye 			else if (rc == FMD_AGENT_RETIRE_ASYNC)
789e4b86885SCheng Sean Ye 				rc = FMD_SERVICE_STATE_ISOLATE_PENDING;
790e4b86885SCheng Sean Ye 		}
791e4b86885SCheng Sean Ye 	}
792e4b86885SCheng Sean Ye 
793e4b86885SCheng Sean Ye 	topo_mod_dprintf(mod, "ntv_page_service_state: rc = %u\n", rc);
794e4b86885SCheng Sean Ye 	return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc));
795e4b86885SCheng Sean Ye }
796e4b86885SCheng Sean Ye 
797e4b86885SCheng Sean Ye /* ARGSUSED */
798e4b86885SCheng Sean Ye int
ntv_page_unusable(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)799e4b86885SCheng Sean Ye ntv_page_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version,
800e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
801e4b86885SCheng Sean Ye {
802e4b86885SCheng Sean Ye 	fmd_agent_hdl_t *hdl;
803e4b86885SCheng Sean Ye 	uint32_t rc = FMD_AGENT_RETIRE_FAIL;
804e4b86885SCheng Sean Ye 
805e4b86885SCheng Sean Ye 	if (version > TOPO_METH_UNUSABLE_VERSION)
806e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
807e4b86885SCheng Sean Ye 	if (is_page_fmri(in)) {
808e4b86885SCheng Sean Ye 		if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
809e4b86885SCheng Sean Ye 			rc = fmd_agent_page_isretired(hdl, in);
810e4b86885SCheng Sean Ye 			fmd_agent_close(hdl);
811e4b86885SCheng Sean Ye 		}
812e4b86885SCheng Sean Ye 	}
813e4b86885SCheng Sean Ye 	topo_mod_dprintf(mod, "ntv_page_unusable: rc = %u\n", rc);
814e4b86885SCheng Sean Ye 	return (set_retnvl(mod, out, TOPO_METH_UNUSABLE_RET,
815e4b86885SCheng Sean Ye 	    rc == FMD_AGENT_RETIRE_DONE ? 1 : 0));
816e4b86885SCheng Sean Ye }
8172a613b59SRobert Mustacchi 
8182a613b59SRobert Mustacchi /*
8192a613b59SRobert Mustacchi  * Determine whether or not we believe a chip has been replaced. While it's
8202a613b59SRobert Mustacchi  * tempting to just do a straight up comparison of the FMRI and its serial
8212a613b59SRobert Mustacchi  * number, things are not that straightforward.
8222a613b59SRobert Mustacchi  *
8232a613b59SRobert Mustacchi  * The presence of a serial number on the CPU is not always guaranteed. It is
8242a613b59SRobert Mustacchi  * possible that systems firmware can hide the information required to generate
8252a613b59SRobert Mustacchi  * a synthesized serial number or that it is strictly not present. As such, we
8262a613b59SRobert Mustacchi  * will only declare something replaced when both the old and current resource
8272a613b59SRobert Mustacchi  * have a serial number present. If it is missing for whatever reason, then we
8282a613b59SRobert Mustacchi  * cannot assume anything about a replacement having occurred.
8292a613b59SRobert Mustacchi  *
8302a613b59SRobert Mustacchi  * This logic applies regardless of whether or not we have an FM-aware SMBIOS.
8312a613b59SRobert Mustacchi  */
8322a613b59SRobert Mustacchi int
chip_fmri_replaced(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)8332a613b59SRobert Mustacchi chip_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version,
8342a613b59SRobert Mustacchi     nvlist_t *in, nvlist_t **out)
8352a613b59SRobert Mustacchi {
8362a613b59SRobert Mustacchi 	nvlist_t *rsrc = NULL;
8372a613b59SRobert Mustacchi 	int err, ret;
8382a613b59SRobert Mustacchi 	char *old_serial, *new_serial;
8392a613b59SRobert Mustacchi 
8402a613b59SRobert Mustacchi 	if (version > TOPO_METH_REPLACED_VERSION)
8412a613b59SRobert Mustacchi 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
8422a613b59SRobert Mustacchi 
8432a613b59SRobert Mustacchi 	if (topo_node_resource(node, &rsrc, &err) == -1) {
8442a613b59SRobert Mustacchi 		return (topo_mod_seterrno(mod, err));
8452a613b59SRobert Mustacchi 	}
8462a613b59SRobert Mustacchi 
8472a613b59SRobert Mustacchi 	if (nvlist_lookup_string(rsrc, FM_FMRI_HC_SERIAL_ID,
8482a613b59SRobert Mustacchi 	    &new_serial) != 0) {
8492a613b59SRobert Mustacchi 		ret = FMD_OBJ_STATE_UNKNOWN;
8502a613b59SRobert Mustacchi 		goto out;
8512a613b59SRobert Mustacchi 	}
8522a613b59SRobert Mustacchi 
8532a613b59SRobert Mustacchi 	if (nvlist_lookup_string(in, FM_FMRI_HC_SERIAL_ID, &old_serial) != 0) {
8542a613b59SRobert Mustacchi 		ret = FMD_OBJ_STATE_UNKNOWN;
8552a613b59SRobert Mustacchi 		goto out;
8562a613b59SRobert Mustacchi 	}
8572a613b59SRobert Mustacchi 
8582a613b59SRobert Mustacchi 	if (strcmp(old_serial, new_serial) == 0) {
8592a613b59SRobert Mustacchi 		ret = FMD_OBJ_STATE_STILL_PRESENT;
8602a613b59SRobert Mustacchi 	} else {
8612a613b59SRobert Mustacchi 		ret = FMD_OBJ_STATE_REPLACED;
8622a613b59SRobert Mustacchi 	}
8632a613b59SRobert Mustacchi 
8642a613b59SRobert Mustacchi out:
8652a613b59SRobert Mustacchi 	nvlist_free(rsrc);
8662a613b59SRobert Mustacchi 	return (set_retnvl(mod, out, TOPO_METH_REPLACED_RET, ret));
8672a613b59SRobert Mustacchi }
868c26bf377SRob Johnston 
869*d0caeb89SRobert Mustacchi void
get_chip_kstat_strs(topo_mod_t * mod,kstat_ctl_t * kc,int32_t chipid,char ** brandp,char ** sktp)870*d0caeb89SRobert Mustacchi get_chip_kstat_strs(topo_mod_t *mod, kstat_ctl_t *kc, int32_t chipid,
871*d0caeb89SRobert Mustacchi     char **brandp, char **sktp)
872c26bf377SRob Johnston {
873c26bf377SRob Johnston 	kstat_t *ksp;
874c26bf377SRob Johnston 	kstat_named_t *ks;
875*d0caeb89SRobert Mustacchi 	uint_t i;
876c26bf377SRob Johnston 
877*d0caeb89SRobert Mustacchi 	for (i = 0, ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next, i++) {
878*d0caeb89SRobert Mustacchi 		if (strcmp(ksp->ks_module, "cpu_info") != 0)
879*d0caeb89SRobert Mustacchi 			continue;
880*d0caeb89SRobert Mustacchi 
881*d0caeb89SRobert Mustacchi 		if (kstat_read(kc, ksp, NULL) == -1) {
882*d0caeb89SRobert Mustacchi 			topo_mod_dprintf(mod, "failed to read stat cpu_info:%u",
883*d0caeb89SRobert Mustacchi 			    i);
884*d0caeb89SRobert Mustacchi 			continue;
885*d0caeb89SRobert Mustacchi 		}
886*d0caeb89SRobert Mustacchi 
887*d0caeb89SRobert Mustacchi 		if ((ks = kstat_data_lookup(ksp, "chip_id")) == NULL ||
888*d0caeb89SRobert Mustacchi 		    chipid != ks->value.i32) {
889*d0caeb89SRobert Mustacchi 			continue;
890*d0caeb89SRobert Mustacchi 		}
891*d0caeb89SRobert Mustacchi 
892*d0caeb89SRobert Mustacchi 		if ((ks = kstat_data_lookup(ksp, "brand")) != NULL) {
893*d0caeb89SRobert Mustacchi 			*brandp = topo_mod_strdup(mod, ks->value.str.addr.ptr);
894*d0caeb89SRobert Mustacchi 
895*d0caeb89SRobert Mustacchi 		}
896*d0caeb89SRobert Mustacchi 
897*d0caeb89SRobert Mustacchi 		if ((ks = kstat_data_lookup(ksp, "socket_type")) != NULL) {
898*d0caeb89SRobert Mustacchi 			if (strcmp(ks->value.str.addr.ptr, "Unknown") != 0) {
899*d0caeb89SRobert Mustacchi 				*sktp = topo_mod_strdup(mod,
900*d0caeb89SRobert Mustacchi 				    ks->value.str.addr.ptr);
901*d0caeb89SRobert Mustacchi 			}
902*d0caeb89SRobert Mustacchi 		}
903*d0caeb89SRobert Mustacchi 
904*d0caeb89SRobert Mustacchi 		return;
905c26bf377SRob Johnston 	}
906c26bf377SRob Johnston }
907