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