1e9713012Stsien /*
2e9713012Stsien  * CDDL HEADER START
3e9713012Stsien  *
4e9713012Stsien  * The contents of this file are subject to the terms of the
5e9713012Stsien  * Common Development and Distribution License (the "License").
6e9713012Stsien  * You may not use this file except in compliance with the License.
7e9713012Stsien  *
8e9713012Stsien  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e9713012Stsien  * or http://www.opensolaris.org/os/licensing.
10e9713012Stsien  * See the License for the specific language governing permissions
11e9713012Stsien  * and limitations under the License.
12e9713012Stsien  *
13e9713012Stsien  * When distributing Covered Code, include this CDDL HEADER in each
14e9713012Stsien  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e9713012Stsien  * If applicable, add the following below this CDDL HEADER, with the
16e9713012Stsien  * fields enclosed by brackets "[]" replaced with your own identifying
17e9713012Stsien  * information: Portions Copyright [yyyy] [name of copyright owner]
18e9713012Stsien  *
19e9713012Stsien  * CDDL HEADER END
20e9713012Stsien  */
21e9713012Stsien /*
229f69d791Std  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23e9713012Stsien  * Use is subject to license terms.
24e9713012Stsien  */
25e9713012Stsien 
26e9713012Stsien 
27e9713012Stsien #include <fm/fmd_api.h>
2813faa912Ssd #include <fm/libtopo.h>
29e9713012Stsien #include <sys/fm/protocol.h>
3019d61fc7Stsien #include <cmd.h>
3113faa912Ssd #include <string.h>
3213faa912Ssd #include <cmd_hc_sun4v.h>
3313faa912Ssd 
3470818f58Stsien /* Using a global variable is safe because the DE is single threaded */
3570818f58Stsien 
3670818f58Stsien nvlist_t *dimm_nvl;
3713faa912Ssd nvlist_t *mb_nvl;
383f1e69beSCheng Sean Ye nvlist_t *rsc_nvl;
39e9713012Stsien 
40e9713012Stsien nvlist_t *
cmd_fault_add_location(fmd_hdl_t * hdl,nvlist_t * flt,const char * locstr)41e9713012Stsien cmd_fault_add_location(fmd_hdl_t *hdl, nvlist_t *flt, const char *locstr) {
42e9713012Stsien 
439f69d791Std 	char *t, *s;
44e9713012Stsien 
45e9713012Stsien 	if (nvlist_lookup_string(flt, FM_FAULT_LOCATION, &t) == 0)
46e9713012Stsien 		return (flt); /* already has location value */
479f69d791Std 
489f69d791Std 	/* Replace occurrence of ": " with "/" to avoid confusing ILOM. */
499f69d791Std 	t = fmd_hdl_zalloc(hdl, strlen(locstr) + 1, FMD_SLEEP);
509f69d791Std 	s = strstr(locstr, ": ");
519f69d791Std 	if (s != NULL) {
529f69d791Std 		(void) strncpy(t, locstr, s - locstr);
539f69d791Std 		(void) strcat(t, "/");
549f69d791Std 		(void) strcat(t, s + 2);
559f69d791Std 	} else {
569f69d791Std 		(void) strcpy(t, locstr);
579f69d791Std 	}
589f69d791Std 
599f69d791Std 	/* Also, remove any J number from end of this string. */
609f69d791Std 	s = strstr(t, "/J");
619f69d791Std 	if (s != NULL)
629f69d791Std 		*s = '\0';
639f69d791Std 
649f69d791Std 	if (nvlist_add_string(flt, FM_FAULT_LOCATION, t) != 0)
65e9713012Stsien 		fmd_hdl_error(hdl, "unable to alloc location for fault\n");
669f69d791Std 	fmd_hdl_free(hdl, t, strlen(locstr) + 1);
67e9713012Stsien 	return (flt);
68e9713012Stsien }
69fbd1c0daSsd 
7013faa912Ssd typedef struct tr_ent {
7113faa912Ssd 	const char *nac_component;
7213faa912Ssd 	const char *hc_component;
7313faa912Ssd } tr_ent_t;
7413faa912Ssd 
7513faa912Ssd static tr_ent_t tr_tbl[] = {
7613faa912Ssd 	{ "MB",		"motherboard" },
7713faa912Ssd 	{ "CPU",	"cpuboard" },
7813faa912Ssd 	{ "MEM",	"memboard" },
7913faa912Ssd 	{ "CMP",	"chip" },
8013faa912Ssd 	{ "BR",		"branch" },
8113faa912Ssd 	{ "CH",		"dram-channel" },
8213faa912Ssd 	{ "R",		"rank" },
8313faa912Ssd 	{ "D",		"dimm" }
8413faa912Ssd };
8513faa912Ssd 
8613faa912Ssd #define	tr_tbl_n	sizeof (tr_tbl) / sizeof (tr_ent_t)
8713faa912Ssd 
8813faa912Ssd int
map_name(const char * p)8913faa912Ssd map_name(const char *p) {
9013faa912Ssd 	int i;
9113faa912Ssd 
9213faa912Ssd 	for (i = 0; i < tr_tbl_n; i++) {
9313faa912Ssd 		if (strncmp(p, tr_tbl[i].nac_component,
9413faa912Ssd 		    strlen(tr_tbl[i].nac_component)) == 0)
9513faa912Ssd 			return (i);
9613faa912Ssd 	}
9713faa912Ssd 	return (-1);
9813faa912Ssd }
9913faa912Ssd 
10013faa912Ssd int
cmd_count_components(const char * str,char sep)10113faa912Ssd cmd_count_components(const char *str, char sep)
102fbd1c0daSsd {
10313faa912Ssd 	int num = 0;
10413faa912Ssd 	const char *cptr = str;
105fbd1c0daSsd 
10613faa912Ssd 	if (*cptr == sep) cptr++;		/* skip initial sep */
10713faa912Ssd 	if (strlen(cptr) > 0) num = 1;
10813faa912Ssd 	while ((cptr = strchr(cptr, sep)) != NULL) {
10913faa912Ssd 		cptr++;
11013faa912Ssd 		if (cptr == NULL || strcmp(cptr, "") == 0) break;
11113faa912Ssd 		if (map_name(cptr) >= 0) num++;
11213faa912Ssd 	}
11313faa912Ssd 	return (num);
11413faa912Ssd }
11513faa912Ssd 
11613faa912Ssd /*
11713faa912Ssd  * This version of breakup_components assumes that all component names which
11813faa912Ssd  * it sees are of the form:  <nonnumeric piece><numeric piece>
11913faa912Ssd  * i.e. no embedded numerals in component name which have to be spelled out.
12013faa912Ssd  */
12113faa912Ssd 
12213faa912Ssd int
cmd_breakup_components(char * str,char * sep,nvlist_t ** hc_nvl)12313faa912Ssd cmd_breakup_components(char *str, char *sep, nvlist_t **hc_nvl)
12413faa912Ssd {
12513faa912Ssd 	char namebuf[64], instbuf[64];
12613faa912Ssd 	char *token, *tokbuf;
12713faa912Ssd 	int i, j, namelen, instlen;
128fbd1c0daSsd 
12913faa912Ssd 	i = 0;
13013faa912Ssd 	for (token = strtok_r(str, sep, &tokbuf);
13113faa912Ssd 	    token != NULL;
13213faa912Ssd 	    token = strtok_r(NULL, sep, &tokbuf)) {
13313faa912Ssd 		namelen = strcspn(token, "0123456789");
13413faa912Ssd 		instlen = strspn(token+namelen, "0123456789");
13513faa912Ssd 		(void) strncpy(namebuf, token, namelen);
13613faa912Ssd 		namebuf[namelen] = '\0';
13713faa912Ssd 
13813faa912Ssd 		if ((j = map_name(namebuf)) < 0)
13913faa912Ssd 			continue; /* skip names that don't map */
14013faa912Ssd 
14113faa912Ssd 		if (instlen == 0) {
14213faa912Ssd 			(void) strncpy(instbuf, "0", 2);
14313faa912Ssd 		} else {
14413faa912Ssd 			(void) strncpy(instbuf, token+namelen, instlen);
14513faa912Ssd 			instbuf[instlen] = '\0';
14613faa912Ssd 		}
14713faa912Ssd 		if (nvlist_add_string(hc_nvl[i], FM_FMRI_HC_NAME,
14813faa912Ssd 		    tr_tbl[j].hc_component) != 0 ||
14913faa912Ssd 		    nvlist_add_string(hc_nvl[i], FM_FMRI_HC_ID, instbuf) != 0)
15013faa912Ssd 			return (-1);
15113faa912Ssd 		i++;
15213faa912Ssd 	}
15313faa912Ssd 	return (1);
15413faa912Ssd }
15513faa912Ssd 
15613faa912Ssd char *
cmd_getfru_loc(fmd_hdl_t * hdl,nvlist_t * asru)15713faa912Ssd cmd_getfru_loc(fmd_hdl_t *hdl, nvlist_t *asru) {
15813faa912Ssd 
15913faa912Ssd 	char *fru_loc, *cpufru;
16013faa912Ssd 	if (nvlist_lookup_string(asru, FM_FMRI_CPU_CPUFRU, &cpufru) == 0) {
16113faa912Ssd 		fru_loc = strstr(cpufru, "MB");
16213faa912Ssd 		if (fru_loc != NULL) {
16313faa912Ssd 			fmd_hdl_debug(hdl, "cmd_getfru_loc: fruloc=%s\n",
16413faa912Ssd 			    fru_loc);
16513faa912Ssd 			return (fmd_hdl_strdup(hdl, fru_loc, FMD_SLEEP));
16613faa912Ssd 		}
16713faa912Ssd 	}
16813faa912Ssd 	fmd_hdl_debug(hdl, "cmd_getfru_loc: Default fruloc=empty string\n");
16913faa912Ssd 	return (fmd_hdl_strdup(hdl, EMPTY_STR, FMD_SLEEP));
17013faa912Ssd }
17113faa912Ssd 
17213faa912Ssd nvlist_t *
cmd_mkboard_fru(fmd_hdl_t * hdl,char * frustr,char * serialstr,char * partstr)17313faa912Ssd cmd_mkboard_fru(fmd_hdl_t *hdl, char *frustr, char *serialstr, char *partstr) {
17413faa912Ssd 
17513faa912Ssd 	char *nac, *nac_name;
17613faa912Ssd 	int n, i, len;
17713faa912Ssd 	nvlist_t *fru, **hc_list;
17813faa912Ssd 
17913faa912Ssd 	if (frustr == NULL)
180fbd1c0daSsd 		return (NULL);
181fbd1c0daSsd 
18213faa912Ssd 	if ((nac_name = strstr(frustr, "MB")) == NULL)
18313faa912Ssd 		return (NULL);
18413faa912Ssd 
18513faa912Ssd 	len = strlen(nac_name) + 1;
18613faa912Ssd 
18713faa912Ssd 	nac = fmd_hdl_zalloc(hdl, len, FMD_SLEEP);
18813faa912Ssd 	(void) strcpy(nac, nac_name);
18913faa912Ssd 
19013faa912Ssd 	n = cmd_count_components(nac, '/');
19113faa912Ssd 
19213faa912Ssd 	fmd_hdl_debug(hdl, "cmd_mkboard_fru: nac=%s components=%d\n", nac, n);
19313faa912Ssd 
19413faa912Ssd 	hc_list = fmd_hdl_zalloc(hdl, sizeof (nvlist_t *)*n, FMD_SLEEP);
19513faa912Ssd 
19613faa912Ssd 	for (i = 0; i < n; i++) {
19713faa912Ssd 		(void) nvlist_alloc(&hc_list[i],
19813faa912Ssd 		    NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE, 0);
19913faa912Ssd 	}
20013faa912Ssd 
20113faa912Ssd 	if (cmd_breakup_components(nac, "/", hc_list) < 0) {
20213faa912Ssd 		for (i = 0; i < n; i++) {
203*aab83bb8SJosef 'Jeff' Sipek 			nvlist_free(hc_list[i]);
20413faa912Ssd 		}
20513faa912Ssd 		fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
20613faa912Ssd 		fmd_hdl_free(hdl, nac, len);
207fbd1c0daSsd 		return (NULL);
208fbd1c0daSsd 	}
209fbd1c0daSsd 
210fbd1c0daSsd 	if (nvlist_alloc(&fru, NV_UNIQUE_NAME, 0) != 0) {
21113faa912Ssd 		for (i = 0; i < n; i++) {
212*aab83bb8SJosef 'Jeff' Sipek 			nvlist_free(hc_list[i]);
21313faa912Ssd 		}
21413faa912Ssd 		fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
21513faa912Ssd 		fmd_hdl_free(hdl, nac, len);
216fbd1c0daSsd 		return (NULL);
217fbd1c0daSsd 	}
218fbd1c0daSsd 
219fbd1c0daSsd 	if (nvlist_add_uint8(fru, FM_VERSION, FM_HC_SCHEME_VERSION) != 0 ||
220fbd1c0daSsd 	    nvlist_add_string(fru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0 ||
22113faa912Ssd 	    nvlist_add_string(fru, FM_FMRI_HC_ROOT, "") != 0 ||
22213faa912Ssd 	    nvlist_add_uint32(fru, FM_FMRI_HC_LIST_SZ, n) != 0 ||
22313faa912Ssd 	    nvlist_add_nvlist_array(fru, FM_FMRI_HC_LIST, hc_list, n) != 0) {
22413faa912Ssd 		for (i = 0; i < n; i++) {
225*aab83bb8SJosef 'Jeff' Sipek 			nvlist_free(hc_list[i]);
22613faa912Ssd 		}
22713faa912Ssd 		fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
22813faa912Ssd 		fmd_hdl_free(hdl, nac, len);
22913faa912Ssd 		nvlist_free(fru);
23013faa912Ssd 		return (NULL);
23113faa912Ssd 	}
23213faa912Ssd 
23313faa912Ssd 	for (i = 0; i < n; i++) {
234*aab83bb8SJosef 'Jeff' Sipek 		nvlist_free(hc_list[i]);
23513faa912Ssd 	}
23613faa912Ssd 	fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
23713faa912Ssd 	fmd_hdl_free(hdl, nac, len);
23813faa912Ssd 
23913faa912Ssd 	if ((serialstr != NULL &&
240fbd1c0daSsd 	    nvlist_add_string(fru, FM_FMRI_HC_SERIAL_ID, serialstr) != 0) ||
241fbd1c0daSsd 	    (partstr != NULL &&
242fbd1c0daSsd 	    nvlist_add_string(fru, FM_FMRI_HC_PART, partstr) != 0)) {
243fbd1c0daSsd 		nvlist_free(fru);
244fbd1c0daSsd 		return (NULL);
245fbd1c0daSsd 	}
24613faa912Ssd 
247fbd1c0daSsd 	return (fru);
248fbd1c0daSsd }
249fbd1c0daSsd 
250fbd1c0daSsd nvlist_t *
cmd_boardfru_create_fault(fmd_hdl_t * hdl,nvlist_t * asru,const char * fltnm,uint_t cert,char * loc)25113faa912Ssd cmd_boardfru_create_fault(fmd_hdl_t *hdl, nvlist_t *asru, const char *fltnm,
25213faa912Ssd     uint_t cert, char *loc)
253fbd1c0daSsd {
25413faa912Ssd 	nvlist_t *flt, *nvlfru;
25513faa912Ssd 	char *serialstr, *partstr;
25613faa912Ssd 
25713faa912Ssd 	if ((loc == NULL) || (strcmp(loc, EMPTY_STR) == 0))
25813faa912Ssd 		return (NULL);
259fbd1c0daSsd 
26013faa912Ssd 	if (nvlist_lookup_string(asru, FM_FMRI_HC_SERIAL_ID, &serialstr) != 0)
26113faa912Ssd 		serialstr = NULL;
26213faa912Ssd 	if (nvlist_lookup_string(asru, FM_FMRI_HC_PART, &partstr) != 0)
26313faa912Ssd 		partstr = NULL;
26413faa912Ssd 
26513faa912Ssd 	nvlfru = cmd_mkboard_fru(hdl, loc, serialstr, partstr);
26613faa912Ssd 	if (nvlfru == NULL)
26713faa912Ssd 		return (NULL);
26813faa912Ssd 
26913faa912Ssd 	flt = cmd_nvl_create_fault(hdl, fltnm, cert, nvlfru, nvlfru, NULL);
27013faa912Ssd 	flt = cmd_fault_add_location(hdl, flt, loc);
271*aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(nvlfru);
272fbd1c0daSsd 	return (flt);
273fbd1c0daSsd }
27413faa912Ssd 
27513faa912Ssd /* find_mb -- find hardware platform motherboard within libtopo */
27613faa912Ssd 
27713faa912Ssd /* ARGSUSED */
27813faa912Ssd static int
find_mb(topo_hdl_t * thp,tnode_t * node,void * arg)27913faa912Ssd find_mb(topo_hdl_t *thp, tnode_t *node, void *arg)
28013faa912Ssd {
28113faa912Ssd 	int err;
28213faa912Ssd 	nvlist_t *rsrc, **hcl;
28313faa912Ssd 	char *name;
28413faa912Ssd 	uint_t n;
28513faa912Ssd 
28613faa912Ssd 	if (topo_node_resource(node, &rsrc, &err) < 0) {
28713faa912Ssd 		return (TOPO_WALK_NEXT);	/* no resource, try next */
28813faa912Ssd 	}
28913faa912Ssd 
29013faa912Ssd 	if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hcl, &n) < 0) {
29113faa912Ssd 		nvlist_free(rsrc);
29213faa912Ssd 		return (TOPO_WALK_NEXT);
29313faa912Ssd 	}
29413faa912Ssd 
29513faa912Ssd 	if (nvlist_lookup_string(hcl[0], FM_FMRI_HC_NAME, &name) != 0) {
29613faa912Ssd 		nvlist_free(rsrc);
29713faa912Ssd 		return (TOPO_WALK_NEXT);
29813faa912Ssd 	}
29913faa912Ssd 
30013faa912Ssd 	if (strcmp(name, "motherboard") != 0) {
30113faa912Ssd 		nvlist_free(rsrc);
30213faa912Ssd 		return (TOPO_WALK_NEXT); /* not MB hc list, try next */
30313faa912Ssd 	}
30413faa912Ssd 
30513faa912Ssd 	(void) nvlist_dup(rsrc, &mb_nvl, NV_UNIQUE_NAME);
30613faa912Ssd 
30713faa912Ssd 	nvlist_free(rsrc);
30813faa912Ssd 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
30913faa912Ssd }
31013faa912Ssd 
31113faa912Ssd /* init_mb -- read hardware platform motherboard from libtopo */
31213faa912Ssd 
31313faa912Ssd nvlist_t *
init_mb(fmd_hdl_t * hdl)31413faa912Ssd init_mb(fmd_hdl_t *hdl)
31513faa912Ssd {
31613faa912Ssd 	topo_hdl_t *thp;
31713faa912Ssd 	topo_walk_t *twp;
31813faa912Ssd 	int err;
31913faa912Ssd 
32013faa912Ssd 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
32113faa912Ssd 		return (NULL);
32213faa912Ssd 	if ((twp = topo_walk_init(thp,
32313faa912Ssd 	    FM_FMRI_SCHEME_HC, find_mb, NULL, &err))
32413faa912Ssd 	    == NULL) {
32513faa912Ssd 		fmd_hdl_topo_rele(hdl, thp);
32613faa912Ssd 		return (NULL);
32713faa912Ssd 	}
32813faa912Ssd 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
32913faa912Ssd 	topo_walk_fini(twp);
33013faa912Ssd 	fmd_hdl_topo_rele(hdl, thp);
33113faa912Ssd 	return (mb_nvl);
33213faa912Ssd }
33370818f58Stsien 
33470818f58Stsien /*ARGSUSED*/
33570818f58Stsien static int
find_dimm_sn_mem(topo_hdl_t * thp,tnode_t * node,void * arg)33670818f58Stsien find_dimm_sn_mem(topo_hdl_t *thp, tnode_t *node, void *arg)
33770818f58Stsien {
33870818f58Stsien 	int err;
33970818f58Stsien 	uint_t n;
34070818f58Stsien 	nvlist_t *rsrc;
34170818f58Stsien 	char **sn;
34270818f58Stsien 
34370818f58Stsien 	if (topo_node_resource(node, &rsrc, &err) < 0) {
34470818f58Stsien 		return (TOPO_WALK_NEXT);	/* no resource, try next */
34570818f58Stsien 	}
34670818f58Stsien 	if (nvlist_lookup_string_array(rsrc,
34770818f58Stsien 	    FM_FMRI_HC_SERIAL_ID, &sn, &n) != 0) {
34870818f58Stsien 		nvlist_free(rsrc);
34970818f58Stsien 		return (TOPO_WALK_NEXT);
35070818f58Stsien 	}
35170818f58Stsien 	if (strcmp(*sn, (char *)arg) != 0) {
35270818f58Stsien 		nvlist_free(rsrc);
35370818f58Stsien 		return (TOPO_WALK_NEXT);
35470818f58Stsien 	}
35570818f58Stsien 	(void) nvlist_dup(rsrc, &dimm_nvl, NV_UNIQUE_NAME);
35670818f58Stsien 	nvlist_free(rsrc);
35770818f58Stsien 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
35870818f58Stsien }
35970818f58Stsien 
36070818f58Stsien /*ARGSUSED*/
36170818f58Stsien static int
find_dimm_sn_hc(topo_hdl_t * thp,tnode_t * node,void * arg)36270818f58Stsien find_dimm_sn_hc(topo_hdl_t *thp, tnode_t *node, void *arg)
36370818f58Stsien {
36470818f58Stsien 	int err;
36570818f58Stsien 	nvlist_t *fru;
36670818f58Stsien 	char *sn;
36770818f58Stsien 
36870818f58Stsien 	if (topo_node_fru(node, &fru, 0,  &err) < 0) {
36970818f58Stsien 		return (TOPO_WALK_NEXT);	/* no fru, try next */
37070818f58Stsien 	}
37170818f58Stsien 	if (nvlist_lookup_string(fru, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
37270818f58Stsien 		nvlist_free(fru);
37370818f58Stsien 		return (TOPO_WALK_NEXT);
37470818f58Stsien 	}
37570818f58Stsien 	if (strcmp(sn, (char *)arg) != 0) {
37670818f58Stsien 		nvlist_free(fru);
37770818f58Stsien 		return (TOPO_WALK_NEXT);
37870818f58Stsien 	}
37970818f58Stsien 	(void) nvlist_dup(fru, &dimm_nvl, NV_UNIQUE_NAME);
38070818f58Stsien 	nvlist_free(fru);
38170818f58Stsien 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
38270818f58Stsien }
38370818f58Stsien 
38470818f58Stsien /* cmd_find_dimm_by_sn -- find fmri by sn from libtopo */
38570818f58Stsien 
38670818f58Stsien nvlist_t *
cmd_find_dimm_by_sn(fmd_hdl_t * hdl,char * schemename,char * sn)38770818f58Stsien cmd_find_dimm_by_sn(fmd_hdl_t *hdl, char *schemename, char *sn)
38870818f58Stsien {
38970818f58Stsien 	topo_hdl_t *thp;
39070818f58Stsien 	topo_walk_t *twp;
39170818f58Stsien 	int err;
39270818f58Stsien 
39370818f58Stsien 	dimm_nvl = NULL;
39470818f58Stsien 
39570818f58Stsien 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
39670818f58Stsien 		return (NULL);
39770818f58Stsien 	if (strcmp(schemename, FM_FMRI_SCHEME_MEM) == 0) {
39870818f58Stsien 		if ((twp = topo_walk_init(thp,
39970818f58Stsien 		    schemename, find_dimm_sn_mem, sn, &err)) == NULL) {
40070818f58Stsien 			fmd_hdl_topo_rele(hdl, thp);
40170818f58Stsien 			return (NULL);
40270818f58Stsien 		}
40370818f58Stsien 	} else {
40470818f58Stsien 		if ((twp = topo_walk_init(thp,
40570818f58Stsien 		    schemename, find_dimm_sn_hc, sn, &err)) == NULL) {
40670818f58Stsien 			fmd_hdl_topo_rele(hdl, thp);
40770818f58Stsien 			return (NULL);
40870818f58Stsien 		}
40970818f58Stsien 	}
41070818f58Stsien 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
41170818f58Stsien 	topo_walk_fini(twp);
41270818f58Stsien 	fmd_hdl_topo_rele(hdl, thp);
41370818f58Stsien 	return (dimm_nvl);
41470818f58Stsien }
4153f1e69beSCheng Sean Ye 
4163f1e69beSCheng Sean Ye typedef struct cpuid {
4173f1e69beSCheng Sean Ye 	char serial[100];
4183f1e69beSCheng Sean Ye 	char id[10];
4193f1e69beSCheng Sean Ye } cpuid_t;
4203f1e69beSCheng Sean Ye 
4213f1e69beSCheng Sean Ye /*ARGSUSED*/
4223f1e69beSCheng Sean Ye static int
find_cpu_rsc_by_sn(topo_hdl_t * thp,tnode_t * node,void * arg)4233f1e69beSCheng Sean Ye find_cpu_rsc_by_sn(topo_hdl_t *thp, tnode_t *node, void *arg)
4243f1e69beSCheng Sean Ye {
4253f1e69beSCheng Sean Ye 	int err;
4263f1e69beSCheng Sean Ye 	nvlist_t *rsc;
4273f1e69beSCheng Sean Ye 	cpuid_t *rscid = (cpuid_t *)arg;
4283f1e69beSCheng Sean Ye 	char *sn, *name, *id;
4293f1e69beSCheng Sean Ye 	nvlist_t **hcl;
4303f1e69beSCheng Sean Ye 	uint_t n;
4313f1e69beSCheng Sean Ye 
4323f1e69beSCheng Sean Ye 	if (topo_node_resource(node, &rsc, &err) < 0) {
4333f1e69beSCheng Sean Ye 		return (TOPO_WALK_NEXT);	/* no rsc, try next */
4343f1e69beSCheng Sean Ye 	}
4353f1e69beSCheng Sean Ye 
4363f1e69beSCheng Sean Ye 	if (nvlist_lookup_string(rsc, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
4373f1e69beSCheng Sean Ye 		nvlist_free(rsc);
4383f1e69beSCheng Sean Ye 		return (TOPO_WALK_NEXT);
4393f1e69beSCheng Sean Ye 	}
4403f1e69beSCheng Sean Ye 	if (strcmp(rscid->serial, sn) != 0) {
4413f1e69beSCheng Sean Ye 		nvlist_free(rsc);
4423f1e69beSCheng Sean Ye 		return (TOPO_WALK_NEXT);
4433f1e69beSCheng Sean Ye 	}
4443f1e69beSCheng Sean Ye 
4453f1e69beSCheng Sean Ye 	if (nvlist_lookup_nvlist_array(rsc, FM_FMRI_HC_LIST, &hcl, &n) != 0) {
4463f1e69beSCheng Sean Ye 		nvlist_free(rsc);
4473f1e69beSCheng Sean Ye 		return (TOPO_WALK_NEXT);
4483f1e69beSCheng Sean Ye 	}
4493f1e69beSCheng Sean Ye 
4503f1e69beSCheng Sean Ye 	if ((nvlist_lookup_string(hcl[n - 1], FM_FMRI_HC_NAME, &name) != 0) ||
4513f1e69beSCheng Sean Ye 	    (nvlist_lookup_string(hcl[n - 1], FM_FMRI_HC_ID, &id) != 0)) {
4523f1e69beSCheng Sean Ye 		nvlist_free(rsc);
4533f1e69beSCheng Sean Ye 		return (TOPO_WALK_NEXT);
4543f1e69beSCheng Sean Ye 	}
4553f1e69beSCheng Sean Ye 
4563f1e69beSCheng Sean Ye 	if ((strcmp(name, "cpu") != 0) || (strcmp(rscid->id, id) != 0)) {
4573f1e69beSCheng Sean Ye 		nvlist_free(rsc);
4583f1e69beSCheng Sean Ye 		return (TOPO_WALK_NEXT);
4593f1e69beSCheng Sean Ye 	}
4603f1e69beSCheng Sean Ye 
4613f1e69beSCheng Sean Ye 	(void) nvlist_dup(rsc, &rsc_nvl, NV_UNIQUE_NAME);
4623f1e69beSCheng Sean Ye 
4633f1e69beSCheng Sean Ye 	nvlist_free(rsc);
4643f1e69beSCheng Sean Ye 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
4653f1e69beSCheng Sean Ye }
4663f1e69beSCheng Sean Ye 
4673f1e69beSCheng Sean Ye nvlist_t *
cmd_find_cpu_rsc_by_sn(fmd_hdl_t * hdl,cpuid_t * cpuid)4683f1e69beSCheng Sean Ye cmd_find_cpu_rsc_by_sn(fmd_hdl_t *hdl, cpuid_t *cpuid)
4693f1e69beSCheng Sean Ye {
4703f1e69beSCheng Sean Ye 	topo_hdl_t *thp;
4713f1e69beSCheng Sean Ye 	topo_walk_t *twp;
4723f1e69beSCheng Sean Ye 	int err;
4733f1e69beSCheng Sean Ye 
4743f1e69beSCheng Sean Ye 	rsc_nvl = NULL;
4753f1e69beSCheng Sean Ye 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
4763f1e69beSCheng Sean Ye 		return (NULL);
4773f1e69beSCheng Sean Ye 	if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
4783f1e69beSCheng Sean Ye 	    find_cpu_rsc_by_sn, cpuid, &err)) == NULL) {
4793f1e69beSCheng Sean Ye 		fmd_hdl_topo_rele(hdl, thp);
4803f1e69beSCheng Sean Ye 		return (NULL);
4813f1e69beSCheng Sean Ye 	}
4823f1e69beSCheng Sean Ye 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
4833f1e69beSCheng Sean Ye 	topo_walk_fini(twp);
4843f1e69beSCheng Sean Ye 	fmd_hdl_topo_rele(hdl, thp);
4853f1e69beSCheng Sean Ye 	return (rsc_nvl);
4863f1e69beSCheng Sean Ye }
4873f1e69beSCheng Sean Ye 
4883f1e69beSCheng Sean Ye nvlist_t *
get_cpu_fault_resource(fmd_hdl_t * hdl,nvlist_t * asru)4893f1e69beSCheng Sean Ye get_cpu_fault_resource(fmd_hdl_t *hdl, nvlist_t *asru)
4903f1e69beSCheng Sean Ye {
4913f1e69beSCheng Sean Ye 	uint32_t cpu;
4923f1e69beSCheng Sean Ye 	uint64_t serint;
4933f1e69beSCheng Sean Ye 	char serial[64];
4943f1e69beSCheng Sean Ye 	nvlist_t *rsc = NULL;
4953f1e69beSCheng Sean Ye 	cpuid_t cpuid;
4963f1e69beSCheng Sean Ye 	char strid[10];
4973f1e69beSCheng Sean Ye 
4983f1e69beSCheng Sean Ye 	if (nvlist_lookup_uint64(asru, FM_FMRI_CPU_SERIAL_ID, &serint) != 0 ||
4993f1e69beSCheng Sean Ye 	    nvlist_lookup_uint32(asru, FM_FMRI_CPU_ID, &cpu) != 0)
5003f1e69beSCheng Sean Ye 		return (rsc);
5013f1e69beSCheng Sean Ye 
5023f1e69beSCheng Sean Ye 	(void) snprintf(serial, sizeof (serial), "%llx", serint);
5033f1e69beSCheng Sean Ye 	(void) snprintf(strid, sizeof (strid), "%d", cpu);
5043f1e69beSCheng Sean Ye 
5053f1e69beSCheng Sean Ye 	(void) strcpy(cpuid.serial, serial);
5063f1e69beSCheng Sean Ye 	(void) strcpy(cpuid.id, strid);
5073f1e69beSCheng Sean Ye 
5083f1e69beSCheng Sean Ye 	rsc = cmd_find_cpu_rsc_by_sn(hdl, &cpuid);
5093f1e69beSCheng Sean Ye 	return (rsc);
5103f1e69beSCheng Sean Ye }
5113f1e69beSCheng Sean Ye 
5123f1e69beSCheng Sean Ye /*ARGSUSED*/
5133f1e69beSCheng Sean Ye static int
find_mem_rsc_hc(topo_hdl_t * thp,tnode_t * node,void * arg)5143f1e69beSCheng Sean Ye find_mem_rsc_hc(topo_hdl_t *thp, tnode_t *node, void *arg)
5153f1e69beSCheng Sean Ye {
5163f1e69beSCheng Sean Ye 	int err;
5173f1e69beSCheng Sean Ye 	nvlist_t *rsc;
5183f1e69beSCheng Sean Ye 	char *sn;
5193f1e69beSCheng Sean Ye 
5203f1e69beSCheng Sean Ye 	if (topo_node_resource(node, &rsc, &err) < 0) {
5213f1e69beSCheng Sean Ye 		return (TOPO_WALK_NEXT);	/* no rsc, try next */
5223f1e69beSCheng Sean Ye 	}
5233f1e69beSCheng Sean Ye 	if (nvlist_lookup_string(rsc, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
5243f1e69beSCheng Sean Ye 		nvlist_free(rsc);
5253f1e69beSCheng Sean Ye 		return (TOPO_WALK_NEXT);
5263f1e69beSCheng Sean Ye 	}
5273f1e69beSCheng Sean Ye 	if (strcmp(sn, (char *)arg) != 0) {
5283f1e69beSCheng Sean Ye 		nvlist_free(rsc);
5293f1e69beSCheng Sean Ye 		return (TOPO_WALK_NEXT);
5303f1e69beSCheng Sean Ye 	}
5313f1e69beSCheng Sean Ye 	(void) nvlist_dup(rsc, &rsc_nvl, NV_UNIQUE_NAME);
5323f1e69beSCheng Sean Ye 	nvlist_free(rsc);
5333f1e69beSCheng Sean Ye 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
5343f1e69beSCheng Sean Ye }
5353f1e69beSCheng Sean Ye 
5363f1e69beSCheng Sean Ye nvlist_t *
cmd_find_mem_rsc_by_sn(fmd_hdl_t * hdl,char * sn)5373f1e69beSCheng Sean Ye cmd_find_mem_rsc_by_sn(fmd_hdl_t *hdl, char *sn)
5383f1e69beSCheng Sean Ye {
5393f1e69beSCheng Sean Ye 	topo_hdl_t *thp;
5403f1e69beSCheng Sean Ye 	topo_walk_t *twp;
5413f1e69beSCheng Sean Ye 	int err;
5423f1e69beSCheng Sean Ye 
5433f1e69beSCheng Sean Ye 	rsc_nvl = NULL;
5443f1e69beSCheng Sean Ye 
5453f1e69beSCheng Sean Ye 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
5463f1e69beSCheng Sean Ye 		return (NULL);
5473f1e69beSCheng Sean Ye 	if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
5483f1e69beSCheng Sean Ye 	    find_mem_rsc_hc, sn, &err)) == NULL) {
5493f1e69beSCheng Sean Ye 		fmd_hdl_topo_rele(hdl, thp);
5503f1e69beSCheng Sean Ye 		return (NULL);
5513f1e69beSCheng Sean Ye 	}
5523f1e69beSCheng Sean Ye 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
5533f1e69beSCheng Sean Ye 	topo_walk_fini(twp);
5543f1e69beSCheng Sean Ye 	fmd_hdl_topo_rele(hdl, thp);
5553f1e69beSCheng Sean Ye 	return (rsc_nvl);
5563f1e69beSCheng Sean Ye }
5573f1e69beSCheng Sean Ye 
5583f1e69beSCheng Sean Ye nvlist_t *
get_mem_fault_resource(fmd_hdl_t * hdl,nvlist_t * fru)5593f1e69beSCheng Sean Ye get_mem_fault_resource(fmd_hdl_t *hdl, nvlist_t *fru)
5603f1e69beSCheng Sean Ye {
5613f1e69beSCheng Sean Ye 	char *sn;
5623f1e69beSCheng Sean Ye 	uint_t n;
5633f1e69beSCheng Sean Ye 	char **snarray;
5643f1e69beSCheng Sean Ye 
5653f1e69beSCheng Sean Ye 	if (nvlist_lookup_string(fru, FM_FMRI_HC_SERIAL_ID, &sn) == 0)
5663f1e69beSCheng Sean Ye 		return (cmd_find_mem_rsc_by_sn(hdl, sn));
5673f1e69beSCheng Sean Ye 
5683f1e69beSCheng Sean Ye 	/*
5693f1e69beSCheng Sean Ye 	 * T1 platform fru is in mem scheme
5703f1e69beSCheng Sean Ye 	 */
5713f1e69beSCheng Sean Ye 	if (nvlist_lookup_string_array(fru, FM_FMRI_MEM_SERIAL_ID,
5723f1e69beSCheng Sean Ye 	    &snarray, &n) == 0)
5733f1e69beSCheng Sean Ye 		return (cmd_find_mem_rsc_by_sn(hdl, snarray[0]));
5743f1e69beSCheng Sean Ye 
5753f1e69beSCheng Sean Ye 	return (NULL);
5763f1e69beSCheng Sean Ye }
5773f1e69beSCheng Sean Ye 
5783f1e69beSCheng Sean Ye int
is_T1_platform(nvlist_t * asru)5793f1e69beSCheng Sean Ye is_T1_platform(nvlist_t *asru)
5803f1e69beSCheng Sean Ye {
5813f1e69beSCheng Sean Ye 	char *unum;
5823f1e69beSCheng Sean Ye 	if (nvlist_lookup_string(asru, FM_FMRI_MEM_UNUM, &unum) == 0) {
5833f1e69beSCheng Sean Ye 		if (strstr(unum, "BR") == NULL)
5843f1e69beSCheng Sean Ye 			return (1);
5853f1e69beSCheng Sean Ye 	}
5863f1e69beSCheng Sean Ye 	return (0);
5873f1e69beSCheng Sean Ye }
5883f1e69beSCheng Sean Ye 
5893f1e69beSCheng Sean Ye nvlist_t *
cmd_nvl_create_fault(fmd_hdl_t * hdl,const char * class,uint8_t cert,nvlist_t * asru,nvlist_t * fru,nvlist_t * rsrc)5903f1e69beSCheng Sean Ye cmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t cert,
5913f1e69beSCheng Sean Ye     nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc)
5923f1e69beSCheng Sean Ye {
5933f1e69beSCheng Sean Ye 	nvlist_t *fllist;
5943f1e69beSCheng Sean Ye 	uint64_t offset, phyaddr;
5953f1e69beSCheng Sean Ye 	nvlist_t *hsp = NULL;
5963f1e69beSCheng Sean Ye 
5973f1e69beSCheng Sean Ye 	rsrc = NULL;
5983f1e69beSCheng Sean Ye 	(void) nvlist_add_nvlist(fru, FM_FMRI_AUTHORITY,
5993f1e69beSCheng Sean Ye 	    cmd.cmd_auth); /* not an error if this fails */
6003f1e69beSCheng Sean Ye 
6013f1e69beSCheng Sean Ye 	if (strstr(class, "fault.memory.") != NULL) {
6023f1e69beSCheng Sean Ye 		/*
6033f1e69beSCheng Sean Ye 		 * For T1 platform fault.memory.bank and fault.memory.dimm,
6043f1e69beSCheng Sean Ye 		 * do not issue the hc schmem for resource and fru
6053f1e69beSCheng Sean Ye 		 */
6063f1e69beSCheng Sean Ye 		if (is_T1_platform(asru) && (strstr(class, ".page") == NULL)) {
6073f1e69beSCheng Sean Ye 			fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
6083f1e69beSCheng Sean Ye 			    fru, fru);
6093f1e69beSCheng Sean Ye 			return (fllist);
6103f1e69beSCheng Sean Ye 		}
6113f1e69beSCheng Sean Ye 
6123f1e69beSCheng Sean Ye 		rsrc = get_mem_fault_resource(hdl, fru);
6133f1e69beSCheng Sean Ye 		/*
6143f1e69beSCheng Sean Ye 		 * Need to append the phyaddr & offset into the
6153f1e69beSCheng Sean Ye 		 * hc-specific of the fault.memory.page resource
6163f1e69beSCheng Sean Ye 		 */
6173f1e69beSCheng Sean Ye 		if ((rsrc != NULL) && strstr(class, ".page") != NULL) {
6183f1e69beSCheng Sean Ye 			if (nvlist_alloc(&hsp, NV_UNIQUE_NAME, 0) == 0) {
6193f1e69beSCheng Sean Ye 				if (nvlist_lookup_uint64(asru,
6203f1e69beSCheng Sean Ye 				    FM_FMRI_MEM_PHYSADDR, &phyaddr) == 0)
6213f1e69beSCheng Sean Ye 					(void) (nvlist_add_uint64(hsp,
6223f1e69beSCheng Sean Ye 					    FM_FMRI_MEM_PHYSADDR,
6233f1e69beSCheng Sean Ye 					    phyaddr));
6243f1e69beSCheng Sean Ye 
6253f1e69beSCheng Sean Ye 				if (nvlist_lookup_uint64(asru,
6263f1e69beSCheng Sean Ye 				    FM_FMRI_MEM_OFFSET, &offset) == 0)
6273f1e69beSCheng Sean Ye 					(void) nvlist_add_uint64(hsp,
6283f1e69beSCheng Sean Ye 					    FM_FMRI_HC_SPECIFIC_OFFSET, offset);
6293f1e69beSCheng Sean Ye 
6303f1e69beSCheng Sean Ye 				(void) nvlist_add_nvlist(rsrc,
6313f1e69beSCheng Sean Ye 				    FM_FMRI_HC_SPECIFIC, hsp);
6323f1e69beSCheng Sean Ye 			}
6333f1e69beSCheng Sean Ye 		}
6343f1e69beSCheng Sean Ye 		fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
6353f1e69beSCheng Sean Ye 		    fru, rsrc);
636*aab83bb8SJosef 'Jeff' Sipek 		nvlist_free(hsp);
6373f1e69beSCheng Sean Ye 	} else {
6383f1e69beSCheng Sean Ye 		rsrc = get_cpu_fault_resource(hdl, asru);
6393f1e69beSCheng Sean Ye 		fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
6403f1e69beSCheng Sean Ye 		    fru, rsrc);
6413f1e69beSCheng Sean Ye 	}
6423f1e69beSCheng Sean Ye 
643*aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(rsrc);
6443f1e69beSCheng Sean Ye 
6453f1e69beSCheng Sean Ye 	return (fllist);
6463f1e69beSCheng Sean Ye }
647