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