mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
This commit is based on the s390-tools-1.39.0 version. Changes on top of s390-tools-1.39.0: - Add MIT license to all source files - Add LICENSE file - Transform REAMDE to README.md (markdown) - Add AUTHORS.md file - Add CONTRIBUTING.md file - Move changelog from README to CHANGELOG.md file Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
470 lines
8.9 KiB
Bash
Executable File
470 lines
8.9 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# chccwdev - Tool to change attributes of a ccw device
|
|
#
|
|
# Copyright IBM Corp. 2003, 2017
|
|
#
|
|
# s390-tools is free software; you can redistribute it and/or modify
|
|
# it under the terms of the MIT license. See LICENSE for details.
|
|
#
|
|
|
|
CMD=$(basename $0)
|
|
MAX_RETRIES=5
|
|
CIO_SETTLE="/proc/cio_settle"
|
|
ONLINEATTR="online"
|
|
SYSPATH=NULL
|
|
|
|
if [ "$(cat /proc/filesystems|grep sysfs)" = "" ]; then
|
|
echo "ERROR: $CMD requires sysfs support!" >&2
|
|
exit 1
|
|
fi
|
|
SYSFSDIR=$(cat /proc/mounts|awk '$3=="sysfs"{print $2; exit}')
|
|
if [ "$SYSFSDIR" = "" ]; then
|
|
echo "ERROR: $CMD requires sysfs filesystem mounted!" >&2
|
|
fi
|
|
|
|
function PrintUsage() {
|
|
cat <<-EOD
|
|
Usage: $(basename $0) [<options>] <devices>
|
|
|
|
<options>
|
|
-a|--attribute <name>=<value>
|
|
-e|--online
|
|
Tries to set the given device online.
|
|
-f|--forceonline
|
|
Tries to force a device online if the device
|
|
driver supports this.
|
|
-d|--offline
|
|
Tries to set the given device offline.
|
|
-s|--safeoffline
|
|
Tries to set the given device offline waiting for all outstanding I/O. May block forever.
|
|
-v|--version
|
|
Show tools and command version.
|
|
|
|
<devices>
|
|
<bus ID>[-<busid>][,<busid>[-<busid>]] ...
|
|
EOD
|
|
}
|
|
|
|
function PrintVersion()
|
|
{
|
|
cat <<-EOD
|
|
$CMD: version %S390_TOOLS_VERSION%
|
|
Copyright IBM Corp. 2003, 2017
|
|
EOD
|
|
}
|
|
|
|
function CheckOnlineArg()
|
|
{
|
|
if [ "$ONLINE" = $1 ] ;then
|
|
echo "$CMD: Incompatible argument list." >&2
|
|
echo "Try '$CMD --help' for more information." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
function SetAttribute()
|
|
{
|
|
local NAME="$1"
|
|
local VAL="$2"
|
|
local CNT=0
|
|
|
|
if [ "$VAL" = "" ]; then
|
|
echo "WARNING: Attribute[$NAME] has no value and will" \
|
|
"be ignored!" >&2
|
|
return
|
|
fi
|
|
if [ "$NAME" = "online" ]; then
|
|
if [ "$VAL" = "force" ]; then
|
|
CheckOnlineArg 0
|
|
ONLINE=1
|
|
FORCE="force"
|
|
elif [ "$VAL" = "1" ]; then
|
|
CheckOnlineArg 0
|
|
ONLINE=1
|
|
else
|
|
CheckOnlineArg 1
|
|
ONLINE=0
|
|
fi
|
|
ACTIONSET=true
|
|
return
|
|
elif [ "$NAME" = "safe_offline" ]; then
|
|
CheckOnlineArg 1
|
|
ONLINE=0
|
|
ACTIONSET=true
|
|
ONLINEATTR="safe_offline"
|
|
return
|
|
fi
|
|
|
|
while [ $CNT -lt $NUMATTR ]; do
|
|
if [ "${ATTRNAME[$CNT]}" = "$NAME" ]; then
|
|
break
|
|
fi
|
|
let "CNT++"
|
|
done
|
|
|
|
ATTRNAME[$CNT]="$NAME"
|
|
ATTRVAL[$CNT]="$VAL"
|
|
|
|
if [ $CNT = $NUMATTR ]; then
|
|
let "NUMATTR++"
|
|
ACTIONSET=true
|
|
fi
|
|
}
|
|
|
|
FORCE=""
|
|
ONLINE=""
|
|
NUMATTR=0
|
|
ACTIONSET=false
|
|
while [ $# -gt 0 ]; do
|
|
case $1 in
|
|
-a|--attribute)
|
|
SetAttribute "$(echo $2|cut -d= -f1)" \
|
|
"$(echo $2|cut -d= -f2)"
|
|
shift
|
|
;;
|
|
-a*)
|
|
SetAttribute "$(echo $1|cut -c3-|cut -d= -f1)" \
|
|
"$(echo $1|cut -c3-|cut -d= -f2)"
|
|
;;
|
|
-h|--help)
|
|
PrintUsage
|
|
exit 0
|
|
;;
|
|
-e|--online)
|
|
SetAttribute "online" 1
|
|
;;
|
|
-f|--forceonline)
|
|
SetAttribute "online" "force"
|
|
;;
|
|
-d|--offline)
|
|
SetAttribute "online" 0
|
|
;;
|
|
-s|--safeoffline)
|
|
SetAttribute "safe_offline" 0
|
|
;;
|
|
-v|--version)
|
|
PrintVersion
|
|
exit 0
|
|
;;
|
|
-*)
|
|
echo "$CMD: Invalid option $1" >&2
|
|
echo "Try '$CMD --help' for more" \
|
|
"information." >&2
|
|
exit 1
|
|
;;
|
|
*)
|
|
if [ "$BUSIDLIST" = "" ]; then
|
|
BUSIDLIST="$1"
|
|
else
|
|
BUSIDLIST="$BUSIDLIST,$1"
|
|
fi
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [ -w $CIO_SETTLE ] ; then
|
|
echo 1 > $CIO_SETTLE
|
|
fi
|
|
|
|
#
|
|
# Parse the BUSIDLIST and expand the ranges and short IDs.
|
|
#
|
|
BUSIDLIST=$(
|
|
echo "$BUSIDLIST" | awk '
|
|
function hex2dec(hex, d, h, i) {
|
|
d = 0
|
|
for (i = 1; i <= length(hex); i++) {
|
|
h = index("0123456789abcdef", tolower(substr(hex,i,1)))
|
|
d = (d * 16) + (h - 1)
|
|
}
|
|
return d
|
|
}
|
|
function dec2hex(dec, d, h) {
|
|
h = ""
|
|
for(d = dec; d > 0; d = int(d / 16)) {
|
|
h = substr("0123456789abcdef", (d % 16) + 1, 1) h
|
|
}
|
|
while (length(h) < 4)
|
|
h = "0" h
|
|
|
|
return h
|
|
}
|
|
function BusIDValid(id, css, dsn) {
|
|
split(id, part, ".")
|
|
css = int(part[1])
|
|
if (css < 0 || css > 255)
|
|
return 0
|
|
dsn = int(part[2])
|
|
if (dsn < 0 || dsn > 255)
|
|
return 0
|
|
if (length(part[3]) > 4)
|
|
return 0
|
|
if (match(part[3], /^[a-f0-9]+$/) == 0)
|
|
return 0
|
|
return 1
|
|
}
|
|
function ExpandBusID(id) {
|
|
if (length(id) < 1) {
|
|
print "\"\" is not a valid bus ID." >err
|
|
return ""
|
|
}
|
|
split(id, part, ".")
|
|
if (3 in part) {
|
|
css = part[1]
|
|
dsn = part[2]
|
|
did = part[3]
|
|
} else if (2 in part) {
|
|
css = 0
|
|
dsn = part[1]
|
|
did = part[2]
|
|
} else {
|
|
css = 0
|
|
dsn = 0
|
|
did = part[1]
|
|
}
|
|
while (length(did) < 4)
|
|
did = "0" did
|
|
|
|
busid = css "." dsn "." did
|
|
if (! BusIDValid(busid)) {
|
|
print busid " is not a valid bus ID." >err
|
|
return ""
|
|
}
|
|
return busid
|
|
}
|
|
function ExpandRange(range, i) {
|
|
split(range, id, "-")
|
|
from = ExpandBusID(id[1])
|
|
if (from == "")
|
|
return -1
|
|
|
|
to = ExpandBusID(id[2])
|
|
if (to == "")
|
|
return -1
|
|
|
|
split(from, parts1, ".")
|
|
split(to, parts2, ".")
|
|
|
|
if (parts1[1] != parts2[1] || parts1[2] != parts2[2]) {
|
|
print "Invalid range (" from "-" to ")" >err
|
|
return -1
|
|
}
|
|
from = hex2dec(parts1[3])
|
|
to = hex2dec(parts2[3])
|
|
if (from > to) {
|
|
print "Invalid range order" >err
|
|
return -1
|
|
}
|
|
found = 0
|
|
for (i = from; i <= to; i++) {
|
|
# Expand ranges only to valid entries.
|
|
busid = parts1[1] "." parts1[2] "." dec2hex(i)
|
|
filen = SYSFSBASE busid "/devtype"
|
|
if ((getline x <filen) > 0) {
|
|
found = 1
|
|
print busid
|
|
}
|
|
close(filen)
|
|
}
|
|
if (!found) {
|
|
print "No Device in range (" parts1[1] "." parts1[2] \
|
|
"." parts1[3] "-" parts2[1] "." parts2[2] \
|
|
"." parts2[3] ") found" >err
|
|
return -1
|
|
}
|
|
}
|
|
BEGIN{
|
|
SYSFSBASE = "'$SYSFSDIR'/bus/ccw/devices/"
|
|
err = "/dev/stderr"
|
|
}
|
|
{
|
|
line = tolower($0)
|
|
gsub(/[ \t]+/, "", line)
|
|
|
|
split(line, range, ",")
|
|
for (i=1; i in range; i++) {
|
|
if (match(range[i], /-/)) {
|
|
if (ExpandRange(range[i]) < 0)
|
|
exit 1
|
|
} else {
|
|
busid = ExpandBusID(range[i])
|
|
if (busid == "")
|
|
exit 1
|
|
print busid
|
|
}
|
|
}
|
|
}'
|
|
)
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "ERROR: Evaluation of bus IDs failed!" >&2
|
|
echo ""
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$BUSIDLIST" = "" ]; then
|
|
PrintUsage
|
|
echo ""
|
|
echo "No bus ID given!" >&2
|
|
exit 1
|
|
fi
|
|
if ! $ACTIONSET; then
|
|
PrintUsage
|
|
echo ""
|
|
echo "No action specified. Please use a valid action switch." >&2
|
|
exit 1
|
|
fi
|
|
|
|
function IsOnline() {
|
|
local ONLINE=$(cat $1/online 2>/dev/null)
|
|
if [ -z $ONLINE ]; then
|
|
if [ $2 -eq 0 ]; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
fi
|
|
if [ $ONLINE -eq $2 ]; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
function StoreAttribute()
|
|
{
|
|
local SYSPATH="$1"
|
|
local BUSID="$(basename "$1")"
|
|
local NAME="${ATTRNAME[$2]}"
|
|
local VALUE="${ATTRVAL[$2]}"
|
|
local CHECK="$3"
|
|
|
|
if [ ! -f "$SYSPATH/$NAME" ]; then
|
|
return 1
|
|
fi
|
|
if [ "$VALUE" = "" ]; then
|
|
return 0
|
|
fi
|
|
if [ "$(cat $SYSPATH/$NAME)" = "$VALUE" ]; then
|
|
echo "The $NAME attribute of $BUSID already is $VALUE"
|
|
ATTRVAL[$2]=""
|
|
return 0
|
|
fi
|
|
|
|
echo "Setting $NAME attribute of $BUSID to $VALUE"
|
|
echo "$VALUE" >"$SYSPATH/$NAME" 2>/dev/null
|
|
if [ $? -eq 0 ]; then
|
|
ATTRVAL[$2]=""
|
|
return 0
|
|
fi
|
|
|
|
if [ $CHECK ]; then
|
|
echo "ERROR: Failed to set $NAME attribute of $BUSID!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
function PrintError()
|
|
{
|
|
read ERROR
|
|
if [ -n "$ERROR" ] ;then
|
|
echo "Failed (${ERROR##*: })" >&2
|
|
if [ ! -e $SYSPATH/driver ]; then
|
|
read CUTYPE 2>/dev/null < $SYSPATH/cutype
|
|
read DEVTYPE 2>/dev/null < $SYSPATH/devtype
|
|
if [ $? -ne 0 ] ;then
|
|
exit 1
|
|
fi
|
|
if [[ $DEVTYPE == "n/a" ]] ;then
|
|
DEVTYPE="0000/00"
|
|
fi
|
|
echo "Note: No driver is attached to this device" \
|
|
"(DevType:$DEVTYPE CU Type:$CUTYPE)." >&2
|
|
fi
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
SAVEDATTRS=("${ATTRVAL[@]}")
|
|
for BUSID in $BUSIDLIST; do
|
|
SYSPATH=$SYSFSDIR/bus/ccw/devices/$BUSID
|
|
if [ ! -r $SYSPATH ]; then
|
|
echo "Device $BUSID not found"
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$ONLINE" != "" ]; then
|
|
|
|
CNT=0
|
|
while [ $CNT -lt $NUMATTR ]; do
|
|
StoreAttribute "$SYSPATH" $CNT
|
|
if [ $? -ne 0 ]; then
|
|
if IsOnline $SYSPATH 1; then
|
|
echo "ERROR: Device[$BUSID] has no attribute" \
|
|
"${ATTRNAME[$CNT]}!" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
let "CNT++"
|
|
done
|
|
|
|
if IsOnline $SYSPATH $ONLINE; then
|
|
if [ "$ONLINE" -eq 1 ]; then
|
|
echo "WARNING: Device[$BUSID] is already " \
|
|
"online" >&2
|
|
else
|
|
echo "Device is already offline" >&2
|
|
fi
|
|
else
|
|
if [ "$ONLINE" -eq 1 ]; then
|
|
echo "Setting device $BUSID online"
|
|
else
|
|
echo "Setting device $BUSID offline"
|
|
fi
|
|
if [ ! -e $SYSPATH/$ONLINEATTR ]; then
|
|
echo "$ONLINEATTR attribute not available for" \
|
|
" device[$BUSID]" >&2
|
|
exit 1
|
|
fi
|
|
if [ "$FORCE" != "" ]; then
|
|
echo $FORCE 2>&1 >$SYSPATH/$ONLINEATTR | PrintError
|
|
else
|
|
echo $ONLINE 2>&1 > $SYSPATH/$ONLINEATTR | PrintError
|
|
fi
|
|
|
|
#
|
|
# Workaround for bad drivers which report success but
|
|
# silently fail or have an asynchronous online processing.
|
|
#
|
|
RETRIES=0
|
|
while ! IsOnline $SYSPATH $ONLINE; do
|
|
if [ $RETRIES -eq $MAX_RETRIES ]; then
|
|
echo "Failed" >&2
|
|
exit 1
|
|
fi
|
|
sleep 0.5
|
|
let "RETRIES++"
|
|
done
|
|
fi
|
|
fi
|
|
|
|
CNT=0
|
|
while [ $CNT -lt $NUMATTR ]; do
|
|
StoreAttribute "$SYSPATH" $CNT "CHECK"
|
|
if [ $? -ne 0 ]; then
|
|
echo "ERROR: Device[$BUSID] has no attribute" \
|
|
"${ATTRNAME[$CNT]}!" >&2
|
|
exit 1
|
|
fi
|
|
let "CNT++"
|
|
done
|
|
echo "Done"
|
|
|
|
unset ATTRVAL
|
|
ATTRVAL=("${SAVEDATTRS[@]}")
|
|
done
|
|
|
|
exit 0
|