xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c (revision f48205be61a214698b763ff550ab9e657525104c)
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 	if (out == NULL ||
160 	    topo_hdl_nvdup(thp, out, fmri) != 0)
161 		return (set_error(thp, ETOPO_FMRI_NVL, err,
162 		    TOPO_METH_STR2NVL, in));
163 
164 	nvlist_free(out);
165 	nvlist_free(in);
166 
167 	return (0);
168 }
169 
170 int
171 topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err)
172 {
173 	uint32_t present = 0;
174 	char *scheme;
175 	nvlist_t *out = NULL;
176 	tnode_t *rnode;
177 
178 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
179 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
180 		    TOPO_METH_PRESENT, out));
181 
182 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
183 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
184 		    TOPO_METH_PRESENT, out));
185 
186 	if (topo_method_invoke(rnode, TOPO_METH_PRESENT,
187 	    TOPO_METH_PRESENT_VERSION, fmri, &out, err) < 0) {
188 		(void) set_error(thp, *err, err, TOPO_METH_PRESENT, out);
189 		return (present);
190 	}
191 
192 	(void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present);
193 	nvlist_free(out);
194 
195 	return (present);
196 }
197 
198 int
199 topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err)
200 {
201 	uint32_t contains;
202 	char *scheme;
203 	nvlist_t *in = NULL, *out = NULL;
204 	tnode_t *rnode;
205 
206 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
207 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
208 		    TOPO_METH_CONTAINS, NULL));
209 
210 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
211 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
212 		    TOPO_METH_CONTAINS, NULL));
213 
214 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
215 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
216 		    NULL));
217 
218 	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 ||
219 	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0)
220 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
221 		    in));
222 
223 	if (topo_hdl_nvalloc(thp, &out, NV_UNIQUE_NAME) != 0)
224 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
225 		    out));
226 
227 	if (topo_method_invoke(rnode, TOPO_METH_CONTAINS,
228 	    TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0) {
229 		nvlist_free(out);
230 		return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in));
231 	}
232 
233 	(void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains);
234 	nvlist_free(in);
235 	nvlist_free(out);
236 
237 	return (contains);
238 }
239 
240 int
241 topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err)
242 {
243 	char *scheme;
244 	uint32_t unusable = 0;
245 	nvlist_t *out = NULL;
246 	tnode_t *rnode;
247 
248 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
249 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
250 		    TOPO_METH_UNUSABLE, out));
251 
252 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
253 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
254 		    TOPO_METH_UNUSABLE, out));
255 
256 	if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE,
257 	    TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0)
258 		return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out));
259 
260 	(void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable);
261 	nvlist_free(out);
262 
263 	return (unusable);
264 }
265 
266 int
267 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err)
268 {
269 	char *scheme;
270 	nvlist_t *out = NULL;
271 	tnode_t *rnode;
272 
273 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
274 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
275 		    TOPO_METH_EXPAND, out));
276 
277 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
278 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
279 		    TOPO_METH_EXPAND, out));
280 
281 	if (topo_method_invoke(rnode, TOPO_METH_EXPAND,
282 	    TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0)
283 		return (set_error(thp, *err, err, TOPO_METH_EXPAND, out));
284 
285 	return (0);
286 }
287 
288 static int
289 fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
290     const char *pname, nvlist_t *args, nvlist_t **prop,
291     int *err)
292 {
293 	int rv;
294 	nvlist_t *in = NULL;
295 	tnode_t *rnode;
296 	char *scheme;
297 
298 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
299 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
300 		    TOPO_METH_PROP_GET, in));
301 
302 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
303 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
304 		    TOPO_METH_PROP_GET, in));
305 
306 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
307 		return (set_error(thp, ETOPO_FMRI_NVL, err,
308 		    TOPO_METH_PROP_GET, in));
309 
310 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
311 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
312 	rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname);
313 	if (args != NULL)
314 		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
315 	if (rv != 0)
316 		return (set_error(thp, ETOPO_FMRI_NVL, err,
317 		    TOPO_METH_PROP_GET, in));
318 
319 	*prop = NULL;
320 	rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET,
321 	    TOPO_METH_PROP_GET_VERSION, in, prop, err);
322 
323 	nvlist_free(in);
324 
325 	if (rv != 0)
326 		return (-1); /* *err is set for us */
327 
328 	if (*prop == NULL)
329 		return (set_error(thp, ETOPO_PROP_NOENT, err,
330 		    TOPO_METH_PROP_GET, NULL));
331 	return (0);
332 }
333 
334 int
335 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err)
336 {
337 	nvlist_t *ap, *prop = NULL;
338 
339 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU,
340 	    nvl, &prop, err) < 0)
341 		return (set_error(thp, *err, err, "topo_fmri_asru", NULL));
342 
343 	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0)
344 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru",
345 		    prop));
346 
347 	if (topo_hdl_nvdup(thp, ap, asru) < 0)
348 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru",
349 		    prop));
350 
351 	nvlist_free(prop);
352 
353 	return (0);
354 }
355 
356 int
357 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err)
358 {
359 	nvlist_t *fp, *prop = NULL;
360 
361 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU,
362 	    nvl, &prop, err) < 0)
363 		return (set_error(thp, *err, err, "topo_fmri_fru", NULL));
364 
365 	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0)
366 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru",
367 		    prop));
368 
369 	if (topo_hdl_nvdup(thp, fp, fru) < 0)
370 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru",
371 		    prop));
372 
373 	nvlist_free(prop);
374 
375 	return (0);
376 }
377 
378 int
379 topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err)
380 {
381 	nvlist_t *prop = NULL;
382 	char *lp;
383 
384 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL,
385 	    NULL, &prop, err) < 0)
386 		return (set_error(thp, *err, err, "topo_fmri_label", NULL));
387 
388 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0)
389 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label",
390 		    prop));
391 
392 	if ((*label = topo_hdl_strdup(thp, lp)) == NULL)
393 		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label",
394 		    prop));
395 
396 	nvlist_free(prop);
397 
398 	return (0);
399 }
400 
401 int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
402     const char *pname, nvlist_t *args,  nvlist_t **prop,
403     int *err)
404 {
405 	*prop = NULL;
406 
407 	return (fmri_prop(thp, nvl, pg, pname, args, prop, err));
408 }
409 
410 int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
411     nvlist_t *prop, int flag, nvlist_t *args, int *err)
412 {
413 	int rv;
414 	nvlist_t *in = NULL, *out = NULL;
415 	tnode_t *rnode;
416 	char *scheme;
417 
418 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0)
419 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
420 		    TOPO_METH_PROP_SET, in));
421 
422 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
423 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
424 		    TOPO_METH_PROP_SET, in));
425 
426 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
427 		return (set_error(thp, ETOPO_FMRI_NVL, err,
428 		    TOPO_METH_PROP_SET, in));
429 
430 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl);
431 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg);
432 	rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop);
433 	rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag);
434 	if (args != NULL)
435 		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
436 	if (rv != 0)
437 		return (set_error(thp, ETOPO_FMRI_NVL, err,
438 		    TOPO_METH_PROP_SET, in));
439 
440 	rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET,
441 	    TOPO_METH_PROP_SET_VERSION, in, &out, err);
442 
443 	nvlist_free(in);
444 
445 	/* no return values */
446 	if (out != NULL)
447 		nvlist_free(out);
448 
449 	if (rv)
450 		return (-1);
451 
452 	return (0);
453 
454 }
455 
456 int
457 topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
458     nvlist_t **pgroup, int *err)
459 {
460 	int rv;
461 	nvlist_t *in = NULL;
462 	tnode_t *rnode;
463 	char *scheme;
464 
465 	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
466 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
467 		    TOPO_METH_PROP_GET, in));
468 
469 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
470 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
471 		    TOPO_METH_PROP_GET, in));
472 
473 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
474 		return (set_error(thp, ETOPO_FMRI_NVL, err,
475 		    TOPO_METH_PROP_GET, in));
476 
477 	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
478 	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
479 	if (rv != 0)
480 		return (set_error(thp, ETOPO_FMRI_NVL, err,
481 		    TOPO_METH_PROP_GET, in));
482 
483 	*pgroup = NULL;
484 	rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET,
485 	    TOPO_METH_PGRP_GET_VERSION, in, pgroup, err);
486 
487 	nvlist_free(in);
488 
489 	if (rv != 0)
490 		return (-1); /* *err is set for us */
491 
492 	if (*pgroup == NULL)
493 		return (set_error(thp, ETOPO_PROP_NOENT, err,
494 		    TOPO_METH_PROP_GET, NULL));
495 	return (0);
496 }
497 
498 int
499 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err)
500 {
501 	uint32_t compare;
502 	char *scheme1, *scheme2;
503 	nvlist_t *in;
504 	nvlist_t *out = NULL;
505 	tnode_t *rnode;
506 
507 	if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0)
508 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
509 		    TOPO_METH_COMPARE, NULL));
510 	if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0)
511 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
512 		    TOPO_METH_COMPARE, NULL));
513 
514 	if (strcmp(scheme1, scheme2) != 0)
515 		return (0);
516 
517 	if ((rnode = topo_hdl_root(thp, scheme1)) == NULL)
518 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
519 		    TOPO_METH_COMPARE, NULL));
520 
521 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
522 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
523 		    NULL));
524 
525 	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 ||
526 	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0)
527 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
528 		    in));
529 
530 	if (topo_method_invoke(rnode, TOPO_METH_COMPARE,
531 	    TOPO_METH_COMPARE_VERSION, in, &out, err) < 0)
532 		return (set_error(thp, *err, err, TOPO_METH_COMPARE, in));
533 
534 	(void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare);
535 	nvlist_free(out);
536 	nvlist_free(in);
537 
538 	return (compare);
539 }
540 
541 /*
542  * topo_fmri_create
543  *
544  *	If possible, creates an FMRI of the requested version in the
545  *	requested scheme.  Args are passed as part of the inputs to the
546  *	fmri-create method of the scheme.
547  */
548 nvlist_t *
549 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name,
550     topo_instance_t inst, nvlist_t *nvl, int *err)
551 {
552 	nvlist_t *ins;
553 	nvlist_t *out;
554 	tnode_t *rnode;
555 
556 	ins = out = NULL;
557 
558 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
559 		return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err,
560 		    TOPO_METH_FMRI, NULL));
561 
562 	if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0)
563 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
564 		    TOPO_METH_FMRI, NULL));
565 
566 	if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 ||
567 	    nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) {
568 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
569 		    TOPO_METH_FMRI, ins));
570 	}
571 
572 	if (nvl != NULL &&
573 	    nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) {
574 		return (set_nverror(thp, ETOPO_FMRI_NVL, err,
575 		    TOPO_METH_FMRI, ins));
576 	}
577 	if (topo_method_invoke(rnode,
578 	    TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) {
579 		return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins));
580 	}
581 	nvlist_free(ins);
582 	return (out);
583 }
584