#!/bin/sh
PATH=$PATH:/usr/local/bin
. sig_catcher

# Sel logging variables, please refer netapp/include/sel.h for more info
# values under sel_component_t & sel_sev_t
SEL_PARAM="SP.notice"
SEL_LOGGER="sel_logger"
pcie_return_code=0
SHOWUSAGE=255
PLATFORM_MODEL=/usr/local/bin/platform_model
BUSY_FLAG="/tmp/ACCESSING_PCIESWITCH_EEPROM"

cleanup_exit()
#$1: exit code
{
        local exit_val=$1
        if [ -f $BUSY_FLAG ];then
                rm -f $BUSY_FLAG
        fi
        exit $exit_val
}

#
# Signal handler, for when the user presses ctrl-c or the process gets a shutdown signal
#
handlesignal() {

    echo "**ctrl-c pressed, stopping**"
        cleanup_exit 1

        trap "echo ctrl-c already pressed, stopping in progress " SIGHUP SIGINT SIGTERM
}

# enable the above signalhander
trap handlesignal SIGHUP SIGINT SIGTERM

update_return_code()
#1 : current return code
{
	#if current return code !=0, update it to pcie_return_code
	if [ $1 -ne 0 ];then
		pcie_return_code=$1
	fi
}
get_silicon_rev()
{
	silicon_rev=$(/usr/local/bin/pcieswitch version $sw_id 2>/dev/null)
	if [ $? -ne 0 ]; then
		echo "Error: can't get chip revision ID ($silicon_rev)."
		cleanup_exit 0
	fi
	rev_id=Rev$silicon_rev
}
find_default_file() 
{
	#FASRAZL is RazorL, FASRAZM is RazorM
	if [ 0 -eq $platformtype ]; then
		filename_pre="FASRAZL"
	elif [ 1 -eq $platformtype ]; then
		filename_pre="FASRAZM"
	fi

	# find default file in /firmware/${platform}/switch
	if [ 186 = ${silicon_rev} ]; then
		#BA revision
		echo "There is no default file for PCIe switch chip revision BAh."
		echo "For revision BAh, please use pcieswitch_eeprom.sh and specify the file name for the operation."
		cleanup_exit 0
	fi
	filename=$(ls /firmware/${platform}/pcieswitch/${filename_pre}*_*${sw_id}_*.bin 2>/dev/null)
	if [ "$filename" == "" ]; then
		echo "Can't find default file in /firmware/.../pcieswitch"
	    	cleanup_exit 1
	fi
	echo "Locating default file ... "
}
exit_msg()
{
	echo "The platform doesn't match."
	cleanup_exit 1
}

usage() 
{
cat << USAGE_HERE
Usage:
	pcieswitch_eeprom.sh list - List all PCIe switch IDs
	pcieswitch_eeprom.sh program_wr <pcie-switch-id> <platform type> [configuration-file-name][-f] - Download the configuration file into the EEPROM
	pcieswitch_eeprom.sh program_rd <pcie-switch-id>  - Read back the programmed contents from the EEPROM
	pcieswitch_eeprom.sh verify <pcie-switch-id> <platform type> [configuration-file-name] [-d] - Compare the contents of the EEPROM with the configuration file
	pcieswitch_eeprom.sh version <pcie-switch-id> [-a] - Version of the configuration file in the PCIe switch EEPROM
	pcieswitch_eeprom.sh reset <pcie-switch-id> [-a] - Reset a PCIe switch 
	pcieswitch_eeprom.sh crc <filename> - Calculate CRC of the file by software
	<pcie-switch-id>:
	valid vaule : 0 - $((max_pcieswitch_num-1))
	<platform type>
		0: RazorL,  1: RazorM
	[configuration-file-name]:
		If the file name is not specified, default file will be used.
	[-f]
		When -f is specified, it forces to programming the file even the revision of the file is smaller than or equal to the revision of the EEPROM.
	[-d]
		When -d is specified, the contents of the EEPROM/configuration file and differences will be dumped
		if data between the EEPROM and configuration file are different.
	[-a]
		When -a is specified, NetApp and vendor revisions will be displayed.

	example: program the default configuration file into pcieswitch 0.
	pcieswitch_eeprom.sh program_wr 0 0
USAGE_HERE
    cleanup_exit 1
}

check_platform_type() 
{

	if [ -z $platformtype ]; then

		#platform type is a null string
		echo "platform type(null string) is not a digit"
		usage
	elif [ $platformtype != $((platformtype + 0)) ];then

		#platform type is a string
		echo "platform type($platformtype) is not a digit"
		usage
	elif [ $platformtype -lt 0 -o $platformtype -gt 4 ]; then

		#platform type is a digit but the value is not correct
		echo "platform type($platformtype) is not correct"
		usage
	fi

	case $platformtype in
	0)#(RazorL)
		if [ $platform = "RazorL" ]; then
			input_modelname=$platform
		else
			exit_msg
		fi
	;;
	1)#(RazorM)
		if [ $platform = "RazorM" ]; then
			input_modelname=$platform
		else
			exit_msg
		fi
	;;
	*)
		echo "platform type($platformtype) is not supported"
		usage
	;;
	esac

}
validate_file()
# $1: filename
{
	
	if [ ! -f $1 ]; then
		echo "Error: input file doesn't exit."
		usage
	fi
}
platform=$(cat /var/run/platform)
partner_type=$(cat /var/run/partner)
bbsp_code=$(cat /sys/class/hwmon/bbsp)
silicon_rev=202
rev_id="Rev4"

case $platform in
    RazorL)
         max_pcieswitch_num=2
	    ;;
    RazorM)
         max_pcieswitch_num=1
	    ;;
    *)
	echo "Command not applicable on this platform"
	exit 1
    ;;
esac

if [ -f $BUSY_FLAG ]; then
	echo "pciewitch_eeprom.sh is currently running. Please try again later."
        exit 1
else
        touch $BUSY_FLAG
fi

if [ $# -lt 1 ];then
  usage
fi

#Check if CPU complex is power on, if not, show a message out and abort the operation
power_status=$(agentlite power status | cut -d : -f 2)
if [ 0 -eq ${power_status} ]; then
	echo "CPU complex is power off. Please power on CPU complex"
fi


# the first argument is command
cmd=${1}

# the second argument is pcieswitch id
sw_id=${2}

# the third argument is platform type
platformtype=${3}

# the fourth argument is name of the configuration file
filename=${4} 

# the fifth argument is option -d or -f
swopt=${5}



if [ "$cmd" == "program_wr" ];then
	check_platform_type
	#Check if ontap is running, if so, ask user if he wants to continue.
	if [ "$bbsp_code" == "2f" ];then
		read -p "This $cmd operation is disruptive when storage controller is operational. Continue (y/n)?" ans
		case "$ans" in
			Y*|y*)
				echo "Continue ..."
				;;
			*)
				echo "Exit the application"
				cleanup_exit 1
				;;
			esac
	fi

	if [ "$filename" == "-f" ] ;then
		swopt="-f"
	fi

	if [ -z "$filename" -o "$filename" == "-f" ] ;then
		get_silicon_rev
		find_default_file
	fi
	if [ -z $swopt ] ;then
			get_silicon_rev
	fi
	old_version=$(/usr/local/bin/pcieswitch version $sw_id 2> /dev/null)
	if [ $? -ne 0 -o "$old_version" == "version-unknown" ];then
	  #Fail to get version
	  old_version="NA"
	fi

elif [ "$cmd" == "verify" ];then
	check_platform_type
	if [ "$filename" == "-d" ] ;then
		swopt="-d"
	fi

	if [ -z "$filename" -o "$filename" == "-d" ] ;then
		get_silicon_rev
		find_default_file
	fi
elif [ "$cmd" == "crc" ];then
	filename=${2}
	validate_file $filename

	#This command doesn't access any hardware. sw_id can be 0~6.
	sw_id=0
elif [ "$cmd" == "version" ] ;then
	swopt=${3}
fi

#In order to avoid ouput two usages of commands(one from switchpcie, other from switchpcie_eeprom.sh),
#direct usage of commands from switchpcie to /dev/null.
/usr/local/bin/pcieswitch $cmd $sw_id $filename $swopt 2>/dev/null

update_return_code $?

if [ "$cmd" == "program_wr" ];then
	file_version=$(echo $filename | awk -F_ '{printf $NF}'| sed -e 's/Rev//g' | sed -e's/.bin//g')
	update_return_code $?
	if [ $pcie_return_code -eq 0 ]; then
		$SEL_LOGGER $SEL_PARAM "pcie_switch update: Old: $old_version, New: $file_version"
	else
		#Add an SEL entry for update failure, except input parameter error.
		$SEL_LOGGER $SEL_PARAM "pcie_switch update: $old_version to $file_version failed"
	fi
	update_return_code $?
fi
if [ $pcie_return_code -ne 0 ];then
	if [ $pcie_return_code -eq $SHOWUSAGE ]; then
		usage
	else
		if [ -n $filename ];then
			#Filename contains folder name which includes RazorL/RazorM information, remove folder name.
			filename=$(echo $filename | awk -F/ '{printf $NF}')
		fi
		echo "Failed($pcie_return_code) to execute /usr/local/bin/pcieswitch $cmd $sw_id $filename $swopt"
	fi
fi
echo "Done"
cleanup_exit 0
