#!/bin/sh
#
#    Copyright (c) 2004 Brocade Communications Systems, Inc.
#    All rights reserved.
#
#    Description:
#
#        This pre-install script will be run before firmware
#        download or firmwarerestore starts.  It checks the
#	 combination of platform (21=meteor/cp128, 42=saturn/cp256),
#	 chassis option (1=single switch/CER, 2=dual switch, etc),
#	 and other switch features to see if the firmware download
#	 or firmwarerestore will be accepted.
#
#	 It can run some preprocessing code before the commands start,
#	 e.g. removing some files to free up disk space, etc.
#
#	 WARNING: This file is run before firmwarerestore also. If
#	 you add code that only applies to firmwaredownload, you will
#	 need to use the "TYPE" flag to exclude firmwarerestore. 
#
#        This version of the script is for starting firmware version 5.1.
#        It needs to be updated for every minor release.
#

PATH=/bin:/usr/bin:/sbin:/usr/sbin

#
# Passed in version numbers
#
TO_MAJOR=$1
TO_MINOR=$2
TO_PATCH=$3
#
# When firmwaredownload is invoking this script,
# TYPE should be NULL; when firmwarerestore is
# invoking it, TYPE is "restore"
#
TYPE=$4

#
# Common variables
#
CHASSISCONFIG=/bin/getchassisconfig
NULL=/dev/null


DEBUG=0
if [ $DEBUG = 1 ]; then
	ECHO='echo -e'
else
	ECHO=:
fi

#
# Error codes - these have to match the error codes
# in fwdl.h.
#
STS_OK=0
ERR_CONF_CHASSIS=42		# FWDL_ERR_CHASSISOPT 0x2a
ERR_UNSUPPORTED_VER=44 		# FWDL_ERR_VERSION 0x2c
ERR_CONF_ROUTING=45 		# FWDL_ERR_ROUTING 0x2d
ERR_CONF_BLADETYPE17=47		# FWDL_ERR_BLADETYPE 0x2f
ERR_CONF_BLADETYPE24=48		# FWDL_ERR_BLADETYPE 0x30
ERR_CONF_LSPORTTYPE=49		# FWDL_ERR_PORTTYPE 0x31
ERR_CONF_PORTCFG1=51		# FWDL_ERR_PORTCFG1 0x33
ERR_CONF_PORTCFG2=52		# FWDL_ERR_PORTCFG1 0x34
RET=${STS_OK}

otherhost(){
        printf 10.0.0.$((5+$(othercp)))
}

HASHOW="$(/fabos/bin/hashow)"

othercp(){
        that=${HASHOW#*Remote CP \(Slot}
        that="${that%%,*}"
        printf $(($that - 5))
}

lsport_active(){
	LSPORT=`/fabos/bin/portcfgshow | grep "Long Dist" | grep "LS" | wc -l`
	return $LSPORT;
}

#
#	Make sure CPs are synchronized. This is to ensure
#	the other CP is up and running so rsh will not block
#	while trying to execute the command. If the CPs are
#	not synchronized, return 0 (no port set in LS mode).
#
lsport_standby(){
	sync=`/fabos/bin/hashow | sed -n -e 's/^.\+\(State sync\).\+$/\1/gp'`
	if [ "$sync" != "State sync" ]; then
		return 0
	else
		LSPORT=`/usr/bin/rsh -n $(otherhost) /fabos/bin/portcfgshow | grep "Long Dist" | grep "LS" | wc -l`
		return $LSPORT
	fi
}

cfgcheck_active(){
	error=$(/fabos/sbin/switchcfgvalid 0x50)
	echo "$error"
	error=${error#*error}
	error=${error%%)*}
	return $error
}

#
#	Make sure CPs are synchronized. This is to ensure
#	the other CP is up and running so rsh will not block
#	while trying to execute the command. If the CPs are
#	not synchronized, return 0 (no port set in LS mode).
#
cfgcheck_standby(){
	error=$(/usr/bin/rsh -n $(otherhost) /fabos/sbin/switchcfgvalid 0x50)
	echo "$error"
	error=${error#*error}
	error=${error%%)*}
	return $error
}

#
# swbd
#
# Retrieve the current system platform name, of the form "SWBDn", where n
# is cardinal number, assuming a sin/hinv input stream.
#
swbd() {
	sed -n -e 's/^.\+\(SWBD[[:digit:]]\{1,\}\).\+$/\1/gp'
}

#
# chassisopt
#
# Retrieve the current chassisconfig option.
#
chassisopt() {
	sed -n -e 's/^Cur.\+on: \([[:digit:]]\{1,\}\).*$/\1/gp'
}

#
# proton_present
#
# Check whether there are any Proton blades enabled in the system.
#
proton_present() {
	/fabos/bin/slotshow | grep 17 | grep -v "NOT POWERED" | wc -l
}

#
# marathon_present
#
# Check whether there are any marathon blades enabled in the system.
#
marathon_present() {
	/fabos/bin/slotshow | grep 24 | grep -v "NOT POWERED" | wc -l
}

#
# lsport_present
#
# Check whether there are any long distance ports configured in LS mode.
#
lsport_present() {
	case "$(/fabos/bin/hashow | ( read a; echo $a ))" in
        	*Local*Active*) 
			lsport_active
			;;
        	*Local*Standby*)
			lsport_standby
			;;
        	*"Not supported"*)
			lsport_active
			;;
        	*) unknow
			;;
	esac
}

#
# config_check
#
# Check the port configurations
#
cfgcheck() {
	case "$(/fabos/bin/hashow | ( read a; echo $a ))" in
        	*Local*Active*) 
			cfgcheck_active
			;;
        	*Local*Standby*)
			cfgcheck_standby
			;;
        	*"Not supported"*)
			cfgcheck_active
			;;
        	*) unknow
			;;
	esac
}

#
# Routing policy
#
# Check what routing policy it is. 
#
routing_policy() {
	/fabos/sbin/aptpolicy | sed -n -e 's/^ Cur.\+Policy: \([[:digit:]]\{1,\}\).*$/\1/gp'
}

handle_to_pre51()
{
	lsport_present

	LS_PORT=$?

	$ECHO The number of long distance port in LS mode is $LS_PORT
	if [ $LS_PORT != 0 ]; then
		echo "Cannot downgrade due to the presence of long-distance ports in LS mode." 
		echo "Remove the LS port settings before proceeding."
		return $ERR_CONF_LSPORTTYPE
	fi


#
# Check to see if port configuration is valid for anything
# before 5.1
#
	cfgcheck
	
	PORTCFG=$?

	if [ $PORTCFG == "1" ]; then
		return $ERR_CONF_PORTCFG1

	elif [ $PORTCFG == "2" ]; then
		return $ERR_CONF_PORTCFG2
	fi


	MARATHON=`marathon_present` 
	if [ $MARATHON != "0" ]; then
		echo "Cannot downgrade due to the presence of SW BLADE type 24."
		echo "Remove or power off these blades before proceeding."
		return $ERR_CONF_BLADETYPE24
	fi

	return ${STS_OK}
}

handle_to_51()
{
	$ECHO handle_to_51

	#
	# Device based routine policy is not supported in 5.1
	#
	routing=`routing_policy 2> ${NULL}`

	if ! test -z $routing; then
	    if [ $routing == "2" ]; then
		echo "Cannot download 5.1 because Device Based Routing policy is not supported by 5.1."
		echo "Use aptPolicy to change the routing policy before proceeding."
		return $ERR_CONF_ROUTING
	    fi
	fi

	SWBD=`sin | swbd 2> ${NULL}`
	case ${SWBD##SWBD} in
		'21') 
			option=`$CHASSISCONFIG | chassisopt 2> ${NULL}`
			$ECHO "option is $option"

			if test -z $option; then
				echo "No chassisconfig option found"
				return $ERR_CONF_CHASSIS
			fi

			if [ $option == "3" -o $option == "4" ] ; then
				echo "Only platform options 1, 2, 5 are supported by version 5.1."
				echo "Use chassisconfig to reset the option before downloading the firmware."
				return $ERR_CONF_CHASSIS
			fi

			return ${STS_OK}
			;;
		*)
			;;
	esac
}


#
# Preprocessing for fwdl from v5.1 to v4.4.  This is not acceptable
# for CP256's, but most options are ok.  (Actually option 5, RTE,
# couldn't really be an issue, because that presupposes CP256, but we
# check it anyway.)
#
handle_to_44()
{
	$ECHO handle_to_44

	SWBD=`sin | swbd 2> ${NULL}`
	$ECHO "swbd is $SWBD"

	case ${SWBD##SWBD} in
		'21')
			option=`$CHASSISCONFIG | chassisopt 2> ${NULL}`
			$ECHO "option is $option"

			if test -z $option; then
				echo "No chassisconfig option found"
				return $ERR_CONF_CHASSIS
			fi

			if [ $option == "1" ] ; then
				PROTON=`proton_present` 
				if [ $PROTON != "0" ]; then
					echo "Cannot downgrade due to presence of SW BLADE type 17."
					echo "Remove or power off these blades before proceeding."
					return $ERR_CONF_BLADETYPE17
				fi
				return ${STS_OK}
			fi
			if [ $option == "2" ] ; then
				return ${STS_OK}
			fi
			if [ $option == "3" ] ; then
				return ${STS_OK}
			fi
			if [ $option == "4" ] ; then
				return ${STS_OK}
			fi

			echo "Only platform options 1-4 are supported for SWBD21."
			echo "Please use chassisconfig to re-set the option."
			return $ERR_CONF_CHASSIS
			;;

		'42')
			echo "Downgrading to versions 4.4 and earlier with SWBD42 is not supported."
			return $ERR_CONF_CHASSIS
			;;
		*)
			;;
	esac
}


#
# Preprocessing for fwdl from v5.1 to v4.3.
# Since 4.3 was never released, we just let it go ahead.
#
handle_to_43()
{
	$ECHO handle_to_43

	return ${STS_OK}
}

#
# Preprocessing for fwdl from v5.1 to v4.2 (or v4.1).  This is not
# acceptable for CP256's, or for dual-switch options.
#
handle_to_42_or_41()
{
	$ECHO handle_to_42_or_41
	echo "Cannot downgrade to version 4.2 or lower. "
	echo "Please downgrade to 5.0 or 4.4 first and then download the desired version."
	return ${ERR_UNSUPPORTED_VER}
}

#
# main()
#
$ECHO Requested version is ${TO_MAJOR}.${TO_MINOR}.${TO_PATCH} Type is $TYPE

#
# clean up to free up disk space on /mnt before firmwaredownload
#
if [ -z $TYPE ]; then
	$ECHO removing tracedump.dmp
	rm -f /mnt/var/tracedump.dmp
fi

#
# Handle all pre-5.1 versions
#
if [ $TO_MAJOR -lt 5 -o $TO_MINOR -lt 1 ]; then
	handle_to_pre51
	RET=$?
	if [ $RET -ne 0 ]; then
		exit $RET 
	fi
fi

#
# Handle a specific firmware version
#
case "${TO_MAJOR}.${TO_MINOR}" in
	'5.1')
		handle_to_51
		RET=$?
	;;
	'4.4')
		handle_to_44
		RET=$?
	;;
	'4.3')
		handle_to_43
		RET=$?
	;;
	'4.2')
		handle_to_42_or_41
		RET=$?
	;;
	'4.1')
		handle_to_42_or_41
		RET=$?
	;;
	*)
	;;
esac

#
# There is no preprocessing function, just return OK.
#
$ECHO return code is $RET
exit $RET
