/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <limits.h>
#include <alloca.h>
#include <errno.h>
#include <libnvpair.h>
#include <fm/topo_mod.h>
#include <libipmi.h>
/*
* The largest possible SDR ID length is 2^5+1
*/
#define TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION 0
#define TOPO_METH_IPMI_READING_VERSION 0
#define TOPO_METH_IPMI_STATE_VERSION 0
#define TOPO_METH_IPMI_MODE_VERSION 0
#define TOPO_METH_X4500_MODE_VERSION 0
#define TOPO_METH_BAY_LOCATE_VERSION 0
#define TOPO_METH_BAY_MODE_VERSION 0
#define TOPO_METH_CHASSIS_SERVICE_VERSION 0
#define TOPO_METH_IPMI_ENTITY_VERSION 0
#define TOPO_METH_DIMM_IPMI_ENTITY_VERSION 0
topo_instance_t, topo_instance_t, void *, void *);
/*
* IPMI facility provider methods
*/
nvlist_t **);
nvlist_t **);
nvlist_t **);
&ipmi_ops };
{ "dimm_ipmi_entity", TOPO_PROP_METH_DESC,
{ "cs_ipmi_entity", TOPO_PROP_METH_DESC,
{ NULL }
};
{ "ipmi_platform_message", TOPO_PROP_METH_DESC,
{ "ipmi_sensor_reading", TOPO_PROP_METH_DESC,
{ "ipmi_sensor_state", TOPO_PROP_METH_DESC,
{ "ipmi_indicator_mode", TOPO_PROP_METH_DESC,
{ "bay_locate_mode", TOPO_PROP_METH_DESC,
{ "bay_indicator_mode", TOPO_PROP_METH_DESC,
{ "chassis_service_mode", TOPO_PROP_METH_DESC,
{ "x4500_present_mode", TOPO_PROP_METH_DESC,
{ "dimm_ipmi_entity", TOPO_PROP_METH_DESC,
{ "cs_ipmi_entity", TOPO_PROP_METH_DESC,
{ NULL }
};
struct entity_info {
};
struct sensor_data {
char *sd_class;
};
/*ARGSUSED*/
int
{
}
void
{
}
static void
{
for (int i = 0; i < nelems; i++)
}
/*
* Some platforms (most notably G1/2N) use the 'platform event message' command
* to manipulate disk fault LEDs over IPMI, but uses the standard sensor
* reading to read the value. This method implements this alternative
* interface for these platforms.
*/
/*ARGSUSED*/
static int
{
char *entity_ref;
/*
* Get an IPMI handle and then lookup the generic device locator sensor
* data record referenced by the entity_ref prop val
*/
return (-1);
}
&entity_ref, &err) != 0) {
return (-1);
}
return (-1);
}
/*
* Now look for a private argument list to figure out whether we're
* doing a get or a set operation, and then do it.
*/
/*
* Set the LED mode
*/
&mode)) != 0) {
return (-1);
}
if (mode != TOPO_LED_STATE_OFF &&
mode != TOPO_LED_STATE_ON) {
mode);
return (-1);
}
/*
* The spec states that any values between 0x20 and 0x29 are
* legitimate for "system software". However, some versions of
* of 0x20, so we use 0x21 instead.
*/
pem.ipem_event_dir = 0;
if (mode == TOPO_LED_STATE_ON)
else
pem.ipem_event_data[0] = 0;
return (-1);
}
} else {
/*
* Get the LED mode
*/
== NULL) {
"for sensor %s: %s\n", entity_ref,
ipmi_errmsg(hdl));
return (-1);
}
else
}
}
return (0);
}
/*ARGSUSED*/
static int
{
char **entity_refs;
int err, i;
if (vers > TOPO_METH_IPMI_STATE_VERSION)
}
return (-1);
}
for (i = 0; i < nelems; i++) {
break;
} else
}
if (! found_sdr) {
return (-1);
}
break;
break;
default:
"compact SDR\n", entity_refs[i]);
return (-1);
}
== NULL) {
ipmi_errmsg(hdl));
return (-1);
}
TOPO_SENSOR_STATE) != 0 ||
!= 0) {
}
return (0);
}
/*ARGSUSED*/
static int
{
int err = 0, i;
double conv_reading;
}
return (-1);
}
for (i = 0; i < nelems; i++) {
!= NULL) {
break;
} else
}
if (! found_sdr) {
return (-1);
}
== NULL) {
"%s, sensor_num=%d (%s)\n", entity_refs[i],
return (-1);
}
!= 0) {
return (-1);
}
TOPO_SENSOR_READING) != 0 ||
}
return (0);
}
static int
{
char **entity_refs;
if (vers > TOPO_METH_IPMI_MODE_VERSION)
/*
* Get an IPMI handle and then lookup the generic device locator sensor
* data record referenced by the entity_ref prop val
*/
return (-1);
}
}
for (i = 0; i < nelems; i++) {
!= NULL) {
break;
} else
}
if (! found_sdr) {
return (-1);
}
/*
* Now look for a private argument list to figure out whether we're
* doing a get or a set operation, and then do it.
*/
/*
* Set the LED mode
*/
&mode_in)) != 0) {
}
if (mode_in != TOPO_LED_STATE_OFF &&
mode_in != TOPO_LED_STATE_ON) {
mode_in);
}
return (-1);
}
} else {
/*
* Get the LED mode
*/
ipmi_errmsg(hdl));
return (-1);
}
}
}
return (0);
}
/*
* On most Sun platforms there is no seperate locate LED for the drive bays.
* This propmethod simulates a locate LED by blinking the ok2rm LED.
*
*/
static int
{
char **entity_refs;
if (vers > TOPO_METH_BAY_LOCATE_VERSION)
/*
* Get an IPMI handle and then lookup the generic device locator sensor
* data record referenced by the entity_ref prop val
*/
return (-1);
}
}
for (i = 0; i < nelems; i++) {
!= NULL) {
break;
} else
}
if (! found_sdr) {
return (-1);
}
/*
* Now look for a private argument list to figure out whether we're
* doing a get or a set operation, and then do it.
*/
/*
* Set the LED mode
*/
&mode_in)) != 0) {
}
if (mode_in != TOPO_LED_STATE_OFF &&
mode_in != TOPO_LED_STATE_ON) {
mode_in);
}
if (mode_in == TOPO_LED_STATE_ON)
else
return (-1);
}
} else {
/*
* Get the LED mode
*/
return (-1);
}
}
if (ledmode == IPMI_SUNOEM_LED_MODE_SLOW ||
else
}
return (0);
}
/*
* This is a method for the "mode" property that is specific for the ok2rm and
* ILOM 3.x.
*
* For ILOM 2.x, the LED's are controlled by a Sun OEM led set command
*
* For ILOM 3.x platforms the LED's are controlled by sending a platform event
*
* For both ILOM 2 and ILOM 3, the current LED mode can be obtained by a
* Sun OEM led get command.
*/
static int
{
char **entity_refs;
if (vers > TOPO_METH_BAY_MODE_VERSION)
}
switch (type) {
case (TOPO_LED_TYPE_SERVICE):
ev_off = 0x01;
break;
case (TOPO_LED_TYPE_OK2RM):
ev_off = 0x03;
break;
default:
}
}
/*
* Figure out whether the SP is running ILOM 2.x or ILOM 3.x
*/
return (-1);
}
return (-1);
}
/*
* Now lookup the propmethod argument list and figure out whether we're
* doing a get or a set operation, and then do it.
*/
/*
* Set the LED mode
*/
&ledmode)) != 0) {
}
for (i = 0; i < nelems; i++) {
entity_refs[i])) != NULL) {
break;
} else
"Failed to lookup SDR for %s(%s)\n",
}
if (! found_sdr) {
return (-1);
}
< 0) {
"Failed to set LED mode for %s (%s)\n",
return (-1);
}
} else {
for (i = 0; i < nelems; i++) {
entity_refs[i])) != NULL) {
break;
} else
"Failed to lookup SDR for %s(%s)\n",
}
if (! found_sdr) {
return (-1);
}
if (ledmode == TOPO_LED_STATE_ON)
pem.ipem_event_dir = 0;
else
"platform event mesg for %s (%s)\n",
return (-1);
}
}
} else {
/*
* Get the LED mode
*/
for (i = 0; i < nelems; i++) {
!= NULL) {
break;
} else
"SDR for %s (%s)\n", __func__,
}
if (! found_sdr) {
return (-1);
}
ipmi_errmsg(hdl));
return (-1);
}
}
}
return (0);
}
/*
* This propmethod is for controlling the present LED on the drive bays for
* the X4500 platform.
*/
static int
{
char **entity_refs;
if (vers > TOPO_METH_X4500_MODE_VERSION)
}
return (-1);
}
for (i = 0; i < nelems; i++) {
!= NULL) {
break;
} else
"(%s)\n", entity_refs[i],
ipmi_errmsg(hdl));
}
if (! found_sdr) {
return (-1);
}
/*
* Now lookup the propmethod argument list and figure out whether we're
* doing a get or a set operation, and then do it.
*/
/*
* Set the LED mode
*/
&ledmode)) != 0) {
}
if (ledmode == TOPO_LED_STATE_OFF) {
} else if (ledmode == TOPO_LED_STATE_ON) {
} else {
return (-1);
}
"sensor reading for %s (%s)\n", __func__,
return (-1);
}
} else {
/*
* Get the LED mode
*/
== NULL) {
"for sensor %s (sensor num: %d) (error: %s)\n",
return (-1);
}
else
}
}
return (0);
}
/*
* This is a property method for controlling the chassis service LED on
* ILOM 3.x based platforms.
*/
static int
{
char **entity_refs;
/*
* Get an IPMI handle and then lookup the generic device locator record
* referenced by the entity_ref prop val
*/
return (-1);
}
}
for (i = 0; i < nelems; i++) {
!= NULL) {
break;
} else
}
if (! found_sdr) {
return (-1);
}
/*
* Now lookup the propmethod argument list and figure out whether we're
* doing a get or a set operation, and then do it.
*/
/*
* Set the LED mode
*/
&mode_in)) != 0) {
}
/*
* Determine which IPMI mechanism to use to set the LED mode
* based on whether the SP is running ILOM 2 or later.
*/
return (-1);
}
if (mode_in != TOPO_LED_STATE_OFF &&
mode_in != TOPO_LED_STATE_ON) {
"%d\n", mode_in);
}
< 0) {
"for %s (%s)\n", entity_refs[i],
ipmi_errmsg(hdl));
return (-1);
}
} else {
if (mode_in == TOPO_LED_STATE_ON)
pem.ipem_event_dir = 0;
else
"platform event mesg for sensor 0 (%s)\n",
return (-1);
}
}
} else {
/*
* Get the LED mode
*/
ipmi_errmsg(hdl));
return (-1);
}
}
}
return (0);
}
static int
{
/*
* Some platforms have '/' characters in the IPMI entity name, but '/'
* has a special meaning for FMRI's so we change them to '.' before
* binding the node into the topology.
*/
for (i = 0; facname[i]; i++)
if (facname[i] == '/')
facname[i] = '.';
facname);
/* topo errno set */
return (-1);
}
if (err != ETOPO_PROP_DEFD) {
topo_strerror(err));
return (-1);
}
}
"failed to register facility methods");
return (-1);
}
/*
* For both threshold and discrete sensors we set up a propmethod for
* getting the sensor state and properties to hold the entity ref,
* sensor class and sensor type.
*
* Additionally, for analog sensors we set up a property method for
* getting the converted sensor reading and property for the base
* unit type
*/
&err) != 0) {
return (-1);
}
return (-1);
}
return (-1);
}
}
!= 0) {
return (-1);
}
&err) != 0) {
topo_strerror(err));
return (-1);
}
"on fac node %s (%s)\n", TOPO_SENSOR_READING,
return (-1);
}
!= 0) {
topo_strerror(err));
return (-1);
}
}
return (0);
}
/* ARGSUSED */
static int
{
int sensor_idlen;
f_sensor =
break;
c_sensor =
break;
default:
return (0);
}
else
/*
* We offset the threshold and generic sensor reading types by 0x100
*/
return (-1);
}
return (0);
}
/* ARGSUSED */
static int
{
char **entity_refs;
int err;
return (-1);
}
/*
* Use the entity ref to lookup the SDR, which will have the entity ID
* and instance.
*/
}
for (int i = 0; i < nelems; i++) {
break;
} else
ipmi_errmsg(hdl));
}
if (! found_sdr) {
return (-1);
}
break;
break;
break;
break;
default:
}
/*
* Now iterate through all of the full and compact sensor data records
* and create a sensor facility node for each record that matches our
* entity ID and instance
*/
return (-1);
}
return (0);
}
static int
{
}
}
}
}
== NULL)
else
for (int i = 0; i < nelems; i++) {
switch (nparams) {
case 1:
/* LINTED: E_SEC_PRINTF_VAR_FMT */
break;
case 2:
+ offset;
/* LINTED: E_SEC_PRINTF_VAR_FMT */
break;
default:
nparams);
}
}
TOPO_TYPE_STRING_ARRAY) != 0 ||
nelems) != 0) {
}
return (0);
}
/* ARGSUSED */
static int
{
int ret;
}
}
}
== NULL)
else
for (int i = 0; i < nelems; i++) {
/* LINTED: E_SEC_PRINTF_VAR_FMT */
}
TOPO_TYPE_STRING_ARRAY) != 0 ||
!= 0) {
}
return (0);
}
/* ARGSUSED */
static int
{
}
}
}
== NULL)
} else {
}
for (int i = 0; i < nelems; i++) {
/* LINTED: E_SEC_PRINTF_VAR_FMT */
dimm_num);
}
TOPO_TYPE_STRING_ARRAY) != 0 ||
!= 0) {
}
return (0);
}
/*ARGSUSED*/
static int
{
int err;
if (err != ETOPO_PROP_DEFD) {
"pgroups create failure: %s\n",
topo_strerror(err));
return (-1);
}
}
"topo_method_register() failed: %s",
return (-1);
}
} else {
"topo_method_register() failed: %s",
return (-1);
}
}
return (0);
}