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, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A
2N/A#include <errno.h>
2N/A#include <limits.h>
2N/A#include <strings.h>
2N/A#include <unistd.h>
2N/A#include <topo_error.h>
2N/A#include <fm/topo_mod.h>
2N/A#include <sys/fm/protocol.h>
2N/A
2N/A#include <topo_method.h>
2N/A#include <topo_fmri.h>
2N/A#include <sys/processor.h>
2N/A#include <fm/fmd_fmri.h>
2N/A#include <cpu.h>
2N/A
2N/A/*
2N/A * platform specific cpu module
2N/A */
2N/A#define PLATFORM_CPU_VERSION CPU_VERSION
2N/A#define PLATFORM_CPU_NAME "platform-cpu"
2N/A
2N/Astatic int cpu_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
2N/A topo_instance_t, void *, void *);
2N/Astatic void cpu_release(topo_mod_t *, tnode_t *);
2N/Astatic int cpu_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
2N/A nvlist_t **);
2N/Astatic int cpu_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
2N/A nvlist_t **);
2N/Astatic int cpu_fmri_asru(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
2N/A nvlist_t **);
2N/Astatic int cpu_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int cpu_fmri_strcmp_path(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int cpu_fmri_strcmp_ident(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int cpu_fmri_strhash_path(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic int cpu_fmri_service_state(topo_mod_t *, tnode_t *, topo_version_t,
2N/A nvlist_t *, nvlist_t **);
2N/Astatic nvlist_t *fmri_create(topo_mod_t *, uint32_t, uint8_t, char *);
2N/A
2N/Astatic const topo_method_t cpu_methods[] = {
2N/A { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION,
2N/A TOPO_STABILITY_INTERNAL, cpu_nvl2str },
2N/A { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION,
2N/A TOPO_STABILITY_INTERNAL, cpu_str2nvl },
2N/A { TOPO_METH_ASRU_COMPUTE, TOPO_METH_ASRU_COMPUTE_DESC,
2N/A TOPO_METH_ASRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL,
2N/A cpu_fmri_asru },
2N/A { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION,
2N/A TOPO_STABILITY_INTERNAL, cpu_fmri_create_meth },
2N/A { TOPO_METH_STRCMP_PATH, TOPO_METH_STRCMP_PATH_DESC,
2N/A TOPO_METH_STRCMP_VERSION, TOPO_STABILITY_INTERNAL,
2N/A cpu_fmri_strcmp_path },
2N/A { TOPO_METH_STRCMP_IDENT, TOPO_METH_STRCMP_IDENT_DESC,
2N/A TOPO_METH_STRCMP_VERSION, TOPO_STABILITY_INTERNAL,
2N/A cpu_fmri_strcmp_ident },
2N/A { TOPO_METH_STRHASH_PATH, TOPO_METH_STRHASH_PATH_DESC,
2N/A TOPO_METH_STRHASH_VERSION, TOPO_STABILITY_INTERNAL,
2N/A cpu_fmri_strhash_path },
2N/A { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC,
2N/A TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL,
2N/A cpu_fmri_service_state },
2N/A { NULL }
2N/A};
2N/A
2N/Astatic const topo_modops_t cpu_ops =
2N/A { cpu_enum, cpu_release };
2N/A
2N/Astatic const topo_modinfo_t cpu_info =
2N/A { "cpu", FM_FMRI_SCHEME_CPU, CPU_VERSION, &cpu_ops };
2N/A
2N/Aint
2N/Acpu_init(topo_mod_t *mod, topo_version_t version)
2N/A{
2N/A cpu_node_t *cpuip;
2N/A
2N/A if (getenv("TOPOCPUDEBUG"))
2N/A topo_mod_setdebug(mod);
2N/A topo_mod_dprintf(mod, "initializing cpu builtin\n");
2N/A
2N/A if (version != CPU_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A
2N/A if ((cpuip = topo_mod_zalloc(mod, sizeof (cpu_node_t))) == NULL)
2N/A return (topo_mod_seterrno(mod, EMOD_NOMEM));
2N/A
2N/A if ((cpuip->cn_kc = kstat_open()) == NULL) {
2N/A topo_mod_dprintf(mod, "kstat_open failed: %s\n",
2N/A strerror(errno));
2N/A topo_mod_free(mod, cpuip, sizeof (cpu_node_t));
2N/A return (-1);
2N/A }
2N/A
2N/A cpuip->cn_ncpustats = sysconf(_SC_CPUID_MAX);
2N/A if ((cpuip->cn_cpustats = topo_mod_zalloc(mod, (
2N/A cpuip->cn_ncpustats + 1) * sizeof (kstat_t *))) == NULL) {
2N/A (void) kstat_close(cpuip->cn_kc);
2N/A topo_mod_free(mod, cpuip, sizeof (cpu_node_t));
2N/A return (-1);
2N/A }
2N/A
2N/A if (topo_mod_register(mod, &cpu_info, TOPO_VERSION) != 0) {
2N/A topo_mod_dprintf(mod, "failed to register cpu_info: "
2N/A "%s\n", topo_mod_errmsg(mod));
2N/A topo_mod_free(mod, cpuip->cn_cpustats,
2N/A (cpuip->cn_ncpustats + 1) * sizeof (kstat_t *));
2N/A (void) kstat_close(cpuip->cn_kc);
2N/A topo_mod_free(mod, cpuip, sizeof (cpu_node_t));
2N/A return (-1);
2N/A }
2N/A
2N/A topo_mod_setspecific(mod, (void *)cpuip);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Avoid
2N/Acpu_fini(topo_mod_t *mod)
2N/A{
2N/A cpu_node_t *cpuip;
2N/A
2N/A cpuip = topo_mod_getspecific(mod);
2N/A
2N/A if (cpuip->cn_cpustats != NULL)
2N/A topo_mod_free(mod, cpuip->cn_cpustats,
2N/A (cpuip->cn_ncpustats + 1) * sizeof (kstat_t *));
2N/A
2N/A (void) kstat_close(cpuip->cn_kc);
2N/A topo_mod_free(mod, cpuip, sizeof (cpu_node_t));
2N/A
2N/A topo_mod_unregister(mod);
2N/A}
2N/A
2N/Astatic int
2N/Acpu_kstat_init(cpu_node_t *cpuip, int i)
2N/A{
2N/A kstat_t *ksp;
2N/A
2N/A if (cpuip->cn_cpustats[i] == NULL) {
2N/A if ((ksp = kstat_lookup(cpuip->cn_kc, "cpu_info", i, NULL)) ==
2N/A NULL || kstat_read(cpuip->cn_kc, ksp, NULL) < 0)
2N/A return (-1);
2N/A
2N/A cpuip->cn_cpustats[i] = ksp;
2N/A } else {
2N/A ksp = cpuip->cn_cpustats[i];
2N/A }
2N/A
2N/A return (ksp->ks_instance);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Acpu_create(topo_mod_t *mod, tnode_t *rnode, const char *name,
2N/A topo_instance_t min, topo_instance_t max, cpu_node_t *cpuip)
2N/A{
2N/A int i;
2N/A processorid_t cpu_id;
2N/A char *s, sbuf[21];
2N/A kstat_named_t *ks;
2N/A nvlist_t *fmri;
2N/A
2N/A for (i = 0; i <= cpuip->cn_ncpustats; i++) {
2N/A
2N/A if ((cpu_id = cpu_kstat_init(cpuip, i)) < 0)
2N/A continue;
2N/A
2N/A if ((ks = kstat_data_lookup(cpuip->cn_cpustats[i],
2N/A "device_ID")) != NULL) {
2N/A (void) snprintf(sbuf, 21, "%llX", ks->value.ui64);
2N/A s = sbuf;
2N/A } else {
2N/A s = NULL;
2N/A }
2N/A
2N/A if ((fmri = fmri_create(mod, cpu_id, 0, s)) == NULL)
2N/A continue;
2N/A (void) topo_node_bind(mod, rnode, name, cpu_id, fmri);
2N/A nvlist_free(fmri);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Acpu_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
2N/A topo_instance_t min, topo_instance_t max, void *arg, void *notused2)
2N/A{
2N/A topo_mod_t *nmp;
2N/A cpu_node_t *cpuip = (cpu_node_t *)arg;
2N/A
2N/A if ((nmp = topo_mod_load(mod, PLATFORM_CPU_NAME,
2N/A PLATFORM_CPU_VERSION)) == NULL) {
2N/A if (topo_mod_errno(mod) == ETOPO_MOD_NOENT) {
2N/A /*
2N/A * There is no platform specific cpu module, so use
2N/A * the default enumeration with kstats of this builtin
2N/A * cpu module.
2N/A */
2N/A if (topo_node_range_create(mod, pnode, name, 0,
2N/A cpuip->cn_ncpustats + 1) < 0) {
2N/A topo_mod_dprintf(mod,
2N/A "cpu enumeration failed to create "
2N/A "cpu range [0-%d]: %s\n",
2N/A cpuip->cn_ncpustats + 1,
2N/A topo_mod_errmsg(mod));
2N/A return (-1); /* mod_errno set */
2N/A }
2N/A (void) topo_method_register(mod, pnode, cpu_methods);
2N/A return (cpu_create(mod, pnode, name, min, max, cpuip));
2N/A
2N/A } else {
2N/A /* Fail to load the module */
2N/A topo_mod_dprintf(mod,
2N/A "Failed to load module %s: %s",
2N/A PLATFORM_CPU_NAME,
2N/A topo_mod_errmsg(mod));
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A if (topo_mod_enumerate(nmp, pnode, PLATFORM_CPU_NAME, name,
2N/A min, max, NULL) < 0) {
2N/A topo_mod_dprintf(mod,
2N/A "%s failed to enumerate: %s",
2N/A PLATFORM_CPU_NAME,
2N/A topo_mod_errmsg(mod));
2N/A return (-1);
2N/A }
2N/A (void) topo_method_register(mod, pnode, cpu_methods);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic void
2N/Acpu_release(topo_mod_t *mod, tnode_t *node)
2N/A{
2N/A topo_method_unregister_all(mod, node);
2N/A}
2N/A
2N/Assize_t
2N/Afmri_nvl2str(nvlist_t *nvl, uint8_t version, char *buf, size_t buflen)
2N/A{
2N/A int rc;
2N/A uint8_t type;
2N/A uint32_t cpuid, way;
2N/A uint32_t index;
2N/A uint16_t bit;
2N/A uint64_t serint;
2N/A char *serstr = NULL;
2N/A
2N/A if (version == CPU_SCHEME_VERSION0) {
2N/A if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0 ||
2N/A nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, &serint)
2N/A != 0)
2N/A return (0);
2N/A
2N/A return (snprintf(buf, buflen, "cpu:///%s=%u/%s=%llX",
2N/A FM_FMRI_CPU_ID, cpuid, FM_FMRI_CPU_SERIAL_ID,
2N/A (u_longlong_t)serint));
2N/A
2N/A } else if (version == CPU_SCHEME_VERSION1) {
2N/A if (nvlist_lookup_uint32(nvl, FM_FMRI_CPU_ID, &cpuid) != 0)
2N/A return (0);
2N/A
2N/A /*
2N/A * Serial number is an optional element
2N/A */
2N/A if ((rc = nvlist_lookup_string(nvl, FM_FMRI_CPU_SERIAL_ID,
2N/A &serstr)) != 0)
2N/A
2N/A if (rc != ENOENT)
2N/A return (0);
2N/A
2N/A /*
2N/A * Cache index, way and type are optional elements
2N/A * But if we have one of them, we must have them all.
2N/A */
2N/A rc = nvlist_lookup_uint32(nvl, FM_FMRI_CPU_CACHE_INDEX,
2N/A &index);
2N/A rc |= nvlist_lookup_uint32(nvl, FM_FMRI_CPU_CACHE_WAY, &way);
2N/A rc |= nvlist_lookup_uint16(nvl, FM_FMRI_CPU_CACHE_BIT, &bit);
2N/A rc |= nvlist_lookup_uint8(nvl, FM_FMRI_CPU_CACHE_TYPE, &type);
2N/A
2N/A /* Insure there were no errors accessing the nvl */
2N/A if (rc != 0 && rc != ENOENT)
2N/A return (0);
2N/A
2N/A if (serstr == NULL) {
2N/A /* If we have a serial string and no cache info */
2N/A if (rc == ENOENT)
2N/A return (snprintf(buf, buflen, "cpu:///%s=%u",
2N/A FM_FMRI_CPU_ID, cpuid));
2N/A else {
2N/A return (snprintf(buf, buflen,
2N/A "cpu:///%s=%u/%s=%u/%s=%u/%s=%d/%s=%d",
2N/A FM_FMRI_CPU_ID, cpuid,
2N/A FM_FMRI_CPU_CACHE_INDEX, index,
2N/A FM_FMRI_CPU_CACHE_WAY, way,
2N/A FM_FMRI_CPU_CACHE_BIT, bit,
2N/A FM_FMRI_CPU_CACHE_TYPE, type));
2N/A }
2N/A } else {
2N/A if (rc == ENOENT) {
2N/A return (snprintf(buf, buflen,
2N/A "cpu:///%s=%u/%s=%s",
2N/A FM_FMRI_CPU_ID, cpuid,
2N/A FM_FMRI_CPU_SERIAL_ID, serstr));
2N/A } else {
2N/A return (snprintf(buf, buflen,
2N/A "cpu:///%s=%u/%s=%s/%s=%u/%s=%u/%s=%d/%s=%d",
2N/A FM_FMRI_CPU_ID, cpuid,
2N/A FM_FMRI_CPU_SERIAL_ID, serstr,
2N/A FM_FMRI_CPU_CACHE_INDEX, index,
2N/A FM_FMRI_CPU_CACHE_WAY, way,
2N/A FM_FMRI_CPU_CACHE_BIT, bit,
2N/A FM_FMRI_CPU_CACHE_TYPE, type));
2N/A }
2N/A }
2N/A } else
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Acpu_nvl2str(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 fver;
2N/A ssize_t len;
2N/A char *name;
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 (nvlist_lookup_uint8(in, FM_VERSION, &fver) != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_VERSION));
2N/A
2N/A if ((len = fmri_nvl2str(in, fver, NULL, 0)) == 0 ||
2N/A (name = topo_mod_alloc(mod, len + 1)) == NULL ||
2N/A fmri_nvl2str(in, fver, name, len + 1) == 0)
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
2N/A
2N/A if (topo_mod_nvalloc(mod, out, 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
2N/A if (nvlist_add_string(*out, "fmri-string", 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 topo_mod_free(mod, name, len + 1);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Acpu_str2nvl(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 ulong_t cpuid;
2N/A uint8_t type = 0;
2N/A uint32_t way = 0;
2N/A uint32_t index = 0;
2N/A int index_present = 0;
2N/A uint16_t bit = 0;
2N/A char *str, *s, *end, *serial_end;
2N/A char *serial = NULL;
2N/A nvlist_t *fmri;
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_FMRI_NVL));
2N/A
2N/A /* We're expecting a string version of a cpu scheme FMRI */
2N/A if (strncmp(str, "cpu:///", 7) != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
2N/A
2N/A s = strchr(str + 7, '=');
2N/A if (s == NULL)
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
2N/A
2N/A ++s;
2N/A cpuid = strtoul(s, &end, 0);
2N/A
2N/A if (cpuid == ULONG_MAX && errno == ERANGE)
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
2N/A
2N/A /* If there is a serial #, then there might also be cache data */
2N/A if (*(s = end) == '/') {
2N/A s = strchr(s, '=');
2N/A ++s;
2N/A serial = s;
2N/A serial_end = strchr(s, '/');
2N/A /* If there is cache data, all must be present */
2N/A if (serial_end != NULL) {
2N/A /* Now terminate the serial string */
2N/A *serial_end = '\0';
2N/A index_present = 1;
2N/A s = serial_end + 1;
2N/A s = strchr(s, '=');
2N/A ++s;
2N/A index = strtoul(s, &end, 0);
2N/A if (*(s = end) != '/') {
2N/A return (topo_mod_seterrno(mod,
2N/A EMOD_FMRI_MALFORM));
2N/A }
2N/A s = strchr(s, '=');
2N/A if (s == NULL) {
2N/A return (topo_mod_seterrno(mod,
2N/A EMOD_FMRI_MALFORM));
2N/A }
2N/A ++s;
2N/A way = strtoul(s, &end, 0);
2N/A if (*(s = end) != '/') {
2N/A return (topo_mod_seterrno(mod,
2N/A EMOD_FMRI_MALFORM));
2N/A }
2N/A s = strchr(s, '=');
2N/A if (s == NULL) {
2N/A return (topo_mod_seterrno(mod,
2N/A EMOD_FMRI_MALFORM));
2N/A }
2N/A ++s;
2N/A bit = strtoul(s, &end, 0);
2N/A if (*(s = end) != '/') {
2N/A return (topo_mod_seterrno(mod,
2N/A EMOD_FMRI_MALFORM));
2N/A }
2N/A s = strchr(s, '=');
2N/A if (s == NULL) {
2N/A return (topo_mod_seterrno(mod,
2N/A EMOD_FMRI_MALFORM));
2N/A }
2N/A ++s;
2N/A type = strtoul(s, &end, 0);
2N/A }
2N/A
2N/A }
2N/A if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
2N/A
2N/A err = nvlist_add_uint8(fmri, FM_VERSION, CPU_SCHEME_VERSION1);
2N/A err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU);
2N/A err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, (uint32_t)cpuid);
2N/A err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, 0);
2N/A if (serial != NULL)
2N/A err |= nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID,
2N/A serial);
2N/A
2N/A if (index_present) {
2N/A err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_CACHE_INDEX,
2N/A index);
2N/A err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_CACHE_WAY,
2N/A way);
2N/A err |= nvlist_add_uint16(fmri, FM_FMRI_CPU_CACHE_BIT,
2N/A bit);
2N/A err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_CACHE_TYPE,
2N/A type);
2N/A }
2N/A if (err != 0) {
2N/A nvlist_free(fmri);
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
2N/A }
2N/A *out = fmri;
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic nvlist_t *
2N/Afmri_create(topo_mod_t *mod, uint32_t cpu_id, uint8_t cpumask, char *s)
2N/A{
2N/A int err;
2N/A nvlist_t *fmri;
2N/A
2N/A if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) {
2N/A (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
2N/A return (NULL);
2N/A }
2N/A
2N/A err = nvlist_add_uint8(fmri, FM_VERSION, FM_CPU_SCHEME_VERSION);
2N/A err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU);
2N/A err |= nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, cpu_id);
2N/A err |= nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, cpumask);
2N/A if (s != NULL)
2N/A err |= nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID, s);
2N/A if (err != 0) {
2N/A nvlist_free(fmri);
2N/A (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
2N/A return (NULL);
2N/A }
2N/A
2N/A return (fmri);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Acpu_fmri_asru(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2N/A nvlist_t *in, nvlist_t **out)
2N/A{
2N/A int rc;
2N/A uint32_t cpu_id;
2N/A uint8_t cpumask = 0;
2N/A char *serial = NULL;
2N/A
2N/A if ((rc = nvlist_lookup_uint32(in, FM_FMRI_CPU_ID, &cpu_id)) != 0) {
2N/A if (rc == ENOENT)
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A else
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
2N/A }
2N/A
2N/A (void) nvlist_lookup_string(in, FM_FMRI_CPU_SERIAL_ID, &serial);
2N/A (void) nvlist_lookup_uint8(in, FM_FMRI_CPU_MASK, &cpumask);
2N/A
2N/A *out = fmri_create(mod, cpu_id, cpumask, serial);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Acpu_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 rc;
2N/A nvlist_t *args;
2N/A uint32_t cpu_id;
2N/A uint8_t cpumask = 0;
2N/A char *serial = NULL;
2N/A
2N/A if (version > TOPO_METH_FMRI_VERSION) {
2N/A return (topo_mod_seterrno(mod, EMOD_VER_NEW));
2N/A }
2N/A
2N/A rc = nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args);
2N/A if (rc != 0) {
2N/A /*
2N/A * This routine requires arguments to be packed in the
2N/A * format used in topo_fmri_create()
2N/A */
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A }
2N/A
2N/A if (nvlist_lookup_string(args, FM_FMRI_CPU_SERIAL_ID, &serial) != 0 ||
2N/A nvlist_lookup_uint32(args, FM_FMRI_CPU_ID, &cpu_id) != 0 ||
2N/A nvlist_lookup_uint8(args, FM_FMRI_CPU_MASK, &cpumask) != 0) {
2N/A return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2N/A }
2N/A
2N/A *out = fmri_create(mod, cpu_id, cpumask, serial);
2N/A if (*out == NULL) {
2N/A return (-1);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Acpu_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 int state;
2N/A uint32_t cpuid;
2N/A uint8_t fmversion;
2N/A
2N/A if (nvlist_lookup_uint8(in, FM_VERSION, &fmversion) != 0 ||
2N/A fmversion > FM_CPU_SCHEME_VERSION)
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
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 (nvlist_lookup_uint32(in, FM_FMRI_CPU_ID, &cpuid) != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
2N/A
2N/A state = p_online(cpuid, P_STATUS) == P_FAULTED ?
2N/A FMD_SERVICE_STATE_UNUSABLE : FMD_SERVICE_STATE_OK;
2N/A
2N/A if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0)
2N/A return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
2N/A if (nvlist_add_uint32(*out, TOPO_METH_SERVICE_STATE_RET,
2N/A state) != 0) {
2N/A nvlist_free(*out);
2N/A return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Acpu_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 *fmri = (char *)in, *f;
2N/A uint64_t h = 0;
2N/A uint64_t *rval = (uint64_t *)(void *)out;
2N/A int len;
2N/A
2N/A if ((f = strchr(fmri + 7, '/')) != NULL)
2N/A len = f++ - fmri;
2N/A h += topo_fmri_strhash_one(fmri, len);
2N/A
2N/A if (f != NULL && strncmp(f, FM_FMRI_CPU_SERIAL_ID,
2N/A sizeof (FM_FMRI_CPU_SERIAL_ID) - 1) == 0)
2N/A if ((f = strchr(f, '/')) != NULL)
2N/A f++;
2N/A if (f != NULL)
2N/A h += topo_fmri_strhash_one(f, strlen(f));
2N/A *rval = h;
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Acpu_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 *fa, *fb;
2N/A int lena = -1, lenb = -1;
2N/A
2N/A /*
2N/A * just skip the next char ("/") as there is no auth for cpu
2N/A */
2N/A a++;
2N/A b++;
2N/A
2N/A /*
2N/A * First compare the cpuid bit (first element)
2N/A */
2N/A if ((fa = strchr(a, '/')) != NULL)
2N/A lena = fa++ - a;
2N/A if ((fb = strchr(b, '/')) != NULL)
2N/A lenb = fb++ - b;
2N/A if (lena != lenb)
2N/A return (B_FALSE);
2N/A if (strncmp(a, b, lena) != 0)
2N/A return (B_FALSE);
2N/A
2N/A /*
2N/A * If next element is FM_FMRI_CPU_SERIAL_ID then skip it
2N/A * and compare what's left.
2N/A */
2N/A if (fa != NULL && strncmp(fa, FM_FMRI_CPU_SERIAL_ID,
2N/A sizeof (FM_FMRI_CPU_SERIAL_ID) - 1) == 0)
2N/A if ((fa = strchr(fa, '/')) != NULL)
2N/A fa++;
2N/A if (fb != NULL && strncmp(fb, FM_FMRI_CPU_SERIAL_ID,
2N/A sizeof (FM_FMRI_CPU_SERIAL_ID) - 1) == 0)
2N/A if ((fb = strchr(fb, '/')) != NULL)
2N/A fb++;
2N/A if (fa == NULL && fb == NULL)
2N/A return (B_TRUE);
2N/A else if (fa == NULL || fb == NULL)
2N/A return (B_FALSE);
2N/A else
2N/A return (strcmp(fa, fb) == 0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Acpu_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;
2N/A int lena = -1, lenb = -1;
2N/A
2N/A a = strstr(a, FM_FMRI_CPU_SERIAL_ID);
2N/A b = strstr(b, FM_FMRI_CPU_SERIAL_ID);
2N/A if (a == NULL && b == NULL)
2N/A return (B_TRUE);
2N/A else if (a == NULL || b == NULL)
2N/A return (B_FALSE);
2N/A
2N/A if ((fa = strchr(a, '/')) != NULL)
2N/A lena = fa - a;
2N/A if ((fb = strchr(b, '/')) != NULL)
2N/A lenb = fb - b;
2N/A if (lena != lenb)
2N/A return (B_FALSE);
2N/A return (strncmp(a, b, lena) == 0);
2N/A}