at 25.11-pre 2.7 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 inherit (lib) 9 mkEnableOption 10 mkIf 11 mkOption 12 types 13 ; 14 15 cfg = config.hardware.sata.timeout; 16 17 buildRule = 18 d: 19 lib.concatStringsSep ", " [ 20 ''ACTION=="add"'' 21 ''SUBSYSTEM=="block"'' 22 ''ENV{ID_${lib.toUpper d.idBy}}=="${d.name}"'' 23 ''TAG+="systemd"'' 24 ''ENV{SYSTEMD_WANTS}="${unitName d}"'' 25 ]; 26 27 devicePath = device: "/dev/disk/by-${device.idBy}/${device.name}"; 28 29 unitName = device: "sata-timeout-${lib.strings.sanitizeDerivationName device.name}"; 30 31 startScript = pkgs.writeShellScript "sata-timeout.sh" '' 32 set -eEuo pipefail 33 34 device="$1" 35 36 ${pkgs.smartmontools}/bin/smartctl \ 37 -l scterc,${toString cfg.deciSeconds},${toString cfg.deciSeconds} \ 38 --quietmode errorsonly \ 39 "$device" 40 ''; 41 42in 43{ 44 meta.maintainers = with lib.maintainers; [ peterhoeg ]; 45 46 options.hardware.sata.timeout = { 47 enable = mkEnableOption "SATA drive timeouts"; 48 49 deciSeconds = mkOption { 50 example = 70; 51 type = types.int; 52 description = '' 53 Set SCT Error Recovery Control timeout in deciseconds for use in RAID configurations. 54 55 Values are as follows: 56 0 = disable SCT ERT 57 70 = default in consumer drives (7 seconds) 58 59 Maximum is disk dependant but probably 60 seconds. 60 ''; 61 }; 62 63 drives = mkOption { 64 description = "List of drives for which to configure the timeout."; 65 type = types.listOf ( 66 types.submodule { 67 options = { 68 name = mkOption { 69 description = "Drive name without the full path."; 70 type = types.str; 71 }; 72 73 idBy = mkOption { 74 description = "The method to identify the drive."; 75 type = types.enum [ 76 "path" 77 "wwn" 78 ]; 79 default = "path"; 80 }; 81 }; 82 } 83 ); 84 }; 85 }; 86 87 config = mkIf cfg.enable { 88 services.udev.extraRules = lib.concatMapStringsSep "\n" buildRule cfg.drives; 89 90 systemd.services = lib.listToAttrs ( 91 map ( 92 e: 93 lib.nameValuePair (unitName e) { 94 description = "SATA timeout for ${e.name}"; 95 wantedBy = [ "sata-timeout.target" ]; 96 serviceConfig = { 97 Type = "oneshot"; 98 ExecStart = "${startScript} '${devicePath e}'"; 99 PrivateTmp = true; 100 PrivateNetwork = true; 101 ProtectHome = "tmpfs"; 102 ProtectSystem = "strict"; 103 }; 104 } 105 ) cfg.drives 106 ); 107 108 systemd.targets.sata-timeout = { 109 description = "SATA timeout"; 110 wantedBy = [ "multi-user.target" ]; 111 }; 112 }; 113}