DNS-320L NAS

Table of Contents

1. Intro

The D-Link DNS-320L is a simple 2-bay SATA NAS device which can run multiple versions of Linux. This post provides information on how to run the newest (at the point of writing) mainline kernel on it without patching as well as how to build a simple initramfs using buildroot. This is a bit different than other projects building Linux which usually focus on using debian packages.

2. Hardware

There exist at least four versions of the hardware, I own two of them and the ones that I own can be distinguished by using the following features:

Version P/N on bottom label HW version on bottom label U-Boot banner Other distinguishing marks Notes
DNS-320L A1         Referenced here
DNS-320L A2         Referenced here
DNS-320L A3 ENS320LM…..A3E H/W Ver.: A3 U-Boot 1.1.4 (Aug 22 2012 - 17:06:54) Marvell version: 3.6.0.DNS-320L.01 Text "TWO BAY NETWORK ATTACHED STORAGE" on top plastic cover Only 100 Mbit link working?
DNS-320L A4 ENS320LM…..A4E H/W Ver.: A4 U-Boot 1.1.4 (Apr 17 2014 - 17:31:34) Marvell version: 3.6.0.DNS-320L.01    

In the A3 version I have only the 100 Mbit Ethernet link is working contrary to the NAS being advertised as supporting 1000 Mbps Ethernet. This is broken both in the stock firmware and in the kernel that I have built so I suspect it's some hardware problem. Is this a bug on this board revision or is my particular NAS damaged I do not know.

There are differences between the A3 and A4 versions in the type of memory chips and used Ethernet transformer. Other than that I have not noticed any differences.

The system is based on a Marvell Kirkwood 1GHz SOC, other chips include an Ethernet controller, flash, RAM as well as an MCU which is a systems management controller similar to what you would have in a laptop or PC. The NAS has it's page on both deviwiki and new wikidevi where detailed information about the chips on the board can be found. Different devices based on the 88F6702 SoC used are:

The main board looks like this:

thumb-board1.jpg

Number Label Chip type on A3 board Chip type on A4 board Description
1 M1 Fan: AVC DS04010B12U   The fan connector
2 JP1     The serial console
3 U2 Hynix H27U1G8F2BTR   NAND flash
4 U3 Marvell 88E1318R   Ethernet chip
5       Testpads (likely JTAG)
6 U7 Marvell 88F6702   The CPU
7 U10,U11 Nanya NT5TU128M8GE-AC Hynix H5PS1G83KFR RAM chips
8 U14 Weltrend WT69P3   The system management MCU
9 JP2     WT69P3 programming bus?
10 T1 MNC G2436CG MNC G2497CG Ethernet transformer (datasheet)
         

The exact datasheet for the Marvell 88F6702 is nowhere to be found, however according to the Marvell Product Selection Guide and other available info this SoC looks to be a faster 1GHz clock variant of the Marvell 88F6192. In order to access the unpopulated pads on the board I soldered two pin connectors, because the JP2 pitch was smaller than the standard 2.54mm pinheads I had I used some wire to route it to where it can be accessed:

thumb-connectors.jpg

The board contains four LEDs with the following purpose:

Label Color Description
D6 Blue Power-on and booting indicator LED
D7 Red "USB" LED
D8 Red SATA1 port activity LED
D9 Red SATA2 port activity LED

2.0.1. JP1 connector

The JP1 connector is the bootloader and device operating system console. It runs at 3.3V logic levels with baudrate of 115200 bps, 8 bits, no parity and 1 stop bit. The pinout is the following:

Pin number Description Notes
1 RXD Square pad, Device <– Host
2 N/C  
3 3.3V source
4 GND  
5 TXD Device –> Host

2.0.2. Weltrend WT69P3

The WT69P3 is a systems management MCU which controls the power to the board, provides an RTC for time keeping and controls the fan. The MCU is connected via a RS232 link with the main CPU and in the original firmare a daemon in the system communicates with it. The communications protocol has been reverse-engineered and there exist at least two independent open-source implementations of the manamgement daemon - https://www.aboehler.at/hg/dns320l-daemon and https://github.com/martignlo/DNS-320L.

2.0.3. JP2 connector

This connector seems to terminate an I2C bus. Both lines have pullups to +3.3 V and the Weltrend chip's ISP protocol is I2C according to information from the manufacturer. Unfortunately the programmer software published uses a custom WLINK-I2C adapter with a WT6563 microcontroller. Unfortunately I was not able to find any place selling this programmer online. The assumption was that this is the ISP interface for the Weltrend WT69P3 MCU.

When I connected a Saleae logic analyzer to the bus I noticed something interesting however. When the system boots it tries to initiate a write to address 0x40.

[WT69P3-boot.png]

In order to investigate this I used an Arduino board and the builtin Wire library to make an I2C slave respond to the address where the MCU is writing. The code for the sketch used is below:

#include <Wire.h>

void setup()
{
  Wire.begin(0x20);
  Wire.onReceive(receiveCmd);
  Wire.onRequest(sendResponse);
  Serial.begin(9600);
}

void loop()
{
  delay(100);
}

void receiveCmd(int howMany)
{
  while(Wire.available()>0) // loop through all but the last
  {
    char c = Wire.read(); // receive byte as a character
    Serial.print("CMD: ");
    Serial.println(c, HEX);         // print the character
  }
}

void sendResponse() {
  Wire.write(0xAA);
}

The wiring is documented in the Wire library reference page. Now things have started to look more interesting:

[WT69P3-i2c-write.png]

When we decode the traffic we see that the MCU is first writing byte 0x00 to address 0x40 and then reading a byte from address 0x41:

Time [s], Analyzer Name, Decoded Protocol Result
4.226217250000000,I2C,Setup Write to [0x40] + ACK
4.228212250000000,I2C,0x00 + ACK
4.233196500000000,I2C,Setup Read to [0x41] + ACK
4.235190500000000,I2C,0xAA + NAK

As I was expecting the second read to be some kind of status register I tried to send all 256 different responses to see what would happen. Some bytes sent back have triggered interesting behaviour:

Response byte Boot message LEDs
0x01 Module 0 is TDM  
0x02 Module 0 is AUDIO D7 and D9 LEDs light up
0x03 Module 0 is RGMII  
0x04 Module 0 is GMII  
0x05 Module 0 is TS  
0x06 Module 0 is MII  
0x07 Module 0 is TDM  
0x09 Error!, MV88F6282 doesn't support LCD module when booting from NAND!  

Later I noticed an "iprobe" command in the U-Boot help. It detected 3 addresses on the bus:

Marvell>> iprobe
Valid chip addresses: 13 20 64

This bus layout seems to be confirmed when we scan the bus with buspirate:

I2C>(1)
Searching I2C address space. Found devices at:
0x02(0x01 W) 0x26(0x13 W) 0x27(0x13 R) 0x40(0x20 W) 0x41(0x20 R) 0xC9(0x64 R) 

What is interesting apart from the 0x13, 0x20 (our fake Arduino slave) and 0x64 we also get write address 0x02. Interestingly, when the device is not booting (when LED6 is not blinking) the 0x64 is not present:

I2C>(1)
Searching I2C address space. Found devices at:
0x02(0x01 W) 0x26(0x13 W) 0x27(0x13 R) 0x40(0x20 W) 0x41(0x20 R) 

The "Boot message" documents additional messages that are printed by U-Boot when we respond to a read from 0x20 with a particular byte, for example for response 0x04:

 ** MARVELL BOARD: DB-88F6702A-BP LE 

U-Boot 1.1.4 (Aug 22 2012 - 17:06:54) Marvell version: 3.6.0.DNS-320L.01

U-Boot code: 00600000 -> 0067FFF0  BSS: -> 006CFB00

Soc: 88F6702 A1 CPU running @ 1000Mhz L2 running @ 500Mhz
SysClock = 400Mhz , TClock = 166Mhz 

DRAM (DDR2) CAS Latency = 5 tRP = 5 tRAS = 18 tRCD=6
DRAM CS[0] base 0x00000000   size 256MB 
DRAM Total size 256MB  16bit width
Addresses 8M - 0M are saved for the U-Boot usage.
Mem malloc Initialization (8M - 7M): Done
NAND:128 MB
Flash:  0 kB

CPU : Marvell Feroceon (Rev 1)

Streaming disabled 
Write allocate disabled

Module 0 is GMII

USB 0: host mode

It looks like the 0x20 address is some kind of peripheral type detection mechanism and the u-boot code is shared between different devices. I have found references to the "Boot message" strings from the table in various places on the internet, for example here, here and here always in connection to some hardware using the Kirkwood chipset.

3. Bootloader

The board uses the U-Boot bootloader like other Kirkwood-based devices. The boot process can be escaped in the usual way for U-Boot - by pressing SPACE and then 1. When we do this we are greeted with the U-Boot prompt and can poke around various commands. Below you can see exploration results of the information seen by the bootloader:

Marvell>> printenv
bootargs=root=/dev/ram console=ttyS0,115200 :::DB88FXX81:egiga0:none
baudrate=115200
loads_echo=0
ipaddr=2.66.66.201
serverip=2.66.66.32
rootpath=/srv/ubuntu
netmask=255.255.255.0
run_diag=yes
console=console=ttyS0,115200 mtdparts=nand_mtd:0xc0000@0(uboot)ro,0x7f00000@0x100000(root)
MALLOC_len=1
ethprime=egiga0
bootargs_root=root=/dev/nfs rw
bootargs_end=:::DB88FXX81:eth0:none
image_name=uImage
standalone=fsload 0x2000000 $(image_name);setenv bootargs $(console) root=/dev/mtdblock0 rw ip=$(ipaddr):$(serverip)$(bootargs_end) $(mvPhoneConfig); bootm 0x2000000;
ethaddr=00:50:43:00:02:02
ethmtu=1500
mvPhoneConfig=mv_phone_config=dev[0]:fxs,dev[1]:fxo
mvNetConfig=mv_net_config=(00:11:88:0f:62:81,0:1:2:3),mtu=1500
usb0Mode=host
yuk_ethaddr=00:00:00:EE:51:81
nandEcc=1bit
netretry=no
rcvrip=169.254.100.100
loadaddr=0x02000000
autoload=no
image_multi=yes
ethact=egiga0
bootcmd=nand read.e 0xa00000 0x100000 0x300000;nand read.e 0xf00000 0x600000 0x300000;bootm 0xa00000 0xf00000
stdin=serial
stdout=serial
stderr=serial
mainlineLinux=no
enaMonExt=no
enaCpuStream=no
enaWrAllo=no
pexMode=RC
disL2Cache=no
setL2CacheWT=yes
disL2Prefetch=yes
enaICPref=yes
enaDCPref=yes
sata_dma_mode=yes
netbsd_en=no
vxworks_en=no
bootdelay=1
disaMvPnp=no
enaAutoRecovery=yes
pcieTune=no
Marvell>> version

U-Boot 1.1.4 (Aug 22 2012 - 17:06:54) Marvell version: 3.6.0.DNS-320L.01
Marvell>> usb start
(Re)start USB...
USB:   scanning bus for devices... 2 USB Device(s) found
Waiting for storage device(s) to settle before scanning...
1 Storage Device(s) found
Marvell>> usb tree

Device Tree:
  1  Hub (480MBit/s, 0mA)
  |  Marvell EHCI 
  |
  +-2  Mass Storage (480MBit/s, 200mA)
       Kingston DT 100 G2 XXXXXXXXXXXXXXXXXXXX
     
Marvell>> usb storage
  Device 0: Vendor: Kingston Prod.: DT 100 G2        Rev: PMAP
            Type: Removable Hard Disk
            Capacity: 3736.9 MB = 3.6 GB (7653312 x 512)
Marvell>> Temp
Unknown command 'Temp' - try 'help'
Marvell>> temp
Tj temp is 0
Marvell>> sp

Bus: 0 Device: 0 Func: 0 Vendor ID: 11ab Device ID: 6702
-------------------------------------------------------------------
Class: Memory controller
PCI_BAR0 (Mem-64bit) base: 0f1000000	size: 1048576 bytes
PCI_BAR1 (Mem-64bit) base: 000000000		size: 268435456 bytes
Marvell>> sg
PHY 0 :
---------
Auto negotiation: Enabled
Speed: 100 Mbps
Duplex: Half
Link: up

PHY 1 :
---------
Auto negotiation: Enabled
Speed: Uknown
Duplex: Full
Link: up
Marvell>> nand info

Device 0: NAND 128MB 3,3V 8-bit, sector size 128 KB
Marvell>> map

CPU Interface
-------------
SDRAM_CS0 ....base 00000000, size 256MB 
SDRAM_CS1 ....disable
SDRAM_CS2 ....disable
SDRAM_CS3 ....disable
PEX0_MEM ....base 90000000, size 128MB 
PEX0_IO ....base f0000000, size  16MB 
PEX1_MEM ....no such
PEX1_IO ....no such
INTER_REGS ....base f1000000, size   1MB 
NFLASH_CS ....base f9000000, size   8MB 
SPI_CS ....base f8000000, size  16MB 
BOOT_ROM_CS ....no such
DEV_BOOTCS ....no such
CRYPT_ENG ....base fb000000, size  64KB 

AHB To MBUS Bridge:
-------------------
win0 - PEX0_MEM base 90000000, ....size 128MB 
win1 - disable
win2 - PEX0_IO base f0000000, ....size  16MB 
win3 - disable
win4 - NFLASH_CS base f9000000, ....size   8MB 
win5 - SPI_CS base f8000000, ....size  16MB 
win6 - disable
win7 - CRYPT_ENG base fb000000, ....size  64KB 
win8 - INTER_REGS base f1000000, ....size   1MB 

PEX0:
-----

Pex Bars 

Internal Regs Bar0.... base f1000000, size   1MB 
DRAM Bar1............. base 00000000, size 256MB 
Devices Bar2.......... disable

Pex Decode Windows

win0 - SDRAM_CS0 base 00000000, ....size 256MB 
win1 - disable
win2 - disable
win3 - disable
win4 - disable
win5 - disable
default win - target unknown 
Expansion ROM - NFLASH_CS 

USB:
----
Device 0:
win0 - SDRAM_CS0 base 00000000, size 256MB 
win1 - PEX0_MEM base 90000000, size 128MB 
win2 - disable
win3 - disable

ETH 0:
----
win0 - SDRAM_CS0 base 00000000, ....size 256MB 
win1 - NFLASH_CS base f9000000, ....size   8MB 
win2 - SPI_CS base f8000000, ....size  16MB 
win3 - PEX0_IO base f0000000, ....size  16MB 
win4 - disable
win5 - disable

XOR 0:
----
win0 - NFLASH_CS base f9000000, size   8MB 
win1 - PEX0_MEM base 90000000, size 128MB 
win2 - SDRAM_CS0 base 0, size 256MB 
win3 - SPI_CS base f8000000, size  16MB 
win4 - CRYPT_ENG base fb000000, size  64KB 
win5 - disable
win6 - disable
win7 - disable

XOR 1:
----
win0 - NFLASH_CS base f9000000, size   8MB 
win1 - PEX0_MEM base 90000000, size 128MB 
win2 - SDRAM_CS0 base 0, size 256MB 
win3 - SPI_CS base f8000000, size  16MB 
win4 - CRYPT_ENG base fb000000, size  64KB 
win5 - disable
win6 - disable
win7 - disable

SATA 0:
----
win0 - SDRAM_CS0 base 00000000, ....size 256MB 
win1 - SDRAM_CS1 base 10000000, ....size 256MB 
win2 - SDRAM_CS2 base 20000000, ....size 256MB 
win3 - SDRAM_CS3 base 30000000, ....size 256MB 

SATA 1:
----
win0 - SDRAM_CS0 base 00000000, ....size 256MB 
win1 - SDRAM_CS1 base 10000000, ....size 256MB 
win2 - SDRAM_CS2 base 20000000, ....size 256MB 
win3 - SDRAM_CS3 base 30000000, ....size 256MB 

AUDIO:
----
win0 - SDRAM_CS0 base 00000000, ....size 256MB 
win1 - SDRAM_CS1 base 10000000, ....size 256MB 
Marvell>> dclk
TCLK 166Mhz, SYSCLK 400Mhz (UART baudrate 115200)
Marvell>> ide reset

Reset IDE: 
Marvell Serial ATA Adapter
Integrated Sata device found
[0 0 0]: Enable DMA mode (6)
  Device 0 @ 0 0:
Model: HITACHI HUA722010ALA330                  Firm: JP4ONA01 Ser#: XXXXXX
            Type: Hard Disk
            Supports 48-bit addressing
            Capacity: 953869.7 MB = 931.5 GB (1953525168 x 512)
[0 1 0]: Enable DMA mode (6)
  Device 1 @ 0 1:
Model: ST31000524AS                             Firm: JC4A     Ser#:             XXXXXXXXXX
            Type: Hard Disk
            Supports 48-bit addressing
            Capacity: 953869.7 MB = 931.5 GB (1953525168 x 512)

Some of these variables are documented, some seem to be Marvell or Kirkwood specific cruft. The bootloader version is ancient, according to github, version 1.1.4 was released in 2005.

4. Original firmware

The original firmware resides on the NAND flash and an example of the entire boot console log is provided below:

 ** MARVELL BOARD: DB-88F6702A-BP LE 

U-Boot 1.1.4 (Aug 22 2012 - 17:06:54) Marvell version: 3.6.0.DNS-320L.01

U-Boot code: 00600000 -> 0067FFF0  BSS: -> 006CFB00

Soc: 88F6702 A1 CPU running @ 1000Mhz L2 running @ 500Mhz
SysClock = 400Mhz , TClock = 166Mhz 

DRAM (DDR2) CAS Latency = 5 tRP = 5 tRAS = 18 tRCD=6
DRAM CS[0] base 0x00000000   size 256MB 
DRAM Total size 256MB  16bit width
Addresses 8M - 0M are saved for the U-Boot usage.
Mem malloc Initialization (8M - 7M): Done
NAND:128 MB
Flash:  0 kB

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

 3145728 bytes read: OK
## Booting image at 00a00000 ...
   Image Name:   Linux-2.6.31.8
   Created:      2012-08-22   8:55:08 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    2630552 Bytes =  2.5 MB
   Load Address: 00008000
   Entry Point:  00008000
   Verifying Checksum ... OK
OK
## Loading Ramdisk Image at 00f00000 ...
   Image Name:   Ramdisk
   Created:      2014-12-26   3:00:57 UTC
   Image Type:   ARM Linux RAMDisk Image (gzip compressed)
   Data Size:    1743894 Bytes =  1.7 MB
   Load Address: 00e00000
   Entry Point:  00e00000
   Verifying Checksum ... OK

Starting kernel ...

Uncompressing Linux......................................................................................................................................................................... done, booting the kernel.
Linux version 2.6.31.8 (jack@swtest6) (gcc version 4.3.2 (sdk3.3-ct-ng-1.4.1) ) #1 Wed Aug 22 16:55:05 CST 2012
CPU: Feroceon 88FR131 [56251311] revision 1 (ARMv5TE), cr=00053977
CPU: VIVT data cache, VIVT instruction cache
Machine: Feroceon-KW
Using UBoot passing parameters structure
Memory policy: ECC disabled, Data cache writeback
Built 1 zonelists in Zone order, mobility grouping off.  Total pages: 65024
Kernel command line: root=/dev/ram console=ttyS0,115200 :::DB88FXX81:egiga0:none
PID hash table entries: 1024 (order: 10, 4096 bytes)
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
Memory: 256MB = 256MB total
Memory: 246272KB available (4960K code, 334K data, 136K init, 0K highmem)
Hierarchical RCU implementation.
NR_IRQS:128
Console: colour dummy device 80x30
Calibrating delay loop... 999.42 BogoMIPS (lpj=4997120)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
NET: Registered protocol family 16
Feroceon L2: Enabling L2
Feroceon L2: Cache support initialised.

CPU Interface
-------------
SDRAM_CS0 ....base 00000000, size 256MB 
SDRAM_CS1 ....disable
SDRAM_CS2 ....disable
SDRAM_CS3 ....disable
PEX0_MEM ....base e0000000, size 128MB 
PEX0_IO ....base f2000000, size   1MB 
PEX1_MEM ....no such
PEX1_IO ....no such
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_5.1.3_patch29)-- DB-88F6702A-BP  Soc: 88F6702 A1 LE

 Detected Tclk 166666667 and SysClk 400000000 
MV Buttons Device Load
Marvell USB EHCI Host controller #0: c8040740
PEX0 interface detected no Link.
PCI: bus0: Fast back to back transfers enabled
mvPexLocalBusNumSet: ERR. Invalid PEX interface 1
bio: create slab  at 0
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
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
NET: Registered protocol family 1
Trying to unpack rootfs image as initramfs...
rootfs image is not initramfs (no cpio magic); looks like an initrd
Freeing initrd memory: 1700K
RTC has been updated!!!
rtc mv_rtc: rtc core: registered kw-rtc as rtc0
RTC registered
cpufreq: Init kirkwood cpufreq driver
XOR registered 4 channels
XOR 2nd invalidate WA enabled
cesadev_init(c000ed5c)
mvCesaInit: sessions=640, queue=64, pSram=f0000000
MV Buttons Driver Load
VFS: Disk quotas dquot_6.5.2
Dquot-cache hash table entries: 1024 (order 0, 4096 bytes)
squashfs: version 4.0 (2009/01/31) Phillip Lougher
Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
NTFS driver 2.1.29 [Flags: R/O].
JFFS2 version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
fuse init (API version 7.12)
msgmni has been set to 484
alg: No test for cipher_null (cipher_null-generic)
alg: No test for ecb(cipher_null) (ecb-cipher_null)
alg: No test for digest_null (digest_null-generic)
alg: No test for compress_null (compress_null-generic)
alg: No test for lzma (lzma-generic)
alg: No test for stdrng (krng)
alg: No test for hmac(digest_null) (hmac(digest_null-generic))
Block layer SCSI generic (bsg) driver version 0.4 loaded (major 253)
io scheduler noop registered
io scheduler anticipatory registered (default)
Initializing ths8200_init
Initializing dove_adi9889_init
Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
serial8250.0: ttyS0 at MMIO 0xf1012000 (irq = 33) is a 16550A
console [ttyS0] enabled
serial8250.1: ttyS1 at MMIO 0xf1012100 (irq = 34) is a 16550A
brd: module loaded
loop: module loaded
Integrated Sata device found
IRQ 21/mvSata: IRQF_DISABLED is not guaranteed on shared IRQs
scsi0 : Marvell SCSI to SATA adapter
scsi1 : Marvell SCSI to SATA adapter
Loading Marvell Ethernet Driver:
  o Cached descriptors in DRAM
  o DRAM SW cache-coherency
  o 2 Giga ports supported
  o Single RX Queue support - ETH_DEF_RXQ=0
  o Single TX Queue support - ETH_DEF_TXQ=0
  o TCP segmentation offload (TSO) supported
  o Large Receive offload (LRO) supported
  o Receive checksum offload supported
  o Transmit checksum offload supported
  o Network Fast Processing (Routing) supported - (Disabled)
  o Driver ERROR statistics enabled
  o Proc tool API enabled
  o SKB Reuse supported - (Disabled)
  o SKB Recycle supported - (Disabled)
  o Rx descripors: q0=128
  o Tx descripors: q0=532
  o Loading network interface(s):
     o register under mv88fx_eth platform
     o egiga0, ifindex = 2, GbE port = 0

Warning: Giga 1 is Powered Off

mvFpRuleDb (c0edc000): 2048 entries, 8192 bytes
Counter=0, opIdx=6, overhead=16
Counter=1, opIdx=2, overhead=0
Counter=2, opIdx=1, overhead=18
Counter=3, opIdx=2, overhead=0
NAND device: Manufacturer ID: 0xad, Chip ID: 0xf1 (Hynix NAND 128MiB 3,3V 8-bit)
Scanning device for bad blocks
Using static partition definition
Creating 7 MTD partitions on "nand_mtd":
0x000000000000-0x000000100000 : "u-boot"
0x000000100000-0x000000600000 : "uImage"
0x000000600000-0x000000b00000 : "ramdisk"
0x000000b00000-0x000006f00000 : "image"
0x000006f00000-0x000007900000 : "rescue firmware"
0x000007900000-0x000007e00000 : "config"
0x000007e00000-0x000008000000 : "my-dlink"
ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
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
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
uhci_hcd: USB Universal Host Controller Interface driver
Initializing USB Mass Storage driver...
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
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.15.0-ioctl (2009-04-01) initialised: dm-devel@redhat.com
usbcore: registered new interface driver usbhid
usbhid: v2.6:USB HID core driver
TCP cubic registered
NET: Registered protocol family 17
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
rtc mv_rtc: setting system clock to 2000-01-01 00:00:00 UTC (946684800)
md: Waiting for all devices to be available before autodetect
md: If you don't use raid, use raid=noautodetect
md: Autodetecting RAID arrays.
md: Scanned 0 and added 0 devices.
md: autorun ...
md: ... autorun DONE.
RAMDISK: gzip image found at block 0
VFS: Mounted root (ext2 filesystem) on device 1:0.
Freeing init memory: 136K
init started: BusyBox v1.20.2 (2013-11-27 15:54:37 CST)
starting pid 536, tty '': '/etc/rc.sh'
 Mounting /etc/fstab
umount: can't umount /proc: Invalid argument
umount: can't umount /usr/local/modules: Invalid argument
sh: can't open '/usr/sbin/pre_usb.sh'
first good block is 0
image len = 39137280 , image checksum = beaa9c0
umount: can't umount /usr/local/tmp: Invalid argument
dump image checksum=beaa9c0
mount cmd:busybox mount -t squashfs -o loop /usr/local/tmp/image.cfs /usr/local/modules
ln: /lib/./libnss_dns-2.8.so: File exists
ln: /lib/./libnss_dns.so.2: File exists
ln: /usr/sbin/./system_init: File exists
hardware init
GbE port 0: TxEnable WA - Enabled, deep=1, tx_en_bk=1

mtd check v1.02.08062012
config mtd type is JFFS2
/usr/local/config free size is 4767744
 copy config files
cp: can't stat '/usr/local/config/user.log.old': No such file or directory
usbcore: registered new interface driver usblp
 set loopback interface
old firmware ver:20141226
new firmware ver:20141226
first good block is 0
mac1 = 70:62:B8:2A:52:73
lan0:ifconfig egiga0 hw ether 70:62:B8:2A:52:73
egiga0: mac address changed
egiga0: started
Support Mydlink
NET: Registered protocol family 10
lo: Disabled Privacy Extensions
ADDRCONF(NETDEV_UP): egiga0: link is not ready
IPv6 over IPv4 tunneling driver
sit0: Disabled Privacy Extensions
ip6tnl0: Disabled Privacy Extensions
IPv4 over IPv4 tunneling driver
tunl0: Disabled Privacy Extensions
net.ipv6.conf.default.accept_dad = 2
net.ipv6.conf.egiga0.accept_dad = 2
net.ipv6.conf.default.dad_transmits = 1
net.ipv6.conf.egiga0.dad_transmits = 1
net.ipv6.conf.default.forwarding = 0
net.ipv6.conf.default.accept_redirects = 1
 execute rc.init.sh
awk: /var/run/udhcpc0.pid: No such file or directory
udhcpc (v1.20.2) started
Sending discover...
Sending discover...
Sending discover...
init egiga0
No lease, forking to background
killall: crond: no process killed
 set Time Zone ****
Fri Dec 31 22:00:51 GMT 1999
 get Time from rtc and set it into system ****
rtc: RTC time = 2020/3/2 Mon 10:16:15
Mon Mar  2 10:16:15 GMT 2020
 Do not adjust RTC time ***

Module IPC SERVER Version:(1.00.20090706)

ads=0
created mail daemon thread 0
ifconfig: egiga1: error fetching interface information: Device not found
Starting system message bus
Command: wget -T5 -t3 -q http://cfaj.freeshell.org/ipaddr.cgi -O /tmp/exip.0
Command: wget -T5 -t3 -q http://icanhazip.com/ -O /tmp/exip.1
Command: wget -T5 -t3 -q http://ifconfig.me/ip -O /tmp/exip.2
Command: wget -T5 -t3 -q http://whatismyip.org/ -O /tmp/exip.3
Command: wget -T5 -t3 -q http://ifconfig.me/ip -O /tmp/exip.4
Command: wget -T5 -t3 -q http://checkip.dyndns.com:8245/ -O /tmp/exip.5
config egiga0 169.254.173.176
RTNETLINK answers: File exists
call load_module network

Up_Send_Ctl : Can not find specified command "SysIP1"
Command line is not complete. Try option "help"
zcip: script /usr/share/udhcpc/zcip.script config failed, exitcode=1
Stop NFS Deamon....
Stop NFS mountd....
Unload Driver....
Stop Portmap.
No NFS information .
Stop NFS Server OVER.
Start config the NFS needed file....
Config Over.
No NFS information .
Start portmap....
Load Driver .
Start NFS Deamon .
svc: failed to register lockdv1 RPC service (errno 97).
NFSD: Using /var/lib/nfs/v4recovery as the NFSv4 state recovury0di�e{u�_k�owSf:�unicne*�o*gind recovery directory /var/lib/nfs/v4recovery
NFSD: starting 90-second grace period
Start NFS Server OVER .
cp: can't stat '/usr/local/config/Mydlink_Status.xml': No such file or directory
mcu version 1.02
system daemon v1.03.20130707
chk_io v1.03.20130502

mfg_start version 1.00(2014-12-26)

Mon Mar  2 10:16:42 2020

usb_dir []
cp: can't stat '/usr/local/config/mydlink_time.xml': No such file or directory
2020-03-02 10:16:39: (../../src/log.c.166) server started 
killall: chk_hotplug: no process killed
sh: you need to specify whom to kill
killall: dcp: no process killed
2020-03-02 10:16:42: (../../src/log.c.166) server started 
kinmyno��signalc: no process killed
usb_dir [/]
filename_mfg mfg_DNS_320L
check //mfg_DNS_320L file
opeo*��/mfw_Vn[�3::m�vime>gainme�jkillall: upnpc-ddns: no process killed
killall: tsa: no process killed
opt.local stop�ok.
o|w/oo{un���izu6ok��Jkillall: smbd: no process killed

Please press Enter to activate this console. LED_POWER_ON

5. Building mainline Linux kernel

I managed to build the mainline kernel 5.5.7 using a slightly modified device tree from github using Ubuntu 18.04 LTS:

➜  linux-5.5.7 lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.4 LTS
Release:	18.04
Codename:	bionic

The GCC version used was 7.5.0:

➜  linux-5.5.7 arm-linux-gnueabi-gcc -v
Using built-in specs.
COLLECT_GCC=arm-linux-gnueabi-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/arm-linux-gnueabi/7/lto-wrapper
Target: arm-linux-gnueabi
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 7.5.0-3ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --with-system-zlib --with-target-system-zlib --enable-multiarch --enable-multilib --disable-sjlj-exceptions --with-arch=armv5t --with-float=soft --disable-werror --enable-multilib --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=arm-linux-gnueabi --program-prefix=arm-linux-gnueabi- --includedir=/usr/arm-linux-gnueabi/include
Thread model: posix
gcc version 7.5.0 (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 

In order to install this compiler you should run the command:

➜  linux-5.5.7 sudo apt install -y gcc-arm-linux-gnueabi

Now we can setup an alias which will be useful for building all other software. The alias should use the prefix for the compiler we just installed:

➜  linux-5.5.7 alias cross-make='make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-'

First we need to create a default config for the mvebuv5 target. Why mvebu? mv means Marvell, EBU is Engineering Business Unit and v5 is the ARM architecture version. Therefore:

➜  linux-5.5.7 cross-make mvebu_v5_defconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  HOSTCC  scripts/kconfig/confdata.o
  HOSTCC  scripts/kconfig/expr.o
  LEX     scripts/kconfig/lexer.lex.c
  YACC    scripts/kconfig/parser.tab.[ch]
  HOSTCC  scripts/kconfig/lexer.lex.o
  HOSTCC  scripts/kconfig/parser.tab.o
  HOSTCC  scripts/kconfig/preprocess.o
  HOSTCC  scripts/kconfig/symbol.o
  HOSTCC  scripts/kconfig/util.o
  HOSTLD  scripts/kconfig/conf
#
# configuration written to .config
#

Now we need to copy in the Device Tree (.dts) file from the github repo to our Linux source directory:

➜ ~ git clone https://github.com/scus1/dns320l
Cloning into 'dns320l'...
remote: Enumerating objects: 327, done.
remote: Total 327 (delta 0), reused 0 (delta 0), pack-reused 327
Receiving objects: 100% (327/327), 82.17 KiB | 203.00 KiB/s, done.
Resolving deltas: 100% (154/154), done.
➜ ~ cp dns320l/kernel/dts/kirkwood-dns320l.dts linux-5.5.7/arch/arm/boot/dts 

At this point we can build the U-boot kernel image (uImage) and the DTB which is a compiled version of the Device Tree:

➜  linux-5.5.7 cross-make -j16 LOADADDR=0x8000 uImage kirkwood-dns320l.dtb  
[...]
  CALL    scripts/atomic/check-atomics.sh
  CALL    scripts/checksyscalls.sh
  CHK     include/generated/compile.h
  Kernel: arch/arm/boot/Image is ready
  Kernel: arch/arm/boot/zImage is ready
  UIMAGE  arch/arm/boot/uImage
Image Name:   Linux-5.5.7
Created:      Sat Apr  4 21:49:09 2020
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    4550496 Bytes = 4443.84 KiB = 4.34 MiB
Load Address: 00008000
Entry Point:  00008000
  Kernel: arch/arm/boot/uImage is ready
➜  linux-5.5.7 

The kernel image and DTB files need to be joined together for the kernel to notice the DTB blob. Then a new uImage needs to built from the joined file:

➜  linux-5.5.7 cat arch/arm/boot/zImage arch/arm/boot/dts/kirkwood-dns320l.dtb > arch/arm/boot/zImage-dtb 
➜  linux-5.5.7 bash ./scripts/mkuboot.sh -A arm -O linux -C none  -T kernel -a 0x8000 -e 0x8000 -n 'Linux-5.5.7' -d arch/arm/boot/zImage-dtb arch/arm/boot/uImage
Image Name:   Linux-5.5.7
Created:      Sat Apr  4 21:51:29 2020
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    4561674 Bytes = 4454.76 KiB = 4.35 MiB
Load Address: 00008000
Entry Point:  00008000
➜  linux-5.5.7 

Now the kernel can be booted with PXE for example:

## Booting image at 00a00000 ...
   Image Name:   Linux-5.5.7
   Created:      2020-04-04  19:51:29 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    4561674 Bytes =  4.4 MB
   Load Address: 00008000
   Entry Point:  00008000
   Verifying Checksum ... OK
OK

Starting kernel ...

Booting Linux on physical CPU 0x0
Linux version 5.5.7 (enki@newton) (gcc version 7.5.0 (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04)) #1 PREEMPT Sat Apr 4 21:47:13 CEST 2020
CPU: Feroceon 88FR131 [56251311] revision 1 (ARMv5TE), cr=0005397f
CPU: VIVT data cache, VIVT instruction cache
OF: fdt: Machine model: D-Link DNS-320L
Memory policy: Data cache writeback
Built 1 zonelists, mobility grouping on.  Total pages: 65024
Kernel command line: root=/dev/ram console=ttyS0,115200 :::DB88FXX81:egiga0:none
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes, linear)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes, linear)
mem auto-init: stack:off, heap alloc:off, heap free:off
Memory: 250112K/262144K available (6669K kernel code, 286K rwdata, 1676K rodata, 200K init, 657K bss, 12032K reserved, 0K cma-reserved, 0K highmem)
SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
rcu: Preemptible hierarchical RCU implementation.
	Tasks RCU enabled.
rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
random: get_random_bytes called from start_kernel+0x278/0x410 with crng_init=0
clocksource: orion_clocksource: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 11467562657 ns
sched_clock: 32 bits at 166MHz, resolution 6ns, wraps every 12884901885ns
Switching to timer-based delay loop, resolution 6ns
Console: colour dummy device 80x30
Calibrating delay loop (skipped), value calculated using timer frequency.. 333.33 BogoMIPS (lpj=1666666)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
CPU: Testing write buffer coherency: ok
Setting up static identity map for 0x81e0 - 0x8238
mvebu-soc-id: MVEBU SoC ID=0x6702, Rev=0x3
rcu: Hierarchical SRCU implementation.
devtmpfs: initialized
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash table entries: 256 (order: -1, 3072 bytes, linear)
pinctrl core: initialized pinctrl subsystem
thermal_sys: Registered thermal governor 'step_wise'
NET: Registered protocol family 16
DMA: preallocated 256 KiB pool for atomic coherent allocations
cpuidle: using governor menu
Feroceon L2: Enabling L2
Feroceon L2: Cache support initialised.
vgaarb: loaded
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
Advanced Linux Sound Architecture Driver Initialized.
clocksource: Switched to clocksource orion_clocksource
NET: Registered protocol family 2
tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 4096 bytes, linear)
TCP established hash table entries: 2048 (order: 1, 8192 bytes, linear)
TCP bind hash table entries: 2048 (order: 1, 8192 bytes, linear)
TCP: Hash tables configured (established 2048 bind 2048)
UDP hash table entries: 256 (order: 0, 4096 bytes, linear)
UDP-Lite hash table entries: 256 (order: 0, 4096 bytes, linear)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
PCI: CLS 0 bytes, default 32
Initialise system trusted keyrings
workingset: timestamp_bits=30 max_order=16 bucket_order=0
jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
Key type asymmetric registered
Asymmetric key parser 'x509' registered
io scheduler mq-deadline registered
io scheduler kyber registered
kirkwood-pinctrl f1010000.pin-controller: registered pinctrl driver
mvebu-gpio f1010140.gpio: IRQ index 3 not found
mv_xor f1060800.xor: Marvell shared XOR driver
mv_xor f1060800.xor: Marvell XOR (Registers Mode): ( xor cpy intr )
mv_xor f1060900.xor: Marvell shared XOR driver
mv_xor f1060900.xor: Marvell XOR (Registers Mode): ( xor cpy intr )
Serial: 8250/16550 driver, 2 ports, IRQ sharing disabled
printk: console [ttyS0] disabled
f1012000.serial: ttyS0 at MMIO 0xf1012000 (irq = 25, base_baud = 10416666) is a 16550A
printk: console [ttyS0] enabled
f1012100.serial: ttyS1 at MMIO 0xf1012100 (irq = 26, base_baud = 10416666) is a 16550A
loop: module loaded
sata_mv f1080000.sata: slots 32 ports 2
scsi host0: sata_mv
scsi host1: sata_mv
ata1: SATA max UDMA/133 irq 33
ata2: SATA max UDMA/133 irq 33
nand: device found, Manufacturer ID: 0xad, Chip ID: 0xf1
nand: Hynix H27U1G8F2BTR-BC
nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
Scanning device for bad blocks
7 fixed-partitions partitions found on MTD device orion_nand
Creating 7 MTD partitions on "orion_nand":
0x000000000000-0x000000100000 : "u-boot"
0x000000100000-0x000000600000 : "uImage"
0x000000600000-0x000000b00000 : "ramdisk"
0x000000b00000-0x000006f00000 : "image"
0x000006f00000-0x000007900000 : "mini firmware"
0x000007900000-0x000007e00000 : "config"
0x000007e00000-0x000008000000 : "my-dlink"
libphy: Fixed MDIO Bus: probed
libphy: orion_mdio_bus: probed
mv643xx_eth: MV-643xx 10/100/1000 ethernet driver version 1.4
mv643xx_eth_port mv643xx_eth_port.0 eth0: port 0 with MAC address 00:50:43:00:02:02
libertas_sdio: Libertas SDIO driver
libertas_sdio: Copyright Pierre Ossman
ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
ehci-pci: EHCI PCI platform driver
ehci-orion: EHCI orion driver
orion-ehci f1050000.ehci: EHCI Host Controller
orion-ehci f1050000.ehci: new USB bus registered, assigned bus number 1
orion-ehci f1050000.ehci: irq 30, io mem 0xf1050000
orion-ehci f1050000.ehci: USB 2.0 started, EHCI 1.00
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
usbcore: registered new interface driver usb-storage
usbcore: registered new interface driver ums-datafab
usbcore: registered new interface driver ums-freecom
usbcore: registered new interface driver ums-jumpshot
usbcore: registered new interface driver ums-sddr09
usbcore: registered new interface driver ums-sddr55
ata1: SATA link down (SStatus 0 SControl F300)
ata2: SATA link down (SStatus 0 SControl F300)
rtc-mv f1010300.rtc: internal RTC not ticking
i2c /dev entries driver
watchdog: f1020300.watchdog-timer: driver supplied timeout (4294967295) out of range
watchdog: f1020300.watchdog-timer: falling back to default timeout (25)
orion_wdt: Initial timeout 25 sec
marvell-cesa f1030000.crypto: CESA device successfully registered
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
oprofile: no performance counters
oprofile: using timer interrupt.
NET: Registered protocol family 17
lib80211: common routines for IEEE802.11 drivers
Loading compiled-in X.509 certificates
input: gpio-keys as /devices/platform/gpio-keys/input/input0
hctosys: unable to open rtc device (rtc0)
cfg80211: Loading compiled-in X.509 certificates for regulatory database
cfg80211: Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'
platform regulatory.0: Direct firmware load for regulatory.db failed with error -2
cfg80211: failed to load regulatory.db
ALSA device list:
  No soundcards found.
VFS: Cannot open root device "ram" or unknown-block(1,0): error -6
[...]

Additional kernel options can now be added depending on your needs. I have provided the config I was using here.

6. Building a rootfs

For the rootfs I wanted to use buildroot as I've found it's build system to be the easiest to understand. First we download buildroot-2020.02:

➜  ~ tar xvf buildroot-2020.02.tar.bz2
[...]
buildroot-2020.02/docs/manual/manual.html
buildroot-2020.02/.br2-external.in.openssl
buildroot-2020.02/.br2-external.in.toolchains
➜  ~

Then we need to copy in the packages for the DNS320L mcu communications daemon:

(default) ➜  buildroot-2020.02 cp -r buildroot-dns320l/package/* package
(default) ➜  buildroot-2020.02 patch -p1 < buildroot-dns320l/add-to-config.patch 
patching file package/Config.in
(default) ➜  buildroot-2020.02 

We can now build whatever options we want, the config I used can be downloaded here. The target architecture should be "ARM little-endian" and the target architecture variant is arm926t. After building buildroot

(default) ➜  buildroot-2020.02 make -j16
[...]
ln -snf /home/enki/Pobrane/buildroot-2020.02/output/host/arm-buildroot-linux-gnueabi/sysroot /home/enki/Pobrane/buildroot-2020.02/output/staging
(default) ➜  buildroot-2020.02 ls -l output/images/rootfs.cpio.uboot 
-rw-r--r-- 1 enki enki 20115884 kwi  5 19:08 output/images/rootfs.cpio.uboot

The initramfs image is inside the output/images/ directory and can be directly booted with the kernel built before.

7. Bootloader setup

For my own firmware I made the choice to not remove the original firmware from NAND just in case. I opted to boot my FW from an external USB stick plugged into the back USB port as I won't use it anyway. In order to configure the NAS for USB booting you need to perform the following steps:

First, interrupt the autoboot sequence by pressing SPACE and 1. After that perform the u-boot shell commands to save the existing boot configuration:

USB 0: host mode
PEX 0: interface detected no Link.
Net:   egiga0 [PRIME]
Hit any key to stop autoboot:  0 
Marvell>> 
Marvell>> setenv bootcmd_stock $(bootcmd)
Marvell>> printenv bootcmd_stock
bootcmd_stock=nand read.e 0xa00000 0x100000 0x300000;nand read.e 0xf00000 0x600000 0x300000;bootm 0xa00000 0xf00000

As you can see the original boot configuration has been saved to the 'bootcmdstock' variable and can be restored later if required. Now create a new variable with commands used to launch the kernel and initramfs from the USB stick and set 'bootcmd' to run them:

Marvell>> setenv bootcmd_usb usb start\;fatload usb 0 0xa00000 /slots/A/kernel\;fatload usb 0 0xf00000 /slots/A/initramfs\;bootm 0xa00000 0xf00000
Marvell>> printenv bootcmd_usb
bootcmd_usb=usb start;fatload usb 0 0xa00000 /slots/A/kernel;fatload usb 0 0xf00000 /slots/A/initramfs;bootm 0xa00000 0xf00000
Marvell>> 
Marvell>> setenv bootcmd run bootcmd_usb
Marvell>> printenv bootcmd
bootcmd=run bootcmd_usb
Marvell>> 

The last setenv command sets the boootcmd to run the contents of the bootcmdusb variable which contains commands to load the kernel and initramfs from the usb stick and execute the kernel entry point. Now if you would want to restore the NAS to boot the original firmware you just need to setenv bootcmd to contain the 'run bootcmdstock' string. The last step is to save the u-boot configuration:

Marvell>> saveenv
Saving Environment to NAND...
Erasing Nand...Writing to Nand... done
Marvell>> 

8. Benchmarks

Silicon Device Ciphersuite # jobs Read BW KB/s Write BW KB/s Util% CPU user CPU sys Notes
Marvell CESA sda plaintext 1 7495 7733   0.735452 5.410057  
Marvell CESA sda aes-cbc-plain 1 3675 3830   0.385759 1.805941  
Marvell CESA sda aes-xts-plain64 1 3789 3980   0.287679 1.985887  
CPU linear plaintext 1 7450 7703   0.744598 5.411187  
CPU linear aes-cbc-plain 1 3486 3621   0.385765 1.697039  
CPU linear aex-xts-plain64 1 3776 3954   0.294207 1.968481  
CPU sda plaintext 1 7350 7585   0.579864 5.382793  
CPU sda aes-cbc-plain 1 3671 3824   0.315302 1.860694  
CPU sda aes-xts-plain64 1 3780 3961   0.438496 1.826110  

8.1. I/O speed

Hard drives:

  <pre>
# smartctl -a /dev/sda
smartctl 7.3 2022-02-28 r5338 [armv5tel-linux-6.5.5] (local build)
Copyright (C) 2002-22, Bruce Allen, Christian Franke, www.smartmontools.org

=== START OF INFORMATION SECTION ===
Model Family:     Toshiba 2.5" HDD MQ01ABD...
Device Model:     TOSHIBA MQ01ABD050V
Serial Number:    X7NESTTBS
LU WWN Device Id: 5 000039 815c85c50
Firmware Version: AX0D1Q
User Capacity:    499,034,120,192 bytes [499 GB]
Sector Sizes:     512 bytes logical, 4096 bytes physical
Rotation Rate:    5400 rpm
Form Factor:      2.5 inches
Device is:        In smartctl database 7.3/5319
ATA Version is:   ATA8-ACS (minor revision not indicated)
SATA Version is:  SATA 2.6, 3.0 Gb/s (current: 3.0 Gb/s)
Local Time is:    Thu Jan  1 00:25:18 1970 UTC
SMART support is: Available - device has SMART capability.
SMART support is: Enabled
# smartctl -a /dev/sdb
smartctl 7.3 2022-02-28 r5338 [armv5tel-linux-6.5.5] (local build)
Copyright (C) 2002-22, Bruce Allen, Christian Franke, www.smartmontools.org

=== START OF INFORMATION SECTION ===
Device Model:     HITACHI HTS547550A9E384
Serial Number:    J2120052C1ST5B
LU WWN Device Id: 5 000cca 63dc0cda3
Firmware Version: JE3ZD60D
User Capacity:    500,107,862,016 bytes [500 GB]
Sector Sizes:     512 bytes logical, 4096 bytes physical
Rotation Rate:    5400 rpm
Form Factor:      2.5 inches
Device is:        Not in smartctl database 7.3/5319
ATA Version is:   ATA8-ACS T13/1699-D revision 6
SATA Version is:  SATA 2.6, 3.0 Gb/s (current: 3.0 Gb/s)
Local Time is:    Thu Jan  1 00:26:22 1970 UTC
SMART support is: Available - device has SMART capability.
SMART support is: Enabled
  </pre>

RAID configuration:

  <pre>
# cat /proc/mdstat
Personalities : [raid1]
md127 : active raid1 sda1[0] sdb1[1]
      487204864 blocks super 1.2 [2/2] [UU]
      bitmap: 0/4 pages [0KB], 65536KB chunk

unused devices: <none>
  </pre>

8.2. Direct I/O, no encryption

fio job file:

  <pre>
# cat directio.job 
[global]
bs=256K
iodepth=64
direct=1
ioengine=libaio
group_reporting
time_based
runtime=120
numjobs=1
rw=readwrite

[job1]
filename=/dev/md127
  </pre>

Results:

  <pre>
# fio directio.job
job1: (g=0): rw=rw, bs=(R) 256KiB-256KiB, (W) 256KiB-256KiB, (T) 256KiB-256KiB, ioengine=libaio, iodepth=64
fio-3.34
Starting 1 process
Jobs: 1 (f=1): [M(1)][100.0%][r=34.0MiB/s,w=30.5MiB/s][r=135,w=121 IOPS][eta 00m:00s]
job1: (groupid=0, jobs=1): err= 0: pid=250: Thu Jan  1 01:08:59 1970
  read: IOPS=163, BW=40.8MiB/s (42.8MB/s)(4908MiB/120237msec)
    slat (usec): min=517, max=49145, avg=1553.57, stdev=1950.45
    clat (usec): min=682, max=787092, avg=188469.05, stdev=87065.91
     lat (msec): min=7, max=787, avg=190.02, stdev=86.76
    clat percentiles (msec):
     |  1.00th=[   25],  5.00th=[   61], 10.00th=[   89], 20.00th=[  118],
     | 30.00th=[  142], 40.00th=[  165], 50.00th=[  184], 60.00th=[  201],
     | 70.00th=[  224], 80.00th=[  247], 90.00th=[  284], 95.00th=[  338],
     | 99.00th=[  472], 99.50th=[  550], 99.90th=[  701], 99.95th=[  726],
     | 99.99th=[  776]
   bw (  KiB/s): min=10199, max=81431, per=100.00%, avg=41797.59, stdev=11447.05, samples=239
   iops        : min=   39, max=  318, avg=162.93, stdev=44.75, samples=239
  write: IOPS=163, BW=40.9MiB/s (42.9MB/s)(4916MiB/120237msec); 0 zone resets
    slat (usec): min=546, max=331436, avg=1501.62, stdev=3122.70
    clat (msec): min=5, max=536, avg=198.85, stdev=87.85
     lat (msec): min=7, max=537, avg=200.35, stdev=87.55
    clat percentiles (msec):
     |  1.00th=[   34],  5.00th=[   66], 10.00th=[   92], 20.00th=[  124],
     | 30.00th=[  150], 40.00th=[  174], 50.00th=[  192], 60.00th=[  211],
     | 70.00th=[  234], 80.00th=[  262], 90.00th=[  326], 95.00th=[  368],
     | 99.00th=[  430], 99.50th=[  456], 99.90th=[  489], 99.95th=[  502],
     | 99.99th=[  535]
   bw (  KiB/s): min= 7619, max=78336, per=100.00%, avg=41909.28, stdev=12653.75, samples=239
   iops        : min=   29, max=  306, avg=163.36, stdev=49.50, samples=239
  lat (usec)   : 750=0.01%
  lat (msec)   : 4=0.01%, 10=0.06%, 20=0.31%, 50=2.98%, 100=9.46%
  lat (msec)   : 250=65.92%, 500=20.83%, 750=0.41%, 1000=0.02%
  cpu          : usr=2.38%, sys=23.41%, ctx=45281, majf=0, minf=29
  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, >=64=99.8%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.1%, >=64=0.0%
     issued rwts: total=19631,19665,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=64

Run status group 0 (all jobs):
   READ: bw=40.8MiB/s (42.8MB/s), 40.8MiB/s-40.8MiB/s (42.8MB/s-42.8MB/s), io=4908MiB (5146MB), run=120237-120237msec
  WRITE: bw=40.9MiB/s (42.9MB/s), 40.9MiB/s-40.9MiB/s (42.9MB/s-42.9MB/s), io=4916MiB (5155MB), run=120237-120237msec

Disk stats (read/write):
    md127: ios=19591/19647, merge=0/0, ticks=3263450/3625690, in_queue=6889140, util=99.57%, aggrios=6172/15260, aggrmerge=3643/4485, aggrticks=951136/1018075, aggrin_queue=1983680, aggrutil=98.87%
  sdb: ios=0/17080, merge=0/2665, ticks=0/923250, in_queue=928836, util=74.01%
  sda: ios=12344/13440, merge=7287/6305, ticks=1902272/1112901, in_queue=3038525, util=98.87%
  </pre>

8.3. Direct I/O, encrypted using dm-crypt with aes-cbc-plain

Cipher setup:

  <pre>
# cryptsetup luksDump /dev/md127
LUKS header information
Version:        2
Epoch:          3
Metadata area:  16384 [bytes]
Keyslots area:  16744448 [bytes]
UUID:           73f64ff8-b02c-4496-931f-dcb3ffbb5a9f
Label:          (no label)
Subsystem:      (no subsystem)
Flags:          (no flags)

Data segments:
  0: crypt
        offset: 16777216 [bytes]
        length: (whole device)
        cipher: aes-cbc-plain
        sector: 4096 [bytes]

Keyslots:
  0: luks2
        Key:        128 bits
        Priority:   normal
        Cipher:     aes-cbc-plain
        Cipher key: 128 bits
        PBKDF:      pbkdf2
        Hash:       sha256
        Iterations: 6701
        Salt:       f9 73 0c a0 2e 2f 44 76 3c 78 80 19 fc 58 db a3
                    62 47 53 5d 71 56 16 28 8d 95 cd 5c b9 71 6a 37
        AF stripes: 4000
        AF hash:    sha256
        Area offset:32768 [bytes]
        Area length:65536 [bytes]
        Digest ID:  0
Tokens:
Digests:
  0: pbkdf2
        Hash:       sha256
        Iterations: 8471
        Salt:       26 a6 31 88 41 7a 6e c6 0b bb 41 94 df fd fa 58
                    35 c7 aa 9c 02 0c 6d b3 84 dd ff 0e 1f b7 ea eb
        Digest:     40 9b 61 99 00 3c b3 af f1 d0 de 3b 3d 1d 50 cd
                    b8 f6 b8 99 f5 fa 94 27 96 f7 44 6b 8b 39 53 17
  </pre>

Cipher should be accelerated by Marvell CESA engine:

<pre>
name         : cbc(aes)
driver       : mv-cbc-aes
module       : kernel
priority     : 300
refcnt       : 1
selftest     : passed
internal     : no
type         : skcipher
async        : yes
blocksize    : 16
min keysize  : 16
max keysize  : 32
ivsize       : 16
chunksize    : 16
walksize     : 16
</pre>

Job file:

  <pre>
# cat directio.job
[global]
bs=256K
iodepth=64
direct=1
ioengine=libaio
group_reporting
time_based
runtime=120
numjobs=1
rw=readwrite

[job1]
filename=/dev/mapper/dcrypt
  </pre>

Results:

  <pre>
# fio directio.job
job1: (g=0): rw=rw, bs=(R) 256KiB-256KiB, (W) 256KiB-256KiB, (T) 256KiB-256KiB, ioengine=libaio, iodepth=64
fio-3.34
Starting 1 process
Jobs: 1 (f=1): [M(1)][0.2%][r=1021KiB/s,w=1532KiB/s][r=3,w=5 IOPS][eta 14h:40m:51s]
job1: (groupid=0, jobs=1): err= 0: pid=243: Thu Jan  1 01:03:04 1970
  read: IOPS=17, BW=4520KiB/s (4628kB/s)(537MiB/121664msec)
    slat (usec): min=528, max=4022, avg=1344.08, stdev=179.64
    clat (msec): min=210, max=3387, avg=1761.69, stdev=161.71
     lat (msec): min=211, max=3389, avg=1763.03, stdev=161.67
    clat percentiles (msec):
     |  1.00th=[ 1250],  5.00th=[ 1720], 10.00th=[ 1737], 20.00th=[ 1737],
     | 30.00th=[ 1754], 40.00th=[ 1754], 50.00th=[ 1770], 60.00th=[ 1770],
     | 70.00th=[ 1770], 80.00th=[ 1787], 90.00th=[ 1787], 95.00th=[ 1804],
     | 99.00th=[ 2165], 99.50th=[ 2836], 99.90th=[ 3306], 99.95th=[ 3339],
     | 99.99th=[ 3373]
   bw (  KiB/s): min= 2043, max= 7680, per=99.76%, avg=4509.92, stdev=1172.23, samples=240
   iops        : min=    7, max=   30, avg=17.22, stdev= 4.57, samples=240
  write: IOPS=18, BW=4760KiB/s (4874kB/s)(566MiB/121664msec); 0 zone resets
    slat (usec): min=560, max=5922, avg=616.20, stdev=245.15
    clat (msec): min=437, max=3357, avg=1765.04, stdev=157.04
     lat (msec): min=438, max=3357, avg=1765.66, stdev=156.95
    clat percentiles (msec):
     |  1.00th=[ 1183],  5.00th=[ 1737], 10.00th=[ 1737], 20.00th=[ 1754],
     | 30.00th=[ 1754], 40.00th=[ 1754], 50.00th=[ 1770], 60.00th=[ 1770],
     | 70.00th=[ 1787], 80.00th=[ 1787], 90.00th=[ 1787], 95.00th=[ 1804],
     | 99.00th=[ 2198], 99.50th=[ 2735], 99.90th=[ 3239], 99.95th=[ 3272],
     | 99.99th=[ 3373]
   bw (  KiB/s): min= 2043, max= 7168, per=99.90%, avg=4755.18, stdev=982.85, samples=240
   iops        : min=    7, max=   28, avg=18.18, stdev= 3.89, samples=240
  lat (msec)   : 250=0.05%, 500=0.32%, 750=0.20%, 1000=0.23%, 2000=98.05%
  lat (msec)   : >=2000=1.16%
  cpu          : usr=0.35%, sys=2.35%, ctx=6614, majf=0, minf=29
  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.2%, 16=0.4%, 32=0.7%, >=64=98.6%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.1%, >=64=0.0%
     issued rwts: total=2148,2262,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=64

Run status group 0 (all jobs):
   READ: bw=4520KiB/s (4628kB/s), 4520KiB/s-4520KiB/s (4628kB/s-4628kB/s), io=537MiB (563MB), run=121664-121664msec
  WRITE: bw=4760KiB/s (4874kB/s), 4760KiB/s-4760KiB/s (4874kB/s-4874kB/s), io=566MiB (593MB), run=121664-121664msec

Disk stats (read/write):
    dm-0: ios=2144/2259, merge=0/0, ticks=3753660/3961610, in_queue=7715270, util=99.93%, aggrios=2148/2262, aggrmerge=0/0, aggrticks=6800/6450, aggrin_queue=13250, aggrutil=38.04%
    md127: ios=2148/2262, merge=0/0, ticks=6800/6450, in_queue=13250, util=38.04%, aggrios=1072/2280, aggrmerge=2/0, aggrticks=4064/5653, aggrin_queue=10229, aggrutil=37.44%
  sdb: ios=0/2280, merge=0/0, ticks=0/6580, in_queue=7062, util=24.07%
  sda: ios=2144/2280, merge=4/0, ticks=8128/4726, in_queue=13397, util=37.44%
  </pre>

8.4. Direct I/O, encrypted using dm-crypt with aes-xts-plain64

Cipher setup:

  <pre>
# cryptsetup luksDump /dev/md127
LUKS header information
Version:       	2
Epoch:         	3
Metadata area: 	16384 [bytes]
Keyslots area: 	16744448 [bytes]
UUID:          	9a516a3a-abcb-4958-9b42-7c00becdd349
Label:         	(no label)
Subsystem:     	(no subsystem)
Flags:       	(no flags)

Data segments:
  0: crypt
  offset: 16777216 [bytes]
  length: (whole device)
  cipher: aes-xts-plain64
  sector: 4096 [bytes]

Keyslots:
  0: luks2
  Key:        512 bits
  Priority:   normal
  Cipher:     aes-xts-plain64
  Cipher key: 512 bits
  PBKDF:      pbkdf2
  Hash:       sha256
  Iterations: 3299
  Salt:       84 43 2c 52 48 72 f0 e5 4b b4 78 f6 59 2b 1d fb
              91 e4 48 de 8c 89 8c 53 d8 2d 08 65 2c 6b 0c b2
  AF stripes: 4000
  AF hash:    sha256
  Area offset:32768 [bytes]
  Area length:258048 [bytes]
  Digest ID:  0
Tokens:
Digests:
  0: pbkdf2
  Hash:       sha256
  Iterations: 4116
  Salt:       0a 29 d2 d8 c2 15 d1 31 94 ed 55 ac ad c2 65 41
              32 7f 51 f0 02 d8 f1 91 f7 f5 62 4c a3 7b 70 4e
  Digest:     c5 71 38 6f 6b 6f ba f2 5e b5 9d 3f 53 75 3f 01
              ef b5 f5 4b 49 f9 4e f1 68 5a 83 a6 f7 a1 5f 76
  </pre>

Job file:

  <pre>
[global]
bs=256K
iodepth=64
direct=1
ioengine=libaio
group_reporting
time_based
runtime=120
numjobs=1
rw=readwrite

[job1]
filename=/dev/mapper/dcrypt

  </pre>

Results:

    <pre>
# fio directio.job
job1: (g=0): rw=rw, bs=(R) 256KiB-256KiB, (W) 256KiB-256KiB, (T) 256KiB-256KiB, ioengine=libaio, iodepth=64
fio-3.34
Starting 1 process
Jobs: 1 (f=1): [M(1)][0.2%][eta 17h:56m:08s]
job1: (groupid=0, jobs=1): err= 0: pid=219: Thu Jan  1 00:50:28 1970
  read: IOPS=14, BW=3752KiB/s (3842kB/s)(447MiB/122054msec)
    slat (usec): min=535, max=3178, avg=1333.50, stdev=132.79
    clat (msec): min=301, max=4105, avg=2135.65, stdev=204.95
     lat (msec): min=303, max=4106, avg=2136.98, stdev=204.93
    clat percentiles (msec):
     |  1.00th=[ 1284],  5.00th=[ 2123], 10.00th=[ 2123], 20.00th=[ 2123],
     | 30.00th=[ 2123], 40.00th=[ 2140], 50.00th=[ 2140], 60.00th=[ 2140],
     | 70.00th=[ 2140], 80.00th=[ 2140], 90.00th=[ 2165], 95.00th=[ 2165],
     | 99.00th=[ 2836], 99.50th=[ 3473], 99.90th=[ 4044], 99.95th=[ 4111],
     | 99.99th=[ 4111]
   bw (  KiB/s): min= 1024, max= 7168, per=99.78%, avg=3744.96, stdev=1040.30, samples=240
   iops        : min=    4, max=   28, avg=14.26, stdev= 4.08, samples=240
  write: IOPS=15, BW=3908KiB/s (4001kB/s)(466MiB/122054msec); 0 zone resets
    slat (usec): min=558, max=6949, avg=627.68, stdev=372.27
    clat (msec): min=438, max=4137, avg=2136.88, stdev=220.34
     lat (msec): min=438, max=4138, avg=2137.51, stdev=220.20
    clat percentiles (msec):
     |  1.00th=[ 1200],  5.00th=[ 2123], 10.00th=[ 2123], 20.00th=[ 2123],
     | 30.00th=[ 2140], 40.00th=[ 2140], 50.00th=[ 2140], 60.00th=[ 2140],
     | 70.00th=[ 2140], 80.00th=[ 2165], 90.00th=[ 2165], 95.00th=[ 2165],
     | 99.00th=[ 2970], 99.50th=[ 3574], 99.90th=[ 4077], 99.95th=[ 4144],
     | 99.99th=[ 4144]
   bw (  KiB/s): min= 1024, max= 6144, per=99.91%, avg=3904.90, stdev=967.18, samples=240
   iops        : min=    4, max=   24, avg=14.88, stdev= 3.83, samples=240
  lat (msec)   : 500=0.33%, 750=0.25%, 1000=0.22%, 2000=1.01%, >=2000=98.19%
  cpu          : usr=0.32%, sys=1.90%, ctx=5499, majf=0, minf=26
  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.2%, 16=0.4%, 32=0.9%, >=64=98.3%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.1%, >=64=0.0%
     issued rwts: total=1789,1863,0,0 short=0,0,0,0 dropped=0,0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=64

Run status group 0 (all jobs):
   READ: bw=3752KiB/s (3842kB/s), 3752KiB/s-3752KiB/s (3842kB/s-3842kB/s), io=447MiB (469MB), run=122054-122054msec
  WRITE: bw=3908KiB/s (4001kB/s), 3908KiB/s-3908KiB/s (4001kB/s-4001kB/s), io=466MiB (488MB), run=122054-122054msec

Disk stats (read/write):
    dm-0: ios=1788/1861, merge=0/0, ticks=3790690/3943590, in_queue=7734280, util=99.92%, aggrios=1789/1863, aggrmerge=0/0, aggrticks=5710/5270, aggrin_queue=10980, aggrutil=31.40%
    md127: ios=1789/1863, merge=0/0, ticks=5710/5270, in_queue=10980, util=31.40%, aggrios=892/1886, aggrmerge=2/0, aggrticks=3369/4966, aggrin_queue=9076, aggrutil=31.00%
  sdb: ios=0/1886, merge=0/0, ticks=0/5860, in_queue=6559, util=20.10%
  sda: ios=1785/1886, merge=4/0, ticks=6739/4073, in_queue=11594, util=31.00%
    </pre>

8.5. Direct I/O, encrypted using dm-crypt with

9. References

Author: Maciej Grela <enki@fsck.pl>

Fediring