18

I'm currently setting up a home-server using a Raspberry Pi with an external hard-disk connected via usb. However, my hard-drive will never spin down when being idle.

I tried already the hints provided at raspberrypi.org ... without any success.

1.)

sudo hdparm -S5 /dev/sda

returns

/dev/sda:
 setting standby to 5 (25 seconds)
SG_IO: bad/missing sense data, sb[]:  70 00 04 00 00 00 00 0a 00 00 00 00 44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

2.)

sudo hdparm -y /dev/sda

returns

/dev/sda:
 issuing standby command
SG_IO: bad/missing sense data, sb[]:  70 00 04 00 00 00 00 0a 00 00 00 00 44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

...and 3.)

sudo sdparm --flexible --command=stop /dev/sda

returns

/dev/sda: HDD         1234

... without spin-down of the drive.

I use the following hardware:

  • Inateck FDU3C-2 dual Ports USB 3.0 HDD docking station
  • Western Digital WD10EZRX Green 1TB

Is it possible, that the sent spin-down-signals are somewhere overwritten/lost/ignored?

3
  • 1
    Update: The menioned Inateck docking station has a functionality to clone hard drives, providing a master/source and a slave/sink port for HDDs. When plugging the HDD to the slave port the commands, mentioned above, workout. This limits the problem of missing spin-down to the master port.
    – user258346
    Commented Oct 15, 2013 at 16:54
  • 1
    If you think this is solution, you should accept your own solution. Corny though it may seem, it is useful for future readers with the same problem. Commented Oct 22, 2013 at 11:20
  • 2
    You do realize, of course, that the command you use in your script is the very same you stated was not working, right? hdparm -y /dev/sda... Commented Apr 22, 2014 at 7:42

5 Answers 5

5

I didn't have luck with hd-idle; it ran but didn't function. I ended up writing the script below:

#!/bin/bash
# This script looks for recent disk access, and if nothing has changed, puts /dev/"drive" into spindown mode.
# This should be used only is the hdparm power management function is not working.
# Call this script with cron or manually as desired
#
#
#
# Change which drive this script looks at by changing the drive variable below:
drive="sda"
#
#
current=`date`
caller=$(ps ax | grep "^ *$PPID" | awk '{print $NF}')
filename="/tmp/diskaccess.txt"
if [ -f "$filename" ]; then
    stat_old=`cat "$filename" | tr -dc "[:digit:]"`
    stat_new=`cat /sys/block/"$drive"/stat | tr -dc "[:digit:]"`
    if [ "$stat_old" == "$stat_new" ]; then
        stat="0"
        echo "The disk hasn't been used; spinning down /dev/$drive"
        echo $stat_old
        hdparm -y /dev/$drive > /dev/null
    else
        stat="1"
        echo $stat_old
        echo $stat_new
        echo "The drive has been used..."
        echo $stat_new > $filename
    fi
else
    echo "/tmp/diskaccess.txt file does not exist; creating it now."
    echo $stat_new > $filename
fi
echo $stat " - " $drive " - " $current " - by: " $caller >> /tmp/diskaccesslog.txt
2
  • 5
    I thought hdparm -y didn't work. Commented Jul 19, 2014 at 5:21
  • Thanks, works perfectly. My WD blue harddisk spins down now, when not used. What is a reasonable intervall for cron to call the script, in your opinion? I call it every 15min for now.
    – Tarator
    Commented Jan 17, 2019 at 5:26
5

Yes, it is possible but will require some custom development work and not trivial and the code is going to be specific to the USB->SATA bridge chip INSIDE of your enclosure.

The deal is that the USB bridge serves as more than an electrical convertor. A USB-attached HDD emulates a SCSI drive which has a different command set. While the standard read/write/seek commands translate all the time the more exotic spin up/down do not. Most chips won't do that. Furthermore there is NOT a universal chip level API. So If I wrote the code I would have to have a programming manual for the USB bridge chip.

Bottom line, unless you have programming specifics on the chip and are familiar with the ATA and SCSI instruction set and encapsulating pass-through commands, then you're just going to have to do without. Too much work and no standard.

5

It is entirely possible that the signals you are sending are neglected. You did not provide the output of

sudo hdparm -I /dev/sdX

which would have told us the disk capabilities, but many disks simply do not respond to these commands.

Luckily, there is a very convenient utility, hd-idle, which you can download from here, allowing you to force a disk spin down after some specified lapse of time. The program has been developed especially for Debian, (but it works on Linux in general), so that its installation should be very easy to you. I just hope it also works on an ARM architecture, something which I cannot test.

Edit: it compiles and installs correctly on raspbian.

0

I'm using Raspberry Pi 4 and I could not get the drive to spin down. With hdparm -y I could get the disk to sleep for just a split second before it spins up again. I got a lot of read/writes on the disk while the disk was newly formatted with no data!

But the solution, which I haven't seen on the internet yet, is to use btrfs instead of ext4. This will engage the spin down setting on my Seagate drive (set with Seagate Dashboard).

0

I did some changes to the otherwise nice script posted by user300457.

Changes:

  1. When calling the script, add the drive as parameter ("sdb" for example). This makes it possible for the script to control more than one drive (just add the script several times with different drives to the crontab).
  2. I needed to be able to check, if the drive is in standby mode or not (in another unrelated application), but when checking the status, the original script thinks that the drive has changed. This effectively means that the drive would never spin down, if the status was checked regularly. So... the script is updated to be able to handle checking the current state.
  3. A cleaner log file tracking only when the drive spins up and down is generated in /var/log/hdd_spindown.log

The script is included below with comments describing how to use it.

I hope, this is useful to someone :-)

#!/bin/bash
# This script looks for recent disk access, and if nothing has changed, puts the drive into spindown mode
#
# 1. Copy the script to /root:
#      sudo cp hdd_spindown.sh /root
#
# 2. Add the script to crontab:
#      sudo crontab -e
#
# 3. Add the following line to the crontab:
#      */30 *   *   *   *  /root/hdd_spindown.sh >> /var/log/hdd_spindown.log <drive name> 2>&1
#    where <drive name> could be "sda", "sdb" etc. 
#
# 4. Reload crontab:
#      sudo service cron reload
#
# This will run the script every 30 minutes - i.e. spin down the drive when not being accessed for 30 to 60 minutes
#
# A file logging the spinups/downs is created in /var/log/hdd_spindown.log

drive="$1"
current_spin_state=$(/usr/sbin/hdparm -C /dev/$drive | awk '/state/{print $NF}')

# If the drive is already in standby mode, there is no need to do more
if [ "$current_spin_state" != "standby" ]; then
    current_time=$(date +"%Y-%m-%d %T")
    script_name=$(basename -- "$0")
    filename="/tmp/${script_name}_${drive}_status.txt"
    current_sectors=$(cat /sys/block/"$drive"/stat | awk '{print $3,$7}')

    if [ -f "$filename" ]; then
        previous_drive_status=$(cat "$filename")
        previous_spin_state=$(echo $previous_drive_status | awk '{print $1}')
        previous_sectors=$(echo $previous_drive_status | awk '{print $2,$3}')

        # If the drive has just spun up store new state and add to log
        if [ "$current_spin_state" != "$previous_spin_state" ]; then
            echo "$current_time /dev/$drive has spun up since the last check"
            echo "$current_spin_state $current_sectors" > $filename
        else 
            # Check if drive sectors have been read or written to 
            if [ "$current_sectors" == "$previous_sectors" ]; then
                # If nothing changed, spin down the drive
                echo "$current_time Spinning down /dev/$drive"
                /usr/sbin/hdparm -y /dev/$drive > /dev/null
                echo "standby $current_sectors" > $filename
            else
                # If something changed, just store the new drive status
                echo "$current_spin_state $current_sectors" > $filename
            fi
        fi
    else
        echo "$current_time File $filename does not exist - creating it now"
        echo "$current_spin_state $current_sectors" > $filename
    fi
fi

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .