xref: /titanic_50/usr/src/lib/fm/topo/libtopo/common/hc.c (revision 59596c01ca1b980a016d25670874f53e64c27ec0)
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.
25*59596c01SRobert Mustacchi  * Copyright (c) 2017, Joyent, Inc.
267aec1d6eScindi  */
277aec1d6eScindi 
287aec1d6eScindi #include <stdio.h>
297aec1d6eScindi #include <stdlib.h>
307aec1d6eScindi #include <string.h>
317aec1d6eScindi #include <errno.h>
327aec1d6eScindi #include <ctype.h>
337aec1d6eScindi #include <alloca.h>
34e4b86885SCheng Sean Ye #include <assert.h>
357aec1d6eScindi #include <limits.h>
36f6e214c7SGavin Maltby #include <zone.h>
377aec1d6eScindi #include <fm/topo_mod.h>
380eb822a1Scindi #include <fm/topo_hc.h>
3925c6ff4bSstephh #include <fm/fmd_fmri.h>
407aec1d6eScindi #include <sys/param.h>
417aec1d6eScindi #include <sys/systeminfo.h>
427aec1d6eScindi #include <sys/fm/protocol.h>
430eb822a1Scindi #include <sys/stat.h>
440eb822a1Scindi #include <sys/systeminfo.h>
450eb822a1Scindi #include <sys/utsname.h>
460eb822a1Scindi 
470eb822a1Scindi #include <topo_method.h>
48825ba0f2Srobj #include <topo_module.h>
4974a31ce6Stimh #include <topo_subr.h>
50c40d7343Scindi #include <topo_prop.h>
51940d71d2Seschrock #include <topo_tree.h>
520eb822a1Scindi #include <hc.h>
537aec1d6eScindi 
547aec1d6eScindi static int hc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
550eb822a1Scindi     topo_instance_t, void *, void *);
567aec1d6eScindi static void hc_release(topo_mod_t *, tnode_t *);
577aec1d6eScindi static int hc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t,
587aec1d6eScindi     nvlist_t *, nvlist_t **);
597aec1d6eScindi static int hc_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t,
607aec1d6eScindi     nvlist_t *, nvlist_t **);
617aec1d6eScindi static int hc_compare(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
627aec1d6eScindi     nvlist_t **);
63c40d7343Scindi static int hc_fmri_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
64c40d7343Scindi     nvlist_t **);
6525c6ff4bSstephh static int hc_fmri_replaced(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
6625c6ff4bSstephh     nvlist_t **);
67c40d7343Scindi static int hc_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
68c40d7343Scindi     nvlist_t **);
69e4b86885SCheng Sean Ye static int hc_fmri_expand(topo_mod_t *, tnode_t *, topo_version_t,
70e4b86885SCheng Sean Ye     nvlist_t *, nvlist_t **);
71e4b86885SCheng Sean Ye static int hc_fmri_retire(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
72e4b86885SCheng Sean Ye     nvlist_t **);
73e4b86885SCheng Sean Ye static int hc_fmri_unretire(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
74e4b86885SCheng Sean Ye     nvlist_t **);
75e4b86885SCheng Sean Ye static int hc_fmri_service_state(topo_mod_t *, tnode_t *, topo_version_t,
76e4b86885SCheng Sean Ye     nvlist_t *, nvlist_t **);
777aec1d6eScindi static int hc_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t,
787aec1d6eScindi     nvlist_t *, nvlist_t **);
79c40d7343Scindi static int hc_fmri_prop_get(topo_mod_t *, tnode_t *, topo_version_t,
80c40d7343Scindi     nvlist_t *, nvlist_t **);
81c40d7343Scindi static int hc_fmri_prop_set(topo_mod_t *, tnode_t *, topo_version_t,
82c40d7343Scindi     nvlist_t *, nvlist_t **);
83c40d7343Scindi static int hc_fmri_pgrp_get(topo_mod_t *, tnode_t *, topo_version_t,
84c40d7343Scindi     nvlist_t *, nvlist_t **);
85825ba0f2Srobj static int hc_fmri_facility(topo_mod_t *, tnode_t *, topo_version_t,
86825ba0f2Srobj     nvlist_t *, nvlist_t **);
877aec1d6eScindi 
887aec1d6eScindi static nvlist_t *hc_fmri_create(topo_mod_t *, nvlist_t *, int, const char *,
897aec1d6eScindi     topo_instance_t inst, const nvlist_t *, const char *, const char *,
907aec1d6eScindi     const char *);
917aec1d6eScindi 
927aec1d6eScindi const topo_method_t hc_methods[] = {
937aec1d6eScindi 	{ TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION,
947aec1d6eScindi 	    TOPO_STABILITY_INTERNAL, hc_fmri_nvl2str },
957aec1d6eScindi 	{ TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION,
967aec1d6eScindi 	    TOPO_STABILITY_INTERNAL, hc_fmri_str2nvl },
977aec1d6eScindi 	{ TOPO_METH_COMPARE, TOPO_METH_COMPARE_DESC, TOPO_METH_COMPARE_VERSION,
987aec1d6eScindi 	    TOPO_STABILITY_INTERNAL, hc_compare },
99c40d7343Scindi 	{ TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION,
100c40d7343Scindi 	    TOPO_STABILITY_INTERNAL, hc_fmri_present },
10125c6ff4bSstephh 	{ TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC,
10225c6ff4bSstephh 	    TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL,
10325c6ff4bSstephh 	    hc_fmri_replaced },
104c40d7343Scindi 	{ TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
105c40d7343Scindi 	    TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
106c40d7343Scindi 	    hc_fmri_unusable },
107e4b86885SCheng Sean Ye 	{ TOPO_METH_EXPAND, TOPO_METH_EXPAND_DESC,
108e4b86885SCheng Sean Ye 	    TOPO_METH_EXPAND_VERSION, TOPO_STABILITY_INTERNAL,
109e4b86885SCheng Sean Ye 	    hc_fmri_expand },
110e4b86885SCheng Sean Ye 	{ TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
111e4b86885SCheng Sean Ye 	    TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
112e4b86885SCheng Sean Ye 	    hc_fmri_retire },
113e4b86885SCheng Sean Ye 	{ TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
114e4b86885SCheng Sean Ye 	    TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
115e4b86885SCheng Sean Ye 	    hc_fmri_unretire },
116e4b86885SCheng Sean Ye 	{ TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
117e4b86885SCheng Sean Ye 	    TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
118e4b86885SCheng Sean Ye 	    hc_fmri_service_state },
1197aec1d6eScindi 	{ TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION,
1207aec1d6eScindi 	    TOPO_STABILITY_INTERNAL, hc_fmri_create_meth },
121c40d7343Scindi 	{ TOPO_METH_PROP_GET, TOPO_METH_PROP_GET_DESC,
122c40d7343Scindi 	    TOPO_METH_PROP_GET_VERSION, TOPO_STABILITY_INTERNAL,
123c40d7343Scindi 	    hc_fmri_prop_get },
124c40d7343Scindi 	{ TOPO_METH_PROP_SET, TOPO_METH_PROP_SET_DESC,
125c40d7343Scindi 	    TOPO_METH_PROP_SET_VERSION, TOPO_STABILITY_INTERNAL,
126c40d7343Scindi 	    hc_fmri_prop_set },
127c40d7343Scindi 	{ TOPO_METH_PGRP_GET, TOPO_METH_PGRP_GET_DESC,
128c40d7343Scindi 	    TOPO_METH_PGRP_GET_VERSION, TOPO_STABILITY_INTERNAL,
129c40d7343Scindi 	    hc_fmri_pgrp_get },
130825ba0f2Srobj 	{ TOPO_METH_FACILITY, TOPO_METH_FACILITY_DESC,
131825ba0f2Srobj 	    TOPO_METH_FACILITY_VERSION, TOPO_STABILITY_INTERNAL,
132825ba0f2Srobj 	    hc_fmri_facility },
1337aec1d6eScindi 	{ NULL }
1347aec1d6eScindi };
1357aec1d6eScindi 
1360eb822a1Scindi static const topo_modops_t hc_ops =
1370eb822a1Scindi 	{ hc_enum, hc_release };
1380eb822a1Scindi static const topo_modinfo_t hc_info =
1390eb822a1Scindi 	{ HC, FM_FMRI_SCHEME_HC, HC_VERSION, &hc_ops };
1407aec1d6eScindi 
1410eb822a1Scindi static const hcc_t hc_canon[] = {
142908f1e13Ssd77468 	{ BANK, TOPO_STABILITY_PRIVATE },
143184cd04cScth 	{ BAY, TOPO_STABILITY_PRIVATE },
144908f1e13Ssd77468 	{ BLADE, TOPO_STABILITY_PRIVATE },
14514ea4bb7Ssd77468 	{ BRANCH, TOPO_STABILITY_PRIVATE },
1460eb822a1Scindi 	{ CMP, TOPO_STABILITY_PRIVATE },
1470eb822a1Scindi 	{ CENTERPLANE, TOPO_STABILITY_PRIVATE },
1480eb822a1Scindi 	{ CHASSIS, TOPO_STABILITY_PRIVATE },
1490eb822a1Scindi 	{ CHIP, TOPO_STABILITY_PRIVATE },
1500eb822a1Scindi 	{ CHIP_SELECT, TOPO_STABILITY_PRIVATE },
151908f1e13Ssd77468 	{ CORE, TOPO_STABILITY_PRIVATE },
152940d71d2Seschrock 	{ CONTROLLER, TOPO_STABILITY_PRIVATE },
1530eb822a1Scindi 	{ CPU, TOPO_STABILITY_PRIVATE },
15413faa912Ssd77468 	{ CPUBOARD, TOPO_STABILITY_PRIVATE },
1550eb822a1Scindi 	{ DIMM, TOPO_STABILITY_PRIVATE },
1560eb822a1Scindi 	{ DISK, TOPO_STABILITY_PRIVATE },
157908f1e13Ssd77468 	{ DRAM, TOPO_STABILITY_PRIVATE },
1580eb822a1Scindi 	{ DRAMCHANNEL, TOPO_STABILITY_PRIVATE },
1592eeaed14Srobj 	{ FAN, TOPO_STABILITY_PRIVATE },
160ded93414SHyon Kim 	{ FANBOARD, TOPO_STABILITY_PRIVATE },
1612eeaed14Srobj 	{ FANMODULE, TOPO_STABILITY_PRIVATE },
162fc333478STom Pothier 	{ HBA, TOPO_STABILITY_PRIVATE },
1630eb822a1Scindi 	{ HOSTBRIDGE, TOPO_STABILITY_PRIVATE },
1640eb822a1Scindi 	{ INTERCONNECT, TOPO_STABILITY_PRIVATE },
1650eb822a1Scindi 	{ IOBOARD, TOPO_STABILITY_PRIVATE },
166ac88567aSHyon Kim 	{ IPORT, TOPO_STABILITY_PRIVATE },
16713faa912Ssd77468 	{ MEMBOARD, TOPO_STABILITY_PRIVATE },
168908f1e13Ssd77468 	{ MEMORYBUFFER, TOPO_STABILITY_PRIVATE },
1690eb822a1Scindi 	{ MEMORYCONTROL, TOPO_STABILITY_PRIVATE },
170908f1e13Ssd77468 	{ MICROCORE, TOPO_STABILITY_PRIVATE },
1710eb822a1Scindi 	{ MOTHERBOARD, TOPO_STABILITY_PRIVATE },
17214ea4bb7Ssd77468 	{ NIU, TOPO_STABILITY_PRIVATE },
17314ea4bb7Ssd77468 	{ NIUFN, TOPO_STABILITY_PRIVATE },
1740eb822a1Scindi 	{ PCI_BUS, TOPO_STABILITY_PRIVATE },
1750eb822a1Scindi 	{ PCI_DEVICE, TOPO_STABILITY_PRIVATE },
1760eb822a1Scindi 	{ PCI_FUNCTION, TOPO_STABILITY_PRIVATE },
1770eb822a1Scindi 	{ PCIEX_BUS, TOPO_STABILITY_PRIVATE },
1780eb822a1Scindi 	{ PCIEX_DEVICE, TOPO_STABILITY_PRIVATE },
1790eb822a1Scindi 	{ PCIEX_FUNCTION, TOPO_STABILITY_PRIVATE },
1800eb822a1Scindi 	{ PCIEX_ROOT, TOPO_STABILITY_PRIVATE },
1810eb822a1Scindi 	{ PCIEX_SWUP, TOPO_STABILITY_PRIVATE },
1820eb822a1Scindi 	{ PCIEX_SWDWN, TOPO_STABILITY_PRIVATE },
183*59596c01SRobert Mustacchi 	{ PORT, TOPO_STABILITY_PRIVATE },
184ded93414SHyon Kim 	{ POWERBOARD, TOPO_STABILITY_PRIVATE },
1852eeaed14Srobj 	{ POWERMODULE, TOPO_STABILITY_PRIVATE },
1862eeaed14Srobj 	{ PSU, TOPO_STABILITY_PRIVATE },
1870eb822a1Scindi 	{ RANK, TOPO_STABILITY_PRIVATE },
188ac88567aSHyon Kim 	{ RECEPTACLE, TOPO_STABILITY_PRIVATE },
189908f1e13Ssd77468 	{ RISER, TOPO_STABILITY_PRIVATE },
190ac88567aSHyon Kim 	{ SASEXPANDER, TOPO_STABILITY_PRIVATE },
191ac88567aSHyon Kim 	{ SCSI_DEVICE, TOPO_STABILITY_PRIVATE },
192908f1e13Ssd77468 	{ SHELF, TOPO_STABILITY_PRIVATE },
193940d71d2Seschrock 	{ SES_ENCLOSURE, TOPO_STABILITY_PRIVATE },
194ac88567aSHyon Kim 	{ SMP_DEVICE, TOPO_STABILITY_PRIVATE },
1954df55fdeSJanie Lu 	{ SP, TOPO_STABILITY_PRIVATE },
196e4b86885SCheng Sean Ye 	{ STRAND, TOPO_STABILITY_PRIVATE },
19753dbcc59SSundeep Panicker 	{ SUBCHASSIS, TOPO_STABILITY_PRIVATE },
19814ea4bb7Ssd77468 	{ SYSTEMBOARD, TOPO_STABILITY_PRIVATE },
199*59596c01SRobert Mustacchi 	{ TRANSCEIVER, TOPO_STABILITY_PRIVATE },
20014ea4bb7Ssd77468 	{ XAUI, TOPO_STABILITY_PRIVATE },
20114ea4bb7Ssd77468 	{ XFP, TOPO_STABILITY_PRIVATE }
2020eb822a1Scindi };
2030eb822a1Scindi 
2040eb822a1Scindi static int hc_ncanon = sizeof (hc_canon) / sizeof (hcc_t);
2050eb822a1Scindi 
2060eb822a1Scindi int
hc_init(topo_mod_t * mod,topo_version_t version)2070eb822a1Scindi hc_init(topo_mod_t *mod, topo_version_t version)
2087aec1d6eScindi {
2097aec1d6eScindi 	/*
2107aec1d6eScindi 	 * Turn on module debugging output
2117aec1d6eScindi 	 */
2120eb822a1Scindi 	if (getenv("TOPOHCDEBUG"))
2130eb822a1Scindi 		topo_mod_setdebug(mod);
2147aec1d6eScindi 
2150eb822a1Scindi 	topo_mod_dprintf(mod, "initializing hc builtin\n");
2160eb822a1Scindi 
2170eb822a1Scindi 	if (version != HC_VERSION)
2180eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2190eb822a1Scindi 
2200eb822a1Scindi 	if (topo_mod_register(mod, &hc_info, TOPO_VERSION) != 0) {
2210eb822a1Scindi 		topo_mod_dprintf(mod, "failed to register hc: "
2220eb822a1Scindi 		    "%s\n", topo_mod_errmsg(mod));
2230eb822a1Scindi 		return (-1); /* mod errno already set */
2247aec1d6eScindi 	}
2250eb822a1Scindi 
2260eb822a1Scindi 	return (0);
2277aec1d6eScindi }
2287aec1d6eScindi 
2297aec1d6eScindi void
hc_fini(topo_mod_t * mod)2300eb822a1Scindi hc_fini(topo_mod_t *mod)
2317aec1d6eScindi {
2320eb822a1Scindi 	topo_mod_unregister(mod);
2330eb822a1Scindi }
2340eb822a1Scindi 
2350eb822a1Scindi 
2360eb822a1Scindi static const topo_pgroup_info_t sys_pgroup = {
2370eb822a1Scindi 	TOPO_PGROUP_SYSTEM,
2380eb822a1Scindi 	TOPO_STABILITY_PRIVATE,
2390eb822a1Scindi 	TOPO_STABILITY_PRIVATE,
2400eb822a1Scindi 	1
2410eb822a1Scindi };
2420eb822a1Scindi 
2430eb822a1Scindi static const topo_pgroup_info_t auth_pgroup = {
2440eb822a1Scindi 	FM_FMRI_AUTHORITY,
2450eb822a1Scindi 	TOPO_STABILITY_PRIVATE,
2460eb822a1Scindi 	TOPO_STABILITY_PRIVATE,
2470eb822a1Scindi 	1
2480eb822a1Scindi };
2490eb822a1Scindi 
2500eb822a1Scindi static void
hc_prop_set(tnode_t * node,nvlist_t * auth)2510eb822a1Scindi hc_prop_set(tnode_t *node, nvlist_t *auth)
2520eb822a1Scindi {
2530eb822a1Scindi 	int err;
2540eb822a1Scindi 	char isa[MAXNAMELEN];
2550eb822a1Scindi 	struct utsname uts;
2569c94f155SCheng Sean Ye 	char *prod, *psn, *csn, *server;
2570eb822a1Scindi 
2589dd0f810Scindi 	if (auth == NULL)
2599dd0f810Scindi 		return;
2609dd0f810Scindi 
2610eb822a1Scindi 	if (topo_pgroup_create(node, &auth_pgroup, &err) != 0) {
2620eb822a1Scindi 		if (err != ETOPO_PROP_DEFD)
2630eb822a1Scindi 			return;
2640eb822a1Scindi 	}
2650eb822a1Scindi 
2660eb822a1Scindi 	/*
2670eb822a1Scindi 	 * Inherit if we can, it saves memory
2680eb822a1Scindi 	 */
2692eeaed14Srobj 	if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT,
2702eeaed14Srobj 	    &err) != 0) && (err != ETOPO_PROP_DEFD)) {
2710eb822a1Scindi 		if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, &prod)
2720eb822a1Scindi 		    == 0)
2730eb822a1Scindi 			(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
2740eb822a1Scindi 			    FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod,
2750eb822a1Scindi 			    &err);
2760eb822a1Scindi 	}
2779c94f155SCheng Sean Ye 	if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT_SN,
2789c94f155SCheng Sean Ye 	    &err) != 0) && (err != ETOPO_PROP_DEFD)) {
2799c94f155SCheng Sean Ye 		if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN, &psn)
2809c94f155SCheng Sean Ye 		    == 0)
2819c94f155SCheng Sean Ye 			(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
2829c94f155SCheng Sean Ye 			    FM_FMRI_AUTH_PRODUCT_SN, TOPO_PROP_IMMUTABLE, psn,
2839c94f155SCheng Sean Ye 			    &err);
2849c94f155SCheng Sean Ye 	}
2852eeaed14Srobj 	if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS,
2862eeaed14Srobj 	    &err) != 0) && (err != ETOPO_PROP_DEFD)) {
2870eb822a1Scindi 		if (nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, &csn) == 0)
2880eb822a1Scindi 			(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
2890eb822a1Scindi 			    FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn,
2900eb822a1Scindi 			    &err);
2910eb822a1Scindi 	}
2922eeaed14Srobj 	if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_SERVER,
2932eeaed14Srobj 	    &err) != 0) && (err != ETOPO_PROP_DEFD)) {
2940eb822a1Scindi 		if (nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server)
2950eb822a1Scindi 		    == 0)
2960eb822a1Scindi 			(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
2970eb822a1Scindi 			    FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server,
2980eb822a1Scindi 			    &err);
2990eb822a1Scindi 	}
3000eb822a1Scindi 
3010eb822a1Scindi 	if (topo_pgroup_create(node, &sys_pgroup, &err) != 0)
3020eb822a1Scindi 		return;
3030eb822a1Scindi 
3040eb822a1Scindi 	isa[0] = '\0';
3050eb822a1Scindi 	(void) sysinfo(SI_ARCHITECTURE, isa, sizeof (isa));
3060eb822a1Scindi 	(void) uname(&uts);
3070eb822a1Scindi 	(void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
3080eb822a1Scindi 	    TOPO_PROP_IMMUTABLE, isa, &err);
3090eb822a1Scindi 	(void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE,
3100eb822a1Scindi 	    TOPO_PROP_IMMUTABLE, uts.machine, &err);
3117aec1d6eScindi }
3127aec1d6eScindi 
3137aec1d6eScindi /*ARGSUSED*/
3147aec1d6eScindi 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)3150eb822a1Scindi hc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min,
3169dd0f810Scindi     topo_instance_t max, void *notused1, void *notused2)
3177aec1d6eScindi {
318f6e214c7SGavin Maltby 	int isglobal = (getzoneid() == GLOBAL_ZONEID);
3197aec1d6eScindi 	nvlist_t *pfmri = NULL;
3207aec1d6eScindi 	nvlist_t *nvl;
3210eb822a1Scindi 	nvlist_t *auth;
3220eb822a1Scindi 	tnode_t *node;
3237aec1d6eScindi 	int err;
3247aec1d6eScindi 	/*
3257aec1d6eScindi 	 * Register root node methods
3267aec1d6eScindi 	 */
3277aec1d6eScindi 	if (strcmp(name, HC) == 0) {
3280eb822a1Scindi 		(void) topo_method_register(mod, pnode, hc_methods);
3297aec1d6eScindi 		return (0);
3307aec1d6eScindi 	}
3317aec1d6eScindi 	if (min != max) {
3320eb822a1Scindi 		topo_mod_dprintf(mod,
3337aec1d6eScindi 		    "Request to enumerate %s component with an "
3347aec1d6eScindi 		    "ambiguous instance number, min (%d) != max (%d).\n",
3357aec1d6eScindi 		    HC, min, max);
3360eb822a1Scindi 		return (topo_mod_seterrno(mod, EINVAL));
3377aec1d6eScindi 	}
3387aec1d6eScindi 
339f6e214c7SGavin Maltby 	if (!isglobal)
340f6e214c7SGavin Maltby 		return (0);
341f6e214c7SGavin Maltby 
3427aec1d6eScindi 	(void) topo_node_resource(pnode, &pfmri, &err);
3430eb822a1Scindi 	auth = topo_mod_auth(mod, pnode);
3440eb822a1Scindi 	nvl = hc_fmri_create(mod, pfmri, FM_HC_SCHEME_VERSION, name, min,
3450eb822a1Scindi 	    auth, NULL, NULL, NULL);
3467aec1d6eScindi 	nvlist_free(pfmri);	/* callee ignores NULLs */
3470eb822a1Scindi 	if (nvl == NULL) {
3480eb822a1Scindi 		nvlist_free(auth);
3497aec1d6eScindi 		return (-1);
3500eb822a1Scindi 	}
3517aec1d6eScindi 
3520eb822a1Scindi 	if ((node = topo_node_bind(mod, pnode, name, min, nvl)) == NULL) {
3530eb822a1Scindi 		topo_mod_dprintf(mod, "topo_node_bind failed: %s\n",
3540eb822a1Scindi 		    topo_strerror(topo_mod_errno(mod)));
3550eb822a1Scindi 		nvlist_free(auth);
3567aec1d6eScindi 		nvlist_free(nvl);
3577aec1d6eScindi 		return (-1);
3587aec1d6eScindi 	}
3590eb822a1Scindi 
36047911a7dScy152378 	/*
36147911a7dScy152378 	 * Set FRU for the motherboard node
36247911a7dScy152378 	 */
36347911a7dScy152378 	if (strcmp(name, MOTHERBOARD) == 0)
36447911a7dScy152378 		(void) topo_node_fru_set(node, nvl, 0, &err);
36547911a7dScy152378 
3660eb822a1Scindi 	hc_prop_set(node, auth);
3677aec1d6eScindi 	nvlist_free(nvl);
3680eb822a1Scindi 	nvlist_free(auth);
3690eb822a1Scindi 
3707aec1d6eScindi 	return (0);
3717aec1d6eScindi }
3727aec1d6eScindi 
3737aec1d6eScindi /*ARGSUSED*/
3747aec1d6eScindi static void
hc_release(topo_mod_t * mp,tnode_t * node)3757aec1d6eScindi hc_release(topo_mod_t *mp, tnode_t *node)
3767aec1d6eScindi {
3777aec1d6eScindi 	topo_method_unregister_all(mp, node);
3787aec1d6eScindi }
3797aec1d6eScindi 
3807aec1d6eScindi static int
fmri_compare(topo_mod_t * mod,nvlist_t * nv1,nvlist_t * nv2)381c40d7343Scindi fmri_compare(topo_mod_t *mod, nvlist_t *nv1, nvlist_t *nv2)
3827aec1d6eScindi {
3837aec1d6eScindi 	uint8_t v1, v2;
3847aec1d6eScindi 	nvlist_t **hcp1, **hcp2;
385825ba0f2Srobj 	nvlist_t *f1 = NULL, *f2 = NULL;
3867aec1d6eScindi 	int err, i;
3877aec1d6eScindi 	uint_t nhcp1, nhcp2;
388825ba0f2Srobj 	char *f1str, *f2str;
3897aec1d6eScindi 
3907aec1d6eScindi 	if (nvlist_lookup_uint8(nv1, FM_VERSION, &v1) != 0 ||
3917aec1d6eScindi 	    nvlist_lookup_uint8(nv2, FM_VERSION, &v2) != 0 ||
3927aec1d6eScindi 	    v1 > FM_HC_SCHEME_VERSION || v2 > FM_HC_SCHEME_VERSION)
3930eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_VERSION));
3947aec1d6eScindi 
3957aec1d6eScindi 	err = nvlist_lookup_nvlist_array(nv1, FM_FMRI_HC_LIST, &hcp1, &nhcp1);
3967aec1d6eScindi 	err |= nvlist_lookup_nvlist_array(nv2, FM_FMRI_HC_LIST, &hcp2, &nhcp2);
3977aec1d6eScindi 	if (err != 0)
3980eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
3997aec1d6eScindi 
4007aec1d6eScindi 	if (nhcp1 != nhcp2)
4017aec1d6eScindi 		return (0);
4027aec1d6eScindi 
4037aec1d6eScindi 	for (i = 0; i < nhcp1; i++) {
4047aec1d6eScindi 		char *nm1 = NULL;
4057aec1d6eScindi 		char *nm2 = NULL;
4067aec1d6eScindi 		char *id1 = NULL;
4077aec1d6eScindi 		char *id2 = NULL;
4087aec1d6eScindi 
4097aec1d6eScindi 		(void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_NAME, &nm1);
4107aec1d6eScindi 		(void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_NAME, &nm2);
4117aec1d6eScindi 		(void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_ID, &id1);
4127aec1d6eScindi 		(void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_ID, &id2);
4137aec1d6eScindi 		if (nm1 == NULL || nm2 == NULL || id1 == NULL || id2 == NULL)
4140eb822a1Scindi 			return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
4157aec1d6eScindi 
4167aec1d6eScindi 		if (strcmp(nm1, nm2) == 0 && strcmp(id1, id2) == 0)
4177aec1d6eScindi 			continue;
4187aec1d6eScindi 
4197aec1d6eScindi 		return (0);
4207aec1d6eScindi 	}
4217aec1d6eScindi 
422825ba0f2Srobj 	/*
423825ba0f2Srobj 	 * Finally, check if the FMRI's represent a facility node.  If so, then
424825ba0f2Srobj 	 * verify that the facilty type ("sensor"|"indicator") and facility
425825ba0f2Srobj 	 * name match.
426825ba0f2Srobj 	 */
427825ba0f2Srobj 	(void) nvlist_lookup_nvlist(nv1, FM_FMRI_FACILITY, &f1);
428825ba0f2Srobj 	(void) nvlist_lookup_nvlist(nv2, FM_FMRI_FACILITY, &f2);
429825ba0f2Srobj 
430825ba0f2Srobj 	if (f1 == NULL && f2 == NULL)
4317aec1d6eScindi 		return (1);
432825ba0f2Srobj 	else if (f1 == NULL || f2 == NULL)
433825ba0f2Srobj 		return (0);
434825ba0f2Srobj 
435825ba0f2Srobj 	if (nvlist_lookup_string(f1, FM_FMRI_FACILITY_NAME, &f1str) == 0 &&
436825ba0f2Srobj 	    nvlist_lookup_string(f2, FM_FMRI_FACILITY_NAME, &f2str) == 0 &&
437825ba0f2Srobj 	    strcmp(f1str, f2str) == 0 &&
438825ba0f2Srobj 	    nvlist_lookup_string(f1, FM_FMRI_FACILITY_TYPE, &f1str) == 0 &&
439825ba0f2Srobj 	    nvlist_lookup_string(f2, FM_FMRI_FACILITY_TYPE, &f2str) == 0 &&
440825ba0f2Srobj 	    strcmp(f1str, f2str) == 0) {
441825ba0f2Srobj 		return (1);
442825ba0f2Srobj 	}
443825ba0f2Srobj 	return (0);
4447aec1d6eScindi }
4457aec1d6eScindi 
446c40d7343Scindi /*ARGSUSED*/
447c40d7343Scindi static int
hc_compare(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)448c40d7343Scindi hc_compare(topo_mod_t *mod, tnode_t *node, topo_version_t version,
449c40d7343Scindi     nvlist_t *in, nvlist_t **out)
450c40d7343Scindi {
451c40d7343Scindi 	int ret;
452c40d7343Scindi 	uint32_t compare;
453c40d7343Scindi 	nvlist_t *nv1, *nv2;
454c40d7343Scindi 
455c40d7343Scindi 	if (version > TOPO_METH_COMPARE_VERSION)
456c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
457c40d7343Scindi 
458c40d7343Scindi 	if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV1, &nv1) != 0 ||
45912cc75c8Scindi 	    nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV2, &nv2) != 0)
460c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
461c40d7343Scindi 
462c40d7343Scindi 	ret = fmri_compare(mod, nv1, nv2);
463c40d7343Scindi 	if (ret < 0)
464c40d7343Scindi 		return (-1);
465c40d7343Scindi 
466c40d7343Scindi 	compare = ret;
467c40d7343Scindi 	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) == 0) {
468c40d7343Scindi 		if (nvlist_add_uint32(*out, TOPO_METH_COMPARE_RET,
469c40d7343Scindi 		    compare) == 0)
470c40d7343Scindi 			return (0);
471c40d7343Scindi 		else
472c40d7343Scindi 			nvlist_free(*out);
473c40d7343Scindi 	}
474c40d7343Scindi 
475c40d7343Scindi 	return (-1);
476c40d7343Scindi }
477c40d7343Scindi 
4787aec1d6eScindi static ssize_t
fmri_nvl2str(nvlist_t * nvl,char * buf,size_t buflen)4797aec1d6eScindi fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
4807aec1d6eScindi {
4817aec1d6eScindi 	nvlist_t **hcprs = NULL;
482e4b86885SCheng Sean Ye 	nvlist_t *hcsp = NULL;
4837aec1d6eScindi 	nvlist_t *anvl = NULL;
4849c94f155SCheng Sean Ye 	nvpair_t *apair;
485825ba0f2Srobj 	nvlist_t *fnvl;
4867aec1d6eScindi 	uint8_t version;
4877aec1d6eScindi 	ssize_t size = 0;
4887aec1d6eScindi 	uint_t hcnprs;
4897aec1d6eScindi 	char *serial = NULL;
4907aec1d6eScindi 	char *part = NULL;
4917aec1d6eScindi 	char *root = NULL;
4927aec1d6eScindi 	char *rev = NULL;
4939c94f155SCheng Sean Ye 	char *aname, *aval;
494825ba0f2Srobj 	char *fname = NULL, *ftype = NULL;
4957aec1d6eScindi 	int err, i;
4967aec1d6eScindi 
4977aec1d6eScindi 	if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
4987aec1d6eScindi 	    version > FM_HC_SCHEME_VERSION)
499f5961f52SAdrian Frost 		return (0);
5007aec1d6eScindi 
5017aec1d6eScindi 	/* Get authority, if present */
5027aec1d6eScindi 	err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl);
5037aec1d6eScindi 	if (err != 0 && err != ENOENT)
504f5961f52SAdrian Frost 		return (0);
5057aec1d6eScindi 
506f5961f52SAdrian Frost 	(void) nvlist_lookup_string(nvl, FM_FMRI_HC_ROOT, &root);
5077aec1d6eScindi 
5087aec1d6eScindi 	err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs);
5097aec1d6eScindi 	if (err != 0 || hcprs == NULL)
510f5961f52SAdrian Frost 		return (0);
5117aec1d6eScindi 
5127aec1d6eScindi 	(void) nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &serial);
5137aec1d6eScindi 	(void) nvlist_lookup_string(nvl, FM_FMRI_HC_PART, &part);
5147aec1d6eScindi 	(void) nvlist_lookup_string(nvl, FM_FMRI_HC_REVISION, &rev);
5157aec1d6eScindi 
5167aec1d6eScindi 	/* hc:// */
51774a31ce6Stimh 	topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_HC, NULL, "://");
5187aec1d6eScindi 
5197aec1d6eScindi 	/* authority, if any */
5209c94f155SCheng Sean Ye 	if (anvl != NULL) {
5219c94f155SCheng Sean Ye 		for (apair = nvlist_next_nvpair(anvl, NULL);
5229c94f155SCheng Sean Ye 		    apair != NULL; apair = nvlist_next_nvpair(anvl, apair)) {
5239c94f155SCheng Sean Ye 			if (nvpair_type(apair) != DATA_TYPE_STRING ||
5249c94f155SCheng Sean Ye 			    nvpair_value_string(apair, &aval) != 0)
5259c94f155SCheng Sean Ye 				continue;
5269c94f155SCheng Sean Ye 			aname = nvpair_name(apair);
5279c94f155SCheng Sean Ye 			topo_fmristr_build(&size, buf, buflen, ":", NULL, NULL);
5289c94f155SCheng Sean Ye 			topo_fmristr_build(&size, buf, buflen, "=",
5299c94f155SCheng Sean Ye 			    aname, aval);
5309c94f155SCheng Sean Ye 		}
5319c94f155SCheng Sean Ye 	}
5327aec1d6eScindi 
5337aec1d6eScindi 	/* hardware-id part */
53474a31ce6Stimh 	topo_fmristr_build(&size,
53574a31ce6Stimh 	    buf, buflen, serial, ":" FM_FMRI_HC_SERIAL_ID "=", NULL);
53674a31ce6Stimh 	topo_fmristr_build(&size,
53774a31ce6Stimh 	    buf, buflen, part, ":" FM_FMRI_HC_PART "=", NULL);
53874a31ce6Stimh 	topo_fmristr_build(&size,
53974a31ce6Stimh 	    buf, buflen, rev, ":" FM_FMRI_HC_REVISION "=", NULL);
5407aec1d6eScindi 
5417aec1d6eScindi 	/* separating slash */
54274a31ce6Stimh 	topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL);
5437aec1d6eScindi 
5447aec1d6eScindi 	/* hc-root */
545f5961f52SAdrian Frost 	if (root)
54674a31ce6Stimh 		topo_fmristr_build(&size, buf, buflen, root, NULL, NULL);
5477aec1d6eScindi 
5487aec1d6eScindi 	/* all the pairs */
5497aec1d6eScindi 	for (i = 0; i < hcnprs; i++) {
5507aec1d6eScindi 		char *nm = NULL;
5517aec1d6eScindi 		char *id = NULL;
5527aec1d6eScindi 
5537aec1d6eScindi 		if (i > 0)
55474a31ce6Stimh 			topo_fmristr_build(&size,
55574a31ce6Stimh 			    buf, buflen, "/", NULL, NULL);
5567aec1d6eScindi 		(void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_NAME, &nm);
5577aec1d6eScindi 		(void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_ID, &id);
5587aec1d6eScindi 		if (nm == NULL || id == NULL)
5597aec1d6eScindi 			return (0);
56074a31ce6Stimh 		topo_fmristr_build(&size, buf, buflen, nm, NULL, "=");
56174a31ce6Stimh 		topo_fmristr_build(&size, buf, buflen, id, NULL, NULL);
5627aec1d6eScindi 	}
5637aec1d6eScindi 
564e4b86885SCheng Sean Ye 	/* append offset/physaddr if it exists in hc-specific */
565e4b86885SCheng Sean Ye 	if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) {
566e4b86885SCheng Sean Ye 		char *hcsn = NULL;
567e4b86885SCheng Sean Ye 		char hexstr[17];
568e4b86885SCheng Sean Ye 		uint64_t val;
569e4b86885SCheng Sean Ye 
570e4b86885SCheng Sean Ye 		if (nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET,
571e4b86885SCheng Sean Ye 		    &val) == 0 || nvlist_lookup_uint64(hcsp,
572e4b86885SCheng Sean Ye 		    "asru-" FM_FMRI_HC_SPECIFIC_OFFSET, &val) == 0)
573e4b86885SCheng Sean Ye 			hcsn = FM_FMRI_HC_SPECIFIC_OFFSET;
574e4b86885SCheng Sean Ye 		else if (nvlist_lookup_uint64(hcsp,
575e4b86885SCheng Sean Ye 		    FM_FMRI_HC_SPECIFIC_PHYSADDR, &val) == 0 ||
576e4b86885SCheng Sean Ye 		    nvlist_lookup_uint64(hcsp,
577e4b86885SCheng Sean Ye 		    "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR, &val) == 0)
578e4b86885SCheng Sean Ye 			hcsn = FM_FMRI_HC_SPECIFIC_PHYSADDR;
579e4b86885SCheng Sean Ye 
580e4b86885SCheng Sean Ye 		if (hcsn != NULL) {
581e4b86885SCheng Sean Ye 			(void) snprintf(hexstr, sizeof (hexstr), "%llx", val);
582e4b86885SCheng Sean Ye 			topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL);
583e4b86885SCheng Sean Ye 			topo_fmristr_build(&size, buf, buflen, "=", hcsn,
584e4b86885SCheng Sean Ye 			    hexstr);
585e4b86885SCheng Sean Ye 		}
586e4b86885SCheng Sean Ye 	}
587e4b86885SCheng Sean Ye 
588825ba0f2Srobj 	/*
589825ba0f2Srobj 	 * If the nvlist represents a facility node, then we append the
590825ba0f2Srobj 	 * facility type and name to the end of the string representation using
591825ba0f2Srobj 	 * the format below:
592825ba0f2Srobj 	 *
593825ba0f2Srobj 	 * ?<ftype>=<fname>
594825ba0f2Srobj 	 */
595825ba0f2Srobj 	if (nvlist_lookup_nvlist(nvl, FM_FMRI_FACILITY, &fnvl) == 0) {
596825ba0f2Srobj 		if (nvlist_lookup_string(fnvl, FM_FMRI_FACILITY_NAME,
597825ba0f2Srobj 		    &fname) != 0 || nvlist_lookup_string(fnvl,
598825ba0f2Srobj 		    FM_FMRI_FACILITY_TYPE, &ftype) != 0)
599825ba0f2Srobj 			return (0);
600825ba0f2Srobj 		topo_fmristr_build(&size, buf, buflen, "?", NULL, NULL);
601825ba0f2Srobj 		topo_fmristr_build(&size, buf, buflen, "=", ftype, fname);
602825ba0f2Srobj 	}
603825ba0f2Srobj 
6047aec1d6eScindi 	return (size);
6057aec1d6eScindi }
6067aec1d6eScindi 
6077aec1d6eScindi /*ARGSUSED*/
6087aec1d6eScindi static int
hc_fmri_nvl2str(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * nvl,nvlist_t ** out)6097aec1d6eScindi hc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version,
6107aec1d6eScindi     nvlist_t *nvl, nvlist_t **out)
6117aec1d6eScindi {
6127aec1d6eScindi 	ssize_t len;
6137aec1d6eScindi 	char *name = NULL;
6147aec1d6eScindi 	nvlist_t *fmristr;
6157aec1d6eScindi 
6167aec1d6eScindi 	if (version > TOPO_METH_NVL2STR_VERSION)
6177aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
6187aec1d6eScindi 
6197aec1d6eScindi 	if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 ||
6207aec1d6eScindi 	    (name = topo_mod_alloc(mod, len + 1)) == NULL ||
6217aec1d6eScindi 	    fmri_nvl2str(nvl, name, len + 1) == 0) {
6227aec1d6eScindi 		if (name != NULL)
6237aec1d6eScindi 			topo_mod_free(mod, name, len + 1);
6247aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
6257aec1d6eScindi 	}
6267aec1d6eScindi 
62712cc75c8Scindi 	if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) {
62812cc75c8Scindi 		topo_mod_free(mod, name, len + 1);
6297aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
63012cc75c8Scindi 	}
6317aec1d6eScindi 	if (nvlist_add_string(fmristr, "fmri-string", name) != 0) {
6327aec1d6eScindi 		topo_mod_free(mod, name, len + 1);
6337aec1d6eScindi 		nvlist_free(fmristr);
6347aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
6357aec1d6eScindi 	}
6367aec1d6eScindi 	topo_mod_free(mod, name, len + 1);
6377aec1d6eScindi 	*out = fmristr;
6387aec1d6eScindi 
6397aec1d6eScindi 	return (0);
6407aec1d6eScindi }
6417aec1d6eScindi 
6427aec1d6eScindi static nvlist_t *
hc_base_fmri_create(topo_mod_t * mod,const nvlist_t * auth,const char * part,const char * rev,const char * serial)6437aec1d6eScindi hc_base_fmri_create(topo_mod_t *mod, const nvlist_t *auth, const char *part,
6447aec1d6eScindi     const char *rev, const char *serial)
6457aec1d6eScindi {
6467aec1d6eScindi 	nvlist_t *fmri;
6477aec1d6eScindi 	int err = 0;
6487aec1d6eScindi 
6497aec1d6eScindi 	/*
6507aec1d6eScindi 	 * Create base HC nvlist
6517aec1d6eScindi 	 */
6527aec1d6eScindi 	if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0)
6537aec1d6eScindi 		return (NULL);
6547aec1d6eScindi 
6557aec1d6eScindi 	err = nvlist_add_uint8(fmri, FM_VERSION, FM_HC_SCHEME_VERSION);
6567aec1d6eScindi 	err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC);
6577aec1d6eScindi 	err |= nvlist_add_string(fmri, FM_FMRI_HC_ROOT, "");
6587aec1d6eScindi 	if (err != 0) {
6597aec1d6eScindi 		nvlist_free(fmri);
6607aec1d6eScindi 		return (NULL);
6617aec1d6eScindi 	}
6627aec1d6eScindi 
6637aec1d6eScindi 	/*
6647aec1d6eScindi 	 * Add optional payload members
6657aec1d6eScindi 	 */
6667aec1d6eScindi 	if (serial != NULL)
6677aec1d6eScindi 		(void) nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID, serial);
6687aec1d6eScindi 	if (part != NULL)
6697aec1d6eScindi 		(void) nvlist_add_string(fmri, FM_FMRI_HC_PART, part);
6707aec1d6eScindi 	if (rev != NULL)
6717aec1d6eScindi 		(void) nvlist_add_string(fmri, FM_FMRI_HC_REVISION, rev);
6727aec1d6eScindi 	if (auth != NULL)
6737aec1d6eScindi 		(void) nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
6747aec1d6eScindi 		    (nvlist_t *)auth);
6757aec1d6eScindi 
6767aec1d6eScindi 	return (fmri);
6777aec1d6eScindi }
6787aec1d6eScindi 
6797aec1d6eScindi static nvlist_t **
make_hc_pairs(topo_mod_t * mod,char * fmri,int * num)6800eb822a1Scindi make_hc_pairs(topo_mod_t *mod, char *fmri, int *num)
6817aec1d6eScindi {
6827aec1d6eScindi 	nvlist_t **pa;
6830eb822a1Scindi 	char *hc, *fromstr;
6847aec1d6eScindi 	char *starti, *startn, *endi, *endi2;
6857aec1d6eScindi 	char *ne, *ns;
686c40d7343Scindi 	char *cname = NULL;
6877aec1d6eScindi 	char *find;
688c40d7343Scindi 	char *cid = NULL;
6897aec1d6eScindi 	int nslashes = 0;
6907aec1d6eScindi 	int npairs = 0;
69112cc75c8Scindi 	int i, hclen;
6927aec1d6eScindi 
6930eb822a1Scindi 	if ((hc = topo_mod_strdup(mod, fmri + 5)) == NULL)
6940eb822a1Scindi 		return (NULL);
6950eb822a1Scindi 
69612cc75c8Scindi 	hclen = strlen(hc) + 1;
69712cc75c8Scindi 
6987aec1d6eScindi 	/*
6997aec1d6eScindi 	 * Count equal signs and slashes to determine how many
7007aec1d6eScindi 	 * hc-pairs will be present in the final FMRI.  There should
7017aec1d6eScindi 	 * be at least as many slashes as equal signs.  There can be
7027aec1d6eScindi 	 * more, though if the string after an = includes them.
7037aec1d6eScindi 	 */
7040eb822a1Scindi 	if ((fromstr = strchr(hc, '/')) == NULL)
7050eb822a1Scindi 		return (NULL);
7060eb822a1Scindi 
7077aec1d6eScindi 	find = fromstr;
7087aec1d6eScindi 	while ((ne = strchr(find, '=')) != NULL) {
7097aec1d6eScindi 		find = ne + 1;
7107aec1d6eScindi 		npairs++;
7117aec1d6eScindi 	}
7127aec1d6eScindi 
7137aec1d6eScindi 	find = fromstr;
7147aec1d6eScindi 	while ((ns = strchr(find, '/')) != NULL) {
7157aec1d6eScindi 		find = ns + 1;
7167aec1d6eScindi 		nslashes++;
7177aec1d6eScindi 	}
7187aec1d6eScindi 
7197aec1d6eScindi 	/*
7207aec1d6eScindi 	 * Do we appear to have a well-formed string version of the FMRI?
7217aec1d6eScindi 	 */
7220eb822a1Scindi 	if (nslashes < npairs || npairs == 0) {
72312cc75c8Scindi 		topo_mod_free(mod, hc, hclen);
7247aec1d6eScindi 		return (NULL);
7250eb822a1Scindi 	}
7267aec1d6eScindi 
7277aec1d6eScindi 	*num = npairs;
7287aec1d6eScindi 
7297aec1d6eScindi 	find = fromstr;
7307aec1d6eScindi 
73112cc75c8Scindi 	if ((pa = topo_mod_zalloc(mod, npairs * sizeof (nvlist_t *))) == NULL) {
73212cc75c8Scindi 		topo_mod_free(mod, hc, hclen);
733c40d7343Scindi 		return (NULL);
734c40d7343Scindi 	}
735c40d7343Scindi 
7367aec1d6eScindi 	/*
7377aec1d6eScindi 	 * We go through a pretty complicated procedure to find the
7387aec1d6eScindi 	 * name and id for each pair.  That's because, unfortunately,
7397aec1d6eScindi 	 * we have some ids that can have slashes within them.  So
7407aec1d6eScindi 	 * we can't just search for the next slash after the equal sign
7417aec1d6eScindi 	 * and decide that starts a new pair.  Instead we have to find
7427aec1d6eScindi 	 * an equal sign for the next pair and work our way back to the
7437aec1d6eScindi 	 * slash from there.
7447aec1d6eScindi 	 */
7457aec1d6eScindi 	for (i = 0; i < npairs; i++) {
7467aec1d6eScindi 		startn = strchr(find, '/');
7477aec1d6eScindi 		if (startn == NULL)
7487aec1d6eScindi 			break;
7497aec1d6eScindi 		startn++;
7507aec1d6eScindi 		starti = strchr(find, '=');
7517aec1d6eScindi 		if (starti == NULL)
7527aec1d6eScindi 			break;
7537aec1d6eScindi 		*starti = '\0';
754c40d7343Scindi 		if ((cname = topo_mod_strdup(mod, startn)) == NULL)
755c40d7343Scindi 			break;
7567aec1d6eScindi 		*starti++ = '=';
7577aec1d6eScindi 		endi = strchr(starti, '=');
7587aec1d6eScindi 		if (endi != NULL) {
7597aec1d6eScindi 			*endi = '\0';
7607aec1d6eScindi 			endi2 = strrchr(starti, '/');
7617aec1d6eScindi 			if (endi2 == NULL)
7627aec1d6eScindi 				break;
7637aec1d6eScindi 			*endi = '=';
7647aec1d6eScindi 			*endi2 = '\0';
765c40d7343Scindi 			if ((cid = topo_mod_strdup(mod, starti)) == NULL)
766c40d7343Scindi 				break;
7677aec1d6eScindi 			*endi2 = '/';
7687aec1d6eScindi 			find = endi2;
7697aec1d6eScindi 		} else {
770c40d7343Scindi 			if ((cid = topo_mod_strdup(mod, starti)) == NULL)
771c40d7343Scindi 				break;
7727aec1d6eScindi 			find = starti + strlen(starti);
7737aec1d6eScindi 		}
774c40d7343Scindi 		if (topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME) < 0)
775c40d7343Scindi 			break;
776c40d7343Scindi 
777c40d7343Scindi 		if (nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname) ||
778c40d7343Scindi 		    nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid))
779c40d7343Scindi 			break;
780c40d7343Scindi 
7817aec1d6eScindi 		topo_mod_strfree(mod, cname);
7827aec1d6eScindi 		topo_mod_strfree(mod, cid);
783c40d7343Scindi 		cname = NULL;
784c40d7343Scindi 		cid = NULL;
7857aec1d6eScindi 	}
7867aec1d6eScindi 
7877aec1d6eScindi 	topo_mod_strfree(mod, cname);
7887aec1d6eScindi 	topo_mod_strfree(mod, cid);
7897aec1d6eScindi 
7907aec1d6eScindi 	if (i < npairs) {
79112cc75c8Scindi 		for (i = 0; i < npairs; i++)
79212cc75c8Scindi 			nvlist_free(pa[i]);
7937aec1d6eScindi 		topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *));
79412cc75c8Scindi 		topo_mod_free(mod, hc, hclen);
7957aec1d6eScindi 		return (NULL);
7967aec1d6eScindi 	}
7977aec1d6eScindi 
79812cc75c8Scindi 	topo_mod_free(mod, hc, hclen);
7990eb822a1Scindi 
8007aec1d6eScindi 	return (pa);
8017aec1d6eScindi }
8027aec1d6eScindi 
803825ba0f2Srobj int
make_hc_auth(topo_mod_t * mod,char * fmri,char ** serial,char ** part,char ** rev,nvlist_t ** auth)8040eb822a1Scindi make_hc_auth(topo_mod_t *mod, char *fmri, char **serial, char **part,
8050eb822a1Scindi     char **rev, nvlist_t **auth)
8060eb822a1Scindi {
8070eb822a1Scindi 	char *starti, *startn, *endi, *copy;
808825ba0f2Srobj 	char *aname = NULL, *aid = NULL, *fs;
8090eb822a1Scindi 	nvlist_t *na = NULL;
8100eb822a1Scindi 	size_t len;
8110eb822a1Scindi 
8120eb822a1Scindi 	if ((copy = topo_mod_strdup(mod, fmri + 5)) == NULL)
813825ba0f2Srobj 		return (-1);
8140eb822a1Scindi 
8150eb822a1Scindi 	len = strlen(copy);
8160eb822a1Scindi 
8170eb822a1Scindi 	/*
8180eb822a1Scindi 	 * Make sure there are a valid authority members
8190eb822a1Scindi 	 */
8200eb822a1Scindi 	startn = strchr(copy, ':');
8210eb822a1Scindi 	fs = strchr(copy, '/');
8220eb822a1Scindi 
8230eb822a1Scindi 	if (startn == NULL || fs == NULL) {
8240eb822a1Scindi 		topo_mod_strfree(mod, copy);
825825ba0f2Srobj 		return (0);
8260eb822a1Scindi 	}
8270eb822a1Scindi 
8280eb822a1Scindi 	/*
8290eb822a1Scindi 	 * The first colon we encounter must occur before the
8300eb822a1Scindi 	 * first slash
8310eb822a1Scindi 	 */
8320eb822a1Scindi 	if (startn > fs)
833825ba0f2Srobj 		goto hcabail;
8340eb822a1Scindi 
8350eb822a1Scindi 	do {
8360eb822a1Scindi 		if (++startn >= copy + len)
8370eb822a1Scindi 			break;
8380eb822a1Scindi 
8390eb822a1Scindi 		if ((starti = strchr(startn, '=')) == NULL)
840825ba0f2Srobj 			goto hcabail;
8410eb822a1Scindi 
8420eb822a1Scindi 		*starti = '\0';
8430eb822a1Scindi 		if (++starti > copy + len)
844825ba0f2Srobj 			goto hcabail;
8450eb822a1Scindi 
8460eb822a1Scindi 		if ((aname = topo_mod_strdup(mod, startn)) == NULL)
847825ba0f2Srobj 			goto hcabail;
8480eb822a1Scindi 
8490eb822a1Scindi 		startn = endi = strchr(starti, ':');
8500eb822a1Scindi 		if (endi == NULL)
8510eb822a1Scindi 			if ((endi = strchr(starti, '/')) == NULL)
8520eb822a1Scindi 				break;
8530eb822a1Scindi 
8540eb822a1Scindi 		*endi = '\0';
855825ba0f2Srobj 		if ((aid = topo_mod_strdup(mod, starti)) == NULL)
856825ba0f2Srobj 			goto hcabail;
8570eb822a1Scindi 
8580eb822a1Scindi 		/*
8590eb822a1Scindi 		 * Return possible serial, part and revision
8600eb822a1Scindi 		 */
8610eb822a1Scindi 		if (strcmp(aname, FM_FMRI_HC_SERIAL_ID) == 0) {
86214ea4bb7Ssd77468 			*serial = topo_mod_strdup(mod, aid);
8630eb822a1Scindi 		} else if (strcmp(aname, FM_FMRI_HC_PART) == 0) {
86414ea4bb7Ssd77468 			*part = topo_mod_strdup(mod, aid);
8650eb822a1Scindi 		} else if (strcmp(aname, FM_FMRI_HC_REVISION) == 0) {
86614ea4bb7Ssd77468 			*rev = topo_mod_strdup(mod, aid);
8670eb822a1Scindi 		} else {
8680eb822a1Scindi 			if (na == NULL) {
8690eb822a1Scindi 				if (topo_mod_nvalloc(mod, &na,
8700eb822a1Scindi 				    NV_UNIQUE_NAME) == 0) {
87124db4641Seschrock 					(void) nvlist_add_string(na, aname,
87224db4641Seschrock 					    aid);
8730eb822a1Scindi 				}
8740eb822a1Scindi 			} else {
8750eb822a1Scindi 				(void) nvlist_add_string(na, aname, aid);
8760eb822a1Scindi 			}
8770eb822a1Scindi 		}
8780eb822a1Scindi 		topo_mod_strfree(mod, aname);
8790eb822a1Scindi 		topo_mod_strfree(mod, aid);
880825ba0f2Srobj 		aname = aid = NULL;
8810eb822a1Scindi 
8820eb822a1Scindi 	} while (startn != NULL);
8830eb822a1Scindi 
8840eb822a1Scindi 	*auth = na;
8850eb822a1Scindi 
8860eb822a1Scindi 	topo_mod_free(mod, copy, len + 1);
887825ba0f2Srobj 	return (0);
888825ba0f2Srobj 
889825ba0f2Srobj hcabail:
890825ba0f2Srobj 	topo_mod_free(mod, copy, len + 1);
891825ba0f2Srobj 	topo_mod_strfree(mod, aname);
892825ba0f2Srobj 	topo_mod_strfree(mod, aid);
893825ba0f2Srobj 	nvlist_free(na);
894825ba0f2Srobj 	return (-1);
895825ba0f2Srobj }
896825ba0f2Srobj 
897825ba0f2Srobj 
898825ba0f2Srobj /*
899825ba0f2Srobj  * This function creates an nvlist to represent the facility portion of an
900825ba0f2Srobj  * hc-scheme node, given a string representation of the fmri.  This is called by
901825ba0f2Srobj  * hc_fmri_str2nvl.  If the string does not contain a facility component
902825ba0f2Srobj  * (e.g. ?<ftype>=<fname>) then it bails early and returns 0.
903825ba0f2Srobj  *
904825ba0f2Srobj  * On failure it returns -1 and sets the topo mod errno
905825ba0f2Srobj  */
906825ba0f2Srobj int
make_facility(topo_mod_t * mod,char * str,nvlist_t ** nvl)907825ba0f2Srobj make_facility(topo_mod_t *mod, char *str, nvlist_t **nvl)
908825ba0f2Srobj {
909825ba0f2Srobj 	char *fac, *copy, *fname, *ftype;
910825ba0f2Srobj 	nvlist_t *nf = NULL;
911825ba0f2Srobj 	size_t len;
912825ba0f2Srobj 
913825ba0f2Srobj 	if ((fac = strchr(str, '?')) == NULL)
914825ba0f2Srobj 		return (0);
915825ba0f2Srobj 
916825ba0f2Srobj 	++fac;
917825ba0f2Srobj 	if ((copy = topo_mod_strdup(mod, fac)) == NULL)
918825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
919825ba0f2Srobj 
920825ba0f2Srobj 	fac = copy;
921825ba0f2Srobj 	len = strlen(fac);
922825ba0f2Srobj 
923825ba0f2Srobj 	if ((fname = strchr(fac, '=')) == NULL) {
924825ba0f2Srobj 		topo_mod_free(mod, copy, len + 1);
925825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
926825ba0f2Srobj 	}
927825ba0f2Srobj 
928825ba0f2Srobj 	fname[0] = '\0';
929825ba0f2Srobj 	++fname;
930825ba0f2Srobj 	ftype = fac;
931825ba0f2Srobj 
932825ba0f2Srobj 	if (topo_mod_nvalloc(mod, &nf, NV_UNIQUE_NAME) != 0) {
933825ba0f2Srobj 		topo_mod_free(mod, copy, len + 1);
934825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
935825ba0f2Srobj 	}
936825ba0f2Srobj 
937825ba0f2Srobj 	if (nvlist_add_string(nf, FM_FMRI_FACILITY_NAME, fname) != 0 ||
938825ba0f2Srobj 	    nvlist_add_string(nf, FM_FMRI_FACILITY_TYPE, ftype) != 0) {
939825ba0f2Srobj 		topo_mod_free(mod, copy, len + 1);
940825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
941825ba0f2Srobj 	}
942825ba0f2Srobj 
943825ba0f2Srobj 	topo_mod_free(mod, copy, len + 1);
944825ba0f2Srobj 
945825ba0f2Srobj 	*nvl = nf;
946825ba0f2Srobj 
947825ba0f2Srobj 	return (0);
9480eb822a1Scindi }
9490eb822a1Scindi 
9507aec1d6eScindi /*ARGSUSED*/
9517aec1d6eScindi static int
hc_fmri_str2nvl(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)9527aec1d6eScindi hc_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version,
9537aec1d6eScindi     nvlist_t *in, nvlist_t **out)
9547aec1d6eScindi {
9557aec1d6eScindi 	nvlist_t **pa = NULL;
9567aec1d6eScindi 	nvlist_t *nf = NULL;
9570eb822a1Scindi 	nvlist_t *auth = NULL;
958825ba0f2Srobj 	nvlist_t *fac = NULL;
9590eb822a1Scindi 	char *str;
960e4b86885SCheng Sean Ye 	char *serial = NULL, *part = NULL, *rev = NULL, *hcsn = NULL;
961e4b86885SCheng Sean Ye 	int npairs, n;
9627aec1d6eScindi 	int i, e;
9637aec1d6eScindi 
9647aec1d6eScindi 	if (version > TOPO_METH_STR2NVL_VERSION)
9657aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
9667aec1d6eScindi 
9677aec1d6eScindi 	if (nvlist_lookup_string(in, "fmri-string", &str) != 0)
9687aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
9697aec1d6eScindi 
9707aec1d6eScindi 	/* We're expecting a string version of an hc scheme FMRI */
9710eb822a1Scindi 	if (strncmp(str, "hc://", 5) != 0)
9727aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
9737aec1d6eScindi 
9740eb822a1Scindi 	if ((pa = make_hc_pairs(mod, str, &npairs)) == NULL)
9757aec1d6eScindi 		return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
9767aec1d6eScindi 
977825ba0f2Srobj 	if (make_hc_auth(mod, str, &serial, &part, &rev, &auth) < 0)
978825ba0f2Srobj 		goto hcfmbail;
979825ba0f2Srobj 
9800eb822a1Scindi 	if ((nf = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL)
9817aec1d6eScindi 		goto hcfmbail;
982e4b86885SCheng Sean Ye 
983e4b86885SCheng Sean Ye 	n = npairs;
984e4b86885SCheng Sean Ye 
985e4b86885SCheng Sean Ye 	/*
986e4b86885SCheng Sean Ye 	 * If the last pair in hc-list is offset or physaddr, we move
987e4b86885SCheng Sean Ye 	 * it to hc-specific.
988e4b86885SCheng Sean Ye 	 */
989e4b86885SCheng Sean Ye 	(void) nvlist_lookup_string(pa[npairs - 1], FM_FMRI_HC_NAME, &hcsn);
990e4b86885SCheng Sean Ye 	if (strcmp(hcsn, FM_FMRI_HC_SPECIFIC_OFFSET) == 0 ||
991e4b86885SCheng Sean Ye 	    strcmp(hcsn, FM_FMRI_HC_SPECIFIC_PHYSADDR) == 0) {
992e4b86885SCheng Sean Ye 		char *hcid;
993e4b86885SCheng Sean Ye 		nvlist_t *hcsp;
994e4b86885SCheng Sean Ye 		uint64_t val;
995e4b86885SCheng Sean Ye 
996e4b86885SCheng Sean Ye 		(void) nvlist_lookup_string(pa[npairs - 1], FM_FMRI_HC_ID,
997e4b86885SCheng Sean Ye 		    &hcid);
9981db96d3bSCheng Sean Ye 		val = strtoull(hcid, NULL, 16);
999e4b86885SCheng Sean Ye 		if (topo_mod_nvalloc(mod, &hcsp, NV_UNIQUE_NAME) != 0)
1000e4b86885SCheng Sean Ye 			goto hcfmbail;
1001e4b86885SCheng Sean Ye 		if (nvlist_add_uint64(hcsp, hcsn, val) != 0 ||
1002e4b86885SCheng Sean Ye 		    nvlist_add_nvlist(nf, FM_FMRI_HC_SPECIFIC, hcsp) != 0) {
1003e4b86885SCheng Sean Ye 			nvlist_free(hcsp);
1004e4b86885SCheng Sean Ye 			goto hcfmbail;
1005e4b86885SCheng Sean Ye 		}
1006e4b86885SCheng Sean Ye 
1007e4b86885SCheng Sean Ye 		nvlist_free(hcsp);
1008e4b86885SCheng Sean Ye 		n--;
1009e4b86885SCheng Sean Ye 	}
1010e4b86885SCheng Sean Ye 
1011e4b86885SCheng Sean Ye 	if ((e = nvlist_add_uint32(nf, FM_FMRI_HC_LIST_SZ, n)) == 0)
1012e4b86885SCheng Sean Ye 		e = nvlist_add_nvlist_array(nf, FM_FMRI_HC_LIST, pa, n);
10137aec1d6eScindi 	if (e != 0) {
10147aec1d6eScindi 		topo_mod_dprintf(mod, "construction of new hc nvl failed");
10157aec1d6eScindi 		goto hcfmbail;
10167aec1d6eScindi 	}
1017825ba0f2Srobj 
1018825ba0f2Srobj 	/*
1019825ba0f2Srobj 	 * Clean-up
1020825ba0f2Srobj 	 */
10217aec1d6eScindi 	for (i = 0; i < npairs; i++)
10227aec1d6eScindi 		nvlist_free(pa[i]);
10237aec1d6eScindi 	topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *));
10240eb822a1Scindi 	topo_mod_strfree(mod, serial);
10250eb822a1Scindi 	topo_mod_strfree(mod, part);
10260eb822a1Scindi 	topo_mod_strfree(mod, rev);
10270eb822a1Scindi 	nvlist_free(auth);
10280eb822a1Scindi 
1029825ba0f2Srobj 	if (make_facility(mod, str, &fac) == -1)
1030825ba0f2Srobj 		goto hcfmbail;
1031825ba0f2Srobj 
1032825ba0f2Srobj 	if (fac != NULL) {
1033825ba0f2Srobj 		if (nvlist_add_nvlist(nf, FM_FMRI_FACILITY, fac) != 0)
1034825ba0f2Srobj 			goto hcfmbail;
1035825ba0f2Srobj 	}
1036825ba0f2Srobj 
10377aec1d6eScindi 	*out = nf;
10387aec1d6eScindi 
10397aec1d6eScindi 	return (0);
10407aec1d6eScindi 
10417aec1d6eScindi hcfmbail:
10427aec1d6eScindi 	nvlist_free(nf);
10437aec1d6eScindi 	for (i = 0; i < npairs; i++)
10447aec1d6eScindi 		nvlist_free(pa[i]);
10457aec1d6eScindi 	topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *));
1046825ba0f2Srobj 
10470eb822a1Scindi 	topo_mod_strfree(mod, serial);
10480eb822a1Scindi 	topo_mod_strfree(mod, part);
10490eb822a1Scindi 	topo_mod_strfree(mod, rev);
10500eb822a1Scindi 	nvlist_free(auth);
1051825ba0f2Srobj 	nvlist_free(nf);
10527aec1d6eScindi 	return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
10537aec1d6eScindi }
10547aec1d6eScindi 
10557aec1d6eScindi static nvlist_t *
hc_list_create(topo_mod_t * mod,const char * name,char * inst)10567aec1d6eScindi hc_list_create(topo_mod_t *mod, const char *name, char *inst)
10577aec1d6eScindi {
10587aec1d6eScindi 	int err;
10597aec1d6eScindi 	nvlist_t *hc;
10607aec1d6eScindi 
10617aec1d6eScindi 	if (topo_mod_nvalloc(mod, &hc, NV_UNIQUE_NAME) != 0)
10627aec1d6eScindi 		return (NULL);
10637aec1d6eScindi 
10647aec1d6eScindi 	err = nvlist_add_string(hc, FM_FMRI_HC_NAME, name);
10657aec1d6eScindi 	err |= nvlist_add_string(hc, FM_FMRI_HC_ID, inst);
10667aec1d6eScindi 	if (err != 0) {
10677aec1d6eScindi 		nvlist_free(hc);
10687aec1d6eScindi 		return (NULL);
10697aec1d6eScindi 	}
10707aec1d6eScindi 
10717aec1d6eScindi 	return (hc);
10727aec1d6eScindi }
10737aec1d6eScindi 
10747aec1d6eScindi static nvlist_t *
hc_create_seterror(topo_mod_t * mod,nvlist_t ** hcl,int n,nvlist_t * fmri,int err)10757aec1d6eScindi hc_create_seterror(topo_mod_t *mod, nvlist_t **hcl, int n, nvlist_t *fmri,
10767aec1d6eScindi     int err)
10777aec1d6eScindi {
10787aec1d6eScindi 	int i;
10797aec1d6eScindi 
10807aec1d6eScindi 	if (hcl != NULL) {
10817aec1d6eScindi 		for (i = 0; i < n + 1; ++i)
10827aec1d6eScindi 			nvlist_free(hcl[i]);
10837aec1d6eScindi 
10847aec1d6eScindi 		topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (n + 1));
10857aec1d6eScindi 	}
10867aec1d6eScindi 
10877aec1d6eScindi 	nvlist_free(fmri);
10887aec1d6eScindi 
10897aec1d6eScindi 	(void) topo_mod_seterrno(mod, err);
10907aec1d6eScindi 
10917aec1d6eScindi 	topo_mod_dprintf(mod, "unable to create hc FMRI: %s\n",
10927aec1d6eScindi 	    topo_mod_errmsg(mod));
10937aec1d6eScindi 
10947aec1d6eScindi 	return (NULL);
10957aec1d6eScindi }
10967aec1d6eScindi 
10977aec1d6eScindi static int
hc_name_canonical(topo_mod_t * mod,const char * name)10980eb822a1Scindi hc_name_canonical(topo_mod_t *mod, const char *name)
10997aec1d6eScindi {
11007aec1d6eScindi 	int i;
11010eb822a1Scindi 
11020eb822a1Scindi 	if (getenv("NOHCCHECK") != NULL)
11030eb822a1Scindi 		return (1);
11040eb822a1Scindi 
11057aec1d6eScindi 	/*
11067aec1d6eScindi 	 * Only enumerate elements with correct canonical names
11077aec1d6eScindi 	 */
11080eb822a1Scindi 	for (i = 0; i < hc_ncanon; i++) {
11090eb822a1Scindi 		if (strcmp(name, hc_canon[i].hcc_name) == 0)
11107aec1d6eScindi 			break;
11117aec1d6eScindi 	}
11120eb822a1Scindi 	if (i >= hc_ncanon) {
11130eb822a1Scindi 		topo_mod_dprintf(mod, "non-canonical name %s\n",
11140eb822a1Scindi 		    name);
11157aec1d6eScindi 		return (0);
11160eb822a1Scindi 	} else {
11177aec1d6eScindi 		return (1);
11187aec1d6eScindi 	}
11190eb822a1Scindi }
11207aec1d6eScindi 
11217aec1d6eScindi 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)11227aec1d6eScindi hc_fmri_create(topo_mod_t *mod, nvlist_t *pfmri, int version, const char *name,
11237aec1d6eScindi     topo_instance_t inst, const nvlist_t *auth, const char *part,
11247aec1d6eScindi     const char *rev, const char *serial)
11257aec1d6eScindi {
11267aec1d6eScindi 	int i;
11277aec1d6eScindi 	char str[21]; /* sizeof (UINT64_MAX) + '\0' */
11287aec1d6eScindi 	uint_t pelems = 0;
11297aec1d6eScindi 	nvlist_t **phcl = NULL;
11307aec1d6eScindi 	nvlist_t **hcl = NULL;
11317aec1d6eScindi 	nvlist_t *fmri = NULL;
11327aec1d6eScindi 
11337aec1d6eScindi 	if (version > FM_HC_SCHEME_VERSION)
11347aec1d6eScindi 		return (hc_create_seterror(mod,
11357aec1d6eScindi 		    hcl, pelems, fmri, EMOD_VER_OLD));
11367aec1d6eScindi 	else if (version < FM_HC_SCHEME_VERSION)
11377aec1d6eScindi 		return (hc_create_seterror(mod,
11387aec1d6eScindi 		    hcl, pelems, fmri, EMOD_VER_NEW));
11397aec1d6eScindi 
11407aec1d6eScindi 	/*
11417aec1d6eScindi 	 * Check that the requested name is in our canonical list
11427aec1d6eScindi 	 */
11430eb822a1Scindi 	if (hc_name_canonical(mod, name) == 0)
11447aec1d6eScindi 		return (hc_create_seterror(mod,
11457aec1d6eScindi 		    hcl, pelems, fmri, EMOD_NONCANON));
11467aec1d6eScindi 	/*
11477aec1d6eScindi 	 * Copy the parent's HC_LIST
11487aec1d6eScindi 	 */
11497aec1d6eScindi 	if (pfmri != NULL) {
11507aec1d6eScindi 		if (nvlist_lookup_nvlist_array(pfmri, FM_FMRI_HC_LIST,
11517aec1d6eScindi 		    &phcl, &pelems) != 0)
11527aec1d6eScindi 			return (hc_create_seterror(mod,
11537aec1d6eScindi 			    hcl, pelems, fmri, EMOD_FMRI_MALFORM));
11547aec1d6eScindi 	}
11557aec1d6eScindi 
11567aec1d6eScindi 	hcl = topo_mod_zalloc(mod, sizeof (nvlist_t *) * (pelems + 1));
11577aec1d6eScindi 	if (hcl == NULL)
11587aec1d6eScindi 		return (hc_create_seterror(mod,  hcl, pelems, fmri,
11597aec1d6eScindi 		    EMOD_NOMEM));
11607aec1d6eScindi 
11617aec1d6eScindi 	for (i = 0; i < pelems; ++i)
11627aec1d6eScindi 		if (topo_mod_nvdup(mod, phcl[i], &hcl[i]) != 0)
11637aec1d6eScindi 			return (hc_create_seterror(mod,
11647aec1d6eScindi 			    hcl, pelems, fmri, EMOD_FMRI_NVL));
11657aec1d6eScindi 
11667aec1d6eScindi 	(void) snprintf(str, sizeof (str), "%d", inst);
11677aec1d6eScindi 	if ((hcl[i] = hc_list_create(mod, name, str)) == NULL)
11687aec1d6eScindi 		return (hc_create_seterror(mod,
11697aec1d6eScindi 		    hcl, pelems, fmri, EMOD_FMRI_NVL));
11707aec1d6eScindi 
11717aec1d6eScindi 	if ((fmri = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL)
11727aec1d6eScindi 		return (hc_create_seterror(mod,
11737aec1d6eScindi 		    hcl, pelems, fmri, EMOD_FMRI_NVL));
11747aec1d6eScindi 
11757aec1d6eScindi 	if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, hcl, pelems + 1)
11767aec1d6eScindi 	    != 0)
11777aec1d6eScindi 		return (hc_create_seterror(mod,
11787aec1d6eScindi 		    hcl, pelems, fmri, EMOD_FMRI_NVL));
11797aec1d6eScindi 
11807aec1d6eScindi 	if (hcl != NULL) {
11817aec1d6eScindi 		for (i = 0; i < pelems + 1; ++i) {
11827aec1d6eScindi 			nvlist_free(hcl[i]);
11837aec1d6eScindi 		}
11847aec1d6eScindi 		topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (pelems + 1));
11857aec1d6eScindi 	}
11867aec1d6eScindi 
11877aec1d6eScindi 	return (fmri);
11887aec1d6eScindi }
11897aec1d6eScindi 
11907aec1d6eScindi /*ARGSUSED*/
11917aec1d6eScindi static int
hc_fmri_create_meth(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)11920eb822a1Scindi hc_fmri_create_meth(topo_mod_t *mod, tnode_t *node, topo_version_t version,
11937aec1d6eScindi     nvlist_t *in, nvlist_t **out)
11947aec1d6eScindi {
119589c0ae93Scindi 	int ret;
119689c0ae93Scindi 	nvlist_t *args, *pfmri = NULL;
11977aec1d6eScindi 	nvlist_t *auth;
11987aec1d6eScindi 	uint32_t inst;
11997aec1d6eScindi 	char *name, *serial, *rev, *part;
12007aec1d6eScindi 
12017aec1d6eScindi 	if (version > TOPO_METH_FMRI_VERSION)
12020eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
12037aec1d6eScindi 
12047aec1d6eScindi 	/* First the must-have fields */
12057aec1d6eScindi 	if (nvlist_lookup_string(in, TOPO_METH_FMRI_ARG_NAME, &name) != 0)
12060eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
12077aec1d6eScindi 	if (nvlist_lookup_uint32(in, TOPO_METH_FMRI_ARG_INST, &inst) != 0)
12080eb822a1Scindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
12097aec1d6eScindi 
121089c0ae93Scindi 	/*
121189c0ae93Scindi 	 * args is optional
121289c0ae93Scindi 	 */
121389c0ae93Scindi 	pfmri = NULL;
12147aec1d6eScindi 	auth = NULL;
12157aec1d6eScindi 	serial = rev = part = NULL;
121689c0ae93Scindi 	if ((ret = nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args))
121789c0ae93Scindi 	    != 0) {
121889c0ae93Scindi 		if (ret != ENOENT)
12190eb822a1Scindi 			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
122089c0ae93Scindi 	} else {
122189c0ae93Scindi 
122289c0ae93Scindi 		/* And then optional arguments */
122389c0ae93Scindi 		(void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
122489c0ae93Scindi 		    &pfmri);
122589c0ae93Scindi 		(void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_AUTH,
122689c0ae93Scindi 		    &auth);
122789c0ae93Scindi 		(void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_PART,
122889c0ae93Scindi 		    &part);
12297aec1d6eScindi 		(void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_REV, &rev);
123089c0ae93Scindi 		(void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_SER,
123189c0ae93Scindi 		    &serial);
123289c0ae93Scindi 	}
12337aec1d6eScindi 
12340eb822a1Scindi 	*out = hc_fmri_create(mod, pfmri, version, name, inst, auth, part,
12350eb822a1Scindi 	    rev, serial);
12367aec1d6eScindi 	if (*out == NULL)
12377aec1d6eScindi 		return (-1);
12387aec1d6eScindi 	return (0);
12397aec1d6eScindi }
1240c40d7343Scindi 
1241c40d7343Scindi struct hc_walk {
1242c40d7343Scindi 	topo_mod_walk_cb_t hcw_cb;
1243c40d7343Scindi 	void *hcw_priv;
1244c40d7343Scindi 	topo_walk_t *hcw_wp;
1245c40d7343Scindi 	nvlist_t **hcw_list;
1246940d71d2Seschrock 	nvlist_t *hcw_fmri;
1247825ba0f2Srobj 	nvlist_t *hcw_fac;
1248c40d7343Scindi 	uint_t hcw_index;
1249c40d7343Scindi 	uint_t hcw_end;
1250c40d7343Scindi };
1251c40d7343Scindi 
1252c40d7343Scindi /*
1253940d71d2Seschrock  * Returns true if the given node is beneath the specified FMRI.  This uses
1254940d71d2Seschrock  * the TOPO_METH_CONTAINS method, because some enumerators (such as external
1255940d71d2Seschrock  * enclosures) may want to do a comparison based on chassis WWN instead of the
1256940d71d2Seschrock  * instance ID.  If this comparison function fails or is not supported, then we
1257940d71d2Seschrock  * fall back to a direct name/instance comparison.
1258940d71d2Seschrock  */
1259940d71d2Seschrock static int
hc_match(topo_mod_t * mod,tnode_t * node,nvlist_t * fmri,const char * name,topo_instance_t inst,boolean_t * result)1260940d71d2Seschrock hc_match(topo_mod_t *mod, tnode_t *node, nvlist_t *fmri, const char *name,
1261940d71d2Seschrock     topo_instance_t inst, boolean_t *result)
1262940d71d2Seschrock {
1263940d71d2Seschrock 	nvlist_t *rsrc;
1264940d71d2Seschrock 	nvlist_t *arg, *nvl;
1265940d71d2Seschrock 	uint32_t match = 0;
1266940d71d2Seschrock 	int err;
1267940d71d2Seschrock 
1268940d71d2Seschrock 	if (topo_node_resource(node, &rsrc, &err) != 0)
1269940d71d2Seschrock 		return (-1);
1270940d71d2Seschrock 
1271940d71d2Seschrock 	if (topo_mod_nvalloc(mod, &arg, NV_UNIQUE_NAME) != 0 ||
1272940d71d2Seschrock 	    nvlist_add_nvlist(arg, TOPO_METH_FMRI_ARG_FMRI,
1273940d71d2Seschrock 	    rsrc) != 0 ||
1274940d71d2Seschrock 	    nvlist_add_nvlist(arg, TOPO_METH_FMRI_ARG_SUBFMRI,
1275940d71d2Seschrock 	    fmri) != 0) {
1276940d71d2Seschrock 		nvlist_free(rsrc);
1277940d71d2Seschrock 		(void) topo_mod_seterrno(mod, EMOD_NOMEM);
1278940d71d2Seschrock 		return (-1);
1279940d71d2Seschrock 	}
1280940d71d2Seschrock 
1281940d71d2Seschrock 	nvlist_free(rsrc);
1282940d71d2Seschrock 
1283940d71d2Seschrock 	if (topo_method_invoke(node, TOPO_METH_CONTAINS,
1284940d71d2Seschrock 	    TOPO_METH_CONTAINS_VERSION, arg, &nvl, &err) != 0) {
1285940d71d2Seschrock 		nvlist_free(arg);
1286940d71d2Seschrock 		if (err == ETOPO_METHOD_NOTSUP) {
1287940d71d2Seschrock 			match = (strcmp(name,
1288940d71d2Seschrock 			    topo_node_name(node)) == 0 &&
1289940d71d2Seschrock 			    inst == topo_node_instance(node));
1290940d71d2Seschrock 		} else {
1291940d71d2Seschrock 			return (-1);
1292940d71d2Seschrock 		}
1293940d71d2Seschrock 	} else {
1294940d71d2Seschrock 		nvlist_free(arg);
1295940d71d2Seschrock 		if (nvlist_lookup_uint32(nvl, TOPO_METH_CONTAINS_RET,
1296940d71d2Seschrock 		    &match) != 0) {
1297940d71d2Seschrock 			nvlist_free(nvl);
1298940d71d2Seschrock 			(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
1299940d71d2Seschrock 			return (-1);
1300940d71d2Seschrock 		}
1301940d71d2Seschrock 		nvlist_free(nvl);
1302940d71d2Seschrock 	}
1303940d71d2Seschrock 
1304940d71d2Seschrock 	*result = (match != 0);
1305940d71d2Seschrock 	return (0);
1306940d71d2Seschrock }
1307940d71d2Seschrock 
1308940d71d2Seschrock /*
1309940d71d2Seschrock  * Ideally, we should just be able to call topo_walk_bysibling().  But that
1310940d71d2Seschrock  * code assumes that the name/instance pair will match, so we need to
1311940d71d2Seschrock  * explicitly iterate over children of the parent looking for a matching value.
1312940d71d2Seschrock  */
1313940d71d2Seschrock static int
hc_walk_sibling(topo_mod_t * mod,tnode_t * node,struct hc_walk * hwp,const char * name,topo_instance_t inst)1314940d71d2Seschrock hc_walk_sibling(topo_mod_t *mod, tnode_t *node, struct hc_walk *hwp,
1315940d71d2Seschrock     const char *name, topo_instance_t inst)
1316940d71d2Seschrock {
1317940d71d2Seschrock 	tnode_t *pnp = topo_node_parent(node);
1318940d71d2Seschrock 	topo_walk_t *wp = hwp->hcw_wp;
1319940d71d2Seschrock 	tnode_t *np;
1320940d71d2Seschrock 	boolean_t matched;
1321940d71d2Seschrock 	int status;
1322940d71d2Seschrock 
1323940d71d2Seschrock 	for (np = topo_child_first(pnp); np != NULL;
1324940d71d2Seschrock 	    np = topo_child_next(pnp, np)) {
1325940d71d2Seschrock 		topo_node_hold(np);
1326940d71d2Seschrock 		if (hc_match(mod, np, hwp->hcw_fmri, name, inst,
1327940d71d2Seschrock 		    &matched) == 0 && matched) {
1328940d71d2Seschrock 			wp->tw_node = np;
1329940d71d2Seschrock 			if (wp->tw_mod != NULL)
1330940d71d2Seschrock 				status = wp->tw_cb(mod, np, hwp);
1331940d71d2Seschrock 			else
1332940d71d2Seschrock 				status = wp->tw_cb(wp->tw_thp, np, hwp);
1333940d71d2Seschrock 			topo_node_rele(np);
1334940d71d2Seschrock 			wp->tw_node = node;
1335940d71d2Seschrock 			return (status);
1336940d71d2Seschrock 		}
1337940d71d2Seschrock 
1338940d71d2Seschrock 		topo_node_rele(np);
1339940d71d2Seschrock 	}
1340940d71d2Seschrock 
1341940d71d2Seschrock 	return (TOPO_WALK_TERMINATE);
1342940d71d2Seschrock }
1343940d71d2Seschrock 
1344940d71d2Seschrock /*
1345c40d7343Scindi  * Generic walker for the hc-scheme topo tree.  This function uses the
1346825ba0f2Srobj  * hierachical nature of the hc-scheme to efficiently step through
134778432d5eScy152378  * the topo hc tree.  Node lookups are done by topo_walk_byid() and
134878432d5eScy152378  * topo_walk_bysibling()  at each component level to avoid unnecessary
134978432d5eScy152378  * traversal of the tree.  hc_walker() never returns TOPO_WALK_NEXT, so
135078432d5eScy152378  * whether TOPO_WALK_CHILD or TOPO_WALK_SIBLING is specified by
135178432d5eScy152378  * topo_walk_step() doesn't affect the traversal.
1352c40d7343Scindi  */
1353c40d7343Scindi static int
hc_walker(topo_mod_t * mod,tnode_t * node,void * pdata)1354c40d7343Scindi hc_walker(topo_mod_t *mod, tnode_t *node, void *pdata)
1355c40d7343Scindi {
1356c40d7343Scindi 	int i, err;
1357c40d7343Scindi 	struct hc_walk *hwp = (struct hc_walk *)pdata;
1358c40d7343Scindi 	char *name, *id;
1359825ba0f2Srobj 	char *fname, *ftype;
1360c40d7343Scindi 	topo_instance_t inst;
1361940d71d2Seschrock 	boolean_t match;
1362c40d7343Scindi 
1363c40d7343Scindi 	i = hwp->hcw_index;
1364c40d7343Scindi 	if (i > hwp->hcw_end) {
1365825ba0f2Srobj 		if (hwp->hcw_fac != NULL) {
1366825ba0f2Srobj 			if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv))
1367825ba0f2Srobj 			    != 0) {
1368825ba0f2Srobj 				(void) topo_mod_seterrno(mod, err);
1369825ba0f2Srobj 				topo_mod_dprintf(mod, "hc_walker: callback "
1370825ba0f2Srobj 				    "failed: %s\n ", topo_mod_errmsg(mod));
1371825ba0f2Srobj 				return (TOPO_WALK_ERR);
1372825ba0f2Srobj 			}
1373825ba0f2Srobj 			topo_mod_dprintf(mod, "hc_walker: callback "
1374825ba0f2Srobj 			    "complete: terminate walk\n");
1375c40d7343Scindi 			return (TOPO_WALK_TERMINATE);
1376825ba0f2Srobj 		} else {
1377825ba0f2Srobj 			topo_mod_dprintf(mod, "hc_walker: node not found\n");
1378825ba0f2Srobj 			return (TOPO_WALK_TERMINATE);
1379825ba0f2Srobj 		}
1380c40d7343Scindi 	}
1381c40d7343Scindi 
1382c40d7343Scindi 	err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name);
1383c40d7343Scindi 	err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id);
1384c40d7343Scindi 
1385c40d7343Scindi 	if (err != 0) {
1386c40d7343Scindi 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
1387c40d7343Scindi 		return (TOPO_WALK_ERR);
1388c40d7343Scindi 	}
1389c40d7343Scindi 
1390c40d7343Scindi 	inst = atoi(id);
139101e689ccScindi 
139201e689ccScindi 	/*
1393940d71d2Seschrock 	 * Check to see if our node matches the requested FMRI.  If it doesn't
1394940d71d2Seschrock 	 * (because the enumerator determines matching based on something other
1395940d71d2Seschrock 	 * than name/instance, or because we're at the first level below the
1396940d71d2Seschrock 	 * root), then iterate over siblings to find the matching node.
139701e689ccScindi 	 */
1398940d71d2Seschrock 	if (hc_match(mod, node, hwp->hcw_fmri, name, inst, &match) != 0)
1399940d71d2Seschrock 		return (TOPO_WALK_ERR);
1400940d71d2Seschrock 
1401940d71d2Seschrock 	if (!match)
1402940d71d2Seschrock 		return (hc_walk_sibling(mod, node, hwp, name, inst));
140301e689ccScindi 
1404c40d7343Scindi 	topo_mod_dprintf(mod, "hc_walker: walking node:%s=%d for hc:"
1405c40d7343Scindi 	    "%s=%d at %d, end at %d \n", topo_node_name(node),
1406c40d7343Scindi 	    topo_node_instance(node), name, inst, i, hwp->hcw_end);
1407825ba0f2Srobj 
1408c40d7343Scindi 	if (i == hwp->hcw_end) {
1409825ba0f2Srobj 
1410c40d7343Scindi 		/*
1411825ba0f2Srobj 		 * We are at the end of the hc-list.  Now, check for
1412825ba0f2Srobj 		 * a facility leaf and walk one more time.
1413c40d7343Scindi 		 */
1414825ba0f2Srobj 		if (hwp->hcw_fac != NULL) {
1415825ba0f2Srobj 			err = nvlist_lookup_string(hwp->hcw_fac,
1416825ba0f2Srobj 			    FM_FMRI_FACILITY_NAME, &fname);
1417825ba0f2Srobj 			err |= nvlist_lookup_string(hwp->hcw_fac,
1418825ba0f2Srobj 			    FM_FMRI_FACILITY_TYPE, &ftype);
1419825ba0f2Srobj 			if (err != 0) {
1420825ba0f2Srobj 				(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
1421825ba0f2Srobj 				return (TOPO_WALK_ERR);
1422825ba0f2Srobj 			}
1423825ba0f2Srobj 			hwp->hcw_index++;
1424825ba0f2Srobj 			topo_mod_dprintf(mod, "hc_walker: walk to facility "
1425825ba0f2Srobj 			    "node:%s=%s\n", fname, ftype);
1426825ba0f2Srobj 			return (topo_walk_byid(hwp->hcw_wp, fname, 0));
1427825ba0f2Srobj 		}
1428825ba0f2Srobj 
1429825ba0f2Srobj 		/*
1430825ba0f2Srobj 		 * Otherwise, this is the node we're looking for.
1431825ba0f2Srobj 		 */
1432825ba0f2Srobj 		if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv)) != 0) {
1433c40d7343Scindi 			(void) topo_mod_seterrno(mod, err);
1434c40d7343Scindi 			topo_mod_dprintf(mod, "hc_walker: callback "
1435c40d7343Scindi 			    "failed: %s\n ", topo_mod_errmsg(mod));
1436c40d7343Scindi 			return (TOPO_WALK_ERR);
1437825ba0f2Srobj 		} else {
1438c40d7343Scindi 			topo_mod_dprintf(mod, "hc_walker: callback "
1439c40d7343Scindi 			    "complete: terminate walk\n");
1440c40d7343Scindi 			return (TOPO_WALK_TERMINATE);
1441c40d7343Scindi 		}
1442c40d7343Scindi 	}
1443c40d7343Scindi 
1444825ba0f2Srobj 	/*
1445825ba0f2Srobj 	 * Move on to the next component in the hc-list
1446825ba0f2Srobj 	 */
1447c40d7343Scindi 	hwp->hcw_index = ++i;
1448c40d7343Scindi 	err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name);
1449c40d7343Scindi 	err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id);
1450c40d7343Scindi 	if (err != 0) {
1451c40d7343Scindi 		(void) topo_mod_seterrno(mod, err);
1452c40d7343Scindi 		return (TOPO_WALK_ERR);
1453c40d7343Scindi 	}
1454c40d7343Scindi 	inst = atoi(id);
1455c40d7343Scindi 
1456c40d7343Scindi 	return (topo_walk_byid(hwp->hcw_wp, name, inst));
1457c40d7343Scindi 
1458c40d7343Scindi }
1459c40d7343Scindi 
1460c40d7343Scindi 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)1461c40d7343Scindi hc_walk_init(topo_mod_t *mod, tnode_t *node, nvlist_t *rsrc,
1462c40d7343Scindi     topo_mod_walk_cb_t cb, void *pdata)
1463c40d7343Scindi {
1464825ba0f2Srobj 	int err, ret;
1465c40d7343Scindi 	uint_t sz;
1466c40d7343Scindi 	struct hc_walk *hwp;
1467c40d7343Scindi 	topo_walk_t *wp;
1468c40d7343Scindi 
1469918a0d8aSrobj 	if ((hwp = topo_mod_alloc(mod, sizeof (struct hc_walk))) == NULL) {
1470c40d7343Scindi 		(void) topo_mod_seterrno(mod, EMOD_NOMEM);
1471918a0d8aSrobj 		return (NULL);
1472918a0d8aSrobj 	}
1473c40d7343Scindi 
1474c40d7343Scindi 	if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hwp->hcw_list,
1475c40d7343Scindi 	    &sz) != 0) {
1476825ba0f2Srobj 		topo_mod_dprintf(mod, "hc_walk_init: failed to lookup %s "
1477825ba0f2Srobj 		    "nvlist\n", FM_FMRI_HC_LIST);
1478c40d7343Scindi 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1479c40d7343Scindi 		(void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
1480c40d7343Scindi 		return (NULL);
1481c40d7343Scindi 	}
1482825ba0f2Srobj 	if ((ret = nvlist_lookup_nvlist(rsrc, FM_FMRI_FACILITY, &hwp->hcw_fac))
1483825ba0f2Srobj 	    != 0) {
1484825ba0f2Srobj 		if (ret != ENOENT) {
1485825ba0f2Srobj 			topo_mod_dprintf(mod, "hc_walk_init: unexpected error "
1486825ba0f2Srobj 			    "looking up %s nvlist", FM_FMRI_FACILITY);
1487825ba0f2Srobj 			topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1488825ba0f2Srobj 			(void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
1489825ba0f2Srobj 			return (NULL);
1490825ba0f2Srobj 		} else {
1491825ba0f2Srobj 			hwp->hcw_fac = NULL;
1492825ba0f2Srobj 		}
1493825ba0f2Srobj 	}
1494c40d7343Scindi 
1495940d71d2Seschrock 	hwp->hcw_fmri = rsrc;
1496c40d7343Scindi 	hwp->hcw_end = sz - 1;
1497c40d7343Scindi 	hwp->hcw_index = 0;
1498c40d7343Scindi 	hwp->hcw_priv = pdata;
1499c40d7343Scindi 	hwp->hcw_cb = cb;
1500c40d7343Scindi 	if ((wp = topo_mod_walk_init(mod, node, hc_walker, (void *)hwp, &err))
1501c40d7343Scindi 	    == NULL) {
1502825ba0f2Srobj 		topo_mod_dprintf(mod, "hc_walk_init: topo_mod_walk_init failed "
1503825ba0f2Srobj 		    "(%s)\n", topo_strerror(err));
1504c40d7343Scindi 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1505c40d7343Scindi 		(void) topo_mod_seterrno(mod, err);
1506c40d7343Scindi 		return (NULL);
1507c40d7343Scindi 	}
1508c40d7343Scindi 
1509c40d7343Scindi 	hwp->hcw_wp = wp;
1510c40d7343Scindi 
1511c40d7343Scindi 	return (hwp);
1512c40d7343Scindi }
1513c40d7343Scindi 
1514c40d7343Scindi struct prop_lookup {
1515c40d7343Scindi 	const char *pl_pgroup;
1516c40d7343Scindi 	const char *pl_pname;
1517c40d7343Scindi 	int pl_flag;
1518c40d7343Scindi 	nvlist_t *pl_args;
1519c40d7343Scindi 	nvlist_t *pl_rsrc;
1520c40d7343Scindi 	nvlist_t *pl_prop;
1521c40d7343Scindi };
1522c40d7343Scindi 
1523c40d7343Scindi /*ARGSUSED*/
1524c40d7343Scindi static int
hc_prop_get(topo_mod_t * mod,tnode_t * node,void * pdata)1525c40d7343Scindi hc_prop_get(topo_mod_t *mod, tnode_t *node, void *pdata)
1526c40d7343Scindi {
1527c40d7343Scindi 	int err = 0;
1528c40d7343Scindi 
1529c40d7343Scindi 	struct prop_lookup *plp = (struct prop_lookup *)pdata;
1530c40d7343Scindi 
1531c40d7343Scindi 	(void) topo_prop_getprop(node, plp->pl_pgroup, plp->pl_pname,
1532c40d7343Scindi 	    plp->pl_args, &plp->pl_prop, &err);
1533c40d7343Scindi 
1534c40d7343Scindi 	return (err);
1535c40d7343Scindi }
1536c40d7343Scindi 
1537c40d7343Scindi static int
hc_fmri_prop_get(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)1538c40d7343Scindi hc_fmri_prop_get(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1539c40d7343Scindi     nvlist_t *in, nvlist_t **out)
1540c40d7343Scindi {
1541c40d7343Scindi 	int err;
1542c40d7343Scindi 	struct hc_walk *hwp;
1543c40d7343Scindi 	struct prop_lookup *plp;
1544c40d7343Scindi 
1545c40d7343Scindi 	if (version > TOPO_METH_PROP_GET_VERSION)
1546c40d7343Scindi 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1547c40d7343Scindi 
1548c40d7343Scindi 	if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
1549c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1550c40d7343Scindi 
1551c40d7343Scindi 	err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
1552c40d7343Scindi 	    (char **)&plp->pl_pgroup);
1553c40d7343Scindi 	err |= nvlist_lookup_string(in, TOPO_PROP_VAL_NAME,
1554c40d7343Scindi 	    (char **)&plp->pl_pname);
1555c40d7343Scindi 	err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
1556c40d7343Scindi 	if (err != 0) {
1557c40d7343Scindi 		topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1558c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1559c40d7343Scindi 	}
1560c40d7343Scindi 
1561c40d7343Scindi 	/*
1562c40d7343Scindi 	 * Private args to prop method are optional
1563c40d7343Scindi 	 */
1564c40d7343Scindi 	if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args))
1565c40d7343Scindi 	    != 0) {
1566c40d7343Scindi 		if (err != ENOENT) {
1567c40d7343Scindi 			topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1568c40d7343Scindi 			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1569c40d7343Scindi 		} else {
1570c40d7343Scindi 			plp->pl_args = NULL;
1571c40d7343Scindi 		}
1572c40d7343Scindi 	}
1573c40d7343Scindi 
1574c40d7343Scindi 	plp->pl_prop = NULL;
1575c40d7343Scindi 	if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_get,
1576c40d7343Scindi 	    (void *)plp)) != NULL) {
157778432d5eScy152378 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1578c40d7343Scindi 		    TOPO_WALK_ERR)
1579c40d7343Scindi 			err = -1;
1580c40d7343Scindi 		else
1581c40d7343Scindi 			err = 0;
1582c40d7343Scindi 		topo_walk_fini(hwp->hcw_wp);
1583918a0d8aSrobj 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1584c40d7343Scindi 	} else {
1585c40d7343Scindi 		err = -1;
1586c40d7343Scindi 	}
1587c40d7343Scindi 
1588c40d7343Scindi 	if (plp->pl_prop != NULL)
1589c40d7343Scindi 		*out = plp->pl_prop;
1590c40d7343Scindi 
1591c40d7343Scindi 	topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1592c40d7343Scindi 
1593c40d7343Scindi 	return (err);
1594c40d7343Scindi }
1595c40d7343Scindi 
1596c40d7343Scindi /*ARGSUSED*/
1597c40d7343Scindi static int
hc_pgrp_get(topo_mod_t * mod,tnode_t * node,void * pdata)1598c40d7343Scindi hc_pgrp_get(topo_mod_t *mod, tnode_t *node, void *pdata)
1599c40d7343Scindi {
1600c40d7343Scindi 	int err = 0;
1601c40d7343Scindi 
1602c40d7343Scindi 	struct prop_lookup *plp = (struct prop_lookup *)pdata;
1603c40d7343Scindi 
1604c40d7343Scindi 	(void) topo_prop_getpgrp(node, plp->pl_pgroup, &plp->pl_prop, &err);
1605c40d7343Scindi 
1606c40d7343Scindi 	return (err);
1607c40d7343Scindi }
1608c40d7343Scindi 
1609c40d7343Scindi static int
hc_fmri_pgrp_get(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)1610c40d7343Scindi hc_fmri_pgrp_get(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1611c40d7343Scindi     nvlist_t *in, nvlist_t **out)
1612c40d7343Scindi {
1613c40d7343Scindi 	int err;
1614c40d7343Scindi 	struct hc_walk *hwp;
1615c40d7343Scindi 	struct prop_lookup *plp;
1616c40d7343Scindi 
1617c40d7343Scindi 	if (version > TOPO_METH_PGRP_GET_VERSION)
1618c40d7343Scindi 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1619c40d7343Scindi 
1620c40d7343Scindi 	if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
1621c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1622c40d7343Scindi 
1623c40d7343Scindi 	err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
1624c40d7343Scindi 	    (char **)&plp->pl_pgroup);
1625c40d7343Scindi 	err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
1626c40d7343Scindi 	if (err != 0) {
1627c40d7343Scindi 		topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1628c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1629c40d7343Scindi 	}
1630c40d7343Scindi 
1631c40d7343Scindi 	plp->pl_prop = NULL;
1632c40d7343Scindi 	if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_pgrp_get,
1633c40d7343Scindi 	    (void *)plp)) != NULL) {
163478432d5eScy152378 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1635c40d7343Scindi 		    TOPO_WALK_ERR)
1636c40d7343Scindi 			err = -1;
1637c40d7343Scindi 		else
1638c40d7343Scindi 			err = 0;
1639c40d7343Scindi 		topo_walk_fini(hwp->hcw_wp);
1640918a0d8aSrobj 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1641c40d7343Scindi 	} else {
1642c40d7343Scindi 		err = -1;
1643c40d7343Scindi 	}
1644c40d7343Scindi 
1645c40d7343Scindi 	if (plp->pl_prop != NULL)
1646c40d7343Scindi 		*out = plp->pl_prop;
1647c40d7343Scindi 
1648c40d7343Scindi 	topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1649c40d7343Scindi 
1650c40d7343Scindi 	return (err);
1651c40d7343Scindi }
1652c40d7343Scindi 
1653c40d7343Scindi /*ARGSUSED*/
1654c40d7343Scindi static int
hc_prop_setprop(topo_mod_t * mod,tnode_t * node,void * pdata)1655c40d7343Scindi hc_prop_setprop(topo_mod_t *mod, tnode_t *node, void *pdata)
1656c40d7343Scindi {
1657c40d7343Scindi 	int err = 0;
1658c40d7343Scindi 
1659c40d7343Scindi 	struct prop_lookup *plp = (struct prop_lookup *)pdata;
1660c40d7343Scindi 
1661c40d7343Scindi 	(void) topo_prop_setprop(node, plp->pl_pgroup, plp->pl_prop,
1662c40d7343Scindi 	    plp->pl_flag, plp->pl_args, &err);
1663c40d7343Scindi 
1664c40d7343Scindi 	return (err);
1665c40d7343Scindi }
1666c40d7343Scindi 
1667c40d7343Scindi /*ARGSUSED*/
1668c40d7343Scindi static int
hc_fmri_prop_set(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)1669c40d7343Scindi hc_fmri_prop_set(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1670c40d7343Scindi     nvlist_t *in, nvlist_t **out)
1671c40d7343Scindi {
1672c40d7343Scindi 	int err;
1673c40d7343Scindi 	struct hc_walk *hwp;
1674c40d7343Scindi 	struct prop_lookup *plp;
1675c40d7343Scindi 
1676c40d7343Scindi 	if (version > TOPO_METH_PROP_SET_VERSION)
1677c40d7343Scindi 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1678c40d7343Scindi 
1679c40d7343Scindi 	if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
1680c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1681c40d7343Scindi 
1682c40d7343Scindi 	err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
1683c40d7343Scindi 	    (char **)&plp->pl_pgroup);
1684c40d7343Scindi 	err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
1685c40d7343Scindi 	err |= nvlist_lookup_nvlist(in, TOPO_PROP_VAL, &plp->pl_prop);
1686c40d7343Scindi 	err |= nvlist_lookup_int32(in, TOPO_PROP_FLAG, &plp->pl_flag);
1687c40d7343Scindi 	if (err != 0) {
1688c40d7343Scindi 		topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1689c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1690c40d7343Scindi 	}
1691c40d7343Scindi 
1692c40d7343Scindi 	/*
1693c40d7343Scindi 	 * Private args to prop method are optional
1694c40d7343Scindi 	 */
1695c40d7343Scindi 	if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args))
1696c40d7343Scindi 	    != 0) {
1697c40d7343Scindi 		if (err != ENOENT)
1698c40d7343Scindi 			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1699c40d7343Scindi 		else
1700c40d7343Scindi 			plp->pl_args = NULL;
1701c40d7343Scindi 	}
1702c40d7343Scindi 
1703c40d7343Scindi 	if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_setprop,
1704c40d7343Scindi 	    (void *)plp)) != NULL) {
170578432d5eScy152378 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1706c40d7343Scindi 		    TOPO_WALK_ERR)
1707c40d7343Scindi 			err = -1;
1708c40d7343Scindi 		else
1709c40d7343Scindi 			err = 0;
1710c40d7343Scindi 		topo_walk_fini(hwp->hcw_wp);
1711918a0d8aSrobj 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1712c40d7343Scindi 	} else {
1713c40d7343Scindi 		err = -1;
1714c40d7343Scindi 	}
1715c40d7343Scindi 
1716c40d7343Scindi 	topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1717c40d7343Scindi 
1718c40d7343Scindi 	return (err);
1719c40d7343Scindi }
1720c40d7343Scindi 
1721c40d7343Scindi struct hc_args {
1722c40d7343Scindi 	nvlist_t *ha_fmri;
1723c40d7343Scindi 	nvlist_t *ha_nvl;
1724e4b86885SCheng Sean Ye 	char *ha_method_name;
1725e4b86885SCheng Sean Ye 	topo_version_t ha_method_ver;
1726c40d7343Scindi };
1727c40d7343Scindi 
17286e1fa242SStephen Hanson static int
hc_auth_changed(nvlist_t * nva,nvlist_t * nvb,const char * propname)17297793aa8bSEric Schrock hc_auth_changed(nvlist_t *nva, nvlist_t *nvb, const char *propname)
17307793aa8bSEric Schrock {
17317793aa8bSEric Schrock 	char *stra, *strb;
17327793aa8bSEric Schrock 
17337793aa8bSEric Schrock 	if (nvlist_lookup_string(nva, propname, &stra) != 0 ||
17347793aa8bSEric Schrock 	    nvlist_lookup_string(nvb, propname, &strb) != 0)
17356e1fa242SStephen Hanson 		return (FMD_OBJ_STATE_UNKNOWN);
17367793aa8bSEric Schrock 
17377793aa8bSEric Schrock 	if (strcmp(stra, strb) != 0)
17386e1fa242SStephen Hanson 		return (FMD_OBJ_STATE_REPLACED);
17397793aa8bSEric Schrock 	else
17406e1fa242SStephen Hanson 		return (FMD_OBJ_STATE_STILL_PRESENT);
17417793aa8bSEric Schrock }
17427793aa8bSEric Schrock 
1743c40d7343Scindi static int
hc_is_present(topo_mod_t * mod,tnode_t * node,void * pdata)1744c40d7343Scindi hc_is_present(topo_mod_t *mod, tnode_t *node, void *pdata)
1745c40d7343Scindi {
1746c40d7343Scindi 	int err;
1747c40d7343Scindi 	struct hc_args *hap = (struct hc_args *)pdata;
17487793aa8bSEric Schrock 	nvlist_t *rsrc;
17497793aa8bSEric Schrock 	boolean_t present;
1750c40d7343Scindi 
1751c40d7343Scindi 	/*
1752c40d7343Scindi 	 * check with the enumerator that created this FMRI
1753c40d7343Scindi 	 * (topo node)
1754c40d7343Scindi 	 */
1755c40d7343Scindi 	if (topo_method_invoke(node, TOPO_METH_PRESENT,
1756c40d7343Scindi 	    TOPO_METH_PRESENT_VERSION, hap->ha_fmri, &hap->ha_nvl,
1757c40d7343Scindi 	    &err) < 0) {
1758c40d7343Scindi 
1759c40d7343Scindi 		/*
17607793aa8bSEric Schrock 		 * If the method exists but failed for some other reason,
17617793aa8bSEric Schrock 		 * propagate the error as making any decision over presence is
17627793aa8bSEric Schrock 		 * impossible.
1763c40d7343Scindi 		 */
17647793aa8bSEric Schrock 		if (err != ETOPO_METHOD_NOTSUP)
17657793aa8bSEric Schrock 			return (err);
1766c40d7343Scindi 
17677793aa8bSEric Schrock 		/*
17687793aa8bSEric Schrock 		 * Check the authority information.  If the part id or serial
17697793aa8bSEric Schrock 		 * number doesn't match, then it isn't the same FMRI.
17707793aa8bSEric Schrock 		 * Otherwise, assume presence.
17717793aa8bSEric Schrock 		 */
17727793aa8bSEric Schrock 		if (topo_node_resource(node, &rsrc, &err) != 0)
17737793aa8bSEric Schrock 			return (err);
17747793aa8bSEric Schrock 
17757793aa8bSEric Schrock 		present = B_TRUE;
17767793aa8bSEric Schrock 		if (hc_auth_changed(hap->ha_fmri, rsrc,
17776e1fa242SStephen Hanson 		    FM_FMRI_HC_SERIAL_ID) == FMD_OBJ_STATE_REPLACED ||
17787793aa8bSEric Schrock 		    hc_auth_changed(hap->ha_fmri, rsrc,
17796e1fa242SStephen Hanson 		    FM_FMRI_HC_PART) == FMD_OBJ_STATE_REPLACED) {
17807793aa8bSEric Schrock 			present = B_FALSE;
17817793aa8bSEric Schrock 		}
17827793aa8bSEric Schrock 		nvlist_free(rsrc);
17837793aa8bSEric Schrock 
17847793aa8bSEric Schrock 		if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) != 0)
17857793aa8bSEric Schrock 			return (EMOD_NOMEM);
17867793aa8bSEric Schrock 
17877793aa8bSEric Schrock 		if (nvlist_add_uint32(hap->ha_nvl,
17887793aa8bSEric Schrock 		    TOPO_METH_PRESENT_RET, present) != 0) {
17897793aa8bSEric Schrock 			nvlist_free(hap->ha_nvl);
17907793aa8bSEric Schrock 			hap->ha_nvl = NULL;
17917793aa8bSEric Schrock 			return (EMOD_NOMEM);
17927793aa8bSEric Schrock 		}
1793c40d7343Scindi 	}
1794c40d7343Scindi 
179524db4641Seschrock 	return (0);
1796c40d7343Scindi }
1797c40d7343Scindi 
1798c40d7343Scindi static int
hc_fmri_present(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)1799c40d7343Scindi hc_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1800c40d7343Scindi     nvlist_t *in, nvlist_t **out)
1801c40d7343Scindi {
1802c40d7343Scindi 	int err;
1803c40d7343Scindi 	struct hc_walk *hwp;
1804c40d7343Scindi 	struct hc_args *hap;
1805c40d7343Scindi 
1806c40d7343Scindi 	if (version > TOPO_METH_PRESENT_VERSION)
1807c40d7343Scindi 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1808c40d7343Scindi 
1809c40d7343Scindi 	if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
1810c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1811c40d7343Scindi 
1812c40d7343Scindi 	hap->ha_fmri = in;
1813c40d7343Scindi 	hap->ha_nvl = NULL;
1814c40d7343Scindi 	if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_is_present,
1815c40d7343Scindi 	    (void *)hap)) != NULL) {
181678432d5eScy152378 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1817c40d7343Scindi 		    TOPO_WALK_ERR)
1818c40d7343Scindi 			err = -1;
1819c40d7343Scindi 		else
1820c40d7343Scindi 			err = 0;
1821c40d7343Scindi 		topo_walk_fini(hwp->hcw_wp);
1822918a0d8aSrobj 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1823c40d7343Scindi 	} else {
1824c40d7343Scindi 		err = -1;
1825c40d7343Scindi 	}
1826c40d7343Scindi 
1827c40d7343Scindi 	if (hap->ha_nvl != NULL)
1828c40d7343Scindi 		*out = hap->ha_nvl;
1829c40d7343Scindi 
1830c40d7343Scindi 	topo_mod_free(mod, hap, sizeof (struct hc_args));
1831c40d7343Scindi 
1832c40d7343Scindi 	return (err);
1833c40d7343Scindi }
1834c40d7343Scindi 
1835c40d7343Scindi static int
hc_is_replaced(topo_mod_t * mod,tnode_t * node,void * pdata)183625c6ff4bSstephh hc_is_replaced(topo_mod_t *mod, tnode_t *node, void *pdata)
183725c6ff4bSstephh {
183825c6ff4bSstephh 	int err;
183925c6ff4bSstephh 	struct hc_args *hap = (struct hc_args *)pdata;
184025c6ff4bSstephh 	uint32_t present = 0;
18416e1fa242SStephen Hanson 	nvlist_t *rsrc;
18426e1fa242SStephen Hanson 	uint32_t rval = FMD_OBJ_STATE_UNKNOWN;
184325c6ff4bSstephh 
184425c6ff4bSstephh 	/*
184525c6ff4bSstephh 	 * check with the enumerator that created this FMRI
184625c6ff4bSstephh 	 * (topo node)
184725c6ff4bSstephh 	 */
184825c6ff4bSstephh 	if (topo_method_invoke(node, TOPO_METH_REPLACED,
184925c6ff4bSstephh 	    TOPO_METH_REPLACED_VERSION, hap->ha_fmri, &hap->ha_nvl,
185025c6ff4bSstephh 	    &err) < 0) {
185125c6ff4bSstephh 		/*
18526e1fa242SStephen Hanson 		 * If the method exists but failed for some other
18536e1fa242SStephen Hanson 		 * reason, propagate the error as making any decision
18546e1fa242SStephen Hanson 		 * over presence is impossible.
18556e1fa242SStephen Hanson 		 */
18566e1fa242SStephen Hanson 		if (err != ETOPO_METHOD_NOTSUP)
18576e1fa242SStephen Hanson 			return (err);
18586e1fa242SStephen Hanson 
18596e1fa242SStephen Hanson 		/*
18606e1fa242SStephen Hanson 		 * Enumerator didn't provide "replaced" method -
186125c6ff4bSstephh 		 * try "present" method
186225c6ff4bSstephh 		 */
186325c6ff4bSstephh 		if (topo_method_invoke(node, TOPO_METH_PRESENT,
186425c6ff4bSstephh 		    TOPO_METH_PRESENT_VERSION, hap->ha_fmri, &hap->ha_nvl,
186525c6ff4bSstephh 		    &err) < 0) {
18666e1fa242SStephen Hanson 			/*
18676e1fa242SStephen Hanson 			 * If the method exists but failed for some other
18686e1fa242SStephen Hanson 			 * reason, propagate the error as making any decision
18696e1fa242SStephen Hanson 			 * over presence is impossible.
18706e1fa242SStephen Hanson 			 */
18716e1fa242SStephen Hanson 			if (err != ETOPO_METHOD_NOTSUP)
18726e1fa242SStephen Hanson 				return (err);
18736e1fa242SStephen Hanson 
18746e1fa242SStephen Hanson 			/*
18756e1fa242SStephen Hanson 			 * Enumerator didn't provide "present" method either -
18766e1fa242SStephen Hanson 			 * so check the authority information.  If the part id
18776e1fa242SStephen Hanson 			 * or serial number doesn't match, then it isn't the
18786e1fa242SStephen Hanson 			 * same FMRI. Otherwise, if we have a serial number and
18796e1fa242SStephen Hanson 			 * it hasn't changed, then assume it is the same FMRI.
18806e1fa242SStephen Hanson 			 */
18816e1fa242SStephen Hanson 			if (topo_node_resource(node, &rsrc, &err) != 0)
18826e1fa242SStephen Hanson 				return (err);
18836e1fa242SStephen Hanson 			rval = hc_auth_changed(hap->ha_fmri, rsrc,
18846e1fa242SStephen Hanson 			    FM_FMRI_HC_PART);
18856e1fa242SStephen Hanson 			if (rval != FMD_OBJ_STATE_REPLACED)
18866e1fa242SStephen Hanson 				rval = hc_auth_changed(hap->ha_fmri, rsrc,
18876e1fa242SStephen Hanson 				    FM_FMRI_HC_SERIAL_ID);
18886e1fa242SStephen Hanson 			nvlist_free(rsrc);
1889e5dcf7beSRobert Johnston 			if (topo_mod_nvalloc(mod, &hap->ha_nvl,
1890e5dcf7beSRobert Johnston 			    NV_UNIQUE_NAME) != 0)
18916e1fa242SStephen Hanson 				return (EMOD_NOMEM);
18926e1fa242SStephen Hanson 			if (nvlist_add_uint32(hap->ha_nvl,
18936e1fa242SStephen Hanson 			    TOPO_METH_REPLACED_RET, rval) != 0) {
18946e1fa242SStephen Hanson 				nvlist_free(hap->ha_nvl);
18956e1fa242SStephen Hanson 				hap->ha_nvl = NULL;
1896e5dcf7beSRobert Johnston 				return (ETOPO_PROP_NVL);
18976e1fa242SStephen Hanson 			}
189825c6ff4bSstephh 		} else {
189925c6ff4bSstephh 			(void) nvlist_lookup_uint32(hap->ha_nvl,
190025c6ff4bSstephh 			    TOPO_METH_PRESENT_RET, &present);
190125c6ff4bSstephh 			(void) nvlist_remove(hap->ha_nvl,
190225c6ff4bSstephh 			    TOPO_METH_PRESENT_RET, DATA_TYPE_UINT32);
19036e1fa242SStephen Hanson 			if (nvlist_add_uint32(hap->ha_nvl,
19046e1fa242SStephen Hanson 			    TOPO_METH_REPLACED_RET,
1905c7d6cfd6SStephen Hanson 			    present ? FMD_OBJ_STATE_UNKNOWN :
1906e5dcf7beSRobert Johnston 			    FMD_OBJ_STATE_NOT_PRESENT) != 0) {
1907e5dcf7beSRobert Johnston 				nvlist_free(hap->ha_nvl);
19086e1fa242SStephen Hanson 				hap->ha_nvl = NULL;
190925c6ff4bSstephh 				return (ETOPO_PROP_NVL);
191025c6ff4bSstephh 			}
1911e5dcf7beSRobert Johnston 		}
19126e1fa242SStephen Hanson 	}
191325c6ff4bSstephh 	return (0);
191425c6ff4bSstephh }
191525c6ff4bSstephh 
191625c6ff4bSstephh static int
hc_fmri_replaced(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)191725c6ff4bSstephh hc_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version,
191825c6ff4bSstephh     nvlist_t *in, nvlist_t **out)
191925c6ff4bSstephh {
192025c6ff4bSstephh 	int err;
192125c6ff4bSstephh 	struct hc_walk *hwp;
192225c6ff4bSstephh 	struct hc_args *hap;
192325c6ff4bSstephh 
192425c6ff4bSstephh 	if (version > TOPO_METH_REPLACED_VERSION)
192525c6ff4bSstephh 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
192625c6ff4bSstephh 
192725c6ff4bSstephh 	if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
192825c6ff4bSstephh 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
192925c6ff4bSstephh 
193025c6ff4bSstephh 	hap->ha_fmri = in;
193125c6ff4bSstephh 	hap->ha_nvl = NULL;
193225c6ff4bSstephh 	if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_is_replaced,
193325c6ff4bSstephh 	    (void *)hap)) != NULL) {
193425c6ff4bSstephh 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
193525c6ff4bSstephh 		    TOPO_WALK_ERR)
193625c6ff4bSstephh 			err = -1;
193725c6ff4bSstephh 		else
193825c6ff4bSstephh 			err = 0;
193925c6ff4bSstephh 		topo_walk_fini(hwp->hcw_wp);
194025c6ff4bSstephh 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
194125c6ff4bSstephh 	} else {
194225c6ff4bSstephh 		err = -1;
194325c6ff4bSstephh 	}
194425c6ff4bSstephh 
194525c6ff4bSstephh 	if (hap->ha_nvl != NULL)
194625c6ff4bSstephh 		*out = hap->ha_nvl;
194725c6ff4bSstephh 
194825c6ff4bSstephh 	topo_mod_free(mod, hap, sizeof (struct hc_args));
194925c6ff4bSstephh 
195025c6ff4bSstephh 	return (err);
195125c6ff4bSstephh }
195225c6ff4bSstephh 
195325c6ff4bSstephh static int
hc_unusable(topo_mod_t * mod,tnode_t * node,void * pdata)1954c40d7343Scindi hc_unusable(topo_mod_t *mod, tnode_t *node, void *pdata)
1955c40d7343Scindi {
1956c40d7343Scindi 	int err;
1957c40d7343Scindi 	struct hc_args *hap = (struct hc_args *)pdata;
1958c40d7343Scindi 
1959c40d7343Scindi 	/*
1960c40d7343Scindi 	 * check with the enumerator that created this FMRI
1961c40d7343Scindi 	 * (topo node)
1962c40d7343Scindi 	 */
1963c40d7343Scindi 	if (topo_method_invoke(node, TOPO_METH_UNUSABLE,
1964c40d7343Scindi 	    TOPO_METH_UNUSABLE_VERSION, hap->ha_fmri, &hap->ha_nvl,
1965c40d7343Scindi 	    &err) < 0) {
1966c40d7343Scindi 
1967c40d7343Scindi 		/*
1968c40d7343Scindi 		 * Err on the side of caution and return usable
1969c40d7343Scindi 		 */
1970c40d7343Scindi 		if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) == 0)
1971c40d7343Scindi 			if (nvlist_add_uint32(hap->ha_nvl,
1972c40d7343Scindi 			    TOPO_METH_UNUSABLE_RET, 0) == 0)
1973c40d7343Scindi 				return (0);
1974c40d7343Scindi 
1975c40d7343Scindi 		return (ETOPO_PROP_NVL);
1976c40d7343Scindi 	}
1977c40d7343Scindi 
1978e4b86885SCheng Sean Ye 	return (0);
1979c40d7343Scindi }
1980c40d7343Scindi 
1981c40d7343Scindi static int
hc_fmri_unusable(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)1982c40d7343Scindi hc_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1983c40d7343Scindi     nvlist_t *in, nvlist_t **out)
1984c40d7343Scindi {
1985c40d7343Scindi 	int err;
1986c40d7343Scindi 	struct hc_walk *hwp;
1987c40d7343Scindi 	struct hc_args *hap;
1988c40d7343Scindi 
1989c40d7343Scindi 	if (version > TOPO_METH_UNUSABLE_VERSION)
1990c40d7343Scindi 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1991c40d7343Scindi 
1992c40d7343Scindi 	if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
1993c40d7343Scindi 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1994c40d7343Scindi 
1995c40d7343Scindi 	hap->ha_fmri = in;
1996c40d7343Scindi 	hap->ha_nvl = NULL;
1997c40d7343Scindi 	if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_unusable,
1998c40d7343Scindi 	    (void *)hap)) != NULL) {
199978432d5eScy152378 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2000c40d7343Scindi 		    TOPO_WALK_ERR)
2001c40d7343Scindi 			err = -1;
2002c40d7343Scindi 		else
2003c40d7343Scindi 			err = 0;
2004c40d7343Scindi 		topo_walk_fini(hwp->hcw_wp);
2005918a0d8aSrobj 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2006c40d7343Scindi 	} else {
2007c40d7343Scindi 		err = -1;
2008c40d7343Scindi 	}
2009c40d7343Scindi 
2010c40d7343Scindi 	if (hap->ha_nvl != NULL)
2011c40d7343Scindi 		*out = hap->ha_nvl;
2012c40d7343Scindi 
2013c40d7343Scindi 	topo_mod_free(mod, hap, sizeof (struct hc_args));
2014c40d7343Scindi 
2015c40d7343Scindi 	return (err);
2016c40d7343Scindi }
2017825ba0f2Srobj 
2018825ba0f2Srobj struct fac_lookup {
2019825ba0f2Srobj 	const char *fl_fac_type;
2020825ba0f2Srobj 	uint32_t fl_fac_subtype;
2021825ba0f2Srobj #ifdef _LP64
2022825ba0f2Srobj 	uint64_t fl_callback;
2023825ba0f2Srobj 	uint64_t fl_callback_args;
2024825ba0f2Srobj #else
2025825ba0f2Srobj 	uint32_t fl_callback;
2026825ba0f2Srobj 	uint32_t fl_callback_args;
2027825ba0f2Srobj #endif
2028825ba0f2Srobj 	nvlist_t *fl_rsrc;
2029825ba0f2Srobj 	nvlist_t *fl_fac_rsrc;
2030825ba0f2Srobj };
2031825ba0f2Srobj 
2032825ba0f2Srobj static int
hc_fac_get(topo_mod_t * mod,tnode_t * node,void * pdata)2033825ba0f2Srobj hc_fac_get(topo_mod_t *mod, tnode_t *node, void *pdata)
2034825ba0f2Srobj {
2035825ba0f2Srobj 	struct fac_lookup *flp = (struct fac_lookup *)pdata;
2036825ba0f2Srobj 	topo_walk_cb_t cb = (topo_walk_cb_t)flp->fl_callback;
2037825ba0f2Srobj 	topo_faclist_t faclist, *tmp;
2038825ba0f2Srobj 	int err, ret = 0;
2039825ba0f2Srobj 
2040825ba0f2Srobj 	/*
2041825ba0f2Srobj 	 * Lookup the specified facility node.  Return with an error if we can't
2042825ba0f2Srobj 	 * find it.
2043825ba0f2Srobj 	 */
2044825ba0f2Srobj 	if (topo_node_facility(mod->tm_hdl, node, flp->fl_fac_type,
2045825ba0f2Srobj 	    flp->fl_fac_subtype, &faclist, &err) != 0) {
2046825ba0f2Srobj 		topo_mod_dprintf(mod, "hc_fac_get: topo_node_facility "
2047825ba0f2Srobj 		    "failed\n");
2048825ba0f2Srobj 		return (TOPO_WALK_ERR);
2049825ba0f2Srobj 	}
2050825ba0f2Srobj 
2051825ba0f2Srobj 	/*
2052825ba0f2Srobj 	 * Invoke user's callback for each facility node in the topo list,
2053825ba0f2Srobj 	 * passing in a pointer to the facility node
2054825ba0f2Srobj 	 */
2055825ba0f2Srobj 	for (tmp = topo_list_next(&faclist.tf_list); tmp != NULL;
2056825ba0f2Srobj 	    tmp = topo_list_next(tmp)) {
2057825ba0f2Srobj 
2058825ba0f2Srobj 		if ((err = cb(mod->tm_hdl, tmp->tf_node,
2059825ba0f2Srobj 		    (void *)flp->fl_callback_args)) != 0) {
2060825ba0f2Srobj 			(void) topo_mod_seterrno(mod, err);
2061825ba0f2Srobj 			topo_mod_dprintf(mod, "hc_fac_get: callback failed: "
2062825ba0f2Srobj 			    "%s\n ", topo_mod_errmsg(mod));
2063825ba0f2Srobj 			ret = TOPO_WALK_ERR;
2064825ba0f2Srobj 			break;
2065825ba0f2Srobj 		}
2066825ba0f2Srobj 	}
2067825ba0f2Srobj 
2068825ba0f2Srobj 	while ((tmp = topo_list_next(&faclist.tf_list)) != NULL) {
2069825ba0f2Srobj 		topo_list_delete(&faclist.tf_list, tmp);
2070825ba0f2Srobj 		topo_mod_free(mod, tmp, sizeof (topo_faclist_t));
2071825ba0f2Srobj 	}
2072825ba0f2Srobj 	return (ret);
2073825ba0f2Srobj }
2074825ba0f2Srobj 
2075825ba0f2Srobj static int
hc_fmri_facility(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)2076825ba0f2Srobj hc_fmri_facility(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2077825ba0f2Srobj     nvlist_t *in, nvlist_t **out)
2078825ba0f2Srobj {
2079825ba0f2Srobj 	int err = 0;
2080825ba0f2Srobj 	struct hc_walk *hwp;
2081825ba0f2Srobj 	struct fac_lookup *flp;
2082825ba0f2Srobj 
2083825ba0f2Srobj 	if (version > TOPO_METH_FACILITY_VERSION)
2084825ba0f2Srobj 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2085825ba0f2Srobj 
2086825ba0f2Srobj 	if ((flp = topo_mod_alloc(mod, sizeof (struct fac_lookup))) == NULL)
2087825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
2088825ba0f2Srobj 
2089825ba0f2Srobj 	/*
2090825ba0f2Srobj 	 * lookup arguments: hw resource, facility type, facility subtype,
2091825ba0f2Srobj 	 *  callback and callback args
2092825ba0f2Srobj 	 */
2093825ba0f2Srobj 	err = nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &flp->fl_rsrc);
2094825ba0f2Srobj 	err |= nvlist_lookup_string(in, FM_FMRI_FACILITY_TYPE,
2095825ba0f2Srobj 	    (char **)&flp->fl_fac_type);
2096825ba0f2Srobj 	err |= nvlist_lookup_uint32(in, "type", &flp->fl_fac_subtype);
2097825ba0f2Srobj #ifdef _LP64
2098825ba0f2Srobj 	err |= nvlist_lookup_uint64(in, "callback", &flp->fl_callback);
2099825ba0f2Srobj 	err |= nvlist_lookup_uint64(in, "callback-args",
2100825ba0f2Srobj 	    &flp->fl_callback_args);
2101825ba0f2Srobj #else
2102825ba0f2Srobj 	err |= nvlist_lookup_uint32(in, "callback", &flp->fl_callback);
2103825ba0f2Srobj 	err |= nvlist_lookup_uint32(in, "callback-args",
2104825ba0f2Srobj 	    &flp->fl_callback_args);
2105825ba0f2Srobj #endif
2106825ba0f2Srobj 	if (err != 0) {
2107825ba0f2Srobj 		topo_mod_dprintf(mod, "hc_fmri_facility: failed to construct "
2108825ba0f2Srobj 		    "walker arg nvlist\n");
2109825ba0f2Srobj 		topo_mod_free(mod, flp, sizeof (struct fac_lookup));
2110825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2111825ba0f2Srobj 	}
2112825ba0f2Srobj 
2113825ba0f2Srobj 	flp->fl_fac_rsrc = NULL;
2114825ba0f2Srobj 	if ((hwp = hc_walk_init(mod, node, flp->fl_rsrc, hc_fac_get,
2115825ba0f2Srobj 	    (void *)flp)) != NULL) {
2116825ba0f2Srobj 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2117825ba0f2Srobj 		    TOPO_WALK_ERR)
2118825ba0f2Srobj 			err = -1;
2119825ba0f2Srobj 		else
2120825ba0f2Srobj 			err = 0;
2121825ba0f2Srobj 		topo_walk_fini(hwp->hcw_wp);
2122825ba0f2Srobj 		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2123825ba0f2Srobj 	} else {
2124825ba0f2Srobj 		topo_mod_dprintf(mod, "hc_fmri_facility: failed to initialize "
2125825ba0f2Srobj 		    "hc walker\n");
2126825ba0f2Srobj 		err = -1;
2127825ba0f2Srobj 	}
2128825ba0f2Srobj 
2129825ba0f2Srobj 	if (flp->fl_fac_rsrc != NULL)
2130825ba0f2Srobj 		*out = flp->fl_fac_rsrc;
2131825ba0f2Srobj 
2132825ba0f2Srobj 	topo_mod_free(mod, flp, sizeof (struct fac_lookup));
2133825ba0f2Srobj 
2134825ba0f2Srobj 	return (err);
2135825ba0f2Srobj }
2136e4b86885SCheng Sean Ye 
2137e4b86885SCheng Sean Ye /* ARGSUSED */
2138e4b86885SCheng Sean Ye static int
hc_expand(topo_mod_t * mod,tnode_t * node,void * pdata)2139e4b86885SCheng Sean Ye hc_expand(topo_mod_t *mod, tnode_t *node, void *pdata)
2140e4b86885SCheng Sean Ye {
2141e4b86885SCheng Sean Ye 	int err;
2142e4b86885SCheng Sean Ye 	nvlist_t *nvl;
2143e4b86885SCheng Sean Ye 	const char **namep;
2144e4b86885SCheng Sean Ye 	struct hc_args *hap = (struct hc_args *)pdata;
2145e4b86885SCheng Sean Ye 	const char *names[] = {
2146e4b86885SCheng Sean Ye 		FM_FMRI_HC_SERIAL_ID,
2147e4b86885SCheng Sean Ye 		FM_FMRI_HC_PART,
2148e4b86885SCheng Sean Ye 		FM_FMRI_HC_REVISION,
2149e4b86885SCheng Sean Ye 		NULL
2150e4b86885SCheng Sean Ye 	};
2151e4b86885SCheng Sean Ye 
2152e4b86885SCheng Sean Ye 	if (topo_node_resource(node, &nvl, &err) != 0)
2153e4b86885SCheng Sean Ye 		return (ETOPO_METHOD_FAIL);
2154e4b86885SCheng Sean Ye 
2155e4b86885SCheng Sean Ye 	for (namep = names; *namep != NULL; namep++) {
2156e4b86885SCheng Sean Ye 		char *in_val, *node_val;
2157e4b86885SCheng Sean Ye 
2158e4b86885SCheng Sean Ye 		if (nvlist_lookup_string(nvl, *namep, &node_val) != 0)
2159e4b86885SCheng Sean Ye 			continue;
2160e4b86885SCheng Sean Ye 
2161e4b86885SCheng Sean Ye 		if (nvlist_lookup_string(hap->ha_fmri, *namep, &in_val) == 0) {
2162e4b86885SCheng Sean Ye 			if (strcmp(in_val, node_val) == 0)
2163e4b86885SCheng Sean Ye 				continue;
2164e4b86885SCheng Sean Ye 			(void) nvlist_remove(hap->ha_fmri, *namep,
2165e4b86885SCheng Sean Ye 			    DATA_TYPE_STRING);
2166e4b86885SCheng Sean Ye 		}
2167e4b86885SCheng Sean Ye 
2168e4b86885SCheng Sean Ye 		if (nvlist_add_string(hap->ha_fmri, *namep, node_val) != 0) {
2169e4b86885SCheng Sean Ye 			nvlist_free(nvl);
2170e4b86885SCheng Sean Ye 			return (ETOPO_PROP_NVL);
2171e4b86885SCheng Sean Ye 		}
2172e4b86885SCheng Sean Ye 	}
2173e4b86885SCheng Sean Ye 	nvlist_free(nvl);
2174e4b86885SCheng Sean Ye 
2175e4b86885SCheng Sean Ye 	return (0);
2176e4b86885SCheng Sean Ye }
2177e4b86885SCheng Sean Ye 
2178e4b86885SCheng Sean Ye /* ARGSUSED */
2179e4b86885SCheng Sean Ye static int
hc_fmri_expand(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)2180e4b86885SCheng Sean Ye hc_fmri_expand(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2181e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
2182e4b86885SCheng Sean Ye {
2183e4b86885SCheng Sean Ye 	int err;
2184e4b86885SCheng Sean Ye 	struct hc_walk *hwp;
2185e4b86885SCheng Sean Ye 	struct hc_args *hap;
2186e4b86885SCheng Sean Ye 
2187e4b86885SCheng Sean Ye 	if (version > TOPO_METH_EXPAND_VERSION)
2188e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2189e4b86885SCheng Sean Ye 
2190e4b86885SCheng Sean Ye 	if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
2191e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
2192e4b86885SCheng Sean Ye 
2193e4b86885SCheng Sean Ye 	hap->ha_fmri = in;
2194e4b86885SCheng Sean Ye 	hap->ha_nvl = NULL;
2195e4b86885SCheng Sean Ye 	if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_expand,
2196e4b86885SCheng Sean Ye 	    (void *)hap)) != NULL) {
2197e4b86885SCheng Sean Ye 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2198e4b86885SCheng Sean Ye 		    TOPO_WALK_ERR)
2199e4b86885SCheng Sean Ye 			err = -1;
2200e4b86885SCheng Sean Ye 		else
2201e4b86885SCheng Sean Ye 			err = 0;
2202e4b86885SCheng Sean Ye 		topo_walk_fini(hwp->hcw_wp);
2203e4b86885SCheng Sean Ye 	} else {
2204e4b86885SCheng Sean Ye 		err = -1;
2205e4b86885SCheng Sean Ye 	}
2206e4b86885SCheng Sean Ye 
2207e4b86885SCheng Sean Ye 	topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2208e4b86885SCheng Sean Ye 
2209e4b86885SCheng Sean Ye 	/* expand method should not return out nvlist */
2210e4b86885SCheng Sean Ye 	assert(hap->ha_nvl == NULL);
2211e4b86885SCheng Sean Ye 
2212e4b86885SCheng Sean Ye 	topo_mod_free(mod, hap, sizeof (struct hc_args));
2213e4b86885SCheng Sean Ye 
2214e4b86885SCheng Sean Ye 	return (err);
2215e4b86885SCheng Sean Ye }
2216e4b86885SCheng Sean Ye 
2217e4b86885SCheng Sean Ye static int
hc_retire_subr(topo_mod_t * mod,tnode_t * node,void * pdata)2218e4b86885SCheng Sean Ye hc_retire_subr(topo_mod_t *mod, tnode_t *node, void *pdata)
2219e4b86885SCheng Sean Ye {
2220e4b86885SCheng Sean Ye 	int err, rc;
2221e4b86885SCheng Sean Ye 	struct hc_args *hap = (struct hc_args *)pdata;
2222e4b86885SCheng Sean Ye 
2223e4b86885SCheng Sean Ye 	topo_mod_dprintf(mod, "hc_retire_subr: invoking method %s\n",
2224e4b86885SCheng Sean Ye 	    hap->ha_method_name);
2225e4b86885SCheng Sean Ye 	/*
2226e4b86885SCheng Sean Ye 	 * check with the enumerator that created this FMRI
2227e4b86885SCheng Sean Ye 	 * (topo node)
2228e4b86885SCheng Sean Ye 	 */
2229e4b86885SCheng Sean Ye 	rc = topo_method_invoke(node, hap->ha_method_name,
2230e4b86885SCheng Sean Ye 	    hap->ha_method_ver, hap->ha_fmri, &hap->ha_nvl, &err);
2231e4b86885SCheng Sean Ye 
2232e4b86885SCheng Sean Ye 	topo_mod_dprintf(mod, "hc_retire_subr: invoking method %s "
2233e4b86885SCheng Sean Ye 	    "returned %d\n", hap->ha_method_name, rc);
2234e4b86885SCheng Sean Ye 
2235e4b86885SCheng Sean Ye 	return (rc < 0 ? err : 0);
2236e4b86885SCheng Sean Ye }
2237e4b86885SCheng Sean Ye 
2238e4b86885SCheng 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)2239e4b86885SCheng Sean Ye hc_fmri_retire_subr(topo_mod_t *mod, tnode_t *node, char *method_name,
2240e4b86885SCheng Sean Ye     topo_version_t builtin_version, topo_version_t version, nvlist_t *in,
2241e4b86885SCheng Sean Ye     nvlist_t **out)
2242e4b86885SCheng Sean Ye {
2243e4b86885SCheng Sean Ye 	int err;
2244e4b86885SCheng Sean Ye 	struct hc_walk *hwp;
2245e4b86885SCheng Sean Ye 	struct hc_args *hap;
2246e4b86885SCheng Sean Ye 
2247e4b86885SCheng Sean Ye 	if (version > builtin_version)
2248e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2249e4b86885SCheng Sean Ye 
2250e4b86885SCheng Sean Ye 	if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
2251e4b86885SCheng Sean Ye 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
2252e4b86885SCheng Sean Ye 
2253e4b86885SCheng Sean Ye 	hap->ha_fmri = in;
2254e4b86885SCheng Sean Ye 	hap->ha_nvl = NULL;
2255e4b86885SCheng Sean Ye 	hap->ha_method_name = method_name;
2256e4b86885SCheng Sean Ye 	hap->ha_method_ver = version;
2257e4b86885SCheng Sean Ye 	if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_retire_subr,
2258e4b86885SCheng Sean Ye 	    (void *)hap)) != NULL) {
2259e4b86885SCheng Sean Ye 		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2260e4b86885SCheng Sean Ye 		    TOPO_WALK_ERR)
2261e4b86885SCheng Sean Ye 			err = -1;
2262e4b86885SCheng Sean Ye 		else
2263e4b86885SCheng Sean Ye 			err = 0;
2264e4b86885SCheng Sean Ye 		topo_walk_fini(hwp->hcw_wp);
2265e4b86885SCheng Sean Ye 	} else {
2266e4b86885SCheng Sean Ye 		err = -1;
2267e4b86885SCheng Sean Ye 	}
2268e4b86885SCheng Sean Ye 
2269e4b86885SCheng Sean Ye 	topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2270e4b86885SCheng Sean Ye 
2271e4b86885SCheng Sean Ye 	if (hap->ha_nvl != NULL)
2272e4b86885SCheng Sean Ye 		*out = hap->ha_nvl;
2273e4b86885SCheng Sean Ye 
2274e4b86885SCheng Sean Ye 	topo_mod_free(mod, hap, sizeof (struct hc_args));
2275e4b86885SCheng Sean Ye 
2276e4b86885SCheng Sean Ye 	return (err);
2277e4b86885SCheng Sean Ye }
2278e4b86885SCheng Sean Ye 
2279e4b86885SCheng Sean Ye static int
hc_fmri_retire(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)2280e4b86885SCheng Sean Ye hc_fmri_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2281e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
2282e4b86885SCheng Sean Ye {
2283e4b86885SCheng Sean Ye 	return (hc_fmri_retire_subr(mod, node, TOPO_METH_RETIRE,
2284e4b86885SCheng Sean Ye 	    TOPO_METH_RETIRE_VERSION, version, in, out));
2285e4b86885SCheng Sean Ye }
2286e4b86885SCheng Sean Ye 
2287e4b86885SCheng Sean Ye static int
hc_fmri_unretire(topo_mod_t * mod,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)2288e4b86885SCheng Sean Ye hc_fmri_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2289e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
2290e4b86885SCheng Sean Ye {
2291e4b86885SCheng Sean Ye 	return (hc_fmri_retire_subr(mod, node, TOPO_METH_UNRETIRE,
2292e4b86885SCheng Sean Ye 	    TOPO_METH_UNRETIRE_VERSION, version, in, out));
2293e4b86885SCheng Sean Ye }
2294e4b86885SCheng Sean Ye 
2295e4b86885SCheng 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)2296e4b86885SCheng Sean Ye hc_fmri_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2297e4b86885SCheng Sean Ye     nvlist_t *in, nvlist_t **out)
2298e4b86885SCheng Sean Ye {
2299e4b86885SCheng Sean Ye 	return (hc_fmri_retire_subr(mod, node, TOPO_METH_SERVICE_STATE,
2300e4b86885SCheng Sean Ye 	    TOPO_METH_SERVICE_STATE_VERSION, version, in, out));
2301e4b86885SCheng Sean Ye }
2302