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