Inhaltsverzeichnis

Scope

This is no manual of how to install the latest U-Boot, the latest Linux kernel and the latest GNU/Debian to your Seagate BlackArmor 220, though probably you can use it as such. This is the story of how I bricked my NAS and it turned out to be one of the best things I ever did.

If you have questions, ideas of how to make things better or anything else, you can find mrm2m on IRC in hackint or freenode or in real life in the CCC-FFM hackquarter

Seagate Blackarmor NAS 220

The Blackarmor NAS 220 is based on the Marvell 88F6192 Kirkwood prozessor.

Some years ago Hajo Noerenberg published some notes on this device. Unfortunately the stock kernel provided from Seagate was too old to run anything newer than Debian 5 properly on the device.

In December 2014 Evgeni Dobrev made a nice Christmas present by providing a patch for the Blackarmor 220 for the mainline kernel. Some days before he contributed source code for the Blackarmor 220 for U-Boot as well. So we can compile the latest bootloader and kernel \o/.

Serial interface

You can connect to a serial 3.3V interface over Connector CN5 (Norenberg refers to it as CN4, but for me the the labeling looks like CN5 - so either there are different hardware platforms out there or one of us did a wrong interpretation of the labeling):

   9|- x - x -|10
   7|- x - x -|8
   5|- x -GND-|6
   3|- x -nRX-|4
   1|-nTX- x -|2

The stock system

I managed successfully to FUBAR the system, that came from the manufacturer, so I can't say much about it. Just so much: The serial interface shows some U-Boot v0.2 and then boots a 2.something kernel into a root shell. There are some executables to do things with the flash.

How to brick the device

I tried to backup the old system with one of these to a USB stick and was a little bit surprised as the resulting files all provided „0xFF“ as their only contents. A reboot of the system showed that it was not only the copy that was strange, but it looked a lots like the real flash content was gone as well. No boot loader, no operating system no nothing:

Picture similar to product

A step back - the Kirkwood boot-ROM

So after the NAS did not talk to me any more I had to find a way to talk to the NAS instead. So I did the obvious and started RTFM. Marvell provides a very good manual for the 88F6192.

I found out about the bootrom that tries to boot from several sources depending on the wiring and register setup of the processor, but there is one thing always probed first: A serial interface is listening to some magical bytes at a baud rate of 115200. Depending on which bytes are received a debugging prompt is started at that serial line or it waits for a boot image packed in a proprietary package format that is well described as well.

So I gave it a try and started a very simple python application:

import serial
import sys
 
MAGIC="\xDD\x11\x22\x33\x44\x55\x66\x77"
 
if __name__ == "__main__":
    s = serial.Serial(sys.argv[1], baudrate=115200, timeout=0.1)
    s.readall()
    res = ""
    while res == "":
        s.write(MAGIC)
        res = s.readall()
    print(repr(res))

I started the program and rebooted the NAS. Sometimes my USB serial converter does not survive the power cycle of the target device, but that's just fine. Just restart the script.

So the NAS respoded. Now I had a nice black brick with a debugging console - Hurray!

moritz@major-tom /tmp % python foo.py /dev/ttyUSB1
'\n\rBootstrap 1.21>'

Unfortunately this console is not described further in the public documentation that I could find, but there is another magic bytes string that can be sent to start an image transfer over UART and xmodem protocol.

I changed my program to use that other magic byte string „\xBB\x11\x22\x33\x44\x55\x66\x77“ and got '\x15' as result which is a NAK from the xmodem protocol and therefor the valid start for xmodem data transmission. Now I needed a valid U-Boot image for the Kirkwood.

Building U-Boot for the BlackArmor NAS 220

I used the latest stable release from the official repository. That is at the moment version 2015.04. I use the arm cross toolchain packaged with my operating system Debian 8:

export CROSS_COMPILE=arm-none-eabi-
export ARCH=arm
make nas220_defconfig
make -j2

This will produce a uimage.bin. This image cannot be used directly with the Kirkwood processor. You will need to package it. Fortunately there is a tool for that:

./tools/mkimage -n ./board/Seagate/nas220/kwbimage.cfg -T kwbimage -a 0x00600000 -e 0x00600000  -d u-boot.bin u-boot.kwb

Now we have a Kirkwood image that can be loaded from flash by the Kirkwood BootROM.

Booting from UART

From the BootROM manual I found which bytes to change to make a UART boot image from the flash boot image that we just created. I flipped the corresponding bits with ghex2, started minicom and tried to transmit the image, but I always got back a message telling me that the result on the first package was 0x00 which is not valid. So I tried to implement the xmodem transmission myself to be sure there's not a timing issue or anything like that. I got the same result: 0x00. So I did some research and found out that someone had already written a tool that automatically reworks the flash boot image to a UART boot image, starts the BootROM into xmodem mode and transmits the image via xmodem:

moritz@major-tom ~/Downloads/u-boot-2015.04 % /home/moritz/Downloads/u-boot-2015.04/tools/kwboot -b u-boot.kwb -p -B 115200 /dev/ttyUSB1                                            :(
Sending boot message. Please reboot the target.../
Sending boot image...
  0 % [+++++++++++++++++xmodem: Bad message

Unfortunately I got an error message there as well.

So I used my logic analyzer to see what is going on on the serial lines. The result was not very promising: Serial line fail on UART boot

Now I wanted to compare my results with the results of the other options I had to start the UART boot and … „BAAMMM!“ - the transmission worked. I have no real clue why it works sometimes and doesn't work in most of the other cases, but I can reproduce that the transmission works after some tries:

moritz@major-tom ~/Downloads/u-boot-2015.04 % /home/moritz/Downloads/u-boot-2015.04/tools/kwboot -b u-boot.kwb -p -B 115200 /dev/ttyUSB1                                            :(
Sending boot message. Please reboot the target.../
Sending boot image...
  0 % [......................................................................]
  2 % [......................................................................]
  4 % [................................................................

So now we have a brick booting (sometimes) from UART. That's definitely a smart brick!

nas220> version 

U-Boot 2015.04 (May 09 2015 - 15:37:28)
NAS 220
arm-none-eabi-gcc (4.8.4-1+11-1) 4.8.4 20141219 (release)
GNU ld (2.25-5+5+b1) 2.25

Writing U-Boot into flash

After we booted from UART we want to have it persistent in our flash. There are several ways to transfer our image into the RAM of the target device: USB, Ethernet, UART, …

As I already have the UART up and running I use ymodem over UART from my minicom terminal:

nas220> loady                                                                                                                      
## Ready for binary (ymodem) download to 0x00800000 at 115200 bps...                                                               
C## Total Size      = 0x0006a5c0 = 435648 Bytes                                                                                    

So we transfered 0x0006a5c0 bytes to RAM memory address 0x00800000. From there we copy it to flash address 0x00:

nas220> nand erase 0x0 0x6a5c0                                                                                                     
NAND erase: device 0 offset 0x0, size 0x6a5c0                                                                                      
Erasing at 0x68000 -- 100% complete.                                                                                               
OK
nas220> nand write 0x00800000 0x00 0x6a5c0                                                                                         
                                                                                                                                   
NAND write: device 0 offset 0x0, size 0x6a5c0
 435648 bytes written: OK

That should do. Lets reboot the Device.

U-Boot 2015.04 (May 09 2015 - 15:37:28)
NAS 220

SoC:   Kirkwood 88F6281_A1
DRAM:  128 MiB
WARNING: Caches not enabled
NAND:  32 MiB
NAND read from offset a0000 failed -74
*** Warning - readenv() failed, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   egiga0
Error: egiga0 address not set.

88E1116 Initialized on egiga0
IDE:   Bus 0: .....OK Bus 1: not available  
  Device 0: Model: SAMSUNG HD251HJ  Firm: 1AC01113 Ser#: S1FYJ90QB26678
            Type: Hard Disk
            Supports 48-bit addressing
            Capacity: 238418.5 MB = 232.8 GB (488281250 x 512)
nas220> 

Settings

This was the situation I was in when I got reply from Evgeni the contributor of the kernel- and U-Boot sources. He sent me his kernel config and images for the kernel and the device tree and his U-Boot settings. I used his setup that boots from a USB stick. You could boot from one of the hard disks as well, from Network or from the internal flash, but booting from the USB stick makes it very easy to change things as long as you don't have a SSH server up and running at the target device.

So here is my U-Boot setup:

autoload=no
autostart=no
baudrate=115200
bootargs=console=ttyS0,115200 root=PARTUUID=${UUID_FROM_BOOT_PARTITION} rw rootfstype=ext4 rootwait panic=10
bootcmd=usb start;ext2load usb 0:1 0x40000 /boot/uImage;ext2load usb 0:1 0x1c00000 /boot/kirkwood-blackarmor-nas220.dtb;fdt addr 0x1c00000;fdt resize;fdt chosen;bootm 0x40000 - 0x1c00000
bootdelay=3
ethact=egiga0
ethaddr=${MAC_PRINTED_ON_THE_BACK_OF_THE_DEVICE}
mtddevname=uboot
mtddevnum=0
mtdids=nand0=orion_nand
mtdparts=mtdparts=orion_nand:0xa0000@0x0(uboot),0x010000@0xa0000(env),0x500000@0xc0000(uimage),0x1a40000@0x5c0000(rootfs)
stderr=serial
stdin=serial
stdout=serial

If you just installed the U-Boot a lot's of these entries will not be there. You can set them with setenv - e.g.:

setenv bootdelay 3
setenv ethaddr xx:xx:xx:xx:xx:xx
setenv bootcmd 'usb start;ext2load usb 0:1 0x40000 /boot/uImage;ext2load usb 0:1 0x1c00000 /boot/kirkwood-blackarmor-nas220.dtb;fdt addr 0x1c00000;fdt resize;fdt chosen;bootm 0x40000 - 0x1c00000'

You will have to set the ethernet mac in the „ethaddr“ according to your device of course and the UUID in the „bootargs“. You can get the UUID from your USB stick from this commands in the U-Boot command shell:

nas220> usb start
starting USB...
USB0:   USB EHCI 1.00
scanning bus 0 for devices... 3 USB Device(s) found
       scanning usb for storage devices... 1 Storage Device(s) found
nas220> usb part

Partition Map for USB device 0  --   Partition Type: EFI

Part    Start LBA       End LBA         Name
        Attributes
        Type GUID
        Partition GUID
  1     0x00000800      0x00eebfde      "nasboot"
        attrs:  0x0000000000000000
        type:   0fc63daf-8483-4772-8e79-3d69d8477de4
        guid:   bae0db31-1efd-4453-8bcc-91e34be7b6bb

The UUID you are looking for is the one shown as „guid“ in the listing. As long as you don't change the partition a reformatting of the file system will not change this UUID.

Compiling the kernel

Actually compiling the kernel was the first thing I had done - then there was this little issue with the outdated stock U-Boot 0.2 that does not know about device tree files, then there was this little issue with not having any U-Boot any more and so on… So now we are in the position to boot a kernel and we should definitely do that.

I use the latest mainline kernel 4.0 from kernel.org and the arm cross toolchain packaged with my debian jessie host system:

export CROSS_COMPILE=arm-none-eabi-
export ARCH=arm
export LOADADDR=00008000

It took me some time to figure out the correct configuration for my setup, even though Evgeni had done the lion's share of work and had provided his kernel config to me. Never the less I had to do some changes to make the kernel suitable for systemd. You can use my kernel blackarmor_220_config.txt and save it into the main folder of your kernel sources as „.config“.

make oldconfig
make -j3        # a good value here is number of CPU threads + 1, I have a Core 2 Dou with only 2 cores and no hyper threading
make uImage
make kirkwood-blackarmor-nas220.dtb

You should have now arch/arm/boot/uImage (kernel image for U-Boot) and arch/arm/boot/dts/kirkwood-blackarmor-nas220.dtb (device tree image). These are the files we'll need. You will notice that there is no „make modules“ here. In my kernel config modules are disabled, that's the reason.

Creating the root file system

There is a nice manual how to create a root file system for debian from the EmbDebian project. I use the lagacy debootstrap approach as it always worked nice for me. I even did not bother to do it as root - it's your decision if you want to do that. If you scroll down a little bit you will find notes on how do do it as a non-root user but I did not test that. So here is what I did (as root on my system):

debootstrap --foreign --arch armel jessie debian_armel_jessie http://ftp.debian.org/debian/
cp /usr/bin/qemu-arm-static debian_armel_jessie/usr/bin/
DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true LC_ALL=C LANGUAGE=C LANG=C chroot debian_armel_jessie /debootstrap/debootstrap --second-stage
DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true LC_ALL=C LANGUAGE=C LANG=C chroot debian_armel_jessie dpkg --configure -a
DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true LC_ALL=C LANGUAGE=C LANG=C chroot debian_armel_jessie passwd

Then I packed the full root system into a .tar.gz and formatted my USB stick.

Creating the USB boot device

I used cfdisk to create a gpt partition table and one ext4 partition for the root system. If you change the partition table now, don't forget to go a step back and change the UUID of the kernel boot rootfs-parameter to the new value. So here is how my stick shows up:

root@major-tom:~# fdisk -l /dev/sdb

Disk /dev/sdb: 7,5 GiB, 8011120640 bytes, 15646720 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 213C8ADB-89C5-42BC-B7E4-418F50A608B1

Device     Start      End  Sectors  Size Type
/dev/sdb1   2048 15646686 15644639  7,5G Linux filesystem

I unpacked the root file system that I created before and copied the uImage and kirkwood-blackarmor-nas220.dtb that I got from the kernel compile session into the boot folder on the stick.

The result

Debian GNU/Linux 8 brick ttyS0

brick login: root
Password: 
Last login: Sat May  9 23:56:13 UTC 2015 on ttyS0
Linux brick 4.0.0 #3 Sun May 10 01:17:36 CEST 2015 armv5tel

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@brick:~# systemd-analyze
Startup finished in 5.872s (kernel) + 6.288s (userspace) = 12.160s
root@brick:~# cat /proc/version 
Linux version 4.0.0 (moritz@major-tom) (gcc version 4.8.4 20141219 (release) (4.8.4-1+11-1) ) #3 Sun May 10 01:17:36 CEST 2015
root@brick:~# 

Full boot log

Making something useful out of the NAS

Tuning

The NAS is running and you can hear it. That's OK if you want to mount this NAS to a rack in your dedicated server room, but for a NAS in my living room this is not appropreate. So we have to think about the fan speed and maybe about the Disks.

Speed down the fan

In the kernel sources of the BlackArmor you will find a reference to the i2c chip adt7476. So I looked into /sys/class/i2c and bingo:

root@brick:~# cat /sys/class/i2c-dev/i2c-0/device/0-002e/name 
adt7476
root@brick:~# cat /sys/class/i2c-dev/i2c-0/device/0-002e/pwm1
255

So what could possibly go wrong?

root@brick:~# echo 128 > /sys/class/i2c-dev/i2c-0/device/0-002e/pwm1

Oh yes! That sounds good. Bette check, what we did here:

root@brick:~# cat /sys/class/i2c-dev/i2c-0/device/0-002e/temp1_input 
33250

Well, yes. Whatever. Let's duckduckgo a little bit. Looks like lm-sensors is what we are looking for.

root@brick:~# apt-get install lm-sensors

As the driver for the sensor was compiled into the kernel we can skip sensors-detect and start right away:

root@brick:~# sensors
adt7476-i2c-0-2e
Adapter: mv64xxx_i2c adapter
in0:          +0.00 V  (min =  +0.00 V, max =  +3.31 V)
Vcore:        +1.00 V  (min =  +0.00 V, max =  +2.99 V)
+3.3V:        +3.36 V  (min =  +2.96 V, max =  +3.61 V)
+5V:          +0.00 V  (min =  +4.48 V, max =  +5.50 V)
+12V:         +0.00 V  (min =  +0.00 V, max = +15.69 V)
fan1:        2013 RPM  (min =    0 RPM)
fan2:           0 RPM  (min =    0 RPM)
fan3:           0 RPM  (min =    0 RPM)
fan4:           0 RPM  (min =    0 RPM)
temp1:        +34.8°C  (low  = -63.0°C, high = +191.0°C)
                       (crit = +100.0°C, hyst = +96.0°C)
M/B Temp:     +34.8°C  (low  = -63.0°C, high = +191.0°C)
                       (crit = +100.0°C, hyst = +96.0°C)
temp3:        +41.0°C  (low  = -63.0°C, high = +191.0°C)
                       (crit = +100.0°C, hyst = +96.0°C)
cpu0_vid:    +0.000 V

fan1, temp1 and temp3 look interesting - and reasonable!

So let's make that permanent. I found the fancontrol package and used pwmconfig to configure the fan speed. I will not provide my config here, nor describe what I did, as I don't know, if what I did was reasonabe. If you do something wrong here, you can brick your device with this tool - I mean brick-brick! Just so much: At least my device did not die from the tests pwmconfig did during it's initialization, but I will not give you any guarantee on that either.

You should monitore your actual system healty during the setup, test and some time after your settings were made permanent:

watch sensors

So After you found a appropriate configuration you can test it with

service fancontrol restart

A good temperature range for operating hard disks is 25°C to 40°C if you ask someone who should know about storage. So I checked the hard drive temperatures with smartctl and set up my fancontrol to run at a speed where this value is something just below 40°C:

root@brick:~# smartctl --all /dev/sda | grep Temperature_Celsius
194 Temperature_Celsius     0x0022   038   052   000    Old_age   Always       -       38 (0 19 0 0 0)
root@brick:~# smartctl --all /dev/sdb | grep Temperature_Celsius
194 Temperature_Celsius     0x0022   038   050   000    Old_age   Always       -       38 (0 20 0 0 0)

Spin down the Hard drives

hdparm can spin down the hard drives after some time. We can test that:

apt-get install hdparm
root@brick:~# hdparm -S 1 /dev/sdb

/dev/sdb:
 setting standby to 1 (5 seconds)
root@brick:~# hdparm -S 1 /dev/sda

/dev/sda:
 setting standby to 1 (5 seconds)

Wait some seconds and you will hear the hard drives spinning down. Unfortunately the next thing you do will take several seconds to perform, so 5 seconds is way to low value. I tried 12 (60 seconds). I'm not sure yet, if that is a good idea.