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
i2cparams_sun4u_debug(i2c_noise_param_t * pi2cparams,int usingDefaults)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
i2cparams_sun4u_load(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
psvc_update_thresholds_0(psvc_opaque_t hdlp,char * id)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
check_temp(psvc_opaque_t hdlp,char * id,int32_t silent)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
psvc_check_temperature_policy_0(psvc_opaque_t hdlp,char * id)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
psvc_check_temperature_silent_policy_0(psvc_opaque_t hdlp,char * id)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
psvc_fan_enable_disable_policy_0(psvc_opaque_t hdlp,char * id)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
psvc_switch_fan_onoff_policy_0(psvc_opaque_t hdlp,char * id)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
check_cpu_temp_fault(psvc_opaque_t hdlp,char * cpu,int32_t cpu_count)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
psvc_shutdown_policy_0(psvc_opaque_t hdlp,char * id)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
psvc_keyswitch_position_policy_0(psvc_opaque_t hdlp,char * id)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
psvc_hotplug_notifier_policy_0(psvc_opaque_t hdlp,char * id)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
psvc_fan_hotplug_policy_0(psvc_opaque_t hdlp,char * id)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
psvc_init_led_policy_0(psvc_opaque_t hdlp,char * id)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
psvc_init_state_policy_0(psvc_opaque_t hdlp,char * id)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
psvc_ps_overcurrent_check_policy_0(psvc_opaque_t hdlp,char * power_supply_id)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, &s);
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
psvc_device_fail_notifier_policy_0(psvc_opaque_t hdlp,char * id)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
get_filtered_error(float * last_errors,int current_error)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
change_cpu_fans(psvc_opaque_t hdlp,char * fan_id,int32_t fan_speed)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
device_temp_check(psvc_opaque_t hdlp,char * fan_id,int32_t * hot_device)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
psvc_fan_control_policy_0(psvc_opaque_t hdlp,char * fan_id)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
psvc_fan_present_policy_0(psvc_opaque_t hdlp,char * id)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