xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_mod.c (revision 9a5d73e03cd3312ddb571a748c40a63c58bd66e5)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Topology Plugin Modules
28  *
29  * Topology plugin modules are shared libraries that are dlopen'd and
30  * used to enumerate resources in the system and export per-node method
31  * operations.
32  *
33  * They are loaded by our builtin scheme-specific plugins, other modules or
34  * by processing a topo map XML file to enumerate and create nodes for
35  * resources that are present in the system.  They may also export a set of
36  * topology node specific methods that can be invoked directly via
37  * topo_method_invoke() or indirectly via the
38  * topo_prop_get* family of functions to access dynamic property data.
39  *
40  * Module Plugin API
41  *
42  * Enumerators must provide entry points for initialization and clean-up
43  * (_topo_init() and _topo_fini()).  In their _topo_init() function, an
44  * enumerator should register (topo_mod_register()) its enumeration callback
45  * and allocate resources required for a subsequent call to the callback.
46  * Optionally, methods may also be registered with topo_method_register().
47  *
48  * In its enumeration callback routine, the module should search for resources
49  * within its realm of responsibility and create any node ranges,
50  * topo_node_range_create() and nodes, topo_node_bind().  The Enumerator
51  * module is handed a node to which it may begin attaching additional
52  * topology nodes.  The enumerator may only access those nodes within its
53  * current scope of operation: the node passed into its enumeration op and
54  * any nodes it creates during enumeration.  If the enumerator requires walker-
55  * style access to these nodes, it must use
56  * topo_mod_walk_init()/topo_walk_step()/topo_walk_fini().
57  *
58  * If additional helper modules need to be loaded to complete the enumeration
59  * the module may do so by calling topo_mod_load().  Enumeration may then
60  * continue with the module handing off enumeration to its helper module
61  * by calling topo_mod_enumerate().  Similarly, a module may call
62  * topo_mod_enummap() to kick-off enumeration according to a given XML
63  * topology map file.  A module *may* not cause re-entrance to itself
64  * via either of these interfaces.  If re-entry is detected an error
65  * will be returned (ETOPO_ENUM_RECURS).
66  *
67  * If the module registers a release callback, it will be called on a node
68  * by node basis during topo_snap_rele().  Any private node data may be
69  * deallocated or methods unregistered at that time.  Global module data
70  * should be cleaned up before or at the time that the module _topo_fini
71  * entry point is called.
72  *
73  * Module entry points and method invocations are guaranteed to be
74  * single-threaded for a given snapshot handle.  Applications may have
75  * more than one topology snapshot open at a time.  This means that the
76  * module operations and methods may be called for different module handles
77  * (topo_mod_t) asynchronously.  The enumerator should not use static or
78  * global data structures that may become inconsistent in this situation.
79  * Method operations may be re-entrant if the module invokes one of its own
80  * methods directly or via dynamic property access.  Caution should be
81  * exercised with method operations to insure that data remains consistent
82  * within the module and that deadlocks can not occur.
83  */
84 
85 #include <pthread.h>
86 #include <assert.h>
87 #include <errno.h>
88 #include <dirent.h>
89 #include <limits.h>
90 #include <alloca.h>
91 #include <unistd.h>
92 #include <stdio.h>
93 #include <sys/param.h>
94 #include <sys/utsname.h>
95 #include <sys/smbios.h>
96 #include <sys/fm/protocol.h>
97 
98 #include <topo_alloc.h>
99 #include <topo_error.h>
100 #include <topo_file.h>
101 #include <topo_fmri.h>
102 #include <topo_module.h>
103 #include <topo_method.h>
104 #include <topo_string.h>
105 #include <topo_subr.h>
106 #include <topo_tree.h>
107 
108 #define	PLUGIN_PATH	"plugins"
109 #define	PLUGIN_PATH_LEN	MAXNAMELEN + 5
110 
111 topo_mod_t *
112 topo_mod_load(topo_mod_t *pmod, const char *name,
113     topo_version_t version)
114 {
115 	char *path;
116 	char file[PLUGIN_PATH_LEN];
117 	topo_mod_t *mod = NULL;
118 	topo_hdl_t *thp;
119 
120 	thp = pmod->tm_hdl;
121 
122 	/*
123 	 * Already loaded, topo_mod_lookup will bump the ref count
124 	 */
125 	if ((mod = topo_mod_lookup(thp, name, 1)) != NULL) {
126 		if (mod->tm_info->tmi_version != version) {
127 			topo_mod_rele(mod);
128 			(void) topo_mod_seterrno(pmod, ETOPO_MOD_VER);
129 			return (NULL);
130 		}
131 		return (mod);
132 	}
133 
134 	(void) snprintf(file, PLUGIN_PATH_LEN, "%s/%s.so",
135 	    PLUGIN_PATH, name);
136 	path = topo_search_path(pmod, thp->th_rootdir, (const char *)file);
137 	if (path == NULL ||
138 	    (mod = topo_modhash_load(thp, name, path, &topo_rtld_ops, version))
139 	    == NULL) { /* returned with mod held */
140 			topo_mod_strfree(pmod, path);
141 			(void) topo_mod_seterrno(pmod, topo_hdl_errno(thp) ?
142 			    topo_hdl_errno(thp) : ETOPO_MOD_NOENT);
143 			return (NULL);
144 	}
145 
146 	topo_mod_strfree(pmod, path);
147 
148 	return (mod);
149 }
150 
151 void
152 topo_mod_unload(topo_mod_t *mod)
153 {
154 	topo_mod_rele(mod);
155 }
156 
157 static int
158 set_register_error(topo_mod_t *mod, int err)
159 {
160 	if (mod->tm_info != NULL)
161 		topo_mod_unregister(mod);
162 
163 	topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
164 	    "module registration failed for %s: %s\n",
165 	    mod->tm_name, topo_strerror(err));
166 
167 	return (topo_mod_seterrno(mod, err));
168 }
169 
170 int
171 topo_mod_register(topo_mod_t *mod, const topo_modinfo_t *mip,
172     topo_version_t version)
173 {
174 
175 	assert(!(mod->tm_flags & TOPO_MOD_FINI ||
176 	    mod->tm_flags & TOPO_MOD_REG));
177 
178 	if (version != TOPO_VERSION)
179 		return (set_register_error(mod, EMOD_VER_ABI));
180 
181 	if ((mod->tm_info = topo_mod_zalloc(mod, sizeof (topo_imodinfo_t)))
182 	    == NULL)
183 		return (set_register_error(mod, EMOD_NOMEM));
184 	if ((mod->tm_info->tmi_ops = topo_mod_alloc(mod,
185 	    sizeof (topo_modops_t))) == NULL)
186 		return (set_register_error(mod, EMOD_NOMEM));
187 
188 	mod->tm_info->tmi_desc = topo_mod_strdup(mod, mip->tmi_desc);
189 	if (mod->tm_info->tmi_desc == NULL)
190 		return (set_register_error(mod, EMOD_NOMEM));
191 
192 	mod->tm_info->tmi_scheme = topo_mod_strdup(mod, mip->tmi_scheme);
193 	if (mod->tm_info->tmi_scheme == NULL)
194 		return (set_register_error(mod, EMOD_NOMEM));
195 
196 
197 	mod->tm_info->tmi_version = (topo_version_t)mip->tmi_version;
198 	mod->tm_info->tmi_ops->tmo_enum = mip->tmi_ops->tmo_enum;
199 	mod->tm_info->tmi_ops->tmo_release = mip->tmi_ops->tmo_release;
200 
201 	mod->tm_flags |= TOPO_MOD_REG;
202 
203 	topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
204 	    "registration succeeded for %s\n", mod->tm_name);
205 
206 	return (0);
207 }
208 
209 void
210 topo_mod_unregister(topo_mod_t *mod)
211 {
212 	if (mod->tm_info == NULL)
213 		return;
214 
215 	assert(!(mod->tm_flags & TOPO_MOD_FINI));
216 
217 	mod->tm_flags &= ~TOPO_MOD_REG;
218 
219 	if (mod->tm_info == NULL)
220 		return;
221 
222 	if (mod->tm_info->tmi_ops != NULL)
223 		topo_mod_free(mod, mod->tm_info->tmi_ops,
224 		    sizeof (topo_modops_t));
225 	if (mod->tm_info->tmi_desc != NULL)
226 		topo_mod_strfree(mod, mod->tm_info->tmi_desc);
227 	if (mod->tm_info->tmi_scheme != NULL)
228 		topo_mod_strfree(mod, mod->tm_info->tmi_scheme);
229 
230 	topo_mod_free(mod, mod->tm_info, sizeof (topo_imodinfo_t));
231 
232 	mod->tm_info = NULL;
233 }
234 
235 int
236 topo_mod_enumerate(topo_mod_t *mod, tnode_t *node, const char *enum_name,
237     const char *name, topo_instance_t min, topo_instance_t max, void *data)
238 {
239 	int err = 0;
240 	topo_mod_t *enum_mod;
241 
242 	assert(mod->tm_flags & TOPO_MOD_REG);
243 
244 	if ((enum_mod = topo_mod_lookup(mod->tm_hdl, enum_name, 0)) == NULL)
245 		return (topo_mod_seterrno(mod, EMOD_MOD_NOENT));
246 
247 	topo_node_hold(node);
248 
249 	topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "module %s enumerating "
250 	    "node %s=%d\n", (char *)mod->tm_name, (char *)node->tn_name,
251 	    node->tn_instance);
252 
253 	topo_mod_enter(enum_mod);
254 	err = enum_mod->tm_info->tmi_ops->tmo_enum(enum_mod, node, name, min,
255 	    max, enum_mod->tm_priv, data);
256 	topo_mod_exit(enum_mod);
257 
258 	if (err != 0) {
259 		(void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
260 
261 		topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
262 		    "module %s failed enumeration for "
263 		    " node %s=%d\n", (char *)mod->tm_name,
264 		    (char *)node->tn_name, node->tn_instance);
265 
266 		topo_node_rele(node);
267 		return (-1);
268 	}
269 
270 	topo_node_rele(node);
271 
272 	return (0);
273 }
274 
275 int
276 topo_mod_enummap(topo_mod_t *mod, tnode_t *node, const char *name,
277     const char *scheme)
278 {
279 	return (topo_file_load(mod, node, (char *)name, (char *)scheme, 0));
280 }
281 
282 static nvlist_t *
283 set_fmri_err(topo_mod_t *mod, int err)
284 {
285 	(void) topo_mod_seterrno(mod, err);
286 	return (NULL);
287 }
288 
289 nvlist_t *
290 topo_mod_hcfmri(topo_mod_t *mod, tnode_t *pnode, int version, const char *name,
291     topo_instance_t inst, nvlist_t *hc_specific, nvlist_t *auth,
292     const char *part, const char *rev, const char *serial)
293 {
294 	int err;
295 	nvlist_t *pfmri = NULL, *fmri = NULL, *args = NULL;
296 	nvlist_t *nfp = NULL;
297 	char *lpart, *lrev, *lserial;
298 
299 	if (version != FM_HC_SCHEME_VERSION)
300 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
301 
302 	/*
303 	 * Do we have any args to pass?
304 	 */
305 	if (pnode != NULL || auth != NULL || part != NULL || rev != NULL ||
306 	    serial != NULL || hc_specific != NULL) {
307 		if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
308 			return (set_fmri_err(mod, EMOD_FMRI_NVL));
309 	}
310 
311 	if (pnode != NULL) {
312 		if (topo_node_resource(pnode, &pfmri, &err) < 0) {
313 			nvlist_free(args);
314 			return (set_fmri_err(mod, EMOD_NVL_INVAL));
315 		}
316 
317 		if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
318 		    pfmri) != 0) {
319 			nvlist_free(pfmri);
320 			nvlist_free(args);
321 			return (set_fmri_err(mod, EMOD_FMRI_NVL));
322 		}
323 		nvlist_free(pfmri);
324 	}
325 
326 	/*
327 	 * Add optional payload
328 	 */
329 	if (auth != NULL)
330 		(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, auth);
331 	if (part != NULL) {
332 		lpart = topo_cleanup_auth_str(mod->tm_hdl, part);
333 		if (lpart != NULL) {
334 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
335 			    lpart);
336 			topo_hdl_free(mod->tm_hdl, lpart, strlen(lpart) + 1);
337 		} else {
338 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
339 			    part);
340 		}
341 	}
342 	if (rev != NULL) {
343 		lrev = topo_cleanup_auth_str(mod->tm_hdl, rev);
344 		if (lrev != NULL) {
345 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
346 			    lrev);
347 			topo_hdl_free(mod->tm_hdl, lrev, strlen(lrev) + 1);
348 		} else {
349 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
350 			    rev);
351 		}
352 	}
353 	if (serial != NULL) {
354 		lserial = topo_cleanup_auth_str(mod->tm_hdl, serial);
355 		if (lserial != NULL) {
356 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
357 			    lserial);
358 			topo_hdl_free(mod->tm_hdl, lserial,
359 			    strlen(lserial) + 1);
360 		} else {
361 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
362 			    serial);
363 		}
364 	}
365 	if (hc_specific != NULL)
366 		(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_HCS,
367 		    hc_specific);
368 
369 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_HC, name, inst,
370 	    args, &err)) == NULL) {
371 		nvlist_free(args);
372 		return (set_fmri_err(mod, err));
373 	}
374 
375 	nvlist_free(args);
376 
377 	(void) topo_mod_nvdup(mod, fmri, &nfp);
378 	nvlist_free(fmri);
379 
380 	return (nfp);
381 }
382 
383 nvlist_t *
384 topo_mod_devfmri(topo_mod_t *mod, int version, const char *dev_path,
385     const char *devid)
386 {
387 	int err;
388 	nvlist_t *fmri, *args;
389 	nvlist_t *nfp = NULL;
390 
391 	if (version != FM_DEV_SCHEME_VERSION)
392 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
393 
394 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
395 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
396 
397 	if (nvlist_add_string(args, FM_FMRI_DEV_PATH, dev_path) != 0) {
398 		nvlist_free(args);
399 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
400 	}
401 
402 	(void) nvlist_add_string(args, FM_FMRI_DEV_ID, devid);
403 
404 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_DEV,
405 	    FM_FMRI_SCHEME_DEV, 0, args, &err)) == NULL) {
406 		nvlist_free(args);
407 		return (set_fmri_err(mod, err));
408 	}
409 
410 	nvlist_free(args);
411 
412 	(void) topo_mod_nvdup(mod, fmri, &nfp);
413 	nvlist_free(fmri);
414 
415 	return (nfp);
416 }
417 
418 nvlist_t *
419 topo_mod_cpufmri(topo_mod_t *mod, int version, uint32_t cpu_id, uint8_t cpumask,
420     const char *serial)
421 {
422 	int err;
423 	nvlist_t *fmri = NULL, *args = NULL;
424 	nvlist_t *nfp = NULL;
425 
426 	if (version != FM_CPU_SCHEME_VERSION)
427 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
428 
429 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
430 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
431 
432 	if (nvlist_add_uint32(args, FM_FMRI_CPU_ID, cpu_id) != 0) {
433 		nvlist_free(args);
434 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
435 	}
436 
437 	/*
438 	 * Add optional payload
439 	 */
440 	(void) nvlist_add_uint8(args, FM_FMRI_CPU_MASK, cpumask);
441 	(void) nvlist_add_string(args, FM_FMRI_CPU_SERIAL_ID, serial);
442 
443 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_CPU,
444 	    FM_FMRI_SCHEME_CPU, 0, args, &err)) == NULL) {
445 		nvlist_free(args);
446 		return (set_fmri_err(mod, err));
447 	}
448 
449 	nvlist_free(args);
450 
451 	(void) topo_mod_nvdup(mod, fmri, &nfp);
452 	nvlist_free(fmri);
453 
454 	return (nfp);
455 }
456 
457 nvlist_t *
458 topo_mod_memfmri(topo_mod_t *mod, int version, uint64_t pa, uint64_t offset,
459 	const char *unum, int flags)
460 {
461 	int err;
462 	nvlist_t *args = NULL, *fmri = NULL;
463 	nvlist_t *nfp = NULL;
464 
465 	if (version != FM_MEM_SCHEME_VERSION)
466 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
467 
468 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
469 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
470 
471 	err = nvlist_add_string(args, FM_FMRI_MEM_UNUM, unum);
472 		nvlist_free(args);
473 	if (flags & TOPO_MEMFMRI_PA)
474 		err |= nvlist_add_uint64(args, FM_FMRI_MEM_PHYSADDR, pa);
475 	if (flags & TOPO_MEMFMRI_OFFSET)
476 		err |= nvlist_add_uint64(args, FM_FMRI_MEM_OFFSET, offset);
477 
478 	if (err != 0) {
479 		nvlist_free(args);
480 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
481 	}
482 
483 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MEM,
484 	    FM_FMRI_SCHEME_MEM, 0, args, &err)) == NULL) {
485 		nvlist_free(args);
486 		return (set_fmri_err(mod, err));
487 	}
488 
489 	nvlist_free(args);
490 
491 	(void) topo_mod_nvdup(mod, fmri, &nfp);
492 	nvlist_free(fmri);
493 
494 	return (nfp);
495 
496 }
497 
498 nvlist_t *
499 topo_mod_pkgfmri(topo_mod_t *mod, int version, const char *path)
500 {
501 	int err;
502 	nvlist_t *fmri = NULL, *args = NULL;
503 	nvlist_t *nfp = NULL;
504 
505 	if (version != FM_PKG_SCHEME_VERSION)
506 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
507 
508 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
509 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
510 
511 	if (nvlist_add_string(args, "path", path) != 0) {
512 		nvlist_free(args);
513 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
514 	}
515 
516 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_PKG,
517 	    FM_FMRI_SCHEME_PKG, 0, args, &err)) == NULL) {
518 		nvlist_free(args);
519 		return (set_fmri_err(mod, err));
520 	}
521 
522 	nvlist_free(args);
523 
524 	(void) topo_mod_nvdup(mod, fmri, &nfp);
525 	nvlist_free(fmri);
526 
527 	return (nfp);
528 }
529 
530 nvlist_t *
531 topo_mod_modfmri(topo_mod_t *mod, int version, const char *driver)
532 {
533 	int err;
534 	nvlist_t *fmri = NULL, *args = NULL;
535 	nvlist_t *nfp = NULL;
536 
537 	if (version != FM_MOD_SCHEME_VERSION)
538 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
539 
540 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
541 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
542 
543 	if (nvlist_add_string(args, "DRIVER", driver) != 0) {
544 		nvlist_free(args);
545 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
546 	}
547 
548 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MOD,
549 	    FM_FMRI_SCHEME_MOD, 0, args, &err)) == NULL) {
550 		nvlist_free(args);
551 		return (set_fmri_err(mod, err));
552 	}
553 
554 	nvlist_free(args);
555 
556 	(void) topo_mod_nvdup(mod, fmri, &nfp);
557 	nvlist_free(fmri);
558 
559 	return (nfp);
560 }
561 
562 int
563 topo_mod_str2nvl(topo_mod_t *mod, const char *fmristr, nvlist_t **fmri)
564 {
565 	int err;
566 	nvlist_t *np = NULL;
567 
568 	if (topo_fmri_str2nvl(mod->tm_hdl, fmristr, &np, &err) < 0)
569 		return (topo_mod_seterrno(mod, err));
570 
571 	if (topo_mod_nvdup(mod, np, fmri) < 0) {
572 		nvlist_free(np);
573 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
574 	}
575 
576 	nvlist_free(np);
577 
578 	return (0);
579 }
580 
581 int
582 topo_mod_nvl2str(topo_mod_t *mod, nvlist_t *fmri, char **fmristr)
583 {
584 	int err;
585 	char *sp;
586 
587 	if (topo_fmri_nvl2str(mod->tm_hdl, fmri, &sp, &err) < 0)
588 		return (topo_mod_seterrno(mod, err));
589 
590 	if ((*fmristr = topo_mod_strdup(mod, sp)) == NULL) {
591 		topo_hdl_strfree(mod->tm_hdl, sp);
592 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
593 	}
594 
595 	topo_hdl_strfree(mod->tm_hdl, sp);
596 
597 	return (0);
598 }
599 
600 void *
601 topo_mod_getspecific(topo_mod_t *mod)
602 {
603 	return (mod->tm_priv);
604 }
605 
606 void
607 topo_mod_setspecific(topo_mod_t *mod, void *data)
608 {
609 	mod->tm_priv = data;
610 }
611 
612 void
613 topo_mod_setdebug(topo_mod_t *mod)
614 {
615 	mod->tm_debug = 1;
616 }
617 
618 ipmi_handle_t *
619 topo_mod_ipmi_hold(topo_mod_t *mod)
620 {
621 	topo_hdl_t *thp = mod->tm_hdl;
622 	int err;
623 	char *errmsg;
624 
625 	(void) pthread_mutex_lock(&thp->th_ipmi_lock);
626 	if (thp->th_ipmi == NULL) {
627 		if ((thp->th_ipmi = ipmi_open(&err, &errmsg)) == NULL) {
628 			topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
629 			    "ipmi_open() failed: %s (ipmi errno=%d)", errmsg,
630 			    err);
631 			(void) pthread_mutex_unlock(&thp->th_ipmi_lock);
632 		}
633 	}
634 
635 
636 	return (thp->th_ipmi);
637 }
638 
639 void
640 topo_mod_ipmi_rele(topo_mod_t *mod)
641 {
642 	topo_hdl_t *thp = mod->tm_hdl;
643 
644 	(void) pthread_mutex_unlock(&thp->th_ipmi_lock);
645 }
646 
647 di_node_t
648 topo_mod_devinfo(topo_mod_t *mod)
649 {
650 	return (topo_hdl_devinfo(mod->tm_hdl));
651 }
652 
653 di_prom_handle_t
654 topo_mod_prominfo(topo_mod_t *mod)
655 {
656 	return (topo_hdl_prominfo(mod->tm_hdl));
657 }
658 
659 void
660 topo_mod_clrdebug(topo_mod_t *mod)
661 {
662 	mod->tm_debug = 0;
663 }
664 
665 /*PRINTFLIKE2*/
666 void
667 topo_mod_dprintf(topo_mod_t *mod, const char *format, ...)
668 {
669 	va_list alist;
670 
671 	if (mod->tm_debug == 0)
672 		return;
673 
674 	va_start(alist, format);
675 	topo_vdprintf(mod->tm_hdl, TOPO_DBG_MOD, (const char *)mod->tm_name,
676 	    format, alist);
677 	va_end(alist);
678 }
679 
680 static char *
681 topo_mod_product(topo_mod_t *mod)
682 {
683 	return (topo_mod_strdup(mod, mod->tm_hdl->th_product));
684 }
685 
686 static char *
687 topo_mod_server(topo_mod_t *mod)
688 {
689 	static struct utsname uts;
690 
691 	(void) uname(&uts);
692 	return (topo_mod_strdup(mod, uts.nodename));
693 }
694 
695 static char *
696 topo_mod_csn(topo_mod_t *mod)
697 {
698 	char csn[MAXNAMELEN];
699 	di_prom_handle_t promh = DI_PROM_HANDLE_NIL;
700 	di_node_t rooth = DI_NODE_NIL;
701 	char *bufp, *str;
702 	smbios_hdl_t *shp;
703 	smbios_system_t s1;
704 	smbios_info_t s2;
705 	id_t id;
706 
707 	if ((shp = smbios_open(NULL, SMB_VERSION, 0, NULL)) != NULL) {
708 		if ((id = smbios_info_system(shp, &s1)) != SMB_ERR &&
709 		    smbios_info_common(shp, id, &s2) != SMB_ERR) {
710 			(void) strlcpy(csn, s2.smbi_serial, MAXNAMELEN);
711 		}
712 		smbios_close(shp);
713 
714 		if (strcmp(csn, SMB_DEFAULT1) == 0 ||
715 		    strcmp(csn, SMB_DEFAULT2) == 0)
716 			return (NULL);
717 
718 		/*
719 		 * Terminate CSN at the first white space
720 		 */
721 		if ((str = strchr(csn, ' ')) != NULL)
722 			*str = '\0';
723 
724 	} else if ((rooth = topo_mod_devinfo(mod)) != DI_NODE_NIL &&
725 	    (promh = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) {
726 		if (di_prom_prop_lookup_bytes(promh, rooth, "chassis-sn",
727 		    (unsigned char **)&bufp) != -1) {
728 			(void) strlcpy(csn, bufp, MAXNAMELEN);
729 		} else {
730 			return (NULL);
731 		}
732 	} else {
733 		return (NULL);
734 	}
735 
736 
737 	return (topo_cleanup_auth_str(mod->tm_hdl, csn));
738 }
739 
740 nvlist_t *
741 topo_mod_auth(topo_mod_t *mod, tnode_t *pnode)
742 {
743 	int err;
744 	char *prod = NULL;
745 	char *csn = NULL;
746 	char *server = NULL;
747 	nvlist_t *auth;
748 
749 	if ((err = topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME)) != 0) {
750 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
751 		return (NULL);
752 	}
753 
754 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
755 	    FM_FMRI_AUTH_PRODUCT, &prod, &err);
756 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
757 	    FM_FMRI_AUTH_CHASSIS, &csn, &err);
758 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
759 	    FM_FMRI_AUTH_SERVER, &server, &err);
760 
761 	/*
762 	 * Let's do this the hard way
763 	 */
764 	if (prod == NULL)
765 		prod = topo_mod_product(mod);
766 	if (csn == NULL)
767 		csn = topo_mod_csn(mod);
768 	if (server == NULL) {
769 		server = topo_mod_server(mod);
770 	}
771 
772 	/*
773 	 * No luck, return NULL
774 	 */
775 	if (!prod && !server && !csn) {
776 		nvlist_free(auth);
777 		return (NULL);
778 	}
779 
780 	err = 0;
781 	if (prod != NULL) {
782 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, prod);
783 		topo_mod_strfree(mod, prod);
784 	}
785 	if (server != NULL) {
786 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, server);
787 		topo_mod_strfree(mod, server);
788 	}
789 	if (csn != NULL) {
790 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, csn);
791 		topo_mod_strfree(mod, csn);
792 	}
793 
794 	if (err != 0) {
795 		nvlist_free(auth);
796 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
797 		return (NULL);
798 	}
799 
800 	return (auth);
801 }
802 
803 topo_walk_t *
804 topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f,
805     void *pdata, int *errp)
806 {
807 	topo_walk_t *wp;
808 	topo_hdl_t *thp = mod->tm_hdl;
809 
810 	if ((wp = topo_node_walk_init(thp, mod, node, (int (*)())cb_f, pdata,
811 	    errp)) == NULL)
812 		return (NULL);
813 
814 	return (wp);
815 }
816