Hard Drive Standby Timer – How to Set on FreeBSD/TrueNAS

freebsdtruenas

I'd like to have my hard drives spin down when idle for, let's say 20 minutes. Any number of minutes is fine, as this NAS is rarely used.

What I've tried and didn't work:

  • ataidle -S 20 /dev/ada0 simply spins down the drive immediately and the timer has no effect. Once drives are spun back up due to an access they stay spinning.

  • camcontrol standby /dev/ada0 -t 1200 same behavior as ataidle.

  • FreeNAS UI's Storage -> Disks -> Adv. Power Manager setting simply calls camcontrol and similarly the timer has no effect. If a power setting that allows standby is selected (such as 127) then drives spin down nearly immediately (potentially after 8 seconds), and get constantly spun up and down if there are any accesses. UPDATE: See How to get FreeNAS to spin down disks? for instructions on how to make this work and skip the manual scripts.

How can I get the normal expected "stand by if not used in a while" behavior?

Using FreeBSD 11.2-STABLE via FreeNAS 11.2. Drives are 4x Samsung 2TB 2.5" .T2000LM003`

# smartctl -P show /dev/ada0
smartctl 6.6 2017-11-05 r4594 [FreeBSD 11.2-STABLE amd64] (local build)
Copyright (C) 2002-17, Bruce Allen, Christian Franke, www.smartmontools.org

Drive found in smartmontools Database.  Drive identity strings:
MODEL:              ST2000LM003 HN-M201RAD
FIRMWARE:           2BC10007
match smartmontools Drive Database entry:
MODEL REGEXP:       ST(1500|2000)LM0(03|04|06|07|10) HN-M[0-9]*RAD
FIRMWARE REGEXP:    .*
MODEL FAMILY:       Seagate Samsung SpinPoint M9T
ATTRIBUTE OPTIONS:  None preset; no -v options are required.

Best Answer

Thanks for this idea. I had been struggling with this problem for a few days. As I am not used to write bash scripts I rewrote it in python3. Maybe somebody finds it useful:

import subprocess
import time

drives_to_check = ['ada3', 'ada4', 'ada5']
no_sleep_hours = ['00', '01']
seconds = 600

if time.strftime("%H") in no_sleep_hours:
    exit()

o = subprocess.check_output(f'/usr/sbin/iostat -x -z -d {seconds} 2', shell=True)

for drive in drives_to_check:
    if drive not in o.decode().split('extended')[-1]:
        p = subprocess.check_output(f'/sbin/camcontrol cmd {drive} -a "E5 00 00 00 00 00 00 00 00 00 00 00" -r -', shell=True)
        if p.decode()[27:29] != '00':
            q = subprocess.check_output(f'/usr/local/sbin/ataidle -s /dev/{drive}', shell=True)

My small add-ons were: you can add hours to no_sleep_hours when you don't want the script to run. And you have to add the drives you want to check to "drives_to_check" so you can exclude drives that should not do a spindown. Maybe you would have to adjust the paths for iostat and ataidle, these are the paths used in FreeNAS. You can find your paths with: which adaidle or which iostat. You can add it to cron with */15 * * * * /usr/local/bin/python3 /path/to/the/folder/check_disk_usage_and_spindown.py