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