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