#! /bin/bash
### Xsigo VHBA rescan script ###

scsi_dev_arr=()
scsi_dev_cnt=0

vhba_dev_arr=()
vhba_dev_cnt=0
vhba_index=-1

get_vhba_index()
{
        if [ -e "/proc/driver/xsvhba/target_info/$1" ]; then
        	host_no=`cat /proc/driver/xsvhba/target_info/$1 |grep 'Host no'`
        	vhba_index=${host_no:13}
	else
		vhba_index=-1
	fi
}

display_vhba()
{
	echo "========================================================"
	echo "VHBA Provisioned:"
	echo "========================================================"
	sl_no=0
        if [ $1 = "-a" ]; then
                host_arr=( `ls /proc/driver/xsvhba/target_info/* 2>/dev/null | sort -n` )
        else
		if [ ! -e "/proc/driver/xsvhba/target_info/$1" ]; then
			echo "VHBA is not available"
			return
		fi
                host_arr=( "/proc/driver/xsvhba/target_info/$1" )
        fi
        host_no="Host no"
        tgt_no="Map Order"
        lun_ids="Lun id(s)"
	tgt_wwn="Target WWPN"
        len_hst=${#host_no}
        len_tgt=${#tgt_no}
        len_lun=${#lun_ids}
	len_wwn=${#tgt_wwn}

	for host in "${host_arr[@]}"
	do
		name=$host
		let "sl_no++"
		sl_tgt=0
		if [ $sl_no -gt 1 ]; then
		echo "--------------------------------------------------------"
		fi
		printf "%3d. VHBA_Name:  %-16s " $sl_no "${name##/*/}"
		while read line
		do
                        if [ `expr match "$line" "$host_no"` -eq $len_hst ]; then
                                Hst_no=${line:13}
                                Hst_no=${Hst_no//'\t'/''}
				echo " Host_no: " ${Hst_no}
				echo 
                        elif [ `expr match "$line" "$tgt_no"` -eq $len_tgt ]; then
                                Tgt_no=${line:13}
                                Tgt_no=${Tgt_no//' '/''}
				echo "       Tgt_no  : " ${Tgt_no}
			elif [ `expr match "$line" "$tgt_wwn"` -eq $len_wwn ]; then
				Tgt_wwn=${line:16}
				Tgt_wwn=${Tgt_wwn//'\t'/''}
				Tgt_wwn=${Tgt_wwn//' '/':'}
				let "sl_tgt++"
				printf "  %3d. Tgt_wwn :  %s\n" $sl_tgt "${Tgt_wwn}"
                        elif [ `expr match "$line" "$lun_ids"` -eq $len_lun ]; then
                                Lun_no=${line:11}
                                Lun_no=${Lun_no:2}
				echo "       Lun_id  : " ${Lun_no}
				echo 
                        fi
		done < $host
	done
	echo "--------------------------------------------------------"
}

find_scsi_dev()
{
pwd=`pwd`
	if [ $1 = "-a" ]; then
        	host_arr=( `ls /proc/scsi/xsvhba/  2>/dev/null | sort -n` )
	else
		host_arr=$1
	fi
	scsi_dev_cnt=0
	for host in "${host_arr[@]}"
	do
		cd /sys/class/scsi_host/host${host}/device/rport-${host}:0-*
		tgt_arr=( `ls -d target${host}:0:* 2>/dev/null | sed "s/target${host}:0://"` )
		for tgt in "${tgt_arr[@]}"
		do
			cd target${host}:0:${tgt}
			lun_arr=( `ls -d ${host}:0:${tgt}:*  2>/dev/null | sed "s/${host}:0:${tgt}://" | sort -n` )
			for lun in "${lun_arr[@]}"
			do
				Lun_info=`echo "${host}" ":0:" "${tgt}" ":" "$lun"`
				Lun_info=${Lun_info//' '/''}
				let "scsi_dev_cnt++"
				scsi_dev_arr[$scsi_dev_cnt]=$Lun_info		
			done
			cd ..
		done
	done
}

display_scsi_dev()
{
	echo "Num of (scsi) devices = " $scsi_dev_cnt
	echo ""
	echo "------------------"
	echo "   HH:CC:TT:LL"
	echo "------------------"
	echo ""
	i=1
	while [ $i -le $scsi_dev_cnt ]
	do
		printf "%3d) %s\n" $i "${scsi_dev_arr[$i]}"
		let "i++"
	done
}

find_vhba_dev()
{
        if [ $1 = "-a" ]; then
		FILES=`ls /proc/driver/xsvhba/target_info/*  2>/dev/null`
        else
                if [ ! -e "/proc/driver/xsvhba/target_info/$1" ]; then
                        echo "VHBA is not available"
                        return
                fi
                FILES=( "/proc/driver/xsvhba/target_info/$1" )
        fi

	host_no="Host no"
	tgt_no="Map Order"
	lun_ids="Lun id(s)"
	len_hst=${#host_no}
	len_tgt=${#tgt_no}
	len_lun=${#lun_ids}

	vhba_dev_arr=()
	vhba_dev_cnt=0
	for file in $FILES
	do
	        while read line
	        do
		        if [ `expr match "$line" "$host_no"` -eq $len_hst ]; then
			        Hst_no=${line:13}
				Hst_no=${Hst_no//'\t'/'a'}
		        elif [ `expr match "$line" "$tgt_no"` -eq $len_tgt ]; then
			        Tgt_no=${line:13}
				Tgt_no=${Tgt_no//' '/''}
		        elif [ `expr match "$line" "$lun_ids"` -eq $len_lun ]; then
			        Lun_no=${line:11}
			        Lun_no=${Lun_no:2}
				Lun_no=${Lun_no//','/' '}
			        for lun in $Lun_no
			        do
				        Lun_info=` echo "$Hst_no" ":0:" "$Tgt_no" ":" $lun`
					Lun_info=${Lun_info//' '/''}
					let "vhba_dev_cnt++"
					vhba_dev_arr[$vhba_dev_cnt]=$Lun_info
			        done
		        fi
	        done < $file
	done
}

display_vhba_dev()
{
        echo "Num of (vhba) devices = " $vhba_dev_cnt
        echo "=============="
        echo " HH:CC:TT:LL"
        echo "=============="
        echo ""

        i=1
        while [ $i -le $vhba_dev_cnt ]
        do
                echo "$i) ${vhba_dev_arr[$i]}"
                let "i++"
        done
}

scan_dev()
{
	i=1
	cnt=0
	while [ $i -le $vhba_dev_cnt ]
	do
		j=1
		fnd=0
		while [ $j -le $scsi_dev_cnt ]
		do
			if [ "${vhba_dev_arr[$i]}" = "${scsi_dev_arr[$j]}" ]
			then
			# device already added
				fnd=1
				break
			fi
			let "j++"
		done
                if [ $fnd -ne 1 ]; then
			# add the device
			echo "scsi add-single-device ${vhba_dev_arr[$i]}" > /proc/scsi/scsi
			let "cnt++"
                fi
		let "i++"
	done
	echo "----------------------"
	echo "Devices Added: $cnt"
	echo "----------------------"
	echo ""
}

refresh_dev()
{
	cnt=0
        i=1
        while [ $i -le $scsi_dev_cnt ]
        do
                j=1
                fnd=0
                while [ $j -le $vhba_dev_cnt ]
                do
                        if [ "${vhba_dev_arr[$j]}" = "${scsi_dev_arr[$i]}" ]
                        then
                        # device already existing
			# remove it and add it again
			# this makes sure we get updated info about LUNs
				echo "scsi remove-single-device ${scsi_dev_arr[$i]}" > /proc/scsi/scsi
				echo "scsi add-single-device ${scsi_dev_arr[$i]}" > /proc/scsi/scsi
                                fnd=1
                                break
                        fi
                        let "j++"
                done
                if [ $fnd -ne 1 ]; then
                        # Remove the lost device
			echo "scsi remove-single-device ${scsi_dev_arr[$i]}" > /proc/scsi/scsi
			let "cnt++"
                fi
                let "i++"
        done
	echo "----------------------"
	echo "Devices Removed: $cnt"
	echo "----------------------"
	echo ""

}
usage()
{
	echo  "-------------------------------------------------------------------------"
	echo  "Usage: xsigo-scan <option>"
	echo  "Option:"
	echo  "   -s <-a|vhba-name>      : Scan for new devices"
	echo  "   -r <-a|vhba-name> [-nc]: Scan for new devices and remove lost devices"
	echo  "                     [-nc]: to skip the confirmation prompt"
	echo  "   -d <-a|vhba-name>      : Display current devices"
	echo  "   -l <-a|vhba-name>      : Display VHBA details"
	echo  "   -h                     : This help message"
	echo  ""
	echo  "              [-a]        = applicable to all VHBAs"
	echo  "              [vhba-name] = applicable only to this VHBA"
	echo  "-------------------------------------------------------------------------"
}

get_confirmation()
{
	conf=
	echo ""
	echo "======================================================"
	echo "!!! Warning: This may affect the IO currently running"
	echo "======================================================"
	echo ""
	echo "Do you want to continue: (Y/y/N/n)?"
	read conf
	case ${conf} in
        	y | Y ) return
        	;;
        	n | N | * ) exit 1
        	;;
	esac
}

case "$1" in
	-s)
		if [ $# -ne 2 ]; then
			usage
			exit 1
		fi
        	if [ $2 = "-a" ]; then
			arg="-a"
		else
			get_vhba_index $2
			if [ $vhba_index = "-1" ]; then
				echo "VHBA is not available"
                        	exit 1
                	else
                        	arg=$vhba_index
                	fi
		fi
		find_scsi_dev $arg
		find_vhba_dev $2
		scan_dev
	;;

	-r)
		if [[ $# -gt 3  || $# -eq 3 && $3 != "-nc" || $# -eq 1 ]] ; then
			usage
			exit 1
		fi
		if [ $# -eq 2 ]; then
			get_confirmation
		fi
		if [ $2 = "-a" ]; then
			arg="-a"
		else
			get_vhba_index $2
			if [ $vhba_index = "-1" ]; then
				echo "VHBA is not available"
				exit 1
			else
				arg=$vhba_index
			fi
		fi
		find_scsi_dev $arg
        	find_vhba_dev $2
        	scan_dev
		refresh_dev
	;;

	-l)
        	if [ $# -ne 2 ]; then
			usage
                	exit 1
		fi
        	if [ $2 = "-a" ]; then
                	arg="-a"
        	fi
		display_vhba $2
	;;

	-d)
        	if [ $# -ne 2 ]; then
			usage
                	exit 1
        	fi
        	if [ $2 = "-a" ]; then
                	arg="-a"
        	else
			get_vhba_index $2
			if [ $vhba_index = "-1" ]; then
				echo "VHBA is not available"
				exit 1
			else
				arg=$vhba_index
			fi
		fi
		find_scsi_dev $arg
		find_vhba_dev $2
		display_scsi_dev
	;;

	-h)
		usage
	;;

	*)
		usage
		exit 1
	;;
esac

exit 0
