xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_mod.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  * Copyright 2007 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));
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 			return (set_fmri_err(mod, EMOD_NVL_INVAL));
315 
316 		if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
317 		    pfmri) != 0) {
318 			nvlist_free(pfmri);
319 			nvlist_free(args);
320 			return (set_fmri_err(mod, EMOD_FMRI_NVL));
321 		}
322 		nvlist_free(pfmri);
323 	}
324 
325 	/*
326 	 * Add optional payload
327 	 */
328 	if (auth != NULL)
329 		(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, auth);
330 	if (part != NULL)
331 		(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART, part);
332 	if (rev != NULL)
333 		(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV, rev);
334 	if (serial != NULL)
335 		(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
336 		    serial);
337 	if (hc_specific != NULL)
338 		(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_HCS,
339 		    hc_specific);
340 
341 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_HC, name, inst,
342 	    args, &err)) == NULL) {
343 		nvlist_free(args);
344 		return (set_fmri_err(mod, err));
345 	}
346 
347 	nvlist_free(args);
348 
349 	(void) topo_mod_nvdup(mod, fmri, &nfp);
350 	nvlist_free(fmri);
351 
352 	return (nfp);
353 }
354 
355 nvlist_t *
356 topo_mod_devfmri(topo_mod_t *mod, int version, const char *dev_path,
357     const char *devid)
358 {
359 	int err;
360 	nvlist_t *fmri, *args;
361 	nvlist_t *nfp = NULL;
362 
363 	if (version != FM_DEV_SCHEME_VERSION)
364 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
365 
366 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
367 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
368 
369 	if (nvlist_add_string(args, FM_FMRI_DEV_PATH, dev_path) != 0) {
370 		nvlist_free(args);
371 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
372 	}
373 
374 	(void) nvlist_add_string(args, FM_FMRI_DEV_ID, devid);
375 
376 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_DEV,
377 	    FM_FMRI_SCHEME_DEV, 0, args, &err)) == NULL) {
378 		nvlist_free(args);
379 		return (set_fmri_err(mod, err));
380 	}
381 
382 	nvlist_free(args);
383 
384 	(void) topo_mod_nvdup(mod, fmri, &nfp);
385 	nvlist_free(fmri);
386 
387 	return (nfp);
388 }
389 
390 nvlist_t *
391 topo_mod_cpufmri(topo_mod_t *mod, int version, uint32_t cpu_id, uint8_t cpumask,
392     const char *serial)
393 {
394 	int err;
395 	nvlist_t *fmri = NULL, *args = NULL;
396 	nvlist_t *nfp = NULL;
397 
398 	if (version != FM_CPU_SCHEME_VERSION)
399 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
400 
401 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
402 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
403 
404 	if (nvlist_add_uint32(args, FM_FMRI_CPU_ID, cpu_id) != 0) {
405 		nvlist_free(args);
406 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
407 	}
408 
409 	/*
410 	 * Add optional payload
411 	 */
412 	(void) nvlist_add_uint8(args, FM_FMRI_CPU_MASK, cpumask);
413 	(void) nvlist_add_string(args, FM_FMRI_CPU_SERIAL_ID, serial);
414 
415 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_CPU,
416 	    FM_FMRI_SCHEME_CPU, 0, args, &err)) == NULL) {
417 		nvlist_free(args);
418 		return (set_fmri_err(mod, err));
419 	}
420 
421 	nvlist_free(args);
422 
423 	(void) topo_mod_nvdup(mod, fmri, &nfp);
424 	nvlist_free(fmri);
425 
426 	return (nfp);
427 }
428 
429 nvlist_t *
430 topo_mod_memfmri(topo_mod_t *mod, int version, uint64_t pa, uint64_t offset,
431 	const char *unum, int flags)
432 {
433 	int err;
434 	nvlist_t *args = NULL, *fmri = NULL;
435 	nvlist_t *nfp = NULL;
436 
437 	if (version != FM_MEM_SCHEME_VERSION)
438 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
439 
440 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
441 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
442 
443 	err = nvlist_add_string(args, FM_FMRI_MEM_UNUM, unum);
444 		nvlist_free(args);
445 	if (flags & TOPO_MEMFMRI_PA)
446 		err |= nvlist_add_uint64(args, FM_FMRI_MEM_PHYSADDR, pa);
447 	if (flags & TOPO_MEMFMRI_OFFSET)
448 		err |= nvlist_add_uint64(args, FM_FMRI_MEM_OFFSET, offset);
449 
450 	if (err != 0) {
451 		nvlist_free(args);
452 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
453 	}
454 
455 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MEM,
456 	    FM_FMRI_SCHEME_MEM, 0, args, &err)) == NULL) {
457 		nvlist_free(args);
458 		return (set_fmri_err(mod, err));
459 	}
460 
461 	nvlist_free(args);
462 
463 	(void) topo_mod_nvdup(mod, fmri, &nfp);
464 	nvlist_free(fmri);
465 
466 	return (nfp);
467 
468 }
469 
470 nvlist_t *
471 topo_mod_pkgfmri(topo_mod_t *mod, int version, const char *path)
472 {
473 	int err;
474 	nvlist_t *fmri = NULL, *args = NULL;
475 	nvlist_t *nfp = NULL;
476 
477 	if (version != FM_PKG_SCHEME_VERSION)
478 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
479 
480 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
481 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
482 
483 	if (nvlist_add_string(args, "path", path) != 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_PKG,
489 	    FM_FMRI_SCHEME_PKG, 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 nvlist_t *
503 topo_mod_modfmri(topo_mod_t *mod, int version, const char *driver)
504 {
505 	int err;
506 	nvlist_t *fmri = NULL, *args = NULL;
507 	nvlist_t *nfp = NULL;
508 
509 	if (version != FM_MOD_SCHEME_VERSION)
510 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
511 
512 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
513 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
514 
515 	if (nvlist_add_string(args, "DRIVER", driver) != 0) {
516 		nvlist_free(args);
517 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
518 	}
519 
520 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MOD,
521 	    FM_FMRI_SCHEME_MOD, 0, args, &err)) == NULL) {
522 		nvlist_free(args);
523 		return (set_fmri_err(mod, err));
524 	}
525 
526 	nvlist_free(args);
527 
528 	(void) topo_mod_nvdup(mod, fmri, &nfp);
529 	nvlist_free(fmri);
530 
531 	return (nfp);
532 }
533 
534 int
535 topo_mod_str2nvl(topo_mod_t *mod, const char *fmristr, nvlist_t **fmri)
536 {
537 	int err;
538 	nvlist_t *np = NULL;
539 
540 	if (topo_fmri_str2nvl(mod->tm_hdl, fmristr, &np, &err) < 0)
541 		return (topo_mod_seterrno(mod, err));
542 
543 	if (topo_mod_nvdup(mod, np, fmri) < 0) {
544 		nvlist_free(np);
545 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
546 	}
547 
548 	nvlist_free(np);
549 
550 	return (0);
551 }
552 
553 int
554 topo_mod_nvl2str(topo_mod_t *mod, nvlist_t *fmri, char **fmristr)
555 {
556 	int err;
557 	char *sp;
558 
559 	if (topo_fmri_nvl2str(mod->tm_hdl, fmri, &sp, &err) < 0)
560 		return (topo_mod_seterrno(mod, err));
561 
562 	if ((*fmristr = topo_mod_strdup(mod, sp)) == NULL) {
563 		topo_hdl_strfree(mod->tm_hdl, sp);
564 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
565 	}
566 
567 	topo_hdl_strfree(mod->tm_hdl, sp);
568 
569 	return (0);
570 }
571 
572 void *
573 topo_mod_getspecific(topo_mod_t *mod)
574 {
575 	return (mod->tm_priv);
576 }
577 
578 void
579 topo_mod_setspecific(topo_mod_t *mod, void *data)
580 {
581 	mod->tm_priv = data;
582 }
583 
584 void
585 topo_mod_setdebug(topo_mod_t *mod)
586 {
587 	mod->tm_debug = 1;
588 }
589 
590 di_node_t
591 topo_mod_devinfo(topo_mod_t *mod)
592 {
593 	topo_hdl_t *thp = mod->tm_hdl;
594 
595 	if (thp->th_di == DI_NODE_NIL)
596 		thp->th_di = di_init("/", DINFOCPYALL);
597 
598 	return (thp->th_di);
599 }
600 
601 di_prom_handle_t
602 topo_mod_prominfo(topo_mod_t *mod)
603 {
604 	topo_hdl_t *thp = mod->tm_hdl;
605 
606 	if (thp->th_pi == DI_PROM_HANDLE_NIL)
607 		thp->th_pi = di_prom_init();
608 
609 	return (thp->th_pi);
610 }
611 
612 void
613 topo_mod_clrdebug(topo_mod_t *mod)
614 {
615 	mod->tm_debug = 0;
616 }
617 
618 /*PRINTFLIKE2*/
619 void
620 topo_mod_dprintf(topo_mod_t *mod, const char *format, ...)
621 {
622 	va_list alist;
623 
624 	if (mod->tm_debug == 0)
625 		return;
626 
627 	va_start(alist, format);
628 	topo_vdprintf(mod->tm_hdl, TOPO_DBG_MOD, (const char *)mod->tm_name,
629 	    format, alist);
630 	va_end(alist);
631 }
632 
633 static char *
634 topo_mod_product(topo_mod_t *mod)
635 {
636 	return (topo_mod_strdup(mod, mod->tm_hdl->th_product));
637 }
638 
639 static char *
640 topo_mod_server(topo_mod_t *mod)
641 {
642 	static struct utsname uts;
643 
644 	(void) uname(&uts);
645 	return (topo_mod_strdup(mod, uts.nodename));
646 }
647 
648 static char *
649 topo_mod_csn(topo_mod_t *mod)
650 {
651 	char csn[MAXNAMELEN];
652 	di_prom_handle_t promh = DI_PROM_HANDLE_NIL;
653 	di_node_t rooth = DI_NODE_NIL;
654 	char *bufp, *str;
655 	smbios_hdl_t *shp;
656 	smbios_system_t s1;
657 	smbios_info_t s2;
658 	id_t id;
659 
660 	if ((shp = smbios_open(NULL, SMB_VERSION, 0, NULL)) != NULL) {
661 		if ((id = smbios_info_system(shp, &s1)) != SMB_ERR &&
662 		    smbios_info_common(shp, id, &s2) != SMB_ERR) {
663 			(void) strlcpy(csn, s2.smbi_serial, MAXNAMELEN);
664 		}
665 		smbios_close(shp);
666 
667 		if (strcmp(csn, SMB_DEFAULT1) == 0 ||
668 		    strcmp(csn, SMB_DEFAULT2) == 0)
669 			return (NULL);
670 
671 		/*
672 		 * Terminate CSN at the first white space
673 		 */
674 		if ((str = strchr(csn, ' ')) != NULL)
675 			*str = '\0';
676 
677 	} else if ((rooth = topo_mod_devinfo(mod)) != DI_NODE_NIL &&
678 	    (promh = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) {
679 		if (di_prom_prop_lookup_bytes(promh, rooth, "chassis-sn",
680 		    (unsigned char **)&bufp) != -1) {
681 			(void) strlcpy(csn, bufp, MAXNAMELEN);
682 		} else {
683 			return (NULL);
684 		}
685 	} else {
686 		return (NULL);
687 	}
688 
689 
690 	return (topo_cleanup_auth_str(mod->tm_hdl, csn));
691 }
692 
693 nvlist_t *
694 topo_mod_auth(topo_mod_t *mod, tnode_t *pnode)
695 {
696 	int err;
697 	char *prod = NULL;
698 	char *csn = NULL;
699 	char *server = NULL;
700 	nvlist_t *auth;
701 
702 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
703 	    FM_FMRI_AUTH_PRODUCT, &prod, &err);
704 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
705 	    FM_FMRI_AUTH_CHASSIS, &csn, &err);
706 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
707 	    FM_FMRI_AUTH_SERVER, &server, &err);
708 
709 	/*
710 	 * Let's do this the hard way
711 	 */
712 	if (prod == NULL)
713 		prod = topo_mod_product(mod);
714 	if (csn == NULL)
715 		csn = topo_mod_csn(mod);
716 	if (server == NULL) {
717 		server = topo_mod_server(mod);
718 	}
719 
720 	/*
721 	 * No luck, return NULL
722 	 */
723 	if (!prod && !server && !csn)
724 		return (NULL);
725 
726 	if ((err = topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME)) != 0) {
727 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
728 		return (NULL);
729 	}
730 
731 	if (prod != NULL) {
732 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, prod);
733 		topo_mod_strfree(mod, prod);
734 	}
735 	if (server != NULL) {
736 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, server);
737 		topo_mod_strfree(mod, server);
738 	}
739 	if (csn != NULL) {
740 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, csn);
741 		topo_mod_strfree(mod, csn);
742 	}
743 
744 	if (err != 0) {
745 		nvlist_free(auth);
746 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
747 		return (NULL);
748 	}
749 
750 	return (auth);
751 }
752 
753 topo_walk_t *
754 topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f,
755     void *pdata, int *errp)
756 {
757 	topo_walk_t *wp;
758 	topo_hdl_t *thp = mod->tm_hdl;
759 
760 	if ((wp = topo_node_walk_init(thp, mod, node, (int (*)())cb_f, pdata,
761 	    errp)) == NULL)
762 		return (NULL);
763 
764 	return (wp);
765 }
766