60405de4d8688d96dd05157c28db3ade5c9bc234kz/*
60405de4d8688d96dd05157c28db3ade5c9bc234kz * CDDL HEADER START
60405de4d8688d96dd05157c28db3ade5c9bc234kz *
60405de4d8688d96dd05157c28db3ade5c9bc234kz * The contents of this file are subject to the terms of the
60405de4d8688d96dd05157c28db3ade5c9bc234kz * Common Development and Distribution License (the "License").
60405de4d8688d96dd05157c28db3ade5c9bc234kz * You may not use this file except in compliance with the License.
60405de4d8688d96dd05157c28db3ade5c9bc234kz *
60405de4d8688d96dd05157c28db3ade5c9bc234kz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
60405de4d8688d96dd05157c28db3ade5c9bc234kz * or http://www.opensolaris.org/os/licensing.
60405de4d8688d96dd05157c28db3ade5c9bc234kz * See the License for the specific language governing permissions
60405de4d8688d96dd05157c28db3ade5c9bc234kz * and limitations under the License.
60405de4d8688d96dd05157c28db3ade5c9bc234kz *
60405de4d8688d96dd05157c28db3ade5c9bc234kz * When distributing Covered Code, include this CDDL HEADER in each
60405de4d8688d96dd05157c28db3ade5c9bc234kz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
60405de4d8688d96dd05157c28db3ade5c9bc234kz * If applicable, add the following below this CDDL HEADER, with the
60405de4d8688d96dd05157c28db3ade5c9bc234kz * fields enclosed by brackets "[]" replaced with your own identifying
60405de4d8688d96dd05157c28db3ade5c9bc234kz * information: Portions Copyright [yyyy] [name of copyright owner]
60405de4d8688d96dd05157c28db3ade5c9bc234kz *
60405de4d8688d96dd05157c28db3ade5c9bc234kz * CDDL HEADER END
60405de4d8688d96dd05157c28db3ade5c9bc234kz */
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz/*
60405de4d8688d96dd05157c28db3ade5c9bc234kz * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
60405de4d8688d96dd05157c28db3ade5c9bc234kz * Use is subject to license terms.
60405de4d8688d96dd05157c28db3ade5c9bc234kz */
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz#include <strings.h>
60405de4d8688d96dd05157c28db3ade5c9bc234kz#include <string.h>
60405de4d8688d96dd05157c28db3ade5c9bc234kz#include <libnvpair.h>
60405de4d8688d96dd05157c28db3ade5c9bc234kz#include <sys/fm/ldom.h>
60405de4d8688d96dd05157c28db3ade5c9bc234kz#include <fm/libtopo.h>
e92e3a8694f157faf8a9e44096a70ada86c556bfzw#include <fm/topo_mod.h>
e92e3a8694f157faf8a9e44096a70ada86c556bfzw#include <fm/fmd_fmri.h>
e92e3a8694f157faf8a9e44096a70ada86c556bfzw#include <fm/fmd_agent.h>
e92e3a8694f157faf8a9e44096a70ada86c556bfzw#include <sys/fm/ldom.h>
e92e3a8694f157faf8a9e44096a70ada86c556bfzw
60405de4d8688d96dd05157c28db3ade5c9bc234kzstruct cpu_walk_data {
60405de4d8688d96dd05157c28db3ade5c9bc234kz tnode_t *parent; /* walk start node */
60405de4d8688d96dd05157c28db3ade5c9bc234kz ldom_hdl_t *lhp; /* ldom handle */
60405de4d8688d96dd05157c28db3ade5c9bc234kz int (*func)(ldom_hdl_t *, nvlist_t *); /* callback func */
60405de4d8688d96dd05157c28db3ade5c9bc234kz int err; /* walk errors count */
60405de4d8688d96dd05157c28db3ade5c9bc234kz int online; /* online cpus count */
60405de4d8688d96dd05157c28db3ade5c9bc234kz int offline; /* offline cpus count */
60405de4d8688d96dd05157c28db3ade5c9bc234kz int fail; /* callback fails */
60405de4d8688d96dd05157c28db3ade5c9bc234kz};
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kzstatic topo_method_f
60405de4d8688d96dd05157c28db3ade5c9bc234kz cpu_retire, cpu_unretire, cpu_service_state,
60405de4d8688d96dd05157c28db3ade5c9bc234kz cpu_unusable, mem_asru_compute, dimm_page_unusable,
60405de4d8688d96dd05157c28db3ade5c9bc234kz dimm_page_service_state, dimm_page_retire, dimm_page_unretire;
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kzconst topo_method_t pi_cpu_methods[] = {
60405de4d8688d96dd05157c28db3ade5c9bc234kz { TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
60405de4d8688d96dd05157c28db3ade5c9bc234kz TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
60405de4d8688d96dd05157c28db3ade5c9bc234kz cpu_retire },
60405de4d8688d96dd05157c28db3ade5c9bc234kz { TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
60405de4d8688d96dd05157c28db3ade5c9bc234kz TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
60405de4d8688d96dd05157c28db3ade5c9bc234kz cpu_unretire },
60405de4d8688d96dd05157c28db3ade5c9bc234kz { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
60405de4d8688d96dd05157c28db3ade5c9bc234kz TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
60405de4d8688d96dd05157c28db3ade5c9bc234kz cpu_service_state },
60405de4d8688d96dd05157c28db3ade5c9bc234kz { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
60405de4d8688d96dd05157c28db3ade5c9bc234kz TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
60405de4d8688d96dd05157c28db3ade5c9bc234kz cpu_unusable },
60405de4d8688d96dd05157c28db3ade5c9bc234kz { NULL }
60405de4d8688d96dd05157c28db3ade5c9bc234kz};
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kzconst topo_method_t pi_mem_methods[] = {
60405de4d8688d96dd05157c28db3ade5c9bc234kz { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
60405de4d8688d96dd05157c28db3ade5c9bc234kz TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
60405de4d8688d96dd05157c28db3ade5c9bc234kz mem_asru_compute },
60405de4d8688d96dd05157c28db3ade5c9bc234kz { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
60405de4d8688d96dd05157c28db3ade5c9bc234kz TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
60405de4d8688d96dd05157c28db3ade5c9bc234kz dimm_page_service_state },
60405de4d8688d96dd05157c28db3ade5c9bc234kz { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
60405de4d8688d96dd05157c28db3ade5c9bc234kz TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
60405de4d8688d96dd05157c28db3ade5c9bc234kz dimm_page_unusable },
60405de4d8688d96dd05157c28db3ade5c9bc234kz { TOPO_METH_RETIRE, TOPO_METH_RETIRE_DESC,
60405de4d8688d96dd05157c28db3ade5c9bc234kz TOPO_METH_RETIRE_VERSION, TOPO_STABILITY_INTERNAL,
60405de4d8688d96dd05157c28db3ade5c9bc234kz dimm_page_retire },
60405de4d8688d96dd05157c28db3ade5c9bc234kz { TOPO_METH_UNRETIRE, TOPO_METH_UNRETIRE_DESC,
60405de4d8688d96dd05157c28db3ade5c9bc234kz TOPO_METH_UNRETIRE_VERSION, TOPO_STABILITY_INTERNAL,
60405de4d8688d96dd05157c28db3ade5c9bc234kz dimm_page_unretire },
60405de4d8688d96dd05157c28db3ade5c9bc234kz { NULL }
60405de4d8688d96dd05157c28db3ade5c9bc234kz};
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kzstatic ldom_hdl_t *pi_lhp = NULL;
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz#pragma init(pi_ldom_init)
60405de4d8688d96dd05157c28db3ade5c9bc234kzstatic void
60405de4d8688d96dd05157c28db3ade5c9bc234kzpi_ldom_init(void)
60405de4d8688d96dd05157c28db3ade5c9bc234kz{
60405de4d8688d96dd05157c28db3ade5c9bc234kz pi_lhp = ldom_init(NULL, NULL);
60405de4d8688d96dd05157c28db3ade5c9bc234kz}
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz#pragma fini(pi_ldom_fini)
60405de4d8688d96dd05157c28db3ade5c9bc234kzstatic void
60405de4d8688d96dd05157c28db3ade5c9bc234kzpi_ldom_fini(void)
60405de4d8688d96dd05157c28db3ade5c9bc234kz{
60405de4d8688d96dd05157c28db3ade5c9bc234kz if (pi_lhp != NULL)
60405de4d8688d96dd05157c28db3ade5c9bc234kz ldom_fini(pi_lhp);
60405de4d8688d96dd05157c28db3ade5c9bc234kz}
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kzstatic int
60405de4d8688d96dd05157c28db3ade5c9bc234kzset_retnvl(topo_mod_t *mod, nvlist_t **out, const char *retname, uint32_t ret)
60405de4d8688d96dd05157c28db3ade5c9bc234kz{
60405de4d8688d96dd05157c28db3ade5c9bc234kz nvlist_t *nvl;
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz topo_mod_dprintf(mod, "topo method set \"%s\" = %u\n", retname, ret);
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) < 0)
60405de4d8688d96dd05157c28db3ade5c9bc234kz return (topo_mod_seterrno(mod, EMOD_NOMEM));
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz if (nvlist_add_uint32(nvl, retname, ret) != 0) {
60405de4d8688d96dd05157c28db3ade5c9bc234kz nvlist_free(nvl);
60405de4d8688d96dd05157c28db3ade5c9bc234kz return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
60405de4d8688d96dd05157c28db3ade5c9bc234kz }
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz *out = nvl;
60405de4d8688d96dd05157c28db3ade5c9bc234kz return (0);
60405de4d8688d96dd05157c28db3ade5c9bc234kz}
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz/*
60405de4d8688d96dd05157c28db3ade5c9bc234kz * For each visited cpu node, call the callback function with its ASRU.
e92e3a8694f157faf8a9e44096a70ada86c556bfzw */
e92e3a8694f157faf8a9e44096a70ada86c556bfzwstatic int
60405de4d8688d96dd05157c28db3ade5c9bc234kzcpu_walker(topo_mod_t *mod, tnode_t *node, void *pdata)
60405de4d8688d96dd05157c28db3ade5c9bc234kz{
60405de4d8688d96dd05157c28db3ade5c9bc234kz struct cpu_walk_data *swdp = pdata;
60405de4d8688d96dd05157c28db3ade5c9bc234kz nvlist_t *asru;
60405de4d8688d96dd05157c28db3ade5c9bc234kz int err, rc;
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz /*
60405de4d8688d96dd05157c28db3ade5c9bc234kz * Terminate the walk if we reach start-node's sibling
60405de4d8688d96dd05157c28db3ade5c9bc234kz */
60405de4d8688d96dd05157c28db3ade5c9bc234kz if (node != swdp->parent &&
60405de4d8688d96dd05157c28db3ade5c9bc234kz topo_node_parent(node) == topo_node_parent(swdp->parent))
60405de4d8688d96dd05157c28db3ade5c9bc234kz return (TOPO_WALK_TERMINATE);
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz if (strcmp(topo_node_name(node), CPU) != 0 &&
60405de4d8688d96dd05157c28db3ade5c9bc234kz strcmp(topo_node_name(node), STRAND) != 0)
60405de4d8688d96dd05157c28db3ade5c9bc234kz return (TOPO_WALK_NEXT);
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz if (topo_node_asru(node, &asru, NULL, &err) != 0) {
60405de4d8688d96dd05157c28db3ade5c9bc234kz swdp->fail++;
60405de4d8688d96dd05157c28db3ade5c9bc234kz return (TOPO_WALK_NEXT);
60405de4d8688d96dd05157c28db3ade5c9bc234kz }
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz rc = swdp->func(swdp->lhp, asru);
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz /*
60405de4d8688d96dd05157c28db3ade5c9bc234kz * The "offline" and "online" counter are only useful for the "status"
60405de4d8688d96dd05157c28db3ade5c9bc234kz * callback.
60405de4d8688d96dd05157c28db3ade5c9bc234kz */
60405de4d8688d96dd05157c28db3ade5c9bc234kz if (rc == P_OFFLINE || rc == P_FAULTED) {
60405de4d8688d96dd05157c28db3ade5c9bc234kz swdp->offline++;
e92e3a8694f157faf8a9e44096a70ada86c556bfzw err = 0;
e92e3a8694f157faf8a9e44096a70ada86c556bfzw } else if (rc == P_ONLINE) {
e92e3a8694f157faf8a9e44096a70ada86c556bfzw swdp->online++;
60405de4d8688d96dd05157c28db3ade5c9bc234kz err = 0;
60405de4d8688d96dd05157c28db3ade5c9bc234kz } else {
60405de4d8688d96dd05157c28db3ade5c9bc234kz swdp->fail++;
60405de4d8688d96dd05157c28db3ade5c9bc234kz err = errno;
60405de4d8688d96dd05157c28db3ade5c9bc234kz }
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz /* dump out status info if debug is turned on. */
e92e3a8694f157faf8a9e44096a70ada86c556bfzw if (getenv("TOPOCHIPDBG") != NULL ||
e92e3a8694f157faf8a9e44096a70ada86c556bfzw getenv("TOPOSUN4VPIDBG") != NULL) {
e92e3a8694f157faf8a9e44096a70ada86c556bfzw const char *op;
60405de4d8688d96dd05157c28db3ade5c9bc234kz char *fmristr = NULL;
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz if (swdp->func == ldom_fmri_retire)
60405de4d8688d96dd05157c28db3ade5c9bc234kz op = "retire";
60405de4d8688d96dd05157c28db3ade5c9bc234kz else if (swdp->func == ldom_fmri_unretire)
60405de4d8688d96dd05157c28db3ade5c9bc234kz op = "unretire";
60405de4d8688d96dd05157c28db3ade5c9bc234kz else if (swdp->func == ldom_fmri_status)
60405de4d8688d96dd05157c28db3ade5c9bc234kz op = "check status";
60405de4d8688d96dd05157c28db3ade5c9bc234kz else
60405de4d8688d96dd05157c28db3ade5c9bc234kz op = "unknown op";
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz (void) topo_mod_nvl2str(mod, asru, &fmristr);
60405de4d8688d96dd05157c28db3ade5c9bc234kz topo_mod_dprintf(mod, "%s cpu (%s): rc = %d, err = %s\n",
60405de4d8688d96dd05157c28db3ade5c9bc234kz op, fmristr == NULL ? "unknown fmri" : fmristr,
60405de4d8688d96dd05157c28db3ade5c9bc234kz rc, strerror(err));
60405de4d8688d96dd05157c28db3ade5c9bc234kz if (fmristr != NULL)
60405de4d8688d96dd05157c28db3ade5c9bc234kz topo_mod_strfree(mod, fmristr);
60405de4d8688d96dd05157c28db3ade5c9bc234kz }
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz nvlist_free(asru);
60405de4d8688d96dd05157c28db3ade5c9bc234kz return (TOPO_WALK_NEXT);
60405de4d8688d96dd05157c28db3ade5c9bc234kz}
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kzstatic int
60405de4d8688d96dd05157c28db3ade5c9bc234kzwalk_cpus(topo_mod_t *mod, struct cpu_walk_data *swdp, tnode_t *parent,
60405de4d8688d96dd05157c28db3ade5c9bc234kz int (*func)(ldom_hdl_t *, nvlist_t *))
60405de4d8688d96dd05157c28db3ade5c9bc234kz{
60405de4d8688d96dd05157c28db3ade5c9bc234kz topo_walk_t *twp;
60405de4d8688d96dd05157c28db3ade5c9bc234kz int err;
60405de4d8688d96dd05157c28db3ade5c9bc234kz
60405de4d8688d96dd05157c28db3ade5c9bc234kz swdp->lhp = pi_lhp;
60405de4d8688d96dd05157c28db3ade5c9bc234kz swdp->parent = parent;
60405de4d8688d96dd05157c28db3ade5c9bc234kz swdp->func = func;
60405de4d8688d96dd05157c28db3ade5c9bc234kz swdp->err = swdp->offline = swdp->online = swdp->fail = 0;
60405de4d8688d96dd05157c28db3ade5c9bc234kz
e92e3a8694f157faf8a9e44096a70ada86c556bfzw /*
e92e3a8694f157faf8a9e44096a70ada86c556bfzw * Return failure if ldom service is not initialized.
e92e3a8694f157faf8a9e44096a70ada86c556bfzw */
e92e3a8694f157faf8a9e44096a70ada86c556bfzw if (pi_lhp == NULL) {
e92e3a8694f157faf8a9e44096a70ada86c556bfzw swdp->fail++;
e92e3a8694f157faf8a9e44096a70ada86c556bfzw return (0);
e92e3a8694f157faf8a9e44096a70ada86c556bfzw }
e92e3a8694f157faf8a9e44096a70ada86c556bfzw
e92e3a8694f157faf8a9e44096a70ada86c556bfzw twp = topo_mod_walk_init(mod, parent, cpu_walker, swdp, &err);
e92e3a8694f157faf8a9e44096a70ada86c556bfzw if (twp == NULL)
e92e3a8694f157faf8a9e44096a70ada86c556bfzw return (-1);
e92e3a8694f157faf8a9e44096a70ada86c556bfzw
e92e3a8694f157faf8a9e44096a70ada86c556bfzw err = topo_walk_step(twp, TOPO_WALK_CHILD);
e92e3a8694f157faf8a9e44096a70ada86c556bfzw topo_walk_fini(twp);
e92e3a8694f157faf8a9e44096a70ada86c556bfzw
e92e3a8694f157faf8a9e44096a70ada86c556bfzw if (err == TOPO_WALK_ERR || swdp->err > 0)
e92e3a8694f157faf8a9e44096a70ada86c556bfzw return (-1);
e92e3a8694f157faf8a9e44096a70ada86c556bfzw
e92e3a8694f157faf8a9e44096a70ada86c556bfzw return (0);
e92e3a8694f157faf8a9e44096a70ada86c556bfzw}
e92e3a8694f157faf8a9e44096a70ada86c556bfzw
/* ARGSUSED */
int
cpu_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
nvlist_t *in, nvlist_t **out)
{
struct cpu_walk_data swd;
uint32_t rc;
if (version > TOPO_METH_RETIRE_VERSION)
return (topo_mod_seterrno(mod, EMOD_VER_NEW));
if (walk_cpus(mod, &swd, node, ldom_fmri_retire) == -1)
return (-1);
rc = swd.fail > 0 ? FMD_AGENT_RETIRE_FAIL : FMD_AGENT_RETIRE_DONE;
return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc));
}
/* ARGSUSED */
int
cpu_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
nvlist_t *in, nvlist_t **out)
{
struct cpu_walk_data swd;
uint32_t rc;
if (version > TOPO_METH_UNRETIRE_VERSION)
return (topo_mod_seterrno(mod, EMOD_VER_NEW));
if (walk_cpus(mod, &swd, node, ldom_fmri_unretire) == -1)
return (-1);
rc = swd.fail > 0 ? FMD_AGENT_RETIRE_FAIL : FMD_AGENT_RETIRE_DONE;
return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc));
}
/* ARGSUSED */
int
cpu_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version,
nvlist_t *in, nvlist_t **out)
{
struct cpu_walk_data swd;
uint32_t rc;
if (version > TOPO_METH_SERVICE_STATE_VERSION)
return (topo_mod_seterrno(mod, EMOD_VER_NEW));
if (walk_cpus(mod, &swd, node, ldom_fmri_status) == -1)
return (-1);
if (swd.fail > 0)
rc = FMD_SERVICE_STATE_UNKNOWN;
else if (swd.offline > 0)
rc = swd.online > 0 ? FMD_SERVICE_STATE_DEGRADED :
FMD_SERVICE_STATE_UNUSABLE;
else
rc = FMD_SERVICE_STATE_OK;
return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc));
}
/* ARGSUSED */
int
cpu_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version,
nvlist_t *in, nvlist_t **out)
{
struct cpu_walk_data swd;
uint32_t rc;
if (version > TOPO_METH_UNUSABLE_VERSION)
return (topo_mod_seterrno(mod, EMOD_VER_NEW));
if (walk_cpus(mod, &swd, node, ldom_fmri_status) == -1)
return (-1);
rc = (swd.offline > 0 && swd.fail + swd.online == 0) ? 1 : 0;
return (set_retnvl(mod, out, TOPO_METH_UNUSABLE_RET, rc));
}
static nvlist_t *
mem_fmri_create(topo_mod_t *mod, char *serial, char *label)
{
int err;
nvlist_t *fmri;
if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0)
return (NULL);
err = nvlist_add_uint8(fmri, FM_VERSION, FM_MEM_SCHEME_VERSION);
err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM);
if (serial != NULL)
err |= nvlist_add_string_array(fmri, FM_FMRI_MEM_SERIAL_ID,
&serial, 1);
if (label != NULL)
err |= nvlist_add_string(fmri, FM_FMRI_MEM_UNUM, label);
if (err != 0) {
nvlist_free(fmri);
(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
return (NULL);
}
return (fmri);
}
/* Topo Methods */
static int
mem_asru_compute(topo_mod_t *mod, tnode_t *node, topo_version_t version,
nvlist_t *in, nvlist_t **out)
{
nvlist_t *asru, *pargs, *args, *hcsp;
int err;
char *serial = NULL, *label = NULL;
uint64_t pa, offset;
if (version > TOPO_METH_ASRU_COMPUTE_VERSION)
return (topo_mod_seterrno(mod, EMOD_VER_NEW));
if (strcmp(topo_node_name(node), DIMM) != 0)
return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
pargs = NULL;
if (nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0)
(void) nvlist_lookup_string(pargs, FM_FMRI_HC_SERIAL_ID,
&serial);
if (serial == NULL &&
nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) == 0)
(void) nvlist_lookup_string(args, FM_FMRI_HC_SERIAL_ID,
&serial);
(void) topo_node_label(node, &label, &err);
asru = mem_fmri_create(mod, serial, label);
if (label != NULL)
topo_mod_strfree(mod, label);
if (asru == NULL)
return (topo_mod_seterrno(mod, EMOD_NOMEM));
err = 0;
/*
* For a memory page, 'in' includes an hc-specific member which
* specifies physaddr and/or offset. Set them in asru as well.
*/
if (pargs && nvlist_lookup_nvlist(pargs,
FM_FMRI_HC_SPECIFIC, &hcsp) == 0) {
if (nvlist_lookup_uint64(hcsp,
FM_FMRI_HC_SPECIFIC_PHYSADDR, &pa) == 0)
err += nvlist_add_uint64(asru, FM_FMRI_MEM_PHYSADDR,
pa);
if (nvlist_lookup_uint64(hcsp,
FM_FMRI_HC_SPECIFIC_OFFSET, &offset) == 0)
err += nvlist_add_uint64(asru, FM_FMRI_MEM_OFFSET,
offset);
}
if (err != 0 || topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) {
nvlist_free(asru);
return (topo_mod_seterrno(mod, EMOD_NOMEM));
}
err = nvlist_add_string(*out, TOPO_PROP_VAL_NAME, TOPO_PROP_ASRU);
err |= nvlist_add_uint32(*out, TOPO_PROP_VAL_TYPE, TOPO_TYPE_FMRI);
err |= nvlist_add_nvlist(*out, TOPO_PROP_VAL_VAL, asru);
nvlist_free(asru);
if (err != 0) {
nvlist_free(*out);
*out = NULL;
return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
}
return (0);
}
static boolean_t
is_page_fmri(nvlist_t *nvl)
{
nvlist_t *hcsp;
uint64_t val;
if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) == 0 &&
(nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET,
&val) == 0 ||
nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_OFFSET,
&val) == 0 ||
nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_PHYSADDR,
&val) == 0 ||
nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR,
&val) == 0))
return (B_TRUE);
return (B_FALSE);
}
static int
dimm_page_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version,
nvlist_t *in, nvlist_t **out)
{
uint32_t rc = FMD_SERVICE_STATE_OK;
nvlist_t *asru;
int err;
if (version > TOPO_METH_SERVICE_STATE_VERSION)
return (topo_mod_seterrno(mod, EMOD_VER_NEW));
if (pi_lhp != NULL && is_page_fmri(in) &&
topo_node_asru(node, &asru, in, &err) == 0) {
err = ldom_fmri_status(pi_lhp, asru);
if (err == 0 || err == EINVAL)
rc = FMD_SERVICE_STATE_UNUSABLE;
else if (err == EAGAIN)
rc = FMD_SERVICE_STATE_ISOLATE_PENDING;
nvlist_free(asru);
}
return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc));
}
static int
dimm_page_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version,
nvlist_t *in, nvlist_t **out)
{
uint32_t rc = 0;
nvlist_t *asru;
int err;
if (version > TOPO_METH_UNUSABLE_VERSION)
return (topo_mod_seterrno(mod, EMOD_VER_NEW));
if (pi_lhp != NULL && is_page_fmri(in) &&
topo_node_asru(node, &asru, in, &err) == 0) {
err = ldom_fmri_status(pi_lhp, asru);
if (err == 0 || err == EINVAL)
rc = 1;
nvlist_free(asru);
}
return (set_retnvl(mod, out, TOPO_METH_UNUSABLE_RET, rc));
}
static int
dimm_page_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
nvlist_t *in, nvlist_t **out)
{
uint32_t rc = FMD_AGENT_RETIRE_FAIL;
nvlist_t *asru;
int err;
if (version > TOPO_METH_RETIRE_VERSION)
return (topo_mod_seterrno(mod, EMOD_VER_NEW));
if (pi_lhp != NULL && is_page_fmri(in) &&
topo_node_asru(node, &asru, in, &err) == 0) {
err = ldom_fmri_retire(pi_lhp, asru);
if (err == 0 || err == EIO || err == EINVAL)
rc = FMD_AGENT_RETIRE_DONE;
else if (err == EAGAIN)
rc = FMD_AGENT_RETIRE_ASYNC;
nvlist_free(asru);
}
return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc));
}
static int
dimm_page_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
nvlist_t *in, nvlist_t **out)
{
uint32_t rc = FMD_AGENT_RETIRE_FAIL;
nvlist_t *asru;
int err;
if (version > TOPO_METH_UNRETIRE_VERSION)
return (topo_mod_seterrno(mod, EMOD_VER_NEW));
if (pi_lhp != NULL && is_page_fmri(in) &&
topo_node_asru(node, &asru, in, &err) == 0) {
err = ldom_fmri_unretire(pi_lhp, asru);
if (err == 0 || err == EIO)
rc = FMD_AGENT_RETIRE_DONE;
nvlist_free(asru);
}
return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc));
}