10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*5510Sanbui * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * Cherrystone platform specific environment monitoring policies
310Sstevel@tonic-gate */
320Sstevel@tonic-gate
330Sstevel@tonic-gate #include <syslog.h>
340Sstevel@tonic-gate #include <unistd.h>
350Sstevel@tonic-gate #include <stdio.h>
360Sstevel@tonic-gate #include <libintl.h>
370Sstevel@tonic-gate #include <string.h>
380Sstevel@tonic-gate #include <stdlib.h>
390Sstevel@tonic-gate #include <errno.h>
400Sstevel@tonic-gate #include <fcntl.h>
410Sstevel@tonic-gate #include <sys/types.h>
420Sstevel@tonic-gate #include <sys/time.h>
430Sstevel@tonic-gate #include <sys/time_impl.h>
440Sstevel@tonic-gate #include <sys/signal.h>
450Sstevel@tonic-gate #include <sys/devctl.h>
460Sstevel@tonic-gate #include <libdevinfo.h>
470Sstevel@tonic-gate #include <libdevice.h>
480Sstevel@tonic-gate #include <picl.h>
490Sstevel@tonic-gate #include <picltree.h>
500Sstevel@tonic-gate #include <sys/i2c/clients/i2c_client.h>
510Sstevel@tonic-gate #include <hbaapi.h>
520Sstevel@tonic-gate #include <limits.h>
53958Sjfrank #include <sys/systeminfo.h>
540Sstevel@tonic-gate
550Sstevel@tonic-gate #include <psvc_objects.h>
560Sstevel@tonic-gate
570Sstevel@tonic-gate /* Device paths for power supply hotplug handling */
580Sstevel@tonic-gate #define SEG5_ADDR 0x30
590Sstevel@tonic-gate #define EBUS_DEV_NAME "/devices/pci@9,700000/ebus@1/"
60376Swesolows #define SEG5_DEV_NAME EBUS_DEV_NAME "i2c@1,30/"
61376Swesolows #define SEG5_ADDR_DEV_FMT EBUS_DEV_NAME "i2c@1,%x:devctl"
620Sstevel@tonic-gate
630Sstevel@tonic-gate #define QLC_NODE "/pci@9,600000/SUNW,qlc@2"
640Sstevel@tonic-gate
650Sstevel@tonic-gate #define DISK_DRV "ssd"
660Sstevel@tonic-gate #define MAX_DISKS 2
670Sstevel@tonic-gate #define WWN_SIZE 8
680Sstevel@tonic-gate #define ONBOARD_CONTR "../../devices/pci@9,600000/SUNW,qlc@2/fp@0,0:fc"
690Sstevel@tonic-gate
700Sstevel@tonic-gate /* Bit masks so we don't "wedge" the inputs */
710Sstevel@tonic-gate #define PCF8574_BIT_WRITE_VALUE(byte, bit, value)\
720Sstevel@tonic-gate ((value << bit) | (byte & (~(0x01 << bit))))
730Sstevel@tonic-gate
740Sstevel@tonic-gate #define PDB_MUST_BE_1 0xBF
750Sstevel@tonic-gate #define PSU_MUST_BE_1 0x7F
760Sstevel@tonic-gate #define DISKBP_MUST_BE_1 0x0F
770Sstevel@tonic-gate
780Sstevel@tonic-gate /*LINTLIBRARY*/
790Sstevel@tonic-gate
800Sstevel@tonic-gate #define PSVC_MAX_STR_LEN 32
810Sstevel@tonic-gate
820Sstevel@tonic-gate #define PS_MAX_FAULT_SENSORS 3
830Sstevel@tonic-gate
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate * Keep track of the power supply's fail status for reporting if/when
860Sstevel@tonic-gate * they go good.
870Sstevel@tonic-gate * ID's:
880Sstevel@tonic-gate * O PSx_FAULT_SENSOR
890Sstevel@tonic-gate * 1 Doesn't matter -- only need 0 to be PSx_FAULT_SENSOR
900Sstevel@tonic-gate * 2 Doesn't matter
910Sstevel@tonic-gate */
920Sstevel@tonic-gate static char *ps_prev_id[2][3] =
930Sstevel@tonic-gate {{NULL, NULL, NULL}, {NULL, NULL, NULL}};
940Sstevel@tonic-gate static int ps_prev_failed[2][3] = {{0, 0, 0}, {0, 0, 0}};
950Sstevel@tonic-gate
960Sstevel@tonic-gate /*
970Sstevel@tonic-gate * Keep track of the power supply's previous presence
980Sstevel@tonic-gate * because PSVC doesn't do that for us.
990Sstevel@tonic-gate */
1000Sstevel@tonic-gate static boolean_t ps_prev_present[2];
1010Sstevel@tonic-gate static boolean_t ps_present[2];
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate /* Local Routines for the environmental policies */
1040Sstevel@tonic-gate static int ac_unplugged(psvc_opaque_t, char *);
1050Sstevel@tonic-gate static int ac_power_check(psvc_opaque_t, char *, char *);
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate /*
108958Sjfrank * The I2C bus is noisy, and the state may be incorrectly reported as
109958Sjfrank * having changed. When the state changes, we attempt to confirm by
110958Sjfrank * retrying. If any retries indicate that the state has not changed, we
111958Sjfrank * assume the state change(s) were incorrect and the state has not changed.
112958Sjfrank * The following variables are used to store the tuneable values read in
113958Sjfrank * from the optional i2cparam.conf file for this shared object library.
114958Sjfrank */
115958Sjfrank static int n_retry_fan = PSVC_NUM_OF_RETRIES;
116958Sjfrank static int retry_sleep_fan = 1;
117958Sjfrank static int n_retry_ps_status = PSVC_NUM_OF_RETRIES;
118958Sjfrank static int retry_sleep_ps_status = 1;
119958Sjfrank static int n_retry_pshp = PSVC_NUM_OF_RETRIES;
120958Sjfrank static int retry_sleep_pshp = 1;
121958Sjfrank static int n_retry_diskhp = PSVC_NUM_OF_RETRIES;
122958Sjfrank static int retry_sleep_diskhp = 1;
123958Sjfrank static int n_retry_temp_shutdown = PSVC_NUM_OF_RETRIES;
124958Sjfrank static int retry_sleep_temp_shutdown = 1;
125958Sjfrank static int n_retry_fsp_fault = PSVC_NUM_OF_RETRIES;
126958Sjfrank static int retry_sleep_fsp_fault = 1;
127958Sjfrank
128958Sjfrank typedef struct {
129958Sjfrank int *pvar;
130958Sjfrank char *texttag;
131958Sjfrank } i2c_noise_param_t;
132958Sjfrank
133958Sjfrank static i2c_noise_param_t i2cparams[] = {
134958Sjfrank &n_retry_fan, "n_retry_fan",
135958Sjfrank &retry_sleep_fan, "retry_sleep_fan",
136958Sjfrank &n_retry_ps_status, "n_retry_ps_status",
137958Sjfrank &retry_sleep_ps_status, "retry_sleep_ps_status",
138958Sjfrank &n_retry_pshp, "n_retry_pshp",
139958Sjfrank &retry_sleep_pshp, "retry_sleep_pshp",
140958Sjfrank &n_retry_diskhp, "n_retry_diskhp",
141958Sjfrank &retry_sleep_diskhp, "retry_sleep_diskhp",
142958Sjfrank &n_retry_temp_shutdown, "n_retry_temp_shutdown",
143958Sjfrank &retry_sleep_temp_shutdown, "retry_sleep_temp_shutdown",
144958Sjfrank &n_retry_fsp_fault, "n_retry_fsp_fault",
145958Sjfrank &retry_sleep_fsp_fault, "retry_sleep_fsp_fault",
146958Sjfrank NULL, NULL
147958Sjfrank };
148958Sjfrank
149958Sjfrank #pragma init(i2cparams_load)
150958Sjfrank
151958Sjfrank static void
i2cparams_debug(i2c_noise_param_t * pi2cparams,char * platform,int usingDefaults)152958Sjfrank i2cparams_debug(i2c_noise_param_t *pi2cparams, char *platform,
153958Sjfrank int usingDefaults)
154958Sjfrank {
155958Sjfrank char s[128];
156958Sjfrank i2c_noise_param_t *p;
157958Sjfrank
158958Sjfrank if (!usingDefaults) {
159958Sjfrank (void) snprintf(s, sizeof (s),
160958Sjfrank "# Values from /usr/platform/%s/lib/i2cparam.conf\n",
161958Sjfrank platform);
162958Sjfrank syslog(LOG_WARNING, "%s", s);
163958Sjfrank } else {
164958Sjfrank /* no file - we're using the defaults */
165958Sjfrank (void) snprintf(s, sizeof (s),
166958Sjfrank "# No /usr/platform/%s/lib/i2cparam.conf file, using defaults\n",
167958Sjfrank platform);
168958Sjfrank }
169958Sjfrank (void) fputs(s, stdout);
170958Sjfrank p = pi2cparams;
171958Sjfrank while (p->pvar != NULL) {
172958Sjfrank (void) snprintf(s, sizeof (s), "%s %d\n", p->texttag,
173958Sjfrank *(p->pvar));
174958Sjfrank if (!usingDefaults)
175958Sjfrank syslog(LOG_WARNING, "%s", s);
176958Sjfrank (void) fputs(s, stdout);
177958Sjfrank p++;
178958Sjfrank }
179958Sjfrank }
180958Sjfrank
181958Sjfrank static void
i2cparams_load(void)182958Sjfrank i2cparams_load(void)
183958Sjfrank {
184958Sjfrank FILE *fp;
185958Sjfrank char filename[PATH_MAX];
186958Sjfrank char platform[64];
187958Sjfrank char s[128];
188958Sjfrank char var[128];
189958Sjfrank int val;
190958Sjfrank i2c_noise_param_t *p;
191958Sjfrank
192958Sjfrank if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
193958Sjfrank syslog(LOG_ERR, "sysinfo error %s\n", strerror(errno));
194958Sjfrank return;
195958Sjfrank }
196958Sjfrank (void) snprintf(filename, sizeof (filename),
197958Sjfrank "/usr/platform/%s/lib/i2cparam.conf", platform);
198958Sjfrank /* read thru the i2cparam.conf file and set variables */
199958Sjfrank if ((fp = fopen(filename, "r")) != NULL) {
200958Sjfrank while (fgets(s, sizeof (s), fp) != NULL) {
201958Sjfrank if (s[0] == '#') /* skip comment lines */
202958Sjfrank continue;
203958Sjfrank /* try to find a string match and get the value */
204958Sjfrank if (sscanf(s, "%127s %d", var, &val) != 2)
205958Sjfrank continue;
206958Sjfrank if (val < 1)
207958Sjfrank val = 1; /* clamp min value */
208958Sjfrank p = &(i2cparams[0]);
209958Sjfrank while (p->pvar != NULL) {
210958Sjfrank if (strncmp(p->texttag, var, sizeof (var)) ==
211958Sjfrank 0) {
212958Sjfrank *(p->pvar) = val;
213958Sjfrank break;
214958Sjfrank }
215958Sjfrank p++;
216958Sjfrank }
217958Sjfrank }
218958Sjfrank (void) fclose(fp);
219958Sjfrank }
220958Sjfrank /* output the values of the parameters */
221958Sjfrank i2cparams_debug(&(i2cparams[0]), platform, ((fp == NULL)? 1 : 0));
222958Sjfrank }
223958Sjfrank
224958Sjfrank /*
2250Sstevel@tonic-gate * Create an I2C device node.
2260Sstevel@tonic-gate */
2270Sstevel@tonic-gate static int
create_i2c_node(char * nd_name,char * nd_compat,int nd_nexi,int * nd_reg)2280Sstevel@tonic-gate create_i2c_node(char *nd_name, char *nd_compat, int nd_nexi, int *nd_reg)
2290Sstevel@tonic-gate {
2300Sstevel@tonic-gate devctl_ddef_t ddef_hdl = NULL;
2310Sstevel@tonic-gate devctl_hdl_t bus_hdl = NULL;
2320Sstevel@tonic-gate devctl_hdl_t dev_hdl = NULL;
2330Sstevel@tonic-gate char buf[MAXPATHLEN];
2340Sstevel@tonic-gate char dev_path[MAXPATHLEN];
2350Sstevel@tonic-gate int rv = PSVC_FAILURE;
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), SEG5_ADDR_DEV_FMT, nd_nexi);
2380Sstevel@tonic-gate bus_hdl = devctl_bus_acquire(buf, 0);
2390Sstevel@tonic-gate if (bus_hdl == NULL)
2400Sstevel@tonic-gate goto bad;
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate /* device definition properties */
2430Sstevel@tonic-gate ddef_hdl = devctl_ddef_alloc(nd_name, 0);
2440Sstevel@tonic-gate (void) devctl_ddef_string(ddef_hdl, "compatible", nd_compat);
2450Sstevel@tonic-gate (void) devctl_ddef_int_array(ddef_hdl, "reg", 2, nd_reg);
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate /* create the device node */
2480Sstevel@tonic-gate if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl))
2490Sstevel@tonic-gate goto bad;
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate if (devctl_get_pathname(dev_hdl, dev_path, MAXPATHLEN) == NULL)
2520Sstevel@tonic-gate goto bad;
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate #ifdef DEBUG
2550Sstevel@tonic-gate syslog(LOG_ERR, "PSVC: create_i2c_node: Device node created: (%s)",
2560Sstevel@tonic-gate dev_path);
2570Sstevel@tonic-gate #endif
2580Sstevel@tonic-gate rv = PSVC_SUCCESS;
2590Sstevel@tonic-gate bad:
2600Sstevel@tonic-gate if (dev_hdl) devctl_release(dev_hdl);
2610Sstevel@tonic-gate if (ddef_hdl) devctl_ddef_free(ddef_hdl);
2620Sstevel@tonic-gate if (bus_hdl) devctl_release(bus_hdl);
2630Sstevel@tonic-gate return (rv);
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate /*
2670Sstevel@tonic-gate * Delete an I2C device node given the device path.
2680Sstevel@tonic-gate */
2690Sstevel@tonic-gate static void
delete_i2c_node(char * nd)2700Sstevel@tonic-gate delete_i2c_node(char *nd)
2710Sstevel@tonic-gate {
2720Sstevel@tonic-gate int rv;
2730Sstevel@tonic-gate devctl_hdl_t dev_hdl;
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate dev_hdl = devctl_device_acquire(nd, 0);
2760Sstevel@tonic-gate if (dev_hdl == NULL) {
2770Sstevel@tonic-gate return;
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate rv = devctl_device_remove(dev_hdl);
2810Sstevel@tonic-gate if (rv != DDI_SUCCESS)
2820Sstevel@tonic-gate perror(nd);
2830Sstevel@tonic-gate #ifdef DEBUG
2840Sstevel@tonic-gate else
2850Sstevel@tonic-gate syslog(LOG_ERR, "Device node deleted: (%s)", nd);
2860Sstevel@tonic-gate #endif
2870Sstevel@tonic-gate devctl_release(dev_hdl);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate /* PCF8574 Reset Function */
2920Sstevel@tonic-gate static int
send_pcf8574_reset(psvc_opaque_t hdlp,char * reset_dev)2930Sstevel@tonic-gate send_pcf8574_reset(psvc_opaque_t hdlp, char *reset_dev)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate int err;
2960Sstevel@tonic-gate uint8_t reset_bits[2] = {0x7F, 0xFF};
2970Sstevel@tonic-gate int i;
2980Sstevel@tonic-gate for (i = 0; i < 2; i++) {
2990Sstevel@tonic-gate err = psvc_set_attr(hdlp, reset_dev, PSVC_GPIO_VALUE_ATTR,
3000Sstevel@tonic-gate &reset_bits[i]);
3010Sstevel@tonic-gate if (err != PSVC_SUCCESS) {
3020Sstevel@tonic-gate #ifdef DEBUG
3030Sstevel@tonic-gate syslog(LOG_ERR,
3040Sstevel@tonic-gate gettext("Reset to %s with 0x%x failed"),
3050Sstevel@tonic-gate reset_dev, reset_bits[i]);
3060Sstevel@tonic-gate #endif
3070Sstevel@tonic-gate return (err);
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate /* Need to give u-code a chance to update */
3110Sstevel@tonic-gate sleep(3);
3120Sstevel@tonic-gate return (err);
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate static int
pcf8574_write_bit(psvc_opaque_t hdlp,char * id,uint8_t bit_num,uint8_t bit_val,uint8_t write_must_be_1)3160Sstevel@tonic-gate pcf8574_write_bit(psvc_opaque_t hdlp, char *id, uint8_t bit_num,
3170Sstevel@tonic-gate uint8_t bit_val, uint8_t write_must_be_1)
3180Sstevel@tonic-gate {
3190Sstevel@tonic-gate int rv = PSVC_FAILURE;
3200Sstevel@tonic-gate uint8_t byte;
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate rv = psvc_get_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR, &byte);
3230Sstevel@tonic-gate if (rv != PSVC_SUCCESS)
3240Sstevel@tonic-gate return (rv);
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate byte = PCF8574_BIT_WRITE_VALUE(byte, bit_num, bit_val);
3270Sstevel@tonic-gate byte |= write_must_be_1;
3280Sstevel@tonic-gate rv = psvc_set_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR, &byte);
3290Sstevel@tonic-gate return (rv);
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate /*
3330Sstevel@tonic-gate * To enable the i2c bus, we must toggle bit 6 on the PDB's
3340Sstevel@tonic-gate * PCF8574 (0x4C) high->low->high
3350Sstevel@tonic-gate */
3360Sstevel@tonic-gate static int
pdb_enable_i2c(psvc_opaque_t hdlp)3370Sstevel@tonic-gate pdb_enable_i2c(psvc_opaque_t hdlp)
3380Sstevel@tonic-gate {
3390Sstevel@tonic-gate int rv = PSVC_SUCCESS, i;
3400Sstevel@tonic-gate int bit_vals[3] = {1, 0, 1};
3410Sstevel@tonic-gate int bit_num = 6;
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate for (i = 0; i < 3; i++) {
3440Sstevel@tonic-gate rv = pcf8574_write_bit(hdlp, "PDB_PORT", bit_num, bit_vals[i],
3450Sstevel@tonic-gate PDB_MUST_BE_1);
3460Sstevel@tonic-gate if (rv != PSVC_SUCCESS) {
3470Sstevel@tonic-gate goto bad;
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate return (rv);
3510Sstevel@tonic-gate bad:
3520Sstevel@tonic-gate #ifdef DEBUG
3530Sstevel@tonic-gate syslog(LOG_ERR, gettext("PDB I2C Bus Enabling Failed"));
3540Sstevel@tonic-gate #endif
3550Sstevel@tonic-gate return (rv);
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate int32_t
psvc_init_disk_bp_policy_0(psvc_opaque_t hdlp,char * id)3590Sstevel@tonic-gate psvc_init_disk_bp_policy_0(psvc_opaque_t hdlp, char *id)
3600Sstevel@tonic-gate {
3610Sstevel@tonic-gate uint8_t reset = 0xFF;
3620Sstevel@tonic-gate return (psvc_set_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR,
3630Sstevel@tonic-gate &reset));
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate int32_t
pcf8574_init_policy_0(psvc_opaque_t hdlp,char * id)3670Sstevel@tonic-gate pcf8574_init_policy_0(psvc_opaque_t hdlp, char *id)
3680Sstevel@tonic-gate {
3690Sstevel@tonic-gate return (send_pcf8574_reset(hdlp, id));
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate static int32_t
check_fan(psvc_opaque_t hdlp,char * tray_id,char * fan_id,boolean_t * fault_on)3730Sstevel@tonic-gate check_fan(psvc_opaque_t hdlp, char *tray_id, char *fan_id, boolean_t *fault_on)
3740Sstevel@tonic-gate {
3750Sstevel@tonic-gate int status;
3760Sstevel@tonic-gate int speed;
3770Sstevel@tonic-gate int low_thresh;
3780Sstevel@tonic-gate boolean_t have_fault = 0;
3790Sstevel@tonic-gate char *tach_id;
3800Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
3810Sstevel@tonic-gate char prev_state[PSVC_MAX_STR_LEN];
3820Sstevel@tonic-gate char fault_state[PSVC_MAX_STR_LEN];
383958Sjfrank int retry;
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate /* Get this fan object's corresponding fan tach */
3860Sstevel@tonic-gate status = psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_ID_ATTR,
3870Sstevel@tonic-gate &tach_id, PSVC_FAN_SPEED_TACHOMETER, 0);
3880Sstevel@tonic-gate if (status != PSVC_SUCCESS)
3890Sstevel@tonic-gate return (status);
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate /* Get the low fan speed threshold */
3920Sstevel@tonic-gate status = psvc_get_attr(hdlp, tach_id, PSVC_LO_WARN_ATTR, &low_thresh);
3930Sstevel@tonic-gate if (status != PSVC_SUCCESS)
3940Sstevel@tonic-gate return (status);
3950Sstevel@tonic-gate
396958Sjfrank retry = 0;
397958Sjfrank do {
398958Sjfrank if (retry)
399958Sjfrank (void) sleep(retry_sleep_fan);
400958Sjfrank /* Get the fan speed */
401958Sjfrank status = psvc_get_attr(hdlp, tach_id, PSVC_SENSOR_VALUE_ATTR,
402958Sjfrank &speed);
403958Sjfrank if (status != PSVC_SUCCESS)
4040Sstevel@tonic-gate return (status);
4050Sstevel@tonic-gate
406958Sjfrank if (speed <= low_thresh) { /* We see a fault */
407958Sjfrank strlcpy(fault_state, "DEVICE_FAIL",
408958Sjfrank sizeof (fault_state));
409958Sjfrank strlcpy(state, PSVC_ERROR, sizeof (state));
410958Sjfrank have_fault = 1;
411958Sjfrank } else { /* Fault gone? */
412958Sjfrank strlcpy(fault_state, PSVC_NO_FAULT,
413958Sjfrank sizeof (fault_state));
414958Sjfrank strlcpy(state, PSVC_OK, sizeof (state));
415958Sjfrank have_fault = 0;
416958Sjfrank }
417958Sjfrank retry++;
418958Sjfrank } while ((retry < n_retry_fan) && (speed <= low_thresh));
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate /* Assign new states to the fan object */
4210Sstevel@tonic-gate status = psvc_set_attr(hdlp, fan_id, PSVC_FAULTID_ATTR, fault_state);
4220Sstevel@tonic-gate if (status != PSVC_SUCCESS)
4230Sstevel@tonic-gate return (status);
4240Sstevel@tonic-gate status = psvc_set_attr(hdlp, fan_id, PSVC_STATE_ATTR, state);
4250Sstevel@tonic-gate if (status != PSVC_SUCCESS)
4260Sstevel@tonic-gate return (status);
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate /* Get state and previous state */
4290Sstevel@tonic-gate status = psvc_get_attr(hdlp, fan_id, PSVC_STATE_ATTR, state);
4300Sstevel@tonic-gate if (status != PSVC_SUCCESS)
4310Sstevel@tonic-gate return (status);
4320Sstevel@tonic-gate status = psvc_get_attr(hdlp, fan_id, PSVC_PREV_STATE_ATTR, prev_state);
4330Sstevel@tonic-gate if (status != PSVC_SUCCESS)
4340Sstevel@tonic-gate return (status);
4350Sstevel@tonic-gate
4360Sstevel@tonic-gate /* Display notices */
4370Sstevel@tonic-gate if (strcmp(state, PSVC_OK) != 0) {
4380Sstevel@tonic-gate syslog(LOG_ERR, gettext("WARNING: %s (%s) failure detected"),
4390Sstevel@tonic-gate tray_id, fan_id);
4400Sstevel@tonic-gate } else {
4410Sstevel@tonic-gate if (strcmp(state, prev_state) != 0) {
4420Sstevel@tonic-gate syslog(LOG_ERR, gettext("NOTICE: Device %s (%s) OK"),
4430Sstevel@tonic-gate tray_id, fan_id);
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate *fault_on |= have_fault;
4480Sstevel@tonic-gate return (PSVC_SUCCESS);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate /*
4520Sstevel@tonic-gate * This policy acts on fan trays. It looks at each of its fans
4530Sstevel@tonic-gate * and checks the speeds. If the fan speed is less than the threshold,
4540Sstevel@tonic-gate * then indicate: console, log, LED.
4550Sstevel@tonic-gate */
4560Sstevel@tonic-gate int32_t
psvc_fan_fault_check_policy_0(psvc_opaque_t hdlp,char * id)4570Sstevel@tonic-gate psvc_fan_fault_check_policy_0(psvc_opaque_t hdlp, char *id)
4580Sstevel@tonic-gate {
4590Sstevel@tonic-gate int fan_count;
4600Sstevel@tonic-gate int led_count;
4610Sstevel@tonic-gate int err, i;
4620Sstevel@tonic-gate char *led_id;
4630Sstevel@tonic-gate char *fan_id;
4640Sstevel@tonic-gate char led_state[PSVC_MAX_STR_LEN];
4650Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
4660Sstevel@tonic-gate char prev_state[PSVC_MAX_STR_LEN];
4670Sstevel@tonic-gate boolean_t fault_on = 0;
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate /* Get the number of fans associated with this fan tray. */
4700Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &fan_count,
4710Sstevel@tonic-gate PSVC_FAN_TRAY_FANS);
4720Sstevel@tonic-gate if (err != PSVC_SUCCESS)
4730Sstevel@tonic-gate return (err);
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate for (i = 0; i < fan_count; i++) {
4760Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
4770Sstevel@tonic-gate &fan_id, PSVC_FAN_TRAY_FANS, i);
4780Sstevel@tonic-gate if (err != PSVC_SUCCESS)
4790Sstevel@tonic-gate return (err);
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate err = check_fan(hdlp, id, fan_id, &fault_on);
4820Sstevel@tonic-gate if (err != PSVC_SUCCESS)
4830Sstevel@tonic-gate return (err);
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate if (fault_on) {
4870Sstevel@tonic-gate strlcpy(led_state, PSVC_LED_ON, sizeof (led_state));
4880Sstevel@tonic-gate err = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_ERROR);
4890Sstevel@tonic-gate if (err != PSVC_SUCCESS)
4900Sstevel@tonic-gate return (err);
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate } else {
4930Sstevel@tonic-gate strlcpy(led_state, PSVC_LED_OFF, sizeof (led_state));
4940Sstevel@tonic-gate err = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_OK);
4950Sstevel@tonic-gate if (err != PSVC_SUCCESS)
4960Sstevel@tonic-gate return (err);
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
5000Sstevel@tonic-gate if (err != PSVC_SUCCESS)
5010Sstevel@tonic-gate return (err);
5020Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, prev_state);
5030Sstevel@tonic-gate if (err != PSVC_SUCCESS)
5040Sstevel@tonic-gate return (err);
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate /*
5070Sstevel@tonic-gate * Set leds according to the fan tray's states.
5080Sstevel@tonic-gate * (we only do this if there is a change of state in order
5090Sstevel@tonic-gate * to reduce i2c traffic)
5100Sstevel@tonic-gate */
5110Sstevel@tonic-gate if (strcmp(state, prev_state) != 0) {
5120Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR,
5130Sstevel@tonic-gate &led_count, PSVC_DEV_FAULT_LED);
5140Sstevel@tonic-gate if (err != PSVC_SUCCESS)
5150Sstevel@tonic-gate return (err);
5160Sstevel@tonic-gate for (i = 0; i < led_count; i++) {
5170Sstevel@tonic-gate err = psvc_get_attr(hdlp, id,
5180Sstevel@tonic-gate PSVC_ASSOC_ID_ATTR, &led_id,
5190Sstevel@tonic-gate PSVC_DEV_FAULT_LED, i);
5200Sstevel@tonic-gate if (err != PSVC_SUCCESS)
5210Sstevel@tonic-gate return (err);
5220Sstevel@tonic-gate err = psvc_set_attr(hdlp, led_id,
5230Sstevel@tonic-gate PSVC_LED_STATE_ATTR, led_state);
5240Sstevel@tonic-gate if (err != PSVC_SUCCESS)
5250Sstevel@tonic-gate return (err);
5260Sstevel@tonic-gate err = psvc_get_attr(hdlp, led_id,
5270Sstevel@tonic-gate PSVC_LED_STATE_ATTR, led_state);
5280Sstevel@tonic-gate if (err != PSVC_SUCCESS)
5290Sstevel@tonic-gate return (err);
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate return (err);
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate static int32_t
check_cpu_temp_fault(psvc_opaque_t hdlp,char * cpu,int32_t cpu_count)5360Sstevel@tonic-gate check_cpu_temp_fault(psvc_opaque_t hdlp, char *cpu, int32_t cpu_count)
5370Sstevel@tonic-gate {
5380Sstevel@tonic-gate char *sensorid;
5390Sstevel@tonic-gate int32_t sensor_count;
5400Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
5410Sstevel@tonic-gate int32_t i;
5420Sstevel@tonic-gate char fault[PSVC_MAX_STR_LEN];
543958Sjfrank int retry;
5440Sstevel@tonic-gate
5450Sstevel@tonic-gate psvc_get_attr(hdlp, cpu, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
5460Sstevel@tonic-gate PSVC_DEV_TEMP_SENSOR);
5470Sstevel@tonic-gate for (i = 0; i < sensor_count; ++i) {
5480Sstevel@tonic-gate status = psvc_get_attr(hdlp, cpu, PSVC_ASSOC_ID_ATTR,
5490Sstevel@tonic-gate &sensorid, PSVC_DEV_TEMP_SENSOR, i);
5500Sstevel@tonic-gate if (status == PSVC_FAILURE)
5510Sstevel@tonic-gate return (status);
5520Sstevel@tonic-gate
553958Sjfrank retry = 0;
554958Sjfrank do {
555958Sjfrank if (retry)
556958Sjfrank (void) sleep(retry_sleep_temp_shutdown);
557958Sjfrank status = psvc_get_attr(hdlp, sensorid,
558958Sjfrank PSVC_FAULTID_ATTR, fault);
559958Sjfrank if (status == PSVC_FAILURE)
560958Sjfrank return (status);
561958Sjfrank retry++;
562958Sjfrank } while (((strcmp(fault, PSVC_TEMP_LO_SHUT) == 0) ||
563958Sjfrank (strcmp(fault, PSVC_TEMP_HI_SHUT) == 0)) &&
564958Sjfrank (retry < n_retry_temp_shutdown));
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate if ((strcmp(fault, PSVC_TEMP_HI_SHUT) == 0) ||
5670Sstevel@tonic-gate (strcmp(fault, PSVC_TEMP_LO_SHUT) == 0)) {
5680Sstevel@tonic-gate system("shutdown -y -g 60 -i 5 \"OVERTEMP condition\"");
5690Sstevel@tonic-gate }
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate
5720Sstevel@tonic-gate return (status);
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate int32_t
psvc_shutdown_policy_0(psvc_opaque_t hdlp,char * id)5760Sstevel@tonic-gate psvc_shutdown_policy_0(psvc_opaque_t hdlp, char *id)
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate int32_t cpu_count;
5790Sstevel@tonic-gate char *cpuid;
5800Sstevel@tonic-gate int32_t i;
5810Sstevel@tonic-gate boolean_t present;
5820Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
5830Sstevel@tonic-gate
5840Sstevel@tonic-gate psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count,
5850Sstevel@tonic-gate PSVC_CPU);
5860Sstevel@tonic-gate for (i = 0; i < cpu_count; ++i) {
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &cpuid,
5890Sstevel@tonic-gate PSVC_CPU, i);
5900Sstevel@tonic-gate if (status == PSVC_FAILURE)
5910Sstevel@tonic-gate return (status);
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate status = psvc_get_attr(hdlp, cpuid,
5940Sstevel@tonic-gate PSVC_PRESENCE_ATTR, &present);
5950Sstevel@tonic-gate if (status == PSVC_FAILURE && present == PSVC_PRESENT)
5960Sstevel@tonic-gate return (status);
5970Sstevel@tonic-gate if (present == PSVC_PRESENT) {
5980Sstevel@tonic-gate status = check_cpu_temp_fault(hdlp, cpuid, cpu_count);
5990Sstevel@tonic-gate if (status == PSVC_FAILURE && errno != ENODEV)
6000Sstevel@tonic-gate return (status);
6010Sstevel@tonic-gate }
6020Sstevel@tonic-gate }
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate return (PSVC_SUCCESS);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate
6070Sstevel@tonic-gate /*
6080Sstevel@tonic-gate * Checks device specified by the PSVC_DEV_FAULT_SENSOR association
6090Sstevel@tonic-gate * for errors, and if there is, then report and turn on the FSP Fault
6100Sstevel@tonic-gate * Led.
6110Sstevel@tonic-gate */
6120Sstevel@tonic-gate int32_t
psvc_fsp_device_fault_check_policy_0(psvc_opaque_t hdlp,char * id)6130Sstevel@tonic-gate psvc_fsp_device_fault_check_policy_0(psvc_opaque_t hdlp, char *id)
6140Sstevel@tonic-gate {
6150Sstevel@tonic-gate int32_t status;
6160Sstevel@tonic-gate int32_t i;
6170Sstevel@tonic-gate int32_t device_count = 0;
6180Sstevel@tonic-gate char device_state[PSVC_MAX_STR_LEN];
6190Sstevel@tonic-gate char *device_id;
6200Sstevel@tonic-gate int32_t failed_count = 0;
6210Sstevel@tonic-gate static int32_t led_on = 0;
622958Sjfrank int retry;
6230Sstevel@tonic-gate
6240Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR,
6250Sstevel@tonic-gate &device_count, PSVC_DEV_FAULT_SENSOR);
6260Sstevel@tonic-gate if (status != PSVC_SUCCESS)
6270Sstevel@tonic-gate return (status);
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate for (i = 0; i < device_count; i++) {
6300Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
6310Sstevel@tonic-gate &device_id, PSVC_DEV_FAULT_SENSOR, i);
6320Sstevel@tonic-gate if (status != PSVC_SUCCESS)
6330Sstevel@tonic-gate return (status);
6340Sstevel@tonic-gate
635958Sjfrank retry = 0;
636958Sjfrank do {
637958Sjfrank if (retry)
638958Sjfrank (void) sleep(retry_sleep_fsp_fault);
639958Sjfrank status = psvc_get_attr(hdlp, device_id, PSVC_STATE_ATTR,
640958Sjfrank device_state);
641958Sjfrank if (status != PSVC_SUCCESS)
642958Sjfrank return (status);
6430Sstevel@tonic-gate
644958Sjfrank if (strcmp(device_state, PSVC_OK) != 0 &&
645958Sjfrank strcmp(device_state, PSVC_HOTPLUGGED) != 0 &&
646958Sjfrank strcmp(device_state, "NO AC POWER") != 0 &&
647958Sjfrank strlen(device_state) != 0) {
648958Sjfrank failed_count++;
649958Sjfrank }
650958Sjfrank retry++;
651958Sjfrank } while ((retry < n_retry_fsp_fault) && (failed_count));
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate if (failed_count == 0 && led_on) {
6540Sstevel@tonic-gate syslog(LOG_ERR, gettext("%s has turned OFF"), id);
6550Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_LED_STATE_ATTR,
6560Sstevel@tonic-gate PSVC_LED_OFF);
6570Sstevel@tonic-gate led_on = 0;
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate if (failed_count > 0 && ! led_on) {
6610Sstevel@tonic-gate syslog(LOG_ERR,
6620Sstevel@tonic-gate gettext("%s has turned ON"), id);
6630Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_LED_STATE_ATTR,
6640Sstevel@tonic-gate PSVC_LED_ON);
6650Sstevel@tonic-gate led_on = 1;
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate
6680Sstevel@tonic-gate return (PSVC_SUCCESS);
6690Sstevel@tonic-gate }
6700Sstevel@tonic-gate
6710Sstevel@tonic-gate /* Power Supply Policy Helper and Worker Functions */
6720Sstevel@tonic-gate static void
ps_reset_prev_failed(int index)6730Sstevel@tonic-gate ps_reset_prev_failed(int index)
6740Sstevel@tonic-gate {
6750Sstevel@tonic-gate int i;
6760Sstevel@tonic-gate /* Reset the power supply's failure information */
6770Sstevel@tonic-gate for (i = 0; i < 3; i++) {
6780Sstevel@tonic-gate ps_prev_id[index][i] = NULL;
6790Sstevel@tonic-gate ps_prev_failed[index][i] = 0;
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate static int
check_i2c_access(psvc_opaque_t hdlp,char * id)6840Sstevel@tonic-gate check_i2c_access(psvc_opaque_t hdlp, char *id)
6850Sstevel@tonic-gate {
6860Sstevel@tonic-gate int rv;
6870Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
6880Sstevel@tonic-gate char ps_fault_sensor[PSVC_MAX_STR_LEN];
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate snprintf(ps_fault_sensor, sizeof (ps_fault_sensor),
6910Sstevel@tonic-gate "%s_FAULT_SENSOR", id);
6920Sstevel@tonic-gate
6930Sstevel@tonic-gate rv = psvc_get_attr(hdlp, ps_fault_sensor, PSVC_SWITCH_STATE_ATTR,
6940Sstevel@tonic-gate &state);
6950Sstevel@tonic-gate return (rv);
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate
6980Sstevel@tonic-gate /*
6990Sstevel@tonic-gate * This routine takes in the PSVC handle pointer, the PS name, and the
7000Sstevel@tonic-gate * instance number (0 or 1). It simply make a psvc_get call to get the
7010Sstevel@tonic-gate * presence of each of the children under the PS. This call will set the
7020Sstevel@tonic-gate * presence state of the child device if it was not there when the system
7030Sstevel@tonic-gate * was booted.
7040Sstevel@tonic-gate */
7050Sstevel@tonic-gate static int
handle_ps_hotplug_children_presence(psvc_opaque_t hdlp,char * id)7060Sstevel@tonic-gate handle_ps_hotplug_children_presence(psvc_opaque_t hdlp, char *id)
7070Sstevel@tonic-gate {
7080Sstevel@tonic-gate char *child_add_on[4] = {"_RESET", "_LOGICAL_STATE", "_AC_IN_SENSOR",
7090Sstevel@tonic-gate "_FAULT_SENSOR"};
7100Sstevel@tonic-gate int add_ons = 4;
7110Sstevel@tonic-gate char addon_id[PICL_PROPNAMELEN_MAX];
7120Sstevel@tonic-gate char *sensor_id;
7130Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
7140Sstevel@tonic-gate boolean_t presence;
7150Sstevel@tonic-gate int j;
7160Sstevel@tonic-gate
7170Sstevel@tonic-gate /* Go through the add on list and set presence */
7180Sstevel@tonic-gate for (j = 0; j < add_ons; j++) {
7190Sstevel@tonic-gate snprintf(addon_id, sizeof (addon_id), "%s%s", id,
7200Sstevel@tonic-gate child_add_on[j]);
7210Sstevel@tonic-gate status = psvc_get_attr(hdlp, addon_id, PSVC_PRESENCE_ATTR,
7220Sstevel@tonic-gate &presence);
7230Sstevel@tonic-gate if (status != PSVC_SUCCESS)
7240Sstevel@tonic-gate return (status);
7250Sstevel@tonic-gate }
7260Sstevel@tonic-gate
7270Sstevel@tonic-gate /* Go through each PS's fault sensors */
7280Sstevel@tonic-gate for (j = 0; j < PS_MAX_FAULT_SENSORS; j++) {
7290Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
7300Sstevel@tonic-gate &(sensor_id), PSVC_DEV_FAULT_SENSOR, j);
7310Sstevel@tonic-gate if (status != PSVC_SUCCESS)
7320Sstevel@tonic-gate return (status);
7330Sstevel@tonic-gate status = psvc_get_attr(hdlp, sensor_id, PSVC_PRESENCE_ATTR,
7340Sstevel@tonic-gate &presence);
7350Sstevel@tonic-gate if (status != PSVC_SUCCESS)
7360Sstevel@tonic-gate return (status);
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate
7390Sstevel@tonic-gate /* Go through each PS's onboard i2c hardware */
7400Sstevel@tonic-gate for (j = 0; j < 2; j++) {
7410Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
7420Sstevel@tonic-gate &(sensor_id), PSVC_PHYSICAL_DEVICE, j);
7430Sstevel@tonic-gate if (status != PSVC_SUCCESS)
7440Sstevel@tonic-gate return (status);
7450Sstevel@tonic-gate status = psvc_get_attr(hdlp, sensor_id, PSVC_PRESENCE_ATTR,
7460Sstevel@tonic-gate &presence);
7470Sstevel@tonic-gate if (status != PSVC_SUCCESS)
7480Sstevel@tonic-gate return (status);
7490Sstevel@tonic-gate }
7500Sstevel@tonic-gate
7510Sstevel@tonic-gate return (status);
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate
7540Sstevel@tonic-gate static int
handle_ps_hotplug(psvc_opaque_t hdlp,char * id,boolean_t present)7550Sstevel@tonic-gate handle_ps_hotplug(psvc_opaque_t hdlp, char *id, boolean_t present)
7560Sstevel@tonic-gate {
7570Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
7580Sstevel@tonic-gate int32_t instance;
7590Sstevel@tonic-gate picl_nodehdl_t parent_node;
7600Sstevel@tonic-gate picl_nodehdl_t child_node;
7610Sstevel@tonic-gate char info[PSVC_MAX_STR_LEN];
7620Sstevel@tonic-gate char ps_logical_state[PICL_PROPNAMELEN_MAX];
7630Sstevel@tonic-gate char parent_path[PICL_PROPNAMELEN_MAX];
7640Sstevel@tonic-gate char ps_path[PICL_PROPNAMELEN_MAX];
7650Sstevel@tonic-gate static int fruprom_addr[2][2] = { {0, 0xa2}, {0, 0xa0} };
7660Sstevel@tonic-gate static int pcf8574_addr[2][2] = { {0, 0x72}, {0, 0x70} };
7670Sstevel@tonic-gate char dev_path[MAXPATHLEN];
7680Sstevel@tonic-gate
7690Sstevel@tonic-gate /* Convert name to node and parent path */
7700Sstevel@tonic-gate psvcplugin_lookup(id, parent_path, &child_node);
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate /*
7730Sstevel@tonic-gate * Get the power supply's instance.
7740Sstevel@tonic-gate * Used to index the xxx_addr arrays
7750Sstevel@tonic-gate */
7760Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
7770Sstevel@tonic-gate if (status != PSVC_SUCCESS)
7780Sstevel@tonic-gate return (status);
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate if (present == PSVC_PRESENT && !ps_prev_present[instance]) {
7810Sstevel@tonic-gate /* Service Power Supply Insertion */
7820Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s inserted"), id);
7830Sstevel@tonic-gate
7840Sstevel@tonic-gate /* PICL Tree Maintenance */
7850Sstevel@tonic-gate ptree_get_node_by_path(parent_path, &parent_node);
7860Sstevel@tonic-gate ptree_add_node(parent_node, child_node);
7870Sstevel@tonic-gate snprintf(ps_path, sizeof (ps_path), "%s/%s", parent_path, id);
7880Sstevel@tonic-gate psvcplugin_add_children(ps_path);
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate /*
7910Sstevel@tonic-gate * This code to update the presences of power supply
7920Sstevel@tonic-gate * child devices in the event that picld was started
7930Sstevel@tonic-gate * without a power supply present. This call makes
7940Sstevel@tonic-gate * the devices available after that initial insertion.
7950Sstevel@tonic-gate */
7960Sstevel@tonic-gate status = handle_ps_hotplug_children_presence(hdlp, id);
7970Sstevel@tonic-gate
7980Sstevel@tonic-gate /*
7990Sstevel@tonic-gate * Device Tree Maintenance
8000Sstevel@tonic-gate * Add the devinfo tree node entry for the pcf8574 and seeprom
8010Sstevel@tonic-gate * and attach their drivers.
8020Sstevel@tonic-gate */
8030Sstevel@tonic-gate status |= create_i2c_node("ioexp", "i2c-pcf8574", SEG5_ADDR,
8040Sstevel@tonic-gate pcf8574_addr[instance]);
8050Sstevel@tonic-gate status |= create_i2c_node("fru", "i2c-at24c64", SEG5_ADDR,
8060Sstevel@tonic-gate fruprom_addr[instance]);
8070Sstevel@tonic-gate } else {
8080Sstevel@tonic-gate /* Service Power Supply Removal */
8090Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s removed"), id);
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate /* Reset the power supply's failure information */
8120Sstevel@tonic-gate ps_reset_prev_failed(instance);
8130Sstevel@tonic-gate
8140Sstevel@tonic-gate /* PICL Tree Maintenance */
8150Sstevel@tonic-gate if (ptree_delete_node(child_node) != PICL_SUCCESS)
8160Sstevel@tonic-gate syslog(LOG_ERR, "ptree_delete_node failed!");
8170Sstevel@tonic-gate
8180Sstevel@tonic-gate /*
8190Sstevel@tonic-gate * The hardcoded subscript in pcf8574_add[instance][1]
8200Sstevel@tonic-gate * refers to the address. We are appending the address to
8210Sstevel@tonic-gate * device path. Both elements are used when creating
8220Sstevel@tonic-gate * the i2c node (above).
8230Sstevel@tonic-gate */
8240Sstevel@tonic-gate snprintf(dev_path, sizeof (dev_path),
8250Sstevel@tonic-gate SEG5_DEV_NAME"ioexp@0,%x:pcf8574",
8260Sstevel@tonic-gate pcf8574_addr[instance][1]);
8270Sstevel@tonic-gate delete_i2c_node(dev_path);
8280Sstevel@tonic-gate
8290Sstevel@tonic-gate snprintf(dev_path, sizeof (dev_path),
8300Sstevel@tonic-gate SEG5_DEV_NAME"fru@0,%x:fru", fruprom_addr[instance][1]);
8310Sstevel@tonic-gate delete_i2c_node(dev_path);
8320Sstevel@tonic-gate }
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate snprintf(ps_logical_state, sizeof (ps_logical_state),
8350Sstevel@tonic-gate "%s_LOGICAL_STATE", id);
8360Sstevel@tonic-gate
8370Sstevel@tonic-gate strlcpy(info, PSVC_OK, sizeof (info));
8380Sstevel@tonic-gate status |= psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, info);
8390Sstevel@tonic-gate status |= psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR, info);
8400Sstevel@tonic-gate
8410Sstevel@tonic-gate strlcpy(info, PSVC_NO_FAULT, sizeof (info));
8420Sstevel@tonic-gate status |= psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, info);
8430Sstevel@tonic-gate
8440Sstevel@tonic-gate /* Enable the i2c connection to the power supply */
8450Sstevel@tonic-gate status |= pdb_enable_i2c(hdlp);
8460Sstevel@tonic-gate return (status);
8470Sstevel@tonic-gate }
8480Sstevel@tonic-gate
8490Sstevel@tonic-gate /*
8500Sstevel@tonic-gate * check_ps_state() Checks for:
8510Sstevel@tonic-gate *
8520Sstevel@tonic-gate * - Failure bits:
8530Sstevel@tonic-gate * Power Supply Fan Failure
8540Sstevel@tonic-gate * Power Supply Temperature Failure
8550Sstevel@tonic-gate * Power Supply Generic Fault
8560Sstevel@tonic-gate * Power Supply AC Cord Plugged In
8570Sstevel@tonic-gate *
8580Sstevel@tonic-gate * - If we see a "bad" state we will report an error.
8590Sstevel@tonic-gate *
8600Sstevel@tonic-gate * - "Bad" states:
8610Sstevel@tonic-gate * Fault bit shows fault.
8620Sstevel@tonic-gate * Temperature fault shows fault.
8630Sstevel@tonic-gate * Fan fault shows fault.
8640Sstevel@tonic-gate * AC power NOT okay to supply.
8650Sstevel@tonic-gate *
8660Sstevel@tonic-gate * - If we see that the AC Cord is not plugged in, then the the other
8670Sstevel@tonic-gate * failure bits are invalid.
8680Sstevel@tonic-gate *
8690Sstevel@tonic-gate * - Send pcf8574_reset at the end of the policy if we see
8700Sstevel@tonic-gate * any "bad" states.
8710Sstevel@tonic-gate */
8720Sstevel@tonic-gate static int32_t
check_ps_state(psvc_opaque_t hdlp,char * id)8730Sstevel@tonic-gate check_ps_state(psvc_opaque_t hdlp, char *id)
8740Sstevel@tonic-gate {
8750Sstevel@tonic-gate int32_t sensor_count;
8760Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
8770Sstevel@tonic-gate int32_t i;
8780Sstevel@tonic-gate int32_t fault_on = 0;
8790Sstevel@tonic-gate char *sensor_id;
8800Sstevel@tonic-gate char ps_ok_sensor[PICL_PROPNAMELEN_MAX];
8810Sstevel@tonic-gate char ps_logical_state[PICL_PROPNAMELEN_MAX];
8820Sstevel@tonic-gate char ps_reset[PICL_PROPNAMELEN_MAX];
8830Sstevel@tonic-gate char previous_state[PSVC_MAX_STR_LEN];
8840Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
8850Sstevel@tonic-gate char fault[PSVC_MAX_STR_LEN];
8860Sstevel@tonic-gate int ps_okay = 1; /* Keep track of the PDB PS OK Bit */
8870Sstevel@tonic-gate int instance;
888958Sjfrank int retry;
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate /* Logical state id */
8910Sstevel@tonic-gate snprintf(ps_logical_state, sizeof (ps_logical_state),
8920Sstevel@tonic-gate "%s_LOGICAL_STATE", id);
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate /*
8950Sstevel@tonic-gate * ac_power_check updates the Power Supply state with "NO AC POWER" if
8960Sstevel@tonic-gate * the power cord is out OR PSVC_OK if the power cord is in.
8970Sstevel@tonic-gate */
8980Sstevel@tonic-gate status = ac_power_check(hdlp, id, ps_logical_state);
8990Sstevel@tonic-gate if (status == PSVC_FAILURE)
9000Sstevel@tonic-gate return (status);
9010Sstevel@tonic-gate
9020Sstevel@tonic-gate /*
9030Sstevel@tonic-gate * After running ac_power_check we now need to get the current state
9040Sstevel@tonic-gate * of the PS. If the power supply state is "NO AC POWER" then we do
9050Sstevel@tonic-gate * not need to check for failures and we return.
9060Sstevel@tonic-gate */
9070Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
9080Sstevel@tonic-gate if (status != PSVC_SUCCESS)
9090Sstevel@tonic-gate return (status);
9100Sstevel@tonic-gate
9110Sstevel@tonic-gate if (strcmp(state, "NO AC POWER") == 0)
9120Sstevel@tonic-gate return (status);
9130Sstevel@tonic-gate
914958Sjfrank status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, previous_state);
9150Sstevel@tonic-gate if (status != PSVC_SUCCESS)
9160Sstevel@tonic-gate return (status);
9170Sstevel@tonic-gate
918958Sjfrank snprintf(ps_ok_sensor, sizeof (ps_ok_sensor), "%s_OK_SENSOR", id);
919958Sjfrank retry = 0;
920958Sjfrank do {
921958Sjfrank if (retry)
922958Sjfrank (void) sleep(retry_sleep_ps_status);
923958Sjfrank /* Handle the PDB P/S OK Bit */
924958Sjfrank status = psvc_get_attr(hdlp, ps_ok_sensor,
925958Sjfrank PSVC_SWITCH_STATE_ATTR, state);
926958Sjfrank if (status != PSVC_SUCCESS)
927958Sjfrank return (status);
928958Sjfrank retry++;
929958Sjfrank } while ((retry < n_retry_ps_status) &&
930958Sjfrank (strcmp(previous_state, state)));
931958Sjfrank
9320Sstevel@tonic-gate
9330Sstevel@tonic-gate /*
9340Sstevel@tonic-gate * If there is a change of state (current state differs from
9350Sstevel@tonic-gate * previous state, then assign the error values.
9360Sstevel@tonic-gate */
9370Sstevel@tonic-gate if (strcmp(previous_state, state) != 0) {
9380Sstevel@tonic-gate if (strcmp(state, PSVC_SWITCH_OFF) == 0) {
9390Sstevel@tonic-gate strlcpy(state, PSVC_ERROR, sizeof (state));
9400Sstevel@tonic-gate strlcpy(fault, "DEVICE_FAIL", sizeof (fault));
9410Sstevel@tonic-gate fault_on = 1;
9420Sstevel@tonic-gate syslog(LOG_ERR, gettext(
9430Sstevel@tonic-gate "Device %s: Failure Detected -- %s "
9440Sstevel@tonic-gate "shutdown!"), id, id);
9450Sstevel@tonic-gate ps_okay = 0;
9460Sstevel@tonic-gate } else {
9470Sstevel@tonic-gate strlcpy(state, PSVC_OK, sizeof (state));
9480Sstevel@tonic-gate strlcpy(fault, PSVC_NO_FAULT, sizeof (fault));
9490Sstevel@tonic-gate }
9500Sstevel@tonic-gate
9510Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
9520Sstevel@tonic-gate if (status != PSVC_SUCCESS)
9530Sstevel@tonic-gate return (status);
9540Sstevel@tonic-gate
9550Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
9560Sstevel@tonic-gate if (status != PSVC_SUCCESS)
9570Sstevel@tonic-gate return (status);
9580Sstevel@tonic-gate }
9590Sstevel@tonic-gate
9600Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
9610Sstevel@tonic-gate if (status != PSVC_SUCCESS)
9620Sstevel@tonic-gate return (status);
9630Sstevel@tonic-gate
9640Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
9650Sstevel@tonic-gate PSVC_DEV_FAULT_SENSOR);
9660Sstevel@tonic-gate if (status != PSVC_SUCCESS) {
9670Sstevel@tonic-gate return (status);
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate
9700Sstevel@tonic-gate /* Handle the power supply fail bits. */
9710Sstevel@tonic-gate for (i = 0; i < sensor_count; i++) {
9720Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
9730Sstevel@tonic-gate &sensor_id, PSVC_DEV_FAULT_SENSOR, i);
9740Sstevel@tonic-gate if (status != PSVC_SUCCESS)
9750Sstevel@tonic-gate return (status);
9760Sstevel@tonic-gate
977958Sjfrank retry = 0;
978958Sjfrank do {
979958Sjfrank if (retry)
980958Sjfrank (void) sleep(retry_sleep_ps_status);
981958Sjfrank status = psvc_get_attr(hdlp, sensor_id,
982958Sjfrank PSVC_SWITCH_STATE_ATTR, state);
983958Sjfrank if (status != PSVC_SUCCESS)
984958Sjfrank return (status);
985958Sjfrank retry++;
986958Sjfrank } while ((retry < n_retry_ps_status) &&
987958Sjfrank (strcmp(state, PSVC_SWITCH_ON) == 0));
9880Sstevel@tonic-gate
9890Sstevel@tonic-gate if (strcmp(state, PSVC_SWITCH_ON) == 0) {
9900Sstevel@tonic-gate if (ps_prev_id[instance][i] == NULL)
9910Sstevel@tonic-gate ps_prev_id[instance][i] = sensor_id;
9920Sstevel@tonic-gate
9930Sstevel@tonic-gate if (ps_prev_failed[instance][i] != 1)
9940Sstevel@tonic-gate ps_prev_failed[instance][i] = 1;
9950Sstevel@tonic-gate fault_on = 1;
9960Sstevel@tonic-gate /*
9970Sstevel@tonic-gate * The first sensor in the list is:
9980Sstevel@tonic-gate * PSx_DEV_FAULT_SENSOR. If this is on, we do not
9990Sstevel@tonic-gate * want to merely report that it's on, but rather
10000Sstevel@tonic-gate * report that there was a fault detected, thus
10010Sstevel@tonic-gate * improving diagnosability.
10020Sstevel@tonic-gate */
10030Sstevel@tonic-gate if (i == 0) {
10040Sstevel@tonic-gate /*
10050Sstevel@tonic-gate * Don't notify if the PDB PS OKAY Bit is
10060Sstevel@tonic-gate * "0"
10070Sstevel@tonic-gate */
10080Sstevel@tonic-gate if (ps_okay)
10090Sstevel@tonic-gate syslog(LOG_ERR, gettext(
10100Sstevel@tonic-gate "Device %s: Fault Detected"),
10110Sstevel@tonic-gate id);
10120Sstevel@tonic-gate } else {
10130Sstevel@tonic-gate syslog(LOG_ERR, gettext("Warning %s: %s is ON"),
10140Sstevel@tonic-gate id, sensor_id);
10150Sstevel@tonic-gate }
10160Sstevel@tonic-gate }
10170Sstevel@tonic-gate }
10180Sstevel@tonic-gate
10190Sstevel@tonic-gate status = psvc_get_attr(hdlp, ps_logical_state,
10200Sstevel@tonic-gate PSVC_STATE_ATTR, state);
10210Sstevel@tonic-gate if (status != PSVC_SUCCESS)
10220Sstevel@tonic-gate return (status);
10230Sstevel@tonic-gate
10240Sstevel@tonic-gate status = psvc_get_attr(hdlp, ps_logical_state,
10250Sstevel@tonic-gate PSVC_PREV_STATE_ATTR, previous_state);
10260Sstevel@tonic-gate if (status != PSVC_SUCCESS)
10270Sstevel@tonic-gate return (status);
10280Sstevel@tonic-gate
10290Sstevel@tonic-gate /*
10300Sstevel@tonic-gate * If we encountered a fault of any kind (something before
10310Sstevel@tonic-gate * has set 'fault_on' to '1') then we want to send the reset
10320Sstevel@tonic-gate * signal to the power supply's PCF8574 and also set
10330Sstevel@tonic-gate * 'ps_logical_state' to "ERROR" so that the FSP General Fault
10340Sstevel@tonic-gate * LED will light.
10350Sstevel@tonic-gate */
10360Sstevel@tonic-gate if (fault_on) {
10370Sstevel@tonic-gate if (ps_okay) {
10380Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
10390Sstevel@tonic-gate PSVC_GEN_FAULT);
10400Sstevel@tonic-gate if (status != PSVC_SUCCESS)
10410Sstevel@tonic-gate return (status);
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate status = psvc_set_attr(hdlp, ps_logical_state,
10440Sstevel@tonic-gate PSVC_STATE_ATTR, PSVC_ERROR);
10450Sstevel@tonic-gate if (status != PSVC_SUCCESS)
10460Sstevel@tonic-gate return (status);
10470Sstevel@tonic-gate /*
10480Sstevel@tonic-gate * "id" is in the form of "PSx", We need to make it
10490Sstevel@tonic-gate * PSx_RESET.
10500Sstevel@tonic-gate */
10510Sstevel@tonic-gate snprintf(ps_reset, sizeof (ps_reset), "%s_RESET", id);
10520Sstevel@tonic-gate status = send_pcf8574_reset(hdlp, ps_reset);
10530Sstevel@tonic-gate return (status);
10540Sstevel@tonic-gate }
10550Sstevel@tonic-gate
10560Sstevel@tonic-gate /*
10570Sstevel@tonic-gate * There was no fault encountered so we want to
10580Sstevel@tonic-gate * set 'ps_logical_state' to "OK"
10590Sstevel@tonic-gate */
10600Sstevel@tonic-gate if (strcmp(state, PSVC_OK) != 0) {
10610Sstevel@tonic-gate for (i = 0; i < 3; i++) {
10620Sstevel@tonic-gate char *sensor = ps_prev_id[instance][i];
10630Sstevel@tonic-gate int *prev_failed = &ps_prev_failed[instance][i];
10640Sstevel@tonic-gate if (sensor == NULL)
10650Sstevel@tonic-gate continue;
10660Sstevel@tonic-gate if (*prev_failed == 0)
10670Sstevel@tonic-gate continue;
10680Sstevel@tonic-gate *prev_failed = 0;
10690Sstevel@tonic-gate if (i == 0) {
10700Sstevel@tonic-gate /*
10710Sstevel@tonic-gate * Don't notifiy if we have a power supply
10720Sstevel@tonic-gate * failure (PDB PS OKAY == 0
10730Sstevel@tonic-gate */
10740Sstevel@tonic-gate if (ps_okay)
10750Sstevel@tonic-gate syslog(LOG_ERR, gettext(
10760Sstevel@tonic-gate "Notice %s: Fault Cleared"),
10770Sstevel@tonic-gate id);
10780Sstevel@tonic-gate } else {
10790Sstevel@tonic-gate syslog(LOG_ERR, gettext("Notice %s: %s is OFF"),
10800Sstevel@tonic-gate id, sensor);
10810Sstevel@tonic-gate }
10820Sstevel@tonic-gate }
10830Sstevel@tonic-gate
10840Sstevel@tonic-gate status = psvc_set_attr(hdlp, ps_logical_state,
10850Sstevel@tonic-gate PSVC_STATE_ATTR, PSVC_OK);
10860Sstevel@tonic-gate if (status != PSVC_SUCCESS)
10870Sstevel@tonic-gate return (status);
10880Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s Okay"), id);
10890Sstevel@tonic-gate }
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate return (PSVC_SUCCESS);
10920Sstevel@tonic-gate }
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate /*
10950Sstevel@tonic-gate * This routine takes in a handle pointer and a Power Supply id. It then gets
10960Sstevel@tonic-gate * the switch state for the PSx_AC_IN_SENSOR. If the switch is OFF the cord is
10970Sstevel@tonic-gate * unplugged and we return a true (1). If the switch is ON then the cord is
10980Sstevel@tonic-gate * plugged in and we return a false (0). If the get_attr call fails we return
10990Sstevel@tonic-gate * PSVC_FAILURE (-1).
11000Sstevel@tonic-gate */
11010Sstevel@tonic-gate static int
ac_unplugged(psvc_opaque_t hdlp,char * id)11020Sstevel@tonic-gate ac_unplugged(psvc_opaque_t hdlp, char *id)
11030Sstevel@tonic-gate {
11040Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
11050Sstevel@tonic-gate char ac_sensor_id[PICL_PROPNAMELEN_MAX];
11060Sstevel@tonic-gate char ac_switch_state[PSVC_MAX_STR_LEN];
11070Sstevel@tonic-gate
11080Sstevel@tonic-gate snprintf(ac_sensor_id, sizeof (ac_sensor_id), "%s_AC_IN_SENSOR", id);
11090Sstevel@tonic-gate
11100Sstevel@tonic-gate status = psvc_get_attr(hdlp, ac_sensor_id, PSVC_SWITCH_STATE_ATTR,
11110Sstevel@tonic-gate ac_switch_state);
11120Sstevel@tonic-gate if (status == PSVC_FAILURE) {
11130Sstevel@tonic-gate return (status);
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate
11160Sstevel@tonic-gate if (strcmp(ac_switch_state, PSVC_SWITCH_OFF) == 0) {
11170Sstevel@tonic-gate return (1);
11180Sstevel@tonic-gate } else {
11190Sstevel@tonic-gate return (0);
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate }
11220Sstevel@tonic-gate
11230Sstevel@tonic-gate /*
11240Sstevel@tonic-gate * This routine expects a handle pointer, a Power Supply ID, and a PS logical
11250Sstevel@tonic-gate * state switch ID. It check to see if the power cord has been removed from or
11260Sstevel@tonic-gate * inserted to the power supply. It then updates the PS state accordingly.
11270Sstevel@tonic-gate */
11280Sstevel@tonic-gate static int
ac_power_check(psvc_opaque_t hdlp,char * id,char * ps_logical_state)11290Sstevel@tonic-gate ac_power_check(psvc_opaque_t hdlp, char *id, char *ps_logical_state)
11300Sstevel@tonic-gate {
11310Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
11320Sstevel@tonic-gate int32_t sensor_count;
11330Sstevel@tonic-gate char *sensor_id;
11340Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
11350Sstevel@tonic-gate int unplugged, i;
11360Sstevel@tonic-gate
11370Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
11380Sstevel@tonic-gate if (status != PSVC_SUCCESS)
11390Sstevel@tonic-gate return (status);
11400Sstevel@tonic-gate
11410Sstevel@tonic-gate /*
11420Sstevel@tonic-gate * Check for AC Power Cord. ac_unplugged will return true if the PS is
11430Sstevel@tonic-gate * unplugged, a false is the PS is plugged in, and PSVC_FAILURE if the
11440Sstevel@tonic-gate * call to get the state fails.
11450Sstevel@tonic-gate */
11460Sstevel@tonic-gate unplugged = ac_unplugged(hdlp, id);
11470Sstevel@tonic-gate if (status == PSVC_FAILURE) {
11480Sstevel@tonic-gate return (status);
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate
11510Sstevel@tonic-gate /*
11520Sstevel@tonic-gate * If power cord is not in, then we set the fault and error
11530Sstevel@tonic-gate * states to "".
11540Sstevel@tonic-gate * If power cord is in, then we check the devices.
11550Sstevel@tonic-gate */
11560Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
11570Sstevel@tonic-gate PSVC_DEV_FAULT_SENSOR);
11580Sstevel@tonic-gate if (status != PSVC_SUCCESS) {
11590Sstevel@tonic-gate return (status);
11600Sstevel@tonic-gate }
11610Sstevel@tonic-gate
11620Sstevel@tonic-gate if ((unplugged) && (strcmp(state, "NO AC POWER") != 0)) {
11630Sstevel@tonic-gate /* set id's state to "NO AC POWER" */
11640Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
11650Sstevel@tonic-gate "NO AC POWER");
11660Sstevel@tonic-gate if (status != PSVC_SUCCESS)
11670Sstevel@tonic-gate return (status);
11680Sstevel@tonic-gate /*
11690Sstevel@tonic-gate * Set this state so that the FSP Fault LED lights
11700Sstevel@tonic-gate * when there is no AC Power to the power supply.
11710Sstevel@tonic-gate */
11720Sstevel@tonic-gate status = psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR,
11730Sstevel@tonic-gate PSVC_ERROR);
11740Sstevel@tonic-gate if (status != PSVC_SUCCESS)
11750Sstevel@tonic-gate return (status);
11760Sstevel@tonic-gate
11770Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
11780Sstevel@tonic-gate "NO AC POWER");
11790Sstevel@tonic-gate if (status != PSVC_SUCCESS)
11800Sstevel@tonic-gate return (status);
11810Sstevel@tonic-gate
11820Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s AC UNAVAILABLE"), id);
11830Sstevel@tonic-gate
11840Sstevel@tonic-gate /* Set fault sensor states to "" */
11850Sstevel@tonic-gate for (i = 0; i < sensor_count; ++i) {
11860Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
11870Sstevel@tonic-gate &sensor_id, PSVC_DEV_FAULT_SENSOR, i);
11880Sstevel@tonic-gate if (status != PSVC_SUCCESS)
11890Sstevel@tonic-gate return (status);
11900Sstevel@tonic-gate
11910Sstevel@tonic-gate status = psvc_set_attr(hdlp, sensor_id,
11920Sstevel@tonic-gate PSVC_FAULTID_ATTR, "");
11930Sstevel@tonic-gate if (status != PSVC_SUCCESS)
11940Sstevel@tonic-gate return (status);
11950Sstevel@tonic-gate }
11960Sstevel@tonic-gate }
11970Sstevel@tonic-gate
11980Sstevel@tonic-gate /* Power cord is plugged in */
11990Sstevel@tonic-gate if ((!unplugged) && (strcmp(state, "NO AC POWER") == 0)) {
12000Sstevel@tonic-gate /* Default the state to "OK" */
12010Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
12020Sstevel@tonic-gate PSVC_OK);
12030Sstevel@tonic-gate if (status != PSVC_SUCCESS)
12040Sstevel@tonic-gate return (status);
12050Sstevel@tonic-gate /* Default the PS_LOGICAL_STATE to "OK" */
12060Sstevel@tonic-gate status = psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR,
12070Sstevel@tonic-gate PSVC_OK);
12080Sstevel@tonic-gate if (status != PSVC_SUCCESS)
12090Sstevel@tonic-gate return (status);
12100Sstevel@tonic-gate /* Display message */
12110Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s AC AVAILABLE"), id);
12120Sstevel@tonic-gate }
12130Sstevel@tonic-gate
12140Sstevel@tonic-gate return (status);
12150Sstevel@tonic-gate }
12160Sstevel@tonic-gate
12170Sstevel@tonic-gate int32_t
psvc_init_ps_presence(psvc_opaque_t hdlp,char * id)12180Sstevel@tonic-gate psvc_init_ps_presence(psvc_opaque_t hdlp, char *id)
12190Sstevel@tonic-gate {
12200Sstevel@tonic-gate int err;
12210Sstevel@tonic-gate int instance;
12220Sstevel@tonic-gate boolean_t presence;
12230Sstevel@tonic-gate
12240Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
12250Sstevel@tonic-gate err |= psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence);
12260Sstevel@tonic-gate ps_prev_present[instance] = ps_present[instance] = presence;
12270Sstevel@tonic-gate return (err);
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate
12300Sstevel@tonic-gate int32_t
psvc_ps_monitor_policy_0(psvc_opaque_t hdlp,char * id)12310Sstevel@tonic-gate psvc_ps_monitor_policy_0(psvc_opaque_t hdlp, char *id)
12320Sstevel@tonic-gate {
12330Sstevel@tonic-gate int err;
12340Sstevel@tonic-gate int instance;
12350Sstevel@tonic-gate static int failed_last_time[2] = {0, 0};
1236958Sjfrank int retry;
12370Sstevel@tonic-gate
12380Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
12390Sstevel@tonic-gate if (err != PSVC_SUCCESS)
12400Sstevel@tonic-gate return (err);
12410Sstevel@tonic-gate
12420Sstevel@tonic-gate /* copy current presence to previous presence */
12430Sstevel@tonic-gate ps_prev_present[instance] = ps_present[instance];
12440Sstevel@tonic-gate
1245958Sjfrank retry = 0;
1246958Sjfrank do {
1247958Sjfrank if (retry)
1248958Sjfrank (void) sleep(retry_sleep_pshp);
1249958Sjfrank /* Get new presence */
1250958Sjfrank err = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR,
1251958Sjfrank &ps_present[instance]);
1252958Sjfrank if (err != PSVC_SUCCESS)
1253958Sjfrank goto out;
1254958Sjfrank retry++;
1255958Sjfrank } while ((retry < n_retry_pshp) &&
1256958Sjfrank (ps_present[instance] != ps_prev_present[instance]));
12570Sstevel@tonic-gate
12580Sstevel@tonic-gate /* Sustained Hotplug detected */
12590Sstevel@tonic-gate if (ps_present[instance] != ps_prev_present[instance]) {
12600Sstevel@tonic-gate err = handle_ps_hotplug(hdlp, id, ps_present[instance]);
12610Sstevel@tonic-gate return (err);
12620Sstevel@tonic-gate }
12630Sstevel@tonic-gate
12640Sstevel@tonic-gate /* If our power supply is not present, we're done */
12650Sstevel@tonic-gate if (!ps_present[instance])
12660Sstevel@tonic-gate return (PSVC_SUCCESS);
12670Sstevel@tonic-gate
12680Sstevel@tonic-gate err = check_i2c_access(hdlp, id);
12690Sstevel@tonic-gate if (err != PSVC_SUCCESS) {
12700Sstevel@tonic-gate /* Quickie hotplug */
12710Sstevel@tonic-gate if (ps_present[instance] == PSVC_PRESENT &&
12720Sstevel@tonic-gate ps_prev_present[instance] == PSVC_PRESENT) {
12730Sstevel@tonic-gate syslog(LOG_ERR, "Device %s removed", id);
12740Sstevel@tonic-gate /* Reset prev_failed information */
12750Sstevel@tonic-gate ps_reset_prev_failed(instance);
12760Sstevel@tonic-gate ps_prev_present[instance] = 0;
12770Sstevel@tonic-gate handle_ps_hotplug(hdlp, id, ps_present[instance]);
12780Sstevel@tonic-gate /* We ignore the error on a quickie hotplug */
12790Sstevel@tonic-gate return (PSVC_SUCCESS);
12800Sstevel@tonic-gate }
12810Sstevel@tonic-gate /* There was an actual i2c access error */
12820Sstevel@tonic-gate goto out;
12830Sstevel@tonic-gate }
12840Sstevel@tonic-gate
12850Sstevel@tonic-gate err = check_ps_state(hdlp, id);
12860Sstevel@tonic-gate if (err != PSVC_SUCCESS)
12870Sstevel@tonic-gate goto out;
12880Sstevel@tonic-gate
12890Sstevel@tonic-gate failed_last_time[instance] = 0;
12900Sstevel@tonic-gate return (err);
12910Sstevel@tonic-gate
12920Sstevel@tonic-gate out:
12930Sstevel@tonic-gate if (! failed_last_time[instance]) {
12940Sstevel@tonic-gate /*
12950Sstevel@tonic-gate * We ignore the error condition the first time thru
12960Sstevel@tonic-gate * because the PS could have been removed after (or
12970Sstevel@tonic-gate * during) our call to check_ps_hotplug().
12980Sstevel@tonic-gate *
12990Sstevel@tonic-gate * If the problem is still there the next time, then
13000Sstevel@tonic-gate * we'll raise a flag.
13010Sstevel@tonic-gate *
13020Sstevel@tonic-gate * The instance determines which power supply the policy
13030Sstevel@tonic-gate * errored on. For instance PS0 might have failed and then
13040Sstevel@tonic-gate * PS1 might have failed, but we'll display a warning
13050Sstevel@tonic-gate * even though there might not be anything actually wrong.
13060Sstevel@tonic-gate * The instance keeps track of which failure occurred so
13070Sstevel@tonic-gate * we warn on the corresponding occurrence of errors.
13080Sstevel@tonic-gate */
13090Sstevel@tonic-gate failed_last_time[instance] = 1;
13100Sstevel@tonic-gate return (PSVC_SUCCESS);
13110Sstevel@tonic-gate }
13120Sstevel@tonic-gate return (err);
13130Sstevel@tonic-gate }
13140Sstevel@tonic-gate
13150Sstevel@tonic-gate static int
light_disk_fault_leds(psvc_opaque_t hdlp,char * id,boolean_t disk_presence)13160Sstevel@tonic-gate light_disk_fault_leds(psvc_opaque_t hdlp, char *id, boolean_t disk_presence)
13170Sstevel@tonic-gate {
13180Sstevel@tonic-gate int err;
13190Sstevel@tonic-gate int bit_nums[MAX_DISKS] = {6, 7};
13200Sstevel@tonic-gate uint8_t led_masks[MAX_DISKS] = {0x40, 0x80};
13210Sstevel@tonic-gate int instance;
13220Sstevel@tonic-gate int bit_value;
13230Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
13240Sstevel@tonic-gate uint8_t byte;
13250Sstevel@tonic-gate
13260Sstevel@tonic-gate if (disk_presence != PSVC_PRESENT)
13270Sstevel@tonic-gate return (PSVC_SUCCESS);
13280Sstevel@tonic-gate
13290Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
13300Sstevel@tonic-gate if (err != PSVC_SUCCESS)
13310Sstevel@tonic-gate return (err);
13320Sstevel@tonic-gate
13330Sstevel@tonic-gate err = psvc_get_attr(hdlp, "DISK_PORT", PSVC_GPIO_VALUE_ATTR,
13340Sstevel@tonic-gate &byte);
13350Sstevel@tonic-gate if (err != PSVC_SUCCESS)
13360Sstevel@tonic-gate return (err);
13370Sstevel@tonic-gate
13380Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
13390Sstevel@tonic-gate if (err != PSVC_SUCCESS)
13400Sstevel@tonic-gate return (err);
13410Sstevel@tonic-gate if (strcmp(state, PSVC_OK) == 0 || strcmp(state, "") == 0) { /* OK */
13420Sstevel@tonic-gate if (byte & led_masks[instance]) { /* Led is OFF */
13430Sstevel@tonic-gate return (err); /* Done. */
13440Sstevel@tonic-gate } else { /* Led is ON, Turn if OFF */
13450Sstevel@tonic-gate bit_value = 1; /* Active Low */
13460Sstevel@tonic-gate err = pcf8574_write_bit(hdlp, "DISK_PORT",
13470Sstevel@tonic-gate bit_nums[instance], bit_value,
13480Sstevel@tonic-gate DISKBP_MUST_BE_1);
13490Sstevel@tonic-gate if (err != PSVC_SUCCESS)
13500Sstevel@tonic-gate return (err);
13510Sstevel@tonic-gate }
13520Sstevel@tonic-gate } else { /* Disk is NOT OK */
13530Sstevel@tonic-gate if (byte & led_masks[instance]) { /* Led is OFF, Turn it ON */
13540Sstevel@tonic-gate bit_value = 0; /* Active Low */
13550Sstevel@tonic-gate err = pcf8574_write_bit(hdlp, "DISK_PORT",
13560Sstevel@tonic-gate bit_nums[instance], bit_value,
13570Sstevel@tonic-gate DISKBP_MUST_BE_1);
13580Sstevel@tonic-gate if (err != PSVC_SUCCESS)
13590Sstevel@tonic-gate return (err);
13600Sstevel@tonic-gate } else {
13610Sstevel@tonic-gate return (err); /* Done. */
13620Sstevel@tonic-gate }
13630Sstevel@tonic-gate }
13640Sstevel@tonic-gate return (err);
13650Sstevel@tonic-gate }
13660Sstevel@tonic-gate
13670Sstevel@tonic-gate int
verify_disk_wwn(char * wwn)13680Sstevel@tonic-gate verify_disk_wwn(char *wwn)
13690Sstevel@tonic-gate {
13700Sstevel@tonic-gate HBA_PORTATTRIBUTES hbaPortAttrs, discPortAttrs;
13710Sstevel@tonic-gate HBA_HANDLE handle;
13720Sstevel@tonic-gate HBA_STATUS status;
13730Sstevel@tonic-gate HBA_ADAPTERATTRIBUTES hbaAttrs;
13740Sstevel@tonic-gate HBA_UINT32 numberOfAdapters, hbaCount, hbaPort, discPort;
13750Sstevel@tonic-gate char adaptername[256];
13760Sstevel@tonic-gate char vwwn[WWN_SIZE * 2];
13770Sstevel@tonic-gate char OSDeviceName[PATH_MAX + 1];
13780Sstevel@tonic-gate int count, linksize;
13790Sstevel@tonic-gate
13800Sstevel@tonic-gate /* Load common lib */
13810Sstevel@tonic-gate status = HBA_LoadLibrary();
13820Sstevel@tonic-gate if (status != HBA_STATUS_OK) {
13830Sstevel@tonic-gate (void) HBA_FreeLibrary();
13840Sstevel@tonic-gate return (HBA_STATUS_ERROR);
13850Sstevel@tonic-gate }
13860Sstevel@tonic-gate
13870Sstevel@tonic-gate /*
13880Sstevel@tonic-gate * Since devfs can store multiple instances
13890Sstevel@tonic-gate * of a target the validity of the WWN of a disk is
13900Sstevel@tonic-gate * verified with an actual probe of internal disks
13910Sstevel@tonic-gate */
13920Sstevel@tonic-gate
13930Sstevel@tonic-gate /* Cycle through FC-AL Adapters and search for WWN */
13940Sstevel@tonic-gate numberOfAdapters = HBA_GetNumberOfAdapters();
13950Sstevel@tonic-gate for (hbaCount = 0; hbaCount < numberOfAdapters; hbaCount++) {
13960Sstevel@tonic-gate if ((status = HBA_GetAdapterName(hbaCount, adaptername)) !=
13970Sstevel@tonic-gate HBA_STATUS_OK)
13980Sstevel@tonic-gate continue;
13990Sstevel@tonic-gate
14000Sstevel@tonic-gate handle = HBA_OpenAdapter(adaptername);
14010Sstevel@tonic-gate if (handle == 0)
14020Sstevel@tonic-gate continue;
14030Sstevel@tonic-gate
14040Sstevel@tonic-gate /* Get Adapter Attributes */
14050Sstevel@tonic-gate if ((status = HBA_GetAdapterAttributes(handle,
14060Sstevel@tonic-gate &hbaAttrs)) != HBA_STATUS_OK) {
14070Sstevel@tonic-gate HBA_CloseAdapter(handle);
14080Sstevel@tonic-gate continue;
14090Sstevel@tonic-gate }
14100Sstevel@tonic-gate
14110Sstevel@tonic-gate /* Get Adapter's Port Attributes */
14120Sstevel@tonic-gate for (hbaPort = 0;
14130Sstevel@tonic-gate hbaPort < hbaAttrs.NumberOfPorts; hbaPort++) {
14140Sstevel@tonic-gate if ((status = HBA_GetAdapterPortAttributes(handle,
14150Sstevel@tonic-gate hbaPort, &hbaPortAttrs)) != HBA_STATUS_OK)
14160Sstevel@tonic-gate continue;
14170Sstevel@tonic-gate
14180Sstevel@tonic-gate /*
14190Sstevel@tonic-gate * Verify whether this is onboard controller.
14200Sstevel@tonic-gate * HBAAPI provides path of symbol link to
14210Sstevel@tonic-gate * to the qlc node therefore readlink() is
14220Sstevel@tonic-gate * needed to obtain hard link
14230Sstevel@tonic-gate */
14240Sstevel@tonic-gate linksize = readlink(hbaPortAttrs.OSDeviceName,
14250Sstevel@tonic-gate OSDeviceName, PATH_MAX);
14260Sstevel@tonic-gate
14270Sstevel@tonic-gate /*
14280Sstevel@tonic-gate * If readlink does not return size of onboard
14290Sstevel@tonic-gate * controller than don't bother checking device
14300Sstevel@tonic-gate */
14310Sstevel@tonic-gate if ((linksize + 1) != sizeof (ONBOARD_CONTR))
14320Sstevel@tonic-gate continue;
14330Sstevel@tonic-gate
14340Sstevel@tonic-gate OSDeviceName[linksize] = '\0';
14350Sstevel@tonic-gate if (strcmp(OSDeviceName, ONBOARD_CONTR) != 0)
14360Sstevel@tonic-gate continue;
14370Sstevel@tonic-gate
14380Sstevel@tonic-gate /* Get Discovered Port Attributes */
14390Sstevel@tonic-gate for (discPort = 0;
14400Sstevel@tonic-gate discPort < hbaPortAttrs.NumberofDiscoveredPorts;
14410Sstevel@tonic-gate discPort++) {
14420Sstevel@tonic-gate status = HBA_GetDiscoveredPortAttributes(
14430Sstevel@tonic-gate handle, hbaPort, discPort,
14440Sstevel@tonic-gate &discPortAttrs);
14450Sstevel@tonic-gate if (status != HBA_STATUS_OK)
14460Sstevel@tonic-gate continue;
14470Sstevel@tonic-gate
14480Sstevel@tonic-gate /* Get target info */
14490Sstevel@tonic-gate for (count = 0; count < WWN_SIZE; count++)
14500Sstevel@tonic-gate (void) sprintf(&vwwn[count * 2],
14510Sstevel@tonic-gate "%2.2x",
14520Sstevel@tonic-gate discPortAttrs.NodeWWN.wwn[count]);
14530Sstevel@tonic-gate
14540Sstevel@tonic-gate if (strcmp(wwn, vwwn) == 0) {
14550Sstevel@tonic-gate HBA_CloseAdapter(handle);
14560Sstevel@tonic-gate (void) HBA_FreeLibrary();
14570Sstevel@tonic-gate return (HBA_STATUS_OK);
14580Sstevel@tonic-gate }
14590Sstevel@tonic-gate
14600Sstevel@tonic-gate }
14610Sstevel@tonic-gate }
14620Sstevel@tonic-gate HBA_CloseAdapter(handle);
14630Sstevel@tonic-gate }
14640Sstevel@tonic-gate (void) HBA_FreeLibrary();
14650Sstevel@tonic-gate return (HBA_STATUS_ERROR_ILLEGAL_WWN);
14660Sstevel@tonic-gate }
14670Sstevel@tonic-gate
14680Sstevel@tonic-gate static int
light_disk_ok2remove_leds(psvc_opaque_t hdlp,boolean_t * disk_present)14690Sstevel@tonic-gate light_disk_ok2remove_leds(psvc_opaque_t hdlp, boolean_t *disk_present)
14700Sstevel@tonic-gate {
14710Sstevel@tonic-gate di_node_t node;
14720Sstevel@tonic-gate di_node_t root_node;
14730Sstevel@tonic-gate di_minor_t min_node;
14740Sstevel@tonic-gate int *prop;
14750Sstevel@tonic-gate int n;
14760Sstevel@tonic-gate int target;
14770Sstevel@tonic-gate int rv;
14780Sstevel@tonic-gate int disk_online = 0;
14790Sstevel@tonic-gate static int prev_online[MAX_DISKS] = {-1, -1};
14800Sstevel@tonic-gate int bit_nums[MAX_DISKS] = {4, 5};
14810Sstevel@tonic-gate int bit_val;
14820Sstevel@tonic-gate int count;
14830Sstevel@tonic-gate char *dev_path;
14840Sstevel@tonic-gate char wwn[WWN_SIZE * 2];
14850Sstevel@tonic-gate uchar_t *prop_wwn;
14860Sstevel@tonic-gate
14870Sstevel@tonic-gate root_node = di_init("/", DINFOCPYALL);
14880Sstevel@tonic-gate if (root_node == DI_NODE_NIL)
14890Sstevel@tonic-gate return (PSVC_FAILURE);
14900Sstevel@tonic-gate
14910Sstevel@tonic-gate for (node = di_drv_first_node(DISK_DRV, root_node);
14920Sstevel@tonic-gate node != DI_NODE_NIL;
14930Sstevel@tonic-gate node = di_drv_next_node(node)) {
14940Sstevel@tonic-gate n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "target", &prop);
14950Sstevel@tonic-gate if (n == -1)
14960Sstevel@tonic-gate continue;
14970Sstevel@tonic-gate target = *prop;
14980Sstevel@tonic-gate if (target < 0 || target > 1)
14990Sstevel@tonic-gate continue;
15000Sstevel@tonic-gate
15010Sstevel@tonic-gate if (! disk_present[target])
15020Sstevel@tonic-gate continue;
15030Sstevel@tonic-gate
15040Sstevel@tonic-gate dev_path = di_devfs_path(node);
15050Sstevel@tonic-gate if (memcmp(dev_path, QLC_NODE, (sizeof (QLC_NODE) - 1)) != 0) {
15060Sstevel@tonic-gate /*
15070Sstevel@tonic-gate * This isn't our FC-AL controller, so this
15080Sstevel@tonic-gate * must be an external disk on Loop B. Skip it.
15090Sstevel@tonic-gate */
15100Sstevel@tonic-gate di_devfs_path_free(dev_path);
15110Sstevel@tonic-gate continue;
15120Sstevel@tonic-gate }
15130Sstevel@tonic-gate di_devfs_path_free(dev_path);
15140Sstevel@tonic-gate
15150Sstevel@tonic-gate /*
15160Sstevel@tonic-gate * Verify if disk is valid by checking WWN
15170Sstevel@tonic-gate * because devfs retains stale data.
15180Sstevel@tonic-gate */
15190Sstevel@tonic-gate n = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
15200Sstevel@tonic-gate "node-wwn", &prop_wwn);
15210Sstevel@tonic-gate if (n == -1)
15220Sstevel@tonic-gate continue;
15230Sstevel@tonic-gate
15240Sstevel@tonic-gate for (count = 0; count < WWN_SIZE; count++)
15250Sstevel@tonic-gate (void) sprintf(&wwn[count * 2], "%2.2x",
15260Sstevel@tonic-gate prop_wwn[count]);
15270Sstevel@tonic-gate
15280Sstevel@tonic-gate n = verify_disk_wwn(wwn);
15290Sstevel@tonic-gate if (n == HBA_STATUS_ERROR_ILLEGAL_WWN)
15300Sstevel@tonic-gate continue;
15310Sstevel@tonic-gate
15320Sstevel@tonic-gate min_node = di_minor_next(node, DI_MINOR_NIL);
15330Sstevel@tonic-gate disk_online = (min_node != DI_MINOR_NIL);
1534*5510Sanbui if ((disk_online == 0) && (prev_online[target] == 1)) {
15350Sstevel@tonic-gate /* Light Led */
15360Sstevel@tonic-gate bit_val = 0;
15370Sstevel@tonic-gate rv = pcf8574_write_bit(hdlp, "DISK_PORT",
15380Sstevel@tonic-gate bit_nums[target], bit_val, DISKBP_MUST_BE_1);
15390Sstevel@tonic-gate if (rv != PSVC_SUCCESS)
15400Sstevel@tonic-gate goto done;
1541*5510Sanbui } else if ((prev_online[target] == 0) && (disk_online == 1)) {
15420Sstevel@tonic-gate /* Unlight Led */
15430Sstevel@tonic-gate bit_val = 1;
15440Sstevel@tonic-gate rv = pcf8574_write_bit(hdlp, "DISK_PORT",
15450Sstevel@tonic-gate bit_nums[target], bit_val, DISKBP_MUST_BE_1);
15460Sstevel@tonic-gate if (rv != PSVC_SUCCESS)
15470Sstevel@tonic-gate goto done;
15480Sstevel@tonic-gate }
15490Sstevel@tonic-gate if (disk_online != prev_online[target])
15500Sstevel@tonic-gate prev_online[target] = disk_online;
15510Sstevel@tonic-gate }
15520Sstevel@tonic-gate done:
15530Sstevel@tonic-gate di_fini(root_node);
15540Sstevel@tonic-gate return (rv);
15550Sstevel@tonic-gate }
15560Sstevel@tonic-gate
15570Sstevel@tonic-gate static int
check_disk_fault(psvc_opaque_t hdlp,char * id,boolean_t disk_presence)15580Sstevel@tonic-gate check_disk_fault(psvc_opaque_t hdlp, char *id, boolean_t disk_presence)
15590Sstevel@tonic-gate {
15600Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
15610Sstevel@tonic-gate int32_t fault_on = 0;
15620Sstevel@tonic-gate char *sensor_id;
15630Sstevel@tonic-gate char disk_state[PSVC_MAX_STR_LEN];
15640Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
15650Sstevel@tonic-gate char fault[PSVC_MAX_STR_LEN];
15660Sstevel@tonic-gate boolean_t change_of_state = 0;
15670Sstevel@tonic-gate
15680Sstevel@tonic-gate if (disk_presence != PSVC_PRESENT)
15690Sstevel@tonic-gate return (PSVC_SUCCESS);
15700Sstevel@tonic-gate
15710Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, disk_state);
15720Sstevel@tonic-gate if (status != PSVC_SUCCESS)
15730Sstevel@tonic-gate return (status);
15740Sstevel@tonic-gate
15750Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
15760Sstevel@tonic-gate &sensor_id, PSVC_DEV_FAULT_SENSOR, 0);
15770Sstevel@tonic-gate if (status != PSVC_SUCCESS)
15780Sstevel@tonic-gate return (status);
15790Sstevel@tonic-gate
15800Sstevel@tonic-gate status = psvc_get_attr(hdlp, sensor_id, PSVC_SWITCH_STATE_ATTR, state);
15810Sstevel@tonic-gate if (status != PSVC_SUCCESS)
15820Sstevel@tonic-gate return (status);
15830Sstevel@tonic-gate
15840Sstevel@tonic-gate /* Fault detected */
15850Sstevel@tonic-gate if (strcmp(state, PSVC_SWITCH_ON) == 0) {
15860Sstevel@tonic-gate strlcpy(state, PSVC_ERROR, sizeof (state));
15870Sstevel@tonic-gate strlcpy(fault, PSVC_GEN_FAULT, sizeof (fault));
15880Sstevel@tonic-gate fault_on = 1;
15890Sstevel@tonic-gate } else { /* No fault detected */
15900Sstevel@tonic-gate if (strcmp(disk_state, PSVC_OK) != 0)
15910Sstevel@tonic-gate change_of_state = 1;
15920Sstevel@tonic-gate strlcpy(state, PSVC_OK, sizeof (state));
15930Sstevel@tonic-gate strlcpy(fault, PSVC_NO_FAULT, sizeof (fault));
15940Sstevel@tonic-gate }
15950Sstevel@tonic-gate
15960Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
15970Sstevel@tonic-gate if (status != PSVC_SUCCESS)
15980Sstevel@tonic-gate return (status);
15990Sstevel@tonic-gate
16000Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
16010Sstevel@tonic-gate if (status != PSVC_SUCCESS)
16020Sstevel@tonic-gate return (status);
16030Sstevel@tonic-gate
16040Sstevel@tonic-gate if (fault_on) {
16050Sstevel@tonic-gate syslog(LOG_ERR, gettext("Fault detected: %s"), id);
16060Sstevel@tonic-gate
16070Sstevel@tonic-gate } else {
16080Sstevel@tonic-gate if (change_of_state)
16090Sstevel@tonic-gate syslog(LOG_ERR, gettext("Notice: %s okay"), id);
16100Sstevel@tonic-gate }
16110Sstevel@tonic-gate return (PSVC_SUCCESS);
16120Sstevel@tonic-gate }
16130Sstevel@tonic-gate
16140Sstevel@tonic-gate static int
check_disk_hotplug(psvc_opaque_t hdlp,char * id,boolean_t * disk_presence,int disk_instance)16150Sstevel@tonic-gate check_disk_hotplug(psvc_opaque_t hdlp, char *id, boolean_t *disk_presence,
16160Sstevel@tonic-gate int disk_instance)
16170Sstevel@tonic-gate {
16180Sstevel@tonic-gate boolean_t presence;
16190Sstevel@tonic-gate boolean_t previous_presence;
16200Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
16210Sstevel@tonic-gate char label[PSVC_MAX_STR_LEN];
16220Sstevel@tonic-gate uint8_t disk_leds[MAX_DISKS][2] = {{4, 6}, {5, 7}};
1623958Sjfrank int retry;
16240Sstevel@tonic-gate
16250Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR,
16260Sstevel@tonic-gate &previous_presence);
16270Sstevel@tonic-gate if (status != PSVC_SUCCESS)
16280Sstevel@tonic-gate return (status);
16290Sstevel@tonic-gate
1630958Sjfrank retry = 0;
1631958Sjfrank do {
1632958Sjfrank if (retry)
1633958Sjfrank (void) sleep(retry_sleep_diskhp);
1634958Sjfrank status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR,
1635958Sjfrank &presence);
1636958Sjfrank if (status != PSVC_SUCCESS)
1637958Sjfrank return (status);
1638958Sjfrank retry++;
1639958Sjfrank } while ((retry < n_retry_diskhp) &&
1640958Sjfrank (presence != previous_presence));
1641958Sjfrank
16420Sstevel@tonic-gate *disk_presence = presence;
16430Sstevel@tonic-gate
16440Sstevel@tonic-gate if (presence != previous_presence) {
16450Sstevel@tonic-gate char parent_path[PICL_PROPNAMELEN_MAX];
16460Sstevel@tonic-gate picl_nodehdl_t child_node;
16470Sstevel@tonic-gate
16480Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
16490Sstevel@tonic-gate if (status != PSVC_SUCCESS)
16500Sstevel@tonic-gate return (status);
16510Sstevel@tonic-gate
16520Sstevel@tonic-gate /* return parent path and node for an object */
16530Sstevel@tonic-gate psvcplugin_lookup(id, parent_path, &child_node);
16540Sstevel@tonic-gate
16550Sstevel@tonic-gate if (presence == PSVC_PRESENT) {
16560Sstevel@tonic-gate picl_nodehdl_t parent_node;
16570Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
16580Sstevel@tonic-gate char fault[PSVC_MAX_STR_LEN];
16590Sstevel@tonic-gate
16600Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s inserted"), label);
16610Sstevel@tonic-gate strlcpy(state, PSVC_OK, sizeof (state));
16620Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
16630Sstevel@tonic-gate state);
16640Sstevel@tonic-gate if (status != PSVC_SUCCESS)
16650Sstevel@tonic-gate return (status);
16660Sstevel@tonic-gate
16670Sstevel@tonic-gate strlcpy(fault, PSVC_NO_FAULT, sizeof (fault));
16680Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
16690Sstevel@tonic-gate fault);
16700Sstevel@tonic-gate if (status != PSVC_SUCCESS) {
16710Sstevel@tonic-gate return (status);
16720Sstevel@tonic-gate }
16730Sstevel@tonic-gate
16740Sstevel@tonic-gate status = ptree_get_node_by_path(parent_path,
16750Sstevel@tonic-gate &parent_node);
16760Sstevel@tonic-gate if (status != PICL_SUCCESS)
16770Sstevel@tonic-gate return (PSVC_FAILURE);
16780Sstevel@tonic-gate status = ptree_add_node(parent_node, child_node);
16790Sstevel@tonic-gate if (status != PICL_SUCCESS)
16800Sstevel@tonic-gate return (PSVC_FAILURE);
16810Sstevel@tonic-gate } else {
16820Sstevel@tonic-gate /*
16830Sstevel@tonic-gate * Disk Removed so we need to turn off these LEDs:
16840Sstevel@tonic-gate * DISKx_FLT_LED
16850Sstevel@tonic-gate * DISKx_REMOVE_LED
16860Sstevel@tonic-gate */
16870Sstevel@tonic-gate int i;
16880Sstevel@tonic-gate int bit_val = 1; /* Active Low */
16890Sstevel@tonic-gate for (i = 0; i < 2; i++) {
16900Sstevel@tonic-gate status = pcf8574_write_bit(hdlp, "DISK_PORT",
16910Sstevel@tonic-gate disk_leds[disk_instance][i], bit_val,
16920Sstevel@tonic-gate DISKBP_MUST_BE_1);
16930Sstevel@tonic-gate if (status != PSVC_SUCCESS)
16940Sstevel@tonic-gate syslog(LOG_ERR, "Failed in turning off"
16950Sstevel@tonic-gate " %d's LEDs", id);
16960Sstevel@tonic-gate }
16970Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s removed"), label);
16980Sstevel@tonic-gate ptree_delete_node(child_node);
16990Sstevel@tonic-gate }
17000Sstevel@tonic-gate }
17010Sstevel@tonic-gate
17020Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence);
17030Sstevel@tonic-gate if (status != PSVC_SUCCESS)
17040Sstevel@tonic-gate return (status);
17050Sstevel@tonic-gate
17060Sstevel@tonic-gate return (status);
17070Sstevel@tonic-gate }
17080Sstevel@tonic-gate
17090Sstevel@tonic-gate int32_t
psvc_disk_monitor_policy_0(psvc_opaque_t hdlp,char * id)17100Sstevel@tonic-gate psvc_disk_monitor_policy_0(psvc_opaque_t hdlp, char *id)
17110Sstevel@tonic-gate {
17120Sstevel@tonic-gate int rv, err, i;
17130Sstevel@tonic-gate char *disks[MAX_DISKS] = {"DISK0", "DISK1"};
17140Sstevel@tonic-gate int saved_errno = 0;
17150Sstevel@tonic-gate boolean_t disk_present[MAX_DISKS] = {0, 0};
17160Sstevel@tonic-gate
17170Sstevel@tonic-gate for (i = 0; i < MAX_DISKS; i++) {
17180Sstevel@tonic-gate err = check_disk_hotplug(hdlp, disks[i], &disk_present[i], i);
17190Sstevel@tonic-gate if (err) saved_errno = errno;
17200Sstevel@tonic-gate rv = err;
17210Sstevel@tonic-gate
17220Sstevel@tonic-gate err = check_disk_fault(hdlp, disks[i], disk_present[i]);
17230Sstevel@tonic-gate if (err) saved_errno = errno;
17240Sstevel@tonic-gate rv |= err;
17250Sstevel@tonic-gate
17260Sstevel@tonic-gate err |= light_disk_fault_leds(hdlp, disks[i], disk_present[i]);
17270Sstevel@tonic-gate if (err) saved_errno = errno;
17280Sstevel@tonic-gate rv |= err;
17290Sstevel@tonic-gate }
17300Sstevel@tonic-gate
17310Sstevel@tonic-gate err = light_disk_ok2remove_leds(hdlp, disk_present);
17320Sstevel@tonic-gate if (err) saved_errno = errno;
17330Sstevel@tonic-gate rv |= err;
17340Sstevel@tonic-gate
17350Sstevel@tonic-gate errno = saved_errno;
17360Sstevel@tonic-gate return (rv);
17370Sstevel@tonic-gate }
17380Sstevel@tonic-gate
17390Sstevel@tonic-gate /*
17400Sstevel@tonic-gate * Read in temperature thresholds from FRU Prom and update the
17410Sstevel@tonic-gate * default values.
17420Sstevel@tonic-gate */
17430Sstevel@tonic-gate
17440Sstevel@tonic-gate #define START_OFFSET 0x1800 /* Last 2K of SEEPROM */
17450Sstevel@tonic-gate #define NUM_SEG_OFFSET 0x1805 /* Number of segments */
17460Sstevel@tonic-gate #define SEG_TABLE_OFFSET 0x1806 /* Segment description tables */
17470Sstevel@tonic-gate
17480Sstevel@tonic-gate static int32_t
read_sc_segment(psvc_opaque_t hdlp,char * id,char * fru_id,int offset)17490Sstevel@tonic-gate read_sc_segment(psvc_opaque_t hdlp, char *id, char *fru_id, int offset)
17500Sstevel@tonic-gate {
17510Sstevel@tonic-gate static int thresh_names[] = {
17520Sstevel@tonic-gate PSVC_HW_LO_SHUT_ATTR,
17530Sstevel@tonic-gate PSVC_LO_SHUT_ATTR,
17540Sstevel@tonic-gate PSVC_LO_WARN_ATTR,
17550Sstevel@tonic-gate PSVC_NOT_USED, /* LOW MODE */
17560Sstevel@tonic-gate PSVC_OPTIMAL_TEMP_ATTR,
17570Sstevel@tonic-gate PSVC_HI_WARN_ATTR,
17580Sstevel@tonic-gate PSVC_HI_SHUT_ATTR,
17590Sstevel@tonic-gate PSVC_HW_HI_SHUT_ATTR
17600Sstevel@tonic-gate };
17610Sstevel@tonic-gate int8_t amb_temp_array[8];
17620Sstevel@tonic-gate int i;
17630Sstevel@tonic-gate fru_info_t fru_info;
17640Sstevel@tonic-gate int err;
17650Sstevel@tonic-gate
17660Sstevel@tonic-gate fru_info.buf_start = offset + 8;
17670Sstevel@tonic-gate fru_info.buf = amb_temp_array;
17680Sstevel@tonic-gate fru_info.read_size = 8;
17690Sstevel@tonic-gate
17700Sstevel@tonic-gate err = psvc_get_attr(hdlp, fru_id, PSVC_FRU_INFO_ATTR, &fru_info);
17710Sstevel@tonic-gate if (err != PSVC_SUCCESS)
17720Sstevel@tonic-gate return (err);
17730Sstevel@tonic-gate
17740Sstevel@tonic-gate for (i = 0; i < 8; i++) {
17750Sstevel@tonic-gate int32_t temp = amb_temp_array[i];
17760Sstevel@tonic-gate if (thresh_names[i] == PSVC_NOT_USED)
17770Sstevel@tonic-gate continue;
17780Sstevel@tonic-gate err = psvc_set_attr(hdlp, id, thresh_names[i], &temp);
17790Sstevel@tonic-gate if (err != PSVC_SUCCESS)
17800Sstevel@tonic-gate return (err);
17810Sstevel@tonic-gate }
17820Sstevel@tonic-gate return (PSVC_SUCCESS);
17830Sstevel@tonic-gate }
17840Sstevel@tonic-gate
17850Sstevel@tonic-gate int32_t
update_disk_bp_temp_thresholds(psvc_opaque_t hdlp,char * id)17860Sstevel@tonic-gate update_disk_bp_temp_thresholds(psvc_opaque_t hdlp, char *id)
17870Sstevel@tonic-gate {
17880Sstevel@tonic-gate
17890Sstevel@tonic-gate char *fru;
17900Sstevel@tonic-gate fru_info_t fru_info;
17910Sstevel@tonic-gate int16_t seg_offset;
17920Sstevel@tonic-gate int8_t byte;
17930Sstevel@tonic-gate int8_t seg_count;
17940Sstevel@tonic-gate char seg_name[2];
17950Sstevel@tonic-gate int current_offset, i, err;
17960Sstevel@tonic-gate
17970Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &fru, PSVC_FRU, 0);
17980Sstevel@tonic-gate if (err != PSVC_SUCCESS)
17990Sstevel@tonic-gate return (err);
18000Sstevel@tonic-gate
18010Sstevel@tonic-gate /* Sanity Check */
18020Sstevel@tonic-gate fru_info.buf_start = START_OFFSET;
18030Sstevel@tonic-gate fru_info.buf = &byte;
18040Sstevel@tonic-gate fru_info.read_size = 1;
18050Sstevel@tonic-gate
18060Sstevel@tonic-gate err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info);
18070Sstevel@tonic-gate if (err != PSVC_SUCCESS)
18080Sstevel@tonic-gate return (err);
18090Sstevel@tonic-gate if (*fru_info.buf != 8) {
18100Sstevel@tonic-gate syslog(LOG_ERR, "Notice: FRU Prom %s not programmed", fru);
18110Sstevel@tonic-gate }
18120Sstevel@tonic-gate /* Should do CRC Check on fru */
18130Sstevel@tonic-gate
18140Sstevel@tonic-gate /* Get Segment Count */
18150Sstevel@tonic-gate fru_info.buf_start = NUM_SEG_OFFSET;
18160Sstevel@tonic-gate fru_info.buf = &seg_count;
18170Sstevel@tonic-gate fru_info.read_size = 1;
18180Sstevel@tonic-gate
18190Sstevel@tonic-gate err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info);
18200Sstevel@tonic-gate if (err != PSVC_SUCCESS)
18210Sstevel@tonic-gate return (err);
18220Sstevel@tonic-gate
18230Sstevel@tonic-gate current_offset = SEG_TABLE_OFFSET;
18240Sstevel@tonic-gate for (i = 0; i < seg_count; i++) {
18250Sstevel@tonic-gate fru_info.buf_start = current_offset;
18260Sstevel@tonic-gate fru_info.buf = seg_name;
18270Sstevel@tonic-gate fru_info.read_size = 2;
18280Sstevel@tonic-gate err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info);
18290Sstevel@tonic-gate if (err != PSVC_SUCCESS)
18300Sstevel@tonic-gate return (err);
18310Sstevel@tonic-gate
18320Sstevel@tonic-gate if (memcmp(seg_name, "SC", 2) == 0) {
18330Sstevel@tonic-gate current_offset += 6; /* Skip over description */
18340Sstevel@tonic-gate fru_info.buf_start = current_offset;
18350Sstevel@tonic-gate fru_info.buf = (char *)&seg_offset;
18360Sstevel@tonic-gate fru_info.read_size = 2;
18370Sstevel@tonic-gate psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
18380Sstevel@tonic-gate &fru_info);
18390Sstevel@tonic-gate return (read_sc_segment(hdlp, id, fru, seg_offset));
18400Sstevel@tonic-gate }
18410Sstevel@tonic-gate current_offset += 10;
18420Sstevel@tonic-gate }
18430Sstevel@tonic-gate
18440Sstevel@tonic-gate return (PSVC_SUCCESS);
18450Sstevel@tonic-gate }
1846