mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
b0dcc61ed5
s390-tools-1.8.1 introduced a regression skipping all fc_rports with port_state != Online. While we need to skip some output parts for a zfcp_port which does not exist anymore due to port_remove, there are other cases with port_state != Online for which we should not skip an fc_rport. Such as port_state "Blocked" after a cable pull beyond host-adjacent switch or port_state "Not Present" after dev_loss_tmo ran out. This way the user can see the previously discovered ports, even if they might currently not be usable for traffic. Non-good ports are marked in the short output with suffix "NotOnline". In order not to break scripting or expectations around lszfcp, make the new feature depend on the extended output command line option. Sysfs path globbing does not work for a removed zfcp_port to obtain the FCP device bus-ID. Instead, properly walk the sysfs. Examples with a removed zfcp_port: $ lszfcp -Pe 0.0.50c0/0x500507680b2481fa rport-6:0-2 $ lszfcp -PeV - (NoMoreZfcpPort:0.0.50c0/0x500507680b2481fa) /sys/class/fc_remote_ports/rport-6:0-2 Examples with an existing zfcp_port but pulled fibre: $ lszfcp -Pe 0.0.3c40/0x500507680b2181fb rport-7:0-4 $ lszfcp -PeV /sys/devices/css0/defunct/0.0.3c40/0x500507680b2181fb /sys/class/fc_remote_ports/rport-7:0-4 Signed-off-by: Steffen Maier <maier@linux.ibm.com> Reviewed-by: Jens Remus <jremus@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
385 lines
9.0 KiB
Bash
Executable File
385 lines
9.0 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# lszfcp - Tool to display information about zfcp devices (adapters/ports/units)
|
|
#
|
|
# Copyright IBM Corp. 2006, 2019
|
|
#
|
|
# s390-tools is free software; you can redistribute it and/or modify
|
|
# it under the terms of the MIT license. See LICENSE for details.
|
|
#
|
|
|
|
SCRIPTNAME='lszfcp'
|
|
SYSFS=`cat /proc/mounts | grep -m1 sysfs | awk '{ print $2 }'`
|
|
FC_CLASS=false
|
|
|
|
# Command line parameters
|
|
VERBOSITY=0
|
|
SHOW_HOSTS=0
|
|
SHOW_PORTS=0
|
|
SHOW_DEVICES=0
|
|
SHOW_ATTRIBUTES=false
|
|
SHOW_EXTENDED=false
|
|
unset PAR_BUSID PAR_WWPN PAR_LUN
|
|
|
|
|
|
##############################################################################
|
|
|
|
check_sysfs()
|
|
{
|
|
if [ -z $SYSFS -o ! -d $SYSFS -o ! -r $SYSFS ]; then
|
|
echo "Error: sysfs not available."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_zfcp_support()
|
|
{
|
|
if [ ! -e $SYSFS/bus/ccw/drivers/zfcp ]; then
|
|
echo "Error: No zfcp support available."
|
|
echo "Load the zfcp module or compile"
|
|
echo "the kernel with zfcp support."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_fcp_devs()
|
|
{
|
|
if $FC_CLASS; then
|
|
ignore=`ls $SYSFS/class/fc_host/host* 2>&1`
|
|
else
|
|
ignore=`ls $SYSFS/devices/css0/[0-9]*/[0-9]*/host[0-9]* 2>&1`
|
|
fi
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: No fcp devices found."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_fc_class()
|
|
{
|
|
if [ -d "$SYSFS/class/fc_host" ]; then
|
|
FC_CLASS=true
|
|
fi
|
|
}
|
|
|
|
print_version()
|
|
{
|
|
cat <<EOF
|
|
$SCRIPTNAME: version %S390_TOOLS_VERSION%
|
|
Copyright IBM Corp. 2006, 2019
|
|
EOF
|
|
}
|
|
|
|
print_help()
|
|
{
|
|
cat <<EOF
|
|
Usage: $SCRIPTNAME [OPTIONS]
|
|
|
|
Provide information contained in sysfs about zfcp adapters, ports and
|
|
units that are online.
|
|
|
|
Mandatory arguments to long options are mandatory for short options too.
|
|
|
|
OPTIONS:
|
|
-H, --hosts show host information (default)
|
|
-P, --ports show remote port information
|
|
-D, --devices show SCSI device information
|
|
-b, --busid=BUSID select specific busid
|
|
-p, --wwpn=WWPN select specific port name
|
|
-l, --lun=LUN select specific LUN
|
|
-a, --attributes show all attributes
|
|
-V, --verbose show sysfs paths of associated class
|
|
and bus devices
|
|
-e, --extended extended output format
|
|
-s, --sysfs=PATH use path as sysfs (for dbginfo archives)
|
|
-h, --help print this help
|
|
-v, --version print version information
|
|
|
|
EXAMPLE:
|
|
List for all zfcp adapters, ports and units the names of their
|
|
associated SCSI hosts, FC remote ports and SCSI devices.
|
|
|
|
#> lszfcp -P -H -D
|
|
0.0.3d0c host0
|
|
0.0.3d0c/0x500507630300c562 rport-0:0-0
|
|
0.0.3d0c/0x500507630300c562/0x4010403300000000 0:0:0:0
|
|
|
|
The default is to list bus_ids of all zfcp adapters and corresponding
|
|
SCSI host names (equals "lszfcp -H").
|
|
EOF
|
|
}
|
|
|
|
|
|
show_attributes()
|
|
{
|
|
if [ -z $1 -o ! -d $1 -o ! -r $1 ]; then
|
|
return 1
|
|
fi
|
|
|
|
for FILE in `ls $1`; do
|
|
read 2>/dev/null CONTENT < $1/$FILE
|
|
|
|
# Read fails for directories and
|
|
# files with permissions 0200.
|
|
if [ $? -ne 0 ]; then
|
|
continue
|
|
fi
|
|
|
|
printf " %-19s = \"%s\"\n" "$FILE" "$CONTENT"
|
|
done
|
|
}
|
|
|
|
|
|
show_hosts()
|
|
{
|
|
HOST_LIST=`ls -dX $SYSFS/devices/css0/[0-9]*/[0-9]*/host[0-9]*`
|
|
|
|
for HOST_PATH in $HOST_LIST; do
|
|
SCSI_HOST=`basename $HOST_PATH`
|
|
ADAPTER_PATH=`dirname $HOST_PATH`
|
|
ADAPTER=`basename $ADAPTER_PATH`
|
|
|
|
[ $ADAPTER != ${PAR_BUSID:-$ADAPTER} ] && continue
|
|
|
|
if [ $VERBOSITY -eq 0 ]; then
|
|
echo $ADAPTER $SCSI_HOST
|
|
else
|
|
echo $ADAPTER_PATH
|
|
$FC_CLASS && echo "$SYSFS/class/fc_host/$SCSI_HOST"
|
|
echo "$SYSFS/class/scsi_host/$SCSI_HOST"
|
|
fi
|
|
|
|
if $SHOW_ATTRIBUTES; then
|
|
echo 'Bus = "ccw"'
|
|
show_attributes $ADAPTER_PATH
|
|
|
|
if $FC_CLASS; then
|
|
echo 'Class = "fc_host"'
|
|
show_attributes \
|
|
"$SYSFS/class/fc_host/$SCSI_HOST"
|
|
fi
|
|
|
|
echo 'Class = "scsi_host"'
|
|
show_attributes "$SYSFS/class/scsi_host/$SCSI_HOST"
|
|
echo
|
|
fi
|
|
done
|
|
}
|
|
|
|
|
|
show_ports()
|
|
{
|
|
# Without fc_remote_class there is far less information to display.
|
|
if ! $FC_CLASS; then
|
|
PORT_LIST=`ls -d $SYSFS/devices/css0/*/*/0x*`
|
|
|
|
for PORT_PATH in $PORT_LIST; do
|
|
WWPN=`basename $PORT_PATH`
|
|
ADAPTER=`basename \`dirname $PORT_PATH\``
|
|
|
|
[ $WWPN != ${PAR_WWPN:-$WWPN} ] && continue
|
|
[ $ADAPTER != ${PAR_BUSID:-$ADAPTER} ] && continue
|
|
|
|
if [ $VERBOSITY -eq 0 ]; then
|
|
echo "$ADAPTER/$WWPN"
|
|
else
|
|
echo $PORT_PATH
|
|
fi
|
|
done
|
|
return
|
|
fi
|
|
|
|
|
|
if [ -e $SYSFS/class/fc_remote_ports/ ]; then
|
|
PORT_LIST=`ls -d $SYSFS/class/fc_remote_ports/* 2>/dev/null`
|
|
fi;
|
|
|
|
for FC_PORT_PATH in $PORT_LIST; do
|
|
PORT=`basename $FC_PORT_PATH`
|
|
read PORT_STATE < $FC_PORT_PATH/port_state
|
|
if [ "$PORT_STATE" == "Online" ] || $SHOW_EXTENDED; then
|
|
read WWPN < $FC_PORT_PATH/port_name
|
|
else
|
|
continue
|
|
fi
|
|
|
|
[ $WWPN != ${PAR_WWPN:-$WWPN} ] && continue
|
|
|
|
local sysreal=$(readlink -e "$FC_PORT_PATH")
|
|
local ADAPTER=""
|
|
while [ -n "$sysreal" ]; do
|
|
# ascend to parent: strip last path part
|
|
sysreal=${sysreal%/*}
|
|
[ -h $sysreal/subsystem ] || continue
|
|
local subsystem=$(readlink -e $sysreal/subsystem)
|
|
if [ "${subsystem##*/}" = "ccw" ]; then
|
|
ADAPTER=${sysreal##*/}
|
|
break
|
|
fi
|
|
done
|
|
[ -z "$ADAPTER" ] && continue # skip not zfcp-attached ones
|
|
if [ -d $SYSFS/devices/css[0-9]*/[0-9d]*/[0-9]*/$WWPN/../host[0-9]*/$PORT ];
|
|
then
|
|
ADAPTER_PORT_PATH=$SYSFS/devices/css[0-9]*/[0-9d]*/$ADAPTER/$WWPN
|
|
else
|
|
ADAPTER_PORT_PATH="-"
|
|
fi
|
|
|
|
[ $ADAPTER != ${PAR_BUSID:-$ADAPTER} ] && continue
|
|
|
|
if [ $VERBOSITY -eq 0 ]; then
|
|
echo "$ADAPTER/$WWPN $PORT"
|
|
else
|
|
if [ "$ADAPTER_PORT_PATH" != "-" ]; then
|
|
echo $ADAPTER_PORT_PATH
|
|
else
|
|
echo "- (NoMoreZfcpPort:$ADAPTER/$WWPN)"
|
|
fi
|
|
echo $FC_PORT_PATH
|
|
fi
|
|
|
|
if $SHOW_ATTRIBUTES; then
|
|
echo 'Class = "fc_remote_ports"'
|
|
show_attributes "$FC_PORT_PATH"
|
|
echo
|
|
fi
|
|
done
|
|
}
|
|
|
|
|
|
show_devices()
|
|
{
|
|
# Differentiate old and new sysfs layout
|
|
if $FC_CLASS; then
|
|
SCSI_DEVICE_LIST=`ls -d \
|
|
$SYSFS/bus/ccw/drivers/zfcp/*/host*/rport*/target*/*/ \
|
|
2>/dev/null |grep -P '\d+:\d+:\d+:\d+'`
|
|
else
|
|
SCSI_DEVICE_LIST=`ls -d $SYSFS/devices/css0/*/*/host[0-9]*/*/`
|
|
fi
|
|
|
|
if [ -z "$SCSI_DEVICE_LIST" ]; then
|
|
echo "Error: No fcp devices found."
|
|
fi
|
|
|
|
for SCSI_DEVICE_PATH in $SCSI_DEVICE_LIST; do
|
|
read ADAPTER < $SCSI_DEVICE_PATH/hba_id
|
|
read WWPN < $SCSI_DEVICE_PATH/wwpn
|
|
read LUN < $SCSI_DEVICE_PATH/fcp_lun
|
|
|
|
[ $LUN != ${PAR_LUN:-$LUN} ] && continue
|
|
[ $WWPN != ${PAR_WWPN:-$WWPN} ] && continue
|
|
[ $ADAPTER != ${PAR_BUSID:-$ADAPTER} ] && continue
|
|
|
|
if [ $VERBOSITY -eq 0 ]; then
|
|
echo "$ADAPTER/$WWPN/$LUN `basename $SCSI_DEVICE_PATH`"
|
|
else
|
|
echo "`ls -d $SYSFS/devices/css0/*/$ADAPTER`/$WWPN/$LUN"
|
|
echo ${SCSI_DEVICE_PATH%*/} # without trailing slash
|
|
|
|
# On live systems, there are links to the block and
|
|
# generic devices. In a dbginfo archive, these links
|
|
# are not present. Therefore, fall back to reading
|
|
# the runtime.out log file.
|
|
if [ `ls $SCSI_DEVICE_PATH | grep -c block:` -eq 1 ]
|
|
then
|
|
BLOCK_DEV=`ls $SCSI_DEVICE_PATH | grep block:`
|
|
GEN_DEV=`ls $SCSI_DEVICE_PATH |\
|
|
grep scsi_generic:`
|
|
echo -n "$SYSFS/block/${BLOCK_DEV#*:} "
|
|
echo "$SYSFS/class/scsi_generic/${GEN_DEV#*:}"
|
|
|
|
elif [ -d $SCSI_DEVICE_PATH/block ] && $SHOW_EXTENDED
|
|
then
|
|
# case without CONFIG_SYSFS_DEPRECATED
|
|
BLOCK_DEV=$(echo $SCSI_DEVICE_PATH/block/*)
|
|
BLOCK_DEV=${BLOCK_DEV##*/}
|
|
echo -n "$SYSFS/block/$BLOCK_DEV "
|
|
local SGPATH=$SCSI_DEVICE_PATH/scsi_generic
|
|
if [ -d $SGPATH ]; then
|
|
GEN_DEV=$(echo $SGPATH/*)
|
|
GEN_DEV=${GEN_DEV##*/}
|
|
echo "$SYSFS/class/scsi_generic/$GEN_DEV"
|
|
else
|
|
echo "-"
|
|
fi
|
|
|
|
# FIXME Find a way to assign the generic devices.
|
|
elif [ -r $SYSFS/../runtime.out ]; then
|
|
SCSI_DEV=`basename $SCSI_DEVICE_PATH`
|
|
echo "$SYSFS/block/"`grep -r "\[$SCSI_DEV\]"\
|
|
$SYSFS/../runtime.out |\
|
|
awk -F "/dev/" '{print $2}'`
|
|
fi
|
|
fi
|
|
|
|
if $SHOW_ATTRIBUTES; then
|
|
echo 'Class = "scsi_device"'
|
|
show_attributes "$SCSI_DEVICE_PATH"
|
|
echo
|
|
fi
|
|
done
|
|
}
|
|
|
|
|
|
##############################################################################
|
|
|
|
ARGS=`getopt --options ahvHPDVb:p:l:s:e --longoptions \
|
|
attributes,help,version,hosts,ports,devices,verbose,busid:,wwpn:,lun:,sysfs:,extended \
|
|
-n "$SCRIPTNAME" -- "$@"`
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo
|
|
print_help
|
|
exit
|
|
fi
|
|
|
|
eval set -- "$ARGS"
|
|
|
|
for ARG; do
|
|
case "$ARG" in
|
|
-a|--attributes) SHOW_ATTRIBUTES=true; shift 1;;
|
|
-e|--extended) SHOW_EXTENDED=true; shift 1;;
|
|
-b|--busid) PAR_BUSID=$2; shift 2;;
|
|
-h|--help) print_help; exit 0;;
|
|
-l|--lun) PAR_LUN=$2; shift 2;;
|
|
-p|--wwpn) PAR_WWPN=$2; shift 2;;
|
|
-v|--version) print_version; exit 0;;
|
|
-H|--hosts) SHOW_HOSTS=1; shift 1;;
|
|
-D|--devices) SHOW_DEVICES=1; shift 1;;
|
|
-P|--ports) SHOW_PORTS=1; shift 1;;
|
|
-V|--verbose) VERBOSITY=1; shift 1;;
|
|
-s|--sysfs) SYSFS=$2; shift 2;;
|
|
--) shift; break;;
|
|
esac
|
|
done
|
|
|
|
check_sysfs
|
|
check_zfcp_support
|
|
check_fc_class
|
|
check_fcp_devs
|
|
|
|
default=1
|
|
if [ $SHOW_HOSTS -eq 1 ]; then
|
|
default=0; show_hosts
|
|
elif [ $SHOW_PORTS -eq 0 -a $SHOW_DEVICES -eq 0 -a -n "$PAR_BUSID" ]; then
|
|
default=0; show_hosts
|
|
fi
|
|
|
|
if [ $SHOW_PORTS -eq 1 ]; then
|
|
default=0; show_ports
|
|
elif [ $SHOW_HOSTS -eq 0 -a $SHOW_DEVICES -eq 0 -a -n "$PAR_WWPN" ]; then
|
|
default=0; show_ports
|
|
fi
|
|
|
|
if [ $SHOW_DEVICES -eq 1 ]; then
|
|
default=0; show_devices
|
|
elif [ $SHOW_HOSTS -eq 0 -a $SHOW_PORTS -eq 0 -a -n "$PAR_LUN" ]; then
|
|
default=0; show_devices
|
|
fi
|
|
|
|
if [ $default == 1 ]; then
|
|
show_hosts
|
|
fi
|