From 096a0e1e1897431ac974573de007ed01d8aaaa15 Mon Sep 17 00:00:00 2001 From: Nazarii Hnydyn Date: Mon, 13 Apr 2020 18:12:16 +0300 Subject: [PATCH] [mellanox]: Add SSD FW update tool (#4352) * [mellanox]: Add SSD FW update tool. Signed-off-by: Nazarii Hnydyn * [mellanox]: Update SSD tool. Signed-off-by: Nazarii Hnydyn --- .../build_templates/sonic_debian_extension.j2 | 3 +- platform/mellanox/cpld.mk | 3 +- platform/mellanox/fw.mk | 17 +- platform/mellanox/hw-management-wd.mk | 3 +- platform/mellanox/issu-version.mk | 3 +- platform/mellanox/mlnx-ffb.mk | 2 + platform/mellanox/mlnx-fw-upgrade.j2 | 2 +- platform/mellanox/mlnx-ssd-fw-update.mk | 9 + platform/mellanox/mlnx-ssd-fw-update.sh | 727 ++++++++++++++++++ platform/mellanox/one-image.mk | 7 +- platform/mellanox/rules.mk | 1 + 11 files changed, 759 insertions(+), 18 deletions(-) create mode 100644 platform/mellanox/mlnx-ssd-fw-update.mk create mode 100755 platform/mellanox/mlnx-ssd-fw-update.sh diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index 157b8cd48e..d75e9ef754 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -358,13 +358,14 @@ sudo cp {{src}} $FILESYSTEM_ROOT/{{dst}} {% if sonic_asic_platform == "mellanox" %} sudo mkdir -p $FILESYSTEM_ROOT/etc/mlnx/cpld/ -sudo cp target/files/$MLNX_FW_FILE $FILESYSTEM_ROOT/etc/mlnx/fw-SPC.mfa +sudo cp target/files/$MLNX_SPC_FW_FILE $FILESYSTEM_ROOT/etc/mlnx/fw-SPC.mfa for MLNX_CPLD_ARCHIVE in $MLNX_CPLD_ARCHIVES; do sudo cp target/files/$MLNX_CPLD_ARCHIVE $FILESYSTEM_ROOT/etc/mlnx/cpld/ done sudo cp target/files/$ISSU_VERSION_FILE $FILESYSTEM_ROOT/etc/mlnx/issu-version sudo cp target/files/$MLNX_FFB_SCRIPT $FILESYSTEM_ROOT/usr/bin/mlnx-ffb.sh sudo cp target/files/$HW_MANAGEMENT_WD_SCRIPT $FILESYSTEM_ROOT/usr/bin/$HW_MANAGEMENT_WD_SCRIPT +sudo cp target/files/$MLNX_SSD_FW_UPDATE $FILESYSTEM_ROOT/usr/bin/$MLNX_SSD_FW_UPDATE j2 platform/mellanox/mlnx-fw-upgrade.j2 | sudo tee $FILESYSTEM_ROOT/usr/bin/mlnx-fw-upgrade.sh sudo chmod 755 $FILESYSTEM_ROOT/usr/bin/mlnx-fw-upgrade.sh diff --git a/platform/mellanox/cpld.mk b/platform/mellanox/cpld.mk index 0a03b3c54a..385308e004 100644 --- a/platform/mellanox/cpld.mk +++ b/platform/mellanox/cpld.mk @@ -4,6 +4,7 @@ MLNX_SN2700_CPLD_ARCHIVE = msn2700_cpld.tar.gz $(MLNX_SN2700_CPLD_ARCHIVE)_PATH = platform/mellanox/cpld/ SONIC_COPY_FILES += $(MLNX_SN2700_CPLD_ARCHIVE) -MLNX_CPLD_ARCHIVES += $(MLNX_SN2700_CPLD_ARCHIVE) +MLNX_CPLD_ARCHIVES = $(MLNX_SN2700_CPLD_ARCHIVE) +MLNX_FILES += $(MLNX_CPLD_ARCHIVES) export MLNX_CPLD_ARCHIVES diff --git a/platform/mellanox/fw.mk b/platform/mellanox/fw.mk index d6a0b4c8ce..6365906016 100644 --- a/platform/mellanox/fw.mk +++ b/platform/mellanox/fw.mk @@ -1,9 +1,12 @@ -# mellanox firmware +# mellanox asic firmware -MLNX_FW_VERSION = 13.2000.1658 -MLNX_FW_FILE = fw-SPC-rel-$(subst .,_,$(MLNX_FW_VERSION))-EVB.mfa -$(MLNX_FW_FILE)_URL = $(MLNX_SDK_BASE_URL)/$(MLNX_FW_FILE) -SONIC_ONLINE_FILES += $(MLNX_FW_FILE) +MLNX_SPC_FW_VERSION = 13.2000.1658 +MLNX_SPC_FW_FILE = fw-SPC-rel-$(subst .,_,$(MLNX_SPC_FW_VERSION))-EVB.mfa +$(MLNX_SPC_FW_FILE)_URL = $(MLNX_SDK_BASE_URL)/$(MLNX_SPC_FW_FILE) +SONIC_ONLINE_FILES += $(MLNX_SPC_FW_FILE) -export MLNX_FW_VERSION -export MLNX_FW_FILE +MLNX_FW_FILES = $(MLNX_SPC_FW_FILE) +MLNX_FILES += $(MLNX_FW_FILES) + +export MLNX_SPC_FW_VERSION +export MLNX_SPC_FW_FILE diff --git a/platform/mellanox/hw-management-wd.mk b/platform/mellanox/hw-management-wd.mk index d4e0c78261..a0f3271fa7 100644 --- a/platform/mellanox/hw-management-wd.mk +++ b/platform/mellanox/hw-management-wd.mk @@ -4,5 +4,6 @@ HW_MANAGEMENT_WD_SCRIPT = hw-management-wd.sh $(HW_MANAGEMENT_WD_SCRIPT)_PATH = platform/mellanox/ SONIC_COPY_FILES += $(HW_MANAGEMENT_WD_SCRIPT) -export HW_MANAGEMENT_WD_SCRIPT +MLNX_FILES += $(HW_MANAGEMENT_WD_SCRIPT) +export HW_MANAGEMENT_WD_SCRIPT diff --git a/platform/mellanox/issu-version.mk b/platform/mellanox/issu-version.mk index c7ae4296ab..db368ffd8c 100644 --- a/platform/mellanox/issu-version.mk +++ b/platform/mellanox/issu-version.mk @@ -5,5 +5,6 @@ $(ISSU_VERSION_FILE)_SRC_PATH = $(PLATFORM_PATH)/issu-version $(ISSU_VERSION_FILE)_DEPENDS += $(APPLIBS) SONIC_MAKE_FILES += $(ISSU_VERSION_FILE) -export ISSU_VERSION_FILE +MLNX_FILES += $(ISSU_VERSION_FILE) +export ISSU_VERSION_FILE diff --git a/platform/mellanox/mlnx-ffb.mk b/platform/mellanox/mlnx-ffb.mk index dabb995a36..82d50b7ae3 100755 --- a/platform/mellanox/mlnx-ffb.mk +++ b/platform/mellanox/mlnx-ffb.mk @@ -4,4 +4,6 @@ MLNX_FFB_SCRIPT = mlnx-ffb.sh $(MLNX_FFB_SCRIPT)_PATH = platform/mellanox/ SONIC_COPY_FILES += $(MLNX_FFB_SCRIPT) +MLNX_FILES += $(MLNX_FFB_SCRIPT) + export MLNX_FFB_SCRIPT diff --git a/platform/mellanox/mlnx-fw-upgrade.j2 b/platform/mellanox/mlnx-fw-upgrade.j2 index efe2728afe..599fc7bcab 100755 --- a/platform/mellanox/mlnx-fw-upgrade.j2 +++ b/platform/mellanox/mlnx-fw-upgrade.j2 @@ -24,7 +24,7 @@ declare -r BURN_CMD="mlxfwmanager -u -f -y" declare -r FW_FILE="/etc/mlnx/fw-SPC.mfa" declare -r QUERY_FILE="/tmp/mlxfwmanager-query.txt" -declare -r FW_REQUIRED="{{ MLNX_FW_VERSION }}" +declare -r FW_REQUIRED="{{ MLNX_SPC_FW_VERSION }}" IMAGE_UPGRADE="${NO_PARAM}" CPLD_UPGRADE="${NO_PARAM}" diff --git a/platform/mellanox/mlnx-ssd-fw-update.mk b/platform/mellanox/mlnx-ssd-fw-update.mk new file mode 100644 index 0000000000..f932e57d25 --- /dev/null +++ b/platform/mellanox/mlnx-ssd-fw-update.mk @@ -0,0 +1,9 @@ +# ssd update tool + +MLNX_SSD_FW_UPDATE = mlnx-ssd-fw-update.sh +$(MLNX_SSD_FW_UPDATE)_PATH = platform/mellanox/ +SONIC_COPY_FILES += $(MLNX_SSD_FW_UPDATE) + +MLNX_FILES += $(MLNX_SSD_FW_UPDATE) + +export MLNX_SSD_FW_UPDATE diff --git a/platform/mellanox/mlnx-ssd-fw-update.sh b/platform/mellanox/mlnx-ssd-fw-update.sh new file mode 100755 index 0000000000..5163c8e7f8 --- /dev/null +++ b/platform/mellanox/mlnx-ssd-fw-update.sh @@ -0,0 +1,727 @@ +#!/bin/bash +######################################################################## +# Copyright (c) 2020 Mellanox Technologies. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the names of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# Alternatively, this software may be distributed under the terms of the +# GNU General Public License ("GPL") version 2 as published by the Free +# Software Foundation. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +#==============================================================================# +#= Global variable # +#= +#===== +VERSION="1.3" +#===== +SWITCH_SSD_DEV="/dev/sda" +UTIL_TITLE="This is MLNX SSD firmware update utility to read and write SSD FW. Version ${VERSION}" +DEPENDECIES=("smartctl" "sha256sum" "tar" "/bin/bash" "gpg" "sed" "realpath" "dirname") +TRUE="0" +FALSE="1" +ERR_MSG="ERR_MSG" +INI_PREFIX="ini_section_" +PUBLIC_CERT_NAME="trusted.gpg" +CHECKSUM_NAME="checksum" +SCRIPT_MODE="RELESE" # RELESE -or- DEBUG +DEBUG_MSG="DEBUG" # remove all instance after script is ready. +#===== +PKG_EXTRACTED=$FALSE +LOGGER_UTIL=$FALSE +SSD_FW_VER="" +SSD_DEVICE_MODEL="" +SSD_SERIAL="" +SSD_SIZE="" +SECTIONS=() +#===== +ARG_IMAGE_FLAG=$FALSE +ARG_IMAGE_VAL="" +ARG_QUERY_FLAG=$FALSE +ARG_YES_FLAG=$FALSE +ARG_POWER_CYCLE_FLAG=$FALSE +ARG_HELP_FLAG=$FALSE +ARG_VERSION_FLAG=$FALSE +ARG_PACKAGE_INFO_FLAG=$FALSE +ARG_UPDATE_FLAG=$FALSE + + + +#==============================================================================# +#= usage function. # +#= +function init_script() { +# check if logger utility supported + if [ -x "$(command -v logger)" ]; then + LOGGER_UTIL=$TRUE + else + LOGGER_UTIL=$FALSE + fi +} + +#==============================================================================# +#= usage function. # +#= +function usage() { + echo + echo -e "$UTIL_TITLE" + echo + echo -e "Usage:" + echo -e "\tmlnx_ssd_fw_update.sh [OPTION]" + echo -e "Commands:" + echo -e "\t-i, --image\t\t Path to SSD FW package" + echo -e "\t-q, --query\t\t Print SSD information (SSD model, serial number, version and size)" + echo -e "\t\t\t\t Combined with image, comparison is made if update is required" + echo -e "\t-p, --package-info\t Get package info" + echo -e "\t-u, --update\t\t Upgrade firmware" + echo -e "\t-y --yes\t\t Assume \"yes\" to all questions" + echo -e "\t-V, --version\t\t Print utility version" + echo -e "\t-h, --help\t\t Show this usage" + echo -e "\t --power-cycle\t Execute power cycle at completion, even if not required" + echo + echo -e "Example:" + echo -e "\tmlnx_ssd_fw_update.sh -q" + echo -e "\tmlnx_ssd_fw_update.sh -q -i mlnx_ssd_fw_package.pkg" + echo -e "\tmlnx_ssd_fw_update.sh -p -i mlnx_ssd_fw_package.pkg" + echo -e "\tmlnx_ssd_fw_update.sh -u -i mlnx_ssd_fw_package.pkg" + echo +} + +#==============================================================================# +#= Log function. # +#= +function LOG_MSG() { + if [ $# -gt 0 ]; then + LOG_STR=$1 + if [[ $# -eq 1 ]]; then + [[ "$LOGGER_UTIL" == "$TRUE" && "$LOG_STR" != "" ]] && logger -t mlnx_ssd_fw_update.sh -p user.notice $(echo "$LOG_STR" | sed 's/\\t//g') + echo -e "$LOG_STR" + elif [[ $# -eq 2 && "$2" == "$ERR_MSG" ]]; then + [[ "$LOGGER_UTIL" == "$TRUE" && "$LOG_STR" != "" ]] && logger -t mlnx_ssd_fw_update.sh -p user.err $(echo "$LOG_STR" | sed 's/\\t//g') + echo -e "$LOG_STR" + elif [[ $# -eq 2 && "$2" == "$SCRIPT_MODE" ]]; then + echo -e "DBG: $LOG_STR" + fi + fi +} + +#==============================================================================# +#= Log function. # +#= +function LOG_MSG_AND_EXIT() { + LOG_MSG "$@" "$ERR_MSG" + erase_extract_package "$extraction_path" + LOG_MSG "Exiting..." + exit 1 +} + +#==============================================================================# +#= This function check if given argument is valid and return boolean result. # +#= +function check_usage() { + local argument_count=$# + + LOG_MSG "Number of argument:$argument_count" ${DEBUG_MSG} + + if [ $# -eq 0 ]; then + LOG_MSG "Error: false usage given." + usage + exit 1 + fi + + while [[ $# -gt 0 ]] + do + key="$1" + + case $key in + -i|--image) + ARG_IMAGE_FLAG=$TRUE + ARG_IMAGE_VAL="$2" + shift # past argument + shift # past value + ;; + -q|--query) + ARG_QUERY_FLAG=$TRUE + shift # past argument + ;; + -y|--yes) + ARG_YES_FLAG=$TRUE + shift # past argument + ;; + -h|--help) + ARG_HELP_FLAG=$TRUE + shift # past argument + ;; + -V|--version) + ARG_VERSION_FLAG=$TRUE + shift # past argument + ;; + -u|--update) + ARG_UPDATE_FLAG=$TRUE + shift # past argument + ;; + -p|--package-info) + ARG_PACKAGE_INFO_FLAG=$TRUE + shift # past argument + ;; + --power-cycle) + ARG_POWER_CYCLE_FLAG=$TRUE + shift # past argument + ;; + *) + LOG_MSG "Error: false usage given." + usage + exit 1 + ;; + esac + done + + if [[ ("$ARG_IMAGE_FLAG" == "$TRUE" && ( $argument_count -lt 3 )) || + ("$ARG_IMAGE_FLAG" == "$TRUE" && ( $argument_count -gt 5 )) || + ("$ARG_PACKAGE_INFO_FLAG" == "$TRUE" && ( $argument_count -ne 3 )) || + ("$ARG_QUERY_FLAG" == "$TRUE" && ( $argument_count -lt 1 )) || + ("$ARG_QUERY_FLAG" == "$TRUE" && ( $argument_count -gt 3 )) || + ("$ARG_HELP_FLAG" == "$TRUE" && ( $argument_count -gt 1 )) || + ("$ARG_VERSION_FLAG" == "$TRUE" && ( $argument_count -gt 1 )) || + ("$ARG_IMAGE_FLAG" == "$TRUE" && "$ARG_IMAGE_VAL" == "") || + ("$ARG_UPDATE_FLAG" == "$TRUE" && "$ARG_IMAGE_FLAG" == "$FALSE") || + ("$ARG_PACKAGE_INFO_FLAG" == "$TRUE" && "$ARG_IMAGE_FLAG" == "$FALSE") || + ("$ARG_POWER_CYCLE_FLAG" == "$TRUE" && "$ARG_UPDATE_FLAG" == "$FALSE") || + ("$ARG_UPDATE_FLAG" == "$TRUE" && "$ARG_PACKAGE_INFO_FLAG" == "$TRUE") ]]; then + + LOG_MSG "Error: false usage given." + usage + exit 1 + fi + +### Debug message remove when script is done. + LOG_MSG "ARG_IMAGE_FLAG = ${ARG_IMAGE_FLAG}" ${DEBUG_MSG} + LOG_MSG "ARG_IMAGE_VAL = ${ARG_IMAGE_VAL}" ${DEBUG_MSG} + LOG_MSG "ARG_QUERY_FLAG = ${ARG_QUERY_FLAG}" ${DEBUG_MSG} + LOG_MSG "ARG_YES_FLAG = ${ARG_YES_FLAG}" ${DEBUG_MSG} + LOG_MSG "ARG_HELP_FLAG = ${ARG_HELP_FLAG}" ${DEBUG_MSG} + LOG_MSG "ARG_VERSION_FLAG = ${ARG_VERSION_FLAG}" ${DEBUG_MSG} + LOG_MSG "ARG_PACKAGE_INFO_FLAG = ${ARG_PACKAGE_INFO_FLAG}" ${DEBUG_MSG} + LOG_MSG "ARG_POWER_CYCLE_FLAG = ${ARG_POWER_CYCLE_FLAG}" ${DEBUG_MSG} + +} + +#==============================================================================# +# This function return SSD fw version using hdparm utility # +# +function get_ssd_fw_version() { + [ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; } + + local device_fw_version + device_fw_version=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "Firmware Version: +\K[^,]+") + LOG_MSG "device_fw_version: $device_fw_version" ${DEBUG_MSG} + eval $1='$device_fw_version' +} + +#==============================================================================# +# This function return SSD device model using hdparm utility # +# +function get_ssd_device_model() { + [ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; } + + local device_model_name + device_model_name=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "Device Model: +\K[^,]+") + LOG_MSG "device_model_name: $device_model_name" ${DEBUG_MSG} + eval $1='$device_model_name' +} + +#==============================================================================# +# This function return SSD size using hdparm utility # +# +function get_ssd_size() { + [ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; } + + local device_size + device_size=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "User Capacity:.+bytes \[\K[^ ]+") + LOG_MSG "device_size: $device_size" ${DEBUG_MSG} + eval $1='$device_size' +} + +#==============================================================================# +# This function return SSD serial using hdparm utility # +# +function get_ssd_serial() { + [ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; } + + local device_serial + device_serial=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "Serial Number: +\K[^,]+") + LOG_MSG "device_serial: $device_serial" ${DEBUG_MSG} + eval $1='$device_serial' +} + +#==============================================================================# +#= This function check if given argument is valid and return boolean result. # +#= +function get_ssd_info() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + get_ssd_fw_version SSD_FW_VER + get_ssd_device_model SSD_DEVICE_MODEL + get_ssd_serial SSD_SERIAL + get_ssd_size SSD_SIZE +} + +#==============================================================================# +#= This function check if given argument is valid and return boolean result. # +#= +function check_tool_dependencies() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + for i in "${!DEPENDECIES[@]}" + do + if [ ! -x "$(command -v ${DEPENDECIES[$i]})" ]; then + LOG_MSG_AND_EXIT "Error: This tool require the following utils to be installed ${DEPENDECIES[$i]}" + fi + done +} + +#==============================================================================# +#= This function parse package ini file and declare it attributes # +#= +function ini_parser { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + + local filename="$1" + LOG_MSG "filename:$filename" ${DEBUG_MSG} + + shopt -p extglob &> /dev/null + CHANGE_EXTGLOB=$? + if [ $CHANGE_EXTGLOB = 1 ] + then + shopt -s extglob + fi + ini="$(<$filename)" # read the file + ini=${ini//$'\r'/} # remove linefeed i.e dos2unix + ini="${ini//[/\\[}" + ini="${ini//]/\\]}" + IFS=$'\n' && ini=( ${ini} ) # convert to line-array + ini=( ${ini[*]//\)/\\\)} ) # append / before any parenthesis + ini=( ${ini[*]//\(/\\\(} ) # append / before any parenthesis + ini=( ${ini[*]/#*([[:space:]]);*/} ) + ini=( ${ini[*]/#*([[:space:]])\#*/} ) + ini=( ${ini[*]/#+([[:space:]])/} ) # remove init whitespace + ini=( ${ini[*]/%+([[:space:]])/} ) # remove ending whitespace + ini=( ${ini[*]/*([[:space:]])=*([[:space:]])/=} ) # remove whitespace around = + ini=( ${ini[*]/#\\[/\}$'\n'"$INI_PREFIX"} ) # set section prefix + ini=( ${ini[*]/%\\]/ \(} ) # convert text2function (1) + ini=( ${ini[*]/=/=\( } ) # convert item to array + ini=( ${ini[*]/%/ \)} ) # close array parenthesis + ini=( ${ini[*]/%\\ \)/ \\} ) # the multiline trick + ini=( ${ini[*]/%\( \)/\(\) \{} ) # convert text2function (2) + ini=( ${ini[*]/%\} \)/\}} ) # remove extra parenthesis + ini=( ${ini[*]/%\{/\{$'\n''ini_unset ${FUNCNAME/#'$INI_PREFIX'}'$'\n'} ) # clean previous definition of section + ini[0]="" # remove first element + ini[${#ini[*]} + 1]='}' # add the last brace + eval "$(echo "${ini[*]}")" # eval the result + [ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: failed to parse package content." + SECTIONS="$(echo ${ini[*]} | grep -Po "$INI_PREFIX+\K[\w]+")" + if [ $CHANGE_EXTGLOB = 1 ] + then + shopt -u extglob + fi +} + +#==============================================================================# +#= This function unset parse ini section and variables # +#= +function ini_unset { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + SECTION=$1 + OLDIFS="$IFS" + IFS=' '$'\n' + if [ -z "$SECTION" ] + then + fun="$(declare -F)" + else + fun="$(declare -F $INI_PREFIX$SECTION)" + if [ -z "$fun" ] + then + echo "section $SECTION not found" 1>&2 + return + fi + fi + fun="${fun//declare -f/}" + for f in $fun; do + [ "${f#$INI_PREFIX}" == "${f}" ] && continue + item="$(declare -f ${f})" + item="${item##*\{}" # remove function definition + item="${item##*FUNCNAME*$INI_PREFIX\};}" # remove clear section + item="${item/\}}" # remove function close + item="${item%)*}" # remove everything after parenthesis + item="${item});" # add close parenthesis + vars="" + while [ "$item" != "" ] + do + newvar="${item%%=*}" # get item name + vars="$vars $newvar" # add name to collection + item="${item#*;}" # remove readed line + done + for var in $vars; do + unset $var + done + done + IFS="$OLDIFS" +} + +#==============================================================================# +#= This function check package signing and returns back true or false # +#= +function check_package_signing() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + + [ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; } + + local package_path=$1 + local checksum_unsigned_file="$package_path/$CHECKSUM_NAME" + local checksum_signed_file="$package_path/$CHECKSUM_NAME.sig" + local public_cert_file="$package_path/$PUBLIC_CERT_NAME" + +### Check if unsigned checksum file exists + [ ! -f "$checksum_unsigned_file" ] && LOG_MSG_AND_EXIT "Error: fail to find unsigned checksum file to verify package signing." + +### Check if signed checksum file exists + [ ! -f "$checksum_signed_file" ] && LOG_MSG_AND_EXIT "Error: fail to find sign checksum file to verify package signing." + +### Check if public key exists + [ ! -f "$public_cert_file" ] && LOG_MSG_AND_EXIT "Error: fail to find public certificate to verify package signing." + + + LOG_MSG "public_cert_file: ${public_cert_file}" ${DEBUG_MSG} + LOG_MSG "checksum_signed_file: ${checksum_signed_file}" ${DEBUG_MSG} + LOG_MSG "checksum_unsigned_file: ${checksum_unsigned_file}" ${DEBUG_MSG} + + gpg --keyring "$public_cert_file" --verify "$checksum_signed_file" "$checksum_unsigned_file" > /dev/null 2>&1 + [ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: fault package signing." + + LOG_MSG "cd into: ${package_path}" ${DEBUG_MSG} + cd $package_path > /dev/null 2>&1 + sha256sum -c $CHECKSUM_NAME > /dev/null 2>&1 + [ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: fault package SHA signing, file has been compromised" + LOG_MSG "backing back:" ${DEBUG_MSG} + cd - > /dev/null 2>&1 + LOG_MSG "exiting:" ${DEBUG_MSG} + +} + +#==============================================================================# +#= This function prints supported SSD from package ini # +#= +function string_supported_model() { + + local section=$1 + + if [[ ! -z "${Vendor[*]}" ]] && [[ ! -z "${SSD_FW_Model[*]}" ]] && [[ ! -z "${SSD_FW_Version[*]}" ]] \ + && [[ ! -z "${SSD_Size[*]}" ]] && [[ ! -z ${Shutdown_Policy[*]} ]]; then + printf 'o %-10s | %-30s | %-12s | %-6sGB | %-7s |\n' \ + "$( IFS=$'\n'; echo "${Vendor[@]}" )" "$( IFS=$'\n'; echo "${SSD_FW_Model[@]}" )" \ + "${SSD_FW_Version[@]}" "${SSD_Size[@]}" "${Shutdown_Policy[@],,}" + fi + +} + +#==============================================================================# +#= This function extract SSD FW package into /tmp # +#= +function extract_package() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + + local filename=$1 + LOG_MSG "filename:$filename" ${DEBUG_MSG} +### Check if file exists + [ ! -f $filename ] && LOG_MSG_AND_EXIT "Error: given file ($filename) not found." +### Check if tmp available + [ ! -d "/tmp" ] && LOG_MSG_AND_EXIT "Error: directory /tmp DOES NOT exists." + + local base_filename="${filename##*/}" + local folder_name="/tmp/""${base_filename%%.*}" + +### Check if full path available + if [ -d $folder_name ]; then + LOG_MSG "Path:$folder_name already exists, removing folder." ${DEBUG_MSG} + rm -rf ${folder_name} + [ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: folder:$folder_name is already in use and can't be overwrite, please remove it and retry." + fi + + mkdir ${folder_name} && tar xf ${filename} -C ${folder_name} --strip-components 1 --warning=no-timestamp > /dev/null 2>&1 + #tar -xf $filename --directory /tmp/ --warning=no-timestamp > /dev/null 2>&1 +### Check if untar succeed. + [ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: fail to extract given package ($filename)." + +### return the path file extraction is + # local base_filename="${filename##*/}" + # local folder_name="/tmp/""${base_filename%%.*}" + eval $2="$folder_name" + + PKG_EXTRACTED=$TRUE + + check_package_signing $folder_name + + LOG_MSG "successfully untar file." ${DEBUG_MSG} +} + +#==============================================================================# +#= This function extract SSD FW package into /tmp # +#= +function erase_extract_package() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + + [[ "$PKG_EXTRACTED" == "$FALSE" ]] && return + + local folder_name=$1 + + LOG_MSG "folder_name: $folder_name" ${DEBUG_MSG} + +### Check if folder exists + if [ ! -d "$folder_name" ]; then + LOG_MSG "Error: directory $folder_name DOES NOT exists." "$ERR_MSG" + LOG_MSG "Exiting..." + exit 1 + fi + rm -rf $folder_name +### Check if untar succeed. + if [ $? -ne 0 ]; then + LOG_MSG "Error: fail to delete $folder_name folder." "$ERR_MSG" + LOG_MSG "Exiting..." + exit 1 + fi + + PKG_EXTRACTED=$FALSE + LOG_MSG "successfully removed folder:$folder_name" ${DEBUG_MSG} +} + + +#==============================================================================# +#= This function returns back ini section array. +#= +function call_ini_section() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + + local ini_section=$1 + LOG_MSG "ini_section:$ini_section" ${DEBUG_MSG} + + [[ -z "$ini_section" ]] && LOG_MSG_AND_EXIT "Error: given INI section is null." + [[ -z "$(declare -F "$INI_PREFIX$ini_section")" ]] && LOG_MSG_AND_EXIT "Error: $ini_section section is missing in INI file." + + eval "$(echo "$INI_PREFIX$ini_section")" # call given section function. +} + +#==============================================================================# +#= This function prints ssd info +#= +function print_ssd_info() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + + local argument_count=$# + + if [ $argument_count -eq 2 ]; then + local newer_fw_version=$1 + local power_policy=$2 + LOG_MSG "Device Model\t\t : $SSD_DEVICE_MODEL" + LOG_MSG "Serial Number\t\t : $SSD_SERIAL" + LOG_MSG "User Capacity\t\t : $SSD_SIZE GB" + LOG_MSG "Current Firmware Version : $SSD_FW_VER" + LOG_MSG "Available Firmware Version : $Newer_FW_Version" + LOG_MSG "Power Cycle Required\t : $power_policy" + LOG_MSG "Upgrade Required\t : yes" + elif [ $argument_count -eq 1 ]; then + local _upgrade_require=$1 + LOG_MSG "Device Model\t : $SSD_DEVICE_MODEL" + LOG_MSG "Serial Number\t : $SSD_SERIAL" + LOG_MSG "User Capacity\t : $SSD_SIZE GB" + LOG_MSG "Firmware Version : $SSD_FW_VER" + LOG_MSG "Upgrade Required : $_upgrade_require" + else + LOG_MSG "Device Model\t : $SSD_DEVICE_MODEL" + LOG_MSG "Serial Number\t : $SSD_SERIAL" + LOG_MSG "User Capacity\t : $SSD_SIZE GB" + LOG_MSG "Firmware Version : $SSD_FW_VER" + fi +} + +# Main +# ------------------------------------------------------------------------------ +init_script +check_usage "$@" + +# show help +if [ $ARG_HELP_FLAG == $TRUE ]; then + usage + exit 0 +# show version +elif [ $ARG_VERSION_FLAG == $TRUE ]; then + echo $UTIL_TITLE + exit 0 +# show SSD info +elif [ $ARG_QUERY_FLAG == $TRUE ]; then + match_found=$FALSE + check_tool_dependencies + get_ssd_info + + if [ $ARG_IMAGE_FLAG == $TRUE ]; then + extract_package $ARG_IMAGE_VAL extraction_path + ini_parser "$extraction_path/list.ini" + + for section in $SECTIONS; do + if [[ $section != "main" ]]; then + call_ini_section $section + if [[ "$SSD_DEVICE_MODEL" == "$( IFS=$'\n'; echo "${SSD_FW_Model[@]}" )" ]] && \ + [[ "$SSD_FW_VER" == "${SSD_FW_Version[@]}" ]] && \ + [[ "$SSD_SIZE" == "${SSD_Size[@]}" ]]; then + + match_found=$TRUE + break + fi + ini_unset $section + fi + done + + erase_extract_package "$extraction_path" + if [[ "$match_found" == "$FALSE" ]]; then + #LOG_MSG "SSD FW upgrade not require, based on given package latest version is in used." + print_ssd_info "no" + echo -e "" + exit 0 + fi + fi + + if [[ "$match_found" == "$TRUE" ]]; then + print_ssd_info $Newer_FW_Version ${Shutdown_Policy[0],,} + erase_extract_package "$extraction_path" + else + print_ssd_info + fi + + echo -e "" + + exit 0 +# show package version +elif [ $ARG_PACKAGE_INFO_FLAG == $TRUE ]; then + check_tool_dependencies + extract_package $ARG_IMAGE_VAL extraction_path + # 2. check signing + ini_parser "$extraction_path/list.ini" + + call_ini_section "main" + LOG_MSG "Package Name: $ARG_IMAGE_VAL" + [[ ! -z ${description[@]} ]] && LOG_MSG "Description: ${description[@]}" + [[ ! -z ${version[@]} ]] && LOG_MSG "Version: ${version[@]}" + [[ ! -z ${release_date[@]} ]] && LOG_MSG "Release Date: ${release_date[@]}" + LOG_MSG "Supported SSDs:" + LOG_MSG " Vendor | Model | FW ver | Size | Pwr Cyc Req |" + LOG_MSG "=============|================================|==============|==========|=============|" + for section in $SECTIONS; do + if [[ "$section" != "main" ]]; then + call_ini_section $section + supported_model=$(string_supported_model $section) + LOG_MSG "$supported_model" + ini_unset $section + fi + done + echo -e "" + erase_extract_package "$extraction_path" + exit 0 +# operate SSD fw update +elif [ $ARG_UPDATE_FLAG == $TRUE ]; then + check_tool_dependencies + get_ssd_info + extract_package $ARG_IMAGE_VAL extraction_path + # 2. check signing + UPDATE_DONE=$FALSE + ini_parser "$extraction_path/list.ini" + for section in $SECTIONS; do + if [[ $section != "main" ]]; then + call_ini_section $section + if [[ "$SSD_DEVICE_MODEL" == "$( IFS=$'\n'; echo "${SSD_FW_Model[@]}" )" ]] && \ + [[ "$SSD_FW_VER" == "${SSD_FW_Version[@]}" ]] && \ + [[ "$SSD_SIZE" == "${SSD_Size[@]}" ]]; then + UPDATE_DONE=$TRUE + + power_policy=${Shutdown_Policy[0],,} + LOG_MSG "Power policy:$power_policy" ${DEBUG_MSG} + print_ssd_info $Newer_FW_Version ${Shutdown_Policy[0],,} + echo -e "" + #[[ "yes" == "$power_policy" ]] && LOG_MSG "PLEASE NOTE: System will power-cycle automatically once SSD FW Update complete!" + [[ "yes" == "$power_policy" || "$ARG_POWER_CYCLE_FLAG" == "$TRUE" ]] && LOG_MSG "Please note: Once SSD FW Update process ends, system will power-cycle automaticly and it will take up to 1 minute to access it back." + + # Prompt approval for FW update if ignore in case "yes" flag is on. + if [[ "$ARG_YES_FLAG" == "$FALSE" ]]; then + read -p "Do you want to continue? [Y/N]" -n 1 -r + echo # (optional) move to a new line + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + LOG_MSG_AND_EXIT "Aborting..." + exit 0 + fi + fi + + # Check FWUpgrade scripts exists & if so call it. + ssd_script_name=$Update_Script + ssd_script_path="${extraction_path}/${section}/${ssd_script_name}" + LOG_MSG "ssd_script_path: $ssd_script_path" ${DEBUG_MSG} + if [ ! -f $ssd_script_path ]; then + LOG_MSG_AND_EXIT "Error: fail to call upgrade script ($ssd_script_path)!" + fi + ( + cd "${extraction_path}/${section}" > /dev/null 2>&1 || exit + /bin/bash "$ssd_script_path" "${extraction_path}/${section}" + #cd - > /dev/null 2>&1 || exit + ) + if [ $? -ne 0 ]; then + LOG_MSG_AND_EXIT "Error: SSD FW update failed." + else + LOG_MSG "SSD FW update completed successfully." + + if [ $ARG_POWER_CYCLE_FLAG == $TRUE ]; then + LOG_MSG "Execute power cycle..." + sleep 1 + sync + power_cycle_script="${extraction_path}/common/mlnx_shutdown.sh" + [ ! -f $power_cycle_script ]&& LOG_MSG_AND_EXIT "Error: failed to initiate power cycle." + ($power_cycle_script "-s") + [ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: failed to power cycle the system automatically." + erase_extract_package "$extraction_path" + + fi + + fi + + break # Exit the for loop + fi + ini_unset $section + fi + done + if [ $UPDATE_DONE == $FALSE ]; then + LOG_MSG "SSD FW upgrade not require, based on given package latest version is in used." + print_ssd_info "no" + fi + + echo -e "" + erase_extract_package "$extraction_path" + exit 0 +fi + +exit 0 diff --git a/platform/mellanox/one-image.mk b/platform/mellanox/one-image.mk index e42b4fca46..89f203defe 100644 --- a/platform/mellanox/one-image.mk +++ b/platform/mellanox/one-image.mk @@ -5,10 +5,5 @@ $(SONIC_ONE_IMAGE)_MACHINE = mellanox $(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie $(SONIC_ONE_IMAGE)_INSTALLS += $(SX_KERNEL) $(KERNEL_MFT) $(MFT_OEM) $(MFT) $(MLNX_HW_MANAGEMENT) $(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES) -$(SONIC_ONE_IMAGE)_FILES += $(MLNX_FW_FILE) \ - $(MLNX_CPLD_ARCHIVES) \ - $(MLNX_FFB_SCRIPT) \ - $(ISSU_VERSION_FILE) \ - $(HW_MANAGEMENT_WD_SCRIPT) - +$(SONIC_ONE_IMAGE)_FILES += $(MLNX_FILES) SONIC_INSTALLERS += $(SONIC_ONE_IMAGE) diff --git a/platform/mellanox/rules.mk b/platform/mellanox/rules.mk index 076ed824e2..56e27bb477 100644 --- a/platform/mellanox/rules.mk +++ b/platform/mellanox/rules.mk @@ -16,6 +16,7 @@ include $(PLATFORM_PATH)/docker-ptf-mlnx.mk include $(PLATFORM_PATH)/mlnx-sfpd.mk include $(PLATFORM_PATH)/mlnx-ffb.mk include $(PLATFORM_PATH)/issu-version.mk +include $(PLATFORM_PATH)/mlnx-ssd-fw-update.mk SONIC_ALL += $(SONIC_ONE_IMAGE) \ $(DOCKER_FPM)