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