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