Linux UltraBay Hotswap

Aus ThinkPad-Wiki

Hotswap von UltraBay-Geräten auf einem T61 unter Debian Linux

Hier wird eine funktionierende Lösung für den Hotswap von UltraBay-Geräten auf einem T61 unter Debian Linux präsentiert. Es handelt sich dabei um eine angepasste Version der Skripte von www.thinkwiki.org/wiki/How_to_hotswap_Ultrabay_devices#Script_for_Ultrabay_eject

Erfolgreich getestet wurde diese Version bisher auf einem T61 mit Debian Linux (unstable) und Kernel 3.8.5 aus dem experimentellen Bereich von Debian. Für andere ThinkPads sind gegebenenfalls Anpassungen der DEVPATH-Variablen am Anfang der jeweiligen Skripte vorzunehmen.

Voraussetzungen

Die unten aufgeführten Skripte benachrichtigen den Anwender mittels notify-send über den Erfolgsstatus der Hotswap-Skripte, und setzen deswegen die Installation des Debian-Pakets libnotify-bin vorraus:

apt-get -u -m install libnotify-bin

Da die UltraBay eines T61 im Gegensatz zu neueren ThinkPad-Modellen noch auf ATA-Basis statt SATA funktioniert, ist es zu empfehlen, darauf zu achten, das Kernel-Modul ata_piix möglichst erst am Ende des Bootvorgangs laden zu lassen. Das bietet den Vorteil, dass eine in der UltraBay enthaltene zweite Festplatte niemals fälschlicherweise als erste Systemplatte /dev/sda eingebunden wird.

Zu diesem Zwecke legt man zuerst die Datei "/etc/modprobe.d/blacklist-ata_piix.conf" mit folgendem Inhalt an:

### module ata_piix is loaded in /etc/rc.local after reboot, to make sure
### that ultrabay disk always gets assigned a disk device file other than
### /dev/sda and thus leaving sda to the internal SATA system disk.
blacklist ata_piix                                                                                                                                                                                                        

Im zweiten Schritt fügt man in "/etc/rc.local" folgende Einträge hinzu:

### module ata_piix blacklisted in /etc/modprobe.d/blacklist.conf and
### loaded manually after reboot, in order to make sure that ultrabay
### disk always gets assigned a disk device file other than /dev/sda and
### thus leaving sda to the internal SATA system disk.

/sbin/modprobe ata_piix

### Do a vgscan to have any LV located on ultrabay disk noticed by LVM.

/sbin/vgscan

# enable still inactive logical volumes if any is found:

for LVOL in $(/sbin/lvscan | /bin/grep inactive | /usr/bin/cut -d\/ -f3 | /usr/bin/sort -u)
do
    [ "$(/bin/echo $LVOL)" != "" ] && /sbin/vgchange -a y $LVOL
done

# Make sure that the script will "exit 0" on success or any other value on error.
exit 0

Skripte zur Bereitstellung der Hotswap-Funktionalität

Folgendes Skript als "/etc/udev/rules.d/50-thinkpad-ultrabay.rules" speichern und mit dem Befehl udevadm control --reload-rules im System aktivieren:

# Change the DEVPATH variable to match your system, if it doesn't match your ThinkPad model
# The DEVPATH value used here should hopefully be working out of the box on any T6x ThinkPad.
# To find the correct value for your ThinkPad, insert the UltraBay optical drive and execute:
# udevadm info --query=path --name=/dev/sr0 | perl -pe 's!/block/...$!!'
 
SUBSYSTEMS=="block", DEVPATH=="/devices/pci0000:00/0000:00:1f.1/ata4/host3/*", ENV{UDISKS_SYSTEM_INTERNAL}="0"
ENV{EVENT}=="undock", KERNEL=="dock.1", ACTION=="change", SUBSYSTEM=="platform", RUN+="/usr/local/sbin/ultrabay_eject"
ENV{EVENT}=="dock", KERNEL=="dock.1", ACTION=="change", SUBSYSTEM=="platform", RUN+="/usr/local/sbin/ultrabay_insert"

Folgendes Skript als "/usr/local/sbin/ultrabay_eject" speichern und Ausführungsrechte mit "chmod 754 /usr/local/sbin/ultrabay_eject" setzen:

#!/bin/bash
#set -x

# Sources:
# http://www.thinkwiki.org/wiki/How_to_hotswap_Ultrabay_devices#Script_for_Ultrabay_eject
# http://www.thinkwiki.org/wiki/Talk:How_to_hotswap_Ultrabay_devices

SCRIPTNAME="$(basename $0)"

# Change the DEVPATH variable to match your system, if it doesn't match your ThinkPad model
# The DEVPATH value used here should hopefully be working out of the box on any T6x ThinkPad.
# To find the correct value for your ThinkPad, insert the UltraBay optical drive and execute:
# udevadm info --query=path --name=/dev/sr0 | perl -pe 's!/block/...$!!'

if [ "$DEVPATH" = "" ]
then
   DEVPATH="/devices/pci0000:00/0000:00:1f.1/ata4/host3/target3:0:0/3:0:0:0"
fi

shopt -s nullglob
export DISPLAY=:0.0 # required for notify-send

DISP0_USER=$(who | grep "tty" | awk '{ print $1 }')
DISP0_USER_HOME=`getent passwd ${DISP0_USER} | cut -d':' -f6`
export XAUTHORITY=${DISP0_USER_HOME}/.Xauthority # also required for notify-send

ULTRABAY_SYSDIR=/sys$DEVPATH

# Find generic dock interface for UltraBay
dock=$(dirname $(/bin/grep -l ata_bay /sys/devices/platform/dock.?/type))

if [ ! -n "$dock" -a -d "$dock" ]; then
        logger "$SCRIPTNAME": cannot locate bay dock device
        notify-send -u critical -t 100000 "ThinkPad Ultrabay eject failed" "Cannot locate bay dock device"
        exit 1
fi

# Umount the filesystem(s) backed by the given major:minor device(s)
unmount_rdev() { perl - "$@" <<'EOPERL'  # let's do it in Perl
        for $major_minor (@ARGV) {
                $major_minor =~ m/^(\d+):(\d+)$/ or die;
                push(@tgt_rdevs, ($1<<8)|$2);
        }
        # Sort by reverse length of mount point, to unmount sub-directories first
        open MOUNTS,"</proc/mounts" or die "$!";
        @mounts=sort { length($b->[1]) <=> length($a->[1]) } map { [ split ] } <MOUNTS>;
        close MOUNTS;
        foreach $m (@mounts) {
                ($dev,$dir)=@$m;
                next unless -b $dev;  $rdev=(stat($dev))[6];
                next unless grep($_==$rdev, @tgt_rdevs);
                system("umount","-v","$dir")==0  or  $bad=1;
                if ($bad == 1) {
                        system("logger","ultrabay_eject","ERROR unmounting",$dev,$dir);
                        system("notify-send -u critical -t 100000 \"Error unmounting $dir\" \"Unmounting of $dir on $dev failed!\"");
                } else {
                        system("logger","ultrabay_eject","unmounted",$dev,$dir);
                        system("notify-send -u normal -t 5000 \"Unmounted $dir\"");
                };
        }
        exit 1 if $bad;
EOPERL
}

# Get the UltraBay's /dev/foo block device node
ultrabay_dev_node() {
        UDEV_PATH="`readlink -e "$ULTRABAY_SYSDIR/block/"*`" || return 1
        UDEV_NAME="`udevadm info --query=name --path=$UDEV_PATH`" || return 1
        echo /dev/$UDEV_NAME
}

if [ $( cat $dock/docked ) == 0 ]; then
        logger "$SCRIPTNAME": dock reports empty
else 
    if [ -d $ULTRABAY_SYSDIR ]; then
	logger "$SCRIPTNAME": dock occupied, shutting down storage device $DEVPATH
	sync
	# Unmount filesystems backed by this device
	## This seems to be very inelegant and prone to failure
	unmount_rdev `cat $ULTRABAY_SYSDIR/block/*/dev     \
	  $ULTRABAY_SYSDIR/block/*/*/dev`  \
	|| {
		logger "$SCRIPTNAME": umounting failed
		notify-send -u critical -t 100000 "ThinkPad Ultrabay eject failed" "Please do not pull the device, doing so could cause file corruption and possibly  hang the system. Unmounting of the filesystem on the ThinkPad Ultrabay device failed. Please put the eject leaver back in place, and try to unmount the filesystem manually. If this succeeds you can try the eject again"
		exit 1;
	}
	sync
	# Nicely power off the device
	DEVNODE=`ultrabay_dev_node` && hdparm -Y $DEVNODE
	# Let HAL+KDE notice the unmount and let the disk spin down
	sleep 0.5
	# Unregister this SCSI device:
	sync
	echo 1 > $ULTRABAY_SYSDIR/delete
    else
	logger "$SCRIPTNAME": bay occupied but incorrect device path $DEVPATH
	notify-send -u critical -t 100000 "ThinkPad Ultrabay eject failed" "Bay occupied but incorrect device path"
	exit 1
    fi
fi

# We need to sleep here to wait for the bay and the drive to disconnect
sleep 1

# Undocking the UltraBay:
logger "$SCRIPTNAME": undocking $dock
if [ "$(cat $dock/docked)" != "0" ]; then
    echo 1 > $dock/undock
else
    # Tell the user we're OK once done
    logger "$SCRIPTNAME": successfully completed
    notify-send -u normal -t 10000 "Safe to remove device" "The ThinkPad Ultrabay device can now be safely removed"
    exit 0
fi

Folgendes Skript als "/usr/local/sbin/ultrabay_insert" speichern und Ausführungsrechte mit "chmod 754 /usr/local/sbin/ultrabay_insert" setzen

#!/bin/bash
#set -x

# Source:
# http://www.thinkwiki.org/wiki/How_to_hotswap_Ultrabay_devices#Script_for_Ultrabay_eject
# http://www.thinkwiki.org/wiki/Talk:How_to_hotswap_Ultrabay_devices

SCRIPTNAME="$(basename $0)"

export DISPLAY=:0.0 # required for notify-send
DISP0_USER=$(who | grep "tty" | awk '{ print $1 }')
DISP0_USER_HOME=`getent passwd ${DISP0_USER} | cut -d':' -f6`
export XAUTHORITY=${DISP0_USER_HOME}/.Xauthority # also required for notify-send

# Change the DEVPATH variable to match your system, if it doesn't match your ThinkPad model
# The DEVPATH value used here should hopefully be working out of the box on any T6x ThinkPad.
# To find the correct value for your ThinkPad, insert the UltraBay optical drive and execute:
# udevadm info --query=path --name=/dev/sr0 | perl -pe 's!/block/...$!!'

if [ "$DEVPATH" = "" ]
then
   DEVPATH="/devices/pci0000:00/0000:00:1f.1/ata4/host3/target3:0:0/3:0:0:0"
fi

ULTRABAY_SYSDIR=/sys$DEVPATH

# Get the UltraBay's /dev/foo block device node
ultrabay_dev_node() {
        UDEV_PATH="`readlink -e "$ULTRABAY_SYSDIR/block/"*`" || return 1
        UDEV_NAME="`udevadm info --query=name --path=$UDEV_PATH`" || return 1
        echo /dev/$UDEV_NAME
}

DOCKDEVICE=$(lsscsi | grep $(ultrabay_dev_node) | tr -s " ")

# Find generic dock interface for UltraBay
dock=$(dirname $(/bin/grep -l ata_bay /sys/devices/platform/dock.?/type))

if [ ! -n "$dock" -a -d "$dock" ]; then
    logger "$SCRIPTNAME": cannot locate bay dock device
    notify-send -u critical -t 100000 "ThinkPad Ultrabay device docking failed" "Cannot locate bay dock device"
    exit 1
fi

# Tell the user we're OK once done

if [ "$(cat $dock/docked)" = "1" ]; then
    sync
    logger "$SCRIPTNAME": Scanning ThinkPad Ultrabay for new device
    echo 0 0 0 > /sys/class/scsi_host/host3/scan
    logger "$SCRIPTNAME": Docking of ThinkPad Ultrabay device successfully completed.
    notify-send -u normal -t 10000 "Docking ThinkPad Ultrabay device completed" "The ThinkPad Ultrabay device is now available for use."
    exit 0
else
    logger "$SCRIPTNAME": ThinkPad Ultrabay device docking failed
    notify-send -u normal -t 10000 "Docking ThinkPad Ultrabay device failed" "Docking the ThinkPad Ultrabay device failed. Please check what went wrong and fix it."
    exit 1
fi

Beschreibung des Hotswap-Vorgangs

Sobald die oben aufgeführten Skripte mit den jeweils notwendigen Zugriffsrechten erstellt und aktiviert wurden, bewirkt die Betätigung des Schiebeschalters zur Initialisierung des Auswurfvorgangs an der UltraBay die automatische Abschaltung des in der UltraBay enthaltenen Geräts. Vorher noch wird versucht, alle gemounteten Dateisysteme des Gerätes zu umounten.

Sobald das Gerät erfolgreich deaktiviert wurde, erscheint eine Desktop-Benachrichtigung in Form einer Textblase mit einem entsprechenden Hinweis, bzw. im Fehlerfalle mit einer entsprechenden Fehlermeldung. Im Erfolgsfalle kann das Gerät nun einfach an der herausgesprungenen Lasche der Ultrabay herausgezogenen werden.

Wenn ein Gerät in die UltraBay eingesetzt wird, dann wird es automatisch aktiviert, und der Desktop-Benutzer erhält eine Benachrichtigung über den Erfolgsstatus.

Debian Paket ultrabay-scripts

Eine bereits weiter fortgeschrittene Variante der oben gelisteten Skripte wurden zusammen mit zusätzlichen Erweiterungen in ein Debian Paket namens "ultrabay-scripts" zusammengefasst. Sowohl das fertige Binär-Paket als auch der Quellcode können von http://sourceforge.net/projects/wmlive/files/ultrabay-scripts heruntergeladen werden.