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 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2019 Joyent, Inc.
24 * Copyright 2023 Oxide Computer Company
25 */
26
27 /*
28 * Topology Plugin Modules
29 *
30 * Topology plugin modules are shared libraries that are dlopen'd and
31 * used to enumerate resources in the system and export per-node method
32 * operations.
33 *
34 * They are loaded by our builtin scheme-specific plugins, other modules or
35 * by processing a topo map XML file to enumerate and create nodes for
36 * resources that are present in the system. They may also export a set of
37 * topology node specific methods that can be invoked directly via
38 * topo_method_invoke() or indirectly via the
39 * topo_prop_get* family of functions to access dynamic property data.
40 *
41 * Module Plugin API
42 *
43 * Enumerators must provide entry points for initialization and clean-up
44 * (_topo_init() and _topo_fini()). In their _topo_init() function, an
45 * enumerator should register (topo_mod_register()) its enumeration callback
46 * and allocate resources required for a subsequent call to the callback.
47 * Optionally, methods may also be registered with topo_method_register().
48 *
49 * In its enumeration callback routine, the module should search for resources
50 * within its realm of responsibility and create any node ranges,
51 * topo_node_range_create() and nodes, topo_node_bind(). The Enumerator
52 * module is handed a node to which it may begin attaching additional
53 * topology nodes. The enumerator may only access those nodes within its
54 * current scope of operation: the node passed into its enumeration op and
55 * any nodes it creates during enumeration. If the enumerator requires walker-
56 * style access to these nodes, it must use
57 * topo_mod_walk_init()/topo_walk_step()/topo_walk_fini().
58 *
59 * If additional helper modules need to be loaded to complete the enumeration
60 * the module may do so by calling topo_mod_load(). Enumeration may then
61 * continue with the module handing off enumeration to its helper module
62 * by calling topo_mod_enumerate(). Similarly, a module may call
63 * topo_mod_enummap() to kick-off enumeration according to a given XML
64 * topology map file. A module *may* not cause re-entrance to itself
65 * via either of these interfaces. If re-entry is detected an error
66 * will be returned (ETOPO_ENUM_RECURS).
67 *
68 * If the module registers a release callback, it will be called on a node
69 * by node basis during topo_snap_rele(). Any private node data may be
70 * deallocated or methods unregistered at that time. Global module data
71 * should be cleaned up before or at the time that the module _topo_fini
72 * entry point is called.
73 *
74 * Module entry points and method invocations are guaranteed to be
75 * single-threaded for a given snapshot handle. Applications may have
76 * more than one topology snapshot open at a time. This means that the
77 * module operations and methods may be called for different module handles
78 * (topo_mod_t) asynchronously. The enumerator should not use static or
79 * global data structures that may become inconsistent in this situation.
80 * Method operations may be re-entrant if the module invokes one of its own
81 * methods directly or via dynamic property access. Caution should be
82 * exercised with method operations to insure that data remains consistent
83 * within the module and that deadlocks can not occur.
84 */
85
86 #include <pthread.h>
87 #include <assert.h>
88 #include <errno.h>
89 #include <dirent.h>
90 #include <limits.h>
91 #include <alloca.h>
92 #include <unistd.h>
93 #include <stdio.h>
94 #include <ctype.h>
95 #include <pcidb.h>
96 #include <sys/param.h>
97 #include <sys/utsname.h>
98 #include <sys/smbios.h>
99 #include <sys/fm/protocol.h>
100 #include <sys/types.h>
101 #include <sys/stat.h>
102 #include <fcntl.h>
103
104 #include <topo_alloc.h>
105 #include <topo_error.h>
106 #include <topo_file.h>
107 #include <topo_fmri.h>
108 #include <topo_module.h>
109 #include <topo_method.h>
110 #include <topo_string.h>
111 #include <topo_subr.h>
112 #include <topo_tree.h>
113
114 #define PLUGIN_PATH "plugins"
115 #define PLUGIN_PATH_LEN MAXNAMELEN + 5
116
117 topo_mod_t *
topo_mod_load(topo_mod_t * pmod,const char * name,topo_version_t version)118 topo_mod_load(topo_mod_t *pmod, const char *name,
119 topo_version_t version)
120 {
121 char *path;
122 char file[PLUGIN_PATH_LEN];
123 topo_mod_t *mod = NULL;
124 topo_hdl_t *thp;
125
126 thp = pmod->tm_hdl;
127
128 /*
129 * Already loaded, topo_mod_lookup will bump the ref count
130 */
131 if ((mod = topo_mod_lookup(thp, name, 1)) != NULL) {
132 if (mod->tm_info->tmi_version != version) {
133 topo_mod_rele(mod);
134 (void) topo_mod_seterrno(pmod, ETOPO_MOD_VER);
135 return (NULL);
136 }
137 return (mod);
138 }
139
140 (void) snprintf(file, PLUGIN_PATH_LEN, "%s/%s.so",
141 PLUGIN_PATH, name);
142 path = topo_search_path(pmod, thp->th_rootdir, (const char *)file);
143 if (path == NULL ||
144 (mod = topo_modhash_load(thp, name, path, &topo_rtld_ops, version))
145 == NULL) { /* returned with mod held */
146 topo_mod_strfree(pmod, path);
147 (void) topo_mod_seterrno(pmod, topo_hdl_errno(thp) ?
148 topo_hdl_errno(thp) : ETOPO_MOD_NOENT);
149 return (NULL);
150 }
151
152 topo_mod_strfree(pmod, path);
153
154 return (mod);
155 }
156
157 void
topo_mod_unload(topo_mod_t * mod)158 topo_mod_unload(topo_mod_t *mod)
159 {
160 topo_mod_rele(mod);
161 }
162
163 static int
set_register_error(topo_mod_t * mod,int err)164 set_register_error(topo_mod_t *mod, int err)
165 {
166 if (mod->tm_info != NULL)
167 topo_mod_unregister(mod);
168
169 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
170 "module registration failed for %s: %s\n",
171 mod->tm_name, topo_strerror(err));
172
173 return (topo_mod_seterrno(mod, err));
174 }
175
176 int
topo_mod_register(topo_mod_t * mod,const topo_modinfo_t * mip,topo_version_t version)177 topo_mod_register(topo_mod_t *mod, const topo_modinfo_t *mip,
178 topo_version_t version)
179 {
180
181 assert(!(mod->tm_flags & TOPO_MOD_FINI ||
182 mod->tm_flags & TOPO_MOD_REG));
183
184 if (version != TOPO_VERSION)
185 return (set_register_error(mod, EMOD_VER_ABI));
186
187 if ((mod->tm_info = topo_mod_zalloc(mod, sizeof (topo_imodinfo_t)))
188 == NULL)
189 return (set_register_error(mod, EMOD_NOMEM));
190 if ((mod->tm_info->tmi_ops = topo_mod_alloc(mod,
191 sizeof (topo_modops_t))) == NULL)
192 return (set_register_error(mod, EMOD_NOMEM));
193
194 mod->tm_info->tmi_desc = topo_mod_strdup(mod, mip->tmi_desc);
195 if (mod->tm_info->tmi_desc == NULL)
196 return (set_register_error(mod, EMOD_NOMEM));
197
198 mod->tm_info->tmi_scheme = topo_mod_strdup(mod, mip->tmi_scheme);
199 if (mod->tm_info->tmi_scheme == NULL)
200 return (set_register_error(mod, EMOD_NOMEM));
201
202
203 mod->tm_info->tmi_version = (topo_version_t)mip->tmi_version;
204 mod->tm_info->tmi_ops->tmo_enum = mip->tmi_ops->tmo_enum;
205 mod->tm_info->tmi_ops->tmo_release = mip->tmi_ops->tmo_release;
206
207 mod->tm_flags |= TOPO_MOD_REG;
208
209 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
210 "registration succeeded for %s\n", mod->tm_name);
211
212 return (0);
213 }
214
215 void
topo_mod_unregister(topo_mod_t * mod)216 topo_mod_unregister(topo_mod_t *mod)
217 {
218 if (mod->tm_info == NULL)
219 return;
220
221 assert(!(mod->tm_flags & TOPO_MOD_FINI));
222
223 mod->tm_flags &= ~TOPO_MOD_REG;
224
225 if (mod->tm_info == NULL)
226 return;
227
228 if (mod->tm_info->tmi_ops != NULL)
229 topo_mod_free(mod, mod->tm_info->tmi_ops,
230 sizeof (topo_modops_t));
231 if (mod->tm_info->tmi_desc != NULL)
232 topo_mod_strfree(mod, mod->tm_info->tmi_desc);
233 if (mod->tm_info->tmi_scheme != NULL)
234 topo_mod_strfree(mod, mod->tm_info->tmi_scheme);
235
236 topo_mod_free(mod, mod->tm_info, sizeof (topo_imodinfo_t));
237
238 mod->tm_info = NULL;
239 }
240
241 int
topo_mod_enumerate(topo_mod_t * mod,tnode_t * node,const char * enum_name,const char * name,topo_instance_t min,topo_instance_t max,void * data)242 topo_mod_enumerate(topo_mod_t *mod, tnode_t *node, const char *enum_name,
243 const char *name, topo_instance_t min, topo_instance_t max, void *data)
244 {
245 int err = 0;
246 topo_mod_t *enum_mod;
247
248 assert(mod->tm_flags & TOPO_MOD_REG);
249
250 if ((enum_mod = topo_mod_lookup(mod->tm_hdl, enum_name, 0)) == NULL)
251 return (topo_mod_seterrno(mod, EMOD_MOD_NOENT));
252
253 topo_node_hold(node);
254
255 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "module %s enumerating "
256 "node %s=%d\n", (char *)mod->tm_name, (char *)node->tn_name,
257 node->tn_instance);
258
259 topo_mod_enter(enum_mod);
260 err = enum_mod->tm_info->tmi_ops->tmo_enum(enum_mod, node, name, min,
261 max, enum_mod->tm_priv, data);
262 topo_mod_exit(enum_mod);
263
264 if (err != 0) {
265 (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
266
267 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
268 "module %s failed enumeration for "
269 " node %s=%d\n", (char *)mod->tm_name,
270 (char *)node->tn_name, node->tn_instance);
271
272 topo_node_rele(node);
273 return (-1);
274 }
275
276 topo_node_rele(node);
277
278 return (0);
279 }
280
281 int
topo_mod_enummap(topo_mod_t * mod,tnode_t * node,const char * name,const char * scheme)282 topo_mod_enummap(topo_mod_t *mod, tnode_t *node, const char *name,
283 const char *scheme)
284 {
285 return (topo_file_load(mod, node, (char *)name, (char *)scheme, 0));
286 }
287
288 static nvlist_t *
set_fmri_err(topo_mod_t * mod,int err)289 set_fmri_err(topo_mod_t *mod, int err)
290 {
291 (void) topo_mod_seterrno(mod, err);
292 return (NULL);
293 }
294
295 nvlist_t *
topo_mod_hcfmri(topo_mod_t * mod,tnode_t * pnode,int version,const char * name,topo_instance_t inst,nvlist_t * hc_specific,nvlist_t * auth,const char * part,const char * rev,const char * serial)296 topo_mod_hcfmri(topo_mod_t *mod, tnode_t *pnode, int version, const char *name,
297 topo_instance_t inst, nvlist_t *hc_specific, nvlist_t *auth,
298 const char *part, const char *rev, const char *serial)
299 {
300 int err;
301 nvlist_t *pfmri = NULL, *fmri = NULL, *args = NULL;
302 nvlist_t *nfp = NULL;
303 char *lpart, *lrev, *lserial;
304
305 if (version != FM_HC_SCHEME_VERSION)
306 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
307
308 /*
309 * Do we have any args to pass?
310 */
311 if (pnode != NULL || auth != NULL || part != NULL || rev != NULL ||
312 serial != NULL || hc_specific != NULL) {
313 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
314 return (set_fmri_err(mod, EMOD_FMRI_NVL));
315 }
316
317 if (pnode != NULL) {
318 if (topo_node_resource(pnode, &pfmri, &err) < 0) {
319 nvlist_free(args);
320 return (set_fmri_err(mod, EMOD_NVL_INVAL));
321 }
322
323 if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
324 pfmri) != 0) {
325 nvlist_free(pfmri);
326 nvlist_free(args);
327 return (set_fmri_err(mod, EMOD_FMRI_NVL));
328 }
329 nvlist_free(pfmri);
330 }
331
332 /*
333 * Add optional payload
334 */
335 if (auth != NULL)
336 (void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, auth);
337 if (part != NULL) {
338 lpart = topo_cleanup_auth_str(mod->tm_hdl, part);
339 if (lpart != NULL) {
340 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
341 lpart);
342 topo_hdl_free(mod->tm_hdl, lpart, strlen(lpart) + 1);
343 } else {
344 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
345 "");
346 }
347 }
348 if (rev != NULL) {
349 lrev = topo_cleanup_auth_str(mod->tm_hdl, rev);
350 if (lrev != NULL) {
351 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
352 lrev);
353 topo_hdl_free(mod->tm_hdl, lrev, strlen(lrev) + 1);
354 } else {
355 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
356 "");
357 }
358 }
359 if (serial != NULL) {
360 lserial = topo_cleanup_auth_str(mod->tm_hdl, serial);
361 if (lserial != NULL) {
362 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
363 lserial);
364 topo_hdl_free(mod->tm_hdl, lserial,
365 strlen(lserial) + 1);
366 } else {
367 (void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
368 "");
369 }
370 }
371 if (hc_specific != NULL)
372 (void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_HCS,
373 hc_specific);
374
375 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_HC, name, inst,
376 args, &err)) == NULL) {
377 nvlist_free(args);
378 return (set_fmri_err(mod, err));
379 }
380
381 nvlist_free(args);
382
383 (void) topo_mod_nvdup(mod, fmri, &nfp);
384 nvlist_free(fmri);
385
386 return (nfp);
387 }
388
389 nvlist_t *
topo_mod_devfmri(topo_mod_t * mod,int version,const char * dev_path,const char * devid)390 topo_mod_devfmri(topo_mod_t *mod, int version, const char *dev_path,
391 const char *devid)
392 {
393 int err;
394 nvlist_t *fmri, *args;
395 nvlist_t *nfp = NULL;
396
397 if (version != FM_DEV_SCHEME_VERSION)
398 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
399
400 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
401 return (set_fmri_err(mod, EMOD_FMRI_NVL));
402
403 if (nvlist_add_string(args, FM_FMRI_DEV_PATH, dev_path) != 0) {
404 nvlist_free(args);
405 return (set_fmri_err(mod, EMOD_FMRI_NVL));
406 }
407
408 (void) nvlist_add_string(args, FM_FMRI_DEV_ID, devid);
409
410 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_DEV,
411 FM_FMRI_SCHEME_DEV, 0, args, &err)) == NULL) {
412 nvlist_free(args);
413 return (set_fmri_err(mod, err));
414 }
415
416 nvlist_free(args);
417
418 (void) topo_mod_nvdup(mod, fmri, &nfp);
419 nvlist_free(fmri);
420
421 return (nfp);
422 }
423
424 nvlist_t *
topo_mod_cpufmri(topo_mod_t * mod,int version,uint32_t cpu_id,uint8_t cpumask,const char * serial)425 topo_mod_cpufmri(topo_mod_t *mod, int version, uint32_t cpu_id, uint8_t cpumask,
426 const char *serial)
427 {
428 int err;
429 nvlist_t *fmri = NULL, *args = NULL;
430 nvlist_t *nfp = NULL;
431
432 if (version != FM_CPU_SCHEME_VERSION)
433 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
434
435 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
436 return (set_fmri_err(mod, EMOD_FMRI_NVL));
437
438 if (nvlist_add_uint32(args, FM_FMRI_CPU_ID, cpu_id) != 0) {
439 nvlist_free(args);
440 return (set_fmri_err(mod, EMOD_FMRI_NVL));
441 }
442
443 /*
444 * Add optional payload
445 */
446 (void) nvlist_add_uint8(args, FM_FMRI_CPU_MASK, cpumask);
447 (void) nvlist_add_string(args, FM_FMRI_CPU_SERIAL_ID, serial);
448
449 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_CPU,
450 FM_FMRI_SCHEME_CPU, 0, args, &err)) == NULL) {
451 nvlist_free(args);
452 return (set_fmri_err(mod, err));
453 }
454
455 nvlist_free(args);
456
457 (void) topo_mod_nvdup(mod, fmri, &nfp);
458 nvlist_free(fmri);
459
460 return (nfp);
461 }
462
463 nvlist_t *
topo_mod_memfmri(topo_mod_t * mod,int version,uint64_t pa,uint64_t offset,const char * unum,int flags)464 topo_mod_memfmri(topo_mod_t *mod, int version, uint64_t pa, uint64_t offset,
465 const char *unum, int flags)
466 {
467 int err;
468 nvlist_t *args = NULL, *fmri = NULL;
469 nvlist_t *nfp = NULL;
470
471 if (version != FM_MEM_SCHEME_VERSION)
472 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
473
474 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
475 return (set_fmri_err(mod, EMOD_FMRI_NVL));
476
477 err = nvlist_add_string(args, FM_FMRI_MEM_UNUM, unum);
478 if (flags & TOPO_MEMFMRI_PA)
479 err |= nvlist_add_uint64(args, FM_FMRI_MEM_PHYSADDR, pa);
480 if (flags & TOPO_MEMFMRI_OFFSET)
481 err |= nvlist_add_uint64(args, FM_FMRI_MEM_OFFSET, offset);
482
483 if (err != 0) {
484 nvlist_free(args);
485 return (set_fmri_err(mod, EMOD_FMRI_NVL));
486 }
487
488 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MEM,
489 FM_FMRI_SCHEME_MEM, 0, args, &err)) == NULL) {
490 nvlist_free(args);
491 return (set_fmri_err(mod, err));
492 }
493
494 nvlist_free(args);
495
496 (void) topo_mod_nvdup(mod, fmri, &nfp);
497 nvlist_free(fmri);
498
499 return (nfp);
500
501 }
502
503 nvlist_t *
topo_mod_pkgfmri(topo_mod_t * mod,int version,const char * path)504 topo_mod_pkgfmri(topo_mod_t *mod, int version, const char *path)
505 {
506 int err;
507 nvlist_t *fmri = NULL, *args = NULL;
508 nvlist_t *nfp = NULL;
509
510 if (version != FM_PKG_SCHEME_VERSION)
511 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
512
513 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
514 return (set_fmri_err(mod, EMOD_FMRI_NVL));
515
516 if (nvlist_add_string(args, "path", path) != 0) {
517 nvlist_free(args);
518 return (set_fmri_err(mod, EMOD_FMRI_NVL));
519 }
520
521 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_PKG,
522 FM_FMRI_SCHEME_PKG, 0, args, &err)) == NULL) {
523 nvlist_free(args);
524 return (set_fmri_err(mod, err));
525 }
526
527 nvlist_free(args);
528
529 (void) topo_mod_nvdup(mod, fmri, &nfp);
530 nvlist_free(fmri);
531
532 return (nfp);
533 }
534
535 nvlist_t *
topo_mod_modfmri(topo_mod_t * mod,int version,const char * driver)536 topo_mod_modfmri(topo_mod_t *mod, int version, const char *driver)
537 {
538 int err;
539 nvlist_t *fmri = NULL, *args = NULL;
540 nvlist_t *nfp = NULL;
541
542 if (version != FM_MOD_SCHEME_VERSION)
543 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
544
545 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
546 return (set_fmri_err(mod, EMOD_FMRI_NVL));
547
548 if (nvlist_add_string(args, "DRIVER", driver) != 0) {
549 nvlist_free(args);
550 return (set_fmri_err(mod, EMOD_FMRI_NVL));
551 }
552
553 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MOD,
554 FM_FMRI_SCHEME_MOD, 0, args, &err)) == NULL) {
555 nvlist_free(args);
556 return (set_fmri_err(mod, err));
557 }
558
559 nvlist_free(args);
560
561 (void) topo_mod_nvdup(mod, fmri, &nfp);
562 nvlist_free(fmri);
563
564 return (nfp);
565 }
566
567 #define _SWFMRI_ADD_STRING(nvl, name, val) \
568 ((val) ? (nvlist_add_string(nvl, name, val) != 0) : 0)
569
570 nvlist_t *
topo_mod_swfmri(topo_mod_t * mod,int version,char * obj_path,char * obj_root,nvlist_t * obj_pkg,char * site_token,char * site_module,char * site_file,char * site_func,int64_t site_line,char * ctxt_origin,char * ctxt_execname,int64_t ctxt_pid,char * ctxt_zone,int64_t ctxt_ctid,char ** ctxt_stack,uint_t ctxt_stackdepth)571 topo_mod_swfmri(topo_mod_t *mod, int version,
572 char *obj_path, char *obj_root, nvlist_t *obj_pkg,
573 char *site_token, char *site_module, char *site_file, char *site_func,
574 int64_t site_line, char *ctxt_origin, char *ctxt_execname,
575 int64_t ctxt_pid, char *ctxt_zone, int64_t ctxt_ctid,
576 char **ctxt_stack, uint_t ctxt_stackdepth)
577 {
578 nvlist_t *fmri, *args;
579 nvlist_t *nfp = NULL;
580 int err;
581
582 if (version != FM_SW_SCHEME_VERSION)
583 return (set_fmri_err(mod, EMOD_FMRI_VERSION));
584
585 if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
586 return (set_fmri_err(mod, EMOD_FMRI_NVL));
587
588 err = 0;
589 err |= _SWFMRI_ADD_STRING(args, "obj_path", obj_path);
590 err |= _SWFMRI_ADD_STRING(args, "obj_root", obj_root);
591 if (obj_pkg)
592 err |= nvlist_add_nvlist(args, "obj_pkg", obj_pkg);
593
594 err |= _SWFMRI_ADD_STRING(args, "site_token", site_token);
595 err |= _SWFMRI_ADD_STRING(args, "site_module", site_module);
596 err |= _SWFMRI_ADD_STRING(args, "site_file", site_file);
597 err |= _SWFMRI_ADD_STRING(args, "site_func", site_func);
598 if (site_line != -1)
599 err |= nvlist_add_int64(args, "site_line", site_line);
600
601 err |= _SWFMRI_ADD_STRING(args, "ctxt_origin", ctxt_origin);
602 err |= _SWFMRI_ADD_STRING(args, "ctxt_execname", ctxt_execname);
603 if (ctxt_pid != -1)
604 err |= nvlist_add_int64(args, "ctxt_pid", ctxt_pid);
605 err |= _SWFMRI_ADD_STRING(args, "ctxt_zone", ctxt_zone);
606 if (ctxt_ctid != -1)
607 err |= nvlist_add_int64(args, "ctxt_ctid", ctxt_ctid);
608 if (ctxt_stack != NULL && ctxt_stackdepth != 0)
609 err |= nvlist_add_string_array(args, "stack", ctxt_stack,
610 ctxt_stackdepth);
611
612 if (err) {
613 nvlist_free(args);
614 return (set_fmri_err(mod, EMOD_FMRI_NVL));
615 }
616
617 if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_SW,
618 FM_FMRI_SCHEME_SW, 0, args, &err)) == NULL) {
619 nvlist_free(args);
620 return (set_fmri_err(mod, err));
621 }
622
623 nvlist_free(args);
624
625 (void) topo_mod_nvdup(mod, fmri, &nfp);
626 nvlist_free(fmri);
627
628 return (nfp);
629 }
630
631 int
topo_mod_str2nvl(topo_mod_t * mod,const char * fmristr,nvlist_t ** fmri)632 topo_mod_str2nvl(topo_mod_t *mod, const char *fmristr, nvlist_t **fmri)
633 {
634 int err;
635 nvlist_t *np = NULL;
636
637 if (topo_fmri_str2nvl(mod->tm_hdl, fmristr, &np, &err) < 0)
638 return (topo_mod_seterrno(mod, err));
639
640 if (topo_mod_nvdup(mod, np, fmri) < 0) {
641 nvlist_free(np);
642 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
643 }
644
645 nvlist_free(np);
646
647 return (0);
648 }
649
650 int
topo_mod_nvl2str(topo_mod_t * mod,nvlist_t * fmri,char ** fmristr)651 topo_mod_nvl2str(topo_mod_t *mod, nvlist_t *fmri, char **fmristr)
652 {
653 int err;
654 char *sp;
655
656 if (topo_fmri_nvl2str(mod->tm_hdl, fmri, &sp, &err) < 0)
657 return (topo_mod_seterrno(mod, err));
658
659 if ((*fmristr = topo_mod_strdup(mod, sp)) == NULL) {
660 topo_hdl_strfree(mod->tm_hdl, sp);
661 return (topo_mod_seterrno(mod, EMOD_NOMEM));
662 }
663
664 topo_hdl_strfree(mod->tm_hdl, sp);
665
666 return (0);
667 }
668
669 void *
topo_mod_getspecific(topo_mod_t * mod)670 topo_mod_getspecific(topo_mod_t *mod)
671 {
672 return (mod->tm_priv);
673 }
674
675 void
topo_mod_setspecific(topo_mod_t * mod,void * data)676 topo_mod_setspecific(topo_mod_t *mod, void *data)
677 {
678 mod->tm_priv = data;
679 }
680
681 void
topo_mod_setdebug(topo_mod_t * mod)682 topo_mod_setdebug(topo_mod_t *mod)
683 {
684 mod->tm_debug = 1;
685 }
686
687 ipmi_handle_t *
topo_mod_ipmi_hold(topo_mod_t * mod)688 topo_mod_ipmi_hold(topo_mod_t *mod)
689 {
690 topo_hdl_t *thp = mod->tm_hdl;
691 int err;
692 char *errmsg;
693
694 (void) pthread_mutex_lock(&thp->th_ipmi_lock);
695 if (thp->th_ipmi == NULL) {
696 if ((thp->th_ipmi = ipmi_open(&err, &errmsg, IPMI_TRANSPORT_BMC,
697 NULL)) == NULL) {
698 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
699 "ipmi_open() failed: %s (ipmi errno=%d)", errmsg,
700 err);
701 (void) pthread_mutex_unlock(&thp->th_ipmi_lock);
702 }
703 }
704
705
706 return (thp->th_ipmi);
707 }
708
709 void
topo_mod_ipmi_rele(topo_mod_t * mod)710 topo_mod_ipmi_rele(topo_mod_t *mod)
711 {
712 topo_hdl_t *thp = mod->tm_hdl;
713
714 (void) pthread_mutex_unlock(&thp->th_ipmi_lock);
715 }
716
717 di_node_t
topo_mod_devinfo(topo_mod_t * mod)718 topo_mod_devinfo(topo_mod_t *mod)
719 {
720 return (topo_hdl_devinfo(mod->tm_hdl));
721 }
722
723 smbios_hdl_t *
topo_mod_smbios(topo_mod_t * mod)724 topo_mod_smbios(topo_mod_t *mod)
725 {
726 topo_hdl_t *thp = mod->tm_hdl;
727
728 if (thp->th_smbios == NULL)
729 thp->th_smbios = smbios_open(NULL, SMB_VERSION, 0, NULL);
730
731 return (thp->th_smbios);
732 }
733
734 di_prom_handle_t
topo_mod_prominfo(topo_mod_t * mod)735 topo_mod_prominfo(topo_mod_t *mod)
736 {
737 return (topo_hdl_prominfo(mod->tm_hdl));
738 }
739
740 pcidb_hdl_t *
topo_mod_pcidb(topo_mod_t * mod)741 topo_mod_pcidb(topo_mod_t *mod)
742 {
743 topo_hdl_t *thp = mod->tm_hdl;
744
745 if (thp->th_pcidb == NULL)
746 thp->th_pcidb = pcidb_open(PCIDB_VERSION);
747
748 return (thp->th_pcidb);
749 }
750
751 void
topo_mod_clrdebug(topo_mod_t * mod)752 topo_mod_clrdebug(topo_mod_t *mod)
753 {
754 mod->tm_debug = 0;
755 }
756
757 /*PRINTFLIKE2*/
758 void
topo_mod_dprintf(topo_mod_t * mod,const char * format,...)759 topo_mod_dprintf(topo_mod_t *mod, const char *format, ...)
760 {
761 topo_hdl_t *thp = mod->tm_hdl;
762 va_list alist;
763
764 if (mod->tm_debug == 0 || !(thp->th_debug & TOPO_DBG_MOD))
765 return;
766
767 va_start(alist, format);
768 topo_vdprintf(mod->tm_hdl, (const char *)mod->tm_name, format, alist);
769 va_end(alist);
770 }
771
772 char *
topo_mod_product(topo_mod_t * mod)773 topo_mod_product(topo_mod_t *mod)
774 {
775 return (topo_mod_strdup(mod, mod->tm_hdl->th_product));
776 }
777
778 static char *
topo_mod_server(topo_mod_t * mod)779 topo_mod_server(topo_mod_t *mod)
780 {
781 static struct utsname uts;
782
783 (void) uname(&uts);
784 return (topo_mod_strdup(mod, uts.nodename));
785 }
786
787 static char *
topo_mod_psn(topo_mod_t * mod)788 topo_mod_psn(topo_mod_t *mod)
789 {
790 smbios_hdl_t *shp;
791 const char *psn;
792
793 if ((shp = topo_mod_smbios(mod)) == NULL ||
794 (psn = smbios_psn(shp)) == NULL)
795 return (NULL);
796
797 return (topo_cleanup_auth_str(mod->tm_hdl, psn));
798 }
799
800 static char *
topo_mod_csn(topo_mod_t * mod)801 topo_mod_csn(topo_mod_t *mod)
802 {
803 char csn[MAXNAMELEN];
804 smbios_hdl_t *shp;
805 di_prom_handle_t promh = DI_PROM_HANDLE_NIL;
806 di_node_t rooth = DI_NODE_NIL;
807 const char *bufp;
808
809 if ((shp = topo_mod_smbios(mod)) != NULL) {
810 bufp = smbios_csn(shp);
811 if (bufp != NULL)
812 (void) strlcpy(csn, bufp, MAXNAMELEN);
813 else
814 return (NULL);
815 } else if ((rooth = topo_mod_devinfo(mod)) != DI_NODE_NIL &&
816 (promh = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) {
817 if (di_prom_prop_lookup_bytes(promh, rooth, "chassis-sn",
818 (unsigned char **)&bufp) != -1) {
819 (void) strlcpy(csn, bufp, MAXNAMELEN);
820 } else {
821 return (NULL);
822 }
823 } else {
824 return (NULL);
825 }
826
827 return (topo_cleanup_auth_str(mod->tm_hdl, csn));
828 }
829
830 nvlist_t *
topo_mod_auth(topo_mod_t * mod,tnode_t * pnode)831 topo_mod_auth(topo_mod_t *mod, tnode_t *pnode)
832 {
833 int err;
834 char *prod = NULL;
835 char *csn = NULL;
836 char *psn = NULL;
837 char *server = NULL;
838 nvlist_t *auth;
839
840 if ((err = topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME)) != 0) {
841 (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
842 return (NULL);
843 }
844
845 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
846 FM_FMRI_AUTH_PRODUCT, &prod, &err);
847 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
848 FM_FMRI_AUTH_PRODUCT_SN, &psn, &err);
849 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
850 FM_FMRI_AUTH_CHASSIS, &csn, &err);
851 (void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
852 FM_FMRI_AUTH_SERVER, &server, &err);
853
854 /*
855 * Let's do this the hard way
856 */
857 if (prod == NULL)
858 prod = topo_mod_product(mod);
859 if (csn == NULL)
860 csn = topo_mod_csn(mod);
861 if (psn == NULL)
862 psn = topo_mod_psn(mod);
863 if (server == NULL) {
864 server = topo_mod_server(mod);
865 }
866
867 /*
868 * No luck, return NULL
869 */
870 if (!prod && !server && !csn && !psn) {
871 nvlist_free(auth);
872 return (NULL);
873 }
874
875 err = 0;
876 if (prod != NULL) {
877 err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, prod);
878 topo_mod_strfree(mod, prod);
879 }
880 if (psn != NULL) {
881 err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT_SN, psn);
882 topo_mod_strfree(mod, psn);
883 }
884 if (server != NULL) {
885 err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, server);
886 topo_mod_strfree(mod, server);
887 }
888 if (csn != NULL) {
889 err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, csn);
890 topo_mod_strfree(mod, csn);
891 }
892
893 if (err != 0) {
894 nvlist_free(auth);
895 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
896 return (NULL);
897 }
898
899 return (auth);
900 }
901
902 topo_walk_t *
topo_mod_walk_init(topo_mod_t * mod,tnode_t * node,topo_mod_walk_cb_t cb_f,void * pdata,int * errp)903 topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f,
904 void *pdata, int *errp)
905 {
906 topo_walk_t *wp;
907 topo_hdl_t *thp = mod->tm_hdl;
908
909 if ((wp = topo_node_walk_init(thp, mod, node, (int (*)())cb_f, pdata,
910 errp)) == NULL)
911 return (NULL);
912
913 return (wp);
914 }
915
916 char *
topo_mod_clean_str(topo_mod_t * mod,const char * str)917 topo_mod_clean_str(topo_mod_t *mod, const char *str)
918 {
919 if (str == NULL)
920 return (NULL);
921
922 return (topo_cleanup_strn(mod->tm_hdl, str, strlen(str)));
923 }
924
925 char *
topo_mod_clean_strn(topo_mod_t * mod,const char * str,size_t len)926 topo_mod_clean_strn(topo_mod_t *mod, const char *str, size_t len)
927 {
928 if (str == NULL)
929 return (NULL);
930
931 return (topo_cleanup_strn(mod->tm_hdl, str, len));
932 }
933
934 int
topo_mod_file_search(topo_mod_t * mod,const char * file,int oflags)935 topo_mod_file_search(topo_mod_t *mod, const char *file, int oflags)
936 {
937 int ret;
938 char *path;
939 topo_hdl_t *thp = mod->tm_hdl;
940
941 path = topo_search_path(mod, thp->th_rootdir, file);
942 if (path == NULL) {
943 return (-1);
944 }
945
946 ret = open(path, oflags);
947 topo_mod_strfree(mod, path);
948 return (ret);
949 }
950
951 /*ARGSUSED*/
952 int
topo_mod_hc_occupied(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)953 topo_mod_hc_occupied(topo_mod_t *mod, tnode_t *node, topo_version_t version,
954 nvlist_t *in, nvlist_t **out)
955 {
956 nvlist_t *nvl = NULL;
957 tnode_t *cnp;
958 boolean_t is_occupied = B_FALSE;
959
960 if (version > TOPO_METH_OCCUPIED_VERSION)
961 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
962
963 /*
964 * Iterate though the child nodes. If there are no non-facility
965 * node children then it is unoccupied.
966 */
967 for (cnp = topo_child_first(node); cnp != NULL;
968 cnp = topo_child_next(node, cnp)) {
969 if (topo_node_flags(cnp) != TOPO_NODE_FACILITY)
970 is_occupied = B_TRUE;
971 }
972
973 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
974 nvlist_add_boolean_value(nvl, TOPO_METH_OCCUPIED_RET,
975 is_occupied) != 0) {
976 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
977 nvlist_free(nvl);
978 return (topo_mod_seterrno(mod, EMOD_NOMEM));
979 }
980 *out = nvl;
981
982 return (0);
983 }
984
985 /*
986 * Convenience routine for creating a UFM slot node. This routine assumes
987 * that the caller has already created the containing range via a call to
988 * topo_node_range_create().
989 */
990 tnode_t *
topo_mod_create_ufm_slot(topo_mod_t * mod,tnode_t * ufmnode,topo_ufm_slot_info_t * slotinfo)991 topo_mod_create_ufm_slot(topo_mod_t *mod, tnode_t *ufmnode,
992 topo_ufm_slot_info_t *slotinfo)
993 {
994 nvlist_t *auth = NULL, *fmri = NULL;
995 tnode_t *slotnode;
996 topo_pgroup_info_t pgi;
997 int err, rc;
998
999 if (slotinfo == NULL || slotinfo->usi_mode == 0) {
1000 topo_mod_dprintf(mod, "invalid slot info");
1001 (void) topo_mod_seterrno(mod, ETOPO_MOD_INVAL);
1002 return (NULL);
1003 }
1004 if ((auth = topo_mod_auth(mod, ufmnode)) == NULL) {
1005 topo_mod_dprintf(mod, "topo_mod_auth() failed: %s",
1006 topo_mod_errmsg(mod));
1007 /* errno set */
1008 return (NULL);
1009 }
1010
1011 if ((fmri = topo_mod_hcfmri(mod, ufmnode, FM_HC_SCHEME_VERSION,
1012 SLOT, slotinfo->usi_slotid, NULL, auth, NULL, NULL, NULL)) ==
1013 NULL) {
1014 nvlist_free(auth);
1015 topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
1016 topo_mod_errmsg(mod));
1017 /* errno set */
1018 return (NULL);
1019 }
1020
1021 if ((slotnode = topo_node_bind(mod, ufmnode, SLOT,
1022 slotinfo->usi_slotid, fmri)) == NULL) {
1023 nvlist_free(auth);
1024 nvlist_free(fmri);
1025 topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
1026 topo_mod_errmsg(mod));
1027 /* errno set */
1028 return (NULL);
1029 }
1030
1031 /* Create authority and system pgroups */
1032 topo_pgroup_hcset(slotnode, auth);
1033 nvlist_free(auth);
1034 nvlist_free(fmri);
1035
1036 /* Just inherit the parent's FRU */
1037 if (topo_node_fru_set(slotnode, NULL, 0, &err) != 0) {
1038 topo_mod_dprintf(mod, "failed to set FRU on %s: %s", UFM,
1039 topo_strerror(err));
1040 (void) topo_mod_seterrno(mod, err);
1041 goto slotfail;
1042 }
1043
1044 pgi.tpi_name = TOPO_PGROUP_SLOT;
1045 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1046 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1047 pgi.tpi_version = TOPO_VERSION;
1048 rc = topo_pgroup_create(slotnode, &pgi, &err);
1049
1050 if (rc == 0)
1051 rc += topo_prop_set_uint32(slotnode, TOPO_PGROUP_SLOT,
1052 TOPO_PROP_SLOT_TYPE, TOPO_PROP_IMMUTABLE,
1053 TOPO_SLOT_TYPE_UFM, &err);
1054
1055 pgi.tpi_name = TOPO_PGROUP_UFM_SLOT;
1056
1057 if (rc == 0)
1058 rc += topo_pgroup_create(slotnode, &pgi, &err);
1059
1060 if (rc == 0) {
1061 rc += topo_prop_set_uint32(slotnode, TOPO_PGROUP_UFM_SLOT,
1062 TOPO_PROP_UFM_SLOT_MODE, TOPO_PROP_IMMUTABLE,
1063 slotinfo->usi_mode, &err);
1064 }
1065
1066 if (rc == 0) {
1067 rc += topo_prop_set_uint32(slotnode, TOPO_PGROUP_UFM_SLOT,
1068 TOPO_PROP_UFM_SLOT_ACTIVE, TOPO_PROP_IMMUTABLE,
1069 (uint32_t)slotinfo->usi_active, &err);
1070 }
1071
1072 /*
1073 * We can have a NULL version for an empty slot.
1074 */
1075 if (rc == 0 && slotinfo->usi_version != NULL) {
1076 rc += topo_prop_set_string(slotnode, TOPO_PGROUP_UFM_SLOT,
1077 TOPO_PROP_UFM_SLOT_VERSION, TOPO_PROP_IMMUTABLE,
1078 slotinfo->usi_version, &err);
1079 }
1080
1081 if (rc == 0 && slotinfo->usi_extra != NULL) {
1082 nvpair_t *elem = NULL;
1083 char *pname, *pval;
1084
1085 while ((elem = nvlist_next_nvpair(slotinfo->usi_extra,
1086 elem)) != NULL) {
1087 if (nvpair_type(elem) != DATA_TYPE_STRING)
1088 continue;
1089
1090 pname = nvpair_name(elem);
1091 if ((rc -= nvpair_value_string(elem, &pval)) != 0)
1092 break;
1093
1094 rc += topo_prop_set_string(slotnode,
1095 TOPO_PGROUP_UFM_SLOT, pname, TOPO_PROP_IMMUTABLE,
1096 pval, &err);
1097
1098 if (rc != 0)
1099 break;
1100 }
1101 }
1102
1103 if (rc != 0) {
1104 topo_mod_dprintf(mod, "error setting properties on %s node",
1105 SLOT);
1106 (void) topo_mod_seterrno(mod, err);
1107 goto slotfail;
1108 }
1109 return (slotnode);
1110
1111 slotfail:
1112 topo_node_unbind(slotnode);
1113 return (NULL);
1114 }
1115
1116 /*
1117 * This is a convenience routine to allow enumerator modules to easily create
1118 * the necessary UFM node layout for the most common case, which will be a
1119 * single UFM with a single slot. This routine assumes that the caller has
1120 * already created the containing range via a call to topo_node_range_create().
1121 *
1122 * For more complex scenarios (like multiple slots per UFM), callers can set
1123 * the slotinfo param to NULL. In this case the ufm node will get created, but
1124 * it will skip creating the slot node - allowing the module to manually call
1125 * topo_mod_create_ufm_slot() to create custom UFM slots.
1126 */
1127 tnode_t *
topo_mod_create_ufm(topo_mod_t * mod,tnode_t * parent,topo_instance_t inst,const char * descr,topo_ufm_slot_info_t * slotinfo)1128 topo_mod_create_ufm(topo_mod_t *mod, tnode_t *parent, topo_instance_t inst,
1129 const char *descr, topo_ufm_slot_info_t *slotinfo)
1130 {
1131 nvlist_t *auth = NULL, *fmri = NULL;
1132 tnode_t *ufmnode, *slotnode;
1133 topo_pgroup_info_t pgi;
1134 int err, rc;
1135
1136 if ((auth = topo_mod_auth(mod, parent)) == NULL) {
1137 topo_mod_dprintf(mod, "topo_mod_auth() failed: %s",
1138 topo_mod_errmsg(mod));
1139 /* errno set */
1140 return (NULL);
1141 }
1142
1143 if ((fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION,
1144 UFM, inst, NULL, auth, NULL, NULL, NULL)) ==
1145 NULL) {
1146 nvlist_free(auth);
1147 topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
1148 topo_mod_errmsg(mod));
1149 /* errno set */
1150 return (NULL);
1151 }
1152
1153 if ((ufmnode = topo_node_bind(mod, parent, UFM, inst, fmri)) == NULL) {
1154 nvlist_free(auth);
1155 nvlist_free(fmri);
1156 topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
1157 topo_mod_errmsg(mod));
1158 /* errno set */
1159 return (NULL);
1160 }
1161
1162 /* Create authority and system pgroups */
1163 topo_pgroup_hcset(ufmnode, auth);
1164 nvlist_free(auth);
1165 nvlist_free(fmri);
1166
1167 /* Just inherit the parent's FRU */
1168 if (topo_node_fru_set(ufmnode, NULL, 0, &err) != 0) {
1169 topo_mod_dprintf(mod, "failed to set FRU on %s: %s", UFM,
1170 topo_strerror(err));
1171 (void) topo_mod_seterrno(mod, err);
1172 goto ufmfail;
1173 }
1174
1175 pgi.tpi_name = TOPO_PGROUP_UFM;
1176 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1177 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1178 pgi.tpi_version = TOPO_VERSION;
1179 rc = topo_pgroup_create(ufmnode, &pgi, &err);
1180
1181 if (rc == 0)
1182 rc += topo_prop_set_string(ufmnode, TOPO_PGROUP_UFM,
1183 TOPO_PROP_UFM_DESCR, TOPO_PROP_IMMUTABLE, descr, &err);
1184
1185 if (rc != 0) {
1186 topo_mod_dprintf(mod, "error setting properties on %s node",
1187 UFM);
1188 (void) topo_mod_seterrno(mod, err);
1189 goto ufmfail;
1190 }
1191
1192 if (slotinfo != NULL) {
1193 if (topo_node_range_create(mod, ufmnode, SLOT, 0, 0) < 0) {
1194 topo_mod_dprintf(mod, "error creating %s range", SLOT);
1195 goto ufmfail;
1196 }
1197 slotnode = topo_mod_create_ufm_slot(mod, ufmnode, slotinfo);
1198
1199 if (slotnode == NULL)
1200 goto ufmfail;
1201 }
1202 return (ufmnode);
1203
1204 ufmfail:
1205 topo_node_unbind(ufmnode);
1206 return (NULL);
1207 }
1208