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