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
count_records(FILE * fp,char * end,uint32_t * countp)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
find_file_section(FILE * fd,char * start)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
name_compare_bsearch(char * s1,picl_psvc_t * s2)170 static int32_t name_compare_bsearch(char *s1, picl_psvc_t *s2)
171 {
172 return (strcmp(s1, s2->name));
173 }
174
init_err(char * fmt,char * arg1,char * arg2)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
projected_lookup(picl_prophdl_t proph,struct proj_prop ** dstp)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
fan_speed_read(ptree_rarg_t * rarg,void * buf)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
load_projected_properties(FILE * fp)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
psvc_psr_plugin_init(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
psvc_psr_plugin_fini(void)499 psvc_psr_plugin_fini(void)
500 {
501 psvc_fini(hdlp);
502 }
503
504 void
psvc_psr_plugin_register(void)505 psvc_psr_plugin_register(void)
506 {
507 picld_plugin_register(&psvc_psr_reg);
508 }
509