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