#!/bin/sh
############################################################################
# Copyright (c) 2003  Hewlett-Packard Development Company, L.P.
############################################################################
# Startup/Shutdown for the UNH iSCSI Initiator
#
# See "man chkconfig" for information on next two lines (Red Hat only)
# chkconfig: 2345 10 20
# description: UNH-iSCSI Initiator/Target startup/shutdown script
#
# Following lines are in conformance with LSB 1.2 spec
### BEGIN INIT INFO
# Provides:            unh-iscsi
# Required-Start:      $remote_fs
# Required-Stop:       
# Default-Start:       2 3 4 5
# Default-Stop:        0 1 6
# Description:         UNH iSCSI Initiator/Target startup/shutdown script
### END INIT INFO

#
# DIST = 1 ==> SLES | UnitedLinux
#      = 2 ==> RH
#
DIST=0
SUSE=1
RH=2


# Set the distribution
cnt=0
[ -f /etc/SuSE-release ] && DIST=$SUSE
[ -f /etc/UnitedLinux-release ] && DIST=$SUSE
[ -f /etc/redhat-release ] && DIST=$RH

[ $DIST -eq 0 ] && exit 1

# Set up the distributions function library
case $DIST in
	$SUSE)
		. /etc/rc.config
		. /etc/rc.status
		;;
	$RH)
		. /etc/rc.d/init.d/functions	
		;;
	*)
		exit 1
		;;
esac

# Can be changed to unh_iscsi_target, if target needs to be loaded.
UNH_ISCSI=unh_iscsi_initiator
UNH_ISCSI_DEV=${UNH_ISCSI}
UNH_ISCSI_DIR=/opt/unh/iscsi
UNH_ISCSI_BIN=${UNH_ISCSI_DIR}/bin
UNH_ISCSI_LOG=/var/${UNH_ISCSI_DIR}/logs/unh_iscsi_boot.log
UNH_LOCK_FILE=/var/lock/subsys/unh_iscsi
KERNEL_VER="`/bin/uname -r`"

# Log to UNH iSCSI Log File
unh_log() {
	echo "$*" >> ${UNH_ISCSI_LOG}
}

# Log to UNH iSCSI Log File and Console
unh_clog () {
	unh_log "$@"
	echo "$*"
}

# Log to UNH iSCSI Log File and use echo_cmd
unh_elog () {
	unh_log "$@"
	echo_cmd "$*"
}

# Echo the return status
echo_cmd()
{
	case $DIST in
		$SUSE)
			rc_reset
			echo -n "$1 "
			;;
		$RH)
			echo -n "$1  "
			;;
	esac

	return
}

# Set command return status
cmd_ret()
{
	ret=$1

	case $DIST in
		$SUSE)
			rc_failed $ret
			echo -n "$1"
			rc_status -v
			;;
		$RH)
			if [ $ret -eq 0 ] 
			then
				echo_success
			else
				echo_failure
			fi
			echo
			;;
	esac

	return
}

# Create device entries for UNH iSCSI Driver (after module load)
create_device()
{
	MAJOR="`/bin/cat /proc/devices | /bin/grep -w $UNH_ISCSI | /bin/awk '{print $1;}'`"
	[ -z "$MAJOR" ] && return

	/bin/rm -f /dev/${UNH_ISCSI_DEV}
	/bin/mknod /dev/${UNH_ISCSI_DEV} c ${MAJOR} 0
}

# Remove devices for UNH iSCSI Driver (after rmmod)
remove_device()
{
	/bin/rm -f /dev/${UNH_ISCSI_DEV} > /dev/null 2>&1
}

# Check if a module is already loaded
check_loaded()
{
	MODULE=$1
	# Load scsi_mod and sd_mod modules
	if [ -f /usr/local/bin/lsmod ] 
	# 2.6.0 temporary fix. This is the case with a 2.6.0
	# kernel on a 2.4.x distro. I expect when a real 
  	# distro is built with the new modules tools that
	# this will not be needed. jpd 1/10/04
	#
	then LOADED="`/usr/local/bin/lsmod | /bin/grep -w ${MODULE}`"
	else LOADED="`/sbin/lsmod | /bin/grep -w ${MODULE}`"
	fi

	# Nothing to do if module is already loaded
	[ ! -z "$LOADED" ] && return 0
	return 1
}

# Check if a module is in use. Returns 0 if used
mod_in_use()
{
	export DRIVER=$1
	if [ -f /usr/local/bin/lsmod ] 
	# 2.6.0 temporary fix. This is the case with a 2.6.0
	# kernel on a 2.4.x distro. I expect when a real 
  	# distro is built with the new modules tools that
	# this will not be needed. jpd 1/10/04
	#
	then usage=`/usr/local/bin/lsmod | eval /bin/grep \"^${DRIVER}\" | /bin/awk '{print $3;}'`

	else usage=`/sbin/lsmod | eval /bin/grep \"^${DRIVER}\" | /bin/awk '{print $3;}'`
	fi
	[ "0${usage}" -gt 0 ] && return 0
	return 1
}

# Load the UNH iSCSI Initiator/Target Modules for this kernel 
# If not available, build and load them.
load_module()
{
	MODULE=$1

	MOD_DIR=${UNH_ISCSI_DIR}/modules/${KERNEL_VER}

	#
	# Check pre-installed modules and determine 
	# what RPM this is.
	#
	if [ -f ${MOD_DIR}/${MODULE}.o ] 
		then MOD_OBJ=${MOD_DIR}/${MODULE}.o
	# 2.6.0 modules
 	else if [ -f ${MOD_DIR}/${MODULE}.ko ]
		then MOD_OBJ=${MOD_DIR}/${MODULE}.ko
		fi	
	fi

	# Load scsi_mod and sd_mod modules
	if [ -f /usr/local/sbin/modprobe ] 
	# 2.6.0 temporary fix. This is the case with a 2.6.0
	# kernel on a 2.4.x distro. I expect when a real 
  	# distro is built with the new modules tools that
	# this will not be needed. jpd 1/10/04
	#
	then
		/usr/local/sbin/modprobe scsi_mod >> ${UNH_ISCSI_LOG} 2>&1
		/usr/local/sbin/modprobe sd_mod >> ${UNH_ISCSI_LOG} 2>&1
	else
		/sbin/modprobe scsi_mod >> ${UNH_ISCSI_LOG} 2>&1
		/sbin/modprobe sd_mod >> ${UNH_ISCSI_LOG} 2>&1
	fi
	
	#
	# FYI - We don't check the exit codes for the above modprobes
	# because some kernels have the modules linked into the
	# kernel and the probe fails. If the modules are NOT present
	# the Initiator won't load anyway and it will report unresolved
	# symbol references.
 	#

	if [ ! -r ${MOD_OBJ} ]
	then
		ls -l ${MOD_DIR}
		ls -l ${MOD_OBJ}
		unh_clog " "
		unh_clog "The UNH iSCSI modules are not available for "
		unh_clog "${MOD_OBJ}" and 
		unh_clog "        this Linux kernel:  ${KERNEL_VER}"
		unh_clog "Attempting to rebuild the UNH iSCSI Modules..."
		unh_clog "Attempting to rebuild the UNH iSCSI Modules..."
	else
		if [ -f /usr/local/sbin/insmod  -a ${MOD_DIR}/${MODULE}.ko ] 
		then
		# 2.6.0 temporary fix. This is the case with a 2.6.0
		# kernel on a 2.4.x distro. I expect when a real 
  		# distro is built with the new modules tools that
		# this will not be needed. jpd 1/10/04
		#
			 /usr/local/sbin/insmod ${MOD_OBJ} >> ${UNH_ISCSI_LOG} 2>&1
		else
			/sbin/insmod ${MOD_OBJ} >> ${UNH_ISCSI_LOG} 2>&1
		fi

      	[ $? -eq 0 ] && return 0
		unh_clog "Linux Kernel Symbol Conflict - Attempting rebuild UNH iSCSI Modules..."
	fi

	# Rebuild the UNH iSCSI Modules for this kernel
	${UNH_ISCSI_BIN}/iscsi_rebuild ${KERNEL_VER} >> ${UNH_ISCSI_LOG} 2>&1

	if [ -f ${MOD_DIR}/${MODULE}.o ] 
		then MOD_OBJ=${MOD_DIR}/${MODULE}.o
	# 2.6.0 modules
 	else if [ -f ${MOD_DIR}/${MODULE}.ko ]
		then MOD_OBJ=${MOD_DIR}/${MODULE}.ko
		fi	
	fi

	if [ $? -ne 0 -o ! -r ${MOD_OBJ} ]
	then
		unh_clog "ERROR: Unable to rebuild UNH iSCSI modules for this kernel!"
		unh_clog "       See  ${UNH_ISCSI_LOG} for error details."
		return 1
	fi

	unh_clog "The UNH iSCSI Modules have been rebuilt successfully."
	unh_log "Attempting to reload the UNH iSCSI Modules..."

	if [ -f /usr/local/sbin/insmod  -a ${MOD_DIR}/${MODULE}.ko ] 
	then
		# 2.6.0 temporary fix. This is the case with a 2.6.0
		# kernel on a 2.4.x distro. I expect when a real 
  		# distro is built with the new modules tools that
		# this will not be needed. jpd 1/10/04
		#
		/usr/local/sbin/insmod ${MOD_OBJ} >> ${UNH_ISCSI_LOG} 2>&1
	else
		/sbin/insmod ${MOD_OBJ} >> ${UNH_ISCSI_LOG} 2>&1
	fi
	if [ $? -ne 0 ]
	then
			unh_clog "ERROR: Unable to reload the UNH iSCSI Modules."
			unh_clog "       Modules are not compatible with this kernel."
			unh_clog "       See  ${UNH_ISCSI_LOG} for error details."
			return 1
	fi

	unh_log "UNH iSCSI Modules have been reloaded successfully."
	return 0
}

# Unload the UNH iSCSI Initiator
unload_module()
{
	DRVRMODULE=$1

	check_loaded $DRVRMODULE
	if [ $? -eq 0 ]
	then
		if [ -f /usr/local/sbin/rmmod ] 
		then
			# 2.6.0 temporary fix. This is the case with a 2.6.0
			# kernel on a 2.4.x distro. I expect when a real 
  			# distro is built with the new modules tools that
			# this will not be needed. jpd 1/10/04
			#
			/usr/local/sbin/rmmod ${DRVRMODULE} >> ${UNH_ISCSI_LOG} 2>&1
		else
			/sbin/rmmod ${DRVRMODULE} >> ${UNH_ISCSI_LOG} 2>&1
		fi
		return $?
	fi

	return 0
}

# Load UNH iSCSI Initiator
unh_iscsi_start()
{
	# Initialize the log file
	DATE="`/bin/date`"
	mv ${UNH_ISCSI_LOG} ${UNH_ISCSI_LOG}.old > /dev/null 2>&1
	unh_log "UNH iSCSI Initiator loading at ${DATE} on Linux kernel:  ${KERNEL_VER}"

	unh_elog "Starting UNH iSCSI Initiator (${UNH_ISCSI})"

	# Nothing to do if module is already loaded
	check_loaded ${UNH_ISCSI}
	if [ $? -eq 0 ]
	then
		unh_log "UNH iSCSI Initiator (${UNH_ISCSI}) already loaded!"
		cmd_ret 1
		return 0
	fi

	# Check and build UNH iSCSI Modules, Return if error
	load_module ${UNH_ISCSI}
	ret=$?

	cmd_ret $ret
	if [ $ret -eq 0 ]
	then
		unh_log "UNH iSCSI Initiator loaded successfully."
		/bin/touch ${UNH_LOCK_FILE} > /dev/null 2>&1
		create_device ${UNH_ISCSI}
	else
		unh_log "ERROR: UNH iSCSI Initiator failed to load."
	fi

	return $ret
}

# Connect and Mount UNH iSCSI File Systems
unh_iscsi_mount()
{
	# Wipe out old devices
	/bin/rm -rf ${UNH_ISCSI_DIR}/dev/* > /dev/null 2>&1

	# Connect to the targets
	unh_elog "Connecting to UNH iSCSI Targets"

	${UNH_ISCSI_BIN}/iscsi_connect >> ${UNH_ISCSI_LOG} 2>&1
	ret=$?

	cmd_ret $ret
	if [ $ret -eq 0 ]
	then
		unh_log "UNH iSCSI Targets connected."
	elif [ $ret -eq 2 ]
	then
		unh_clog "ERROR: Some iSCSI Targets failed to connect."
		unh_clog "       See  ${UNH_ISCSI_LOG} for error details."
	else
		unh_clog "ERROR: All iSCSI Targets failed to connect."
		unh_clog "       See  ${UNH_ISCSI_LOG} for error details."
		return $ret
	fi

	# Mount file systems
	unh_elog "Mounting file systems on UNH iSCSI Targets"

	${UNH_ISCSI_BIN}/iscsi_mount >> ${UNH_ISCSI_LOG} 2>&1
	ret=$?

	cmd_ret $ret
	if [ $ret -eq 0 ]
	then
		unh_log "File systems on UNH iSCSI Disks mounted."
	elif [ $ret -eq 2 ]
	then
		unh_clog "ERROR: Some iSCSI Disks failed to mount."
		unh_clog "       See  ${UNH_ISCSI_LOG} for error details."
		# Some mounted.. that's fine too
		ret=0
	else
		unh_clog "ERROR: All iSCSI Disks failed to mount."
		unh_clog "       See  ${UNH_ISCSI_LOG} for error details."
		return $ret
	fi

	return $ret
}

# Unmount UNH iSCSI File Systems
unh_iscsi_umount()
{
	# Connect to the targets
	unh_elog "Unmounting file systems on UNH iSCSI Targets"

	${UNH_ISCSI_BIN}/iscsi_umount >> ${UNH_ISCSI_LOG} 2>&1
	ret=$?

	cmd_ret $ret
	if [ $ret -eq 0 ]
	then
		unh_log "File systems on UNH iSCSI Disks unmounted."
	else
		unh_clog "ERROR: Some or all iSCSI Disks failed to unmount."
		unh_clog "       See  ${UNH_ISCSI_LOG} for error details."
		return $ret
	fi

	# Connect to the targets
	unh_elog "Disconnecting from UNH iSCSI Targets"

	${UNH_ISCSI_BIN}/iscsi_disconnect >> ${UNH_ISCSI_LOG} 2>&1
	ret=$?

	cmd_ret $?
	if [ $ret -eq 0 ]
	then
		unh_log "UNH iSCSI Targets disconnected."
	elif [ $ret -eq 2 ]
	then
		unh_clog "ERROR: Some iSCSI Targets failed to disconnect."
		unh_clog "       See  ${UNH_ISCSI_LOG} for error details."
	else
		unh_clog "ERROR: All iSCSI Targets failed to disconnect."
		unh_clog "       See  ${UNH_ISCSI_LOG} for error details."
	fi

	return 0
}

# Stop the UNH iSCSI Initiator
unh_iscsi_stop()
{
	unh_elog "Stopping UNH iSCSI Initiator (${UNH_ISCSI})" 

	mod_in_use ${UNH_ISCSI}
	if [ $? -eq 0 ]
	then
		unh_log "ERROR: Module can not be unloaded while in use."
		cmd_ret 1
		return 1
	else
		unload_module $UNH_ISCSI
		ret=$?

		cmd_ret $ret
		if [ $ret -eq 0 ]
		then
			/bin/rm -f ${UNH_LOCK_FILE}
			remove_device ${UNH_ISCSI}
			unh_log "Module unloaded successfully."
		else
			unh_log "ERROR: Module could not be unloaded."
		fi
	fi

	return 0
}

unh_iscsi_status()
{
	echo -e "UNH iSCSI Initiator (${UNH_ISCSI}) is \c"
	check_loaded ${UNH_ISCSI}
	 if [ $? -eq 0 ]
	then
		echo "loaded."
	else
		echo "NOT loaded."
	fi

	return
}

# Main
case "$1" in
	start)
		unh_iscsi_start
		[ $? -ne 0 ] && exit 1
		unh_iscsi_mount
		;;
	stop)
		unh_iscsi_umount
		if [ $? -ne 0 ]
		then
			echo_cmd "Stopping UNH iSCSI Initiator (${UNH_ISCSI}): " 
			cmd_ret 1
			exit 1
		fi

		unh_iscsi_stop
		;;
	mount)
		unh_iscsi_mount
		;;
	restart)
		$0 stop
		[ $? -ne 0 ] && exit
		$0 start
		;;
	status)
		unh_iscsi_status
		;;
	*)
		# Default - Show Usage.
		echo "Usage: $0 {start|stop|enable|disable|status|restart}"
		exit 1
		;;
esac

exit 0
