204 lines
4.4 KiB
Plaintext
204 lines
4.4 KiB
Plaintext
|
#!/bin/sh
|
||
|
#
|
||
|
# Copyright 2009 Red Hat, Inc.
|
||
|
# License: GPLv2
|
||
|
# Author: Dan Horák <dhorak@redhat.com>
|
||
|
#
|
||
|
# unblock devices listed in various config files and wait until they are ready
|
||
|
#
|
||
|
# it uses dasd and zfcp config file
|
||
|
# config file syntax:
|
||
|
# deviceno options
|
||
|
# or
|
||
|
# deviceno WWPN FCPLUN
|
||
|
#
|
||
|
# also processes the system ccw config file and network interface configurations
|
||
|
#
|
||
|
|
||
|
DASDCONFIG=/etc/dasd.conf
|
||
|
ZFCPCONFIG=/etc/zfcp.conf
|
||
|
ZNETCONFIG=/etc/ccw.conf
|
||
|
BLACKLIST=/proc/cio_ignore
|
||
|
VERBOSE=
|
||
|
PATH=/bin:/usr/bin:/sbin:/usr/sbin
|
||
|
ALL_DEVICES=
|
||
|
|
||
|
usage()
|
||
|
{
|
||
|
echo "$0 [-h|--help] [-V|--verbose]"
|
||
|
exit 1
|
||
|
}
|
||
|
|
||
|
# accepts single device, comma-separated lists and dash separated ranges and their combinations
|
||
|
free_device()
|
||
|
{
|
||
|
local DEV
|
||
|
|
||
|
[ -z "$1" ] && return
|
||
|
|
||
|
DEV=$(echo $1 | tr "A-Z" "a-z")
|
||
|
|
||
|
[ $VERBOSE ] && echo "Freeing device(s) $DEV"
|
||
|
if [ echo "free $DEV" > $BLACKLIST 2> /dev/null ]; then
|
||
|
echo "Error: can't free device(s) $DEV"
|
||
|
else
|
||
|
if [ -z $ALL_DEVICES ]; then
|
||
|
ALL_DEVICES=$DEV
|
||
|
else
|
||
|
ALL_DEVICES="$ALL_DEVICES,$DEV"
|
||
|
fi
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# wait until a device appears on the ccw bus
|
||
|
wait_on_device()
|
||
|
{
|
||
|
local DEVICE_ONLINE DEV
|
||
|
|
||
|
[ -z "$1" ] && return
|
||
|
|
||
|
DEV=$1
|
||
|
DEVICE_ONLINE=/sys/bus/ccw/devices/$DEV/online
|
||
|
|
||
|
[ $VERBOSE ] && echo "Waiting on device $DEV"
|
||
|
[ -f "$DEVICE_ONLINE" ] && return
|
||
|
|
||
|
for t in 1 2 3 4 5
|
||
|
do
|
||
|
sleep $t
|
||
|
[ -f "$DEVICE_ONLINE" ] && return
|
||
|
done
|
||
|
echo "Error: device $DEV still not ready"
|
||
|
}
|
||
|
|
||
|
# check how we were called
|
||
|
case $(basename "$0") in
|
||
|
"dasd_cio_free")
|
||
|
CONFIG=$DASDCONFIG
|
||
|
MODE=dasd
|
||
|
;;
|
||
|
"zfcp_cio_free")
|
||
|
CONFIG=$ZFCPCONFIG
|
||
|
MODE=zfcp
|
||
|
;;
|
||
|
"znet_cio_free")
|
||
|
CONFIG=$ZNETCONFIG
|
||
|
MODE=znet
|
||
|
;;
|
||
|
*)
|
||
|
echo "Error: unknown alias '$CMD'."
|
||
|
echo "Supported aliases are dasd_cio_free, zfcp_cio_free and znet_cio_free."
|
||
|
exit 1
|
||
|
;;
|
||
|
esac
|
||
|
|
||
|
# process command line options
|
||
|
if [ $# -gt 0 ]; then
|
||
|
case $1 in
|
||
|
-V|--verbose)
|
||
|
VERBOSE=yes
|
||
|
shift
|
||
|
;;
|
||
|
-h|--help)
|
||
|
usage
|
||
|
;;
|
||
|
*)
|
||
|
echo "Error: unknown option $1"
|
||
|
usage
|
||
|
;;
|
||
|
esac
|
||
|
fi
|
||
|
|
||
|
if [ ! -f $BLACKLIST ]; then
|
||
|
echo "Error: $BLACKLIST kernel interface doesn't exist"
|
||
|
exit 2
|
||
|
fi
|
||
|
|
||
|
if [ $MODE = "dasd" -o $MODE = "zfcp" ]; then
|
||
|
# process the config file
|
||
|
if [ -f "$CONFIG" ]; then
|
||
|
while read line; do
|
||
|
case $line in
|
||
|
\#*) ;;
|
||
|
*)
|
||
|
[ -z "$line" ] && continue
|
||
|
set $line
|
||
|
free_device $1
|
||
|
;;
|
||
|
esac
|
||
|
done < $CONFIG
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
if [ $MODE = "dasd" ]; then
|
||
|
# process the device list defined as option for the dasd module
|
||
|
DEVICES=$(modprobe --showconfig | grep "options[[:space:]]\+dasd_mod" | \
|
||
|
sed -e 's/.*[[:space:]]dasd=\([^[:space:]]*\).*/\1/' -e 's/([^)]*)//g' \
|
||
|
-e 's/nopav\|nofcx\|autodetect\|probeonly//g' -e 's/,,/,/g' -e 's/^,//' -e 's/,$//')
|
||
|
|
||
|
free_device $DEVICES
|
||
|
fi
|
||
|
|
||
|
if [ $MODE = "znet" ]; then
|
||
|
# process the config file
|
||
|
if [ -f "$CONFIG" ]; then
|
||
|
while read line; do
|
||
|
case $line in
|
||
|
\#*) ;;
|
||
|
*)
|
||
|
[ -z "$line" ] && continue
|
||
|
# grep 2 or 3 channels from beginning of each line
|
||
|
DEVICES=$(echo $line | egrep -i -o "^([0-9]\.[0-9]\.[a-f0-9]+,){1,2}([0-9]\.[0-9]\.[a-f0-9]+)")
|
||
|
free_device $DEVICES
|
||
|
;;
|
||
|
esac
|
||
|
done < $CONFIG
|
||
|
fi
|
||
|
# process channels from network interface configurations
|
||
|
for line in $(egrep -i -h "^[[:space:]]*SUBCHANNELS=['\"]?([0-9]\.[0-9]\.[a-f0-9]+,){1,2}([0-9]\.[0-9]\.[a-f0-9]+)['\"]?([[:space:]]+#|[[:space:]]*$)" /etc/sysconfig/network-scripts/ifcfg-* 2> /dev/null)
|
||
|
do
|
||
|
eval "$line"
|
||
|
free_device $SUBCHANNELS
|
||
|
done
|
||
|
fi
|
||
|
|
||
|
# wait until recently unblocked devices are ready
|
||
|
# at this point we know the content of ALL_DEVICES is syntacticly correct
|
||
|
IFS=","
|
||
|
set $ALL_DEVICES
|
||
|
while [ "$1" ]
|
||
|
do
|
||
|
DEV="$1"
|
||
|
IFS="."
|
||
|
|
||
|
# get the lower bound for range or get the single device
|
||
|
LOWER=${DEV%%-*}
|
||
|
read -a L <<< "$LOWER"
|
||
|
if [ ${#L[@]} -eq 1 ]; then
|
||
|
L[2]=${L[0]}
|
||
|
L[0]=0
|
||
|
L[1]=0
|
||
|
fi
|
||
|
|
||
|
# get the upper bound for range or get the single device
|
||
|
UPPER=${DEV##*-}
|
||
|
read -a U <<< "$UPPER"
|
||
|
if [ ${#U[@]} -eq 1 ]; then
|
||
|
U[2]=${U[0]}
|
||
|
U[0]=0
|
||
|
U[1]=0
|
||
|
fi
|
||
|
|
||
|
# iterate thru all devices
|
||
|
for (( i=0x${L[0]}; i<=0x${U[0]}; i++ )); do
|
||
|
for (( j=0x${L[1]}; j<=0x${U[1]}; j++ )); do
|
||
|
for (( k=0x${L[2]}; k<=0x${U[2]}; k++ )); do
|
||
|
wait_on_device "$(printf %x.%x.%04x $i $j $k)"
|
||
|
done
|
||
|
done
|
||
|
done
|
||
|
|
||
|
# go to the next device
|
||
|
shift
|
||
|
done
|