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*298b7f4cSjfrank  * Copyright 2005 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  * Littleneck 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	<sys/types.h>
397c478bd9Sstevel@tonic-gate #include	<fcntl.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>
48*298b7f4cSjfrank #include	<limits.h>
49*298b7f4cSjfrank #include	<sys/systeminfo.h>
507c478bd9Sstevel@tonic-gate #include	<psvc_objects.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #define	LOWTEMP_CRITICAL_MSG		\
557c478bd9Sstevel@tonic-gate 	gettext("CRITICAL : LOW TEMPERATURE DETECTED %d, %s")
567c478bd9Sstevel@tonic-gate #define	LOWTEMP_WARNING_MSG		\
577c478bd9Sstevel@tonic-gate 	gettext("WARNING : LOW TEMPERATURE DETECTED %d, %s")
587c478bd9Sstevel@tonic-gate #define	HIGHTEMP_CRITICAL_MSG		\
597c478bd9Sstevel@tonic-gate 	gettext("CRITICAL : HIGH TEMPERATURE DETECTED %d, %s")
607c478bd9Sstevel@tonic-gate #define	HIGHTEMP_WARNING_MSG		\
617c478bd9Sstevel@tonic-gate 	gettext("WARNING : HIGH TEMPERATURE DETECTED %d, %s")
627c478bd9Sstevel@tonic-gate #define	DEVICE_INSERTED_MSG	gettext("Device %s inserted")
637c478bd9Sstevel@tonic-gate #define	DEVICE_REMOVED_MSG	gettext("Device %s removed")
647c478bd9Sstevel@tonic-gate #define	PS_TYPE_MSG			\
657c478bd9Sstevel@tonic-gate 	gettext("WARNING: Incorrect type power supply inserted, device %s")
667c478bd9Sstevel@tonic-gate #define	DEVICE_FAILURE_MSG		\
677c478bd9Sstevel@tonic-gate 	gettext("WARNING: Device %s failure detected by sensor %s\n")
687c478bd9Sstevel@tonic-gate #define	DEVICE_OK_MSG	gettext("Device %s OK")
697c478bd9Sstevel@tonic-gate #define	DEVTREE_NODE_CREATE_FAILED	\
707c478bd9Sstevel@tonic-gate 	gettext("psvc PICL plugin: Failed to create node for %s, errno = %d")
717c478bd9Sstevel@tonic-gate #define	DEVTREE_NODE_DELETE_FAILED	\
727c478bd9Sstevel@tonic-gate 	gettext("psvc PICL plugin: Failed to delete node for %s, errno = %d")
737c478bd9Sstevel@tonic-gate #define	NO_FRU_INFO			\
747c478bd9Sstevel@tonic-gate 	gettext("No FRU Information for %s using default temperatures\n")
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate static char *shutdown_string = "shutdown -y -g 60 -i 5 \"OVERTEMP condition\"";
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate typedef struct seg_desc {
797c478bd9Sstevel@tonic-gate 	int32_t segdesc;
807c478bd9Sstevel@tonic-gate 	int16_t segoffset;
817c478bd9Sstevel@tonic-gate 	int16_t seglength;
827c478bd9Sstevel@tonic-gate } seg_desc_t;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate static int32_t find_segment(psvc_opaque_t hdlp, char *fru, seg_desc_t *segment,
857c478bd9Sstevel@tonic-gate     char *seg_to_find);
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate static int temp_attr[] = {
887c478bd9Sstevel@tonic-gate 	PSVC_HW_HI_SHUT_ATTR, PSVC_HI_SHUT_ATTR, PSVC_HI_WARN_ATTR,
897c478bd9Sstevel@tonic-gate 	PSVC_LO_WARN_ATTR, PSVC_LO_SHUT_ATTR, PSVC_HW_LO_SHUT_ATTR
907c478bd9Sstevel@tonic-gate };
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate #define	MAX_TEMP_ATTR	(sizeof (temp_attr)/sizeof (temp_attr[0]))
937c478bd9Sstevel@tonic-gate #define	TEMP_OFFSET	12
947c478bd9Sstevel@tonic-gate #define	PART_NO_OFFSET	152
957c478bd9Sstevel@tonic-gate #define	NUM_OF_SEG_ADDR	0x1805
967c478bd9Sstevel@tonic-gate #define	SEG_DESC_START 	0x1806
977c478bd9Sstevel@tonic-gate #define	PSVC_NO_DEVICE 	-2
987c478bd9Sstevel@tonic-gate 
99*298b7f4cSjfrank /*
100*298b7f4cSjfrank  * The I2C bus is noisy, and the state may be incorrectly reported as
101*298b7f4cSjfrank  * having changed.  When the state changes, we attempt to confirm by
102*298b7f4cSjfrank  * retrying.  If any retries indicate that the state has not changed, we
103*298b7f4cSjfrank  * assume the state change(s) were incorrect and the state has not changed.
104*298b7f4cSjfrank  * The following variables are used to store the tuneable values read in
105*298b7f4cSjfrank  * from the optional i2cparam.conf file for this shared object library.
106*298b7f4cSjfrank  */
107*298b7f4cSjfrank static int n_retry_temp = PSVC_THRESHOLD_COUNTER;
108*298b7f4cSjfrank static int retry_sleep_temp = 1;
109*298b7f4cSjfrank static int n_retry_hotplug = PSVC_NUM_OF_RETRIES;
110*298b7f4cSjfrank static int retry_sleep_hotplug = 1;
111*298b7f4cSjfrank static int n_retry_temp_shutdown = PSVC_NUM_OF_RETRIES;
112*298b7f4cSjfrank static int retry_sleep_temp_shutdown = 1;
113*298b7f4cSjfrank 
114*298b7f4cSjfrank typedef struct {
115*298b7f4cSjfrank 	int *pvar;
116*298b7f4cSjfrank 	char *texttag;
117*298b7f4cSjfrank } i2c_noise_param_t;
118*298b7f4cSjfrank 
119*298b7f4cSjfrank static i2c_noise_param_t i2cparams[] = {
120*298b7f4cSjfrank 	&n_retry_temp, "n_retry_temp",
121*298b7f4cSjfrank 	&retry_sleep_temp, "retry_sleep_temp",
122*298b7f4cSjfrank 	&n_retry_hotplug, "n_retry_hotplug",
123*298b7f4cSjfrank 	&retry_sleep_hotplug, "retry_sleep_hotplug",
124*298b7f4cSjfrank 	NULL, NULL
125*298b7f4cSjfrank };
126*298b7f4cSjfrank 
127*298b7f4cSjfrank #pragma init(i2cparams_load)
128*298b7f4cSjfrank 
129*298b7f4cSjfrank static void
i2cparams_debug(i2c_noise_param_t * pi2cparams,char * platform,int usingDefaults)130*298b7f4cSjfrank i2cparams_debug(i2c_noise_param_t *pi2cparams, char *platform,
131*298b7f4cSjfrank 	int usingDefaults)
132*298b7f4cSjfrank {
133*298b7f4cSjfrank 	char s[128];
134*298b7f4cSjfrank 	i2c_noise_param_t *p;
135*298b7f4cSjfrank 
136*298b7f4cSjfrank 	if (!usingDefaults) {
137*298b7f4cSjfrank 		(void) snprintf(s, sizeof (s),
138*298b7f4cSjfrank 		    "# Values from /usr/platform/%s/lib/i2cparam.conf\n",
139*298b7f4cSjfrank 		    platform);
140*298b7f4cSjfrank 		syslog(LOG_WARNING, "%s", s);
141*298b7f4cSjfrank 	} else {
142*298b7f4cSjfrank 		/* no file - we're using the defaults */
143*298b7f4cSjfrank 		(void) snprintf(s, sizeof (s),
144*298b7f4cSjfrank "# No /usr/platform/%s/lib/i2cparam.conf file, using defaults\n",
145*298b7f4cSjfrank 		    platform);
146*298b7f4cSjfrank 	}
147*298b7f4cSjfrank 	(void) fputs(s, stdout);
148*298b7f4cSjfrank 	p = pi2cparams;
149*298b7f4cSjfrank 	while (p->pvar != NULL) {
150*298b7f4cSjfrank 		(void) snprintf(s, sizeof (s), "%s %d\n", p->texttag,
151*298b7f4cSjfrank 		    *(p->pvar));
152*298b7f4cSjfrank 		if (!usingDefaults)
153*298b7f4cSjfrank 			syslog(LOG_WARNING, "%s", s);
154*298b7f4cSjfrank 		(void) fputs(s, stdout);
155*298b7f4cSjfrank 		p++;
156*298b7f4cSjfrank 	}
157*298b7f4cSjfrank }
158*298b7f4cSjfrank 
159*298b7f4cSjfrank static void
i2cparams_load(void)160*298b7f4cSjfrank i2cparams_load(void)
161*298b7f4cSjfrank {
162*298b7f4cSjfrank 	FILE *fp;
163*298b7f4cSjfrank 	char filename[PATH_MAX];
164*298b7f4cSjfrank 	char platform[64];
165*298b7f4cSjfrank 	char s[128];
166*298b7f4cSjfrank 	char var[128];
167*298b7f4cSjfrank 	int val;
168*298b7f4cSjfrank 	i2c_noise_param_t *p;
169*298b7f4cSjfrank 
170*298b7f4cSjfrank 	if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
171*298b7f4cSjfrank 		syslog(LOG_ERR, "sysinfo error %s\n", strerror(errno));
172*298b7f4cSjfrank 		return;
173*298b7f4cSjfrank 	}
174*298b7f4cSjfrank 	(void) snprintf(filename, sizeof (filename),
175*298b7f4cSjfrank 	    "/usr/platform/%s/lib/i2cparam.conf", platform);
176*298b7f4cSjfrank 	/* read thru the i2cparam.conf file and set variables */
177*298b7f4cSjfrank 	if ((fp = fopen(filename, "r")) != NULL) {
178*298b7f4cSjfrank 		while (fgets(s, sizeof (s), fp) != NULL) {
179*298b7f4cSjfrank 			if (s[0] == '#') /* skip comment lines */
180*298b7f4cSjfrank 				continue;
181*298b7f4cSjfrank 			/* try to find a string match and get the value */
182*298b7f4cSjfrank 			if (sscanf(s, "%127s %d", var, &val) != 2)
183*298b7f4cSjfrank 				continue;
184*298b7f4cSjfrank 			if (val < 1)
185*298b7f4cSjfrank 				val = 1;  /* clamp min value */
186*298b7f4cSjfrank 			p = &(i2cparams[0]);
187*298b7f4cSjfrank 			while (p->pvar != NULL) {
188*298b7f4cSjfrank 				if (strncmp(p->texttag, var, sizeof (var)) ==
189*298b7f4cSjfrank 				    0) {
190*298b7f4cSjfrank 					*(p->pvar) = val;
191*298b7f4cSjfrank 					break;
192*298b7f4cSjfrank 				}
193*298b7f4cSjfrank 				p++;
194*298b7f4cSjfrank 			}
195*298b7f4cSjfrank 		}
196*298b7f4cSjfrank 		(void) fclose(fp);
197*298b7f4cSjfrank 	}
198*298b7f4cSjfrank 	/* output the values of the parameters */
199*298b7f4cSjfrank 	i2cparams_debug(&(i2cparams[0]), platform, ((fp == NULL)? 1 : 0));
200*298b7f4cSjfrank }
201*298b7f4cSjfrank 
202*298b7f4cSjfrank 
2037c478bd9Sstevel@tonic-gate int32_t
find_segment(psvc_opaque_t hdlp,char * fru,seg_desc_t * segment,char seg_to_find[2])2047c478bd9Sstevel@tonic-gate find_segment(psvc_opaque_t hdlp, char *fru, seg_desc_t *segment,
2057c478bd9Sstevel@tonic-gate     char seg_to_find[2])
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate 	int32_t seg_found = 0, status;
2087c478bd9Sstevel@tonic-gate 	int32_t seg_desc_start = SEG_DESC_START, j;
2097c478bd9Sstevel@tonic-gate 	int8_t seg_count;
2107c478bd9Sstevel@tonic-gate 	char seg_name[2];
2117c478bd9Sstevel@tonic-gate 	fru_info_t fru_data;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	/*
2147c478bd9Sstevel@tonic-gate 	 * Read the number of segments in the Read Only section
2157c478bd9Sstevel@tonic-gate 	 */
2167c478bd9Sstevel@tonic-gate 	fru_data.buf_start = NUM_OF_SEG_ADDR;
2177c478bd9Sstevel@tonic-gate 	fru_data.buf = (char *)&seg_count;
2187c478bd9Sstevel@tonic-gate 	fru_data.read_size = 1;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
2217c478bd9Sstevel@tonic-gate 	    &fru_data);
2227c478bd9Sstevel@tonic-gate 	/*
2237c478bd9Sstevel@tonic-gate 	 * We test for ENOENT and ENXIO because Littleneck does not
2247c478bd9Sstevel@tonic-gate 	 * have actual presence sensors and so the only way to see
2257c478bd9Sstevel@tonic-gate 	 * if a part is there or not is to actually make a call to
2267c478bd9Sstevel@tonic-gate 	 * that part.
2277c478bd9Sstevel@tonic-gate 	 */
2287c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS) {
2297c478bd9Sstevel@tonic-gate 		if ((errno == ENOENT) || (errno == ENXIO))
2307c478bd9Sstevel@tonic-gate 			return (PSVC_NO_DEVICE);
2317c478bd9Sstevel@tonic-gate 		else
2327c478bd9Sstevel@tonic-gate 			return (PSVC_FAILURE);
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 	/*
2357c478bd9Sstevel@tonic-gate 	 * Read in each segment to find the segment we are looking for
2367c478bd9Sstevel@tonic-gate 	 */
2377c478bd9Sstevel@tonic-gate 	for (j = 0; (j < seg_count) && (!(seg_found)); j++) {
2387c478bd9Sstevel@tonic-gate 		fru_data.buf_start = seg_desc_start;
2397c478bd9Sstevel@tonic-gate 		fru_data.buf = seg_name;
2407c478bd9Sstevel@tonic-gate 		fru_data.read_size = 2;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
2437c478bd9Sstevel@tonic-gate 		    &fru_data);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 		seg_desc_start = seg_desc_start + 2;
2467c478bd9Sstevel@tonic-gate 		fru_data.buf_start = seg_desc_start;
2477c478bd9Sstevel@tonic-gate 		fru_data.buf = (char *)segment;
2487c478bd9Sstevel@tonic-gate 		fru_data.read_size = sizeof (seg_desc_t);
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
2517c478bd9Sstevel@tonic-gate 		    &fru_data);
2527c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS) {
2537c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
2547c478bd9Sstevel@tonic-gate 			    "Failed psvc_get_attr for FRU info\n");
2557c478bd9Sstevel@tonic-gate 			return (PSVC_FAILURE);
2567c478bd9Sstevel@tonic-gate 		}
2577c478bd9Sstevel@tonic-gate 		seg_desc_start = seg_desc_start + sizeof (seg_desc_t);
2587c478bd9Sstevel@tonic-gate 		if (memcmp(seg_name, seg_to_find, 2) == 0) {
2597c478bd9Sstevel@tonic-gate 			seg_found = 1;
2607c478bd9Sstevel@tonic-gate 		}
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate 	return (seg_found);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate int32_t
psvc_update_thresholds_0(psvc_opaque_t hdlp,char * id)2667c478bd9Sstevel@tonic-gate psvc_update_thresholds_0(psvc_opaque_t hdlp, char *id)
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
2697c478bd9Sstevel@tonic-gate 	fru_info_t fru_data;
2707c478bd9Sstevel@tonic-gate 	char *fru, part_no[7];
2717c478bd9Sstevel@tonic-gate 	int16_t data_offset;
2727c478bd9Sstevel@tonic-gate 	int32_t fru_count, i, j, temp_address;
2737c478bd9Sstevel@tonic-gate 	int32_t seg_found, temp;
2747c478bd9Sstevel@tonic-gate 	seg_desc_t segment;
2757c478bd9Sstevel@tonic-gate 	int8_t temps[MAX_TEMP_ATTR];
2767c478bd9Sstevel@tonic-gate 	int32_t num_of_parts = 2;
2777c478bd9Sstevel@tonic-gate 	char fruless_parts[2][7] = {"5015988", "5015675"};
2787c478bd9Sstevel@tonic-gate 	int fd;
2797c478bd9Sstevel@tonic-gate 	FILE *fp;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &fru_count,
2827c478bd9Sstevel@tonic-gate 	    PSVC_FRU);
2837c478bd9Sstevel@tonic-gate 	if (status == PSVC_FAILURE)
2847c478bd9Sstevel@tonic-gate 		return (status);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	for (i = 0; i < fru_count; i++) {
2877c478bd9Sstevel@tonic-gate 		seg_found = 0;
2887c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
2897c478bd9Sstevel@tonic-gate 		    &fru, PSVC_FRU, i);
2907c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
2917c478bd9Sstevel@tonic-gate 			return (status);
2927c478bd9Sstevel@tonic-gate 		seg_found = find_segment(hdlp, fru, &segment, "ES");
2937c478bd9Sstevel@tonic-gate 		if (seg_found == PSVC_FAILURE)
2947c478bd9Sstevel@tonic-gate 			return (PSVC_FAILURE);
2957c478bd9Sstevel@tonic-gate 		else if (seg_found == PSVC_NO_DEVICE)
2967c478bd9Sstevel@tonic-gate 			return (PSVC_SUCCESS);
2977c478bd9Sstevel@tonic-gate 		if (seg_found) {
2987c478bd9Sstevel@tonic-gate 			/*
2997c478bd9Sstevel@tonic-gate 			 * For Littleneck we need to read the offset of the
3007c478bd9Sstevel@tonic-gate 			 * die-sensor data record
3017c478bd9Sstevel@tonic-gate 			 */
3027c478bd9Sstevel@tonic-gate 			temp_address = segment.segoffset + TEMP_OFFSET;
3037c478bd9Sstevel@tonic-gate 			fru_data.buf_start = temp_address;
3047c478bd9Sstevel@tonic-gate 			fru_data.buf = (char *)&data_offset;
3057c478bd9Sstevel@tonic-gate 			fru_data.read_size = sizeof (data_offset);
3067c478bd9Sstevel@tonic-gate 			status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
3077c478bd9Sstevel@tonic-gate 			    &fru_data);
3087c478bd9Sstevel@tonic-gate 			if (status != PSVC_SUCCESS) {
3097c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR,
3107c478bd9Sstevel@tonic-gate 				    "Failed psvc_get_attr for FRU info\n");
3117c478bd9Sstevel@tonic-gate 				return (status);
3127c478bd9Sstevel@tonic-gate 			}
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 			/*
3157c478bd9Sstevel@tonic-gate 			 * Now go and get the new temperature settings
3167c478bd9Sstevel@tonic-gate 			 */
3177c478bd9Sstevel@tonic-gate 			temp_address = segment.segoffset + data_offset;
3187c478bd9Sstevel@tonic-gate 			fru_data.buf_start = temp_address;
3197c478bd9Sstevel@tonic-gate 			fru_data.buf = (char *)&temps;
3207c478bd9Sstevel@tonic-gate 			fru_data.read_size = sizeof (temps);
3217c478bd9Sstevel@tonic-gate 			status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
3227c478bd9Sstevel@tonic-gate 			    &fru_data);
3237c478bd9Sstevel@tonic-gate 			if (status != PSVC_SUCCESS) {
3247c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR,
3257c478bd9Sstevel@tonic-gate 				    "Failed psvc_get_attr for FRU info\n");
3267c478bd9Sstevel@tonic-gate 				return (status);
3277c478bd9Sstevel@tonic-gate 			} else {
3287c478bd9Sstevel@tonic-gate 				/*
3297c478bd9Sstevel@tonic-gate 				 * Now set the updated Thresholds
3307c478bd9Sstevel@tonic-gate 				 */
3317c478bd9Sstevel@tonic-gate 				for (j = 0; j < MAX_TEMP_ATTR; j++) {
3327c478bd9Sstevel@tonic-gate 					temp = temps[j];
3337c478bd9Sstevel@tonic-gate 					status = psvc_set_attr(hdlp, id,
3347c478bd9Sstevel@tonic-gate 					    temp_attr[j], &temp);
3357c478bd9Sstevel@tonic-gate 				}
3367c478bd9Sstevel@tonic-gate 			}
3377c478bd9Sstevel@tonic-gate 		} else {
3387c478bd9Sstevel@tonic-gate 			/*
3397c478bd9Sstevel@tonic-gate 			 * For Littleneck only we need to check for the part
3407c478bd9Sstevel@tonic-gate 			 * number of the CPU as there are parts that do not
3417c478bd9Sstevel@tonic-gate 			 * have the ES segment programmed.
3427c478bd9Sstevel@tonic-gate 			 */
3437c478bd9Sstevel@tonic-gate 			seg_found = find_segment(hdlp, fru, &segment, "SD");
3447c478bd9Sstevel@tonic-gate 			if (seg_found == PSVC_FAILURE)
3457c478bd9Sstevel@tonic-gate 				return (PSVC_FAILURE);
3467c478bd9Sstevel@tonic-gate 			if (seg_found) {
3477c478bd9Sstevel@tonic-gate 				/*
3487c478bd9Sstevel@tonic-gate 				 * We now goto the SD segment to get the part
3497c478bd9Sstevel@tonic-gate 				 * number.
3507c478bd9Sstevel@tonic-gate 				 */
3517c478bd9Sstevel@tonic-gate 				fru_data.buf_start =
3527c478bd9Sstevel@tonic-gate 				    segment.segoffset + PART_NO_OFFSET;
3537c478bd9Sstevel@tonic-gate 				fru_data.buf = part_no;
3547c478bd9Sstevel@tonic-gate 				fru_data.read_size = sizeof (part_no);
3557c478bd9Sstevel@tonic-gate 				status = psvc_get_attr(hdlp, fru,
3567c478bd9Sstevel@tonic-gate 				    PSVC_FRU_INFO_ATTR, &fru_data);
3577c478bd9Sstevel@tonic-gate 				if (status != PSVC_SUCCESS) {
3587c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR, "Failed psvc_get_attr"
3597c478bd9Sstevel@tonic-gate 					    "for FRU info\n");
3607c478bd9Sstevel@tonic-gate 					return (status);
3617c478bd9Sstevel@tonic-gate 				}
3627c478bd9Sstevel@tonic-gate 				/*
3637c478bd9Sstevel@tonic-gate 				 * We are go through the parts list to see
3647c478bd9Sstevel@tonic-gate 				 * if the part number from the FRU is in
3657c478bd9Sstevel@tonic-gate 				 * this list.  If it is we simply return
3667c478bd9Sstevel@tonic-gate 				 * as the FRU is not programmed.
3677c478bd9Sstevel@tonic-gate 				 */
3687c478bd9Sstevel@tonic-gate 				for (j = 0; j < num_of_parts; j++) {
3697c478bd9Sstevel@tonic-gate 					if (memcmp(fruless_parts[j], part_no,
3707c478bd9Sstevel@tonic-gate 						7) == 0) {
3717c478bd9Sstevel@tonic-gate 					return (status);
3727c478bd9Sstevel@tonic-gate 					}
3737c478bd9Sstevel@tonic-gate 				}
3747c478bd9Sstevel@tonic-gate 			}
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 			/*
3777c478bd9Sstevel@tonic-gate 			 * If the Part is not in the Part list and we
3787c478bd9Sstevel@tonic-gate 			 * get to here this means that the FRU is
3797c478bd9Sstevel@tonic-gate 			 * considered broken (no ES segment found)
3807c478bd9Sstevel@tonic-gate 			 * and we need to report this.
3817c478bd9Sstevel@tonic-gate 			 */
3827c478bd9Sstevel@tonic-gate 			/*
3837c478bd9Sstevel@tonic-gate 			 * We make this open, write, close, call
3847c478bd9Sstevel@tonic-gate 			 * because picld starts in rcS.d while print
3857c478bd9Sstevel@tonic-gate 			 * services does not start until later
3867c478bd9Sstevel@tonic-gate 			 * (either rc2.d or rc3.d).
3877c478bd9Sstevel@tonic-gate 			 */
3887c478bd9Sstevel@tonic-gate 			fd = open("/dev/console", O_WRONLY | O_NOCTTY);
3897c478bd9Sstevel@tonic-gate 			if (fd != -1) {
3907c478bd9Sstevel@tonic-gate 				fp = fdopen(fd, "w+");
3917c478bd9Sstevel@tonic-gate 				if (fp != NULL) {
3927c478bd9Sstevel@tonic-gate 					fprintf(fp, NO_FRU_INFO, id);
3937c478bd9Sstevel@tonic-gate 					fclose(fp);
3947c478bd9Sstevel@tonic-gate 				}
3957c478bd9Sstevel@tonic-gate 				close(fd);
3967c478bd9Sstevel@tonic-gate 			}
3977c478bd9Sstevel@tonic-gate 			syslog(LOG_NOTICE, NO_FRU_INFO, id);
3987c478bd9Sstevel@tonic-gate 		}
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 	return (status);
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate int32_t
psvc_check_temperature_policy_0(psvc_opaque_t hdlp,char * id)4047c478bd9Sstevel@tonic-gate psvc_check_temperature_policy_0(psvc_opaque_t hdlp, char *id)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate 	int32_t lo_warn, hi_warn, lo_shut, hi_shut;
4077c478bd9Sstevel@tonic-gate 	uint64_t features;
4087c478bd9Sstevel@tonic-gate 	int32_t temp;
4097c478bd9Sstevel@tonic-gate 	char previous_state[32];
4107c478bd9Sstevel@tonic-gate 	char state[32];
4117c478bd9Sstevel@tonic-gate 	char fault[32];
4127c478bd9Sstevel@tonic-gate 	char label[32];
4137c478bd9Sstevel@tonic-gate 	boolean_t pr;
4147c478bd9Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
415*298b7f4cSjfrank 	int retry;
416*298b7f4cSjfrank 	int8_t temp_oor;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &pr);
4197c478bd9Sstevel@tonic-gate 	if ((status != PSVC_SUCCESS) || (pr != PSVC_PRESENT)) {
4207c478bd9Sstevel@tonic-gate 		return (status);
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_FEATURES_ATTR, &features);
4247c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4257c478bd9Sstevel@tonic-gate 		return (status);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_LO_WARN_ATTR, &lo_warn);
4287c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4297c478bd9Sstevel@tonic-gate 		return (status);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_LO_SHUT_ATTR, &lo_shut);
4327c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4337c478bd9Sstevel@tonic-gate 		return (status);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_HI_WARN_ATTR, &hi_warn);
4367c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4377c478bd9Sstevel@tonic-gate 		return (status);
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_HI_SHUT_ATTR, &hi_shut);
4407c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4417c478bd9Sstevel@tonic-gate 		return (status);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
4447c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4457c478bd9Sstevel@tonic-gate 		return (status);
4467c478bd9Sstevel@tonic-gate 
447*298b7f4cSjfrank 	retry = 0;
448*298b7f4cSjfrank 	do {
449*298b7f4cSjfrank 		if (retry)
450*298b7f4cSjfrank 			(void) sleep(retry_sleep_temp);
451*298b7f4cSjfrank 		status = psvc_get_attr(hdlp, id, PSVC_SENSOR_VALUE_ATTR, &temp);
452*298b7f4cSjfrank 		if (status != PSVC_SUCCESS) {
453*298b7f4cSjfrank 			if ((errno == ENOENT) || (errno == ENXIO))
454*298b7f4cSjfrank 				return (PSVC_SUCCESS);
455*298b7f4cSjfrank 			else
456*298b7f4cSjfrank 				return (PSVC_FAILURE);
457*298b7f4cSjfrank 		}
458*298b7f4cSjfrank 		temp_oor = 0;
459*298b7f4cSjfrank 		if (((features & PSVC_LOW_SHUT) && temp <= lo_shut) ||
460*298b7f4cSjfrank 		    ((features & PSVC_LOW_WARN) && temp <= lo_warn) ||
461*298b7f4cSjfrank 		    ((features & PSVC_HIGH_SHUT) && temp >= hi_shut) ||
462*298b7f4cSjfrank 		    ((features & PSVC_HIGH_WARN) && temp >= hi_warn))
463*298b7f4cSjfrank 			temp_oor = 1;
464*298b7f4cSjfrank 		retry++;
465*298b7f4cSjfrank 	} while ((retry < n_retry_temp) && temp_oor);
466*298b7f4cSjfrank 
4677c478bd9Sstevel@tonic-gate 	if ((features & PSVC_LOW_SHUT) && temp <= lo_shut) {
4687c478bd9Sstevel@tonic-gate 		strcpy(state, PSVC_ERROR);
4697c478bd9Sstevel@tonic-gate 		strcpy(fault, PSVC_TEMP_LO_SHUT);
4707c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, LOWTEMP_CRITICAL_MSG, temp, label);
4717c478bd9Sstevel@tonic-gate 	} else if ((features & PSVC_LOW_WARN) && temp <= lo_warn) {
4727c478bd9Sstevel@tonic-gate 		strcpy(state, PSVC_ERROR);
4737c478bd9Sstevel@tonic-gate 		strcpy(fault, PSVC_TEMP_LO_WARN);
4747c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, LOWTEMP_WARNING_MSG, temp, label);
4757c478bd9Sstevel@tonic-gate 	} else if ((features & PSVC_HIGH_SHUT) && temp >= hi_shut) {
4767c478bd9Sstevel@tonic-gate 		strcpy(state, PSVC_ERROR);
4777c478bd9Sstevel@tonic-gate 		strcpy(fault, PSVC_TEMP_HI_SHUT);
4787c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, HIGHTEMP_CRITICAL_MSG,  temp, label);
4797c478bd9Sstevel@tonic-gate 	} else if ((features & PSVC_HIGH_WARN) && temp >= hi_warn) {
4807c478bd9Sstevel@tonic-gate 		strcpy(state, PSVC_ERROR);
4817c478bd9Sstevel@tonic-gate 		strcpy(fault, PSVC_TEMP_HI_WARN);
4827c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, HIGHTEMP_WARNING_MSG, temp, label);
4837c478bd9Sstevel@tonic-gate 	} else {
4847c478bd9Sstevel@tonic-gate 		/* within limits */
4857c478bd9Sstevel@tonic-gate 		strcpy(state, PSVC_OK);
4867c478bd9Sstevel@tonic-gate 		strcpy(fault, PSVC_NO_FAULT);
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
4907c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4917c478bd9Sstevel@tonic-gate 		return (status);
4927c478bd9Sstevel@tonic-gate 	status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
4937c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4947c478bd9Sstevel@tonic-gate 		return (status);
4957c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR,
4967c478bd9Sstevel@tonic-gate 		previous_state);
4977c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
4987c478bd9Sstevel@tonic-gate 		return (status);
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	if (strcmp(previous_state, state) != 0) {
5017c478bd9Sstevel@tonic-gate 		char *led_id;
5027c478bd9Sstevel@tonic-gate 		uint8_t _8bit_val;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 		led_id = "SYSTEM_FAULT_LED_WR";
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, led_id,
5077c478bd9Sstevel@tonic-gate 			PSVC_GPIO_VALUE_ATTR, &_8bit_val);
5087c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
5097c478bd9Sstevel@tonic-gate 			return (status);
5107c478bd9Sstevel@tonic-gate 		if (strcmp(state, PSVC_ERROR) == 0)
5117c478bd9Sstevel@tonic-gate 			_8bit_val &= 0xef;  /* clear bit 4 */
5127c478bd9Sstevel@tonic-gate 		else
5137c478bd9Sstevel@tonic-gate 			_8bit_val |= 0x10;  /* set bit 4 */
5147c478bd9Sstevel@tonic-gate 		_8bit_val |= 0xe4;  /* set bits 3, 5, 6, 7 */
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 		status = psvc_set_attr(hdlp, led_id,
5177c478bd9Sstevel@tonic-gate 			PSVC_GPIO_VALUE_ATTR, &_8bit_val);
5187c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
5197c478bd9Sstevel@tonic-gate 			return (status);
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	}
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	return (PSVC_SUCCESS);
5247c478bd9Sstevel@tonic-gate }
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate static int32_t ps0_addr[] = {0, 0xac};
5277c478bd9Sstevel@tonic-gate static int32_t ps1_addr[] = {0, 0xae};
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate int32_t
psvc_ps_hotplug_policy_0(psvc_opaque_t hdlp,char * id)5307c478bd9Sstevel@tonic-gate psvc_ps_hotplug_policy_0(psvc_opaque_t hdlp, char *id)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	boolean_t presence, previous_presence;
5337c478bd9Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
5347c478bd9Sstevel@tonic-gate 	char label[32];
5357c478bd9Sstevel@tonic-gate 	int i;
5367c478bd9Sstevel@tonic-gate 	int32_t led_count;
5377c478bd9Sstevel@tonic-gate 	char state[32], fault[32];
5387c478bd9Sstevel@tonic-gate 	boolean_t ps_type;
5397c478bd9Sstevel@tonic-gate 	char *sensor_id, *led_id;
5407c478bd9Sstevel@tonic-gate 	char led_state[32];
5417c478bd9Sstevel@tonic-gate 	picl_nodehdl_t parent_node;
5427c478bd9Sstevel@tonic-gate 	char parent_path[256];
5437c478bd9Sstevel@tonic-gate 	picl_nodehdl_t child_node;
5447c478bd9Sstevel@tonic-gate 	int ps_instance;
5457c478bd9Sstevel@tonic-gate 	devctl_hdl_t bus_handle, dev_handle;
5467c478bd9Sstevel@tonic-gate 	devctl_ddef_t ddef_hdl;
5477c478bd9Sstevel@tonic-gate 	char devpath[256];
548*298b7f4cSjfrank 	int retry;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR,
5517c478bd9Sstevel@tonic-gate 		&previous_presence);
5527c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
5537c478bd9Sstevel@tonic-gate 		return (status);
554*298b7f4cSjfrank 	retry = 0;
555*298b7f4cSjfrank 	do {
556*298b7f4cSjfrank 		if (retry)
557*298b7f4cSjfrank 			(void) sleep(retry_sleep_hotplug);
558*298b7f4cSjfrank 		status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence);
559*298b7f4cSjfrank 		if (status != PSVC_SUCCESS)
560*298b7f4cSjfrank 			return (status);
561*298b7f4cSjfrank 		retry++;
562*298b7f4cSjfrank 	} while ((retry < n_retry_hotplug) && (presence != previous_presence));
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	if (presence == previous_presence) {
5657c478bd9Sstevel@tonic-gate 		/* No change */
5667c478bd9Sstevel@tonic-gate 		return (status);
5677c478bd9Sstevel@tonic-gate 	}
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
5707c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
5717c478bd9Sstevel@tonic-gate 		return (status);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	/* Convert name to node and parent path */
5747c478bd9Sstevel@tonic-gate 	psvcplugin_lookup(id, parent_path, &child_node);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	if (presence == PSVC_PRESENT) {
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 		/* may detect presence before all connections are made */
5797c478bd9Sstevel@tonic-gate 		sleep(1);
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 		/* Device added */
5827c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, DEVICE_INSERTED_MSG, label);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 		/* Verify P/S is correct type */
5867c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
5877c478bd9Sstevel@tonic-gate 			&sensor_id, PSVC_DEV_TYPE_SENSOR, 0);
5887c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
5897c478bd9Sstevel@tonic-gate 			return (status);
5907c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, sensor_id,
5917c478bd9Sstevel@tonic-gate 			PSVC_GPIO_VALUE_ATTR, &ps_type);
5927c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
5937c478bd9Sstevel@tonic-gate 			return (status);
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 		if (ps_type ==  1) {	/* correct p/s */
5967c478bd9Sstevel@tonic-gate 			strcpy(state, PSVC_OK);
5977c478bd9Sstevel@tonic-gate 			strcpy(fault, PSVC_NO_FAULT);
5987c478bd9Sstevel@tonic-gate 			strcpy(led_state, PSVC_LED_OFF);
5997c478bd9Sstevel@tonic-gate 		} else {		/* wrong type */
6007c478bd9Sstevel@tonic-gate 			strcpy(state, PSVC_ERROR);
6017c478bd9Sstevel@tonic-gate 			strcpy(fault, PSVC_PS_TYPE_FLT);
6027c478bd9Sstevel@tonic-gate 			strcpy(led_state, PSVC_LED_ON);
6037c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, PS_TYPE_MSG, label);
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 		}
6067c478bd9Sstevel@tonic-gate 		status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
6077c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
6087c478bd9Sstevel@tonic-gate 			return (status);
6097c478bd9Sstevel@tonic-gate 		status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
6107c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
6117c478bd9Sstevel@tonic-gate 			return (status);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 		/* Set state of fault LEDs */
6147c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, sensor_id, PSVC_ASSOC_MATCHES_ATTR,
6157c478bd9Sstevel@tonic-gate 			&led_count, PSVC_DEV_FAULT_LED);
6167c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS) {
6177c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
6187c478bd9Sstevel@tonic-gate 				gettext("Failed for PSVC_DEV_FAULT_LED\n"));
6197c478bd9Sstevel@tonic-gate 			return (status);
6207c478bd9Sstevel@tonic-gate 		}
6217c478bd9Sstevel@tonic-gate 		for (i = 0; i < led_count; ++i) {
6227c478bd9Sstevel@tonic-gate 			status = psvc_get_attr(hdlp, sensor_id,
6237c478bd9Sstevel@tonic-gate 				PSVC_ASSOC_ID_ATTR, &led_id,
6247c478bd9Sstevel@tonic-gate 				PSVC_DEV_FAULT_LED, i);
6257c478bd9Sstevel@tonic-gate 			if (status != PSVC_SUCCESS)
6267c478bd9Sstevel@tonic-gate 				return (status);
6277c478bd9Sstevel@tonic-gate 			status = psvc_set_attr(hdlp, led_id,
6287c478bd9Sstevel@tonic-gate 				PSVC_LED_STATE_ATTR, led_state);
6297c478bd9Sstevel@tonic-gate 			if (status != PSVC_SUCCESS)
6307c478bd9Sstevel@tonic-gate 				return (status);
6317c478bd9Sstevel@tonic-gate 		}
6327c478bd9Sstevel@tonic-gate 		ptree_get_node_by_path(parent_path, &parent_node);
6337c478bd9Sstevel@tonic-gate 		ptree_add_node(parent_node, child_node);
6347c478bd9Sstevel@tonic-gate 	} else {
6357c478bd9Sstevel@tonic-gate 		/* Device removed */
6367c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, DEVICE_REMOVED_MSG, label);
6377c478bd9Sstevel@tonic-gate 		ptree_delete_node(child_node);
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence);
6417c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
6427c478bd9Sstevel@tonic-gate 		return (status);
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &ps_instance);
6457c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
6467c478bd9Sstevel@tonic-gate 		return (status);
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	if (presence != PSVC_PRESENT) {
6497c478bd9Sstevel@tonic-gate 		if (ps_instance == 0)
6507c478bd9Sstevel@tonic-gate 			strcpy(devpath,
6517c478bd9Sstevel@tonic-gate 	"/devices/pci@8,700000/ebus@5/i2c@1,30/power-supply@0,ac:power-supply");
6527c478bd9Sstevel@tonic-gate 		else
6537c478bd9Sstevel@tonic-gate 			strcpy(devpath,
6547c478bd9Sstevel@tonic-gate 	"/devices/pci@8,700000/ebus@5/i2c@1,30/power-supply@0,ae:power-supply");
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 		dev_handle = devctl_device_acquire(devpath, 0);
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 		if (devctl_device_remove(dev_handle)) {
6597c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, DEVTREE_NODE_DELETE_FAILED, label,
6607c478bd9Sstevel@tonic-gate 				errno);
6617c478bd9Sstevel@tonic-gate 			status = PSVC_FAILURE;
6627c478bd9Sstevel@tonic-gate 		} else {
6637c478bd9Sstevel@tonic-gate 			devctl_release(dev_handle);
6647c478bd9Sstevel@tonic-gate 			status = PSVC_SUCCESS;
6657c478bd9Sstevel@tonic-gate 		}
6667c478bd9Sstevel@tonic-gate 		return (status);
6677c478bd9Sstevel@tonic-gate 	}
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	/*
6707c478bd9Sstevel@tonic-gate 	 * We fall through to here if the device has been inserted.
6717c478bd9Sstevel@tonic-gate 	 * Add the devinfo tree node entry for the seeprom and attach
6727c478bd9Sstevel@tonic-gate 	 * the i2c seeprom driver
6737c478bd9Sstevel@tonic-gate 	 */
6747c478bd9Sstevel@tonic-gate 	ddef_hdl = devctl_ddef_alloc("power-supply", 0);
6757c478bd9Sstevel@tonic-gate 	(void) devctl_ddef_string(ddef_hdl, "compatible", "i2c-at24c64");
6767c478bd9Sstevel@tonic-gate 	if (ps_instance == 0) {
6777c478bd9Sstevel@tonic-gate 		(void) devctl_ddef_int_array(ddef_hdl, "reg", 2, ps0_addr);
6787c478bd9Sstevel@tonic-gate 	} else {
6797c478bd9Sstevel@tonic-gate 		(void) devctl_ddef_int_array(ddef_hdl, "reg", 2, ps1_addr);
6807c478bd9Sstevel@tonic-gate 	}
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	bus_handle = devctl_bus_acquire(
6837c478bd9Sstevel@tonic-gate 			"/devices/pci@8,700000/ebus@5/i2c@1,30:i2c", 0);
6847c478bd9Sstevel@tonic-gate 	if (devctl_bus_dev_create(bus_handle, ddef_hdl, 0, &dev_handle)) {
6857c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, DEVTREE_NODE_CREATE_FAILED, label, errno);
6867c478bd9Sstevel@tonic-gate 		status = PSVC_FAILURE;
6877c478bd9Sstevel@tonic-gate 	} else
6887c478bd9Sstevel@tonic-gate 		devctl_release(dev_handle);
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	devctl_release(bus_handle);
6917c478bd9Sstevel@tonic-gate 	devctl_ddef_free(ddef_hdl);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	return (status);
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate int32_t
psvc_device_fail_notifier_policy_0(psvc_opaque_t hdlp,char * id)6977c478bd9Sstevel@tonic-gate psvc_device_fail_notifier_policy_0(psvc_opaque_t hdlp, char *id)
6987c478bd9Sstevel@tonic-gate {
6997c478bd9Sstevel@tonic-gate 	int32_t sensor_count;
7007c478bd9Sstevel@tonic-gate 	char *led_id, *sensor_id;
7017c478bd9Sstevel@tonic-gate 	int i;
7027c478bd9Sstevel@tonic-gate 	char state[32], fault[32], previous_state[32];
7037c478bd9Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
7047c478bd9Sstevel@tonic-gate 	boolean_t present;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &present);
7077c478bd9Sstevel@tonic-gate 	if (status == PSVC_FAILURE)
7087c478bd9Sstevel@tonic-gate 		return (status);
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	if (present == PSVC_ABSENT) {
7117c478bd9Sstevel@tonic-gate 		errno = ENODEV;
7127c478bd9Sstevel@tonic-gate 		return (PSVC_FAILURE);
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
7167c478bd9Sstevel@tonic-gate 		PSVC_DEV_FAULT_SENSOR);
7177c478bd9Sstevel@tonic-gate 	for (i = 0; i < sensor_count; ++i) {
7187c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
7197c478bd9Sstevel@tonic-gate 			&sensor_id, PSVC_DEV_FAULT_SENSOR, i);
7207c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
7217c478bd9Sstevel@tonic-gate 			return (status);
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, sensor_id,
7247c478bd9Sstevel@tonic-gate 			PSVC_SWITCH_STATE_ATTR, state);
7257c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
7267c478bd9Sstevel@tonic-gate 			return (status);
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 		if (strcmp(state, PSVC_SWITCH_ON) == 0) {
7297c478bd9Sstevel@tonic-gate 			strcpy(state, PSVC_ERROR);
7307c478bd9Sstevel@tonic-gate 			strcpy(fault, PSVC_GEN_FAULT);
7317c478bd9Sstevel@tonic-gate 		} else {
7327c478bd9Sstevel@tonic-gate 			strcpy(state, PSVC_OK);
7337c478bd9Sstevel@tonic-gate 			strcpy(fault, PSVC_NO_FAULT);
7347c478bd9Sstevel@tonic-gate 		}
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 		status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
7377c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
7387c478bd9Sstevel@tonic-gate 			return (status);
7397c478bd9Sstevel@tonic-gate 		status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
7407c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
7417c478bd9Sstevel@tonic-gate 			return (status);
7427c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR,
7437c478bd9Sstevel@tonic-gate 			previous_state);
7447c478bd9Sstevel@tonic-gate 		if (status != PSVC_SUCCESS)
7457c478bd9Sstevel@tonic-gate 			return (status);
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 		if (strcmp(state, previous_state) != 0) {
7487c478bd9Sstevel@tonic-gate 			char sensor_label[32];
7497c478bd9Sstevel@tonic-gate 			char dev_label[32];
7507c478bd9Sstevel@tonic-gate 			uint8_t _8bit_val;
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 			psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, dev_label);
7537c478bd9Sstevel@tonic-gate 			psvc_get_attr(hdlp, sensor_id, PSVC_LABEL_ATTR,
7547c478bd9Sstevel@tonic-gate 			    sensor_label);
7557c478bd9Sstevel@tonic-gate 			if (strcmp(state, PSVC_ERROR) == 0)
7567c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, DEVICE_FAILURE_MSG, dev_label,
7577c478bd9Sstevel@tonic-gate 					sensor_label);
7587c478bd9Sstevel@tonic-gate 			else
7597c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, DEVICE_OK_MSG, dev_label);
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 			led_id = "SYSTEM_FAULT_LED_WR";
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 			status = psvc_get_attr(hdlp, led_id,
7647c478bd9Sstevel@tonic-gate 				PSVC_GPIO_VALUE_ATTR, &_8bit_val);
7657c478bd9Sstevel@tonic-gate 			if (status != PSVC_SUCCESS)
7667c478bd9Sstevel@tonic-gate 				return (status);
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 			if (strcmp(state, PSVC_ERROR) == 0)
7697c478bd9Sstevel@tonic-gate 				_8bit_val &= 0xef;  /* clear bit 4 */
7707c478bd9Sstevel@tonic-gate 			else
7717c478bd9Sstevel@tonic-gate 				_8bit_val |= 0x10;  /* set bit 4 */
7727c478bd9Sstevel@tonic-gate 			_8bit_val |= 0xe4;  /* set bits 3, 5, 6, 7 */
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 			status = psvc_set_attr(hdlp, led_id,
7757c478bd9Sstevel@tonic-gate 				PSVC_GPIO_VALUE_ATTR, &_8bit_val);
7767c478bd9Sstevel@tonic-gate 			if (status != PSVC_SUCCESS)
7777c478bd9Sstevel@tonic-gate 				return (status);
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 		}
7807c478bd9Sstevel@tonic-gate 	}
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	return (PSVC_SUCCESS);
7837c478bd9Sstevel@tonic-gate }
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate int32_t
psvc_init_led_policy_0(psvc_opaque_t hdlp,char * id)7867c478bd9Sstevel@tonic-gate psvc_init_led_policy_0(psvc_opaque_t hdlp, char *id)
7877c478bd9Sstevel@tonic-gate {
7887c478bd9Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
7897c478bd9Sstevel@tonic-gate 	uint8_t _8bit_val;
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	status = psvc_get_attr(hdlp, id,
7927c478bd9Sstevel@tonic-gate 		PSVC_GPIO_VALUE_ATTR, &_8bit_val);
7937c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
7947c478bd9Sstevel@tonic-gate 		return (status);
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	_8bit_val &= 0xef;  /* clear bit 4 */
7977c478bd9Sstevel@tonic-gate 	_8bit_val |= 0xf4;  /* set bits 3, 5, 6, 7 */
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	status = psvc_set_attr(hdlp, id,
8007c478bd9Sstevel@tonic-gate 		PSVC_GPIO_VALUE_ATTR, &_8bit_val);
8017c478bd9Sstevel@tonic-gate 	if (status != PSVC_SUCCESS)
8027c478bd9Sstevel@tonic-gate 		return (status);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	return (status);
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate static int32_t
check_cpu_temp_fault(psvc_opaque_t hdlp,char * cpu,int32_t cpu_count)8087c478bd9Sstevel@tonic-gate check_cpu_temp_fault(psvc_opaque_t hdlp, char *cpu, int32_t cpu_count)
8097c478bd9Sstevel@tonic-gate {
8107c478bd9Sstevel@tonic-gate 	char *sensorid;
8117c478bd9Sstevel@tonic-gate 	int32_t sensor_count;
8127c478bd9Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
8137c478bd9Sstevel@tonic-gate 	int32_t i;
8147c478bd9Sstevel@tonic-gate 	char fault[32];
815*298b7f4cSjfrank 	int retry;
816*298b7f4cSjfrank 	int8_t temp_oor;
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	psvc_get_attr(hdlp, cpu, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
8197c478bd9Sstevel@tonic-gate 		PSVC_DEV_TEMP_SENSOR);
8207c478bd9Sstevel@tonic-gate 	for (i = 0; i < sensor_count; ++i) {
8217c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, cpu, PSVC_ASSOC_ID_ATTR,
8227c478bd9Sstevel@tonic-gate 			&sensorid, PSVC_DEV_TEMP_SENSOR, i);
8237c478bd9Sstevel@tonic-gate 		if (status == PSVC_FAILURE)
8247c478bd9Sstevel@tonic-gate 			return (status);
8257c478bd9Sstevel@tonic-gate 
826*298b7f4cSjfrank 		retry = 0;
827*298b7f4cSjfrank 		do {
828*298b7f4cSjfrank 			if (retry)
829*298b7f4cSjfrank 				(void) sleep(retry_sleep_temp_shutdown);
830*298b7f4cSjfrank 			status = psvc_get_attr(hdlp, sensorid,
831*298b7f4cSjfrank 			    PSVC_FAULTID_ATTR, fault);
832*298b7f4cSjfrank 			if (status == PSVC_FAILURE)
833*298b7f4cSjfrank 				return (status);
834*298b7f4cSjfrank 			temp_oor = 0;
835*298b7f4cSjfrank 			if ((strcmp(fault, PSVC_TEMP_HI_SHUT) == 0) ||
836*298b7f4cSjfrank 			    (strcmp(fault, PSVC_TEMP_LO_SHUT) == 0)) {
837*298b7f4cSjfrank 				temp_oor = 1;
838*298b7f4cSjfrank 			}
839*298b7f4cSjfrank 			retry++;
840*298b7f4cSjfrank 		} while ((retry < n_retry_temp_shutdown) && temp_oor);
8417c478bd9Sstevel@tonic-gate 
842*298b7f4cSjfrank 		if (temp_oor) {
8437c478bd9Sstevel@tonic-gate 			system(shutdown_string);
8447c478bd9Sstevel@tonic-gate 		}
8457c478bd9Sstevel@tonic-gate 	}
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	return (status);
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate int32_t
psvc_shutdown_policy_0(psvc_opaque_t hdlp,char * id)8517c478bd9Sstevel@tonic-gate psvc_shutdown_policy_0(psvc_opaque_t hdlp, char *id)
8527c478bd9Sstevel@tonic-gate {
8537c478bd9Sstevel@tonic-gate 	int32_t cpu_count;
8547c478bd9Sstevel@tonic-gate 	char *cpuid;
8557c478bd9Sstevel@tonic-gate 	int32_t i;
8567c478bd9Sstevel@tonic-gate 	boolean_t present;
8577c478bd9Sstevel@tonic-gate 	int32_t status = PSVC_SUCCESS;
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count,
8607c478bd9Sstevel@tonic-gate 		PSVC_CPU);
8617c478bd9Sstevel@tonic-gate 	for (i = 0; i < cpu_count; ++i) {
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &cpuid,
8647c478bd9Sstevel@tonic-gate 			PSVC_CPU, i);
8657c478bd9Sstevel@tonic-gate 		if (status == PSVC_FAILURE)
8667c478bd9Sstevel@tonic-gate 			return (status);
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 		status = psvc_get_attr(hdlp, cpuid,
8697c478bd9Sstevel@tonic-gate 			PSVC_PRESENCE_ATTR, &present);
8707c478bd9Sstevel@tonic-gate 		if (status == PSVC_FAILURE && present == PSVC_PRESENT)
8717c478bd9Sstevel@tonic-gate 			return (status);
8727c478bd9Sstevel@tonic-gate 		if (present == PSVC_PRESENT) {
8737c478bd9Sstevel@tonic-gate 			status = check_cpu_temp_fault(hdlp, cpuid, cpu_count);
8747c478bd9Sstevel@tonic-gate 			if (status == PSVC_FAILURE && errno != ENODEV)
8757c478bd9Sstevel@tonic-gate 				return (status);
8767c478bd9Sstevel@tonic-gate 		}
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	return (PSVC_SUCCESS);
8807c478bd9Sstevel@tonic-gate }
881