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