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