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