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