17aec1d6eScindi /*
27aec1d6eScindi  * CDDL HEADER START
37aec1d6eScindi  *
47aec1d6eScindi  * The contents of this file are subject to the terms of the
50eb822a1Scindi  * Common Development and Distribution License (the "License").
60eb822a1Scindi  * You may not use this file except in compliance with the License.
77aec1d6eScindi  *
87aec1d6eScindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97aec1d6eScindi  * or http://www.opensolaris.org/os/licensing.
107aec1d6eScindi  * See the License for the specific language governing permissions
117aec1d6eScindi  * and limitations under the License.
127aec1d6eScindi  *
137aec1d6eScindi  * When distributing Covered Code, include this CDDL HEADER in each
147aec1d6eScindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157aec1d6eScindi  * If applicable, add the following below this CDDL HEADER, with the
167aec1d6eScindi  * fields enclosed by brackets "[]" replaced with your own identifying
177aec1d6eScindi  * information: Portions Copyright [yyyy] [name of copyright owner]
187aec1d6eScindi  *
197aec1d6eScindi  * CDDL HEADER END
207aec1d6eScindi  */
217aec1d6eScindi /*
22f6e214c7SGavin Maltby  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23508a0e8cSRob Johnston  * Copyright 2019 Joyent, Inc.
24*9c994d58SRobert Mustacchi  * Copyright 2023 Oxide Computer Company
257aec1d6eScindi  */
267aec1d6eScindi 
277aec1d6eScindi /*
287aec1d6eScindi  * Topology Plugin Modules
297aec1d6eScindi  *
307aec1d6eScindi  * Topology plugin modules are shared libraries that are dlopen'd and
31c40d7343Scindi  * used to enumerate resources in the system and export per-node method
32c40d7343Scindi  * operations.
33c40d7343Scindi  *
34c40d7343Scindi  * They are loaded by our builtin scheme-specific plugins, other modules or
35c40d7343Scindi  * by processing a topo map XML file to enumerate and create nodes for
36c40d7343Scindi  * resources that are present in the system.  They may also export a set of
37c40d7343Scindi  * topology node specific methods that can be invoked directly via
38c40d7343Scindi  * topo_method_invoke() or indirectly via the
39c40d7343Scindi  * topo_prop_get* family of functions to access dynamic property data.
407aec1d6eScindi  *
417aec1d6eScindi  * Module Plugin API
427aec1d6eScindi  *
4324db4641Seschrock  * Enumerators must provide entry points for initialization and clean-up
447aec1d6eScindi  * (_topo_init() and _topo_fini()).  In their _topo_init() function, an
457aec1d6eScindi  * enumerator should register (topo_mod_register()) its enumeration callback
467aec1d6eScindi  * and allocate resources required for a subsequent call to the callback.
477aec1d6eScindi  * Optionally, methods may also be registered with topo_method_register().
487aec1d6eScindi  *
497aec1d6eScindi  * In its enumeration callback routine, the module should search for resources
5024db4641Seschrock  * within its realm of responsibility and create any node ranges,
51c40d7343Scindi  * topo_node_range_create() and nodes, topo_node_bind().  The Enumerator
527aec1d6eScindi  * module is handed a node to which it may begin attaching additional
53c40d7343Scindi  * topology nodes.  The enumerator may only access those nodes within its
54c40d7343Scindi  * current scope of operation: the node passed into its enumeration op and
55c40d7343Scindi  * any nodes it creates during enumeration.  If the enumerator requires walker-
56c40d7343Scindi  * style access to these nodes, it must use
57c40d7343Scindi  * topo_mod_walk_init()/topo_walk_step()/topo_walk_fini().
587aec1d6eScindi  *
597aec1d6eScindi  * If additional helper modules need to be loaded to complete the enumeration
607aec1d6eScindi  * the module may do so by calling topo_mod_load().  Enumeration may then
617aec1d6eScindi  * continue with the module handing off enumeration to its helper module
62c40d7343Scindi  * by calling topo_mod_enumerate().  Similarly, a module may call
63c40d7343Scindi  * topo_mod_enummap() to kick-off enumeration according to a given XML
64c40d7343Scindi  * topology map file.  A module *may* not cause re-entrance to itself
65c40d7343Scindi  * via either of these interfaces.  If re-entry is detected an error
66c40d7343Scindi  * will be returned (ETOPO_ENUM_RECURS).
677aec1d6eScindi  *
687aec1d6eScindi  * If the module registers a release callback, it will be called on a node
697aec1d6eScindi  * by node basis during topo_snap_rele().  Any private node data may be
707aec1d6eScindi  * deallocated or methods unregistered at that time.  Global module data
71c40d7343Scindi  * should be cleaned up before or at the time that the module _topo_fini
727aec1d6eScindi  * entry point is called.
73c40d7343Scindi  *
74c40d7343Scindi  * Module entry points and method invocations are guaranteed to be
75c40d7343Scindi  * single-threaded for a given snapshot handle.  Applications may have
76c40d7343Scindi  * more than one topology snapshot open at a time.  This means that the
77c40d7343Scindi  * module operations and methods may be called for different module handles
78c40d7343Scindi  * (topo_mod_t) asynchronously.  The enumerator should not use static or
79c40d7343Scindi  * global data structures that may become inconsistent in this situation.
80c40d7343Scindi  * Method operations may be re-entrant if the module invokes one of its own
81c40d7343Scindi  * methods directly or via dynamic property access.  Caution should be
82c40d7343Scindi  * exercised with method operations to insure that data remains consistent
83c40d7343Scindi  * within the module and that deadlocks can not occur.
847aec1d6eScindi  */
857aec1d6eScindi 
867aec1d6eScindi #include <pthread.h>
877aec1d6eScindi #include <assert.h>
887aec1d6eScindi #include <errno.h>
897aec1d6eScindi #include <dirent.h>
907aec1d6eScindi #include <limits.h>
917aec1d6eScindi #include <alloca.h>
927aec1d6eScindi #include <unistd.h>
937aec1d6eScindi #include <stdio.h>
949c94f155SCheng Sean Ye #include <ctype.h>
9566d05358SRob Johnston #include <pcidb.h>
960eb822a1Scindi #include <sys/param.h>
970eb822a1Scindi #include <sys/utsname.h>
980eb822a1Scindi #include <sys/smbios.h>
990eb822a1Scindi #include <sys/fm/protocol.h>
100672fc84aSRobert Mustacchi #include <sys/types.h>
101672fc84aSRobert Mustacchi #include <sys/stat.h>
102672fc84aSRobert Mustacchi #include <fcntl.h>
1037aec1d6eScindi 
1047aec1d6eScindi #include <topo_alloc.h>
1057aec1d6eScindi #include <topo_error.h>
1060eb822a1Scindi #include <topo_file.h>
1079dd0f810Scindi #include <topo_fmri.h>
1080eb822a1Scindi #include <topo_module.h>
1090eb822a1Scindi #include <topo_method.h>
1100eb822a1Scindi #include <topo_string.h>
1117aec1d6eScindi #include <topo_subr.h>
1120eb822a1Scindi #include <topo_tree.h>
1130eb822a1Scindi 
1140eb822a1Scindi #define	PLUGIN_PATH	"plugins"
1150eb822a1Scindi #define	PLUGIN_PATH_LEN	MAXNAMELEN + 5
1167aec1d6eScindi 
1177aec1d6eScindi topo_mod_t *
topo_mod_load(topo_mod_t * pmod,const char * name,topo_version_t version)1180eb822a1Scindi topo_mod_load(topo_mod_t *pmod, const char *name,
1190eb822a1Scindi     topo_version_t version)
1207aec1d6eScindi {
1210eb822a1Scindi 	char *path;
1220eb822a1Scindi 	char file[PLUGIN_PATH_LEN];
1237aec1d6eScindi 	topo_mod_t *mod = NULL;
1247aec1d6eScindi 	topo_hdl_t *thp;
1257aec1d6eScindi 
1267aec1d6eScindi 	thp = pmod->tm_hdl;
1277aec1d6eScindi 
1287aec1d6eScindi 	/*
1290eb822a1Scindi 	 * Already loaded, topo_mod_lookup will bump the ref count
1307aec1d6eScindi 	 */
1310eb822a1Scindi 	if ((mod = topo_mod_lookup(thp, name, 1)) != NULL) {
1320eb822a1Scindi 		if (mod->tm_info->tmi_version != version) {
1330eb822a1Scindi 			topo_mod_rele(mod);
1340eb822a1Scindi 			(void) topo_mod_seterrno(pmod, ETOPO_MOD_VER);
1350eb822a1Scindi 			return (NULL);
1360eb822a1Scindi 		}
1377aec1d6eScindi 		return (mod);
1387aec1d6eScindi 	}
1397aec1d6eScindi 
1400eb822a1Scindi 	(void) snprintf(file, PLUGIN_PATH_LEN, "%s/%s.so",
1410eb822a1Scindi 	    PLUGIN_PATH, name);
1420eb822a1Scindi 	path = topo_search_path(pmod, thp->th_rootdir, (const char *)file);
1430eb822a1Scindi 	if (path == NULL ||
1440eb822a1Scindi 	    (mod = topo_modhash_load(thp, name, path, &topo_rtld_ops, version))
1450eb822a1Scindi 	    == NULL) { /* returned with mod held */
1460eb822a1Scindi 			topo_mod_strfree(pmod, path);
1470eb822a1Scindi 			(void) topo_mod_seterrno(pmod, topo_hdl_errno(thp) ?
1480eb822a1Scindi 			    topo_hdl_errno(thp) : ETOPO_MOD_NOENT);
1497aec1d6eScindi 			return (NULL);
1507aec1d6eScindi 	}
1517aec1d6eScindi 
1520eb822a1Scindi 	topo_mod_strfree(pmod, path);
1530eb822a1Scindi 
1547aec1d6eScindi 	return (mod);
1557aec1d6eScindi }
1567aec1d6eScindi 
1577aec1d6eScindi void
topo_mod_unload(topo_mod_t * mod)1587aec1d6eScindi topo_mod_unload(topo_mod_t *mod)
1597aec1d6eScindi {
1607aec1d6eScindi 	topo_mod_rele(mod);
1617aec1d6eScindi }
1627aec1d6eScindi 
1637aec1d6eScindi static int
set_register_error(topo_mod_t * mod,int err)1647aec1d6eScindi set_register_error(topo_mod_t *mod, int err)
1657aec1d6eScindi {
1667aec1d6eScindi 	if (mod->tm_info != NULL)
1677aec1d6eScindi 		topo_mod_unregister(mod);
1687aec1d6eScindi 
1690eb822a1Scindi 	topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
1700eb822a1Scindi 	    "module registration failed for %s: %s\n",
1717aec1d6eScindi 	    mod->tm_name, topo_strerror(err));
1727aec1d6eScindi 
1737aec1d6eScindi 	return (topo_mod_seterrno(mod, err));
1747aec1d6eScindi }
1757aec1d6eScindi 
1767aec1d6eScindi int
topo_mod_register(topo_mod_t * mod,const topo_modinfo_t * mip,topo_version_t version)1770eb822a1Scindi topo_mod_register(topo_mod_t *mod, const topo_modinfo_t *mip,
1780eb822a1Scindi     topo_version_t version)
1797aec1d6eScindi {
1807aec1d6eScindi 
1817aec1d6eScindi 	assert(!(mod->tm_flags & TOPO_MOD_FINI ||
1827aec1d6eScindi 	    mod->tm_flags & TOPO_MOD_REG));
1837aec1d6eScindi 
1840eb822a1Scindi 	if (version != TOPO_VERSION)
1850eb822a1Scindi 		return (set_register_error(mod, EMOD_VER_ABI));
1867aec1d6eScindi 
187c40d7343Scindi 	if ((mod->tm_info = topo_mod_zalloc(mod, sizeof (topo_imodinfo_t)))
1887aec1d6eScindi 	    == NULL)
1890eb822a1Scindi 		return (set_register_error(mod, EMOD_NOMEM));
1900eb822a1Scindi 	if ((mod->tm_info->tmi_ops = topo_mod_alloc(mod,
1910eb822a1Scindi 	    sizeof (topo_modops_t))) == NULL)
1920eb822a1Scindi 		return (set_register_error(mod, EMOD_NOMEM));
1937aec1d6eScindi 
1947aec1d6eScindi 	mod->tm_info->tmi_desc = topo_mod_strdup(mod, mip->tmi_desc);
1957aec1d6eScindi 	if (mod->tm_info->tmi_desc == NULL)
1960eb822a1Scindi 		return (set_register_error(mod, EMOD_NOMEM));
1977aec1d6eScindi 
1980eb822a1Scindi 	mod->tm_info->tmi_scheme = topo_mod_strdup(mod, mip->tmi_scheme);
1990eb822a1Scindi 	if (mod->tm_info->tmi_scheme == NULL)
2000eb822a1Scindi 		return (set_register_error(mod, EMOD_NOMEM));
2017aec1d6eScindi 
2027aec1d6eScindi 
2030eb822a1Scindi 	mod->tm_info->tmi_version = (topo_version_t)mip->tmi_version;
2040eb822a1Scindi 	mod->tm_info->tmi_ops->tmo_enum = mip->tmi_ops->tmo_enum;
2050eb822a1Scindi 	mod->tm_info->tmi_ops->tmo_release = mip->tmi_ops->tmo_release;
2067aec1d6eScindi 
2070eb822a1Scindi 	mod->tm_flags |= TOPO_MOD_REG;
2087aec1d6eScindi 
2090eb822a1Scindi 	topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
2100eb822a1Scindi 	    "registration succeeded for %s\n", mod->tm_name);
2117aec1d6eScindi 
2127aec1d6eScindi 	return (0);
2137aec1d6eScindi }
2147aec1d6eScindi 
2157aec1d6eScindi void
topo_mod_unregister(topo_mod_t * mod)2167aec1d6eScindi topo_mod_unregister(topo_mod_t *mod)
2177aec1d6eScindi {
2187aec1d6eScindi 	if (mod->tm_info == NULL)
2197aec1d6eScindi 		return;
2207aec1d6eScindi 
2217aec1d6eScindi 	assert(!(mod->tm_flags & TOPO_MOD_FINI));
2227aec1d6eScindi 
2237aec1d6eScindi 	mod->tm_flags &= ~TOPO_MOD_REG;
2247aec1d6eScindi 
2257aec1d6eScindi 	if (mod->tm_info == NULL)
2267aec1d6eScindi 		return;
2277aec1d6eScindi 
2280eb822a1Scindi 	if (mod->tm_info->tmi_ops != NULL)
2290eb822a1Scindi 		topo_mod_free(mod, mod->tm_info->tmi_ops,
2300eb822a1Scindi 		    sizeof (topo_modops_t));
2317aec1d6eScindi 	if (mod->tm_info->tmi_desc != NULL)
2327aec1d6eScindi 		topo_mod_strfree(mod, mod->tm_info->tmi_desc);
2330eb822a1Scindi 	if (mod->tm_info->tmi_scheme != NULL)
2340eb822a1Scindi 		topo_mod_strfree(mod, mod->tm_info->tmi_scheme);
2357aec1d6eScindi 
2360eb822a1Scindi 	topo_mod_free(mod, mod->tm_info, sizeof (topo_imodinfo_t));
2377aec1d6eScindi 
2387aec1d6eScindi 	mod->tm_info = NULL;
2397aec1d6eScindi }
2407aec1d6eScindi 
2417aec1d6eScindi int
topo_mod_enumerate(topo_mod_t * mod,tnode_t * node,const char * enum_name,const char * name,topo_instance_t min,topo_instance_t max,void * data)2427aec1d6eScindi topo_mod_enumerate(topo_mod_t *mod, tnode_t *node, const char *enum_name,
2430eb822a1Scindi     const char *name, topo_instance_t min, topo_instance_t max, void *data)
2447aec1d6eScindi {
2457aec1d6eScindi 	int err = 0;
2467aec1d6eScindi 	topo_mod_t *enum_mod;
2477aec1d6eScindi 
2487aec1d6eScindi 	assert(mod->tm_flags & TOPO_MOD_REG);
2497aec1d6eScindi 
2500eb822a1Scindi 	if ((enum_mod = topo_mod_lookup(mod->tm_hdl, enum_name, 0)) == NULL)
2510eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_MOD_NOENT));
2527aec1d6eScindi 
2537aec1d6eScindi 	topo_node_hold(node);
2547aec1d6eScindi 
2550eb822a1Scindi 	topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "module %s enumerating "
2560eb822a1Scindi 	    "node %s=%d\n", (char *)mod->tm_name, (char *)node->tn_name,
2570eb822a1Scindi 	    node->tn_instance);
2587aec1d6eScindi 
2597aec1d6eScindi 	topo_mod_enter(enum_mod);
2600eb822a1Scindi 	err = enum_mod->tm_info->tmi_ops->tmo_enum(enum_mod, node, name, min,
2610eb822a1Scindi 	    max, enum_mod->tm_priv, data);
2627aec1d6eScindi 	topo_mod_exit(enum_mod);
2637aec1d6eScindi 
2647aec1d6eScindi 	if (err != 0) {
2650eb822a1Scindi 		(void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
2667aec1d6eScindi 
2670eb822a1Scindi 		topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
2680eb822a1Scindi 		    "module %s failed enumeration for "
2697aec1d6eScindi 		    " node %s=%d\n", (char *)mod->tm_name,
2707aec1d6eScindi 		    (char *)node->tn_name, node->tn_instance);
2717aec1d6eScindi 
2727aec1d6eScindi 		topo_node_rele(node);
2737aec1d6eScindi 		return (-1);
2747aec1d6eScindi 	}
2757aec1d6eScindi 
2767aec1d6eScindi 	topo_node_rele(node);
2777aec1d6eScindi 
2787aec1d6eScindi 	return (0);
2797aec1d6eScindi }
2807aec1d6eScindi 
2810eb822a1Scindi int
topo_mod_enummap(topo_mod_t * mod,tnode_t * node,const char * name,const char * scheme)2820eb822a1Scindi topo_mod_enummap(topo_mod_t *mod, tnode_t *node, const char *name,
2830eb822a1Scindi     const char *scheme)
2840eb822a1Scindi {
2854557a2a1Srobj 	return (topo_file_load(mod, node, (char *)name, (char *)scheme, 0));
2860eb822a1Scindi }
2870eb822a1Scindi 
2880eb822a1Scindi static nvlist_t *
set_fmri_err(topo_mod_t * mod,int err)2890eb822a1Scindi set_fmri_err(topo_mod_t *mod, int err)
2900eb822a1Scindi {
2910eb822a1Scindi 	(void) topo_mod_seterrno(mod, err);
2920eb822a1Scindi 	return (NULL);
2930eb822a1Scindi }
2940eb822a1Scindi 
2950eb822a1Scindi nvlist_t *
topo_mod_hcfmri(topo_mod_t * mod,tnode_t * pnode,int version,const char * name,topo_instance_t inst,nvlist_t * hc_specific,nvlist_t * auth,const char * part,const char * rev,const char * serial)2960eb822a1Scindi topo_mod_hcfmri(topo_mod_t *mod, tnode_t *pnode, int version, const char *name,
2970eb822a1Scindi     topo_instance_t inst, nvlist_t *hc_specific, nvlist_t *auth,
2980eb822a1Scindi     const char *part, const char *rev, const char *serial)
2990eb822a1Scindi {
3000eb822a1Scindi 	int err;
3010eb822a1Scindi 	nvlist_t *pfmri = NULL, *fmri = NULL, *args = NULL;
3020eb822a1Scindi 	nvlist_t *nfp = NULL;
303e3d60c9bSAdrian Frost 	char *lpart, *lrev, *lserial;
3040eb822a1Scindi 
3050eb822a1Scindi 	if (version != FM_HC_SCHEME_VERSION)
3060eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
3070eb822a1Scindi 
3080eb822a1Scindi 	/*
3090eb822a1Scindi 	 * Do we have any args to pass?
3100eb822a1Scindi 	 */
3110eb822a1Scindi 	if (pnode != NULL || auth != NULL || part != NULL || rev != NULL ||
3120eb822a1Scindi 	    serial != NULL || hc_specific != NULL) {
3130eb822a1Scindi 		if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
31424db4641Seschrock 			return (set_fmri_err(mod, EMOD_FMRI_NVL));
3150eb822a1Scindi 	}
3160eb822a1Scindi 
3170eb822a1Scindi 	if (pnode != NULL) {
31812cc75c8Scindi 		if (topo_node_resource(pnode, &pfmri, &err) < 0) {
31912cc75c8Scindi 			nvlist_free(args);
3200eb822a1Scindi 			return (set_fmri_err(mod, EMOD_NVL_INVAL));
32112cc75c8Scindi 		}
3220eb822a1Scindi 
3230eb822a1Scindi 		if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
3240eb822a1Scindi 		    pfmri) != 0) {
3250eb822a1Scindi 			nvlist_free(pfmri);
3260eb822a1Scindi 			nvlist_free(args);
3270eb822a1Scindi 			return (set_fmri_err(mod, EMOD_FMRI_NVL));
3280eb822a1Scindi 		}
3290eb822a1Scindi 		nvlist_free(pfmri);
3300eb822a1Scindi 	}
3310eb822a1Scindi 
3320eb822a1Scindi 	/*
3330eb822a1Scindi 	 * Add optional payload
3340eb822a1Scindi 	 */
3350eb822a1Scindi 	if (auth != NULL)
3360eb822a1Scindi 		(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, auth);
337e3d60c9bSAdrian Frost 	if (part != NULL) {
338e3d60c9bSAdrian Frost 		lpart = topo_cleanup_auth_str(mod->tm_hdl, part);
339e3d60c9bSAdrian Frost 		if (lpart != NULL) {
340e3d60c9bSAdrian Frost 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
341e3d60c9bSAdrian Frost 			    lpart);
342e3d60c9bSAdrian Frost 			topo_hdl_free(mod->tm_hdl, lpart, strlen(lpart) + 1);
343e3d60c9bSAdrian Frost 		} else {
344e3d60c9bSAdrian Frost 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART,
345c4df5970SAdrian Frost 			    "");
346e3d60c9bSAdrian Frost 		}
347e3d60c9bSAdrian Frost 	}
348e3d60c9bSAdrian Frost 	if (rev != NULL) {
349e3d60c9bSAdrian Frost 		lrev = topo_cleanup_auth_str(mod->tm_hdl, rev);
350e3d60c9bSAdrian Frost 		if (lrev != NULL) {
351e3d60c9bSAdrian Frost 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
352e3d60c9bSAdrian Frost 			    lrev);
353e3d60c9bSAdrian Frost 			topo_hdl_free(mod->tm_hdl, lrev, strlen(lrev) + 1);
354e3d60c9bSAdrian Frost 		} else {
355e3d60c9bSAdrian Frost 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV,
356c4df5970SAdrian Frost 			    "");
357e3d60c9bSAdrian Frost 		}
358e3d60c9bSAdrian Frost 	}
359e3d60c9bSAdrian Frost 	if (serial != NULL) {
360e3d60c9bSAdrian Frost 		lserial = topo_cleanup_auth_str(mod->tm_hdl, serial);
361e3d60c9bSAdrian Frost 		if (lserial != NULL) {
362e3d60c9bSAdrian Frost 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
363e3d60c9bSAdrian Frost 			    lserial);
364e3d60c9bSAdrian Frost 			topo_hdl_free(mod->tm_hdl, lserial,
365e3d60c9bSAdrian Frost 			    strlen(lserial) + 1);
366e3d60c9bSAdrian Frost 		} else {
367e3d60c9bSAdrian Frost 			(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
368c4df5970SAdrian Frost 			    "");
369e3d60c9bSAdrian Frost 		}
370e3d60c9bSAdrian Frost 	}
3710eb822a1Scindi 	if (hc_specific != NULL)
3720eb822a1Scindi 		(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_HCS,
3730eb822a1Scindi 		    hc_specific);
3740eb822a1Scindi 
3750eb822a1Scindi 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_HC, name, inst,
3760eb822a1Scindi 	    args, &err)) == NULL) {
3770eb822a1Scindi 		nvlist_free(args);
3780eb822a1Scindi 		return (set_fmri_err(mod, err));
3790eb822a1Scindi 	}
3800eb822a1Scindi 
3810eb822a1Scindi 	nvlist_free(args);
3820eb822a1Scindi 
3830eb822a1Scindi 	(void) topo_mod_nvdup(mod, fmri, &nfp);
3840eb822a1Scindi 	nvlist_free(fmri);
3850eb822a1Scindi 
3860eb822a1Scindi 	return (nfp);
3870eb822a1Scindi }
3880eb822a1Scindi 
3890eb822a1Scindi nvlist_t *
topo_mod_devfmri(topo_mod_t * mod,int version,const char * dev_path,const char * devid)3900eb822a1Scindi topo_mod_devfmri(topo_mod_t *mod, int version, const char *dev_path,
3910eb822a1Scindi     const char *devid)
3920eb822a1Scindi {
3930eb822a1Scindi 	int err;
3940eb822a1Scindi 	nvlist_t *fmri, *args;
3950eb822a1Scindi 	nvlist_t *nfp = NULL;
3960eb822a1Scindi 
3970eb822a1Scindi 	if (version != FM_DEV_SCHEME_VERSION)
3980eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
3990eb822a1Scindi 
4000eb822a1Scindi 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
4010eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
4020eb822a1Scindi 
4030eb822a1Scindi 	if (nvlist_add_string(args, FM_FMRI_DEV_PATH, dev_path) != 0) {
4040eb822a1Scindi 		nvlist_free(args);
4050eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
4060eb822a1Scindi 	}
4070eb822a1Scindi 
4080eb822a1Scindi 	(void) nvlist_add_string(args, FM_FMRI_DEV_ID, devid);
4090eb822a1Scindi 
4100eb822a1Scindi 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_DEV,
4110eb822a1Scindi 	    FM_FMRI_SCHEME_DEV, 0, args, &err)) == NULL) {
4120eb822a1Scindi 		nvlist_free(args);
4130eb822a1Scindi 		return (set_fmri_err(mod, err));
4140eb822a1Scindi 	}
4150eb822a1Scindi 
4160eb822a1Scindi 	nvlist_free(args);
4170eb822a1Scindi 
4180eb822a1Scindi 	(void) topo_mod_nvdup(mod, fmri, &nfp);
4190eb822a1Scindi 	nvlist_free(fmri);
4200eb822a1Scindi 
4210eb822a1Scindi 	return (nfp);
4220eb822a1Scindi }
4230eb822a1Scindi 
4240eb822a1Scindi nvlist_t *
topo_mod_cpufmri(topo_mod_t * mod,int version,uint32_t cpu_id,uint8_t cpumask,const char * serial)4250eb822a1Scindi topo_mod_cpufmri(topo_mod_t *mod, int version, uint32_t cpu_id, uint8_t cpumask,
4260eb822a1Scindi     const char *serial)
4270eb822a1Scindi {
4280eb822a1Scindi 	int err;
4290eb822a1Scindi 	nvlist_t *fmri = NULL, *args = NULL;
4300eb822a1Scindi 	nvlist_t *nfp = NULL;
4310eb822a1Scindi 
4320eb822a1Scindi 	if (version != FM_CPU_SCHEME_VERSION)
4330eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
4340eb822a1Scindi 
4350eb822a1Scindi 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
4360eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
4370eb822a1Scindi 
4380eb822a1Scindi 	if (nvlist_add_uint32(args, FM_FMRI_CPU_ID, cpu_id) != 0) {
4390eb822a1Scindi 		nvlist_free(args);
4400eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
4410eb822a1Scindi 	}
4420eb822a1Scindi 
4430eb822a1Scindi 	/*
4440eb822a1Scindi 	 * Add optional payload
4450eb822a1Scindi 	 */
4460eb822a1Scindi 	(void) nvlist_add_uint8(args, FM_FMRI_CPU_MASK, cpumask);
4470eb822a1Scindi 	(void) nvlist_add_string(args, FM_FMRI_CPU_SERIAL_ID, serial);
4480eb822a1Scindi 
4490eb822a1Scindi 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_CPU,
4500eb822a1Scindi 	    FM_FMRI_SCHEME_CPU, 0, args, &err)) == NULL) {
4510eb822a1Scindi 		nvlist_free(args);
4520eb822a1Scindi 		return (set_fmri_err(mod, err));
4530eb822a1Scindi 	}
4540eb822a1Scindi 
4550eb822a1Scindi 	nvlist_free(args);
4560eb822a1Scindi 
4570eb822a1Scindi 	(void) topo_mod_nvdup(mod, fmri, &nfp);
4580eb822a1Scindi 	nvlist_free(fmri);
4590eb822a1Scindi 
4600eb822a1Scindi 	return (nfp);
4610eb822a1Scindi }
4620eb822a1Scindi 
4630eb822a1Scindi nvlist_t *
topo_mod_memfmri(topo_mod_t * mod,int version,uint64_t pa,uint64_t offset,const char * unum,int flags)4640eb822a1Scindi topo_mod_memfmri(topo_mod_t *mod, int version, uint64_t pa, uint64_t offset,
46566d05358SRob Johnston     const char *unum, int flags)
4660eb822a1Scindi {
4670eb822a1Scindi 	int err;
4680eb822a1Scindi 	nvlist_t *args = NULL, *fmri = NULL;
4690eb822a1Scindi 	nvlist_t *nfp = NULL;
4700eb822a1Scindi 
4710eb822a1Scindi 	if (version != FM_MEM_SCHEME_VERSION)
4720eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
4730eb822a1Scindi 
4740eb822a1Scindi 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
4750eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
4760eb822a1Scindi 
4770eb822a1Scindi 	err = nvlist_add_string(args, FM_FMRI_MEM_UNUM, unum);
4780eb822a1Scindi 	if (flags & TOPO_MEMFMRI_PA)
4790eb822a1Scindi 		err |= nvlist_add_uint64(args, FM_FMRI_MEM_PHYSADDR, pa);
4800eb822a1Scindi 	if (flags & TOPO_MEMFMRI_OFFSET)
4810eb822a1Scindi 		err |= nvlist_add_uint64(args, FM_FMRI_MEM_OFFSET, offset);
4820eb822a1Scindi 
4830eb822a1Scindi 	if (err != 0) {
4840eb822a1Scindi 		nvlist_free(args);
4850eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
4860eb822a1Scindi 	}
4870eb822a1Scindi 
4880eb822a1Scindi 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MEM,
4890eb822a1Scindi 	    FM_FMRI_SCHEME_MEM, 0, args, &err)) == NULL) {
4900eb822a1Scindi 		nvlist_free(args);
4910eb822a1Scindi 		return (set_fmri_err(mod, err));
4920eb822a1Scindi 	}
4930eb822a1Scindi 
4940eb822a1Scindi 	nvlist_free(args);
4950eb822a1Scindi 
4960eb822a1Scindi 	(void) topo_mod_nvdup(mod, fmri, &nfp);
4970eb822a1Scindi 	nvlist_free(fmri);
4980eb822a1Scindi 
4990eb822a1Scindi 	return (nfp);
5000eb822a1Scindi 
5010eb822a1Scindi }
5020eb822a1Scindi 
5030eb822a1Scindi nvlist_t *
topo_mod_pkgfmri(topo_mod_t * mod,int version,const char * path)5040eb822a1Scindi topo_mod_pkgfmri(topo_mod_t *mod, int version, const char *path)
5050eb822a1Scindi {
5060eb822a1Scindi 	int err;
5070eb822a1Scindi 	nvlist_t *fmri = NULL, *args = NULL;
5080eb822a1Scindi 	nvlist_t *nfp = NULL;
5090eb822a1Scindi 
5100eb822a1Scindi 	if (version != FM_PKG_SCHEME_VERSION)
5110eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
5120eb822a1Scindi 
5130eb822a1Scindi 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
5140eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
5150eb822a1Scindi 
5160eb822a1Scindi 	if (nvlist_add_string(args, "path", path) != 0) {
5170eb822a1Scindi 		nvlist_free(args);
5180eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
5190eb822a1Scindi 	}
5200eb822a1Scindi 
5219dd0f810Scindi 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_PKG,
5229dd0f810Scindi 	    FM_FMRI_SCHEME_PKG, 0, args, &err)) == NULL) {
5230eb822a1Scindi 		nvlist_free(args);
5240eb822a1Scindi 		return (set_fmri_err(mod, err));
5250eb822a1Scindi 	}
5260eb822a1Scindi 
5270eb822a1Scindi 	nvlist_free(args);
5280eb822a1Scindi 
5290eb822a1Scindi 	(void) topo_mod_nvdup(mod, fmri, &nfp);
5300eb822a1Scindi 	nvlist_free(fmri);
5310eb822a1Scindi 
5320eb822a1Scindi 	return (nfp);
5330eb822a1Scindi }
5340eb822a1Scindi 
5350eb822a1Scindi nvlist_t *
topo_mod_modfmri(topo_mod_t * mod,int version,const char * driver)5360eb822a1Scindi topo_mod_modfmri(topo_mod_t *mod, int version, const char *driver)
5377aec1d6eScindi {
5380eb822a1Scindi 	int err;
5390eb822a1Scindi 	nvlist_t *fmri = NULL, *args = NULL;
5400eb822a1Scindi 	nvlist_t *nfp = NULL;
5410eb822a1Scindi 
5420eb822a1Scindi 	if (version != FM_MOD_SCHEME_VERSION)
5430eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
5440eb822a1Scindi 
5450eb822a1Scindi 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
5460eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
5470eb822a1Scindi 
5480eb822a1Scindi 	if (nvlist_add_string(args, "DRIVER", driver) != 0) {
5490eb822a1Scindi 		nvlist_free(args);
5500eb822a1Scindi 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
5510eb822a1Scindi 	}
5520eb822a1Scindi 
5539dd0f810Scindi 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MOD,
5549dd0f810Scindi 	    FM_FMRI_SCHEME_MOD, 0, args, &err)) == NULL) {
5550eb822a1Scindi 		nvlist_free(args);
5560eb822a1Scindi 		return (set_fmri_err(mod, err));
5570eb822a1Scindi 	}
5580eb822a1Scindi 
5590eb822a1Scindi 	nvlist_free(args);
5600eb822a1Scindi 
5610eb822a1Scindi 	(void) topo_mod_nvdup(mod, fmri, &nfp);
5620eb822a1Scindi 	nvlist_free(fmri);
5630eb822a1Scindi 
5640eb822a1Scindi 	return (nfp);
5657aec1d6eScindi }
5667aec1d6eScindi 
567f6e214c7SGavin Maltby #define	_SWFMRI_ADD_STRING(nvl, name, val) \
568f6e214c7SGavin Maltby 	((val) ? (nvlist_add_string(nvl, name, val) != 0) : 0)
569f6e214c7SGavin Maltby 
570f6e214c7SGavin Maltby nvlist_t *
topo_mod_swfmri(topo_mod_t * mod,int version,char * obj_path,char * obj_root,nvlist_t * obj_pkg,char * site_token,char * site_module,char * site_file,char * site_func,int64_t site_line,char * ctxt_origin,char * ctxt_execname,int64_t ctxt_pid,char * ctxt_zone,int64_t ctxt_ctid,char ** ctxt_stack,uint_t ctxt_stackdepth)571f6e214c7SGavin Maltby topo_mod_swfmri(topo_mod_t *mod, int version,
572f6e214c7SGavin Maltby     char *obj_path, char *obj_root, nvlist_t *obj_pkg,
573f6e214c7SGavin Maltby     char *site_token, char *site_module, char *site_file, char *site_func,
574f6e214c7SGavin Maltby     int64_t site_line, char *ctxt_origin, char *ctxt_execname,
575f6e214c7SGavin Maltby     int64_t ctxt_pid, char *ctxt_zone, int64_t ctxt_ctid,
576f6e214c7SGavin Maltby     char **ctxt_stack, uint_t ctxt_stackdepth)
577f6e214c7SGavin Maltby {
578f6e214c7SGavin Maltby 	nvlist_t *fmri, *args;
579f6e214c7SGavin Maltby 	nvlist_t *nfp = NULL;
580f6e214c7SGavin Maltby 	int err;
581f6e214c7SGavin Maltby 
582f6e214c7SGavin Maltby 	if (version != FM_SW_SCHEME_VERSION)
583f6e214c7SGavin Maltby 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
584f6e214c7SGavin Maltby 
585f6e214c7SGavin Maltby 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
586f6e214c7SGavin Maltby 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
587f6e214c7SGavin Maltby 
588f6e214c7SGavin Maltby 	err = 0;
589f6e214c7SGavin Maltby 	err |= _SWFMRI_ADD_STRING(args, "obj_path", obj_path);
590f6e214c7SGavin Maltby 	err |= _SWFMRI_ADD_STRING(args, "obj_root", obj_root);
591f6e214c7SGavin Maltby 	if (obj_pkg)
592f6e214c7SGavin Maltby 		err |= nvlist_add_nvlist(args, "obj_pkg", obj_pkg);
593f6e214c7SGavin Maltby 
594f6e214c7SGavin Maltby 	err |= _SWFMRI_ADD_STRING(args, "site_token", site_token);
595f6e214c7SGavin Maltby 	err |= _SWFMRI_ADD_STRING(args, "site_module", site_module);
596f6e214c7SGavin Maltby 	err |= _SWFMRI_ADD_STRING(args, "site_file", site_file);
597f6e214c7SGavin Maltby 	err |= _SWFMRI_ADD_STRING(args, "site_func", site_func);
598f6e214c7SGavin Maltby 	if (site_line != -1)
599f6e214c7SGavin Maltby 		err |= nvlist_add_int64(args, "site_line", site_line);
600f6e214c7SGavin Maltby 
601f6e214c7SGavin Maltby 	err |= _SWFMRI_ADD_STRING(args, "ctxt_origin", ctxt_origin);
602f6e214c7SGavin Maltby 	err |= _SWFMRI_ADD_STRING(args, "ctxt_execname", ctxt_execname);
603f6e214c7SGavin Maltby 	if (ctxt_pid != -1)
604f6e214c7SGavin Maltby 		err |= nvlist_add_int64(args, "ctxt_pid", ctxt_pid);
605f6e214c7SGavin Maltby 	err |= _SWFMRI_ADD_STRING(args, "ctxt_zone", ctxt_zone);
606f6e214c7SGavin Maltby 	if (ctxt_ctid != -1)
607f6e214c7SGavin Maltby 		err |= nvlist_add_int64(args, "ctxt_ctid", ctxt_ctid);
608f6e214c7SGavin Maltby 	if (ctxt_stack != NULL && ctxt_stackdepth != 0)
609f6e214c7SGavin Maltby 		err |= nvlist_add_string_array(args, "stack", ctxt_stack,
610f6e214c7SGavin Maltby 		    ctxt_stackdepth);
611f6e214c7SGavin Maltby 
612f6e214c7SGavin Maltby 	if (err) {
613f6e214c7SGavin Maltby 		nvlist_free(args);
614f6e214c7SGavin Maltby 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
615f6e214c7SGavin Maltby 	}
616f6e214c7SGavin Maltby 
617f6e214c7SGavin Maltby 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_SW,
618f6e214c7SGavin Maltby 	    FM_FMRI_SCHEME_SW, 0, args, &err)) == NULL) {
619f6e214c7SGavin Maltby 		nvlist_free(args);
620f6e214c7SGavin Maltby 		return (set_fmri_err(mod, err));
621f6e214c7SGavin Maltby 	}
622f6e214c7SGavin Maltby 
623f6e214c7SGavin Maltby 	nvlist_free(args);
624f6e214c7SGavin Maltby 
625f6e214c7SGavin Maltby 	(void) topo_mod_nvdup(mod, fmri, &nfp);
626f6e214c7SGavin Maltby 	nvlist_free(fmri);
627f6e214c7SGavin Maltby 
628f6e214c7SGavin Maltby 	return (nfp);
629f6e214c7SGavin Maltby }
630f6e214c7SGavin Maltby 
6310eb822a1Scindi int
topo_mod_str2nvl(topo_mod_t * mod,const char * fmristr,nvlist_t ** fmri)6320eb822a1Scindi topo_mod_str2nvl(topo_mod_t *mod, const char *fmristr, nvlist_t **fmri)
6337aec1d6eScindi {
6340eb822a1Scindi 	int err;
6350eb822a1Scindi 	nvlist_t *np = NULL;
6360eb822a1Scindi 
6370eb822a1Scindi 	if (topo_fmri_str2nvl(mod->tm_hdl, fmristr, &np, &err) < 0)
6380eb822a1Scindi 		return (topo_mod_seterrno(mod, err));
6390eb822a1Scindi 
6400eb822a1Scindi 	if (topo_mod_nvdup(mod, np, fmri) < 0) {
6410eb822a1Scindi 		nvlist_free(np);
6420eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
6430eb822a1Scindi 	}
6440eb822a1Scindi 
6450eb822a1Scindi 	nvlist_free(np);
6460eb822a1Scindi 
6470eb822a1Scindi 	return (0);
6480eb822a1Scindi }
6490eb822a1Scindi 
6500eb822a1Scindi int
topo_mod_nvl2str(topo_mod_t * mod,nvlist_t * fmri,char ** fmristr)6510eb822a1Scindi topo_mod_nvl2str(topo_mod_t *mod, nvlist_t *fmri, char **fmristr)
6520eb822a1Scindi {
6530eb822a1Scindi 	int err;
6540eb822a1Scindi 	char *sp;
6550eb822a1Scindi 
6560eb822a1Scindi 	if (topo_fmri_nvl2str(mod->tm_hdl, fmri, &sp, &err) < 0)
6570eb822a1Scindi 		return (topo_mod_seterrno(mod, err));
6580eb822a1Scindi 
6590eb822a1Scindi 	if ((*fmristr = topo_mod_strdup(mod, sp)) == NULL) {
6600eb822a1Scindi 		topo_hdl_strfree(mod->tm_hdl, sp);
6610eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
6620eb822a1Scindi 	}
6630eb822a1Scindi 
6640eb822a1Scindi 	topo_hdl_strfree(mod->tm_hdl, sp);
6650eb822a1Scindi 
6660eb822a1Scindi 	return (0);
6677aec1d6eScindi }
6687aec1d6eScindi 
6697aec1d6eScindi void *
topo_mod_getspecific(topo_mod_t * mod)6700eb822a1Scindi topo_mod_getspecific(topo_mod_t *mod)
6717aec1d6eScindi {
6727aec1d6eScindi 	return (mod->tm_priv);
6737aec1d6eScindi }
6747aec1d6eScindi 
6757aec1d6eScindi void
topo_mod_setspecific(topo_mod_t * mod,void * data)6760eb822a1Scindi topo_mod_setspecific(topo_mod_t *mod, void *data)
6770eb822a1Scindi {
6780eb822a1Scindi 	mod->tm_priv = data;
6790eb822a1Scindi }
6800eb822a1Scindi 
6810eb822a1Scindi void
topo_mod_setdebug(topo_mod_t * mod)6820eb822a1Scindi topo_mod_setdebug(topo_mod_t *mod)
6830eb822a1Scindi {
6840eb822a1Scindi 	mod->tm_debug = 1;
6850eb822a1Scindi }
6860eb822a1Scindi 
6872eeaed14Srobj ipmi_handle_t *
topo_mod_ipmi_hold(topo_mod_t * mod)6880b1b4412SEric Schrock topo_mod_ipmi_hold(topo_mod_t *mod)
6892eeaed14Srobj {
6902eeaed14Srobj 	topo_hdl_t *thp = mod->tm_hdl;
6912eeaed14Srobj 	int err;
6922eeaed14Srobj 	char *errmsg;
6932eeaed14Srobj 
6940b1b4412SEric Schrock 	(void) pthread_mutex_lock(&thp->th_ipmi_lock);
6950b1b4412SEric Schrock 	if (thp->th_ipmi == NULL) {
69681d9f076SRobert Johnston 		if ((thp->th_ipmi = ipmi_open(&err, &errmsg, IPMI_TRANSPORT_BMC,
69781d9f076SRobert Johnston 		    NULL)) == NULL) {
6982eeaed14Srobj 			topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
6992eeaed14Srobj 			    "ipmi_open() failed: %s (ipmi errno=%d)", errmsg,
7002eeaed14Srobj 			    err);
7010b1b4412SEric Schrock 			(void) pthread_mutex_unlock(&thp->th_ipmi_lock);
7020b1b4412SEric Schrock 		}
7030b1b4412SEric Schrock 	}
7040b1b4412SEric Schrock 
7052eeaed14Srobj 
7062eeaed14Srobj 	return (thp->th_ipmi);
7072eeaed14Srobj }
7082eeaed14Srobj 
7090b1b4412SEric Schrock void
topo_mod_ipmi_rele(topo_mod_t * mod)7100b1b4412SEric Schrock topo_mod_ipmi_rele(topo_mod_t *mod)
7110b1b4412SEric Schrock {
7120b1b4412SEric Schrock 	topo_hdl_t *thp = mod->tm_hdl;
7130b1b4412SEric Schrock 
7140b1b4412SEric Schrock 	(void) pthread_mutex_unlock(&thp->th_ipmi_lock);
7150b1b4412SEric Schrock }
7160b1b4412SEric Schrock 
717c93c462eSCheng Sean Ye di_node_t
topo_mod_devinfo(topo_mod_t * mod)718c93c462eSCheng Sean Ye topo_mod_devinfo(topo_mod_t *mod)
719c93c462eSCheng Sean Ye {
720c93c462eSCheng Sean Ye 	return (topo_hdl_devinfo(mod->tm_hdl));
721c93c462eSCheng Sean Ye }
722c93c462eSCheng Sean Ye 
723738c43b5SEric Schrock smbios_hdl_t *
topo_mod_smbios(topo_mod_t * mod)724738c43b5SEric Schrock topo_mod_smbios(topo_mod_t *mod)
725738c43b5SEric Schrock {
726738c43b5SEric Schrock 	topo_hdl_t *thp = mod->tm_hdl;
727738c43b5SEric Schrock 
728738c43b5SEric Schrock 	if (thp->th_smbios == NULL)
729738c43b5SEric Schrock 		thp->th_smbios = smbios_open(NULL, SMB_VERSION, 0, NULL);
730738c43b5SEric Schrock 
731738c43b5SEric Schrock 	return (thp->th_smbios);
732738c43b5SEric Schrock }
733738c43b5SEric Schrock 
7340eb822a1Scindi di_prom_handle_t
topo_mod_prominfo(topo_mod_t * mod)7350eb822a1Scindi topo_mod_prominfo(topo_mod_t *mod)
7367aec1d6eScindi {
737c93c462eSCheng Sean Ye 	return (topo_hdl_prominfo(mod->tm_hdl));
7387aec1d6eScindi }
7397aec1d6eScindi 
74066d05358SRob Johnston pcidb_hdl_t *
topo_mod_pcidb(topo_mod_t * mod)74166d05358SRob Johnston topo_mod_pcidb(topo_mod_t *mod)
74266d05358SRob Johnston {
74366d05358SRob Johnston 	topo_hdl_t *thp = mod->tm_hdl;
74466d05358SRob Johnston 
74566d05358SRob Johnston 	if (thp->th_pcidb == NULL)
74666d05358SRob Johnston 		thp->th_pcidb = pcidb_open(PCIDB_VERSION);
74766d05358SRob Johnston 
74866d05358SRob Johnston 	return (thp->th_pcidb);
74966d05358SRob Johnston }
75066d05358SRob Johnston 
7517aec1d6eScindi void
topo_mod_clrdebug(topo_mod_t * mod)7527aec1d6eScindi topo_mod_clrdebug(topo_mod_t *mod)
7537aec1d6eScindi {
7547aec1d6eScindi 	mod->tm_debug = 0;
7557aec1d6eScindi }
7567aec1d6eScindi 
7577aec1d6eScindi /*PRINTFLIKE2*/
7587aec1d6eScindi void
topo_mod_dprintf(topo_mod_t * mod,const char * format,...)7597aec1d6eScindi topo_mod_dprintf(topo_mod_t *mod, const char *format, ...)
7607aec1d6eScindi {
7611de1e652SRob Johnston 	topo_hdl_t *thp = mod->tm_hdl;
7620eb822a1Scindi 	va_list alist;
7630eb822a1Scindi 
7641de1e652SRob Johnston 	if (mod->tm_debug == 0 || !(thp->th_debug & TOPO_DBG_MOD))
7650eb822a1Scindi 		return;
7660eb822a1Scindi 
7670eb822a1Scindi 	va_start(alist, format);
7681de1e652SRob Johnston 	topo_vdprintf(mod->tm_hdl, (const char *)mod->tm_name, format, alist);
7690eb822a1Scindi 	va_end(alist);
7700eb822a1Scindi }
7710eb822a1Scindi 
772317c37f3SRob Johnston char *
topo_mod_product(topo_mod_t * mod)7730eb822a1Scindi topo_mod_product(topo_mod_t *mod)
7740eb822a1Scindi {
7750eb822a1Scindi 	return (topo_mod_strdup(mod, mod->tm_hdl->th_product));
7760eb822a1Scindi }
7770eb822a1Scindi 
7780eb822a1Scindi static char *
topo_mod_server(topo_mod_t * mod)7790eb822a1Scindi topo_mod_server(topo_mod_t *mod)
7800eb822a1Scindi {
7810eb822a1Scindi 	static struct utsname uts;
7827aec1d6eScindi 
7830eb822a1Scindi 	(void) uname(&uts);
7840eb822a1Scindi 	return (topo_mod_strdup(mod, uts.nodename));
7850eb822a1Scindi }
7860eb822a1Scindi 
7879c94f155SCheng Sean Ye static char *
topo_mod_psn(topo_mod_t * mod)7889c94f155SCheng Sean Ye topo_mod_psn(topo_mod_t *mod)
7899c94f155SCheng Sean Ye {
7909c94f155SCheng Sean Ye 	smbios_hdl_t *shp;
7919c94f155SCheng Sean Ye 	const char *psn;
7929c94f155SCheng Sean Ye 
7939c94f155SCheng Sean Ye 	if ((shp = topo_mod_smbios(mod)) == NULL ||
7949c94f155SCheng Sean Ye 	    (psn = smbios_psn(shp)) == NULL)
7959c94f155SCheng Sean Ye 		return (NULL);
7969c94f155SCheng Sean Ye 
7979c94f155SCheng Sean Ye 	return (topo_cleanup_auth_str(mod->tm_hdl, psn));
7989c94f155SCheng Sean Ye }
7999c94f155SCheng Sean Ye 
8000eb822a1Scindi static char *
topo_mod_csn(topo_mod_t * mod)8010eb822a1Scindi topo_mod_csn(topo_mod_t *mod)
8020eb822a1Scindi {
8030eb822a1Scindi 	char csn[MAXNAMELEN];
8049c94f155SCheng Sean Ye 	smbios_hdl_t *shp;
8050eb822a1Scindi 	di_prom_handle_t promh = DI_PROM_HANDLE_NIL;
8060eb822a1Scindi 	di_node_t rooth = DI_NODE_NIL;
8079c94f155SCheng Sean Ye 	const char *bufp;
8080eb822a1Scindi 
809738c43b5SEric Schrock 	if ((shp = topo_mod_smbios(mod)) != NULL) {
8109c94f155SCheng Sean Ye 		bufp = smbios_csn(shp);
8119c94f155SCheng Sean Ye 		if (bufp != NULL)
8129c94f155SCheng Sean Ye 			(void) strlcpy(csn, bufp, MAXNAMELEN);
8139c94f155SCheng Sean Ye 		else
8140eb822a1Scindi 			return (NULL);
8150eb822a1Scindi 	} else if ((rooth = topo_mod_devinfo(mod)) != DI_NODE_NIL &&
8160eb822a1Scindi 	    (promh = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) {
8170eb822a1Scindi 		if (di_prom_prop_lookup_bytes(promh, rooth, "chassis-sn",
8180eb822a1Scindi 		    (unsigned char **)&bufp) != -1) {
8190eb822a1Scindi 			(void) strlcpy(csn, bufp, MAXNAMELEN);
8200eb822a1Scindi 		} else {
8210eb822a1Scindi 			return (NULL);
8220eb822a1Scindi 		}
8230eb822a1Scindi 	} else {
8240eb822a1Scindi 		return (NULL);
8257aec1d6eScindi 	}
8260eb822a1Scindi 
82724db4641Seschrock 	return (topo_cleanup_auth_str(mod->tm_hdl, csn));
8280eb822a1Scindi }
8290eb822a1Scindi 
8300eb822a1Scindi nvlist_t *
topo_mod_auth(topo_mod_t * mod,tnode_t * pnode)8310eb822a1Scindi topo_mod_auth(topo_mod_t *mod, tnode_t *pnode)
8320eb822a1Scindi {
8330eb822a1Scindi 	int err;
8340eb822a1Scindi 	char *prod = NULL;
8350eb822a1Scindi 	char *csn = NULL;
8369c94f155SCheng Sean Ye 	char *psn = NULL;
8370eb822a1Scindi 	char *server = NULL;
8380eb822a1Scindi 	nvlist_t *auth;
8390eb822a1Scindi 
84012cc75c8Scindi 	if ((err = topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME)) != 0) {
84112cc75c8Scindi 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
84212cc75c8Scindi 		return (NULL);
84312cc75c8Scindi 	}
84412cc75c8Scindi 
8450eb822a1Scindi 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
8460eb822a1Scindi 	    FM_FMRI_AUTH_PRODUCT, &prod, &err);
8479c94f155SCheng Sean Ye 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
8489c94f155SCheng Sean Ye 	    FM_FMRI_AUTH_PRODUCT_SN, &psn, &err);
8490eb822a1Scindi 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
8500eb822a1Scindi 	    FM_FMRI_AUTH_CHASSIS, &csn, &err);
8510eb822a1Scindi 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
8520eb822a1Scindi 	    FM_FMRI_AUTH_SERVER, &server, &err);
8530eb822a1Scindi 
8540eb822a1Scindi 	/*
8550eb822a1Scindi 	 * Let's do this the hard way
8560eb822a1Scindi 	 */
8570eb822a1Scindi 	if (prod == NULL)
8580eb822a1Scindi 		prod = topo_mod_product(mod);
8590eb822a1Scindi 	if (csn == NULL)
8600eb822a1Scindi 		csn = topo_mod_csn(mod);
8619c94f155SCheng Sean Ye 	if (psn == NULL)
8629c94f155SCheng Sean Ye 		psn = topo_mod_psn(mod);
8630eb822a1Scindi 	if (server == NULL) {
8640eb822a1Scindi 		server = topo_mod_server(mod);
8650eb822a1Scindi 	}
8660eb822a1Scindi 
8670eb822a1Scindi 	/*
8680eb822a1Scindi 	 * No luck, return NULL
8690eb822a1Scindi 	 */
8709c94f155SCheng Sean Ye 	if (!prod && !server && !csn && !psn) {
87112cc75c8Scindi 		nvlist_free(auth);
8720eb822a1Scindi 		return (NULL);
8730eb822a1Scindi 	}
8740eb822a1Scindi 
87512cc75c8Scindi 	err = 0;
8760eb822a1Scindi 	if (prod != NULL) {
8770eb822a1Scindi 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, prod);
8780eb822a1Scindi 		topo_mod_strfree(mod, prod);
8790eb822a1Scindi 	}
8809c94f155SCheng Sean Ye 	if (psn != NULL) {
8819c94f155SCheng Sean Ye 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT_SN, psn);
8829c94f155SCheng Sean Ye 		topo_mod_strfree(mod, psn);
8839c94f155SCheng Sean Ye 	}
8840eb822a1Scindi 	if (server != NULL) {
8850eb822a1Scindi 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, server);
8860eb822a1Scindi 		topo_mod_strfree(mod, server);
8870eb822a1Scindi 	}
8880eb822a1Scindi 	if (csn != NULL) {
8890eb822a1Scindi 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, csn);
8900eb822a1Scindi 		topo_mod_strfree(mod, csn);
8910eb822a1Scindi 	}
8920eb822a1Scindi 
8930eb822a1Scindi 	if (err != 0) {
8940eb822a1Scindi 		nvlist_free(auth);
8950eb822a1Scindi 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
8960eb822a1Scindi 		return (NULL);
8970eb822a1Scindi 	}
8980eb822a1Scindi 
8990eb822a1Scindi 	return (auth);
9007aec1d6eScindi }
901c40d7343Scindi 
902c40d7343Scindi topo_walk_t *
topo_mod_walk_init(topo_mod_t * mod,tnode_t * node,topo_mod_walk_cb_t cb_f,void * pdata,int * errp)903c40d7343Scindi topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f,
904c40d7343Scindi     void *pdata, int *errp)
905c40d7343Scindi {
906c40d7343Scindi 	topo_walk_t *wp;
907c40d7343Scindi 	topo_hdl_t *thp = mod->tm_hdl;
908c40d7343Scindi 
909c40d7343Scindi 	if ((wp = topo_node_walk_init(thp, mod, node, (int (*)())cb_f, pdata,
910c40d7343Scindi 	    errp)) == NULL)
911c40d7343Scindi 		return (NULL);
912c40d7343Scindi 
913c40d7343Scindi 	return (wp);
914c40d7343Scindi }
9156d65bee7SRob Johnston 
9166d65bee7SRob Johnston char *
topo_mod_clean_str(topo_mod_t * mod,const char * str)9176d65bee7SRob Johnston topo_mod_clean_str(topo_mod_t *mod, const char *str)
9186d65bee7SRob Johnston {
9196d65bee7SRob Johnston 	if (str == NULL)
9206d65bee7SRob Johnston 		return (NULL);
9216d65bee7SRob Johnston 
922*9c994d58SRobert Mustacchi 	return (topo_cleanup_strn(mod->tm_hdl, str, strlen(str)));
923*9c994d58SRobert Mustacchi }
924*9c994d58SRobert Mustacchi 
925*9c994d58SRobert Mustacchi char *
topo_mod_clean_strn(topo_mod_t * mod,const char * str,size_t len)926*9c994d58SRobert Mustacchi topo_mod_clean_strn(topo_mod_t *mod, const char *str, size_t len)
927*9c994d58SRobert Mustacchi {
928*9c994d58SRobert Mustacchi 	if (str == NULL)
929*9c994d58SRobert Mustacchi 		return (NULL);
930*9c994d58SRobert Mustacchi 
931*9c994d58SRobert Mustacchi 	return (topo_cleanup_strn(mod->tm_hdl, str, len));
9326d65bee7SRob Johnston }
933672fc84aSRobert Mustacchi 
934672fc84aSRobert Mustacchi int
topo_mod_file_search(topo_mod_t * mod,const char * file,int oflags)935672fc84aSRobert Mustacchi topo_mod_file_search(topo_mod_t *mod, const char *file, int oflags)
936672fc84aSRobert Mustacchi {
937672fc84aSRobert Mustacchi 	int ret;
938672fc84aSRobert Mustacchi 	char *path;
939672fc84aSRobert Mustacchi 	topo_hdl_t *thp = mod->tm_hdl;
940672fc84aSRobert Mustacchi 
941672fc84aSRobert Mustacchi 	path = topo_search_path(mod, thp->th_rootdir, file);
942672fc84aSRobert Mustacchi 	if (path == NULL) {
943672fc84aSRobert Mustacchi 		return (-1);
944672fc84aSRobert Mustacchi 	}
945672fc84aSRobert Mustacchi 
946672fc84aSRobert Mustacchi 	ret = open(path, oflags);
947672fc84aSRobert Mustacchi 	topo_mod_strfree(mod, path);
948672fc84aSRobert Mustacchi 	return (ret);
949672fc84aSRobert Mustacchi }
9508abca89fSRob Johnston 
9518abca89fSRob Johnston /*ARGSUSED*/
9528abca89fSRob Johnston int
topo_mod_hc_occupied(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)9538abca89fSRob Johnston topo_mod_hc_occupied(topo_mod_t *mod, tnode_t *node, topo_version_t version,
9548abca89fSRob Johnston     nvlist_t *in, nvlist_t **out)
9558abca89fSRob Johnston {
9568abca89fSRob Johnston 	nvlist_t *nvl = NULL;
9578abca89fSRob Johnston 	tnode_t *cnp;
9588abca89fSRob Johnston 	boolean_t is_occupied = B_FALSE;
9598abca89fSRob Johnston 
9608abca89fSRob Johnston 	if (version > TOPO_METH_OCCUPIED_VERSION)
9618abca89fSRob Johnston 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
9628abca89fSRob Johnston 
9638abca89fSRob Johnston 	/*
9648abca89fSRob Johnston 	 * Iterate though the child nodes.  If there are no non-facility
9658abca89fSRob Johnston 	 * node children then it is unoccupied.
9668abca89fSRob Johnston 	 */
9678abca89fSRob Johnston 	for (cnp = topo_child_first(node); cnp != NULL;
9688abca89fSRob Johnston 	    cnp = topo_child_next(node, cnp)) {
9698abca89fSRob Johnston 		if (topo_node_flags(cnp) != TOPO_NODE_FACILITY)
9708abca89fSRob Johnston 			is_occupied = B_TRUE;
9718abca89fSRob Johnston 	}
9728abca89fSRob Johnston 
9738abca89fSRob Johnston 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
9748abca89fSRob Johnston 	    nvlist_add_boolean_value(nvl, TOPO_METH_OCCUPIED_RET,
9758abca89fSRob Johnston 	    is_occupied) != 0) {
9768abca89fSRob Johnston 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
9778abca89fSRob Johnston 		nvlist_free(nvl);
9788abca89fSRob Johnston 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
9798abca89fSRob Johnston 	}
9808abca89fSRob Johnston 	*out = nvl;
9818abca89fSRob Johnston 
9828abca89fSRob Johnston 	return (0);
9838abca89fSRob Johnston }
984508a0e8cSRob Johnston 
985508a0e8cSRob Johnston /*
986508a0e8cSRob Johnston  * Convenience routine for creating a UFM slot node.  This routine assumes
987508a0e8cSRob Johnston  * that the caller has already created the containing range via a call to
988508a0e8cSRob Johnston  * topo_node_range_create().
989508a0e8cSRob Johnston  */
990508a0e8cSRob Johnston tnode_t *
topo_mod_create_ufm_slot(topo_mod_t * mod,tnode_t * ufmnode,topo_ufm_slot_info_t * slotinfo)991508a0e8cSRob Johnston topo_mod_create_ufm_slot(topo_mod_t *mod, tnode_t *ufmnode,
992508a0e8cSRob Johnston     topo_ufm_slot_info_t *slotinfo)
993508a0e8cSRob Johnston {
994508a0e8cSRob Johnston 	nvlist_t *auth = NULL, *fmri = NULL;
995508a0e8cSRob Johnston 	tnode_t *slotnode;
996508a0e8cSRob Johnston 	topo_pgroup_info_t pgi;
997508a0e8cSRob Johnston 	int err, rc;
998508a0e8cSRob Johnston 
999744642a2SRobert Mustacchi 	if (slotinfo == NULL || slotinfo->usi_mode == 0) {
1000508a0e8cSRob Johnston 		topo_mod_dprintf(mod, "invalid slot info");
1001508a0e8cSRob Johnston 		(void) topo_mod_seterrno(mod, ETOPO_MOD_INVAL);
1002508a0e8cSRob Johnston 		return (NULL);
1003508a0e8cSRob Johnston 	}
1004508a0e8cSRob Johnston 	if ((auth = topo_mod_auth(mod, ufmnode)) == NULL) {
1005508a0e8cSRob Johnston 		topo_mod_dprintf(mod, "topo_mod_auth() failed: %s",
1006508a0e8cSRob Johnston 		    topo_mod_errmsg(mod));
1007508a0e8cSRob Johnston 		/* errno set */
1008508a0e8cSRob Johnston 		return (NULL);
1009508a0e8cSRob Johnston 	}
1010508a0e8cSRob Johnston 
1011508a0e8cSRob Johnston 	if ((fmri = topo_mod_hcfmri(mod, ufmnode, FM_HC_SCHEME_VERSION,
1012508a0e8cSRob Johnston 	    SLOT, slotinfo->usi_slotid, NULL, auth, NULL, NULL, NULL)) ==
1013508a0e8cSRob Johnston 	    NULL) {
1014508a0e8cSRob Johnston 		nvlist_free(auth);
1015508a0e8cSRob Johnston 		topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
1016508a0e8cSRob Johnston 		    topo_mod_errmsg(mod));
1017508a0e8cSRob Johnston 		/* errno set */
1018508a0e8cSRob Johnston 		return (NULL);
1019508a0e8cSRob Johnston 	}
1020508a0e8cSRob Johnston 
1021508a0e8cSRob Johnston 	if ((slotnode = topo_node_bind(mod, ufmnode, SLOT,
1022508a0e8cSRob Johnston 	    slotinfo->usi_slotid, fmri)) == NULL) {
1023508a0e8cSRob Johnston 		nvlist_free(auth);
1024508a0e8cSRob Johnston 		nvlist_free(fmri);
1025508a0e8cSRob Johnston 		topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
1026508a0e8cSRob Johnston 		    topo_mod_errmsg(mod));
1027508a0e8cSRob Johnston 		/* errno set */
1028508a0e8cSRob Johnston 		return (NULL);
1029508a0e8cSRob Johnston 	}
1030508a0e8cSRob Johnston 
1031508a0e8cSRob Johnston 	/* Create authority and system pgroups */
1032508a0e8cSRob Johnston 	topo_pgroup_hcset(slotnode, auth);
1033508a0e8cSRob Johnston 	nvlist_free(auth);
1034508a0e8cSRob Johnston 	nvlist_free(fmri);
1035508a0e8cSRob Johnston 
1036508a0e8cSRob Johnston 	/* Just inherit the parent's FRU */
1037508a0e8cSRob Johnston 	if (topo_node_fru_set(slotnode, NULL, 0, &err) != 0) {
1038508a0e8cSRob Johnston 		topo_mod_dprintf(mod, "failed to set FRU on %s: %s", UFM,
1039508a0e8cSRob Johnston 		    topo_strerror(err));
1040508a0e8cSRob Johnston 		(void) topo_mod_seterrno(mod, err);
1041508a0e8cSRob Johnston 		goto slotfail;
1042508a0e8cSRob Johnston 	}
1043508a0e8cSRob Johnston 
1044508a0e8cSRob Johnston 	pgi.tpi_name = TOPO_PGROUP_SLOT;
1045508a0e8cSRob Johnston 	pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1046508a0e8cSRob Johnston 	pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1047508a0e8cSRob Johnston 	pgi.tpi_version = TOPO_VERSION;
1048508a0e8cSRob Johnston 	rc = topo_pgroup_create(slotnode, &pgi, &err);
1049508a0e8cSRob Johnston 
1050508a0e8cSRob Johnston 	if (rc == 0)
1051508a0e8cSRob Johnston 		rc += topo_prop_set_uint32(slotnode, TOPO_PGROUP_SLOT,
1052508a0e8cSRob Johnston 		    TOPO_PROP_SLOT_TYPE, TOPO_PROP_IMMUTABLE,
1053508a0e8cSRob Johnston 		    TOPO_SLOT_TYPE_UFM, &err);
1054508a0e8cSRob Johnston 
1055508a0e8cSRob Johnston 	pgi.tpi_name = TOPO_PGROUP_UFM_SLOT;
1056508a0e8cSRob Johnston 
1057508a0e8cSRob Johnston 	if (rc == 0)
1058508a0e8cSRob Johnston 		rc += topo_pgroup_create(slotnode, &pgi, &err);
1059508a0e8cSRob Johnston 
1060508a0e8cSRob Johnston 	if (rc == 0) {
1061508a0e8cSRob Johnston 		rc += topo_prop_set_uint32(slotnode, TOPO_PGROUP_UFM_SLOT,
1062508a0e8cSRob Johnston 		    TOPO_PROP_UFM_SLOT_MODE, TOPO_PROP_IMMUTABLE,
1063508a0e8cSRob Johnston 		    slotinfo->usi_mode, &err);
1064508a0e8cSRob Johnston 	}
1065508a0e8cSRob Johnston 
1066508a0e8cSRob Johnston 	if (rc == 0) {
1067508a0e8cSRob Johnston 		rc += topo_prop_set_uint32(slotnode, TOPO_PGROUP_UFM_SLOT,
1068508a0e8cSRob Johnston 		    TOPO_PROP_UFM_SLOT_ACTIVE, TOPO_PROP_IMMUTABLE,
1069508a0e8cSRob Johnston 		    (uint32_t)slotinfo->usi_active, &err);
1070508a0e8cSRob Johnston 	}
1071508a0e8cSRob Johnston 
1072744642a2SRobert Mustacchi 	/*
1073744642a2SRobert Mustacchi 	 * We can have a NULL version for an empty slot.
1074744642a2SRobert Mustacchi 	 */
1075744642a2SRobert Mustacchi 	if (rc == 0 && slotinfo->usi_version != NULL) {
1076508a0e8cSRob Johnston 		rc += topo_prop_set_string(slotnode, TOPO_PGROUP_UFM_SLOT,
1077508a0e8cSRob Johnston 		    TOPO_PROP_UFM_SLOT_VERSION, TOPO_PROP_IMMUTABLE,
1078508a0e8cSRob Johnston 		    slotinfo->usi_version, &err);
1079508a0e8cSRob Johnston 	}
1080508a0e8cSRob Johnston 
1081508a0e8cSRob Johnston 	if (rc == 0 && slotinfo->usi_extra != NULL) {
1082508a0e8cSRob Johnston 		nvpair_t *elem = NULL;
1083508a0e8cSRob Johnston 		char *pname, *pval;
1084508a0e8cSRob Johnston 
1085508a0e8cSRob Johnston 		while ((elem = nvlist_next_nvpair(slotinfo->usi_extra,
1086508a0e8cSRob Johnston 		    elem)) != NULL) {
1087508a0e8cSRob Johnston 			if (nvpair_type(elem) != DATA_TYPE_STRING)
1088508a0e8cSRob Johnston 				continue;
1089508a0e8cSRob Johnston 
1090508a0e8cSRob Johnston 			pname = nvpair_name(elem);
1091508a0e8cSRob Johnston 			if ((rc -= nvpair_value_string(elem, &pval)) != 0)
1092508a0e8cSRob Johnston 				break;
1093508a0e8cSRob Johnston 
1094508a0e8cSRob Johnston 			rc += topo_prop_set_string(slotnode,
1095508a0e8cSRob Johnston 			    TOPO_PGROUP_UFM_SLOT, pname, TOPO_PROP_IMMUTABLE,
1096508a0e8cSRob Johnston 			    pval, &err);
1097508a0e8cSRob Johnston 
1098508a0e8cSRob Johnston 			if (rc != 0)
1099508a0e8cSRob Johnston 				break;
1100508a0e8cSRob Johnston 		}
1101508a0e8cSRob Johnston 	}
1102508a0e8cSRob Johnston 
1103508a0e8cSRob Johnston 	if (rc != 0) {
1104508a0e8cSRob Johnston 		topo_mod_dprintf(mod, "error setting properties on %s node",
1105508a0e8cSRob Johnston 		    SLOT);
1106508a0e8cSRob Johnston 		(void) topo_mod_seterrno(mod, err);
1107508a0e8cSRob Johnston 		goto slotfail;
1108508a0e8cSRob Johnston 	}
1109508a0e8cSRob Johnston 	return (slotnode);
1110508a0e8cSRob Johnston 
1111508a0e8cSRob Johnston slotfail:
1112508a0e8cSRob Johnston 	topo_node_unbind(slotnode);
1113508a0e8cSRob Johnston 	return (NULL);
1114508a0e8cSRob Johnston }
1115508a0e8cSRob Johnston 
1116508a0e8cSRob Johnston /*
1117508a0e8cSRob Johnston  * This is a convenience routine to allow enumerator modules to easily create
1118508a0e8cSRob Johnston  * the necessary UFM node layout for the most common case, which will be a
1119508a0e8cSRob Johnston  * single UFM with a single slot.  This routine assumes that the caller has
1120508a0e8cSRob Johnston  * already created the containing range via a call to topo_node_range_create().
1121508a0e8cSRob Johnston  *
1122508a0e8cSRob Johnston  * For more complex scenarios (like multiple slots per UFM), callers can set
1123508a0e8cSRob Johnston  * the slotinfo param to NULL.  In this case the ufm node will get created, but
1124508a0e8cSRob Johnston  * it will skip creating the slot node - allowing the module to manually call
1125508a0e8cSRob Johnston  * topo_mod_create_ufm_slot() to create custom UFM slots.
1126508a0e8cSRob Johnston  */
1127508a0e8cSRob Johnston tnode_t *
topo_mod_create_ufm(topo_mod_t * mod,tnode_t * parent,topo_instance_t inst,const char * descr,topo_ufm_slot_info_t * slotinfo)1128744642a2SRobert Mustacchi topo_mod_create_ufm(topo_mod_t *mod, tnode_t *parent, topo_instance_t inst,
1129744642a2SRobert Mustacchi     const char *descr, topo_ufm_slot_info_t *slotinfo)
1130508a0e8cSRob Johnston {
1131508a0e8cSRob Johnston 	nvlist_t *auth = NULL, *fmri = NULL;
1132508a0e8cSRob Johnston 	tnode_t *ufmnode, *slotnode;
1133508a0e8cSRob Johnston 	topo_pgroup_info_t pgi;
1134508a0e8cSRob Johnston 	int err, rc;
1135508a0e8cSRob Johnston 
1136508a0e8cSRob Johnston 	if ((auth = topo_mod_auth(mod, parent)) == NULL) {
1137508a0e8cSRob Johnston 		topo_mod_dprintf(mod, "topo_mod_auth() failed: %s",
1138508a0e8cSRob Johnston 		    topo_mod_errmsg(mod));
1139508a0e8cSRob Johnston 		/* errno set */
1140508a0e8cSRob Johnston 		return (NULL);
1141508a0e8cSRob Johnston 	}
1142508a0e8cSRob Johnston 
1143508a0e8cSRob Johnston 	if ((fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION,
1144744642a2SRobert Mustacchi 	    UFM, inst, NULL, auth, NULL, NULL, NULL)) ==
1145508a0e8cSRob Johnston 	    NULL) {
1146508a0e8cSRob Johnston 		nvlist_free(auth);
1147508a0e8cSRob Johnston 		topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
1148508a0e8cSRob Johnston 		    topo_mod_errmsg(mod));
1149508a0e8cSRob Johnston 		/* errno set */
1150508a0e8cSRob Johnston 		return (NULL);
1151508a0e8cSRob Johnston 	}
1152508a0e8cSRob Johnston 
1153744642a2SRobert Mustacchi 	if ((ufmnode = topo_node_bind(mod, parent, UFM, inst, fmri)) == NULL) {
1154508a0e8cSRob Johnston 		nvlist_free(auth);
1155508a0e8cSRob Johnston 		nvlist_free(fmri);
1156508a0e8cSRob Johnston 		topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
1157508a0e8cSRob Johnston 		    topo_mod_errmsg(mod));
1158508a0e8cSRob Johnston 		/* errno set */
1159508a0e8cSRob Johnston 		return (NULL);
1160508a0e8cSRob Johnston 	}
1161508a0e8cSRob Johnston 
1162508a0e8cSRob Johnston 	/* Create authority and system pgroups */
1163508a0e8cSRob Johnston 	topo_pgroup_hcset(ufmnode, auth);
1164508a0e8cSRob Johnston 	nvlist_free(auth);
1165508a0e8cSRob Johnston 	nvlist_free(fmri);
1166508a0e8cSRob Johnston 
1167508a0e8cSRob Johnston 	/* Just inherit the parent's FRU */
1168508a0e8cSRob Johnston 	if (topo_node_fru_set(ufmnode, NULL, 0, &err) != 0) {
1169508a0e8cSRob Johnston 		topo_mod_dprintf(mod, "failed to set FRU on %s: %s", UFM,
1170508a0e8cSRob Johnston 		    topo_strerror(err));
1171508a0e8cSRob Johnston 		(void) topo_mod_seterrno(mod, err);
1172508a0e8cSRob Johnston 		goto ufmfail;
1173508a0e8cSRob Johnston 	}
1174508a0e8cSRob Johnston 
1175508a0e8cSRob Johnston 	pgi.tpi_name = TOPO_PGROUP_UFM;
1176508a0e8cSRob Johnston 	pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1177508a0e8cSRob Johnston 	pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1178508a0e8cSRob Johnston 	pgi.tpi_version = TOPO_VERSION;
1179508a0e8cSRob Johnston 	rc = topo_pgroup_create(ufmnode, &pgi, &err);
1180508a0e8cSRob Johnston 
1181508a0e8cSRob Johnston 	if (rc == 0)
1182508a0e8cSRob Johnston 		rc += topo_prop_set_string(ufmnode, TOPO_PGROUP_UFM,
1183508a0e8cSRob Johnston 		    TOPO_PROP_UFM_DESCR, TOPO_PROP_IMMUTABLE, descr, &err);
1184508a0e8cSRob Johnston 
1185508a0e8cSRob Johnston 	if (rc != 0) {
1186508a0e8cSRob Johnston 		topo_mod_dprintf(mod, "error setting properties on %s node",
1187508a0e8cSRob Johnston 		    UFM);
1188508a0e8cSRob Johnston 		(void) topo_mod_seterrno(mod, err);
1189508a0e8cSRob Johnston 		goto ufmfail;
1190508a0e8cSRob Johnston 	}
1191508a0e8cSRob Johnston 
1192508a0e8cSRob Johnston 	if (slotinfo != NULL) {
1193508a0e8cSRob Johnston 		if (topo_node_range_create(mod, ufmnode, SLOT, 0, 0) < 0) {
1194508a0e8cSRob Johnston 			topo_mod_dprintf(mod, "error creating %s range", SLOT);
1195508a0e8cSRob Johnston 			goto ufmfail;
1196508a0e8cSRob Johnston 		}
1197508a0e8cSRob Johnston 		slotnode = topo_mod_create_ufm_slot(mod, ufmnode, slotinfo);
1198508a0e8cSRob Johnston 
1199508a0e8cSRob Johnston 		if (slotnode == NULL)
1200508a0e8cSRob Johnston 			goto ufmfail;
1201508a0e8cSRob Johnston 	}
1202508a0e8cSRob Johnston 	return (ufmnode);
1203508a0e8cSRob Johnston 
1204508a0e8cSRob Johnston ufmfail:
1205508a0e8cSRob Johnston 	topo_node_unbind(ufmnode);
1206508a0e8cSRob Johnston 	return (NULL);
1207508a0e8cSRob Johnston }
1208