2020-08-24 06:44:05 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
let
|
|
|
|
inherit (lib) mkEnableOption mkIf mkOption types;
|
|
|
|
|
|
|
|
cfg = config.hardware.sata.timeout;
|
|
|
|
|
|
|
|
buildRule = d:
|
|
|
|
lib.concatStringsSep ", " [
|
|
|
|
''ACTION=="add"''
|
|
|
|
''SUBSYSTEM=="block"''
|
|
|
|
''ENV{ID_${lib.toUpper d.idBy}}=="${d.name}"''
|
|
|
|
''TAG+="systemd"''
|
|
|
|
''ENV{SYSTEMD_WANTS}="${unitName d}"''
|
|
|
|
];
|
|
|
|
|
|
|
|
devicePath = device:
|
|
|
|
"/dev/disk/by-${device.idBy}/${device.name}";
|
|
|
|
|
|
|
|
unitName = device:
|
|
|
|
"sata-timeout-${lib.strings.sanitizeDerivationName device.name}";
|
|
|
|
|
|
|
|
startScript =
|
|
|
|
pkgs.writeShellScript "sata-timeout.sh" ''
|
|
|
|
set -eEuo pipefail
|
|
|
|
|
|
|
|
device="$1"
|
|
|
|
|
|
|
|
${pkgs.smartmontools}/bin/smartctl \
|
|
|
|
-l scterc,${toString cfg.deciSeconds},${toString cfg.deciSeconds} \
|
|
|
|
--quietmode errorsonly \
|
|
|
|
"$device"
|
|
|
|
'';
|
|
|
|
|
|
|
|
in
|
|
|
|
{
|
|
|
|
meta.maintainers = with lib.maintainers; [ peterhoeg ];
|
|
|
|
|
|
|
|
options.hardware.sata.timeout = {
|
|
|
|
enable = mkEnableOption (lib.mdDoc "SATA drive timeouts");
|
|
|
|
|
|
|
|
deciSeconds = mkOption {
|
2021-10-03 16:06:03 +00:00
|
|
|
example = 70;
|
2020-08-24 06:44:05 +00:00
|
|
|
type = types.int;
|
|
|
|
description = lib.mdDoc ''
|
|
|
|
Set SCT Error Recovery Control timeout in deciseconds for use in RAID configurations.
|
|
|
|
|
|
|
|
Values are as follows:
|
|
|
|
0 = disable SCT ERT
|
|
|
|
70 = default in consumer drives (7 seconds)
|
|
|
|
|
|
|
|
Maximum is disk dependant but probably 60 seconds.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
drives = mkOption {
|
|
|
|
description = lib.mdDoc "List of drives for which to configure the timeout.";
|
|
|
|
type = types.listOf
|
|
|
|
(types.submodule {
|
|
|
|
options = {
|
|
|
|
name = mkOption {
|
|
|
|
description = lib.mdDoc "Drive name without the full path.";
|
|
|
|
type = types.str;
|
|
|
|
};
|
|
|
|
|
|
|
|
idBy = mkOption {
|
|
|
|
description = lib.mdDoc "The method to identify the drive.";
|
|
|
|
type = types.enum [ "path" "wwn" ];
|
|
|
|
default = "path";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
services.udev.extraRules = lib.concatMapStringsSep "\n" buildRule cfg.drives;
|
|
|
|
|
|
|
|
systemd.services = lib.listToAttrs (map
|
|
|
|
(e:
|
|
|
|
lib.nameValuePair (unitName e) {
|
|
|
|
description = "SATA timeout for ${e.name}";
|
|
|
|
wantedBy = [ "sata-timeout.target" ];
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "oneshot";
|
|
|
|
ExecStart = "${startScript} '${devicePath e}'";
|
|
|
|
PrivateTmp = true;
|
|
|
|
PrivateNetwork = true;
|
|
|
|
ProtectHome = "tmpfs";
|
|
|
|
ProtectSystem = "strict";
|
|
|
|
};
|
|
|
|
}
|
|
|
|
)
|
|
|
|
cfg.drives);
|
|
|
|
|
|
|
|
systemd.targets.sata-timeout = {
|
|
|
|
description = "SATA timeout";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|