4

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?

  • PUIS doesn't prevent the HDD from powering up initially, but the HDD will go to sleep when not in use, and the OS needs to know to power the HDD back on otherwise it will simulate a drive failure, and the OS hang up waiting on a file that will never come. I'm not certain of the exact details, just that initially it acts like it's not on even when it is. Also you can set this as a flag on the HDD, it doesn't just work via jumpers. – JFA Oct 28 '16 at 19:55
2

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).

3

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.

  • 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. – onlinespending Apr 6 '18 at 15:27
  • This looks like it could work on a laptop, but might be more trouble than it's worth... – Michael Jul 7 '18 at 17:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.