====== 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 [[https://ccc-ffm.de/hackerspace/|CCC-FFM hackquarter]] ====== Seagate Blackarmor NAS 220 ====== The Blackarmor NAS 220 is based on the [[https://origin-www.marvell.com/embedded-processors/kirkwood/|Marvell 88F6192 Kirkwood prozessor]]. Some years ago [[http://www.noerenberg.de/hajo/pub/seagate-blackarmor-nas.txt|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 [[http://lkml.iu.edu/hypermail/linux/kernel/1412.3/00410.html|patch for the Blackarmor 220 for the mainline kernel]]. Some days before he contributed source code for the [[http://lists.denx.de/pipermail/u-boot/2014-December/198043.html|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: {{https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Brick.jpg/800px-Brick.jpg|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 [[https://origin-www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf|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 [[ftp://ftp.denx.de/pub/u-boot/|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: {{:projekte:diverses:blackarmor_220_boot_fail_logic.png?800|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 [[https://bbs.archlinux.org/viewtopic.php?pid=1353672#p1353672|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 [[http://cgit.freedesktop.org/systemd/systemd/tree/README#n37|make the kernel suitable for systemd]]. You can use my kernel {{:projekte:diverses: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 [[https://wiki.debian.org/EmDebian/CrossDebootstrap#QEMU.2Fdebootstrap_approach|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 [[https://wiki.debian.org/EmDebian/CrossDebootstrap#Generating_cross_images_as_non-root_user|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 [[projekte:diverses:seagate_blackarmor_nas_220_debian#settings|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:~# {{:projekte:diverses:blackarmor_220_bootlog.txt|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 [[https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/arch/arm/boot/dts/kirkwood-blackarmor-nas220.dts?id=refs/tags/v4.0.5 | 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 [[https://www.youtube.com/watch?v=WSuYQ2YZck0|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 [[http://www.cyberciti.biz/faq/howto-linux-get-sensors-information/|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 [[http://research.google.com/archive/disk_failures.pdf|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.