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 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 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 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 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 3757aec1d6eScindi hc_release(topo_mod_t *mp, tnode_t *node) 3767aec1d6eScindi { 3777aec1d6eScindi topo_method_unregister_all(mp, node); 3787aec1d6eScindi } 3797aec1d6eScindi 3807aec1d6eScindi static int 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 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 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 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 * 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 ** 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 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 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 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 * 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 * 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 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 * 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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