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 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Littleneck platform specific environment monitoring policies 29 */ 30 31 #include <syslog.h> 32 #include <unistd.h> 33 #include <stdio.h> 34 #include <libintl.h> 35 #include <string.h> 36 #include <stdlib.h> 37 #include <errno.h> 38 #include <sys/types.h> 39 #include <fcntl.h> 40 #include <sys/time.h> 41 #include <sys/time_impl.h> 42 #include <sys/signal.h> 43 #include <sys/devctl.h> 44 #include <libdevinfo.h> 45 #include <libdevice.h> 46 #include <picl.h> 47 #include <picltree.h> 48 #include <limits.h> 49 #include <sys/systeminfo.h> 50 #include <psvc_objects.h> 51 52 /*LINTLIBRARY*/ 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 PS_TYPE_MSG \ 65 gettext("WARNING: Incorrect type power supply inserted, device %s") 66 #define DEVICE_FAILURE_MSG \ 67 gettext("WARNING: Device %s failure detected by sensor %s\n") 68 #define DEVICE_OK_MSG gettext("Device %s OK") 69 #define DEVTREE_NODE_CREATE_FAILED \ 70 gettext("psvc PICL plugin: Failed to create node for %s, errno = %d") 71 #define DEVTREE_NODE_DELETE_FAILED \ 72 gettext("psvc PICL plugin: Failed to delete node for %s, errno = %d") 73 #define NO_FRU_INFO \ 74 gettext("No FRU Information for %s using default temperatures\n") 75 76 static char *shutdown_string = "shutdown -y -g 60 -i 5 \"OVERTEMP condition\""; 77 78 typedef struct seg_desc { 79 int32_t segdesc; 80 int16_t segoffset; 81 int16_t seglength; 82 } seg_desc_t; 83 84 static int32_t find_segment(psvc_opaque_t hdlp, char *fru, seg_desc_t *segment, 85 char *seg_to_find); 86 87 static int temp_attr[] = { 88 PSVC_HW_HI_SHUT_ATTR, PSVC_HI_SHUT_ATTR, PSVC_HI_WARN_ATTR, 89 PSVC_LO_WARN_ATTR, PSVC_LO_SHUT_ATTR, PSVC_HW_LO_SHUT_ATTR 90 }; 91 92 #define MAX_TEMP_ATTR (sizeof (temp_attr)/sizeof (temp_attr[0])) 93 #define TEMP_OFFSET 12 94 #define PART_NO_OFFSET 152 95 #define NUM_OF_SEG_ADDR 0x1805 96 #define SEG_DESC_START 0x1806 97 #define PSVC_NO_DEVICE -2 98 99 /* 100 * The I2C bus is noisy, and the state may be incorrectly reported as 101 * having changed. When the state changes, we attempt to confirm by 102 * retrying. If any retries indicate that the state has not changed, we 103 * assume the state change(s) were incorrect and the state has not changed. 104 * The following variables are used to store the tuneable values read in 105 * from the optional i2cparam.conf file for this shared object library. 106 */ 107 static int n_retry_temp = PSVC_THRESHOLD_COUNTER; 108 static int retry_sleep_temp = 1; 109 static int n_retry_hotplug = PSVC_NUM_OF_RETRIES; 110 static int retry_sleep_hotplug = 1; 111 static int n_retry_temp_shutdown = PSVC_NUM_OF_RETRIES; 112 static int retry_sleep_temp_shutdown = 1; 113 114 typedef struct { 115 int *pvar; 116 char *texttag; 117 } i2c_noise_param_t; 118 119 static i2c_noise_param_t i2cparams[] = { 120 &n_retry_temp, "n_retry_temp", 121 &retry_sleep_temp, "retry_sleep_temp", 122 &n_retry_hotplug, "n_retry_hotplug", 123 &retry_sleep_hotplug, "retry_sleep_hotplug", 124 NULL, NULL 125 }; 126 127 #pragma init(i2cparams_load) 128 129 static void 130 i2cparams_debug(i2c_noise_param_t *pi2cparams, char *platform, 131 int usingDefaults) 132 { 133 char s[128]; 134 i2c_noise_param_t *p; 135 136 if (!usingDefaults) { 137 (void) snprintf(s, sizeof (s), 138 "# Values from /usr/platform/%s/lib/i2cparam.conf\n", 139 platform); 140 syslog(LOG_WARNING, "%s", s); 141 } else { 142 /* no file - we're using the defaults */ 143 (void) snprintf(s, sizeof (s), 144 "# No /usr/platform/%s/lib/i2cparam.conf file, using defaults\n", 145 platform); 146 } 147 (void) fputs(s, stdout); 148 p = pi2cparams; 149 while (p->pvar != NULL) { 150 (void) snprintf(s, sizeof (s), "%s %d\n", p->texttag, 151 *(p->pvar)); 152 if (!usingDefaults) 153 syslog(LOG_WARNING, "%s", s); 154 (void) fputs(s, stdout); 155 p++; 156 } 157 } 158 159 static void 160 i2cparams_load(void) 161 { 162 FILE *fp; 163 char filename[PATH_MAX]; 164 char platform[64]; 165 char s[128]; 166 char var[128]; 167 int val; 168 i2c_noise_param_t *p; 169 170 if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) { 171 syslog(LOG_ERR, "sysinfo error %s\n", strerror(errno)); 172 return; 173 } 174 (void) snprintf(filename, sizeof (filename), 175 "/usr/platform/%s/lib/i2cparam.conf", platform); 176 /* read thru the i2cparam.conf file and set variables */ 177 if ((fp = fopen(filename, "r")) != NULL) { 178 while (fgets(s, sizeof (s), fp) != NULL) { 179 if (s[0] == '#') /* skip comment lines */ 180 continue; 181 /* try to find a string match and get the value */ 182 if (sscanf(s, "%127s %d", var, &val) != 2) 183 continue; 184 if (val < 1) 185 val = 1; /* clamp min value */ 186 p = &(i2cparams[0]); 187 while (p->pvar != NULL) { 188 if (strncmp(p->texttag, var, sizeof (var)) == 189 0) { 190 *(p->pvar) = val; 191 break; 192 } 193 p++; 194 } 195 } 196 (void) fclose(fp); 197 } 198 /* output the values of the parameters */ 199 i2cparams_debug(&(i2cparams[0]), platform, ((fp == NULL)? 1 : 0)); 200 } 201 202 203 int32_t 204 find_segment(psvc_opaque_t hdlp, char *fru, seg_desc_t *segment, 205 char seg_to_find[2]) 206 { 207 int32_t seg_found = 0, status; 208 int32_t seg_desc_start = SEG_DESC_START, j; 209 int8_t seg_count; 210 char seg_name[2]; 211 fru_info_t fru_data; 212 213 /* 214 * Read the number of segments in the Read Only section 215 */ 216 fru_data.buf_start = NUM_OF_SEG_ADDR; 217 fru_data.buf = (char *)&seg_count; 218 fru_data.read_size = 1; 219 220 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, 221 &fru_data); 222 /* 223 * We test for ENOENT and ENXIO because Littleneck does not 224 * have actual presence sensors and so the only way to see 225 * if a part is there or not is to actually make a call to 226 * that part. 227 */ 228 if (status != PSVC_SUCCESS) { 229 if ((errno == ENOENT) || (errno == ENXIO)) 230 return (PSVC_NO_DEVICE); 231 else 232 return (PSVC_FAILURE); 233 } 234 /* 235 * Read in each segment to find the segment we are looking for 236 */ 237 for (j = 0; (j < seg_count) && (!(seg_found)); j++) { 238 fru_data.buf_start = seg_desc_start; 239 fru_data.buf = seg_name; 240 fru_data.read_size = 2; 241 242 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, 243 &fru_data); 244 245 seg_desc_start = seg_desc_start + 2; 246 fru_data.buf_start = seg_desc_start; 247 fru_data.buf = (char *)segment; 248 fru_data.read_size = sizeof (seg_desc_t); 249 250 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, 251 &fru_data); 252 if (status != PSVC_SUCCESS) { 253 syslog(LOG_ERR, 254 "Failed psvc_get_attr for FRU info\n"); 255 return (PSVC_FAILURE); 256 } 257 seg_desc_start = seg_desc_start + sizeof (seg_desc_t); 258 if (memcmp(seg_name, seg_to_find, 2) == 0) { 259 seg_found = 1; 260 } 261 } 262 return (seg_found); 263 } 264 265 int32_t 266 psvc_update_thresholds_0(psvc_opaque_t hdlp, char *id) 267 { 268 int32_t status = PSVC_SUCCESS; 269 fru_info_t fru_data; 270 char *fru, part_no[7]; 271 int16_t data_offset; 272 int32_t fru_count, i, j, temp_address; 273 int32_t seg_found, temp; 274 seg_desc_t segment; 275 int8_t temps[MAX_TEMP_ATTR]; 276 int32_t num_of_parts = 2; 277 char fruless_parts[2][7] = {"5015988", "5015675"}; 278 int fd; 279 FILE *fp; 280 281 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &fru_count, 282 PSVC_FRU); 283 if (status == PSVC_FAILURE) 284 return (status); 285 286 for (i = 0; i < fru_count; i++) { 287 seg_found = 0; 288 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 289 &fru, PSVC_FRU, i); 290 if (status != PSVC_SUCCESS) 291 return (status); 292 seg_found = find_segment(hdlp, fru, &segment, "ES"); 293 if (seg_found == PSVC_FAILURE) 294 return (PSVC_FAILURE); 295 else if (seg_found == PSVC_NO_DEVICE) 296 return (PSVC_SUCCESS); 297 if (seg_found) { 298 /* 299 * For Littleneck we need to read the offset of the 300 * die-sensor data record 301 */ 302 temp_address = segment.segoffset + TEMP_OFFSET; 303 fru_data.buf_start = temp_address; 304 fru_data.buf = (char *)&data_offset; 305 fru_data.read_size = sizeof (data_offset); 306 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, 307 &fru_data); 308 if (status != PSVC_SUCCESS) { 309 syslog(LOG_ERR, 310 "Failed psvc_get_attr for FRU info\n"); 311 return (status); 312 } 313 314 /* 315 * Now go and get the new temperature settings 316 */ 317 temp_address = segment.segoffset + data_offset; 318 fru_data.buf_start = temp_address; 319 fru_data.buf = (char *)&temps; 320 fru_data.read_size = sizeof (temps); 321 status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, 322 &fru_data); 323 if (status != PSVC_SUCCESS) { 324 syslog(LOG_ERR, 325 "Failed psvc_get_attr for FRU info\n"); 326 return (status); 327 } else { 328 /* 329 * Now set the updated Thresholds 330 */ 331 for (j = 0; j < MAX_TEMP_ATTR; j++) { 332 temp = temps[j]; 333 status = psvc_set_attr(hdlp, id, 334 temp_attr[j], &temp); 335 } 336 } 337 } else { 338 /* 339 * For Littleneck only we need to check for the part 340 * number of the CPU as there are parts that do not 341 * have the ES segment programmed. 342 */ 343 seg_found = find_segment(hdlp, fru, &segment, "SD"); 344 if (seg_found == PSVC_FAILURE) 345 return (PSVC_FAILURE); 346 if (seg_found) { 347 /* 348 * We now goto the SD segment to get the part 349 * number. 350 */ 351 fru_data.buf_start = 352 segment.segoffset + PART_NO_OFFSET; 353 fru_data.buf = part_no; 354 fru_data.read_size = sizeof (part_no); 355 status = psvc_get_attr(hdlp, fru, 356 PSVC_FRU_INFO_ATTR, &fru_data); 357 if (status != PSVC_SUCCESS) { 358 syslog(LOG_ERR, "Failed psvc_get_attr" 359 "for FRU info\n"); 360 return (status); 361 } 362 /* 363 * We are go through the parts list to see 364 * if the part number from the FRU is in 365 * this list. If it is we simply return 366 * as the FRU is not programmed. 367 */ 368 for (j = 0; j < num_of_parts; j++) { 369 if (memcmp(fruless_parts[j], part_no, 370 7) == 0) { 371 return (status); 372 } 373 } 374 } 375 376 /* 377 * If the Part is not in the Part list and we 378 * get to here this means that the FRU is 379 * considered broken (no ES segment found) 380 * and we need to report this. 381 */ 382 /* 383 * We make this open, write, close, call 384 * because picld starts in rcS.d while print 385 * services does not start until later 386 * (either rc2.d or rc3.d). 387 */ 388 fd = open("/dev/console", O_WRONLY | O_NOCTTY); 389 if (fd != -1) { 390 fp = fdopen(fd, "w+"); 391 if (fp != NULL) { 392 fprintf(fp, NO_FRU_INFO, id); 393 fclose(fp); 394 } 395 close(fd); 396 } 397 syslog(LOG_NOTICE, NO_FRU_INFO, id); 398 } 399 } 400 return (status); 401 } 402 403 int32_t 404 psvc_check_temperature_policy_0(psvc_opaque_t hdlp, char *id) 405 { 406 int32_t lo_warn, hi_warn, lo_shut, hi_shut; 407 uint64_t features; 408 int32_t temp; 409 char previous_state[32]; 410 char state[32]; 411 char fault[32]; 412 char label[32]; 413 boolean_t pr; 414 int32_t status = PSVC_SUCCESS; 415 int retry; 416 int8_t temp_oor; 417 418 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &pr); 419 if ((status != PSVC_SUCCESS) || (pr != PSVC_PRESENT)) { 420 return (status); 421 } 422 423 status = psvc_get_attr(hdlp, id, PSVC_FEATURES_ATTR, &features); 424 if (status != PSVC_SUCCESS) 425 return (status); 426 427 status = psvc_get_attr(hdlp, id, PSVC_LO_WARN_ATTR, &lo_warn); 428 if (status != PSVC_SUCCESS) 429 return (status); 430 431 status = psvc_get_attr(hdlp, id, PSVC_LO_SHUT_ATTR, &lo_shut); 432 if (status != PSVC_SUCCESS) 433 return (status); 434 435 status = psvc_get_attr(hdlp, id, PSVC_HI_WARN_ATTR, &hi_warn); 436 if (status != PSVC_SUCCESS) 437 return (status); 438 439 status = psvc_get_attr(hdlp, id, PSVC_HI_SHUT_ATTR, &hi_shut); 440 if (status != PSVC_SUCCESS) 441 return (status); 442 443 status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label); 444 if (status != PSVC_SUCCESS) 445 return (status); 446 447 retry = 0; 448 do { 449 if (retry) 450 (void) sleep(retry_sleep_temp); 451 status = psvc_get_attr(hdlp, id, PSVC_SENSOR_VALUE_ATTR, &temp); 452 if (status != PSVC_SUCCESS) { 453 if ((errno == ENOENT) || (errno == ENXIO)) 454 return (PSVC_SUCCESS); 455 else 456 return (PSVC_FAILURE); 457 } 458 temp_oor = 0; 459 if (((features & PSVC_LOW_SHUT) && temp <= lo_shut) || 460 ((features & PSVC_LOW_WARN) && temp <= lo_warn) || 461 ((features & PSVC_HIGH_SHUT) && temp >= hi_shut) || 462 ((features & PSVC_HIGH_WARN) && temp >= hi_warn)) 463 temp_oor = 1; 464 retry++; 465 } while ((retry < n_retry_temp) && temp_oor); 466 467 if ((features & PSVC_LOW_SHUT) && temp <= lo_shut) { 468 strcpy(state, PSVC_ERROR); 469 strcpy(fault, PSVC_TEMP_LO_SHUT); 470 syslog(LOG_ERR, LOWTEMP_CRITICAL_MSG, temp, label); 471 } else if ((features & PSVC_LOW_WARN) && temp <= lo_warn) { 472 strcpy(state, PSVC_ERROR); 473 strcpy(fault, PSVC_TEMP_LO_WARN); 474 syslog(LOG_ERR, LOWTEMP_WARNING_MSG, temp, label); 475 } else if ((features & PSVC_HIGH_SHUT) && temp >= hi_shut) { 476 strcpy(state, PSVC_ERROR); 477 strcpy(fault, PSVC_TEMP_HI_SHUT); 478 syslog(LOG_ERR, HIGHTEMP_CRITICAL_MSG, temp, label); 479 } else if ((features & PSVC_HIGH_WARN) && temp >= hi_warn) { 480 strcpy(state, PSVC_ERROR); 481 strcpy(fault, PSVC_TEMP_HI_WARN); 482 syslog(LOG_ERR, HIGHTEMP_WARNING_MSG, temp, label); 483 } else { 484 /* within limits */ 485 strcpy(state, PSVC_OK); 486 strcpy(fault, PSVC_NO_FAULT); 487 } 488 489 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state); 490 if (status != PSVC_SUCCESS) 491 return (status); 492 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault); 493 if (status != PSVC_SUCCESS) 494 return (status); 495 status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, 496 previous_state); 497 if (status != PSVC_SUCCESS) 498 return (status); 499 500 if (strcmp(previous_state, state) != 0) { 501 char *led_id; 502 uint8_t _8bit_val; 503 504 led_id = "SYSTEM_FAULT_LED_WR"; 505 506 status = psvc_get_attr(hdlp, led_id, 507 PSVC_GPIO_VALUE_ATTR, &_8bit_val); 508 if (status != PSVC_SUCCESS) 509 return (status); 510 if (strcmp(state, PSVC_ERROR) == 0) 511 _8bit_val &= 0xef; /* clear bit 4 */ 512 else 513 _8bit_val |= 0x10; /* set bit 4 */ 514 _8bit_val |= 0xe4; /* set bits 3, 5, 6, 7 */ 515 516 status = psvc_set_attr(hdlp, led_id, 517 PSVC_GPIO_VALUE_ATTR, &_8bit_val); 518 if (status != PSVC_SUCCESS) 519 return (status); 520 521 } 522 523 return (PSVC_SUCCESS); 524 } 525 526 static int32_t ps0_addr[] = {0, 0xac}; 527 static int32_t ps1_addr[] = {0, 0xae}; 528 529 int32_t 530 psvc_ps_hotplug_policy_0(psvc_opaque_t hdlp, char *id) 531 { 532 boolean_t presence, previous_presence; 533 int32_t status = PSVC_SUCCESS; 534 char label[32]; 535 int i; 536 int32_t led_count; 537 char state[32], fault[32]; 538 boolean_t ps_type; 539 char *sensor_id, *led_id; 540 char led_state[32]; 541 picl_nodehdl_t parent_node; 542 char parent_path[256]; 543 picl_nodehdl_t child_node; 544 int ps_instance; 545 devctl_hdl_t bus_handle, dev_handle; 546 devctl_ddef_t ddef_hdl; 547 char devpath[256]; 548 int retry; 549 550 status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, 551 &previous_presence); 552 if (status != PSVC_SUCCESS) 553 return (status); 554 retry = 0; 555 do { 556 if (retry) 557 (void) sleep(retry_sleep_hotplug); 558 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence); 559 if (status != PSVC_SUCCESS) 560 return (status); 561 retry++; 562 } while ((retry < n_retry_hotplug) && (presence != previous_presence)); 563 564 if (presence == previous_presence) { 565 /* No change */ 566 return (status); 567 } 568 569 status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label); 570 if (status != PSVC_SUCCESS) 571 return (status); 572 573 /* Convert name to node and parent path */ 574 psvcplugin_lookup(id, parent_path, &child_node); 575 576 if (presence == PSVC_PRESENT) { 577 578 /* may detect presence before all connections are made */ 579 sleep(1); 580 581 /* Device added */ 582 syslog(LOG_ERR, DEVICE_INSERTED_MSG, label); 583 584 585 /* Verify P/S is correct type */ 586 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 587 &sensor_id, PSVC_DEV_TYPE_SENSOR, 0); 588 if (status != PSVC_SUCCESS) 589 return (status); 590 status = psvc_get_attr(hdlp, sensor_id, 591 PSVC_GPIO_VALUE_ATTR, &ps_type); 592 if (status != PSVC_SUCCESS) 593 return (status); 594 595 if (ps_type == 1) { /* correct p/s */ 596 strcpy(state, PSVC_OK); 597 strcpy(fault, PSVC_NO_FAULT); 598 strcpy(led_state, PSVC_LED_OFF); 599 } else { /* wrong type */ 600 strcpy(state, PSVC_ERROR); 601 strcpy(fault, PSVC_PS_TYPE_FLT); 602 strcpy(led_state, PSVC_LED_ON); 603 syslog(LOG_ERR, PS_TYPE_MSG, label); 604 605 } 606 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state); 607 if (status != PSVC_SUCCESS) 608 return (status); 609 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault); 610 if (status != PSVC_SUCCESS) 611 return (status); 612 613 /* Set state of fault LEDs */ 614 status = psvc_get_attr(hdlp, sensor_id, PSVC_ASSOC_MATCHES_ATTR, 615 &led_count, PSVC_DEV_FAULT_LED); 616 if (status != PSVC_SUCCESS) { 617 syslog(LOG_ERR, 618 gettext("Failed for PSVC_DEV_FAULT_LED\n")); 619 return (status); 620 } 621 for (i = 0; i < led_count; ++i) { 622 status = psvc_get_attr(hdlp, sensor_id, 623 PSVC_ASSOC_ID_ATTR, &led_id, 624 PSVC_DEV_FAULT_LED, i); 625 if (status != PSVC_SUCCESS) 626 return (status); 627 status = psvc_set_attr(hdlp, led_id, 628 PSVC_LED_STATE_ATTR, led_state); 629 if (status != PSVC_SUCCESS) 630 return (status); 631 } 632 ptree_get_node_by_path(parent_path, &parent_node); 633 ptree_add_node(parent_node, child_node); 634 } else { 635 /* Device removed */ 636 syslog(LOG_ERR, DEVICE_REMOVED_MSG, label); 637 ptree_delete_node(child_node); 638 } 639 640 status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence); 641 if (status != PSVC_SUCCESS) 642 return (status); 643 644 status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &ps_instance); 645 if (status != PSVC_SUCCESS) 646 return (status); 647 648 if (presence != PSVC_PRESENT) { 649 if (ps_instance == 0) 650 strcpy(devpath, 651 "/devices/pci@8,700000/ebus@5/i2c@1,30/power-supply@0,ac:power-supply"); 652 else 653 strcpy(devpath, 654 "/devices/pci@8,700000/ebus@5/i2c@1,30/power-supply@0,ae:power-supply"); 655 656 dev_handle = devctl_device_acquire(devpath, 0); 657 658 if (devctl_device_remove(dev_handle)) { 659 syslog(LOG_ERR, DEVTREE_NODE_DELETE_FAILED, label, 660 errno); 661 status = PSVC_FAILURE; 662 } else { 663 devctl_release(dev_handle); 664 status = PSVC_SUCCESS; 665 } 666 return (status); 667 } 668 669 /* 670 * We fall through to here if the device has been inserted. 671 * Add the devinfo tree node entry for the seeprom and attach 672 * the i2c seeprom driver 673 */ 674 ddef_hdl = devctl_ddef_alloc("power-supply", 0); 675 (void) devctl_ddef_string(ddef_hdl, "compatible", "i2c-at24c64"); 676 if (ps_instance == 0) { 677 (void) devctl_ddef_int_array(ddef_hdl, "reg", 2, ps0_addr); 678 } else { 679 (void) devctl_ddef_int_array(ddef_hdl, "reg", 2, ps1_addr); 680 } 681 682 bus_handle = devctl_bus_acquire( 683 "/devices/pci@8,700000/ebus@5/i2c@1,30:i2c", 0); 684 if (devctl_bus_dev_create(bus_handle, ddef_hdl, 0, &dev_handle)) { 685 syslog(LOG_ERR, DEVTREE_NODE_CREATE_FAILED, label, errno); 686 status = PSVC_FAILURE; 687 } else 688 devctl_release(dev_handle); 689 690 devctl_release(bus_handle); 691 devctl_ddef_free(ddef_hdl); 692 693 return (status); 694 } 695 696 int32_t 697 psvc_device_fail_notifier_policy_0(psvc_opaque_t hdlp, char *id) 698 { 699 int32_t sensor_count; 700 char *led_id, *sensor_id; 701 int i; 702 char state[32], fault[32], previous_state[32]; 703 int32_t status = PSVC_SUCCESS; 704 boolean_t present; 705 706 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &present); 707 if (status == PSVC_FAILURE) 708 return (status); 709 710 if (present == PSVC_ABSENT) { 711 errno = ENODEV; 712 return (PSVC_FAILURE); 713 } 714 715 psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count, 716 PSVC_DEV_FAULT_SENSOR); 717 for (i = 0; i < sensor_count; ++i) { 718 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 719 &sensor_id, PSVC_DEV_FAULT_SENSOR, i); 720 if (status != PSVC_SUCCESS) 721 return (status); 722 723 status = psvc_get_attr(hdlp, sensor_id, 724 PSVC_SWITCH_STATE_ATTR, state); 725 if (status != PSVC_SUCCESS) 726 return (status); 727 728 if (strcmp(state, PSVC_SWITCH_ON) == 0) { 729 strcpy(state, PSVC_ERROR); 730 strcpy(fault, PSVC_GEN_FAULT); 731 } else { 732 strcpy(state, PSVC_OK); 733 strcpy(fault, PSVC_NO_FAULT); 734 } 735 736 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state); 737 if (status != PSVC_SUCCESS) 738 return (status); 739 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault); 740 if (status != PSVC_SUCCESS) 741 return (status); 742 status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, 743 previous_state); 744 if (status != PSVC_SUCCESS) 745 return (status); 746 747 if (strcmp(state, previous_state) != 0) { 748 char sensor_label[32]; 749 char dev_label[32]; 750 uint8_t _8bit_val; 751 752 psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, dev_label); 753 psvc_get_attr(hdlp, sensor_id, PSVC_LABEL_ATTR, 754 sensor_label); 755 if (strcmp(state, PSVC_ERROR) == 0) 756 syslog(LOG_ERR, DEVICE_FAILURE_MSG, dev_label, 757 sensor_label); 758 else 759 syslog(LOG_ERR, DEVICE_OK_MSG, dev_label); 760 761 led_id = "SYSTEM_FAULT_LED_WR"; 762 763 status = psvc_get_attr(hdlp, led_id, 764 PSVC_GPIO_VALUE_ATTR, &_8bit_val); 765 if (status != PSVC_SUCCESS) 766 return (status); 767 768 if (strcmp(state, PSVC_ERROR) == 0) 769 _8bit_val &= 0xef; /* clear bit 4 */ 770 else 771 _8bit_val |= 0x10; /* set bit 4 */ 772 _8bit_val |= 0xe4; /* set bits 3, 5, 6, 7 */ 773 774 status = psvc_set_attr(hdlp, led_id, 775 PSVC_GPIO_VALUE_ATTR, &_8bit_val); 776 if (status != PSVC_SUCCESS) 777 return (status); 778 779 } 780 } 781 782 return (PSVC_SUCCESS); 783 } 784 785 int32_t 786 psvc_init_led_policy_0(psvc_opaque_t hdlp, char *id) 787 { 788 int32_t status = PSVC_SUCCESS; 789 uint8_t _8bit_val; 790 791 status = psvc_get_attr(hdlp, id, 792 PSVC_GPIO_VALUE_ATTR, &_8bit_val); 793 if (status != PSVC_SUCCESS) 794 return (status); 795 796 _8bit_val &= 0xef; /* clear bit 4 */ 797 _8bit_val |= 0xf4; /* set bits 3, 5, 6, 7 */ 798 799 status = psvc_set_attr(hdlp, id, 800 PSVC_GPIO_VALUE_ATTR, &_8bit_val); 801 if (status != PSVC_SUCCESS) 802 return (status); 803 804 return (status); 805 } 806 807 static int32_t 808 check_cpu_temp_fault(psvc_opaque_t hdlp, char *cpu, int32_t cpu_count) 809 { 810 char *sensorid; 811 int32_t sensor_count; 812 int32_t status = PSVC_SUCCESS; 813 int32_t i; 814 char fault[32]; 815 int retry; 816 int8_t temp_oor; 817 818 psvc_get_attr(hdlp, cpu, PSVC_ASSOC_MATCHES_ATTR, &sensor_count, 819 PSVC_DEV_TEMP_SENSOR); 820 for (i = 0; i < sensor_count; ++i) { 821 status = psvc_get_attr(hdlp, cpu, PSVC_ASSOC_ID_ATTR, 822 &sensorid, PSVC_DEV_TEMP_SENSOR, i); 823 if (status == PSVC_FAILURE) 824 return (status); 825 826 retry = 0; 827 do { 828 if (retry) 829 (void) sleep(retry_sleep_temp_shutdown); 830 status = psvc_get_attr(hdlp, sensorid, 831 PSVC_FAULTID_ATTR, fault); 832 if (status == PSVC_FAILURE) 833 return (status); 834 temp_oor = 0; 835 if ((strcmp(fault, PSVC_TEMP_HI_SHUT) == 0) || 836 (strcmp(fault, PSVC_TEMP_LO_SHUT) == 0)) { 837 temp_oor = 1; 838 } 839 retry++; 840 } while ((retry < n_retry_temp_shutdown) && temp_oor); 841 842 if (temp_oor) { 843 system(shutdown_string); 844 } 845 } 846 847 return (status); 848 } 849 850 int32_t 851 psvc_shutdown_policy_0(psvc_opaque_t hdlp, char *id) 852 { 853 int32_t cpu_count; 854 char *cpuid; 855 int32_t i; 856 boolean_t present; 857 int32_t status = PSVC_SUCCESS; 858 859 psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count, 860 PSVC_CPU); 861 for (i = 0; i < cpu_count; ++i) { 862 863 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &cpuid, 864 PSVC_CPU, i); 865 if (status == PSVC_FAILURE) 866 return (status); 867 868 status = psvc_get_attr(hdlp, cpuid, 869 PSVC_PRESENCE_ATTR, &present); 870 if (status == PSVC_FAILURE && present == PSVC_PRESENT) 871 return (status); 872 if (present == PSVC_PRESENT) { 873 status = check_cpu_temp_fault(hdlp, cpuid, cpu_count); 874 if (status == PSVC_FAILURE && errno != ENODEV) 875 return (status); 876 } 877 } 878 879 return (PSVC_SUCCESS); 880 } 881