#!/bin/bash
#
# calvados/asr9k_pkg/boot/scripts/pd-functions
# This script provides PD functions to other scripts.
#
# Copyright (c) 2014-2017 by Cisco Systems, Inc.
# All rights reserved.

myvmtype=`cat /proc/cmdline | sed 's/^.*vmtype=//' | cut -d" " -f1`
if [ "$myvmtype" == "xr-vm" ]; then
    myshowemt="/pkg/sbin/showemt_static"
    myshowipu="/pkg/sbin/showipu_static"
elif [ "$myvmtype" == "sysadmin-vm" ]; then
    myshowemt="/opt/cisco/calvados/bin/showemt_static"
    myshowipu="/opt/cisco/calvados/bin/showipu_static"
else
    myshowemt="/sbin/showemt"
    myshowipu="/sbin/showipu"
fi

KMSG_LOG=/var/log/kmsg.log
A9K_BOOT_LOG=/misc/scratch/pcie/a9k_pd_boot.log

function kmsg_log
{
    local STRING=$@
    local timestamp=$( date +"%b %d %T" )

    # kmsg_log: log to both dmesg and KMSG_LOG
    echo "A9K $STRING" > /dev/kmsg
    printf "%s %s\n" "$timestamp" "$STRING" >> ${KMSG_LOG}
    grep -q "root=/dev/ram" /proc/cmdline
    if [ $? -ne 0 ]; then
        printf "A9K %s %s\n" "$timestamp" "$STRING" >> ${A9K_BOOT_LOG}
    fi
}

function kmsg_exec
{
    local CMD=$@

    $CMD 2>&1 | tee -a ${KMSG_LOG}
    local ret=${PIPESTATUS[0]}
    if [[ "$ret" -ne 0 ]]
    then
        # kmsg_exec: log to dmesg on error
        echo "A9K $CMD error=$ret" > /dev/kmsg
        grep -q "root=/dev/ram" /proc/cmdline
        if [ $? -ne 0 ]; then
            printf "A9K %s error=%s\n" "$CMD" "$ret" >> ${A9K_BOOT_LOG}
        fi    
    fi

    # kmsg_exec: log to KMSG_LOG always
    local timestamp=$( date +"%b %d %T" )
    printf "%s %s exit=%d\n" "$timestamp" "$CMD" "$ret" >> ${KMSG_LOG}

    return $ret
}

function update_virt_method {
    local caller=${FUNCNAME[1]}
    local rootdir=$1
    local is_install=$(grep "install=" /proc/cmdline | wc -l)

    is_vxr_sim
    if [[ $? == 1 ]]; then
        VIRT_METHOD=lxc
        export VIRT_METHOD
        readonly VIRT_METHOD
        return
    fi

    if [ ! -z "$is_install" ]; then
        platform_is_virtvm $is_install
        local rc=$?
        if [[ $rc == 1 ]]; then
            VIRT_METHOD=vm
        else
            VIRT_METHOD=lxc
        fi
        export VIRT_METHOD
        readonly VIRT_METHOD
    fi
    kmsg_log "$caller new $VIRT_METHOD in $rootdir"
    echo     "$caller new $VIRT_METHOD in $rootdir" > $rootdir/etc/init.d/$caller.out
    cp /proc/cmdline $rootdir/etc/init.d/proc_cmdline.$caller.$VIRT_METHOD
    cp /root/cmdline $rootdir/etc/init.d/root_cmdline.$caller.$VIRT_METHOD
}

function update_vmmprofile {

    if [ "$BOARDTYPE" != "RP" ]; then
        return
    fi

    local rootdir=$1
    local vmm_ln=${rootdir}/opt/cisco/calvados/etc/platform_profile/hw/vmm_profile.cfg
    local vmm_fn

    if [[ -L $vmm_ln ]]; then
        vmm_fn=$( stat $vmm_ln | grep File | awk '{print $4}' | sed -e "s;';;g" )
        vmm_fn=${rootdir}/${vmm_fn}
    else
        vmm_fn=$vmm_ln
    fi

    if [[ ! -f $vmm_fn ]]; then
        echo update_vmmprofile cannot locate $vmm_fn
        return
    fi

    if [[ $VIRT_METHOD == "vm" ]]; then
        sed -i -e "s;#CONSOLE_ON_TTY;CONSOLE_ON_TTY;" $vmm_fn
    else
        sed -i -e "s;^CONSOLE_ON_TTY;#CONSOLE_ON_TTY;" $vmm_fn
    fi
}

function update_bootstrap {
    local bootstrap_fn=$1/etc/rc.d/init.d/calvados_bootstrap.cfg

    if [[ ! -f $bootstrap_fn ]]; then
        echo update_bootstrap cannot locate $bootstrap_fn
        return
    fi

    if [[ $VIRT_METHOD == "vm" ]]; then
        sed -i -e "s;VIRT_METHOD=lxc;VIRT_METHOD=vm;" $bootstrap_fn
        sed -i -e "s;HOST_IP_ADDR=0A000210;HOST_IP_ADDR=0A000202;" $bootstrap_fn
        sed -i -e "s;10.0.2.16;10.0.2.2;" $bootstrap_fn
    else
        sed -i -e "s;VIRT_METHOD=vm;VIRT_METHOD=lxc;" $bootstrap_fn
        sed -i -e "s;HOST_IP_ADDR=0A000202;HOST_IP_ADDR=0A000210;" $bootstrap_fn
        sed -i -e "s;10.0.2.2;10.0.2.16;" $bootstrap_fn
    fi
}

function get_host_reboot_count_addr {
    # Obtain host counter address in EMT
    if [ -n "${host_reboot_count}" ]; then
        return;
    fi
    if [[ -f /opt/cisco/calvados/bin/showemt_static ]]; then
         /opt/cisco/calvados/bin/showemt_static addr | grep host_reboot_count > /tmp/emt_addr_offset
    elif [[ -f /pkg/sbin/showemt ]]; then
         /pkg/sbin/showemt addr | grep host_reboot_count > /tmp/emt_addr_offset
    else
        showemt addr | grep host_reboot_count > /tmp/emt_addr_offset
    fi
    if [[ $? != 0 ]]; then
        rm /tmp/emt_addr_offset
        echo "Unable to detect host count address via emt"
        return
    fi
    source /tmp/emt_addr_offset
    rm /tmp/emt_addr_offset
    if [ -n "${host_reboot_count}" ]; then
        return;
    fi
    echo "Unable to gather host count address via emt"
}

# We use the host_reboot_count in the emt area for deciding vm or lxc mode.
# The bios maintains host_reboot_count across reload.
# Prior to this change, host_reboot_count was a 32 bit counter.
# Now it is a 24 bit counter. The upper 8 bits of host_reboot_count
# determine either vm or lxc. Zero means vm, non-zero means lxc.
# Adding 16777216 (0x01000000) effectively sets lxc mode.
# Subtracting 16777216 sets vm mode.
# Testing for greater than 16777216 indicates vm vs. lxc
# This simple, yet persistient, model allows us to maintain vm vs. lxc distinction at bake time

function platform_is_emtvm {

    get_host_reboot_count_addr
    if [ -n "${host_reboot_count}" ]; then
        local CURR_CNT=$(pcimemread `printf '%x' $host_reboot_count` 4 | grep -v PCI | awk '{ print $3 ;}' | sed -e 's/^0/0x/')
        local count=`expr $(($CURR_CNT))`
        if [[ $count -gt "16777216" ]]; then
            return 0
        fi
    else
        echo platform_is_emtvm empty -${host_reboot_count}-
    fi
    return 1
}

function platform_set_lxc {
    platform_is_emtvm
    if [[ $? == 0 ]]; then
        # already lxc
        return;
    fi
    if [[ ! -n  $host_reboot_count ]]; then
        echo Cannot determine emt address
        return
    fi
    local CURR_CNT=$(pcimemread `printf '%x' $host_reboot_count` 4 | grep -v PCI | awk '{ print $3 ;}' | sed -e 's/^0/0x/')
    local count=`expr $(($CURR_CNT))`
    count=`expr $(($CURR_CNT)) + 16777216`
    local counthex=`printf '%x' $count`
    pcimemwrite `printf '%x' $host_reboot_count` 4 $counthex > /dev/null 2>&1
}

function platform_set_vm {
    platform_is_emtvm
    if [[ $? == 1 ]]; then
        # already vm
        return;
    fi
    if [[ ! -n  $host_reboot_count ]]; then
        echo Cannot determine emt address
        return
    fi
    local CURR_CNT=$(pcimemread `printf '%x' $host_reboot_count` 4 | grep -v PCI | awk '{ print $3 ;}' | sed -e 's/^0/0x/')
    local count=`expr $(($CURR_CNT))`
    count=`expr $(($CURR_CNT)) - 16777216`
    local counthex=`printf '%x' $count`
    pcimemwrite `printf '%x' $host_reboot_count` 4 $counthex > /dev/null 2>&1
}

function platform_is_virtvm {
    local virtmethod
    local emt_check=$1

    is_vxr_sim
    if [[ $? == 1 ]]; then
        return 0;
    fi

    # first check for virtvm
    virtmethod=$(cat /proc/cmdline | grep virtvm | wc -l)
    if [ "$virtmethod" == "1" ]; then
        # echo platform_is_virtvm from ${FUNCNAME[1]} return 1
        return 1
    fi

    # next, check for virtlxc
    virtmethod=$(cat /proc/cmdline | grep virtlxc | wc -l)
    if [ "$virtmethod" == "1" ]; then
        # echo platform_is_virtvm from ${FUNCNAME[1]} return 0
        return 0
    fi

    # Neither virtvm nor virtlxc set
    # LC must have on or other, default to VM
    if [[ "${BOARDTYPE}" == "LC" ]]; then
        # echo platform_is_virtvm LC ${FUNCNAME[1]} return 0
        return 1
    fi

    # If operting in calvados or xr, default to VM
    if [[ $emt_check == "0" ]]; then
        # echo platform_is_virtvm no emt ${FUNCNAME[1]} return 0
        return 1
    fi

    # RSP hostos case, check emt override
    platform_is_emtvm
    local rc=$?
    # echo platform_is_virtvm exit ${FUNCNAME[1]} return $rc
    return $rc
}

#
# Check if pd_funcions should be skipped
#
function skip_pd_functions {
    local install=$(cat /proc/cmdline | grep install=)
    if [ -n "${install}" ]; then
        return 1
    fi
    local sim=$(cat /proc/cmdline | grep simulator=)
    if [ -n "${sim}" ]; then
        return 1
    fi
    if [[ "${BOARDTYPE}" == "LC" ]]; then
        return 1
    fi
    return 0
}


# read field=value pair from /etc/init.d/calvados_bootstrap.cfg file
# example : cal_bootstrap_field_value VIRT_METHOD
function cal_bootstrap_field_value()
{
    local cal_bs="/etc/init.d/calvados_bootstrap.cfg"

    echo `grep -a $1 $cal_bs | cut -d"=" -f2`
}


# read field=value pair from /dev/xr_bootstrap file
# example : xr_bootstrap_field_value ISSU_ROLE
function xr_bootstrap_field_value()
{
    local bs="/dev/xr_bootstrap"

    echo `grep -a $1 $bs | cut -d"=" -f2`
}

#
# Which TTY should calvados con use
#
function platform_enable_calvados_con
{
    local virt_method=`cal_bootstrap_field_value VIRT_METHOD`

    skip_pd_functions
    if [ $? -ne 0 ]; then
        return;
    fi

    if [ "$virt_method" == "vm" ]; then
        ACTIVE_SERIAL='/dev/hvc0'
    else
        ACTIVE_SERIAL='/dev/pts/0'
    fi

    declare -F platform_log &>/dev/null && platform_log "Calvados console on $ACTIVE_SERIAL"
    echo "Calvados console on $ACTIVE_SERIAL"
}

#
# Which TTY should calvados aux use
#
function platform_enable_calvados_aux
{
    skip_pd_functions
    if [ $? -ne 0 ]; then
        return;
    fi
    ACTIVE_SERIAL=
    declare -F platform_log &>/dev/null && platform_log "Do not start Calvados aux"
    echo "Calvados aux disabled"
}

#
# Which TTY should XR con use
#
function platform_enable_xr_con
{
    local virt_method=`cal_bootstrap_field_value VIRT_METHOD`

    skip_pd_functions
    if [ $? -ne 0 ]; then
        return;
    fi

    if [ "$virt_method" == "vm" ]; then
        ACTIVE_SERIAL_XR_CON="hvc0"
    else
        ACTIVE_SERIAL_XR_CON="pts/0"
    fi

    declare -F platform_log &>/dev/null && platform_log "XR console on $ACTIVE_SERIAL_XR_CON"
    echo "XR console on $ACTIVE_SERIAL_XR_CON"
}

#
# Which TTY should XR aux use
#
function platform_enable_xr_aux
{
    local virt_method=`cal_bootstrap_field_value VIRT_METHOD`

    skip_pd_functions
    if [ $? -ne 0 ]; then
        return;
    fi

    if [ "$virt_method" == "vm" ]; then
        ACTIVE_SERIAL_XR_AUX="hvc1"
    else
        ACTIVE_SERIAL_XR_AUX="pts/1"
    fi

    declare -F platform_log &>/dev/null && platform_log "XR aux on $ACTIVE_SERIAL_XR_AUX"
    echo "XR aux on $ACTIVE_SERIAL_XR_AUX"
}


#
# Should we allow the first serial port to have a tty login?
#
function platform_enable_host_login_on_first_serial
{
    skip_pd_functions
    if [ $? -ne 0 ]; then
        return;
    fi
    if [[ "${BOARDTYPE}" == "RP" ]]; then
        local cmd_host_console=$(cat /proc/cmdline | grep "hostconsole" \
                                 | wc -l)
        if [ "$cmd_host_console" == "1" ]; then
            ACTIVE_SERIAL='/dev/ttyS0' # Console
            declare -F platform_log &>/dev/null && platform_log \
                    "Host console on $ACTIVE_SERIAL"
            echo "Host console on $ACTIVE_SERIAL"
        else
            ACTIVE_SERIAL= # Host console is disabled in production
            echo "XR console. Please wait ..."
        fi
    fi
}

#
# Do we want to enable host access on extra ttys? Good for development but
# is a security risk to leave host access visible.
#
function platform_starts_serial
{
    # On LC ttyS1 is for CBC
    #
    skip_pd_functions
    if [ $? -ne 0 ]; then
        if [[ "${BOARDTYPE}" != "LC" ]]; then
            return;
        fi
    fi
    #
    # We do not want host tty access unless enabled by development mode,
    # so default to no access.on
    #
    # echo "Start serial incoming on $ACTIVE_SERIAL, Clearing .."
    declare -F platform_log &>/dev/null && platform_log "Start serial incoming on $ACTIVE_SERIAL, Clearing .."
    ACTIVE_SERIAL=
    if [[ "${BOARDTYPE}" == "LC" ]]; then
        if [ "$VMTYPE" == "hostos" ]; then
            ACTIVE_SERIAL=/dev/ttyS0
        fi
    fi
    kmsg_log "platform_starts_serial $VMTYPE $ACTIVE_SERIAL"
}

function update_rsp_var_mount
{
    local my_ipaddr=$1
    local rc
    local npass=1
    local maxpass=1

    date >> /tmp/varmount 2>&1
    echo my_ipaddr is ${my_ipaddr}  >> /tmp/varmount

    local my_hostname=$( grep ${my_ipaddr} /etc/hosts | sed -e "s;^.* ;;" )
    if [[ -z ${my_hostname} ]]; then
        echo "my_hostname is null" >> /tmp/varmount
        return
    fi
    echo "my_hostname is $my_hostname" >> /tmp/varmount

    local node
    for node in rsp0_xr rsp1_xr; do
        ping -c 1 ${node} >> /tmp/varmount 2>&1
        rc=$?
        if [[ ${rc} == 0 ]]; then
            ssh -o "BatchMode=yes" ${node} mount /misc/scratchlc/${my_hostname} >> /tmp/varmount 2>&1
        fi
    done
}

#
# The step-by-step flow of np log file preservation across bake is:
# Below description refers to np log files, pcie log files also follow a similar flow
# a) At bake time: function save_sys_files xr_misc_scratch np - saves np files from XR:/misc/scratch/np
# b) At bake time: function restore_sys_files admin_var_log np - saves np files to Admin:/var/log/np.tar
# c) In Calvados(PI): temporarily mount bind Calvados:/var/log within XR rootfs - via mount_pd_fs.sh/fs_required.txt
# d) In Calvados: In update_xr_files (below):  Move np.tar from Calvados:/var/log/ to XR:/xr/
# e) In Calvados(PI): umount temporary binding - via mount_pd_fs.sh/fs_required.txt
# f) In XR: In update_misc_scratch_xr (below): untar /xr/np.tar to /misc/scratch/np
# g) In XR: In update_misc_scratch_xr (below): Remove /xr/np.tar
#

XR_TAR_FILE_DIR=/xr
XR_MISC_SCRATCH_TAR_LIST="np.tar pcie.tar"
XR_EUSB_TAR_LIST="migration.tar"

function update_xr_files {
    for tar_fn in $XR_MISC_SCRATCH_TAR_LIST $XR_EUSB_TAR_LIST; do
        if [[ -f /var/log/$tar_fn ]]; then
            mkdir -p ${XR_TAR_FILE_DIR}
            mv /var/log/$tar_fn ${XR_TAR_FILE_DIR}/
        fi
    done
}

function update_misc_scratch_xr
{
    local curdir=`pwd`
    cd /misc/scratch/

    for tar_fn in $XR_MISC_SCRATCH_TAR_LIST; do
        if [[ -f ${XR_TAR_FILE_DIR}/$tar_fn ]]; then
            echo update_misc_scratch_xr process $tar_fn >> /tmp/varmount
            tar xvf ${XR_TAR_FILE_DIR}/$tar_fn >> /tmp/varmount
            if [[ $? != 0 ]]; then
                echo untar ${XR_TAR_FILE_DIR}/$tar_fn files did not work  >> /tmp/varmount 2>&1
            fi
        fi
    done
    
    cd $curdir
}

function update_eusb_xr
{
    local curdir=`pwd`

    cd /eusbb/
    for tar_fn in $XR_EUSB_TAR_LIST; do
        if [[ -f ${XR_TAR_FILE_DIR}/$tar_fn ]]; then
            echo update_misc_scratch_xr process $tar_fn >> /tmp/varmount
            tar xvf ${XR_TAR_FILE_DIR}/$tar_fn >> /tmp/varmount
            if [[ $? != 0 ]]; then
                echo untar ${XR_TAR_FILE_DIR}/$tar_fn files did not work  >> /tmp/varmount 2>&1
            fi
        fi
    done
    
    rm -r ${XR_TAR_FILE_DIR} >> /tmp/varmount
    cd $curdir
}

function rename_nic
{
    if [ ! -L /sys/class/net/$1 ]; then
        echo Warning cannot rename network interface $1
        kmsg_log "Warning cannot rename network interface $1"
        return 1
    fi
    kmsg_exec "ip link set dev $1 name $2"
}

function config_nic
{
    kmsg_exec "ifconfig $1 mtu 9700"
    kmsg_exec "ifconfig $1 up"
}

function set_bfd_affinity
{
    local irq
    local affinity=1
    local lastcpu=$( grep processor /proc/cpuinfo | tail -1 | awk '{print $3}' )
    local irqs=$( grep bfd /proc/interrupts | awk '{print $1}' | tr -d ':' )    

    
    # Find out affinity value (include all cores except core 0)
    for ((i=0;i<$lastcpu;i++)) 
    do
        let affinity=$affinity*2+1
    done
    let affinity=$affinity-1
    
    # Convert affinity to hex
    printf -v affinity "%x" $affinity

    # Update bfd irq affinities
    for irq in ${irqs}                                                          
    do                                                                          
        echo $affinity  > /proc/irq/${irq}/smp_affinity                       
        kmsg_log "Setting up smp_affinity to: $affinity for irq: $irq"
    done  

}


function configure_from_xr_bootstrap_vm
{
    local issu_role=`xr_bootstrap_field_value ISSU_ROLE`
    local issu_id=`xr_bootstrap_field_value ISSU_ID`
    local mlan_mtu=9200

    kmsg_log "configure_from_xr_bootstrap_vm $issu_role $issu_id"

    declare -F platform_log &>/dev/null && \
    platform_log "configure from XR bootstrap ISSU role $issu_role id $issu_id"

    modprobe ixgbevf

    ifconfig eth1 down
    rename_nic  eth1  eth-punt
    config_nic  eth-punt
    rename_nic  eth0 eth-vf1
    config_nic  eth-vf1
    if [[ "${BOARDTYPE}" == "LC" ]]; then
        rename_nic  eth2  eth-bfd
        config_nic  eth-bfd
        set_bfd_affinity
    else
        rename_nic  eth2  eth-tpa
        config_nic  eth-tpa
        modprobe igba9k
        sleep 1
        rename_nic  eth0   eth-mgmt1
    fi
}

function set_vlan_ingress_egress_map() {
    local dev=$1
    for i in {0..7}
    do
         vconfig set_egress_map $dev $i $i  > /dev/null 2>&1
         vconfig set_ingress_map $dev $i $i  > /dev/null 2>&1
    done
}

function platform_xr_ifconfig
{

    local virt_method=`cal_bootstrap_field_value VIRT_METHOD`

    declare -F platform_log &>/dev/null && platform_log "virt_method= $virt_method"

    if [[ "${virt_method}" == "vm" ]]; then
        configure_from_xr_bootstrap_vm
    fi

    kmsg_log "platform_xr_ifconfig start"
    /usr/bin/tr -d '\0' < /dev/xr_bootstrap > /tmp/xr_bootstrap
    source /tmp/xr_bootstrap

    kmsg_exec "/usr/sbin/ethtool -K eth-vf1 gro off"
    kmsg_exec "/sbin/vconfig add eth-vf1 ${CALVADOS_CTRL_ETH_VLAN}"
    kmsg_exec "/sbin/ifconfig ${ADMIN_CTRL_ETH} ${GUEST_IP_ADDR} netmask 255.0.0.0 up"
    kmsg_exec "/sbin/ifconfig ${ADMIN_CTRL_ETH} hw ether ${GUEST_MAC_ADDR} up"
    kmsg_exec "/sbin/ifconfig ${ADMIN_CTRL_ETH} mtu 9700 up"
    kmsg_exec "/usr/sbin/ethtool -K ${ADMIN_CTRL_ETH} gro off"

    INSTANCE_BASE=32
    INSTANCE=$(($INSTANCE_BASE + $(($ISSU_ID * 8))))

    # MAC format is V:K:G:R:S:I 
    MAC_BYTE4=$(printf "%02x" ${PD_SLOT_NUM})
    MAC_BYTE5=$(printf "%02x" ${INSTANCE})
    kmsg_exec "/sbin/vconfig add eth-vf1 ${GUEST_CTRL_ETH_VLAN}"
    kmsg_exec "/sbin/ifconfig ${GUEST_CTRL_ETH} 172.0.${PD_SLOT_NUM}.${INSTANCE} netmask 255.0.0.0 up"
    kmsg_exec "/sbin/ifconfig ${GUEST_CTRL_ETH} hw ether 56:4b:47:00:${MAC_BYTE4}:${MAC_BYTE5} up"
    kmsg_exec "/sbin/ifconfig ${GUEST_CTRL_ETH} mtu 9700 up"
    kmsg_exec "/usr/sbin/ethtool -K ${GUEST_CTRL_ETH} gro off"

    set_vlan_ingress_egress_map ${ADMIN_CTRL_ETH}
    set_vlan_ingress_egress_map ${GUEST_CTRL_ETH}

    # For front panel management ports
    if [[ "${BOARDTYPE}" == "RP" ]]; then
        kmsg_exec "/usr/sbin/ethtool -K eth-mgmt1 gro off"
        kmsg_exec "/sbin/ifconfig eth-mgmt1 mtu 9200 up"
        #
        # sed to make sure we pick real cavecreek MAC address (burned in PROM)
        # extending for eth-mgmt1 and eth-mgmt2
        # emgmt2 will found first in xr_bootstrap
        #
        PREV=$(grep -a "GUEST_MGMT_ETH_MAC_ADDR" /dev/xr_bootstrap)
        NEW=$(ifconfig eth-mgmt1 | grep HW | awk '{print $5}')
        sed -i "s/$PREV/GUEST_MGMT_ETH_MAC_ADDR1=$NEW/g" /dev/xr_bootstrap
        NEW=$(ifconfig eth-mgmt2 | grep HW | awk '{print $5}')
        echo "GUEST_MGMT_ETH_MAC_ADDR2=$NEW" > /tmp/emgmt2
    fi
    
    kmsg_exec "/usr/sbin/ethtool -K eth-punt gro off"
    kmsg_exec "/sbin/vconfig add eth-punt ${GUEST_PUNT_ETH_VLAN}"
    kmsg_exec "/sbin/ifconfig ${GUEST_PUNT_ETH} hw ether 56:4b:47:50:4E:54 up"
    kmsg_exec "/sbin/ifconfig ${GUEST_PUNT_ETH} mtu 9700 up"
    kmsg_exec "/usr/sbin/ethtool -K ${GUEST_PUNT_ETH} gro off"

    if [[ "${BOARDTYPE}" == "LC" ]]; then
        kmsg_exec "/usr/sbin/ethtool -K eth-bfd gro off"
        kmsg_exec "/sbin/vconfig add eth-bfd ${GUEST_PUNT_ETH_VLAN}"
        kmsg_exec "/sbin/ifconfig ${GUEST_BFD_ETH} hw ether 56:4b:47:50:4E:42 up"
        kmsg_exec "/usr/sbin/ethtool -K ${GUEST_BFD_ETH} gro off"
        kmsg_exec "/sbin/ifconfig ${GUEST_BFD_ETH} mtu 9700 up"
        update_rsp_var_mount ${GUEST_IP_ADDR}
    else
        kmsg_exec "/usr/sbin/ethtool -K eth-tpa gro off"
        kmsg_exec "/sbin/vconfig add eth-tpa ${GUEST_PUNT_ETH_VLAN}"
        kmsg_exec "/sbin/ifconfig eth-tpa.1282 hw ether 56:4b:47:50:4E:77 up"
        kmsg_exec "/sbin/ifconfig eth-tpa.1282 mtu 9700 up"
        kmsg_exec "/usr/sbin/ethtool -K eth-tpa.1282 gro off"
    fi
    kmsg_log "platform_xr_ifconfig finish"
}

function is_development_platform()
{
    grep -q "__development=true" /proc/cmdline
    if [ $? -eq 0 ]; then
        true
        return
    fi

    false
}

function on_dev()
{
    if [ "${DEVELOPMENT}" == "" ]; then
        #
        # Only log the first time we decide on the simulation setting to avoid
        # noise and repeated looking up of the information we need.
        # 
        is_development_platform
        if [[ $? == 0 ]]; then
            readonly DEVELOPMENT=1
        else
            readonly DEVELOPMENT=0
        fi
    fi

    return $DEVELOPMENT
}

#
# Disable all 8717 links
#
function pci_disable_8717_down
{
    local dev=$(lspci -nn | grep 8717 | grep -v "00.0" | awk '{print $1}')
    for d in $dev; do
        setpci -s $d CAP_EXP+10.l=10:10
    done
}

#
# Check IPU MB ID from info rom
# Matching below table
#
# /* IPU MB ID */
#define IPU_MB_ID_PYRO_SAC          1
#define IPU_MB_ID_PYRO_SM15         2
#define IPU_MB_ID_OCTANE            3
#define IPU_MB_ID_SURESHOT          4
#define IPU_MB_ID_SKYHAMMER         5
#define IPU_MB_ID_RSP4              0x20   /* RSP4                    */
#define IPU_MB_ID_RP2               0x21   /* RP2                     */
#define IPU_MB_ID_RSP_SHK_WV_2XBAR  0x22   /* RSP Shockwave 2x SM15   */
#define IPU_MB_ID_RSP_SHK_WV_1XBAR  0x23   /* RSP Shockwave 1x SM15   */
#define IPU_MB_ID_RSP4_PROD_A0      0x24   /* RSP4 Production -A0     */
#define IPU_MB_ID_RP2_PROD_A0       0x25   /* RP2 Produciton -A0      */
#define IPU_MB_ID_FC2               0x30   /* FC2                     */
#define IPU_MB_ID_FC2_SS            0x31   /* Starscream specific FC2 */
#define IPU_MB_ID_FC2_SHK_WV        0x32   /* Shockwave FC2           */
#define IPU_MB_ID_FC2_TRCH_WD       0x33   /* Torchwood FC2           */
#define IPU_MB_ID_FC2_B2B           0x34   /* 2x SM15 proof of concept */
#define IPU_MB_ID_FC3               0x35   /* 2x SKB MT               */
#define IPU_MB_ID_FC3_B2B           0x36   /* 4x SKB Back to back     */
#define IPU_MB_ID_FC3_SHK_WV        0x37   /* Shockwave FC3           */

function check_ipu_magic
{
    local base=$1
    INFO_ROM_CT_OFF=0xc0

    # confirm ipu info rom block id 2240d (35d << 6)
    local block_id=$( pcimemread $base 0x4 | grep -v PCI |  awk '{ print $3 ; }' )
    if [[ -z $block_id ]]; then
        echo Unable to determine block_id for address $base
        return 1
    fi
    block_id=0x${block_id}
    let "block_id = $block_id & 0x3fc0"
    if [[ "$block_id" != "2240" ]]; then
        return 1
    fi

    # confirm permissable MBI_ID value from above table
    local hw_cardtype_addr=$(($base + $INFO_ROM_CT_OFF))
    local hw_cardtype=$( pcimemread `printf "%x" $hw_cardtype_addr` 0x4 | \
                         grep -v PCI | awk '{ print $3 ; }' | sed -e 's/...../0x/' )
    if [[ $hw_cardtype -ge 0x20 && $hw_cardtype -lt 0x30 ]]; then
        return 0
    fi
    if [[ $hw_cardtype -ge 0x1 && $hw_cardtype -lt 0x10 ]]; then
        return 0
    fi
    return 1   # FC's
}

#
# Safest way to get IPU base
#
function get_ipu_base_safe
{
    local devices=$(lspci -nn | grep "10b5:87a0" | awk '{print $1}' | grep ":00.0")
    for dev in $devices; do
        local mem=$(echo `lspci -s ${dev} -v | grep Memory | awk '{print $3}'`)
        if [[ ! -z ${mem} ]]; then
            check_ipu_magic 0x${mem}
            if [ $? -eq  0 ]; then
                echo 0x${mem}
                return
            fi
        fi
    done
}

function get_ipu_bdf_safe
{
    local devices=$(lspci -nn | grep "10b5:87a0" | awk '{print $1}')
    for dev in $devices; do
        local mem=$(echo `lspci -s ${dev} -v | grep Memory | awk '{print $3}'`)
        if [[ ! -z ${mem} ]]; then
            check_ipu_magic 0x${mem}
            if [ $? -eq  0 ]; then
                echo ${dev}
                return
            fi
        fi
    done
}

function display_ipu_devices
{
    local devices=$(lspci -nn | grep "10b5:87a0" | awk '{print $1}' | grep ":00.0" | paste - - - - - - )
    kmsg_log "Warning: IPU device not found: $devices"
}

function set_ipu_base
{
    if [[ ! -z ${IPU_BASE} ]]; then
        # IPU_BASE already set
        return 0
    fi

    # first try
    IPU_BASE=$(get_ipu_base_safe)
    if [[ ! -z ${IPU_BASE} ]]; then
        kmsg_log "IPU_BASE: ${IPU_BASE}"
        return 0
    fi

    sleep 1

    # second try
    IPU_BASE=$(get_ipu_base_safe)
    if [[ ! -z ${IPU_BASE} ]]; then
        kmsg_log "IPU_BASE: ${IPU_BASE} - second try"
        return 0
    fi

    # IPU_BASE set failure
    display_ipu_devices
    return 1
}

function set_ipu_bdf
{
    if [[ ! -z ${IPU_BDF} ]]; then
        # IPU_BDF already set
        return 0
    fi

    # first try
    IPU_BDF=$(get_ipu_bdf_safe)
    if [[ ! -z ${IPU_BDF} ]]; then
        kmsg_log "IPU_BDF: ${IPU_BDF}"
        return 0
    fi

    # second try
    IPU_BDF=$(get_ipu_bdf_safe)
    if [[ ! -z ${IPU_BDF} ]]; then
        kmsg_log "IPU_BDF: ${IPU_BDF} - second try"
        return 0
    fi

    # IPU_BDF set failure
    display_ipu_devices
    return 1
}

#
# Mask malformed TLP and surprise link down errors
#
function pd_mask_uncorrectable_err
{
    local dev=$(lspci -nn | grep 8717 | grep -v "00.0" | awk '{print $1}')
    for d in $dev; do
        setpci -s $d ECAP_AER+8.l=40020:40020
    done

    local rootb=$(lspci -nn | grep 8749 | grep -v "00.0" | awk '{print $1}' |\
            cut -d ":" -f1 | head -1)
    setpci -s $rootb":03.0" ECAP_AER+8.l=20:20
    setpci -s $rootb":05.0" ECAP_AER+8.l=20:20
}

function setup_host_access_lxc()
{
    # for release use on_dev to bypass host access

    # On RP V1 and V2 are not active at same time, so one address 10.11.12.14
    # is enough for host access. On LC V1 and V2 can be active at same time
    # so second address (10.11.12.13) is needed for V2 instance

    local issu_id=`xr_bootstrap_field_value ISSU_ID`
    if [ $issu_id -eq 1 ] && [[ "${BOARDTYPE}" == "LC" ]]; then
        kmsg_exec "ifconfig eth-vf0 10.11.12.13/24 up"
    else
        kmsg_exec "ifconfig eth-vf0 10.11.12.14/24 up"
    fi
    kmsg_exec "route add default gateway 10.11.12.2 eth-vf0"
    kmsg_exec "route add 10.0.2.16 eth-vf0"
}


function configure_from_xr_bootstrap_lxc
{
    local issu_role=`xr_bootstrap_field_value ISSU_ROLE`
    local issu_id=`xr_bootstrap_field_value ISSU_ID`

    kmsg_log "configure_from_xr_bootstrap_lxc $issu_role $issu_id"

    declare -F platform_log &>/dev/null && \
    platform_log "configure from XR bootstrap ISSU role $issu_role id $issu_id"

    # configuration must match with lxc_set_sdr_intf_hook
    if [ $issu_id -eq 1 ] && [[ "${BOARDTYPE}" == "LC" ]]; then
        kmsg_exec "ifconfig eth-vnic4 down"
        rename_nic  eth-vnic4  eth-vf1
        config_nic  eth-vf1
        rename_nic  eth-vnic6  eth-punt
        config_nic  eth-punt
        rename_nic  eth-vnic8  eth-bfd
        config_nic  eth-bfd
    else    
        kmsg_exec "ifconfig eth-vnic2 down"
        rename_nic  eth-vnic2  eth-vf1
        config_nic  eth-vf1
        rename_nic  eth-vnic5  eth-punt
        config_nic  eth-punt
        if [[ "${BOARDTYPE}" == "LC" ]]; then
            rename_nic  eth-vnic7  eth-bfd
            config_nic eth-bfd
        else
            rename_nic  eth-vnic7  eth-tpa
            config_nic eth-tpa
        fi
    fi
}

# Invoked when host set the vmm cfg as XR bootstrap
# modify the bootstrap if needed
# configure XR based on bootstrap parameters
function platform_patch_xr_bootstrap
{
    local xr_bootstrap=$1
    local virt_method=`cal_bootstrap_field_value VIRT_METHOD`

    declare -F platform_log &>/dev/null && platform_log "XR bootstrap $xr_bootstrap"
    declare -F platform_log &>/dev/null && platform_log "virt_method= $virt_method"

    if [[ "${virt_method}" == "lxc" ]]; then
        configure_from_xr_bootstrap_lxc
        setup_host_access_lxc
    fi
}

#
# Get the offset for any block $1: String/block name $2: Instance number
#
function get_ipu_block_offset {
    if [[ -z ${IPU_BASE} ]]; then
        return
    fi
    local req=$1
    local inst=$2
    echo $($myshowipu -p ${IPU_BASE} | grep $req | cut -d ":" -f1 | sed -n ${inst}p)
}

#
# Set the MUX settings for XR console
#
function platform_get_mux_tty_settings
{
    local virt_method=`cal_bootstrap_field_value VIRT_METHOD`

    skip_pd_functions
    if [ $? -ne 0 ] || [ "$virt_method" == "vm" ]; then
        return;
    fi
    
    MUX_TTY=/dev/ttyS0
    MUX_TTY_SPEED=115200
    MUX_TTY_TYPE=1
    MUX_TTY_FLOWCTRL=""
    MUX_TTY_SOCAT_OPTION="raw,echo=0,opost=1"
}

#
# Set the MUX settings for calvados console
#
function platform_get_mux_calvados_tty_settings
{
    local virt_method=`cal_bootstrap_field_value VIRT_METHOD`

    skip_pd_functions
    if [ $? -ne 0 ] || [ "$virt_method" == "vm" ]; then
        return;
    fi

    MUX_TTY=/dev/ttyS1
    MUX_TTY_SPEED=115200
    MUX_TTY_TYPE=2
    MUX_TTY_FLOWCTRL=""
    MUX_TTY_SOCAT_OPTION="raw,echo=0,opost=1"
}


function pcimemsetbit {
    local offset=$1
    local setbit=$2
    
    local val=$( pcimemread $offset 0x4 | grep -v PCI | awk '{ print $3 ; }' | sed -e 's/^/0x/' )
    let "val = $val | $setbit"
    val=0x$( printf "%08x" $val )
    pcimemwrite $offset 4 $val &> /dev/null
    local new_val=$( pcimemread $offset 0x4 | grep -v PCI | awk '{ print $3 ; }' | sed -e 's/^/0x/' )
    if [ $val != $new_val ]; then
        echo set failure offset $offset wrote $val read back $new_val
    fi
}

function pcimemclrbit {
    local offset=$1
    local setbit=$2
    
    local val=$( pcimemread $offset 0x4 | grep -v PCI | awk '{ print $3 ; }' | sed -e 's/^/0x/' )
    let "setbit = ~ $setbit"
    let "val = $val & $setbit"
    val=0x$( printf "%08x" $val )
    pcimemwrite $offset 4 $val &> /dev/null
    local new_val=$( pcimemread $offset 0x4 | grep -v PCI | awk '{ print $3 ; }' | sed -e 's/^/0x/' )
    if [ $val != $new_val ]; then
        echo clr failure offset $offset wrote $val read back $new_val
    fi
}

function oir_reset {
    local OIR_RESET_SUPPORT=$(get_card_specific_value OIR_RESET_SUPPORT)
    OIR_RESET_SUPPORT=$(printf "%d" $OIR_RESET_SUPPORT)

    if [ $OIR_RESET_SUPPORT -eq 0 ]; then
      return
    fi

    # OIR reset supported by card. Programming it (if we find an IPU_BASE).
    INFO_ROM_X86_CTRL_OFF=0xE0

    if [[ -z ${IPU_BASE} ]]; then
        echo Warning: No IPU base - skipping oir reset
        return
    fi

    X86_CTRL_ADDR=$(( $IPU_BASE + $INFO_ROM_X86_CTRL_OFF ))
    X86_CTRL_OFF=$( pcimemread `printf "%x" $X86_CTRL_ADDR` 0x4 | grep -v PCI | awk '{ print $3 ; }' | sed -e 's/^0/0x0/' )
    
    X86_CTRL_CKEY_OFF=$(( $IPU_BASE + $X86_CTRL_OFF + 0x20 ))
    X86_CTRL_CKEY_OFF=$( printf "%x" $X86_CTRL_CKEY_OFF )

    X86_CTRL_CTRL_OFF=$(( $IPU_BASE + $X86_CTRL_OFF + 0x24 ))
    X86_CTRL_CTRL_OFF=$( printf "%x" $X86_CTRL_CTRL_OFF )

    pcimemsetbit $X86_CTRL_CKEY_OFF 0x10000000
    pcimemclrbit $X86_CTRL_CTRL_OFF 0x10000000
    pcimemclrbit $X86_CTRL_CKEY_OFF 0x10000000
 
    pcimemsetbit $X86_CTRL_CKEY_OFF 0x10000
    pcimemsetbit $X86_CTRL_CTRL_OFF 0x10000
    pcimemclrbit $X86_CTRL_CKEY_OFF 0x10000
}

# Patch host_auth* files to stop console output for noise control
function patch_host_auth {
    local rootdir=$1
    local hauth_xr="${rootdir}/etc/init/host_auth.conf"
    local hauth_calv="${rootdir}/etc/init/host_auth_calvados.conf"
    if [ -f ${hauth_xr} ]; then
        sed -i -e "s;console output;;" ${hauth_xr}
    fi
    if [ -f ${hauth_calv} ]; then
        sed -i -e "s;console output;;" ${hauth_calv}
    fi
}

function show_bars
{
    local vid=$1
    local did=$2
    local virt_method=$4
    local count=0

    local bdf_list=$( lspci -d $vid:$did | awk '{ print $1 }' )
    for bdf in $bdf_list; do
        local bars=$(   lspci -s $bdf -v      | \
                        grep "Memory at"      | \
                        awk '{ print $3 $6 }' | \
                        sed -e "s;size=;;"    | \
                        paste -d" " - - - )

        local cmd=$(    lspci -s $bdf -x      | \
                        grep 00: | awk '{print $7 $6}' )

        if [ "${BOARDTYPE}" == "LC" ]; then
            if [ "$VM_TYPE" == "hostos" ]; then
                echo "$vid:$did $bdf ${bars} ${cmd}"
            fi
        fi
        kmsg_log "$vid:$did $bdf ${bars} ${cmd}"
        let "count = $count + 1"
    done
    if [[ $count != 0 ]]; then
        if [ "$VM_TYPE" == "hostos" ]; then
            echo Discovered ${vid}:${did} x${count}
        fi
    fi
    return $count
}

function pcie_proxy_enable
{
    local vid=$1
    local did=$2
    local VM_TYPE=$3
    local VIRT_METHOD=$4

    show_bars $vid $did $VM_TYPE $VIRT_METHOD
    if [ "$VM_TYPE" == "hostos" ] || [ "$VIRT_METHOD" == "vm" ]; then
        echo "$vid $did" > /sys/bus/pci/drivers/pci_proxy/new_id
    fi
}

function setup_var_log_links
{
  if [[ -d /var/log ]]; then
      # If the /log: symlink already exists, simple ln -s will
      # create a new symlink: /var/log/log -> /var/log - that is
      # not wanted. Use the ln --no-dereference option to avoid.
      ln -sf --no-dereference /var/log /log:

      # And need to delete old instances of /var/log/log, so things
      # like tar don't trip over the infinite recursion
      if [ -L /var/log/log ]; then
        I1=`ls -id /var/log | cut -d ' ' -f 1`
        I2=`ls -Lid /var/log/log | cut -d ' ' -f 1`
        if [[ $I1 -eq $I2 ]]; then
          rm /var/log/log
        fi
      fi
  fi
}

function a9k_pcie_proxy_enable
{
  local VM_TYPE=$1
  local VIRT_METHOD=$2

  # Marvell
  pcie_proxy_enable "11ab" "8000" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "11ab" "c81f" $VM_TYPE $VIRT_METHOD

  # IPU
  pcie_proxy_enable "10b5" "87a0" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "10b5" "87b1" $VM_TYPE $VIRT_METHOD

  # Fabric devices
  pcie_proxy_enable "1137" "00ca" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "0082" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "003b" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "00fb" $VM_TYPE $VIRT_METHOD

  # AMCC Phy devices
  # PCI links not used for AMCC PHYs. They rather cause
  # spurious AERs on Sureshot
  #pcie_proxy_enable "10e8" "307c" $VM_TYPE $VIRT_METHOD

  # MSIX Virtual device
  pcie_proxy_enable "1137" "2345" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "2346" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "2347" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "2348" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "2349" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "234a" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "234b" $VM_TYPE $VIRT_METHOD

  # ETNA
  pcie_proxy_enable "1137" "0120" $VM_TYPE $VIRT_METHOD

  # FRENZY
  pcie_proxy_enable "1137" "016b" $VM_TYPE $VIRT_METHOD

  # NP5C
  pcie_proxy_enable "11ab" "05c1" $VM_TYPE $VIRT_METHOD

  # Sureshot FPGA's  need for each MPA fpga type
  pcie_proxy_enable "1137" "0094" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "0095" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "0096" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "0097" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "0100" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "0167" $VM_TYPE $VIRT_METHOD
  pcie_proxy_enable "1137" "016a" $VM_TYPE $VIRT_METHOD
}

function a9k_devices_enable
{
  local VM_TYPE=$1
  local VIRT_METHOD=$2

  # Enable PCIE RPC server
  initctl start pcie_rpc_svr

  # Start MSIX daemon on Host only with LXCs
  if [[ $VIRT_METHOD == "lxc" ]]; then
      msixd -v 0x1137 -d 0x2345
  fi

  # Reset the EOBC switch
  es_reset

  reset_lgt_pcie $VM_TYPE $VIRT_METHOD
  update_host_counters

  # On oir immediately reset card
  oir_reset
}

function a9k_show_media
{
    local size
    local install=$(cat /proc/cmdline | grep install=)

    for i in sda sdb sdc sdd; do
        if [[ -b /dev/$i ]]; then
            size=$( fdisk -l /dev/$i    | \
                grep Disk | head -1     | \
                awk '{print $3 $4}'     | \
                sed -e "s;,;;" )
            if [ -n "${install}" ]; then
                step_log_console "Discovered $i: $size"
            else
                echo     "Discovered $i: $size"
                kmsg_log "Discovered $i: $size"
            fi
        fi
    done
}


#App hosting Cgroup settings
function pd_tpa_cgroup_settings
{
    APP_CGROUP_MEM_NUMA_NODES=0
    APP_CGROUP_CPUSET_CPUS=1
    APP_CGROUP_CPU_SHARES=512
    APP_CGROUP_MEM_LIMIT_IN_BYTES=1G
}

function modify_init_console_para_xr()
{
    local XROOT=$1
    local devc_con=`ls -l ${XROOT}/pkg/init.d/devc_conaux_con.init | awk '{print $11}'`
    local devc_aux=`ls -l ${XROOT}/pkg/init.d/devc_conaux_aux.init | awk '{print $11}'`

    ACTIVE_SERIAL_XR_CON="pts/0"
    ACTIVE_SERIAL_XR_AUX="pts/1"

    #
    # Allow platform to override ACTIVE_SERIAL_XR_CON/AUX
    #
    platform_enable_xr_con
    sed -i "s;pts/0;$ACTIVE_SERIAL_XR_CON;g" ${XROOT}/${devc_con}

    platform_enable_xr_aux
    sed -i "s;hvc1;$ACTIVE_SERIAL_XR_AUX;g" ${XROOT}/${devc_aux}
}

# Function called by pxe_install.sh script to allow PD to patch hostos boot
# partition.
function pd_pxe_install_patch_hostos_boot
{
    local LOCAL_PARTMNT=$1
    local LOCAL_LVG_NAME=$2
    local LOCAL_LV_ID=$3

    /etc/init.d/calvados_patch_lxc_iso.sh ${LOCAL_PARTMNT} ${LOCAL_LVG_NAME} \
        ${LOCAL_LV_ID} "hostos"

}

# Function called by pxe_install.sh script to allow PD to patch SysAdmin VM
# boot partition.
function pd_pxe_install_patch_sysadmin_vm_boot
{
    local LOCAL_PARTMNT=$1
    local LOCAL_LVG_NAME=$2
    local LOCAL_LV_ID=$3

    /etc/init.d/calvados_patch_lxc_iso.sh ${LOCAL_PARTMNT} ${LOCAL_LVG_NAME} \
        ${LOCAL_LV_ID} "sysadmin-vm"
}
