[Из песочницы] Реанимация D-Link NAS DNS-325
Добрый день! Хочу поделиться историей о том, как я чинил примус свой домашний NAS D-Link DNS-325.
Сам NAS у меня обычно в режиме минимального потребления электроэнергии с выключенными жёсткими дисками WD Green (установлен fun_plug на внешнюю USB флешку, об этой «прокачке» есть статья на Хабре). Однажды, после отпуска, я включил питание на NAS, чтобы просмотреть/загрузить фотографии. Он не включился. Cветодиод питания весело замигал, загорелись индикаторы сотояния HDD, но мигание продолжалось и продолжалось без признаков жизни. При нормальных условиях мигание означает процесс загрузки, который должен завершиться полной инициализацией и установлением стабильного свечения power LED. После многих попыток запустить устройство, отключения жёстких дисков, нажатия кнопки reset (которая, кстати, безполезна пока загрузка не завершится успешно), я с горечью осознал, что это не тривиальная проблема, с которой мне прийдётся справиться самому из-за истёкшей гарантии (12 месяцев).Осмотр содержимого жёстких дисков через USB-to-SATA показал, что данные в порядке, RAID1 сконфигурирован.
Джедайское гугление дало надежду на подключение к последовательному порту DNS-325 и возможной диагностики. Необходимо подобраться к порту, плата легко достаётся после отключения жёстких дисков и вывинчивания 4-х винтов сзади NAS (шлицы находятся под резиновыми заглушками).
Детали о распиновке UART на плате и способе подключения можно найти здесь. Оставалась одна проблема. UART на плате DNS-325 требует TTL 3.3V и может сгореть при более высоких напряжениях. У меня не оказалось RS-232-TTL 3.3V конвертора, а заказанный кабель на eBay так и не пришёл в срок. Связавшись с продавцом, я получил ответ, мол, видимо, потерялся, бывает. Деньги он вернул, но нужно было искать другой кабель или… На помощь пришла идея использовать завалявшуюся Raspberry PI (или просто Малину), на борту которой есть 3.3V UART.
Возможно, повторюсь, рассказывая о том, как настроить Малину с «нуля», но я сам был бы рад прочитать об этом в одном месте и последовательно.
Настройка Raspberry PIТак как моя «Малина» была уже в работе, необходимый минимум железа имелся: Собственно, сама Raspberry PI; Акриловый корпус; SD карта; Коннектор на GPIO/UART пины, блок питания etc. Итак, скачиваем готовый образ для SD-карты дистрибутива RASPBIAN с главного сайта www.raspberrypi.org. Далее записываем скаченый образ на SD-карту. В моём случае я использовал встроенный card-reader в ноутбуке и программу Win32DiskImager. По умолчанию сетевой интерфейс в дистрибутиве запрашивает адрес по DHCP, поэтому, подключив Малину к домашнему роутеру, я смог залогинится и сконфигурировать последовательный порт с помощью:
root@raspberrypi:~# raspi-config
Далее навигация по меню:»8 Advanced Options» --> «A7 Serial»:
Would you like a login shell to be accessible over serial? Current setting: yes
Выбираем «No» и перезагружаемся.
Установка и настройка терминала apt-get install minicomЗапускаем эмулятор терминала для работы с последовательным портом:
minicom -D /dev/ttyAMA0 -b 115200 -8
После того, как соответствующие пины последовательного порта DNS-325 подключены к Raspberry PI, наступает самый долгожданный момент включения устройства. Сейчас, собственно, хоть что-то станет ясно, почему NAS после включения входит в «крутое пике» и не подает признаков жизни. Скорость порта и прочие настройки установлены верно, само устройство оказалось «живым» и в консоли Малины побежал лог загрузки.Раскрыв спойлер, можно увидеть весь лог загрузки:
Вывод сообщений загрузки на терминал ** MARVELL BOARD: DB-88F6281A-BP LEU-Boot 1.1.4 (May 16 2011 — 10:40:38) Marvell version: 3.4.14.DNS-325.03
U-Boot code: 00600000 → 0067FFF0 BSS: → 006CEE80
Soc: MV88F6281 Rev 3 (DDR2)CPU running @ 1200Mhz L2 running @ 400MhzSysClock = 400Mhz, TClock = 200Mhz
DRAM CAS Latency = 5 tRP = 5 tRAS = 18 tRCD=6DRAM CS[0] base 0×00000000 size 256MBDRAM Total size 256MB 16bit widthFlash: 0 kBAddresses 8M — 0M are saved for the U-Boot usage.Mem malloc Initialization (8M — 7M): DoneNAND:128 MB
CPU: Marvell Feroceon (Rev 1)
Streaming disabledWrite allocate disabled
USB 0: host modePEX 0: interface detected no Link.Net: egiga0 [PRIME]Hit any key to stop autoboot: 0
NAND read: device 0 offset 0×100000, size 0×300000load addr… =a00000
3145728 bytes read: OK
NAND read: device 0 offset 0×600000, size 0×300000load addr… =f00000
Bad block at 0×780000 in erase block from 0×780000 will be skipped3145728 bytes read: OK## Booting image at 00a00000…Image Name: Linux-2.6.31.8Created: 2012–06–26 3:38:43 UTCImage Type: ARM Linux Kernel Image (uncompressed)Data Size: 2565784 Bytes = 2.4 MBLoad Address: 00008000Entry Point: 00008000Verifying Checksum… Bad Data CRC
NAND read: device 0 offset 0×7100800, size 0×500000load addr… =a00000
5242880 bytes read: OK## Booting image at 00a00000…Image Name: Linux-2.6.22.18Created: 2011–05–25 7:23:15 UTCImage Type: ARM Linux Kernel Image (uncompressed)Data Size: 2214860 Bytes = 2.1 MBLoad Address: 00008000Entry Point: 00008000Verifying Checksum… OKOK## Loading Ramdisk Image at 00d00000…Image Name: RamdiskCreated: 2011–07–11 5:47:12 UTCImage Type: ARM Linux RAMDisk Image (gzip compressed)Data Size: 1566183 Bytes = 1.5 MBLoad Address: 00e00000Entry Point: 00e00000Verifying Checksum… OK
Starting kernel…
Uncompressing Linux… done,.Linux version 2.6.22.18 (jack@swtest4) (gcc version 4.2.1) #15 Wed May 25 15:23:11 CST 2011CPU: ARM926EJ-S [56251311] revision 1 (ARMv5TE), cr=00053977Machine: Feroceon-KWUsing UBoot passing parameters structureMemory policy: ECC disabled, Data cache writebackCPU0: D VIVT write-back cacheCPU0: I cache: 16384 bytes, associativity 4, 32 byte lines, 128 setsCPU0: D cache: 16384 bytes, associativity 4, 32 byte lines, 128 setsBuilt 1 zonelists. Total pages: 65024Kernel command line: root=/dev/ram console=ttyS0,115200::: DB88FXX81: egiga0: nonePID hash table entries: 1024 (order: 10, 4096 bytes)Console: colour dummy device 80×30Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)Memory: 256MB 0MB 0MB 0MB = 256MB totalMemory: 253696KB available (4156K code, 252K data, 124K init)Mount-cache hash table entries: 512CPU: Testing write buffer coherency: okNET: Registered protocol family 16
CPU Interface— SDRAM_CS0 …base 00000000, size 256MBSDRAM_CS1 …base 10000000, size 256MBSDRAM_CS2 …disableSDRAM_CS3 …disablePEX0_MEM …base e8000000, size 128MBPEX0_IO …base f2000000, size 1MBINTER_REGS …base f1000000, size 1MBNFLASH_CS …base fa000000, size 2MBSPI_CS …base f4000000, size 16MBBOOT_ROM_CS …no suchDEV_BOOTCS …no suchCRYPT_ENG …base f0000000, size 2MB
Marvell Development Board (LSP Version KW_LSP_4.3.4_patch30)-- DB-88F6281A-BP Soc: 88F6281 A1 LE
Detected Tclk 200000000 and SysClk 400000000MV Buttons Device LoadMarvell USB EHCI Host controller #0: c06de600PEX0 interface detected no Link.PCI: bus0: Fast back to back transfers enabledSCSI subsystem initializedusbcore: registered new interface driver usbfsusbcore: registered new interface driver hubusbcore: registered new device driver usbNET: Registered protocol family 2Time: kw_clocksource clocksource has been installed.IP route cache hash table entries: 2048 (order: 1, 8192 bytes)TCP established hash table entries: 8192 (order: 4, 65536 bytes)TCP bind hash table entries: 8192 (order: 3, 32768 bytes)TCP: Hash tables configured (established 8192 bind 8192)TCP reno registeredchecking if image is initramfs…it isn’t (no cpio magic); looks like an initrdFreeing initrd memory: 1529Kcpufreq: Init kirkwood cpufreq driverXOR registered 1 NET_DMA over 4 channelsXOR 2nd invalidate WA enabledcesadev_init (c00119d8)mvCesaInit: sessions=640, queue=64, pSram=f0000000Warning: TS unit is powered off.MV Buttons Driver LoadVFS: Disk quotas dquot_6.5.1Dquot-cache hash table entries: 1024 (order 0, 4096 bytes)squashfs: version 3.3 (2007/10/31) Phillip Loughersquashfs: LZMA suppport for slax.org by jroInstalling knfsd (copyright © 1996 okir@monad.swb.de).JFFS2 version 2.2. (NAND) ц┐ц┌ц┌б╘ 2001–2006 Red Hat, Inc.fuse init (API version 7.8)SGI XFS with large block numbers, no debug enabledio scheduler noop registeredio scheduler anticipatory registered (default)Serial: 8250/16550 driver $Revision: 1.1.1.1 $ 4 ports, IRQ sharing disabledserial8250.0: ttyS0 at MMIO 0xf1012000 (irq = 33) is a 16550Aserial8250.0: ttyS1 at MMIO 0xf1012100 (irq = 34) is a 16550ARAMDISK driver initialized: 16 RAM disks of 10240K size 1024 blocksizeloop: module loadedLoading Marvell Ethernet Driver: o Cached descriptors in DRAMo DRAM SW cache-coherencyo Single RX Queue support — ETH_DEF_RXQ=0o Single TX Queue support — ETH_DEF_TXQ=0o TCP segmentation offload enabledo LRO support supportedo Receive checksum offload enabledo Transmit checksum offload enabledo Network Fast Processing (Routing) supportedo Driver ERROR statistics enabledo Driver INFO statistics enabledo Proc tool API enabledo SKB Reuse supportedo SKB Recycle supportedo Rx descripors: q0=128o Tx descripors: q0=532o Loading network interface (s): o register under egiga0 platformo egiga0, ifindex = 1, GbE port = 0
Warning: Giga 1 is Powered Off
mvFpRuleDb (c0f2a000): 2048 entries, 8192 bytesIntegrated Sata device foundscsi0: Marvell SCSI to SATA adapterscsi1: Marvell SCSI to SATA adapterNFTL driver: nftlcore.c $Revision: 1.1.1.1 $, nftlmount.c $Revision: 1.1.1.1 $NAND device: Manufacturer ID: 0xec, Chip ID: 0xf1 (Samsung NAND 128MiB 3,3V 8-bit)Scanning device for bad blocksBad eraseblock 60 at 0×00780000Bad eraseblock 109 at 0×00da0000Bad eraseblock 455 at 0×038e0000Bad eraseblock 499 at 0×03e60000Using static partition definitionCreating 6 MTD partitions on «nand_mtd»:0×00000000–0×00100000: «u-boot»0×00100000–0×00600000: «uImage»0×00600000–0×00b00000: «ramdisk»0×00b00000–0×07100000: «image»0×07100000–0×07b00000: «mini firmware»0×07b00000–0×08000000: «config«ehci_marvell ehci_marvell.70059: Marvell Orion EHCIehci_marvell ehci_marvell.70059: new USB bus registered, assigned bus number 1ehci_marvell ehci_marvell.70059: irq 19, io base 0xf1050100ehci_marvell ehci_marvell.70059: USB 2.0 started, EHCI 1.00, driver 10 Dec 2004usb usb1: configuration #1 chosen from 1 choicehub 1–0:1.0: USB hub foundhub 1–0:1.0: 1 port detectedUSB Universal Host Controller Interface driver v3.0mice: PS/2 mouse device common for all micei2c /dev entries drivermd: linear personality registered for level -1md: raid0 personality registered for level 0md: raid1 personality registered for level 1device-mapper: ioctl: 4.11.0-ioctl (2006–10–12) initialised: dm-devel@redhat.comdm_crypt using the OCF package.usbcore: registered new interface driver usbhiddrivers/hid/usbhid/hid-core.c: v2.6: USB HID core driverTCP cubic registeredNET: Registered protocol family 1NET: Registered protocol family 17md: Autodetecting RAID arrays.md: autorun…md: … autorun DONE.RAMDISK: Compressed image found at block 0EXT2-fs warning: maximal mount count reached, running e2fsck is recommendedVFS: Mounted root (ext2 filesystem).Freeing init memory: 124Kinit started: BusyBox v1.11.2 (2010–11–17 11:44:30 CST)starting pid 276, tty '': '/etc/rc.sh'** Mounting /etc/fstabumount: proc: not mountedumount: proc: not mountedumount: /usr/local/modules: not mountedumount: /usr/local/tmp/image.cfs: not foundumount: /usr/local/tmp: not mountedfirst good block is 0ECC failed: 0ECC corrected: 0Number of bad blocks: 3Number of bbt blocks: 0Block size 131072, page size 2048, OOB size 64Dumping data starting at 0×00000000 and ending at 0×00000800…image len = 36900864, image checksum = 9a5bf12ECC failed: 0ECC corrected: 0Number of bad blocks: 3Number of bbt blocks: 0Block size 131072, page size 2048, OOB size 64Dumping data starting at 0×00000800 and ending at 0×02d00000…dump image checksum=9a5bf12SQUASHFS error: Major/Minor mismatch, trying to mount newer 4.0 filesystemSQUASHFS error: Please update your kernelmount: wrong fs type, bad option, bad superblock on /dev/loop0, missing codepage or other errorIn some cases useful info is found in syslog — trydmesg | tail or so
/etc/rc.sh: line 17: system_init: not foundstarting pid 302, tty '': '-/bin/sh'
BusyBox v1.11.2 (2010–11–17 11:44:30 CST) built-in shell (ash)Enter 'help' for a list of built-in commands.
Для доступа в shell необходимо ввести код 5784468.После беглого осмотра в консоли стало ясно, что NAS загрузился в single-user mode. Ничего не смонтировано кроме корневой системы.Очевидно, что процесс загрузки не продолжается именно из-за проблем с монтированием основного файлового дерева из squash образа: SQUASHFS error: Major/Minor mismatch, trying to mount newer 4.0 filesystemSQUASHFS error: Please update your kernelmount: wrong fs type, bad option, bad superblock on /dev/loop0,
Сам файл, в котором squash образ, выгружается из внутренней flash в файл /usr/local/tmp/image.cfs с помошью nanddump.mount -o loop /usr/local/tmp/image.cfs /mnt приводило к такой же ошибке, что и при загрузке.
Первое, что приходило в голову, была мысль о возможном повреждении самого image.cfs во flash памяти. Но очередного просмотра лога загрузки я обратил внимание на сообщение об ошибке, которое изначально затерялось в длинном тексте лога: Image Name: Linux-2.6.31.8…Verifying Checksum … Bad Data CRC
После чего U-Boot грузил образ другого, более старого ядра: Image Name: Linux-2.6.22.18
NAND read: device 0 offset 0×7100800, size 0×500000 load addr … =a00000
5242880 bytes read: OK ## Booting image at 00a00000 … Image Name: Linux-2.6.22.18 Created: 2011–05–25 7:23:15 UTC Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 2214860 Bytes = 2.1 MB Load Address: 00008000 Entry Point: 00008000 Verifying Checksum … OK Забегая вперёд, хотелось бы отметить, что область «mini firmware» внутренней flash, откуда загрузился образ с ядром в аварийном режиме, по-видимому, предназначена для подобных ситуаций. Если бы у меня стояла более ранняя прошивка, загрузка бы прошла успешно и я бы и не узнал о повреждении. Но в прошивке 1.04 новое ядро 2.6.31.8 и поэтому монтирование образа сжатой файловой системой (опять же, нового формата) на старом ядре завершалось ошибкой.
Гугление не дало готового решения, но вдохновило на jugaad, а именно: используя возможности U-Boot перезаписать uImage образ во внутренней flash памяти с помощью вырезанного образа из стоковой прошивки.
Достаём образ uImage с ядром из прошивки Скачиваем стоковую прошивку с сайта D-Link: DLINK_DNS325.1.04b05 (на тот момент у меня стояла именна эта версия).Каким-то образом необходимо было достать образ с ядром и попробовать перезаписать в повреждённую область.Очень полезным инструментом оказался binwalk:
Вырезанный uImage образ попробуем записать во внутреннюю flash память начиная с адреса 0×100000.
Установка и настройка Kermit Для того, что передавать бинарные файлы в U-Boot нам понадобится достаточно древний протокол Kermit.apt-get install ckermit
Создаём .kermrc с таким содержимым:
set line /dev/ttyAMA0
set speed 115200
set carrier-watch off
set handshake none
set flow-control none
robust
set file type bin
set rec pack 1000
set send pack 1000
set window 5
Загрузка расширенного U-Boot
Чтобы попасть в U-Boot командную строку, необходимо успеть прервать процесс загрузки нажав Пробел и »1» в момент, когда в консоли minicom на эту операцию отводится 2 секунды: PEX 0: interface detected no Link.Net: egiga0 [PRIME]Hit any key to stop autoboot: 1К сожалению, я не обнаружил в стоковом U-Boot команды loadb
Необходим компилятор для сборки на Малине: apt-get install gcc
Скачаем U-Boot: git clone -b dns320_support https://github.com/lentinj/u-boot.gitСобираем: make distclean && make dns325_config && make u-boot.kwb
(Если вы подключились с помощью кабеля USB-Uart-TTL и производите сборку на x86 платформе, необходимо установить ARM-компилятор: export CROSS_COMPILE=arm-linux-gnueabi-)
Запускаем утилиту для передачи U-Boot: root@raspberrypi:~/u-boot# cd u-bootroot@raspberrypi:~/u-boot# ./tools/kwboot -p -b u-boot.kwb -B115200 -t /dev/ttyAMA0Sending boot message. Please reboot the target…/
Всё готово к передаче, выключаем NAS, ждём 10 с, включаем и следим за процессом передачи u-boot.kwb.Процесс займёт несколько минут. В консоле вы сможете видеть процесс передачи в виде бегущих точек.По окончании передачи необходимо прервать загрузку в момент Hit any key to stop autoboot: 4 (см. выше).Выйдем из программы с помошью Ctrl+/ затем «c»
Передача образа и запись во flash Запускаем kermit на Малине и инициируем передачу файла uKernel, который мы вырезали ранее из прошивки: root@raspberrypi:~# kermitи переходим в режим коесоли последовательного порта: (/root/) C-Kermit>connect Connecting to /dev/ttyAMA0, speed 115200 Escape character: Ctrl-\ (ASCII 28, FS): enabled Type the escape character followed by C to get back, or followed by? to see other options. ---------------------------------------------------- Здесь, в командной строке U-Boot, даём команду на приём файла по адресу 0×000000 (загружаем мы временно для перезаписи, поэтому базовый адрес не важен):
=> loadb 0×00000000
U-Boot переходит в режим ожидания файла, а мы выходим в командную строку Kermit нажатием Ctrl+\ и «c» и передаем файл:
(/root/) C-Kermit>send uKernel
Через несколько минут файл передан и готов к записи во flash:
=> nand erase 0×100000 0×300000 — Очистка flash области 0×100000–0×300000=> nand write 0×000000 0×100000 0×300000 — Запись из памяти со смещением 0×000000
ВСЁ… можно перезагрузиться.NAS успешно загрузился с установленными дисками и USB флешкой как ни в чём не бывало.Для перестраховки я загрузил последнюю версию прошивки стандартным путём через страничку управления.
P.S. Подобные операции с U-Boot и перезаписыванием внутренней flash я производил впервые, поэтому остаётся открытыми вопросы эффективности описанных выше шагов. В частности, я не смог найти ответы или проверить:
Что произошло и как этого избежать в будущем? Реальный размер uImage образа существенно меньше считываемого U-Boot’ом размера 0×300000; Использование tftp для передачи образа uImage; Использование USB flash для загрузки образа uImage (в расширеном U-Boot есть возможность инициализации USB); Бэкап разделов внутренней flash памяти на внешнюю USB память.