Home | History | Annotate | Download | only in cpumem-diagnosis
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 #include <fm/fmd_api.h>
     28 #include <fm/libtopo.h>
     29 #include <sys/fm/protocol.h>
     30 #include <cmd.h>
     31 #include <string.h>
     32 #include <cmd_hc_sun4v.h>
     33 
     34 /* Using a global variable is safe because the DE is single threaded */
     35 
     36 nvlist_t *dimm_nvl;
     37 nvlist_t *mb_nvl;
     38 nvlist_t *rsc_nvl;
     39 
     40 nvlist_t *
     41 cmd_fault_add_location(fmd_hdl_t *hdl, nvlist_t *flt, const char *locstr) {
     42 
     43 	char *t, *s;
     44 
     45 	if (nvlist_lookup_string(flt, FM_FAULT_LOCATION, &t) == 0)
     46 		return (flt); /* already has location value */
     47 
     48 	/* Replace occurrence of ": " with "/" to avoid confusing ILOM. */
     49 	t = fmd_hdl_zalloc(hdl, strlen(locstr) + 1, FMD_SLEEP);
     50 	s = strstr(locstr, ": ");
     51 	if (s != NULL) {
     52 		(void) strncpy(t, locstr, s - locstr);
     53 		(void) strcat(t, "/");
     54 		(void) strcat(t, s + 2);
     55 	} else {
     56 		(void) strcpy(t, locstr);
     57 	}
     58 
     59 	/* Also, remove any J number from end of this string. */
     60 	s = strstr(t, "/J");
     61 	if (s != NULL)
     62 		*s = '\0';
     63 
     64 	if (nvlist_add_string(flt, FM_FAULT_LOCATION, t) != 0)
     65 		fmd_hdl_error(hdl, "unable to alloc location for fault\n");
     66 	fmd_hdl_free(hdl, t, strlen(locstr) + 1);
     67 	return (flt);
     68 }
     69 
     70 typedef struct tr_ent {
     71 	const char *nac_component;
     72 	const char *hc_component;
     73 } tr_ent_t;
     74 
     75 static tr_ent_t tr_tbl[] = {
     76 	{ "MB",		"motherboard" },
     77 	{ "CPU",	"cpuboard" },
     78 	{ "MEM",	"memboard" },
     79 	{ "CMP",	"chip" },
     80 	{ "BR",		"branch" },
     81 	{ "CH",		"dram-channel" },
     82 	{ "R",		"rank" },
     83 	{ "D",		"dimm" }
     84 };
     85 
     86 #define	tr_tbl_n	sizeof (tr_tbl) / sizeof (tr_ent_t)
     87 
     88 int
     89 map_name(const char *p) {
     90 	int i;
     91 
     92 	for (i = 0; i < tr_tbl_n; i++) {
     93 		if (strncmp(p, tr_tbl[i].nac_component,
     94 		    strlen(tr_tbl[i].nac_component)) == 0)
     95 			return (i);
     96 	}
     97 	return (-1);
     98 }
     99 
    100 int
    101 cmd_count_components(const char *str, char sep)
    102 {
    103 	int num = 0;
    104 	const char *cptr = str;
    105 
    106 	if (*cptr == sep) cptr++;		/* skip initial sep */
    107 	if (strlen(cptr) > 0) num = 1;
    108 	while ((cptr = strchr(cptr, sep)) != NULL) {
    109 		cptr++;
    110 		if (cptr == NULL || strcmp(cptr, "") == 0) break;
    111 		if (map_name(cptr) >= 0) num++;
    112 	}
    113 	return (num);
    114 }
    115 
    116 /*
    117  * This version of breakup_components assumes that all component names which
    118  * it sees are of the form:  <nonnumeric piece><numeric piece>
    119  * i.e. no embedded numerals in component name which have to be spelled out.
    120  */
    121 
    122 int
    123 cmd_breakup_components(char *str, char *sep, nvlist_t **hc_nvl)
    124 {
    125 	char namebuf[64], instbuf[64];
    126 	char *token, *tokbuf;
    127 	int i, j, namelen, instlen;
    128 
    129 	i = 0;
    130 	for (token = strtok_r(str, sep, &tokbuf);
    131 	    token != NULL;
    132 	    token = strtok_r(NULL, sep, &tokbuf)) {
    133 		namelen = strcspn(token, "0123456789");
    134 		instlen = strspn(token+namelen, "0123456789");
    135 		(void) strncpy(namebuf, token, namelen);
    136 		namebuf[namelen] = '\0';
    137 
    138 		if ((j = map_name(namebuf)) < 0)
    139 			continue; /* skip names that don't map */
    140 
    141 		if (instlen == 0) {
    142 			(void) strncpy(instbuf, "0", 2);
    143 		} else {
    144 			(void) strncpy(instbuf, token+namelen, instlen);
    145 			instbuf[instlen] = '\0';
    146 		}
    147 		if (nvlist_add_string(hc_nvl[i], FM_FMRI_HC_NAME,
    148 		    tr_tbl[j].hc_component) != 0 ||
    149 		    nvlist_add_string(hc_nvl[i], FM_FMRI_HC_ID, instbuf) != 0)
    150 			return (-1);
    151 		i++;
    152 	}
    153 	return (1);
    154 }
    155 
    156 char *
    157 cmd_getfru_loc(fmd_hdl_t *hdl, nvlist_t *asru) {
    158 
    159 	char *fru_loc, *cpufru;
    160 	if (nvlist_lookup_string(asru, FM_FMRI_CPU_CPUFRU, &cpufru) == 0) {
    161 		fru_loc = strstr(cpufru, "MB");
    162 		if (fru_loc != NULL) {
    163 			fmd_hdl_debug(hdl, "cmd_getfru_loc: fruloc=%s\n",
    164 			    fru_loc);
    165 			return (fmd_hdl_strdup(hdl, fru_loc, FMD_SLEEP));
    166 		}
    167 	}
    168 	fmd_hdl_debug(hdl, "cmd_getfru_loc: Default fruloc=empty string\n");
    169 	return (fmd_hdl_strdup(hdl, EMPTY_STR, FMD_SLEEP));
    170 }
    171 
    172 nvlist_t *
    173 cmd_mkboard_fru(fmd_hdl_t *hdl, char *frustr, char *serialstr, char *partstr) {
    174 
    175 	char *nac, *nac_name;
    176 	int n, i, len;
    177 	nvlist_t *fru, **hc_list;
    178 
    179 	if (frustr == NULL)
    180 		return (NULL);
    181 
    182 	if ((nac_name = strstr(frustr, "MB")) == NULL)
    183 		return (NULL);
    184 
    185 	len = strlen(nac_name) + 1;
    186 
    187 	nac = fmd_hdl_zalloc(hdl, len, FMD_SLEEP);
    188 	(void) strcpy(nac, nac_name);
    189 
    190 	n = cmd_count_components(nac, '/');
    191 
    192 	fmd_hdl_debug(hdl, "cmd_mkboard_fru: nac=%s components=%d\n", nac, n);
    193 
    194 	hc_list = fmd_hdl_zalloc(hdl, sizeof (nvlist_t *)*n, FMD_SLEEP);
    195 
    196 	for (i = 0; i < n; i++) {
    197 		(void) nvlist_alloc(&hc_list[i],
    198 		    NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE, 0);
    199 	}
    200 
    201 	if (cmd_breakup_components(nac, "/", hc_list) < 0) {
    202 		for (i = 0; i < n; i++) {
    203 			if (hc_list[i] != NULL)
    204 			    nvlist_free(hc_list[i]);
    205 		}
    206 		fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
    207 		fmd_hdl_free(hdl, nac, len);
    208 		return (NULL);
    209 	}
    210 
    211 	if (nvlist_alloc(&fru, NV_UNIQUE_NAME, 0) != 0) {
    212 		for (i = 0; i < n; i++) {
    213 			if (hc_list[i] != NULL)
    214 			    nvlist_free(hc_list[i]);
    215 		}
    216 		fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
    217 		fmd_hdl_free(hdl, nac, len);
    218 		return (NULL);
    219 	}
    220 
    221 	if (nvlist_add_uint8(fru, FM_VERSION, FM_HC_SCHEME_VERSION) != 0 ||
    222 	    nvlist_add_string(fru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0 ||
    223 	    nvlist_add_string(fru, FM_FMRI_HC_ROOT, "") != 0 ||
    224 	    nvlist_add_uint32(fru, FM_FMRI_HC_LIST_SZ, n) != 0 ||
    225 	    nvlist_add_nvlist_array(fru, FM_FMRI_HC_LIST, hc_list, n) != 0) {
    226 		for (i = 0; i < n; i++) {
    227 			if (hc_list[i] != NULL)
    228 			    nvlist_free(hc_list[i]);
    229 		}
    230 		fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
    231 		fmd_hdl_free(hdl, nac, len);
    232 		nvlist_free(fru);
    233 		return (NULL);
    234 	}
    235 
    236 	for (i = 0; i < n; i++) {
    237 		if (hc_list[i] != NULL)
    238 		    nvlist_free(hc_list[i]);
    239 	}
    240 	fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
    241 	fmd_hdl_free(hdl, nac, len);
    242 
    243 	if ((serialstr != NULL &&
    244 	    nvlist_add_string(fru, FM_FMRI_HC_SERIAL_ID, serialstr) != 0) ||
    245 	    (partstr != NULL &&
    246 	    nvlist_add_string(fru, FM_FMRI_HC_PART, partstr) != 0)) {
    247 		nvlist_free(fru);
    248 		return (NULL);
    249 	}
    250 
    251 	return (fru);
    252 }
    253 
    254 nvlist_t *
    255 cmd_boardfru_create_fault(fmd_hdl_t *hdl, nvlist_t *asru, const char *fltnm,
    256     uint_t cert, char *loc)
    257 {
    258 	nvlist_t *flt, *nvlfru;
    259 	char *serialstr, *partstr;
    260 
    261 	if ((loc == NULL) || (strcmp(loc, EMPTY_STR) == 0))
    262 		return (NULL);
    263 
    264 	if (nvlist_lookup_string(asru, FM_FMRI_HC_SERIAL_ID, &serialstr) != 0)
    265 		serialstr = NULL;
    266 	if (nvlist_lookup_string(asru, FM_FMRI_HC_PART, &partstr) != 0)
    267 		partstr = NULL;
    268 
    269 	nvlfru = cmd_mkboard_fru(hdl, loc, serialstr, partstr);
    270 	if (nvlfru == NULL)
    271 		return (NULL);
    272 
    273 	flt = cmd_nvl_create_fault(hdl, fltnm, cert, nvlfru, nvlfru, NULL);
    274 	flt = cmd_fault_add_location(hdl, flt, loc);
    275 	if (nvlfru != NULL)
    276 		nvlist_free(nvlfru);
    277 	return (flt);
    278 }
    279 
    280 /* find_mb -- find hardware platform motherboard within libtopo */
    281 
    282 /* ARGSUSED */
    283 static int
    284 find_mb(topo_hdl_t *thp, tnode_t *node, void *arg)
    285 {
    286 	int err;
    287 	nvlist_t *rsrc, **hcl;
    288 	char *name;
    289 	uint_t n;
    290 
    291 	if (topo_node_resource(node, &rsrc, &err) < 0) {
    292 		return (TOPO_WALK_NEXT);	/* no resource, try next */
    293 	}
    294 
    295 	if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hcl, &n) < 0) {
    296 		nvlist_free(rsrc);
    297 		return (TOPO_WALK_NEXT);
    298 	}
    299 
    300 	if (nvlist_lookup_string(hcl[0], FM_FMRI_HC_NAME, &name) != 0) {
    301 		nvlist_free(rsrc);
    302 		return (TOPO_WALK_NEXT);
    303 	}
    304 
    305 	if (strcmp(name, "motherboard") != 0) {
    306 		nvlist_free(rsrc);
    307 		return (TOPO_WALK_NEXT); /* not MB hc list, try next */
    308 	}
    309 
    310 	(void) nvlist_dup(rsrc, &mb_nvl, NV_UNIQUE_NAME);
    311 
    312 	nvlist_free(rsrc);
    313 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
    314 }
    315 
    316 /* init_mb -- read hardware platform motherboard from libtopo */
    317 
    318 nvlist_t *
    319 init_mb(fmd_hdl_t *hdl)
    320 {
    321 	topo_hdl_t *thp;
    322 	topo_walk_t *twp;
    323 	int err;
    324 
    325 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
    326 		return (NULL);
    327 	if ((twp = topo_walk_init(thp,
    328 	    FM_FMRI_SCHEME_HC, find_mb, NULL, &err))
    329 	    == NULL) {
    330 		fmd_hdl_topo_rele(hdl, thp);
    331 		return (NULL);
    332 	}
    333 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
    334 	topo_walk_fini(twp);
    335 	fmd_hdl_topo_rele(hdl, thp);
    336 	return (mb_nvl);
    337 }
    338 
    339 /*ARGSUSED*/
    340 static int
    341 find_dimm_sn_mem(topo_hdl_t *thp, tnode_t *node, void *arg)
    342 {
    343 	int err;
    344 	uint_t n;
    345 	nvlist_t *rsrc;
    346 	char **sn;
    347 
    348 	if (topo_node_resource(node, &rsrc, &err) < 0) {
    349 		return (TOPO_WALK_NEXT);	/* no resource, try next */
    350 	}
    351 	if (nvlist_lookup_string_array(rsrc,
    352 	    FM_FMRI_HC_SERIAL_ID, &sn, &n) != 0) {
    353 		nvlist_free(rsrc);
    354 		return (TOPO_WALK_NEXT);
    355 	}
    356 	if (strcmp(*sn, (char *)arg) != 0) {
    357 		nvlist_free(rsrc);
    358 		return (TOPO_WALK_NEXT);
    359 	}
    360 	(void) nvlist_dup(rsrc, &dimm_nvl, NV_UNIQUE_NAME);
    361 	nvlist_free(rsrc);
    362 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
    363 }
    364 
    365 /*ARGSUSED*/
    366 static int
    367 find_dimm_sn_hc(topo_hdl_t *thp, tnode_t *node, void *arg)
    368 {
    369 	int err;
    370 	nvlist_t *fru;
    371 	char *sn;
    372 
    373 	if (topo_node_fru(node, &fru, 0,  &err) < 0) {
    374 		return (TOPO_WALK_NEXT);	/* no fru, try next */
    375 	}
    376 	if (nvlist_lookup_string(fru, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
    377 		nvlist_free(fru);
    378 		return (TOPO_WALK_NEXT);
    379 	}
    380 	if (strcmp(sn, (char *)arg) != 0) {
    381 		nvlist_free(fru);
    382 		return (TOPO_WALK_NEXT);
    383 	}
    384 	(void) nvlist_dup(fru, &dimm_nvl, NV_UNIQUE_NAME);
    385 	nvlist_free(fru);
    386 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
    387 }
    388 
    389 /* cmd_find_dimm_by_sn -- find fmri by sn from libtopo */
    390 
    391 nvlist_t *
    392 cmd_find_dimm_by_sn(fmd_hdl_t *hdl, char *schemename, char *sn)
    393 {
    394 	topo_hdl_t *thp;
    395 	topo_walk_t *twp;
    396 	int err;
    397 
    398 	dimm_nvl = NULL;
    399 
    400 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
    401 		return (NULL);
    402 	if (strcmp(schemename, FM_FMRI_SCHEME_MEM) == 0) {
    403 		if ((twp = topo_walk_init(thp,
    404 		    schemename, find_dimm_sn_mem, sn, &err)) == NULL) {
    405 			fmd_hdl_topo_rele(hdl, thp);
    406 			return (NULL);
    407 		}
    408 	} else {
    409 		if ((twp = topo_walk_init(thp,
    410 		    schemename, find_dimm_sn_hc, sn, &err)) == NULL) {
    411 			fmd_hdl_topo_rele(hdl, thp);
    412 			return (NULL);
    413 		}
    414 	}
    415 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
    416 	topo_walk_fini(twp);
    417 	fmd_hdl_topo_rele(hdl, thp);
    418 	return (dimm_nvl);
    419 }
    420 
    421 typedef struct cpuid {
    422 	char serial[100];
    423 	char id[10];
    424 } cpuid_t;
    425 
    426 /*ARGSUSED*/
    427 static int
    428 find_cpu_rsc_by_sn(topo_hdl_t *thp, tnode_t *node, void *arg)
    429 {
    430 	int err;
    431 	nvlist_t *rsc;
    432 	cpuid_t *rscid = (cpuid_t *)arg;
    433 	char *sn, *name, *id;
    434 	nvlist_t **hcl;
    435 	uint_t n;
    436 
    437 	if (topo_node_resource(node, &rsc, &err) < 0) {
    438 		return (TOPO_WALK_NEXT);	/* no rsc, try next */
    439 	}
    440 
    441 	if (nvlist_lookup_string(rsc, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
    442 		nvlist_free(rsc);
    443 		return (TOPO_WALK_NEXT);
    444 	}
    445 	if (strcmp(rscid->serial, sn) != 0) {
    446 		nvlist_free(rsc);
    447 		return (TOPO_WALK_NEXT);
    448 	}
    449 
    450 	if (nvlist_lookup_nvlist_array(rsc, FM_FMRI_HC_LIST, &hcl, &n) != 0) {
    451 		nvlist_free(rsc);
    452 		return (TOPO_WALK_NEXT);
    453 	}
    454 
    455 	if ((nvlist_lookup_string(hcl[n - 1], FM_FMRI_HC_NAME, &name) != 0) ||
    456 	    (nvlist_lookup_string(hcl[n - 1], FM_FMRI_HC_ID, &id) != 0)) {
    457 		nvlist_free(rsc);
    458 		return (TOPO_WALK_NEXT);
    459 	}
    460 
    461 	if ((strcmp(name, "cpu") != 0) || (strcmp(rscid->id, id) != 0)) {
    462 		nvlist_free(rsc);
    463 		return (TOPO_WALK_NEXT);
    464 	}
    465 
    466 	(void) nvlist_dup(rsc, &rsc_nvl, NV_UNIQUE_NAME);
    467 
    468 	nvlist_free(rsc);
    469 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
    470 }
    471 
    472 nvlist_t *
    473 cmd_find_cpu_rsc_by_sn(fmd_hdl_t *hdl, cpuid_t *cpuid)
    474 {
    475 	topo_hdl_t *thp;
    476 	topo_walk_t *twp;
    477 	int err;
    478 
    479 	rsc_nvl = NULL;
    480 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
    481 		return (NULL);
    482 	if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
    483 	    find_cpu_rsc_by_sn, cpuid, &err)) == NULL) {
    484 		fmd_hdl_topo_rele(hdl, thp);
    485 		return (NULL);
    486 	}
    487 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
    488 	topo_walk_fini(twp);
    489 	fmd_hdl_topo_rele(hdl, thp);
    490 	return (rsc_nvl);
    491 }
    492 
    493 nvlist_t *
    494 get_cpu_fault_resource(fmd_hdl_t *hdl, nvlist_t *asru)
    495 {
    496 	uint32_t cpu;
    497 	uint64_t serint;
    498 	char serial[64];
    499 	nvlist_t *rsc = NULL;
    500 	cpuid_t cpuid;
    501 	char strid[10];
    502 
    503 	if (nvlist_lookup_uint64(asru, FM_FMRI_CPU_SERIAL_ID, &serint) != 0 ||
    504 	    nvlist_lookup_uint32(asru, FM_FMRI_CPU_ID, &cpu) != 0)
    505 		return (rsc);
    506 
    507 	(void) snprintf(serial, sizeof (serial), "%llx", serint);
    508 	(void) snprintf(strid, sizeof (strid), "%d", cpu);
    509 
    510 	(void) strcpy(cpuid.serial, serial);
    511 	(void) strcpy(cpuid.id, strid);
    512 
    513 	rsc = cmd_find_cpu_rsc_by_sn(hdl, &cpuid);
    514 	return (rsc);
    515 }
    516 
    517 /*ARGSUSED*/
    518 static int
    519 find_mem_rsc_hc(topo_hdl_t *thp, tnode_t *node, void *arg)
    520 {
    521 	int err;
    522 	nvlist_t *rsc;
    523 	char *sn;
    524 
    525 	if (topo_node_resource(node, &rsc, &err) < 0) {
    526 		return (TOPO_WALK_NEXT);	/* no rsc, try next */
    527 	}
    528 	if (nvlist_lookup_string(rsc, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
    529 		nvlist_free(rsc);
    530 		return (TOPO_WALK_NEXT);
    531 	}
    532 	if (strcmp(sn, (char *)arg) != 0) {
    533 		nvlist_free(rsc);
    534 		return (TOPO_WALK_NEXT);
    535 	}
    536 	(void) nvlist_dup(rsc, &rsc_nvl, NV_UNIQUE_NAME);
    537 	nvlist_free(rsc);
    538 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
    539 }
    540 
    541 nvlist_t *
    542 cmd_find_mem_rsc_by_sn(fmd_hdl_t *hdl, char *sn)
    543 {
    544 	topo_hdl_t *thp;
    545 	topo_walk_t *twp;
    546 	int err;
    547 
    548 	rsc_nvl = NULL;
    549 
    550 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
    551 		return (NULL);
    552 	if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
    553 	    find_mem_rsc_hc, sn, &err)) == NULL) {
    554 		fmd_hdl_topo_rele(hdl, thp);
    555 		return (NULL);
    556 	}
    557 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
    558 	topo_walk_fini(twp);
    559 	fmd_hdl_topo_rele(hdl, thp);
    560 	return (rsc_nvl);
    561 }
    562 
    563 nvlist_t *
    564 get_mem_fault_resource(fmd_hdl_t *hdl, nvlist_t *fru)
    565 {
    566 	char *sn;
    567 	uint_t n;
    568 	char **snarray;
    569 
    570 	if (nvlist_lookup_string(fru, FM_FMRI_HC_SERIAL_ID, &sn) == 0)
    571 		return (cmd_find_mem_rsc_by_sn(hdl, sn));
    572 
    573 	/*
    574 	 * T1 platform fru is in mem scheme
    575 	 */
    576 	if (nvlist_lookup_string_array(fru, FM_FMRI_MEM_SERIAL_ID,
    577 	    &snarray, &n) == 0)
    578 		return (cmd_find_mem_rsc_by_sn(hdl, snarray[0]));
    579 
    580 	return (NULL);
    581 }
    582 
    583 int
    584 is_T1_platform(nvlist_t *asru)
    585 {
    586 	char *unum;
    587 	if (nvlist_lookup_string(asru, FM_FMRI_MEM_UNUM, &unum) == 0) {
    588 		if (strstr(unum, "BR") == NULL)
    589 			return (1);
    590 	}
    591 	return (0);
    592 }
    593 
    594 nvlist_t *
    595 cmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t cert,
    596     nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc)
    597 {
    598 	nvlist_t *fllist;
    599 	uint64_t offset, phyaddr;
    600 	nvlist_t *hsp = NULL;
    601 
    602 	rsrc = NULL;
    603 	(void) nvlist_add_nvlist(fru, FM_FMRI_AUTHORITY,
    604 	    cmd.cmd_auth); /* not an error if this fails */
    605 
    606 	if (strstr(class, "fault.memory.") != NULL) {
    607 		/*
    608 		 * For T1 platform fault.memory.bank and fault.memory.dimm,
    609 		 * do not issue the hc schmem for resource and fru
    610 		 */
    611 		if (is_T1_platform(asru) && (strstr(class, ".page") == NULL)) {
    612 			fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
    613 			    fru, fru);
    614 			return (fllist);
    615 		}
    616 
    617 		rsrc = get_mem_fault_resource(hdl, fru);
    618 		/*
    619 		 * Need to append the phyaddr & offset into the
    620 		 * hc-specific of the fault.memory.page resource
    621 		 */
    622 		if ((rsrc != NULL) && strstr(class, ".page") != NULL) {
    623 			if (nvlist_alloc(&hsp, NV_UNIQUE_NAME, 0) == 0) {
    624 				if (nvlist_lookup_uint64(asru,
    625 				    FM_FMRI_MEM_PHYSADDR, &phyaddr) == 0)
    626 					(void) (nvlist_add_uint64(hsp,
    627 					    FM_FMRI_MEM_PHYSADDR,
    628 					    phyaddr));
    629 
    630 				if (nvlist_lookup_uint64(asru,
    631 				    FM_FMRI_MEM_OFFSET, &offset) == 0)
    632 					(void) nvlist_add_uint64(hsp,
    633 					    FM_FMRI_HC_SPECIFIC_OFFSET, offset);
    634 
    635 				(void) nvlist_add_nvlist(rsrc,
    636 				    FM_FMRI_HC_SPECIFIC, hsp);
    637 			}
    638 		}
    639 		fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
    640 		    fru, rsrc);
    641 		if (hsp != NULL)
    642 			nvlist_free(hsp);
    643 	} else {
    644 		rsrc = get_cpu_fault_resource(hdl, asru);
    645 		fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
    646 		    fru, rsrc);
    647 	}
    648 
    649 	if (rsrc != NULL)
    650 		nvlist_free(rsrc);
    651 
    652 	return (fllist);
    653 }
    654