xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c (revision e3d60c9bd991a9826cbfa63b10595d44e123b9c4)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <ctype.h>
30 #include <string.h>
31 #include <limits.h>
32 #include <fm/topo_mod.h>
33 #include <fm/fmd_fmri.h>
34 #include <sys/fm/protocol.h>
35 #include <topo_alloc.h>
36 #include <topo_error.h>
37 #include <topo_hc.h>
38 #include <topo_method.h>
39 #include <topo_subr.h>
40 #include <topo_string.h>
41 
42 /*
43  * Topology node properties and method operations may be accessed by FMRI.
44  * The FMRI used to perform property look-ups and method operations is
45  * the FMRI contained in the matching topology node's protocol property
46  * grouping for the resource property. The full range of fmd(1M)
47  * scheme plugin operations are supported as long as a backend method is
48  * supplied by a scheme-specific enumerator or the enumerator module that
49  * created the matching topology node.  Support for fmd scheme operations
50  * include:
51  *
52  *	- expand
53  *	- present
54  *	- replaced
55  *	- contains
56  *	- unusable
57  *	- service_state
58  *	- nvl2str
59  *
60  * In addition, the following operations are supported per-FMRI:
61  *
62  *	- str2nvl: convert string-based FMRI to nvlist
63  *	- compare: compare two FMRIs
64  *	- asru: lookup associated ASRU property by FMRI
65  *	- fru: lookup associated FRU by FMRI
66  *	- create: an FMRI nvlist by scheme type
67  *	- propery lookup
68  *
69  * These routines may only be called by consumers of a topology snapshot.
70  * They may not be called by libtopo enumerator or method modules.
71  */
72 
73 /*ARGSUSED*/
74 static int
75 set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp)
76 {
77 	if (nvlp != NULL)
78 		nvlist_free(nvlp);
79 
80 	topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method,
81 	    topo_strerror(err));
82 
83 	*errp = err;
84 	return (-1);
85 }
86 
87 /*ARGSUSED*/
88 static nvlist_t *
89 set_nverror(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp)
90 {
91 	if (nvlp != NULL)
92 		nvlist_free(nvlp);
93 
94 	topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method,
95 	    topo_strerror(err));
96 
97 	*errp = err;
98 	return (NULL);
99 }
100 
101 int
102 topo_fmri_nvl2str(topo_hdl_t *thp, nvlist_t *fmri, char **fmristr, int *err)
103 {
104 	char *scheme, *str;
105 	nvlist_t *out = NULL;
106 	tnode_t *rnode;
107 
108 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
109 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
110 		    TOPO_METH_NVL2STR, out));
111 
112 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
113 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
114 		    TOPO_METH_NVL2STR, out));
115 
116 	if (topo_method_invoke(rnode, TOPO_METH_NVL2STR,
117 	    TOPO_METH_NVL2STR_VERSION, fmri, &out, err) != 0)
118 		return (set_error(thp, *err, err, TOPO_METH_NVL2STR, out));
119 
120 	if (out == NULL || nvlist_lookup_string(out, "fmri-string", &str) != 0)
121 		return (set_error(thp, ETOPO_METHOD_INVAL, err,
122 		    TOPO_METH_NVL2STR, out));
123 
124 	if ((*fmristr = topo_hdl_strdup(thp, str)) == NULL)
125 		return (set_error(thp, ETOPO_NOMEM, err,
126 		    TOPO_METH_NVL2STR, out));
127 
128 	nvlist_free(out);
129 
130 	return (0);
131 }
132 
133 int
134 topo_fmri_str2nvl(topo_hdl_t *thp, const char *fmristr, nvlist_t **fmri,
135     int *err)
136 {
137 	char *f, buf[PATH_MAX];
138 	nvlist_t *out = NULL, *in = NULL;
139 	tnode_t *rnode;
140 
141 	(void) strlcpy(buf, fmristr, sizeof (buf));
142 	if ((f = strchr(buf, ':')) == NULL)
143 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
144 		    TOPO_METH_STR2NVL, in));
145 
146 	*f = '\0'; /* strip trailing FMRI path */
147 
148 	if ((rnode = topo_hdl_root(thp, buf)) == NULL)
149 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
150 		    TOPO_METH_STR2NVL, in));
151 
152 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
153 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL,
154 		    in));
155 
156 	if (nvlist_add_string(in, "fmri-string", fmristr) != 0)
157 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL,
158 		    in));
159 
160 	if (topo_method_invoke(rnode, TOPO_METH_STR2NVL,
161 	    TOPO_METH_STR2NVL_VERSION, in, &out, err) != 0)
162 		return (set_error(thp, *err, err, TOPO_METH_STR2NVL, in));
163 
164 	nvlist_free(in);
165 
166 	if (out == NULL ||
167 	    topo_hdl_nvdup(thp, out, fmri) != 0)
168 		return (set_error(thp, ETOPO_FMRI_NVL, err,
169 		    TOPO_METH_STR2NVL, out));
170 
171 	nvlist_free(out);
172 
173 	return (0);
174 }
175 
176 int
177 topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err)
178 {
179 	uint32_t present = 0;
180 	char *scheme;
181 	nvlist_t *out = NULL;
182 	tnode_t *rnode;
183 
184 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
185 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
186 		    TOPO_METH_PRESENT, out));
187 
188 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
189 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
190 		    TOPO_METH_PRESENT, out));
191 
192 	if (topo_method_invoke(rnode, TOPO_METH_PRESENT,
193 	    TOPO_METH_PRESENT_VERSION, fmri, &out, err) < 0) {
194 		(void) set_error(thp, *err, err, TOPO_METH_PRESENT, out);
195 		return (present);
196 	}
197 
198 	(void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present);
199 	nvlist_free(out);
200 
201 	return (present);
202 }
203 
204 int
205 topo_fmri_replaced(topo_hdl_t *thp, nvlist_t *fmri, int *err)
206 {
207 	uint32_t replaced = FMD_OBJ_STATE_NOT_PRESENT;
208 	char *scheme;
209 	nvlist_t *out = NULL;
210 	tnode_t *rnode;
211 
212 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
213 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
214 		    TOPO_METH_REPLACED, out));
215 
216 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
217 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
218 		    TOPO_METH_REPLACED, out));
219 
220 	if (topo_method_invoke(rnode, TOPO_METH_REPLACED,
221 	    TOPO_METH_REPLACED_VERSION, fmri, &out, err) < 0) {
222 		(void) set_error(thp, *err, err, TOPO_METH_REPLACED, out);
223 		return (FMD_OBJ_STATE_UNKNOWN);
224 	}
225 
226 	(void) nvlist_lookup_uint32(out, TOPO_METH_REPLACED_RET, &replaced);
227 	nvlist_free(out);
228 
229 	return (replaced);
230 }
231 
232 int
233 topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err)
234 {
235 	uint32_t contains;
236 	char *scheme;
237 	nvlist_t *in = NULL, *out = NULL;
238 	tnode_t *rnode;
239 
240 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
241 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
242 		    TOPO_METH_CONTAINS, NULL));
243 
244 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
245 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
246 		    TOPO_METH_CONTAINS, NULL));
247 
248 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
249 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
250 		    NULL));
251 
252 	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 ||
253 	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0)
254 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
255 		    in));
256 
257 	if (topo_hdl_nvalloc(thp, &out, NV_UNIQUE_NAME) != 0)
258 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
259 		    out));
260 
261 	if (topo_method_invoke(rnode, TOPO_METH_CONTAINS,
262 	    TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0) {
263 		nvlist_free(out);
264 		return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in));
265 	}
266 
267 	(void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains);
268 	nvlist_free(in);
269 	nvlist_free(out);
270 
271 	return (contains);
272 }
273 
274 int
275 topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err)
276 {
277 	char *scheme;
278 	uint32_t unusable = 0;
279 	nvlist_t *out = NULL;
280 	tnode_t *rnode;
281 
282 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
283 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
284 		    TOPO_METH_UNUSABLE, out));
285 
286 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
287 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
288 		    TOPO_METH_UNUSABLE, out));
289 
290 	if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE,
291 	    TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0)
292 		return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out));
293 
294 	(void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable);
295 	nvlist_free(out);
296 
297 	return (unusable);
298 }
299 
300 int
301 topo_fmri_service_state(topo_hdl_t *thp, nvlist_t *fmri, int *err)
302 {
303 	char *scheme;
304 	uint32_t service_state = FMD_SERVICE_STATE_UNKNOWN;
305 	nvlist_t *out = NULL;
306 	tnode_t *rnode;
307 
308 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
309 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
310 		    TOPO_METH_SERVICE_STATE, out));
311 
312 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
313 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
314 		    TOPO_METH_SERVICE_STATE, out));
315 
316 	if (topo_method_invoke(rnode, TOPO_METH_SERVICE_STATE,
317 	    TOPO_METH_SERVICE_STATE_VERSION, fmri, &out, err) < 0)
318 		return (set_error(thp, *err, err, TOPO_METH_SERVICE_STATE,
319 		    out));
320 
321 	(void) nvlist_lookup_uint32(out, TOPO_METH_SERVICE_STATE_RET,
322 	    &service_state);
323 	nvlist_free(out);
324 
325 	return (service_state);
326 }
327 
328 int
329 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err)
330 {
331 	char *scheme;
332 	nvlist_t *out = NULL;
333 	tnode_t *rnode;
334 
335 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
336 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
337 		    TOPO_METH_EXPAND, out));
338 
339 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
340 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
341 		    TOPO_METH_EXPAND, out));
342 
343 	if (topo_method_invoke(rnode, TOPO_METH_EXPAND,
344 	    TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0)
345 		return (set_error(thp, *err, err, TOPO_METH_EXPAND, out));
346 
347 	return (0);
348 }
349 
350 static int
351 fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
352     const char *pname, nvlist_t *args, nvlist_t **prop,
353     int *err)
354 {
355 	int rv;
356 	nvlist_t *in = NULL;
357 	tnode_t *rnode;
358 	char *scheme;
359 
360 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
361 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
362 		    TOPO_METH_PROP_GET, in));
363 
364 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
365 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
366 		    TOPO_METH_PROP_GET, in));
367 
368 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
369 		return (set_error(thp, ETOPO_FMRI_NVL, err,
370 		    TOPO_METH_PROP_GET, in));
371 
372 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
373 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
374 	rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname);
375 	if (args != NULL)
376 		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
377 	if (rv != 0)
378 		return (set_error(thp, ETOPO_FMRI_NVL, err,
379 		    TOPO_METH_PROP_GET, in));
380 
381 	*prop = NULL;
382 	rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET,
383 	    TOPO_METH_PROP_GET_VERSION, in, prop, err);
384 
385 	nvlist_free(in);
386 
387 	if (rv != 0)
388 		return (-1); /* *err is set for us */
389 
390 	if (*prop == NULL)
391 		return (set_error(thp, ETOPO_PROP_NOENT, err,
392 		    TOPO_METH_PROP_GET, NULL));
393 	return (0);
394 }
395 
396 int
397 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err)
398 {
399 	nvlist_t *ap, *prop = NULL;
400 
401 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU,
402 	    nvl, &prop, err) < 0)
403 		return (set_error(thp, *err, err, "topo_fmri_asru", NULL));
404 
405 	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0)
406 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru",
407 		    prop));
408 
409 	if (topo_hdl_nvdup(thp, ap, asru) < 0)
410 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru",
411 		    prop));
412 
413 	nvlist_free(prop);
414 
415 	return (0);
416 }
417 
418 int
419 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err)
420 {
421 	nvlist_t *fp, *prop = NULL;
422 
423 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU,
424 	    nvl, &prop, err) < 0)
425 		return (set_error(thp, *err, err, "topo_fmri_fru", NULL));
426 
427 	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0)
428 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru",
429 		    prop));
430 
431 	if (topo_hdl_nvdup(thp, fp, fru) < 0)
432 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru",
433 		    prop));
434 
435 	nvlist_free(prop);
436 
437 	return (0);
438 }
439 
440 int
441 topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err)
442 {
443 	nvlist_t *prop = NULL;
444 	char *lp;
445 
446 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL,
447 	    NULL, &prop, err) < 0)
448 		return (set_error(thp, *err, err, "topo_fmri_label", NULL));
449 
450 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0)
451 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label",
452 		    prop));
453 
454 	if ((*label = topo_hdl_strdup(thp, lp)) == NULL)
455 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label",
456 		    prop));
457 
458 	nvlist_free(prop);
459 
460 	return (0);
461 }
462 
463 int
464 topo_fmri_serial(topo_hdl_t *thp, nvlist_t *nvl, char **serial, int *err)
465 {
466 	nvlist_t *prop = NULL;
467 	char *sp;
468 
469 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, FM_FMRI_HC_SERIAL_ID,
470 	    NULL, &prop, err) < 0)
471 		return (set_error(thp, *err, err, "topo_fmri_serial", NULL));
472 
473 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &sp) != 0)
474 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_serial",
475 		    prop));
476 
477 	if ((*serial = topo_hdl_strdup(thp, sp)) == NULL)
478 		return (set_error(thp, ETOPO_PROP_NOMEM, err,
479 		    "topo_fmri_serial", prop));
480 
481 	nvlist_free(prop);
482 
483 	return (0);
484 }
485 
486 int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
487     const char *pname, nvlist_t *args,  nvlist_t **prop,
488     int *err)
489 {
490 	*prop = NULL;
491 
492 	return (fmri_prop(thp, nvl, pg, pname, args, prop, err));
493 }
494 
495 int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
496     nvlist_t *prop, int flag, nvlist_t *args, int *err)
497 {
498 	int rv;
499 	nvlist_t *in = NULL, *out = NULL;
500 	tnode_t *rnode;
501 	char *scheme;
502 
503 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0)
504 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
505 		    TOPO_METH_PROP_SET, in));
506 
507 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
508 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
509 		    TOPO_METH_PROP_SET, in));
510 
511 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
512 		return (set_error(thp, ETOPO_FMRI_NVL, err,
513 		    TOPO_METH_PROP_SET, in));
514 
515 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl);
516 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg);
517 	rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop);
518 	rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag);
519 	if (args != NULL)
520 		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
521 	if (rv != 0)
522 		return (set_error(thp, ETOPO_FMRI_NVL, err,
523 		    TOPO_METH_PROP_SET, in));
524 
525 	rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET,
526 	    TOPO_METH_PROP_SET_VERSION, in, &out, err);
527 
528 	nvlist_free(in);
529 
530 	/* no return values */
531 	if (out != NULL)
532 		nvlist_free(out);
533 
534 	if (rv)
535 		return (-1);
536 
537 	return (0);
538 
539 }
540 
541 int
542 topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
543     nvlist_t **pgroup, int *err)
544 {
545 	int rv;
546 	nvlist_t *in = NULL;
547 	tnode_t *rnode;
548 	char *scheme;
549 
550 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
551 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
552 		    TOPO_METH_PROP_GET, in));
553 
554 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
555 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
556 		    TOPO_METH_PROP_GET, in));
557 
558 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
559 		return (set_error(thp, ETOPO_FMRI_NVL, err,
560 		    TOPO_METH_PROP_GET, in));
561 
562 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
563 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
564 	if (rv != 0)
565 		return (set_error(thp, ETOPO_FMRI_NVL, err,
566 		    TOPO_METH_PROP_GET, in));
567 
568 	*pgroup = NULL;
569 	rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET,
570 	    TOPO_METH_PGRP_GET_VERSION, in, pgroup, err);
571 
572 	nvlist_free(in);
573 
574 	if (rv != 0)
575 		return (-1); /* *err is set for us */
576 
577 	if (*pgroup == NULL)
578 		return (set_error(thp, ETOPO_PROP_NOENT, err,
579 		    TOPO_METH_PROP_GET, NULL));
580 	return (0);
581 }
582 
583 int
584 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err)
585 {
586 	uint32_t compare;
587 	char *scheme1, *scheme2;
588 	nvlist_t *in;
589 	nvlist_t *out = NULL;
590 	tnode_t *rnode;
591 
592 	if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0)
593 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
594 		    TOPO_METH_COMPARE, NULL));
595 	if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0)
596 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
597 		    TOPO_METH_COMPARE, NULL));
598 
599 	if (strcmp(scheme1, scheme2) != 0)
600 		return (0);
601 
602 	if ((rnode = topo_hdl_root(thp, scheme1)) == NULL)
603 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
604 		    TOPO_METH_COMPARE, NULL));
605 
606 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
607 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
608 		    NULL));
609 
610 	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 ||
611 	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0)
612 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
613 		    in));
614 
615 	if (topo_method_invoke(rnode, TOPO_METH_COMPARE,
616 	    TOPO_METH_COMPARE_VERSION, in, &out, err) < 0)
617 		return (set_error(thp, *err, err, TOPO_METH_COMPARE, in));
618 
619 	(void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare);
620 	nvlist_free(out);
621 	nvlist_free(in);
622 
623 	return (compare);
624 }
625 
626 /*
627  * topo_fmri_create
628  *
629  *	If possible, creates an FMRI of the requested version in the
630  *	requested scheme.  Args are passed as part of the inputs to the
631  *	fmri-create method of the scheme.
632  */
633 nvlist_t *
634 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name,
635     topo_instance_t inst, nvlist_t *nvl, int *err)
636 {
637 	nvlist_t *ins;
638 	nvlist_t *out;
639 	tnode_t *rnode;
640 
641 	ins = out = NULL;
642 
643 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
644 		return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err,
645 		    TOPO_METH_FMRI, NULL));
646 
647 	if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0)
648 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
649 		    TOPO_METH_FMRI, NULL));
650 
651 	if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 ||
652 	    nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) {
653 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
654 		    TOPO_METH_FMRI, ins));
655 	}
656 
657 	if (nvl != NULL &&
658 	    nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) {
659 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
660 		    TOPO_METH_FMRI, ins));
661 	}
662 	if (topo_method_invoke(rnode,
663 	    TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) {
664 		return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins));
665 	}
666 	nvlist_free(ins);
667 	return (out);
668 }
669 
670 /*
671  * These private utility functions are used by fmd to maintain its resource
672  * cache.  Because hc instance numbers are not guaranteed, it's possible to
673  * have two different FMRI strings represent the same logical entity.  These
674  * functions hide this implementation detail from unknowing consumers such as
675  * fmd.
676  *
677  * Ideally, we'd like to do a str2nvl() and then a full FMRI hash and
678  * comparison, but these functions are designed to be fast and efficient.
679  * Given that there is only a single hc node that has this property
680  * (ses-enclosure), we hard-code this behavior here.  If there are more
681  * instances of this behavior in the future, this function could be made more
682  * generic.
683  */
684 static ulong_t
685 topo_fmri_strhash_one(const char *fmri, size_t len)
686 {
687 	ulong_t g, h = 0;
688 	size_t i;
689 
690 	for (i = 0; i < len; i++) {
691 		h = (h << 4) + fmri[i];
692 
693 		if ((g = (h & 0xf0000000)) != 0) {
694 			h ^= (g >> 24);
695 			h ^= g;
696 		}
697 	}
698 
699 	return (h);
700 }
701 
702 /*ARGSUSED*/
703 ulong_t
704 topo_fmri_strhash(topo_hdl_t *thp, const char *fmri)
705 {
706 	char *e;
707 	ulong_t h;
708 
709 	if (strncmp(fmri, "hc://", 5) != 0 ||
710 	    (e = strstr(fmri, SES_ENCLOSURE)) == NULL)
711 		return (topo_fmri_strhash_one(fmri, strlen(fmri)));
712 
713 	h = topo_fmri_strhash_one(fmri, e - fmri);
714 	e += sizeof (SES_ENCLOSURE);
715 
716 	while (isdigit(*e))
717 		e++;
718 
719 	h += topo_fmri_strhash_one(e, strlen(e));
720 
721 	return (h);
722 }
723 
724 /*ARGSUSED*/
725 boolean_t
726 topo_fmri_strcmp(topo_hdl_t *thp, const char *a, const char *b)
727 {
728 	char *ea, *eb;
729 
730 	if (strncmp(a, "hc://", 5) != 0 ||
731 	    strncmp(b, "hc://", 5) != 0 ||
732 	    (ea = strstr(a, SES_ENCLOSURE)) == NULL ||
733 	    (eb = strstr(b, SES_ENCLOSURE)) == NULL)
734 		return (strcmp(a, b) == 0);
735 
736 	if ((ea - a) != (eb - b))
737 		return (B_FALSE);
738 
739 	if (strncmp(a, b, ea - a) != 0)
740 		return (B_FALSE);
741 
742 	ea += sizeof (SES_ENCLOSURE);
743 	eb += sizeof (SES_ENCLOSURE);
744 
745 	while (isdigit(*ea))
746 		ea++;
747 	while (isdigit(*eb))
748 		eb++;
749 
750 	return (strcmp(ea, eb) == 0);
751 }
752 
753 int
754 topo_fmri_facility(topo_hdl_t *thp, nvlist_t *rsrc, const char *fac_type,
755     uint32_t fac_subtype, topo_walk_cb_t cb, void *cb_args, int *err)
756 {
757 	int rv;
758 	nvlist_t *in = NULL, *out;
759 	tnode_t *rnode;
760 	char *scheme;
761 
762 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
763 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
764 		    TOPO_METH_PROP_GET, in));
765 
766 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
767 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
768 		    TOPO_METH_PROP_GET, in));
769 
770 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
771 		return (set_error(thp, ETOPO_FMRI_NVL, err,
772 		    TOPO_METH_PROP_GET, in));
773 
774 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
775 	rv |= nvlist_add_string(in, FM_FMRI_FACILITY_TYPE, fac_type);
776 	rv |= nvlist_add_uint32(in, "type", fac_subtype);
777 #ifdef _LP64
778 	rv |= nvlist_add_uint64(in, "callback", (uint64_t)cb);
779 	rv |= nvlist_add_uint64(in, "callback-args", (uint64_t)cb_args);
780 #else
781 	rv |= nvlist_add_uint32(in, "callback", (uint32_t)cb);
782 	rv |= nvlist_add_uint32(in, "callback-args", (uint32_t)cb_args);
783 #endif
784 	if (rv != 0)
785 		return (set_error(thp, ETOPO_FMRI_NVL, err,
786 		    TOPO_METH_PROP_GET, in));
787 
788 	rv = topo_method_invoke(rnode, TOPO_METH_FACILITY,
789 	    TOPO_METH_FACILITY_VERSION, in, &out, err);
790 
791 	nvlist_free(in);
792 
793 	if (rv != 0)
794 		return (-1); /* *err is set for us */
795 
796 	return (0);
797 }
798