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 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This file contains the environmental PICL plug-in module.
34 * This plugin sets up the PICLTREE for Enchilada WS.
35 * It provides functionality to get/set temperatures and
38 * The environmental policy defaults to the auto mode
39 * as programmed by OBP at boot time.
44 #include <sys/sysmacros.h>
51 #include <sys/processor.h>
60 #include <libdevinfo.h>
64 #include <sys/utsname.h>
65 #include <sys/systeminfo.h>
67 #include <sys/i2c/clients/i2c_client.h>
68 #include <sys/i2c/clients/adm1031.h>
69 #include <sys/i2c/clients/pic16f819_reg.h>
71 #include <sys/scsi/scsi.h>
72 #include <sys/scsi/generic/commands.h>
76 * PICL plugin entry points
78 static void piclenvd_register(void);
79 static void piclenvd_init(void);
80 static void piclenvd_fini(void);
85 extern void env_picl_setup(void);
86 extern void env_picl_destroy(void);
87 extern int env_picl_setup_tuneables(void);
90 * Sleep routine used for polling
92 static int get_dimm_fan_speed(int, fanspeed_t
*);
93 static int is_dimm_fan_failed(void);
95 #pragma init(piclenvd_register)
98 * Plugin registration information
100 static picld_plugin_reg_t my_reg_info
= {
101 PICLD_PLUGIN_VERSION
,
102 PICLD_PLUGIN_CRITICAL
,
108 #define REGISTER_INFORMATION_STRING_LENGTH 16
109 static char dimm_fan_rpm_string
[REGISTER_INFORMATION_STRING_LENGTH
] = {0};
110 static char dimm_fan_status_string
[REGISTER_INFORMATION_STRING_LENGTH
] = {0};
111 static char dimm_fan_command_string
[REGISTER_INFORMATION_STRING_LENGTH
] = {0};
112 static char dimm_fan_debug_string
[REGISTER_INFORMATION_STRING_LENGTH
] = {0};
114 static int scsi_log_sense(int fd
, uchar_t page_code
, uchar_t
*pagebuf
,
116 static int get_disk_temp(env_disk_t
*);
118 * ES Segment data structures
120 static sensor_ctrl_blk_t sensor_ctrl
[MAX_SENSORS
];
121 static fan_ctrl_blk_t fan_ctrl
[MAX_FANS
];
122 static fruenvseg_t
*envfru
= NULL
;
125 * Env thread variables
127 static boolean_t system_shutdown_started
= B_FALSE
;
128 static boolean_t ovtemp_thr1_created
= B_FALSE
;
129 static pthread_t ovtemp_thr1_id
;
130 static pthread_attr_t thr_attr
;
131 static boolean_t ovtemp_thr2_created
= B_FALSE
;
132 static pthread_t ovtemp_thr2_id
;
133 static boolean_t dimm_fan_thr_created
= B_FALSE
;
134 static pthread_t dimm_fan_thr_id
;
135 static boolean_t disk_temp_thr_created
= B_FALSE
;
136 static pthread_t disk_temp_thr_id
;
139 * PM thread related variables
141 static pthread_t pmthr_tid
; /* pmthr thread ID */
142 static int pm_fd
= -1; /* PM device file descriptor */
143 static boolean_t pmthr_created
= B_FALSE
;
144 static int cur_lpstate
; /* cur low power state */
147 * Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var
148 * Setting the verbose tuneable also enables debugging for better
156 static env_fan_t envd_sys_out_fan
= {
157 ENV_SYSTEM_OUT_FAN
, ENV_SYSTEM_OUT_FAN_DEVFS
, NULL
,
158 SYSTEM_OUT_FAN_ID
, SYSTEM_OUT_FAN_SPEED_MIN
, SYSTEM_OUT_FAN_SPEED_MAX
,
162 static env_fan_t envd_sys_in_fan
= {
163 ENV_SYSTEM_INTAKE_FAN
, ENV_SYSTEM_INTAKE_FAN_DEVFS
, NULL
,
164 SYSTEM_INTAKE_FAN_ID
, SYSTEM_INTAKE_FAN_SPEED_MIN
,
165 SYSTEM_INTAKE_FAN_SPEED_MAX
, -1, -1,
168 static env_fan_t envd_cpu0_fan
= {
169 ENV_CPU0_FAN
, ENV_CPU0_FAN_DEVFS
, NULL
,
170 CPU0_FAN_ID
, CPU_FAN_SPEED_MIN
, CPU_FAN_SPEED_MAX
, -1, -1,
173 static env_fan_t envd_cpu1_fan
= {
174 ENV_CPU1_FAN
, ENV_CPU1_FAN_DEVFS
, NULL
,
175 CPU1_FAN_ID
, CPU_FAN_SPEED_MIN
, CPU_FAN_SPEED_MAX
, -1, -1,
178 static env_fan_t envd_dimm_fan
= {
179 ENV_DIMM_FAN
, ENV_DIMM_FAN_DEVFS
, NULL
,
180 DIMM_FAN_ID
, 100, 100, -1, -1,
183 static env_disk_t envd_disk0
= {
184 ENV_DISK0
, ENV_DISK0_DEVFS
, DISK0_PHYSPATH
, DISK0_NODE_PATH
,
188 static env_disk_t envd_disk1
= {
189 ENV_DISK1
, ENV_DISK1_DEVFS
, DISK1_PHYSPATH
, DISK1_NODE_PATH
,
194 * The vendor-id and device-id are the properties associated with
195 * the SCSI controller. This is used to identify a particular controller
198 #define VENDOR_ID "vendor-id"
199 #define DEVICE_ID "device-id"
202 * The implementation for SCSI disk drives to supply info. about
203 * temperature is not mandatory. Hence we first determine if the
204 * temperature page is supported. To do this we need to scan the list
205 * of pages supported.
207 #define SUPPORTED_LPAGES 0
208 #define TEMPERATURE_PAGE 0x0D
209 #define LOGPAGEHDRSIZE 4
212 * NULL terminated array of fans
214 static env_fan_t
*envd_fans
[] = {
223 static env_disk_t
*envd_disks
[] = {
230 * ADM1031 speedrange map is indexed by a 2-bit value
232 static int adm_speedrange_map
[] = {1, 2, 4, 8};
237 static char *hwm_devs
[] = {
238 CPU_HWM_DEVFS
, /* CPU_HWM_ID */
239 SYS_HWM_DEVFS
/* SYS_HWM_ID */
243 * Fan names associated with each ADM1031 hwms - used to
244 * print fault messages.
246 static char *hwm_fans
[MAX_HWMS
][2] = {
247 {ENV_CPU0_FAN
, ENV_CPU1_FAN
},
248 {ENV_SYSTEM_INTAKE_FAN
, ENV_SYSTEM_OUT_FAN
}
252 * Temperature sensors
254 static env_sensor_t envd_sensors
[] = {
255 { SENSOR_CPU0_DIE
, SENSOR_CPU0_DIE_DEVFS
, NULL
,
256 CPU0_SENSOR_ID
, CPU_HWM_ID
, (void *)&envd_cpu0_fan
, -1},
257 { SENSOR_CPU1_DIE
, SENSOR_CPU1_DIE_DEVFS
, NULL
,
258 CPU1_SENSOR_ID
, CPU_HWM_ID
, (void *)&envd_cpu1_fan
, -1},
259 { SENSOR_INT_AMB_0
, SENSOR_INT_AMB_0_DEVFS
, NULL
,
260 INT_AMB0_SENSOR_ID
, CPU_HWM_ID
, NULL
, -1},
261 { SENSOR_SYS_OUT
, SENSOR_SYS_OUT_DEVFS
, NULL
,
262 SYS_OUT_SENSOR_ID
, SYS_HWM_ID
, (void *)&envd_sys_out_fan
, -1},
263 { SENSOR_INT_AMB_1
, SENSOR_INT_AMB_1_DEVFS
, NULL
,
264 INT_AMB1_SENSOR_ID
, SYS_HWM_ID
, NULL
, -1},
265 { SENSOR_SYS_IN
, SENSOR_SYS_IN_DEVFS
, NULL
,
266 SYS_IN_SENSOR_ID
, SYS_HWM_ID
, (void *)&envd_sys_in_fan
, -1},
268 #define N_ENVD_SENSORS (sizeof (envd_sensors)/sizeof (envd_sensors[0]))
270 #define NOT_AVAILABLE "NA"
275 #define TACH_UNKNOWN 255
276 #define FAN_OUT_OF_RANGE (TACH_UNKNOWN)
277 #define ADM_HYSTERISIS 5
278 #define N_SEQ_TACH 15
280 #define TMIN_MASK (0xF8)
281 #define TMIN_SHIFT (3)
282 #define TMIN_UNITS (4) /* increments of 4 degrees celsius */
283 #define TRANGE_MASK (0x7)
285 #define TMIN(regval) (((regval & TMIN_MASK) >> TMIN_SHIFT) * TMIN_UNITS)
286 #define TRANGE(regval) (regval & TRANGE_MASK)
288 #define GET_TMIN_RANGE(tmin, trange) \
289 ((((tmin / TMIN_UNITS) & TMIN_MASK) << TMIN_SHIFT) | \
290 (trange & TRANGE_MASK))
292 #define TACH_ENABLE_MASK (0x0C)
293 #define ADM_SETFANSPEED_CONV(speed) (15 * speed / 100)
301 int monitor_disk_temp
= 1; /* enabled */
302 static int disk_high_warn_temperature
= DISK_HIGH_WARN_TEMPERATURE
;
303 static int disk_low_warn_temperature
= DISK_LOW_WARN_TEMPERATURE
;
304 static int disk_high_shutdown_temperature
=
305 DISK_HIGH_SHUTDOWN_TEMPERATURE
;
306 static int disk_low_shutdown_temperature
= DISK_LOW_SHUTDOWN_TEMPERATURE
;
307 static int disk_scan_interval
= DISK_SCAN_INTERVAL
;
309 static int get_monitor_cpu_mode(ptree_rarg_t
*parg
, void *buf
);
310 static int set_monitor_cpu_mode(ptree_warg_t
*parg
, const void *buf
);
311 static int get_monitor_sys_mode(ptree_rarg_t
*parg
, void *buf
);
312 static int set_monitor_sys_mode(ptree_warg_t
*parg
, const void *buf
);
313 static int get_int_val(ptree_rarg_t
*parg
, void *buf
);
314 static int set_int_val(ptree_warg_t
*parg
, const void *buf
);
315 static int get_string_val(ptree_rarg_t
*parg
, void *buf
);
316 static int set_string_val(ptree_warg_t
*parg
, const void *buf
);
317 static int get_cpu_tach(ptree_rarg_t
*parg
, void *buf
);
318 static int set_cpu_tach(ptree_warg_t
*parg
, const void *buf
);
319 static int get_sys_tach(ptree_rarg_t
*parg
, void *buf
);
320 static int set_sys_tach(ptree_warg_t
*parg
, const void *buf
);
322 static int shutdown_override
= 0;
323 static int sensor_poll_interval
= SENSORPOLL_INTERVAL
;
324 static int warning_interval
= WARNING_INTERVAL
;
325 static int disk_warning_interval
= DISK_WARNING_INTERVAL
;
326 static int disk_warning_duration
= DISK_WARNING_DURATION
;
327 static int shutdown_interval
= SHUTDOWN_INTERVAL
;
328 static int disk_shutdown_interval
= DISK_SHUTDOWN_INTERVAL
;
329 static int ovtemp_monitor
= 1; /* enabled */
330 static int pm_monitor
= 1; /* enabled */
331 static int mon_fanstat
= 1; /* enabled */
337 static char shutdown_cmd
[] = SHUTDOWN_CMD
;
339 env_tuneable_t tuneables
[] = {
340 {"ovtemp-monitor", PICL_PTYPE_INT
, &ovtemp_monitor
,
341 &get_int_val
, &set_int_val
, sizeof (int)},
343 {"pm-monitor", PICL_PTYPE_INT
, &pm_monitor
,
344 &get_int_val
, &set_int_val
, sizeof (int)},
346 {"shutdown-override", PICL_PTYPE_INT
, &shutdown_override
,
347 &get_int_val
, &set_int_val
, sizeof (int)},
349 {"cpu-hm-automode-enable", PICL_PTYPE_INT
, &cpu_mode
,
350 &get_monitor_cpu_mode
, &set_monitor_cpu_mode
,
353 {"sys-hm-automode-enable", PICL_PTYPE_INT
, &sys_mode
,
354 &get_monitor_sys_mode
, &set_monitor_sys_mode
,
357 {"sensor-poll-interval", PICL_PTYPE_INT
,
358 &sensor_poll_interval
,
359 &get_int_val
, &set_int_val
,
362 {"disk-scan-interval", PICL_PTYPE_INT
,
364 &get_int_val
, &set_int_val
,
367 {"warning-interval", PICL_PTYPE_INT
, &warning_interval
,
368 &get_int_val
, &set_int_val
,
371 {"shutdown-interval", PICL_PTYPE_INT
, &shutdown_interval
,
372 &get_int_val
, &set_int_val
,
375 {"disk_warning-interval", PICL_PTYPE_INT
, &disk_warning_interval
,
376 &get_int_val
, &set_int_val
,
379 {"disk_warning-duration", PICL_PTYPE_INT
, &disk_warning_duration
,
380 &get_int_val
, &set_int_val
,
383 {"disk_shutdown-interval", PICL_PTYPE_INT
, &disk_shutdown_interval
,
384 &get_int_val
, &set_int_val
,
387 {"shutdown-command", PICL_PTYPE_CHARSTRING
, shutdown_cmd
,
388 &get_string_val
, &set_string_val
,
389 sizeof (shutdown_cmd
)},
391 {"cpu-tach-enable", PICL_PTYPE_INT
, &cpu_tach
,
392 &get_cpu_tach
, &set_cpu_tach
,
395 {"sys-tach-enable", PICL_PTYPE_INT
, &sys_tach
,
396 &get_sys_tach
, &set_sys_tach
,
399 {"monitor-fanstat", PICL_PTYPE_INT
, &mon_fanstat
,
400 &get_int_val
, &set_int_val
, sizeof (int)},
402 {"monitor-disk-temp", PICL_PTYPE_INT
, &monitor_disk_temp
,
403 &get_int_val
, &set_int_val
, sizeof (int)},
405 {"disk-high-warn-temperature", PICL_PTYPE_INT
,
406 &disk_high_warn_temperature
, &get_int_val
,
407 &set_int_val
, sizeof (int)},
409 {"disk-low-warn-temperature", PICL_PTYPE_INT
,
410 &disk_low_warn_temperature
, &get_int_val
,
411 &set_int_val
, sizeof (int)},
413 {"disk-high-shutdown-temperature", PICL_PTYPE_INT
,
414 &disk_high_shutdown_temperature
, &get_int_val
,
415 &set_int_val
, sizeof (int)},
417 {"disk-low-shutdown-temperature", PICL_PTYPE_INT
,
418 &disk_low_shutdown_temperature
, &get_int_val
,
419 &set_int_val
, sizeof (int)},
421 {"verbose", PICL_PTYPE_INT
, &env_debug
,
422 &get_int_val
, &set_int_val
, sizeof (int)},
428 * We use this to figure out how many tuneables there are
429 * This is variable because the publishing routine needs this info
432 int ntuneables
= (sizeof (tuneables
)/sizeof (tuneables
[0]));
435 * Table Handling Code
438 fini_table(table_t
*tblp
)
447 init_table(int npoints
)
455 if ((tblp
= malloc(sizeof (*tblp
))) == NULL
)
458 if ((xy
= malloc(sizeof (*xy
) * npoints
)) == NULL
) {
463 tblp
->nentries
= npoints
;
470 * function: calculates y for a given x based on a table of points
471 * for monotonically increasing x values.
472 * 'tbl' specifies the table to use, 'val' specifies the 'x', returns 'y'
475 y_of_x(table_t
*tbl
, int xval
)
483 entries
= tbl
->nentries
;
486 * If the temperature is outside the correction table
487 * then simply return the original value.
489 if ((xval
< xymap
[0].x
) || (xval
> xymap
[entries
- 1].x
))
491 if (xval
== xymap
[0].x
)
493 if (xval
== xymap
[entries
- 1].x
)
494 return (xymap
[entries
- 1].y
);
496 for (i
= 1; i
< entries
- 1; i
++) {
497 if (xval
== xymap
[i
].x
)
499 if (xval
< xymap
[i
].x
)
504 * Use linear interpolation
506 dy
= (float)(xymap
[i
].y
- xymap
[i
-1].y
);
507 dx
= (float)(xymap
[i
].x
- xymap
[i
-1].x
);
509 newval
= xymap
[i
- 1].y
+ slope
* (xval
- xymap
[i
- 1].x
);
510 return ((int)(newval
+ (newval
>= 0 ? 0.5 : -0.5)));
514 * Get environmental segment from the specified FRU SEEPROM
517 get_envseg(int fd
, void **envsegp
, int *envseglenp
)
519 int i
, segcnt
, envseglen
;
520 section_layout_t section
;
521 segment_layout_t segment
;
524 if (lseek(fd
, (long)SECTION_HDR_OFFSET
, 0) == -1L ||
525 read(fd
, §ion
, sizeof (section
)) != sizeof (section
)) {
530 * Verify we have the correct section and contents are valid
531 * For now, we don't verify the CRC.
533 if (section
.header_tag
!= SECTION_HDR_TAG
||
534 GET_UNALIGN16(§ion
.header_version
[0]) != SECTION_HDR_VER
) {
537 "Invalid section header tag:%x version:%x\n",
539 GET_UNALIGN16(§ion
.header_version
));
544 * Locate our environmental segment
546 segcnt
= section
.segment_count
;
547 for (i
= 0; i
< segcnt
; i
++) {
548 if (read(fd
, &segment
, sizeof (segment
)) != sizeof (segment
)) {
553 "Seg name: %x desc:%x off:%x len:%x\n",
554 GET_UNALIGN16(&segment
.name
),
555 GET_UNALIGN32(&segment
.descriptor
[0]),
556 GET_UNALIGN16(&segment
.offset
),
557 GET_UNALIGN16(&segment
.length
));
558 if (GET_UNALIGN16(&segment
.name
) == ENVSEG_NAME
)
567 * Allocate memory to hold the environmental segment data.
569 envseglen
= GET_UNALIGN16(&segment
.length
);
570 if ((envseg
= malloc(envseglen
)) == NULL
) {
574 if (lseek(fd
, (long)GET_UNALIGN16(&segment
.offset
), 0) == -1L ||
575 read(fd
, envseg
, envseglen
) != envseglen
) {
580 *envseglenp
= envseglen
;
585 * Get all environmental segments
586 * Return NULL on error
589 get_fru_envsegs(void)
591 fruenvseg_t
*fruenvsegs
;
592 envseg_layout_t
*envsegp
;
594 int fd
, envseglen
, hdrlen
;
598 fruenvsegs
= malloc(sizeof (*fruenvsegs
));
599 if (fruenvsegs
== NULL
) {
604 * Now get the environmental segment from this FRU
606 (void) snprintf(path
, sizeof (path
), "%s%s", I2C_DEVFS
, MBFRU_DEV
);
607 fd
= open(path
, O_RDONLY
);
609 envd_log(LOG_ERR
, ENV_FRU_OPEN_FAIL
, errno
, path
);
615 * Read environmental segment from this FRU SEEPROM
617 if (get_envseg(fd
, &envsegbufp
, &envseglen
) != 0) {
618 envd_log(LOG_ERR
, ENV_FRU_BAD_ENVSEG
, path
);
625 * Validate envseg version number and header length
627 envsegp
= (envseg_layout_t
*)envsegbufp
;
628 hdrlen
= sizeof (envseg_layout_t
) -
629 sizeof (envseg_sensor_t
) +
630 (envsegp
->sensor_count
) * sizeof (envseg_sensor_t
);
632 if (envsegp
->version
!= ENVSEG_VERSION
||
633 envseglen
< hdrlen
) {
635 * version mismatch or header not big enough
637 envd_log(LOG_CRIT
, ENV_FRU_BAD_ENVSEG
, FRU_SEEPROM_NAME
);
638 if (envsegbufp
!= NULL
)
639 (void) free(envsegbufp
);
645 fruenvsegs
->envseglen
= envseglen
;
646 fruenvsegs
->envsegbufp
= envsegbufp
;
652 process_fru_seeprom(unsigned char *buff
)
660 env_sensor_t
*snodep
;
662 #define NSENSOR_OFFSET 1
663 #define ID_OFF_SIZE 6
664 #define NFANS_OFFSET(x) ((x * ID_OFF_SIZE) + 2)
666 nsensors
= (int)buff
[NSENSOR_OFFSET
];
667 if (nsensors
!= MAX_SENSORS
) {
668 envd_log(LOG_CRIT
, ENV_FRU_BAD_ENVSEG
, FRU_SEEPROM_NAME
);
672 nfans
= (int)buff
[NFANS_OFFSET(nsensors
)];
673 if (nfans
!= MAX_FANS
) {
674 envd_log(LOG_CRIT
, ENV_FRU_BAD_ENVSEG
, FRU_SEEPROM_NAME
);
678 while (nsensors
> 0) {
679 (void) memcpy((char *)&id
,
680 (char *)&buff
[id_offset
+ 2],
684 envd_log(LOG_ERR
, "\n Sensor Id %x offset %x",
687 if (id
.id
> MAX_SENSOR_ID
) {
688 envd_log(LOG_CRIT
, ENV_FRU_BAD_ENVSEG
,
694 * Copy into the sensor control block array according to the
697 (void) memcpy((char *)&sensor_ctrl
[id
.id
],
698 (char *)&buff
[id
.offset
],
699 sizeof (sensor_ctrl_blk_t
));
701 id_offset
+= ID_OFF_SIZE
;
705 * Skip past no of Fan entry(single byte)
709 (void) memcpy((char *)&id
, (char *)&buff
[id_offset
+ 2],
713 envd_log(LOG_ERR
, "\n Fan Id %x offset %x", id
.id
,
717 envd_log(LOG_CRIT
, ENV_FRU_BAD_ENVSEG
,
722 (void) memcpy((char *)&fan_ctrl
[id
.id
],
723 (char *)&buff
[id
.offset
], sizeof (fan_ctrl_blk_t
));
726 id_offset
+= ID_OFF_SIZE
;
730 * Match Sensor/ES ID and point correct data
733 for (i
= 0; i
< N_ENVD_SENSORS
; i
++) {
734 snodep
= &envd_sensors
[i
];
735 snodep
->es_ptr
= &sensor_ctrl
[snodep
->id
];
739 * Match Fan/ES ID and point to correct ES Data
742 for (i
= 0; (fnodep
= envd_fans
[i
]) != NULL
; i
++)
743 fnodep
->es_ptr
= &fan_ctrl
[fnodep
->id
];
751 envfru
= get_fru_envsegs();
752 if (envfru
== NULL
) {
753 envd_log(LOG_CRIT
, ENV_FRU_BAD_ENVSEG
, FRU_SEEPROM_NAME
);
756 return (process_fru_seeprom((uchar_t
*)envfru
->envsegbufp
));
760 envd_es_destroy(void)
763 free(envfru
->envsegbufp
);
767 * Lookup fan and return a pointer to env_fan_t data structure.
770 fan_lookup(char *name
)
775 for (i
= 0; (fanp
= envd_fans
[i
]) != NULL
; i
++) {
776 if (strcmp(fanp
->name
, name
) == 0)
783 * Lookup sensor and return a pointer to env_sensor_t data structure.
786 sensor_lookup(char *name
)
788 env_sensor_t
*sensorp
;
791 for (i
= 0; i
< N_ENVD_SENSORS
; ++i
) {
792 sensorp
= &envd_sensors
[i
];
793 if (strcmp(sensorp
->name
, name
) == 0)
800 * Lookup disk and return a pointer to env_disk_t data structure.
803 disk_lookup(char *name
)
808 for (i
= 0; (diskp
= envd_disks
[i
]) != NULL
; i
++) {
809 if (strncmp(diskp
->name
, name
, strlen(name
)) == 0)
816 * Get current temperature
817 * Returns -1 on error, 0 if successful
820 get_temperature(env_sensor_t
*sensorp
, tempr_t
*temp
)
822 int fd
= sensorp
->fd
;
827 else if (ioctl(fd
, I2C_GET_TEMPERATURE
, temp
) == -1) {
831 if (sensorp
->error
== 0) {
833 envd_log(LOG_WARNING
, ENV_SENSOR_ACCESS_FAIL
,
834 sensorp
->name
, errno
, strerror(errno
));
836 } else if (sensorp
->error
!= 0) {
838 envd_log(LOG_WARNING
, ENV_SENSOR_ACCESS_OK
, sensorp
->name
);
840 if (sensorp
->crtbl
!= NULL
) {
841 *temp
= (tempr_t
)y_of_x(sensorp
->crtbl
, *temp
);
848 * Get current disk temperature
849 * Returns -1 on error, 0 if successful
852 disk_temperature(env_disk_t
*diskp
, tempr_t
*temp
)
859 *temp
= diskp
->current_temp
;
865 * Get uncorrected current temperature
866 * Returns -1 on error, 0 if successful
869 get_raw_temperature(env_sensor_t
*sensorp
, tempr_t
*temp
)
871 int fd
= sensorp
->fd
;
876 else if (ioctl(fd
, I2C_GET_TEMPERATURE
, temp
) == -1) {
884 * Return Fan RPM given N & tach
885 * count and N are retrived from the
889 tach_to_rpm(int n
, uint8_t tach
)
893 return ((ADCSAMPLE
* 60) / (n
* tach
));
897 get_raw_fan_speed(env_fan_t
*fanp
, uint8_t *fanspeedp
)
906 else if (ioctl(fan_fd
, I2C_GET_FAN_SPEED
, fanspeedp
) == -1) {
915 * Get current fan speed
916 * This function returns a RPM value for fanspeed
918 * Returns -1 on error, 0 if successful
921 get_fan_speed(env_fan_t
*fanp
, fanspeed_t
*fanspeedp
)
930 if (fanp
->id
== DIMM_FAN_ID
) {
931 return (get_dimm_fan_speed(fan_fd
, fanspeedp
));
933 if (ioctl(fan_fd
, I2C_GET_FAN_SPEED
, &tach
) == -1) {
938 * Fanspeeds are reported as 0
939 * if the tach is out of range or fan status is off
940 * and if monitoring fan status is enabled.
942 if (mon_fanstat
&& (!fanp
->fanstat
|| tach
== FAN_OUT_OF_RANGE
)) {
946 tach_to_rpm(fanp
->speedrange
, tach
);
954 * This function accepts a percentage of fan speed
955 * from 0-100 and programs the HW monitor fans to the corresponding
957 * Returns -1 on error, -2 on invalid args passed, 0 if successful
960 set_fan_speed(env_fan_t
*fanp
, fanspeed_t fanspeed
)
970 if (fanspeed
< 0 || fanspeed
> 100)
973 speed
= (uint8_t)ADM_SETFANSPEED_CONV(fanspeed
);
975 if (ioctl(fan_fd
, I2C_SET_FAN_SPEED
, &speed
) == -1) {
982 * close all fan devices
985 envd_close_fans(void)
990 for (i
= 0; (fanp
= envd_fans
[i
]) != NULL
; i
++) {
991 if (fanp
->fd
!= -1) {
992 (void) close(fanp
->fd
);
999 * Close sensor devices and freeup resources
1002 envd_close_sensors(void)
1004 env_sensor_t
*sensorp
;
1007 for (i
= 0; i
< N_ENVD_SENSORS
; ++i
) {
1008 sensorp
= &envd_sensors
[i
];
1009 if (sensorp
->fd
!= -1) {
1010 (void) close(sensorp
->fd
);
1013 if (sensorp
->crtbl
!= NULL
)
1014 fini_table(sensorp
->crtbl
);
1019 * Open fan devices and initialize per fan data structure.
1020 * Returns #fans found.
1023 envd_setup_fans(void)
1027 char path
[PATH_MAX
];
1030 picl_nodehdl_t tnodeh
;
1033 for (i
= 0; (fanp
= envd_fans
[i
]) != NULL
; i
++) {
1034 /* make sure cpu0/1 present for validating cpu fans */
1035 if (fanp
->id
== CPU0_FAN_ID
) {
1036 if (ptree_get_node_by_path(CPU0_PATH
, &tnodeh
) !=
1038 fanp
->present
= B_FALSE
;
1042 if (fanp
->id
== CPU1_FAN_ID
) {
1043 if (ptree_get_node_by_path(CPU1_PATH
, &tnodeh
) !=
1045 fanp
->present
= B_FALSE
;
1049 if (fanp
->id
== DIMM_FAN_ID
) {
1050 if (ptree_get_node_by_path(DIMM_FAN_CONTROLLER_PATH
,
1051 &tnodeh
) != PICL_SUCCESS
) {
1054 "dimm Fan not found in the system.\n");
1055 fanp
->present
= B_FALSE
;
1059 (void) strcpy(path
, "/devices");
1060 (void) strlcat(path
, fanp
->devfs_path
, sizeof (path
));
1061 fd
= open(path
, O_RDWR
);
1064 ENV_FAN_OPEN_FAIL
, fanp
->name
,
1065 fanp
->devfs_path
, errno
, strerror(errno
));
1066 fanp
->present
= B_FALSE
;
1070 if (fanp
->id
== DIMM_FAN_ID
) {
1072 * set the SW aware bit in command register.
1073 * Clear the Fan fault latch bit.
1075 i2c_reg
.reg_num
= PIC16F819_COMMAND_REGISTER
;
1076 i2c_reg
.reg_value
= (PIC16F819_SW_AWARE_MODE
|
1077 PIC16F819_FAN_FAULT_CLEAR
);
1078 if (ioctl(fd
, I2C_SET_REG
, &i2c_reg
) == -1) {
1081 "Error in writing to COMMAND reg. of DIMM FAN controller\n");
1084 /* Get speed range value */
1085 if (ioctl(fd
, ADM1031_GET_FAN_FEATURE
, &n
) != -1) {
1087 adm_speedrange_map
[(n
>> 6) & 0x03];
1089 fanp
->speedrange
= FAN_RANGE_DEFAULT
;
1092 fanp
->present
= B_TRUE
;
1094 fanp
->cspeed
= TACH_UNKNOWN
;
1095 fanp
->lspeed
= TACH_UNKNOWN
;
1103 envd_setup_disks(void)
1105 int ret
, i
, page_index
, page_len
;
1106 picl_nodehdl_t tnodeh
;
1110 uchar_t log_page
[256];
1113 * Check if the SCSi controller on the system is 1010 or 1030
1116 if (ptree_get_node_by_path(SCSI_CONTROLLER_NODE_PATH
,
1117 &tnodeh
) != PICL_SUCCESS
) {
1120 "On-Board SCSI controller not found in the system.\n");
1121 monitor_disk_temp
= 0;
1125 if ((ret
= ptree_get_propval_by_name(tnodeh
, VENDOR_ID
,
1127 sizeof (vendor_id
))) != 0) {
1130 "Error in getting vendor-id for SCSI controller. ret = %d errno = 0x%d\n",
1132 monitor_disk_temp
= 0;
1135 if ((ret
= ptree_get_propval_by_name(tnodeh
, DEVICE_ID
,
1137 sizeof (device_id
))) != 0) {
1140 "Error in getting device-id for SCSI controller. ret = %d errno = 0x%d\n",
1142 monitor_disk_temp
= 0;
1146 envd_log(LOG_ERR
, "vendor-id=0x%x device-id=0x%x\n",
1147 vendor_id
, device_id
);
1148 if ((vendor_id
!= LSI1030_VENDOR_ID
) ||
1149 (device_id
!= LSI1030_DEVICE_ID
)) {
1150 monitor_disk_temp
= 0;
1154 * We have found LSI1030 SCSi controller onboard.
1157 for (i
= 0; (diskp
= envd_disks
[i
]) != NULL
; i
++) {
1159 if (ptree_get_node_by_path(diskp
->nodepath
,
1160 &tnodeh
) != PICL_SUCCESS
) {
1161 diskp
->present
= B_FALSE
;
1164 "DISK %d not found in the system.\n",
1168 diskp
->fd
= open(diskp
->devfs_path
, O_RDONLY
);
1169 if (diskp
->fd
== -1) {
1170 diskp
->present
= B_FALSE
;
1172 "Error in opening %s errno = 0x%x\n",
1173 diskp
->devfs_path
, errno
);
1176 diskp
->present
= B_TRUE
;
1177 diskp
->tpage_supported
= B_FALSE
;
1179 * Find out if the Temperature page is supported by the disk.
1181 ret
= scsi_log_sense(diskp
->fd
, SUPPORTED_LPAGES
,
1182 log_page
, sizeof (log_page
));
1186 page_len
= ((log_page
[2] << 8) & 0xFF00) | log_page
[3];
1188 for (page_index
= LOGPAGEHDRSIZE
;
1189 page_index
< page_len
+ LOGPAGEHDRSIZE
; page_index
++) {
1190 switch (log_page
[page_index
]) {
1191 case TEMPERATURE_PAGE
:
1192 diskp
->tpage_supported
= B_TRUE
;
1195 "tpage supported for %s\n",
1201 diskp
->warning_tstamp
= 0;
1202 diskp
->shutdown_tstamp
= 0;
1203 diskp
->high_warning
= disk_high_warn_temperature
;
1204 diskp
->low_warning
= disk_low_warn_temperature
;
1205 diskp
->high_shutdown
= disk_high_shutdown_temperature
;
1206 diskp
->low_shutdown
= disk_low_shutdown_temperature
;
1207 ret
= get_disk_temp(diskp
);
1213 * Open temperature sensor devices and initialize per sensor data structure.
1214 * Returns #sensors found.
1217 envd_setup_sensors(void)
1219 env_sensor_t
*sensorp
;
1220 sensor_ctrl_blk_t
*es_ptr
;
1222 char path
[PATH_MAX
];
1226 picl_nodehdl_t tnodeh
;
1228 for (i
= 0; i
< N_ENVD_SENSORS
; ++i
) {
1229 sensorp
= &envd_sensors
[i
];
1230 /* Initialize sensor's initial state */
1231 sensorp
->shutdown_initiated
= B_FALSE
;
1232 sensorp
->warning_tstamp
= 0;
1233 sensorp
->shutdown_tstamp
= 0;
1235 sensorp
->crtbl
= NULL
;
1236 /* make sure cpu0/1 sensors are present */
1237 if (sensorp
->id
== CPU0_SENSOR_ID
) {
1238 if (ptree_get_node_by_path(CPU0_PATH
, &tnodeh
) !=
1240 sensorp
->present
= B_FALSE
;
1244 if (sensorp
->id
== CPU1_SENSOR_ID
) {
1245 if (ptree_get_node_by_path(CPU1_PATH
, &tnodeh
) !=
1247 sensorp
->present
= B_FALSE
;
1251 (void) strcpy(path
, "/devices");
1252 (void) strlcat(path
, sensorp
->devfs_path
,
1254 sensorp
->fd
= open(path
, O_RDWR
);
1255 if (sensorp
->fd
== -1) {
1256 envd_log(LOG_ERR
, ENV_SENSOR_OPEN_FAIL
,
1257 sensorp
->name
, sensorp
->devfs_path
,
1258 errno
, strerror(errno
));
1259 sensorp
->present
= B_FALSE
;
1262 sensorp
->present
= B_TRUE
;
1269 if (ioctl(sensorp
->fd
, ADM1031_GET_TEMP_MIN_RANGE
,
1271 sensorp
->tmin
= TMIN(tmin
);
1276 envd_log(LOG_ERR
, "Sensor %s tmin %d",
1277 sensorp
->name
, sensorp
->tmin
);
1280 * Create a correction table
1281 * if correction pairs are present in es
1284 es_ptr
= sensorp
->es_ptr
;
1286 if (es_ptr
== NULL
) {
1289 nentries
= es_ptr
->correctionEntries
;
1291 if (nentries
<= 2) {
1293 envd_log(LOG_CRIT
, "sensor correction <2");
1297 sensorp
->crtbl
= init_table(nentries
);
1298 if (sensorp
->crtbl
== NULL
)
1300 tblp
= sensorp
->crtbl
;
1302 (char)es_ptr
->correctionPair
[0].measured
;
1304 (char)es_ptr
->correctionPair
[0].corrected
;
1306 for (j
= 1; j
< nentries
; ++j
) {
1308 (char)es_ptr
->correctionPair
[j
].measured
;
1310 (char)es_ptr
->correctionPair
[j
].corrected
;
1312 if (tblp
->xymap
[j
].x
<= tblp
->xymap
[j
- 1].x
) {
1314 sensorp
->crtbl
= NULL
;
1315 envd_log(LOG_CRIT
, ENV_FRU_BAD_ENVSEG
,
1322 envd_log(LOG_CRIT
, "Sensor correction %s",
1324 for (j
= 0; j
< nentries
; j
++)
1325 envd_log(LOG_CRIT
, " %d %d",
1326 tblp
->xymap
[j
].x
, tblp
->xymap
[j
].y
);
1333 * Modify ADM Tmin/ranges depending what power level
1337 updateadm_ranges(char *name
, uchar_t cur_lpstate
)
1339 env_sensor_t
*sensorp
;
1340 fan_ctrl_blk_t
*fanctl
;
1345 uchar_t sys_id
= SYS_HWM_ID
;
1347 static uint16_t tsave
[2] = {0, 0};
1348 /* Index of saved Tmin/Trange for two sensors */
1349 uint16_t tindex
= 0;
1351 sensorp
= sensor_lookup(name
);
1352 if (sensorp
== NULL
)
1356 * If there is only one Control pairs then return
1358 fanctl
= ((env_fan_t
*)sensorp
->fanp
)->es_ptr
;
1360 if (fanctl
!= NULL
&& fanctl
->no_ctl_pairs
<= 1)
1364 * if fan control specifies that ranges are same then
1365 * we skip re-programming adm chip.
1368 tmin
= fanctl
->fan_ctl_pairs
[0].tMin
;
1369 trange
= fanctl
->fan_ctl_pairs
[0].tRange
;
1370 if ((tmin
== fanctl
->fan_ctl_pairs
[1].tMin
) &&
1371 (trange
== fanctl
->fan_ctl_pairs
[1].tRange
))
1374 sysfd
= open(hwm_devs
[sys_id
], O_RDWR
);
1377 envd_log(LOG_ERR
, ENV_ADM_OPEN_FAIL
, hwm_devs
[sys_id
],
1378 errno
, strerror(errno
));
1381 tindex
= ((strcmp(name
, SENSOR_SYS_IN
) == 0) ? 0 : 1);
1383 /* Read ADM default value only for the first time */
1384 if (tsave
[tindex
] == 0) {
1385 if (ioctl(sensorp
->fd
, ADM1031_GET_TEMP_MIN_RANGE
,
1386 &tsave
[tindex
]) == -1) {
1389 "read tminrange ioctl failed");
1390 (void) close(sysfd
);
1395 * Need to reinit ADM to manual mode for Tmin range to be
1398 mode
= ADM1031_MANUAL_MODE
;
1399 if (ioctl(sysfd
, ADM1031_SET_MONITOR_MODE
, &mode
) == -1) {
1401 envd_log(LOG_ERR
, ENV_ADM_MANUAL_MODE
);
1402 (void) close(sysfd
);
1406 if (cur_lpstate
== 1) {
1408 * ADM 1031 Tmin/Trange register need to be reprogrammed.
1410 tdata
= ((fanctl
->fan_ctl_pairs
[cur_lpstate
].tMin
/ TMIN_UNITS
)
1412 /* Need to pack tRange in ADM bits 2:0 */
1413 switch (fanctl
->fan_ctl_pairs
[cur_lpstate
].tRange
) {
1434 tdata
= tsave
[tindex
];
1436 if (ioctl(sensorp
->fd
, ADM1031_SET_TEMP_MIN_RANGE
,
1438 sensorp
->tmin
= TMIN(tdata
);
1440 mode
= ADM1031_AUTO_MODE
;
1441 if (ioctl(sysfd
, ADM1031_SET_MONITOR_MODE
, &mode
) == -1) {
1443 envd_log(LOG_ERR
, ENV_ADM_AUTO_MODE
);
1445 (void) close(sysfd
);
1452 pm_state_change_t pmstate
;
1453 char physpath
[PATH_MAX
];
1456 pmstate
.physpath
= physpath
;
1457 pmstate
.size
= sizeof (physpath
);
1461 pm_fd
= open(PM_DEVICE
, O_RDWR
);
1463 envd_log(LOG_ERR
, PM_THREAD_EXITING
, errno
, strerror(errno
));
1468 * Get PM state change events to check if the system
1469 * is in lowest power state and adjust ADM hardware
1470 * monitor's fan speed settings.
1472 * To minimize polling, we use the blocking interface
1473 * to get the power state change event here.
1475 if (ioctl(pm_fd
, PM_GET_STATE_CHANGE_WAIT
, &pmstate
) != 0) {
1483 "pmstate event:0x%x flags:%x"
1484 "comp:%d oldval:%d newval:%d path:%s\n",
1485 pmstate
.event
, pmstate
.flags
,
1492 (pmstate
.flags
& PSC_ALL_LOWEST
) ? 1 : 0;
1493 } while (ioctl(pm_fd
, PM_GET_STATE_CHANGE
, &pmstate
) == 0);
1495 * Change ADM ranges as per E* Requirements. Update
1496 * happens only for valid state changes.
1498 if (pre_lpstate
!= cur_lpstate
) {
1499 pre_lpstate
= cur_lpstate
;
1500 updateadm_ranges(SENSOR_SYS_OUT
, cur_lpstate
);
1501 updateadm_ranges(SENSOR_SYS_IN
, cur_lpstate
);
1509 * This function is used to reasonably predict the
1510 * state of the fan (ON/OFF) using tmin and current temperature.
1512 * We know the fan is on if temp >= tmin and fan is off if
1513 * temp < (Tmin - Hysterisis).
1515 * When the temperature is in between we don't know if the fan is on/off
1516 * because the temperature could be decreasing and not have crossed
1517 * Tmin - hysterisis and vice a versa.
1521 * -------------------------------------------
1525 * --------------------------------------------
1529 * To solve the problem of finding out if the fan is on/off in our gray region
1530 * we keep track of the last read tach and the current read tach. From
1531 * experimentation and from discussions with analog devices it is unlikely that
1532 * if the fans are on we will get a constant tach reading more than 5 times in
1533 * a row. This is not but the most fool proof approach but the best we can do.
1535 * This routine implements the above logic for a sensor with an
1536 * associated fan. The caller garauntees sensorp and fanp are not null.
1540 check_fanstat(env_sensor_t
*sensorp
)
1542 env_fan_t
*fanp
= sensorp
->fanp
;
1546 if (get_raw_temperature(sensorp
, &temp
) == -1)
1549 if (temp
< (sensorp
->tmin
- ADM_HYSTERISIS
)) {
1551 fanp
->fanstat
= 0; /* Fan off */
1552 fanp
->lspeed
= TACH_UNKNOWN
; /* Reset Last read tach */
1555 } else if (temp
>= sensorp
->tmin
) {
1557 fanp
->fanstat
= 1; /* Fan on */
1558 fanp
->lspeed
= TACH_UNKNOWN
;
1562 if (get_raw_fan_speed(fanp
, &fanspeed
) == -1)
1565 fanp
->cspeed
= fanspeed
;
1567 * First time in the gray area
1568 * set last read speed to current speed
1570 if (fanp
->lspeed
== TACH_UNKNOWN
) {
1571 fanp
->lspeed
= fanspeed
;
1573 if (fanp
->lspeed
!= fanp
->cspeed
) {
1579 if (fanp
->conccnt
>= N_SEQ_TACH
)
1582 fanp
->lspeed
= fanp
->cspeed
;
1587 * There is an issue with the ADM1031 chip that causes the chip
1588 * to not update the tach register in case the fan stops. The
1589 * fans stop when the temperature measured (temp) drops below
1590 * Tmin - Hysterisis and turn on when the temp >= Tmin.
1592 * Since the tach registers don't update and remain stuck at the
1593 * last read tach value our get_fan_speed function always returns
1594 * a non-zero RPM reading.
1596 * To fix this we need to figure out when the fans will be on/off
1597 * depending on the current temperature. Currently we poll for
1598 * interrupts, we can use that loop to determine what the current
1599 * temperature is and if the fans should be on/off.
1601 * We get current temperature and check the fans.
1604 monitor_fanstat(void)
1606 env_sensor_t
*sensorp
;
1610 for (i
= 0; i
< N_ENVD_SENSORS
; i
++) {
1611 sensorp
= &envd_sensors
[i
];
1616 fanp
= sensorp
->fanp
;
1618 if (!(fanp
&& fanp
->present
))
1621 if (sensorp
->tmin
!= -1) {
1622 check_fanstat(sensorp
);
1631 handle_overtemp_interrupt(int hwm_id
)
1633 env_sensor_t
*sensorp
;
1635 uchar_t smap
[MAX_SENSORS
];
1638 char msgbuf
[BUFSIZ
];
1639 char syscmd
[BUFSIZ
];
1640 boolean_t return_flag
;
1643 pthread_mutex_t env_monitor_mutex
= PTHREAD_MUTEX_INITIALIZER
;
1644 pthread_cond_t env_monitor_cv
= PTHREAD_COND_INITIALIZER
;
1646 /* Clear Map of Sensor Entries */
1647 (void) memset(smap
, SENSOR_OK
, sizeof (smap
));
1650 for (i
= 0; i
< N_ENVD_SENSORS
; i
++) {
1651 sensorp
= &envd_sensors
[i
];
1654 * Check whether the sensor belongs to the
1655 * interrupting ADM hardware monitor
1657 if (sensorp
->hwm_id
!= hwm_id
)
1660 if (sensorp
->present
== B_FALSE
)
1663 * if shutdown is initiated then we simply loop
1664 * through the sensors until shutdown
1666 if (sensorp
->shutdown_initiated
== B_TRUE
)
1669 /* get current temp for this sensor */
1670 if (get_temperature(sensorp
, &temp
) == -1)
1673 sensorp
->cur_temp
= temp
;
1677 "sensor name %s, cur temp %d, "
1678 "HW %d LW %d SD %d LS %d\n",
1679 sensorp
->name
, temp
,
1680 sensorp
->es_ptr
->high_warning
,
1681 (int)sensorp
->es_ptr
->low_warning
,
1682 sensorp
->es_ptr
->high_shutdown
,
1683 (int)sensorp
->es_ptr
->low_shutdown
);
1685 if (TEMP_IN_WARNING_RANGE(sensorp
->cur_temp
, sensorp
)) {
1687 * Log on warning atmost one second
1689 ct
= (time_t)(gethrtime() / NANOSEC
);
1690 if ((ct
- sensorp
->warning_tstamp
) >=
1693 ENV_WARNING_MSG
, sensorp
->name
,
1695 sensorp
->es_ptr
->low_warning
,
1696 sensorp
->es_ptr
->high_warning
);
1697 sensorp
->warning_tstamp
= ct
;
1699 smap
[i
] = SENSOR_WARN
;
1702 * We will fall in this caterory only if
1703 * Temperature drops/increases from warning
1704 * threshold. If so we set sensor map to
1705 * OK so that we can exit the loop if
1706 * shutdown not initiated.
1708 smap
[i
] = SENSOR_OK
;
1711 if (TEMP_IN_SHUTDOWN_RANGE(temp
, sensorp
) &&
1712 !shutdown_override
) {
1713 ct
= (time_t)(gethrtime() / NANOSEC
);
1714 if (sensorp
->shutdown_tstamp
== 0)
1715 sensorp
->shutdown_tstamp
= ct
;
1716 if ((ct
- sensorp
->shutdown_tstamp
) >=
1717 shutdown_interval
) {
1718 sensorp
->shutdown_initiated
= B_TRUE
;
1719 (void) snprintf(msgbuf
, sizeof (msgbuf
),
1720 ENV_SHUTDOWN_MSG
, sensorp
->name
,
1722 sensorp
->es_ptr
->low_shutdown
,
1723 sensorp
->es_ptr
->high_shutdown
);
1724 envd_log(LOG_ALERT
, msgbuf
);
1726 if (system_shutdown_started
== B_FALSE
) {
1727 (void) snprintf(syscmd
, sizeof (syscmd
),
1728 "%s \"%s\"", SHUTDOWN_CMD
, msgbuf
);
1729 envd_log(LOG_ALERT
, syscmd
);
1730 system_shutdown_started
= B_TRUE
;
1731 (void) system(syscmd
);
1733 } else if (sensorp
->shutdown_tstamp
!= 0)
1734 sensorp
->shutdown_tstamp
= 0;
1738 * Sweep thorugh Sensor Map and if warnings OR shutdown
1739 * are not logged then return to caller.
1741 return_flag
= B_TRUE
;
1742 for (i
= 0; i
< N_ENVD_SENSORS
; i
++)
1743 if (smap
[i
] == SENSOR_WARN
)
1744 return_flag
= B_FALSE
;
1746 if ((return_flag
== B_TRUE
) &&
1747 (system_shutdown_started
== B_FALSE
)) {
1753 * We use pthread_cond_reltimedwait_np to sleep for
1754 * fixed interval of time.
1755 * earlier implementation used alarm() call which
1756 * fails in Multi threaded environment. If multiple
1757 * threads call alarm() only one of the threads is
1758 * sent the SIGALRM signal.
1760 (void) pthread_mutex_lock(&env_monitor_mutex
);
1761 ret
= pthread_cond_reltimedwait_np(&env_monitor_cv
,
1762 &env_monitor_mutex
, &to
);
1763 to
.tv_sec
= SENSORPOLL_INTERVAL
;
1765 if (ret
!= ETIMEDOUT
) {
1766 (void) pthread_mutex_unlock(&env_monitor_mutex
);
1767 goto wait_till_timeout
;
1769 (void) pthread_mutex_unlock(&env_monitor_mutex
);
1774 * This is env thread which monitors the current temperature when
1775 * warning threshold is exceeded. The job is to make sure it does
1776 * not execced/decrease shutdown threshold. If it does it will start
1777 * forced shutdown to avoid reaching hardware poweroff via THERM interrupt.
1778 * For Enchilada there will be two threads, one for each ADM chip.
1781 ovtemp_thr(void *args
)
1785 int hwm_id
= (int)args
;
1790 pthread_mutex_t env_monitor_mutex
= PTHREAD_MUTEX_INITIALIZER
;
1791 pthread_cond_t env_monitor_cv
= PTHREAD_COND_INITIALIZER
;
1793 fd
= open(hwm_devs
[hwm_id
], O_RDWR
);
1795 envd_log(LOG_ERR
, ENV_ADM_OPEN_FAIL
, hwm_devs
[hwm_id
],
1796 errno
, strerror(errno
));
1800 envd_log(LOG_ERR
, "ovtemp thread for %s running...\n",
1805 * Sleep for specified seconds before issuing IOCTL
1810 * We use pthread_cond_reltimedwait_np to sleep for
1811 * fixed interval of time.
1812 * earlier implementation used alarm() call which
1813 * fails in Multi threaded environment. If multiple
1814 * threads call alarm() only one of the threads is
1815 * sent the SIGALRM signal.
1817 (void) pthread_mutex_lock(&env_monitor_mutex
);
1818 ret
= pthread_cond_reltimedwait_np(&env_monitor_cv
,
1819 &env_monitor_mutex
, &to
);
1820 to
.tv_sec
= INTERRUPTPOLL_INTERVAL
;
1822 if (ret
!= ETIMEDOUT
) {
1823 (void) pthread_mutex_unlock(&env_monitor_mutex
);
1826 (void) pthread_mutex_unlock(&env_monitor_mutex
);
1828 * Monitor the sensors to update fan status
1834 * Read ADM1031 two Status Registers to determine source
1838 if ((err
= ioctl(fd
, ADM1031_GET_STATUS_1
, &stat
[0])) != -1)
1839 err
= ioctl(fd
, ADM1031_GET_STATUS_2
, &stat
[1]);
1844 "OverTemp: Status Error");
1849 envd_log(LOG_ERR
, "INTR %s, Stat1 %x, Stat2 %x",
1850 hwm_devs
[hwm_id
], stat
[0], stat
[1]);
1852 if (stat
[0] & FANFAULT
) {
1853 fanp
= fan_lookup(hwm_fans
[hwm_id
][HWM_FAN1
]);
1854 if (fanp
&& fanp
->present
)
1855 envd_log(LOG_ERR
, ENV_FAN_FAULT
,
1857 hwm_fans
[hwm_id
][HWM_FAN1
]);
1859 if (stat
[1] & FANFAULT
) {
1860 fanp
= fan_lookup(hwm_fans
[hwm_id
][HWM_FAN2
]);
1861 if (fanp
&& fanp
->present
)
1862 envd_log(LOG_ERR
, ENV_FAN_FAULT
,
1864 hwm_fans
[hwm_id
][HWM_FAN2
]);
1867 * Check respective Remote/Local High, Low before start
1870 if ((stat
[0] & STAT1MASK
) || (stat
[1] & STAT2MASK
))
1871 (void) handle_overtemp_interrupt(hwm_id
);
1873 } /* end of for ever loop */
1879 dimm_fan_thr(void *args
)
1881 char syscmd
[BUFSIZ
];
1882 char msgbuf
[BUFSIZ
];
1886 pthread_mutex_t env_monitor_mutex
= PTHREAD_MUTEX_INITIALIZER
;
1887 pthread_cond_t env_monitor_cv
= PTHREAD_COND_INITIALIZER
;
1895 * Sleep for specified seconds before issuing IOCTL
1898 (void) pthread_mutex_lock(&env_monitor_mutex
);
1899 ret
= pthread_cond_reltimedwait_np(&env_monitor_cv
,
1900 &env_monitor_mutex
, &to
);
1901 to
.tv_sec
= INTERRUPTPOLL_INTERVAL
;
1903 if (ret
!= ETIMEDOUT
) {
1904 (void) pthread_mutex_unlock(&env_monitor_mutex
);
1907 (void) pthread_mutex_unlock(&env_monitor_mutex
);
1909 * We write to the comand register periodically
1910 * to inform the PIC firmware that Solaris is
1911 * Monitoring the dimm fan periodically.
1913 i2c_reg
.reg_num
= PIC16F819_COMMAND_REGISTER
;
1914 i2c_reg
.reg_value
= PIC16F819_SW_AWARE_MODE
;
1915 if (ioctl(envd_dimm_fan
.fd
,
1916 I2C_SET_REG
, &i2c_reg
) == -1) {
1919 "Error in writing to COMMAND reg. of DIMM FAN controller\n");
1922 * We initiate shutdown if fan status indicates
1925 if (is_dimm_fan_failed() != 0) {
1927 * Mark Dimm fan present as False so that we
1928 * do not WARN the user of the Fan failure
1931 envd_dimm_fan
.present
= B_FALSE
;
1932 (void) snprintf(msgbuf
, sizeof (msgbuf
),
1933 ENV_DIMM_FAN_FAILURE_SHUTDOWN_MSG
,
1935 dimm_fan_rpm_string
, dimm_fan_status_string
,
1936 dimm_fan_command_string
,
1937 dimm_fan_debug_string
);
1938 envd_log(LOG_ALERT
, msgbuf
);
1940 if (system_shutdown_started
== B_FALSE
) {
1941 system_shutdown_started
= B_TRUE
;
1942 (void) snprintf(syscmd
, sizeof (syscmd
),
1946 envd_log(LOG_ALERT
, syscmd
);
1947 (void) system(syscmd
);
1955 scsi_log_sense(int fd
, uchar_t page_code
, uchar_t
*pagebuf
, uint16_t pagelen
)
1957 struct uscsi_cmd ucmd_buf
;
1958 uchar_t cdb_buf
[CDB_GROUP1
];
1959 struct scsi_extended_sense sense_buf
;
1962 bzero((void *)&cdb_buf
, sizeof (cdb_buf
));
1963 bzero((void *)&ucmd_buf
, sizeof (ucmd_buf
));
1964 bzero((void *)&sense_buf
, sizeof (sense_buf
));
1966 cdb_buf
[0] = SCMD_LOG_SENSE_G1
;
1967 cdb_buf
[2] = (0x01 << 6) | page_code
;
1968 cdb_buf
[7] = (uchar_t
)((pagelen
& 0xFF00) >> 8);
1969 cdb_buf
[8] = (uchar_t
)(pagelen
& 0x00FF);
1971 ucmd_buf
.uscsi_cdb
= (char *)cdb_buf
;
1972 ucmd_buf
.uscsi_cdblen
= sizeof (cdb_buf
);
1973 ucmd_buf
.uscsi_bufaddr
= (caddr_t
)pagebuf
;
1974 ucmd_buf
.uscsi_buflen
= pagelen
;
1975 ucmd_buf
.uscsi_rqbuf
= (caddr_t
)&sense_buf
;
1976 ucmd_buf
.uscsi_rqlen
= sizeof (struct scsi_extended_sense
);
1977 ucmd_buf
.uscsi_flags
= USCSI_RQENABLE
| USCSI_READ
| USCSI_SILENT
;
1978 ucmd_buf
.uscsi_timeout
= 60;
1980 ret_val
= ioctl(fd
, USCSICMD
, ucmd_buf
);
1981 if (ret_val
== 0 && ucmd_buf
.uscsi_status
== 0) {
1984 "log sense command for page_code 0x%x succeeded\n", page_code
);
1989 "log sense command failed.ret_val = 0x%x status = 0x%x errno = 0x%x\n",
1990 ret_val
, ucmd_buf
.uscsi_status
, errno
);
1995 get_disk_temp(env_disk_t
*diskp
)
2000 ret
= scsi_log_sense(diskp
->fd
,
2002 tpage
, sizeof (tpage
));
2004 diskp
->current_temp
= DISK_INVALID_TEMP
;
2005 diskp
->ref_temp
= DISK_INVALID_TEMP
;
2009 * For the current temperature verify that the parameter
2010 * length is 0x02 and the parameter code is 0x00
2011 * Temperature value of 255(0xFF) is considered INVALID.
2013 if ((tpage
[7] == 0x02) && (tpage
[4] == 0x00) &&
2014 (tpage
[5] == 0x00)) {
2015 if (tpage
[9] == 0xFF) {
2016 diskp
->current_temp
= DISK_INVALID_TEMP
;
2019 diskp
->current_temp
= tpage
[9];
2024 * For the reference temperature verify that the parameter
2025 * length is 0x02 and the parameter code is 0x01
2026 * Temperature value of 255(0xFF) is considered INVALID.
2028 if ((tpage
[13] == 0x02) && (tpage
[10] == 0x00) &&
2029 (tpage
[11] == 0x01)) {
2030 if (tpage
[15] == 0xFF) {
2031 diskp
->ref_temp
= DISK_INVALID_TEMP
;
2033 diskp
->ref_temp
= tpage
[15];
2041 disk_temp_thr(void *args
)
2043 char syscmd
[BUFSIZ
];
2044 char msgbuf
[BUFSIZ
];
2048 pthread_mutex_t env_monitor_mutex
= PTHREAD_MUTEX_INITIALIZER
;
2049 pthread_cond_t env_monitor_cv
= PTHREAD_COND_INITIALIZER
;
2050 pm_state_change_t pmstate
;
2055 disk_pm_fd
= open(PM_DEVICE
, O_RDWR
);
2056 if (disk_pm_fd
== -1) {
2058 DISK_TEMP_THREAD_EXITING
,
2059 errno
, strerror(errno
));
2064 * Sleep for specified seconds before issuing IOCTL
2067 (void) pthread_mutex_lock(&env_monitor_mutex
);
2068 ret
= pthread_cond_reltimedwait_np(&env_monitor_cv
,
2069 &env_monitor_mutex
, &to
);
2070 to
.tv_sec
= disk_scan_interval
;
2072 if (ret
!= ETIMEDOUT
) {
2073 (void) pthread_mutex_unlock(&env_monitor_mutex
);
2076 (void) pthread_mutex_unlock(&env_monitor_mutex
);
2077 for (i
= 0; (diskp
= envd_disks
[i
]) != NULL
; i
++) {
2078 if (diskp
->present
== B_FALSE
)
2080 if (diskp
->tpage_supported
== B_FALSE
)
2083 * If the disk temperature is above the warning threshold
2084 * continue monitoring until the temperature drops below
2085 * warning threshold.
2086 * if the temperature is in the NORMAL range monitor only
2087 * when the disk is BUSY.
2088 * We do not want to read the disk temperature if the disk is
2089 * is idling. The reason for this is disk will never get into
2090 * lowest power mode if we scan the disk temperature
2091 * peridoically. To avoid this situation we first determine
2092 * the idle_time of the disk. If the disk has been IDLE since
2093 * we scanned the temperature last time we will not read the
2096 if (!DISK_TEMP_IN_WARNING_RANGE(diskp
->current_temp
, diskp
)) {
2097 pmstate
.physpath
= diskp
->physpath
;
2098 pmstate
.size
= strlen(diskp
->physpath
);
2099 pmstate
.component
= 0;
2102 PM_GET_TIME_IDLE
, &pmstate
)) == -1) {
2103 if (errno
!= EINTR
) {
2106 "ioctl PM_GET_TIME_IDLE failed for DISK0. errno=0x%x\n",
2112 if (idle_time
>= (disk_scan_interval
/2)) {
2115 "%s idle time = %d\n",
2116 diskp
->name
, idle_time
);
2121 ret
= get_disk_temp(diskp
);
2126 "%s temp = %d ref. temp = %d\n",
2127 diskp
->name
, diskp
->current_temp
, diskp
->ref_temp
);
2130 * If this disk already triggered system shutdown, don't
2131 * log any more shutdown/warning messages for it.
2133 if (diskp
->shutdown_initiated
)
2137 * Check for the temperature in warning and shutdown range
2138 * and take appropriate action.
2140 if (DISK_TEMP_IN_WARNING_RANGE(diskp
->current_temp
, diskp
)) {
2142 * Check if the temperature has been in warning
2143 * range during last disk_warning_duration interval.
2144 * If so, the temperature is truly in warning
2145 * range and we need to log a warning message,
2146 * but no more than once every disk_warning_interval
2149 time_t wtstamp
= diskp
->warning_tstamp
;
2151 ct
= (time_t)(gethrtime() / NANOSEC
);
2152 if (diskp
->warning_start
== 0)
2153 diskp
->warning_start
= ct
;
2154 if (((ct
- diskp
->warning_start
) >=
2155 disk_warning_duration
) && (wtstamp
== 0 ||
2156 (ct
- wtstamp
) >= disk_warning_interval
)) {
2157 envd_log(LOG_CRIT
, ENV_WARNING_MSG
,
2158 diskp
->name
, diskp
->current_temp
,
2160 diskp
->high_warning
);
2161 diskp
->warning_tstamp
= ct
;
2163 } else if (diskp
->warning_start
!= 0)
2164 diskp
->warning_start
= 0;
2166 if (!shutdown_override
&&
2167 DISK_TEMP_IN_SHUTDOWN_RANGE(diskp
->current_temp
, diskp
)) {
2168 ct
= (time_t)(gethrtime() / NANOSEC
);
2169 if (diskp
->shutdown_tstamp
== 0)
2170 diskp
->shutdown_tstamp
= ct
;
2173 * Shutdown the system if the temperature remains
2174 * in the shutdown range for over disk_shutdown_interval
2177 if ((ct
- diskp
->shutdown_tstamp
) >=
2178 disk_shutdown_interval
) {
2180 diskp
->shutdown_initiated
= B_TRUE
;
2181 (void) snprintf(msgbuf
, sizeof (msgbuf
),
2182 ENV_SHUTDOWN_MSG
, diskp
->name
,
2183 diskp
->current_temp
, diskp
->low_shutdown
,
2184 diskp
->high_shutdown
);
2185 envd_log(LOG_ALERT
, msgbuf
);
2187 /* shutdown the system (only once) */
2188 if (system_shutdown_started
== B_FALSE
) {
2189 (void) snprintf(syscmd
, sizeof (syscmd
),
2190 "%s \"%s\"", shutdown_cmd
, msgbuf
);
2191 envd_log(LOG_ALERT
, syscmd
);
2192 system_shutdown_started
= B_TRUE
;
2193 (void) system(syscmd
);
2196 } else if (diskp
->shutdown_tstamp
!= 0)
2197 diskp
->shutdown_tstamp
= 0;
2200 } /* end of forever loop */
2204 * Setup envrionmental monitor state and start threads to monitor
2205 * temperature and power management state.
2206 * Returns -1 on error, 0 if successful.
2213 if (getenv("SUNW_piclenvd_debug") != NULL
)
2216 if (pthread_attr_init(&thr_attr
) != 0 ||
2217 pthread_attr_setscope(&thr_attr
, PTHREAD_SCOPE_SYSTEM
) != 0) {
2221 ret
= envd_es_setup();
2228 * Setup temperature sensors and fail if we can't open
2229 * at least one sensor.
2231 if (envd_setup_sensors() <= 0) {
2236 * Setup fan device (don't fail even if we can't access
2237 * the fan as we can still monitor temeperature.
2239 (void) envd_setup_fans();
2241 (void) envd_setup_disks();
2243 /* If ES Segment setup failed,don't create thread */
2245 if (ovtemp_monitor
&& ovtemp_thr1_created
== B_FALSE
) {
2246 if (pthread_create(&ovtemp_thr1_id
, &thr_attr
, ovtemp_thr
,
2247 (void *)CPU_HWM_ID
) != 0)
2248 envd_log(LOG_ERR
, ENVTHR_THREAD_CREATE_FAILED
);
2250 ovtemp_thr1_created
= B_TRUE
;
2253 if (ovtemp_monitor
&& ovtemp_thr2_created
== B_FALSE
) {
2254 if (pthread_create(&ovtemp_thr2_id
, &thr_attr
, ovtemp_thr
,
2255 (void *)SYS_HWM_ID
) != 0)
2256 envd_log(LOG_ERR
, ENVTHR_THREAD_CREATE_FAILED
);
2258 ovtemp_thr2_created
= B_TRUE
;
2261 if (envd_dimm_fan
.present
) {
2262 if (dimm_fan_thr_created
== B_FALSE
) {
2263 if (pthread_create(&dimm_fan_thr_id
, &thr_attr
, dimm_fan_thr
,
2265 envd_log(LOG_ERR
, ENVTHR_THREAD_CREATE_FAILED
);
2267 dimm_fan_thr_created
= B_TRUE
;
2272 * Create a thread to monitor PM state
2274 if (pm_monitor
&& pmthr_created
== B_FALSE
) {
2275 if (pthread_create(&pmthr_tid
, &thr_attr
, pmthr
,
2277 envd_log(LOG_CRIT
, PM_THREAD_CREATE_FAILED
);
2279 pmthr_created
= B_TRUE
;
2281 if (monitor_disk_temp
) {
2282 if (disk_temp_thr_created
== B_FALSE
) {
2283 if (pthread_create(&disk_temp_thr_id
, &thr_attr
, disk_temp_thr
,
2285 envd_log(LOG_ERR
, ENVTHR_THREAD_CREATE_FAILED
);
2287 disk_temp_thr_created
= B_TRUE
;
2294 piclenvd_register(void)
2296 picld_plugin_register(&my_reg_info
);
2303 (void) env_picl_setup_tuneables();
2306 * Setup the environmental data structures
2308 if (envd_setup() != 0) {
2309 envd_log(LOG_CRIT
, ENVD_PLUGIN_INIT_FAILED
);
2314 * Now setup/populate PICL tree
2324 * Invoke env_picl_destroy() to remove any PICL nodes/properties
2325 * (including volatile properties) we created. Once this call
2326 * returns, there can't be any more calls from the PICL framework
2327 * to get current temperature or fan speed.
2330 envd_close_sensors();
2337 envd_log(int pri
, const char *fmt
, ...)
2342 vsyslog(pri
, fmt
, ap
);
2347 * Tunables support functions
2349 static env_tuneable_t
*
2350 tuneable_lookup(picl_prophdl_t proph
)
2353 env_tuneable_t
*tuneablep
= NULL
;
2355 for (i
= 0; i
< ntuneables
; i
++) {
2356 tuneablep
= &tuneables
[i
];
2357 if (tuneablep
->proph
== proph
)
2365 get_cpu_tach(ptree_rarg_t
*parg
, void *buf
)
2367 picl_prophdl_t proph
;
2368 env_tuneable_t
*tuneablep
;
2372 proph
= parg
->proph
;
2374 tuneablep
= tuneable_lookup(proph
);
2376 if (tuneablep
== NULL
)
2377 return (PICL_FAILURE
);
2379 fd
= open(CPU_HWM_DEVFS
, O_RDWR
);
2382 return (PICL_FAILURE
);
2385 if (ioctl(fd
, ADM1031_GET_CONFIG_2
, &cfg
) == -1) {
2386 return (PICL_FAILURE
);
2389 if ((cfg
& TACH_ENABLE_MASK
) == TACH_ENABLE_MASK
) {
2390 *((int *)tuneablep
->value
) = ENABLE
;
2392 *((int *)tuneablep
->value
) = DISABLE
;
2395 (void) memcpy(buf
, tuneablep
->value
,
2399 return (PICL_SUCCESS
);
2403 set_cpu_tach(ptree_warg_t
*parg
, const void *buf
)
2405 picl_prophdl_t proph
;
2406 env_tuneable_t
*tuneablep
;
2410 if (parg
->cred
.dc_euid
!= 0)
2411 return (PICL_PERMDENIED
);
2413 proph
= parg
->proph
;
2415 tuneablep
= tuneable_lookup(proph
);
2417 if (tuneablep
== NULL
)
2418 return (PICL_FAILURE
);
2421 fd
= open(CPU_HWM_DEVFS
, O_RDWR
);
2424 return (PICL_FAILURE
);
2427 if (ioctl(fd
, ADM1031_GET_CONFIG_2
, &cfg
) == -1) {
2428 return (PICL_FAILURE
);
2431 (void) memcpy(&val
, (caddr_t
)buf
, sizeof (val
));
2433 if (val
== ENABLE
) {
2434 cfg
|= TACH_ENABLE_MASK
;
2435 } else if (val
== DISABLE
) {
2436 cfg
&= ~TACH_ENABLE_MASK
;
2440 if (ioctl(fd
, ADM1031_SET_CONFIG_2
, &cfg
) == -1) {
2441 return (PICL_FAILURE
);
2445 return (PICL_SUCCESS
);
2449 get_sys_tach(ptree_rarg_t
*parg
, void *buf
)
2451 picl_prophdl_t proph
;
2452 env_tuneable_t
*tuneablep
;
2456 proph
= parg
->proph
;
2458 tuneablep
= tuneable_lookup(proph
);
2460 if (tuneablep
== NULL
)
2461 return (PICL_FAILURE
);
2463 fd
= open(SYS_HWM_DEVFS
, O_RDWR
);
2466 return (PICL_FAILURE
);
2469 if (ioctl(fd
, ADM1031_GET_CONFIG_2
, &cfg
) == -1) {
2470 return (PICL_FAILURE
);
2473 if ((cfg
& TACH_ENABLE_MASK
) == TACH_ENABLE_MASK
) {
2474 *((int *)tuneablep
->value
) = ENABLE
;
2476 *((int *)tuneablep
->value
) = DISABLE
;
2479 (void) memcpy(buf
, tuneablep
->value
,
2483 return (PICL_SUCCESS
);
2487 set_sys_tach(ptree_warg_t
*parg
, const void *buf
)
2489 picl_prophdl_t proph
;
2490 env_tuneable_t
*tuneablep
;
2494 if (parg
->cred
.dc_euid
!= 0)
2495 return (PICL_PERMDENIED
);
2497 proph
= parg
->proph
;
2499 tuneablep
= tuneable_lookup(proph
);
2501 if (tuneablep
== NULL
)
2502 return (PICL_FAILURE
);
2505 fd
= open(SYS_HWM_DEVFS
, O_RDWR
);
2508 return (PICL_FAILURE
);
2511 if (ioctl(fd
, ADM1031_GET_CONFIG_2
, &cfg
) == -1) {
2512 return (PICL_FAILURE
);
2515 (void) memcpy(&val
, buf
, sizeof (val
));
2517 if (val
== ENABLE
) {
2518 cfg
|= TACH_ENABLE_MASK
;
2519 } else if (val
== DISABLE
) {
2520 cfg
&= ~TACH_ENABLE_MASK
;
2524 if (ioctl(fd
, ADM1031_SET_CONFIG_2
, &cfg
) == -1) {
2525 return (PICL_FAILURE
);
2529 return (PICL_SUCCESS
);
2533 get_monitor_cpu_mode(ptree_rarg_t
*parg
, void *buf
)
2535 picl_prophdl_t proph
;
2536 env_tuneable_t
*tuneablep
;
2540 proph
= parg
->proph
;
2542 tuneablep
= tuneable_lookup(proph
);
2544 if (tuneablep
== NULL
)
2545 return (PICL_FAILURE
);
2547 fd
= open(CPU_HWM_DEVFS
, O_RDWR
);
2550 return (PICL_FAILURE
);
2553 if (ioctl(fd
, ADM1031_GET_MONITOR_MODE
, &mmode
) == -1) {
2554 return (PICL_FAILURE
);
2557 if (mmode
== ADM1031_AUTO_MODE
) {
2558 *((int *)tuneablep
->value
) = ENABLE
;
2560 *((int *)tuneablep
->value
) = DISABLE
;
2563 (void) memcpy(buf
, tuneablep
->value
,
2567 return (PICL_SUCCESS
);
2571 set_monitor_cpu_mode(ptree_warg_t
*parg
, const void *buf
)
2573 picl_prophdl_t proph
;
2574 env_tuneable_t
*tuneablep
;
2578 if (parg
->cred
.dc_euid
!= 0)
2579 return (PICL_PERMDENIED
);
2581 proph
= parg
->proph
;
2583 tuneablep
= tuneable_lookup(proph
);
2585 if (tuneablep
== NULL
)
2586 return (PICL_FAILURE
);
2588 fd
= open(CPU_HWM_DEVFS
, O_RDWR
);
2591 return (PICL_FAILURE
);
2594 (void) memcpy(&val
, buf
, sizeof (val
));
2596 if (val
== ENABLE
) {
2597 mmode
= ADM1031_AUTO_MODE
;
2598 } else if (val
== DISABLE
) {
2599 mmode
= ADM1031_MANUAL_MODE
;
2602 if (ioctl(fd
, ADM1031_SET_MONITOR_MODE
, &mmode
) == -1) {
2603 return (PICL_FAILURE
);
2607 return (PICL_SUCCESS
);
2611 get_monitor_sys_mode(ptree_rarg_t
*parg
, void *buf
)
2613 picl_prophdl_t proph
;
2614 env_tuneable_t
*tuneablep
;
2618 proph
= parg
->proph
;
2620 tuneablep
= tuneable_lookup(proph
);
2622 if (tuneablep
== NULL
)
2623 return (PICL_FAILURE
);
2625 fd
= open(SYS_HWM_DEVFS
, O_RDWR
);
2628 return (PICL_FAILURE
);
2631 if (ioctl(fd
, ADM1031_GET_MONITOR_MODE
, &mmode
) == -1) {
2632 return (PICL_FAILURE
);
2635 if (mmode
== ADM1031_AUTO_MODE
) {
2636 *((int *)tuneablep
->value
) = ENABLE
;
2638 *((int *)tuneablep
->value
) = DISABLE
;
2641 (void) memcpy(buf
, tuneablep
->value
,
2645 return (PICL_SUCCESS
);
2649 set_monitor_sys_mode(ptree_warg_t
*parg
, const void *buf
)
2651 picl_prophdl_t proph
;
2652 env_tuneable_t
*tuneablep
;
2656 if (parg
->cred
.dc_euid
!= 0)
2657 return (PICL_PERMDENIED
);
2659 proph
= parg
->proph
;
2661 tuneablep
= tuneable_lookup(proph
);
2663 if (tuneablep
== NULL
)
2664 return (PICL_FAILURE
);
2666 fd
= open(SYS_HWM_DEVFS
, O_RDWR
);
2669 return (PICL_FAILURE
);
2672 (void) memcpy(&val
, buf
, sizeof (val
));
2674 if (val
== ENABLE
) {
2675 mmode
= ADM1031_AUTO_MODE
;
2676 } else if (val
== DISABLE
) {
2677 mmode
= ADM1031_MANUAL_MODE
;
2680 if (ioctl(fd
, ADM1031_SET_MONITOR_MODE
, &mmode
) == -1) {
2681 return (PICL_FAILURE
);
2685 return (PICL_SUCCESS
);
2689 get_string_val(ptree_rarg_t
*parg
, void *buf
)
2691 picl_prophdl_t proph
;
2692 env_tuneable_t
*tuneablep
;
2694 proph
= parg
->proph
;
2696 tuneablep
= tuneable_lookup(proph
);
2698 if (tuneablep
== NULL
)
2699 return (PICL_FAILURE
);
2701 (void) memcpy(buf
, (caddr_t
)tuneablep
->value
,
2704 return (PICL_SUCCESS
);
2708 set_string_val(ptree_warg_t
*parg
, const void *buf
)
2710 picl_prophdl_t proph
;
2711 env_tuneable_t
*tuneablep
;
2713 if (parg
->cred
.dc_euid
!= 0)
2714 return (PICL_PERMDENIED
);
2716 proph
= parg
->proph
;
2718 tuneablep
= tuneable_lookup(proph
);
2720 if (tuneablep
== NULL
)
2721 return (PICL_FAILURE
);
2723 (void) memcpy((caddr_t
)tuneables
->value
, (caddr_t
)buf
,
2727 return (PICL_SUCCESS
);
2731 get_int_val(ptree_rarg_t
*parg
, void *buf
)
2733 picl_prophdl_t proph
;
2734 env_tuneable_t
*tuneablep
;
2736 proph
= parg
->proph
;
2738 tuneablep
= tuneable_lookup(proph
);
2740 if (tuneablep
== NULL
)
2741 return (PICL_FAILURE
);
2743 (void) memcpy((int *)buf
, (int *)tuneablep
->value
,
2746 return (PICL_SUCCESS
);
2750 set_int_val(ptree_warg_t
*parg
, const void *buf
)
2752 picl_prophdl_t proph
;
2753 env_tuneable_t
*tuneablep
;
2755 if (parg
->cred
.dc_euid
!= 0)
2756 return (PICL_PERMDENIED
);
2758 proph
= parg
->proph
;
2760 tuneablep
= tuneable_lookup(proph
);
2762 if (tuneablep
== NULL
)
2763 return (PICL_FAILURE
);
2765 (void) memcpy((int *)tuneablep
->value
, (int *)buf
,
2768 return (PICL_SUCCESS
);
2772 get_dimm_fan_speed(int fan_fd
, fanspeed_t
*fanspeedp
)
2774 int16_t dimm_fan_period
;
2778 * The dimm fan period is 16 bit value and we need to read
2779 * registers 2 and 3 to get the LSB and MSB values.
2781 i2c_reg
.reg_num
= PIC16F819_FAN_PERIOD_MSB_REGISTER
;
2782 if (ioctl(fan_fd
, I2C_GET_REG
, &i2c_reg
) == -1) {
2785 "Error in reading FAN_PERIOD MSB REGISTER\n");
2788 dimm_fan_period
= (i2c_reg
.reg_value
<< 8);
2789 i2c_reg
.reg_num
= PIC16F819_FAN_PERIOD_LSB_REGISTER
;
2790 if (ioctl(fan_fd
, I2C_GET_REG
, &i2c_reg
) == -1) {
2793 "Error in reading FAN_PERIOD LSB REGISTER\n");
2796 dimm_fan_period
|= i2c_reg
.reg_value
;
2799 " dimm fan tach period is 0x%x\n", dimm_fan_period
);
2800 if (dimm_fan_period
== 0) {
2803 "dimm fan tach period read as zero. Illegal value.\n");
2806 *fanspeedp
= PIC16F819_FAN_TACH_TO_RPM(dimm_fan_period
);
2811 is_dimm_fan_failed(void)
2814 fanspeed_t fan_speed
;
2817 if (envd_dimm_fan
.fd
== -1)
2820 * read register 1 to look at Fan fault bit.
2822 i2c_reg
.reg_num
= PIC16F819_STATUS_REGISTER
;
2823 retry_count
= MAX_RETRIES_FOR_PIC16F819_REG_READ
;
2824 while (retry_count
> 0) {
2825 if (ioctl(envd_dimm_fan
.fd
, I2C_GET_REG
, &i2c_reg
) == -1) {
2830 if (retry_count
!= MAX_RETRIES_FOR_PIC16F819_REG_READ
) {
2833 "%d retries attempted in reading STATUS register.\n",
2834 (MAX_RETRIES_FOR_PIC16F819_REG_READ
- retry_count
));
2836 if (retry_count
== 0) {
2837 (void) strncpy(dimm_fan_status_string
, NOT_AVAILABLE
,
2838 sizeof (dimm_fan_status_string
));
2839 (void) strncpy(dimm_fan_command_string
, NOT_AVAILABLE
,
2840 sizeof (dimm_fan_command_string
));
2841 (void) strncpy(dimm_fan_debug_string
, NOT_AVAILABLE
,
2842 sizeof (dimm_fan_debug_string
));
2843 (void) strncpy(dimm_fan_rpm_string
, NOT_AVAILABLE
,
2844 sizeof (dimm_fan_rpm_string
));
2849 "DIMM FAN STATUS reg = 0x%x\n", i2c_reg
.reg_value
);
2850 if (i2c_reg
.reg_value
& PIC16F819_FAN_FAILED
) {
2851 (void) snprintf(dimm_fan_status_string
,
2852 sizeof (dimm_fan_status_string
), "0x%x",
2854 i2c_reg
.reg_num
= PIC16F819_DEBUG_REGISTER
;
2855 if (ioctl(envd_dimm_fan
.fd
, I2C_GET_REG
, &i2c_reg
) == -1) {
2856 (void) strncpy(dimm_fan_debug_string
, NOT_AVAILABLE
,
2857 sizeof (dimm_fan_debug_string
));
2859 (void) snprintf(dimm_fan_debug_string
,
2860 sizeof (dimm_fan_debug_string
),
2861 "0x%x", i2c_reg
.reg_value
);
2863 i2c_reg
.reg_num
= PIC16F819_COMMAND_REGISTER
;
2864 if (ioctl(envd_dimm_fan
.fd
, I2C_GET_REG
, &i2c_reg
) == -1) {
2865 (void) strncpy(dimm_fan_command_string
, NOT_AVAILABLE
,
2866 sizeof (dimm_fan_command_string
));
2868 (void) snprintf(dimm_fan_command_string
,
2869 sizeof (dimm_fan_command_string
),
2870 "0x%x", i2c_reg
.reg_value
);
2872 if (get_dimm_fan_speed(envd_dimm_fan
.fd
, &fan_speed
) == -1) {
2873 (void) strncpy(dimm_fan_rpm_string
, NOT_AVAILABLE
,
2874 sizeof (dimm_fan_rpm_string
));
2876 (void) snprintf(dimm_fan_rpm_string
,
2877 sizeof (dimm_fan_rpm_string
),