Home | History | Annotate | Download | only in common
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     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 <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 int
    564 topo_mod_str2nvl(topo_mod_t *mod, const char *fmristr, nvlist_t **fmri)
    565 {
    566 	int err;
    567 	nvlist_t *np = NULL;
    568 
    569 	if (topo_fmri_str2nvl(mod->tm_hdl, fmristr, &np, &err) < 0)
    570 		return (topo_mod_seterrno(mod, err));
    571 
    572 	if (topo_mod_nvdup(mod, np, fmri) < 0) {
    573 		nvlist_free(np);
    574 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
    575 	}
    576 
    577 	nvlist_free(np);
    578 
    579 	return (0);
    580 }
    581 
    582 int
    583 topo_mod_nvl2str(topo_mod_t *mod, nvlist_t *fmri, char **fmristr)
    584 {
    585 	int err;
    586 	char *sp;
    587 
    588 	if (topo_fmri_nvl2str(mod->tm_hdl, fmri, &sp, &err) < 0)
    589 		return (topo_mod_seterrno(mod, err));
    590 
    591 	if ((*fmristr = topo_mod_strdup(mod, sp)) == NULL) {
    592 		topo_hdl_strfree(mod->tm_hdl, sp);
    593 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
    594 	}
    595 
    596 	topo_hdl_strfree(mod->tm_hdl, sp);
    597 
    598 	return (0);
    599 }
    600 
    601 void *
    602 topo_mod_getspecific(topo_mod_t *mod)
    603 {
    604 	return (mod->tm_priv);
    605 }
    606 
    607 void
    608 topo_mod_setspecific(topo_mod_t *mod, void *data)
    609 {
    610 	mod->tm_priv = data;
    611 }
    612 
    613 void
    614 topo_mod_setdebug(topo_mod_t *mod)
    615 {
    616 	mod->tm_debug = 1;
    617 }
    618 
    619 ipmi_handle_t *
    620 topo_mod_ipmi_hold(topo_mod_t *mod)
    621 {
    622 	topo_hdl_t *thp = mod->tm_hdl;
    623 	int err;
    624 	char *errmsg;
    625 
    626 	(void) pthread_mutex_lock(&thp->th_ipmi_lock);
    627 	if (thp->th_ipmi == NULL) {
    628 		if ((thp->th_ipmi = ipmi_open(&err, &errmsg)) == NULL) {
    629 			topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
    630 			    "ipmi_open() failed: %s (ipmi errno=%d)", errmsg,
    631 			    err);
    632 			(void) pthread_mutex_unlock(&thp->th_ipmi_lock);
    633 		}
    634 	}
    635 
    636 
    637 	return (thp->th_ipmi);
    638 }
    639 
    640 void
    641 topo_mod_ipmi_rele(topo_mod_t *mod)
    642 {
    643 	topo_hdl_t *thp = mod->tm_hdl;
    644 
    645 	(void) pthread_mutex_unlock(&thp->th_ipmi_lock);
    646 }
    647 
    648 di_node_t
    649 topo_mod_devinfo(topo_mod_t *mod)
    650 {
    651 	return (topo_hdl_devinfo(mod->tm_hdl));
    652 }
    653 
    654 smbios_hdl_t *
    655 topo_mod_smbios(topo_mod_t *mod)
    656 {
    657 	topo_hdl_t *thp = mod->tm_hdl;
    658 
    659 	if (thp->th_smbios == NULL)
    660 		thp->th_smbios = smbios_open(NULL, SMB_VERSION, 0, NULL);
    661 
    662 	return (thp->th_smbios);
    663 }
    664 
    665 di_prom_handle_t
    666 topo_mod_prominfo(topo_mod_t *mod)
    667 {
    668 	return (topo_hdl_prominfo(mod->tm_hdl));
    669 }
    670 
    671 void
    672 topo_mod_clrdebug(topo_mod_t *mod)
    673 {
    674 	mod->tm_debug = 0;
    675 }
    676 
    677 /*PRINTFLIKE2*/
    678 void
    679 topo_mod_dprintf(topo_mod_t *mod, const char *format, ...)
    680 {
    681 	va_list alist;
    682 
    683 	if (mod->tm_debug == 0)
    684 		return;
    685 
    686 	va_start(alist, format);
    687 	topo_vdprintf(mod->tm_hdl, TOPO_DBG_MOD, (const char *)mod->tm_name,
    688 	    format, alist);
    689 	va_end(alist);
    690 }
    691 
    692 static char *
    693 topo_mod_product(topo_mod_t *mod)
    694 {
    695 	return (topo_mod_strdup(mod, mod->tm_hdl->th_product));
    696 }
    697 
    698 static char *
    699 topo_mod_server(topo_mod_t *mod)
    700 {
    701 	static struct utsname uts;
    702 
    703 	(void) uname(&uts);
    704 	return (topo_mod_strdup(mod, uts.nodename));
    705 }
    706 
    707 static char *
    708 topo_mod_psn(topo_mod_t *mod)
    709 {
    710 	smbios_hdl_t *shp;
    711 	const char *psn;
    712 
    713 	if ((shp = topo_mod_smbios(mod)) == NULL ||
    714 	    (psn = smbios_psn(shp)) == NULL)
    715 		return (NULL);
    716 
    717 	return (topo_cleanup_auth_str(mod->tm_hdl, psn));
    718 }
    719 
    720 static char *
    721 topo_mod_csn(topo_mod_t *mod)
    722 {
    723 	char csn[MAXNAMELEN];
    724 	smbios_hdl_t *shp;
    725 	di_prom_handle_t promh = DI_PROM_HANDLE_NIL;
    726 	di_node_t rooth = DI_NODE_NIL;
    727 	const char *bufp;
    728 
    729 	if ((shp = topo_mod_smbios(mod)) != NULL) {
    730 		bufp = smbios_csn(shp);
    731 		if (bufp != NULL)
    732 			(void) strlcpy(csn, bufp, MAXNAMELEN);
    733 		else
    734 			return (NULL);
    735 	} else if ((rooth = topo_mod_devinfo(mod)) != DI_NODE_NIL &&
    736 	    (promh = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) {
    737 		if (di_prom_prop_lookup_bytes(promh, rooth, "chassis-sn",
    738 		    (unsigned char **)&bufp) != -1) {
    739 			(void) strlcpy(csn, bufp, MAXNAMELEN);
    740 		} else {
    741 			return (NULL);
    742 		}
    743 	} else {
    744 		return (NULL);
    745 	}
    746 
    747 	return (topo_cleanup_auth_str(mod->tm_hdl, csn));
    748 }
    749 
    750 nvlist_t *
    751 topo_mod_auth(topo_mod_t *mod, tnode_t *pnode)
    752 {
    753 	int err;
    754 	char *prod = NULL;
    755 	char *csn = NULL;
    756 	char *psn = NULL;
    757 	char *server = NULL;
    758 	nvlist_t *auth;
    759 
    760 	if ((err = topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME)) != 0) {
    761 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
    762 		return (NULL);
    763 	}
    764 
    765 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
    766 	    FM_FMRI_AUTH_PRODUCT, &prod, &err);
    767 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
    768 	    FM_FMRI_AUTH_PRODUCT_SN, &psn, &err);
    769 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
    770 	    FM_FMRI_AUTH_CHASSIS, &csn, &err);
    771 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
    772 	    FM_FMRI_AUTH_SERVER, &server, &err);
    773 
    774 	/*
    775 	 * Let's do this the hard way
    776 	 */
    777 	if (prod == NULL)
    778 		prod = topo_mod_product(mod);
    779 	if (csn == NULL)
    780 		csn = topo_mod_csn(mod);
    781 	if (psn == NULL)
    782 		psn = topo_mod_psn(mod);
    783 	if (server == NULL) {
    784 		server = topo_mod_server(mod);
    785 	}
    786 
    787 	/*
    788 	 * No luck, return NULL
    789 	 */
    790 	if (!prod && !server && !csn && !psn) {
    791 		nvlist_free(auth);
    792 		return (NULL);
    793 	}
    794 
    795 	err = 0;
    796 	if (prod != NULL) {
    797 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, prod);
    798 		topo_mod_strfree(mod, prod);
    799 	}
    800 	if (psn != NULL) {
    801 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT_SN, psn);
    802 		topo_mod_strfree(mod, psn);
    803 	}
    804 	if (server != NULL) {
    805 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, server);
    806 		topo_mod_strfree(mod, server);
    807 	}
    808 	if (csn != NULL) {
    809 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, csn);
    810 		topo_mod_strfree(mod, csn);
    811 	}
    812 
    813 	if (err != 0) {
    814 		nvlist_free(auth);
    815 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
    816 		return (NULL);
    817 	}
    818 
    819 	return (auth);
    820 }
    821 
    822 topo_walk_t *
    823 topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f,
    824     void *pdata, int *errp)
    825 {
    826 	topo_walk_t *wp;
    827 	topo_hdl_t *thp = mod->tm_hdl;
    828 
    829 	if ((wp = topo_node_walk_init(thp, mod, node, (int (*)())cb_f, pdata,
    830 	    errp)) == NULL)
    831 		return (NULL);
    832 
    833 	return (wp);
    834 }
    835