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]
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.
41 * Depends on PICL devtree plugin.
57 #include <sys/types.h>
58 #include <sys/obpdefs.h>
59 #include <sys/lom_io.h>
60 #include <sys/systeminfo.h>
63 #include <picld_pluginutil.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
,
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
,
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
;
142 } colour_lkup
[1 + LOM_LED_COLOUR_AMBER
];
147 } ledstate_lkup
[] = {
150 { LOM_LED_BLINKING
},
154 create_node_el(picl_nodehdl_t nodeh
)
156 node_el_t
*ptr
= malloc(sizeof (node_el_t
));
167 delete_node_el(node_el_t
*pel
)
175 node_list_t
*ptr
= malloc(sizeof (node_list_t
));
186 delete_node_list_contents(node_list_t
*pnl
)
193 while ((pel
= pnl
->head
) != NULL
) {
194 pnl
->head
= pel
->next
;
202 delete_node_list(node_list_t
*pnl
)
204 delete_node_list_contents(pnl
);
209 * Get a linking element and add handle to end of chain
212 add_node_to_list(picl_nodehdl_t nodeh
, node_list_t
*listp
)
214 node_el_t
*pel
= create_node_el(nodeh
);
217 if (listp
->tail
== NULL
)
220 listp
->tail
->next
= 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
232 get_node_list_by_class(picl_nodehdl_t nodeh
, const char *classname
,
236 char clname
[PICL_CLASSNAMELEN_MAX
+1];
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
);
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
));
260 get_lom_node(picl_nodehdl_t
*lominfh
)
262 int err
= PICL_SUCCESS
;
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
) {
278 syslog(LOG_ERR
, EM_MISSING_NODE
, PICL_CLASS_SERVICE_PROCESSOR
);
279 err
= PICL_NODENOTFOUND
;
281 *lominfh
= listp
->head
->nodeh
;
283 if (listp
->head
!= listp
->tail
)
284 syslog(LOG_ERR
, EM_LOM_DUPLICATE
);
287 delete_node_list(listp
);
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
);
315 * Look for a node of specified name and class
316 * Confine search to nodes one level below that of supplied handle
319 get_node_by_name_and_class(picl_nodehdl_t srchnodeh
, const char *nodename
,
320 const char *classname
, picl_nodehdl_t
*chdh
)
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
,
331 if (err
!= PICL_SUCCESS
)
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
));
348 * Create and add the specified regular property
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
)
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
)
364 err
= ptree_create_and_add_prop(nodeh
, &propinfo
, (void *)valbuf
,
366 if (err
== PICL_SUCCESS
&& prophp
)
373 * Create and add the specified volatile property
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
)
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
)
389 err
= ptree_create_and_add_prop(nodeh
, &propinfo
, NULL
, &proph
);
390 if (err
== PICL_SUCCESS
&& prophp
)
396 * open LOM device to read
399 open_lom_rd(int *lom_fd
)
401 *lom_fd
= open(lom_device_path
, O_RDONLY
);
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.
414 get_lom_temp(int index
, tempr_t
*temp_p
)
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
);
428 *temp_p
= lom_temp
.temp
[index
];
438 * Function to open LOM and read voltage monitor values.
439 * Called for each property, so only perform update if time has changed
442 update_voltage_stats()
444 static time_t then
= 0;
448 time_t now
= time(NULL
);
451 return (PICL_SUCCESS
);
454 err
= open_lom_rd(&lom_fd
);
456 if (err
== PICL_SUCCESS
) {
457 res
= ioctl(lom_fd
, LOMIOCVOLTS
, &voltsdata
);
458 (void) close(lom_fd
);
468 * Function to open LOM and read voltage monitor values.
469 * The index to a specific voltage status is supplied and that value returned.
472 get_lom_volts_status(int index
, int *voltsStatus_p
)
476 if ((res
= update_voltage_stats()) != PICL_SUCCESS
)
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.
488 get_lom_volts_shutdown(int index
, int *voltsShutdown_p
)
492 if ((res
= update_voltage_stats()) != PICL_SUCCESS
)
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
508 static time_t then
= 0;
512 time_t now
= time(NULL
);
515 return (PICL_SUCCESS
);
518 err
= open_lom_rd(&lom_fd
);
519 if (err
== PICL_SUCCESS
) {
520 res
= ioctl(lom_fd
, LOMIOCFANSTATE
, &fandata
);
521 (void) close(lom_fd
);
533 * The index to a specific fan is supplied and its speed value returned.
536 get_lom_fan_speed(int index
, int *fan_speed
)
540 if ((res
= update_fan_stats()) != PICL_SUCCESS
)
543 *fan_speed
= fandata
.speed
[index
];
544 return (PICL_SUCCESS
);
549 * Read function for volatile "Temperature" property via LOM
552 read_vol_temp(ptree_rarg_t
*parg
, void *buf
)
555 picl_prophdl_t proph
;
559 * get the sensor index from the displacement of the
560 * property handle and get its temperature.
563 for (index
= 0; index
< MAX_TEMPS
; index
++) {
564 if (temp_handles
[index
] == proph
)
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
586 read_vol_volts_status(ptree_rarg_t
*parg
, void *buf
)
589 picl_prophdl_t proph
;
593 * get the voltage monitor index from the displacement of the
594 * status property handle and get its status.
598 for (index
= 0; index
< MAX_VOLTS
; index
++) {
599 if (volts_status_handles
[index
] == proph
)
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
,
611 return (PICL_SUCCESS
);
615 * Read function for volatile "VoltageShutdown" property via LOM
618 read_vol_volts_shutdown(ptree_rarg_t
*parg
, void *buf
)
621 picl_prophdl_t proph
;
625 * get the voltage monitor index from the displacement of the
626 * shutdown property handle and get its value.
630 for (index
= 0; index
< MAX_VOLTS
; index
++) {
631 if (volts_shutdown_handles
[index
] == proph
)
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
651 read_fan_speed(ptree_rarg_t
*parg
, void *buf
)
654 picl_prophdl_t proph
;
658 * get the relevant fan from the displacement of its property handle
662 for (index
= 0; index
< MAX_FANS
; index
++) {
663 if (fan_speed_handles
[index
] == proph
)
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
681 lookup_led_status(int8_t state
, const char **string
)
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
);
695 case LOM_LED_ACCESS_ERROR
:
696 return (PICL_PROPVALUNAVAILABLE
);
697 case LOM_LED_NOT_IMPLEMENTED
:
699 case LOM_LED_OUTOFRANGE
:
702 return (PICL_FAILURE
);
707 * Read function for volatile led status property.
710 read_led_status(ptree_rarg_t
*parg
, void *buf
)
712 lom_led_state_t led_data
;
713 picl_prophdl_t proph
;
720 * get the relevant led from the displacement of its property handle
724 for (index
= 0; index
< n_leds
; index
++) {
725 if (led_handles
[index
] == proph
)
730 return (PICL_FAILURE
);
732 res
= open_lom_rd(&lom_fd
);
733 if (res
!= PICL_SUCCESS
)
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
760 (void) memset(&led_data
, 0, sizeof (led_data
));
762 res
= ioctl(lom_fd
, LOMIOCLEDSTATE
, &led_data
);
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) {
772 for (i
= 0; i
< n
; i
++) {
773 (void) memset(&led_data
, 0, sizeof (led_data
));
775 res
= ioctl(lom_fd
, LOMIOCLEDSTATE
, &led_data
);
778 led_data
.state
!= LOM_LED_NOT_IMPLEMENTED
||
779 strcmp(led_data
.label
, led_labels
[index
]) ==
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
);
802 * Read function for volatile fan status property.
803 * This is a synthesized property using speed and min speed properties
806 read_fan_status(ptree_rarg_t
*parg
, void *buf
)
809 picl_prophdl_t proph
;
813 * get the relevant fan from the displacement of its property handle
817 for (index
= 0; index
< MAX_FANS
; index
++) {
818 if (fan_status_handles
[index
] == proph
)
822 if (index
== MAX_FANS
)
823 return (PICL_FAILURE
);
825 if (get_lom_fan_speed(index
, &fan_speed
) != PICL_SUCCESS
)
826 return (PICL_FAILURE
);
829 fan_speed
< fandata
.minspeed
[index
] ? str_FAIL
: str_OK
,
831 return (PICL_SUCCESS
);
837 * change to lower case and convert any spaces into hyphens
840 convert_node_name(char *ptr
)
844 for (ch
= *ptr
; ch
!= '\0'; ch
= *++ptr
) {
847 } else if (isspace(ch
)) {
854 add_temp_sensors(int lom_fd
, picl_nodehdl_t lominfh
)
859 int err
= PICL_SUCCESS
;
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
)
882 err
= add_volatile_prop(tempsensh
,
883 PICL_PROP_TEMPERATURE
, PICL_PTYPE_INT
, PICL_READ
,
884 sizeof (tempr_t
), read_vol_temp
, NULL
,
886 if (err
!= PICL_SUCCESS
)
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
],
895 if (err
!= PICL_SUCCESS
)
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
],
905 if (err
!= PICL_SUCCESS
)
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
) !=
915 (strcasestr(lom_temp
.name
[i
], CPU_AMBIENT
) !=
918 } else if ((cptr
= strcasestr(lom_temp
.name
[i
],
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
) {
934 err
= ptree_add_node(lominfh
, tempsensh
);
936 if (err
!= PICL_SUCCESS
)
940 if (err
!= PICL_SUCCESS
) {
941 syslog(LOG_ERR
, EM_LOMINFO_TREE_FAILED
);
949 add_voltage_monitors(int lom_fd
, picl_nodehdl_t lominfh
)
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
)
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
)
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
)
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
)
993 err
= ptree_add_node(lominfh
, voltsmonh
);
995 if (err
!= PICL_SUCCESS
)
999 if (err
!= PICL_SUCCESS
) {
1000 syslog(LOG_ERR
, EM_LOMINFO_TREE_FAILED
);
1008 add_led(const lom_led_state_t
*led_state
, picl_nodehdl_t lominfh
)
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')) {
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
)
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
)
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
)
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
)
1055 err
= ptree_add_node(lominfh
, ledh
);
1057 if (err
!= PICL_SUCCESS
) {
1058 syslog(LOG_ERR
, EM_LOMINFO_TREE_FAILED
);
1063 fixstate(uint8_t state
, const char *string
, int *max_len
)
1068 for (i
= 0; i
< (sizeof (ledstate_lkup
) / sizeof (ledstate_lkup
[0]));
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
)
1082 add_led_nodes(int lom_fd
, picl_nodehdl_t lominfh
)
1084 lom_led_state_t led_data
;
1085 picl_nodehdl_t ledh
;
1090 * If the led state enquiry ioctl is supported, an enquiry on
1091 * index -1 will return the state of the highest supported index
1094 (void) memset(&led_data
, 0, sizeof (led_data
));
1095 led_data
.index
= -1;
1096 res
= ioctl(lom_fd
, LOMIOCLEDSTATE
, &led_data
);
1101 if (led_labels
!= NULL
) {
1102 for (i
= 0; i
< n_leds
; i
++) {
1103 if (led_labels
[i
] != NULL
) {
1104 free(led_labels
[i
]);
1112 if (led_handles
!= NULL
) {
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
)) {
1125 syslog(LOG_ERR
, EM_NO_LED_MEM
);
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
));
1138 res
= ioctl(lom_fd
, LOMIOCLEDSTATE
, &led_data
);
1143 if (led_data
.state
== LOM_LED_OUTOFRANGE
||
1144 led_data
.state
== LOM_LED_NOT_IMPLEMENTED
)
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
);
1163 add_fan_nodes(int lom_fd
, picl_nodehdl_t lominfh
)
1167 int err
= PICL_SUCCESS
;
1169 res
= ioctl(lom_fd
, LOMIOCFANSTATE
, &fandata
);
1173 * fan data available through lom, remove any placeholder
1174 * fan-unit nodes, they will be superseded via lom.conf
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
) !=
1186 if (ptree_delete_node(fan_unit_h
) != PICL_SUCCESS
)
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
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
++) {
1205 picl_nodehdl_t fanh
;
1206 picl_nodehdl_t proph
;
1208 if (fandata
.fitted
[i
] == 0)
1211 if (info2data
.fan_names
[i
][0] == '\0') {
1212 (void) snprintf(fanname
, sizeof (fanname
),
1215 (void) strlcpy(fanname
, info2data
.fan_names
[i
],
1218 convert_node_name(fanname
);
1219 err
= ptree_create_node(fanname
, PICL_CLASS_FAN
, &fanh
);
1220 if (err
!= PICL_SUCCESS
)
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
)
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
)
1235 err
= add_regular_prop(fanh
, PICL_PROP_FAN_SPEED_UNIT
,
1236 PICL_PTYPE_CHARSTRING
, PICL_READ
, sizeof ("%"),
1238 if (err
!= PICL_SUCCESS
)
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
)
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
)
1257 err
= ptree_add_node(lominfh
, fanh
);
1258 if (err
!= PICL_SUCCESS
)
1262 if (err
!= PICL_SUCCESS
) {
1263 syslog(LOG_ERR
, EM_LOMINFO_TREE_FAILED
);
1274 * initialise led colours lookup
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
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
);
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
);
1330 (void) snprintf(pname
, PATH_MAX
, "%s/%s", PICLD_COMMON_PLUGIN_DIR
,
1333 if (access(pname
, R_OK
) == 0) {
1334 (void) strlcpy(outfilename
, pname
, PATH_MAX
);
1344 * executed as part of .init when the plugin is dlopen()ed
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.
1359 picl_nodehdl_t rooth
;
1360 picl_nodehdl_t plfh
;
1361 picl_nodehdl_t lominfh
;
1363 char fullfilename
[PATH_MAX
];
1368 if (ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM
, &plfh
)
1370 syslog(LOG_ERR
, EM_MISSING_NODE
, PICL_NODE_PLATFORM
);
1371 syslog(LOG_ERR
, EM_INIT_FAILED
);
1378 if (get_lom_node(&lominfh
) != PICL_SUCCESS
) {
1379 syslog(LOG_ERR
, EM_LOM_NODE_MISSING
);
1380 syslog(LOG_ERR
, EM_INIT_FAILED
);
1385 * Retrive the device path to open
1387 if (get_lom_device_path(&lominfh
) < 0) {
1388 syslog(LOG_ERR
, EM_INIT_FAILED
);
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
));
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
);
1413 if (ptree_get_root(&rooth
) != PICL_SUCCESS
) {
1414 (void) close(lom_fd
);
1418 if (picld_pluginutil_parse_config_file(rooth
, fullfilename
) !=
1420 syslog(LOG_ERR
, EM_INIT_FAILED
);
1422 (void) close(lom_fd
);
1426 * fini entry point of the plugin