17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
23*71e32251Sanbui * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * Cherrystone platform specific environment monitoring policies
297c478bd9Sstevel@tonic-gate */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate #include <syslog.h>
327c478bd9Sstevel@tonic-gate #include <unistd.h>
337c478bd9Sstevel@tonic-gate #include <stdio.h>
347c478bd9Sstevel@tonic-gate #include <libintl.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <stdlib.h>
377c478bd9Sstevel@tonic-gate #include <errno.h>
387c478bd9Sstevel@tonic-gate #include <fcntl.h>
397c478bd9Sstevel@tonic-gate #include <sys/types.h>
407c478bd9Sstevel@tonic-gate #include <sys/time.h>
417c478bd9Sstevel@tonic-gate #include <sys/time_impl.h>
427c478bd9Sstevel@tonic-gate #include <sys/signal.h>
437c478bd9Sstevel@tonic-gate #include <sys/devctl.h>
447c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
457c478bd9Sstevel@tonic-gate #include <libdevice.h>
467c478bd9Sstevel@tonic-gate #include <picl.h>
477c478bd9Sstevel@tonic-gate #include <picltree.h>
487c478bd9Sstevel@tonic-gate #include <sys/i2c/clients/i2c_client.h>
497c478bd9Sstevel@tonic-gate #include <hbaapi.h>
507c478bd9Sstevel@tonic-gate #include <limits.h>
51298b7f4cSjfrank #include <sys/systeminfo.h>
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate #include <psvc_objects.h>
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate /* Device paths for power supply hotplug handling */
567c478bd9Sstevel@tonic-gate #define SEG5_ADDR 0x30
577c478bd9Sstevel@tonic-gate #define EBUS_DEV_NAME "/devices/pci@9,700000/ebus@1/"
58159cf8a6Swesolows #define SEG5_DEV_NAME EBUS_DEV_NAME "i2c@1,30/"
59159cf8a6Swesolows #define SEG5_ADDR_DEV_FMT EBUS_DEV_NAME "i2c@1,%x:devctl"
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate #define QLC_NODE "/pci@9,600000/SUNW,qlc@2"
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate #define DISK_DRV "ssd"
647c478bd9Sstevel@tonic-gate #define MAX_DISKS 2
657c478bd9Sstevel@tonic-gate #define WWN_SIZE 8
667c478bd9Sstevel@tonic-gate #define ONBOARD_CONTR "../../devices/pci@9,600000/SUNW,qlc@2/fp@0,0:fc"
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate /* Bit masks so we don't "wedge" the inputs */
697c478bd9Sstevel@tonic-gate #define PCF8574_BIT_WRITE_VALUE(byte, bit, value)\
707c478bd9Sstevel@tonic-gate ((value << bit) | (byte & (~(0x01 << bit))))
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate #define PDB_MUST_BE_1 0xBF
737c478bd9Sstevel@tonic-gate #define PSU_MUST_BE_1 0x7F
747c478bd9Sstevel@tonic-gate #define DISKBP_MUST_BE_1 0x0F
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate #define PSVC_MAX_STR_LEN 32
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate #define PS_MAX_FAULT_SENSORS 3
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate /*
837c478bd9Sstevel@tonic-gate * Keep track of the power supply's fail status for reporting if/when
847c478bd9Sstevel@tonic-gate * they go good.
857c478bd9Sstevel@tonic-gate * ID's:
867c478bd9Sstevel@tonic-gate * O PSx_FAULT_SENSOR
877c478bd9Sstevel@tonic-gate * 1 Doesn't matter -- only need 0 to be PSx_FAULT_SENSOR
887c478bd9Sstevel@tonic-gate * 2 Doesn't matter
897c478bd9Sstevel@tonic-gate */
907c478bd9Sstevel@tonic-gate static char *ps_prev_id[2][3] =
917c478bd9Sstevel@tonic-gate {{NULL, NULL, NULL}, {NULL, NULL, NULL}};
927c478bd9Sstevel@tonic-gate static int ps_prev_failed[2][3] = {{0, 0, 0}, {0, 0, 0}};
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate * Keep track of the power supply's previous presence
967c478bd9Sstevel@tonic-gate * because PSVC doesn't do that for us.
977c478bd9Sstevel@tonic-gate */
987c478bd9Sstevel@tonic-gate static boolean_t ps_prev_present[2];
997c478bd9Sstevel@tonic-gate static boolean_t ps_present[2];
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate /* Local Routines for the environmental policies */
1027c478bd9Sstevel@tonic-gate static int ac_unplugged(psvc_opaque_t, char *);
1037c478bd9Sstevel@tonic-gate static int ac_power_check(psvc_opaque_t, char *, char *);
1047c478bd9Sstevel@tonic-gate
105298b7f4cSjfrank /*
106298b7f4cSjfrank * The I2C bus is noisy, and the state may be incorrectly reported as
107298b7f4cSjfrank * having changed. When the state changes, we attempt to confirm by
108298b7f4cSjfrank * retrying. If any retries indicate that the state has not changed, we
109298b7f4cSjfrank * assume the state change(s) were incorrect and the state has not changed.
110298b7f4cSjfrank * The following variables are used to store the tuneable values read in
111298b7f4cSjfrank * from the optional i2cparam.conf file for this shared object library.
112298b7f4cSjfrank */
113298b7f4cSjfrank static int n_retry_fan = PSVC_NUM_OF_RETRIES;
114298b7f4cSjfrank static int retry_sleep_fan = 1;
115298b7f4cSjfrank static int n_retry_ps_status = PSVC_NUM_OF_RETRIES;
116298b7f4cSjfrank static int retry_sleep_ps_status = 1;
117298b7f4cSjfrank static int n_retry_pshp = PSVC_NUM_OF_RETRIES;
118298b7f4cSjfrank static int retry_sleep_pshp = 1;
119298b7f4cSjfrank static int n_retry_diskhp = PSVC_NUM_OF_RETRIES;
120298b7f4cSjfrank static int retry_sleep_diskhp = 1;
121298b7f4cSjfrank static int n_retry_temp_shutdown = PSVC_NUM_OF_RETRIES;
122298b7f4cSjfrank static int retry_sleep_temp_shutdown = 1;
123298b7f4cSjfrank static int n_retry_fsp_fault = PSVC_NUM_OF_RETRIES;
124298b7f4cSjfrank static int retry_sleep_fsp_fault = 1;
125298b7f4cSjfrank
126298b7f4cSjfrank typedef struct {
127298b7f4cSjfrank int *pvar;
128298b7f4cSjfrank char *texttag;
129298b7f4cSjfrank } i2c_noise_param_t;
130298b7f4cSjfrank
131298b7f4cSjfrank static i2c_noise_param_t i2cparams[] = {
132298b7f4cSjfrank &n_retry_fan, "n_retry_fan",
133298b7f4cSjfrank &retry_sleep_fan, "retry_sleep_fan",
134298b7f4cSjfrank &n_retry_ps_status, "n_retry_ps_status",
135298b7f4cSjfrank &retry_sleep_ps_status, "retry_sleep_ps_status",
136298b7f4cSjfrank &n_retry_pshp, "n_retry_pshp",
137298b7f4cSjfrank &retry_sleep_pshp, "retry_sleep_pshp",
138298b7f4cSjfrank &n_retry_diskhp, "n_retry_diskhp",
139298b7f4cSjfrank &retry_sleep_diskhp, "retry_sleep_diskhp",
140298b7f4cSjfrank &n_retry_temp_shutdown, "n_retry_temp_shutdown",
141298b7f4cSjfrank &retry_sleep_temp_shutdown, "retry_sleep_temp_shutdown",
142298b7f4cSjfrank &n_retry_fsp_fault, "n_retry_fsp_fault",
143298b7f4cSjfrank &retry_sleep_fsp_fault, "retry_sleep_fsp_fault",
144298b7f4cSjfrank NULL, NULL
145298b7f4cSjfrank };
146298b7f4cSjfrank
147298b7f4cSjfrank #pragma init(i2cparams_load)
148298b7f4cSjfrank
149298b7f4cSjfrank static void
i2cparams_debug(i2c_noise_param_t * pi2cparams,char * platform,int usingDefaults)150298b7f4cSjfrank i2cparams_debug(i2c_noise_param_t *pi2cparams, char *platform,
151298b7f4cSjfrank int usingDefaults)
152298b7f4cSjfrank {
153298b7f4cSjfrank char s[128];
154298b7f4cSjfrank i2c_noise_param_t *p;
155298b7f4cSjfrank
156298b7f4cSjfrank if (!usingDefaults) {
157298b7f4cSjfrank (void) snprintf(s, sizeof (s),
158298b7f4cSjfrank "# Values from /usr/platform/%s/lib/i2cparam.conf\n",
159298b7f4cSjfrank platform);
160298b7f4cSjfrank syslog(LOG_WARNING, "%s", s);
161298b7f4cSjfrank } else {
162298b7f4cSjfrank /* no file - we're using the defaults */
163298b7f4cSjfrank (void) snprintf(s, sizeof (s),
164298b7f4cSjfrank "# No /usr/platform/%s/lib/i2cparam.conf file, using defaults\n",
165298b7f4cSjfrank platform);
166298b7f4cSjfrank }
167298b7f4cSjfrank (void) fputs(s, stdout);
168298b7f4cSjfrank p = pi2cparams;
169298b7f4cSjfrank while (p->pvar != NULL) {
170298b7f4cSjfrank (void) snprintf(s, sizeof (s), "%s %d\n", p->texttag,
171298b7f4cSjfrank *(p->pvar));
172298b7f4cSjfrank if (!usingDefaults)
173298b7f4cSjfrank syslog(LOG_WARNING, "%s", s);
174298b7f4cSjfrank (void) fputs(s, stdout);
175298b7f4cSjfrank p++;
176298b7f4cSjfrank }
177298b7f4cSjfrank }
178298b7f4cSjfrank
179298b7f4cSjfrank static void
i2cparams_load(void)180298b7f4cSjfrank i2cparams_load(void)
181298b7f4cSjfrank {
182298b7f4cSjfrank FILE *fp;
183298b7f4cSjfrank char filename[PATH_MAX];
184298b7f4cSjfrank char platform[64];
185298b7f4cSjfrank char s[128];
186298b7f4cSjfrank char var[128];
187298b7f4cSjfrank int val;
188298b7f4cSjfrank i2c_noise_param_t *p;
189298b7f4cSjfrank
190298b7f4cSjfrank if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
191298b7f4cSjfrank syslog(LOG_ERR, "sysinfo error %s\n", strerror(errno));
192298b7f4cSjfrank return;
193298b7f4cSjfrank }
194298b7f4cSjfrank (void) snprintf(filename, sizeof (filename),
195298b7f4cSjfrank "/usr/platform/%s/lib/i2cparam.conf", platform);
196298b7f4cSjfrank /* read thru the i2cparam.conf file and set variables */
197298b7f4cSjfrank if ((fp = fopen(filename, "r")) != NULL) {
198298b7f4cSjfrank while (fgets(s, sizeof (s), fp) != NULL) {
199298b7f4cSjfrank if (s[0] == '#') /* skip comment lines */
200298b7f4cSjfrank continue;
201298b7f4cSjfrank /* try to find a string match and get the value */
202298b7f4cSjfrank if (sscanf(s, "%127s %d", var, &val) != 2)
203298b7f4cSjfrank continue;
204298b7f4cSjfrank if (val < 1)
205298b7f4cSjfrank val = 1; /* clamp min value */
206298b7f4cSjfrank p = &(i2cparams[0]);
207298b7f4cSjfrank while (p->pvar != NULL) {
208298b7f4cSjfrank if (strncmp(p->texttag, var, sizeof (var)) ==
209298b7f4cSjfrank 0) {
210298b7f4cSjfrank *(p->pvar) = val;
211298b7f4cSjfrank break;
212298b7f4cSjfrank }
213298b7f4cSjfrank p++;
214298b7f4cSjfrank }
215298b7f4cSjfrank }
216298b7f4cSjfrank (void) fclose(fp);
217298b7f4cSjfrank }
218298b7f4cSjfrank /* output the values of the parameters */
219298b7f4cSjfrank i2cparams_debug(&(i2cparams[0]), platform, ((fp == NULL)? 1 : 0));
220298b7f4cSjfrank }
221298b7f4cSjfrank
2227c478bd9Sstevel@tonic-gate /*
2237c478bd9Sstevel@tonic-gate * Create an I2C device node.
2247c478bd9Sstevel@tonic-gate */
2257c478bd9Sstevel@tonic-gate static int
create_i2c_node(char * nd_name,char * nd_compat,int nd_nexi,int * nd_reg)2267c478bd9Sstevel@tonic-gate create_i2c_node(char *nd_name, char *nd_compat, int nd_nexi, int *nd_reg)
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate devctl_ddef_t ddef_hdl = NULL;
2297c478bd9Sstevel@tonic-gate devctl_hdl_t bus_hdl = NULL;
2307c478bd9Sstevel@tonic-gate devctl_hdl_t dev_hdl = NULL;
2317c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN];
2327c478bd9Sstevel@tonic-gate char dev_path[MAXPATHLEN];
2337c478bd9Sstevel@tonic-gate int rv = PSVC_FAILURE;
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), SEG5_ADDR_DEV_FMT, nd_nexi);
2367c478bd9Sstevel@tonic-gate bus_hdl = devctl_bus_acquire(buf, 0);
2377c478bd9Sstevel@tonic-gate if (bus_hdl == NULL)
2387c478bd9Sstevel@tonic-gate goto bad;
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate /* device definition properties */
2417c478bd9Sstevel@tonic-gate ddef_hdl = devctl_ddef_alloc(nd_name, 0);
2427c478bd9Sstevel@tonic-gate (void) devctl_ddef_string(ddef_hdl, "compatible", nd_compat);
2437c478bd9Sstevel@tonic-gate (void) devctl_ddef_int_array(ddef_hdl, "reg", 2, nd_reg);
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate /* create the device node */
2467c478bd9Sstevel@tonic-gate if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl))
2477c478bd9Sstevel@tonic-gate goto bad;
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate if (devctl_get_pathname(dev_hdl, dev_path, MAXPATHLEN) == NULL)
2507c478bd9Sstevel@tonic-gate goto bad;
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate #ifdef DEBUG
2537c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "PSVC: create_i2c_node: Device node created: (%s)",
2547c478bd9Sstevel@tonic-gate dev_path);
2557c478bd9Sstevel@tonic-gate #endif
2567c478bd9Sstevel@tonic-gate rv = PSVC_SUCCESS;
2577c478bd9Sstevel@tonic-gate bad:
2587c478bd9Sstevel@tonic-gate if (dev_hdl) devctl_release(dev_hdl);
2597c478bd9Sstevel@tonic-gate if (ddef_hdl) devctl_ddef_free(ddef_hdl);
2607c478bd9Sstevel@tonic-gate if (bus_hdl) devctl_release(bus_hdl);
2617c478bd9Sstevel@tonic-gate return (rv);
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate * Delete an I2C device node given the device path.
2667c478bd9Sstevel@tonic-gate */
2677c478bd9Sstevel@tonic-gate static void
delete_i2c_node(char * nd)2687c478bd9Sstevel@tonic-gate delete_i2c_node(char *nd)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate int rv;
2717c478bd9Sstevel@tonic-gate devctl_hdl_t dev_hdl;
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate dev_hdl = devctl_device_acquire(nd, 0);
2747c478bd9Sstevel@tonic-gate if (dev_hdl == NULL) {
2757c478bd9Sstevel@tonic-gate return;
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate rv = devctl_device_remove(dev_hdl);
2797c478bd9Sstevel@tonic-gate if (rv != DDI_SUCCESS)
2807c478bd9Sstevel@tonic-gate perror(nd);
2817c478bd9Sstevel@tonic-gate #ifdef DEBUG
2827c478bd9Sstevel@tonic-gate else
2837c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Device node deleted: (%s)", nd);
2847c478bd9Sstevel@tonic-gate #endif
2857c478bd9Sstevel@tonic-gate devctl_release(dev_hdl);
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate /* PCF8574 Reset Function */
2907c478bd9Sstevel@tonic-gate static int
send_pcf8574_reset(psvc_opaque_t hdlp,char * reset_dev)2917c478bd9Sstevel@tonic-gate send_pcf8574_reset(psvc_opaque_t hdlp, char *reset_dev)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate int err;
2947c478bd9Sstevel@tonic-gate uint8_t reset_bits[2] = {0x7F, 0xFF};
2957c478bd9Sstevel@tonic-gate int i;
2967c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) {
2977c478bd9Sstevel@tonic-gate err = psvc_set_attr(hdlp, reset_dev, PSVC_GPIO_VALUE_ATTR,
2987c478bd9Sstevel@tonic-gate &reset_bits[i]);
2997c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS) {
3007c478bd9Sstevel@tonic-gate #ifdef DEBUG
3017c478bd9Sstevel@tonic-gate syslog(LOG_ERR,
3027c478bd9Sstevel@tonic-gate gettext("Reset to %s with 0x%x failed"),
3037c478bd9Sstevel@tonic-gate reset_dev, reset_bits[i]);
3047c478bd9Sstevel@tonic-gate #endif
3057c478bd9Sstevel@tonic-gate return (err);
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate /* Need to give u-code a chance to update */
3097c478bd9Sstevel@tonic-gate sleep(3);
3107c478bd9Sstevel@tonic-gate return (err);
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@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)3147c478bd9Sstevel@tonic-gate pcf8574_write_bit(psvc_opaque_t hdlp, char *id, uint8_t bit_num,
3157c478bd9Sstevel@tonic-gate uint8_t bit_val, uint8_t write_must_be_1)
3167c478bd9Sstevel@tonic-gate {
3177c478bd9Sstevel@tonic-gate int rv = PSVC_FAILURE;
3187c478bd9Sstevel@tonic-gate uint8_t byte;
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate rv = psvc_get_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR, &byte);
3217c478bd9Sstevel@tonic-gate if (rv != PSVC_SUCCESS)
3227c478bd9Sstevel@tonic-gate return (rv);
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate byte = PCF8574_BIT_WRITE_VALUE(byte, bit_num, bit_val);
3257c478bd9Sstevel@tonic-gate byte |= write_must_be_1;
3267c478bd9Sstevel@tonic-gate rv = psvc_set_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR, &byte);
3277c478bd9Sstevel@tonic-gate return (rv);
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate * To enable the i2c bus, we must toggle bit 6 on the PDB's
3327c478bd9Sstevel@tonic-gate * PCF8574 (0x4C) high->low->high
3337c478bd9Sstevel@tonic-gate */
3347c478bd9Sstevel@tonic-gate static int
pdb_enable_i2c(psvc_opaque_t hdlp)3357c478bd9Sstevel@tonic-gate pdb_enable_i2c(psvc_opaque_t hdlp)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate int rv = PSVC_SUCCESS, i;
3387c478bd9Sstevel@tonic-gate int bit_vals[3] = {1, 0, 1};
3397c478bd9Sstevel@tonic-gate int bit_num = 6;
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate for (i = 0; i < 3; i++) {
3427c478bd9Sstevel@tonic-gate rv = pcf8574_write_bit(hdlp, "PDB_PORT", bit_num, bit_vals[i],
3437c478bd9Sstevel@tonic-gate PDB_MUST_BE_1);
3447c478bd9Sstevel@tonic-gate if (rv != PSVC_SUCCESS) {
3457c478bd9Sstevel@tonic-gate goto bad;
3467c478bd9Sstevel@tonic-gate }
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate return (rv);
3497c478bd9Sstevel@tonic-gate bad:
3507c478bd9Sstevel@tonic-gate #ifdef DEBUG
3517c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("PDB I2C Bus Enabling Failed"));
3527c478bd9Sstevel@tonic-gate #endif
3537c478bd9Sstevel@tonic-gate return (rv);
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate int32_t
psvc_init_disk_bp_policy_0(psvc_opaque_t hdlp,char * id)3577c478bd9Sstevel@tonic-gate psvc_init_disk_bp_policy_0(psvc_opaque_t hdlp, char *id)
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate uint8_t reset = 0xFF;
3607c478bd9Sstevel@tonic-gate return (psvc_set_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR,
3617c478bd9Sstevel@tonic-gate &reset));
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate int32_t
pcf8574_init_policy_0(psvc_opaque_t hdlp,char * id)3657c478bd9Sstevel@tonic-gate pcf8574_init_policy_0(psvc_opaque_t hdlp, char *id)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate return (send_pcf8574_reset(hdlp, id));
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate static int32_t
check_fan(psvc_opaque_t hdlp,char * tray_id,char * fan_id,boolean_t * fault_on)3717c478bd9Sstevel@tonic-gate check_fan(psvc_opaque_t hdlp, char *tray_id, char *fan_id, boolean_t *fault_on)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate int status;
3747c478bd9Sstevel@tonic-gate int speed;
3757c478bd9Sstevel@tonic-gate int low_thresh;
3767c478bd9Sstevel@tonic-gate boolean_t have_fault = 0;
3777c478bd9Sstevel@tonic-gate char *tach_id;
3787c478bd9Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
3797c478bd9Sstevel@tonic-gate char prev_state[PSVC_MAX_STR_LEN];
3807c478bd9Sstevel@tonic-gate char fault_state[PSVC_MAX_STR_LEN];
381298b7f4cSjfrank int retry;
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate /* Get this fan object's corresponding fan tach */
3847c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_ID_ATTR,
3857c478bd9Sstevel@tonic-gate &tach_id, PSVC_FAN_SPEED_TACHOMETER, 0);
3867c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
3877c478bd9Sstevel@tonic-gate return (status);
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate /* Get the low fan speed threshold */
3907c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, tach_id, PSVC_LO_WARN_ATTR, &low_thresh);
3917c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
3927c478bd9Sstevel@tonic-gate return (status);
3937c478bd9Sstevel@tonic-gate
394298b7f4cSjfrank retry = 0;
395298b7f4cSjfrank do {
396298b7f4cSjfrank if (retry)
397298b7f4cSjfrank (void) sleep(retry_sleep_fan);
398298b7f4cSjfrank /* Get the fan speed */
399298b7f4cSjfrank status = psvc_get_attr(hdlp, tach_id, PSVC_SENSOR_VALUE_ATTR,
400298b7f4cSjfrank &speed);
401298b7f4cSjfrank if (status != PSVC_SUCCESS)
4027c478bd9Sstevel@tonic-gate return (status);
4037c478bd9Sstevel@tonic-gate
404298b7f4cSjfrank if (speed <= low_thresh) { /* We see a fault */
405298b7f4cSjfrank strlcpy(fault_state, "DEVICE_FAIL",
406298b7f4cSjfrank sizeof (fault_state));
407298b7f4cSjfrank strlcpy(state, PSVC_ERROR, sizeof (state));
408298b7f4cSjfrank have_fault = 1;
409298b7f4cSjfrank } else { /* Fault gone? */
410298b7f4cSjfrank strlcpy(fault_state, PSVC_NO_FAULT,
411298b7f4cSjfrank sizeof (fault_state));
412298b7f4cSjfrank strlcpy(state, PSVC_OK, sizeof (state));
413298b7f4cSjfrank have_fault = 0;
414298b7f4cSjfrank }
415298b7f4cSjfrank retry++;
416298b7f4cSjfrank } while ((retry < n_retry_fan) && (speed <= low_thresh));
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate /* Assign new states to the fan object */
4197c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, fan_id, PSVC_FAULTID_ATTR, fault_state);
4207c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
4217c478bd9Sstevel@tonic-gate return (status);
4227c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, fan_id, PSVC_STATE_ATTR, state);
4237c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
4247c478bd9Sstevel@tonic-gate return (status);
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate /* Get state and previous state */
4277c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, fan_id, PSVC_STATE_ATTR, state);
4287c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
4297c478bd9Sstevel@tonic-gate return (status);
4307c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, fan_id, PSVC_PREV_STATE_ATTR, prev_state);
4317c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
4327c478bd9Sstevel@tonic-gate return (status);
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate /* Display notices */
4357c478bd9Sstevel@tonic-gate if (strcmp(state, PSVC_OK) != 0) {
4367c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("WARNING: %s (%s) failure detected"),
4377c478bd9Sstevel@tonic-gate tray_id, fan_id);
4387c478bd9Sstevel@tonic-gate } else {
4397c478bd9Sstevel@tonic-gate if (strcmp(state, prev_state) != 0) {
4407c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("NOTICE: Device %s (%s) OK"),
4417c478bd9Sstevel@tonic-gate tray_id, fan_id);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate *fault_on |= have_fault;
4467c478bd9Sstevel@tonic-gate return (PSVC_SUCCESS);
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate /*
4507c478bd9Sstevel@tonic-gate * This policy acts on fan trays. It looks at each of its fans
4517c478bd9Sstevel@tonic-gate * and checks the speeds. If the fan speed is less than the threshold,
4527c478bd9Sstevel@tonic-gate * then indicate: console, log, LED.
4537c478bd9Sstevel@tonic-gate */
4547c478bd9Sstevel@tonic-gate int32_t
psvc_fan_fault_check_policy_0(psvc_opaque_t hdlp,char * id)4557c478bd9Sstevel@tonic-gate psvc_fan_fault_check_policy_0(psvc_opaque_t hdlp, char *id)
4567c478bd9Sstevel@tonic-gate {
4577c478bd9Sstevel@tonic-gate int fan_count;
4587c478bd9Sstevel@tonic-gate int led_count;
4597c478bd9Sstevel@tonic-gate int err, i;
4607c478bd9Sstevel@tonic-gate char *led_id;
4617c478bd9Sstevel@tonic-gate char *fan_id;
4627c478bd9Sstevel@tonic-gate char led_state[PSVC_MAX_STR_LEN];
4637c478bd9Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
4647c478bd9Sstevel@tonic-gate char prev_state[PSVC_MAX_STR_LEN];
4657c478bd9Sstevel@tonic-gate boolean_t fault_on = 0;
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate /* Get the number of fans associated with this fan tray. */
4687c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &fan_count,
4697c478bd9Sstevel@tonic-gate PSVC_FAN_TRAY_FANS);
4707c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
4717c478bd9Sstevel@tonic-gate return (err);
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate for (i = 0; i < fan_count; i++) {
4747c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
4757c478bd9Sstevel@tonic-gate &fan_id, PSVC_FAN_TRAY_FANS, i);
4767c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
4777c478bd9Sstevel@tonic-gate return (err);
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate err = check_fan(hdlp, id, fan_id, &fault_on);
4807c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
4817c478bd9Sstevel@tonic-gate return (err);
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate if (fault_on) {
4857c478bd9Sstevel@tonic-gate strlcpy(led_state, PSVC_LED_ON, sizeof (led_state));
4867c478bd9Sstevel@tonic-gate err = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_ERROR);
4877c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
4887c478bd9Sstevel@tonic-gate return (err);
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate } else {
4917c478bd9Sstevel@tonic-gate strlcpy(led_state, PSVC_LED_OFF, sizeof (led_state));
4927c478bd9Sstevel@tonic-gate err = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_OK);
4937c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
4947c478bd9Sstevel@tonic-gate return (err);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
4987c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
4997c478bd9Sstevel@tonic-gate return (err);
5007c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, prev_state);
5017c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
5027c478bd9Sstevel@tonic-gate return (err);
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate /*
5057c478bd9Sstevel@tonic-gate * Set leds according to the fan tray's states.
5067c478bd9Sstevel@tonic-gate * (we only do this if there is a change of state in order
5077c478bd9Sstevel@tonic-gate * to reduce i2c traffic)
5087c478bd9Sstevel@tonic-gate */
5097c478bd9Sstevel@tonic-gate if (strcmp(state, prev_state) != 0) {
5107c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR,
5117c478bd9Sstevel@tonic-gate &led_count, PSVC_DEV_FAULT_LED);
5127c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
5137c478bd9Sstevel@tonic-gate return (err);
5147c478bd9Sstevel@tonic-gate for (i = 0; i < led_count; i++) {
5157c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, id,
5167c478bd9Sstevel@tonic-gate PSVC_ASSOC_ID_ATTR, &led_id,
5177c478bd9Sstevel@tonic-gate PSVC_DEV_FAULT_LED, i);
5187c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
5197c478bd9Sstevel@tonic-gate return (err);
5207c478bd9Sstevel@tonic-gate err = psvc_set_attr(hdlp, led_id,
5217c478bd9Sstevel@tonic-gate PSVC_LED_STATE_ATTR, led_state);
5227c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
5237c478bd9Sstevel@tonic-gate return (err);
5247c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, led_id,
5257c478bd9Sstevel@tonic-gate PSVC_LED_STATE_ATTR, led_state);
5267c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
5277c478bd9Sstevel@tonic-gate return (err);
5287c478bd9Sstevel@tonic-gate }
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate return (err);
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate static int32_t
check_cpu_temp_fault(psvc_opaque_t hdlp,char * cpu,int32_t cpu_count)5347c478bd9Sstevel@tonic-gate check_cpu_temp_fault(psvc_opaque_t hdlp, char *cpu, int32_t cpu_count)
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate char *sensorid;
5377c478bd9Sstevel@tonic-gate int32_t sensor_count;
5387c478bd9Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
5397c478bd9Sstevel@tonic-gate int32_t i;
5407c478bd9Sstevel@tonic-gate char fault[PSVC_MAX_STR_LEN];
541298b7f4cSjfrank int retry;
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate psvc_get_attr(hdlp, cpu, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
5447c478bd9Sstevel@tonic-gate PSVC_DEV_TEMP_SENSOR);
5457c478bd9Sstevel@tonic-gate for (i = 0; i < sensor_count; ++i) {
5467c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, cpu, PSVC_ASSOC_ID_ATTR,
5477c478bd9Sstevel@tonic-gate &sensorid, PSVC_DEV_TEMP_SENSOR, i);
5487c478bd9Sstevel@tonic-gate if (status == PSVC_FAILURE)
5497c478bd9Sstevel@tonic-gate return (status);
5507c478bd9Sstevel@tonic-gate
551298b7f4cSjfrank retry = 0;
552298b7f4cSjfrank do {
553298b7f4cSjfrank if (retry)
554298b7f4cSjfrank (void) sleep(retry_sleep_temp_shutdown);
555298b7f4cSjfrank status = psvc_get_attr(hdlp, sensorid,
556298b7f4cSjfrank PSVC_FAULTID_ATTR, fault);
557298b7f4cSjfrank if (status == PSVC_FAILURE)
558298b7f4cSjfrank return (status);
559298b7f4cSjfrank retry++;
560298b7f4cSjfrank } while (((strcmp(fault, PSVC_TEMP_LO_SHUT) == 0) ||
561298b7f4cSjfrank (strcmp(fault, PSVC_TEMP_HI_SHUT) == 0)) &&
562298b7f4cSjfrank (retry < n_retry_temp_shutdown));
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate if ((strcmp(fault, PSVC_TEMP_HI_SHUT) == 0) ||
5657c478bd9Sstevel@tonic-gate (strcmp(fault, PSVC_TEMP_LO_SHUT) == 0)) {
5667c478bd9Sstevel@tonic-gate system("shutdown -y -g 60 -i 5 \"OVERTEMP condition\"");
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate
5707c478bd9Sstevel@tonic-gate return (status);
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate int32_t
psvc_shutdown_policy_0(psvc_opaque_t hdlp,char * id)5747c478bd9Sstevel@tonic-gate psvc_shutdown_policy_0(psvc_opaque_t hdlp, char *id)
5757c478bd9Sstevel@tonic-gate {
5767c478bd9Sstevel@tonic-gate int32_t cpu_count;
5777c478bd9Sstevel@tonic-gate char *cpuid;
5787c478bd9Sstevel@tonic-gate int32_t i;
5797c478bd9Sstevel@tonic-gate boolean_t present;
5807c478bd9Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count,
5837c478bd9Sstevel@tonic-gate PSVC_CPU);
5847c478bd9Sstevel@tonic-gate for (i = 0; i < cpu_count; ++i) {
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &cpuid,
5877c478bd9Sstevel@tonic-gate PSVC_CPU, i);
5887c478bd9Sstevel@tonic-gate if (status == PSVC_FAILURE)
5897c478bd9Sstevel@tonic-gate return (status);
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, cpuid,
5927c478bd9Sstevel@tonic-gate PSVC_PRESENCE_ATTR, &present);
5937c478bd9Sstevel@tonic-gate if (status == PSVC_FAILURE && present == PSVC_PRESENT)
5947c478bd9Sstevel@tonic-gate return (status);
5957c478bd9Sstevel@tonic-gate if (present == PSVC_PRESENT) {
5967c478bd9Sstevel@tonic-gate status = check_cpu_temp_fault(hdlp, cpuid, cpu_count);
5977c478bd9Sstevel@tonic-gate if (status == PSVC_FAILURE && errno != ENODEV)
5987c478bd9Sstevel@tonic-gate return (status);
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate return (PSVC_SUCCESS);
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate /*
6067c478bd9Sstevel@tonic-gate * Checks device specified by the PSVC_DEV_FAULT_SENSOR association
6077c478bd9Sstevel@tonic-gate * for errors, and if there is, then report and turn on the FSP Fault
6087c478bd9Sstevel@tonic-gate * Led.
6097c478bd9Sstevel@tonic-gate */
6107c478bd9Sstevel@tonic-gate int32_t
psvc_fsp_device_fault_check_policy_0(psvc_opaque_t hdlp,char * id)6117c478bd9Sstevel@tonic-gate psvc_fsp_device_fault_check_policy_0(psvc_opaque_t hdlp, char *id)
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate int32_t status;
6147c478bd9Sstevel@tonic-gate int32_t i;
6157c478bd9Sstevel@tonic-gate int32_t device_count = 0;
6167c478bd9Sstevel@tonic-gate char device_state[PSVC_MAX_STR_LEN];
6177c478bd9Sstevel@tonic-gate char *device_id;
6187c478bd9Sstevel@tonic-gate int32_t failed_count = 0;
6197c478bd9Sstevel@tonic-gate static int32_t led_on = 0;
620298b7f4cSjfrank int retry;
6217c478bd9Sstevel@tonic-gate
6227c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR,
6237c478bd9Sstevel@tonic-gate &device_count, PSVC_DEV_FAULT_SENSOR);
6247c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
6257c478bd9Sstevel@tonic-gate return (status);
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate for (i = 0; i < device_count; i++) {
6287c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
6297c478bd9Sstevel@tonic-gate &device_id, PSVC_DEV_FAULT_SENSOR, i);
6307c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
6317c478bd9Sstevel@tonic-gate return (status);
6327c478bd9Sstevel@tonic-gate
633298b7f4cSjfrank retry = 0;
634298b7f4cSjfrank do {
635298b7f4cSjfrank if (retry)
636298b7f4cSjfrank (void) sleep(retry_sleep_fsp_fault);
637298b7f4cSjfrank status = psvc_get_attr(hdlp, device_id, PSVC_STATE_ATTR,
638298b7f4cSjfrank device_state);
639298b7f4cSjfrank if (status != PSVC_SUCCESS)
640298b7f4cSjfrank return (status);
6417c478bd9Sstevel@tonic-gate
642298b7f4cSjfrank if (strcmp(device_state, PSVC_OK) != 0 &&
643298b7f4cSjfrank strcmp(device_state, PSVC_HOTPLUGGED) != 0 &&
644298b7f4cSjfrank strcmp(device_state, "NO AC POWER") != 0 &&
645298b7f4cSjfrank strlen(device_state) != 0) {
646298b7f4cSjfrank failed_count++;
647298b7f4cSjfrank }
648298b7f4cSjfrank retry++;
649298b7f4cSjfrank } while ((retry < n_retry_fsp_fault) && (failed_count));
6507c478bd9Sstevel@tonic-gate }
6517c478bd9Sstevel@tonic-gate if (failed_count == 0 && led_on) {
6527c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("%s has turned OFF"), id);
6537c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_LED_STATE_ATTR,
6547c478bd9Sstevel@tonic-gate PSVC_LED_OFF);
6557c478bd9Sstevel@tonic-gate led_on = 0;
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate
6587c478bd9Sstevel@tonic-gate if (failed_count > 0 && ! led_on) {
6597c478bd9Sstevel@tonic-gate syslog(LOG_ERR,
6607c478bd9Sstevel@tonic-gate gettext("%s has turned ON"), id);
6617c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_LED_STATE_ATTR,
6627c478bd9Sstevel@tonic-gate PSVC_LED_ON);
6637c478bd9Sstevel@tonic-gate led_on = 1;
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate return (PSVC_SUCCESS);
6677c478bd9Sstevel@tonic-gate }
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate /* Power Supply Policy Helper and Worker Functions */
6707c478bd9Sstevel@tonic-gate static void
ps_reset_prev_failed(int index)6717c478bd9Sstevel@tonic-gate ps_reset_prev_failed(int index)
6727c478bd9Sstevel@tonic-gate {
6737c478bd9Sstevel@tonic-gate int i;
6747c478bd9Sstevel@tonic-gate /* Reset the power supply's failure information */
6757c478bd9Sstevel@tonic-gate for (i = 0; i < 3; i++) {
6767c478bd9Sstevel@tonic-gate ps_prev_id[index][i] = NULL;
6777c478bd9Sstevel@tonic-gate ps_prev_failed[index][i] = 0;
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate static int
check_i2c_access(psvc_opaque_t hdlp,char * id)6827c478bd9Sstevel@tonic-gate check_i2c_access(psvc_opaque_t hdlp, char *id)
6837c478bd9Sstevel@tonic-gate {
6847c478bd9Sstevel@tonic-gate int rv;
6857c478bd9Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
6867c478bd9Sstevel@tonic-gate char ps_fault_sensor[PSVC_MAX_STR_LEN];
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate snprintf(ps_fault_sensor, sizeof (ps_fault_sensor),
6897c478bd9Sstevel@tonic-gate "%s_FAULT_SENSOR", id);
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate rv = psvc_get_attr(hdlp, ps_fault_sensor, PSVC_SWITCH_STATE_ATTR,
6927c478bd9Sstevel@tonic-gate &state);
6937c478bd9Sstevel@tonic-gate return (rv);
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate /*
6977c478bd9Sstevel@tonic-gate * This routine takes in the PSVC handle pointer, the PS name, and the
6987c478bd9Sstevel@tonic-gate * instance number (0 or 1). It simply make a psvc_get call to get the
6997c478bd9Sstevel@tonic-gate * presence of each of the children under the PS. This call will set the
7007c478bd9Sstevel@tonic-gate * presence state of the child device if it was not there when the system
7017c478bd9Sstevel@tonic-gate * was booted.
7027c478bd9Sstevel@tonic-gate */
7037c478bd9Sstevel@tonic-gate static int
handle_ps_hotplug_children_presence(psvc_opaque_t hdlp,char * id)7047c478bd9Sstevel@tonic-gate handle_ps_hotplug_children_presence(psvc_opaque_t hdlp, char *id)
7057c478bd9Sstevel@tonic-gate {
7067c478bd9Sstevel@tonic-gate char *child_add_on[4] = {"_RESET", "_LOGICAL_STATE", "_AC_IN_SENSOR",
7077c478bd9Sstevel@tonic-gate "_FAULT_SENSOR"};
7087c478bd9Sstevel@tonic-gate int add_ons = 4;
7097c478bd9Sstevel@tonic-gate char addon_id[PICL_PROPNAMELEN_MAX];
7107c478bd9Sstevel@tonic-gate char *sensor_id;
7117c478bd9Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
7127c478bd9Sstevel@tonic-gate boolean_t presence;
7137c478bd9Sstevel@tonic-gate int j;
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate /* Go through the add on list and set presence */
7167c478bd9Sstevel@tonic-gate for (j = 0; j < add_ons; j++) {
7177c478bd9Sstevel@tonic-gate snprintf(addon_id, sizeof (addon_id), "%s%s", id,
7187c478bd9Sstevel@tonic-gate child_add_on[j]);
7197c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, addon_id, PSVC_PRESENCE_ATTR,
7207c478bd9Sstevel@tonic-gate &presence);
7217c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
7227c478bd9Sstevel@tonic-gate return (status);
7237c478bd9Sstevel@tonic-gate }
7247c478bd9Sstevel@tonic-gate
7257c478bd9Sstevel@tonic-gate /* Go through each PS's fault sensors */
7267c478bd9Sstevel@tonic-gate for (j = 0; j < PS_MAX_FAULT_SENSORS; j++) {
7277c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
7287c478bd9Sstevel@tonic-gate &(sensor_id), PSVC_DEV_FAULT_SENSOR, j);
7297c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
7307c478bd9Sstevel@tonic-gate return (status);
7317c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, sensor_id, PSVC_PRESENCE_ATTR,
7327c478bd9Sstevel@tonic-gate &presence);
7337c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
7347c478bd9Sstevel@tonic-gate return (status);
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate
7377c478bd9Sstevel@tonic-gate /* Go through each PS's onboard i2c hardware */
7387c478bd9Sstevel@tonic-gate for (j = 0; j < 2; j++) {
7397c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
7407c478bd9Sstevel@tonic-gate &(sensor_id), PSVC_PHYSICAL_DEVICE, j);
7417c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
7427c478bd9Sstevel@tonic-gate return (status);
7437c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, sensor_id, PSVC_PRESENCE_ATTR,
7447c478bd9Sstevel@tonic-gate &presence);
7457c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
7467c478bd9Sstevel@tonic-gate return (status);
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate return (status);
7507c478bd9Sstevel@tonic-gate }
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate static int
handle_ps_hotplug(psvc_opaque_t hdlp,char * id,boolean_t present)7537c478bd9Sstevel@tonic-gate handle_ps_hotplug(psvc_opaque_t hdlp, char *id, boolean_t present)
7547c478bd9Sstevel@tonic-gate {
7557c478bd9Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
7567c478bd9Sstevel@tonic-gate int32_t instance;
7577c478bd9Sstevel@tonic-gate picl_nodehdl_t parent_node;
7587c478bd9Sstevel@tonic-gate picl_nodehdl_t child_node;
7597c478bd9Sstevel@tonic-gate char info[PSVC_MAX_STR_LEN];
7607c478bd9Sstevel@tonic-gate char ps_logical_state[PICL_PROPNAMELEN_MAX];
7617c478bd9Sstevel@tonic-gate char parent_path[PICL_PROPNAMELEN_MAX];
7627c478bd9Sstevel@tonic-gate char ps_path[PICL_PROPNAMELEN_MAX];
7637c478bd9Sstevel@tonic-gate static int fruprom_addr[2][2] = { {0, 0xa2}, {0, 0xa0} };
7647c478bd9Sstevel@tonic-gate static int pcf8574_addr[2][2] = { {0, 0x72}, {0, 0x70} };
7657c478bd9Sstevel@tonic-gate char dev_path[MAXPATHLEN];
7667c478bd9Sstevel@tonic-gate
7677c478bd9Sstevel@tonic-gate /* Convert name to node and parent path */
7687c478bd9Sstevel@tonic-gate psvcplugin_lookup(id, parent_path, &child_node);
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate /*
7717c478bd9Sstevel@tonic-gate * Get the power supply's instance.
7727c478bd9Sstevel@tonic-gate * Used to index the xxx_addr arrays
7737c478bd9Sstevel@tonic-gate */
7747c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
7757c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
7767c478bd9Sstevel@tonic-gate return (status);
7777c478bd9Sstevel@tonic-gate
7787c478bd9Sstevel@tonic-gate if (present == PSVC_PRESENT && !ps_prev_present[instance]) {
7797c478bd9Sstevel@tonic-gate /* Service Power Supply Insertion */
7807c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s inserted"), id);
7817c478bd9Sstevel@tonic-gate
7827c478bd9Sstevel@tonic-gate /* PICL Tree Maintenance */
7837c478bd9Sstevel@tonic-gate ptree_get_node_by_path(parent_path, &parent_node);
7847c478bd9Sstevel@tonic-gate ptree_add_node(parent_node, child_node);
7857c478bd9Sstevel@tonic-gate snprintf(ps_path, sizeof (ps_path), "%s/%s", parent_path, id);
7867c478bd9Sstevel@tonic-gate psvcplugin_add_children(ps_path);
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate /*
7897c478bd9Sstevel@tonic-gate * This code to update the presences of power supply
7907c478bd9Sstevel@tonic-gate * child devices in the event that picld was started
7917c478bd9Sstevel@tonic-gate * without a power supply present. This call makes
7927c478bd9Sstevel@tonic-gate * the devices available after that initial insertion.
7937c478bd9Sstevel@tonic-gate */
7947c478bd9Sstevel@tonic-gate status = handle_ps_hotplug_children_presence(hdlp, id);
7957c478bd9Sstevel@tonic-gate
7967c478bd9Sstevel@tonic-gate /*
7977c478bd9Sstevel@tonic-gate * Device Tree Maintenance
7987c478bd9Sstevel@tonic-gate * Add the devinfo tree node entry for the pcf8574 and seeprom
7997c478bd9Sstevel@tonic-gate * and attach their drivers.
8007c478bd9Sstevel@tonic-gate */
8017c478bd9Sstevel@tonic-gate status |= create_i2c_node("ioexp", "i2c-pcf8574", SEG5_ADDR,
8027c478bd9Sstevel@tonic-gate pcf8574_addr[instance]);
8037c478bd9Sstevel@tonic-gate status |= create_i2c_node("fru", "i2c-at24c64", SEG5_ADDR,
8047c478bd9Sstevel@tonic-gate fruprom_addr[instance]);
8057c478bd9Sstevel@tonic-gate } else {
8067c478bd9Sstevel@tonic-gate /* Service Power Supply Removal */
8077c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s removed"), id);
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate /* Reset the power supply's failure information */
8107c478bd9Sstevel@tonic-gate ps_reset_prev_failed(instance);
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate /* PICL Tree Maintenance */
8137c478bd9Sstevel@tonic-gate if (ptree_delete_node(child_node) != PICL_SUCCESS)
8147c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "ptree_delete_node failed!");
8157c478bd9Sstevel@tonic-gate
8167c478bd9Sstevel@tonic-gate /*
8177c478bd9Sstevel@tonic-gate * The hardcoded subscript in pcf8574_add[instance][1]
8187c478bd9Sstevel@tonic-gate * refers to the address. We are appending the address to
8197c478bd9Sstevel@tonic-gate * device path. Both elements are used when creating
8207c478bd9Sstevel@tonic-gate * the i2c node (above).
8217c478bd9Sstevel@tonic-gate */
8227c478bd9Sstevel@tonic-gate snprintf(dev_path, sizeof (dev_path),
8237c478bd9Sstevel@tonic-gate SEG5_DEV_NAME"ioexp@0,%x:pcf8574",
8247c478bd9Sstevel@tonic-gate pcf8574_addr[instance][1]);
8257c478bd9Sstevel@tonic-gate delete_i2c_node(dev_path);
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate snprintf(dev_path, sizeof (dev_path),
8287c478bd9Sstevel@tonic-gate SEG5_DEV_NAME"fru@0,%x:fru", fruprom_addr[instance][1]);
8297c478bd9Sstevel@tonic-gate delete_i2c_node(dev_path);
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate snprintf(ps_logical_state, sizeof (ps_logical_state),
8337c478bd9Sstevel@tonic-gate "%s_LOGICAL_STATE", id);
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate strlcpy(info, PSVC_OK, sizeof (info));
8367c478bd9Sstevel@tonic-gate status |= psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, info);
8377c478bd9Sstevel@tonic-gate status |= psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR, info);
8387c478bd9Sstevel@tonic-gate
8397c478bd9Sstevel@tonic-gate strlcpy(info, PSVC_NO_FAULT, sizeof (info));
8407c478bd9Sstevel@tonic-gate status |= psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, info);
8417c478bd9Sstevel@tonic-gate
8427c478bd9Sstevel@tonic-gate /* Enable the i2c connection to the power supply */
8437c478bd9Sstevel@tonic-gate status |= pdb_enable_i2c(hdlp);
8447c478bd9Sstevel@tonic-gate return (status);
8457c478bd9Sstevel@tonic-gate }
8467c478bd9Sstevel@tonic-gate
8477c478bd9Sstevel@tonic-gate /*
8487c478bd9Sstevel@tonic-gate * check_ps_state() Checks for:
8497c478bd9Sstevel@tonic-gate *
8507c478bd9Sstevel@tonic-gate * - Failure bits:
8517c478bd9Sstevel@tonic-gate * Power Supply Fan Failure
8527c478bd9Sstevel@tonic-gate * Power Supply Temperature Failure
8537c478bd9Sstevel@tonic-gate * Power Supply Generic Fault
8547c478bd9Sstevel@tonic-gate * Power Supply AC Cord Plugged In
8557c478bd9Sstevel@tonic-gate *
8567c478bd9Sstevel@tonic-gate * - If we see a "bad" state we will report an error.
8577c478bd9Sstevel@tonic-gate *
8587c478bd9Sstevel@tonic-gate * - "Bad" states:
8597c478bd9Sstevel@tonic-gate * Fault bit shows fault.
8607c478bd9Sstevel@tonic-gate * Temperature fault shows fault.
8617c478bd9Sstevel@tonic-gate * Fan fault shows fault.
8627c478bd9Sstevel@tonic-gate * AC power NOT okay to supply.
8637c478bd9Sstevel@tonic-gate *
8647c478bd9Sstevel@tonic-gate * - If we see that the AC Cord is not plugged in, then the the other
8657c478bd9Sstevel@tonic-gate * failure bits are invalid.
8667c478bd9Sstevel@tonic-gate *
8677c478bd9Sstevel@tonic-gate * - Send pcf8574_reset at the end of the policy if we see
8687c478bd9Sstevel@tonic-gate * any "bad" states.
8697c478bd9Sstevel@tonic-gate */
8707c478bd9Sstevel@tonic-gate static int32_t
check_ps_state(psvc_opaque_t hdlp,char * id)8717c478bd9Sstevel@tonic-gate check_ps_state(psvc_opaque_t hdlp, char *id)
8727c478bd9Sstevel@tonic-gate {
8737c478bd9Sstevel@tonic-gate int32_t sensor_count;
8747c478bd9Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
8757c478bd9Sstevel@tonic-gate int32_t i;
8767c478bd9Sstevel@tonic-gate int32_t fault_on = 0;
8777c478bd9Sstevel@tonic-gate char *sensor_id;
8787c478bd9Sstevel@tonic-gate char ps_ok_sensor[PICL_PROPNAMELEN_MAX];
8797c478bd9Sstevel@tonic-gate char ps_logical_state[PICL_PROPNAMELEN_MAX];
8807c478bd9Sstevel@tonic-gate char ps_reset[PICL_PROPNAMELEN_MAX];
8817c478bd9Sstevel@tonic-gate char previous_state[PSVC_MAX_STR_LEN];
8827c478bd9Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
8837c478bd9Sstevel@tonic-gate char fault[PSVC_MAX_STR_LEN];
8847c478bd9Sstevel@tonic-gate int ps_okay = 1; /* Keep track of the PDB PS OK Bit */
8857c478bd9Sstevel@tonic-gate int instance;
886298b7f4cSjfrank int retry;
8877c478bd9Sstevel@tonic-gate
8887c478bd9Sstevel@tonic-gate /* Logical state id */
8897c478bd9Sstevel@tonic-gate snprintf(ps_logical_state, sizeof (ps_logical_state),
8907c478bd9Sstevel@tonic-gate "%s_LOGICAL_STATE", id);
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gate /*
8937c478bd9Sstevel@tonic-gate * ac_power_check updates the Power Supply state with "NO AC POWER" if
8947c478bd9Sstevel@tonic-gate * the power cord is out OR PSVC_OK if the power cord is in.
8957c478bd9Sstevel@tonic-gate */
8967c478bd9Sstevel@tonic-gate status = ac_power_check(hdlp, id, ps_logical_state);
8977c478bd9Sstevel@tonic-gate if (status == PSVC_FAILURE)
8987c478bd9Sstevel@tonic-gate return (status);
8997c478bd9Sstevel@tonic-gate
9007c478bd9Sstevel@tonic-gate /*
9017c478bd9Sstevel@tonic-gate * After running ac_power_check we now need to get the current state
9027c478bd9Sstevel@tonic-gate * of the PS. If the power supply state is "NO AC POWER" then we do
9037c478bd9Sstevel@tonic-gate * not need to check for failures and we return.
9047c478bd9Sstevel@tonic-gate */
9057c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
9067c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
9077c478bd9Sstevel@tonic-gate return (status);
9087c478bd9Sstevel@tonic-gate
9097c478bd9Sstevel@tonic-gate if (strcmp(state, "NO AC POWER") == 0)
9107c478bd9Sstevel@tonic-gate return (status);
9117c478bd9Sstevel@tonic-gate
9127c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, previous_state);
9137c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
9147c478bd9Sstevel@tonic-gate return (status);
9157c478bd9Sstevel@tonic-gate
916298b7f4cSjfrank snprintf(ps_ok_sensor, sizeof (ps_ok_sensor), "%s_OK_SENSOR", id);
917298b7f4cSjfrank retry = 0;
918298b7f4cSjfrank do {
919298b7f4cSjfrank if (retry)
920298b7f4cSjfrank (void) sleep(retry_sleep_ps_status);
921298b7f4cSjfrank /* Handle the PDB P/S OK Bit */
922298b7f4cSjfrank status = psvc_get_attr(hdlp, ps_ok_sensor,
923298b7f4cSjfrank PSVC_SWITCH_STATE_ATTR, state);
924298b7f4cSjfrank if (status != PSVC_SUCCESS)
925298b7f4cSjfrank return (status);
926298b7f4cSjfrank retry++;
927298b7f4cSjfrank } while ((retry < n_retry_ps_status) &&
928298b7f4cSjfrank (strcmp(previous_state, state)));
929298b7f4cSjfrank
930298b7f4cSjfrank
9317c478bd9Sstevel@tonic-gate /*
9327c478bd9Sstevel@tonic-gate * If there is a change of state (current state differs from
9337c478bd9Sstevel@tonic-gate * previous state, then assign the error values.
9347c478bd9Sstevel@tonic-gate */
9357c478bd9Sstevel@tonic-gate if (strcmp(previous_state, state) != 0) {
9367c478bd9Sstevel@tonic-gate if (strcmp(state, PSVC_SWITCH_OFF) == 0) {
9377c478bd9Sstevel@tonic-gate strlcpy(state, PSVC_ERROR, sizeof (state));
9387c478bd9Sstevel@tonic-gate strlcpy(fault, "DEVICE_FAIL", sizeof (fault));
9397c478bd9Sstevel@tonic-gate fault_on = 1;
9407c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext(
9417c478bd9Sstevel@tonic-gate "Device %s: Failure Detected -- %s "
9427c478bd9Sstevel@tonic-gate "shutdown!"), id, id);
9437c478bd9Sstevel@tonic-gate ps_okay = 0;
9447c478bd9Sstevel@tonic-gate } else {
9457c478bd9Sstevel@tonic-gate strlcpy(state, PSVC_OK, sizeof (state));
9467c478bd9Sstevel@tonic-gate strlcpy(fault, PSVC_NO_FAULT, sizeof (fault));
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate
9497c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
9507c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
9517c478bd9Sstevel@tonic-gate return (status);
9527c478bd9Sstevel@tonic-gate
9537c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
9547c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
9557c478bd9Sstevel@tonic-gate return (status);
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate
9587c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
9597c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
9607c478bd9Sstevel@tonic-gate return (status);
9617c478bd9Sstevel@tonic-gate
9627c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
9637c478bd9Sstevel@tonic-gate PSVC_DEV_FAULT_SENSOR);
9647c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS) {
9657c478bd9Sstevel@tonic-gate return (status);
9667c478bd9Sstevel@tonic-gate }
9677c478bd9Sstevel@tonic-gate
9687c478bd9Sstevel@tonic-gate /* Handle the power supply fail bits. */
9697c478bd9Sstevel@tonic-gate for (i = 0; i < sensor_count; i++) {
9707c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
9717c478bd9Sstevel@tonic-gate &sensor_id, PSVC_DEV_FAULT_SENSOR, i);
9727c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
9737c478bd9Sstevel@tonic-gate return (status);
9747c478bd9Sstevel@tonic-gate
975298b7f4cSjfrank retry = 0;
976298b7f4cSjfrank do {
977298b7f4cSjfrank if (retry)
978298b7f4cSjfrank (void) sleep(retry_sleep_ps_status);
979298b7f4cSjfrank status = psvc_get_attr(hdlp, sensor_id,
980298b7f4cSjfrank PSVC_SWITCH_STATE_ATTR, state);
981298b7f4cSjfrank if (status != PSVC_SUCCESS)
982298b7f4cSjfrank return (status);
983298b7f4cSjfrank retry++;
984298b7f4cSjfrank } while ((retry < n_retry_ps_status) &&
985298b7f4cSjfrank (strcmp(state, PSVC_SWITCH_ON) == 0));
9867c478bd9Sstevel@tonic-gate
9877c478bd9Sstevel@tonic-gate if (strcmp(state, PSVC_SWITCH_ON) == 0) {
9887c478bd9Sstevel@tonic-gate if (ps_prev_id[instance][i] == NULL)
9897c478bd9Sstevel@tonic-gate ps_prev_id[instance][i] = sensor_id;
9907c478bd9Sstevel@tonic-gate
9917c478bd9Sstevel@tonic-gate if (ps_prev_failed[instance][i] != 1)
9927c478bd9Sstevel@tonic-gate ps_prev_failed[instance][i] = 1;
9937c478bd9Sstevel@tonic-gate fault_on = 1;
9947c478bd9Sstevel@tonic-gate /*
9957c478bd9Sstevel@tonic-gate * The first sensor in the list is:
9967c478bd9Sstevel@tonic-gate * PSx_DEV_FAULT_SENSOR. If this is on, we do not
9977c478bd9Sstevel@tonic-gate * want to merely report that it's on, but rather
9987c478bd9Sstevel@tonic-gate * report that there was a fault detected, thus
9997c478bd9Sstevel@tonic-gate * improving diagnosability.
10007c478bd9Sstevel@tonic-gate */
10017c478bd9Sstevel@tonic-gate if (i == 0) {
10027c478bd9Sstevel@tonic-gate /*
10037c478bd9Sstevel@tonic-gate * Don't notify if the PDB PS OKAY Bit is
10047c478bd9Sstevel@tonic-gate * "0"
10057c478bd9Sstevel@tonic-gate */
10067c478bd9Sstevel@tonic-gate if (ps_okay)
10077c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext(
10087c478bd9Sstevel@tonic-gate "Device %s: Fault Detected"),
10097c478bd9Sstevel@tonic-gate id);
10107c478bd9Sstevel@tonic-gate } else {
10117c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("Warning %s: %s is ON"),
10127c478bd9Sstevel@tonic-gate id, sensor_id);
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate }
10157c478bd9Sstevel@tonic-gate }
10167c478bd9Sstevel@tonic-gate
10177c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, ps_logical_state,
10187c478bd9Sstevel@tonic-gate PSVC_STATE_ATTR, state);
10197c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
10207c478bd9Sstevel@tonic-gate return (status);
10217c478bd9Sstevel@tonic-gate
10227c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, ps_logical_state,
10237c478bd9Sstevel@tonic-gate PSVC_PREV_STATE_ATTR, previous_state);
10247c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
10257c478bd9Sstevel@tonic-gate return (status);
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate /*
10287c478bd9Sstevel@tonic-gate * If we encountered a fault of any kind (something before
10297c478bd9Sstevel@tonic-gate * has set 'fault_on' to '1') then we want to send the reset
10307c478bd9Sstevel@tonic-gate * signal to the power supply's PCF8574 and also set
10317c478bd9Sstevel@tonic-gate * 'ps_logical_state' to "ERROR" so that the FSP General Fault
10327c478bd9Sstevel@tonic-gate * LED will light.
10337c478bd9Sstevel@tonic-gate */
10347c478bd9Sstevel@tonic-gate if (fault_on) {
10357c478bd9Sstevel@tonic-gate if (ps_okay) {
10367c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
10377c478bd9Sstevel@tonic-gate PSVC_GEN_FAULT);
10387c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
10397c478bd9Sstevel@tonic-gate return (status);
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, ps_logical_state,
10427c478bd9Sstevel@tonic-gate PSVC_STATE_ATTR, PSVC_ERROR);
10437c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
10447c478bd9Sstevel@tonic-gate return (status);
10457c478bd9Sstevel@tonic-gate /*
10467c478bd9Sstevel@tonic-gate * "id" is in the form of "PSx", We need to make it
10477c478bd9Sstevel@tonic-gate * PSx_RESET.
10487c478bd9Sstevel@tonic-gate */
10497c478bd9Sstevel@tonic-gate snprintf(ps_reset, sizeof (ps_reset), "%s_RESET", id);
10507c478bd9Sstevel@tonic-gate status = send_pcf8574_reset(hdlp, ps_reset);
10517c478bd9Sstevel@tonic-gate return (status);
10527c478bd9Sstevel@tonic-gate }
10537c478bd9Sstevel@tonic-gate
10547c478bd9Sstevel@tonic-gate /*
10557c478bd9Sstevel@tonic-gate * There was no fault encountered so we want to
10567c478bd9Sstevel@tonic-gate * set 'ps_logical_state' to "OK"
10577c478bd9Sstevel@tonic-gate */
10587c478bd9Sstevel@tonic-gate if (strcmp(state, PSVC_OK) != 0) {
10597c478bd9Sstevel@tonic-gate for (i = 0; i < 3; i++) {
10607c478bd9Sstevel@tonic-gate char *sensor = ps_prev_id[instance][i];
10617c478bd9Sstevel@tonic-gate int *prev_failed = &ps_prev_failed[instance][i];
10627c478bd9Sstevel@tonic-gate if (sensor == NULL)
10637c478bd9Sstevel@tonic-gate continue;
10647c478bd9Sstevel@tonic-gate if (*prev_failed == 0)
10657c478bd9Sstevel@tonic-gate continue;
10667c478bd9Sstevel@tonic-gate *prev_failed = 0;
10677c478bd9Sstevel@tonic-gate if (i == 0) {
10687c478bd9Sstevel@tonic-gate /*
10697c478bd9Sstevel@tonic-gate * Don't notifiy if we have a power supply
10707c478bd9Sstevel@tonic-gate * failure (PDB PS OKAY == 0
10717c478bd9Sstevel@tonic-gate */
10727c478bd9Sstevel@tonic-gate if (ps_okay)
10737c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext(
10747c478bd9Sstevel@tonic-gate "Notice %s: Fault Cleared"),
10757c478bd9Sstevel@tonic-gate id);
10767c478bd9Sstevel@tonic-gate } else {
10777c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("Notice %s: %s is OFF"),
10787c478bd9Sstevel@tonic-gate id, sensor);
10797c478bd9Sstevel@tonic-gate }
10807c478bd9Sstevel@tonic-gate }
10817c478bd9Sstevel@tonic-gate
10827c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, ps_logical_state,
10837c478bd9Sstevel@tonic-gate PSVC_STATE_ATTR, PSVC_OK);
10847c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
10857c478bd9Sstevel@tonic-gate return (status);
10867c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s Okay"), id);
10877c478bd9Sstevel@tonic-gate }
10887c478bd9Sstevel@tonic-gate
10897c478bd9Sstevel@tonic-gate return (PSVC_SUCCESS);
10907c478bd9Sstevel@tonic-gate }
10917c478bd9Sstevel@tonic-gate
10927c478bd9Sstevel@tonic-gate /*
10937c478bd9Sstevel@tonic-gate * This routine takes in a handle pointer and a Power Supply id. It then gets
10947c478bd9Sstevel@tonic-gate * the switch state for the PSx_AC_IN_SENSOR. If the switch is OFF the cord is
10957c478bd9Sstevel@tonic-gate * unplugged and we return a true (1). If the switch is ON then the cord is
10967c478bd9Sstevel@tonic-gate * plugged in and we return a false (0). If the get_attr call fails we return
10977c478bd9Sstevel@tonic-gate * PSVC_FAILURE (-1).
10987c478bd9Sstevel@tonic-gate */
10997c478bd9Sstevel@tonic-gate static int
ac_unplugged(psvc_opaque_t hdlp,char * id)11007c478bd9Sstevel@tonic-gate ac_unplugged(psvc_opaque_t hdlp, char *id)
11017c478bd9Sstevel@tonic-gate {
11027c478bd9Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
11037c478bd9Sstevel@tonic-gate char ac_sensor_id[PICL_PROPNAMELEN_MAX];
11047c478bd9Sstevel@tonic-gate char ac_switch_state[PSVC_MAX_STR_LEN];
11057c478bd9Sstevel@tonic-gate
11067c478bd9Sstevel@tonic-gate snprintf(ac_sensor_id, sizeof (ac_sensor_id), "%s_AC_IN_SENSOR", id);
11077c478bd9Sstevel@tonic-gate
11087c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, ac_sensor_id, PSVC_SWITCH_STATE_ATTR,
11097c478bd9Sstevel@tonic-gate ac_switch_state);
11107c478bd9Sstevel@tonic-gate if (status == PSVC_FAILURE) {
11117c478bd9Sstevel@tonic-gate return (status);
11127c478bd9Sstevel@tonic-gate }
11137c478bd9Sstevel@tonic-gate
11147c478bd9Sstevel@tonic-gate if (strcmp(ac_switch_state, PSVC_SWITCH_OFF) == 0) {
11157c478bd9Sstevel@tonic-gate return (1);
11167c478bd9Sstevel@tonic-gate } else {
11177c478bd9Sstevel@tonic-gate return (0);
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate }
11207c478bd9Sstevel@tonic-gate
11217c478bd9Sstevel@tonic-gate /*
11227c478bd9Sstevel@tonic-gate * This routine expects a handle pointer, a Power Supply ID, and a PS logical
11237c478bd9Sstevel@tonic-gate * state switch ID. It check to see if the power cord has been removed from or
11247c478bd9Sstevel@tonic-gate * inserted to the power supply. It then updates the PS state accordingly.
11257c478bd9Sstevel@tonic-gate */
11267c478bd9Sstevel@tonic-gate static int
ac_power_check(psvc_opaque_t hdlp,char * id,char * ps_logical_state)11277c478bd9Sstevel@tonic-gate ac_power_check(psvc_opaque_t hdlp, char *id, char *ps_logical_state)
11287c478bd9Sstevel@tonic-gate {
11297c478bd9Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
11307c478bd9Sstevel@tonic-gate int32_t sensor_count;
11317c478bd9Sstevel@tonic-gate char *sensor_id;
11327c478bd9Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
11337c478bd9Sstevel@tonic-gate int unplugged, i;
11347c478bd9Sstevel@tonic-gate
11357c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
11367c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
11377c478bd9Sstevel@tonic-gate return (status);
11387c478bd9Sstevel@tonic-gate
11397c478bd9Sstevel@tonic-gate /*
11407c478bd9Sstevel@tonic-gate * Check for AC Power Cord. ac_unplugged will return true if the PS is
11417c478bd9Sstevel@tonic-gate * unplugged, a false is the PS is plugged in, and PSVC_FAILURE if the
11427c478bd9Sstevel@tonic-gate * call to get the state fails.
11437c478bd9Sstevel@tonic-gate */
11447c478bd9Sstevel@tonic-gate unplugged = ac_unplugged(hdlp, id);
11457c478bd9Sstevel@tonic-gate if (status == PSVC_FAILURE) {
11467c478bd9Sstevel@tonic-gate return (status);
11477c478bd9Sstevel@tonic-gate }
11487c478bd9Sstevel@tonic-gate
11497c478bd9Sstevel@tonic-gate /*
11507c478bd9Sstevel@tonic-gate * If power cord is not in, then we set the fault and error
11517c478bd9Sstevel@tonic-gate * states to "".
11527c478bd9Sstevel@tonic-gate * If power cord is in, then we check the devices.
11537c478bd9Sstevel@tonic-gate */
11547c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
11557c478bd9Sstevel@tonic-gate PSVC_DEV_FAULT_SENSOR);
11567c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS) {
11577c478bd9Sstevel@tonic-gate return (status);
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate
11607c478bd9Sstevel@tonic-gate if ((unplugged) && (strcmp(state, "NO AC POWER") != 0)) {
11617c478bd9Sstevel@tonic-gate /* set id's state to "NO AC POWER" */
11627c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
11637c478bd9Sstevel@tonic-gate "NO AC POWER");
11647c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
11657c478bd9Sstevel@tonic-gate return (status);
11667c478bd9Sstevel@tonic-gate /*
11677c478bd9Sstevel@tonic-gate * Set this state so that the FSP Fault LED lights
11687c478bd9Sstevel@tonic-gate * when there is no AC Power to the power supply.
11697c478bd9Sstevel@tonic-gate */
11707c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR,
11717c478bd9Sstevel@tonic-gate PSVC_ERROR);
11727c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
11737c478bd9Sstevel@tonic-gate return (status);
11747c478bd9Sstevel@tonic-gate
11757c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
11767c478bd9Sstevel@tonic-gate "NO AC POWER");
11777c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
11787c478bd9Sstevel@tonic-gate return (status);
11797c478bd9Sstevel@tonic-gate
11807c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s AC UNAVAILABLE"), id);
11817c478bd9Sstevel@tonic-gate
11827c478bd9Sstevel@tonic-gate /* Set fault sensor states to "" */
11837c478bd9Sstevel@tonic-gate for (i = 0; i < sensor_count; ++i) {
11847c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
11857c478bd9Sstevel@tonic-gate &sensor_id, PSVC_DEV_FAULT_SENSOR, i);
11867c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
11877c478bd9Sstevel@tonic-gate return (status);
11887c478bd9Sstevel@tonic-gate
11897c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, sensor_id,
11907c478bd9Sstevel@tonic-gate PSVC_FAULTID_ATTR, "");
11917c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
11927c478bd9Sstevel@tonic-gate return (status);
11937c478bd9Sstevel@tonic-gate }
11947c478bd9Sstevel@tonic-gate }
11957c478bd9Sstevel@tonic-gate
11967c478bd9Sstevel@tonic-gate /* Power cord is plugged in */
11977c478bd9Sstevel@tonic-gate if ((!unplugged) && (strcmp(state, "NO AC POWER") == 0)) {
11987c478bd9Sstevel@tonic-gate /* Default the state to "OK" */
11997c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
12007c478bd9Sstevel@tonic-gate PSVC_OK);
12017c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
12027c478bd9Sstevel@tonic-gate return (status);
12037c478bd9Sstevel@tonic-gate /* Default the PS_LOGICAL_STATE to "OK" */
12047c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR,
12057c478bd9Sstevel@tonic-gate PSVC_OK);
12067c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
12077c478bd9Sstevel@tonic-gate return (status);
12087c478bd9Sstevel@tonic-gate /* Display message */
12097c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s AC AVAILABLE"), id);
12107c478bd9Sstevel@tonic-gate }
12117c478bd9Sstevel@tonic-gate
12127c478bd9Sstevel@tonic-gate return (status);
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate
12157c478bd9Sstevel@tonic-gate int32_t
psvc_init_ps_presence(psvc_opaque_t hdlp,char * id)12167c478bd9Sstevel@tonic-gate psvc_init_ps_presence(psvc_opaque_t hdlp, char *id)
12177c478bd9Sstevel@tonic-gate {
12187c478bd9Sstevel@tonic-gate int err;
12197c478bd9Sstevel@tonic-gate int instance;
12207c478bd9Sstevel@tonic-gate boolean_t presence;
12217c478bd9Sstevel@tonic-gate
12227c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
12237c478bd9Sstevel@tonic-gate err |= psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence);
12247c478bd9Sstevel@tonic-gate ps_prev_present[instance] = ps_present[instance] = presence;
12257c478bd9Sstevel@tonic-gate return (err);
12267c478bd9Sstevel@tonic-gate }
12277c478bd9Sstevel@tonic-gate
12287c478bd9Sstevel@tonic-gate int32_t
psvc_ps_monitor_policy_0(psvc_opaque_t hdlp,char * id)12297c478bd9Sstevel@tonic-gate psvc_ps_monitor_policy_0(psvc_opaque_t hdlp, char *id)
12307c478bd9Sstevel@tonic-gate {
12317c478bd9Sstevel@tonic-gate int err;
12327c478bd9Sstevel@tonic-gate int instance;
12337c478bd9Sstevel@tonic-gate static int failed_last_time[2] = {0, 0};
1234298b7f4cSjfrank int retry;
12357c478bd9Sstevel@tonic-gate
12367c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
12377c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
12387c478bd9Sstevel@tonic-gate return (err);
12397c478bd9Sstevel@tonic-gate
12407c478bd9Sstevel@tonic-gate /* copy current presence to previous presence */
12417c478bd9Sstevel@tonic-gate ps_prev_present[instance] = ps_present[instance];
12427c478bd9Sstevel@tonic-gate
1243298b7f4cSjfrank retry = 0;
1244298b7f4cSjfrank do {
1245298b7f4cSjfrank if (retry)
1246298b7f4cSjfrank (void) sleep(retry_sleep_pshp);
1247298b7f4cSjfrank /* Get new presence */
1248298b7f4cSjfrank err = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR,
1249298b7f4cSjfrank &ps_present[instance]);
1250298b7f4cSjfrank if (err != PSVC_SUCCESS)
1251298b7f4cSjfrank goto out;
1252298b7f4cSjfrank retry++;
1253298b7f4cSjfrank } while ((retry < n_retry_pshp) &&
1254298b7f4cSjfrank (ps_present[instance] != ps_prev_present[instance]));
12557c478bd9Sstevel@tonic-gate
12567c478bd9Sstevel@tonic-gate /* Sustained Hotplug detected */
12577c478bd9Sstevel@tonic-gate if (ps_present[instance] != ps_prev_present[instance]) {
12587c478bd9Sstevel@tonic-gate err = handle_ps_hotplug(hdlp, id, ps_present[instance]);
12597c478bd9Sstevel@tonic-gate return (err);
12607c478bd9Sstevel@tonic-gate }
12617c478bd9Sstevel@tonic-gate
12627c478bd9Sstevel@tonic-gate /* If our power supply is not present, we're done */
12637c478bd9Sstevel@tonic-gate if (!ps_present[instance])
12647c478bd9Sstevel@tonic-gate return (PSVC_SUCCESS);
12657c478bd9Sstevel@tonic-gate
12667c478bd9Sstevel@tonic-gate err = check_i2c_access(hdlp, id);
12677c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS) {
12687c478bd9Sstevel@tonic-gate /* Quickie hotplug */
12697c478bd9Sstevel@tonic-gate if (ps_present[instance] == PSVC_PRESENT &&
12707c478bd9Sstevel@tonic-gate ps_prev_present[instance] == PSVC_PRESENT) {
12717c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Device %s removed", id);
12727c478bd9Sstevel@tonic-gate /* Reset prev_failed information */
12737c478bd9Sstevel@tonic-gate ps_reset_prev_failed(instance);
12747c478bd9Sstevel@tonic-gate ps_prev_present[instance] = 0;
12757c478bd9Sstevel@tonic-gate handle_ps_hotplug(hdlp, id, ps_present[instance]);
12767c478bd9Sstevel@tonic-gate /* We ignore the error on a quickie hotplug */
12777c478bd9Sstevel@tonic-gate return (PSVC_SUCCESS);
12787c478bd9Sstevel@tonic-gate }
12797c478bd9Sstevel@tonic-gate /* There was an actual i2c access error */
12807c478bd9Sstevel@tonic-gate goto out;
12817c478bd9Sstevel@tonic-gate }
12827c478bd9Sstevel@tonic-gate
12837c478bd9Sstevel@tonic-gate err = check_ps_state(hdlp, id);
12847c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
12857c478bd9Sstevel@tonic-gate goto out;
12867c478bd9Sstevel@tonic-gate
12877c478bd9Sstevel@tonic-gate failed_last_time[instance] = 0;
12887c478bd9Sstevel@tonic-gate return (err);
12897c478bd9Sstevel@tonic-gate
12907c478bd9Sstevel@tonic-gate out:
12917c478bd9Sstevel@tonic-gate if (! failed_last_time[instance]) {
12927c478bd9Sstevel@tonic-gate /*
12937c478bd9Sstevel@tonic-gate * We ignore the error condition the first time thru
12947c478bd9Sstevel@tonic-gate * because the PS could have been removed after (or
12957c478bd9Sstevel@tonic-gate * during) our call to check_ps_hotplug().
12967c478bd9Sstevel@tonic-gate *
12977c478bd9Sstevel@tonic-gate * If the problem is still there the next time, then
12987c478bd9Sstevel@tonic-gate * we'll raise a flag.
12997c478bd9Sstevel@tonic-gate *
13007c478bd9Sstevel@tonic-gate * The instance determines which power supply the policy
13017c478bd9Sstevel@tonic-gate * errored on. For instance PS0 might have failed and then
13027c478bd9Sstevel@tonic-gate * PS1 might have failed, but we'll display a warning
13037c478bd9Sstevel@tonic-gate * even though there might not be anything actually wrong.
13047c478bd9Sstevel@tonic-gate * The instance keeps track of which failure occurred so
13057c478bd9Sstevel@tonic-gate * we warn on the corresponding occurrence of errors.
13067c478bd9Sstevel@tonic-gate */
13077c478bd9Sstevel@tonic-gate failed_last_time[instance] = 1;
13087c478bd9Sstevel@tonic-gate return (PSVC_SUCCESS);
13097c478bd9Sstevel@tonic-gate }
13107c478bd9Sstevel@tonic-gate return (err);
13117c478bd9Sstevel@tonic-gate }
13127c478bd9Sstevel@tonic-gate
13137c478bd9Sstevel@tonic-gate static int
light_disk_fault_leds(psvc_opaque_t hdlp,char * id,boolean_t disk_presence)13147c478bd9Sstevel@tonic-gate light_disk_fault_leds(psvc_opaque_t hdlp, char *id, boolean_t disk_presence)
13157c478bd9Sstevel@tonic-gate {
13167c478bd9Sstevel@tonic-gate int err;
13177c478bd9Sstevel@tonic-gate int bit_nums[MAX_DISKS] = {6, 7};
13187c478bd9Sstevel@tonic-gate uint8_t led_masks[MAX_DISKS] = {0x40, 0x80};
13197c478bd9Sstevel@tonic-gate int instance;
13207c478bd9Sstevel@tonic-gate int bit_value;
13217c478bd9Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
13227c478bd9Sstevel@tonic-gate uint8_t byte;
13237c478bd9Sstevel@tonic-gate
13247c478bd9Sstevel@tonic-gate if (disk_presence != PSVC_PRESENT)
13257c478bd9Sstevel@tonic-gate return (PSVC_SUCCESS);
13267c478bd9Sstevel@tonic-gate
13277c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
13287c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
13297c478bd9Sstevel@tonic-gate return (err);
13307c478bd9Sstevel@tonic-gate
13317c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, "DISK_PORT", PSVC_GPIO_VALUE_ATTR,
13327c478bd9Sstevel@tonic-gate &byte);
13337c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
13347c478bd9Sstevel@tonic-gate return (err);
13357c478bd9Sstevel@tonic-gate
13367c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
13377c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
13387c478bd9Sstevel@tonic-gate return (err);
13397c478bd9Sstevel@tonic-gate if (strcmp(state, PSVC_OK) == 0 || strcmp(state, "") == 0) { /* OK */
13407c478bd9Sstevel@tonic-gate if (byte & led_masks[instance]) { /* Led is OFF */
13417c478bd9Sstevel@tonic-gate return (err); /* Done. */
13427c478bd9Sstevel@tonic-gate } else { /* Led is ON, Turn if OFF */
13437c478bd9Sstevel@tonic-gate bit_value = 1; /* Active Low */
13447c478bd9Sstevel@tonic-gate err = pcf8574_write_bit(hdlp, "DISK_PORT",
13457c478bd9Sstevel@tonic-gate bit_nums[instance], bit_value,
13467c478bd9Sstevel@tonic-gate DISKBP_MUST_BE_1);
13477c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
13487c478bd9Sstevel@tonic-gate return (err);
13497c478bd9Sstevel@tonic-gate }
13507c478bd9Sstevel@tonic-gate } else { /* Disk is NOT OK */
13517c478bd9Sstevel@tonic-gate if (byte & led_masks[instance]) { /* Led is OFF, Turn it ON */
13527c478bd9Sstevel@tonic-gate bit_value = 0; /* Active Low */
13537c478bd9Sstevel@tonic-gate err = pcf8574_write_bit(hdlp, "DISK_PORT",
13547c478bd9Sstevel@tonic-gate bit_nums[instance], bit_value,
13557c478bd9Sstevel@tonic-gate DISKBP_MUST_BE_1);
13567c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
13577c478bd9Sstevel@tonic-gate return (err);
13587c478bd9Sstevel@tonic-gate } else {
13597c478bd9Sstevel@tonic-gate return (err); /* Done. */
13607c478bd9Sstevel@tonic-gate }
13617c478bd9Sstevel@tonic-gate }
13627c478bd9Sstevel@tonic-gate return (err);
13637c478bd9Sstevel@tonic-gate }
13647c478bd9Sstevel@tonic-gate
13657c478bd9Sstevel@tonic-gate int
verify_disk_wwn(char * wwn)13667c478bd9Sstevel@tonic-gate verify_disk_wwn(char *wwn)
13677c478bd9Sstevel@tonic-gate {
13687c478bd9Sstevel@tonic-gate HBA_PORTATTRIBUTES hbaPortAttrs, discPortAttrs;
13697c478bd9Sstevel@tonic-gate HBA_HANDLE handle;
13707c478bd9Sstevel@tonic-gate HBA_STATUS status;
13717c478bd9Sstevel@tonic-gate HBA_ADAPTERATTRIBUTES hbaAttrs;
13727c478bd9Sstevel@tonic-gate HBA_UINT32 numberOfAdapters, hbaCount, hbaPort, discPort;
13737c478bd9Sstevel@tonic-gate char adaptername[256];
13747c478bd9Sstevel@tonic-gate char vwwn[WWN_SIZE * 2];
13757c478bd9Sstevel@tonic-gate char OSDeviceName[PATH_MAX + 1];
13767c478bd9Sstevel@tonic-gate int count, linksize;
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate /* Load common lib */
13797c478bd9Sstevel@tonic-gate status = HBA_LoadLibrary();
13807c478bd9Sstevel@tonic-gate if (status != HBA_STATUS_OK) {
13817c478bd9Sstevel@tonic-gate (void) HBA_FreeLibrary();
13827c478bd9Sstevel@tonic-gate return (HBA_STATUS_ERROR);
13837c478bd9Sstevel@tonic-gate }
13847c478bd9Sstevel@tonic-gate
13857c478bd9Sstevel@tonic-gate /*
13867c478bd9Sstevel@tonic-gate * Since devfs can store multiple instances
13877c478bd9Sstevel@tonic-gate * of a target the validity of the WWN of a disk is
13887c478bd9Sstevel@tonic-gate * verified with an actual probe of internal disks
13897c478bd9Sstevel@tonic-gate */
13907c478bd9Sstevel@tonic-gate
13917c478bd9Sstevel@tonic-gate /* Cycle through FC-AL Adapters and search for WWN */
13927c478bd9Sstevel@tonic-gate numberOfAdapters = HBA_GetNumberOfAdapters();
13937c478bd9Sstevel@tonic-gate for (hbaCount = 0; hbaCount < numberOfAdapters; hbaCount++) {
13947c478bd9Sstevel@tonic-gate if ((status = HBA_GetAdapterName(hbaCount, adaptername)) !=
13957c478bd9Sstevel@tonic-gate HBA_STATUS_OK)
13967c478bd9Sstevel@tonic-gate continue;
13977c478bd9Sstevel@tonic-gate
13987c478bd9Sstevel@tonic-gate handle = HBA_OpenAdapter(adaptername);
13997c478bd9Sstevel@tonic-gate if (handle == 0)
14007c478bd9Sstevel@tonic-gate continue;
14017c478bd9Sstevel@tonic-gate
14027c478bd9Sstevel@tonic-gate /* Get Adapter Attributes */
14037c478bd9Sstevel@tonic-gate if ((status = HBA_GetAdapterAttributes(handle,
14047c478bd9Sstevel@tonic-gate &hbaAttrs)) != HBA_STATUS_OK) {
14057c478bd9Sstevel@tonic-gate HBA_CloseAdapter(handle);
14067c478bd9Sstevel@tonic-gate continue;
14077c478bd9Sstevel@tonic-gate }
14087c478bd9Sstevel@tonic-gate
14097c478bd9Sstevel@tonic-gate /* Get Adapter's Port Attributes */
14107c478bd9Sstevel@tonic-gate for (hbaPort = 0;
14117c478bd9Sstevel@tonic-gate hbaPort < hbaAttrs.NumberOfPorts; hbaPort++) {
14127c478bd9Sstevel@tonic-gate if ((status = HBA_GetAdapterPortAttributes(handle,
14137c478bd9Sstevel@tonic-gate hbaPort, &hbaPortAttrs)) != HBA_STATUS_OK)
14147c478bd9Sstevel@tonic-gate continue;
14157c478bd9Sstevel@tonic-gate
14167c478bd9Sstevel@tonic-gate /*
14177c478bd9Sstevel@tonic-gate * Verify whether this is onboard controller.
14187c478bd9Sstevel@tonic-gate * HBAAPI provides path of symbol link to
14197c478bd9Sstevel@tonic-gate * to the qlc node therefore readlink() is
14207c478bd9Sstevel@tonic-gate * needed to obtain hard link
14217c478bd9Sstevel@tonic-gate */
14227c478bd9Sstevel@tonic-gate linksize = readlink(hbaPortAttrs.OSDeviceName,
14237c478bd9Sstevel@tonic-gate OSDeviceName, PATH_MAX);
14247c478bd9Sstevel@tonic-gate
14257c478bd9Sstevel@tonic-gate /*
14267c478bd9Sstevel@tonic-gate * If readlink does not return size of onboard
14277c478bd9Sstevel@tonic-gate * controller than don't bother checking device
14287c478bd9Sstevel@tonic-gate */
14297c478bd9Sstevel@tonic-gate if ((linksize + 1) != sizeof (ONBOARD_CONTR))
14307c478bd9Sstevel@tonic-gate continue;
14317c478bd9Sstevel@tonic-gate
14327c478bd9Sstevel@tonic-gate OSDeviceName[linksize] = '\0';
14337c478bd9Sstevel@tonic-gate if (strcmp(OSDeviceName, ONBOARD_CONTR) != 0)
14347c478bd9Sstevel@tonic-gate continue;
14357c478bd9Sstevel@tonic-gate
14367c478bd9Sstevel@tonic-gate /* Get Discovered Port Attributes */
14377c478bd9Sstevel@tonic-gate for (discPort = 0;
14387c478bd9Sstevel@tonic-gate discPort < hbaPortAttrs.NumberofDiscoveredPorts;
14397c478bd9Sstevel@tonic-gate discPort++) {
14407c478bd9Sstevel@tonic-gate status = HBA_GetDiscoveredPortAttributes(
14417c478bd9Sstevel@tonic-gate handle, hbaPort, discPort,
14427c478bd9Sstevel@tonic-gate &discPortAttrs);
14437c478bd9Sstevel@tonic-gate if (status != HBA_STATUS_OK)
14447c478bd9Sstevel@tonic-gate continue;
14457c478bd9Sstevel@tonic-gate
14467c478bd9Sstevel@tonic-gate /* Get target info */
14477c478bd9Sstevel@tonic-gate for (count = 0; count < WWN_SIZE; count++)
14487c478bd9Sstevel@tonic-gate (void) sprintf(&vwwn[count * 2],
14497c478bd9Sstevel@tonic-gate "%2.2x",
14507c478bd9Sstevel@tonic-gate discPortAttrs.NodeWWN.wwn[count]);
14517c478bd9Sstevel@tonic-gate
14527c478bd9Sstevel@tonic-gate if (strcmp(wwn, vwwn) == 0) {
14537c478bd9Sstevel@tonic-gate HBA_CloseAdapter(handle);
14547c478bd9Sstevel@tonic-gate (void) HBA_FreeLibrary();
14557c478bd9Sstevel@tonic-gate return (HBA_STATUS_OK);
14567c478bd9Sstevel@tonic-gate }
14577c478bd9Sstevel@tonic-gate
14587c478bd9Sstevel@tonic-gate }
14597c478bd9Sstevel@tonic-gate }
14607c478bd9Sstevel@tonic-gate HBA_CloseAdapter(handle);
14617c478bd9Sstevel@tonic-gate }
14627c478bd9Sstevel@tonic-gate (void) HBA_FreeLibrary();
14637c478bd9Sstevel@tonic-gate return (HBA_STATUS_ERROR_ILLEGAL_WWN);
14647c478bd9Sstevel@tonic-gate }
14657c478bd9Sstevel@tonic-gate
14667c478bd9Sstevel@tonic-gate static int
light_disk_ok2remove_leds(psvc_opaque_t hdlp,boolean_t * disk_present)14677c478bd9Sstevel@tonic-gate light_disk_ok2remove_leds(psvc_opaque_t hdlp, boolean_t *disk_present)
14687c478bd9Sstevel@tonic-gate {
14697c478bd9Sstevel@tonic-gate di_node_t node;
14707c478bd9Sstevel@tonic-gate di_node_t root_node;
14717c478bd9Sstevel@tonic-gate di_minor_t min_node;
14727c478bd9Sstevel@tonic-gate int *prop;
14737c478bd9Sstevel@tonic-gate int n;
14747c478bd9Sstevel@tonic-gate int target;
14757c478bd9Sstevel@tonic-gate int rv;
14767c478bd9Sstevel@tonic-gate int disk_online = 0;
14777c478bd9Sstevel@tonic-gate static int prev_online[MAX_DISKS] = {-1, -1};
14787c478bd9Sstevel@tonic-gate int bit_nums[MAX_DISKS] = {4, 5};
14797c478bd9Sstevel@tonic-gate int bit_val;
14807c478bd9Sstevel@tonic-gate int count;
14817c478bd9Sstevel@tonic-gate char *dev_path;
14827c478bd9Sstevel@tonic-gate char wwn[WWN_SIZE * 2];
14837c478bd9Sstevel@tonic-gate uchar_t *prop_wwn;
14847c478bd9Sstevel@tonic-gate
14857c478bd9Sstevel@tonic-gate root_node = di_init("/", DINFOCPYALL);
14867c478bd9Sstevel@tonic-gate if (root_node == DI_NODE_NIL)
14877c478bd9Sstevel@tonic-gate return (PSVC_FAILURE);
14887c478bd9Sstevel@tonic-gate
14897c478bd9Sstevel@tonic-gate for (node = di_drv_first_node(DISK_DRV, root_node);
14907c478bd9Sstevel@tonic-gate node != DI_NODE_NIL;
14917c478bd9Sstevel@tonic-gate node = di_drv_next_node(node)) {
14927c478bd9Sstevel@tonic-gate n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "target", &prop);
14937c478bd9Sstevel@tonic-gate if (n == -1)
14947c478bd9Sstevel@tonic-gate continue;
14957c478bd9Sstevel@tonic-gate target = *prop;
14967c478bd9Sstevel@tonic-gate if (target < 0 || target > 1)
14977c478bd9Sstevel@tonic-gate continue;
14987c478bd9Sstevel@tonic-gate
14997c478bd9Sstevel@tonic-gate if (! disk_present[target])
15007c478bd9Sstevel@tonic-gate continue;
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate dev_path = di_devfs_path(node);
15037c478bd9Sstevel@tonic-gate if (memcmp(dev_path, QLC_NODE, (sizeof (QLC_NODE) - 1)) != 0) {
15047c478bd9Sstevel@tonic-gate /*
15057c478bd9Sstevel@tonic-gate * This isn't our FC-AL controller, so this
15067c478bd9Sstevel@tonic-gate * must be an external disk on Loop B. Skip it.
15077c478bd9Sstevel@tonic-gate */
15087c478bd9Sstevel@tonic-gate di_devfs_path_free(dev_path);
15097c478bd9Sstevel@tonic-gate continue;
15107c478bd9Sstevel@tonic-gate }
15117c478bd9Sstevel@tonic-gate di_devfs_path_free(dev_path);
15127c478bd9Sstevel@tonic-gate
15137c478bd9Sstevel@tonic-gate /*
15147c478bd9Sstevel@tonic-gate * Verify if disk is valid by checking WWN
15157c478bd9Sstevel@tonic-gate * because devfs retains stale data.
15167c478bd9Sstevel@tonic-gate */
15177c478bd9Sstevel@tonic-gate n = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
15187c478bd9Sstevel@tonic-gate "node-wwn", &prop_wwn);
15197c478bd9Sstevel@tonic-gate if (n == -1)
15207c478bd9Sstevel@tonic-gate continue;
15217c478bd9Sstevel@tonic-gate
15227c478bd9Sstevel@tonic-gate for (count = 0; count < WWN_SIZE; count++)
15237c478bd9Sstevel@tonic-gate (void) sprintf(&wwn[count * 2], "%2.2x",
15247c478bd9Sstevel@tonic-gate prop_wwn[count]);
15257c478bd9Sstevel@tonic-gate
15267c478bd9Sstevel@tonic-gate n = verify_disk_wwn(wwn);
15277c478bd9Sstevel@tonic-gate if (n == HBA_STATUS_ERROR_ILLEGAL_WWN)
15287c478bd9Sstevel@tonic-gate continue;
15297c478bd9Sstevel@tonic-gate
15307c478bd9Sstevel@tonic-gate min_node = di_minor_next(node, DI_MINOR_NIL);
15317c478bd9Sstevel@tonic-gate disk_online = (min_node != DI_MINOR_NIL);
1532*71e32251Sanbui if ((disk_online == 0) && (prev_online[target] == 1)) {
15337c478bd9Sstevel@tonic-gate /* Light Led */
15347c478bd9Sstevel@tonic-gate bit_val = 0;
15357c478bd9Sstevel@tonic-gate rv = pcf8574_write_bit(hdlp, "DISK_PORT",
15367c478bd9Sstevel@tonic-gate bit_nums[target], bit_val, DISKBP_MUST_BE_1);
15377c478bd9Sstevel@tonic-gate if (rv != PSVC_SUCCESS)
15387c478bd9Sstevel@tonic-gate goto done;
1539*71e32251Sanbui } else if ((prev_online[target] == 0) && (disk_online == 1)) {
15407c478bd9Sstevel@tonic-gate /* Unlight Led */
15417c478bd9Sstevel@tonic-gate bit_val = 1;
15427c478bd9Sstevel@tonic-gate rv = pcf8574_write_bit(hdlp, "DISK_PORT",
15437c478bd9Sstevel@tonic-gate bit_nums[target], bit_val, DISKBP_MUST_BE_1);
15447c478bd9Sstevel@tonic-gate if (rv != PSVC_SUCCESS)
15457c478bd9Sstevel@tonic-gate goto done;
15467c478bd9Sstevel@tonic-gate }
15477c478bd9Sstevel@tonic-gate if (disk_online != prev_online[target])
15487c478bd9Sstevel@tonic-gate prev_online[target] = disk_online;
15497c478bd9Sstevel@tonic-gate }
15507c478bd9Sstevel@tonic-gate done:
15517c478bd9Sstevel@tonic-gate di_fini(root_node);
15527c478bd9Sstevel@tonic-gate return (rv);
15537c478bd9Sstevel@tonic-gate }
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate static int
check_disk_fault(psvc_opaque_t hdlp,char * id,boolean_t disk_presence)15567c478bd9Sstevel@tonic-gate check_disk_fault(psvc_opaque_t hdlp, char *id, boolean_t disk_presence)
15577c478bd9Sstevel@tonic-gate {
15587c478bd9Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
15597c478bd9Sstevel@tonic-gate int32_t fault_on = 0;
15607c478bd9Sstevel@tonic-gate char *sensor_id;
15617c478bd9Sstevel@tonic-gate char disk_state[PSVC_MAX_STR_LEN];
15627c478bd9Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
15637c478bd9Sstevel@tonic-gate char fault[PSVC_MAX_STR_LEN];
15647c478bd9Sstevel@tonic-gate boolean_t change_of_state = 0;
15657c478bd9Sstevel@tonic-gate
15667c478bd9Sstevel@tonic-gate if (disk_presence != PSVC_PRESENT)
15677c478bd9Sstevel@tonic-gate return (PSVC_SUCCESS);
15687c478bd9Sstevel@tonic-gate
15697c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, disk_state);
15707c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
15717c478bd9Sstevel@tonic-gate return (status);
15727c478bd9Sstevel@tonic-gate
15737c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
15747c478bd9Sstevel@tonic-gate &sensor_id, PSVC_DEV_FAULT_SENSOR, 0);
15757c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
15767c478bd9Sstevel@tonic-gate return (status);
15777c478bd9Sstevel@tonic-gate
15787c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, sensor_id, PSVC_SWITCH_STATE_ATTR, state);
15797c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
15807c478bd9Sstevel@tonic-gate return (status);
15817c478bd9Sstevel@tonic-gate
15827c478bd9Sstevel@tonic-gate /* Fault detected */
15837c478bd9Sstevel@tonic-gate if (strcmp(state, PSVC_SWITCH_ON) == 0) {
15847c478bd9Sstevel@tonic-gate strlcpy(state, PSVC_ERROR, sizeof (state));
15857c478bd9Sstevel@tonic-gate strlcpy(fault, PSVC_GEN_FAULT, sizeof (fault));
15867c478bd9Sstevel@tonic-gate fault_on = 1;
15877c478bd9Sstevel@tonic-gate } else { /* No fault detected */
15887c478bd9Sstevel@tonic-gate if (strcmp(disk_state, PSVC_OK) != 0)
15897c478bd9Sstevel@tonic-gate change_of_state = 1;
15907c478bd9Sstevel@tonic-gate strlcpy(state, PSVC_OK, sizeof (state));
15917c478bd9Sstevel@tonic-gate strlcpy(fault, PSVC_NO_FAULT, sizeof (fault));
15927c478bd9Sstevel@tonic-gate }
15937c478bd9Sstevel@tonic-gate
15947c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
15957c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
15967c478bd9Sstevel@tonic-gate return (status);
15977c478bd9Sstevel@tonic-gate
15987c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
15997c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
16007c478bd9Sstevel@tonic-gate return (status);
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate if (fault_on) {
16037c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("Fault detected: %s"), id);
16047c478bd9Sstevel@tonic-gate
16057c478bd9Sstevel@tonic-gate } else {
16067c478bd9Sstevel@tonic-gate if (change_of_state)
16077c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("Notice: %s okay"), id);
16087c478bd9Sstevel@tonic-gate }
16097c478bd9Sstevel@tonic-gate return (PSVC_SUCCESS);
16107c478bd9Sstevel@tonic-gate }
16117c478bd9Sstevel@tonic-gate
16127c478bd9Sstevel@tonic-gate static int
check_disk_hotplug(psvc_opaque_t hdlp,char * id,boolean_t * disk_presence,int disk_instance)16137c478bd9Sstevel@tonic-gate check_disk_hotplug(psvc_opaque_t hdlp, char *id, boolean_t *disk_presence,
16147c478bd9Sstevel@tonic-gate int disk_instance)
16157c478bd9Sstevel@tonic-gate {
16167c478bd9Sstevel@tonic-gate boolean_t presence;
16177c478bd9Sstevel@tonic-gate boolean_t previous_presence;
16187c478bd9Sstevel@tonic-gate int32_t status = PSVC_SUCCESS;
16197c478bd9Sstevel@tonic-gate char label[PSVC_MAX_STR_LEN];
16207c478bd9Sstevel@tonic-gate uint8_t disk_leds[MAX_DISKS][2] = {{4, 6}, {5, 7}};
1621298b7f4cSjfrank int retry;
16227c478bd9Sstevel@tonic-gate
16237c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR,
16247c478bd9Sstevel@tonic-gate &previous_presence);
16257c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
16267c478bd9Sstevel@tonic-gate return (status);
16277c478bd9Sstevel@tonic-gate
1628298b7f4cSjfrank retry = 0;
1629298b7f4cSjfrank do {
1630298b7f4cSjfrank if (retry)
1631298b7f4cSjfrank (void) sleep(retry_sleep_diskhp);
1632298b7f4cSjfrank status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR,
1633298b7f4cSjfrank &presence);
1634298b7f4cSjfrank if (status != PSVC_SUCCESS)
1635298b7f4cSjfrank return (status);
1636298b7f4cSjfrank retry++;
1637298b7f4cSjfrank } while ((retry < n_retry_diskhp) &&
1638298b7f4cSjfrank (presence != previous_presence));
1639298b7f4cSjfrank
16407c478bd9Sstevel@tonic-gate *disk_presence = presence;
16417c478bd9Sstevel@tonic-gate
16427c478bd9Sstevel@tonic-gate if (presence != previous_presence) {
16437c478bd9Sstevel@tonic-gate char parent_path[PICL_PROPNAMELEN_MAX];
16447c478bd9Sstevel@tonic-gate picl_nodehdl_t child_node;
16457c478bd9Sstevel@tonic-gate
16467c478bd9Sstevel@tonic-gate status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
16477c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
16487c478bd9Sstevel@tonic-gate return (status);
16497c478bd9Sstevel@tonic-gate
16507c478bd9Sstevel@tonic-gate /* return parent path and node for an object */
16517c478bd9Sstevel@tonic-gate psvcplugin_lookup(id, parent_path, &child_node);
16527c478bd9Sstevel@tonic-gate
16537c478bd9Sstevel@tonic-gate if (presence == PSVC_PRESENT) {
16547c478bd9Sstevel@tonic-gate picl_nodehdl_t parent_node;
16557c478bd9Sstevel@tonic-gate char state[PSVC_MAX_STR_LEN];
16567c478bd9Sstevel@tonic-gate char fault[PSVC_MAX_STR_LEN];
16577c478bd9Sstevel@tonic-gate
16587c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s inserted"), label);
16597c478bd9Sstevel@tonic-gate strlcpy(state, PSVC_OK, sizeof (state));
16607c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
16617c478bd9Sstevel@tonic-gate state);
16627c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
16637c478bd9Sstevel@tonic-gate return (status);
16647c478bd9Sstevel@tonic-gate
16657c478bd9Sstevel@tonic-gate strlcpy(fault, PSVC_NO_FAULT, sizeof (fault));
16667c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
16677c478bd9Sstevel@tonic-gate fault);
16687c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS) {
16697c478bd9Sstevel@tonic-gate return (status);
16707c478bd9Sstevel@tonic-gate }
16717c478bd9Sstevel@tonic-gate
16727c478bd9Sstevel@tonic-gate status = ptree_get_node_by_path(parent_path,
16737c478bd9Sstevel@tonic-gate &parent_node);
16747c478bd9Sstevel@tonic-gate if (status != PICL_SUCCESS)
16757c478bd9Sstevel@tonic-gate return (PSVC_FAILURE);
16767c478bd9Sstevel@tonic-gate status = ptree_add_node(parent_node, child_node);
16777c478bd9Sstevel@tonic-gate if (status != PICL_SUCCESS)
16787c478bd9Sstevel@tonic-gate return (PSVC_FAILURE);
16797c478bd9Sstevel@tonic-gate } else {
16807c478bd9Sstevel@tonic-gate /*
16817c478bd9Sstevel@tonic-gate * Disk Removed so we need to turn off these LEDs:
16827c478bd9Sstevel@tonic-gate * DISKx_FLT_LED
16837c478bd9Sstevel@tonic-gate * DISKx_REMOVE_LED
16847c478bd9Sstevel@tonic-gate */
16857c478bd9Sstevel@tonic-gate int i;
16867c478bd9Sstevel@tonic-gate int bit_val = 1; /* Active Low */
16877c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) {
16887c478bd9Sstevel@tonic-gate status = pcf8574_write_bit(hdlp, "DISK_PORT",
16897c478bd9Sstevel@tonic-gate disk_leds[disk_instance][i], bit_val,
16907c478bd9Sstevel@tonic-gate DISKBP_MUST_BE_1);
16917c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
16927c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Failed in turning off"
16937c478bd9Sstevel@tonic-gate " %d's LEDs", id);
16947c478bd9Sstevel@tonic-gate }
16957c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("Device %s removed"), label);
16967c478bd9Sstevel@tonic-gate ptree_delete_node(child_node);
16977c478bd9Sstevel@tonic-gate }
16987c478bd9Sstevel@tonic-gate }
16997c478bd9Sstevel@tonic-gate
17007c478bd9Sstevel@tonic-gate status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence);
17017c478bd9Sstevel@tonic-gate if (status != PSVC_SUCCESS)
17027c478bd9Sstevel@tonic-gate return (status);
17037c478bd9Sstevel@tonic-gate
17047c478bd9Sstevel@tonic-gate return (status);
17057c478bd9Sstevel@tonic-gate }
17067c478bd9Sstevel@tonic-gate
17077c478bd9Sstevel@tonic-gate int32_t
psvc_disk_monitor_policy_0(psvc_opaque_t hdlp,char * id)17087c478bd9Sstevel@tonic-gate psvc_disk_monitor_policy_0(psvc_opaque_t hdlp, char *id)
17097c478bd9Sstevel@tonic-gate {
17107c478bd9Sstevel@tonic-gate int rv, err, i;
17117c478bd9Sstevel@tonic-gate char *disks[MAX_DISKS] = {"DISK0", "DISK1"};
17127c478bd9Sstevel@tonic-gate int saved_errno = 0;
17137c478bd9Sstevel@tonic-gate boolean_t disk_present[MAX_DISKS] = {0, 0};
17147c478bd9Sstevel@tonic-gate
17157c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_DISKS; i++) {
17167c478bd9Sstevel@tonic-gate err = check_disk_hotplug(hdlp, disks[i], &disk_present[i], i);
17177c478bd9Sstevel@tonic-gate if (err) saved_errno = errno;
17187c478bd9Sstevel@tonic-gate rv = err;
17197c478bd9Sstevel@tonic-gate
17207c478bd9Sstevel@tonic-gate err = check_disk_fault(hdlp, disks[i], disk_present[i]);
17217c478bd9Sstevel@tonic-gate if (err) saved_errno = errno;
17227c478bd9Sstevel@tonic-gate rv |= err;
17237c478bd9Sstevel@tonic-gate
17247c478bd9Sstevel@tonic-gate err |= light_disk_fault_leds(hdlp, disks[i], disk_present[i]);
17257c478bd9Sstevel@tonic-gate if (err) saved_errno = errno;
17267c478bd9Sstevel@tonic-gate rv |= err;
17277c478bd9Sstevel@tonic-gate }
17287c478bd9Sstevel@tonic-gate
17297c478bd9Sstevel@tonic-gate err = light_disk_ok2remove_leds(hdlp, disk_present);
17307c478bd9Sstevel@tonic-gate if (err) saved_errno = errno;
17317c478bd9Sstevel@tonic-gate rv |= err;
17327c478bd9Sstevel@tonic-gate
17337c478bd9Sstevel@tonic-gate errno = saved_errno;
17347c478bd9Sstevel@tonic-gate return (rv);
17357c478bd9Sstevel@tonic-gate }
17367c478bd9Sstevel@tonic-gate
17377c478bd9Sstevel@tonic-gate /*
17387c478bd9Sstevel@tonic-gate * Read in temperature thresholds from FRU Prom and update the
17397c478bd9Sstevel@tonic-gate * default values.
17407c478bd9Sstevel@tonic-gate */
17417c478bd9Sstevel@tonic-gate
17427c478bd9Sstevel@tonic-gate #define START_OFFSET 0x1800 /* Last 2K of SEEPROM */
17437c478bd9Sstevel@tonic-gate #define NUM_SEG_OFFSET 0x1805 /* Number of segments */
17447c478bd9Sstevel@tonic-gate #define SEG_TABLE_OFFSET 0x1806 /* Segment description tables */
17457c478bd9Sstevel@tonic-gate
17467c478bd9Sstevel@tonic-gate static int32_t
read_sc_segment(psvc_opaque_t hdlp,char * id,char * fru_id,int offset)17477c478bd9Sstevel@tonic-gate read_sc_segment(psvc_opaque_t hdlp, char *id, char *fru_id, int offset)
17487c478bd9Sstevel@tonic-gate {
17497c478bd9Sstevel@tonic-gate static int thresh_names[] = {
17507c478bd9Sstevel@tonic-gate PSVC_HW_LO_SHUT_ATTR,
17517c478bd9Sstevel@tonic-gate PSVC_LO_SHUT_ATTR,
17527c478bd9Sstevel@tonic-gate PSVC_LO_WARN_ATTR,
17537c478bd9Sstevel@tonic-gate PSVC_NOT_USED, /* LOW MODE */
17547c478bd9Sstevel@tonic-gate PSVC_OPTIMAL_TEMP_ATTR,
17557c478bd9Sstevel@tonic-gate PSVC_HI_WARN_ATTR,
17567c478bd9Sstevel@tonic-gate PSVC_HI_SHUT_ATTR,
17577c478bd9Sstevel@tonic-gate PSVC_HW_HI_SHUT_ATTR
17587c478bd9Sstevel@tonic-gate };
17597c478bd9Sstevel@tonic-gate int8_t amb_temp_array[8];
17607c478bd9Sstevel@tonic-gate int i;
17617c478bd9Sstevel@tonic-gate fru_info_t fru_info;
17627c478bd9Sstevel@tonic-gate int err;
17637c478bd9Sstevel@tonic-gate
17647c478bd9Sstevel@tonic-gate fru_info.buf_start = offset + 8;
17657c478bd9Sstevel@tonic-gate fru_info.buf = amb_temp_array;
17667c478bd9Sstevel@tonic-gate fru_info.read_size = 8;
17677c478bd9Sstevel@tonic-gate
17687c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, fru_id, PSVC_FRU_INFO_ATTR, &fru_info);
17697c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
17707c478bd9Sstevel@tonic-gate return (err);
17717c478bd9Sstevel@tonic-gate
17727c478bd9Sstevel@tonic-gate for (i = 0; i < 8; i++) {
17737c478bd9Sstevel@tonic-gate int32_t temp = amb_temp_array[i];
17747c478bd9Sstevel@tonic-gate if (thresh_names[i] == PSVC_NOT_USED)
17757c478bd9Sstevel@tonic-gate continue;
17767c478bd9Sstevel@tonic-gate err = psvc_set_attr(hdlp, id, thresh_names[i], &temp);
17777c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
17787c478bd9Sstevel@tonic-gate return (err);
17797c478bd9Sstevel@tonic-gate }
17807c478bd9Sstevel@tonic-gate return (PSVC_SUCCESS);
17817c478bd9Sstevel@tonic-gate }
17827c478bd9Sstevel@tonic-gate
17837c478bd9Sstevel@tonic-gate int32_t
update_disk_bp_temp_thresholds(psvc_opaque_t hdlp,char * id)17847c478bd9Sstevel@tonic-gate update_disk_bp_temp_thresholds(psvc_opaque_t hdlp, char *id)
17857c478bd9Sstevel@tonic-gate {
17867c478bd9Sstevel@tonic-gate
17877c478bd9Sstevel@tonic-gate char *fru;
17887c478bd9Sstevel@tonic-gate fru_info_t fru_info;
17897c478bd9Sstevel@tonic-gate int16_t seg_offset;
17907c478bd9Sstevel@tonic-gate int8_t byte;
17917c478bd9Sstevel@tonic-gate int8_t seg_count;
17927c478bd9Sstevel@tonic-gate char seg_name[2];
17937c478bd9Sstevel@tonic-gate int current_offset, i, err;
17947c478bd9Sstevel@tonic-gate
17957c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &fru, PSVC_FRU, 0);
17967c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
17977c478bd9Sstevel@tonic-gate return (err);
17987c478bd9Sstevel@tonic-gate
17997c478bd9Sstevel@tonic-gate /* Sanity Check */
18007c478bd9Sstevel@tonic-gate fru_info.buf_start = START_OFFSET;
18017c478bd9Sstevel@tonic-gate fru_info.buf = &byte;
18027c478bd9Sstevel@tonic-gate fru_info.read_size = 1;
18037c478bd9Sstevel@tonic-gate
18047c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info);
18057c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
18067c478bd9Sstevel@tonic-gate return (err);
18077c478bd9Sstevel@tonic-gate if (*fru_info.buf != 8) {
18087c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Notice: FRU Prom %s not programmed", fru);
18097c478bd9Sstevel@tonic-gate }
18107c478bd9Sstevel@tonic-gate /* Should do CRC Check on fru */
18117c478bd9Sstevel@tonic-gate
18127c478bd9Sstevel@tonic-gate /* Get Segment Count */
18137c478bd9Sstevel@tonic-gate fru_info.buf_start = NUM_SEG_OFFSET;
18147c478bd9Sstevel@tonic-gate fru_info.buf = &seg_count;
18157c478bd9Sstevel@tonic-gate fru_info.read_size = 1;
18167c478bd9Sstevel@tonic-gate
18177c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info);
18187c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
18197c478bd9Sstevel@tonic-gate return (err);
18207c478bd9Sstevel@tonic-gate
18217c478bd9Sstevel@tonic-gate current_offset = SEG_TABLE_OFFSET;
18227c478bd9Sstevel@tonic-gate for (i = 0; i < seg_count; i++) {
18237c478bd9Sstevel@tonic-gate fru_info.buf_start = current_offset;
18247c478bd9Sstevel@tonic-gate fru_info.buf = seg_name;
18257c478bd9Sstevel@tonic-gate fru_info.read_size = 2;
18267c478bd9Sstevel@tonic-gate err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info);
18277c478bd9Sstevel@tonic-gate if (err != PSVC_SUCCESS)
18287c478bd9Sstevel@tonic-gate return (err);
18297c478bd9Sstevel@tonic-gate
18307c478bd9Sstevel@tonic-gate if (memcmp(seg_name, "SC", 2) == 0) {
18317c478bd9Sstevel@tonic-gate current_offset += 6; /* Skip over description */
18327c478bd9Sstevel@tonic-gate fru_info.buf_start = current_offset;
18337c478bd9Sstevel@tonic-gate fru_info.buf = (char *)&seg_offset;
18347c478bd9Sstevel@tonic-gate fru_info.read_size = 2;
18357c478bd9Sstevel@tonic-gate psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
18367c478bd9Sstevel@tonic-gate &fru_info);
18377c478bd9Sstevel@tonic-gate return (read_sc_segment(hdlp, id, fru, seg_offset));
18387c478bd9Sstevel@tonic-gate }
18397c478bd9Sstevel@tonic-gate current_offset += 10;
18407c478bd9Sstevel@tonic-gate }
18417c478bd9Sstevel@tonic-gate
18427c478bd9Sstevel@tonic-gate return (PSVC_SUCCESS);
18437c478bd9Sstevel@tonic-gate }
1844