4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2000 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This file contains the environmental daemon module.
35 * Grover system contains one temperature device, MAX1617, which consists
36 * of two sensors: CPU die and CPU ambient. Each sensor is represented
37 * as a different minor device and the current temperature is read via an
38 * I2C_GET_TEMPERATURE ioctl call to the max1617 driver. Additionally, the
39 * MAX1617 device supports both a low and high temperature limit, which
40 * can trigger an alert condition, causing power supply to turn off.
42 * The environmental daemon defines the following thresholds per sensor:
44 * high_power_off high hard shutdown
45 * high_shutdown high soft shutdown limit
46 * high_warning high warning limit
47 * low_warning low warning limit
48 * low_shutdown low soft shutdown limit
49 * low_power_off low hard shutdown limit
51 * Except for the low_power_off and high_power_off limits, all other threshold
52 * values can be changed via "piclenvd.conf" configuration file.
54 * Environmental monitoring is done by the "envthr" thread. It periodically
55 * monitors both CPU die and CPU ambient temperatures and takes appropriate
56 * action depending upon the current temperature and threshold values for
57 * that sensor. If the temperature reaches the high_shutdown limit or the
58 * low_shutdown limit, and remains there for over shutdown_interval seconds,
59 * it forces a graceful system shutdown via tuneable shutdown_cmd string
60 * variable. Otherwise, if the temperature reaches the high_warning limit
61 * or the low_warning limit, it logs and prints a message on the console.
62 * This message will be printed at most at "warning_interval" seconds
63 * interval, which is also a tuneable variable.
65 * Grover system also contains a fan, known as system fan, which can be turned
66 * ON or OFF under software control. However, its speed is automatically
67 * controlled by the hardware based upon the ambient temperature. When in EStar
68 * mode (i.e. lowest power state), the environmental daemon will turn off this
69 * fan provided the CPU die and ambient temperature is below the high warning
72 * The power state monitoring is done by the "pmthr" thread. It uses the
73 * PM_GET_STATE_CHANGE and PM_GET_STATE_CHANGE_WAIT ioctl commands to pick
74 * up any power state change events. It processes all queued power state
75 * change events and determines the curret lowest power state and saves it
76 * in cur_lpstate variable. Whenever this state changes from the previous
77 * lowest power state (saved in prev_lpstate), it wakes up the "envtrh"
80 * The "lpstate_lock" mutex and "lpstate_cond" condition variables are used
81 * to communicate power state change events from the "pmthr" to the "envthr"
82 * thread. The "envthr" thread uses the pthread_cond_timedwait() interface
83 * to wait for any power state change notifications. The "pmthr" uses the
84 * pthread_signal() interface to wake up the "envthr" thread.
100 #include <sys/open.h>
101 #include <sys/time.h>
102 #include <sys/utsname.h>
103 #include <sys/systeminfo.h>
104 #include <sys/i2c/clients/max1617.h>
105 #include <sys/i2c/clients/i2c_client.h>
112 static void piclenvd_register(void);
113 static void piclenvd_init(void);
114 static void piclenvd_fini(void);
115 extern void env_picl_setup();
117 #pragma init(piclenvd_register)
119 static picld_plugin_reg_t my_reg_info
= {
120 PICLD_PLUGIN_VERSION_1
,
121 PICLD_PLUGIN_CRITICAL
,
131 static int sensor_poll_interval
= SENSOR_POLL_INTERVAL
;
132 static int warning_interval
= WARNING_INTERVAL
;
133 static int shutdown_interval
= SHUTDOWN_INTERVAL
;
134 static char shutdown_cmd
[128] = SHUTDOWN_CMD
;
135 static int monitor_temperature
= 0;
137 static sensor_thresh_t cpu_die_thresh
= {
138 CPU_DIE_LOW_POWER_OFF
, CPU_DIE_HIGH_POWER_OFF
,
139 CPU_DIE_LOW_SHUTDOWN
, CPU_DIE_HIGH_SHUTDOWN
,
140 CPU_DIE_LOW_WARNING
, CPU_DIE_HIGH_WARNING
,
144 static sensor_thresh_t cpu_amb_thresh
= {
145 CPU_AMB_LOW_POWER_OFF
, CPU_AMB_HIGH_POWER_OFF
,
146 CPU_AMB_LOW_SHUTDOWN
, CPU_AMB_HIGH_SHUTDOWN
,
147 CPU_AMB_LOW_WARNING
, CPU_AMB_HIGH_WARNING
,
152 * Temperature sensors
155 static env_sensor_t cpu_die_sensor
=
156 { SENSOR_CPU_DIE
, CPU_DIE_SENSOR_DEVFS
, &cpu_die_thresh
};
158 static env_sensor_t cpu_amb_sensor
=
159 { SENSOR_CPU_AMB
, CPU_AMB_SENSOR_DEVFS
, &cpu_amb_thresh
};
162 static env_sensor_t
*envd_sensors
[] = {
171 static env_fan_t envd_system_fan
= {
172 ENV_SYSTEM_FAN
, ENV_SYSTEM_FAN_DEVFS
,
173 SYSTEM_FAN_SPEED_MIN
, SYSTEM_FAN_SPEED_MAX
,
176 static env_fan_t
*envd_fans
[] = {
183 * Environmental thread variables
185 static boolean_t envd_inited
= B_FALSE
;
186 static boolean_t system_shutdown_started
;
187 static boolean_t envthr_created
; /* envthr created */
188 static pthread_t envthr_tid
; /* envthr thread ID */
189 static pthread_attr_t thr_attr
;
192 * Power management thread (pmthr) variables
194 static pthread_t pmthr_tid
; /* pmthr thread ID */
195 static int pmthr_created
; /* pmthr created */
196 static int pm_fd
; /* PM device file descriptor */
197 static int cur_lpstate
; /* cur low power state */
199 static pthread_mutex_t lpstate_lock
; /* low power state lock */
200 static pthread_cond_t lpstate_cond
; /* low power state condvar */
204 * Tuneable variables data structure/array
208 char *name
; /* keyword */
209 void *addr
; /* memory (variable) address */
210 int type
; /* keyword type */
211 int size
; /* variable size */
215 #define KTYPE_INT 1 /* signed int */
216 #define KTYPE_STRING 2 /* string in double quotes */
218 static env_tuneable_t env_tuneables
[] = {
219 {"cpu_amb_low_shutdown", &cpu_amb_thresh
.low_shutdown
, KTYPE_INT
,
221 {"cpu_amb_low_warning", &cpu_amb_thresh
.low_warning
, KTYPE_INT
,
223 {"cpu_amb_target_temp", &cpu_amb_thresh
.target_temp
, KTYPE_INT
,
225 {"cpu_amb_high_shutdown", &cpu_amb_thresh
.high_shutdown
, KTYPE_INT
,
227 {"cpu_amb_high_warning", &cpu_amb_thresh
.high_warning
, KTYPE_INT
,
229 {"cpu_die_low_shutdown", &cpu_die_thresh
.low_shutdown
, KTYPE_INT
,
231 {"cpu_die_low_warning", &cpu_die_thresh
.low_warning
, KTYPE_INT
,
233 {"cpu_die_target_temp", &cpu_die_thresh
.target_temp
, KTYPE_INT
,
235 {"cpu_die_high_shutdown", &cpu_die_thresh
.high_shutdown
, KTYPE_INT
,
237 {"cpu_die_high_warning", &cpu_die_thresh
.high_warning
, KTYPE_INT
,
239 {"sensor_poll_interval", &sensor_poll_interval
, KTYPE_INT
,
240 sizeof (sensor_poll_interval
)},
241 {"monitor_temperature", &monitor_temperature
, KTYPE_INT
,
242 sizeof (monitor_temperature
)},
243 {"warning_interval", &warning_interval
, KTYPE_INT
,
244 sizeof (warning_interval
)},
245 {"shutdown_interval", &shutdown_interval
, KTYPE_INT
,
246 sizeof (shutdown_interval
)},
247 {"shutdown_cmd", &shutdown_cmd
[0], KTYPE_STRING
, sizeof (shutdown_cmd
)},
248 {"env_debug", &env_debug
, KTYPE_INT
, sizeof (env_debug
)},
253 * Lookup fan and return a pointer to env_fan_t data structure.
256 fan_lookup(char *name
)
261 for (i
= 0; (fanp
= envd_fans
[i
]) != NULL
; i
++) {
262 if (strcmp(fanp
->name
, name
) == 0)
269 * Lookup sensor and return a pointer to env_sensor_t data structure.
272 sensor_lookup(char *name
)
275 env_sensor_t
*sensorp
;
277 for (i
= 0; (sensorp
= envd_sensors
[i
]) != NULL
; i
++) {
278 if (strcmp(sensorp
->name
, name
) == 0)
285 * Get current temperature
286 * Returns -1 on error, 0 if successful
289 get_temperature(env_sensor_t
*sensorp
, tempr_t
*temp
)
291 int fd
= sensorp
->fd
;
296 else if (ioctl(fd
, I2C_GET_TEMPERATURE
, temp
) == -1) {
298 if (sensorp
->error
== 0) {
300 envd_log(LOG_WARNING
, ENV_SENSOR_ACCESS_FAIL
,
301 sensorp
->name
, errno
, strerror(errno
));
303 } else if (sensorp
->error
!= 0) {
305 envd_log(LOG_WARNING
, ENV_SENSOR_ACCESS_OK
, sensorp
->name
);
312 * Get current fan speed
313 * Returns -1 on error, 0 if successful
316 get_fan_speed(env_fan_t
*fanp
, fanspeed_t
*fanspeedp
)
322 if (fan_fd
== -1 || read(fan_fd
, fanspeedp
, sizeof (fanspeed_t
)) !=
330 * Returns -1 on error, 0 if successful
333 set_fan_speed(env_fan_t
*fanp
, fanspeed_t fanspeed
)
339 if (fan_fd
== -1 || write(fan_fd
, &fanspeed
, sizeof (fanspeed
)) !=
347 * close all fan devices
350 envd_close_fans(void)
355 for (i
= 0; (fanp
= envd_fans
[i
]) != NULL
; i
++) {
356 if (fanp
->fd
!= -1) {
357 (void) close(fanp
->fd
);
364 * Close sensor devices
367 envd_close_sensors(void)
370 env_sensor_t
*sensorp
;
372 for (i
= 0; (sensorp
= envd_sensors
[i
]) != NULL
; i
++) {
373 if (sensorp
->fd
!= -1) {
374 (void) close(sensorp
->fd
);
393 * Open fan devices and initialize per fan data structure.
394 * Returns #fans found.
397 envd_setup_fans(void)
402 char path
[FILENAME_MAX
];
405 for (i
= 0; (fanp
= envd_fans
[i
]) != NULL
; i
++) {
408 fanp
->prev_speed
= 0;
410 (void) strcpy(path
, "/devices");
411 (void) strlcat(path
, fanp
->devfs_path
, sizeof (path
));
412 fd
= open(path
, O_RDWR
);
414 envd_log(LOG_WARNING
, ENV_FAN_OPEN_FAIL
, fanp
->name
,
415 fanp
->devfs_path
, errno
, strerror(errno
));
416 fanp
->present
= B_FALSE
;
420 fanp
->present
= B_TRUE
;
424 * Set cur_speed/prev_speed to current fan speed
426 if (get_fan_speed(fanp
, &speed
) == -1) {
428 * The Fan driver does not know the current fan speed.
429 * Initialize it to 50% of the max speed and reread
430 * to get the current speed.
432 speed
= fanp
->speed_max
/2;
433 (void) set_fan_speed(fanp
, speed
);
434 if (get_fan_speed(fanp
, &speed
) == -1)
437 fanp
->cur_speed
= speed
;
438 fanp
->prev_speed
= speed
;
444 * Open temperature sensor devices and initialize per sensor data structure.
445 * Returns #sensors found.
448 envd_setup_sensors(void)
452 env_sensor_t
*sensorp
;
453 char path
[FILENAME_MAX
];
455 sensor_thresh_t
*threshp
;
457 for (i
= 0; (sensorp
= envd_sensors
[i
]) != NULL
; i
++) {
459 sensorp
->shutdown_initiated
= B_FALSE
;
460 sensorp
->warning_tstamp
= 0;
461 sensorp
->shutdown_tstamp
= 0;
462 threshp
= sensorp
->temp_thresh
;
463 sensorp
->cur_temp
= threshp
->target_temp
;
466 (void) strcpy(path
, "/devices");
467 (void) strlcat(path
, sensorp
->devfs_path
, sizeof (path
));
468 sensorp
->fd
= open(path
, O_RDWR
);
469 if (sensorp
->fd
== -1) {
470 envd_log(LOG_WARNING
, ENV_SENSOR_OPEN_FAIL
,
471 sensorp
->name
, sensorp
->devfs_path
, errno
,
473 sensorp
->present
= B_FALSE
;
476 sensorp
->present
= B_TRUE
;
479 if (monitor_temperature
) {
481 * Set low_power_off and high_power_off limits
483 (void) ioctl(sensorp
->fd
, MAX1617_SET_LOW_LIMIT
,
484 &threshp
->low_power_off
);
485 (void) ioctl(sensorp
->fd
, MAX1617_SET_HIGH_LIMIT
,
486 &threshp
->high_power_off
);
490 * Set cur_temp field to the current temperature value
492 if (get_temperature(sensorp
, &temp
) == 0) {
493 sensorp
->cur_temp
= temp
;
500 * Read all temperature sensors and take appropriate action based
501 * upon temperature threshols associated with each sensor. Possible
504 * temperature > high_shutdown
505 * temperature < low_shutdown
506 * Gracefully shutdown the system and log/print a message
507 * on the system console provided the temperature has been
508 * in shutdown range for "shutdown_interval" seconds.
510 * high_warning < temperature <= high_shutdown
511 * low_warning > temperature >= low_shutdown
512 * Log/print a warning message on the system console at most
513 * once every "warning_interval" seconds.
515 * Note that the current temperature is recorded in the "cur_temp" field
516 * within each env_sensor_t structure.
519 monitor_sensors(void)
523 env_sensor_t
*sensorp
;
524 sensor_thresh_t
*threshp
;
529 for (i
= 0; (sensorp
= envd_sensors
[i
]) != NULL
; i
++) {
530 if (get_temperature(sensorp
, &temp
) < 0)
533 sensorp
->cur_temp
= temp
;
537 "sensor: %-13s temp cur:%3d target:%3d\n",
539 sensorp
->temp_thresh
->target_temp
);
541 if (!monitor_temperature
)
545 * If this sensor already triggered system shutdown, don't
546 * log any more shutdown/warning messages for it.
548 if (sensorp
->shutdown_initiated
)
552 * Check for the temperature in warning and shutdown range
553 * and take appropriate action.
555 threshp
= sensorp
->temp_thresh
;
556 if (TEMP_IN_WARNING_RANGE(temp
, threshp
)) {
558 * Log warning message at most once every
559 * warning_interval seconds.
561 (void) gettimeofday(&ct
, NULL
);
562 if ((ct
.tv_sec
- sensorp
->warning_tstamp
) >=
564 envd_log(LOG_WARNING
, ENV_WARNING_MSG
,
566 threshp
->low_warning
,
567 threshp
->high_warning
);
568 sensorp
->warning_tstamp
= ct
.tv_sec
;
572 if (TEMP_IN_SHUTDOWN_RANGE(temp
, threshp
)) {
573 (void) gettimeofday(&ct
, NULL
);
574 if (sensorp
->shutdown_tstamp
== 0)
575 sensorp
->shutdown_tstamp
= ct
.tv_sec
;
578 * Shutdown the system if the temperature remains
579 * in the shutdown range for over shutdown_interval
582 if ((ct
.tv_sec
- sensorp
->shutdown_tstamp
) >=
585 sensorp
->shutdown_initiated
= B_TRUE
;
586 (void) snprintf(msgbuf
, sizeof (msgbuf
),
587 ENV_SHUTDOWN_MSG
, sensorp
->name
,
588 temp
, threshp
->low_shutdown
,
589 threshp
->high_shutdown
);
590 envd_log(LOG_CRIT
, msgbuf
);
592 /* shutdown the system (only once) */
593 if (system_shutdown_started
== B_FALSE
) {
594 (void) snprintf(syscmd
, sizeof (syscmd
),
595 "%s \"%s\"", shutdown_cmd
, msgbuf
);
596 envd_log(LOG_CRIT
, syscmd
);
597 system_shutdown_started
= B_TRUE
;
598 (void) system(syscmd
);
601 } else if (sensorp
->shutdown_tstamp
!= 0)
602 sensorp
->shutdown_tstamp
= 0;
608 * This is the environment thread, which monitors the current temperature
609 * and power managed state and controls system fan speed. Temperature is
610 * polled every sensor-poll_interval seconds duration.
616 fanspeed_t fan_speed
;
619 env_fan_t
*pmfanp
= &envd_system_fan
;
620 tempr_t cpu_amb_temp
, cpu_die_temp
;
621 tempr_t cpu_amb_warning
, cpu_die_warning
;
623 (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
);
624 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
626 cpu_amb_warning
= cpu_amb_sensor
.temp_thresh
->high_warning
;
627 cpu_die_warning
= cpu_die_sensor
.temp_thresh
->high_warning
;
630 (void) gettimeofday(&ct
, NULL
);
633 * Monitor current temperature for all sensors
634 * (current temperature is recorded in the "cur_temp"
635 * field within each sensor data structure)
639 cpu_amb_temp
= cpu_amb_sensor
.cur_temp
;
640 cpu_die_temp
= cpu_die_sensor
.cur_temp
;
643 * Process any PM state change events while waiting until
644 * time to poll sensors again (i.e. sensor_poll_interval
645 * seconds from the last time).
647 to
.tv_sec
= ct
.tv_sec
+ sensor_poll_interval
;
651 * Turn off system fan if in lowest power state
652 * and both CPU die and ambient temperatures are
653 * below corresponding high warning temperatures.
655 fan_speed
= pmfanp
->speed_max
;
656 if (cur_lpstate
&& cpu_amb_temp
< cpu_amb_warning
&&
657 cpu_die_temp
< cpu_die_warning
)
658 fan_speed
= pmfanp
->speed_min
;
662 "fan: %-16s speed cur:%3d new:%3d "
663 "low-power:%d\n", pmfanp
->name
,
664 (uint_t
)pmfanp
->cur_speed
,
665 (uint_t
)fan_speed
, cur_lpstate
);
667 if (fan_speed
!= pmfanp
->cur_speed
&&
668 set_fan_speed(pmfanp
, fan_speed
) == 0)
669 pmfanp
->cur_speed
= fan_speed
;
671 /* wait for power state change or time to poll */
672 pthread_mutex_lock(&lpstate_lock
);
673 err
= pthread_cond_timedwait(&lpstate_cond
,
675 pthread_mutex_unlock(&lpstate_lock
);
676 if (err
== ETIMEDOUT
)
685 * This is the power management thread, which monitors all power state
686 * change events and wakes up the "envthr" thread when the system enters
687 * or exits the lowest power state.
692 pm_state_change_t pmstate
;
693 char physpath
[PATH_MAX
];
696 (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
);
697 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
699 pmstate
.physpath
= physpath
;
700 pmstate
.size
= sizeof (physpath
);
706 * Get PM state change events to check if the system
707 * is in lowest power state and wake up the "envthr"
708 * thread when the power state changes.
710 * To minimize polling, we use the blocking interface
711 * to get the power state change event here.
713 if (ioctl(pm_fd
, PM_GET_STATE_CHANGE_WAIT
, &pmstate
) != 0) {
720 * Extract the lowest power state from the last queued
721 * state change events. We pick up queued state change
722 * events using the non-blocking interface and wake up
723 * the "envthr" thread only after consuming all the
724 * state change events queued at that time.
729 "pmstate event:0x%x flags:%x comp:%d "
730 "oldval:%d newval:%d path:%s\n",
731 pmstate
.event
, pmstate
.flags
,
732 pmstate
.component
, pmstate
.old_level
,
733 pmstate
.new_level
, pmstate
.physpath
);
736 (pmstate
.flags
& PSC_ALL_LOWEST
) ? 1 : 0;
737 } while (ioctl(pm_fd
, PM_GET_STATE_CHANGE
, &pmstate
) == 0);
739 if (cur_lpstate
!= prev_lpstate
) {
740 prev_lpstate
= cur_lpstate
;
741 pthread_mutex_lock(&lpstate_lock
);
742 pthread_cond_signal(&lpstate_cond
);
743 pthread_mutex_unlock(&lpstate_lock
);
748 * We won't be able to monitor lowest power state any longer,
749 * hence reset it and wakeup the "envthr".
751 if (cur_lpstate
!= 0) {
752 prev_lpstate
= cur_lpstate
;
754 pthread_mutex_lock(&lpstate_lock
);
755 pthread_cond_signal(&lpstate_cond
);
756 pthread_mutex_unlock(&lpstate_lock
);
758 envd_log(LOG_ERR
, PM_THREAD_EXITING
, errno
, strerror(errno
));
764 * Parse string value (handling escaped double quotes and other characters)
765 * and return string end pointer.
769 parse_string_val(char *buf
)
776 for (p
= buf
+1; (c
= *p
) != '\0'; p
++)
777 if (c
== '"' || (c
== '\\' && *++p
== '\0'))
780 return ((*p
== '"') ? p
: NULL
);
785 * Process configuration file
788 process_env_conf_file(void)
790 int line
, len
, val
, toklen
;
793 env_tuneable_t
*tunep
;
794 char nmbuf
[SYS_NMLN
];
795 char fname
[PATH_MAX
];
796 char *tok
, *valuep
, *strend
;
797 char tokdel
[] = " \t\n\r";
800 if (sysinfo(SI_PLATFORM
, nmbuf
, sizeof (nmbuf
)) == -1)
803 (void) snprintf(fname
, sizeof (fname
), PICLD_PLAT_PLUGIN_DIRF
, nmbuf
);
804 (void) strlcat(fname
, ENV_CONF_FILE
, sizeof (fname
));
805 fp
= fopen(fname
, "r");
810 * Blank lines or lines starting with "#" or "*" in the first
811 * column are ignored. All other lines are assumed to contain
812 * input in the following format:
816 * where the "value" can be a signed integer or string (in
817 * double quotes) depending upon the keyword.
820 for (line
= 1; fgets(buf
, sizeof (buf
), fp
) != NULL
; line
++) {
825 /* skip long lines */
826 if (buf
[len
-1] != '\n') {
829 } else if (skip_line
) {
836 if (buf
[0] == '*' || buf
[0] == '#')
840 * Skip over white space to get the keyword
842 tok
= buf
+ strspn(buf
, tokdel
);
844 continue; /* blank line */
846 toklen
= strcspn(tok
, tokdel
);
849 /* Get possible location for value (within current line) */
850 valuep
= tok
+ toklen
+ 1;
851 if (valuep
> buf
+len
)
855 * Lookup the keyword and process value accordingly
857 for (tunep
= &env_tuneables
[0]; tunep
->name
!= NULL
; tunep
++) {
858 if (strcmp(tunep
->name
, tok
) != 0)
861 switch (tunep
->type
) {
864 val
= strtol(valuep
, &valuep
, 0);
866 /* Check for invalid value or extra tokens */
867 if (errno
!= 0 || strtok(valuep
, tokdel
)) {
869 ENV_CONF_INT_EXPECTED
,
874 /* Update only if value within range */
875 if (tunep
->size
== sizeof (int8_t) &&
877 *(int8_t *)tunep
->addr
= (int8_t)val
;
878 else if (tunep
->size
== sizeof (short) &&
880 *(short *)tunep
->addr
= (short)val
;
881 else if (tunep
->size
== sizeof (int))
882 *(int *)tunep
->addr
= (int)val
;
885 ENV_CONF_INT_EXPECTED
,
890 envd_log(LOG_INFO
, "SUNW_piclenvd: "
891 "file:%s line:%d %s = %d\n",
892 fname
, line
, tok
, val
);
897 * String value must be within double quotes.
898 * Skip over initial white spaces before
901 valuep
+= strspn(valuep
, tokdel
);
902 strend
= parse_string_val(valuep
);
904 if (strend
== NULL
|| *valuep
!= '"' ||
905 strtok(strend
+1, tokdel
) != NULL
||
906 (strend
-valuep
) > tunep
->size
) {
908 ENV_CONF_STRING_EXPECTED
,
915 envd_log(LOG_INFO
, "piclenvd: file:%s"
916 " line:%d %s = \"%s\"\n",
917 fname
, line
, tok
, valuep
+1);
918 (void) strcpy(tunep
->addr
, (caddr_t
)valuep
+1);
923 ENV_CONF_UNSUPPORTED_TYPE
,
925 tunep
->type
, tunep
->name
);
930 if (tunep
->name
== NULL
)
931 envd_log(LOG_INFO
, ENV_CONF_UNSUPPORTED_KEYWORD
,
938 * Setup envrionmental daemon state and start threads to monitor
939 * temperature and power management state.
940 * Returns -1 on error, 0 if successful.
946 if (envd_inited
== B_FALSE
) {
948 * Initialize global state
950 system_shutdown_started
= B_FALSE
;
951 envthr_created
= B_FALSE
;
952 pmthr_created
= B_FALSE
;
954 if (pthread_attr_init(&thr_attr
) != 0 ||
955 pthread_attr_setscope(&thr_attr
, PTHREAD_SCOPE_SYSTEM
) != 0)
958 if (pthread_mutex_init(&lpstate_lock
, NULL
) != 0 ||
959 pthread_cond_init(&lpstate_cond
, NULL
) != 0)
963 * Process tuneable parameters
965 process_env_conf_file();
968 * Setup temperature sensors and fail if we can't open
969 * at least one sensor.
971 if (envd_setup_sensors() <= 0)
975 * Setup fan device (don't fail even if we can't access
976 * the fan as we can still monitor temeperature.
978 (void) envd_setup_fans();
981 * Create a thread to monitor temperature and control fan
984 if (envthr_created
== B_FALSE
&& pthread_create(&envthr_tid
,
985 &thr_attr
, envthr
, (void *)NULL
) != 0) {
987 envd_close_sensors();
988 envd_log(LOG_CRIT
, ENV_THREAD_CREATE_FAILED
);
991 envthr_created
= B_TRUE
;
993 envd_inited
= B_TRUE
;
996 * Create a thread to monitor PM state
998 if (pmthr_created
== B_FALSE
) {
999 pm_fd
= open(PM_DEVICE
, O_RDONLY
);
1000 if (pm_fd
== -1 || pthread_create(&pmthr_tid
, &thr_attr
,
1001 pmthr
, (void *)NULL
) != 0) {
1003 envd_log(LOG_CRIT
, PM_THREAD_CREATE_FAILED
);
1005 pmthr_created
= B_TRUE
;
1012 piclenvd_register(void)
1014 picld_plugin_register(&my_reg_info
);
1021 * Start environmental daemon/threads
1023 if (envd_setup() != 0) {
1024 envd_log(LOG_CRIT
, ENVD_PLUGIN_INIT_FAILED
);
1029 * Now setup/populate PICL tree
1040 * Kill both "envthr" and "pmthr" threads.
1042 if (envthr_created
) {
1043 (void) pthread_cancel(envthr_tid
);
1044 (void) pthread_join(envthr_tid
, &exitval
);
1045 envthr_created
= B_FALSE
;
1048 if (pmthr_created
) {
1049 (void) pthread_cancel(pmthr_tid
);
1050 (void) pthread_join(pmthr_tid
, &exitval
);
1051 pmthr_created
= B_FALSE
;
1055 * close all sensors, fans and the power management device
1059 envd_close_sensors();
1060 envd_inited
= B_FALSE
;
1065 envd_log(int pri
, const char *fmt
, ...)
1070 vsyslog(pri
, fmt
, ap
);