17aec1d6eScindi /*
27aec1d6eScindi  * CDDL HEADER START
37aec1d6eScindi  *
47aec1d6eScindi  * The contents of this file are subject to the terms of the
57aec1d6eScindi  * Common Development and Distribution License (the "License").
67aec1d6eScindi  * You may not use this file except in compliance with the License.
77aec1d6eScindi  *
87aec1d6eScindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97aec1d6eScindi  * or http://www.opensolaris.org/os/licensing.
107aec1d6eScindi  * See the License for the specific language governing permissions
117aec1d6eScindi  * and limitations under the License.
127aec1d6eScindi  *
137aec1d6eScindi  * When distributing Covered Code, include this CDDL HEADER in each
147aec1d6eScindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157aec1d6eScindi  * If applicable, add the following below this CDDL HEADER, with the
167aec1d6eScindi  * fields enclosed by brackets "[]" replaced with your own identifying
177aec1d6eScindi  * information: Portions Copyright [yyyy] [name of copyright owner]
187aec1d6eScindi  *
197aec1d6eScindi  * CDDL HEADER END
207aec1d6eScindi  */
217aec1d6eScindi 
227aec1d6eScindi /*
236e1fa242SStephen Hanson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247aec1d6eScindi  * Use is subject to license terms.
257aec1d6eScindi  */
26c5591576SRob Johnston /*
27c5591576SRob Johnston  * Copyright 2020 Joyent, Inc.
28c5591576SRob Johnston  */
297aec1d6eScindi 
30940d71d2Seschrock #include <ctype.h>
317aec1d6eScindi #include <string.h>
327aec1d6eScindi #include <limits.h>
337aec1d6eScindi #include <fm/topo_mod.h>
3425c6ff4bSstephh #include <fm/fmd_fmri.h>
357aec1d6eScindi #include <sys/fm/protocol.h>
367aec1d6eScindi #include <topo_alloc.h>
37c5591576SRob Johnston #include <topo_digraph.h>
387aec1d6eScindi #include <topo_error.h>
39940d71d2Seschrock #include <topo_hc.h>
400eb822a1Scindi #include <topo_method.h>
417aec1d6eScindi #include <topo_subr.h>
427aec1d6eScindi #include <topo_string.h>
437aec1d6eScindi 
44c40d7343Scindi /*
45c40d7343Scindi  * Topology node properties and method operations may be accessed by FMRI.
46c40d7343Scindi  * The FMRI used to perform property look-ups and method operations is
47c40d7343Scindi  * the FMRI contained in the matching topology node's protocol property
48*bbf21555SRichard Lowe  * grouping for the resource property. The full range of fmd(8)
49c40d7343Scindi  * scheme plugin operations are supported as long as a backend method is
50c40d7343Scindi  * supplied by a scheme-specific enumerator or the enumerator module that
51c40d7343Scindi  * created the matching topology node.  Support for fmd scheme operations
52c40d7343Scindi  * include:
53c40d7343Scindi  *
54c40d7343Scindi  *	- expand
55c40d7343Scindi  *	- present
5625c6ff4bSstephh  *	- replaced
57c40d7343Scindi  *	- contains
58c40d7343Scindi  *	- unusable
5925c6ff4bSstephh  *	- service_state
60c40d7343Scindi  *	- nvl2str
61e4b86885SCheng Sean Ye  *	- retire
62e4b86885SCheng Sean Ye  *	- unretire
63c40d7343Scindi  *
64c40d7343Scindi  * In addition, the following operations are supported per-FMRI:
65c40d7343Scindi  *
66c40d7343Scindi  *	- str2nvl: convert string-based FMRI to nvlist
67c40d7343Scindi  *	- compare: compare two FMRIs
68c40d7343Scindi  *	- asru: lookup associated ASRU property by FMRI
69c40d7343Scindi  *	- fru: lookup associated FRU by FMRI
70c40d7343Scindi  *	- create: an FMRI nvlist by scheme type
71c40d7343Scindi  *	- propery lookup
72c40d7343Scindi  *
73c40d7343Scindi  * These routines may only be called by consumers of a topology snapshot.
74c40d7343Scindi  * They may not be called by libtopo enumerator or method modules.
75c40d7343Scindi  */
76c40d7343Scindi 
777aec1d6eScindi /*ARGSUSED*/
787aec1d6eScindi static int
set_error(topo_hdl_t * thp,int err,int * errp,char * method,nvlist_t * nvlp)797aec1d6eScindi set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp)
807aec1d6eScindi {
81aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(nvlp);
827aec1d6eScindi 
830eb822a1Scindi 	topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method,
847aec1d6eScindi 	    topo_strerror(err));
857aec1d6eScindi 
867aec1d6eScindi 	*errp = err;
877aec1d6eScindi 	return (-1);
887aec1d6eScindi }
897aec1d6eScindi 
907aec1d6eScindi /*ARGSUSED*/
917aec1d6eScindi static nvlist_t *
set_nverror(topo_hdl_t * thp,int err,int * errp,char * method,nvlist_t * nvlp)927aec1d6eScindi set_nverror(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp)
937aec1d6eScindi {
94aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(nvlp);
957aec1d6eScindi 
960eb822a1Scindi 	topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method,
977aec1d6eScindi 	    topo_strerror(err));
987aec1d6eScindi 
997aec1d6eScindi 	*errp = err;
1007aec1d6eScindi 	return (NULL);
1017aec1d6eScindi }
1027aec1d6eScindi 
1037aec1d6eScindi int
topo_fmri_nvl2str(topo_hdl_t * thp,nvlist_t * fmri,char ** fmristr,int * err)1047aec1d6eScindi topo_fmri_nvl2str(topo_hdl_t *thp, nvlist_t *fmri, char **fmristr, int *err)
1057aec1d6eScindi {
1067aec1d6eScindi 	char *scheme, *str;
1077aec1d6eScindi 	nvlist_t *out = NULL;
1087aec1d6eScindi 	tnode_t *rnode;
1097aec1d6eScindi 
1107aec1d6eScindi 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
1117aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
1127aec1d6eScindi 		    TOPO_METH_NVL2STR, out));
1137aec1d6eScindi 
1147aec1d6eScindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
1157aec1d6eScindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
1167aec1d6eScindi 		    TOPO_METH_NVL2STR, out));
1177aec1d6eScindi 
1187aec1d6eScindi 	if (topo_method_invoke(rnode, TOPO_METH_NVL2STR,
1197aec1d6eScindi 	    TOPO_METH_NVL2STR_VERSION, fmri, &out, err) != 0)
1207aec1d6eScindi 		return (set_error(thp, *err, err, TOPO_METH_NVL2STR, out));
1217aec1d6eScindi 
1227aec1d6eScindi 	if (out == NULL || nvlist_lookup_string(out, "fmri-string", &str) != 0)
1237aec1d6eScindi 		return (set_error(thp, ETOPO_METHOD_INVAL, err,
1247aec1d6eScindi 		    TOPO_METH_NVL2STR, out));
1257aec1d6eScindi 
1267aec1d6eScindi 	if ((*fmristr = topo_hdl_strdup(thp, str)) == NULL)
1277aec1d6eScindi 		return (set_error(thp, ETOPO_NOMEM, err,
1287aec1d6eScindi 		    TOPO_METH_NVL2STR, out));
1297aec1d6eScindi 
1307aec1d6eScindi 	nvlist_free(out);
1317aec1d6eScindi 
1327aec1d6eScindi 	return (0);
1337aec1d6eScindi }
1347aec1d6eScindi 
1357aec1d6eScindi int
topo_fmri_str2nvl(topo_hdl_t * thp,const char * fmristr,nvlist_t ** fmri,int * err)1367aec1d6eScindi topo_fmri_str2nvl(topo_hdl_t *thp, const char *fmristr, nvlist_t **fmri,
1377aec1d6eScindi     int *err)
1387aec1d6eScindi {
139c5591576SRob Johnston 	char *f, buf[PATH_MAX], *method = TOPO_METH_STR2NVL;
1407aec1d6eScindi 	nvlist_t *out = NULL, *in = NULL;
1417aec1d6eScindi 	tnode_t *rnode;
142c5591576SRob Johnston 	boolean_t is_path = B_FALSE;
1437aec1d6eScindi 
144c5591576SRob Johnston 	/*
145c5591576SRob Johnston 	 * For path FMRI's the scheme is encoded in the authority portion of
146c5591576SRob Johnston 	 * the FMRI - e.g.
147c5591576SRob Johnston 	 *
148c5591576SRob Johnston 	 * path://scheme=<scheme>/...
149c5591576SRob Johnston 	 */
150c5591576SRob Johnston 	if (strncmp(fmristr, "path://", 7) == 0) {
151c5591576SRob Johnston 		char *scheme_start, *scheme_end;
1527aec1d6eScindi 
153c5591576SRob Johnston 		is_path = B_TRUE;
154c5591576SRob Johnston 		method = TOPO_METH_PATH_STR2NVL;
1557aec1d6eScindi 
156c5591576SRob Johnston 		if ((scheme_start = strchr(fmristr, '=')) == NULL) {
157c5591576SRob Johnston 			return (set_error(thp, ETOPO_FMRI_MALFORM, err,
158c5591576SRob Johnston 			    TOPO_METH_STR2NVL, in));
159c5591576SRob Johnston 		}
160c5591576SRob Johnston 		scheme_start++;
161c5591576SRob Johnston 		if ((scheme_end = strchr(scheme_start, '/')) == NULL) {
162c5591576SRob Johnston 			return (set_error(thp, ETOPO_FMRI_MALFORM, err,
163c5591576SRob Johnston 			    TOPO_METH_STR2NVL, in));
164c5591576SRob Johnston 		}
165c5591576SRob Johnston 		(void) strlcpy(buf, scheme_start,
166c5591576SRob Johnston 		    (scheme_end - scheme_start) + 1);
167c5591576SRob Johnston 	} else {
168c5591576SRob Johnston 		(void) strlcpy(buf, fmristr, sizeof (buf));
169c5591576SRob Johnston 
170c5591576SRob Johnston 		if ((f = strchr(buf, ':')) == NULL)
171c5591576SRob Johnston 			return (set_error(thp, ETOPO_FMRI_MALFORM, err,
172c5591576SRob Johnston 			    TOPO_METH_STR2NVL, in));
173c5591576SRob Johnston 
174c5591576SRob Johnston 		*f = '\0'; /* strip trailing FMRI path */
175c5591576SRob Johnston 	}
176c5591576SRob Johnston 
177c5591576SRob Johnston 	if (is_path) {
178c5591576SRob Johnston 		topo_digraph_t *tdg;
179c5591576SRob Johnston 
180c5591576SRob Johnston 		if ((tdg = topo_digraph_get(thp, buf)) == NULL) {
181c5591576SRob Johnston 			return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
182c5591576SRob Johnston 			    TOPO_METH_STR2NVL, in));
183c5591576SRob Johnston 		}
184c5591576SRob Johnston 		rnode = tdg->tdg_rootnode;
185c5591576SRob Johnston 	} else if ((rnode = topo_hdl_root(thp, buf)) == NULL) {
1867aec1d6eScindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
1877aec1d6eScindi 		    TOPO_METH_STR2NVL, in));
188c5591576SRob Johnston 	}
1897aec1d6eScindi 
1907aec1d6eScindi 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
1917aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL,
1927aec1d6eScindi 		    in));
1937aec1d6eScindi 
1947aec1d6eScindi 	if (nvlist_add_string(in, "fmri-string", fmristr) != 0)
1957aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL,
1967aec1d6eScindi 		    in));
1977aec1d6eScindi 
198c5591576SRob Johnston 	if (topo_method_invoke(rnode, method, TOPO_METH_STR2NVL_VERSION, in,
199c5591576SRob Johnston 	    &out, err) != 0)
2007aec1d6eScindi 		return (set_error(thp, *err, err, TOPO_METH_STR2NVL, in));
2017aec1d6eScindi 
20212cc75c8Scindi 	nvlist_free(in);
20312cc75c8Scindi 
2047aec1d6eScindi 	if (out == NULL ||
2057aec1d6eScindi 	    topo_hdl_nvdup(thp, out, fmri) != 0)
2067aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
20712cc75c8Scindi 		    TOPO_METH_STR2NVL, out));
2087aec1d6eScindi 
2097aec1d6eScindi 	nvlist_free(out);
2107aec1d6eScindi 
2117aec1d6eScindi 	return (0);
2127aec1d6eScindi }
2137aec1d6eScindi 
2147aec1d6eScindi int
topo_fmri_present(topo_hdl_t * thp,nvlist_t * fmri,int * err)2157aec1d6eScindi topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err)
2167aec1d6eScindi {
2170eb822a1Scindi 	uint32_t present = 0;
2187aec1d6eScindi 	char *scheme;
2197aec1d6eScindi 	nvlist_t *out = NULL;
2207aec1d6eScindi 	tnode_t *rnode;
2217aec1d6eScindi 
2227aec1d6eScindi 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
2237aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
2247aec1d6eScindi 		    TOPO_METH_PRESENT, out));
2257aec1d6eScindi 
2267aec1d6eScindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
2277aec1d6eScindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
2287aec1d6eScindi 		    TOPO_METH_PRESENT, out));
2297aec1d6eScindi 
2300eb822a1Scindi 	if (topo_method_invoke(rnode, TOPO_METH_PRESENT,
2310eb822a1Scindi 	    TOPO_METH_PRESENT_VERSION, fmri, &out, err) < 0) {
2320eb822a1Scindi 		(void) set_error(thp, *err, err, TOPO_METH_PRESENT, out);
2330eb822a1Scindi 		return (present);
2340eb822a1Scindi 	}
2357aec1d6eScindi 
2360eb822a1Scindi 	(void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present);
2370eb822a1Scindi 	nvlist_free(out);
2380eb822a1Scindi 
2390eb822a1Scindi 	return (present);
2407aec1d6eScindi }
2417aec1d6eScindi 
24225c6ff4bSstephh int
topo_fmri_replaced(topo_hdl_t * thp,nvlist_t * fmri,int * err)24325c6ff4bSstephh topo_fmri_replaced(topo_hdl_t *thp, nvlist_t *fmri, int *err)
24425c6ff4bSstephh {
24525c6ff4bSstephh 	uint32_t replaced = FMD_OBJ_STATE_NOT_PRESENT;
24625c6ff4bSstephh 	char *scheme;
24725c6ff4bSstephh 	nvlist_t *out = NULL;
24825c6ff4bSstephh 	tnode_t *rnode;
24925c6ff4bSstephh 
25025c6ff4bSstephh 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
25125c6ff4bSstephh 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
25225c6ff4bSstephh 		    TOPO_METH_REPLACED, out));
25325c6ff4bSstephh 
25425c6ff4bSstephh 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
25525c6ff4bSstephh 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
25625c6ff4bSstephh 		    TOPO_METH_REPLACED, out));
25725c6ff4bSstephh 
25825c6ff4bSstephh 	if (topo_method_invoke(rnode, TOPO_METH_REPLACED,
25925c6ff4bSstephh 	    TOPO_METH_REPLACED_VERSION, fmri, &out, err) < 0) {
26025c6ff4bSstephh 		(void) set_error(thp, *err, err, TOPO_METH_REPLACED, out);
26125c6ff4bSstephh 		return (FMD_OBJ_STATE_UNKNOWN);
26225c6ff4bSstephh 	}
26325c6ff4bSstephh 
26425c6ff4bSstephh 	(void) nvlist_lookup_uint32(out, TOPO_METH_REPLACED_RET, &replaced);
26525c6ff4bSstephh 	nvlist_free(out);
26625c6ff4bSstephh 
26725c6ff4bSstephh 	return (replaced);
26825c6ff4bSstephh }
26925c6ff4bSstephh 
2707aec1d6eScindi int
topo_fmri_contains(topo_hdl_t * thp,nvlist_t * fmri,nvlist_t * subfmri,int * err)2717aec1d6eScindi topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err)
2727aec1d6eScindi {
273c40d7343Scindi 	uint32_t contains;
2747aec1d6eScindi 	char *scheme;
275c40d7343Scindi 	nvlist_t *in = NULL, *out = NULL;
2767aec1d6eScindi 	tnode_t *rnode;
2777aec1d6eScindi 
2787aec1d6eScindi 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
2797aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
280c40d7343Scindi 		    TOPO_METH_CONTAINS, NULL));
2817aec1d6eScindi 
2827aec1d6eScindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
2837aec1d6eScindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
284c40d7343Scindi 		    TOPO_METH_CONTAINS, NULL));
2857aec1d6eScindi 
2867aec1d6eScindi 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
2877aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
288c40d7343Scindi 		    NULL));
2897aec1d6eScindi 
290c40d7343Scindi 	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 ||
291c40d7343Scindi 	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0)
2927aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
293c40d7343Scindi 		    in));
2947aec1d6eScindi 
295c40d7343Scindi 	if (topo_method_invoke(rnode, TOPO_METH_CONTAINS,
296e4b86885SCheng Sean Ye 	    TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0)
297c40d7343Scindi 		return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in));
298c40d7343Scindi 
299c40d7343Scindi 	(void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains);
300c40d7343Scindi 	nvlist_free(in);
301c40d7343Scindi 	nvlist_free(out);
3027aec1d6eScindi 
303c40d7343Scindi 	return (contains);
3047aec1d6eScindi }
3057aec1d6eScindi 
3067aec1d6eScindi int
topo_fmri_unusable(topo_hdl_t * thp,nvlist_t * fmri,int * err)3077aec1d6eScindi topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err)
3087aec1d6eScindi {
3097aec1d6eScindi 	char *scheme;
310dd566498Svn 	uint32_t unusable = 0;
3117aec1d6eScindi 	nvlist_t *out = NULL;
3127aec1d6eScindi 	tnode_t *rnode;
3137aec1d6eScindi 
3147aec1d6eScindi 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
3157aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
3167aec1d6eScindi 		    TOPO_METH_UNUSABLE, out));
3177aec1d6eScindi 
3187aec1d6eScindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
3197aec1d6eScindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
3207aec1d6eScindi 		    TOPO_METH_UNUSABLE, out));
3217aec1d6eScindi 
322dd566498Svn 	if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE,
323dd566498Svn 	    TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0)
3247aec1d6eScindi 		return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out));
3257aec1d6eScindi 
326dd566498Svn 	(void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable);
327dd566498Svn 	nvlist_free(out);
328dd566498Svn 
329dd566498Svn 	return (unusable);
3307aec1d6eScindi }
3317aec1d6eScindi 
332e4b86885SCheng Sean Ye int
topo_fmri_retire(topo_hdl_t * thp,nvlist_t * fmri,int * err)333e4b86885SCheng Sean Ye topo_fmri_retire(topo_hdl_t *thp, nvlist_t *fmri, int *err)
334e4b86885SCheng Sean Ye {
335e4b86885SCheng Sean Ye 	char *scheme;
336e4b86885SCheng Sean Ye 	uint32_t status;
337e4b86885SCheng Sean Ye 	nvlist_t *out = NULL;
338e4b86885SCheng Sean Ye 	tnode_t *rnode;
339e4b86885SCheng Sean Ye 
340e4b86885SCheng Sean Ye 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
341e4b86885SCheng Sean Ye 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
342e4b86885SCheng Sean Ye 		    TOPO_METH_RETIRE, out));
343e4b86885SCheng Sean Ye 
344e4b86885SCheng Sean Ye 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
345e4b86885SCheng Sean Ye 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
346e4b86885SCheng Sean Ye 		    TOPO_METH_RETIRE, out));
347e4b86885SCheng Sean Ye 
348e4b86885SCheng Sean Ye 	if (topo_method_invoke(rnode, TOPO_METH_RETIRE,
349e4b86885SCheng Sean Ye 	    TOPO_METH_RETIRE_VERSION, fmri, &out, err) < 0)
350e4b86885SCheng Sean Ye 		return (set_error(thp, *err, err, TOPO_METH_RETIRE, out));
351e4b86885SCheng Sean Ye 
352e4b86885SCheng Sean Ye 	if (nvlist_lookup_uint32(out, TOPO_METH_RETIRE_RET, &status) != 0)
353e4b86885SCheng Sean Ye 		return (set_error(thp, ETOPO_METHOD_FAIL, err,
354e4b86885SCheng Sean Ye 		    TOPO_METH_RETIRE, out));
355e4b86885SCheng Sean Ye 	nvlist_free(out);
356e4b86885SCheng Sean Ye 
357e4b86885SCheng Sean Ye 	return (status);
358e4b86885SCheng Sean Ye }
359e4b86885SCheng Sean Ye 
360e4b86885SCheng Sean Ye int
topo_fmri_unretire(topo_hdl_t * thp,nvlist_t * fmri,int * err)361e4b86885SCheng Sean Ye topo_fmri_unretire(topo_hdl_t *thp, nvlist_t *fmri, int *err)
362e4b86885SCheng Sean Ye {
363e4b86885SCheng Sean Ye 	char *scheme;
364e4b86885SCheng Sean Ye 	uint32_t status;
365e4b86885SCheng Sean Ye 	nvlist_t *out = NULL;
366e4b86885SCheng Sean Ye 	tnode_t *rnode;
367e4b86885SCheng Sean Ye 
368e4b86885SCheng Sean Ye 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
369e4b86885SCheng Sean Ye 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
370e4b86885SCheng Sean Ye 		    TOPO_METH_UNRETIRE, out));
371e4b86885SCheng Sean Ye 
372e4b86885SCheng Sean Ye 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
373e4b86885SCheng Sean Ye 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
374e4b86885SCheng Sean Ye 		    TOPO_METH_UNRETIRE, out));
375e4b86885SCheng Sean Ye 
376e4b86885SCheng Sean Ye 	if (topo_method_invoke(rnode, TOPO_METH_UNRETIRE,
377e4b86885SCheng Sean Ye 	    TOPO_METH_UNRETIRE_VERSION, fmri, &out, err) < 0)
378e4b86885SCheng Sean Ye 		return (set_error(thp, *err, err, TOPO_METH_UNRETIRE, out));
379e4b86885SCheng Sean Ye 
380e4b86885SCheng Sean Ye 	if (nvlist_lookup_uint32(out, TOPO_METH_UNRETIRE_RET, &status) != 0) {
381e4b86885SCheng Sean Ye 		nvlist_free(out);
382e4b86885SCheng Sean Ye 		return (set_error(thp, ETOPO_METHOD_FAIL, err,
383e4b86885SCheng Sean Ye 		    TOPO_METH_UNRETIRE, out));
384e4b86885SCheng Sean Ye 	}
385e4b86885SCheng Sean Ye 	nvlist_free(out);
386e4b86885SCheng Sean Ye 
387e4b86885SCheng Sean Ye 	return (status);
388e4b86885SCheng Sean Ye }
389e4b86885SCheng Sean Ye 
39025c6ff4bSstephh int
topo_fmri_service_state(topo_hdl_t * thp,nvlist_t * fmri,int * err)39125c6ff4bSstephh topo_fmri_service_state(topo_hdl_t *thp, nvlist_t *fmri, int *err)
39225c6ff4bSstephh {
39325c6ff4bSstephh 	char *scheme;
39425c6ff4bSstephh 	uint32_t service_state = FMD_SERVICE_STATE_UNKNOWN;
39525c6ff4bSstephh 	nvlist_t *out = NULL;
39625c6ff4bSstephh 	tnode_t *rnode;
39725c6ff4bSstephh 
39825c6ff4bSstephh 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
39925c6ff4bSstephh 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
40025c6ff4bSstephh 		    TOPO_METH_SERVICE_STATE, out));
40125c6ff4bSstephh 
40225c6ff4bSstephh 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
40325c6ff4bSstephh 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
40425c6ff4bSstephh 		    TOPO_METH_SERVICE_STATE, out));
40525c6ff4bSstephh 
40625c6ff4bSstephh 	if (topo_method_invoke(rnode, TOPO_METH_SERVICE_STATE,
40725c6ff4bSstephh 	    TOPO_METH_SERVICE_STATE_VERSION, fmri, &out, err) < 0)
40825c6ff4bSstephh 		return (set_error(thp, *err, err, TOPO_METH_SERVICE_STATE,
40925c6ff4bSstephh 		    out));
41025c6ff4bSstephh 
41125c6ff4bSstephh 	(void) nvlist_lookup_uint32(out, TOPO_METH_SERVICE_STATE_RET,
41225c6ff4bSstephh 	    &service_state);
41325c6ff4bSstephh 	nvlist_free(out);
41425c6ff4bSstephh 
41525c6ff4bSstephh 	return (service_state);
41625c6ff4bSstephh }
41725c6ff4bSstephh 
4187aec1d6eScindi int
topo_fmri_expand(topo_hdl_t * thp,nvlist_t * fmri,int * err)4197aec1d6eScindi topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err)
4207aec1d6eScindi {
4217aec1d6eScindi 	char *scheme;
4227aec1d6eScindi 	nvlist_t *out = NULL;
4237aec1d6eScindi 	tnode_t *rnode;
4247aec1d6eScindi 
4257aec1d6eScindi 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
4267aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
4277aec1d6eScindi 		    TOPO_METH_EXPAND, out));
4287aec1d6eScindi 
4297aec1d6eScindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
4307aec1d6eScindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
4317aec1d6eScindi 		    TOPO_METH_EXPAND, out));
4327aec1d6eScindi 
4337aec1d6eScindi 	if (topo_method_invoke(rnode, TOPO_METH_EXPAND,
4347aec1d6eScindi 	    TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0)
4357aec1d6eScindi 		return (set_error(thp, *err, err, TOPO_METH_EXPAND, out));
4367aec1d6eScindi 
4377aec1d6eScindi 	return (0);
4387aec1d6eScindi }
4397aec1d6eScindi 
4407aec1d6eScindi 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)441c40d7343Scindi fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
442c40d7343Scindi     const char *pname, nvlist_t *args, nvlist_t **prop,
443c40d7343Scindi     int *err)
4447aec1d6eScindi {
445c40d7343Scindi 	int rv;
446c40d7343Scindi 	nvlist_t *in = NULL;
447c40d7343Scindi 	tnode_t *rnode;
448c40d7343Scindi 	char *scheme;
4499dd0f810Scindi 
450c40d7343Scindi 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
451c40d7343Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
452c40d7343Scindi 		    TOPO_METH_PROP_GET, in));
4537aec1d6eScindi 
454c40d7343Scindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
455c40d7343Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
456c40d7343Scindi 		    TOPO_METH_PROP_GET, in));
4577aec1d6eScindi 
458c40d7343Scindi 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
459c40d7343Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
460c40d7343Scindi 		    TOPO_METH_PROP_GET, in));
461c40d7343Scindi 
462c40d7343Scindi 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
463c40d7343Scindi 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
464c40d7343Scindi 	rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname);
465c40d7343Scindi 	if (args != NULL)
466c40d7343Scindi 		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
467c40d7343Scindi 	if (rv != 0)
468c40d7343Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
469c40d7343Scindi 		    TOPO_METH_PROP_GET, in));
4709dd0f810Scindi 
4713cb1d852Scindi 	*prop = NULL;
472c40d7343Scindi 	rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET,
473c40d7343Scindi 	    TOPO_METH_PROP_GET_VERSION, in, prop, err);
4747aec1d6eScindi 
475c40d7343Scindi 	nvlist_free(in);
476c40d7343Scindi 
477c40d7343Scindi 	if (rv != 0)
478c40d7343Scindi 		return (-1); /* *err is set for us */
4793cb1d852Scindi 
480c40d7343Scindi 	if (*prop == NULL)
481c40d7343Scindi 		return (set_error(thp, ETOPO_PROP_NOENT, err,
482c40d7343Scindi 		    TOPO_METH_PROP_GET, NULL));
4837aec1d6eScindi 	return (0);
4847aec1d6eScindi }
4857aec1d6eScindi 
4867aec1d6eScindi int
topo_fmri_asru(topo_hdl_t * thp,nvlist_t * nvl,nvlist_t ** asru,int * err)4879dd0f810Scindi topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err)
4887aec1d6eScindi {
489c40d7343Scindi 	nvlist_t *ap, *prop = NULL;
4903cb1d852Scindi 
4919dd0f810Scindi 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU,
492c40d7343Scindi 	    nvl, &prop, err) < 0)
4939dd0f810Scindi 		return (set_error(thp, *err, err, "topo_fmri_asru", NULL));
4947aec1d6eScindi 
495c40d7343Scindi 	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0)
496c40d7343Scindi 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru",
497c40d7343Scindi 		    prop));
498c40d7343Scindi 
499c40d7343Scindi 	if (topo_hdl_nvdup(thp, ap, asru) < 0)
500c40d7343Scindi 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru",
501c40d7343Scindi 		    prop));
502c40d7343Scindi 
503c40d7343Scindi 	nvlist_free(prop);
504c40d7343Scindi 
5059dd0f810Scindi 	return (0);
5069dd0f810Scindi }
5077aec1d6eScindi 
5089dd0f810Scindi int
topo_fmri_fru(topo_hdl_t * thp,nvlist_t * nvl,nvlist_t ** fru,int * err)5099dd0f810Scindi topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err)
5109dd0f810Scindi {
511c40d7343Scindi 	nvlist_t *fp, *prop = NULL;
5129dd0f810Scindi 
5139dd0f810Scindi 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU,
51424db4641Seschrock 	    nvl, &prop, err) < 0)
5157aec1d6eScindi 		return (set_error(thp, *err, err, "topo_fmri_fru", NULL));
5169dd0f810Scindi 
517c40d7343Scindi 	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0)
518c40d7343Scindi 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru",
519c40d7343Scindi 		    prop));
520c40d7343Scindi 
521c40d7343Scindi 	if (topo_hdl_nvdup(thp, fp, fru) < 0)
522c40d7343Scindi 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru",
523c40d7343Scindi 		    prop));
524c40d7343Scindi 
525c40d7343Scindi 	nvlist_free(prop);
526c40d7343Scindi 
5279dd0f810Scindi 	return (0);
5289dd0f810Scindi }
5299dd0f810Scindi 
5309dd0f810Scindi int
topo_fmri_label(topo_hdl_t * thp,nvlist_t * nvl,char ** label,int * err)531c40d7343Scindi topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err)
5329dd0f810Scindi {
533c40d7343Scindi 	nvlist_t *prop = NULL;
534c40d7343Scindi 	char *lp;
5359dd0f810Scindi 
536c40d7343Scindi 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL,
537c40d7343Scindi 	    NULL, &prop, err) < 0)
5389dd0f810Scindi 		return (set_error(thp, *err, err, "topo_fmri_label", NULL));
5399dd0f810Scindi 
540c40d7343Scindi 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0)
5419dd0f810Scindi 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label",
542c40d7343Scindi 		    prop));
5439dd0f810Scindi 
544c40d7343Scindi 	if ((*label = topo_hdl_strdup(thp, lp)) == NULL)
545c40d7343Scindi 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label",
546c40d7343Scindi 		    prop));
5477aec1d6eScindi 
548c40d7343Scindi 	nvlist_free(prop);
5492cb5535aSrobj 
5502cb5535aSrobj 	return (0);
5512cb5535aSrobj }
5522cb5535aSrobj 
5532cb5535aSrobj int
topo_fmri_serial(topo_hdl_t * thp,nvlist_t * nvl,char ** serial,int * err)5542cb5535aSrobj topo_fmri_serial(topo_hdl_t *thp, nvlist_t *nvl, char **serial, int *err)
5552cb5535aSrobj {
5562cb5535aSrobj 	nvlist_t *prop = NULL;
5572cb5535aSrobj 	char *sp;
5582cb5535aSrobj 
5596e1fa242SStephen Hanson 	/*
5606e1fa242SStephen Hanson 	 * If there is a serial id in the resource fmri, then use that.
5616e1fa242SStephen Hanson 	 * Otherwise fall back to looking for a serial id property in the
5626e1fa242SStephen Hanson 	 * protocol group.
5636e1fa242SStephen Hanson 	 */
5646e1fa242SStephen Hanson 	if (nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &sp) == 0) {
5656e1fa242SStephen Hanson 		if ((*serial = topo_hdl_strdup(thp, sp)) == NULL)
5666e1fa242SStephen Hanson 			return (set_error(thp, ETOPO_PROP_NOMEM, err,
5676e1fa242SStephen Hanson 			    "topo_fmri_serial", prop));
5686e1fa242SStephen Hanson 		else
5696e1fa242SStephen Hanson 			return (0);
5706e1fa242SStephen Hanson 	}
5716e1fa242SStephen Hanson 
5722cb5535aSrobj 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, FM_FMRI_HC_SERIAL_ID,
5732cb5535aSrobj 	    NULL, &prop, err) < 0)
5742cb5535aSrobj 		return (set_error(thp, *err, err, "topo_fmri_serial", NULL));
5752cb5535aSrobj 
5762cb5535aSrobj 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &sp) != 0)
5772cb5535aSrobj 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_serial",
5782cb5535aSrobj 		    prop));
5792cb5535aSrobj 
5802cb5535aSrobj 	if ((*serial = topo_hdl_strdup(thp, sp)) == NULL)
5812cb5535aSrobj 		return (set_error(thp, ETOPO_PROP_NOMEM, err,
5822cb5535aSrobj 		    "topo_fmri_serial", prop));
5832cb5535aSrobj 
5842cb5535aSrobj 	nvlist_free(prop);
5859dd0f810Scindi 
586c40d7343Scindi 	return (0);
587c40d7343Scindi }
588c40d7343Scindi 
topo_fmri_getprop(topo_hdl_t * thp,nvlist_t * nvl,const char * pg,const char * pname,nvlist_t * args,nvlist_t ** prop,int * err)589c40d7343Scindi int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
590c40d7343Scindi     const char *pname, nvlist_t *args,  nvlist_t **prop,
591c40d7343Scindi     int *err)
592c40d7343Scindi {
593c40d7343Scindi 	*prop = NULL;
594c40d7343Scindi 
595c40d7343Scindi 	return (fmri_prop(thp, nvl, pg, pname, args, prop, err));
596c40d7343Scindi }
597c40d7343Scindi 
topo_fmri_setprop(topo_hdl_t * thp,nvlist_t * nvl,const char * pg,nvlist_t * prop,int flag,nvlist_t * args,int * err)598c40d7343Scindi int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
599c40d7343Scindi     nvlist_t *prop, int flag, nvlist_t *args, int *err)
600c40d7343Scindi {
601c40d7343Scindi 	int rv;
602c40d7343Scindi 	nvlist_t *in = NULL, *out = NULL;
603c40d7343Scindi 	tnode_t *rnode;
604c40d7343Scindi 	char *scheme;
605c40d7343Scindi 
606c40d7343Scindi 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0)
607c40d7343Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
608c40d7343Scindi 		    TOPO_METH_PROP_SET, in));
609c40d7343Scindi 
610c40d7343Scindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
611c40d7343Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
612c40d7343Scindi 		    TOPO_METH_PROP_SET, in));
613c40d7343Scindi 
614c40d7343Scindi 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
615c40d7343Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
616c40d7343Scindi 		    TOPO_METH_PROP_SET, in));
617c40d7343Scindi 
618c40d7343Scindi 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl);
619c40d7343Scindi 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg);
620c40d7343Scindi 	rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop);
621c40d7343Scindi 	rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag);
622c40d7343Scindi 	if (args != NULL)
623c40d7343Scindi 		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
624c40d7343Scindi 	if (rv != 0)
625c40d7343Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
626c40d7343Scindi 		    TOPO_METH_PROP_SET, in));
627c40d7343Scindi 
628c40d7343Scindi 	rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET,
629c40d7343Scindi 	    TOPO_METH_PROP_SET_VERSION, in, &out, err);
630c40d7343Scindi 
631c40d7343Scindi 	nvlist_free(in);
632c40d7343Scindi 
633c40d7343Scindi 	/* no return values */
634aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(out);
635c40d7343Scindi 
636c40d7343Scindi 	if (rv)
637c40d7343Scindi 		return (-1);
638c40d7343Scindi 
639c40d7343Scindi 	return (0);
640c40d7343Scindi 
641c40d7343Scindi }
642c40d7343Scindi 
643c40d7343Scindi int
topo_fmri_getpgrp(topo_hdl_t * thp,nvlist_t * rsrc,const char * pgname,nvlist_t ** pgroup,int * err)644c40d7343Scindi topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
645c40d7343Scindi     nvlist_t **pgroup, int *err)
646c40d7343Scindi {
647c40d7343Scindi 	int rv;
648c40d7343Scindi 	nvlist_t *in = NULL;
649c40d7343Scindi 	tnode_t *rnode;
650c40d7343Scindi 	char *scheme;
651c40d7343Scindi 
652c40d7343Scindi 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
653c40d7343Scindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
654c40d7343Scindi 		    TOPO_METH_PROP_GET, in));
6559dd0f810Scindi 
656c40d7343Scindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
657c40d7343Scindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
658c40d7343Scindi 		    TOPO_METH_PROP_GET, in));
659c40d7343Scindi 
660c40d7343Scindi 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
661c40d7343Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
662c40d7343Scindi 		    TOPO_METH_PROP_GET, in));
6639dd0f810Scindi 
664c40d7343Scindi 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
665c40d7343Scindi 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
666c40d7343Scindi 	if (rv != 0)
667c40d7343Scindi 		return (set_error(thp, ETOPO_FMRI_NVL, err,
668c40d7343Scindi 		    TOPO_METH_PROP_GET, in));
669c40d7343Scindi 
670c40d7343Scindi 	*pgroup = NULL;
671c40d7343Scindi 	rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET,
672c40d7343Scindi 	    TOPO_METH_PGRP_GET_VERSION, in, pgroup, err);
673c40d7343Scindi 
674c40d7343Scindi 	nvlist_free(in);
6759dd0f810Scindi 
676c40d7343Scindi 	if (rv != 0)
677c40d7343Scindi 		return (-1); /* *err is set for us */
678c40d7343Scindi 
679c40d7343Scindi 	if (*pgroup == NULL)
680c40d7343Scindi 		return (set_error(thp, ETOPO_PROP_NOENT, err,
681c40d7343Scindi 		    TOPO_METH_PROP_GET, NULL));
6827aec1d6eScindi 	return (0);
6837aec1d6eScindi }
6847aec1d6eScindi 
6857aec1d6eScindi int
topo_fmri_compare(topo_hdl_t * thp,nvlist_t * f1,nvlist_t * f2,int * err)6867aec1d6eScindi topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err)
6877aec1d6eScindi {
688c40d7343Scindi 	uint32_t compare;
6897aec1d6eScindi 	char *scheme1, *scheme2;
6907aec1d6eScindi 	nvlist_t *in;
6917aec1d6eScindi 	nvlist_t *out = NULL;
6927aec1d6eScindi 	tnode_t *rnode;
6937aec1d6eScindi 
6947aec1d6eScindi 	if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0)
6957aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
6967aec1d6eScindi 		    TOPO_METH_COMPARE, NULL));
697724365f7Ssethg 	if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0)
6987aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
6997aec1d6eScindi 		    TOPO_METH_COMPARE, NULL));
7007aec1d6eScindi 
7017aec1d6eScindi 	if (strcmp(scheme1, scheme2) != 0)
7027aec1d6eScindi 		return (0);
7037aec1d6eScindi 
7047aec1d6eScindi 	if ((rnode = topo_hdl_root(thp, scheme1)) == NULL)
7057aec1d6eScindi 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
7067aec1d6eScindi 		    TOPO_METH_COMPARE, NULL));
7077aec1d6eScindi 
7087aec1d6eScindi 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
7097aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
7107aec1d6eScindi 		    NULL));
7117aec1d6eScindi 
712c40d7343Scindi 	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 ||
713c40d7343Scindi 	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0)
7147aec1d6eScindi 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
7157aec1d6eScindi 		    in));
7167aec1d6eScindi 
717c40d7343Scindi 	if (topo_method_invoke(rnode, TOPO_METH_COMPARE,
718c40d7343Scindi 	    TOPO_METH_COMPARE_VERSION, in, &out, err) < 0)
7197aec1d6eScindi 		return (set_error(thp, *err, err, TOPO_METH_COMPARE, in));
7207aec1d6eScindi 
721c40d7343Scindi 	(void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare);
722c40d7343Scindi 	nvlist_free(out);
7237aec1d6eScindi 	nvlist_free(in);
7247aec1d6eScindi 
725c40d7343Scindi 	return (compare);
7267aec1d6eScindi }
7277aec1d6eScindi 
7287aec1d6eScindi /*
7297aec1d6eScindi  * topo_fmri_create
7307aec1d6eScindi  *
7317aec1d6eScindi  *	If possible, creates an FMRI of the requested version in the
7327aec1d6eScindi  *	requested scheme.  Args are passed as part of the inputs to the
7337aec1d6eScindi  *	fmri-create method of the scheme.
7347aec1d6eScindi  */
7357aec1d6eScindi nvlist_t *
topo_fmri_create(topo_hdl_t * thp,const char * scheme,const char * name,topo_instance_t inst,nvlist_t * nvl,int * err)7367aec1d6eScindi topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name,
7377aec1d6eScindi     topo_instance_t inst, nvlist_t *nvl, int *err)
7387aec1d6eScindi {
7397aec1d6eScindi 	nvlist_t *ins;
7407aec1d6eScindi 	nvlist_t *out;
7417aec1d6eScindi 	tnode_t *rnode;
7427aec1d6eScindi 
7437aec1d6eScindi 	ins = out = NULL;
7447aec1d6eScindi 
7457aec1d6eScindi 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
7467aec1d6eScindi 		return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err,
7477aec1d6eScindi 		    TOPO_METH_FMRI, NULL));
7487aec1d6eScindi 
7497aec1d6eScindi 	if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0)
7507aec1d6eScindi 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
7517aec1d6eScindi 		    TOPO_METH_FMRI, NULL));
7527aec1d6eScindi 
7537aec1d6eScindi 	if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 ||
754c5591576SRob Johnston 	    nvlist_add_uint64(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) {
7557aec1d6eScindi 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
7567aec1d6eScindi 		    TOPO_METH_FMRI, ins));
7577aec1d6eScindi 	}
7587aec1d6eScindi 
7597aec1d6eScindi 	if (nvl != NULL &&
7607aec1d6eScindi 	    nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) {
7617aec1d6eScindi 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
7627aec1d6eScindi 		    TOPO_METH_FMRI, ins));
7637aec1d6eScindi 	}
7647aec1d6eScindi 	if (topo_method_invoke(rnode,
7657aec1d6eScindi 	    TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) {
7667aec1d6eScindi 		return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins));
7677aec1d6eScindi 	}
7687aec1d6eScindi 	nvlist_free(ins);
7697aec1d6eScindi 	return (out);
7707aec1d6eScindi }
771940d71d2Seschrock 
772940d71d2Seschrock /*
773940d71d2Seschrock  * These private utility functions are used by fmd to maintain its resource
774940d71d2Seschrock  * cache.  Because hc instance numbers are not guaranteed, it's possible to
775940d71d2Seschrock  * have two different FMRI strings represent the same logical entity.  These
776940d71d2Seschrock  * functions hide this implementation detail from unknowing consumers such as
777940d71d2Seschrock  * fmd.
778940d71d2Seschrock  *
779940d71d2Seschrock  * Ideally, we'd like to do a str2nvl() and then a full FMRI hash and
780940d71d2Seschrock  * comparison, but these functions are designed to be fast and efficient.
781940d71d2Seschrock  * Given that there is only a single hc node that has this property
782940d71d2Seschrock  * (ses-enclosure), we hard-code this behavior here.  If there are more
783940d71d2Seschrock  * instances of this behavior in the future, this function could be made more
784940d71d2Seschrock  * generic.
785069f55e2SEric Schrock  *
786069f55e2SEric Schrock  * This code also handles changes in the server-id or revision fields of the hc
787069f55e2SEric Schrock  * FMRI, as these fields have no bearing on equivalence of FRUs.
788940d71d2Seschrock  */
789940d71d2Seschrock static ulong_t
topo_fmri_strhash_one(const char * fmri,size_t len)790940d71d2Seschrock topo_fmri_strhash_one(const char *fmri, size_t len)
791940d71d2Seschrock {
792940d71d2Seschrock 	ulong_t g, h = 0;
793940d71d2Seschrock 	size_t i;
794940d71d2Seschrock 
795940d71d2Seschrock 	for (i = 0; i < len; i++) {
796940d71d2Seschrock 		h = (h << 4) + fmri[i];
797940d71d2Seschrock 
798940d71d2Seschrock 		if ((g = (h & 0xf0000000)) != 0) {
799940d71d2Seschrock 			h ^= (g >> 24);
800940d71d2Seschrock 			h ^= g;
801940d71d2Seschrock 		}
802940d71d2Seschrock 	}
803940d71d2Seschrock 
804940d71d2Seschrock 	return (h);
805940d71d2Seschrock }
806940d71d2Seschrock 
807069f55e2SEric Schrock static const char *
topo_fmri_next_auth(const char * auth)808069f55e2SEric Schrock topo_fmri_next_auth(const char *auth)
809069f55e2SEric Schrock {
810069f55e2SEric Schrock 	const char *colon, *slash;
811069f55e2SEric Schrock 
812069f55e2SEric Schrock 	colon = strchr(auth + 1, ':');
813069f55e2SEric Schrock 	slash = strchr(auth, '/');
814069f55e2SEric Schrock 
815069f55e2SEric Schrock 	if (colon == NULL && slash == NULL)
816069f55e2SEric Schrock 		return (NULL);
817069f55e2SEric Schrock 
818069f55e2SEric Schrock 	if (colon == NULL)
819069f55e2SEric Schrock 		return (slash);
820069f55e2SEric Schrock 	else if (slash < colon)
821069f55e2SEric Schrock 		return (slash);
822069f55e2SEric Schrock 	else
823069f55e2SEric Schrock 		return (colon);
824069f55e2SEric Schrock }
825069f55e2SEric Schrock 
826069f55e2SEric Schrock /*
827069f55e2SEric Schrock  * List of authority information we care about.  Note that we explicitly ignore
828069f55e2SEric Schrock  * things that are properties of the chassis and not the resource itself:
829069f55e2SEric Schrock  *
830c5591576SRob Johnston  *      FM_FMRI_AUTH_PRODUCT_SN         "product-sn"
831c5591576SRob Johnston  *      FM_FMRI_AUTH_PRODUCT            "product-id"
832c5591576SRob Johnston  *      FM_FMRI_AUTH_DOMAIN             "domain-id"
833c5591576SRob Johnston  *      FM_FMRI_AUTH_SERVER             "server-id"
834c5591576SRob Johnston  *	FM_FMRI_AUTH_HOST               "host-id"
835069f55e2SEric Schrock  *
836069f55e2SEric Schrock  * We also ignore the "revision" authority member, as that typically indicates
837069f55e2SEric Schrock  * the firmware revision and is not a static property of the FRU.  This leaves
838069f55e2SEric Schrock  * the following interesting members:
839069f55e2SEric Schrock  *
840c5591576SRob Johnston  *      FM_FMRI_AUTH_CHASSIS            "chassis-id"
841069f55e2SEric Schrock  *	FM_FMRI_HC_SERIAL_ID		"serial"
842069f55e2SEric Schrock  *	FM_FMRI_HC_PART			"part"
843069f55e2SEric Schrock  */
844069f55e2SEric Schrock typedef enum {
845069f55e2SEric Schrock 	HC_AUTH_CHASSIS,
846069f55e2SEric Schrock 	HC_AUTH_SERIAL,
847069f55e2SEric Schrock 	HC_AUTH_PART,
848069f55e2SEric Schrock 	HC_AUTH_MAX
849069f55e2SEric Schrock } hc_auth_type_t;
850069f55e2SEric Schrock 
851069f55e2SEric Schrock static char *hc_auth_table[] = {
852069f55e2SEric Schrock 	FM_FMRI_AUTH_CHASSIS,
853069f55e2SEric Schrock 	FM_FMRI_HC_SERIAL_ID,
854069f55e2SEric Schrock 	FM_FMRI_HC_PART
855069f55e2SEric Schrock };
856069f55e2SEric Schrock 
857069f55e2SEric Schrock /*
858069f55e2SEric Schrock  * Takes an authority member, with leading ":" and trailing "=", and returns
859069f55e2SEric Schrock  * one of the above types if it's one of the things we care about.  If
860069f55e2SEric Schrock  * 'authlen' is specified, it is filled in with the length of the authority
861069f55e2SEric Schrock  * member, including leading and trailing characters.
862069f55e2SEric Schrock  */
863069f55e2SEric Schrock static hc_auth_type_t
hc_auth_to_type(const char * auth,size_t * authlen)864069f55e2SEric Schrock hc_auth_to_type(const char *auth, size_t *authlen)
865069f55e2SEric Schrock {
866069f55e2SEric Schrock 	int i;
867069f55e2SEric Schrock 	size_t len;
868069f55e2SEric Schrock 
869069f55e2SEric Schrock 	if (auth[0] != ':')
870069f55e2SEric Schrock 		return (HC_AUTH_MAX);
871069f55e2SEric Schrock 
872069f55e2SEric Schrock 	for (i = 0; i < HC_AUTH_MAX; i++) {
873069f55e2SEric Schrock 		len = strlen(hc_auth_table[i]);
874069f55e2SEric Schrock 
875069f55e2SEric Schrock 		if (strncmp(auth + 1, hc_auth_table[i], len) == 0 &&
876069f55e2SEric Schrock 		    auth[len + 1] == '=') {
877069f55e2SEric Schrock 			if (authlen)
878069f55e2SEric Schrock 				*authlen = len + 2;
879069f55e2SEric Schrock 			break;
880069f55e2SEric Schrock 		}
881069f55e2SEric Schrock 	}
882069f55e2SEric Schrock 
883069f55e2SEric Schrock 	return (i);
884069f55e2SEric Schrock }
885069f55e2SEric Schrock 
886940d71d2Seschrock /*ARGSUSED*/
887940d71d2Seschrock ulong_t
topo_fmri_strhash_internal(topo_hdl_t * thp,const char * fmri,boolean_t noauth)888069f55e2SEric Schrock topo_fmri_strhash_internal(topo_hdl_t *thp, const char *fmri, boolean_t noauth)
889940d71d2Seschrock {
890069f55e2SEric Schrock 	const char *auth, *next;
891069f55e2SEric Schrock 	const char *enclosure;
892940d71d2Seschrock 	ulong_t h;
893069f55e2SEric Schrock 	hc_auth_type_t type;
894940d71d2Seschrock 
895069f55e2SEric Schrock 	if (strncmp(fmri, "hc://", 5) != 0)
896940d71d2Seschrock 		return (topo_fmri_strhash_one(fmri, strlen(fmri)));
897940d71d2Seschrock 
898069f55e2SEric Schrock 	enclosure = strstr(fmri, SES_ENCLOSURE);
899940d71d2Seschrock 
900069f55e2SEric Schrock 	h = 0;
901940d71d2Seschrock 
902069f55e2SEric Schrock 	auth = next = fmri + 5;
903069f55e2SEric Schrock 	while (*next != '/') {
904069f55e2SEric Schrock 		auth = next;
905069f55e2SEric Schrock 
906069f55e2SEric Schrock 		if ((next = topo_fmri_next_auth(auth)) == NULL) {
907069f55e2SEric Schrock 			next = auth;
908069f55e2SEric Schrock 			break;
909069f55e2SEric Schrock 		}
910069f55e2SEric Schrock 
911069f55e2SEric Schrock 		if ((type = hc_auth_to_type(auth, NULL)) == HC_AUTH_MAX)
912069f55e2SEric Schrock 			continue;
913069f55e2SEric Schrock 
914069f55e2SEric Schrock 		if (!noauth || type == HC_AUTH_CHASSIS)
915069f55e2SEric Schrock 			h += topo_fmri_strhash_one(auth, next - auth);
916069f55e2SEric Schrock 	}
917069f55e2SEric Schrock 
918069f55e2SEric Schrock 	if (enclosure) {
919069f55e2SEric Schrock 		next = enclosure + sizeof (SES_ENCLOSURE);
920069f55e2SEric Schrock 		while (isdigit(*next))
921069f55e2SEric Schrock 			next++;
922069f55e2SEric Schrock 	}
923069f55e2SEric Schrock 
924069f55e2SEric Schrock 	h += topo_fmri_strhash_one(next, strlen(next));
925940d71d2Seschrock 
926940d71d2Seschrock 	return (h);
927940d71d2Seschrock }
928940d71d2Seschrock 
929940d71d2Seschrock /*ARGSUSED*/
930069f55e2SEric Schrock ulong_t
topo_fmri_strhash(topo_hdl_t * thp,const char * fmri)931069f55e2SEric Schrock topo_fmri_strhash(topo_hdl_t *thp, const char *fmri)
932940d71d2Seschrock {
933069f55e2SEric Schrock 	return (topo_fmri_strhash_internal(thp, fmri, B_FALSE));
934069f55e2SEric Schrock }
935940d71d2Seschrock 
936069f55e2SEric Schrock /*ARGSUSED*/
937069f55e2SEric Schrock ulong_t
topo_fmri_strhash_noauth(topo_hdl_t * thp,const char * fmri)938069f55e2SEric Schrock topo_fmri_strhash_noauth(topo_hdl_t *thp, const char *fmri)
939069f55e2SEric Schrock {
940069f55e2SEric Schrock 	return (topo_fmri_strhash_internal(thp, fmri, B_TRUE));
941069f55e2SEric Schrock }
942069f55e2SEric Schrock 
943069f55e2SEric Schrock 
944069f55e2SEric Schrock static void
topo_fmri_strcmp_parse_auth(const char * auth,const char * authtype[],size_t authlen[])945069f55e2SEric Schrock topo_fmri_strcmp_parse_auth(const char *auth, const char *authtype[],
946069f55e2SEric Schrock     size_t authlen[])
947069f55e2SEric Schrock {
948069f55e2SEric Schrock 	int i;
949069f55e2SEric Schrock 	const char *next;
950069f55e2SEric Schrock 	hc_auth_type_t type;
951069f55e2SEric Schrock 	size_t len;
952069f55e2SEric Schrock 
953069f55e2SEric Schrock 	for (i = 0; i < HC_AUTH_MAX; i++)
954069f55e2SEric Schrock 		authlen[i] = 0;
955069f55e2SEric Schrock 
956069f55e2SEric Schrock 	while (*auth != '/' &&
957069f55e2SEric Schrock 	    (next = topo_fmri_next_auth(auth)) != NULL) {
958069f55e2SEric Schrock 		if ((type = hc_auth_to_type(auth, &len)) == HC_AUTH_MAX) {
959069f55e2SEric Schrock 			auth = next;
960069f55e2SEric Schrock 			continue;
961069f55e2SEric Schrock 		}
962069f55e2SEric Schrock 
963069f55e2SEric Schrock 		authtype[type] = auth + len;
964069f55e2SEric Schrock 		authlen[type] = next - (auth + len);
965069f55e2SEric Schrock 		auth = next;
966069f55e2SEric Schrock 	}
967069f55e2SEric Schrock }
968069f55e2SEric Schrock 
969069f55e2SEric Schrock /*ARGSUSED*/
970069f55e2SEric Schrock static boolean_t
topo_fmri_strcmp_internal(topo_hdl_t * thp,const char * a,const char * b,boolean_t noauth)971069f55e2SEric Schrock topo_fmri_strcmp_internal(topo_hdl_t *thp, const char *a, const char *b,
972069f55e2SEric Schrock     boolean_t noauth)
973069f55e2SEric Schrock {
974069f55e2SEric Schrock 	const char *fmria, *fmrib;
975069f55e2SEric Schrock 	const char *autha[HC_AUTH_MAX], *authb[HC_AUTH_MAX];
976069f55e2SEric Schrock 	size_t authlena[HC_AUTH_MAX], authlenb[HC_AUTH_MAX];
977069f55e2SEric Schrock 	int i;
978069f55e2SEric Schrock 
979069f55e2SEric Schrock 	/*
980069f55e2SEric Schrock 	 * For non-hc FMRIs, we don't do anything.
981069f55e2SEric Schrock 	 */
982940d71d2Seschrock 	if (strncmp(a, "hc://", 5) != 0 ||
983069f55e2SEric Schrock 	    strncmp(b, "hc://", 5) != 0)
984940d71d2Seschrock 		return (strcmp(a, b) == 0);
985940d71d2Seschrock 
986069f55e2SEric Schrock 	/*
987069f55e2SEric Schrock 	 * Get the portion of the FMRI independent of the authority
988069f55e2SEric Schrock 	 * information.
989069f55e2SEric Schrock 	 */
990069f55e2SEric Schrock 	fmria = strchr(a + 5, '/');
991069f55e2SEric Schrock 	fmrib = strchr(b + 5, '/');
992069f55e2SEric Schrock 	if (fmria == NULL || fmrib == NULL)
993069f55e2SEric Schrock 		return (strcmp(a, b));
994069f55e2SEric Schrock 	fmria++;
995069f55e2SEric Schrock 	fmrib++;
996069f55e2SEric Schrock 
997069f55e2SEric Schrock 	/*
998069f55e2SEric Schrock 	 * Comparing fmri authority information is a bit of a pain, because
999069f55e2SEric Schrock 	 * there may be a different number of members, and they can (but
1000069f55e2SEric Schrock 	 * shouldn't be) in a different order.  We need to create a copy of the
1001069f55e2SEric Schrock 	 * authority and parse it into pieces.  Because this function is
1002069f55e2SEric Schrock 	 * intended to be fast (and not necessarily extensible), we hard-code
1003069f55e2SEric Schrock 	 * the list of possible authority members in an enum and parse it into
1004069f55e2SEric Schrock 	 * an array.
1005069f55e2SEric Schrock 	 */
1006069f55e2SEric Schrock 	topo_fmri_strcmp_parse_auth(a + 5, autha, authlena);
1007069f55e2SEric Schrock 	topo_fmri_strcmp_parse_auth(b + 5, authb, authlenb);
1008069f55e2SEric Schrock 
1009069f55e2SEric Schrock 	for (i = 0; i < HC_AUTH_MAX; i++) {
1010069f55e2SEric Schrock 		if (noauth && i != HC_AUTH_CHASSIS)
1011069f55e2SEric Schrock 			continue;
1012069f55e2SEric Schrock 
1013069f55e2SEric Schrock 		if (authlena[i] == 0 && authlenb[i] == 0)
1014069f55e2SEric Schrock 			continue;
1015069f55e2SEric Schrock 
1016069f55e2SEric Schrock 		if (authlena[i] != authlenb[i])
1017069f55e2SEric Schrock 			return (B_FALSE);
1018940d71d2Seschrock 
1019069f55e2SEric Schrock 		if (strncmp(autha[i], authb[i], authlena[i]) != 0)
1020069f55e2SEric Schrock 			return (B_FALSE);
1021069f55e2SEric Schrock 	}
1022940d71d2Seschrock 
1023069f55e2SEric Schrock 	/*
1024069f55e2SEric Schrock 	 * If this is rooted at a ses-enclosure node, skip past the instance
1025069f55e2SEric Schrock 	 * number, as it has no meaning.
1026069f55e2SEric Schrock 	 */
1027069f55e2SEric Schrock 	if (strncmp(fmria, SES_ENCLOSURE, sizeof (SES_ENCLOSURE) - 1) == 0 &&
1028069f55e2SEric Schrock 	    strncmp(fmrib, SES_ENCLOSURE, sizeof (SES_ENCLOSURE) - 1) == 0) {
1029069f55e2SEric Schrock 		fmria += sizeof (SES_ENCLOSURE);
1030069f55e2SEric Schrock 		fmrib += sizeof (SES_ENCLOSURE);
1031069f55e2SEric Schrock 
1032069f55e2SEric Schrock 		while (isdigit(*fmria))
1033069f55e2SEric Schrock 			fmria++;
1034069f55e2SEric Schrock 		while (isdigit(*fmrib))
1035069f55e2SEric Schrock 			fmrib++;
1036069f55e2SEric Schrock 	}
1037940d71d2Seschrock 
1038069f55e2SEric Schrock 	return (strcmp(fmria, fmrib) == 0);
1039069f55e2SEric Schrock }
1040940d71d2Seschrock 
1041069f55e2SEric Schrock /*ARGSUSED*/
1042069f55e2SEric Schrock boolean_t
topo_fmri_strcmp(topo_hdl_t * thp,const char * a,const char * b)1043069f55e2SEric Schrock topo_fmri_strcmp(topo_hdl_t *thp, const char *a, const char *b)
1044069f55e2SEric Schrock {
1045069f55e2SEric Schrock 	return (topo_fmri_strcmp_internal(thp, a, b, B_FALSE));
1046069f55e2SEric Schrock }
1047069f55e2SEric Schrock 
1048069f55e2SEric Schrock /*ARGSUSED*/
1049069f55e2SEric Schrock boolean_t
topo_fmri_strcmp_noauth(topo_hdl_t * thp,const char * a,const char * b)1050069f55e2SEric Schrock topo_fmri_strcmp_noauth(topo_hdl_t *thp, const char *a, const char *b)
1051069f55e2SEric Schrock {
1052069f55e2SEric Schrock 	return (topo_fmri_strcmp_internal(thp, a, b, B_TRUE));
1053940d71d2Seschrock }
1054825ba0f2Srobj 
1055825ba0f2Srobj 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)1056825ba0f2Srobj topo_fmri_facility(topo_hdl_t *thp, nvlist_t *rsrc, const char *fac_type,
1057825ba0f2Srobj     uint32_t fac_subtype, topo_walk_cb_t cb, void *cb_args, int *err)
1058825ba0f2Srobj {
1059825ba0f2Srobj 	int rv;
1060825ba0f2Srobj 	nvlist_t *in = NULL, *out;
1061825ba0f2Srobj 	tnode_t *rnode;
1062825ba0f2Srobj 	char *scheme;
1063825ba0f2Srobj 
1064825ba0f2Srobj 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
1065825ba0f2Srobj 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
1066825ba0f2Srobj 		    TOPO_METH_PROP_GET, in));
1067825ba0f2Srobj 
1068825ba0f2Srobj 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
1069825ba0f2Srobj 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
1070825ba0f2Srobj 		    TOPO_METH_PROP_GET, in));
1071825ba0f2Srobj 
1072825ba0f2Srobj 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
1073825ba0f2Srobj 		return (set_error(thp, ETOPO_FMRI_NVL, err,
1074825ba0f2Srobj 		    TOPO_METH_PROP_GET, in));
1075825ba0f2Srobj 
1076825ba0f2Srobj 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
1077825ba0f2Srobj 	rv |= nvlist_add_string(in, FM_FMRI_FACILITY_TYPE, fac_type);
1078825ba0f2Srobj 	rv |= nvlist_add_uint32(in, "type", fac_subtype);
1079825ba0f2Srobj #ifdef _LP64
1080825ba0f2Srobj 	rv |= nvlist_add_uint64(in, "callback", (uint64_t)cb);
1081825ba0f2Srobj 	rv |= nvlist_add_uint64(in, "callback-args", (uint64_t)cb_args);
1082825ba0f2Srobj #else
1083825ba0f2Srobj 	rv |= nvlist_add_uint32(in, "callback", (uint32_t)cb);
1084825ba0f2Srobj 	rv |= nvlist_add_uint32(in, "callback-args", (uint32_t)cb_args);
1085825ba0f2Srobj #endif
1086825ba0f2Srobj 	if (rv != 0)
1087825ba0f2Srobj 		return (set_error(thp, ETOPO_FMRI_NVL, err,
1088825ba0f2Srobj 		    TOPO_METH_PROP_GET, in));
1089825ba0f2Srobj 
1090825ba0f2Srobj 	rv = topo_method_invoke(rnode, TOPO_METH_FACILITY,
1091825ba0f2Srobj 	    TOPO_METH_FACILITY_VERSION, in, &out, err);
1092825ba0f2Srobj 
1093825ba0f2Srobj 	nvlist_free(in);
1094825ba0f2Srobj 
1095825ba0f2Srobj 	if (rv != 0)
1096825ba0f2Srobj 		return (-1); /* *err is set for us */
1097825ba0f2Srobj 
1098825ba0f2Srobj 	return (0);
1099825ba0f2Srobj }
1100