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