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