Добрый день!
Хочу поделиться историей о том, как я чинил примус свой домашний 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 после включения входит в «крутое пике» и не подает признаков жизни. Скорость порта и прочие настройки установлены верно, само устройство оказалось «живым» и в консоли Малины побежал лог загрузки.
Раскрыв спойлер, можно увидеть весь лог загрузки:
U-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 @ 400Mhz
SysClock = 400Mhz, TClock = 200Mhz
DRAM CAS Latency = 5 tRP = 5 tRAS = 18 tRCD=6
DRAM CS[0] base 0x00000000 size 256MB
DRAM Total size 256MB 16bit width
Flash: 0 kB
Addresses 8M — 0M are saved for the U-Boot usage.
Mem malloc Initialization (8M — 7M): Done
NAND:128 MB
CPU: Marvell Feroceon (Rev 1)
Streaming disabled
Write allocate disabled
USB 0: host mode
PEX 0: interface detected no Link.
Net: egiga0 [PRIME]
Hit any key to stop autoboot: 0
NAND read: device 0 offset 0x100000, size 0x300000
load addr… =a00000
3145728 bytes read: OK
NAND read: device 0 offset 0x600000, size 0x300000
load addr… =f00000
Bad block at 0x780000 in erase block from 0x780000 will be skipped
3145728 bytes read: OK
## Booting image at 00a00000…
Image Name: Linux-2.6.31.8
Created: 2012-06-26 3:38:43 UTC
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 2565784 Bytes = 2.4 MB
Load Address: 00008000
Entry Point: 00008000
Verifying Checksum… Bad Data CRC
NAND read: device 0 offset 0x7100800, size 0x500000
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
OK
## Loading Ramdisk Image at 00d00000…
Image Name: Ramdisk
Created: 2011-07-11 5:47:12 UTC
Image Type: ARM Linux RAMDisk Image (gzip compressed)
Data Size: 1566183 Bytes = 1.5 MB
Load Address: 00e00000
Entry Point: 00e00000
Verifying 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 2011
CPU: ARM926EJ-S [56251311] revision 1 (ARMv5TE), cr=00053977
Machine: Feroceon-KW
Using UBoot passing parameters structure
Memory policy: ECC disabled, Data cache writeback
CPU0: D VIVT write-back cache
CPU0: I cache: 16384 bytes, associativity 4, 32 byte lines, 128 sets
CPU0: D cache: 16384 bytes, associativity 4, 32 byte lines, 128 sets
Built 1 zonelists. Total pages: 65024
Kernel command line: root=/dev/ram console=ttyS0,115200 :::DB88FXX81:egiga0:none
PID hash table entries: 1024 (order: 10, 4096 bytes)
Console: colour dummy device 80x30
Dentry 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 total
Memory: 253696KB available (4156K code, 252K data, 124K init)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
NET: Registered protocol family 16
CPU Interface
— SDRAM_CS0 ....base 00000000, size 256MB
SDRAM_CS1 ....base 10000000, size 256MB
SDRAM_CS2 ....disable
SDRAM_CS3 ....disable
PEX0_MEM ....base e8000000, size 128MB
PEX0_IO ....base f2000000, size 1MB
INTER_REGS ....base f1000000, size 1MB
NFLASH_CS ....base fa000000, size 2MB
SPI_CS ....base f4000000, size 16MB
BOOT_ROM_CS ....no such
DEV_BOOTCS ....no such
CRYPT_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 400000000
MV Buttons Device Load
Marvell USB EHCI Host controller #0: c06de600
PEX0 interface detected no Link.
PCI: bus0: Fast back to back transfers enabled
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
NET: Registered protocol family 2
Time: 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 registered
checking if image is initramfs...it isn't (no cpio magic); looks like an initrd
Freeing initrd memory: 1529K
cpufreq: Init kirkwood cpufreq driver
XOR registered 1 NET_DMA over 4 channels
XOR 2nd invalidate WA enabled
cesadev_init(c00119d8)
mvCesaInit: sessions=640, queue=64, pSram=f0000000
Warning: TS unit is powered off.
MV Buttons Driver Load
VFS: Disk quotas dquot_6.5.1
Dquot-cache hash table entries: 1024 (order 0, 4096 bytes)
squashfs: version 3.3 (2007/10/31) Phillip Lougher
squashfs: LZMA suppport for slax.org by jro
Installing 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 enabled
io scheduler noop registered
io scheduler anticipatory registered (default)
Serial: 8250/16550 driver $Revision: 1.1.1.1 $ 4 ports, IRQ sharing disabled
serial8250.0: ttyS0 at MMIO 0xf1012000 (irq = 33) is a 16550A
serial8250.0: ttyS1 at MMIO 0xf1012100 (irq = 34) is a 16550A
RAMDISK driver initialized: 16 RAM disks of 10240K size 1024 blocksize
loop: module loaded
Loading Marvell Ethernet Driver:
o Cached descriptors in DRAM
o DRAM SW cache-coherency
o Single RX Queue support — ETH_DEF_RXQ=0
o Single TX Queue support — ETH_DEF_TXQ=0
o TCP segmentation offload enabled
o LRO support supported
o Receive checksum offload enabled
o Transmit checksum offload enabled
o Network Fast Processing (Routing) supported
o Driver ERROR statistics enabled
o Driver INFO statistics enabled
o Proc tool API enabled
o SKB Reuse supported
o SKB Recycle supported
o Rx descripors: q0=128
o Tx descripors: q0=532
o Loading network interface(s):
o register under egiga0 platform
o egiga0, ifindex = 1, GbE port = 0
Warning: Giga 1 is Powered Off
mvFpRuleDb (c0f2a000): 2048 entries, 8192 bytes
Integrated Sata device found
scsi0: Marvell SCSI to SATA adapter
scsi1: Marvell SCSI to SATA adapter
NFTL 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 blocks
Bad eraseblock 60 at 0x00780000
Bad eraseblock 109 at 0x00da0000
Bad eraseblock 455 at 0x038e0000
Bad eraseblock 499 at 0x03e60000
Using static partition definition
Creating 6 MTD partitions on «nand_mtd»:
0x00000000-0x00100000: «u-boot»
0x00100000-0x00600000: «uImage»
0x00600000-0x00b00000: «ramdisk»
0x00b00000-0x07100000: «image»
0x07100000-0x07b00000: «mini firmware»
0x07b00000-0x08000000: «config»
ehci_marvell ehci_marvell.70059: Marvell Orion EHCI
ehci_marvell ehci_marvell.70059: new USB bus registered, assigned bus number 1
ehci_marvell ehci_marvell.70059: irq 19, io base 0xf1050100
ehci_marvell ehci_marvell.70059: USB 2.0 started, EHCI 1.00, driver 10 Dec 2004
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
USB Universal Host Controller Interface driver v3.0
mice: PS/2 mouse device common for all mice
i2c /dev entries driver
md: linear personality registered for level -1
md: raid0 personality registered for level 0
md: raid1 personality registered for level 1
device-mapper: ioctl: 4.11.0-ioctl (2006-10-12) initialised: dm-devel@redhat.com
dm_crypt using the OCF package.
usbcore: registered new interface driver usbhid
drivers/hid/usbhid/hid-core.c: v2.6:USB HID core driver
TCP cubic registered
NET: Registered protocol family 1
NET: Registered protocol family 17
md: Autodetecting RAID arrays.
md: autorun…
md:… autorun DONE.
RAMDISK: Compressed image found at block 0
EXT2-fs warning: maximal mount count reached, running e2fsck is recommended
VFS: Mounted root (ext2 filesystem).
Freeing init memory: 124K
init started: BusyBox v1.11.2 (2010-11-17 11:44:30 CST)
starting pid 276, tty '': '/etc/rc.sh'
** Mounting /etc/fstab
umount: proc: not mounted
umount: proc: not mounted
umount: /usr/local/modules: not mounted
umount: /usr/local/tmp/image.cfs: not found
umount: /usr/local/tmp: not mounted
first good block is 0
ECC failed: 0
ECC corrected: 0
Number of bad blocks: 3
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x00000000 and ending at 0x00000800…
image len = 36900864, image checksum = 9a5bf12
ECC failed: 0
ECC corrected: 0
Number of bad blocks: 3
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x00000800 and ending at 0x02d00000…
dump image checksum=9a5bf12
SQUASHFS error: Major/Minor mismatch, trying to mount newer 4.0 filesystem
SQUASHFS error: Please update your kernel
mount: wrong fs type, bad option, bad superblock on /dev/loop0,
missing codepage or other error
In some cases useful info is found in syslog — try
dmesg | tail or so
/etc/rc.sh: line 17: system_init: not found
starting 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 filesystem
SQUASHFS error: Please update your kernel
mount: 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 0x7100800, size 0x500000
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 память начиная с адреса 0x100000
.
Установка и настройка 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 <addr>
, которая позволяет загружать бинарный файл по указанному адресу в памяти.
Поэтому прийдётся скачать и сконфигурировать утилиту для загрузки расширенного U-Boot через последовательный порт.
Необходим компилятор для сборки на Малине:
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-boot
root@raspberrypi:~/u-boot# ./tools/kwboot -p -b u-boot.kwb -B115200 -t /dev/ttyAMA0
Sending 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, даём команду на приём файла по адресу 0x000000 (загружаем мы временно для перезаписи, поэтому базовый адрес не важен):
=> loadb 0x00000000
U-Boot переходит в режим ожидания файла, а мы выходим в командную строку Kermit
нажатием Ctrl+ и «c» и передаем файл:
(/root/) C-Kermit>send uKernel
Через несколько минут файл передан и готов к записи во flash:
=> nand erase 0x100000 0x300000
— Очистка flash области 0x100000-0x300000
=> nand write 0x000000 0x100000 0x300000
— Запись из памяти со смещением 0x000000
ВСЁ… можно перезагрузиться.
NAS успешно загрузился с установленными дисками и USB флешкой как ни в чём не бывало.
Для перестраховки я загрузил последнюю версию прошивки стандартным путём через страничку управления.
P.S. Подобные операции с U-Boot и перезаписыванием внутренней flash я производил впервые, поэтому остаётся открытыми вопросы эффективности описанных выше шагов. В частности, я не смог найти ответы или проверить:
- Что произошло и как этого избежать в будущем?
- Реальный размер uImage образа существенно меньше считываемого U-Boot'ом размера 0x300000;
- Использование
tftp
для передачи образа uImage; - Использование USB flash для загрузки образа uImage (в расширеном U-Boot есть возможность инициализации USB);
- Бэкап разделов внутренней flash памяти на внешнюю USB память.
Автор: wwwalex