xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c (revision 03100a6332bd4edc7a53091fcf7c9a7131bcdaa7)
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 2007 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 topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
403     const char *pname, nvlist_t *args,  nvlist_t **prop,
404     int *err)
405 {
406 	*prop = NULL;
407 
408 	return (fmri_prop(thp, nvl, pg, pname, args, prop, err));
409 }
410 
411 int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
412     nvlist_t *prop, int flag, nvlist_t *args, int *err)
413 {
414 	int rv;
415 	nvlist_t *in = NULL, *out = NULL;
416 	tnode_t *rnode;
417 	char *scheme;
418 
419 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0)
420 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
421 		    TOPO_METH_PROP_SET, in));
422 
423 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
424 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
425 		    TOPO_METH_PROP_SET, in));
426 
427 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
428 		return (set_error(thp, ETOPO_FMRI_NVL, err,
429 		    TOPO_METH_PROP_SET, in));
430 
431 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl);
432 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg);
433 	rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop);
434 	rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag);
435 	if (args != NULL)
436 		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
437 	if (rv != 0)
438 		return (set_error(thp, ETOPO_FMRI_NVL, err,
439 		    TOPO_METH_PROP_SET, in));
440 
441 	rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET,
442 	    TOPO_METH_PROP_SET_VERSION, in, &out, err);
443 
444 	nvlist_free(in);
445 
446 	/* no return values */
447 	if (out != NULL)
448 		nvlist_free(out);
449 
450 	if (rv)
451 		return (-1);
452 
453 	return (0);
454 
455 }
456 
457 int
458 topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
459     nvlist_t **pgroup, int *err)
460 {
461 	int rv;
462 	nvlist_t *in = NULL;
463 	tnode_t *rnode;
464 	char *scheme;
465 
466 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
467 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
468 		    TOPO_METH_PROP_GET, in));
469 
470 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
471 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
472 		    TOPO_METH_PROP_GET, in));
473 
474 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
475 		return (set_error(thp, ETOPO_FMRI_NVL, err,
476 		    TOPO_METH_PROP_GET, in));
477 
478 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
479 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
480 	if (rv != 0)
481 		return (set_error(thp, ETOPO_FMRI_NVL, err,
482 		    TOPO_METH_PROP_GET, in));
483 
484 	*pgroup = NULL;
485 	rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET,
486 	    TOPO_METH_PGRP_GET_VERSION, in, pgroup, err);
487 
488 	nvlist_free(in);
489 
490 	if (rv != 0)
491 		return (-1); /* *err is set for us */
492 
493 	if (*pgroup == NULL)
494 		return (set_error(thp, ETOPO_PROP_NOENT, err,
495 		    TOPO_METH_PROP_GET, NULL));
496 	return (0);
497 }
498 
499 int
500 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err)
501 {
502 	uint32_t compare;
503 	char *scheme1, *scheme2;
504 	nvlist_t *in;
505 	nvlist_t *out = NULL;
506 	tnode_t *rnode;
507 
508 	if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0)
509 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
510 		    TOPO_METH_COMPARE, NULL));
511 	if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0)
512 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
513 		    TOPO_METH_COMPARE, NULL));
514 
515 	if (strcmp(scheme1, scheme2) != 0)
516 		return (0);
517 
518 	if ((rnode = topo_hdl_root(thp, scheme1)) == NULL)
519 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
520 		    TOPO_METH_COMPARE, NULL));
521 
522 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
523 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
524 		    NULL));
525 
526 	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 ||
527 	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0)
528 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
529 		    in));
530 
531 	if (topo_method_invoke(rnode, TOPO_METH_COMPARE,
532 	    TOPO_METH_COMPARE_VERSION, in, &out, err) < 0)
533 		return (set_error(thp, *err, err, TOPO_METH_COMPARE, in));
534 
535 	(void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare);
536 	nvlist_free(out);
537 	nvlist_free(in);
538 
539 	return (compare);
540 }
541 
542 /*
543  * topo_fmri_create
544  *
545  *	If possible, creates an FMRI of the requested version in the
546  *	requested scheme.  Args are passed as part of the inputs to the
547  *	fmri-create method of the scheme.
548  */
549 nvlist_t *
550 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name,
551     topo_instance_t inst, nvlist_t *nvl, int *err)
552 {
553 	nvlist_t *ins;
554 	nvlist_t *out;
555 	tnode_t *rnode;
556 
557 	ins = out = NULL;
558 
559 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
560 		return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err,
561 		    TOPO_METH_FMRI, NULL));
562 
563 	if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0)
564 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
565 		    TOPO_METH_FMRI, NULL));
566 
567 	if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 ||
568 	    nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) {
569 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
570 		    TOPO_METH_FMRI, ins));
571 	}
572 
573 	if (nvl != NULL &&
574 	    nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) {
575 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
576 		    TOPO_METH_FMRI, ins));
577 	}
578 	if (topo_method_invoke(rnode,
579 	    TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) {
580 		return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins));
581 	}
582 	nvlist_free(ins);
583 	return (out);
584 }
585