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
87 static char *shutdown_string = "shutdown -y -g 60 -i 5 \"OVERTEMP condition\"";
88
89 static int cpus_online = 0;
90
91 typedef struct seg_desc {
92 int32_t segdesc;
93 int16_t segoffset;
94 int16_t seglength;
95 } seg_desc_t;
96
97 static 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 */
116 static int n_read_temp = PSVC_THRESHOLD_COUNTER;
117 static int n_retry_keyswitch = PSVC_NUM_OF_RETRIES;
118 static int retry_sleep_keyswitch = 1;
119 static int n_retry_hotplug = PSVC_NUM_OF_RETRIES;
120 static int retry_sleep_hotplug = 1;
121 static int n_retry_fan_hotplug = PSVC_NUM_OF_RETRIES;
122 static int retry_sleep_fan_hotplug = 1;
123 static int n_retry_fan_present = PSVC_NUM_OF_RETRIES;
124 static int retry_sleep_fan_present = 1;
125
126 typedef struct {
127 int *pvar;
128 char *texttag;
129 } i2c_noise_param_t;
130
131 static 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
146 static void
i2cparams_sun4u_debug(i2c_noise_param_t * pi2cparams,int usingDefaults)147 i2cparams_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
175 static void
i2cparams_sun4u_load(void)176 i2cparams_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
212 int32_t
psvc_update_thresholds_0(psvc_opaque_t hdlp,char * id)213 psvc_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
306 static int32_t
check_temp(psvc_opaque_t hdlp,char * id,int32_t silent)307 check_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
518 int32_t
psvc_check_temperature_policy_0(psvc_opaque_t hdlp,char * id)519 psvc_check_temperature_policy_0(psvc_opaque_t hdlp, char *id)
520 {
521 return (check_temp(hdlp, id, 0));
522 }
523
524 int32_t
psvc_check_temperature_silent_policy_0(psvc_opaque_t hdlp,char * id)525 psvc_check_temperature_silent_policy_0(psvc_opaque_t hdlp, char *id)
526 {
527 return (check_temp(hdlp, id, 1));
528 }
529
530 int32_t
psvc_fan_enable_disable_policy_0(psvc_opaque_t hdlp,char * id)531 psvc_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 */
652 int32_t
psvc_switch_fan_onoff_policy_0(psvc_opaque_t hdlp,char * id)653 psvc_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
679 static int32_t
check_cpu_temp_fault(psvc_opaque_t hdlp,char * cpu,int32_t cpu_count)680 check_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
721 int32_t
psvc_shutdown_policy_0(psvc_opaque_t hdlp,char * id)722 psvc_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 */
771 int32_t
psvc_keyswitch_position_policy_0(psvc_opaque_t hdlp,char * id)772 psvc_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
824 int32_t
psvc_hotplug_notifier_policy_0(psvc_opaque_t hdlp,char * id)825 psvc_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
899 int32_t
psvc_fan_hotplug_policy_0(psvc_opaque_t hdlp,char * id)900 psvc_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
1010 int32_t
psvc_init_led_policy_0(psvc_opaque_t hdlp,char * id)1011 psvc_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
1019 int32_t
psvc_init_state_policy_0(psvc_opaque_t hdlp,char * id)1020 psvc_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
1029 int32_t
psvc_ps_overcurrent_check_policy_0(psvc_opaque_t hdlp,char * power_supply_id)1030 psvc_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, &s);
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
1089 int32_t
psvc_device_fail_notifier_policy_0(psvc_opaque_t hdlp,char * id)1090 psvc_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
1181 static float
get_filtered_error(float * last_errors,int current_error)1182 get_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
1198 static int32_t
change_cpu_fans(psvc_opaque_t hdlp,char * fan_id,int32_t fan_speed)1199 change_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
1243 static int32_t
device_temp_check(psvc_opaque_t hdlp,char * fan_id,int32_t * hot_device)1244 device_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
1279 int32_t
psvc_fan_control_policy_0(psvc_opaque_t hdlp,char * fan_id)1280 psvc_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
1360 int32_t
psvc_fan_present_policy_0(psvc_opaque_t hdlp,char * id)1361 psvc_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