This repository has been archived on 2025-03-20. You can view files and clone it, but cannot push or open issues or pull requests.
sonic-buildimage/platform/mellanox/mlnx-fw-upgrade.j2
Stepan Blyshchak 16cce80e20
[201911][Mellanox] Place FW binaries under platform directory instead of squashfs (#14270)
202211 and above uses different squashfs compression type that 201911 kernel can not handle. Therefore, we avoid mounting squashfs altogather with this change.
2023-04-10 19:00:12 -07:00

397 lines
11 KiB
Django/Jinja
Executable File

#!/bin/bash
declare -r SCRIPT_NAME="$(basename "$0")"
declare -r SCRIPT_PATH="$(readlink -f "$0")"
declare -r SCRIPT_DIR="$(dirname "$SCRIPT_PATH")"
declare -r YES_PARAM="yes"
declare -r NO_PARAM="no"
declare -r VERBOSE_ERROR="1"
declare -r VERBOSE_WARNING="2"
declare -r VERBOSE_NOTICE="3"
declare -r VERBOSE_INFO="4"
declare -r VERBOSE_MAX="${VERBOSE_INFO}"
declare -r VERBOSE_MIN="${VERBOSE_ERROR}"
declare -r EXIT_SUCCESS="0"
declare -r EXIT_FAILURE="1"
declare -r QUERY_CMD="mlxfwmanager --query"
declare -r BURN_CMD="mlxfwmanager -u -f -y"
declare -r QUERY_FILE="/tmp/mlxfwmanager-query.log"
declare -r SPC1_ASIC="spc1"
declare -r SPC2_ASIC="spc2"
declare -r SPC3_ASIC="spc3"
declare -r UNKN_ASIC="unknown"
declare -rA FW_FILE_MAP=( \
[$SPC1_ASIC]="fw-SPC.mfa" \
[$SPC2_ASIC]="fw-SPC2.mfa" \
[$SPC3_ASIC]="fw-SPC3.mfa" \
)
declare -rA FW_REQUIRED_MAP=( \
[$SPC1_ASIC]="{{ MLNX_SPC_FW_VERSION }}" \
[$SPC2_ASIC]="{{ MLNX_SPC2_FW_VERSION }}" \
[$SPC3_ASIC]="{{ MLNX_SPC3_FW_VERSION }}" \
)
IMAGE_UPGRADE="${NO_PARAM}"
CPLD_UPGRADE="${NO_PARAM}"
VERBOSE_LEVEL="${VERBOSE_MIN}"
function PrintHelp() {
echo
echo "Usage: ./${SCRIPT_NAME} [OPTIONS]"
echo
echo "OPTIONS:"
echo " -u, --upgrade Upgrade ASIC firmware using next boot image (useful after SONiC-To-SONiC update)"
echo " -c, --cpld Upgrade CPLD firmware (requires -u|--upgrade)"
echo " -v, --verbose Verbose mode"
echo " -h, --help Print help"
echo
echo "Examples:"
echo " ./${SCRIPT_NAME} --verbose"
echo " ./${SCRIPT_NAME} --upgrade"
echo " ./${SCRIPT_NAME} --upgrade --cpld --verbose"
echo " ./${SCRIPT_NAME} --help"
echo
}
function ParseArguments() {
while [ "$#" -ge "1" ]; do
case "$1" in
-u|--upgrade)
IMAGE_UPGRADE="${YES_PARAM}"
;;
-c|--cpld)
CPLD_UPGRADE="${YES_PARAM}"
;;
-v|--verbose)
VERBOSE_LEVEL="${VERBOSE_MAX}"
;;
-h|--help)
PrintHelp
exit "${EXIT_SUCCESS}"
;;
esac
shift
done
}
function LogError() {
if [[ "${VERBOSE_LEVEL}" -ge "${VERBOSE_ERROR}" ]]; then
echo "ERROR: $*"
fi
}
function LogWarning() {
if [[ "${VERBOSE_LEVEL}" -ge "${VERBOSE_WARNING}" ]]; then
echo "WARNING: $*"
fi
}
function LogNotice() {
if [[ "${VERBOSE_LEVEL}" -ge "${VERBOSE_NOTICE}" ]]; then
echo "NOTICE: $*"
fi
}
function LogInfo() {
if [[ "${VERBOSE_LEVEL}" -ge "${VERBOSE_INFO}" ]]; then
echo "INFO: $*"
fi
}
function ExitFailure() {
if [[ "${VERBOSE_LEVEL}" -ge "${VERBOSE_ERROR}" ]]; then
echo
LogError "$@"
echo
fi
exit "${EXIT_FAILURE}"
}
function ExitSuccess() {
if [[ "${VERBOSE_LEVEL}" -ge "${VERBOSE_INFO}" ]]; then
echo
LogInfo "$@"
echo
fi
exit "${EXIT_SUCCESS}"
}
function ParseMachineConf() {
ONIE_MACHINE="$(cat /host/machine.conf | grep 'onie_machine=' | cut -f2 -d'=')"
ONIE_PLATFORM="$(cat /host/machine.conf | grep 'onie_platform=' | cut -f2 -d'=')"
}
function ShowProgressBar() {
local -rA SPIN=(
[0]="-"
[1]="\\"
[2]="|"
[3]="/"
)
if [[ "${VERBOSE_LEVEL}" -lt "${VERBOSE_INFO}" ]]; then
sleep 2s
return "${EXIT_SUCCESS}"
fi
# Print progress bar: use carriage return to overwrite command line content
for i in "${SPIN[@]}"; do
echo -ne "\r[${i}] ${1}"
sleep 0.5s
done
# Clear command line content + carriage return
echo -ne "\033[1K\r"
}
function WaitForDevice() {
local -i QUERY_RETRY_COUNT_MAX="10"
local -i QUERY_RETRY_COUNT="0"
${QUERY_CMD} &> /dev/null
while [[ ("${QUERY_RETRY_COUNT}" -lt "${QUERY_RETRY_COUNT_MAX}") && ("$?" -ne "${EXIT_SUCCESS}") ]]; do
sleep 1s
((QUERY_RETRY_COUNT++))
${QUERY_CMD} &> /dev/null
done
}
function GetAsicType() {
local -r VENDOR_ID="15b3"
local -r SPC1_PRODUCT_ID="cb84"
local -r SPC2_PRODUCT_ID="cf6c"
local -r SPC3_PRODUCT_ID="cf70"
if lspci -n | grep "${VENDOR_ID}:${SPC1_PRODUCT_ID}" &>/dev/null; then
echo "${SPC1_ASIC}"
exit "${EXIT_SUCCESS}"
elif lspci -n | grep "${VENDOR_ID}:${SPC2_PRODUCT_ID}" &>/dev/null; then
echo "${SPC2_ASIC}"
exit "${EXIT_SUCCESS}"
elif lspci -n | grep "${VENDOR_ID}:${SPC3_PRODUCT_ID}" &>/dev/null; then
echo "${SPC3_ASIC}"
exit "${EXIT_SUCCESS}"
fi
echo "${UNKN_ASIC}"
exit "${EXIT_FAILURE}"
}
function RunCmd() {
local ERROR_CODE="${EXIT_SUCCESS}"
if [[ "${VERBOSE_LEVEL}" -eq "${VERBOSE_MAX}" ]]; then
eval "$@"
else
eval "$@" &>/dev/null
fi
ERROR_CODE="$?"
if [[ "${ERROR_CODE}" != "${EXIT_SUCCESS}" ]]; then
ExitFailure "command failed: $@"
fi
}
function UpgradeASICFW() {
local -r _FW_BIN_PATH="$1"
local -r _ASIC_TYPE="$(GetAsicType)"
if [[ "${_ASIC_TYPE}" = "${UNKN_ASIC}" ]]; then
ExitFailure "failed to detect ASIC type"
fi
if [ ! -z "${_FW_BIN_PATH}" ]; then
local -r _FW_FILE="${_FW_BIN_PATH}/${FW_FILE_MAP[$_ASIC_TYPE]}"
if [ ! -f "${_FW_FILE}" ]; then
ExitFailure "no such file: ${_FW_FILE}"
fi
RunCmd "${QUERY_CMD} -i ${_FW_FILE} -L ${QUERY_FILE}" &>/dev/null
local -r _FW_INFO="$(grep FW ${QUERY_FILE})"
local -r _FW_CURRENT="$(echo ${_FW_INFO} | cut -f2 -d' ')"
local -r _FW_AVAILABLE="$(echo ${_FW_INFO} | cut -f3 -d' ')"
else
local -r _FW_FILE="/etc/mlnx/${FW_FILE_MAP[$_ASIC_TYPE]}"
RunCmd "${QUERY_CMD} -L ${QUERY_FILE}" &>/dev/null
local -r _FW_INFO="$(grep FW ${QUERY_FILE})"
local -r _FW_CURRENT="$(echo ${_FW_INFO} | cut -f2 -d' ')"
local -r _FW_AVAILABLE="${FW_REQUIRED_MAP[$_ASIC_TYPE]}"
fi
if [[ -z "${_FW_CURRENT}" ]]; then
ExitFailure "could not retreive current FW version"
fi
if [[ -z "${_FW_AVAILABLE}" ]]; then
ExitFailure "could not retreive available FW version"
fi
if [[ "${_FW_CURRENT}" == "${_FW_AVAILABLE}" ]]; then
LogInfo "firmware is up to date"
else
LogNotice "firmware upgrade is required. Installing compatible version..."
RunCmd "${BURN_CMD} -i ${_FW_FILE}"
fi
}
function UpgradeCPLDFW_Worker() {
local -r _CPLD_BURN_FILE="${1}"
local -r _CPLD_REFRESH_FILE="${2}"
local -r _ASIC_DEV="$(find /dev/mst -iname '*_pciconf0')"
if [[ -f /tmp/cpld_fw_updated ]]; then
RunCmd "cpldupdate --dev ${_ASIC_DEV} ${_CPLD_REFRESH_FILE}"
return "${EXIT_SUCCESS}"
fi
RunCmd "cpldupdate --dev ${_ASIC_DEV} ${_CPLD_BURN_FILE}"
RunCmd "cpldupdate --dev ${_ASIC_DEV} ${_CPLD_REFRESH_FILE}"
}
function UpgradeCPLDFW() {
local -r _CPLD_ARCHIVE="$1"
if [[ -f /tmp/cpld_fw_updated ]]; then
LogWarning "forced CPLD refresh was requested for ${ONIE_PLATFORM}"
CPLD_UPGRADE="${YES_PARAM}"
fi
if [[ "${CPLD_UPGRADE}" != "${YES_PARAM}" ]]; then
LogNotice "CPLD upgrade was not requested for ${ONIE_PLATFORM}"
return "${EXIT_SUCCESS}"
fi
if [[ ! -f "${_CPLD_ARCHIVE}" ]]; then
LogNotice "CPLD update $(basename ${_CPLD_ARCHIVE}) was not provided for ${ONIE_PLATFORM}"
return "${EXIT_SUCCESS}"
fi
CPLD_DIR="$(mktemp -d)"
RunCmd "tar xzf ${_CPLD_ARCHIVE} -C ${CPLD_DIR}"
local -r _CPLD_BURN_FILE="${CPLD_DIR}/$(cat ${CPLD_DIR}/bundle.txt | grep 'burn=' | cut -f2 -d'=')"
local -r _CPLD_REFRESH_FILE="${CPLD_DIR}/$(cat ${CPLD_DIR}/bundle.txt | grep 'refresh=' | cut -f2 -d'=')"
local -r _CPLD_VERSION="$(cat ${CPLD_DIR}/bundle.txt | grep 'version=' | cut -f2 -d'=')"
local _CURRENT_CPLD_VERSION="${_CPLD_VERSION}"
local _TARGET_CPLD_VERSION="${_CPLD_VERSION}"
if [[ -f /bsp/cpld/cpld_mgmt_version ]]; then
_CURRENT_CPLD_VERSION="$(cat /bsp/cpld/cpld_mgmt_version)"
elif [[ -f /var/run/hw-management/system/cpld1_version ]]; then
_CURRENT_CPLD_VERSION="$(cat /var/run/hw-management/system/cpld1_version)"
else
ExitFailure "could not retrieve current CPLD firmware version"
fi
if [[ "${_CURRENT_CPLD_VERSION}" -ge "${_TARGET_CPLD_VERSION}" ]]; then
LogInfo "CPLD firmware is up to date"
return "${EXIT_SUCCESS}"
fi
LogNotice "CPLD firmware upgrade is required. Installing compatible version..."
LogInfo "current CPLD firmware version: ${_CURRENT_CPLD_VERSION}"
LogInfo "target CPLD firmware version: ${_TARGET_CPLD_VERSION}"
LogInfo "CPLD burn firmware file: ${_CPLD_BURN_FILE}"
LogInfo "CPLD refresh firmware file: ${_CPLD_REFRESH_FILE}"
UpgradeCPLDFW_Worker "${_CPLD_BURN_FILE}" "${_CPLD_REFRESH_FILE}" &
local -r _PID="$!"
while $(ps -e -o pid | grep -E "^[[:blank:]]*${_PID}$" &> /dev/null); do
ShowProgressBar "CPLD update..."
done
RunCmd "wait ${_PID}"
}
function UpgradeFWFromImage() {
local -r _NEXT_SONIC_IMAGE="$(sonic_installer list | grep 'Next: ' | cut -f2 -d' ')"
local -r _CURRENT_SONIC_IMAGE="$(sonic_installer list | grep 'Current: ' | cut -f2 -d' ')"
if [[ "${_CURRENT_SONIC_IMAGE}" = "${_NEXT_SONIC_IMAGE}" ]]; then
ExitSuccess "firmware is up to date"
fi
# /host/image-<version>/platform/fw is now the new location for FW binaries.
# Prefere this path and if it does not exist use squashfs as a fallback.
local -r _PLATFORM_FW_BIN_PATH="/host/image-${_NEXT_SONIC_IMAGE#SONiC-OS-}/platform/fw/"
if [[ -d "${_PLATFORM_FW_BIN_PATH}" ]]; then
LogInfo "Using FW binaries from ${_PLATFORM_FW_BIN_PATH}"
UpgradeASICFW "${_PLATFORM_FW_BIN_PATH}/asic"
UpgradeCPLDFW "${_PLATFORM_FW_BIN_PATH}/cpld/${ONIE_MACHINE#mlnx_}_cpld.tar.gz"
else
FS_PATH="/host/image-${_NEXT_SONIC_IMAGE#SONiC-OS-}/fs.squashfs"
FS_MOUNTPOINT="/tmp/image-${_NEXT_SONIC_IMAGE#SONiC-OS-}-fs"
LogInfo "Using FW binaries from ${FS_MOUNTPOINT}"
RunCmd "mkdir -p ${FS_MOUNTPOINT}"
RunCmd "mount -t squashfs ${FS_PATH} ${FS_MOUNTPOINT}"
UpgradeASICFW "${FS_MOUNTPOINT}/etc/mlnx/${FW_FILE}"
UpgradeCPLDFW "${FS_MOUNTPOINT}/etc/mlnx/cpld/${ONIE_MACHINE#mlnx_}_cpld.tar.gz"
fi
}
function Cleanup() {
if [[ -d "${FS_MOUNTPOINT}" ]]; then
umount -rf "${FS_MOUNTPOINT}"
rm -rf "${FS_MOUNTPOINT}"
fi
if [[ -d "${CPLD_DIR}" ]]; then
rm -rf "${CPLD_DIR}"
fi
}
function ExitIfQEMU() {
if [[ $(cat /sys/devices/virtual/dmi/id/chassis_vendor) = "QEMU" ]]; then
ExitSuccess "No FW upgrade for SimX platform"
fi
}
trap Cleanup EXIT
ParseMachineConf
ParseArguments "$@"
ExitIfQEMU
WaitForDevice
if [[ "${CPLD_UPGRADE}" = "${YES_PARAM}" ]]; then
if [[ "${IMAGE_UPGRADE}" = "${NO_PARAM}" ]]; then
ExitFailure "mandatory parameter was not provided: -u|--upgrade"
fi
fi
if [[ "${IMAGE_UPGRADE}" = "${YES_PARAM}" ]]; then
UpgradeFWFromImage
else
UpgradeASICFW
fi
ExitSuccess "firmware upgrade is completed"