xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4u/chicago/envd/piclenvsetup.c (revision 16ade92d9ce9c9ab33a25f7a2fdd00b581b6efda)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * This file contains code for setting up environmental related nodes
31  * and properties in the PICL tree.
32  *
33  */
34 
35 #include <stdio.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <syslog.h>
39 #include <stdlib.h>
40 #include <limits.h>
41 #include <errno.h>
42 #include <sys/open.h>
43 #include <ctype.h>
44 #include <string.h>
45 #include <alloca.h>
46 #include <libintl.h>
47 #include <sys/systeminfo.h>
48 #include <picl.h>
49 #include <picltree.h>
50 #include <picld_pluginutil.h>
51 #include <pthread.h>
52 #include <sys/utsname.h>
53 #include <sys/systeminfo.h>
54 #include "picldefs.h"
55 #include "envd.h"
56 
57 /*
58  * Volatile property read/write function typedef
59  */
60 typedef int ptree_vol_rdfunc_t(ptree_rarg_t *parg, void *buf);
61 typedef int ptree_vol_wrfunc_t(ptree_warg_t *parg, const void *buf);
62 
63 extern int disk_temp_monitor;
64 extern env_tuneable_t	tuneables[];
65 extern	int errno;
66 extern	int	ntuneables;
67 #define	PROP_FAN_SPEED_UNIT_VALUE	"rpm"
68 
69 /*
70  * Sensor node data structure
71  */
72 typedef struct {
73 	char		*parent_path;	/* parent path */
74 	char		*sensor_name;	/* sensor name */
75 	env_sensor_t	*sensorp;	/* sensor info */
76 	picl_nodehdl_t	nodeh;		/* sensor node handle */
77 	picl_prophdl_t	proph;		/* "Temperature" property handle */
78 	picl_prophdl_t	target_proph;	/* "TargetTemp" property handle */
79 } sensor_node_t;
80 
81 /*
82  * Sensor nodes array
83  */
84 static sensor_node_t sensor_nodes[] = {
85 	{"/platform/ebus@1f,464000/env-monitor@3,0", SENSOR_CPU0,
86 	NULL, NULL, NULL, NULL},
87 	{"/platform/ebus@1f,464000/env-monitor@3,0", SENSOR_CPU1,
88 	NULL, NULL, NULL, NULL},
89 	{"/platform/ebus@1f,464000/env-monitor@3,0", SENSOR_MB,
90 	NULL, NULL, NULL, NULL},
91 	{"/platform/ebus@1f,464000/env-monitor@3,0", SENSOR_ADT7462,
92 	NULL, NULL, NULL, NULL},
93 	{"/platform/ebus@1f,464000/env-monitor@3,0", SENSOR_LM95221,
94 	NULL, NULL, NULL, NULL},
95 	{"/platform/ebus@1f,464000/env-monitor@3,0", SENSOR_FIRE,
96 	NULL, NULL, NULL, NULL},
97 	{"/platform/ebus@1f,464000/env-monitor@3,0", SENSOR_LSI1064,
98 	NULL, NULL, NULL, NULL},
99 	{"/platform/ebus@1f,464000/env-monitor@3,0", SENSOR_FRONT_PANEL,
100 	NULL, NULL, NULL, NULL}
101 };
102 #define	N_SENSOR_NODES	(sizeof (sensor_nodes)/sizeof (sensor_nodes[0]))
103 
104 /*
105  * Fan node data structure
106  */
107 typedef struct {
108 	char		*parent_path;	/* parent node path */
109 	char		*fan_name;	/* fan name */
110 	env_fan_t 	*fanp;		/* fan information */
111 	char		*speed_unit;	/* speed unit string */
112 	picl_nodehdl_t	nodeh;		/* "fan" node handle */
113 	picl_prophdl_t	proph;		/* "Speed" property handle */
114 } fan_node_t;
115 
116 /*
117  * Fan node array
118  */
119 static fan_node_t fan_nodes[] =  {
120 	{"/platform/ebus@1f,464000/env-monitor@3,0", ENV_SYSTEM_FAN0,
121 	NULL, PROP_FAN_SPEED_UNIT_VALUE, NULL, NULL},
122 	{"/platform/ebus@1f,464000/env-monitor@3,0", ENV_SYSTEM_FAN1,
123 	NULL, PROP_FAN_SPEED_UNIT_VALUE, NULL, NULL},
124 	{"/platform/ebus@1f,464000/env-monitor@3,0", ENV_SYSTEM_FAN2,
125 	NULL, PROP_FAN_SPEED_UNIT_VALUE, NULL, NULL},
126 	{"/platform/ebus@1f,464000/env-monitor@3,0", ENV_SYSTEM_FAN3,
127 	NULL, PROP_FAN_SPEED_UNIT_VALUE, NULL, NULL},
128 	{"/platform/ebus@1f,464000/env-monitor@3,0", ENV_SYSTEM_FAN4,
129 	NULL, PROP_FAN_SPEED_UNIT_VALUE, NULL, NULL}
130 };
131 #define	N_FAN_NODES	(sizeof (fan_nodes)/sizeof (fan_nodes[0]))
132 
133 /*
134  * Disk node data structure
135  */
136 typedef struct {
137 	char		*parent_path;	/* parent node path */
138 	char		*disk_name;	/* disk name */
139 	env_disk_t 	*diskp;		/* disk information */
140 	picl_nodehdl_t	nodeh;		/* "disk" node handle */
141 	picl_prophdl_t	proph;		/* "Temperature" property handle */
142 } disk_node_t;
143 
144 /*
145  * Disk node array
146  */
147 static disk_node_t disk_nodes[] =  {
148 	{DISK0_NODE_PATH, ENV_DISK0, NULL, NULL, NULL},
149 	{DISK1_NODE_PATH, ENV_DISK1, NULL, NULL, NULL},
150 	{DISK2_NODE_PATH, ENV_DISK2, NULL, NULL, NULL},
151 	{DISK3_NODE_PATH, ENV_DISK3, NULL, NULL, NULL}
152 };
153 #define	N_DISK_NODES	(sizeof (disk_nodes)/sizeof (disk_nodes[0]))
154 
155 /*
156  * Miscellaneous declarations
157  */
158 static void delete_sensor_nodes_and_props(void);
159 static void delete_disk_nodes_and_props(void);
160 static void delete_fan_nodes_and_props(void);
161 
162 
163 /*
164  * Read function for volatile "Temperature" property
165  */
166 static int
167 get_current_temp(ptree_rarg_t *parg, void *buf)
168 {
169 	tempr_t 	temp;
170 	picl_prophdl_t	proph;
171 	sensor_node_t	*snodep;
172 	int		i;
173 
174 	/*
175 	 * Locate the sensor in our sensor_nodes table by matching the
176 	 * property handle and get its temperature.
177 	 */
178 	proph = parg->proph;
179 	for (i = 0; i < N_SENSOR_NODES; i++) {
180 		snodep = &sensor_nodes[i];
181 		if (snodep->proph != proph)
182 			continue;
183 
184 		if (get_temperature(snodep->sensorp, &temp) < 0)
185 			break;
186 		(void) memcpy(buf, (caddr_t)&temp, sizeof (tempr_t));
187 		return (PICL_SUCCESS);
188 	}
189 	return (PICL_FAILURE);
190 }
191 
192 /*
193  * Read function for volatile "Temperature" property
194  */
195 static int
196 get_disk_temp(ptree_rarg_t *parg, void *buf)
197 {
198 	tempr_t 	temp;
199 	picl_prophdl_t	proph;
200 	disk_node_t	*dnodep;
201 	int		i;
202 
203 	/*
204 	 * Locate the sensor in our sensor_nodes table by matching the
205 	 * property handle and get its temperature.
206 	 */
207 	proph = parg->proph;
208 	for (i = 0; i < N_DISK_NODES; i++) {
209 		dnodep = &disk_nodes[i];
210 		if (dnodep->proph != proph)
211 			continue;
212 
213 		if (disk_temperature(dnodep->diskp, &temp) < 0)
214 			break;
215 		(void) memcpy(buf, (caddr_t)&temp, sizeof (tempr_t));
216 		return (PICL_SUCCESS);
217 	}
218 	return (PICL_FAILURE);
219 }
220 
221 /*
222  * Read function for volatile "Speed" property on "fan" class node
223  */
224 static int
225 set_current_speed(ptree_warg_t *parg, const void *buf)
226 {
227 	fanspeed_t	speed;
228 	picl_prophdl_t	proph;
229 	fan_node_t	*fnodep;
230 	int		i, ret;
231 
232 	/*
233 	 * Locate the fan in our fan_nodes table by matching the
234 	 * property handle and get fan speed.
235 	 */
236 	proph = parg->proph;
237 	for (i = 0; i < N_FAN_NODES; i++) {
238 		fnodep = &fan_nodes[i];
239 		if (fnodep->proph != proph)
240 			continue;
241 		if (fnodep->fanp->fd == -1)
242 			continue;
243 
244 		(void) memcpy((caddr_t)&speed, buf, sizeof (speed));
245 
246 		ret = set_fan_speed(fnodep->fanp, speed);
247 
248 		if (ret < 0) {
249 			if (ret == -1 && errno == EBUSY)
250 				return (PICL_NOTWRITABLE);
251 			if (ret == -2)
252 				return (PICL_INVALIDARG);
253 			break;
254 		}
255 
256 
257 		return (PICL_SUCCESS);
258 	}
259 	return (PICL_FAILURE);
260 }
261 
262 
263 /*
264  * Read function for volatile "Speed" property on "fan" class node
265  */
266 static int
267 get_current_speed(ptree_rarg_t *parg, void *buf)
268 {
269 	fanspeed_t	speed;
270 	picl_prophdl_t	proph;
271 	fan_node_t	*fnodep;
272 	int		i;
273 
274 	/*
275 	 * Locate the fan in our fan_nodes table by matching the
276 	 * property handle and get fan speed.
277 	 */
278 	proph = parg->proph;
279 	for (i = 0; i < N_FAN_NODES; i++) {
280 		fnodep = &fan_nodes[i];
281 		if (fnodep->proph != proph)
282 			continue;
283 		if (fnodep->fanp->fd == -1)
284 			continue;
285 		if (get_fan_speed(fnodep->fanp, &speed) < 0)
286 			break;
287 
288 		(void) memcpy(buf, (caddr_t)&speed, sizeof (speed));
289 		return (PICL_SUCCESS);
290 	}
291 	return (PICL_FAILURE);
292 }
293 
294 /*
295  * Create and add the specified regular property
296  */
297 
298 static int
299 add_regular_prop(picl_nodehdl_t nodeh, char *name, int type, int access,
300     int size, void *valbuf, picl_prophdl_t *prophp)
301 {
302 	int			err;
303 	ptree_propinfo_t	propinfo;
304 	picl_prophdl_t		proph;
305 
306 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
307 	    type, access, size, name, NULL, NULL);
308 	if (err != PICL_SUCCESS)
309 		return (err);
310 
311 	err = ptree_create_and_add_prop(nodeh, &propinfo, valbuf, &proph);
312 	if (err == PICL_SUCCESS && prophp)
313 		*prophp = proph;
314 	return (err);
315 }
316 
317 
318 /*
319  * Create and add the specified volatile property
320  */
321 static int
322 add_volatile_prop(picl_nodehdl_t nodeh, char *name, int type, int access,
323     int size, ptree_vol_rdfunc_t *rdfunc, ptree_vol_wrfunc_t *wrfunc,
324     picl_prophdl_t *prophp)
325 {
326 	int			err;
327 	ptree_propinfo_t	propinfo;
328 	picl_prophdl_t		proph;
329 
330 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
331 	    type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc);
332 	if (err != PICL_SUCCESS)
333 		return (err);
334 
335 	err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph);
336 	if (err == PICL_SUCCESS && prophp)
337 		*prophp = proph;
338 	return (err);
339 }
340 
341 /*
342  * Add temperature threshold properties
343  */
344 static void
345 add_sensor_thresh_props(picl_nodehdl_t nodeh, env_sensor_t *sensorp)
346 {
347 	picl_prophdl_t	proph;
348 
349 	(void) add_regular_prop(nodeh, PICL_PROP_LOW_POWER_OFF,
350 	    PICL_PTYPE_INT, PICL_READ,
351 	    sizeof (sensorp->low_power_off),
352 	    (void *)&(sensorp->low_power_off), &proph);
353 
354 	(void) add_regular_prop(nodeh, PICL_PROP_LOW_SHUTDOWN,
355 	    PICL_PTYPE_INT, PICL_READ,
356 	    sizeof (sensorp->low_shutdown),
357 	    (void *)&(sensorp->low_shutdown), &proph);
358 
359 	(void) add_regular_prop(nodeh, PICL_PROP_LOW_WARNING,
360 	    PICL_PTYPE_INT, PICL_READ,
361 	    sizeof (sensorp->low_warning),
362 	    (void *)&(sensorp->low_warning), &proph);
363 
364 	(void) add_regular_prop(nodeh, PICL_PROP_HIGH_WARNING,
365 	    PICL_PTYPE_INT, PICL_READ,
366 	    sizeof (sensorp->high_warning),
367 	    (void *)&(sensorp->high_warning), &proph);
368 
369 	(void) add_regular_prop(nodeh, PICL_PROP_HIGH_SHUTDOWN,
370 	    PICL_PTYPE_INT, PICL_READ,
371 	    sizeof (sensorp->high_shutdown),
372 	    (void *)&(sensorp->high_shutdown), &proph);
373 
374 	(void) add_regular_prop(nodeh, PICL_PROP_HIGH_POWER_OFF,
375 	    PICL_PTYPE_INT, PICL_READ,
376 	    sizeof (sensorp->high_power_off),
377 	    (void *)&(sensorp->high_power_off), &proph);
378 }
379 
380 
381 /*
382  * Go through the sensor_nodes array and create those nodes
383  * and the Temperature property to report the temperature.
384  */
385 static int
386 add_sensor_nodes_and_props()
387 {
388 	int		err;
389 	char		*pname, *nodename, *devfs_path;
390 	sensor_node_t	*snodep;
391 	picl_nodehdl_t	nodeh, cnodeh;
392 	picl_prophdl_t	proph;
393 	env_sensor_t	*sensorp;
394 	int		i;
395 
396 	for (i = 0; i < N_SENSOR_NODES; i++) {
397 		snodep = &sensor_nodes[i];
398 		/*
399 		 * Get the parent nodeh
400 		 */
401 		err = ptree_get_node_by_path(snodep->parent_path, &nodeh);
402 		if (err != PICL_SUCCESS) {
403 		if (env_debug)
404 			envd_log(LOG_ERR, "failed to get_node_by_path %s\n",
405 			    snodep->parent_path);
406 			continue;
407 		}
408 		sensorp = snodep->sensorp;
409 		if (sensorp == NULL)
410 			continue;
411 		if (sensorp->present == B_FALSE)
412 			continue;
413 		/*
414 		 * Create temperature-sensor node
415 		 */
416 		nodename = snodep->sensor_name;
417 		err = ptree_create_and_add_node(nodeh, nodename,
418 		    PICL_CLASS_TEMPERATURE_SENSOR, &cnodeh);
419 		if (env_debug)
420 			envd_log(LOG_ERR,
421 			    "Creating PICL sensor node '%s' err:%d\n",
422 			    nodename, err);
423 		if (err != PICL_SUCCESS)
424 			break;
425 
426 		/* save node handle */
427 		snodep->nodeh = cnodeh;
428 
429 		/*
430 		 * Add "devfs_path" property in child node
431 		 */
432 		devfs_path = sensorp->devfs_path;
433 		pname = PICL_PROP_DEVFS_PATH;
434 		err = add_regular_prop(cnodeh, pname,
435 		    PICL_PTYPE_CHARSTRING, PICL_READ,
436 		    strlen(devfs_path)+1, (void *)devfs_path, &proph);
437 		if (err != PICL_SUCCESS)
438 			break;
439 
440 		/*
441 		 * Now add volatile "temperature" volatile property
442 		 * in this "temperature-sensor" class node.
443 		 */
444 		pname = PICL_PROP_TEMPERATURE;
445 		err = add_volatile_prop(cnodeh, pname,
446 		    PICL_PTYPE_INT, PICL_READ, sizeof (tempr_t),
447 		    get_current_temp, NULL, &proph);
448 		if (err != PICL_SUCCESS)
449 			break;
450 
451 		/* Save prop handle */
452 		snodep->proph = proph;
453 
454 		/*
455 		 * Add threshold related properties
456 		 */
457 
458 		add_sensor_thresh_props(cnodeh, sensorp);
459 
460 	}
461 	if (err != PICL_SUCCESS) {
462 		delete_sensor_nodes_and_props();
463 		if (env_debug)
464 			envd_log(LOG_INFO,
465 			    "Can't create prop/node for sensor '%s'\n",
466 			    nodename);
467 		return (err);
468 	}
469 	return (PICL_SUCCESS);
470 }
471 
472 /*
473  * Delete all sensor nodes and related properties created by the
474  * add_sensor_prop() for each sensor node in the PICL tree.
475  */
476 static void
477 delete_sensor_nodes_and_props(void)
478 {
479 	sensor_node_t	*snodep;
480 	int		i;
481 
482 	/*
483 	 * Delete/destroy any property created in the sensed device
484 	 * as well as the sensor node and all properties under it.
485 	 * Note that deleiing/destroying a node deletes/destroys
486 	 * all properties within that node.
487 	 */
488 
489 	for (i = 0; i < N_SENSOR_NODES; i++) {
490 		snodep = &sensor_nodes[i];
491 		if (snodep->nodeh != NULL) {
492 			/* delete node and all properties under it */
493 			(void) ptree_delete_node(snodep->nodeh);
494 			(void) ptree_destroy_node(snodep->nodeh);
495 			snodep->nodeh = NULL;
496 			snodep->proph = NULL;
497 		}
498 	}
499 }
500 
501 /*
502  * Go through the disk_nodes array and create those nodes
503  * and the Temperature property to report the temperature.
504  */
505 static int
506 add_disk_nodes_and_props()
507 {
508 	int		err;
509 	char		*pname, *nodename, *devfs_path;
510 	disk_node_t	*dnodep;
511 	picl_nodehdl_t	nodeh, cnodeh;
512 	picl_prophdl_t	proph;
513 	env_disk_t	*diskp;
514 	int		i;
515 
516 	for (i = 0; i < N_DISK_NODES; i++) {
517 		if (env_debug)
518 			envd_log(LOG_ERR, "adding disk nodes...\n");
519 		dnodep = &disk_nodes[i];
520 		/*
521 		 * Get the parent nodeh
522 		 */
523 		err = ptree_get_node_by_path(dnodep->parent_path, &nodeh);
524 		if (err != PICL_SUCCESS) {
525 			if (env_debug)
526 				envd_log(LOG_ERR,
527 				    "failed to get node for path %s\n",
528 				    dnodep->parent_path);
529 
530 			err = PICL_SUCCESS;
531 			continue;
532 		}
533 		diskp = dnodep->diskp;
534 		if (diskp == NULL)
535 			continue;
536 		if (diskp->present == B_FALSE)
537 			continue;
538 		/*
539 		 * Create temperature-sensor node
540 		 */
541 		nodename = dnodep->disk_name;
542 		err = ptree_create_and_add_node(nodeh, nodename,
543 		    PICL_CLASS_TEMPERATURE_SENSOR, &cnodeh);
544 		if (env_debug)
545 			envd_log(LOG_ERR,
546 			    "Creating PICL disk node '%s' err:%d\n",
547 			    nodename, err);
548 		if (err != PICL_SUCCESS)
549 			break;
550 
551 		/* save node handle */
552 		dnodep->nodeh = cnodeh;
553 
554 		/*
555 		 * Add "devfs_path" property in child node
556 		 */
557 		devfs_path = diskp->devfs_path;
558 		pname = PICL_PROP_DEVFS_PATH;
559 		err = add_regular_prop(cnodeh, pname,
560 		    PICL_PTYPE_CHARSTRING, PICL_READ,
561 		    strlen(devfs_path)+1, (void *)devfs_path, &proph);
562 		if (err != PICL_SUCCESS)
563 			break;
564 
565 		/*
566 		 * Now add volatile "temperature" volatile property
567 		 * in this "temperature-sensor" class node.
568 		 */
569 		pname = PICL_PROP_TEMPERATURE;
570 		err = add_volatile_prop(cnodeh, pname,
571 		    PICL_PTYPE_INT, PICL_READ, sizeof (tempr_t),
572 		    get_disk_temp, NULL, &proph);
573 		if (err != PICL_SUCCESS)
574 			break;
575 
576 		/* Save prop handle */
577 		dnodep->proph = proph;
578 
579 		/*
580 		 * Add threshold related properties
581 		 */
582 
583 		(void) add_regular_prop(cnodeh, PICL_PROP_LOW_SHUTDOWN,
584 		    PICL_PTYPE_INT, PICL_READ,
585 		    sizeof (diskp->low_shutdown),
586 		    (void *)&(diskp->low_shutdown), &proph);
587 
588 		(void) add_regular_prop(cnodeh, PICL_PROP_LOW_WARNING,
589 		    PICL_PTYPE_INT, PICL_READ,
590 		    sizeof (diskp->low_warning),
591 		    (void *)&(diskp->low_warning), &proph);
592 
593 		(void) add_regular_prop(cnodeh, PICL_PROP_HIGH_WARNING,
594 		    PICL_PTYPE_INT, PICL_READ,
595 		    sizeof (diskp->high_warning),
596 		    (void *)&(diskp->high_warning), &proph);
597 
598 		(void) add_regular_prop(cnodeh, PICL_PROP_HIGH_SHUTDOWN,
599 		    PICL_PTYPE_INT, PICL_READ,
600 		    sizeof (diskp->high_shutdown),
601 		    (void *)&(diskp->high_shutdown), &proph);
602 
603 	}
604 	if (err != PICL_SUCCESS) {
605 		delete_disk_nodes_and_props();
606 		if (env_debug)
607 			envd_log(LOG_INFO,
608 			    "Can't create prop/node for disk '%s'\n",
609 			    nodename);
610 		return (err);
611 	}
612 	return (PICL_SUCCESS);
613 }
614 
615 /*
616  * Delete all disk nodes and related properties created by the
617  * add_disk_props() for each disk node in the PICL tree.
618  */
619 static void
620 delete_disk_nodes_and_props(void)
621 {
622 	disk_node_t	*dnodep;
623 	int		i;
624 
625 	/*
626 	 * Delete/destroy disk node and all properties under it.
627 	 * Note that deleting/destroying a node deletes/destroys
628 	 * all properties within that node.
629 	 */
630 
631 	for (i = 0; i < N_DISK_NODES; i++) {
632 		dnodep = &disk_nodes[i];
633 		if (dnodep->nodeh != NULL) {
634 			(void) ptree_delete_node(dnodep->nodeh);
635 			(void) ptree_destroy_node(dnodep->nodeh);
636 			dnodep->nodeh = NULL;
637 			dnodep->proph = NULL;
638 		}
639 	}
640 }
641 
642 /*
643  * For each entry in fan_nodes[] array, do the following:
644  *	- Create specified "fan" class node.
645  *	- Create "Speed" volatile propery under "fan" class node.
646  *	- Create "SpeedUnit" property under "fan" class node.
647  */
648 static int
649 add_fan_nodes_and_props()
650 {
651 	int		err = PICL_FAILURE;
652 	char		*pname, *nodename, *devfs_path;
653 	env_fan_t	*fanp;
654 	fan_node_t	*fnodep;
655 	picl_nodehdl_t	nodeh, cnodeh;
656 	picl_prophdl_t	proph;
657 	int		i;
658 
659 	for (i = 0; i < N_FAN_NODES; i++) {
660 		/*
661 		 * Add various fan nodes and properties
662 		 */
663 		fnodep = &fan_nodes[i];
664 		if (fnodep == NULL)
665 			continue;
666 		if (fnodep->fanp == NULL)
667 			continue;
668 		if (fnodep->fanp->present == B_FALSE)
669 			continue;
670 		/*
671 		 * get parent nodeh
672 		 */
673 		err = ptree_get_node_by_path(fnodep->parent_path, &nodeh);
674 		if (err != PICL_SUCCESS) {
675 			if (env_debug)
676 				envd_log(LOG_ERR,
677 		"node for %s NOT FOUND.\n", fnodep->parent_path);
678 			err = PICL_SUCCESS;
679 			continue;
680 		}
681 		/*
682 		 * Create "fan" class node and save node handle
683 		 */
684 		nodename = fnodep->fan_name;
685 		err = ptree_create_and_add_node(nodeh, nodename,
686 		    PICL_CLASS_FAN, &cnodeh);
687 		if (env_debug)
688 			envd_log(LOG_ERR,
689 			    "Creating PICL fan node '%s' err:%d\n",
690 			    nodename, err);
691 
692 		if (err != PICL_SUCCESS)
693 			break;
694 		fnodep->nodeh = cnodeh;
695 
696 		/*
697 		 * Add "devfs_path" property in child node
698 		 */
699 		fanp = fnodep->fanp;
700 		devfs_path  = fanp->devfs_path;
701 		pname = PICL_PROP_DEVFS_PATH;
702 		err = add_regular_prop(cnodeh, pname,
703 		    PICL_PTYPE_CHARSTRING, PICL_READ,
704 		    strlen(devfs_path)+1, (void *)devfs_path, &proph);
705 
706 		if (err != PICL_SUCCESS)
707 
708 			break;
709 
710 		/*
711 		 * Add "Speed" volatile property in this "fan"
712 		 * class node and save prop handle.
713 		 */
714 		pname = PICL_PROP_FAN_SPEED;
715 
716 		err = add_volatile_prop(cnodeh, pname, PICL_PTYPE_INT,
717 		    PICL_READ|PICL_WRITE, sizeof (fanspeed_t),
718 		    get_current_speed, set_current_speed, &proph);
719 
720 		if (err != PICL_SUCCESS)
721 			break;
722 		fnodep->proph = proph;
723 
724 		/*
725 		 * Add other "fan" class properties
726 		 */
727 		pname = PICL_PROP_FAN_SPEED_UNIT;
728 		err = add_regular_prop(cnodeh, pname,
729 		    PICL_PTYPE_CHARSTRING, PICL_READ,
730 		    strlen(fnodep->speed_unit)+1,
731 		    (void *)fnodep->speed_unit, &proph);
732 
733 		if (err != PICL_SUCCESS)
734 			break;
735 
736 		pname = PICL_PROP_LOW_WARNING;
737 		err = add_regular_prop(cnodeh, pname,
738 		    PICL_PTYPE_INT, PICL_READ,
739 		    sizeof (fanspeed_t),
740 		    &(fnodep->fanp->speed_min), &proph);
741 
742 		if (err != PICL_SUCCESS)
743 			break;
744 	}
745 	if (err != PICL_SUCCESS) {
746 		delete_fan_nodes_and_props();
747 		return (err);
748 	}
749 	return (PICL_SUCCESS);
750 }
751 
752 
753 /*
754  * Delete all fan nodes and related properties created by the
755  * add_fan_props() for each fan node in the PICL tree.
756  */
757 static void
758 delete_fan_nodes_and_props(void)
759 {
760 	fan_node_t	*fnodep;
761 	int		i;
762 
763 	/*
764 	 * Delete/destroy fan node and all properties under it.
765 	 * Note that deleting/destroying a node deletes/destroys
766 	 * all properties within that node.
767 	 */
768 
769 	for (i = 0; i < N_FAN_NODES; i++) {
770 		fnodep = &fan_nodes[i];
771 		if (fnodep->nodeh != NULL) {
772 			(void) ptree_delete_node(fnodep->nodeh);
773 			(void) ptree_destroy_node(fnodep->nodeh);
774 			fnodep->nodeh = NULL;
775 		}
776 	}
777 }
778 /*
779  * Tuneables publishing functions
780  */
781 static int
782 copy_persistent_tuneable(env_tuneable_t *tune, char *buf)
783 {
784 
785 	switch (tune->type) {
786 	case PICL_PTYPE_INT : {
787 		(void) memcpy((int *)tune->value,
788 		    buf, tune->nbytes);
789 		break;
790 	}
791 	case PICL_PTYPE_CHARSTRING : {
792 		(void) memcpy((caddr_t)tune->value,
793 		    buf, tune->nbytes);
794 		break;
795 	}
796 	default	: {
797 		return (PICL_FAILURE);
798 	}
799 	}
800 	return (PICL_SUCCESS);
801 }
802 
803 static void
804 env_parse_tunables(picl_nodehdl_t rooth)
805 {
806 	char	nmbuf[SYS_NMLN];
807 	char    pname[PATH_MAX];
808 
809 	if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
810 		(void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
811 		(void) strlcat(pname, TUNABLE_CONF_FILE, PATH_MAX);
812 		if (access(pname, R_OK) == 0) {
813 			(void) picld_pluginutil_parse_config_file(rooth, pname);
814 			return;
815 		}
816 	}
817 }
818 
819 int
820 env_picl_setup_tuneables(void)
821 {
822 	int		err;
823 	int		i;
824 	picl_nodehdl_t	nodeh;
825 	picl_nodehdl_t	rooth;
826 	picl_prophdl_t	proph;
827 	env_tuneable_t	*tuneablep;
828 	char		read_buf[BUFSIZ];
829 
830 	if (ptree_get_root(&rooth) != PICL_SUCCESS) {
831 		return (PICL_FAILURE);
832 	}
833 	err = ptree_create_and_add_node(rooth, PICL_PLUGINS_NODE,
834 	    PICL_CLASS_PICL, &nodeh);
835 	if (err != PICL_SUCCESS)
836 		return (PICL_FAILURE);
837 	err = ptree_create_and_add_node(nodeh, PICL_ENVIRONMENTAL_NODE,
838 	    PICL_CLASS_PICL, &nodeh);
839 	if (err != PICL_SUCCESS) {
840 		return (PICL_FAILURE);
841 	}
842 
843 	/*
844 	 * Parse the conf file
845 	 */
846 	if (env_debug)
847 		envd_log(LOG_ERR, "parsing tuneables...\n");
848 	env_parse_tunables(rooth);
849 	for (i = 0; i < ntuneables; i++) {
850 		if (env_debug)
851 			envd_log(LOG_ERR, "tuneable %d being added\n", i);
852 		tuneablep = &tuneables[i];
853 		err = ptree_get_propval_by_name(nodeh, tuneablep->name,
854 		    read_buf, tuneablep->nbytes);
855 
856 		if (err != PICL_SUCCESS) {
857 			/*
858 			 * Add volitle functions to environmental node
859 			 */
860 			err = add_volatile_prop(nodeh, tuneablep->name,
861 			    tuneablep->type,
862 			    PICL_READ|PICL_WRITE, tuneablep->nbytes,
863 			    tuneablep->rfunc,
864 			    tuneablep->wfunc, &proph);
865 
866 			tuneablep->proph = proph;
867 		} else {
868 			/*
869 			 * property is persistent
870 			 */
871 			(void) copy_persistent_tuneable(tuneablep,
872 			    read_buf);
873 		}
874 	}
875 
876 	return	(PICL_SUCCESS);
877 }
878 
879 /*
880  * Find the ENVMODEL_CONF_FILE file.
881  */
882 static int
883 get_envmodel_conf_file(char *outfilename)
884 {
885 	char	nmbuf[SYS_NMLN];
886 	char    pname[PATH_MAX];
887 
888 	if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
889 		(void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
890 		(void) strlcat(pname, ENV_CONF_FILE, PATH_MAX);
891 		if (access(pname, R_OK) == 0) {
892 			(void) strlcpy(outfilename, pname, PATH_MAX);
893 			return (0);
894 		}
895 	}
896 
897 	if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
898 		(void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
899 		(void) strlcat(pname, ENV_CONF_FILE, PATH_MAX);
900 		if (access(pname, R_OK) == 0) {
901 			(void) strlcpy(outfilename, pname, PATH_MAX);
902 			return (0);
903 		}
904 	}
905 
906 	(void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR,
907 	    ENV_CONF_FILE);
908 
909 	if (access(pname, R_OK) == 0) {
910 		(void) strlcpy(outfilename, pname, PATH_MAX);
911 		return (0);
912 	}
913 
914 	return (-1);
915 }
916 
917 /* Delete all sensor/fan nodes and any properties created by this plugin */
918 void
919 env_picl_destroy(void)
920 {
921 	delete_fan_nodes_and_props();
922 	delete_sensor_nodes_and_props();
923 	delete_disk_nodes_and_props();
924 }
925 
926 void
927 env_picl_setup(void)
928 {
929 	int		err, sensor_err, fan_err, disk_err;
930 	sensor_node_t	*snodep;
931 	fan_node_t	*fnodep;
932 	disk_node_t	*dnodep;
933 	picl_nodehdl_t	plath;
934 	char		fullfilename[PATH_MAX];
935 	picl_nodehdl_t  rooth;
936 	int		i;
937 
938 
939 	/*
940 	 * Initialize sensorp and other fields in the sensor_nodes[] array
941 	 */
942 
943 	for (i = 0; i < N_SENSOR_NODES; i++) {
944 		snodep = &sensor_nodes[i];
945 		snodep->sensorp = sensor_lookup(snodep->sensor_name);
946 		snodep->nodeh = NULL;
947 		snodep->proph = NULL;
948 		snodep->target_proph = NULL;
949 	}
950 
951 	/*
952 	 * Initialize fanp and other fields in the fan_nodes[] array
953 	 */
954 	for (i = 0; i < N_FAN_NODES; i++) {
955 		fnodep = &fan_nodes[i];
956 		fnodep->fanp = fan_lookup(fnodep->fan_name);
957 		fnodep->nodeh = NULL;
958 		fnodep->proph = NULL;
959 	}
960 
961 	/*
962 	 * Initialize diskp and other fields in the disk_nodes[] array
963 	 */
964 	for (i = 0; i < N_DISK_NODES; i++) {
965 		dnodep = &disk_nodes[i];
966 		dnodep->diskp = disk_lookup(dnodep->disk_name);
967 		dnodep->nodeh = NULL;
968 		dnodep->proph = NULL;
969 	}
970 
971 	/*
972 	 * Get platform handle and populate PICL tree with environmental
973 	 * nodes and properties
974 	 */
975 	err = ptree_get_node_by_path("/platform", &plath);
976 
977 	if (err == PICL_SUCCESS) {
978 		sensor_err = add_sensor_nodes_and_props();
979 		fan_err = add_fan_nodes_and_props();
980 		if (disk_temp_monitor)
981 			disk_err = add_disk_nodes_and_props();
982 	}
983 
984 	/*
985 	 * We can safely call delete_xxx_nodes_and_props even
986 	 * if nodes were not added.
987 	 */
988 
989 	if (err != PICL_SUCCESS) {
990 		if (fan_err != PICL_SUCCESS)
991 			delete_fan_nodes_and_props();
992 		if (disk_err != PICL_SUCCESS)
993 			delete_disk_nodes_and_props();
994 		if (sensor_err != PICL_SUCCESS)
995 			delete_sensor_nodes_and_props();
996 
997 	envd_log(LOG_CRIT, ENVD_PICL_SETUP_FAILED);
998 		return;
999 	}
1000 	if (env_debug)
1001 		envd_log(LOG_ERR, "parsing the envmodel.conf file...\n");
1002 
1003 	/*
1004 	 * Parse the envmodel.conf file and populate the PICL tree
1005 	 */
1006 	if (get_envmodel_conf_file(fullfilename) < 0)
1007 		envd_log(LOG_CRIT, ENVD_PICL_SETUP_FAILED);
1008 	if (ptree_get_root(&rooth) != PICL_SUCCESS)
1009 		envd_log(LOG_CRIT, ENVD_PICL_SETUP_FAILED);
1010 	err = picld_pluginutil_parse_config_file(rooth, fullfilename);
1011 
1012 	if (err != PICL_SUCCESS)
1013 		envd_log(LOG_CRIT, ENVD_PICL_SETUP_FAILED);
1014 }
1015