10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*958Sjfrank  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Littleneck platform specific environment monitoring policies
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include	<syslog.h>
340Sstevel@tonic-gate #include	<unistd.h>
350Sstevel@tonic-gate #include	<stdio.h>
360Sstevel@tonic-gate #include 	<libintl.h>
370Sstevel@tonic-gate #include	<string.h>
380Sstevel@tonic-gate #include	<stdlib.h>
390Sstevel@tonic-gate #include	<errno.h>
400Sstevel@tonic-gate #include	<sys/types.h>
410Sstevel@tonic-gate #include	<fcntl.h>
420Sstevel@tonic-gate #include	<sys/time.h>
430Sstevel@tonic-gate #include	<sys/time_impl.h>
440Sstevel@tonic-gate #include	<sys/signal.h>
450Sstevel@tonic-gate #include	<sys/devctl.h>
460Sstevel@tonic-gate #include	<libdevinfo.h>
470Sstevel@tonic-gate #include	<libdevice.h>
480Sstevel@tonic-gate #include	<picl.h>
490Sstevel@tonic-gate #include	<picltree.h>
50*958Sjfrank #include	<limits.h>
51*958Sjfrank #include	<sys/systeminfo.h>
520Sstevel@tonic-gate #include	<psvc_objects.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /*LINTLIBRARY*/
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #define	LOWTEMP_CRITICAL_MSG		\
570Sstevel@tonic-gate 	gettext("CRITICAL : LOW TEMPERATURE DETECTED %d, %s")
580Sstevel@tonic-gate #define	LOWTEMP_WARNING_MSG		\
590Sstevel@tonic-gate 	gettext("WARNING : LOW TEMPERATURE DETECTED %d, %s")
600Sstevel@tonic-gate #define	HIGHTEMP_CRITICAL_MSG		\
610Sstevel@tonic-gate 	gettext("CRITICAL : HIGH TEMPERATURE DETECTED %d, %s")
620Sstevel@tonic-gate #define	HIGHTEMP_WARNING_MSG		\
630Sstevel@tonic-gate 	gettext("WARNING : HIGH TEMPERATURE DETECTED %d, %s")
640Sstevel@tonic-gate #define	DEVICE_INSERTED_MSG	gettext("Device %s inserted")
650Sstevel@tonic-gate #define	DEVICE_REMOVED_MSG	gettext("Device %s removed")
660Sstevel@tonic-gate #define	PS_TYPE_MSG			\
670Sstevel@tonic-gate 	gettext("WARNING: Incorrect type power supply inserted, device %s")
680Sstevel@tonic-gate #define	DEVICE_FAILURE_MSG		\
690Sstevel@tonic-gate 	gettext("WARNING: Device %s failure detected by sensor %s\n")
700Sstevel@tonic-gate #define	DEVICE_OK_MSG	gettext("Device %s OK")
710Sstevel@tonic-gate #define	DEVTREE_NODE_CREATE_FAILED	\
720Sstevel@tonic-gate 	gettext("psvc PICL plugin: Failed to create node for %s, errno = %d")
730Sstevel@tonic-gate #define	DEVTREE_NODE_DELETE_FAILED	\
740Sstevel@tonic-gate 	gettext("psvc PICL plugin: Failed to delete node for %s, errno = %d")
750Sstevel@tonic-gate #define	NO_FRU_INFO			\
760Sstevel@tonic-gate 	gettext("No FRU Information for %s using default temperatures\n")
770Sstevel@tonic-gate 
780Sstevel@tonic-gate static char *shutdown_string = "shutdown -y -g 60 -i 5 \"OVERTEMP condition\"";
790Sstevel@tonic-gate 
800Sstevel@tonic-gate typedef struct seg_desc {
810Sstevel@tonic-gate 	int32_t segdesc;
820Sstevel@tonic-gate 	int16_t segoffset;
830Sstevel@tonic-gate 	int16_t seglength;
840Sstevel@tonic-gate } seg_desc_t;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate static int32_t find_segment(psvc_opaque_t hdlp, char *fru, seg_desc_t *segment,
870Sstevel@tonic-gate     char *seg_to_find);
880Sstevel@tonic-gate 
890Sstevel@tonic-gate static int temp_attr[] = {
900Sstevel@tonic-gate 	PSVC_HW_HI_SHUT_ATTR, PSVC_HI_SHUT_ATTR, PSVC_HI_WARN_ATTR,
910Sstevel@tonic-gate 	PSVC_LO_WARN_ATTR, PSVC_LO_SHUT_ATTR, PSVC_HW_LO_SHUT_ATTR
920Sstevel@tonic-gate };
930Sstevel@tonic-gate 
940Sstevel@tonic-gate #define	MAX_TEMP_ATTR	(sizeof (temp_attr)/sizeof (temp_attr[0]))
950Sstevel@tonic-gate #define	TEMP_OFFSET	12
960Sstevel@tonic-gate #define	PART_NO_OFFSET	152
970Sstevel@tonic-gate #define	NUM_OF_SEG_ADDR	0x1805
980Sstevel@tonic-gate #define	SEG_DESC_START 	0x1806
990Sstevel@tonic-gate #define	PSVC_NO_DEVICE 	-2
1000Sstevel@tonic-gate 
101*958Sjfrank /*
102*958Sjfrank  * The I2C bus is noisy, and the state may be incorrectly reported as
103*958Sjfrank  * having changed.  When the state changes, we attempt to confirm by
104*958Sjfrank  * retrying.  If any retries indicate that the state has not changed, we
105*958Sjfrank  * assume the state change(s) were incorrect and the state has not changed.
106*958Sjfrank  * The following variables are used to store the tuneable values read in
107*958Sjfrank  * from the optional i2cparam.conf file for this shared object library.
108*958Sjfrank  */
109*958Sjfrank static int n_retry_temp = PSVC_THRESHOLD_COUNTER;
110*958Sjfrank static int retry_sleep_temp = 1;
111*958Sjfrank static int n_retry_hotplug = PSVC_NUM_OF_RETRIES;
112*958Sjfrank static int retry_sleep_hotplug = 1;
113*958Sjfrank static int n_retry_temp_shutdown = PSVC_NUM_OF_RETRIES;
114*958Sjfrank static int retry_sleep_temp_shutdown = 1;
115*958Sjfrank 
116*958Sjfrank typedef struct {
117*958Sjfrank 	int *pvar;
118*958Sjfrank 	char *texttag;
119*958Sjfrank } i2c_noise_param_t;
120*958Sjfrank 
121*958Sjfrank static i2c_noise_param_t i2cparams[] = {
122*958Sjfrank 	&n_retry_temp, "n_retry_temp",
123*958Sjfrank 	&retry_sleep_temp, "retry_sleep_temp",
124*958Sjfrank 	&n_retry_hotplug, "n_retry_hotplug",
125*958Sjfrank 	&retry_sleep_hotplug, "retry_sleep_hotplug",
126*958Sjfrank 	NULL, NULL
127*958Sjfrank };
128*958Sjfrank 
129*958Sjfrank #pragma init(i2cparams_load)
130*958Sjfrank 
131*958Sjfrank static void
i2cparams_debug(i2c_noise_param_t * pi2cparams,char * platform,int usingDefaults)132*958Sjfrank i2cparams_debug(i2c_noise_param_t *pi2cparams, char *platform,
133*958Sjfrank 	int usingDefaults)
134*958Sjfrank {
135*958Sjfrank 	char s[128];
136*958Sjfrank 	i2c_noise_param_t *p;
137*958Sjfrank 
138*958Sjfrank 	if (!usingDefaults) {
139*958Sjfrank 		(void) snprintf(s, sizeof (s),
140*958Sjfrank 		    "# Values from /usr/platform/%s/lib/i2cparam.conf\n",
141*958Sjfrank 		    platform);
142*958Sjfrank 		syslog(LOG_WARNING, "%s", s);
143*958Sjfrank 	} else {
144*958Sjfrank 		/* no file - we're using the defaults */
145*958Sjfrank 		(void) snprintf(s, sizeof (s),
146*958Sjfrank "# No /usr/platform/%s/lib/i2cparam.conf file, using defaults\n",
147*958Sjfrank 		    platform);
148*958Sjfrank 	}
149*958Sjfrank 	(void) fputs(s, stdout);
150*958Sjfrank 	p = pi2cparams;
151*958Sjfrank 	while (p->pvar != NULL) {
152*958Sjfrank 		(void) snprintf(s, sizeof (s), "%s %d\n", p->texttag,
153*958Sjfrank 		    *(p->pvar));
154*958Sjfrank 		if (!usingDefaults)
155*958Sjfrank 			syslog(LOG_WARNING, "%s", s);
156*958Sjfrank 		(void) fputs(s, stdout);
157*958Sjfrank 		p++;
158*958Sjfrank 	}
159*958Sjfrank }
160*958Sjfrank 
161*958Sjfrank static void
i2cparams_load(void)162*958Sjfrank i2cparams_load(void)
163*958Sjfrank {
164*958Sjfrank 	FILE *fp;
165*958Sjfrank 	char filename[PATH_MAX];
166*958Sjfrank 	char platform[64];
167*958Sjfrank 	char s[128];
168*958Sjfrank 	char var[128];
169*958Sjfrank 	int val;
170*958Sjfrank 	i2c_noise_param_t *p;
171*958Sjfrank 
172*958Sjfrank 	if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
173*958Sjfrank 		syslog(LOG_ERR, "sysinfo error %s\n", strerror(errno));
174*958Sjfrank 		return;
175*958Sjfrank 	}
176*958Sjfrank 	(void) snprintf(filename, sizeof (filename),
177*958Sjfrank 	    "/usr/platform/%s/lib/i2cparam.conf", platform);
178*958Sjfrank 	/* read thru the i2cparam.conf file and set variables */
179*958Sjfrank 	if ((fp = fopen(filename, "r")) != NULL) {
180*958Sjfrank 		while (fgets(s, sizeof (s), fp) != NULL) {
181*958Sjfrank 			if (s[0] == '#') /* skip comment lines */
182*958Sjfrank 				continue;
183*958Sjfrank 			/* try to find a string match and get the value */
184*958Sjfrank 			if (sscanf(s, "%127s %d", var, &val) != 2)
185*958Sjfrank 				continue;
186*958Sjfrank 			if (val < 1)
187*958Sjfrank 				val = 1;  /* clamp min value */
188*958Sjfrank 			p = &(i2cparams[0]);
189*958Sjfrank 			while (p->pvar != NULL) {
190*958Sjfrank 				if (strncmp(p->texttag, var, sizeof (var)) ==
191*958Sjfrank 				    0) {
192*958Sjfrank 					*(p->pvar) = val;
193*958Sjfrank 					break;
194*958Sjfrank 				}
195*958Sjfrank 				p++;
196*958Sjfrank 			}
197*958Sjfrank 		}
198*958Sjfrank 		(void) fclose(fp);
199*958Sjfrank 	}
200*958Sjfrank 	/* output the values of the parameters */
201*958Sjfrank 	i2cparams_debug(&(i2cparams[0]), platform, ((fp == NULL)? 1 : 0));
202*958Sjfrank }
203*958Sjfrank 
204*958Sjfrank 
2050Sstevel@tonic-gate int32_t
find_segment(psvc_opaque_t hdlp,char * fru,seg_desc_t * segment,char seg_to_find[2])2060Sstevel@tonic-gate find_segment(psvc_opaque_t hdlp, char *fru, seg_desc_t *segment,
2070Sstevel@tonic-gate     char seg_to_find[2])
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate 	int32_t seg_found = 0, status;
2100Sstevel@tonic-gate 	int32_t seg_desc_start = SEG_DESC_START, j;
2110Sstevel@tonic-gate 	int8_t seg_count;
2120Sstevel@tonic-gate 	char seg_name[2];
2130Sstevel@tonic-gate 	fru_info_t fru_data;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	/*
2160Sstevel@tonic-gate 	 * Read the number of segments in the Read Only section
2170Sstevel@tonic-gate 	 */
2180Sstevel@tonic-gate 	fru_data.buf_start = NUM_OF_SEG_ADDR;
2190Sstevel@tonic-gate 	fru_data.buf = (char *)&seg_count;
2200Sstevel@tonic-gate 	fru_data.read_size = 1;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
2230Sstevel@tonic-gate 	    &fru_data);
2240Sstevel@tonic-gate 	/*
2250Sstevel@tonic-gate 	 * We test for ENOENT and ENXIO because Littleneck does not
2260Sstevel@tonic-gate 	 * have actual presence sensors and so the only way to see
2270Sstevel@tonic-gate 	 * if a part is there or not is to actually make a call to
2280Sstevel@tonic-gate 	 * that part.
2290Sstevel@tonic-gate 	 */
2300Sstevel@tonic-gate 	if (status != PSVC_SUCCESS) {
2310Sstevel@tonic-gate 		if ((errno == ENOENT) || (errno == ENXIO))
2320Sstevel@tonic-gate 			return (PSVC_NO_DEVICE);
2330Sstevel@tonic-gate 		else
2340Sstevel@tonic-gate 			return (PSVC_FAILURE);
2350Sstevel@tonic-gate 	}
2360Sstevel@tonic-gate 	/*
2370Sstevel@tonic-gate 	 * Read in each segment to find the segment we are looking for
2380Sstevel@tonic-gate 	 */
2390Sstevel@tonic-gate 	for (j = 0; (j < seg_count) && (!(seg_found)); j++) {
2400Sstevel@tonic-gate 		fru_data.buf_start = seg_desc_start;
2410Sstevel@tonic-gate 		fru_data.buf = seg_name;
2420Sstevel@tonic-gate 		fru_data.read_size = 2;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
2450Sstevel@tonic-gate 		    &fru_data);
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 		seg_desc_start = seg_desc_start + 2;
2480Sstevel@tonic-gate 		fru_data.buf_start = seg_desc_start;
2490Sstevel@tonic-gate 		fru_data.buf = (char *)segment;
2500Sstevel@tonic-gate 		fru_data.read_size = sizeof (seg_desc_t);
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
2530Sstevel@tonic-gate 		    &fru_data);
2540Sstevel@tonic-gate 		if (status != PSVC_SUCCESS) {
2550Sstevel@tonic-gate 			syslog(LOG_ERR,
2560Sstevel@tonic-gate 			    "Failed psvc_get_attr for FRU info\n");
2570Sstevel@tonic-gate 			return (PSVC_FAILURE);
2580Sstevel@tonic-gate 		}
2590Sstevel@tonic-gate 		seg_desc_start = seg_desc_start + sizeof (seg_desc_t);
2600Sstevel@tonic-gate 		if (memcmp(seg_name, seg_to_find, 2) == 0) {
2610Sstevel@tonic-gate 			seg_found = 1;
2620Sstevel@tonic-gate 		}
2630Sstevel@tonic-gate 	}
2640Sstevel@tonic-gate 	return (seg_found);
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate int32_t
psvc_update_thresholds_0(psvc_opaque_t hdlp,char * id)2680Sstevel@tonic-gate psvc_update_thresholds_0(psvc_opaque_t hdlp, char *id)
2690Sstevel@tonic-gate {
2700Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
2710Sstevel@tonic-gate 	fru_info_t fru_data;
2720Sstevel@tonic-gate 	char *fru, part_no[7];
2730Sstevel@tonic-gate 	int16_t data_offset;
2740Sstevel@tonic-gate 	int32_t fru_count, i, j, temp_address;
2750Sstevel@tonic-gate 	int32_t seg_found, temp;
2760Sstevel@tonic-gate 	seg_desc_t segment;
2770Sstevel@tonic-gate 	int8_t temps[MAX_TEMP_ATTR];
2780Sstevel@tonic-gate 	int32_t num_of_parts = 2;
2790Sstevel@tonic-gate 	char fruless_parts[2][7] = {"5015988", "5015675"};
2800Sstevel@tonic-gate 	int fd;
2810Sstevel@tonic-gate 	FILE *fp;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &fru_count,
2840Sstevel@tonic-gate 	    PSVC_FRU);
2850Sstevel@tonic-gate 	if (status == PSVC_FAILURE)
2860Sstevel@tonic-gate 		return (status);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	for (i = 0; i < fru_count; i++) {
2890Sstevel@tonic-gate 		seg_found = 0;
2900Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
2910Sstevel@tonic-gate 		    &fru, PSVC_FRU, i);
2920Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
2930Sstevel@tonic-gate 			return (status);
2940Sstevel@tonic-gate 		seg_found = find_segment(hdlp, fru, &segment, "ES");
2950Sstevel@tonic-gate 		if (seg_found == PSVC_FAILURE)
2960Sstevel@tonic-gate 			return (PSVC_FAILURE);
2970Sstevel@tonic-gate 		else if (seg_found == PSVC_NO_DEVICE)
2980Sstevel@tonic-gate 			return (PSVC_SUCCESS);
2990Sstevel@tonic-gate 		if (seg_found) {
3000Sstevel@tonic-gate 			/*
3010Sstevel@tonic-gate 			 * For Littleneck we need to read the offset of the
3020Sstevel@tonic-gate 			 * die-sensor data record
3030Sstevel@tonic-gate 			 */
3040Sstevel@tonic-gate 			temp_address = segment.segoffset + TEMP_OFFSET;
3050Sstevel@tonic-gate 			fru_data.buf_start = temp_address;
3060Sstevel@tonic-gate 			fru_data.buf = (char *)&data_offset;
3070Sstevel@tonic-gate 			fru_data.read_size = sizeof (data_offset);
3080Sstevel@tonic-gate 			status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
3090Sstevel@tonic-gate 			    &fru_data);
3100Sstevel@tonic-gate 			if (status != PSVC_SUCCESS) {
3110Sstevel@tonic-gate 				syslog(LOG_ERR,
3120Sstevel@tonic-gate 				    "Failed psvc_get_attr for FRU info\n");
3130Sstevel@tonic-gate 				return (status);
3140Sstevel@tonic-gate 			}
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 			/*
3170Sstevel@tonic-gate 			 * Now go and get the new temperature settings
3180Sstevel@tonic-gate 			 */
3190Sstevel@tonic-gate 			temp_address = segment.segoffset + data_offset;
3200Sstevel@tonic-gate 			fru_data.buf_start = temp_address;
3210Sstevel@tonic-gate 			fru_data.buf = (char *)&temps;
3220Sstevel@tonic-gate 			fru_data.read_size = sizeof (temps);
3230Sstevel@tonic-gate 			status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
3240Sstevel@tonic-gate 			    &fru_data);
3250Sstevel@tonic-gate 			if (status != PSVC_SUCCESS) {
3260Sstevel@tonic-gate 				syslog(LOG_ERR,
3270Sstevel@tonic-gate 				    "Failed psvc_get_attr for FRU info\n");
3280Sstevel@tonic-gate 				return (status);
3290Sstevel@tonic-gate 			} else {
3300Sstevel@tonic-gate 				/*
3310Sstevel@tonic-gate 				 * Now set the updated Thresholds
3320Sstevel@tonic-gate 				 */
3330Sstevel@tonic-gate 				for (j = 0; j < MAX_TEMP_ATTR; j++) {
3340Sstevel@tonic-gate 					temp = temps[j];
3350Sstevel@tonic-gate 					status = psvc_set_attr(hdlp, id,
3360Sstevel@tonic-gate 					    temp_attr[j], &temp);
3370Sstevel@tonic-gate 				}
3380Sstevel@tonic-gate 			}
3390Sstevel@tonic-gate 		} else {
3400Sstevel@tonic-gate 			/*
3410Sstevel@tonic-gate 			 * For Littleneck only we need to check for the part
3420Sstevel@tonic-gate 			 * number of the CPU as there are parts that do not
3430Sstevel@tonic-gate 			 * have the ES segment programmed.
3440Sstevel@tonic-gate 			 */
3450Sstevel@tonic-gate 			seg_found = find_segment(hdlp, fru, &segment, "SD");
3460Sstevel@tonic-gate 			if (seg_found == PSVC_FAILURE)
3470Sstevel@tonic-gate 				return (PSVC_FAILURE);
3480Sstevel@tonic-gate 			if (seg_found) {
3490Sstevel@tonic-gate 				/*
3500Sstevel@tonic-gate 				 * We now goto the SD segment to get the part
3510Sstevel@tonic-gate 				 * number.
3520Sstevel@tonic-gate 				 */
3530Sstevel@tonic-gate 				fru_data.buf_start =
3540Sstevel@tonic-gate 				    segment.segoffset + PART_NO_OFFSET;
3550Sstevel@tonic-gate 				fru_data.buf = part_no;
3560Sstevel@tonic-gate 				fru_data.read_size = sizeof (part_no);
3570Sstevel@tonic-gate 				status = psvc_get_attr(hdlp, fru,
3580Sstevel@tonic-gate 				    PSVC_FRU_INFO_ATTR, &fru_data);
3590Sstevel@tonic-gate 				if (status != PSVC_SUCCESS) {
3600Sstevel@tonic-gate 					syslog(LOG_ERR, "Failed psvc_get_attr"
3610Sstevel@tonic-gate 					    "for FRU info\n");
3620Sstevel@tonic-gate 					return (status);
3630Sstevel@tonic-gate 				}
3640Sstevel@tonic-gate 				/*
3650Sstevel@tonic-gate 				 * We are go through the parts list to see
3660Sstevel@tonic-gate 				 * if the part number from the FRU is in
3670Sstevel@tonic-gate 				 * this list.  If it is we simply return
3680Sstevel@tonic-gate 				 * as the FRU is not programmed.
3690Sstevel@tonic-gate 				 */
3700Sstevel@tonic-gate 				for (j = 0; j < num_of_parts; j++) {
3710Sstevel@tonic-gate 					if (memcmp(fruless_parts[j], part_no,
3720Sstevel@tonic-gate 						7) == 0) {
3730Sstevel@tonic-gate 					return (status);
3740Sstevel@tonic-gate 					}
3750Sstevel@tonic-gate 				}
3760Sstevel@tonic-gate 			}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 			/*
3790Sstevel@tonic-gate 			 * If the Part is not in the Part list and we
3800Sstevel@tonic-gate 			 * get to here this means that the FRU is
3810Sstevel@tonic-gate 			 * considered broken (no ES segment found)
3820Sstevel@tonic-gate 			 * and we need to report this.
3830Sstevel@tonic-gate 			 */
3840Sstevel@tonic-gate 			/*
3850Sstevel@tonic-gate 			 * We make this open, write, close, call
3860Sstevel@tonic-gate 			 * because picld starts in rcS.d while print
3870Sstevel@tonic-gate 			 * services does not start until later
3880Sstevel@tonic-gate 			 * (either rc2.d or rc3.d).
3890Sstevel@tonic-gate 			 */
3900Sstevel@tonic-gate 			fd = open("/dev/console", O_WRONLY | O_NOCTTY);
3910Sstevel@tonic-gate 			if (fd != -1) {
3920Sstevel@tonic-gate 				fp = fdopen(fd, "w+");
3930Sstevel@tonic-gate 				if (fp != NULL) {
3940Sstevel@tonic-gate 					fprintf(fp, NO_FRU_INFO, id);
3950Sstevel@tonic-gate 					fclose(fp);
3960Sstevel@tonic-gate 				}
3970Sstevel@tonic-gate 				close(fd);
3980Sstevel@tonic-gate 			}
3990Sstevel@tonic-gate 			syslog(LOG_NOTICE, NO_FRU_INFO, id);
4000Sstevel@tonic-gate 		}
4010Sstevel@tonic-gate 	}
4020Sstevel@tonic-gate 	return (status);
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate int32_t
psvc_check_temperature_policy_0(psvc_opaque_t hdlp,char * id)4060Sstevel@tonic-gate psvc_check_temperature_policy_0(psvc_opaque_t hdlp, char *id)
4070Sstevel@tonic-gate {
4080Sstevel@tonic-gate 	int32_t lo_warn, hi_warn, lo_shut, hi_shut;
4090Sstevel@tonic-gate 	uint64_t features;
4100Sstevel@tonic-gate 	int32_t temp;
4110Sstevel@tonic-gate 	char previous_state[32];
4120Sstevel@tonic-gate 	char state[32];
4130Sstevel@tonic-gate 	char fault[32];
4140Sstevel@tonic-gate 	char label[32];
4150Sstevel@tonic-gate 	boolean_t pr;
4160Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
417*958Sjfrank 	int retry;
418*958Sjfrank 	int8_t temp_oor;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &pr);
4210Sstevel@tonic-gate 	if ((status != PSVC_SUCCESS) || (pr != PSVC_PRESENT)) {
4220Sstevel@tonic-gate 		return (status);
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_FEATURES_ATTR, &features);
4260Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4270Sstevel@tonic-gate 		return (status);
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_LO_WARN_ATTR, &lo_warn);
4300Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4310Sstevel@tonic-gate 		return (status);
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_LO_SHUT_ATTR, &lo_shut);
4340Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4350Sstevel@tonic-gate 		return (status);
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_HI_WARN_ATTR, &hi_warn);
4380Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4390Sstevel@tonic-gate 		return (status);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_HI_SHUT_ATTR, &hi_shut);
4420Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4430Sstevel@tonic-gate 		return (status);
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
4460Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4470Sstevel@tonic-gate 		return (status);
4480Sstevel@tonic-gate 
449*958Sjfrank 	retry = 0;
450*958Sjfrank 	do {
451*958Sjfrank 		if (retry)
452*958Sjfrank 			(void) sleep(retry_sleep_temp);
453*958Sjfrank 		status = psvc_get_attr(hdlp, id, PSVC_SENSOR_VALUE_ATTR, &temp);
454*958Sjfrank 		if (status != PSVC_SUCCESS) {
455*958Sjfrank 			if ((errno == ENOENT) || (errno == ENXIO))
456*958Sjfrank 				return (PSVC_SUCCESS);
457*958Sjfrank 			else
458*958Sjfrank 				return (PSVC_FAILURE);
459*958Sjfrank 		}
460*958Sjfrank 		temp_oor = 0;
461*958Sjfrank 		if (((features & PSVC_LOW_SHUT) && temp <= lo_shut) ||
462*958Sjfrank 		    ((features & PSVC_LOW_WARN) && temp <= lo_warn) ||
463*958Sjfrank 		    ((features & PSVC_HIGH_SHUT) && temp >= hi_shut) ||
464*958Sjfrank 		    ((features & PSVC_HIGH_WARN) && temp >= hi_warn))
465*958Sjfrank 			temp_oor = 1;
466*958Sjfrank 		retry++;
467*958Sjfrank 	} while ((retry < n_retry_temp) && temp_oor);
468*958Sjfrank 
4690Sstevel@tonic-gate 	if ((features & PSVC_LOW_SHUT) && temp <= lo_shut) {
4700Sstevel@tonic-gate 		strcpy(state, PSVC_ERROR);
4710Sstevel@tonic-gate 		strcpy(fault, PSVC_TEMP_LO_SHUT);
4720Sstevel@tonic-gate 		syslog(LOG_ERR, LOWTEMP_CRITICAL_MSG, temp, label);
4730Sstevel@tonic-gate 	} else if ((features & PSVC_LOW_WARN) && temp <= lo_warn) {
4740Sstevel@tonic-gate 		strcpy(state, PSVC_ERROR);
4750Sstevel@tonic-gate 		strcpy(fault, PSVC_TEMP_LO_WARN);
4760Sstevel@tonic-gate 		syslog(LOG_ERR, LOWTEMP_WARNING_MSG, temp, label);
4770Sstevel@tonic-gate 	} else if ((features & PSVC_HIGH_SHUT) && temp >= hi_shut) {
4780Sstevel@tonic-gate 		strcpy(state, PSVC_ERROR);
4790Sstevel@tonic-gate 		strcpy(fault, PSVC_TEMP_HI_SHUT);
4800Sstevel@tonic-gate 		syslog(LOG_ERR, HIGHTEMP_CRITICAL_MSG,  temp, label);
4810Sstevel@tonic-gate 	} else if ((features & PSVC_HIGH_WARN) && temp >= hi_warn) {
4820Sstevel@tonic-gate 		strcpy(state, PSVC_ERROR);
4830Sstevel@tonic-gate 		strcpy(fault, PSVC_TEMP_HI_WARN);
4840Sstevel@tonic-gate 		syslog(LOG_ERR, HIGHTEMP_WARNING_MSG, temp, label);
4850Sstevel@tonic-gate 	} else {
4860Sstevel@tonic-gate 		/* within limits */
4870Sstevel@tonic-gate 		strcpy(state, PSVC_OK);
4880Sstevel@tonic-gate 		strcpy(fault, PSVC_NO_FAULT);
4890Sstevel@tonic-gate 	}
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
4920Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4930Sstevel@tonic-gate 		return (status);
4940Sstevel@tonic-gate 	status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
4950Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4960Sstevel@tonic-gate 		return (status);
4970Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR,
4980Sstevel@tonic-gate 		previous_state);
4990Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
5000Sstevel@tonic-gate 		return (status);
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	if (strcmp(previous_state, state) != 0) {
5030Sstevel@tonic-gate 		char *led_id;
5040Sstevel@tonic-gate 		uint8_t _8bit_val;
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 		led_id = "SYSTEM_FAULT_LED_WR";
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, led_id,
5090Sstevel@tonic-gate 			PSVC_GPIO_VALUE_ATTR, &_8bit_val);
5100Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
5110Sstevel@tonic-gate 			return (status);
5120Sstevel@tonic-gate 		if (strcmp(state, PSVC_ERROR) == 0)
5130Sstevel@tonic-gate 			_8bit_val &= 0xef;  /* clear bit 4 */
5140Sstevel@tonic-gate 		else
5150Sstevel@tonic-gate 			_8bit_val |= 0x10;  /* set bit 4 */
5160Sstevel@tonic-gate 		_8bit_val |= 0xe4;  /* set bits 3, 5, 6, 7 */
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 		status = psvc_set_attr(hdlp, led_id,
5190Sstevel@tonic-gate 			PSVC_GPIO_VALUE_ATTR, &_8bit_val);
5200Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
5210Sstevel@tonic-gate 			return (status);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	return (PSVC_SUCCESS);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate static int32_t ps0_addr[] = {0, 0xac};
5290Sstevel@tonic-gate static int32_t ps1_addr[] = {0, 0xae};
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate int32_t
psvc_ps_hotplug_policy_0(psvc_opaque_t hdlp,char * id)5320Sstevel@tonic-gate psvc_ps_hotplug_policy_0(psvc_opaque_t hdlp, char *id)
5330Sstevel@tonic-gate {
5340Sstevel@tonic-gate 	boolean_t presence, previous_presence;
5350Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
5360Sstevel@tonic-gate 	char label[32];
5370Sstevel@tonic-gate 	int i;
5380Sstevel@tonic-gate 	int32_t led_count;
5390Sstevel@tonic-gate 	char state[32], fault[32];
5400Sstevel@tonic-gate 	boolean_t ps_type;
5410Sstevel@tonic-gate 	char *sensor_id, *led_id;
5420Sstevel@tonic-gate 	char led_state[32];
5430Sstevel@tonic-gate 	picl_nodehdl_t parent_node;
5440Sstevel@tonic-gate 	char parent_path[256];
5450Sstevel@tonic-gate 	picl_nodehdl_t child_node;
5460Sstevel@tonic-gate 	int ps_instance;
5470Sstevel@tonic-gate 	devctl_hdl_t bus_handle, dev_handle;
5480Sstevel@tonic-gate 	devctl_ddef_t ddef_hdl;
5490Sstevel@tonic-gate 	char devpath[256];
550*958Sjfrank 	int retry;
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR,
5530Sstevel@tonic-gate 		&previous_presence);
5540Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
5550Sstevel@tonic-gate 		return (status);
556*958Sjfrank 	retry = 0;
557*958Sjfrank 	do {
558*958Sjfrank 		if (retry)
559*958Sjfrank 			(void) sleep(retry_sleep_hotplug);
560*958Sjfrank 		status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence);
561*958Sjfrank 		if (status != PSVC_SUCCESS)
562*958Sjfrank 			return (status);
563*958Sjfrank 		retry++;
564*958Sjfrank 	} while ((retry < n_retry_hotplug) && (presence != previous_presence));
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	if (presence == previous_presence) {
5670Sstevel@tonic-gate 		/* No change */
5680Sstevel@tonic-gate 		return (status);
5690Sstevel@tonic-gate 	}
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
5720Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
5730Sstevel@tonic-gate 		return (status);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	/* Convert name to node and parent path */
5760Sstevel@tonic-gate 	psvcplugin_lookup(id, parent_path, &child_node);
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	if (presence == PSVC_PRESENT) {
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 		/* may detect presence before all connections are made */
5810Sstevel@tonic-gate 		sleep(1);
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 		/* Device added */
5840Sstevel@tonic-gate 		syslog(LOG_ERR, DEVICE_INSERTED_MSG, label);
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 		/* Verify P/S is correct type */
5880Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
5890Sstevel@tonic-gate 			&sensor_id, PSVC_DEV_TYPE_SENSOR, 0);
5900Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
5910Sstevel@tonic-gate 			return (status);
5920Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, sensor_id,
5930Sstevel@tonic-gate 			PSVC_GPIO_VALUE_ATTR, &ps_type);
5940Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
5950Sstevel@tonic-gate 			return (status);
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 		if (ps_type ==  1) {	/* correct p/s */
5980Sstevel@tonic-gate 			strcpy(state, PSVC_OK);
5990Sstevel@tonic-gate 			strcpy(fault, PSVC_NO_FAULT);
6000Sstevel@tonic-gate 			strcpy(led_state, PSVC_LED_OFF);
6010Sstevel@tonic-gate 		} else {		/* wrong type */
6020Sstevel@tonic-gate 			strcpy(state, PSVC_ERROR);
6030Sstevel@tonic-gate 			strcpy(fault, PSVC_PS_TYPE_FLT);
6040Sstevel@tonic-gate 			strcpy(led_state, PSVC_LED_ON);
6050Sstevel@tonic-gate 			syslog(LOG_ERR, PS_TYPE_MSG, label);
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 		}
6080Sstevel@tonic-gate 		status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
6090Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
6100Sstevel@tonic-gate 			return (status);
6110Sstevel@tonic-gate 		status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
6120Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
6130Sstevel@tonic-gate 			return (status);
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 		/* Set state of fault LEDs */
6160Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, sensor_id, PSVC_ASSOC_MATCHES_ATTR,
6170Sstevel@tonic-gate 			&led_count, PSVC_DEV_FAULT_LED);
6180Sstevel@tonic-gate 		if (status != PSVC_SUCCESS) {
6190Sstevel@tonic-gate 			syslog(LOG_ERR,
6200Sstevel@tonic-gate 				gettext("Failed for PSVC_DEV_FAULT_LED\n"));
6210Sstevel@tonic-gate 			return (status);
6220Sstevel@tonic-gate 		}
6230Sstevel@tonic-gate 		for (i = 0; i < led_count; ++i) {
6240Sstevel@tonic-gate 			status = psvc_get_attr(hdlp, sensor_id,
6250Sstevel@tonic-gate 				PSVC_ASSOC_ID_ATTR, &led_id,
6260Sstevel@tonic-gate 				PSVC_DEV_FAULT_LED, i);
6270Sstevel@tonic-gate 			if (status != PSVC_SUCCESS)
6280Sstevel@tonic-gate 				return (status);
6290Sstevel@tonic-gate 			status = psvc_set_attr(hdlp, led_id,
6300Sstevel@tonic-gate 				PSVC_LED_STATE_ATTR, led_state);
6310Sstevel@tonic-gate 			if (status != PSVC_SUCCESS)
6320Sstevel@tonic-gate 				return (status);
6330Sstevel@tonic-gate 		}
6340Sstevel@tonic-gate 		ptree_get_node_by_path(parent_path, &parent_node);
6350Sstevel@tonic-gate 		ptree_add_node(parent_node, child_node);
6360Sstevel@tonic-gate 	} else {
6370Sstevel@tonic-gate 		/* Device removed */
6380Sstevel@tonic-gate 		syslog(LOG_ERR, DEVICE_REMOVED_MSG, label);
6390Sstevel@tonic-gate 		ptree_delete_node(child_node);
6400Sstevel@tonic-gate 	}
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 	status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence);
6430Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
6440Sstevel@tonic-gate 		return (status);
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &ps_instance);
6470Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
6480Sstevel@tonic-gate 		return (status);
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	if (presence != PSVC_PRESENT) {
6510Sstevel@tonic-gate 		if (ps_instance == 0)
6520Sstevel@tonic-gate 			strcpy(devpath,
6530Sstevel@tonic-gate 	"/devices/pci@8,700000/ebus@5/i2c@1,30/power-supply@0,ac:power-supply");
6540Sstevel@tonic-gate 		else
6550Sstevel@tonic-gate 			strcpy(devpath,
6560Sstevel@tonic-gate 	"/devices/pci@8,700000/ebus@5/i2c@1,30/power-supply@0,ae:power-supply");
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 		dev_handle = devctl_device_acquire(devpath, 0);
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 		if (devctl_device_remove(dev_handle)) {
6610Sstevel@tonic-gate 			syslog(LOG_ERR, DEVTREE_NODE_DELETE_FAILED, label,
6620Sstevel@tonic-gate 				errno);
6630Sstevel@tonic-gate 			status = PSVC_FAILURE;
6640Sstevel@tonic-gate 		} else {
6650Sstevel@tonic-gate 			devctl_release(dev_handle);
6660Sstevel@tonic-gate 			status = PSVC_SUCCESS;
6670Sstevel@tonic-gate 		}
6680Sstevel@tonic-gate 		return (status);
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	/*
6720Sstevel@tonic-gate 	 * We fall through to here if the device has been inserted.
6730Sstevel@tonic-gate 	 * Add the devinfo tree node entry for the seeprom and attach
6740Sstevel@tonic-gate 	 * the i2c seeprom driver
6750Sstevel@tonic-gate 	 */
6760Sstevel@tonic-gate 	ddef_hdl = devctl_ddef_alloc("power-supply", 0);
6770Sstevel@tonic-gate 	(void) devctl_ddef_string(ddef_hdl, "compatible", "i2c-at24c64");
6780Sstevel@tonic-gate 	if (ps_instance == 0) {
6790Sstevel@tonic-gate 		(void) devctl_ddef_int_array(ddef_hdl, "reg", 2, ps0_addr);
6800Sstevel@tonic-gate 	} else {
6810Sstevel@tonic-gate 		(void) devctl_ddef_int_array(ddef_hdl, "reg", 2, ps1_addr);
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	bus_handle = devctl_bus_acquire(
6850Sstevel@tonic-gate 			"/devices/pci@8,700000/ebus@5/i2c@1,30:i2c", 0);
6860Sstevel@tonic-gate 	if (devctl_bus_dev_create(bus_handle, ddef_hdl, 0, &dev_handle)) {
6870Sstevel@tonic-gate 		syslog(LOG_ERR, DEVTREE_NODE_CREATE_FAILED, label, errno);
6880Sstevel@tonic-gate 		status = PSVC_FAILURE;
6890Sstevel@tonic-gate 	} else
6900Sstevel@tonic-gate 		devctl_release(dev_handle);
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	devctl_release(bus_handle);
6930Sstevel@tonic-gate 	devctl_ddef_free(ddef_hdl);
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	return (status);
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate int32_t
psvc_device_fail_notifier_policy_0(psvc_opaque_t hdlp,char * id)6990Sstevel@tonic-gate psvc_device_fail_notifier_policy_0(psvc_opaque_t hdlp, char *id)
7000Sstevel@tonic-gate {
7010Sstevel@tonic-gate 	int32_t sensor_count;
7020Sstevel@tonic-gate 	char *led_id, *sensor_id;
7030Sstevel@tonic-gate 	int i;
7040Sstevel@tonic-gate 	char state[32], fault[32], previous_state[32];
7050Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
7060Sstevel@tonic-gate 	boolean_t present;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &present);
7090Sstevel@tonic-gate 	if (status == PSVC_FAILURE)
7100Sstevel@tonic-gate 		return (status);
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	if (present == PSVC_ABSENT) {
7130Sstevel@tonic-gate 		errno = ENODEV;
7140Sstevel@tonic-gate 		return (PSVC_FAILURE);
7150Sstevel@tonic-gate 	}
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
7180Sstevel@tonic-gate 		PSVC_DEV_FAULT_SENSOR);
7190Sstevel@tonic-gate 	for (i = 0; i < sensor_count; ++i) {
7200Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
7210Sstevel@tonic-gate 			&sensor_id, PSVC_DEV_FAULT_SENSOR, i);
7220Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
7230Sstevel@tonic-gate 			return (status);
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, sensor_id,
7260Sstevel@tonic-gate 			PSVC_SWITCH_STATE_ATTR, state);
7270Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
7280Sstevel@tonic-gate 			return (status);
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 		if (strcmp(state, PSVC_SWITCH_ON) == 0) {
7310Sstevel@tonic-gate 			strcpy(state, PSVC_ERROR);
7320Sstevel@tonic-gate 			strcpy(fault, PSVC_GEN_FAULT);
7330Sstevel@tonic-gate 		} else {
7340Sstevel@tonic-gate 			strcpy(state, PSVC_OK);
7350Sstevel@tonic-gate 			strcpy(fault, PSVC_NO_FAULT);
7360Sstevel@tonic-gate 		}
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 		status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
7390Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
7400Sstevel@tonic-gate 			return (status);
7410Sstevel@tonic-gate 		status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
7420Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
7430Sstevel@tonic-gate 			return (status);
7440Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR,
7450Sstevel@tonic-gate 			previous_state);
7460Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
7470Sstevel@tonic-gate 			return (status);
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 		if (strcmp(state, previous_state) != 0) {
7500Sstevel@tonic-gate 			char sensor_label[32];
7510Sstevel@tonic-gate 			char dev_label[32];
7520Sstevel@tonic-gate 			uint8_t _8bit_val;
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 			psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, dev_label);
7550Sstevel@tonic-gate 			psvc_get_attr(hdlp, sensor_id, PSVC_LABEL_ATTR,
7560Sstevel@tonic-gate 			    sensor_label);
7570Sstevel@tonic-gate 			if (strcmp(state, PSVC_ERROR) == 0)
7580Sstevel@tonic-gate 				syslog(LOG_ERR, DEVICE_FAILURE_MSG, dev_label,
7590Sstevel@tonic-gate 					sensor_label);
7600Sstevel@tonic-gate 			else
7610Sstevel@tonic-gate 				syslog(LOG_ERR, DEVICE_OK_MSG, dev_label);
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 			led_id = "SYSTEM_FAULT_LED_WR";
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 			status = psvc_get_attr(hdlp, led_id,
7660Sstevel@tonic-gate 				PSVC_GPIO_VALUE_ATTR, &_8bit_val);
7670Sstevel@tonic-gate 			if (status != PSVC_SUCCESS)
7680Sstevel@tonic-gate 				return (status);
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 			if (strcmp(state, PSVC_ERROR) == 0)
7710Sstevel@tonic-gate 				_8bit_val &= 0xef;  /* clear bit 4 */
7720Sstevel@tonic-gate 			else
7730Sstevel@tonic-gate 				_8bit_val |= 0x10;  /* set bit 4 */
7740Sstevel@tonic-gate 			_8bit_val |= 0xe4;  /* set bits 3, 5, 6, 7 */
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 			status = psvc_set_attr(hdlp, led_id,
7770Sstevel@tonic-gate 				PSVC_GPIO_VALUE_ATTR, &_8bit_val);
7780Sstevel@tonic-gate 			if (status != PSVC_SUCCESS)
7790Sstevel@tonic-gate 				return (status);
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 		}
7820Sstevel@tonic-gate 	}
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 	return (PSVC_SUCCESS);
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate int32_t
psvc_init_led_policy_0(psvc_opaque_t hdlp,char * id)7880Sstevel@tonic-gate psvc_init_led_policy_0(psvc_opaque_t hdlp, char *id)
7890Sstevel@tonic-gate {
7900Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
7910Sstevel@tonic-gate 	uint8_t _8bit_val;
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id,
7940Sstevel@tonic-gate 		PSVC_GPIO_VALUE_ATTR, &_8bit_val);
7950Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
7960Sstevel@tonic-gate 		return (status);
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	_8bit_val &= 0xef;  /* clear bit 4 */
7990Sstevel@tonic-gate 	_8bit_val |= 0xf4;  /* set bits 3, 5, 6, 7 */
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	status = psvc_set_attr(hdlp, id,
8020Sstevel@tonic-gate 		PSVC_GPIO_VALUE_ATTR, &_8bit_val);
8030Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
8040Sstevel@tonic-gate 		return (status);
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	return (status);
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate static int32_t
check_cpu_temp_fault(psvc_opaque_t hdlp,char * cpu,int32_t cpu_count)8100Sstevel@tonic-gate check_cpu_temp_fault(psvc_opaque_t hdlp, char *cpu, int32_t cpu_count)
8110Sstevel@tonic-gate {
8120Sstevel@tonic-gate 	char *sensorid;
8130Sstevel@tonic-gate 	int32_t sensor_count;
8140Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
8150Sstevel@tonic-gate 	int32_t i;
8160Sstevel@tonic-gate 	char fault[32];
817*958Sjfrank 	int retry;
818*958Sjfrank 	int8_t temp_oor;
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	psvc_get_attr(hdlp, cpu, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
8210Sstevel@tonic-gate 		PSVC_DEV_TEMP_SENSOR);
8220Sstevel@tonic-gate 	for (i = 0; i < sensor_count; ++i) {
8230Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, cpu, PSVC_ASSOC_ID_ATTR,
8240Sstevel@tonic-gate 			&sensorid, PSVC_DEV_TEMP_SENSOR, i);
8250Sstevel@tonic-gate 		if (status == PSVC_FAILURE)
8260Sstevel@tonic-gate 			return (status);
8270Sstevel@tonic-gate 
828*958Sjfrank 		retry = 0;
829*958Sjfrank 		do {
830*958Sjfrank 			if (retry)
831*958Sjfrank 				(void) sleep(retry_sleep_temp_shutdown);
832*958Sjfrank 			status = psvc_get_attr(hdlp, sensorid,
833*958Sjfrank 			    PSVC_FAULTID_ATTR, fault);
834*958Sjfrank 			if (status == PSVC_FAILURE)
835*958Sjfrank 				return (status);
836*958Sjfrank 			temp_oor = 0;
837*958Sjfrank 			if ((strcmp(fault, PSVC_TEMP_HI_SHUT) == 0) ||
838*958Sjfrank 			    (strcmp(fault, PSVC_TEMP_LO_SHUT) == 0)) {
839*958Sjfrank 				temp_oor = 1;
840*958Sjfrank 			}
841*958Sjfrank 			retry++;
842*958Sjfrank 		} while ((retry < n_retry_temp_shutdown) && temp_oor);
8430Sstevel@tonic-gate 
844*958Sjfrank 		if (temp_oor) {
8450Sstevel@tonic-gate 			system(shutdown_string);
8460Sstevel@tonic-gate 		}
8470Sstevel@tonic-gate 	}
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	return (status);
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate int32_t
psvc_shutdown_policy_0(psvc_opaque_t hdlp,char * id)8530Sstevel@tonic-gate psvc_shutdown_policy_0(psvc_opaque_t hdlp, char *id)
8540Sstevel@tonic-gate {
8550Sstevel@tonic-gate 	int32_t cpu_count;
8560Sstevel@tonic-gate 	char *cpuid;
8570Sstevel@tonic-gate 	int32_t i;
8580Sstevel@tonic-gate 	boolean_t present;
8590Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count,
8620Sstevel@tonic-gate 		PSVC_CPU);
8630Sstevel@tonic-gate 	for (i = 0; i < cpu_count; ++i) {
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &cpuid,
8660Sstevel@tonic-gate 			PSVC_CPU, i);
8670Sstevel@tonic-gate 		if (status == PSVC_FAILURE)
8680Sstevel@tonic-gate 			return (status);
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, cpuid,
8710Sstevel@tonic-gate 			PSVC_PRESENCE_ATTR, &present);
8720Sstevel@tonic-gate 		if (status == PSVC_FAILURE && present == PSVC_PRESENT)
8730Sstevel@tonic-gate 			return (status);
8740Sstevel@tonic-gate 		if (present == PSVC_PRESENT) {
8750Sstevel@tonic-gate 			status = check_cpu_temp_fault(hdlp, cpuid, cpu_count);
8760Sstevel@tonic-gate 			if (status == PSVC_FAILURE && errno != ENODEV)
8770Sstevel@tonic-gate 				return (status);
8780Sstevel@tonic-gate 		}
8790Sstevel@tonic-gate 	}
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	return (PSVC_SUCCESS);
8820Sstevel@tonic-gate }
883