xref: /titanic_41/usr/src/lib/fm/topo/libtopo/common/hc.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
17aec1d6eScindi /*
27aec1d6eScindi  *
37aec1d6eScindi  * CDDL HEADER START
47aec1d6eScindi  *
57aec1d6eScindi  * The contents of this file are subject to the terms of the
67aec1d6eScindi  * Common Development and Distribution License (the "License").
77aec1d6eScindi  * You may not use this file except in compliance with the License.
87aec1d6eScindi  *
97aec1d6eScindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107aec1d6eScindi  * or http://www.opensolaris.org/os/licensing.
117aec1d6eScindi  * See the License for the specific language governing permissions
127aec1d6eScindi  * and limitations under the License.
137aec1d6eScindi  *
147aec1d6eScindi  * When distributing Covered Code, include this CDDL HEADER in each
157aec1d6eScindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167aec1d6eScindi  * If applicable, add the following below this CDDL HEADER, with the
177aec1d6eScindi  * fields enclosed by brackets "[]" replaced with your own identifying
187aec1d6eScindi  * information: Portions Copyright [yyyy] [name of copyright owner]
197aec1d6eScindi  *
207aec1d6eScindi  * CDDL HEADER END
217aec1d6eScindi  */
227aec1d6eScindi 
237aec1d6eScindi /*
24ac88567aSHyon Kim  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
257aec1d6eScindi  */
267aec1d6eScindi 
277aec1d6eScindi #include <stdio.h>
287aec1d6eScindi #include <stdlib.h>
297aec1d6eScindi #include <string.h>
307aec1d6eScindi #include <errno.h>
317aec1d6eScindi #include <ctype.h>
327aec1d6eScindi #include <alloca.h>
33e4b86885SCheng Sean Ye #include <assert.h>
347aec1d6eScindi #include <limits.h>
35*f6e214c7SGavin Maltby #include <zone.h>
367aec1d6eScindi #include <fm/topo_mod.h>
370eb822a1Scindi #include <fm/topo_hc.h>
3825c6ff4bSstephh #include <fm/fmd_fmri.h>
397aec1d6eScindi #include <sys/param.h>
407aec1d6eScindi #include <sys/systeminfo.h>
417aec1d6eScindi #include <sys/fm/protocol.h>
420eb822a1Scindi #include <sys/stat.h>
430eb822a1Scindi #include <sys/systeminfo.h>
440eb822a1Scindi #include <sys/utsname.h>
450eb822a1Scindi 
460eb822a1Scindi #include <topo_method.h>
47825ba0f2Srobj #include <topo_module.h>
4874a31ce6Stimh #include <topo_subr.h>
49c40d7343Scindi #include <topo_prop.h>
50940d71d2Seschrock #include <topo_tree.h>
510eb822a1Scindi #include <hc.h>
527aec1d6eScindi 
537aec1d6eScindi static int hc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
540eb822a1Scindi     topo_instance_t, void *, void *);
557aec1d6eScindi static void hc_release(topo_mod_t *, tnode_t *);
567aec1d6eScindi static int hc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t,
577aec1d6eScindi     nvlist_t *, nvlist_t **);
587aec1d6eScindi static int hc_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t,
597aec1d6eScindi     nvlist_t *, nvlist_t **);
607aec1d6eScindi static int hc_compare(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
617aec1d6eScindi     nvlist_t **);
62c40d7343Scindi static int hc_fmri_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
63c40d7343Scindi     nvlist_t **);
6425c6ff4bSstephh static int hc_fmri_replaced(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
6525c6ff4bSstephh     nvlist_t **);
66c40d7343Scindi static int hc_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
67c40d7343Scindi     nvlist_t **);
68e4b86885SCheng Sean Ye static int hc_fmri_expand(topo_mod_t *, tnode_t *, topo_version_t,
69e4b86885SCheng Sean Ye     nvlist_t *, nvlist_t **);
70e4b86885SCheng Sean Ye static int hc_fmri_retire(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
71e4b86885SCheng Sean Ye     nvlist_t **);
72e4b86885SCheng Sean Ye static int hc_fmri_unretire(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
73e4b86885SCheng Sean Ye     nvlist_t **);
74e4b86885SCheng Sean Ye static int hc_fmri_service_state(topo_mod_t *, tnode_t *, topo_version_t,
75e4b86885SCheng Sean Ye     nvlist_t *, nvlist_t **);
767aec1d6eScindi static int hc_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t,
777aec1d6eScindi     nvlist_t *, nvlist_t **);
78c40d7343Scindi static int hc_fmri_prop_get(topo_mod_t *, tnode_t *, topo_version_t,
79c40d7343Scindi     nvlist_t *, nvlist_t **);
80c40d7343Scindi static int hc_fmri_prop_set(topo_mod_t *, tnode_t *, topo_version_t,
81c40d7343Scindi     nvlist_t *, nvlist_t **);
82c40d7343Scindi static int hc_fmri_pgrp_get(topo_mod_t *, tnode_t *, topo_version_t,
83c40d7343Scindi     nvlist_t *, nvlist_t **);
84825ba0f2Srobj static int hc_fmri_facility(topo_mod_t *, tnode_t *, topo_version_t,
85825ba0f2Srobj     nvlist_t *, nvlist_t **);
867aec1d6eScindi 
877aec1d6eScindi static nvlist_t *hc_fmri_create(topo_mod_t *, nvlist_t *, int, const char *,
887aec1d6eScindi     topo_instance_t inst, const nvlist_t *, const char *, const char *,
897aec1d6eScindi     const char *);
907aec1d6eScindi 
917aec1d6eScindi const topo_method_t hc_methods[] = {
927aec1d6eScindi 	{ TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION,
937aec1d6eScindi 	    TOPO_STABILITY_INTERNAL, hc_fmri_nvl2str },
947aec1d6eScindi 	{ TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION,
957aec1d6eScindi 	    TOPO_STABILITY_INTERNAL, hc_fmri_str2nvl },
967aec1d6eScindi 	{ TOPO_METH_COMPARE, TOPO_METH_COMPARE_DESC, TOPO_METH_COMPARE_VERSION,
977aec1d6eScindi 	    TOPO_STABILITY_INTERNAL, hc_compare },
98c40d7343Scindi 	{ TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION,
99c40d7343Scindi 	    TOPO_STABILITY_INTERNAL, hc_fmri_present },
10025c6ff4bSstephh 	{ TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC,
10125c6ff4bSstephh 	    TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL,
10225c6ff4bSstephh 	    hc_fmri_replaced },
103c40d7343Scindi 	{ TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
104c40d7343Scindi 	    TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
105c40d7343Scindi 	    hc_fmri_unusable },
106e4b86885SCheng Sean Ye 	{ TOPO_METH_EXPAND, TOPO_METH_EXPAND_DESC,
107e4b86885SCheng Sean Ye 	    TOPO_METH_EXPAND_VERSION, TOPO_STABILITY_INTERNAL,
108e4b86885SCheng Sean Ye 	    hc_fmri_expand },
109e4b86885SCheng Sean Ye 	{ TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
110e4b86885SCheng Sean Ye 	    TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
111e4b86885SCheng Sean Ye 	    hc_fmri_retire },
112e4b86885SCheng Sean Ye 	{ TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
113e4b86885SCheng Sean Ye 	    TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
114e4b86885SCheng Sean Ye 	    hc_fmri_unretire },
115e4b86885SCheng Sean Ye 	{ TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
116e4b86885SCheng Sean Ye 	    TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
117e4b86885SCheng Sean Ye 	    hc_fmri_service_state },
1187aec1d6eScindi 	{ TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION,
1197aec1d6eScindi 	    TOPO_STABILITY_INTERNAL, hc_fmri_create_meth },
120c40d7343Scindi 	{ TOPO_METH_PROP_GET, TOPO_METH_PROP_GET_DESC,
121c40d7343Scindi 	    TOPO_METH_PROP_GET_VERSION, TOPO_STABILITY_INTERNAL,
122c40d7343Scindi 	    hc_fmri_prop_get },
123c40d7343Scindi 	{ TOPO_METH_PROP_SET, TOPO_METH_PROP_SET_DESC,
124c40d7343Scindi 	    TOPO_METH_PROP_SET_VERSION, TOPO_STABILITY_INTERNAL,
125c40d7343Scindi 	    hc_fmri_prop_set },
126c40d7343Scindi 	{ TOPO_METH_PGRP_GET, TOPO_METH_PGRP_GET_DESC,
127c40d7343Scindi 	    TOPO_METH_PGRP_GET_VERSION, TOPO_STABILITY_INTERNAL,
128c40d7343Scindi 	    hc_fmri_pgrp_get },
129825ba0f2Srobj 	{ TOPO_METH_FACILITY, TOPO_METH_FACILITY_DESC,
130825ba0f2Srobj 	    TOPO_METH_FACILITY_VERSION, TOPO_STABILITY_INTERNAL,
131825ba0f2Srobj 	    hc_fmri_facility },
1327aec1d6eScindi 	{ NULL }
1337aec1d6eScindi };
1347aec1d6eScindi 
1350eb822a1Scindi static const topo_modops_t hc_ops =
1360eb822a1Scindi 	{ hc_enum, hc_release };
1370eb822a1Scindi static const topo_modinfo_t hc_info =
1380eb822a1Scindi 	{ HC, FM_FMRI_SCHEME_HC, HC_VERSION, &hc_ops };
1397aec1d6eScindi 
1400eb822a1Scindi static const hcc_t hc_canon[] = {
141908f1e13Ssd77468 	{ BANK, TOPO_STABILITY_PRIVATE },
142184cd04cScth 	{ BAY, TOPO_STABILITY_PRIVATE },
143908f1e13Ssd77468 	{ BLADE, TOPO_STABILITY_PRIVATE },
14414ea4bb7Ssd77468 	{ BRANCH, TOPO_STABILITY_PRIVATE },
1450eb822a1Scindi 	{ CMP, TOPO_STABILITY_PRIVATE },
1460eb822a1Scindi 	{ CENTERPLANE, TOPO_STABILITY_PRIVATE },
1470eb822a1Scindi 	{ CHASSIS, TOPO_STABILITY_PRIVATE },
1480eb822a1Scindi 	{ CHIP, TOPO_STABILITY_PRIVATE },
1490eb822a1Scindi 	{ CHIP_SELECT, TOPO_STABILITY_PRIVATE },
150908f1e13Ssd77468 	{ CORE, TOPO_STABILITY_PRIVATE },
151940d71d2Seschrock 	{ CONTROLLER, TOPO_STABILITY_PRIVATE },
1520eb822a1Scindi 	{ CPU, TOPO_STABILITY_PRIVATE },
15313faa912Ssd77468 	{ CPUBOARD, TOPO_STABILITY_PRIVATE },
1540eb822a1Scindi 	{ DIMM, TOPO_STABILITY_PRIVATE },
1550eb822a1Scindi 	{ DISK, TOPO_STABILITY_PRIVATE },
156908f1e13Ssd77468 	{ DRAM, TOPO_STABILITY_PRIVATE },
1570eb822a1Scindi 	{ DRAMCHANNEL, TOPO_STABILITY_PRIVATE },
1582eeaed14Srobj 	{ FAN, TOPO_STABILITY_PRIVATE },
159ded93414SHyon Kim 	{ FANBOARD, TOPO_STABILITY_PRIVATE },
1602eeaed14Srobj 	{ FANMODULE, TOPO_STABILITY_PRIVATE },
161fc333478STom Pothier 	{ HBA, TOPO_STABILITY_PRIVATE },
1620eb822a1Scindi 	{ HOSTBRIDGE, TOPO_STABILITY_PRIVATE },
1630eb822a1Scindi 	{ INTERCONNECT, TOPO_STABILITY_PRIVATE },
1640eb822a1Scindi 	{ IOBOARD, TOPO_STABILITY_PRIVATE },
165ac88567aSHyon Kim 	{ IPORT, TOPO_STABILITY_PRIVATE },
16613faa912Ssd77468 	{ MEMBOARD, TOPO_STABILITY_PRIVATE },
167908f1e13Ssd77468 	{ MEMORYBUFFER, TOPO_STABILITY_PRIVATE },
1680eb822a1Scindi 	{ MEMORYCONTROL, TOPO_STABILITY_PRIVATE },
169908f1e13Ssd77468 	{ MICROCORE, TOPO_STABILITY_PRIVATE },
1700eb822a1Scindi 	{ MOTHERBOARD, TOPO_STABILITY_PRIVATE },
17114ea4bb7Ssd77468 	{ NIU, TOPO_STABILITY_PRIVATE },
17214ea4bb7Ssd77468 	{ NIUFN, TOPO_STABILITY_PRIVATE },
1730eb822a1Scindi 	{ PCI_BUS, TOPO_STABILITY_PRIVATE },
1740eb822a1Scindi 	{ PCI_DEVICE, TOPO_STABILITY_PRIVATE },
1750eb822a1Scindi 	{ PCI_FUNCTION, TOPO_STABILITY_PRIVATE },
1760eb822a1Scindi 	{ PCIEX_BUS, TOPO_STABILITY_PRIVATE },
1770eb822a1Scindi 	{ PCIEX_DEVICE, TOPO_STABILITY_PRIVATE },
1780eb822a1Scindi 	{ PCIEX_FUNCTION, TOPO_STABILITY_PRIVATE },
1790eb822a1Scindi 	{ PCIEX_ROOT, TOPO_STABILITY_PRIVATE },
1800eb822a1Scindi 	{ PCIEX_SWUP, TOPO_STABILITY_PRIVATE },
1810eb822a1Scindi 	{ PCIEX_SWDWN, TOPO_STABILITY_PRIVATE },
182ded93414SHyon Kim 	{ POWERBOARD, TOPO_STABILITY_PRIVATE },
1832eeaed14Srobj 	{ POWERMODULE, TOPO_STABILITY_PRIVATE },
1842eeaed14Srobj 	{ PSU, TOPO_STABILITY_PRIVATE },
1850eb822a1Scindi 	{ RANK, TOPO_STABILITY_PRIVATE },
186ac88567aSHyon Kim 	{ RECEPTACLE, TOPO_STABILITY_PRIVATE },
187908f1e13Ssd77468 	{ RISER, TOPO_STABILITY_PRIVATE },
188ac88567aSHyon Kim 	{ SASEXPANDER, TOPO_STABILITY_PRIVATE },
189ac88567aSHyon Kim 	{ SCSI_DEVICE, TOPO_STABILITY_PRIVATE },
190908f1e13Ssd77468 	{ SHELF, TOPO_STABILITY_PRIVATE },
191940d71d2Seschrock 	{ SES_ENCLOSURE, TOPO_STABILITY_PRIVATE },
192ac88567aSHyon Kim 	{ SMP_DEVICE, TOPO_STABILITY_PRIVATE },
1934df55fdeSJanie Lu 	{ SP, TOPO_STABILITY_PRIVATE },
194e4b86885SCheng Sean Ye 	{ STRAND, TOPO_STABILITY_PRIVATE },
19553dbcc59SSundeep Panicker 	{ SUBCHASSIS, TOPO_STABILITY_PRIVATE },
19614ea4bb7Ssd77468 	{ SYSTEMBOARD, TOPO_STABILITY_PRIVATE },
19714ea4bb7Ssd77468 	{ XAUI, TOPO_STABILITY_PRIVATE },
19814ea4bb7Ssd77468 	{ XFP, TOPO_STABILITY_PRIVATE }
1990eb822a1Scindi };
2000eb822a1Scindi 
2010eb822a1Scindi static int hc_ncanon = sizeof (hc_canon) / sizeof (hcc_t);
2020eb822a1Scindi 
2030eb822a1Scindi int
hc_init(topo_mod_t * mod,topo_version_t version)2040eb822a1Scindi hc_init(topo_mod_t *mod, topo_version_t version)
2057aec1d6eScindi {
2067aec1d6eScindi 	/*
2077aec1d6eScindi 	 * Turn on module debugging output
2087aec1d6eScindi 	 */
2090eb822a1Scindi 	if (getenv("TOPOHCDEBUG"))
2100eb822a1Scindi 		topo_mod_setdebug(mod);
2117aec1d6eScindi 
2120eb822a1Scindi 	topo_mod_dprintf(mod, "initializing hc builtin\n");
2130eb822a1Scindi 
2140eb822a1Scindi 	if (version != HC_VERSION)
2150eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2160eb822a1Scindi 
2170eb822a1Scindi 	if (topo_mod_register(mod, &hc_info, TOPO_VERSION) != 0) {
2180eb822a1Scindi 		topo_mod_dprintf(mod, "failed to register hc: "
2190eb822a1Scindi 		    "%s\n", topo_mod_errmsg(mod));
2200eb822a1Scindi 		return (-1); /* mod errno already set */
2217aec1d6eScindi 	}
2220eb822a1Scindi 
2230eb822a1Scindi 	return (0);
2247aec1d6eScindi }
2257aec1d6eScindi 
2267aec1d6eScindi void
hc_fini(topo_mod_t * mod)2270eb822a1Scindi hc_fini(topo_mod_t *mod)
2287aec1d6eScindi {
2290eb822a1Scindi 	topo_mod_unregister(mod);
2300eb822a1Scindi }
2310eb822a1Scindi 
2320eb822a1Scindi 
2330eb822a1Scindi static const topo_pgroup_info_t sys_pgroup = {
2340eb822a1Scindi 	TOPO_PGROUP_SYSTEM,
2350eb822a1Scindi 	TOPO_STABILITY_PRIVATE,
2360eb822a1Scindi 	TOPO_STABILITY_PRIVATE,
2370eb822a1Scindi 	1
2380eb822a1Scindi };
2390eb822a1Scindi 
2400eb822a1Scindi static const topo_pgroup_info_t auth_pgroup = {
2410eb822a1Scindi 	FM_FMRI_AUTHORITY,
2420eb822a1Scindi 	TOPO_STABILITY_PRIVATE,
2430eb822a1Scindi 	TOPO_STABILITY_PRIVATE,
2440eb822a1Scindi 	1
2450eb822a1Scindi };
2460eb822a1Scindi 
2470eb822a1Scindi static void
hc_prop_set(tnode_t * node,nvlist_t * auth)2480eb822a1Scindi hc_prop_set(tnode_t *node, nvlist_t *auth)
2490eb822a1Scindi {
2500eb822a1Scindi 	int err;
2510eb822a1Scindi 	char isa[MAXNAMELEN];
2520eb822a1Scindi 	struct utsname uts;
2539c94f155SCheng Sean Ye 	char *prod, *psn, *csn, *server;
2540eb822a1Scindi 
2559dd0f810Scindi 	if (auth == NULL)
2569dd0f810Scindi 		return;
2579dd0f810Scindi 
2580eb822a1Scindi 	if (topo_pgroup_create(node, &auth_pgroup, &err) != 0) {
2590eb822a1Scindi 		if (err != ETOPO_PROP_DEFD)
2600eb822a1Scindi 			return;
2610eb822a1Scindi 	}
2620eb822a1Scindi 
2630eb822a1Scindi 	/*
2640eb822a1Scindi 	 * Inherit if we can, it saves memory
2650eb822a1Scindi 	 */
2662eeaed14Srobj 	if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT,
2672eeaed14Srobj 	    &err) != 0) && (err != ETOPO_PROP_DEFD)) {
2680eb822a1Scindi 		if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, &prod)
2690eb822a1Scindi 		    == 0)
2700eb822a1Scindi 			(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
2710eb822a1Scindi 			    FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod,
2720eb822a1Scindi 			    &err);
2730eb822a1Scindi 	}
2749c94f155SCheng Sean Ye 	if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT_SN,
2759c94f155SCheng Sean Ye 	    &err) != 0) && (err != ETOPO_PROP_DEFD)) {
2769c94f155SCheng Sean Ye 		if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN, &psn)
2779c94f155SCheng Sean Ye 		    == 0)
2789c94f155SCheng Sean Ye 			(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
2799c94f155SCheng Sean Ye 			    FM_FMRI_AUTH_PRODUCT_SN, TOPO_PROP_IMMUTABLE, psn,
2809c94f155SCheng Sean Ye 			    &err);
2819c94f155SCheng Sean Ye 	}
2822eeaed14Srobj 	if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS,
2832eeaed14Srobj 	    &err) != 0) && (err != ETOPO_PROP_DEFD)) {
2840eb822a1Scindi 		if (nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, &csn) == 0)
2850eb822a1Scindi 			(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
2860eb822a1Scindi 			    FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn,
2870eb822a1Scindi 			    &err);
2880eb822a1Scindi 	}
2892eeaed14Srobj 	if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_SERVER,
2902eeaed14Srobj 	    &err) != 0) && (err != ETOPO_PROP_DEFD)) {
2910eb822a1Scindi 		if (nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server)
2920eb822a1Scindi 		    == 0)
2930eb822a1Scindi 			(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
2940eb822a1Scindi 			    FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server,
2950eb822a1Scindi 			    &err);
2960eb822a1Scindi 	}
2970eb822a1Scindi 
2980eb822a1Scindi 	if (topo_pgroup_create(node, &sys_pgroup, &err) != 0)
2990eb822a1Scindi 		return;
3000eb822a1Scindi 
3010eb822a1Scindi 	isa[0] = '\0';
3020eb822a1Scindi 	(void) sysinfo(SI_ARCHITECTURE, isa, sizeof (isa));
3030eb822a1Scindi 	(void) uname(&uts);
3040eb822a1Scindi 	(void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
3050eb822a1Scindi 	    TOPO_PROP_IMMUTABLE, isa, &err);
3060eb822a1Scindi 	(void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE,
3070eb822a1Scindi 	    TOPO_PROP_IMMUTABLE, uts.machine, &err);
3087aec1d6eScindi }
3097aec1d6eScindi 
3107aec1d6eScindi /*ARGSUSED*/
3117aec1d6eScindi int
hc_enum(topo_mod_t * mod,tnode_t * pnode,const char * name,topo_instance_t min,topo_instance_t max,void * notused1,void * notused2)3120eb822a1Scindi hc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min,
3139dd0f810Scindi     topo_instance_t max, void *notused1, void *notused2)
3147aec1d6eScindi {
315*f6e214c7SGavin Maltby 	int isglobal = (getzoneid() == GLOBAL_ZONEID);
3167aec1d6eScindi 	nvlist_t *pfmri = NULL;
3177aec1d6eScindi 	nvlist_t *nvl;
3180eb822a1Scindi 	nvlist_t *auth;
3190eb822a1Scindi 	tnode_t *node;
3207aec1d6eScindi 	int err;
3217aec1d6eScindi 	/*
3227aec1d6eScindi 	 * Register root node methods
3237aec1d6eScindi 	 */
3247aec1d6eScindi 	if (strcmp(name, HC) == 0) {
3250eb822a1Scindi 		(void) topo_method_register(mod, pnode, hc_methods);
3267aec1d6eScindi 		return (0);
3277aec1d6eScindi 	}
3287aec1d6eScindi 	if (min != max) {
3290eb822a1Scindi 		topo_mod_dprintf(mod,
3307aec1d6eScindi 		    "Request to enumerate %s component with an "
3317aec1d6eScindi 		    "ambiguous instance number, min (%d) != max (%d).\n",
3327aec1d6eScindi 		    HC, min, max);
3330eb822a1Scindi 		return (topo_mod_seterrno(mod, EINVAL));
3347aec1d6eScindi 	}
3357aec1d6eScindi 
336*f6e214c7SGavin Maltby 	if (!isglobal)
337*f6e214c7SGavin Maltby 		return (0);
338*f6e214c7SGavin Maltby 
3397aec1d6eScindi 	(void) topo_node_resource(pnode, &pfmri, &err);
3400eb822a1Scindi 	auth = topo_mod_auth(mod, pnode);
3410eb822a1Scindi 	nvl = hc_fmri_create(mod, pfmri, FM_HC_SCHEME_VERSION, name, min,
3420eb822a1Scindi 	    auth, NULL, NULL, NULL);
3437aec1d6eScindi 	nvlist_free(pfmri);	/* callee ignores NULLs */
3440eb822a1Scindi 	if (nvl == NULL) {
3450eb822a1Scindi 		nvlist_free(auth);
3467aec1d6eScindi 		return (-1);
3470eb822a1Scindi 	}
3487aec1d6eScindi 
3490eb822a1Scindi 	if ((node = topo_node_bind(mod, pnode, name, min, nvl)) == NULL) {
3500eb822a1Scindi 		topo_mod_dprintf(mod, "topo_node_bind failed: %s\n",
3510eb822a1Scindi 		    topo_strerror(topo_mod_errno(mod)));
3520eb822a1Scindi 		nvlist_free(auth);
3537aec1d6eScindi 		nvlist_free(nvl);
3547aec1d6eScindi 		return (-1);
3557aec1d6eScindi 	}
3560eb822a1Scindi 
35747911a7dScy152378 	/*
35847911a7dScy152378 	 * Set FRU for the motherboard node
35947911a7dScy152378 	 */
36047911a7dScy152378 	if (strcmp(name, MOTHERBOARD) == 0)
36147911a7dScy152378 		(void) topo_node_fru_set(node, nvl, 0, &err);
36247911a7dScy152378 
3630eb822a1Scindi 	hc_prop_set(node, auth);
3647aec1d6eScindi 	nvlist_free(nvl);
3650eb822a1Scindi 	nvlist_free(auth);
3660eb822a1Scindi 
3677aec1d6eScindi 	return (0);
3687aec1d6eScindi }
3697aec1d6eScindi 
3707aec1d6eScindi /*ARGSUSED*/
3717aec1d6eScindi static void
hc_release(topo_mod_t * mp,tnode_t * node)3727aec1d6eScindi hc_release(topo_mod_t *mp, tnode_t *node)
3737aec1d6eScindi {
3747aec1d6eScindi 	topo_method_unregister_all(mp, node);
3757aec1d6eScindi }
3767aec1d6eScindi 
3777aec1d6eScindi static int
fmri_compare(topo_mod_t * mod,nvlist_t * nv1,nvlist_t * nv2)378c40d7343Scindi fmri_compare(topo_mod_t *mod, nvlist_t *nv1, nvlist_t *nv2)
3797aec1d6eScindi {
3807aec1d6eScindi 	uint8_t v1, v2;
3817aec1d6eScindi 	nvlist_t **hcp1, **hcp2;
382825ba0f2Srobj 	nvlist_t *f1 = NULL, *f2 = NULL;
3837aec1d6eScindi 	int err, i;
3847aec1d6eScindi 	uint_t nhcp1, nhcp2;
385825ba0f2Srobj 	char *f1str, *f2str;
3867aec1d6eScindi 
3877aec1d6eScindi 	if (nvlist_lookup_uint8(nv1, FM_VERSION, &v1) != 0 ||
3887aec1d6eScindi 	    nvlist_lookup_uint8(nv2, FM_VERSION, &v2) != 0 ||
3897aec1d6eScindi 	    v1 > FM_HC_SCHEME_VERSION || v2 > FM_HC_SCHEME_VERSION)
3900eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_VERSION));
3917aec1d6eScindi 
3927aec1d6eScindi 	err = nvlist_lookup_nvlist_array(nv1, FM_FMRI_HC_LIST, &hcp1, &nhcp1);
3937aec1d6eScindi 	err |= nvlist_lookup_nvlist_array(nv2, FM_FMRI_HC_LIST, &hcp2, &nhcp2);
3947aec1d6eScindi 	if (err != 0)
3950eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
3967aec1d6eScindi 
3977aec1d6eScindi 	if (nhcp1 != nhcp2)
3987aec1d6eScindi 		return (0);
3997aec1d6eScindi 
4007aec1d6eScindi 	for (i = 0; i < nhcp1; i++) {
4017aec1d6eScindi 		char *nm1 = NULL;
4027aec1d6eScindi 		char *nm2 = NULL;
4037aec1d6eScindi 		char *id1 = NULL;
4047aec1d6eScindi 		char *id2 = NULL;
4057aec1d6eScindi 
4067aec1d6eScindi 		(void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_NAME, &nm1);
4077aec1d6eScindi 		(void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_NAME, &nm2);
4087aec1d6eScindi 		(void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_ID, &id1);
4097aec1d6eScindi 		(void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_ID, &id2);
4107aec1d6eScindi 		if (nm1 == NULL || nm2 == NULL || id1 == NULL || id2 == NULL)
4110eb822a1Scindi 			return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
4127aec1d6eScindi 
4137aec1d6eScindi 		if (strcmp(nm1, nm2) == 0 && strcmp(id1, id2) == 0)
4147aec1d6eScindi 			continue;
4157aec1d6eScindi 
4167aec1d6eScindi 		return (0);
4177aec1d6eScindi 	}
4187aec1d6eScindi 
419825ba0f2Srobj 	/*
420825ba0f2Srobj 	 * Finally, check if the FMRI's represent a facility node.  If so, then
421825ba0f2Srobj 	 * verify that the facilty type ("sensor"|"indicator") and facility
422825ba0f2Srobj 	 * name match.
423825ba0f2Srobj 	 */
424825ba0f2Srobj 	(void) nvlist_lookup_nvlist(nv1, FM_FMRI_FACILITY, &f1);
425825ba0f2Srobj 	(void) nvlist_lookup_nvlist(nv2, FM_FMRI_FACILITY, &f2);
426825ba0f2Srobj 
427825ba0f2Srobj 	if (f1 == NULL && f2 == NULL)
4287aec1d6eScindi 		return (1);
429825ba0f2Srobj 	else if (f1 == NULL || f2 == NULL)
430825ba0f2Srobj 		return (0);
431825ba0f2Srobj 
432825ba0f2Srobj 	if (nvlist_lookup_string(f1, FM_FMRI_FACILITY_NAME, &f1str) == 0 &&
433825ba0f2Srobj 	    nvlist_lookup_string(f2, FM_FMRI_FACILITY_NAME, &f2str) == 0 &&
434825ba0f2Srobj 	    strcmp(f1str, f2str) == 0 &&
435825ba0f2Srobj 	    nvlist_lookup_string(f1, FM_FMRI_FACILITY_TYPE, &f1str) == 0 &&
436825ba0f2Srobj 	    nvlist_lookup_string(f2, FM_FMRI_FACILITY_TYPE, &f2str) == 0 &&
437825ba0f2Srobj 	    strcmp(f1str, f2str) == 0) {
438825ba0f2Srobj 		return (1);
439825ba0f2Srobj 	}
440825ba0f2Srobj 	return (0);
4417aec1d6eScindi }
4427aec1d6eScindi 
443c40d7343Scindi /*ARGSUSED*/
444c40d7343Scindi static int
hc_compare(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)445c40d7343Scindi hc_compare(topo_mod_t *mod, tnode_t *node, topo_version_t version,
446c40d7343Scindi     nvlist_t *in, nvlist_t **out)
447c40d7343Scindi {
448c40d7343Scindi 	int ret;
449c40d7343Scindi 	uint32_t compare;
450c40d7343Scindi 	nvlist_t *nv1, *nv2;
451c40d7343Scindi 
452c40d7343Scindi 	if (version > TOPO_METH_COMPARE_VERSION)
453c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
454c40d7343Scindi 
455c40d7343Scindi 	if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV1, &nv1) != 0 ||
45612cc75c8Scindi 	    nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV2, &nv2) != 0)
457c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
458c40d7343Scindi 
459c40d7343Scindi 	ret = fmri_compare(mod, nv1, nv2);
460c40d7343Scindi 	if (ret < 0)
461c40d7343Scindi 		return (-1);
462c40d7343Scindi 
463c40d7343Scindi 	compare = ret;
464c40d7343Scindi 	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) == 0) {
465c40d7343Scindi 		if (nvlist_add_uint32(*out, TOPO_METH_COMPARE_RET,
466c40d7343Scindi 		    compare) == 0)
467c40d7343Scindi 			return (0);
468c40d7343Scindi 		else
469c40d7343Scindi 			nvlist_free(*out);
470c40d7343Scindi 	}
471c40d7343Scindi 
472c40d7343Scindi 	return (-1);
473c40d7343Scindi }
474c40d7343Scindi 
4757aec1d6eScindi static ssize_t
fmri_nvl2str(nvlist_t * nvl,char * buf,size_t buflen)4767aec1d6eScindi fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
4777aec1d6eScindi {
4787aec1d6eScindi 	nvlist_t **hcprs = NULL;
479e4b86885SCheng Sean Ye 	nvlist_t *hcsp = NULL;
4807aec1d6eScindi 	nvlist_t *anvl = NULL;
4819c94f155SCheng Sean Ye 	nvpair_t *apair;
482825ba0f2Srobj 	nvlist_t *fnvl;
4837aec1d6eScindi 	uint8_t version;
4847aec1d6eScindi 	ssize_t size = 0;
4857aec1d6eScindi 	uint_t hcnprs;
4867aec1d6eScindi 	char *serial = NULL;
4877aec1d6eScindi 	char *part = NULL;
4887aec1d6eScindi 	char *root = NULL;
4897aec1d6eScindi 	char *rev = NULL;
4909c94f155SCheng Sean Ye 	char *aname, *aval;
491825ba0f2Srobj 	char *fname = NULL, *ftype = NULL;
4927aec1d6eScindi 	int err, i;
4937aec1d6eScindi 
4947aec1d6eScindi 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
4957aec1d6eScindi 	    version > FM_HC_SCHEME_VERSION)
496f5961f52SAdrian Frost 		return (0);
4977aec1d6eScindi 
4987aec1d6eScindi 	/* Get authority, if present */
4997aec1d6eScindi 	err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl);
5007aec1d6eScindi 	if (err != 0 && err != ENOENT)
501f5961f52SAdrian Frost 		return (0);
5027aec1d6eScindi 
503f5961f52SAdrian Frost 	(void) nvlist_lookup_string(nvl, FM_FMRI_HC_ROOT, &root);
5047aec1d6eScindi 
5057aec1d6eScindi 	err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs);
5067aec1d6eScindi 	if (err != 0 || hcprs == NULL)
507f5961f52SAdrian Frost 		return (0);
5087aec1d6eScindi 
5097aec1d6eScindi 	(void) nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &serial);
5107aec1d6eScindi 	(void) nvlist_lookup_string(nvl, FM_FMRI_HC_PART, &part);
5117aec1d6eScindi 	(void) nvlist_lookup_string(nvl, FM_FMRI_HC_REVISION, &rev);
5127aec1d6eScindi 
5137aec1d6eScindi 	/* hc:// */
51474a31ce6Stimh 	topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_HC, NULL, "://");
5157aec1d6eScindi 
5167aec1d6eScindi 	/* authority, if any */
5179c94f155SCheng Sean Ye 	if (anvl != NULL) {
5189c94f155SCheng Sean Ye 		for (apair = nvlist_next_nvpair(anvl, NULL);
5199c94f155SCheng Sean Ye 		    apair != NULL; apair = nvlist_next_nvpair(anvl, apair)) {
5209c94f155SCheng Sean Ye 			if (nvpair_type(apair) != DATA_TYPE_STRING ||
5219c94f155SCheng Sean Ye 			    nvpair_value_string(apair, &aval) != 0)
5229c94f155SCheng Sean Ye 				continue;
5239c94f155SCheng Sean Ye 			aname = nvpair_name(apair);
5249c94f155SCheng Sean Ye 			topo_fmristr_build(&size, buf, buflen, ":", NULL, NULL);
5259c94f155SCheng Sean Ye 			topo_fmristr_build(&size, buf, buflen, "=",
5269c94f155SCheng Sean Ye 			    aname, aval);
5279c94f155SCheng Sean Ye 		}
5289c94f155SCheng Sean Ye 	}
5297aec1d6eScindi 
5307aec1d6eScindi 	/* hardware-id part */
53174a31ce6Stimh 	topo_fmristr_build(&size,
53274a31ce6Stimh 	    buf, buflen, serial, ":" FM_FMRI_HC_SERIAL_ID "=", NULL);
53374a31ce6Stimh 	topo_fmristr_build(&size,
53474a31ce6Stimh 	    buf, buflen, part, ":" FM_FMRI_HC_PART "=", NULL);
53574a31ce6Stimh 	topo_fmristr_build(&size,
53674a31ce6Stimh 	    buf, buflen, rev, ":" FM_FMRI_HC_REVISION "=", NULL);
5377aec1d6eScindi 
5387aec1d6eScindi 	/* separating slash */
53974a31ce6Stimh 	topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL);
5407aec1d6eScindi 
5417aec1d6eScindi 	/* hc-root */
542f5961f52SAdrian Frost 	if (root)
54374a31ce6Stimh 		topo_fmristr_build(&size, buf, buflen, root, NULL, NULL);
5447aec1d6eScindi 
5457aec1d6eScindi 	/* all the pairs */
5467aec1d6eScindi 	for (i = 0; i < hcnprs; i++) {
5477aec1d6eScindi 		char *nm = NULL;
5487aec1d6eScindi 		char *id = NULL;
5497aec1d6eScindi 
5507aec1d6eScindi 		if (i > 0)
55174a31ce6Stimh 			topo_fmristr_build(&size,
55274a31ce6Stimh 			    buf, buflen, "/", NULL, NULL);
5537aec1d6eScindi 		(void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_NAME, &nm);
5547aec1d6eScindi 		(void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_ID, &id);
5557aec1d6eScindi 		if (nm == NULL || id == NULL)
5567aec1d6eScindi 			return (0);
55774a31ce6Stimh 		topo_fmristr_build(&size, buf, buflen, nm, NULL, "=");
55874a31ce6Stimh 		topo_fmristr_build(&size, buf, buflen, id, NULL, NULL);
5597aec1d6eScindi 	}
5607aec1d6eScindi 
561e4b86885SCheng Sean Ye 	/* append offset/physaddr if it exists in hc-specific */
562e4b86885SCheng Sean Ye 	if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) {
563e4b86885SCheng Sean Ye 		char *hcsn = NULL;
564e4b86885SCheng Sean Ye 		char hexstr[17];
565e4b86885SCheng Sean Ye 		uint64_t val;
566e4b86885SCheng Sean Ye 
567e4b86885SCheng Sean Ye 		if (nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET,
568e4b86885SCheng Sean Ye 		    &val) == 0 || nvlist_lookup_uint64(hcsp,
569e4b86885SCheng Sean Ye 		    "asru-" FM_FMRI_HC_SPECIFIC_OFFSET, &val) == 0)
570e4b86885SCheng Sean Ye 			hcsn = FM_FMRI_HC_SPECIFIC_OFFSET;
571e4b86885SCheng Sean Ye 		else if (nvlist_lookup_uint64(hcsp,
572e4b86885SCheng Sean Ye 		    FM_FMRI_HC_SPECIFIC_PHYSADDR, &val) == 0 ||
573e4b86885SCheng Sean Ye 		    nvlist_lookup_uint64(hcsp,
574e4b86885SCheng Sean Ye 		    "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR, &val) == 0)
575e4b86885SCheng Sean Ye 			hcsn = FM_FMRI_HC_SPECIFIC_PHYSADDR;
576e4b86885SCheng Sean Ye 
577e4b86885SCheng Sean Ye 		if (hcsn != NULL) {
578e4b86885SCheng Sean Ye 			(void) snprintf(hexstr, sizeof (hexstr), "%llx", val);
579e4b86885SCheng Sean Ye 			topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL);
580e4b86885SCheng Sean Ye 			topo_fmristr_build(&size, buf, buflen, "=", hcsn,
581e4b86885SCheng Sean Ye 			    hexstr);
582e4b86885SCheng Sean Ye 		}
583e4b86885SCheng Sean Ye 	}
584e4b86885SCheng Sean Ye 
585825ba0f2Srobj 	/*
586825ba0f2Srobj 	 * If the nvlist represents a facility node, then we append the
587825ba0f2Srobj 	 * facility type and name to the end of the string representation using
588825ba0f2Srobj 	 * the format below:
589825ba0f2Srobj 	 *
590825ba0f2Srobj 	 * ?<ftype>=<fname>
591825ba0f2Srobj 	 */
592825ba0f2Srobj 	if (nvlist_lookup_nvlist(nvl, FM_FMRI_FACILITY, &fnvl) == 0) {
593825ba0f2Srobj 		if (nvlist_lookup_string(fnvl, FM_FMRI_FACILITY_NAME,
594825ba0f2Srobj 		    &fname) != 0 || nvlist_lookup_string(fnvl,
595825ba0f2Srobj 		    FM_FMRI_FACILITY_TYPE, &ftype) != 0)
596825ba0f2Srobj 			return (0);
597825ba0f2Srobj 		topo_fmristr_build(&size, buf, buflen, "?", NULL, NULL);
598825ba0f2Srobj 		topo_fmristr_build(&size, buf, buflen, "=", ftype, fname);
599825ba0f2Srobj 	}
600825ba0f2Srobj 
6017aec1d6eScindi 	return (size);
6027aec1d6eScindi }
6037aec1d6eScindi 
6047aec1d6eScindi /*ARGSUSED*/
6057aec1d6eScindi static int
hc_fmri_nvl2str(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * nvl,nvlist_t ** out)6067aec1d6eScindi hc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version,
6077aec1d6eScindi     nvlist_t *nvl, nvlist_t **out)
6087aec1d6eScindi {
6097aec1d6eScindi 	ssize_t len;
6107aec1d6eScindi 	char *name = NULL;
6117aec1d6eScindi 	nvlist_t *fmristr;
6127aec1d6eScindi 
6137aec1d6eScindi 	if (version > TOPO_METH_NVL2STR_VERSION)
6147aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
6157aec1d6eScindi 
6167aec1d6eScindi 	if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 ||
6177aec1d6eScindi 	    (name = topo_mod_alloc(mod, len + 1)) == NULL ||
6187aec1d6eScindi 	    fmri_nvl2str(nvl, name, len + 1) == 0) {
6197aec1d6eScindi 		if (name != NULL)
6207aec1d6eScindi 			topo_mod_free(mod, name, len + 1);
6217aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
6227aec1d6eScindi 	}
6237aec1d6eScindi 
62412cc75c8Scindi 	if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) {
62512cc75c8Scindi 		topo_mod_free(mod, name, len + 1);
6267aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
62712cc75c8Scindi 	}
6287aec1d6eScindi 	if (nvlist_add_string(fmristr, "fmri-string", name) != 0) {
6297aec1d6eScindi 		topo_mod_free(mod, name, len + 1);
6307aec1d6eScindi 		nvlist_free(fmristr);
6317aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
6327aec1d6eScindi 	}
6337aec1d6eScindi 	topo_mod_free(mod, name, len + 1);
6347aec1d6eScindi 	*out = fmristr;
6357aec1d6eScindi 
6367aec1d6eScindi 	return (0);
6377aec1d6eScindi }
6387aec1d6eScindi 
6397aec1d6eScindi static nvlist_t *
hc_base_fmri_create(topo_mod_t * mod,const nvlist_t * auth,const char * part,const char * rev,const char * serial)6407aec1d6eScindi hc_base_fmri_create(topo_mod_t *mod, const nvlist_t *auth, const char *part,
6417aec1d6eScindi     const char *rev, const char *serial)
6427aec1d6eScindi {
6437aec1d6eScindi 	nvlist_t *fmri;
6447aec1d6eScindi 	int err = 0;
6457aec1d6eScindi 
6467aec1d6eScindi 	/*
6477aec1d6eScindi 	 * Create base HC nvlist
6487aec1d6eScindi 	 */
6497aec1d6eScindi 	if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0)
6507aec1d6eScindi 		return (NULL);
6517aec1d6eScindi 
6527aec1d6eScindi 	err = nvlist_add_uint8(fmri, FM_VERSION, FM_HC_SCHEME_VERSION);
6537aec1d6eScindi 	err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC);
6547aec1d6eScindi 	err |= nvlist_add_string(fmri, FM_FMRI_HC_ROOT, "");
6557aec1d6eScindi 	if (err != 0) {
6567aec1d6eScindi 		nvlist_free(fmri);
6577aec1d6eScindi 		return (NULL);
6587aec1d6eScindi 	}
6597aec1d6eScindi 
6607aec1d6eScindi 	/*
6617aec1d6eScindi 	 * Add optional payload members
6627aec1d6eScindi 	 */
6637aec1d6eScindi 	if (serial != NULL)
6647aec1d6eScindi 		(void) nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID, serial);
6657aec1d6eScindi 	if (part != NULL)
6667aec1d6eScindi 		(void) nvlist_add_string(fmri, FM_FMRI_HC_PART, part);
6677aec1d6eScindi 	if (rev != NULL)
6687aec1d6eScindi 		(void) nvlist_add_string(fmri, FM_FMRI_HC_REVISION, rev);
6697aec1d6eScindi 	if (auth != NULL)
6707aec1d6eScindi 		(void) nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
6717aec1d6eScindi 		    (nvlist_t *)auth);
6727aec1d6eScindi 
6737aec1d6eScindi 	return (fmri);
6747aec1d6eScindi }
6757aec1d6eScindi 
6767aec1d6eScindi static nvlist_t **
make_hc_pairs(topo_mod_t * mod,char * fmri,int * num)6770eb822a1Scindi make_hc_pairs(topo_mod_t *mod, char *fmri, int *num)
6787aec1d6eScindi {
6797aec1d6eScindi 	nvlist_t **pa;
6800eb822a1Scindi 	char *hc, *fromstr;
6817aec1d6eScindi 	char *starti, *startn, *endi, *endi2;
6827aec1d6eScindi 	char *ne, *ns;
683c40d7343Scindi 	char *cname = NULL;
6847aec1d6eScindi 	char *find;
685c40d7343Scindi 	char *cid = NULL;
6867aec1d6eScindi 	int nslashes = 0;
6877aec1d6eScindi 	int npairs = 0;
68812cc75c8Scindi 	int i, hclen;
6897aec1d6eScindi 
6900eb822a1Scindi 	if ((hc = topo_mod_strdup(mod, fmri + 5)) == NULL)
6910eb822a1Scindi 		return (NULL);
6920eb822a1Scindi 
69312cc75c8Scindi 	hclen = strlen(hc) + 1;
69412cc75c8Scindi 
6957aec1d6eScindi 	/*
6967aec1d6eScindi 	 * Count equal signs and slashes to determine how many
6977aec1d6eScindi 	 * hc-pairs will be present in the final FMRI.  There should
6987aec1d6eScindi 	 * be at least as many slashes as equal signs.  There can be
6997aec1d6eScindi 	 * more, though if the string after an = includes them.
7007aec1d6eScindi 	 */
7010eb822a1Scindi 	if ((fromstr = strchr(hc, '/')) == NULL)
7020eb822a1Scindi 		return (NULL);
7030eb822a1Scindi 
7047aec1d6eScindi 	find = fromstr;
7057aec1d6eScindi 	while ((ne = strchr(find, '=')) != NULL) {
7067aec1d6eScindi 		find = ne + 1;
7077aec1d6eScindi 		npairs++;
7087aec1d6eScindi 	}
7097aec1d6eScindi 
7107aec1d6eScindi 	find = fromstr;
7117aec1d6eScindi 	while ((ns = strchr(find, '/')) != NULL) {
7127aec1d6eScindi 		find = ns + 1;
7137aec1d6eScindi 		nslashes++;
7147aec1d6eScindi 	}
7157aec1d6eScindi 
7167aec1d6eScindi 	/*
7177aec1d6eScindi 	 * Do we appear to have a well-formed string version of the FMRI?
7187aec1d6eScindi 	 */
7190eb822a1Scindi 	if (nslashes < npairs || npairs == 0) {
72012cc75c8Scindi 		topo_mod_free(mod, hc, hclen);
7217aec1d6eScindi 		return (NULL);
7220eb822a1Scindi 	}
7237aec1d6eScindi 
7247aec1d6eScindi 	*num = npairs;
7257aec1d6eScindi 
7267aec1d6eScindi 	find = fromstr;
7277aec1d6eScindi 
72812cc75c8Scindi 	if ((pa = topo_mod_zalloc(mod, npairs * sizeof (nvlist_t *))) == NULL) {
72912cc75c8Scindi 		topo_mod_free(mod, hc, hclen);
730c40d7343Scindi 		return (NULL);
731c40d7343Scindi 	}
732c40d7343Scindi 
7337aec1d6eScindi 	/*
7347aec1d6eScindi 	 * We go through a pretty complicated procedure to find the
7357aec1d6eScindi 	 * name and id for each pair.  That's because, unfortunately,
7367aec1d6eScindi 	 * we have some ids that can have slashes within them.  So
7377aec1d6eScindi 	 * we can't just search for the next slash after the equal sign
7387aec1d6eScindi 	 * and decide that starts a new pair.  Instead we have to find
7397aec1d6eScindi 	 * an equal sign for the next pair and work our way back to the
7407aec1d6eScindi 	 * slash from there.
7417aec1d6eScindi 	 */
7427aec1d6eScindi 	for (i = 0; i < npairs; i++) {
7437aec1d6eScindi 		startn = strchr(find, '/');
7447aec1d6eScindi 		if (startn == NULL)
7457aec1d6eScindi 			break;
7467aec1d6eScindi 		startn++;
7477aec1d6eScindi 		starti = strchr(find, '=');
7487aec1d6eScindi 		if (starti == NULL)
7497aec1d6eScindi 			break;
7507aec1d6eScindi 		*starti = '\0';
751c40d7343Scindi 		if ((cname = topo_mod_strdup(mod, startn)) == NULL)
752c40d7343Scindi 			break;
7537aec1d6eScindi 		*starti++ = '=';
7547aec1d6eScindi 		endi = strchr(starti, '=');
7557aec1d6eScindi 		if (endi != NULL) {
7567aec1d6eScindi 			*endi = '\0';
7577aec1d6eScindi 			endi2 = strrchr(starti, '/');
7587aec1d6eScindi 			if (endi2 == NULL)
7597aec1d6eScindi 				break;
7607aec1d6eScindi 			*endi = '=';
7617aec1d6eScindi 			*endi2 = '\0';
762c40d7343Scindi 			if ((cid = topo_mod_strdup(mod, starti)) == NULL)
763c40d7343Scindi 				break;
7647aec1d6eScindi 			*endi2 = '/';
7657aec1d6eScindi 			find = endi2;
7667aec1d6eScindi 		} else {
767c40d7343Scindi 			if ((cid = topo_mod_strdup(mod, starti)) == NULL)
768c40d7343Scindi 				break;
7697aec1d6eScindi 			find = starti + strlen(starti);
7707aec1d6eScindi 		}
771c40d7343Scindi 		if (topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME) < 0)
772c40d7343Scindi 			break;
773c40d7343Scindi 
774c40d7343Scindi 		if (nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname) ||
775c40d7343Scindi 		    nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid))
776c40d7343Scindi 			break;
777c40d7343Scindi 
7787aec1d6eScindi 		topo_mod_strfree(mod, cname);
7797aec1d6eScindi 		topo_mod_strfree(mod, cid);
780c40d7343Scindi 		cname = NULL;
781c40d7343Scindi 		cid = NULL;
7827aec1d6eScindi 	}
7837aec1d6eScindi 
7847aec1d6eScindi 	topo_mod_strfree(mod, cname);
7857aec1d6eScindi 	topo_mod_strfree(mod, cid);
7867aec1d6eScindi 
7877aec1d6eScindi 	if (i < npairs) {
78812cc75c8Scindi 		for (i = 0; i < npairs; i++)
78912cc75c8Scindi 			nvlist_free(pa[i]);
7907aec1d6eScindi 		topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *));
79112cc75c8Scindi 		topo_mod_free(mod, hc, hclen);
7927aec1d6eScindi 		return (NULL);
7937aec1d6eScindi 	}
7947aec1d6eScindi 
79512cc75c8Scindi 	topo_mod_free(mod, hc, hclen);
7960eb822a1Scindi 
7977aec1d6eScindi 	return (pa);
7987aec1d6eScindi }
7997aec1d6eScindi 
800825ba0f2Srobj int
make_hc_auth(topo_mod_t * mod,char * fmri,char ** serial,char ** part,char ** rev,nvlist_t ** auth)8010eb822a1Scindi make_hc_auth(topo_mod_t *mod, char *fmri, char **serial, char **part,
8020eb822a1Scindi char **rev, nvlist_t **auth)
8030eb822a1Scindi {
8040eb822a1Scindi 	char *starti, *startn, *endi, *copy;
805825ba0f2Srobj 	char *aname = NULL, *aid = NULL, *fs;
8060eb822a1Scindi 	nvlist_t *na = NULL;
8070eb822a1Scindi 	size_t len;
8080eb822a1Scindi 
8090eb822a1Scindi 	if ((copy = topo_mod_strdup(mod, fmri + 5)) == NULL)
810825ba0f2Srobj 		return (-1);
8110eb822a1Scindi 
8120eb822a1Scindi 	len = strlen(copy);
8130eb822a1Scindi 
8140eb822a1Scindi 	/*
8150eb822a1Scindi 	 * Make sure there are a valid authority members
8160eb822a1Scindi 	 */
8170eb822a1Scindi 	startn = strchr(copy, ':');
8180eb822a1Scindi 	fs = strchr(copy, '/');
8190eb822a1Scindi 
8200eb822a1Scindi 	if (startn == NULL || fs == NULL) {
8210eb822a1Scindi 		topo_mod_strfree(mod, copy);
822825ba0f2Srobj 		return (0);
8230eb822a1Scindi 	}
8240eb822a1Scindi 
8250eb822a1Scindi 	/*
8260eb822a1Scindi 	 * The first colon we encounter must occur before the
8270eb822a1Scindi 	 * first slash
8280eb822a1Scindi 	 */
8290eb822a1Scindi 	if (startn > fs)
830825ba0f2Srobj 		goto hcabail;
8310eb822a1Scindi 
8320eb822a1Scindi 	do {
8330eb822a1Scindi 		if (++startn >= copy + len)
8340eb822a1Scindi 			break;
8350eb822a1Scindi 
8360eb822a1Scindi 		if ((starti = strchr(startn, '=')) == NULL)
837825ba0f2Srobj 			goto hcabail;
8380eb822a1Scindi 
8390eb822a1Scindi 		*starti = '\0';
8400eb822a1Scindi 		if (++starti > copy + len)
841825ba0f2Srobj 			goto hcabail;
8420eb822a1Scindi 
8430eb822a1Scindi 		if ((aname = topo_mod_strdup(mod, startn)) == NULL)
844825ba0f2Srobj 			goto hcabail;
8450eb822a1Scindi 
8460eb822a1Scindi 		startn = endi = strchr(starti, ':');
8470eb822a1Scindi 		if (endi == NULL)
8480eb822a1Scindi 			if ((endi = strchr(starti, '/')) == NULL)
8490eb822a1Scindi 				break;
8500eb822a1Scindi 
8510eb822a1Scindi 		*endi = '\0';
852825ba0f2Srobj 		if ((aid = topo_mod_strdup(mod, starti)) == NULL)
853825ba0f2Srobj 			goto hcabail;
8540eb822a1Scindi 
8550eb822a1Scindi 		/*
8560eb822a1Scindi 		 * Return possible serial, part and revision
8570eb822a1Scindi 		 */
8580eb822a1Scindi 		if (strcmp(aname, FM_FMRI_HC_SERIAL_ID) == 0) {
85914ea4bb7Ssd77468 			*serial = topo_mod_strdup(mod, aid);
8600eb822a1Scindi 		} else if (strcmp(aname, FM_FMRI_HC_PART) == 0) {
86114ea4bb7Ssd77468 			*part = topo_mod_strdup(mod, aid);
8620eb822a1Scindi 		} else if (strcmp(aname, FM_FMRI_HC_REVISION) == 0) {
86314ea4bb7Ssd77468 			*rev = topo_mod_strdup(mod, aid);
8640eb822a1Scindi 		} else {
8650eb822a1Scindi 			if (na == NULL) {
8660eb822a1Scindi 				if (topo_mod_nvalloc(mod, &na,
8670eb822a1Scindi 				    NV_UNIQUE_NAME) == 0) {
86824db4641Seschrock 					(void) nvlist_add_string(na, aname,
86924db4641Seschrock 					    aid);
8700eb822a1Scindi 				}
8710eb822a1Scindi 			} else {
8720eb822a1Scindi 				(void) nvlist_add_string(na, aname, aid);
8730eb822a1Scindi 			}
8740eb822a1Scindi 		}
8750eb822a1Scindi 		topo_mod_strfree(mod, aname);
8760eb822a1Scindi 		topo_mod_strfree(mod, aid);
877825ba0f2Srobj 		aname = aid = NULL;
8780eb822a1Scindi 
8790eb822a1Scindi 	} while (startn != NULL);
8800eb822a1Scindi 
8810eb822a1Scindi 	*auth = na;
8820eb822a1Scindi 
8830eb822a1Scindi 	topo_mod_free(mod, copy, len + 1);
884825ba0f2Srobj 	return (0);
885825ba0f2Srobj 
886825ba0f2Srobj hcabail:
887825ba0f2Srobj 	topo_mod_free(mod, copy, len + 1);
888825ba0f2Srobj 	topo_mod_strfree(mod, aname);
889825ba0f2Srobj 	topo_mod_strfree(mod, aid);
890825ba0f2Srobj 	nvlist_free(na);
891825ba0f2Srobj 	return (-1);
892825ba0f2Srobj }
893825ba0f2Srobj 
894825ba0f2Srobj 
895825ba0f2Srobj /*
896825ba0f2Srobj  * This function creates an nvlist to represent the facility portion of an
897825ba0f2Srobj  * hc-scheme node, given a string representation of the fmri.  This is called by
898825ba0f2Srobj  * hc_fmri_str2nvl.  If the string does not contain a facility component
899825ba0f2Srobj  * (e.g. ?<ftype>=<fname>) then it bails early and returns 0.
900825ba0f2Srobj  *
901825ba0f2Srobj  * On failure it returns -1 and sets the topo mod errno
902825ba0f2Srobj  */
903825ba0f2Srobj int
make_facility(topo_mod_t * mod,char * str,nvlist_t ** nvl)904825ba0f2Srobj make_facility(topo_mod_t *mod, char *str, nvlist_t **nvl)
905825ba0f2Srobj {
906825ba0f2Srobj 	char *fac, *copy, *fname, *ftype;
907825ba0f2Srobj 	nvlist_t *nf = NULL;
908825ba0f2Srobj 	size_t len;
909825ba0f2Srobj 
910825ba0f2Srobj 	if ((fac = strchr(str, '?')) == NULL)
911825ba0f2Srobj 		return (0);
912825ba0f2Srobj 
913825ba0f2Srobj 	++fac;
914825ba0f2Srobj 	if ((copy = topo_mod_strdup(mod, fac)) == NULL)
915825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
916825ba0f2Srobj 
917825ba0f2Srobj 	fac = copy;
918825ba0f2Srobj 	len = strlen(fac);
919825ba0f2Srobj 
920825ba0f2Srobj 	if ((fname = strchr(fac, '=')) == NULL) {
921825ba0f2Srobj 		topo_mod_free(mod, copy, len + 1);
922825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
923825ba0f2Srobj 	}
924825ba0f2Srobj 
925825ba0f2Srobj 	fname[0] = '\0';
926825ba0f2Srobj 	++fname;
927825ba0f2Srobj 	ftype = fac;
928825ba0f2Srobj 
929825ba0f2Srobj 	if (topo_mod_nvalloc(mod, &nf, NV_UNIQUE_NAME) != 0) {
930825ba0f2Srobj 		topo_mod_free(mod, copy, len + 1);
931825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
932825ba0f2Srobj 	}
933825ba0f2Srobj 
934825ba0f2Srobj 	if (nvlist_add_string(nf, FM_FMRI_FACILITY_NAME, fname) != 0 ||
935825ba0f2Srobj 	    nvlist_add_string(nf, FM_FMRI_FACILITY_TYPE, ftype) != 0) {
936825ba0f2Srobj 		topo_mod_free(mod, copy, len + 1);
937825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
938825ba0f2Srobj 	}
939825ba0f2Srobj 
940825ba0f2Srobj 	topo_mod_free(mod, copy, len + 1);
941825ba0f2Srobj 
942825ba0f2Srobj 	*nvl = nf;
943825ba0f2Srobj 
944825ba0f2Srobj 	return (0);
9450eb822a1Scindi }
9460eb822a1Scindi 
9477aec1d6eScindi /*ARGSUSED*/
9487aec1d6eScindi static int
hc_fmri_str2nvl(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)9497aec1d6eScindi hc_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version,
9507aec1d6eScindi     nvlist_t *in, nvlist_t **out)
9517aec1d6eScindi {
9527aec1d6eScindi 	nvlist_t **pa = NULL;
9537aec1d6eScindi 	nvlist_t *nf = NULL;
9540eb822a1Scindi 	nvlist_t *auth = NULL;
955825ba0f2Srobj 	nvlist_t *fac = NULL;
9560eb822a1Scindi 	char *str;
957e4b86885SCheng Sean Ye 	char *serial = NULL, *part = NULL, *rev = NULL, *hcsn = NULL;
958e4b86885SCheng Sean Ye 	int npairs, n;
9597aec1d6eScindi 	int i, e;
9607aec1d6eScindi 
9617aec1d6eScindi 	if (version > TOPO_METH_STR2NVL_VERSION)
9627aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
9637aec1d6eScindi 
9647aec1d6eScindi 	if (nvlist_lookup_string(in, "fmri-string", &str) != 0)
9657aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
9667aec1d6eScindi 
9677aec1d6eScindi 	/* We're expecting a string version of an hc scheme FMRI */
9680eb822a1Scindi 	if (strncmp(str, "hc://", 5) != 0)
9697aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
9707aec1d6eScindi 
9710eb822a1Scindi 	if ((pa = make_hc_pairs(mod, str, &npairs)) == NULL)
9727aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
9737aec1d6eScindi 
974825ba0f2Srobj 	if (make_hc_auth(mod, str, &serial, &part, &rev, &auth) < 0)
975825ba0f2Srobj 		goto hcfmbail;
976825ba0f2Srobj 
9770eb822a1Scindi 	if ((nf = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL)
9787aec1d6eScindi 		goto hcfmbail;
979e4b86885SCheng Sean Ye 
980e4b86885SCheng Sean Ye 	n = npairs;
981e4b86885SCheng Sean Ye 
982e4b86885SCheng Sean Ye 	/*
983e4b86885SCheng Sean Ye 	 * If the last pair in hc-list is offset or physaddr, we move
984e4b86885SCheng Sean Ye 	 * it to hc-specific.
985e4b86885SCheng Sean Ye 	 */
986e4b86885SCheng Sean Ye 	(void) nvlist_lookup_string(pa[npairs - 1], FM_FMRI_HC_NAME, &hcsn);
987e4b86885SCheng Sean Ye 	if (strcmp(hcsn, FM_FMRI_HC_SPECIFIC_OFFSET) == 0 ||
988e4b86885SCheng Sean Ye 	    strcmp(hcsn, FM_FMRI_HC_SPECIFIC_PHYSADDR) == 0) {
989e4b86885SCheng Sean Ye 		char *hcid;
990e4b86885SCheng Sean Ye 		nvlist_t *hcsp;
991e4b86885SCheng Sean Ye 		uint64_t val;
992e4b86885SCheng Sean Ye 
993e4b86885SCheng Sean Ye 		(void) nvlist_lookup_string(pa[npairs - 1], FM_FMRI_HC_ID,
994e4b86885SCheng Sean Ye 		    &hcid);
9951db96d3bSCheng Sean Ye 		val = strtoull(hcid, NULL, 16);
996e4b86885SCheng Sean Ye 		if (topo_mod_nvalloc(mod, &hcsp, NV_UNIQUE_NAME) != 0)
997e4b86885SCheng Sean Ye 			goto hcfmbail;
998e4b86885SCheng Sean Ye 		if (nvlist_add_uint64(hcsp, hcsn, val) != 0 ||
999e4b86885SCheng Sean Ye 		    nvlist_add_nvlist(nf, FM_FMRI_HC_SPECIFIC, hcsp) != 0) {
1000e4b86885SCheng Sean Ye 			nvlist_free(hcsp);
1001e4b86885SCheng Sean Ye 			goto hcfmbail;
1002e4b86885SCheng Sean Ye 		}
1003e4b86885SCheng Sean Ye 
1004e4b86885SCheng Sean Ye 		nvlist_free(hcsp);
1005e4b86885SCheng Sean Ye 		n--;
1006e4b86885SCheng Sean Ye 	}
1007e4b86885SCheng Sean Ye 
1008e4b86885SCheng Sean Ye 	if ((e = nvlist_add_uint32(nf, FM_FMRI_HC_LIST_SZ, n)) == 0)
1009e4b86885SCheng Sean Ye 		e = nvlist_add_nvlist_array(nf, FM_FMRI_HC_LIST, pa, n);
10107aec1d6eScindi 	if (e != 0) {
10117aec1d6eScindi 		topo_mod_dprintf(mod, "construction of new hc nvl failed");
10127aec1d6eScindi 		goto hcfmbail;
10137aec1d6eScindi 	}
1014825ba0f2Srobj 
1015825ba0f2Srobj 	/*
1016825ba0f2Srobj 	 * Clean-up
1017825ba0f2Srobj 	 */
10187aec1d6eScindi 	for (i = 0; i < npairs; i++)
10197aec1d6eScindi 		nvlist_free(pa[i]);
10207aec1d6eScindi 	topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *));
10210eb822a1Scindi 	topo_mod_strfree(mod, serial);
10220eb822a1Scindi 	topo_mod_strfree(mod, part);
10230eb822a1Scindi 	topo_mod_strfree(mod, rev);
10240eb822a1Scindi 	nvlist_free(auth);
10250eb822a1Scindi 
1026825ba0f2Srobj 	if (make_facility(mod, str, &fac) == -1)
1027825ba0f2Srobj 		goto hcfmbail;
1028825ba0f2Srobj 
1029825ba0f2Srobj 	if (fac != NULL) {
1030825ba0f2Srobj 		if (nvlist_add_nvlist(nf, FM_FMRI_FACILITY, fac) != 0)
1031825ba0f2Srobj 			goto hcfmbail;
1032825ba0f2Srobj 	}
1033825ba0f2Srobj 
10347aec1d6eScindi 	*out = nf;
10357aec1d6eScindi 
10367aec1d6eScindi 	return (0);
10377aec1d6eScindi 
10387aec1d6eScindi hcfmbail:
10397aec1d6eScindi 	if (nf != NULL)
10407aec1d6eScindi 		nvlist_free(nf);
10417aec1d6eScindi 	for (i = 0; i < npairs; i++)
10427aec1d6eScindi 		nvlist_free(pa[i]);
10437aec1d6eScindi 	topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *));
1044825ba0f2Srobj 
10450eb822a1Scindi 	topo_mod_strfree(mod, serial);
10460eb822a1Scindi 	topo_mod_strfree(mod, part);
10470eb822a1Scindi 	topo_mod_strfree(mod, rev);
10480eb822a1Scindi 	nvlist_free(auth);
1049825ba0f2Srobj 	nvlist_free(nf);
10507aec1d6eScindi 	return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
10517aec1d6eScindi }
10527aec1d6eScindi 
10537aec1d6eScindi static nvlist_t *
hc_list_create(topo_mod_t * mod,const char * name,char * inst)10547aec1d6eScindi hc_list_create(topo_mod_t *mod, const char *name, char *inst)
10557aec1d6eScindi {
10567aec1d6eScindi 	int err;
10577aec1d6eScindi 	nvlist_t *hc;
10587aec1d6eScindi 
10597aec1d6eScindi 	if (topo_mod_nvalloc(mod, &hc, NV_UNIQUE_NAME) != 0)
10607aec1d6eScindi 		return (NULL);
10617aec1d6eScindi 
10627aec1d6eScindi 	err = nvlist_add_string(hc, FM_FMRI_HC_NAME, name);
10637aec1d6eScindi 	err |= nvlist_add_string(hc, FM_FMRI_HC_ID, inst);
10647aec1d6eScindi 	if (err != 0) {
10657aec1d6eScindi 		nvlist_free(hc);
10667aec1d6eScindi 		return (NULL);
10677aec1d6eScindi 	}
10687aec1d6eScindi 
10697aec1d6eScindi 	return (hc);
10707aec1d6eScindi }
10717aec1d6eScindi 
10727aec1d6eScindi static nvlist_t *
hc_create_seterror(topo_mod_t * mod,nvlist_t ** hcl,int n,nvlist_t * fmri,int err)10737aec1d6eScindi hc_create_seterror(topo_mod_t *mod, nvlist_t **hcl, int n, nvlist_t *fmri,
10747aec1d6eScindi     int err)
10757aec1d6eScindi {
10767aec1d6eScindi 	int i;
10777aec1d6eScindi 
10787aec1d6eScindi 	if (hcl != NULL) {
10797aec1d6eScindi 		for (i = 0; i < n + 1; ++i)
10807aec1d6eScindi 			nvlist_free(hcl[i]);
10817aec1d6eScindi 
10827aec1d6eScindi 		topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (n + 1));
10837aec1d6eScindi 	}
10847aec1d6eScindi 
10857aec1d6eScindi 	nvlist_free(fmri);
10867aec1d6eScindi 
10877aec1d6eScindi 	(void) topo_mod_seterrno(mod, err);
10887aec1d6eScindi 
10897aec1d6eScindi 	topo_mod_dprintf(mod, "unable to create hc FMRI: %s\n",
10907aec1d6eScindi 	    topo_mod_errmsg(mod));
10917aec1d6eScindi 
10927aec1d6eScindi 	return (NULL);
10937aec1d6eScindi }
10947aec1d6eScindi 
10957aec1d6eScindi static int
hc_name_canonical(topo_mod_t * mod,const char * name)10960eb822a1Scindi hc_name_canonical(topo_mod_t *mod, const char *name)
10977aec1d6eScindi {
10987aec1d6eScindi 	int i;
10990eb822a1Scindi 
11000eb822a1Scindi 	if (getenv("NOHCCHECK") != NULL)
11010eb822a1Scindi 		return (1);
11020eb822a1Scindi 
11037aec1d6eScindi 	/*
11047aec1d6eScindi 	 * Only enumerate elements with correct canonical names
11057aec1d6eScindi 	 */
11060eb822a1Scindi 	for (i = 0; i < hc_ncanon; i++) {
11070eb822a1Scindi 		if (strcmp(name, hc_canon[i].hcc_name) == 0)
11087aec1d6eScindi 			break;
11097aec1d6eScindi 	}
11100eb822a1Scindi 	if (i >= hc_ncanon) {
11110eb822a1Scindi 		topo_mod_dprintf(mod, "non-canonical name %s\n",
11120eb822a1Scindi 		    name);
11137aec1d6eScindi 		return (0);
11140eb822a1Scindi 	} else {
11157aec1d6eScindi 		return (1);
11167aec1d6eScindi 	}
11170eb822a1Scindi }
11187aec1d6eScindi 
11197aec1d6eScindi static nvlist_t *
hc_fmri_create(topo_mod_t * mod,nvlist_t * pfmri,int version,const char * name,topo_instance_t inst,const nvlist_t * auth,const char * part,const char * rev,const char * serial)11207aec1d6eScindi hc_fmri_create(topo_mod_t *mod, nvlist_t *pfmri, int version, const char *name,
11217aec1d6eScindi     topo_instance_t inst, const nvlist_t *auth, const char *part,
11227aec1d6eScindi     const char *rev, const char *serial)
11237aec1d6eScindi {
11247aec1d6eScindi 	int i;
11257aec1d6eScindi 	char str[21]; /* sizeof (UINT64_MAX) + '\0' */
11267aec1d6eScindi 	uint_t pelems = 0;
11277aec1d6eScindi 	nvlist_t **phcl = NULL;
11287aec1d6eScindi 	nvlist_t **hcl = NULL;
11297aec1d6eScindi 	nvlist_t *fmri = NULL;
11307aec1d6eScindi 
11317aec1d6eScindi 	if (version > FM_HC_SCHEME_VERSION)
11327aec1d6eScindi 		return (hc_create_seterror(mod,
11337aec1d6eScindi 		    hcl, pelems, fmri, EMOD_VER_OLD));
11347aec1d6eScindi 	else if (version < FM_HC_SCHEME_VERSION)
11357aec1d6eScindi 		return (hc_create_seterror(mod,
11367aec1d6eScindi 		    hcl, pelems, fmri, EMOD_VER_NEW));
11377aec1d6eScindi 
11387aec1d6eScindi 	/*
11397aec1d6eScindi 	 * Check that the requested name is in our canonical list
11407aec1d6eScindi 	 */
11410eb822a1Scindi 	if (hc_name_canonical(mod, name) == 0)
11427aec1d6eScindi 		return (hc_create_seterror(mod,
11437aec1d6eScindi 		    hcl, pelems, fmri, EMOD_NONCANON));
11447aec1d6eScindi 	/*
11457aec1d6eScindi 	 * Copy the parent's HC_LIST
11467aec1d6eScindi 	 */
11477aec1d6eScindi 	if (pfmri != NULL) {
11487aec1d6eScindi 		if (nvlist_lookup_nvlist_array(pfmri, FM_FMRI_HC_LIST,
11497aec1d6eScindi 		    &phcl, &pelems) != 0)
11507aec1d6eScindi 			return (hc_create_seterror(mod,
11517aec1d6eScindi 			    hcl, pelems, fmri, EMOD_FMRI_MALFORM));
11527aec1d6eScindi 	}
11537aec1d6eScindi 
11547aec1d6eScindi 	hcl = topo_mod_zalloc(mod, sizeof (nvlist_t *) * (pelems + 1));
11557aec1d6eScindi 	if (hcl == NULL)
11567aec1d6eScindi 		return (hc_create_seterror(mod,  hcl, pelems, fmri,
11577aec1d6eScindi 		    EMOD_NOMEM));
11587aec1d6eScindi 
11597aec1d6eScindi 	for (i = 0; i < pelems; ++i)
11607aec1d6eScindi 		if (topo_mod_nvdup(mod, phcl[i], &hcl[i]) != 0)
11617aec1d6eScindi 			return (hc_create_seterror(mod,
11627aec1d6eScindi 			    hcl, pelems, fmri, EMOD_FMRI_NVL));
11637aec1d6eScindi 
11647aec1d6eScindi 	(void) snprintf(str, sizeof (str), "%d", inst);
11657aec1d6eScindi 	if ((hcl[i] = hc_list_create(mod, name, str)) == NULL)
11667aec1d6eScindi 		return (hc_create_seterror(mod,
11677aec1d6eScindi 		    hcl, pelems, fmri, EMOD_FMRI_NVL));
11687aec1d6eScindi 
11697aec1d6eScindi 	if ((fmri = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL)
11707aec1d6eScindi 		return (hc_create_seterror(mod,
11717aec1d6eScindi 		    hcl, pelems, fmri, EMOD_FMRI_NVL));
11727aec1d6eScindi 
11737aec1d6eScindi 	if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, hcl, pelems + 1)
11747aec1d6eScindi 	    != 0)
11757aec1d6eScindi 		return (hc_create_seterror(mod,
11767aec1d6eScindi 		    hcl, pelems, fmri, EMOD_FMRI_NVL));
11777aec1d6eScindi 
11787aec1d6eScindi 	if (hcl != NULL) {
11797aec1d6eScindi 		for (i = 0; i < pelems + 1; ++i) {
11807aec1d6eScindi 			if (hcl[i] != NULL)
11817aec1d6eScindi 				nvlist_free(hcl[i]);
11827aec1d6eScindi 		}
11837aec1d6eScindi 		topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (pelems + 1));
11847aec1d6eScindi 	}
11857aec1d6eScindi 
11867aec1d6eScindi 	return (fmri);
11877aec1d6eScindi }
11887aec1d6eScindi 
11897aec1d6eScindi /*ARGSUSED*/
11907aec1d6eScindi static int
hc_fmri_create_meth(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)11910eb822a1Scindi hc_fmri_create_meth(topo_mod_t *mod, tnode_t *node, topo_version_t version,
11927aec1d6eScindi     nvlist_t *in, nvlist_t **out)
11937aec1d6eScindi {
119489c0ae93Scindi 	int ret;
119589c0ae93Scindi 	nvlist_t *args, *pfmri = NULL;
11967aec1d6eScindi 	nvlist_t *auth;
11977aec1d6eScindi 	uint32_t inst;
11987aec1d6eScindi 	char *name, *serial, *rev, *part;
11997aec1d6eScindi 
12007aec1d6eScindi 	if (version > TOPO_METH_FMRI_VERSION)
12010eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
12027aec1d6eScindi 
12037aec1d6eScindi 	/* First the must-have fields */
12047aec1d6eScindi 	if (nvlist_lookup_string(in, TOPO_METH_FMRI_ARG_NAME, &name) != 0)
12050eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
12067aec1d6eScindi 	if (nvlist_lookup_uint32(in, TOPO_METH_FMRI_ARG_INST, &inst) != 0)
12070eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
12087aec1d6eScindi 
120989c0ae93Scindi 	/*
121089c0ae93Scindi 	 * args is optional
121189c0ae93Scindi 	 */
121289c0ae93Scindi 	pfmri = NULL;
12137aec1d6eScindi 	auth = NULL;
12147aec1d6eScindi 	serial = rev = part = NULL;
121589c0ae93Scindi 	if ((ret = nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args))
121689c0ae93Scindi 	    != 0) {
121789c0ae93Scindi 		if (ret != ENOENT)
12180eb822a1Scindi 			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
121989c0ae93Scindi 	} else {
122089c0ae93Scindi 
122189c0ae93Scindi 		/* And then optional arguments */
122289c0ae93Scindi 		(void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
122389c0ae93Scindi 		    &pfmri);
122489c0ae93Scindi 		(void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_AUTH,
122589c0ae93Scindi 		    &auth);
122689c0ae93Scindi 		(void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_PART,
122789c0ae93Scindi 		    &part);
12287aec1d6eScindi 		(void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_REV, &rev);
122989c0ae93Scindi 		(void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_SER,
123089c0ae93Scindi 		    &serial);
123189c0ae93Scindi 	}
12327aec1d6eScindi 
12330eb822a1Scindi 	*out = hc_fmri_create(mod, pfmri, version, name, inst, auth, part,
12340eb822a1Scindi 	    rev, serial);
12357aec1d6eScindi 	if (*out == NULL)
12367aec1d6eScindi 		return (-1);
12377aec1d6eScindi 	return (0);
12387aec1d6eScindi }
1239c40d7343Scindi 
1240c40d7343Scindi struct hc_walk {
1241c40d7343Scindi 	topo_mod_walk_cb_t hcw_cb;
1242c40d7343Scindi 	void *hcw_priv;
1243c40d7343Scindi 	topo_walk_t *hcw_wp;
1244c40d7343Scindi 	nvlist_t **hcw_list;
1245940d71d2Seschrock 	nvlist_t *hcw_fmri;
1246825ba0f2Srobj 	nvlist_t *hcw_fac;
1247c40d7343Scindi 	uint_t hcw_index;
1248c40d7343Scindi 	uint_t hcw_end;
1249c40d7343Scindi };
1250c40d7343Scindi 
1251c40d7343Scindi /*
1252940d71d2Seschrock  * Returns true if the given node is beneath the specified FMRI.  This uses
1253940d71d2Seschrock  * the TOPO_METH_CONTAINS method, because some enumerators (such as external
1254940d71d2Seschrock  * enclosures) may want to do a comparison based on chassis WWN instead of the
1255940d71d2Seschrock  * instance ID.  If this comparison function fails or is not supported, then we
1256940d71d2Seschrock  * fall back to a direct name/instance comparison.
1257940d71d2Seschrock  */
1258940d71d2Seschrock static int
hc_match(topo_mod_t * mod,tnode_t * node,nvlist_t * fmri,const char * name,topo_instance_t inst,boolean_t * result)1259940d71d2Seschrock hc_match(topo_mod_t *mod, tnode_t *node, nvlist_t *fmri, const char *name,
1260940d71d2Seschrock     topo_instance_t inst, boolean_t *result)
1261940d71d2Seschrock {
1262940d71d2Seschrock 	nvlist_t *rsrc;
1263940d71d2Seschrock 	nvlist_t *arg, *nvl;
1264940d71d2Seschrock 	uint32_t match = 0;
1265940d71d2Seschrock 	int err;
1266940d71d2Seschrock 
1267940d71d2Seschrock 	if (topo_node_resource(node, &rsrc, &err) != 0)
1268940d71d2Seschrock 		return (-1);
1269940d71d2Seschrock 
1270940d71d2Seschrock 	if (topo_mod_nvalloc(mod, &arg, NV_UNIQUE_NAME) != 0 ||
1271940d71d2Seschrock 	    nvlist_add_nvlist(arg, TOPO_METH_FMRI_ARG_FMRI,
1272940d71d2Seschrock 	    rsrc) != 0 ||
1273940d71d2Seschrock 	    nvlist_add_nvlist(arg, TOPO_METH_FMRI_ARG_SUBFMRI,
1274940d71d2Seschrock 	    fmri) != 0) {
1275940d71d2Seschrock 		nvlist_free(rsrc);
1276940d71d2Seschrock 		(void) topo_mod_seterrno(mod, EMOD_NOMEM);
1277940d71d2Seschrock 		return (-1);
1278940d71d2Seschrock 	}
1279940d71d2Seschrock 
1280940d71d2Seschrock 	nvlist_free(rsrc);
1281940d71d2Seschrock 
1282940d71d2Seschrock 	if (topo_method_invoke(node, TOPO_METH_CONTAINS,
1283940d71d2Seschrock 	    TOPO_METH_CONTAINS_VERSION, arg, &nvl, &err) != 0) {
1284940d71d2Seschrock 		nvlist_free(arg);
1285940d71d2Seschrock 		if (err == ETOPO_METHOD_NOTSUP) {
1286940d71d2Seschrock 			match = (strcmp(name,
1287940d71d2Seschrock 			    topo_node_name(node)) == 0 &&
1288940d71d2Seschrock 			    inst == topo_node_instance(node));
1289940d71d2Seschrock 		} else {
1290940d71d2Seschrock 			return (-1);
1291940d71d2Seschrock 		}
1292940d71d2Seschrock 	} else {
1293940d71d2Seschrock 		nvlist_free(arg);
1294940d71d2Seschrock 		if (nvlist_lookup_uint32(nvl, TOPO_METH_CONTAINS_RET,
1295940d71d2Seschrock 		    &match) != 0) {
1296940d71d2Seschrock 			nvlist_free(nvl);
1297940d71d2Seschrock 			(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
1298940d71d2Seschrock 			return (-1);
1299940d71d2Seschrock 		}
1300940d71d2Seschrock 		nvlist_free(nvl);
1301940d71d2Seschrock 	}
1302940d71d2Seschrock 
1303940d71d2Seschrock 	*result = (match != 0);
1304940d71d2Seschrock 	return (0);
1305940d71d2Seschrock }
1306940d71d2Seschrock 
1307940d71d2Seschrock /*
1308940d71d2Seschrock  * Ideally, we should just be able to call topo_walk_bysibling().  But that
1309940d71d2Seschrock  * code assumes that the name/instance pair will match, so we need to
1310940d71d2Seschrock  * explicitly iterate over children of the parent looking for a matching value.
1311940d71d2Seschrock  */
1312940d71d2Seschrock static int
hc_walk_sibling(topo_mod_t * mod,tnode_t * node,struct hc_walk * hwp,const char * name,topo_instance_t inst)1313940d71d2Seschrock hc_walk_sibling(topo_mod_t *mod, tnode_t *node, struct hc_walk *hwp,
1314940d71d2Seschrock     const char *name, topo_instance_t inst)
1315940d71d2Seschrock {
1316940d71d2Seschrock 	tnode_t *pnp = topo_node_parent(node);
1317940d71d2Seschrock 	topo_walk_t *wp = hwp->hcw_wp;
1318940d71d2Seschrock 	tnode_t *np;
1319940d71d2Seschrock 	boolean_t matched;
1320940d71d2Seschrock 	int status;
1321940d71d2Seschrock 
1322940d71d2Seschrock 	for (np = topo_child_first(pnp); np != NULL;
1323940d71d2Seschrock 	    np = topo_child_next(pnp, np)) {
1324940d71d2Seschrock 		topo_node_hold(np);
1325940d71d2Seschrock 		if (hc_match(mod, np, hwp->hcw_fmri, name, inst,
1326940d71d2Seschrock 		    &matched) == 0 && matched) {
1327940d71d2Seschrock 			wp->tw_node = np;
1328940d71d2Seschrock 			if (wp->tw_mod != NULL)
1329940d71d2Seschrock 				status = wp->tw_cb(mod, np, hwp);
1330940d71d2Seschrock 			else
1331940d71d2Seschrock 				status = wp->tw_cb(wp->tw_thp, np, hwp);
1332940d71d2Seschrock 			topo_node_rele(np);
1333940d71d2Seschrock 			wp->tw_node = node;
1334940d71d2Seschrock 			return (status);
1335940d71d2Seschrock 		}
1336940d71d2Seschrock 
1337940d71d2Seschrock 		topo_node_rele(np);
1338940d71d2Seschrock 	}
1339940d71d2Seschrock 
1340940d71d2Seschrock 	return (TOPO_WALK_TERMINATE);
1341940d71d2Seschrock }
1342940d71d2Seschrock 
1343940d71d2Seschrock /*
1344c40d7343Scindi  * Generic walker for the hc-scheme topo tree.  This function uses the
1345825ba0f2Srobj  * hierachical nature of the hc-scheme to efficiently step through
134678432d5eScy152378  * the topo hc tree.  Node lookups are done by topo_walk_byid() and
134778432d5eScy152378  * topo_walk_bysibling()  at each component level to avoid unnecessary
134878432d5eScy152378  * traversal of the tree.  hc_walker() never returns TOPO_WALK_NEXT, so
134978432d5eScy152378  * whether TOPO_WALK_CHILD or TOPO_WALK_SIBLING is specified by
135078432d5eScy152378  * topo_walk_step() doesn't affect the traversal.
1351c40d7343Scindi  */
1352c40d7343Scindi static int
hc_walker(topo_mod_t * mod,tnode_t * node,void * pdata)1353c40d7343Scindi hc_walker(topo_mod_t *mod, tnode_t *node, void *pdata)
1354c40d7343Scindi {
1355c40d7343Scindi 	int i, err;
1356c40d7343Scindi 	struct hc_walk *hwp = (struct hc_walk *)pdata;
1357c40d7343Scindi 	char *name, *id;
1358825ba0f2Srobj 	char *fname, *ftype;
1359c40d7343Scindi 	topo_instance_t inst;
1360940d71d2Seschrock 	boolean_t match;
1361c40d7343Scindi 
1362c40d7343Scindi 	i = hwp->hcw_index;
1363c40d7343Scindi 	if (i > hwp->hcw_end) {
1364825ba0f2Srobj 		if (hwp->hcw_fac != NULL) {
1365825ba0f2Srobj 			if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv))
1366825ba0f2Srobj 			    != 0) {
1367825ba0f2Srobj 				(void) topo_mod_seterrno(mod, err);
1368825ba0f2Srobj 				topo_mod_dprintf(mod, "hc_walker: callback "
1369825ba0f2Srobj 				    "failed: %s\n ", topo_mod_errmsg(mod));
1370825ba0f2Srobj 				return (TOPO_WALK_ERR);
1371825ba0f2Srobj 			}
1372825ba0f2Srobj 			topo_mod_dprintf(mod, "hc_walker: callback "
1373825ba0f2Srobj 			    "complete: terminate walk\n");
1374c40d7343Scindi 			return (TOPO_WALK_TERMINATE);
1375825ba0f2Srobj 		} else {
1376825ba0f2Srobj 			topo_mod_dprintf(mod, "hc_walker: node not found\n");
1377825ba0f2Srobj 			return (TOPO_WALK_TERMINATE);
1378825ba0f2Srobj 		}
1379c40d7343Scindi 	}
1380c40d7343Scindi 
1381c40d7343Scindi 	err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name);
1382c40d7343Scindi 	err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id);
1383c40d7343Scindi 
1384c40d7343Scindi 	if (err != 0) {
1385c40d7343Scindi 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
1386c40d7343Scindi 		return (TOPO_WALK_ERR);
1387c40d7343Scindi 	}
1388c40d7343Scindi 
1389c40d7343Scindi 	inst = atoi(id);
139001e689ccScindi 
139101e689ccScindi 	/*
1392940d71d2Seschrock 	 * Check to see if our node matches the requested FMRI.  If it doesn't
1393940d71d2Seschrock 	 * (because the enumerator determines matching based on something other
1394940d71d2Seschrock 	 * than name/instance, or because we're at the first level below the
1395940d71d2Seschrock 	 * root), then iterate over siblings to find the matching node.
139601e689ccScindi 	 */
1397940d71d2Seschrock 	if (hc_match(mod, node, hwp->hcw_fmri, name, inst, &match) != 0)
1398940d71d2Seschrock 		return (TOPO_WALK_ERR);
1399940d71d2Seschrock 
1400940d71d2Seschrock 	if (!match)
1401940d71d2Seschrock 		return (hc_walk_sibling(mod, node, hwp, name, inst));
140201e689ccScindi 
1403c40d7343Scindi 	topo_mod_dprintf(mod, "hc_walker: walking node:%s=%d for hc:"
1404c40d7343Scindi 	    "%s=%d at %d, end at %d \n", topo_node_name(node),
1405c40d7343Scindi 	    topo_node_instance(node), name, inst, i, hwp->hcw_end);
1406825ba0f2Srobj 
1407c40d7343Scindi 	if (i == hwp->hcw_end) {
1408825ba0f2Srobj 
1409c40d7343Scindi 		/*
1410825ba0f2Srobj 		 * We are at the end of the hc-list.  Now, check for
1411825ba0f2Srobj 		 * a facility leaf and walk one more time.
1412c40d7343Scindi 		 */
1413825ba0f2Srobj 		if (hwp->hcw_fac != NULL) {
1414825ba0f2Srobj 			err = nvlist_lookup_string(hwp->hcw_fac,
1415825ba0f2Srobj 			    FM_FMRI_FACILITY_NAME, &fname);
1416825ba0f2Srobj 			err |= nvlist_lookup_string(hwp->hcw_fac,
1417825ba0f2Srobj 			    FM_FMRI_FACILITY_TYPE, &ftype);
1418825ba0f2Srobj 			if (err != 0) {
1419825ba0f2Srobj 				(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
1420825ba0f2Srobj 				return (TOPO_WALK_ERR);
1421825ba0f2Srobj 			}
1422825ba0f2Srobj 			hwp->hcw_index++;
1423825ba0f2Srobj 			topo_mod_dprintf(mod, "hc_walker: walk to facility "
1424825ba0f2Srobj 			    "node:%s=%s\n", fname, ftype);
1425825ba0f2Srobj 			return (topo_walk_byid(hwp->hcw_wp, fname, 0));
1426825ba0f2Srobj 		}
1427825ba0f2Srobj 
1428825ba0f2Srobj 		/*
1429825ba0f2Srobj 		 * Otherwise, this is the node we're looking for.
1430825ba0f2Srobj 		 */
1431825ba0f2Srobj 		if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv)) != 0) {
1432c40d7343Scindi 			(void) topo_mod_seterrno(mod, err);
1433c40d7343Scindi 			topo_mod_dprintf(mod, "hc_walker: callback "
1434c40d7343Scindi 			    "failed: %s\n ", topo_mod_errmsg(mod));
1435c40d7343Scindi 			return (TOPO_WALK_ERR);
1436825ba0f2Srobj 		} else {
1437c40d7343Scindi 			topo_mod_dprintf(mod, "hc_walker: callback "
1438c40d7343Scindi 			    "complete: terminate walk\n");
1439c40d7343Scindi 			return (TOPO_WALK_TERMINATE);
1440c40d7343Scindi 		}
1441c40d7343Scindi 	}
1442c40d7343Scindi 
1443825ba0f2Srobj 	/*
1444825ba0f2Srobj 	 * Move on to the next component in the hc-list
1445825ba0f2Srobj 	 */
1446c40d7343Scindi 	hwp->hcw_index = ++i;
1447c40d7343Scindi 	err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name);
1448c40d7343Scindi 	err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id);
1449c40d7343Scindi 	if (err != 0) {
1450c40d7343Scindi 		(void) topo_mod_seterrno(mod, err);
1451c40d7343Scindi 		return (TOPO_WALK_ERR);
1452c40d7343Scindi 	}
1453c40d7343Scindi 	inst = atoi(id);
1454c40d7343Scindi 
1455c40d7343Scindi 	return (topo_walk_byid(hwp->hcw_wp, name, inst));
1456c40d7343Scindi 
1457c40d7343Scindi }
1458c40d7343Scindi 
1459c40d7343Scindi static struct hc_walk *
hc_walk_init(topo_mod_t * mod,tnode_t * node,nvlist_t * rsrc,topo_mod_walk_cb_t cb,void * pdata)1460c40d7343Scindi hc_walk_init(topo_mod_t *mod, tnode_t *node, nvlist_t *rsrc,
1461c40d7343Scindi     topo_mod_walk_cb_t cb, void *pdata)
1462c40d7343Scindi {
1463825ba0f2Srobj 	int err, ret;
1464c40d7343Scindi 	uint_t sz;
1465c40d7343Scindi 	struct hc_walk *hwp;
1466c40d7343Scindi 	topo_walk_t *wp;
1467c40d7343Scindi 
1468918a0d8aSrobj 	if ((hwp = topo_mod_alloc(mod, sizeof (struct hc_walk))) == NULL) {
1469c40d7343Scindi 		(void) topo_mod_seterrno(mod, EMOD_NOMEM);
1470918a0d8aSrobj 		return (NULL);
1471918a0d8aSrobj 	}
1472c40d7343Scindi 
1473c40d7343Scindi 	if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hwp->hcw_list,
1474c40d7343Scindi 	    &sz) != 0) {
1475825ba0f2Srobj 		topo_mod_dprintf(mod, "hc_walk_init: failed to lookup %s "
1476825ba0f2Srobj 		    "nvlist\n", FM_FMRI_HC_LIST);
1477c40d7343Scindi 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1478c40d7343Scindi 		(void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
1479c40d7343Scindi 		return (NULL);
1480c40d7343Scindi 	}
1481825ba0f2Srobj 	if ((ret = nvlist_lookup_nvlist(rsrc, FM_FMRI_FACILITY, &hwp->hcw_fac))
1482825ba0f2Srobj 	    != 0) {
1483825ba0f2Srobj 		if (ret != ENOENT) {
1484825ba0f2Srobj 			topo_mod_dprintf(mod, "hc_walk_init: unexpected error "
1485825ba0f2Srobj 			    "looking up %s nvlist", FM_FMRI_FACILITY);
1486825ba0f2Srobj 			topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1487825ba0f2Srobj 			(void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
1488825ba0f2Srobj 			return (NULL);
1489825ba0f2Srobj 		} else {
1490825ba0f2Srobj 			hwp->hcw_fac = NULL;
1491825ba0f2Srobj 		}
1492825ba0f2Srobj 	}
1493c40d7343Scindi 
1494940d71d2Seschrock 	hwp->hcw_fmri = rsrc;
1495c40d7343Scindi 	hwp->hcw_end = sz - 1;
1496c40d7343Scindi 	hwp->hcw_index = 0;
1497c40d7343Scindi 	hwp->hcw_priv = pdata;
1498c40d7343Scindi 	hwp->hcw_cb = cb;
1499c40d7343Scindi 	if ((wp = topo_mod_walk_init(mod, node, hc_walker, (void *)hwp, &err))
1500c40d7343Scindi 	    == NULL) {
1501825ba0f2Srobj 		topo_mod_dprintf(mod, "hc_walk_init: topo_mod_walk_init failed "
1502825ba0f2Srobj 		    "(%s)\n", topo_strerror(err));
1503c40d7343Scindi 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1504c40d7343Scindi 		(void) topo_mod_seterrno(mod, err);
1505c40d7343Scindi 		return (NULL);
1506c40d7343Scindi 	}
1507c40d7343Scindi 
1508c40d7343Scindi 	hwp->hcw_wp = wp;
1509c40d7343Scindi 
1510c40d7343Scindi 	return (hwp);
1511c40d7343Scindi }
1512c40d7343Scindi 
1513c40d7343Scindi struct prop_lookup {
1514c40d7343Scindi 	const char *pl_pgroup;
1515c40d7343Scindi 	const char *pl_pname;
1516c40d7343Scindi 	int pl_flag;
1517c40d7343Scindi 	nvlist_t *pl_args;
1518c40d7343Scindi 	nvlist_t *pl_rsrc;
1519c40d7343Scindi 	nvlist_t *pl_prop;
1520c40d7343Scindi };
1521c40d7343Scindi 
1522c40d7343Scindi /*ARGSUSED*/
1523c40d7343Scindi static int
hc_prop_get(topo_mod_t * mod,tnode_t * node,void * pdata)1524c40d7343Scindi hc_prop_get(topo_mod_t *mod, tnode_t *node, void *pdata)
1525c40d7343Scindi {
1526c40d7343Scindi 	int err = 0;
1527c40d7343Scindi 
1528c40d7343Scindi 	struct prop_lookup *plp = (struct prop_lookup *)pdata;
1529c40d7343Scindi 
1530c40d7343Scindi 	(void) topo_prop_getprop(node, plp->pl_pgroup, plp->pl_pname,
1531c40d7343Scindi 	    plp->pl_args, &plp->pl_prop, &err);
1532c40d7343Scindi 
1533c40d7343Scindi 	return (err);
1534c40d7343Scindi }
1535c40d7343Scindi 
1536c40d7343Scindi static int
hc_fmri_prop_get(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)1537c40d7343Scindi hc_fmri_prop_get(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1538c40d7343Scindi     nvlist_t *in, nvlist_t **out)
1539c40d7343Scindi {
1540c40d7343Scindi 	int err;
1541c40d7343Scindi 	struct hc_walk *hwp;
1542c40d7343Scindi 	struct prop_lookup *plp;
1543c40d7343Scindi 
1544c40d7343Scindi 	if (version > TOPO_METH_PROP_GET_VERSION)
1545c40d7343Scindi 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1546c40d7343Scindi 
1547c40d7343Scindi 	if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
1548c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1549c40d7343Scindi 
1550c40d7343Scindi 	err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
1551c40d7343Scindi 	    (char **)&plp->pl_pgroup);
1552c40d7343Scindi 	err |= nvlist_lookup_string(in, TOPO_PROP_VAL_NAME,
1553c40d7343Scindi 	    (char **)&plp->pl_pname);
1554c40d7343Scindi 	err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
1555c40d7343Scindi 	if (err != 0) {
1556c40d7343Scindi 		topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1557c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1558c40d7343Scindi 	}
1559c40d7343Scindi 
1560c40d7343Scindi 	/*
1561c40d7343Scindi 	 * Private args to prop method are optional
1562c40d7343Scindi 	 */
1563c40d7343Scindi 	if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args))
1564c40d7343Scindi 	    != 0) {
1565c40d7343Scindi 		if (err != ENOENT) {
1566c40d7343Scindi 			topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1567c40d7343Scindi 			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1568c40d7343Scindi 		} else {
1569c40d7343Scindi 			plp->pl_args = NULL;
1570c40d7343Scindi 		}
1571c40d7343Scindi 	}
1572c40d7343Scindi 
1573c40d7343Scindi 	plp->pl_prop = NULL;
1574c40d7343Scindi 	if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_get,
1575c40d7343Scindi 	    (void *)plp)) != NULL) {
157678432d5eScy152378 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1577c40d7343Scindi 		    TOPO_WALK_ERR)
1578c40d7343Scindi 			err = -1;
1579c40d7343Scindi 		else
1580c40d7343Scindi 			err = 0;
1581c40d7343Scindi 		topo_walk_fini(hwp->hcw_wp);
1582918a0d8aSrobj 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1583c40d7343Scindi 	} else {
1584c40d7343Scindi 		err = -1;
1585c40d7343Scindi 	}
1586c40d7343Scindi 
1587c40d7343Scindi 	if (plp->pl_prop != NULL)
1588c40d7343Scindi 		*out = plp->pl_prop;
1589c40d7343Scindi 
1590c40d7343Scindi 	topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1591c40d7343Scindi 
1592c40d7343Scindi 	return (err);
1593c40d7343Scindi }
1594c40d7343Scindi 
1595c40d7343Scindi /*ARGSUSED*/
1596c40d7343Scindi static int
hc_pgrp_get(topo_mod_t * mod,tnode_t * node,void * pdata)1597c40d7343Scindi hc_pgrp_get(topo_mod_t *mod, tnode_t *node, void *pdata)
1598c40d7343Scindi {
1599c40d7343Scindi 	int err = 0;
1600c40d7343Scindi 
1601c40d7343Scindi 	struct prop_lookup *plp = (struct prop_lookup *)pdata;
1602c40d7343Scindi 
1603c40d7343Scindi 	(void) topo_prop_getpgrp(node, plp->pl_pgroup, &plp->pl_prop, &err);
1604c40d7343Scindi 
1605c40d7343Scindi 	return (err);
1606c40d7343Scindi }
1607c40d7343Scindi 
1608c40d7343Scindi static int
hc_fmri_pgrp_get(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)1609c40d7343Scindi hc_fmri_pgrp_get(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1610c40d7343Scindi     nvlist_t *in, nvlist_t **out)
1611c40d7343Scindi {
1612c40d7343Scindi 	int err;
1613c40d7343Scindi 	struct hc_walk *hwp;
1614c40d7343Scindi 	struct prop_lookup *plp;
1615c40d7343Scindi 
1616c40d7343Scindi 	if (version > TOPO_METH_PGRP_GET_VERSION)
1617c40d7343Scindi 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1618c40d7343Scindi 
1619c40d7343Scindi 	if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
1620c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1621c40d7343Scindi 
1622c40d7343Scindi 	err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
1623c40d7343Scindi 	    (char **)&plp->pl_pgroup);
1624c40d7343Scindi 	err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
1625c40d7343Scindi 	if (err != 0) {
1626c40d7343Scindi 		topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1627c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1628c40d7343Scindi 	}
1629c40d7343Scindi 
1630c40d7343Scindi 	plp->pl_prop = NULL;
1631c40d7343Scindi 	if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_pgrp_get,
1632c40d7343Scindi 	    (void *)plp)) != NULL) {
163378432d5eScy152378 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1634c40d7343Scindi 		    TOPO_WALK_ERR)
1635c40d7343Scindi 			err = -1;
1636c40d7343Scindi 		else
1637c40d7343Scindi 			err = 0;
1638c40d7343Scindi 		topo_walk_fini(hwp->hcw_wp);
1639918a0d8aSrobj 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1640c40d7343Scindi 	} else {
1641c40d7343Scindi 		err = -1;
1642c40d7343Scindi 	}
1643c40d7343Scindi 
1644c40d7343Scindi 	if (plp->pl_prop != NULL)
1645c40d7343Scindi 		*out = plp->pl_prop;
1646c40d7343Scindi 
1647c40d7343Scindi 	topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1648c40d7343Scindi 
1649c40d7343Scindi 	return (err);
1650c40d7343Scindi }
1651c40d7343Scindi 
1652c40d7343Scindi /*ARGSUSED*/
1653c40d7343Scindi static int
hc_prop_setprop(topo_mod_t * mod,tnode_t * node,void * pdata)1654c40d7343Scindi hc_prop_setprop(topo_mod_t *mod, tnode_t *node, void *pdata)
1655c40d7343Scindi {
1656c40d7343Scindi 	int err = 0;
1657c40d7343Scindi 
1658c40d7343Scindi 	struct prop_lookup *plp = (struct prop_lookup *)pdata;
1659c40d7343Scindi 
1660c40d7343Scindi 	(void) topo_prop_setprop(node, plp->pl_pgroup, plp->pl_prop,
1661c40d7343Scindi 	    plp->pl_flag, plp->pl_args, &err);
1662c40d7343Scindi 
1663c40d7343Scindi 	return (err);
1664c40d7343Scindi }
1665c40d7343Scindi 
1666c40d7343Scindi /*ARGSUSED*/
1667c40d7343Scindi static int
hc_fmri_prop_set(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)1668c40d7343Scindi hc_fmri_prop_set(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1669c40d7343Scindi     nvlist_t *in, nvlist_t **out)
1670c40d7343Scindi {
1671c40d7343Scindi 	int err;
1672c40d7343Scindi 	struct hc_walk *hwp;
1673c40d7343Scindi 	struct prop_lookup *plp;
1674c40d7343Scindi 
1675c40d7343Scindi 	if (version > TOPO_METH_PROP_SET_VERSION)
1676c40d7343Scindi 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1677c40d7343Scindi 
1678c40d7343Scindi 	if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
1679c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1680c40d7343Scindi 
1681c40d7343Scindi 	err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
1682c40d7343Scindi 	    (char **)&plp->pl_pgroup);
1683c40d7343Scindi 	err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
1684c40d7343Scindi 	err |= nvlist_lookup_nvlist(in, TOPO_PROP_VAL, &plp->pl_prop);
1685c40d7343Scindi 	err |= nvlist_lookup_int32(in, TOPO_PROP_FLAG, &plp->pl_flag);
1686c40d7343Scindi 	if (err != 0) {
1687c40d7343Scindi 		topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1688c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1689c40d7343Scindi 	}
1690c40d7343Scindi 
1691c40d7343Scindi 	/*
1692c40d7343Scindi 	 * Private args to prop method are optional
1693c40d7343Scindi 	 */
1694c40d7343Scindi 	if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args))
1695c40d7343Scindi 	    != 0) {
1696c40d7343Scindi 		if (err != ENOENT)
1697c40d7343Scindi 			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1698c40d7343Scindi 		else
1699c40d7343Scindi 			plp->pl_args = NULL;
1700c40d7343Scindi 	}
1701c40d7343Scindi 
1702c40d7343Scindi 	if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_setprop,
1703c40d7343Scindi 	    (void *)plp)) != NULL) {
170478432d5eScy152378 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1705c40d7343Scindi 		    TOPO_WALK_ERR)
1706c40d7343Scindi 			err = -1;
1707c40d7343Scindi 		else
1708c40d7343Scindi 			err = 0;
1709c40d7343Scindi 		topo_walk_fini(hwp->hcw_wp);
1710918a0d8aSrobj 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1711c40d7343Scindi 	} else {
1712c40d7343Scindi 		err = -1;
1713c40d7343Scindi 	}
1714c40d7343Scindi 
1715c40d7343Scindi 	topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1716c40d7343Scindi 
1717c40d7343Scindi 	return (err);
1718c40d7343Scindi }
1719c40d7343Scindi 
1720c40d7343Scindi struct hc_args {
1721c40d7343Scindi 	nvlist_t *ha_fmri;
1722c40d7343Scindi 	nvlist_t *ha_nvl;
1723e4b86885SCheng Sean Ye 	char *ha_method_name;
1724e4b86885SCheng Sean Ye 	topo_version_t ha_method_ver;
1725c40d7343Scindi };
1726c40d7343Scindi 
17276e1fa242SStephen Hanson static int
hc_auth_changed(nvlist_t * nva,nvlist_t * nvb,const char * propname)17287793aa8bSEric Schrock hc_auth_changed(nvlist_t *nva, nvlist_t *nvb, const char *propname)
17297793aa8bSEric Schrock {
17307793aa8bSEric Schrock 	char *stra, *strb;
17317793aa8bSEric Schrock 
17327793aa8bSEric Schrock 	if (nvlist_lookup_string(nva, propname, &stra) != 0 ||
17337793aa8bSEric Schrock 	    nvlist_lookup_string(nvb, propname, &strb) != 0)
17346e1fa242SStephen Hanson 		return (FMD_OBJ_STATE_UNKNOWN);
17357793aa8bSEric Schrock 
17367793aa8bSEric Schrock 	if (strcmp(stra, strb) != 0)
17376e1fa242SStephen Hanson 		return (FMD_OBJ_STATE_REPLACED);
17387793aa8bSEric Schrock 	else
17396e1fa242SStephen Hanson 		return (FMD_OBJ_STATE_STILL_PRESENT);
17407793aa8bSEric Schrock }
17417793aa8bSEric Schrock 
1742c40d7343Scindi static int
hc_is_present(topo_mod_t * mod,tnode_t * node,void * pdata)1743c40d7343Scindi hc_is_present(topo_mod_t *mod, tnode_t *node, void *pdata)
1744c40d7343Scindi {
1745c40d7343Scindi 	int err;
1746c40d7343Scindi 	struct hc_args *hap = (struct hc_args *)pdata;
17477793aa8bSEric Schrock 	nvlist_t *rsrc;
17487793aa8bSEric Schrock 	boolean_t present;
1749c40d7343Scindi 
1750c40d7343Scindi 	/*
1751c40d7343Scindi 	 * check with the enumerator that created this FMRI
1752c40d7343Scindi 	 * (topo node)
1753c40d7343Scindi 	 */
1754c40d7343Scindi 	if (topo_method_invoke(node, TOPO_METH_PRESENT,
1755c40d7343Scindi 	    TOPO_METH_PRESENT_VERSION, hap->ha_fmri, &hap->ha_nvl,
1756c40d7343Scindi 	    &err) < 0) {
1757c40d7343Scindi 
1758c40d7343Scindi 		/*
17597793aa8bSEric Schrock 		 * If the method exists but failed for some other reason,
17607793aa8bSEric Schrock 		 * propagate the error as making any decision over presence is
17617793aa8bSEric Schrock 		 * impossible.
1762c40d7343Scindi 		 */
17637793aa8bSEric Schrock 		if (err != ETOPO_METHOD_NOTSUP)
17647793aa8bSEric Schrock 			return (err);
1765c40d7343Scindi 
17667793aa8bSEric Schrock 		/*
17677793aa8bSEric Schrock 		 * Check the authority information.  If the part id or serial
17687793aa8bSEric Schrock 		 * number doesn't match, then it isn't the same FMRI.
17697793aa8bSEric Schrock 		 * Otherwise, assume presence.
17707793aa8bSEric Schrock 		 */
17717793aa8bSEric Schrock 		if (topo_node_resource(node, &rsrc, &err) != 0)
17727793aa8bSEric Schrock 			return (err);
17737793aa8bSEric Schrock 
17747793aa8bSEric Schrock 		present = B_TRUE;
17757793aa8bSEric Schrock 		if (hc_auth_changed(hap->ha_fmri, rsrc,
17766e1fa242SStephen Hanson 		    FM_FMRI_HC_SERIAL_ID) == FMD_OBJ_STATE_REPLACED ||
17777793aa8bSEric Schrock 		    hc_auth_changed(hap->ha_fmri, rsrc,
17786e1fa242SStephen Hanson 		    FM_FMRI_HC_PART) == FMD_OBJ_STATE_REPLACED) {
17797793aa8bSEric Schrock 			present = B_FALSE;
17807793aa8bSEric Schrock 		}
17817793aa8bSEric Schrock 		nvlist_free(rsrc);
17827793aa8bSEric Schrock 
17837793aa8bSEric Schrock 		if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) != 0)
17847793aa8bSEric Schrock 			return (EMOD_NOMEM);
17857793aa8bSEric Schrock 
17867793aa8bSEric Schrock 		if (nvlist_add_uint32(hap->ha_nvl,
17877793aa8bSEric Schrock 		    TOPO_METH_PRESENT_RET, present) != 0) {
17887793aa8bSEric Schrock 			nvlist_free(hap->ha_nvl);
17897793aa8bSEric Schrock 			hap->ha_nvl = NULL;
17907793aa8bSEric Schrock 			return (EMOD_NOMEM);
17917793aa8bSEric Schrock 		}
1792c40d7343Scindi 	}
1793c40d7343Scindi 
179424db4641Seschrock 	return (0);
1795c40d7343Scindi }
1796c40d7343Scindi 
1797c40d7343Scindi static int
hc_fmri_present(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)1798c40d7343Scindi hc_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1799c40d7343Scindi     nvlist_t *in, nvlist_t **out)
1800c40d7343Scindi {
1801c40d7343Scindi 	int err;
1802c40d7343Scindi 	struct hc_walk *hwp;
1803c40d7343Scindi 	struct hc_args *hap;
1804c40d7343Scindi 
1805c40d7343Scindi 	if (version > TOPO_METH_PRESENT_VERSION)
1806c40d7343Scindi 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1807c40d7343Scindi 
1808c40d7343Scindi 	if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
1809c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1810c40d7343Scindi 
1811c40d7343Scindi 	hap->ha_fmri = in;
1812c40d7343Scindi 	hap->ha_nvl = NULL;
1813c40d7343Scindi 	if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_is_present,
1814c40d7343Scindi 	    (void *)hap)) != NULL) {
181578432d5eScy152378 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1816c40d7343Scindi 		    TOPO_WALK_ERR)
1817c40d7343Scindi 			err = -1;
1818c40d7343Scindi 		else
1819c40d7343Scindi 			err = 0;
1820c40d7343Scindi 		topo_walk_fini(hwp->hcw_wp);
1821918a0d8aSrobj 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1822c40d7343Scindi 	} else {
1823c40d7343Scindi 		err = -1;
1824c40d7343Scindi 	}
1825c40d7343Scindi 
1826c40d7343Scindi 	if (hap->ha_nvl != NULL)
1827c40d7343Scindi 		*out = hap->ha_nvl;
1828c40d7343Scindi 
1829c40d7343Scindi 	topo_mod_free(mod, hap, sizeof (struct hc_args));
1830c40d7343Scindi 
1831c40d7343Scindi 	return (err);
1832c40d7343Scindi }
1833c40d7343Scindi 
1834c40d7343Scindi static int
hc_is_replaced(topo_mod_t * mod,tnode_t * node,void * pdata)183525c6ff4bSstephh hc_is_replaced(topo_mod_t *mod, tnode_t *node, void *pdata)
183625c6ff4bSstephh {
183725c6ff4bSstephh 	int err;
183825c6ff4bSstephh 	struct hc_args *hap = (struct hc_args *)pdata;
183925c6ff4bSstephh 	uint32_t present = 0;
18406e1fa242SStephen Hanson 	nvlist_t *rsrc;
18416e1fa242SStephen Hanson 	uint32_t rval = FMD_OBJ_STATE_UNKNOWN;
184225c6ff4bSstephh 
184325c6ff4bSstephh 	/*
184425c6ff4bSstephh 	 * check with the enumerator that created this FMRI
184525c6ff4bSstephh 	 * (topo node)
184625c6ff4bSstephh 	 */
184725c6ff4bSstephh 	if (topo_method_invoke(node, TOPO_METH_REPLACED,
184825c6ff4bSstephh 	    TOPO_METH_REPLACED_VERSION, hap->ha_fmri, &hap->ha_nvl,
184925c6ff4bSstephh 	    &err) < 0) {
185025c6ff4bSstephh 		/*
18516e1fa242SStephen Hanson 		 * If the method exists but failed for some other
18526e1fa242SStephen Hanson 		 * reason, propagate the error as making any decision
18536e1fa242SStephen Hanson 		 * over presence is impossible.
18546e1fa242SStephen Hanson 		 */
18556e1fa242SStephen Hanson 		if (err != ETOPO_METHOD_NOTSUP)
18566e1fa242SStephen Hanson 			return (err);
18576e1fa242SStephen Hanson 
18586e1fa242SStephen Hanson 		/*
18596e1fa242SStephen Hanson 		 * Enumerator didn't provide "replaced" method -
186025c6ff4bSstephh 		 * try "present" method
186125c6ff4bSstephh 		 */
186225c6ff4bSstephh 		if (topo_method_invoke(node, TOPO_METH_PRESENT,
186325c6ff4bSstephh 		    TOPO_METH_PRESENT_VERSION, hap->ha_fmri, &hap->ha_nvl,
186425c6ff4bSstephh 		    &err) < 0) {
18656e1fa242SStephen Hanson 			/*
18666e1fa242SStephen Hanson 			 * If the method exists but failed for some other
18676e1fa242SStephen Hanson 			 * reason, propagate the error as making any decision
18686e1fa242SStephen Hanson 			 * over presence is impossible.
18696e1fa242SStephen Hanson 			 */
18706e1fa242SStephen Hanson 			if (err != ETOPO_METHOD_NOTSUP)
18716e1fa242SStephen Hanson 				return (err);
18726e1fa242SStephen Hanson 
18736e1fa242SStephen Hanson 			/*
18746e1fa242SStephen Hanson 			 * Enumerator didn't provide "present" method either -
18756e1fa242SStephen Hanson 			 * so check the authority information.  If the part id
18766e1fa242SStephen Hanson 			 * or serial number doesn't match, then it isn't the
18776e1fa242SStephen Hanson 			 * same FMRI. Otherwise, if we have a serial number and
18786e1fa242SStephen Hanson 			 * it hasn't changed, then assume it is the same FMRI.
18796e1fa242SStephen Hanson 			 */
18806e1fa242SStephen Hanson 			if (topo_node_resource(node, &rsrc, &err) != 0)
18816e1fa242SStephen Hanson 				return (err);
18826e1fa242SStephen Hanson 			rval = hc_auth_changed(hap->ha_fmri, rsrc,
18836e1fa242SStephen Hanson 			    FM_FMRI_HC_PART);
18846e1fa242SStephen Hanson 			if (rval != FMD_OBJ_STATE_REPLACED)
18856e1fa242SStephen Hanson 				rval = hc_auth_changed(hap->ha_fmri, rsrc,
18866e1fa242SStephen Hanson 				    FM_FMRI_HC_SERIAL_ID);
18876e1fa242SStephen Hanson 			nvlist_free(rsrc);
1888e5dcf7beSRobert Johnston 			if (topo_mod_nvalloc(mod, &hap->ha_nvl,
1889e5dcf7beSRobert Johnston 			    NV_UNIQUE_NAME) != 0)
18906e1fa242SStephen Hanson 				return (EMOD_NOMEM);
18916e1fa242SStephen Hanson 			if (nvlist_add_uint32(hap->ha_nvl,
18926e1fa242SStephen Hanson 			    TOPO_METH_REPLACED_RET, rval) != 0) {
18936e1fa242SStephen Hanson 				nvlist_free(hap->ha_nvl);
18946e1fa242SStephen Hanson 				hap->ha_nvl = NULL;
1895e5dcf7beSRobert Johnston 				return (ETOPO_PROP_NVL);
18966e1fa242SStephen Hanson 			}
189725c6ff4bSstephh 		} else {
189825c6ff4bSstephh 			(void) nvlist_lookup_uint32(hap->ha_nvl,
189925c6ff4bSstephh 			    TOPO_METH_PRESENT_RET, &present);
190025c6ff4bSstephh 			(void) nvlist_remove(hap->ha_nvl,
190125c6ff4bSstephh 			    TOPO_METH_PRESENT_RET, DATA_TYPE_UINT32);
19026e1fa242SStephen Hanson 			if (nvlist_add_uint32(hap->ha_nvl,
19036e1fa242SStephen Hanson 			    TOPO_METH_REPLACED_RET,
1904c7d6cfd6SStephen Hanson 			    present ? FMD_OBJ_STATE_UNKNOWN :
1905e5dcf7beSRobert Johnston 			    FMD_OBJ_STATE_NOT_PRESENT) != 0) {
1906e5dcf7beSRobert Johnston 				nvlist_free(hap->ha_nvl);
19076e1fa242SStephen Hanson 				hap->ha_nvl = NULL;
190825c6ff4bSstephh 				return (ETOPO_PROP_NVL);
190925c6ff4bSstephh 			}
1910e5dcf7beSRobert Johnston 		}
19116e1fa242SStephen Hanson 	}
191225c6ff4bSstephh 	return (0);
191325c6ff4bSstephh }
191425c6ff4bSstephh 
191525c6ff4bSstephh static int
hc_fmri_replaced(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)191625c6ff4bSstephh hc_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version,
191725c6ff4bSstephh     nvlist_t *in, nvlist_t **out)
191825c6ff4bSstephh {
191925c6ff4bSstephh 	int err;
192025c6ff4bSstephh 	struct hc_walk *hwp;
192125c6ff4bSstephh 	struct hc_args *hap;
192225c6ff4bSstephh 
192325c6ff4bSstephh 	if (version > TOPO_METH_REPLACED_VERSION)
192425c6ff4bSstephh 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
192525c6ff4bSstephh 
192625c6ff4bSstephh 	if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
192725c6ff4bSstephh 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
192825c6ff4bSstephh 
192925c6ff4bSstephh 	hap->ha_fmri = in;
193025c6ff4bSstephh 	hap->ha_nvl = NULL;
193125c6ff4bSstephh 	if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_is_replaced,
193225c6ff4bSstephh 	    (void *)hap)) != NULL) {
193325c6ff4bSstephh 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
193425c6ff4bSstephh 		    TOPO_WALK_ERR)
193525c6ff4bSstephh 			err = -1;
193625c6ff4bSstephh 		else
193725c6ff4bSstephh 			err = 0;
193825c6ff4bSstephh 		topo_walk_fini(hwp->hcw_wp);
193925c6ff4bSstephh 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
194025c6ff4bSstephh 	} else {
194125c6ff4bSstephh 		err = -1;
194225c6ff4bSstephh 	}
194325c6ff4bSstephh 
194425c6ff4bSstephh 	if (hap->ha_nvl != NULL)
194525c6ff4bSstephh 		*out = hap->ha_nvl;
194625c6ff4bSstephh 
194725c6ff4bSstephh 	topo_mod_free(mod, hap, sizeof (struct hc_args));
194825c6ff4bSstephh 
194925c6ff4bSstephh 	return (err);
195025c6ff4bSstephh }
195125c6ff4bSstephh 
195225c6ff4bSstephh static int
hc_unusable(topo_mod_t * mod,tnode_t * node,void * pdata)1953c40d7343Scindi hc_unusable(topo_mod_t *mod, tnode_t *node, void *pdata)
1954c40d7343Scindi {
1955c40d7343Scindi 	int err;
1956c40d7343Scindi 	struct hc_args *hap = (struct hc_args *)pdata;
1957c40d7343Scindi 
1958c40d7343Scindi 	/*
1959c40d7343Scindi 	 * check with the enumerator that created this FMRI
1960c40d7343Scindi 	 * (topo node)
1961c40d7343Scindi 	 */
1962c40d7343Scindi 	if (topo_method_invoke(node, TOPO_METH_UNUSABLE,
1963c40d7343Scindi 	    TOPO_METH_UNUSABLE_VERSION, hap->ha_fmri, &hap->ha_nvl,
1964c40d7343Scindi 	    &err) < 0) {
1965c40d7343Scindi 
1966c40d7343Scindi 		/*
1967c40d7343Scindi 		 * Err on the side of caution and return usable
1968c40d7343Scindi 		 */
1969c40d7343Scindi 		if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) == 0)
1970c40d7343Scindi 			if (nvlist_add_uint32(hap->ha_nvl,
1971c40d7343Scindi 			    TOPO_METH_UNUSABLE_RET, 0) == 0)
1972c40d7343Scindi 				return (0);
1973c40d7343Scindi 
1974c40d7343Scindi 		return (ETOPO_PROP_NVL);
1975c40d7343Scindi 	}
1976c40d7343Scindi 
1977e4b86885SCheng Sean Ye 	return (0);
1978c40d7343Scindi }
1979c40d7343Scindi 
1980c40d7343Scindi static int
hc_fmri_unusable(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)1981c40d7343Scindi hc_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1982c40d7343Scindi     nvlist_t *in, nvlist_t **out)
1983c40d7343Scindi {
1984c40d7343Scindi 	int err;
1985c40d7343Scindi 	struct hc_walk *hwp;
1986c40d7343Scindi 	struct hc_args *hap;
1987c40d7343Scindi 
1988c40d7343Scindi 	if (version > TOPO_METH_UNUSABLE_VERSION)
1989c40d7343Scindi 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1990c40d7343Scindi 
1991c40d7343Scindi 	if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
1992c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1993c40d7343Scindi 
1994c40d7343Scindi 	hap->ha_fmri = in;
1995c40d7343Scindi 	hap->ha_nvl = NULL;
1996c40d7343Scindi 	if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_unusable,
1997c40d7343Scindi 	    (void *)hap)) != NULL) {
199878432d5eScy152378 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1999c40d7343Scindi 		    TOPO_WALK_ERR)
2000c40d7343Scindi 			err = -1;
2001c40d7343Scindi 		else
2002c40d7343Scindi 			err = 0;
2003c40d7343Scindi 		topo_walk_fini(hwp->hcw_wp);
2004918a0d8aSrobj 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2005c40d7343Scindi 	} else {
2006c40d7343Scindi 		err = -1;
2007c40d7343Scindi 	}
2008c40d7343Scindi 
2009c40d7343Scindi 	if (hap->ha_nvl != NULL)
2010c40d7343Scindi 		*out = hap->ha_nvl;
2011c40d7343Scindi 
2012c40d7343Scindi 	topo_mod_free(mod, hap, sizeof (struct hc_args));
2013c40d7343Scindi 
2014c40d7343Scindi 	return (err);
2015c40d7343Scindi }
2016825ba0f2Srobj 
2017825ba0f2Srobj struct fac_lookup {
2018825ba0f2Srobj 	const char *fl_fac_type;
2019825ba0f2Srobj 	uint32_t fl_fac_subtype;
2020825ba0f2Srobj #ifdef _LP64
2021825ba0f2Srobj 	uint64_t fl_callback;
2022825ba0f2Srobj 	uint64_t fl_callback_args;
2023825ba0f2Srobj #else
2024825ba0f2Srobj 	uint32_t fl_callback;
2025825ba0f2Srobj 	uint32_t fl_callback_args;
2026825ba0f2Srobj #endif
2027825ba0f2Srobj 	nvlist_t *fl_rsrc;
2028825ba0f2Srobj 	nvlist_t *fl_fac_rsrc;
2029825ba0f2Srobj };
2030825ba0f2Srobj 
2031825ba0f2Srobj static int
hc_fac_get(topo_mod_t * mod,tnode_t * node,void * pdata)2032825ba0f2Srobj hc_fac_get(topo_mod_t *mod, tnode_t *node, void *pdata)
2033825ba0f2Srobj {
2034825ba0f2Srobj 	struct fac_lookup *flp = (struct fac_lookup *)pdata;
2035825ba0f2Srobj 	topo_walk_cb_t cb = (topo_walk_cb_t)flp->fl_callback;
2036825ba0f2Srobj 	topo_faclist_t faclist, *tmp;
2037825ba0f2Srobj 	int err, ret = 0;
2038825ba0f2Srobj 
2039825ba0f2Srobj 	/*
2040825ba0f2Srobj 	 * Lookup the specified facility node.  Return with an error if we can't
2041825ba0f2Srobj 	 * find it.
2042825ba0f2Srobj 	 */
2043825ba0f2Srobj 	if (topo_node_facility(mod->tm_hdl, node, flp->fl_fac_type,
2044825ba0f2Srobj 	    flp->fl_fac_subtype, &faclist, &err) != 0) {
2045825ba0f2Srobj 		topo_mod_dprintf(mod, "hc_fac_get: topo_node_facility "
2046825ba0f2Srobj 		    "failed\n");
2047825ba0f2Srobj 		return (TOPO_WALK_ERR);
2048825ba0f2Srobj 	}
2049825ba0f2Srobj 
2050825ba0f2Srobj 	/*
2051825ba0f2Srobj 	 * Invoke user's callback for each facility node in the topo list,
2052825ba0f2Srobj 	 * passing in a pointer to the facility node
2053825ba0f2Srobj 	 */
2054825ba0f2Srobj 	for (tmp = topo_list_next(&faclist.tf_list); tmp != NULL;
2055825ba0f2Srobj 	    tmp = topo_list_next(tmp)) {
2056825ba0f2Srobj 
2057825ba0f2Srobj 		if ((err = cb(mod->tm_hdl, tmp->tf_node,
2058825ba0f2Srobj 		    (void *)flp->fl_callback_args)) != 0) {
2059825ba0f2Srobj 			(void) topo_mod_seterrno(mod, err);
2060825ba0f2Srobj 			topo_mod_dprintf(mod, "hc_fac_get: callback failed: "
2061825ba0f2Srobj 			    "%s\n ", topo_mod_errmsg(mod));
2062825ba0f2Srobj 			ret = TOPO_WALK_ERR;
2063825ba0f2Srobj 			break;
2064825ba0f2Srobj 		}
2065825ba0f2Srobj 	}
2066825ba0f2Srobj 
2067825ba0f2Srobj 	while ((tmp = topo_list_next(&faclist.tf_list)) != NULL) {
2068825ba0f2Srobj 		topo_list_delete(&faclist.tf_list, tmp);
2069825ba0f2Srobj 		topo_mod_free(mod, tmp, sizeof (topo_faclist_t));
2070825ba0f2Srobj 	}
2071825ba0f2Srobj 	return (ret);
2072825ba0f2Srobj }
2073825ba0f2Srobj 
2074825ba0f2Srobj static int
hc_fmri_facility(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)2075825ba0f2Srobj hc_fmri_facility(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2076825ba0f2Srobj     nvlist_t *in, nvlist_t **out)
2077825ba0f2Srobj {
2078825ba0f2Srobj 	int err = 0;
2079825ba0f2Srobj 	struct hc_walk *hwp;
2080825ba0f2Srobj 	struct fac_lookup *flp;
2081825ba0f2Srobj 
2082825ba0f2Srobj 	if (version > TOPO_METH_FACILITY_VERSION)
2083825ba0f2Srobj 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2084825ba0f2Srobj 
2085825ba0f2Srobj 	if ((flp = topo_mod_alloc(mod, sizeof (struct fac_lookup))) == NULL)
2086825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
2087825ba0f2Srobj 
2088825ba0f2Srobj 	/*
2089825ba0f2Srobj 	 * lookup arguments: hw resource, facility type, facility subtype,
2090825ba0f2Srobj 	 *  callback and callback args
2091825ba0f2Srobj 	 */
2092825ba0f2Srobj 	err = nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &flp->fl_rsrc);
2093825ba0f2Srobj 	err |= nvlist_lookup_string(in, FM_FMRI_FACILITY_TYPE,
2094825ba0f2Srobj 	    (char **)&flp->fl_fac_type);
2095825ba0f2Srobj 	err |= nvlist_lookup_uint32(in, "type", &flp->fl_fac_subtype);
2096825ba0f2Srobj #ifdef _LP64
2097825ba0f2Srobj 	err |= nvlist_lookup_uint64(in, "callback", &flp->fl_callback);
2098825ba0f2Srobj 	err |= nvlist_lookup_uint64(in, "callback-args",
2099825ba0f2Srobj 	    &flp->fl_callback_args);
2100825ba0f2Srobj #else
2101825ba0f2Srobj 	err |= nvlist_lookup_uint32(in, "callback", &flp->fl_callback);
2102825ba0f2Srobj 	err |= nvlist_lookup_uint32(in, "callback-args",
2103825ba0f2Srobj 	    &flp->fl_callback_args);
2104825ba0f2Srobj #endif
2105825ba0f2Srobj 	if (err != 0) {
2106825ba0f2Srobj 		topo_mod_dprintf(mod, "hc_fmri_facility: failed to construct "
2107825ba0f2Srobj 		    "walker arg nvlist\n");
2108825ba0f2Srobj 		topo_mod_free(mod, flp, sizeof (struct fac_lookup));
2109825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2110825ba0f2Srobj 	}
2111825ba0f2Srobj 
2112825ba0f2Srobj 	flp->fl_fac_rsrc = NULL;
2113825ba0f2Srobj 	if ((hwp = hc_walk_init(mod, node, flp->fl_rsrc, hc_fac_get,
2114825ba0f2Srobj 	    (void *)flp)) != NULL) {
2115825ba0f2Srobj 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2116825ba0f2Srobj 		    TOPO_WALK_ERR)
2117825ba0f2Srobj 			err = -1;
2118825ba0f2Srobj 		else
2119825ba0f2Srobj 			err = 0;
2120825ba0f2Srobj 		topo_walk_fini(hwp->hcw_wp);
2121825ba0f2Srobj 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2122825ba0f2Srobj 	} else {
2123825ba0f2Srobj 		topo_mod_dprintf(mod, "hc_fmri_facility: failed to initialize "
2124825ba0f2Srobj 		    "hc walker\n");
2125825ba0f2Srobj 		err = -1;
2126825ba0f2Srobj 	}
2127825ba0f2Srobj 
2128825ba0f2Srobj 	if (flp->fl_fac_rsrc != NULL)
2129825ba0f2Srobj 		*out = flp->fl_fac_rsrc;
2130825ba0f2Srobj 
2131825ba0f2Srobj 	topo_mod_free(mod, flp, sizeof (struct fac_lookup));
2132825ba0f2Srobj 
2133825ba0f2Srobj 	return (err);
2134825ba0f2Srobj }
2135e4b86885SCheng Sean Ye 
2136e4b86885SCheng Sean Ye /* ARGSUSED */
2137e4b86885SCheng Sean Ye static int
hc_expand(topo_mod_t * mod,tnode_t * node,void * pdata)2138e4b86885SCheng Sean Ye hc_expand(topo_mod_t *mod, tnode_t *node, void *pdata)
2139e4b86885SCheng Sean Ye {
2140e4b86885SCheng Sean Ye 	int err;
2141e4b86885SCheng Sean Ye 	nvlist_t *nvl;
2142e4b86885SCheng Sean Ye 	const char **namep;
2143e4b86885SCheng Sean Ye 	struct hc_args *hap = (struct hc_args *)pdata;
2144e4b86885SCheng Sean Ye 	const char *names[] = {
2145e4b86885SCheng Sean Ye 		FM_FMRI_HC_SERIAL_ID,
2146e4b86885SCheng Sean Ye 		FM_FMRI_HC_PART,
2147e4b86885SCheng Sean Ye 		FM_FMRI_HC_REVISION,
2148e4b86885SCheng Sean Ye 		NULL
2149e4b86885SCheng Sean Ye 	};
2150e4b86885SCheng Sean Ye 
2151e4b86885SCheng Sean Ye 	if (topo_node_resource(node, &nvl, &err) != 0)
2152e4b86885SCheng Sean Ye 		return (ETOPO_METHOD_FAIL);
2153e4b86885SCheng Sean Ye 
2154e4b86885SCheng Sean Ye 	for (namep = names; *namep != NULL; namep++) {
2155e4b86885SCheng Sean Ye 		char *in_val, *node_val;
2156e4b86885SCheng Sean Ye 
2157e4b86885SCheng Sean Ye 		if (nvlist_lookup_string(nvl, *namep, &node_val) != 0)
2158e4b86885SCheng Sean Ye 			continue;
2159e4b86885SCheng Sean Ye 
2160e4b86885SCheng Sean Ye 		if (nvlist_lookup_string(hap->ha_fmri, *namep, &in_val) == 0) {
2161e4b86885SCheng Sean Ye 			if (strcmp(in_val, node_val) == 0)
2162e4b86885SCheng Sean Ye 				continue;
2163e4b86885SCheng Sean Ye 			(void) nvlist_remove(hap->ha_fmri, *namep,
2164e4b86885SCheng Sean Ye 			    DATA_TYPE_STRING);
2165e4b86885SCheng Sean Ye 		}
2166e4b86885SCheng Sean Ye 
2167e4b86885SCheng Sean Ye 		if (nvlist_add_string(hap->ha_fmri, *namep, node_val) != 0) {
2168e4b86885SCheng Sean Ye 			nvlist_free(nvl);
2169e4b86885SCheng Sean Ye 			return (ETOPO_PROP_NVL);
2170e4b86885SCheng Sean Ye 		}
2171e4b86885SCheng Sean Ye 	}
2172e4b86885SCheng Sean Ye 	nvlist_free(nvl);
2173e4b86885SCheng Sean Ye 
2174e4b86885SCheng Sean Ye 	return (0);
2175e4b86885SCheng Sean Ye }
2176e4b86885SCheng Sean Ye 
2177e4b86885SCheng Sean Ye /* ARGSUSED */
2178e4b86885SCheng Sean Ye static int
hc_fmri_expand(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)2179e4b86885SCheng Sean Ye hc_fmri_expand(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2180e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
2181e4b86885SCheng Sean Ye {
2182e4b86885SCheng Sean Ye 	int err;
2183e4b86885SCheng Sean Ye 	struct hc_walk *hwp;
2184e4b86885SCheng Sean Ye 	struct hc_args *hap;
2185e4b86885SCheng Sean Ye 
2186e4b86885SCheng Sean Ye 	if (version > TOPO_METH_EXPAND_VERSION)
2187e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2188e4b86885SCheng Sean Ye 
2189e4b86885SCheng Sean Ye 	if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
2190e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
2191e4b86885SCheng Sean Ye 
2192e4b86885SCheng Sean Ye 	hap->ha_fmri = in;
2193e4b86885SCheng Sean Ye 	hap->ha_nvl = NULL;
2194e4b86885SCheng Sean Ye 	if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_expand,
2195e4b86885SCheng Sean Ye 	    (void *)hap)) != NULL) {
2196e4b86885SCheng Sean Ye 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2197e4b86885SCheng Sean Ye 		    TOPO_WALK_ERR)
2198e4b86885SCheng Sean Ye 			err = -1;
2199e4b86885SCheng Sean Ye 		else
2200e4b86885SCheng Sean Ye 			err = 0;
2201e4b86885SCheng Sean Ye 		topo_walk_fini(hwp->hcw_wp);
2202e4b86885SCheng Sean Ye 	} else {
2203e4b86885SCheng Sean Ye 		err = -1;
2204e4b86885SCheng Sean Ye 	}
2205e4b86885SCheng Sean Ye 
2206e4b86885SCheng Sean Ye 	topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2207e4b86885SCheng Sean Ye 
2208e4b86885SCheng Sean Ye 	/* expand method should not return out nvlist */
2209e4b86885SCheng Sean Ye 	assert(hap->ha_nvl == NULL);
2210e4b86885SCheng Sean Ye 
2211e4b86885SCheng Sean Ye 	topo_mod_free(mod, hap, sizeof (struct hc_args));
2212e4b86885SCheng Sean Ye 
2213e4b86885SCheng Sean Ye 	return (err);
2214e4b86885SCheng Sean Ye }
2215e4b86885SCheng Sean Ye 
2216e4b86885SCheng Sean Ye static int
hc_retire_subr(topo_mod_t * mod,tnode_t * node,void * pdata)2217e4b86885SCheng Sean Ye hc_retire_subr(topo_mod_t *mod, tnode_t *node, void *pdata)
2218e4b86885SCheng Sean Ye {
2219e4b86885SCheng Sean Ye 	int err, rc;
2220e4b86885SCheng Sean Ye 	struct hc_args *hap = (struct hc_args *)pdata;
2221e4b86885SCheng Sean Ye 
2222e4b86885SCheng Sean Ye 	topo_mod_dprintf(mod, "hc_retire_subr: invoking method %s\n",
2223e4b86885SCheng Sean Ye 	    hap->ha_method_name);
2224e4b86885SCheng Sean Ye 	/*
2225e4b86885SCheng Sean Ye 	 * check with the enumerator that created this FMRI
2226e4b86885SCheng Sean Ye 	 * (topo node)
2227e4b86885SCheng Sean Ye 	 */
2228e4b86885SCheng Sean Ye 	rc = topo_method_invoke(node, hap->ha_method_name,
2229e4b86885SCheng Sean Ye 	    hap->ha_method_ver, hap->ha_fmri, &hap->ha_nvl, &err);
2230e4b86885SCheng Sean Ye 
2231e4b86885SCheng Sean Ye 	topo_mod_dprintf(mod, "hc_retire_subr: invoking method %s "
2232e4b86885SCheng Sean Ye 	    "returned %d\n", hap->ha_method_name, rc);
2233e4b86885SCheng Sean Ye 
2234e4b86885SCheng Sean Ye 	return (rc < 0 ? err : 0);
2235e4b86885SCheng Sean Ye }
2236e4b86885SCheng Sean Ye 
2237e4b86885SCheng Sean Ye static int
hc_fmri_retire_subr(topo_mod_t * mod,tnode_t * node,char * method_name,topo_version_t builtin_version,topo_version_t version,nvlist_t * in,nvlist_t ** out)2238e4b86885SCheng Sean Ye hc_fmri_retire_subr(topo_mod_t *mod, tnode_t *node, char *method_name,
2239e4b86885SCheng Sean Ye     topo_version_t builtin_version, topo_version_t version, nvlist_t *in,
2240e4b86885SCheng Sean Ye     nvlist_t **out)
2241e4b86885SCheng Sean Ye {
2242e4b86885SCheng Sean Ye 	int err;
2243e4b86885SCheng Sean Ye 	struct hc_walk *hwp;
2244e4b86885SCheng Sean Ye 	struct hc_args *hap;
2245e4b86885SCheng Sean Ye 
2246e4b86885SCheng Sean Ye 	if (version > builtin_version)
2247e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2248e4b86885SCheng Sean Ye 
2249e4b86885SCheng Sean Ye 	if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
2250e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
2251e4b86885SCheng Sean Ye 
2252e4b86885SCheng Sean Ye 	hap->ha_fmri = in;
2253e4b86885SCheng Sean Ye 	hap->ha_nvl = NULL;
2254e4b86885SCheng Sean Ye 	hap->ha_method_name = method_name;
2255e4b86885SCheng Sean Ye 	hap->ha_method_ver = version;
2256e4b86885SCheng Sean Ye 	if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_retire_subr,
2257e4b86885SCheng Sean Ye 	    (void *)hap)) != NULL) {
2258e4b86885SCheng Sean Ye 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2259e4b86885SCheng Sean Ye 		    TOPO_WALK_ERR)
2260e4b86885SCheng Sean Ye 			err = -1;
2261e4b86885SCheng Sean Ye 		else
2262e4b86885SCheng Sean Ye 			err = 0;
2263e4b86885SCheng Sean Ye 		topo_walk_fini(hwp->hcw_wp);
2264e4b86885SCheng Sean Ye 	} else {
2265e4b86885SCheng Sean Ye 		err = -1;
2266e4b86885SCheng Sean Ye 	}
2267e4b86885SCheng Sean Ye 
2268e4b86885SCheng Sean Ye 	topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2269e4b86885SCheng Sean Ye 
2270e4b86885SCheng Sean Ye 	if (hap->ha_nvl != NULL)
2271e4b86885SCheng Sean Ye 		*out = hap->ha_nvl;
2272e4b86885SCheng Sean Ye 
2273e4b86885SCheng Sean Ye 	topo_mod_free(mod, hap, sizeof (struct hc_args));
2274e4b86885SCheng Sean Ye 
2275e4b86885SCheng Sean Ye 	return (err);
2276e4b86885SCheng Sean Ye }
2277e4b86885SCheng Sean Ye 
2278e4b86885SCheng Sean Ye static int
hc_fmri_retire(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)2279e4b86885SCheng Sean Ye hc_fmri_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2280e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
2281e4b86885SCheng Sean Ye {
2282e4b86885SCheng Sean Ye 	return (hc_fmri_retire_subr(mod, node, TOPO_METH_RETIRE,
2283e4b86885SCheng Sean Ye 	    TOPO_METH_RETIRE_VERSION, version, in, out));
2284e4b86885SCheng Sean Ye }
2285e4b86885SCheng Sean Ye 
2286e4b86885SCheng Sean Ye static int
hc_fmri_unretire(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)2287e4b86885SCheng Sean Ye hc_fmri_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2288e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
2289e4b86885SCheng Sean Ye {
2290e4b86885SCheng Sean Ye 	return (hc_fmri_retire_subr(mod, node, TOPO_METH_UNRETIRE,
2291e4b86885SCheng Sean Ye 	    TOPO_METH_UNRETIRE_VERSION, version, in, out));
2292e4b86885SCheng Sean Ye }
2293e4b86885SCheng Sean Ye 
2294e4b86885SCheng Sean Ye static int
hc_fmri_service_state(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)2295e4b86885SCheng Sean Ye hc_fmri_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2296e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
2297e4b86885SCheng Sean Ye {
2298e4b86885SCheng Sean Ye 	return (hc_fmri_retire_subr(mod, node, TOPO_METH_SERVICE_STATE,
2299e4b86885SCheng Sean Ye 	    TOPO_METH_SERVICE_STATE_VERSION, version, in, out));
2300e4b86885SCheng Sean Ye }
2301