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