#!/bin/sh
#
# (c) Copyright 2002, 2008 Hewlett-Packard Development Company, L.P.
#
# See "man chkconfig" for information on next two lines (Red Hat only)
# chkconfig: 2345 91 1
# description: hp System Health Monitor and Command line Utility Package. 
#
#
# Following lines are in conformance with LSB 1.2 spec
### BEGIN INIT INFO
# Provides:            hp-health
# Required-Start: 
# Required-Stop: 
# Default-Start:       2 3 4 5
# Default-Stop:        0 1 6
# Description:         starts hpasm (HP System Health Monitor)
### END INIT INFO


#list of known agent that could use this interface
AGENTS="cmahealthd cmastdeqd cmahostd cmathreshd cmasm2d cmarackd cmapeerd cmaeventd cmafcad cmasasd cmaidad cmaided cmascsid cmanicd"
HPOPENIPMI_ROOT="/opt/hp/hp-OpenIPMI"
KVER="$(uname -r)"

PARAM=$1
PFLAGS=""

### Do we need these exports? -dannf
export RETVAL=0
export PNAME
export PFLAGS
export STARTADDON
export STOPADDON
export STATUSADDON

## Is this used anywhere? -dannf
EXTRAMSG="PLEASE WAIT! It may take a few minutes"

#precaution only
## Can these be removed now? -dannf
unset LD_ASSUME_KERNEL
unset LD_LIBRARY_PATH
unset VMWARE

## Do we use any of these functions? -dannf
# source function library
if [ -f /etc/rc.d/init.d/functions ]; then
    . /etc/rc.d/init.d/functions
elif [ -f /etc/rc.config ]; then
    . /etc/rc.config
elif [ -f /etc/rc.d/functions ]; then
    . /etc/rc.d/functions
elif [ -f /etc/rc.status ]; then
    . /etc/rc.status
fi

if [ -z "$LOGFILE" ]; then
   LOGFILE=/var/log/hp-health/hpasmd.log
   if [ ! -d /var/log/hp-health ]; then
      mkdir -p /var/log/hp-health
   fi
fi

cmaerr () {
  printf "  $*\n" >&2
  printf "  $*\n" >>$LOGFILE 2>&1
}

cmaecho () {
  printf "  $*\n"
  printf "  $*\n" >>$LOGFILE 2>&1
}

cmaechon () {
  printf "  $*"
  printf "  $*" >>$LOGFILE 2>&1
}

#different distros put pidof in different places
if [ -x /sbin/pidof ]; then
  PIDOF=/sbin/pidof
elif [ -x /bin/pidof ]; then
  PIDOF=/bin/pidof
fi

showsuccess() {
    if [ -f /etc/rc.d/init.d/functions ]; then
	echo_success
    elif [ -f /etc/rc.status ]; then
	rc_reset
	rc_status -v
    else
	printf "\t\t[ SUCCESS ]\n"
    fi
}

showfailure() {
    if [ -f /etc/rc.d/init.d/functions ]; then
	echo_failure
    elif [ -f /etc/rc.status ]; then
	rc_failed
	rc_status -v
    else
	printf "\t\t[ FAILED ]\n"
    fi
}

stopproc () 
{
   rc=1
   used=`$PIDOF $AGENTS`
   if [ -z "$used" ]; then
	pidlist=`$PIDOF -o $$ $1`
  	for i in `seq 1 25`; do
		if [ -z "$pidlist" ]; then
			rc=0	
			break
		fi
		if [ "$i" = "1" ]; then
			kill $pidlist 2>/dev/null
		elif [ "$i" = "22" ]; then
			kill -9 $pidlist 2>/dev/null
		else
			sleep 1 
		fi
		pidlist=`$PIDOF -o $$ $1`
	done
   fi
   return $rc
}

is_24_kernel() {
    [ "$(uname -r | cut -d. -f1-2)" = "2.4" ]
    return $?
}

is_26_kernel() {
    [ "$(uname -r | cut -d. -f1-2)" = "2.6" ]
    return $?
}

## Checking to see if OS is ESX 4.0 (from VMware)
## return code is 0 = yes, ESX 4.0
## return code is 1 = no, not ESX 4.0 
##
## An assumption here is that only ESX systems would have /usr/bin/vmware
## and ESX 4x is based on the 2.6 kernel
is_OS_VMware4x() {
    RET_STAT=1
    test -x /usr/bin/vmware && is_26_kernel
    if [ $? -eq 0 ]; then
        vmware -v | grep ESX > /dev/null
        if [ $? -eq 0 ]; then
          uname -a | grep ESX > /dev/null
          if [ $? -eq 0 ]; then
                RET_STAT=0
          fi
        fi
      fi
    return $RET_STAT

}

module_name() {
   if is_24_kernel; then
        echo ipmi_si_drv.o
   else
        echo ipmi_si.ko
   fi
}

module_is_loaded() {
    if lsmod | grep -q "$1"; then
	return 0
    fi
    return 1
}

ipmi_loaded() {
    if module_is_loaded ipmi_si && module_is_loaded ipmi_devintf; then
	return 0
    fi
	return 1
}

have_hp_ipmi() {
    test -f "$HPOPENIPMI_ROOT/hp-OpenIPMI"
}

module_path() {
    local module=$(module_name)

    if have_hp_ipmi; then
	echo "$HPOPENIPMI_ROOT/bin/${KVER}/$module"
    else
	echo "/lib/modules/${KVER}/kernel/drivers/char/ipmi/$module"
    fi
}

hp_ipmi_needs_rebuild() {
    local module=$(module_name)

    if [ -f "${HPOPENIPMI_ROOT}/bin/${KVER}/$module" ]; then
	return 1
    else
	return 0
    fi
}

attempt_hp_ipmi_build() {
    cd $HPOPENIPMI_ROOT
    cmaecho "hpasmxld:  Attempting Rebuild of hp-OpenIPMI package" 
    sh check_install_kernel.sh >> $LOGFILE

    if [ $? -ne 0 ]; then
	cmaecho "Can not rebuild the hp-OpenIPMI drivers!"
	cmaecho "See $LOGFILE for details."
	cmaecho "See hp-OpenIPMI(4) and hpasm(4) for options."
	cd -
	exit 99
    else
	cmaecho "hpasmxld:  Successful rebuild of hp-OpenIPMI package" 
    fi
    cd -
}

guess_dev_file() {

    ## NOTE: Testing if OS is VMware must be 1st
    ## because there are certain commands
    ## that are not recognized in the
    ## ESX 4.0 COS ( example: nm, modinfo)
    ## User will see command not recognized
    ## on ESX systems if the other test
    ## conditions are tried

    if is_OS_VMware4x; then
	echo "/dev/ipmi0"
	return
    fi

    if is_supported_100_series; then
	echo "/dev/ipmi0"
	return
    fi

    if have_hp_ipmi; then
	if supports_quiesce_intfs; then
	    echo "/dev/ipmi1"
	    return
	fi
	if ! supports_pci_vend_devs; then
	    # Lightly patched upstream, e.g. SLES11
	    echo "/dev/ipmi1"
	    return
	fi
    else
	if ! is_24_kernel && ! supports_pci_vend_devs && \
	    supports_pci_probe; then
	    echo "/dev/ipmi1"
	    return
	fi
    fi

    echo "/dev/ipmi0"
}

have_distro_ipmi() {
    ## Debian-based distros don't include an ipmi initscript
    if [ -x /usr/bin/dpkg ] && modprobe -n ipmi_si; then
	return 0
    fi

    test -x /etc/init.d/ipmi
    return $?
}

## Check to see if the distro's IPMI drivers are new enough to
## provide feature parity with hp-OpenIPMI
distro_ipmi_is_hpasmxld_compatible() {
    local kpatch="$(echo $KVER | cut -d. -f2)"
    local ksub="$(echo $KVER | sed -r 's/[0-9]+\.[0-9]+\.([0-9]+).*/\1/')"

    # Upstream 2.6.30 is sufficient
    if [ "$kpatch" = 6 ] && [ -n "$ksub" ] && [ "$ksub" -ge 30 ]; then
	return 0
    fi

    # SLES11 SP1 includes the necessary backport
    if [ -f /etc/SuSE-release ]; then
	local slesver="$(grep '^VERSION' /etc/SuSE-release | awk '{print $3}')"
	local slespatch="$(grep '^PATCHLEVEL' /etc/SuSE-release | awk '{print $3}')"
	
	if [ "$slesver" -eq 11 ] && [ "$slespatch" -gt 0 ]; then
	    return 0
	fi
    fi

    return 1
}

config_distro_ipmi() {
    local modopts="$1"
    local modprobe_delay="$2"

    delay=""
    if [ "$modprobe_delay" -gt 0 ]; then
	delay="sleep $modprobe_delay\n\t\t"
    fi

    if [ -f /etc/init.d/ipmi ]; then
	sed "s/modprobe \${IPMI_SI_MODULE_NAME}/${delay}modprobe \${IPMI_SI_MODULE_NAME} $modopts/" /etc/init.d/ipmi > /etc/init.d/ipmi.hp
	chmod 755 /etc/init.d/ipmi.hp
	STARTADDON="/etc/init.d/ipmi.hp start"
	STATUSADDON="/etc/init.d/ipmi.hp status"
    else
	if [ -d /etc/modprobe.d -a -n "$modopts" ]; then
	    cat > /etc/modprobe.d/hp-health <<EOF
# FILE GENERATED BY /etc/init.d/hp-health
# DO NOT EDIT - CHANGES WILL GET OVERWRITTEN
options $(module_name | cut -d. -f1) $modopts
EOF
	fi
        STARTADDON="modprobe -a ipmi_si ipmi_devintf"
        STATUSADDON=":"
    fi
    cmaecho "Using standard Linux IPMI device driver"
}

supports_pci_vend_devs() {
    modinfo -p $(module_path) | grep -q pci_vend_devs
    return $?
}

supports_pci_probe() {
    nm $(module_path) | grep -q ipmi_pci_probe
    return $?
}

supports_quiesce_intfs() {
    modinfo -p $(module_path) | grep -q quiesce_intfs
    return $?
}

# Check for iLO/iLO2
find_ilo() {
    BUSDEV=`lspci -d "0e11:b203" | cut  -d  ' ' -f1` 
    if [ $? -eq 0 -a -n "$BUSDEV" ]; then
	echo "$BUSDEV"
	return 0
    fi
    return 1
}

have_ilo() {
    if find_ilo > /dev/null; then
	return 0
    fi
    return 1
}

have_embedded_health() {
    BUSDEV="$(find_ilo)"
    if [ $? -eq 0 -a -n "$BUSDEV" ]; then
        #We have a management controller, now lets see
        #if it is embedded health
	if lspci -xv -s $BUSDEV | grep -q "3c 10 05 33"; then
            return 0
	fi
    fi
    return 1
}

have_100_series_productname() {
    if [ -z "$(which dmidecode)" ]; then
        cmaerr "Error: Could not find dmidecode utility, unable to identify system"
        return 1
    fi
    cmaechon "Trying to identify the Product Name..."
    PRODNAME=`dmidecode | grep "Product Name" | cut -d" " -f4 | head -n1`
    GENERATION=`dmidecode | grep "Product Name" | cut -d" " -f5 | head -n1`
    PRODNUM=`echo $PRODNAME |  egrep -o '[0-9][0-9][0-9]'`
    if [ "$PRODNUM" -ge 100 -a "$PRODNUM" -lt 200 ] ; then  # TRUE only if the server is 100 series
        if [ "$GENERATION" = "G6" -o "$GENERATION" \> "G6" ]; then  # TRUE only if the server is G6 or higher
            cmaecho "Done"
            return 0
        fi
    fi
    cmaecho ""
    return 1
}

## Used to cache the answer the first time through
SUPPORTED_100_SERIES=""
is_supported_100_series() {
    if [ -z "$SUPPORTED_100_SERIES" ]; then
	SUPPORTED_100_SERIES=1
        # Check if it is an iLO/iLO2 system
        if have_ilo; then
	    return $SUPPORTED_100_SERIES
	fi
	# We need /proc/acpi/dsdt to identify 100series 
	if [ ! -f /proc/acpi/dsdt ]; then
	    cmaerr "ERROR: /proc/acpi/dsdt does not exist"
	    cmaerr "Cannot use ACPI tables to identify system"
	    # Check the Product Name if we cannot parse 
	    # ACPI DSDT table to identify the system
	    if ! have_100_series_productname; then
                cmaerr "ERROR: This server is NOT supported!"
                return $SUPPORTED_100_SERIES
            else
                SUPPORTED_100_SERIES=0
                return $SUPPORTED_100_SERIES
            fi

	fi
	# Search the ACPI IPMI device _HID in 
	# /proc/acpi/dsdt ouptut.
	# For G6 servers, the HID wil be
	# 	Name (_HID, EisaId ("HPQ000B"))
	# In AML(ACPI Machine Language), it can be coded as
	# 	08 5f 48 49 44 0c 22 11 00 0b
	# 5f 48 49 44  -  _HID
	# 22 11 00 0b  -  EISAID ("HPQ000B")
	# 08           -  Name Op
	# Refer ACPI Spec for AML specification.
	# We search the above pattern in ACPI DSDT table. If we
	# find a match, then we conclude that it is a supported
	# 100series server.
	local ACPI_DEV="\x08\x5f\x48\x49\x44\x0c\x22\x11\x00\x0b"
	if [ "$(awk '/'$ACPI_DEV'/ {print 1}' /proc/acpi/dsdt)" ]; then
	    SUPPORTED_100_SERIES=0
	else
	    cmaerr "ERROR: This Server is NOT Supported!"
	fi
    fi
    return $SUPPORTED_100_SERIES
}

config_hp_ipmi() {
    if hp_ipmi_needs_rebuild; then
	attempt_hp_ipmi_build
    fi
    
    if ! ipmi_loaded; then
        STARTADDON="$HPOPENIPMI_ROOT/hp-OpenIPMI start"
    fi

    STATUSADDON="$HPOPENIPMI_ROOT/hp-OpenIPMI status"
}

use_hpasmd() {
    NAME="Proliant System Health Monitor"
    PNAME="hpasmd"
}    

use_hpasmxld() {
    NAME="Proliant High Performance\n \tIPMI based System Health Monitor"
    PNAME="hpasmxld"
    PFLAGS="-f $(guess_dev_file)"
    cmaecho "Using $NAME"
}

use_hpasmlited() {
    NAME="Proliant Standard\n \tIPMI based System Health Monitor"
    PNAME="hpasmlited"
    PFLAGS="-f $(guess_dev_file)"
    cmaecho "Using $NAME"
}

use_hpasmpld() {
    NAME="Proliant Standard\n \tIPMI based 1XX System Health Monitor"
    PNAME="hpasmpld"
    PFLAGS="-f $(guess_dev_file)"
    cmaecho "Using $NAME"
}

SetupIPMI() {

    ## NOTE: This test must be first in this function 
    ## - see comments in guess_dev_file()
    ##   same circumtances apply for this function
    if is_OS_VMware4x; then 
	## IPMI is already in vmkernel, no setup needed
	return 0
    fi

    if ! have_embedded_health && ! is_supported_100_series; then
	## We don't need IPMI
	return 0
    fi

    if have_hp_ipmi; then
	config_hp_ipmi
	return
    fi

    if ! have_distro_ipmi; then
	echo
	cmaecho "ERROR: There is NO IPMI support available on this system!"
	cmaecho "Please install the hp-OpenIPMI package or enable IPMI support"
	cmaecho "for this distribution. Aborting hp-health initialization process!"
	exit 1
    fi

    ## Use distro's IPMI stack ##

    if supports_pci_vend_devs; then
	modopts="${modoptprefix}type=kcs"
	modopts="$modopts ${modoptprefix}pci_vend_devs=0x103c3302"
	modopts="$modopts ${modoptprefix}debug_intfs=0"
    fi

    if is_24_kernel || ! supports_pci_probe; then
	modopts="${modoptprefix}type=kcs"
	modopts="$modopts ${modoptprefix}ports=0xca2"
    fi
    
    if is_24_kernel; then
	modprobe_delay=3
    else
	modprobe_delay=0
    fi

    config_distro_ipmi "$modopts" "$modprobe_delay"
}

DetermineProg() {

    if is_supported_100_series; then
	use_hpasmpld
	return
    fi

    if ! have_embedded_health; then
	use_hpasmd
	return
    fi

    ## NOTE: This test must be first in this function 
    ## - see comments in guess_dev_file()
    ##   same circumtances apply for this function
    if is_OS_VMware4x; then
	use_hpasmlited
	return
    fi

    if have_hp_ipmi; then
	use_hpasmxld
	return
    fi

    if distro_ipmi_is_hpasmxld_compatible; then
	use_hpasmxld
	return
    fi

    use_hpasmlited
}

start_proc() {

    $STARTADDON
    RETVAL=$?
    if [ $RETVAL -eq 0 ]; then
        if [ "$PNAME" = "hpasmxld" ]; then
            cmaecho "Starting Proliant High Performance"
            cmaechon "IPMI based System Health Monitor ($PNAME): "
        else
            cmaechon "Starting $NAME ($PNAME): "
        fi

        pidlist=`$PIDOF -o $$ $PNAME`

        if [ -z "$pidlist" ]; then
            $PNAME $PFLAGS < /dev/null >> $LOGFILE 2>&1
            RETVAL=$?
            if [ $RETVAL -eq 0 ]; then
               if [ -f /etc/redhat-release ]; then
			touch /var/lock/subsys/hp-health
		fi
            fi
        else
            RETVAL=1
        fi
    fi
}

stop_proc()
{
    if [ "$PNAME" = "hpasmxld" ]; then
        cmaecho "Shutting down Proliant High Performance"
        cmaechon "IPMI based System Health Monitor ($PNAME): "
    else
        cmaechon "Shutting down $NAME ($PNAME): "
    fi

    pidlist=`$PIDOF -o $$ $PNAME`

    if [ -z "$pidlist" ]; then
        RETVAL=1
    else
        stopproc $PNAME
        RETVAL=$?
        if [ $RETVAL -eq 0 ]; then
               [ -f /etc/redhat-release ] && rm -rf /var/lock/subsys/hp-health
        fi
        if [ $RETVAL -eq 1 ]; then
            showfailure
            cmaecho
            cmaecho "($PNAME) may be in use. Please stop all agents before stopping hp-health"
            exit 1
        fi

        if [ -n "$STOPADDON" ]; then
            cmaecho
        fi
    fi

    $STOPADDON
}


DetermineProg
SetupIPMI

#both hpasmxld and hpasmlited depend on the output 
#of IrqRouteTbl so run it now
if [ "$PNAME" != "hpasmd" -a "$1" = "start" ]; then 
   if [ -x /opt/hp/hp-health/bin/IrqRouteTbl ]; then
      /opt/hp/hp-health/bin/IrqRouteTbl
   fi
fi

RETVAL=0
PATH=/opt/hp/hp-health/bin:$PATH
case "$1" in
  start)
        start_proc
	;;
  stop)
	stop_proc
	;;
  restart)
	stop_proc
	RETVAL=$?
        if [ $RETVAL -eq 0 ]; then
	   showsuccess
           cmaecho
           start_proc
	   RETVAL=$?
	else
           showfailure
           pidlist=`$PIDOF -o $$ $PNAME`
           if [ -z "$pidlist" ]; then
                start_proc
                RETVAL=$?
           fi
	fi
        if [ $RETVAL -eq 0 ]; then
           showsuccess
        else
           showfailure
        fi
	;;
  status)
      
        if [ -n "$STATUSADDON" ]; then
	   cmaecho
        fi
	$STATUSADDON
	cmaecho
        if [ -f /etc/rc.status ]; then
           cmaechon "$PNAME is ..."
           checkproc $PNAME
           rc_status -v
           exit 0
        else
           pid=`$PIDOF -o $$ -o $PPID -o %PPID -x $PNAME`
           if [ -n "$pid" ]; then
                   cmaechon "($PNAME) is running..."
           else
                   cmaechon "($PNAME) is stopped..."
           fi
	   RETVAL=$?
        fi
	;;
  *)
	cmaecho "Usage: /etc/init.d/hp-health {start|stop|restart|status}"
	exit 1
        ;;
esac

if [ "$1" != "restart" ]; then
   if [ $RETVAL -eq 0 ]; then
      showsuccess
   else
      showfailure
   fi
fi

cmaecho

exit $RETVAL
