From dd636f81085c4a4a202455f86a1b9a38362bb507 Mon Sep 17 00:00:00 2001 From: zhaoertao Date: Fri, 10 Oct 2014 03:14:52 -0700 Subject: [PATCH] support firmware update for p8LE --- xCAT-genesis-scripts/bin/pseries_platform | 29 ++ xCAT-genesis-scripts/bin/update_flash | 457 ++++++++++++++++++++++ xCAT-genesis-scripts/bin/update_flash_nv | 416 ++++++++++++++++++++ 3 files changed, 902 insertions(+) create mode 100755 xCAT-genesis-scripts/bin/pseries_platform create mode 100755 xCAT-genesis-scripts/bin/update_flash create mode 100755 xCAT-genesis-scripts/bin/update_flash_nv diff --git a/xCAT-genesis-scripts/bin/pseries_platform b/xCAT-genesis-scripts/bin/pseries_platform new file mode 100755 index 000000000..39d0ccfa9 --- /dev/null +++ b/xCAT-genesis-scripts/bin/pseries_platform @@ -0,0 +1,29 @@ +#!/bin/sh + +SOURCE_FILE="pseries_platform" +PLATFORM_FILE=/proc/cpuinfo +export PLATFORM_UNKNOWN=0 +export PLATFORM_POWERKVM_HOST=1 +export PLATFORM_POWERKVM_GUEST=2 +export PLATFORM_PSERIES_LPAR=3 + +export platform_name="Unknown" +export platform=$PLATFORM_UNKNOWN + +if grep -q "PowerNV" $PLATFORM_FILE; then + platform_name="PowerKVM Host" + platform=$PLATFORM_POWERKVM_HOST +elif grep -q "IBM pSeries (emulated by qemu)" $PLATFORM_FILE; then + platform_name="PowerKVM pSeries Guest" + platform=$PLATFORM_POWERKVM_GUEST +elif grep -q "pSeries" $PLATFORM_FILE; then + platform_name="PowerVM pSeries LPAR" + platform=$PLATFORM_PSERIES_LPAR +fi +PARAM=$0 +BASENAME=`basename $0` +echo "basename:$BASENAME, param:$PARAM" + +if [ $SOURCE_FILE = `basename $0` ]; then + echo $platform_name +fi diff --git a/xCAT-genesis-scripts/bin/update_flash b/xCAT-genesis-scripts/bin/update_flash new file mode 100755 index 000000000..5f3b2e5a6 --- /dev/null +++ b/xCAT-genesis-scripts/bin/update_flash @@ -0,0 +1,457 @@ +#!/bin/sh +# Copyright (c) 2003, 2004, 2008 International Business Machines +# Common Public License Version 1.0 (see COPYRIGHT) +# +# Authors: John Rose +# Mike Strosaker + +# Simple script to update flash. The kernel module rtas_flash does +# the real work at reboot time. +# This script has minimal dependencies so it can operate in a rescue +# environment. This is probably overkill since it is easy enough to +# flash without this script. + +#set -x + +# For now firmware can only handle 4k pages. At some point in the +# future they will be able to handle large pages. When that (hopefully) +# happens we will need to use getconf to retrieve the systems page size. +PAGE_SIZE=4096 + +# Error Codes +E_SUCCESS=0 # Success +E_UNSUPPORTED=1 # Flash update is not supported on this system +E_USAGE=3 # Usage error +E_PERM=4 # Permission error +E_IMAGE=5 # Image file error +E_PROC_FS=6 # Proc file either doesn't exist, or behaves unexpectedly +E_MODULE=7 # Error loading module +E_RTAS=8 # RTAS call failed +E_USER=9 # User aborted operation +E_OVERWRITE=10 # Auto overwrite permanent side image +E_WRNTY=15 # Update Access Key Expired + +# Script Constants +PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH +PROCFLASH=/proc/ppc64/rtas/firmware_update +PROCMANAGE=/proc/ppc64/rtas/manage_flash +PROCVALIDATE=/proc/ppc64/rtas/validate_flash +OLDPROCFLASH=/proc/ppc64/rtas/firmware_flash +PSERIES_PLATFORM=$(dirname $0)/pseries_platform + +# firmware_update Status Values +FLASH_AUTH=-9002 # RTAS Not Service Authority Partition +FLASH_NO_OP=-1099 # No operation initiated by user +FLASH_IMG_SHORT=-1005 # Flash image shorter than expected +FLASH_IMG_BAD_LEN=-1004 # Bad length value in flash list block +FLASH_IMG_NULL_DATA=-1003 # Bad data value in flash list block +FLASH_IMG_READY=0 # Firmware img ready for flash on reboot + +# manage_flash Status Values +MANAGE_AUTH=-9002 # RTAS Not Service Authority Partition +MANAGE_ACTIVE_ERR=-9001 # RTAS Cannot Overwrite Active Img +MANAGE_NO_OP=-1099 # No operation initiated by user +MANAGE_PARAM_ERR=-3 # RTAS Parameter Error +MANAGE_HW_ERR=-1 # RTAS Hardware Error +MANAGE_SUCCESS=0 # Operation Successful + +# validate_flash Status Values +VALIDATE_AUTH=-9002 # RTAS Not Service Authority Partition +VALIDATE_INCOMPLETE=-1002 # User copied < VALIDATE_BUF_SIZE +VALIDATE_READY=-1001 # Firmware image ready for validation +VALIDATE_PARAM_ERR=-3 # RTAS Parameter Error +VALIDATE_HW_ERR=-1 # RTAS Hardware Error +VALIDATE_TMP_UPDATE=0 # RPA Section 7.3, Table 63 +VALIDATE_FLASH_AUTH=1 # RPA Section 7.3, Table 63 +VALIDATE_INVALID_IMG=2 # RPA Section 7.3, Table 63 +VALIDATE_CUR_UNKNOWN=3 # RPA Section 7.3, Table 63 +VALIDATE_TMP_COMMIT_DL=4 # RPA Section 7.3, Table 63 +VALIDATE_TMP_COMMIT=5 # RPA Section 7.3, Table 63 +VALIDATE_TMP_UPDATE_DL=6 # RPA Section 7.3, Table 63 +VALIDATE_OUT_OF_WRNTY=7 # RPA Section 7.3, Table 63 + +error() { + local exit_code=$1 + + if [ $# -lt 1 ]; then + echo "error(): usage" >&2 + return $E_USAGE + fi + + shift; + echo update_flash: $* >&2 + exit $exit_code +} + +usage() { + local exit_code; + + if [ "$1" == $E_SUCCESS ]; then + exit_code=$E_SUCCESS + else + exit_code=$E_USAGE + fi + + echo "USAGE: update_flash {-h | -s | -r | -c | [-v|-n] -f }" >&2 + echo " -h Print this message." >&2 + echo " -s Determine if partition has access to" >&2 + echo " perform flash image management." >&2 + echo " -r Reject temporary image." >&2 + echo " -c Commit temporary image." >&2 + echo " -v Validate ONLY with given image file." >&2 + echo " -n Do not overwrite Permanent side" >&2 + echo " image automatically." >&2 + echo " -f Update with given image file. If possible," >&2 + echo " the image is automatically validated prior" >&2 + echo " to update." >&2 + echo "" >&2 + exit $exit_code +} + +query_support() { + local exit_status=$E_UNSUPPORTED + + if [ ! -r "$PROCVALIDATE" ]; then + modprobe rtas_flash || error $E_MODULE "could not load rtas_flash kernel module" + fi + + if [ -e "/proc/device-tree/rtas/ibm,manage-flash-image" ]; then + grep \\"$VALIDATE_AUTH" "$PROCVALIDATE" > /dev/null + if [ $? -ne 0 ]; then + # validate-flash did not return "not authorized" + head --bytes=4k /dev/zero > $PROCVALIDATE 2>/dev/null + grep 1 "$PROCVALIDATE" > /dev/null + if [ $? -ne 0 ]; then + # validate-flash did not return "not authorized" + exit_status=0 + fi + fi + else + if [ -e "/proc/device-tree/rtas/ibm,update-flash-64-and-reboot" ] || [ -e "/proc/device-tree/rtas/udpate-flash-and-reboot" ]; then + exit_status=0 + fi + fi + + if [ $exit_status -ne 0 ]; then + echo update_flash: flash image cannot be managed from this partition + else + echo update_flash: flash image management is supported + fi + + exit $exit_status; +} + +echo_validate_rtas_buf() { + local output="$1" + local cur_t_name=$(echo "$output" | grep "^MI" | head -n 1 | awk ' { print $2 } ') + local cur_p_name=$(echo "$output" | grep "^MI" | head -n 1 | awk ' { print $3 } ') + local new_t_name=$(echo "$output" | grep "^MI" | tail -n 1 | awk ' { print $2 } ') + local new_p_name=$(echo "$output" | grep "^MI" | tail -n 1 | awk ' { print $3 } ') + + echo "Projected Flash Update Results:" + echo "Current T Image: $cur_t_name" + echo "Current P Image: $cur_p_name" + echo "New T Image: $new_t_name" + echo "New P Image: $new_p_name" +} + +echo_entitlement_expiry_date() { + local build_date=`cat $PROCVALIDATE | grep "^MG" | tail -n 1 | cut -d " " -f2` + local entl_date=`cat $PROCVALIDATE | grep "^ME" | cut -d " " -f2` + + echo "The selected firmware image cannot be applied." + echo "" + echo -n "The Build Date of the firmware image selected is " + if [ "$build_date" != "" ]; then + echo "$(date --date=$build_date +"%B %d, %Y")." + else + echo "UNKNOWN." + fi + + echo -n "The System's Update Access Key Expiration Date is " + if [ "$entl_date" != "" ]; then + echo "$(date --date=$entl_date +"%B %d, %Y")." + else + echo "UNKNOWN." + fi + echo "" + echo "Please go to http://www.ibm.com/servers/eserver/ess to obtain " + echo "a replacement update access key." +} + +echo_validate_return_status() { + local output="$1" + local rc=$(echo "$output" | head -n 1) + local rtas_buf=$(echo "$output" | tail -n +2) + + [ $# -eq 1 ] || error $E_USAGE "echo_validate_return_status(): usage" + + case "$rc" in + $VALIDATE_PARAM_ERR) + error $E_RTAS "RTAS: validate() Parameter Error";; + $VALIDATE_HW_ERR) + error $E_RTAS "RTAS: validate() Hardware Error";; + $VALIDATE_FLASH_AUTH) + error $E_RTAS "RTAS: validate() Partition does not have authority";; + $VALIDATE_AUTH) + error $E_RTAS "RTAS: validate() Partition does not have authority";; + $VALIDATE_INVALID_IMG) + error $E_RTAS "RTAS: validate() Invalid candidate image for this platform";; + $VALIDATE_TMP_UPDATE) + echo "info: Temporary side will be updated with a newer or" + echo "identical image";; + $VALIDATE_CUR_UNKNOWN) + echo "info: Current fixpack level is unknown";; + $VALIDATE_TMP_COMMIT_DL) + echo "info: Current Temporary image will be committed to" + echo "Permanent side before being replaced with new image, and" + echo "the new image is downlevel from current image";; + $VALIDATE_TMP_COMMIT) + echo "info: Current Temporary side will be committed to" + echo "Permanent side before being replaced with the new image";; + $VALIDATE_TMP_UPDATE_DL) + echo "info: Temporary side will be updated with a downlevel" + echo "image";; + $VALIDATE_OUT_OF_WRNTY) + echo_entitlement_expiry_date + error $E_WRNTY "Please contact your service support structure.";; + *) error $E_RTAS "RTAS: Unknown validate-flash-image Return Status" + esac + + echo + echo_validate_rtas_buf "$rtas_buf" + + # Do not commit T side image to P side + if [ $no_overwrite_opt -eq 1 ]; then + if [ $rc -eq $VALIDATE_TMP_COMMIT_DL ] || [ $rc -eq $VALIDATE_TMP_COMMIT ]; then + echo "" + echo "update_flash: Run without -n option to flash new image" + exit $E_OVERWRITE + fi + fi +} + +validate_flash() { + local img_file=$1 + local output="" + + [ $# -eq 1 ] || error $E_USAGE "validate_flash(): usage" + + [ -r $PROCVALIDATE ] || return $E_PROC_FS + + grep \\"$VALIDATE_AUTH" "$PROCVALIDATE" > /dev/null + if [ $? -eq 0 ]; then # validate-flash returned "not authorized" + return $E_RTAS + fi + + # Copy image file to proc file + cp "$img_file" "$PROCVALIDATE" || error $E_PROC_FS "error copying flash image to rtas_flash validate module" + + # Display appropriate message, exiting if necessary + output="$(cat $PROCVALIDATE)" + echo_validate_return_status "$output" + + return 0 +} + +validate_flash_from_file() { + local img_file=$1 + + [ $# -eq 1 ] || error $E_USAGE "validate_flash_from_file(): usage" + + if [ ! -r "$PROCVALIDATE" ]; then + modprobe rtas_flash || error $E_MODULE "could not load rtas_flash kernel module" + [ -r "$PROCVALIDATE" ] || error $E_PROC_FS "rtas_flash kernel module did not create $PROCVALIDATE" + fi + + if validate_flash $img_file; then + return 0; + else + case "$?" in + $E_PROC_FS) error $E_PROC_FS "validate: $PROCVALIDATE does not exist";; + $E_RTAS) error $E_RTAS "validate: firmware validation not supported on this system";; + esac + fi +} + +echo_update_status() { + local rc="$1" + + [ $# -eq 1 ] || error $E_USAGE "echo_update_status(): usage" + + case "$rc" in + $FLASH_AUTH) + error $E_RTAS "RTAS: Partition does not have authority";; + $FLASH_IMG_SHORT) + error $E_IMAGE "Flash image shorter than expected";; + $FLASH_IMG_BAD_LEN) + error $E_PROC_FS "Bad length value in flash list block";; + $FLASH_IMG_NULL_DATA) + error $E_PROC_FS "Bad data value in flash list block";; + $FLASH_IMG_READY) + echo "Flash image ready...rebooting the system...";; + *) error $E_PROC_FS "RTAS: Unknown update flash status" + esac +} + +update_flash_from_file() { + local img_file=$1 + local output="" + local oldkernel=0 + + [ $# -eq 1 ] || error $E_USAGE "update_flash_from_file(): usage" + + [ -r "$img_file" ] || error $E_IMAGE "cannot read $img_file" + + flashfile=$PROCFLASH + if [ ! -r "$PROCFLASH" ]; then + modprobe rtas_flash + if [ ! -r "$PROCFLASH" ]; then + if [ -r "$OLDPROCFLASH" ]; then + oldkernel=1 + else + error $E_PROC_FS "rtas_flash kernel module did not create $PROCFLASH" + fi + fi + fi + + if [ -r "$PROCVALIDATE" ]; then + validate_flash "$img_file" + fi + + if [ $oldkernel -eq 0 ]; then + dd if="$img_file" of="$PROCFLASH" bs=$PAGE_SIZE 2>/dev/null || error $E_PROC_FS "error copying flash image to rtas_flash kernel module" + + output="$(cat $PROCFLASH)" + echo_update_status "$output" + else + dd if="$img_file" of="$OLDPROCFLASH" bs=PAGE_SIZE 2>/dev/null || error $E_PROC_FS "error copying flash image to rtas_flash kernel module" + cat "$OLDPROCFLASH" + fi + + #XXX + reboot + + return 0; +} + +echo_manage_return_status() { + local is_commit=$1 + local output=$2 + local rc=$(echo $output) + + [ $# -eq 2 ] || error $E_USAGE "echo_manage_return_status(): usage" + + case "$rc" in + $MANAGE_AUTH) + error $E_RTAS "RTAS: manage() Partition does not have authority";; + $MANAGE_ACTIVE_ERR) + error $E_RTAS "RTAS: manage() Cannot Overwrite the Active Firmware Image";; + $MANAGE_PARAM_ERR) + error $E_RTAS "RTAS: manage() Parameter Error";; + $MANAGE_HW_ERR) + error $E_RTAS "RTAS: manage() Hardware Error";; + $MANAGE_SUCCESS) + if [ $is_commit -eq 0 ]; then + echo "success: Rejected temporary firmware image" + else + echo "success: Committed temporary firmware image" + fi + ;; + *) error $E_RTAS "Unknown manage-flash-image Return Status" + esac +} + +manage_flash() { + local is_commit=$1 + local commit_str="1" + local reject_str="0" + local output="" + + [ $# -eq 1 ] || error $E_USAGE "manage_flash(): usage" + + if [ ! -r "$PROCMANAGE" ]; then + modprobe rtas_flash || error $E_MODULE "could not load rtas_flash kernel module" + [ -r "$PROCMANAGE" ] || error $E_PROC_FS "rtas_flash kernel module did not create $PROCMANAGE" + fi + + if [ $is_commit -eq 1 ]; then + echo $commit_str > $PROCMANAGE + else + echo $reject_str > $PROCMANAGE + fi + + output=$(cat $PROCMANAGE) + + echo_manage_return_status $is_commit "$output" + + if echo $output | grep "^success" > /dev/null; then + return 0 + else + return $E_RTAS + fi +} + +file="" +check_opt=0 +commit_opt=0 +reject_opt=0 +validate_opt=0 +no_overwrite_opt=0 +file_opt=0 + +[ -d /proc/device-tree ] || error $E_PROC_FS "iSeries or /proc not mounted" +#XXX +#[ "`whoami`" = "root" ] || error $E_PERM "must be root to execute this command" + +# Check for platform and if PowerNV call update_flash_nv + +# PowerNV update_flash tool +UPDATE_FLASH_NV=$(dirname $0)/update_flash_nv + +. $PSERIES_PLATFORM +case "$platform" in + $PLATFORM_UNKNOWN | $PLATFORM_POWERKVM_GUEST) + echo "update_flash: is not supported on the $platform_name platform" + exit 1;; + $PLATFORM_POWERKVM_HOST) + if [ ! -r "$UPDATE_FLASH_NV" ]; then + error $E_PERM "Couldn't find $UPDATE_FLASH_NV file." + fi + /bin/sh $UPDATE_FLASH_NV $@ + exit $? +esac + +while [ -n "$1" ]; do + arg="$1" + shift + case "$arg" in + -q|-l|-D|-S) error $E_USAGE "the $arg option is not implemented";; + -h) usage $E_SUCCESS;; + -s) check_opt=1;; + -c) commit_opt=1;; + -r) reject_opt=1;; + -v) validate_opt=1;; + -n) no_overwrite_opt=1;; + -f) file_opt=1; file="$1"; shift;; + *) error $E_USAGE "unknown option $arg" + esac +done + +if [ -n "$file" ]; then + if [ $commit_opt -eq 1 ] || [ $reject_opt -eq 1 ] || + [ $check_opt -eq 1 ]; then + usage + elif [ $validate_opt -eq 1 ] && [ $no_overwrite_opt -eq 1 ]; then + usage + elif [ $validate_opt -eq 1 ]; then + validate_flash_from_file $file + else + update_flash_from_file $file + fi +else + [ $check_opt -eq 1 ] && query_support + [ $commit_opt -eq 0 ] && [ $reject_opt -eq 0 ] && usage + [ $commit_opt -eq 1 ] && [ $reject_opt -eq 1 ] && usage + manage_flash $commit_opt +fi diff --git a/xCAT-genesis-scripts/bin/update_flash_nv b/xCAT-genesis-scripts/bin/update_flash_nv new file mode 100755 index 000000000..4bd03a806 --- /dev/null +++ b/xCAT-genesis-scripts/bin/update_flash_nv @@ -0,0 +1,416 @@ +#!/bin/sh +# Copyright (c) 2013 International Business Machines +# Common Public License Version 1.0 (see COPYRIGHT) +# +# Authors: Vasant Hegde +# +# Simple script for code update on "KVM on Power" machines. This +# is a simple wrapper script to pass the image. The Linux kernel +# and FW does the real work during system reboot. +# +# This script has minimal dependencies so it can operate in a +# rescue environment. + +#set -x + +# Error codes +E_SUCCESS=0 # Success +E_UNSUPPORTED=1 # Firmware update is not supported +E_USAGE=3 # Usage error +E_PERM=4 # Permission error +E_IMAGE=5 # Image file error +E_SYS_FS=6 # Firmware update related sysfs file doesn't exist +E_MODULE=7 # Error loading module +E_OPAL=8 # OPAL call failed +E_USER=9 # User aborted operation +E_OVERWRITE=10 # Auto overwrite permanent side image +E_WRNTY=15 # Update Access Key Expired + +# Firmware update related files +SYS_IMAGE_FILE=/sys/firmware/opal/image +SYS_VALIDATE_FLASH=/sys/firmware/opal/validate_flash +SYS_MANAGE_FLASH=/sys/firmware/opal/manage_flash +SYS_UPDATE_FLASH=/sys/firmware/opal/update_flash + +# Code update status values +FLASH_SUCCESS=0 # Success +FLASH_PARAM_ERR=-1 # Parameter error +FLASH_BUSY=-2 # OPAL busy +FLASH_HW_ERR=-6 # Hardware error +FLASH_INTERNAL_ERR=-11 # Internal error +FLASH_NO_OP=-1099 # No operation initiated by user +FLASH_NO_AUTH=-9002 # Inband firmware update is not allowed + +# Validate image status values +FLASH_IMG_READY=-1001 # Image ready for validation +FLASH_IMG_INCOMPLETE=-1002 # User copied < VALIDATE_BUF_SIZE + +# Manage image status values +FLASH_ACTIVE_ERR=-9001 # Cannot overwrite active img + +# Flash image status values +FLASH_IMG_READY=0 # Image ready for flash on reboot +FLASH_INVALID_IMG=-1003 # Flash image shorter than expected +FLASH_IMG_NULL_DATA=-1004 # Bad data +FLASH_IMG_BAD_LEN=-1005 # Bad length + +# Validate image update result tokens +# +# T side will be updated +VALIDATE_TMP_UPDATE=0 +# +# Partition does not have authority +VALIDATE_FLASH_AUTH=1 +# +# Candidate image is not valid for this platform +VALIDATE_INVALID_IMG=2 +# +# Current fixpack level is unknown +VALIDATE_CUR_UNKNOWN=3 +# +# Current T side will be committed to P side before being replace +# with new image, and the new image is downlevel from current image +VALIDATE_TMP_COMMIT_DL=4 +# +# Current T side will be committed to P side before being replaced +# with new image +VALIDATE_TMP_COMMIT=5 +# +# T side will be updated with a downlevel image +VALIDATE_TMP_UPDATE_DL=6 +# +# The candidate image's release date is later than the system's Update +# Access Key Expiration date - service warranty period has expired +VALIDATE_OUT_OF_WRNTY=7 + +error() { + local exit_code=$1 + + if [ $# -lt 1 ]; then + echo "error(): usage." >&2 + return $E_USAGE + fi + + shift; + echo update_flash: $* >&2 + exit $exit_code +} + +usage() { + local exit_code; + + if [ "$1" == $E_SUCCESS ]; then + exit_code=$E_SUCCESS + else + exit_code=$E_USAGE + fi + + echo "USAGE: update_flash {-h | -s | -r | -c | [-v|-n] -f }" >&2 + echo " -h Print this message." >&2 + echo " -s Determine if partition has access to" >&2 + echo " perform flash image management." >&2 + echo " -r Reject temporary image." >&2 + echo " -c Commit temporary image." >&2 + echo " -v Validate the given image file." >&2 + echo " -n Do not overwrite Permanent side" >&2 + echo " image automatically." >&2 + echo " -f Update with given image file. If possible," >&2 + echo " the image is automatically validated prior" >&2 + echo " to update." >&2 + echo "" >&2 + exit $exit_code +} + +# Validate sysfs interface +validate_sysfs_file() { + local file="$1" + if [ -r "$file" ]; then + return $E_SUCCESS + fi + + error $E_SYS_FS "sysfs interface for firmware update does not exists." +} + +# Copy image to sysfs file +copy_candidate_image() { + local img_file=$1 + + [ $# -eq 1 ] || error $E_USAGE "copy_candidate_image(): usage." + + [ -r "$img_file" ] || error $E_IMAGE "Cannot read ${img_file}." + + # Copy candidate image + dd if=$img_file of=$SYS_IMAGE_FILE 2>/dev/null + if [ $? -ne 0 ]; then + echo "update_flash: Error copying firmware image." + error $E_IMAGE "Please retry with valid firmware image." + fi +} + +echo_opal_return_status() { + case "$1" in + $FLASH_PARAM_ERR) + error $E_OPAL "Parameter Error.";; + $FLASH_BUSY) + error $E_OPAL "OPAL Busy.";; + $FLASH_HW_ERR) + error $E_OPAL "Hardware error.";; + $FLASH_INTERNAL_ERR) + error $E_OPAL "OPAL internal error.";; + $FLASH_NO_AUTH) + error $E_PERM "System does not have authority to perform firmware update.";; + $FLASH_IMG_INCOMPLETE) + error $E_IMAGE "Invalid candidate image.";; + $FLASH_ACTIVE_ERR) + error $E_OVERWRITE "Cannot Overwrite the Active Firmware Image.";; + $FLASH_INVALID_IMG) + error $E_IMAGE "Invalid candidate image.";; + $FLASH_IMG_NULL_DATA) + error $E_IMAGE "Bad data value in flash list block.";; + $FLASH_IMG_BAD_LEN) + error $E_IMAGE "Bad length value in flash list block.";; + *) error $E_OPAL "Unknown return status.";; + esac +} + +# Determine if partition has access to perform flash image management +query_flash_support() { + # Validate sysfs interface + validate_sysfs_file $SYS_IMAGE_FILE + + # By default KVM on Power host is allowed to do firmware management + echo "update_flash: Firmware image management is supported." + + exit $E_SUCCESS +} + +echo_validate_buf() { + local output="$1" + local cur_t=$(echo "$output" | grep "^MI" | head -n 1 | awk ' { print $2 } ') + local cur_p=$(echo "$output" | grep "^MI" | head -n 1 | awk ' { print $3 } ') + local new_t=$(echo "$output" | grep "^MI" | tail -n 1 | awk ' { print $2 } ') + local new_p=$(echo "$output" | grep "^MI" | tail -n 1 | awk ' { print $3 } ') + + echo "Projected Flash Update Results:" + echo "Current T Image: $cur_t" + echo "Current P Image: $cur_p" + echo "New T Image: $new_t" + echo "New P Image: $new_p" +} + +echo_validate_return_status() { + local output="$1" + local rc=$(echo "$output" | head -n 1) + local opal_buf=$(echo "$output" | tail -n +2) + + [ $# -eq 1 ] || error $E_USAGE "echo_validate_return_status(): usage." + + if [ $rc -lt 0 ]; then + echo_opal_return_status $rc + fi + + # Validation result + case "$rc" in + $VALIDATE_TMP_UPDATE) + echo -n "info: Temporary side will be updated with a newer or" + echo " identical image.";; + $VALIDATE_FLASH_AUTH) + error $E_OPAL "System does not have authority.";; + $VALIDATE_INVALID_IMG) + error $E_OPAL "Invalid candidate image for this platform.";; + $VALIDATE_CUR_UNKNOWN) + echo "info: Current fixpack level is unknown.";; + $VALIDATE_TMP_COMMIT_DL) + echo "info: Current Temporary image will be committed to" + echo "Permanent side before being replaced with new image," + echo "and the new image is downlevel from current image.";; + $VALIDATE_TMP_COMMIT) + echo "info: Current Temporary side will be committed to" + echo "Permanent side before being replaced with the new" + echo "image.";; + $VALIDATE_TMP_UPDATE_DL) + echo "info: Temporary side will be updated with a downlevel image.";; + *) error $E_OPAL "Unknown return status." + esac + + echo + echo_validate_buf "$opal_buf" + + # Do not commit T side image to P side + if [ $no_overwrite_opt -eq 1 ]; then + if [ $rc -eq $VALIDATE_TMP_COMMIT_DL ] || + [ $rc -eq $VALIDATE_TMP_COMMIT ]; then + echo "" + echo "update_flash: Run without -n option to flash new image." + exit $E_OVERWRITE + fi + fi +} + +validate_flash() { + local output="" + + # Validate candidate image + echo 1 > $SYS_VALIDATE_FLASH 2>/dev/null + + # Display appropriate message, exiting if necessary + output="$(cat $SYS_VALIDATE_FLASH)" + echo_validate_return_status "$output" +} + +validate_flash_from_file() { + local img_file=$1 + + [ $# -eq 1 ] || error $E_USAGE "validate_flash_from_file(): usage." + + # Validate sysfs interface + validate_sysfs_file $SYS_VALIDATE_FLASH + + # Copy candiadate image + copy_candidate_image $img_file + + # Validate candidate image + validate_flash + + exit $E_SUCCESS +} + +echo_update_return_status() { + local rc="$1" + + [ $# -eq 1 ] || error $E_USAGE "echo_update_return_status(): usage." + + if [ $rc -lt 0 ]; then + echo_opal_return_status $rc + elif [ $rc -eq $FLASH_IMG_READY ]; then + echo + echo "FLASH: Image ready...rebooting the system..." + echo "FLASH: This will take several minutes." + echo "FLASH: Do not power off!" + else + error $E_SYS_FS "Unknown return status." + fi +} + +update_flash_from_file() { + local img_file=$1 + local output="" + + [ $# -eq 1 ] || error $E_USAGE "update_flash_from_file(): usage." + + # Validate sysfs interface + validate_sysfs_file $SYS_UPDATE_FLASH + + # Copy candidate image + copy_candidate_image $img_file + + # Validate candidate image + validate_flash + + # Update image + echo 1 > $SYS_UPDATE_FLASH 2>/dev/null + output="$(cat $SYS_UPDATE_FLASH)" + echo_update_return_status "$output" + + # Reboot system, so that we can flash new image + reboot -f + + exit $E_SUCCESS +} + +echo_manage_return_status() { + local is_commit=$1 + local output=$2 + local rc=$(echo $output) + + [ $# -eq 2 ] || error $E_USAGE "echo_manage_return_status(): usage." + + if [ $rc -lt 0 ]; then + echo_opal_return_status $rc + elif [ $rc -eq $FLASH_SUCCESS ]; then + if [ $is_commit -eq 0 ]; then + echo "Success: Rejected temporary firmware image." + else + echo "Success: Committed temporary firmware image." + fi + else + error $E_OPAL "Unknown return status." + fi +} + +manage_flash() { + local is_commit=$1 + local commit_str="1" + local reject_str="0" + local output="" + + [ $# -eq 1 ] || error $E_USAGE "manage_flash(): usage." + + # Validate sysfs interface + validate_sysfs_file $SYS_MANAGE_FLASH + + # Commit operation + if [ $is_commit -eq 1 ]; then + echo $commit_str > $SYS_MANAGE_FLASH + else + echo $reject_str > $SYS_MANAGE_FLASH + fi + + # Result + output=$(cat $SYS_MANAGE_FLASH) + echo_manage_return_status $is_commit "$output" + + exit $E_SUCCESS +} + +file="" +check_opt=0 +commit_opt=0 +reject_opt=0 +validate_opt=0 +no_overwrite_opt=0 +file_opt=0 + +# Only root user can perform firmware update +[ "`whoami`" == "root" ] || error $E_PERM "Must be root to execute this command." + +# Parse command line options +while [ -n "$1" ]; do + arg="$1" + shift + case "$arg" in + -q|-l|-D|-S) error $E_USAGE "The $arg option is not implemented.";; + -h) usage $E_SUCCESS;; + -s) check_opt=1;; + -c) commit_opt=1;; + -r) reject_opt=1;; + -v) validate_opt=1;; + -n) no_overwrite_opt=1;; + -f) file_opt=1; file="$1"; shift;; + *) error $E_USAGE "Unknown option ${arg}." + esac +done + +if [ -n "$file" ]; then + if [ $commit_opt -eq 1 ] || [ $reject_opt -eq 1 ] || + [ $check_opt -eq 1 ]; then + usage + elif [ $validate_opt -eq 1 ] && [ $no_overwrite_opt -eq 1 ]; then + usage + elif [ $validate_opt -eq 1 ]; then + validate_flash_from_file $file + else + update_flash_from_file $file + fi +else + if [ $check_opt -eq 1 ]; then + if [ $commit_opt -eq 1 ] || [ $reject_opt -eq 1 ]; then + usage + else + query_flash_support + fi + fi + [ $commit_opt -eq 0 ] && [ $reject_opt -eq 0 ] && usage + [ $commit_opt -eq 1 ] && [ $reject_opt -eq 1 ] && usage + manage_flash $commit_opt +fi