xref: /illumos-gate/usr/src/cmd/fm/modules/common/eversholt/platform.c (revision 60a3f738d56f92ae8b80e4b62a2331c6e1f2311f)
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 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * platform.c -- interfaces to the platform's configuration information
27  *
28  * this platform.c allows eft to run on Solaris systems.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <ctype.h>
38 #include <dirent.h>
39 #include <libnvpair.h>
40 #include <dlfcn.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include <stropts.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <sys/wait.h>
47 #include <sys/filio.h>
48 #include <sys/param.h>
49 #include <sys/fm/protocol.h>
50 #include <fm/fmd_api.h>
51 #include <fm/libtopo.h>
52 #include "alloc.h"
53 #include "out.h"
54 #include "tree.h"
55 #include "itree.h"
56 #include "ipath.h"
57 #include "ptree.h"
58 #include "fme.h"
59 #include "stable.h"
60 #include "eval.h"
61 #include "config.h"
62 #include "platform.h"
63 
64 extern fmd_hdl_t *Hdl;		/* handle from eft.c */
65 
66 /*
67  * Lastcfg points to the last configuration snapshot we made.  If we
68  * need to make a dev to hc scheme conversion of an event path, we use
69  * the last snapshot as a best guess.  If we don't have a last snapshot
70  * we take one and save it in Initcfg below.
71  */
72 static struct cfgdata *Lastcfg;
73 static topo_hdl_t *Eft_topo_hdl;
74 
75 /*
76  * Initcfg points to any config snapshot we have to make prior
77  * to starting our first fme.
78  */
79 static struct cfgdata *Initcfg;
80 
81 void *
82 topo_use_alloc(size_t bytes)
83 {
84 	void *p = alloc_malloc(bytes, NULL, 0);
85 
86 	bzero(p, bytes);
87 	return (p);
88 }
89 
90 void
91 topo_use_free(void *p)
92 {
93 	alloc_free(p, NULL, 0);
94 }
95 
96 /*ARGSUSED*/
97 static void *
98 alloc_nv_alloc(nv_alloc_t *nva, size_t size)
99 {
100 	return (alloc_malloc(size, NULL, 0));
101 }
102 
103 /*ARGSUSED*/
104 static void
105 alloc_nv_free(nv_alloc_t *nva, void *p, size_t sz)
106 {
107 	alloc_free(p, NULL, 0);
108 }
109 
110 const nv_alloc_ops_t Eft_nv_alloc_ops = {
111 	NULL,		/* nv_ao_init() */
112 	NULL,		/* nv_ao_fini() */
113 	alloc_nv_alloc,	/* nv_ao_alloc() */
114 	alloc_nv_free,	/* nv_ao_free() */
115 	NULL		/* nv_ao_reset() */
116 };
117 
118 nv_alloc_t Eft_nv_hdl;
119 
120 static char *Root;
121 static char *Mach;
122 static char *Plat;
123 static char tmpbuf[MAXPATHLEN];
124 static char numbuf[MAXPATHLEN];
125 
126 /*
127  * platform_globals -- set global variables based on sysinfo() calls
128  */
129 static void
130 platform_globals()
131 {
132 	Root = fmd_prop_get_string(Hdl, "fmd.rootdir");
133 	Mach = fmd_prop_get_string(Hdl, "fmd.machine");
134 	Plat = fmd_prop_get_string(Hdl, "fmd.platform");
135 }
136 
137 static void
138 platform_free_globals()
139 {
140 	fmd_prop_free_string(Hdl, Root);
141 	fmd_prop_free_string(Hdl, Mach);
142 	fmd_prop_free_string(Hdl, Plat);
143 }
144 
145 /*
146  * platform_init -- perform any platform-specific initialization
147  */
148 void
149 platform_init(void)
150 {
151 	(void) nv_alloc_init(&Eft_nv_hdl, &Eft_nv_alloc_ops);
152 	Eft_topo_hdl = fmd_hdl_topology(Hdl, TOPO_VERSION);
153 	platform_globals();
154 
155 	out(O_ALTFP, "platform_init() sucessful");
156 }
157 
158 void
159 platform_fini(void)
160 {
161 	if (Lastcfg != NULL) {
162 		config_free(Lastcfg);
163 		Lastcfg = NULL;
164 	}
165 	if (Initcfg != NULL) {
166 		config_free(Initcfg);
167 		Initcfg = NULL;
168 	}
169 
170 	platform_free_globals();
171 	(void) nv_alloc_fini(&Eft_nv_hdl);
172 
173 	out(O_ALTFP, "platform_fini() sucessful");
174 }
175 
176 /*
177  * hc_fmri_nodeize -- convert hc-scheme FMRI to eft compatible format
178  *
179  * this is an internal platform.c helper routine
180  */
181 static struct node *
182 hc_fmri_nodeize(nvlist_t *hcfmri)
183 {
184 	struct node *pathtree = NULL;
185 	struct node *tmpn;
186 	nvlist_t **hc_prs;
187 	uint_t hc_nprs;
188 	const char *sname;
189 	char *ename;
190 	char *eid;
191 	int e, r;
192 
193 	/*
194 	 * What to do with/about hc-root?  Would we have any clue what
195 	 * to do with it if it weren't /?  For now, we don't bother
196 	 * even looking it up.
197 	 */
198 
199 	/*
200 	 * Get the hc-list of elements in the FMRI
201 	 */
202 	if (nvlist_lookup_nvlist_array(hcfmri, FM_FMRI_HC_LIST,
203 	    &hc_prs, &hc_nprs) != 0) {
204 		out(O_ALTFP, "XFILE: hc FMRI missing %s", FM_FMRI_HC_LIST);
205 		return (NULL);
206 	}
207 
208 	for (e = 0; e < hc_nprs; e++) {
209 		ename = NULL;
210 		eid = NULL;
211 		r = nvlist_lookup_string(hc_prs[e], FM_FMRI_HC_NAME, &ename);
212 		r |= nvlist_lookup_string(hc_prs[e], FM_FMRI_HC_ID, &eid);
213 		if (r != 0) {
214 			/* probably should bail */
215 			continue;
216 		}
217 		sname = stable(ename);
218 		tmpn = tree_name_iterator(
219 			tree_name(sname, IT_VERTICAL, NULL, 0),
220 			tree_num(eid, NULL, 0));
221 
222 		if (pathtree == NULL)
223 			pathtree = tmpn;
224 		else
225 			(void) tree_name_append(pathtree, tmpn);
226 	}
227 
228 	return (pathtree);
229 }
230 
231 /*
232  * platform_getpath -- extract eft-compatible path from ereport
233  */
234 struct node *
235 platform_getpath(nvlist_t *nvl)
236 {
237 	struct node *ret;
238 	nvlist_t *dfmri = NULL;
239 	char *scheme = NULL;
240 	char *path = NULL;
241 
242 	/*
243 	 * For now we assume the "path" part of the error report is
244 	 * the detector FMRI
245 	 */
246 	if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &dfmri) != 0) {
247 		out(O_ALTFP, "XFILE: ereport has no detector FMRI");
248 		return (NULL);
249 	}
250 
251 	if (nvlist_lookup_string(dfmri, FM_FMRI_SCHEME, &scheme) != 0) {
252 		out(O_ALTFP, "XFILE: detector FMRI missing scheme");
253 		return (NULL);
254 	}
255 
256 	if (strcmp(scheme, FM_FMRI_SCHEME_HC) != 0) {
257 		/*
258 		 *  later, if FM_FMRI_SCHEME_DEV or FM_FMRI_SCHEME_CPU
259 		 *  we can look and perform a reverse translation into
260 		 *  an hc node
261 		 */
262 		uint32_t id;
263 		int isdev = 0;
264 
265 		out(O_ALTFP|O_VERB, "Received ereport in scheme %s", scheme);
266 		if (strcmp(scheme, FM_FMRI_SCHEME_DEV) == 0) {
267 			isdev = 1;
268 		} else if (strcmp(scheme, FM_FMRI_SCHEME_CPU) != 0) {
269 			out(O_ALTFP, "XFILE: detector FMRI not recognized "
270 			    "(scheme is %s, expect %s or %s or %s)",
271 			    scheme, FM_FMRI_SCHEME_HC, FM_FMRI_SCHEME_DEV,
272 			    FM_FMRI_SCHEME_CPU);
273 			return (NULL);
274 		}
275 
276 		if (isdev == 1 &&
277 		    nvlist_lookup_string(dfmri, FM_FMRI_DEV_PATH, &path) != 0) {
278 			out(O_ALTFP, "XFILE: detector FMRI missing %s",
279 			    FM_FMRI_DEV_PATH);
280 			return (NULL);
281 		} else if (isdev == 0 &&
282 		    nvlist_lookup_uint32(dfmri, FM_FMRI_CPU_ID, &id) != 0) {
283 			out(O_ALTFP, "XFILE: detector FMRI missing %s",
284 			    FM_FMRI_CPU_ID);
285 			return (NULL);
286 		}
287 
288 		/*
289 		 * If we haven't taken a config snapshot yet, we need
290 		 * to do so now.  The call to config_snapshot() has the
291 		 * side-effect of setting Lastcfg.  We squirrel away the
292 		 * pointer to this snapshot so we may free it later.
293 		 */
294 		if (Lastcfg == NULL)
295 			if ((Initcfg = config_snapshot()) == NULL) {
296 				out(O_ALTFP,
297 				    "XFILE: cannot snapshot configuration");
298 				return (NULL);
299 			}
300 
301 		/*
302 		 * Look up the path or cpu id in the last config snapshot.
303 		 */
304 		if (isdev == 1 &&
305 		    (ret = config_bydev_lookup(Lastcfg, path)) == NULL)
306 			out(O_ALTFP, "XFILE: no configuration node has "
307 			    "device path matching %s.", path);
308 		else if (isdev == 0 &&
309 		    (ret = config_bycpuid_lookup(Lastcfg, id)) == NULL)
310 			out(O_ALTFP, "XFILE: no configuration node has "
311 			    "cpu-id matching %u.", id);
312 
313 		return (ret);
314 	}
315 
316 	return (hc_fmri_nodeize(dfmri));
317 }
318 
319 /* Allocate space for raw config strings in chunks of this size */
320 #define	STRSBUFLEN	512
321 
322 /*
323  * cfgadjust -- Make sure the amount we want to add to the raw config string
324  *		buffer will fit, and if not, increase the size of the buffer.
325  */
326 static void
327 cfgadjust(struct cfgdata *rawdata, int addlen)
328 {
329 	int curnext, newlen;
330 
331 	if (rawdata->nextfree + addlen >= rawdata->end) {
332 		newlen = (((rawdata->nextfree - rawdata->begin + 1 + addlen)
333 		    / STRSBUFLEN) + 1) * STRSBUFLEN;
334 		curnext = rawdata->nextfree - rawdata->begin;
335 		rawdata->begin = REALLOC(rawdata->begin, newlen);
336 		rawdata->nextfree = rawdata->begin + curnext;
337 		rawdata->end = rawdata->begin + newlen;
338 	}
339 }
340 
341 static char *
342 hc_path(tnode_t *node)
343 {
344 	int i, err;
345 	char *name, *instance, *estr;
346 	nvlist_t *fmri, **hcl;
347 	ulong_t ul;
348 	uint_t nhc;
349 
350 	if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE,
351 	    &fmri, &err) < 0)
352 		return (NULL);
353 
354 	if (nvlist_lookup_nvlist_array(fmri, FM_FMRI_HC_LIST, &hcl, &nhc)
355 	    != 0) {
356 		nvlist_free(fmri);
357 		return (NULL);
358 	}
359 
360 	tmpbuf[0] = '\0';
361 	for (i = 0; i < nhc; ++i) {
362 		err = nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name);
363 		err |= nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &instance);
364 		if (err) {
365 			nvlist_free(fmri);
366 			return (NULL);
367 		}
368 
369 		ul = strtoul(instance, &estr, 10);
370 		/* conversion to number failed? */
371 		if (estr == instance) {
372 			nvlist_free(fmri);
373 			return (NULL);
374 		}
375 
376 		(void) strlcat(tmpbuf, "/", MAXPATHLEN);
377 		(void) strlcat(tmpbuf, name, MAXPATHLEN);
378 		(void) snprintf(numbuf, MAXPATHLEN, "%u", ul);
379 		(void) strlcat(tmpbuf, numbuf, MAXPATHLEN);
380 	}
381 
382 	nvlist_free(fmri);
383 
384 	return (tmpbuf);
385 }
386 
387 static void
388 add_prop_val(topo_hdl_t *thp, struct cfgdata *rawdata, char *propn,
389     nvpair_t *pv_nvp)
390 {
391 	int addlen, err;
392 	char *propv, *fmristr = NULL;
393 	nvlist_t *fmri;
394 	uint64_t ui64;
395 	char buf[32];	/* big enough for any 64-bit int */
396 
397 	/*
398 	 * We can only handle properties of string type
399 	 */
400 	switch (nvpair_type(pv_nvp)) {
401 	case DATA_TYPE_STRING:
402 		(void) nvpair_value_string(pv_nvp, &propv);
403 		break;
404 
405 	case DATA_TYPE_NVLIST:
406 		/*
407 		 * At least try to collect the protocol
408 		 * properties
409 		 */
410 		(void) nvpair_value_nvlist(pv_nvp, &fmri);
411 		if (topo_fmri_nvl2str(thp, fmri, &fmristr, &err) < 0) {
412 			out(O_ALTFP, "cfgcollect: failed to convert fmri to "
413 			    "string");
414 			return;
415 		} else {
416 			propv = fmristr;
417 		}
418 		break;
419 
420 	case DATA_TYPE_UINT64:
421 		/*
422 		 * Convert uint64 to hex strings
423 		 */
424 		(void) nvpair_value_uint64(pv_nvp, &ui64);
425 		(void) snprintf(buf, sizeof (buf), "0x%llx", ui64);
426 		propv = buf;
427 		break;
428 
429 	default:
430 		return;
431 	}
432 
433 	/* = & NULL */
434 	addlen = strlen(propn) + strlen(propv) + 2;
435 	cfgadjust(rawdata, addlen);
436 	(void) snprintf(rawdata->nextfree,
437 	    rawdata->end - rawdata->nextfree, "%s=%s",
438 	    propn, propv);
439 	rawdata->nextfree += addlen;
440 
441 	if (fmristr != NULL)
442 		topo_hdl_strfree(thp, fmristr);
443 }
444 
445 /*
446  * cfgcollect -- Assemble raw configuration data in string form suitable
447  *		 for checkpointing.
448  */
449 static int
450 cfgcollect(topo_hdl_t *thp, tnode_t *node, void *arg)
451 {
452 	struct cfgdata *rawdata = (struct cfgdata *)arg;
453 	int addlen;
454 	char *propn, *path = NULL;
455 	nvlist_t *p_nv, *pg_nv, *pv_nv;
456 	nvpair_t *nvp, *pg_nvp, *pv_nvp;
457 
458 	path = hc_path(node);
459 	if (path == NULL)
460 		return (TOPO_WALK_ERR);
461 
462 	addlen = strlen(path) + 1;
463 
464 	cfgadjust(rawdata, addlen);
465 	(void) strcpy(rawdata->nextfree, path);
466 	rawdata->nextfree += addlen;
467 
468 	/*
469 	 * Collect properties
470 	 *
471 	 * eversholt should support alternate property types
472 	 * Better yet, topo properties could be represented as
473 	 * a packed nvlist
474 	 */
475 	p_nv = topo_prop_get_all(thp, node);
476 	for (nvp = nvlist_next_nvpair(p_nv, NULL); nvp != NULL;
477 	    nvp = nvlist_next_nvpair(p_nv, nvp)) {
478 		if (strcmp(TOPO_PROP_GROUP, nvpair_name(nvp)) != 0 ||
479 		    nvpair_type(nvp) != DATA_TYPE_NVLIST)
480 			continue;
481 
482 		(void) nvpair_value_nvlist(nvp, &pg_nv);
483 
484 		for (pg_nvp = nvlist_next_nvpair(pg_nv, NULL); pg_nvp != NULL;
485 		    pg_nvp = nvlist_next_nvpair(pg_nv, pg_nvp)) {
486 
487 			if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp)) != 0 ||
488 			    nvpair_type(pg_nvp) != DATA_TYPE_NVLIST)
489 				continue;
490 
491 			(void) nvpair_value_nvlist(pg_nvp, &pv_nv);
492 
493 			for (pv_nvp = nvlist_next_nvpair(pv_nv, NULL);
494 			    pv_nvp != NULL;
495 			    pv_nvp = nvlist_next_nvpair(pv_nv, pv_nvp)) {
496 
497 				/* Get property name */
498 				propn = nvpair_name(pv_nvp);
499 				if (strcmp(TOPO_PROP_VAL_NAME, propn) != 0)
500 					continue;
501 				if (nvpair_value_string(pv_nvp, &propn) != 0)
502 					continue;
503 
504 				/*
505 				 * Get property value
506 				 */
507 				pv_nvp = nvlist_next_nvpair(pv_nv, pv_nvp);
508 				add_prop_val(thp, rawdata, propn, pv_nvp);
509 			}
510 
511 		}
512 	}
513 
514 	nvlist_free(p_nv);
515 
516 	return (TOPO_WALK_NEXT);
517 }
518 
519 /*
520  * platform_config_snapshot -- gather a snapshot of the current configuration
521  */
522 struct cfgdata *
523 platform_config_snapshot(void)
524 {
525 	int err;
526 	char *uuid;
527 	topo_walk_t *twp;
528 
529 	/*
530 	 *
531 	 * If the DR generation number has changed,
532 	 * we need to grab a new snapshot, otherwise we
533 	 * can simply point them at the last config.
534 	 *
535 	 *	svgen = DRgen;
536 	 *	if (svgen == (Drgen = fmd_drgen_get()) && Lastcfg != NULL) {
537 	 *		Lastcfg->refcnt++;
538 	 *		return (Lastcfg);
539 	 *	}
540 	 */
541 
542 	/* we're getting a new config, so clean up the last one */
543 	if (Lastcfg != NULL)
544 		config_free(Lastcfg);
545 
546 	Lastcfg = MALLOC(sizeof (struct cfgdata));
547 	Lastcfg->refcnt = 2;	/* caller + Lastcfg */
548 	Lastcfg->begin = Lastcfg->nextfree = Lastcfg->end = NULL;
549 	Lastcfg->cooked = NULL;
550 	Lastcfg->devcache = NULL;
551 	Lastcfg->cpucache = NULL;
552 
553 	out(O_ALTFP, "platform_config_snapshot(): topo snapshot");
554 	if ((uuid = topo_snap_hold(Eft_topo_hdl, NULL, &err)) == NULL)
555 		out(O_DIE, "platform_config_snapshot: topo snapshot failed: %s",
556 		    topo_strerror(err));
557 
558 	if ((twp = topo_walk_init(Eft_topo_hdl, FM_FMRI_SCHEME_HC, cfgcollect,
559 	    Lastcfg, &err)) == NULL) {
560 		topo_hdl_strfree(Eft_topo_hdl, uuid);
561 		out(O_DIE, "platform_config_snapshot: NULL topology tree: %s",
562 		    topo_strerror(err));
563 	}
564 
565 	if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) {
566 		topo_hdl_strfree(Eft_topo_hdl, uuid);
567 		topo_walk_fini(twp);
568 		out(O_DIE, "platform_config_snapshot: error walking topology "
569 		    "tree");
570 	}
571 
572 	topo_walk_fini(twp);
573 
574 	topo_hdl_strfree(Eft_topo_hdl, uuid);
575 	topo_snap_release(Eft_topo_hdl);
576 
577 	return (Lastcfg);
578 }
579 
580 static const char *
581 cfgstrprop_lookup(struct config *croot, char *path, char *pname)
582 {
583 	struct config *cresource;
584 	const char *fmristr;
585 
586 	/*
587 	 * The first order of business is to find the resource in the
588 	 * config database so we can examine properties associated with
589 	 * that node.
590 	 */
591 	if ((cresource = config_lookup(croot, path, 0)) == NULL) {
592 		out(O_ALTFP, "Cannot find config info for %s.", path);
593 		return (NULL);
594 	}
595 	if ((fmristr = config_getprop(cresource, pname)) == NULL) {
596 		out(O_ALTFP, "Cannot find %s property for %s resource "
597 		    "re-write", pname, path);
598 		return (NULL);
599 	}
600 	return (fmristr);
601 }
602 
603 static nvlist_t *
604 rewrite_resource(char *pname, struct config *croot, char *path)
605 {
606 	const char *fmristr;
607 	nvlist_t *fmri;
608 	int err;
609 
610 	if ((fmristr = cfgstrprop_lookup(croot, path, pname)) == NULL)
611 		return (NULL);
612 
613 	if (topo_fmri_str2nvl(Eft_topo_hdl, fmristr, &fmri, &err) < 0) {
614 		out(O_ALTFP, "Can not convert config info: %s",
615 		    topo_strerror(err));
616 		return (NULL);
617 	}
618 
619 	return (fmri);
620 }
621 
622 static void
623 defect_units(nvlist_t **ap, nvlist_t **fp, struct config *croot, char *path)
624 {
625 	const char *driverstr;
626 	nvlist_t *cf, *nf;
627 	nvlist_t *na;
628 	nvlist_t *arg;
629 	int err;
630 
631 	/*
632 	 * Defects aren't required to have ASRUs and FRUs defined with
633 	 * them in the eversholt fault tree, so usually we'll be
634 	 * creating original FMRIs here.  If either the ASRU or FRU
635 	 * is defined when we get here, we won't replace it.
636 	 */
637 	if (*ap != NULL && *fp != NULL)
638 		return;
639 
640 	/*
641 	 * Find the driver for this resource and use that to get
642 	 * mod and pkg fmris for ASRU and FRU respectively.
643 	 */
644 	if ((driverstr = cfgstrprop_lookup(croot, path, "DRIVER")) == NULL)
645 		return;
646 
647 	if (topo_hdl_nvalloc(Eft_topo_hdl, &arg, NV_UNIQUE_NAME) != 0) {
648 		out(O_ALTFP, "Can not allocate nvlist for MOD fmri lookup");
649 		return;
650 	}
651 	if (nvlist_add_string(arg, "DRIVER", driverstr) != 0) {
652 		out(O_ALTFP, "Failed to add DRIVER string to arg nvlist");
653 		nvlist_free(arg);
654 		return;
655 	}
656 	na = topo_fmri_create(Eft_topo_hdl, FM_FMRI_SCHEME_MOD,
657 	    FM_FMRI_SCHEME_MOD, 0, arg, &err);
658 	if (na == NULL) {
659 		out(O_ALTFP, "topo_fmri_create() of %s scheme fmri"
660 		    " for driver %s failed.", FM_FMRI_SCHEME_MOD, driverstr);
661 		nvlist_free(arg);
662 		return;
663 	}
664 	nvlist_free(arg);
665 
666 	if (*ap != NULL)
667 		nvlist_free(*ap);
668 	*ap = na;
669 
670 	err = nvlist_lookup_nvlist(na, FM_FMRI_MOD_PKG, &cf);
671 	if (err != 0) {
672 		out(O_ALTFP, "No pkg RTI within mod FMRI for %s (%s)\n",
673 		    driverstr, topo_strerror(err));
674 		return;
675 	}
676 	if (nvlist_xdup(cf, &nf, &Eft_nv_hdl) != 0) {
677 		out(O_ALTFP, "Dup of pkg FMRI to be FRU FMRI failed\n");
678 		return;
679 	}
680 	if (*fp != NULL)
681 		nvlist_free(*fp);
682 	*fp = nf;
683 }
684 
685 /*
686  * platform_units_translate
687  *	This routines offers a chance for platform-specific rewrites of
688  *	the hc scheme FRU and ASRUs associated with a suspect fault.
689  */
690 /*ARGSUSED*/
691 void
692 platform_units_translate(int isdefect, struct config *croot,
693     nvlist_t **dfltasru, nvlist_t **dfltfru, nvlist_t **dfltrsrc, char *path)
694 {
695 	nvlist_t *asru, *rsrc, *fru;
696 
697 	out(O_ALTFP, "platform_units_translate(%d, ....)", isdefect);
698 
699 	/*
700 	 * Get our FMRIs from libtopo
701 	 */
702 	if ((rsrc = rewrite_resource(TOPO_PROP_RESOURCE, croot, path))
703 	    == NULL) {
704 		out(O_ALTFP, "Cannot rewrite resource for %s.", path);
705 	} else {
706 		nvlist_free(*dfltrsrc);
707 		*dfltrsrc = rsrc;
708 	}
709 
710 	/*
711 	 * If it is a defect we want to re-write the FRU as the pkg
712 	 * scheme fmri of the package containing the buggy driver, and
713 	 * the ASRU as the mod scheme fmri of the driver's kernel
714 	 * module.
715 	 */
716 	if (isdefect) {
717 		defect_units(dfltasru, dfltfru, croot, path);
718 		return;
719 	}
720 
721 	/*
722 	 * Find the TOPO_PROP_ASRU and TOPO_PROP_FRU properties
723 	 * for this resource
724 	 */
725 	if ((asru = rewrite_resource(TOPO_PROP_ASRU, croot, path)) == NULL) {
726 		out(O_ALTFP, "Cannot rewrite %s for %s.", TOPO_PROP_ASRU, path);
727 	} else {
728 		nvlist_free(*dfltasru);
729 		*dfltasru = asru;
730 	}
731 
732 	if ((fru = rewrite_resource(TOPO_PROP_FRU, croot, path)) == NULL) {
733 		out(O_ALTFP, "Cannot rewrite %s for %s.",
734 		    TOPO_PROP_FRU, path);
735 	} else {
736 		nvlist_free(*dfltfru);
737 		*dfltfru = fru;
738 	}
739 }
740 
741 /*
742  * platform_get_files -- return names of all files we should load
743  *
744  * search directories in dirname[] for all files with names ending with the
745  * substring fnstr.  dirname[] should be a NULL-terminated array.  fnstr
746  * may be set to "*" to indicate all files in a directory.
747  *
748  * if nodups is non-zero, then the first file of a given name found is
749  * the only file added to the list of names.  for example if nodups is
750  * set and we're looking for .efts, and find a pci.eft in the dirname[0],
751  * then no pci.eft found in any of the other dirname[] entries will be
752  * included in the final list of names.
753  *
754  * this routine doesn't return NULL, even if no files are found (in that
755  * case, a char ** is returned with the first element NULL).
756  */
757 static char **
758 platform_get_files(const char *dirname[], const char *fnstr, int nodups)
759 {
760 	DIR *dirp;
761 	struct dirent *dp;
762 	struct lut *foundnames = NULL;
763 	char **files = NULL;	/* char * array of filenames found */
764 	int nfiles = 0;		/* files found so far */
765 	int slots = 0;		/* char * slots allocated in files */
766 	size_t fnlen, d_namelen;
767 	size_t totlen;
768 	int i;
769 	static char *nullav;
770 
771 	ASSERT(fnstr != NULL);
772 	fnlen = strlen(fnstr);
773 
774 	for (i = 0; dirname[i] != NULL; i++) {
775 		out(O_DEBUG, "Looking for %s files in %s", fnstr, dirname[i]);
776 		if ((dirp = opendir(dirname[i])) == NULL) {
777 			out(O_DEBUG|O_SYS,
778 			    "platform_get_files: opendir failed for %s",
779 			    dirname[i]);
780 			continue;
781 		}
782 		while ((dp = readdir(dirp)) != NULL) {
783 			if ((fnlen == 1 && *fnstr == '*') ||
784 			    ((d_namelen = strlen(dp->d_name)) >= fnlen &&
785 			    strncmp(dp->d_name + d_namelen - fnlen,
786 			    fnstr, fnlen) == 0)) {
787 
788 				if (nodups != 0) {
789 					const char *snm = stable(dp->d_name);
790 
791 					if (lut_lookup(foundnames,
792 					    (void *)snm,
793 					    NULL) != NULL) {
794 						out(O_DEBUG,
795 						    "platform_get_files: "
796 						    "skipping repeated name "
797 						    "%s/%s",
798 						    dirname[i],
799 						    snm);
800 						continue;
801 					}
802 					foundnames = lut_add(foundnames,
803 					    (void *)snm,
804 					    (void *)snm,
805 					    NULL);
806 				}
807 
808 				if (nfiles > slots - 2) {
809 					/* allocate ten more slots */
810 					slots += 10;
811 					files = (char **)REALLOC(files,
812 						slots * sizeof (char *));
813 				}
814 				/* prepend directory name and / */
815 				totlen = strlen(dirname[i]) + 1;
816 				totlen += strlen(dp->d_name) + 1;
817 				files[nfiles] = MALLOC(totlen);
818 				out(O_DEBUG, "File %d: \"%s/%s\"", nfiles,
819 				    dirname[i], dp->d_name);
820 				(void) snprintf(files[nfiles++], totlen,
821 				    "%s/%s", dirname[i], dp->d_name);
822 			}
823 		}
824 		(void) closedir(dirp);
825 	}
826 
827 	if (foundnames != NULL)
828 		lut_free(foundnames, NULL, NULL);
829 
830 	if (nfiles == 0)
831 		return (&nullav);
832 
833 	files[nfiles] = NULL;
834 	return (files);
835 }
836 
837 /*
838  * search for files in a standard set of directories
839  */
840 static char **
841 platform_get_files_stddirs(char *fname, int nodups)
842 {
843 	const char *dirlist[4];
844 	char **flist;
845 	char *eftgendir, *eftmachdir, *eftplatdir;
846 
847 	eftgendir = MALLOC(MAXPATHLEN);
848 	eftmachdir = MALLOC(MAXPATHLEN);
849 	eftplatdir = MALLOC(MAXPATHLEN);
850 
851 	/* Generic files that apply to any machine */
852 	(void) snprintf(eftgendir, MAXPATHLEN, "%s/usr/lib/fm/eft", Root);
853 
854 	(void) snprintf(eftmachdir,
855 	    MAXPATHLEN, "%s/usr/platform/%s/lib/fm/eft", Root, Mach);
856 
857 	(void) snprintf(eftplatdir,
858 	    MAXPATHLEN, "%s/usr/platform/%s/lib/fm/eft", Root, Plat);
859 
860 	dirlist[0] = eftplatdir;
861 	dirlist[1] = eftmachdir;
862 	dirlist[2] = eftgendir;
863 	dirlist[3] = NULL;
864 
865 	flist = platform_get_files(dirlist, fname, nodups);
866 
867 	FREE(eftplatdir);
868 	FREE(eftmachdir);
869 	FREE(eftgendir);
870 
871 	return (flist);
872 }
873 
874 /*
875  * platform_run_poller -- execute a poller
876  *
877  * when eft needs to know if a polled ereport exists this routine
878  * is called so the poller code may be run in a platform-specific way.
879  * there's no return value from this routine -- either the polled ereport
880  * is generated (and delivered *before* this routine returns) or not.
881  * any errors, like "poller unknown" are considered platform-specific
882  * should be handled here rather than passing an error back up.
883  */
884 /*ARGSUSED*/
885 void
886 platform_run_poller(const char *poller)
887 {
888 }
889 
890 /*
891  * fork and execve path with argument array argv and environment array
892  * envp.  data from stdout and stderr are placed in outbuf and errbuf,
893  * respectively.
894  *
895  * see execve(2) for more descriptions for path, argv and envp.
896  */
897 static int
898 forkandexecve(const char *path, char *const argv[], char *const envp[],
899 	char *outbuf, size_t outbuflen, char *errbuf, size_t errbuflen)
900 {
901 	pid_t pid;
902 	int outpipe[2], errpipe[2];
903 	int rt = 0;
904 
905 	/*
906 	 * run the cmd and see if it failed.  this function is *not* a
907 	 * generic command runner -- we depend on some knowledge we
908 	 * have about the commands we run.  first of all, we expect
909 	 * errors to spew something to stdout, and that something is
910 	 * typically short enough to fit into a pipe so we can wait()
911 	 * for the command to complete and then fetch the error text
912 	 * from the pipe.
913 	 */
914 	if (pipe(outpipe) < 0)
915 		if (strlcat(errbuf, ": pipe(outpipe) failed",
916 			    errbuflen) >= errbuflen)
917 			return (1);
918 	if (pipe(errpipe) < 0)
919 		if (strlcat(errbuf, ": pipe(errpipe) failed",
920 			    errbuflen) >= errbuflen)
921 			return (1);
922 
923 	if ((pid = fork()) < 0)
924 		rt = (int)strlcat(errbuf, ": fork() failed", errbuflen);
925 	else if (pid) {
926 		int wstat, count;
927 
928 		/* parent */
929 		(void) close(errpipe[1]);
930 		(void) close(outpipe[1]);
931 
932 		/* PHASE2 need to guard against hang in child? */
933 		if (waitpid(pid, &wstat, 0) < 0)
934 			if (strlcat(errbuf, ": waitpid() failed",
935 				    errbuflen) >= errbuflen)
936 				return (1);
937 
938 		/* check for stderr contents */
939 		if (ioctl(errpipe[0], FIONREAD, &count) >= 0 && count) {
940 			if (read(errpipe[0], errbuf, errbuflen) <= 0) {
941 				/*
942 				 * read failed even though ioctl indicated
943 				 * that nonzero bytes were available for
944 				 * reading
945 				 */
946 				if (strlcat(errbuf, ": read(errpipe) failed",
947 					    errbuflen) >= errbuflen)
948 					return (1);
949 			}
950 			/*
951 			 * handle case where errbuf is not properly
952 			 * terminated
953 			 */
954 			if (count > errbuflen - 1)
955 				count = errbuflen - 1;
956 			if (errbuf[count - 1] != '\0' &&
957 			    errbuf[count - 1] != '\n')
958 				errbuf[count] = '\0';
959 		} else if (WIFSIGNALED(wstat))
960 			if (strlcat(errbuf, ": signaled",
961 				    errbuflen) >= errbuflen)
962 				return (1);
963 		else if (WIFEXITED(wstat) && WEXITSTATUS(wstat))
964 			if (strlcat(errbuf, ": abnormal exit",
965 				    errbuflen) >= errbuflen)
966 				return (1);
967 
968 		/* check for stdout contents */
969 		if (ioctl(outpipe[0], FIONREAD, &count) >= 0 && count) {
970 			if (read(outpipe[0], outbuf, outbuflen) <= 0) {
971 				/*
972 				 * read failed even though ioctl indicated
973 				 * that nonzero bytes were available for
974 				 * reading
975 				 */
976 				if (strlcat(errbuf, ": read(outpipe) failed",
977 					    errbuflen) >= errbuflen)
978 					return (1);
979 			}
980 			/*
981 			 * handle case where outbuf is not properly
982 			 * terminated
983 			 */
984 			if (count > outbuflen - 1)
985 				count = outbuflen - 1;
986 			if (outbuf[count - 1] != '\0' &&
987 			    outbuf[count - 1] != '\n')
988 				outbuf[count] = '\0';
989 		}
990 
991 		(void) close(errpipe[0]);
992 		(void) close(outpipe[0]);
993 	} else {
994 		/* child */
995 		(void) dup2(errpipe[1], fileno(stderr));
996 		(void) close(errpipe[0]);
997 		(void) dup2(outpipe[1], fileno(stdout));
998 		(void) close(outpipe[0]);
999 
1000 		if (execve(path, argv, envp))
1001 			perror(path);
1002 		_exit(1);
1003 	}
1004 
1005 	return (rt);
1006 }
1007 
1008 #define	MAXDIGITIDX	23
1009 
1010 static int
1011 arglist2argv(struct node *np, struct lut **globals, struct config *croot,
1012 	struct arrow *arrowp, char ***argv, int *argc, int *argvlen)
1013 {
1014 	struct node *namep;
1015 	char numbuf[MAXDIGITIDX + 1];
1016 	char *numstr, *nullbyte;
1017 	char *addthisarg = NULL;
1018 
1019 	if (np == NULL)
1020 		return (0);
1021 
1022 	switch (np->t) {
1023 	case T_QUOTE:
1024 		addthisarg = STRDUP(np->u.func.s);
1025 		break;
1026 	case T_LIST:
1027 		if (arglist2argv(np->u.expr.left, globals, croot, arrowp,
1028 				argv, argc, argvlen))
1029 			return (1);
1030 		/*
1031 		 * only leftmost element of a list can provide the command
1032 		 * name (after which *argc becomes 1)
1033 		 */
1034 		ASSERT(*argc > 0);
1035 		if (arglist2argv(np->u.expr.right, globals, croot, arrowp,
1036 				argv, argc, argvlen))
1037 			return (1);
1038 		break;
1039 	case T_FUNC:
1040 	case T_GLOBID:
1041 	case T_ASSIGN:
1042 	case T_CONDIF:
1043 	case T_CONDELSE:
1044 	case T_EQ:
1045 	case T_NE:
1046 	case T_LT:
1047 	case T_LE:
1048 	case T_GT:
1049 	case T_GE:
1050 	case T_BITAND:
1051 	case T_BITOR:
1052 	case T_BITXOR:
1053 	case T_BITNOT:
1054 	case T_LSHIFT:
1055 	case T_RSHIFT:
1056 	case T_AND:
1057 	case T_OR:
1058 	case T_NOT:
1059 	case T_ADD:
1060 	case T_SUB:
1061 	case T_MUL:
1062 	case T_DIV:
1063 	case T_MOD: {
1064 		struct evalue value;
1065 
1066 		if (!eval_expr(np, NULL, NULL, globals, croot, arrowp,
1067 			    0, &value))
1068 			return (1);
1069 
1070 		switch (value.t) {
1071 		case UINT64:
1072 			numbuf[MAXDIGITIDX] = '\0';
1073 			nullbyte = &numbuf[MAXDIGITIDX];
1074 			numstr = ulltostr(value.v, nullbyte);
1075 			addthisarg = STRDUP(numstr);
1076 			break;
1077 		case STRING:
1078 			addthisarg = STRDUP((const char *)(uintptr_t)value.v);
1079 			break;
1080 		case NODEPTR :
1081 			namep = (struct node *)(uintptr_t)value.v;
1082 			addthisarg = ipath2str(NULL, ipath(namep));
1083 			break;
1084 		default:
1085 			out(O_ERR,
1086 			    "call: arglist2argv: unexpected result from"
1087 			    " operation %s",
1088 			    ptree_nodetype2str(np->t));
1089 			return (1);
1090 		}
1091 		break;
1092 	}
1093 	case T_NUM:
1094 	case T_TIMEVAL:
1095 		numbuf[MAXDIGITIDX] = '\0';
1096 		nullbyte = &numbuf[MAXDIGITIDX];
1097 		numstr = ulltostr(np->u.ull, nullbyte);
1098 		addthisarg = STRDUP(numstr);
1099 		break;
1100 	case T_NAME:
1101 		addthisarg = ipath2str(NULL, ipath(np));
1102 		break;
1103 	case T_EVENT:
1104 		addthisarg = ipath2str(np->u.event.ename->u.name.s,
1105 		    ipath(np->u.event.epname));
1106 		break;
1107 	default:
1108 		out(O_ERR, "call: arglist2argv: node type %s is unsupported",
1109 		    ptree_nodetype2str(np->t));
1110 		return (1);
1111 		/*NOTREACHED*/
1112 		break;
1113 	}
1114 
1115 	if (*argc == 0 && addthisarg != NULL) {
1116 		/*
1117 		 * first argument added is the command name.
1118 		 */
1119 		char **files;
1120 
1121 		files = platform_get_files_stddirs(addthisarg, 0);
1122 
1123 		/* do not proceed if number of files found != 1 */
1124 		if (files[0] == NULL)
1125 			out(O_DIE, "call: function %s not found", addthisarg);
1126 		if (files[1] != NULL)
1127 			out(O_DIE, "call: multiple functions %s found",
1128 			    addthisarg);
1129 		FREE(addthisarg);
1130 
1131 		addthisarg = STRDUP(files[0]);
1132 		FREE(files[0]);
1133 		FREE(files);
1134 	}
1135 
1136 	if (addthisarg != NULL) {
1137 		if (*argc >= *argvlen - 2) {
1138 			/*
1139 			 * make sure argv is long enough so it has a
1140 			 * terminating element set to NULL
1141 			 */
1142 			*argvlen += 10;
1143 			*argv = (char **)REALLOC(*argv,
1144 						sizeof (char *) * *argvlen);
1145 		}
1146 		(*argv)[*argc] = addthisarg;
1147 		(*argc)++;
1148 		(*argv)[*argc] = NULL;
1149 	}
1150 
1151 	return (0);
1152 }
1153 
1154 static int
1155 generate_envp(struct arrow *arrowp, char ***envp, int *envc, int *envplen)
1156 {
1157 	char *envnames[] = { "EFT_FROM_EVENT", "EFT_TO_EVENT",
1158 			    "EFT_FILE", "EFT_LINE", NULL };
1159 	char *envvalues[4];
1160 	char *none = "(none)";
1161 	size_t elen;
1162 	int i;
1163 
1164 	*envc = 4;
1165 
1166 	/*
1167 	 * make sure envp is long enough so it has a terminating element
1168 	 * set to NULL
1169 	 */
1170 	*envplen = *envc + 1;
1171 	*envp = (char **)MALLOC(sizeof (char *) * *envplen);
1172 
1173 	envvalues[0] = ipath2str(
1174 	    arrowp->tail->myevent->enode->u.event.ename->u.name.s,
1175 	    arrowp->tail->myevent->ipp);
1176 	envvalues[1] = ipath2str(
1177 	    arrowp->head->myevent->enode->u.event.ename->u.name.s,
1178 	    arrowp->head->myevent->ipp);
1179 
1180 	if (arrowp->head->myevent->enode->file == NULL) {
1181 		envvalues[2] = STRDUP(none);
1182 		envvalues[3] = STRDUP(none);
1183 	} else {
1184 		envvalues[2] = STRDUP(arrowp->head->myevent->enode->file);
1185 
1186 		/* large enough for max int */
1187 		envvalues[3] = MALLOC(sizeof (char) * 25);
1188 		(void) snprintf(envvalues[3], sizeof (envvalues[3]), "%d",
1189 				arrowp->head->myevent->enode->line);
1190 	}
1191 
1192 	for (i = 0; envnames[i] != NULL && i < *envc; i++) {
1193 		elen = strlen(envnames[i]) + strlen(envvalues[i]) + 2;
1194 		(*envp)[i] = MALLOC(elen);
1195 		(void) snprintf((*envp)[i], elen, "%s=%s",
1196 		    envnames[i], envvalues[i]);
1197 		FREE(envvalues[i]);
1198 	}
1199 	(*envp)[*envc] = NULL;
1200 
1201 	return (0);
1202 }
1203 
1204 /*
1205  * platform_call -- call an external function
1206  *
1207  * evaluate a user-defined function and place result in valuep.  return 0
1208  * if function evaluation was successful; 1 if otherwise.
1209  */
1210 int
1211 platform_call(struct node *np, struct lut **globals, struct config *croot,
1212 	struct arrow *arrowp, struct evalue *valuep)
1213 {
1214 	/*
1215 	 * use rather short buffers.  only the first string on outbuf[] is
1216 	 * taken as output from the called function.  any message in
1217 	 * errbuf[] is echoed out as an error message.
1218 	 */
1219 	char outbuf[256], errbuf[512];
1220 	struct stat buf;
1221 	char **argv, **envp;
1222 	int argc, argvlen, envc, envplen;
1223 	int i, ret;
1224 
1225 	/*
1226 	 * np is the argument list.  the user-defined function is the first
1227 	 * element of the list.
1228 	 */
1229 	ASSERT(np->t == T_LIST);
1230 
1231 	argv = NULL;
1232 	argc = 0;
1233 	argvlen = 0;
1234 	if (arglist2argv(np, globals, croot, arrowp, &argv, &argc, &argvlen) ||
1235 	    argc == 0)
1236 		return (1);
1237 
1238 	/*
1239 	 * make sure program has executable bit set
1240 	 */
1241 	if (stat(argv[0], &buf) == 0) {
1242 		int exec_bit_set = 0;
1243 
1244 		if (buf.st_uid == geteuid() && buf.st_mode & S_IXUSR)
1245 			exec_bit_set = 1;
1246 		else if (buf.st_gid == getegid() && buf.st_mode & S_IXGRP)
1247 			exec_bit_set = 1;
1248 		else if (buf.st_mode & S_IXOTH)
1249 			exec_bit_set = 1;
1250 
1251 		if (exec_bit_set == 0)
1252 			out(O_DIE, "call: executable bit not set on %s",
1253 			    argv[0]);
1254 	} else {
1255 		out(O_DIE, "call: failure in stat(), errno = %d\n", errno);
1256 	}
1257 
1258 	envp = NULL;
1259 	envc = 0;
1260 	envplen = 0;
1261 	if (generate_envp(arrowp, &envp, &envc, &envplen))
1262 		return (1);
1263 
1264 	outbuf[0] = '\0';
1265 	errbuf[0] = '\0';
1266 
1267 	ret = forkandexecve((const char *) argv[0], (char *const *) argv,
1268 			    (char *const *) envp, outbuf, sizeof (outbuf),
1269 			    errbuf, sizeof (errbuf));
1270 
1271 	for (i = 0; i < envc; i++)
1272 		FREE(envp[i]);
1273 	if (envp)
1274 		FREE(envp);
1275 
1276 	if (ret) {
1277 		outfl(O_OK, np->file, np->line,
1278 			"call: failure in fork + exec of %s", argv[0]);
1279 	} else {
1280 		char *ptr;
1281 
1282 		/* chomp the result */
1283 		for (ptr = outbuf; *ptr; ptr++)
1284 			if (*ptr == '\n' || *ptr == '\r') {
1285 				*ptr = '\0';
1286 				break;
1287 			}
1288 		valuep->t = STRING;
1289 		valuep->v = (uintptr_t)stable(outbuf);
1290 	}
1291 
1292 	if (errbuf[0] != '\0') {
1293 		ret = 1;
1294 		outfl(O_OK, np->file, np->line,
1295 			"call: unexpected stderr output from %s: %s",
1296 			argv[0], errbuf);
1297 	}
1298 
1299 	for (i = 0; i < argc; i++)
1300 		FREE(argv[i]);
1301 	FREE(argv);
1302 
1303 	return (ret);
1304 }
1305 
1306 /*
1307  * platform_confcall -- call a configuration database function
1308  *
1309  * returns result in *valuep, return 0 on success
1310  */
1311 /*ARGSUSED*/
1312 int
1313 platform_confcall(struct node *np, struct lut **globals, struct config *croot,
1314 	struct arrow *arrowp, struct evalue *valuep)
1315 {
1316 	nvlist_t *rsrc, *hcs;
1317 	nvpair_t *nvp;
1318 
1319 	ASSERT(np != NULL);
1320 
1321 	/* assume we're returning true */
1322 	valuep->t = UINT64;
1323 	valuep->v = 1;
1324 
1325 	/*
1326 	 * We've detected a well-formed confcall() to rewrite
1327 	 * an ASRU in a fault.  We get here via lines like this
1328 	 * in the eversholt rules:
1329 	 *
1330 	 *	event fault.memory.page@dimm, FITrate=PAGE_FIT,
1331 	 *		ASRU=dimm, message=0,
1332 	 *		count=stat.page_fault@dimm,
1333 	 *		action=confcall("rewrite-ASRU");
1334 	 *
1335 	 * So first rewrite the resource in the fault.  Any payload data
1336 	 * following the FM_FMRI_HC_SPECIFIC member is used to expand the
1337 	 * resource nvlist.  Next, use libtopo to compute the ASRU from
1338 	 * from the new resource.
1339 	 */
1340 	if (np->t == T_QUOTE && np->u.quote.s == stable("rewrite-ASRU")) {
1341 		int err;
1342 		nvlist_t *asru;
1343 
1344 		out(O_ALTFP|O_VERB, "platform_confcall: rewrite-ASRU");
1345 
1346 		if (nvlist_lookup_nvlist(Action_nvl, FM_FAULT_RESOURCE, &rsrc)
1347 		    != 0) {
1348 			outfl(O_ALTFP|O_VERB, np->file, np->line, "no resource "
1349 			    "in fault event");
1350 			return (0);
1351 		}
1352 
1353 		if (topo_hdl_nvalloc(Eft_topo_hdl, &hcs, NV_UNIQUE_NAME) != 0) {
1354 			outfl(O_ALTFP|O_VERB, np->file, np->line,
1355 			    "unable to allocate nvlist for resource rewrite");
1356 			return (0);
1357 		}
1358 
1359 		/*
1360 		 * Loop until we run across asru-specific payload.  All
1361 		 * payload members prefixed "asru-" will be added to the
1362 		 * hc-specific nvlist and removed from the original.
1363 		 */
1364 		nvp = nvlist_next_nvpair(Action_nvl, NULL);
1365 		while (nvp != NULL) {
1366 			if (strncmp(nvpair_name(nvp), "asru-", 5) == 0) {
1367 				if (nvlist_add_nvpair(hcs, nvp) != 0) {
1368 					nvlist_free(hcs);
1369 					outfl(O_ALTFP|O_VERB, np->file,
1370 					    np->line, "unable to rewrite "
1371 					    "resource - nvlist_add_nvpair for "
1372 					    "'%s' failed", nvpair_name(nvp));
1373 					return (0);
1374 				}
1375 
1376 				(void) nvlist_remove(Action_nvl,
1377 				    nvpair_name(nvp), nvpair_type(nvp));
1378 				nvp = nvlist_next_nvpair(Action_nvl, NULL);
1379 			} else {
1380 				nvp = nvlist_next_nvpair(Action_nvl, nvp);
1381 			}
1382 		}
1383 
1384 		if (nvlist_add_nvlist(rsrc, FM_FMRI_HC_SPECIFIC, hcs) != 0) {
1385 			nvlist_free(hcs);
1386 			outfl(O_ALTFP|O_VERB, np->file, np->line, "unable to "
1387 			    "rewrite resource with HC specific data");
1388 			return (0);
1389 		}
1390 		nvlist_free(hcs);
1391 
1392 		if (topo_fmri_asru(Eft_topo_hdl, rsrc, &asru, &err) != 0) {
1393 			outfl(O_ALTFP|O_VERB, np->file, np->line, "unable to "
1394 			    "rewrite asru: %s", topo_strerror(err));
1395 			return (0);
1396 		}
1397 
1398 		if (nvlist_remove(Action_nvl, FM_FAULT_ASRU, DATA_TYPE_NVLIST)
1399 		    != 0) {
1400 			nvlist_free(asru);
1401 			outfl(O_ALTFP|O_VERB, np->file, np->line,
1402 			    "failed to remove old asru during rewrite");
1403 			return (0);
1404 		}
1405 		if (nvlist_add_nvlist(Action_nvl, FM_FAULT_ASRU, asru) != 0) {
1406 			nvlist_free(asru);
1407 			outfl(O_ALTFP|O_VERB, np->file, np->line,
1408 			    "unable to add re-written asru");
1409 			return (0);
1410 		}
1411 		nvlist_free(asru);
1412 	} else {
1413 		outfl(O_ALTFP|O_VERB, np->file, np->line, "unknown confcall");
1414 	}
1415 
1416 	return (0);
1417 }
1418 
1419 /*
1420  * platform_get_eft_files -- return names of all eft files we should load
1421  *
1422  * this routine doesn't return NULL, even if no files are found (in that
1423  * case, a char ** is returned with the first element NULL).
1424  */
1425 char **
1426 platform_get_eft_files(void)
1427 {
1428 	return (platform_get_files_stddirs(".eft", 1));
1429 }
1430 
1431 void
1432 platform_free_eft_files(char **flist)
1433 {
1434 	char **f;
1435 
1436 	if (flist == NULL || *flist == NULL)
1437 		return;	/* no files were found so we're done */
1438 
1439 	f = flist;
1440 	while (*f != NULL) {
1441 		FREE(*f);
1442 		f++;
1443 	}
1444 	FREE(flist);
1445 }
1446 
1447 static nvlist_t *payloadnvp = NULL;
1448 
1449 void
1450 platform_set_payloadnvp(nvlist_t *nvlp)
1451 {
1452 	/*
1453 	 * cannot replace a non-NULL payloadnvp with a non-NULL nvlp
1454 	 */
1455 	ASSERT(payloadnvp != NULL ? nvlp == NULL : 1);
1456 	payloadnvp = nvlp;
1457 }
1458 
1459 /*
1460  * given array notation in inputstr such as "foo[1]" or "foo [ 1 ]" (spaces
1461  * allowed), figure out the array name and index.  return 0 if successful,
1462  * nonzero if otherwise.
1463  */
1464 static int
1465 get_array_info(const char *inputstr, const char **name, unsigned int *index)
1466 {
1467 	char *indexptr, *indexend, *dupname, *endname;
1468 
1469 	if (strchr(inputstr, '[') == NULL)
1470 		return (1);
1471 
1472 	dupname = STRDUP(inputstr);
1473 	indexptr = strchr(dupname, '[');
1474 	indexend = strchr(dupname, ']');
1475 
1476 	/*
1477 	 * return if array notation is not complete or if index is negative
1478 	 */
1479 	if (indexend == NULL || indexptr >= indexend ||
1480 	    strchr(indexptr, '-') != NULL) {
1481 		FREE(dupname);
1482 		return (1);
1483 	}
1484 
1485 	/*
1486 	 * search past any spaces between the name string and '['
1487 	 */
1488 	endname = indexptr;
1489 	while (isspace(*(endname - 1)) && dupname < endname)
1490 		endname--;
1491 	*endname = '\0';
1492 	ASSERT(dupname < endname);
1493 
1494 	/*
1495 	 * search until indexptr points to the first digit and indexend
1496 	 * points to the last digit
1497 	 */
1498 	while (!isdigit(*indexptr) && indexptr < indexend)
1499 		indexptr++;
1500 	while (!isdigit(*indexend) && indexptr <= indexend)
1501 		indexend--;
1502 
1503 	*(indexend + 1) = '\0';
1504 	*index = (unsigned int)atoi(indexptr);
1505 
1506 	*name = stable(dupname);
1507 	FREE(dupname);
1508 
1509 	return (0);
1510 }
1511 
1512 /*
1513  * platform_payloadprop -- fetch a payload value
1514  *
1515  * XXX this function should be replaced and eval_func() should be
1516  * XXX changed to use the more general platform_payloadprop_values().
1517  */
1518 int
1519 platform_payloadprop(struct node *np, struct evalue *valuep)
1520 {
1521 	nvlist_t *basenvp;
1522 	nvlist_t *embnvp = NULL;
1523 	nvpair_t *nvpair;
1524 	const char *nameptr, *propstr, *lastnameptr;
1525 	int not_array = 0;
1526 	unsigned int index = 0;
1527 	uint_t nelem;
1528 	char *nvpname, *nameslist = NULL;
1529 	char *scheme = NULL;
1530 
1531 	ASSERT(np->t == T_QUOTE);
1532 
1533 	propstr = np->u.quote.s;
1534 	if (payloadnvp == NULL) {
1535 		out(O_ALTFP | O_VERB2, "platform_payloadprop: no nvp for %s",
1536 		    propstr);
1537 		return (1);
1538 	}
1539 	basenvp = payloadnvp;
1540 
1541 	/*
1542 	 * first handle any embedded nvlists.  if propstr is "foo.bar[2]"
1543 	 * then lastnameptr should end up being "bar[2]" with basenvp set
1544 	 * to the nvlist for "foo".  (the search for "bar" within "foo"
1545 	 * will be done later.)
1546 	 */
1547 	if (strchr(propstr, '.') != NULL) {
1548 		nvlist_t **arraynvp;
1549 		uint_t nelem;
1550 		char *w;
1551 		int ier;
1552 
1553 		nameslist = STRDUP(propstr);
1554 		lastnameptr = strtok(nameslist, ".");
1555 
1556 		/*
1557 		 * decompose nameslist into its component names while
1558 		 * extracting the embedded nvlist
1559 		 */
1560 		while ((w = strtok(NULL, ".")) != NULL) {
1561 			if (get_array_info(lastnameptr, &nameptr, &index)) {
1562 				ier = nvlist_lookup_nvlist(basenvp,
1563 						    lastnameptr, &basenvp);
1564 			} else {
1565 				/* handle array of nvlists */
1566 				ier = nvlist_lookup_nvlist_array(basenvp,
1567 					    nameptr, &arraynvp, &nelem);
1568 				if (ier == 0) {
1569 					if ((uint_t)index > nelem - 1)
1570 						ier = 1;
1571 					else
1572 						basenvp = arraynvp[index];
1573 				}
1574 			}
1575 
1576 			if (ier) {
1577 				out(O_ALTFP, "platform_payloadprop: "
1578 				    " invalid list for %s (in %s)",
1579 				    lastnameptr, propstr);
1580 				FREE(nameslist);
1581 				return (1);
1582 			}
1583 
1584 			lastnameptr = w;
1585 		}
1586 	} else {
1587 		lastnameptr = propstr;
1588 	}
1589 
1590 	/* if property is an array reference, extract array name and index */
1591 	not_array = get_array_info(lastnameptr, &nameptr, &index);
1592 	if (not_array)
1593 		nameptr = stable(lastnameptr);
1594 
1595 	if (nameslist != NULL)
1596 		FREE(nameslist);
1597 
1598 	/* search for nvpair entry */
1599 	nvpair = NULL;
1600 	while ((nvpair = nvlist_next_nvpair(basenvp, nvpair)) != NULL) {
1601 		nvpname = nvpair_name(nvpair);
1602 		ASSERT(nvpname != NULL);
1603 
1604 		if (nameptr == stable(nvpname))
1605 			break;
1606 	}
1607 
1608 	if (nvpair == NULL) {
1609 		out(O_ALTFP, "platform_payloadprop: no entry for %s", propstr);
1610 		return (1);
1611 	} else if (valuep == NULL) {
1612 		/*
1613 		 * caller is interested in the existence of a property with
1614 		 * this name, regardless of type or value
1615 		 */
1616 		return (0);
1617 	}
1618 
1619 	valuep->t = UNDEFINED;
1620 
1621 	/*
1622 	 * get to this point if we found an entry.  figure out its data
1623 	 * type and copy its value.
1624 	 */
1625 	(void) nvpair_value_nvlist(nvpair, &embnvp);
1626 	if (nvlist_lookup_string(embnvp, FM_FMRI_SCHEME, &scheme) == 0) {
1627 		if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
1628 			valuep->t = NODEPTR;
1629 			valuep->v = (uintptr_t)hc_fmri_nodeize(embnvp);
1630 			return (0);
1631 		}
1632 	}
1633 	switch (nvpair_type(nvpair)) {
1634 	case DATA_TYPE_BOOLEAN:
1635 	case DATA_TYPE_BOOLEAN_VALUE: {
1636 		boolean_t val;
1637 		(void) nvpair_value_boolean_value(nvpair, &val);
1638 		valuep->t = UINT64;
1639 		valuep->v = (unsigned long long)val;
1640 		break;
1641 	}
1642 	case DATA_TYPE_BYTE: {
1643 		uchar_t val;
1644 		(void) nvpair_value_byte(nvpair, &val);
1645 		valuep->t = UINT64;
1646 		valuep->v = (unsigned long long)val;
1647 		break;
1648 	}
1649 	case DATA_TYPE_STRING: {
1650 		char *val;
1651 		valuep->t = STRING;
1652 		(void) nvpair_value_string(nvpair, &val);
1653 		valuep->v = (uintptr_t)stable(val);
1654 		break;
1655 	}
1656 
1657 	case DATA_TYPE_INT8: {
1658 		int8_t val;
1659 		(void) nvpair_value_int8(nvpair, &val);
1660 		valuep->t = UINT64;
1661 		valuep->v = (unsigned long long)val;
1662 		break;
1663 	}
1664 	case DATA_TYPE_UINT8: {
1665 		uint8_t val;
1666 		(void) nvpair_value_uint8(nvpair, &val);
1667 		valuep->t = UINT64;
1668 		valuep->v = (unsigned long long)val;
1669 		break;
1670 	}
1671 
1672 	case DATA_TYPE_INT16: {
1673 		int16_t val;
1674 		(void) nvpair_value_int16(nvpair, &val);
1675 		valuep->t = UINT64;
1676 		valuep->v = (unsigned long long)val;
1677 		break;
1678 	}
1679 	case DATA_TYPE_UINT16: {
1680 		uint16_t val;
1681 		(void) nvpair_value_uint16(nvpair, &val);
1682 		valuep->t = UINT64;
1683 		valuep->v = (unsigned long long)val;
1684 		break;
1685 	}
1686 
1687 	case DATA_TYPE_INT32: {
1688 		int32_t val;
1689 		(void) nvpair_value_int32(nvpair, &val);
1690 		valuep->t = UINT64;
1691 		valuep->v = (unsigned long long)val;
1692 		break;
1693 	}
1694 	case DATA_TYPE_UINT32: {
1695 		uint32_t val;
1696 		(void) nvpair_value_uint32(nvpair, &val);
1697 		valuep->t = UINT64;
1698 		valuep->v = (unsigned long long)val;
1699 		break;
1700 	}
1701 
1702 	case DATA_TYPE_INT64: {
1703 		int64_t val;
1704 		(void) nvpair_value_int64(nvpair, &val);
1705 		valuep->t = UINT64;
1706 		valuep->v = (unsigned long long)val;
1707 		break;
1708 	}
1709 	case DATA_TYPE_UINT64: {
1710 		uint64_t val;
1711 		(void) nvpair_value_uint64(nvpair, &val);
1712 		valuep->t = UINT64;
1713 		valuep->v = (unsigned long long)val;
1714 		break;
1715 	}
1716 
1717 	case DATA_TYPE_BOOLEAN_ARRAY: {
1718 		boolean_t *val;
1719 		(void) nvpair_value_boolean_array(nvpair, &val, &nelem);
1720 		if (not_array == 1 || index >= nelem)
1721 			goto invalid;
1722 		valuep->t = UINT64;
1723 		valuep->v = (unsigned long long)val[index];
1724 		break;
1725 	}
1726 	case DATA_TYPE_BYTE_ARRAY: {
1727 		uchar_t *val;
1728 		(void) nvpair_value_byte_array(nvpair, &val, &nelem);
1729 		if (not_array == 1 || index >= nelem)
1730 			goto invalid;
1731 		valuep->t = UINT64;
1732 		valuep->v = (unsigned long long)val[index];
1733 		break;
1734 	}
1735 	case DATA_TYPE_STRING_ARRAY: {
1736 		char **val;
1737 		(void) nvpair_value_string_array(nvpair, &val, &nelem);
1738 		if (not_array == 1 || index >= nelem)
1739 			goto invalid;
1740 		valuep->t = STRING;
1741 		valuep->v = (uintptr_t)stable(val[index]);
1742 		break;
1743 	}
1744 
1745 	case DATA_TYPE_INT8_ARRAY: {
1746 		int8_t *val;
1747 		(void) nvpair_value_int8_array(nvpair, &val, &nelem);
1748 		if (not_array == 1 || index >= nelem)
1749 			goto invalid;
1750 		valuep->t = UINT64;
1751 		valuep->v = (unsigned long long)val[index];
1752 		break;
1753 	}
1754 	case DATA_TYPE_UINT8_ARRAY: {
1755 		uint8_t *val;
1756 		(void) nvpair_value_uint8_array(nvpair, &val, &nelem);
1757 		if (not_array == 1 || index >= nelem)
1758 			goto invalid;
1759 		valuep->t = UINT64;
1760 		valuep->v = (unsigned long long)val[index];
1761 		break;
1762 	}
1763 	case DATA_TYPE_INT16_ARRAY: {
1764 		int16_t *val;
1765 		(void) nvpair_value_int16_array(nvpair, &val, &nelem);
1766 		if (not_array == 1 || index >= nelem)
1767 			goto invalid;
1768 		valuep->t = UINT64;
1769 		valuep->v = (unsigned long long)val[index];
1770 		break;
1771 	}
1772 	case DATA_TYPE_UINT16_ARRAY: {
1773 		uint16_t *val;
1774 		(void) nvpair_value_uint16_array(nvpair, &val, &nelem);
1775 		if (not_array == 1 || index >= nelem)
1776 			goto invalid;
1777 		valuep->t = UINT64;
1778 		valuep->v = (unsigned long long)val[index];
1779 		break;
1780 	}
1781 	case DATA_TYPE_INT32_ARRAY: {
1782 		int32_t *val;
1783 		(void) nvpair_value_int32_array(nvpair, &val, &nelem);
1784 		if (not_array == 1 || index >= nelem)
1785 			goto invalid;
1786 		valuep->t = UINT64;
1787 		valuep->v = (unsigned long long)val[index];
1788 		break;
1789 	}
1790 	case DATA_TYPE_UINT32_ARRAY: {
1791 		uint32_t *val;
1792 		(void) nvpair_value_uint32_array(nvpair, &val, &nelem);
1793 		if (not_array == 1 || index >= nelem)
1794 			goto invalid;
1795 		valuep->t = UINT64;
1796 		valuep->v = (unsigned long long)val[index];
1797 		break;
1798 	}
1799 	case DATA_TYPE_INT64_ARRAY: {
1800 		int64_t *val;
1801 		(void) nvpair_value_int64_array(nvpair, &val, &nelem);
1802 		if (not_array == 1 || index >= nelem)
1803 			goto invalid;
1804 		valuep->t = UINT64;
1805 		valuep->v = (unsigned long long)val[index];
1806 		break;
1807 	}
1808 	case DATA_TYPE_UINT64_ARRAY: {
1809 		uint64_t *val;
1810 		(void) nvpair_value_uint64_array(nvpair, &val, &nelem);
1811 		if (not_array == 1 || index >= nelem)
1812 			goto invalid;
1813 		valuep->t = UINT64;
1814 		valuep->v = (unsigned long long)val[index];
1815 		break;
1816 	}
1817 
1818 	default :
1819 		out(O_ALTFP|O_VERB2,
1820 		    "platform_payloadprop: unsupported data type for %s",
1821 		    propstr);
1822 		return (1);
1823 	}
1824 
1825 	return (0);
1826 
1827 invalid:
1828 	out(O_ALTFP|O_VERB2,
1829 	    "platform_payloadprop: invalid array reference for %s", propstr);
1830 	return (1);
1831 }
1832 
1833 /*ARGSUSED*/
1834 int
1835 platform_path_exists(nvlist_t *fmri)
1836 {
1837 	return (fmd_nvl_fmri_present(Hdl, fmri));
1838 }
1839 
1840 struct evalue *
1841 platform_payloadprop_values(const char *propstr, int *nvals)
1842 {
1843 	struct evalue *retvals;
1844 	nvlist_t *basenvp;
1845 	nvpair_t *nvpair;
1846 	char *nvpname;
1847 
1848 	*nvals = 0;
1849 
1850 	if (payloadnvp == NULL)
1851 		return (NULL);
1852 
1853 	basenvp = payloadnvp;
1854 
1855 	/* search for nvpair entry */
1856 	nvpair = NULL;
1857 	while ((nvpair = nvlist_next_nvpair(basenvp, nvpair)) != NULL) {
1858 		nvpname = nvpair_name(nvpair);
1859 		ASSERT(nvpname != NULL);
1860 
1861 		if (strcmp(propstr, nvpname) == 0)
1862 			break;
1863 	}
1864 
1865 	if (nvpair == NULL)
1866 		return (NULL);	/* property not found */
1867 
1868 	switch (nvpair_type(nvpair)) {
1869 	case DATA_TYPE_NVLIST: {
1870 		nvlist_t *embnvp = NULL;
1871 		char *scheme = NULL;
1872 
1873 		(void) nvpair_value_nvlist(nvpair, &embnvp);
1874 		if (nvlist_lookup_string(embnvp, FM_FMRI_SCHEME,
1875 		    &scheme) == 0) {
1876 			if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
1877 				*nvals = 1;
1878 				retvals = MALLOC(sizeof (struct evalue));
1879 				retvals->t = NODEPTR;
1880 				retvals->v =
1881 				    (uintptr_t)hc_fmri_nodeize(embnvp);
1882 				return (retvals);
1883 			}
1884 		}
1885 		return (NULL);
1886 	}
1887 	case DATA_TYPE_NVLIST_ARRAY: {
1888 		char *scheme = NULL;
1889 		nvlist_t **nvap;
1890 		uint_t nel;
1891 		int i;
1892 		int hccount;
1893 
1894 		/*
1895 		 * since we're only willing to handle hc fmri's, we
1896 		 * must count them first before allocating retvals.
1897 		 */
1898 		if (nvpair_value_nvlist_array(nvpair, &nvap, &nel) != 0)
1899 			return (NULL);
1900 
1901 		hccount = 0;
1902 		for (i = 0; i < nel; i++) {
1903 			if (nvlist_lookup_string(nvap[i], FM_FMRI_SCHEME,
1904 			    &scheme) == 0 &&
1905 			    strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
1906 				hccount++;
1907 			}
1908 		}
1909 
1910 		if (hccount == 0)
1911 			return (NULL);
1912 
1913 		*nvals = hccount;
1914 		retvals = MALLOC(sizeof (struct evalue) * hccount);
1915 
1916 		hccount = 0;
1917 		for (i = 0; i < nel; i++) {
1918 			if (nvlist_lookup_string(nvap[i], FM_FMRI_SCHEME,
1919 			    &scheme) == 0 &&
1920 			    strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
1921 				retvals[hccount].t = NODEPTR;
1922 				retvals[hccount].v = (uintptr_t)
1923 				    hc_fmri_nodeize(nvap[i]);
1924 				hccount++;
1925 			}
1926 		}
1927 		return (retvals);
1928 	}
1929 	case DATA_TYPE_BOOLEAN:
1930 	case DATA_TYPE_BOOLEAN_VALUE: {
1931 		boolean_t val;
1932 
1933 		*nvals = 1;
1934 		retvals = MALLOC(sizeof (struct evalue));
1935 		(void) nvpair_value_boolean_value(nvpair, &val);
1936 		retvals->t = UINT64;
1937 		retvals->v = (unsigned long long)val;
1938 		return (retvals);
1939 	}
1940 	case DATA_TYPE_BYTE: {
1941 		uchar_t val;
1942 
1943 		*nvals = 1;
1944 		retvals = MALLOC(sizeof (struct evalue));
1945 		(void) nvpair_value_byte(nvpair, &val);
1946 		retvals->t = UINT64;
1947 		retvals->v = (unsigned long long)val;
1948 		return (retvals);
1949 	}
1950 	case DATA_TYPE_STRING: {
1951 		char *val;
1952 
1953 		*nvals = 1;
1954 		retvals = MALLOC(sizeof (struct evalue));
1955 		retvals->t = STRING;
1956 		(void) nvpair_value_string(nvpair, &val);
1957 		retvals->v = (uintptr_t)stable(val);
1958 		return (retvals);
1959 	}
1960 
1961 	case DATA_TYPE_INT8: {
1962 		int8_t val;
1963 
1964 		*nvals = 1;
1965 		retvals = MALLOC(sizeof (struct evalue));
1966 		(void) nvpair_value_int8(nvpair, &val);
1967 		retvals->t = UINT64;
1968 		retvals->v = (unsigned long long)val;
1969 		return (retvals);
1970 	}
1971 	case DATA_TYPE_UINT8: {
1972 		uint8_t val;
1973 
1974 		*nvals = 1;
1975 		retvals = MALLOC(sizeof (struct evalue));
1976 		(void) nvpair_value_uint8(nvpair, &val);
1977 		retvals->t = UINT64;
1978 		retvals->v = (unsigned long long)val;
1979 		return (retvals);
1980 	}
1981 
1982 	case DATA_TYPE_INT16: {
1983 		int16_t val;
1984 
1985 		*nvals = 1;
1986 		retvals = MALLOC(sizeof (struct evalue));
1987 		(void) nvpair_value_int16(nvpair, &val);
1988 		retvals->t = UINT64;
1989 		retvals->v = (unsigned long long)val;
1990 		return (retvals);
1991 	}
1992 	case DATA_TYPE_UINT16: {
1993 		uint16_t val;
1994 
1995 		*nvals = 1;
1996 		retvals = MALLOC(sizeof (struct evalue));
1997 		(void) nvpair_value_uint16(nvpair, &val);
1998 		retvals->t = UINT64;
1999 		retvals->v = (unsigned long long)val;
2000 		return (retvals);
2001 	}
2002 
2003 	case DATA_TYPE_INT32: {
2004 		int32_t val;
2005 
2006 		*nvals = 1;
2007 		retvals = MALLOC(sizeof (struct evalue));
2008 		(void) nvpair_value_int32(nvpair, &val);
2009 		retvals->t = UINT64;
2010 		retvals->v = (unsigned long long)val;
2011 		return (retvals);
2012 	}
2013 	case DATA_TYPE_UINT32: {
2014 		uint32_t val;
2015 
2016 		*nvals = 1;
2017 		retvals = MALLOC(sizeof (struct evalue));
2018 		(void) nvpair_value_uint32(nvpair, &val);
2019 		retvals->t = UINT64;
2020 		retvals->v = (unsigned long long)val;
2021 		return (retvals);
2022 	}
2023 
2024 	case DATA_TYPE_INT64: {
2025 		int64_t val;
2026 
2027 		*nvals = 1;
2028 		retvals = MALLOC(sizeof (struct evalue));
2029 		(void) nvpair_value_int64(nvpair, &val);
2030 		retvals->t = UINT64;
2031 		retvals->v = (unsigned long long)val;
2032 		return (retvals);
2033 	}
2034 	case DATA_TYPE_UINT64: {
2035 		uint64_t val;
2036 
2037 		*nvals = 1;
2038 		retvals = MALLOC(sizeof (struct evalue));
2039 		(void) nvpair_value_uint64(nvpair, &val);
2040 		retvals->t = UINT64;
2041 		retvals->v = (unsigned long long)val;
2042 		return (retvals);
2043 	}
2044 
2045 	case DATA_TYPE_BOOLEAN_ARRAY: {
2046 		boolean_t *val;
2047 		uint_t nel;
2048 		int i;
2049 
2050 		(void) nvpair_value_boolean_array(nvpair, &val, &nel);
2051 		*nvals = nel;
2052 		retvals = MALLOC(sizeof (struct evalue) * nel);
2053 		for (i = 0; i < nel; i++) {
2054 			retvals[i].t = UINT64;
2055 			retvals[i].v = (unsigned long long)val[i];
2056 		}
2057 		return (retvals);
2058 	}
2059 	case DATA_TYPE_BYTE_ARRAY: {
2060 		uchar_t *val;
2061 		uint_t nel;
2062 		int i;
2063 
2064 		(void) nvpair_value_byte_array(nvpair, &val, &nel);
2065 		*nvals = nel;
2066 		retvals = MALLOC(sizeof (struct evalue) * nel);
2067 		for (i = 0; i < nel; i++) {
2068 			retvals[i].t = UINT64;
2069 			retvals[i].v = (unsigned long long)val[i];
2070 		}
2071 		return (retvals);
2072 	}
2073 	case DATA_TYPE_STRING_ARRAY: {
2074 		char **val;
2075 		uint_t nel;
2076 		int i;
2077 
2078 		(void) nvpair_value_string_array(nvpair, &val, &nel);
2079 		*nvals = nel;
2080 		retvals = MALLOC(sizeof (struct evalue) * nel);
2081 		for (i = 0; i < nel; i++) {
2082 			retvals[i].t = STRING;
2083 			retvals[i].v = (uintptr_t)stable(val[i]);
2084 		}
2085 		return (retvals);
2086 	}
2087 
2088 	case DATA_TYPE_INT8_ARRAY: {
2089 		int8_t *val;
2090 		uint_t nel;
2091 		int i;
2092 
2093 		(void) nvpair_value_int8_array(nvpair, &val, &nel);
2094 		*nvals = nel;
2095 		retvals = MALLOC(sizeof (struct evalue) * nel);
2096 		for (i = 0; i < nel; i++) {
2097 			retvals[i].t = UINT64;
2098 			retvals[i].v = (unsigned long long)val[i];
2099 		}
2100 		return (retvals);
2101 	}
2102 	case DATA_TYPE_UINT8_ARRAY: {
2103 		uint8_t *val;
2104 		uint_t nel;
2105 		int i;
2106 
2107 		(void) nvpair_value_uint8_array(nvpair, &val, &nel);
2108 		*nvals = nel;
2109 		retvals = MALLOC(sizeof (struct evalue) * nel);
2110 		for (i = 0; i < nel; i++) {
2111 			retvals[i].t = UINT64;
2112 			retvals[i].v = (unsigned long long)val[i];
2113 		}
2114 		return (retvals);
2115 	}
2116 	case DATA_TYPE_INT16_ARRAY: {
2117 		int16_t *val;
2118 		uint_t nel;
2119 		int i;
2120 
2121 		(void) nvpair_value_int16_array(nvpair, &val, &nel);
2122 		*nvals = nel;
2123 		retvals = MALLOC(sizeof (struct evalue) * nel);
2124 		for (i = 0; i < nel; i++) {
2125 			retvals[i].t = UINT64;
2126 			retvals[i].v = (unsigned long long)val[i];
2127 		}
2128 		return (retvals);
2129 	}
2130 	case DATA_TYPE_UINT16_ARRAY: {
2131 		uint16_t *val;
2132 		uint_t nel;
2133 		int i;
2134 
2135 		(void) nvpair_value_uint16_array(nvpair, &val, &nel);
2136 		*nvals = nel;
2137 		retvals = MALLOC(sizeof (struct evalue) * nel);
2138 		for (i = 0; i < nel; i++) {
2139 			retvals[i].t = UINT64;
2140 			retvals[i].v = (unsigned long long)val[i];
2141 		}
2142 		return (retvals);
2143 	}
2144 	case DATA_TYPE_INT32_ARRAY: {
2145 		int32_t *val;
2146 		uint_t nel;
2147 		int i;
2148 
2149 		(void) nvpair_value_int32_array(nvpair, &val, &nel);
2150 		*nvals = nel;
2151 		retvals = MALLOC(sizeof (struct evalue) * nel);
2152 		for (i = 0; i < nel; i++) {
2153 			retvals[i].t = UINT64;
2154 			retvals[i].v = (unsigned long long)val[i];
2155 		}
2156 		return (retvals);
2157 	}
2158 	case DATA_TYPE_UINT32_ARRAY: {
2159 		uint32_t *val;
2160 		uint_t nel;
2161 		int i;
2162 
2163 		(void) nvpair_value_uint32_array(nvpair, &val, &nel);
2164 		*nvals = nel;
2165 		retvals = MALLOC(sizeof (struct evalue) * nel);
2166 		for (i = 0; i < nel; i++) {
2167 			retvals[i].t = UINT64;
2168 			retvals[i].v = (unsigned long long)val[i];
2169 		}
2170 		return (retvals);
2171 	}
2172 	case DATA_TYPE_INT64_ARRAY: {
2173 		int64_t *val;
2174 		uint_t nel;
2175 		int i;
2176 
2177 		(void) nvpair_value_int64_array(nvpair, &val, &nel);
2178 		*nvals = nel;
2179 		retvals = MALLOC(sizeof (struct evalue) * nel);
2180 		for (i = 0; i < nel; i++) {
2181 			retvals[i].t = UINT64;
2182 			retvals[i].v = (unsigned long long)val[i];
2183 		}
2184 		return (retvals);
2185 	}
2186 	case DATA_TYPE_UINT64_ARRAY: {
2187 		uint64_t *val;
2188 		uint_t nel;
2189 		int i;
2190 
2191 		(void) nvpair_value_uint64_array(nvpair, &val, &nel);
2192 		*nvals = nel;
2193 		retvals = MALLOC(sizeof (struct evalue) * nel);
2194 		for (i = 0; i < nel; i++) {
2195 			retvals[i].t = UINT64;
2196 			retvals[i].v = (unsigned long long)val[i];
2197 		}
2198 		return (retvals);
2199 	}
2200 
2201 	}
2202 
2203 	return (NULL);
2204 }
2205 
2206 /*
2207  * When a list.repaired event is seen the following is called for
2208  * each fault in the associated fault list to convert the given FMRI
2209  * to an instanced path.  Only hc scheme is supported.
2210  */
2211 const struct ipath *
2212 platform_fault2ipath(nvlist_t *flt)
2213 {
2214 	nvlist_t *rsrc;
2215 	struct node *np;
2216 	char *scheme;
2217 
2218 	if (nvlist_lookup_nvlist(flt, FM_FAULT_RESOURCE, &rsrc) != 0) {
2219 		out(O_ALTFP, "platform_fault2ipath: no resource member");
2220 		return (NULL);
2221 	} else if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) {
2222 		out(O_ALTFP, "platform_fault2ipath: no scheme type for rsrc");
2223 		return (NULL);
2224 	}
2225 
2226 	if (strncmp(scheme, FM_FMRI_SCHEME_HC,
2227 	    sizeof (FM_FMRI_SCHEME_HC) - 1) != 0) {
2228 		out(O_ALTFP, "platform_fault2ipath: returning NULL for non-hc "
2229 		"scheme %s", scheme);
2230 		return (NULL);
2231 	}
2232 
2233 	if ((np = hc_fmri_nodeize(rsrc)) == NULL)
2234 		return (NULL);		/* nodeize will already have whinged */
2235 
2236 	return (ipath(np));
2237 }
2238