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'

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

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

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