#!/bin/bash
#set -e
#****************************************************************
#  FileName  :  install
#  Version   :  1.0
#  Date      :  2019-08-17
#  Function  :  Upgrade SATA hard disk firmware under server
#  Copyright © Huawei Technologies Co., Ltd. 2019-2021. All rights reserved.
#****************************************************************

# Create log time
log_time()
{
    echo $(date +'%Y-%m-%d %H:%M:%S')
}

# Create test results
create_resultxml()
{
    echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>" > "${currentdir}/result.xml"
    echo "<ConfigureResult>" >> "${currentdir}/result.xml"
    echo "    <FwUpgrade>" >> "${currentdir}/result.xml"
    echo "        <Result>${result}</Result>" >> "${currentdir}/result.xml"
    echo "        <ErrorCode>${error_code}</ErrorCode>" >> "${currentdir}/result.xml"
    echo "        <Description>${description}</Description>" >> "${currentdir}/result.xml"
    echo "    </FwUpgrade>" >> "${currentdir}/result.xml"
    echo "</ConfigureResult>" >> "${currentdir}/result.xml"
}


# Handling errors
error_func()
{
    error_code=$1
    description=$2

    if [ "$error_code" -ne 0 ]
    then
        result="Fail"
        echo -e "\033[0;31m $(log_time) [Error ${error_code}] ${description} \033[0m" | tee -a $error_log
    else
        result="OK"
        echo -e "\033[0;33m ${description} \033[0m" | tee -a $upgrade_log
    fi
    create_resultxml
    exit ${error_code}
}

spinup_func()
{
    local cid=$1
    local eid=$2
    local slot=$3
    local spinup_value=$("$storclitool" /c${cid}/e${eid}/s${slot} show all | grep -w "${eid}:${slot}" | awk '{print $(NF-1)}')
    if [[ -n "${spinup_value}" ]] && [[ "${spinup_value}" == "D" ]]
    then
        "$storclitool" /c${cid}/e${eid}/s${slot} spindown
        sleep 2
        "$storclitool" /c${cid}/e${eid}/s${slot} spinup
    fi
}

# check disk firmware in history list
check_xml(){
  local current_firmware="$1"
  local disk_model="$2"
  local disk="$3"
  local sn="$4"
  local resume_res="$5"
  local firmwarecompare=$(cat $currentdir/version.xml | grep "<RuleOldVersion>" | grep -i "$current_firmware")
  if [ -z "$firmwarecompare" ]
  then
    resume_bt
    local error_code=6
    local description="[$disk_model][$disk] disk fw $current_firmware not in history_fw, Disk SN: $sn $resume_res"
    error_func $error_code "${description[*]}"
  fi
}

# A27(Y) send vu command before fw upgrade
send_vu_command()
{
    local disk_fw=$1
    local raid_type=$2
    local cid_index=$3
    local disk_info=$4

    local hex_check_fw=$((0x10A0))
    local hex_disk_fw=$((0x${disk_fw}))
    if [[ $hex_disk_fw -lt $hex_check_fw ]]
    then
        echo -e "This fw[${disk_fw}] not support vu command, skip vu..." | tee -a $upgrade_log
        return
    fi

    echo -e "$(log_time) Start send vu command..." | tee -a $upgrade_log
    mcscli_slc="$testtool/mcscli_slc"
    if [[ "$raid_type" == "megaraid" ]]
    then
        # get disk logic volumn
        local eid=$(echo ${disk_info} | awk -F ":" '{print $1}')
        local slot=$(echo ${disk_info} | awk -F ":" '{print $2}')
        local drive_info=$("$storclitool" /c${cid_index}/e${eid}/s${slot} show | awk '/Drive Information/,/EID=/' | grep -P "\d+:\d+")
        local disk_onln=$(echo "${drive_info}" | grep -wi "Onln" | awk '{print $4}')
        local disk_jbod=$(echo "${drive_info}" | grep -wi "JBOD")

        if [ -n "$disk_onln" ]
        then
            local logic_volumn=$("$storclitool" /c${cid_index}/v${disk_onln} show all | grep -wi "OS Drive Name" | awk '{print $NF}')
        elif [ -z "$logic_volumn" ] && [ -n "$disk_jbod" ]
        then
            local sn=$("$storclitool" /c${cid_index}/e${eid}/s${slot} show all | grep "^SN" | awk -F "=" '{print $2}' | grep -Po "\b.*\b")
            local disk_model=$("$storclitool" /c${cid_index}/e${eid}/s${slot} show all | grep "Model Number" | awk -F "=" '{print $2}' | grep -Po "\b.*\b")
            local disk_model_part=${disk_model::16}

            local logic_volumn_arr=($("$sg_scan" -i | grep -wiB1 "$disk_model_part" | grep -Po "/dev/sg(\d+)"))
            for logic_volumn_member in ${logic_volumn_arr[@]}
            do
                local sn_check=$("$sg_inq" $logic_volumn_member | grep -wi "serial number" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                if [[ "$sn_check" == "$sn" ]]
                then
                    local logic_volumn="$logic_volumn_member"
                    break
                fi
            done
        fi
        if [ -n "$logic_volumn" ]
        then
            local did=$(echo "${drive_info}" | awk '{print $2}')
            "$mcscli_slc" attr selftest-slc-map -d lsi:${did} $logic_volumn
            if [ $? -eq 0 ]
            then
                echo "$(log_time) vu command execute success for ${disk_info} under MEGARAID_MODE" | tee -a $upgrade_log
            else
                echo "$(log_time) vu command execute failed for ${disk_info} under MEGARAID_MODE" | tee -a $upgrade_log
            fi
        fi
    elif [[ "$raid_type" == "pch" ]]
    then
        "$mcscli_slc" attr selftest-slc-map $disk_info
        if [ $? -eq 0 ]
        then
            echo "$(log_time) vu command execute success for ${disk_info} under PCH_MODE" | tee -a $upgrade_log
        else
            echo "$(log_time) vu command execute failed for ${disk_info} under PCH_MODE" | tee -a $upgrade_log
        fi
    elif [[ "$raid_type" == "pmc" ]]
    then
        local disk_arr=($("$arcconf" list 1 | grep -P "\d+,\d+" | egrep -o "[0-9]+,[0-9]+"))
        for ((i=0;i<${#disk_arr[@]};i++))
        do
            if [[ "${disk_arr[i]}" == "$disk_info" ]]
            then
                local did="$i"
            fi
        done
        local disk_onln_arr=($("$arcconf" getconfig ${cid_index} ld | grep -wi "Disk Name" | awk '{print $NF}'))
        if [ -n "$disk_onln_arr" ]
        then
            local pmc_logic_volumn="${disk_onln_arr[0]}"
        else
            local disk_jbod_arr=($("$arcconf" getconfig ${cid_index} pd | grep -wi "Disk Name" | awk '{print $NF}'))
            if [ -n "$disk_jbod_arr" ]
            then
                local pmc_logic_volumn="${disk_jbod_arr[0]}"
            fi
        fi
        if [ -n "$did" ] && [ -n "$pmc_logic_volumn" ]
        then
            "$mcscli_slc" attr selftest-slc-map -d pmc:${did} $pmc_logic_volumn
            if [ $? -eq 0 ]
            then
                echo "$(log_time) vu command execute success for ${disk_info} under PMC_MODE" | tee -a $upgrade_log
            else
                echo "$(log_time) vu command execute failed for ${disk_info} under PMC_MODE" | tee -a $upgrade_log
            fi
        fi
    elif [[ "$raid_type" == "hiraid" ]]
    then
        local eid=$(echo ${disk_info} | awk -F ":" '{print $1}')
        local slot=$(echo ${disk_info} | awk -F ":" '{print $2}')
        local drive_letter=$("$hiraidadm" c${cid_index}:e${eid}:s${slot} show | grep "OS Drive Letter" | awk -F "|" '{print $NF}' | grep -Po "\b.*\b")
        if [ "$drive_letter" == "NA" ]  # raid mode
        then
            local vdlist=($("$hiraidadm" c${cid_index} show vdlist | awk '/VDID/,/_/' | grep -P "\d+"))
            if [ -n "$vdlist" ]
            then
                local vd_idx=$(echo "${vdlist[0]}" | awk '{print $1}')
                local drive_letter=$("$hiraidadm" c${cid_index}:vd${vd_idx} show | grep "OS Drive Letter" | awk -F "|" '{print $NF}' | grep -Po "\b.*\b")
            fi
        fi
        local scsi_host=$(lsscsi -g | grep "$drive_letter" | awk '{print $1}' | awk -F ":" '{print $1}' | grep -Po "\d+")
        if [ -n "$scsi_host" ]
        then
            "$mcscli_slc" attr selftest-slc-map -d hiraid:${disk_info} /dev/bsg/hiraid$scsi_host
            if [ $? -eq 0 ]
            then
                echo "$(log_time) vu command execute success for ${disk_info} under HIRAID_MODE" | tee -a $upgrade_log
            else
                echo "$(log_time) vu command execute failed for ${disk_info} under HIRAID_MODE" | tee -a $upgrade_log
            fi
        fi
    fi
}

# Upgrade disk firmware under Megaraid
megaraid_fw_update()
{
    local eid_slot=$1
    local cid_index=$2
    local eid=$(echo ${eid_slot} | awk -F ":" '{print $1}')
    local slot=$(echo ${eid_slot} | awk -F ":" '{print $2}')
    local disk_firmware=$("$storclitool" /c${cid_index}/e${eid}/s${slot} show all | grep "Firmware Revision" | awk '{print $NF}')
    local disk_model=$("$storclitool" /c${cid_index}/e${eid}/s${slot} show all | grep "Model Number" | awk -F "=" '{print $2}' | grep -Po "\b.*\b")
    local sn=$("$storclitool" /c${cid_index}/e${eid}/s${slot} show all | grep "^SN" | awk -F "=" '{print $2}' | grep -Po "\b.*\b")

    # Null check
    if [ -z "$disk_model" ] || [ -z "$disk_firmware" ]
    then
        # Restore Raid background tasks
        resume_bt
        local error_code=10
        local description="disk_firmware or disk_model that <${eid_slot}><Control_id:${cid_index}> is empty. Disk SN: $sn. $resume_res"
        error_func $error_code "${description[*]}"
    fi
    # Record scan on the disk
    echo "$disk_model : $disk_firmware" >> $currentdir/raid_drive_list.txt

    # Check whether tested disk model number in version.xml
    local disk_model_part=$(echo "$disk_model" | awk '{print $NF}')
    local raidmodel_check=$(cat $currentdir/version.xml | grep "<SupportModel>" | grep -i "$disk_model_part")
    if [ -n "$raidmodel_check" ]
    then
        # Check the tested disk whether the firmware is the latest
        local new_firmware=$(cat $currentdir/version.xml | grep "<Version>" | sed 's/\///g' | awk -F "<Version>" '{print $2}')
        local check_new=$(echo "$new_firmware" | grep -w "$disk_firmware")
        if [ -z "$check_new" ]
        then
            # Check whether disk current firmware in the history list
            check_xml $disk_firmware $disk_model $eid_slot $sn $resume_res
            # Check XH disk current firmware in the history list
            local fwrule=$(cat $currentdir/version.xml | grep "<RuleOldVersion>" | awk -F "<RuleOldVersion>" '{print $2}' | awk -F ";" '{print $1}')
            local history_fw_check=$(echo "$fwrule" | egrep -wo "$disk_firmware")
            if [ -z "$history_fw_check" ]
            then
                echo -e "The hard disk [model:$disk_model] is correct, but the hard disk firmware is not in the historical upgrade list." | tee -a $upgrade_log
                return 0
            fi
            spinup_func "${cid_index}" "${eid}" "${slot}"
            send_vu_command $disk_firmware "megaraid" $cid_index $eid_slot

            # Began to upgrade the firmware
            echo -e "\033[0;32m     start $disk_model update firmware \033[0m" | tee -a $upgrade_log
            for bin_fw in ${bin_fw_list[@]}
            do
                sleep 10
                # Upgrade command/check firmware is tried three times
                for ((n=1;n<4;n++))
                do
                    sleep 2
                    "$storclitool" /c${cid_index}/e${eid}/s${slot} download src=$currentdir/fw/${bin_fw} mode=7
                    if [ $? -eq 0 ]
                    then
                        echo "$(log_time) No.$n fw update ${bin_fw} command execute success for ${eid_slot} under MEGARAID_RAID_MODE" | tee -a $upgrade_log
                    else
                        echo "$(log_time) No.$n fw update ${bin_fw} command execute failed for ${eid_slot} under MEGARAID_RAID_MODE" | tee -a $upgrade_log
                        echo "No.$n fw update ${bin_fw} command execute failed for ${eid_slot} under MEGARAID_RAID_MODE" >> $error_log
                    fi
                    # Before the query firmware, waiting for 10 s
                    sleep 10
                    local after_update_firmware=$("$storclitool" /c${cid_index}/e${eid}/s${slot} show all | grep "Firmware Revision" | awk '{print $NF}')
                    if [ -n "$after_update_firmware" ]
                    then
                        local check_fw=$(echo "${bin_fw}" | grep "$after_update_firmware")
                    fi
                    if [ "$after_update_firmware" == "$new_firmware" ]
                    then
                        echo "$(log_time) $eid_slot fw update to $new_firmware success SN: $sn" | tee -a $upgrade_log
                        break
                    elif [ -n "$check_fw" ]
                    then
                        echo "$(log_time) $eid_slot fw update to ${bin_fw} success SN: $sn" | tee -a $upgrade_log
                        break
                    elif [ $n -ge 3 ]
                    then
                        echo -e "\033[0;31m Model:${disk_model}[$eid_slot] SN:${sn} fw update to $new_firmware failed \033[0m" | tee -a $error_log
                        # Restore Raid background tasks
                        resume_bt
                        local error_code=7
                        local description="$(cat $error_log). $resume_res"
                        error_func $error_code "${description[*]}"
                    fi
                done
            done
            echo -e "\033[0;32m     finish $disk_model update to $new_firmware firmware \033[0m" | tee -a $upgrade_log
        else
            echo -e "\033[0;32m     raid $disk_model : $disk_firmware is newest firmware \033[0m" | tee -a $upgrade_log
        fi
        return 0
    else
        echo -e "\033[0;32m     $eid_slot($disk_model) is not in the configuration,Skipping it... \033[0m" | tee -a $upgrade_log
    fi
    return 0
}

# Upgrade disk firmware under Hiraid
hiraid_fw_update()
{
    local eid_slot=$1
    local cidindex=$2
    local Eid=$(echo ${eid_slot} | awk -F ":" '{print $1}')
    local slot=$(echo ${eid_slot} | awk -F ":" '{print $2}')
    local disk_firmware=$("$hiraidadm" c${cidindex}:e${Eid}:s${slot} show | grep -w "Firmware Version" | awk -F "|" '{print $NF}' | grep -Po "\b.*\b")
    local disk_model=$("$hiraidadm" c${cidindex}:e${Eid}:s${slot} show | grep -w "Model" | awk -F "|" '{print $NF}' | grep -Po "\b.*\b")
    local sn=$("$hiraidadm" c${cidindex}:e${Eid}:s${slot} show | grep -w "Serial Number" | awk -F "|" '{print $NF}' | grep -Po "\b.*\b")

    # NULL check
    if [ -z "$disk_model" ] || [ -z "$disk_firmware" ]
    then
        local error_code=10
        local description="disk_firmware or disk_model that <${eid_slot}><Control_id:${cidindex}> is empty. Disk SN: $sn.$resume_res"
        error_func $error_code "${description[*]}"
    fi
    # Record scan on the disk
    echo "$disk_model : $disk_firmware" >> $currentdir/raid_drive_list.txt
    # Check whether tested disk model number in version.xml
    local disk_model_part=$(echo "$disk_model" | awk '{print $NF}')
    local raidmodel_check=$(cat $currentdir/version.xml | grep "<SupportModel>" | grep -i "$disk_model_part")
    if [ -n "$raidmodel_check" ]
    then
        # Check the tested disk whether the firmware is the latest
        local new_firmware=$(cat $currentdir/version.xml | grep "<Version>" | sed 's/\///g' | awk -F "<Version>" '{print $2}')
        local check_new=$(echo "$new_firmware" | grep -w "$disk_firmware")
        if [ -z "$check_new" ]
        then
            # Check whether disk current firmware in the history list
            check_xml $disk_firmware $disk_model $eid_slot $sn
            # Check XH disk current firmware in the history list
            local fwrule=$(cat $currentdir/version.xml | grep "<RuleOldVersion>" | awk -F "<RuleOldVersion>" '{print $2}' | awk -F ";" '{print $1}')
            local history_fw_check=$(echo "$fwrule" | egrep -wo "$disk_firmware")
            if [ -z "$history_fw_check" ]
            then
                echo -e "The hard disk [model:$disk_model] is correct, but the hard disk firmware is not in the historical upgrade list." | tee -a $upgrade_log
                return 0
            fi
            send_vu_command $disk_firmware "hiraid" $cidindex $eid_slot

            # Began to upgrade the firmware
            echo -e "\033[0;32m     start $disk_model update firmware \033[0m" | tee -a $upgrade_log
            for bin_fw in ${bin_fw_list[@]}
            do
                sleep 10
                # Upgrade command/check firmware is tried three times
                for ((n=1;n<4;n++))
                do
                    sleep 2
                    "$hiraidadm" c${cidindex}:e${Eid}:s${slot} update fw file=./fw/${bin_fw}
                    if [ $? -eq 0 ]
                    then
                        echo "$(log_time) No.$n fw update ${bin_fw} command execute success for ${eid_slot} under HIRAID_RAID_MODE" | tee -a $upgrade_log
                    else
                        echo "$(log_time) No.$n fw update ${bin_fw} command execute failed for ${eid_slot} under HIRAID_RAID_MODE" | tee -a $upgrade_log
                        echo "No.$n fw update ${bin_fw} command execute failed for ${eid_slot} under HIRAID_RAID_MODE" >> $error_log
                    fi
                    sleep 5
                    "$hiraidadm" c${cidindex}:e${Eid}:s${slot} active fw
                    [ $? -eq 0 ] && echo "$(log_time) finish c${cidindex}:e${Eid}:s${slot} ${bin_fw} activated" | tee -a $upgrade_log
                    # Before the query firmware, waiting for 10 s
                    sleep 10
                    local after_update_firmware=$("$hiraidadm" c${cidindex}:e${Eid}:s${slot} show | grep -w "Firmware Version" | awk -F "|" '{print $NF}' | grep -Po "\b.*\b")
                    if [ -n "$after_update_firmware" ]
                    then
                        local check_fw=$(echo "${bin_fw}" | grep "$after_update_firmware")
                    fi
                    if [ "$after_update_firmware" == "$new_firmware" ]
                    then
                        echo "$(log_time) $eid_slot fw update to $new_firmware success SN: $sn" | tee -a $upgrade_log
                        break
                    elif [ -n "$check_fw" ]
                    then
                        echo "$(log_time) $eid_slot fw update to ${bin_fw} success SN: $sn" | tee -a $upgrade_log
                        break
                    elif [ $n -ge 3 ]
                    then
                        echo -e "\033[0;31m Model:${disk_model}[$eid_slot] SN:${sn} fw update to $new_firmware failed \033[0m" | tee -a $error_log
                        local error_code=7
                        local description="$(cat $error_log). $resume_res"
                        error_func $error_code "${description[*]}"
                    fi
                done
            done
            echo -e "\033[0;32m     finish $disk_model update to $new_firmware firmware \033[0m" | tee -a $upgrade_log
        else
            echo -e "\033[0;32m     raid $disk_model : $disk_firmware is newest firmware \033[0m" | tee -a $upgrade_log
        fi
        return 0
    else
        echo -e "\033[0;32m     $eid_slot($disk_model) is not in the configuration,Skipping it... \033[0m" | tee -a $upgrade_log
    fi
    return 0

}


# Upgrade disk firmware under pass-through
pch_fw_update()
{
    local disk=$1
    local disk_fw=$("$hdparm" -I "$disk" | grep -wi "Firmware Revision" | awk '{print $NF}')
    local disk_model=$("$hdparm" -I "$disk" | grep -wi "Model Number" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
    local sn=$("$hdparm" -I "$disk" | grep -wi "Serial Number" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")

    # Null check
    if [ -z "$disk_model" ] || [ -z "$disk_fw" ]
    then
        # Restore Raid background tasks
        resume_bt
        local error_code=10
        local description="disk_firmware or disk_model that <${disk}> is empty. Disk SN: $sn. $resume_res"
        error_func $error_code "${description[*]}"
    fi
    # Record scan on the disk
    echo "$disk_model : $disk_fw" >> $currentdir/direct_drive_list.txt

    # Check whether tested disk model number in version.xml
    local disk_model_part=$(echo "$disk_model" | awk '{print $NF}')
    local diskcompare=$(cat $currentdir/version.xml | grep "<SupportModel>" | grep -i "$disk_model_part")
    if [ -n "$diskcompare" ]
    then
        # Check the tested disk whether the firmware is the latest
        local new_firmware=$(cat $currentdir/version.xml | grep "<Version>" | sed 's/\///g' | awk -F"<Version>" '{print $2}')
        local check_new=$(echo "$new_firmware" | grep -w "$disk_fw")
        if [ -z "$check_new" ]
        then
            # Check whether disk current firmware in the history list
            check_xml $disk_fw $disk_model $disk $sn $resume_res
            # Check XH disk current firmware in the history list
            local fwrule=$(cat $currentdir/version.xml | grep "<RuleOldVersion>" | awk -F "<RuleOldVersion>" '{print $2}' | awk -F ";" '{print $1}')
            local history_fw_check=$(echo "$fwrule" | egrep -wo "$disk_fw")
            if [ -z "$history_fw_check" ]
            then
                echo -e "The hard disk [model:$disk_model] is correct, but the hard disk firmware is not in the historical upgrade list." | tee -a $upgrade_log
                return 0
            fi
            send_vu_command $disk_fw "pch" "NA" $disk

            # Began to upgrade the firmware
            echo -e "\033[0;32m     start ${disk} update firmware \033[0m" | tee -a $upgrade_log
            for bin_fw in ${bin_fw_list[@]}
            do
                sleep 10
                # Upgrade command/check firmware is tried three times
                for ((n=1;n<4;n++))
                do
                    sleep 2
                    "$hdparm" --yes-i-know-what-i-am-doing --please-destroy-my-drive --fwdownload $currentdir/fw/${bin_fw} $disk
                    if [ $? -eq 0 ]
                    then
                        echo "$(log_time) No.$n fw update ${bin_fw} command execute success for ${disk} under PCH/HBA" | tee -a $upgrade_log
                    else
                        echo "$(log_time) No.$n fw update ${bin_fw} command execute failed for ${disk} under PCH/HBA" | tee -a $upgrade_log
                        echo "No.$n fw update ${bin_fw} command execute failed for ${disk} under PCH/HBA" >> $error_log
                    fi
                    # Before the query firmware, waiting for 10 s
                    sleep 10
                    local after_update_firmware=$("$hdparm" -I "$disk" | grep -i "Firmware Revision" | awk '{print $NF}')
                    if [ -n "$after_update_firmware" ]
                    then
                        local check_fw=$(echo "${bin_fw}" | grep "$after_update_firmware")
                    fi
                    if [ "$after_update_firmware" == "$new_firmware" ]
                    then
                        echo "$(log_time) PCH/HBA ${disk} update to $new_firmware success SN: $sn" | tee -a $upgrade_log
                        break
                    elif [ -n "$check_fw" ]
                    then
                        echo "$(log_time) PCH/HBA ${disk} update to ${bin_fw} success SN: $sn" | tee -a $upgrade_log
                        break
                    elif [ $n -ge 3 ]
                    then
                        echo -e "\033[0;31m Model:${disk_model}[$disk] SN:${sn} update to $new_firmware fail \033[0m" | tee -a $error_log
                        # Restore Raid background tasks
                        resume_bt
                        local error_code=7
                        local description="$(cat $error_log). $resume_res"
                        error_func $error_code "${description[*]}"
                    fi
                done
            done
            echo -e "\033[0;32m     finish ${disk} update to $new_firmware firmware \033[0m" | tee -a $upgrade_log
        else
            echo -e "\033[0;32m     PCH/HBA $disk_model : $disk_fw is newest firmware \033[0m" | tee -a $upgrade_log
        fi
        return 0
    else
        echo -e "\033[0;32m     $disk($disk_model) is not in the configuration,Skipping it... \033[0m" | tee -a $upgrade_log
    fi
    return 0
}


# Upgrade disk firmware under PMC
pmc_fw_update()
{
    local physical_loc=$1
    local raid_num=$2
    local type_feature=$3
    local eid=$(echo "$physical_loc" | awk -F "," '{print $1}')
    local slot=$(echo "$physical_loc" | awk -F "," '{print $2}')
    local sn=$("$arcconf" getconfig ${raid_num} pd $eid $slot | grep -wi "Serial number" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")

    # Because arcconf tools cannot complete access to the model and firmware, adopt indirect access here
    local disk_name=$("$arcconf" getconfig ${raid_num} pd $eid $slot | grep -wi "Disk Name" | awk '{print $NF}')
    if [ -z "$disk_name" ]
    then
        # Access to Online mode corresponds to drive
        local disk_onln_arr=($("$arcconf" getconfig ${raid_num} ld | grep -wi "Disk Name" | grep -wi "/dev/sd." | awk '{print $NF}'))

        # PMC8060 card need accurate access to drive
        if [ -n "$disk_onln_arr" ] && [ "$type_feature" -eq 0 ]
        then
            # Choose the raid card under a logical drive letter, provide logical channel to retrieve information from a hard disk
            local disk_name="${disk_onln_arr[0]}"
        else
            # According to the model number of reverse matching logical drive
            local pmc_disk_model=$("$arcconf" getconfig ${raid_num} pd $eid $slot | grep -wi "Model" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
            local pmc_model_part=${pmc_disk_model::16}

            # Get all the logical drive of corresponding to the model
            local pmc_logic_volumn_arr=($("$sg_scan" -i | grep -wiB1 "$pmc_model_part" | grep -Po "/dev/sg(\d+)"))
            for pmc_logic_volumn_member in ${pmc_logic_volumn_arr[@]}
            do
                local sn_check=$("$sg_inq" $pmc_logic_volumn_member | grep -wi "serial number" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                if [ -n "$sn_check" ]
                then
                    if [[ "$sn_check" == "$sn" ]]
                    then
                        local disk_name="$pmc_logic_volumn_member"
                        break
                    fi
                fi
            done
            if [ -z "$disk_name" ]
            then
                # Restore Raid background tasks
                resume_bt
                local error_code=8
                local description="logical_disk is not found under PMC <control_id:${raid_num}>, result in get disk_model fail. Disk SN: $sn. $resume_res"
                error_func $error_code "${description[*]}"
            fi
        fi
    fi
    # PMC 8060 card information command : smartctl -i /dev/sgx
    if [ "$type_feature" -ne 1 ]
    then
        local all_channel=($($arcconf list ${raid_num} | grep -P "\d+,\d+" | grep -vi "Not Applicable" | egrep -o "[0-9]+,[0-9]+"))
        for ((number=0;number<${#all_channel[@]};number++))
        do
            if [[ "$physical_loc" == "${all_channel[$number]}" ]]
            then
                local disk_model=$("$smartool" -i --device=cciss,${number} ${disk_name} | grep -wi "Device Model" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                local disk_firmware=$("$smartool" -i --device=cciss,${number} ${disk_name} | grep -wi "Firmware Version" | awk '{print $NF}')
                break
            fi
        done
    else
        local disk_model=$("$smartool" -i ${disk_name} | grep -wi "Device Model" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
        local disk_firmware=$("$smartool" -i ${disk_name} | grep -wi "Firmware Version" | awk '{print $NF}')
    fi

    # Null check
    if [ -z "$disk_model" ] || [ -z "$disk_firmware" ]
    then
        # Restore Raid background tasks
        resume_bt
        local error_code=10
        local description="disk_firmware or disk_model that <${physical_loc}><Control_id:${raid_num}> is empty. Disk SN: $sn. $resume_res"
        error_func $error_code "${description[*]}"
    fi
    # Record scan on the disk
    echo "$disk_model : $disk_firmware" >> $currentdir/pmc_drive_list.txt

    # Check whether tested disk model number in version.xml
    local disk_model_part=$(echo "$disk_model" | awk '{print $NF}')
    local model_check=$(cat $currentdir/version.xml | grep "<SupportModel>" | grep -i "$disk_model_part")
    if [ -n "$model_check" ]
    then
        # Check the tested disk whether the firmware is the latest
        local new_firmware=$(cat $currentdir/version.xml | grep "<Version>" | sed 's/\///g' | awk -F"<Version>" '{print $2}')
        local check_new=$(echo "$new_firmware" | grep -w "$disk_firmware")
        if [ -z "$check_new" ]
        then
            # Check whether disk current firmware in the history list
            check_xml $disk_firmware $disk_model $physical_loc $sn $resume_res
            # Check XH disk current firmware in the history list
            local fwrule=$(cat $currentdir/version.xml | grep "<RuleOldVersion>" | awk -F "<RuleOldVersion>" '{print $2}' | awk -F ";" '{print $1}')
            local history_fw_check=$(echo "$fwrule" | egrep -wo "$disk_firmware")
            if [ -z "$history_fw_check" ]
            then
                echo -e "The hard disk [model:$disk_model] is correct, but the hard disk firmware is not in the historical upgrade list." | tee -a $upgrade_log
                return 0
            fi
            send_vu_command $disk_firmware "pmc" $raid_num $physical_loc

            # Began to upgrade the firmware
            echo -e "\033[0;32m     start ${disk_model} update firmware \033[0m" | tee -a $upgrade_log
            for bin_fw in ${bin_fw_list[@]}
            do
                sleep 10
                # Upgrade command/check firmware is tried three times
                for ((n=1;n<4;n++))
                do
                    sleep 2
                    # Upgrade in the command under 8060, 3 and 7 instead
                    if [ "$type_feature" -eq 0 ]
                    then
                        echo y | "$arcconf" imageupdate "$raid_num" device "$eid" "$slot" 32768 $currentdir/fw/${bin_fw} 3 Rescan
                    else
                        echo y | "$arcconf" imageupdate "$raid_num" device "$eid" "$slot" 32768 $currentdir/fw/${bin_fw} 7 Rescan
                    fi
                    if [ $? -eq 0 ]
                    then
                        echo "$(log_time) No.$n fw update ${bin_fw} command execute success for ${physical_loc} under PMC_RAID" | tee -a $upgrade_log
                    else
                        echo "$(log_time) No.$n fw update ${bin_fw} command execute failed for ${physical_loc} under PMC_RAID" | tee -a $upgrade_log
                        echo "No.$n fw update ${bin_fw} command execute failed for ${physical_loc} under PMC_RAID" >> $error_log
                    fi
                    # Before the query firmware, waiting for 10 s
                    sleep 10
                    local after_update_firmware=$("$smartool" -i --device=cciss,${number} ${disk_name} | grep -wi "Firmware Version" | awk '{print $NF}')
                    if [ -n "$after_update_firmware" ]
                    then
                        local check_fw=$(echo "${bin_fw}" | grep "$after_update_firmware")
                    fi
                    if [ "$after_update_firmware" == "$new_firmware" ]
                    then
                        echo "$(log_time) ${physical_loc} fw update to $new_firmware success SN: $sn" | tee -a $upgrade_log
                        break
                    elif [ -n "$check_fw" ]
                    then
                        echo "$(log_time) ${physical_loc} fw update to ${bin_fw} success SN: $sn" | tee -a $upgrade_log
                        break
                    elif [ $n -ge 3 ]
                    then
                        # Restore Raid background tasks
                        resume_bt
                        local error_code=7
                        local description="$(cat $error_log). $resume_res"
                        error_func $error_code "${description[*]}"
                    fi
                done
            done
            echo -e "\033[0;32m     finish ${disk_model} update firmware \033[0m" | tee -a $upgrade_log
        else
            echo -e "\033[0;32m     ${disk_model} : ${disk_firmware} is newest firmware \033[0m" | tee -a $upgrade_log
        fi
        return 0
    else
        echo -e "\033[0;32m     ${physical_loc}($disk_model) is not in the configuration,Skipping it... \033[0m" | tee -a $upgrade_log
    fi
    return 0
}


# Suspend Raid background tasks
close_bt()
{
    local cid_index=$1
    local raid_id=$2

    # check bgi
    local check_bgi=$("$storclitool" /c${cid_index}/v${raid_id} show bgi | grep "In progress")
    if [ -n "$check_bgi" ]
    then
        "$storclitool" /c${cid_index}/v${raid_id} pause bgi > command_result.log
        local res=$(cat command_result.log | grep -i "Status =" | grep -Pio "Success")
        if [ -n "$res" ]
        then
            echo -e "\033[0;36m     c${cid_index}/v${raid_id} bgi pause success \033[0m" | tee -a $upgrade_log
            bgi_arr=(${bgi_arr[@]} "${cid_index}_${raid_id}")
        else
            echo -e "\033[0;31m     c${cid_index}/v${raid_id} bgi pause failure \033[0m" | tee -a $error_log
        fi
    fi

    # check patrolread
    local check_pr=$("$storclitool" /c${cid_index} show patrolread | grep -i "PR Current State" | grep -i "Active")
    if [ -n "$check_pr" ]
    then
        local check_mode=$("$storclitool" /c${cid_index} show patrolread | grep -i "PR Mode" | grep -io "Disable")
        if [ -n "$check_mode" ]
        then
            "$storclitool" /c${cid_index} set patrolread=on mode=manual > command_result.log
            local res=$(cat command_result.log | grep -i "Status =" | grep -Pio "Success")
            if [ -n "$res" ]
            then
                echo -e "\033[0;36m     c${cid_index} mode_switch success \033[0m" | tee -a $upgrade_log
                pr_mode_arr=(${pr_mode_arr[@]} ${cid_index})
            else
                echo -e "\033[0;31m     c${cid_index} mode_switch failure \033[0m" | tee -a $error_log
            fi
            sleep 2
        fi
        "$storclitool" /c${cid_index} pause patrolread > command_result.log
        local res=$(cat command_result.log | grep -i "Status =" | grep -Pio "Success")
        if [ -n "$res" ]
        then
            echo -e "\033[0;36m     c${cid_index} patrolread pause success \033[0m" | tee -a $upgrade_log
            pr_arr=(${pr_arr[@]} ${cid_index})
        else
            echo -e "\033[0;31m     c${cid_index} patrolread pause failure \033[0m" | tee -a $error_log
        fi
    fi

    # check cc
    local check_cc=$("$storclitool" /c${cid_index}/v${raid_id} show cc | grep "In progress")
    if [ -n "$check_cc" ]
    then
        "$storclitool" /c${cid_index}/v${raid_id} pause cc > command_result.log
        local res=$(cat command_result.log | grep -i "Status =" | grep -Pio "Success")
        if [ -n "$res" ]
        then
            echo -e "\033[0;36m     c${cid_index}/v${raid_id} cc pause success \033[0m" | tee -a $upgrade_log
            cc_arr=(${cc_arr[@]} "${cid_index}_${raid_id}")
        else
            echo -e "\033[0;31m     c${cid_index}/v${raid_id} cc pause failure \033[0m" | tee -a $error_log
        fi
    fi
}


# Restore Raid background tasks
resume_bt()
{
    for cid_raid in ${bgi_arr[@]}
    do
        local cid_index=$(echo $cid_raid | awk -F "_" '{print $1}')
        local raid_id=$(echo $cid_raid | awk -F "_" '{print $2}')
        "$storclitool" /c${cid_index}/v${raid_id} resume bgi > command_result.log
        local res=$(cat command_result.log | grep -i "Status =" | grep -Pio "Success")
        if [ -n "$res" ]
        then
            echo -e "\033[0;33m c${cid_index}/v${raid_id} bgi resume success \033[0m"
        else
            echo "bgi : c${cid_index}/v${raid_id}" >> $resume_log
        fi
    done

    for cid_index in ${pr_arr[@]}
    do
        "$storclitool" /c${cid_index} resume patrolread > command_result.log
        local res=$(cat command_result.log | grep -i "Status =" | grep -Pio "Success")
        if [ -n "$res" ]
        then
            echo -e "\033[0;33m c${cid_index} patrolread resume success \033[0m"
        else
            echo "patrolread : c${cid_index}" >> $resume_log
        fi
    done
    for pr_mode in ${pr_mode_arr[@]}
    do
        "$storclitool" /c${cid_index} set patrolread=off > command_result.log
        local res=$(cat command_result.log | grep -i "Status =" | grep -Pio "Success")
        if [ -n "$res" ]
        then
            echo -e "\033[0;33m c${cid_index} patrolread mode_switch success \033[0m"
        else
            echo "patrolread mode : c${cid_index}" >> $resume_log
        fi
    done

    for cid_raid in ${cc_arr[@]}
    do
        local cid_index=$(echo $cid_raid | awk -F "_" '{print $1}')
        local raid_id=$(echo $cid_raid | awk -F "_" '{print $2}')
        "$storclitool" /c${cid_index}/v${raid_id} resume cc > command_result.log
        local res=$(cat command_result.log | grep -i "Status =" | grep -Pio "Success")
        if [ -n "$res" ]
        then
            echo -e "\033[0;33m c${cid_index}/v${raid_id} cc resume success \033[0m"
        else
            echo "cc : c${cid_index}/v${raid_id}" >> $resume_log
        fi
    done

    # Raid background tasks without full recovery, the error to exit
    if [ -n "$(cat $resume_log | grep -E "bgi|patrolread|cc")" ]
    then
        echo -e "\033[0;31m The Raid background tasks not fully recovered \033[0m" | tee -a $error_log
        resume_res="The Raid background tasks not fully recovered, need to manually restore. $(cat $resume_log)"
    fi
}


# Check the hard disk health status
check_disk_healthy()
{
    local raid_type=$1
    local cid_index=$2
    local disk_all=($3)
    local type_feature=$4

    echo -e "\033[0;36m     Disk health is checking... \033[0m"
    if [[ "$raid_type" == "megaraid" ]]
    then
        # Access to the online state hard disk raid number
        local disk_onln_arr=($("$storclitool" /c${cid_index} show | awk '/PD LIST/,/EID=/' | grep -P "\d+:\d+" | grep -wi "SATA" | grep -wi "Onln" | awk '{print $4}'))
        # Get jbod state hard drive slot number
        local disk_jbod_arr=($("$storclitool" /c${cid_index} show | awk '/PD LIST/,/EID=/' | grep -P "\d+:\d+" | grep -wi "SATA" | grep -wi "JBOD" | awk '{print $1}'))
        if [ -n "$disk_onln_arr" ]
        then
            for disk_onln in ${disk_onln_arr[@]}
            do
                local logic_volumn=$("$storclitool" /c${cid_index}/v${disk_onln} show all | grep -wi "OS Drive Name" | awk '{print $NF}')
                [ -n "$logic_volumn" ] && break
            done
        elif [ -z "$logic_volumn" ] && [ -n "$disk_jbod_arr" ]
        then
            # According to the model number of reverse matching logical drive
            for disk_jbod in ${disk_jbod_arr[@]}
            do
                local eid=$(echo "${disk_jbod}" | awk -F ":" '{print $1}')
                local slot=$(echo "${disk_jbod}" | awk -F ":" '{print $2}')
                local sn=$("$storclitool" /c${cid_index}/e${eid}/s${slot} show all | grep "^SN" | awk -F "=" '{print $2}' | grep -Po "\b.*\b")
                local disk_model=$("$storclitool" /c${cid_index}/e${eid}/s${slot} show all | grep "Model Number" | awk -F "=" '{print $2}' | grep -Po "\b.*\b")
                local disk_model_part=${disk_model::16}
                
                # Get all the logical drive of corresponding to the model
                local logic_volumn_arr=($("$sg_scan" -i | grep -wiB1 "$disk_model_part" | grep -Po "/dev/sg(\d+)"))
                for logic_volumn_member in ${logic_volumn_arr[@]}
                do
                    local sn_check=$("$sg_inq" $logic_volumn_member | grep -wi "serial number" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                    if [[ "$sn_check" == "$sn" ]]
                    then
                        local logic_volumn="$logic_volumn_member"
                        break
                    fi
                done
                [ -n "$logic_volumn" ] && break
            done
        fi
        if [ -n "$logic_volumn" ]
        then
            # Gets the current raid card DID all the hard disk
            local did_all=($("$storclitool" /c${cid_index} show | awk '/PD LIST/,/EID=/' | grep -wi "SATA" | grep -P "\d+:\d+" | awk '{print $2}'))
            for did in ${did_all[@]}
            do
                # check smart
                local disk_health_field=$("$smartool" -a -d sat+megaraid,${did} ${logic_volumn} | grep -Pwi "SMART[\s\S]+Health")
                if [ -n "$disk_health_field" ]
                then
                    local disk_health=$(echo "$disk_health_field" | egrep -wi "PASSED|OK")
                    if [ -z "$disk_health" ]
                    then
                        local disk_model=$("$smartool" -i -d sat+megaraid,${did} ${logic_volumn} | grep -wi "Device Model" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                        local disk_sn=$("$smartool" -i -d sat+megaraid,${did} ${logic_volumn} | grep -wi "Serial Number" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                        # Restore Raid background tasks
                        resume_bt
                        local error_code=5
                        local description="$disk_health_field, Model:${disk_model} SN:${disk_sn} is not healthy, Please confirm the smart health of the disk. $resume_res"
                        error_func $error_code "${description[*]}"
                    fi
                fi
            done
        fi
    elif [[ "$raid_type" == "hba" ]]
    then
        # Check all the hard disk of smart information
        for disk_sg in ${disk_all[@]}
        do
            local disk_health_field=$("$smartool" -H ${disk_sg} | grep -Pwi "SMART[\s\S]+Health")
            if [ -n "$disk_health_field" ]
            then
                local disk_health=$(echo "$disk_health_field" | egrep -wi "PASSED|OK")
                if [ -z "$disk_health" ]
                then
                    local disk_model=$("$smartool" -i ${disk_sg} | grep -wi "Device Model" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                    local disk_sn=$("$smartool" -i ${disk_sg} | grep -wi "Serial Number" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                    # Restore Raid background tasks
                    resume_bt
                    local error_code=5
                    local description="$disk_health_field, Model:${disk_model} SN:${disk_sn} is not healthy, Please confirm the smart health of the disk. $resume_res"
                    error_func $error_code "${description[*]}"
                fi
            fi
        done
    elif [[ "$raid_type" == "pmc" ]]
    then
        # Gets the current raid card all the virtual disk letter(Online or Ready mode)
        local disk_onln_arr=($("$arcconf" getconfig ${cid_index} ld | grep -wi "Disk Name" | grep -wi "/dev/sd." | awk '{print $NF}'))

        # PMC8060 card need accurate access to drive
        if [ -n "$disk_onln_arr" ] && [ "$type_feature" -eq 0 ]
        then
            # Choose a virtual drive, provide logical channel to smart info
            local pmc_logic_volumn="${disk_onln_arr[0]}"
        fi
        for ((n=0;n<${#disk_all[@]};n++))
        do
            if [ -z "$pmc_logic_volumn" ] || [ "$type_feature" -eq 1 ]
            then
                # Choose the raid card under a logical drive letter, provide logical channel to smart info
                local pmc_disk_name=$("$arcconf" getconfig ${cid_index} pd | grep -wB10 "${disk_all[$n]}" | grep -wi "Disk Name" | awk '{print $NF}')
                if [ -n "$pmc_disk_name" ]
                then
                    local pmc_logic_volumn="$pmc_disk_name"
                else
                    # According to the model number of reverse matching logical drive
                    local sn=$("$arcconf" getconfig ${cid_index} pd | grep -wA10 "${disk_all[$n]}" | grep -wi "Serial number" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                    local pmc_disk_model=$("$arcconf" getconfig ${cid_index} pd | grep -wA10 "${disk_all[$n]}" | grep -wi "Model" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                    local pmc_model_part=${pmc_disk_model::16}

                    # Get all the logical drive of corresponding to the model
                    local pmc_logic_volumn_arr=($("$sg_scan" -i | grep -wiB1 "$pmc_model_part" | grep -Po "/dev/sg(\d+)"))
                    for pmc_logic_volumn_member in ${pmc_logic_volumn_arr[@]}
                    do
                        local sn_check=$("$sg_inq" $pmc_logic_volumn_member | grep -wi "serial number" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                        if [[ "$sn_check" == "$sn" ]]
                        then
                            local pmc_logic_volumn="$pmc_logic_volumn_member"
                            break
                        fi
                    done
                fi
            fi
            if [ -n "$pmc_logic_volumn" ]
            then
                if [ "$type_feature" -ne 1 ]
                then
                    local disk_health_field=$("$smartool" -a --device=cciss,${n} ${pmc_logic_volumn} | grep -Pwi "SMART[\s\S]+Health")
                else
                    # PMC 8060 card information command : smartctl -i /dev/sgx
                    local disk_health_field=$("$smartool" -a ${pmc_logic_volumn} | grep -Pwi "SMART[\s\S]+Health")
                fi
                if [ -n "$disk_health_field" ]
                then
                    local disk_health=$(echo "$disk_health_field" | egrep -wi "PASSED|OK")
                    if [ -z "$disk_health" ]
                    then
                        if [ "$type_feature" -ne 1 ]
                        then
                            local disk_model=$("$smartool" -i --device=cciss,${n} ${pmc_logic_volumn} | grep -wi "Device Model" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                            local disk_sn=$("$smartool" -i --device=cciss,${n} ${pmc_logic_volumn} | grep -wi "Serial Number" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                        else
                            local disk_model=$("$smartool" -i ${pmc_logic_volumn} | grep -wi "Device Model" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                            local disk_sn=$("$smartool" -i ${pmc_logic_volumn} | grep -wi "Serial Number" | awk -F ":" '{print $2}' | grep -Po "\b.*\b")
                        fi
                        # Restore Raid background tasks
                        resume_bt
                        local error_code=5
                        local description="$disk_health_field, Model:${disk_model} SN:${disk_sn} is not healthy, Please confirm the smart health of the disk. $resume_res"
                        error_func $error_code "${description[*]}"
                    fi
                fi
            fi
        done
    elif [[ "$raid_type" == "hiraid" ]]
    then
        # check disk health
        local index_arr=($("$hiraidadm" c"$cid_index" show pdlist | awk '/Enc  Slot DID/,/Status =/' | grep -wi "SATA" | awk '{print $1}'))
        for index in ${index_arr[@]}
        do
            local prefail=($("$hiraidadm" c"$cid_index" show pdlist | awk '/Enc  Slot DID/,/Status =/' | grep -wi "SATA" | grep -Pw "^$index" | awk '{print $9}'))
            if [[ "$prefail" != "No" ]]
            then
                local eid_sid=($("$hiraidadm" c"$cid_index" show pdlist | awk '/Enc  Slot DID/,/Status =/' | grep -wi "SATA" | grep -Pw "^$index" | awk '{print "e"$2":s"$3}'))
                local disk_model=$("$hiraidadm" c"$cid_index":$eid_sid show | grep -P "^Model" | awk -F "|" '{print $NF}' | grep -Po "\b.*\b")
                local disk_sn=$("$hiraidadm" c"$cid_index":$eid_sid show | grep -i "Serial Number" | awk -F "|" '{print $NF}'| grep -Po "\b.*\b")
                local error_code=5
                local description="Model:${disk_model} SN:${disk_sn} is not healthy, Please confirm the smart health of the disk. $resume_res"
                error_func $error_code "${description[*]}"
            fi
        done
    fi
    return 0
}

# Check the raid group health status
check_raid_healthy()
{
    local raid_type=$1
    local cid_index=$2

    echo -e "\033[0;36m     Raid health is checking... \033[0m"
    if [[ "$raid_type" == "megaraid" ]]
    then
        # Check the background task
        local bt_values=($("$storclitool" /c${cid_index} show | grep -wiA30 -m 1 "BT" | grep -P "^\s" | awk '{print $8}'))
        for ((h=0;h<${#bt_values[@]};h++))
        do
            if [[ "${bt_values[$h]}" == "Y" ]]
            then
                local disk_id_arr=($("$storclitool" /c${cid_index} show | grep -wiA30 -m 1 "BT" | grep -P "^\s" | awk '{print $1}'))
                local v_id=$("$storclitool" /c${cid_index}/vall show | grep -i "RAID" | grep -Po "${disk_id_arr[$h]}/\d+" | awk -F "/" '{print $2}')
                # Suspend Raid background tasks
                echo -e "\033[0;36m     Detect the Raid group(/c${cid_index}/v${v_id}) has a background task, pausing... \033[0m"
                close_bt $cid_index $v_id
            fi
        done
        # Check all the virtual disk
        local virtual_state=($("$storclitool" /c${cid_index} show | grep -wP "\d+/\d+" | grep -i "RAID" | awk '{print $3}'))
        for state in ${virtual_state[@]}
        do
            if [[ "$state" != "Optl" ]]
            then
                # Restore Raid background tasks
                resume_bt
                local error_code=4
                local description="virtual_disk_state is $state, Megaraid ${cid_index} virtual_disk_state is is abnormal. $resume_res"
                error_func $error_code "${description[*]}"
            fi
        done
        # Check VD_Cache
        local vd_field=$("$storclitool" /c${cid_index} show all | grep -wi "VD Cache")
        if [ -n "$vd_field" ]
        then
            local cache_value=$(echo "$vd_field" | awk '{print $NF}' | grep -wi "No")
            if [ -z "$cache_value" ]
            then
                # Restore Raid background tasks
                resume_bt
                local error_code=4
                local description="$vd_field, Megaraid ${cid_index} VD_Cache is abnormal. $resume_res"
                error_func $error_code "${description[*]}"
            fi
        fi
    elif [[ "$raid_type" == "hba" ]]
    then
        # Check the background task
        local current_operation=($("$sas3" ${cid_index} status | grep -wi "Current operation" | awk '{print $NF}'))
        for task in ${current_operation[@]}
        do
            if [[ "$task" != "None" ]]
            then
                echo -e "\033[0;31m Error 4: current_operation is $task, background task is exist under HBA ${cid_index} raid_group \033[0m" | tee -a $error_log
            fi
        done
        # Check all the virtual disk
        local virtual_state=($("$sas3" ${cid_index} display | grep -wi "Status of volume" | awk '{print $5}'))
        for vir_state in ${virtual_state[@]}
        do
            if [[ "$vir_state" != "Okay" ]]
            then
                # Restore Raid background tasks
                resume_bt
                local error_code=4
                local description="virtual_disk_state is ${vir_state}, HBA ${cid_index} virtual_disk_state is abnormal. $resume_res"
                error_func $error_code "${description[*]}"
            fi
        done
        # Check all the physical disk
        local physical_state=($("$sas3" ${cid_index} display | awk '/Hard disk/,/Drive Type/' | grep -PwiB10 'Protocol[\S\s]+SATA' | grep -wi "State" | awk '{print $3}'))
        for phy_state in ${physical_state[@]}
        do
            # Use -a or -o can only be used for connection to the multiple conditions []
            if [ "$phy_state" != "Ready" -a "$phy_state" != "Optimal" -a "$phy_state" != "Hot" ]
            then
                # Restore Raid background tasks
                resume_bt
                local error_code=4
                local description="physical_disk_state is $phy_state, HBA ${cid_index} physical_disk_state is abnormal. $resume_res"
                error_func $error_code "${description[*]}"
            fi
        done
    elif [[ "$raid_type" == "pmc" ]]
    then
        # Check the background task
        local background_check_field=$("$arcconf" getstatus ${cid_index} | grep -wi "Current operation")
        if [ -n "$background_check_field" ]
        then
            local background_check=$(echo "$background_check_field" | egrep -wi "None")
            if [ -z "$background_check" ]
            then
                echo -e "\033[0;31m Error 4: $background_check_field, background task is exist under PMC ${cid_index} raid_group \033[0m" | tee -a $error_log
            fi
        fi
        # Check the state of controller
        local controller_check_field=$("$arcconf" getconfig ${cid_index} ad | grep -wi "Controller Status")
        if [ -n "$controller_check_field" ]
        then
            local controller_check=$(echo "$controller_check_field" | egrep -wi "Optimal")
            if [ -z "$controller_check" ]
            then
                # Restore Raid background tasks
                resume_bt
                local error_code=4
                local description="$controller_check_field, PMC ${cid_index} Controller is abnormal. $resume_res"
                error_func $error_code "${description[*]}"
            fi
        fi
        # Check all the virtual disk
        local virtual_state=($("$arcconf" getconfig ${cid_index} ar | grep -wiA5 "Array Number" | grep -wi "Status" | awk '{print $NF}'))
        for state in ${virtual_state[@]}
        do
            if [[ "$state" != "Ok" ]]
            then
                # Restore Raid background tasks
                resume_bt
                local error_code=4
                local description="virtual_disk_state is $state, PMC ${cid_index} virtual_disk_state is abnormal. $resume_res"
                error_func $error_code "${description[*]}"
            fi
        done
    elif [[ "$raid_type" == "hiraid" ]]
    then
        # Check all the virtual disk
        local virtual_state=($("$hiraidadm" c${cid_index} show vdlist | grep -wiA30 -m 1 "VDID" | egrep -v "^-" | grep -vi "status"  | egrep -vi "normal[ ]+normal"))
        if [ -n "${virtual_state}" ]
        then
            local error_code=4
            local description="virtual_disk_state is $state, HIRAID ${cid_index} virtual_disk_state is abnormal. $resume_res"
            error_func $error_code "${description[*]}"
        fi
        # Check the state of controller
        local controller_number=$("$hiraidadm" show allctrl | grep -Pwi "Controllers\s+Number\s+=" | awk -F "=" '{print $NF}'| grep -Po "\b.*\b")
        local controller_id=($("$hiraidadm" show allctrl | grep -Pwi "Controller\s+Id" | awk -F '|' '{print $NF}' | grep -Po "\b.*\b"))
        if [[ "$controller_number" -ne "${#controller_id[@]}" ]]
        then
            local error_code=4
            local description="HIRAID Controller is abnormal. $resume_res"
            error_func $error_code "${description[*]}"
        fi
    fi
    return 0
}


# Check whether the raid card support
check_raid()
{
    echo -e "\033[0;34m Raid Type is checking... \033[0m"
    # set Raid flag
    megaraid_flag=0
    hiraid_flag=0
    pmc_flag=0

    # Read the version file support raid card information
    support_raid_infos=($(cat $currentdir/version.xml | grep "<ObjectID>" | sed -e 's/\///g' | awk -F "<ObjectID>" '{print $2}' | sed -e 's/;/ /g'))

    # Get all the megaraid card number
    MEGAR_CID=($("$storclitool" /call show | grep "Controller ="| grep -Eo "[0-9]+"))
    for megar_cid in ${MEGAR_CID[@]}
    do
        # Out of 3008
        local megar_name=$("$storclitool" /c${megar_cid} show | grep -wi "Product Name" | awk -F "=" '{print $2}' | sed 's/ //g')
        [ -n "$(echo $megar_name | grep -o '3008')" ] && continue
        echo -e "\033[0;36m     Megaraid $megar_cid is found \033[0m" | tee -a $upgrade_log
        megaraid_flag=1
        # Obtain the corresponding raid card VID DID SVID SDID
        vdss=(vid did svid sdid)
        megar_vdss_raw=($("$storclitool" /c${megar_cid} show | egrep -w "Vendor Id|Device Id|SubVendor Id|SubDevice Id" | awk '{print $NF}'))
        for ((i=0;i<${#megar_vdss_raw[@]};i++))
        do
            local length=$(echo ${#megar_vdss_raw[$i]})
            if [[ "$length" == "5" ]]
            then
                eval ${vdss[$i]}=$(echo "${megar_vdss_raw[$i]}" | sed 's/0x/0x0/')
            elif [[ "$length" == "4" ]]
            then
                eval ${vdss[$i]}=$(echo "${megar_vdss_raw[$i]}" | sed 's/0x/0x00/')
            elif [[ "$length" == "3" ]]
            then
                eval ${vdss[$i]}=$(echo "${megar_vdss_raw[$i]}" | sed 's/0x/0x000/')
            else
                eval ${vdss[$i]}="${megar_vdss_raw[$i]}"
            fi
        done
        raid_identify_megar="$vid:$did:$svid:$sdid"
        match_raid=$(echo "${support_raid_infos[@]}" | grep -wi "$raid_identify_megar")
        if [ -z "$match_raid" ]
        then
            local error_code=3
            local description="Megaraid controller Numbers for $megar_cid card does not support"
            error_func $error_code "${description[*]}"
        fi
    done

    # HBA2308 card use sas2ircu tools, 2308 don't match the arm
    raidcard=$(lspci | grep LSI | awk -F 'Symbios Logic' '{print $2}' | awk '{print $1}')
    if [[ "$raidcard" == "SAS2308" ]] && [ -n "${x86_env}" ]
    then
        sas3="$testtool/sas2ircu"
    fi
    # Get all the HBA card number
    HBA_CID=($("$sas3" list | grep -A5 "Index" | awk '{print $1}' | grep -Ew "[0-9]+"))
    for hba_cid in ${HBA_CID[@]}
    do
        echo -e "\033[0;36m     HBA $hba_cid is found \033[0m" | tee -a $upgrade_log
        # Obtain the corresponding raid card VID DID SVID SDID
        vdss=(vid did svid sdid)
        hba_vdss_raw=($("$sas3" list | grep -w "${hba_cid}" | awk '{print $3,$4,$6,$7}' | sed -e 's/h//g'))
        for ((i=0;i<${#hba_vdss_raw[@]};i++))
        do
            local length=$(echo ${#hba_vdss_raw[$i]})
            if [[ "$length" == "1" ]]
            then
                eval ${vdss[$i]}=$(echo "${hba_vdss_raw[$i]}" | sed 's/^/000/')
            elif [[ "$length" == "2" ]]
            then
                eval ${vdss[$i]}=$(echo "${hba_vdss_raw[$i]}" | sed 's/^/00/')
            elif [[ "$length" == "3" ]]
            then
                eval ${vdss[$i]}=$(echo "${hba_vdss_raw[$i]}" | sed 's/^/0/')
            else
                eval ${vdss[$i]}="${hba_vdss_raw[$i]}"
            fi
        done
        raid_identify_hba="0x$vid:0x$did:0x$svid:0x$sdid"
        match_raid=$(echo "${support_raid_infos[@]}" | grep -wi "$raid_identify_hba")
        if [ -z "$match_raid" ]
        then
            local error_code=3
            local description="HBA controller Numbers for $hba_cid card does not support"
            error_func $error_code "${description[*]}"
        fi
    done

    # Obtain all PMC card bus number
    all_pmc=($(lspci | grep -i "Adaptec" | awk '{print $1}'))
    for check_pmc in ${all_pmc[@]}
    do
        echo -e "\033[0;36m     PMC $check_pmc is found \033[0m" | tee -a $upgrade_log
        pmc_flag=1
        # Obtain the corresponding raid card VID DID SVID SDID
        vid=$(lspci -s ${check_pmc} -x | sed -n 2p | awk '{print $3$2}' | sed 's/^/0x/')
        did=$(lspci -s ${check_pmc} -x | sed -n 2p | awk '{print $5$4}' | sed 's/^/0x/')
        svid=$(lspci -s ${check_pmc} -x | sed -n 4p | awk '{print $15$14}' | sed 's/^/0x/')
        sdid=$(lspci -s ${check_pmc} -x | sed -n 4p | awk '{print $17$16}' | sed 's/^/0x/')
        raid_identify_pmc="$vid:$did:$svid:$sdid"
        match_raid=$(echo "${support_raid_infos[@]}" | grep -wi "$raid_identify_pmc")
        check_pmc_exist=$("$arcconf" list | egrep -io "Controller [0-9]+" | egrep -o "[0-9]+")
        if [ -z "$match_raid" ] && [ -n "$check_pmc_exist" ]
        then
            local error_code=3
            local description="PMC bus numbers for $check_pmc card does not support"
            error_func $error_code "${description[*]}"
        fi
        echo -e "\033[0;36m     PMC $raid_identify_pmc is found \033[0m" | tee -a $upgrade_log
    done

    [ -z "$arm_env" ] && return 0
    # Get all the hiraid card number
    HIRAID_CID=($("$hiraidadm" show allctrl | grep "Controller Id" | grep -Eo "[0-9]+"))
    for hiraid_cid in ${HIRAID_CID[@]}
    do
        hiraid_flag=1
        # Obtain the corresponding raid card VID DID SVID SDID
        hiraid_vdss_info="$("$hiraidadm" c${hiraid_cid} show status)"
        vid="0x"$(echo "$hiraid_vdss_info"| grep -w "Vendor Id" | awk -F "|" '{print $NF}' | grep -Po "\b.*\b")
        did="0x"$(echo "$hiraid_vdss_info"| grep -w "Device Id" | awk -F "|" '{print $NF}'  | grep -Po "\b.*\b")
        svid="0x"$(echo "$hiraid_vdss_info"| grep -w "SubVendor Id" | awk -F "|" '{print $NF}' | grep -Po "\b.*\b")
        sdid="$(echo "$hiraid_vdss_info"| grep -w "SubDevice Id" | awk -F "|" '{print $NF}' | grep -Po "\b.*\b")"
        sdid="0x"${sdid:1}
        raid_identify_hiraid="$vid:$did:$svid:$sdid"
        match_raid=$(echo "${support_raid_infos[@]}" | grep -wi "$raid_identify_hiraid")
        if [ -z "$match_raid" ]
        then
            local error_code=3
            local description="Hiraid controller Numbers for $hiraid_cid card does not support"
            error_func $error_code "${description[*]}"
        fi
        echo -e "\033[0;36m     Hiraid $hiraid_cid is found \033[0m" | tee -a $upgrade_log
    done
    return 0
}


# Check the fw file
check_firmware()
{
    bin_fw_list=($(cat $currentdir/version.xml | grep "<FileName>" | sed -e 's/\///g' | awk -F "<FileName>" '{print $2}' | sed -e 's/,/ /g'))
    for fw_name in ${bin_fw_list[@]}
    do
        findfw=$(ls $currentdir/fw | grep "$fw_name")
        if [ -z "$findfw" ]
        then
            local error_code=2
            local description="Firmware or configure file invalid"
            error_func $error_code "${description[*]}"
        fi
    done
}


# Tool to assign permissions
add_permission()
{
    tools=($(ls "$testtool"/))
    for tool in ${tools[@]}
    do
        chmod +x "$testtool"/"$tool"
    done
}


# Check the raid driver
check_raid_drive()
{
    echo -e "\033[0;34m Raid drive is checking... \033[0m"
    local it_drive=$(lsmod | grep "mpt3sas")
    local megaraid_drive=$(lsmod | grep "megaraid_sas")

    # If no mpt3sas drive, the installation
    if [ -z "$it_drive" ]
    then
        local it_rpm="$currentdir/drives/$(ls $currentdir/drives | grep "mpt3sas")"
        rpm -Uvh $it_rpm
        modprobe mpt3sas
    fi
    # If no megaraid_sas drive, the installation
    if [ -z "$megaraid_drive" ]
    then
        local megaraid_rpm="$currentdir/drives/$(ls $currentdir/drives | grep "megaraid_sas")"
        rpm -Uvh $megaraid_rpm
        modprobe megaraid_sas
    fi

    sleep 2
    # Check the raid drive again
    if [ -n "$(lsmod | grep "mpt3sas")" ] && [ -n "$(lsmod | grep "megaraid_sas")" ]
    then
        echo "$(log_time) raid drive installed successfully" >> $upgrade_log
    else
        local error_code=9
        local description="raid drive installed failure"
        error_func $error_code "${description[*]}"
    fi
    return 0
}


# Check the environment
check_env()
{
    echo -e "\033[0;34m Env is checking... \033[0m"
    x86_env=$(uname -a 2>/dev/null | grep -w "x86_64")
    arm_env=$(uname -a 2>/dev/null | grep -w "aarch64")
    pack_env=$(cat $currentdir/version.xml | grep "<ProcessorArchitecture>" | awk -F ">" '{print $2}' | awk -F "<" '{print $1}')
    if [ -n "${x86_env}" ] && [[ "$pack_env" == "x86" ]]
    then
        testtool="$currentdir/tools/tools_x86"
        hdparm="$testtool/hdparm"
        storclitool="$testtool/storcli64"
        arcconf="$testtool/arcconf"
        sas3="$testtool/sas3ircu"
        smartool="$testtool/smartctl"
        sg_scan="$testtool/sg_scan"
        sg_inq="$testtool/sg_inq"
    elif [ -n "${arm_env}" ] && [[ "$pack_env" == "ARM" ]]
    then
        testtool="$currentdir/tools/tools_arm"
        hdparm="$testtool/hdparm"
        storclitool="$testtool/storcli64"
        arcconf="$testtool/arcconf"
        sas3="$testtool/sas3ircu"
        smartool="$testtool/smartctl"
        sg_scan="$testtool/sg_scan"
        sg_inq="$testtool/sg_inq"
        hiraidadm="$testtool/hiraidadm"
    else
        local error_code=1
        local description="The script package and environment isn't matched"
        error_func $error_code "${description[*]}"
    fi
}


# main
main()
{
    currentdir="."
    upgrade_log="$currentdir/work.log"
    error_log="$currentdir/sata_error.log"
    resume_log="$currentdir/sata_resume.log"
    echo "date: $(log_time)" > $upgrade_log
    echo "date: $(log_time)" > $error_log
    echo "date: $(log_time)" > $resume_log
    [ -f "${currentdir}/result.xml" ] && rm -f ${currentdir}/result.xml
    echo -e "\033[0;33m The Firmware program runs began \033[0m" | tee -a $upgrade_log

    check_env

    # x86 environment load driver
    [ -n "${x86_env}" ] && check_raid_drive

    add_permission

    check_firmware

    check_raid

    # Megaraid
    if [ "$megaraid_flag" -eq 1 ]
    then
        echo "" > $currentdir/raid_drive_list.txt
        for megar_cid in ${MEGAR_CID[@]}
        do
            # Judge IT card and remove(High version storcli64 utilities that can identify 3008IR card, remove together here)
            local product_name=$("$storclitool" /c${megar_cid} show | grep -wi "Product Name" | awk '{print $NF}' | grep -Eo '3008|IT$')
            [ -n "$product_name" ] && continue
            
            # Get all the slot number
            local eid_slot_all=($("$storclitool" /c${megar_cid} show | awk '/PD LIST/,/EID=/' | grep -P "\d+:\d+" | grep -wi "SATA" | grep "^[0-9]" | awk '{print $1}'))
            for ((p=0;p<${#eid_slot_all[@]};p++))
            do
                echo -e "\033[0;34m ${eid_slot_all[$p]} is testing... \033[0m" | tee -a $upgrade_log

                check_raid_healthy "megaraid" $megar_cid

                check_disk_healthy "megaraid" $megar_cid
        
                megaraid_fw_update ${eid_slot_all[$p]} $megar_cid
            done
        done
    fi

    # Hiraid
    if [ -n "$arm_env" ] && [ "$hiraid_flag" -eq 1 ]
    then
      echo "" > $currentdir/raid_drive_list.txt
      hiraidadm_CID=($("$hiraidadm" show allctrl | grep "Controller Id" | grep -Eo "[0-9]+"))
      for cid in ${hiraidadm_CID[@]}
      do
          local E_s_all=($("$hiraidadm" c${cid} show pdlist | grep -w "SATA" | awk '{print $2,$3}' | sed 's/ /:/g'))
          for ((p=0;p<${#E_s_all[@]};p++))
          do
              echo -e "\033[0;34m ${E_s_all[$p]} is testing... \033[0m" | tee -a $upgrade_log

              check_raid_healthy "hiraid" $cid

              check_disk_healthy "hiraid" $cid

              hiraid_fw_update ${E_s_all[$p]} "$cid"
          done
      done
    fi

    # PMC
    if [ "$pmc_flag" -eq 1 ]
    then
        echo "" > $currentdir/pmc_drive_list.txt
        # Obtain all PMC card number
        PMC_CID=($("$arcconf" list | egrep -io "Controller [0-9]+" | egrep -o "[0-9]+"))
        for pmc_cid in ${PMC_CID[@]}
        do
            # 1 : 8060，0 : not 8060
            local type_feature=0
            local check_type=$("$arcconf" list | grep -i "Controller $pmc_cid" | grep "8060")
            [ -n "$check_type" ] && local type_feature=1

            # Get all the slot number(e.g: 0,1 0,2)
            local pmc_all_disks=($($arcconf list ${pmc_cid} | grep -P "\d+,\d+" | grep -vi "Not Applicable" | egrep -o "[0-9]+,[0-9]+"))
            # Get all the slot number of SATA disk
            local specified_disks=($($arcconf list ${pmc_cid} | grep -P "\d+,\d+" | grep -wi "SATA" | grep -vi "Not Applicable" | egrep -o "[0-9]+,[0-9]+"))
            for ((num=0;num<${#specified_disks[@]};num++))
            do
                echo -e "\033[0;34m ${specified_disks[$num]} is testing... \033[0m" | tee -a $upgrade_log

                check_raid_healthy "pmc" $pmc_cid

                check_disk_healthy "pmc" $pmc_cid "${pmc_all_disks[*]}" $type_feature
        
                pmc_fw_update ${specified_disks[$num]} $pmc_cid $type_feature
            done
        done
    fi

    # HBA&PCH
    # Get sg device and remove virtual
    sg_all_src=($("$sg_scan" | awk -F ":" '{print $1}'))
    for temp in ${sg_all_src[@]}
    do
        [ -z "$($sg_scan -i | grep -wA1 $temp | grep -Ei "Virtual|USB")" ] && sg_all=("${sg_all[@]}" ${temp})
    done
    
    # Remove after the raid set of logical drive
    for item in ${sg_all[@]}
    do
        local sg_type=$("$sg_inq" $item | grep -wi "type" | awk '{print $NF}' | grep -wi "disk")
        local disk_sata=$("$sg_inq" $item | grep -wi "Vendor identification" | awk '{print $NF}' | grep -wi "ATA")
        local disk_identify1=$("$sg_inq" $item | grep -wi "Product identification" | awk -F ":" '{print $2}' | grep -Po "\b.*\b" | egrep -i "Logical|HW-SAS|AVAGO|LSI")
        if [ -n "$sg_type" ] && [ -n "$disk_sata" ] && [ -z "$disk_identify1" ]
        then
            disk_all=("${disk_all[@]}" ${item})
        fi
    done
    echo "" > $currentdir/direct_drive_list.txt
    for disk in ${disk_all[@]}
    do
        echo -e "\033[0;34m $disk is testing... \033[0m" | tee -a $upgrade_log

        for hba_cid in ${HBA_CID[@]}
        do
            check_raid_healthy "hba" $hba_cid
        done

        # Parameter cid is just a placeholder
        check_disk_healthy "hba" "cid" "${disk_all[*]}"

        pch_fw_update $disk
    done

    # Restore Raid background tasks
    resume_bt
    local error_code=0
    local description="The Firmware program runs finished. $resume_res"
    error_func $error_code "${description[*]}"
}

main

