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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Cherrystone 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 <fcntl.h> 39 #include <sys/types.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 <sys/i2c/clients/i2c_client.h> 49 #include <hbaapi.h> 50 #include <limits.h> 51 #include <sys/systeminfo.h> 52 53 #include <psvc_objects.h> 54 55 /* Device paths for power supply hotplug handling */ 56 #define SEG5_ADDR 0x30 57 #define EBUS_DEV_NAME "/devices/pci@9,700000/ebus@1/" 58 #define SEG5_DEV_NAME EBUS_DEV_NAME "i2c@1,30/" 59 #define SEG5_ADDR_DEV_FMT EBUS_DEV_NAME "i2c@1,%x:devctl" 60 61 #define QLC_NODE "/pci@9,600000/SUNW,qlc@2" 62 63 #define DISK_DRV "ssd" 64 #define MAX_DISKS 2 65 #define WWN_SIZE 8 66 #define ONBOARD_CONTR "../../devices/pci@9,600000/SUNW,qlc@2/fp@0,0:fc" 67 68 /* Bit masks so we don't "wedge" the inputs */ 69 #define PCF8574_BIT_WRITE_VALUE(byte, bit, value)\ 70 ((value << bit) | (byte & (~(0x01 << bit)))) 71 72 #define PDB_MUST_BE_1 0xBF 73 #define PSU_MUST_BE_1 0x7F 74 #define DISKBP_MUST_BE_1 0x0F 75 76 /*LINTLIBRARY*/ 77 78 #define PSVC_MAX_STR_LEN 32 79 80 #define PS_MAX_FAULT_SENSORS 3 81 82 /* 83 * Keep track of the power supply's fail status for reporting if/when 84 * they go good. 85 * ID's: 86 * O PSx_FAULT_SENSOR 87 * 1 Doesn't matter -- only need 0 to be PSx_FAULT_SENSOR 88 * 2 Doesn't matter 89 */ 90 static char *ps_prev_id[2][3] = 91 {{NULL, NULL, NULL}, {NULL, NULL, NULL}}; 92 static int ps_prev_failed[2][3] = {{0, 0, 0}, {0, 0, 0}}; 93 94 /* 95 * Keep track of the power supply's previous presence 96 * because PSVC doesn't do that for us. 97 */ 98 static boolean_t ps_prev_present[2]; 99 static boolean_t ps_present[2]; 100 101 /* Local Routines for the environmental policies */ 102 static int ac_unplugged(psvc_opaque_t, char *); 103 static int ac_power_check(psvc_opaque_t, char *, char *); 104 105 /* 106 * The I2C bus is noisy, and the state may be incorrectly reported as 107 * having changed. When the state changes, we attempt to confirm by 108 * retrying. If any retries indicate that the state has not changed, we 109 * assume the state change(s) were incorrect and the state has not changed. 110 * The following variables are used to store the tuneable values read in 111 * from the optional i2cparam.conf file for this shared object library. 112 */ 113 static int n_retry_fan = PSVC_NUM_OF_RETRIES; 114 static int retry_sleep_fan = 1; 115 static int n_retry_ps_status = PSVC_NUM_OF_RETRIES; 116 static int retry_sleep_ps_status = 1; 117 static int n_retry_pshp = PSVC_NUM_OF_RETRIES; 118 static int retry_sleep_pshp = 1; 119 static int n_retry_diskhp = PSVC_NUM_OF_RETRIES; 120 static int retry_sleep_diskhp = 1; 121 static int n_retry_temp_shutdown = PSVC_NUM_OF_RETRIES; 122 static int retry_sleep_temp_shutdown = 1; 123 static int n_retry_fsp_fault = PSVC_NUM_OF_RETRIES; 124 static int retry_sleep_fsp_fault = 1; 125 126 typedef struct { 127 int *pvar; 128 char *texttag; 129 } i2c_noise_param_t; 130 131 static i2c_noise_param_t i2cparams[] = { 132 &n_retry_fan, "n_retry_fan", 133 &retry_sleep_fan, "retry_sleep_fan", 134 &n_retry_ps_status, "n_retry_ps_status", 135 &retry_sleep_ps_status, "retry_sleep_ps_status", 136 &n_retry_pshp, "n_retry_pshp", 137 &retry_sleep_pshp, "retry_sleep_pshp", 138 &n_retry_diskhp, "n_retry_diskhp", 139 &retry_sleep_diskhp, "retry_sleep_diskhp", 140 &n_retry_temp_shutdown, "n_retry_temp_shutdown", 141 &retry_sleep_temp_shutdown, "retry_sleep_temp_shutdown", 142 &n_retry_fsp_fault, "n_retry_fsp_fault", 143 &retry_sleep_fsp_fault, "retry_sleep_fsp_fault", 144 NULL, NULL 145 }; 146 147 #pragma init(i2cparams_load) 148 149 static void 150 i2cparams_debug(i2c_noise_param_t *pi2cparams, char *platform, 151 int usingDefaults) 152 { 153 char s[128]; 154 i2c_noise_param_t *p; 155 156 if (!usingDefaults) { 157 (void) snprintf(s, sizeof (s), 158 "# Values from /usr/platform/%s/lib/i2cparam.conf\n", 159 platform); 160 syslog(LOG_WARNING, "%s", s); 161 } else { 162 /* no file - we're using the defaults */ 163 (void) snprintf(s, sizeof (s), 164 "# No /usr/platform/%s/lib/i2cparam.conf file, using defaults\n", 165 platform); 166 } 167 (void) fputs(s, stdout); 168 p = pi2cparams; 169 while (p->pvar != NULL) { 170 (void) snprintf(s, sizeof (s), "%s %d\n", p->texttag, 171 *(p->pvar)); 172 if (!usingDefaults) 173 syslog(LOG_WARNING, "%s", s); 174 (void) fputs(s, stdout); 175 p++; 176 } 177 } 178 179 static void 180 i2cparams_load(void) 181 { 182 FILE *fp; 183 char filename[PATH_MAX]; 184 char platform[64]; 185 char s[128]; 186 char var[128]; 187 int val; 188 i2c_noise_param_t *p; 189 190 if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) { 191 syslog(LOG_ERR, "sysinfo error %s\n", strerror(errno)); 192 return; 193 } 194 (void) snprintf(filename, sizeof (filename), 195 "/usr/platform/%s/lib/i2cparam.conf", platform); 196 /* read thru the i2cparam.conf file and set variables */ 197 if ((fp = fopen(filename, "r")) != NULL) { 198 while (fgets(s, sizeof (s), fp) != NULL) { 199 if (s[0] == '#') /* skip comment lines */ 200 continue; 201 /* try to find a string match and get the value */ 202 if (sscanf(s, "%127s %d", var, &val) != 2) 203 continue; 204 if (val < 1) 205 val = 1; /* clamp min value */ 206 p = &(i2cparams[0]); 207 while (p->pvar != NULL) { 208 if (strncmp(p->texttag, var, sizeof (var)) == 209 0) { 210 *(p->pvar) = val; 211 break; 212 } 213 p++; 214 } 215 } 216 (void) fclose(fp); 217 } 218 /* output the values of the parameters */ 219 i2cparams_debug(&(i2cparams[0]), platform, ((fp == NULL)? 1 : 0)); 220 } 221 222 /* 223 * Create an I2C device node. 224 */ 225 static int 226 create_i2c_node(char *nd_name, char *nd_compat, int nd_nexi, int *nd_reg) 227 { 228 devctl_ddef_t ddef_hdl = NULL; 229 devctl_hdl_t bus_hdl = NULL; 230 devctl_hdl_t dev_hdl = NULL; 231 char buf[MAXPATHLEN]; 232 char dev_path[MAXPATHLEN]; 233 int rv = PSVC_FAILURE; 234 235 (void) snprintf(buf, sizeof (buf), SEG5_ADDR_DEV_FMT, nd_nexi); 236 bus_hdl = devctl_bus_acquire(buf, 0); 237 if (bus_hdl == NULL) 238 goto bad; 239 240 /* device definition properties */ 241 ddef_hdl = devctl_ddef_alloc(nd_name, 0); 242 (void) devctl_ddef_string(ddef_hdl, "compatible", nd_compat); 243 (void) devctl_ddef_int_array(ddef_hdl, "reg", 2, nd_reg); 244 245 /* create the device node */ 246 if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl)) 247 goto bad; 248 249 if (devctl_get_pathname(dev_hdl, dev_path, MAXPATHLEN) == NULL) 250 goto bad; 251 252 #ifdef DEBUG 253 syslog(LOG_ERR, "PSVC: create_i2c_node: Device node created: (%s)", 254 dev_path); 255 #endif 256 rv = PSVC_SUCCESS; 257 bad: 258 if (dev_hdl) devctl_release(dev_hdl); 259 if (ddef_hdl) devctl_ddef_free(ddef_hdl); 260 if (bus_hdl) devctl_release(bus_hdl); 261 return (rv); 262 } 263 264 /* 265 * Delete an I2C device node given the device path. 266 */ 267 static void 268 delete_i2c_node(char *nd) 269 { 270 int rv; 271 devctl_hdl_t dev_hdl; 272 273 dev_hdl = devctl_device_acquire(nd, 0); 274 if (dev_hdl == NULL) { 275 return; 276 } 277 278 rv = devctl_device_remove(dev_hdl); 279 if (rv != DDI_SUCCESS) 280 perror(nd); 281 #ifdef DEBUG 282 else 283 syslog(LOG_ERR, "Device node deleted: (%s)", nd); 284 #endif 285 devctl_release(dev_hdl); 286 } 287 288 289 /* PCF8574 Reset Function */ 290 static int 291 send_pcf8574_reset(psvc_opaque_t hdlp, char *reset_dev) 292 { 293 int err; 294 uint8_t reset_bits[2] = {0x7F, 0xFF}; 295 int i; 296 for (i = 0; i < 2; i++) { 297 err = psvc_set_attr(hdlp, reset_dev, PSVC_GPIO_VALUE_ATTR, 298 &reset_bits[i]); 299 if (err != PSVC_SUCCESS) { 300 #ifdef DEBUG 301 syslog(LOG_ERR, 302 gettext("Reset to %s with 0x%x failed"), 303 reset_dev, reset_bits[i]); 304 #endif 305 return (err); 306 } 307 } 308 /* Need to give u-code a chance to update */ 309 sleep(3); 310 return (err); 311 } 312 313 static int 314 pcf8574_write_bit(psvc_opaque_t hdlp, char *id, uint8_t bit_num, 315 uint8_t bit_val, uint8_t write_must_be_1) 316 { 317 int rv = PSVC_FAILURE; 318 uint8_t byte; 319 320 rv = psvc_get_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR, &byte); 321 if (rv != PSVC_SUCCESS) 322 return (rv); 323 324 byte = PCF8574_BIT_WRITE_VALUE(byte, bit_num, bit_val); 325 byte |= write_must_be_1; 326 rv = psvc_set_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR, &byte); 327 return (rv); 328 } 329 330 /* 331 * To enable the i2c bus, we must toggle bit 6 on the PDB's 332 * PCF8574 (0x4C) high->low->high 333 */ 334 static int 335 pdb_enable_i2c(psvc_opaque_t hdlp) 336 { 337 int rv = PSVC_SUCCESS, i; 338 int bit_vals[3] = {1, 0, 1}; 339 int bit_num = 6; 340 341 for (i = 0; i < 3; i++) { 342 rv = pcf8574_write_bit(hdlp, "PDB_PORT", bit_num, bit_vals[i], 343 PDB_MUST_BE_1); 344 if (rv != PSVC_SUCCESS) { 345 goto bad; 346 } 347 } 348 return (rv); 349 bad: 350 #ifdef DEBUG 351 syslog(LOG_ERR, gettext("PDB I2C Bus Enabling Failed")); 352 #endif 353 return (rv); 354 } 355 356 int32_t 357 psvc_init_disk_bp_policy_0(psvc_opaque_t hdlp, char *id) 358 { 359 uint8_t reset = 0xFF; 360 return (psvc_set_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR, 361 &reset)); 362 } 363 364 int32_t 365 pcf8574_init_policy_0(psvc_opaque_t hdlp, char *id) 366 { 367 return (send_pcf8574_reset(hdlp, id)); 368 } 369 370 static int32_t 371 check_fan(psvc_opaque_t hdlp, char *tray_id, char *fan_id, boolean_t *fault_on) 372 { 373 int status; 374 int speed; 375 int low_thresh; 376 boolean_t have_fault = 0; 377 char *tach_id; 378 char state[PSVC_MAX_STR_LEN]; 379 char prev_state[PSVC_MAX_STR_LEN]; 380 char fault_state[PSVC_MAX_STR_LEN]; 381 int retry; 382 383 /* Get this fan object's corresponding fan tach */ 384 status = psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_ID_ATTR, 385 &tach_id, PSVC_FAN_SPEED_TACHOMETER, 0); 386 if (status != PSVC_SUCCESS) 387 return (status); 388 389 /* Get the low fan speed threshold */ 390 status = psvc_get_attr(hdlp, tach_id, PSVC_LO_WARN_ATTR, &low_thresh); 391 if (status != PSVC_SUCCESS) 392 return (status); 393 394 retry = 0; 395 do { 396 if (retry) 397 (void) sleep(retry_sleep_fan); 398 /* Get the fan speed */ 399 status = psvc_get_attr(hdlp, tach_id, PSVC_SENSOR_VALUE_ATTR, 400 &speed); 401 if (status != PSVC_SUCCESS) 402 return (status); 403 404 if (speed <= low_thresh) { /* We see a fault */ 405 strlcpy(fault_state, "DEVICE_FAIL", 406 sizeof (fault_state)); 407 strlcpy(state, PSVC_ERROR, sizeof (state)); 408 have_fault = 1; 409 } else { /* Fault gone? */ 410 strlcpy(fault_state, PSVC_NO_FAULT, 411 sizeof (fault_state)); 412 strlcpy(state, PSVC_OK, sizeof (state)); 413 have_fault = 0; 414 } 415 retry++; 416 } while ((retry < n_retry_fan) && (speed <= low_thresh)); 417 418 /* Assign new states to the fan object */ 419 status = psvc_set_attr(hdlp, fan_id, PSVC_FAULTID_ATTR, fault_state); 420 if (status != PSVC_SUCCESS) 421 return (status); 422 status = psvc_set_attr(hdlp, fan_id, PSVC_STATE_ATTR, state); 423 if (status != PSVC_SUCCESS) 424 return (status); 425 426 /* Get state and previous state */ 427 status = psvc_get_attr(hdlp, fan_id, PSVC_STATE_ATTR, state); 428 if (status != PSVC_SUCCESS) 429 return (status); 430 status = psvc_get_attr(hdlp, fan_id, PSVC_PREV_STATE_ATTR, prev_state); 431 if (status != PSVC_SUCCESS) 432 return (status); 433 434 /* Display notices */ 435 if (strcmp(state, PSVC_OK) != 0) { 436 syslog(LOG_ERR, gettext("WARNING: %s (%s) failure detected"), 437 tray_id, fan_id); 438 } else { 439 if (strcmp(state, prev_state) != 0) { 440 syslog(LOG_ERR, gettext("NOTICE: Device %s (%s) OK"), 441 tray_id, fan_id); 442 } 443 } 444 445 *fault_on |= have_fault; 446 return (PSVC_SUCCESS); 447 } 448 449 /* 450 * This policy acts on fan trays. It looks at each of its fans 451 * and checks the speeds. If the fan speed is less than the threshold, 452 * then indicate: console, log, LED. 453 */ 454 int32_t 455 psvc_fan_fault_check_policy_0(psvc_opaque_t hdlp, char *id) 456 { 457 int fan_count; 458 int led_count; 459 int err, i; 460 char *led_id; 461 char *fan_id; 462 char led_state[PSVC_MAX_STR_LEN]; 463 char state[PSVC_MAX_STR_LEN]; 464 char prev_state[PSVC_MAX_STR_LEN]; 465 boolean_t fault_on = 0; 466 467 /* Get the number of fans associated with this fan tray. */ 468 err = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &fan_count, 469 PSVC_FAN_TRAY_FANS); 470 if (err != PSVC_SUCCESS) 471 return (err); 472 473 for (i = 0; i < fan_count; i++) { 474 err = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 475 &fan_id, PSVC_FAN_TRAY_FANS, i); 476 if (err != PSVC_SUCCESS) 477 return (err); 478 479 err = check_fan(hdlp, id, fan_id, &fault_on); 480 if (err != PSVC_SUCCESS) 481 return (err); 482 } 483 484 if (fault_on) { 485 strlcpy(led_state, PSVC_LED_ON, sizeof (led_state)); 486 err = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_ERROR); 487 if (err != PSVC_SUCCESS) 488 return (err); 489 490 } else { 491 strlcpy(led_state, PSVC_LED_OFF, sizeof (led_state)); 492 err = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_OK); 493 if (err != PSVC_SUCCESS) 494 return (err); 495 } 496 497 err = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state); 498 if (err != PSVC_SUCCESS) 499 return (err); 500 err = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, prev_state); 501 if (err != PSVC_SUCCESS) 502 return (err); 503 504 /* 505 * Set leds according to the fan tray's states. 506 * (we only do this if there is a change of state in order 507 * to reduce i2c traffic) 508 */ 509 if (strcmp(state, prev_state) != 0) { 510 err = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, 511 &led_count, PSVC_DEV_FAULT_LED); 512 if (err != PSVC_SUCCESS) 513 return (err); 514 for (i = 0; i < led_count; i++) { 515 err = psvc_get_attr(hdlp, id, 516 PSVC_ASSOC_ID_ATTR, &led_id, 517 PSVC_DEV_FAULT_LED, i); 518 if (err != PSVC_SUCCESS) 519 return (err); 520 err = psvc_set_attr(hdlp, led_id, 521 PSVC_LED_STATE_ATTR, led_state); 522 if (err != PSVC_SUCCESS) 523 return (err); 524 err = psvc_get_attr(hdlp, led_id, 525 PSVC_LED_STATE_ATTR, led_state); 526 if (err != PSVC_SUCCESS) 527 return (err); 528 } 529 } 530 return (err); 531 } 532 533 static int32_t 534 check_cpu_temp_fault(psvc_opaque_t hdlp, char *cpu, int32_t cpu_count) 535 { 536 char *sensorid; 537 int32_t sensor_count; 538 int32_t status = PSVC_SUCCESS; 539 int32_t i; 540 char fault[PSVC_MAX_STR_LEN]; 541 int retry; 542 543 psvc_get_attr(hdlp, cpu, PSVC_ASSOC_MATCHES_ATTR, &sensor_count, 544 PSVC_DEV_TEMP_SENSOR); 545 for (i = 0; i < sensor_count; ++i) { 546 status = psvc_get_attr(hdlp, cpu, PSVC_ASSOC_ID_ATTR, 547 &sensorid, PSVC_DEV_TEMP_SENSOR, i); 548 if (status == PSVC_FAILURE) 549 return (status); 550 551 retry = 0; 552 do { 553 if (retry) 554 (void) sleep(retry_sleep_temp_shutdown); 555 status = psvc_get_attr(hdlp, sensorid, 556 PSVC_FAULTID_ATTR, fault); 557 if (status == PSVC_FAILURE) 558 return (status); 559 retry++; 560 } while (((strcmp(fault, PSVC_TEMP_LO_SHUT) == 0) || 561 (strcmp(fault, PSVC_TEMP_HI_SHUT) == 0)) && 562 (retry < n_retry_temp_shutdown)); 563 564 if ((strcmp(fault, PSVC_TEMP_HI_SHUT) == 0) || 565 (strcmp(fault, PSVC_TEMP_LO_SHUT) == 0)) { 566 system("shutdown -y -g 60 -i 5 \"OVERTEMP condition\""); 567 } 568 } 569 570 return (status); 571 } 572 573 int32_t 574 psvc_shutdown_policy_0(psvc_opaque_t hdlp, char *id) 575 { 576 int32_t cpu_count; 577 char *cpuid; 578 int32_t i; 579 boolean_t present; 580 int32_t status = PSVC_SUCCESS; 581 582 psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count, 583 PSVC_CPU); 584 for (i = 0; i < cpu_count; ++i) { 585 586 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &cpuid, 587 PSVC_CPU, i); 588 if (status == PSVC_FAILURE) 589 return (status); 590 591 status = psvc_get_attr(hdlp, cpuid, 592 PSVC_PRESENCE_ATTR, &present); 593 if (status == PSVC_FAILURE && present == PSVC_PRESENT) 594 return (status); 595 if (present == PSVC_PRESENT) { 596 status = check_cpu_temp_fault(hdlp, cpuid, cpu_count); 597 if (status == PSVC_FAILURE && errno != ENODEV) 598 return (status); 599 } 600 } 601 602 return (PSVC_SUCCESS); 603 } 604 605 /* 606 * Checks device specified by the PSVC_DEV_FAULT_SENSOR association 607 * for errors, and if there is, then report and turn on the FSP Fault 608 * Led. 609 */ 610 int32_t 611 psvc_fsp_device_fault_check_policy_0(psvc_opaque_t hdlp, char *id) 612 { 613 int32_t status; 614 int32_t i; 615 int32_t device_count = 0; 616 char device_state[PSVC_MAX_STR_LEN]; 617 char *device_id; 618 int32_t failed_count = 0; 619 static int32_t led_on = 0; 620 int retry; 621 622 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, 623 &device_count, PSVC_DEV_FAULT_SENSOR); 624 if (status != PSVC_SUCCESS) 625 return (status); 626 627 for (i = 0; i < device_count; i++) { 628 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 629 &device_id, PSVC_DEV_FAULT_SENSOR, i); 630 if (status != PSVC_SUCCESS) 631 return (status); 632 633 retry = 0; 634 do { 635 if (retry) 636 (void) sleep(retry_sleep_fsp_fault); 637 status = psvc_get_attr(hdlp, device_id, PSVC_STATE_ATTR, 638 device_state); 639 if (status != PSVC_SUCCESS) 640 return (status); 641 642 if (strcmp(device_state, PSVC_OK) != 0 && 643 strcmp(device_state, PSVC_HOTPLUGGED) != 0 && 644 strcmp(device_state, "NO AC POWER") != 0 && 645 strlen(device_state) != 0) { 646 failed_count++; 647 } 648 retry++; 649 } while ((retry < n_retry_fsp_fault) && (failed_count)); 650 } 651 if (failed_count == 0 && led_on) { 652 syslog(LOG_ERR, gettext("%s has turned OFF"), id); 653 status = psvc_set_attr(hdlp, id, PSVC_LED_STATE_ATTR, 654 PSVC_LED_OFF); 655 led_on = 0; 656 } 657 658 if (failed_count > 0 && ! led_on) { 659 syslog(LOG_ERR, 660 gettext("%s has turned ON"), id); 661 status = psvc_set_attr(hdlp, id, PSVC_LED_STATE_ATTR, 662 PSVC_LED_ON); 663 led_on = 1; 664 } 665 666 return (PSVC_SUCCESS); 667 } 668 669 /* Power Supply Policy Helper and Worker Functions */ 670 static void 671 ps_reset_prev_failed(int index) 672 { 673 int i; 674 /* Reset the power supply's failure information */ 675 for (i = 0; i < 3; i++) { 676 ps_prev_id[index][i] = NULL; 677 ps_prev_failed[index][i] = 0; 678 } 679 680 } 681 static int 682 check_i2c_access(psvc_opaque_t hdlp, char *id) 683 { 684 int rv; 685 char state[PSVC_MAX_STR_LEN]; 686 char ps_fault_sensor[PSVC_MAX_STR_LEN]; 687 688 snprintf(ps_fault_sensor, sizeof (ps_fault_sensor), 689 "%s_FAULT_SENSOR", id); 690 691 rv = psvc_get_attr(hdlp, ps_fault_sensor, PSVC_SWITCH_STATE_ATTR, 692 &state); 693 return (rv); 694 } 695 696 /* 697 * This routine takes in the PSVC handle pointer, the PS name, and the 698 * instance number (0 or 1). It simply make a psvc_get call to get the 699 * presence of each of the children under the PS. This call will set the 700 * presence state of the child device if it was not there when the system 701 * was booted. 702 */ 703 static int 704 handle_ps_hotplug_children_presence(psvc_opaque_t hdlp, char *id) 705 { 706 char *child_add_on[4] = {"_RESET", "_LOGICAL_STATE", "_AC_IN_SENSOR", 707 "_FAULT_SENSOR"}; 708 int add_ons = 4; 709 char addon_id[PICL_PROPNAMELEN_MAX]; 710 char *sensor_id; 711 int32_t status = PSVC_SUCCESS; 712 boolean_t presence; 713 int j; 714 715 /* Go through the add on list and set presence */ 716 for (j = 0; j < add_ons; j++) { 717 snprintf(addon_id, sizeof (addon_id), "%s%s", id, 718 child_add_on[j]); 719 status = psvc_get_attr(hdlp, addon_id, PSVC_PRESENCE_ATTR, 720 &presence); 721 if (status != PSVC_SUCCESS) 722 return (status); 723 } 724 725 /* Go through each PS's fault sensors */ 726 for (j = 0; j < PS_MAX_FAULT_SENSORS; j++) { 727 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 728 &(sensor_id), PSVC_DEV_FAULT_SENSOR, j); 729 if (status != PSVC_SUCCESS) 730 return (status); 731 status = psvc_get_attr(hdlp, sensor_id, PSVC_PRESENCE_ATTR, 732 &presence); 733 if (status != PSVC_SUCCESS) 734 return (status); 735 } 736 737 /* Go through each PS's onboard i2c hardware */ 738 for (j = 0; j < 2; j++) { 739 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 740 &(sensor_id), PSVC_PHYSICAL_DEVICE, j); 741 if (status != PSVC_SUCCESS) 742 return (status); 743 status = psvc_get_attr(hdlp, sensor_id, PSVC_PRESENCE_ATTR, 744 &presence); 745 if (status != PSVC_SUCCESS) 746 return (status); 747 } 748 749 return (status); 750 } 751 752 static int 753 handle_ps_hotplug(psvc_opaque_t hdlp, char *id, boolean_t present) 754 { 755 int32_t status = PSVC_SUCCESS; 756 int32_t instance; 757 picl_nodehdl_t parent_node; 758 picl_nodehdl_t child_node; 759 char info[PSVC_MAX_STR_LEN]; 760 char ps_logical_state[PICL_PROPNAMELEN_MAX]; 761 char parent_path[PICL_PROPNAMELEN_MAX]; 762 char ps_path[PICL_PROPNAMELEN_MAX]; 763 static int fruprom_addr[2][2] = { {0, 0xa2}, {0, 0xa0} }; 764 static int pcf8574_addr[2][2] = { {0, 0x72}, {0, 0x70} }; 765 char dev_path[MAXPATHLEN]; 766 767 /* Convert name to node and parent path */ 768 psvcplugin_lookup(id, parent_path, &child_node); 769 770 /* 771 * Get the power supply's instance. 772 * Used to index the xxx_addr arrays 773 */ 774 status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance); 775 if (status != PSVC_SUCCESS) 776 return (status); 777 778 if (present == PSVC_PRESENT && !ps_prev_present[instance]) { 779 /* Service Power Supply Insertion */ 780 syslog(LOG_ERR, gettext("Device %s inserted"), id); 781 782 /* PICL Tree Maintenance */ 783 ptree_get_node_by_path(parent_path, &parent_node); 784 ptree_add_node(parent_node, child_node); 785 snprintf(ps_path, sizeof (ps_path), "%s/%s", parent_path, id); 786 psvcplugin_add_children(ps_path); 787 788 /* 789 * This code to update the presences of power supply 790 * child devices in the event that picld was started 791 * without a power supply present. This call makes 792 * the devices available after that initial insertion. 793 */ 794 status = handle_ps_hotplug_children_presence(hdlp, id); 795 796 /* 797 * Device Tree Maintenance 798 * Add the devinfo tree node entry for the pcf8574 and seeprom 799 * and attach their drivers. 800 */ 801 status |= create_i2c_node("ioexp", "i2c-pcf8574", SEG5_ADDR, 802 pcf8574_addr[instance]); 803 status |= create_i2c_node("fru", "i2c-at24c64", SEG5_ADDR, 804 fruprom_addr[instance]); 805 } else { 806 /* Service Power Supply Removal */ 807 syslog(LOG_ERR, gettext("Device %s removed"), id); 808 809 /* Reset the power supply's failure information */ 810 ps_reset_prev_failed(instance); 811 812 /* PICL Tree Maintenance */ 813 if (ptree_delete_node(child_node) != PICL_SUCCESS) 814 syslog(LOG_ERR, "ptree_delete_node failed!"); 815 816 /* 817 * The hardcoded subscript in pcf8574_add[instance][1] 818 * refers to the address. We are appending the address to 819 * device path. Both elements are used when creating 820 * the i2c node (above). 821 */ 822 snprintf(dev_path, sizeof (dev_path), 823 SEG5_DEV_NAME"ioexp@0,%x:pcf8574", 824 pcf8574_addr[instance][1]); 825 delete_i2c_node(dev_path); 826 827 snprintf(dev_path, sizeof (dev_path), 828 SEG5_DEV_NAME"fru@0,%x:fru", fruprom_addr[instance][1]); 829 delete_i2c_node(dev_path); 830 } 831 832 snprintf(ps_logical_state, sizeof (ps_logical_state), 833 "%s_LOGICAL_STATE", id); 834 835 strlcpy(info, PSVC_OK, sizeof (info)); 836 status |= psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, info); 837 status |= psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR, info); 838 839 strlcpy(info, PSVC_NO_FAULT, sizeof (info)); 840 status |= psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, info); 841 842 /* Enable the i2c connection to the power supply */ 843 status |= pdb_enable_i2c(hdlp); 844 return (status); 845 } 846 847 /* 848 * check_ps_state() Checks for: 849 * 850 * - Failure bits: 851 * Power Supply Fan Failure 852 * Power Supply Temperature Failure 853 * Power Supply Generic Fault 854 * Power Supply AC Cord Plugged In 855 * 856 * - If we see a "bad" state we will report an error. 857 * 858 * - "Bad" states: 859 * Fault bit shows fault. 860 * Temperature fault shows fault. 861 * Fan fault shows fault. 862 * AC power NOT okay to supply. 863 * 864 * - If we see that the AC Cord is not plugged in, then the the other 865 * failure bits are invalid. 866 * 867 * - Send pcf8574_reset at the end of the policy if we see 868 * any "bad" states. 869 */ 870 static int32_t 871 check_ps_state(psvc_opaque_t hdlp, char *id) 872 { 873 int32_t sensor_count; 874 int32_t status = PSVC_SUCCESS; 875 int32_t i; 876 int32_t fault_on = 0; 877 char *sensor_id; 878 char ps_ok_sensor[PICL_PROPNAMELEN_MAX]; 879 char ps_logical_state[PICL_PROPNAMELEN_MAX]; 880 char ps_reset[PICL_PROPNAMELEN_MAX]; 881 char previous_state[PSVC_MAX_STR_LEN]; 882 char state[PSVC_MAX_STR_LEN]; 883 char fault[PSVC_MAX_STR_LEN]; 884 int ps_okay = 1; /* Keep track of the PDB PS OK Bit */ 885 int instance; 886 int retry; 887 888 /* Logical state id */ 889 snprintf(ps_logical_state, sizeof (ps_logical_state), 890 "%s_LOGICAL_STATE", id); 891 892 /* 893 * ac_power_check updates the Power Supply state with "NO AC POWER" if 894 * the power cord is out OR PSVC_OK if the power cord is in. 895 */ 896 status = ac_power_check(hdlp, id, ps_logical_state); 897 if (status == PSVC_FAILURE) 898 return (status); 899 900 /* 901 * After running ac_power_check we now need to get the current state 902 * of the PS. If the power supply state is "NO AC POWER" then we do 903 * not need to check for failures and we return. 904 */ 905 status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state); 906 if (status != PSVC_SUCCESS) 907 return (status); 908 909 if (strcmp(state, "NO AC POWER") == 0) 910 return (status); 911 912 status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, previous_state); 913 if (status != PSVC_SUCCESS) 914 return (status); 915 916 snprintf(ps_ok_sensor, sizeof (ps_ok_sensor), "%s_OK_SENSOR", id); 917 retry = 0; 918 do { 919 if (retry) 920 (void) sleep(retry_sleep_ps_status); 921 /* Handle the PDB P/S OK Bit */ 922 status = psvc_get_attr(hdlp, ps_ok_sensor, 923 PSVC_SWITCH_STATE_ATTR, state); 924 if (status != PSVC_SUCCESS) 925 return (status); 926 retry++; 927 } while ((retry < n_retry_ps_status) && 928 (strcmp(previous_state, state))); 929 930 931 /* 932 * If there is a change of state (current state differs from 933 * previous state, then assign the error values. 934 */ 935 if (strcmp(previous_state, state) != 0) { 936 if (strcmp(state, PSVC_SWITCH_OFF) == 0) { 937 strlcpy(state, PSVC_ERROR, sizeof (state)); 938 strlcpy(fault, "DEVICE_FAIL", sizeof (fault)); 939 fault_on = 1; 940 syslog(LOG_ERR, gettext( 941 "Device %s: Failure Detected -- %s " 942 "shutdown!"), id, id); 943 ps_okay = 0; 944 } else { 945 strlcpy(state, PSVC_OK, sizeof (state)); 946 strlcpy(fault, PSVC_NO_FAULT, sizeof (fault)); 947 } 948 949 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state); 950 if (status != PSVC_SUCCESS) 951 return (status); 952 953 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault); 954 if (status != PSVC_SUCCESS) 955 return (status); 956 } 957 958 status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance); 959 if (status != PSVC_SUCCESS) 960 return (status); 961 962 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count, 963 PSVC_DEV_FAULT_SENSOR); 964 if (status != PSVC_SUCCESS) { 965 return (status); 966 } 967 968 /* Handle the power supply fail bits. */ 969 for (i = 0; i < sensor_count; i++) { 970 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 971 &sensor_id, PSVC_DEV_FAULT_SENSOR, i); 972 if (status != PSVC_SUCCESS) 973 return (status); 974 975 retry = 0; 976 do { 977 if (retry) 978 (void) sleep(retry_sleep_ps_status); 979 status = psvc_get_attr(hdlp, sensor_id, 980 PSVC_SWITCH_STATE_ATTR, state); 981 if (status != PSVC_SUCCESS) 982 return (status); 983 retry++; 984 } while ((retry < n_retry_ps_status) && 985 (strcmp(state, PSVC_SWITCH_ON) == 0)); 986 987 if (strcmp(state, PSVC_SWITCH_ON) == 0) { 988 if (ps_prev_id[instance][i] == NULL) 989 ps_prev_id[instance][i] = sensor_id; 990 991 if (ps_prev_failed[instance][i] != 1) 992 ps_prev_failed[instance][i] = 1; 993 fault_on = 1; 994 /* 995 * The first sensor in the list is: 996 * PSx_DEV_FAULT_SENSOR. If this is on, we do not 997 * want to merely report that it's on, but rather 998 * report that there was a fault detected, thus 999 * improving diagnosability. 1000 */ 1001 if (i == 0) { 1002 /* 1003 * Don't notify if the PDB PS OKAY Bit is 1004 * "0" 1005 */ 1006 if (ps_okay) 1007 syslog(LOG_ERR, gettext( 1008 "Device %s: Fault Detected"), 1009 id); 1010 } else { 1011 syslog(LOG_ERR, gettext("Warning %s: %s is ON"), 1012 id, sensor_id); 1013 } 1014 } 1015 } 1016 1017 status = psvc_get_attr(hdlp, ps_logical_state, 1018 PSVC_STATE_ATTR, state); 1019 if (status != PSVC_SUCCESS) 1020 return (status); 1021 1022 status = psvc_get_attr(hdlp, ps_logical_state, 1023 PSVC_PREV_STATE_ATTR, previous_state); 1024 if (status != PSVC_SUCCESS) 1025 return (status); 1026 1027 /* 1028 * If we encountered a fault of any kind (something before 1029 * has set 'fault_on' to '1') then we want to send the reset 1030 * signal to the power supply's PCF8574 and also set 1031 * 'ps_logical_state' to "ERROR" so that the FSP General Fault 1032 * LED will light. 1033 */ 1034 if (fault_on) { 1035 if (ps_okay) { 1036 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, 1037 PSVC_GEN_FAULT); 1038 if (status != PSVC_SUCCESS) 1039 return (status); 1040 } 1041 status = psvc_set_attr(hdlp, ps_logical_state, 1042 PSVC_STATE_ATTR, PSVC_ERROR); 1043 if (status != PSVC_SUCCESS) 1044 return (status); 1045 /* 1046 * "id" is in the form of "PSx", We need to make it 1047 * PSx_RESET. 1048 */ 1049 snprintf(ps_reset, sizeof (ps_reset), "%s_RESET", id); 1050 status = send_pcf8574_reset(hdlp, ps_reset); 1051 return (status); 1052 } 1053 1054 /* 1055 * There was no fault encountered so we want to 1056 * set 'ps_logical_state' to "OK" 1057 */ 1058 if (strcmp(state, PSVC_OK) != 0) { 1059 for (i = 0; i < 3; i++) { 1060 char *sensor = ps_prev_id[instance][i]; 1061 int *prev_failed = &ps_prev_failed[instance][i]; 1062 if (sensor == NULL) 1063 continue; 1064 if (*prev_failed == 0) 1065 continue; 1066 *prev_failed = 0; 1067 if (i == 0) { 1068 /* 1069 * Don't notifiy if we have a power supply 1070 * failure (PDB PS OKAY == 0 1071 */ 1072 if (ps_okay) 1073 syslog(LOG_ERR, gettext( 1074 "Notice %s: Fault Cleared"), 1075 id); 1076 } else { 1077 syslog(LOG_ERR, gettext("Notice %s: %s is OFF"), 1078 id, sensor); 1079 } 1080 } 1081 1082 status = psvc_set_attr(hdlp, ps_logical_state, 1083 PSVC_STATE_ATTR, PSVC_OK); 1084 if (status != PSVC_SUCCESS) 1085 return (status); 1086 syslog(LOG_ERR, gettext("Device %s Okay"), id); 1087 } 1088 1089 return (PSVC_SUCCESS); 1090 } 1091 1092 /* 1093 * This routine takes in a handle pointer and a Power Supply id. It then gets 1094 * the switch state for the PSx_AC_IN_SENSOR. If the switch is OFF the cord is 1095 * unplugged and we return a true (1). If the switch is ON then the cord is 1096 * plugged in and we return a false (0). If the get_attr call fails we return 1097 * PSVC_FAILURE (-1). 1098 */ 1099 static int 1100 ac_unplugged(psvc_opaque_t hdlp, char *id) 1101 { 1102 int32_t status = PSVC_SUCCESS; 1103 char ac_sensor_id[PICL_PROPNAMELEN_MAX]; 1104 char ac_switch_state[PSVC_MAX_STR_LEN]; 1105 1106 snprintf(ac_sensor_id, sizeof (ac_sensor_id), "%s_AC_IN_SENSOR", id); 1107 1108 status = psvc_get_attr(hdlp, ac_sensor_id, PSVC_SWITCH_STATE_ATTR, 1109 ac_switch_state); 1110 if (status == PSVC_FAILURE) { 1111 return (status); 1112 } 1113 1114 if (strcmp(ac_switch_state, PSVC_SWITCH_OFF) == 0) { 1115 return (1); 1116 } else { 1117 return (0); 1118 } 1119 } 1120 1121 /* 1122 * This routine expects a handle pointer, a Power Supply ID, and a PS logical 1123 * state switch ID. It check to see if the power cord has been removed from or 1124 * inserted to the power supply. It then updates the PS state accordingly. 1125 */ 1126 static int 1127 ac_power_check(psvc_opaque_t hdlp, char *id, char *ps_logical_state) 1128 { 1129 int32_t status = PSVC_SUCCESS; 1130 int32_t sensor_count; 1131 char *sensor_id; 1132 char state[PSVC_MAX_STR_LEN]; 1133 int unplugged, i; 1134 1135 status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state); 1136 if (status != PSVC_SUCCESS) 1137 return (status); 1138 1139 /* 1140 * Check for AC Power Cord. ac_unplugged will return true if the PS is 1141 * unplugged, a false is the PS is plugged in, and PSVC_FAILURE if the 1142 * call to get the state fails. 1143 */ 1144 unplugged = ac_unplugged(hdlp, id); 1145 if (status == PSVC_FAILURE) { 1146 return (status); 1147 } 1148 1149 /* 1150 * If power cord is not in, then we set the fault and error 1151 * states to "". 1152 * If power cord is in, then we check the devices. 1153 */ 1154 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count, 1155 PSVC_DEV_FAULT_SENSOR); 1156 if (status != PSVC_SUCCESS) { 1157 return (status); 1158 } 1159 1160 if ((unplugged) && (strcmp(state, "NO AC POWER") != 0)) { 1161 /* set id's state to "NO AC POWER" */ 1162 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, 1163 "NO AC POWER"); 1164 if (status != PSVC_SUCCESS) 1165 return (status); 1166 /* 1167 * Set this state so that the FSP Fault LED lights 1168 * when there is no AC Power to the power supply. 1169 */ 1170 status = psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR, 1171 PSVC_ERROR); 1172 if (status != PSVC_SUCCESS) 1173 return (status); 1174 1175 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, 1176 "NO AC POWER"); 1177 if (status != PSVC_SUCCESS) 1178 return (status); 1179 1180 syslog(LOG_ERR, gettext("Device %s AC UNAVAILABLE"), id); 1181 1182 /* Set fault sensor states to "" */ 1183 for (i = 0; i < sensor_count; ++i) { 1184 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 1185 &sensor_id, PSVC_DEV_FAULT_SENSOR, i); 1186 if (status != PSVC_SUCCESS) 1187 return (status); 1188 1189 status = psvc_set_attr(hdlp, sensor_id, 1190 PSVC_FAULTID_ATTR, ""); 1191 if (status != PSVC_SUCCESS) 1192 return (status); 1193 } 1194 } 1195 1196 /* Power cord is plugged in */ 1197 if ((!unplugged) && (strcmp(state, "NO AC POWER") == 0)) { 1198 /* Default the state to "OK" */ 1199 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, 1200 PSVC_OK); 1201 if (status != PSVC_SUCCESS) 1202 return (status); 1203 /* Default the PS_LOGICAL_STATE to "OK" */ 1204 status = psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR, 1205 PSVC_OK); 1206 if (status != PSVC_SUCCESS) 1207 return (status); 1208 /* Display message */ 1209 syslog(LOG_ERR, gettext("Device %s AC AVAILABLE"), id); 1210 } 1211 1212 return (status); 1213 } 1214 1215 int32_t 1216 psvc_init_ps_presence(psvc_opaque_t hdlp, char *id) 1217 { 1218 int err; 1219 int instance; 1220 boolean_t presence; 1221 1222 err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance); 1223 err |= psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence); 1224 ps_prev_present[instance] = ps_present[instance] = presence; 1225 return (err); 1226 } 1227 1228 int32_t 1229 psvc_ps_monitor_policy_0(psvc_opaque_t hdlp, char *id) 1230 { 1231 int err; 1232 int instance; 1233 static int failed_last_time[2] = {0, 0}; 1234 int retry; 1235 1236 err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance); 1237 if (err != PSVC_SUCCESS) 1238 return (err); 1239 1240 /* copy current presence to previous presence */ 1241 ps_prev_present[instance] = ps_present[instance]; 1242 1243 retry = 0; 1244 do { 1245 if (retry) 1246 (void) sleep(retry_sleep_pshp); 1247 /* Get new presence */ 1248 err = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, 1249 &ps_present[instance]); 1250 if (err != PSVC_SUCCESS) 1251 goto out; 1252 retry++; 1253 } while ((retry < n_retry_pshp) && 1254 (ps_present[instance] != ps_prev_present[instance])); 1255 1256 /* Sustained Hotplug detected */ 1257 if (ps_present[instance] != ps_prev_present[instance]) { 1258 err = handle_ps_hotplug(hdlp, id, ps_present[instance]); 1259 return (err); 1260 } 1261 1262 /* If our power supply is not present, we're done */ 1263 if (!ps_present[instance]) 1264 return (PSVC_SUCCESS); 1265 1266 err = check_i2c_access(hdlp, id); 1267 if (err != PSVC_SUCCESS) { 1268 /* Quickie hotplug */ 1269 if (ps_present[instance] == PSVC_PRESENT && 1270 ps_prev_present[instance] == PSVC_PRESENT) { 1271 syslog(LOG_ERR, "Device %s removed", id); 1272 /* Reset prev_failed information */ 1273 ps_reset_prev_failed(instance); 1274 ps_prev_present[instance] = 0; 1275 handle_ps_hotplug(hdlp, id, ps_present[instance]); 1276 /* We ignore the error on a quickie hotplug */ 1277 return (PSVC_SUCCESS); 1278 } 1279 /* There was an actual i2c access error */ 1280 goto out; 1281 } 1282 1283 err = check_ps_state(hdlp, id); 1284 if (err != PSVC_SUCCESS) 1285 goto out; 1286 1287 failed_last_time[instance] = 0; 1288 return (err); 1289 1290 out: 1291 if (! failed_last_time[instance]) { 1292 /* 1293 * We ignore the error condition the first time thru 1294 * because the PS could have been removed after (or 1295 * during) our call to check_ps_hotplug(). 1296 * 1297 * If the problem is still there the next time, then 1298 * we'll raise a flag. 1299 * 1300 * The instance determines which power supply the policy 1301 * errored on. For instance PS0 might have failed and then 1302 * PS1 might have failed, but we'll display a warning 1303 * even though there might not be anything actually wrong. 1304 * The instance keeps track of which failure occurred so 1305 * we warn on the corresponding occurrence of errors. 1306 */ 1307 failed_last_time[instance] = 1; 1308 return (PSVC_SUCCESS); 1309 } 1310 return (err); 1311 } 1312 1313 static int 1314 light_disk_fault_leds(psvc_opaque_t hdlp, char *id, boolean_t disk_presence) 1315 { 1316 int err; 1317 int bit_nums[MAX_DISKS] = {6, 7}; 1318 uint8_t led_masks[MAX_DISKS] = {0x40, 0x80}; 1319 int instance; 1320 int bit_value; 1321 char state[PSVC_MAX_STR_LEN]; 1322 uint8_t byte; 1323 1324 if (disk_presence != PSVC_PRESENT) 1325 return (PSVC_SUCCESS); 1326 1327 err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance); 1328 if (err != PSVC_SUCCESS) 1329 return (err); 1330 1331 err = psvc_get_attr(hdlp, "DISK_PORT", PSVC_GPIO_VALUE_ATTR, 1332 &byte); 1333 if (err != PSVC_SUCCESS) 1334 return (err); 1335 1336 err = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state); 1337 if (err != PSVC_SUCCESS) 1338 return (err); 1339 if (strcmp(state, PSVC_OK) == 0 || strcmp(state, "") == 0) { /* OK */ 1340 if (byte & led_masks[instance]) { /* Led is OFF */ 1341 return (err); /* Done. */ 1342 } else { /* Led is ON, Turn if OFF */ 1343 bit_value = 1; /* Active Low */ 1344 err = pcf8574_write_bit(hdlp, "DISK_PORT", 1345 bit_nums[instance], bit_value, 1346 DISKBP_MUST_BE_1); 1347 if (err != PSVC_SUCCESS) 1348 return (err); 1349 } 1350 } else { /* Disk is NOT OK */ 1351 if (byte & led_masks[instance]) { /* Led is OFF, Turn it ON */ 1352 bit_value = 0; /* Active Low */ 1353 err = pcf8574_write_bit(hdlp, "DISK_PORT", 1354 bit_nums[instance], bit_value, 1355 DISKBP_MUST_BE_1); 1356 if (err != PSVC_SUCCESS) 1357 return (err); 1358 } else { 1359 return (err); /* Done. */ 1360 } 1361 } 1362 return (err); 1363 } 1364 1365 int 1366 verify_disk_wwn(char *wwn) 1367 { 1368 HBA_PORTATTRIBUTES hbaPortAttrs, discPortAttrs; 1369 HBA_HANDLE handle; 1370 HBA_STATUS status; 1371 HBA_ADAPTERATTRIBUTES hbaAttrs; 1372 HBA_UINT32 numberOfAdapters, hbaCount, hbaPort, discPort; 1373 char adaptername[256]; 1374 char vwwn[WWN_SIZE * 2]; 1375 char OSDeviceName[PATH_MAX + 1]; 1376 int count, linksize; 1377 1378 /* Load common lib */ 1379 status = HBA_LoadLibrary(); 1380 if (status != HBA_STATUS_OK) { 1381 (void) HBA_FreeLibrary(); 1382 return (HBA_STATUS_ERROR); 1383 } 1384 1385 /* 1386 * Since devfs can store multiple instances 1387 * of a target the validity of the WWN of a disk is 1388 * verified with an actual probe of internal disks 1389 */ 1390 1391 /* Cycle through FC-AL Adapters and search for WWN */ 1392 numberOfAdapters = HBA_GetNumberOfAdapters(); 1393 for (hbaCount = 0; hbaCount < numberOfAdapters; hbaCount++) { 1394 if ((status = HBA_GetAdapterName(hbaCount, adaptername)) != 1395 HBA_STATUS_OK) 1396 continue; 1397 1398 handle = HBA_OpenAdapter(adaptername); 1399 if (handle == 0) 1400 continue; 1401 1402 /* Get Adapter Attributes */ 1403 if ((status = HBA_GetAdapterAttributes(handle, 1404 &hbaAttrs)) != HBA_STATUS_OK) { 1405 HBA_CloseAdapter(handle); 1406 continue; 1407 } 1408 1409 /* Get Adapter's Port Attributes */ 1410 for (hbaPort = 0; 1411 hbaPort < hbaAttrs.NumberOfPorts; hbaPort++) { 1412 if ((status = HBA_GetAdapterPortAttributes(handle, 1413 hbaPort, &hbaPortAttrs)) != HBA_STATUS_OK) 1414 continue; 1415 1416 /* 1417 * Verify whether this is onboard controller. 1418 * HBAAPI provides path of symbol link to 1419 * to the qlc node therefore readlink() is 1420 * needed to obtain hard link 1421 */ 1422 linksize = readlink(hbaPortAttrs.OSDeviceName, 1423 OSDeviceName, PATH_MAX); 1424 1425 /* 1426 * If readlink does not return size of onboard 1427 * controller than don't bother checking device 1428 */ 1429 if ((linksize + 1) != sizeof (ONBOARD_CONTR)) 1430 continue; 1431 1432 OSDeviceName[linksize] = '\0'; 1433 if (strcmp(OSDeviceName, ONBOARD_CONTR) != 0) 1434 continue; 1435 1436 /* Get Discovered Port Attributes */ 1437 for (discPort = 0; 1438 discPort < hbaPortAttrs.NumberofDiscoveredPorts; 1439 discPort++) { 1440 status = HBA_GetDiscoveredPortAttributes( 1441 handle, hbaPort, discPort, 1442 &discPortAttrs); 1443 if (status != HBA_STATUS_OK) 1444 continue; 1445 1446 /* Get target info */ 1447 for (count = 0; count < WWN_SIZE; count++) 1448 (void) sprintf(&vwwn[count * 2], 1449 "%2.2x", 1450 discPortAttrs.NodeWWN.wwn[count]); 1451 1452 if (strcmp(wwn, vwwn) == 0) { 1453 HBA_CloseAdapter(handle); 1454 (void) HBA_FreeLibrary(); 1455 return (HBA_STATUS_OK); 1456 } 1457 1458 } 1459 } 1460 HBA_CloseAdapter(handle); 1461 } 1462 (void) HBA_FreeLibrary(); 1463 return (HBA_STATUS_ERROR_ILLEGAL_WWN); 1464 } 1465 1466 static int 1467 light_disk_ok2remove_leds(psvc_opaque_t hdlp, boolean_t *disk_present) 1468 { 1469 di_node_t node; 1470 di_node_t root_node; 1471 di_minor_t min_node; 1472 int *prop; 1473 int n; 1474 int target; 1475 int rv; 1476 int disk_online = 0; 1477 static int prev_online[MAX_DISKS] = {-1, -1}; 1478 int bit_nums[MAX_DISKS] = {4, 5}; 1479 int bit_val; 1480 int count; 1481 char *dev_path; 1482 char wwn[WWN_SIZE * 2]; 1483 uchar_t *prop_wwn; 1484 1485 root_node = di_init("/", DINFOCPYALL); 1486 if (root_node == DI_NODE_NIL) 1487 return (PSVC_FAILURE); 1488 1489 for (node = di_drv_first_node(DISK_DRV, root_node); 1490 node != DI_NODE_NIL; 1491 node = di_drv_next_node(node)) { 1492 n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "target", &prop); 1493 if (n == -1) 1494 continue; 1495 target = *prop; 1496 if (target < 0 || target > 1) 1497 continue; 1498 1499 if (! disk_present[target]) 1500 continue; 1501 1502 dev_path = di_devfs_path(node); 1503 if (memcmp(dev_path, QLC_NODE, (sizeof (QLC_NODE) - 1)) != 0) { 1504 /* 1505 * This isn't our FC-AL controller, so this 1506 * must be an external disk on Loop B. Skip it. 1507 */ 1508 di_devfs_path_free(dev_path); 1509 continue; 1510 } 1511 di_devfs_path_free(dev_path); 1512 1513 /* 1514 * Verify if disk is valid by checking WWN 1515 * because devfs retains stale data. 1516 */ 1517 n = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, 1518 "node-wwn", &prop_wwn); 1519 if (n == -1) 1520 continue; 1521 1522 for (count = 0; count < WWN_SIZE; count++) 1523 (void) sprintf(&wwn[count * 2], "%2.2x", 1524 prop_wwn[count]); 1525 1526 n = verify_disk_wwn(wwn); 1527 if (n == HBA_STATUS_ERROR_ILLEGAL_WWN) 1528 continue; 1529 1530 min_node = di_minor_next(node, DI_MINOR_NIL); 1531 disk_online = (min_node != DI_MINOR_NIL); 1532 if ((disk_online == 0) && (prev_online[target] == 1)) { 1533 /* Light Led */ 1534 bit_val = 0; 1535 rv = pcf8574_write_bit(hdlp, "DISK_PORT", 1536 bit_nums[target], bit_val, DISKBP_MUST_BE_1); 1537 if (rv != PSVC_SUCCESS) 1538 goto done; 1539 } else if ((prev_online[target] == 0) && (disk_online == 1)) { 1540 /* Unlight Led */ 1541 bit_val = 1; 1542 rv = pcf8574_write_bit(hdlp, "DISK_PORT", 1543 bit_nums[target], bit_val, DISKBP_MUST_BE_1); 1544 if (rv != PSVC_SUCCESS) 1545 goto done; 1546 } 1547 if (disk_online != prev_online[target]) 1548 prev_online[target] = disk_online; 1549 } 1550 done: 1551 di_fini(root_node); 1552 return (rv); 1553 } 1554 1555 static int 1556 check_disk_fault(psvc_opaque_t hdlp, char *id, boolean_t disk_presence) 1557 { 1558 int32_t status = PSVC_SUCCESS; 1559 int32_t fault_on = 0; 1560 char *sensor_id; 1561 char disk_state[PSVC_MAX_STR_LEN]; 1562 char state[PSVC_MAX_STR_LEN]; 1563 char fault[PSVC_MAX_STR_LEN]; 1564 boolean_t change_of_state = 0; 1565 1566 if (disk_presence != PSVC_PRESENT) 1567 return (PSVC_SUCCESS); 1568 1569 status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, disk_state); 1570 if (status != PSVC_SUCCESS) 1571 return (status); 1572 1573 status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, 1574 &sensor_id, PSVC_DEV_FAULT_SENSOR, 0); 1575 if (status != PSVC_SUCCESS) 1576 return (status); 1577 1578 status = psvc_get_attr(hdlp, sensor_id, PSVC_SWITCH_STATE_ATTR, state); 1579 if (status != PSVC_SUCCESS) 1580 return (status); 1581 1582 /* Fault detected */ 1583 if (strcmp(state, PSVC_SWITCH_ON) == 0) { 1584 strlcpy(state, PSVC_ERROR, sizeof (state)); 1585 strlcpy(fault, PSVC_GEN_FAULT, sizeof (fault)); 1586 fault_on = 1; 1587 } else { /* No fault detected */ 1588 if (strcmp(disk_state, PSVC_OK) != 0) 1589 change_of_state = 1; 1590 strlcpy(state, PSVC_OK, sizeof (state)); 1591 strlcpy(fault, PSVC_NO_FAULT, sizeof (fault)); 1592 } 1593 1594 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state); 1595 if (status != PSVC_SUCCESS) 1596 return (status); 1597 1598 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault); 1599 if (status != PSVC_SUCCESS) 1600 return (status); 1601 1602 if (fault_on) { 1603 syslog(LOG_ERR, gettext("Fault detected: %s"), id); 1604 1605 } else { 1606 if (change_of_state) 1607 syslog(LOG_ERR, gettext("Notice: %s okay"), id); 1608 } 1609 return (PSVC_SUCCESS); 1610 } 1611 1612 static int 1613 check_disk_hotplug(psvc_opaque_t hdlp, char *id, boolean_t *disk_presence, 1614 int disk_instance) 1615 { 1616 boolean_t presence; 1617 boolean_t previous_presence; 1618 int32_t status = PSVC_SUCCESS; 1619 char label[PSVC_MAX_STR_LEN]; 1620 uint8_t disk_leds[MAX_DISKS][2] = {{4, 6}, {5, 7}}; 1621 int retry; 1622 1623 status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, 1624 &previous_presence); 1625 if (status != PSVC_SUCCESS) 1626 return (status); 1627 1628 retry = 0; 1629 do { 1630 if (retry) 1631 (void) sleep(retry_sleep_diskhp); 1632 status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, 1633 &presence); 1634 if (status != PSVC_SUCCESS) 1635 return (status); 1636 retry++; 1637 } while ((retry < n_retry_diskhp) && 1638 (presence != previous_presence)); 1639 1640 *disk_presence = presence; 1641 1642 if (presence != previous_presence) { 1643 char parent_path[PICL_PROPNAMELEN_MAX]; 1644 picl_nodehdl_t child_node; 1645 1646 status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label); 1647 if (status != PSVC_SUCCESS) 1648 return (status); 1649 1650 /* return parent path and node for an object */ 1651 psvcplugin_lookup(id, parent_path, &child_node); 1652 1653 if (presence == PSVC_PRESENT) { 1654 picl_nodehdl_t parent_node; 1655 char state[PSVC_MAX_STR_LEN]; 1656 char fault[PSVC_MAX_STR_LEN]; 1657 1658 syslog(LOG_ERR, gettext("Device %s inserted"), label); 1659 strlcpy(state, PSVC_OK, sizeof (state)); 1660 status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, 1661 state); 1662 if (status != PSVC_SUCCESS) 1663 return (status); 1664 1665 strlcpy(fault, PSVC_NO_FAULT, sizeof (fault)); 1666 status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, 1667 fault); 1668 if (status != PSVC_SUCCESS) { 1669 return (status); 1670 } 1671 1672 status = ptree_get_node_by_path(parent_path, 1673 &parent_node); 1674 if (status != PICL_SUCCESS) 1675 return (PSVC_FAILURE); 1676 status = ptree_add_node(parent_node, child_node); 1677 if (status != PICL_SUCCESS) 1678 return (PSVC_FAILURE); 1679 } else { 1680 /* 1681 * Disk Removed so we need to turn off these LEDs: 1682 * DISKx_FLT_LED 1683 * DISKx_REMOVE_LED 1684 */ 1685 int i; 1686 int bit_val = 1; /* Active Low */ 1687 for (i = 0; i < 2; i++) { 1688 status = pcf8574_write_bit(hdlp, "DISK_PORT", 1689 disk_leds[disk_instance][i], bit_val, 1690 DISKBP_MUST_BE_1); 1691 if (status != PSVC_SUCCESS) 1692 syslog(LOG_ERR, "Failed in turning off" 1693 " %d's LEDs", id); 1694 } 1695 syslog(LOG_ERR, gettext("Device %s removed"), label); 1696 ptree_delete_node(child_node); 1697 } 1698 } 1699 1700 status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence); 1701 if (status != PSVC_SUCCESS) 1702 return (status); 1703 1704 return (status); 1705 } 1706 1707 int32_t 1708 psvc_disk_monitor_policy_0(psvc_opaque_t hdlp, char *id) 1709 { 1710 int rv, err, i; 1711 char *disks[MAX_DISKS] = {"DISK0", "DISK1"}; 1712 int saved_errno = 0; 1713 boolean_t disk_present[MAX_DISKS] = {0, 0}; 1714 1715 for (i = 0; i < MAX_DISKS; i++) { 1716 err = check_disk_hotplug(hdlp, disks[i], &disk_present[i], i); 1717 if (err) saved_errno = errno; 1718 rv = err; 1719 1720 err = check_disk_fault(hdlp, disks[i], disk_present[i]); 1721 if (err) saved_errno = errno; 1722 rv |= err; 1723 1724 err |= light_disk_fault_leds(hdlp, disks[i], disk_present[i]); 1725 if (err) saved_errno = errno; 1726 rv |= err; 1727 } 1728 1729 err = light_disk_ok2remove_leds(hdlp, disk_present); 1730 if (err) saved_errno = errno; 1731 rv |= err; 1732 1733 errno = saved_errno; 1734 return (rv); 1735 } 1736 1737 /* 1738 * Read in temperature thresholds from FRU Prom and update the 1739 * default values. 1740 */ 1741 1742 #define START_OFFSET 0x1800 /* Last 2K of SEEPROM */ 1743 #define NUM_SEG_OFFSET 0x1805 /* Number of segments */ 1744 #define SEG_TABLE_OFFSET 0x1806 /* Segment description tables */ 1745 1746 static int32_t 1747 read_sc_segment(psvc_opaque_t hdlp, char *id, char *fru_id, int offset) 1748 { 1749 static int thresh_names[] = { 1750 PSVC_HW_LO_SHUT_ATTR, 1751 PSVC_LO_SHUT_ATTR, 1752 PSVC_LO_WARN_ATTR, 1753 PSVC_NOT_USED, /* LOW MODE */ 1754 PSVC_OPTIMAL_TEMP_ATTR, 1755 PSVC_HI_WARN_ATTR, 1756 PSVC_HI_SHUT_ATTR, 1757 PSVC_HW_HI_SHUT_ATTR 1758 }; 1759 int8_t amb_temp_array[8]; 1760 int i; 1761 fru_info_t fru_info; 1762 int err; 1763 1764 fru_info.buf_start = offset + 8; 1765 fru_info.buf = amb_temp_array; 1766 fru_info.read_size = 8; 1767 1768 err = psvc_get_attr(hdlp, fru_id, PSVC_FRU_INFO_ATTR, &fru_info); 1769 if (err != PSVC_SUCCESS) 1770 return (err); 1771 1772 for (i = 0; i < 8; i++) { 1773 int32_t temp = amb_temp_array[i]; 1774 if (thresh_names[i] == PSVC_NOT_USED) 1775 continue; 1776 err = psvc_set_attr(hdlp, id, thresh_names[i], &temp); 1777 if (err != PSVC_SUCCESS) 1778 return (err); 1779 } 1780 return (PSVC_SUCCESS); 1781 } 1782 1783 int32_t 1784 update_disk_bp_temp_thresholds(psvc_opaque_t hdlp, char *id) 1785 { 1786 1787 char *fru; 1788 fru_info_t fru_info; 1789 int16_t seg_offset; 1790 int8_t byte; 1791 int8_t seg_count; 1792 char seg_name[2]; 1793 int current_offset, i, err; 1794 1795 err = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &fru, PSVC_FRU, 0); 1796 if (err != PSVC_SUCCESS) 1797 return (err); 1798 1799 /* Sanity Check */ 1800 fru_info.buf_start = START_OFFSET; 1801 fru_info.buf = &byte; 1802 fru_info.read_size = 1; 1803 1804 err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info); 1805 if (err != PSVC_SUCCESS) 1806 return (err); 1807 if (*fru_info.buf != 8) { 1808 syslog(LOG_ERR, "Notice: FRU Prom %s not programmed", fru); 1809 } 1810 /* Should do CRC Check on fru */ 1811 1812 /* Get Segment Count */ 1813 fru_info.buf_start = NUM_SEG_OFFSET; 1814 fru_info.buf = &seg_count; 1815 fru_info.read_size = 1; 1816 1817 err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info); 1818 if (err != PSVC_SUCCESS) 1819 return (err); 1820 1821 current_offset = SEG_TABLE_OFFSET; 1822 for (i = 0; i < seg_count; i++) { 1823 fru_info.buf_start = current_offset; 1824 fru_info.buf = seg_name; 1825 fru_info.read_size = 2; 1826 err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info); 1827 if (err != PSVC_SUCCESS) 1828 return (err); 1829 1830 if (memcmp(seg_name, "SC", 2) == 0) { 1831 current_offset += 6; /* Skip over description */ 1832 fru_info.buf_start = current_offset; 1833 fru_info.buf = (char *)&seg_offset; 1834 fru_info.read_size = 2; 1835 psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, 1836 &fru_info); 1837 return (read_sc_segment(hdlp, id, fru, seg_offset)); 1838 } 1839 current_offset += 10; 1840 } 1841 1842 return (PSVC_SUCCESS); 1843 } 1844