I've modified Kevin Horton's basic fan controller script. I had to correct a few issues with Seagate drives, and I've made it a bit more flexible. It now has a debug mode, as well as a loop mode, so that you can play with it in an ssh session without having to have cron going.
To use this script, have your HD fans connected to FANA. The "fan mode" you select in IPMI will then control your CPU/Exhaust fans. I use Optimal mode (mode #2), personally, and I've verified that the FANA header behaves correctly in this mode.
You can use this command to set Optimal mode:
ipmitool raw 0x30 0x45 0x01 0x02
Once you have confirmed that its working for you in a terminal session, you can disable debug mode, and loop mode, and then configure it to run as a cron job. Or alternatively, disable debug mode and configure it to run at startup, like Glorius1's script. The cron job would ensure that if the script were to crash... it would be restarted again.
My intention is next to get Glorius1's PID script working
:)
Update 2016-08-18:
I updated the script a tiny bit to deal with two issues I found.
1) HeavyIO is not compatible, so the script starts by setting Optimal mode
2) This is not compatible with X9, so I've changed the description
3) Sometimes the fans don't spin down/up fast enough causing the BMC to be reset unneccessarily. I've increased the BMC reset test delay to 10 seconds, to avoid this.
4) fixed a bug where the date would not be changed in loop mode
Code:
#!/usr/local/bin/perl
# This script works on SuperMicro X9 and X10 IPMI motherboards to control FANA Peripheral
# Zone fan speed in response to maximum hard drive temperature.
# To use this correctly, you should connect all your PWM HD fans, by splitters if necessary to the FANA header.
# Case and Exhaust fans should then be connected to the numbered (ie CPU based) headers. This script will then control the
# HD fans in response to the HD temp, and allow the system to control the other fans in response to the CPU temp.
# It should be set as a cron job to run on roughly a three minute interval, or alternatively
# you can set a loop_sleep value, and it will loop indefinately after loop_sleep seconds.
# you can see debug output by setting the debug_mode value to a greater value than 0. higher
# values are more detailed.
# Remember to adjust the configuration values below.
# In order for these duty cycle changes to work, you need to ensure that you’ve adjusted your fan thresholds as per:
# https://forums.freenas.org/index.php?threads/how-to-change-sensor-thresholds-with-ipmi-using-ipmitool.23571/
# The original version of this script was developed by Kevin Horton and can be found at:
# https://forums.freenas.org/index.php?threads/script-to-control-fan-speed-in-response-to-hard-drive-temperatures.41294/page-3#post-282683
# This version was modified by myself (stux), to support systems where the HD fans are connected to
# the peripheral fan headers (ie FANA). I corrected a number of issues with reading the temperature from Seagate
# drives, as well as made the temperature configurable, corrected a few timing issues, and added the loop_seconds, max_allowed_temp and
# debug constructs
# More information on CPU/Peripheral Zone can be found in this post:
# https://forums.freenas.org/index.php?threads/thermal-and-accoustical-design-validation.28364/
# And the Duty Cycle/Zone commands are found in these posts
# https://forums.freenas.org/index.php?threads/script-to-control-fan-speed-in-response-to-hard-drive-temperatures.41294/page-4#post-289940
# https://forums.freenas.org/index.php?threads/script-to-control-fan-speed-in-response-to-hard-drive-temperatures.41294/page-4#post-290054
# https://forums.servethehome.com/index.php?resources/supermicro-x9-x10-x11-fan-speed-control.20/
# Version History
#--------------------
# 1.x Kevin's scripts
# 2.0 stux: initial changes to support a FANA/Zone 1 based system
# 2.1 stux: added initial setting to Optimal mode. Increased delay before reset to 10 seconds. Fixed date/time logging bug
# if loop_sleep is non-zero, then we'll never exit. Its how long, in seconds, we should sleep each iteration...
$loop_sleep = 180; # 0 for no looping. 180 for 3 minute looping (suggested)
$debug = 1; # 0 for no debug. 1..4 for verbosity
# edit the following values
$number_of_hard_drives = 8;
$hd_designator = "/dev/ada";
$min_fan_speed = 300;
$max_fan_speed = 1400;
$max_allowed_temp = 38; # celsius. you will hit 100% duty cycle when you HDs hit this temp.
$LogFile = '/root/HD_TempLog.txt';
$min_fan_speed *= 1.4;
$max_fan_speed *= 0.8;
# edit nothing below this line
use POSIX qw(strftime);
# go to Optimal mode
`ipmitool raw 0x30 0x45 0x01 2`;
sleep 1;
do {
#build datestring
$datestring = strftime "%F %H:%M:%S", localtime;
open (LOGFILE, ">>$LogFile");
$max_temp = 0;
foreach $item (0..$number_of_hard_drives-1) {
$command = "/usr/local/sbin/smartctl -A $hd_designator$item | grep Temperature_Celsius";
if( $debug > 3) {
print "$command\n";
}
$output = `$command`;
if ($debug > 2) {
print "$output\n";
}
@vals = split(" ", $output);
# grab 4th item from the output, which is the hard drive temperature
$temp = "$vals[3]\n";
if( $debug > 1 ) {
print "$hd_designator$item: $temp";
}
# update maximum drive temperature
$max_temp = $temp if $temp > $max_temp;
}
if( $debug > 0 ) {
print "Maximum HD Temperature: $max_temp\n";
}
if ($max_temp >= $max_allowed_temp ) {
if( $debug > 0 ) {
print "drives are too hot, going to 100%\n";
}
# set hd fan speed control to 100%
`ipmitool raw 0x30 0x70 0x66 0x01 1 100`;
}
elsif ($max_temp >= $max_allowed_temp - 1 ) {
if( $debug > 0 ) {
print "drives are warm, going to %75\n";
}
# set hd fans speed control to 75%
`ipmitool raw 0x30 0x70 0x66 0x01 1 75`;
}
elsif ($max_temp >= $max_allowed_temp - 2 ) {
if( $debug > 0 ) {
print "drives are warming, going to 50%\n";
}
# set peripheral zone fan speed to 50% duty cycle
`ipmitool raw 0x30 0x70 0x66 0x01 1 50`;
}
else {
if( $debug > 0 ) {
print "drives are cool enough, going to 25%\n";
}
# set to 30%
`ipmitool raw 0x30 0x70 0x66 0x01 1 25`;
}
# reset BMC if temps are cool, and fan is not slow
if ($max_temp < $max_allowed_temp - 3 ){
sleep 10; #need to wait for fans to change speed
$command = "ipmitool sdr | grep FANA";
$output = `$command`;
@vals = split(" ", $output);
$fan_speed = "$vals[2]";
if ($fan_speed > $min_fan_speed){
if( $debug > 0 ) {
print "drives are cool ($max_temp), but fan is high ($fan_speed). resetting BMC\n";
}
`ipmitool bmc reset cold`;
}
}
# reset BMC if temps are warm, and fan is not fast
if ($max_temp > $max_allowed_temp ){
sleep 10; # need to wait for fans to change speed...
$command = "ipmitool sdr | grep FANA";
$output = `$command`;
@vals = split(" ", $output);
$fan_speed = "$vals[2]";
if ($fan_speed < $max_fan_speed){
if( $debug > 0 ) {
print "drives are hot ($max_temp), but fan is low ($fan_speed). resetting BMC\n";
}
`ipmitool bmc reset cold`;
}
}
print LOGFILE "$datestring - $max_temp";
close (LOGFILE);
if( $loop_sleep > 0 ) {
if( $debug > 2 ) {
print "sleeping...\n";
}
sleep $loop_sleep;
}
} while( $loop_sleep )
I've attached the modified perl script. To use this like kevin's original, set debug = 0, and loop_seconds = 0.
Also, you can change the "max_allowed_temp".
You should run it as is in a terminal to verify its working.
PS: I've now written a different
Hybrid CPU & HD Fan Controller script