piclenvmon.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This plugin creates PICL nodes and properties for objects handled through
* the enhanced LOMV system-processor interface.
*
* All the nodes which may be accessible through the system-processor are
* included below the service-processor node in the /platform tree.
* This plugin interrogates the system-processor to determine which of
* those nodes are actually available. Properties are added to such nodes and
* in the case of volatile properties like temperature, a call-back function
* is established for on-demand access to the current value.
* LEDs for which the system-processor provides write access are associated
*
* NOTE:
* Depends on PICL devtree plugin.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <alloca.h>
#include <syslog.h>
#include <string.h>
#include <libintl.h>
#include <picl.h>
#include <picltree.h>
#include <libnvpair.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>
#include <sys/systeminfo.h>
#include <dirent.h>
#include <time.h>
#include <picldefs.h>
#include <picld_pluginutil.h>
#include <libdevinfo.h>
#include "piclenvmon.h"
static void piclenvmon_register(void);
static void piclenvmon_init(void);
static void piclenvmon_fini(void);
static node_list_t *create_node_list();
static void create_arrays();
static void convert_node_name(char *ptr);
static void convert_label_name(char *ptr);
static int get_config_file(char *filename);
int *max_len);
static void setup_strings();
#pragma init(piclenvmon_register)
static picld_plugin_reg_t my_reg_info = {
"SUNW_piclenvmon",
};
static const char str_On[] = "on";
static const char str_Off[] = "off";
static const char str_SC[] = "SC";
static char *envmon_device_name = NULL;
static envmon_sysinfo_t env_limits;
static handle_array_t handle_arr;
static struct {
int size;
char *str_colour;
static struct {
char *str_ledstate;
} ledstate_lkup[] = {
{ ENVMON_LED_OFF },
{ ENVMON_LED_ON },
{ ENVMON_LED_BLINKING },
};
static struct {
char *str_keyposn;
} keyposn_lkup[] = {
};
/*
* fru-type to ioctl cmd lookup
*/
int fru_to_cmd[] = {
};
/*
* fru-type to PICL CLASS
*/
const char *fru_to_class[] = {
};
/*
* fru-type to PICL PROPERTY for volatile data
*/
const char *fru_to_prop[] = {
};
/*
* fru-type to PICL PTYPE
*/
int fru_to_ptype[] = {
};
/*
* condition strings
*/
static char *cond_okay;
static char *cond_failed;
/*
* fru-type to size of volatile property
* the -1's are replaced by the max size of a condition string
*/
int fru_to_size[] = {
4, -1, 4, -1, 2, -1, 2, -1, -1, -1
};
static node_el_t *
{
}
return (ptr);
}
static void
{
}
static node_list_t *
{
}
return (ptr);
}
static void
{
return;
}
/*
* normally pnl->tail would be to NULL next,
* but as it is about to be freed, this step can be skipped.
*/
}
/*
* Get a linking element and add handle to end of chain
*/
static void
{
else
}
}
/*
* Get a list of nodes of the specified classname under nodeh.
* Once a node of the specified class is found, its children are not
* searched.
*/
static void
{
int err;
/*
* go through the children
*/
sizeof (picl_nodehdl_t));
while (err == PICL_SUCCESS) {
else
sizeof (picl_nodehdl_t));
}
}
static int
{
}
static int
{
int res;
int maxnum;
if (res != 0)
return (res);
/*
* space requirements have changed
*/
(piclprhdls == NULL)) {
return (-1);
}
} else {
maxnum * sizeof (envmon_handle_t));
maxnum * sizeof (picl_prophdl_t));
}
handle_arr.num = 0;
return (0);
}
static void
{
handle_arr.num = 0;
}
static int
{
int err = PICL_SUCCESS;
listp = create_node_list();
envmoninfh)) != PICL_SUCCESS) {
return (err); /* no /platform ! */
}
listp);
*envmoninfh = 0;
} else {
}
return (err);
}
static char *
{
char *ptr;
/* prefix devfs-path name with /devices */
/*
* append devfs-path property
*/
return (NULL);
}
/* locate final component of name */
return (NULL);
return (NULL);
}
/*
* look for a name which starts with the string at *ptr
*/
continue; /* skip short names */
/*
* Got a match, restore full pathname and stat the
* entry. Reject if not a char device
*/
continue; /* reject if can't stat it */
continue; /* not a character device */
/*
* go with this entry
*/
}
}
return (NULL);
}
/*
* look for named node as child of supplied handle
*/
static int
{
int err;
char node_name[ENVMON_MAXNAMELEN];
return (PICL_NODENOTFOUND);
sizeof (*childh));
while (err == PICL_SUCCESS) {
if ((err == PICL_SUCCESS) &&
return (PICL_SUCCESS);
}
return (err);
}
/*
* Create and add the specified regular property
*/
static int
{
int err;
if (err != PICL_SUCCESS)
return (err);
&proph);
return (err);
}
/*
* Create and add the specified volatile property
*/
static int
{
int err;
if (err != PICL_SUCCESS)
return (err);
return (err);
}
/*
* There are 5 different structures used for reading environmental data
* from the service-processor. A different function is used for each one.
* Some functions cover several ioctls, so the desired ioctl is part of
* returned value being the next id for this fru type.
*/
/*
* Function to read sensor data.
*/
static int
{
int res;
if (res < 0) {
return (PICL_NOTREADABLE);
}
return (PICL_INVALIDHANDLE);
/*
* it is assumed that threshold data will be available,
* even though the current sensor value may be inaccessible
*/
return (PICL_PROPVALUNAVAILABLE);
}
return (PICL_SUCCESS);
}
/*
* Function to read indicator data.
*/
static int
{
int res;
if (res < 0)
return (PICL_NOTREADABLE);
return (PICL_INVALIDHANDLE);
return (PICL_PROPVALUNAVAILABLE);
}
return (PICL_SUCCESS);
}
/*
* Function to read fan data.
*/
static int
{
int res;
if (res < 0)
return (PICL_NOTREADABLE);
return (PICL_INVALIDHANDLE);
return (PICL_PROPVALUNAVAILABLE);
}
return (PICL_SUCCESS);
}
/*
* Function to read LED data.
*/
static int
{
int res;
if (res < 0)
return (PICL_NOTREADABLE);
return (PICL_INVALIDHANDLE);
return (PICL_PROPVALUNAVAILABLE);
}
return (PICL_SUCCESS);
}
/*
* Function to read key-switch position
* Returns PICL_INVALIDHANDLE if ioctl not supported (or fails)
*/
static int
{
int res;
return (PICL_INVALIDHANDLE);
return (PICL_INVALIDHANDLE);
} else {
if (res < 0)
return (PICL_INVALIDHANDLE);
return (PICL_SUCCESS);
}
}
/*
* change to lower case and convert any spaces into hyphens,
* and any dots or colons symbols into underscores
*/
static void
convert_node_name(char *ptr)
{
char ch;
*ptr = '-';
*ptr = '_';
}
}
}
/*
* strip to the last '.' separator and keep the rest
* change ':' to '/' within the last component
*/
static void
convert_label_name(char *name)
{
const char *cptr;
char ch;
else
cptr++; /* skip the '.' */
do {
if (ch == ':')
ch = '/';
} while (ch != '\0');
}
/*
* add a value property
*/
static int
{
int err;
union {
float u_f;
} val_buf;
else
return (err);
}
static int
{
int index;
return (index);
}
return (-1);
}
/*
* look up function to convert led status into string
*/
static int
{
int i;
for (i = 0; i < lim; i++) {
return (PICL_SUCCESS);
}
}
*string = "";
return (PICL_PROPVALUNAVAILABLE);
}
static int
{
int i;
for (i = 0; i < lim; i++) {
return (PICL_SUCCESS);
}
}
*string = "";
return (PICL_PROPVALUNAVAILABLE);
}
/*
* function to read volatile data associated with a PICL property handle
*/
static int
{
int index;
float float_data;
int cmd;
int err;
int envmon_fd;
const char *cptr;
if (index < 0)
return (PICL_INVALIDHANDLE);
if (envmon_fd < 0)
return (PICL_NOTREADABLE);
/*
* read environmental data according to type
*/
switch (fru_type) {
case ENVMON_VOLT_SENS:
/*FALLTHROUGH*/
case ENVMON_AMP_SENS:
/*FALLTHROUGH*/
case ENVMON_TEMP_SENS:
&sensor_data);
break;
case ENVMON_VOLT_IND:
/*FALLTHROUGH*/
case ENVMON_AMP_IND:
/*FALLTHROUGH*/
case ENVMON_TEMP_IND:
/*FALLTHROUGH*/
case ENVMON_FAN_IND:
break;
case ENVMON_FAN_SENS:
break;
case ENVMON_LED_IND:
break;
case ENVMON_KEY_SWITCH:
break;
default:
err = PICL_FAILURE;
break;
}
if (err != PICL_SUCCESS) {
/*
* PICL_INVALIDHANDLE is used internally, but it upsets
* prtpicl; change it to PICL_PROPVALUNAVAILABLE
*/
if (err == PICL_INVALIDHANDLE)
return (err);
}
/*
* convert data and copy out
*/
switch (fru_type) {
case ENVMON_VOLT_SENS:
/*FALLTHROUGH*/
case ENVMON_AMP_SENS:
break;
case ENVMON_TEMP_SENS:
/*FALLTHROUGH*/
case ENVMON_FAN_SENS:
break;
case ENVMON_VOLT_IND:
/*FALLTHROUGH*/
case ENVMON_AMP_IND:
/*FALLTHROUGH*/
case ENVMON_TEMP_IND:
/*FALLTHROUGH*/
case ENVMON_FAN_IND:
break;
case ENVMON_LED_IND:
if (err != PICL_SUCCESS)
return (err);
break;
case ENVMON_KEY_SWITCH:
if (err != PICL_SUCCESS)
return (err);
break;
default:
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
static int
{
int index;
int err;
int envmon_fd;
if (index < 0)
return (PICL_INVALIDHANDLE);
if (fru_type != ENVMON_LED_IND)
return (PICL_INVALIDARG);
return (PICL_PERMDENIED);
/* see if the requested state is recognized */
else
return (PICL_INVALIDARG);
if (envmon_fd < 0)
return (PICL_FAILURE);
if (err < 0)
return (PICL_FAILURE);
return (PICL_SUCCESS);
}
/*
* if colour information is not supplied by the service processor,
* try to determine led colour from the handle name.
*/
static void
{
if ((*colour_p < ENVMON_LED_CLR_NONE) ||
(*colour_p > ENVMON_LED_CLR_RED))
return;
}
cptr++; /* step over '.' */
else
}
/*
* Add nodes for environmental devices of type fru_type
* below the supplied node.
*/
static int
{
char units[ENVMON_MAXNAMELEN];
char label_name[ENVMON_MAXNAMELEN];
int cmd;
int err;
/*
* catch table is full at start
*/
return (PICL_FAILURE);
do {
/* must store id before reading data as it is then updated */
/*
* read environmental data according to type
*/
switch (fru_type) {
case ENVMON_VOLT_SENS:
/*FALLTHROUGH*/
case ENVMON_AMP_SENS:
/*FALLTHROUGH*/
case ENVMON_TEMP_SENS:
&highs, &sensor_data);
break;
case ENVMON_VOLT_IND:
/*FALLTHROUGH*/
case ENVMON_AMP_IND:
/*FALLTHROUGH*/
case ENVMON_TEMP_IND:
/*FALLTHROUGH*/
case ENVMON_FAN_IND:
&sensor_data);
break;
case ENVMON_FAN_SENS:
break;
case ENVMON_LED_IND:
&colour);
break;
case ENVMON_KEY_SWITCH:
&key_state);
break;
default:
return (PICL_FAILURE);
}
if (err == PICL_INVALIDHANDLE)
continue;
continue;
}
/*
* successfully read environmental data, add to PICL
*/
(void) strlcpy(platform_tree_name,
sizeof (platform_tree_name));
/*
* does this node already exist?
*/
if (err == PICL_SUCCESS) {
/*
* skip over existing node
*/
continue;
}
if (err != PICL_SUCCESS) {
break;
}
if (err != PICL_SUCCESS) {
break;
}
/*
* if any thresholds are defined add a property
*/
if (err != PICL_SUCCESS) {
break;
}
}
if (err != PICL_SUCCESS) {
break;
}
}
if (err != PICL_SUCCESS) {
break;
}
}
if (err != PICL_SUCCESS) {
break;
}
}
if (err != PICL_SUCCESS) {
break;
}
}
if (err != PICL_SUCCESS) {
break;
}
}
/*
* if device is a fan sensor, add a speedunit property
*/
if (fru_type == ENVMON_FAN_SENS) {
if (err != PICL_SUCCESS) {
break;
}
}
/*
* If device is a LED indicator and returns a colour,
* add a colour property.
*/
if (fru_type == ENVMON_LED_IND) {
if (colour != ENVMON_LED_CLR_NONE) {
if (err != PICL_SUCCESS) {
break;
}
}
}
/*
* add a label property unless it's a keyswitch
* (keyswitch is labelled from a config file because the
* ALOM interface doesn't supply a name for it)
*/
if (fru_type != ENVMON_KEY_SWITCH) {
if (err != PICL_SUCCESS) {
break;
}
}
/*
* all properties added to this node, add the node below
* the supplied anchor point
*/
if (err != PICL_SUCCESS) {
break;
}
/*
* that node went in OK, advance index
*/
index++;
return (err);
}
static void
{
int i;
int len;
for (i = 0; i < (sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]));
i++) {
break;
}
}
}
static void
{
int i;
int len;
for (i = 0; i < (sizeof (keyposn_lkup) / sizeof (keyposn_lkup[0]));
i++) {
break;
}
}
}
static void
{
int string_size;
int i;
/*
* initialise led colours lookup
*/
for (i = 0; i < lim; i++) {
}
for (i = 0; i < lim; i++) {
colour_lkup[i].size =
}
/*
* initialise condition strings and note longest
*/
string_size = 0;
for (i = 0; i < sizeof (fru_to_size) / sizeof (fru_to_size[0]); i++)
if (fru_to_size[i] == -1)
fru_to_size[i] = string_size;
/*
* initialise led state lookup strings
*/
string_size = 0;
/*
* initialise key position lookup strings
*/
string_size = 0;
}
/*
* The size of outfilename must be PATH_MAX
*/
static int
get_config_file(char *filename)
{
return (0);
}
}
return (0);
}
}
return (0);
}
return (-1);
}
static void
{
int index;
if (index >= 0) {
handle_arr.num--;
/* relocate last entry into hole just created */
}
}
}
/*
* handle PICL FRU ADDED and FRU REMOVED events
*/
/*ARGSUSED*/
static void
void *cookie)
{
char path[MAXPATHLEN];
int retval;
if (retval != 0) {
return;
}
if (retval == PICL_SUCCESS) {
/*
* Open envmon device and interrogate
*/
int envmon_fd;
int fru_type;
return;
}
0) {
return;
}
/*
* SC state change - re-assess platform tree
*/
if (re_create_arrays(envmon_fd) != 0) {
/*
* out of memory - make no changes
*/
return;
}
/*
* dropped memory of volatile prop handles
* so drop the nodes also, then rebuild for
* the newly loaded SC
*/
if (retval != PICL_SUCCESS) {
return;
}
if (retval != PICL_SUCCESS) {
return;
}
if (retval == PICL_SUCCESS)
(void) ptree_destroy_node(envmoninfh);
if (retval != PICL_SUCCESS) {
return;
}
if (retval != PICL_SUCCESS) {
return;
}
}
fru_type++) {
}
}
if (retval != 0) {
return;
}
if (retval == PICL_SUCCESS) {
if (retval != PICL_SUCCESS) {
/* no Devices table, nothing to do */
return;
}
/*
* follow all reference properties in the second
* column of the table and delete the referenced node
*/
sizeof (tblh));
if (retval != PICL_SUCCESS) {
/*
* can't get value of table property
*/
return;
}
/* get first col, first row */
if (retval != PICL_SUCCESS) {
/*
* no rows?
*/
return;
}
/*
* starting at next col, get every entry in the column
*/
retval == PICL_SUCCESS;
/*
* should be a ref prop in our hands,
* get the target node handle
*/
sizeof (nodeh));
if (retval != PICL_SUCCESS) {
continue;
}
/*
* got the referenced node, has it got a
* volatile property to clean up?
*/
while (retval == PICL_SUCCESS) {
if ((retval == PICL_SUCCESS) &&
&proph);
}
/*
* all volatile properties gone, remove node
*/
if (retval == PICL_SUCCESS)
(void) ptree_destroy_node(nodeh);
}
}
}
}
/*
* executed as part of .init when the plugin is dlopen()ed
*/
static void
piclenvmon_register(void)
{
(void) picld_plugin_register(&my_reg_info);
}
/*
* Init entry point of the plugin
* Creates the PICL nodes and properties in the physical and logical aspects.
*/
static void
piclenvmon_init(void)
{
int res;
int envmon_fd;
int fru_type;
/*
* locate and parse config file
*/
if (get_config_file(pathname) < 0)
return;
PICL_SUCCESS)) {
}
/*
* Get platform node
*/
!= PICL_SUCCESS) {
return;
}
/*
* Get service-processor node
*/
return;
/*
* We may have been restarted, make sure we don't leak
*/
if (envmon_device_name != NULL) {
}
return;
/*
* Open envmon device and interrogate for devices it monitors
*/
return;
}
return;
/*
* A set of arrays are used whose bounds are determined by the
* response to get_envmon_limits. Establish these arrays now.
*/
}
if (res != PICL_SUCCESS) {
}
if (res != PICL_SUCCESS) {
}
}
/*
* fini entry point of the plugin
*/
static void
piclenvmon_fini(void)
{
if (envmon_device_name != NULL) {
}
}