9113a79cf228b8f7bd509b1328adf88659dfe218eschrock/*
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * CDDL HEADER START
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock *
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * The contents of this file are subject to the terms of the
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * Common Development and Distribution License (the "License").
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * You may not use this file except in compliance with the License.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock *
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * or http://www.opensolaris.org/os/licensing.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * See the License for the specific language governing permissions
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * and limitations under the License.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock *
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * When distributing Covered Code, include this CDDL HEADER in each
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * If applicable, add the following below this CDDL HEADER, with the
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * fields enclosed by brackets "[]" replaced with your own identifying
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * information: Portions Copyright [yyyy] [name of copyright owner]
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock *
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * CDDL HEADER END
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock/*
81d9f076db88c1f40c85831ce1ebb444a209c5a8Robert Johnston * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * Use is subject to license terms.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * Copyright 2012 Joyent, Inc. All rights reserved.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock/*
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * /dev/ipmi IPMI monitor
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock *
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * The purpose of this module is to monitor the connection between the system
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * and the service processor attached via /dev/ipmi0. The module assumes the SP
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * supports the Sun OEM uptime IPMI command. If the BMC connection does not
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * exist, or the uptime function is not implemented, then the module unloads
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * without doing anything.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock *
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * When the module is first loaded, or a reset is detected, the module will
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * generate the ESC_PLATFORM_SP_RESET sysevent as a system-wide notification to
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * indicate that this event has occurred.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock *
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * Note that this event generation is not guaranteed to have a one-to-one
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * correspondence with an SP reset. There is no persistence, so if fmd is
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * restarted we will generate this event again. Thus the event only indicates
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * the possibility that the SP has been reset. This could be enhanced using fmd
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * checkpoints to have some persistent state to avoid this scenario. However,
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * it currently serves the useful dual purpose of notifying consumers of system
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * startup as well as SP reset through a single channel.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock#include <errno.h>
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock#include <libipmi.h>
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock#include <libsysevent.h>
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock#include <string.h>
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock#include <fm/fmd_api.h>
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock#include <sys/sysevent/eventdefs.h>
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrocktypedef struct sp_monitor {
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock ipmi_handle_t *sm_hdl;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock uint32_t sm_seconds;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock uint32_t sm_generation;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock hrtime_t sm_interval;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock} sp_monitor_t;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrockstatic void
9113a79cf228b8f7bd509b1328adf88659dfe218eschrocksp_post_sysevent(fmd_hdl_t *hdl)
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock{
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock sp_monitor_t *smp = fmd_hdl_getspecific(hdl);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock sysevent_id_t eid;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_debug(hdl, "SP reset detected, posting sysevent");
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock if (sysevent_post_event(EC_PLATFORM, ESC_PLATFORM_SP_RESET,
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock SUNW_VENDOR, "fmd", NULL, &eid) != 0) {
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_debug(hdl, "failed to send sysevent: %s",
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock strerror(errno));
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock /*
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * We reset the seconds and generation so that the next time
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * through we will try to post the sysevent again.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock smp->sm_seconds = -1U;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock smp->sm_generation = -1U;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock }
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock}
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock/*ARGSUSED*/
9113a79cf228b8f7bd509b1328adf88659dfe218eschrockstatic void
9113a79cf228b8f7bd509b1328adf88659dfe218eschrocksp_timeout(fmd_hdl_t *hdl, id_t id, void *data)
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock{
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock sp_monitor_t *smp = fmd_hdl_getspecific(hdl);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock uint32_t seconds, generation;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock if (ipmi_sunoem_uptime(smp->sm_hdl, &seconds, &generation) != 0) {
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock /*
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * Ignore uptime failures. We will generate the appropriate
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * event when it comes back online.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_debug(hdl, "failed to get uptime: %s",
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock ipmi_errmsg(smp->sm_hdl));
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock } else {
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock /*
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * We want to catch cases where the generation number is
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * explicitly reset, or when the SP configuration is reset after
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * a reboot (and the generation number is 0). We also post a
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * sysevent when the module initially loads, since we can't be
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * sure if we missed a SP reset or not.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock if (seconds < smp->sm_seconds ||
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock generation != smp->sm_generation ||
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock smp->sm_seconds == 0)
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock sp_post_sysevent(hdl);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock smp->sm_seconds = seconds;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock smp->sm_generation = generation;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock }
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock (void) fmd_timer_install(hdl, NULL, NULL, smp->sm_interval);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock}
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrockstatic const fmd_hdl_ops_t fmd_ops = {
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock NULL, /* fmdo_recv */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock sp_timeout, /* fmdo_timeout */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock NULL, /* fmdo_close */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock NULL, /* fmdo_stats */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock NULL, /* fmdo_gc */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock};
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrockstatic const fmd_prop_t fmd_props[] = {
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock { "interval", FMD_TYPE_TIME, "60sec" },
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock { NULL, 0, NULL }
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock};
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrockstatic const fmd_hdl_info_t fmd_info = {
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock "Service Processor Monitor", "1.0", &fmd_ops, fmd_props
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock};
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrockvoid
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock_fmd_init(fmd_hdl_t *hdl)
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock{
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock sp_monitor_t *smp;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock int error;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock char *msg;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0)
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock return;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock smp = fmd_hdl_zalloc(hdl, sizeof (sp_monitor_t), FMD_SLEEP);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_setspecific(hdl, smp);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
81d9f076db88c1f40c85831ce1ebb444a209c5a8Robert Johnston if ((smp->sm_hdl = ipmi_open(&error, &msg, IPMI_TRANSPORT_BMC, NULL))
81d9f076db88c1f40c85831ce1ebb444a209c5a8Robert Johnston == NULL) {
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock /*
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * If /dev/ipmi0 doesn't exist on the system, then unload the
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * module without doing anything.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock if (error != EIPMI_BMC_OPEN_FAILED)
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_abort(hdl, "failed to initialize IPMI "
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock "connection: %s\n", msg);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_debug(hdl, "failed to load: no IPMI connection "
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock "present");
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_free(hdl, smp, sizeof (sp_monitor_t));
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_unregister(hdl);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock return;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock }
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock /*
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * Attempt an initial uptime() call. If the IPMI command is
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * unrecognized, then this is an unsupported platform and the module
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * should be unloaded. Any other error is treated is transient failure.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock if ((error = ipmi_sunoem_uptime(smp->sm_hdl, &smp->sm_seconds,
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock &smp->sm_generation)) != 0 &&
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock ipmi_errno(smp->sm_hdl) == EIPMI_INVALID_COMMAND) {
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_debug(hdl, "failed to load: uptime command "
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock "not supported");
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock ipmi_close(smp->sm_hdl);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_free(hdl, smp, sizeof (sp_monitor_t));
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_unregister(hdl);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock return;
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock }
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock smp->sm_interval = fmd_prop_get_int64(hdl, "interval");
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock if (error == 0)
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_debug(hdl, "successfully loaded, uptime = %u seconds "
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock "(generation %u)", smp->sm_seconds, smp->sm_generation);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock else
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_debug(hdl, "successfully loaded, but uptime call "
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock "failed: %s", ipmi_errmsg(smp->sm_hdl));
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock /*
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock * Setup the recurring timer.
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock */
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock (void) fmd_timer_install(hdl, NULL, NULL, 0);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock}
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrockvoid
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock_fmd_fini(fmd_hdl_t *hdl)
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock{
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock sp_monitor_t *smp = fmd_hdl_getspecific(hdl);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock if (smp) {
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock ipmi_close(smp->sm_hdl);
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock fmd_hdl_free(hdl, smp, sizeof (sp_monitor_t));
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock }
9113a79cf228b8f7bd509b1328adf88659dfe218eschrock}