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