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