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