#!/bin/bash

# scsi-map - show how SCSI devices are configured by the system
# Copyright (C) 2011  Dennis Leeuw

# This program 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 3 of the License, or
# (at your option) any later version.
# This program 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.

# A copy of the GNU General Public Licens can be found at:
# <http://www.gnu.org/licenses/>.


function get_kdevice() {
	local my_dev=$1
	local out=""

	# Get device
	if [ -d /sys/block/${my_dev} ]
		then
		my_out=`echo /sys/block/${my_dev}/device/scsi_disk* 2>/dev/null`
		my_out=${my_out#*scsi_disk:}
		echo ${my_out#*scsi_disk\*}
		return 0
		fi

	return 1
}

function get_bus_id() {
	# Get busID
	local tmp=""
	local my_dev=$1
	local my_request=$2
	local my_busid=`ls -l /dev/disk/by-path/* | grep ${my_dev}$`
	my_busid=${my_busid#*by-path/}
	my_busid=${my_busid%% *}

	# busid = bus-device-protocol-address-part*
	case $my_request in
		bus)
			echo ${my_busid} | cut -d- -f1
			return 0
		;;
		device)
			echo ${my_busid} | cut -d- -f2
			return 0
		;;
		protocol)
			echo ${my_busid} | cut -d- -f3
			return 0
		;;
		address)
			
			local my_address=`echo ${my_busid} | cut -d- -f4-`
			if [ "${my_address}" = "" ] && [ -L /sys/block/${my_dev}/device ]
				then
				my_address=`ls -l /sys/block/${my_dev}/device`
				my_address=${my_address##*/}
				fi
			echo $my_address
			return 0
		;;
	esac
}

function get_dev_holders() {
	local sys_path=`find /sys -name $1 | grep -vE "slaves|holders"`
	local holders=`echo ${sys_path}/holders/*`
	local holder=""
	for holder in ${holders}
		do
		holder=${holder#*holders/}
		holder=${holder#\*}
		echo -n "$holder "
		done
}

function show_all() {
	for bdev in `echo /dev/sd*`
		do
		# Get base name
		bdev_name=${bdev##*/}
		show_dev ${bdev_name}

		done
}

function show_dev() {
	local bdev_name=$1

	# busid = bus-device-protocol-address-part*
	bdev_bus=`get_bus_id ${bdev_name} bus`
	bdev_device=`get_bus_id ${bdev_name} device`
	bdev_protocol=`get_bus_id ${bdev_name} protocol`
	bdev_address=`get_bus_id ${bdev_name} address`

	bdev_id=`get_kdevice ${bdev_name}`
	if [ $? = 1 ]
		then
		# Assume partition
		bdev_id=${bdev_address%-part*}
		fi


	bdev_holders=`get_dev_holders ${bdev_name}`
	if [ "${bdev_holders}" = "" ]
		then
		bdev_holders="----"
		fi

	# Get generic device
	if [ -d /sys/bus/scsi/devices/${bdev_id} ]
		then
		## Get generic device
		if [ -L /sys/bus/scsi/devices/${bdev_address}/generic ]
			then
			bdev_generic=`ls -l /sys/bus/scsi/devices/${bdev_address}/generic`
			bdev_generic=${bdev_generic##*/}
			fi

		## Get status
		if [ -f /sys/bus/scsi/devices/${bdev_id}/state ]
			then
			bdev_status=`cat /sys/bus/scsi/devices/${bdev_id}/state`
			fi

		else
		bdev_generic="---"
		bdev_status="-------"
		fi

	echo ${bdev_bus} ${bdev_device} ${bdev_protocol} ${bdev_address} ${bdev_id} ${bdev_generic} ${bdev_name} ${bdev_status} ${bdev_holders}
}

if [ "$1 $2" = "show all" ]
	then
	show_all
elif [ "$1" = "show" ]
	then
	show_dev $2
else
	echo "Help"
fi
