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