[ltp] handling UltraBay with hard disk
Peter F. Patel-Schneider
linux-thinkpad@linux-thinkpad.org
Tue, 05 May 2009 15:13:06 -0400 (EDT)
From: Peter F. Patel-Schneider <pfps@research.bell-labs.com>
Subject: Re: [ltp] handling UltraBay with hard disk
Date: Tue, 05 May 2009 07:17:29 -0400 (EDT)
[...]
> Lay it on me. What I have is a modified version of the hotswap stuff
> from ThinkWiki and *it* is a crazy combination of a shell script and
> perl. The ThinkWiki script unmounts, powers off the device, deletes the
> device, and then powers off the UltraBay itself, but unfortunately
> doesn't quite work in F11. What I do have working is unmounting and
> then deleting the SCSI device.
>
> What I would like to have would be a general script that in a safe and
> sane and *general* fashion does everything needed, for any dock/bay
> device that has a disk in it (maybe even including a CD). However, I
> don't see how to really correctly do that in a udev rule, particularly
> coordinating the actions on the device (unmount, ...) and the bay (power
> down).
>
> Perhaps I'm just stuck with my 90% solution (upgraded to a 95%
> solution).
>
> I would also like to update the ThinkWiki page
> http://www.thinkwiki.org/wiki/How_to_hotswap_UltraBay_devices
> but I don't know what can safely be removed. Perhaps I'll just clean
> out anything that looks too old to me and see if anyone screams.
>
> peter
As thinkwiki.org has been down for a while, I thought that I would
socialize my 90% solution directly.
My solution has the following problems:
1/ The code to get from the disk to the mounts is too complex.
2/ I can't get the "spin hard drive down" to work.
3/ The link from the disk to the bay is hard coded so the script is
not general.
However, the following scenarios all work and end up only four
different states
- A - bay in and disk/bay on - eject tab in
- B - bay in and disk/bay off - eject tab out
- C - bay in and disk/bay on - eject tab out - error state
- D - bay out
1/ Unmount (from state A)
- flip the switch
- unmount is successful and bay turned off
- ends up in state B
2/ Remove (from state B)
- pull the bay out, using the eject tab
- ends up in state D
3/ Insert (from state D)
- push the bay in
- ends up in state B
4/ Mount (from state B)
- push the eject tab in
- ends up in state A
5/ Drive busy (from state A)
- flip the switch
- drive is busy so unmount is not successful and bay not turned off
- goes to state C
- pushing eject tab in goes back to state A
What I did was add a udev rule
ENV{BAY_EVENT}=="3", ACTION=="change", SUBSYSTEM=="scsi", RUN+="/usr/local/sbin/ultrabay_eject"
with the following script, modified from
http://www.thinkwiki.org/wiki/How_to_hotswap_UltraBay_devices
#!/bin/bash
# Semi-graceful unmount of the SCSI device in a ThinkPad Ultrabay
# in response to flipping the pre-eject switch
ULTRABAY_SYSDIR=/sys$DEVPATH
shopt -s nullglob
logger ultrabay_eject unmounting storage device $DEVPATH
# Umount the filesystem(s) backed by the given major:minor device(s)
## It would be nice to do this in the shell instead
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("logger","ultrabay_eject","umounting",$dev,$dir);
system("umount","-v","$dir")==0 or $bad=1;
}
exit 1 if $bad;
EOPERL
}
## This doesn't seem to work somehow - I don't know why
ultrabay_dev_node() {
shopt -u nullglob
DEV_SYSPATH="$@"
UDEV_NAME=`udevadm info --query=name --path=$DEV_SYSPATH` || return 1
echo /dev/$UDEV_NAME
}
if [ -d $ULTRABAY_SYSDIR ]; then
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 ultrabay_eject umounting failed
echo 2 > /proc/acpi/ibm/beep # error beep
exit 1
}
sync
## Nicely power off the device ?? - Can't get this to work!
# DEVNODE=`ultrabay_dev_node $ULTRABAY_SYSDIR/block/*` && hdparm -Y $DEVNODE
# Let HAL+KDE notice the unmount and let the disk spin down
# Unregister this SCSI device:
sync
logger ultrabay_eject deleting device
echo 1 > $ULTRABAY_SYSDIR/delete
# Need to sleep to let something disassociate the drive from the dock
sleep 0.5
else
logger ultrabay_eject no ultrabay device directory
echo 2 > /proc/acpi/ibm/beep # error beep
exit 1
fi
sync
# Turn off power to the UltraBay:
## This is fragile and obviously the wrong way to go,
## but I don't know how to go from the disk to the bay
if [ -d /sys/devices/platform/dock.2 ]; then
logger ultrabay_eject undocking bay
echo 1 > /sys/devices/platform/dock.2/undock
fi
# Tell the user we're OK
logger ultrabay_eject done
echo 12 > /proc/acpi/ibm/beep