cmd: remove sparc-only virtinfo
[unleashed.git] / usr / src / cmd / picl / plugins / sun4u / blade / bsc / picllom.c
blob17c6b098af44362d13252133c0a133ece7bb50e4
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
27 * This plugin creates PICL nodes and properties for objects handled through
28 * the blade support chip (BSC). The BSC Solaris land device driver exposes
29 * information to the plugin and other clients through an existing LOM
30 * (Lights Out Management) ioctl interface. The plugin only exercises
31 * a subset of the interface which is known to be supported by the bsc.
33 * All the nodes which may be accessible through the BSC are included below
34 * the SUNW,bscv node (class system-controller) in the /platform tree.
35 * This plugin interrogates the BSC 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.
40 * NOTE:
41 * Depends on PICL devtree plugin.
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <alloca.h>
49 #include <syslog.h>
50 #include <string.h>
51 #include <libintl.h>
52 #include <picl.h>
53 #include <picltree.h>
54 #include <errno.h>
55 #include <limits.h>
56 #include <ctype.h>
57 #include <sys/types.h>
58 #include <sys/obpdefs.h>
59 #include <sys/lom_io.h>
60 #include <sys/systeminfo.h>
61 #include <time.h>
62 #include <picldefs.h>
63 #include <picld_pluginutil.h>
64 #include "picllom.h"
66 static void picllom_register(void);
67 static void picllom_init(void);
68 static void picllom_fini(void);
69 static node_el_t *create_node_el(picl_nodehdl_t nodeh);
70 static void delete_node_el(node_el_t *pel);
71 static node_list_t *create_node_list();
72 static void delete_node_list_contents(node_list_t *pnl);
73 static void delete_node_list(node_list_t *pnl);
74 static void add_node_to_list(picl_nodehdl_t nodeh,
75 node_list_t *listp);
76 static void get_node_list_by_class(picl_nodehdl_t nodeh,
77 const char *classname, node_list_t *listp);
78 static int get_lom_node(picl_nodehdl_t *lominfh);
79 static int get_lom_device_path(picl_nodehdl_t *lominfh);
80 static int get_node_by_name_and_class(picl_nodehdl_t srchnodeh,
81 const char *nodename, const char *classname, picl_nodehdl_t *chdh);
82 static int add_regular_prop(picl_nodehdl_t nodeh, const char *name,
83 int type, int access, int size, const void *valbuf, picl_prophdl_t *prophp);
84 static int add_volatile_prop(picl_nodehdl_t nodeh, char *name,
85 int type, int access, int size, ptree_vol_rdfunc_t rdfunc,
86 ptree_vol_wrfunc_t wrfunc, picl_prophdl_t *prophp);
87 static int open_lom_rd(int *lom_fd);
88 static int get_lom_temp(int index, tempr_t *temp_p);
89 static int update_voltage_stats();
90 static int get_lom_volts_status(int index, int *voltsStatus_p);
91 static int get_lom_volts_shutdown(int index, int *voltsShutdown_p);
92 static int update_fan_stats();
93 static int get_lom_fan_speed(int index, int *fan_speed);
94 static int read_vol_temp(ptree_rarg_t *parg, void *buf);
95 static int read_vol_volts_status(ptree_rarg_t *parg, void *buf);
96 static int read_vol_volts_shutdown(ptree_rarg_t *parg, void *buf);
97 static int read_fan_speed(ptree_rarg_t *parg, void *buf);
98 static int read_fan_status(ptree_rarg_t *parg, void *buf);
99 static int lookup_led_status(int8_t state, const char **string);
100 static int read_led_status(ptree_rarg_t *parg, void *buf);
101 static void convert_node_name(char *ptr);
102 static int add_temp_sensors(int lom_fd, picl_nodehdl_t lominfh);
103 static int add_voltage_monitors(int lom_fd,
104 picl_nodehdl_t lominfh);
105 static int add_fan_nodes(int lom_fd, picl_nodehdl_t lominfh);
106 static int get_config_file(char *outfilename);
108 #pragma init(picllom_register)
110 static picld_plugin_reg_t my_reg_info = {
111 PICLD_PLUGIN_VERSION_1,
112 PICLD_PLUGIN_NON_CRITICAL,
113 "SUNW_picllom",
114 picllom_init,
115 picllom_fini
118 static const char str_OK[] = "OK";
119 static const char str_FAIL[] = "FAIL";
120 static const char str_On[] = "on";
121 static const char str_Off[] = "off";
122 static const char str_Enabled[] = "Enabled";
123 static const char str_Disabled[] = "Disabled";
124 static char lom_device_path[PATH_MAX];
125 static tempr_t high_warnings[MAX_TEMPS];
126 static tempr_t high_shutdowns[MAX_TEMPS];
127 static picl_prophdl_t temp_handles[MAX_TEMPS];
128 static lom_fandata_t fandata;
129 static picl_prophdl_t fan_speed_handles[MAX_FANS];
130 static picl_prophdl_t fan_status_handles[MAX_FANS];
131 static lom_volts_t voltsdata;
132 static picl_prophdl_t volts_status_handles[MAX_VOLTS];
133 static picl_prophdl_t volts_shutdown_handles[MAX_VOLTS];
134 static int n_leds = 0;
135 static int max_state_size = 0;
136 static picl_prophdl_t *led_handles = NULL;
137 static char **led_labels = NULL;
138 static lom2_info_t info2data;
139 static struct {
140 int size;
141 char *str_colour;
142 } colour_lkup[1 + LOM_LED_COLOUR_AMBER];
144 static struct {
145 int8_t state;
146 char *str_ledstate;
147 } ledstate_lkup[] = {
148 { LOM_LED_OFF },
149 { LOM_LED_ON },
150 { LOM_LED_BLINKING },
153 static node_el_t *
154 create_node_el(picl_nodehdl_t nodeh)
156 node_el_t *ptr = malloc(sizeof (node_el_t));
158 if (ptr != NULL) {
159 ptr->nodeh = nodeh;
160 ptr->next = NULL;
163 return (ptr);
166 static void
167 delete_node_el(node_el_t *pel)
169 free(pel);
172 static node_list_t *
173 create_node_list()
175 node_list_t *ptr = malloc(sizeof (node_list_t));
177 if (ptr != NULL) {
178 ptr->head = NULL;
179 ptr->tail = NULL;
182 return (ptr);
185 static void
186 delete_node_list_contents(node_list_t *pnl)
188 node_el_t *pel;
190 if (pnl == NULL)
191 return;
193 while ((pel = pnl->head) != NULL) {
194 pnl->head = pel->next;
195 delete_node_el(pel);
198 pnl->tail = NULL;
201 static void
202 delete_node_list(node_list_t *pnl)
204 delete_node_list_contents(pnl);
205 free(pnl);
209 * Get a linking element and add handle to end of chain
211 static void
212 add_node_to_list(picl_nodehdl_t nodeh, node_list_t *listp)
214 node_el_t *pel = create_node_el(nodeh);
216 if (pel != NULL) {
217 if (listp->tail == NULL)
218 listp->head = pel;
219 else
220 listp->tail->next = pel;
222 listp->tail = pel;
227 * Get a list of nodes of the specified classname under nodeh.
228 * Once a node of the specified class is found, its children are not
229 * searched.
231 static void
232 get_node_list_by_class(picl_nodehdl_t nodeh, const char *classname,
233 node_list_t *listp)
235 int err;
236 char clname[PICL_CLASSNAMELEN_MAX+1];
237 picl_nodehdl_t chdh;
240 * go through the children
242 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
243 sizeof (picl_nodehdl_t));
245 while (err == PICL_SUCCESS) {
246 err = ptree_get_propval_by_name(chdh, PICL_PROP_CLASSNAME,
247 clname, strlen(classname) + 1);
249 if ((err == PICL_SUCCESS) && (strcmp(clname, classname) == 0))
250 add_node_to_list(chdh, listp);
251 else
252 get_node_list_by_class(chdh, classname, listp);
254 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
255 sizeof (picl_nodehdl_t));
259 static int
260 get_lom_node(picl_nodehdl_t *lominfh)
262 int err = PICL_SUCCESS;
263 node_list_t *listp;
265 listp = create_node_list();
267 if ((err = ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM,
268 lominfh)) != PICL_SUCCESS) {
269 syslog(LOG_ERR, EM_MISSING_NODE,
270 PICL_NODE_ROOT PICL_NODE_PLATFORM);
271 return (err); /* no /platform ! */
274 get_node_list_by_class(*lominfh, PICL_CLASS_SERVICE_PROCESSOR, listp);
276 if (listp->head == NULL) {
277 *lominfh = 0;
278 syslog(LOG_ERR, EM_MISSING_NODE, PICL_CLASS_SERVICE_PROCESSOR);
279 err = PICL_NODENOTFOUND;
280 } else {
281 *lominfh = listp->head->nodeh;
283 if (listp->head != listp->tail)
284 syslog(LOG_ERR, EM_LOM_DUPLICATE);
287 delete_node_list(listp);
288 return (err);
291 static int
292 get_lom_device_path(picl_nodehdl_t *lominfh)
294 int err = PICL_SUCCESS;
295 char devfs_path[PATH_MAX];
296 char devices_path[PATH_MAX];
298 err = ptree_get_propval_by_name(*lominfh, PICL_PROP_DEVFS_PATH,
299 devfs_path, sizeof (devfs_path));
301 /* Build up the full device path and set the global */
302 strcpy(devices_path, "/devices");
303 strcat(devices_path, devfs_path);
304 strcat(devices_path, LOM_DEV_MINOR_NAME);
305 strcpy(lom_device_path, devices_path);
307 return (err);
315 * Look for a node of specified name and class
316 * Confine search to nodes one level below that of supplied handle
318 static int
319 get_node_by_name_and_class(picl_nodehdl_t srchnodeh, const char *nodename,
320 const char *classname, picl_nodehdl_t *chdh)
322 int err;
323 char namebuf[PATH_MAX];
325 err = ptree_get_propval_by_name(srchnodeh, PICL_PROP_CHILD, chdh,
326 sizeof (picl_nodehdl_t));
328 while (err == PICL_SUCCESS) {
329 err = ptree_get_propval_by_name(*chdh, PICL_PROP_NAME, namebuf,
330 sizeof (namebuf));
331 if (err != PICL_SUCCESS)
332 break;
333 if (strcmp(namebuf, nodename) == 0) {
334 err = ptree_get_propval_by_name(*chdh,
335 PICL_PROP_CLASSNAME, namebuf, sizeof (namebuf));
336 if ((err == PICL_SUCCESS) &&
337 (strcmp(namebuf, classname) == 0))
338 return (PICL_SUCCESS);
340 err = ptree_get_propval_by_name(*chdh, PICL_PROP_PEER, chdh,
341 sizeof (picl_nodehdl_t));
344 return (err);
348 * Create and add the specified regular property
351 static int
352 add_regular_prop(picl_nodehdl_t nodeh, const char *name, int type, int access,
353 int size, const void *valbuf, picl_prophdl_t *prophp)
355 int err;
356 ptree_propinfo_t propinfo;
357 picl_prophdl_t proph;
359 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
360 type, access, size, (char *)name, NULL, NULL);
361 if (err != PICL_SUCCESS)
362 return (err);
364 err = ptree_create_and_add_prop(nodeh, &propinfo, (void *)valbuf,
365 &proph);
366 if (err == PICL_SUCCESS && prophp)
367 *prophp = proph;
368 return (err);
373 * Create and add the specified volatile property
375 static int
376 add_volatile_prop(picl_nodehdl_t nodeh, char *name, int type, int access,
377 int size, ptree_vol_rdfunc_t rdfunc, ptree_vol_wrfunc_t wrfunc,
378 picl_prophdl_t *prophp)
380 int err;
381 ptree_propinfo_t propinfo;
382 picl_prophdl_t proph;
384 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
385 type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc);
386 if (err != PICL_SUCCESS)
387 return (err);
389 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph);
390 if (err == PICL_SUCCESS && prophp)
391 *prophp = proph;
392 return (err);
396 * open LOM device to read
398 static int
399 open_lom_rd(int *lom_fd)
401 *lom_fd = open(lom_device_path, O_RDONLY);
403 if (*lom_fd < 0)
404 return (PICL_FAILURE);
406 return (PICL_SUCCESS);
410 * Function to open LOM and read temperature sensor values.
411 * The index to a specific sensor is supplied and that value returned.
413 static int
414 get_lom_temp(int index, tempr_t *temp_p)
416 lom_temp_t lom_temp;
417 int lom_fd;
418 int err;
419 int res;
421 err = open_lom_rd(&lom_fd);
423 if (err == PICL_SUCCESS) {
424 res = ioctl(lom_fd, LOMIOCTEMP, &lom_temp);
425 (void) close(lom_fd);
427 if (res == 0) {
428 *temp_p = lom_temp.temp[index];
429 } else {
430 err = PICL_FAILURE;
434 return (err);
438 * Function to open LOM and read voltage monitor values.
439 * Called for each property, so only perform update if time has changed
441 static int
442 update_voltage_stats()
444 static time_t then = 0;
445 int lom_fd;
446 int err;
447 int res;
448 time_t now = time(NULL);
450 if (now == then)
451 return (PICL_SUCCESS);
453 then = now;
454 err = open_lom_rd(&lom_fd);
456 if (err == PICL_SUCCESS) {
457 res = ioctl(lom_fd, LOMIOCVOLTS, &voltsdata);
458 (void) close(lom_fd);
459 if (res < 0) {
460 err = PICL_FAILURE;
464 return (err);
468 * Function to open LOM and read voltage monitor values.
469 * The index to a specific voltage status is supplied and that value returned.
471 static int
472 get_lom_volts_status(int index, int *voltsStatus_p)
474 int res;
476 if ((res = update_voltage_stats()) != PICL_SUCCESS)
477 return (res);
479 *voltsStatus_p = voltsdata.status[index];
480 return (PICL_SUCCESS);
484 * Function to open LOM and read voltage monitor values.
485 * The index to a specific shutdown flag is supplied and that value returned.
487 static int
488 get_lom_volts_shutdown(int index, int *voltsShutdown_p)
490 int res;
492 if ((res = update_voltage_stats()) != PICL_SUCCESS)
493 return (res);
495 *voltsShutdown_p = voltsdata.shutdown_enabled[index];
496 return (PICL_SUCCESS);
502 * Function to open LOM and read fan values.
503 * Called for each property, so only perform update if time has changed
505 static int
506 update_fan_stats()
508 static time_t then = 0;
509 int lom_fd;
510 int err;
511 int res;
512 time_t now = time(NULL);
514 if (now == then)
515 return (PICL_SUCCESS);
517 then = now;
518 err = open_lom_rd(&lom_fd);
519 if (err == PICL_SUCCESS) {
520 res = ioctl(lom_fd, LOMIOCFANSTATE, &fandata);
521 (void) close(lom_fd);
522 if (res < 0) {
523 err = PICL_FAILURE;
527 return (err);
533 * The index to a specific fan is supplied and its speed value returned.
535 static int
536 get_lom_fan_speed(int index, int *fan_speed)
538 int res;
540 if ((res = update_fan_stats()) != PICL_SUCCESS)
541 return (res);
543 *fan_speed = fandata.speed[index];
544 return (PICL_SUCCESS);
549 * Read function for volatile "Temperature" property via LOM
551 static int
552 read_vol_temp(ptree_rarg_t *parg, void *buf)
554 tempr_t temp;
555 picl_prophdl_t proph;
556 int index;
559 * get the sensor index from the displacement of the
560 * property handle and get its temperature.
562 proph = parg->proph;
563 for (index = 0; index < MAX_TEMPS; index++) {
564 if (temp_handles[index] == proph)
565 break;
568 if (index == MAX_TEMPS) {
570 * Handle not found. As this is a plugin, stale handles
571 * cannot occur, so just fail.
573 return (PICL_FAILURE);
576 if (get_lom_temp(index, &temp) != PICL_SUCCESS)
577 return (PICL_FAILURE);
578 (void) memcpy(buf, (caddr_t)&temp, sizeof (tempr_t));
579 return (PICL_SUCCESS);
583 * Read function for volatile "VoltageStatus" property via LOM
585 static int
586 read_vol_volts_status(ptree_rarg_t *parg, void *buf)
588 int voltsStatus;
589 picl_prophdl_t proph;
590 int index;
593 * get the voltage monitor index from the displacement of the
594 * status property handle and get its status.
596 proph = parg->proph;
598 for (index = 0; index < MAX_VOLTS; index++) {
599 if (volts_status_handles[index] == proph)
600 break;
603 if (index == MAX_VOLTS)
604 return (PICL_FAILURE);
606 if (get_lom_volts_status(index, &voltsStatus) != PICL_SUCCESS)
607 return (PICL_FAILURE);
609 (void) strlcpy(buf, (voltsStatus == 0) ? str_OK : str_FAIL,
610 sizeof (str_FAIL));
611 return (PICL_SUCCESS);
615 * Read function for volatile "VoltageShutdown" property via LOM
617 static int
618 read_vol_volts_shutdown(ptree_rarg_t *parg, void *buf)
620 int voltsShutdown;
621 picl_prophdl_t proph;
622 int index;
625 * get the voltage monitor index from the displacement of the
626 * shutdown property handle and get its value.
628 proph = parg->proph;
630 for (index = 0; index < MAX_VOLTS; index++) {
631 if (volts_shutdown_handles[index] == proph)
632 break;
635 if (index == MAX_VOLTS)
636 return (PICL_FAILURE);
638 if (get_lom_volts_shutdown(index, &voltsShutdown) != PICL_SUCCESS)
639 return (PICL_FAILURE);
641 (void) strlcpy(buf, (voltsShutdown == 0) ? str_Disabled : str_Enabled,
642 sizeof (str_Disabled));
643 return (PICL_SUCCESS);
648 * Read function for volatile fan speed property via LOM
650 static int
651 read_fan_speed(ptree_rarg_t *parg, void *buf)
653 int fan_speed;
654 picl_prophdl_t proph;
655 int index;
658 * get the relevant fan from the displacement of its property handle
660 proph = parg->proph;
662 for (index = 0; index < MAX_FANS; index++) {
663 if (fan_speed_handles[index] == proph)
664 break;
667 if (index == MAX_FANS)
668 return (PICL_FAILURE);
670 if (get_lom_fan_speed(index, &fan_speed) != PICL_SUCCESS)
671 return (PICL_FAILURE);
673 (void) memcpy(buf, (caddr_t)&fan_speed, sizeof (fan_speed));
674 return (PICL_SUCCESS);
678 * look up function to convert led status into string
680 static int
681 lookup_led_status(int8_t state, const char **string)
683 int i;
684 int lim = sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]);
686 for (i = 0; i < lim; i++) {
687 if (ledstate_lkup[i].state == state) {
688 *string = ledstate_lkup[i].str_ledstate;
689 return (PICL_SUCCESS);
693 *string = "";
694 switch (state) {
695 case LOM_LED_ACCESS_ERROR:
696 return (PICL_PROPVALUNAVAILABLE);
697 case LOM_LED_NOT_IMPLEMENTED:
698 /*FALLTHROUGH*/
699 case LOM_LED_OUTOFRANGE:
700 /*FALLTHROUGH*/
701 default:
702 return (PICL_FAILURE);
707 * Read function for volatile led status property.
709 static int
710 read_led_status(ptree_rarg_t *parg, void *buf)
712 lom_led_state_t led_data;
713 picl_prophdl_t proph;
714 int index;
715 int lom_fd;
716 int res;
717 const char *string;
720 * get the relevant led from the displacement of its property handle
722 proph = parg->proph;
724 for (index = 0; index < n_leds; index++) {
725 if (led_handles[index] == proph)
726 break;
729 if (index == n_leds)
730 return (PICL_FAILURE);
732 res = open_lom_rd(&lom_fd);
733 if (res != PICL_SUCCESS)
734 return (res);
736 * The interface for reading LED status doesn't promise to maintain
737 * a constant mapping between LED index number and LED identity
738 * (as defined by its label). On the other hand, PICL does promise
739 * that whilst a handle remains valid the object it represents will
740 * remain constant. To reconcile these positions, we maintain
741 * tables of labels and handles linked by index value. We search
742 * for the handle with which we are presented and then locate its
743 * label. Then we request LED entries from the LOM and compare their
744 * labels with the one we seek. As an optimisation, we try the original
745 * index value first and then revert to a full search.
747 (void) memset(&led_data, 0, sizeof (led_data));
748 led_data.index = index;
749 res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data);
751 if (res != 0 || led_data.state == LOM_LED_NOT_IMPLEMENTED ||
752 strcmp(led_data.label, led_labels[index]) != 0) {
754 * full scan required (bet it doesn't work!)
755 * first re-establish the range to scan
757 int i;
758 int n;
760 (void) memset(&led_data, 0, sizeof (led_data));
761 led_data.index = -1;
762 res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data);
764 if (res != 0) {
765 (void) close(lom_fd);
766 return (PICL_PROPVALUNAVAILABLE);
769 if (led_data.state == LOM_LED_NOT_IMPLEMENTED ||
770 strcmp(led_data.label, led_labels[index]) != 0) {
771 n = led_data.index;
772 for (i = 0; i < n; i++) {
773 (void) memset(&led_data, 0, sizeof (led_data));
774 led_data.index = i;
775 res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data);
777 if (res == 0 &&
778 led_data.state != LOM_LED_NOT_IMPLEMENTED ||
779 strcmp(led_data.label, led_labels[index]) ==
780 0) {
781 break;
785 if (i == n) {
786 (void) close(lom_fd);
787 return (PICL_PROPVALUNAVAILABLE);
793 * if we get here, then we found the right LED.
795 (void) close(lom_fd);
796 res = lookup_led_status(led_data.state, &string);
797 (void) strlcpy(buf, string, max_state_size);
798 return (res);
802 * Read function for volatile fan status property.
803 * This is a synthesized property using speed and min speed properties
805 static int
806 read_fan_status(ptree_rarg_t *parg, void *buf)
808 int fan_speed;
809 picl_prophdl_t proph;
810 int index;
813 * get the relevant fan from the displacement of its property handle
815 proph = parg->proph;
817 for (index = 0; index < MAX_FANS; index++) {
818 if (fan_status_handles[index] == proph)
819 break;
822 if (index == MAX_FANS)
823 return (PICL_FAILURE);
825 if (get_lom_fan_speed(index, &fan_speed) != PICL_SUCCESS)
826 return (PICL_FAILURE);
828 (void) strlcpy(buf,
829 fan_speed < fandata.minspeed[index] ? str_FAIL : str_OK,
830 sizeof (str_FAIL));
831 return (PICL_SUCCESS);
837 * change to lower case and convert any spaces into hyphens
839 static void
840 convert_node_name(char *ptr)
842 char ch;
844 for (ch = *ptr; ch != '\0'; ch = *++ptr) {
845 if (isupper(ch)) {
846 *ptr = tolower(ch);
847 } else if (isspace(ch)) {
848 *ptr = '-';
853 static int
854 add_temp_sensors(int lom_fd, picl_nodehdl_t lominfh)
856 lom_temp_t lom_temp;
857 int res;
858 int i;
859 int err = PICL_SUCCESS;
860 const char *cptr;
862 res = ioctl(lom_fd, LOMIOCTEMP, &lom_temp);
864 if ((res == 0) && (lom_temp.num > 0)) {
866 * for each temperature location add a sensor node
868 for (i = 0; i < lom_temp.num; i++) {
869 picl_nodehdl_t tempsensh;
870 picl_prophdl_t proph;
872 high_warnings[i] = lom_temp.warning[i];
873 high_shutdowns[i] = lom_temp.shutdown[i];
875 convert_node_name(lom_temp.name[i]);
877 err = ptree_create_node(lom_temp.name[i],
878 PICL_CLASS_TEMPERATURE_SENSOR, &tempsensh);
879 if (err != PICL_SUCCESS)
880 break;
882 err = add_volatile_prop(tempsensh,
883 PICL_PROP_TEMPERATURE, PICL_PTYPE_INT, PICL_READ,
884 sizeof (tempr_t), read_vol_temp, NULL,
885 &temp_handles[i]);
886 if (err != PICL_SUCCESS)
887 break;
889 if (high_warnings[i] != 0) {
890 err = add_regular_prop(
891 tempsensh, PICL_PROP_HIGH_WARNING,
892 PICL_PTYPE_INT, PICL_READ,
893 sizeof (tempr_t), &high_warnings[i],
894 &proph);
895 if (err != PICL_SUCCESS)
896 break;
899 if (high_shutdowns[i] != 0) {
900 err = add_regular_prop(
901 tempsensh, PICL_PROP_HIGH_SHUTDOWN,
902 PICL_PTYPE_INT, PICL_READ,
903 sizeof (tempr_t), &high_shutdowns[i],
904 &proph);
905 if (err != PICL_SUCCESS)
906 break;
910 * for the benefit of prtdiag, add a label of
911 * either enclosure or die where appropriate
913 if ((strcasestr(lom_temp.name[i], CPU_ENCLOSURE) !=
914 NULL) ||
915 (strcasestr(lom_temp.name[i], CPU_AMBIENT) !=
916 NULL)) {
917 cptr = CPU_AMBIENT;
918 } else if ((cptr = strcasestr(lom_temp.name[i],
919 CPU_DIE)) != NULL) {
920 cptr = CPU_DIE;
923 if (cptr != NULL) {
924 err = add_regular_prop(
925 tempsensh, PICL_PROP_LABEL,
926 PICL_PTYPE_CHARSTRING, PICL_READ,
927 strlen(cptr) + 1, cptr, &proph);
929 if (err != PICL_SUCCESS) {
930 break;
934 err = ptree_add_node(lominfh, tempsensh);
936 if (err != PICL_SUCCESS)
937 break;
940 if (err != PICL_SUCCESS) {
941 syslog(LOG_ERR, EM_LOMINFO_TREE_FAILED);
945 return (err);
948 static int
949 add_voltage_monitors(int lom_fd, picl_nodehdl_t lominfh)
951 int res;
952 int i;
953 int err = PICL_SUCCESS;
954 picl_prophdl_t proph;
956 res = ioctl(lom_fd, LOMIOCVOLTS, &voltsdata);
958 if ((res == 0) && (voltsdata.num > 0)) {
960 * for each voltage monitor add a monitor node
962 for (i = 0; i < voltsdata.num; i++) {
963 picl_nodehdl_t voltsmonh;
965 convert_node_name(voltsdata.name[i]);
967 err = ptree_create_node(voltsdata.name[i],
968 PICL_CLASS_VOLTAGE_INDICATOR, &voltsmonh);
969 if (err != PICL_SUCCESS)
970 break;
972 err = add_regular_prop(voltsmonh, PICL_PROP_LABEL,
973 PICL_PTYPE_CHARSTRING, PICL_READ,
974 strlen(voltsdata.name[i]) + 1,
975 voltsdata.name[i], &proph);
976 if (err != PICL_SUCCESS)
977 break;
979 err = add_volatile_prop(voltsmonh, PICL_VOLTS_SHUTDOWN,
980 PICL_PTYPE_CHARSTRING, PICL_READ,
981 sizeof (str_Disabled), read_vol_volts_shutdown,
982 NULL, &volts_shutdown_handles[i]);
983 if (err != PICL_SUCCESS)
984 break;
986 err = add_volatile_prop(voltsmonh, PICL_PROP_CONDITION,
987 PICL_PTYPE_CHARSTRING, PICL_READ,
988 sizeof (str_FAIL), read_vol_volts_status, NULL,
989 &volts_status_handles[i]);
990 if (err != PICL_SUCCESS)
991 break;
993 err = ptree_add_node(lominfh, voltsmonh);
995 if (err != PICL_SUCCESS)
996 break;
999 if (err != PICL_SUCCESS) {
1000 syslog(LOG_ERR, EM_LOMINFO_TREE_FAILED);
1004 return (err);
1007 static void
1008 add_led(const lom_led_state_t *led_state, picl_nodehdl_t lominfh)
1010 int err;
1011 picl_nodehdl_t ledh;
1012 picl_nodehdl_t proph;
1014 if (((unsigned char)led_state->state == LOM_LED_STATE_NOT_PRESENT) ||
1015 (led_state->label[0] == '\0')) {
1016 return;
1019 err = ptree_create_node(led_state->label, PICL_CLASS_LED, &ledh);
1021 * the led may exist already, e.g. Fault
1023 if (err != PICL_SUCCESS)
1024 return;
1027 * Unlike LEDs derived from other interfaces, these are not
1028 * writable. Establish a read-only volatile property.
1030 err = add_volatile_prop(ledh, PICL_PROP_STATE, PICL_PTYPE_CHARSTRING,
1031 PICL_READ, max_state_size, read_led_status, NULL,
1032 &led_handles[led_state->index]);
1033 if (err != PICL_SUCCESS)
1034 return;
1037 * if colour was defined for this LED, add a colour property
1039 if ((led_state->colour != LOM_LED_COLOUR_NONE) &&
1040 (led_state->colour != LOM_LED_COLOUR_ANY)) {
1041 err = add_regular_prop(ledh, PICL_PROP_COLOR,
1042 PICL_PTYPE_CHARSTRING, PICL_READ,
1043 colour_lkup[led_state->index].size,
1044 colour_lkup[led_state->index].str_colour, &proph);
1046 if (err != PICL_SUCCESS)
1047 return;
1049 err = add_regular_prop(ledh, PICL_PROP_LABEL,
1050 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(led_state->label) + 1,
1051 led_state->label, &proph);
1052 if (err != PICL_SUCCESS)
1053 return;
1055 err = ptree_add_node(lominfh, ledh);
1057 if (err != PICL_SUCCESS) {
1058 syslog(LOG_ERR, EM_LOMINFO_TREE_FAILED);
1062 static void
1063 fixstate(uint8_t state, const char *string, int *max_len)
1065 int i;
1066 int len;
1068 for (i = 0; i < (sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]));
1069 i++) {
1070 if (ledstate_lkup[i].state == state) {
1071 free(ledstate_lkup[i].str_ledstate);
1072 ledstate_lkup[i].str_ledstate = strdup(string);
1073 len = strlen(string);
1074 if (len >= *max_len)
1075 *max_len = len + 1;
1076 break;
1081 static void
1082 add_led_nodes(int lom_fd, picl_nodehdl_t lominfh)
1084 lom_led_state_t led_data;
1085 picl_nodehdl_t ledh;
1086 int res;
1087 int i;
1090 * If the led state enquiry ioctl is supported, an enquiry on
1091 * index -1 will return the state of the highest supported index
1092 * value.
1094 (void) memset(&led_data, 0, sizeof (led_data));
1095 led_data.index = -1;
1096 res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data);
1098 if (res != 0)
1099 return;
1101 if (led_labels != NULL) {
1102 for (i = 0; i < n_leds; i++) {
1103 if (led_labels[i] != NULL) {
1104 free(led_labels[i]);
1108 free(led_labels);
1109 led_labels = NULL;
1112 if (led_handles != NULL) {
1113 free(led_handles);
1116 n_leds = 0;
1117 led_handles = calloc(led_data.index + 1, sizeof (picl_nodehdl_t));
1118 led_labels = calloc(led_data.index + 1, sizeof (char *));
1120 if ((led_labels == NULL) || (led_handles == NULL)) {
1121 free(led_labels);
1122 free(led_handles);
1123 led_labels = NULL;
1124 led_handles = NULL;
1125 syslog(LOG_ERR, EM_NO_LED_MEM);
1126 return;
1129 n_leds = led_data.index + 1;
1132 * For each LED with a valid state, add a node
1133 * and because of the ludicrous API, stache a copy of its label too
1135 for (i = 0; i < n_leds; i++) {
1136 (void) memset(&led_data, 0, sizeof (led_data));
1137 led_data.index = i;
1138 res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data);
1140 if (res != 0)
1141 continue;
1143 if (led_data.state == LOM_LED_OUTOFRANGE ||
1144 led_data.state == LOM_LED_NOT_IMPLEMENTED)
1145 continue;
1148 led_labels[i] = strdup(led_data.label);
1149 convert_node_name(led_data.label);
1151 if (get_node_by_name_and_class(lominfh, led_data.label,
1152 "led", &ledh) != PICL_SUCCESS) {
1154 * only add a new led node,
1155 * if it's not already in place
1157 add_led(&led_data, lominfh);
1162 static int
1163 add_fan_nodes(int lom_fd, picl_nodehdl_t lominfh)
1165 int res;
1166 int i;
1167 int err = PICL_SUCCESS;
1169 res = ioctl(lom_fd, LOMIOCFANSTATE, &fandata);
1171 if (res == 0) {
1173 * fan data available through lom, remove any placeholder
1174 * fan-unit nodes, they will be superseded via lom.conf
1176 char path[80];
1177 int slot;
1178 picl_nodehdl_t fan_unit_h;
1180 for (slot = 0; slot < MAX_FANS; slot++) {
1181 (void) snprintf(path, sizeof (path),
1182 "/frutree/chassis/fan-slot?Slot=%d/fan-unit", slot);
1183 if (ptree_get_node_by_path(path, &fan_unit_h) !=
1184 PICL_SUCCESS)
1185 continue;
1186 if (ptree_delete_node(fan_unit_h) != PICL_SUCCESS)
1187 continue;
1188 (void) ptree_destroy_node(fan_unit_h);
1191 * see if fan names can be obtained
1193 (void) memset(&info2data, 0, sizeof (info2data));
1195 * if LOMIOCINFO2 not supported, names area
1196 * will remain empty
1198 (void) ioctl(lom_fd, LOMIOCINFO2, &info2data);
1201 * for each fan which is present, add a fan node
1203 for (i = 0; i < MAX_FANS; i++) {
1204 char fanname[80];
1205 picl_nodehdl_t fanh;
1206 picl_nodehdl_t proph;
1208 if (fandata.fitted[i] == 0)
1209 continue;
1211 if (info2data.fan_names[i][0] == '\0') {
1212 (void) snprintf(fanname, sizeof (fanname),
1213 "fan%d", i + 1);
1214 } else {
1215 (void) strlcpy(fanname, info2data.fan_names[i],
1216 sizeof (fanname));
1218 convert_node_name(fanname);
1219 err = ptree_create_node(fanname, PICL_CLASS_FAN, &fanh);
1220 if (err != PICL_SUCCESS)
1221 break;
1223 err = add_volatile_prop(fanh, PICL_PROP_FAN_SPEED,
1224 PICL_PTYPE_INT, PICL_READ, sizeof (int),
1225 read_fan_speed, NULL, &fan_speed_handles[i]);
1226 if (err != PICL_SUCCESS)
1227 break;
1229 err = add_regular_prop(fanh, PICL_PROP_LOW_WARNING,
1230 PICL_PTYPE_INT, PICL_READ, sizeof (int),
1231 &fandata.minspeed[i], &proph);
1232 if (err != PICL_SUCCESS)
1233 break;
1235 err = add_regular_prop(fanh, PICL_PROP_FAN_SPEED_UNIT,
1236 PICL_PTYPE_CHARSTRING, PICL_READ, sizeof ("%"),
1237 "%", &proph);
1238 if (err != PICL_SUCCESS)
1239 break;
1241 err = add_volatile_prop(fanh, PICL_PROP_CONDITION,
1242 PICL_PTYPE_CHARSTRING, PICL_READ,
1243 sizeof (str_FAIL), read_fan_status, NULL,
1244 &fan_status_handles[i]);
1245 if (err != PICL_SUCCESS)
1246 break;
1249 * add a label for prtdiag
1251 err = add_regular_prop(fanh, PICL_PROP_LABEL,
1252 PICL_PTYPE_CHARSTRING, PICL_READ,
1253 strlen(fanname) + 1, fanname, &proph);
1254 if (err != PICL_SUCCESS)
1255 break;
1257 err = ptree_add_node(lominfh, fanh);
1258 if (err != PICL_SUCCESS)
1259 break;
1262 if (err != PICL_SUCCESS) {
1263 syslog(LOG_ERR, EM_LOMINFO_TREE_FAILED);
1267 return (err);
1270 static void
1271 setup_strings()
1274 * initialise led colours lookup
1276 int i;
1277 int lim = sizeof (colour_lkup) / sizeof (colour_lkup[0]);
1279 for (i = 0; i < lim; i++) {
1280 free(colour_lkup[i].str_colour);
1283 colour_lkup[LOM_LED_COLOUR_ANY].str_colour = strdup(gettext("any"));
1284 colour_lkup[LOM_LED_COLOUR_WHITE].str_colour = strdup(gettext("white"));
1285 colour_lkup[LOM_LED_COLOUR_BLUE].str_colour = strdup(gettext("blue"));
1286 colour_lkup[LOM_LED_COLOUR_GREEN].str_colour = strdup(gettext("green"));
1287 colour_lkup[LOM_LED_COLOUR_AMBER].str_colour = strdup(gettext("amber"));
1289 for (i = 0; i < lim; i++) {
1290 if (colour_lkup[i].str_colour != NULL)
1291 colour_lkup[i].size =
1292 1 + strlen(colour_lkup[i].str_colour);
1296 * initialise led state lookup strings
1298 fixstate(LOM_LED_OFF, gettext("off"), &max_state_size);
1299 fixstate(LOM_LED_ON, gettext("on"), &max_state_size);
1300 fixstate(LOM_LED_BLINKING, gettext("blinking"), &max_state_size);
1304 * The size of outfilename must be PATH_MAX
1306 static int
1307 get_config_file(char *outfilename)
1309 char nmbuf[SYS_NMLN];
1310 char pname[PATH_MAX];
1312 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
1313 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
1314 (void) strlcat(pname, LOM_CONFFILE_NAME, PATH_MAX);
1315 if (access(pname, R_OK) == 0) {
1316 (void) strlcpy(outfilename, pname, PATH_MAX);
1317 return (0);
1321 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
1322 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
1323 (void) strlcat(pname, LOM_CONFFILE_NAME, PATH_MAX);
1324 if (access(pname, R_OK) == 0) {
1325 (void) strlcpy(outfilename, pname, PATH_MAX);
1326 return (0);
1330 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR,
1331 LOM_CONFFILE_NAME);
1333 if (access(pname, R_OK) == 0) {
1334 (void) strlcpy(outfilename, pname, PATH_MAX);
1335 return (0);
1338 return (-1);
1344 * executed as part of .init when the plugin is dlopen()ed
1346 static void
1347 picllom_register(void)
1349 (void) picld_plugin_register(&my_reg_info);
1353 * Init entry point of the plugin
1354 * Creates the PICL nodes and properties in the physical and logical aspects.
1356 static void
1357 picllom_init(void)
1359 picl_nodehdl_t rooth;
1360 picl_nodehdl_t plfh;
1361 picl_nodehdl_t lominfh;
1362 int lom_fd;
1363 char fullfilename[PATH_MAX];
1366 * Get platform node
1368 if (ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM, &plfh)
1369 != PICL_SUCCESS) {
1370 syslog(LOG_ERR, EM_MISSING_NODE, PICL_NODE_PLATFORM);
1371 syslog(LOG_ERR, EM_INIT_FAILED);
1372 return;
1376 * Get lom node
1378 if (get_lom_node(&lominfh) != PICL_SUCCESS) {
1379 syslog(LOG_ERR, EM_LOM_NODE_MISSING);
1380 syslog(LOG_ERR, EM_INIT_FAILED);
1381 return;
1385 * Retrive the device path to open
1387 if (get_lom_device_path(&lominfh) < 0) {
1388 syslog(LOG_ERR, EM_INIT_FAILED);
1389 return;
1393 * Open LOM device and interrogate for devices it monitors
1395 if ((lom_fd = open(lom_device_path, O_RDONLY)) < 0) {
1396 syslog(LOG_ERR, EM_SYS_ERR, lom_device_path, strerror(errno));
1397 return;
1400 setup_strings();
1401 (void) add_temp_sensors(lom_fd, lominfh);
1402 (void) add_voltage_monitors(lom_fd, lominfh);
1403 (void) add_fan_nodes(lom_fd, lominfh);
1404 add_led_nodes(lom_fd, lominfh);
1407 if (get_config_file(fullfilename) < 0) {
1408 (void) close(lom_fd);
1409 syslog(LOG_ERR, EM_NO_CONFIG);
1410 return;
1413 if (ptree_get_root(&rooth) != PICL_SUCCESS) {
1414 (void) close(lom_fd);
1415 return;
1418 if (picld_pluginutil_parse_config_file(rooth, fullfilename) !=
1419 PICL_SUCCESS)
1420 syslog(LOG_ERR, EM_INIT_FAILED);
1422 (void) close(lom_fd);
1426 * fini entry point of the plugin
1428 static void
1429 picllom_fini(void)