#!/bin/sh
#Environment argument
I82571_484_ID="0x105e8086" 	#INTEL 82571 ABN484 VIDDID
I82571_482_ID="0x105f8086"	#INDEL 82571 ABN482 VIDDID
BYPASSID="4820 4840 4841 4260 5124 5212 5312 5514 5224 5412"
ABN482=4820	# ABN482 BYPASS ID
ABN484=4840	# ABN484 BYPASS ID
ABN484L=4841	# ABN484L BYPASS ID
ABN426=4260 	# ABN426 BYPASS ID
NIP5124X=5124	# NIP5124 BYPASS ID
NIP5514X=5514	# NIP5124 BYPASS ID one copper
NIP5212X=5212	# NIP5212 BYPASS ID
NIP5312X=5312	# NIP5312 BYPASS ID
NIP5224X=5224	# NIP5224 BYPASS ID
NIP5412X=5412	# NIP5412 BYPASS ID one copper
W10ADDR="0x0010"	#eeprom BYPASSID for register
W16ADDR="0x0016"	#eeprom BYPASS SDID
W2AADDR="0x002a"	#eeprom BYPASSID for 10Gregister
W2CADDR="0x002c"    #eeprom BYPASS generation for 10Gregister
W12ADDR="0x0012"	#eeprom segment register
W20ADDR="0x0020"	#eeprom SDP register
W40ADDR="0x0040"	#eeprom SDP register
ABN484TYPE=1	#ABN484 ByPass parameter
ABN482TYPE=2	#ABN482 ByPass parameter
ABN484LTYPE=3	#ABN484L ByPass parameter
ABN5514TYPE=4	#ABN5514 ByPass parameter
ABN426TYPE=5	#ABN426 ByPass parameter
NIP5224TYPE=6	#NIP5224 ByPass parameter
NIP5412TYPE=7	#NIP5412 ByPass parameter
slota="0"	#default Slot is zero
slotb="0"	#default Slot is zero
slotc="0"	#default Slot is zero
slotd="0"	#default Slot is zero
PCIBUS="all"	#default pci bus is for all
INT=1		#Ethtool only support v1.8 above version
DEC=8		#Ethtool only support v1.8 above version
CFG_DIR=mb_cfg

#print_help
print_help(){
echo ""
echo "Addressing functionality usage:"
echo "  sh addressing.sh <MB Name> [Command] ..."
echo ""
echo "MB_NAME: The target mother board model name"
echo "  ex. NAR7090  => If motherboard is NAR-7090"
echo "[Command]"
echo "  display => It will detect and show the slot information (type of add-card)"
echo "             in slot order"
echo "  set     => It will auto write the probing information (add-card's proper I2C"
echo "             address) to add-card's eeprom"
echo "  default => It will restore the factory default value to add-card's eeprom"
echo ""
echo "Or use -s option to check support model list"
echo
}

print_support()
{
	local SUPPORT_MODEL="`ls $CFG_DIR | sed 's/.cfg//g'`"
	echo "Addressing Support Model list:"
	echo
	echo $SUPPORT_MODEL
	echo
}
#print help for motherboard which uses CPU with NB inside.
print_sub_help()
{
	local MB_NAME="$1"
	echo ""
	echo "Addressing usage:"
	echo "    $1 platform needs to be assigned CPU type. "
	echo ""
	echo "    Usage: "
	echo "        <MB Name>-<CPU type>"
	echo "        ex. CAR4000-lyn  => If CPU type is Lynnfield."
	echo ""
	case "$MB_NAME" in
		CAR4000)
			echo "    Support list: "
			echo "        Lynnfield: CAR4000-lyn"
			echo "        Clarkdale: CAR4000-cla"
		;;
	esac
	echo ""
}

#modify slot sequence parameter
select_model()
{
case $1 in
$NIP5514X)
	[ "$2" = 0 ] && slota=$ABN5514TYPE
	[ "$2" = 1 ] && slotb=$ABN5514TYPE
	[ "$2" = 2 ] && slotc=$ABN5514TYPE
	[ "$2" = 3 ] && slotd=$ABN5514TYPE
	;;
$NIP5412X)
	[ "$2" = 0 ] && slota=$NIP5412TYPE
	[ "$2" = 1 ] && slotb=$NIP5412TYPE
	[ "$2" = 2 ] && slotc=$NIP5412TYPE
	[ "$2" = 3 ] && slotd=$NIP5412TYPE
	;;
$ABN484L|$NIP5124X)
	[ "$2" = 0 ] && slota=$ABN484LTYPE
	[ "$2" = 1 ] && slotb=$ABN484LTYPE
	[ "$2" = 2 ] && slotc=$ABN484LTYPE
	[ "$2" = 3 ] && slotd=$ABN484LTYPE
	;;
$ABN484)
	[ "$2" = 0 ] && slota=$ABN484TYPE
	[ "$2" = 1 ] && slotb=$ABN484TYPE
	[ "$2" = 2 ] && slotc=$ABN484TYPE
	[ "$2" = 3 ] && slotd=$ABN484TYPE
	;;
$ABN482|$NIP5212X|$NIP5312X)
	[ "$2" = 0 ] && slota=$ABN482TYPE
	[ "$2" = 1 ] && slotb=$ABN482TYPE
	[ "$2" = 2 ] && slotc=$ABN482TYPE
	[ "$2" = 3 ] && slotd=$ABN482TYPE
	;;
$ABN426)
	[ "$2" = 0 ] && slota=$ABN426TYPE
	[ "$2" = 1 ] && slotb=$ABN426TYPE
	[ "$2" = 2 ] && slotc=$ABN426TYPE
	[ "$2" = 3 ] && slotd=$ABN426TYPE
	;;
$NIP5224X)
       [ "$2" = 0 ] && slota=$NIP5224TYPE
       [ "$2" = 1 ] && slotb=$NIP5224TYPE
       [ "$2" = 2 ] && slotc=$NIP5224TYPE
       [ "$2" = 3 ] && slotd=$NIP5224TYPE
       ;;
esac
}
#Set slot number and modify slot sequence parameter
select_slot()
{
	#Define checking slot list
	if [ -n "$3" ];then
		# If there is dual CPU pci bus condition, 
		# check slot id by specific bus.
		eval SLOT_LIST=\$SLOT$3
	else
		SLOT_LIST="SLOTA SLOTB SLOTC SLOTD"
	fi

	for slotn in $SLOT_LIST;do
		eval echo \$$slotn | grep $1 > /dev/null 2>&1
		if [ "$?" = 0 ] ;then
			if [ "$slotn" = "SLOTA" ] ; then
				SLOT=A
			elif [ "$slotn" = "SLOTB" ] ; then
				SLOT=B
			elif [ "$slotn" = "SLOTC" ] ; then
				SLOT=C
			elif [ "$slotn" = "SLOTD" ] ; then
				SLOT=D
			fi
		fi
	done

	# Re-select slot if it is on extend slot
	if [ "$RSLOTN" -gt 0 ];then
		SLOTE="$SLOT$RSLOTN"
		case "$SLOTE" in
			$SLOTA) SLOT=A
			;;
			$SLOTB) SLOT=B
			;;
			$SLOTC) SLOT=C
			;;
			$SLOTD) SLOT=D
			;;
		esac
	fi

	case $SLOT in
		A)
		select_model $2 0
                ;;
		B)
		select_model $2 1
                ;;
		C)
		select_model $2 2
                ;;
		D)
		select_model $2 3
                ;;
	esac
	SLOT=$(echo $SLOT)
}

get_riser_slot(){
	local eslot
	for eslot in $SLOTR;do
		eval echo \$$eslot | grep $1 > /dev/null 2>&1
		if [ $? -eq 0 ];then
			echo $eslot | sed 's/EXTEND//g'
		fi
	done
}

getslot(){
	for z in $PCIBUS;do
		[ "$z" = "all" ] && z=""
		for y in `find /proc/bus/pci/$z -type f`; do
			#Check if there is needed to seperate pci bus for detection.
			if [ -n "$z" ];then
				eval SLOT_LIST=\$SLOT$z
				SLOTT=""
				for s in $SLOT_LIST;do
					eval SLOTT="\"\$SLOTT \$$s\""
				done
			fi
			for x in $SLOTT ; do
				check=""
				BUSN=""
				SECONDARY=""
				SUBORDINATE=""
				SLOT=""
				EXTEND_DEV=""
				#Check if this is slot device then get its bus number
				check=`hexdump $y | grep "\<$x\>" 2>/dev/null`
				if [ -n "$check" ];then
					BUSN="$(hexdump -C $y | awk '/^00000010/ {print $11}')"
					SECONDARY=$BUSN
					SUBORDINATE="$(hexdump -C $y | awk '/^00000010/ {print $12}')"
				else
					continue
				fi

				#Check if there is a riser under this slot
				SLOTDEV="`hexdump /proc/bus/pci/$BUSN/00.0 2> /dev/null |\
				           awk '/^0000000/ {print $2$3}'`"
				if [ -n "$RISER" -a "$SLOTDEV" = "$RISER" ];then
					RISER_BUSN="`printf "%02x" $((0x$BUSN+1))`"
					for ext in $SLOTR;do
						eval EXTEND_DEV="\"\$EXTEND_DEV \$$ext\""
					done
				elif [ -n "$SLOTDEV" -a "$DOUBLE_SWITCH" = "y" ] ; then
					RISER_BUSN=`echo $y|awk -F/ '{printf $5}'`
					for ext in $SLOTR;do
						eval EXTEND_DEV="\"\$EXTEND_DEV \$$ext\""
					done
				else
					EXTEND_DEV="none"
					RSLOTN="0"
				fi

				if [ "$EXTEND_DEV" = "none" ]; then
					for bus in `seq $((16#$SECONDARY)) $((16#$SUBORDINATE))`
					do
						[ -z "$bus" ] && continue

						#Check PCI devices Bus number equal ethtool get information 
						if [ "$2" = "$ABN484L" ]; then
							base=$((0x$bus+1))
							base=`printf "%02x" $base`;
							for i in `seq 1 4`
							do
								path=/proc/bus/pci/$base/0$i.0
								BUSN="$(hexdump -C $path 2>/dev/null |\
									awk '/^00000010/ {print $11}')"
								[ "$((16#$1))" -eq "$bus" ] &&\
									select_slot "$x" "$2" "$z" 0 && return
							done
						else
							[ "$((16#$1))" -eq "$bus" ] &&\
								select_slot "$x" "$2" "$z" 0 && return
						fi
					done
				else
					for extend in $EXTEND_DEV;do
						#Check if we need retrieve bus number from riser
						BUSN="`hexdump -C /proc/bus/pci/$RISER_BUSN/$extend \
						        2>/dev/null | awk '/^00000010/ {print $11}'`"
						RSLOTN=`get_riser_slot $extend`

						[ -z "$BUSN" ] && continue
						#Check PCI devices Bus number equal ethtool get information 
						if [ "$2" = "$ABN484L" ]; then
							base=$((0x$BUSN+1))
							base=`printf "%02x" $base`;	
							for i in `seq 1 4`
							do	
								path=/proc/bus/pci/$base/0$i.0
								BUSN="$(hexdump -C $path 2>/dev/null |\
									 awk '/^00000010/ {print $11}')"
								[ "$1" = "$BUSN" ] &&\
									 select_slot "$x" "$2" "$z" "$RSLOTN" && return
							done
						else	
							[ "$1" = "$BUSN" ] &&\
								select_slot "$x" "$2" "$z" "$RSLOTN" &&\
								    return
						fi
					done #end of extend
				fi
			done #end of slot scan
		done #end of bus scan
	done #end of root bus scan
}

set_eeprom(){
	case $3 in
	$ABN484)
		case $1 in
			A)
				case $4 in 
				10)
					[ "$5" != 4c ] && ethtool -E $2 magic $I82571_484_ID offset $W20ADDR value 0x4c
					[ "$6" != 0c ] && ethtool -E $2 magic $I82571_484_ID offset $W40ADDR value 0x0c
					;;
				11)
					[ "$6" != 0c ] && ethtool -E $2 magic $I82571_484_ID offset $W40ADDR value 0x0c
					;;
				esac
			;;
			B)
				case $4 in 
				10)
					[ "$5" != 4d ] && ethtool -E $2 magic $I82571_484_ID offset $W20ADDR value 0x4d
					[ "$6" != 0d ] && ethtool -E $2 magic $I82571_484_ID offset $W40ADDR value 0x0d
					;;
				11)
					[ "$6" != 0d ] && ethtool -E $2 magic $I82571_484_ID offset $W40ADDR value 0x0d
					;;
				esac
			;;
			C)
				case $4 in 
				10)
					[ "$5" != 4e ] && ethtool -E $2 magic $I82571_484_ID offset $W20ADDR value 0x4e
					[ "$6" != 0e ] && ethtool -E $2 magic $I82571_484_ID offset $W40ADDR value 0x0e
					;;
				11)
					[ "$6" != 0e ] && ethtool -E $2 magic $I82571_484_ID offset $W40ADDR value 0x0e
					;;
				esac
			;;
			D)
				case $4 in 
				10)
					[ "$5" != 4f ] && ethtool -E $2 magic $I82571_484_ID offset $W20ADDR value 0x4f
					[ "$6" != 0f ] && ethtool -E $2 magic $I82571_484_ID offset $W40ADDR value 0x0f
					;;
				11)
					[ "$6" != 0f ] && ethtool -E $2 magic $I82571_484_ID offset $W40ADDR value 0x0f
					;;
				esac
			;;
			default)
				case $4 in
				10)
					[ "$5" != 0d ] && ethtool -E $2 magic $I82571_484_ID offset $W20ADDR value 0x0d
					[ "$6" != 4e ] && ethtool -E $2 magic $I82571_484_ID offset $W40ADDR value 0x4e
					;;
				11)
					[ "$6" != 0e ] && ethtool -E $2 magic $I82571_484_ID offset $W40ADDR value 0x0e
				;;
				esac
			;;
		esac
		;;
	$ABN482)
		case $1 in
			A)
			[ "$5" != 80 ] && ethtool -E $2 magic $I82571_482_ID offset $W20ADDR value 0x80
			[ "$6" != 00 ] && ethtool -E $2 magic $I82571_482_ID offset $W40ADDR value 0x00
			;;
			B)
			[ "$5" != 81 ] && ethtool -E $2 magic $I82571_482_ID offset $W20ADDR value 0x81
			[ "$6" != 01 ] && ethtool -E $2 magic $I82571_482_ID offset $W40ADDR value 0x01
			;;
			C)
			[ "$5" != c0 ] && ethtool -E $2 magic $I82571_482_ID offset $W20ADDR value 0xc0
			[ "$6" != 40 ] && ethtool -E $2 magic $I82571_482_ID offset $W40ADDR value 0x40
			;;
			D)
			[ "$5" != c1 ] && ethtool -E $2 magic $I82571_482_ID offset $W20ADDR value 0xc1
			[ "$6" != 41 ] && ethtool -E $2 magic $I82571_482_ID offset $W40ADDR value 0x41
			;;
			default)
			[ "$5" != c0 ] && ethtool -E $2 magic $I82571_482_ID offset $W20ADDR value 0xc0
			[ "$6" != 01 ] && ethtool -E $2 magic $I82571_482_ID offset $W40ADDR value 0x01
			;;
		esac
		;;
	esac	
}

switch_config(){
	if [ -f ${CFG_DIR}/$1.cfg ] ; then
		. ./${CFG_DIR}/$1.cfg
	else
		echo "The model [$1] is not supported!"
		echo
		print_support
		exit 1
	fi
}
ethtool_version_check(){
	which ethtool >/dev/null 2>&1
	if [ "$?" = 0 ] ; then
		ETHTVER="`ethtool -h 2>&1 | grep "version" | head -n1 |\
		        awk '{print $3}' | sed 's/[-|A-Za-z]//g'`"
		integer=$(echo $ETHTVER | awk -F. '//{ print $1}')
		decimal=$(echo $ETHTVER | awk -F. '//{ print $2}')
		if [ "$integer" -le "$INT" ] ; then
			if [ "$decimal" -lt "$DEC" ] ; then
				print_help
				echo "Warning: Ethtool Version is less than V1.8, please ethtool update to V1.8 above"
				exit 1
			fi
		fi
	else
		echo "Make sure that ethtool command exists."
		exit 1
	fi
	
}


get_pci_dev(){
	local BASE_DIR=/sys/bus/pci/devices
	local HIGH_LAYER_DIR
	TMP_DEV_LIST=""
	local tmp_dir x
	for tmp_dir in `ls $BASE_DIR/0000:$1*`;do
		HIGH_LAYER_DIR=`find $tmp_dir/ -type d -name '0000:*:*.[0-7]'`
		for x in $HIGH_LAYER_DIR;do
			[ ! "`ls $x/0000:*:*.[0-7] -d 2>/dev/null`" ] && \
				TMP_DEV_LIST="$TMP_DEV_LIST `basename $x`"
		done
		[ ! "$HIGH_LAYER_DIR" ] && TMP_DEV_LIST="$TMP_DEV_LIST `basename $tmp_dir`"
	done
	echo $TMP_DEV_LIST
}

scan_slot_device(){
	local slot_bus
	for x in $SLOT_LIST;do
		eval slot_bus="$"$x
		eval DEV_$x=\"`get_pci_dev $slot_bus`\" #"
	done
}

get_slot_mips(){
	local DEV_LIST
	local INPUT_BUS=$1
	SLOT=""
	for x in $SLOT_LIST;do
	    eval DEV_LIST=\""$"DEV_$x\"			    #"
	    for y in $DEV_LIST;do
		    if [ "$y" = "$INPUT_BUS" ];then
			    SLOT=`echo $x | sed 's/SLOT//'`
			    case $SLOT in
				    C)
					select_model $2 2;;
				    A)
					select_model $2 0;;
				    B)
				    select_model $2 1;;
			    esac
			    return
		    fi
	    done
	done
}

#main
[ "$1" == "-s" ] && print_support && exit
[ -z "$2" ] && print_help && exit
ethtool_version_check		#check ethtool version and command exist
switch_config $1

IFACE_LIST=`ls /sys/class/net`
[ "$PLATEFORM" = "CAVIUM-MIPS" ] && scan_slot_device

pass=0
for IFACE in $IFACE_LIST
do
	ethtool $IFACE 2>/dev/null | grep "Supports auto-negotiation" -B 4|grep "10000" 1>/dev/null 2>&1
	if [ "$?" = 0 ] ; then
		BPADDR=$W2AADDR
		GENADDR=$W2CADDR
	else
		BPADDR=$W10ADDR
		GENADDR=$W12ADDR
	fi
	ethtool -i $IFACE 2>/dev/null |grep 'e1000\|igb\|ixgbe' 1>/dev/null 2>&1
	if [ "$?" = 0 ] ; then
		BYPAID=$(ethtool -e $IFACE offset $BPADDR length 2 | \
			awk '{if (/'$BPADDR'/) printf("%s\n",$3$2)};')
		# Get the bypass generation number
		GEN=$(ethtool -e $IFACE offset $GENADDR length 2 | \
			awk '{if (/'$GENADDR'/) printf("%s\n",$3)};')
	else
		BYPAID=""
		GEN=""
	fi

	# If Bypass ID is equal to 0xFAFA, the content of next word will be the pointer of PBA.
	if [ "$BYPAID" = "fafa" ]; then
		BPADDR=$((BPADDR+2))
		PADDR=$(ethtool -e $IFACE offset $BPADDR length 2 | \
			awk '{if (/'0x'/) printf("%s\n",$3$2)};')
		# Offset units change from byte to word and moved to the BP_ID_W1 address (shift 8).
		POINTADDR=$((16#$PADDR*2+8))
		# Offset units change from byte to word and moved to the BP_ID_W2 address (shift 10).
		POINTADDR2=$((16#$PADDR*2+10))
		BYPAID=$(ethtool -e $IFACE offset $POINTADDR length 2 | \
			awk '{if (/'0x'/) printf("%s\n",$3$2);}')
		# Get the bypass generation number
		GEN=$(ethtool -e $IFACE offset $POINTADDR2 length 2 | \
			awk '{if (/'0x'/) printf("%s\n",$3);}')
	fi

	if [ "$GEN" != "20" ]; then
		continue
	fi

	for BYID in $BYPASSID
	do
		if [ "$BYID" = "$BYPAID" ] ;then
			BUSN="$(ethtool -i $IFACE|grep bus-info:|awk '{print $2}')"
			W12=$(ethtool -e $IFACE offset $W12ADDR length 2|awk '{if (/'$W12ADDR'/) printf("%s\n",$2)};')
			W20=$(ethtool -e $IFACE offset $W20ADDR length 2|awk '{if (/'$W20ADDR'/) printf("%s\n",$2)};')
			W40=$(ethtool -e $IFACE offset $W40ADDR length 2|awk '{if (/'$W40ADDR'/) printf("%s\n",$2)};')
			W16=$(ethtool -e $IFACE offset $W16ADDR length 2|awk '{if (/'$W16ADDR'/) printf("%s\n",$3$2)};')
			#Select kerver version is 2.6 Or 2.4
			uname -r|grep 2.4 >/dev/null
			if [ "$?" = 0 ] ;then
				bus=$(ethtool -i $IFACE|grep bus|sed -n 's/':'/ /pg'|awk '{print $2}')
			else
				bus=$(ethtool -i $IFACE|grep bus|sed -n 's/':'/ /pg'|awk '{print $3}')
			fi

			if [ "$2" = "set" ];then
				pass=2
				[ "$PLATEFORM" = "CAVIUM-MIPS" ] && get_slot_mips $BUSN $BYPAID \
								|| getslot $bus $BYPAID
				echo "Write Data to EEPRROM"
				set_eeprom $SLOT $IFACE $BYPAID $W12 $W20 $W40 $W16
				ethtool -s $IFACE autoneg on > /dev/null 2>&1
				echo "Slot=$SLOT ETH=$IFACE BUSN=$bus BYPASSID=$BYPAID"
			elif [ "$2" = "default" ] ;then 
				pass=2
				[ "$PLATEFORM" = "CAVIUM-MIPS" ] && get_slot_mips $BUSN $BYPAID \
								|| getslot $bus $BYPAID
				echo "Reset factory default"
				set_eeprom $2 $IFACE $BYPAID $W12 $W20 $W40 $W16
				ethtool -s $IFACE autoneg on > /dev/null 2>&1
				echo "Slot=$SLOT ETH=$IFACE BUSN=$bus BYPASSID=$BYPAID"
			elif [ "$2" = "display" ] ; then
				pass=2
				[ "$PLATEFORM" = "CAVIUM-MIPS" ] && get_slot_mips $BUSN $BYPAID \
								|| getslot $bus $BYPAID
				[ -n "$SLOT" ] && echo "Slot=$SLOT ETH=$IFACE BUSN=$bus BYPASSID=$BYPAID"
			else
				pass=1
				break
			fi
		fi
	done
done

case $pass in
	0)
		echo "Can not found ABN/NIP BYPASS Gen2 Card"
	;;
	1)
		print_help
		echo "@@@@@@@Input parameter Fail@@@@@@@"
	;;
	2)
		if [ "$((slota+slotb+slotc+slotd))" = 0 ] ;then
			echo "Can not found ABN/NIP BYPASS Gen2 Card"
		else
			echo "BYPASS Gen2 Card sequence parameter = 0x${slota}${slotb}${slotc}${slotd}"
		fi
	;;
	*)
	;;

esac
