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