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) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <atomic.h>
2N/A#include <errno.h>
2N/A#include <libdevinfo.h>
2N/A#include <libsysevent.h>
2N/A#include <pthread.h>
2N/A#include <smbios.h>
2N/A#include <string.h>
2N/A#include <sys/fm/protocol.h>
2N/A#include <sys/sysevent/eventdefs.h>
2N/A
2N/A#include "asr.h"
2N/A#include "asr_mem.h"
2N/A#include "asr_nvl.h"
2N/A#include "asr_err.h"
2N/A
2N/A#define LATEST_TOPO "/var/fm/fmd/topo/latest"
2N/A
2N/Astatic pthread_mutex_t asr_topo_lock = PTHREAD_MUTEX_INITIALIZER;
2N/A
2N/A/*
2N/A * Generates a new topology
2N/A */
2N/Astatic topo_hdl_t *
2N/Aasr_topo_gen(asr_handle_t *ah)
2N/A{
2N/A int err = 0;
2N/A topo_hdl_t *th = NULL;
2N/A char *id;
2N/A
2N/A (void) pthread_mutex_lock(&asr_topo_lock);
2N/A if ((th = topo_open(TOPO_VERSION, NULL, &err)) == NULL) {
2N/A (void) asr_error(EASR_TOPO,
2N/A "failed to alloc topo handle: %s", topo_strerror(err));
2N/A goto finally;
2N/A }
2N/A if ((id = topo_snap_load(th, LATEST_TOPO, &err)) == NULL) {
2N/A topo_close(th);
2N/A th = NULL;
2N/A (void) asr_error(EASR_TOPO,
2N/A "failed to load libtopo snapshot: %s", topo_strerror(err));
2N/A goto finally;
2N/A }
2N/A asr_log_debug(ah, "Loaded topology reference %s", id);
2N/A topo_hdl_strfree(th, id);
2N/A
2N/Afinally:
2N/A (void) pthread_mutex_unlock(&asr_topo_lock);
2N/A return (th);
2N/A}
2N/A
2N/A/*
2N/A * Given an FMRI (in nvlist form), convert it to a string. Simply wrap around
2N/A * topo_fmri_nvl2str, but fallback to something if we don't have an appropriate
2N/A * libtopo plugin.
2N/A */
2N/Achar *
2N/Aasr_topo_fmri2str(topo_hdl_t *thp, nvlist_t *fmri)
2N/A{
2N/A int err;
2N/A char *scheme, *fmristr;
2N/A char *buf;
2N/A size_t len;
2N/A
2N/A if (topo_fmri_nvl2str(thp, fmri, &fmristr, &err) == 0) {
2N/A buf = asr_strdup(fmristr);
2N/A topo_hdl_strfree(thp, fmristr);
2N/A return (buf);
2N/A }
2N/A
2N/A if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) {
2N/A (void) asr_error(EASR_FM, "unknown FMRI scheme");
2N/A return (NULL);
2N/A }
2N/A
2N/A len = snprintf(NULL, 0, "%s://unknown", scheme);
2N/A if ((buf = asr_zalloc(len + 1)) == NULL) {
2N/A (void) asr_error(EASR_NOMEM, "unable to alloc fmri string");
2N/A return (NULL);
2N/A }
2N/A (void) snprintf(buf, len + 1, "%s://unknown", scheme);
2N/A return (buf);
2N/A}
2N/A
2N/A/*
2N/A * Walks the FM topology using the given walker callback function and
2N/A * callback data.
2N/A */
2N/Aint
2N/Aasr_topo_walk(asr_handle_t *ah, topo_walk_cb_t walker, void *data)
2N/A{
2N/A int err = 0;
2N/A topo_hdl_t *th;
2N/A topo_walk_t *twp = NULL;
2N/A asr_topo_enum_data_t tdata;
2N/A
2N/A if ((th = asr_topo_gen(ah)) == NULL)
2N/A return (ASR_FAILURE);
2N/A
2N/A tdata.asr_hdl = ah;
2N/A tdata.asr_topoh = th;
2N/A tdata.asr_data = data;
2N/A if ((twp = topo_walk_init(
2N/A th, FM_FMRI_SCHEME_HC, walker, &tdata, &err)) == NULL)
2N/A goto finally;
2N/A
2N/A if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) {
2N/A asr_log_warn(ah, "topo_error: %s", topo_strerror(err));
2N/A err = EASR_TOPO;
2N/A }
2N/A
2N/Afinally:
2N/A if (twp != NULL)
2N/A topo_walk_fini(twp);
2N/A topo_close(th);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Gets the FMA host authority information from fmtopo
2N/A */
2N/Aint
2N/Aasr_topo_auth(asr_handle_t *ah, nvlist_t **auth)
2N/A{
2N/A topo_hdl_t *th;
2N/A
2N/A if ((th = asr_topo_gen(ah)) == NULL)
2N/A return (ASR_FAILURE);
2N/A *auth = asr_nvl_dup(topo_hdl_auth(th));
2N/A topo_close(th);
2N/A return (*auth == NULL ? ASR_FAILURE : ASR_OK);
2N/A}
2N/A
2N/A/*
2N/A * Gets a system prop property and sets it to the given asrprop name.
2N/A */
2N/Astatic int
2N/Aasr_topo_prom_prop(asr_handle_t *ah, char *promprop, char *asrprop)
2N/A{
2N/A di_prom_handle_t promh = DI_PROM_HANDLE_NIL;
2N/A di_node_t rooth = DI_NODE_NIL;
2N/A unsigned char *bufp;
2N/A int result = ASR_FAILURE;
2N/A
2N/A if ((promh = di_prom_init()) == NULL)
2N/A return (result);
2N/A
2N/A if ((rooth = di_init("/", DINFOPROP)) == NULL) {
2N/A di_prom_fini(promh);
2N/A return (result);
2N/A }
2N/A
2N/A if (di_prom_prop_lookup_bytes(promh, rooth, promprop, &bufp) != -1)
2N/A result = asr_setprop_str(ah, asrprop, (char *)bufp);
2N/A
2N/A di_fini(rooth);
2N/A di_prom_fini(promh);
2N/A return (result);
2N/A}
2N/A
2N/A/*
2N/A * Sets the ASR system id property from the prom or smbios.
2N/A */
2N/Aint
2N/Aasr_topo_set_system_id(asr_handle_t *ah)
2N/A{
2N/A smbios_hdl_t *shp = NULL;
2N/A const char *csn = NULL;
2N/A int result = ASR_FAILURE;
2N/A
2N/A if (asr_topo_prom_prop(ah, "chassis-sn", ASR_PROP_SYSTEM_ID) == 0)
2N/A return (ASR_OK);
2N/A
2N/A if ((shp = smbios_open(NULL, SMB_VERSION, 0, NULL)) == NULL)
2N/A return (ASR_FAILURE);
2N/A if ((csn = smbios_csn(shp)) != NULL)
2N/A result = asr_setprop_str(ah, ASR_PROP_SYSTEM_ID, csn);
2N/A smbios_close(shp);
2N/A return (result);
2N/A}
2N/A
2N/A/*
2N/A * Sets the ASR product name from the prom or smbios.
2N/A */
2N/Aint
2N/Aasr_topo_set_product_name(asr_handle_t *ah)
2N/A{
2N/A smbios_hdl_t *shp = NULL;
2N/A id_t id;
2N/A smbios_system_t s1;
2N/A smbios_info_t s2;
2N/A int result = ASR_FAILURE;
2N/A
2N/A if (asr_topo_prom_prop(ah, "name", ASR_PROP_PRODUCT_NAME) == 0)
2N/A return (ASR_OK);
2N/A
2N/A if ((shp = smbios_open(NULL, SMB_VERSION, 0, NULL)) == NULL)
2N/A return (ASR_FAILURE);
2N/A
2N/A if (((id = smbios_info_system(shp, &s1)) != SMB_ERR) &&
2N/A (smbios_info_common(shp, id, &s2) != SMB_ERR) &&
2N/A (strcmp(s2.smbi_product, SMB_DEFAULT1) != 0) &&
2N/A (strcmp(s2.smbi_product, SMB_DEFAULT2) != 0))
2N/A result = asr_setprop_str(ah, ASR_PROP_PRODUCT_NAME,
2N/A s2.smbi_product);
2N/A smbios_close(shp);
2N/A return (result);
2N/A}