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