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