#! /bin/sh
# chkconfig: 2345 11 89
# description: iSCSI daemon

# For SuSE, the following information is read by "insserv" program and the
# start/stoplinks are installed at appropriate runlevels.
# The network interface and logger has to be up for starting iscsi service
### BEGIN INIT INFO
# Provides: iscsi
# Required-Start: $network $syslog
# Required-Stop:  $network $syslog
# Default-Start:  2 3 5
# Default-Stop:   0 1 6
# Description:    Start iSCSI to allow access to remote SCSI devices
### END INIT INFO

BASEDIR=/
PIDFILE=/var/run/iscsid.pid

#Timeouts to be used during iscsi shutdown
CONNFAILTIMEOUT=30
DISKCOMMANDTIMEOUT=5

# Increase the maximum TCP window size in Linux (well, socket memory, which is related) to this number
TCP_WINDOW_SIZE=1048576

PATH="$BASEDIR/sbin:$BASEDIR/bin:/sbin:/bin:/usr/sbin:/usr/bin:$PATH"
export PATH

test -d $BASEDIR || exit 0

iscsi_network_boot()
{
	mtab=/etc/mtab
	iscsirootfs=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $1; }}' $mtab)
	
	tmp="/dev/inbpdisk"
	
	dev=$(echo $tmp |sed -e "s/\//\\\\\//g")
	partnr=$(echo $iscsirootfs | sed -e "s/$dev//g")
	
	tmp=$tmp$partnr
	
	if [ ! $tmp = $iscsirootfs ] ; then
	    return 1
	else
	    return 0
	fi
}

case $1 in
 start)
        # Do sanity checks before we start..
        if [ ! -e /etc/iscsi.conf ]; then
		echo
                echo "Error: configuration file /etc/iscsi.conf is missing!"
		echo "The iSCSI driver has not been correctly installed and cannot start."
		echo
                exit 1
        elif [ -s $PIDFILE ] && kill -0 `head -n 1 $PIDFILE` >/dev/null ; then
                echo "iSCSI daemon already running"
		echo
                exit 1
        fi

        grep -Eq '^[^#]' /etc/iscsi.conf
        if [ $? -ne 0 ] ; then
            echo "Error: Configuration file is empty, unable to start the driver"
            echo
            exit 1
        fi

	if [ ! -f /var/lib/iscsi/bindings ] ; then
	    if [ -e /etc/iscsi.bindings ] ; then
		echo
		echo "Changing the name and location of /etc/iscsi.bindings file to /var/lib/iscsi/bindings"
		if [ ! -d /var/lib/iscsi ] ; then
			mkdir -p /var/lib/iscsi
		fi
		mv /etc/iscsi.bindings /var/lib/iscsi/bindings
	    elif [ -e /var/iscsi/bindings ] ; then
		echo
		echo "Changing the name and location of /var/iscsi/bindings file to /var/lib/iscsi/bindings"
		if [ ! -d /var/lib/iscsi ] ; then
			mkdir -p /var/lib/iscsi
		fi
		mv /var/iscsi/bindings /var/lib/iscsi/bindings
	    fi
	fi

        if [ ! -f /etc/initiatorname.iscsi ] ; then
	    echo
            echo "Error: InitiatorName file /etc/initiatorname.iscsi is missing!"
	    echo "The iSCSI driver has not been correctly installed and cannot start."
	    echo
            exit 1
        fi

        # see if we need to generate a unique iSCSI InitiatorName
	# this should only happen if the 
        if grep -q "^GenerateName=yes" /etc/initiatorname.iscsi ; then
	    if [ ! -x $BASEDIR/sbin/iscsi-iname ] ; then
		echo "Error: $BASEDIR/sbin/iscsi-iname does not exist, driver was not successfully installed"
		exit 1;
	    fi 
	    # Generate a unique InitiatorName and save it
	    INAME=`$BASEDIR/sbin/iscsi-iname`
	    if [ "$INAME" != "" ] ; then
		echo "## DO NOT EDIT OR REMOVE THIS FILE!" > /etc/initiatorname.iscsi
		echo "## If you remove this file, the iSCSI daemon will not start." >> /etc/initiatorname.iscsi
		echo "## If you change the InitiatorName, existing access control lists" >> /etc/initiatorname.iscsi
		echo "## may reject this initiator.  The InitiatorName must be unique">> /etc/initiatorname.iscsi
		echo "## for each iSCSI initiator.  Do NOT duplicate iSCSI InitiatorNames." >> /etc/initiatorname.iscsi
		printf "InitiatorName=$INAME\n"  >> /etc/initiatorname.iscsi
		chmod 600 /etc/initiatorname.iscsi
	    else
		echo "Error: failed to generate an iSCSI InitiatorName, driver cannot start."
		echo
		exit 1;
	    fi
        fi

	# make sure there is a valid InitiatorName for the driver
        if ! grep -q "^InitiatorName=[^ \t\n]" /etc/initiatorname.iscsi ; then
	    echo
	    echo "Error: /etc/initiatorname.iscsi does not contain a valid InitiatorName."
	    echo "The iSCSI driver has not been correctly installed and cannot start."
	    echo
	    exit 1
	fi

        # cycle the old log, since we can't guarantee anything is managing
        # it, and in any case it's now only used for debugging info.
        if [ -e /var/log/iscsi.log ] ; then
            rm -f /var/log/iscsi.log.old
            mv /var/log/iscsi.log /var/log/iscsi.log.old
        fi
        echo "" > /var/log/iscsi.log
        chmod 0600 /var/log/iscsi.log

        # Increase the maximum TCP window size to something that will give reasonable 
        # performance for storage networking.  Use at least a 1 MB max.
        # This only works if we have /proc, but the daemon assumes that anyway,
        # so there's no point trying to use sysctl.
        if [ -e /proc/sys/net/core/rmem_max ] ; then
            RMEM_MAX=`cat /proc/sys/net/core/rmem_max`
            if [ $RMEM_MAX -lt $TCP_WINDOW_SIZE ] ; then
                echo "$TCP_WINDOW_SIZE" > /proc/sys/net/core/rmem_max
            fi
        fi

        if [ -e /proc/sys/net/core/wmem_max ] ; then
            WMEM_MAX=`cat /proc/sys/net/core/wmem_max`
            if [ $WMEM_MAX -lt $TCP_WINDOW_SIZE ] ; then
                echo "$TCP_WINDOW_SIZE" > /proc/sys/net/core/wmem_max
            fi
        fi

	# 2.4 kernels don't use the net/core values for TCP anymore
        if [ -e /proc/sys/net/ipv4/tcp_rmem ] ; then
	    max=`awk '{print $3}' /proc/sys/net/ipv4/tcp_rmem`
	    if [ $max -lt $TCP_WINDOW_SIZE ] ; then
		min=`awk '{print $1}' /proc/sys/net/ipv4/tcp_rmem`
		default=`awk '{print $2}' /proc/sys/net/ipv4/tcp_rmem`
		echo "$min $default $TCP_WINDOW_SIZE" > /proc/sys/net/ipv4/tcp_rmem
            fi
        fi

        if [ -e /proc/sys/net/ipv4/tcp_wmem ] ; then
	    max=`awk '{print $3}' /proc/sys/net/ipv4/tcp_wmem`
	    if [ $max -lt $TCP_WINDOW_SIZE ] ; then
		min=`awk '{print $1}' /proc/sys/net/ipv4/tcp_wmem`
		default=`awk '{print $2}' /proc/sys/net/ipv4/tcp_wmem`
		echo "$min $default $TCP_WINDOW_SIZE" > /proc/sys/net/ipv4/tcp_wmem
            fi
        fi

        # start
        echo -n "Starting iSCSI: iscsi"

	# the install script tells us when we need to unload an old module,
	# so that 'make install; rc.iscsi restart' does what people expect.
	if [ -d /tmp -a -e /tmp/.iscsi.unload.module ] ; then
	    rmmod iscsi_sfnet > /dev/null 2>&1
	    rm -f /tmp/.iscsi.unload.module
        fi

        if ! modprobe iscsi_sfnet >> /var/log/iscsi.log 2>&1; then
            # collect info useful in debugging module load problems.
	    echo >> /var/log/iscsi.log
	    printf "uname -r = %s\n" `uname -r` >> /var/log/iscsi.log
	    printf "uname -m = %s\n" `uname -m` >> /var/log/iscsi.log
	    printf "/proc/cmdline = %s\n" `cat /proc/cmdline` >> /var/log/iscsi.log
	    printf "\nls -la /boot/:\n" >> /var/log/iscsi.log
	    ls -la /boot/ >> /var/log/iscsi.log
	    printf "\n/boot md5sums:\n" >> /var/log/iscsi.log
	    for k in /boot/vmlinu* ; do md5sum $k ; done >> /var/log/iscsi.log
	    printf "\nls -la /usr/src:\n" >> /var/log/iscsi.log
	    ls -la /usr/src >> /var/log/iscsi.log
	    DIR=/lib/modules/`uname -r`
	    printf "\nls -la $DIR:\n" >> /var/log/iscsi.log
	    ls -la $DIR >> /var/log/iscsi.log
	    printf "\nls -la $DIR/build/:\n" >> /var/log/iscsi.log
	    ls -la $DIR/build/ >> /var/log/iscsi.log
	    printf "\nhead $DIR/build/Makefile:\n" >> /var/log/iscsi.log
	    head -5 $DIR/build/Makefile >> /var/log/iscsi.log
	    printf "\nfind $DIR -name '*iscsi*' -print:\n" >> /var/log/iscsi.log
	    find $DIR -name '*iscsi*' -print >> /var/log/iscsi.log
	    printf "\nnm iSCSI modules:\n" >> /var/log/iscsi.log
            for m in `find $DIR -name '*iscsi*' -print` ; do (printf "\n${m}:\n" ; nm $m ) ; done >> /var/log/iscsi.log
	    printf "\n/proc/ksyms:\n" >> /var/log/iscsi.log
	    cat /proc/ksyms >> /var/log/iscsi.log
	    # FIXME: should we find and copy some kernel config files as well?
	    # Tell the user it failed.
            echo
            echo "Couldn't load module iscsi_sfnet"
            echo "See error log in /var/log/iscsi.log"
            exit 1
        fi

	# By default, we try to load the scsi disk driver module.
	# If SCSI support is in modules, sd_mod won't get loaded
	# until after a /dev/sd* device is opened.  This means no 
	# messages about disks will be logged until a disk device 
	# is opened.  Worse, mounting by label won't work, since
	# it relies on /proc/partitions, which won't get updated
	# until the SCSI disk driver is loaded, creating a circular
	# dependency.  To work around these problems, we try to load 
	# the disk driver here.  If you're not using SCSI disks, 
	# you can comment this out.
	modprobe sd_mod > /dev/null 2>&1

        echo -n " iscsid"
        if [ -d /proc/scsi/iscsi ] ; then
	    for hba in /proc/scsi/iscsi/* ; do
		if [ -f $hba ] ; then
		    break
		fi
	    done
	    if [ -f $hba ] ; then
		while read busid targetid lun ip port name ; do
		    case $busid
			in
			\#*) continue ;; #  ignore comments
			'')  continue ;; # ignore empty lines
		    esac
		    
		    break
		    
		done < $hba
	    fi
	fi

	if [ "$DEBUG_ISCSI" ] ; then
	    if [ -e /proc/scsi/scsi ] ; then
		# log SCSI error handling
#		echo "scsi log scan 5" > /proc/scsi/scsi
		echo "scsi log timeout 3" > /proc/scsi/scsi
		echo "scsi log error 5" > /proc/scsi/scsi
	    fi
	    if [ -e /proc/sys/kernel/sysrq ] ; then
		# enable magic SysRq
		echo "1" > /proc/sys/kernel/sysrq
	    fi	
	    if [ -d /proc/scsi/iscsi ] ; then
		# turn on some useful kernel module debug messages by default
		for hba in /proc/scsi/iscsi/* ; do
		    echo "log sense always" > $hba
#		    echo "log login on" > $hba
		    echo "log init on" > $hba
#		    echo "log queue on" > $hba
#		    echo "log flow on" > $hba
		    echo "log retry on" > $hba
		    echo "log eh on" > $hba
#		    echo "log alloc on" > $hba
		done
            fi
	    iscsid -d $DEBUG_ISCSI
        else
	    iscsid
        fi
	
	# Make sure the K*iscsi scripts get called
	if [ -d /var/lock/subsys ] ; then 
	    touch /var/lock/subsys/iscsi 
	fi
        
        # if we have an iSCSI fstab, process it
        if [ -f /etc/fstab.iscsi ] ; then
            echo -n " fsck/mount"
            sleep 6
            iscsi-mountall
        fi

        echo ""

        ;;
 stop)
	# if iSCSI network boot then exit.
	if iscsi_network_boot ; then
	    echo "Since it is an iSCSI network boot therefore, driver cannot be stopped/restarted"
	    exit 1
	fi

        echo -n "Stopping iSCSI:"
        for hba in /proc/scsi/iscsi/* ; do
            echo "connfailtimeout - - $CONNFAILTIMEOUT" > $hba
            echo "diskcommandtimeout - - $DISKCOMMANDTIMEOUT" > $hba
        done

        echo -n " sync"
        sync

        # unmount all filesystems on iSCSI devices
        echo -n " umount"
        iscsi-umountall -t -k

        echo -n " sync"
        sync
        sleep 3

        if [ -f $PIDFILE ] ; then
	    echo -n " iscsid"
            kill -TERM `head -n 1 $PIDFILE`
	    sleep 2
            killall $BASEDIR/sbin/iscsid > /dev/null 2>&1
            killall iscsid > /dev/null 2>&1
            rm -f $PIDFILE
        fi

	# shutdown the kernel module
	if [ -d /proc/scsi/iscsi ] ; then
	    echo -n " iscsi"
	    for hba in /proc/scsi/iscsi/* ; do
		echo "shutdown" > $hba
	    done
	fi

	# the install script tells us when we need to unload an old module,
	# so that 'make install; rc.iscsi start' does what people expect.
	if [ -d /tmp -a -e /tmp/.iscsi.unload.module ] ; then
	    rmmod iscsi_sfnet > /dev/null 2>&1
	    rm -f /tmp/.iscsi.unload.module
        fi

	if [ -e /var/lock/subsys/iscsi ] ; then
 	    rm /var/lock/subsys/iscsi
        fi

        echo
        ;;
 restart)
	# if iSCSI network boot then exit.
	if iscsi_network_boot ; then
	    echo "Since it is an iSCSI network boot therefore, driver cannot be stopped/restarted"
	    exit 1
	fi

        $0 stop
        $0 start
        ;;
 reload)
        if [ -f $PIDFILE ] ; then
            kill -HUP `head -n 1 $PIDFILE`
        fi
	;;
 status)
        if [ -s $PIDFILE ] && kill -0 `head -n 1 $PIDFILE` >/dev/null ; then
            echo "iSCSI driver is loaded"
        else
            echo "iSCSI driver is not loaded"
        fi
        ;;
 debug1)
        DEBUG_ISCSI=1
        export DEBUG_ISCSI
        $0 start
        ;;
 debug2)
        DEBUG_ISCSI=2
        export DEBUG_ISCSI
        $0 start
        ;;
 debug3)
        DEBUG_ISCSI=3
        export DEBUG_ISCSI
        $0 start
        ;;
 debug4)
        DEBUG_ISCSI=4
        export DEBUG_ISCSI
        $0 start
        ;;
 debug|debug5)
        DEBUG_ISCSI=5
        export DEBUG_ISCSI
        $0 start
        ;;
 debug6)
        DEBUG_ISCSI=6
        export DEBUG_ISCSI
        $0 start
        ;;
 debug7)
        DEBUG_ISCSI=7
        export DEBUG_ISCSI
        $0 start
        ;;
 redebug1)
        $0 stop
        $0 debug1
        ;;
 redebug2)
        $0 stop
        $0 debug2
        ;;
 redebug3)
        $0 stop
        $0 debug3
        ;;
 redebug4)
        $0 stop
        $0 debug4
        ;;
 redebug|redebug5)
        $0 stop
        $0 debug5
        ;;
 redebug6)
        $0 stop
        $0 debug6
        ;;
 redebug7)
        $0 stop
        $0 debug
        ;;
 *)
        echo "Usage: /etc/init.d/iscsi { start | stop | restart | status | reload }"

        ;;
esac

exit 0
