#!/bin/bash
#----------------------------------------------------------------------------
# Purpose:
# Copyright Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
#----------------------------------------------------------------------------

cd $(dirname $0)

VERSION_FILE=$(basename "${PWD}" | awk -F "-" '{print $3}')
INSTALL_STATUS="failed"
CMD_TEMP_LOG="./cmd_log.log"
LOG_FILE_PATH=/var/log/nic
LOG_FILE=$LOG_FILE_PATH/nic_deploy.log
OPERATION_LOG=$LOG_FILE_PATH/operation.log
SYS_ARCH=$(arch)
pkg_format="rpm"
if [ -f /etc/debian_version ];then
    pkg_format="deb"
fi

tool_list=(
    "hinicadm3"
)

if [[ ! -f "$LOG_FILE" ]];then
    if [[ ! -d "$LOG_FILE_PATH" ]];then
        mkdir -p $LOG_FILE_PATH
    fi
    touch $LOG_FILE
    chmod 600 $LOG_FILE
fi

function log() {
    local log_time=$(date +"%Y-%m-%d %H:%M:%S")
    echo "$log_time $*" | tee -a ${LOG_FILE}
}

function g_log_info() {
    local log_msg="[Info] $*"
    log "$log_msg"
}

function g_log_err() {
    local log_msg="[Error] $*"
    log "$log_msg"
}

function g_log_warn() {
    local log_msg="[Warn] $*"
    log "$log_msg"
}

function log_operation() {
    local operation="$1"
    local result="$2"
    local runfilename="$3"
    local cmdlist="$4"
    local start_time=$(date +"%Y-%m-%d %H:%M:%S")
    local op_user=$(whoami)
    local log_level="MAJOR"

    if [ ! -f "${OPERATION_LOG}" ]; then
        touch ${OPERATION_LOG}
        chmod 640 ${OPERATION_LOG}
    fi

    if [ "$cmdlist" == "help" ]; then
        log_level="MINOR"
    fi

    if [ "$cmdlist" == "" ]; then
        echo "${operation} ${log_level} ${op_user} ${start_time} local ${runfilename} ${result}." >> ${OPERATION_LOG}
    else
        echo "${operation} ${log_level} ${op_user} ${start_time} local ${runfilename} ${result}"\
        "cmdlist=${cmdlist}." >> ${OPERATION_LOG}
    fi
}

function limit_count_log(){
    local maxline=10000

    if [ -f "${OPERATION_LOG}" ];then
        linecount=$(wc -l ${OPERATION_LOG} | awk '{print $1}');
        if [ ${linecount} -gt ${maxline} ];then
            sed -i '1,100d' ${OPERATION_LOG}
        fi
    fi
}

install_pkg()
{
    if [ $pkg_format == "rpm" ]; then
        rpm -Uvh $1 --force 2>&1 | tee -a ${LOG_FILE}
    else
        dpkg -i $1 2>&1 | tee -a ${LOG_FILE}
    fi

    if [ $? != 0 ]; then
        g_log_err "install $1 fail! Exit install!"
        exit 1
    fi

    g_log_info "install_$pkg_format $1 ok"
}

install_tool()
{

    echo "---------tool---------"
    if [ -f tool/$SYS_ARCH/$tool*$pkg_format ]; then
        for tool in ${tool_list[*]}
        do
            install_pkg "tool/$SYS_ARCH/$tool*$pkg_format"
        done
    else
        \cp -f ./tool/$SYS_ARCH/hinicadm3 /usr/bin/hinicadm3
    fi

    # check hinicadm3 tool install ok or not
    hinicadm3 -v
    if [ $? != 0 ]; then 
        g_log_err "hinicadm3 install fail! Exit install!"
        exit 1
    fi
}

# always install new version tool
install_tool

HINIC_DEVICE_NUM=0
HINIC_DEVICE_NUM=$(hinicadm3 info | grep -oP 'hinic\d+'  | wc -l)    # only update hinic firmware
firmware_file_list=(
    "SP670/Hinic3_flash.bin"
    "SP681/Hinic3_flash.bin"
    "SP623Q/Hinic3_flash.bin"
    "SP680/Hinic3_flash.bin"
    "SP226D/Hinic3_flash.bin"
    "SP225D/Hinic3_flash.bin"
    )

firmware_default_type=0
driver_install_file_list=("hisdk3")
driver_install_file_num=${#driver_install_file_list[*]}

function check_firmware_type()
{
    bdf=$(hinicadm3 info |grep -A 1 $1 | awk -F "|--------" '{print $2}' | awk -F "(" '{print $1}')
    subsystem=$(lspci -s $bdf -vnn | grep "Subsystem" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}')

    if [[ "${subsystem}" == "19e5:00a1" ]];then
        # SP670
        firmware_default_type=0
    elif [[ "${subsystem}" == "19e5:0051" ]];then
        # SP681
        firmware_default_type=1
    elif [[ "${subsystem}" == "19e5:0152" ]];then
        # SP623Q
        firmware_default_type=2
    elif [[ "${subsystem}" == "19e5:0052" ]];then
        # SP680
        firmware_default_type=3
    elif [[ "${subsystem}" == "19e5:04b1" ]];then
        # SP226D
        firmware_default_type=4
    elif [[ "${subsystem}" == "19e5:02a4" ]];then
        # SP225D
        firmware_default_type=5
    else
        g_log_err "no firmware match"
        return 1
    fi
    return 0
}

# 0 ok; 1 file not exist
function check_file_exist() {
    # input "file_name"+*, unsupport check more than one file!
    if [[ $# -ne 1 ]]; then
        g_log_err "Check $# file, install will be failed!($1,$2)"
        return 1
    fi

    file=$1
    # check driver file
    ls $file >/dev/null 2>&1
    if [[ $? != 0 ]]; then
        g_log_err "Can not find $file!"
        return 1
    fi
    g_log_info "check $file ok"
}

function install_firmware()
{

    local hinic_info=""
    #only update hinic0-HINIC_DEVICE_NUM firmware
    firmware_upgrade=0
    for ((i=0;i<${HINIC_DEVICE_NUM};i++))
    do
        try_time=0
        hinic_info=$(hinicadm3 info | grep hinic$i)
        if [ $? != 0 ]; then
            g_log_err "There is no hinic device."
            continue
        fi
        local hinic_dev=$(echo $hinic_info | awk -F "(" '{print $1}' | awk -F "-" '{print $5}')
        check_firmware_type $hinic_dev
        if [ $? != 0 ]; then
            continue
        fi

        check_file_exist ${firmware_file_list[$firmware_default_type]}
        if [ $? -ne 0 ];then
            continue
        fi
        g_log_info "install firmware for $hinic_dev"
        firmware_upgrade=1

        if [ -f "$CMD_TEMP_LOG" ]; then
            rm $CMD_TEMP_LOG
        fi

        local version=$(hinicadm3 version -i $hinic_dev | grep npu | awk -F ":" '{print $2}' | awk '{print $1}')
        version_new=${VERSION_FILE}
        g_log_info "current fw_version=$version, update fw_version=$version_new"

        while ((try_time <= 3))
        do
            # update firmware
            hinicadm3 updatefw -i $hinic_dev -or -f ${firmware_file_list[$firmware_default_type]} -x 0 | tee $CMD_TEMP_LOG

            # check spi busy
            cat $CMD_TEMP_LOG | grep "MPU other host reset spi busy, update delay!" > /dev/null
            if [ $? == 0 ]; then
                rm $CMD_TEMP_LOG
                g_log_err "MPU other host reset spi busy when update firmware, sleep 30s!"
                sleep 30
                ((try_time++))
                continue
            fi

            #check update success or fail
            cat $CMD_TEMP_LOG | grep "Loading firmware image succeed" > /dev/null
            if [ $? != 0 ]; then
                rm $CMD_TEMP_LOG
                g_log_err "Loading firmware image failed! Try again!"
                ((try_time++))
                continue
            fi
            g_log_info "$hinic_dev Loading firmware image succeed"

            #check active firmware success or fail
            cat $CMD_TEMP_LOG | grep "Set update active cfg succeed" > /dev/null
            if [ $? != 0 ]; then
                rm $CMD_TEMP_LOG
                g_log_err "Set update active cfg failed! Try again!"
                ((try_time++))
                continue
            fi
            g_log_info "$hinic_dev Set update active cfg succeed"

            rm $CMD_TEMP_LOG
            break
        done

        if [[ $try_time -eq 3 ]]; then
            g_log_err "update firmware failed! Exit install!"
            return 1
        fi
        g_log_info "update $hinic_dev firmware ok for install (reboot host to take effect)"
    done
    if [[ "$firmware_upgrade" == 0 ]]; then
        g_log_err "no device install firmware"
        return 1
    fi

    g_log_info "update firmware -----------------pass"
}

check_card_type()
{
    #check netcard
    touch card_type_check_log
    lspci -vnn | grep -A 1 "Eth" > card_type_check_log
    cat card_type_check_log | grep "Eth" | grep "19e5:0222" > /dev/null
    if [ $? != 0 ]; then
        g_log_err "netcard is not exist"
        rm card_type_check_log
        return 1
    fi
    rm card_type_check_log
    return 0
}

check_before_install()
{
    check_card_type
    if [ $? -ne 0 ]; then
        g_log_err "check_card_type failed."
        return 1
    fi

    #check tools file exist
    hinicadm3 -v
    if [ $? -ne 0 ];then
        g_log_err "please install hinicadm3 tool on host os."
        return 1
    fi

    for ((i=0;i<$driver_install_file_num;i++))
    do
        lsmod | grep "hisdk3" > /dev/null
        if [ $? -ne 0 ]; then
            if [ $pkg_format == "rpm" ]; then
                rpm -qa | grep ${driver_install_file_list[$i]}
            else
                dpkg -l | grep ${driver_install_file_list[$i]}
            fi
            if [ $? -ne 0 ];then
                g_log_err -e "No ${driver_install_file_list[$i]} relative driver installed at all. Pls install thedriver firstly."
                return 1
            else
                modprobe ${driver_install_file_list[$i]}
                if [ $? -ne 0 ];then
                    g_log_err "modprobe ${driver_install_file_list[$i]} failed"
                    return 1
                fi
                g_log_info "modprobe ${driver_install_file_list[$i]}"
            fi
        fi
    done
    g_log_info "check before install ok"
}

main()
{
    log ""
    g_log_info "install nic firmware start."

    check_before_install
    if [ $? -ne 0 ];then
        g_log_err "check_before_install failed."
        return 1
    fi

    install_firmware
    if [ $? -ne 0 ];then
        g_log_err "install_firmware failed."
        return 1
    fi

    g_log_info "install nic_sdk firmware ok. please reboot host now!"
}

main
OPERATION_VALUE=$(echo $?)
if [ "${OPERATION_VALUE}" == 0 ];then
    INSTALL_STATUS="success"
fi

limit_count_log
log_operation "INSTALL" ${INSTALL_STATUS} "install.sh" ${INSTALL_PARAM}
exit ${OPERATION_VALUE}