#!/bin/sh
#############################################################################
#
# ipmi:		OpenIPMI Driver init script
#
# Authors:	Matt Domsch <Matt_Domsch@dell.com>
#               Chris Poblete <Chris_Poblete@dell.com>
#
# chkconfig: 2345 14 70
# description: OpenIPMI Driver init script
#
###
### The following new-style init info ought to allow `chkconfig` to
### start OpenIPMI before its clients, but some clients don't mention
### their dependency in their own init info.  Since `chkconfig` acts
### badly when both sets of init info are present, we have to choose the
### old style which allows us to force early start / late stop.
###
##### BEGIN INIT INFO
### Provides: ipmidrv
### Required-Start: $localfs $remotefs $syslog
### Required-Stop: $localfs $remotefs $syslog
### Default-Start: 2 3 5
### Default-Stop:
### Short-Description: OpenIPMI Driver init script
### Description: OpenIPMI Driver init script
##### END INIT INFO
#
# Status return code bits
# no bits set = no errors
# bit 0 set = minimum modules aren't loaded
# bit 1 set = requested feature module isn't loaded
# bit 2 set = /dev/ipmi0 (or /dev/imb if using that instead) doesn't exist
# bit 3 set = /dev/watchdog doesn't exist
# bit 4 set = lockfile doesn't exist
# bit 5 set = modules are loaded even when asked to be unloaded

#
#############################################################################
# for log_success_msg and friends
if [ -r /lib/lsb/init-functions ]; then
# LSB, SLES, ...
    . /lib/lsb/init-functions
elif [ -r /etc/init.d/functions ]; then
# Red Hat / VMware
    . /etc/init.d/functions
    my_log_message()
    {
	ACTION=$1
	shift
	
	case "$ACTION" in
	    success)
		echo -n $*
		success "$*"
		echo
		;;
	    failure)
		echo -n $*
		failure "$*"
		echo
		;;
	    warning)
		echo -n $*
		warning "$*"
		echo
		;;
	    *)
		;;
	esac
    }
    log_success_msg()
    {
	my_log_message success "$*"
    }
    log_failure_msg()
    {
	my_log_message failure "$*"
    }
    log_warning_msg()
    {
	my_log_message warning "$*"
    }
fi

CONFIGFILE=/etc/sysconfig/ipmi
# source config info
[ -r ${CONFIGFILE} ] && . ${CONFIGFILE}

#############################################################################
# GLOBALS
#############################################################################
MODULE_NAME="ipmi"
MAX_INTF_COUNT=10	# limit is MAX_DEVICES (10) in ipmi_devintf.c
MAX_INTF_CLEAN=10	# clean the full 10 so old nodes are removed

IPMI_SMB_MODULE_NAME="ipmi_smb"
IPMI_SI_MODULE_NAME="ipmi_si"
kernel=`uname -r | cut -d. -f1-2`
if [ "${kernel}" == "2.4" ]; then
    IPMI_SMB_MODULE_NAME="ipmi_smb_intf"
    IPMI_SI_MODULE_NAME="ipmi_si_drv"
fi

MODULES_INTERFACES=""
[ "${DEV_IPMI}" = "yes" ] && MODULES_INTERFACES="${MODULES_INTERFACES} ipmi_devintf"
[ "${IPMI_IMB}" = "yes" ] && MODULES_INTERFACES="${MODULES_INTERFACES} ipmi_imb"

MODULES_FEATURES=""
[ "${IPMI_WATCHDOG}" = "yes" ] && MODULES_FEATURES="${MODULES_FEATURES} ipmi_watchdog"
[ "${IPMI_POWEROFF}" = "yes" ] && MODULES_FEATURES="${MODULES_FEATURES} ipmi_poweroff"

MODULES_HW=""
[ "${IPMI_SI}"  = "yes" ] && MODULES_HW="${MODULES_HW} ${IPMI_SI_MODULE_NAME}"
[ "${IPMI_SMB}" = "yes" ] && MODULES_HW="${MODULES_HW} ${IPMI_SMB_MODULE_NAME}"

MODULES_BASE="ipmi_msghandler"
MODULES="${MODULES_INTERFACES} ${MODULES_FEATURES} ${MODULES_HW} ${MODULES_BASE}"

RETVAL=0
LOCKFILE=/var/lock/subsys/ipmi
DEV_IPMI_TIMEOUT=15

#############################################################################
# NOTES:
# * /dev/ipmi0 is unconditionally deleted here on ipmi_devintf unload,
#   because SLES9 and RHEL4 kernels don't send a message for udev to delete
#   it for us.
# 
#############################################################################

modules_loaded_verbose()
{
	OnePlusLoaded=0
	OnePlusUnloaded=0
	for m in $@; do
		if /sbin/lsmod | grep $m >/dev/null 2>&1 ; then
			echo "$m module loaded."
			OnePlusLoaded=1
		else
			echo "$m module not loaded."
			OnePlusUnloaded=1
		fi
	done
}

modules_loaded()
{
	OnePlusLoaded=0
	OnePlusUnloaded=0
	for m in $@; do
		if /sbin/lsmod | grep $m >/dev/null 2>&1 ; then
			OnePlusLoaded=1
		else
			OnePlusUnloaded=1
		fi
	done
}

device_node_exists ()
{
	if [ -e "$1" ]; then
		echo "$1 exists."
		return 1
	fi
	echo "$1 does not exist."
	return 0
}

minimum_modules_loaded()
{
        rc_base=1
	rc_hw=1
        modules_loaded_verbose "${MODULES_BASE}"
	[ ${OnePlusLoaded} -eq 0 ] && rc_base=0
	    
	modules_loaded_verbose "${MODULES_HW}"
	[ ${OnePlusLoaded} -eq 0 ] && rc_hw=0
	
	return $((rc_base && rc_hw))
}

#############################################################################

load_si()
{
	if [ "${IPMI_SI}" = "yes" ]; then
		# Light up "HP iLO 2 Advanced" BMC, if available
		if [ "" != "`lspci -d 103c:3302`" ]; then
			# Removed the unnecessary {} here to prevent
			# another script from mis-editing this line.
			modprobe $IPMI_SI_MODULE_NAME si_type=kcs si_pci_vend_devs=0x103c3302 > /dev/null 2>&1
			modules_loaded ${IPMI_SI_MODULE_NAME}
		else
			OnePlusLoaded=0
		fi
		if [ ${OnePlusLoaded} -ne 1 ]; then
			# Removed the unnecessary {} here to prevent
			# another script from mis-editing this line.
			modprobe $IPMI_SI_MODULE_NAME > /dev/null 2>&1
			modules_loaded ${IPMI_SI_MODULE_NAME}
		fi
		[ ${OnePlusLoaded} -ne 1 ] && RETVAL=$((RETVAL | 1))
	fi
}

load_smb()
{
	if [ "${IPMI_SMB}" = "yes" ]; then
		modprobe ${IPMI_SMB_MODULE_NAME} > /dev/null 2>&1
		modules_loaded ${IPMI_SMB_MODULE_NAME}
		[ ${OnePlusLoaded} -ne 1 ] && RETVAL=$((RETVAL | 1))
	fi
}

load_hw_modules()
{
	load_si
	load_smb
}

start_watchdog_common()
{
	load_hw_modules
	modprobe ipmi_watchdog ${IPMI_WATCHDOG_OPTIONS} > /dev/null 2>&1
	modules_loaded ipmi_watchdog
	[ ${OnePlusUnloaded} -ne 0 ] &&
		RETVAL=$((RETVAL | 2)) &&
		log_failure_msg &&
		return
	if [ ! -x /sbin/udev -a ! -e /dev/watchdog ]; then
		mknod -m 0600 /dev/watchdog c 10 130
		[ $? -ne 0 ] &&
			RETVAL=$((RETVAL | 8)) &&
			log_failure_msg &&
			return
	fi
	log_success_msg
}

start_watchdog_quiet()
{
	[ "${IPMI_WATCHDOG}" != "yes" ] &&
		return
	echo -n $"Starting ipmi_watchdog driver: "
	start_watchdog_common
}

start_watchdog()
{
	echo -n $"Starting ipmi_watchdog driver: "
	[ "${IPMI_WATCHDOG}" != "yes" ] &&
		RETVAL=$((RETVAL | 2)) &&
		log_failure_msg "not configured" &&
		return
	start_watchdog_common
}

stop_watchdog()
{
	echo -n $"Stopping ipmi_watchdog driver: "
	#modprobe -q -r ipmi_watchdog > /dev/null 2>&1
	modules_loaded ipmi_watchdog
	if [ ${OnePlusLoaded} -ne 0 ]; then
	    RETVAL=$((RETVAL | 32))
	    log_failure_msg
	else
	    if [ "${IPMI_WATCHDOG}" = "yes" ]; then
		[ ! -x /sbin/udev ] && rm -f /dev/watchdog
	    fi
	    log_success_msg
	fi
}

stop_watchdog_quiet()
{
	modprobe -q -r ipmi_watchdog > /dev/null 2>&1
	modules_loaded ipmi_watchdog
	if [ ${OnePlusLoaded} -ne 0 ]; then
	    RETVAL=$((RETVAL | 32))
	else
	    if [ "${IPMI_WATCHDOG}" = "yes" ]; then
		[ ! -x /sbin/udev ] && rm -f /dev/watchdog
	    fi
	fi
}

start_powercontrol_common()
{
	local poweroff_opts=""
	load_hw_modules
	if [ "${IPMI_POWERCYCLE}" == "yes" ]; then
	    modinfo ipmi_poweroff 2>/dev/null | grep poweroff_control > /dev/null 2>&1 && \
		poweroff_opts="poweroff_control=2"
	    modinfo ipmi_poweroff 2>/dev/null | grep poweroff_powercycle > /dev/null 2>&1 && \
		poweroff_opts="poweroff_powercycle=1"
	fi
	modprobe ipmi_poweroff "${poweroff_opts}" > /dev/null 2>&1
	modules_loaded ipmi_poweroff
	[ ${OnePlusUnloaded} -ne 0 ] &&
		RETVAL=$((RETVAL | 2)) &&
		log_failure_msg &&
		return
	log_success_msg
}

start_powercontrol_quiet()
{
	[ "${IPMI_POWEROFF}" != "yes" ] &&
		return
	echo -n $"Starting ipmi_poweroff driver: "
	start_powercontrol_common
}

start_powercontrol()
{
	echo -n $"Starting ipmi_poweroff driver: "
	[ "${IPMI_POWEROFF}" != "yes" ] &&
		RETVAL=$((RETVAL | 2)) &&
		log_failure_msg "not configured" &&
		return
	start_powercontrol_common
}

stop_powercontrol()
{
	echo -n $"Stopping ipmi_poweroff driver: "
	modprobe -q -r ipmi_poweroff > /dev/null 2>&1
	modules_loaded ipmi_poweroff
	if [ ${OnePlusLoaded} -ne 0 ]; then
	    RETVAL=$((RETVAL | 32))
	    log_failure_msg
	else
	    log_success_msg
	fi
}

stop_powercontrol_quiet()
{
	modprobe -q -r ipmi_poweroff > /dev/null 2>&1
	modules_loaded ipmi_poweroff
	[ ${OnePlusLoaded} -ne 0 ] && RETVAL=$((RETVAL | 32))
}

#############################################################################
remove_dev_nodes()
{
	INTF_NUM=0
	while [ $INTF_NUM -lt $MAX_INTF_CLEAN ]; do
		rm -f /dev/ipmi${INTF_NUM}
		INTF_NUM=$((INTF_NUM + 1))
	done
}

#############################################################################
unload_all_ipmi_modules()
{
	stop_watchdog_quiet
	stop_powercontrol_quiet
	for m in ${MODULES}; do
		modprobe -q -r ${m} > /dev/null 2>&1
	done
        # delete interface node ONLY if ipmi_devintf is unloaded
        [ `lsmod | grep -c "ipmi_devintf"` -eq 0 ] &&
		remove_dev_nodes
}

unload_ipmi_modules_leave_features()
{
	for m in ${MODULES_INTERFACES}; do
		modprobe -q -r ${m} > /dev/null 2>&1
	done
        # delete interface node ONLY if ipmi_devintf is unloaded
        [ `lsmod | grep -c "ipmi_devintf"` -eq 0 ] &&
		remove_dev_nodes
	lsmod | egrep -q "ipmi_(poweroff|watchdog)" > /dev/null 2>&1
	if [ "$?" -ne "0" ]; then
		stop_watchdog_quiet
		stop_powercontrol_quiet
		for m in ${MODULES}; do
			modprobe -q -r ${m} > /dev/null 2>&1
		done
	fi
}

#############################################################################
load_ipmi_modules ()
{
	local locdelay
	modprobe ipmi_msghandler > /dev/null 2>&1
	modules_loaded ipmi_msghandler
	[ ${OnePlusLoaded} -ne 1 ] && unload_all_ipmi_modules && RETVAL=$((RETVAL | 1)) && return
	load_hw_modules
	[ $((RETVAL & 1)) -eq 1 ] && unload_all_ipmi_modules && RETVAL=$((RETVAL | 1)) && return

	if [ "${DEV_IPMI}" = "yes" ]; then
		modprobe ipmi_devintf > /dev/null 2>&1
		modules_loaded ipmi_devintf
		RETVAL=$((RETVAL & ~2))
		[ ${OnePlusLoaded} -eq 0 ] && RETVAL=$((RETVAL | 2))
		if [ ${OnePlusLoaded} -eq 1 ]; then
			if [ ! -x /sbin/udev ]; then
				remove_dev_nodes
				DEVMAJOR=`cat /proc/devices | awk '/ipmidev/{print $1}'`
				INTF_NUM=0
				while [ $INTF_NUM -lt $MAX_INTF_COUNT ]; do
					if [ -d /proc/ipmi/$INTF_NUM ]; then
						mknod -m 0600 /dev/ipmi${INTF_NUM} c ${DEVMAJOR} $INTF_NUM || RETVAL=$((RETVAL | 4))
					fi
					INTF_NUM=$((INTF_NUM + 1))
				done
			else
				# udev can take several seconds to create /dev/ipmi0, 
				# but it happens asynchronously, so delay here
				locdelay=${DEV_IPMI_TIMEOUT}
				while [ ! -e /dev/ipmi0 -a ${locdelay} -gt 0 ]; do
					locdelay=$((locdelay - 1))
					sleep 1
				done
			fi
		fi
	fi

	if [ "${IPMI_IMB}" = "yes" ]; then
		modprobe ipmi_imb > /dev/null 2>&1
		modules_loaded ipmi_imb
		RETVAL=$((RETVAL & ~2))
		[ ${OnePlusLoaded} -eq 0 ] && RETVAL=$((RETVAL | 2))
		if [ ${OnePlusLoaded} -eq 1 ]; then
			DEVMAJOR=`cat /proc/devices | awk '/imb/{print $1}'`
			rm -f /dev/imb
			mknod -m 0600 /dev/imb c ${DEVMAJOR} 0 || RETVAL=$((RETVAL | 4))
		fi
	fi

	# Per Corey Minyard, essentially no one uses ipmi_radisys
	# and we don't want to encourage its further use
	# so it won't be handled here.
	return
}

#############################################################################
start()
{
	echo -n "Starting ${MODULE_NAME} drivers: "
	load_ipmi_modules
	if [ ${RETVAL} -eq 0 ]; then
		touch ${LOCKFILE} && log_success_msg
	else
		if [ $((RETVAL & 1)) -eq 1 ]; then
			log_failure_msg
		else
			touch ${LOCKFILE} && log_warning_msg
		fi
	fi
	start_watchdog_quiet
	start_powercontrol_quiet
}

#############################################################################
stop()
{
# VMWARE {
# 	echo -n "Stopping ${MODULE_NAME} drivers: "
# 	unload_ipmi_modules_leave_features
# 	modules_loaded ${MODULES_INTERFACES}
# 	if [ ${OnePlusLoaded} -ne 0 ]; then
# 		RETVAL=$((RETVAL | 32))
# 		log_failure_msg "may be in use"
# 	else
# 		rm -f ${LOCKFILE}
# 		log_success_msg
# 	fi
# } VMWARE
	success "$*"
}

stop_all()
{
# VMWARE {
# 	echo -n $"Stopping all ${MODULE_NAME} drivers: "
# 	unload_all_ipmi_modules
# 	modules_loaded ${MODULES}
# 	if [ ${OnePlusLoaded} -ne 0 ]; then
# 		RETVAL=$((RETVAL | 32))
# 		log_failure_msg "may be in use"
# 	else
# 		rm -f ${LOCKFILE}
# 		log_success_msg
# 	fi
# } VMWARE
	success "$*"
}

#############################################################################
restart()
{
#VMWARE {
# 	stop_all
# 	RETVAL=0
# 	start
# } VMWARE
	if [ ! -e ${LOCKFILE} ]; then
		start
	else
		success "$*"
	fi
}

#############################################################################
ipmi_nodes_exist()
{
	RETVAL=0
	INTF_NUM=0
	while [ $INTF_NUM -lt $MAX_INTF_COUNT ]; do
	    if [ $INTF_NUM -eq 0 -o -d /proc/ipmi/$INTF_NUM ]; then
		device_node_exists /dev/ipmi${INTF_NUM}
		[ $? -eq 0 ] && RETVAL=$((RETVAL | 4))
	    fi
	    INTF_NUM=$((INTF_NUM + 1))
	done
	return $RETVAL
}

status_all()
{
	minimum_modules_loaded
	[ $? -eq 0 ] && RETVAL=$((RETVAL | 1))
	
	modules_loaded_verbose ${MODULES_FEATURES} ${MODULES_INTERFACES}
	[ ${OnePlusUnloaded} -ne 0 ] && RETVAL=$((RETVAL | 2))

	if [ "${DEV_IPMI}" = "yes" ]; then 
	    ipmi_nodes_exist
	    RETVAL=$((RETVAL | $?))
	fi

	if [ "${IPMI_IMB}" = "yes" ]; then
	    device_node_exists /dev/imb
	    [ $? -eq 0 ] && RETVAL=$((RETVAL | 4))
	fi

	if [ "${IPMI_WATCHDOG}" = "yes" ]; then
	    device_node_exists /dev/watchdog
	    [ $? -eq 0 ] && RETVAL=$((RETVAL | 8))
	fi

	[ ! -e ${LOCKFILE} ] && RETVAL=$((RETVAL | 16))
}

status()
{
	minimum_modules_loaded
	[ $? -eq 0 ] && RETVAL=$((RETVAL | 1))
	
	if [ "${DEV_IPMI}" = "yes" ]; then 
	    modules_loaded_verbose ipmi_devintf
	    [ ${OnePlusLoaded} -eq 0 ] && RETVAL=$((RETVAL | 2))

	    ipmi_nodes_exist
	    RETVAL=$((RETVAL | $?))
	fi

	if [ "${IPMI_IMB}" = "yes" ]; then
	    device_node_exists /dev/imb
	    [ $? -eq 0 ] && RETVAL=$((RETVAL | 4))
	fi
}

status_watchdog()
{
	minimum_modules_loaded
	[ $? -eq 0 ] && RETVAL=$((RETVAL | 1))

	modules_loaded_verbose ipmi_watchdog
	[ ${OnePlusLoaded} -eq 0 ] && RETVAL=$((RETVAL | 2))

	device_node_exists /dev/watchdog
	[ $? -eq 0 ] && RETVAL=$((RETVAL | 8))
}

status_powercontrol()
{
	minimum_modules_loaded
	[ $? -eq 0 ] && RETVAL=$((RETVAL | 1))

	modules_loaded_verbose ipmi_powercontrol
	[ ${OnePlusLoaded} -eq 0 ] && RETVAL=$((RETVAL | 2))
}

#############################################################################
usage ()
{
	echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart" 1>&2
	echo $"          start-watchdog|stop-watchdog|status-watchdog" 1>&2
	echo $"          start-powercontrol|stop-powercontrol|status-powercontrol" 1>&2
	echo $"          stop-all|status-all}" 1>&2
	RETVAL=1
}

condrestart ()
{
	[ -e ${LOCKFILE} ] && restart
}

#############################################################################
# MAIN
#############################################################################
case "$1" in
	start) start ;;
	stop)  stop ;;
	restart) restart ;;
	status)	status ;;
	status-all) status_all ;;
	condrestart) condrestart ;;
	try-restart) condrestart ;;
	start-watchdog) start_watchdog ;;
	stop-watchdog) stop_watchdog ;;
	status-watchdog) status_watchdog ;;
	start-powercontrol) start_powercontrol ;;
	stop-powercontrol) stop_powercontrol ;;
	status-powercontrol) status_powercontrol ;;
	stop-all) stop_all ;;
	*) usage ;;
esac

exit ${RETVAL}

#############################################################################
# end of file
#############################################################################

