Table of Contents

Hacking the LaCie d2 Network

LaCie d2 Network After power-up the LaCie will get an IP address from a DHCP server, if available.

A simple nmap run will show:

nmap 192.168.2.131
Starting Nmap 4.62 ( http://nmap.org ) at 2009-12-25 10:46 CET
Interesting ports on 192.168.2.131:
Not shown: 1709 closed ports
PORT    STATE SERVICE
21/tcp  open  ftp
80/tcp  open  http
139/tcp open  netbios-ssn
443/tcp open  https
445/tcp open  microsoft-ds
548/tcp open  afp
MAC Address: 00:D0:4B:88:62:FE (LA CIE Group S.A.)
Nmap done: 1 IP address (1 host up) scanned in 0.319 seconds

We can point the browser to the ip address and make a login with the default admin username/password: admin/admin. The web interface is available via https too. The web interface is available in english, français, deutsch, italiano, español, dutch, svenska, dansk and japanese.

Main features of this device are:

With default configuration I tested the transfer rate and disk speed writing 30 mp3 songs - about 100 Mb of data - from the local hard disk to the smb share. It took about 15 seconds, this is about 6.64 Mb/s on a 100 Mbit network.

From the web interface you can control a BitTorrent client: just upload a .torrent file from the local hard disk and choose the destination folder. Several download can run simultaneously.

The LaCie supports Ethernet jumbo frame sizes of 1500, 4000 and 9000 bytes, not a very interesting feature in my opinion.

The front panel

On the front panel there is one large button with led. Pressing the button will power up the device, if it is powered down and it is in the auto mode (see below). During normal operation the button press will start the copy of USB external storage contents to the internal disk. The light is steading blue when the device is ready, blinking blue when busy booting or shutting down. It becomes red when performing USB content backup.

The back panel

On the back panel there is a three position power switch. In the on position the device is powered-up and cannot be switched off via software. In the auto position the device can be controlled by the front button and via software. In the off position the device is off, as you can guess.

LaCie software

I tried to install LaCie Network Assistant 1.1, which is distributed as a MS-Windows installer or as a GNU/Linux autopackage archive. The autopackage version requires the avahi-daemon and it will install into $HOME/.local/ and $HOME/.packages/. I was unable to run the Windows version of the program both under Wine and under Qemu.

LaCie Network Assistant allows to wake-up a device, discover LaCie devices on the local network, configure IP address and automatically mount shares via smb protocol. It is not a very impressive software, sometimes it crashes too. You can live without it.

Hacking it

I found two recipes to break into the LaCie operating system: Jailbreaking LaCie (in English) and LaCie telnet hack (in Italian, with telnetd package to download). Both hacks do not require skrewdrivers.

This is my revised procedure:

  1. Create a new share called root and make it writable.
  2. Save the configuration: System, Maintenance, Save configuration. A file named edconf.xml will be saved on your hard disk.
  3. Make a copy of the configuration file, open it with an editor, search the share section and change the
    <path>root</path> with:
    <path>root/../../../</path>
    i.e. the same directory followed by 3 levels up.
  4. Load the configuration back to the device: System, Maintenance, Load configuration.
  5. Browse the root share to get access to the root filesystem.

Notice 1: when this hack is active, do not change the configuration of shares: you risk to erase their contents. Once you hacked the root filesystem as you wish (see below), reload the original configuration.

Notice 2: this hack is temporary. If you reboot, the root share will be broken and you will find a recovered_root_YYYYMMDD_hhmmss share. Do not change them from the web interface, just upload the original configuration file. This is due a bug in the LaCie code, which does not properly sanitize the modified configuration file and save a corrupted version of it.

The web interface runs with root privileges, so it is possible to modify system files by browsing the share contents and using the upload function.

  1. Unpack this archive, upload utelnetd and telnet.cgi into /www/cgi-bin/public/ directory of the LaCie.
  2. Point the browser to http://192.168.2.133/cgi-bin/public/telnet.cgi: the telnet daemon will start.
  3. Telnet into the LaCie, you will get a root shell.
  4. Reload the original configuration from System, Maintenance, Load configuration.

Starting the ssh service

LaCie operating system does not use the traditional sysvinit to start the services on boot, it uses the initng replacement. The main tool for initng is ngc, used to start/stop the services, query the status of a service, etc.

Here it is the help screen of ngc:

[root@LaCie-d2 ~]# ngc -h
 initNGControl (0.6.10.2 ) by Jimmy Wennlund http://www.initng.org/
 ngc understand this commands:
 short Option                          : description
 ----------------------------------------------------------
 [-h] --help                           : Print what commands you can send to initng.
 [-H] --help_all                       : Print out verbose list of all commands.
 [-s] --status <opt>                   : Print all services.
 [-u] --start opt                      : Start service.
 [-d] --stop opt                       : Stop service.
 [-t] --states <opt>                   : Print out all possible states.
 [-c] --hot_reload                     : Fast Reload
 [-z] --zap <opt>                      : Resets a failed service, so it can be restarted.
 [-r] --restart opt                    : Restart service
 [-R] --reload_service <opt>           : Reload service data from disk ( reparse /etc/initng )
 [-6] --reboot                         : Reboot the computer
 [-0] --poweroff                       : Power off the computer
 [-1] --halt                           : Halt the computer
 [-y] --stop_unneeded                  : Stop all services, not in runlevel

If you have some problem running initng commans, try to send a SIGHUP signal to initng:

ngc --start sshd
Error connecting to initng socket
kill -HUP 1

The ssh daemon is already installed in the LaCie d2 Network, but it does not start automatically. To start sshd - the very first time be prepared to wait some minutes for host keys generation - run:

ngc --start sshd

Once started, you can add sshd to the list of services to start automatically, and initialize the lastlog:

echo sshd >> /etc/initng/runlevel/default.runlevel
touch /var/log/lastlog

Files /etc/passwd and /etc/shadow will be “sanitized” on each reboot, so it is useless to change the root password or change the users login shell (default to /bin/false). To allow ssh root access, just create a /root/.ssh/authorized_keys file and put in it your ssh public key (see ssh-keygen(1) man page).

Looking around at the shell prompt

root@LaCie-d2:~# uname -a
Linux LaCie-d2 2.6.22.7 #1 Mon Mar 23 17:03:07 CET 2009 armv5tejl unknown

Here the kernel config, obtained with zcat /proc/config.gz

root@LaCie-d2:~# free
              total         used         free       shared      buffers
  Mem:       126928        71204        55724            0         6564
 Swap:       128448            0       128448
Total:       255376        71204       184172
root@LaCie-d2:~# cat /proc/cpuinfo
Processor       : ARM926EJ-S rev 0 (v5l)
BogoMIPS        : 266.24
Features        : swp half thumb fastmult edsp
CPU implementer : 0x41
CPU architecture: 5TEJ
CPU variant     : 0x0
CPU part        : 0x926
CPU revision    : 0
Cache type      : write-back
Cache clean     : cp15 c7 ops
Cache lockdown  : format C
Cache format    : Harvard
I size          : 32768
I assoc         : 1
I line length   : 32
I sets          : 1024
D size          : 32768
D assoc         : 1
D line length   : 32
D sets          : 1024

Hardware        : Feroceon
Revision        : 0000
Serial          : 0000000000000000
root@LaCie-d2:~# df -h
Filesystem                Size      Used Available Use% Mounted on
rootfs                  648.5M     20.0M    595.5M   3% /
udev                    648.5M     20.0M    595.5M   3% /dev
df: /dev/pts: No such file or directory
/dev/sda7                 7.5M      5.9M      1.2M  83% /oldroot
udev                     10.0M         0     10.0M   0% /oldroot/dev
udev                     10.0M         0     10.0M   0% /oldroot/dev
none                     62.0M         0     62.0M   0% /oldroot/dev/shm
/dev/sda8               167.0M    111.3M     47.1M  70% /oldroot/var/original
/dev/sda9               648.5M     20.0M    595.5M   3% /oldroot/snapshots
unionfs                 648.5M     20.0M    595.5M   3% /
/dev/sda9               648.5M     20.0M    595.5M   3% /var
/dev/sda9               648.5M     20.0M    595.5M   3% /tmp
/dev/sda2               930.4G    907.9M    929.5G   0% /home
root@LaCie-d2:~# fdisk -l

Disk /dev/sda: 1000.2 GB, 1000204886016 bytes
255 heads, 63 sectors/track, 121601 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks  Id System
/dev/sda1               1         125     1004031   5 Extended
/dev/sda2             126      121601   975755970  83 Linux
/dev/sda5               1          16      128457  82 Linux swap
/dev/sda6              17          17        8001  83 Linux
/dev/sda7              18          18        8001  83 Linux
/dev/sda8              19          40      176683+ 83 Linux
/dev/sda9              41         124      674698+ 83 Linux
/dev/sda10            125         125        8001  83 Linux
[root@LaCie-d2 ~]# mount
rootfs on / type rootfs (rw)
none on /proc type proc (rw)
none on /sys type sysfs (rw)
udev on /dev type tmpfs (rw)
devpts on /dev/pts type devpts (rw)
/dev/sda7 on /oldroot type ext3 (ro,data=ordered)
udev on /oldroot/dev type tmpfs (rw)
none on /oldroot/proc type proc (rw)
none on /oldroot/sys type sysfs (rw)
udev on /oldroot/dev type tmpfs (rw)
devpts on /oldroot/dev/pts type devpts (rw)
none on /oldroot/dev/shm type tmpfs (rw)
/dev/sda8 on /oldroot/var/original type ext3 (ro,data=ordered)
/dev/sda9 on /oldroot/snapshots type ext3 (rw,data=ordered)
unionfs on / type unionfs (rw,dirs=/oldroot/snapshots/snaps/00=rw:/oldroot/var/original=ro)
proc on /proc type proc (rw)
sys on /sys type sysfs (rw)
/dev/sda9 on /var type ext3 (rw,data=ordered)
/dev/sda9 on /tmp type ext3 (rw,data=ordered)
usbfs on /proc/bus/usb type usbfs (rw)
/dev/sda2 on /home type xfs (rw)
[root@LaCie-d2 ~]# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00080000 00010000 "cfi_flash_0"
dmesg
Linux version 2.6.22.7 (root@grp-dash) (gcc version 4.2.1) #1 Mon Mar 23 17:03:07 CET 2009
CPU: ARM926EJ-S [41069260] revision 0 (ARMv5TEJ), cr=a0053177
Machine: Feroceon
Using UBoot passing parameters structure
...
Kernel command line: console=ttyS0,115200 root=/dev/sda7 ro boardType=mv88F5182 productType=d2Next 
...
Memory: 128MB 0MB 0MB 0MB = 128MB total
Memory: 126464KB available (2792K code, 185K data, 356K init)
Calibrating delay loop... 266.24 BogoMIPS (lpj=1331200)
...
Sys Clk = 200000000, Tclk = 166666667
...
Init Marvell USB port 0 => HOST
Marvell USB EHCI Host controller #0: c0493600
Init Marvell USB port 1 => HOST
Marvell USB EHCI Host controller #1: c0493400
...
Time: orion_clocksource clocksource has been installed.
...
Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing disabled
serial8250.0: ttyS0 at MMIO 0xf1012000 (irq = 3) is a 16550A
serial8250.0: ttyS1 at MMIO 0xf1012100 (irq = 4) is a 16550A
Marvell Ethernet Driver 'mv_ethernet':
...
Intergrated Sata device found
scsi0 : Marvell SCSI to SATA adapter
scsi1 : Marvell SCSI to SATA adapter
scsi 1:0:0:0: Direct-Access     Hitachi  HDT721010SLA360  ST6O PQ: 0 ANSI: 5
sd 1:0:0:0: [sda] 1953525168 512-byte hardware sectors (1000205 MB)
...
egiga0: link down
egiga0: link up, full duplex, speed 100 Mbps

Here the full dmesg output.

The pseudo file /proc/edmini is provided by a LaCie kernel driver (released under the GPL license). It reports some useful info and can be used to write some configuration to the device, see below.

[root@LaCie-d2 ~]# cat /proc/edmini
d2Net status:
------------

Restore: NO

Sw Power button:
  Status: Auto
  Count: 0/0

ACTION:
  name                  count   blink   callback
  Shutdown              0       0/0     Internal call
  Button action         1       0/0     /sbin/snapshot

The S.M.A.R.T. function works, just add the --device=marvell option (otherwise you get the error Device does not support SMART):

[root@LaCie-d2 ~]# smartctl --device=marvell -a /dev/sda

The filesystems

Device Start End Blocks Id System Note
/dev/sda1 1 125 1004031 5 Extended Contains sda5 … sda10.
/dev/sda2 126 121601 975755970 83 Linux Mounted as /home, formatted as xfs filesystem.
/dev/sda5 1 16 128457 82 Linux-swap Used as swap partition.
/dev/sda6 17 17 8001 83 Linux U-Boot image with kernel, etc.
/dev/sda7 18 18 8001 83 Linux Initial root filesystem used by the kernel. Contains the scripts to assemble a running root filesystem via unionfs. Available at runtime under /oldroot.
/dev/sda8 19 40 176683 83 Linux Runtime root filesystem, read-only part in unionfs. Also available at runtime under /oldroot/var/original.
/dev/sda9 41 124 674698 83 Linux Runtime root filesystem, read/write part in unionfs. Also available at runtime under /oldroot/snapshots. The system can save several snapshots, unionfs uses the last one available, which is /oldroot/snapshots/snaps/00/ in a clean device.
/dev/sda10 125 125 8001 83 Linux Empty partition. If it contains an U-Boot image, it will used instead of /dev/sda6. Probably used to boot from disk2 if disk1 fails, on Lacie RAID models.

As you can see, the root filesystem at runtime is an unionfs.

The original configuration is stored read-only in /dev/sda8 which is mounted in /oldroot/var/original. Here you can always find the original version of each configuration and system file. Changes to the root filesystem are stored in /dev/sda9, into a snapshot, the read/write part in unionfs. So the current version of each system file is available into /oldroot/snapshots/snaps/00/ (assuming that 00 is the latest snapshot available).

If you want to learn how the bootstrap works on the LaCie, look at the script /oldroot/sbin/init and the functions countained into /oldroot/lib/lacie/libunionfs. The unionfs is assembled in this way:

mount -n -t unionfs -o dirs=/var/original=rw unionfs /var/base
mount    -t unionfs -o remount,add=/snapshots/snaps/00 none /var/base

Some shell variables used by the script:

$root_partition /dev/sda8
$root_mountpoint /var/original
$snap_partition /dev/sda9
$snap_mountpoint /snapshots
$union_base /var/base
$oldroot oldroot

Wake-On-Lan

The Wake-On-Lan function works when the device is turned off but the power switch is on the auto position: sending a Magic packet will power-up the LaCie. The etherwake(8) program does not work, while wakeonlan(1) does. May be the difference is that etherwake uses raw Ethernet packet, while wakeonlan encapsulate the Magic packet into an UDP packet.

Connect the Ethernet cable before the power cable, otherwise the Wake-On-Lan will not work.

Dual boot with Debian

We can install a full-featured Debian distribution on this LaCie NAS, the processor requires a Debian armel architecture, do not use the old one arm. The armel is very much faster in floating point operations, with or without an FPU.

Our goal is to install a full Debian system and use it in dual boot with the original system.

Make a new partition

First of all we need a new partition /dev/sda3 to host Debian. Unfortunately the data partition /dev/sda2 (mounted in /home) is XFS formatted and cannot be shrunk, so we need to backup the data, delete it and create it smaller. In my case making it 122 cylinders smaller, leaves room for a new partition of about 1 Gb.

From the ssh prompt:

# Backup user data, you can use tar over ssh:
tar cf - /home | ssh user@other_host 'cat > lacie_home.tar'

umount /home
fdisk /dev/sda

# (d)elete partition sda(2)
# create a (n)ew (p)rimary partition sda(2)
# create a (n)ew (p)rimary partition sda(3)
# (w)rite the parition table and (q)uit fdisk

# Notice the warning:
# fdisk: WARNING: rereading partition table failed, kernel still uses old table
reboot

# Once rebooted:
mkfs.xfs -f /dev/sda2
mkfs.ext3 /dev/sda3
reboot

First stage of debootstrap on a Linux box

We use debootstrap(8) on a standard Linux box. We need to specify the target architecture armel, which is different from the hosting one (i386 or whatever). We ask to perform the unpack phase of bootstrapping only, the rest will be executed on the LaCie. debootstrap requires root privileges:

mkdir debian-armel
debootstrap --arch=armel --foreign lenny debian-armel
tar debian-armel.tgz debian-armel

Second stage of debootstrap on the LaCie

Copy the tar archive to the LaCie and extract the /debian-armel directory. We can switch to this Debian environment using chroot(8) and execute the rest of debootstrap:

cd /
mkdir /debian-armel
mount /dev/sda3 /debian-armel
tar zxf /home/share/share/debian-armel.tgz
mount /proc /debian-armel/proc
mount /sys /debian-armel/sys
mount /oldroot/dev/ /debian-armel/dev
chroot /debian-armel
/debootstrap/debootstrap --second-stage

Complete the Debian installation

Still in the chroot environment, we can proceed with the rest of Debian setup.

To exit from the chroot environment, stop all the services you have started and execute exit. Then umount /proc, /sys and /dev underneath the chroot before umounting /debian-armel itself.

Controlling the dual boot

We will use the original kernel and the original root filesystem to bootstrap. The original bootstrap sequence is like this:

  1. Load the kernel from /dev/sda6.
  2. Mount the root filesystem from /dev/sda7.
  3. Assemble a new root filesystem from /dev/sda8 and /dev/sda9, using unionfs.
  4. Switch to the new rootfs using pivot_root(8).
  5. Execute init from the unionfs.

We will change the init sequence in /dev/sda7, so that if a specified file exists (used as a flag), pivot_root will proceed with /dev/sda3 instead of unionfs. Do not forget to copy kernel modules into the new partition.

Via ssh execute the following into the LaCie environment (not into the Debian chroot):

cp -pr /lib/modules/2.6.22.7 /debian-armel/lib/modules/
mount -o remount,rw /dev/sda7
vi /oldroot/sbin/init
# Add a 4.1 section, as below...
mount -o remount,ro /dev/sda7
echo "/dev/sda3" > /rootfs

On /dev/sda7 partition, init is just a shell script. This is the part that we added (put it after section 4, at line 160 in our case):

    #===========================================================================
    # 4.1. Boot with an alternative RootFS.
    #===========================================================================
    if [ -f $union_base/rootfs ]; then
        rootfs=`cat $union_base/rootfs`
        rootfs_base=/var/rootfs
        debug_msg "Found file $union_base/rootfs, using (once) $rootfs as RootFS"
        rm $union_base/rootfs
        sync
        if [ -b $rootfs ]; then
            debug_msg "Preparing RootFS: $rootfs_base and $rootfs_base/dev"
            [ -d $rootfs_base ] || mkdir $rootfs_base
            mount -n $rootfs $rootfs_base
            mount -n -o size=10M,mode=0755 -t tmpfs udev $rootfs_base/dev
            mknod $rootfs_base/dev/console c 5  1
            mknod $rootfs_base/dev/ttyS0   c 4 64
            mknod $rootfs_base/dev/sda     b 8  0
            for n in 1 2 3 4 5 6 7 8 9 10 ; do
                mknod $rootfs_base/dev/sda$n b 8 $n
            done
            cd $rootfs_base
            mkdir -p $oldroot
            mount -n -o remount,ro $rootfs $rootfs_base
            debug_msg "Executing pivot_root and exec init from the new RootFS"
            pivot_root . $oldroot
            umount /oldroot/proc
            umount /oldroot/sys
            umount /oldroot/dev/shm
            umount /oldroot/dev/pts
            exec /sbin/init < /dev/console > /dev/console 2>&1
        fi
    fi

At the next reboot, the system will boot into our new Debian system. For an added safety this will be done only once: the flag file is removed just before switching rootfs. If something goes wrong we can power-cycle and restart with the original LaCie system.

If Debian bootstrap nicely, we can create the flag file again adding this in /etc/rc.local:

echo "/dev/sda3" > /oldroot/var/base/rootfs

Debian settings

You can find my Debian customization in this archive: debian_on_lacie_d2_network.tgz. Most important files contained herein:

Bugs and TODO

Once booted in Debian, some things does not work as expected.

Power management

When the power switch is in the auto position, it is necessary to set in advance the required action (halt or reboot) executed by the shutdown(8) command, traditional flags -P and -r are ignored. This is accomplished by writing a string to /proc/edmini:

String Action with power switch in the auto position
POWER:HALT Do an halt after shutdown.
POWER:REBOOT Do a reboot after shutdown.

Actually a flag is written into the Lacie d2 Network EEPROM. The shutdown command always does a reboot and the U-Boot will do the proper action upon the power switch position and the EEPROM flag.

LED, button and switch

The LaCie has a big button on the front which includes a blue/red LED. On the back it has a rocker switch with three positions: on, auto and off.

With LaCie kernel

The big LED on the front panel is normally steady blue. It is possible to change its status writing some values to the /proc/edmini pseudo file. To change the LED status run a command like this:

echo "LED:MAIN:HBT:BLUE_RED" > /proc/edmini

Here there are some values (extracted from the /sbin/event-led-manager script):

Value LED light
SYSTEM_READY Restore default state
LED:MAIN:CTL:OFF Off
LED:MAIN:CTL:ON Steady blue
LED:MAIN:HBT:BLUE Blinking blue
LED:MAIN:HBT:BLUE_RED Blinking blue/red
LED:MAIN:HBT:RED Blinking red
LED:MAIN:SWT:RED:OFF Turn off the red light
LED:MAIN:SWT:RED:ON Steady red

To associate an action to the button press (it is the snapshot function on the original system), just execute:

echo "ACTION:ADD:snapshot:/usr/bin/command:1:300/0" > /proc/edmini

The string is composed of ACTION:ADD:Name:Path:Count:Led_ON_Time/Led_OFF_time.

To remove the association:

echo "ACTION:DEL:1" > /proc/edmini

With Linux 2.6.32 kernel

Vanilla 2.6.32 kernel supports the dual color blue/red LED, but does not activate the blue LED blinking on SATA access. It lacks also the ability to program the GPIO #24, required to ignore the power-off switch. So it is impossible to control the shutdown via software.

Default actions associated to the switches are:

Front Push Button None
Power rocker switch (on|auto) None
Power rocker switch (auto|off) Power-off immediately (not clean)

The rocker switch, when switched to off, will power off the device, this is different from the behaviour with the LaCie kernel, where a soft reboot is started.

The path for controlling the LEDs are: /sys/class/leds/d2net:blue:power and /sys/class/leds/d2net:red:fail.

With Linux 2.6.32 patched

Thanks to Simon Guinot, there is a patch for kernel 2.6.32, which enables GPIO #24 programming and blue LED blinking on disk access. Notice that BLUE led path is canged.

# Blue led blinking.
echo "timer" > "/sys/class/leds/d2net:blue:sata/trigger"
echo "50"    > "/sys/class/leds/d2net:blue:sata/delay_off"
echo "50"    > "/sys/class/leds/d2net:blue:sata/delay_on"
 
# Blue led steady on (blinking on SATA access):
echo "default-on" > "/sys/class/leds/d2net:blue:sata/trigger"
 
# Blue led steady off:
echo "none" > "/sys/class/leds/d2net:blue:sata/trigger"
 
# Red led blinking.
echo "timer" > "/sys/class/leds/d2net:red:fail/trigger"
echo "50"    > "/sys/class/leds/d2net:red:fail/delay_on"
echo "50"    > "/sys/class/leds/d2net:red:fail/delay_off"

Front push button and rear rocker switch are connected to an irq:

cat /proc/interrupts
           CPU0
 40:         57  orion_gpio_irq  Power rocker switch (on|auto)
 41:          0  orion_gpio_irq  Power rocker switch (auto|off)
 50:          4  orion_gpio_irq  Front Push Button

It is possible to control the power-off behaviour using GPIO #24, setting this pin to 1 will activate the ignore power-off status, thus enabling the software to catch the event and initiate a clean shutdown.

Here are the commands required to activate GPIO programming and setting the value to 1:

echo 24 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio24/direction
echo 1 > /sys/class/gpio/gpio24/value
echo 24 > /sys/class/gpio/unexport

The kernel module evdev and gpio_keys (CONFIG_INPUT_EVDEV and CONFIG_KEYBOARD_GPIO) provide the device /dev/input/event0. With the input-events(8) command (provided by the input-utils package) it is possible to monitor the button events:

lacie:~# input-events -t 120 0
/dev/input/event0
   bustype : BUS_HOST
   vendor  : 0x1
   product : 0x1
   version : 256
   name    : "gpio-keys"
   phys    : "gpio-keys/input0"
   bits ev : EV_SYN EV_KEY EV_SW

waiting for events
#
# Front button pressed:
00:11:11.723379: EV_KEY KEY_POWER pressed
00:11:11.723394: EV_SYN code=0 value=0
#
# Front button released:
00:11:11.816207: EV_KEY KEY_POWER released
00:11:11.816219: EV_SYN code=0 value=0
#
# Rocker switch from AUTO to ON position:
00:11:38.619606: EV_SW code=1 value=1
00:11:38.619634: EV_SYN code=0 value=0
#
# Rocker switch from ON to AUTO position:
00:11:40.321607: EV_SW code=1 value=0
00:11:40.321618: EV_SYN code=0 value=0
#
# Rocker switch from AUTO to OFF position:
16:08:04.410119: EV_SW code=2 value=1
16:08:04.410134: EV_SYN code=0 value=0
#
# Rocker switch from OFF to AUTO position:
16:08:06.845804: EV_SW code=2 value=0
16:08:06.845816: EV_SYN code=0 value=0

FIXME How to react to input events? See Power Buttons Under HAL and this mail suggesting some code.

LaCie U-Boot looks at an EEPROM flag to decide if it will stop the bootstrap waiting for a Wake-On-Lan packet or if it will proceed. So we need to set this flag before doing an halt or a reboot to obtain the correct behaviour.

Furtunately the Linux kernel exposes the EEPROM content for reading and writing. To obtain an halt, write a 0 at offset 6, to obtain a reboot write 1 at the same offset:

eeprom_write_byte /sys/bus/i2c/devices/0-0050/eeprom 6 0

Here it is the binary and the source code of eeprom_write_byte.

The EEPROM

With a proper kernel (2.6.32 with the above patch, or 2.6.37) the EEPROM content is exposed for read and write via the pseudo file /sys/bus/i2c/devices/0-0050/eeprom. This is what I know about its content:

Offset Length Content
0 6 Ethernet MAC address.
6 1 Power flag.
If set to LACIE_POWER_OFF (0), U-Boot will stop the boot process and wait for Wake-on-LAN.
If set to LACIE_POWER_ON (1), U-Boot will reboot.

Disassembling the LaCie d2 Network

Removing the four screws from the back, you can remove the front and the back panels. Removing other two screws from the bottom, the hard disk with the attached PCB will slide out from the aluminium body.

The back panel PCB top PCB bottom

U-Boot NetConsole

It is possible to have a boot prompt without using the serial port (see below). The boot loader U-Boot waits some time before booting, for a special Lacie UDP magic packet (see the message Waiting for LUMP on the serial console), if it receives it from an host, it will enter a special remote console, communicating on port 6666 UDP.

You need the NetConsole client called clunc. I downloaded the Clunc source code from the Git repository and compiled it just with make. You need also the nc command from the netcat-traditional package.

Start the clunc program on your Linux box and power on the Lacie (WARNING: it seems that clunc broadcasts to U-Boot only to the interface where you have the default route, beware if you have more than one Ethernet interface):

./clunc -v -i 192.168.2.35
waiting U-Boot...

U-Boot NetConsole
-----------------

Marvell>> help

This is also a security hole in the device: anybody with IP connectivity to the Lacie can interrupt the bootstrap process and perform low level operations on the device, taking full control of it. FIXME Actually I was not able to bootstrap the internal hard disk from the NetConsole, it seems that the SATA controller is disabled when NetConsole is activated.

Here it is the output of the help and printenv (print environment variables) command.

Experimenting on the NetConosole:

Marvell>> echo ${bootcmd}
echo ${bootcmd}
if lump 2; then ; else run disk_disk; fi
Marvell>> echo ${disk_disk}
echo ${disk_disk}
ide reset; run boot_disk1; bootm ${kernel_addr};
Marvell>> echo ${boot_disk1}
echo ${boot_disk1}
if disk ${kernel_addr} 1:A; then; else run boot_disk2; fi
Marvell>> echo ${kernel_addr}
echo ${kernel_addr}
0x400000
Marvell>> echo ${boot_disk2}
echo ${boot_disk2}
disk ${kernel_addr} 1:6
Marvell>> echo ${bootargs}
echo ${bootargs}
console=ttyS0,115200 root=/dev/sda7 ro boardType=mv88F5182 productType=d2Next

As you can see the standard boot sequence is:

  1. Eventually wait for the LUMP packet
  2. If not LUMP packet, load boot image from IDE device 1:A (/dev/sda10)
  3. If boot from sda10 fails, load boot image from IDE device 1:6 (/dev/sda6)
  4. Run the boot image, passing bootargs to the kernel.

The commands diskboot and bootm are used to load the boot image and to run it respectively.

FIXME Strange enough: I cannot start the device with boot, it does not find the hard disk.

Marvell>> boot
boot
Waiting for LUMP (2)
no lump receive; continuing

Reset IDE:
Marvell Serial ATA Adapter
Integrated Sata device found


** Device 1 not available

** Device 1 not available
## Booting image at 00400000 ...
Bad Magic Number
Marvell>> ide reset
ide reset

Reset IDE:
Marvell Serial ATA Adapter
Integrated Sata device found

Marvell>> ide info
ide info

Marvell>>

JTAG Serial Connector Pin-out

Once disassembled you can see the JTAG 8 pin connector: a 8 pin header 2.0 mm pitch (you can use a female connector SQT-108-01-L-S). Pin 1 is toward the hard disk, pin 8 is toward the power switch.

JTAG Serial Pin Out

Pin Signal
1 +3.3 V
2 GND
3
4
5
6
7 RX
8 TX

This is a 3.3 volt serial port, to connect it to a standard one we need an adapter, like those based on the MAX232 chip.

The U-Boot boot loader will write to the serial port at 115200,8,N,1, so the kernel during bootstrap. Once started the system will spawn a getty on the same serial port, with the same baud rate. On the original system, only root can login, but we don't know its password.

This is the start of boot messages, here you can find the full bootstrap log.

         __  __                      _ _
        |  \/  | __ _ _ ____   _____| | |
        | |\/| |/ _` | '__\ \ / / _ \ | |
        | |  | | (_| | |   \ V /  __/ | |
        |_|  |_|\__,_|_|    \_/ \___|_|_|
 _   _     ____              _
| | | |   | __ )  ___   ___ | |_
| | | |___|  _ \ / _ \ / _ \| __|
| |_| |___| |_) | (_) | (_) | |_
 \___/    |____/ \___/ \___/ \__|  ** LOADER **
 ** MARVELL BOARD: DB-88F5182-LaCie LE

U-Boot 1.1.4 (Feb  9 2009 - 13:15:53) Marvell version: 2.4.9  LaCie : 1.00.0001

U-Boot code: 00200000 -> 0026FFF0  BSS: -> 00283280

Soc: 88F5182 A2 (DDR2)
CPU running @ 400Mhz
SysClock = 200Mhz , TClock = 166Mhz

DRAM CS[0] base 0x00000000   size 128MB
DRAM Total size 128MB  32bit width
[512kB@fff80000] Flash: 512 kB
Addresses 4M - 0M are saved for the U-Boot usage.
Mem malloc Initialization (4M - 3M): Done
*** Warning - bad CRC, using default environment

CPU : ARM926 (Rev 0)
88F5182 A2 streaming disabled

Compiling the Linux kernel

You can download the custom kernel I compiled (vanilla with patches for LEDs) here: http://www.rigacci.org/pub/Linux/kernel-lacie/

After several tries, I compiled a 2.6.32 kernel suitable to boot the LaCie from an ext3 Debian Lenny partition. No initrd is required to boot (this is fortunate FIXME, because I don't know how to install initrd with U-Boot). Here it is the config file.

The installation steps are:

  1. dd(1) the uImage (not the vmlinuz bzImage) to /dev/sda6.
  2. Provide a Debian rootfs into /dev/sda7 (substitute the LaCie one. Partition sda8, sda9 and sda10 are no longer used).
  3. Install the linux-image-2.6.32_lacie.0.10_armel.deb Debian package.
  4. Provide a swap partion into /dev/sda5 (this is the LaCie default).

Native compile

We will try to compile a Debian kernel directly on the LaCie, i.e. this is a native compile, not a cross-compile. Obviously this will require a lot of time, a typical Debian kernel will require over 13.5 hours!

We start installing the Debian packages kernel-package and linux-source-2.6.32 (from Debian Squeeze) and all the dependencies.

We get a .config file from the Debian package linux-image-2.6.32-trunk-kirkwood_2.6.32-5_armel.deb, just to have something to start from:

/usr/src
tar jxf linux-source-2.6.32.tar.bz2
ln -s linux-source-2.6.32 linux
cd linux
make-kpkg clean
cp /root/config-2.6.32-trunk-kirkwood .config
make-kpkg --revision=lacie.0.1 kernel_image --initrd --cross_compile=-

The cross_compile option is required, otherwise the script will prepend the arm-linux-gnueabi- prefix to all the build tool (ar, as, cc, ld, nm, objdump, objcopy, strip) and will fail, unless you make required symlinks in /usr/bin/.

To avoid Cannot allocate memory errors, provide plenty of swap space. The standard 128 Mb swap partition was not sufficient, an additional 1 Gb swap file did.

Cross compile

Compiling an arm kernel (for the LaCie) on a non-arm Linux box (e.g. your i386 or amd64 desktop) is called cross-compiling, this requires a specific toolchain (compiler and utilities). The Embedian project provides several prebuilt toolchains for Debian. See also How to build a new Debian/NSLU2 image. Compiling a kernel on my virtual KVM Linux box (running on an AMD Athlon 2.3 GHz) requires about 1 hour.

The Emdebian Wiki has detailed instructions, in short (we are working on Debian Lenny):

NOTE 1: make-kpkg suggests to use the value of DEB_HOST_ARCH_CPU reported by dpkg-architecture as the -arch parameter. On the LaCie it is arm, but we want KERNEL_ARCH=arm and DPKG_ARCH=armel so that the resulting .deb package will be installable into Debain armel. To obtain this, we need to add some line at the end of /usr/share/kernel-package/ruleset/misc/kernel_arch.mk:

ifeq ($(strip $(architecture)),armel)
  KERNEL_ARCH := arm
endif
ifeq ($(strip $(architecture)),armeb)
  KERNEL_ARCH := arm
endif

NOTE 2: Always remember to define the CROSS_COMPILE and ARCH variables before making anything in the source tree, also if you are just executing a make menuconfig.

NOTE 3: After installing the .deb package, you must also install the uImage:

dd if=uImage of=/dev/sda6

NOTE 4: Using kernel-package 12.032 from Debian Squeeze, requires to patch debug.mk and image.mk files into /usr/share/kernel-package/ruleset/targets/ directory. They invoke the objcopy command wich fails on arm files, it should be substituted by $(CROSS_COMPILE)objcopy. Is this a bug? FIXME

Testing a kernel image

Our first try did not produce an image capable of booting the LaCie, fortunately it is possible to test a kernel image without actually installing it: just load it from a tftp server and try a boot.

On your Linux box install the tftpd package and copy the kernel uImage into /srv/tftp/C0A80224.img (the default filename loaded by the U-Boot tftp client depends on the LaCie IP address).

Start the NetConsole using clunc (see above), and use the tftpboot and bootm commands:

Marvell>> tftpboot
TFTP from server 192.168.2.6; our IP address is 192.168.2.36
Filename 'C0A80224.img'.
Load address: 0x400000
Loading: #####...
done
Bytes transferred = 1433512 (15dfa8 hex)
Marvell>> bootm 0x400000
bootm 0x400000
## Booting image at 00400000 ...
   Image Name:   Linux-2.6.32
   Created:      2010-02-01  13:29:21 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    1433448 Bytes =  1.4 MB
   Load Address: 00008000
   Entry Point:  00008000
   Verifying Checksum ... OK
OK

Starting kernel ...

If you need to pass different boot arguments to the kernel, use setenv before bootm (the change is temporary, use saveenv to make it permanent):

Marvell>> echo ${bootargs}
echo ${bootargs}
console=ttyS0,115200 root=/dev/sda7 ro boardType=mv88F5182 productType=d2Next
Marvell>> setenv bootargs "console=ttyS0... "

If you are attached to the serial console you can see the kernel boot messages and errors:

Waiting for WOL Magic Packet
Using egiga0 device
Hit any key to stop autoboot:  0
Waiting for LUMP (0)
Lump received switching to NetConsole on 192.168.2.6
Uncompressing Linux... done, booting the kernel.

Error: unrecognized/unsupported machine ID (r1 = 0x0000020e).

Available machine support:

ID (hex)        NAME
00000690        Marvell DB-88F6281-BP Development Board
00000691        Marvell RD-88F6192-NAS Development Board
00000692        Marvell RD-88F6281 Reference Board
00000831        Marvell SheevaPlug Reference Board
0000085b        QNAP TS-119/TS-219
000009c6        QNAP TS-41x
00000915        Marvell OpenRD Base Board
00000939        Marvell OpenRD Client Board

Please check your kernel config and/or bootloader.

Tip #1: Fixing the machine ID

The first problem was with the machine ID: the boot loader passes 0x20e = 526 in the r1 register, while the Linux kernel knows about different values (0x8ea = 2282 is the LaCie d2 Network). See the explanation here: Resolving Booting Problems on arm.

The fix is to change the archNumber environment variable (saving it into the U-Boot flash is required) and reset:

Marvell>> echo ${arcNumber}
echo ${arcNumber}
526
Marvell>> setenv arcNumber 2282
setenv arcNumber 2282
saveenv
reset

Tip #2: Warning: unable to open an initial console

If we are trying to use a kernel without initrd, remember to populate the /dev/ directory, at least with the following devices:

crw------- 1 root root    5,  1 2010-02-03 21:28 /dev/console
brw-rw---- 1 root disk    8,  0 2010-02-03 21:27 /dev/sda
brw-rw---- 1 root disk    8,  1 2010-02-03 21:27 /dev/sda1
brw-rw---- 1 root disk    8,  2 2010-02-03 21:27 /dev/sda2
brw-rw---- 1 root disk    8,  5 2010-02-03 21:27 /dev/sda5
brw-rw---- 1 root disk    8,  6 2010-02-03 21:27 /dev/sda6
brw-rw---- 1 root disk    8,  7 2010-02-03 21:27 /dev/sda7
brw-rw---- 1 root disk    8,  8 2010-02-03 21:27 /dev/sda8
brw-rw---- 1 root disk    8,  9 2010-02-03 21:27 /dev/sda9
brw-rw---- 1 root disk    8, 10 2010-02-03 21:27 /dev/sda10
crw-rw---- 1 root root    4,  0 2010-02-03 21:27 /dev/tty0
crw------- 1 root root    4,  1 2010-02-03 21:28 /dev/tty1
crw------- 1 root root    4,  2 2010-02-03 21:28 /dev/tty2
crw------- 1 root root    4,  3 2010-02-03 21:28 /dev/tty3
crw------- 1 root root    4,  4 2010-02-03 21:28 /dev/tty4
crw------- 1 root root    4, 64 2010-02-03 21:28 /dev/ttyS0
crw-rw---- 1 root dialout 4, 65 2010-02-03 21:27 /dev/ttyS1

Once init(8) will start, other devices will be created by udev(7).

USB Sound

When I attached an USB audio stick, this is what the lsusb command says:

Bus 001 Device 002: ID 0c76:1607 JMTek, LLC.

Then the kernel loads the proper drivers:

usb 1-1: new full speed USB device using orion-ehci and address 2
usb 1-1: New USB device found, idVendor=0c76, idProduct=1607
usb 1-1: New USB device strings: Mfr=0, Product=1, SerialNumber=0
usb 1-1: Product: USB Headphone Set
usb 1-1: configuration #1 chosen from 1 choice
usbcore: registered new interface driver hiddev
input: USB Headphone Set as /devices/platform/orion-ehci.0/usb1/1-1/1-1:1.3/input/input1
generic-usb 0003:0C76:1607.0001: input,hidraw0: USB HID v1.00 Device [USB Headphone Set] on usb-orion-ehci.0-1/input3
usbcore: registered new interface driver usbhid
usbhid: v2.6:USB HID core driver
usbcore: registered new interface driver snd-usb-audio

Playing some mp3 tracks with mpg321 via Alsa resulted in annoying audio glitches; strange enough the glitches tend to disappear if the LaCie is under heavy load. Fortunately there is a workaround: load the Alsa OSS compatibility layer and use OSS output instead:

modprobe snd_pcm_oss
mpg321 -o oss track1.mp3

Playing mp3 takes about 16% of CPU, 2% of memory and system load average remains near to zero.

USB Audio volume problem

On Linux kernel 2.6.32 (providing Alsa sound drivers 1.0.21) the following USB audio dongle works as expected, including the volume control:

Bus 001 Device 003: ID 0c76:1607 JMTek, LLC. audio controller

There is a problem with some other USB chips, where the volume control does not work. When the volume control is set to the lower position, the audio is muted, but at any other position the audio is set to its maximum value. This is a chip wich has the problem:

Bus 001 Device 002: ID 1130:f211 Tenx Technology, Inc. TP6911 Audio Headset

Here there is a bug report #559939 reported to the Ubuntu distribution.

Other NAS comparison

Model CPU RAM Flash HD Fan WoL
Qnap TS-110 800 Mhz 256 Mb 16 Mb 1 Yes ?
Qnap TS-119 1.2 Ghz 512 Mb 16 Mb 1 No ?
ReadyNAS Duo RND2000 280 Mhz Sparc 32 (exp) 256 Mb 64 Mb 2 Yes No
NETGEAR Stora MS2110 1 GHz Marvell 88F6281 Kirkwood 128 Mb 256 Mb 2 Yes ?
LaCie d2 Network 400 Mhz Marvell 88F5182 Orion 128 Mb 4 Mb 1 No Yes
LaCie 2big Network 400 Mhz 64 Mb ? 2 Yes ?
LaCie Network Space 1 TB 400 Mhz Marvell 88F6082 Feroceon 16/64 Mb ? 1 No ?

Backporting minidlna

We run Debian 6 Squeeze on our LaCie d2 Network and we want it to be a DLNA server. We choosed minidlna because it is targeted to embedded systems. The package exists for Debian 7 Wheezy, so we have to backport it.

Into a Qemu armel virtual machine we installed the packages required for Debian developing and build dependencies, we need also debhelper from backports.

apt-get install build-essential dh-make debhelper dpatch
apt-get install libavcodec-dev libavformat-dev libavutil-dev libexif-dev \
    libflac-dev libid3tag0-dev libogg-dev libsqlite3-dev libvorbis-dev libjpeg-dev
wget http://ftp.at.debian.org/debian-backports//pool/main/d/debhelper/debhelper_9.20120909~bpo60+1_all.deb
dpkg -i debhelper_9.20120909~bpo60+1_all.deb

Then we downloaded the minidlna sources and compiled the sources:

mkdir /usr/local/src/minidlna
cd /usr/local/src/minidlna
wget http://ftp.de.debian.org/debian/pool/main/m/minidlna/minidlna_1.0.24+dfsg-1.dsc
wget http://ftp.de.debian.org/debian/pool/main/m/minidlna/minidlna_1.0.24+dfsg.orig.tar.gz
wget http://ftp.de.debian.org/debian/pool/main/m/minidlna/minidlna_1.0.24+dfsg-1.debian.tar.gz
dpkg-source -x minidlna_1.0.24+dfsg-1.dsc
cd minidlna-1.0.24+dfsg
dpkg-buildpackage -rfakeroot
cd ..

The resulting minidlna_1.0.24+dfsg-1_armel.deb package installed fine into the LaCie, just make a symlink /run → /var/run.

Configuration file is /etc/minidlna.conf, default share directory is /var/lib/minidlna, used ports are 8200/TCP (http and media transfer), 3307/UDP and 1900/UDP.