#!/bin/sh
#==============================================================================
# Copyright IBM Corp. 2003, 2006.
#
# lscss ($Revision: 1.9 $)
#
# Script to generate /proc/subchannels output for kernels beyond 2.4.
# (Designed to work with 2.4 as well.)
#
# Author(s): S. Bader <shbader@de.ibm.com>
#
# This file is part of s390-tools
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# s390-tools is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with s390-tools; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#==============================================================================
CMD=$(basename $0)

function PrintUsage() {
	cat <<-EOD
		Usage: $(basename $0): <options>

		<options>
		 	-s|--short
		 		Supress leading "0.0." when printing bus IDs.
		 	-t|--devtype <devtype>[/<model>][,...]
		 		Limit output to devices of the given device
		 		type (e.g. 3390).
		 	--version
		 		Show tools and command version.
	EOD
}

function PrintVersion()
{
	local TVER=$(echo '$Revision: 1.9 $'|awk '{print $2}')

	cat <<-EOD
	$CMD: version %S390_TOOLS_VERSION% ($TVER).
	Copyright IBM Corp. 2003, 2006.
	EOD
}

SHORTID=false
DEVTYPE=""
while [ $# -gt 0 ]; do
	case $1 in
		-h|--help)
			PrintUsage
			exit 1
			;;
		-s|--short)
			SHORTID=true;;
		-t|--devtype)
			DEVTYPE=$2
			shift
			;;
		--version)
			PrintVersion
			exit 0
			;;
		-*|--*)
			echo "$CMD: Invalid option $1" >&2
			echo "Try 'lscss --help' for more information." >&2
			exit 1
			;;
		*)
			echo "Invalid argument <$1>" >&2
			exit 1
			;;
	esac
	shift
done

function PrintList_SysFS() {
echo "Device   Subchan.  DevType CU Type Use  PIM PAM POM  CHPIDs"
echo "----------------------------------------------------------------------"
	find $1/bus/css/devices -exec find {}/ -type d \
		-mindepth 1 -maxdepth 1 \; 2>/dev/null |
	sort -t/ -k6 |
	awk -F/ '
		function Read(file) {
			value = ""
			getline value <file
			close(file)
			return value
		}
		BEGIN{
			SHORTID = ("'$SHORTID'" == "true") ? 1 : 0;
		}
		{
			DEVDIR=$0
			CHNDIR=$0
			sub(/\/[^/]*$/, "", CHNDIR)

			BUSID = $NF
			CHNID = $(NF-1)

			if (SHORTID) {
				sub(/.+[\.:]/, "", BUSID)
				sub(/.+[\.:]/, "", CHNID)
			}

			if (CHNID == "" || BUSID == "")
				next

			DEVTYPE   = Read(DEVDIR "/devtype")
			if (DEVTYPE == "n/a")
				DEVTYPE = "0000/00"
			CUTYPE    = Read(DEVDIR "/cutype")
			ONLINE    = Read(DEVDIR "/online")
			if (ONLINE == "yes" || ONLINE == "1")
				ONLINE = "yes"
			else
				ONLINE = ""
			split(Read(CHNDIR "/pimpampom"), A, " ")
			PIMPAMPOM = A[1] "  " A[2] "  " A[3]

			split(Read(CHNDIR "/chpids"), A, " ")
			CHPIDS    = A[1] A[2] A[3] A[4] " " A[5] A[6] A[7] A[8]

			printf("%-8.8s %-8.8s  %-7.7s %-7.7s ",
				toupper(BUSID),
				toupper(CHNID),
				toupper(DEVTYPE),
				toupper(CUTYPE))
			printf("%3.3s  %s   %s\n",
				ONLINE,
				toupper(PIMPAMPOM),
				toupper(CHPIDS))
		}
	'
}

SYSFS=true
case $(uname -r|cut -d. -f1-2) in
	2.1|2.2|2.3|2.4)
		SYSFS=false
		;;
	*)
		if [ "$(cat /proc/filesystems|grep sysfs)" = "" ]; then
			SYSFS=false
		fi
		SYSFSDIR=$(cat /proc/mounts|awk '$3=="sysfs"{print $2; exit}')
		if [ "$SYSFSDIR" = "" ]; then
			SYSFS=false
		fi
		;;
esac

if $SYSFS; then
	PrintList_SysFS $SYSFSDIR
else
	if [ ! -r /proc/subchannels ]; then
		echo "ERROR: neither proc nor sysfs interface found!" >&2
		exit 1
	fi
	cat /proc/subchannels
fi | (
	if [ "$DEVTYPE" = "" ]; then
		cat -
	else
		awk '
			BEGIN{
				split(toupper("'$DEVTYPE'"), A, ",")
				for(i=1; i in A; i++) {
					list[A[i]] = 1
				}
			}
			FNR < 3{
				print
				next
			}
			FNR > 2{
				split($3, A, "/")
				if($3 in list || A[1] in list)
					print
			}
		'
	fi
)

exit 0

