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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contains routines to support the Platform Services Plugin 31 * These routines implement the platform independent environment monitoring 32 * and control policies that may be invoked by a daemon thread within 33 * the plugin 34 */ 35 36 #include <syslog.h> 37 #include <unistd.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <libintl.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <strings.h> 44 #include <libintl.h> 45 #include <sys/types.h> 46 #include <string.h> 47 #include <limits.h> 48 #include <picl.h> 49 #include <picltree.h> 50 #include <sys/types.h> 51 #include <string.h> 52 #include <psvc_objects.h> 53 54 #define LOWTEMP_CRITICAL_MSG \ 55 gettext("CRITICAL : LOW TEMPERATURE DETECTED %d, %s") 56 #define LOWTEMP_WARNING_MSG \ 57 gettext("WARNING : LOW TEMPERATURE DETECTED %d, %s") 58 #define HIGHTEMP_CRITICAL_MSG \ 59 gettext("CRITICAL : HIGH TEMPERATURE DETECTED %d, %s") 60 #define HIGHTEMP_WARNING_MSG \ 61 gettext("WARNING : HIGH TEMPERATURE DETECTED %d, %s") 62 #define DEVICE_INSERTED_MSG gettext("Device %s inserted") 63 #define DEVICE_REMOVED_MSG gettext("Device %s removed") 64 #define DEVICE_FAILURE_MSG \ 65 gettext("CRITICAL: Device %s failure detected by sensor %s\n") 66 #define DEVICE_OK_MSG gettext("Device %s OK") 67 #define SECONDARY_FAN_FAIL_MSG gettext("Secondary fan failure, device %s") 68 #define KEYSWITCH_POS_READ_FAILED_MSG \ 69 gettext("Keyswitch position could not be determined") 70 #define KEYSWITCH_POS_CHANGED_MSG gettext("Keyswitch position changed to %s") 71 #define GET_PRESENCE_FAILED_MSG \ 72 gettext("Failed to get presence attribute, id = %s, errno = %d\n") 73 #define GET_SENSOR_FAILED_MSG \ 74 gettext("Failed to get sensor value, id = %s, errno = %d\n") 75 #define PS_OVER_CURRENT_MSG \ 76 gettext("WARNING: Power Supply overcurrent detected for %s\n") 77 #define SET_LED_FAILED_MSG \ 78 gettext("Failed to set LED state, id = %s, errno = %d\n") 79 #define SET_FANSPEED_FAILED_MSG \ 80 gettext("Failed to set fan speed, id = %s, errno = %d\n") 81 #define FAN_MISSING_MSG \ 82 gettext("WARNING: Fan missing, id = %s\n") 83 #define TEMP_SENSOR_FAULT \ 84 gettext("WARNING: Temperature Sensor %s returning faulty temp\n") 85 #define TEMP_OFFSET 17 86 87 static char *shutdown_string = "shutdown -y -g 60 -i 5 \"OVERTEMP condition\""; 88 89 static int cpus_online = 0; 90 91 typedef struct seg_desc { 92 int32_t segdesc; 93 int16_t segoffset; 94 int16_t seglength; 95 } seg_desc_t; 96 97 static int32_t threshold_names[] = { 98 PSVC_HW_LO_SHUT_ATTR, 99 PSVC_LO_SHUT_ATTR, 100 PSVC_LO_WARN_ATTR, 101 PSVC_NOT_USED, /* LOW MODE which is not used */ 102 PSVC_OPTIMAL_TEMP_ATTR, 103 PSVC_HI_WARN_ATTR, 104 PSVC_HI_SHUT_ATTR, 105 PSVC_HW_HI_SHUT_ATTR 106 }; 107 108 /* 109 * The I2C bus is noisy, and the state may be incorrectly reported as 110 * having changed. When the state changes, we attempt to confirm by 111 * retrying. If any retries indicate that the state has not changed, we 112 * assume the state change(s) were incorrect and the state has not changed. 113 * The following variables are used to store the tuneable values read in 114 * from the optional i2cparam.conf file for this shared object library. 115 */ 116 static int n_read_temp = PSVC_THRESHOLD_COUNTER; 117 static int n_retry_keyswitch = PSVC_NUM_OF_RETRIES; 118 static int retry_sleep_keyswitch = 1; 119 static int n_retry_hotplug = PSVC_NUM_OF_RETRIES; 120 static int retry_sleep_hotplug = 1; 121 static int n_retry_fan_hotplug = PSVC_NUM_OF_RETRIES; 122 static int retry_sleep_fan_hotplug = 1; 123 static int n_retry_fan_present = PSVC_NUM_OF_RETRIES; 124 static int retry_sleep_fan_present = 1; 125 126 typedef struct { 127 int *pvar; 128 char *texttag; 129 } i2c_noise_param_t; 130 131 static i2c_noise_param_t i2cparams_sun4u[] = { 132 &n_read_temp, "n_read_temp", 133 &n_retry_keyswitch, "n_retry_keyswitch", 134 &retry_sleep_keyswitch, "retry_sleep_keyswitch", 135 &n_retry_hotplug, "n_retry_hotplug", 136 &retry_sleep_hotplug, "retry_sleep_hotplug", 137 &n_retry_fan_hotplug, "n_retry_fan_hotplug", 138 &retry_sleep_fan_hotplug, "retry_sleep_fan_hotplug", 139 &n_retry_fan_present, "n_retry_fan_present", 140 &retry_sleep_fan_present, "retry_sleep_fan_present", 141 NULL, NULL 142 }; 143 144 #pragma init(i2cparams_sun4u_load) 145 146 static void 147 i2cparams_sun4u_debug(i2c_noise_param_t *pi2cparams, int usingDefaults) 148 { 149 char s[128]; 150 i2c_noise_param_t *p; 151 152 if (!usingDefaults) { 153 (void) strncpy(s, 154 "# Values from /usr/platform/sun4u/lib/i2cparam.conf\n", 155 sizeof (s) - 1); 156 syslog(LOG_WARNING, "%s", s); 157 } else { 158 /* no file - we're using the defaults */ 159 (void) strncpy(s, 160 "# No /usr/platform/sun4u/lib/i2cparam.conf file, using defaults\n", 161 sizeof (s) - 1); 162 } 163 (void) fputs(s, stdout); 164 p = pi2cparams; 165 while (p->pvar != NULL) { 166 (void) snprintf(s, sizeof (s), "%s %d\n", p->texttag, 167 *(p->pvar)); 168 if (!usingDefaults) 169 syslog(LOG_WARNING, "%s", s); 170 (void) fputs(s, stdout); 171 p++; 172 } 173 } 174 175 static void 176 i2cparams_sun4u_load(void) 177 { 178 FILE *fp; 179 char *filename = "/usr/platform/sun4u/lib/i2cparam.conf"; 180 char s[128]; 181 char var[128]; 182 int val; 183 i2c_noise_param_t *p; 184 185 /* read thru the i2cparam.conf file and set variables */ 186 if ((fp = fopen(filename, "r")) != NULL) { 187 while (fgets(s, sizeof (s), fp) != NULL) { 188 if (s[0] == '#') /* skip comment lines */ 189 continue; 190 /* try to find a string match and get the value */ 191 if (sscanf(s, "%127s %d", var, &val) != 2) 192 continue; 193 if (val < 1) 194 val = 1; /* clamp min value */ 195 p = &(i2cparams_sun4u[0]); 196 while (p->pvar != NULL) { 197 if (strncmp(p->texttag, var, sizeof (var)) == 198 0) { 199 *(p->pvar) = val; 200 break; 201 } 202 p++; 203 } 204 } 205 (void) fclose(fp); 206 } 207 /* output the values of the parameters */ 208 i2cparams_sun4u_debug(&(i2cparams_sun4u[0]), ((fp == NULL)? 1 : 0)); 209 } 210 211 212 int32_t 213 psvc_update_thresholds_0(psvc_opaque_t hdlp, char *id) 214 { 215 int32_t status = PSVC_SUCCESS; 216 fru_info_t fru_data; 217 char *fru, seg_name[2]; 218 int8_t seg_count, temp_array[8]; 219 int32_t match_count, i, j, seg_desc_start = 0x1806, temp_address; 220 int32_t seg_found, temp; 221 boolean_t present; 222 seg_desc_t segment; 223 224 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &present); 225 if ((status != PSVC_SUCCESS) || (present != PSVC_PRESENT)) 226 return (status); 227 228 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &match_count, 229 PSVC_FRU); 230 if (status == PSVC_FAILURE) 231 return (status); 232 233 for (i = 0; i < match_count; i++) { 234 seg_found = 0; 235 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 236 &fru, PSVC_FRU, i); 237 if (status != PSVC_SUCCESS) 238 return (status); 239 240 fru_data.buf_start = 0x1805; 241 fru_data.buf = (char *)&seg_count; 242 fru_data.read_size = 1; 243 244 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, 245 &fru_data); 246 if (status != PSVC_SUCCESS) { 247 return (status); 248 } 249 for (j = 0; (j < seg_count) && (!seg_found); j++) { 250 fru_data.buf_start = seg_desc_start; 251 fru_data.buf = seg_name; 252 fru_data.read_size = 2; 253 254 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, 255 &fru_data); 256 257 seg_desc_start = seg_desc_start + 2; 258 fru_data.buf_start = seg_desc_start; 259 fru_data.buf = (char *)&segment; 260 fru_data.read_size = sizeof (seg_desc_t); 261 262 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, 263 &fru_data); 264 if (status != PSVC_SUCCESS) { 265 syslog(LOG_ERR, 266 "Failed psvc_get_attr for FRU info\n"); 267 return (status); 268 } 269 seg_desc_start = seg_desc_start + sizeof (seg_desc_t); 270 if (memcmp(seg_name, "SC", 2) == 0) 271 seg_found = 1; 272 } 273 if (seg_found) { 274 temp_address = segment.segoffset + TEMP_OFFSET; 275 fru_data.buf_start = temp_address; 276 fru_data.buf = (char *)&temp_array; 277 fru_data.read_size = sizeof (temp_array); 278 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, 279 &fru_data); 280 if (status != PSVC_SUCCESS) { 281 syslog(LOG_ERR, 282 "Failed psvc_get_attr for FRU info\n"); 283 return (status); 284 } else { 285 for (j = 0; j < sizeof (temp_array); j++) { 286 if (threshold_names[j] == PSVC_NOT_USED) 287 continue; 288 temp = temp_array[j]; 289 status = psvc_set_attr(hdlp, id, 290 threshold_names[j], &temp); 291 if (status != PSVC_SUCCESS) { 292 return (status); 293 } 294 } 295 } 296 } else { 297 syslog(LOG_ERR, "No FRU Information for %s" 298 " using default temperatures\n", id); 299 } 300 } 301 return (status); 302 } 303 304 #define MAX_TEMP_SENSORS 256 305 306 static int32_t 307 check_temp(psvc_opaque_t hdlp, char *id, int32_t silent) 308 { 309 int32_t lo_warn, hi_warn, lo_shut, hi_shut; 310 uint64_t features; 311 int32_t temp; 312 char previous_state[32]; 313 char led_state[32]; 314 char state[32]; 315 char fault[32]; 316 char label[32]; 317 boolean_t pr; 318 int32_t status = PSVC_SUCCESS; 319 int8_t fail = 0; 320 static int threshold_low_shut[MAX_TEMP_SENSORS] = {0}; 321 static int threshold_high_shut[MAX_TEMP_SENSORS] = {0}; 322 static int threshold_low_warn[MAX_TEMP_SENSORS] = {0}; 323 static int threshold_high_warn[MAX_TEMP_SENSORS] = {0}; 324 int32_t instance; 325 326 status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance); 327 if (status != PSVC_SUCCESS) 328 return (status); 329 330 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &pr); 331 if ((status != PSVC_SUCCESS) || (pr != PSVC_PRESENT)) { 332 return (status); 333 } 334 335 status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state); 336 if (status == PSVC_FAILURE) 337 return (status); 338 339 if ((strcmp(state, PSVC_HOTPLUGGED) == 0)) { 340 return (PSVC_SUCCESS); 341 } 342 343 status = psvc_get_attr(hdlp, id, PSVC_FEATURES_ATTR, &features); 344 if (status != PSVC_SUCCESS) 345 return (status); 346 347 status = psvc_get_attr(hdlp, id, PSVC_LO_WARN_ATTR, &lo_warn); 348 if (status != PSVC_SUCCESS) 349 return (status); 350 351 status = psvc_get_attr(hdlp, id, PSVC_LO_SHUT_ATTR, &lo_shut); 352 if (status != PSVC_SUCCESS) 353 return (status); 354 355 status = psvc_get_attr(hdlp, id, PSVC_HI_WARN_ATTR, &hi_warn); 356 if (status != PSVC_SUCCESS) 357 return (status); 358 359 status = psvc_get_attr(hdlp, id, PSVC_HI_SHUT_ATTR, &hi_shut); 360 if (status != PSVC_SUCCESS) 361 return (status); 362 363 status = psvc_get_attr(hdlp, id, PSVC_SENSOR_VALUE_ATTR, &temp); 364 if (status != PSVC_SUCCESS) { 365 return (status); 366 } 367 368 /* 369 * The following code is to check to see if the temp sensor is 370 * returning a faulty reading due to it either being bad or the 371 * CPU being powered off for some reason. Is so we will alert the user 372 * and just label the sensor bad but not the WHOLE CPU module. 373 */ 374 if ((temp == 127) && (strcmp(state, PSVC_ERROR) != 0)) { 375 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_ERROR); 376 if (status != PSVC_SUCCESS) 377 return (status); 378 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, 379 PSVC_GEN_FAULT); 380 if (status != PSVC_SUCCESS) 381 return (status); 382 syslog(LOG_ERR, TEMP_SENSOR_FAULT, id); 383 return (status); 384 } 385 386 status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label); 387 if (status != PSVC_SUCCESS) 388 return (status); 389 390 /* 391 * if any of the four temperature states (lo_shut, lo_warn, 392 * hi_shut, hi_warn) is detected we will not take an action 393 * until the number of similar back-to-back readings equals 394 * 'n_read_temp' (default is PSVC_THRESHOLD_COUNTER). 395 */ 396 if ((features & PSVC_LOW_SHUT) && temp < lo_shut) { 397 /* 398 * once we are in one state, clear all the 399 * counters for the other three states since 400 * back-to-back readings of these other three 401 * states could not happen anymore. 402 */ 403 threshold_low_warn[instance] = 0; 404 threshold_high_shut[instance] = 0; 405 threshold_high_warn[instance] = 0; 406 threshold_low_shut[instance]++; 407 if (threshold_low_shut[instance] == n_read_temp) { 408 threshold_low_shut[instance] = 0; 409 fail = 1; 410 strcpy(state, PSVC_ERROR); 411 strcpy(fault, PSVC_TEMP_LO_SHUT); 412 strcpy(led_state, PSVC_LED_ON); 413 if (silent == 0) 414 syslog(LOG_ERR, LOWTEMP_CRITICAL_MSG, 415 temp, label); 416 } else { /* Threshold for showing error not reached */ 417 return (PSVC_SUCCESS); 418 } 419 } else if ((features & PSVC_LOW_WARN) && temp < lo_warn) { 420 threshold_low_shut[instance] = 0; 421 threshold_high_shut[instance] = 0; 422 threshold_high_warn[instance] = 0; 423 threshold_low_warn[instance]++; 424 if (threshold_low_warn[instance] == n_read_temp) { 425 threshold_low_warn[instance] = 0; 426 fail = 1; 427 strcpy(state, PSVC_ERROR); 428 strcpy(fault, PSVC_TEMP_LO_WARN); 429 strcpy(led_state, PSVC_LED_ON); 430 if (silent == 0) 431 syslog(LOG_ERR, LOWTEMP_WARNING_MSG, 432 temp, label); 433 } else { /* Threshold for showing error not reached */ 434 return (PSVC_SUCCESS); 435 } 436 } else if ((features & PSVC_HIGH_SHUT) && temp > hi_shut) { 437 threshold_low_warn[instance] = 0; 438 threshold_low_shut[instance] = 0; 439 threshold_high_warn[instance] = 0; 440 threshold_high_shut[instance]++; 441 if (threshold_high_shut[instance] == n_read_temp) { 442 threshold_high_shut[instance] = 0; 443 fail = 1; 444 strcpy(state, PSVC_ERROR); 445 strcpy(fault, PSVC_TEMP_HI_SHUT); 446 strcpy(led_state, PSVC_LED_ON); 447 if (silent == 0) 448 syslog(LOG_ERR, HIGHTEMP_CRITICAL_MSG, 449 temp, label); 450 } else { /* Threshold for showing error not reached */ 451 return (PSVC_SUCCESS); 452 } 453 } else if ((features & PSVC_HIGH_WARN) && temp > hi_warn) { 454 threshold_low_warn[instance] = 0; 455 threshold_low_shut[instance] = 0; 456 threshold_high_shut[instance] = 0; 457 threshold_high_warn[instance]++; 458 if (threshold_high_warn[instance] == n_read_temp) { 459 threshold_high_warn[instance] = 0; 460 fail = 1; 461 strcpy(state, PSVC_ERROR); 462 strcpy(fault, PSVC_TEMP_HI_WARN); 463 strcpy(led_state, PSVC_LED_ON); 464 if (silent == 0) 465 syslog(LOG_ERR, HIGHTEMP_WARNING_MSG, 466 temp, label); 467 } else { /* Threshold for showing error not reached */ 468 return (PSVC_SUCCESS); 469 } 470 } 471 472 /* 473 * If we reached this point then that means that we are either 474 * okay, or we have showed error n_read_temp times. 475 */ 476 if (fail != 1) { 477 /* within limits */ 478 strcpy(state, PSVC_OK); 479 strcpy(fault, PSVC_NO_FAULT); 480 strcpy(led_state, PSVC_LED_OFF); 481 } 482 483 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state); 484 if (status != PSVC_SUCCESS) 485 return (status); 486 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault); 487 if (status != PSVC_SUCCESS) 488 return (status); 489 status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, 490 previous_state); 491 if (status != PSVC_SUCCESS) 492 return (status); 493 494 if (strcmp(previous_state, state) != 0) { 495 char *led_id; 496 int32_t led_count; 497 int32_t i; 498 499 /* change state of fault LEDs */ 500 psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &led_count, 501 PSVC_TS_OVERTEMP_LED); 502 for (i = 0; i < led_count; ++i) { 503 status = psvc_get_attr(hdlp, id, 504 PSVC_ASSOC_ID_ATTR, &led_id, 505 PSVC_TS_OVERTEMP_LED, i); 506 if (status == PSVC_FAILURE) 507 return (status); 508 status = psvc_set_attr(hdlp, led_id, 509 PSVC_LED_STATE_ATTR, led_state); 510 if (status == PSVC_FAILURE) 511 return (status); 512 } 513 } 514 515 return (PSVC_SUCCESS); 516 } 517 518 int32_t 519 psvc_check_temperature_policy_0(psvc_opaque_t hdlp, char *id) 520 { 521 return (check_temp(hdlp, id, 0)); 522 } 523 524 int32_t 525 psvc_check_temperature_silent_policy_0(psvc_opaque_t hdlp, char *id) 526 { 527 return (check_temp(hdlp, id, 1)); 528 } 529 530 int32_t 531 psvc_fan_enable_disable_policy_0(psvc_opaque_t hdlp, char *id) 532 { 533 char state[32], previous_state[32]; 534 char *backup_fan; 535 int32_t status = PSVC_SUCCESS; 536 uint64_t features; 537 char label[32]; 538 boolean_t presence; 539 boolean_t enable; 540 int retry; 541 542 status = psvc_get_attr(hdlp, id, PSVC_FEATURES_ATTR, &features); 543 if (status != PSVC_SUCCESS) 544 return (status); 545 546 retry = 0; 547 do { 548 if (retry) 549 (void) sleep(retry_sleep_fan_present); 550 551 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence); 552 if (status != PSVC_SUCCESS) 553 return (status); 554 retry++; 555 } while ((retry < n_retry_fan_present) && (presence == PSVC_ABSENT)); 556 557 if (presence == PSVC_ABSENT) { 558 status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label); 559 if (status != PSVC_SUCCESS) 560 return (status); 561 562 status = psvc_get_attr(hdlp, id, PSVC_ENABLE_ATTR, &enable); 563 if (status != PSVC_SUCCESS) 564 return (status); 565 566 if (features & PSVC_DEV_PRIMARY) { 567 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 568 &backup_fan, PSVC_ALTERNATE, 0); 569 if (status != PSVC_SUCCESS) 570 return (status); 571 572 enable = PSVC_DISABLED; 573 status = psvc_set_attr(hdlp, id, PSVC_ENABLE_ATTR, 574 &enable); 575 if (status != PSVC_SUCCESS) 576 return (status); 577 578 enable = PSVC_ENABLED; 579 status = psvc_set_attr(hdlp, backup_fan, 580 PSVC_ENABLE_ATTR, &enable); 581 if (status != PSVC_SUCCESS) 582 return (status); 583 } else { 584 enable = PSVC_DISABLED; 585 status = psvc_set_attr(hdlp, id, PSVC_ENABLE_ATTR, 586 &enable); 587 if (status != PSVC_SUCCESS) 588 return (status); 589 } 590 return (PSVC_SUCCESS); 591 } 592 593 /* device was present */ 594 status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state); 595 if (status != PSVC_SUCCESS) 596 return (status); 597 598 status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, previous_state); 599 if (status != PSVC_SUCCESS) 600 return (status); 601 602 if (features & PSVC_DEV_PRIMARY) { 603 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 604 &backup_fan, PSVC_ALTERNATE, 0); 605 if (status != PSVC_SUCCESS) 606 return (status); 607 608 if (strcmp(state, PSVC_OK) == 0) { 609 enable = PSVC_ENABLED; 610 status = psvc_set_attr(hdlp, id, PSVC_ENABLE_ATTR, 611 &enable); 612 if (status != PSVC_SUCCESS) 613 return (status); 614 615 enable = PSVC_DISABLED; 616 status = psvc_set_attr(hdlp, backup_fan, 617 PSVC_ENABLE_ATTR, &enable); 618 if (status != PSVC_SUCCESS) 619 return (status); 620 } 621 if ((strcmp(state, PSVC_ERROR) == 0) && 622 (strcmp(previous_state, PSVC_ERROR) != 0)) { 623 enable = PSVC_DISABLED; 624 status = psvc_set_attr(hdlp, id, PSVC_ENABLE_ATTR, 625 &enable); 626 if (status != PSVC_SUCCESS) 627 return (status); 628 629 enable = PSVC_ENABLED; 630 status = psvc_set_attr(hdlp, backup_fan, 631 PSVC_ENABLE_ATTR, &enable); 632 if (status != PSVC_SUCCESS) 633 return (status); 634 } 635 } else { 636 if ((strcmp(state, PSVC_ERROR) == 0) && 637 (strcmp(previous_state, PSVC_ERROR) != 0)) { 638 status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, 639 label); 640 if (status != PSVC_SUCCESS) 641 return (status); 642 syslog(LOG_ERR, SECONDARY_FAN_FAIL_MSG, label); 643 } 644 } 645 return (status); 646 } 647 648 /* 649 * psvc_switch_fan_onoff_policy_0 650 * Turn a fan on if it is enabled, turn it off if it is disabled. 651 */ 652 int32_t 653 psvc_switch_fan_onoff_policy_0(psvc_opaque_t hdlp, char *id) 654 { 655 boolean_t enable; 656 char *switchid; 657 char state[32]; 658 int32_t status = PSVC_SUCCESS; 659 660 status = psvc_get_attr(hdlp, id, PSVC_ENABLE_ATTR, &enable); 661 if (status != PSVC_SUCCESS) 662 return (status); 663 664 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &switchid, 665 PSVC_FAN_ONOFF_SENSOR, 0); 666 if (status != PSVC_SUCCESS) 667 return (status); 668 669 if (enable == PSVC_DISABLED) { 670 strcpy(state, PSVC_SWITCH_OFF); 671 } else { 672 strcpy(state, PSVC_SWITCH_ON); 673 } 674 675 status = psvc_set_attr(hdlp, switchid, PSVC_SWITCH_STATE_ATTR, state); 676 return (status); 677 } 678 679 static int32_t 680 check_cpu_temp_fault(psvc_opaque_t hdlp, char *cpu, int32_t cpu_count) 681 { 682 char *sensorid; 683 int32_t sensor_count; 684 int32_t status = PSVC_SUCCESS; 685 int32_t i; 686 uint64_t features; 687 char fault[32]; 688 689 status = psvc_get_attr(hdlp, cpu, PSVC_FEATURES_ATTR, &features); 690 if (status == PSVC_FAILURE) 691 return (status); 692 693 psvc_get_attr(hdlp, cpu, PSVC_ASSOC_MATCHES_ATTR, &sensor_count, 694 PSVC_DEV_TEMP_SENSOR); 695 for (i = 0; i < sensor_count; ++i) { 696 status = psvc_get_attr(hdlp, cpu, PSVC_ASSOC_ID_ATTR, 697 &sensorid, PSVC_DEV_TEMP_SENSOR, i); 698 if (status == PSVC_FAILURE) 699 return (status); 700 701 status = psvc_get_attr(hdlp, sensorid, PSVC_FAULTID_ATTR, 702 fault); 703 if (status == PSVC_FAILURE) 704 return (status); 705 706 if ((strcmp(fault, PSVC_TEMP_HI_SHUT) == 0) || 707 (strcmp(fault, PSVC_TEMP_LO_SHUT) == 0)) { 708 if (cpu_count == 1 || cpus_online == 1 || 709 !(features & PSVC_DEV_HOTPLUG)) { 710 system(shutdown_string); 711 } else { 712 /* FIX offline cpu */ 713 --cpus_online; 714 } 715 } 716 } 717 718 return (status); 719 } 720 721 int32_t 722 psvc_shutdown_policy_0(psvc_opaque_t hdlp, char *id) 723 { 724 int32_t cpu_count; 725 char *cpuid; 726 int32_t i; 727 boolean_t present; 728 int32_t status = PSVC_SUCCESS; 729 730 if (cpus_online == 0) { 731 /* obviously, zero isn't correct, count present cpu's */ 732 psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count, 733 PSVC_CPU); 734 for (i = 0; i < cpu_count; ++i) { 735 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 736 &cpuid, PSVC_CPU, i); 737 if (status == PSVC_FAILURE) 738 return (status); 739 740 status = psvc_get_attr(hdlp, cpuid, 741 PSVC_PRESENCE_ATTR, &present); 742 if (status == PSVC_FAILURE && present == PSVC_PRESENT) 743 return (status); 744 if (present == PSVC_PRESENT) 745 ++cpus_online; 746 } 747 } 748 psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count, 749 PSVC_CPU); 750 for (i = 0; i < cpu_count; ++i) { 751 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &cpuid, 752 PSVC_CPU, i); 753 if (status == PSVC_FAILURE) 754 return (status); 755 status = check_cpu_temp_fault(hdlp, cpuid, cpu_count); 756 if (status == PSVC_FAILURE && errno != ENODEV) 757 return (status); 758 } 759 760 return (PSVC_SUCCESS); 761 } 762 763 /* 764 * psvc_keyswitch_position_policy_0 765 * Checks the state of the keyswitch sensors. 766 * If a keyswitch position sensor's state is on, the position 767 * of the key is written to syslog. If none of the sensors 768 * are on (keyswitch is not at one of the detents), a message is sent 769 * to syslog stating that the position is unknown. 770 */ 771 int32_t 772 psvc_keyswitch_position_policy_0(psvc_opaque_t hdlp, char *id) 773 { 774 char position[32]; 775 int32_t status = PSVC_SUCCESS; 776 static int error_reported = 0; 777 static char local_previous_position[32]; 778 static int32_t first_time = 1; 779 int retry; 780 781 if (first_time) { 782 first_time = 0; 783 status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, 784 local_previous_position); 785 if (status != PSVC_SUCCESS) 786 return (status); 787 } 788 789 retry = 0; 790 do { 791 if (retry) 792 (void) sleep(retry_sleep_keyswitch); 793 794 status = psvc_get_attr(hdlp, id, PSVC_SWITCH_STATE_ATTR, 795 position); 796 if (status != PSVC_SUCCESS) 797 return (status); 798 799 if (strcmp(position, PSVC_ERROR) == 0) { 800 if ((errno == EINVAL) && (!(error_reported))) { 801 syslog(LOG_ERR, 802 KEYSWITCH_POS_READ_FAILED_MSG); 803 error_reported = 1; 804 return (PSVC_SUCCESS); 805 } 806 } 807 retry++; 808 } while ((retry < n_retry_keyswitch) && 809 (strcmp(position, local_previous_position) != 0)); 810 811 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, position); 812 if (status != PSVC_SUCCESS) 813 return (status); 814 815 if (strcmp(position, local_previous_position) != 0) { 816 error_reported = 0; 817 strcpy(local_previous_position, position); 818 syslog(LOG_ERR, KEYSWITCH_POS_CHANGED_MSG, position); 819 } 820 821 return (status); 822 } 823 824 int32_t 825 psvc_hotplug_notifier_policy_0(psvc_opaque_t hdlp, char *id) 826 { 827 boolean_t presence, previous_presence; 828 int32_t status = PSVC_SUCCESS; 829 char label[32]; 830 int retry; 831 832 status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, 833 &previous_presence); 834 if (status != PSVC_SUCCESS) 835 return (status); 836 837 retry = 0; 838 do { 839 if (retry) 840 (void) sleep(retry_sleep_hotplug); 841 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence); 842 if (status != PSVC_SUCCESS) 843 return (status); 844 retry++; 845 } while ((retry < n_retry_hotplug) && 846 (presence != previous_presence)); 847 848 849 if (presence != previous_presence) { 850 char parent_path[256]; 851 picl_nodehdl_t child_node; 852 853 status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label); 854 if (status != PSVC_SUCCESS) 855 return (status); 856 857 /* return parent path and node for an object */ 858 psvcplugin_lookup(id, parent_path, &child_node); 859 860 if (presence == PSVC_PRESENT) { 861 char state[32], fault[32]; 862 picl_nodehdl_t parent_node; 863 864 syslog(LOG_ERR, DEVICE_INSERTED_MSG, label); 865 strcpy(state, PSVC_OK); 866 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, 867 state); 868 if (status != PSVC_SUCCESS) 869 return (status); 870 strcpy(fault, PSVC_NO_FAULT); 871 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, 872 fault); 873 if (status != PSVC_SUCCESS) { 874 return (status); 875 } 876 877 status = ptree_get_node_by_path(parent_path, 878 &parent_node); 879 if (status != 0) 880 return (PSVC_FAILURE); 881 status = ptree_add_node(parent_node, child_node); 882 if (status != 0) 883 return (PSVC_FAILURE); 884 } else { 885 syslog(LOG_ERR, DEVICE_REMOVED_MSG, label); 886 887 ptree_delete_node(child_node); 888 889 } 890 } 891 892 status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence); 893 if (status != PSVC_SUCCESS) 894 return (status); 895 896 return (status); 897 } 898 899 int32_t 900 psvc_fan_hotplug_policy_0(psvc_opaque_t hdlp, char *id) 901 { 902 boolean_t presence, previous_presence; 903 int32_t status = PSVC_SUCCESS; 904 char label[32]; 905 int retry; 906 907 status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, 908 &previous_presence); 909 if (status != PSVC_SUCCESS) 910 return (status); 911 912 retry = 0; 913 do { 914 if (retry) 915 (void) sleep(retry_sleep_fan_hotplug); 916 917 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence); 918 if (status != PSVC_SUCCESS) 919 return (status); 920 retry++; 921 } while ((retry < n_retry_fan_hotplug) && 922 (presence != previous_presence)); 923 924 925 if (presence != previous_presence) { 926 char parent_path[256]; 927 picl_nodehdl_t child_node; 928 929 status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label); 930 if (status != PSVC_SUCCESS) 931 return (status); 932 933 /* return parent path and node for an object */ 934 psvcplugin_lookup(id, parent_path, &child_node); 935 936 if (presence == PSVC_PRESENT) { 937 char state[32], fault[32]; 938 char *slot_id; 939 char *led_id; 940 int32_t i, led_count; 941 char led_state[32]; 942 picl_nodehdl_t parent_node; 943 944 syslog(LOG_ERR, DEVICE_INSERTED_MSG, label); 945 946 strcpy(state, PSVC_OK); 947 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, 948 state); 949 if (status != PSVC_SUCCESS) 950 return (status); 951 strcpy(fault, PSVC_NO_FAULT); 952 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, 953 fault); 954 if (status != PSVC_SUCCESS) 955 return (status); 956 957 /* turn off fault LEDs */ 958 psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, 959 &led_count, PSVC_DEV_FAULT_LED); 960 strcpy(led_state, PSVC_LED_OFF); 961 for (i = 0; i < led_count; ++i) { 962 status = psvc_get_attr(hdlp, id, 963 PSVC_ASSOC_ID_ATTR, &led_id, 964 PSVC_DEV_FAULT_LED, i); 965 if (status == PSVC_FAILURE) 966 return (status); 967 status = psvc_set_attr(hdlp, led_id, 968 PSVC_LED_STATE_ATTR, led_state); 969 if (status == PSVC_FAILURE) 970 return (status); 971 } 972 973 /* turn off OK to remove LEDs */ 974 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 975 &slot_id, PSVC_PARENT, 0); 976 if (status != PSVC_SUCCESS) 977 return (status); 978 979 psvc_get_attr(hdlp, slot_id, PSVC_ASSOC_MATCHES_ATTR, 980 &led_count, PSVC_SLOT_REMOVE_LED); 981 strcpy(led_state, PSVC_LED_OFF); 982 for (i = 0; i < led_count; ++i) { 983 status = psvc_get_attr(hdlp, slot_id, 984 PSVC_ASSOC_ID_ATTR, &led_id, 985 PSVC_SLOT_REMOVE_LED, i); 986 if (status == PSVC_FAILURE) 987 return (status); 988 989 status = psvc_set_attr(hdlp, led_id, 990 PSVC_LED_STATE_ATTR, led_state); 991 if (status == PSVC_FAILURE) 992 return (status); 993 } 994 995 ptree_get_node_by_path(parent_path, &parent_node); 996 ptree_add_node(parent_node, child_node); 997 } else { 998 syslog(LOG_ERR, DEVICE_REMOVED_MSG, label); 999 ptree_delete_node(child_node); 1000 } 1001 } 1002 1003 status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence); 1004 if (status != PSVC_SUCCESS) 1005 return (status); 1006 1007 return (status); 1008 } 1009 1010 int32_t 1011 psvc_init_led_policy_0(psvc_opaque_t hdlp, char *id) 1012 { 1013 int32_t status; 1014 1015 status = psvc_set_attr(hdlp, id, PSVC_LED_STATE_ATTR, PSVC_LED_OFF); 1016 return (status); 1017 } 1018 1019 int32_t 1020 psvc_init_state_policy_0(psvc_opaque_t hdlp, char *id) 1021 { 1022 int32_t status; 1023 1024 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_OK); 1025 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, PSVC_NO_FAULT); 1026 return (status); 1027 } 1028 1029 int32_t 1030 psvc_ps_overcurrent_check_policy_0(psvc_opaque_t hdlp, char *power_supply_id) 1031 { 1032 int32_t status = PSVC_SUCCESS; 1033 boolean_t present; 1034 char *sensor_id; 1035 int32_t sensor_count; 1036 int32_t i; 1037 int32_t amps, hi_warn; 1038 1039 status = psvc_get_attr(hdlp, power_supply_id, PSVC_PRESENCE_ATTR, 1040 &present); 1041 if (status == PSVC_FAILURE) { 1042 syslog(LOG_ERR, GET_PRESENCE_FAILED_MSG, power_supply_id, 1043 errno); 1044 return (status); 1045 } 1046 1047 if (present == PSVC_ABSENT) { 1048 errno = ENODEV; 1049 return (PSVC_FAILURE); 1050 } 1051 1052 psvc_get_attr(hdlp, power_supply_id, PSVC_ASSOC_MATCHES_ATTR, 1053 &sensor_count, PSVC_PS_I_SENSOR); 1054 for (i = 0; i < sensor_count; ++i) { 1055 status = psvc_get_attr(hdlp, power_supply_id, 1056 PSVC_ASSOC_ID_ATTR, &sensor_id, PSVC_PS_I_SENSOR, i); 1057 if (status != PSVC_SUCCESS) 1058 return (status); 1059 1060 status = psvc_get_attr(hdlp, sensor_id, PSVC_HI_WARN_ATTR, 1061 &hi_warn); 1062 if (status != PSVC_SUCCESS) 1063 return (status); 1064 1065 status = psvc_get_attr(hdlp, sensor_id, 1066 PSVC_SENSOR_VALUE_ATTR, &s); 1067 if (status != PSVC_SUCCESS) { 1068 syslog(LOG_ERR, GET_SENSOR_FAILED_MSG, sensor_id, 1069 errno); 1070 return (status); 1071 } 1072 1073 if (amps >= hi_warn) { 1074 char label[32]; 1075 1076 status = psvc_get_attr(hdlp, power_supply_id, 1077 PSVC_LABEL_ATTR, &label); 1078 if (status != PSVC_SUCCESS) 1079 return (status); 1080 1081 syslog(LOG_ERR, PS_OVER_CURRENT_MSG, label); 1082 } 1083 } 1084 1085 return (PSVC_SUCCESS); 1086 1087 } 1088 1089 int32_t 1090 psvc_device_fail_notifier_policy_0(psvc_opaque_t hdlp, char *id) 1091 { 1092 int32_t led_count, sensor_count; 1093 char *led_id, *sensor_id; 1094 int i; 1095 char state[32], fault[32], previous_state[32]; 1096 char led_state[32]; 1097 int32_t status = PSVC_SUCCESS; 1098 boolean_t present; 1099 1100 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &present); 1101 if (status == PSVC_FAILURE) 1102 return (status); 1103 1104 if (present == PSVC_ABSENT) { 1105 errno = ENODEV; 1106 return (PSVC_FAILURE); 1107 } 1108 1109 psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count, 1110 PSVC_DEV_FAULT_SENSOR); 1111 for (i = 0; i < sensor_count; ++i) { 1112 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 1113 &sensor_id, PSVC_DEV_FAULT_SENSOR, i); 1114 if (status != PSVC_SUCCESS) 1115 return (status); 1116 1117 status = psvc_get_attr(hdlp, sensor_id, 1118 PSVC_SWITCH_STATE_ATTR, state); 1119 if (status != PSVC_SUCCESS) 1120 return (status); 1121 1122 if (strcmp(state, PSVC_SWITCH_ON) == 0) { 1123 strcpy(state, PSVC_ERROR); 1124 strcpy(fault, PSVC_GEN_FAULT); 1125 } else { 1126 strcpy(state, PSVC_OK); 1127 strcpy(fault, PSVC_NO_FAULT); 1128 } 1129 1130 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state); 1131 if (status != PSVC_SUCCESS) 1132 return (status); 1133 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault); 1134 if (status != PSVC_SUCCESS) 1135 return (status); 1136 status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, 1137 previous_state); 1138 if (status != PSVC_SUCCESS) 1139 return (status); 1140 1141 if (strcmp(state, previous_state) != 0) { 1142 char sensor_label[32]; 1143 char dev_label[32]; 1144 int32_t j; 1145 1146 psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, dev_label); 1147 psvc_get_attr(hdlp, sensor_id, PSVC_LABEL_ATTR, 1148 sensor_label); 1149 1150 if (strcmp(state, PSVC_ERROR) == 0) { 1151 syslog(LOG_ERR, DEVICE_FAILURE_MSG, dev_label, 1152 sensor_label); 1153 strcpy(led_state, PSVC_LED_ON); 1154 } else { 1155 syslog(LOG_ERR, DEVICE_OK_MSG, dev_label); 1156 strcpy(led_state, PSVC_LED_OFF); 1157 } 1158 1159 psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, 1160 &led_count, PSVC_DEV_FAULT_LED); 1161 for (j = 0; j < led_count; j++) { 1162 status = psvc_get_attr(hdlp, id, 1163 PSVC_ASSOC_ID_ATTR, &led_id, 1164 PSVC_DEV_FAULT_LED, j); 1165 if (status != PSVC_SUCCESS) 1166 return (status); 1167 status = psvc_set_attr(hdlp, led_id, 1168 PSVC_LED_STATE_ATTR, led_state); 1169 if (status != PSVC_SUCCESS) { 1170 syslog(LOG_ERR, SET_LED_FAILED_MSG, 1171 led_id, errno); 1172 return (status); 1173 } 1174 } 1175 } 1176 } 1177 1178 return (PSVC_SUCCESS); 1179 } 1180 1181 static float 1182 get_filtered_error(float *last_errors, int current_error) 1183 { 1184 float error; 1185 float adder; 1186 int i = 0; 1187 1188 adder = last_errors[0]; 1189 for (i = 1; i < PSVC_MAXERRORS; i++) { 1190 adder = adder + last_errors[i]; 1191 } 1192 adder = adder + current_error; 1193 error = adder/(PSVC_MAXERRORS+1); 1194 1195 return (error); 1196 } 1197 1198 static int32_t 1199 change_cpu_fans(psvc_opaque_t hdlp, char *fan_id, int32_t fan_speed) 1200 { 1201 int err = PSVC_SUCCESS; 1202 int i; 1203 int32_t control_count; 1204 char *control_id; 1205 int32_t old_fan_speed; 1206 1207 psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_MATCHES_ATTR, &control_count, 1208 PSVC_FAN_DRIVE_CONTROL); 1209 if (control_count == 0) 1210 return (PSVC_SUCCESS); 1211 1212 err = psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_ID_ATTR, &control_id, 1213 PSVC_FAN_DRIVE_CONTROL, 0); 1214 if (err != PSVC_SUCCESS) 1215 return (err); 1216 1217 /* 1218 * this call will return PSVC_FAILURE on the first pass, 1219 * because no value has been set. 1220 */ 1221 err = psvc_get_attr(hdlp, control_id, PSVC_CONTROL_VALUE_ATTR, 1222 &old_fan_speed); 1223 if (err == PSVC_SUCCESS && old_fan_speed == fan_speed) 1224 return (PSVC_SUCCESS); 1225 1226 for (i = 0; i < control_count; i++) { 1227 err = psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_ID_ATTR, 1228 &control_id, PSVC_FAN_DRIVE_CONTROL, i); 1229 if (err != PSVC_SUCCESS) 1230 return (err); 1231 1232 err = psvc_set_attr(hdlp, control_id, PSVC_CONTROL_VALUE_ATTR, 1233 &fan_speed); 1234 if (err == PSVC_FAILURE) { 1235 syslog(LOG_ERR, SET_FANSPEED_FAILED_MSG, control_id, 1236 errno); 1237 return (err); 1238 } 1239 } 1240 return (err); 1241 } 1242 1243 static int32_t 1244 device_temp_check(psvc_opaque_t hdlp, char *fan_id, int32_t *hot_device) 1245 { 1246 int i; 1247 int32_t err = PSVC_SUCCESS; 1248 char *sensor_id; 1249 int32_t sensor_count; 1250 int32_t temp; 1251 1252 *hot_device = 0; 1253 1254 psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count, 1255 PSVC_DEV_TEMP_SENSOR); 1256 for (i = 0; i < sensor_count; i++) { 1257 err = psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_ID_ATTR, 1258 &sensor_id, PSVC_DEV_TEMP_SENSOR, i); 1259 if (err == PSVC_FAILURE) 1260 return (err); 1261 err = psvc_get_attr(hdlp, sensor_id, PSVC_SENSOR_VALUE_ATTR, 1262 &temp); 1263 if (err == PSVC_FAILURE) { 1264 if (errno == ENODEV) { 1265 temp = 0; 1266 } else { 1267 syslog(LOG_ERR, GET_SENSOR_FAILED_MSG, 1268 sensor_id, errno); 1269 return (err); 1270 } 1271 } 1272 1273 if (*hot_device < temp) 1274 *hot_device = temp; 1275 } 1276 return (PSVC_SUCCESS); 1277 } 1278 1279 int32_t 1280 psvc_fan_control_policy_0(psvc_opaque_t hdlp, char *fan_id) 1281 { 1282 boolean_t is_enabled; 1283 int32_t err = PSVC_SUCCESS; 1284 int16_t setpoint, hysteresis, loopgain, loopbias; 1285 int current_error; /* Holds current error */ 1286 /* Signal before signaling */ 1287 float filtered_error; /* Holds the filtered error signal */ 1288 int ampout; /* output of loop amplifier */ 1289 int hot_device; 1290 1291 int16_t error_number; 1292 float last_errors[PSVC_MAXERRORS]; /* Holds the filtered error */ 1293 /* from the last n iterations */ 1294 1295 psvc_get_attr(hdlp, fan_id, PSVC_ENABLE_ATTR, &is_enabled); 1296 if (is_enabled == PSVC_DISABLED) 1297 return (PSVC_SUCCESS); 1298 1299 err = psvc_get_attr(hdlp, fan_id, PSVC_SETPOINT_ATTR, &setpoint); 1300 if (err != PSVC_SUCCESS) 1301 return (err); 1302 1303 err = psvc_get_attr(hdlp, fan_id, PSVC_HYSTERESIS_ATTR, 1304 &hysteresis); 1305 if (err != PSVC_SUCCESS) 1306 return (err); 1307 1308 err = psvc_get_attr(hdlp, fan_id, PSVC_LOOPGAIN_ATTR, &loopgain); 1309 if (err != PSVC_SUCCESS) 1310 return (err); 1311 1312 err = psvc_get_attr(hdlp, fan_id, PSVC_LOOPBIAS_ATTR, &loopbias); 1313 if (err != PSVC_SUCCESS) 1314 return (err); 1315 1316 err = psvc_get_attr(hdlp, fan_id, PSVC_TEMP_DIFFERENTIAL_ATTR, 1317 last_errors); 1318 if (err != PSVC_SUCCESS) 1319 return (err); 1320 1321 err = psvc_get_attr(hdlp, fan_id, PSVC_TEMP_DIFFERENTIAL_INDEX_ATTR, 1322 &error_number); 1323 if (err != PSVC_SUCCESS) 1324 return (err); 1325 1326 err = device_temp_check(hdlp, fan_id, &hot_device); 1327 if (err != PSVC_SUCCESS) { 1328 printf("psvc_fan_control failure in device_temp_check\n"); 1329 return (err); 1330 } 1331 current_error = setpoint - hot_device; 1332 filtered_error = get_filtered_error(last_errors, current_error); 1333 if (filtered_error <= 0 || filtered_error > hysteresis) { 1334 ampout = (int)((filtered_error * loopgain) + loopbias); 1335 if (ampout < 0) 1336 ampout = 0; 1337 if (ampout > 1023) 1338 ampout = 1023; 1339 err = change_cpu_fans(hdlp, fan_id, ampout); 1340 if (err != PSVC_SUCCESS) 1341 return (err); 1342 } 1343 last_errors[error_number++] = current_error; 1344 if (error_number == PSVC_MAXERRORS) 1345 error_number = 0; 1346 1347 err = psvc_set_attr(hdlp, fan_id, PSVC_TEMP_DIFFERENTIAL_ATTR, 1348 last_errors); 1349 if (err != PSVC_SUCCESS) 1350 return (err); 1351 1352 err = psvc_set_attr(hdlp, fan_id, PSVC_TEMP_DIFFERENTIAL_INDEX_ATTR, 1353 &error_number); 1354 if (err != PSVC_SUCCESS) 1355 return (err); 1356 1357 return (PSVC_SUCCESS); 1358 } 1359 1360 int32_t 1361 psvc_fan_present_policy_0(psvc_opaque_t hdlp, char *id) 1362 { 1363 int32_t status = PSVC_SUCCESS; 1364 boolean_t presence; 1365 int fd; 1366 FILE *fp; 1367 int retry; 1368 1369 retry = 0; 1370 do { 1371 if (retry) 1372 (void) sleep(retry_sleep_fan_present); 1373 1374 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence); 1375 if (status != PSVC_SUCCESS) 1376 return (status); 1377 retry++; 1378 } while ((retry < n_retry_fan_present) && (presence == PSVC_ABSENT)); 1379 1380 if (presence == PSVC_ABSENT) { 1381 /* 1382 * We make this open, write, close, call because picld 1383 * starts in rcS.d while print services does not start 1384 * until later (either rc2.d or rc3.d) 1385 */ 1386 fd = open("/dev/console", O_WRONLY | O_NOCTTY); 1387 if (fd != -1) { 1388 fp = fdopen(fd, "w+"); 1389 if (fp != NULL) { 1390 fprintf(fp, FAN_MISSING_MSG, id); 1391 fclose(fp); 1392 } 1393 close(fd); 1394 } 1395 syslog(LOG_ERR, FAN_MISSING_MSG, id); 1396 } 1397 return (status); 1398 } 1399