xref: /onnv-gate/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c (revision 10817:7dfde45252f0)
11414Scindi /*
21414Scindi  * CDDL HEADER START
31414Scindi  *
41414Scindi  * The contents of this file are subject to the terms of the
51414Scindi  * Common Development and Distribution License (the "License").
61414Scindi  * You may not use this file except in compliance with the License.
71414Scindi  *
81414Scindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91414Scindi  * or http://www.opensolaris.org/os/licensing.
101414Scindi  * See the License for the specific language governing permissions
111414Scindi  * and limitations under the License.
121414Scindi  *
131414Scindi  * When distributing Covered Code, include this CDDL HEADER in each
141414Scindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151414Scindi  * If applicable, add the following below this CDDL HEADER, with the
161414Scindi  * fields enclosed by brackets "[]" replaced with your own identifying
171414Scindi  * information: Portions Copyright [yyyy] [name of copyright owner]
181414Scindi  *
191414Scindi  * CDDL HEADER END
201414Scindi  */
211414Scindi 
221414Scindi /*
239874SStephen.Hanson@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241414Scindi  * Use is subject to license terms.
251414Scindi  */
261414Scindi 
276869Seschrock #include <ctype.h>
281414Scindi #include <string.h>
291414Scindi #include <limits.h>
301414Scindi #include <fm/topo_mod.h>
317275Sstephh #include <fm/fmd_fmri.h>
321414Scindi #include <sys/fm/protocol.h>
331414Scindi #include <topo_alloc.h>
341414Scindi #include <topo_error.h>
356869Seschrock #include <topo_hc.h>
363062Scindi #include <topo_method.h>
371414Scindi #include <topo_subr.h>
381414Scindi #include <topo_string.h>
391414Scindi 
404087Scindi /*
414087Scindi  * Topology node properties and method operations may be accessed by FMRI.
424087Scindi  * The FMRI used to perform property look-ups and method operations is
434087Scindi  * the FMRI contained in the matching topology node's protocol property
444087Scindi  * grouping for the resource property. The full range of fmd(1M)
454087Scindi  * scheme plugin operations are supported as long as a backend method is
464087Scindi  * supplied by a scheme-specific enumerator or the enumerator module that
474087Scindi  * created the matching topology node.  Support for fmd scheme operations
484087Scindi  * include:
494087Scindi  *
504087Scindi  *	- expand
514087Scindi  *	- present
527275Sstephh  *	- replaced
534087Scindi  *	- contains
544087Scindi  *	- unusable
557275Sstephh  *	- service_state
564087Scindi  *	- nvl2str
577532SSean.Ye@Sun.COM  *	- retire
587532SSean.Ye@Sun.COM  *	- unretire
594087Scindi  *
604087Scindi  * In addition, the following operations are supported per-FMRI:
614087Scindi  *
624087Scindi  *	- str2nvl: convert string-based FMRI to nvlist
634087Scindi  *	- compare: compare two FMRIs
644087Scindi  *	- asru: lookup associated ASRU property by FMRI
654087Scindi  *	- fru: lookup associated FRU by FMRI
664087Scindi  *	- create: an FMRI nvlist by scheme type
674087Scindi  *	- propery lookup
684087Scindi  *
694087Scindi  * These routines may only be called by consumers of a topology snapshot.
704087Scindi  * They may not be called by libtopo enumerator or method modules.
714087Scindi  */
724087Scindi 
731414Scindi /*ARGSUSED*/
741414Scindi static int
set_error(topo_hdl_t * thp,int err,int * errp,char * method,nvlist_t * nvlp)751414Scindi set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp)
761414Scindi {
771414Scindi 	if (nvlp != NULL)
781414Scindi 		nvlist_free(nvlp);
791414Scindi 
803062Scindi 	topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method,
811414Scindi 	    topo_strerror(err));
821414Scindi 
831414Scindi 	*errp = err;
841414Scindi 	return (-1);
851414Scindi }
861414Scindi 
871414Scindi /*ARGSUSED*/
881414Scindi static nvlist_t *
set_nverror(topo_hdl_t * thp,int err,int * errp,char * method,nvlist_t * nvlp)891414Scindi set_nverror(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp)
901414Scindi {
911414Scindi 	if (nvlp != NULL)
921414Scindi 		nvlist_free(nvlp);
931414Scindi 
943062Scindi 	topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method,
951414Scindi 	    topo_strerror(err));
961414Scindi 
971414Scindi 	*errp = err;
981414Scindi 	return (NULL);
991414Scindi }
1001414Scindi 
1011414Scindi int
topo_fmri_nvl2str(topo_hdl_t * thp,nvlist_t * fmri,char ** fmristr,int * err)1021414Scindi topo_fmri_nvl2str(topo_hdl_t *thp, nvlist_t *fmri, char **fmristr, int *err)
1031414Scindi {
1041414Scindi 	char *scheme, *str;
1051414Scindi 	nvlist_t *out = NULL;
1061414Scindi 	tnode_t *rnode;
1071414Scindi 
1081414Scindi 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
1091414Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
1101414Scindi 		    TOPO_METH_NVL2STR, out));
1111414Scindi 
1121414Scindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
1131414Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
1141414Scindi 		    TOPO_METH_NVL2STR, out));
1151414Scindi 
1161414Scindi 	if (topo_method_invoke(rnode, TOPO_METH_NVL2STR,
1171414Scindi 	    TOPO_METH_NVL2STR_VERSION, fmri, &out, err) != 0)
1181414Scindi 		return (set_error(thp, *err, err, TOPO_METH_NVL2STR, out));
1191414Scindi 
1201414Scindi 	if (out == NULL || nvlist_lookup_string(out, "fmri-string", &str) != 0)
1211414Scindi 		return (set_error(thp, ETOPO_METHOD_INVAL, err,
1221414Scindi 		    TOPO_METH_NVL2STR, out));
1231414Scindi 
1241414Scindi 	if ((*fmristr = topo_hdl_strdup(thp, str)) == NULL)
1251414Scindi 		return (set_error(thp, ETOPO_NOMEM, err,
1261414Scindi 		    TOPO_METH_NVL2STR, out));
1271414Scindi 
1281414Scindi 	nvlist_free(out);
1291414Scindi 
1301414Scindi 	return (0);
1311414Scindi }
1321414Scindi 
1331414Scindi int
topo_fmri_str2nvl(topo_hdl_t * thp,const char * fmristr,nvlist_t ** fmri,int * err)1341414Scindi topo_fmri_str2nvl(topo_hdl_t *thp, const char *fmristr, nvlist_t **fmri,
1351414Scindi     int *err)
1361414Scindi {
1373062Scindi 	char *f, buf[PATH_MAX];
1381414Scindi 	nvlist_t *out = NULL, *in = NULL;
1391414Scindi 	tnode_t *rnode;
1401414Scindi 
1413062Scindi 	(void) strlcpy(buf, fmristr, sizeof (buf));
1423062Scindi 	if ((f = strchr(buf, ':')) == NULL)
1431414Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
1441414Scindi 		    TOPO_METH_STR2NVL, in));
1451414Scindi 
1461414Scindi 	*f = '\0'; /* strip trailing FMRI path */
1471414Scindi 
1483062Scindi 	if ((rnode = topo_hdl_root(thp, buf)) == NULL)
1491414Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
1501414Scindi 		    TOPO_METH_STR2NVL, in));
1511414Scindi 
1521414Scindi 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
1531414Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL,
1541414Scindi 		    in));
1551414Scindi 
1561414Scindi 	if (nvlist_add_string(in, "fmri-string", fmristr) != 0)
1571414Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL,
1581414Scindi 		    in));
1591414Scindi 
1601414Scindi 	if (topo_method_invoke(rnode, TOPO_METH_STR2NVL,
1611414Scindi 	    TOPO_METH_STR2NVL_VERSION, in, &out, err) != 0)
1621414Scindi 		return (set_error(thp, *err, err, TOPO_METH_STR2NVL, in));
1631414Scindi 
1644328Scindi 	nvlist_free(in);
1654328Scindi 
1661414Scindi 	if (out == NULL ||
1671414Scindi 	    topo_hdl_nvdup(thp, out, fmri) != 0)
1681414Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
1694328Scindi 		    TOPO_METH_STR2NVL, out));
1701414Scindi 
1711414Scindi 	nvlist_free(out);
1721414Scindi 
1731414Scindi 	return (0);
1741414Scindi }
1751414Scindi 
1761414Scindi int
topo_fmri_present(topo_hdl_t * thp,nvlist_t * fmri,int * err)1771414Scindi topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err)
1781414Scindi {
1793062Scindi 	uint32_t present = 0;
1801414Scindi 	char *scheme;
1811414Scindi 	nvlist_t *out = NULL;
1821414Scindi 	tnode_t *rnode;
1831414Scindi 
1841414Scindi 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
1851414Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
1861414Scindi 		    TOPO_METH_PRESENT, out));
1871414Scindi 
1881414Scindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
1891414Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
1901414Scindi 		    TOPO_METH_PRESENT, out));
1911414Scindi 
1923062Scindi 	if (topo_method_invoke(rnode, TOPO_METH_PRESENT,
1933062Scindi 	    TOPO_METH_PRESENT_VERSION, fmri, &out, err) < 0) {
1943062Scindi 		(void) set_error(thp, *err, err, TOPO_METH_PRESENT, out);
1953062Scindi 		return (present);
1963062Scindi 	}
1971414Scindi 
1983062Scindi 	(void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present);
1993062Scindi 	nvlist_free(out);
2003062Scindi 
2013062Scindi 	return (present);
2021414Scindi }
2031414Scindi 
2041414Scindi int
topo_fmri_replaced(topo_hdl_t * thp,nvlist_t * fmri,int * err)2057275Sstephh topo_fmri_replaced(topo_hdl_t *thp, nvlist_t *fmri, int *err)
2067275Sstephh {
2077275Sstephh 	uint32_t replaced = FMD_OBJ_STATE_NOT_PRESENT;
2087275Sstephh 	char *scheme;
2097275Sstephh 	nvlist_t *out = NULL;
2107275Sstephh 	tnode_t *rnode;
2117275Sstephh 
2127275Sstephh 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
2137275Sstephh 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
2147275Sstephh 		    TOPO_METH_REPLACED, out));
2157275Sstephh 
2167275Sstephh 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
2177275Sstephh 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
2187275Sstephh 		    TOPO_METH_REPLACED, out));
2197275Sstephh 
2207275Sstephh 	if (topo_method_invoke(rnode, TOPO_METH_REPLACED,
2217275Sstephh 	    TOPO_METH_REPLACED_VERSION, fmri, &out, err) < 0) {
2227275Sstephh 		(void) set_error(thp, *err, err, TOPO_METH_REPLACED, out);
2237275Sstephh 		return (FMD_OBJ_STATE_UNKNOWN);
2247275Sstephh 	}
2257275Sstephh 
2267275Sstephh 	(void) nvlist_lookup_uint32(out, TOPO_METH_REPLACED_RET, &replaced);
2277275Sstephh 	nvlist_free(out);
2287275Sstephh 
2297275Sstephh 	return (replaced);
2307275Sstephh }
2317275Sstephh 
2327275Sstephh int
topo_fmri_contains(topo_hdl_t * thp,nvlist_t * fmri,nvlist_t * subfmri,int * err)2331414Scindi topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err)
2341414Scindi {
2354087Scindi 	uint32_t contains;
2361414Scindi 	char *scheme;
2374087Scindi 	nvlist_t *in = NULL, *out = NULL;
2381414Scindi 	tnode_t *rnode;
2391414Scindi 
2401414Scindi 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
2411414Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
2424087Scindi 		    TOPO_METH_CONTAINS, NULL));
2431414Scindi 
2441414Scindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
2451414Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
2464087Scindi 		    TOPO_METH_CONTAINS, NULL));
2471414Scindi 
2481414Scindi 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
2491414Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
2504087Scindi 		    NULL));
2511414Scindi 
2524087Scindi 	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 ||
2534087Scindi 	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0)
2541414Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
2554087Scindi 		    in));
2561414Scindi 
2574087Scindi 	if (topo_method_invoke(rnode, TOPO_METH_CONTAINS,
2587532SSean.Ye@Sun.COM 	    TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0)
2594087Scindi 		return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in));
2601414Scindi 
2614087Scindi 	(void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains);
2624087Scindi 	nvlist_free(in);
2634087Scindi 	nvlist_free(out);
2644087Scindi 
2654087Scindi 	return (contains);
2661414Scindi }
2671414Scindi 
2681414Scindi int
topo_fmri_unusable(topo_hdl_t * thp,nvlist_t * fmri,int * err)2691414Scindi topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err)
2701414Scindi {
2711414Scindi 	char *scheme;
2723681Svn83148 	uint32_t unusable = 0;
2731414Scindi 	nvlist_t *out = NULL;
2741414Scindi 	tnode_t *rnode;
2751414Scindi 
2761414Scindi 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
2771414Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
2781414Scindi 		    TOPO_METH_UNUSABLE, out));
2791414Scindi 
2801414Scindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
2811414Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
2821414Scindi 		    TOPO_METH_UNUSABLE, out));
2831414Scindi 
2843681Svn83148 	if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE,
2853681Svn83148 	    TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0)
2861414Scindi 		return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out));
2871414Scindi 
2883681Svn83148 	(void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable);
2893681Svn83148 	nvlist_free(out);
2903681Svn83148 
2913681Svn83148 	return (unusable);
2921414Scindi }
2931414Scindi 
2941414Scindi int
topo_fmri_retire(topo_hdl_t * thp,nvlist_t * fmri,int * err)2957532SSean.Ye@Sun.COM topo_fmri_retire(topo_hdl_t *thp, nvlist_t *fmri, int *err)
2967532SSean.Ye@Sun.COM {
2977532SSean.Ye@Sun.COM 	char *scheme;
2987532SSean.Ye@Sun.COM 	uint32_t status;
2997532SSean.Ye@Sun.COM 	nvlist_t *out = NULL;
3007532SSean.Ye@Sun.COM 	tnode_t *rnode;
3017532SSean.Ye@Sun.COM 
3027532SSean.Ye@Sun.COM 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
3037532SSean.Ye@Sun.COM 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
3047532SSean.Ye@Sun.COM 		    TOPO_METH_RETIRE, out));
3057532SSean.Ye@Sun.COM 
3067532SSean.Ye@Sun.COM 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
3077532SSean.Ye@Sun.COM 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
3087532SSean.Ye@Sun.COM 		    TOPO_METH_RETIRE, out));
3097532SSean.Ye@Sun.COM 
3107532SSean.Ye@Sun.COM 	if (topo_method_invoke(rnode, TOPO_METH_RETIRE,
3117532SSean.Ye@Sun.COM 	    TOPO_METH_RETIRE_VERSION, fmri, &out, err) < 0)
3127532SSean.Ye@Sun.COM 		return (set_error(thp, *err, err, TOPO_METH_RETIRE, out));
3137532SSean.Ye@Sun.COM 
3147532SSean.Ye@Sun.COM 	if (nvlist_lookup_uint32(out, TOPO_METH_RETIRE_RET, &status) != 0)
3157532SSean.Ye@Sun.COM 		return (set_error(thp, ETOPO_METHOD_FAIL, err,
3167532SSean.Ye@Sun.COM 		    TOPO_METH_RETIRE, out));
3177532SSean.Ye@Sun.COM 	nvlist_free(out);
3187532SSean.Ye@Sun.COM 
3197532SSean.Ye@Sun.COM 	return (status);
3207532SSean.Ye@Sun.COM }
3217532SSean.Ye@Sun.COM 
3227532SSean.Ye@Sun.COM int
topo_fmri_unretire(topo_hdl_t * thp,nvlist_t * fmri,int * err)3237532SSean.Ye@Sun.COM topo_fmri_unretire(topo_hdl_t *thp, nvlist_t *fmri, int *err)
3247532SSean.Ye@Sun.COM {
3257532SSean.Ye@Sun.COM 	char *scheme;
3267532SSean.Ye@Sun.COM 	uint32_t status;
3277532SSean.Ye@Sun.COM 	nvlist_t *out = NULL;
3287532SSean.Ye@Sun.COM 	tnode_t *rnode;
3297532SSean.Ye@Sun.COM 
3307532SSean.Ye@Sun.COM 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
3317532SSean.Ye@Sun.COM 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
3327532SSean.Ye@Sun.COM 		    TOPO_METH_UNRETIRE, out));
3337532SSean.Ye@Sun.COM 
3347532SSean.Ye@Sun.COM 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
3357532SSean.Ye@Sun.COM 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
3367532SSean.Ye@Sun.COM 		    TOPO_METH_UNRETIRE, out));
3377532SSean.Ye@Sun.COM 
3387532SSean.Ye@Sun.COM 	if (topo_method_invoke(rnode, TOPO_METH_UNRETIRE,
3397532SSean.Ye@Sun.COM 	    TOPO_METH_UNRETIRE_VERSION, fmri, &out, err) < 0)
3407532SSean.Ye@Sun.COM 		return (set_error(thp, *err, err, TOPO_METH_UNRETIRE, out));
3417532SSean.Ye@Sun.COM 
3427532SSean.Ye@Sun.COM 	if (nvlist_lookup_uint32(out, TOPO_METH_UNRETIRE_RET, &status) != 0) {
3437532SSean.Ye@Sun.COM 		nvlist_free(out);
3447532SSean.Ye@Sun.COM 		return (set_error(thp, ETOPO_METHOD_FAIL, err,
3457532SSean.Ye@Sun.COM 		    TOPO_METH_UNRETIRE, out));
3467532SSean.Ye@Sun.COM 	}
3477532SSean.Ye@Sun.COM 	nvlist_free(out);
3487532SSean.Ye@Sun.COM 
3497532SSean.Ye@Sun.COM 	return (status);
3507532SSean.Ye@Sun.COM }
3517532SSean.Ye@Sun.COM 
3527532SSean.Ye@Sun.COM int
topo_fmri_service_state(topo_hdl_t * thp,nvlist_t * fmri,int * err)3537275Sstephh topo_fmri_service_state(topo_hdl_t *thp, nvlist_t *fmri, int *err)
3547275Sstephh {
3557275Sstephh 	char *scheme;
3567275Sstephh 	uint32_t service_state = FMD_SERVICE_STATE_UNKNOWN;
3577275Sstephh 	nvlist_t *out = NULL;
3587275Sstephh 	tnode_t *rnode;
3597275Sstephh 
3607275Sstephh 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
3617275Sstephh 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
3627275Sstephh 		    TOPO_METH_SERVICE_STATE, out));
3637275Sstephh 
3647275Sstephh 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
3657275Sstephh 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
3667275Sstephh 		    TOPO_METH_SERVICE_STATE, out));
3677275Sstephh 
3687275Sstephh 	if (topo_method_invoke(rnode, TOPO_METH_SERVICE_STATE,
3697275Sstephh 	    TOPO_METH_SERVICE_STATE_VERSION, fmri, &out, err) < 0)
3707275Sstephh 		return (set_error(thp, *err, err, TOPO_METH_SERVICE_STATE,
3717275Sstephh 		    out));
3727275Sstephh 
3737275Sstephh 	(void) nvlist_lookup_uint32(out, TOPO_METH_SERVICE_STATE_RET,
3747275Sstephh 	    &service_state);
3757275Sstephh 	nvlist_free(out);
3767275Sstephh 
3777275Sstephh 	return (service_state);
3787275Sstephh }
3797275Sstephh 
3807275Sstephh int
topo_fmri_expand(topo_hdl_t * thp,nvlist_t * fmri,int * err)3811414Scindi topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err)
3821414Scindi {
3831414Scindi 	char *scheme;
3841414Scindi 	nvlist_t *out = NULL;
3851414Scindi 	tnode_t *rnode;
3861414Scindi 
3871414Scindi 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
3881414Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
3891414Scindi 		    TOPO_METH_EXPAND, out));
3901414Scindi 
3911414Scindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
3921414Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
3931414Scindi 		    TOPO_METH_EXPAND, out));
3941414Scindi 
3951414Scindi 	if (topo_method_invoke(rnode, TOPO_METH_EXPAND,
3961414Scindi 	    TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0)
3971414Scindi 		return (set_error(thp, *err, err, TOPO_METH_EXPAND, out));
3981414Scindi 
3991414Scindi 	return (0);
4001414Scindi }
4011414Scindi 
4021414Scindi static int
fmri_prop(topo_hdl_t * thp,nvlist_t * rsrc,const char * pgname,const char * pname,nvlist_t * args,nvlist_t ** prop,int * err)4034087Scindi fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
4044087Scindi     const char *pname, nvlist_t *args, nvlist_t **prop,
4054087Scindi     int *err)
4061414Scindi {
4074087Scindi 	int rv;
4084087Scindi 	nvlist_t *in = NULL;
4094087Scindi 	tnode_t *rnode;
4104087Scindi 	char *scheme;
4113323Scindi 
4124087Scindi 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
4134087Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
4144087Scindi 		    TOPO_METH_PROP_GET, in));
4151414Scindi 
4164087Scindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
4174087Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
4184087Scindi 		    TOPO_METH_PROP_GET, in));
4191414Scindi 
4204087Scindi 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
4214087Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
4224087Scindi 		    TOPO_METH_PROP_GET, in));
4231414Scindi 
4244087Scindi 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
4254087Scindi 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
4264087Scindi 	rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname);
4274087Scindi 	if (args != NULL)
4284087Scindi 		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
4294087Scindi 	if (rv != 0)
4304087Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
4314087Scindi 		    TOPO_METH_PROP_GET, in));
4321414Scindi 
4333605Scindi 	*prop = NULL;
4344087Scindi 	rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET,
4354087Scindi 	    TOPO_METH_PROP_GET_VERSION, in, prop, err);
4361414Scindi 
4374087Scindi 	nvlist_free(in);
4383323Scindi 
4394087Scindi 	if (rv != 0)
4404087Scindi 		return (-1); /* *err is set for us */
4411414Scindi 
4423605Scindi 	if (*prop == NULL)
4434087Scindi 		return (set_error(thp, ETOPO_PROP_NOENT, err,
4444087Scindi 		    TOPO_METH_PROP_GET, NULL));
4451414Scindi 	return (0);
4461414Scindi }
4471414Scindi 
4481414Scindi int
topo_fmri_asru(topo_hdl_t * thp,nvlist_t * nvl,nvlist_t ** asru,int * err)4493323Scindi topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err)
4501414Scindi {
4514087Scindi 	nvlist_t *ap, *prop = NULL;
4523605Scindi 
4533323Scindi 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU,
4544087Scindi 	    nvl, &prop, err) < 0)
4553323Scindi 		return (set_error(thp, *err, err, "topo_fmri_asru", NULL));
4563323Scindi 
4574087Scindi 	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0)
4584087Scindi 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru",
4594087Scindi 		    prop));
4604087Scindi 
4614087Scindi 	if (topo_hdl_nvdup(thp, ap, asru) < 0)
4624087Scindi 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru",
4634087Scindi 		    prop));
4644087Scindi 
4654087Scindi 	nvlist_free(prop);
4664087Scindi 
4673323Scindi 	return (0);
4683323Scindi }
4693323Scindi 
4703323Scindi int
topo_fmri_fru(topo_hdl_t * thp,nvlist_t * nvl,nvlist_t ** fru,int * err)4713323Scindi topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err)
4723323Scindi {
4734087Scindi 	nvlist_t *fp, *prop = NULL;
4743323Scindi 
4753323Scindi 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU,
4764198Seschrock 	    nvl, &prop, err) < 0)
4773323Scindi 		return (set_error(thp, *err, err, "topo_fmri_fru", NULL));
4783323Scindi 
4794087Scindi 	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0)
4804087Scindi 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru",
4814087Scindi 		    prop));
4824087Scindi 
4834087Scindi 	if (topo_hdl_nvdup(thp, fp, fru) < 0)
4844087Scindi 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru",
4854087Scindi 		    prop));
4864087Scindi 
4874087Scindi 	nvlist_free(prop);
4884087Scindi 
4893323Scindi 	return (0);
4903323Scindi }
4911414Scindi 
4923323Scindi int
topo_fmri_label(topo_hdl_t * thp,nvlist_t * nvl,char ** label,int * err)4934087Scindi topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err)
4943323Scindi {
4954087Scindi 	nvlist_t *prop = NULL;
4964087Scindi 	char *lp;
4973323Scindi 
4984087Scindi 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL,
4994087Scindi 	    NULL, &prop, err) < 0)
5003323Scindi 		return (set_error(thp, *err, err, "topo_fmri_label", NULL));
5013323Scindi 
5024087Scindi 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0)
5033323Scindi 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label",
5044087Scindi 		    prop));
5054087Scindi 
5064087Scindi 	if ((*label = topo_hdl_strdup(thp, lp)) == NULL)
5074087Scindi 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label",
5084087Scindi 		    prop));
5094087Scindi 
5104087Scindi 	nvlist_free(prop);
5114087Scindi 
5124087Scindi 	return (0);
5134087Scindi }
5144087Scindi 
5156292Srobj int
topo_fmri_serial(topo_hdl_t * thp,nvlist_t * nvl,char ** serial,int * err)5166292Srobj topo_fmri_serial(topo_hdl_t *thp, nvlist_t *nvl, char **serial, int *err)
5176292Srobj {
5186292Srobj 	nvlist_t *prop = NULL;
5196292Srobj 	char *sp;
5206292Srobj 
5219874SStephen.Hanson@Sun.COM 	/*
5229874SStephen.Hanson@Sun.COM 	 * If there is a serial id in the resource fmri, then use that.
5239874SStephen.Hanson@Sun.COM 	 * Otherwise fall back to looking for a serial id property in the
5249874SStephen.Hanson@Sun.COM 	 * protocol group.
5259874SStephen.Hanson@Sun.COM 	 */
5269874SStephen.Hanson@Sun.COM 	if (nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &sp) == 0) {
5279874SStephen.Hanson@Sun.COM 		if ((*serial = topo_hdl_strdup(thp, sp)) == NULL)
5289874SStephen.Hanson@Sun.COM 			return (set_error(thp, ETOPO_PROP_NOMEM, err,
5299874SStephen.Hanson@Sun.COM 			    "topo_fmri_serial", prop));
5309874SStephen.Hanson@Sun.COM 		else
5319874SStephen.Hanson@Sun.COM 			return (0);
5329874SStephen.Hanson@Sun.COM 	}
5339874SStephen.Hanson@Sun.COM 
5346292Srobj 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, FM_FMRI_HC_SERIAL_ID,
5356292Srobj 	    NULL, &prop, err) < 0)
5366292Srobj 		return (set_error(thp, *err, err, "topo_fmri_serial", NULL));
5376292Srobj 
5386292Srobj 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &sp) != 0)
5396292Srobj 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_serial",
5406292Srobj 		    prop));
5416292Srobj 
5426292Srobj 	if ((*serial = topo_hdl_strdup(thp, sp)) == NULL)
5436292Srobj 		return (set_error(thp, ETOPO_PROP_NOMEM, err,
5446292Srobj 		    "topo_fmri_serial", prop));
5456292Srobj 
5466292Srobj 	nvlist_free(prop);
5476292Srobj 
5486292Srobj 	return (0);
5496292Srobj }
5506292Srobj 
topo_fmri_getprop(topo_hdl_t * thp,nvlist_t * nvl,const char * pg,const char * pname,nvlist_t * args,nvlist_t ** prop,int * err)5514087Scindi int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
5524087Scindi     const char *pname, nvlist_t *args,  nvlist_t **prop,
5534087Scindi     int *err)
5544087Scindi {
5554087Scindi 	*prop = NULL;
5564087Scindi 
5574087Scindi 	return (fmri_prop(thp, nvl, pg, pname, args, prop, err));
5584087Scindi }
5591414Scindi 
topo_fmri_setprop(topo_hdl_t * thp,nvlist_t * nvl,const char * pg,nvlist_t * prop,int flag,nvlist_t * args,int * err)5604087Scindi int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
5614087Scindi     nvlist_t *prop, int flag, nvlist_t *args, int *err)
5624087Scindi {
5634087Scindi 	int rv;
5644087Scindi 	nvlist_t *in = NULL, *out = NULL;
5654087Scindi 	tnode_t *rnode;
5664087Scindi 	char *scheme;
5674087Scindi 
5684087Scindi 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0)
5694087Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
5704087Scindi 		    TOPO_METH_PROP_SET, in));
5714087Scindi 
5724087Scindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
5734087Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
5744087Scindi 		    TOPO_METH_PROP_SET, in));
5754087Scindi 
5764087Scindi 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
5774087Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
5784087Scindi 		    TOPO_METH_PROP_SET, in));
5794087Scindi 
5804087Scindi 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl);
5814087Scindi 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg);
5824087Scindi 	rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop);
5834087Scindi 	rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag);
5844087Scindi 	if (args != NULL)
5854087Scindi 		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
5864087Scindi 	if (rv != 0)
5874087Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
5884087Scindi 		    TOPO_METH_PROP_SET, in));
5891414Scindi 
5904087Scindi 	rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET,
5914087Scindi 	    TOPO_METH_PROP_SET_VERSION, in, &out, err);
5924087Scindi 
5934087Scindi 	nvlist_free(in);
5944087Scindi 
5954087Scindi 	/* no return values */
5964087Scindi 	if (out != NULL)
5974087Scindi 		nvlist_free(out);
5984087Scindi 
5994087Scindi 	if (rv)
6004087Scindi 		return (-1);
6013323Scindi 
6024087Scindi 	return (0);
6034087Scindi 
6044087Scindi }
6054087Scindi 
6064087Scindi int
topo_fmri_getpgrp(topo_hdl_t * thp,nvlist_t * rsrc,const char * pgname,nvlist_t ** pgroup,int * err)6074087Scindi topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
6084087Scindi     nvlist_t **pgroup, int *err)
6094087Scindi {
6104087Scindi 	int rv;
6114087Scindi 	nvlist_t *in = NULL;
6124087Scindi 	tnode_t *rnode;
6134087Scindi 	char *scheme;
6143323Scindi 
6154087Scindi 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
6164087Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
6174087Scindi 		    TOPO_METH_PROP_GET, in));
6184087Scindi 
6194087Scindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
6204087Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
6214087Scindi 		    TOPO_METH_PROP_GET, in));
6224087Scindi 
6234087Scindi 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
6244087Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
6254087Scindi 		    TOPO_METH_PROP_GET, in));
6263323Scindi 
6274087Scindi 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
6284087Scindi 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
6294087Scindi 	if (rv != 0)
6304087Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
6314087Scindi 		    TOPO_METH_PROP_GET, in));
6323323Scindi 
6334087Scindi 	*pgroup = NULL;
6344087Scindi 	rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET,
6354087Scindi 	    TOPO_METH_PGRP_GET_VERSION, in, pgroup, err);
6364087Scindi 
6374087Scindi 	nvlist_free(in);
6384087Scindi 
6394087Scindi 	if (rv != 0)
6404087Scindi 		return (-1); /* *err is set for us */
6414087Scindi 
6424087Scindi 	if (*pgroup == NULL)
6434087Scindi 		return (set_error(thp, ETOPO_PROP_NOENT, err,
6444087Scindi 		    TOPO_METH_PROP_GET, NULL));
6451414Scindi 	return (0);
6461414Scindi }
6471414Scindi 
6481414Scindi int
topo_fmri_compare(topo_hdl_t * thp,nvlist_t * f1,nvlist_t * f2,int * err)6491414Scindi topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err)
6501414Scindi {
6514087Scindi 	uint32_t compare;
6521414Scindi 	char *scheme1, *scheme2;
6531414Scindi 	nvlist_t *in;
6541414Scindi 	nvlist_t *out = NULL;
6551414Scindi 	tnode_t *rnode;
6561414Scindi 
6571414Scindi 	if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0)
6581414Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
6591414Scindi 		    TOPO_METH_COMPARE, NULL));
6602027Ssethg 	if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0)
6611414Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
6621414Scindi 		    TOPO_METH_COMPARE, NULL));
6631414Scindi 
6641414Scindi 	if (strcmp(scheme1, scheme2) != 0)
6651414Scindi 		return (0);
6661414Scindi 
6671414Scindi 	if ((rnode = topo_hdl_root(thp, scheme1)) == NULL)
6681414Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
6691414Scindi 		    TOPO_METH_COMPARE, NULL));
6701414Scindi 
6711414Scindi 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
6721414Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
6731414Scindi 		    NULL));
6741414Scindi 
6754087Scindi 	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 ||
6764087Scindi 	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0)
6771414Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
6781414Scindi 		    in));
6791414Scindi 
6804087Scindi 	if (topo_method_invoke(rnode, TOPO_METH_COMPARE,
6814087Scindi 	    TOPO_METH_COMPARE_VERSION, in, &out, err) < 0)
6821414Scindi 		return (set_error(thp, *err, err, TOPO_METH_COMPARE, in));
6831414Scindi 
6844087Scindi 	(void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare);
6854087Scindi 	nvlist_free(out);
6861414Scindi 	nvlist_free(in);
6871414Scindi 
6884087Scindi 	return (compare);
6891414Scindi }
6901414Scindi 
6911414Scindi /*
6921414Scindi  * topo_fmri_create
6931414Scindi  *
6941414Scindi  *	If possible, creates an FMRI of the requested version in the
6951414Scindi  *	requested scheme.  Args are passed as part of the inputs to the
6961414Scindi  *	fmri-create method of the scheme.
6971414Scindi  */
6981414Scindi nvlist_t *
topo_fmri_create(topo_hdl_t * thp,const char * scheme,const char * name,topo_instance_t inst,nvlist_t * nvl,int * err)6991414Scindi topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name,
7001414Scindi     topo_instance_t inst, nvlist_t *nvl, int *err)
7011414Scindi {
7021414Scindi 	nvlist_t *ins;
7031414Scindi 	nvlist_t *out;
7041414Scindi 	tnode_t *rnode;
7051414Scindi 
7061414Scindi 	ins = out = NULL;
7071414Scindi 
7081414Scindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
7091414Scindi 		return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err,
7101414Scindi 		    TOPO_METH_FMRI, NULL));
7111414Scindi 
7121414Scindi 	if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0)
7131414Scindi 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
7141414Scindi 		    TOPO_METH_FMRI, NULL));
7151414Scindi 
7161414Scindi 	if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 ||
7171414Scindi 	    nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) {
7181414Scindi 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
7191414Scindi 		    TOPO_METH_FMRI, ins));
7201414Scindi 	}
7211414Scindi 
7221414Scindi 	if (nvl != NULL &&
7231414Scindi 	    nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) {
7241414Scindi 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
7251414Scindi 		    TOPO_METH_FMRI, ins));
7261414Scindi 	}
7271414Scindi 	if (topo_method_invoke(rnode,
7281414Scindi 	    TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) {
7291414Scindi 		return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins));
7301414Scindi 	}
7311414Scindi 	nvlist_free(ins);
7321414Scindi 	return (out);
7331414Scindi }
7346869Seschrock 
7356869Seschrock /*
7366869Seschrock  * These private utility functions are used by fmd to maintain its resource
7376869Seschrock  * cache.  Because hc instance numbers are not guaranteed, it's possible to
7386869Seschrock  * have two different FMRI strings represent the same logical entity.  These
7396869Seschrock  * functions hide this implementation detail from unknowing consumers such as
7406869Seschrock  * fmd.
7416869Seschrock  *
7426869Seschrock  * Ideally, we'd like to do a str2nvl() and then a full FMRI hash and
7436869Seschrock  * comparison, but these functions are designed to be fast and efficient.
7446869Seschrock  * Given that there is only a single hc node that has this property
7456869Seschrock  * (ses-enclosure), we hard-code this behavior here.  If there are more
7466869Seschrock  * instances of this behavior in the future, this function could be made more
7476869Seschrock  * generic.
748*10817SEric.Schrock@Sun.COM  *
749*10817SEric.Schrock@Sun.COM  * This code also handles changes in the server-id or revision fields of the hc
750*10817SEric.Schrock@Sun.COM  * FMRI, as these fields have no bearing on equivalence of FRUs.
7516869Seschrock  */
7526869Seschrock static ulong_t
topo_fmri_strhash_one(const char * fmri,size_t len)7536869Seschrock topo_fmri_strhash_one(const char *fmri, size_t len)
7546869Seschrock {
7556869Seschrock 	ulong_t g, h = 0;
7566869Seschrock 	size_t i;
7576869Seschrock 
7586869Seschrock 	for (i = 0; i < len; i++) {
7596869Seschrock 		h = (h << 4) + fmri[i];
7606869Seschrock 
7616869Seschrock 		if ((g = (h & 0xf0000000)) != 0) {
7626869Seschrock 			h ^= (g >> 24);
7636869Seschrock 			h ^= g;
7646869Seschrock 		}
7656869Seschrock 	}
7666869Seschrock 
7676869Seschrock 	return (h);
7686869Seschrock }
7696869Seschrock 
770*10817SEric.Schrock@Sun.COM static const char *
topo_fmri_next_auth(const char * auth)771*10817SEric.Schrock@Sun.COM topo_fmri_next_auth(const char *auth)
772*10817SEric.Schrock@Sun.COM {
773*10817SEric.Schrock@Sun.COM 	const char *colon, *slash;
774*10817SEric.Schrock@Sun.COM 
775*10817SEric.Schrock@Sun.COM 	colon = strchr(auth + 1, ':');
776*10817SEric.Schrock@Sun.COM 	slash = strchr(auth, '/');
777*10817SEric.Schrock@Sun.COM 
778*10817SEric.Schrock@Sun.COM 	if (colon == NULL && slash == NULL)
779*10817SEric.Schrock@Sun.COM 		return (NULL);
780*10817SEric.Schrock@Sun.COM 
781*10817SEric.Schrock@Sun.COM 	if (colon == NULL)
782*10817SEric.Schrock@Sun.COM 		return (slash);
783*10817SEric.Schrock@Sun.COM 	else if (slash < colon)
784*10817SEric.Schrock@Sun.COM 		return (slash);
785*10817SEric.Schrock@Sun.COM 	else
786*10817SEric.Schrock@Sun.COM 		return (colon);
787*10817SEric.Schrock@Sun.COM }
788*10817SEric.Schrock@Sun.COM 
789*10817SEric.Schrock@Sun.COM /*
790*10817SEric.Schrock@Sun.COM  * List of authority information we care about.  Note that we explicitly ignore
791*10817SEric.Schrock@Sun.COM  * things that are properties of the chassis and not the resource itself:
792*10817SEric.Schrock@Sun.COM  *
793*10817SEric.Schrock@Sun.COM  * 	FM_FMRI_AUTH_PRODUCT_SN		"product-sn"
794*10817SEric.Schrock@Sun.COM  * 	FM_FMRI_AUTH_PRODUCT		"product-id"
795*10817SEric.Schrock@Sun.COM  * 	FM_FMRI_AUTH_DOMAIN		"domain-id"
796*10817SEric.Schrock@Sun.COM  * 	FM_FMRI_AUTH_SERVER		"server-id"
797*10817SEric.Schrock@Sun.COM  *	FM_FMRI_AUTH_HOST		"host-id"
798*10817SEric.Schrock@Sun.COM  *
799*10817SEric.Schrock@Sun.COM  * We also ignore the "revision" authority member, as that typically indicates
800*10817SEric.Schrock@Sun.COM  * the firmware revision and is not a static property of the FRU.  This leaves
801*10817SEric.Schrock@Sun.COM  * the following interesting members:
802*10817SEric.Schrock@Sun.COM  *
803*10817SEric.Schrock@Sun.COM  * 	FM_FMRI_AUTH_CHASSIS		"chassis-id"
804*10817SEric.Schrock@Sun.COM  *	FM_FMRI_HC_SERIAL_ID		"serial"
805*10817SEric.Schrock@Sun.COM  *	FM_FMRI_HC_PART			"part"
806*10817SEric.Schrock@Sun.COM  */
807*10817SEric.Schrock@Sun.COM typedef enum {
808*10817SEric.Schrock@Sun.COM 	HC_AUTH_CHASSIS,
809*10817SEric.Schrock@Sun.COM 	HC_AUTH_SERIAL,
810*10817SEric.Schrock@Sun.COM 	HC_AUTH_PART,
811*10817SEric.Schrock@Sun.COM 	HC_AUTH_MAX
812*10817SEric.Schrock@Sun.COM } hc_auth_type_t;
813*10817SEric.Schrock@Sun.COM 
814*10817SEric.Schrock@Sun.COM static char *hc_auth_table[] = {
815*10817SEric.Schrock@Sun.COM 	FM_FMRI_AUTH_CHASSIS,
816*10817SEric.Schrock@Sun.COM 	FM_FMRI_HC_SERIAL_ID,
817*10817SEric.Schrock@Sun.COM 	FM_FMRI_HC_PART
818*10817SEric.Schrock@Sun.COM };
819*10817SEric.Schrock@Sun.COM 
820*10817SEric.Schrock@Sun.COM /*
821*10817SEric.Schrock@Sun.COM  * Takes an authority member, with leading ":" and trailing "=", and returns
822*10817SEric.Schrock@Sun.COM  * one of the above types if it's one of the things we care about.  If
823*10817SEric.Schrock@Sun.COM  * 'authlen' is specified, it is filled in with the length of the authority
824*10817SEric.Schrock@Sun.COM  * member, including leading and trailing characters.
825*10817SEric.Schrock@Sun.COM  */
826*10817SEric.Schrock@Sun.COM static hc_auth_type_t
hc_auth_to_type(const char * auth,size_t * authlen)827*10817SEric.Schrock@Sun.COM hc_auth_to_type(const char *auth, size_t *authlen)
828*10817SEric.Schrock@Sun.COM {
829*10817SEric.Schrock@Sun.COM 	int i;
830*10817SEric.Schrock@Sun.COM 	size_t len;
831*10817SEric.Schrock@Sun.COM 
832*10817SEric.Schrock@Sun.COM 	if (auth[0] != ':')
833*10817SEric.Schrock@Sun.COM 		return (HC_AUTH_MAX);
834*10817SEric.Schrock@Sun.COM 
835*10817SEric.Schrock@Sun.COM 	for (i = 0; i < HC_AUTH_MAX; i++) {
836*10817SEric.Schrock@Sun.COM 		len = strlen(hc_auth_table[i]);
837*10817SEric.Schrock@Sun.COM 
838*10817SEric.Schrock@Sun.COM 		if (strncmp(auth + 1, hc_auth_table[i], len) == 0 &&
839*10817SEric.Schrock@Sun.COM 		    auth[len + 1] == '=') {
840*10817SEric.Schrock@Sun.COM 			if (authlen)
841*10817SEric.Schrock@Sun.COM 				*authlen = len + 2;
842*10817SEric.Schrock@Sun.COM 			break;
843*10817SEric.Schrock@Sun.COM 		}
844*10817SEric.Schrock@Sun.COM 	}
845*10817SEric.Schrock@Sun.COM 
846*10817SEric.Schrock@Sun.COM 	return (i);
847*10817SEric.Schrock@Sun.COM }
848*10817SEric.Schrock@Sun.COM 
849*10817SEric.Schrock@Sun.COM /*ARGSUSED*/
850*10817SEric.Schrock@Sun.COM ulong_t
topo_fmri_strhash_internal(topo_hdl_t * thp,const char * fmri,boolean_t noauth)851*10817SEric.Schrock@Sun.COM topo_fmri_strhash_internal(topo_hdl_t *thp, const char *fmri, boolean_t noauth)
852*10817SEric.Schrock@Sun.COM {
853*10817SEric.Schrock@Sun.COM 	const char *auth, *next;
854*10817SEric.Schrock@Sun.COM 	const char *enclosure;
855*10817SEric.Schrock@Sun.COM 	ulong_t h;
856*10817SEric.Schrock@Sun.COM 	hc_auth_type_t type;
857*10817SEric.Schrock@Sun.COM 
858*10817SEric.Schrock@Sun.COM 	if (strncmp(fmri, "hc://", 5) != 0)
859*10817SEric.Schrock@Sun.COM 		return (topo_fmri_strhash_one(fmri, strlen(fmri)));
860*10817SEric.Schrock@Sun.COM 
861*10817SEric.Schrock@Sun.COM 	enclosure = strstr(fmri, SES_ENCLOSURE);
862*10817SEric.Schrock@Sun.COM 
863*10817SEric.Schrock@Sun.COM 	h = 0;
864*10817SEric.Schrock@Sun.COM 
865*10817SEric.Schrock@Sun.COM 	auth = next = fmri + 5;
866*10817SEric.Schrock@Sun.COM 	while (*next != '/') {
867*10817SEric.Schrock@Sun.COM 		auth = next;
868*10817SEric.Schrock@Sun.COM 
869*10817SEric.Schrock@Sun.COM 		if ((next = topo_fmri_next_auth(auth)) == NULL) {
870*10817SEric.Schrock@Sun.COM 			next = auth;
871*10817SEric.Schrock@Sun.COM 			break;
872*10817SEric.Schrock@Sun.COM 		}
873*10817SEric.Schrock@Sun.COM 
874*10817SEric.Schrock@Sun.COM 		if ((type = hc_auth_to_type(auth, NULL)) == HC_AUTH_MAX)
875*10817SEric.Schrock@Sun.COM 			continue;
876*10817SEric.Schrock@Sun.COM 
877*10817SEric.Schrock@Sun.COM 		if (!noauth || type == HC_AUTH_CHASSIS)
878*10817SEric.Schrock@Sun.COM 			h += topo_fmri_strhash_one(auth, next - auth);
879*10817SEric.Schrock@Sun.COM 	}
880*10817SEric.Schrock@Sun.COM 
881*10817SEric.Schrock@Sun.COM 	if (enclosure) {
882*10817SEric.Schrock@Sun.COM 		next = enclosure + sizeof (SES_ENCLOSURE);
883*10817SEric.Schrock@Sun.COM 		while (isdigit(*next))
884*10817SEric.Schrock@Sun.COM 			next++;
885*10817SEric.Schrock@Sun.COM 	}
886*10817SEric.Schrock@Sun.COM 
887*10817SEric.Schrock@Sun.COM 	h += topo_fmri_strhash_one(next, strlen(next));
888*10817SEric.Schrock@Sun.COM 
889*10817SEric.Schrock@Sun.COM 	return (h);
890*10817SEric.Schrock@Sun.COM }
891*10817SEric.Schrock@Sun.COM 
8926869Seschrock /*ARGSUSED*/
8936869Seschrock ulong_t
topo_fmri_strhash(topo_hdl_t * thp,const char * fmri)8946869Seschrock topo_fmri_strhash(topo_hdl_t *thp, const char *fmri)
8956869Seschrock {
896*10817SEric.Schrock@Sun.COM 	return (topo_fmri_strhash_internal(thp, fmri, B_FALSE));
897*10817SEric.Schrock@Sun.COM }
898*10817SEric.Schrock@Sun.COM 
899*10817SEric.Schrock@Sun.COM /*ARGSUSED*/
900*10817SEric.Schrock@Sun.COM ulong_t
topo_fmri_strhash_noauth(topo_hdl_t * thp,const char * fmri)901*10817SEric.Schrock@Sun.COM topo_fmri_strhash_noauth(topo_hdl_t *thp, const char *fmri)
902*10817SEric.Schrock@Sun.COM {
903*10817SEric.Schrock@Sun.COM 	return (topo_fmri_strhash_internal(thp, fmri, B_TRUE));
904*10817SEric.Schrock@Sun.COM }
905*10817SEric.Schrock@Sun.COM 
906*10817SEric.Schrock@Sun.COM 
907*10817SEric.Schrock@Sun.COM static void
topo_fmri_strcmp_parse_auth(const char * auth,const char * authtype[],size_t authlen[])908*10817SEric.Schrock@Sun.COM topo_fmri_strcmp_parse_auth(const char *auth, const char *authtype[],
909*10817SEric.Schrock@Sun.COM     size_t authlen[])
910*10817SEric.Schrock@Sun.COM {
911*10817SEric.Schrock@Sun.COM 	int i;
912*10817SEric.Schrock@Sun.COM 	const char *next;
913*10817SEric.Schrock@Sun.COM 	hc_auth_type_t type;
914*10817SEric.Schrock@Sun.COM 	size_t len;
915*10817SEric.Schrock@Sun.COM 
916*10817SEric.Schrock@Sun.COM 	for (i = 0; i < HC_AUTH_MAX; i++)
917*10817SEric.Schrock@Sun.COM 		authlen[i] = 0;
9186869Seschrock 
919*10817SEric.Schrock@Sun.COM 	while (*auth != '/' &&
920*10817SEric.Schrock@Sun.COM 	    (next = topo_fmri_next_auth(auth)) != NULL) {
921*10817SEric.Schrock@Sun.COM 		if ((type = hc_auth_to_type(auth, &len)) == HC_AUTH_MAX) {
922*10817SEric.Schrock@Sun.COM 			auth = next;
923*10817SEric.Schrock@Sun.COM 			continue;
924*10817SEric.Schrock@Sun.COM 		}
925*10817SEric.Schrock@Sun.COM 
926*10817SEric.Schrock@Sun.COM 		authtype[type] = auth + len;
927*10817SEric.Schrock@Sun.COM 		authlen[type] = next - (auth + len);
928*10817SEric.Schrock@Sun.COM 		auth = next;
929*10817SEric.Schrock@Sun.COM 	}
930*10817SEric.Schrock@Sun.COM }
931*10817SEric.Schrock@Sun.COM 
932*10817SEric.Schrock@Sun.COM /*ARGSUSED*/
933*10817SEric.Schrock@Sun.COM static boolean_t
topo_fmri_strcmp_internal(topo_hdl_t * thp,const char * a,const char * b,boolean_t noauth)934*10817SEric.Schrock@Sun.COM topo_fmri_strcmp_internal(topo_hdl_t *thp, const char *a, const char *b,
935*10817SEric.Schrock@Sun.COM     boolean_t noauth)
936*10817SEric.Schrock@Sun.COM {
937*10817SEric.Schrock@Sun.COM 	const char *fmria, *fmrib;
938*10817SEric.Schrock@Sun.COM 	const char *autha[HC_AUTH_MAX], *authb[HC_AUTH_MAX];
939*10817SEric.Schrock@Sun.COM 	size_t authlena[HC_AUTH_MAX], authlenb[HC_AUTH_MAX];
940*10817SEric.Schrock@Sun.COM 	int i;
941*10817SEric.Schrock@Sun.COM 
942*10817SEric.Schrock@Sun.COM 	/*
943*10817SEric.Schrock@Sun.COM 	 * For non-hc FMRIs, we don't do anything.
944*10817SEric.Schrock@Sun.COM 	 */
945*10817SEric.Schrock@Sun.COM 	if (strncmp(a, "hc://", 5) != 0 ||
946*10817SEric.Schrock@Sun.COM 	    strncmp(b, "hc://", 5) != 0)
947*10817SEric.Schrock@Sun.COM 		return (strcmp(a, b) == 0);
9486869Seschrock 
949*10817SEric.Schrock@Sun.COM 	/*
950*10817SEric.Schrock@Sun.COM 	 * Get the portion of the FMRI independent of the authority
951*10817SEric.Schrock@Sun.COM 	 * information.
952*10817SEric.Schrock@Sun.COM 	 */
953*10817SEric.Schrock@Sun.COM 	fmria = strchr(a + 5, '/');
954*10817SEric.Schrock@Sun.COM 	fmrib = strchr(b + 5, '/');
955*10817SEric.Schrock@Sun.COM 	if (fmria == NULL || fmrib == NULL)
956*10817SEric.Schrock@Sun.COM 		return (strcmp(a, b));
957*10817SEric.Schrock@Sun.COM 	fmria++;
958*10817SEric.Schrock@Sun.COM 	fmrib++;
959*10817SEric.Schrock@Sun.COM 
960*10817SEric.Schrock@Sun.COM 	/*
961*10817SEric.Schrock@Sun.COM 	 * Comparing fmri authority information is a bit of a pain, because
962*10817SEric.Schrock@Sun.COM 	 * there may be a different number of members, and they can (but
963*10817SEric.Schrock@Sun.COM 	 * shouldn't be) in a different order.  We need to create a copy of the
964*10817SEric.Schrock@Sun.COM 	 * authority and parse it into pieces.  Because this function is
965*10817SEric.Schrock@Sun.COM 	 * intended to be fast (and not necessarily extensible), we hard-code
966*10817SEric.Schrock@Sun.COM 	 * the list of possible authority members in an enum and parse it into
967*10817SEric.Schrock@Sun.COM 	 * an array.
968*10817SEric.Schrock@Sun.COM 	 */
969*10817SEric.Schrock@Sun.COM 	topo_fmri_strcmp_parse_auth(a + 5, autha, authlena);
970*10817SEric.Schrock@Sun.COM 	topo_fmri_strcmp_parse_auth(b + 5, authb, authlenb);
971*10817SEric.Schrock@Sun.COM 
972*10817SEric.Schrock@Sun.COM 	for (i = 0; i < HC_AUTH_MAX; i++) {
973*10817SEric.Schrock@Sun.COM 		if (noauth && i != HC_AUTH_CHASSIS)
974*10817SEric.Schrock@Sun.COM 			continue;
9756869Seschrock 
976*10817SEric.Schrock@Sun.COM 		if (authlena[i] == 0 && authlenb[i] == 0)
977*10817SEric.Schrock@Sun.COM 			continue;
978*10817SEric.Schrock@Sun.COM 
979*10817SEric.Schrock@Sun.COM 		if (authlena[i] != authlenb[i])
980*10817SEric.Schrock@Sun.COM 			return (B_FALSE);
981*10817SEric.Schrock@Sun.COM 
982*10817SEric.Schrock@Sun.COM 		if (strncmp(autha[i], authb[i], authlena[i]) != 0)
983*10817SEric.Schrock@Sun.COM 			return (B_FALSE);
984*10817SEric.Schrock@Sun.COM 	}
9856869Seschrock 
986*10817SEric.Schrock@Sun.COM 	/*
987*10817SEric.Schrock@Sun.COM 	 * If this is rooted at a ses-enclosure node, skip past the instance
988*10817SEric.Schrock@Sun.COM 	 * number, as it has no meaning.
989*10817SEric.Schrock@Sun.COM 	 */
990*10817SEric.Schrock@Sun.COM 	if (strncmp(fmria, SES_ENCLOSURE, sizeof (SES_ENCLOSURE) - 1) == 0 &&
991*10817SEric.Schrock@Sun.COM 	    strncmp(fmrib, SES_ENCLOSURE, sizeof (SES_ENCLOSURE) - 1) == 0) {
992*10817SEric.Schrock@Sun.COM 		fmria += sizeof (SES_ENCLOSURE);
993*10817SEric.Schrock@Sun.COM 		fmrib += sizeof (SES_ENCLOSURE);
9946869Seschrock 
995*10817SEric.Schrock@Sun.COM 		while (isdigit(*fmria))
996*10817SEric.Schrock@Sun.COM 			fmria++;
997*10817SEric.Schrock@Sun.COM 		while (isdigit(*fmrib))
998*10817SEric.Schrock@Sun.COM 			fmrib++;
999*10817SEric.Schrock@Sun.COM 	}
1000*10817SEric.Schrock@Sun.COM 
1001*10817SEric.Schrock@Sun.COM 	return (strcmp(fmria, fmrib) == 0);
10026869Seschrock }
10036869Seschrock 
10046869Seschrock /*ARGSUSED*/
10056869Seschrock boolean_t
topo_fmri_strcmp(topo_hdl_t * thp,const char * a,const char * b)10066869Seschrock topo_fmri_strcmp(topo_hdl_t *thp, const char *a, const char *b)
10076869Seschrock {
1008*10817SEric.Schrock@Sun.COM 	return (topo_fmri_strcmp_internal(thp, a, b, B_FALSE));
1009*10817SEric.Schrock@Sun.COM }
10106869Seschrock 
1011*10817SEric.Schrock@Sun.COM /*ARGSUSED*/
1012*10817SEric.Schrock@Sun.COM boolean_t
topo_fmri_strcmp_noauth(topo_hdl_t * thp,const char * a,const char * b)1013*10817SEric.Schrock@Sun.COM topo_fmri_strcmp_noauth(topo_hdl_t *thp, const char *a, const char *b)
1014*10817SEric.Schrock@Sun.COM {
1015*10817SEric.Schrock@Sun.COM 	return (topo_fmri_strcmp_internal(thp, a, b, B_TRUE));
10166869Seschrock }
10177243Srobj 
10187243Srobj int
topo_fmri_facility(topo_hdl_t * thp,nvlist_t * rsrc,const char * fac_type,uint32_t fac_subtype,topo_walk_cb_t cb,void * cb_args,int * err)10197243Srobj topo_fmri_facility(topo_hdl_t *thp, nvlist_t *rsrc, const char *fac_type,
10207243Srobj     uint32_t fac_subtype, topo_walk_cb_t cb, void *cb_args, int *err)
10217243Srobj {
10227243Srobj 	int rv;
10237243Srobj 	nvlist_t *in = NULL, *out;
10247243Srobj 	tnode_t *rnode;
10257243Srobj 	char *scheme;
10267243Srobj 
10277243Srobj 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
10287243Srobj 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
10297243Srobj 		    TOPO_METH_PROP_GET, in));
10307243Srobj 
10317243Srobj 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
10327243Srobj 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
10337243Srobj 		    TOPO_METH_PROP_GET, in));
10347243Srobj 
10357243Srobj 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
10367243Srobj 		return (set_error(thp, ETOPO_FMRI_NVL, err,
10377243Srobj 		    TOPO_METH_PROP_GET, in));
10387243Srobj 
10397243Srobj 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
10407243Srobj 	rv |= nvlist_add_string(in, FM_FMRI_FACILITY_TYPE, fac_type);
10417243Srobj 	rv |= nvlist_add_uint32(in, "type", fac_subtype);
10427243Srobj #ifdef _LP64
10437243Srobj 	rv |= nvlist_add_uint64(in, "callback", (uint64_t)cb);
10447243Srobj 	rv |= nvlist_add_uint64(in, "callback-args", (uint64_t)cb_args);
10457243Srobj #else
10467243Srobj 	rv |= nvlist_add_uint32(in, "callback", (uint32_t)cb);
10477243Srobj 	rv |= nvlist_add_uint32(in, "callback-args", (uint32_t)cb_args);
10487243Srobj #endif
10497243Srobj 	if (rv != 0)
10507243Srobj 		return (set_error(thp, ETOPO_FMRI_NVL, err,
10517243Srobj 		    TOPO_METH_PROP_GET, in));
10527243Srobj 
10537243Srobj 	rv = topo_method_invoke(rnode, TOPO_METH_FACILITY,
10547243Srobj 	    TOPO_METH_FACILITY_VERSION, in, &out, err);
10557243Srobj 
10567243Srobj 	nvlist_free(in);
10577243Srobj 
10587243Srobj 	if (rv != 0)
10597243Srobj 		return (-1); /* *err is set for us */
10607243Srobj 
10617243Srobj 	return (0);
10627243Srobj }
1063