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 2004 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  * This file contains routines to support the Platform Services Plugin
31  * These routines implement the platform independent environment monitoring
32  * and control policies that may be invoked by a daemon thread within
33  * the plugin
34  */
35 
36 #include <syslog.h>
37 #include <unistd.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <libintl.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <strings.h>
44 #include <libintl.h>
45 #include <sys/types.h>
46 #include <picl.h>
47 #include <picltree.h>
48 #include <sys/types.h>
49 #include <string.h>
50 #include <psvc_objects.h>
51 
52 #define	LOWTEMP_CRITICAL_MSG		\
53 	gettext("CRITICAL : LOW TEMPERATURE DETECTED %d, %s")
54 #define	LOWTEMP_WARNING_MSG		\
55 	gettext("WARNING : LOW TEMPERATURE DETECTED %d, %s")
56 #define	HIGHTEMP_CRITICAL_MSG		\
57 	gettext("CRITICAL : HIGH TEMPERATURE DETECTED %d, %s")
58 #define	HIGHTEMP_WARNING_MSG		\
59 	gettext("WARNING : HIGH TEMPERATURE DETECTED %d, %s")
60 #define	DEVICE_INSERTED_MSG	gettext("Device %s inserted")
61 #define	DEVICE_REMOVED_MSG	gettext("Device %s removed")
62 #define	DEVICE_FAILURE_MSG		\
63 	gettext("CRITICAL: Device %s failure detected by sensor %s\n")
64 #define	DEVICE_OK_MSG	gettext("Device %s OK")
65 #define	SECONDARY_FAN_FAIL_MSG	gettext("Secondary fan failure, device %s")
66 #define	KEYSWITCH_POS_READ_FAILED_MSG	\
67 	gettext("Keyswitch position could not be determined")
68 #define	KEYSWITCH_POS_CHANGED_MSG gettext("Keyswitch position changed to %s")
69 #define	GET_PRESENCE_FAILED_MSG		\
70 	gettext("Failed to get presence attribute, id = %s, errno = %d\n")
71 #define	GET_SENSOR_FAILED_MSG		\
72 	gettext("Failed to get sensor value, id = %s, errno = %d\n")
73 #define	PS_OVER_CURRENT_MSG		\
74 	gettext("WARNING: Power Supply overcurrent detected for %s\n")
75 #define	SET_LED_FAILED_MSG		\
76 	gettext("Failed to set LED state, id = %s, errno = %d\n")
77 #define	SET_FANSPEED_FAILED_MSG		\
78 	gettext("Failed to set fan speed, id = %s, errno = %d\n")
79 #define	FAN_MISSING_MSG			\
80 	gettext("WARNING: Fan missing, id = %s\n")
81 #define	TEMP_SENSOR_FAULT		\
82 	gettext("WARNING: Temperature Sensor %s returning faulty temp\n")
83 #define	TEMP_OFFSET	17
84 
85 static char *shutdown_string = "shutdown -y -g 60 -i 5 \"OVERTEMP condition\"";
86 
87 static int cpus_online = 0;
88 
89 typedef struct seg_desc {
90 	int32_t segdesc;
91 	int16_t segoffset;
92 	int16_t seglength;
93 } seg_desc_t;
94 
95 static int32_t threshold_names[] = {
96 	PSVC_HW_LO_SHUT_ATTR,
97 	PSVC_LO_SHUT_ATTR,
98 	PSVC_LO_WARN_ATTR,
99 	PSVC_NOT_USED,			/* LOW MODE which is not used */
100 	PSVC_OPTIMAL_TEMP_ATTR,
101 	PSVC_HI_WARN_ATTR,
102 	PSVC_HI_SHUT_ATTR,
103 	PSVC_HW_HI_SHUT_ATTR
104 };
105 
106 int32_t
107 psvc_update_thresholds_0(psvc_opaque_t hdlp, char *id)
108 {
109 	int32_t status = PSVC_SUCCESS;
110 	fru_info_t fru_data;
111 	char *fru, seg_name[2];
112 	int8_t seg_count, temp_array[8];
113 	int32_t match_count, i, j, seg_desc_start = 0x1806, temp_address;
114 	int32_t seg_found, temp;
115 	boolean_t present;
116 	seg_desc_t segment;
117 
118 	status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &present);
119 	if ((status != PSVC_SUCCESS) || (present != PSVC_PRESENT))
120 		return (status);
121 
122 	status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &match_count,
123 	    PSVC_FRU);
124 	if (status == PSVC_FAILURE)
125 		return (status);
126 
127 	for (i = 0; i < match_count; i++) {
128 		seg_found = 0;
129 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
130 		    &fru, PSVC_FRU, i);
131 		if (status != PSVC_SUCCESS)
132 			return (status);
133 
134 		fru_data.buf_start = 0x1805;
135 		fru_data.buf = (char *)&seg_count;
136 		fru_data.read_size = 1;
137 
138 		status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
139 		    &fru_data);
140 		if (status != PSVC_SUCCESS) {
141 			return (status);
142 		}
143 		for (j = 0; (j < seg_count) && (!seg_found); j++) {
144 			fru_data.buf_start = seg_desc_start;
145 			fru_data.buf = seg_name;
146 			fru_data.read_size = 2;
147 
148 			status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
149 			    &fru_data);
150 
151 			seg_desc_start = seg_desc_start + 2;
152 			fru_data.buf_start = seg_desc_start;
153 			fru_data.buf = (char *)&segment;
154 			fru_data.read_size = sizeof (seg_desc_t);
155 
156 			status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
157 			    &fru_data);
158 			if (status != PSVC_SUCCESS) {
159 				syslog(LOG_ERR,
160 				    "Failed psvc_get_attr for FRU info\n");
161 				return (status);
162 			}
163 			seg_desc_start = seg_desc_start + sizeof (seg_desc_t);
164 			if (memcmp(seg_name, "SC", 2) == 0)
165 				seg_found = 1;
166 		}
167 		if (seg_found) {
168 			temp_address = segment.segoffset + TEMP_OFFSET;
169 			fru_data.buf_start = temp_address;
170 			fru_data.buf = (char *)&temp_array;
171 			fru_data.read_size = sizeof (temp_array);
172 			status = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
173 			    &fru_data);
174 			if (status != PSVC_SUCCESS) {
175 				syslog(LOG_ERR,
176 				    "Failed psvc_get_attr for FRU info\n");
177 				return (status);
178 			} else {
179 				for (j = 0; j < sizeof (temp_array); j++) {
180 					if (threshold_names[j] == PSVC_NOT_USED)
181 						continue;
182 					temp = temp_array[j];
183 					status = psvc_set_attr(hdlp, id,
184 					    threshold_names[j], &temp);
185 					if (status != PSVC_SUCCESS) {
186 						return (status);
187 					}
188 				}
189 			}
190 		} else {
191 			syslog(LOG_ERR, "No FRU Information for %s"
192 			    " using default temperatures\n", id);
193 		}
194 	}
195 	return (status);
196 }
197 
198 #define	MAX_TEMP_SENSORS	256
199 
200 static int32_t
201 check_temp(psvc_opaque_t hdlp, char *id, int32_t silent)
202 {
203 	int32_t		lo_warn, hi_warn, lo_shut, hi_shut;
204 	uint64_t	features;
205 	int32_t		temp;
206 	char		previous_state[32];
207 	char		led_state[32];
208 	char		state[32];
209 	char		fault[32];
210 	char		label[32];
211 	boolean_t	pr;
212 	int32_t		status = PSVC_SUCCESS;
213 	int8_t		fail = 0;
214 	static int8_t	threshold_low_shut[MAX_TEMP_SENSORS] = {0};
215 	static int8_t	threshold_high_shut[MAX_TEMP_SENSORS] = {0};
216 	static int8_t	threshold_low_warn[MAX_TEMP_SENSORS] = {0};
217 	static int8_t	threshold_high_warn[MAX_TEMP_SENSORS] = {0};
218 	int32_t		instance;
219 
220 	status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
221 	if (status != PSVC_SUCCESS)
222 		return (status);
223 
224 	status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &pr);
225 	if ((status != PSVC_SUCCESS) || (pr != PSVC_PRESENT)) {
226 		return (status);
227 	}
228 
229 	status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
230 	if (status == PSVC_FAILURE)
231 		return (status);
232 
233 	if ((strcmp(state, PSVC_HOTPLUGGED) == 0)) {
234 		return (PSVC_SUCCESS);
235 	}
236 
237 	status = psvc_get_attr(hdlp, id, PSVC_FEATURES_ATTR, &features);
238 	if (status != PSVC_SUCCESS)
239 		return (status);
240 
241 	status = psvc_get_attr(hdlp, id, PSVC_LO_WARN_ATTR, &lo_warn);
242 	if (status != PSVC_SUCCESS)
243 		return (status);
244 
245 	status = psvc_get_attr(hdlp, id, PSVC_LO_SHUT_ATTR, &lo_shut);
246 	if (status != PSVC_SUCCESS)
247 		return (status);
248 
249 	status = psvc_get_attr(hdlp, id, PSVC_HI_WARN_ATTR, &hi_warn);
250 	if (status != PSVC_SUCCESS)
251 		return (status);
252 
253 	status = psvc_get_attr(hdlp, id, PSVC_HI_SHUT_ATTR, &hi_shut);
254 	if (status != PSVC_SUCCESS)
255 		return (status);
256 
257 	status = psvc_get_attr(hdlp, id, PSVC_SENSOR_VALUE_ATTR, &temp);
258 	if (status != PSVC_SUCCESS) {
259 		return (status);
260 	}
261 
262 	/*
263 	 * The following code is to check to see if the temp sensor is
264 	 * returning a faulty reading due to it either being bad or the
265 	 * CPU being powered off for some reason. Is so we will alert the user
266 	 * and just label the sensor bad but not the WHOLE CPU module.
267 	 */
268 	if ((temp == 127) && (strcmp(state, PSVC_ERROR) != 0)) {
269 		status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_ERROR);
270 		if (status != PSVC_SUCCESS)
271 			return (status);
272 		status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
273 		    PSVC_GEN_FAULT);
274 		if (status != PSVC_SUCCESS)
275 			return (status);
276 		syslog(LOG_ERR, TEMP_SENSOR_FAULT, id);
277 		return (status);
278 	}
279 
280 	status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
281 	if (status != PSVC_SUCCESS)
282 		return (status);
283 
284 	/*
285 	 * if any of the four temperature states (lo_shut, lo_warn,
286 	 * hi_shut, hi_warn) is detected we will not take an action
287 	 * until PSVC_THRESHOLD_COUNTER (i.e. 2) similar back-to-back readings
288 	 * take place.
289 	 */
290 	if ((features & PSVC_LOW_SHUT) && temp < lo_shut) {
291 		/*
292 		 * once we are in one state, clear all the
293 		 * counters for the other three states since
294 		 * back-to-back readings of these other three
295 		 * states could not happen anymore.
296 		 */
297 		threshold_low_warn[instance] = 0;
298 		threshold_high_shut[instance] = 0;
299 		threshold_high_warn[instance] = 0;
300 		threshold_low_shut[instance]++;
301 		if (threshold_low_shut[instance] == PSVC_THRESHOLD_COUNTER) {
302 			threshold_low_shut[instance] = 0;
303 			fail = 1;
304 			strcpy(state, PSVC_ERROR);
305 			strcpy(fault, PSVC_TEMP_LO_SHUT);
306 			strcpy(led_state, PSVC_LED_ON);
307 			if (silent == 0)
308 				syslog(LOG_ERR, LOWTEMP_CRITICAL_MSG,
309 				    temp, label);
310 		} else { /* Threshold for showing error not reached */
311 			return (PSVC_SUCCESS);
312 		}
313 	} else if ((features & PSVC_LOW_WARN) && temp < lo_warn) {
314 		threshold_low_shut[instance] = 0;
315 		threshold_high_shut[instance] = 0;
316 		threshold_high_warn[instance] = 0;
317 		threshold_low_warn[instance]++;
318 		if (threshold_low_warn[instance] == PSVC_THRESHOLD_COUNTER) {
319 			threshold_low_warn[instance] = 0;
320 			fail = 1;
321 			strcpy(state, PSVC_ERROR);
322 			strcpy(fault, PSVC_TEMP_LO_WARN);
323 			strcpy(led_state, PSVC_LED_ON);
324 			if (silent == 0)
325 				syslog(LOG_ERR, LOWTEMP_WARNING_MSG,
326 				    temp, label);
327 		} else { /* Threshold for showing error not reached */
328 			return (PSVC_SUCCESS);
329 		}
330 	} else if ((features & PSVC_HIGH_SHUT) && temp > hi_shut) {
331 		threshold_low_warn[instance] = 0;
332 		threshold_low_shut[instance] = 0;
333 		threshold_high_warn[instance] = 0;
334 		threshold_high_shut[instance]++;
335 		if (threshold_high_shut[instance] == PSVC_THRESHOLD_COUNTER) {
336 			threshold_high_shut[instance] = 0;
337 			fail = 1;
338 			strcpy(state, PSVC_ERROR);
339 			strcpy(fault, PSVC_TEMP_HI_SHUT);
340 			strcpy(led_state, PSVC_LED_ON);
341 			if (silent == 0)
342 				syslog(LOG_ERR, HIGHTEMP_CRITICAL_MSG,
343 				    temp, label);
344 		} else { /* Threshold for showing error not reached */
345 			return (PSVC_SUCCESS);
346 		}
347 	} else if ((features & PSVC_HIGH_WARN) && temp > hi_warn) {
348 		threshold_low_warn[instance] = 0;
349 		threshold_low_shut[instance] = 0;
350 		threshold_high_shut[instance] = 0;
351 		threshold_high_warn[instance]++;
352 		if (threshold_high_warn[instance] == PSVC_THRESHOLD_COUNTER) {
353 			threshold_high_warn[instance] = 0;
354 			fail = 1;
355 			strcpy(state, PSVC_ERROR);
356 			strcpy(fault, PSVC_TEMP_HI_WARN);
357 			strcpy(led_state, PSVC_LED_ON);
358 			if (silent == 0)
359 				syslog(LOG_ERR, HIGHTEMP_WARNING_MSG,
360 				    temp, label);
361 		} else { /* Threshold for showing error not reached */
362 			return (PSVC_SUCCESS);
363 		}
364 	}
365 
366 	/*
367 	 * If we reached this point then that means that we are either
368 	 * okay, or we have showed error PSVC_THRESHOLD_COUNTER times.
369 	 */
370 	if (fail != 1) {
371 		/* within limits */
372 		strcpy(state, PSVC_OK);
373 		strcpy(fault, PSVC_NO_FAULT);
374 		strcpy(led_state, PSVC_LED_OFF);
375 	}
376 
377 	status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
378 	if (status != PSVC_SUCCESS)
379 		return (status);
380 	status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
381 	if (status != PSVC_SUCCESS)
382 		return (status);
383 	status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR,
384 		previous_state);
385 	if (status != PSVC_SUCCESS)
386 		return (status);
387 
388 	if (strcmp(previous_state, state) != 0) {
389 		char *led_id;
390 		int32_t led_count;
391 		int32_t i;
392 
393 		/* change state of fault LEDs */
394 		psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &led_count,
395 			PSVC_TS_OVERTEMP_LED);
396 		for (i = 0; i < led_count; ++i) {
397 			status = psvc_get_attr(hdlp, id,
398 				PSVC_ASSOC_ID_ATTR, &led_id,
399 				PSVC_TS_OVERTEMP_LED, i);
400 			if (status == PSVC_FAILURE)
401 				return (status);
402 			status = psvc_set_attr(hdlp, led_id,
403 				PSVC_LED_STATE_ATTR, led_state);
404 			if (status == PSVC_FAILURE)
405 				return (status);
406 		}
407 	}
408 
409 	return (PSVC_SUCCESS);
410 }
411 
412 int32_t
413 psvc_check_temperature_policy_0(psvc_opaque_t hdlp, char *id)
414 {
415 	return (check_temp(hdlp, id, 0));
416 }
417 
418 int32_t
419 psvc_check_temperature_silent_policy_0(psvc_opaque_t hdlp, char *id)
420 {
421 	return (check_temp(hdlp, id, 1));
422 }
423 
424 int32_t
425 psvc_fan_enable_disable_policy_0(psvc_opaque_t hdlp, char *id)
426 {
427 	char state[32], previous_state[32];
428 	char *backup_fan;
429 	int32_t status = PSVC_SUCCESS;
430 	uint64_t features;
431 	char label[32];
432 	boolean_t presence;
433 	boolean_t enable;
434 
435 	status = psvc_get_attr(hdlp, id, PSVC_FEATURES_ATTR, &features);
436 	if (status != PSVC_SUCCESS)
437 		return (status);
438 
439 	status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence);
440 	if (status != PSVC_SUCCESS)
441 		return (status);
442 
443 	if (presence == PSVC_ABSENT) {
444 		status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
445 		if (status != PSVC_SUCCESS)
446 			return (status);
447 
448 		status = psvc_get_attr(hdlp, id, PSVC_ENABLE_ATTR, &enable);
449 		if (status != PSVC_SUCCESS)
450 			return (status);
451 
452 		if (features & PSVC_DEV_PRIMARY) {
453 			status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
454 				&backup_fan, PSVC_ALTERNATE, 0);
455 			if (status != PSVC_SUCCESS)
456 				return (status);
457 
458 			enable = PSVC_DISABLED;
459 			status = psvc_set_attr(hdlp, id, PSVC_ENABLE_ATTR,
460 				&enable);
461 			if (status != PSVC_SUCCESS)
462 				return (status);
463 
464 			enable = PSVC_ENABLED;
465 			status = psvc_set_attr(hdlp, backup_fan,
466 				PSVC_ENABLE_ATTR, &enable);
467 			if (status != PSVC_SUCCESS)
468 				return (status);
469 		} else {
470 			enable = PSVC_DISABLED;
471 			status = psvc_set_attr(hdlp, id, PSVC_ENABLE_ATTR,
472 				&enable);
473 			if (status != PSVC_SUCCESS)
474 				return (status);
475 		}
476 		return (PSVC_SUCCESS);
477 	}
478 
479 	/* device was present */
480 	status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
481 	if (status != PSVC_SUCCESS)
482 		return (status);
483 
484 	status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, previous_state);
485 	if (status != PSVC_SUCCESS)
486 		return (status);
487 
488 	if (features & PSVC_DEV_PRIMARY) {
489 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
490 			&backup_fan, PSVC_ALTERNATE, 0);
491 		if (status != PSVC_SUCCESS)
492 			return (status);
493 
494 		if (strcmp(state, PSVC_OK) == 0) {
495 			enable = PSVC_ENABLED;
496 			status = psvc_set_attr(hdlp, id, PSVC_ENABLE_ATTR,
497 				&enable);
498 			if (status != PSVC_SUCCESS)
499 				return (status);
500 
501 			enable = PSVC_DISABLED;
502 			status = psvc_set_attr(hdlp, backup_fan,
503 				PSVC_ENABLE_ATTR, &enable);
504 			if (status != PSVC_SUCCESS)
505 				return (status);
506 		}
507 		if ((strcmp(state, PSVC_ERROR) == 0) &&
508 			(strcmp(previous_state, PSVC_ERROR) != 0)) {
509 			enable = PSVC_DISABLED;
510 			status = psvc_set_attr(hdlp, id, PSVC_ENABLE_ATTR,
511 				&enable);
512 			if (status != PSVC_SUCCESS)
513 				return (status);
514 
515 			enable = PSVC_ENABLED;
516 			status = psvc_set_attr(hdlp, backup_fan,
517 				PSVC_ENABLE_ATTR, &enable);
518 			if (status != PSVC_SUCCESS)
519 				return (status);
520 		}
521 	} else {
522 		if ((strcmp(state, PSVC_ERROR) == 0) &&
523 			(strcmp(previous_state, PSVC_ERROR) != 0)) {
524 			status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR,
525 				label);
526 			if (status != PSVC_SUCCESS)
527 				return (status);
528 			syslog(LOG_ERR, SECONDARY_FAN_FAIL_MSG, label);
529 		}
530 	}
531 	return (status);
532 }
533 
534 /*
535  * psvc_switch_fan_onoff_policy_0
536  * Turn a fan on if it is enabled, turn it off if it is disabled.
537  */
538 int32_t
539 psvc_switch_fan_onoff_policy_0(psvc_opaque_t hdlp, char *id)
540 {
541 	boolean_t enable;
542 	char *switchid;
543 	char state[32];
544 	int32_t status = PSVC_SUCCESS;
545 
546 	status = psvc_get_attr(hdlp, id, PSVC_ENABLE_ATTR, &enable);
547 	if (status != PSVC_SUCCESS)
548 		return (status);
549 
550 	status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &switchid,
551 		PSVC_FAN_ONOFF_SENSOR, 0);
552 	if (status != PSVC_SUCCESS)
553 		return (status);
554 
555 	if (enable == PSVC_DISABLED) {
556 		strcpy(state, PSVC_SWITCH_OFF);
557 	} else {
558 		strcpy(state, PSVC_SWITCH_ON);
559 	}
560 
561 	status = psvc_set_attr(hdlp, switchid, PSVC_SWITCH_STATE_ATTR, state);
562 	return (status);
563 }
564 
565 static int32_t
566 check_cpu_temp_fault(psvc_opaque_t hdlp, char *cpu, int32_t cpu_count)
567 {
568 	char *sensorid;
569 	int32_t sensor_count;
570 	int32_t status = PSVC_SUCCESS;
571 	int32_t i;
572 	uint64_t features;
573 	char fault[32];
574 
575 	status = psvc_get_attr(hdlp, cpu, PSVC_FEATURES_ATTR, &features);
576 	if (status == PSVC_FAILURE)
577 		return (status);
578 
579 	psvc_get_attr(hdlp, cpu, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
580 		PSVC_DEV_TEMP_SENSOR);
581 	for (i = 0; i < sensor_count; ++i) {
582 		status = psvc_get_attr(hdlp, cpu, PSVC_ASSOC_ID_ATTR,
583 			&sensorid, PSVC_DEV_TEMP_SENSOR, i);
584 		if (status == PSVC_FAILURE)
585 			return (status);
586 
587 		status = psvc_get_attr(hdlp, sensorid, PSVC_FAULTID_ATTR,
588 			fault);
589 		if (status == PSVC_FAILURE)
590 			return (status);
591 
592 		if ((strcmp(fault, PSVC_TEMP_HI_SHUT) == 0) ||
593 			(strcmp(fault, PSVC_TEMP_LO_SHUT) == 0)) {
594 			if (cpu_count == 1 || cpus_online == 1 ||
595 			    !(features & PSVC_DEV_HOTPLUG)) {
596 				system(shutdown_string);
597 			} else {
598 				/* FIX offline cpu */
599 				--cpus_online;
600 			}
601 		}
602 	}
603 
604 	return (status);
605 }
606 
607 int32_t
608 psvc_shutdown_policy_0(psvc_opaque_t hdlp, char *id)
609 {
610 	int32_t cpu_count;
611 	char *cpuid;
612 	int32_t i;
613 	boolean_t present;
614 	int32_t status = PSVC_SUCCESS;
615 
616 	if (cpus_online == 0) {
617 		/* obviously, zero isn't correct, count present cpu's */
618 		psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count,
619 			PSVC_CPU);
620 		for (i = 0; i < cpu_count; ++i) {
621 			status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
622 				&cpuid, PSVC_CPU, i);
623 			if (status == PSVC_FAILURE)
624 				return (status);
625 
626 			status = psvc_get_attr(hdlp, cpuid,
627 				PSVC_PRESENCE_ATTR, &present);
628 			if (status == PSVC_FAILURE && present == PSVC_PRESENT)
629 				return (status);
630 			if (present == PSVC_PRESENT)
631 				++cpus_online;
632 		}
633 	}
634 	psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count,
635 		PSVC_CPU);
636 	for (i = 0; i < cpu_count; ++i) {
637 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &cpuid,
638 			PSVC_CPU, i);
639 		if (status == PSVC_FAILURE)
640 			return (status);
641 		status = check_cpu_temp_fault(hdlp, cpuid, cpu_count);
642 		if (status == PSVC_FAILURE && errno != ENODEV)
643 			return (status);
644 	}
645 
646 	return (PSVC_SUCCESS);
647 }
648 
649 /*
650  * psvc_keyswitch_position_policy_0
651  * Checks the state of the keyswitch sensors.
652  * If a keyswitch position sensor's state is on, the position
653  * of the key is written to syslog.  If none of the sensors
654  * are on (keyswitch is not at one of the detents), a message is sent
655  * to syslog stating that the position is unknown.
656  */
657 int32_t
658 psvc_keyswitch_position_policy_0(psvc_opaque_t hdlp, char *id)
659 {
660 	char position[32];
661 	int32_t status = PSVC_SUCCESS;
662 	static int error_reported = 0;
663 	static char local_previous_position[32];
664 	static int32_t first_time = 1;
665 	int8_t retry;
666 
667 	if (first_time) {
668 		first_time = 0;
669 		status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR,
670 		    local_previous_position);
671 		if (status != PSVC_SUCCESS)
672 			return (status);
673 	}
674 
675 	retry = 0;
676 	do {
677 		if (retry)
678 			sleep(1);
679 
680 		status = psvc_get_attr(hdlp, id, PSVC_SWITCH_STATE_ATTR,
681 		    position);
682 		if (status != PSVC_SUCCESS)
683 			return (status);
684 
685 		if (strcmp(position, PSVC_ERROR) == 0) {
686 			if ((errno == EINVAL) && (!(error_reported))) {
687 				syslog(LOG_ERR,
688 				    KEYSWITCH_POS_READ_FAILED_MSG);
689 				error_reported = 1;
690 				return (PSVC_SUCCESS);
691 			}
692 		}
693 		retry++;
694 	} while ((retry < PSVC_NUM_OF_RETRIES) &&
695 	    (strcmp(position, local_previous_position) != 0));
696 
697 	status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, position);
698 	if (status != PSVC_SUCCESS)
699 		return (status);
700 
701 	if (strcmp(position, local_previous_position) != 0) {
702 		error_reported = 0;
703 		strcpy(local_previous_position, position);
704 		syslog(LOG_ERR, KEYSWITCH_POS_CHANGED_MSG, position);
705 	}
706 
707 	return (status);
708 }
709 
710 int32_t
711 psvc_hotplug_notifier_policy_0(psvc_opaque_t hdlp, char *id)
712 {
713 	boolean_t presence, previous_presence;
714 	int32_t status = PSVC_SUCCESS;
715 	char label[32];
716 	int8_t retry;
717 
718 	status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR,
719 		&previous_presence);
720 	if (status != PSVC_SUCCESS)
721 		return (status);
722 	retry = 0;
723 	do {
724 		if (retry)
725 			sleep(1);
726 		status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence);
727 		if (status != PSVC_SUCCESS)
728 			return (status);
729 		retry++;
730 	} while ((retry < PSVC_NUM_OF_RETRIES) &&
731 	    (presence != previous_presence));
732 
733 
734 	if (presence != previous_presence) {
735 		char parent_path[256];
736 		picl_nodehdl_t child_node;
737 
738 		status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
739 		if (status != PSVC_SUCCESS)
740 			return (status);
741 
742 		/* return parent path and node for an object */
743 		psvcplugin_lookup(id, parent_path, &child_node);
744 
745 		if (presence == PSVC_PRESENT) {
746 			char state[32], fault[32];
747 			picl_nodehdl_t parent_node;
748 
749 			syslog(LOG_ERR, DEVICE_INSERTED_MSG, label);
750 			strcpy(state, PSVC_OK);
751 			status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
752 				state);
753 			if (status != PSVC_SUCCESS)
754 				return (status);
755 			strcpy(fault, PSVC_NO_FAULT);
756 			status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
757 				fault);
758 			if (status != PSVC_SUCCESS) {
759 				return (status);
760 			}
761 
762 			status = ptree_get_node_by_path(parent_path,
763 				&parent_node);
764 			if (status != 0)
765 				return (PSVC_FAILURE);
766 			status = ptree_add_node(parent_node, child_node);
767 			if (status != 0)
768 				return (PSVC_FAILURE);
769 		} else {
770 			syslog(LOG_ERR, DEVICE_REMOVED_MSG, label);
771 
772 			ptree_delete_node(child_node);
773 
774 		}
775 	}
776 
777 	status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence);
778 	if (status != PSVC_SUCCESS)
779 		return (status);
780 
781 	return (status);
782 }
783 
784 int32_t
785 psvc_fan_hotplug_policy_0(psvc_opaque_t hdlp, char *id)
786 {
787 	boolean_t presence, previous_presence;
788 	int32_t status = PSVC_SUCCESS;
789 	char label[32];
790 	int8_t retry;
791 
792 	status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR,
793 		&previous_presence);
794 	if (status != PSVC_SUCCESS)
795 		return (status);
796 
797 	retry = 0;
798 	do {
799 		if (retry)
800 			sleep(1);
801 
802 		status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence);
803 		if (status != PSVC_SUCCESS)
804 			return (status);
805 		retry++;
806 	} while ((retry < PSVC_NUM_OF_RETRIES) &&
807 	    (presence != previous_presence));
808 
809 
810 	if (presence != previous_presence) {
811 		char parent_path[256];
812 		picl_nodehdl_t child_node;
813 
814 		status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
815 		if (status != PSVC_SUCCESS)
816 			return (status);
817 
818 		/* return parent path and node for an object */
819 		psvcplugin_lookup(id, parent_path, &child_node);
820 
821 		if (presence == PSVC_PRESENT) {
822 			char state[32], fault[32];
823 			char *slot_id;
824 			char *led_id;
825 			int32_t i, led_count;
826 			char led_state[32];
827 			picl_nodehdl_t parent_node;
828 
829 			syslog(LOG_ERR, DEVICE_INSERTED_MSG, label);
830 
831 			strcpy(state, PSVC_OK);
832 			status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
833 				state);
834 			if (status != PSVC_SUCCESS)
835 				return (status);
836 			strcpy(fault, PSVC_NO_FAULT);
837 			status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
838 				fault);
839 			if (status != PSVC_SUCCESS)
840 				return (status);
841 
842 			/* turn off fault LEDs */
843 			psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR,
844 				&led_count, PSVC_DEV_FAULT_LED);
845 			strcpy(led_state, PSVC_LED_OFF);
846 			for (i = 0; i < led_count; ++i) {
847 				status = psvc_get_attr(hdlp, id,
848 					PSVC_ASSOC_ID_ATTR, &led_id,
849 					PSVC_DEV_FAULT_LED, i);
850 				if (status == PSVC_FAILURE)
851 					return (status);
852 				status = psvc_set_attr(hdlp, led_id,
853 					PSVC_LED_STATE_ATTR, led_state);
854 				if (status == PSVC_FAILURE)
855 					return (status);
856 			}
857 
858 			/* turn off OK to remove LEDs */
859 			status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
860 				&slot_id, PSVC_PARENT, 0);
861 			if (status != PSVC_SUCCESS)
862 				return (status);
863 
864 			psvc_get_attr(hdlp, slot_id, PSVC_ASSOC_MATCHES_ATTR,
865 				&led_count, PSVC_SLOT_REMOVE_LED);
866 			strcpy(led_state, PSVC_LED_OFF);
867 			for (i = 0; i < led_count; ++i) {
868 				status = psvc_get_attr(hdlp, slot_id,
869 					PSVC_ASSOC_ID_ATTR, &led_id,
870 					PSVC_SLOT_REMOVE_LED, i);
871 				if (status == PSVC_FAILURE)
872 					return (status);
873 
874 				status = psvc_set_attr(hdlp, led_id,
875 					PSVC_LED_STATE_ATTR, led_state);
876 				if (status == PSVC_FAILURE)
877 					return (status);
878 			}
879 
880 			ptree_get_node_by_path(parent_path, &parent_node);
881 			ptree_add_node(parent_node, child_node);
882 		} else {
883 			syslog(LOG_ERR, DEVICE_REMOVED_MSG, label);
884 			ptree_delete_node(child_node);
885 		}
886 	}
887 
888 	status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence);
889 	if (status != PSVC_SUCCESS)
890 		return (status);
891 
892 	return (status);
893 }
894 
895 int32_t
896 psvc_init_led_policy_0(psvc_opaque_t hdlp, char *id)
897 {
898 	int32_t status;
899 
900 	status = psvc_set_attr(hdlp, id, PSVC_LED_STATE_ATTR, PSVC_LED_OFF);
901 	return (status);
902 }
903 
904 int32_t
905 psvc_init_state_policy_0(psvc_opaque_t hdlp, char *id)
906 {
907 	int32_t status;
908 
909 	status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_OK);
910 	status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, PSVC_NO_FAULT);
911 	return (status);
912 }
913 
914 int32_t
915 psvc_ps_overcurrent_check_policy_0(psvc_opaque_t hdlp, char *power_supply_id)
916 {
917 	int32_t status = PSVC_SUCCESS;
918 	boolean_t present;
919 	char *sensor_id;
920 	int32_t sensor_count;
921 	int32_t i;
922 	int32_t amps, hi_warn;
923 
924 	status = psvc_get_attr(hdlp, power_supply_id, PSVC_PRESENCE_ATTR,
925 		&present);
926 	if (status == PSVC_FAILURE) {
927 		syslog(LOG_ERR, GET_PRESENCE_FAILED_MSG, power_supply_id,
928 			errno);
929 		return (status);
930 	}
931 
932 	if (present == PSVC_ABSENT) {
933 		errno = ENODEV;
934 		return (PSVC_FAILURE);
935 	}
936 
937 	psvc_get_attr(hdlp, power_supply_id, PSVC_ASSOC_MATCHES_ATTR,
938 		&sensor_count, PSVC_PS_I_SENSOR);
939 	for (i = 0; i < sensor_count; ++i) {
940 		status = psvc_get_attr(hdlp, power_supply_id,
941 			PSVC_ASSOC_ID_ATTR, &sensor_id, PSVC_PS_I_SENSOR, i);
942 		if (status != PSVC_SUCCESS)
943 			return (status);
944 
945 		status = psvc_get_attr(hdlp, sensor_id, PSVC_HI_WARN_ATTR,
946 			&hi_warn);
947 		if (status != PSVC_SUCCESS)
948 			return (status);
949 
950 		status = psvc_get_attr(hdlp, sensor_id,
951 			PSVC_SENSOR_VALUE_ATTR, &amps);
952 		if (status != PSVC_SUCCESS) {
953 			syslog(LOG_ERR, GET_SENSOR_FAILED_MSG, sensor_id,
954 				errno);
955 			return (status);
956 		}
957 
958 		if (amps >= hi_warn) {
959 			char label[32];
960 
961 			status = psvc_get_attr(hdlp, power_supply_id,
962 				PSVC_LABEL_ATTR, &label);
963 			if (status != PSVC_SUCCESS)
964 				return (status);
965 
966 			syslog(LOG_ERR, PS_OVER_CURRENT_MSG, label);
967 		}
968 	}
969 
970 	return (PSVC_SUCCESS);
971 
972 }
973 
974 int32_t
975 psvc_device_fail_notifier_policy_0(psvc_opaque_t hdlp, char *id)
976 {
977 	int32_t led_count, sensor_count;
978 	char *led_id, *sensor_id;
979 	int i;
980 	char state[32], fault[32], previous_state[32];
981 	char led_state[32];
982 	int32_t status = PSVC_SUCCESS;
983 	boolean_t present;
984 
985 	status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &present);
986 	if (status == PSVC_FAILURE)
987 		return (status);
988 
989 	if (present == PSVC_ABSENT) {
990 		errno = ENODEV;
991 		return (PSVC_FAILURE);
992 	}
993 
994 	psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
995 		PSVC_DEV_FAULT_SENSOR);
996 	for (i = 0; i < sensor_count; ++i) {
997 		status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
998 			&sensor_id, PSVC_DEV_FAULT_SENSOR, i);
999 		if (status != PSVC_SUCCESS)
1000 			return (status);
1001 
1002 		status = psvc_get_attr(hdlp, sensor_id,
1003 			PSVC_SWITCH_STATE_ATTR, state);
1004 		if (status != PSVC_SUCCESS)
1005 			return (status);
1006 
1007 		if (strcmp(state, PSVC_SWITCH_ON) == 0) {
1008 			strcpy(state, PSVC_ERROR);
1009 			strcpy(fault, PSVC_GEN_FAULT);
1010 		} else {
1011 			strcpy(state, PSVC_OK);
1012 			strcpy(fault, PSVC_NO_FAULT);
1013 		}
1014 
1015 		status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
1016 		if (status != PSVC_SUCCESS)
1017 			return (status);
1018 		status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
1019 		if (status != PSVC_SUCCESS)
1020 			return (status);
1021 		status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR,
1022 			previous_state);
1023 		if (status != PSVC_SUCCESS)
1024 			return (status);
1025 
1026 		if (strcmp(state, previous_state) != 0) {
1027 			char sensor_label[32];
1028 			char dev_label[32];
1029 			int32_t j;
1030 
1031 			psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, dev_label);
1032 			psvc_get_attr(hdlp, sensor_id, PSVC_LABEL_ATTR,
1033 				sensor_label);
1034 
1035 			if (strcmp(state, PSVC_ERROR) == 0) {
1036 				syslog(LOG_ERR, DEVICE_FAILURE_MSG, dev_label,
1037 					sensor_label);
1038 				strcpy(led_state, PSVC_LED_ON);
1039 			} else {
1040 				syslog(LOG_ERR, DEVICE_OK_MSG, dev_label);
1041 				strcpy(led_state, PSVC_LED_OFF);
1042 			}
1043 
1044 			psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR,
1045 				&led_count, PSVC_DEV_FAULT_LED);
1046 			for (j = 0; j < led_count; j++) {
1047 				status = psvc_get_attr(hdlp, id,
1048 					PSVC_ASSOC_ID_ATTR, &led_id,
1049 					PSVC_DEV_FAULT_LED, j);
1050 				if (status != PSVC_SUCCESS)
1051 					return (status);
1052 				status = psvc_set_attr(hdlp, led_id,
1053 					PSVC_LED_STATE_ATTR, led_state);
1054 				if (status != PSVC_SUCCESS) {
1055 					syslog(LOG_ERR, SET_LED_FAILED_MSG,
1056 						led_id, errno);
1057 					return (status);
1058 				}
1059 			}
1060 		}
1061 	}
1062 
1063 	return (PSVC_SUCCESS);
1064 }
1065 
1066 static float
1067 get_filtered_error(float *last_errors, int current_error)
1068 {
1069 	float error;
1070 	float adder;
1071 	int i = 0;
1072 
1073 	adder = last_errors[0];
1074 	for (i = 1; i < PSVC_MAXERRORS; i++) {
1075 		adder = adder + last_errors[i];
1076 	}
1077 	adder = adder + current_error;
1078 	error = adder/(PSVC_MAXERRORS+1);
1079 
1080 	return (error);
1081 }
1082 
1083 static int32_t
1084 change_cpu_fans(psvc_opaque_t hdlp, char *fan_id, int32_t fan_speed)
1085 {
1086 	int err = PSVC_SUCCESS;
1087 	int i;
1088 	int32_t control_count;
1089 	char *control_id;
1090 	int32_t old_fan_speed;
1091 
1092 	psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_MATCHES_ATTR, &control_count,
1093 		PSVC_FAN_DRIVE_CONTROL);
1094 	if (control_count == 0)
1095 		return (PSVC_SUCCESS);
1096 
1097 	err = psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_ID_ATTR, &control_id,
1098 		PSVC_FAN_DRIVE_CONTROL, 0);
1099 	if (err != PSVC_SUCCESS)
1100 		return (err);
1101 
1102 	/*
1103 	 * this call will return PSVC_FAILURE on the first pass,
1104 	 * because no value has been set.
1105 	 */
1106 	err = psvc_get_attr(hdlp, control_id, PSVC_CONTROL_VALUE_ATTR,
1107 		&old_fan_speed);
1108 	if (err == PSVC_SUCCESS && old_fan_speed == fan_speed)
1109 		return (PSVC_SUCCESS);
1110 
1111 	for (i = 0; i < control_count; i++) {
1112 		err = psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_ID_ATTR,
1113 			&control_id, PSVC_FAN_DRIVE_CONTROL, i);
1114 		if (err != PSVC_SUCCESS)
1115 			return (err);
1116 
1117 		err = psvc_set_attr(hdlp, control_id, PSVC_CONTROL_VALUE_ATTR,
1118 			&fan_speed);
1119 		if (err == PSVC_FAILURE) {
1120 			syslog(LOG_ERR, SET_FANSPEED_FAILED_MSG, control_id,
1121 				errno);
1122 			return (err);
1123 		}
1124 	}
1125 	return (err);
1126 }
1127 
1128 static int32_t
1129 device_temp_check(psvc_opaque_t hdlp, char *fan_id, int32_t *hot_device)
1130 {
1131 	int i;
1132 	int32_t err = PSVC_SUCCESS;
1133 	char *sensor_id;
1134 	int32_t sensor_count;
1135 	int32_t temp;
1136 
1137 	*hot_device = 0;
1138 
1139 	psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
1140 		PSVC_DEV_TEMP_SENSOR);
1141 	for (i = 0; i < sensor_count; i++) {
1142 		err = psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_ID_ATTR,
1143 			&sensor_id, PSVC_DEV_TEMP_SENSOR, i);
1144 		if (err == PSVC_FAILURE)
1145 			return (err);
1146 		err = psvc_get_attr(hdlp, sensor_id, PSVC_SENSOR_VALUE_ATTR,
1147 			&temp);
1148 		if (err == PSVC_FAILURE) {
1149 			if (errno == ENODEV) {
1150 				temp = 0;
1151 			} else {
1152 				syslog(LOG_ERR, GET_SENSOR_FAILED_MSG, errno,
1153 					sensor_id);
1154 				return (err);
1155 			}
1156 		}
1157 
1158 		if (*hot_device < temp)
1159 			*hot_device = temp;
1160 	}
1161 	return (PSVC_SUCCESS);
1162 }
1163 
1164 int32_t
1165 psvc_fan_control_policy_0(psvc_opaque_t hdlp, char *fan_id)
1166 {
1167 	boolean_t is_enabled;
1168 	int32_t err = PSVC_SUCCESS;
1169 	int16_t setpoint, hysteresis, loopgain, loopbias;
1170 	int current_error;		/* Holds current error */
1171 					/* Signal before signaling */
1172 	float filtered_error;		/* Holds the filtered error signal */
1173 	int ampout;			/* output of loop amplifier */
1174 	int hot_device;
1175 
1176 	int16_t error_number;
1177 	float last_errors[PSVC_MAXERRORS];	/* Holds the filtered error */
1178 						/* from the last n iterations */
1179 
1180 	psvc_get_attr(hdlp, fan_id, PSVC_ENABLE_ATTR, &is_enabled);
1181 	if (is_enabled == PSVC_DISABLED)
1182 		return (PSVC_SUCCESS);
1183 
1184 	err = psvc_get_attr(hdlp, fan_id, PSVC_SETPOINT_ATTR, &setpoint);
1185 	if (err != PSVC_SUCCESS)
1186 		return (err);
1187 
1188 	err = psvc_get_attr(hdlp, fan_id, PSVC_HYSTERESIS_ATTR,
1189 		&hysteresis);
1190 	if (err != PSVC_SUCCESS)
1191 		return (err);
1192 
1193 	err = psvc_get_attr(hdlp, fan_id, PSVC_LOOPGAIN_ATTR, &loopgain);
1194 	if (err != PSVC_SUCCESS)
1195 		return (err);
1196 
1197 	err = psvc_get_attr(hdlp, fan_id, PSVC_LOOPBIAS_ATTR, &loopbias);
1198 	if (err != PSVC_SUCCESS)
1199 		return (err);
1200 
1201 	err = psvc_get_attr(hdlp, fan_id, PSVC_TEMP_DIFFERENTIAL_ATTR,
1202 		last_errors);
1203 	if (err != PSVC_SUCCESS)
1204 		return (err);
1205 
1206 	err = psvc_get_attr(hdlp, fan_id, PSVC_TEMP_DIFFERENTIAL_INDEX_ATTR,
1207 		&error_number);
1208 	if (err != PSVC_SUCCESS)
1209 		return (err);
1210 
1211 	err = device_temp_check(hdlp, fan_id, &hot_device);
1212 	if (err != PSVC_SUCCESS) {
1213 		printf("psvc_fan_control failure in device_temp_check\n");
1214 		return (err);
1215 	}
1216 	current_error = setpoint - hot_device;
1217 	filtered_error = get_filtered_error(last_errors, current_error);
1218 	if (filtered_error <= 0 || filtered_error > hysteresis) {
1219 		ampout = (int)((filtered_error * loopgain) + loopbias);
1220 		if (ampout < 0)
1221 			ampout = 0;
1222 		if (ampout > 1023)
1223 			ampout = 1023;
1224 		err = change_cpu_fans(hdlp, fan_id, ampout);
1225 		if (err != PSVC_SUCCESS)
1226 			return (err);
1227 	}
1228 	last_errors[error_number++] = current_error;
1229 	if (error_number == PSVC_MAXERRORS)
1230 		error_number = 0;
1231 
1232 	err = psvc_set_attr(hdlp, fan_id, PSVC_TEMP_DIFFERENTIAL_ATTR,
1233 		last_errors);
1234 	if (err != PSVC_SUCCESS)
1235 		return (err);
1236 
1237 	err = psvc_set_attr(hdlp, fan_id, PSVC_TEMP_DIFFERENTIAL_INDEX_ATTR,
1238 		&error_number);
1239 	if (err != PSVC_SUCCESS)
1240 		return (err);
1241 
1242 	return (PSVC_SUCCESS);
1243 }
1244 
1245 int32_t
1246 psvc_fan_present_policy_0(psvc_opaque_t hdlp, char *id)
1247 {
1248 	int32_t		status = PSVC_SUCCESS;
1249 	boolean_t	presence;
1250 	int fd;
1251 	FILE *fp;
1252 
1253 	status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence);
1254 	if (status != PSVC_SUCCESS)
1255 		return (status);
1256 
1257 	if (presence == PSVC_ABSENT) {
1258 		/*
1259 		 * We make this open, write, close, call because picld
1260 		 * starts in rcS.d while print services does not start
1261 		 * until later (either rc2.d or rc3.d)
1262 		 */
1263 		fd = open("/dev/console", O_WRONLY | O_NOCTTY);
1264 		if (fd != -1) {
1265 			fp = fdopen(fd, "w+");
1266 			if (fp != NULL) {
1267 				fprintf(fp, FAN_MISSING_MSG, id);
1268 				fclose(fp);
1269 			}
1270 			close(fd);
1271 		}
1272 		syslog(LOG_ERR, FAN_MISSING_MSG, id);
1273 	}
1274 	return (status);
1275 }
1276