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 */
60typedef int ptree_vol_rdfunc_t(ptree_rarg_t *parg, void *buf);
61typedef int ptree_vol_wrfunc_t(ptree_warg_t *parg, const void *buf);
62
63extern int disk_temp_monitor;
64extern env_tuneable_t	tuneables[];
65extern	int errno;
66extern	int	ntuneables;
67#define	PROP_FAN_SPEED_UNIT_VALUE	"rpm"
68
69/*
70 * Sensor node data structure
71 */
72typedef 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 */
84static 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 */
109typedef 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 */
121static 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 */
138typedef 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 */
149static 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 */
160static void delete_sensor_nodes_and_props(void);
161static void delete_disk_nodes_and_props(void);
162static void delete_fan_nodes_and_props(void);
163
164
165/*
166 * Read function for volatile "Temperature" property
167 */
168static int
169get_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 */
197static int
198get_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 */
226static int
227set_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 */
268static int
269get_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
300static int
301add_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 */
323static int
324add_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 */
346static void
347add_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 */
387static int
388add_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 */
480static void
481delete_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 */
509static int
510add_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 */
623static void
624delete_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 */
652static int
653add_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 */
761static void
762delete_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 */
785static int
786copy_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
807static void
808env_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
823int
824env_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 */
886static int
887get_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 */
922void
923env_picl_destroy(void)
924{
925	delete_fan_nodes_and_props();
926	delete_sensor_nodes_and_props();
927	delete_disk_nodes_and_props();
928}
929
930void
931env_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