#!/bin/sh
#
#    Copyright (c) 2013, 2018 Brocade Communications Systems, Inc.
#    All rights reserved.
#
#    Description:
#		This script is a different flavor of preinstall checking.
#		Essentially it is intended to make easier the
#		Compatibility checking of newly introduced features
#		which are introduced in new releases but also
#		back ported to Older maint/patch release versions as well
#
#		The current preinstall checking design is to always run the 
#		preinstall of the higher of the two versions.
#		This does not lend itself to checking whether
#		the new firmware being downloaded supports a given feature,
#		except through a complex specific version checking.
#
#		This scheme requires such new features to be identified by
#		a tag in preinstall script that helps identify if the new release
#		being downloaded supports the given feature or not.
#
#		Enhancements to this script can then be done to perform
#		feature compatibility checking of such features,
#		and blocking downloads where appropriate.
#
#		If is important that each feature compatibility check
#		- Appends the corresponding error message to BOTH  ERROR/STATUS FILES
#		  STATUS_FILE and BNA_STATUS_FILE
#		- Increments the return code count (or alternately set it to non zero)
#		- return STS_ERR (this is not required but recommended for consistency)
#		This will permit a one pass checking of all features
#		And a cumulative message reflecting all corrective actions.
##############################################################################

CUR_PREINST_FILE=/sbin/preinst
NEW_PREINST_FILE=$1	# This is the preinst file of the new version being downloaded.
                    # It indicates if it supports these new features:
                    # - ZENTRON 4 CP, 8548 Rev 31 CPU
                    # - nonDFE

#
# Passed in version numbers
#
TO_MAJOR=$2
TO_MINOR=$3
TO_PATCH=$4

###############################################################################
##                            CHECK FEATURE TAGS                             ##
## This section is to define tags for the current running version of code as ##
## opposed to the target version of code. Tags defined in the preinst script ##
## and then checked here will check if the target version of code supports a ##
## given feature. The tags defined here and then checked in the preinstall   ##
## script have the opposite effect where the defined feature is supported on ##
## the current version of code, and then can be used to do conditional check ##
## from the preinst script as needed.                                        ##
##                                                                           ##
## Please do not remove these lines unless a given feature or functionality  ##
## is being removed from the current version of code.                        ##
###############################################################################

EXTN_FWDL_PREP_SUPPORTED="Current version supports extn fwdl-prep feature."
EXTN_FWDL_NEW_VALIDATE="Current version supports extncfg --validate feature."

###############################################################################
##  END of CHECK FEATURE TAGS Section.....                                   ##
###############################################################################

##########################################################
#    Begin Common code for Preinst / check_features      #
#    Need to move this to common file shared by the      #
#    2 scripts to prevent finding/fixing same bug twice  #
##########################################################
 
PATH=/bin:/usr/bin:/sbin:/usr/sbin # adding comment to protect from DOS conversion
#
# Common variables
#
NULL=/dev/null
if [ "$DEBUG" = 1 ]; then
	ECHO='echo -e'
else
	ECHO=:
fi

# This should match the file name in src/lib/upgrade/upgrade.c
STATUS_FILE=/tmp/fwdl_err.txt
BNA_STATUS_FILE=/tmp/bna_fwdl_err.txt
FWDL_WARN_STATUS_FILE=/tmp/fwdl_warn.txt
BNA_WARN_STATUS_FILE=/tmp/bna_fwdl_warn.txt

#
# Error codes - these have to match the error codes
# in fwdl.h.
#

STS_OK=0
STS_ERR=255

RET_CODE=${STS_OK}
RET=${STS_OK}

export CHASSIS_ROLEID=0
if /fabos/bin/fosconfig --show | grep "Virtual Fabric" | grep enabled > /dev/null 2>&1 ; then
	VF_ENABLED=$STS_ERR;
else
	VF_ENABLED=$STS_OK;
fi

# cpid
#
# Retrieve the current Control Processor ID
#
cpid() {
	sed -n -e 's/^Control.\+No: \([[:digit:]]\{1,\}\)$/\1/gp'
}

#
# 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'
}

# Determine the system platform identifier.
SWBD=`sin | swbd 2> ${NULL}`
CPID=`sin | cpid 2> ${NULL}`

otherhost(){
	case ${SWBD##SWBD} in
	'165' | '166' | '179' | '180')
	    printf 127.3.1.$((2 - CPID % 2))
	    ;;
	*)
	    printf 10.0.0.$((6 - CPID % 2))
	    ;;
	esac
}

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

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

ha_role() {
	/fabos/cliexec/hashow -l | /bin/grep ACTIVE > /dev/null 2>&1
	if [ $? -eq 0 ]; then
		printf "ACTIVE"
	else
		printf "STANDBY"
	fi
}

HA_ROLE=$(ha_role)
if [ $HA_ROLE == "ACTIVE" ]; then
    ACTIVECP=1
fi

ha_state() {
    sync=`/fabos/cliexec/hashow | sed -n -e 's/^.\+\(State sync\).\+$/\1/gp'`

    if [ "$sync" != "State sync" ]; then
	    printf "NOSYNC"
    else
	    printf "SYNC"
    fi
}

HA_STATE=$(ha_state)

correcthost() {
    if [ $ACTIVECP ] ; then
    "$@"
    else
    /usr/bin/rsh -n $(otherhost) ROLE_ID=root LOGIN_ID=root CURRENT_AD=0 "$@"
    fi
}

# get the current firmware version
CUR_MAJOR=$(/sbin/getfabosver | sed -n -e 's/Major://gp')

context_switch()
{
    if [ $VF_ENABLED -ne $STS_OK ]; then
        if [ "$1" != "chassis" ]
        then
            eval $(/fabos/cliexec/lscfg_util --switch $1)
        else
            eval $(/fabos/cliexec/lscfg_util --chassis)
            #export CHASSIS_ROLEID=0
        fi
    fi
    # glb_vf_id="$CURRENT_VF"
    # glb_ls_id="$FABOS_SWITCHNO"
    export ROLE_ID=root
}

#
# both Active and Standby have the information of
# VF and logical switches configured.
#
# VF case: on Standby CP, in order to login to each logical switch, 
# we need to set CHASSIS_ROLEID FABOS_SWITCHNO CURRENT_VF in rsh.
#
correcthost_to_curr_vfid() {
	if [ $ACTIVECP ] ; then
		# for_all_context already did "context_switch --switch vfid"
		"$@"
	else
		if [ $VF_ENABLED -eq $STS_OK ]; then
			# VF disabled
			/usr/bin/rsh -n $(otherhost) ROLE_ID=root LOGIN_ID=root CURRENT_AD=0 "$@"
		else
			# VF enabled, for_all_context changed glb_ls_id and glb_vf_id to each logical switch's
			/usr/bin/rsh -n $(otherhost) ROLE_ID=root LOGIN_ID=root CHASSIS_ROLEID=0 FABOS_SWITCHNO=$glb_ls_id CURRENT_VF=$glb_vf_id CURRENT_AD=0 "$@"
		fi
	fi
}

# Helper function. Loop over the valid fabric IDs running the test that is passed as
# a parameter. As soon as one test fails then return $STS_ERR. If all pass then
# return $STS_OK.
# WARNING. This command will change to a random context (The first one that fails
# the test or the last context if all pass). Random terms in case someone is searching
# this file, VF Virtual Fabric AD setcontext FID context and wants to find this warning
for_all_contexts(){
	for FID in ${CONTEXTS} ; do
		context_switch $FID
		glb_vf_id="$CURRENT_VF"
		glb_ls_id="$FABOS_SWITCHNO"
		
		if "$@"
		then	$ECHO -n "$FID-passed "
		else	$ECHO -n "$FID-failed "
			    return $STS_ERR
		fi
	done
	return $STS_OK
}

for_all_contexts_standby(){
	rval=$STS_OK
	/bin/ln -s /fabos/cliexec/lscfg_util /fabos/link_sbin/lscfg_test 2> /dev/null
	local_flag=$?
	export PATH=/fabos/link_bin:/bin:/usr/bin:/sbin:/usr/sbin:/fabos/link_abin:/fabos/link_sbin:/fabos/link_rbin:/fabos/factory:/fabos/xtool
	lscfg_test --all | grep -e "[0-9]" | grep -v "Total" |
	while read glb_ls_id glb_vf_id role
	do
		context_switch $glb_vf_id
		if "$@"
		then	$ECHO -n "$glb_vf_id-passed "
		else	$ECHO -n "$glb_vf_id-failed "
			# note the following return just return from the "|" subshell
			return $STS_ERR
		fi
	done
	if [ $? -ne $STS_OK ]; then rval=$STS_ERR; fi
	if [ $local_flag -eq 0 ];then /bin/rm /fabos/link_sbin/lscfg_test 2> /dev/null; fi
	return $rval
}

is_fwdl_arg() {

    #
    # Reads command line args passed to firmwaredownload
    # and checks if the required argument is specified
    #
    fwdl_proc_id=`ps -ef | awk '/[f]irmwaredownload /{print $2}'`
    for arg in $(/usr/bin/tr '\0' ' ' < /proc/$fwdl_proc_id/cmdline)
    do
            case $arg in
            (-*$1*)
        return $STS_OK
        ;;
            esac
        done
        return $STS_ERR
}

timestamp()
{
	date '+%m/%d/%y %H:%M:%S'
}

add_warn_status_fid(){
	if [ "$#" -eq 2 ]; then
		if [ $CUR_MAJOR -lt 9 ]; then
			echo -e "$1" "$2"
		fi
		echo -e "$1" "$2" >> $FWDL_WARN_STATUS_FILE
		echo -e "$1" "$2" >> $BNA_WARN_STATUS_FILE
	elif [ "$#" -eq 3 ]; then
		if [ $CUR_MAJOR -lt 9 ]; then
			echo -e "$1" "$3"
		fi
		echo -e "$1" "$3" >> $FWDL_WARN_STATUS_FILE
		echo -e "$2" "$3" >> $BNA_WARN_STATUS_FILE
	fi
	#echo -e "$1" "$2" >> $BNA_WARN_STATUS_FILE
}

TEST_FIDS()
{
	check_failed=0
	FID_CONTEXT="FID(s)"
	SPACE_STRING=" "
	PERIOD="."
	COMMA=","
	num_err=0
	rval=$STS_OK
	local_flag=$?
	non_vf_switch="the switch"

	$ECHO  -n "$(timestamp) TEST $1 "
	if [ $(ha_role) == "STANDBY" ] && [ $(ha_state) == "NOSYNC" ]; then
		$ECHO "skipped - standby out of sync"
		return $STS_OK
	fi
	if [ $VF_ENABLED -ne $STS_OK ]; then
		if [ $(ha_role) == "ACTIVE" ]; then
			FID_LIST=${CONTEXTS}
		else
			/bin/ln -s /fabos/cliexec/lscfg_util /fabos/link_sbin/lscfg_test 2> /dev/null
			export PATH=/fabos/link_bin:/bin:/usr/bin:/sbin:/usr/sbin:/fabos/link_abin:/fabos/link_sbin:/fabos/link_rbin:/fabos/factory:/fabos/xtool
			STANDBY_FIDS=`lscfg_test --all | grep -e "[0-9]" | grep -v "Total" | \
				awk '{ print $2 }'`
			FID_LIST=$STANDBY_FIDS
		fi

		for FID in $FID_LIST
		do
			context_switch $FID
			$1
			if [ $? -ne $STS_OK ]; then
				check_failed=1
				num_err=`expr $num_err + 1`
				if [ $num_err -eq 1 ]; then
					FID_CONTEXT=$FID_CONTEXT$SPACE_STRING$FID
				else
					FID_CONTEXT=$FID_CONTEXT$COMMA$FID
				fi
			else
				continue
			fi
		done
	else
		$1
		if [ $? -ne $STS_OK ]; then
			check_failed=1
			FID_CONTEXT=$non_vf_switch
		fi
	fi
	if [ $check_failed -eq 0 ]; then
		$ECHO "passed"
		return $STS_OK
	else
		$ECHO "failed"
		FID_CONTEXT=$FID_CONTEXT$PERIOD
		if [ "$#" -eq 2 ]; then
			add_err_status_fid "$2" "$FID_CONTEXT"
		elif [ "$#" -eq 3 ]; then
			add_err_status_fid "$2" "$3" "$FID_CONTEXT"
		fi
		RET_CODE=$STS_ERR
		return $STS_ERR
	fi
}

########################################################
#    End Common code for Preinst / check_features      #
########################################################

rc=$STS_OK
##############################################################################
#       Zentron 4 compatibility checking
# Zentron 4 CPs (i.e 8548 Rev (SVR) 31 CPU based CPs)
# MUST NOT be permitted to be upgraded or downgraded to firmware versions that
# Do not have the enhancement to support this new CPU.
# Any accidental firmwaredownload (on Z4 CP blade) to such firmware versions
# Will Render the CP Blade into a Brick - that will need to be RMA'd to fix.
#
# Hence the need for this fw compatibility check and blocking of older fw
# on the newer (Z4 CP) platforms.
#
# The enhanced firmware to support the new hardware is identified by the
# "CP31_ZENTRON4_SUPPORTED" string in the preinstall scripti (preinst.sh.in).
#
# This Checks if CP is new - 8548E rev (SVR) 31 CPU
# If so then it block downgrade to prior releases 
# that do not support the new CPU
#
##############################################################################
Z4_CP_ERR_MSG="The new firmware is not compatible with 
            the 8548 Rev 3.1 CPU based CP blade in this system."
check_new_8548_CP_fw_compatibility()
{
    chipset=`cat /proc/cpuinfo | awk '/chipset/ {print $3}'`
    if [ -z $chipset ] || [ $chipset != 8548E ]; then
        # This is not a 8548E CP return OK
        return $STS_OK
    fi

    revision=`cat /proc/cpuinfo | awk '/SVR/ {print $3}' | awk  -F 'x' '{print $2}'`
    let revision=$revision%100

    #revision=31 #uncomment to test with current 2.0 CP faked to new
    new_cp_supported=`grep -c "CP31_ZENTRON4_SUPPORTED" $NEW_PREINST_FILE`
    result=`expr $revision '>=' "31" 2>/dev/null`
    if [ $result == 1  ]; then
        # Current CP is new - 8548E CP Rev (SVR) 31
        # check if the firmware being downloaded supports new CP 
        if [ $new_cp_supported -eq 0 ]; then
            # New 8548E Rev (SVR) 31 CP But Firmware is older version.
            # Cannot downgrade to fw version that does not support this CP
            let rc=$rc+1
            echo -e $Z4_CP_ERR_MSG >> $STATUS_FILE
            echo -e $Z4_CP_ERR_MSG >> $BNA_STATUS_FILE
            return $STS_ERR
        else
            # New 8548E Rev (SVR) 31 CP and new firmware is compatible.
            return $STS_OK
        fi
    fi

    #
    # Current CP is Old i.e. 8548E but less than Rev (SVR) 31
    # Next check the redundant CP for the new rev (SVR) 31 CPU
    # if redundant CP is new then block downgrades to 
    # firmware versions that do not support the new CP
    #
    if [ $(ha_state) == "SYNC" ]; then
        revision=`/usr/bin/rsh -n $(otherhost) ROLE_ID=root LOGIN_ID=root CURRENT_AD=0 /bin/cat /proc/cpuinfo | /bin/awk '/SVR/ {print $3}' | awk  -F 'x' '{print $2}'`

        # if revision is not defined then return STS_OK
        if [ -z $revision ]; then
            return $STS_OK
        fi

        let revision=$revision%100
        #revision=31 #uncomment to test with current 2.0 StbyCP faked to new
        result=`expr $revision '>=' "31" 2>/dev/null`
        if [ $result == 0  ]; then
            # Other CP is also old - so no compatibility checking necessary.
            return $STS_OK
        fi
    else
        # This is a single CP system or non-redundant chassis system.
        # And the CP is old -  8548E but not Rev 31
        return $STS_OK
    fi

    # Here Current CP is Old but the Other CP is new 
    # Check if the preinstall of the new firmware being downloaded
    # Supports the new hardware

    if [ $new_cp_supported -eq 0 ]; then
        # Cannot downgrade to fw version that does not support this CP
        let rc=$rc+1
        echo -e $Z4_CP_ERR_MSG >> $STATUS_FILE
        echo -e $Z4_CP_ERR_MSG >> $BNA_STATUS_FILE
        return $STS_ERR
    fi

    return $STS_OK
}



##############################################################################
#
# Non-DFE (Decision Feedback Equalization) Feature compatibility checks.
# If Non-DFE is enabled on any of the ports and the new firmware does not
# support this feature then firmwaredownload to that version must be blocked
# with appropriate message to disable the feature before moving to that version
#
##############################################################################

NON_DFE_ENABLED_ERR_MSG="Non-DFE is enabled and the new firmware does not support it.
\n   Please run portcfgnondfe --disable [slot/]port for all ports where it is enabled, before downloading the new firmware.
\n   Use porcfgshow to find all ports where Non-DFE is enabled."
BNA_NON_DFE_ENABLED_ERR_MSG="Non-DFE is enabled and the new firmware does not support it.
\n  Please disable Non DFE on the port using WebTools -> Port Admin -> Actions -> Non DFE.
\n  Find the list of Non DFE Enabled Ports in Port Admin table."

check_non_dfe()
{
    #
    # do not use the correcthost primitive here.
    # The preinst file is on this host and not on correcthost
    # correcthost will not work when running fwdl from standby.
    #
    non_dfe_supported=`grep -c "NON_DFE_SUPPORTED" $NEW_PREINST_FILE`
    if [ $non_dfe_supported -ne 0 ]; then
        # The new release supports this feature so ok to proceed.
        return $STS_OK
    fi

    # DFE is not supported by the new firmware.
    # Check if DFE is enabled before permitting download to a version
    # That does not support DFE and block download if enabled

    non_dfe_enabled=`correcthost /fabos/cliexec/portcfgshow | grep Non-DFE | grep -c ON`
    if [ $non_dfe_enabled -ne 0 ]; then
        # Let each failing check
        # Append its own Detailed corrective message to BOTH files:
        # - STATUS_FILE and BNA_STATUS_FILE 
        # increment return code
        let rc=$rc+1
        echo -e $NON_DFE_ENABLED_ERR_MSG >> $STATUS_FILE
        echo -e $BNA_NON_DFE_ENABLED_ERR_MSG >> $BNA_STATUS_FILE
        return $STS_ERR
    fi

    return $STS_OK
}




##############################################################################
#
# QSFP on ICLs Feature compatibility checks.
# Downgrade to a release that does not support this feature is not allowed
# if some of the ICL ports are connected with new QSFP which support upto 2km. 
#
##############################################################################


glb_ls_id=-1
glb_vf_id=255

ICL_QSFP_FWDL_CHECK="Downgrade is not allowed as some of the ICL ports are connected with new QSFP which support upto 2km. Please remove the QSFP(s) flagged and connect the old QSFP before proceeding with the downgrade."

check_qsfpp_icl()
{
    #
    # do not use the correcthost primitive here.
    # The preinst file is on this host and not on correcthost
    # correcthost will not work when running fwdl from standby.
    #
    qsfpp_icl_supported=`grep -c "QSFPP_ICL_SUPPORTED" $NEW_PREINST_FILE`
    if [ $qsfpp_icl_supported -ne 0 ]; then
        # The new release supports this feature so ok to proceed.
        return $STS_OK
    fi

    # QSFP_ICL is not supported by the new firmware.
    # Check if any QSFPs on ICLs. If so then block the downgrade.

	icl_fwdl_ret=`correcthost_to_curr_vfid /fabos/bin/icl_qsfp_fwdl_check 2>/dev/null | grep -E "2KM QSFP"`
	if [ $? -eq 0 ]; then
		let rc=$rc+1
		echo -e $icl_fwdl_ret >> $STATUS_FILE
		echo -e $ICL_QSFP_FWDL_CHECK  >> $STATUS_FILE
		echo -e $icl_fwdl_ret >> $BNA_STATUS_FILE
		echo -e $ICL_QSFP_FWDL_CHECK  >> $BNA_STATUS_FILE
		return $STS_ERR;
	fi
    return $STS_OK
}


################################################################################
#
# check for 2KM 32G QSFP ICLs support
#
QSFP_32G_FWDL_BLOCK="Downgrade is not allowed as some of the ICL ports are connected with new 2 KM 32G QSFPs. Please remove the QSFP(s) flagged and connect the old QSFP before proceeding with the downgrade."


check_2km_32G_qsfp_icl()
{
    #
    # do not use the correcthost primitive here.
    # The preinst file is on this host and not on correcthost
    # correcthost will not work when running fwdl from standby.
    #
    qsfp_32G_icl_supported=`grep -c "QSFP_32G_ICL_SUPPORTED" $NEW_PREINST_FILE`
    if [ $qsfp_32G_icl_supported -ne 0 ]; then
        # The new release supports this feature so ok to proceed.
        return $STS_OK
    fi

    # 2KM_32G_QSFP_ICL is not supported by the new firmware.
    # Check if any 2KM 32G QSFPs on ICLs. If so then block the downgrade.
    qsfp_32G_icl_fwdl_ret=`correcthost_to_curr_vfid /fabos/rbin/icl_32G_qsfp_fwdl_check 2>/dev/null | grep -E "2KM 32G QSFP"`
	if [ $? -eq 0 ]; then
		let rc=$rc+1
		echo -e $qsfp_32G_icl_fwdl_ret >> $STATUS_FILE
		echo -e $QSFP_32G_FWDL_BLOCK  >> $STATUS_FILE
		echo -e $qsfp_32G_icl_fwdl_ret >> $BNA_STATUS_FILE
		echo -e $QSFP_32G_FWDL_BLOCK  >> $BNA_STATUS_FILE
		return $STS_ERR;
	fi
    return $STS_OK
}

QSFP_32G_2KM_FWDL_BLOCK="Downgrade is not allowed as some of the ports are connected with 2KM 32G QSFPs. Please remove the QSFP(s) flagged and connect the supported QSFP before proceeding with the downgrade."

UNSUPPORTED_32G_LUMENTUM_QSFP_ON_DOWNGRADE_ERR="Downgrade is not allowed since 32G LUMENTUM QSFP is present on port\(s\) \$ports_with_32G_lumentum_qsfp. Please remove the 32G LUMENTUM QSFP and retry firmwaredownload."

# executes the provided function in the context of all configured virtual
# fabrics, and logical switches on the active and standby CP's to determine
# if a critera is met
correcthost_all_vfs() {
	if [ $VF_ENABLED -ne $STS_OK ]; then
		# VF is enabled
		if [ $ACTIVECP ] ; then
			for_all_contexts correcthost_to_curr_vfid $@
		else
			# this is the standby cp, examine the configuration of the
			# active cp
			for_all_contexts_standby correcthost_to_curr_vfid $@
		fi
	else
		correcthost_to_curr_vfid $@
	fi
	if [ $? -eq 0 ]; then
		return $STS_OK
	else
		return $STS_ERR
	fi
}

check_32G_lumentum_qsfp_ports()
{
    qsfp_32G_lumentum_supported=`correcthost_all_vfs /fabos/bin/slotshow | awk '{print $4}' | grep -e 214 -e 215 | wc -l`
    if [ $qsfp_32G_lumentum_supported -gt 0 ]; then
        # Get list of port which have 32G Lumentum media plugged in
        media_identifier="Serial No: ZMJ"
        ports_with_unsupported_media=`correcthost_all_vfs /fabos/cliexec/sfpshow | grep "$media_identifier" | sed '/Slot[ ]*/s///g' | sed '/Port[ ]*/s///g' | cut -f1 -d ":"`
        ports_with_32G_lumentum_qsfp=`echo $ports_with_unsupported_media | sed '/ /s//,/g'`

        if [ "$ports_with_32G_lumentum_qsfp" = "" ]; then
            # There are no 32G lumentum optics plugged in
            return 0
        else
            return 1
        fi
    fi
}

check_32G_lumentum_qsfp_error_msg()
{
    $ECHO "32G Lumentum QSFP exist on ports $ports_with_32G_lumentum_qsfp"
    UNSUPPORTED_32G_LUMENTUM_QSFP_ON_DOWNGRADE_ERR=$(eval echo "$UNSUPPORTED_32G_LUMENTUM_QSFP_ON_DOWNGRADE_ERR")
    BNA_UNSUPPORTED_32G_LUMENTUM_QSFP_ON_DOWNGRADE_ERR=$(eval echo "$UNSUPPORTED_32G_LUMENTUM_QSFP_ON_DOWNGRADE_ERR")
    # Explicit call to add_err_status since error strings were changed
    add_err_status "$UNSUPPORTED_32G_LUMENTUM_QSFP_ON_DOWNGRADE_ERR" "$BNA_UNSUPPORTED_32G_LUMENTUM_QSFP_ON_DOWNGRADE_ERR"
}

check_lumentum_32G_qsfp_gen7_core_blades()
{
    lumentum_32G_qsfp_gen7_core_blades_supported=`grep -c "LUMENTUM32G_QSFP_GEN7_CORE_BLADE_SUPPORTED" $NEW_PREINST_FILE`
    if [ $lumentum_32G_qsfp_gen7_core_blades_supported -ne 0 ]; then
        # The new release supports this feature so ok to proceed.
        return $STS_OK
    fi

    # Lumentum_32G_QSFP is not supported by the new firmware.
    # Check if Lumentum 32G QSFPs on GEN7 core blades. If so then block the downgrade.
    check_32G_lumentum_qsfp_ports
    if [ $? -eq 1 ]; then
        $ECHO "32G Lumentum QSFP exist on ports $ports_with_32G_lumentum_qsfp"
        UNSUPPORTED_32G_LUMENTUM_QSFP_ON_DOWNGRADE_ERR=$(eval echo "$UNSUPPORTED_32G_LUMENTUM_QSFP_ON_DOWNGRADE_ERR")
        echo -e $UNSUPPORTED_32G_LUMENTUM_QSFP_ON_DOWNGRADE_ERR >> $STATUS_FILE
        echo -e $UNSUPPORTED_32G_LUMENTUM_QSFP_ON_DOWNGRADE_ERR >> $BNA_STATUS_FILE
        let rc=$rc+1
        return $STS_ERR
	fi

    return $STS_OK
}

check_2km_32G_qsfp()
{
    #
    # do not use the correcthost primitive here.
    # The preinst file is on this host and not on correcthost
    # correcthost will not work when running fwdl from standby.
    #
    qsfp_32G_2KM_icl_non_icl_supported=`grep -c "QSFP_32G_2KM_ICL_NON_ICL_SUPPORTED" $NEW_PREINST_FILE`
    if [ $qsfp_32G_2KM_icl_non_icl_supported -ne 0 ]; then
        # The new release supports this feature so ok to proceed.
        return $STS_OK
    fi

    # 2KM_32G_QSFP is not supported by the new firmware.
    # Check if any 2KM 32G QSFPs. If so then block the downgrade.
    qsfp_32G_2KM_fwdl_ret=`correcthost_to_curr_vfid /fabos/bin/qsfp_32g_2km_fwdl_check 2>/dev/null | grep -E "2KM 32G QSFP"`
	if [ $? -eq 0 ]; then
		let rc=$rc+1
		echo -e $qsfp_32G_2KM_fwdl_ret >> $STATUS_FILE
		echo -e $QSFP_32G_2KM_FWDL_BLOCK  >> $STATUS_FILE
		echo -e $qsfp_32G_2KM_fwdl_ret >> $BNA_STATUS_FILE
		echo -e $QSFP_32G_2KM_FWDL_BLOCK  >> $BNA_STATUS_FILE
		return $STS_ERR;
	fi
	# control reaching here means 2KM_32G_QSFP is not supported by the new firmware.
	# And no 2KM_32G_QSFPs plugged in on non-ICL ports
	# Next check if any 2KM_32G_QSFP plugged in on ICL ports
	# if so then block - check_2km_32G_qsfp_icl will take care of that by incrementing rc.
	check_2km_32G_qsfp_icl
    return $STS_OK
}

BUF_OP_MODE_CHECK_FAILED="Downgrade is not allowed because BufOpMode is enabled on CORE blade(s).  Please disable bufopmode using the CLI \"bufopmode --resetall\" \n"
check_buf_op_mode()
{
	if  [ ${SWBD##SWBD} -eq 165 ] || [ ${SWBD##SWBD} -eq 166 ]; then
		buf_op_mode_supported=`grep -c "GEN6_BUF_OP_MODE_SUPPORTED" $NEW_PREINST_FILE`
	else
		buf_op_mode_supported=`grep -c "BUF_OP_MODE_SUPPORTED" $NEW_PREINST_FILE`
	fi
	if [ $buf_op_mode_supported -ne 0 ]; then
		# The new release supports this feature so ok to proceed.
		return $STS_OK
	fi

	# special check for v7.2.1d which also supports BUF_OP_MODE
	# but did not include the BUF_OP_MODE_SUPPORTED tag.
	buf_op_mode_supported=`grep -c "BUFOPMODE_ENABLED" $NEW_PREINST_FILE`
	if [ $buf_op_mode_supported -ne 0 ]; then
		# The new release supports this feature so ok to proceed.
		return $STS_OK
	fi

	# BUF_OP_MODE is not supported by the new firmware.
	# Check if BUF_OP_MODE is enabled on any slots. If so then block the downgrade.
	icl_slots=`correcthost_to_curr_vfid /fabos/bin/slotshow -m | grep "CORE" | awk {'print $1'}`
	if [ "$icl_slots" == "" ]; then
		return $STS_OK
	fi

	for slot in $icl_slots; do
		correcthost_to_curr_vfid /fabos/sbin/bufopmode --show $slot | grep "On" > /dev/null
		if [ $? -eq 0 ]; then
			let rc=$rc+1
			echo -e $BUF_OP_MODE_CHECK_FAILED >> $STATUS_FILE
			echo -e $BUF_OP_MODE_CHECK_FAILED >> $BNA_STATUS_FILE
			return $STS_ERR
		fi
	done

    return $STS_OK
}


UNSUPPORTED_DOWNGRADE_MSG="Downgrade is not allowed because root account is permanently disabled in this platform. Requested firmware does not support." 
check_permanet_root_disable_huawei_supported()
{
	huawei_banded=`correcthost_to_curr_vfid /fabos/cliexec/chassisshow | grep -c "BRD0000HU"`

	# Check if the switch is huawei banded.
	if [ $huawei_banded -ne 0 ]; then
		root_disble_supported=`grep -c "ROOT_PERMANET_DISABLE_SUPPORTED" $NEW_PREINST_FILE`
		# Check if root disable feature exist in requested firmware.
		if [ $root_disble_supported -eq 0 ]; then
			let rc=$rc+1
			echo -e $UNSUPPORTED_DOWNGRADE_MSG >> $STATUS_FILE
			echo -e $UNSUPPORTED_DOWNGRADE_MSG >> $BNA_STATUS_FILE
			return $STS_ERR;
		fi
	fi

	return $STS_OK;
}	




check_Thalassa8G_blade() {
    result=`/fabos/cliexec/slotshow -m | grep "FC8-48E" | wc -l`
    if [ $result -ge 1 ]; then
                return $STS_ERR
    else
       return $STS_OK
    fi
}

check_Quattro_blade() {
    result=`/fabos/cliexec/slotshow -m | grep "FC8-64" | wc -l`
    if [ $result -ge 1 ]; then
                return $STS_ERR
    else
       return $STS_OK
    fi
}
check_Galatea8G_blade() {
    result=`/fabos/cliexec/slotshow -m | grep "FC8-32E" | wc -l`
    if [ $result -ge 1 ]; then
                return $STS_ERR
    else
       return $STS_OK
    fi
}


add_err_status(){
    echo -e "$1" >> $STATUS_FILE
    if [ "$#" -eq "1" ]; then
        echo -e "$1" >> $BNA_STATUS_FILE
    elif [ "$#" -eq "2" ]; then
        echo -e $rc:	"$2" >> $BNA_STATUS_FILE
    fi
}


TEST() {

    $ECHO  -n "TEST $1 "
    if [ $HA_ROLE == "STANDBY" ] && [ $HA_STATE == "NOSYNC" ]; then
        return $STS_OK
    fi

    $1
    if [ "$?" -ne "$STS_OK" ]; then
        $ECHO "failed"
		let rc=$rc+1
        if [ "$#" -eq "2" ]; then
            add_err_status "$2"
        elif [ "$#" -eq "3" ]; then
            add_err_status "$2" "$3"
        fi
        RET_CODE=$STS_ERR
        return $STS_ERR
    fi

    $ECHO "passed"
    return $STS_OK
}


QUATTRO_BLADE_IS_PRESENT="FC8-64 blade is not supported by the targeted firmware.Please remove the blade and retry."
THALASSA8G_BLADE_IS_PRESENT="FC8-48E blade is not supported by the targeted firmware.Please remove the blade and retry."
GALATEA8G_BLADE_IS_PRESENT="FC8-32E blade is not supported by the targeted firmware.Please remove the blade and retry."

#BNA_QUATTRO_BLADE_IS_PRESENT="Quattro (FC8-64) blade is not supported by the targeted firmware.Please remove the blade and retry."
#BNA_THALASSA8G_BLADE_IS_PRESENT="Thalssa (FC8-48E) blade is not supported by the targeted firmware.Please remove the blade and retry."
#BNA_GALATEA8G_BLADE_IS_PRESENT="Thalssa (FC8-32E) blade is not supported by the targeted firmware.Please remove the blade and retry."

check_enhanced_fc8_blades()
{
	enhanced_fc8_supported=`grep -c "ENHANCED_FC8_BLADES_SUPPORTED" $NEW_PREINST_FILE`
	if [ $enhanced_fc8_supported -ne 0 ]; then
		# The new release supports ENHANCED_FC8_BLADES so ok to proceed.
		return $STS_OK;
	fi

	# Here we know that the new firmware does not support ENHANCED_FC8_BLADES.
	# Make a special check for pattern "check_Thalassa8G_blade" in target preinst file
	# If this pattern is not there then we can safely assume we are going to v7.4.x
	# where these blades are supported - so no need to block
	check_Thalassa=`grep -c "check_Thalassa8G_blade" $NEW_PREINST_FILE`
	if [ $check_Thalassa -eq 0 ]; then
		# The new release supports ENHANCED_FC8_BLADES so ok to proceed.
		return $STS_OK;
	fi

	# Now we are down to the releases that don't support these blades (ie 8.0.1x)
	# Check if Enhanced FC8 Blades are present. If so then block the downgrade.

	#result=`/fabos/cliexec/slotshow -m | grep -E "FC8-48E|FC8-64|FC8-32E" | wc -l
	#TEST check_Thalassa8G_blade "$THALASSA8G_BLADE_IS_PRESENT" "$BNA_THALASSA8G_BLADE_IS_PRESENT"
	#TEST check_Quattro_blade "$QUATTRO_BLADE_IS_PRESENT" "$BNA_QUATTRO_BLADE_IS_PRESENT" 
	#TEST check_Galatea8G_blade "$GALATEA8G_BLADE_IS_PRESENT" "$BNA_GALATEA8G_BLADE_IS_PRESENT" 

	TEST check_Thalassa8G_blade "$THALASSA8G_BLADE_IS_PRESENT"
	TEST check_Quattro_blade "$QUATTRO_BLADE_IS_PRESENT"
	TEST check_Galatea8G_blade "$GALATEA8G_BLADE_IS_PRESENT"

	return $STS_OK;
}

export PATH=/fabos/link_bin:/bin:/usr/bin:/sbin:/usr/sbin:/fabos/link_abin:/fabos/link_sbin:/fabos/link_rbin:/fabos/factory:/fabos/xtool
export VFROLEMAP=-1:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0

cmd_chassis() {

  context_switch chassis

  if [ "$CONFIG" = "TRUE" ]; then
    echo -n . > $TTY
    cliidx=`/usr/bin/expr $cliidx + 1`
    echo "$cliidx $1 $2 $3 $4 $5 $6 $7 $8 $9" >> $cshow
    echo -e "$1 $2 $3 $4 $5 $6 $7 $8 $9:"
      echo "** $1 $2 $3 $4 $5 $6 $7 $8 $9: Command:$rc **" >> $cshow
  else
    echo -e "$1 $2 $3 $4 $5 $6 $7 $8 $9:"
    $1 $2 $3 $4 $5 $6 $7 $8 $9
  fi
}

CHASSISCMD="cmd_chassis"

CONTEXTS=$($CHASSISCMD /fabos/cliexec/configshow -all | sed -n 's/Fabric ID =//p')

# copy all the configuration to tmp files before pre-install script runs.
# this avoids anyone to run RSH

copyAllConfigurationFiles() {
    # checks for active or standby
    if [ $ACTIVECP ] ; then
	#VF enable
	if [ $VF_ENABLED -ne $STS_OK ]; then
	    # iterating through all the FIDs
	    for FID in ${CONTEXTS} ; do
		context_switch $FID
		/fabos/cliexec/configshow -fid $FID > /tmp/chk_config_$FID
	    done
	else
	    # in non FD enviorenment there will be only one configuration - no all, no chassis
	    /fabos/cliexec/configshow > /tmp/chk_config_128
	    
	fi
	/fabos/cliexec/configshow -chassis  > /tmp/chk_config_chassis
	/fabos/cliexec/configshow -all  > /tmp/chk_config_all
    fi    
}

# calling to copy configuration files to /tmp directory
copyAllConfigurationFiles

CONFIGSHOW() {
	if [ $ACTIVECP ] ; then
		if [ "$1" = "-chassis"  ]; then 
			cat /tmp/chk_config_chassis
		elif [ "$1" = "-a" ] || [ "$1" = "-all" ] ; then
			cat /tmp/chk_config_all
		else
			if [ $VF_ENABLED -ne $STS_OK ]; then
				cat /tmp/chk_config_$CURRENT_VF
			else 
				cat /tmp/chk_config_128
			fi
		fi
	else
		if [ "$1" = "-chassis"  ]; then 
			cmd="/fabos/cliexec/configshow -chassis"
			glb_ls_id=-1;
			glb_vf_id=255;
		elif [ "$1" = "-a" ] || [ "$1" = "-all" ] ; then
			glb_ls_id=-1;
			glb_vf_id=255;
			cmd="/fabos/cliexec/configshow -all"
		else
			cmd="/fabos/cliexec/configshow"
		fi
	
		if [ $VF_ENABLED -eq $STS_OK ]; then
			# VF disabled
			/usr/bin/rsh -n $(otherhost) ROLE_ID=root LOGIN_ID=root CURRENT_AD=0 "$cmd"
		else
			# VF enabled, for_all_context changed glb_ls_id and glb_vf_id to each logical switch's
			/usr/bin/rsh -n $(otherhost) ROLE_ID=root LOGIN_ID=root CHASSIS_ROLEID=0 FABOS_SWITCHNO=$glb_ls_id CURRENT_VF=$glb_vf_id CURRENT_AD=0 "$cmd"
		fi
	fi

}




################################################################################
NONDFE_FD_MSG="Cannot download the requested firmware because it does not support portcfgnondfe --force_disable and one or more ports are configured with --force_disable option. Please use portcfgshow to identify these ports and reconfigure them with --enable or --disable option and then retry firmwaredownload."
check_nondfeforcedisable_supported()
{
	nondfe_forcedisable_supported=`grep -c "NONDFE_FORCE_DISABLE_SUPPORTED" $NEW_PREINST_FILE`
	if [ $nondfe_forcedisable_supported -ne 0 ]; then
		# The new release supports portcfgnondfe --forcedisable
		# No need to check further for blocking fwdl due to this feature.
		return $STS_OK;
	fi

	# portcfgnondfe --forcedisable is not supported by the new firmware being downloaded
	# Check if any ports are configured for nondfe force_disable. If so then block the downgrade.
	nondfe_fd=`correcthost_to_curr_vfid /fabos/cliexec/portcfgshow | grep "8G Non-DFE" | grep -c FD`
	if [ $nondfe_fd -ne 0 ]; then
		# one or more ports have nondfe configured with --force_disable option.
		# So return error to block downgrade.
		let rc=$rc+1
		echo -e $NONDFE_FD_MSG >> $STATUS_FILE
		echo -e $NONDFE_FD_MSG >> $BNA_STATUS_FILE
		return $STS_ERR;
	fi

	# New firmware does not support portcfgnondfe --forcedisable
	# But none of the ports are configured for --forcedisable. so ok to proceed.
	return $STS_OK;
}


UNSUPPORTED_TACACS_ENCRYPTION="Downgrade is not allowed since switch has TACACS+ configurations with encryption enabled. Please remove TACACS+ configurations or set the encryption level to NONE to proceed."

check_tacacs_encryption_enabled()
{
 tacacs_encryption_enabled=$(CONFIGSHOW -all | /bin/grep "tacacs.server" | /bin/grep -c "encryptionlevel:1")
 if [ $tacacs_encryption_enabled -ne 0 ]; then
	return $STS_ERR
 fi
 
 return $STS_OK
}

check_tacacs_encryption()
{
	#
	# Check if new firwmare supports TACACS encryption feature.
	#
	tacacs_encryption_supported=`/bin/grep -c "TACACS_ENCRYPTION_SUPPORTED" $NEW_PREINST_FILE`
	if [ $tacacs_encryption_supported -ne 0 ]; then
        
		# The new release supports this feature so ok to proceed.
		return $STS_OK
 	fi
 
	#
	# New firmware does not support TACACS encryption feature.
	# Now, check if TACACS configurations has encryption enabled
	#
	TEST check_tacacs_encryption_enabled "$UNSUPPORTED_TACACS_ENCRYPTION"
}


UNSUPPORTED_ROLE_NAME_LENGTH="New firmware does not support LDAP rolename length over 31 characters. Please remove/modify the mapping using \"ldapcfg\" command to proceed with firmwaredownload"

check_ldap_support_for_group_length()
{
        #
        # Check if new firmware supports ldap group name length of 64
        #
        ldap_role_length_64_supported=`/bin/grep -c "LDAP_ROLE_NAME_LENGTH_64_SUPPORTED" $NEW_PREINST_FILE`
        if [ $ldap_role_length_64_supported -ne 0 ]; then

                # The new release supports this feature so ok to proceed.
                return $STS_OK
        fi

        #
        # New firmware does not support LDAP group length of 64
        # Now, check if LDAP group name length > 32 is configured on switch including the trailing '\0'
        #
	TEST check_ldap_role_name_length "$UNSUPPORTED_ROLE_NAME_LENGTH"
}


#
# Check if ldap maps role has 32 or less characters including the trailing '\0'
# The changes are specific to customer CVR. May extend to future releases.
#
check_ldap_role_name_length()
{
	if [ -f /etc/fabos/ldap.map ]; then
		input="/etc/fabos/ldap.map"
		while read -r line
		do
                	result=`echo $line | sed -e 's/^.//;s/:.*//' | wc -c`
                        if [ $result -ge 32 ]; then
                                return $STS_ERR
                        fi
        	done <"$input"
        fi
        return $STS_OK
}

UNSUPPORTED_RADIUS_TACACS_ENCRYPION="Downgrade is not allowed since switch has RADIUS or TACACS+ configurations with encryption enabled. Please remove RADIUS or TACACS+ configurations or set the encryption level to NONE to proceed."

check_radius_tacacs_encryption_enabled()
{
 tacacs_encryption=$(CONFIGSHOW -all | /bin/grep "tacacs.server" | /bin/grep -c "encryptionlevel:1")
 radius_encryption=$(CONFIGSHOW -all | /bin/grep "radius.server" | /bin/grep -c "encryptionlevel:1")
 if [ $tacacs_encryption -ne 0 ] || [ $radius_encryption -ne 0 ]; then
 	return $STS_ERR
 fi
  
 return $STS_OK
}

check_radius_tacacs_encryption()
{
	#
	# Check if new firwmare supports storage of only encrypted shared secret for RADIUS and TACACS 
	#
	radius_tacacs_encrypt=`/bin/grep -c "RADIUS_TACACS_ENCRYPTION" $NEW_PREINST_FILE`
	if [ $radius_tacacs_encrypt -ne 0 ]; then
        
		# The new release supports this feature so ok to proceed.
		return $STS_OK
 	fi
 
	#
	# New firmware does not support storage of only encrypted shared secret for RADIUS and TACACS 
	# Now, check if RADIUS or TACACS configurations have encryption enabled
	#
	TEST check_radius_tacacs_encryption_enabled "$UNSUPPORTED_RADIUS_TACACS_ENCRYPION"
}

SERDES_VERSIONS_DIFFER="The Serdes Version of target firmware differs from the current firmware. HCL to FOS version with different Serdes Versions is not permitted.  Please use \"firmwaredownload -s\" for disruptive firmwaredownload so that the new serdes values will take effect. \n"

check_serdes_version_between_cur_n_new_fos()
{
	case ${SWBD##SWBD} in
		'169' | '170')
		;;
	*)
		# Do not bother with Serdes checking for non Chewbacca platforms
		return $STS_OK;
		;;
	esac

	cur_serdes_supported=$(grep CHEW_SERDES_SUPPORTED $CUR_PREINST_FILE)
	new_serdes_supported=$(grep CHEW_SERDES_SUPPORTED $NEW_PREINST_FILE)
	if [ "$cur_serdes_supported" = "$new_serdes_supported" ]; then
		# The cur and new FOS versions support the same SERDES versions
		# So return OK to proceed.
		return $STS_OK;
	fi

	# Current and New (to be downloaded) FOS versions support different versions of serdes. 
	# Check for and block non-disruptive firmwaredownload but permit disruptive firmwaredownload. 

	non_disruptive_fwdl=0

	fwdl_option_s=0;
	fwdl_option_b=0;
	is_fwdl_arg "s"
	if [ $? -eq $STS_OK ]; then
		fwdl_option_s=1;
	fi

	is_fwdl_arg "b"
	if [ $? -eq $STS_OK ]; then
		fwdl_option_b=1;
	fi

	if [ $fwdl_option_s -gt 0 ]; then
		if [ $fwdl_option_b -gt 0 ]; then
			#	-sb is set. this is again non-disruptive (as good as no options set)
			non_disruptive_fwdl=1
		fi
	else
		non_disruptive_fwdl=1
	fi

	if [ $non_disruptive_fwdl -eq 1 ]; then
		let rc=$rc+1
		echo -e $SERDES_VERSIONS_DIFFER >> $STATUS_FILE
		echo -e $SERDES_VERSIONS_DIFFER >> $BNA_STATUS_FILE
		return $STS_ERR;
	fi

	# Here we have different serdes versions but disruptive firmwaredownload
	return $STS_OK
}

################################################################################
# Extension FWDL-PREP Check
################################################################################

check_extn_fwdl_prep()
{
	#
	# Check if new firwmare supports extn fwdl-prep feature.
	#
	extn_fwdl_prep_supported=`/bin/grep -c "EXTN_FWDL_PREP_SUPPORTED" $NEW_PREINST_FILE`
	if [ $extn_fwdl_prep_supported -eq 0 ]; then
		# The new release does not support this command, so don't attempt to execute
		return $STS_OK
 	fi

	case ${SWBD##SWBD} in
		'165' | '166')

		correcthost_to_curr_vfid /fabos/link_sbin/extncfg --fwdl-prep --version ${TO_MAJOR}.${TO_MINOR}.${TO_PATCH} --preinst
		;;

	*)
		;;
	esac

	return $STS_OK
}

################################################################################
NEW_128MB_FLASH_BLOCKING_MSG="Cannot download the requested firmware because it does not support the newer Flash used on this Switch. Please retry firmwaredownload using a firmware version that supports this new flash"
check_for_new_128MB_flash()
{
	new_128MB_flash_supported=`grep -c "NEW_128MB_FLASH_SUPPORTED" $NEW_PREINST_FILE`
	if [ $new_128MB_flash_supported -ne 0 ]; then
		# The new release supports the new  128 MB Flash
		# No need to check further for blocking fwdl to this version.
		return $STS_OK;
	fi

	# Control reaching here means we are attempting to
	# download a firmware version that does not support the new 128MB flash
	# Check if this is one of those platforms that has this new part 
	# and block firmwaredownload to this firmware version 
	# that does not support this new part.
	# Otherwise that firmware will brick this switch.

	case ${SWBD##SWBD} in
		'161' | '162' |	'169' | '170' |	'172')
		# Check for New 128MB Flash on these platforms
		# Wedge(161), Wedge_64(162), Chebacca(169), Chewbacca 24 port(170) or Wedge_plus(172)
		;;

		*)
		# Do not bother with New 128MB Flash checking for other Platforms
		# i.e This needs to be checked only for Wedge and Chewbacca platforms
		return $STS_OK;
		;;
	esac

	# Control reaches here for Wedge and Chewbacca platforms
	# And the firmware being downloaded does not support the new 128 MB flash.
	# Check if this switch has the new Flash and if yes then
	# Block firmaredownload to this version.

	prom0_primary=$(cat /proc/mtd | grep  -c "prom0: primary")
	#
	# These platforms should have this line "prom0: primary"
	# But this one does not. Bail out for now.
	#
	if [ $prom0_primary -eq 0 ]; then
		return $STS_OK;
	fi

	erasesize=$(cat /proc/mtd | grep  "prom0: primary" |  awk '/ / {print $3}')

	if [ $erasesize -ne 00010000 ]; then
		# we have a platform with new 128MB flash
		# and we are attempting to download a firmware version which
		# does not have the support for that part.
		# So return error to block downgrade.
		let rc=$rc+1
		echo -e $NEW_128MB_FLASH_BLOCKING_MSG >> $STATUS_FILE
		echo -e $NEW_128MB_FLASH_BLOCKING_MSG >> $BNA_STATUS_FILE
		return $STS_ERR;
	fi

	# This switch has the old Flash 32MB or 64MB
	# Ok to download the firmware version that does not support the new 128MB flash.
	return $STS_OK;
}

################ Check LCW platform ######################
DDR_2G_NOTBACK4GFOS="Downgrade is not allowed because the target firmware does not support this hardware revision."
check_wedgecr()
{
	case ${SWBD##SWBD} in
		'162')
                if [ -e /proc/system/wedgecr ];then
                        is_lcw="$(cat /proc/system/wedgecr)"
                else
                        is_lcw=0
                fi
                memval=`/fabos/link_bin/memshow | grep "Mem" | awk '{ print $2 }'`
                ddr=$(($memval-2200000000))     # big value, so reduce to smaller number
                if [ $is_lcw -eq 1 ] || [ $ddr -lt 0 ]; then
			newcnt=`grep -c "WEDGE_CR_SUPPORT" $NEW_PREINST_FILE`
			if [ $newcnt -eq 0 ];then
				let rc=$rc+1
				echo -e $DDR_2G_NOTBACK4GFOS >> $STATUS_FILE
				echo -e $DDR_2G_NOTBACK4GFOS >> $BNA_STATUS_FILE
				return $STS_ERR;
                        fi
                fi
	esac
	return $STS_OK;
}

################ Check for Wedge64 Huawei version 162.7/8/9 platform ######################
HUAWEI_SWITCH_SPECIAL_NOTSUPPORTED_MSG="Cannot download the requested firmware because it does not support this switch type."
check_special_huawei_disable_enc_support()
{
    # checks for active or standby
    if [ $ACTIVECP ] ; then
    # Check for Hauwei special switch with disabled encryption/decryption.
    swtype=`correcthost_to_curr_vfid /fabos/bin/switchshow | awk '/switchType/ {print $2}'`
    if [ $swtype == "162.7" ] || [ $swtype == "173.4" ]; then
        # HW is special Huawei platform, now check supported firmware release tag;
        sp_huawei_supported=`grep -c "HUAWEI_SPECIAL_SWBD_SUPPORTED" $NEW_PREINST_FILE`
        if [ $sp_huawei_supported -ne 0 ]; then
            # this release has or supports the huawei special.
            return $STS_OK;
        else
            # missing the above firmware tag will imply no support;
            # special hauwei switch does NOT support this fos, so display error msg;
            let rc=$rc+1
            echo -e $rc:    $HUAWEI_SWITCH_SPECIAL_NOTSUPPORTED_MSG >> $STATUS_FILE
            echo -e $rc:    $HUAWEI_SWITCH_SPECIAL_NOTSUPPORTED_MSG >> $BNA_STATUS_FILE
            return $STS_ERR;
        fi
    else
        # ignore other platforms;
        return $STS_OK;
    fi
    fi
    return $STS_OK;
}

############ CLEAN ADDRESS BIT ############
check_clean_address_bit_enabled()
{
	# Check for any configured ports
	clean_address_bit_enabled=`correcthost_to_curr_vfid /fabos/cliexec/portcfgshow | grep "Clean Address" | grep -c ON`
	if [ $clean_address_bit_enabled -ne 0 ]; then
		# One or more ports are configured and new release does not support Clean Address Bit; Block
		return $STS_ERR;
	fi

	return $STS_OK;
}

LS_ACC_CLEAN_ADDRESS_BIT_BLOCKING_MSG="Cannot download the requested firmware because it does not support Clean Address Bit settings used on this Switch. Please retry firmwaredownload using a firmware version that supports Clean Address Bit, or disable the setting on all ports using the portCfgCleanAddress command."
check_for_clean_address_bit()
{
	# Check for Clean Address Bit support
	clean_address_bit_supported=`grep -c "LS_ACC_CLEAN_ADDRESS_BIT_SUPPORTED" $NEW_PREINST_FILE`
	if [ $clean_address_bit_supported -ne 0 ]; then
		# Clean Address Bit supported, we can proceed
		return $STS_OK;
	fi

	# Check for Virtual Fabrics
	if [ $VF_ENABLED -ne $STS_OK ]; then
		if [ $ACTIVECP ] ; then
			for_all_contexts check_clean_address_bit_enabled
		else
			for_all_contexts_standby check_clean_address_bit_enabled
		fi
	else
		check_clean_address_bit_enabled;
	fi

	if [ $? -ne $STS_OK ]; then
		let rc=$rc+1
		echo -e $LS_ACC_CLEAN_ADDRESS_BIT_BLOCKING_MSG >> $STATUS_FILE
		echo -e $LS_ACC_CLEAN_ADDRESS_BIT_BLOCKING_MSG >> $BNA_STATUS_FILE
		return $STS_ERR
	fi

	# No blocking factors
	return $STS_OK;
}

############ CLEAN BSL ############
BSL_BLOCKING_MSG="Cannot download the requested firmware because it does not support BSN Support Link settings used on this Switch. Please disable the setting using the supportlink --disable command."
check_for_BSL()
{
	# Check for BSL.
	BSL_supported=`grep -c "BSN_SUPPORT_LINK_SUPPORTED" $NEW_PREINST_FILE`
	if [ $BSL_supported -ne 0 ]; then
		# BSL supported, we can proceed
		return $STS_OK;
	fi

	# If on standby CP then before attempting to run supportlink 
	# first check if the Actve CP has supportlink
	# supportlink may not exist on the active CP if it was downgraded in step 1 of the dual step downgrade scenario.
	if [ ! $ACTIVECP ] ; then
		supportlinkDoesNotExist=$(correcthost ls -al /fabos/link_bin/supportlink  2> ${NULL} | grep -c "No such file or directory")
		if [ $supportlinkDoesNotExist ]; then
			return $STS_OK;
		fi
	fi

	# Check for BSL being enabled
	BSL_enabled=`correcthost_to_curr_vfid /fabos/link_bin/supportlink --show | grep "Support Link State" | grep -c Enabled`
	if [ $BSL_enabled -eq 1 ]; then
		# BSL is enabled. block
		let rc=$rc+1
		echo -e $BSL_BLOCKING_MSG >> $STATUS_FILE
		echo -e $BSL_BLOCKING_MSG >> $BNA_STATUS_FILE
		return $STS_ERR;
	fi

	# No blocking factors
	return $STS_OK;
}

###############################################################################
#
# Check to block downgrade to 9.0.0 from 9.0.0a if FCR EX-Port configured with differnet long distance fabric mode
#

FCR_LONG_DISTANCE_FABRIC_MODE_CONFLICT=" Downgrade to selected version is not allowed because some of the edge fabric Long distance fabric mode mismatch with backbone configuration"

check_fcr_long_distance_fabric_mode_configured() {

	# verify if there is any conflict configuration
	if err=`correcthost_to_curr_vfid /fabos/cliexec/fcrdbgportshow --modeconflict 2>/dev/null | grep "Long distance fabric mode conflict"` ; then
		return $STS_ERR
	fi
	return $STS_OK
}

check_fcr_long_distance_fabric_mode_conflict() {

	fcr_long_distance_fabric_mode_supported=`grep -c "FCR_LONG_DISTANCE_FABRIC_MODE_SUPPORT" $NEW_PREINST_FILE`
	if [ $fcr_long_distance_fabric_mode_supported -ne 0 ]; then
		# The new release supports this feature so ok to proceed.
		return $STS_OK
	fi
	# Check for Virtual Fabrics
	if [ $VF_ENABLED -ne $STS_OK ]; then
		CHASSISCMD="cmd_chassis"
		if [ $ACTIVECP ] ; then
			for_all_contexts check_fcr_long_distance_fabric_mode_configured
		else
			for_all_contexts_standby check_fcr_long_distance_fabric_mode_configured
		fi
	else
		# vf disabled
		check_fcr_long_distance_fabric_mode_configured;
	fi
	if [ $? -ne $STS_OK ]; then
		let rc=$rc+1
		echo -e $FCR_LONG_DISTANCE_FABRIC_MODE_CONFLICT >> $STATUS_FILE
		echo -e $FCR_LONG_DISTANCE_FABRIC_MODE_CONFLICT >> $BNA_STATUS_FILE
		return $STS_ERR
	fi
	return $STS_OK

}

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

#
# Check for Emulex F-Port trunking configuration before downgrading to lower firmware version
# 8.1.x and 8.2.0 from 8.2.1.
#
EMULEX_FPORT_TRUNNKING_FWDL_CHECK="Downgrade is not allowed because some F-Ports devices are in trunk. Please disable the trunking on these devices and the corresponding switch ports before downgrading firmware."

check_emulex_fport_trunking_configured() {
	slot_based=`correcthost_to_curr_vfid /fabos/bin/slotshow | grep "Not supported on this platform"`
	if [ "$slot_based" == "" ] ; then
		port_list=`correcthost_to_curr_vfid /fabos/bin/switchshow | grep "F-Port" | awk '{print $2"/"$3}'`
	else
		port_list=`correcthost_to_curr_vfid /fabos/bin/switchshow | grep "F-Port" | awk '{print $1}'`
	fi

	role=$ROLE_ID
	ROLE_ID=root
	for port in $port_list
	do
		local_flags=`correcthost_to_curr_vfid /fabos/cliexec/fabportshow $port | grep "Local Flags" | awk '{print $3}'`
		bitmask="0x08000000"
		let ret="$local_flags & $bitmask"
		if [ $ret -ne 0 ]; then
			return $STS_ERR
		fi
	done
	ROLE_ID=$role

	return $STS_OK
}

check_emulex_fport_trunking() {
	emulex_fport_trunking_supported=`grep -c "EMULEX_FPORT_TRUNKING_SUPPORTED" $NEW_PREINST_FILE`
	if [ $emulex_fport_trunking_supported -ne 0 ]; then
		# The new release supports this feature so ok to proceed.
		return $STS_OK
	fi
	
	# Check for Virtual Fabrics
	if [ $VF_ENABLED -ne $STS_OK ]; then
		CHASSISCMD="cmd_chassis"
		if [ $ACTIVECP ] ; then
			for_all_contexts check_emulex_fport_trunking_configured
		else
			for_all_contexts_standby check_emulex_fport_trunking_configured
		fi
	else
		check_emulex_fport_trunking_configured;
	fi
	
	if [ $? -ne $STS_OK ]; then 
		let rc=$rc+1
		echo -e $EMULEX_FPORT_TRUNNKING_FWDL_CHECK >> $STATUS_FILE
		echo -e $EMULEX_FPORT_TRUNNKING_FWDL_CHECK >> $BNA_STATUS_FILE
		return $STS_ERR
	fi
	return $STS_OK
}

not_gen7_switch() {

	case ${SWBD##SWBD} in
	'179' | '180' | '181')
	    return $STS_ERR
	    ;;
	*)
	    return $STS_OK
	    ;;
	esac
}

GEN7_SWITCH_NOT_SUPPORTED="Downgrade is not allowed to the target firmware 9.0.0 for this platform."

check_gen7_support() {
	if not_gen7_switch; then
		#This is not a gen7 switch. So proceed to download.
		return $STS_OK
	fi

	if [ ${TO_MAJOR} -lt 9 ]; then
		return $STS_OK
	fi

	gen7_supported=`grep -c "GEN7_SUPPORTED" $NEW_PREINST_FILE`
	if [ $gen7_supported -ne 0 ]; then
		# The new release supports this feature so ok to proceed.
		return $STS_OK
	fi
	
	echo -e $GEN7_SWITCH_NOT_SUPPORTED >> $STATUS_FILE
	echo -e $GEN7_SWITCH_NOT_SUPPORTED >> $BNA_STATUS_FILE
	let rc=$rc+1
	return $STS_ERR
}

##############################################################################
#
# Cypress 16MB bootflash Feature compatibility checks.
# Downgrade to a release that does not support this feature is not allowed
#
##############################################################################
CYPRESS_MANUFACTURER_ID=0x000001
CYPRESS_CHIPID=0x002101
CYPRESS_BOOTFLASH_BLOCKING_MSG="Cannot download the requested firmware because it does not support the Cypress Bootflash. Please retry firmwaredownload using a version that supports Cypress Bootflash"
check_cypress_bootflash()
{
	# Need to check compatibility only on Lando CP
    case ${SWBD##SWBD} in
        '165' | '166')
        ;;
    *)
        # Not a Lando CP in a chassis, ok to download
        return $STS_OK;
        ;;
    esac

	cypress_bootflash_supported=`grep -c "CYPRESS_MID01_BOOTFLASH_SUPPORTED" $NEW_PREINST_FILE`
	if [ $cypress_bootflash_supported -ne 0 ]; then
		# The new release supports the Cpress Bootflash
		# ok to proceed without further compatibility checking.
		return $STS_OK;
	fi

		
	# The version being downloaded does not support the Cypress Bootflash
	# Check if the system has the Cypress BootfFlash and if so block the download
	# Cypress Bootflash: Manufacturer ID 0x000001 Chip ID 0x002101 size 0x1000000 bytes
	manufacturerId=$(cat /proc/mtd_device_info | awk '/Manufacturer ID / {print $3}')
	chipId=$(cat /proc/mtd_device_info | awk '/Chip ID / {print $6}')

	if [ $manufacturerId == $CYPRESS_MANUFACTURER_ID ] && [ $chipId == $CYPRESS_CHIPID ]; then
		let rc=$rc+1
		echo -e $rc:    $CYPRESS_BOOTFLASH_BLOCKING_MSG >> $STATUS_FILE
		echo -e $rc:    $CYPRESS_BOOTFLASH_BLOCKING_MSG >> $BNA_STATUS_FILE
		return $STS_ERR
	fi


    #
    # Current CP does not have Cypress bootflash. check if the other CP has it.
    # if redundant CP is has CYPRESS bootflash then block downgrades to 
    # firmware versions that do not support CYPRESS bootflash
    #
    if [ $(ha_state) == "NOSYNC" ]; then
		# No Cypress Bootflash found and CPs not in SYNC, OK to download
		return $STS_OK
		
	fi

	manufacturerId=`/usr/bin/rsh -n $(otherhost) ROLE_ID=root LOGIN_ID=root CURRENT_AD=0 /bin/cat /proc/mtd_device_info | awk '/Manufacturer ID / {print $3}'`
	chipId=$(/usr/bin/rsh -n $(otherhost) ROLE_ID=root LOGIN_ID=root CURRENT_AD=0 /bin/cat /proc/mtd_device_info | awk '/Chip ID / {print $6}')

	if [ $manufacturerId == $CYPRESS_MANUFACTURER_ID ] && [ $chipId == $CYPRESS_CHIPID ]; then
		# Other CP has cypress bootflash and the firmware does not support it. Block download
		let rc=$rc+1
		echo -e $rc:    $CYPRESS_BOOTFLASH_BLOCKING_MSG >> $STATUS_FILE
		echo -e $rc:    $CYPRESS_BOOTFLASH_BLOCKING_MSG >> $BNA_STATUS_FILE
		return $STS_ERR
	fi

	# No Cypress Bootflash found, OK to download
	return $STS_OK
}

##############################################################################
#
# Address following FICON Requirements in 9.0.0 Patch B.
#
# Add a warning message that ports will toggle if a downgrade from this
# firmware is done to any other firmware which does not adhere to these
# requirements.
#
##############################################################################
FMS_DISABLED_FICON_LS_WARN="WARNING !!!!! FMS Mode is disabled in FICON Logical switch. Proceeding with downgrade will be disruptive for online ports in this FICON LS."

check_fmsmode_in_ficon_ls()
{
	if [ $VF_ENABLED -ne $STS_OK ]; then
		FICON_LS=`correcthost_to_curr_vfid /fabos/bin/switchshow | grep "Ficon Switch:" | cut -d ' ' -f 12 | cut -d ',' -f 1`
	else
		FICON_LS="No"
	fi

	if [ "$FICON_LS" == "Yes" ] ; then
		FMS_MODE=`CONFIGSHOW | /bin/grep "ficu.fmsmode" | /usr/bin/cut -d ':' -f2`
		if [ "$FMS_MODE" == "0" ] ; then
			add_warn_status_fid "$FMS_DISABLED_FICON_LS_WARN" "$FMS_DISABLED_FICON_LS_WARN" "FID:$CURRENT_VF"
		fi
	fi

	return $STS_OK
}

check_ficon_features()
{
	#
	# If disruptive firmware download is given by user, need not warn the
	# user about port toggle.
	#

	is_fwdl_arg "s"
	if [ $? -eq $STS_OK ]; then
		return $STS_OK
	fi

	disruptive_downgrade=`grep -c "FICON_DISRUPTIVE_DOWNGRADE" $NEW_PREINST_FILE`
	if [ $disruptive_downgrade -ne 0 ]; then
		# The new release supports this feature so ok to proceed.
		return $STS_OK
	fi

	# The target firmware does not have CUP filters in FMS disabled mode.
	TEST_FIDS check_fmsmode_in_ficon_ls
}

#
# Block upgrade the Graphite32 to any FOS version that don't support Graphite32 Miss Hash
# License Issue.
#

GRAPHITE32_MISS_HASH_BLOCKING_MSG="Firmware upgrade is not allowed as Target Release doesn't support Graphite32 enhanced licensing support"

check_graphite32_miss_hash_support()
{
	GRAPHITE32_WITH_ISSUE_FILE=/etc/config/.hash714
	# If GRAPHITE32_WITH_ISSUE_FILE exist, it is a graphite32 with licensing issue
	# If not, OK to proceed
	if [ ! -f $GRAPHITE32_WITH_ISSUE_FILE ]; then
		return $STS_OK;
	fi

	# Check if target firmware support GRAPHITE32_MISS_HASH fix
	graphite32_miss_hash_supported=`grep -c "GRAPHITE32_MISS_HASH_SUPPORT" $NEW_PREINST_FILE`
	if [ $graphite32_miss_hash_supported -ne 0 ]; then
		# The new release supports graphite32 miss hash
		# OK to proceed 
		return $STS_OK;
	fi

	# It is a graphite32 with licensing issue
	# and Target release doesn't support GRAPHITE32_MISS_HASH fix
	# Block the firmware upgrade
	let rc=$rc+1
	echo -e $rc:    $GRAPHITE32_MISS_HASH_BLOCKING_MSG >> $STATUS_FILE
	echo -e $rc:    $GRAPHITE32_MISS_HASH_BLOCKING_MSG >> $BNA_STATUS_FILE
	return $STS_ERR
}

##############################################################################
#
# 32G LWL SFP support compatibility checks.
# Downgrade to a release that does not support this feature is not allowed
#
##############################################################################
LWL_32G_SFP_BLOCKING_MSG="Downgrade is not allowed since LWL 32G secure SFP is not supported. Please remove the LWL 32G secure SFP and retry firmwaredownload. The SFP is presents on ports "

check_32G_lwl_media()
{
	# This check is applicable only for gen7
	# Return Success for all other platforms

	rey_blade_id=216
	rey32_blade_id=218
	rey_blade_slots=""

	case ${SWBD##SWBD} in
	'181')
	    ;;
	'165' | '166' | '179' | '180')
		rey_blade_slots=$(correcthost /fabos/cliexec/slotshow -m 2>${NULL} | grep -w -E "$rey_blade_id|$rey32_blade_id" | awk '{print $1}')
		if [ "$rey_blade_slots" = "" ]; then
			# Rey blade is not present
			return $STS_OK
		fi
	    ;;
	*)
	    return $STS_OK
	    ;;
	esac

	# This check is applicable for all platforms 

	lwl_32G_sfp_supported=`grep -c "LWL_32G_SFP_SUPPORTED" $NEW_PREINST_FILE`
	if [ $lwl_32G_sfp_supported -ne 0 ]; then
		# The new release supports the 32G LWL SFP
		# ok to proceed without further compatibility checking.
		return $STS_OK;
	fi

	# Get list of port which have the 32G LWL media plugged in
	#media_identifier="57-1000486-01"
	#serial_identifier="JDF"

#	ports_with_unsupported_media=`correcthost_all_vfs /fabos/cliexec/sfpshow | grep "$serial_identifier"  | sed '/Slot[ ]*/s///g' | sed '/Port[ ]*/s///g' | cut -f1 -d ":"`


	serial_identifier="JDF[A-Z0-9]{12}S"
	ports_with_unsupported_media=`correcthost_all_vfs /fabos/cliexec/sfpshow | grep -E "$serial_identifier"  | sed '/Slot[ ]*/s///g' | sed '/Port[ ]*/s///g' | cut -f1 -d ":"`

	ports_with_lwl_32G_secure_sfp=`echo $ports_with_unsupported_media | sed '/ /s//,/g'`

	if [ "$ports_with_lwl_32G_secure_sfp" = "" ]; then
		# There are no lwl 32G secure  media plugged in
	return $STS_OK
	else
		echo -e $rc:    $LWL_32G_SFP_BLOCKING_MSG $ports_with_lwl_32G_secure_sfp >> $STATUS_FILE
		echo -e $rc:    $LWL_32G_SFP_BLOCKING_MSG $ports_with_lwl_32G_secure_sfp >> $BNA_STATUS_FILE
		let rc=$rc+1
		return $STS_ERR
	fi

}

# main()
#
echo -n > $STATUS_FILE      # Clear the error file
echo -n > $BNA_STATUS_FILE  # Clear the BNA error file
echo -n > $FWDL_WARN_STATUS_FILE		# Clear the warning file
echo -n > $BNA_WARN_STATUS_FILE			# Clear the BNA warning file

echo "The following item(s) need to be addressed before downloading the specified firmware:" >> $STATUS_FILE
#echo "Please address the following before downloading the specified firmware:" >> $STATUS_FILE

check_new_8548_CP_fw_compatibility
check_non_dfe
check_qsfpp_icl
check_2km_32G_qsfp
check_buf_op_mode
check_permanet_root_disable_huawei_supported
check_enhanced_fc8_blades
check_nondfeforcedisable_supported
check_tacacs_encryption
check_radius_tacacs_encryption
check_serdes_version_between_cur_n_new_fos
check_for_new_128MB_flash
check_wedgecr
check_special_huawei_disable_enc_support
check_for_clean_address_bit
check_for_BSL
check_emulex_fport_trunking
check_ldap_support_for_group_length
check_fcr_long_distance_fabric_mode_conflict
check_gen7_support
check_cypress_bootflash
check_ficon_features
check_graphite32_miss_hash_support
check_lumentum_32G_qsfp_gen7_core_blades
check_32G_lwl_media

exit $rc
