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.
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 – 2016-10-28T19:55:03.600