mysurik.ru

SCSI rescan — как я воскрешал диск

Бывают дни, когда всё идёт не по плану. А бывают дни, когда ты перезагружаешь сервер и понимаешь, что один из дисков просто исчез. Это история про такой день.

Всё началось с рядового обновления. Proxmox 8.2, очередной патч ядра 6.8, штатная перезагрузка. Я залил кофе, открыл ноутбук, подключился по SSH — рутина. Запустил lsblk и обомлел: sdd пропал. Три диска из четырёх. Второй порт SATA показывал пустоту.

У меня дома стоит сервер на базе ASRock B450M Steel Legend. Процессор — Ryzen 5 3600, оперативки 32 ГБ ECC. Да, ECC на B450 официально не поддерживается, но с Ryzen PRO работает. Четыре SATA порта на чипсете B450, к ним подключены: SSD Samsung 870 EVO под систему и три WD Blue на 1 ТБ каждый в ZFS raidz2. Один из WD Blue просто исчез. Ни в lsblk, ни в fdisk -l, ни в /proc/partitions. Даже в BIOS при следующей перезагрузке он не определился, хотя до этого работал стабильно больше года. Мысленно я уже попрощался с терабайтом конфигов, бекапов и проектов.

Я проверил всё, что мог. Переткнул SATA кабель. Поменял питание. Переставил диск на другой SATA порт. Перезагрузился ещё раз. Ничего. Тогда я полез в dmesg

# dmesg | grep -E 'ata[0-9]+'
ata1: SATA link up 6.0 Gbps (SStatus 113, SControl 300)
ata2: SStatus 0, SControl 0
ata3: SATA link up 6.0 Gbps (SStatus 113, SControl 300)
ata4: SATA link up 6.0 Gbps (SStatus 113, SControl 300)

Смотрите: ata2 — второй SATA порт — показывает SStatus 0. Это значит, что физического соединения нет. Не таймаут, не ошибка, а буквально «нет устройства». Для тех, кто не в курсе: SStatus (SCR0 в спецификации AHCI) отображает текущее состояние SATA-линка. 0 — детекта нет. 113 — всё отлично, линк на полной скорости. Либо диск реально умер, либо контроллер его не опрашивает.

Тут надо сделать отступление. Контроллеры AHCI на современных материнках могут вести себя по-разному при загрузке. В идеале они опрашивают все SATA порты при старте, находят устройства и передают их ядру. Но на практике всё зависит от таймингов. Если диск не успел инициализироваться к моменту опроса — он остаётся невидимым. Это не баг, это особенность бюджетных чипсетов.

Решение есть, и оно проще, чем кажется. SATA диски на уровне ядра Linux работают через прослойку SCSI. Можно вручную сказать ядру: «друг, пересканируй шину, может, там что-то появилось». Команда:

echo "- - -" > /sys/class/scsi_host/host*/scan

Три дефиса — это channel, target и lun. Звёздочка вместо номера хоста — чтобы не гадать, к какому контроллеру привязан пропавший диск. Можно пересканировать и конкретный хост: host0, host1, host2, host3 — по одному.

Секунда после команды — и lsblk показывает sdd. Диск жив. Я сразу проверил SMART — PASSED. Все данные на месте. Ни одного битого сектора. Весь терабайт цел и невредим.

Почему это сработало? Когда ядро загружается, оно опрашивает SCSI-хосты один раз — при старте. Если устройство не ответило в этот момент (например, питание на SATA порт подаётся с задержкой, или контроллер не успел инициализироваться), оно не появится в системе. Команда echo "- - -" > /sys/class/scsi_host/host*/scan заставляет ядро сделать этот опрос заново — прямо сейчас, на живом сервере, без перезагрузки.

После этого случая я сел и написал небольшой скрипт проверки дисков при старте. Он лежит в /usr/local/bin/check-disks.sh и делает простые вещи: проверяет количество дисков через lsblk, если кого-то не хватает — запускает рескан, проверяет dmesg на ошибки ata, смотрит SMART статус. Если что-то не так — шлёт уведомление через ntfy (настроил буквально на днях, кстати).

Вот основная часть скрипта:

#!/bin/bash
EXPECTED=4
COUNT=$(lsblk -d -o NAME | grep -c 'sd[a-z]')
if [ "$COUNT" -lt "$EXPECTED" ]; then
  echo "Expected $EXPECTED disks, found $COUNT. Rescanning..."
  echo "- - -" > /sys/class/scsi_host/host*/scan
  sleep 2
  COUNT=$(lsblk -d -o NAME | grep -c 'sd[a-z]')
  if [ "$COUNT" -eq "$EXPECTED" ]; then
    echo "Rescan successful. All disks present."
  else
    echo "Still missing disks after rescan."
  fi
fi

Я добавил его в cron @reboot, и теперь после каждой перезагрузки сервер сам проверяет, все ли диски на месте.

SMART я проверил сразу после рескана. Команда smartctl -a /dev/sdd показала: 18000 часов работы, 12 включений, 0 переназначенных секторов. Диск в отличном состоянии. Единственное, что насторожило — температура 42 градуса, но это для WD Blue нормально.

Ещё один важный момент. Если у вас на сервере ZFS или mdadm, рескан SCSI не повредит данные. После того, как диск появится в системе, ZFS сама подхватит его, если он был частью пула. У меня был raidz2 из трёх дисков — после рескана пул собрался сам, никаких ручных действий не потребовалось.

Пара вещей, которые я вынес из этой истории. Во-первых, не паниковать раньше времени. Диск не всегда умирает внезапно — чаще он просто не определился из-за таймингов питания или глюка контроллера. Во-вторых, SCSI-рескан — это безболезненная операция, которую можно делать сколько угодно раз на работающем сервере. В-третьих, не доверять старым блокам питания. Мой Chieftec на 500W честно отработал лет семь, но, видимо, пора на покой.

Что я теперь делаю иначе? Во-первых, после каждого ребута я смотрю вывод dmesg сразу, не дожидаясь, пока программа обнаружит проблему. Во-вторых, у меня теперь есть скрипт автоматической проверки. В-третьих, я планирую купить новый блок питания — maybe Seasonic или be quiet, чтоб не гадать, просядет ли линия при старте.

Если у вас на сервере Proxmox, и вы заметили пропажу диска после перезагрузки — не спешите его менять. SCSI-рескан может решить проблему за секунду. Если не помог — тогда уже копайте глубже: проверяйте кабели, питание, сам диск.

Кстати, есть ещё один трюк. Если нужно не просто пересканировать, а именно переинициализировать конкретный диск на уже известном хосте, можно уточнить target:

echo "0 0 0" > /sys/class/scsi_host/host2/scan

Но с wildcard через host* надёжнее — меньше шансов ошибиться номером порта.

Ещё полезная команда — посмотреть, какие SCSI-хосты вообще есть в системе:

ls /sys/class/scsi_host/

У меня, например, вывод показывает host0, host1, host2, host3 — четыре хоста на четыре SATA порта. Если копнуть глубже, можно посмотреть, какой драйвер за что отвечает:

# ls -l /sys/class/scsi_host/host0/device/driver
lrwxrwxrwx ... /sys/class/scsi_host/host0/device/driver -> ../../../../bus/pci/drivers/ahci

AHCI — это наш родной драйвер для SATA. Если у вас NVMe диски или SAS-контроллеры, там будут другие драйверы, но команда рескана работает так же.

После этой истории я стал относиться к SCSI-рескану как к магическому заклинанию из трёх дефисов. Сервер не видит диск? echo "- - -". Что-то странное с блочными устройствами? echo "- - -". Не пашет? Ну, тогда уже лезем в dmesg и smartctl.

Сохраните эту команду куда-нибудь в alias. Я, например, добавил в .bashrc:

alias disk-rescan='echo "- - -" | sudo tee /sys/class/scsi_host/host*/scan'

Когда-нибудь она спасёт ваш вечер, а может, и данные.

Конец этой истории я знал наперёд, но расскажу по порядку, потому что выводов из неё набралось больше, чем хотелось бы. Той ночью я понял, что спасает не магия, а понимание того, как устроен стек хранения. Давай разложу по полочкам, что именно произошло и как не наступать на те же грабли в будущем.

Сначала про то, почему диск «пропал» именно после перезагрузки. Дело в том, что AHCI-контроллер при старте системы опрашивает порты в строго определённом порядке и с очень коротким таймаутом. Если в этот момент диск ещё не успел поднять питание или контроллер сбоит — устройство просто не попадает в список. Это не поломка, это особенность бюджетных чипсетов вроде B450, где тайминги инициализации не идеальны. Производители это знают, поэтому и существует возможность пересканировать шину на лету.

Теперь про то, как я теперь проверяю диски после каждого ребута. Первым делом смотрю lsblk и сравниваю с ожидаемым количеством. Если кого-то не хватает — делаю рескан SCSI-шины. Если не помогло — смотрю dmesg на предмет ошибок ata, потом перебираю кабели и питание. Только после этого впадаю в панику и думаю про замену. Порядок важен: сначала бесплатные действия, потом уже деньги.

Отдельная тема — питание. Старый блок питания с просадками по линии 12V — это классическая причина «внезапно исчезнувших» дисков при старте. После того случая я измерил вольтметром напряжения под нагрузкой: на 12V было 11.7 вместо честных 12. Это в пределах допуска, но на границе. Для дисков на ZFS-пуле, где любое «моргание» питания может выкинуть устройство из массива, лучше иметь запас. Так что рекомендация про Seasonic или be quiet — не реклама, а итог изучения вопроса.

Что я понял про ZFS. Когда диск перестаёт отвечать, ZFS помечает его как degraded, но данные не теряет — raidz2 выдерживает два отказа. Но что важнее: если диск «воскрес» после рескана, пул сам вернёт его в строй без вмешательства. У меня после рескана zpool status показал «DEGRADED», а через пару минут после подхвата — снова ONLINE. Никаких ручных команд для возврата диска не потребовалось. Это сильная сторона ZFS, но и причина не паниковать заранее: пока raidz2 не «протёрся» до двух сломанных дисков, один пропавший — это временное неудобство, а не катастрофа.

Ещё я добавил в свой мониторинг проверку температуры и ошибок SATA. Смотрю через smartctl периодически: переназначенные сектора, ошибки CRC на интерфейсе, температуру. Если что-то начинает ползти вверх — это сигнал присматриваться к диску. Тот самый WD Blue показал за всё время ноль переназначенных секторов, но я всё равно поставил его под пристальный мониторинг — потому что 18 тысяч часов работы это уже почтенный возраст.

Отдельно про резервные копии. Даже с raidz2 я не расслабляюсь: массив защищает от отказа диска, но не от случайного удаления, шифровальщика или кривого обновления. Поэтому у меня есть и внешний бэкап на отдельный диск, и снапшоты ZFS по расписанию. Конфиги всех сервисов — в git. Всё это кажется избыточным, пока не приходит день, когда диск «пропадает», и ты с облегчением понимаешь, что данные в трёх местах.

Если совсем вкратце:
— Пропал диск после ребута? Сначала `echo «- — -» > /sys/class/scsi_host/host*/scan`, потом уже диагностика.
— Проверяй dmesg, а не только lsblk — там видно, определился ли линк.
— Не игнорируй старый блок питания — это частая причина «пропаж» при старте.
— Держи ZFS с избыточностью (raidz2/z2) и бэкапы в отдельном месте.
— Автоматизируй проверку дисков при загрузке — скрипт, который делает рескан и шлёт уведомление, экономит нервы.

Эта история научила меня главному: загадочные «пропажи» дисков чаще всего имеют банальное объяснение, и команда из трёх дефисов — первое, что стоит попробовать. Инструмент, который выглядит как магия, на деле просто просит ядро посмотреть на шину ещё раз. И он спасает терабайты данных, недвижимости и нервов. Сохрани этот alias в .bashrc — пригодится. Мне пригодился, и не раз.

Ваш комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *