beeugene
13 просмотров0 комментариев+2

NVMe на Repka Pi 5: диск не определяется. История одной бессонной диагностики

TL;DR. Купил NVMe на 1 ТБ, вставил в Repka Pi 5 через кейс Argon NEO 5 — диск не виден вообще. Полвечера копался в логах, грешил на кривой SSD и кернел-патчи, а причина оказалась банальной: перевёрнутый шлейф на полторы минуты дела. Под катом — живой разбор, что я делал, где ошибался и как всё-таки завёл диск на ~757 МБ/с. Заодно простыми словами объясню страшные термины вроде PHY и LTSSM — чтобы вы не блуждали, как я.

Что вообще собирал и зачем #

Идея простая: Repka Pi 5 — одноплатник на Rockchip RK3588, у него есть слот PCIe. Хочу уйти с медленной microSD-карты на быстрый NVMe — система и данные должны летать. Комплект такой:

Компонент Модель
Платформа Repka Pi 5 (RK3588)
ОС Repka OS (Ubuntu 25.10), ядро 6.1.115.1-repka-pi5
Кейс Argon NEO 5 M.2 NVMe (форм-фактор Raspberry Pi 5 — совместим с Repka)
SSD CUSU CV3500Q 1TB, PCIe 3.0 ×4, контроллер Maxio, QLC

Кейс Argon NEO 5 — это не просто коробочка, а кейс со встроенной M.2-HAT-платой: в неё вставляется SSD, а к плате Repka шлейфом (гибким плоским кабелем, FPCFlexible Printed Circuit) тянется линия PCIe. Всё это должно работать «из коробки».

Собрал, подключил, включаю питание, жду загрузки... и ничего. Диска нет.

Диск исчез. Что делать? #

Первая мысль любого нормального человека: «наверное, SSD битый или несовместимый». Вторая: «может, кейс бракованный». Прежде чем нести обратно, решил проверить, что вообще видит сама плата. Это главный урок всей истории: не паникуй, читай логи.

Шаг 1. Есть ли устройство в системе? #

Самое простое — посмотреть список дисков:

lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,MODEL,TRAN

Вывод:

NAME         SIZE TYPE MOUNTPOINT MODEL TRAN
mmcblk1     14,8G disk                  mmc
└─mmcblk1p1 14,8G part /                mmc

Только карта mmcblk1 (та самая microSD, с которой грузится система). NVMe — пусто. Проверяю напрямую:

ls /dev/nvme*
# ls: cannot access '/dev/nvme*': No such file or directory

Файла устройства нет. Если бы файл был, а раздела нет — речь шло бы о разметке. Но файла нет — значит, диск не определился на самом нижнем уровне, на шине PCIe. Это важная развилка: проблема не в Linux, а в «железе» где-то ниже.

💡 Что такое /dev/nvme0 и /dev/nvme0n1?
В Linux всё оборудование — это файлы в /dev. nvme0 — это сам контроллер SSD (character device), а nvme0n1 — само «блочное» устройство, то есть диск, на который можно писать данные (n1 = namespace 1, грубо «логический диск» внутри NVMe). Нет этих файлов — ядро вообще не знает о существовании диска.

Шаг 2. Что говорит ядро? (Главный шаг) #

Если устройство не появилось, ядро почти всегда оставляет «улики» в логах. Читаем их:

dmesg | grep -iE "rk-pcie|nvme|fe150000"

💡 Что это за команда? dmesg выводит кольцевой буфер сообщений ядра — всё, что ядро рассказывало при загрузке и работе. grep -iE "..." оставляет только строки со словами rk-pcie, nvme или fe150000 (адрес PCIe-контроллера на RK3588). -i — игнорировать регистр, -E — несколько слов через |.

И вот что я вижу:

rk-pcie fe150000.pcie: host bridge /pcie@fe150000 ranges: ...
rk-pcie fe150000.pcie: PCIe Linking... LTSSM is 0x0
rk-pcie fe150000.pcie: PCIe Linking... LTSSM is 0x1
rk-pcie fe150000.pcie: PCIe Linking... LTSSM is 0x0
rk-pcie fe150000.pcie: PCIe Link Fail, LTSSM is 0x0, hw_retries=0
rk-pcie fe150000.pcie: failed to initialize host

Сердце упало: PCIe Link Fail. Линк не поднялся. Но что это всё значит? Прежде чем паниковать, разберёмся в терминах.

Лирическое отступление: PCIe, PHY и LTSSM простыми словами #

PCIe — это шина, по которой быстрые устройства общаются с процессором. Чтобы два устройства «поговорили», они должны сначала договориться, на какой скорости и по каким правилам работать. Этот процесс называется link training (обучение связи).

За физическую часть отвечает PHY (Physical Layer, физический уровень). Грубо говоря, PHY — это «модем» внутри контроллера: он превращает цифровые байты в электрические сигналы на проводах и обратно. Если провода подключены криво — PHY ничего не разберёт.

Сам процесс договорённостей управляется автоматом состояний с жутким именем LTSSMLink Training and Status State Machine. У него есть шаги:

  • 0x0Detect: «есть ли вообще кто-то на другом конце провода?»
  • 0x1Polling: «о, вроде кто-то есть, давай проверим сигнал»
  • и дальше — согласование скорости, ширины канала, переход в рабочее состояние L0.

Теперь перечитываем лог осмысленно:

PCIe Linking... LTSSM is 0x0   ← никого не вижу
PCIe Linking... LTSSM is 0x1   ← о! кто-то моргнул
PCIe Linking... LTSSM is 0x0   ← опять никого
PCIe Link Fail, LTSSM is 0x0   ← сдаюсь, линк не удался

PHY видел какую-то активность (0x1), но дальше дело не пошло. Это очень важная подсказка: если бы диска физически не было, LTSSM застрял бы в 0x0 навсегда. А тут «моргок» 0x1 — значит, что-то на другом конце есть, но сигнал доходит искажённым, и договориться не получается.

Шаг 3. Питание на слот вообще подаётся? #

Дальше я начал грешить на питание. Проверяю регуляторы напряжения:

for r in /sys/class/regulator/*; do
  n=$(basename $r); st=$(cat $r/state 2>/dev/null); nm=$(cat $r/name 2>/dev/null)
  case "$nm $n" in *pcie*) echo "$n : name=$nm state=$st";; esac
done

Вывод:

regulator.8 : name=vcc3v3_pcie30 state=disabled

disabled — и тут я на секунду обрадовался: «Ага, питание выключено, вот и не работает!». Но копнув глубже в device tree, понял, что это нормально: регулятор vcc3v3_pcie30 подаёт 3.3 В на слот только в момент инициализации, а после неудачной попытки ядро его отключает. То есть disabled — следствие, а не причина. Ложный след.

💡 Что такое device tree (DT)?
Это текстовое (компилируемое в бинарник) описание всего железа платы: какие контроллеры есть, по каким адресам, какие пины за что отвечают, какие регуляторы питания подключены. В Linux на ARM без device tree ядро вообще не знало бы, к чему обращается. На Repka он лежит в /boot/dtb/rockchip/rk3588-repka-pi5.dtb.

Шаг 4. А вдруг софтом всё и заблокировано? #

Проверяю, что контроллер включён в device tree и драйверы NVMe на месте:

cat /proc/device-tree/pcie@fe150000/status
# okay   ← контроллер активен

find /lib/modules/$(uname -r) -iname "nvme*"
# /lib/modules/.../kernel/drivers/nvme/host/nvme-fc.ko
# /lib/modules/.../kernel/drivers/nvme/host/nvme-tcp.ko
# ...

Софтверно всё готово: контроллер включён, драйверы есть. Значит, дело не в Linux.

Сводка после четырёх шагов #

Проверка Результат
/dev/nvme* отсутствует
dmesg PCIe Link Fail, LTSSM is 0x0 (с «моргком» 0x1)
Регулятор питания описан, отключается после неудачи — норма
Device tree pcie@fe150000 активен (status = okay)
Драйверы присутствуют

Всё софтверное готово. PHY сигналы ходят, но link training не сходится. Вывод один: физическая проблема контакта где-то между платой и SSD.

Ложные следы, на которые я чуть не повёлся #

Тут я полез в интернет и успел напугать себя знатно. Наткнулся на статьи про контроллер Maxio MAP1602 (а у моего CUSU именно Maxio-класс контроллер) — дескать, в новых ядрах Linux есть регрессия, и такие диски не инициализируются без кернел-патча. Я уже мысленно готовился пересобирать ядро.

Но вовремя одёрнул себя. Тот баг MAP1602 — про софтверную инициализацию NVMe после того, как линк уже встал. А у меня линк вообще не вставал — LTSSM падал в 0x0 ещё на этапе физического «рукопожатия». То есть софт NVMe даже не запускался. Кернел-патч тут ни при чём. Уф, отложил пересборку ядра.

Мораль: сначала физика, потом софт. Если линк не поднимается — копать в сторону контактов, кабеля, разъёма, а не в драйверы.

Решение: банальщина, которая заняла минуту #

Перечитываю симптомы ещё раз: PHY «видит» кого-то (LTSSM 0x1), но договориться не может. Сигнал доходит, но искажённым. Что между платой и SSD? Шлейф.

Выключаю плату, обесточиваю, вытаскиваю FPC-шлейф между Repka Pi 5 и M.2-HAT-платой кейса. И тут — озарение.

⚠️ У FPC-кабеля медные контакты («пятаки») расположены только с одной стороны ленты. У разъёмов на плате и на HAT-плате контакты тоже ориентированы строго в одну сторону. Если вставить шлейф перевёрнутым, то RX- и TX-пары (приём/передача) уходят не на те пины, а часть сигнальных линий вообще повисает в воздухе. PHY что-то ловит, но не может «договориться».

Переворачиваю шлейф, вставляю до упора, без перекоса, фиксирую защёлками. Включаю.

И — о чудо — в логах теперь:

rk-pcie fe150000.pcie: PCIe Linking... LTSSM is 0x3
rk-pcie fe150000.pcie: PCIe Linking... LTSSM is 0x210023
rk-pcie fe150000.pcie: PCIe Link up, LTSSM is 0x230011
rk-pcie fe150000.pcie: PCIe Gen.3 x1 link up
nvme nvme0: pci function 0000:01:00.0
nvme nvme0: allocated 16 MiB host memory buffer.

Сравните: раньше LTSSM 0x0 → Link Fail, теперь LTSSM 0x230011 → Gen.3 x1 link up. Link training дошёл до рабочего состояния L0, и ядро тут же нашло NVMe-устройство.

💡 Что такое 0x230011? Это битовое поле состояния LTSSM в рабочем режиме: старшие биты говорят, что линк в L0 (нормальная работа) и согласован на Gen3. Точная расшифровка битов не так важна — важно, что значение «большое» (не 0x0/0x1) = линк встал.

Проверка: всё ли правда хорошо? #

Появления строчки в логе мало — проверяю по-настоящему.

Устройство появилось #

lsblk
NAME          SIZE TYPE MODEL            TRAN
nvme0n1     953,9G disk CUSU CV3500Q 1TB nvme
└─nvme0n1p1 953,9G part                  nvme

Диск nvme0n1 на 953,9 GiB, модель определилась. Есть раздел nvme0n1p1.

Скорость и ширина линка #

cat /sys/class/nvme/nvme0/device/current_link_speed   # 8.0 GT/s PCIe
cat /sys/class/nvme/nvme0/device/current_link_width   # 1
cat /sys/class/nvme/nvme0/device/max_link_speed       # 8.0 GT/s PCIe
cat /sys/class/nvme/nvme0/device/max_link_width       # 4

Линк встал на PCIe Gen3 × 1 (8.0 ГТ/с, одна линия). Диск-то умеет Gen3 ×4, но Repka Pi 5 выводит на этот слот только одну линию — это конструктив платы, не дефект. Узкое место — слот, а не SSD.

💡 Что значит ×1 и ×4? PCIe — многополосная шина: «линии» (lanes) — это независимые пары проводов для приёма и передачи. ×4 = четыре линии = вчетверо большая пропускная способность, чем ×1. Диск умеет ×4, плата даёт ×1 — работаем на одну линию, но это всё равно в разы быстрее любой microSD.

SMART: здоровье диска #

sudo apt install nvme-cli
sudo nvme smart-log /dev/nvme0
critical_warning            : 0
temperature                 : 32 °C
available_spare             : 100%
percentage_used             : 0%        ← диск новый, износа нет
media_errors                : 0
power_on_hours              : 0
power_cycles                : 5
unsafe_shutdowns            : 5

Диск новый, износ 0%, ошибок носителя нет, температура в норме (32 °C). Один момент — unsafe_shutdowns = 5: это я сам накопил, дёргая питание во время пересборки. В штатной работе закрывайте ОС командой sudo poweroff, чтобы счётчик не рос.

💡 Что такое SMART? Это технология самодиагностики накопителя: диск сам считает, сколько часов проработал, сколько данных записал, насколько износился, какая температура, были ли ошибки. У NVMe читается утилитой nvme smart-log. Первый параметр, на который смотреть — critical_warning: если тут не 0, есть повод беспокоиться.

Скорость чтения — финальный замер #

sudo apt install hdparm
sudo hdparm -tT /dev/nvme0n1
# Timing buffered disk reads: 2272 MB in 3.00 seconds = 756.97 MB/sec

~757 МБ/с. Это потолок для PCIe Gen3 ×1: теоретически ~985 МБ/с, на практике 750–800 с учётом накладных расходов. Диск отдаёт максимум того, что позволяет слот. Для сравнения — хорошая microSD отдаёт ~100–150 МБ/с, а типовая и того меньше. Выигрыш в 5–7 раз налицо.

Нюанс, о котором стоит знать: раздел exFAT #

Диск пришёл из коробки с одним разделом nvme0n1p1, отформатированным в exFAT:

blkid /dev/nvme0n1p1
# /dev/nvme0n1p1: LABEL="Новый том" UUID="32C3-A2DA" TYPE="exfat"

exFAT — файловая система от Microsoft, заточенная под флешки и перенос между Windows/Mac/Linux. Но у неё есть минус для нашего случая: она не поддерживает права доступа UNIX (нет chmod/chown, нет symlink). Это значит:

  • ✅ Годится как «большая флешка» для хранения файлов и переноса между системами.
  • ❌ Не годится под системный раздел Linux, Docker, базы данных — там права нужны по полной.

Если хотите полноценное рабочее хранилище под Linux, переразметьте в ext4 (внимание: это сотрёт все данные на диске!):

sudo mkfs.ext4 -L nvme-data /dev/nvme0n1p1
sudo mkdir -p /mnt/nvme
sudo mount /dev/nvme0n1p1 /mnt/nvme

Если exFAT устраивает — просто ставим утилиты и монтируем:

sudo apt install exfatprogs
sudo mkdir -p /mnt/nvme
sudo mount -t exfat /dev/nvme0n1p1 /mnt/nvme

Чтобы монтировалось автоматически при загрузке — добавьте строку в /etc/fstab по UUID из вывода blkid.

А что с таблицей разделов: GPT или MBR? #

Прежде чем форматировать сам диск в файловую систему, нужно разобраться с таблицей разделов — это структура на самом начале диска, которая говорит: «вот тут раздел 1, вот тут раздел 2». Без неё операционная система не поймёт, где что лежит. Двух стандартов достаточно для понимания:

Параметр MBR (Master Boot Record) GPT (GUID Partition Table)
Возраст Из 80386-й эпохи, ~1983 год Современный, часть UEFI
Лимит размера диска 2 ТБ (при секторе 512 Б) до 9,4 ЗБ — фактически без лимита
Число разделов До 4 основных (или 3 + 1 расширенный) До 128 по умолчанию
Избыточность Нет — копия одна, при повреждении диск «срывается» Копия заголовка в конце диска — переживает частичные повреждения
Совместимость Старые BIOS, унаследованные системы UEFI (современные ПК, плата Repka через u-boot тоже умеет)
Как посмотреть в Linux fdisk -l пишет Тип метки диска: dos fdisk -l пишет Тип метки диска: gpt

У моего диска из коробки оказалась таблица MBR (Тип метки диска: dos) и один раздел. Для 1 ТБ этого хватало, но я сразу переписал на GPT — это современный стандарт, и при дальнейшем апгрейде на диск бóльшего объёма (2+, 4 ТБ) не придётся ничего перелопачивать.

💡 Почему GPT почти всегда лучше. MBR — это 512 байт в самом начале диска, без резервной копии: повреди этот участок — и таблицу разделов придётся восстанавливать утилитами и nerves of steel. GPT хранит основную копию в начале и вторую — в конце диска, плюс контрольные суммы (CRC32): при повреждении одной ядро автоматически читает вторую. На современных накопителях GPT — де-факто стандарт.

Проверить текущую таблицу разделов просто:

sudo fdisk -l /dev/nvme0n1 | grep -i "метка\|label"
# Тип метки диска: dos   ← это MBR
# или
# Тип метки диска: gpt   ← это GPT

Переписать таблицу (внимание: сотрёт все разделы и данные!):

sudo parted /dev/nvme0n1 mklabel gpt     # создать пустую GPT
sudo parted /dev/nvme0n1 mkpart primary ext4 0% 100%   # один раздел на весь диск
sudo mkfs.ext4 -L nvme-data /dev/nvme0n1p1             # файловая система

⚠️ MBR ловушка на больших дисках. Если возьмёте NVMe на 2 ТБ и выше, а таблица останется MBR — Linux увидит только первые 2 ТБ, остальное «пропадёт». Это не брак диска, а ограничение стандарта. Решение одно — переписать таблицу на GPT перед использованием.

Итоги #

Параметр Значение
Статус ✅ работает
Линк PCIe Gen3 ×1 (одна линия — максимум слота)
Скорость чтения ~757 МБ/с
Износ (SMART) 0% — диск новый
Ошибки носителя 0
Температура 32 °C
Файловая система exFAT (под замену на ext4 под Linux-задачи)
Таблица разделов MBR из коробки — рекомендую переписать на GPT

Причина «неработающего диска» была аппаратной и банальной: перевёрнутый FPC-шлейф между Repka Pi 5 и M.2-HAT-платой. Никакого несовместимого SSD, никаких кернел-патчей и пересборки ядра — минута правильной ориентации шлейфа решила всё.

Три урока, которые я вынес #

  1. Сначала читай логи, потом паникуй. dmesg | grep -iE "rk-pcie|nvme" за десять секунд сказал больше, чем час гугления. Линк падал ещё на физике — значит, копать в сторону «железа», а не софта.
  2. Физика раньше софта. Если LTSSM застревает в 0x0/0x1 — проверяй шлейф, разъём, дощатость вставки, и только потом лезь в device tree, оверлеи и драйверы. Софтверные баги (как история с MAP1602) бывают, но они про следующий этап — после того, как линк уже встал.
  3. FPC-шлейфы капризны. Контакты с одной стороны, разъёмы строго ориентированы — вставляй до щелчка, без перекоса, и проверяй направление при первой сборке. Это сэкономит тебе вечер, как не сэкономило мне.

Шпаргалка команд #

# Диск виден?
lsblk
ls /dev/nvme*

# Логи ядра про PCIe/NVMe
dmesg | grep -iE "rk-pcie|nvme|fe150000"

# Скорость и ширина линка
cat /sys/class/nvme/nvme0/device/current_link_speed
cat /sys/class/nvme/nvme0/device/current_link_width

# Модель, прошивка, серийник
cat /sys/class/nvme/nvme0/{model,firmware_rev,serial}

# SMART и здоровье
sudo nvme smart-log /dev/nvme0

# Замер скорости чтения
sudo hdparm -tT /dev/nvme0n1

# Таблица разделов (MBR или GPT)
sudo fdisk -l /dev/nvme0n1 | grep -i "метка\|label"

Ссылки #


+2

Комментарии (0)

Для участия в обсуждении Вы должны быть авторизованным пользователем

Еще посты по теме

Новые посты



Наиболее интересные по мнению читателей



Темы

Навигация

ВойтиРегистрация