xref: /onnv-gate/usr/src/cmd/fm/modules/common/eversholt/config.c (revision 12618:0e5eaf4bf546)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51490Stimh  * Common Development and Distribution License (the "License").
61490Stimh  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211490Stimh 
220Sstevel@tonic-gate /*
2312106SStephen.Hanson@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
241490Stimh  */
251490Stimh 
261490Stimh /*
270Sstevel@tonic-gate  * config.c -- system configuration cache module
280Sstevel@tonic-gate  *
290Sstevel@tonic-gate  * this module caches the system configuration in a format useful
300Sstevel@tonic-gate  * to eft.  the information is loaded into this module by
310Sstevel@tonic-gate  * config_snapshot() at the beginning of each FME.  config_snapshot()
320Sstevel@tonic-gate  * calls the platform-specific platform_config_snapshot() to get
330Sstevel@tonic-gate  * the configuration information loaded up.
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #include <stdio.h>
370Sstevel@tonic-gate #include <stdlib.h>
380Sstevel@tonic-gate #include <ctype.h>
390Sstevel@tonic-gate #include <string.h>
400Sstevel@tonic-gate #include <strings.h>
413062Scindi #include <fm/topo_hc.h>
420Sstevel@tonic-gate #include "alloc.h"
430Sstevel@tonic-gate #include "out.h"
440Sstevel@tonic-gate #include "literals.h"
450Sstevel@tonic-gate #include "stable.h"
460Sstevel@tonic-gate #include "lut.h"
470Sstevel@tonic-gate #include "tree.h"
480Sstevel@tonic-gate #include "itree.h"
490Sstevel@tonic-gate #include "ipath.h"
500Sstevel@tonic-gate #include "ptree.h"
510Sstevel@tonic-gate #include "eval.h"
520Sstevel@tonic-gate #include "config.h"
535433Saf #include "config_impl.h"
540Sstevel@tonic-gate #include "fme.h"
550Sstevel@tonic-gate #include "platform.h"
560Sstevel@tonic-gate 
574436Sstephh static const char *config_lastcomp;
584436Sstephh 
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate  * newcnode -- local function to allocate new config node
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate static struct config *
newcnode(const char * s,int num)630Sstevel@tonic-gate newcnode(const char *s, int num)
640Sstevel@tonic-gate {
650Sstevel@tonic-gate 	struct config *retval;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 	retval = MALLOC(sizeof (struct config));
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	retval->s = s;
700Sstevel@tonic-gate 	retval->num = num;
710Sstevel@tonic-gate 	retval->next = NULL;
720Sstevel@tonic-gate 	retval->props = NULL;
730Sstevel@tonic-gate 	retval->child = retval->parent = NULL;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	return (retval);
760Sstevel@tonic-gate }
770Sstevel@tonic-gate 
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate  * If we need to cache certain types of nodes for reverse look-up or
800Sstevel@tonic-gate  * somesuch, do it here.  Currently we need to cache nodes representing
810Sstevel@tonic-gate  * cpus.
820Sstevel@tonic-gate  */
830Sstevel@tonic-gate static void
config_node_cache(struct cfgdata * cdata,struct config * n)840Sstevel@tonic-gate config_node_cache(struct cfgdata *cdata, struct config *n)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate 	if (n->s != stable("cpu"))
870Sstevel@tonic-gate 		return;
880Sstevel@tonic-gate 	cdata->cpucache = lut_add(cdata->cpucache,
890Sstevel@tonic-gate 	    (void *)n->num, (void *)n, NULL);
900Sstevel@tonic-gate }
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate  * config_lookup -- lookup/add components in configuration cache
940Sstevel@tonic-gate  */
950Sstevel@tonic-gate struct config *
config_lookup(struct config * croot,char * path,int add)960Sstevel@tonic-gate config_lookup(struct config *croot, char *path, int add)
970Sstevel@tonic-gate {
980Sstevel@tonic-gate 	char *pathbegin = path;
990Sstevel@tonic-gate 	struct config *parent = croot;
1000Sstevel@tonic-gate 	struct config *cp;
1010Sstevel@tonic-gate 	struct config *lastcp;
1020Sstevel@tonic-gate 	struct config *newnode;
1030Sstevel@tonic-gate 	char *thiscom;	/* this component */
1040Sstevel@tonic-gate 	char *nextcom;	/* next component */
1050Sstevel@tonic-gate 	char svdigit;
1060Sstevel@tonic-gate 	int len;
1070Sstevel@tonic-gate 	int num;
1080Sstevel@tonic-gate 	const char *s;
1090Sstevel@tonic-gate 	int exists;
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	if (parent == NULL)
1120Sstevel@tonic-gate 		out(O_DIE, "uninitialized configuration");
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	while (*path) {
1150Sstevel@tonic-gate 		if ((nextcom = strchr(path, '/')) != NULL)
1160Sstevel@tonic-gate 			*nextcom = '\0';
1170Sstevel@tonic-gate 		if ((len = strlen(path)) == 0)
1180Sstevel@tonic-gate 			out(O_DIE, "config_lookup: zero length component");
1190Sstevel@tonic-gate 		/* start at end of string and work backwards */
1200Sstevel@tonic-gate 		thiscom = &path[len - 1];
1210Sstevel@tonic-gate 		if (!isdigit(*thiscom))
1220Sstevel@tonic-gate 			out(O_DIE, "config_lookup: "
1230Sstevel@tonic-gate 			    "component \"%s\" has no number following it",
1240Sstevel@tonic-gate 			    path);
1250Sstevel@tonic-gate 		while (thiscom > path && isdigit(*thiscom))
1260Sstevel@tonic-gate 			thiscom--;
1270Sstevel@tonic-gate 		if (thiscom == path && isdigit(*thiscom))
1280Sstevel@tonic-gate 			out(O_DIE, "config_lookup: "
1290Sstevel@tonic-gate 			    "component \"%s\" has no name part", path);
1300Sstevel@tonic-gate 		thiscom++;	/* move to first numeric character */
1310Sstevel@tonic-gate 		num = atoi(thiscom);
1320Sstevel@tonic-gate 		svdigit = *thiscom;
1330Sstevel@tonic-gate 		*thiscom = '\0';
1340Sstevel@tonic-gate 		s = stable(path);
1354436Sstephh 		if (add)
1364436Sstephh 			config_lastcomp = s;
1370Sstevel@tonic-gate 		*thiscom = svdigit;
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 		if (nextcom != NULL)
1400Sstevel@tonic-gate 			*nextcom++ = '/';
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 		/* now we have s & num, figure out if it exists already */
1430Sstevel@tonic-gate 		exists = 0;
1440Sstevel@tonic-gate 		lastcp = NULL;
1450Sstevel@tonic-gate 		for (cp = parent->child; cp; lastcp = cp, cp = cp->next)
1460Sstevel@tonic-gate 			if (cp->s == s && cp->num == num) {
1470Sstevel@tonic-gate 				exists = 1;
1480Sstevel@tonic-gate 				parent = cp;
1490Sstevel@tonic-gate 			}
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 		if (!exists) {
1520Sstevel@tonic-gate 			/* creating new node */
1530Sstevel@tonic-gate 			if (!add) {
1540Sstevel@tonic-gate 				/*
1550Sstevel@tonic-gate 				 * indicate component not found by copying
1560Sstevel@tonic-gate 				 * it to path (allows better error messages
1570Sstevel@tonic-gate 				 * in the caller).
1580Sstevel@tonic-gate 				 */
1590Sstevel@tonic-gate 				(void) strcpy(pathbegin, s);
1600Sstevel@tonic-gate 				return (NULL);
1610Sstevel@tonic-gate 			}
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 			newnode = newcnode(s, num);
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 			if (lastcp)
1660Sstevel@tonic-gate 				lastcp->next = newnode;
1670Sstevel@tonic-gate 			else
1680Sstevel@tonic-gate 				parent->child = newnode;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 			newnode->parent = parent;
1710Sstevel@tonic-gate 			parent = newnode;
1720Sstevel@tonic-gate 		}
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 		if (nextcom == NULL)
1750Sstevel@tonic-gate 			return (parent);	/* all done */
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 		/* move on to next component */
1780Sstevel@tonic-gate 		path = nextcom;
1790Sstevel@tonic-gate 	}
1800Sstevel@tonic-gate 	return (parent);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate  * addconfigprop -- add a config prop to a config cache entry
1850Sstevel@tonic-gate  */
1860Sstevel@tonic-gate static void
addconfigprop(const char * lhs,struct node * rhs,void * arg)1870Sstevel@tonic-gate addconfigprop(const char *lhs, struct node *rhs, void *arg)
1880Sstevel@tonic-gate {
1890Sstevel@tonic-gate 	struct config *cp = (struct config *)arg;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	ASSERT(cp != NULL);
1920Sstevel@tonic-gate 	ASSERT(lhs != NULL);
1930Sstevel@tonic-gate 	ASSERT(rhs != NULL);
1940Sstevel@tonic-gate 	ASSERT(rhs->t == T_QUOTE);
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	config_setprop(cp, lhs, STRDUP(rhs->u.quote.s));
1970Sstevel@tonic-gate }
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate /*
2000Sstevel@tonic-gate  * addconfig -- add a config from parse tree to given configuration cache
2010Sstevel@tonic-gate  */
2020Sstevel@tonic-gate /*ARGSUSED*/
2030Sstevel@tonic-gate static void
addconfig(struct node * lhs,struct node * rhs,void * arg)2040Sstevel@tonic-gate addconfig(struct node *lhs, struct node *rhs, void *arg)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate 	struct config *parent = (struct config *)arg;
2070Sstevel@tonic-gate 	struct config *cp;
2080Sstevel@tonic-gate 	const char *s;
2090Sstevel@tonic-gate 	int num;
2100Sstevel@tonic-gate 	struct config *lastcp;
2110Sstevel@tonic-gate 	struct config *newnode;
2120Sstevel@tonic-gate 	int exists;
2130Sstevel@tonic-gate 	struct lut *lutp;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	ASSERT(rhs->t == T_CONFIG);
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	lutp = rhs->u.stmt.lutp;
2180Sstevel@tonic-gate 	rhs = rhs->u.stmt.np;
2190Sstevel@tonic-gate 	while (rhs != NULL) {
2200Sstevel@tonic-gate 		ASSERT(rhs->t == T_NAME);
2210Sstevel@tonic-gate 		ASSERT(rhs->u.name.child->t == T_NUM);
2220Sstevel@tonic-gate 		s = rhs->u.name.s;
2230Sstevel@tonic-gate 		num = rhs->u.name.child->u.ull;
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 		/* now we have s & num, figure out if it exists already */
2260Sstevel@tonic-gate 		exists = 0;
2270Sstevel@tonic-gate 		lastcp = NULL;
2280Sstevel@tonic-gate 		for (cp = parent->child; cp; lastcp = cp, cp = cp->next)
2290Sstevel@tonic-gate 			if (cp->s == s && cp->num == num) {
2300Sstevel@tonic-gate 				exists = 1;
2310Sstevel@tonic-gate 				parent = cp;
2320Sstevel@tonic-gate 			}
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 		if (!exists) {
2350Sstevel@tonic-gate 			/* creating new node */
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 			newnode = newcnode(s, num);
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 			if (lastcp)
2400Sstevel@tonic-gate 				lastcp->next = newnode;
2410Sstevel@tonic-gate 			else
2420Sstevel@tonic-gate 				parent->child = newnode;
2430Sstevel@tonic-gate 
2444436Sstephh 			newnode->parent = parent;
2450Sstevel@tonic-gate 			parent = newnode;
2460Sstevel@tonic-gate 		}
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 		/* move on to next component */
2490Sstevel@tonic-gate 		rhs = rhs->u.name.next;
2500Sstevel@tonic-gate 	}
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	/* add configuration properties */
2530Sstevel@tonic-gate 	lut_walk(lutp, (lut_cb)addconfigprop, (void *)parent);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate /*
2570Sstevel@tonic-gate  * config_cook -- convert raw config strings to eft internal representation
2580Sstevel@tonic-gate  */
2590Sstevel@tonic-gate void
config_cook(struct cfgdata * cdata)2600Sstevel@tonic-gate config_cook(struct cfgdata *cdata)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate 	struct config *newnode;
2630Sstevel@tonic-gate 	char *cfgstr, *equals;
2640Sstevel@tonic-gate 	const char *pn, *sv;
2650Sstevel@tonic-gate 	char *pv;
2664436Sstephh 	const char *ptr;
2674436Sstephh 	extern struct lut *Usedprops;
2684436Sstephh 	extern struct lut *Usednames;
2694436Sstephh 
2700Sstevel@tonic-gate 	cdata->cooked = newcnode(NULL, 0);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	if ((cfgstr = cdata->begin) == cdata->nextfree) {
2730Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, "Platform provided no config data.");
2740Sstevel@tonic-gate 		goto eftcfgs;
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 
2774436Sstephh 	/*
2784436Sstephh 	 * add the following properties to the "usedprops" table as they
2794436Sstephh 	 * are used internally by eft
2804436Sstephh 	 */
2814436Sstephh 	ptr = stable("module");
2824436Sstephh 	Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
2834436Sstephh 	ptr = stable("resource");
2844436Sstephh 	Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
28511202SStephen.Hanson@Sun.COM 	ptr = stable("serial");
28611202SStephen.Hanson@Sun.COM 	Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
2874436Sstephh 
2880Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, "Raw config data follows:");
2890Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL,
2900Sstevel@tonic-gate 	    "nextfree is %p\n%p ", (void *)cdata->nextfree, (void *)cfgstr);
2910Sstevel@tonic-gate 	while (cfgstr < cdata->nextfree) {
2920Sstevel@tonic-gate 		if (!*cfgstr)
2930Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3|O_NONL, "\n%p ",
2940Sstevel@tonic-gate 			    (void *)(cfgstr + 1));
2950Sstevel@tonic-gate 		else
2960Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3|O_NONL, "%c", *cfgstr);
2970Sstevel@tonic-gate 		cfgstr++;
2980Sstevel@tonic-gate 	}
2990Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, NULL);
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	cfgstr = cdata->begin;
3020Sstevel@tonic-gate 	while (cfgstr < cdata->nextfree) {
3030Sstevel@tonic-gate 		while (*cfgstr == '/' && cfgstr < cdata->nextfree) {
3040Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3,
3050Sstevel@tonic-gate 			    "next string (%p) is %s", (void *)cfgstr, cfgstr);
3060Sstevel@tonic-gate 			/* skip the initial slash from libtopo */
3070Sstevel@tonic-gate 			newnode = config_lookup(cdata->cooked, cfgstr + 1, 1);
3080Sstevel@tonic-gate 			/*
3090Sstevel@tonic-gate 			 * Note we'll only cache nodes that have
3100Sstevel@tonic-gate 			 * properties on them.  Intermediate nodes
3110Sstevel@tonic-gate 			 * will have been added to the config tree,
3120Sstevel@tonic-gate 			 * but we don't have easy means of accessing
3130Sstevel@tonic-gate 			 * them except if we climb the tree from this
3140Sstevel@tonic-gate 			 * newnode to the root.
3150Sstevel@tonic-gate 			 *
3160Sstevel@tonic-gate 			 * Luckily, the nodes we care to cache
3170Sstevel@tonic-gate 			 * (currently just cpus) always have some
3180Sstevel@tonic-gate 			 * properties attached to them
3190Sstevel@tonic-gate 			 * so we don't bother climbing the tree.
3200Sstevel@tonic-gate 			 */
3210Sstevel@tonic-gate 			config_node_cache(cdata, newnode);
3220Sstevel@tonic-gate 			cfgstr += strlen(cfgstr) + 1;
3230Sstevel@tonic-gate 		}
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 		if (cfgstr >= cdata->nextfree)
3260Sstevel@tonic-gate 			break;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 		out(O_ALTFP|O_VERB3, "next string (%p) is %s", (void *)cfgstr,
3290Sstevel@tonic-gate 		    cfgstr);
3300Sstevel@tonic-gate 		if ((equals = strchr(cfgstr, '=')) == NULL) {
3310Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3, "raw config data bad (%p); "
3320Sstevel@tonic-gate 			    "property missing equals.\n", (void *)cfgstr);
3330Sstevel@tonic-gate 			break;
3340Sstevel@tonic-gate 		}
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 		*equals = '\0';
3370Sstevel@tonic-gate 		pn = stable(cfgstr);
3380Sstevel@tonic-gate 
3394436Sstephh 		/*
3404436Sstephh 		 * only actually add the props if the rules use them (saves
3414436Sstephh 		 * memory)
3424436Sstephh 		 */
3435204Sstephh 		if ((lut_lookup(Usedprops, (void *)pn, NULL) != NULL ||
3445204Sstephh 		    strncmp(pn, "serd_", 5) == 0) && lut_lookup(Usednames,
3455204Sstephh 		    (void *)config_lastcomp, NULL) != NULL) {
3464436Sstephh 			pv = STRDUP(equals + 1);
3474436Sstephh 			out(O_ALTFP|O_VERB3, "add prop (%s) val %p", pn,
3484436Sstephh 			    (void *)pv);
3494436Sstephh 			config_setprop(newnode, pn, pv);
3504436Sstephh 		}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		/*
35312106SStephen.Hanson@Sun.COM 		 * If this property is a device path, tp or devid, cache it
3546640Scth 		 * for quick lookup.
3550Sstevel@tonic-gate 		 */
356*12618SStephen.Hanson@Sun.COM 		if (config_lastcomp == stable(SCSI_DEVICE) ||
357*12618SStephen.Hanson@Sun.COM 		    config_lastcomp == stable(SMP_DEVICE)) {
358*12618SStephen.Hanson@Sun.COM 			/*
359*12618SStephen.Hanson@Sun.COM 			 * we can't get ereports on SCSI_DEVICE or SMP_DEVICE
360*12618SStephen.Hanson@Sun.COM 			 * nodes, so don't cache.
361*12618SStephen.Hanson@Sun.COM 			 */
362*12618SStephen.Hanson@Sun.COM 			out(O_ALTFP|O_VERB3, "not caching %s for %s",
363*12618SStephen.Hanson@Sun.COM 			    pn, config_lastcomp);
364*12618SStephen.Hanson@Sun.COM 		} else if (pn == stable(TOPO_IO_DEV)) {
3654436Sstephh 			sv = stable(equals + 1);
36612106SStephen.Hanson@Sun.COM 			out(O_ALTFP|O_VERB3, "caching dev %s", sv);
3670Sstevel@tonic-gate 			cdata->devcache = lut_add(cdata->devcache,
3680Sstevel@tonic-gate 			    (void *)sv, (void *)newnode, NULL);
369*12618SStephen.Hanson@Sun.COM 		} else if (pn == stable(TOPO_IO_DEVID) ||
370*12618SStephen.Hanson@Sun.COM 		    pn == stable(TOPO_PROP_SES_DEVID) ||
371*12618SStephen.Hanson@Sun.COM 		    pn == stable(TOPO_PROP_SMP_DEVID)) {
3726640Scth 			sv = stable(equals + 1);
37312106SStephen.Hanson@Sun.COM 			out(O_ALTFP|O_VERB3, "caching devid %s", sv);
3746640Scth 			cdata->devidcache = lut_add(cdata->devidcache,
3756640Scth 			    (void *)sv, (void *)newnode, NULL);
37612106SStephen.Hanson@Sun.COM 		} else if (pn == stable(TOPO_STORAGE_TARGET_PORT_L0IDS)) {
37712106SStephen.Hanson@Sun.COM 			/*
37812106SStephen.Hanson@Sun.COM 			 * This was stored as a set of space-separated strings.
37912106SStephen.Hanson@Sun.COM 			 * Find each string in turn and add to the lut. Then if
38012106SStephen.Hanson@Sun.COM 			 * a ereport comes in with a target-path matching any
38112106SStephen.Hanson@Sun.COM 			 * of the strings we will match it.
38212106SStephen.Hanson@Sun.COM 			 */
38312106SStephen.Hanson@Sun.COM 			char *x, *y = equals;
38412106SStephen.Hanson@Sun.COM 			while (y != NULL) {
38512106SStephen.Hanson@Sun.COM 				x = y + 1;
38612106SStephen.Hanson@Sun.COM 				y = strchr(x, ' ');
38712106SStephen.Hanson@Sun.COM 				if (y != NULL)
38812106SStephen.Hanson@Sun.COM 					*y = '\0';
38912106SStephen.Hanson@Sun.COM 				sv = stable(x);
39012106SStephen.Hanson@Sun.COM 				out(O_ALTFP|O_VERB3, "caching tp %s", sv);
39112106SStephen.Hanson@Sun.COM 				cdata->tpcache = lut_add(cdata->tpcache,
39212106SStephen.Hanson@Sun.COM 				    (void *)sv, (void *)newnode, NULL);
39312106SStephen.Hanson@Sun.COM 				if (y != NULL)
39412106SStephen.Hanson@Sun.COM 					*y = ' ';
39512106SStephen.Hanson@Sun.COM 			}
3960Sstevel@tonic-gate 		}
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 		*equals = '=';
3990Sstevel@tonic-gate 		cfgstr += strlen(cfgstr) + 1;
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate eftcfgs:
4030Sstevel@tonic-gate 	/* now run through Configs table, adding to config cache */
4040Sstevel@tonic-gate 	lut_walk(Configs, (lut_cb)addconfig, (void *)cdata->cooked);
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate /*
4080Sstevel@tonic-gate  * config_snapshot -- gather a snapshot of the current configuration
4090Sstevel@tonic-gate  */
4100Sstevel@tonic-gate struct cfgdata *
config_snapshot(void)4110Sstevel@tonic-gate config_snapshot(void)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate 	struct cfgdata *rawcfg;
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	rawcfg = platform_config_snapshot();
4160Sstevel@tonic-gate 	config_cook(rawcfg);
4170Sstevel@tonic-gate 	return (rawcfg);
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate /*
4210Sstevel@tonic-gate  * prop_destructor -- free a prop value
4220Sstevel@tonic-gate  */
4230Sstevel@tonic-gate /*ARGSUSED*/
4240Sstevel@tonic-gate static void
prop_destructor(void * left,void * right,void * arg)4250Sstevel@tonic-gate prop_destructor(void *left, void *right, void *arg)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate 	FREE(right);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate /*
4310Sstevel@tonic-gate  * structconfig_free -- free a struct config pointer and all its relatives
4320Sstevel@tonic-gate  */
4335204Sstephh void
structconfig_free(struct config * cp)4340Sstevel@tonic-gate structconfig_free(struct config *cp)
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 	if (cp == NULL)
4370Sstevel@tonic-gate 		return;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	structconfig_free(cp->child);
4400Sstevel@tonic-gate 	structconfig_free(cp->next);
4410Sstevel@tonic-gate 	lut_free(cp->props, prop_destructor, NULL);
4420Sstevel@tonic-gate 	FREE(cp);
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate /*
4460Sstevel@tonic-gate  * config_free -- free a configuration snapshot
4470Sstevel@tonic-gate  */
4480Sstevel@tonic-gate void
config_free(struct cfgdata * cp)4490Sstevel@tonic-gate config_free(struct cfgdata *cp)
4500Sstevel@tonic-gate {
4510Sstevel@tonic-gate 	if (cp == NULL)
4520Sstevel@tonic-gate 		return;
4530Sstevel@tonic-gate 
4545204Sstephh 	if (--cp->raw_refcnt == 0) {
4554436Sstephh 		if (cp->devcache != NULL)
4564436Sstephh 			lut_free(cp->devcache, NULL, NULL);
4574436Sstephh 		cp->devcache = NULL;
45812106SStephen.Hanson@Sun.COM 		if (cp->tpcache != NULL)
45912106SStephen.Hanson@Sun.COM 			lut_free(cp->tpcache, NULL, NULL);
46012106SStephen.Hanson@Sun.COM 		cp->tpcache = NULL;
4616640Scth 		if (cp->devidcache != NULL)
4626640Scth 			lut_free(cp->devidcache, NULL, NULL);
4636640Scth 		cp->devidcache = NULL;
4644436Sstephh 		if (cp->cpucache != NULL)
4654436Sstephh 			lut_free(cp->cpucache, NULL, NULL);
4664436Sstephh 		cp->cpucache = NULL;
4674436Sstephh 		if (cp->begin != NULL)
4684436Sstephh 			FREE(cp->begin);
4694436Sstephh 		FREE(cp);
4704436Sstephh 	}
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate /*
4740Sstevel@tonic-gate  * config_next -- get the "next" config node
4750Sstevel@tonic-gate  */
4760Sstevel@tonic-gate struct config *
config_next(struct config * cp)4770Sstevel@tonic-gate config_next(struct config *cp)
4780Sstevel@tonic-gate {
4790Sstevel@tonic-gate 	ASSERT(cp != NULL);
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	return ((struct config *)((struct config *)cp)->next);
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate /*
4860Sstevel@tonic-gate  * config_child -- get the "child" of a config node
4870Sstevel@tonic-gate  */
4880Sstevel@tonic-gate struct config *
config_child(struct config * cp)4890Sstevel@tonic-gate config_child(struct config *cp)
4900Sstevel@tonic-gate {
4910Sstevel@tonic-gate 	ASSERT(cp != NULL);
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	return ((struct config *)((struct config *)cp)->child);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate /*
4974436Sstephh  * config_parent -- get the "parent" of a config node
4984436Sstephh  */
4994436Sstephh struct config *
config_parent(struct config * cp)5004436Sstephh config_parent(struct config *cp)
5014436Sstephh {
5024436Sstephh 	ASSERT(cp != NULL);
5034436Sstephh 
5044436Sstephh 	return ((struct config *)((struct config *)cp)->parent);
5054436Sstephh }
5064436Sstephh 
5074436Sstephh /*
5080Sstevel@tonic-gate  * config_setprop -- add a property to a config node
5090Sstevel@tonic-gate  */
5100Sstevel@tonic-gate void
config_setprop(struct config * cp,const char * propname,const char * propvalue)5110Sstevel@tonic-gate config_setprop(struct config *cp, const char *propname, const char *propvalue)
5120Sstevel@tonic-gate {
5130Sstevel@tonic-gate 	const char *pn = stable(propname);
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	cp->props = lut_add(cp->props, (void *)pn, (void *)propvalue, NULL);
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate /*
5190Sstevel@tonic-gate  * config_getprop -- lookup a config property
5200Sstevel@tonic-gate  */
5210Sstevel@tonic-gate const char *
config_getprop(struct config * cp,const char * propname)5220Sstevel@tonic-gate config_getprop(struct config *cp, const char *propname)
5230Sstevel@tonic-gate {
5240Sstevel@tonic-gate 	return (lut_lookup(cp->props, (void *) stable(propname), NULL));
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate /*
5280Sstevel@tonic-gate  * config_getcompname -- get the component name of a config node
5290Sstevel@tonic-gate  */
5300Sstevel@tonic-gate void
config_getcompname(struct config * cp,char ** name,int * inst)5310Sstevel@tonic-gate config_getcompname(struct config *cp, char **name, int *inst)
5320Sstevel@tonic-gate {
5330Sstevel@tonic-gate 	ASSERT(cp != NULL);
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	if (name != NULL)
5360Sstevel@tonic-gate 		*name = (char *)cp->s;
5370Sstevel@tonic-gate 	if (inst != NULL)
5380Sstevel@tonic-gate 		*inst = cp->num;
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate /*
5420Sstevel@tonic-gate  * config_nodeize -- convert the config element represented by cp to struct
5430Sstevel@tonic-gate  *		     node format
5440Sstevel@tonic-gate  */
5450Sstevel@tonic-gate static struct node *
config_nodeize(struct config * cp)5460Sstevel@tonic-gate config_nodeize(struct config *cp)
5470Sstevel@tonic-gate {
5480Sstevel@tonic-gate 	struct node *tmpn, *ptmpn;
5490Sstevel@tonic-gate 	struct node *numn;
5500Sstevel@tonic-gate 	const char *sname;
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	if (cp == NULL || cp->s == NULL)
5530Sstevel@tonic-gate 		return (NULL);
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	sname = stable(cp->s);
5560Sstevel@tonic-gate 	numn = newnode(T_NUM, NULL, 0);
5570Sstevel@tonic-gate 	numn->u.ull = cp->num;
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	tmpn = tree_name_iterator(tree_name(sname, IT_VERTICAL, NULL, 0), numn);
5600Sstevel@tonic-gate 	if ((ptmpn = config_nodeize(cp->parent)) == NULL)
5610Sstevel@tonic-gate 		return (tmpn);
5620Sstevel@tonic-gate 	return (tree_name_append(ptmpn, tmpn));
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate /*ARGSUSED*/
5660Sstevel@tonic-gate static void
prtdevcache(void * lhs,void * rhs,void * arg)5670Sstevel@tonic-gate prtdevcache(void *lhs, void *rhs, void *arg)
5680Sstevel@tonic-gate {
5690Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate /*ARGSUSED*/
5730Sstevel@tonic-gate static void
prtdevidcache(void * lhs,void * rhs,void * arg)5746640Scth prtdevidcache(void *lhs, void *rhs, void *arg)
5756640Scth {
5766640Scth 	out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
5776640Scth }
5786640Scth 
5796640Scth /*ARGSUSED*/
5806640Scth static void
prttpcache(void * lhs,void * rhs,void * arg)58112106SStephen.Hanson@Sun.COM prttpcache(void *lhs, void *rhs, void *arg)
58212106SStephen.Hanson@Sun.COM {
58312106SStephen.Hanson@Sun.COM 	out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
58412106SStephen.Hanson@Sun.COM }
58512106SStephen.Hanson@Sun.COM 
58612106SStephen.Hanson@Sun.COM /*ARGSUSED*/
58712106SStephen.Hanson@Sun.COM static void
prtcpucache(void * lhs,void * rhs,void * arg)5880Sstevel@tonic-gate prtcpucache(void *lhs, void *rhs, void *arg)
5890Sstevel@tonic-gate {
5900Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "%u -> %p", (uint32_t)lhs, rhs);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate /*
5946640Scth  * config_bydev_lookup -- look up the path in our devcache lut.  If we find
5950Sstevel@tonic-gate  * it return the config path, but as a struct node.
5960Sstevel@tonic-gate  */
5970Sstevel@tonic-gate struct node *
config_bydev_lookup(struct cfgdata * fromcfg,const char * path)5980Sstevel@tonic-gate config_bydev_lookup(struct cfgdata *fromcfg, const char *path)
5990Sstevel@tonic-gate {
6000Sstevel@tonic-gate 	struct config *find;
6010Sstevel@tonic-gate 	struct node *np;
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, "Device path cache:");
6040Sstevel@tonic-gate 	lut_walk(fromcfg->devcache, (lut_cb)prtdevcache, NULL);
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	if ((find = lut_lookup(fromcfg->devcache,
6070Sstevel@tonic-gate 	    (void *) stable(path), NULL)) == NULL)
6080Sstevel@tonic-gate 		return (NULL);
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	np = config_nodeize(find);
6110Sstevel@tonic-gate 	if (np != NULL) {
6120Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, "Matching config entry:");
6130Sstevel@tonic-gate 		ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np);
6140Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
6150Sstevel@tonic-gate 	}
6160Sstevel@tonic-gate 	return (np);
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate /*
6206640Scth  * config_bydevid_lookup -- look up the path in our DEVIDcache lut.
6216640Scth  * If we find it return the config path, but as a struct node.
6226640Scth  */
6236640Scth struct node *
config_bydevid_lookup(struct cfgdata * fromcfg,const char * devid)6246640Scth config_bydevid_lookup(struct cfgdata *fromcfg, const char *devid)
6256640Scth {
6266640Scth 	struct config *find;
6276640Scth 	struct node *np;
6286640Scth 
6296640Scth 	out(O_ALTFP|O_VERB3, "Device id cache:");
6306640Scth 	lut_walk(fromcfg->devcache, (lut_cb)prtdevidcache, NULL);
6316640Scth 
6326640Scth 	if ((find = lut_lookup(fromcfg->devidcache,
6336640Scth 	    (void *) stable(devid), NULL)) == NULL)
6346640Scth 		return (NULL);
6356640Scth 
6366640Scth 	np = config_nodeize(find);
6376640Scth 	if (np != NULL) {
6386640Scth 		out(O_ALTFP|O_VERB, "Matching config entry:");
6396640Scth 		ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np);
6406640Scth 		out(O_ALTFP|O_VERB, NULL);
6416640Scth 	}
6426640Scth 	return (np);
6436640Scth }
6446640Scth 
6456640Scth /*
64612106SStephen.Hanson@Sun.COM  * config_bytp_lookup -- look up the path in our TPcache lut.
64712106SStephen.Hanson@Sun.COM  * If we find it return the config path, but as a struct node.
64812106SStephen.Hanson@Sun.COM  */
64912106SStephen.Hanson@Sun.COM struct node *
config_bytp_lookup(struct cfgdata * fromcfg,const char * tp)65012106SStephen.Hanson@Sun.COM config_bytp_lookup(struct cfgdata *fromcfg, const char *tp)
65112106SStephen.Hanson@Sun.COM {
65212106SStephen.Hanson@Sun.COM 	struct config *find;
65312106SStephen.Hanson@Sun.COM 	struct node *np;
65412106SStephen.Hanson@Sun.COM 
65512106SStephen.Hanson@Sun.COM 	out(O_ALTFP|O_VERB3, "Device id cache:");
65612106SStephen.Hanson@Sun.COM 	lut_walk(fromcfg->devcache, (lut_cb)prttpcache, NULL);
65712106SStephen.Hanson@Sun.COM 
65812106SStephen.Hanson@Sun.COM 	if ((find = lut_lookup(fromcfg->tpcache,
65912106SStephen.Hanson@Sun.COM 	    (void *) stable(tp), NULL)) == NULL)
66012106SStephen.Hanson@Sun.COM 		return (NULL);
66112106SStephen.Hanson@Sun.COM 
66212106SStephen.Hanson@Sun.COM 	np = config_nodeize(find);
66312106SStephen.Hanson@Sun.COM 	if (np != NULL) {
66412106SStephen.Hanson@Sun.COM 		out(O_ALTFP|O_VERB, "Matching config entry:");
66512106SStephen.Hanson@Sun.COM 		ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np);
66612106SStephen.Hanson@Sun.COM 		out(O_ALTFP|O_VERB, NULL);
66712106SStephen.Hanson@Sun.COM 	}
66812106SStephen.Hanson@Sun.COM 	return (np);
66912106SStephen.Hanson@Sun.COM }
67012106SStephen.Hanson@Sun.COM 
67112106SStephen.Hanson@Sun.COM /*
6720Sstevel@tonic-gate  * config_bycpuid_lookup -- look up the cpu id in our CPUcache lut.
6730Sstevel@tonic-gate  * If we find it return the config path, but as a struct node.
6740Sstevel@tonic-gate  */
6750Sstevel@tonic-gate struct node *
config_bycpuid_lookup(struct cfgdata * fromcfg,uint32_t id)6760Sstevel@tonic-gate config_bycpuid_lookup(struct cfgdata *fromcfg, uint32_t id)
6770Sstevel@tonic-gate {
6780Sstevel@tonic-gate 	struct config *find;
6790Sstevel@tonic-gate 	struct node *np;
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "Cpu cache:");
6820Sstevel@tonic-gate 	lut_walk(fromcfg->cpucache, (lut_cb)prtcpucache, NULL);
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	if ((find = lut_lookup(fromcfg->cpucache,
6850Sstevel@tonic-gate 	    (void *)id, NULL)) == NULL)
6860Sstevel@tonic-gate 		return (NULL);
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	np = config_nodeize(find);
6890Sstevel@tonic-gate 	if (np != NULL) {
6900Sstevel@tonic-gate 		out(O_ALTFP|O_VERB3, "Matching config entry:");
6910Sstevel@tonic-gate 		ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, np);
6920Sstevel@tonic-gate 		out(O_ALTFP|O_VERB3, NULL);
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 	return (np);
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate /*
6980Sstevel@tonic-gate  * printprop -- print prop associated with config node
6990Sstevel@tonic-gate  */
7000Sstevel@tonic-gate static void
printprop(const char * lhs,const char * rhs,void * arg)7010Sstevel@tonic-gate printprop(const char *lhs, const char *rhs, void *arg)
7020Sstevel@tonic-gate {
7030Sstevel@tonic-gate 	int flags = (int)arg;
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	out(flags, "\t%s=%s", lhs, rhs);
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate /*
7090Sstevel@tonic-gate  * pconf -- internal printing function to recurse through the tree
7100Sstevel@tonic-gate  */
7110Sstevel@tonic-gate static void
pconf(int flags,struct config * cp,char * buf,int offset,int limit)7120Sstevel@tonic-gate pconf(int flags, struct config *cp, char *buf, int offset, int limit)
7130Sstevel@tonic-gate {
7140Sstevel@tonic-gate 	char *sep = "/";
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	if (offset)
7170Sstevel@tonic-gate 		sep = "/";
7180Sstevel@tonic-gate 	else
7190Sstevel@tonic-gate 		sep = "";
7200Sstevel@tonic-gate 	(void) snprintf(&buf[offset], limit - offset, "%s%s%d",
7210Sstevel@tonic-gate 	    sep, cp->s, cp->num);
7220Sstevel@tonic-gate 	if (cp->child == NULL) {
7230Sstevel@tonic-gate 		out(flags, "%s", buf);
7240Sstevel@tonic-gate 		lut_walk(cp->props, (lut_cb)printprop, (void *)flags);
7250Sstevel@tonic-gate 	} else
7260Sstevel@tonic-gate 		pconf(flags, cp->child, buf, strlen(buf), limit);
7270Sstevel@tonic-gate 	if (cp->next)
7280Sstevel@tonic-gate 		pconf(flags, cp->next, buf, offset, limit);
7290Sstevel@tonic-gate }
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate /*
7320Sstevel@tonic-gate  * config_print -- spew the current configuration cache
7330Sstevel@tonic-gate  */
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate #define	MAXCONFLINE 4096
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate void
config_print(int flags,struct config * croot)7380Sstevel@tonic-gate config_print(int flags, struct config *croot)
7390Sstevel@tonic-gate {
7400Sstevel@tonic-gate 	char buf[MAXCONFLINE];
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 	if (croot == NULL)
7430Sstevel@tonic-gate 		out(flags, "empty configuration");
7440Sstevel@tonic-gate 	else
7450Sstevel@tonic-gate 		pconf(flags, croot->child, buf, 0, MAXCONFLINE);
7460Sstevel@tonic-gate }
747