xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4u/grover/envd/piclenvsetup.c (revision 8aafd47d0dbabbca4365c9565fbe0e051e7346dd)
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 (c) 1999-2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 /*
28  * This file contains code for setting up environmental related nodes
29  * and properties in the PICL tree.
30  *
31  * For each temperature-device class node, it does the following:
32  *	- Create cpu and cpu-ambient temperautre-sensor class nodes.
33  *	- Create "devfs-path" property under each temperature-sensor class node
34  *	- Create "Temperature" volatile property under these nodes.
35  *	- Create various temperature threshold properties under each node.
36  *	- Create "Temperature" and "AmbientTemperature" volatile properties
37  *	  under corresponding "cpu" class node.
38  *
39  * For the "fan-control" node, it does the following:
40  *	- Create system-fan node
41  *	- Create "devfs-path" property under "fan" class node
42  *	- Create "Speed" volatile propery under each node.
43  *	- Create "SpeedUnit" property under each node.
44  */
45 
46 #include <stdio.h>
47 #include <fcntl.h>
48 #include <unistd.h>
49 #include <syslog.h>
50 #include <stdlib.h>
51 #include <limits.h>
52 #include <sys/open.h>
53 #include <ctype.h>
54 #include <string.h>
55 #include <alloca.h>
56 #include <libintl.h>
57 #include <sys/systeminfo.h>
58 #include <picl.h>
59 #include <picltree.h>
60 #include <picld_pluginutil.h>
61 #include <pthread.h>
62 #include <sys/utsname.h>
63 #include <sys/systeminfo.h>
64 #include "envd.h"
65 
66 
67 /*
68  * Volatile property read/write function typedef
69  */
70 typedef int ptree_vol_rdfunc_t(ptree_rarg_t *parg, void *buf);
71 typedef int ptree_vol_wrfunc_t(ptree_warg_t *parg, const void *buf);
72 
73 /*
74  * PICL Classes and standard property names
75  */
76 #define	PICL_CLASS_CPU		"cpu"
77 #define	PICL_CLASS_FAN		"fan"
78 #define	PICL_CLASS_FAN_CONTROL	"fan-control"
79 #define	PICL_CLASS_TEMP_DEVICE	"temperature-device"
80 #define	PICL_CLASS_TEMP_SENSOR	"temperature-sensor"
81 
82 #define	PICL_PROP_REG		"reg"
83 #define	PICL_PROP_DEVFS_PATH	"devfs-path"
84 #define	PICL_PROP_UNIT_ADDRESS	"UnitAddress"
85 #define	UNITADDR_LEN_MAX	256	/* max length for UnitAddress */
86 
87 /*
88  * temperature properties
89  */
90 #define	PROP_TEMPERATURE	"Temperature"
91 #define	PROP_CPU_AMB_TEMP	"AmbientTemperature"
92 #define	PROP_CPU_DIE_TEMP	"Temperature"
93 
94 /*
95  * Various temperature threshold property names
96  */
97 #define	PROP_LOW_POWER_OFF	"LowPowerOffThreshold"
98 #define	PROP_LOW_SHUTDOWN	"LowShutdownThreshold"
99 #define	PROP_LOW_WARNING	"LowWarningThreshold"
100 #define	PROP_HIGH_POWER_OFF	"HighPowerOffThreshold"
101 #define	PROP_HIGH_SHUTDOWN	"HighShutdownThreshold"
102 #define	PROP_HIGH_WARNING	"HighWarningThreshold"
103 
104 /*
105  * fan properties
106  */
107 #define	PROP_FAN_SPEED		"Speed"
108 #define	PROP_FAN_SPEED_UNIT	"SpeedUnit"
109 #define	PROP_FAN_SPEED_UNIT_VALUE	"%"
110 
111 /*
112  * PICL class path for CPU nodes
113  */
114 #define	CPU_PLAT_PATH		"_class:/upa/cpu?ID=0"
115 
116 /*
117  * "UnitAddress" propval for various temperature devices (platform dependent)
118  */
119 #define	CPU_TEMPDEV_UNITADDR	"0,30"
120 
121 /*
122  * Sensor node data structure
123  */
124 typedef struct {
125 	char		*sensor_name;	/* sensor name */
126 	env_sensor_t	*sensorp;	/* sensor info */
127 	char		*unitaddr;	/* parent's UnitAddress propval */
128 	char		*sdev_node;	/* sensed device node name */
129 	char		*sdev_pname;	/* sensed device "temp" prop name */
130 	picl_nodehdl_t	nodeh;		/* sensor node handle */
131 	picl_prophdl_t	proph;		/* "Temperature" property handle */
132 	picl_prophdl_t	sdev_proph;	/* property handle for sensed dev */
133 } sensor_node_t;
134 
135 
136 /*
137  * Sensor nodes array
138  */
139 static sensor_node_t sensor_nodes[] = {
140 	{SENSOR_CPU_DIE, NULL, CPU_TEMPDEV_UNITADDR,
141 	    CPU_PLAT_PATH, PROP_CPU_DIE_TEMP},
142 
143 	{SENSOR_CPU_AMB, NULL, CPU_TEMPDEV_UNITADDR,
144 	    CPU_PLAT_PATH, PROP_CPU_AMB_TEMP},
145 
146 	{NULL, NULL, NULL, NULL, NULL}
147 };
148 
149 
150 /*
151  * Fan node data structure
152  */
153 typedef struct {
154 	char		*fan_name;	/* fan name */
155 	env_fan_t	*fanp;		/* fan information */
156 	char		*speed_unit;	/* speed unit string */
157 	picl_nodehdl_t	nodeh;		/* "fan" node handle */
158 	picl_prophdl_t	proph;		/* "Speed" property handle */
159 } fan_node_t;
160 
161 
162 /*
163  * Fan node array
164  */
165 static fan_node_t fan_nodes[] =  {
166 	{ENV_SYSTEM_FAN, NULL, PROP_FAN_SPEED_UNIT_VALUE},
167 	{NULL, NULL, NULL}
168 };
169 
170 /*
171  * Miscellaneous declarations
172  */
173 typedef struct node_list {
174 	picl_nodehdl_t		nodeh;
175 	struct node_list	*next;
176 } node_list_t;
177 
178 static void delete_sensor_nodes_and_props(void);
179 static void delete_fan_nodes_and_props(void);
180 
181 
182 
183 /*
184  * Read function for volatile "Temperature" property
185  */
186 static int
187 get_current_temp(ptree_rarg_t *parg, void *buf)
188 {
189 	tempr_t		temp;
190 	picl_prophdl_t	proph;
191 	sensor_node_t	*snodep;
192 
193 	/*
194 	 * Locate the sensor in our sensor_nodes table by matching the
195 	 * property handle and get its temperature.
196 	 */
197 	proph = parg->proph;
198 	for (snodep = &sensor_nodes[0]; snodep->sensor_name != NULL; snodep++) {
199 		if (snodep->proph != proph &&
200 		    snodep->sdev_proph != proph)
201 			continue;
202 
203 		if (get_temperature(snodep->sensorp, &temp) < 0)
204 			return (PICL_FAILURE);
205 		(void) memcpy(buf, (caddr_t)&temp, sizeof (tempr_t));
206 		return (PICL_SUCCESS);
207 	}
208 	return (PICL_FAILURE);
209 }
210 
211 
212 /*
213  * Read function for volatile "Speed" property on "fan" class node
214  */
215 static int
216 get_current_speed(ptree_rarg_t *parg, void *buf)
217 {
218 	fanspeed_t	speed;
219 	picl_prophdl_t	proph;
220 	fan_node_t	*fnodep;
221 
222 	/*
223 	 * Locate the fan in our fan_nodes table by matching the
224 	 * property handle and get fan speed.
225 	 */
226 	proph = parg->proph;
227 	for (fnodep = &fan_nodes[0]; fnodep->fan_name != NULL; fnodep++) {
228 		if (fnodep->proph != proph)
229 			continue;
230 		if (get_fan_speed(fnodep->fanp, &speed) < 0)
231 			return (PICL_FAILURE);
232 
233 		(void) memcpy(buf, (caddr_t)&speed, sizeof (speed));
234 		return (PICL_SUCCESS);
235 	}
236 	return (PICL_FAILURE);
237 }
238 
239 
240 static node_list_t *
241 add_node_to_list(picl_nodehdl_t nodeh, node_list_t *listp)
242 {
243 	node_list_t	*el;
244 	node_list_t	*tmp;
245 
246 	el = malloc(sizeof (node_list_t));
247 	if (el == NULL)
248 		return (listp);
249 	el->nodeh = nodeh;
250 	el->next = NULL;
251 	if (listp == NULL) {
252 		listp = el;
253 		return (listp);
254 	}
255 
256 	/*
257 	 * append to the end to preserve the order found
258 	 */
259 	tmp = listp;
260 	while (tmp->next != NULL)
261 		tmp = tmp->next;
262 
263 	tmp->next = el;
264 	return (listp);
265 }
266 
267 
268 
269 /*
270  * Get a list of nodes of the specified classname under nodeh
271  * Once a node of the specified class is found, it's children are not
272  * searched.
273  */
274 static node_list_t *
275 get_node_list_by_class(picl_nodehdl_t nodeh, const char *classname,
276     node_list_t *listp)
277 {
278 	int		err;
279 	char		clname[PICL_CLASSNAMELEN_MAX+1];
280 	picl_nodehdl_t	chdh;
281 
282 	/*
283 	 * go through the children
284 	 */
285 	err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
286 	    sizeof (picl_nodehdl_t));
287 
288 	while (err == PICL_SUCCESS) {
289 		err = ptree_get_propval_by_name(chdh, PICL_PROP_CLASSNAME,
290 		    clname, strlen(classname) + 1);
291 
292 		if ((err == PICL_SUCCESS) && (strcmp(clname, classname) == 0))
293 			listp = add_node_to_list(chdh, listp);
294 		else
295 			listp = get_node_list_by_class(chdh, classname, listp);
296 
297 		err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
298 		    sizeof (picl_nodehdl_t));
299 	}
300 	return (listp);
301 }
302 
303 
304 /*
305  * Free memory allocated to build the specified node list.
306  */
307 static void
308 free_node_list(node_list_t *listp)
309 {
310 	node_list_t	*next;
311 
312 	for (; listp != NULL; listp = next) {
313 		next = listp->next;
314 		free(listp);
315 	}
316 }
317 
318 /*
319  * Get PICL_PTYPE_CHARSTRING "UnitAddress" property
320  */
321 static int
322 get_unit_address_prop(picl_nodehdl_t nodeh, void *buf, size_t len)
323 {
324 	int			err;
325 	picl_prophdl_t		proph;
326 	ptree_propinfo_t	pinfo;
327 
328 	err = ptree_get_prop_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, &proph);
329 	if (err == PICL_SUCCESS)
330 		err = ptree_get_propinfo(proph, &pinfo);
331 
332 	if (err != PICL_SUCCESS)
333 		return (err);
334 
335 	if (pinfo.piclinfo.type != PICL_PTYPE_CHARSTRING ||
336 	    pinfo.piclinfo.size > len)
337 		return (PICL_FAILURE);
338 
339 	err = ptree_get_propval(proph, buf, pinfo.piclinfo.size);
340 	return (err);
341 }
342 
343 
344 /*
345  * Create and add the specified regular property
346  */
347 
348 static int
349 add_regular_prop(picl_nodehdl_t nodeh, char *name, int type, int access,
350     int size, void *valbuf, picl_prophdl_t *prophp)
351 {
352 	int			err;
353 	ptree_propinfo_t	propinfo;
354 	picl_prophdl_t		proph;
355 
356 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
357 	    type, access, size, name, NULL, NULL);
358 	if (err != PICL_SUCCESS)
359 		return (err);
360 
361 	err = ptree_create_and_add_prop(nodeh, &propinfo, valbuf, &proph);
362 	if (err == PICL_SUCCESS && prophp)
363 		*prophp = proph;
364 	return (err);
365 }
366 
367 
368 /*
369  * Create and add the specified volatile property
370  */
371 static int
372 add_volatile_prop(picl_nodehdl_t nodeh, char *name, int type, int access,
373     int size, ptree_vol_rdfunc_t *rdfunc, ptree_vol_wrfunc_t *wrfunc,
374     picl_prophdl_t *prophp)
375 {
376 	int			err;
377 	ptree_propinfo_t	propinfo;
378 	picl_prophdl_t		proph;
379 
380 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
381 	    type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc);
382 	if (err != PICL_SUCCESS)
383 		return (err);
384 
385 	err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph);
386 	if (err == PICL_SUCCESS && prophp)
387 		*prophp = proph;
388 	return (err);
389 }
390 
391 /*
392  * Add temperature threshold properties
393  */
394 static void
395 add_sensor_thresh_props(picl_nodehdl_t nodeh, sensor_thresh_t *threshp)
396 {
397 	picl_prophdl_t	proph;
398 
399 	(void) add_regular_prop(nodeh, PROP_LOW_POWER_OFF,
400 	    PICL_PTYPE_INT, PICL_READ,
401 	    sizeof (threshp->low_power_off),
402 	    (void *)&(threshp->low_power_off), &proph);
403 
404 	(void) add_regular_prop(nodeh, PROP_LOW_SHUTDOWN,
405 	    PICL_PTYPE_INT, PICL_READ,
406 	    sizeof (threshp->low_shutdown),
407 	    (void *)&(threshp->low_shutdown), &proph);
408 
409 	(void) add_regular_prop(nodeh, PROP_LOW_WARNING,
410 	    PICL_PTYPE_INT, PICL_READ,
411 	    sizeof (threshp->low_warning),
412 	    (void *)&(threshp->low_warning), &proph);
413 
414 	(void) add_regular_prop(nodeh, PROP_HIGH_WARNING,
415 	    PICL_PTYPE_INT, PICL_READ,
416 	    sizeof (threshp->high_warning),
417 	    (void *)&(threshp->high_warning), &proph);
418 
419 	(void) add_regular_prop(nodeh, PROP_HIGH_SHUTDOWN,
420 	    PICL_PTYPE_INT, PICL_READ,
421 	    sizeof (threshp->high_shutdown),
422 	    (void *)&(threshp->high_shutdown), &proph);
423 
424 	(void) add_regular_prop(nodeh, PROP_HIGH_POWER_OFF,
425 	    PICL_PTYPE_INT, PICL_READ,
426 	    sizeof (threshp->high_power_off),
427 	    (void *)&(threshp->high_power_off), &proph);
428 }
429 
430 
431 /*
432  * Lookup "temperature-device" class nodes and create "temperature-sensor"
433  * class nodes and relevant properties under those nodes.
434  *
435  * For each entry in sensor_nodes[] array, do the following:
436  *	- Create specified (cpu-die or cpu-ambient) "temperautre-sensor" class
437  *	  node.
438  *	- Create "devfs-path" property under this node.
439  *	- Create "Temperature" volatile property under this node.
440  *	- Create various temperature threshold properties under this node.
441  *	- Create specified ("Temperature" or "AmbientTemperature") volatile
442  *	  temperature property under specified sdev_node node.
443  */
444 
445 static int
446 add_sensor_nodes_and_props(picl_nodehdl_t plath)
447 {
448 	int		err;
449 	char		*pname, *nodename, *refnode, *devfs_path;
450 	node_list_t	*node_list, *listp;
451 	sensor_node_t	*snodep;
452 	sensor_thresh_t *threshp;
453 	picl_nodehdl_t	nodeh, refnodeh, cnodeh;
454 	picl_prophdl_t	proph;
455 	char		unitaddr[UNITADDR_LEN_MAX];
456 	env_sensor_t	*sensorp;
457 
458 	node_list =
459 	    get_node_list_by_class(plath, PICL_CLASS_TEMP_DEVICE, NULL);
460 
461 	if (node_list == NULL)
462 		return (PICL_FAILURE);
463 
464 	for (listp = node_list; listp != NULL; listp = listp->next) {
465 		/*
466 		 * Get "reg" property. Skip if no "reg" property found.
467 		 */
468 		nodeh = listp->nodeh;
469 		err = get_unit_address_prop(nodeh, (void *)unitaddr,
470 		    sizeof (unitaddr));
471 		if (err != PICL_SUCCESS)
472 			continue;
473 
474 		for (snodep = sensor_nodes; snodep->sensor_name != NULL;
475 		    snodep++) {
476 
477 			/* Match "UnitAddress" property */
478 			if (strcasecmp(unitaddr, snodep->unitaddr) != 0)
479 				continue;
480 
481 			/*
482 			 * Skip if already initialized or no sensor info
483 			 */
484 			sensorp = snodep->sensorp;
485 			if (snodep->nodeh != 0 || sensorp == NULL)
486 				continue;
487 
488 			/*
489 			 * Create temperature-sensor node
490 			 */
491 			nodename = snodep->sensor_name;
492 			err = ptree_create_and_add_node(nodeh, nodename,
493 			    PICL_CLASS_TEMP_SENSOR, &cnodeh);
494 			if (env_debug)
495 				envd_log(LOG_INFO,
496 				    "Creating PICL sensor node '%s' err:%d\n",
497 				    nodename, err);
498 			if (err != PICL_SUCCESS)
499 				break;
500 
501 			/* save node handle */
502 			snodep->nodeh = cnodeh;
503 
504 			/*
505 			 * Add "devfs_path" property in child node
506 			 */
507 			devfs_path = sensorp->devfs_path;
508 			pname = PICL_PROP_DEVFS_PATH;
509 			err = add_regular_prop(cnodeh, pname,
510 			    PICL_PTYPE_CHARSTRING, PICL_READ,
511 			    strlen(devfs_path)+1, (void *)devfs_path, &proph);
512 			if (err != PICL_SUCCESS)
513 				break;
514 
515 			/*
516 			 * Now add volatile "temperature" volatile property
517 			 * in this "temperature-sensor" class node.
518 			 */
519 			pname = PROP_TEMPERATURE;
520 			err = add_volatile_prop(cnodeh, pname,
521 			    PICL_PTYPE_INT, PICL_READ, sizeof (tempr_t),
522 			    get_current_temp, NULL, &proph);
523 			if (err != PICL_SUCCESS)
524 				break;
525 
526 			/* Save prop handle */
527 			snodep->proph = proph;
528 
529 			/*
530 			 * Add threshold related properties
531 			 */
532 			threshp = sensorp->temp_thresh;
533 			if (threshp != NULL)
534 				add_sensor_thresh_props(cnodeh, threshp);
535 
536 			/*
537 			 * Finally create property in the sensed device
538 			 * (if one specified)
539 			 */
540 			refnode =  snodep->sdev_node;
541 			pname =  snodep->sdev_pname;
542 			if (refnode == NULL || pname == NULL)
543 				continue;
544 
545 			err = ptree_get_node_by_path(refnode, &refnodeh);
546 			if (err == PICL_SUCCESS) {
547 				err = add_volatile_prop(refnodeh, pname,
548 				    PICL_PTYPE_INT, PICL_READ,
549 				    sizeof (tempr_t), get_current_temp,
550 				    NULL, &proph);
551 			}
552 
553 			if (err != PICL_SUCCESS)
554 				break;
555 
556 			/* Save prop handle */
557 			snodep->sdev_proph = proph;
558 		}
559 		if (err != PICL_SUCCESS) {
560 			delete_sensor_nodes_and_props();
561 			free_node_list(node_list);
562 			if (env_debug)
563 				envd_log(LOG_INFO,
564 				    "Can't create prop/node for sensor '%s'\n",
565 				    nodename);
566 			return (err);
567 		}
568 	}
569 
570 	free_node_list(node_list);
571 	return (PICL_SUCCESS);
572 }
573 
574 /*
575  * Delete all sensor nodes and related properties created by the
576  * add_sensor_prop() for each sensor node in the PICL tree.
577  */
578 static void
579 delete_sensor_nodes_and_props(void)
580 {
581 	sensor_node_t	*snodep;
582 
583 	/*
584 	 * Delete/destroy any property created in the sensed device
585 	 * as well as the sensor node and all properties under it.
586 	 * Note that deleiing/destroying a node deletes/destroys
587 	 * all properties within that node.
588 	 */
589 
590 	for (snodep = sensor_nodes; snodep->sensor_name != NULL; snodep++) {
591 		if (snodep->sdev_proph != 0) {
592 			(void) ptree_delete_prop(snodep->sdev_proph);
593 			(void) ptree_destroy_prop(snodep->sdev_proph);
594 			snodep->sdev_proph = 0;
595 		}
596 
597 		if (snodep->nodeh != 0) {
598 			/* delete node and all properties under it */
599 			(void) ptree_delete_node(snodep->nodeh);
600 			(void) ptree_destroy_node(snodep->nodeh);
601 			snodep->nodeh = 0;
602 			snodep->proph = 0;
603 		}
604 	}
605 }
606 
607 
608 /*
609  * Lookup "fan-control" class node and create "fan" class nodes and
610  * relevant properties under those nodes.
611  *
612  * For each entry in fan_nodes[] array, do the following:
613  *	- Create specified "fan" class node.
614  *	- Create "devfs-path" property under "fan" class node
615  *	- Create "Speed" volatile propery under "fan" class node.
616  *	- Create "SpeedUnit" property under "fan" class node.
617  */
618 
619 static int
620 add_fan_nodes_and_props(picl_nodehdl_t plath)
621 {
622 	int		err;
623 	char		*pname, *nodename, *devfs_path;
624 	env_fan_t	*fanp;
625 	fan_node_t	*fnodep;
626 	picl_nodehdl_t	nodeh, cnodeh;
627 	picl_prophdl_t	proph;
628 	node_list_t	*node_list, *listp;
629 
630 	node_list =
631 	    get_node_list_by_class(plath, PICL_CLASS_FAN_CONTROL, NULL);
632 
633 	if (node_list == NULL)
634 		return (PICL_FAILURE);
635 
636 	for (listp = node_list; listp != NULL; listp = listp->next) {
637 		/*
638 		 * Add various fan nodes and properties
639 		 */
640 		nodeh = listp->nodeh;
641 		err = PICL_SUCCESS;
642 		for (fnodep = fan_nodes; fnodep->fan_name != NULL; fnodep++) {
643 
644 			/* Skip if already initialized or no fan info */
645 			if (fnodep->nodeh != 0 || fnodep->fanp == NULL)
646 				continue;
647 
648 			/*
649 			 * Create "fan" class node and save node handle
650 			 */
651 			nodename = fnodep->fan_name;
652 			err = ptree_create_and_add_node(nodeh, nodename,
653 			    PICL_CLASS_FAN, &cnodeh);
654 			if (env_debug)
655 				envd_log(LOG_INFO,
656 				    "Creating PICL fan node '%s' err:%d\n",
657 				    nodename, err);
658 
659 			if (err != PICL_SUCCESS)
660 				break;
661 			fnodep->nodeh = cnodeh;
662 
663 			/*
664 			 * Add "devfs_path" property in child node
665 			 */
666 			fanp = fnodep->fanp;
667 			devfs_path  = fanp->devfs_path;
668 			pname = PICL_PROP_DEVFS_PATH;
669 			err = add_regular_prop(cnodeh, pname,
670 			    PICL_PTYPE_CHARSTRING, PICL_READ,
671 			    strlen(devfs_path)+1, (void *)devfs_path, &proph);
672 
673 			if (err != PICL_SUCCESS)
674 				break;
675 
676 			/*
677 			 * Add "Speed" volatile property in this "fan"
678 			 * class node and save prop handle.
679 			 */
680 			pname = PROP_FAN_SPEED;
681 			err = add_volatile_prop(cnodeh, pname, PICL_PTYPE_INT,
682 			    PICL_READ, sizeof (fanspeed_t), get_current_speed,
683 			    NULL, &proph);
684 
685 			if (err != PICL_SUCCESS)
686 				break;
687 			fnodep->proph = proph;
688 
689 			/*
690 			 * Add other "fan" class properties
691 			 */
692 			pname = PROP_FAN_SPEED_UNIT;
693 			err = add_regular_prop(cnodeh, pname,
694 			    PICL_PTYPE_CHARSTRING, PICL_READ,
695 			    strlen(fnodep->speed_unit)+1,
696 			    (void *)fnodep->speed_unit, &proph);
697 
698 			if (err != PICL_SUCCESS)
699 				break;
700 		}
701 		if (err != PICL_SUCCESS) {
702 			delete_fan_nodes_and_props();
703 			free_node_list(node_list);
704 			if (env_debug)
705 				envd_log(LOG_WARNING,
706 				    "Can't create prop/node for fan '%s'\n",
707 				    nodename);
708 			return (err);
709 		}
710 	}
711 
712 	free_node_list(node_list);
713 	return (PICL_SUCCESS);
714 }
715 
716 
717 /*
718  * Delete all fan nodes and related properties created by the
719  * add_fan_props() for each fan node in the PICL tree.
720  */
721 static void
722 delete_fan_nodes_and_props(void)
723 {
724 	fan_node_t	*fnodep;
725 
726 	/*
727 	 * Delete/destroy fan node and all properties under it.
728 	 * Note that deleiing/destroying a node deletes/destroys
729 	 * all properties within that node.
730 	 */
731 
732 	for (fnodep = fan_nodes; fnodep->fan_name != NULL; fnodep++) {
733 		if (fnodep->nodeh != 0) {
734 			(void) ptree_delete_node(fnodep->nodeh);
735 			(void) ptree_destroy_node(fnodep->nodeh);
736 			fnodep->nodeh = 0;
737 		}
738 	}
739 }
740 
741 /*
742  * Find the ENVMODEL_CONF_FILE file.
743  */
744 static int
745 get_envmodel_conf_file(char *outfilename)
746 {
747 	char	nmbuf[SYS_NMLN];
748 	char    pname[PATH_MAX];
749 
750 	if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
751 		(void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
752 		(void) strlcat(pname, ENVMODEL_CONF_FILE, PATH_MAX);
753 		if (access(pname, R_OK) == 0) {
754 			(void) strlcpy(outfilename, pname, PATH_MAX);
755 			return (0);
756 		}
757 	}
758 
759 	if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
760 		(void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
761 		(void) strlcat(pname, ENVMODEL_CONF_FILE, PATH_MAX);
762 		if (access(pname, R_OK) == 0) {
763 			(void) strlcpy(outfilename, pname, PATH_MAX);
764 			return (0);
765 		}
766 	}
767 
768 	(void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR,
769 	    ENVMODEL_CONF_FILE);
770 
771 	if (access(pname, R_OK) == 0) {
772 		(void) strlcpy(outfilename, pname, PATH_MAX);
773 		return (0);
774 	}
775 
776 	return (-1);
777 }
778 
779 void
780 env_picl_setup(void)
781 {
782 	int		err;
783 	sensor_node_t	*snodep;
784 	fan_node_t	*fnodep;
785 	picl_nodehdl_t	plath;
786 	char		fullfilename[PATH_MAX];
787 	picl_nodehdl_t	rooth;
788 
789 	/*
790 	 * Initialize sensorp and other fields in the sensor_nodes[] array
791 	 */
792 	for (snodep = sensor_nodes; snodep->sensor_name != NULL; snodep++) {
793 		snodep->sensorp = sensor_lookup(snodep->sensor_name);
794 		snodep->nodeh = 0;
795 		snodep->proph = 0;
796 		snodep->sdev_proph = 0;
797 	}
798 
799 	/*
800 	 * Initialize fanp and other fields in the fan_nodes[] array
801 	 */
802 	for (fnodep = fan_nodes; fnodep->fan_name != NULL; fnodep++) {
803 		fnodep->fanp = fan_lookup(fnodep->fan_name);
804 		fnodep->nodeh = 0;
805 		fnodep->proph = 0;
806 	}
807 
808 	/*
809 	 * Get platform handle and populate PICL tree with environmental
810 	 * nodes and properties
811 	 */
812 	err = ptree_get_node_by_path("/platform", &plath);
813 
814 	if (err == PICL_SUCCESS) {
815 		err = add_sensor_nodes_and_props(plath);
816 		if (err == PICL_SUCCESS)
817 			err = add_fan_nodes_and_props(plath);
818 	}
819 
820 	if (err != PICL_SUCCESS) {
821 		envd_log(LOG_CRIT, ENVD_PICL_SETUP_FAILED);
822 		return;
823 	}
824 
825 	/*
826 	 * Parse the envmodel.conf file and populate the PICL tree
827 	 */
828 	if (get_envmodel_conf_file(fullfilename) < 0)
829 		envd_log(LOG_CRIT, ENVD_PICL_SETUP_FAILED);
830 	if (ptree_get_root(&rooth) != PICL_SUCCESS)
831 		envd_log(LOG_CRIT, ENVD_PICL_SETUP_FAILED);
832 	err = picld_pluginutil_parse_config_file(rooth, fullfilename);
833 
834 	if (err != PICL_SUCCESS)
835 		envd_log(LOG_CRIT, ENVD_PICL_SETUP_FAILED);
836 }
837