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