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 *
cmd_fault_add_location(fmd_hdl_t * hdl,nvlist_t * flt,const char * locstr)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
map_name(const char * p)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
cmd_count_components(const char * str,char sep)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
cmd_breakup_components(char * str,char * sep,nvlist_t ** hc_nvl)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 *
cmd_getfru_loc(fmd_hdl_t * hdl,nvlist_t * asru)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 *
cmd_mkboard_fru(fmd_hdl_t * hdl,char * frustr,char * serialstr,char * partstr)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 			nvlist_free(hc_list[i]);
204 		}
205 		fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
206 		fmd_hdl_free(hdl, nac, len);
207 		return (NULL);
208 	}
209 
210 	if (nvlist_alloc(&fru, NV_UNIQUE_NAME, 0) != 0) {
211 		for (i = 0; i < n; i++) {
212 			nvlist_free(hc_list[i]);
213 		}
214 		fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
215 		fmd_hdl_free(hdl, nac, len);
216 		return (NULL);
217 	}
218 
219 	if (nvlist_add_uint8(fru, FM_VERSION, FM_HC_SCHEME_VERSION) != 0 ||
220 	    nvlist_add_string(fru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0 ||
221 	    nvlist_add_string(fru, FM_FMRI_HC_ROOT, "") != 0 ||
222 	    nvlist_add_uint32(fru, FM_FMRI_HC_LIST_SZ, n) != 0 ||
223 	    nvlist_add_nvlist_array(fru, FM_FMRI_HC_LIST, hc_list, n) != 0) {
224 		for (i = 0; i < n; i++) {
225 			nvlist_free(hc_list[i]);
226 		}
227 		fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
228 		fmd_hdl_free(hdl, nac, len);
229 		nvlist_free(fru);
230 		return (NULL);
231 	}
232 
233 	for (i = 0; i < n; i++) {
234 		nvlist_free(hc_list[i]);
235 	}
236 	fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
237 	fmd_hdl_free(hdl, nac, len);
238 
239 	if ((serialstr != NULL &&
240 	    nvlist_add_string(fru, FM_FMRI_HC_SERIAL_ID, serialstr) != 0) ||
241 	    (partstr != NULL &&
242 	    nvlist_add_string(fru, FM_FMRI_HC_PART, partstr) != 0)) {
243 		nvlist_free(fru);
244 		return (NULL);
245 	}
246 
247 	return (fru);
248 }
249 
250 nvlist_t *
cmd_boardfru_create_fault(fmd_hdl_t * hdl,nvlist_t * asru,const char * fltnm,uint_t cert,char * loc)251 cmd_boardfru_create_fault(fmd_hdl_t *hdl, nvlist_t *asru, const char *fltnm,
252     uint_t cert, char *loc)
253 {
254 	nvlist_t *flt, *nvlfru;
255 	char *serialstr, *partstr;
256 
257 	if ((loc == NULL) || (strcmp(loc, EMPTY_STR) == 0))
258 		return (NULL);
259 
260 	if (nvlist_lookup_string(asru, FM_FMRI_HC_SERIAL_ID, &serialstr) != 0)
261 		serialstr = NULL;
262 	if (nvlist_lookup_string(asru, FM_FMRI_HC_PART, &partstr) != 0)
263 		partstr = NULL;
264 
265 	nvlfru = cmd_mkboard_fru(hdl, loc, serialstr, partstr);
266 	if (nvlfru == NULL)
267 		return (NULL);
268 
269 	flt = cmd_nvl_create_fault(hdl, fltnm, cert, nvlfru, nvlfru, NULL);
270 	flt = cmd_fault_add_location(hdl, flt, loc);
271 	nvlist_free(nvlfru);
272 	return (flt);
273 }
274 
275 /* find_mb -- find hardware platform motherboard within libtopo */
276 
277 /* ARGSUSED */
278 static int
find_mb(topo_hdl_t * thp,tnode_t * node,void * arg)279 find_mb(topo_hdl_t *thp, tnode_t *node, void *arg)
280 {
281 	int err;
282 	nvlist_t *rsrc, **hcl;
283 	char *name;
284 	uint_t n;
285 
286 	if (topo_node_resource(node, &rsrc, &err) < 0) {
287 		return (TOPO_WALK_NEXT);	/* no resource, try next */
288 	}
289 
290 	if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hcl, &n) < 0) {
291 		nvlist_free(rsrc);
292 		return (TOPO_WALK_NEXT);
293 	}
294 
295 	if (nvlist_lookup_string(hcl[0], FM_FMRI_HC_NAME, &name) != 0) {
296 		nvlist_free(rsrc);
297 		return (TOPO_WALK_NEXT);
298 	}
299 
300 	if (strcmp(name, "motherboard") != 0) {
301 		nvlist_free(rsrc);
302 		return (TOPO_WALK_NEXT); /* not MB hc list, try next */
303 	}
304 
305 	(void) nvlist_dup(rsrc, &mb_nvl, NV_UNIQUE_NAME);
306 
307 	nvlist_free(rsrc);
308 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
309 }
310 
311 /* init_mb -- read hardware platform motherboard from libtopo */
312 
313 nvlist_t *
init_mb(fmd_hdl_t * hdl)314 init_mb(fmd_hdl_t *hdl)
315 {
316 	topo_hdl_t *thp;
317 	topo_walk_t *twp;
318 	int err;
319 
320 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
321 		return (NULL);
322 	if ((twp = topo_walk_init(thp,
323 	    FM_FMRI_SCHEME_HC, find_mb, NULL, &err))
324 	    == NULL) {
325 		fmd_hdl_topo_rele(hdl, thp);
326 		return (NULL);
327 	}
328 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
329 	topo_walk_fini(twp);
330 	fmd_hdl_topo_rele(hdl, thp);
331 	return (mb_nvl);
332 }
333 
334 /*ARGSUSED*/
335 static int
find_dimm_sn_mem(topo_hdl_t * thp,tnode_t * node,void * arg)336 find_dimm_sn_mem(topo_hdl_t *thp, tnode_t *node, void *arg)
337 {
338 	int err;
339 	uint_t n;
340 	nvlist_t *rsrc;
341 	char **sn;
342 
343 	if (topo_node_resource(node, &rsrc, &err) < 0) {
344 		return (TOPO_WALK_NEXT);	/* no resource, try next */
345 	}
346 	if (nvlist_lookup_string_array(rsrc,
347 	    FM_FMRI_HC_SERIAL_ID, &sn, &n) != 0) {
348 		nvlist_free(rsrc);
349 		return (TOPO_WALK_NEXT);
350 	}
351 	if (strcmp(*sn, (char *)arg) != 0) {
352 		nvlist_free(rsrc);
353 		return (TOPO_WALK_NEXT);
354 	}
355 	(void) nvlist_dup(rsrc, &dimm_nvl, NV_UNIQUE_NAME);
356 	nvlist_free(rsrc);
357 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
358 }
359 
360 /*ARGSUSED*/
361 static int
find_dimm_sn_hc(topo_hdl_t * thp,tnode_t * node,void * arg)362 find_dimm_sn_hc(topo_hdl_t *thp, tnode_t *node, void *arg)
363 {
364 	int err;
365 	nvlist_t *fru;
366 	char *sn;
367 
368 	if (topo_node_fru(node, &fru, 0,  &err) < 0) {
369 		return (TOPO_WALK_NEXT);	/* no fru, try next */
370 	}
371 	if (nvlist_lookup_string(fru, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
372 		nvlist_free(fru);
373 		return (TOPO_WALK_NEXT);
374 	}
375 	if (strcmp(sn, (char *)arg) != 0) {
376 		nvlist_free(fru);
377 		return (TOPO_WALK_NEXT);
378 	}
379 	(void) nvlist_dup(fru, &dimm_nvl, NV_UNIQUE_NAME);
380 	nvlist_free(fru);
381 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
382 }
383 
384 /* cmd_find_dimm_by_sn -- find fmri by sn from libtopo */
385 
386 nvlist_t *
cmd_find_dimm_by_sn(fmd_hdl_t * hdl,char * schemename,char * sn)387 cmd_find_dimm_by_sn(fmd_hdl_t *hdl, char *schemename, char *sn)
388 {
389 	topo_hdl_t *thp;
390 	topo_walk_t *twp;
391 	int err;
392 
393 	dimm_nvl = NULL;
394 
395 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
396 		return (NULL);
397 	if (strcmp(schemename, FM_FMRI_SCHEME_MEM) == 0) {
398 		if ((twp = topo_walk_init(thp,
399 		    schemename, find_dimm_sn_mem, sn, &err)) == NULL) {
400 			fmd_hdl_topo_rele(hdl, thp);
401 			return (NULL);
402 		}
403 	} else {
404 		if ((twp = topo_walk_init(thp,
405 		    schemename, find_dimm_sn_hc, sn, &err)) == NULL) {
406 			fmd_hdl_topo_rele(hdl, thp);
407 			return (NULL);
408 		}
409 	}
410 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
411 	topo_walk_fini(twp);
412 	fmd_hdl_topo_rele(hdl, thp);
413 	return (dimm_nvl);
414 }
415 
416 typedef struct cpuid {
417 	char serial[100];
418 	char id[10];
419 } cpuid_t;
420 
421 /*ARGSUSED*/
422 static int
find_cpu_rsc_by_sn(topo_hdl_t * thp,tnode_t * node,void * arg)423 find_cpu_rsc_by_sn(topo_hdl_t *thp, tnode_t *node, void *arg)
424 {
425 	int err;
426 	nvlist_t *rsc;
427 	cpuid_t *rscid = (cpuid_t *)arg;
428 	char *sn, *name, *id;
429 	nvlist_t **hcl;
430 	uint_t n;
431 
432 	if (topo_node_resource(node, &rsc, &err) < 0) {
433 		return (TOPO_WALK_NEXT);	/* no rsc, try next */
434 	}
435 
436 	if (nvlist_lookup_string(rsc, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
437 		nvlist_free(rsc);
438 		return (TOPO_WALK_NEXT);
439 	}
440 	if (strcmp(rscid->serial, sn) != 0) {
441 		nvlist_free(rsc);
442 		return (TOPO_WALK_NEXT);
443 	}
444 
445 	if (nvlist_lookup_nvlist_array(rsc, FM_FMRI_HC_LIST, &hcl, &n) != 0) {
446 		nvlist_free(rsc);
447 		return (TOPO_WALK_NEXT);
448 	}
449 
450 	if ((nvlist_lookup_string(hcl[n - 1], FM_FMRI_HC_NAME, &name) != 0) ||
451 	    (nvlist_lookup_string(hcl[n - 1], FM_FMRI_HC_ID, &id) != 0)) {
452 		nvlist_free(rsc);
453 		return (TOPO_WALK_NEXT);
454 	}
455 
456 	if ((strcmp(name, "cpu") != 0) || (strcmp(rscid->id, id) != 0)) {
457 		nvlist_free(rsc);
458 		return (TOPO_WALK_NEXT);
459 	}
460 
461 	(void) nvlist_dup(rsc, &rsc_nvl, NV_UNIQUE_NAME);
462 
463 	nvlist_free(rsc);
464 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
465 }
466 
467 nvlist_t *
cmd_find_cpu_rsc_by_sn(fmd_hdl_t * hdl,cpuid_t * cpuid)468 cmd_find_cpu_rsc_by_sn(fmd_hdl_t *hdl, cpuid_t *cpuid)
469 {
470 	topo_hdl_t *thp;
471 	topo_walk_t *twp;
472 	int err;
473 
474 	rsc_nvl = NULL;
475 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
476 		return (NULL);
477 	if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
478 	    find_cpu_rsc_by_sn, cpuid, &err)) == NULL) {
479 		fmd_hdl_topo_rele(hdl, thp);
480 		return (NULL);
481 	}
482 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
483 	topo_walk_fini(twp);
484 	fmd_hdl_topo_rele(hdl, thp);
485 	return (rsc_nvl);
486 }
487 
488 nvlist_t *
get_cpu_fault_resource(fmd_hdl_t * hdl,nvlist_t * asru)489 get_cpu_fault_resource(fmd_hdl_t *hdl, nvlist_t *asru)
490 {
491 	uint32_t cpu;
492 	uint64_t serint;
493 	char serial[64];
494 	nvlist_t *rsc = NULL;
495 	cpuid_t cpuid;
496 	char strid[10];
497 
498 	if (nvlist_lookup_uint64(asru, FM_FMRI_CPU_SERIAL_ID, &serint) != 0 ||
499 	    nvlist_lookup_uint32(asru, FM_FMRI_CPU_ID, &cpu) != 0)
500 		return (rsc);
501 
502 	(void) snprintf(serial, sizeof (serial), "%llx", serint);
503 	(void) snprintf(strid, sizeof (strid), "%d", cpu);
504 
505 	(void) strcpy(cpuid.serial, serial);
506 	(void) strcpy(cpuid.id, strid);
507 
508 	rsc = cmd_find_cpu_rsc_by_sn(hdl, &cpuid);
509 	return (rsc);
510 }
511 
512 /*ARGSUSED*/
513 static int
find_mem_rsc_hc(topo_hdl_t * thp,tnode_t * node,void * arg)514 find_mem_rsc_hc(topo_hdl_t *thp, tnode_t *node, void *arg)
515 {
516 	int err;
517 	nvlist_t *rsc;
518 	char *sn;
519 
520 	if (topo_node_resource(node, &rsc, &err) < 0) {
521 		return (TOPO_WALK_NEXT);	/* no rsc, try next */
522 	}
523 	if (nvlist_lookup_string(rsc, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
524 		nvlist_free(rsc);
525 		return (TOPO_WALK_NEXT);
526 	}
527 	if (strcmp(sn, (char *)arg) != 0) {
528 		nvlist_free(rsc);
529 		return (TOPO_WALK_NEXT);
530 	}
531 	(void) nvlist_dup(rsc, &rsc_nvl, NV_UNIQUE_NAME);
532 	nvlist_free(rsc);
533 	return (TOPO_WALK_TERMINATE);	/* if no space, give up */
534 }
535 
536 nvlist_t *
cmd_find_mem_rsc_by_sn(fmd_hdl_t * hdl,char * sn)537 cmd_find_mem_rsc_by_sn(fmd_hdl_t *hdl, char *sn)
538 {
539 	topo_hdl_t *thp;
540 	topo_walk_t *twp;
541 	int err;
542 
543 	rsc_nvl = NULL;
544 
545 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
546 		return (NULL);
547 	if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
548 	    find_mem_rsc_hc, sn, &err)) == NULL) {
549 		fmd_hdl_topo_rele(hdl, thp);
550 		return (NULL);
551 	}
552 	(void) topo_walk_step(twp, TOPO_WALK_CHILD);
553 	topo_walk_fini(twp);
554 	fmd_hdl_topo_rele(hdl, thp);
555 	return (rsc_nvl);
556 }
557 
558 nvlist_t *
get_mem_fault_resource(fmd_hdl_t * hdl,nvlist_t * fru)559 get_mem_fault_resource(fmd_hdl_t *hdl, nvlist_t *fru)
560 {
561 	char *sn;
562 	uint_t n;
563 	char **snarray;
564 
565 	if (nvlist_lookup_string(fru, FM_FMRI_HC_SERIAL_ID, &sn) == 0)
566 		return (cmd_find_mem_rsc_by_sn(hdl, sn));
567 
568 	/*
569 	 * T1 platform fru is in mem scheme
570 	 */
571 	if (nvlist_lookup_string_array(fru, FM_FMRI_MEM_SERIAL_ID,
572 	    &snarray, &n) == 0)
573 		return (cmd_find_mem_rsc_by_sn(hdl, snarray[0]));
574 
575 	return (NULL);
576 }
577 
578 int
is_T1_platform(nvlist_t * asru)579 is_T1_platform(nvlist_t *asru)
580 {
581 	char *unum;
582 	if (nvlist_lookup_string(asru, FM_FMRI_MEM_UNUM, &unum) == 0) {
583 		if (strstr(unum, "BR") == NULL)
584 			return (1);
585 	}
586 	return (0);
587 }
588 
589 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)590 cmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t cert,
591     nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc)
592 {
593 	nvlist_t *fllist;
594 	uint64_t offset, phyaddr;
595 	nvlist_t *hsp = NULL;
596 
597 	rsrc = NULL;
598 	(void) nvlist_add_nvlist(fru, FM_FMRI_AUTHORITY,
599 	    cmd.cmd_auth); /* not an error if this fails */
600 
601 	if (strstr(class, "fault.memory.") != NULL) {
602 		/*
603 		 * For T1 platform fault.memory.bank and fault.memory.dimm,
604 		 * do not issue the hc schmem for resource and fru
605 		 */
606 		if (is_T1_platform(asru) && (strstr(class, ".page") == NULL)) {
607 			fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
608 			    fru, fru);
609 			return (fllist);
610 		}
611 
612 		rsrc = get_mem_fault_resource(hdl, fru);
613 		/*
614 		 * Need to append the phyaddr & offset into the
615 		 * hc-specific of the fault.memory.page resource
616 		 */
617 		if ((rsrc != NULL) && strstr(class, ".page") != NULL) {
618 			if (nvlist_alloc(&hsp, NV_UNIQUE_NAME, 0) == 0) {
619 				if (nvlist_lookup_uint64(asru,
620 				    FM_FMRI_MEM_PHYSADDR, &phyaddr) == 0)
621 					(void) (nvlist_add_uint64(hsp,
622 					    FM_FMRI_MEM_PHYSADDR,
623 					    phyaddr));
624 
625 				if (nvlist_lookup_uint64(asru,
626 				    FM_FMRI_MEM_OFFSET, &offset) == 0)
627 					(void) nvlist_add_uint64(hsp,
628 					    FM_FMRI_HC_SPECIFIC_OFFSET, offset);
629 
630 				(void) nvlist_add_nvlist(rsrc,
631 				    FM_FMRI_HC_SPECIFIC, hsp);
632 			}
633 		}
634 		fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
635 		    fru, rsrc);
636 		nvlist_free(hsp);
637 	} else {
638 		rsrc = get_cpu_fault_resource(hdl, asru);
639 		fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
640 		    fru, rsrc);
641 	}
642 
643 	nvlist_free(rsrc);
644 
645 	return (fllist);
646 }
647