1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * This plugin creates PICL nodes and properties for objects handled through
31 * the enhanced LOMV system-processor interface.
32 *
33 * All the nodes which may be accessible through the system-processor are
34 * included below the service-processor node in the /platform tree.
35 * This plugin interrogates the system-processor to determine which of
36 * those nodes are actually available. Properties are added to such nodes and
37 * in the case of volatile properties like temperature, a call-back function
38 * is established for on-demand access to the current value.
39 * LEDs for which the system-processor provides write access are associated
40 * with read/write volatile properties.
41 *
42 * NOTE:
43 * Depends on PICL devtree plugin.
44 */
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50 #include <alloca.h>
51 #include <syslog.h>
52 #include <string.h>
53 #include <libintl.h>
54 #include <picl.h>
55 #include <picltree.h>
56 #include <libnvpair.h>
57 #include <errno.h>
58 #include <limits.h>
59 #include <ctype.h>
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 #include <sys/obpdefs.h>
63 #include <sys/envmon.h>
64 #include <sys/systeminfo.h>
65 #include <dirent.h>
66 #include <time.h>
67 #include <picldefs.h>
68 #include <picld_pluginutil.h>
69 #include <libdevinfo.h>
70 #include "piclenvmon.h"
71
72 static void piclenvmon_register(void);
73 static void piclenvmon_init(void);
74 static void piclenvmon_fini(void);
75 static node_el_t *create_node_el(picl_nodehdl_t nodeh);
76 static void delete_node_el(node_el_t *pel);
77 static node_list_t *create_node_list();
78 static void delete_node_list(node_list_t *pnl);
79 static void add_node_to_list(picl_nodehdl_t nodeh, node_list_t *listp);
80 static void get_node_list_by_class(picl_nodehdl_t nodeh,
81 const char *classname, node_list_t *listp);
82 static int get_envmon_limits(int envmon_fd, envmon_sysinfo_t *limits_p);
83 static void create_arrays();
84 static int get_envmon_node(picl_nodehdl_t *envmoninfh);
85 static char *create_envmon_pathname(picl_nodehdl_t envmoninfh);
86 static int get_child_by_name(picl_nodehdl_t nodeh, const char *name,
87 picl_nodehdl_t *childh);
88 static int add_regular_prop(picl_nodehdl_t nodeh, const char *name,
89 int type, int access, int size, const void *valbuf, picl_prophdl_t *prophp);
90 static int add_volatile_prop(picl_nodehdl_t nodeh, const char *name,
91 int type, int access, int size, ptree_vol_rdfunc_t rdfunc,
92 ptree_vol_wrfunc_t wrfunc, picl_prophdl_t *prophp);
93 static int get_sensor_data(int envmon_fd, envmon_handle_t *id, int cmd,
94 envmon_thresholds_t *lows, envmon_thresholds_t *highs, int16_t *value);
95 static int get_indicator_data(int envmon_fd, envmon_handle_t *id, int cmd,
96 int16_t *condition);
97 static int get_fan_data(int envmon_fd, envmon_handle_t *id, int cmd,
98 envmon_thresholds_t *lows, uint16_t *speed, char *units);
99 static int get_led_data(int envmon_fd, envmon_handle_t *id, int cmd,
100 int8_t *state, int8_t *colour);
101 static int get_keyswitch_data(int envmon_fd, envmon_handle_t *id, int cmd,
102 envmon_keysw_pos_t *key_state);
103 static void convert_node_name(char *ptr);
104 static void convert_label_name(char *ptr);
105 static int add_value_prop(picl_nodehdl_t node_hdl, const char *prop_name,
106 int fru_type, int16_t value);
107 static int find_picl_handle(picl_prophdl_t proph);
108 static int lookup_led_status(int8_t state, const char **string);
109 static int lookup_key_posn(envmon_keysw_pos_t pos, const char **string);
110 static int get_config_file(char *filename);
111 static int read_vol_data(ptree_rarg_t *r_arg, void *buf);
112 static int write_led_data(ptree_warg_t *w_arg, const void *buf);
113 static int add_env_nodes(int envmon_fd, uint8_t fru_type,
114 picl_nodehdl_t envmonh);
115 static void fixstate(uint8_t state, const char *string, int *max_len);
116 static void fixkeyposn(envmon_keysw_pos_t keyposn, const char *string,
117 int *max_len);
118 static void setup_strings();
119 static void free_vol_prop(picl_prophdl_t proph);
120 static void envmon_evhandler(const char *ename, const void *earg,
121 size_t size, void *cookie);
122 static int get_serial_num(int envmon_fd, envmon_handle_t *id, int cmd,
123 envmon_chassis_t *chassis);
124
125 #pragma init(piclenvmon_register)
126
127 static picld_plugin_reg_t my_reg_info = {
128 PICLD_PLUGIN_VERSION_1,
129 PICLD_PLUGIN_NON_CRITICAL,
130 "SUNW_piclenvmon",
131 piclenvmon_init,
132 piclenvmon_fini
133 };
134
135 static const char str_On[] = "on";
136 static const char str_Off[] = "off";
137 static const char str_Blinking[] = "blinking";
138 static const char str_Flashing[] = "flashing";
139 static const char str_SC[] = "SC";
140 static char *envmon_device_name = NULL;
141 static envmon_sysinfo_t env_limits;
142 static handle_array_t handle_arr;
143 static struct {
144 int size;
145 char *str_colour;
146 } colour_lkup[1 + ENVMON_LED_CLR_RED];
147
148 static struct {
149 int8_t state;
150 char *str_ledstate;
151 } ledstate_lkup[] = {
152 { ENVMON_LED_OFF },
153 { ENVMON_LED_ON },
154 { ENVMON_LED_BLINKING },
155 { ENVMON_LED_FLASHING }
156 };
157
158 static struct {
159 envmon_keysw_pos_t pos;
160 char *str_keyposn;
161 } keyposn_lkup[] = {
162 { ENVMON_KEYSW_POS_UNKNOWN },
163 { ENVMON_KEYSW_POS_NORMAL },
164 { ENVMON_KEYSW_POS_DIAG },
165 { ENVMON_KEYSW_POS_LOCKED },
166 { ENVMON_KEYSW_POS_OFF }
167 };
168
169 /*
170 * fru-type to ioctl cmd lookup
171 */
172 int fru_to_cmd[] = {
173 ENVMONIOCVOLTSENSOR,
174 ENVMONIOCVOLTIND,
175 ENVMONIOCAMPSENSOR,
176 ENVMONIOCAMPIND,
177 ENVMONIOCTEMPSENSOR,
178 ENVMONIOCTEMPIND,
179 ENVMONIOCFAN,
180 ENVMONIOCFANIND,
181 ENVMONIOCGETLED,
182 ENVMONIOCGETKEYSW,
183 ENVMONIOCCHASSISSERIALNUM
184 };
185
186 /*
187 * fru-type to PICL CLASS
188 */
189 const char *fru_to_class[] = {
190 PICL_CLASS_VOLTAGE_SENSOR,
191 PICL_CLASS_VOLTAGE_INDICATOR,
192 PICL_CLASS_CURRENT_SENSOR,
193 PICL_CLASS_CURRENT_INDICATOR,
194 PICL_CLASS_TEMPERATURE_SENSOR,
195 PICL_CLASS_TEMPERATURE_INDICATOR,
196 PICL_CLASS_FAN,
197 PICL_CLASS_FAN,
198 PICL_CLASS_LED,
199 PICL_CLASS_KEYSWITCH,
200 PICL_CLASS_CHASSIS_SERIAL_NUM
201 };
202
203 /*
204 * fru-type to PICL PROPERTY for volatile data
205 */
206 const char *fru_to_prop[] = {
207 PICL_PROP_VOLTAGE,
208 PICL_PROP_CONDITION,
209 PICL_PROP_CURRENT,
210 PICL_PROP_CONDITION,
211 PICL_PROP_TEMPERATURE,
212 PICL_PROP_CONDITION,
213 PICL_PROP_FAN_SPEED,
214 PICL_PROP_FAN_SPEED_UNIT,
215 PICL_PROP_STATE,
216 PICL_PROP_STATE,
217 PICL_PROP_SERIAL_NUMBER
218 };
219
220 /*
221 * fru-type to PICL PTYPE
222 */
223 int fru_to_ptype[] = {
224 PICL_PTYPE_FLOAT,
225 PICL_PTYPE_CHARSTRING,
226 PICL_PTYPE_FLOAT,
227 PICL_PTYPE_CHARSTRING,
228 PICL_PTYPE_INT,
229 PICL_PTYPE_CHARSTRING,
230 PICL_PTYPE_UNSIGNED_INT,
231 PICL_PTYPE_CHARSTRING,
232 PICL_PTYPE_CHARSTRING,
233 PICL_PTYPE_CHARSTRING,
234 PICL_PTYPE_CHARSTRING
235 };
236
237 /*
238 * condition strings
239 */
240 static char *cond_okay;
241 static char *cond_failed;
242
243 /*
244 * fru-type to size of volatile property
245 * the -1's are replaced by the max size of a condition string
246 */
247 int fru_to_size[] = {
248 4, -1, 4, -1, 2, -1, 2, -1, -1, -1, -1
249 };
250
251 static node_el_t *
create_node_el(picl_nodehdl_t nodeh)252 create_node_el(picl_nodehdl_t nodeh)
253 {
254 node_el_t *ptr = malloc(sizeof (node_el_t));
255
256 if (ptr != NULL) {
257 ptr->nodeh = nodeh;
258 ptr->next = NULL;
259 }
260
261 return (ptr);
262 }
263
264 static void
delete_node_el(node_el_t * pel)265 delete_node_el(node_el_t *pel)
266 {
267 free(pel);
268 }
269
270 static node_list_t *
create_node_list()271 create_node_list()
272 {
273 node_list_t *ptr = malloc(sizeof (node_list_t));
274
275 if (ptr != NULL) {
276 ptr->head = NULL;
277 ptr->tail = NULL;
278 }
279
280 return (ptr);
281 }
282
283 static void
delete_node_list(node_list_t * pnl)284 delete_node_list(node_list_t *pnl)
285 {
286 node_el_t *pel;
287
288 if (pnl == NULL)
289 return;
290
291 while ((pel = pnl->head) != NULL) {
292 pnl->head = pel->next;
293 delete_node_el(pel);
294 }
295
296 /*
297 * normally pnl->tail would be to NULL next,
298 * but as it is about to be freed, this step can be skipped.
299 */
300 free(pnl);
301 }
302
303 /*
304 * Get a linking element and add handle to end of chain
305 */
306 static void
add_node_to_list(picl_nodehdl_t nodeh,node_list_t * listp)307 add_node_to_list(picl_nodehdl_t nodeh, node_list_t *listp)
308 {
309 node_el_t *pel = create_node_el(nodeh);
310
311 if (pel != NULL) {
312 if (listp->tail == NULL)
313 listp->head = pel;
314 else
315 listp->tail->next = pel;
316
317 listp->tail = pel;
318 }
319 }
320
321 /*
322 * Get a list of nodes of the specified classname under nodeh.
323 * Once a node of the specified class is found, its children are not
324 * searched.
325 */
326 static void
get_node_list_by_class(picl_nodehdl_t nodeh,const char * classname,node_list_t * listp)327 get_node_list_by_class(picl_nodehdl_t nodeh, const char *classname,
328 node_list_t *listp)
329 {
330 int err;
331 char clname[PICL_CLASSNAMELEN_MAX+1];
332 picl_nodehdl_t chdh;
333
334 /*
335 * go through the children
336 */
337 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
338 sizeof (picl_nodehdl_t));
339
340 while (err == PICL_SUCCESS) {
341 err = ptree_get_propval_by_name(chdh, PICL_PROP_CLASSNAME,
342 clname, strlen(classname) + 1);
343
344 if ((err == PICL_SUCCESS) && (strcmp(clname, classname) == 0))
345 add_node_to_list(chdh, listp);
346 else
347 get_node_list_by_class(chdh, classname, listp);
348
349 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
350 sizeof (picl_nodehdl_t));
351 }
352 }
353
354 static int
get_envmon_limits(int envmon_fd,envmon_sysinfo_t * limits_p)355 get_envmon_limits(int envmon_fd, envmon_sysinfo_t *limits_p)
356 {
357 return (ioctl(envmon_fd, ENVMONIOCSYSINFO, limits_p));
358 }
359
360 static int
re_create_arrays(int envmon_fd)361 re_create_arrays(int envmon_fd)
362 {
363 envmon_sysinfo_t new_limits;
364 int res;
365 int maxnum;
366 uchar_t *fru_types;
367 envmon_handle_t *envhandles;
368 picl_prophdl_t *piclprhdls;
369
370 res = get_envmon_limits(envmon_fd, &new_limits);
371 if (res != 0)
372 return (res);
373
374 maxnum = new_limits.maxVoltSens + new_limits.maxVoltInd +
375 new_limits.maxAmpSens + new_limits.maxAmpInd +
376 new_limits.maxTempSens + new_limits.maxTempInd +
377 new_limits.maxFanSens + new_limits.maxFanInd +
378 new_limits.maxLED + N_KEY_SWITCHES;
379
380 if (maxnum != handle_arr.maxnum) {
381 /*
382 * space requirements have changed
383 */
384 fru_types = calloc(maxnum, sizeof (uchar_t));
385 envhandles = calloc(maxnum, sizeof (envmon_handle_t));
386 piclprhdls = calloc(maxnum, sizeof (picl_prophdl_t));
387 if ((fru_types == NULL) || (envhandles == NULL) ||
388 (piclprhdls == NULL)) {
389 free(fru_types);
390 free(envhandles);
391 free(piclprhdls);
392 return (-1);
393 }
394 free(handle_arr.fru_types);
395 handle_arr.fru_types = fru_types;
396 free(handle_arr.envhandles);
397 handle_arr.envhandles = envhandles;
398 free(handle_arr.piclprhdls);
399 handle_arr.piclprhdls = piclprhdls;
400 } else {
401 (void) memset(handle_arr.fru_types, 0,
402 maxnum * sizeof (uchar_t));
403 (void) memset(handle_arr.envhandles, 0,
404 maxnum * sizeof (envmon_handle_t));
405 (void) memset(handle_arr.piclprhdls, 0,
406 maxnum * sizeof (picl_prophdl_t));
407 }
408
409 handle_arr.num = 0;
410 handle_arr.maxnum = maxnum;
411 env_limits = new_limits;
412 return (0);
413 }
414
415 static void
create_arrays()416 create_arrays()
417 {
418 int maxnum = env_limits.maxVoltSens + env_limits.maxVoltInd +
419 env_limits.maxAmpSens + env_limits.maxAmpInd +
420 env_limits.maxTempSens + env_limits.maxTempInd +
421 env_limits.maxFanSens + env_limits.maxFanInd +
422 env_limits.maxLED + N_KEY_SWITCHES;
423 handle_arr.maxnum = maxnum;
424 handle_arr.num = 0;
425 handle_arr.fru_types = calloc(maxnum, sizeof (uchar_t));
426 handle_arr.envhandles = calloc(maxnum, sizeof (envmon_handle_t));
427 handle_arr.piclprhdls = calloc(maxnum, sizeof (picl_prophdl_t));
428 }
429
430 static int
get_envmon_node(picl_nodehdl_t * envmoninfh)431 get_envmon_node(picl_nodehdl_t *envmoninfh)
432 {
433 int err = PICL_SUCCESS;
434 node_list_t *listp;
435
436 listp = create_node_list();
437
438 if ((err = ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM,
439 envmoninfh)) != PICL_SUCCESS) {
440 syslog(LOG_ERR, EM_MISSING_NODE,
441 PICL_NODE_ROOT PICL_NODE_PLATFORM);
442 return (err); /* no /platform ! */
443 }
444
445 get_node_list_by_class(*envmoninfh, PICL_CLASS_SERVICE_PROCESSOR,
446 listp);
447
448 if (listp->head == NULL) {
449 *envmoninfh = 0;
450 syslog(LOG_ERR, EM_MISSING_NODE, PICL_CLASS_SERVICE_PROCESSOR);
451 err = PICL_NODENOTFOUND;
452 } else {
453 *envmoninfh = listp->head->nodeh;
454 }
455
456 delete_node_list(listp);
457 return (err);
458 }
459
460 static char *
create_envmon_pathname(picl_nodehdl_t envmoninfh)461 create_envmon_pathname(picl_nodehdl_t envmoninfh)
462 {
463 char *ptr;
464 char namebuf[PATH_MAX];
465 size_t len;
466 DIR *dirp;
467 struct dirent *dp;
468 struct stat statbuf;
469
470 /* prefix devfs-path name with /devices */
471 (void) strlcpy(namebuf, "/devices", PATH_MAX);
472
473 /*
474 * append devfs-path property
475 */
476 len = strlen(namebuf);
477 if (ptree_get_propval_by_name(envmoninfh, PICL_PROP_DEVFS_PATH,
478 namebuf + len, sizeof (namebuf) - len) != PICL_SUCCESS) {
479 syslog(LOG_ERR, EM_SC_NODE_INCOMPLETE);
480 return (NULL);
481 }
482
483 /* locate final component of name */
484 ptr = strrchr(namebuf, '/');
485 if (ptr == NULL)
486 return (NULL);
487 *ptr = '\0'; /* terminate at end of directory path */
488 len = strlen(ptr + 1); /* length of terminal name */
489 dirp = opendir(namebuf);
490 if (dirp == NULL) {
491 syslog(LOG_ERR, EM_SC_NODE_MISSING);
492 return (NULL);
493 }
494 *ptr++ = '/'; /* restore '/' and advance to final name */
495
496 while ((dp = readdir(dirp)) != NULL) {
497 /*
498 * look for a name which starts with the string at *ptr
499 */
500 if (strlen(dp->d_name) < len)
501 continue; /* skip short names */
502 if (strncmp(dp->d_name, ptr, len) == 0) {
503 /*
504 * Got a match, restore full pathname and stat the
505 * entry. Reject if not a char device
506 */
507 (void) strlcpy(ptr, dp->d_name,
508 sizeof (namebuf) - (ptr - namebuf));
509 if (stat(namebuf, &statbuf) < 0)
510 continue; /* reject if can't stat it */
511 if (!S_ISCHR(statbuf.st_mode))
512 continue; /* not a character device */
513 /*
514 * go with this entry
515 */
516 (void) closedir(dirp);
517 return (strdup(namebuf));
518 }
519 }
520 syslog(LOG_ERR, EM_SC_NODE_MISSING);
521 (void) closedir(dirp);
522 return (NULL);
523 }
524
525 /*
526 * look for named node as child of supplied handle
527 */
528 static int
get_child_by_name(picl_nodehdl_t nodeh,const char * name,picl_nodehdl_t * childh)529 get_child_by_name(picl_nodehdl_t nodeh, const char *name,
530 picl_nodehdl_t *childh)
531 {
532 int err;
533 char node_name[ENVMON_MAXNAMELEN];
534
535 if (strlen(name) >= ENVMON_MAXNAMELEN)
536 return (PICL_NODENOTFOUND);
537 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, childh,
538 sizeof (*childh));
539 while (err == PICL_SUCCESS) {
540 err = ptree_get_propval_by_name(*childh, PICL_PROP_NAME,
541 node_name, sizeof (node_name));
542 if ((err == PICL_SUCCESS) &&
543 (strncmp(name, node_name, ENVMON_MAXNAMELEN) == 0))
544 return (PICL_SUCCESS);
545 err = ptree_get_propval_by_name(*childh, PICL_PROP_PEER,
546 childh, sizeof (*childh));
547 }
548 return (err);
549 }
550
551 /*
552 * Create and add the specified regular property
553 */
554 static int
add_regular_prop(picl_nodehdl_t nodeh,const char * name,int type,int access,int size,const void * valbuf,picl_prophdl_t * prophp)555 add_regular_prop(picl_nodehdl_t nodeh, const char *name, int type, int access,
556 int size, const void *valbuf, picl_prophdl_t *prophp)
557 {
558 int err;
559 ptree_propinfo_t propinfo;
560 picl_prophdl_t proph;
561
562 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
563 type, access, size, (char *)name, NULL, NULL);
564 if (err != PICL_SUCCESS)
565 return (err);
566
567 err = ptree_create_and_add_prop(nodeh, &propinfo, (void *)valbuf,
568 &proph);
569 if (err == PICL_SUCCESS && prophp)
570 *prophp = proph;
571 return (err);
572 }
573
574
575 /*
576 * Create and add the specified volatile property
577 */
578 static int
add_volatile_prop(picl_nodehdl_t nodeh,const char * name,int type,int access,int size,ptree_vol_rdfunc_t rdfunc,ptree_vol_wrfunc_t wrfunc,picl_prophdl_t * prophp)579 add_volatile_prop(picl_nodehdl_t nodeh, const char *name, int type, int access,
580 int size, ptree_vol_rdfunc_t rdfunc, ptree_vol_wrfunc_t wrfunc,
581 picl_prophdl_t *prophp)
582 {
583 int err;
584 ptree_propinfo_t propinfo;
585 picl_prophdl_t proph;
586
587 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
588 type, (access|PICL_VOLATILE), size, (char *)name, rdfunc, wrfunc);
589 if (err != PICL_SUCCESS)
590 return (err);
591
592 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph);
593 if (err == PICL_SUCCESS && prophp)
594 *prophp = proph;
595 return (err);
596 }
597
598 /*
599 * There are 5 different structures used for reading environmental data
600 * from the service-processor. A different function is used for each one.
601 * Some functions cover several ioctls, so the desired ioctl is part of
602 * the interface. In each case the id parameter is read/write, the
603 * returned value being the next id for this fru type.
604 */
605
606 /*
607 * Function to read sensor data.
608 */
609 static int
get_sensor_data(int envmon_fd,envmon_handle_t * id,int cmd,envmon_thresholds_t * lows,envmon_thresholds_t * highs,int16_t * value)610 get_sensor_data(int envmon_fd, envmon_handle_t *id, int cmd,
611 envmon_thresholds_t *lows, envmon_thresholds_t *highs, int16_t *value)
612 {
613 int res;
614 envmon_sensor_t data;
615
616 (void) memset(&data, 0, sizeof (data));
617 data.id = *id;
618 res = ioctl(envmon_fd, cmd, &data);
619 if (res < 0) {
620 return (PICL_NOTREADABLE);
621 }
622
623 *id = data.next_id;
624
625 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0)
626 return (PICL_INVALIDHANDLE);
627
628 /*
629 * it is assumed that threshold data will be available,
630 * even though the current sensor value may be inaccessible
631 */
632 if (lows != NULL)
633 *lows = data.lowthresholds;
634 if (highs != NULL)
635 *highs = data.highthresholds;
636
637 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) {
638 if (value != NULL)
639 *value = ENVMON_VAL_UNAVAILABLE;
640 return (PICL_PROPVALUNAVAILABLE);
641 }
642 if (value != NULL)
643 *value = data.value;
644 return (PICL_SUCCESS);
645 }
646
647 /*
648 * Function to read indicator data.
649 */
650 static int
get_indicator_data(int envmon_fd,envmon_handle_t * id,int cmd,int16_t * condition)651 get_indicator_data(int envmon_fd, envmon_handle_t *id, int cmd,
652 int16_t *condition)
653 {
654 int res;
655 envmon_indicator_t data;
656
657 data.id = *id;
658 res = ioctl(envmon_fd, cmd, &data);
659 if (res < 0)
660 return (PICL_NOTREADABLE);
661 *id = data.next_id;
662 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0)
663 return (PICL_INVALIDHANDLE);
664 if (condition != NULL)
665 *condition = data.condition;
666 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) {
667 return (PICL_PROPVALUNAVAILABLE);
668 }
669 return (PICL_SUCCESS);
670 }
671
672 /*
673 * Function to read fan data.
674 */
675 static int
get_fan_data(int envmon_fd,envmon_handle_t * id,int cmd,envmon_thresholds_t * lows,uint16_t * speed,char * units)676 get_fan_data(int envmon_fd, envmon_handle_t *id, int cmd,
677 envmon_thresholds_t *lows, uint16_t *speed, char *units)
678 {
679 int res;
680 envmon_fan_t data;
681
682 data.id = *id;
683 res = ioctl(envmon_fd, cmd, &data);
684 if (res < 0)
685 return (PICL_NOTREADABLE);
686 *id = data.next_id;
687 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0)
688 return (PICL_INVALIDHANDLE);
689 if (lows != NULL)
690 *lows = data.lowthresholds;
691 if (units != NULL)
692 (void) strlcpy(units, data.units, sizeof (data.units));
693
694 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) {
695 if (speed != NULL)
696 *speed = ENVMON_VAL_UNAVAILABLE;
697 return (PICL_PROPVALUNAVAILABLE);
698 }
699 if (speed != NULL)
700 *speed = data.speed;
701 return (PICL_SUCCESS);
702 }
703
704 /*
705 * Function to read LED data.
706 */
707 static int
get_led_data(int envmon_fd,envmon_handle_t * id,int cmd,int8_t * state,int8_t * colour)708 get_led_data(int envmon_fd, envmon_handle_t *id, int cmd,
709 int8_t *state, int8_t *colour)
710 {
711 int res;
712 envmon_led_info_t data;
713
714 data.id = *id;
715 res = ioctl(envmon_fd, cmd, &data);
716 if (res < 0)
717 return (PICL_NOTREADABLE);
718 *id = data.next_id;
719 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0)
720 return (PICL_INVALIDHANDLE);
721 if (colour != NULL)
722 *colour = data.led_color;
723 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) {
724 return (PICL_PROPVALUNAVAILABLE);
725 }
726 if (state != NULL)
727 *state = data.led_state;
728 return (PICL_SUCCESS);
729 }
730
731 /*
732 * Function to read key-switch position
733 * Returns PICL_INVALIDHANDLE if ioctl not supported (or fails)
734 */
735 static int
get_keyswitch_data(int envmon_fd,envmon_handle_t * id,int cmd,envmon_keysw_pos_t * key_state)736 get_keyswitch_data(int envmon_fd, envmon_handle_t *id, int cmd,
737 envmon_keysw_pos_t *key_state)
738 {
739 int res;
740
741 if (id->name[0] == '\0') {
742 (void) strlcpy(id->name, KEYSWITCH_NAME, sizeof (id->name));
743 return (PICL_INVALIDHANDLE);
744 } else if (strncmp(id->name, KEYSWITCH_NAME, sizeof (id->name)) != 0) {
745 id->name[0] = '\0';
746 return (PICL_INVALIDHANDLE);
747 } else {
748 res = ioctl(envmon_fd, cmd, key_state);
749 id->name[0] = '\0';
750
751 if (res < 0)
752 return (PICL_INVALIDHANDLE);
753 return (PICL_SUCCESS);
754 }
755 }
756
757 /*
758 * Function to read the chassis serial number
759 * Returns PICL_INVALIDHANDLE if ioctl not supported (or fails)
760 */
761 static int
get_serial_num(int envmon_fd,envmon_handle_t * id,int cmd,envmon_chassis_t * chassis)762 get_serial_num(int envmon_fd, envmon_handle_t *id, int cmd,
763 envmon_chassis_t *chassis)
764 {
765 int res;
766
767 if (id->name[0] == '\0') {
768 (void) strlcpy(id->name, CHASSIS_SERIAL_NUMBER,
769 sizeof (id->name));
770 return (PICL_INVALIDHANDLE);
771 } else if (strncmp(id->name, CHASSIS_SERIAL_NUMBER, sizeof (id->name))
772 != 0) {
773 id->name[0] = '\0';
774 return (PICL_INVALIDHANDLE);
775 } else {
776 res = ioctl(envmon_fd, cmd, chassis);
777 id->name[0] = '\0';
778
779 if (res < 0)
780 return (PICL_INVALIDHANDLE);
781 return (PICL_SUCCESS);
782 }
783 }
784
785 /*
786 * change to lower case and convert any spaces into hyphens,
787 * and any dots or colons symbols into underscores
788 */
789 static void
convert_node_name(char * ptr)790 convert_node_name(char *ptr)
791 {
792 char ch;
793
794 for (ch = *ptr; ch != '\0'; ch = *++ptr) {
795 if (isupper(ch)) {
796 *ptr = tolower(ch);
797 } else if (isspace(ch)) {
798 *ptr = '-';
799 } else if ((ch == '.') || (ch == ':')) {
800 *ptr = '_';
801 }
802 }
803 }
804
805 /*
806 * strip to the last '.' separator and keep the rest
807 * change ':' to '/' within the last component
808 */
809 static void
convert_label_name(char * name)810 convert_label_name(char *name)
811 {
812 const char *cptr;
813 char ch;
814
815 cptr = strrchr(name, '.');
816
817 if (cptr == NULL)
818 cptr = name;
819 else
820 cptr++; /* skip the '.' */
821
822 do {
823 ch = *cptr++;
824
825 if (ch == ':')
826 ch = '/';
827
828 *name++ = ch;
829 } while (ch != '\0');
830 }
831
832 /*
833 * add a value property
834 */
835 static int
add_value_prop(picl_nodehdl_t node_hdl,const char * prop_name,int fru_type,int16_t value)836 add_value_prop(picl_nodehdl_t node_hdl, const char *prop_name, int fru_type,
837 int16_t value)
838 {
839 int err;
840 union {
841 float u_f;
842 int16_t u_i16;
843 } val_buf;
844
845 if (fru_to_ptype[fru_type] == PICL_PTYPE_FLOAT)
846 val_buf.u_f = (float)((float)value / (float)1000.0);
847 else
848 val_buf.u_i16 = value;
849
850 err = add_regular_prop(node_hdl, prop_name, fru_to_ptype[fru_type],
851 PICL_READ, fru_to_size[fru_type], &val_buf, NULL);
852 return (err);
853 }
854
855 static int
find_picl_handle(picl_prophdl_t proph)856 find_picl_handle(picl_prophdl_t proph)
857 {
858 int index;
859
860 for (index = 0; index < handle_arr.num; index++) {
861 if (handle_arr.piclprhdls[index] == proph)
862 return (index);
863 }
864
865 return (-1);
866 }
867
868 /*
869 * look up function to convert led status into string
870 */
871 static int
lookup_led_status(int8_t state,const char ** string)872 lookup_led_status(int8_t state, const char **string)
873 {
874 int i;
875 int lim = sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]);
876
877 for (i = 0; i < lim; i++) {
878 if (ledstate_lkup[i].state == state) {
879 *string = ledstate_lkup[i].str_ledstate;
880 return (PICL_SUCCESS);
881 }
882 }
883
884 *string = "";
885 return (PICL_PROPVALUNAVAILABLE);
886 }
887
888 static int
lookup_key_posn(envmon_keysw_pos_t pos,const char ** string)889 lookup_key_posn(envmon_keysw_pos_t pos, const char **string)
890 {
891 int i;
892 int lim = sizeof (keyposn_lkup) / sizeof (keyposn_lkup[0]);
893
894 for (i = 0; i < lim; i++) {
895 if (keyposn_lkup[i].pos == pos) {
896 *string = keyposn_lkup[i].str_keyposn;
897 return (PICL_SUCCESS);
898 }
899 }
900
901 *string = "";
902 return (PICL_PROPVALUNAVAILABLE);
903 }
904
905 /*
906 * function to read volatile data associated with a PICL property handle
907 */
908 static int
read_vol_data(ptree_rarg_t * r_arg,void * buf)909 read_vol_data(ptree_rarg_t *r_arg, void *buf)
910 {
911 picl_prophdl_t proph;
912 int index;
913 uint8_t fru_type;
914 envmon_handle_t id;
915 int16_t sensor_data;
916 int8_t led_state;
917 envmon_keysw_pos_t key_posn;
918 envmon_chassis_t chassis;
919 float float_data;
920 int cmd;
921 int err;
922 int envmon_fd;
923 const char *cptr;
924
925 proph = r_arg->proph;
926 index = find_picl_handle(proph);
927 if (index < 0)
928 return (PICL_INVALIDHANDLE);
929 fru_type = handle_arr.fru_types[index];
930 id = handle_arr.envhandles[index];
931 cmd = fru_to_cmd[fru_type];
932 envmon_fd = open(envmon_device_name, O_RDONLY);
933 if (envmon_fd < 0)
934 return (PICL_NOTREADABLE);
935
936 /*
937 * read environmental data according to type
938 */
939 switch (fru_type) {
940 case ENVMON_VOLT_SENS:
941 /*FALLTHROUGH*/
942 case ENVMON_AMP_SENS:
943 /*FALLTHROUGH*/
944 case ENVMON_TEMP_SENS:
945 err = get_sensor_data(envmon_fd, &id, cmd, NULL, NULL,
946 &sensor_data);
947 break;
948 case ENVMON_VOLT_IND:
949 /*FALLTHROUGH*/
950 case ENVMON_AMP_IND:
951 /*FALLTHROUGH*/
952 case ENVMON_TEMP_IND:
953 /*FALLTHROUGH*/
954 case ENVMON_FAN_IND:
955 err = get_indicator_data(envmon_fd, &id, cmd, &sensor_data);
956 break;
957 case ENVMON_FAN_SENS:
958 err = get_fan_data(envmon_fd, &id, cmd, NULL,
959 (uint16_t *)&sensor_data, NULL);
960 break;
961 case ENVMON_LED_IND:
962 err = get_led_data(envmon_fd, &id, cmd, &led_state, NULL);
963 break;
964 case ENVMON_KEY_SWITCH:
965 err = get_keyswitch_data(envmon_fd, &id, cmd, &key_posn);
966 break;
967 case ENVMON_CHASSIS:
968 err = get_serial_num(envmon_fd, &id, cmd, &chassis);
969 break;
970 default:
971 err = PICL_FAILURE;
972 break;
973 }
974
975 (void) close(envmon_fd);
976 if (err != PICL_SUCCESS) {
977 /*
978 * PICL_INVALIDHANDLE is used internally, but it upsets
979 * prtpicl; change it to PICL_PROPVALUNAVAILABLE
980 */
981 if (err == PICL_INVALIDHANDLE)
982 err = PICL_PROPVALUNAVAILABLE;
983 return (err);
984 }
985
986 /*
987 * convert data and copy out
988 */
989 switch (fru_type) {
990 case ENVMON_VOLT_SENS:
991 /*FALLTHROUGH*/
992 case ENVMON_AMP_SENS:
993 float_data = (float)((float)sensor_data / (float)1000.0);
994 (void) memcpy(buf, &float_data, sizeof (float_data));
995 break;
996
997 case ENVMON_TEMP_SENS:
998 /*FALLTHROUGH*/
999 case ENVMON_FAN_SENS:
1000 (void) memcpy(buf, &sensor_data, sizeof (sensor_data));
1001 break;
1002
1003 case ENVMON_VOLT_IND:
1004 /*FALLTHROUGH*/
1005 case ENVMON_AMP_IND:
1006 /*FALLTHROUGH*/
1007 case ENVMON_TEMP_IND:
1008 /*FALLTHROUGH*/
1009 case ENVMON_FAN_IND:
1010 (void) strlcpy(buf, sensor_data == 0 ? cond_okay : cond_failed,
1011 fru_to_size[fru_type]);
1012 break;
1013
1014 case ENVMON_LED_IND:
1015 err = lookup_led_status(led_state, &cptr);
1016 if (err != PICL_SUCCESS)
1017 return (err);
1018 (void) strlcpy(buf, cptr, fru_to_size[fru_type]);
1019 break;
1020
1021 case ENVMON_KEY_SWITCH:
1022 err = lookup_key_posn(key_posn, &cptr);
1023 if (err != PICL_SUCCESS)
1024 return (err);
1025 (void) strlcpy(buf, cptr, fru_to_size[fru_type]);
1026 break;
1027 case ENVMON_CHASSIS:
1028 (void) memcpy(buf, chassis.serial_number,
1029 sizeof (chassis.serial_number));
1030 break;
1031
1032 default:
1033 return (PICL_FAILURE);
1034 }
1035
1036 return (PICL_SUCCESS);
1037 }
1038
1039 static int
write_led_data(ptree_warg_t * w_arg,const void * buf)1040 write_led_data(ptree_warg_t *w_arg, const void *buf)
1041 {
1042 picl_prophdl_t proph;
1043 int index;
1044 uint8_t fru_type;
1045 int err;
1046 int envmon_fd;
1047 envmon_led_ctl_t led_ctl;
1048
1049 proph = w_arg->proph;
1050 index = find_picl_handle(proph);
1051 if (index < 0)
1052 return (PICL_INVALIDHANDLE);
1053 fru_type = handle_arr.fru_types[index];
1054 if (fru_type != ENVMON_LED_IND)
1055 return (PICL_INVALIDARG);
1056 if (w_arg->cred.dc_euid != SUPER_USER)
1057 return (PICL_PERMDENIED);
1058
1059 /* see if the requested state is recognized */
1060 if (strcasecmp(str_Off, buf) == 0)
1061 led_ctl.led_state = ENVMON_LED_OFF;
1062 else if (strcasecmp(str_On, buf) == 0)
1063 led_ctl.led_state = ENVMON_LED_ON;
1064 else if (strcasecmp(str_Blinking, buf) == 0)
1065 led_ctl.led_state = ENVMON_LED_BLINKING;
1066 else if (strcasecmp(str_Flashing, buf) == 0)
1067 led_ctl.led_state = ENVMON_LED_FLASHING;
1068 else
1069 return (PICL_INVALIDARG);
1070
1071 envmon_fd = open(envmon_device_name, O_RDWR);
1072 if (envmon_fd < 0)
1073 return (PICL_FAILURE);
1074 led_ctl.id = handle_arr.envhandles[index];
1075 err = ioctl(envmon_fd, ENVMONIOCSETLED, &led_ctl);
1076 (void) close(envmon_fd);
1077 if (err < 0)
1078 return (PICL_FAILURE);
1079 return (PICL_SUCCESS);
1080 }
1081
1082 /*
1083 * if colour information is not supplied by the service processor,
1084 * try to determine led colour from the handle name.
1085 */
1086 static void
fix_led_colour(int8_t * colour_p,const char * id)1087 fix_led_colour(int8_t *colour_p, const char *id)
1088 {
1089 const char *cptr = strrchr(id, '.');
1090
1091 if ((*colour_p < ENVMON_LED_CLR_NONE) ||
1092 (*colour_p > ENVMON_LED_CLR_RED))
1093 syslog(LOG_ERR, EM_INVALID_COLOR, *colour_p, id);
1094 if (cptr == NULL) {
1095 *colour_p = ENVMON_LED_CLR_NONE;
1096 return;
1097 }
1098
1099 cptr++; /* step over '.' */
1100
1101 if (strcmp(cptr, LED_ACT) == 0)
1102 *colour_p = ENVMON_LED_CLR_GREEN;
1103 else if (strcmp(cptr, LED_SERVICE) == 0)
1104 *colour_p = ENVMON_LED_CLR_AMBER;
1105 else if (strcmp(cptr, LED_LOCATE) == 0)
1106 *colour_p = ENVMON_LED_CLR_WHITE;
1107 else if (strcmp(cptr, LED_OK2RM) == 0)
1108 *colour_p = ENVMON_LED_CLR_BLUE;
1109 else
1110 *colour_p = ENVMON_LED_CLR_NONE;
1111 }
1112
1113 /*
1114 * Add nodes for environmental devices of type fru_type
1115 * below the supplied node.
1116 */
1117 static int
add_env_nodes(int envmon_fd,uint8_t fru_type,picl_nodehdl_t envmonh)1118 add_env_nodes(int envmon_fd, uint8_t fru_type, picl_nodehdl_t envmonh)
1119 {
1120 envmon_handle_t id;
1121 envmon_thresholds_t lows;
1122 envmon_thresholds_t highs;
1123 char units[ENVMON_MAXNAMELEN];
1124 char platform_tree_name[ENVMON_MAXNAMELEN];
1125 char label_name[ENVMON_MAXNAMELEN];
1126 int16_t sensor_data;
1127 int8_t led_state;
1128 int8_t colour;
1129 envmon_keysw_pos_t key_state;
1130 envmon_chassis_t chassis_num;
1131 int cmd;
1132 int err;
1133 int index = handle_arr.num;
1134 picl_nodehdl_t node_hdl;
1135
1136 /*
1137 * catch table is full at start
1138 */
1139 if (index >= handle_arr.maxnum)
1140 return (PICL_FAILURE);
1141
1142 cmd = fru_to_cmd[fru_type];
1143 id.name[0] = '\0';
1144
1145 do {
1146 lows.warning = lows.shutdown = lows.poweroff =
1147 ENVMON_VAL_UNAVAILABLE;
1148 highs.warning = highs.shutdown = highs.poweroff =
1149 ENVMON_VAL_UNAVAILABLE;
1150 handle_arr.fru_types[index] = fru_type;
1151 /* must store id before reading data as it is then updated */
1152 handle_arr.envhandles[index] = id;
1153 /*
1154 * read environmental data according to type
1155 */
1156 switch (fru_type) {
1157 case ENVMON_VOLT_SENS:
1158 /*FALLTHROUGH*/
1159 case ENVMON_AMP_SENS:
1160 /*FALLTHROUGH*/
1161 case ENVMON_TEMP_SENS:
1162 err = get_sensor_data(envmon_fd, &id, cmd, &lows,
1163 &highs, &sensor_data);
1164 break;
1165 case ENVMON_VOLT_IND:
1166 /*FALLTHROUGH*/
1167 case ENVMON_AMP_IND:
1168 /*FALLTHROUGH*/
1169 case ENVMON_TEMP_IND:
1170 /*FALLTHROUGH*/
1171 case ENVMON_FAN_IND:
1172 err = get_indicator_data(envmon_fd, &id, cmd,
1173 &sensor_data);
1174 break;
1175 case ENVMON_FAN_SENS:
1176 err = get_fan_data(envmon_fd, &id, cmd, &lows,
1177 (uint16_t *)&sensor_data, units);
1178 break;
1179 case ENVMON_LED_IND:
1180 err = get_led_data(envmon_fd, &id, cmd, &led_state,
1181 &colour);
1182 break;
1183 case ENVMON_KEY_SWITCH:
1184 err = get_keyswitch_data(envmon_fd, &id, cmd,
1185 &key_state);
1186 break;
1187 case ENVMON_CHASSIS:
1188 err = get_serial_num(envmon_fd, &id, cmd,
1189 &chassis_num);
1190 break;
1191 default:
1192 return (PICL_FAILURE);
1193 }
1194
1195 if (err == PICL_INVALIDHANDLE)
1196 continue;
1197 if ((err != PICL_SUCCESS) && (err != PICL_PROPVALUNAVAILABLE)) {
1198 syslog(LOG_ERR, EM_NODE_ACCESS, id, fru_type, err);
1199 continue;
1200 }
1201
1202 /*
1203 * successfully read environmental data, add to PICL
1204 */
1205 (void) strlcpy(platform_tree_name,
1206 handle_arr.envhandles[index].name,
1207 sizeof (platform_tree_name));
1208
1209 (void) strlcpy(label_name, platform_tree_name,
1210 ENVMON_MAXNAMELEN);
1211 convert_label_name(label_name);
1212 convert_node_name(platform_tree_name);
1213 /*
1214 * does this node already exist?
1215 */
1216 err = get_child_by_name(envmonh, platform_tree_name, &node_hdl);
1217 if (err == PICL_SUCCESS) {
1218 /*
1219 * skip over existing node
1220 */
1221 continue;
1222 }
1223 err = ptree_create_node(platform_tree_name,
1224 fru_to_class[fru_type], &node_hdl);
1225 if (err != PICL_SUCCESS) {
1226 break;
1227 }
1228 err = add_volatile_prop(node_hdl, fru_to_prop[fru_type],
1229 fru_to_ptype[fru_type],
1230 PICL_READ | (fru_type == ENVMON_LED_IND ? PICL_WRITE : 0),
1231 fru_to_size[fru_type], read_vol_data,
1232 fru_type == ENVMON_LED_IND ? write_led_data : NULL,
1233 &handle_arr.piclprhdls[index]);
1234 if (err != PICL_SUCCESS) {
1235 break;
1236 }
1237
1238 /*
1239 * if any thresholds are defined add a property
1240 */
1241 if (lows.warning != ENVMON_VAL_UNAVAILABLE) {
1242 err = add_value_prop(node_hdl, PICL_PROP_LOW_WARNING,
1243 fru_type, lows.warning);
1244 if (err != PICL_SUCCESS) {
1245 break;
1246 }
1247 }
1248 if (lows.shutdown != ENVMON_VAL_UNAVAILABLE) {
1249 err = add_value_prop(node_hdl, PICL_PROP_LOW_SHUTDOWN,
1250 fru_type, lows.shutdown);
1251 if (err != PICL_SUCCESS) {
1252 break;
1253 }
1254 }
1255 if (lows.poweroff != ENVMON_VAL_UNAVAILABLE) {
1256 err = add_value_prop(node_hdl, PICL_PROP_LOW_POWER_OFF,
1257 fru_type, lows.poweroff);
1258 if (err != PICL_SUCCESS) {
1259 break;
1260 }
1261 }
1262 if (highs.warning != ENVMON_VAL_UNAVAILABLE) {
1263 err = add_value_prop(node_hdl, PICL_PROP_HIGH_WARNING,
1264 fru_type, highs.warning);
1265 if (err != PICL_SUCCESS) {
1266 break;
1267 }
1268 }
1269 if (highs.shutdown != ENVMON_VAL_UNAVAILABLE) {
1270 err = add_value_prop(node_hdl, PICL_PROP_HIGH_SHUTDOWN,
1271 fru_type, highs.shutdown);
1272 if (err != PICL_SUCCESS) {
1273 break;
1274 }
1275 }
1276 if (highs.poweroff != ENVMON_VAL_UNAVAILABLE) {
1277 err = add_value_prop(node_hdl, PICL_PROP_HIGH_POWER_OFF,
1278 fru_type, highs.poweroff);
1279 if (err != PICL_SUCCESS) {
1280 break;
1281 }
1282 }
1283
1284 /*
1285 * if device is a fan sensor, add a speedunit property
1286 */
1287 if (fru_type == ENVMON_FAN_SENS) {
1288 err = add_regular_prop(node_hdl,
1289 PICL_PROP_FAN_SPEED_UNIT, PICL_PTYPE_CHARSTRING,
1290 PICL_READ, 1 + strlen(units), units, NULL);
1291 if (err != PICL_SUCCESS) {
1292 break;
1293 }
1294 }
1295 /*
1296 * If device is a LED indicator and returns a colour,
1297 * add a colour property.
1298 */
1299 if (fru_type == ENVMON_LED_IND) {
1300 if (colour < 0 || colour == ENVMON_LED_CLR_ANY ||
1301 colour > ENVMON_LED_CLR_RED)
1302 fix_led_colour(&colour,
1303 handle_arr.envhandles[index].name);
1304 if (colour != ENVMON_LED_CLR_NONE) {
1305 err = add_regular_prop(node_hdl,
1306 PICL_PROP_COLOR, PICL_PTYPE_CHARSTRING,
1307 PICL_READ, colour_lkup[colour].size,
1308 colour_lkup[colour].str_colour, NULL);
1309 if (err != PICL_SUCCESS) {
1310 break;
1311 }
1312 }
1313 }
1314 /*
1315 * add a label property unless it's a keyswitch or the
1316 * chassis serial number. keyswitch and chassis serial
1317 * number are labelled from a config file because the
1318 * ALOM interface doesn't supply a name for it)
1319 */
1320 if ((fru_type != ENVMON_KEY_SWITCH) &&
1321 (fru_type != ENVMON_CHASSIS)) {
1322 err = add_regular_prop(node_hdl, PICL_PROP_LABEL,
1323 PICL_PTYPE_CHARSTRING, PICL_READ,
1324 1 + strlen(label_name), label_name, NULL);
1325
1326 if (err != PICL_SUCCESS) {
1327 break;
1328 }
1329 }
1330 /*
1331 * all properties added to this node, add the node below
1332 * the supplied anchor point
1333 */
1334 err = ptree_add_node(envmonh, node_hdl);
1335
1336 if (err != PICL_SUCCESS) {
1337 break;
1338 }
1339
1340 /*
1341 * that node went in OK, advance index
1342 */
1343 index++;
1344
1345 } while ((id.name[0] != '\0') && (index < handle_arr.maxnum));
1346
1347 handle_arr.num = index;
1348 return (err);
1349 }
1350
1351 static void
fixstate(uint8_t state,const char * string,int * max_len)1352 fixstate(uint8_t state, const char *string, int *max_len)
1353 {
1354 int i;
1355 int len;
1356
1357 for (i = 0; i < (sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]));
1358 i++) {
1359 if (ledstate_lkup[i].state == state) {
1360 if (ledstate_lkup[i].str_ledstate != NULL)
1361 free(ledstate_lkup[i].str_ledstate);
1362 ledstate_lkup[i].str_ledstate = strdup(string);
1363 len = strlen(string);
1364 if (len >= *max_len)
1365 *max_len = len + 1;
1366 break;
1367 }
1368 }
1369 }
1370
1371 static void
fixkeyposn(envmon_keysw_pos_t keyposn,const char * string,int * max_len)1372 fixkeyposn(envmon_keysw_pos_t keyposn, const char *string, int *max_len)
1373 {
1374 int i;
1375 int len;
1376
1377 for (i = 0; i < (sizeof (keyposn_lkup) / sizeof (keyposn_lkup[0]));
1378 i++) {
1379 if (keyposn_lkup[i].pos == keyposn) {
1380 if (keyposn_lkup[i].str_keyposn != NULL)
1381 free(keyposn_lkup[i].str_keyposn);
1382 keyposn_lkup[i].str_keyposn = strdup(string);
1383 len = strlen(string);
1384 if (len >= *max_len)
1385 *max_len = len + 1;
1386 break;
1387 }
1388 }
1389 }
1390
1391 static void
setup_strings()1392 setup_strings()
1393 {
1394 int string_size;
1395 int i;
1396 int lim = sizeof (colour_lkup) / sizeof (colour_lkup[0]);
1397
1398 /*
1399 * initialise led colours lookup
1400 */
1401 for (i = 0; i < lim; i++) {
1402 if (colour_lkup[i].str_colour != NULL)
1403 free(colour_lkup[i].str_colour);
1404 }
1405
1406 colour_lkup[ENVMON_LED_CLR_ANY].str_colour = strdup(gettext("any"));
1407 colour_lkup[ENVMON_LED_CLR_WHITE].str_colour =
1408 strdup(gettext("white"));
1409 colour_lkup[ENVMON_LED_CLR_BLUE].str_colour = strdup(gettext("blue"));
1410 colour_lkup[ENVMON_LED_CLR_GREEN].str_colour =
1411 strdup(gettext("green"));
1412 colour_lkup[ENVMON_LED_CLR_AMBER].str_colour =
1413 strdup(gettext("amber"));
1414 colour_lkup[ENVMON_LED_CLR_RED].str_colour =
1415 strdup(gettext("red"));
1416
1417 for (i = 0; i < lim; i++) {
1418 if (colour_lkup[i].str_colour != NULL)
1419 colour_lkup[i].size =
1420 1 + strlen(colour_lkup[i].str_colour);
1421 }
1422
1423 /*
1424 * initialise condition strings and note longest
1425 */
1426 string_size = 0;
1427 cond_okay = strdup(gettext("okay"));
1428 if (strlen(cond_okay) >= string_size)
1429 string_size = 1 + strlen(cond_okay);
1430 cond_failed = strdup(gettext("failed"));
1431 if (strlen(cond_failed) >= string_size)
1432 string_size = 1 + strlen(cond_failed);
1433
1434 for (i = 0; i < sizeof (fru_to_size) / sizeof (fru_to_size[0]); i++)
1435 if (fru_to_size[i] == -1)
1436 fru_to_size[i] = string_size;
1437
1438 /*
1439 * initialise led state lookup strings
1440 */
1441 string_size = 0;
1442 fixstate(ENVMON_LED_OFF, gettext("off"), &string_size);
1443 fixstate(ENVMON_LED_ON, gettext("on"), &string_size);
1444 fixstate(ENVMON_LED_BLINKING, gettext("blinking"), &string_size);
1445 fixstate(ENVMON_LED_FLASHING, gettext("flashing"), &string_size);
1446 fru_to_size[ENVMON_LED_IND] = string_size;
1447
1448 /*
1449 * initialise key position lookup strings
1450 */
1451 string_size = 0;
1452 fixkeyposn(ENVMON_KEYSW_POS_UNKNOWN, gettext("UNKNOWN"), &string_size);
1453 fixkeyposn(ENVMON_KEYSW_POS_NORMAL, gettext("NORMAL"), &string_size);
1454 fixkeyposn(ENVMON_KEYSW_POS_DIAG, gettext("DIAG"), &string_size);
1455 fixkeyposn(ENVMON_KEYSW_POS_LOCKED, gettext("LOCKED"), &string_size);
1456 fixkeyposn(ENVMON_KEYSW_POS_OFF, gettext("STBY"), &string_size);
1457 fru_to_size[ENVMON_KEY_SWITCH] = string_size;
1458
1459 /*
1460 * initialise chassis serial number string
1461 */
1462 fru_to_size[ENVMON_CHASSIS] = ENVMON_MAXNAMELEN;
1463 }
1464
1465 /*
1466 * The size of outfilename must be PATH_MAX
1467 */
1468 static int
get_config_file(char * filename)1469 get_config_file(char *filename)
1470 {
1471 char nmbuf[SYS_NMLN];
1472 char pname[PATH_MAX];
1473
1474 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
1475 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
1476 (void) strlcat(pname, ENVMON_CONFFILE_NAME, PATH_MAX);
1477 if (access(pname, R_OK) == 0) {
1478 (void) strlcpy(filename, pname, PATH_MAX);
1479 return (0);
1480 }
1481 }
1482
1483 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
1484 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
1485 (void) strlcat(pname, ENVMON_CONFFILE_NAME, PATH_MAX);
1486 if (access(pname, R_OK) == 0) {
1487 (void) strlcpy(filename, pname, PATH_MAX);
1488 return (0);
1489 }
1490 }
1491
1492 (void) snprintf(pname, PATH_MAX, "%s/%s",
1493 PICLD_COMMON_PLUGIN_DIR, ENVMON_CONFFILE_NAME);
1494
1495 if (access(pname, R_OK) == 0) {
1496 (void) strlcpy(filename, pname, PATH_MAX);
1497 return (0);
1498 }
1499
1500 return (-1);
1501 }
1502
1503 static void
free_vol_prop(picl_prophdl_t proph)1504 free_vol_prop(picl_prophdl_t proph)
1505 {
1506 int index;
1507
1508 index = find_picl_handle(proph);
1509 if (index >= 0) {
1510 handle_arr.num--;
1511 if (index != handle_arr.num) {
1512 /* relocate last entry into hole just created */
1513 handle_arr.fru_types[index] =
1514 handle_arr.fru_types[handle_arr.num];
1515 handle_arr.envhandles[index] =
1516 handle_arr.envhandles[handle_arr.num];
1517 handle_arr.piclprhdls[index] =
1518 handle_arr.piclprhdls[handle_arr.num];
1519 }
1520 }
1521 }
1522
1523 /*
1524 * handle PICL FRU ADDED and FRU REMOVED events
1525 */
1526 /*ARGSUSED*/
1527 static void
envmon_evhandler(const char * ename,const void * earg,size_t size,void * cookie)1528 envmon_evhandler(const char *ename, const void *earg, size_t size,
1529 void *cookie)
1530 {
1531 char path[MAXPATHLEN];
1532 picl_nodehdl_t locnodeh;
1533 int retval;
1534 picl_nodehdl_t childh;
1535 picl_nodehdl_t nodeh;
1536 picl_prophdl_t tableh;
1537 picl_prophdl_t tblh;
1538 picl_prophdl_t proph;
1539 ptree_propinfo_t pi;
1540
1541 if (strcmp(ename, PICL_FRU_ADDED) == 0) {
1542 retval = nvlist_lookup_uint64((nvlist_t *)earg,
1543 PICLEVENTARG_PARENTHANDLE, &locnodeh);
1544
1545 if (retval != 0) {
1546 syslog(LOG_ERR, EM_EV_MISSING_ARG,
1547 PICLEVENTARG_PARENTHANDLE);
1548 return;
1549 }
1550 retval = ptree_get_propval_by_name(locnodeh, PICL_PROP_NAME,
1551 path, sizeof (path));
1552 if (retval == PICL_SUCCESS) {
1553 /*
1554 * Open envmon device and interrogate
1555 */
1556 int envmon_fd;
1557 int fru_type;
1558 picl_nodehdl_t envmoninfh;
1559
1560 if (get_envmon_node(&envmoninfh) != PICL_SUCCESS) {
1561 syslog(LOG_ERR, EM_SC_NODE_MISSING);
1562 return;
1563 }
1564
1565 if ((envmon_fd = open(envmon_device_name, O_RDONLY)) <
1566 0) {
1567 syslog(LOG_ERR, EM_SYS_ERR, envmon_device_name,
1568 strerror(errno));
1569 return;
1570 }
1571
1572 if (strcmp(str_SC, path) == 0) {
1573 /*
1574 * SC state change - re-assess platform tree
1575 */
1576 if (re_create_arrays(envmon_fd) != 0) {
1577 /*
1578 * out of memory - make no changes
1579 */
1580 return;
1581 }
1582 /*
1583 * dropped memory of volatile prop handles
1584 * so drop the nodes also, then rebuild for
1585 * the newly loaded SC
1586 */
1587 retval = ptree_get_propval_by_name(envmoninfh,
1588 PICL_PROP_PARENT, &nodeh, sizeof (nodeh));
1589 if (retval != PICL_SUCCESS) {
1590 (void) close(envmon_fd);
1591 return;
1592 }
1593 retval = ptree_get_propval_by_name(envmoninfh,
1594 PICL_PROP_NAME, path, sizeof (path));
1595 if (retval != PICL_SUCCESS) {
1596 (void) close(envmon_fd);
1597 return;
1598 }
1599
1600 retval = ptree_delete_node(envmoninfh);
1601 if (retval == PICL_SUCCESS)
1602 (void) ptree_destroy_node(envmoninfh);
1603 retval = ptree_create_node(path,
1604 PICL_CLASS_SERVICE_PROCESSOR, &envmoninfh);
1605 if (retval != PICL_SUCCESS) {
1606 (void) close(envmon_fd);
1607 return;
1608 }
1609 retval = ptree_add_node(nodeh, envmoninfh);
1610 if (retval != PICL_SUCCESS) {
1611 (void) close(envmon_fd);
1612 return;
1613 }
1614 }
1615
1616 for (fru_type = 0; fru_type < ENVMONTYPES;
1617 fru_type++) {
1618 (void) add_env_nodes(envmon_fd, fru_type,
1619 envmoninfh);
1620 }
1621
1622 (void) close(envmon_fd);
1623 }
1624 } else if (strcmp(ename, PICL_FRU_REMOVED) == 0) {
1625 retval = nvlist_lookup_uint64((nvlist_t *)earg,
1626 PICLEVENTARG_FRUHANDLE, &childh);
1627
1628 if (retval != 0) {
1629 syslog(LOG_ERR, EM_EV_MISSING_ARG,
1630 PICLEVENTARG_FRUHANDLE);
1631 return;
1632 }
1633 retval = ptree_get_propval_by_name(childh, PICL_PROP_NAME,
1634 path, sizeof (path));
1635 if (retval == PICL_SUCCESS) {
1636 retval = ptree_get_prop_by_name(childh,
1637 PICL_PROP_DEVICES, &tableh);
1638
1639 if (retval != PICL_SUCCESS) {
1640 /* no Devices table, nothing to do */
1641 return;
1642 }
1643
1644 /*
1645 * follow all reference properties in the second
1646 * column of the table and delete the referenced node
1647 */
1648 retval = ptree_get_propval(tableh, &tblh,
1649 sizeof (tblh));
1650 if (retval != PICL_SUCCESS) {
1651 /*
1652 * can't get value of table property
1653 */
1654 return;
1655 }
1656 /* get first col, first row */
1657 retval = ptree_get_next_by_col(tblh, &tblh);
1658 if (retval != PICL_SUCCESS) {
1659 /*
1660 * no rows?
1661 */
1662 return;
1663 }
1664 /*
1665 * starting at next col, get every entry in the column
1666 */
1667 for (retval = ptree_get_next_by_row(tblh, &tblh);
1668 retval == PICL_SUCCESS;
1669 retval = ptree_get_next_by_col(tblh, &tblh)) {
1670 /*
1671 * should be a ref prop in our hands,
1672 * get the target node handle
1673 */
1674 retval = ptree_get_propval(tblh, &nodeh,
1675 sizeof (nodeh));
1676 if (retval != PICL_SUCCESS) {
1677 continue;
1678 }
1679 /*
1680 * got the referenced node, has it got a
1681 * volatile property to clean up?
1682 */
1683 retval = ptree_get_first_prop(nodeh, &proph);
1684 while (retval == PICL_SUCCESS) {
1685 retval = ptree_get_propinfo(proph, &pi);
1686 if ((retval == PICL_SUCCESS) &&
1687 (pi.piclinfo.accessmode &
1688 PICL_VOLATILE))
1689 free_vol_prop(proph);
1690 retval = ptree_get_next_prop(proph,
1691 &proph);
1692 }
1693 /*
1694 * all volatile properties gone, remove node
1695 */
1696 retval = ptree_delete_node(nodeh);
1697 if (retval == PICL_SUCCESS)
1698 (void) ptree_destroy_node(nodeh);
1699 }
1700 }
1701 }
1702 }
1703
1704 /*
1705 * executed as part of .init when the plugin is dlopen()ed
1706 */
1707 static void
piclenvmon_register(void)1708 piclenvmon_register(void)
1709 {
1710 (void) picld_plugin_register(&my_reg_info);
1711 }
1712
1713 /*
1714 * Init entry point of the plugin
1715 * Creates the PICL nodes and properties in the physical and logical aspects.
1716 */
1717 static void
piclenvmon_init(void)1718 piclenvmon_init(void)
1719 {
1720 picl_nodehdl_t rooth;
1721 picl_nodehdl_t plfh;
1722 picl_nodehdl_t envmoninfh;
1723 int res;
1724 int envmon_fd;
1725 int fru_type;
1726 char pathname[PATH_MAX];
1727
1728 /*
1729 * locate and parse config file
1730 */
1731 if (get_config_file(pathname) < 0)
1732 return;
1733
1734 if ((ptree_get_root(&rooth) != PICL_SUCCESS) ||
1735 (picld_pluginutil_parse_config_file(rooth, pathname) !=
1736 PICL_SUCCESS)) {
1737 syslog(LOG_ERR, EM_INIT_FAILED);
1738 }
1739
1740 /*
1741 * Get platform node
1742 */
1743 if (ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM, &plfh)
1744 != PICL_SUCCESS) {
1745 syslog(LOG_ERR, EM_MISSING_NODE, PICL_NODE_PLATFORM);
1746 syslog(LOG_ERR, EM_INIT_FAILED);
1747 return;
1748 }
1749
1750 /*
1751 * Get service-processor node
1752 */
1753 if (get_envmon_node(&envmoninfh) != PICL_SUCCESS)
1754 return;
1755
1756 /*
1757 * We may have been restarted, make sure we don't leak
1758 */
1759 if (envmon_device_name != NULL) {
1760 free(envmon_device_name);
1761 }
1762
1763 if ((envmon_device_name = create_envmon_pathname(envmoninfh)) == NULL)
1764 return;
1765
1766 /*
1767 * Open envmon device and interrogate for devices it monitors
1768 */
1769 if ((envmon_fd = open(envmon_device_name, O_RDONLY)) < 0) {
1770 syslog(LOG_ERR, EM_SYS_ERR, envmon_device_name,
1771 strerror(errno));
1772 return;
1773 }
1774
1775 if (get_envmon_limits(envmon_fd, &env_limits) < 0)
1776 return;
1777
1778 /*
1779 * A set of arrays are used whose bounds are determined by the
1780 * response to get_envmon_limits. Establish these arrays now.
1781 */
1782 create_arrays();
1783 setup_strings();
1784
1785 for (fru_type = 0; fru_type < ENVMONTYPES; fru_type++) {
1786 (void) add_env_nodes(envmon_fd, fru_type, envmoninfh);
1787 }
1788
1789 (void) close(envmon_fd);
1790
1791 res = ptree_register_handler(PICL_FRU_ADDED, envmon_evhandler, NULL);
1792 if (res != PICL_SUCCESS) {
1793 syslog(LOG_ERR, EM_EVREG_FAILED, res);
1794 }
1795 res = ptree_register_handler(PICL_FRU_REMOVED, envmon_evhandler, NULL);
1796 if (res != PICL_SUCCESS) {
1797 syslog(LOG_ERR, EM_EVREG_FAILED, res);
1798 }
1799 }
1800
1801 /*
1802 * fini entry point of the plugin
1803 */
1804 static void
piclenvmon_fini(void)1805 piclenvmon_fini(void)
1806 {
1807 if (envmon_device_name != NULL) {
1808 free(envmon_device_name);
1809 envmon_device_name = NULL;
1810 }
1811 (void) ptree_unregister_handler(PICL_FRU_ADDED,
1812 envmon_evhandler, NULL);
1813 (void) ptree_unregister_handler(PICL_FRU_REMOVED,
1814 envmon_evhandler, NULL);
1815 }
1816