xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4u/littleneck/psvcpolicy/psvcpolicy.c (revision 3ce5372277f4657ad0e52d36c979527c4ca22de2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Littleneck platform specific environment monitoring policies
31  */
32 
33 #include	<syslog.h>
34 #include	<unistd.h>
35 #include	<stdio.h>
36 #include 	<libintl.h>
37 #include	<string.h>
38 #include	<stdlib.h>
39 #include	<errno.h>
40 #include	<sys/types.h>
41 #include	<fcntl.h>
42 #include	<sys/time.h>
43 #include	<sys/time_impl.h>
44 #include	<sys/signal.h>
45 #include	<sys/devctl.h>
46 #include	<libdevinfo.h>
47 #include	<libdevice.h>
48 #include	<picl.h>
49 #include	<picltree.h>
50 #include	<limits.h>
51 #include	<sys/systeminfo.h>
52 #include	<psvc_objects.h>
53 
54 /*LINTLIBRARY*/
55 
56 #define	LOWTEMP_CRITICAL_MSG		\
57 	gettext("CRITICAL : LOW TEMPERATURE DETECTED %d, %s")
58 #define	LOWTEMP_WARNING_MSG		\
59 	gettext("WARNING : LOW TEMPERATURE DETECTED %d, %s")
60 #define	HIGHTEMP_CRITICAL_MSG		\
61 	gettext("CRITICAL : HIGH TEMPERATURE DETECTED %d, %s")
62 #define	HIGHTEMP_WARNING_MSG		\
63 	gettext("WARNING : HIGH TEMPERATURE DETECTED %d, %s")
64 #define	DEVICE_INSERTED_MSG	gettext("Device %s inserted")
65 #define	DEVICE_REMOVED_MSG	gettext("Device %s removed")
66 #define	PS_TYPE_MSG			\
67 	gettext("WARNING: Incorrect type power supply inserted, device %s")
68 #define	DEVICE_FAILURE_MSG		\
69 	gettext("WARNING: Device %s failure detected by sensor %s\n")
70 #define	DEVICE_OK_MSG	gettext("Device %s OK")
71 #define	DEVTREE_NODE_CREATE_FAILED	\
72 	gettext("psvc PICL plugin: Failed to create node for %s, errno = %d")
73 #define	DEVTREE_NODE_DELETE_FAILED	\
74 	gettext("psvc PICL plugin: Failed to delete node for %s, errno = %d")
75 #define	NO_FRU_INFO			\
76 	gettext("No FRU Information for %s using default temperatures\n")
77 
78 static char *shutdown_string = "shutdown -y -g 60 -i 5 \"OVERTEMP condition\"";
79 
80 typedef struct seg_desc {
81 	int32_t segdesc;
82 	int16_t segoffset;
83 	int16_t seglength;
84 } seg_desc_t;
85 
86 static int32_t find_segment(psvc_opaque_t hdlp, char *fru, seg_desc_t *segment,
87     char *seg_to_find);
88 
89 static int temp_attr[] = {
90 	PSVC_HW_HI_SHUT_ATTR, PSVC_HI_SHUT_ATTR, PSVC_HI_WARN_ATTR,
91 	PSVC_LO_WARN_ATTR, PSVC_LO_SHUT_ATTR, PSVC_HW_LO_SHUT_ATTR
92 };
93 
94 #define	MAX_TEMP_ATTR	(sizeof (temp_attr)/sizeof (temp_attr[0]))
95 #define	TEMP_OFFSET	12
96 #define	PART_NO_OFFSET	152
97 #define	NUM_OF_SEG_ADDR	0x1805
98 #define	SEG_DESC_START 	0x1806
99 #define	PSVC_NO_DEVICE 	-2
100 
101 /*
102  * The I2C bus is noisy, and the state may be incorrectly reported as
103  * having changed.  When the state changes, we attempt to confirm by
104  * retrying.  If any retries indicate that the state has not changed, we
105  * assume the state change(s) were incorrect and the state has not changed.
106  * The following variables are used to store the tuneable values read in
107  * from the optional i2cparam.conf file for this shared object library.
108  */
109 static int n_retry_temp = PSVC_THRESHOLD_COUNTER;
110 static int retry_sleep_temp = 1;
111 static int n_retry_hotplug = PSVC_NUM_OF_RETRIES;
112 static int retry_sleep_hotplug = 1;
113 static int n_retry_temp_shutdown = PSVC_NUM_OF_RETRIES;
114 static int retry_sleep_temp_shutdown = 1;
115 
116 typedef struct {
117 	int *pvar;
118 	char *texttag;
119 } i2c_noise_param_t;
120 
121 static i2c_noise_param_t i2cparams[] = {
122 	&n_retry_temp, "n_retry_temp",
123 	&retry_sleep_temp, "retry_sleep_temp",
124 	&n_retry_hotplug, "n_retry_hotplug",
125 	&retry_sleep_hotplug, "retry_sleep_hotplug",
126 	NULL, NULL
127 };
128 
129 #pragma init(i2cparams_load)
130 
131 static void
132 i2cparams_debug(i2c_noise_param_t *pi2cparams, char *platform,
133 	int usingDefaults)
134 {
135 	char s[128];
136 	i2c_noise_param_t *p;
137 
138 	if (!usingDefaults) {
139 		(void) snprintf(s, sizeof (s),
140 		    "# Values from /usr/platform/%s/lib/i2cparam.conf\n",
141 		    platform);
142 		syslog(LOG_WARNING, "%s", s);
143 	} else {
144 		/* no file - we're using the defaults */
145 		(void) snprintf(s, sizeof (s),
146 "# No /usr/platform/%s/lib/i2cparam.conf file, using defaults\n",
147 		    platform);
148 	}
149 	(void) fputs(s, stdout);
150 	p = pi2cparams;
151 	while (p->pvar != NULL) {
152 		(void) snprintf(s, sizeof (s), "%s %d\n", p->texttag,
153 		    *(p->pvar));
154 		if (!usingDefaults)
155 			syslog(LOG_WARNING, "%s", s);
156 		(void) fputs(s, stdout);
157 		p++;
158 	}
159 }
160 
161 static void
162 i2cparams_load(void)
163 {
164 	FILE *fp;
165 	char filename[PATH_MAX];
166 	char platform[64];
167 	char s[128];
168 	char var[128];
169 	int val;
170 	i2c_noise_param_t *p;
171 
172 	if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
173 		syslog(LOG_ERR, "sysinfo error %s\n", strerror(errno));
174 		return;
175 	}
176 	(void) snprintf(filename, sizeof (filename),
177 	    "/usr/platform/%s/lib/i2cparam.conf", platform);
178 	/* read thru the i2cparam.conf file and set variables */
179 	if ((fp = fopen(filename, "r")) != NULL) {
180 		while (fgets(s, sizeof (s), fp) != NULL) {
181 			if (s[0] == '#') /* skip comment lines */
182 				continue;
183 			/* try to find a string match and get the value */
184 			if (sscanf(s, "%127s %d", var, &val) != 2)
185 				continue;
186 			if (val < 1)
187 				val = 1;  /* clamp min value */
188 			p = &(i2cparams[0]);
189 			while (p->pvar != NULL) {
190 				if (strncmp(p->texttag, var, sizeof (var)) ==
191 				    0) {
192 					*(p->pvar) = val;
193 					break;
194 				}
195 				p++;
196 			}
197 		}
198 		(void) fclose(fp);
199 	}
200 	/* output the values of the parameters */
201 	i2cparams_debug(&(i2cparams[0]), platform, ((fp == NULL)? 1 : 0));
202 }
203 
204 
205 int32_t
206 find_segment(psvc_opaque_t hdlp, char *fru, seg_desc_t *segment,
207     char seg_to_find[2])
208 {
209 	int32_t seg_found = 0, status;
210 	int32_t seg_desc_start = SEG_DESC_START, j;
211 	int8_t seg_count;
212 	char seg_name[2];
213 	fru_info_t fru_data;
214 
215 	/*
216 	 * Read the number of segments in the Read Only section
217 	 */
218 	fru_data.buf_start = NUM_OF_SEG_ADDR;
219 	fru_data.buf = (char *)&seg_count;
220 	fru_data.read_size = 1;
221 
222 	status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
223 	    &fru_data);
224 	/*
225 	 * We test for ENOENT and ENXIO because Littleneck does not
226 	 * have actual presence sensors and so the only way to see
227 	 * if a part is there or not is to actually make a call to
228 	 * that part.
229 	 */
230 	if (status != PSVC_SUCCESS) {
231 		if ((errno == ENOENT) || (errno == ENXIO))
232 			return (PSVC_NO_DEVICE);
233 		else
234 			return (PSVC_FAILURE);
235 	}
236 	/*
237 	 * Read in each segment to find the segment we are looking for
238 	 */
239 	for (j = 0; (j < seg_count) && (!(seg_found)); j++) {
240 		fru_data.buf_start = seg_desc_start;
241 		fru_data.buf = seg_name;
242 		fru_data.read_size = 2;
243 
244 		status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
245 		    &fru_data);
246 
247 		seg_desc_start = seg_desc_start + 2;
248 		fru_data.buf_start = seg_desc_start;
249 		fru_data.buf = (char *)segment;
250 		fru_data.read_size = sizeof (seg_desc_t);
251 
252 		status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
253 		    &fru_data);
254 		if (status != PSVC_SUCCESS) {
255 			syslog(LOG_ERR,
256 			    "Failed psvc_get_attr for FRU info\n");
257 			return (PSVC_FAILURE);
258 		}
259 		seg_desc_start = seg_desc_start + sizeof (seg_desc_t);
260 		if (memcmp(seg_name, seg_to_find, 2) == 0) {
261 			seg_found = 1;
262 		}
263 	}
264 	return (seg_found);
265 }
266 
267 int32_t
268 psvc_update_thresholds_0(psvc_opaque_t hdlp, char *id)
269 {
270 	int32_t status = PSVC_SUCCESS;
271 	fru_info_t fru_data;
272 	char *fru, part_no[7];
273 	int16_t data_offset;
274 	int32_t fru_count, i, j, temp_address;
275 	int32_t seg_found, temp;
276 	seg_desc_t segment;
277 	int8_t temps[MAX_TEMP_ATTR];
278 	int32_t num_of_parts = 2;
279 	char fruless_parts[2][7] = {"5015988", "5015675"};
280 	int fd;
281 	FILE *fp;
282 
283 	status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &fru_count,
284 	    PSVC_FRU);
285 	if (status == PSVC_FAILURE)
286 		return (status);
287 
288 	for (i = 0; i < fru_count; i++) {
289 		seg_found = 0;
290 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
291 		    &fru, PSVC_FRU, i);
292 		if (status != PSVC_SUCCESS)
293 			return (status);
294 		seg_found = find_segment(hdlp, fru, &segment, "ES");
295 		if (seg_found == PSVC_FAILURE)
296 			return (PSVC_FAILURE);
297 		else if (seg_found == PSVC_NO_DEVICE)
298 			return (PSVC_SUCCESS);
299 		if (seg_found) {
300 			/*
301 			 * For Littleneck we need to read the offset of the
302 			 * die-sensor data record
303 			 */
304 			temp_address = segment.segoffset + TEMP_OFFSET;
305 			fru_data.buf_start = temp_address;
306 			fru_data.buf = (char *)&data_offset;
307 			fru_data.read_size = sizeof (data_offset);
308 			status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
309 			    &fru_data);
310 			if (status != PSVC_SUCCESS) {
311 				syslog(LOG_ERR,
312 				    "Failed psvc_get_attr for FRU info\n");
313 				return (status);
314 			}
315 
316 			/*
317 			 * Now go and get the new temperature settings
318 			 */
319 			temp_address = segment.segoffset + data_offset;
320 			fru_data.buf_start = temp_address;
321 			fru_data.buf = (char *)&temps;
322 			fru_data.read_size = sizeof (temps);
323 			status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
324 			    &fru_data);
325 			if (status != PSVC_SUCCESS) {
326 				syslog(LOG_ERR,
327 				    "Failed psvc_get_attr for FRU info\n");
328 				return (status);
329 			} else {
330 				/*
331 				 * Now set the updated Thresholds
332 				 */
333 				for (j = 0; j < MAX_TEMP_ATTR; j++) {
334 					temp = temps[j];
335 					status = psvc_set_attr(hdlp, id,
336 					    temp_attr[j], &temp);
337 				}
338 			}
339 		} else {
340 			/*
341 			 * For Littleneck only we need to check for the part
342 			 * number of the CPU as there are parts that do not
343 			 * have the ES segment programmed.
344 			 */
345 			seg_found = find_segment(hdlp, fru, &segment, "SD");
346 			if (seg_found == PSVC_FAILURE)
347 				return (PSVC_FAILURE);
348 			if (seg_found) {
349 				/*
350 				 * We now goto the SD segment to get the part
351 				 * number.
352 				 */
353 				fru_data.buf_start =
354 				    segment.segoffset + PART_NO_OFFSET;
355 				fru_data.buf = part_no;
356 				fru_data.read_size = sizeof (part_no);
357 				status = psvc_get_attr(hdlp, fru,
358 				    PSVC_FRU_INFO_ATTR, &fru_data);
359 				if (status != PSVC_SUCCESS) {
360 					syslog(LOG_ERR, "Failed psvc_get_attr"
361 					    "for FRU info\n");
362 					return (status);
363 				}
364 				/*
365 				 * We are go through the parts list to see
366 				 * if the part number from the FRU is in
367 				 * this list.  If it is we simply return
368 				 * as the FRU is not programmed.
369 				 */
370 				for (j = 0; j < num_of_parts; j++) {
371 					if (memcmp(fruless_parts[j], part_no,
372 						7) == 0) {
373 					return (status);
374 					}
375 				}
376 			}
377 
378 			/*
379 			 * If the Part is not in the Part list and we
380 			 * get to here this means that the FRU is
381 			 * considered broken (no ES segment found)
382 			 * and we need to report this.
383 			 */
384 			/*
385 			 * We make this open, write, close, call
386 			 * because picld starts in rcS.d while print
387 			 * services does not start until later
388 			 * (either rc2.d or rc3.d).
389 			 */
390 			fd = open("/dev/console", O_WRONLY | O_NOCTTY);
391 			if (fd != -1) {
392 				fp = fdopen(fd, "w+");
393 				if (fp != NULL) {
394 					fprintf(fp, NO_FRU_INFO, id);
395 					fclose(fp);
396 				}
397 				close(fd);
398 			}
399 			syslog(LOG_NOTICE, NO_FRU_INFO, id);
400 		}
401 	}
402 	return (status);
403 }
404 
405 int32_t
406 psvc_check_temperature_policy_0(psvc_opaque_t hdlp, char *id)
407 {
408 	int32_t lo_warn, hi_warn, lo_shut, hi_shut;
409 	uint64_t features;
410 	int32_t temp;
411 	char previous_state[32];
412 	char state[32];
413 	char fault[32];
414 	char label[32];
415 	boolean_t pr;
416 	int32_t status = PSVC_SUCCESS;
417 	int retry;
418 	int8_t temp_oor;
419 
420 	status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &pr);
421 	if ((status != PSVC_SUCCESS) || (pr != PSVC_PRESENT)) {
422 		return (status);
423 	}
424 
425 	status = psvc_get_attr(hdlp, id, PSVC_FEATURES_ATTR, &features);
426 	if (status != PSVC_SUCCESS)
427 		return (status);
428 
429 	status = psvc_get_attr(hdlp, id, PSVC_LO_WARN_ATTR, &lo_warn);
430 	if (status != PSVC_SUCCESS)
431 		return (status);
432 
433 	status = psvc_get_attr(hdlp, id, PSVC_LO_SHUT_ATTR, &lo_shut);
434 	if (status != PSVC_SUCCESS)
435 		return (status);
436 
437 	status = psvc_get_attr(hdlp, id, PSVC_HI_WARN_ATTR, &hi_warn);
438 	if (status != PSVC_SUCCESS)
439 		return (status);
440 
441 	status = psvc_get_attr(hdlp, id, PSVC_HI_SHUT_ATTR, &hi_shut);
442 	if (status != PSVC_SUCCESS)
443 		return (status);
444 
445 	status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
446 	if (status != PSVC_SUCCESS)
447 		return (status);
448 
449 	retry = 0;
450 	do {
451 		if (retry)
452 			(void) sleep(retry_sleep_temp);
453 		status = psvc_get_attr(hdlp, id, PSVC_SENSOR_VALUE_ATTR, &temp);
454 		if (status != PSVC_SUCCESS) {
455 			if ((errno == ENOENT) || (errno == ENXIO))
456 				return (PSVC_SUCCESS);
457 			else
458 				return (PSVC_FAILURE);
459 		}
460 		temp_oor = 0;
461 		if (((features & PSVC_LOW_SHUT) && temp <= lo_shut) ||
462 		    ((features & PSVC_LOW_WARN) && temp <= lo_warn) ||
463 		    ((features & PSVC_HIGH_SHUT) && temp >= hi_shut) ||
464 		    ((features & PSVC_HIGH_WARN) && temp >= hi_warn))
465 			temp_oor = 1;
466 		retry++;
467 	} while ((retry < n_retry_temp) && temp_oor);
468 
469 	if ((features & PSVC_LOW_SHUT) && temp <= lo_shut) {
470 		strcpy(state, PSVC_ERROR);
471 		strcpy(fault, PSVC_TEMP_LO_SHUT);
472 		syslog(LOG_ERR, LOWTEMP_CRITICAL_MSG, temp, label);
473 	} else if ((features & PSVC_LOW_WARN) && temp <= lo_warn) {
474 		strcpy(state, PSVC_ERROR);
475 		strcpy(fault, PSVC_TEMP_LO_WARN);
476 		syslog(LOG_ERR, LOWTEMP_WARNING_MSG, temp, label);
477 	} else if ((features & PSVC_HIGH_SHUT) && temp >= hi_shut) {
478 		strcpy(state, PSVC_ERROR);
479 		strcpy(fault, PSVC_TEMP_HI_SHUT);
480 		syslog(LOG_ERR, HIGHTEMP_CRITICAL_MSG,  temp, label);
481 	} else if ((features & PSVC_HIGH_WARN) && temp >= hi_warn) {
482 		strcpy(state, PSVC_ERROR);
483 		strcpy(fault, PSVC_TEMP_HI_WARN);
484 		syslog(LOG_ERR, HIGHTEMP_WARNING_MSG, temp, label);
485 	} else {
486 		/* within limits */
487 		strcpy(state, PSVC_OK);
488 		strcpy(fault, PSVC_NO_FAULT);
489 	}
490 
491 	status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
492 	if (status != PSVC_SUCCESS)
493 		return (status);
494 	status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
495 	if (status != PSVC_SUCCESS)
496 		return (status);
497 	status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR,
498 		previous_state);
499 	if (status != PSVC_SUCCESS)
500 		return (status);
501 
502 	if (strcmp(previous_state, state) != 0) {
503 		char *led_id;
504 		uint8_t _8bit_val;
505 
506 		led_id = "SYSTEM_FAULT_LED_WR";
507 
508 		status = psvc_get_attr(hdlp, led_id,
509 			PSVC_GPIO_VALUE_ATTR, &_8bit_val);
510 		if (status != PSVC_SUCCESS)
511 			return (status);
512 		if (strcmp(state, PSVC_ERROR) == 0)
513 			_8bit_val &= 0xef;  /* clear bit 4 */
514 		else
515 			_8bit_val |= 0x10;  /* set bit 4 */
516 		_8bit_val |= 0xe4;  /* set bits 3, 5, 6, 7 */
517 
518 		status = psvc_set_attr(hdlp, led_id,
519 			PSVC_GPIO_VALUE_ATTR, &_8bit_val);
520 		if (status != PSVC_SUCCESS)
521 			return (status);
522 
523 	}
524 
525 	return (PSVC_SUCCESS);
526 }
527 
528 static int32_t ps0_addr[] = {0, 0xac};
529 static int32_t ps1_addr[] = {0, 0xae};
530 
531 int32_t
532 psvc_ps_hotplug_policy_0(psvc_opaque_t hdlp, char *id)
533 {
534 	boolean_t presence, previous_presence;
535 	int32_t status = PSVC_SUCCESS;
536 	char label[32];
537 	int i;
538 	int32_t led_count;
539 	char state[32], fault[32];
540 	boolean_t ps_type;
541 	char *sensor_id, *led_id;
542 	char led_state[32];
543 	picl_nodehdl_t parent_node;
544 	char parent_path[256];
545 	picl_nodehdl_t child_node;
546 	int ps_instance;
547 	devctl_hdl_t bus_handle, dev_handle;
548 	devctl_ddef_t ddef_hdl;
549 	char devpath[256];
550 	int retry;
551 
552 	status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR,
553 		&previous_presence);
554 	if (status != PSVC_SUCCESS)
555 		return (status);
556 	retry = 0;
557 	do {
558 		if (retry)
559 			(void) sleep(retry_sleep_hotplug);
560 		status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence);
561 		if (status != PSVC_SUCCESS)
562 			return (status);
563 		retry++;
564 	} while ((retry < n_retry_hotplug) && (presence != previous_presence));
565 
566 	if (presence == previous_presence) {
567 		/* No change */
568 		return (status);
569 	}
570 
571 	status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
572 	if (status != PSVC_SUCCESS)
573 		return (status);
574 
575 	/* Convert name to node and parent path */
576 	psvcplugin_lookup(id, parent_path, &child_node);
577 
578 	if (presence == PSVC_PRESENT) {
579 
580 		/* may detect presence before all connections are made */
581 		sleep(1);
582 
583 		/* Device added */
584 		syslog(LOG_ERR, DEVICE_INSERTED_MSG, label);
585 
586 
587 		/* Verify P/S is correct type */
588 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
589 			&sensor_id, PSVC_DEV_TYPE_SENSOR, 0);
590 		if (status != PSVC_SUCCESS)
591 			return (status);
592 		status = psvc_get_attr(hdlp, sensor_id,
593 			PSVC_GPIO_VALUE_ATTR, &ps_type);
594 		if (status != PSVC_SUCCESS)
595 			return (status);
596 
597 		if (ps_type ==  1) {	/* correct p/s */
598 			strcpy(state, PSVC_OK);
599 			strcpy(fault, PSVC_NO_FAULT);
600 			strcpy(led_state, PSVC_LED_OFF);
601 		} else {		/* wrong type */
602 			strcpy(state, PSVC_ERROR);
603 			strcpy(fault, PSVC_PS_TYPE_FLT);
604 			strcpy(led_state, PSVC_LED_ON);
605 			syslog(LOG_ERR, PS_TYPE_MSG, label);
606 
607 		}
608 		status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
609 		if (status != PSVC_SUCCESS)
610 			return (status);
611 		status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
612 		if (status != PSVC_SUCCESS)
613 			return (status);
614 
615 		/* Set state of fault LEDs */
616 		status = psvc_get_attr(hdlp, sensor_id, PSVC_ASSOC_MATCHES_ATTR,
617 			&led_count, PSVC_DEV_FAULT_LED);
618 		if (status != PSVC_SUCCESS) {
619 			syslog(LOG_ERR,
620 				gettext("Failed for PSVC_DEV_FAULT_LED\n"));
621 			return (status);
622 		}
623 		for (i = 0; i < led_count; ++i) {
624 			status = psvc_get_attr(hdlp, sensor_id,
625 				PSVC_ASSOC_ID_ATTR, &led_id,
626 				PSVC_DEV_FAULT_LED, i);
627 			if (status != PSVC_SUCCESS)
628 				return (status);
629 			status = psvc_set_attr(hdlp, led_id,
630 				PSVC_LED_STATE_ATTR, led_state);
631 			if (status != PSVC_SUCCESS)
632 				return (status);
633 		}
634 		ptree_get_node_by_path(parent_path, &parent_node);
635 		ptree_add_node(parent_node, child_node);
636 	} else {
637 		/* Device removed */
638 		syslog(LOG_ERR, DEVICE_REMOVED_MSG, label);
639 		ptree_delete_node(child_node);
640 	}
641 
642 	status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence);
643 	if (status != PSVC_SUCCESS)
644 		return (status);
645 
646 	status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &ps_instance);
647 	if (status != PSVC_SUCCESS)
648 		return (status);
649 
650 	if (presence != PSVC_PRESENT) {
651 		if (ps_instance == 0)
652 			strcpy(devpath,
653 	"/devices/pci@8,700000/ebus@5/i2c@1,30/power-supply@0,ac:power-supply");
654 		else
655 			strcpy(devpath,
656 	"/devices/pci@8,700000/ebus@5/i2c@1,30/power-supply@0,ae:power-supply");
657 
658 		dev_handle = devctl_device_acquire(devpath, 0);
659 
660 		if (devctl_device_remove(dev_handle)) {
661 			syslog(LOG_ERR, DEVTREE_NODE_DELETE_FAILED, label,
662 				errno);
663 			status = PSVC_FAILURE;
664 		} else {
665 			devctl_release(dev_handle);
666 			status = PSVC_SUCCESS;
667 		}
668 		return (status);
669 	}
670 
671 	/*
672 	 * We fall through to here if the device has been inserted.
673 	 * Add the devinfo tree node entry for the seeprom and attach
674 	 * the i2c seeprom driver
675 	 */
676 	ddef_hdl = devctl_ddef_alloc("power-supply", 0);
677 	(void) devctl_ddef_string(ddef_hdl, "compatible", "i2c-at24c64");
678 	if (ps_instance == 0) {
679 		(void) devctl_ddef_int_array(ddef_hdl, "reg", 2, ps0_addr);
680 	} else {
681 		(void) devctl_ddef_int_array(ddef_hdl, "reg", 2, ps1_addr);
682 	}
683 
684 	bus_handle = devctl_bus_acquire(
685 			"/devices/pci@8,700000/ebus@5/i2c@1,30:i2c", 0);
686 	if (devctl_bus_dev_create(bus_handle, ddef_hdl, 0, &dev_handle)) {
687 		syslog(LOG_ERR, DEVTREE_NODE_CREATE_FAILED, label, errno);
688 		status = PSVC_FAILURE;
689 	} else
690 		devctl_release(dev_handle);
691 
692 	devctl_release(bus_handle);
693 	devctl_ddef_free(ddef_hdl);
694 
695 	return (status);
696 }
697 
698 int32_t
699 psvc_device_fail_notifier_policy_0(psvc_opaque_t hdlp, char *id)
700 {
701 	int32_t sensor_count;
702 	char *led_id, *sensor_id;
703 	int i;
704 	char state[32], fault[32], previous_state[32];
705 	int32_t status = PSVC_SUCCESS;
706 	boolean_t present;
707 
708 	status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &present);
709 	if (status == PSVC_FAILURE)
710 		return (status);
711 
712 	if (present == PSVC_ABSENT) {
713 		errno = ENODEV;
714 		return (PSVC_FAILURE);
715 	}
716 
717 	psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
718 		PSVC_DEV_FAULT_SENSOR);
719 	for (i = 0; i < sensor_count; ++i) {
720 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
721 			&sensor_id, PSVC_DEV_FAULT_SENSOR, i);
722 		if (status != PSVC_SUCCESS)
723 			return (status);
724 
725 		status = psvc_get_attr(hdlp, sensor_id,
726 			PSVC_SWITCH_STATE_ATTR, state);
727 		if (status != PSVC_SUCCESS)
728 			return (status);
729 
730 		if (strcmp(state, PSVC_SWITCH_ON) == 0) {
731 			strcpy(state, PSVC_ERROR);
732 			strcpy(fault, PSVC_GEN_FAULT);
733 		} else {
734 			strcpy(state, PSVC_OK);
735 			strcpy(fault, PSVC_NO_FAULT);
736 		}
737 
738 		status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
739 		if (status != PSVC_SUCCESS)
740 			return (status);
741 		status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
742 		if (status != PSVC_SUCCESS)
743 			return (status);
744 		status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR,
745 			previous_state);
746 		if (status != PSVC_SUCCESS)
747 			return (status);
748 
749 		if (strcmp(state, previous_state) != 0) {
750 			char sensor_label[32];
751 			char dev_label[32];
752 			uint8_t _8bit_val;
753 
754 			psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, dev_label);
755 			psvc_get_attr(hdlp, sensor_id, PSVC_LABEL_ATTR,
756 			    sensor_label);
757 			if (strcmp(state, PSVC_ERROR) == 0)
758 				syslog(LOG_ERR, DEVICE_FAILURE_MSG, dev_label,
759 					sensor_label);
760 			else
761 				syslog(LOG_ERR, DEVICE_OK_MSG, dev_label);
762 
763 			led_id = "SYSTEM_FAULT_LED_WR";
764 
765 			status = psvc_get_attr(hdlp, led_id,
766 				PSVC_GPIO_VALUE_ATTR, &_8bit_val);
767 			if (status != PSVC_SUCCESS)
768 				return (status);
769 
770 			if (strcmp(state, PSVC_ERROR) == 0)
771 				_8bit_val &= 0xef;  /* clear bit 4 */
772 			else
773 				_8bit_val |= 0x10;  /* set bit 4 */
774 			_8bit_val |= 0xe4;  /* set bits 3, 5, 6, 7 */
775 
776 			status = psvc_set_attr(hdlp, led_id,
777 				PSVC_GPIO_VALUE_ATTR, &_8bit_val);
778 			if (status != PSVC_SUCCESS)
779 				return (status);
780 
781 		}
782 	}
783 
784 	return (PSVC_SUCCESS);
785 }
786 
787 int32_t
788 psvc_init_led_policy_0(psvc_opaque_t hdlp, char *id)
789 {
790 	int32_t status = PSVC_SUCCESS;
791 	uint8_t _8bit_val;
792 
793 	status = psvc_get_attr(hdlp, id,
794 		PSVC_GPIO_VALUE_ATTR, &_8bit_val);
795 	if (status != PSVC_SUCCESS)
796 		return (status);
797 
798 	_8bit_val &= 0xef;  /* clear bit 4 */
799 	_8bit_val |= 0xf4;  /* set bits 3, 5, 6, 7 */
800 
801 	status = psvc_set_attr(hdlp, id,
802 		PSVC_GPIO_VALUE_ATTR, &_8bit_val);
803 	if (status != PSVC_SUCCESS)
804 		return (status);
805 
806 	return (status);
807 }
808 
809 static int32_t
810 check_cpu_temp_fault(psvc_opaque_t hdlp, char *cpu, int32_t cpu_count)
811 {
812 	char *sensorid;
813 	int32_t sensor_count;
814 	int32_t status = PSVC_SUCCESS;
815 	int32_t i;
816 	char fault[32];
817 	int retry;
818 	int8_t temp_oor;
819 
820 	psvc_get_attr(hdlp, cpu, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
821 		PSVC_DEV_TEMP_SENSOR);
822 	for (i = 0; i < sensor_count; ++i) {
823 		status = psvc_get_attr(hdlp, cpu, PSVC_ASSOC_ID_ATTR,
824 			&sensorid, PSVC_DEV_TEMP_SENSOR, i);
825 		if (status == PSVC_FAILURE)
826 			return (status);
827 
828 		retry = 0;
829 		do {
830 			if (retry)
831 				(void) sleep(retry_sleep_temp_shutdown);
832 			status = psvc_get_attr(hdlp, sensorid,
833 			    PSVC_FAULTID_ATTR, fault);
834 			if (status == PSVC_FAILURE)
835 				return (status);
836 			temp_oor = 0;
837 			if ((strcmp(fault, PSVC_TEMP_HI_SHUT) == 0) ||
838 			    (strcmp(fault, PSVC_TEMP_LO_SHUT) == 0)) {
839 				temp_oor = 1;
840 			}
841 			retry++;
842 		} while ((retry < n_retry_temp_shutdown) && temp_oor);
843 
844 		if (temp_oor) {
845 			system(shutdown_string);
846 		}
847 	}
848 
849 	return (status);
850 }
851 
852 int32_t
853 psvc_shutdown_policy_0(psvc_opaque_t hdlp, char *id)
854 {
855 	int32_t cpu_count;
856 	char *cpuid;
857 	int32_t i;
858 	boolean_t present;
859 	int32_t status = PSVC_SUCCESS;
860 
861 	psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count,
862 		PSVC_CPU);
863 	for (i = 0; i < cpu_count; ++i) {
864 
865 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &cpuid,
866 			PSVC_CPU, i);
867 		if (status == PSVC_FAILURE)
868 			return (status);
869 
870 		status = psvc_get_attr(hdlp, cpuid,
871 			PSVC_PRESENCE_ATTR, &present);
872 		if (status == PSVC_FAILURE && present == PSVC_PRESENT)
873 			return (status);
874 		if (present == PSVC_PRESENT) {
875 			status = check_cpu_temp_fault(hdlp, cpuid, cpu_count);
876 			if (status == PSVC_FAILURE && errno != ENODEV)
877 				return (status);
878 		}
879 	}
880 
881 	return (PSVC_SUCCESS);
882 }
883