#!/bin/bash # # lszfcp - Tool to display information about zfcp devices (adapters/ports/units) # # Copyright IBM Corp. 2006, 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. # 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 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 < 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" ]; then read WWPN < $FC_PORT_PATH/port_name else continue fi [ $WWPN != ${PAR_WWPN:-$WWPN} ] && continue ADAPTER_PORT_PATH=`ls -d \ $SYSFS/devices/css0/*/*/$WWPN/../host[0-9]*/$PORT |\ awk -F "/../host" '{ print $1 }'` ADAPTER=`basename \`dirname $ADAPTER_PORT_PATH\`` [ $ADAPTER != ${PAR_BUSID:-$ADAPTER} ] && continue if [ $VERBOSITY -eq 0 ]; then echo "$ADAPTER/$WWPN $PORT" else echo $ADAPTER_PORT_PATH 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#*:}" # 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: --longoptions \ attributes,help,version,hosts,ports,devices,verbose,busid:,wwpn:,lun:,sysfs: \ -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;; -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