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) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Support function for the i86pc chip enumerator
2N/A */
2N/A
2N/A#include <sys/types.h>
2N/A#include <stdarg.h>
2N/A#include <strings.h>
2N/A#include <fm/fmd_fmri.h>
2N/A#include <sys/systeminfo.h>
2N/A#include <sys/fm/protocol.h>
2N/A#include <fm/topo_mod.h>
2N/A#include <fm/fmd_agent.h>
2N/A
2N/A#include "chip.h"
2N/A
2N/Astatic void fmri_dprint(topo_mod_t *, const char *, uint32_t, nvlist_t *);
2N/Astatic boolean_t is_page_fmri(nvlist_t *);
2N/A
2N/Aconst topo_method_t rank_methods[] = {
2N/A { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
2N/A TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
2N/A mem_asru_compute },
2N/A { TOPO_METH_PRESENCE_STATE, TOPO_METH_PRESENCE_STATE_DESC,
2N/A TOPO_METH_PRESENCE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
2N/A rank_fmri_presence_state },
2N/A { NULL }
2N/A};
2N/A
2N/A/*
2N/A * Whinge a debug message via topo_mod_dprintf and increment the
2N/A * given error counter.
2N/A */
2N/Avoid
2N/Awhinge(topo_mod_t *mod, int *nerr, const char *fmt, ...)
2N/A{
2N/A va_list ap;
2N/A char buf[160];
2N/A
2N/A if (nerr != NULL)
2N/A ++*nerr;
2N/A
2N/A va_start(ap, fmt);
2N/A (void) vsnprintf(buf, sizeof (buf), fmt, ap);
2N/A va_end(ap);
2N/A
2N/A topo_mod_dprintf(mod, "%s", buf);
2N/A}
2N/A
2N/A/*
2N/A * Given an nvpair of a limited number of data types, extract the property
2N/A * name and value and add that combination to the given node in the
2N/A * specified property group using the corresponding topo_prop_set_* function
2N/A * for the data type. Return 1 on success, otherwise 0.
2N/A */
2N/Aint
2N/Anvprop_add(topo_mod_t *mod, nvpair_t *nvp, const char *pgname, tnode_t *node)
2N/A{
2N/A int success = 0;
2N/A int err;
2N/A char *pname = nvpair_name(nvp);
2N/A
2N/A switch (nvpair_type(nvp)) {
2N/A case DATA_TYPE_BOOLEAN_VALUE: {
2N/A boolean_t val;
2N/A
2N/A if (nvpair_value_boolean_value(nvp, &val) == 0 &&
2N/A topo_prop_set_string(node, pgname, pname,
2N/A TOPO_PROP_IMMUTABLE, val ? "true" : "false", &err) == 0)
2N/A success = 1;
2N/A break;
2N/A }
2N/A
2N/A case DATA_TYPE_UINT32: {
2N/A uint32_t val;
2N/A
2N/A if (nvpair_value_uint32(nvp, &val) == 0 &&
2N/A topo_prop_set_uint32(node, pgname, pname,
2N/A TOPO_PROP_IMMUTABLE, val, &err) == 0)
2N/A success = 1;
2N/A break;
2N/A }
2N/A
2N/A case DATA_TYPE_UINT64: {
2N/A uint64_t val;
2N/A
2N/A if (nvpair_value_uint64(nvp, &val) == 0 &&
2N/A topo_prop_set_uint64(node, pgname, pname,
2N/A TOPO_PROP_IMMUTABLE, val, &err) == 0)
2N/A success = 1;
2N/A break;
2N/A }
2N/A
2N/A case DATA_TYPE_UINT32_ARRAY: {
2N/A uint32_t *arrp;
2N/A uint_t nelem;
2N/A
2N/A if (nvpair_value_uint32_array(nvp, &arrp, &nelem) == 0 &&
2N/A nelem > 0 && topo_prop_set_uint32_array(node, pgname, pname,
2N/A TOPO_PROP_IMMUTABLE, arrp, nelem, &err) == 0)
2N/A success = 1;
2N/A break;
2N/A }
2N/A
2N/A case DATA_TYPE_STRING: {
2N/A char *str;
2N/A
2N/A if (nvpair_value_string(nvp, &str) == 0 &&
2N/A topo_prop_set_string(node, pgname, pname,
2N/A TOPO_PROP_IMMUTABLE, str, &err) == 0)
2N/A success = 1;
2N/A break;
2N/A }
2N/A
2N/A default:
2N/A whinge(mod, &err, "nvprop_add: Can't handle type %d for "
2N/A "'%s' in property group %s of %s node\n",
2N/A nvpair_type(nvp), pname, pgname, topo_node_name(node));
2N/A break;
2N/A }
2N/A
2N/A return (success ? 0 : 1);
2N/A}
2N/A
2N/A/*
2N/A * Lookup string data named pname in the given nvlist and add that
2N/A * as property named pname in the given property group pgname on the indicated
2N/A * topo node. Fill pvalp with a pointer to the string value, valid until
2N/A * nvlist_free is called.
2N/A */
2N/Aint
2N/Aadd_nvlist_strprop(topo_mod_t *mod, tnode_t *node, nvlist_t *nvl,
2N/A const char *pgname, const char *pname, const char **pvalp)
2N/A{
2N/A char *pval;
2N/A int err = 0;
2N/A
2N/A if (nvlist_lookup_string(nvl, pname, &pval) != 0)
2N/A return (-1);
2N/A
2N/A if (topo_prop_set_string(node, pgname, pname,
2N/A TOPO_PROP_IMMUTABLE, pval, &err) == 0) {
2N/A if (pvalp)
2N/A *pvalp = pval;
2N/A return (0);
2N/A } else {
2N/A whinge(mod, &err, "add_nvlist_strprop: failed to add '%s'\n",
2N/A pname);
2N/A return (-1);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Lookup an int32 item named pname in the given nvlist and add that
2N/A * as property named pname in the given property group pgname on the indicated
2N/A * topo node. Fill pvalp with the property value.
2N/A */
2N/Aint
2N/Aadd_nvlist_longprop(topo_mod_t *mod, tnode_t *node, nvlist_t *nvl,
2N/A const char *pgname, const char *pname, int32_t *pvalp)
2N/A{
2N/A int32_t pval;
2N/A int err;
2N/A
2N/A if ((nvlist_lookup_int32(nvl, pname, &pval)) != 0)
2N/A return (-1);
2N/A
2N/A if (topo_prop_set_int32(node, pgname, pname,
2N/A TOPO_PROP_IMMUTABLE, pval, &err) == 0) {
2N/A if (pvalp)
2N/A *pvalp = pval;
2N/A return (0);
2N/A } else {
2N/A whinge(mod, &err, "add_nvlist_longprop: failed to add '%s'\n",
2N/A pname);
2N/A return (-1);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * In a given nvlist lookup a variable number of int32 properties named in
2N/A * const char * varargs and each each in the given property group on the
2N/A * node. Fill an array of the retrieved values.
2N/A */
2N/Aint
2N/Aadd_nvlist_longprops(topo_mod_t *mod, tnode_t *node, nvlist_t *nvl,
2N/A const char *pgname, int32_t *pvalap, ...)
2N/A{
2N/A const char *pname;
2N/A va_list ap;
2N/A int nerr = 0;
2N/A
2N/A va_start(ap, pvalap);
2N/A while ((pname = va_arg(ap, const char *)) != NULL) {
2N/A if (add_nvlist_longprop(mod, node, nvl, pgname, pname,
2N/A pvalap) != 0)
2N/A nerr++; /* have whinged elsewhere */
2N/A
2N/A if (pvalap != NULL)
2N/A ++pvalap;
2N/A }
2N/A va_end(ap);
2N/A
2N/A return (nerr == 0 ? 0 : -1);
2N/A}
2N/A
2N/A/*
2N/A * Construct an hc scheme resource FMRI for a node named name with
2N/A * instance number inst, parented by the given parent node pnode.
2N/A */
2N/Aint
2N/Amkrsrc(topo_mod_t *mod, tnode_t *pnode, const char *name, int inst,
2N/A nvlist_t *auth, nvlist_t **nvl)
2N/A{
2N/A *nvl = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, name,
2N/A inst, NULL, auth, NULL, NULL, NULL);
2N/A return (nvl != NULL ? 0 : -1); /* caller must free nvlist */
2N/A}
2N/A
2N/A/*
2N/A * Construct a cpu scheme FMRI with the given data; the caller must free
2N/A * the allocated nvlist with nvlist_free().
2N/A */
2N/Anvlist_t *
2N/Acpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *s, uint8_t cpumask)
2N/A{
2N/A int err;
2N/A nvlist_t *asru;
2N/A
2N/A if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0)
2N/A return (NULL);
2N/A
2N/A err = nvlist_add_uint8(asru, FM_VERSION, FM_CPU_SCHEME_VERSION);
2N/A err |= nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU);
2N/A err |= nvlist_add_uint32(asru, FM_FMRI_CPU_ID, cpuid);
2N/A err |= nvlist_add_uint8(asru, FM_FMRI_CPU_MASK, cpumask);
2N/A if (s != NULL)
2N/A err |= nvlist_add_string(asru, FM_FMRI_CPU_SERIAL_ID, s);
2N/A if (err != 0) {
2N/A nvlist_free(asru);
2N/A (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
2N/A return (NULL);
2N/A }
2N/A
2N/A return (asru);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/Amem_asru_compute(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 *asru, *args, *pargs, *hcsp;
2N/A int err;
2N/A uint64_t pa, offset;
2N/A
2N/A if (strcmp(topo_node_name(node), RANK_NODE_NAME) != 0 &&
2N/A strcmp(topo_node_name(node), DIMM_NODE_NAME) != 0 &&
2N/A strcmp(topo_node_name(node), CS_NODE_NAME) != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A
2N/A if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A
2N/A if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs)) != 0) {
2N/A if (err == ENOENT) {
2N/A pargs = args;
2N/A } else {
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A }
2N/A }
2N/A
2N/A if (topo_mod_nvdup(mod, pargs, &asru) != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A
2N/A err = 0;
2N/A
2N/A /*
2N/A * if 'in' includes an hc-specific member which specifies asru-physaddr
2N/A * or asru-offset then rename them to asru and physaddr respectively.
2N/A */
2N/A if (nvlist_lookup_nvlist(asru, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) {
2N/A if (nvlist_lookup_uint64(hcsp,
2N/A "asru-"FM_FMRI_HC_SPECIFIC_PHYSADDR, &pa) == 0) {
2N/A err += nvlist_remove(hcsp,
2N/A "asru-"FM_FMRI_HC_SPECIFIC_PHYSADDR,
2N/A DATA_TYPE_UINT64);
2N/A err += nvlist_add_uint64(hcsp,
2N/A FM_FMRI_HC_SPECIFIC_PHYSADDR,
2N/A pa);
2N/A }
2N/A
2N/A if (nvlist_lookup_uint64(hcsp,
2N/A "asru-"FM_FMRI_HC_SPECIFIC_OFFSET, &offset) == 0) {
2N/A err += nvlist_remove(hcsp,
2N/A "asru-"FM_FMRI_HC_SPECIFIC_OFFSET,
2N/A DATA_TYPE_UINT64);
2N/A err += nvlist_add_uint64(hcsp,
2N/A FM_FMRI_HC_SPECIFIC_OFFSET,
2N/A offset);
2N/A }
2N/A }
2N/A
2N/A if (err != 0 || topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) {
2N/A nvlist_free(asru);
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A }
2N/A
2N/A err = nvlist_add_string(*out, TOPO_PROP_VAL_NAME, TOPO_PROP_ASRU);
2N/A err |= nvlist_add_uint32(*out, TOPO_PROP_VAL_TYPE, TOPO_TYPE_FMRI);
2N/A err |= nvlist_add_nvlist(*out, TOPO_PROP_VAL_VAL, asru);
2N/A if (err != 0) {
2N/A nvlist_free(asru);
2N/A nvlist_free(*out);
2N/A return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
2N/A }
2N/A
2N/A nvlist_free(asru);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aset_retnvl(topo_mod_t *mod, nvlist_t **out, const char *retname, uint32_t ret)
2N/A{
2N/A nvlist_t *nvl;
2N/A
2N/A if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) < 0)
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A
2N/A if (nvlist_add_uint32(nvl, retname, ret) != 0) {
2N/A nvlist_free(nvl);
2N/A return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
2N/A }
2N/A
2N/A *out = nvl;
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * If we're getting called then the question of whether this dimm is plugged
2N/A * in has already been answered. What we don't know for sure is whether it's
2N/A * the same dimm or a different one plugged in the same slot. To check, we
2N/A * try and compare the serial numbers on the dimm in the current topology with
2N/A * the serial num from the unum fmri that got passed into this function as the
2N/A * argument.
2N/A *
2N/A */
2N/Astatic int
2N/Afmri_presence_state(topo_mod_t *mod, tnode_t *node, nvlist_t *unum, int *errp)
2N/A{
2N/A tnode_t *dimmnode;
2N/A nvlist_t *resource;
2N/A int err;
2N/A char *old_serial, *curr_serial;
2N/A
2N/A /*
2N/A * If a serial number for the dimm was available at the time of the
2N/A * fault, it will have been added as a string to the unum nvlist
2N/A */
2N/A if (nvlist_lookup_string(unum, FM_FMRI_HC_V1_FRU_SN, &old_serial) &&
2N/A nvlist_lookup_string(unum, FM_FMRI_HC_V0_SERIAL, &old_serial))
2N/A return (FMD_OBJ_STATE_UNKNOWN);
2N/A
2N/A /*
2N/A * If the current serial number is available for the DIMM that this rank
2N/A * belongs to, it will be accessible as a property on the parent (dimm)
2N/A * node. If there is a serial id in the resource fmri, then use that.
2N/A * Otherwise fall back to looking for a serial id property in the
2N/A * protocol group.
2N/A */
2N/A dimmnode = topo_node_parent(node);
2N/A if (topo_node_resource(dimmnode, &resource, &err) != -1) {
2N/A if (nvlist_lookup_string(resource, FM_FMRI_HC_V1_FRU_SN,
2N/A &curr_serial) == 0 ||
2N/A nvlist_lookup_string(resource, FM_FMRI_HC_V0_SERIAL,
2N/A &curr_serial) == 0) {
2N/A if (strcmp(old_serial, curr_serial) != 0) {
2N/A nvlist_free(resource);
2N/A return (FMD_OBJ_STATE_REPLACED);
2N/A } else {
2N/A nvlist_free(resource);
2N/A return (FMD_OBJ_STATE_STILL_PRESENT);
2N/A }
2N/A }
2N/A nvlist_free(resource);
2N/A }
2N/A if (topo_prop_get_string(dimmnode, TOPO_PGROUP_PROTOCOL,
2N/A FM_FMRI_HC_V1_FRU_SN, &curr_serial, &err) != 0 &&
2N/A topo_prop_get_string(dimmnode, TOPO_PGROUP_PROTOCOL,
2N/A FM_FMRI_HC_V0_SERIAL, &curr_serial, &err) != 0) {
2N/A if (err == ETOPO_PROP_NOENT) {
2N/A return (FMD_OBJ_STATE_UNKNOWN);
2N/A } else {
2N/A *errp = EMOD_NVL_INVAL;
2N/A whinge(mod, NULL, "fmri_presence_state: Unexpected "
2N/A "error retrieving serial from node");
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A if (strcmp(old_serial, curr_serial) != 0) {
2N/A topo_mod_strfree(mod, curr_serial);
2N/A return (FMD_OBJ_STATE_REPLACED);
2N/A }
2N/A
2N/A topo_mod_strfree(mod, curr_serial);
2N/A
2N/A return (FMD_OBJ_STATE_STILL_PRESENT);
2N/A}
2N/A
2N/Aint
2N/Arank_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 presence_state, err;
2N/A
2N/A if (version > TOPO_METH_PRESENCE_STATE_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A
2N/A presence_state = fmri_presence_state(mod, node, in, &err);
2N/A if (presence_state == -1)
2N/A return (topo_mod_seterrno(mod, err));
2N/A
2N/A fmri_dprint(mod, "rank_fmri_presence_state", presence_state, in);
2N/A
2N/A return (set_retnvl(mod, out, TOPO_METH_PRESENCE_STATE_RET,
2N/A presence_state));
2N/A}
2N/A
2N/Astatic void
2N/Afmri_dprint(topo_mod_t *mod, const char *op, uint32_t rc, nvlist_t *fmri)
2N/A{
2N/A char *fmristr;
2N/A const char *status;
2N/A
2N/A if (getenv("TOPOCHIPDBG") == NULL)
2N/A return;
2N/A
2N/A switch (rc) {
2N/A case FMD_AGENT_RETIRE_DONE:
2N/A status = "sync success";
2N/A break;
2N/A case FMD_AGENT_RETIRE_ASYNC:
2N/A status = "async retiring";
2N/A break;
2N/A case FMD_AGENT_RETIRE_FAIL:
2N/A status = "not retired";
2N/A break;
2N/A default:
2N/A status = "unknown status";
2N/A }
2N/A if (fmri != NULL && topo_mod_nvl2str(mod, fmri, &fmristr) == 0) {
2N/A topo_mod_dprintf(mod, "[%s]: %s => %d (\"%s\")\n", fmristr,
2N/A op, rc, status);
2N/A topo_mod_strfree(mod, fmristr);
2N/A }
2N/A}
2N/A
2N/Astruct strand_walk_data {
2N/A tnode_t *parent;
2N/A fmd_agent_hdl_t *hdl;
2N/A int (*func)(fmd_agent_hdl_t *, int, int, int);
2N/A int err;
2N/A int done;
2N/A int fail;
2N/A int async;
2N/A};
2N/A
2N/Astatic int
2N/Astrand_walker(topo_mod_t *mod, tnode_t *node, void *pdata)
2N/A{
2N/A struct strand_walk_data *swdp = pdata;
2N/A int32_t chipid, coreid, strandid;
2N/A int err, rc;
2N/A
2N/A /*
2N/A * Terminate the walk if we reach start-node's sibling
2N/A */
2N/A if (node != swdp->parent &&
2N/A topo_node_parent(node) == topo_node_parent(swdp->parent))
2N/A return (TOPO_WALK_TERMINATE);
2N/A
2N/A if (strcmp(topo_node_name(node), STRAND) != 0)
2N/A return (TOPO_WALK_NEXT);
2N/A
2N/A if (topo_prop_get_int32(node, PGNAME(STRAND), STRAND_CHIP_ID,
2N/A &chipid, &err) < 0 ||
2N/A topo_prop_get_int32(node, PGNAME(STRAND), STRAND_CORE_ID,
2N/A &coreid, &err) < 0) {
2N/A swdp->err++;
2N/A return (TOPO_WALK_NEXT);
2N/A }
2N/A strandid = topo_node_instance(node);
2N/A rc = swdp->func(swdp->hdl, chipid, coreid, strandid);
2N/A
2N/A if (rc == FMD_AGENT_RETIRE_DONE)
2N/A swdp->done++;
2N/A else if (rc == FMD_AGENT_RETIRE_FAIL)
2N/A swdp->fail++;
2N/A else if (rc == FMD_AGENT_RETIRE_ASYNC)
2N/A swdp->async++;
2N/A else
2N/A swdp->err++;
2N/A
2N/A if (getenv("TOPOCHIPDBG") != NULL) {
2N/A const char *op;
2N/A
2N/A if (swdp->func == fmd_agent_cpu_retire)
2N/A op = "retire";
2N/A else if (swdp->func == fmd_agent_cpu_unretire)
2N/A op = "unretire";
2N/A else if (swdp->func == fmd_agent_cpu_isretired)
2N/A op = "check status";
2N/A else
2N/A op = "unknown op";
2N/A
2N/A topo_mod_dprintf(mod, "%s cpu (%d:%d:%d): rc = %d, err = %s\n",
2N/A op, (int)chipid, (int)coreid, (int)strandid, rc,
2N/A fmd_agent_errmsg(swdp->hdl));
2N/A }
2N/A
2N/A return (TOPO_WALK_NEXT);
2N/A}
2N/A
2N/Astatic int
2N/Awalk_strands(topo_mod_t *mod, struct strand_walk_data *swdp, tnode_t *parent,
2N/A int (*func)(fmd_agent_hdl_t *, int, int, int))
2N/A{
2N/A topo_walk_t *twp;
2N/A int err;
2N/A
2N/A swdp->parent = parent;
2N/A swdp->func = func;
2N/A swdp->err = swdp->done = swdp->fail = swdp->async = 0;
2N/A if ((swdp->hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL) {
2N/A swdp->fail++;
2N/A return (0);
2N/A }
2N/A
2N/A twp = topo_mod_walk_init(mod, parent, strand_walker, swdp, &err);
2N/A if (twp == NULL) {
2N/A fmd_agent_close(swdp->hdl);
2N/A return (-1);
2N/A }
2N/A
2N/A err = topo_walk_step(twp, TOPO_WALK_CHILD);
2N/A topo_walk_fini(twp);
2N/A fmd_agent_close(swdp->hdl);
2N/A
2N/A if (err == TOPO_WALK_ERR || swdp->err > 0)
2N/A return (-1);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Aint
2N/Aretire_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A struct strand_walk_data swd;
2N/A uint32_t rc;
2N/A
2N/A if (version > TOPO_METH_RETIRE_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A
2N/A if (walk_strands(mod, &swd, node, fmd_agent_cpu_retire) == -1)
2N/A return (-1);
2N/A
2N/A if (swd.fail > 0)
2N/A rc = FMD_AGENT_RETIRE_FAIL;
2N/A else if (swd.async > 0)
2N/A rc = FMD_AGENT_RETIRE_ASYNC;
2N/A else
2N/A rc = FMD_AGENT_RETIRE_DONE;
2N/A
2N/A return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc));
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Aint
2N/Aunretire_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A struct strand_walk_data swd;
2N/A uint32_t rc;
2N/A
2N/A if (version > TOPO_METH_UNRETIRE_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A
2N/A if (walk_strands(mod, &swd, node, fmd_agent_cpu_unretire) == -1)
2N/A return (-1);
2N/A
2N/A if (swd.fail > 0)
2N/A rc = FMD_AGENT_RETIRE_FAIL;
2N/A else if (swd.async > 0)
2N/A rc = FMD_AGENT_RETIRE_ASYNC;
2N/A else
2N/A rc = FMD_AGENT_RETIRE_DONE;
2N/A
2N/A return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc));
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Aint
2N/Aservice_state_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A struct strand_walk_data swd;
2N/A uint32_t rc;
2N/A
2N/A if (version > TOPO_METH_SERVICE_STATE_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A
2N/A if (walk_strands(mod, &swd, node, fmd_agent_cpu_isretired) == -1)
2N/A return (-1);
2N/A
2N/A if (swd.done > 0)
2N/A rc = (swd.fail + swd.async > 0) ? FMD_SERVICE_STATE_DEGRADED :
2N/A FMD_SERVICE_STATE_UNUSABLE;
2N/A else if (swd.async > 0)
2N/A rc = FMD_SERVICE_STATE_ISOLATE_PENDING;
2N/A else if (swd.fail > 0)
2N/A rc = FMD_SERVICE_STATE_OK;
2N/A else
2N/A rc = FMD_SERVICE_STATE_UNKNOWN;
2N/A
2N/A return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc));
2N/A}
2N/A
2N/Astatic boolean_t
2N/Ais_page_fmri(nvlist_t *nvl)
2N/A{
2N/A nvlist_t *hcsp;
2N/A uint64_t val;
2N/A
2N/A if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) == 0 &&
2N/A (nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET,
2N/A &val) == 0 ||
2N/A nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_OFFSET,
2N/A &val) == 0 ||
2N/A nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_PHYSADDR,
2N/A &val) == 0 ||
2N/A nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR,
2N/A &val) == 0))
2N/A return (B_TRUE);
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Aint
2N/Antv_page_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A fmd_agent_hdl_t *hdl;
2N/A uint32_t rc = FMD_AGENT_RETIRE_FAIL;
2N/A
2N/A if (version > TOPO_METH_RETIRE_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A if (is_page_fmri(in)) {
2N/A if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
2N/A rc = fmd_agent_page_retire(hdl, in);
2N/A fmd_agent_close(hdl);
2N/A }
2N/A }
2N/A fmri_dprint(mod, "ntv_page_retire", rc, in);
2N/A return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc));
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Aint
2N/Antv_page_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A fmd_agent_hdl_t *hdl;
2N/A uint32_t rc = FMD_AGENT_RETIRE_FAIL;
2N/A
2N/A if (version > TOPO_METH_UNRETIRE_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A if (is_page_fmri(in)) {
2N/A if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
2N/A rc = fmd_agent_page_unretire(hdl, in);
2N/A fmd_agent_close(hdl);
2N/A }
2N/A }
2N/A fmri_dprint(mod, "ntv_page_unretire", rc, in);
2N/A return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc));
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Aint
2N/Antv_page_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 fmd_agent_hdl_t *hdl;
2N/A uint32_t rc = FMD_SERVICE_STATE_UNKNOWN;
2N/A
2N/A if (version > TOPO_METH_SERVICE_STATE_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A if (is_page_fmri(in)) {
2N/A if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) {
2N/A rc = fmd_agent_page_isretired(hdl, in);
2N/A fmd_agent_close(hdl);
2N/A if (rc == FMD_AGENT_RETIRE_DONE)
2N/A rc = FMD_SERVICE_STATE_UNUSABLE;
2N/A else if (rc == FMD_AGENT_RETIRE_FAIL)
2N/A rc = FMD_SERVICE_STATE_OK;
2N/A else if (rc == FMD_AGENT_RETIRE_ASYNC)
2N/A rc = FMD_SERVICE_STATE_ISOLATE_PENDING;
2N/A }
2N/A }
2N/A
2N/A topo_mod_dprintf(mod, "ntv_page_service_state: rc = %u\n", rc);
2N/A return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc));
2N/A}