#!/bin/bash

SCST_MODULES="scst scst_disk scst_vdisk iscsi_scst qla2xxx_scst qla2x00tgt"
TCM_MODULES="qla2xxx"
SCST_DAEMON="$(which iscsi-scstd)"
ISCSID_OPTIONS=""
LOG="/var/log/vstorage/vstorage-scstd.log"

start_daemon() {
	"$@" >/dev/null 2>&1
}

killproc() {
	local exe="`basename "$1"`"
	killall $exe
}

# Keep trying to unload kernel module $1 for up to $2 seconds. Return true
# if and only if the kernel module was unloaded before the timeout expired.
unload_kmod() {
	local i m t

	m="$1"
	t="$2"
	i=0
	while [ -e "/sys/module/$m/refcnt" ] && ! rmmod "$m" 2>/dev/null &&
	  [ $i -lt "$t" ]
	do
	sleep 1
	i=$((i+1))
	done
	[ ! -e "/sys/module/$m/refcnt" ]
}

stop_scst() {
	killproc $SCST_DAEMON
	return $?
}

# Unload SCST
unload_scst() {

	stop_scst

	# isert_scst must be unloaded before iscsi_scst. Note that unloading
	# isert_scst may take a while since in certain scenarios (e.g. cable
	# problem and then service stop) MADs get timed out only after about 50+
	# seconds.
	unload_kmod isert_scst 90 || echo "Unloading isert_scst failed"

	reverse_list=""
	for m in $SCST_MODULES; do
	reverse_list="$m $reverse_list"
	done
	for m in $reverse_list; do
	refcnt="`cat /sys/module/$m/refcnt 2>/dev/null`"
	if [ ! -z "$refcnt" ] && [ "$refcnt" -gt 0 ]; then
		# Apparently it can happen that the iscsi_scst refcnt is only
		# decremented a short time after killproc finished. If that
		# occurs, sleep for a short time.
		sleep 1
	fi
	unload_kmod $m 30 || return 1
	done

	return 0
}

start_scst() {
	# Unload TCM modules before loading SCST
	for m in $TCM_MODULES; do
		if [ -e /sys/module/$m ]; then
			rmmod $m
			if [ $? -ne 0 ]; then
				echo "Can't unload $m" 1>&2
				return 4
			fi
		fi
	done

	for m in $SCST_MODULES; do
		if [ ! -e /sys/module/$m ]; then
			local params=""

			if [ "$m" == "scst" ]; then
				params="forcibly_close_sessions=1"
			fi

			if ! modprobe $m $params; then
				echo modprobe $m failed.
				unload_scst
				return 5
			fi
		fi
	done
	if ! start_daemon $SCST_DAEMON $ISCSID_OPTIONS; then
		 echo "Starting $d failed"
		 unload_scst
		 return 1
	fi

	return 0
}


rc=0
case "$1" in
	start)
		## Start the service.
		echo "Loading and configuring SCST"
		start_scst
		rc=$?
		;;
	stop)
		## Stop the service.
		echo "Stopping SCST"
		stop_scst
		rc=$?
		;;
	unload)
		## Stop the service.
		echo "Unloading SCST"
		unload_scst
		rc=$?
		;;
	*)
		echo "Usage: $0 {start|stop}"
		exit 2
	;;
esac

exit $rc

