#!/bin/sh

##############################################################
# N9K SSD firmware update script
#
# The Micron C400 SSDs suffer from a bug where it gets hung 
# after 80+ days of uptime. To fix this Micron gave a workaround
# firmware where the firmware will reload itself when it encounters
# the hung condition.
#
# This script will check whether the SSD Model is C400,
# and if its firmware version is not 08MH, it will
# update its firmware. 
#
##############################################################
#

. /etc/init.d/mod_ins/module-load-functions

BOOTFLASH_DEV=/dev/sda
HDPARM=/sbin/hdparm
HDPARM_IDENTIFY="${HDPARM} -i ${BOOTFLASH_DEV}"
SSD_FIRMWARE_FILE=/isanboot/bin/images/64GMLC.bin
UPDATED_SSD_FW_VER="0AMH"
AFFECTED_SSD_TYPE="C400"
HDPARM_FWUPDATE="${HDPARM} --please-destroy-my-drive --yes-i-know-what-i-am-doing --fwdownload"

check_ssd() {
    if [ -b ${BOOTFLASH_DEV} ] && [ -O ${BOOTFLASH_DEV} ]; then
        echo "1"
    fi
}

# Parse hdparm -i | grep Model
# Model=C400-MTFDDAT064MAM, FwRev=E7M4, SerialNo=MSA171605JL
# field 2 is Model
# field 3 is FwRev
get_ssd_type() {
    
    local ssd_type
    ssd_type=$(${HDPARM_IDENTIFY} | grep Model | cut -d' ' -f2 |cut -d',' -f1 |cut -d '=' -f2 | tr '_' '-'| cut -d'-' -f1)
    echo ${ssd_type}
}
get_ssd_fw_ver() {

    local ssd_fw_ver
    ssd_fw_ver=$(${HDPARM_IDENTIFY} | grep Model | cut -d' ' -f3 |cut -d',' -f1 |cut -d '=' -f2)
    echo ${ssd_fw_ver}
}
    
dispay_ssd_details() {
    ${HDPARM_IDENTIFY} | grep Model
}

check_firmware_file() {
    if [ ! -f ${SSD_FIRMWARE_FILE} ]; then 
        echo "1"
    fi
}

do_firmware_update() {

    local ssd_fw_ver
    local fw_file=$1

    echo "Updating the SSD firmware ..."
    ${HDPARM_FWUPDATE} ${fw_file} ${BOOTFLASH_DEV}
    if [ $? -ne 0 ]; then
        boot_debug "HDPARM failed with error $?!!"
    fi
}

NO_UPDATE_MSG="Your SSD fimware is up to date."
NO_UPDATE_MSG_FOR_M550="Your SSD model doesnt require firmware update. Only SSD Model C400 requires firmware update"
UPDATE_MSG="Your SSD firmware needs update and will be upgraded."

main() {

    if [ -n "$IS_N3K" ]; then
        exit 0
    fi

    if [ -z "$(check_ssd)" ]; then
        boot_debug "SSD not found."
        exit -1 
    fi

    local ssd_type
    local ssd_fw_ver
    local force_update
    local fw_file
    local rc
    local force_fw_file
    
    if [ "$1" = "-f" ]; then
        force_update="y"
        force_fw_file=$2
        if [ -z "${force_fw_file}" ] || [ ! -f ${force_fw_file} ]; then
            boot_debug "Force SSD firmware file ${force_fw_file} not found."
            exit -1
        fi
    fi

    ssd_type="$(get_ssd_type)"
    ssd_fw_ver="$(get_ssd_fw_ver)"

    boot_debug "Checking SSD firmware ..."
    dispay_ssd_details
    boot_debug "SSD Model: ${ssd_type}"
    boot_debug "Current SSD Firmware Version: ${ssd_fw_ver}"

    if [ -z "${force_update}" ] && [ "${ssd_type}" != "${AFFECTED_SSD_TYPE}" ]; then
        boot_debug ${NO_UPDATE_MSG_FOR_M550}
        exit 0
    fi

    if [ -z "${force_update}" ] && [ "${ssd_fw_ver}" = "${UPDATED_SSD_FW_VER}" ]; then
        boot_debug ${NO_UPDATE_MSG}
        exit 0
    fi

    
    if [ -n "$(check_firmware_file)" ]; then
        boot_debug "SSD Firmware file ${SSD_FIRMWARE_FILE} required for upgrade is missing."
        exit -1
    fi

    boot_debug ${UPDATE_MSG}

    if [ -n "${force_update}" ]; then
        fw_file=${force_fw_file}
    else
        fw_file=${SSD_FIRMWARE_FILE}
    fi

    do_firmware_update ${fw_file}

    wait

    ssd_fw_ver="$(get_ssd_fw_ver)"

    dispay_ssd_details
    boot_debug "Current SSD Firmware is ${ssd_fw_ver}."

    if [ -n "${force_update}" ]; then
        boot_debug "SSD Firmware forced update done."
        exit 0
    fi 

    if [ $ssd_fw_ver = "${UPDATED_SSD_FW_VER}" ]; then
        boot_debug "SSD Firmware has been updated successfully."
    else
        boot_debug "SSD Firmware update failed. !!"
    fi

}


main $*
