dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / picl / plugins / sun4u / envmon / piclenvmon.c
blobbe2009bbcdf0ff75dcda7f39b0059dfba552247d
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * This plugin creates PICL nodes and properties for objects handled through
29 * the enhanced LOMV system-processor interface.
31 * All the nodes which may be accessible through the system-processor are
32 * included below the service-processor node in the /platform tree.
33 * This plugin interrogates the system-processor to determine which of
34 * those nodes are actually available. Properties are added to such nodes and
35 * in the case of volatile properties like temperature, a call-back function
36 * is established for on-demand access to the current value.
37 * LEDs for which the system-processor provides write access are associated
38 * with read/write volatile properties.
40 * NOTE:
41 * Depends on PICL devtree plugin.
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <alloca.h>
49 #include <syslog.h>
50 #include <string.h>
51 #include <libintl.h>
52 #include <picl.h>
53 #include <picltree.h>
54 #include <libnvpair.h>
55 #include <errno.h>
56 #include <limits.h>
57 #include <ctype.h>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <sys/obpdefs.h>
61 #include <sys/envmon.h>
62 #include <sys/systeminfo.h>
63 #include <dirent.h>
64 #include <time.h>
65 #include <picldefs.h>
66 #include <picld_pluginutil.h>
67 #include <libdevinfo.h>
68 #include "piclenvmon.h"
70 static void piclenvmon_register(void);
71 static void piclenvmon_init(void);
72 static void piclenvmon_fini(void);
73 static node_el_t *create_node_el(picl_nodehdl_t nodeh);
74 static void delete_node_el(node_el_t *pel);
75 static node_list_t *create_node_list();
76 static void delete_node_list(node_list_t *pnl);
77 static void add_node_to_list(picl_nodehdl_t nodeh, node_list_t *listp);
78 static void get_node_list_by_class(picl_nodehdl_t nodeh,
79 const char *classname, node_list_t *listp);
80 static int get_envmon_limits(int envmon_fd, envmon_sysinfo_t *limits_p);
81 static void create_arrays();
82 static int get_envmon_node(picl_nodehdl_t *envmoninfh);
83 static char *create_envmon_pathname(picl_nodehdl_t envmoninfh);
84 static int get_child_by_name(picl_nodehdl_t nodeh, const char *name,
85 picl_nodehdl_t *childh);
86 static int add_regular_prop(picl_nodehdl_t nodeh, const char *name,
87 int type, int access, int size, const void *valbuf, picl_prophdl_t *prophp);
88 static int add_volatile_prop(picl_nodehdl_t nodeh, const char *name,
89 int type, int access, int size, ptree_vol_rdfunc_t rdfunc,
90 ptree_vol_wrfunc_t wrfunc, picl_prophdl_t *prophp);
91 static int get_sensor_data(int envmon_fd, envmon_handle_t *id, int cmd,
92 envmon_thresholds_t *lows, envmon_thresholds_t *highs, int16_t *value);
93 static int get_indicator_data(int envmon_fd, envmon_handle_t *id, int cmd,
94 int16_t *condition);
95 static int get_fan_data(int envmon_fd, envmon_handle_t *id, int cmd,
96 envmon_thresholds_t *lows, uint16_t *speed, char *units);
97 static int get_led_data(int envmon_fd, envmon_handle_t *id, int cmd,
98 int8_t *state, int8_t *colour);
99 static int get_keyswitch_data(int envmon_fd, envmon_handle_t *id, int cmd,
100 envmon_keysw_pos_t *key_state);
101 static void convert_node_name(char *ptr);
102 static void convert_label_name(char *ptr);
103 static int add_value_prop(picl_nodehdl_t node_hdl, const char *prop_name,
104 int fru_type, int16_t value);
105 static int find_picl_handle(picl_prophdl_t proph);
106 static int lookup_led_status(int8_t state, const char **string);
107 static int lookup_key_posn(envmon_keysw_pos_t pos, const char **string);
108 static int get_config_file(char *filename);
109 static int read_vol_data(ptree_rarg_t *r_arg, void *buf);
110 static int write_led_data(ptree_warg_t *w_arg, const void *buf);
111 static int add_env_nodes(int envmon_fd, uint8_t fru_type,
112 picl_nodehdl_t envmonh);
113 static void fixstate(uint8_t state, const char *string, int *max_len);
114 static void fixkeyposn(envmon_keysw_pos_t keyposn, const char *string,
115 int *max_len);
116 static void setup_strings();
117 static void free_vol_prop(picl_prophdl_t proph);
118 static void envmon_evhandler(const char *ename, const void *earg,
119 size_t size, void *cookie);
120 static int get_serial_num(int envmon_fd, envmon_handle_t *id, int cmd,
121 envmon_chassis_t *chassis);
123 #pragma init(piclenvmon_register)
125 static picld_plugin_reg_t my_reg_info = {
126 PICLD_PLUGIN_VERSION_1,
127 PICLD_PLUGIN_NON_CRITICAL,
128 "SUNW_piclenvmon",
129 piclenvmon_init,
130 piclenvmon_fini
133 static const char str_On[] = "on";
134 static const char str_Off[] = "off";
135 static const char str_Blinking[] = "blinking";
136 static const char str_Flashing[] = "flashing";
137 static const char str_SC[] = "SC";
138 static char *envmon_device_name = NULL;
139 static envmon_sysinfo_t env_limits;
140 static handle_array_t handle_arr;
141 static struct {
142 int size;
143 char *str_colour;
144 } colour_lkup[1 + ENVMON_LED_CLR_RED];
146 static struct {
147 int8_t state;
148 char *str_ledstate;
149 } ledstate_lkup[] = {
150 { ENVMON_LED_OFF },
151 { ENVMON_LED_ON },
152 { ENVMON_LED_BLINKING },
153 { ENVMON_LED_FLASHING }
156 static struct {
157 envmon_keysw_pos_t pos;
158 char *str_keyposn;
159 } keyposn_lkup[] = {
160 { ENVMON_KEYSW_POS_UNKNOWN },
161 { ENVMON_KEYSW_POS_NORMAL },
162 { ENVMON_KEYSW_POS_DIAG },
163 { ENVMON_KEYSW_POS_LOCKED },
164 { ENVMON_KEYSW_POS_OFF }
168 * fru-type to ioctl cmd lookup
170 int fru_to_cmd[] = {
171 ENVMONIOCVOLTSENSOR,
172 ENVMONIOCVOLTIND,
173 ENVMONIOCAMPSENSOR,
174 ENVMONIOCAMPIND,
175 ENVMONIOCTEMPSENSOR,
176 ENVMONIOCTEMPIND,
177 ENVMONIOCFAN,
178 ENVMONIOCFANIND,
179 ENVMONIOCGETLED,
180 ENVMONIOCGETKEYSW,
181 ENVMONIOCCHASSISSERIALNUM
185 * fru-type to PICL CLASS
187 const char *fru_to_class[] = {
188 PICL_CLASS_VOLTAGE_SENSOR,
189 PICL_CLASS_VOLTAGE_INDICATOR,
190 PICL_CLASS_CURRENT_SENSOR,
191 PICL_CLASS_CURRENT_INDICATOR,
192 PICL_CLASS_TEMPERATURE_SENSOR,
193 PICL_CLASS_TEMPERATURE_INDICATOR,
194 PICL_CLASS_FAN,
195 PICL_CLASS_FAN,
196 PICL_CLASS_LED,
197 PICL_CLASS_KEYSWITCH,
198 PICL_CLASS_CHASSIS_SERIAL_NUM
202 * fru-type to PICL PROPERTY for volatile data
204 const char *fru_to_prop[] = {
205 PICL_PROP_VOLTAGE,
206 PICL_PROP_CONDITION,
207 PICL_PROP_CURRENT,
208 PICL_PROP_CONDITION,
209 PICL_PROP_TEMPERATURE,
210 PICL_PROP_CONDITION,
211 PICL_PROP_FAN_SPEED,
212 PICL_PROP_FAN_SPEED_UNIT,
213 PICL_PROP_STATE,
214 PICL_PROP_STATE,
215 PICL_PROP_SERIAL_NUMBER
219 * fru-type to PICL PTYPE
221 int fru_to_ptype[] = {
222 PICL_PTYPE_FLOAT,
223 PICL_PTYPE_CHARSTRING,
224 PICL_PTYPE_FLOAT,
225 PICL_PTYPE_CHARSTRING,
226 PICL_PTYPE_INT,
227 PICL_PTYPE_CHARSTRING,
228 PICL_PTYPE_UNSIGNED_INT,
229 PICL_PTYPE_CHARSTRING,
230 PICL_PTYPE_CHARSTRING,
231 PICL_PTYPE_CHARSTRING,
232 PICL_PTYPE_CHARSTRING
236 * condition strings
238 static char *cond_okay;
239 static char *cond_failed;
242 * fru-type to size of volatile property
243 * the -1's are replaced by the max size of a condition string
245 int fru_to_size[] = {
246 4, -1, 4, -1, 2, -1, 2, -1, -1, -1, -1
249 static node_el_t *
250 create_node_el(picl_nodehdl_t nodeh)
252 node_el_t *ptr = malloc(sizeof (node_el_t));
254 if (ptr != NULL) {
255 ptr->nodeh = nodeh;
256 ptr->next = NULL;
259 return (ptr);
262 static void
263 delete_node_el(node_el_t *pel)
265 free(pel);
268 static node_list_t *
269 create_node_list()
271 node_list_t *ptr = malloc(sizeof (node_list_t));
273 if (ptr != NULL) {
274 ptr->head = NULL;
275 ptr->tail = NULL;
278 return (ptr);
281 static void
282 delete_node_list(node_list_t *pnl)
284 node_el_t *pel;
286 if (pnl == NULL)
287 return;
289 while ((pel = pnl->head) != NULL) {
290 pnl->head = pel->next;
291 delete_node_el(pel);
295 * normally pnl->tail would be to NULL next,
296 * but as it is about to be freed, this step can be skipped.
298 free(pnl);
302 * Get a linking element and add handle to end of chain
304 static void
305 add_node_to_list(picl_nodehdl_t nodeh, node_list_t *listp)
307 node_el_t *pel = create_node_el(nodeh);
309 if (pel != NULL) {
310 if (listp->tail == NULL)
311 listp->head = pel;
312 else
313 listp->tail->next = pel;
315 listp->tail = pel;
320 * Get a list of nodes of the specified classname under nodeh.
321 * Once a node of the specified class is found, its children are not
322 * searched.
324 static void
325 get_node_list_by_class(picl_nodehdl_t nodeh, const char *classname,
326 node_list_t *listp)
328 int err;
329 char clname[PICL_CLASSNAMELEN_MAX+1];
330 picl_nodehdl_t chdh;
333 * go through the children
335 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
336 sizeof (picl_nodehdl_t));
338 while (err == PICL_SUCCESS) {
339 err = ptree_get_propval_by_name(chdh, PICL_PROP_CLASSNAME,
340 clname, strlen(classname) + 1);
342 if ((err == PICL_SUCCESS) && (strcmp(clname, classname) == 0))
343 add_node_to_list(chdh, listp);
344 else
345 get_node_list_by_class(chdh, classname, listp);
347 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
348 sizeof (picl_nodehdl_t));
352 static int
353 get_envmon_limits(int envmon_fd, envmon_sysinfo_t *limits_p)
355 return (ioctl(envmon_fd, ENVMONIOCSYSINFO, limits_p));
358 static int
359 re_create_arrays(int envmon_fd)
361 envmon_sysinfo_t new_limits;
362 int res;
363 int maxnum;
364 uchar_t *fru_types;
365 envmon_handle_t *envhandles;
366 picl_prophdl_t *piclprhdls;
368 res = get_envmon_limits(envmon_fd, &new_limits);
369 if (res != 0)
370 return (res);
372 maxnum = new_limits.maxVoltSens + new_limits.maxVoltInd +
373 new_limits.maxAmpSens + new_limits.maxAmpInd +
374 new_limits.maxTempSens + new_limits.maxTempInd +
375 new_limits.maxFanSens + new_limits.maxFanInd +
376 new_limits.maxLED + N_KEY_SWITCHES;
378 if (maxnum != handle_arr.maxnum) {
380 * space requirements have changed
382 fru_types = calloc(maxnum, sizeof (uchar_t));
383 envhandles = calloc(maxnum, sizeof (envmon_handle_t));
384 piclprhdls = calloc(maxnum, sizeof (picl_prophdl_t));
385 if ((fru_types == NULL) || (envhandles == NULL) ||
386 (piclprhdls == NULL)) {
387 free(fru_types);
388 free(envhandles);
389 free(piclprhdls);
390 return (-1);
392 free(handle_arr.fru_types);
393 handle_arr.fru_types = fru_types;
394 free(handle_arr.envhandles);
395 handle_arr.envhandles = envhandles;
396 free(handle_arr.piclprhdls);
397 handle_arr.piclprhdls = piclprhdls;
398 } else {
399 (void) memset(handle_arr.fru_types, 0,
400 maxnum * sizeof (uchar_t));
401 (void) memset(handle_arr.envhandles, 0,
402 maxnum * sizeof (envmon_handle_t));
403 (void) memset(handle_arr.piclprhdls, 0,
404 maxnum * sizeof (picl_prophdl_t));
407 handle_arr.num = 0;
408 handle_arr.maxnum = maxnum;
409 env_limits = new_limits;
410 return (0);
413 static void
414 create_arrays()
416 int maxnum = env_limits.maxVoltSens + env_limits.maxVoltInd +
417 env_limits.maxAmpSens + env_limits.maxAmpInd +
418 env_limits.maxTempSens + env_limits.maxTempInd +
419 env_limits.maxFanSens + env_limits.maxFanInd +
420 env_limits.maxLED + N_KEY_SWITCHES;
421 handle_arr.maxnum = maxnum;
422 handle_arr.num = 0;
423 handle_arr.fru_types = calloc(maxnum, sizeof (uchar_t));
424 handle_arr.envhandles = calloc(maxnum, sizeof (envmon_handle_t));
425 handle_arr.piclprhdls = calloc(maxnum, sizeof (picl_prophdl_t));
428 static int
429 get_envmon_node(picl_nodehdl_t *envmoninfh)
431 int err = PICL_SUCCESS;
432 node_list_t *listp;
434 listp = create_node_list();
436 if ((err = ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM,
437 envmoninfh)) != PICL_SUCCESS) {
438 syslog(LOG_ERR, EM_MISSING_NODE,
439 PICL_NODE_ROOT PICL_NODE_PLATFORM);
440 return (err); /* no /platform ! */
443 get_node_list_by_class(*envmoninfh, PICL_CLASS_SERVICE_PROCESSOR,
444 listp);
446 if (listp->head == NULL) {
447 *envmoninfh = 0;
448 syslog(LOG_ERR, EM_MISSING_NODE, PICL_CLASS_SERVICE_PROCESSOR);
449 err = PICL_NODENOTFOUND;
450 } else {
451 *envmoninfh = listp->head->nodeh;
454 delete_node_list(listp);
455 return (err);
458 static char *
459 create_envmon_pathname(picl_nodehdl_t envmoninfh)
461 char *ptr;
462 char namebuf[PATH_MAX];
463 size_t len;
464 DIR *dirp;
465 struct dirent *dp;
466 struct stat statbuf;
468 /* prefix devfs-path name with /devices */
469 (void) strlcpy(namebuf, "/devices", PATH_MAX);
472 * append devfs-path property
474 len = strlen(namebuf);
475 if (ptree_get_propval_by_name(envmoninfh, PICL_PROP_DEVFS_PATH,
476 namebuf + len, sizeof (namebuf) - len) != PICL_SUCCESS) {
477 syslog(LOG_ERR, EM_SC_NODE_INCOMPLETE);
478 return (NULL);
481 /* locate final component of name */
482 ptr = strrchr(namebuf, '/');
483 if (ptr == NULL)
484 return (NULL);
485 *ptr = '\0'; /* terminate at end of directory path */
486 len = strlen(ptr + 1); /* length of terminal name */
487 dirp = opendir(namebuf);
488 if (dirp == NULL) {
489 syslog(LOG_ERR, EM_SC_NODE_MISSING);
490 return (NULL);
492 *ptr++ = '/'; /* restore '/' and advance to final name */
494 while ((dp = readdir(dirp)) != NULL) {
496 * look for a name which starts with the string at *ptr
498 if (strlen(dp->d_name) < len)
499 continue; /* skip short names */
500 if (strncmp(dp->d_name, ptr, len) == 0) {
502 * Got a match, restore full pathname and stat the
503 * entry. Reject if not a char device
505 (void) strlcpy(ptr, dp->d_name,
506 sizeof (namebuf) - (ptr - namebuf));
507 if (stat(namebuf, &statbuf) < 0)
508 continue; /* reject if can't stat it */
509 if (!S_ISCHR(statbuf.st_mode))
510 continue; /* not a character device */
512 * go with this entry
514 (void) closedir(dirp);
515 return (strdup(namebuf));
518 syslog(LOG_ERR, EM_SC_NODE_MISSING);
519 (void) closedir(dirp);
520 return (NULL);
524 * look for named node as child of supplied handle
526 static int
527 get_child_by_name(picl_nodehdl_t nodeh, const char *name,
528 picl_nodehdl_t *childh)
530 int err;
531 char node_name[ENVMON_MAXNAMELEN];
533 if (strlen(name) >= ENVMON_MAXNAMELEN)
534 return (PICL_NODENOTFOUND);
535 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, childh,
536 sizeof (*childh));
537 while (err == PICL_SUCCESS) {
538 err = ptree_get_propval_by_name(*childh, PICL_PROP_NAME,
539 node_name, sizeof (node_name));
540 if ((err == PICL_SUCCESS) &&
541 (strncmp(name, node_name, ENVMON_MAXNAMELEN) == 0))
542 return (PICL_SUCCESS);
543 err = ptree_get_propval_by_name(*childh, PICL_PROP_PEER,
544 childh, sizeof (*childh));
546 return (err);
550 * Create and add the specified regular property
552 static int
553 add_regular_prop(picl_nodehdl_t nodeh, const char *name, int type, int access,
554 int size, const void *valbuf, picl_prophdl_t *prophp)
556 int err;
557 ptree_propinfo_t propinfo;
558 picl_prophdl_t proph;
560 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
561 type, access, size, (char *)name, NULL, NULL);
562 if (err != PICL_SUCCESS)
563 return (err);
565 err = ptree_create_and_add_prop(nodeh, &propinfo, (void *)valbuf,
566 &proph);
567 if (err == PICL_SUCCESS && prophp)
568 *prophp = proph;
569 return (err);
574 * Create and add the specified volatile property
576 static int
577 add_volatile_prop(picl_nodehdl_t nodeh, const char *name, int type, int access,
578 int size, ptree_vol_rdfunc_t rdfunc, ptree_vol_wrfunc_t wrfunc,
579 picl_prophdl_t *prophp)
581 int err;
582 ptree_propinfo_t propinfo;
583 picl_prophdl_t proph;
585 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
586 type, (access|PICL_VOLATILE), size, (char *)name, rdfunc, wrfunc);
587 if (err != PICL_SUCCESS)
588 return (err);
590 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph);
591 if (err == PICL_SUCCESS && prophp)
592 *prophp = proph;
593 return (err);
597 * There are 5 different structures used for reading environmental data
598 * from the service-processor. A different function is used for each one.
599 * Some functions cover several ioctls, so the desired ioctl is part of
600 * the interface. In each case the id parameter is read/write, the
601 * returned value being the next id for this fru type.
605 * Function to read sensor data.
607 static int
608 get_sensor_data(int envmon_fd, envmon_handle_t *id, int cmd,
609 envmon_thresholds_t *lows, envmon_thresholds_t *highs, int16_t *value)
611 int res;
612 envmon_sensor_t data;
614 (void) memset(&data, 0, sizeof (data));
615 data.id = *id;
616 res = ioctl(envmon_fd, cmd, &data);
617 if (res < 0) {
618 return (PICL_NOTREADABLE);
621 *id = data.next_id;
623 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0)
624 return (PICL_INVALIDHANDLE);
627 * it is assumed that threshold data will be available,
628 * even though the current sensor value may be inaccessible
630 if (lows != NULL)
631 *lows = data.lowthresholds;
632 if (highs != NULL)
633 *highs = data.highthresholds;
635 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) {
636 if (value != NULL)
637 *value = ENVMON_VAL_UNAVAILABLE;
638 return (PICL_PROPVALUNAVAILABLE);
640 if (value != NULL)
641 *value = data.value;
642 return (PICL_SUCCESS);
646 * Function to read indicator data.
648 static int
649 get_indicator_data(int envmon_fd, envmon_handle_t *id, int cmd,
650 int16_t *condition)
652 int res;
653 envmon_indicator_t data;
655 data.id = *id;
656 res = ioctl(envmon_fd, cmd, &data);
657 if (res < 0)
658 return (PICL_NOTREADABLE);
659 *id = data.next_id;
660 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0)
661 return (PICL_INVALIDHANDLE);
662 if (condition != NULL)
663 *condition = data.condition;
664 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) {
665 return (PICL_PROPVALUNAVAILABLE);
667 return (PICL_SUCCESS);
671 * Function to read fan data.
673 static int
674 get_fan_data(int envmon_fd, envmon_handle_t *id, int cmd,
675 envmon_thresholds_t *lows, uint16_t *speed, char *units)
677 int res;
678 envmon_fan_t data;
680 data.id = *id;
681 res = ioctl(envmon_fd, cmd, &data);
682 if (res < 0)
683 return (PICL_NOTREADABLE);
684 *id = data.next_id;
685 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0)
686 return (PICL_INVALIDHANDLE);
687 if (lows != NULL)
688 *lows = data.lowthresholds;
689 if (units != NULL)
690 (void) strlcpy(units, data.units, sizeof (data.units));
692 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) {
693 if (speed != NULL)
694 *speed = ENVMON_VAL_UNAVAILABLE;
695 return (PICL_PROPVALUNAVAILABLE);
697 if (speed != NULL)
698 *speed = data.speed;
699 return (PICL_SUCCESS);
703 * Function to read LED data.
705 static int
706 get_led_data(int envmon_fd, envmon_handle_t *id, int cmd,
707 int8_t *state, int8_t *colour)
709 int res;
710 envmon_led_info_t data;
712 data.id = *id;
713 res = ioctl(envmon_fd, cmd, &data);
714 if (res < 0)
715 return (PICL_NOTREADABLE);
716 *id = data.next_id;
717 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0)
718 return (PICL_INVALIDHANDLE);
719 if (colour != NULL)
720 *colour = data.led_color;
721 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) {
722 return (PICL_PROPVALUNAVAILABLE);
724 if (state != NULL)
725 *state = data.led_state;
726 return (PICL_SUCCESS);
730 * Function to read key-switch position
731 * Returns PICL_INVALIDHANDLE if ioctl not supported (or fails)
733 static int
734 get_keyswitch_data(int envmon_fd, envmon_handle_t *id, int cmd,
735 envmon_keysw_pos_t *key_state)
737 int res;
739 if (id->name[0] == '\0') {
740 (void) strlcpy(id->name, KEYSWITCH_NAME, sizeof (id->name));
741 return (PICL_INVALIDHANDLE);
742 } else if (strncmp(id->name, KEYSWITCH_NAME, sizeof (id->name)) != 0) {
743 id->name[0] = '\0';
744 return (PICL_INVALIDHANDLE);
745 } else {
746 res = ioctl(envmon_fd, cmd, key_state);
747 id->name[0] = '\0';
749 if (res < 0)
750 return (PICL_INVALIDHANDLE);
751 return (PICL_SUCCESS);
756 * Function to read the chassis serial number
757 * Returns PICL_INVALIDHANDLE if ioctl not supported (or fails)
759 static int
760 get_serial_num(int envmon_fd, envmon_handle_t *id, int cmd,
761 envmon_chassis_t *chassis)
763 int res;
765 if (id->name[0] == '\0') {
766 (void) strlcpy(id->name, CHASSIS_SERIAL_NUMBER,
767 sizeof (id->name));
768 return (PICL_INVALIDHANDLE);
769 } else if (strncmp(id->name, CHASSIS_SERIAL_NUMBER, sizeof (id->name))
770 != 0) {
771 id->name[0] = '\0';
772 return (PICL_INVALIDHANDLE);
773 } else {
774 res = ioctl(envmon_fd, cmd, chassis);
775 id->name[0] = '\0';
777 if (res < 0)
778 return (PICL_INVALIDHANDLE);
779 return (PICL_SUCCESS);
784 * change to lower case and convert any spaces into hyphens,
785 * and any dots or colons symbols into underscores
787 static void
788 convert_node_name(char *ptr)
790 char ch;
792 for (ch = *ptr; ch != '\0'; ch = *++ptr) {
793 if (isupper(ch)) {
794 *ptr = tolower(ch);
795 } else if (isspace(ch)) {
796 *ptr = '-';
797 } else if ((ch == '.') || (ch == ':')) {
798 *ptr = '_';
804 * strip to the last '.' separator and keep the rest
805 * change ':' to '/' within the last component
807 static void
808 convert_label_name(char *name)
810 const char *cptr;
811 char ch;
813 cptr = strrchr(name, '.');
815 if (cptr == NULL)
816 cptr = name;
817 else
818 cptr++; /* skip the '.' */
820 do {
821 ch = *cptr++;
823 if (ch == ':')
824 ch = '/';
826 *name++ = ch;
827 } while (ch != '\0');
831 * add a value property
833 static int
834 add_value_prop(picl_nodehdl_t node_hdl, const char *prop_name, int fru_type,
835 int16_t value)
837 int err;
838 union {
839 float u_f;
840 int16_t u_i16;
841 } val_buf;
843 if (fru_to_ptype[fru_type] == PICL_PTYPE_FLOAT)
844 val_buf.u_f = (float)((float)value / (float)1000.0);
845 else
846 val_buf.u_i16 = value;
848 err = add_regular_prop(node_hdl, prop_name, fru_to_ptype[fru_type],
849 PICL_READ, fru_to_size[fru_type], &val_buf, NULL);
850 return (err);
853 static int
854 find_picl_handle(picl_prophdl_t proph)
856 int index;
858 for (index = 0; index < handle_arr.num; index++) {
859 if (handle_arr.piclprhdls[index] == proph)
860 return (index);
863 return (-1);
867 * look up function to convert led status into string
869 static int
870 lookup_led_status(int8_t state, const char **string)
872 int i;
873 int lim = sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]);
875 for (i = 0; i < lim; i++) {
876 if (ledstate_lkup[i].state == state) {
877 *string = ledstate_lkup[i].str_ledstate;
878 return (PICL_SUCCESS);
882 *string = "";
883 return (PICL_PROPVALUNAVAILABLE);
886 static int
887 lookup_key_posn(envmon_keysw_pos_t pos, const char **string)
889 int i;
890 int lim = sizeof (keyposn_lkup) / sizeof (keyposn_lkup[0]);
892 for (i = 0; i < lim; i++) {
893 if (keyposn_lkup[i].pos == pos) {
894 *string = keyposn_lkup[i].str_keyposn;
895 return (PICL_SUCCESS);
899 *string = "";
900 return (PICL_PROPVALUNAVAILABLE);
904 * function to read volatile data associated with a PICL property handle
906 static int
907 read_vol_data(ptree_rarg_t *r_arg, void *buf)
909 picl_prophdl_t proph;
910 int index;
911 uint8_t fru_type;
912 envmon_handle_t id;
913 int16_t sensor_data;
914 int8_t led_state;
915 envmon_keysw_pos_t key_posn;
916 envmon_chassis_t chassis;
917 float float_data;
918 int cmd;
919 int err;
920 int envmon_fd;
921 const char *cptr;
923 proph = r_arg->proph;
924 index = find_picl_handle(proph);
925 if (index < 0)
926 return (PICL_INVALIDHANDLE);
927 fru_type = handle_arr.fru_types[index];
928 id = handle_arr.envhandles[index];
929 cmd = fru_to_cmd[fru_type];
930 envmon_fd = open(envmon_device_name, O_RDONLY);
931 if (envmon_fd < 0)
932 return (PICL_NOTREADABLE);
935 * read environmental data according to type
937 switch (fru_type) {
938 case ENVMON_VOLT_SENS:
939 /*FALLTHROUGH*/
940 case ENVMON_AMP_SENS:
941 /*FALLTHROUGH*/
942 case ENVMON_TEMP_SENS:
943 err = get_sensor_data(envmon_fd, &id, cmd, NULL, NULL,
944 &sensor_data);
945 break;
946 case ENVMON_VOLT_IND:
947 /*FALLTHROUGH*/
948 case ENVMON_AMP_IND:
949 /*FALLTHROUGH*/
950 case ENVMON_TEMP_IND:
951 /*FALLTHROUGH*/
952 case ENVMON_FAN_IND:
953 err = get_indicator_data(envmon_fd, &id, cmd, &sensor_data);
954 break;
955 case ENVMON_FAN_SENS:
956 err = get_fan_data(envmon_fd, &id, cmd, NULL,
957 (uint16_t *)&sensor_data, NULL);
958 break;
959 case ENVMON_LED_IND:
960 err = get_led_data(envmon_fd, &id, cmd, &led_state, NULL);
961 break;
962 case ENVMON_KEY_SWITCH:
963 err = get_keyswitch_data(envmon_fd, &id, cmd, &key_posn);
964 break;
965 case ENVMON_CHASSIS:
966 err = get_serial_num(envmon_fd, &id, cmd, &chassis);
967 break;
968 default:
969 err = PICL_FAILURE;
970 break;
973 (void) close(envmon_fd);
974 if (err != PICL_SUCCESS) {
976 * PICL_INVALIDHANDLE is used internally, but it upsets
977 * prtpicl; change it to PICL_PROPVALUNAVAILABLE
979 if (err == PICL_INVALIDHANDLE)
980 err = PICL_PROPVALUNAVAILABLE;
981 return (err);
985 * convert data and copy out
987 switch (fru_type) {
988 case ENVMON_VOLT_SENS:
989 /*FALLTHROUGH*/
990 case ENVMON_AMP_SENS:
991 float_data = (float)((float)sensor_data / (float)1000.0);
992 (void) memcpy(buf, &float_data, sizeof (float_data));
993 break;
995 case ENVMON_TEMP_SENS:
996 /*FALLTHROUGH*/
997 case ENVMON_FAN_SENS:
998 (void) memcpy(buf, &sensor_data, sizeof (sensor_data));
999 break;
1001 case ENVMON_VOLT_IND:
1002 /*FALLTHROUGH*/
1003 case ENVMON_AMP_IND:
1004 /*FALLTHROUGH*/
1005 case ENVMON_TEMP_IND:
1006 /*FALLTHROUGH*/
1007 case ENVMON_FAN_IND:
1008 (void) strlcpy(buf, sensor_data == 0 ? cond_okay : cond_failed,
1009 fru_to_size[fru_type]);
1010 break;
1012 case ENVMON_LED_IND:
1013 err = lookup_led_status(led_state, &cptr);
1014 if (err != PICL_SUCCESS)
1015 return (err);
1016 (void) strlcpy(buf, cptr, fru_to_size[fru_type]);
1017 break;
1019 case ENVMON_KEY_SWITCH:
1020 err = lookup_key_posn(key_posn, &cptr);
1021 if (err != PICL_SUCCESS)
1022 return (err);
1023 (void) strlcpy(buf, cptr, fru_to_size[fru_type]);
1024 break;
1025 case ENVMON_CHASSIS:
1026 (void) memcpy(buf, chassis.serial_number,
1027 sizeof (chassis.serial_number));
1028 break;
1030 default:
1031 return (PICL_FAILURE);
1034 return (PICL_SUCCESS);
1037 static int
1038 write_led_data(ptree_warg_t *w_arg, const void *buf)
1040 picl_prophdl_t proph;
1041 int index;
1042 uint8_t fru_type;
1043 int err;
1044 int envmon_fd;
1045 envmon_led_ctl_t led_ctl;
1047 proph = w_arg->proph;
1048 index = find_picl_handle(proph);
1049 if (index < 0)
1050 return (PICL_INVALIDHANDLE);
1051 fru_type = handle_arr.fru_types[index];
1052 if (fru_type != ENVMON_LED_IND)
1053 return (PICL_INVALIDARG);
1054 if (w_arg->cred.dc_euid != SUPER_USER)
1055 return (PICL_PERMDENIED);
1057 /* see if the requested state is recognized */
1058 if (strcasecmp(str_Off, buf) == 0)
1059 led_ctl.led_state = ENVMON_LED_OFF;
1060 else if (strcasecmp(str_On, buf) == 0)
1061 led_ctl.led_state = ENVMON_LED_ON;
1062 else if (strcasecmp(str_Blinking, buf) == 0)
1063 led_ctl.led_state = ENVMON_LED_BLINKING;
1064 else if (strcasecmp(str_Flashing, buf) == 0)
1065 led_ctl.led_state = ENVMON_LED_FLASHING;
1066 else
1067 return (PICL_INVALIDARG);
1069 envmon_fd = open(envmon_device_name, O_RDWR);
1070 if (envmon_fd < 0)
1071 return (PICL_FAILURE);
1072 led_ctl.id = handle_arr.envhandles[index];
1073 err = ioctl(envmon_fd, ENVMONIOCSETLED, &led_ctl);
1074 (void) close(envmon_fd);
1075 if (err < 0)
1076 return (PICL_FAILURE);
1077 return (PICL_SUCCESS);
1081 * if colour information is not supplied by the service processor,
1082 * try to determine led colour from the handle name.
1084 static void
1085 fix_led_colour(int8_t *colour_p, const char *id)
1087 const char *cptr = strrchr(id, '.');
1089 if ((*colour_p < ENVMON_LED_CLR_NONE) ||
1090 (*colour_p > ENVMON_LED_CLR_RED))
1091 syslog(LOG_ERR, EM_INVALID_COLOR, *colour_p, id);
1092 if (cptr == NULL) {
1093 *colour_p = ENVMON_LED_CLR_NONE;
1094 return;
1097 cptr++; /* step over '.' */
1099 if (strcmp(cptr, LED_ACT) == 0)
1100 *colour_p = ENVMON_LED_CLR_GREEN;
1101 else if (strcmp(cptr, LED_SERVICE) == 0)
1102 *colour_p = ENVMON_LED_CLR_AMBER;
1103 else if (strcmp(cptr, LED_LOCATE) == 0)
1104 *colour_p = ENVMON_LED_CLR_WHITE;
1105 else if (strcmp(cptr, LED_OK2RM) == 0)
1106 *colour_p = ENVMON_LED_CLR_BLUE;
1107 else
1108 *colour_p = ENVMON_LED_CLR_NONE;
1112 * Add nodes for environmental devices of type fru_type
1113 * below the supplied node.
1115 static int
1116 add_env_nodes(int envmon_fd, uint8_t fru_type, picl_nodehdl_t envmonh)
1118 envmon_handle_t id;
1119 envmon_thresholds_t lows;
1120 envmon_thresholds_t highs;
1121 char units[ENVMON_MAXNAMELEN];
1122 char platform_tree_name[ENVMON_MAXNAMELEN];
1123 char label_name[ENVMON_MAXNAMELEN];
1124 int16_t sensor_data;
1125 int8_t led_state;
1126 int8_t colour;
1127 envmon_keysw_pos_t key_state;
1128 envmon_chassis_t chassis_num;
1129 int cmd;
1130 int err;
1131 int index = handle_arr.num;
1132 picl_nodehdl_t node_hdl;
1135 * catch table is full at start
1137 if (index >= handle_arr.maxnum)
1138 return (PICL_FAILURE);
1140 cmd = fru_to_cmd[fru_type];
1141 id.name[0] = '\0';
1143 do {
1144 lows.warning = lows.shutdown = lows.poweroff =
1145 ENVMON_VAL_UNAVAILABLE;
1146 highs.warning = highs.shutdown = highs.poweroff =
1147 ENVMON_VAL_UNAVAILABLE;
1148 handle_arr.fru_types[index] = fru_type;
1149 /* must store id before reading data as it is then updated */
1150 handle_arr.envhandles[index] = id;
1152 * read environmental data according to type
1154 switch (fru_type) {
1155 case ENVMON_VOLT_SENS:
1156 /*FALLTHROUGH*/
1157 case ENVMON_AMP_SENS:
1158 /*FALLTHROUGH*/
1159 case ENVMON_TEMP_SENS:
1160 err = get_sensor_data(envmon_fd, &id, cmd, &lows,
1161 &highs, &sensor_data);
1162 break;
1163 case ENVMON_VOLT_IND:
1164 /*FALLTHROUGH*/
1165 case ENVMON_AMP_IND:
1166 /*FALLTHROUGH*/
1167 case ENVMON_TEMP_IND:
1168 /*FALLTHROUGH*/
1169 case ENVMON_FAN_IND:
1170 err = get_indicator_data(envmon_fd, &id, cmd,
1171 &sensor_data);
1172 break;
1173 case ENVMON_FAN_SENS:
1174 err = get_fan_data(envmon_fd, &id, cmd, &lows,
1175 (uint16_t *)&sensor_data, units);
1176 break;
1177 case ENVMON_LED_IND:
1178 err = get_led_data(envmon_fd, &id, cmd, &led_state,
1179 &colour);
1180 break;
1181 case ENVMON_KEY_SWITCH:
1182 err = get_keyswitch_data(envmon_fd, &id, cmd,
1183 &key_state);
1184 break;
1185 case ENVMON_CHASSIS:
1186 err = get_serial_num(envmon_fd, &id, cmd,
1187 &chassis_num);
1188 break;
1189 default:
1190 return (PICL_FAILURE);
1193 if (err == PICL_INVALIDHANDLE)
1194 continue;
1195 if ((err != PICL_SUCCESS) && (err != PICL_PROPVALUNAVAILABLE)) {
1196 syslog(LOG_ERR, EM_NODE_ACCESS, id, fru_type, err);
1197 continue;
1201 * successfully read environmental data, add to PICL
1203 (void) strlcpy(platform_tree_name,
1204 handle_arr.envhandles[index].name,
1205 sizeof (platform_tree_name));
1207 (void) strlcpy(label_name, platform_tree_name,
1208 ENVMON_MAXNAMELEN);
1209 convert_label_name(label_name);
1210 convert_node_name(platform_tree_name);
1212 * does this node already exist?
1214 err = get_child_by_name(envmonh, platform_tree_name, &node_hdl);
1215 if (err == PICL_SUCCESS) {
1217 * skip over existing node
1219 continue;
1221 err = ptree_create_node(platform_tree_name,
1222 fru_to_class[fru_type], &node_hdl);
1223 if (err != PICL_SUCCESS) {
1224 break;
1226 err = add_volatile_prop(node_hdl, fru_to_prop[fru_type],
1227 fru_to_ptype[fru_type],
1228 PICL_READ | (fru_type == ENVMON_LED_IND ? PICL_WRITE : 0),
1229 fru_to_size[fru_type], read_vol_data,
1230 fru_type == ENVMON_LED_IND ? write_led_data : NULL,
1231 &handle_arr.piclprhdls[index]);
1232 if (err != PICL_SUCCESS) {
1233 break;
1237 * if any thresholds are defined add a property
1239 if (lows.warning != ENVMON_VAL_UNAVAILABLE) {
1240 err = add_value_prop(node_hdl, PICL_PROP_LOW_WARNING,
1241 fru_type, lows.warning);
1242 if (err != PICL_SUCCESS) {
1243 break;
1246 if (lows.shutdown != ENVMON_VAL_UNAVAILABLE) {
1247 err = add_value_prop(node_hdl, PICL_PROP_LOW_SHUTDOWN,
1248 fru_type, lows.shutdown);
1249 if (err != PICL_SUCCESS) {
1250 break;
1253 if (lows.poweroff != ENVMON_VAL_UNAVAILABLE) {
1254 err = add_value_prop(node_hdl, PICL_PROP_LOW_POWER_OFF,
1255 fru_type, lows.poweroff);
1256 if (err != PICL_SUCCESS) {
1257 break;
1260 if (highs.warning != ENVMON_VAL_UNAVAILABLE) {
1261 err = add_value_prop(node_hdl, PICL_PROP_HIGH_WARNING,
1262 fru_type, highs.warning);
1263 if (err != PICL_SUCCESS) {
1264 break;
1267 if (highs.shutdown != ENVMON_VAL_UNAVAILABLE) {
1268 err = add_value_prop(node_hdl, PICL_PROP_HIGH_SHUTDOWN,
1269 fru_type, highs.shutdown);
1270 if (err != PICL_SUCCESS) {
1271 break;
1274 if (highs.poweroff != ENVMON_VAL_UNAVAILABLE) {
1275 err = add_value_prop(node_hdl, PICL_PROP_HIGH_POWER_OFF,
1276 fru_type, highs.poweroff);
1277 if (err != PICL_SUCCESS) {
1278 break;
1283 * if device is a fan sensor, add a speedunit property
1285 if (fru_type == ENVMON_FAN_SENS) {
1286 err = add_regular_prop(node_hdl,
1287 PICL_PROP_FAN_SPEED_UNIT, PICL_PTYPE_CHARSTRING,
1288 PICL_READ, 1 + strlen(units), units, NULL);
1289 if (err != PICL_SUCCESS) {
1290 break;
1294 * If device is a LED indicator and returns a colour,
1295 * add a colour property.
1297 if (fru_type == ENVMON_LED_IND) {
1298 if (colour < 0 || colour == ENVMON_LED_CLR_ANY ||
1299 colour > ENVMON_LED_CLR_RED)
1300 fix_led_colour(&colour,
1301 handle_arr.envhandles[index].name);
1302 if (colour != ENVMON_LED_CLR_NONE) {
1303 err = add_regular_prop(node_hdl,
1304 PICL_PROP_COLOR, PICL_PTYPE_CHARSTRING,
1305 PICL_READ, colour_lkup[colour].size,
1306 colour_lkup[colour].str_colour, NULL);
1307 if (err != PICL_SUCCESS) {
1308 break;
1313 * add a label property unless it's a keyswitch or the
1314 * chassis serial number. keyswitch and chassis serial
1315 * number are labelled from a config file because the
1316 * ALOM interface doesn't supply a name for it)
1318 if ((fru_type != ENVMON_KEY_SWITCH) &&
1319 (fru_type != ENVMON_CHASSIS)) {
1320 err = add_regular_prop(node_hdl, PICL_PROP_LABEL,
1321 PICL_PTYPE_CHARSTRING, PICL_READ,
1322 1 + strlen(label_name), label_name, NULL);
1324 if (err != PICL_SUCCESS) {
1325 break;
1329 * all properties added to this node, add the node below
1330 * the supplied anchor point
1332 err = ptree_add_node(envmonh, node_hdl);
1334 if (err != PICL_SUCCESS) {
1335 break;
1339 * that node went in OK, advance index
1341 index++;
1343 } while ((id.name[0] != '\0') && (index < handle_arr.maxnum));
1345 handle_arr.num = index;
1346 return (err);
1349 static void
1350 fixstate(uint8_t state, const char *string, int *max_len)
1352 int i;
1353 int len;
1355 for (i = 0; i < (sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]));
1356 i++) {
1357 if (ledstate_lkup[i].state == state) {
1358 free(ledstate_lkup[i].str_ledstate);
1359 ledstate_lkup[i].str_ledstate = strdup(string);
1360 len = strlen(string);
1361 if (len >= *max_len)
1362 *max_len = len + 1;
1363 break;
1368 static void
1369 fixkeyposn(envmon_keysw_pos_t keyposn, const char *string, int *max_len)
1371 int i;
1372 int len;
1374 for (i = 0; i < (sizeof (keyposn_lkup) / sizeof (keyposn_lkup[0]));
1375 i++) {
1376 if (keyposn_lkup[i].pos == keyposn) {
1377 free(keyposn_lkup[i].str_keyposn);
1378 keyposn_lkup[i].str_keyposn = strdup(string);
1379 len = strlen(string);
1380 if (len >= *max_len)
1381 *max_len = len + 1;
1382 break;
1387 static void
1388 setup_strings()
1390 int string_size;
1391 int i;
1392 int lim = sizeof (colour_lkup) / sizeof (colour_lkup[0]);
1395 * initialise led colours lookup
1397 for (i = 0; i < lim; i++) {
1398 free(colour_lkup[i].str_colour);
1401 colour_lkup[ENVMON_LED_CLR_ANY].str_colour = strdup(gettext("any"));
1402 colour_lkup[ENVMON_LED_CLR_WHITE].str_colour =
1403 strdup(gettext("white"));
1404 colour_lkup[ENVMON_LED_CLR_BLUE].str_colour = strdup(gettext("blue"));
1405 colour_lkup[ENVMON_LED_CLR_GREEN].str_colour =
1406 strdup(gettext("green"));
1407 colour_lkup[ENVMON_LED_CLR_AMBER].str_colour =
1408 strdup(gettext("amber"));
1409 colour_lkup[ENVMON_LED_CLR_RED].str_colour =
1410 strdup(gettext("red"));
1412 for (i = 0; i < lim; i++) {
1413 if (colour_lkup[i].str_colour != NULL)
1414 colour_lkup[i].size =
1415 1 + strlen(colour_lkup[i].str_colour);
1419 * initialise condition strings and note longest
1421 string_size = 0;
1422 cond_okay = strdup(gettext("okay"));
1423 if (strlen(cond_okay) >= string_size)
1424 string_size = 1 + strlen(cond_okay);
1425 cond_failed = strdup(gettext("failed"));
1426 if (strlen(cond_failed) >= string_size)
1427 string_size = 1 + strlen(cond_failed);
1429 for (i = 0; i < sizeof (fru_to_size) / sizeof (fru_to_size[0]); i++)
1430 if (fru_to_size[i] == -1)
1431 fru_to_size[i] = string_size;
1434 * initialise led state lookup strings
1436 string_size = 0;
1437 fixstate(ENVMON_LED_OFF, gettext("off"), &string_size);
1438 fixstate(ENVMON_LED_ON, gettext("on"), &string_size);
1439 fixstate(ENVMON_LED_BLINKING, gettext("blinking"), &string_size);
1440 fixstate(ENVMON_LED_FLASHING, gettext("flashing"), &string_size);
1441 fru_to_size[ENVMON_LED_IND] = string_size;
1444 * initialise key position lookup strings
1446 string_size = 0;
1447 fixkeyposn(ENVMON_KEYSW_POS_UNKNOWN, gettext("UNKNOWN"), &string_size);
1448 fixkeyposn(ENVMON_KEYSW_POS_NORMAL, gettext("NORMAL"), &string_size);
1449 fixkeyposn(ENVMON_KEYSW_POS_DIAG, gettext("DIAG"), &string_size);
1450 fixkeyposn(ENVMON_KEYSW_POS_LOCKED, gettext("LOCKED"), &string_size);
1451 fixkeyposn(ENVMON_KEYSW_POS_OFF, gettext("STBY"), &string_size);
1452 fru_to_size[ENVMON_KEY_SWITCH] = string_size;
1455 * initialise chassis serial number string
1457 fru_to_size[ENVMON_CHASSIS] = ENVMON_MAXNAMELEN;
1461 * The size of outfilename must be PATH_MAX
1463 static int
1464 get_config_file(char *filename)
1466 char nmbuf[SYS_NMLN];
1467 char pname[PATH_MAX];
1469 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
1470 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
1471 (void) strlcat(pname, ENVMON_CONFFILE_NAME, PATH_MAX);
1472 if (access(pname, R_OK) == 0) {
1473 (void) strlcpy(filename, pname, PATH_MAX);
1474 return (0);
1478 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
1479 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
1480 (void) strlcat(pname, ENVMON_CONFFILE_NAME, PATH_MAX);
1481 if (access(pname, R_OK) == 0) {
1482 (void) strlcpy(filename, pname, PATH_MAX);
1483 return (0);
1487 (void) snprintf(pname, PATH_MAX, "%s/%s",
1488 PICLD_COMMON_PLUGIN_DIR, ENVMON_CONFFILE_NAME);
1490 if (access(pname, R_OK) == 0) {
1491 (void) strlcpy(filename, pname, PATH_MAX);
1492 return (0);
1495 return (-1);
1498 static void
1499 free_vol_prop(picl_prophdl_t proph)
1501 int index;
1503 index = find_picl_handle(proph);
1504 if (index >= 0) {
1505 handle_arr.num--;
1506 if (index != handle_arr.num) {
1507 /* relocate last entry into hole just created */
1508 handle_arr.fru_types[index] =
1509 handle_arr.fru_types[handle_arr.num];
1510 handle_arr.envhandles[index] =
1511 handle_arr.envhandles[handle_arr.num];
1512 handle_arr.piclprhdls[index] =
1513 handle_arr.piclprhdls[handle_arr.num];
1519 * handle PICL FRU ADDED and FRU REMOVED events
1521 /*ARGSUSED*/
1522 static void
1523 envmon_evhandler(const char *ename, const void *earg, size_t size,
1524 void *cookie)
1526 char path[MAXPATHLEN];
1527 picl_nodehdl_t locnodeh;
1528 int retval;
1529 picl_nodehdl_t childh;
1530 picl_nodehdl_t nodeh;
1531 picl_prophdl_t tableh;
1532 picl_prophdl_t tblh;
1533 picl_prophdl_t proph;
1534 ptree_propinfo_t pi;
1536 if (strcmp(ename, PICL_FRU_ADDED) == 0) {
1537 retval = nvlist_lookup_uint64((nvlist_t *)earg,
1538 PICLEVENTARG_PARENTHANDLE, &locnodeh);
1540 if (retval != 0) {
1541 syslog(LOG_ERR, EM_EV_MISSING_ARG,
1542 PICLEVENTARG_PARENTHANDLE);
1543 return;
1545 retval = ptree_get_propval_by_name(locnodeh, PICL_PROP_NAME,
1546 path, sizeof (path));
1547 if (retval == PICL_SUCCESS) {
1549 * Open envmon device and interrogate
1551 int envmon_fd;
1552 int fru_type;
1553 picl_nodehdl_t envmoninfh;
1555 if (get_envmon_node(&envmoninfh) != PICL_SUCCESS) {
1556 syslog(LOG_ERR, EM_SC_NODE_MISSING);
1557 return;
1560 if ((envmon_fd = open(envmon_device_name, O_RDONLY)) <
1561 0) {
1562 syslog(LOG_ERR, EM_SYS_ERR, envmon_device_name,
1563 strerror(errno));
1564 return;
1567 if (strcmp(str_SC, path) == 0) {
1569 * SC state change - re-assess platform tree
1571 if (re_create_arrays(envmon_fd) != 0) {
1573 * out of memory - make no changes
1575 return;
1578 * dropped memory of volatile prop handles
1579 * so drop the nodes also, then rebuild for
1580 * the newly loaded SC
1582 retval = ptree_get_propval_by_name(envmoninfh,
1583 PICL_PROP_PARENT, &nodeh, sizeof (nodeh));
1584 if (retval != PICL_SUCCESS) {
1585 (void) close(envmon_fd);
1586 return;
1588 retval = ptree_get_propval_by_name(envmoninfh,
1589 PICL_PROP_NAME, path, sizeof (path));
1590 if (retval != PICL_SUCCESS) {
1591 (void) close(envmon_fd);
1592 return;
1595 retval = ptree_delete_node(envmoninfh);
1596 if (retval == PICL_SUCCESS)
1597 (void) ptree_destroy_node(envmoninfh);
1598 retval = ptree_create_node(path,
1599 PICL_CLASS_SERVICE_PROCESSOR, &envmoninfh);
1600 if (retval != PICL_SUCCESS) {
1601 (void) close(envmon_fd);
1602 return;
1604 retval = ptree_add_node(nodeh, envmoninfh);
1605 if (retval != PICL_SUCCESS) {
1606 (void) close(envmon_fd);
1607 return;
1611 for (fru_type = 0; fru_type < ENVMONTYPES;
1612 fru_type++) {
1613 (void) add_env_nodes(envmon_fd, fru_type,
1614 envmoninfh);
1617 (void) close(envmon_fd);
1619 } else if (strcmp(ename, PICL_FRU_REMOVED) == 0) {
1620 retval = nvlist_lookup_uint64((nvlist_t *)earg,
1621 PICLEVENTARG_FRUHANDLE, &childh);
1623 if (retval != 0) {
1624 syslog(LOG_ERR, EM_EV_MISSING_ARG,
1625 PICLEVENTARG_FRUHANDLE);
1626 return;
1628 retval = ptree_get_propval_by_name(childh, PICL_PROP_NAME,
1629 path, sizeof (path));
1630 if (retval == PICL_SUCCESS) {
1631 retval = ptree_get_prop_by_name(childh,
1632 PICL_PROP_DEVICES, &tableh);
1634 if (retval != PICL_SUCCESS) {
1635 /* no Devices table, nothing to do */
1636 return;
1640 * follow all reference properties in the second
1641 * column of the table and delete the referenced node
1643 retval = ptree_get_propval(tableh, &tblh,
1644 sizeof (tblh));
1645 if (retval != PICL_SUCCESS) {
1647 * can't get value of table property
1649 return;
1651 /* get first col, first row */
1652 retval = ptree_get_next_by_col(tblh, &tblh);
1653 if (retval != PICL_SUCCESS) {
1655 * no rows?
1657 return;
1660 * starting at next col, get every entry in the column
1662 for (retval = ptree_get_next_by_row(tblh, &tblh);
1663 retval == PICL_SUCCESS;
1664 retval = ptree_get_next_by_col(tblh, &tblh)) {
1666 * should be a ref prop in our hands,
1667 * get the target node handle
1669 retval = ptree_get_propval(tblh, &nodeh,
1670 sizeof (nodeh));
1671 if (retval != PICL_SUCCESS) {
1672 continue;
1675 * got the referenced node, has it got a
1676 * volatile property to clean up?
1678 retval = ptree_get_first_prop(nodeh, &proph);
1679 while (retval == PICL_SUCCESS) {
1680 retval = ptree_get_propinfo(proph, &pi);
1681 if ((retval == PICL_SUCCESS) &&
1682 (pi.piclinfo.accessmode &
1683 PICL_VOLATILE))
1684 free_vol_prop(proph);
1685 retval = ptree_get_next_prop(proph,
1686 &proph);
1689 * all volatile properties gone, remove node
1691 retval = ptree_delete_node(nodeh);
1692 if (retval == PICL_SUCCESS)
1693 (void) ptree_destroy_node(nodeh);
1700 * executed as part of .init when the plugin is dlopen()ed
1702 static void
1703 piclenvmon_register(void)
1705 (void) picld_plugin_register(&my_reg_info);
1709 * Init entry point of the plugin
1710 * Creates the PICL nodes and properties in the physical and logical aspects.
1712 static void
1713 piclenvmon_init(void)
1715 picl_nodehdl_t rooth;
1716 picl_nodehdl_t plfh;
1717 picl_nodehdl_t envmoninfh;
1718 int res;
1719 int envmon_fd;
1720 int fru_type;
1721 char pathname[PATH_MAX];
1724 * locate and parse config file
1726 if (get_config_file(pathname) < 0)
1727 return;
1729 if ((ptree_get_root(&rooth) != PICL_SUCCESS) ||
1730 (picld_pluginutil_parse_config_file(rooth, pathname) !=
1731 PICL_SUCCESS)) {
1732 syslog(LOG_ERR, EM_INIT_FAILED);
1736 * Get platform node
1738 if (ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM, &plfh)
1739 != PICL_SUCCESS) {
1740 syslog(LOG_ERR, EM_MISSING_NODE, PICL_NODE_PLATFORM);
1741 syslog(LOG_ERR, EM_INIT_FAILED);
1742 return;
1746 * Get service-processor node
1748 if (get_envmon_node(&envmoninfh) != PICL_SUCCESS)
1749 return;
1752 * We may have been restarted, make sure we don't leak
1754 if (envmon_device_name != NULL) {
1755 free(envmon_device_name);
1758 if ((envmon_device_name = create_envmon_pathname(envmoninfh)) == NULL)
1759 return;
1762 * Open envmon device and interrogate for devices it monitors
1764 if ((envmon_fd = open(envmon_device_name, O_RDONLY)) < 0) {
1765 syslog(LOG_ERR, EM_SYS_ERR, envmon_device_name,
1766 strerror(errno));
1767 return;
1770 if (get_envmon_limits(envmon_fd, &env_limits) < 0)
1771 return;
1774 * A set of arrays are used whose bounds are determined by the
1775 * response to get_envmon_limits. Establish these arrays now.
1777 create_arrays();
1778 setup_strings();
1780 for (fru_type = 0; fru_type < ENVMONTYPES; fru_type++) {
1781 (void) add_env_nodes(envmon_fd, fru_type, envmoninfh);
1784 (void) close(envmon_fd);
1786 res = ptree_register_handler(PICL_FRU_ADDED, envmon_evhandler, NULL);
1787 if (res != PICL_SUCCESS) {
1788 syslog(LOG_ERR, EM_EVREG_FAILED, res);
1790 res = ptree_register_handler(PICL_FRU_REMOVED, envmon_evhandler, NULL);
1791 if (res != PICL_SUCCESS) {
1792 syslog(LOG_ERR, EM_EVREG_FAILED, res);
1797 * fini entry point of the plugin
1799 static void
1800 piclenvmon_fini(void)
1802 if (envmon_device_name != NULL) {
1803 free(envmon_device_name);
1804 envmon_device_name = NULL;
1806 (void) ptree_unregister_handler(PICL_FRU_ADDED,
1807 envmon_evhandler, NULL);
1808 (void) ptree_unregister_handler(PICL_FRU_REMOVED,
1809 envmon_evhandler, NULL);