1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright (c) 2018, Joyent, Inc.
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 <ctype.h>
94 #include <pcidb.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 	char *lpart, *lrev, *lserial;
300 
301 	if (version != FM_HC_SCHEME_VERSION)
302 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
303 
304 	/*
305 	 * Do we have any args to pass?
306 	 */
307 	if (pnode != NULL || auth != NULL || part != NULL || rev != NULL ||
308 	    serial != NULL || hc_specific != NULL) {
309 		if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
310 			return (set_fmri_err(mod, EMOD_FMRI_NVL));
311 	}
312 
313 	if (pnode != NULL) {
314 		if (topo_node_resource(pnode, &pfmri, &err) < 0) {
315 			nvlist_free(args);
316 			return (set_fmri_err(mod, EMOD_NVL_INVAL));
317 		}
318 
319 		if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
320 		    pfmri) != 0) {
321 			nvlist_free(pfmri);
322 			nvlist_free(args);
323 			return (set_fmri_err(mod, EMOD_FMRI_NVL));
324 		}
325 		nvlist_free(pfmri);
326 	}
327 
328 	/*
329 	 * Add optional payload
330 	 */
331 	if (auth != NULL)
332 		(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, auth);
333 	if (part != NULL) {
334 		lpart = topo_cleanup_auth_str(mod->tm_hdl, part);
335 		if (lpart != NULL) {
336 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
337 			    lpart);
338 			topo_hdl_free(mod->tm_hdl, lpart, strlen(lpart) + 1);
339 		} else {
340 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
341 			    "");
342 		}
343 	}
344 	if (rev != NULL) {
345 		lrev = topo_cleanup_auth_str(mod->tm_hdl, rev);
346 		if (lrev != NULL) {
347 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
348 			    lrev);
349 			topo_hdl_free(mod->tm_hdl, lrev, strlen(lrev) + 1);
350 		} else {
351 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
352 			    "");
353 		}
354 	}
355 	if (serial != NULL) {
356 		lserial = topo_cleanup_auth_str(mod->tm_hdl, serial);
357 		if (lserial != NULL) {
358 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
359 			    lserial);
360 			topo_hdl_free(mod->tm_hdl, lserial,
361 			    strlen(lserial) + 1);
362 		} else {
363 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
364 			    "");
365 		}
366 	}
367 	if (hc_specific != NULL)
368 		(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_HCS,
369 		    hc_specific);
370 
371 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_HC, name, inst,
372 	    args, &err)) == NULL) {
373 		nvlist_free(args);
374 		return (set_fmri_err(mod, err));
375 	}
376 
377 	nvlist_free(args);
378 
379 	(void) topo_mod_nvdup(mod, fmri, &nfp);
380 	nvlist_free(fmri);
381 
382 	return (nfp);
383 }
384 
385 nvlist_t *
386 topo_mod_devfmri(topo_mod_t *mod, int version, const char *dev_path,
387     const char *devid)
388 {
389 	int err;
390 	nvlist_t *fmri, *args;
391 	nvlist_t *nfp = NULL;
392 
393 	if (version != FM_DEV_SCHEME_VERSION)
394 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
395 
396 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
397 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
398 
399 	if (nvlist_add_string(args, FM_FMRI_DEV_PATH, dev_path) != 0) {
400 		nvlist_free(args);
401 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
402 	}
403 
404 	(void) nvlist_add_string(args, FM_FMRI_DEV_ID, devid);
405 
406 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_DEV,
407 	    FM_FMRI_SCHEME_DEV, 0, args, &err)) == NULL) {
408 		nvlist_free(args);
409 		return (set_fmri_err(mod, err));
410 	}
411 
412 	nvlist_free(args);
413 
414 	(void) topo_mod_nvdup(mod, fmri, &nfp);
415 	nvlist_free(fmri);
416 
417 	return (nfp);
418 }
419 
420 nvlist_t *
421 topo_mod_cpufmri(topo_mod_t *mod, int version, uint32_t cpu_id, uint8_t cpumask,
422     const char *serial)
423 {
424 	int err;
425 	nvlist_t *fmri = NULL, *args = NULL;
426 	nvlist_t *nfp = NULL;
427 
428 	if (version != FM_CPU_SCHEME_VERSION)
429 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
430 
431 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
432 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
433 
434 	if (nvlist_add_uint32(args, FM_FMRI_CPU_ID, cpu_id) != 0) {
435 		nvlist_free(args);
436 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
437 	}
438 
439 	/*
440 	 * Add optional payload
441 	 */
442 	(void) nvlist_add_uint8(args, FM_FMRI_CPU_MASK, cpumask);
443 	(void) nvlist_add_string(args, FM_FMRI_CPU_SERIAL_ID, serial);
444 
445 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_CPU,
446 	    FM_FMRI_SCHEME_CPU, 0, args, &err)) == NULL) {
447 		nvlist_free(args);
448 		return (set_fmri_err(mod, err));
449 	}
450 
451 	nvlist_free(args);
452 
453 	(void) topo_mod_nvdup(mod, fmri, &nfp);
454 	nvlist_free(fmri);
455 
456 	return (nfp);
457 }
458 
459 nvlist_t *
460 topo_mod_memfmri(topo_mod_t *mod, int version, uint64_t pa, uint64_t offset,
461     const char *unum, int flags)
462 {
463 	int err;
464 	nvlist_t *args = NULL, *fmri = NULL;
465 	nvlist_t *nfp = NULL;
466 
467 	if (version != FM_MEM_SCHEME_VERSION)
468 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
469 
470 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
471 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
472 
473 	err = nvlist_add_string(args, FM_FMRI_MEM_UNUM, unum);
474 		nvlist_free(args);
475 	if (flags & TOPO_MEMFMRI_PA)
476 		err |= nvlist_add_uint64(args, FM_FMRI_MEM_PHYSADDR, pa);
477 	if (flags & TOPO_MEMFMRI_OFFSET)
478 		err |= nvlist_add_uint64(args, FM_FMRI_MEM_OFFSET, offset);
479 
480 	if (err != 0) {
481 		nvlist_free(args);
482 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
483 	}
484 
485 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MEM,
486 	    FM_FMRI_SCHEME_MEM, 0, args, &err)) == NULL) {
487 		nvlist_free(args);
488 		return (set_fmri_err(mod, err));
489 	}
490 
491 	nvlist_free(args);
492 
493 	(void) topo_mod_nvdup(mod, fmri, &nfp);
494 	nvlist_free(fmri);
495 
496 	return (nfp);
497 
498 }
499 
500 nvlist_t *
501 topo_mod_pkgfmri(topo_mod_t *mod, int version, const char *path)
502 {
503 	int err;
504 	nvlist_t *fmri = NULL, *args = NULL;
505 	nvlist_t *nfp = NULL;
506 
507 	if (version != FM_PKG_SCHEME_VERSION)
508 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
509 
510 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
511 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
512 
513 	if (nvlist_add_string(args, "path", path) != 0) {
514 		nvlist_free(args);
515 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
516 	}
517 
518 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_PKG,
519 	    FM_FMRI_SCHEME_PKG, 0, args, &err)) == NULL) {
520 		nvlist_free(args);
521 		return (set_fmri_err(mod, err));
522 	}
523 
524 	nvlist_free(args);
525 
526 	(void) topo_mod_nvdup(mod, fmri, &nfp);
527 	nvlist_free(fmri);
528 
529 	return (nfp);
530 }
531 
532 nvlist_t *
533 topo_mod_modfmri(topo_mod_t *mod, int version, const char *driver)
534 {
535 	int err;
536 	nvlist_t *fmri = NULL, *args = NULL;
537 	nvlist_t *nfp = NULL;
538 
539 	if (version != FM_MOD_SCHEME_VERSION)
540 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
541 
542 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
543 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
544 
545 	if (nvlist_add_string(args, "DRIVER", driver) != 0) {
546 		nvlist_free(args);
547 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
548 	}
549 
550 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MOD,
551 	    FM_FMRI_SCHEME_MOD, 0, args, &err)) == NULL) {
552 		nvlist_free(args);
553 		return (set_fmri_err(mod, err));
554 	}
555 
556 	nvlist_free(args);
557 
558 	(void) topo_mod_nvdup(mod, fmri, &nfp);
559 	nvlist_free(fmri);
560 
561 	return (nfp);
562 }
563 
564 #define	_SWFMRI_ADD_STRING(nvl, name, val) \
565 	((val) ? (nvlist_add_string(nvl, name, val) != 0) : 0)
566 
567 nvlist_t *
568 topo_mod_swfmri(topo_mod_t *mod, int version,
569     char *obj_path, char *obj_root, nvlist_t *obj_pkg,
570     char *site_token, char *site_module, char *site_file, char *site_func,
571     int64_t site_line, char *ctxt_origin, char *ctxt_execname,
572     int64_t ctxt_pid, char *ctxt_zone, int64_t ctxt_ctid,
573     char **ctxt_stack, uint_t ctxt_stackdepth)
574 {
575 	nvlist_t *fmri, *args;
576 	nvlist_t *nfp = NULL;
577 	int err;
578 
579 	if (version != FM_SW_SCHEME_VERSION)
580 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
581 
582 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
583 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
584 
585 	err = 0;
586 	err |= _SWFMRI_ADD_STRING(args, "obj_path", obj_path);
587 	err |= _SWFMRI_ADD_STRING(args, "obj_root", obj_root);
588 	if (obj_pkg)
589 		err |= nvlist_add_nvlist(args, "obj_pkg", obj_pkg);
590 
591 	err |= _SWFMRI_ADD_STRING(args, "site_token", site_token);
592 	err |= _SWFMRI_ADD_STRING(args, "site_module", site_module);
593 	err |= _SWFMRI_ADD_STRING(args, "site_file", site_file);
594 	err |= _SWFMRI_ADD_STRING(args, "site_func", site_func);
595 	if (site_line != -1)
596 		err |= nvlist_add_int64(args, "site_line", site_line);
597 
598 	err |= _SWFMRI_ADD_STRING(args, "ctxt_origin", ctxt_origin);
599 	err |= _SWFMRI_ADD_STRING(args, "ctxt_execname", ctxt_execname);
600 	if (ctxt_pid != -1)
601 		err |= nvlist_add_int64(args, "ctxt_pid", ctxt_pid);
602 	err |= _SWFMRI_ADD_STRING(args, "ctxt_zone", ctxt_zone);
603 	if (ctxt_ctid != -1)
604 		err |= nvlist_add_int64(args, "ctxt_ctid", ctxt_ctid);
605 	if (ctxt_stack != NULL && ctxt_stackdepth != 0)
606 		err |= nvlist_add_string_array(args, "stack", ctxt_stack,
607 		    ctxt_stackdepth);
608 
609 	if (err) {
610 		nvlist_free(args);
611 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
612 	}
613 
614 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_SW,
615 	    FM_FMRI_SCHEME_SW, 0, args, &err)) == NULL) {
616 		nvlist_free(args);
617 		return (set_fmri_err(mod, err));
618 	}
619 
620 	nvlist_free(args);
621 
622 	(void) topo_mod_nvdup(mod, fmri, &nfp);
623 	nvlist_free(fmri);
624 
625 	return (nfp);
626 }
627 
628 int
629 topo_mod_str2nvl(topo_mod_t *mod, const char *fmristr, nvlist_t **fmri)
630 {
631 	int err;
632 	nvlist_t *np = NULL;
633 
634 	if (topo_fmri_str2nvl(mod->tm_hdl, fmristr, &np, &err) < 0)
635 		return (topo_mod_seterrno(mod, err));
636 
637 	if (topo_mod_nvdup(mod, np, fmri) < 0) {
638 		nvlist_free(np);
639 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
640 	}
641 
642 	nvlist_free(np);
643 
644 	return (0);
645 }
646 
647 int
648 topo_mod_nvl2str(topo_mod_t *mod, nvlist_t *fmri, char **fmristr)
649 {
650 	int err;
651 	char *sp;
652 
653 	if (topo_fmri_nvl2str(mod->tm_hdl, fmri, &sp, &err) < 0)
654 		return (topo_mod_seterrno(mod, err));
655 
656 	if ((*fmristr = topo_mod_strdup(mod, sp)) == NULL) {
657 		topo_hdl_strfree(mod->tm_hdl, sp);
658 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
659 	}
660 
661 	topo_hdl_strfree(mod->tm_hdl, sp);
662 
663 	return (0);
664 }
665 
666 void *
667 topo_mod_getspecific(topo_mod_t *mod)
668 {
669 	return (mod->tm_priv);
670 }
671 
672 void
673 topo_mod_setspecific(topo_mod_t *mod, void *data)
674 {
675 	mod->tm_priv = data;
676 }
677 
678 void
679 topo_mod_setdebug(topo_mod_t *mod)
680 {
681 	mod->tm_debug = 1;
682 }
683 
684 ipmi_handle_t *
685 topo_mod_ipmi_hold(topo_mod_t *mod)
686 {
687 	topo_hdl_t *thp = mod->tm_hdl;
688 	int err;
689 	char *errmsg;
690 
691 	(void) pthread_mutex_lock(&thp->th_ipmi_lock);
692 	if (thp->th_ipmi == NULL) {
693 		if ((thp->th_ipmi = ipmi_open(&err, &errmsg, IPMI_TRANSPORT_BMC,
694 		    NULL)) == NULL) {
695 			topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
696 			    "ipmi_open() failed: %s (ipmi errno=%d)", errmsg,
697 			    err);
698 			(void) pthread_mutex_unlock(&thp->th_ipmi_lock);
699 		}
700 	}
701 
702 
703 	return (thp->th_ipmi);
704 }
705 
706 void
707 topo_mod_ipmi_rele(topo_mod_t *mod)
708 {
709 	topo_hdl_t *thp = mod->tm_hdl;
710 
711 	(void) pthread_mutex_unlock(&thp->th_ipmi_lock);
712 }
713 
714 di_node_t
715 topo_mod_devinfo(topo_mod_t *mod)
716 {
717 	return (topo_hdl_devinfo(mod->tm_hdl));
718 }
719 
720 smbios_hdl_t *
721 topo_mod_smbios(topo_mod_t *mod)
722 {
723 	topo_hdl_t *thp = mod->tm_hdl;
724 
725 	if (thp->th_smbios == NULL)
726 		thp->th_smbios = smbios_open(NULL, SMB_VERSION, 0, NULL);
727 
728 	return (thp->th_smbios);
729 }
730 
731 di_prom_handle_t
732 topo_mod_prominfo(topo_mod_t *mod)
733 {
734 	return (topo_hdl_prominfo(mod->tm_hdl));
735 }
736 
737 pcidb_hdl_t *
738 topo_mod_pcidb(topo_mod_t *mod)
739 {
740 	topo_hdl_t *thp = mod->tm_hdl;
741 
742 	if (thp->th_pcidb == NULL)
743 		thp->th_pcidb = pcidb_open(PCIDB_VERSION);
744 
745 	return (thp->th_pcidb);
746 }
747 
748 void
749 topo_mod_clrdebug(topo_mod_t *mod)
750 {
751 	mod->tm_debug = 0;
752 }
753 
754 /*PRINTFLIKE2*/
755 void
756 topo_mod_dprintf(topo_mod_t *mod, const char *format, ...)
757 {
758 	va_list alist;
759 
760 	if (mod->tm_debug == 0)
761 		return;
762 
763 	va_start(alist, format);
764 	topo_vdprintf(mod->tm_hdl, TOPO_DBG_MOD, (const char *)mod->tm_name,
765 	    format, alist);
766 	va_end(alist);
767 }
768 
769 static char *
770 topo_mod_product(topo_mod_t *mod)
771 {
772 	return (topo_mod_strdup(mod, mod->tm_hdl->th_product));
773 }
774 
775 static char *
776 topo_mod_server(topo_mod_t *mod)
777 {
778 	static struct utsname uts;
779 
780 	(void) uname(&uts);
781 	return (topo_mod_strdup(mod, uts.nodename));
782 }
783 
784 static char *
785 topo_mod_psn(topo_mod_t *mod)
786 {
787 	smbios_hdl_t *shp;
788 	const char *psn;
789 
790 	if ((shp = topo_mod_smbios(mod)) == NULL ||
791 	    (psn = smbios_psn(shp)) == NULL)
792 		return (NULL);
793 
794 	return (topo_cleanup_auth_str(mod->tm_hdl, psn));
795 }
796 
797 static char *
798 topo_mod_csn(topo_mod_t *mod)
799 {
800 	char csn[MAXNAMELEN];
801 	smbios_hdl_t *shp;
802 	di_prom_handle_t promh = DI_PROM_HANDLE_NIL;
803 	di_node_t rooth = DI_NODE_NIL;
804 	const char *bufp;
805 
806 	if ((shp = topo_mod_smbios(mod)) != NULL) {
807 		bufp = smbios_csn(shp);
808 		if (bufp != NULL)
809 			(void) strlcpy(csn, bufp, MAXNAMELEN);
810 		else
811 			return (NULL);
812 	} else if ((rooth = topo_mod_devinfo(mod)) != DI_NODE_NIL &&
813 	    (promh = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) {
814 		if (di_prom_prop_lookup_bytes(promh, rooth, "chassis-sn",
815 		    (unsigned char **)&bufp) != -1) {
816 			(void) strlcpy(csn, bufp, MAXNAMELEN);
817 		} else {
818 			return (NULL);
819 		}
820 	} else {
821 		return (NULL);
822 	}
823 
824 	return (topo_cleanup_auth_str(mod->tm_hdl, csn));
825 }
826 
827 nvlist_t *
828 topo_mod_auth(topo_mod_t *mod, tnode_t *pnode)
829 {
830 	int err;
831 	char *prod = NULL;
832 	char *csn = NULL;
833 	char *psn = NULL;
834 	char *server = NULL;
835 	nvlist_t *auth;
836 
837 	if ((err = topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME)) != 0) {
838 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
839 		return (NULL);
840 	}
841 
842 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
843 	    FM_FMRI_AUTH_PRODUCT, &prod, &err);
844 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
845 	    FM_FMRI_AUTH_PRODUCT_SN, &psn, &err);
846 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
847 	    FM_FMRI_AUTH_CHASSIS, &csn, &err);
848 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
849 	    FM_FMRI_AUTH_SERVER, &server, &err);
850 
851 	/*
852 	 * Let's do this the hard way
853 	 */
854 	if (prod == NULL)
855 		prod = topo_mod_product(mod);
856 	if (csn == NULL)
857 		csn = topo_mod_csn(mod);
858 	if (psn == NULL)
859 		psn = topo_mod_psn(mod);
860 	if (server == NULL) {
861 		server = topo_mod_server(mod);
862 	}
863 
864 	/*
865 	 * No luck, return NULL
866 	 */
867 	if (!prod && !server && !csn && !psn) {
868 		nvlist_free(auth);
869 		return (NULL);
870 	}
871 
872 	err = 0;
873 	if (prod != NULL) {
874 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, prod);
875 		topo_mod_strfree(mod, prod);
876 	}
877 	if (psn != NULL) {
878 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT_SN, psn);
879 		topo_mod_strfree(mod, psn);
880 	}
881 	if (server != NULL) {
882 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, server);
883 		topo_mod_strfree(mod, server);
884 	}
885 	if (csn != NULL) {
886 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, csn);
887 		topo_mod_strfree(mod, csn);
888 	}
889 
890 	if (err != 0) {
891 		nvlist_free(auth);
892 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
893 		return (NULL);
894 	}
895 
896 	return (auth);
897 }
898 
899 topo_walk_t *
900 topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f,
901     void *pdata, int *errp)
902 {
903 	topo_walk_t *wp;
904 	topo_hdl_t *thp = mod->tm_hdl;
905 
906 	if ((wp = topo_node_walk_init(thp, mod, node, (int (*)())cb_f, pdata,
907 	    errp)) == NULL)
908 		return (NULL);
909 
910 	return (wp);
911 }
912 
913 char *
914 topo_mod_clean_str(topo_mod_t *mod, const char *str)
915 {
916 	if (str == NULL)
917 		return (NULL);
918 
919 	return (topo_cleanup_auth_str(mod->tm_hdl, str));
920 }
921