2N/A/*
2N/A *
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <errno.h>
2N/A#include <ctype.h>
2N/A#include <alloca.h>
2N/A#include <assert.h>
2N/A#include <limits.h>
2N/A#include <zone.h>
2N/A#include <fm/topo_mod.h>
2N/A#include <fm/topo_hc.h>
2N/A#include <fm/fmd_fmri.h>
2N/A#include <sys/param.h>
2N/A#include <sys/systeminfo.h>
2N/A#include <sys/fm/protocol.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/systeminfo.h>
2N/A#include <sys/utsname.h>
2N/A#include <sys/libdevid.h>
2N/A
2N/A#include <topo_method.h>
2N/A#include <topo_module.h>
2N/A#include <topo_subr.h>
2N/A#include <topo_prop.h>
2N/A#include <topo_tree.h>
2N/A#include <topo_fmri.h>
2N/A#include <hc.h>
2N/A
2N/Astatic int hc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
2N/A topo_instance_t, void *, void *);
2N/Astatic void hc_release(topo_mod_t *, tnode_t *);
2N/Astatic int hc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int hc_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int hc_fmri_presence_state(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int hc_fmri_retire(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
2N/A nvlist_t **);
2N/Astatic int hc_fmri_unretire(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
2N/A nvlist_t **);
2N/Astatic int hc_fmri_service_state(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int hc_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int hc_fmri_prop_get(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int hc_fmri_prop_set(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int hc_fmri_pgrp_get(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int hc_fmri_strcmp_path(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int hc_fmri_strcmp_ident(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int hc_fmri_ident_node(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int hc_fmri_strhash_path(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int hc_fmri_facility(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/A
2N/Astatic nvlist_t *hc_fmri_create(topo_mod_t *, nvlist_t *, int, const char *,
2N/A topo_instance_t inst, const nvlist_t *, const char *, const char *,
2N/A const char *);
2N/A
2N/Aconst topo_method_t hc_methods[] = {
2N/A { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION,
2N/A TOPO_STABILITY_INTERNAL, hc_fmri_nvl2str },
2N/A { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION,
2N/A TOPO_STABILITY_INTERNAL, hc_fmri_str2nvl },
2N/A { TOPO_METH_PRESENCE_STATE, TOPO_METH_PRESENCE_STATE_DESC,
2N/A TOPO_METH_PRESENCE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
2N/A hc_fmri_presence_state },
2N/A { TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
2N/A TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
2N/A hc_fmri_retire },
2N/A { TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
2N/A TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
2N/A hc_fmri_unretire },
2N/A { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
2N/A TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
2N/A hc_fmri_service_state },
2N/A { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION,
2N/A TOPO_STABILITY_INTERNAL, hc_fmri_create_meth },
2N/A { TOPO_METH_PROP_GET, TOPO_METH_PROP_GET_DESC,
2N/A TOPO_METH_PROP_GET_VERSION, TOPO_STABILITY_INTERNAL,
2N/A hc_fmri_prop_get },
2N/A { TOPO_METH_PROP_SET, TOPO_METH_PROP_SET_DESC,
2N/A TOPO_METH_PROP_SET_VERSION, TOPO_STABILITY_INTERNAL,
2N/A hc_fmri_prop_set },
2N/A { TOPO_METH_PGRP_GET, TOPO_METH_PGRP_GET_DESC,
2N/A TOPO_METH_PGRP_GET_VERSION, TOPO_STABILITY_INTERNAL,
2N/A hc_fmri_pgrp_get },
2N/A { TOPO_METH_STRCMP_PATH, TOPO_METH_STRCMP_PATH_DESC,
2N/A TOPO_METH_STRCMP_VERSION, TOPO_STABILITY_INTERNAL,
2N/A hc_fmri_strcmp_path },
2N/A { TOPO_METH_STRHASH_PATH, TOPO_METH_STRHASH_PATH_DESC,
2N/A TOPO_METH_STRHASH_VERSION, TOPO_STABILITY_INTERNAL,
2N/A hc_fmri_strhash_path },
2N/A { TOPO_METH_STRCMP_IDENT, TOPO_METH_STRCMP_IDENT_DESC,
2N/A TOPO_METH_STRCMP_VERSION, TOPO_STABILITY_INTERNAL,
2N/A hc_fmri_strcmp_ident },
2N/A { TOPO_METH_IDENT_NODE, TOPO_METH_IDENT_NODE_DESC,
2N/A TOPO_METH_IDENT_NODE_VERSION, TOPO_STABILITY_INTERNAL,
2N/A hc_fmri_ident_node },
2N/A { TOPO_METH_FACILITY, TOPO_METH_FACILITY_DESC,
2N/A TOPO_METH_FACILITY_VERSION, TOPO_STABILITY_INTERNAL,
2N/A hc_fmri_facility },
2N/A { NULL }
2N/A};
2N/A
2N/Astatic const topo_modops_t hc_ops =
2N/A { hc_enum, hc_release };
2N/Astatic const topo_modinfo_t hc_info =
2N/A { HC, FM_FMRI_SCHEME_HC, HC_VERSION, &hc_ops };
2N/A
2N/Astatic const hcc_t hc_canon[] = {
2N/A { BANK, TOPO_STABILITY_PRIVATE },
2N/A { BAY, TOPO_STABILITY_PRIVATE },
2N/A { BLADE, TOPO_STABILITY_PRIVATE },
2N/A { BRANCH, TOPO_STABILITY_PRIVATE },
2N/A { CMP, TOPO_STABILITY_PRIVATE },
2N/A { CENTERPLANE, TOPO_STABILITY_PRIVATE },
2N/A { CHASSIS, TOPO_STABILITY_PRIVATE },
2N/A { CHIP, TOPO_STABILITY_PRIVATE },
2N/A { CHIP_SELECT, TOPO_STABILITY_PRIVATE },
2N/A { CORE, TOPO_STABILITY_PRIVATE },
2N/A { CONTROLLER, TOPO_STABILITY_PRIVATE },
2N/A { CPU, TOPO_STABILITY_PRIVATE },
2N/A { CPUBOARD, TOPO_STABILITY_PRIVATE },
2N/A { DIMM, TOPO_STABILITY_PRIVATE },
2N/A { DISK, TOPO_STABILITY_PRIVATE },
2N/A { DRAM, TOPO_STABILITY_PRIVATE },
2N/A { DRAMCHANNEL, TOPO_STABILITY_PRIVATE },
2N/A { EXTERNALCHASSIS, TOPO_STABILITY_PRIVATE },
2N/A { FAN, TOPO_STABILITY_PRIVATE },
2N/A { FANBOARD, TOPO_STABILITY_PRIVATE },
2N/A { FANMODULE, TOPO_STABILITY_PRIVATE },
2N/A { HBA, TOPO_STABILITY_PRIVATE },
2N/A { HOSTBRIDGE, TOPO_STABILITY_PRIVATE },
2N/A { INTERCONNECT, TOPO_STABILITY_PRIVATE },
2N/A { IOBOARD, TOPO_STABILITY_PRIVATE },
2N/A { IPORT, TOPO_STABILITY_PRIVATE },
2N/A { MEMBOARD, TOPO_STABILITY_PRIVATE },
2N/A { MEMORYBUFFER, TOPO_STABILITY_PRIVATE },
2N/A { MEMORYCONTROL, TOPO_STABILITY_PRIVATE },
2N/A { MICROCORE, TOPO_STABILITY_PRIVATE },
2N/A { MOTHERBOARD, TOPO_STABILITY_PRIVATE },
2N/A { NIU, TOPO_STABILITY_PRIVATE },
2N/A { NIUFN, TOPO_STABILITY_PRIVATE },
2N/A { PCI_BUS, TOPO_STABILITY_PRIVATE },
2N/A { PCI_DEVICE, TOPO_STABILITY_PRIVATE },
2N/A { PCI_FUNCTION, TOPO_STABILITY_PRIVATE },
2N/A { PCIEX_BUS, TOPO_STABILITY_PRIVATE },
2N/A { PCIEX_DEVICE, TOPO_STABILITY_PRIVATE },
2N/A { PCIEX_FUNCTION, TOPO_STABILITY_PRIVATE },
2N/A { PCIEX_ROOT, TOPO_STABILITY_PRIVATE },
2N/A { PCIEX_SWUP, TOPO_STABILITY_PRIVATE },
2N/A { PCIEX_SWDWN, TOPO_STABILITY_PRIVATE },
2N/A { POWERBOARD, TOPO_STABILITY_PRIVATE },
2N/A { POWERMODULE, TOPO_STABILITY_PRIVATE },
2N/A { PSU, TOPO_STABILITY_PRIVATE },
2N/A { RANK, TOPO_STABILITY_PRIVATE },
2N/A { RECEPTACLE, TOPO_STABILITY_PRIVATE },
2N/A { RISER, TOPO_STABILITY_PRIVATE },
2N/A { SASEXPANDER, TOPO_STABILITY_PRIVATE },
2N/A { SCSI_DEVICE, TOPO_STABILITY_PRIVATE },
2N/A { SHELF, TOPO_STABILITY_PRIVATE },
2N/A { SES_ENCLOSURE, TOPO_STABILITY_PRIVATE },
2N/A { SMP_DEVICE, TOPO_STABILITY_PRIVATE },
2N/A { SP, TOPO_STABILITY_PRIVATE },
2N/A { STRAND, TOPO_STABILITY_PRIVATE },
2N/A { SUBCHASSIS, TOPO_STABILITY_PRIVATE },
2N/A { SYSTEMBOARD, TOPO_STABILITY_PRIVATE },
2N/A { USB_BUS, TOPO_STABILITY_PRIVATE },
2N/A { USB_HUB, TOPO_STABILITY_PRIVATE },
2N/A { USB_DEV, TOPO_STABILITY_PRIVATE },
2N/A { USB_IFC, TOPO_STABILITY_PRIVATE },
2N/A { XAUI, TOPO_STABILITY_PRIVATE },
2N/A { XFP, TOPO_STABILITY_PRIVATE }
2N/A};
2N/A
2N/Astatic int hc_ncanon = sizeof (hc_canon) / sizeof (hcc_t);
2N/A
2N/Aint
2N/Ahc_init(topo_mod_t *mod, topo_version_t version)
2N/A{
2N/A /*
2N/A * Turn on module debugging output
2N/A */
2N/A if (getenv("TOPOHCDEBUG"))
2N/A topo_mod_setdebug(mod);
2N/A
2N/A topo_mod_dprintf(mod, "initializing hc builtin\n");
2N/A
2N/A if (version != HC_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A
2N/A if (topo_mod_register(mod, &hc_info, TOPO_VERSION) != 0) {
2N/A topo_mod_dprintf(mod, "failed to register hc: "
2N/A "%s\n", topo_mod_errmsg(mod));
2N/A return (-1); /* mod errno already set */
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Avoid
2N/Ahc_fini(topo_mod_t *mod)
2N/A{
2N/A topo_mod_unregister(mod);
2N/A}
2N/A
2N/A
2N/Astatic const topo_pgroup_info_t sys_pgroup = {
2N/A TOPO_PGROUP_SYSTEM,
2N/A TOPO_STABILITY_PRIVATE,
2N/A TOPO_STABILITY_PRIVATE,
2N/A 1
2N/A};
2N/A
2N/Astatic const topo_pgroup_info_t auth_pgroup = {
2N/A FM_FMRI_AUTHORITY,
2N/A TOPO_STABILITY_PRIVATE,
2N/A TOPO_STABILITY_PRIVATE,
2N/A 1
2N/A};
2N/A
2N/Astatic void
2N/Ahc_prop_set(tnode_t *node, nvlist_t *auth)
2N/A{
2N/A int err;
2N/A char isa[MAXNAMELEN];
2N/A struct utsname uts;
2N/A char *alias, *mfg, *ch, *cpn, *csn;
2N/A
2N/A if (auth == NULL)
2N/A return;
2N/A
2N/A if (topo_pgroup_create(node, &auth_pgroup, &err) != 0) {
2N/A if (err != ETOPO_PROP_DEFD)
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * Inherit if we can, it saves memory
2N/A */
2N/A if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY,
2N/A FM_FMRI_AUTH_V1_CHASSIS_MFG, &err) != 0) &&
2N/A (err != ETOPO_PROP_DEFD)) {
2N/A if (nvlist_lookup_string(auth, FM_FMRI_AUTH_V1_CHASSIS_MFG,
2N/A &mfg) == 0)
2N/A (void) topo_prop_set_string(node,
2N/A FM_FMRI_AUTHORITY, FM_FMRI_AUTH_V1_CHASSIS_MFG,
2N/A TOPO_PROP_IMMUTABLE, mfg, &err);
2N/A }
2N/A if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY,
2N/A FM_FMRI_AUTH_V1_CHASSIS_NM, &err) != 0) &&
2N/A (err != ETOPO_PROP_DEFD)) {
2N/A if (nvlist_lookup_string(auth, FM_FMRI_AUTH_V1_CHASSIS_NM,
2N/A &ch) == 0)
2N/A (void) topo_prop_set_string(node,
2N/A FM_FMRI_AUTHORITY, FM_FMRI_AUTH_V1_CHASSIS_NM,
2N/A TOPO_PROP_IMMUTABLE, ch, &err);
2N/A }
2N/A if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY,
2N/A FM_FMRI_AUTH_V1_CHASSIS_PN, &err) != 0) &&
2N/A (err != ETOPO_PROP_DEFD)) {
2N/A if (nvlist_lookup_string(auth, FM_FMRI_AUTH_V1_CHASSIS_PN,
2N/A &cpn) == 0)
2N/A (void) topo_prop_set_string(node,
2N/A FM_FMRI_AUTHORITY, FM_FMRI_AUTH_V1_CHASSIS_PN,
2N/A TOPO_PROP_IMMUTABLE, cpn, &err);
2N/A }
2N/A if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY,
2N/A FM_FMRI_AUTH_V1_CHASSIS_SN, &err) != 0) &&
2N/A (err != ETOPO_PROP_DEFD)) {
2N/A if (nvlist_lookup_string(auth, FM_FMRI_AUTH_V1_CHASSIS_SN,
2N/A &csn) == 0)
2N/A (void) topo_prop_set_string(node,
2N/A FM_FMRI_AUTHORITY, FM_FMRI_AUTH_V1_CHASSIS_SN,
2N/A TOPO_PROP_IMMUTABLE, csn, &err);
2N/A }
2N/A if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY,
2N/A FM_FMRI_AUTH_V1_CHASSIS_ALIAS, &err) != 0) &&
2N/A (err != ETOPO_PROP_DEFD)) {
2N/A if (nvlist_lookup_string(auth, FM_FMRI_AUTH_V1_CHASSIS_ALIAS,
2N/A &alias) == 0)
2N/A (void) topo_prop_set_string(node,
2N/A FM_FMRI_AUTHORITY, FM_FMRI_AUTH_V1_CHASSIS_ALIAS,
2N/A TOPO_PROP_IMMUTABLE, alias, &err);
2N/A }
2N/A
2N/A if (topo_pgroup_create(node, &sys_pgroup, &err) != 0)
2N/A return;
2N/A
2N/A isa[0] = '\0';
2N/A (void) sysinfo(SI_ARCHITECTURE, isa, sizeof (isa));
2N/A (void) uname(&uts);
2N/A (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
2N/A TOPO_PROP_IMMUTABLE, isa, &err);
2N/A (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE,
2N/A TOPO_PROP_IMMUTABLE, uts.machine, &err);
2N/A (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM,
2N/A FM_FMRI_AUTH_V1_SERVER_NM, TOPO_PROP_IMMUTABLE, uts.nodename, &err);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/Ahc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min,
2N/A topo_instance_t max, void *notused1, void *notused2)
2N/A{
2N/A int isglobal = (getzoneid() == GLOBAL_ZONEID);
2N/A nvlist_t *pfmri = NULL;
2N/A nvlist_t *nvl;
2N/A nvlist_t *auth;
2N/A tnode_t *node;
2N/A int err;
2N/A /*
2N/A * Register root node methods
2N/A */
2N/A if (strcmp(name, HC) == 0) {
2N/A (void) topo_method_register(mod, pnode, hc_methods);
2N/A return (0);
2N/A }
2N/A if (min != max) {
2N/A topo_mod_dprintf(mod,
2N/A "Request to enumerate %s component with an "
2N/A "ambiguous instance number, min (%d) != max (%d).\n",
2N/A HC, min, max);
2N/A return (topo_mod_seterrno(mod, EINVAL));
2N/A }
2N/A
2N/A if (!isglobal)
2N/A return (0);
2N/A
2N/A /* check for authority, create if none */
2N/A if (mod->tm_hdl->th_auth == NULL) {
2N/A topo_mod_dprintf(mod, "Create authority.\n");
2N/A topo_auth_create(mod->tm_hdl);
2N/A }
2N/A
2N/A (void) topo_node_resource(pnode, &pfmri, &err);
2N/A auth = topo_mod_auth(mod, pnode);
2N/A nvl = hc_fmri_create(mod, pfmri, FM_HC_SCHEME_VERSION, name, min,
2N/A auth, NULL, NULL, NULL);
2N/A nvlist_free(pfmri); /* callee ignores NULLs */
2N/A if (nvl == NULL) {
2N/A nvlist_free(auth);
2N/A return (-1);
2N/A }
2N/A
2N/A if ((node = topo_node_bind(mod, pnode, name, min, nvl)) == NULL) {
2N/A topo_mod_dprintf(mod, "topo_node_bind failed: %s\n",
2N/A topo_strerror(topo_mod_errno(mod)));
2N/A nvlist_free(auth);
2N/A nvlist_free(nvl);
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * Set FRU for the motherboard node
2N/A */
2N/A if (strcmp(name, MOTHERBOARD) == 0)
2N/A (void) topo_node_fru_set(node, nvl, 0, &err);
2N/A
2N/A hc_prop_set(node, auth);
2N/A nvlist_free(nvl);
2N/A nvlist_free(auth);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic void
2N/Ahc_release(topo_mod_t *mp, tnode_t *node)
2N/A{
2N/A topo_method_unregister_all(mp, node);
2N/A}
2N/A
2N/Astatic void
2N/Afmristr_hcs_build(ssize_t *sz, char *buf, size_t buflen, nvlist_t *hcs,
2N/A char *hcsn)
2N/A{
2N/A uint64_t hcsv;
2N/A char decstr[30];
2N/A
2N/A if (nvlist_lookup_uint64(hcs, hcsn, &hcsv) == 0) {
2N/A (void) snprintf(decstr, sizeof (decstr), "%llu", hcsv);
2N/A topo_fmristr_build(sz, buf, buflen, "/", NULL, NULL);
2N/A topo_fmristr_build(sz, buf, buflen, "=", hcsn, decstr);
2N/A }
2N/A}
2N/A
2N/Astatic ssize_t
2N/Afmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
2N/A{
2N/A nvlist_t **hcprs = NULL;
2N/A nvlist_t *hcsp = NULL;
2N/A nvlist_t *anvl = NULL;
2N/A nvpair_t *apair;
2N/A nvlist_t *fnvl;
2N/A uint8_t version;
2N/A ssize_t size = 0;
2N/A uint_t hcnprs;
2N/A char *devid = NULL;
2N/A char *parent_serial = NULL;
2N/A char *serial = NULL;
2N/A char *part = NULL;
2N/A char *root = NULL;
2N/A char *rev = NULL;
2N/A char *aname, *aval;
2N/A char *fname = NULL, *ftype = NULL;
2N/A int err, i;
2N/A
2N/A if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
2N/A version > FM_HC_SCHEME_VERSION)
2N/A return (0);
2N/A
2N/A /* Get authority, if present */
2N/A err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl);
2N/A if (err != 0 && err != ENOENT)
2N/A return (0);
2N/A
2N/A (void) nvlist_lookup_string(nvl, FM_FMRI_HC_ROOT, &root);
2N/A
2N/A err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs);
2N/A if (err != 0 || hcprs == NULL)
2N/A return (0);
2N/A
2N/A if (version == FM_HC_VERS0) {
2N/A (void) nvlist_lookup_string(nvl, FM_FMRI_HC_V0_SERIAL,
2N/A &serial);
2N/A (void) nvlist_lookup_string(nvl, FM_FMRI_HC_V0_PART, &part);
2N/A (void) nvlist_lookup_string(nvl, FM_FMRI_HC_V0_REVISION, &rev);
2N/A } else {
2N/A (void) nvlist_lookup_string(nvl, FM_FMRI_HC_V1_FRU_SN, &serial);
2N/A (void) nvlist_lookup_string(nvl, FM_FMRI_HC_V1_FRU_PN, &part);
2N/A (void) nvlist_lookup_string(nvl, FM_FMRI_HC_V1_FRU_REV, &rev);
2N/A }
2N/A (void) nvlist_lookup_string(nvl, FM_FMRI_HC_DEVID, &devid);
2N/A (void) nvlist_lookup_string(nvl, FM_FMRI_HC_PARENT_SERIAL,
2N/A &parent_serial);
2N/A
2N/A /* hc:// */
2N/A topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_HC, NULL, "://");
2N/A
2N/A /* authority, if any */
2N/A if (anvl != NULL) {
2N/A for (apair = nvlist_next_nvpair(anvl, NULL);
2N/A apair != NULL; apair = nvlist_next_nvpair(anvl, apair)) {
2N/A if (nvpair_type(apair) != DATA_TYPE_STRING ||
2N/A nvpair_value_string(apair, &aval) != 0)
2N/A continue;
2N/A aname = nvpair_name(apair);
2N/A /* omit chassis alias */
2N/A if (strcmp(aname, FM_FMRI_AUTH_V1_CHASSIS_ALIAS) == 0)
2N/A continue;
2N/A topo_fmristr_build(&size, buf, buflen, ":", NULL, NULL);
2N/A topo_fmristr_build(&size, buf, buflen, "=",
2N/A aname, aval);
2N/A }
2N/A }
2N/A
2N/A /* hardware-id part */
2N/A if (version == FM_HC_VERS0) {
2N/A topo_fmristr_build(&size,
2N/A buf, buflen, serial, ":" FM_FMRI_HC_V0_SERIAL "=", NULL);
2N/A topo_fmristr_build(&size,
2N/A buf, buflen, part, ":" FM_FMRI_HC_V0_PART "=", NULL);
2N/A topo_fmristr_build(&size,
2N/A buf, buflen, rev, ":" FM_FMRI_HC_V0_REVISION "=", NULL);
2N/A } else {
2N/A topo_fmristr_build(&size,
2N/A buf, buflen, serial, ":" FM_FMRI_HC_V1_FRU_SN "=", NULL);
2N/A topo_fmristr_build(&size,
2N/A buf, buflen, part, ":" FM_FMRI_HC_V1_FRU_PN "=", NULL);
2N/A topo_fmristr_build(&size,
2N/A buf, buflen, rev, ":" FM_FMRI_HC_V1_FRU_REV "=", NULL);
2N/A }
2N/A topo_fmristr_build(&size,
2N/A buf, buflen, devid, ":" FM_FMRI_HC_DEVID "=", NULL);
2N/A topo_fmristr_build(&size,
2N/A buf, buflen, parent_serial, ":" FM_FMRI_HC_PARENT_SERIAL "=", NULL);
2N/A
2N/A /* separating slash */
2N/A topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL);
2N/A
2N/A /* hc-root */
2N/A if (root)
2N/A topo_fmristr_build(&size, buf, buflen, root, NULL, NULL);
2N/A
2N/A /* all the pairs */
2N/A for (i = 0; i < hcnprs; i++) {
2N/A char *nm = NULL;
2N/A char *id = NULL;
2N/A
2N/A if (i > 0)
2N/A topo_fmristr_build(&size,
2N/A buf, buflen, "/", NULL, NULL);
2N/A (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_NAME, &nm);
2N/A (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_ID, &id);
2N/A if (nm == NULL || id == NULL)
2N/A return (0);
2N/A topo_fmristr_build(&size, buf, buflen, nm, NULL, "=");
2N/A topo_fmristr_build(&size, buf, buflen, id, NULL, NULL);
2N/A }
2N/A
2N/A if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) {
2N/A char *hcsn = NULL;
2N/A char hexstr[17];
2N/A uint64_t val;
2N/A
2N/A /* append offset/physaddr if it exists in hc-specific */
2N/A if (nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET,
2N/A &val) == 0 || nvlist_lookup_uint64(hcsp,
2N/A "asru-" FM_FMRI_HC_SPECIFIC_OFFSET, &val) == 0)
2N/A hcsn = FM_FMRI_HC_SPECIFIC_OFFSET;
2N/A else if (nvlist_lookup_uint64(hcsp,
2N/A FM_FMRI_HC_SPECIFIC_PHYSADDR, &val) == 0 ||
2N/A nvlist_lookup_uint64(hcsp,
2N/A "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR, &val) == 0)
2N/A hcsn = FM_FMRI_HC_SPECIFIC_PHYSADDR;
2N/A
2N/A if (hcsn != NULL) {
2N/A (void) snprintf(hexstr, sizeof (hexstr), "%llx", val);
2N/A topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL);
2N/A topo_fmristr_build(&size, buf, buflen, "=", hcsn,
2N/A hexstr);
2N/A } else {
2N/A /* append l2cache/l3cache/cacheindex/cacheway */
2N/A fmristr_hcs_build(&size, buf, buflen, hcsp,
2N/A FM_FMRI_HC_SPECIFIC_L2CACHE);
2N/A fmristr_hcs_build(&size, buf, buflen, hcsp,
2N/A FM_FMRI_HC_SPECIFIC_L3CACHE);
2N/A fmristr_hcs_build(&size, buf, buflen, hcsp,
2N/A FM_FMRI_HC_SPECIFIC_CACHEINDEX);
2N/A fmristr_hcs_build(&size, buf, buflen, hcsp,
2N/A FM_FMRI_HC_SPECIFIC_CACHEWAY);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * If the nvlist represents a facility node, then we append the
2N/A * facility type and name to the end of the string representation using
2N/A * the format below:
2N/A *
2N/A * ?<ftype>=<fname>
2N/A */
2N/A if (nvlist_lookup_nvlist(nvl, FM_FMRI_FACILITY, &fnvl) == 0) {
2N/A if (nvlist_lookup_string(fnvl, FM_FMRI_FACILITY_NAME,
2N/A &fname) != 0 || nvlist_lookup_string(fnvl,
2N/A FM_FMRI_FACILITY_TYPE, &ftype) != 0)
2N/A return (0);
2N/A topo_fmristr_build(&size, buf, buflen, "?", NULL, NULL);
2N/A topo_fmristr_build(&size, buf, buflen, "=", ftype, fname);
2N/A }
2N/A
2N/A return (size);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *nvl, nvlist_t **out)
2N/A{
2N/A ssize_t len;
2N/A char *name = NULL;
2N/A nvlist_t *fmristr;
2N/A
2N/A if (version > TOPO_METH_NVL2STR_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A
2N/A if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 ||
2N/A (name = topo_mod_alloc(mod, len + 1)) == NULL ||
2N/A fmri_nvl2str(nvl, name, len + 1) == 0) {
2N/A if (name != NULL)
2N/A topo_mod_free(mod, name, len + 1);
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
2N/A }
2N/A
2N/A if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) {
2N/A topo_mod_free(mod, name, len + 1);
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
2N/A }
2N/A if (nvlist_add_string(fmristr, "fmri-string", name) != 0) {
2N/A topo_mod_free(mod, name, len + 1);
2N/A nvlist_free(fmristr);
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
2N/A }
2N/A topo_mod_free(mod, name, len + 1);
2N/A *out = fmristr;
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic nvlist_t *
2N/Ahc_base_fmri_create(topo_mod_t *mod, const nvlist_t *auth, const char *part,
2N/A const char *rev, const char *serial, const char *devid,
2N/A const char *parent_serial)
2N/A{
2N/A nvlist_t *fmri;
2N/A int err = 0;
2N/A
2N/A /*
2N/A * Create base HC nvlist
2N/A */
2N/A if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0)
2N/A return (NULL);
2N/A
2N/A err = nvlist_add_uint8(fmri, FM_VERSION, FM_HC_SCHEME_VERSION);
2N/A err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC);
2N/A err |= nvlist_add_string(fmri, FM_FMRI_HC_ROOT, "");
2N/A if (err != 0) {
2N/A nvlist_free(fmri);
2N/A return (NULL);
2N/A }
2N/A
2N/A /*
2N/A * Add optional payload members
2N/A */
2N/A if (serial != NULL)
2N/A (void) nvlist_add_string(fmri, FM_FMRI_HC_V1_FRU_SN, serial);
2N/A if (devid != NULL)
2N/A (void) nvlist_add_string(fmri, FM_FMRI_HC_DEVID, devid);
2N/A if (parent_serial != NULL)
2N/A (void) nvlist_add_string(fmri, FM_FMRI_HC_PARENT_SERIAL,
2N/A parent_serial);
2N/A if (part != NULL)
2N/A (void) nvlist_add_string(fmri, FM_FMRI_HC_V1_FRU_PN, part);
2N/A if (rev != NULL)
2N/A (void) nvlist_add_string(fmri, FM_FMRI_HC_V1_FRU_REV, rev);
2N/A if (auth != NULL)
2N/A (void) nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
2N/A (nvlist_t *)auth);
2N/A
2N/A return (fmri);
2N/A}
2N/A
2N/Astatic nvlist_t **
2N/Amake_hc_pairs(topo_mod_t *mod, char *fmri, int *num)
2N/A{
2N/A nvlist_t **pa;
2N/A char *hc, *fromstr;
2N/A char *starti, *startn, *endi, *endi2;
2N/A char *ne, *ns;
2N/A char *cname = NULL;
2N/A char *find;
2N/A char *cid = NULL;
2N/A int nslashes = 0;
2N/A int npairs = 0;
2N/A int i, hclen;
2N/A
2N/A if ((hc = topo_mod_strdup(mod, fmri + 5)) == NULL)
2N/A return (NULL);
2N/A
2N/A hclen = strlen(hc) + 1;
2N/A
2N/A /*
2N/A * Count equal signs and slashes to determine how many
2N/A * hc-pairs will be present in the final FMRI. There should
2N/A * be at least as many slashes as equal signs. There can be
2N/A * more, though if the string after an = includes them.
2N/A */
2N/A if ((fromstr = strchr(hc, '/')) == NULL)
2N/A return (NULL);
2N/A
2N/A find = fromstr;
2N/A while ((ne = strchr(find, '=')) != NULL) {
2N/A find = ne + 1;
2N/A npairs++;
2N/A }
2N/A
2N/A find = fromstr;
2N/A while ((ns = strchr(find, '/')) != NULL) {
2N/A find = ns + 1;
2N/A nslashes++;
2N/A }
2N/A
2N/A /*
2N/A * Do we appear to have a well-formed string version of the FMRI?
2N/A */
2N/A if (nslashes < npairs || npairs == 0) {
2N/A topo_mod_free(mod, hc, hclen);
2N/A return (NULL);
2N/A }
2N/A
2N/A *num = npairs;
2N/A
2N/A find = fromstr;
2N/A
2N/A if ((pa = topo_mod_zalloc(mod, npairs * sizeof (nvlist_t *))) == NULL) {
2N/A topo_mod_free(mod, hc, hclen);
2N/A return (NULL);
2N/A }
2N/A
2N/A /*
2N/A * We go through a pretty complicated procedure to find the
2N/A * name and id for each pair. That's because, unfortunately,
2N/A * we have some ids that can have slashes within them. So
2N/A * we can't just search for the next slash after the equal sign
2N/A * and decide that starts a new pair. Instead we have to find
2N/A * an equal sign for the next pair and work our way back to the
2N/A * slash from there.
2N/A */
2N/A for (i = 0; i < npairs; i++) {
2N/A startn = strchr(find, '/');
2N/A if (startn == NULL)
2N/A break;
2N/A startn++;
2N/A starti = strchr(find, '=');
2N/A if (starti == NULL)
2N/A break;
2N/A *starti = '\0';
2N/A if ((cname = topo_mod_strdup(mod, startn)) == NULL)
2N/A break;
2N/A *starti++ = '=';
2N/A endi = strchr(starti, '=');
2N/A if (endi != NULL) {
2N/A *endi = '\0';
2N/A endi2 = strrchr(starti, '/');
2N/A if (endi2 == NULL)
2N/A break;
2N/A *endi = '=';
2N/A *endi2 = '\0';
2N/A if ((cid = topo_mod_strdup(mod, starti)) == NULL)
2N/A break;
2N/A *endi2 = '/';
2N/A find = endi2;
2N/A } else {
2N/A if ((cid = topo_mod_strdup(mod, starti)) == NULL)
2N/A break;
2N/A find = starti + strlen(starti);
2N/A }
2N/A if (topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME) < 0)
2N/A break;
2N/A
2N/A if (nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname) ||
2N/A nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid))
2N/A break;
2N/A
2N/A topo_mod_strfree(mod, cname);
2N/A topo_mod_strfree(mod, cid);
2N/A cname = NULL;
2N/A cid = NULL;
2N/A }
2N/A
2N/A topo_mod_strfree(mod, cname);
2N/A topo_mod_strfree(mod, cid);
2N/A
2N/A if (i < npairs) {
2N/A for (i = 0; i < npairs; i++)
2N/A nvlist_free(pa[i]);
2N/A topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *));
2N/A topo_mod_free(mod, hc, hclen);
2N/A return (NULL);
2N/A }
2N/A
2N/A topo_mod_free(mod, hc, hclen);
2N/A
2N/A return (pa);
2N/A}
2N/A
2N/Astatic int
2N/Acmp_str(char *s1, char *s2)
2N/A{
2N/A return (strlen(s1) != strlen(s2) || strncmp(s1, s2, strlen(s1)) != 0);
2N/A}
2N/A
2N/Aint
2N/Amake_hc_auth(topo_mod_t *mod, char *fmri, char **serial, char **part,
2N/Achar **rev, nvlist_t **auth, char **devid, char **parent_serial)
2N/A{
2N/A char *starti, *startn, *endi, *copy;
2N/A char *aname = NULL, *aid = NULL, *fs;
2N/A nvlist_t *na = NULL;
2N/A size_t len;
2N/A
2N/A if ((copy = topo_mod_strdup(mod, fmri + 5)) == NULL)
2N/A return (-1);
2N/A
2N/A len = strlen(copy);
2N/A
2N/A /*
2N/A * Make sure there are a valid authority members
2N/A */
2N/A startn = strchr(copy, ':');
2N/A fs = strchr(copy, '/');
2N/A
2N/A if (startn == NULL || fs == NULL) {
2N/A topo_mod_strfree(mod, copy);
2N/A return (0);
2N/A }
2N/A
2N/A /*
2N/A * The first colon we encounter must occur before the
2N/A * first slash
2N/A */
2N/A if (startn > fs)
2N/A goto hcabail;
2N/A
2N/A do {
2N/A if (++startn >= copy + len)
2N/A break;
2N/A
2N/A if ((starti = strchr(startn, '=')) == NULL)
2N/A goto hcabail;
2N/A
2N/A *starti = '\0';
2N/A if (++starti > copy + len)
2N/A goto hcabail;
2N/A
2N/A if ((aname = topo_mod_strdup(mod, startn)) == NULL)
2N/A goto hcabail;
2N/A
2N/A startn = endi = strchr(starti, ':');
2N/A if (endi == NULL)
2N/A if ((endi = strchr(starti, '/')) == NULL)
2N/A break;
2N/A
2N/A *endi = '\0';
2N/A if ((aid = topo_mod_strdup(mod, starti)) == NULL)
2N/A goto hcabail;
2N/A
2N/A /*
2N/A * Return possible devid, serial, part and revision. Need
2N/A * to account for both version 0 and version 1 names.
2N/A */
2N/A if (cmp_str(aname, FM_FMRI_HC_V0_SERIAL) == 0 ||
2N/A cmp_str(aname, FM_FMRI_HC_V1_FRU_SN) == 0) {
2N/A *serial = topo_mod_strdup(mod, aid);
2N/A } else if (cmp_str(aname, FM_FMRI_HC_DEVID) == 0) {
2N/A *devid = topo_mod_strdup(mod, aid);
2N/A } else if (cmp_str(aname, FM_FMRI_HC_PARENT_SERIAL)
2N/A == 0) {
2N/A *parent_serial = topo_mod_strdup(mod, aid);
2N/A } else if (cmp_str(aname, FM_FMRI_HC_V0_PART) == 0 ||
2N/A cmp_str(aname, FM_FMRI_HC_V1_FRU_PN) == 0) {
2N/A *part = topo_mod_strdup(mod, aid);
2N/A } else if (cmp_str(aname, FM_FMRI_HC_V0_REVISION) == 0 ||
2N/A cmp_str(aname, FM_FMRI_HC_V1_FRU_REV) == 0) {
2N/A *rev = topo_mod_strdup(mod, aid);
2N/A } else {
2N/A if (na == NULL) {
2N/A if (topo_mod_nvalloc(mod, &na,
2N/A NV_UNIQUE_NAME) == 0) {
2N/A (void) nvlist_add_string(na, aname,
2N/A aid);
2N/A }
2N/A } else {
2N/A (void) nvlist_add_string(na, aname, aid);
2N/A }
2N/A }
2N/A topo_mod_strfree(mod, aname);
2N/A topo_mod_strfree(mod, aid);
2N/A aname = aid = NULL;
2N/A
2N/A } while (startn != NULL);
2N/A
2N/A *auth = na;
2N/A
2N/A topo_mod_free(mod, copy, len + 1);
2N/A return (0);
2N/A
2N/Ahcabail:
2N/A topo_mod_free(mod, copy, len + 1);
2N/A topo_mod_strfree(mod, aname);
2N/A topo_mod_strfree(mod, aid);
2N/A nvlist_free(na);
2N/A return (-1);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * This function creates an nvlist to represent the facility portion of an
2N/A * hc-scheme node, given a string representation of the fmri. This is called by
2N/A * hc_fmri_str2nvl. If the string does not contain a facility component
2N/A * (e.g. ?<ftype>=<fname>) then it bails early and returns 0.
2N/A *
2N/A * On failure it returns -1 and sets the topo mod errno
2N/A */
2N/Aint
2N/Amake_facility(topo_mod_t *mod, char *str, nvlist_t **nvl)
2N/A{
2N/A char *fac, *copy, *fname, *ftype;
2N/A nvlist_t *nf = NULL;
2N/A size_t len;
2N/A
2N/A if ((fac = strchr(str, '?')) == NULL)
2N/A return (0);
2N/A
2N/A ++fac;
2N/A if ((copy = topo_mod_strdup(mod, fac)) == NULL)
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A
2N/A fac = copy;
2N/A len = strlen(fac);
2N/A
2N/A if ((fname = strchr(fac, '=')) == NULL) {
2N/A topo_mod_free(mod, copy, len + 1);
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
2N/A }
2N/A
2N/A fname[0] = '\0';
2N/A ++fname;
2N/A ftype = fac;
2N/A
2N/A if (topo_mod_nvalloc(mod, &nf, NV_UNIQUE_NAME) != 0) {
2N/A topo_mod_free(mod, copy, len + 1);
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A }
2N/A
2N/A if (nvlist_add_string(nf, FM_FMRI_FACILITY_NAME, fname) != 0 ||
2N/A nvlist_add_string(nf, FM_FMRI_FACILITY_TYPE, ftype) != 0) {
2N/A topo_mod_free(mod, copy, len + 1);
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
2N/A }
2N/A
2N/A topo_mod_free(mod, copy, len + 1);
2N/A
2N/A *nvl = nf;
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* hc-specific member names */
2N/Astatic struct hcs_member {
2N/A char *name;
2N/A int base;
2N/A} hcs_members[] = {
2N/A FM_FMRI_HC_SPECIFIC_OFFSET, 16,
2N/A FM_FMRI_HC_SPECIFIC_PHYSADDR, 16,
2N/A FM_FMRI_HC_SPECIFIC_L2CACHE, 10,
2N/A FM_FMRI_HC_SPECIFIC_L3CACHE, 10,
2N/A FM_FMRI_HC_SPECIFIC_CACHEINDEX, 10,
2N/A FM_FMRI_HC_SPECIFIC_CACHEWAY, 10,
2N/A NULL, 0
2N/A};
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A nvlist_t **pa = NULL;
2N/A nvlist_t *nf = NULL, *auth = NULL, *fac = NULL, *hcsp = NULL;
2N/A char *str, *hcsn, *hcsv;
2N/A char *serial = NULL, *part = NULL, *rev = NULL;
2N/A int npairs, n, i, e, ret;
2N/A struct hcs_member *hcsmp;
2N/A char *devid = NULL, *parent_serial = NULL;
2N/A uint64_t val;
2N/A
2N/A if (version > TOPO_METH_STR2NVL_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A
2N/A if (nvlist_lookup_string(in, "fmri-string", &str) != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A
2N/A /* We're expecting a string version of an hc scheme FMRI */
2N/A if (strncmp(str, "hc://", 5) != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
2N/A
2N/A if ((pa = make_hc_pairs(mod, str, &npairs)) == NULL)
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
2N/A
2N/A ret = EMOD_FMRI_MALFORM;
2N/A
2N/A if (make_hc_auth(mod, str, &serial, &part, &rev, &auth, &devid,
2N/A &parent_serial) < 0)
2N/A goto hcfmbail;
2N/A
2N/A if ((nf = hc_base_fmri_create(mod, auth, part, rev, serial,
2N/A devid, parent_serial)) == NULL)
2N/A goto hcfmbail;
2N/A
2N/A /*
2N/A * Walk from the end of the string and add components to "hc-specific"
2N/A * if the names match the known list.
2N/A */
2N/A for (n = npairs - 1; n >= 0; n--) {
2N/A (void) nvlist_lookup_string(pa[n], FM_FMRI_HC_NAME, &hcsn);
2N/A for (hcsmp = hcs_members; hcsmp->name; hcsmp++)
2N/A if (strcmp(hcsmp->name, hcsn) == 0)
2N/A break;
2N/A
2N/A /* The rest should belong to "hc-list" */
2N/A if (hcsmp->name == NULL)
2N/A break;
2N/A
2N/A /* found a "hc-specific" member */
2N/A if (hcsp == NULL &&
2N/A topo_mod_nvalloc(mod, &hcsp, NV_UNIQUE_NAME) != 0)
2N/A goto hcfmbail;
2N/A
2N/A (void) nvlist_lookup_string(pa[n], FM_FMRI_HC_ID, &hcsv);
2N/A val = strtoull(hcsv, NULL, hcsmp->base);
2N/A if (nvlist_add_uint64(hcsp, hcsn, val) != 0)
2N/A goto hcfmbail;
2N/A }
2N/A
2N/A if (hcsp != NULL &&
2N/A nvlist_add_nvlist(nf, FM_FMRI_HC_SPECIFIC, hcsp) != 0)
2N/A goto hcfmbail;
2N/A
2N/A if ((e = nvlist_add_uint32(nf, FM_FMRI_HC_LIST_SZ, n + 1)) == 0)
2N/A e = nvlist_add_nvlist_array(nf, FM_FMRI_HC_LIST, pa, n + 1);
2N/A if (e != 0) {
2N/A topo_mod_dprintf(mod, "construction of new hc nvl failed");
2N/A goto hcfmbail;
2N/A }
2N/A
2N/A if (make_facility(mod, str, &fac) == -1)
2N/A goto hcfmbail;
2N/A
2N/A if (fac != NULL) {
2N/A if (nvlist_add_nvlist(nf, FM_FMRI_FACILITY, fac) != 0)
2N/A goto hcfmbail;
2N/A }
2N/A
2N/A *out = nf;
2N/A ret = 0;
2N/A
2N/Ahcfmbail:
2N/A /*
2N/A * Clean-up
2N/A */
2N/A nvlist_free(fac);
2N/A nvlist_free(hcsp);
2N/A for (i = 0; i < npairs; i++)
2N/A nvlist_free(pa[i]);
2N/A topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *));
2N/A topo_mod_strfree(mod, serial);
2N/A topo_mod_strfree(mod, devid);
2N/A topo_mod_strfree(mod, parent_serial);
2N/A topo_mod_strfree(mod, part);
2N/A topo_mod_strfree(mod, rev);
2N/A nvlist_free(auth);
2N/A if (ret != 0) {
2N/A nvlist_free(nf);
2N/A return (topo_mod_seterrno(mod, ret));
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic nvlist_t *
2N/Ahc_list_create(topo_mod_t *mod, const char *name, char *inst)
2N/A{
2N/A int err;
2N/A nvlist_t *hc;
2N/A
2N/A if (topo_mod_nvalloc(mod, &hc, NV_UNIQUE_NAME) != 0)
2N/A return (NULL);
2N/A
2N/A err = nvlist_add_string(hc, FM_FMRI_HC_NAME, name);
2N/A err |= nvlist_add_string(hc, FM_FMRI_HC_ID, inst);
2N/A if (err != 0) {
2N/A nvlist_free(hc);
2N/A return (NULL);
2N/A }
2N/A
2N/A return (hc);
2N/A}
2N/A
2N/Astatic nvlist_t *
2N/Ahc_create_seterror(topo_mod_t *mod, nvlist_t **hcl, int n, nvlist_t *fmri,
2N/A int err)
2N/A{
2N/A int i;
2N/A
2N/A if (hcl != NULL) {
2N/A for (i = 0; i < n + 1; ++i)
2N/A nvlist_free(hcl[i]);
2N/A
2N/A topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (n + 1));
2N/A }
2N/A
2N/A nvlist_free(fmri);
2N/A
2N/A (void) topo_mod_seterrno(mod, err);
2N/A
2N/A topo_mod_dprintf(mod, "unable to create hc FMRI: %s\n",
2N/A topo_mod_errmsg(mod));
2N/A
2N/A return (NULL);
2N/A}
2N/A
2N/Astatic int
2N/Ahc_name_canonical(topo_mod_t *mod, const char *name)
2N/A{
2N/A int i;
2N/A
2N/A if (getenv("NOHCCHECK") != NULL)
2N/A return (1);
2N/A
2N/A /*
2N/A * Only enumerate elements with correct canonical names
2N/A */
2N/A for (i = 0; i < hc_ncanon; i++) {
2N/A if (strcmp(name, hc_canon[i].hcc_name) == 0)
2N/A break;
2N/A }
2N/A if (i >= hc_ncanon) {
2N/A topo_mod_dprintf(mod, "non-canonical name %s\n",
2N/A name);
2N/A return (0);
2N/A } else {
2N/A return (1);
2N/A }
2N/A}
2N/A
2N/Astatic nvlist_t *
2N/Ahc_fmri_create(topo_mod_t *mod, nvlist_t *pfmri, int version, const char *name,
2N/A topo_instance_t inst, const nvlist_t *auth, const char *part,
2N/A const char *rev, const char *serial)
2N/A{
2N/A int i;
2N/A char str[21]; /* sizeof (UINT64_MAX) + '\0' */
2N/A uint_t pelems = 0;
2N/A nvlist_t **phcl = NULL;
2N/A nvlist_t **hcl = NULL;
2N/A nvlist_t *fmri = NULL;
2N/A
2N/A if (version > FM_HC_SCHEME_VERSION)
2N/A return (hc_create_seterror(mod,
2N/A hcl, pelems, fmri, EMOD_VER_OLD));
2N/A else if (version < FM_HC_SCHEME_VERSION)
2N/A return (hc_create_seterror(mod,
2N/A hcl, pelems, fmri, EMOD_VER_NEW));
2N/A
2N/A /*
2N/A * Check that the requested name is in our canonical list
2N/A */
2N/A if (hc_name_canonical(mod, name) == 0)
2N/A return (hc_create_seterror(mod,
2N/A hcl, pelems, fmri, EMOD_NONCANON));
2N/A /*
2N/A * Copy the parent's HC_LIST
2N/A */
2N/A if (pfmri != NULL) {
2N/A if (nvlist_lookup_nvlist_array(pfmri, FM_FMRI_HC_LIST,
2N/A &phcl, &pelems) != 0)
2N/A return (hc_create_seterror(mod,
2N/A hcl, pelems, fmri, EMOD_FMRI_MALFORM));
2N/A }
2N/A
2N/A hcl = topo_mod_zalloc(mod, sizeof (nvlist_t *) * (pelems + 1));
2N/A if (hcl == NULL)
2N/A return (hc_create_seterror(mod, hcl, pelems, fmri,
2N/A EMOD_NOMEM));
2N/A
2N/A for (i = 0; i < pelems; ++i)
2N/A if (topo_mod_nvdup(mod, phcl[i], &hcl[i]) != 0)
2N/A return (hc_create_seterror(mod,
2N/A hcl, pelems, fmri, EMOD_FMRI_NVL));
2N/A
2N/A (void) snprintf(str, sizeof (str), "%d", inst);
2N/A if ((hcl[i] = hc_list_create(mod, name, str)) == NULL)
2N/A return (hc_create_seterror(mod,
2N/A hcl, pelems, fmri, EMOD_FMRI_NVL));
2N/A
2N/A if ((fmri = hc_base_fmri_create(mod, auth, part, rev, serial,
2N/A NULL, NULL)) == NULL)
2N/A return (hc_create_seterror(mod,
2N/A hcl, pelems, fmri, EMOD_FMRI_NVL));
2N/A
2N/A if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, hcl, pelems + 1)
2N/A != 0)
2N/A return (hc_create_seterror(mod,
2N/A hcl, pelems, fmri, EMOD_FMRI_NVL));
2N/A
2N/A if (nvlist_add_uint32(fmri, FM_FMRI_HC_LIST_SZ, pelems + 1) != 0)
2N/A return (hc_create_seterror(mod,
2N/A hcl, pelems, fmri, EMOD_FMRI_NVL));
2N/A
2N/A if (hcl != NULL) {
2N/A for (i = 0; i < pelems + 1; ++i) {
2N/A if (hcl[i] != NULL)
2N/A nvlist_free(hcl[i]);
2N/A }
2N/A topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (pelems + 1));
2N/A }
2N/A
2N/A return (fmri);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_fmri_create_meth(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A int ret;
2N/A nvlist_t *args, *pfmri = NULL;
2N/A nvlist_t *auth;
2N/A uint32_t inst;
2N/A char *name, *serial, *rev, *part;
2N/A
2N/A if (version > TOPO_METH_FMRI_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A
2N/A /* First the must-have fields */
2N/A if (nvlist_lookup_string(in, TOPO_METH_FMRI_ARG_NAME, &name) != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A if (nvlist_lookup_uint32(in, TOPO_METH_FMRI_ARG_INST, &inst) != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A
2N/A /*
2N/A * args is optional
2N/A */
2N/A pfmri = NULL;
2N/A auth = NULL;
2N/A serial = rev = part = NULL;
2N/A if ((ret = nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args))
2N/A != 0) {
2N/A if (ret != ENOENT)
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A } else {
2N/A
2N/A /* And then optional arguments */
2N/A (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
2N/A &pfmri);
2N/A (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_AUTH,
2N/A &auth);
2N/A (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_PART,
2N/A &part);
2N/A (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_REV, &rev);
2N/A (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_SER,
2N/A &serial);
2N/A }
2N/A
2N/A *out = hc_fmri_create(mod, pfmri, version, name, inst, auth, part,
2N/A rev, serial);
2N/A if (*out == NULL)
2N/A return (-1);
2N/A return (0);
2N/A}
2N/A
2N/Astruct hc_walk {
2N/A topo_mod_walk_cb_t hcw_cb;
2N/A void *hcw_priv;
2N/A topo_walk_t *hcw_wp;
2N/A nvlist_t **hcw_list;
2N/A nvlist_t *hcw_fmri;
2N/A nvlist_t *hcw_fac;
2N/A uint_t hcw_index;
2N/A uint_t hcw_end;
2N/A};
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_match(topo_mod_t *mod, tnode_t *node, nvlist_t *fmri, const char *name,
2N/A topo_instance_t inst, boolean_t *result)
2N/A{
2N/A nvlist_t *rsrc = NULL, *a1, *a2;
2N/A char *c1, *c2;
2N/A int err;
2N/A
2N/A if (strcmp(name, topo_node_name(node)) != 0)
2N/A *result = B_FALSE;
2N/A else if (strcmp(name, SES_ENCLOSURE) == 0 &&
2N/A topo_node_resource(node, &rsrc, &err) == 0 &&
2N/A nvlist_lookup_nvlist(rsrc, FM_FMRI_AUTHORITY, &a1) == 0 &&
2N/A nvlist_lookup_nvlist(fmri, FM_FMRI_AUTHORITY, &a2) == 0 &&
2N/A nvlist_lookup_string(a1, FM_FMRI_AUTH_V1_CHASSIS_SN, &c1) == 0 &&
2N/A nvlist_lookup_string(a2, FM_FMRI_AUTH_V1_CHASSIS_SN, &c2) == 0)
2N/A /*
2N/A * Still need to check chassis serial in case of proxied
2N/A * ereports.
2N/A */
2N/A *result = (strcmp(c1, c2) == 0);
2N/A else
2N/A *result = (inst == topo_node_instance(node));
2N/A if (rsrc)
2N/A nvlist_free(rsrc);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Ideally, we should just be able to call topo_walk_bysibling(). But that
2N/A * code assumes that the name/instance pair will match, so we need to
2N/A * explicitly iterate over children of the parent looking for a matching value.
2N/A */
2N/Astatic int
2N/Ahc_walk_sibling(topo_mod_t *mod, tnode_t *node, struct hc_walk *hwp,
2N/A const char *name, topo_instance_t inst)
2N/A{
2N/A tnode_t *pnp = topo_node_parent(node);
2N/A topo_walk_t *wp = hwp->hcw_wp;
2N/A tnode_t *np;
2N/A boolean_t matched;
2N/A int status;
2N/A
2N/A for (np = topo_child_first(pnp); np != NULL;
2N/A np = topo_child_next(pnp, np)) {
2N/A topo_node_hold(np);
2N/A if (hc_match(mod, np, hwp->hcw_fmri, name, inst,
2N/A &matched) == 0 && matched) {
2N/A wp->tw_node = np;
2N/A if (wp->tw_mod != NULL)
2N/A status = wp->tw_cb(mod, np, hwp);
2N/A else
2N/A status = wp->tw_cb(wp->tw_thp, np, hwp);
2N/A topo_node_rele(np);
2N/A wp->tw_node = node;
2N/A return (status);
2N/A }
2N/A
2N/A topo_node_rele(np);
2N/A }
2N/A
2N/A return (TOPO_WALK_TERMINATE);
2N/A}
2N/A
2N/A/*
2N/A * Generic walker for the hc-scheme topo tree. This function uses the
2N/A * hierachical nature of the hc-scheme to efficiently step through
2N/A * the topo hc tree. Node lookups are done by topo_walk_byid() and
2N/A * topo_walk_bysibling() at each component level to avoid unnecessary
2N/A * traversal of the tree. hc_walker() never returns TOPO_WALK_NEXT, so
2N/A * whether TOPO_WALK_CHILD or TOPO_WALK_SIBLING is specified by
2N/A * topo_walk_step() doesn't affect the traversal.
2N/A */
2N/Astatic int
2N/Ahc_walker(topo_mod_t *mod, tnode_t *node, void *pdata)
2N/A{
2N/A int i, err;
2N/A struct hc_walk *hwp = (struct hc_walk *)pdata;
2N/A char *name, *id;
2N/A char *fname, *ftype;
2N/A topo_instance_t inst;
2N/A boolean_t match;
2N/A
2N/A i = hwp->hcw_index;
2N/A if (i > hwp->hcw_end) {
2N/A if (hwp->hcw_fac != NULL) {
2N/A if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv))
2N/A != 0) {
2N/A (void) topo_mod_seterrno(mod, err);
2N/A topo_mod_dprintf(mod, "hc_walker: callback "
2N/A "failed: %s\n ", topo_mod_errmsg(mod));
2N/A return (TOPO_WALK_ERR);
2N/A }
2N/A topo_mod_dprintf(mod, "hc_walker: callback "
2N/A "complete: terminate walk\n");
2N/A return (TOPO_WALK_TERMINATE);
2N/A } else {
2N/A topo_mod_dprintf(mod, "hc_walker: node not found\n");
2N/A return (TOPO_WALK_TERMINATE);
2N/A }
2N/A }
2N/A
2N/A err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name);
2N/A err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id);
2N/A
2N/A if (err != 0) {
2N/A (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
2N/A return (TOPO_WALK_ERR);
2N/A }
2N/A
2N/A inst = atoi(id);
2N/A
2N/A /*
2N/A * Check to see if our node matches the requested FMRI. If it doesn't
2N/A * (because the enumerator determines matching based on something other
2N/A * than name/instance, or because we're at the first level below the
2N/A * root), then iterate over siblings to find the matching node.
2N/A */
2N/A if (hc_match(mod, node, hwp->hcw_fmri, name, inst, &match) != 0)
2N/A return (TOPO_WALK_ERR);
2N/A
2N/A if (!match)
2N/A return (hc_walk_sibling(mod, node, hwp, name, inst));
2N/A
2N/A topo_mod_dprintf(mod, "hc_walker: walking node:%s=%d for hc:"
2N/A "%s=%d at %d, end at %d \n", topo_node_name(node),
2N/A topo_node_instance(node), name, inst, i, hwp->hcw_end);
2N/A
2N/A if (i == hwp->hcw_end) {
2N/A
2N/A /*
2N/A * We are at the end of the hc-list. Now, check for
2N/A * a facility leaf and walk one more time.
2N/A */
2N/A if (hwp->hcw_fac != NULL) {
2N/A err = nvlist_lookup_string(hwp->hcw_fac,
2N/A FM_FMRI_FACILITY_NAME, &fname);
2N/A err |= nvlist_lookup_string(hwp->hcw_fac,
2N/A FM_FMRI_FACILITY_TYPE, &ftype);
2N/A if (err != 0) {
2N/A (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
2N/A return (TOPO_WALK_ERR);
2N/A }
2N/A hwp->hcw_index++;
2N/A topo_mod_dprintf(mod, "hc_walker: walk to facility "
2N/A "node:%s=%s\n", fname, ftype);
2N/A return (topo_walk_byid(hwp->hcw_wp, fname, 0));
2N/A }
2N/A
2N/A /*
2N/A * Otherwise, this is the node we're looking for.
2N/A */
2N/A if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv)) != 0) {
2N/A (void) topo_mod_seterrno(mod, err);
2N/A topo_mod_dprintf(mod, "hc_walker: callback "
2N/A "failed: %s\n ", topo_mod_errmsg(mod));
2N/A return (TOPO_WALK_ERR);
2N/A } else {
2N/A topo_mod_dprintf(mod, "hc_walker: callback "
2N/A "complete: terminate walk\n");
2N/A return (TOPO_WALK_TERMINATE);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Move on to the next component in the hc-list
2N/A */
2N/A hwp->hcw_index = ++i;
2N/A err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name);
2N/A err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id);
2N/A if (err != 0) {
2N/A (void) topo_mod_seterrno(mod, err);
2N/A return (TOPO_WALK_ERR);
2N/A }
2N/A inst = atoi(id);
2N/A
2N/A return (topo_walk_byid(hwp->hcw_wp, name, inst));
2N/A
2N/A}
2N/A
2N/A/*
2N/A * A call to hc_walk_init() followed by a call to topo_walk_step() will simply
2N/A * find the specified hc-scheme node "rsrc" and run the callback function "cb"
2N/A * on it with argument "pdata".
2N/A *
2N/A * Note that this sequence does not walk the whole tree but simply matches
2N/A * each element in the hc-scheme name "rsrc" one level at a time until it
2N/A * finds the "rsrc" node.
2N/A */
2N/Astatic struct hc_walk *
2N/Ahc_walk_init(topo_mod_t *mod, tnode_t *node, nvlist_t *rsrc,
2N/A topo_mod_walk_cb_t cb, void *pdata)
2N/A{
2N/A int err, ret;
2N/A uint_t sz;
2N/A struct hc_walk *hwp;
2N/A topo_walk_t *wp;
2N/A
2N/A if ((hwp = topo_mod_alloc(mod, sizeof (struct hc_walk))) == NULL) {
2N/A (void) topo_mod_seterrno(mod, EMOD_NOMEM);
2N/A return (NULL);
2N/A }
2N/A
2N/A if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hwp->hcw_list,
2N/A &sz) != 0) {
2N/A topo_mod_dprintf(mod, "hc_walk_init: failed to lookup %s "
2N/A "nvlist\n", FM_FMRI_HC_LIST);
2N/A topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2N/A (void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
2N/A return (NULL);
2N/A }
2N/A if ((ret = nvlist_lookup_nvlist(rsrc, FM_FMRI_FACILITY, &hwp->hcw_fac))
2N/A != 0) {
2N/A if (ret != ENOENT) {
2N/A topo_mod_dprintf(mod, "hc_walk_init: unexpected error "
2N/A "looking up %s nvlist", FM_FMRI_FACILITY);
2N/A topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2N/A (void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
2N/A return (NULL);
2N/A } else {
2N/A hwp->hcw_fac = NULL;
2N/A }
2N/A }
2N/A
2N/A hwp->hcw_fmri = rsrc;
2N/A hwp->hcw_end = sz - 1;
2N/A hwp->hcw_index = 0;
2N/A hwp->hcw_priv = pdata;
2N/A hwp->hcw_cb = cb;
2N/A if ((wp = topo_mod_walk_init(mod, node, hc_walker, (void *)hwp, &err))
2N/A == NULL) {
2N/A topo_mod_dprintf(mod, "hc_walk_init: topo_mod_walk_init failed "
2N/A "(%s)\n", topo_strerror(err));
2N/A topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2N/A (void) topo_mod_seterrno(mod, err);
2N/A return (NULL);
2N/A }
2N/A
2N/A hwp->hcw_wp = wp;
2N/A
2N/A return (hwp);
2N/A}
2N/A
2N/Astruct prop_lookup {
2N/A const char *pl_pgroup;
2N/A const char *pl_pname;
2N/A int pl_flag;
2N/A nvlist_t *pl_args;
2N/A nvlist_t *pl_rsrc;
2N/A nvlist_t *pl_prop;
2N/A};
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_prop_get(topo_mod_t *mod, tnode_t *node, void *pdata)
2N/A{
2N/A int err = 0;
2N/A
2N/A struct prop_lookup *plp = (struct prop_lookup *)pdata;
2N/A
2N/A (void) topo_prop_getprop(node, plp->pl_pgroup, plp->pl_pname,
2N/A plp->pl_args, &plp->pl_prop, &err);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/Astatic int
2N/Ahc_fmri_prop_get(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A int err;
2N/A struct hc_walk *hwp;
2N/A struct prop_lookup *plp;
2N/A
2N/A if (version > TOPO_METH_PROP_GET_VERSION)
2N/A return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2N/A
2N/A if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A
2N/A err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
2N/A (char **)&plp->pl_pgroup);
2N/A err |= nvlist_lookup_string(in, TOPO_PROP_VAL_NAME,
2N/A (char **)&plp->pl_pname);
2N/A err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
2N/A if (err != 0) {
2N/A topo_mod_free(mod, plp, sizeof (struct prop_lookup));
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A }
2N/A
2N/A /*
2N/A * Private args to prop method are optional
2N/A */
2N/A if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args))
2N/A != 0) {
2N/A if (err != ENOENT) {
2N/A topo_mod_free(mod, plp, sizeof (struct prop_lookup));
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A } else {
2N/A plp->pl_args = NULL;
2N/A }
2N/A }
2N/A
2N/A plp->pl_prop = NULL;
2N/A if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_get,
2N/A (void *)plp)) != NULL) {
2N/A if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2N/A TOPO_WALK_ERR)
2N/A err = -1;
2N/A else
2N/A err = 0;
2N/A topo_walk_fini(hwp->hcw_wp);
2N/A topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2N/A } else {
2N/A err = -1;
2N/A }
2N/A
2N/A if (plp->pl_prop != NULL)
2N/A *out = plp->pl_prop;
2N/A
2N/A topo_mod_free(mod, plp, sizeof (struct prop_lookup));
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_pgrp_get(topo_mod_t *mod, tnode_t *node, void *pdata)
2N/A{
2N/A int err = 0;
2N/A
2N/A struct prop_lookup *plp = (struct prop_lookup *)pdata;
2N/A
2N/A (void) topo_prop_getpgrp(node, plp->pl_pgroup, &plp->pl_prop, &err);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/Astatic int
2N/Ahc_fmri_pgrp_get(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A int err;
2N/A struct hc_walk *hwp;
2N/A struct prop_lookup *plp;
2N/A
2N/A if (version > TOPO_METH_PGRP_GET_VERSION)
2N/A return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2N/A
2N/A if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A
2N/A err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
2N/A (char **)&plp->pl_pgroup);
2N/A err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
2N/A if (err != 0) {
2N/A topo_mod_free(mod, plp, sizeof (struct prop_lookup));
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A }
2N/A
2N/A plp->pl_prop = NULL;
2N/A if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_pgrp_get,
2N/A (void *)plp)) != NULL) {
2N/A if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2N/A TOPO_WALK_ERR)
2N/A err = -1;
2N/A else
2N/A err = 0;
2N/A topo_walk_fini(hwp->hcw_wp);
2N/A topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2N/A } else {
2N/A err = -1;
2N/A }
2N/A
2N/A if (plp->pl_prop != NULL)
2N/A *out = plp->pl_prop;
2N/A
2N/A topo_mod_free(mod, plp, sizeof (struct prop_lookup));
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_prop_setprop(topo_mod_t *mod, tnode_t *node, void *pdata)
2N/A{
2N/A int err = 0;
2N/A
2N/A struct prop_lookup *plp = (struct prop_lookup *)pdata;
2N/A
2N/A (void) topo_prop_setprop(node, plp->pl_pgroup, plp->pl_prop,
2N/A plp->pl_flag, plp->pl_args, &err);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_fmri_prop_set(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A int err;
2N/A struct hc_walk *hwp;
2N/A struct prop_lookup *plp;
2N/A
2N/A if (version > TOPO_METH_PROP_SET_VERSION)
2N/A return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2N/A
2N/A if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A
2N/A err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
2N/A (char **)&plp->pl_pgroup);
2N/A err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
2N/A err |= nvlist_lookup_nvlist(in, TOPO_PROP_VAL, &plp->pl_prop);
2N/A err |= nvlist_lookup_int32(in, TOPO_PROP_FLAG, &plp->pl_flag);
2N/A if (err != 0) {
2N/A topo_mod_free(mod, plp, sizeof (struct prop_lookup));
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A }
2N/A
2N/A /*
2N/A * Private args to prop method are optional
2N/A */
2N/A if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args))
2N/A != 0) {
2N/A if (err != ENOENT)
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A else
2N/A plp->pl_args = NULL;
2N/A }
2N/A
2N/A if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_setprop,
2N/A (void *)plp)) != NULL) {
2N/A if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2N/A TOPO_WALK_ERR)
2N/A err = -1;
2N/A else
2N/A err = 0;
2N/A topo_walk_fini(hwp->hcw_wp);
2N/A topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2N/A } else {
2N/A err = -1;
2N/A }
2N/A
2N/A topo_mod_free(mod, plp, sizeof (struct prop_lookup));
2N/A
2N/A return (err);
2N/A}
2N/A
2N/Astruct hc_args {
2N/A nvlist_t *ha_fmri;
2N/A nvlist_t *ha_nvl;
2N/A char *ha_method_name;
2N/A topo_version_t ha_method_ver;
2N/A};
2N/A
2N/Astatic int
2N/Ahc_auth_changed(nvlist_t *nva, nvlist_t *nvb, const char *propnamea,
2N/A const char *propnameb)
2N/A{
2N/A char *stra, *strb;
2N/A
2N/A if (nvlist_lookup_string(nva, propnamea, &stra) != 0 ||
2N/A nvlist_lookup_string(nvb, propnameb, &strb) != 0)
2N/A return (FMD_OBJ_STATE_UNKNOWN);
2N/A
2N/A if (strcmp(stra, strb) != 0)
2N/A return (FMD_OBJ_STATE_REPLACED);
2N/A else
2N/A return (FMD_OBJ_STATE_STILL_PRESENT);
2N/A}
2N/A
2N/Astatic int
2N/Ahc_presence_state(topo_mod_t *mod, tnode_t *node, void *pdata)
2N/A{
2N/A int err;
2N/A struct hc_args *hap = (struct hc_args *)pdata;
2N/A nvlist_t *rsrc;
2N/A uint32_t rval = FMD_OBJ_STATE_UNKNOWN;
2N/A
2N/A /*
2N/A * check with the enumerator that created this FMRI
2N/A * (topo node)
2N/A */
2N/A if (topo_method_invoke(node, TOPO_METH_PRESENCE_STATE,
2N/A TOPO_METH_PRESENCE_STATE_VERSION, hap->ha_fmri, &hap->ha_nvl,
2N/A &err) < 0) {
2N/A char *stra, *strb;
2N/A uint8_t vera = 1, verb = 1;
2N/A
2N/A /*
2N/A * If the method exists but failed for some other
2N/A * reason, propagate the error as making any decision
2N/A * over presence is impossible.
2N/A */
2N/A if (err != ETOPO_METHOD_NOTSUP)
2N/A return (err);
2N/A
2N/A /*
2N/A * Enumerator didn't provide "presence_state" method -
2N/A * so check the authority information. If there is a devid
2N/A * then compare that. Otherwise, if the part id
2N/A * or serial number doesn't match, then it isn't the
2N/A * same FMRI. Otherwise, if we have a serial number and
2N/A * it hasn't changed, then assume it is the same FMRI.
2N/A */
2N/A if (topo_node_resource(node, &rsrc, &err) != 0)
2N/A return (err);
2N/A
2N/A if (nvlist_lookup_string(hap->ha_fmri, FM_FMRI_HC_DEVID,
2N/A &stra) == 0 && nvlist_lookup_string(rsrc, FM_FMRI_HC_DEVID,
2N/A &strb) == 0) {
2N/A if (devid_str_compare(stra, strb) != 0)
2N/A rval = FMD_OBJ_STATE_REPLACED;
2N/A else
2N/A rval = FMD_OBJ_STATE_STILL_PRESENT;
2N/A } else {
2N/A (void) nvlist_lookup_uint8(hap->ha_fmri, FM_VERSION,
2N/A &vera);
2N/A (void) nvlist_lookup_uint8(rsrc, FM_VERSION, &verb);
2N/A
2N/A rval = hc_auth_changed(hap->ha_fmri, rsrc,
2N/A vera == 0 ? FM_FMRI_HC_V0_PART :
2N/A vera == 1 ? FM_FMRI_HC_V1_FRU_PN : NULL,
2N/A verb == 0 ? FM_FMRI_HC_V0_PART :
2N/A verb == 1 ? FM_FMRI_HC_V1_FRU_PN : NULL);
2N/A if (rval != FMD_OBJ_STATE_REPLACED)
2N/A rval = hc_auth_changed(hap->ha_fmri, rsrc,
2N/A vera == 0 ? FM_FMRI_HC_V0_SERIAL :
2N/A vera == 1 ? FM_FMRI_HC_V1_FRU_SN : NULL,
2N/A verb == 0 ? FM_FMRI_HC_V0_SERIAL :
2N/A verb == 1 ? FM_FMRI_HC_V1_FRU_SN : NULL);
2N/A }
2N/A nvlist_free(rsrc);
2N/A if (topo_mod_nvalloc(mod, &hap->ha_nvl,
2N/A NV_UNIQUE_NAME) != 0)
2N/A return (EMOD_NOMEM);
2N/A if (nvlist_add_uint32(hap->ha_nvl,
2N/A TOPO_METH_PRESENCE_STATE_RET, rval) != 0) {
2N/A nvlist_free(hap->ha_nvl);
2N/A hap->ha_nvl = NULL;
2N/A return (ETOPO_PROP_NVL);
2N/A }
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Ahc_fmri_presence_state(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A int err;
2N/A struct hc_walk *hwp;
2N/A struct hc_args *hap;
2N/A uint8_t fmversion;
2N/A
2N/A if (nvlist_lookup_uint8(in, FM_VERSION, &fmversion) != 0 ||
2N/A fmversion > FM_HC_SCHEME_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
2N/A
2N/A if (version > TOPO_METH_PRESENCE_STATE_VERSION)
2N/A return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2N/A
2N/A if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A
2N/A hap->ha_fmri = in;
2N/A hap->ha_nvl = NULL;
2N/A if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_presence_state,
2N/A (void *)hap)) != NULL) {
2N/A if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2N/A TOPO_WALK_ERR)
2N/A err = -1;
2N/A else
2N/A err = 0;
2N/A topo_walk_fini(hwp->hcw_wp);
2N/A topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2N/A } else {
2N/A err = -1;
2N/A }
2N/A
2N/A if (hap->ha_nvl != NULL)
2N/A *out = hap->ha_nvl;
2N/A
2N/A topo_mod_free(mod, hap, sizeof (struct hc_args));
2N/A
2N/A return (err);
2N/A}
2N/A
2N/Astruct fac_lookup {
2N/A const char *fl_fac_type;
2N/A uint32_t fl_fac_subtype;
2N/A#ifdef _LP64
2N/A uint64_t fl_callback;
2N/A uint64_t fl_callback_args;
2N/A#else
2N/A uint32_t fl_callback;
2N/A uint32_t fl_callback_args;
2N/A#endif
2N/A nvlist_t *fl_rsrc;
2N/A nvlist_t *fl_fac_rsrc;
2N/A};
2N/A
2N/Astatic int
2N/Ahc_fac_get(topo_mod_t *mod, tnode_t *node, void *pdata)
2N/A{
2N/A struct fac_lookup *flp = (struct fac_lookup *)pdata;
2N/A topo_walk_cb_t cb = (topo_walk_cb_t)flp->fl_callback;
2N/A topo_faclist_t faclist, *tmp;
2N/A int err, ret = 0;
2N/A
2N/A /*
2N/A * Lookup the specified facility node. Return with an error if we can't
2N/A * find it.
2N/A */
2N/A if (topo_node_facility(mod->tm_hdl, node, flp->fl_fac_type,
2N/A flp->fl_fac_subtype, &faclist, &err) != 0) {
2N/A topo_mod_dprintf(mod, "hc_fac_get: topo_node_facility "
2N/A "failed\n");
2N/A return (TOPO_WALK_ERR);
2N/A }
2N/A
2N/A /*
2N/A * Invoke user's callback for each facility node in the topo list,
2N/A * passing in a pointer to the facility node
2N/A */
2N/A for (tmp = topo_list_next(&faclist.tf_list); tmp != NULL;
2N/A tmp = topo_list_next(tmp)) {
2N/A
2N/A if ((err = cb(mod->tm_hdl, tmp->tf_node,
2N/A (void *)flp->fl_callback_args)) != 0) {
2N/A (void) topo_mod_seterrno(mod, err);
2N/A topo_mod_dprintf(mod, "hc_fac_get: callback failed: "
2N/A "%s\n ", topo_mod_errmsg(mod));
2N/A ret = TOPO_WALK_ERR;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A while ((tmp = topo_list_next(&faclist.tf_list)) != NULL) {
2N/A topo_list_delete(&faclist.tf_list, tmp);
2N/A topo_mod_free(mod, tmp, sizeof (topo_faclist_t));
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/Astatic int
2N/Ahc_fmri_facility(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A int err = 0;
2N/A struct hc_walk *hwp;
2N/A struct fac_lookup *flp;
2N/A
2N/A if (version > TOPO_METH_FACILITY_VERSION)
2N/A return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2N/A
2N/A if ((flp = topo_mod_alloc(mod, sizeof (struct fac_lookup))) == NULL)
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A
2N/A /*
2N/A * lookup arguments: hw resource, facility type, facility subtype,
2N/A * callback and callback args
2N/A */
2N/A err = nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &flp->fl_rsrc);
2N/A err |= nvlist_lookup_string(in, FM_FMRI_FACILITY_TYPE,
2N/A (char **)&flp->fl_fac_type);
2N/A err |= nvlist_lookup_uint32(in, "type", &flp->fl_fac_subtype);
2N/A#ifdef _LP64
2N/A err |= nvlist_lookup_uint64(in, "callback", &flp->fl_callback);
2N/A err |= nvlist_lookup_uint64(in, "callback-args",
2N/A &flp->fl_callback_args);
2N/A#else
2N/A err |= nvlist_lookup_uint32(in, "callback", &flp->fl_callback);
2N/A err |= nvlist_lookup_uint32(in, "callback-args",
2N/A &flp->fl_callback_args);
2N/A#endif
2N/A if (err != 0) {
2N/A topo_mod_dprintf(mod, "hc_fmri_facility: failed to construct "
2N/A "walker arg nvlist\n");
2N/A topo_mod_free(mod, flp, sizeof (struct fac_lookup));
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A }
2N/A
2N/A flp->fl_fac_rsrc = NULL;
2N/A if ((hwp = hc_walk_init(mod, node, flp->fl_rsrc, hc_fac_get,
2N/A (void *)flp)) != NULL) {
2N/A if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2N/A TOPO_WALK_ERR)
2N/A err = -1;
2N/A else
2N/A err = 0;
2N/A topo_walk_fini(hwp->hcw_wp);
2N/A topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2N/A } else {
2N/A topo_mod_dprintf(mod, "hc_fmri_facility: failed to initialize "
2N/A "hc walker\n");
2N/A err = -1;
2N/A }
2N/A
2N/A if (flp->fl_fac_rsrc != NULL)
2N/A *out = flp->fl_fac_rsrc;
2N/A
2N/A topo_mod_free(mod, flp, sizeof (struct fac_lookup));
2N/A
2N/A return (err);
2N/A}
2N/A
2N/Astatic int
2N/Ahc_retire_subr(topo_mod_t *mod, tnode_t *node, void *pdata)
2N/A{
2N/A int err, rc;
2N/A struct hc_args *hap = (struct hc_args *)pdata;
2N/A
2N/A topo_mod_dprintf(mod, "hc_retire_subr: invoking method %s\n",
2N/A hap->ha_method_name);
2N/A /*
2N/A * check with the enumerator that created this FMRI
2N/A * (topo node)
2N/A */
2N/A rc = topo_method_invoke(node, hap->ha_method_name,
2N/A hap->ha_method_ver, hap->ha_fmri, &hap->ha_nvl, &err);
2N/A
2N/A topo_mod_dprintf(mod, "hc_retire_subr: invoking method %s "
2N/A "returned %d\n", hap->ha_method_name, rc);
2N/A
2N/A return (rc < 0 ? err : 0);
2N/A}
2N/A
2N/Astatic int
2N/Ahc_fmri_retire_subr(topo_mod_t *mod, tnode_t *node, char *method_name,
2N/A topo_version_t builtin_version, topo_version_t version, nvlist_t *in,
2N/A nvlist_t **out)
2N/A{
2N/A int err;
2N/A struct hc_walk *hwp;
2N/A struct hc_args *hap;
2N/A
2N/A if (version > builtin_version)
2N/A return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2N/A
2N/A if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A
2N/A hap->ha_fmri = in;
2N/A hap->ha_nvl = NULL;
2N/A hap->ha_method_name = method_name;
2N/A hap->ha_method_ver = version;
2N/A if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_retire_subr,
2N/A (void *)hap)) != NULL) {
2N/A if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2N/A TOPO_WALK_ERR)
2N/A err = -1;
2N/A else
2N/A err = 0;
2N/A topo_walk_fini(hwp->hcw_wp);
2N/A } else {
2N/A err = -1;
2N/A }
2N/A
2N/A topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2N/A
2N/A if (hap->ha_nvl != NULL)
2N/A *out = hap->ha_nvl;
2N/A
2N/A topo_mod_free(mod, hap, sizeof (struct hc_args));
2N/A
2N/A return (err);
2N/A}
2N/A
2N/Astatic int
2N/Ahc_fmri_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A return (hc_fmri_retire_subr(mod, node, TOPO_METH_RETIRE,
2N/A TOPO_METH_RETIRE_VERSION, version, in, out));
2N/A}
2N/A
2N/Astatic int
2N/Ahc_fmri_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A return (hc_fmri_retire_subr(mod, node, TOPO_METH_UNRETIRE,
2N/A TOPO_METH_UNRETIRE_VERSION, version, in, out));
2N/A}
2N/A
2N/Astatic int
2N/Ahc_fmri_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A uint8_t fmversion;
2N/A
2N/A if (nvlist_lookup_uint8(in, FM_VERSION, &fmversion) != 0 ||
2N/A fmversion > FM_HC_SCHEME_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
2N/A
2N/A return (hc_fmri_retire_subr(mod, node, TOPO_METH_SERVICE_STATE,
2N/A TOPO_METH_SERVICE_STATE_VERSION, version, in, out));
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_fmri_strhash_path(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A char *next;
2N/A char *fmri = (char *)in;
2N/A uint64_t h;
2N/A uint64_t *rval = (uint64_t *)(void *)out;
2N/A
2N/A h = topo_fmri_strhash_one(fmri, 5);
2N/A next = strchr(fmri + 5, '/');
2N/A if (next)
2N/A h += topo_fmri_strhash_one(next, strlen(next));
2N/A *rval = h;
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_fmri_strcmp_path(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A char *a = (char *)in, *b = (char *)out;
2N/A char *fmria, *fmrib;
2N/A
2N/A /*
2N/A * Get the portion of the FMRI independent of the authority
2N/A * information.
2N/A */
2N/A fmria = strchr(a, '/');
2N/A fmrib = strchr(b, '/');
2N/A if (fmria == NULL || fmrib == NULL)
2N/A return (strcmp(a, b) == 0);
2N/A else
2N/A return (strcmp(fmria, fmrib) == 0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_fmri_strcmp_ident(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A char *a = (char *)in, *b = (char *)out;
2N/A char *fa, *fb, *ffa, *ffb, bufa[PATH_MAX], bufb[PATH_MAX];
2N/A int lena = -1, lenb = -1;
2N/A
2N/A fa = strstr(a, ":" FM_FMRI_HC_DEVID);
2N/A fb = strstr(b, ":" FM_FMRI_HC_DEVID);
2N/A if (fa != NULL && fb != NULL) {
2N/A /* if we have devid, check that in preference */
2N/A fa += strlen(":" FM_FMRI_HC_DEVID "=");
2N/A fb += strlen(":" FM_FMRI_HC_DEVID "=");
2N/A (void) strlcpy(bufa, fa, sizeof (bufa));
2N/A (void) strlcpy(bufb, fb, sizeof (bufb));
2N/A if ((fa = strchr(bufa, ':')) != NULL ||
2N/A (fa = strchr(bufa, '/')) != NULL)
2N/A *fa++ = '\0';
2N/A if ((fb = strchr(bufb, ':')) != NULL ||
2N/A (fb = strchr(bufb, '/')) != NULL)
2N/A *fb++ = '\0';
2N/A return (devid_str_compare(bufa, bufb) == 0);
2N/A }
2N/A fa = strstr(a, ":" FM_FMRI_HC_V1_FRU_PN);
2N/A if (fa == NULL)
2N/A fa = strstr(a, ":" FM_FMRI_HC_V0_PART);
2N/A fb = strstr(b, ":" FM_FMRI_HC_V1_FRU_PN);
2N/A if (fb == NULL)
2N/A fb = strstr(b, ":" FM_FMRI_HC_V0_PART);
2N/A if (fa != NULL && fb != NULL) {
2N/A ffa = ++fa;
2N/A ffb = ++fb;
2N/A if ((fa = strchr(ffa, ':')) != NULL ||
2N/A (fa = strchr(ffa, '/')) != NULL)
2N/A lena = fa++ - ffa;
2N/A if ((fb = strchr(ffb, ':')) != NULL ||
2N/A (fb = strchr(ffb, '/')) != NULL)
2N/A lenb = fb++ - ffb;
2N/A if (lena != lenb)
2N/A return (B_FALSE);
2N/A if (strncmp(ffa, ffb, lena) != 0)
2N/A return (B_FALSE);
2N/A } else if (fa != NULL || fb != NULL) {
2N/A return (B_FALSE);
2N/A }
2N/A
2N/A fa = strstr(a, ":" FM_FMRI_HC_V1_FRU_SN);
2N/A if (fa == NULL)
2N/A fa = strstr(a, ":" FM_FMRI_HC_V0_SERIAL);
2N/A fb = strstr(b, ":" FM_FMRI_HC_V1_FRU_SN);
2N/A if (fb == NULL)
2N/A fb = strstr(b, ":" FM_FMRI_HC_V0_SERIAL);
2N/A if (fa != NULL && fb != NULL) {
2N/A ffa = ++fa;
2N/A ffb = ++fb;
2N/A if ((fa = strchr(ffa, ':')) != NULL ||
2N/A (fa = strchr(ffa, '/')) != NULL)
2N/A lena = fa++ - ffa;
2N/A if ((fb = strchr(ffb, ':')) != NULL ||
2N/A (fb = strchr(ffb, '/')) != NULL)
2N/A lenb = fb++ - ffb;
2N/A if (lena != lenb)
2N/A return (B_FALSE);
2N/A return (strncmp(ffa, ffb, lena) == 0);
2N/A } else if (fa != NULL || fb != NULL) {
2N/A return (B_FALSE);
2N/A }
2N/A
2N/A fa = strstr(a, ":" FM_FMRI_HC_PARENT_SERIAL);
2N/A fb = strstr(b, ":" FM_FMRI_HC_PARENT_SERIAL);
2N/A if (fa != NULL && fb != NULL) {
2N/A ffa = ++fa;
2N/A ffb = ++fb;
2N/A if ((fa = strchr(ffa, ':')) != NULL ||
2N/A (fa = strchr(ffa, '/')) != NULL)
2N/A lena = fa++ - ffa;
2N/A if ((fb = strchr(ffb, ':')) != NULL ||
2N/A (fb = strchr(ffb, '/')) != NULL)
2N/A lenb = fb++ - ffb;
2N/A if (lena != lenb)
2N/A return (B_FALSE);
2N/A return (strncmp(ffa, ffb, lena) == 0);
2N/A } else if (fa != NULL || fb != NULL) {
2N/A return (B_FALSE);
2N/A }
2N/A return (B_TRUE);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_ident_node(topo_mod_t *mod, tnode_t *node, void *pdata)
2N/A{
2N/A int err;
2N/A tnode_t *pnp = node;
2N/A struct hc_args *hap = (struct hc_args *)pdata;
2N/A nvlist_t *rsrc;
2N/A char *ptr;
2N/A
2N/A while (pnp != NULL && topo_node_resource(pnp, &rsrc, &err) == 0) {
2N/A if (nvlist_lookup_string(rsrc, FM_FMRI_HC_V1_FRU_SN,
2N/A &ptr) == 0 ||
2N/A nvlist_lookup_string(rsrc, FM_FMRI_HC_V0_SERIAL,
2N/A &ptr) == 0 ||
2N/A nvlist_lookup_string(rsrc, FM_FMRI_HC_DEVID, &ptr) == 0) {
2N/A hap->ha_nvl = rsrc;
2N/A return (0);
2N/A } else
2N/A nvlist_free(rsrc);
2N/A pnp = topo_node_parent(pnp);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Ahc_fmri_ident_node(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A int err;
2N/A struct hc_walk *hwp;
2N/A struct hc_args *hap;
2N/A nvlist_t *rsrc;
2N/A
2N/A if (version > TOPO_METH_IDENT_NODE_VERSION)
2N/A return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2N/A
2N/A err = nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &rsrc);
2N/A if (err != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A
2N/A if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A
2N/A hap->ha_nvl = NULL;
2N/A if ((hwp = hc_walk_init(mod, node, rsrc, hc_ident_node,
2N/A (void *)hap)) != NULL) {
2N/A if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2N/A TOPO_WALK_ERR)
2N/A err = -1;
2N/A else
2N/A err = 0;
2N/A topo_walk_fini(hwp->hcw_wp);
2N/A } else {
2N/A err = -1;
2N/A }
2N/A
2N/A topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2N/A
2N/A if (hap->ha_nvl != NULL)
2N/A *out = hap->ha_nvl;
2N/A
2N/A topo_mod_free(mod, hap, sizeof (struct hc_args));
2N/A
2N/A return (err);
2N/A}