xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_mod.c (revision 332e84f52cdee3d0232bd5ac5306c42177959c96)
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 #include <sys/types.h>
100 #include <sys/stat.h>
101 #include <fcntl.h>
102 
103 #include <topo_alloc.h>
104 #include <topo_error.h>
105 #include <topo_file.h>
106 #include <topo_fmri.h>
107 #include <topo_module.h>
108 #include <topo_method.h>
109 #include <topo_string.h>
110 #include <topo_subr.h>
111 #include <topo_tree.h>
112 
113 #define	PLUGIN_PATH	"plugins"
114 #define	PLUGIN_PATH_LEN	MAXNAMELEN + 5
115 
116 topo_mod_t *
117 topo_mod_load(topo_mod_t *pmod, const char *name,
118     topo_version_t version)
119 {
120 	char *path;
121 	char file[PLUGIN_PATH_LEN];
122 	topo_mod_t *mod = NULL;
123 	topo_hdl_t *thp;
124 
125 	thp = pmod->tm_hdl;
126 
127 	/*
128 	 * Already loaded, topo_mod_lookup will bump the ref count
129 	 */
130 	if ((mod = topo_mod_lookup(thp, name, 1)) != NULL) {
131 		if (mod->tm_info->tmi_version != version) {
132 			topo_mod_rele(mod);
133 			(void) topo_mod_seterrno(pmod, ETOPO_MOD_VER);
134 			return (NULL);
135 		}
136 		return (mod);
137 	}
138 
139 	(void) snprintf(file, PLUGIN_PATH_LEN, "%s/%s.so",
140 	    PLUGIN_PATH, name);
141 	path = topo_search_path(pmod, thp->th_rootdir, (const char *)file);
142 	if (path == NULL ||
143 	    (mod = topo_modhash_load(thp, name, path, &topo_rtld_ops, version))
144 	    == NULL) { /* returned with mod held */
145 			topo_mod_strfree(pmod, path);
146 			(void) topo_mod_seterrno(pmod, topo_hdl_errno(thp) ?
147 			    topo_hdl_errno(thp) : ETOPO_MOD_NOENT);
148 			return (NULL);
149 	}
150 
151 	topo_mod_strfree(pmod, path);
152 
153 	return (mod);
154 }
155 
156 void
157 topo_mod_unload(topo_mod_t *mod)
158 {
159 	topo_mod_rele(mod);
160 }
161 
162 static int
163 set_register_error(topo_mod_t *mod, int err)
164 {
165 	if (mod->tm_info != NULL)
166 		topo_mod_unregister(mod);
167 
168 	topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
169 	    "module registration failed for %s: %s\n",
170 	    mod->tm_name, topo_strerror(err));
171 
172 	return (topo_mod_seterrno(mod, err));
173 }
174 
175 int
176 topo_mod_register(topo_mod_t *mod, const topo_modinfo_t *mip,
177     topo_version_t version)
178 {
179 
180 	assert(!(mod->tm_flags & TOPO_MOD_FINI ||
181 	    mod->tm_flags & TOPO_MOD_REG));
182 
183 	if (version != TOPO_VERSION)
184 		return (set_register_error(mod, EMOD_VER_ABI));
185 
186 	if ((mod->tm_info = topo_mod_zalloc(mod, sizeof (topo_imodinfo_t)))
187 	    == NULL)
188 		return (set_register_error(mod, EMOD_NOMEM));
189 	if ((mod->tm_info->tmi_ops = topo_mod_alloc(mod,
190 	    sizeof (topo_modops_t))) == NULL)
191 		return (set_register_error(mod, EMOD_NOMEM));
192 
193 	mod->tm_info->tmi_desc = topo_mod_strdup(mod, mip->tmi_desc);
194 	if (mod->tm_info->tmi_desc == NULL)
195 		return (set_register_error(mod, EMOD_NOMEM));
196 
197 	mod->tm_info->tmi_scheme = topo_mod_strdup(mod, mip->tmi_scheme);
198 	if (mod->tm_info->tmi_scheme == NULL)
199 		return (set_register_error(mod, EMOD_NOMEM));
200 
201 
202 	mod->tm_info->tmi_version = (topo_version_t)mip->tmi_version;
203 	mod->tm_info->tmi_ops->tmo_enum = mip->tmi_ops->tmo_enum;
204 	mod->tm_info->tmi_ops->tmo_release = mip->tmi_ops->tmo_release;
205 
206 	mod->tm_flags |= TOPO_MOD_REG;
207 
208 	topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
209 	    "registration succeeded for %s\n", mod->tm_name);
210 
211 	return (0);
212 }
213 
214 void
215 topo_mod_unregister(topo_mod_t *mod)
216 {
217 	if (mod->tm_info == NULL)
218 		return;
219 
220 	assert(!(mod->tm_flags & TOPO_MOD_FINI));
221 
222 	mod->tm_flags &= ~TOPO_MOD_REG;
223 
224 	if (mod->tm_info == NULL)
225 		return;
226 
227 	if (mod->tm_info->tmi_ops != NULL)
228 		topo_mod_free(mod, mod->tm_info->tmi_ops,
229 		    sizeof (topo_modops_t));
230 	if (mod->tm_info->tmi_desc != NULL)
231 		topo_mod_strfree(mod, mod->tm_info->tmi_desc);
232 	if (mod->tm_info->tmi_scheme != NULL)
233 		topo_mod_strfree(mod, mod->tm_info->tmi_scheme);
234 
235 	topo_mod_free(mod, mod->tm_info, sizeof (topo_imodinfo_t));
236 
237 	mod->tm_info = NULL;
238 }
239 
240 int
241 topo_mod_enumerate(topo_mod_t *mod, tnode_t *node, const char *enum_name,
242     const char *name, topo_instance_t min, topo_instance_t max, void *data)
243 {
244 	int err = 0;
245 	topo_mod_t *enum_mod;
246 
247 	assert(mod->tm_flags & TOPO_MOD_REG);
248 
249 	if ((enum_mod = topo_mod_lookup(mod->tm_hdl, enum_name, 0)) == NULL)
250 		return (topo_mod_seterrno(mod, EMOD_MOD_NOENT));
251 
252 	topo_node_hold(node);
253 
254 	topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "module %s enumerating "
255 	    "node %s=%d\n", (char *)mod->tm_name, (char *)node->tn_name,
256 	    node->tn_instance);
257 
258 	topo_mod_enter(enum_mod);
259 	err = enum_mod->tm_info->tmi_ops->tmo_enum(enum_mod, node, name, min,
260 	    max, enum_mod->tm_priv, data);
261 	topo_mod_exit(enum_mod);
262 
263 	if (err != 0) {
264 		(void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
265 
266 		topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
267 		    "module %s failed enumeration for "
268 		    " node %s=%d\n", (char *)mod->tm_name,
269 		    (char *)node->tn_name, node->tn_instance);
270 
271 		topo_node_rele(node);
272 		return (-1);
273 	}
274 
275 	topo_node_rele(node);
276 
277 	return (0);
278 }
279 
280 int
281 topo_mod_enummap(topo_mod_t *mod, tnode_t *node, const char *name,
282     const char *scheme)
283 {
284 	return (topo_file_load(mod, node, (char *)name, (char *)scheme, 0));
285 }
286 
287 static nvlist_t *
288 set_fmri_err(topo_mod_t *mod, int err)
289 {
290 	(void) topo_mod_seterrno(mod, err);
291 	return (NULL);
292 }
293 
294 nvlist_t *
295 topo_mod_hcfmri(topo_mod_t *mod, tnode_t *pnode, int version, const char *name,
296     topo_instance_t inst, nvlist_t *hc_specific, nvlist_t *auth,
297     const char *part, const char *rev, const char *serial)
298 {
299 	int err;
300 	nvlist_t *pfmri = NULL, *fmri = NULL, *args = NULL;
301 	nvlist_t *nfp = NULL;
302 	char *lpart, *lrev, *lserial;
303 
304 	if (version != FM_HC_SCHEME_VERSION)
305 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
306 
307 	/*
308 	 * Do we have any args to pass?
309 	 */
310 	if (pnode != NULL || auth != NULL || part != NULL || rev != NULL ||
311 	    serial != NULL || hc_specific != NULL) {
312 		if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
313 			return (set_fmri_err(mod, EMOD_FMRI_NVL));
314 	}
315 
316 	if (pnode != NULL) {
317 		if (topo_node_resource(pnode, &pfmri, &err) < 0) {
318 			nvlist_free(args);
319 			return (set_fmri_err(mod, EMOD_NVL_INVAL));
320 		}
321 
322 		if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
323 		    pfmri) != 0) {
324 			nvlist_free(pfmri);
325 			nvlist_free(args);
326 			return (set_fmri_err(mod, EMOD_FMRI_NVL));
327 		}
328 		nvlist_free(pfmri);
329 	}
330 
331 	/*
332 	 * Add optional payload
333 	 */
334 	if (auth != NULL)
335 		(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, auth);
336 	if (part != NULL) {
337 		lpart = topo_cleanup_auth_str(mod->tm_hdl, part);
338 		if (lpart != NULL) {
339 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
340 			    lpart);
341 			topo_hdl_free(mod->tm_hdl, lpart, strlen(lpart) + 1);
342 		} else {
343 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
344 			    "");
345 		}
346 	}
347 	if (rev != NULL) {
348 		lrev = topo_cleanup_auth_str(mod->tm_hdl, rev);
349 		if (lrev != NULL) {
350 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
351 			    lrev);
352 			topo_hdl_free(mod->tm_hdl, lrev, strlen(lrev) + 1);
353 		} else {
354 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
355 			    "");
356 		}
357 	}
358 	if (serial != NULL) {
359 		lserial = topo_cleanup_auth_str(mod->tm_hdl, serial);
360 		if (lserial != NULL) {
361 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
362 			    lserial);
363 			topo_hdl_free(mod->tm_hdl, lserial,
364 			    strlen(lserial) + 1);
365 		} else {
366 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
367 			    "");
368 		}
369 	}
370 	if (hc_specific != NULL)
371 		(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_HCS,
372 		    hc_specific);
373 
374 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_HC, name, inst,
375 	    args, &err)) == NULL) {
376 		nvlist_free(args);
377 		return (set_fmri_err(mod, err));
378 	}
379 
380 	nvlist_free(args);
381 
382 	(void) topo_mod_nvdup(mod, fmri, &nfp);
383 	nvlist_free(fmri);
384 
385 	return (nfp);
386 }
387 
388 nvlist_t *
389 topo_mod_devfmri(topo_mod_t *mod, int version, const char *dev_path,
390     const char *devid)
391 {
392 	int err;
393 	nvlist_t *fmri, *args;
394 	nvlist_t *nfp = NULL;
395 
396 	if (version != FM_DEV_SCHEME_VERSION)
397 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
398 
399 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
400 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
401 
402 	if (nvlist_add_string(args, FM_FMRI_DEV_PATH, dev_path) != 0) {
403 		nvlist_free(args);
404 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
405 	}
406 
407 	(void) nvlist_add_string(args, FM_FMRI_DEV_ID, devid);
408 
409 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_DEV,
410 	    FM_FMRI_SCHEME_DEV, 0, args, &err)) == NULL) {
411 		nvlist_free(args);
412 		return (set_fmri_err(mod, err));
413 	}
414 
415 	nvlist_free(args);
416 
417 	(void) topo_mod_nvdup(mod, fmri, &nfp);
418 	nvlist_free(fmri);
419 
420 	return (nfp);
421 }
422 
423 nvlist_t *
424 topo_mod_cpufmri(topo_mod_t *mod, int version, uint32_t cpu_id, uint8_t cpumask,
425     const char *serial)
426 {
427 	int err;
428 	nvlist_t *fmri = NULL, *args = NULL;
429 	nvlist_t *nfp = NULL;
430 
431 	if (version != FM_CPU_SCHEME_VERSION)
432 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
433 
434 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
435 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
436 
437 	if (nvlist_add_uint32(args, FM_FMRI_CPU_ID, cpu_id) != 0) {
438 		nvlist_free(args);
439 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
440 	}
441 
442 	/*
443 	 * Add optional payload
444 	 */
445 	(void) nvlist_add_uint8(args, FM_FMRI_CPU_MASK, cpumask);
446 	(void) nvlist_add_string(args, FM_FMRI_CPU_SERIAL_ID, serial);
447 
448 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_CPU,
449 	    FM_FMRI_SCHEME_CPU, 0, args, &err)) == NULL) {
450 		nvlist_free(args);
451 		return (set_fmri_err(mod, err));
452 	}
453 
454 	nvlist_free(args);
455 
456 	(void) topo_mod_nvdup(mod, fmri, &nfp);
457 	nvlist_free(fmri);
458 
459 	return (nfp);
460 }
461 
462 nvlist_t *
463 topo_mod_memfmri(topo_mod_t *mod, int version, uint64_t pa, uint64_t offset,
464     const char *unum, int flags)
465 {
466 	int err;
467 	nvlist_t *args = NULL, *fmri = NULL;
468 	nvlist_t *nfp = NULL;
469 
470 	if (version != FM_MEM_SCHEME_VERSION)
471 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
472 
473 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
474 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
475 
476 	err = nvlist_add_string(args, FM_FMRI_MEM_UNUM, unum);
477 		nvlist_free(args);
478 	if (flags & TOPO_MEMFMRI_PA)
479 		err |= nvlist_add_uint64(args, FM_FMRI_MEM_PHYSADDR, pa);
480 	if (flags & TOPO_MEMFMRI_OFFSET)
481 		err |= nvlist_add_uint64(args, FM_FMRI_MEM_OFFSET, offset);
482 
483 	if (err != 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_MEM,
489 	    FM_FMRI_SCHEME_MEM, 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 
503 nvlist_t *
504 topo_mod_pkgfmri(topo_mod_t *mod, int version, const char *path)
505 {
506 	int err;
507 	nvlist_t *fmri = NULL, *args = NULL;
508 	nvlist_t *nfp = NULL;
509 
510 	if (version != FM_PKG_SCHEME_VERSION)
511 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
512 
513 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
514 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
515 
516 	if (nvlist_add_string(args, "path", path) != 0) {
517 		nvlist_free(args);
518 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
519 	}
520 
521 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_PKG,
522 	    FM_FMRI_SCHEME_PKG, 0, args, &err)) == NULL) {
523 		nvlist_free(args);
524 		return (set_fmri_err(mod, err));
525 	}
526 
527 	nvlist_free(args);
528 
529 	(void) topo_mod_nvdup(mod, fmri, &nfp);
530 	nvlist_free(fmri);
531 
532 	return (nfp);
533 }
534 
535 nvlist_t *
536 topo_mod_modfmri(topo_mod_t *mod, int version, const char *driver)
537 {
538 	int err;
539 	nvlist_t *fmri = NULL, *args = NULL;
540 	nvlist_t *nfp = NULL;
541 
542 	if (version != FM_MOD_SCHEME_VERSION)
543 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
544 
545 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
546 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
547 
548 	if (nvlist_add_string(args, "DRIVER", driver) != 0) {
549 		nvlist_free(args);
550 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
551 	}
552 
553 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MOD,
554 	    FM_FMRI_SCHEME_MOD, 0, args, &err)) == NULL) {
555 		nvlist_free(args);
556 		return (set_fmri_err(mod, err));
557 	}
558 
559 	nvlist_free(args);
560 
561 	(void) topo_mod_nvdup(mod, fmri, &nfp);
562 	nvlist_free(fmri);
563 
564 	return (nfp);
565 }
566 
567 #define	_SWFMRI_ADD_STRING(nvl, name, val) \
568 	((val) ? (nvlist_add_string(nvl, name, val) != 0) : 0)
569 
570 nvlist_t *
571 topo_mod_swfmri(topo_mod_t *mod, int version,
572     char *obj_path, char *obj_root, nvlist_t *obj_pkg,
573     char *site_token, char *site_module, char *site_file, char *site_func,
574     int64_t site_line, char *ctxt_origin, char *ctxt_execname,
575     int64_t ctxt_pid, char *ctxt_zone, int64_t ctxt_ctid,
576     char **ctxt_stack, uint_t ctxt_stackdepth)
577 {
578 	nvlist_t *fmri, *args;
579 	nvlist_t *nfp = NULL;
580 	int err;
581 
582 	if (version != FM_SW_SCHEME_VERSION)
583 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
584 
585 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
586 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
587 
588 	err = 0;
589 	err |= _SWFMRI_ADD_STRING(args, "obj_path", obj_path);
590 	err |= _SWFMRI_ADD_STRING(args, "obj_root", obj_root);
591 	if (obj_pkg)
592 		err |= nvlist_add_nvlist(args, "obj_pkg", obj_pkg);
593 
594 	err |= _SWFMRI_ADD_STRING(args, "site_token", site_token);
595 	err |= _SWFMRI_ADD_STRING(args, "site_module", site_module);
596 	err |= _SWFMRI_ADD_STRING(args, "site_file", site_file);
597 	err |= _SWFMRI_ADD_STRING(args, "site_func", site_func);
598 	if (site_line != -1)
599 		err |= nvlist_add_int64(args, "site_line", site_line);
600 
601 	err |= _SWFMRI_ADD_STRING(args, "ctxt_origin", ctxt_origin);
602 	err |= _SWFMRI_ADD_STRING(args, "ctxt_execname", ctxt_execname);
603 	if (ctxt_pid != -1)
604 		err |= nvlist_add_int64(args, "ctxt_pid", ctxt_pid);
605 	err |= _SWFMRI_ADD_STRING(args, "ctxt_zone", ctxt_zone);
606 	if (ctxt_ctid != -1)
607 		err |= nvlist_add_int64(args, "ctxt_ctid", ctxt_ctid);
608 	if (ctxt_stack != NULL && ctxt_stackdepth != 0)
609 		err |= nvlist_add_string_array(args, "stack", ctxt_stack,
610 		    ctxt_stackdepth);
611 
612 	if (err) {
613 		nvlist_free(args);
614 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
615 	}
616 
617 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_SW,
618 	    FM_FMRI_SCHEME_SW, 0, args, &err)) == NULL) {
619 		nvlist_free(args);
620 		return (set_fmri_err(mod, err));
621 	}
622 
623 	nvlist_free(args);
624 
625 	(void) topo_mod_nvdup(mod, fmri, &nfp);
626 	nvlist_free(fmri);
627 
628 	return (nfp);
629 }
630 
631 int
632 topo_mod_str2nvl(topo_mod_t *mod, const char *fmristr, nvlist_t **fmri)
633 {
634 	int err;
635 	nvlist_t *np = NULL;
636 
637 	if (topo_fmri_str2nvl(mod->tm_hdl, fmristr, &np, &err) < 0)
638 		return (topo_mod_seterrno(mod, err));
639 
640 	if (topo_mod_nvdup(mod, np, fmri) < 0) {
641 		nvlist_free(np);
642 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
643 	}
644 
645 	nvlist_free(np);
646 
647 	return (0);
648 }
649 
650 int
651 topo_mod_nvl2str(topo_mod_t *mod, nvlist_t *fmri, char **fmristr)
652 {
653 	int err;
654 	char *sp;
655 
656 	if (topo_fmri_nvl2str(mod->tm_hdl, fmri, &sp, &err) < 0)
657 		return (topo_mod_seterrno(mod, err));
658 
659 	if ((*fmristr = topo_mod_strdup(mod, sp)) == NULL) {
660 		topo_hdl_strfree(mod->tm_hdl, sp);
661 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
662 	}
663 
664 	topo_hdl_strfree(mod->tm_hdl, sp);
665 
666 	return (0);
667 }
668 
669 void *
670 topo_mod_getspecific(topo_mod_t *mod)
671 {
672 	return (mod->tm_priv);
673 }
674 
675 void
676 topo_mod_setspecific(topo_mod_t *mod, void *data)
677 {
678 	mod->tm_priv = data;
679 }
680 
681 void
682 topo_mod_setdebug(topo_mod_t *mod)
683 {
684 	mod->tm_debug = 1;
685 }
686 
687 ipmi_handle_t *
688 topo_mod_ipmi_hold(topo_mod_t *mod)
689 {
690 	topo_hdl_t *thp = mod->tm_hdl;
691 	int err;
692 	char *errmsg;
693 
694 	(void) pthread_mutex_lock(&thp->th_ipmi_lock);
695 	if (thp->th_ipmi == NULL) {
696 		if ((thp->th_ipmi = ipmi_open(&err, &errmsg, IPMI_TRANSPORT_BMC,
697 		    NULL)) == NULL) {
698 			topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
699 			    "ipmi_open() failed: %s (ipmi errno=%d)", errmsg,
700 			    err);
701 			(void) pthread_mutex_unlock(&thp->th_ipmi_lock);
702 		}
703 	}
704 
705 
706 	return (thp->th_ipmi);
707 }
708 
709 void
710 topo_mod_ipmi_rele(topo_mod_t *mod)
711 {
712 	topo_hdl_t *thp = mod->tm_hdl;
713 
714 	(void) pthread_mutex_unlock(&thp->th_ipmi_lock);
715 }
716 
717 di_node_t
718 topo_mod_devinfo(topo_mod_t *mod)
719 {
720 	return (topo_hdl_devinfo(mod->tm_hdl));
721 }
722 
723 smbios_hdl_t *
724 topo_mod_smbios(topo_mod_t *mod)
725 {
726 	topo_hdl_t *thp = mod->tm_hdl;
727 
728 	if (thp->th_smbios == NULL)
729 		thp->th_smbios = smbios_open(NULL, SMB_VERSION, 0, NULL);
730 
731 	return (thp->th_smbios);
732 }
733 
734 di_prom_handle_t
735 topo_mod_prominfo(topo_mod_t *mod)
736 {
737 	return (topo_hdl_prominfo(mod->tm_hdl));
738 }
739 
740 pcidb_hdl_t *
741 topo_mod_pcidb(topo_mod_t *mod)
742 {
743 	topo_hdl_t *thp = mod->tm_hdl;
744 
745 	if (thp->th_pcidb == NULL)
746 		thp->th_pcidb = pcidb_open(PCIDB_VERSION);
747 
748 	return (thp->th_pcidb);
749 }
750 
751 void
752 topo_mod_clrdebug(topo_mod_t *mod)
753 {
754 	mod->tm_debug = 0;
755 }
756 
757 /*PRINTFLIKE2*/
758 void
759 topo_mod_dprintf(topo_mod_t *mod, const char *format, ...)
760 {
761 	topo_hdl_t *thp = mod->tm_hdl;
762 	va_list alist;
763 
764 	if (mod->tm_debug == 0 || !(thp->th_debug & TOPO_DBG_MOD))
765 		return;
766 
767 	va_start(alist, format);
768 	topo_vdprintf(mod->tm_hdl, (const char *)mod->tm_name, format, alist);
769 	va_end(alist);
770 }
771 
772 static char *
773 topo_mod_product(topo_mod_t *mod)
774 {
775 	return (topo_mod_strdup(mod, mod->tm_hdl->th_product));
776 }
777 
778 static char *
779 topo_mod_server(topo_mod_t *mod)
780 {
781 	static struct utsname uts;
782 
783 	(void) uname(&uts);
784 	return (topo_mod_strdup(mod, uts.nodename));
785 }
786 
787 static char *
788 topo_mod_psn(topo_mod_t *mod)
789 {
790 	smbios_hdl_t *shp;
791 	const char *psn;
792 
793 	if ((shp = topo_mod_smbios(mod)) == NULL ||
794 	    (psn = smbios_psn(shp)) == NULL)
795 		return (NULL);
796 
797 	return (topo_cleanup_auth_str(mod->tm_hdl, psn));
798 }
799 
800 static char *
801 topo_mod_csn(topo_mod_t *mod)
802 {
803 	char csn[MAXNAMELEN];
804 	smbios_hdl_t *shp;
805 	di_prom_handle_t promh = DI_PROM_HANDLE_NIL;
806 	di_node_t rooth = DI_NODE_NIL;
807 	const char *bufp;
808 
809 	if ((shp = topo_mod_smbios(mod)) != NULL) {
810 		bufp = smbios_csn(shp);
811 		if (bufp != NULL)
812 			(void) strlcpy(csn, bufp, MAXNAMELEN);
813 		else
814 			return (NULL);
815 	} else if ((rooth = topo_mod_devinfo(mod)) != DI_NODE_NIL &&
816 	    (promh = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) {
817 		if (di_prom_prop_lookup_bytes(promh, rooth, "chassis-sn",
818 		    (unsigned char **)&bufp) != -1) {
819 			(void) strlcpy(csn, bufp, MAXNAMELEN);
820 		} else {
821 			return (NULL);
822 		}
823 	} else {
824 		return (NULL);
825 	}
826 
827 	return (topo_cleanup_auth_str(mod->tm_hdl, csn));
828 }
829 
830 nvlist_t *
831 topo_mod_auth(topo_mod_t *mod, tnode_t *pnode)
832 {
833 	int err;
834 	char *prod = NULL;
835 	char *csn = NULL;
836 	char *psn = NULL;
837 	char *server = NULL;
838 	nvlist_t *auth;
839 
840 	if ((err = topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME)) != 0) {
841 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
842 		return (NULL);
843 	}
844 
845 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
846 	    FM_FMRI_AUTH_PRODUCT, &prod, &err);
847 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
848 	    FM_FMRI_AUTH_PRODUCT_SN, &psn, &err);
849 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
850 	    FM_FMRI_AUTH_CHASSIS, &csn, &err);
851 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
852 	    FM_FMRI_AUTH_SERVER, &server, &err);
853 
854 	/*
855 	 * Let's do this the hard way
856 	 */
857 	if (prod == NULL)
858 		prod = topo_mod_product(mod);
859 	if (csn == NULL)
860 		csn = topo_mod_csn(mod);
861 	if (psn == NULL)
862 		psn = topo_mod_psn(mod);
863 	if (server == NULL) {
864 		server = topo_mod_server(mod);
865 	}
866 
867 	/*
868 	 * No luck, return NULL
869 	 */
870 	if (!prod && !server && !csn && !psn) {
871 		nvlist_free(auth);
872 		return (NULL);
873 	}
874 
875 	err = 0;
876 	if (prod != NULL) {
877 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, prod);
878 		topo_mod_strfree(mod, prod);
879 	}
880 	if (psn != NULL) {
881 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT_SN, psn);
882 		topo_mod_strfree(mod, psn);
883 	}
884 	if (server != NULL) {
885 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, server);
886 		topo_mod_strfree(mod, server);
887 	}
888 	if (csn != NULL) {
889 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, csn);
890 		topo_mod_strfree(mod, csn);
891 	}
892 
893 	if (err != 0) {
894 		nvlist_free(auth);
895 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
896 		return (NULL);
897 	}
898 
899 	return (auth);
900 }
901 
902 topo_walk_t *
903 topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f,
904     void *pdata, int *errp)
905 {
906 	topo_walk_t *wp;
907 	topo_hdl_t *thp = mod->tm_hdl;
908 
909 	if ((wp = topo_node_walk_init(thp, mod, node, (int (*)())cb_f, pdata,
910 	    errp)) == NULL)
911 		return (NULL);
912 
913 	return (wp);
914 }
915 
916 char *
917 topo_mod_clean_str(topo_mod_t *mod, const char *str)
918 {
919 	if (str == NULL)
920 		return (NULL);
921 
922 	return (topo_cleanup_auth_str(mod->tm_hdl, str));
923 }
924 
925 int
926 topo_mod_file_search(topo_mod_t *mod, const char *file, int oflags)
927 {
928 	int ret;
929 	char *path;
930 	topo_hdl_t *thp = mod->tm_hdl;
931 
932 	path = topo_search_path(mod, thp->th_rootdir, file);
933 	if (path == NULL) {
934 		return (-1);
935 	}
936 
937 	ret = open(path, oflags);
938 	topo_mod_strfree(mod, path);
939 	return (ret);
940 }
941