/*
* 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
*/
/*
*/
#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
#define TOPO_METH_CHASSIS_LOCATE_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,
{ "chassis_locate_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++)
}
static void *
{
for (int i = 0; i < nelems; i++)
break;
}
if (! found_sdr)
return (NULL);
switch (entity_type) {
break;
break;
break;
default:
return (NULL);
}
return (record);
}
/*
* 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_refs;
}
/*
* Get an IPMI handle and then lookup the sensor data record referenced
* by the entity_ref prop val
*/
return (-1);
}
IPMI_SDR_TYPE_COMPACT_SENSOR)) == NULL) {
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;
ipmi_errmsg(hdl));
return (-1);
}
} else {
/*
* Get the LED mode
*/
== NULL) {
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;
double conv_reading;
}
return (-1);
}
IPMI_SDR_TYPE_FULL_SENSOR)) == NULL) {
return (-1);
}
== NULL) {
ipmi_errmsg(hdl));
return (-1);
}
!= 0) {
ipmi_errmsg(hdl));
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);
}
}
IPMI_SDR_TYPE_GENERIC_LOCATOR)) == NULL) {
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);
}
ipmi_errmsg(hdl));
return (-1);
}
} else {
/*
* Get the LED mode
*/
return (-1);
}
}
}
return (0);
}
/*ARGSUSED*/
static int
{
return (TOPO_WALK_NEXT);
}
static int
{
int err;
&err);
return (-1);
}
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.
*
* For the X4500, X4540 running ILOM 2.x and X64 platforms running ILOM 3.0.9
*
* For ILOM 3.0.14.x and later platforms, the LED's are controlled by using the
* as defined by PRMS-29.
*
*/
static int
{
char **entity_refs;
if (vers > TOPO_METH_BAY_LOCATE_VERSION)
}
/*
* Figure out what version of ILOM the SP is running
*/
return (-1);
}
__func__);
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
*/
&ledmode)) != 0) {
}
IPMI_SDR_TYPE_GENERIC_LOCATOR)) == NULL) {
return (-1);
}
if (ledmode != TOPO_LED_STATE_OFF &&
ledmode != TOPO_LED_STATE_ON) {
"%d\n", ledmode);
}
if (ledmode == TOPO_LED_STATE_ON)
else
return (-1);
}
IPMI_SDR_TYPE_COMPACT_SENSOR)) == NULL) {
return (-1);
}
if (ledmode == TOPO_LED_STATE_OFF) {
} else if (ledmode == TOPO_LED_STATE_ON) {
} else {
return (-1);
}
mask);
"sensor reading (%s)\n", __func__,
ipmi_errmsg(hdl));
return (-1);
}
} else {
__func__);
}
} else {
/*
* Get the LED mode
*
* If the drive bay is empty, we will not be able to read
* the LED mode. In that case, rather than return an error,
* we will return a state that indicates that the mode is
* unknown.
*/
return (-1);
} else if (empty) {
goto bay_locate_done;
}
IPMI_SDR_TYPE_GENERIC_LOCATOR)) == NULL) {
return (-1);
}
ipmi_errmsg(hdl));
return (-1);
}
if (mode_in == 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.0.9.x platforms the LED's are controlled by sending a platform
*
* For ILOM 3.0.14.x and later platforms, the LED's are controlled by using the
* as defined by PRMS-29.
*
* 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):
case (TOPO_LED_TYPE_LOCATE):
ev_off = 0x03;
break;
default:
}
}
/*
* Figure out what version of ILOM the SP is running
*/
return (-1);
}
__func__);
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 (major == 2) {
IPMI_SDR_TYPE_GENERIC_LOCATOR)) == NULL) {
return (-1);
}
< 0) {
"Failed to set LED mode (%s)\n",
ipmi_errmsg(hdl));
return (-1);
}
IPMI_SDR_TYPE_COMPACT_SENSOR)) == NULL) {
return (-1);
}
if (ledmode == TOPO_LED_STATE_ON)
pem.ipem_event_dir = 0;
else
"platform event mesg (%s)\n",
return (-1);
}
IPMI_SDR_TYPE_COMPACT_SENSOR)) == NULL) {
return (-1);
}
if (ledmode == TOPO_LED_STATE_OFF) {
} else if (ledmode == TOPO_LED_STATE_ON) {
} else {
return (-1);
}
mask);
"sensor reading (%s)\n", __func__,
ipmi_errmsg(hdl));
return (-1);
}
} else {
__func__);
}
} else {
/*
* Get the LED mode
*
* If the drive bay is empty, we will not be able to get read
* the LED mode. In that case, rather than return an error,
* we will return a state that indicates that the mode is
* unknown.
*/
return (-1);
} else if (empty) {
goto bay_indicator_done;
}
IPMI_SDR_TYPE_GENERIC_LOCATOR)) == NULL) {
return (-1);
}
return (-1);
}
if (mode_in != 0)
else
}
}
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);
}
IPMI_SDR_TYPE_COMPACT_SENSOR)) == NULL) {
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 (%s)\n", __func__,
ipmi_errmsg(hdl));
return (-1);
}
} else {
/*
* Get the LED mode
*/
== NULL) {
return (-1);
}
else
}
}
return (0);
}
/*
* This is a property method for controlling the chassis service LED
*/
static int
{
char **entity_refs;
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 the version of ILOM.
*/
&release) != 0) {
return (-1);
}
if (major == 2) {
/*
* For ILOM 2.x, we use the a Sun OEM IPMI command
* set the LED state.
*/
IPMI_SDR_TYPE_GENERIC_LOCATOR)) == NULL) {
return (-1);
}
if (mode_in != TOPO_LED_STATE_OFF &&
mode_in != TOPO_LED_STATE_ON) {
"%d\n", mode_in);
}
< 0) {
return (-1);
}
/*
* For versions of ILOM 3 that are prior to 3.0.14.x
* we set the LED state by sending an IPMI Platform
* Event message per section 29.3 of the IPMI spec
*/
if (mode_in == TOPO_LED_STATE_ON)
pem.ipem_event_dir = 0;
else
"platform event mesg for sensor 0 (%s)\n",
return (-1);
}
/*
* For ILOM 3.0.14 or later, the LED is controlled using
* the interface defined by PRMS-077
*/
IPMI_SDR_TYPE_FULL_SENSOR)) == NULL) {
return (-1);
}
if (mode_in == TOPO_LED_STATE_OFF)
else if (mode_in == TOPO_LED_STATE_ON)
else {
return (-1);
}
"sensor reading (%s)\n", __func__,
ipmi_errmsg(hdl));
return (-1);
}
} else {
__func__);
}
} else {
/*
* Get the LED mode
*/
IPMI_SDR_TYPE_GENERIC_LOCATOR)) == NULL) {
return (-1);
}
return (-1);
}
}
}
return (0);
}
/*
* This is a property method for controlling the chassis locate LED on
* ILOM 3.x based platforms that implement PRMS-007
*/
static int
{
char **entity_refs;
return (-1);
}
/*
* 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) {
}
}
} else {
/*
* Get the LED mode
*/
}
IPMI_SDR_TYPE_GENERIC_LOCATOR)) == NULL) {
return (-1);
}
ipmi_errmsg(hdl));
return (-1);
}
if (ledmode != 0)
}
}
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);
}