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