#!/bin/sh
#
# description: Loads and configures the EMC PowerPath drivers.
#
# ###################################################################
# Copyright (c) 2000, EMC Corporation. All Rights Reserved.
#
# Most Recent Author: Raghu Adabala
# Previous Authors: Raghu Adabala and Ed Goggin
#
# Contents:
# Redhat support for load and configure of EMC PowerPath drivers
# ###################################################################
#

# @(#) $Header: /cvs/source/master/pp2dev/src/pkg/i386_linux/PowerPath.rhel,v 1.3 2005/06/06 05:10:00 dass Exp $


# Functions to preserve exceptional command status return values

rc_reset()
{
    rc_cmd_stat=0
    rc_script_stat=0
}

rc_check()
{
    rc_cmd_stat=$?
    test $rc_cmd_stat -ne 0 && rc_script_stat=$rc_cmd_stat
    return $rc_cmd_stat
}

rc_status()
{
    rc_check

    if [ "$1" = "-v" ]
        then
        case "$rc_script_stat" in
            0)
              echo "`eval_gettext \" done\"`"
              ;;
            *)
              echo "`eval_gettext \" failed\"`"
              ;;
        esac
    fi
    return $rc_script_stat
}

rc_exit()
{
    exit $rc_script_stat
}

#
# ###################################################################
# Copyright (c) 2005, EMC Corporation. All Rights Reserved.
#
#
# Contents:
# This scripts loads and configures the EMC PowerPath driver(s) on 
# bootup and uloads PowerPath on shutdown.
# ###################################################################
#

# @(#) $Header: /cvs/source/master/pp2dev/src/pkg/i386_linux/PowerPath.common,v 1.24 2006/01/20 09:53:55 sachis Exp $

PATH=/usr/bin/:/bin:/sbin:/usr/sbin
PPBASE="/etc/opt/emcpower/EMCpower.LINUX-5.1.2.00.00"

# the following are the internationalization specific lines

if [ ! -x /usr/bin/gettext ]; then
gettext()
{
 echo "$*"
}
eval_gettext()
{
 eval "echo \"$*\""
}

else
. gettext.sh
TEXTDOMAIN=PowerPath
export TEXTDOMAIN
TEXTDOMAINDIR=$PPBASE/i18n/catalog

export TEXTDOMAINDIR
export RPM_INSTALL_PREFIX
fi
# end of internationalization


pp_stop_lvm()
{
    if test -x /sbin/vgchange -a -x /sbin/vgscan ; then
        open_vol=""
        vgname=`vgdisplay 2>/dev/null| grep "VG Name" | sed -e 's/VG Name/ /g'`
        for i in $vgname
        do
                pv=`vgdisplay -v $i 2>/dev/null| grep "PV Name"  | awk '{ print $3 }' | grep emcpower`
		if [ "$pv" != "" ] ; then
                        err_stop=`/sbin/vgchange -a n $i  2>&1 | grep "open logical volume"`
                        if [ "$err_stop" != "" ]; then
                                if [ "$open_vol" = "" ]; then
                                        echo "`eval_gettext \"Following LVM volume groups are in use:\"`"
                                        open_vol=$err_stop
                                fi
			var1=$i
			var2=`echo $pv`
                        echo "`eval_gettext \"      Volume Group: \\$var1 (\\$var2)\"`"
                        fi
                fi
        done
    fi
        if [ "$open_vol" != "" ]; then
            echo "`eval_gettext \"These open logical volume devices use LUNs from Powerpath managed devices,\"`"
            echo "`eval_gettext \"Please re-issue the command after closing these volumes.\"`"
	return 1
        fi
 return 0
}

pp_start_lvm()
{
   if test -x /sbin/vgchange -a -x /sbin/vgscan ; then
      /sbin/vgscan > /dev/null 2>&1
      /sbin/vgchange -a y > /dev/null 2>&1
      if [ $? -eq 5 ]; then  ## "no volume groups" ==> success
        /bin/true
      fi
   fi
}
# Wait for /dev/emcpower to appear.
# $1 is the number of seconds to wait.

dev_emcpower_is_back()
{
    /bin/bash -c "for ((cnt=$1/3; \$cnt > 0; cnt--)); do \
                      test -c /dev/emcpower && break; \
                      sleep 3; \
                  done; \
                  test -c /dev/emcpower"
}


# Start 32 bit Emulation library before powerpath startup for ia64
start_32bit_emulation()
{
    /etc/init.d/ia32el start  > /dev/null 2>&1
    rc_check

    if rc_status ; then
        echo -e "`eval_gettext \"\nSuccessfully started 32-bit emulation library\"`"
    else
        echo -e "`eval_gettext \"\nError in starting 32-bit emulation library\"`"
    fi
}

# Configure PowerPath paths

configure_pp()
{
    if [ -f /etc/emcp_devicesDB.dat ]; then 
        if [ -f /etc/emcp_devicesDB.idx ]; then
            /etc/opt/emcpower/emcpmgr map -p > /dev/null 2>&1
            rc_check
        fi
    fi

    ## If the system has no license, config error is ok.

    if /sbin/emcpreg -l 2>&1 | /usr/bin/grep '^Key' > /dev/null 2>&1; then
        /sbin/powermt config > /dev/null 2>&1
    else
        /sbin/powermt config > /dev/null 2>&1
        /bin/true
    fi
    rc_check

    #  Wait for udev to finish creating emcpower devices
    #
    pdfound=1
    for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
        pdfound=1
    	for pd in `/bin/ls -d /sys/block/emcpower* 2> /dev/null`; do
           bpd=`basename $pd`
           if [ ! -e /dev/$bpd ]; then
              pdfound=0
              sleep 2
              break;
           fi
        done
        if [ "$pdfound" -eq 1 ]; then
	   break
        fi
    done
    if [ "$pdfound" -eq 0 ]; then
       [ 1 = 0 ]
       rc_check
    fi

    /sbin/powermt load		> /dev/null 2>&1
    rc_check
    /etc/opt/emcpower/emcpmgr map	> /dev/null 2>&1
    rc_check
    /etc/opt/emcpower/powercf -C	> /dev/null 2>&1
    if [ ! -e /etc/powermt.custom ]; then 
       /sbin/powermt save		> /dev/null 2>&1
       rc_check
    fi 
    /sbin/powermt register	> /dev/null 2>&1
    rc_check
    /sbin/powermig transition -startup -noprompt   > /dev/null 2>&1
    rc_check
    pp_start_lvm
}

# Check for naviagent and powermt before stopping PowerPath

ok_to_stop()
{
    ps -C naviagent >> /dev/null
    if [ $? -eq 0 ]; then
        echo "`eval_gettext \"Navisphere agent is running.\"`"
        echo  "`eval_gettext \"Please stop the agent and then re-issue \\$script_name stop.\"`"
        return 1
    fi

    ps -C powermt >> /dev/null
    if [ $? -eq 0 ]; then
        echo "`eval_gettext \"The powermt command is running.\"`"
        echo "`eval_gettext \"Please stop powermt and then re-issue \\$script_name stop.\"`"
        return 1
    fi

    mig_info=`/sbin/powermig info -all`
    if [ $? -eq 0 ]; then
        echo "$mig_info" | grep 'No migrations found' > /dev/null
        if test $? -ne 0 ; then 
            echo "`eval_gettext \"PowerPath migrations are present.\"`"
            echo "`eval_gettext \"Please cleanup the migrations and then re-issue \\$script_name stop.\"`"
            return 1
        fi
    fi

    if pp_stop_lvm ; then
        return 0
    fi
    return 1
}

#  Load the extensions.  Dependencies will load base driver.
#  Before load base driver, address of kallsysms_lookup name must be
#  obtained and passed to emcp as emcplu parameter.

load_drivers()
{
    klh=`cat /proc/kallsyms | grep -w 'kallsyms_lookup_name' | awk '{ print $1 }'`
    emcpo=`cat /etc/modprobe.conf.pp | grep -w "options emcp"`
    cat /etc/modprobe.conf.pp | grep -v -w "options emcp" > /tmp/modprobe.conf.pp

    if [ "$emcpo" == "" ]; then
       # no entry yet in modprobe.conf.pp
       echo "options emcp emcplu=0x$klh" >> /tmp/modprobe.conf.pp
    else
       # some emcp options entry found
       oline=`cat /etc/modprobe.conf.pp | grep -w "options emcp" | sed -s 's/emcplu=0x[a-f0-9]*//'`
       echo "$oline emcplu=0x${klh}" >> /tmp/modprobe.conf.pp
    fi
    cp /tmp/modprobe.conf.pp /etc/modprobe.conf.pp

    # Call depmod to generate modules.dep before drivers are loaded.
    # This used to be done by "powercf -m", which is called so oftern, it
    # resulted in many unnecessary depmod calls. 
    /sbin/depmod -a > /dev/null 2>&1

    #/sbin/modprobe -q $mod
    #rc_check
    #if [ $? -ne 0 ]; then
    #     echo "`eval_gettext \"PowerPath could not load emcp module`"
    #     return 1
    #fi
		
    for d in `cat $ext; cat $mgr`
    do
        /sbin/modprobe -q -s --first-time $d
        rc_check
        if [ $? -ne 0 ] ; then
            echo "`eval_gettext \"PowerPath could not load module \\$d\"`"
            break
        fi
    done

    if dev_emcpower_is_back 60; then
        recreate_emcpower_device
        /etc/opt/emcpower/powercf -K        > /dev/null 2>&1
        rc_check
    else
        rc_check
        unload_drivers
    fi

    if rc_status ; then
        /sbin/modprobe -q -s --first-time emcpioc
        rc_check
        if [ $? -eq 0 ] ; then
            /sbin/modprobe -r -q -s --first-time emcpioc
        fi
    fi
}

# Unload drivers and extensions.

unload_drivers()
{
    # Call depmod to generate the module dependencies before the unload
    /sbin/depmod -a > /dev/null 2>&1

    do_unload=0
    retry=4
    powermt prep_drv_unload > /dev/null 2>&1


    ###
    ### At this point, we really want the driver unload to succeed
    ### Try hard to make it happen.
    ###
    while [ $retry -gt 0 ]
    do
        powermt remove dev=all 2> /var/tmp/.pp_exit
        devr=$?
        cat /var/tmp/.pp_exit | grep "not found" > /dev/null 2>&1
        cdevs=$?
        zerolen=`cat /var/tmp/.pp_exit | wc -c`
        rm /var/tmp/.pp_exit
        # reset rc status since we are not willing to
        # report an error just yet.
        rc_reset
        if [ $devr -eq 0 ] ; then
            do_unload=1
            retry=0 #success
        else
            if [ $cdevs -eq 0 -o $zerolen -eq 0 ] ; then
                do_unload=1
                retry=0 #success
            else
                sleep 5
                retry=`expr $retry - 1`
            fi
        fi
    done
    
    if [ $do_unload -eq 1 ] ; then
       /sbin/modprobe -r -q -s  `cat $mgr; cat $ext; echo emcp`
       uerr=$?
       return $uerr
    else
       echo "`eval_gettext \"PowerPath devices are open.\"`"
       echo "`eval_gettext \"Please close these devices and then re-issue \\$script_name stop.\"`"
       /bin/false
       uerr=$?
       return $uerr
    fi

    echo "`eval_gettext \"PowerPath could not unload PowerPath modules.\"`"
    uerr=1
    return $uerr
}

recreate_emcpower_device()
{
    #
    # Create /dev/emcpower based on CURRENT misc driver.
    # These values can be different when PP loads from RD.
    #
    rm -f /dev/emcpower
    mmaj=`cat /sys/class/misc/emcpower/dev | gawk -F : '{print $1}'`
    mmin=`cat /sys/class/misc/emcpower/dev | gawk -F : '{print $2}'`
    mknod /dev/emcpower c $mmaj $mmin > /dev/null

    if [ $? -ne 0 ]; then
        echo "`eval_gettext \"failed to create emcpower device\"`"
    fi

}

rc_reset
script_name=PowerPath
ext=$PPBASE/bin/.drivers_ext
mgr=$PPBASE/bin/.drivers_mgr

case "$1" in
    start)

        echo -n "`eval_gettext \"Starting \\$script_name: \"`"

        ### If a new kernel or new PowerPath is installed, stop
        ### PowerPath, if running, and fix things up for the
        ### new kernel or new PowerPath

        if test -f $PPBASE/../.new_pp_version || \
                 test "`cat $PPBASE/../.os_version`" != `uname -r`
        then
            if lsmod | grep -w '^emcp' > /dev/null
            then
                if [ -f $PPBASE/../.new_pp_version ]; then
                    echo "`eval_gettext \"PowerPath: Can't start, old modules loaded.\"`"
                else
                    $0 stop
                fi
            fi
            $PPBASE/enable
        fi
        
        ###
        # Load PP iff it is not already loaded.
        ###
        if rc_status ; then
            lsmod | grep -w '^emcp' > /dev/null
            if [ $? -ne 0 ]; then
                load_drivers
	    else
                if dev_emcpower_is_back 60; then
                    recreate_emcpower_device
                    /etc/opt/emcpower/powercf -K        > /dev/null 2>&1
                    rc_check
                else
                    rc_check
                    unload_drivers
                fi
		# remove PIOC if it was loaded during RD boot.
	        lsmod | grep emcpioc > /dev/null
		if [ $? -eq 0 ]; then
		    /sbin/rmmod emcpioc > /dev/null
                fi
            fi

            if rc_status ; then
                if dev_emcpower_is_back 60; then
                    configure_pp
                else
                    rc_check
                    unload_drivers
                fi
            else
                echo "`eval_gettext \"PowerPath: unable to load PowerPath modules.\"`"
                unload_drivers
            fi
        fi
        rc_status -v
        ;;

    stop)
        echo -n "`eval_gettext \"Stopping \\$script_name: \"`"
        lsmod | grep -w '^emcp' > /dev/null
        if test $? -ne 0 ;
        then
                echo "`eval_gettext \"PowerPath is not running\"`"
        else
            #
            # Tresspass can happen if new devices are added or some devices 
            # are removed by "powermt remove" before "PowerPath stop". The 
            # reason is that vgscan used by us issues "read" to all block 
            # devices. 
            # We configure all devices to avoid unnecessary trespass.
            #
            /sbin/powermt config > /dev/null 2>&1
            if ok_to_stop; then
                /sbin/powermt save > /dev/null 2>&1
                rc_check
                /etc/opt/emcpower/emcpmgr unmap > /dev/null 2>&1
                rc_check
                /sbin/powermt remove dev=all 2> /var/tmp/.pp_exit
                devr=$?
                cat /var/tmp/.pp_exit | grep "not found" > /dev/null 2>&1
                cdevs=$?
                zerolen=`cat /var/tmp/.pp_exit | wc -c`
                rm /var/tmp/.pp_exit

				# reset rc status since we are not willing to quit
				rc_reset
				if [ $devr -eq 0 -o $cdevs -eq 0 -o $zerolen -eq 0 ] ; then
					unload_drivers
					rc_check
					if [ $? -eq 0 ] ; then
						# Remove any stale pseudo device entries in /dev
						rm -f /dev/emcpower*
					else
						echo "`eval_gettext \"PowerPath could not unload PowerPath modules.\"`"
					fi	
				else
                    echo "`eval_gettext \"PowerPath devices are open.\"`"
                    echo "`eval_gettext \"Please close these devices and then re-issue \\$script_name stop.\"`"
                    /etc/opt/emcpower/emcpmgr map -p > /dev/null 2>&1
                    /sbin/powermt config 	> /dev/null 2>&1
					/sbin/powermt load	> /dev/null 2>&1
                    /bin/false
                fi
            else
                /bin/false  ## not ok_to_stop
            fi
        fi
        rc_status -v
        ;;
    *)
        var=$0
 	echo "`eval_gettext \"Usage: \\$var {start|stop}\"`"
	;;
esac

rc_exit
