xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c (revision e7cbe64f7a72dae5cb44f100db60ca88f3313c65)
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 <string.h>
30 #include <limits.h>
31 #include <fm/topo_mod.h>
32 #include <sys/fm/protocol.h>
33 #include <topo_alloc.h>
34 #include <topo_error.h>
35 #include <topo_method.h>
36 #include <topo_subr.h>
37 #include <topo_string.h>
38 
39 /*
40  * Topology node properties and method operations may be accessed by FMRI.
41  * The FMRI used to perform property look-ups and method operations is
42  * the FMRI contained in the matching topology node's protocol property
43  * grouping for the resource property. The full range of fmd(1M)
44  * scheme plugin operations are supported as long as a backend method is
45  * supplied by a scheme-specific enumerator or the enumerator module that
46  * created the matching topology node.  Support for fmd scheme operations
47  * include:
48  *
49  *	- expand
50  *	- present
51  *	- contains
52  *	- unusable
53  *	- nvl2str
54  *
55  * In addition, the following operations are supported per-FMRI:
56  *
57  *	- str2nvl: convert string-based FMRI to nvlist
58  *	- compare: compare two FMRIs
59  *	- asru: lookup associated ASRU property by FMRI
60  *	- fru: lookup associated FRU by FMRI
61  *	- create: an FMRI nvlist by scheme type
62  *	- propery lookup
63  *
64  * These routines may only be called by consumers of a topology snapshot.
65  * They may not be called by libtopo enumerator or method modules.
66  */
67 
68 /*ARGSUSED*/
69 static int
70 set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp)
71 {
72 	if (nvlp != NULL)
73 		nvlist_free(nvlp);
74 
75 	topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method,
76 	    topo_strerror(err));
77 
78 	*errp = err;
79 	return (-1);
80 }
81 
82 /*ARGSUSED*/
83 static nvlist_t *
84 set_nverror(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp)
85 {
86 	if (nvlp != NULL)
87 		nvlist_free(nvlp);
88 
89 	topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method,
90 	    topo_strerror(err));
91 
92 	*errp = err;
93 	return (NULL);
94 }
95 
96 int
97 topo_fmri_nvl2str(topo_hdl_t *thp, nvlist_t *fmri, char **fmristr, int *err)
98 {
99 	char *scheme, *str;
100 	nvlist_t *out = NULL;
101 	tnode_t *rnode;
102 
103 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
104 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
105 		    TOPO_METH_NVL2STR, out));
106 
107 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
108 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
109 		    TOPO_METH_NVL2STR, out));
110 
111 	if (topo_method_invoke(rnode, TOPO_METH_NVL2STR,
112 	    TOPO_METH_NVL2STR_VERSION, fmri, &out, err) != 0)
113 		return (set_error(thp, *err, err, TOPO_METH_NVL2STR, out));
114 
115 	if (out == NULL || nvlist_lookup_string(out, "fmri-string", &str) != 0)
116 		return (set_error(thp, ETOPO_METHOD_INVAL, err,
117 		    TOPO_METH_NVL2STR, out));
118 
119 	if ((*fmristr = topo_hdl_strdup(thp, str)) == NULL)
120 		return (set_error(thp, ETOPO_NOMEM, err,
121 		    TOPO_METH_NVL2STR, out));
122 
123 	nvlist_free(out);
124 
125 	return (0);
126 }
127 
128 int
129 topo_fmri_str2nvl(topo_hdl_t *thp, const char *fmristr, nvlist_t **fmri,
130     int *err)
131 {
132 	char *f, buf[PATH_MAX];
133 	nvlist_t *out = NULL, *in = NULL;
134 	tnode_t *rnode;
135 
136 	(void) strlcpy(buf, fmristr, sizeof (buf));
137 	if ((f = strchr(buf, ':')) == NULL)
138 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
139 		    TOPO_METH_STR2NVL, in));
140 
141 	*f = '\0'; /* strip trailing FMRI path */
142 
143 	if ((rnode = topo_hdl_root(thp, buf)) == NULL)
144 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
145 		    TOPO_METH_STR2NVL, in));
146 
147 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
148 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL,
149 		    in));
150 
151 	if (nvlist_add_string(in, "fmri-string", fmristr) != 0)
152 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL,
153 		    in));
154 
155 	if (topo_method_invoke(rnode, TOPO_METH_STR2NVL,
156 	    TOPO_METH_STR2NVL_VERSION, in, &out, err) != 0)
157 		return (set_error(thp, *err, err, TOPO_METH_STR2NVL, in));
158 
159 	nvlist_free(in);
160 
161 	if (out == NULL ||
162 	    topo_hdl_nvdup(thp, out, fmri) != 0)
163 		return (set_error(thp, ETOPO_FMRI_NVL, err,
164 		    TOPO_METH_STR2NVL, out));
165 
166 	nvlist_free(out);
167 
168 	return (0);
169 }
170 
171 int
172 topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err)
173 {
174 	uint32_t present = 0;
175 	char *scheme;
176 	nvlist_t *out = NULL;
177 	tnode_t *rnode;
178 
179 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
180 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
181 		    TOPO_METH_PRESENT, out));
182 
183 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
184 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
185 		    TOPO_METH_PRESENT, out));
186 
187 	if (topo_method_invoke(rnode, TOPO_METH_PRESENT,
188 	    TOPO_METH_PRESENT_VERSION, fmri, &out, err) < 0) {
189 		(void) set_error(thp, *err, err, TOPO_METH_PRESENT, out);
190 		return (present);
191 	}
192 
193 	(void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present);
194 	nvlist_free(out);
195 
196 	return (present);
197 }
198 
199 int
200 topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err)
201 {
202 	uint32_t contains;
203 	char *scheme;
204 	nvlist_t *in = NULL, *out = NULL;
205 	tnode_t *rnode;
206 
207 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
208 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
209 		    TOPO_METH_CONTAINS, NULL));
210 
211 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
212 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
213 		    TOPO_METH_CONTAINS, NULL));
214 
215 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
216 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
217 		    NULL));
218 
219 	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 ||
220 	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0)
221 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
222 		    in));
223 
224 	if (topo_hdl_nvalloc(thp, &out, NV_UNIQUE_NAME) != 0)
225 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
226 		    out));
227 
228 	if (topo_method_invoke(rnode, TOPO_METH_CONTAINS,
229 	    TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0) {
230 		nvlist_free(out);
231 		return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in));
232 	}
233 
234 	(void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains);
235 	nvlist_free(in);
236 	nvlist_free(out);
237 
238 	return (contains);
239 }
240 
241 int
242 topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err)
243 {
244 	char *scheme;
245 	uint32_t unusable = 0;
246 	nvlist_t *out = NULL;
247 	tnode_t *rnode;
248 
249 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
250 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
251 		    TOPO_METH_UNUSABLE, out));
252 
253 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
254 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
255 		    TOPO_METH_UNUSABLE, out));
256 
257 	if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE,
258 	    TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0)
259 		return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out));
260 
261 	(void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable);
262 	nvlist_free(out);
263 
264 	return (unusable);
265 }
266 
267 int
268 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err)
269 {
270 	char *scheme;
271 	nvlist_t *out = NULL;
272 	tnode_t *rnode;
273 
274 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
275 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
276 		    TOPO_METH_EXPAND, out));
277 
278 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
279 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
280 		    TOPO_METH_EXPAND, out));
281 
282 	if (topo_method_invoke(rnode, TOPO_METH_EXPAND,
283 	    TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0)
284 		return (set_error(thp, *err, err, TOPO_METH_EXPAND, out));
285 
286 	return (0);
287 }
288 
289 static int
290 fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
291     const char *pname, nvlist_t *args, nvlist_t **prop,
292     int *err)
293 {
294 	int rv;
295 	nvlist_t *in = NULL;
296 	tnode_t *rnode;
297 	char *scheme;
298 
299 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
300 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
301 		    TOPO_METH_PROP_GET, in));
302 
303 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
304 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
305 		    TOPO_METH_PROP_GET, in));
306 
307 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
308 		return (set_error(thp, ETOPO_FMRI_NVL, err,
309 		    TOPO_METH_PROP_GET, in));
310 
311 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
312 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
313 	rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname);
314 	if (args != NULL)
315 		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
316 	if (rv != 0)
317 		return (set_error(thp, ETOPO_FMRI_NVL, err,
318 		    TOPO_METH_PROP_GET, in));
319 
320 	*prop = NULL;
321 	rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET,
322 	    TOPO_METH_PROP_GET_VERSION, in, prop, err);
323 
324 	nvlist_free(in);
325 
326 	if (rv != 0)
327 		return (-1); /* *err is set for us */
328 
329 	if (*prop == NULL)
330 		return (set_error(thp, ETOPO_PROP_NOENT, err,
331 		    TOPO_METH_PROP_GET, NULL));
332 	return (0);
333 }
334 
335 int
336 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err)
337 {
338 	nvlist_t *ap, *prop = NULL;
339 
340 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU,
341 	    nvl, &prop, err) < 0)
342 		return (set_error(thp, *err, err, "topo_fmri_asru", NULL));
343 
344 	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0)
345 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru",
346 		    prop));
347 
348 	if (topo_hdl_nvdup(thp, ap, asru) < 0)
349 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru",
350 		    prop));
351 
352 	nvlist_free(prop);
353 
354 	return (0);
355 }
356 
357 int
358 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err)
359 {
360 	nvlist_t *fp, *prop = NULL;
361 
362 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU,
363 	    nvl, &prop, err) < 0)
364 		return (set_error(thp, *err, err, "topo_fmri_fru", NULL));
365 
366 	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0)
367 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru",
368 		    prop));
369 
370 	if (topo_hdl_nvdup(thp, fp, fru) < 0)
371 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru",
372 		    prop));
373 
374 	nvlist_free(prop);
375 
376 	return (0);
377 }
378 
379 int
380 topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err)
381 {
382 	nvlist_t *prop = NULL;
383 	char *lp;
384 
385 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL,
386 	    NULL, &prop, err) < 0)
387 		return (set_error(thp, *err, err, "topo_fmri_label", NULL));
388 
389 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0)
390 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label",
391 		    prop));
392 
393 	if ((*label = topo_hdl_strdup(thp, lp)) == NULL)
394 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label",
395 		    prop));
396 
397 	nvlist_free(prop);
398 
399 	return (0);
400 }
401 
402 int
403 topo_fmri_serial(topo_hdl_t *thp, nvlist_t *nvl, char **serial, int *err)
404 {
405 	nvlist_t *prop = NULL;
406 	char *sp;
407 
408 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, FM_FMRI_HC_SERIAL_ID,
409 	    NULL, &prop, err) < 0)
410 		return (set_error(thp, *err, err, "topo_fmri_serial", NULL));
411 
412 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &sp) != 0)
413 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_serial",
414 		    prop));
415 
416 	if ((*serial = topo_hdl_strdup(thp, sp)) == NULL)
417 		return (set_error(thp, ETOPO_PROP_NOMEM, err,
418 		    "topo_fmri_serial", prop));
419 
420 	nvlist_free(prop);
421 
422 	return (0);
423 }
424 
425 int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
426     const char *pname, nvlist_t *args,  nvlist_t **prop,
427     int *err)
428 {
429 	*prop = NULL;
430 
431 	return (fmri_prop(thp, nvl, pg, pname, args, prop, err));
432 }
433 
434 int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
435     nvlist_t *prop, int flag, nvlist_t *args, int *err)
436 {
437 	int rv;
438 	nvlist_t *in = NULL, *out = NULL;
439 	tnode_t *rnode;
440 	char *scheme;
441 
442 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0)
443 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
444 		    TOPO_METH_PROP_SET, in));
445 
446 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
447 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
448 		    TOPO_METH_PROP_SET, in));
449 
450 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
451 		return (set_error(thp, ETOPO_FMRI_NVL, err,
452 		    TOPO_METH_PROP_SET, in));
453 
454 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl);
455 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg);
456 	rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop);
457 	rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag);
458 	if (args != NULL)
459 		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
460 	if (rv != 0)
461 		return (set_error(thp, ETOPO_FMRI_NVL, err,
462 		    TOPO_METH_PROP_SET, in));
463 
464 	rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET,
465 	    TOPO_METH_PROP_SET_VERSION, in, &out, err);
466 
467 	nvlist_free(in);
468 
469 	/* no return values */
470 	if (out != NULL)
471 		nvlist_free(out);
472 
473 	if (rv)
474 		return (-1);
475 
476 	return (0);
477 
478 }
479 
480 int
481 topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
482     nvlist_t **pgroup, int *err)
483 {
484 	int rv;
485 	nvlist_t *in = NULL;
486 	tnode_t *rnode;
487 	char *scheme;
488 
489 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
490 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
491 		    TOPO_METH_PROP_GET, in));
492 
493 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
494 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
495 		    TOPO_METH_PROP_GET, in));
496 
497 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
498 		return (set_error(thp, ETOPO_FMRI_NVL, err,
499 		    TOPO_METH_PROP_GET, in));
500 
501 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
502 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
503 	if (rv != 0)
504 		return (set_error(thp, ETOPO_FMRI_NVL, err,
505 		    TOPO_METH_PROP_GET, in));
506 
507 	*pgroup = NULL;
508 	rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET,
509 	    TOPO_METH_PGRP_GET_VERSION, in, pgroup, err);
510 
511 	nvlist_free(in);
512 
513 	if (rv != 0)
514 		return (-1); /* *err is set for us */
515 
516 	if (*pgroup == NULL)
517 		return (set_error(thp, ETOPO_PROP_NOENT, err,
518 		    TOPO_METH_PROP_GET, NULL));
519 	return (0);
520 }
521 
522 int
523 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err)
524 {
525 	uint32_t compare;
526 	char *scheme1, *scheme2;
527 	nvlist_t *in;
528 	nvlist_t *out = NULL;
529 	tnode_t *rnode;
530 
531 	if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0)
532 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
533 		    TOPO_METH_COMPARE, NULL));
534 	if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0)
535 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
536 		    TOPO_METH_COMPARE, NULL));
537 
538 	if (strcmp(scheme1, scheme2) != 0)
539 		return (0);
540 
541 	if ((rnode = topo_hdl_root(thp, scheme1)) == NULL)
542 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
543 		    TOPO_METH_COMPARE, NULL));
544 
545 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
546 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
547 		    NULL));
548 
549 	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 ||
550 	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0)
551 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
552 		    in));
553 
554 	if (topo_method_invoke(rnode, TOPO_METH_COMPARE,
555 	    TOPO_METH_COMPARE_VERSION, in, &out, err) < 0)
556 		return (set_error(thp, *err, err, TOPO_METH_COMPARE, in));
557 
558 	(void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare);
559 	nvlist_free(out);
560 	nvlist_free(in);
561 
562 	return (compare);
563 }
564 
565 /*
566  * topo_fmri_create
567  *
568  *	If possible, creates an FMRI of the requested version in the
569  *	requested scheme.  Args are passed as part of the inputs to the
570  *	fmri-create method of the scheme.
571  */
572 nvlist_t *
573 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name,
574     topo_instance_t inst, nvlist_t *nvl, int *err)
575 {
576 	nvlist_t *ins;
577 	nvlist_t *out;
578 	tnode_t *rnode;
579 
580 	ins = out = NULL;
581 
582 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
583 		return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err,
584 		    TOPO_METH_FMRI, NULL));
585 
586 	if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0)
587 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
588 		    TOPO_METH_FMRI, NULL));
589 
590 	if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 ||
591 	    nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) {
592 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
593 		    TOPO_METH_FMRI, ins));
594 	}
595 
596 	if (nvl != NULL &&
597 	    nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) {
598 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
599 		    TOPO_METH_FMRI, ins));
600 	}
601 	if (topo_method_invoke(rnode,
602 	    TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) {
603 		return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins));
604 	}
605 	nvlist_free(ins);
606 	return (out);
607 }
608