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