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