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