xref: /onnv-gate/usr/src/cmd/fm/modules/common/eversholt/ipath.c (revision 4436:35b72f77cdd9)
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
5*4436Sstephh  * Common Development and Distribution License (the "License").
6*4436Sstephh  * 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  */
210Sstevel@tonic-gate /*
22*4436Sstephh  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  * ipath.c -- instanced pathname module
260Sstevel@tonic-gate  *
270Sstevel@tonic-gate  * this module provides a cache of fully instantized component paths,
280Sstevel@tonic-gate  * stored in a fairly compact format.
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <stdio.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include "alloc.h"
360Sstevel@tonic-gate #include "out.h"
370Sstevel@tonic-gate #include "lut.h"
380Sstevel@tonic-gate #include "tree.h"
390Sstevel@tonic-gate #include "ptree.h"
400Sstevel@tonic-gate #include "itree.h"
410Sstevel@tonic-gate #include "ipath.h"
420Sstevel@tonic-gate #include "stats.h"
430Sstevel@tonic-gate #include "eval.h"
440Sstevel@tonic-gate #include "config.h"
450Sstevel@tonic-gate 
460Sstevel@tonic-gate static struct stats *Nipath;
470Sstevel@tonic-gate static struct stats *Nbytes;
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /* an ipath cache entry is an array of these, with s==NULL at the end */
500Sstevel@tonic-gate struct ipath {
510Sstevel@tonic-gate 	const char *s;	/* component name (in stable) */
520Sstevel@tonic-gate 	int i;		/* instance number */
530Sstevel@tonic-gate };
540Sstevel@tonic-gate 
550Sstevel@tonic-gate static struct lut *Ipaths;	/* the ipath cache itself */
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * ipath_init -- initialize the ipath module
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate void
610Sstevel@tonic-gate ipath_init(void)
620Sstevel@tonic-gate {
630Sstevel@tonic-gate 	Nipath = stats_new_counter("ievent.nipath", "ipath cache entries", 1);
640Sstevel@tonic-gate 	Nbytes = stats_new_counter("ievent.nbytes", "total cache size", 1);
650Sstevel@tonic-gate }
660Sstevel@tonic-gate 
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate  * ipath_cmp -- compare two ipath entries
690Sstevel@tonic-gate  *
700Sstevel@tonic-gate  * since two ipaths containing the same components and instance
710Sstevel@tonic-gate  * numbers always point to the same cache entry, they are equal
720Sstevel@tonic-gate  * if their pointers are equal, so this function is not necessary
730Sstevel@tonic-gate  * to test if two ipaths are same.  but when inserting a new ipath
740Sstevel@tonic-gate  * into the cache, we must use the same lut comparison logic as when
750Sstevel@tonic-gate  * we're searching for it, so this function must always match the
760Sstevel@tonic-gate  * itree_epnamecmp() function's logic (see below) for searching the lut.
770Sstevel@tonic-gate  */
780Sstevel@tonic-gate static int
790Sstevel@tonic-gate ipath_cmp(struct ipath *ipp1, struct ipath *ipp2)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate 	int i;
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	ASSERT(ipp1 != NULL);
840Sstevel@tonic-gate 	ASSERT(ipp2 != NULL);
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	for (i = 0; ipp1[i].s != NULL && ipp2[i].s != NULL; i++)
870Sstevel@tonic-gate 		if (ipp1[i].s != ipp2[i].s)
880Sstevel@tonic-gate 			return (ipp2[i].s - ipp1[i].s);
890Sstevel@tonic-gate 		else if (ipp1[i].i != ipp2[i].i)
900Sstevel@tonic-gate 			return (ipp2[i].i - ipp1[i].i);
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	if (ipp1[i].s == NULL && ipp2[i].s == NULL)
930Sstevel@tonic-gate 		return (0);
940Sstevel@tonic-gate 	else if (ipp1[i].s == NULL)
950Sstevel@tonic-gate 		return (1);
960Sstevel@tonic-gate 	else
970Sstevel@tonic-gate 		return (-1);
980Sstevel@tonic-gate }
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate /*
1010Sstevel@tonic-gate  * ipath_epnamecmp -- compare an ipath with a struct node *epname list
1020Sstevel@tonic-gate  *
1030Sstevel@tonic-gate  * this function is used when searching the cache, allowing us to search
1040Sstevel@tonic-gate  * a lut full of ipaths by looking directly at a struct node *epname
1050Sstevel@tonic-gate  * (without having to convert it first).  the comparison logic here must
1060Sstevel@tonic-gate  * exactly match itree_cmp()'s logic (see above) so lut lookups use find
1070Sstevel@tonic-gate  * the same node as lut inserts.
1080Sstevel@tonic-gate  */
1090Sstevel@tonic-gate static int
1100Sstevel@tonic-gate ipath_epnamecmp(struct ipath *ipp, struct node *np)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate 	int i;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	ASSERT(np != NULL);
1150Sstevel@tonic-gate 	ASSERT(ipp != NULL);
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	for (i = 0; ipp[i].s != NULL && np != NULL; i++, np = np->u.name.next) {
1180Sstevel@tonic-gate 		ASSERTinfo(np->t == T_NAME, ptree_nodetype2str(np->t));
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 		if (ipp[i].s != np->u.name.s)
1210Sstevel@tonic-gate 			return (np->u.name.s - ipp[i].s);
1220Sstevel@tonic-gate 		else {
1230Sstevel@tonic-gate 			int inum;
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 			if (np->u.name.child != NULL &&
1260Sstevel@tonic-gate 			    np->u.name.child->t == T_NUM)
1270Sstevel@tonic-gate 				inum = (int)np->u.name.child->u.ull;
1280Sstevel@tonic-gate 			else
1290Sstevel@tonic-gate 				config_getcompname(np->u.name.cp, NULL, &inum);
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 			if (ipp[i].i != inum)
1320Sstevel@tonic-gate 				return (inum - ipp[i].i);
1330Sstevel@tonic-gate 		}
1340Sstevel@tonic-gate 	}
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	if (ipp[i].s == NULL && np == NULL)
1370Sstevel@tonic-gate 		return (0);
1380Sstevel@tonic-gate 	else if (ipp[i].s == NULL)
1390Sstevel@tonic-gate 		return (1);
1400Sstevel@tonic-gate 	else
1410Sstevel@tonic-gate 		return (-1);
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate 
144*4436Sstephh struct lut *Usednames;
145*4436Sstephh 
146*4436Sstephh void
147*4436Sstephh ipath_dummy_lut(struct arrow *arrowp)
148*4436Sstephh {
149*4436Sstephh 	const struct ipath *ipp;
150*4436Sstephh 
151*4436Sstephh 	ipp = arrowp->head->myevent->ipp;
152*4436Sstephh 	while (ipp->s != NULL) {
153*4436Sstephh 		Usednames = lut_add(Usednames, (void *)ipp->s,
154*4436Sstephh 		    (void *)ipp->s, NULL);
155*4436Sstephh 		ipp++;
156*4436Sstephh 	}
157*4436Sstephh 	ipp = arrowp->tail->myevent->ipp;
158*4436Sstephh 	while (ipp->s != NULL) {
159*4436Sstephh 		Usednames = lut_add(Usednames, (void *)ipp->s,
160*4436Sstephh 		    (void *)ipp->s, NULL);
161*4436Sstephh 		ipp++;
162*4436Sstephh 	}
163*4436Sstephh }
164*4436Sstephh 
165*4436Sstephh struct ipath *
166*4436Sstephh ipath_dummy(struct node *np, struct ipath *ipp)
167*4436Sstephh {
168*4436Sstephh 	struct ipath *ret;
169*4436Sstephh 
170*4436Sstephh 	ret = ipp;
171*4436Sstephh 	while (ipp[1].s != NULL)
172*4436Sstephh 		ipp++;
173*4436Sstephh 	if (strcmp(ipp[0].s, np->u.name.last->u.name.s) == 0)
174*4436Sstephh 		return (ret);
175*4436Sstephh 
176*4436Sstephh 	ret = MALLOC(sizeof (*ret) * 2);
177*4436Sstephh 	ret[0].s = np->u.name.last->u.name.s;
178*4436Sstephh 	ret[0].i = 0;
179*4436Sstephh 	ret[1].s = NULL;
180*4436Sstephh 	if ((ipp = lut_lookup(Ipaths, (void *)ret,
181*4436Sstephh 	    (lut_cmp)ipath_cmp)) != NULL) {
182*4436Sstephh 		FREE(ret);
183*4436Sstephh 		return (ipp);
184*4436Sstephh 	}
185*4436Sstephh 	Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret, (lut_cmp)ipath_cmp);
186*4436Sstephh 	stats_counter_bump(Nipath);
187*4436Sstephh 	stats_counter_add(Nbytes, 2 * sizeof (struct ipath));
188*4436Sstephh 	return (ret);
189*4436Sstephh }
190*4436Sstephh 
1910Sstevel@tonic-gate /*
1920Sstevel@tonic-gate  * ipath -- find instanced path in cache, or add it if necessary
1930Sstevel@tonic-gate  */
1940Sstevel@tonic-gate const struct ipath *
1950Sstevel@tonic-gate ipath(struct node *np)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	struct ipath *ret;
1980Sstevel@tonic-gate 	int count;
1990Sstevel@tonic-gate 	struct node *namep;
2000Sstevel@tonic-gate 	int i;
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	if ((ret = lut_lookup(Ipaths, (void *)np,
2030Sstevel@tonic-gate 	    (lut_cmp)ipath_epnamecmp)) != NULL)
2040Sstevel@tonic-gate 		return (ret);	/* already in cache */
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	/*
2070Sstevel@tonic-gate 	 * not in cache, make new cache entry.
2080Sstevel@tonic-gate 	 * start by counting the length of the name.
2090Sstevel@tonic-gate 	 */
2100Sstevel@tonic-gate 	count = 0;
2110Sstevel@tonic-gate 	namep = np;
2120Sstevel@tonic-gate 	while (namep != NULL) {
2130Sstevel@tonic-gate 		ASSERTinfo(namep->t == T_NAME, ptree_nodetype2str(namep->t));
2140Sstevel@tonic-gate 		count++;
2150Sstevel@tonic-gate 		namep = namep->u.name.next;
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	ASSERT(count > 0);
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	/* allocate array for name and last NULL entry */
2210Sstevel@tonic-gate 	ret = MALLOC(sizeof (*ret) * (count + 1));
2220Sstevel@tonic-gate 	ret[count].s = NULL;
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	/* fill in ipath entry */
2250Sstevel@tonic-gate 	namep = np;
2260Sstevel@tonic-gate 	i = 0;
2270Sstevel@tonic-gate 	while (namep != NULL) {
2280Sstevel@tonic-gate 		ASSERT(i < count);
2290Sstevel@tonic-gate 		ret[i].s = namep->u.name.s;
2300Sstevel@tonic-gate 		if (namep->u.name.child != NULL &&
2310Sstevel@tonic-gate 		    namep->u.name.child->t == T_NUM)
2320Sstevel@tonic-gate 			ret[i].i = (int)namep->u.name.child->u.ull;
2330Sstevel@tonic-gate 		else
2340Sstevel@tonic-gate 			config_getcompname(namep->u.name.cp, NULL, &ret[i].i);
2350Sstevel@tonic-gate 		i++;
2360Sstevel@tonic-gate 		namep = namep->u.name.next;
2370Sstevel@tonic-gate 	}
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	/* add it to the cache */
2400Sstevel@tonic-gate 	Ipaths = lut_add(Ipaths, (void *)ret, (void *)ret,
2410Sstevel@tonic-gate 	    (lut_cmp)ipath_cmp);
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	stats_counter_bump(Nipath);
2440Sstevel@tonic-gate 	stats_counter_add(Nbytes, (count + 1) * sizeof (struct ipath));
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	return (ret);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate /*
2500Sstevel@tonic-gate  * ipath2str -- convert ename and ipath to class@path string
2510Sstevel@tonic-gate  *
2520Sstevel@tonic-gate  * if both ename and ipp are provided (non-NULL), the resulting string
2530Sstevel@tonic-gate  * will be "class@path".  otherwise, the string will just contain the
2540Sstevel@tonic-gate  * event class name (e.g. "ereport.io.pci.device") or just the path
2550Sstevel@tonic-gate  * name (e.g. "mothboard0/hostbridge0/pcibus1/pcidev0/pcifn1"), depending
2560Sstevel@tonic-gate  * on which argument is non-NULL.
2570Sstevel@tonic-gate  */
2580Sstevel@tonic-gate char *
2590Sstevel@tonic-gate ipath2str(const char *ename, const struct ipath *ipp)
2600Sstevel@tonic-gate {
2610Sstevel@tonic-gate 	int i;
2620Sstevel@tonic-gate 	size_t len = 0;
2630Sstevel@tonic-gate 	char *ret;
2640Sstevel@tonic-gate 	char *cp;
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	/* count up length of class string */
2670Sstevel@tonic-gate 	if (ename != NULL)
2680Sstevel@tonic-gate 		len += strlen(ename);
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	/* count up length of path string, including slash separators */
2710Sstevel@tonic-gate 	if (ipp != NULL) {
2720Sstevel@tonic-gate 		for (i = 0; ipp[i].s != NULL; i++) {
2730Sstevel@tonic-gate 			/* add slash separator, but no leading slash */
2740Sstevel@tonic-gate 			if (i != 0)
2750Sstevel@tonic-gate 				len++;
2760Sstevel@tonic-gate 			len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i);
2770Sstevel@tonic-gate 		}
2780Sstevel@tonic-gate 	}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	if (ename != NULL && ipp != NULL)
2810Sstevel@tonic-gate 		len++;	/* room for '@' */
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	len++;	/* room for final '\0' */
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	cp = ret = MALLOC(len);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	if (ename != NULL) {
2880Sstevel@tonic-gate 		/* construct class string */
2890Sstevel@tonic-gate 		(void) strcpy(cp, ename);
2900Sstevel@tonic-gate 		cp += strlen(cp);
2910Sstevel@tonic-gate 	}
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	/* if doing both strings, put '@' between them */
2940Sstevel@tonic-gate 	if (ename != NULL && ipp != NULL)
2950Sstevel@tonic-gate 		*cp++ = '@';
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	if (ipp != NULL) {
2980Sstevel@tonic-gate 		/* construct path string */
2990Sstevel@tonic-gate 		for (i = 0; ipp[i].s != NULL; i++) {
3000Sstevel@tonic-gate 			if (i != 0)
3010Sstevel@tonic-gate 				*cp++ = '/';
3020Sstevel@tonic-gate 			(void) snprintf(cp, &ret[len] - cp, "%s%d",
3030Sstevel@tonic-gate 			    ipp[i].s, ipp[i].i);
3040Sstevel@tonic-gate 			cp += strlen(cp);
3050Sstevel@tonic-gate 		}
3060Sstevel@tonic-gate 	}
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	*cp++ = '\0';
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	return (ret);
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate /*
3141414Scindi  * ipath2strlen -- calculate the len of what ipath2str() would return
3151414Scindi  */
3161414Scindi size_t
3171414Scindi ipath2strlen(const char *ename, const struct ipath *ipp)
3181414Scindi {
3191414Scindi 	int i;
3201414Scindi 	size_t len = 0;
3211414Scindi 
3221414Scindi 	/* count up length of class string */
3231414Scindi 	if (ename != NULL)
3241414Scindi 		len += strlen(ename);
3251414Scindi 
3261414Scindi 	/* count up length of path string, including slash separators */
3271414Scindi 	if (ipp != NULL) {
3281414Scindi 		for (i = 0; ipp[i].s != NULL; i++) {
3291414Scindi 			/* add slash separator, but no leading slash */
3301414Scindi 			if (i != 0)
3311414Scindi 				len++;
3321414Scindi 			len += snprintf(NULL, 0, "%s%d", ipp[i].s, ipp[i].i);
3331414Scindi 		}
3341414Scindi 	}
3351414Scindi 
3361414Scindi 	if (ename != NULL && ipp != NULL)
3371414Scindi 		len++;	/* room for '@' */
3381414Scindi 
3391414Scindi 	return (len);
3401414Scindi }
3411414Scindi 
3421414Scindi /*
3430Sstevel@tonic-gate  * ipath_print -- print out an ename, ipath, or both with '@' between them
3440Sstevel@tonic-gate  */
3450Sstevel@tonic-gate void
3460Sstevel@tonic-gate ipath_print(int flags, const char *ename, const struct ipath *ipp)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 	if (ename != NULL) {
3490Sstevel@tonic-gate 		out(flags|O_NONL, ename);
3500Sstevel@tonic-gate 		if (ipp != NULL)
3510Sstevel@tonic-gate 			out(flags|O_NONL, "@");
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 	if (ipp != NULL) {
3540Sstevel@tonic-gate 		char *sep = "";
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 		while (ipp->s != NULL) {
3570Sstevel@tonic-gate 			out(flags|O_NONL, "%s%s%d", sep, ipp->s, ipp->i);
3580Sstevel@tonic-gate 			ipp++;
3590Sstevel@tonic-gate 			sep = "/";
3600Sstevel@tonic-gate 		}
3610Sstevel@tonic-gate 	}
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate /*ARGSUSED*/
3650Sstevel@tonic-gate static void
3660Sstevel@tonic-gate ipath_destructor(void *left, void *right, void *arg)
3670Sstevel@tonic-gate {
3680Sstevel@tonic-gate 	struct ipath *ipp = (struct ipath *)right;
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	FREE(ipp);
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate /*
3740Sstevel@tonic-gate  * ipath_fini -- free the ipath cache
3750Sstevel@tonic-gate  */
3760Sstevel@tonic-gate void
3770Sstevel@tonic-gate ipath_fini(void)
3780Sstevel@tonic-gate {
3790Sstevel@tonic-gate 	lut_free(Ipaths, ipath_destructor, NULL);
3800Sstevel@tonic-gate 	Ipaths = NULL;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	if (Nipath) {
3830Sstevel@tonic-gate 		stats_delete(Nipath);
3840Sstevel@tonic-gate 		Nipath = NULL;
3850Sstevel@tonic-gate 	}
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	if (Nbytes) {
3880Sstevel@tonic-gate 		stats_delete(Nbytes);
3890Sstevel@tonic-gate 		Nbytes = NULL;
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate }
392