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