HDD Power-Up in Standby: prevent from spinning up

8,152

Solution 1

I searched for the exact thing a few years ago, for Linux Mint and an old HD that was only used for occasional data storage too.

The solutions I found (don't have the links handy anymore) were the same that it looks like you found: a few hard drives might have a jumper setting that should cause the drive to stay sleeping / not spin up at boot time. But it did not work, my results were the exact same as yours, it still spins up at boot. I didn't find any fixes for that, for all I know it was the BIOS/GRUB/linux, separately or working together, or just the HD itself that wasn't listening.

I did some "hot plug"/"hot swap" testing, connecting the power to a (SATA) hard drive while the computer was up & running. It generated some log entries (dmesg & /var/log/syslog) and worked successfully. Then when done with the drive (sync, unmount, sleep/hdparm -y) unplugging the power again. Worked! But it apparently needs a compatible motherboard & OS, so YMMV.

However, pulling the power plug to use the drive isn't very convenient or easy, so I wired up a double-pole single-throw switch - DPST, Wikipedia has a diagram - has 4 terminals, for the 2 separate power wires (12V & 5V?), to keep them separate and turn them both on/off at the same time. Connecting it to the HD's power, I can turn on & off the drive whenever needed.

Update:

Hot swapping used to work on Linux Mint 14/15/16, but for some reason it quit working on 17 & up, I'm guessing some kernel change stopped it. Now hot swapping a hard drive on only appears to work, but the drive reads as corrupted, only a power-on reboot gets it working successfully. Maybe there's an easy way to get it working again, or some recompiled kernel is required with some special switches...?

Update 2

Hot swapping is apparently working again for Ubuntu 16.04 (Mint 18 should work too).

Solution 2

The linux kernel spins up the drive. Take a look at these lines from drivers/ata/libata-core.c (kernel source code):

if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) {
    tried_spinup = 1;
    /*
     * Drive powered-up in standby mode, and requires a specific
     * SET_FEATURES spin-up subcommand before it will accept
     * anything other than the original IDENTIFY command.
     */
    err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0);
    if (err_mask && id[2] != 0x738c) {
        rc = -EIO;
        reason = "SPINUP failed";
        goto err_out;
    }
    /*
     * If the drive initially returned incomplete IDENTIFY info,
     * we now must reissue the IDENTIFY command.
     */
    if (id[2] == 0x37c8)
        goto retry;
}

If you comment these lines and recompile the kernel, the drives will not spin up. Then you'll need a command to spin them up, for example when hdparm disables PUIS it spins up the drive. Take a look at this link.

That's all I know about PUIS.

Edit: I just noticed that your drive spins up before the grub screen: this means the motherboard is spinning up the drive. You can try disabling the corresponding sata port in your BIOS/UEFI configuration, if it allows such a thing, and try again. If it's working, the drive will remain still until the kernel spins it up, after the grub screen and before the user login prompt, and you can find in dmesg

ataX.00: failed to IDENTIFY (SPINUP failed, err_mask=0x4)
ataX.00: revalidation failed (errno=-5)
ataX: SATA link up 6.0 Gbps (SStatus 133 SControl 300)

At this point, if you hack the kernel, the drive will not spin up at all like I described earlier.

Edit 2: I found a better command to spin up the disk:

sg_sat_set_features --feature=7 /dev/sdX

it's part of the sg3_utils package, requires root privileges, but spins up the disk nicely. Post updated on the arch linux forum, that's my final solution for now. A small summary of that post:

  • if your PUIS enabled disk spins up before boot loader screen, try disabling the corresponding sata port, or try a PCI-ex sata controller card
  • recompile the kernel to disable the command that spins up the disks in PUIS state
  • use sg_sat_set_feature to spin up the disk
  • rescan sata port to gain access to partitions

Edit 3: Some kind soul wrote a patch, on the archlinux forum: https://bbs.archlinux.org/viewtopic.php?pid=1855326#p1855326

Transcription:

If we can't avoid patching libata, might as well disable PUIS drives on boot to get rid of endless error messages. The downside is we've to tell the kernel to re-enable them on request, since userspace tools like sg_sat* expect an entry inside /dev.

Take a look at my tentative patch for that feature. I hope someone will consider sparing his time to rework it to kernel standards and propose it upstream. I wrote the patch against clean v4.19.56.

Remember to set "libata.spinup_control=0" kernel parameter in the bootloader after recompiling the module and rebuilding your initramfs image!

Then you should

echo 1 > /sys/module/libata/parameters/spinup_control

and issue a rescan to the drive you want to spin up.

echo '- - -' > devices/pci0000:00/0000:00:1f.2/ata4/host3/scsi_host/host3/scan

--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -171,6 +171,10 @@ static int atapi_an;
 module_param(atapi_an, int, 0444);
 MODULE_PARM_DESC(atapi_an, "Enable ATAPI AN media presence notification (0=0ff [default], 1=on)");

+static int spinup_control = 1;
+module_param(spinup_control, int, 0644);
+MODULE_PARM_DESC(spinup_control, "Spin up standby drives (0=PUIS drives disabled, 1=standby drives can spin up [default])");
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
 MODULE_LICENSE("GPL");
@@ -1978,28 +1982,40 @@ retry:
            goto err_out;
    }

-   if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) {
+   /*
+    * My drives indicate with 0x738c that media is ready when PUIS
+    * is enabled, in conflict with the relevant standards.
+    * The compliant behavior therefore prevents spun-up and ready
+    * drives from being recognized on reboot.
+    * I had no choice but to remove "|| id[2] == 0x738c))".
+    */
+   if (!tried_spinup && (id[2] == 0x37c8)) {
        tried_spinup = 1;
        /*
         * Drive powered-up in standby mode, and requires a specific
         * SET_FEATURES spin-up subcommand before it will accept
         * anything other than the original IDENTIFY command.
         */
-       err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0);
-       if (err_mask && id[2] != 0x738c) {
-           rc = -EIO;
-           reason = "SPINUP failed";
-           goto err_out;
-       }
-       /*
-        * If the drive initially returned incomplete IDENTIFY info,
-        * we now must reissue the IDENTIFY command.
-        */
-       if (id[2] == 0x37c8)
+       if (spinup_control) {
+           err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0);
+           if (err_mask) {
+               rc = -EIO;
+               reason = "SPINUP failed";
+               goto err_out;
+           }
+           /*
+            * If the drive initially returned incomplete IDENTIFY info,
+            * we now must reissue the IDENTIFY command.
+            */
            goto retry;
+       } else {
+           dev->horkage |= ATA_HORKAGE_DISABLE;
+           ata_dev_notice(dev, "horkage modified (drive powered-up in standby)\n");
+       }
    }

-   if ((flags & ATA_READID_POSTRESET) &&
+   if (spinup_control && (flags & ATA_READID_POSTRESET) &&
        (class == ATA_DEV_ATA || class == ATA_DEV_ZAC)) {
        /*
         * The exact sequence expected by certain pre-ATA4 drives is:

Credit to az12shareart, who registerd to arch linux forum just to write this, I think.

Share:
8,152

Related videos on Youtube

Finwood
Author by

Finwood

Student of Mechanical Engineering and Computer Science at Clausthal University of Technology, Germany passionate about Python, Linux, Biking, electronics and quadrocopters I speak English, German and basic Finnish. Write me an E-Mail: [email protected]

Updated on September 18, 2022

Comments

  • Finwood
    Finwood almost 2 years

    On my Linux Mint 17.1 system I am using a Western Digital WD20EZRX HDD for backup. To minimize power consumption and to extend drive endurance, I want the HDD to normally be in spun-down standby state, and to only spin up when explicitly needed.

    This can be achieved in two ways: The trivial approach would be setting the HDD into standby mode manually using hdparm -y /dev/sdb. However, the disadvantage would be the drive spinning up during startup until being set to sleep again by a script. Therefore I would like to let the drive Power-Up in Standby, PUIS, to prevent it from spinnung up in the first time.

    Some WD drives support PUIS, although it is called PM2, Power Management 2 Mode by Western Digital. This feature is being enabled using Jumpers, as described in this WD Knowledge Base article. The result of this configuration can be verified using hdparm:

    # hdparm -I /dev/sdb | grep "Power-Up In Standby"
       *    Power-Up In Standby feature set
    

    However, the drive still spins up during boot, even before the Grub startup-screen is being displayed. Could this be a misconfigured Bootloader, which is looking for operating systems on all connected HDDs?

  • onlinespending
    onlinespending about 6 years
    this is very informative. What I'd like to do is have a headless Linux server that use as a NAS, but that will go into S3 standby mode and upon waking up not spin up the hard drives. Your suggestions can likely get me that far. But then I'd like the system to spin up the drive when it's actually accessed without needing to manually issue that sg_sat_set_features command. But do so automatically on demand. Any suggestions? Thanks.
  • Michael
    Michael almost 6 years
    This looks like it could work on a laptop, but might be more trouble than it's worth...