1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2000, 2002 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * PICL Daktari platform plug-in to create environment tree nodes.
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include	<poll.h>
34*0Sstevel@tonic-gate #include	<picl.h>
35*0Sstevel@tonic-gate #include	<picltree.h>
36*0Sstevel@tonic-gate #include	<stdio.h>
37*0Sstevel@tonic-gate #include	<time.h>
38*0Sstevel@tonic-gate #include	<fcntl.h>
39*0Sstevel@tonic-gate #include	<unistd.h>
40*0Sstevel@tonic-gate #include	<stdlib.h>
41*0Sstevel@tonic-gate #include	<libintl.h>
42*0Sstevel@tonic-gate #include	<limits.h>
43*0Sstevel@tonic-gate #include 	<ctype.h>
44*0Sstevel@tonic-gate #include	<pthread.h>
45*0Sstevel@tonic-gate #include	<errno.h>
46*0Sstevel@tonic-gate #include	<syslog.h>
47*0Sstevel@tonic-gate #include	<sys/types.h>
48*0Sstevel@tonic-gate #include	<sys/systeminfo.h>
49*0Sstevel@tonic-gate #include	<psvc_objects.h>
50*0Sstevel@tonic-gate #include	<strings.h>
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate /*LINTLIBRARY*/
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate #define	BUFSZ	512
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate static psvc_opaque_t hdlp;
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate #define	PSVC_PLUGIN_VERSION	PICLD_PLUGIN_VERSION_1
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate #pragma init(psvc_psr_plugin_register)	/* place in .init section */
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate struct proj_prop {	/* projected property */
64*0Sstevel@tonic-gate 	picl_prophdl_t	handle;
65*0Sstevel@tonic-gate 	picl_nodehdl_t  dst_node;
66*0Sstevel@tonic-gate 	char		name[32];
67*0Sstevel@tonic-gate };
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate typedef struct {
70*0Sstevel@tonic-gate 	char		name[32];
71*0Sstevel@tonic-gate 	picl_nodehdl_t	node;
72*0Sstevel@tonic-gate } picl_psvc_t;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate extern struct handle {
75*0Sstevel@tonic-gate 	uint32_t	obj_count;
76*0Sstevel@tonic-gate 	picl_psvc_t *objects;
77*0Sstevel@tonic-gate 	FILE *fp;
78*0Sstevel@tonic-gate } psvc_hdl;
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate extern struct proj_prop *prop_list;
81*0Sstevel@tonic-gate extern uint32_t proj_prop_count;
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate void psvc_psr_plugin_init(void);
84*0Sstevel@tonic-gate void psvc_psr_plugin_fini(void);
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate picld_plugin_reg_t psvc_psr_reg = {
87*0Sstevel@tonic-gate 	PSVC_PLUGIN_VERSION,
88*0Sstevel@tonic-gate 	PICLD_PLUGIN_CRITICAL,
89*0Sstevel@tonic-gate 	"PSVC_PSR",
90*0Sstevel@tonic-gate 	psvc_psr_plugin_init,
91*0Sstevel@tonic-gate 	psvc_psr_plugin_fini
92*0Sstevel@tonic-gate };
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate #define	PSVC_INIT_MSG		gettext("%s: Error in psvc_init(): %s\n")
96*0Sstevel@tonic-gate #define	PTREE_DELETE_NODE_MSG	gettext("%s: ptree_delete_node() failed: %s\n")
97*0Sstevel@tonic-gate #define	PTREE_GET_NODE_MSG			\
98*0Sstevel@tonic-gate 	gettext("%s: ptree_get_node_by_path() failed for %s: %s\n")
99*0Sstevel@tonic-gate #define	INVALID_FILE_FORMAT_MSG		gettext("%s: Invalid file format\n")
100*0Sstevel@tonic-gate #define	ID_NOT_FOUND_MSG	gettext("%s: Can't determine id of %s\n")
101*0Sstevel@tonic-gate #define	NODE_NOT_FOUND_MSG	gettext("%s: Can't determine node of %s\n")
102*0Sstevel@tonic-gate #define	SIZE_NOT_FOUND_MSG	gettext("%s: Couldn't determine size of %s\n")
103*0Sstevel@tonic-gate #define	PTREE_CREATE_PROP_FAILED_MSG		\
104*0Sstevel@tonic-gate 	gettext("%s: ptree_create_prop failed, %s\n")
105*0Sstevel@tonic-gate #define	PTREE_ADD_PROP_FAILED_MSG gettext("%s: ptree_add_prop: %s\n")
106*0Sstevel@tonic-gate #define	FANSPEED_PROP_NOT_FOUND_MSG		\
107*0Sstevel@tonic-gate 	gettext("%s: Can't find property fan-speed\n")
108*0Sstevel@tonic-gate #define	FANSPEED_PROP_DELETE_FAILED_MSG		\
109*0Sstevel@tonic-gate 	gettext("%s: Can't delete property fan-speed\n")
110*0Sstevel@tonic-gate 
count_records(FILE * fp,char * end,uint32_t * countp)111*0Sstevel@tonic-gate static int32_t count_records(FILE *fp, char *end, uint32_t *countp)
112*0Sstevel@tonic-gate {
113*0Sstevel@tonic-gate 	long first_record;
114*0Sstevel@tonic-gate 	char *ret;
115*0Sstevel@tonic-gate 	char buf[BUFSZ];
116*0Sstevel@tonic-gate 	uint32_t count = 0;
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 	first_record = ftell(fp);
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	while ((ret = fgets(buf, BUFSZ, fp)) != NULL) {
121*0Sstevel@tonic-gate 		if (strncmp(end, buf, strlen(end)) == 0)
122*0Sstevel@tonic-gate 			break;
123*0Sstevel@tonic-gate 		++count;
124*0Sstevel@tonic-gate 	}
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	if (ret == NULL) {
127*0Sstevel@tonic-gate 		errno = EINVAL;
128*0Sstevel@tonic-gate 		return (-1);
129*0Sstevel@tonic-gate 	}
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 	fseek(fp, first_record, SEEK_SET);
132*0Sstevel@tonic-gate 	*countp = count;
133*0Sstevel@tonic-gate 	return (0);
134*0Sstevel@tonic-gate }
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate /*
137*0Sstevel@tonic-gate  * Find start of a section within the config file,
138*0Sstevel@tonic-gate  * Returns number of records in the section.
139*0Sstevel@tonic-gate  * FILE *fd is set to first data record within section.
140*0Sstevel@tonic-gate  */
141*0Sstevel@tonic-gate static int32_t
find_file_section(FILE * fd,char * start)142*0Sstevel@tonic-gate find_file_section(FILE *fd, char *start)
143*0Sstevel@tonic-gate {
144*0Sstevel@tonic-gate 	char *ret;
145*0Sstevel@tonic-gate 	char buf[BUFSZ];
146*0Sstevel@tonic-gate 	char name[32];
147*0Sstevel@tonic-gate 	int found;
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 	fseek(fd, 0, SEEK_SET);
150*0Sstevel@tonic-gate 	while ((ret = fgets(buf, BUFSZ, fd)) != NULL) {
151*0Sstevel@tonic-gate 		if (strncmp(start, buf, strlen(start)) == 0)
152*0Sstevel@tonic-gate 			break;
153*0Sstevel@tonic-gate 	}
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 	if (ret == NULL) {
156*0Sstevel@tonic-gate 		errno = EINVAL;
157*0Sstevel@tonic-gate 		return (-1);
158*0Sstevel@tonic-gate 	}
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	found = sscanf(buf, "%s", name);
161*0Sstevel@tonic-gate 	if (found != 1) {
162*0Sstevel@tonic-gate 		errno = EINVAL;
163*0Sstevel@tonic-gate 		return (-1);
164*0Sstevel@tonic-gate 	} else {
165*0Sstevel@tonic-gate 		return (0);
166*0Sstevel@tonic-gate 	}
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate }
169*0Sstevel@tonic-gate 
name_compare_bsearch(char * s1,picl_psvc_t * s2)170*0Sstevel@tonic-gate static int32_t name_compare_bsearch(char *s1, picl_psvc_t *s2)
171*0Sstevel@tonic-gate {
172*0Sstevel@tonic-gate 	return (strcmp(s1, s2->name));
173*0Sstevel@tonic-gate }
174*0Sstevel@tonic-gate 
init_err(char * fmt,char * arg1,char * arg2)175*0Sstevel@tonic-gate static void init_err(char *fmt, char *arg1, char *arg2)
176*0Sstevel@tonic-gate {
177*0Sstevel@tonic-gate 	char msg[256];
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 	sprintf(msg, fmt, arg1, arg2);
180*0Sstevel@tonic-gate 	syslog(LOG_ERR, msg);
181*0Sstevel@tonic-gate }
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate static int
projected_lookup(picl_prophdl_t proph,struct proj_prop ** dstp)184*0Sstevel@tonic-gate projected_lookup(picl_prophdl_t proph, struct proj_prop **dstp)
185*0Sstevel@tonic-gate {
186*0Sstevel@tonic-gate 	int i;
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	for (i = 0; i < proj_prop_count; ++i) {
189*0Sstevel@tonic-gate 		if (prop_list[i].handle == proph) {
190*0Sstevel@tonic-gate 			*dstp = &prop_list[i];
191*0Sstevel@tonic-gate 			return (PICL_SUCCESS);
192*0Sstevel@tonic-gate 		}
193*0Sstevel@tonic-gate 	}
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	return (PICL_INVALIDHANDLE);
196*0Sstevel@tonic-gate }
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate int
fan_speed_read(ptree_rarg_t * rarg,void * buf)199*0Sstevel@tonic-gate fan_speed_read(ptree_rarg_t *rarg, void *buf)
200*0Sstevel@tonic-gate {
201*0Sstevel@tonic-gate 	struct proj_prop *dstinfo;
202*0Sstevel@tonic-gate 	int err;
203*0Sstevel@tonic-gate 	ptree_propinfo_t propinfo;
204*0Sstevel@tonic-gate 	picl_prophdl_t assoctbl;
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	err = projected_lookup(rarg->proph, &dstinfo);
207*0Sstevel@tonic-gate 	if (err != PSVC_SUCCESS) {
208*0Sstevel@tonic-gate 		return (PICL_FAILURE);
209*0Sstevel@tonic-gate 	}
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	/* see if there's a tach switch */
213*0Sstevel@tonic-gate 	err = ptree_get_propval_by_name(rarg->nodeh,
214*0Sstevel@tonic-gate 	    "PSVC_FAN_PRIM_SEC_SELECTOR", &assoctbl, sizeof (assoctbl));
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
217*0Sstevel@tonic-gate 		return (err);
218*0Sstevel@tonic-gate 	} else {
219*0Sstevel@tonic-gate 		char switch_state[32], temp_state[32];
220*0Sstevel@tonic-gate 		uint64_t features;
221*0Sstevel@tonic-gate 		picl_prophdl_t entry;
222*0Sstevel@tonic-gate 		picl_nodehdl_t tach_switch;
223*0Sstevel@tonic-gate 		char id[PICL_PROPNAMELEN_MAX];
224*0Sstevel@tonic-gate 		char name[PICL_PROPNAMELEN_MAX];
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 		err = ptree_get_next_by_row(assoctbl, &entry);
227*0Sstevel@tonic-gate 		if (err != PICL_SUCCESS) {
228*0Sstevel@tonic-gate 			return (err);
229*0Sstevel@tonic-gate 		}
230*0Sstevel@tonic-gate 		err = ptree_get_propval(entry, &tach_switch,
231*0Sstevel@tonic-gate 			sizeof (tach_switch));
232*0Sstevel@tonic-gate 		if (err != PICL_SUCCESS) {
233*0Sstevel@tonic-gate 			return (err);
234*0Sstevel@tonic-gate 		}
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 		err = ptree_get_propval_by_name(rarg->nodeh, PICL_PROP_NAME,
237*0Sstevel@tonic-gate 			&id, PICL_PROPNAMELEN_MAX);
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 		err = psvc_get_attr(hdlp, id, PSVC_FEATURES_ATTR, &features);
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 		if (err != PSVC_SUCCESS) {
242*0Sstevel@tonic-gate 			return (err);
243*0Sstevel@tonic-gate 		}
244*0Sstevel@tonic-gate 		if (features & PSVC_DEV_PRIMARY) {
245*0Sstevel@tonic-gate 			strlcpy(switch_state, PSVC_SWITCH_ON,
246*0Sstevel@tonic-gate 			    sizeof (switch_state));
247*0Sstevel@tonic-gate 		} else {
248*0Sstevel@tonic-gate 			strlcpy(switch_state, PSVC_SWITCH_OFF,
249*0Sstevel@tonic-gate 			    sizeof (switch_state));
250*0Sstevel@tonic-gate 		}
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 		pthread_mutex_lock(&fan_mutex);
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 		err = ptree_get_propval_by_name(tach_switch, PICL_PROP_NAME,
255*0Sstevel@tonic-gate 			&name, PICL_PROPNAMELEN_MAX);
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 		err = ptree_get_propval_by_name(tach_switch, "State",
258*0Sstevel@tonic-gate 			&temp_state, sizeof (temp_state));
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 		err = psvc_set_attr(hdlp, name, PSVC_SWITCH_STATE_ATTR,
261*0Sstevel@tonic-gate 			&switch_state);
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 		if (err != PSVC_SUCCESS) {
264*0Sstevel@tonic-gate 			pthread_mutex_unlock(&fan_mutex);
265*0Sstevel@tonic-gate 			return (err);
266*0Sstevel@tonic-gate 		}
267*0Sstevel@tonic-gate 		(void) poll(NULL, 0, 250);
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	err = ptree_get_propinfo(rarg->proph, &propinfo);
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
274*0Sstevel@tonic-gate 		pthread_mutex_unlock(&fan_mutex);
275*0Sstevel@tonic-gate 		return (err);
276*0Sstevel@tonic-gate 	}
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	err = ptree_get_propval_by_name(dstinfo->dst_node,
279*0Sstevel@tonic-gate 		dstinfo->name, buf, propinfo.piclinfo.size);
280*0Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
281*0Sstevel@tonic-gate 		pthread_mutex_unlock(&fan_mutex);
282*0Sstevel@tonic-gate 		return (err);
283*0Sstevel@tonic-gate 	}
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	pthread_mutex_unlock(&fan_mutex);
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
288*0Sstevel@tonic-gate }
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate /* Load projected properties */
292*0Sstevel@tonic-gate /*
293*0Sstevel@tonic-gate  * This Routine Searches through the projected properties section of the conf
294*0Sstevel@tonic-gate  * file and replaces the currently set up values in the CPU and IO Fan Objects
295*0Sstevel@tonic-gate  * Fan-Speed property to Daktari specific values
296*0Sstevel@tonic-gate  */
297*0Sstevel@tonic-gate static void
load_projected_properties(FILE * fp)298*0Sstevel@tonic-gate load_projected_properties(FILE *fp)
299*0Sstevel@tonic-gate {
300*0Sstevel@tonic-gate 	int32_t found;
301*0Sstevel@tonic-gate 	ptree_propinfo_t propinfo;
302*0Sstevel@tonic-gate 	ptree_propinfo_t dstinfo;
303*0Sstevel@tonic-gate 	picl_prophdl_t src_prophdl, dst_prophdl;
304*0Sstevel@tonic-gate 	picl_nodehdl_t src_node, dst_node;
305*0Sstevel@tonic-gate 	int err, i;
306*0Sstevel@tonic-gate 	picl_psvc_t *srcobjp, *dstobjp;
307*0Sstevel@tonic-gate 	char src[32], dst[256];
308*0Sstevel@tonic-gate 	char src_prop[32], dst_prop[32];
309*0Sstevel@tonic-gate 	char buf[BUFSZ];
310*0Sstevel@tonic-gate 	char *funcname = "load_projected_properties";
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	if (find_file_section(fp, "PROJECTED_PROPERTIES") != 0)
313*0Sstevel@tonic-gate 		return;
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	if (count_records(fp, "PROJECTED_PROPERTIES_END",
316*0Sstevel@tonic-gate 		&proj_prop_count) != 0) {
317*0Sstevel@tonic-gate 		init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
318*0Sstevel@tonic-gate 		return;
319*0Sstevel@tonic-gate 	}
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	for (i = 0; i < proj_prop_count; ++i) {
323*0Sstevel@tonic-gate 		fgets(buf, BUFSZ, fp);
324*0Sstevel@tonic-gate 		found = sscanf(buf, "%s %s %s %s", src, src_prop, dst,
325*0Sstevel@tonic-gate 			dst_prop);
326*0Sstevel@tonic-gate 		if (found != 4) {
327*0Sstevel@tonic-gate 			init_err(INVALID_FILE_FORMAT_MSG, funcname, 0);
328*0Sstevel@tonic-gate 			return;
329*0Sstevel@tonic-gate 		}
330*0Sstevel@tonic-gate 		if (strcmp(src_prop, "Fan-speed") != 0)
331*0Sstevel@tonic-gate 			continue;
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 		if ((strcmp(src, "IO_BRIDGE_PRIM_FAN") == 0) ||
334*0Sstevel@tonic-gate 			(strcmp(src, "IO_BRIDGE_SEC_FAN") == 0))
335*0Sstevel@tonic-gate 			continue;
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 		/* find src node */
338*0Sstevel@tonic-gate 		if (src[0] == '/') {
339*0Sstevel@tonic-gate 			/* picl node name, outside psvc subtree */
340*0Sstevel@tonic-gate 			err = ptree_get_node_by_path(src, &src_node);
341*0Sstevel@tonic-gate 			if (err != 0) {
342*0Sstevel@tonic-gate 				init_err(NODE_NOT_FOUND_MSG, funcname, src);
343*0Sstevel@tonic-gate 				return;
344*0Sstevel@tonic-gate 			}
345*0Sstevel@tonic-gate 		} else {
346*0Sstevel@tonic-gate 			srcobjp = (picl_psvc_t *)bsearch(src, psvc_hdl.objects,
347*0Sstevel@tonic-gate 				psvc_hdl.obj_count, sizeof (picl_psvc_t),
348*0Sstevel@tonic-gate 				(int (*)(const void *, const void *))
349*0Sstevel@tonic-gate 				name_compare_bsearch);
350*0Sstevel@tonic-gate 			if (srcobjp == NULL) {
351*0Sstevel@tonic-gate 				init_err(ID_NOT_FOUND_MSG, funcname, src);
352*0Sstevel@tonic-gate 				return;
353*0Sstevel@tonic-gate 			}
354*0Sstevel@tonic-gate 			src_node = srcobjp->node;
355*0Sstevel@tonic-gate 		}
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 		/*
358*0Sstevel@tonic-gate 		 * Get the property Handle for the property names "Fan-Speed"
359*0Sstevel@tonic-gate 		 * from the source node
360*0Sstevel@tonic-gate 		 */
361*0Sstevel@tonic-gate 		err = ptree_get_prop_by_name(src_node, "Fan-speed",
362*0Sstevel@tonic-gate 		    &src_prophdl);
363*0Sstevel@tonic-gate 		if (err != 0) {
364*0Sstevel@tonic-gate 			init_err(FANSPEED_PROP_NOT_FOUND_MSG, funcname, 0);
365*0Sstevel@tonic-gate 			return;
366*0Sstevel@tonic-gate 		}
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 		/*
369*0Sstevel@tonic-gate 		 * Delete the current property Handle as we are going to replace
370*0Sstevel@tonic-gate 		 * it's values
371*0Sstevel@tonic-gate 		 */
372*0Sstevel@tonic-gate 		err = ptree_delete_prop(src_prophdl);
373*0Sstevel@tonic-gate 		if (err != 0) {
374*0Sstevel@tonic-gate 			init_err(FANSPEED_PROP_DELETE_FAILED_MSG, funcname, 0);
375*0Sstevel@tonic-gate 			return;
376*0Sstevel@tonic-gate 		}
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 		/* destroy property created by generic plugin */
379*0Sstevel@tonic-gate 		ptree_delete_prop(prop_list[i].handle);
380*0Sstevel@tonic-gate 		ptree_destroy_prop(prop_list[i].handle);
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 		/* find dest node */
383*0Sstevel@tonic-gate 		if (dst[0] == '/') {
384*0Sstevel@tonic-gate 			/* picl node name, outside psvc subtree */
385*0Sstevel@tonic-gate 			err = ptree_get_node_by_path(dst, &dst_node);
386*0Sstevel@tonic-gate 			if (err != 0) {
387*0Sstevel@tonic-gate 				init_err(NODE_NOT_FOUND_MSG, funcname, dst);
388*0Sstevel@tonic-gate 				return;
389*0Sstevel@tonic-gate 			}
390*0Sstevel@tonic-gate 			prop_list[i].dst_node = dst_node;
391*0Sstevel@tonic-gate 		} else {
392*0Sstevel@tonic-gate 			dstobjp = (picl_psvc_t *)bsearch(dst, psvc_hdl.objects,
393*0Sstevel@tonic-gate 				psvc_hdl.obj_count, sizeof (picl_psvc_t),
394*0Sstevel@tonic-gate 				(int (*)(const void *, const void *))
395*0Sstevel@tonic-gate 				name_compare_bsearch);
396*0Sstevel@tonic-gate 			if (dstobjp == NULL) {
397*0Sstevel@tonic-gate 				init_err(ID_NOT_FOUND_MSG, funcname, dst);
398*0Sstevel@tonic-gate 				return;
399*0Sstevel@tonic-gate 			}
400*0Sstevel@tonic-gate 			prop_list[i].dst_node = dstobjp->node;
401*0Sstevel@tonic-gate 			dst_node = dstobjp->node;
402*0Sstevel@tonic-gate 		}
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 		/* determine destination property size */
405*0Sstevel@tonic-gate 		err = ptree_get_first_prop(dst_node, &dst_prophdl);
406*0Sstevel@tonic-gate 		while (err == 0) {
407*0Sstevel@tonic-gate 			err = ptree_get_propinfo(dst_prophdl, &dstinfo);
408*0Sstevel@tonic-gate 			if (err != 0)
409*0Sstevel@tonic-gate 				break;
410*0Sstevel@tonic-gate 			if (strcmp(dst_prop, dstinfo.piclinfo.name) == 0)
411*0Sstevel@tonic-gate 				break;
412*0Sstevel@tonic-gate 			err = ptree_get_next_prop(dst_prophdl, &dst_prophdl);
413*0Sstevel@tonic-gate 		}
414*0Sstevel@tonic-gate 		if (err != 0) {
415*0Sstevel@tonic-gate 			init_err(SIZE_NOT_FOUND_MSG, funcname, dst_prop);
416*0Sstevel@tonic-gate 			return;
417*0Sstevel@tonic-gate 		}
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate 		propinfo.version = PSVC_PLUGIN_VERSION;
420*0Sstevel@tonic-gate 		propinfo.read = fan_speed_read;
421*0Sstevel@tonic-gate 		propinfo.write = 0;
422*0Sstevel@tonic-gate 		propinfo.piclinfo.type = dstinfo.piclinfo.type;
423*0Sstevel@tonic-gate 		propinfo.piclinfo.accessmode = PICL_READ | PICL_VOLATILE;
424*0Sstevel@tonic-gate 		propinfo.piclinfo.size = dstinfo.piclinfo.size;
425*0Sstevel@tonic-gate 		strcpy(propinfo.piclinfo.name, src_prop);
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate 		err = ptree_create_prop(&propinfo, 0, &src_prophdl);
428*0Sstevel@tonic-gate 		if (err != 0) {
429*0Sstevel@tonic-gate 			init_err(PTREE_CREATE_PROP_FAILED_MSG, funcname,
430*0Sstevel@tonic-gate 				picl_strerror(err));
431*0Sstevel@tonic-gate 			return;
432*0Sstevel@tonic-gate 		}
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 		err = ptree_add_prop(src_node, src_prophdl);
435*0Sstevel@tonic-gate 		if (err != 0) {
436*0Sstevel@tonic-gate 			init_err(PTREE_ADD_PROP_FAILED_MSG, funcname,
437*0Sstevel@tonic-gate 				picl_strerror(err));
438*0Sstevel@tonic-gate 			return;
439*0Sstevel@tonic-gate 		}
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 		prop_list[i].handle = src_prophdl;
442*0Sstevel@tonic-gate 		strcpy(prop_list[i].name, dst_prop);
443*0Sstevel@tonic-gate 	}
444*0Sstevel@tonic-gate }
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate void
psvc_psr_plugin_init(void)448*0Sstevel@tonic-gate psvc_psr_plugin_init(void)
449*0Sstevel@tonic-gate {
450*0Sstevel@tonic-gate 	char *funcname = "psvc_psr_plugin_init";
451*0Sstevel@tonic-gate 	int32_t i;
452*0Sstevel@tonic-gate 	int err;
453*0Sstevel@tonic-gate 	boolean_t present;
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	/*
456*0Sstevel@tonic-gate 	 * So the volatile read/write routines can retrieve data from
457*0Sstevel@tonic-gate 	 * psvc or picl
458*0Sstevel@tonic-gate 	 */
459*0Sstevel@tonic-gate 	err = psvc_init(&hdlp);
460*0Sstevel@tonic-gate 	if (err != 0) {
461*0Sstevel@tonic-gate 		init_err(PSVC_INIT_MSG, funcname, strerror(errno));
462*0Sstevel@tonic-gate 	}
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 	load_projected_properties(psvc_hdl.fp);
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 	/*
467*0Sstevel@tonic-gate 	 * Remove nodes whose devices aren't present from the picl tree.
468*0Sstevel@tonic-gate 	 */
469*0Sstevel@tonic-gate 	for (i = 0; i < psvc_hdl.obj_count; ++i) {
470*0Sstevel@tonic-gate 		picl_psvc_t *objp;
471*0Sstevel@tonic-gate 		uint64_t features;
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate 		objp = &psvc_hdl.objects[i];
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 		err = psvc_get_attr(hdlp, objp->name, PSVC_PRESENCE_ATTR,
476*0Sstevel@tonic-gate 			&present);
477*0Sstevel@tonic-gate 		if (err != PSVC_SUCCESS)
478*0Sstevel@tonic-gate 			continue;
479*0Sstevel@tonic-gate 		err = psvc_get_attr(hdlp, objp->name, PSVC_FEATURES_ATTR,
480*0Sstevel@tonic-gate 			&features);
481*0Sstevel@tonic-gate 		if (err != PSVC_SUCCESS)
482*0Sstevel@tonic-gate 			continue;
483*0Sstevel@tonic-gate 		if ((features & (PSVC_DEV_HOTPLUG | PSVC_DEV_OPTION)) &&
484*0Sstevel@tonic-gate 			(present == PSVC_ABSENT)) {
485*0Sstevel@tonic-gate 			err = ptree_delete_node(objp->node);
486*0Sstevel@tonic-gate 			if (err != 0) {
487*0Sstevel@tonic-gate 				init_err(PTREE_DELETE_NODE_MSG, funcname,
488*0Sstevel@tonic-gate 					picl_strerror(err));
489*0Sstevel@tonic-gate 				return;
490*0Sstevel@tonic-gate 			}
491*0Sstevel@tonic-gate 		}
492*0Sstevel@tonic-gate 	}
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 	free(psvc_hdl.objects);
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate }
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate void
psvc_psr_plugin_fini(void)499*0Sstevel@tonic-gate psvc_psr_plugin_fini(void)
500*0Sstevel@tonic-gate {
501*0Sstevel@tonic-gate 	psvc_fini(hdlp);
502*0Sstevel@tonic-gate }
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate void
psvc_psr_plugin_register(void)505*0Sstevel@tonic-gate psvc_psr_plugin_register(void)
506*0Sstevel@tonic-gate {
507*0Sstevel@tonic-gate 	picld_plugin_register(&psvc_psr_reg);
508*0Sstevel@tonic-gate }
509