待机时硬盘上电:防止旋转

Fin*_*ood 5 linux boot hard-drive grub hdparm

在我的 Linux Mint 17.1 系统上,我使用 Western Digital WD20EZRX HDD 进行备份。为了最大限度地降低功耗并延长驱动器的耐用性,我希望 HDD 通常处于停转待机状态,并且仅在明确需要时才启动。

这可以通过两种方式实现: 简单的方法是使用 手动将 HDD 设置为待机模式hdparm -y /dev/sdb。但是,缺点是驱动器在启动期间旋转,直到被脚本再次设置为休眠。因此,我想让驱动器在 StandbyPUIS 中通电,以防止它在第一次启动。

一些 WD 驱动器支持 PUIS,尽管它被Western Digital称为PM2,即电源管理 2 模式。使用跳线启用此功能, 如此 WD 知识库文章 中所述。可以使用hdparm以下方法验证此配置的结果:

# hdparm -I /dev/sdb | grep "Power-Up In Standby"
   *    Power-Up In Standby feature set
Run Code Online (Sandbox Code Playgroud)

但是,即使在 Grub 启动屏幕显示之前,驱动器在启动过程中仍会旋转。这可能是一个错误配置的引导加载程序,它在所有连接的 HDD 上寻找操作系统?

Veo*_*eon 7

Linux 内核启动驱动器。看一下 drivers/ata/libata-core.c (内核源代码)中的这些行:

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;
}
Run Code Online (Sandbox Code Playgroud)

如果您注释这些行并重新编译内核,驱动器将不会旋转。然后,您需要一个命令来启动它们,例如,当 hdparm 禁用 PUIS 时,它会启动驱动器。看看这个链接。

这就是我对 PUIS 的全部了解。

编辑: 我刚刚注意到您的驱动器在 grub 屏幕之前旋转:这意味着主板正在旋转驱动器。您可以尝试在 BIOS/UEFI 配置中禁用相应的 SATA 端口(如果允许),然后重试。如果它工作正常,驱动器将保持静止,直到内核旋转它,在 grub 屏幕之后和用户登录提示之前,您可以在 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)
Run Code Online (Sandbox Code Playgroud)

此时,如果您破解内核,驱动器将根本不会像我之前描述的那样旋转。

编辑2: 我找到了一个更好的命令来旋转磁盘:

sg_sat_set_features --feature=7 /dev/sdX
Run Code Online (Sandbox Code Playgroud)

它是 sg3_utils 包的一部分,需要 root 权限,但可以很好地旋转磁盘。 在 arch linux 论坛上更新的帖子,这是我目前的最终解决方案。该帖子的一个小摘要:

  • 如果启用 PUIS 的磁盘在引导加载程序屏幕之前旋转,请尝试禁用相应的 SATA 端口,或尝试使用 PCI-ex SATA 控制器卡
  • 重新编译内核以禁用在 PUIS 状态下旋转磁盘的命令
  • 使用 sg_sat_set_feature 启动磁盘
  • 重新扫描SATA端口以访问分区

编辑3: 某个好心人在archlinux论坛上写了一个补丁:https://bbs.archlinux.org/viewtopic.php ?pid=1855326#p1855326

转录:

如果我们无法避免修补 libata,不妨在启动时禁用 PUIS 驱动器,以摆脱无尽的错误消息。缺点是我们必须告诉内核根据请求重新启用它们,因为像 sg_sat* 这样的用户空间工具需要 /dev 中的一个条目。

看看我针对该功能的暂定补丁。我希望有人会考虑抽出时间将其重新设计为内核标准并向上游提出。我针对 clean v4.19.56 编写了补丁。

重新编译模块并重建 initramfs 映像后,请记住在引导加载程序中设置“libata.spinup_control=0”内核参数!

那么你应该

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

并对您想要启动的驱动器发出重新扫描。

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:
Run Code Online (Sandbox Code Playgroud)

感谢 az12shareart,我认为他注册到 arch linux 论坛只是为了写这篇文章。


Xen*_*050 3

几年前,我搜索了确切的东西,寻找 Linux Mint 和一个也仅用于偶尔数据存储的旧 HD。

我找到的解决方案(不再有方便的链接)与您发现的相同:一些硬盘驱动器可能有一个跳线设置,该设置应该导致驱动器保持睡眠状态/在启动时不旋转。它不起作用,我的结果和你的完全一样,它仍然在启动时旋转。我没有找到任何解决方案,据我所知,这是 BIOS/GRUB/linux,单独或一起工作,或者只是 HD 本身没有监听。

我做了一些“热插拔”/“热插拔”测试,在计算机启动和运行时将电源连接到(SATA)硬盘驱动器。它生成了一些日志条目(dmesg & /var/log/syslog)并成功运行。然后,当完成驱动器(同步、卸载、睡眠/ hdparm -y)后,再次拔掉电源。成功了!但它显然需要兼容的主板和操作系统,所以 YMMV。

然而,拔掉电源插头来使用驱动器并不是很方便或容易,所以我连接了一个双刀单掷开关 - DPST,维基百科有一个图表- 有 4 个端子,用于 2 条独立的电源线(12V & 5V?),将它们分开并同时打开/关闭它们。将其连接到硬盘的电源后,我可以在需要时打开和关闭硬盘。

更新:

热交换曾经在 Linux Mint 14/15/16 上工作,但由于某种原因它在 17 及更高版本上停止工作,我猜一些内核更改阻止了它。现在,热插拔硬盘似乎可以工作,但驱动器读取为已损坏,只有开机重新启动才能使其成功工作。也许有一种简单的方法可以让它再次工作,或者需要一些重新编译的内核和一些特殊的开关......?

更新2

热插拔显然在 Ubuntu 16.04 上再次起作用(Mint 18 也应该起作用)。