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
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.
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]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * Cherrystone platform specific environment monitoring policies
41 #include <sys/types.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>
50 #include <sys/i2c/clients/i2c_client.h>
53 #include <sys/systeminfo.h>
55 #include <psvc_objects.h>
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"
63 #define QLC_NODE "/pci@9,600000/SUNW,qlc@2"
65 #define DISK_DRV "ssd"
68 #define ONBOARD_CONTR "../../devices/pci@9,600000/SUNW,qlc@2/fp@0,0:fc"
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))))
74 #define PDB_MUST_BE_1 0xBF
75 #define PSU_MUST_BE_1 0x7F
76 #define DISKBP_MUST_BE_1 0x0F
80 #define PSVC_MAX_STR_LEN 32
82 #define PS_MAX_FAULT_SENSORS 3
85 * Keep track of the power supply's fail status for reporting if/when
89 * 1 Doesn't matter -- only need 0 to be PSx_FAULT_SENSOR
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}};
97 * Keep track of the power supply's previous presence
98 * because PSVC doesn't do that for us.
100 static boolean_t ps_prev_present
[2];
101 static boolean_t ps_present
[2];
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 *);
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.
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;
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",
149 #pragma init(i2cparams_load)
152 i2cparams_debug(i2c_noise_param_t
*pi2cparams
, char *platform
,
156 i2c_noise_param_t
*p
;
158 if (!usingDefaults
) {
159 (void) snprintf(s
, sizeof (s
),
160 "# Values from /usr/platform/%s/lib/i2cparam.conf\n",
162 syslog(LOG_WARNING
, "%s", s
);
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",
169 (void) fputs(s
, stdout
);
171 while (p
->pvar
!= NULL
) {
172 (void) snprintf(s
, sizeof (s
), "%s %d\n", p
->texttag
,
175 syslog(LOG_WARNING
, "%s", s
);
176 (void) fputs(s
, stdout
);
185 char filename
[PATH_MAX
];
190 i2c_noise_param_t
*p
;
192 if (sysinfo(SI_PLATFORM
, platform
, sizeof (platform
)) == -1) {
193 syslog(LOG_ERR
, "sysinfo error %s\n", strerror(errno
));
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 */
203 /* try to find a string match and get the value */
204 if (sscanf(s
, "%127s %d", var
, &val
) != 2)
207 val
= 1; /* clamp min value */
209 while (p
->pvar
!= NULL
) {
210 if (strncmp(p
->texttag
, var
, sizeof (var
)) ==
220 /* output the values of the parameters */
221 i2cparams_debug(&(i2cparams
[0]), platform
, ((fp
== NULL
)? 1 : 0));
225 * Create an I2C device node.
228 create_i2c_node(char *nd_name
, char *nd_compat
, int nd_nexi
, int *nd_reg
)
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
;
237 (void) snprintf(buf
, sizeof (buf
), SEG5_ADDR_DEV_FMT
, nd_nexi
);
238 bus_hdl
= devctl_bus_acquire(buf
, 0);
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
);
247 /* create the device node */
248 if (devctl_bus_dev_create(bus_hdl
, ddef_hdl
, 0, &dev_hdl
))
251 if (devctl_get_pathname(dev_hdl
, dev_path
, MAXPATHLEN
) == NULL
)
255 syslog(LOG_ERR
, "PSVC: create_i2c_node: Device node created: (%s)",
260 devctl_release(dev_hdl
);
261 devctl_ddef_free(ddef_hdl
);
262 devctl_release(bus_hdl
);
267 * Delete an I2C device node given the device path.
270 delete_i2c_node(char *nd
)
273 devctl_hdl_t dev_hdl
;
275 dev_hdl
= devctl_device_acquire(nd
, 0);
276 if (dev_hdl
== NULL
) {
280 rv
= devctl_device_remove(dev_hdl
);
281 if (rv
!= DDI_SUCCESS
)
285 syslog(LOG_ERR
, "Device node deleted: (%s)", nd
);
287 devctl_release(dev_hdl
);
291 /* PCF8574 Reset Function */
293 send_pcf8574_reset(psvc_opaque_t hdlp
, char *reset_dev
)
296 uint8_t reset_bits
[2] = {0x7F, 0xFF};
298 for (i
= 0; i
< 2; i
++) {
299 err
= psvc_set_attr(hdlp
, reset_dev
, PSVC_GPIO_VALUE_ATTR
,
301 if (err
!= PSVC_SUCCESS
) {
304 gettext("Reset to %s with 0x%x failed"),
305 reset_dev
, reset_bits
[i
]);
310 /* Need to give u-code a chance to update */
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
)
319 int rv
= PSVC_FAILURE
;
322 rv
= psvc_get_attr(hdlp
, id
, PSVC_GPIO_VALUE_ATTR
, &byte
);
323 if (rv
!= PSVC_SUCCESS
)
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
);
333 * To enable the i2c bus, we must toggle bit 6 on the PDB's
334 * PCF8574 (0x4C) high->low->high
337 pdb_enable_i2c(psvc_opaque_t hdlp
)
339 int rv
= PSVC_SUCCESS
, i
;
340 int bit_vals
[3] = {1, 0, 1};
343 for (i
= 0; i
< 3; i
++) {
344 rv
= pcf8574_write_bit(hdlp
, "PDB_PORT", bit_num
, bit_vals
[i
],
346 if (rv
!= PSVC_SUCCESS
) {
353 syslog(LOG_ERR
, gettext("PDB I2C Bus Enabling Failed"));
359 psvc_init_disk_bp_policy_0(psvc_opaque_t hdlp
, char *id
)
361 uint8_t reset
= 0xFF;
362 return (psvc_set_attr(hdlp
, id
, PSVC_GPIO_VALUE_ATTR
,
367 pcf8574_init_policy_0(psvc_opaque_t hdlp
, char *id
)
369 return (send_pcf8574_reset(hdlp
, id
));
373 check_fan(psvc_opaque_t hdlp
, char *tray_id
, char *fan_id
, boolean_t
*fault_on
)
378 boolean_t have_fault
= 0;
380 char state
[PSVC_MAX_STR_LEN
];
381 char prev_state
[PSVC_MAX_STR_LEN
];
382 char fault_state
[PSVC_MAX_STR_LEN
];
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
)
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
)
399 (void) sleep(retry_sleep_fan
);
400 /* Get the fan speed */
401 status
= psvc_get_attr(hdlp
, tach_id
, PSVC_SENSOR_VALUE_ATTR
,
403 if (status
!= PSVC_SUCCESS
)
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
));
411 } else { /* Fault gone? */
412 strlcpy(fault_state
, PSVC_NO_FAULT
,
413 sizeof (fault_state
));
414 strlcpy(state
, PSVC_OK
, sizeof (state
));
418 } while ((retry
< n_retry_fan
) && (speed
<= low_thresh
));
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
)
424 status
= psvc_set_attr(hdlp
, fan_id
, PSVC_STATE_ATTR
, state
);
425 if (status
!= PSVC_SUCCESS
)
428 /* Get state and previous state */
429 status
= psvc_get_attr(hdlp
, fan_id
, PSVC_STATE_ATTR
, state
);
430 if (status
!= PSVC_SUCCESS
)
432 status
= psvc_get_attr(hdlp
, fan_id
, PSVC_PREV_STATE_ATTR
, prev_state
);
433 if (status
!= PSVC_SUCCESS
)
436 /* Display notices */
437 if (strcmp(state
, PSVC_OK
) != 0) {
438 syslog(LOG_ERR
, gettext("WARNING: %s (%s) failure detected"),
441 if (strcmp(state
, prev_state
) != 0) {
442 syslog(LOG_ERR
, gettext("NOTICE: Device %s (%s) OK"),
447 *fault_on
|= have_fault
;
448 return (PSVC_SUCCESS
);
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.
457 psvc_fan_fault_check_policy_0(psvc_opaque_t hdlp
, char *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;
469 /* Get the number of fans associated with this fan tray. */
470 err
= psvc_get_attr(hdlp
, id
, PSVC_ASSOC_MATCHES_ATTR
, &fan_count
,
472 if (err
!= PSVC_SUCCESS
)
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
)
481 err
= check_fan(hdlp
, id
, fan_id
, &fault_on
);
482 if (err
!= PSVC_SUCCESS
)
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
)
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
)
499 err
= psvc_get_attr(hdlp
, id
, PSVC_STATE_ATTR
, state
);
500 if (err
!= PSVC_SUCCESS
)
502 err
= psvc_get_attr(hdlp
, id
, PSVC_PREV_STATE_ATTR
, prev_state
);
503 if (err
!= PSVC_SUCCESS
)
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)
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
)
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
)
522 err
= psvc_set_attr(hdlp
, led_id
,
523 PSVC_LED_STATE_ATTR
, led_state
);
524 if (err
!= PSVC_SUCCESS
)
526 err
= psvc_get_attr(hdlp
, led_id
,
527 PSVC_LED_STATE_ATTR
, led_state
);
528 if (err
!= PSVC_SUCCESS
)
536 check_cpu_temp_fault(psvc_opaque_t hdlp
, char *cpu
, int32_t cpu_count
)
539 int32_t sensor_count
;
540 int32_t status
= PSVC_SUCCESS
;
542 char fault
[PSVC_MAX_STR_LEN
];
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
)
556 (void) sleep(retry_sleep_temp_shutdown
);
557 status
= psvc_get_attr(hdlp
, sensorid
,
558 PSVC_FAULTID_ATTR
, fault
);
559 if (status
== PSVC_FAILURE
)
562 } while (((strcmp(fault
, PSVC_TEMP_LO_SHUT
) == 0) ||
563 (strcmp(fault
, PSVC_TEMP_HI_SHUT
) == 0)) &&
564 (retry
< n_retry_temp_shutdown
));
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\"");
576 psvc_shutdown_policy_0(psvc_opaque_t hdlp
, char *id
)
582 int32_t status
= PSVC_SUCCESS
;
584 psvc_get_attr(hdlp
, id
, PSVC_ASSOC_MATCHES_ATTR
, &cpu_count
,
586 for (i
= 0; i
< cpu_count
; ++i
) {
588 status
= psvc_get_attr(hdlp
, id
, PSVC_ASSOC_ID_ATTR
, &cpuid
,
590 if (status
== PSVC_FAILURE
)
593 status
= psvc_get_attr(hdlp
, cpuid
,
594 PSVC_PRESENCE_ATTR
, &present
);
595 if (status
== PSVC_FAILURE
&& present
== PSVC_PRESENT
)
597 if (present
== PSVC_PRESENT
) {
598 status
= check_cpu_temp_fault(hdlp
, cpuid
, cpu_count
);
599 if (status
== PSVC_FAILURE
&& errno
!= ENODEV
)
604 return (PSVC_SUCCESS
);
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
613 psvc_fsp_device_fault_check_policy_0(psvc_opaque_t hdlp
, char *id
)
617 int32_t device_count
= 0;
618 char device_state
[PSVC_MAX_STR_LEN
];
620 int32_t failed_count
= 0;
621 static int32_t led_on
= 0;
624 status
= psvc_get_attr(hdlp
, id
, PSVC_ASSOC_MATCHES_ATTR
,
625 &device_count
, PSVC_DEV_FAULT_SENSOR
);
626 if (status
!= PSVC_SUCCESS
)
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
)
638 (void) sleep(retry_sleep_fsp_fault
);
639 status
= psvc_get_attr(hdlp
, device_id
, PSVC_STATE_ATTR
,
641 if (status
!= PSVC_SUCCESS
)
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) {
651 } while ((retry
< n_retry_fsp_fault
) && (failed_count
));
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
,
660 if (failed_count
> 0 && ! led_on
) {
662 gettext("%s has turned ON"), id
);
663 status
= psvc_set_attr(hdlp
, id
, PSVC_LED_STATE_ATTR
,
668 return (PSVC_SUCCESS
);
671 /* Power Supply Policy Helper and Worker Functions */
673 ps_reset_prev_failed(int index
)
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;
684 check_i2c_access(psvc_opaque_t hdlp
, char *id
)
687 char state
[PSVC_MAX_STR_LEN
];
688 char ps_fault_sensor
[PSVC_MAX_STR_LEN
];
690 snprintf(ps_fault_sensor
, sizeof (ps_fault_sensor
),
691 "%s_FAULT_SENSOR", id
);
693 rv
= psvc_get_attr(hdlp
, ps_fault_sensor
, PSVC_SWITCH_STATE_ATTR
,
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
706 handle_ps_hotplug_children_presence(psvc_opaque_t hdlp
, char *id
)
708 char *child_add_on
[4] = {"_RESET", "_LOGICAL_STATE", "_AC_IN_SENSOR",
711 char addon_id
[PICL_PROPNAMELEN_MAX
];
713 int32_t status
= PSVC_SUCCESS
;
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
,
721 status
= psvc_get_attr(hdlp
, addon_id
, PSVC_PRESENCE_ATTR
,
723 if (status
!= PSVC_SUCCESS
)
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
)
733 status
= psvc_get_attr(hdlp
, sensor_id
, PSVC_PRESENCE_ATTR
,
735 if (status
!= PSVC_SUCCESS
)
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
)
745 status
= psvc_get_attr(hdlp
, sensor_id
, PSVC_PRESENCE_ATTR
,
747 if (status
!= PSVC_SUCCESS
)
755 handle_ps_hotplug(psvc_opaque_t hdlp
, char *id
, boolean_t present
)
757 int32_t status
= PSVC_SUCCESS
;
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
];
769 /* Convert name to node and parent path */
770 psvcplugin_lookup(id
, parent_path
, &child_node
);
773 * Get the power supply's instance.
774 * Used to index the xxx_addr arrays
776 status
= psvc_get_attr(hdlp
, id
, PSVC_INSTANCE_ATTR
, &instance
);
777 if (status
!= PSVC_SUCCESS
)
780 if (present
== PSVC_PRESENT
&& !ps_prev_present
[instance
]) {
781 /* Service Power Supply Insertion */
782 syslog(LOG_ERR
, gettext("Device %s inserted"), id
);
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
);
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.
796 status
= handle_ps_hotplug_children_presence(hdlp
, id
);
799 * Device Tree Maintenance
800 * Add the devinfo tree node entry for the pcf8574 and seeprom
801 * and attach their drivers.
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
]);
808 /* Service Power Supply Removal */
809 syslog(LOG_ERR
, gettext("Device %s removed"), id
);
811 /* Reset the power supply's failure information */
812 ps_reset_prev_failed(instance
);
814 /* PICL Tree Maintenance */
815 if (ptree_delete_node(child_node
) != PICL_SUCCESS
)
816 syslog(LOG_ERR
, "ptree_delete_node failed!");
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).
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
);
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
);
834 snprintf(ps_logical_state
, sizeof (ps_logical_state
),
835 "%s_LOGICAL_STATE", id
);
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
);
841 strlcpy(info
, PSVC_NO_FAULT
, sizeof (info
));
842 status
|= psvc_set_attr(hdlp
, id
, PSVC_FAULTID_ATTR
, info
);
844 /* Enable the i2c connection to the power supply */
845 status
|= pdb_enable_i2c(hdlp
);
850 * check_ps_state() Checks for:
853 * Power Supply Fan Failure
854 * Power Supply Temperature Failure
855 * Power Supply Generic Fault
856 * Power Supply AC Cord Plugged In
858 * - If we see a "bad" state we will report an error.
861 * Fault bit shows fault.
862 * Temperature fault shows fault.
863 * Fan fault shows fault.
864 * AC power NOT okay to supply.
866 * - If we see that the AC Cord is not plugged in, then the the other
867 * failure bits are invalid.
869 * - Send pcf8574_reset at the end of the policy if we see
873 check_ps_state(psvc_opaque_t hdlp
, char *id
)
875 int32_t sensor_count
;
876 int32_t status
= PSVC_SUCCESS
;
878 int32_t fault_on
= 0;
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 */
890 /* Logical state id */
891 snprintf(ps_logical_state
, sizeof (ps_logical_state
),
892 "%s_LOGICAL_STATE", id
);
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.
898 status
= ac_power_check(hdlp
, id
, ps_logical_state
);
899 if (status
== PSVC_FAILURE
)
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.
907 status
= psvc_get_attr(hdlp
, id
, PSVC_STATE_ATTR
, state
);
908 if (status
!= PSVC_SUCCESS
)
911 if (strcmp(state
, "NO AC POWER") == 0)
914 status
= psvc_get_attr(hdlp
, id
, PSVC_PREV_STATE_ATTR
, previous_state
);
915 if (status
!= PSVC_SUCCESS
)
918 snprintf(ps_ok_sensor
, sizeof (ps_ok_sensor
), "%s_OK_SENSOR", id
);
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
)
929 } while ((retry
< n_retry_ps_status
) &&
930 (strcmp(previous_state
, state
)));
934 * If there is a change of state (current state differs from
935 * previous state, then assign the error values.
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
));
942 syslog(LOG_ERR
, gettext(
943 "Device %s: Failure Detected -- %s "
944 "shutdown!"), id
, id
);
947 strlcpy(state
, PSVC_OK
, sizeof (state
));
948 strlcpy(fault
, PSVC_NO_FAULT
, sizeof (fault
));
951 status
= psvc_set_attr(hdlp
, id
, PSVC_STATE_ATTR
, state
);
952 if (status
!= PSVC_SUCCESS
)
955 status
= psvc_set_attr(hdlp
, id
, PSVC_FAULTID_ATTR
, fault
);
956 if (status
!= PSVC_SUCCESS
)
960 status
= psvc_get_attr(hdlp
, id
, PSVC_INSTANCE_ATTR
, &instance
);
961 if (status
!= PSVC_SUCCESS
)
964 status
= psvc_get_attr(hdlp
, id
, PSVC_ASSOC_MATCHES_ATTR
, &sensor_count
,
965 PSVC_DEV_FAULT_SENSOR
);
966 if (status
!= PSVC_SUCCESS
) {
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
)
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
)
986 } while ((retry
< n_retry_ps_status
) &&
987 (strcmp(state
, PSVC_SWITCH_ON
) == 0));
989 if (strcmp(state
, PSVC_SWITCH_ON
) == 0) {
990 if (ps_prev_id
[instance
][i
] == NULL
)
991 ps_prev_id
[instance
][i
] = sensor_id
;
993 if (ps_prev_failed
[instance
][i
] != 1)
994 ps_prev_failed
[instance
][i
] = 1;
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.
1005 * Don't notify if the PDB PS OKAY Bit is
1009 syslog(LOG_ERR
, gettext(
1010 "Device %s: Fault Detected"),
1013 syslog(LOG_ERR
, gettext("Warning %s: %s is ON"),
1019 status
= psvc_get_attr(hdlp
, ps_logical_state
,
1020 PSVC_STATE_ATTR
, state
);
1021 if (status
!= PSVC_SUCCESS
)
1024 status
= psvc_get_attr(hdlp
, ps_logical_state
,
1025 PSVC_PREV_STATE_ATTR
, previous_state
);
1026 if (status
!= PSVC_SUCCESS
)
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
1038 status
= psvc_set_attr(hdlp
, id
, PSVC_FAULTID_ATTR
,
1040 if (status
!= PSVC_SUCCESS
)
1043 status
= psvc_set_attr(hdlp
, ps_logical_state
,
1044 PSVC_STATE_ATTR
, PSVC_ERROR
);
1045 if (status
!= PSVC_SUCCESS
)
1048 * "id" is in the form of "PSx", We need to make it
1051 snprintf(ps_reset
, sizeof (ps_reset
), "%s_RESET", id
);
1052 status
= send_pcf8574_reset(hdlp
, ps_reset
);
1057 * There was no fault encountered so we want to
1058 * set 'ps_logical_state' to "OK"
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
];
1066 if (*prev_failed
== 0)
1071 * Don't notifiy if we have a power supply
1072 * failure (PDB PS OKAY == 0
1075 syslog(LOG_ERR
, gettext(
1076 "Notice %s: Fault Cleared"),
1079 syslog(LOG_ERR
, gettext("Notice %s: %s is OFF"),
1084 status
= psvc_set_attr(hdlp
, ps_logical_state
,
1085 PSVC_STATE_ATTR
, PSVC_OK
);
1086 if (status
!= PSVC_SUCCESS
)
1088 syslog(LOG_ERR
, gettext("Device %s Okay"), id
);
1091 return (PSVC_SUCCESS
);
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).
1102 ac_unplugged(psvc_opaque_t hdlp
, char *id
)
1104 int32_t status
= PSVC_SUCCESS
;
1105 char ac_sensor_id
[PICL_PROPNAMELEN_MAX
];
1106 char ac_switch_state
[PSVC_MAX_STR_LEN
];
1108 snprintf(ac_sensor_id
, sizeof (ac_sensor_id
), "%s_AC_IN_SENSOR", id
);
1110 status
= psvc_get_attr(hdlp
, ac_sensor_id
, PSVC_SWITCH_STATE_ATTR
,
1112 if (status
== PSVC_FAILURE
) {
1116 if (strcmp(ac_switch_state
, PSVC_SWITCH_OFF
) == 0) {
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.
1129 ac_power_check(psvc_opaque_t hdlp
, char *id
, char *ps_logical_state
)
1131 int32_t status
= PSVC_SUCCESS
;
1132 int32_t sensor_count
;
1134 char state
[PSVC_MAX_STR_LEN
];
1137 status
= psvc_get_attr(hdlp
, id
, PSVC_STATE_ATTR
, state
);
1138 if (status
!= PSVC_SUCCESS
)
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.
1146 unplugged
= ac_unplugged(hdlp
, id
);
1147 if (status
== PSVC_FAILURE
) {
1152 * If power cord is not in, then we set the fault and error
1154 * If power cord is in, then we check the devices.
1156 status
= psvc_get_attr(hdlp
, id
, PSVC_ASSOC_MATCHES_ATTR
, &sensor_count
,
1157 PSVC_DEV_FAULT_SENSOR
);
1158 if (status
!= PSVC_SUCCESS
) {
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
,
1166 if (status
!= PSVC_SUCCESS
)
1169 * Set this state so that the FSP Fault LED lights
1170 * when there is no AC Power to the power supply.
1172 status
= psvc_set_attr(hdlp
, ps_logical_state
, PSVC_STATE_ATTR
,
1174 if (status
!= PSVC_SUCCESS
)
1177 status
= psvc_set_attr(hdlp
, id
, PSVC_FAULTID_ATTR
,
1179 if (status
!= PSVC_SUCCESS
)
1182 syslog(LOG_ERR
, gettext("Device %s AC UNAVAILABLE"), id
);
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
)
1191 status
= psvc_set_attr(hdlp
, sensor_id
,
1192 PSVC_FAULTID_ATTR
, "");
1193 if (status
!= PSVC_SUCCESS
)
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
,
1203 if (status
!= PSVC_SUCCESS
)
1205 /* Default the PS_LOGICAL_STATE to "OK" */
1206 status
= psvc_set_attr(hdlp
, ps_logical_state
, PSVC_STATE_ATTR
,
1208 if (status
!= PSVC_SUCCESS
)
1210 /* Display message */
1211 syslog(LOG_ERR
, gettext("Device %s AC AVAILABLE"), id
);
1218 psvc_init_ps_presence(psvc_opaque_t hdlp
, char *id
)
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
;
1231 psvc_ps_monitor_policy_0(psvc_opaque_t hdlp
, char *id
)
1235 static int failed_last_time
[2] = {0, 0};
1238 err
= psvc_get_attr(hdlp
, id
, PSVC_INSTANCE_ATTR
, &instance
);
1239 if (err
!= PSVC_SUCCESS
)
1242 /* copy current presence to previous presence */
1243 ps_prev_present
[instance
] = ps_present
[instance
];
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
)
1255 } while ((retry
< n_retry_pshp
) &&
1256 (ps_present
[instance
] != ps_prev_present
[instance
]));
1258 /* Sustained Hotplug detected */
1259 if (ps_present
[instance
] != ps_prev_present
[instance
]) {
1260 err
= handle_ps_hotplug(hdlp
, id
, ps_present
[instance
]);
1264 /* If our power supply is not present, we're done */
1265 if (!ps_present
[instance
])
1266 return (PSVC_SUCCESS
);
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
);
1281 /* There was an actual i2c access error */
1285 err
= check_ps_state(hdlp
, id
);
1286 if (err
!= PSVC_SUCCESS
)
1289 failed_last_time
[instance
] = 0;
1293 if (! failed_last_time
[instance
]) {
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().
1299 * If the problem is still there the next time, then
1300 * we'll raise a flag.
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.
1309 failed_last_time
[instance
] = 1;
1310 return (PSVC_SUCCESS
);
1316 light_disk_fault_leds(psvc_opaque_t hdlp
, char *id
, boolean_t disk_presence
)
1319 int bit_nums
[MAX_DISKS
] = {6, 7};
1320 uint8_t led_masks
[MAX_DISKS
] = {0x40, 0x80};
1323 char state
[PSVC_MAX_STR_LEN
];
1326 if (disk_presence
!= PSVC_PRESENT
)
1327 return (PSVC_SUCCESS
);
1329 err
= psvc_get_attr(hdlp
, id
, PSVC_INSTANCE_ATTR
, &instance
);
1330 if (err
!= PSVC_SUCCESS
)
1333 err
= psvc_get_attr(hdlp
, "DISK_PORT", PSVC_GPIO_VALUE_ATTR
,
1335 if (err
!= PSVC_SUCCESS
)
1338 err
= psvc_get_attr(hdlp
, id
, PSVC_STATE_ATTR
, state
);
1339 if (err
!= PSVC_SUCCESS
)
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
,
1349 if (err
!= PSVC_SUCCESS
)
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
,
1358 if (err
!= PSVC_SUCCESS
)
1361 return (err
); /* Done. */
1368 verify_disk_wwn(char *wwn
)
1370 HBA_PORTATTRIBUTES hbaPortAttrs
, discPortAttrs
;
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
;
1380 /* Load common lib */
1381 status
= HBA_LoadLibrary();
1382 if (status
!= HBA_STATUS_OK
) {
1383 (void) HBA_FreeLibrary();
1384 return (HBA_STATUS_ERROR
);
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
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
)) !=
1400 handle
= HBA_OpenAdapter(adaptername
);
1404 /* Get Adapter Attributes */
1405 if ((status
= HBA_GetAdapterAttributes(handle
,
1406 &hbaAttrs
)) != HBA_STATUS_OK
) {
1407 HBA_CloseAdapter(handle
);
1411 /* Get Adapter's Port Attributes */
1413 hbaPort
< hbaAttrs
.NumberOfPorts
; hbaPort
++) {
1414 if ((status
= HBA_GetAdapterPortAttributes(handle
,
1415 hbaPort
, &hbaPortAttrs
)) != HBA_STATUS_OK
)
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
1424 linksize
= readlink(hbaPortAttrs
.OSDeviceName
,
1425 OSDeviceName
, PATH_MAX
);
1428 * If readlink does not return size of onboard
1429 * controller than don't bother checking device
1431 if ((linksize
+ 1) != sizeof (ONBOARD_CONTR
))
1434 OSDeviceName
[linksize
] = '\0';
1435 if (strcmp(OSDeviceName
, ONBOARD_CONTR
) != 0)
1438 /* Get Discovered Port Attributes */
1440 discPort
< hbaPortAttrs
.NumberofDiscoveredPorts
;
1442 status
= HBA_GetDiscoveredPortAttributes(
1443 handle
, hbaPort
, discPort
,
1445 if (status
!= HBA_STATUS_OK
)
1448 /* Get target info */
1449 for (count
= 0; count
< WWN_SIZE
; count
++)
1450 (void) sprintf(&vwwn
[count
* 2],
1452 discPortAttrs
.NodeWWN
.wwn
[count
]);
1454 if (strcmp(wwn
, vwwn
) == 0) {
1455 HBA_CloseAdapter(handle
);
1456 (void) HBA_FreeLibrary();
1457 return (HBA_STATUS_OK
);
1462 HBA_CloseAdapter(handle
);
1464 (void) HBA_FreeLibrary();
1465 return (HBA_STATUS_ERROR_ILLEGAL_WWN
);
1469 light_disk_ok2remove_leds(psvc_opaque_t hdlp
, boolean_t
*disk_present
)
1472 di_node_t root_node
;
1473 di_minor_t min_node
;
1478 int disk_online
= 0;
1479 static int prev_online
[MAX_DISKS
] = {-1, -1};
1480 int bit_nums
[MAX_DISKS
] = {4, 5};
1484 char wwn
[WWN_SIZE
* 2];
1487 root_node
= di_init("/", DINFOCPYALL
);
1488 if (root_node
== DI_NODE_NIL
)
1489 return (PSVC_FAILURE
);
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
);
1498 if (target
< 0 || target
> 1)
1501 if (! disk_present
[target
])
1504 dev_path
= di_devfs_path(node
);
1505 if (memcmp(dev_path
, QLC_NODE
, (sizeof (QLC_NODE
) - 1)) != 0) {
1507 * This isn't our FC-AL controller, so this
1508 * must be an external disk on Loop B. Skip it.
1510 di_devfs_path_free(dev_path
);
1513 di_devfs_path_free(dev_path
);
1516 * Verify if disk is valid by checking WWN
1517 * because devfs retains stale data.
1519 n
= di_prop_lookup_bytes(DDI_DEV_T_ANY
, node
,
1520 "node-wwn", &prop_wwn
);
1524 for (count
= 0; count
< WWN_SIZE
; count
++)
1525 (void) sprintf(&wwn
[count
* 2], "%2.2x",
1528 n
= verify_disk_wwn(wwn
);
1529 if (n
== HBA_STATUS_ERROR_ILLEGAL_WWN
)
1532 min_node
= di_minor_next(node
, DI_MINOR_NIL
);
1533 disk_online
= (min_node
!= DI_MINOR_NIL
);
1534 if ((disk_online
== 0) && (prev_online
[target
] == 1)) {
1537 rv
= pcf8574_write_bit(hdlp
, "DISK_PORT",
1538 bit_nums
[target
], bit_val
, DISKBP_MUST_BE_1
);
1539 if (rv
!= PSVC_SUCCESS
)
1541 } else if ((prev_online
[target
] == 0) && (disk_online
== 1)) {
1544 rv
= pcf8574_write_bit(hdlp
, "DISK_PORT",
1545 bit_nums
[target
], bit_val
, DISKBP_MUST_BE_1
);
1546 if (rv
!= PSVC_SUCCESS
)
1549 if (disk_online
!= prev_online
[target
])
1550 prev_online
[target
] = disk_online
;
1558 check_disk_fault(psvc_opaque_t hdlp
, char *id
, boolean_t disk_presence
)
1560 int32_t status
= PSVC_SUCCESS
;
1561 int32_t fault_on
= 0;
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;
1568 if (disk_presence
!= PSVC_PRESENT
)
1569 return (PSVC_SUCCESS
);
1571 status
= psvc_get_attr(hdlp
, id
, PSVC_STATE_ATTR
, disk_state
);
1572 if (status
!= PSVC_SUCCESS
)
1575 status
= psvc_get_attr(hdlp
, id
, PSVC_ASSOC_ID_ATTR
,
1576 &sensor_id
, PSVC_DEV_FAULT_SENSOR
, 0);
1577 if (status
!= PSVC_SUCCESS
)
1580 status
= psvc_get_attr(hdlp
, sensor_id
, PSVC_SWITCH_STATE_ATTR
, state
);
1581 if (status
!= PSVC_SUCCESS
)
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
));
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
));
1596 status
= psvc_set_attr(hdlp
, id
, PSVC_STATE_ATTR
, state
);
1597 if (status
!= PSVC_SUCCESS
)
1600 status
= psvc_set_attr(hdlp
, id
, PSVC_FAULTID_ATTR
, fault
);
1601 if (status
!= PSVC_SUCCESS
)
1605 syslog(LOG_ERR
, gettext("Fault detected: %s"), id
);
1608 if (change_of_state
)
1609 syslog(LOG_ERR
, gettext("Notice: %s okay"), id
);
1611 return (PSVC_SUCCESS
);
1615 check_disk_hotplug(psvc_opaque_t hdlp
, char *id
, boolean_t
*disk_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}};
1625 status
= psvc_get_attr(hdlp
, id
, PSVC_PREV_PRESENCE_ATTR
,
1626 &previous_presence
);
1627 if (status
!= PSVC_SUCCESS
)
1633 (void) sleep(retry_sleep_diskhp
);
1634 status
= psvc_get_attr(hdlp
, id
, PSVC_PRESENCE_ATTR
,
1636 if (status
!= PSVC_SUCCESS
)
1639 } while ((retry
< n_retry_diskhp
) &&
1640 (presence
!= previous_presence
));
1642 *disk_presence
= presence
;
1644 if (presence
!= previous_presence
) {
1645 char parent_path
[PICL_PROPNAMELEN_MAX
];
1646 picl_nodehdl_t child_node
;
1648 status
= psvc_get_attr(hdlp
, id
, PSVC_LABEL_ATTR
, label
);
1649 if (status
!= PSVC_SUCCESS
)
1652 /* return parent path and node for an object */
1653 psvcplugin_lookup(id
, parent_path
, &child_node
);
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
];
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
,
1664 if (status
!= PSVC_SUCCESS
)
1667 strlcpy(fault
, PSVC_NO_FAULT
, sizeof (fault
));
1668 status
= psvc_set_attr(hdlp
, id
, PSVC_FAULTID_ATTR
,
1670 if (status
!= PSVC_SUCCESS
) {
1674 status
= ptree_get_node_by_path(parent_path
,
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
);
1683 * Disk Removed so we need to turn off these LEDs:
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
,
1693 if (status
!= PSVC_SUCCESS
)
1694 syslog(LOG_ERR
, "Failed in turning off"
1697 syslog(LOG_ERR
, gettext("Device %s removed"), label
);
1698 ptree_delete_node(child_node
);
1702 status
= psvc_set_attr(hdlp
, id
, PSVC_PREV_PRESENCE_ATTR
, &presence
);
1703 if (status
!= PSVC_SUCCESS
)
1710 psvc_disk_monitor_policy_0(psvc_opaque_t hdlp
, char *id
)
1713 char *disks
[MAX_DISKS
] = {"DISK0", "DISK1"};
1714 int saved_errno
= 0;
1715 boolean_t disk_present
[MAX_DISKS
] = {0, 0};
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
;
1722 err
= check_disk_fault(hdlp
, disks
[i
], disk_present
[i
]);
1723 if (err
) saved_errno
= errno
;
1726 err
|= light_disk_fault_leds(hdlp
, disks
[i
], disk_present
[i
]);
1727 if (err
) saved_errno
= errno
;
1731 err
= light_disk_ok2remove_leds(hdlp
, disk_present
);
1732 if (err
) saved_errno
= errno
;
1735 errno
= saved_errno
;
1740 * Read in temperature thresholds from FRU Prom and update the
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 */
1749 read_sc_segment(psvc_opaque_t hdlp
, char *id
, char *fru_id
, int offset
)
1751 static int thresh_names
[] = {
1752 PSVC_HW_LO_SHUT_ATTR
,
1755 PSVC_NOT_USED
, /* LOW MODE */
1756 PSVC_OPTIMAL_TEMP_ATTR
,
1759 PSVC_HW_HI_SHUT_ATTR
1761 int8_t amb_temp_array
[8];
1763 fru_info_t fru_info
;
1766 fru_info
.buf_start
= offset
+ 8;
1767 fru_info
.buf
= amb_temp_array
;
1768 fru_info
.read_size
= 8;
1770 err
= psvc_get_attr(hdlp
, fru_id
, PSVC_FRU_INFO_ATTR
, &fru_info
);
1771 if (err
!= PSVC_SUCCESS
)
1774 for (i
= 0; i
< 8; i
++) {
1775 int32_t temp
= amb_temp_array
[i
];
1776 if (thresh_names
[i
] == PSVC_NOT_USED
)
1778 err
= psvc_set_attr(hdlp
, id
, thresh_names
[i
], &temp
);
1779 if (err
!= PSVC_SUCCESS
)
1782 return (PSVC_SUCCESS
);
1786 update_disk_bp_temp_thresholds(psvc_opaque_t hdlp
, char *id
)
1790 fru_info_t fru_info
;
1795 int current_offset
, i
, err
;
1797 err
= psvc_get_attr(hdlp
, id
, PSVC_ASSOC_ID_ATTR
, &fru
, PSVC_FRU
, 0);
1798 if (err
!= PSVC_SUCCESS
)
1802 fru_info
.buf_start
= START_OFFSET
;
1803 fru_info
.buf
= &byte
;
1804 fru_info
.read_size
= 1;
1806 err
= psvc_get_attr(hdlp
, fru
, PSVC_FRU_INFO_ATTR
, &fru_info
);
1807 if (err
!= PSVC_SUCCESS
)
1809 if (*fru_info
.buf
!= 8) {
1810 syslog(LOG_ERR
, "Notice: FRU Prom %s not programmed", fru
);
1812 /* Should do CRC Check on fru */
1814 /* Get Segment Count */
1815 fru_info
.buf_start
= NUM_SEG_OFFSET
;
1816 fru_info
.buf
= &seg_count
;
1817 fru_info
.read_size
= 1;
1819 err
= psvc_get_attr(hdlp
, fru
, PSVC_FRU_INFO_ATTR
, &fru_info
);
1820 if (err
!= PSVC_SUCCESS
)
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
)
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
,
1839 return (read_sc_segment(hdlp
, id
, fru
, seg_offset
));
1841 current_offset
+= 10;
1844 return (PSVC_SUCCESS
);