#!/bin/bash
#
# Bring up/down sxdkernel
#
# chkconfig: 2345 05 95
# description: Activates/Deactivates SwitchX Driver to \
#              start at boot time.
#
### BEGIN INIT INFO
# Provides:       sxdkernel
# Required-Start:
# Required-Stop:
# Default-Start:  3 5
# Default-Stop:   0 1 2 6
# Short-Description: SwitchX driver service
# Description:    Activates/Deactivates SwitchX Driver
### END INIT INFO

# Therefore determine the base, follow a runlevel link name ...
base=${0##*/}
link=${base#*[SK][0-9][0-9]}
usr_params=$*
# ... and compare them
if [ $link == $base ] ; then
	RUNMODE=manual
else
	RUNMODE=auto
fi

ACTION=$1
CHIP_TYPE=$2
shift

if [ -z $RESET_TRIGGER ]; then
    RESET_TRIGGER=1
fi

if [ -z $FAST_BOOT ]; then
    export FAST_BOOT=0
fi

if [ "x$RESUME_SDK" == "x1" ]; then
    FAST_BOOT=1
fi

RESTART=0

UNLOAD_MODULES=""
STATUS_MODULES="sx_core sx_netdev 8021q"

#########################################################################
# Get a sane screen width
[ -z "${COLUMNS:-}" ] && COLUMNS=80

[ -z "${CONSOLETYPE:-}" ] && [ -x /sbin/consoletype ] && CONSOLETYPE="`/sbin/consoletype`"

if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then
	. /etc/sysconfig/i18n
	if [ "$CONSOLETYPE" != "pty" ]; then
		case "${LANG:-}" in
			ja_JP*|ko_KR*|zh_CN*|zh_TW*)
				export LC_MESSAGES=en_US
				;;
			*)
				export LANG
				;;
		esac
	else
		export LANG
	fi
fi

echo_success() {
	echo -n $@

	[ "$BOOTUP" = "color" ] && $MOVE_TO_COL
	echo -n "[  "
	[ "$BOOTUP" = "color" ] && $SETCOLOR_SUCCESS
	echo -n $"OK"
	[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
	echo -n "  ]"
	echo -e "\r"
	return 0
}

echo_done() {
	echo -n $@
	[ "$BOOTUP" = "color" ] && $MOVE_TO_COL
	echo -n "[  "
	[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
	echo -n $"done"
	[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
	echo -n "  ]"
	echo -e "\r"
	return 0
}

echo_failure() {
	echo -n $@
	[ "$BOOTUP" = "color" ] && $MOVE_TO_COL
	echo -n "["
	[ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
	echo -n $"FAILED"
	[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
	echo -n "]"
	echo -e "\r"
	return 1
}

echo_warning() {
	echo -n $@
	[ "$BOOTUP" = "color" ] && $MOVE_TO_COL
	echo -n "["
	[ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
	echo -n $"WARNING"
	[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
	echo -n "]"
	echo -e "\r"
	return 1
}

# If module $1 is loaded return - 0 else - 1
is_module()
{
	local RC

	/sbin/lsmod | grep -w "$1" > /dev/null
	RC=$?

	return $RC
}

# Return module's refcnt
is_ref()
{
	local refcnt
	refcnt=`cat /sys/module/"$1"/refcnt 2> /dev/nill`
	return $refcnt
}

# Perform chip reset
reset_asic()
{
	echo 0 > /sys/module/sx_netdev/bind_sx_core

	/usr/bin/hw-management.sh chipdown

	echo "Mellanox ASIC Chip Reset"
	echo "pcidrv_restart" > /proc/mlx_sx/sx_core

	echo 1 > /sys/module/sx_netdev/bind_sx_core
	echo 0 > /var/run/hw-management/config/suspend
}

start()
{
    # Start from a clean state with the ASIC
    # If fastboot is not enabled then reset asic
    # set the flag to normal after we are done
    filename=/etc/modprobe.d/sx.modprobe.conf
    if grep -q "0" $filename; then
        reset_asic
    elif grep -q "1" $filename; then
        echo "options sx_core fast_boot=0" > $filename
    fi

	/sbin/modprobe 8021q
	RC=$?
	if [ $RC -ne 0 ]; then
		echo_failure $"Loading 8021q: "
		return $RC
	fi

	if [ -z $CHIP_TYPE ]; then
		/sbin/modprobe sx_core cq_thread_sched_priority=98 g_chip_type=1 fast_boot=$FAST_BOOT reset_trigger=$RESET_TRIGGER
	else
		/sbin/modprobe sx_core cq_thread_sched_priority=98 g_chip_type=$CHIP_TYPE fast_boot=$FAST_BOOT reset_trigger=$RESET_TRIGGER
	fi

	RC=$?
	if [ $RC -ne 0 ]; then
		echo_failure $"Loading SX core: "
		return $RC
	fi

        /sbin/modprobe sx_netdev
        RC=$?
        if [ $RC -ne 0 ]; then
                echo_failure $"Loading sx_netdev: "
                return $RC
        fi

	rm -rf /dev/sxdevs
	mkdir /dev/sxdevs
	RC=$?
	if [ $RC -ne 0 ]; then
		echo_failure $"Preparing /dev/sxdevs folder, has service been already started?"
		return $RC
	fi

	major=$(awk -F ' ' '$2 == "sxcdev" { print $1}' /proc/devices)
	mknod -m 666 /dev/sxdevs/sxcdev c $major 193

	RC=$?
	if [ $RC -ne 0 ]; then
		echo_failure $"Preparing /dev/sxdevs/sxcdev major='$major' device"
		return $RC
	fi

       /sbin/modprobe sx_bfd
        RC=$?
        if [ $RC -ne 0 ]; then
                echo_failure $"Loading sx_bfd: "
                return $RC
        fi

    major=$(awk -F ' ' '$2 == "bfdcdev" { print $1}' /proc/devices)
    mknod -m 666 /dev/sxdevs/bfdcdev c $major 193

    RC=$?
    if [ $RC -ne 0 ]; then
        echo_failure $"Preparing /dev/sxdevs/bfdcdev major='$major' device"
        return $RC
    fi

	echo_success $"Loading SX driver: "

	return $RC
}

rm_mod()
{
	local mod=$1
	shift

	unload_log=`/sbin/rmmod $mod 2>&1`
	if [ $? -ne 0 ]; then
		echo_failure $"Unloading $mod"
		if [ ! -z "${unload_log}" ]; then
			echo $unload_log
		fi
		[ ! -z $2 ] && echo $2
		return 1
	fi
}

unload()
{
	# Unload module $1
	local mod=$1
	local unload_log

	if is_module $mod; then
		case $mod in
			*)
			/sbin/modprobe -r $mod
			if [ $? -ne 0 ] || is_module $mod; then
				# Try rmmod if modprobe failed.
				rm_mod $mod || return 1
			fi
			;;
		esac
	fi
}

stop()
{
    local NEED_UNLOAD=0

    if ! is_module sx_netdev ; then
        if [ $RESTART -eq 0 ]; then
            echo
            echo_warning $"SX NETDEV driver is not loaded or loaded with errors"
            echo
        fi
    else
        NEED_UNLOAD=1
    fi


    if ! is_module sx_core ; then
        if [ $RESTART -eq 0 ]; then
            echo
            echo_warning $"SX driver is not loaded or loaded with errors"
            echo
        fi
    else
        NEED_UNLOAD=1
    fi

    if ! is_module 8021q ; then
        if [ $RESTART -eq 0 ]; then
            echo
            echo_warning $"8021q is not loaded or loaded with errors"
            echo
        fi
    else
        NEED_UNLOAD=1
    fi

    if [ $NEED_UNLOAD -eq 0 ]; then
        return 0
    fi

	# Unload modules
	if [ "$UNLOAD_MODULES" != "" ]; then
		for mod in  $UNLOAD_MODULES
		do
			unload $mod
		done
	fi

	local done=0

    # Unload sx_bfd
    if is_module sx_bfd; then
        is_ref sx_bfd
        unload sx_bfd
        done=1
    fi


	# Do not leave the ASIC enabled after sx_sdk is stopped
	# otherwise it may e.g., still DMA across reboot/restart
    # If fastboot is not enabled then reset asic
    filename=/etc/modprobe.d/sx.modprobe.conf
    if grep -q "0" $filename; then
        reset_asic
    fi

	if [ $done -eq 1 ]; then
		echo_success $"Unloading SX driver: "
	fi
	sleep 1
}

status()
{
	local RC=0

	if is_module sx_core; then
		echo
		echo "  SX driver loaded"
		echo
	else
		echo
		echo $"SX driver is not loaded"
		echo
	fi

	local cnt=0

	for mod in  $STATUS_MODULES
	do
		if is_module $mod; then
			[ $cnt -eq 0 ] && echo "The following SX modules are loaded:" && echo
			let cnt++
			echo "  $mod"
		fi
	done

	echo

	return $RC
}


RC=0
start_time=$(date +%s | tr -d '[:space:]')

default_trap_handler()
{
	let run_time=$(date +%s | tr -d '[:space:]')-${start_time}

	# Ask to wait for 5 seconds if trying to stop sx
	if [ $run_time -gt 5 ] && [ "$ACTION" == "stop" ]; then
		printf "\nProbably some application are still using SX modules...\n"
	else
		printf "\nPlease wait ...\n"
	fi
	return 0
}

SCRIPTNAME=$(basename $0)
LOCK_DIR="/var/lock/${SCRIPTNAME}"
PIDFILE="${LOCK_DIR}/PID"

lock()
{
  mkdir $LOCK_DIR 2> /dev/null
  if [ $? == 0 ]; then
     echo $$ > $PIDFILE
     DO_UNLOCK=1
     return 0
  else
    return 1
  fi
}

remove_lock()
{
  rm -rf $LOCK_DIR
}

exit_on_signal()
{
  default_trap_handler
  echo "Kill, cleanup..."
  if [ "$DO_UNLOCK" != "0" ]; then
     remove_lock
  fi
  exit 1
}

exit_on_end()
{
  if [ "$DO_UNLOCK" != "0" ]; then
    remove_lock
  fi
  exit $1
}

lock_failed()
{
  # check for PID
  PID=$(cat $PIDFILE)

  # Maybe there was an error reading the PID file
  if [ $? != 0 ]; then
     echo "$PIDFILE read failed, $SCRIPTNAME is running (PID ${PID})" >&2
     DO_UNLOCK=1
     exit 1
  fi

  # Check if the PID is really existing
  if ! kill -0 $PID &>/dev/null; then
     echo "Removing stale lock of nonexistant PID ${PID}" >&2
     remove_lock
     echo "Restarting myself (${SCRIPTNAME})" >&2
     # On Unix-like operating systems, exec is a builtin command of the Bash shell. 
     # It allows you to execute a command that completely replaces the current process. 
     # The current shell process is destroyed, and entirely replaced by the command you specify.
     exec "$0" $usr_params
  else
     echo "Locking failed, another instance of $SCRIPTNAME is still running (PID ${PID})" >&2
     DO_UNLOCK=0
     exit 1
  fi
}
trap exit_on_signal INT KILL TERM 
trap 'exit_on_end $?' QUIT EXIT

# Lock mechanism to insure sxdkernel run as singleton 
lock || lock_failed

case $ACTION in
	start)
		start
	;;
	stop)
		stop
	;;
	restart)
		RESTART=1
		stop
		start
	;;
	status)
		status
	;;
	*)
		echo
		echo "Usage: `basename $0` {start|stop|restart|status}"
		echo
		exit 1
	;;
esac

RC=$?
exit $RC
