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 /*
28 * This plugin creates PICL nodes and properties for objects handled through
29 * the enhanced LOMV system-processor interface.
30 *
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.
39 *
40 * NOTE:
41 * Depends on PICL devtree plugin.
42 */
43
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"
69
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);
122
123 #pragma init(piclenvmon_register)
124
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
131 };
132
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];
145
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 }
154 };
155
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 }
165 };
166
167 /*
168 * fru-type to ioctl cmd lookup
169 */
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
182 };
183
184 /*
185 * fru-type to PICL CLASS
186 */
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
199 };
200
201 /*
202 * fru-type to PICL PROPERTY for volatile data
203 */
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
216 };
217
218 /*
219 * fru-type to PICL PTYPE
220 */
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
233 };
234
235 /*
236 * condition strings
237 */
238 static char *cond_okay;
239 static char *cond_failed;
240
241 /*
242 * fru-type to size of volatile property
243 * the -1's are replaced by the max size of a condition string
244 */
245 int fru_to_size[] = {
246 4, -1, 4, -1, 2, -1, 2, -1, -1, -1, -1
247 };
248
249 static node_el_t *
create_node_el(picl_nodehdl_t nodeh)250 create_node_el(picl_nodehdl_t nodeh)
251 {
252 node_el_t *ptr = malloc(sizeof (node_el_t));
253
254 if (ptr != NULL) {
255 ptr->nodeh = nodeh;
256 ptr->next = NULL;
257 }
258
259 return (ptr);
260 }
261
262 static void
delete_node_el(node_el_t * pel)263 delete_node_el(node_el_t *pel)
264 {
265 free(pel);
266 }
267
268 static node_list_t *
create_node_list()269 create_node_list()
270 {
271 node_list_t *ptr = malloc(sizeof (node_list_t));
272
273 if (ptr != NULL) {
274 ptr->head = NULL;
275 ptr->tail = NULL;
276 }
277
278 return (ptr);
279 }
280
281 static void
delete_node_list(node_list_t * pnl)282 delete_node_list(node_list_t *pnl)
283 {
284 node_el_t *pel;
285
286 if (pnl == NULL)
287 return;
288
289 while ((pel = pnl->head) != NULL) {
290 pnl->head = pel->next;
291 delete_node_el(pel);
292 }
293
294 /*
295 * normally pnl->tail would be to NULL next,
296 * but as it is about to be freed, this step can be skipped.
297 */
298 free(pnl);
299 }
300
301 /*
302 * Get a linking element and add handle to end of chain
303 */
304 static void
add_node_to_list(picl_nodehdl_t nodeh,node_list_t * listp)305 add_node_to_list(picl_nodehdl_t nodeh, node_list_t *listp)
306 {
307 node_el_t *pel = create_node_el(nodeh);
308
309 if (pel != NULL) {
310 if (listp->tail == NULL)
311 listp->head = pel;
312 else
313 listp->tail->next = pel;
314
315 listp->tail = pel;
316 }
317 }
318
319 /*
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.
323 */
324 static void
get_node_list_by_class(picl_nodehdl_t nodeh,const char * classname,node_list_t * listp)325 get_node_list_by_class(picl_nodehdl_t nodeh, const char *classname,
326 node_list_t *listp)
327 {
328 int err;
329 char clname[PICL_CLASSNAMELEN_MAX+1];
330 picl_nodehdl_t chdh;
331
332 /*
333 * go through the children
334 */
335 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
336 sizeof (picl_nodehdl_t));
337
338 while (err == PICL_SUCCESS) {
339 err = ptree_get_propval_by_name(chdh, PICL_PROP_CLASSNAME,
340 clname, strlen(classname) + 1);
341
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);
346
347 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
348 sizeof (picl_nodehdl_t));
349 }
350 }
351
352 static int
get_envmon_limits(int envmon_fd,envmon_sysinfo_t * limits_p)353 get_envmon_limits(int envmon_fd, envmon_sysinfo_t *limits_p)
354 {
355 return (ioctl(envmon_fd, ENVMONIOCSYSINFO, limits_p));
356 }
357
358 static int
re_create_arrays(int envmon_fd)359 re_create_arrays(int envmon_fd)
360 {
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;
367
368 res = get_envmon_limits(envmon_fd, &new_limits);
369 if (res != 0)
370 return (res);
371
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;
377
378 if (maxnum != handle_arr.maxnum) {
379 /*
380 * space requirements have changed
381 */
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);
391 }
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));
405 }
406
407 handle_arr.num = 0;
408 handle_arr.maxnum = maxnum;
409 env_limits = new_limits;
410 return (0);
411 }
412
413 static void
create_arrays()414 create_arrays()
415 {
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));
426 }
427
428 static int
get_envmon_node(picl_nodehdl_t * envmoninfh)429 get_envmon_node(picl_nodehdl_t *envmoninfh)
430 {
431 int err = PICL_SUCCESS;
432 node_list_t *listp;
433
434 listp = create_node_list();
435
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 ! */
441 }
442
443 get_node_list_by_class(*envmoninfh, PICL_CLASS_SERVICE_PROCESSOR,
444 listp);
445
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;
452 }
453
454 delete_node_list(listp);
455 return (err);
456 }
457
458 static char *
create_envmon_pathname(picl_nodehdl_t envmoninfh)459 create_envmon_pathname(picl_nodehdl_t envmoninfh)
460 {
461 char *ptr;
462 char namebuf[PATH_MAX];
463 size_t len;
464 DIR *dirp;
465 struct dirent *dp;
466 struct stat statbuf;
467
468 /* prefix devfs-path name with /devices */
469 (void) strlcpy(namebuf, "/devices", PATH_MAX);
470
471 /*
472 * append devfs-path property
473 */
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);
479 }
480
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);
491 }
492 *ptr++ = '/'; /* restore '/' and advance to final name */
493
494 while ((dp = readdir(dirp)) != NULL) {
495 /*
496 * look for a name which starts with the string at *ptr
497 */
498 if (strlen(dp->d_name) < len)
499 continue; /* skip short names */
500 if (strncmp(dp->d_name, ptr, len) == 0) {
501 /*
502 * Got a match, restore full pathname and stat the
503 * entry. Reject if not a char device
504 */
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 */
511 /*
512 * go with this entry
513 */
514 (void) closedir(dirp);
515 return (strdup(namebuf));
516 }
517 }
518 syslog(LOG_ERR, EM_SC_NODE_MISSING);
519 (void) closedir(dirp);
520 return (NULL);
521 }
522
523 /*
524 * look for named node as child of supplied handle
525 */
526 static int
get_child_by_name(picl_nodehdl_t nodeh,const char * name,picl_nodehdl_t * childh)527 get_child_by_name(picl_nodehdl_t nodeh, const char *name,
528 picl_nodehdl_t *childh)
529 {
530 int err;
531 char node_name[ENVMON_MAXNAMELEN];
532
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));
545 }
546 return (err);
547 }
548
549 /*
550 * Create and add the specified regular property
551 */
552 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)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)
555 {
556 int err;
557 ptree_propinfo_t propinfo;
558 picl_prophdl_t proph;
559
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);
564
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);
570 }
571
572
573 /*
574 * Create and add the specified volatile property
575 */
576 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)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)
580 {
581 int err;
582 ptree_propinfo_t propinfo;
583 picl_prophdl_t proph;
584
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);
589
590 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph);
591 if (err == PICL_SUCCESS && prophp)
592 *prophp = proph;
593 return (err);
594 }
595
596 /*
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.
602 */
603
604 /*
605 * Function to read sensor data.
606 */
607 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)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)
610 {
611 int res;
612 envmon_sensor_t data;
613
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);
619 }
620
621 *id = data.next_id;
622
623 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0)
624 return (PICL_INVALIDHANDLE);
625
626 /*
627 * it is assumed that threshold data will be available,
628 * even though the current sensor value may be inaccessible
629 */
630 if (lows != NULL)
631 *lows = data.lowthresholds;
632 if (highs != NULL)
633 *highs = data.highthresholds;
634
635 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) {
636 if (value != NULL)
637 *value = ENVMON_VAL_UNAVAILABLE;
638 return (PICL_PROPVALUNAVAILABLE);
639 }
640 if (value != NULL)
641 *value = data.value;
642 return (PICL_SUCCESS);
643 }
644
645 /*
646 * Function to read indicator data.
647 */
648 static int
get_indicator_data(int envmon_fd,envmon_handle_t * id,int cmd,int16_t * condition)649 get_indicator_data(int envmon_fd, envmon_handle_t *id, int cmd,
650 int16_t *condition)
651 {
652 int res;
653 envmon_indicator_t data;
654
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);
666 }
667 return (PICL_SUCCESS);
668 }
669
670 /*
671 * Function to read fan data.
672 */
673 static int
get_fan_data(int envmon_fd,envmon_handle_t * id,int cmd,envmon_thresholds_t * lows,uint16_t * speed,char * units)674 get_fan_data(int envmon_fd, envmon_handle_t *id, int cmd,
675 envmon_thresholds_t *lows, uint16_t *speed, char *units)
676 {
677 int res;
678 envmon_fan_t data;
679
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));
691
692 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) {
693 if (speed != NULL)
694 *speed = ENVMON_VAL_UNAVAILABLE;
695 return (PICL_PROPVALUNAVAILABLE);
696 }
697 if (speed != NULL)
698 *speed = data.speed;
699 return (PICL_SUCCESS);
700 }
701
702 /*
703 * Function to read LED data.
704 */
705 static int
get_led_data(int envmon_fd,envmon_handle_t * id,int cmd,int8_t * state,int8_t * colour)706 get_led_data(int envmon_fd, envmon_handle_t *id, int cmd,
707 int8_t *state, int8_t *colour)
708 {
709 int res;
710 envmon_led_info_t data;
711
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);
723 }
724 if (state != NULL)
725 *state = data.led_state;
726 return (PICL_SUCCESS);
727 }
728
729 /*
730 * Function to read key-switch position
731 * Returns PICL_INVALIDHANDLE if ioctl not supported (or fails)
732 */
733 static int
get_keyswitch_data(int envmon_fd,envmon_handle_t * id,int cmd,envmon_keysw_pos_t * key_state)734 get_keyswitch_data(int envmon_fd, envmon_handle_t *id, int cmd,
735 envmon_keysw_pos_t *key_state)
736 {
737 int res;
738
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';
748
749 if (res < 0)
750 return (PICL_INVALIDHANDLE);
751 return (PICL_SUCCESS);
752 }
753 }
754
755 /*
756 * Function to read the chassis serial number
757 * Returns PICL_INVALIDHANDLE if ioctl not supported (or fails)
758 */
759 static int
get_serial_num(int envmon_fd,envmon_handle_t * id,int cmd,envmon_chassis_t * chassis)760 get_serial_num(int envmon_fd, envmon_handle_t *id, int cmd,
761 envmon_chassis_t *chassis)
762 {
763 int res;
764
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';
776
777 if (res < 0)
778 return (PICL_INVALIDHANDLE);
779 return (PICL_SUCCESS);
780 }
781 }
782
783 /*
784 * change to lower case and convert any spaces into hyphens,
785 * and any dots or colons symbols into underscores
786 */
787 static void
convert_node_name(char * ptr)788 convert_node_name(char *ptr)
789 {
790 char ch;
791
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 = '_';
799 }
800 }
801 }
802
803 /*
804 * strip to the last '.' separator and keep the rest
805 * change ':' to '/' within the last component
806 */
807 static void
convert_label_name(char * name)808 convert_label_name(char *name)
809 {
810 const char *cptr;
811 char ch;
812
813 cptr = strrchr(name, '.');
814
815 if (cptr == NULL)
816 cptr = name;
817 else
818 cptr++; /* skip the '.' */
819
820 do {
821 ch = *cptr++;
822
823 if (ch == ':')
824 ch = '/';
825
826 *name++ = ch;
827 } while (ch != '\0');
828 }
829
830 /*
831 * add a value property
832 */
833 static int
add_value_prop(picl_nodehdl_t node_hdl,const char * prop_name,int fru_type,int16_t value)834 add_value_prop(picl_nodehdl_t node_hdl, const char *prop_name, int fru_type,
835 int16_t value)
836 {
837 int err;
838 union {
839 float u_f;
840 int16_t u_i16;
841 } val_buf;
842
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;
847
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);
851 }
852
853 static int
find_picl_handle(picl_prophdl_t proph)854 find_picl_handle(picl_prophdl_t proph)
855 {
856 int index;
857
858 for (index = 0; index < handle_arr.num; index++) {
859 if (handle_arr.piclprhdls[index] == proph)
860 return (index);
861 }
862
863 return (-1);
864 }
865
866 /*
867 * look up function to convert led status into string
868 */
869 static int
lookup_led_status(int8_t state,const char ** string)870 lookup_led_status(int8_t state, const char **string)
871 {
872 int i;
873 int lim = sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]);
874
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);
879 }
880 }
881
882 *string = "";
883 return (PICL_PROPVALUNAVAILABLE);
884 }
885
886 static int
lookup_key_posn(envmon_keysw_pos_t pos,const char ** string)887 lookup_key_posn(envmon_keysw_pos_t pos, const char **string)
888 {
889 int i;
890 int lim = sizeof (keyposn_lkup) / sizeof (keyposn_lkup[0]);
891
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);
896 }
897 }
898
899 *string = "";
900 return (PICL_PROPVALUNAVAILABLE);
901 }
902
903 /*
904 * function to read volatile data associated with a PICL property handle
905 */
906 static int
read_vol_data(ptree_rarg_t * r_arg,void * buf)907 read_vol_data(ptree_rarg_t *r_arg, void *buf)
908 {
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;
922
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);
933
934 /*
935 * read environmental data according to type
936 */
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;
971 }
972
973 (void) close(envmon_fd);
974 if (err != PICL_SUCCESS) {
975 /*
976 * PICL_INVALIDHANDLE is used internally, but it upsets
977 * prtpicl; change it to PICL_PROPVALUNAVAILABLE
978 */
979 if (err == PICL_INVALIDHANDLE)
980 err = PICL_PROPVALUNAVAILABLE;
981 return (err);
982 }
983
984 /*
985 * convert data and copy out
986 */
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;
994
995 case ENVMON_TEMP_SENS:
996 /*FALLTHROUGH*/
997 case ENVMON_FAN_SENS:
998 (void) memcpy(buf, &sensor_data, sizeof (sensor_data));
999 break;
1000
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;
1011
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;
1018
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;
1029
1030 default:
1031 return (PICL_FAILURE);
1032 }
1033
1034 return (PICL_SUCCESS);
1035 }
1036
1037 static int
write_led_data(ptree_warg_t * w_arg,const void * buf)1038 write_led_data(ptree_warg_t *w_arg, const void *buf)
1039 {
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;
1046
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);
1056
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);
1068
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);
1078 }
1079
1080 /*
1081 * if colour information is not supplied by the service processor,
1082 * try to determine led colour from the handle name.
1083 */
1084 static void
fix_led_colour(int8_t * colour_p,const char * id)1085 fix_led_colour(int8_t *colour_p, const char *id)
1086 {
1087 const char *cptr = strrchr(id, '.');
1088
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;
1095 }
1096
1097 cptr++; /* step over '.' */
1098
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;
1109 }
1110
1111 /*
1112 * Add nodes for environmental devices of type fru_type
1113 * below the supplied node.
1114 */
1115 static int
add_env_nodes(int envmon_fd,uint8_t fru_type,picl_nodehdl_t envmonh)1116 add_env_nodes(int envmon_fd, uint8_t fru_type, picl_nodehdl_t envmonh)
1117 {
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;
1133
1134 /*
1135 * catch table is full at start
1136 */
1137 if (index >= handle_arr.maxnum)
1138 return (PICL_FAILURE);
1139
1140 cmd = fru_to_cmd[fru_type];
1141 id.name[0] = '\0';
1142
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;
1151 /*
1152 * read environmental data according to type
1153 */
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);
1191 }
1192
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;
1198 }
1199
1200 /*
1201 * successfully read environmental data, add to PICL
1202 */
1203 (void) strlcpy(platform_tree_name,
1204 handle_arr.envhandles[index].name,
1205 sizeof (platform_tree_name));
1206
1207 (void) strlcpy(label_name, platform_tree_name,
1208 ENVMON_MAXNAMELEN);
1209 convert_label_name(label_name);
1210 convert_node_name(platform_tree_name);
1211 /*
1212 * does this node already exist?
1213 */
1214 err = get_child_by_name(envmonh, platform_tree_name, &node_hdl);
1215 if (err == PICL_SUCCESS) {
1216 /*
1217 * skip over existing node
1218 */
1219 continue;
1220 }
1221 err = ptree_create_node(platform_tree_name,
1222 fru_to_class[fru_type], &node_hdl);
1223 if (err != PICL_SUCCESS) {
1224 break;
1225 }
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;
1234 }
1235
1236 /*
1237 * if any thresholds are defined add a property
1238 */
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;
1244 }
1245 }
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;
1251 }
1252 }
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;
1258 }
1259 }
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;
1265 }
1266 }
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;
1272 }
1273 }
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;
1279 }
1280 }
1281
1282 /*
1283 * if device is a fan sensor, add a speedunit property
1284 */
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;
1291 }
1292 }
1293 /*
1294 * If device is a LED indicator and returns a colour,
1295 * add a colour property.
1296 */
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;
1309 }
1310 }
1311 }
1312 /*
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)
1317 */
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);
1323
1324 if (err != PICL_SUCCESS) {
1325 break;
1326 }
1327 }
1328 /*
1329 * all properties added to this node, add the node below
1330 * the supplied anchor point
1331 */
1332 err = ptree_add_node(envmonh, node_hdl);
1333
1334 if (err != PICL_SUCCESS) {
1335 break;
1336 }
1337
1338 /*
1339 * that node went in OK, advance index
1340 */
1341 index++;
1342
1343 } while ((id.name[0] != '\0') && (index < handle_arr.maxnum));
1344
1345 handle_arr.num = index;
1346 return (err);
1347 }
1348
1349 static void
fixstate(uint8_t state,const char * string,int * max_len)1350 fixstate(uint8_t state, const char *string, int *max_len)
1351 {
1352 int i;
1353 int len;
1354
1355 for (i = 0; i < (sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]));
1356 i++) {
1357 if (ledstate_lkup[i].state == state) {
1358 if (ledstate_lkup[i].str_ledstate != NULL)
1359 free(ledstate_lkup[i].str_ledstate);
1360 ledstate_lkup[i].str_ledstate = strdup(string);
1361 len = strlen(string);
1362 if (len >= *max_len)
1363 *max_len = len + 1;
1364 break;
1365 }
1366 }
1367 }
1368
1369 static void
fixkeyposn(envmon_keysw_pos_t keyposn,const char * string,int * max_len)1370 fixkeyposn(envmon_keysw_pos_t keyposn, const char *string, int *max_len)
1371 {
1372 int i;
1373 int len;
1374
1375 for (i = 0; i < (sizeof (keyposn_lkup) / sizeof (keyposn_lkup[0]));
1376 i++) {
1377 if (keyposn_lkup[i].pos == keyposn) {
1378 if (keyposn_lkup[i].str_keyposn != NULL)
1379 free(keyposn_lkup[i].str_keyposn);
1380 keyposn_lkup[i].str_keyposn = strdup(string);
1381 len = strlen(string);
1382 if (len >= *max_len)
1383 *max_len = len + 1;
1384 break;
1385 }
1386 }
1387 }
1388
1389 static void
setup_strings()1390 setup_strings()
1391 {
1392 int string_size;
1393 int i;
1394 int lim = sizeof (colour_lkup) / sizeof (colour_lkup[0]);
1395
1396 /*
1397 * initialise led colours lookup
1398 */
1399 for (i = 0; i < lim; i++) {
1400 if (colour_lkup[i].str_colour != NULL)
1401 free(colour_lkup[i].str_colour);
1402 }
1403
1404 colour_lkup[ENVMON_LED_CLR_ANY].str_colour = strdup(gettext("any"));
1405 colour_lkup[ENVMON_LED_CLR_WHITE].str_colour =
1406 strdup(gettext("white"));
1407 colour_lkup[ENVMON_LED_CLR_BLUE].str_colour = strdup(gettext("blue"));
1408 colour_lkup[ENVMON_LED_CLR_GREEN].str_colour =
1409 strdup(gettext("green"));
1410 colour_lkup[ENVMON_LED_CLR_AMBER].str_colour =
1411 strdup(gettext("amber"));
1412 colour_lkup[ENVMON_LED_CLR_RED].str_colour =
1413 strdup(gettext("red"));
1414
1415 for (i = 0; i < lim; i++) {
1416 if (colour_lkup[i].str_colour != NULL)
1417 colour_lkup[i].size =
1418 1 + strlen(colour_lkup[i].str_colour);
1419 }
1420
1421 /*
1422 * initialise condition strings and note longest
1423 */
1424 string_size = 0;
1425 cond_okay = strdup(gettext("okay"));
1426 if (strlen(cond_okay) >= string_size)
1427 string_size = 1 + strlen(cond_okay);
1428 cond_failed = strdup(gettext("failed"));
1429 if (strlen(cond_failed) >= string_size)
1430 string_size = 1 + strlen(cond_failed);
1431
1432 for (i = 0; i < sizeof (fru_to_size) / sizeof (fru_to_size[0]); i++)
1433 if (fru_to_size[i] == -1)
1434 fru_to_size[i] = string_size;
1435
1436 /*
1437 * initialise led state lookup strings
1438 */
1439 string_size = 0;
1440 fixstate(ENVMON_LED_OFF, gettext("off"), &string_size);
1441 fixstate(ENVMON_LED_ON, gettext("on"), &string_size);
1442 fixstate(ENVMON_LED_BLINKING, gettext("blinking"), &string_size);
1443 fixstate(ENVMON_LED_FLASHING, gettext("flashing"), &string_size);
1444 fru_to_size[ENVMON_LED_IND] = string_size;
1445
1446 /*
1447 * initialise key position lookup strings
1448 */
1449 string_size = 0;
1450 fixkeyposn(ENVMON_KEYSW_POS_UNKNOWN, gettext("UNKNOWN"), &string_size);
1451 fixkeyposn(ENVMON_KEYSW_POS_NORMAL, gettext("NORMAL"), &string_size);
1452 fixkeyposn(ENVMON_KEYSW_POS_DIAG, gettext("DIAG"), &string_size);
1453 fixkeyposn(ENVMON_KEYSW_POS_LOCKED, gettext("LOCKED"), &string_size);
1454 fixkeyposn(ENVMON_KEYSW_POS_OFF, gettext("STBY"), &string_size);
1455 fru_to_size[ENVMON_KEY_SWITCH] = string_size;
1456
1457 /*
1458 * initialise chassis serial number string
1459 */
1460 fru_to_size[ENVMON_CHASSIS] = ENVMON_MAXNAMELEN;
1461 }
1462
1463 /*
1464 * The size of outfilename must be PATH_MAX
1465 */
1466 static int
get_config_file(char * filename)1467 get_config_file(char *filename)
1468 {
1469 char nmbuf[SYS_NMLN];
1470 char pname[PATH_MAX];
1471
1472 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
1473 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
1474 (void) strlcat(pname, ENVMON_CONFFILE_NAME, PATH_MAX);
1475 if (access(pname, R_OK) == 0) {
1476 (void) strlcpy(filename, pname, PATH_MAX);
1477 return (0);
1478 }
1479 }
1480
1481 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
1482 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
1483 (void) strlcat(pname, ENVMON_CONFFILE_NAME, PATH_MAX);
1484 if (access(pname, R_OK) == 0) {
1485 (void) strlcpy(filename, pname, PATH_MAX);
1486 return (0);
1487 }
1488 }
1489
1490 (void) snprintf(pname, PATH_MAX, "%s/%s",
1491 PICLD_COMMON_PLUGIN_DIR, ENVMON_CONFFILE_NAME);
1492
1493 if (access(pname, R_OK) == 0) {
1494 (void) strlcpy(filename, pname, PATH_MAX);
1495 return (0);
1496 }
1497
1498 return (-1);
1499 }
1500
1501 static void
free_vol_prop(picl_prophdl_t proph)1502 free_vol_prop(picl_prophdl_t proph)
1503 {
1504 int index;
1505
1506 index = find_picl_handle(proph);
1507 if (index >= 0) {
1508 handle_arr.num--;
1509 if (index != handle_arr.num) {
1510 /* relocate last entry into hole just created */
1511 handle_arr.fru_types[index] =
1512 handle_arr.fru_types[handle_arr.num];
1513 handle_arr.envhandles[index] =
1514 handle_arr.envhandles[handle_arr.num];
1515 handle_arr.piclprhdls[index] =
1516 handle_arr.piclprhdls[handle_arr.num];
1517 }
1518 }
1519 }
1520
1521 /*
1522 * handle PICL FRU ADDED and FRU REMOVED events
1523 */
1524 /*ARGSUSED*/
1525 static void
envmon_evhandler(const char * ename,const void * earg,size_t size,void * cookie)1526 envmon_evhandler(const char *ename, const void *earg, size_t size,
1527 void *cookie)
1528 {
1529 char path[MAXPATHLEN];
1530 picl_nodehdl_t locnodeh;
1531 int retval;
1532 picl_nodehdl_t childh;
1533 picl_nodehdl_t nodeh;
1534 picl_prophdl_t tableh;
1535 picl_prophdl_t tblh;
1536 picl_prophdl_t proph;
1537 ptree_propinfo_t pi;
1538
1539 if (strcmp(ename, PICL_FRU_ADDED) == 0) {
1540 retval = nvlist_lookup_uint64((nvlist_t *)earg,
1541 PICLEVENTARG_PARENTHANDLE, &locnodeh);
1542
1543 if (retval != 0) {
1544 syslog(LOG_ERR, EM_EV_MISSING_ARG,
1545 PICLEVENTARG_PARENTHANDLE);
1546 return;
1547 }
1548 retval = ptree_get_propval_by_name(locnodeh, PICL_PROP_NAME,
1549 path, sizeof (path));
1550 if (retval == PICL_SUCCESS) {
1551 /*
1552 * Open envmon device and interrogate
1553 */
1554 int envmon_fd;
1555 int fru_type;
1556 picl_nodehdl_t envmoninfh;
1557
1558 if (get_envmon_node(&envmoninfh) != PICL_SUCCESS) {
1559 syslog(LOG_ERR, EM_SC_NODE_MISSING);
1560 return;
1561 }
1562
1563 if ((envmon_fd = open(envmon_device_name, O_RDONLY)) <
1564 0) {
1565 syslog(LOG_ERR, EM_SYS_ERR, envmon_device_name,
1566 strerror(errno));
1567 return;
1568 }
1569
1570 if (strcmp(str_SC, path) == 0) {
1571 /*
1572 * SC state change - re-assess platform tree
1573 */
1574 if (re_create_arrays(envmon_fd) != 0) {
1575 /*
1576 * out of memory - make no changes
1577 */
1578 return;
1579 }
1580 /*
1581 * dropped memory of volatile prop handles
1582 * so drop the nodes also, then rebuild for
1583 * the newly loaded SC
1584 */
1585 retval = ptree_get_propval_by_name(envmoninfh,
1586 PICL_PROP_PARENT, &nodeh, sizeof (nodeh));
1587 if (retval != PICL_SUCCESS) {
1588 (void) close(envmon_fd);
1589 return;
1590 }
1591 retval = ptree_get_propval_by_name(envmoninfh,
1592 PICL_PROP_NAME, path, sizeof (path));
1593 if (retval != PICL_SUCCESS) {
1594 (void) close(envmon_fd);
1595 return;
1596 }
1597
1598 retval = ptree_delete_node(envmoninfh);
1599 if (retval == PICL_SUCCESS)
1600 (void) ptree_destroy_node(envmoninfh);
1601 retval = ptree_create_node(path,
1602 PICL_CLASS_SERVICE_PROCESSOR, &envmoninfh);
1603 if (retval != PICL_SUCCESS) {
1604 (void) close(envmon_fd);
1605 return;
1606 }
1607 retval = ptree_add_node(nodeh, envmoninfh);
1608 if (retval != PICL_SUCCESS) {
1609 (void) close(envmon_fd);
1610 return;
1611 }
1612 }
1613
1614 for (fru_type = 0; fru_type < ENVMONTYPES;
1615 fru_type++) {
1616 (void) add_env_nodes(envmon_fd, fru_type,
1617 envmoninfh);
1618 }
1619
1620 (void) close(envmon_fd);
1621 }
1622 } else if (strcmp(ename, PICL_FRU_REMOVED) == 0) {
1623 retval = nvlist_lookup_uint64((nvlist_t *)earg,
1624 PICLEVENTARG_FRUHANDLE, &childh);
1625
1626 if (retval != 0) {
1627 syslog(LOG_ERR, EM_EV_MISSING_ARG,
1628 PICLEVENTARG_FRUHANDLE);
1629 return;
1630 }
1631 retval = ptree_get_propval_by_name(childh, PICL_PROP_NAME,
1632 path, sizeof (path));
1633 if (retval == PICL_SUCCESS) {
1634 retval = ptree_get_prop_by_name(childh,
1635 PICL_PROP_DEVICES, &tableh);
1636
1637 if (retval != PICL_SUCCESS) {
1638 /* no Devices table, nothing to do */
1639 return;
1640 }
1641
1642 /*
1643 * follow all reference properties in the second
1644 * column of the table and delete the referenced node
1645 */
1646 retval = ptree_get_propval(tableh, &tblh,
1647 sizeof (tblh));
1648 if (retval != PICL_SUCCESS) {
1649 /*
1650 * can't get value of table property
1651 */
1652 return;
1653 }
1654 /* get first col, first row */
1655 retval = ptree_get_next_by_col(tblh, &tblh);
1656 if (retval != PICL_SUCCESS) {
1657 /*
1658 * no rows?
1659 */
1660 return;
1661 }
1662 /*
1663 * starting at next col, get every entry in the column
1664 */
1665 for (retval = ptree_get_next_by_row(tblh, &tblh);
1666 retval == PICL_SUCCESS;
1667 retval = ptree_get_next_by_col(tblh, &tblh)) {
1668 /*
1669 * should be a ref prop in our hands,
1670 * get the target node handle
1671 */
1672 retval = ptree_get_propval(tblh, &nodeh,
1673 sizeof (nodeh));
1674 if (retval != PICL_SUCCESS) {
1675 continue;
1676 }
1677 /*
1678 * got the referenced node, has it got a
1679 * volatile property to clean up?
1680 */
1681 retval = ptree_get_first_prop(nodeh, &proph);
1682 while (retval == PICL_SUCCESS) {
1683 retval = ptree_get_propinfo(proph, &pi);
1684 if ((retval == PICL_SUCCESS) &&
1685 (pi.piclinfo.accessmode &
1686 PICL_VOLATILE))
1687 free_vol_prop(proph);
1688 retval = ptree_get_next_prop(proph,
1689 &proph);
1690 }
1691 /*
1692 * all volatile properties gone, remove node
1693 */
1694 retval = ptree_delete_node(nodeh);
1695 if (retval == PICL_SUCCESS)
1696 (void) ptree_destroy_node(nodeh);
1697 }
1698 }
1699 }
1700 }
1701
1702 /*
1703 * executed as part of .init when the plugin is dlopen()ed
1704 */
1705 static void
piclenvmon_register(void)1706 piclenvmon_register(void)
1707 {
1708 (void) picld_plugin_register(&my_reg_info);
1709 }
1710
1711 /*
1712 * Init entry point of the plugin
1713 * Creates the PICL nodes and properties in the physical and logical aspects.
1714 */
1715 static void
piclenvmon_init(void)1716 piclenvmon_init(void)
1717 {
1718 picl_nodehdl_t rooth;
1719 picl_nodehdl_t plfh;
1720 picl_nodehdl_t envmoninfh;
1721 int res;
1722 int envmon_fd;
1723 int fru_type;
1724 char pathname[PATH_MAX];
1725
1726 /*
1727 * locate and parse config file
1728 */
1729 if (get_config_file(pathname) < 0)
1730 return;
1731
1732 if ((ptree_get_root(&rooth) != PICL_SUCCESS) ||
1733 (picld_pluginutil_parse_config_file(rooth, pathname) !=
1734 PICL_SUCCESS)) {
1735 syslog(LOG_ERR, EM_INIT_FAILED);
1736 }
1737
1738 /*
1739 * Get platform node
1740 */
1741 if (ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM, &plfh)
1742 != PICL_SUCCESS) {
1743 syslog(LOG_ERR, EM_MISSING_NODE, PICL_NODE_PLATFORM);
1744 syslog(LOG_ERR, EM_INIT_FAILED);
1745 return;
1746 }
1747
1748 /*
1749 * Get service-processor node
1750 */
1751 if (get_envmon_node(&envmoninfh) != PICL_SUCCESS)
1752 return;
1753
1754 /*
1755 * We may have been restarted, make sure we don't leak
1756 */
1757 if (envmon_device_name != NULL) {
1758 free(envmon_device_name);
1759 }
1760
1761 if ((envmon_device_name = create_envmon_pathname(envmoninfh)) == NULL)
1762 return;
1763
1764 /*
1765 * Open envmon device and interrogate for devices it monitors
1766 */
1767 if ((envmon_fd = open(envmon_device_name, O_RDONLY)) < 0) {
1768 syslog(LOG_ERR, EM_SYS_ERR, envmon_device_name,
1769 strerror(errno));
1770 return;
1771 }
1772
1773 if (get_envmon_limits(envmon_fd, &env_limits) < 0)
1774 return;
1775
1776 /*
1777 * A set of arrays are used whose bounds are determined by the
1778 * response to get_envmon_limits. Establish these arrays now.
1779 */
1780 create_arrays();
1781 setup_strings();
1782
1783 for (fru_type = 0; fru_type < ENVMONTYPES; fru_type++) {
1784 (void) add_env_nodes(envmon_fd, fru_type, envmoninfh);
1785 }
1786
1787 (void) close(envmon_fd);
1788
1789 res = ptree_register_handler(PICL_FRU_ADDED, envmon_evhandler, NULL);
1790 if (res != PICL_SUCCESS) {
1791 syslog(LOG_ERR, EM_EVREG_FAILED, res);
1792 }
1793 res = ptree_register_handler(PICL_FRU_REMOVED, envmon_evhandler, NULL);
1794 if (res != PICL_SUCCESS) {
1795 syslog(LOG_ERR, EM_EVREG_FAILED, res);
1796 }
1797 }
1798
1799 /*
1800 * fini entry point of the plugin
1801 */
1802 static void
piclenvmon_fini(void)1803 piclenvmon_fini(void)
1804 {
1805 if (envmon_device_name != NULL) {
1806 free(envmon_device_name);
1807 envmon_device_name = NULL;
1808 }
1809 (void) ptree_unregister_handler(PICL_FRU_ADDED,
1810 envmon_evhandler, NULL);
1811 (void) ptree_unregister_handler(PICL_FRU_REMOVED,
1812 envmon_evhandler, NULL);
1813 }
1814