From 3e875391034567f93cc3386b75629d90f0093f42ba3dcfcecc7066f1cf017ee1 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 18 Feb 2014 15:59:15 +0000 Subject: [PATCH] Forgot another patch to add... OBS-URL: https://build.opensuse.org/package/show/systemsmanagement/ipmitool?expand=0&rev=22 --- ...it_head_31_01_2014_b0aad15d67007c74b.patch | 13828 ++++++++++++++++ 1 file changed, 13828 insertions(+) create mode 100644 ipmitool_update_to_git_head_31_01_2014_b0aad15d67007c74b.patch diff --git a/ipmitool_update_to_git_head_31_01_2014_b0aad15d67007c74b.patch b/ipmitool_update_to_git_head_31_01_2014_b0aad15d67007c74b.patch new file mode 100644 index 0000000..887e752 --- /dev/null +++ b/ipmitool_update_to_git_head_31_01_2014_b0aad15d67007c74b.patch @@ -0,0 +1,13828 @@ +diff --git a/ipmitool/AUTHORS b/ipmitool/AUTHORS +index 80ec56b..9589d87 100644 +--- a/ipmitool/AUTHORS ++++ b/ipmitool/AUTHORS +@@ -2,3 +2,4 @@ Duncan Laurie + Fredrik Öhrn + Jon Cassorla + Jeremy Ellington ++Petter Reinholdtsen +diff --git a/ipmitool/README b/ipmitool/README +index ebcb188..cc5915c 100644 +--- a/ipmitool/README ++++ b/ipmitool/README +@@ -410,3 +410,5 @@ http://www.intel.com/design/servers/ipmi/spec.htm + OpenIPMI project: Linux IPMI kernel driver and userland library + http://openipmi.sourceforge.net + ++IPMItool commit archive ++https://lists.sourceforge.net/lists/listinfo/ipmitool-cvs +diff --git a/ipmitool/configure.in b/ipmitool/configure.in +index d98d754..a42e158 100644 +--- a/ipmitool/configure.in ++++ b/ipmitool/configure.in +@@ -29,7 +29,7 @@ AC_C_BIGENDIAN + AC_FUNC_MALLOC + AC_FUNC_SELECT_ARGTYPES + AC_FUNC_STRTOD +-AC_CHECK_FUNCS([alarm gethostbyname socket select]) ++AC_CHECK_FUNCS([alarm gethostbyname getaddrinfo getifaddrs socket select]) + AC_CHECK_FUNCS([memmove memset strchr strdup strerror]) + AC_CHECK_FUNCS([getpassphrase]) + +@@ -39,6 +39,8 @@ AM_PROG_LIBTOOL + LIBTOOL="$LIBTOOL --silent" + + AC_SEARCH_LIBS([gethostbyname], [nsl]) ++AC_SEARCH_LIBS([getaddrinfo], [nsl]) ++AC_SEARCH_LIBS([getifaddrs], [nsl]) + AC_SEARCH_LIBS([socket], [socket], [], + [AC_CHECK_LIB([nsl], [socket], + [LIBS="$LIBS -lsocket -lnsl"], [], [-lsocket])]) +@@ -60,6 +62,7 @@ xenable_intf_imb=yes + xenable_intf_open=yes + xenable_intf_lipmi=yes + #xenable_intf_serial=yes ++xenable_intf_dummy=no + xenable_all_options=yes + xenable_ipmishell=yes + +@@ -106,6 +109,11 @@ solaris*) + xenable_intf_bmc=no + xenable_intf_open=no + ;; ++gnu*) ++ # disable the linux and solaris-specific interfaces on Hurd ++ xenable_intf_imb=no ++ xenable_intf_open=no ++ ;; + esac + + AC_SUBST(ARCH, $host_cpu) +@@ -503,6 +511,18 @@ if test "x$xenable_intf_bmc" = "xyes"; then + IPMITOOL_INTF_LIB="$IPMITOOL_INTF_LIB bmc/libintf_bmc.la" + fi + ++dnl enable Dummy interface for testing ++AC_ARG_ENABLE([intf-dummy], ++ [AC_HELP_STRING([--enable-intf-dummy], ++ [enable Dummy(test) interface [default=no]])], ++ [xenable_intf_dummy=$enableval], [xenable_intf_dummy=no]) ++if test "x$xenable_intf_dummy" = "xyes"; then ++ AC_DEFINE(IPMI_INTF_DUMMY, [1], [Define to 1 to enable Dummy interface.]) ++ AC_SUBST(INTF_DUMMY, [dummy]) ++ AC_SUBST(INTF_DUMMY_LIB, [libintf_dummy.la]) ++ IPMITOOL_INTF_LIB="$IPMITOOL_INTF_LIB dummy/libintf_dummy.la" ++fi ++ + AC_SUBST(IPMITOOL_INTF_LIB) + + if test "x$xenable_ipmishell" = "xyes"; then +@@ -602,7 +622,8 @@ AC_CONFIG_FILES([Makefile + src/plugins/imb/Makefile + src/plugins/bmc/Makefile + src/plugins/lipmi/Makefile +- src/plugins/serial/Makefile]) ++ src/plugins/serial/Makefile ++ src/plugins/dummy/Makefile]) + + AC_OUTPUT + +@@ -618,6 +639,7 @@ AC_MSG_RESULT([ imb : $xenable_intf_imb]) + AC_MSG_RESULT([ bmc : $xenable_intf_bmc]) + AC_MSG_RESULT([ lipmi : $xenable_intf_lipmi]) + AC_MSG_RESULT([ serial : $xenable_intf_serial]) ++AC_MSG_RESULT([ dummy : $xenable_intf_dummy]) + AC_MSG_RESULT([]) + AC_MSG_RESULT([Extra tools]) + AC_MSG_RESULT([ ipmievd : yes]) +diff --git a/ipmitool/contrib/Makefile.am b/ipmitool/contrib/Makefile.am +index a04f92f..c067dcb 100644 +--- a/ipmitool/contrib/Makefile.am ++++ b/ipmitool/contrib/Makefile.am +@@ -34,6 +34,8 @@ dist_pkgdata_DATA = oem_ibm_sel_map + + EXTRA_DIST = README \ + bmclanconf ipmi.init.basic ipmi.init.redhat \ ++ exchange-bmc-os-info.init.redhat exchange-bmc-os-info.service.redhat \ ++ exchange-bmc-os-info.sysconf \ + ipmievd.init.redhat ipmievd.init.suse ipmievd.init.debian \ + collect_data.sh create_rrds.sh create_webpage_compact.sh create_webpage.sh \ + bmc-snmp-proxy bmc-snmp-proxy.service bmc-snmp-proxy.sysconf +diff --git a/ipmitool/contrib/exchange-bmc-os-info.init.redhat b/ipmitool/contrib/exchange-bmc-os-info.init.redhat +new file mode 100644 +index 0000000..b7ec43f +--- /dev/null ++++ b/ipmitool/contrib/exchange-bmc-os-info.init.redhat +@@ -0,0 +1,326 @@ ++#!/bin/sh ++############################################################################# ++# ++# exchange-bmc-os-info: Set OS and BMC (Baseboard Management Controller) ++# parameters during system startup. ++# ++# version: 0.72 ++# ++# Authors: Charles Rose ++# Jordan Hargrave ++# ++# Description: Script to set OS information in the BMC; fetch BMC IP/URL ++# and set in the OS for use by other scripts/user. ++# ++# BMC IP and URL are made available in /var/run/bmc-info ++# ++# Example to launch BMC web-interface: ++# # . /var/run/bmc-info ++# # xdg-open $BMC_URL ++# ++# See here for details: ++# https://fedoraproject.org/wiki/Features/AgentFreeManagement ++# ++# OEM Specific: OEM specific ipmi commands go in: ++# 'oem_set_os_version' and 'oem_get_bmc_url' ++############################################################################# ++# ++# chkconfig: 345 99 00 ++# description: Set OS name, hostname in BMC; make BMC IP/URL available in OS ++# processname: exchange-bmc-os-info ++# config: /etc/sysconfig/exchange-bmc-os-info ++# ++### BEGIN INIT INFO ++# Provides: exchange-bmc-os-info ++# Required-Start: ipmi ++# Default-Start: 3 4 5 ++# Default-Stop: 0 1 2 6 ++ ++ ++############################################################################# ++# GLOBALS ++############################################################################# ++CONFIGFILE=/etc/sysconfig/exchange-bmc-os-info ++IPMI_TOOL=/usr/bin/ipmitool ++BMC_INFO=/var/run/bmc-info ++ ++# BMC Manufacturer ID used in 'oem_set_os_version' and 'oem_get_bmc_url' ++DELL="674" ++#OTHER_OEM="123" ++ ++# Defaults for ${CONFIGFILE} ++SET_OS_INFO="yes" ++RESET_OS_INFO="no" ++SET_BMC_INFO="yes" ++ ++# getsysinfo and setsysinfo commands ++IPMI_SET_SYSINFO="${IPMI_TOOL} mc setsysinfo" ++IPMI_GET_SYSINFO="${IPMI_TOOL} mc getsysinfo" ++############################################################################# ++SCRIPT_NAME=$(basename $0) ++ ++# source config ++[ -r ${CONFIGFILE} ] && . ${CONFIGFILE} ++ ++RETVAL=0 ++ ++if [ -f /bin/gettext.sh ]; then ++ GETTEXT=1 ++ . /bin/gettext.sh ++ OUTPUT="eval_gettext" ++else ++ GETTEXT=0 ++ OUTPUT="echo" ++fi ++ ++############################################################################# ++# Get Vendor ID of BMC for use in 'oem_set_os_version' and 'oem_get_bmc_url' ++# ++get_bmc_vendor_id() ++{ ++ BMC_VENDOR=$(${IPMI_TOOL} mc info 2>/dev/null | \ ++ sed -n "s#^Manufacturer ID.*: ##p") ++ [ -z "${BMC_VENDOR}" ] && RETVAL=4 ++} ++ ++check_ipmitool() ++{ ++ if [ -x ${IPMI_TOOL} ]; then ++ # v1.8.12 plus patches are required for set/getsysinfo support ++ # http://sourceforge.net/mailarchive/message.php?msg_id=29647222 ++ [ ! ${IPMI_GET_SYSINFO} >/dev/null 2>&1 ] && \ ++ RETVAL=3 ++ else ++ RETVAL=2 ++ fi ++} ++ ++bmc_exists() ++{ ++ check_ipmitool ++ [ $RETVAL -eq 0 ] && get_bmc_vendor_id ++ return $RETVAL ++} ++############################################################################# ++ ++get_os_info() ++{ ++ OS_HOSTNAME=$(hostname) ++ KERNEL_VERSION=$(uname -r -m) ++ ++ if [ -e /etc/lsb-release ] ; then ++ . /etc/lsb-release ++ NAME=${DISTRIB_ID} ++ VERSION="${DISTRIB_RELEASE} ${DISTRIB_CODENAME}" ++ fi ++ ++ # we prefer systemd's /etc/os-release over other sources ++ [ -e /etc/os-release ] && . /etc/os-release ++ ++ OS_NAME=${NAME} ++ OS_VERSION="${VERSION} kernel ${KERNEL_VERSION}" ++} ++ ++oem_set_os_version() ++{ ++ # OS Version setting is not standard yet ++ # we need per vendor oem commands ++ case "${BMC_VENDOR}" in ++ $DELL) ${IPMI_SET_SYSINFO} delloem_os_version \ ++ "${OS_VERSION}" > /dev/null 2>&1 ++ return $? ++ ;; ++# Add OEM specific commands. ++# Example: ++# $OTHER_OEM) ${IPMI_SET_SYSINFO} otheroem_os_version \ ++# "${OS_VERSION}" > /dev/null 2>&1 ++# return $? ++# ;; ++ *) return 0 ++ ;; ++ esac ++} ++ ++set_os_info() ++{ ++ # Set and reset OS info in the BMC ++ if [ "$1" = "reset" ]; then ++ OS_NAME="" ++ OS_HOSTNAME="" ++ OS_VERSION="" ++ fi ++ ++ ${IPMI_SET_SYSINFO} os_name "${OS_NAME}" >/dev/null 2>&1 \ ++ || RETVAL=6 ++ ${IPMI_SET_SYSINFO} primary_os_name "${OS_NAME}" >/dev/null 2>&1 \ ++ || RETVAL=6 ++ ${IPMI_SET_SYSINFO} system_name "${OS_HOSTNAME}" >/dev/null 2>&1 \ ++ || RETVAL=6 ++ oem_set_os_version || RETVAL=6 ++} ++ ++############################################################################# ++valid_url() ++{ ++ url="(https?|http)://[a-z0-9-]+(\.[a-z0-9-]+)+([/?].*)?" ++ printf -- "%s" "${TMP_URL}"| grep -Eq "^${url}" ++ return $? ++} ++ ++oem_get_bmc_url() ++{ ++ # BMC URL is not standard yet ++ # we need per vendor oem commands ++ case "$BMC_VENDOR" in ++ $DELL) TMP_URL=$(${IPMI_GET_SYSINFO} delloem_url 2> /dev/null) ++ ;; ++# Add OEM specific commands ++# Example: ++# $OTHER_OEM) ++# TMP_URL=$(${IPMI_GET_SYSINFO} otheroem_url 2> /dev/null) ++# ;; ++ *) TMP_URL="" ;; ++ esac ++ ++ valid_url && BMC_URL=${TMP_URL} || BMC_URL="" ++} ++ ++valid_ip() ++{ ++ #Thanks to mkyong.com ++ octet="([01]?[[:digit:]][[:digit:]]?|2[0-4][[:digit:]]|25[0-5])" ++ ++ printf -- "%s" "${TMP_IPv4}"| grep -Eq "^${octet}\\.${octet}\\.${octet}\\.${octet}$" ++ return $? ++} ++ ++get_bmc_ip() ++{ ++ #Thanks to http://ingvar.blog.redpill-linpro.com ++ for CHANNEL in `seq 1 14` ++ do ++ [ $(${IPMI_TOOL} lan print ${CHANNEL} 2>/dev/null \ ++ | grep -q "^Set") ] || break ++ done ++ ++ # Get BMC_IPv4 and BMC_URL from BMC ++ TMP_IPv4=$(${IPMI_TOOL} lan print ${CHANNEL} 2>/dev/null \ ++ | sed -n "s#^IP Address .*: ##p") ++ ++ valid_ip && BMC_IPv4=${TMP_IPv4} || BMC_IPv4="" ++} ++ ++get_bmc_info() ++{ ++ get_bmc_ip ++ if [ -z "${BMC_IPv4}" ] || [ "${BMC_IPv4}" = "0.0.0.0" ]; then ++ BMC_IPv4="" ++ RETVAL=5 ++ else ++ # URL makes sense only if there is an IP ++ oem_get_bmc_url ++ fi ++} ++ ++set_bmc_info() ++{ ++ if [ ! $(touch "${BMC_INFO}" && chmod 600 "${BMC_INFO}") ]; then ++ printf "BMC_IPv4=%s\n" "${BMC_IPv4}" > "${BMC_INFO}" ++ [ -n "${BMC_URL}" ] && \ ++ printf "BMC_URL=%s\n" "${BMC_URL}" >> "${BMC_INFO}" ++ else ++ RETVAL=5 ++ fi ++} ++ ++unset_bmc_info() ++{ ++ [ -f ${BMC_INFO} ] && rm -f ${BMC_INFO} > /dev/null 2>&1 ++} ++ ++############################################################################# ++start() ++{ ++ if bmc_exists; then ++ [ "${SET_OS_INFO}" = "yes" ] && \ ++ get_os_info && set_os_info ++ ++ if [ "${SET_BMC_INFO}" = "yes" ]; then ++ get_bmc_info ++ if [ ${RETVAL} -eq 0 ]; then ++ set_bmc_info ++ fi ++ fi ++ fi ++} ++ ++############################################################################# ++stop() ++{ ++ if bmc_exists; then ++ # reset OS info while system reboots ++ # aids with debugging OS boot-up issues ++ if [ "${RESET_OS_INFO}" = "yes" ]; then ++ set_os_info reset ++ fi ++ unset_bmc_info ++ fi ++} ++ ++############################################################################# ++restart() ++{ ++ stop ++ [ $RETVAL -eq 0 ] && start ++} ++ ++############################################################################# ++status() ++{ ++ [ -r ${BMC_INFO} ] && \ ++ grep -q "BMC_IPv4" "${BMC_INFO}" >/dev/null 1>&2 && \ ++ BMC_STATUS="ok" || BMC_STATUS="inactive" ++ ${OUTPUT} "${SCRIPT_NAME}: ${BMC_STATUS}" 1>&2 ++ [ ${GETTEXT} -eq 1 ] && echo ++} ++ ++############################################################################# ++usage() ++{ ++ ${OUTPUT} "Usage: ${SCRIPT_NAME} {start|stop|restart|status}" 1>&2 ++ [ ${GETTEXT} -eq 1 ] && echo ++ RETVAL=1 ++} ++ ++############################################################################# ++# MAIN ++############################################################################# ++case "$1" in ++ start) start ;; ++ stop) stop ;; ++ restart) restart ;; ++ status) status ;; ++ *) usage ;; ++esac ++ ++case "$RETVAL" in ++ 0|1) ;; ++ 2) ${OUTPUT} "${SCRIPT_NAME}: ipmitool(1) not found." 1>&2 ;; ++ 3) ${OUTPUT} "${SCRIPT_NAME}: this version of ipmitool does not support getsysinfo." 1>&2 ;; ++ 4) ${OUTPUT} "${SCRIPT_NAME}: failed to communicate with BMC." 1>&2 ;; ++ 5) ${OUTPUT} "${SCRIPT_NAME}: failed to set OS information in BMC." 1>&2 ;; ++ 6) ${OUTPUT} "${SCRIPT_NAME}: failed to get BMC information." 1>&2 ;; ++ *) ${OUTPUT} "${SCRIPT_NAME}: unexpected error." 1>&2 ;; ++esac ++ ++if [ ${RETVAL} -gt 1 ]; then ++ ${OUTPUT} " Return code: ${RETVAL}" 1>&2 ++ [ ${GETTEXT} -eq 1 ] && echo ++fi ++ ++ ++exit ${RETVAL} ++ ++############################################################################# ++# end of file ++############################################################################# +diff --git a/ipmitool/contrib/exchange-bmc-os-info.service.redhat b/ipmitool/contrib/exchange-bmc-os-info.service.redhat +new file mode 100644 +index 0000000..100493b +--- /dev/null ++++ b/ipmitool/contrib/exchange-bmc-os-info.service.redhat +@@ -0,0 +1,13 @@ ++[Unit] ++Description=Exchange Information between BMC and OS ++After=ipmi.service network.target ++Requires=ipmi.service ++ ++[Service] ++Type=oneshot ++RemainAfterExit=yes ++ExecStart=/usr/libexec/exchange-bmc-os-info start ++ExecStop=/usr/libexec/exchange-bmc-os-info stop ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/ipmitool/contrib/exchange-bmc-os-info.sysconf b/ipmitool/contrib/exchange-bmc-os-info.sysconf +new file mode 100644 +index 0000000..2f0e675 +--- /dev/null ++++ b/ipmitool/contrib/exchange-bmc-os-info.sysconf +@@ -0,0 +1,26 @@ ++# exchange-bmc-os-info ++# ++# Config file to control Exchange of information between ++# the OS and Service Processor/Baseboard Management Controller (BMC) ++# ++# See here for details ++# https://fedoraproject.org/wiki/Features/AgentFreeManagement ++ ++### Set OS Info in BMC/Service Processor ### ++# Name: SET_OS_INFO ++# Description: Set OS Name, Version and Hostname in the Service Processor (BMC) ++# Default: yes ++SET_OS_INFO="yes" ++ ++### Reset OS Info in BMC/Service Processor ### ++# Name: RESET_OS_INFO ++# Description: Reset OS Name, Version and Hostname in the Service Processor (BMC). ++# Useful when the OS Name/Hostname should be empty on reboot ++# Default: no ++RESET_OS_INFO="no" ++ ++### Set BMC/Service Processor Info in OS ### ++# Name; SET_BMC_INFO ++# Description: Set IP Address and URL of Service Processor/BMC in /run/bmc-info ++# Default: yes ++SET_BMC_INFO="yes" +diff --git a/ipmitool/include/ipmitool/helper.h b/ipmitool/include/ipmitool/helper.h +index 4b80058..b6ee7fa 100644 +--- a/ipmitool/include/ipmitool/helper.h ++++ b/ipmitool/include/ipmitool/helper.h +@@ -99,6 +99,7 @@ void printbuf(const uint8_t * buf, int len, const char * desc); + uint8_t ipmi_csum(uint8_t * d, int s); + FILE * ipmi_open_file(const char * file, int rw); + void ipmi_start_daemon(struct ipmi_intf *intf); ++uint16_t ipmi_get_oem_id(struct ipmi_intf *intf); + + #define ipmi_open_file_read(file) ipmi_open_file(file, 0) + #define ipmi_open_file_write(file) ipmi_open_file(file, 1) +diff --git a/ipmitool/include/ipmitool/ipmi.h b/ipmitool/include/ipmitool/ipmi.h +index e74c252..1fd3e2a 100644 +--- a/ipmitool/include/ipmitool/ipmi.h ++++ b/ipmitool/include/ipmitool/ipmi.h +@@ -281,7 +281,8 @@ typedef enum IPMI_OEM { + IPMI_OEM_KONTRON = 15000, + IPMI_OEM_PPS = 16394, + IPMI_OEM_AMI = 20974, +- IPMI_OEM_NOKIA_SIEMENS_NETWORKS = 28458 ++ IPMI_OEM_NOKIA_SIEMENS_NETWORKS = 28458, ++ IPMI_OEM_SUPERMICRO_47488 = 47488 + } IPMI_OEM; + + extern const struct valstr completion_code_vals[]; +diff --git a/ipmitool/include/ipmitool/ipmi_fru.h b/ipmitool/include/ipmitool/ipmi_fru.h +index 6833dd4..4d255a8 100644 +--- a/ipmitool/include/ipmitool/ipmi_fru.h ++++ b/ipmitool/include/ipmitool/ipmi_fru.h +@@ -63,6 +63,8 @@ enum { + struct fru_info { + uint16_t size; + uint8_t access:1; ++ uint8_t max_read_size; ++ uint8_t max_write_size; + }; + + #ifdef HAVE_PRAGMA_PACK +@@ -70,13 +72,16 @@ struct fru_info { + #endif + struct fru_header { + uint8_t version; +- struct { +- uint8_t internal; +- uint8_t chassis; +- uint8_t board; +- uint8_t product; +- uint8_t multi; +- } offset; ++ union { ++ struct { ++ uint8_t internal; ++ uint8_t chassis; ++ uint8_t board; ++ uint8_t product; ++ uint8_t multi; ++ } offset; ++ uint8_t offsets[5]; ++ }; + uint8_t pad; + uint8_t checksum; + }ATTRIBUTE_PACKING; +@@ -598,6 +603,20 @@ static const char * chassis_type_desc[] __attribute__((unused)) = { + "AdvancedTCA", "Blade", "Blade Enclosure" + }; + ++typedef struct ipmi_fru_bloc { ++ struct ipmi_fru_bloc * next; ++ uint16_t start; ++ uint16_t size; ++ uint8_t blocId[32]; ++} t_ipmi_fru_bloc; ++ ++static const char *section_id[4] = { ++ "Internal Use Section", ++ "Chassis Section", ++ "Board Section", ++ "Product Section" ++}; ++ + int ipmi_fru_main(struct ipmi_intf *intf, int argc, char **argv); + int ipmi_fru_print(struct ipmi_intf *intf, struct sdr_record_fru_locator *fru); + +diff --git a/ipmitool/include/ipmitool/ipmi_fwum.h b/ipmitool/include/ipmitool/ipmi_fwum.h +index 712428f..c19a582 100644 +--- a/ipmitool/include/ipmitool/ipmi_fwum.h ++++ b/ipmitool/include/ipmitool/ipmi_fwum.h +@@ -31,12 +31,213 @@ + */ + + #ifndef IPMI_KFWUM_H +-#define IPMI_KFWUM_H ++# define IPMI_KFWUM_H + + #include + #include + ++/* KFWUM Version */ ++# define VER_MAJOR 1 ++# define VER_MINOR 3 ++/* Minimum size (IPMB/IOL/old protocol) */ ++# define KFWUM_SMALL_BUFFER 32 ++/* Maximum size on KCS interface */ ++# define KFWUM_BIG_BUFFER 32 ++# define MAX_BUFFER_SIZE 1024*16 ++ ++/* 3 address + 1 size + 1 checksum + 1 command */ ++# define KFWUM_OLD_CMD_OVERHEAD 6 ++/* 1 sequence + 1 size + 1 checksum + 1 command */ ++# define KFWUM_NEW_CMD_OVERHEAD 4 ++# define KFWUM_PAGE_SIZE 256 ++ ++# define FWUM_SAVE_FIRMWARE_NO_RESPONSE_LIMIT 6 ++# define FWUM_MAX_UPLOAD_RETRY 6 ++ ++# define TRACE_LOG_CHUNK_COUNT 7 ++# define TRACE_LOG_CHUNK_SIZE 7 ++# define TRACE_LOG_ATT_COUNT 3 ++ ++# define IN_FIRMWARE_INFO_OFFSET_LOCATION 0x5a0 ++# define IN_FIRMWARE_INFO_SIZE 20 ++# define IN_FIRMWARE_INFO_OFFSET_FILE_SIZE 0 ++# define IN_FIRMWARE_INFO_OFFSET_CHECKSUM 4 ++# define IN_FIRMWARE_INFO_OFFSET_BOARD_ID 6 ++# define IN_FIRMWARE_INFO_OFFSET_DEVICE_ID 8 ++# define IN_FIRMWARE_INFO_OFFSET_TABLE_VERSION 9 ++# define IN_FIRMWARE_INFO_OFFSET_IMPLEMENT_REV 10 ++# define IN_FIRMWARE_INFO_OFFSET_VER_MAJOROR 11 ++# define IN_FIRMWARE_INFO_OFFSET_VER_MINORSUB 12 ++# define IN_FIRMWARE_INFO_OFFSET_SDR_REV 13 ++# define IN_FIRMWARE_INFO_OFFSET_IANA0 14 ++# define IN_FIRMWARE_INFO_OFFSET_IANA1 15 ++# define IN_FIRMWARE_INFO_OFFSET_IANA2 16 ++ ++# define KWUM_GET_BYTE_AT_OFFSET(pBuffer,os) pBuffer[os] + + int ipmi_fwum_main(struct ipmi_intf *, int, char **); + ++typedef enum eKFWUM_BoardList ++{ ++ KFWUM_BOARD_KONTRON_UNKNOWN = 0, ++ KFWUM_BOARD_KONTRON_5002 = 5002, ++} tKFWUM_BoardList; ++ ++typedef struct sKFWUM_BoardInfo ++{ ++ tKFWUM_BoardList boardId; ++ IPMI_OEM iana; ++} tKFWUM_BoardInfo; ++ ++typedef enum eKFWUM_DownloadType ++{ ++ KFWUM_DOWNLOAD_TYPE_ADDRESS = 0, ++ KFWUM_DOWNLOAD_TYPE_SEQUENCE, ++} tKFWUM_DownloadType; ++ ++typedef enum eKFWUM_DownloadBuffferType ++{ ++ KFWUM_SMALL_BUFFER_TYPE = 0, ++ KFUMW_BIG_BUFFER_TYPE ++} tKFWUM_DownloadBuffferType; ++ ++typedef struct sKFWUM_InFirmwareInfo ++{ ++ unsigned long fileSize; ++ unsigned short checksum; ++ unsigned short sumToRemoveFromChecksum; ++ /* Since the checksum is added in the bin ++ * after the checksum is calculated, we ++ * need to remove the each byte value. This ++ * byte will contain the addition of both bytes ++ */ ++ tKFWUM_BoardList boardId; ++ unsigned char deviceId; ++ unsigned char tableVers; ++ unsigned char implRev; ++ unsigned char versMajor; ++ unsigned char versMinor; ++ unsigned char versSubMinor; ++ unsigned char sdrRev; ++ IPMI_OEM iana; ++} tKFWUM_InFirmwareInfo; ++ ++typedef struct sKFWUM_SaveFirmwareInfo ++{ ++ tKFWUM_DownloadType downloadType; ++ unsigned char bufferSize; ++ unsigned char overheadSize; ++} tKFWUM_SaveFirmwareInfo; ++ ++/* COMMANDS */ ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(1) ++# endif ++struct KfwumGetInfoResp { ++ unsigned char protocolRevision; ++ unsigned char controllerDeviceId; ++ struct { ++ unsigned char mode:1; ++ unsigned char seqAdd:1; ++ unsigned char res : 6; ++ } byte; ++ unsigned char firmRev1; ++ unsigned char firmRev2; ++ unsigned char numBank; ++} ATTRIBUTE_PACKING; ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(0) ++# endif ++ ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(1) ++# endif ++struct KfwumGetStatusResp { ++ unsigned char bankState; ++ unsigned char firmLengthLSB; ++ unsigned char firmLengthMid; ++ unsigned char firmLengthMSB; ++ unsigned char firmRev1; ++ unsigned char firmRev2; ++ unsigned char firmRev3; ++} ATTRIBUTE_PACKING; ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(0) ++# endif ++ ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(1) ++# endif ++struct KfwumManualRollbackReq { ++ unsigned char type; ++} ATTRIBUTE_PACKING; ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(0) ++# endif ++ ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(1) ++# endif ++struct KfwumStartFirmwareDownloadReq { ++ unsigned char lengthLSB; ++ unsigned char lengthMid; ++ unsigned char lengthMSB; ++ unsigned char paddingLSB; ++ unsigned char paddingMSB; ++ unsigned char useSequence; ++} ATTRIBUTE_PACKING; ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(0) ++# endif ++ ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(1) ++# endif ++struct KfwumStartFirmwareDownloadResp { ++ unsigned char bank; ++} ATTRIBUTE_PACKING; ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(0) ++# endif ++ ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(1) ++# endif ++struct KfwumSaveFirmwareAddressReq ++{ ++ unsigned char addressLSB; ++ unsigned char addressMid; ++ unsigned char addressMSB; ++ unsigned char numBytes; ++ unsigned char txBuf[KFWUM_SMALL_BUFFER-KFWUM_OLD_CMD_OVERHEAD]; ++} ATTRIBUTE_PACKING; ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(0) ++# endif ++ ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(1) ++# endif ++struct KfwumSaveFirmwareSequenceReq ++{ ++ unsigned char sequenceNumber; ++ unsigned char txBuf[KFWUM_BIG_BUFFER]; ++} ATTRIBUTE_PACKING; ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(0) ++# endif ++ ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(1) ++# endif ++struct KfwumFinishFirmwareDownloadReq { ++ unsigned char versionMaj; ++ unsigned char versionMinSub; ++ unsigned char versionSdr; ++ unsigned char reserved; ++} ATTRIBUTE_PACKING; ++# ifdef HAVE_PRAGMA_PACK ++# pragma pack(0) ++# endif ++ + #endif /* IPMI_KFWUM_H */ +diff --git a/ipmitool/include/ipmitool/ipmi_hpmfwupg.h b/ipmitool/include/ipmitool/ipmi_hpmfwupg.h +index c464ad4..305091e 100644 +--- a/ipmitool/include/ipmitool/ipmi_hpmfwupg.h ++++ b/ipmitool/include/ipmitool/ipmi_hpmfwupg.h +@@ -38,4 +38,771 @@ + + int ipmi_hpmfwupg_main(struct ipmi_intf *, int, char **); + ++/* Agent version */ ++#define HPMFWUPG_VERSION_MAJOR 1 ++#define HPMFWUPG_VERSION_MINOR 0 ++#define HPMFWUPG_VERSION_SUBMINOR 9 ++ ++/* HPM.1 FIRMWARE UPGRADE COMMANDS (part of PICMG) */ ++#define HPMFWUPG_GET_TARGET_UPG_CAPABILITIES 0x2E ++#define HPMFWUPG_GET_COMPONENT_PROPERTIES 0x2F ++#define HPMFWUPG_ABORT_UPGRADE 0x30 ++#define HPMFWUPG_INITIATE_UPGRADE_ACTION 0x31 ++#define HPMFWUPG_UPLOAD_FIRMWARE_BLOCK 0x32 ++#define HPMFWUPG_FINISH_FIRMWARE_UPLOAD 0x33 ++#define HPMFWUPG_GET_UPGRADE_STATUS 0x34 ++#define HPMFWUPG_ACTIVATE_FIRMWARE 0x35 ++#define HPMFWUPG_QUERY_SELFTEST_RESULT 0x36 ++#define HPMFWUPG_QUERY_ROLLBACK_STATUS 0x37 ++#define HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK 0x38 ++ ++/* HPM.1 SPECIFIC COMPLETION CODES */ ++#define HPMFWUPG_ROLLBACK_COMPLETED 0x00 ++#define HPMFWUPG_COMMAND_IN_PROGRESS 0x80 ++#define HPMFWUPG_NOT_SUPPORTED 0x81 ++#define HPMFWUPG_SIZE_MISMATCH 0x81 ++#define HPMFWUPG_ROLLBACK_FAILURE 0x81 ++#define HPMFWUPG_INV_COMP_MASK 0x81 ++#define HPMFWUPG__ABORT_FAILURE 0x81 ++#define HPMFWUPG_INV_COMP_ID 0x82 ++#define HPMFWUPG_INT_CHECKSUM_ERROR 0x82 ++#define HPMFWUPG_INV_UPLOAD_MODE 0x82 ++#define HPMFWUPG_ROLLBACK_OVERRIDE 0x82 ++#define HPMFWUPG_INV_COMP_PROP 0x83 ++#define HPMFWUPG_FW_MISMATCH 0x83 ++#define HPMFWUPG_ROLLBACK_DENIED 0x83 ++ ++/* ++ * This error code is used as a temporary PATCH to ++ * the latest Open ipmi driver. This PATCH ++ * will be removed once a new Open IPMI driver is released. ++ * (Buggy version = 39) ++ */ ++#define ENABLE_OPENIPMI_V39_PATCH ++ ++#ifdef ENABLE_OPENIPMI_V39_PATCH ++# define RETRY_COUNT_MAX 3 ++static int errorCount; ++# define HPMFWUPG_IS_RETRYABLE(error) \ ++ ((((error==0x83)||(error==0x82)||(error==0x80)) && (errorCount++ + #include + #include ++#include + + #if HAVE_CONFIG_H + # include +@@ -663,9 +664,10 @@ ipmi_start_daemon(struct ipmi_intf *intf) + close(fd); + } + +- open("/dev/null", O_RDWR); +- dup(0); +- dup(0); ++ fd = open("/dev/null", O_RDWR); ++ assert(0 == fd); ++ dup(fd); ++ dup(fd); + } + + /* is_fru_id - wrapper for str-2-int FRU ID conversion. Message is printed +@@ -756,3 +758,32 @@ is_ipmi_user_id(const char *argv_ptr, uint8_t *ipmi_uid_ptr) + IPMI_UID_MIN, IPMI_UID_MAX); + return (-1); + } ++ ++uint16_t ++ipmi_get_oem_id(struct ipmi_intf *intf) ++{ ++ /* Execute a Get Board ID command to determine the board */ ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint16_t oem_id; ++ ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_TSOL; ++ req.msg.cmd = 0x21; ++ req.msg.data_len = 0; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Get Board ID command failed"); ++ return 0; ++ } ++ if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "Get Board ID command failed: %#x %s", ++ rsp->ccode, val2str(rsp->ccode, completion_code_vals)); ++ return 0; ++ } ++ oem_id = rsp->data[0] | (rsp->data[1] << 8); ++ lprintf(LOG_DEBUG,"Board ID: %x", oem_id); ++ ++ return oem_id; ++} +diff --git a/ipmitool/lib/ipmi_dcmi.c b/ipmitool/lib/ipmi_dcmi.c +index ff9646c..0cce769 100755 +--- a/ipmitool/lib/ipmi_dcmi.c ++++ b/ipmitool/lib/ipmi_dcmi.c +@@ -481,44 +481,14 @@ ipmi_dcmi_prnt_oobDiscover(struct ipmi_intf * intf) + intf->abort = 1; + intf->session->sol_data.sequence_number = 1; + +- /* open port to BMC */ +- memset(&s->addr, 0, sizeof(struct sockaddr_in)); +- s->addr.sin_family = AF_INET; +- s->addr.sin_port = htons(s->port); +- +- rc = inet_pton(AF_INET, (const char *)s->hostname, &s->addr.sin_addr); +- if (rc <= 0) { +- struct hostent *host = gethostbyname((const char *)s->hostname); +- if (host == NULL) { +- lprintf(LOG_ERR, "Address lookup for %s failed", +- s->hostname); +- return -1; +- } +- if (host->h_addrtype != AF_INET) { +- lprintf(LOG_ERR, +- "Address lookup for %s failed. Got %s, expected IPv4 address.", +- s->hostname, +- (host->h_addrtype == AF_INET6) ? "IPv6" : "Unknown"); +- return (-1); +- } +- s->addr.sin_family = host->h_addrtype; +- memcpy(&s->addr.sin_addr, host->h_addr, host->h_length); +- } +- +- lprintf(LOG_DEBUG, "IPMI LAN host %s port %d", +- s->hostname, ntohs(s->addr.sin_port)); +- +- intf->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); +- if (intf->fd < 0) { +- lperror(LOG_ERR, "Socket failed"); ++ if (ipmi_intf_socket_connect(intf) == -1) { ++ lprintf(LOG_ERR, "Could not open socket!"); + return -1; + } + +- /* connect to UDP socket so we get async errors */ +- rc = connect(intf->fd, (struct sockaddr *)&s->addr, +- sizeof(struct sockaddr_in)); +- if (rc < 0) { +- lperror(LOG_ERR, "Connect failed"); ++ if (intf->fd < 0) { ++ lperror(LOG_ERR, "Connect to %s failed", ++ s->hostname); + intf->close(intf); + return -1; + } +diff --git a/ipmitool/lib/ipmi_delloem.c b/ipmitool/lib/ipmi_delloem.c +index b4e541a..e190cd4 100644 +--- a/ipmitool/lib/ipmi_delloem.c ++++ b/ipmitool/lib/ipmi_delloem.c +@@ -3232,7 +3232,7 @@ ipmi_get_avgpower_consmpt_history(struct ipmi_intf * intf, + if (verbose > 1) { + rdata = (void *)pavgpower; + printf("Average power consumption history data" +- " :%x %x %x %x %x %x %x\n\n", ++ " :%x %x %x %x %x %x %x %x\n\n", + rdata[0], rdata[1], rdata[2], rdata[3], + rdata[4], rdata[5], rdata[6], rdata[7]); + } +@@ -3281,7 +3281,7 @@ ipmi_get_peakpower_consmpt_history(struct ipmi_intf * intf, + rdata = (void *)pstPeakpower; + printf("Peak power consmhistory Data : " + "%x %x %x %x %x %x %x %x %x %x\n " +- "%x %x %x %x %x %x %x %x %x %x %x %x %x\n\n", ++ "%x %x %x %x %x %x %x %x %x %x %x %x %x %x\n\n", + rdata[0], rdata[1], rdata[2], rdata[3], + rdata[4], rdata[5], rdata[6], rdata[7], + rdata[8], rdata[9], rdata[10], rdata[11], +@@ -3633,7 +3633,7 @@ ipmi_set_power_cap(struct ipmi_intf * intf, int unit, int val) + } + if (verbose > 1) { + rdata = (void *)&ipmipowercap; +- printf("power cap Data :%x %x %x %x %x %x %x %x %x %x ", ++ printf("power cap Data :%x %x %x %x %x %x %x %x %x %x %x ", + rdata[1], rdata[2], rdata[3], + rdata[4], rdata[5], rdata[6], rdata[7], + rdata[8], rdata[9], rdata[10],rdata[11]); +diff --git a/ipmitool/lib/ipmi_ekanalyzer.c b/ipmitool/lib/ipmi_ekanalyzer.c +index f2c9c82..2ac1012 100644 +--- a/ipmitool/lib/ipmi_ekanalyzer.c ++++ b/ipmitool/lib/ipmi_ekanalyzer.c +@@ -2745,6 +2745,8 @@ ipmi_ek_display_board_info_area(FILE * input_file, char * board_type, + ret = fread(data, size_board, 1, input_file); + if ((ret != 1) || ferror(input_file)) { + lprintf(LOG_ERR, "Invalid board type size!"); ++ free(data); ++ data = NULL; + goto out; + } + printf("%s type: 0x%02x\n", board_type, len); +@@ -2761,6 +2763,7 @@ ipmi_ek_display_board_info_area(FILE * input_file, char * board_type, + } + printf("\n"); + free(data); ++ data = NULL; + (*board_length) -= size_board; + goto out; + } +@@ -2807,6 +2810,7 @@ ipmi_ek_display_board_info_area(FILE * input_file, char * board_type, + } + printf("\n"); + free(additional_data); ++ additional_data = NULL; + (*board_length) -= size_board; + } + else { +@@ -2843,7 +2847,7 @@ out: + static int + ipmi_ek_display_product_info_area(FILE * input_file, long offset) + { +- size_t file_offset = ftell(input_file); ++ size_t file_offset; + int ret = 0; + unsigned char ch_len = 0; + unsigned char data = 0; +@@ -2853,6 +2857,7 @@ ipmi_ek_display_product_info_area(FILE * input_file, long offset) + lprintf(LOG_ERR, "No file stream to read."); + return (-1); + } ++ file_offset = ftell(input_file); + printf("%s\n", EQUAL_LINE_LIMITER); + printf("Product Info Area\n"); + printf("%s\n", EQUAL_LINE_LIMITER); +diff --git a/ipmitool/lib/ipmi_fru.c b/ipmitool/lib/ipmi_fru.c +index 6ba2ada..09d5abe 100644 +--- a/ipmitool/lib/ipmi_fru.c ++++ b/ipmitool/lib/ipmi_fru.c +@@ -48,16 +48,6 @@ + # include + #endif + +-/* +-* Apparently some systems have problems with FRU access greater than 16 bytes +-* at a time, even when using byte (not word) access. In order to ensure we +-* work with the widest variety of hardware request size is capped at 16 bytes. +-* Since this may result in slowdowns on some systems with lots of FRU data you +-* can undefine this to enable larger (up to 32 bytes at a time) access. +-* +-* TODO: make this a command line option +-*/ +-#define LIMIT_ALL_REQUEST_SIZE 1 + #define FRU_MULTIREC_CHUNK_SIZE (255 + sizeof(struct fru_multirec_header)) + + extern int verbose; +@@ -71,7 +61,7 @@ static int ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf, uint + static int ipmi_fru_get_multirec_from_file(char * pFileName, uint8_t * pBufArea, + uint32_t size, uint32_t offset); + static int ipmi_fru_get_multirec_size_from_file(char * pFileName, uint32_t * pSize, uint32_t * pOffset); +-int ipmi_fru_get_adjust_size_from_buffer(uint8_t * pBufArea, uint32_t *pSize); ++int ipmi_fru_get_adjust_size_from_buffer(uint8_t *pBufArea, uint32_t *pSize); + static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length); + + static int ipmi_fru_set_field_string(struct ipmi_intf * intf, unsigned +@@ -87,6 +77,7 @@ fru_area_print_multirec_bloc(struct ipmi_intf * intf, struct fru_info * fru, + int + read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, + uint32_t offset, uint32_t length, uint8_t *frubuf); ++void free_fru_bloc(t_ipmi_fru_bloc *bloc); + + /* get_fru_area_str - Parse FRU area string from raw data + * +@@ -235,30 +226,17 @@ is_valid_filename(const char *input_filename) + * returns -1 on error + */ + #define FRU_NUM_BLOC_COMMON_HEADER 6 +-typedef struct ipmi_fru_bloc +-{ +- uint16_t start; +- uint16_t size; +- uint8_t blocId[32]; +-}t_ipmi_fru_bloc; +- + t_ipmi_fru_bloc * +-build_fru_bloc(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, +- /* OUT */uint16_t * ptr_number_bloc) ++build_fru_bloc(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id) + { +- t_ipmi_fru_bloc * p_bloc; ++ t_ipmi_fru_bloc * p_first, * p_bloc, * p_new; + struct ipmi_rs * rsp; + struct ipmi_rq req; + struct fru_header header; +- uint8_t * fru_data = NULL; ++ struct fru_multirec_header rec_hdr; + uint8_t msg_data[4]; +- uint16_t num_bloc; +- uint16_t bloc_count; +- +- (* ptr_number_bloc) = 0; +- +- /*memset(&fru, 0, sizeof(struct fru_info));*/ +- memset(&header, 0, sizeof(struct fru_header)); ++ uint32_t off; ++ uint16_t i; + + /* + * get COMMON Header format +@@ -274,464 +252,322 @@ build_fru_bloc(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, + req.msg.data = msg_data; + req.msg.data_len = 4; + +- + rsp = intf->sendrecv(intf, &req); ++ + if (rsp == NULL) { +- lprintf(LOG_ERR, " Device not present (No Response)\n"); ++ lprintf(LOG_ERR, " Device not present (No Response)"); + return NULL; + } ++ + if (rsp->ccode > 0) { +- lprintf(LOG_ERR," Device not present (%s)\n", +- val2str(rsp->ccode, completion_code_vals)); ++ lprintf(LOG_ERR," Device not present (%s)", ++ val2str(rsp->ccode, completion_code_vals)); + return NULL; + } + +- if (verbose > 1) ++ if (verbose > 1) { + printbuf(rsp->data, rsp->data_len, "FRU DATA"); ++ } + + memcpy(&header, rsp->data + 1, 8); + ++ /* verify header checksum */ ++ if (ipmi_csum((uint8_t *)&header, 8)) { ++ lprintf(LOG_ERR, " Bad header checksum"); ++ return NULL; ++ } ++ + if (header.version != 1) { +- lprintf(LOG_ERR, " Unknown FRU header version 0x%02x", +- header.version); ++ lprintf(LOG_ERR, " Unknown FRU header version 0x%02x", header.version); + return NULL; + } + + /****************************************** +- Count the number of bloc ++ Malloc and fill up the bloc contents + *******************************************/ + + // Common header +- num_bloc = 1; +- // Internal +- if( header.offset.internal ) +- num_bloc ++; +- // Chassis +- if( header.offset.chassis ) +- num_bloc ++; +- // Board +- if( header.offset.board ) +- num_bloc ++; +- // Product +- if( header.offset.product ) +- num_bloc ++; +- +- // Multi +- if( header.offset.multi ) +- { +- +- uint32_t i; +- struct fru_multirec_header * h; +- uint32_t last_off, len; +- +- i = last_off = (header.offset.multi*8); +- //fru_len = 0; +- +- fru_data = malloc(fru->size + 1); +- if (fru_data == NULL) { +- lprintf(LOG_ERR, " Out of memory!"); +- return NULL; +- } +- +- memset(fru_data, 0, fru->size + 1); +- +- do { +- h = (struct fru_multirec_header *) (fru_data + i); +- +- // read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time +- if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len))) +- { +- len = fru->size - last_off; +- if (len > FRU_MULTIREC_CHUNK_SIZE) +- len = FRU_MULTIREC_CHUNK_SIZE; ++ p_first = malloc(sizeof(struct ipmi_fru_bloc)); ++ if (!p_first) { ++ lprintf(LOG_ERR, "ipmitool: malloc failure"); ++ return NULL; ++ } + +- if (read_fru_area(intf, fru, id, last_off, len, fru_data) < 0) +- break; ++ p_bloc = p_first; ++ p_bloc->next = NULL; ++ p_bloc->start= 0; ++ p_bloc->size = fru->size; ++ strcpy((char *)p_bloc->blocId, "Common Header Section"); + +- last_off += len; ++ for (i = 0; i < 4; i++) { ++ if (header.offsets[i]) { ++ p_new = malloc(sizeof(struct ipmi_fru_bloc)); ++ if (!p_new) { ++ lprintf(LOG_ERR, "ipmitool: malloc failure"); ++ free_fru_bloc(p_first); ++ return NULL; + } + +- num_bloc++; +- //printf("Bloc Numb : %i\n", counter); +- //printf("Bloc Start: %i\n", i); +- //printf("Bloc Size : %i\n", h->len); +- //printf("\n"); +- i += h->len + sizeof (struct fru_multirec_header); +- } while (!(h->format & 0x80) && ( last_off < fru->size)); ++ p_new->next = NULL; ++ p_new->start = header.offsets[i] * 8; ++ p_new->size = fru->size - p_new->start; + +- lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)",i,i); ++ strncpy((char *)p_new->blocId, section_id[i], sizeof(p_new->blocId)); ++ /* Make sure string is null terminated */ ++ p_new->blocId[sizeof(p_new->blocId)-1] = 0; + +- if(fru->size > i) +- { +- // Bloc for remaining space +- num_bloc ++; ++ p_bloc->next = p_new; ++ p_bloc->size = p_new->start - p_bloc->start; ++ p_bloc = p_new; + } + } +- else +- { +- /* Since there is no multi-rec area and no end delimiter, the remaining +- space will be added to the last bloc */ +- } +- +- + +- /****************************************** +- Malloc and fill up the bloc contents +- *******************************************/ +- p_bloc = malloc( sizeof( t_ipmi_fru_bloc ) * num_bloc ); +- if(!p_bloc) +- { +- lprintf(LOG_ERR, " Unable to get memory to build Fru bloc"); ++ // Multi ++ if (header.offset.multi) { ++ off = header.offset.multi * 8; + +- if (fru_data != NULL) { +- free(fru_data); +- fru_data = NULL; +- } ++ do { ++ /* ++ * check for odd offset for the case of fru devices ++ * accessed by words ++ */ ++ if (fru->access && (off & 1)) { ++ lprintf(LOG_ERR, " Unaligned offset for a block: %d", off); ++ /* increment offset */ ++ off++; ++ break; ++ } + +- return NULL; +- } ++ if (read_fru_area(intf, fru, id, off, 5, ++ (uint8_t *) &rec_hdr) < 0) { ++ break; ++ } + +- // Common header +- bloc_count = 0; ++ p_new = malloc(sizeof(struct ipmi_fru_bloc)); ++ if (!p_new) { ++ lprintf(LOG_ERR, "ipmitool: malloc failure"); ++ free_fru_bloc(p_first); ++ return NULL; ++ } + +- p_bloc[bloc_count].start= 0; +- p_bloc[bloc_count].size = 8; +- strcpy((char *)p_bloc[bloc_count].blocId, "Common Header Section"); +- bloc_count ++; ++ p_new->next = NULL; ++ p_new->start = off; ++ p_new->size = fru->size - p_new->start; ++ sprintf((char *)p_new->blocId, "Multi-Rec Area: Type %i", ++ rec_hdr.type); + +- // Internal +- if( header.offset.internal ) +- { +- p_bloc[bloc_count].start = (header.offset.internal * 8); +- p_bloc[bloc_count].size = 0; // Will be fillup later +- strcpy((char *)p_bloc[bloc_count].blocId, "Internal Use Section"); +- bloc_count ++; +- } +- // Chassis +- if( header.offset.chassis ) +- { +- p_bloc[bloc_count].start = (header.offset.chassis * 8); +- p_bloc[bloc_count].size = 0; // Will be fillup later +- strcpy((char *)p_bloc[bloc_count].blocId, "Chassis Section"); +- bloc_count ++; +- } +- // Board +- if( header.offset.board ) +- { +- p_bloc[bloc_count].start = (header.offset.board * 8); +- p_bloc[bloc_count].size = 0; // Will be fillup later +- strcpy((char *)p_bloc[bloc_count].blocId, "Board Section"); +- bloc_count ++; +- } +- // Product +- if( header.offset.product ) +- { +- p_bloc[bloc_count].start = (header.offset.product * 8); +- p_bloc[bloc_count].size = 0; // Will be fillup later +- strcpy((char *)p_bloc[bloc_count].blocId, "Product Section"); +- bloc_count ++; +- } +- +- // Multi-Record Area +- if( +- ( header.offset.multi ) +- && +- ( fru_data ) +- ) +- { +- uint32_t i = (header.offset.multi*8); +- struct fru_multirec_header * h; ++ p_bloc->next = p_new; ++ p_bloc->size = p_new->start - p_bloc->start; ++ p_bloc = p_new; + +- do { +- h = (struct fru_multirec_header *) (fru_data + i); ++ off += rec_hdr.len + sizeof(struct fru_multirec_header); + +- p_bloc[bloc_count].start = i; +- p_bloc[bloc_count].size = h->len + sizeof (struct fru_multirec_header); +- sprintf((char *)p_bloc[bloc_count].blocId, "Multi-Rec Aread: Type %i", h->type); +- bloc_count ++; +- /*printf("Bloc Start: %i\n", i); +- printf("Bloc Size : %i\n", h->len); +- printf("\n");*/ ++ /* verify record header */ ++ if (ipmi_csum((uint8_t *)&rec_hdr, ++ sizeof(struct fru_multirec_header))) { ++ /* can't reliably judge for the rest space */ ++ break; ++ } ++ } while (!(rec_hdr.format & 0x80) && (off < fru->size)); + +- i += h->len + sizeof (struct fru_multirec_header); ++ lprintf(LOG_DEBUG,"Multi-Record area ends at: %i (%xh)", off, off); + +- } while (!(h->format & 0x80) && ( bloc_count < num_bloc ) ); ++ if (fru->size > off) { ++ // Bloc for remaining space ++ p_new = malloc(sizeof(struct ipmi_fru_bloc)); ++ if (!p_new) { ++ lprintf(LOG_ERR, "ipmitool: malloc failure"); ++ free_fru_bloc(p_first); ++ return NULL; ++ } + +- lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)",i,i); +- /* If last bloc size was defined and is not until the end, create a +- last bloc with the remaining unused space */ ++ p_new->next = NULL; ++ p_new->start = off; ++ p_new->size = fru->size - p_new->start; ++ strcpy((char *)p_new->blocId, "Unused space"); + +- if((fru->size > i) && (bloc_count < num_bloc)) +- { +- // Bloc for remaining space +- p_bloc[bloc_count].start = i; +- p_bloc[bloc_count].size = (fru->size - i); +- sprintf((char *)p_bloc[bloc_count].blocId, "Unused space"); +- bloc_count ++; ++ p_bloc->next = p_new; ++ p_bloc->size = p_new->start - p_bloc->start; + } +- + } + +- if (fru_data != NULL) { +- free(fru_data); +- fru_data = NULL; ++ /* Dump blocs */ ++ for(p_bloc = p_first, i = 0; p_bloc; p_bloc = p_bloc->next) { ++ lprintf(LOG_DEBUG ,"Bloc Numb : %i", i++); ++ lprintf(LOG_DEBUG ,"Bloc Id : %s", p_bloc->blocId); ++ lprintf(LOG_DEBUG ,"Bloc Start: %i", p_bloc->start); ++ lprintf(LOG_DEBUG ,"Bloc Size : %i", p_bloc->size); ++ lprintf(LOG_DEBUG ,""); + } + +- /* Fill up size for first bloc */ +- { +- unsigned short counter; +- lprintf(LOG_DEBUG ,"\nNumber Bloc : %i\n", num_bloc); +- for(counter = 0; counter < (num_bloc); counter ++) +- { +- /* If size where not initialized, do it. */ +- if( p_bloc[counter].size == 0) +- { +- /* If not the last bloc, use the next bloc to determine the end */ +- if((counter+1) < num_bloc) +- { +- p_bloc[counter].size = (p_bloc[counter+1].start - p_bloc[counter].start); +- } +- else +- { +- p_bloc[counter].size = (fru->size - p_bloc[counter].start); +- } +- } +- lprintf(LOG_DEBUG ,"Bloc Numb : %i\n", counter); +- lprintf(LOG_DEBUG ,"Bloc Id : %s\n", p_bloc[counter].blocId); +- lprintf(LOG_DEBUG ,"Bloc Start: %i\n", p_bloc[counter].start); +- lprintf(LOG_DEBUG ,"Bloc Size : %i\n", p_bloc[counter].size); +- lprintf(LOG_DEBUG ,"\n"); +- } +- } ++ return p_first; ++} + +- (* ptr_number_bloc) = num_bloc; ++void ++free_fru_bloc(t_ipmi_fru_bloc *bloc) ++{ ++ t_ipmi_fru_bloc * del; + +- return p_bloc; ++ while (bloc) { ++ del = bloc; ++ bloc = bloc->next; ++ free(del); ++ del = NULL; ++ } + } + +- ++/* ++ * write FRU[doffset:length] from the pFrubuf[soffset:length] ++ * rc=1 on success ++**/ + int + write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, + uint16_t soffset, uint16_t doffset, + uint16_t length, uint8_t *pFrubuf) +-{ /* +- // fill in frubuf[offset:length] from the FRU[offset:length] +- // rc=1 on success +- */ +- static uint16_t fru_data_rqst_size = 32; +- uint16_t off=0, tmp, finish; ++{ ++ uint16_t tmp, finish; + struct ipmi_rs * rsp; + struct ipmi_rq req; +- uint8_t msg_data[256]; +- uint8_t writeLength; +- uint16_t num_bloc; ++ uint8_t msg_data[255+3]; ++ uint16_t writeLength; ++ uint16_t found_bloc = 0; + + finish = doffset + length; /* destination offset */ + if (finish > fru->size) + { +- lprintf(LOG_ERROR, "Return error\n"); ++ lprintf(LOG_ERROR, "Return error"); + return -1; + } + +- t_ipmi_fru_bloc * fru_bloc = build_fru_bloc(intf, fru, id, &num_bloc); +- +- if (fru_bloc == NULL) { +- lprintf(LOG_ERROR, "Failed to build FRU bloc."); ++ if (fru->access && ((doffset & 1) || (length & 1))) { ++ lprintf(LOG_ERROR, "Odd offset or length specified"); + return (-1); + } + ++ t_ipmi_fru_bloc * fru_bloc = build_fru_bloc(intf, fru, id); ++ t_ipmi_fru_bloc * saved_fru_bloc = fru_bloc; ++ + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = SET_FRU_DATA; + req.msg.data = msg_data; + +-#ifdef LIMIT_ALL_REQUEST_SIZE +- if (fru_data_rqst_size > 16) +-#else +- if (fru->access && fru_data_rqst_size > 16) +-#endif +- fru_data_rqst_size = 16; ++ /* initialize request size only once */ ++ if (fru->max_write_size == 0) { ++ if (intf->channel_buf_size != 0) { ++ /* subtract 1 byte for FRU ID an 2 bytes for offset */ ++ fru->max_write_size = intf->channel_buf_size - 3; ++ } else { ++ /* subtract 1 byte for FRU ID an 2 bytes for offset */ ++ fru->max_write_size = 32 - 3; ++ } + +- /* Check if we receive size in parameters */ +- if(intf->channel_buf_size != 0) +- { +- fru_data_rqst_size = intf->channel_buf_size - 5; /* Plan for overhead */ ++ /* check word access */ ++ if (fru->access) { ++ fru->max_write_size &= ~1; ++ } + } + + do { +- /* Temp init end_bloc to the end, if not found */ +- uint16_t end_bloc = finish; ++ uint16_t end_bloc; + uint8_t protected_bloc = 0; +- uint16_t found_bloc = 0xffff; +- +- /* real destination offset */ +- tmp = fru->access ? (doffset+off) >> 1 : (doffset+off); +- msg_data[0] = id; +- msg_data[1] = (uint8_t)tmp; +- msg_data[2] = (uint8_t)(tmp >> 8); + + /* Write per bloc, try to find the end of a bloc*/ +- { +- uint16_t counter; +- for(counter = 0; counter < (num_bloc); counter ++) +- { +- if( +- (tmp >= fru_bloc[counter].start) +- && +- (tmp < (fru_bloc[counter].start + fru_bloc[counter].size)) +- ) +- { +- found_bloc = counter; +- end_bloc = (fru_bloc[counter].start + fru_bloc[counter].size); +- counter = num_bloc; +- } +- } ++ while (fru_bloc && fru_bloc->start + fru_bloc->size <= doffset) { ++ fru_bloc = fru_bloc->next; ++ found_bloc++; + } + +- tmp = end_bloc - (doffset+off); /* bytes remaining for the bloc */ +- if (tmp > fru_data_rqst_size) { +- memcpy(&msg_data[3], pFrubuf + soffset + off, fru_data_rqst_size); +- req.msg.data_len = fru_data_rqst_size + 3; +- } +- else { +- memcpy(&msg_data[3], pFrubuf + soffset + off, (uint8_t)tmp); +- req.msg.data_len = tmp + 3; +- } +- if(found_bloc == 0) +- { +- lprintf(LOG_INFO,"Writing %d bytes", (req.msg.data_len-3)); +- } +- else if(found_bloc != 0xFFFF) +- { +- lprintf(LOG_INFO,"Writing %d bytes (Bloc #%i: %s)", +- (req.msg.data_len-3), +- found_bloc, fru_bloc[found_bloc].blocId); ++ if (fru_bloc && fru_bloc->start + fru_bloc->size < finish) { ++ end_bloc = fru_bloc->start + fru_bloc->size; ++ } else { ++ end_bloc = finish; + } + +- writeLength = req.msg.data_len-3; ++ /* calculate write length */ ++ tmp = end_bloc - doffset; + +- rsp = intf->sendrecv(intf, &req); +- if (!rsp) { +- break; ++ /* check that write length is more than maximum request size */ ++ if (tmp > fru->max_write_size) { ++ writeLength = fru->max_write_size; ++ } else { ++ writeLength = tmp; + } + +- if(rsp->ccode==0x80) // Write protected section +- { +- protected_bloc = 1; +- } +- else if ((rsp->ccode==0xc7 || rsp->ccode==0xc8 || rsp->ccode==0xca ) && +- --fru_data_rqst_size > 8) { +- lprintf(LOG_NOTICE,"Bad CC -> %x\n", rsp->ccode); +- break; /*continue;*/ +- } +- else if (rsp->ccode > 0) +- break; ++ /* copy fru data */ ++ memcpy(&msg_data[3], pFrubuf + soffset, writeLength); + +- if(protected_bloc == 0) +- { +- lprintf(LOG_INFO,"Wrote %d bytes", writeLength); +- off += writeLength; // Write OK, bloc not protected, continue ++ /* check word access */ ++ if (fru->access) { ++ writeLength &= ~1; + } +- else +- { +- if(found_bloc != 0xffff) +- { +- // Bloc protected, advise user and jump over protected bloc +- lprintf(LOG_INFO,"Bloc [%s] protected at offset: %i (size %i bytes)", +- fru_bloc[found_bloc].blocId, +- fru_bloc[found_bloc].start, +- fru_bloc[found_bloc].size); +- lprintf(LOG_INFO,"Jumping over this bloc"); +- } +- else +- { +- lprintf(LOG_INFO,"Remaining FRU is protected following offset: %i", +- off); + +- } +- off = end_bloc; ++ tmp = doffset; ++ if (fru->access) { ++ tmp >>= 1; + } +- } while ((doffset+off) < finish); +- +- free(fru_bloc); +- fru_bloc = NULL; +- +- return ((doffset+off) >= finish); +-} +- +- +-#if 0 +-int +-write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, +- uint16_t soffset, uint16_t doffset, +- uint16_t length, uint8_t *pFrubuf) +-{ /* +- // fill in frubuf[offset:length] from the FRU[offset:length] +- // rc=1 on success +- */ +- static uint16_t fru_data_rqst_size = 32; +- uint16_t off=0, tmp, finish; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- uint8_t msg_data[25]; +- uint8_t writeLength; +- +- finish = doffset + length; /* destination offset */ +- if (finish > fru->size) +- { +- printf("Return error\n"); +- return -1; +- } +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_STORAGE; +- req.msg.cmd = SET_FRU_DATA; +- req.msg.data = msg_data; +- +-#ifdef LIMIT_ALL_REQUEST_SIZE +- if (fru_data_rqst_size > 16) +-#else +- if (fru->access && fru_data_rqst_size > 16) +-#endif +- fru_data_rqst_size = 16; + +- do { +- /* real destination offset */ +- tmp = fru->access ? (doffset+off) >> 1 : (doffset+off); + msg_data[0] = id; + msg_data[1] = (uint8_t)tmp; + msg_data[2] = (uint8_t)(tmp >> 8); +- tmp = finish - (doffset+off); /* bytes remaining */ +- if (tmp > 16) { +- lprintf(LOG_INFO,"Writing 16 bytes"); +- memcpy(&msg_data[3], pFrubuf + soffset + off, 16); +- req.msg.data_len = 16 + 3; +- } +- else { +- lprintf(LOG_INFO,"Writing %d bytes", tmp); +- memcpy(&msg_data[3], pFrubuf + soffset + off, (uint8_t)tmp); +- req.msg.data_len = tmp + 3; +- } ++ req.msg.data_len = writeLength + 3; + +- writeLength = req.msg.data_len-3; ++ if(fru_bloc) { ++ lprintf(LOG_INFO,"Writing %d bytes (Bloc #%i: %s)", ++ writeLength, found_bloc, fru_bloc->blocId); ++ } else { ++ lprintf(LOG_INFO,"Writing %d bytes", writeLength); ++ } + + rsp = intf->sendrecv(intf, &req); + if (!rsp) { + break; + } +- if ((rsp->ccode==0xc7 || rsp->ccode==0xc8 || rsp->ccode==0xca ) && +- --fru_data_rqst_size > 8) { +- lprintf(LOG_NOTICE,"Bad CC -> %x\n", rsp->ccode); +- break; /*continue;*/ ++ ++ if (rsp->ccode == 0xc7 || rsp->ccode == 0xc8 || rsp->ccode == 0xca) { ++ if (fru->max_write_size > 8) { ++ fru->max_write_size -= 8; ++ lprintf(LOG_INFO, "Retrying FRU write with request size %d", ++ fru->max_write_size); ++ continue; ++ } ++ } else if(rsp->ccode == 0x80) { ++ rsp->ccode = 0; ++ // Write protected section ++ protected_bloc = 1; + } ++ + if (rsp->ccode > 0) + break; + +- off += writeLength; +- } while ((doffset+off) < finish); ++ if (protected_bloc == 0) { ++ // Write OK, bloc not protected, continue ++ lprintf(LOG_INFO,"Wrote %d bytes", writeLength); ++ doffset += writeLength; ++ soffset += writeLength; ++ } else { ++ if(fru_bloc) { ++ // Bloc protected, advise user and jump over protected bloc ++ lprintf(LOG_INFO, ++ "Bloc [%s] protected at offset: %i (size %i bytes)", ++ fru_bloc->blocId, fru_bloc->start, fru_bloc->size); ++ lprintf(LOG_INFO,"Jumping over this bloc"); ++ } else { ++ lprintf(LOG_INFO, ++ "Remaining FRU is protected following offset: %i", ++ doffset); ++ } ++ soffset += end_bloc - doffset; ++ doffset = end_bloc; ++ } ++ } while (doffset < finish); ++ ++ if (saved_fru_bloc) { ++ free_fru_bloc(saved_fru_bloc); ++ } + +- return ((doffset+off) >= finish); ++ return doffset >= finish; + } +-#endif + + /* read_fru_area - fill in frubuf[offset:length] from the FRU[offset:length] + * +@@ -749,7 +585,6 @@ int + read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, + uint32_t offset, uint32_t length, uint8_t *frubuf) + { +- static uint32_t fru_data_rqst_size = 20; + uint32_t off = offset, tmp, finish; + struct ipmi_rs * rsp; + struct ipmi_rq req; +@@ -775,29 +610,24 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, + req.msg.data = msg_data; + req.msg.data_len = 4; + +-#ifdef LIMIT_ALL_REQUEST_SIZE +- if (fru_data_rqst_size > 16) +-#else +- if (fru->access && fru_data_rqst_size > 16) +-#endif +- fru_data_rqst_size = 16; +- ++ if (fru->max_read_size == 0) { ++ /* subtract 1 byte for completion code and 1 for byte count */ ++ fru->max_read_size = 32 - 2; + +- /* Check if we receive size in parameters */ +- if(intf->channel_buf_size != 0) +- { +- fru_data_rqst_size = intf->channel_buf_size - 9; /* Plan for overhead */ ++ /* check word access */ ++ if (fru->access) { ++ fru->max_read_size &= ~1; ++ } + } + +- + do { + tmp = fru->access ? off >> 1 : off; + msg_data[0] = id; + msg_data[1] = (uint8_t)(tmp & 0xff); + msg_data[2] = (uint8_t)(tmp >> 8); + tmp = finish - off; +- if (tmp > fru_data_rqst_size) +- msg_data[3] = (uint8_t)fru_data_rqst_size; ++ if (tmp > fru->max_read_size) ++ msg_data[3] = (uint8_t)fru->max_read_size; + else + msg_data[3] = (uint8_t)tmp; + +@@ -807,33 +637,43 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, + break; + } + if (rsp->ccode > 0) { +- /* if we get C7 or C8 or CA return code then we requested too ++ /* if we get C8h or CAh completion code then we requested too + * many bytes at once so try again with smaller size */ +- if ((rsp->ccode == 0xc7 || rsp->ccode == 0xc8 || rsp->ccode == 0xca) && +- (--fru_data_rqst_size > 8)) { ++ if ((rsp->ccode == 0xc8 || rsp->ccode == 0xca) ++ && fru->max_read_size > 8) { ++ if (fru->max_read_size > 32) { ++ /* subtract read length more aggressively */ ++ fru->max_read_size -= 8; ++ } else { ++ /* subtract length less aggressively */ ++ fru->max_read_size--; ++ } ++ + lprintf(LOG_INFO, "Retrying FRU read with request size %d", +- fru_data_rqst_size); ++ fru->max_read_size); + continue; + } ++ + lprintf(LOG_NOTICE, "FRU Read failed: %s", + val2str(rsp->ccode, completion_code_vals)); + break; + } + + tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0]; +- memcpy((frubuf + off), rsp->data + 1, tmp); ++ memcpy(frubuf, rsp->data + 1, tmp); + off += tmp; +- ++ frubuf += tmp; + /* sometimes the size returned in the Info command + * is too large. return 0 so higher level function + * still attempts to parse what was returned */ +- if (tmp == 0 && off < finish) ++ if (tmp == 0 && off < finish) { + return 0; +- ++ } + } while (off < finish); + +- if (off < finish) ++ if (off < finish) { + return -1; ++ } + + return 0; + } +@@ -1009,40 +849,48 @@ fru_area_print_chassis(struct ipmi_intf * intf, struct fru_info * fru, + uint8_t id, uint32_t offset) + { + char * fru_area; +- uint8_t * fru_data = NULL; +- uint32_t fru_len, area_len, i; ++ uint8_t * fru_data; ++ uint32_t fru_len, i; ++ uint8_t tmp[2]; + +- i = offset; + fru_len = 0; + +- fru_data = malloc(fru->size + 1); +- if (fru_data == NULL) { +- lprintf(LOG_ERR, " Out of memory!"); ++ /* read enough to check length field */ ++ if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) { ++ fru_len = 8 * tmp[1]; ++ } ++ ++ if (fru_len == 0) { + return; + } +- memset(fru_data, 0, fru->size + 1); + +- /* read enough to check length field */ +- if (read_fru_area(intf, fru, id, i, 2, fru_data) == 0) +- fru_len = 8 * fru_data[i + 1]; +- if (fru_len <= 0) { +- free(fru_data); +- fru_data = NULL; ++ fru_data = malloc(fru_len); ++ if (fru_data == NULL) { ++ lprintf(LOG_ERR, "ipmitool: malloc failure"); + return; + } + ++ memset(fru_data, 0, fru_len); ++ + /* read in the full fru */ +- if (read_fru_area(intf, fru, id, i, fru_len, fru_data) < 0) { ++ if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) { + free(fru_data); + fru_data = NULL; + return; + } + +- i++; /* skip fru area version */ +- area_len = fru_data[i++] * 8; /* fru area length */ ++ /* ++ * skip first two bytes which specify ++ * fru area version and fru area length ++ */ ++ i = 2; + + printf(" Chassis Type : %s\n", +- chassis_type_desc[fru_data[i++]]); ++ chassis_type_desc[fru_data[i] > ++ (sizeof(chassis_type_desc)/sizeof(chassis_type_desc[0])) - 1 ? ++ 2 : fru_data[i]]); ++ ++ i++; + + fru_area = get_fru_area_str(fru_data, &i); + if (fru_area != NULL) { +@@ -1063,7 +911,7 @@ fru_area_print_chassis(struct ipmi_intf * intf, struct fru_info * fru, + } + + /* read any extra fields */ +- while ((fru_data[i] != 0xc1) && (i < offset + area_len)) ++ while ((fru_data[i] != 0xc1) && (i < fru_len)) + { + int j = i; + fru_area = get_fru_area_str(fru_data, &i); +@@ -1074,8 +922,10 @@ fru_area_print_chassis(struct ipmi_intf * intf, struct fru_info * fru, + free(fru_area); + fru_area = NULL; + } +- if (i == j) ++ ++ if (i == j) { + break; ++ } + } + + if (fru_area != NULL) { +@@ -1096,39 +946,45 @@ fru_area_print_board(struct ipmi_intf * intf, struct fru_info * fru, + uint8_t id, uint32_t offset) + { + char * fru_area; +- uint8_t * fru_data = NULL; +- uint32_t fru_len, area_len, i; ++ uint8_t * fru_data; ++ uint32_t fru_len; ++ uint32_t i; + time_t tval; ++ uint8_t tmp[2]; + +- i = offset; + fru_len = 0; + +- fru_data = malloc(fru->size + 1); +- if (fru_data == NULL) { +- lprintf(LOG_ERR, " Out of memory!"); +- return; ++ /* read enough to check length field */ ++ if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) { ++ fru_len = 8 * tmp[1]; + } +- memset(fru_data, 0, fru->size + 1); + +- /* read enough to check length field */ +- if (read_fru_area(intf, fru, id, i, 2, fru_data) == 0) +- fru_len = 8 * fru_data[i + 1]; + if (fru_len <= 0) { +- free(fru_data); +- fru_data = NULL; + return; + } + ++ fru_data = malloc(fru_len); ++ if (fru_data == NULL) { ++ lprintf(LOG_ERR, "ipmitool: malloc failure"); ++ return; ++ } ++ ++ memset(fru_data, 0, fru_len); ++ + /* read in the full fru */ +- if (read_fru_area(intf, fru, id, i, fru_len, fru_data) < 0) { ++ if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) { + free(fru_data); + fru_data = NULL; + return; + } + +- i++; /* skip fru area version */ +- area_len = fru_data[i++] * 8; /* fru area length */ +- i++; /* skip fru board language */ ++ /* ++ * skip first three bytes which specify ++ * fru area version, fru area length ++ * and fru board language ++ */ ++ i = 3; ++ + tval=((fru_data[i+2] << 16) + (fru_data[i+1] << 8) + (fru_data[i])); + tval=tval * 60; + tval=tval + secs_from_1970_1996; +@@ -1181,7 +1037,7 @@ fru_area_print_board(struct ipmi_intf * intf, struct fru_info * fru, + } + + /* read any extra fields */ +- while ((fru_data[i] != 0xc1) && (i < offset + area_len)) ++ while ((fru_data[i] != 0xc1) && (i < fru_len)) + { + int j = i; + fru_area = get_fru_area_str(fru_data, &i); +@@ -1213,39 +1069,44 @@ static void + fru_area_print_product(struct ipmi_intf * intf, struct fru_info * fru, + uint8_t id, uint32_t offset) + { +- char * fru_area = NULL; +- uint8_t * fru_data = NULL; +- uint32_t fru_len, area_len, i; ++ char * fru_area; ++ uint8_t * fru_data; ++ uint32_t fru_len, i; ++ uint8_t tmp[2]; + +- i = offset; + fru_len = 0; + +- fru_data = malloc(fru->size + 1); +- if (fru_data == NULL) { +- lprintf(LOG_ERR, " Out of memory!"); ++ /* read enough to check length field */ ++ if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) { ++ fru_len = 8 * tmp[1]; ++ } ++ ++ if (fru_len == 0) { + return; + } +- memset(fru_data, 0, fru->size + 1); + +- /* read enough to check length field */ +- if (read_fru_area(intf, fru, id, i, 2, fru_data) == 0) +- fru_len = 8 * fru_data[i + 1]; +- if (fru_len <= 0) { +- free(fru_data); +- fru_data = NULL; ++ fru_data = malloc(fru_len); ++ if (fru_data == NULL) { ++ lprintf(LOG_ERR, "ipmitool: malloc failure"); + return; + } + ++ memset(fru_data, 0, fru_len); ++ ++ + /* read in the full fru */ +- if (read_fru_area(intf, fru, id, i, fru_len, fru_data) < 0) { ++ if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) { + free(fru_data); + fru_data = NULL; + return; + } + +- i++; /* skip fru area version */ +- area_len = fru_data[i++] * 8; /* fru area length */ +- i++; /* skip fru board language */ ++ /* ++ * skip first three bytes which specify ++ * fru area version, fru area length ++ * and fru board language ++ */ ++ i = 3; + + fru_area = get_fru_area_str(fru_data, &i); + if (fru_area != NULL) { +@@ -1311,7 +1172,7 @@ fru_area_print_product(struct ipmi_intf * intf, struct fru_info * fru, + } + + /* read any extra fields */ +- while ((fru_data[i] != 0xc1) && (i < offset + area_len)) ++ while ((fru_data[i] != 0xc1) && (i < fru_len)) + { + int j = i; + fru_area = get_fru_area_str(fru_data, &i); +@@ -1344,46 +1205,42 @@ fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru, + uint8_t id, uint32_t offset) + { + uint8_t * fru_data; +- uint32_t fru_len, i; + struct fru_multirec_header * h; + struct fru_multirec_powersupply * ps; + struct fru_multirec_dcoutput * dc; + struct fru_multirec_dcload * dl; + uint16_t peak_capacity; + uint8_t peak_hold_up_time; +- uint32_t last_off, len; ++ uint32_t last_off; + +- i = last_off = offset; +- fru_len = 0; ++ last_off = offset; + +- fru_data = malloc(fru->size + 1); ++ fru_data = malloc(FRU_MULTIREC_CHUNK_SIZE); + if (fru_data == NULL) { +- lprintf(LOG_ERR, " Out of memory!"); ++ lprintf(LOG_ERR, "ipmitool: malloc failure"); + return; + } +- memset(fru_data, 0, fru->size + 1); + +- do { +- h = (struct fru_multirec_header *) (fru_data + i); ++ memset(fru_data, 0, FRU_MULTIREC_CHUNK_SIZE); + +- /* read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time */ +- if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len))) +- { +- len = fru->size - last_off; +- if (len > FRU_MULTIREC_CHUNK_SIZE) +- len = FRU_MULTIREC_CHUNK_SIZE; ++ h = (struct fru_multirec_header *) (fru_data); + +- if (read_fru_area(intf, fru, id, last_off, len, fru_data) < 0) +- break; ++ do { ++ if (read_fru_area(intf, fru, id, last_off, sizeof(*h), fru_data) < 0) { ++ break; ++ } + +- last_off += len; ++ if (h->len && read_fru_area(intf, fru, id, ++ last_off + sizeof(*h), h->len, fru_data + sizeof(*h)) < 0) { ++ break; + } + +- switch (h->type) +- { ++ last_off += h->len + sizeof(*h); ++ ++ switch (h->type) { + case FRU_RECORD_TYPE_POWER_SUPPLY_INFORMATION: + ps = (struct fru_multirec_powersupply *) +- (fru_data + i + sizeof (struct fru_multirec_header)); ++ (fru_data + sizeof(struct fru_multirec_header)); + + #if WORDS_BIGENDIAN + ps->capacity = BSWAP_16(ps->capacity); +@@ -1441,7 +1298,7 @@ fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru, + + case FRU_RECORD_TYPE_DC_OUTPUT: + dc = (struct fru_multirec_dcoutput *) +- (fru_data + i + sizeof (struct fru_multirec_header)); ++ (fru_data + sizeof(struct fru_multirec_header)); + + #if WORDS_BIGENDIAN + dc->nominal_voltage = BSWAP_16(dc->nominal_voltage); +@@ -1473,7 +1330,7 @@ fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru, + + case FRU_RECORD_TYPE_DC_LOAD: + dl = (struct fru_multirec_dcload *) +- (fru_data + i + sizeof (struct fru_multirec_header)); ++ (fru_data + sizeof(struct fru_multirec_header)); + + #if WORDS_BIGENDIAN + dl->nominal_voltage = BSWAP_16(dl->nominal_voltage); +@@ -1503,7 +1360,7 @@ fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru, + case FRU_RECORD_TYPE_OEM_EXTENSION: + { + struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *) +- &fru_data[i + sizeof(struct fru_multirec_header)]; ++ &fru_data[sizeof(struct fru_multirec_header)]; + uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16; + + /* Now makes sure this is really PICMG record */ +@@ -1511,7 +1368,7 @@ fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru, + if( iana == IPMI_OEM_PICMG ){ + printf(" PICMG Extension Record\n"); + ipmi_fru_picmg_ext_print(fru_data, +- i + sizeof(struct fru_multirec_header), ++ sizeof(struct fru_multirec_header), + h->len); + } + /* FIXME: Add OEM record support here */ +@@ -1521,13 +1378,11 @@ fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru, + } + break; + } +- i += h->len + sizeof (struct fru_multirec_header); + } while (!(h->format & 0x80)); + +- lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)",i,i); ++ lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)", last_off, last_off); + + free(fru_data); +- fru_data = NULL; + } + + /* ipmi_fru_query_new_value - Query new values to replace original FRU content +@@ -2309,7 +2164,7 @@ static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length) + minexp / 2, (minexp % 2) * 5); + } else { + printf( +- " Min Expected Voltage: -36V (actual invalid value 0x%x)\n", ++ " Min Expected Voltage: -%dV (actual invalid value 0x%x)\n", + 36, minexp); + } + for (j=0; j < entries; j++) { +@@ -2986,6 +2841,7 @@ __ipmi_fru_print(struct ipmi_intf * intf, uint8_t id) + return -1; + } + ++ memset(&fru, 0, sizeof(fru)); + fru.size = (rsp->data[1] << 8) | rsp->data[0]; + fru.access = rsp->data[2] & 0x1; + +@@ -3088,7 +2944,8 @@ int + ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru) + { + char desc[17]; +- uint32_t save_addr = 0; ++ uint8_t bridged_request = 0; ++ uint32_t save_addr; + uint32_t save_channel; + int rc = 0; + +@@ -3131,6 +2988,7 @@ ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru) + case 0x02: + if (BRIDGE_TO_SENSOR(intf, fru->dev_slave_addr, + fru->channel_num)) { ++ bridged_request = 1; + save_addr = intf->target_addr; + intf->target_addr = fru->dev_slave_addr; + save_channel = intf->target_channel; +@@ -3138,7 +2996,7 @@ ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru) + } + /* print FRU */ + rc = __ipmi_fru_print(intf, fru->device_id); +- if (save_addr) { ++ if (bridged_request) { + intf->target_addr = save_addr; + intf->target_channel = save_channel; + } +@@ -3316,6 +3174,8 @@ ipmi_fru_read_to_bin(struct ipmi_intf * intf, + printf (" Timeout accessing FRU info. (Device not present?)\n"); + return; + } ++ ++ memset(&fru, 0, sizeof(fru)); + fru.size = (rsp->data[1] << 8) | rsp->data[0]; + fru.access = rsp->data[2] & 0x1; + +@@ -3382,6 +3242,8 @@ ipmi_fru_write_from_bin(struct ipmi_intf * intf, + printf(" Timeout accessing FRU info. (Device not present?)\n"); + return; + } ++ ++ memset(&fru, 0, sizeof(fru)); + fru.size = (rsp->data[1] << 8) | rsp->data[0]; + fru.access = rsp->data[2] & 0x1; + +@@ -3501,6 +3363,7 @@ ipmi_fru_edit_multirec(struct ipmi_intf * intf, uint8_t id , + return -1; + } + ++ memset(&fru, 0, sizeof(fru)); + fru.size = (rsp->data[1] << 8) | rsp->data[0]; + fru.access = rsp->data[2] & 0x1; + +@@ -3524,6 +3387,7 @@ ipmi_fru_edit_multirec(struct ipmi_intf * intf, uint8_t id , + i = last_off = offset; + fru_len = 0; + ++ memset(&fru, 0, sizeof(fru)); + fru_data = malloc(fru.size + 1); + if (fru_data == NULL) { + lprintf(LOG_ERR, " Out of memory!"); +@@ -3702,6 +3566,7 @@ ipmi_fru_get_multirec(struct ipmi_intf * intf, uint8_t id , + return -1; + } + ++ memset(&fru, 0, sizeof(fru)); + fru.size = (rsp->data[1] << 8) | rsp->data[0]; + fru.access = rsp->data[2] & 0x1; + +@@ -4171,6 +4036,7 @@ ipmi_fru_get_internal_use_info( struct ipmi_intf * intf, + return -1; + } + ++ memset(&fru, 0, sizeof(fru)); + fru->size = (rsp->data[1] << 8) | rsp->data[0]; + fru->access = rsp->data[2] & 0x1; + +@@ -4755,6 +4621,7 @@ f_type, uint8_t f_index, char *f_string) + goto ipmi_fru_set_field_string_out; + } + ++ memset(&fru, 0, sizeof(fru)); + fru.size = (rsp->data[1] << 8) | rsp->data[0]; + fru.access = rsp->data[2] & 0x1; + +diff --git a/ipmitool/lib/ipmi_fwum.c b/ipmitool/lib/ipmi_fwum.c +index d9b562c..b666a2b 100644 +--- a/ipmitool/lib/ipmi_fwum.c ++++ b/ipmitool/lib/ipmi_fwum.c +@@ -19,7 +19,7 @@ + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * +- * This software is provided "AS IS," without a warranty of any kind. ++ * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. +@@ -33,7 +33,6 @@ + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +- + #include + #include + #include +@@ -46,421 +45,259 @@ + #include + #include + +-/****************************************************************************** +-* HISTORY +-* =========================================================================== +-* 2007-01-11 [FI] +-* - Incremented to version 1.3 +-* - Added lan packet size reduction mechanism to workaround fact +-* that lan iface will not return C7 on excessive length +-* +-*****************************************************************************/ +- +-#define VERSION_MAJ 1 +-#define VERSION_MIN 3 +- +- +-typedef enum eKFWUM_Task +-{ +- KFWUM_TASK_INFO, +- KFWUM_TASK_STATUS, +- KFWUM_TASK_DOWNLOAD, +- KFWUM_TASK_UPGRADE, +- KFWUM_TASK_START_UPGRADE, +- KFWUM_TASK_ROLLBACK, +- KFWUM_TASK_TRACELOG +-}tKFWUM_Task; +- +-typedef enum eKFWUM_BoardList +-{ +- KFWUM_BOARD_KONTRON_UNKNOWN = 0, +- KFWUM_BOARD_KONTRON_5002 = 5002, +-}tKFWUM_BoardList; +- +-typedef enum eKFWUM_IanaList +-{ +- KFWUM_IANA_KONTRON = 15000, +-}tKFWUM_IanaList; +- +-typedef struct sKFWUM_BoardInfo +-{ +- tKFWUM_BoardList boardId; +- tKFWUM_IanaList iana; +-}tKFWUM_BoardInfo; +- +-typedef enum eKFWUM_Status +-{ +- KFWUM_STATUS_OK, +- KFWUM_STATUS_ERROR +-}tKFWUM_Status; +- +-typedef enum eKFWUM_DownloadType +-{ +- KFWUM_DOWNLOAD_TYPE_ADDRESS = 0, +- KFWUM_DOWNLOAD_TYPE_SEQUENCE, +-}tKFWUM_DownloadType; ++extern int verbose; ++unsigned char firmBuf[1024*512]; ++tKFWUM_SaveFirmwareInfo save_fw_nfo; ++ ++int KfwumGetFileSize(const char *pFileName, ++ unsigned long *pFileSize); ++int KfwumSetupBuffersFromFile(const char *pFileName, ++ unsigned long fileSize); ++void KfwumShowProgress(const char *task, unsigned long current, ++ unsigned long total); ++unsigned short KfwumCalculateChecksumPadding(unsigned char *pBuffer, ++ unsigned long totalSize); ++int KfwumGetInfo(struct ipmi_intf *intf, unsigned char output, ++ unsigned char *pNumBank); ++int KfwumGetDeviceInfo(struct ipmi_intf *intf, ++ unsigned char output, tKFWUM_BoardInfo *pBoardInfo); ++int KfwumGetStatus(struct ipmi_intf *intf); ++int KfwumManualRollback(struct ipmi_intf *intf); ++int KfwumStartFirmwareImage(struct ipmi_intf *intf, ++ unsigned long length, unsigned short padding); ++int KfwumSaveFirmwareImage(struct ipmi_intf *intf, ++ unsigned char sequenceNumber, unsigned long address, ++ unsigned char *pFirmBuf, unsigned char *pInBufLength); ++int KfwumFinishFirmwareImage(struct ipmi_intf *intf, ++ tKFWUM_InFirmwareInfo firmInfo); ++int KfwumUploadFirmware(struct ipmi_intf *intf, ++ unsigned char *pBuffer, unsigned long totalSize); ++int KfwumStartFirmwareUpgrade(struct ipmi_intf *intf); ++int KfwumGetInfoFromFirmware(unsigned char *pBuf, ++ unsigned long bufSize, tKFWUM_InFirmwareInfo *pInfo); ++void KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo *pInfo); ++int KfwumGetTraceLog(struct ipmi_intf *intf); ++int ipmi_kfwum_checkfwcompat(tKFWUM_BoardInfo boardInfo, ++ tKFWUM_InFirmwareInfo firmInfo); ++ ++int ipmi_fwum_fwupgrade(struct ipmi_intf *intf, char *file, int action); ++int ipmi_fwum_info(struct ipmi_intf *intf); ++int ipmi_fwum_status(struct ipmi_intf *intf); ++void printf_kfwum_help(void); ++void printf_kfwum_info(tKFWUM_BoardInfo boardInfo, ++ tKFWUM_InFirmwareInfo firmInfo); + +-typedef enum eKFWUM_DownloadBuffferType +-{ +- KFWUM_SMALL_BUFFER_TYPE = 0, +- KFUMW_BIG_BUFFER_TYPE +-}tKFWUM_DownloadBuffferType; ++/* String table */ ++/* Must match eFWUM_CmdId */ ++const char *CMD_ID_STRING[] = { ++ "GetFwInfo", ++ "KickWatchdog", ++ "GetLastAnswer", ++ "BootHandshake", ++ "ReportStatus", ++ "CtrlIPMBLine", ++ "SetFwState", ++ "GetFwStatus", ++ "GetSpiMemStatus", ++ "StartFwUpdate", ++ "StartFwImage", ++ "SaveFwImage", ++ "FinishFwImage", ++ "ReadFwImage", ++ "ManualRollback", ++ "GetTraceLog" ++}; + +-typedef struct sKFWUM_InFirmwareInfo +-{ +- unsigned long fileSize; +- unsigned short checksum; +- unsigned short sumToRemoveFromChecksum; +- /* Since the checksum is added in the bin +- after the checksum is calculated, we +- need to remove the each byte value. This +- byte will contain the addition of both bytes*/ +- tKFWUM_BoardList boardId; +- unsigned char deviceId; +- unsigned char tableVers; +- unsigned char implRev; +- unsigned char versMajor; +- unsigned char versMinor; +- unsigned char versSubMinor; +- unsigned char sdrRev; +- tKFWUM_IanaList iana; +-}tKFWUM_InFirmwareInfo; +- +-typedef struct sKFWUM_SaveFirmwareInfo +-{ +- tKFWUM_DownloadType downloadType; +- unsigned char bufferSize; +- unsigned char overheadSize; +-}tKFWUM_SaveFirmwareInfo; +- +-#define KFWUM_SMALL_BUFFER 32 /* Minimum size (IPMB/IOL/old protocol) */ +-#define KFWUM_BIG_BUFFER 32 /* Maximum size on KCS interface */ +- +-#define KFWUM_OLD_CMD_OVERHEAD 6 /*3 address + 1 size + 1 checksum + 1 command*/ +-#define KFWUM_NEW_CMD_OVERHEAD 4 /*1 sequence+ 1 size + 1 checksum + 1 command*/ +-#define KFWUM_PAGE_SIZE 256 ++const char *EXT_CMD_ID_STRING[] = { ++ "FwUpgradeLock", ++ "ProcessFwUpg", ++ "ProcessFwRb", ++ "WaitHSAfterUpg", ++ "WaitFirstHSUpg", ++ "FwInfoStateChange" ++}; + +-extern int verbose; +-static unsigned char fileName[512]; +-static unsigned char firmBuf[1024*512]; +-static tKFWUM_SaveFirmwareInfo saveFirmwareInfo; +- +-static void KfwumOutputHelp(void); +-static void KfwumMain(struct ipmi_intf * intf, tKFWUM_Task task); +-static tKFWUM_Status KfwumGetFileSize(unsigned char * pFileName, +- unsigned long * pFileSize); +-static tKFWUM_Status KfwumSetupBuffersFromFile(unsigned char * pFileName, +- unsigned long fileSize); +-static void KfwumShowProgress( const unsigned char * task, +- unsigned long current, unsigned long total); +-static unsigned short KfwumCalculateChecksumPadding(unsigned char * pBuffer, +- unsigned long totalSize); +- +- +-static tKFWUM_Status KfwumGetInfo(struct ipmi_intf * intf, unsigned char output, +- unsigned char *pNumBank); +-static tKFWUM_Status KfwumGetDeviceInfo(struct ipmi_intf * intf, +- unsigned char output, tKFWUM_BoardInfo * pBoardInfo); +-static tKFWUM_Status KfwumGetStatus(struct ipmi_intf * intf); +-static tKFWUM_Status KfwumManualRollback(struct ipmi_intf * intf); +-static tKFWUM_Status KfwumStartFirmwareImage(struct ipmi_intf * intf, +- unsigned long length,unsigned short padding); +-static tKFWUM_Status KfwumSaveFirmwareImage(struct ipmi_intf * intf, +- unsigned char sequenceNumber, unsigned long address, +- unsigned char *pFirmBuf, unsigned char * pInBufLength); +-static tKFWUM_Status KfwumFinishFirmwareImage(struct ipmi_intf * intf, +- tKFWUM_InFirmwareInfo firmInfo); +-static tKFWUM_Status KfwumUploadFirmware(struct ipmi_intf * intf, +- unsigned char * pBuffer, unsigned long totalSize); +-static tKFWUM_Status KfwumStartFirmwareUpgrade(struct ipmi_intf * intf); +- +-static tKFWUM_Status KfwumGetInfoFromFirmware(unsigned char * pBuf, +- unsigned long bufSize, tKFWUM_InFirmwareInfo * pInfo); +-static void KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo * pInfo); +- +-static tKFWUM_Status KfwumGetTraceLog(struct ipmi_intf * intf); +- +-tKFWUM_Status KfwumValidFirmwareForBoard(tKFWUM_BoardInfo boardInfo, +- tKFWUM_InFirmwareInfo firmInfo); +-static void KfwumOutputInfo(tKFWUM_BoardInfo boardInfo, +- tKFWUM_InFirmwareInfo firmInfo); ++const char *CMD_STATE_STRING[] = { ++ "Invalid", ++ "Begin", ++ "Progress", ++ "Completed" ++}; + ++const struct valstr bankStateValS[] = { ++ { 0x00, "Not programmed" }, ++ { 0x01, "New firmware" }, ++ { 0x02, "Wait for validation" }, ++ { 0x03, "Last Known Good" }, ++ { 0x04, "Previous Good" } ++}; + + /* ipmi_fwum_main - entry point for this ipmitool mode + * +- * @intf: ipmi interface +- * @arc : number of arguments +- * @argv : point to argument array ++ * @intf: ipmi interface ++ * @arc: number of arguments ++ * @argv: point to argument array + * + * returns 0 on success + * returns -1 on error + */ +-int ipmi_fwum_main(struct ipmi_intf * intf, int argc, char ** argv) ++int ++ipmi_fwum_main(struct ipmi_intf *intf, int argc, char **argv) + { +- printf("FWUM extension Version %d.%d\n", VERSION_MAJ, VERSION_MIN); +- if ((!argc) || ( !strncmp(argv[0], "help", 4))) +- { +- KfwumOutputHelp(); +- } +- else +- { +- if (!strncmp(argv[0], "info", 4)) +- { +- KfwumMain(intf, KFWUM_TASK_INFO); +- } +- else if (!strncmp(argv[0], "status", 6)) +- { +- KfwumMain(intf, KFWUM_TASK_STATUS); +- } +- else if (!strncmp(argv[0], "rollback", 8)) +- { +- KfwumMain(intf, KFWUM_TASK_ROLLBACK); +- } +- else if (!strncmp(argv[0], "download", 8)) +- { +- if((argc >= 2) && (strlen(argv[1]) > 0)) +- { +- /* There is a file name in the parameters */ +- if(strlen(argv[1]) < 512) +- { +- strcpy((char *)fileName, argv[1]); +- printf("Firmware File Name : %s\n", fileName); +- +- KfwumMain(intf, KFWUM_TASK_DOWNLOAD); +- } +- else +- { +- fprintf(stderr,"File name must be smaller than 512 bytes\n"); +- } +- } +- else +- { +- fprintf(stderr,"A path and a file name must be specified\n"); +- } +- } +- else if (!strncmp(argv[0], "upgrade", 7)) +- { +- if((argc >= 2) && (strlen(argv[1]) > 0)) +- { +- /* There is a file name in the parameters */ +- if(strlen(argv[1]) < 512) +- { +- strcpy((char *)fileName, argv[1]); +- printf("Upgrading using file name %s\n", fileName); +- KfwumMain(intf, KFWUM_TASK_UPGRADE); +- } +- else +- { +- fprintf(stderr,"File name must be smaller than 512 bytes\n"); +- } +- } +- else +- { +- KfwumMain(intf, KFWUM_TASK_START_UPGRADE); +- } +- +- } +- else if (!strncmp(argv[0], "tracelog", 8)) +- { +- KfwumMain(intf, KFWUM_TASK_TRACELOG); +- } +- else +- { +- printf("Invalid KFWUM command: %s\n", argv[0]); +- } +- } +- return 0; ++ int rc = 0; ++ printf("FWUM extension Version %d.%d\n", VER_MAJOR, VER_MINOR); ++ if (argc < 1) { ++ lprintf(LOG_ERR, "Not enough parameters given."); ++ printf_kfwum_help(); ++ return (-1); ++ } ++ if (strncmp(argv[0], "help", 4) == 0) { ++ printf_kfwum_help(); ++ rc = 0; ++ } else if (strncmp(argv[0], "info", 4) == 0) { ++ rc = ipmi_fwum_info(intf); ++ } else if (strncmp(argv[0], "status", 6) == 0) { ++ rc = ipmi_fwum_status(intf); ++ } else if (strncmp(argv[0], "rollback", 8) == 0) { ++ rc = KfwumManualRollback(intf); ++ } else if (strncmp(argv[0], "download", 8) == 0) { ++ if ((argc < 2) || (strlen(argv[1]) < 1)) { ++ lprintf(LOG_ERR, ++ "Path and file name must be specified."); ++ return (-1); ++ } ++ printf("Firmware File Name : %s\n", argv[1]); ++ rc = ipmi_fwum_fwupgrade(intf, argv[1], 0); ++ } else if (strncmp(argv[0], "upgrade", 7) == 0) { ++ if ((argc >= 2) && (strlen(argv[1]) > 0)) { ++ printf("Upgrading using file name %s\n", argv[1]); ++ rc = ipmi_fwum_fwupgrade(intf, argv[1], 1); ++ } else { ++ rc = KfwumStartFirmwareUpgrade(intf); ++ } ++ } else if (strncmp(argv[0], "tracelog", 8) == 0) { ++ rc = KfwumGetTraceLog(intf); ++ } else { ++ lprintf(LOG_ERR, "Invalid KFWUM command: %s", argv[0]); ++ printf_kfwum_help(); ++ rc = (-1); ++ } ++ return rc; + } + +- +-static void KfwumOutputHelp(void) ++void ++printf_kfwum_help(void) + { +- printf("KFWUM Commands: info status download upgrade rollback tracelog\n"); ++ lprintf(LOG_NOTICE, ++"KFWUM Commands: info status download upgrade rollback tracelog"); + } + +- +-/****************************************/ +-/** private definitions and macros **/ +-/****************************************/ ++/* private definitions and macros */ + typedef enum eFWUM_CmdId + { +- KFWUM_CMD_ID_GET_FIRMWARE_INFO = 0, +- KFWUM_CMD_ID_KICK_IPMC_WATCHDOG = 1, +- KFWUM_CMD_ID_GET_LAST_ANSWER = 2, +- KFWUM_CMD_ID_BOOT_HANDSHAKE = 3, +- KFWUM_CMD_ID_REPORT_STATUS = 4, +- KFWUM_CMD_ID_GET_FIRMWARE_STATUS = 7, +- KFWUM_CMD_ID_START_FIRMWARE_UPDATE = 9, +- KFWUM_CMD_ID_START_FIRMWARE_IMAGE = 0x0a, +- KFWUM_CMD_ID_SAVE_FIRMWARE_IMAGE = 0x0b, +- KFWUM_CMD_ID_FINISH_FIRMWARE_IMAGE = 0x0c, +- KFWUM_CMD_ID_READ_FIRMWARE_IMAGE = 0x0d, +- KFWUM_CMD_ID_MANUAL_ROLLBACK = 0x0e, +- KFWUM_CMD_ID_GET_TRACE_LOG = 0x0f, +- KFWUM_CMD_ID_STD_MAX_CMD, +- KFWUM_CMD_ID_EXTENDED_CMD = 0xC0 ++ KFWUM_CMD_ID_GET_FIRMWARE_INFO = 0, ++ KFWUM_CMD_ID_KICK_IPMC_WATCHDOG = 1, ++ KFWUM_CMD_ID_GET_LAST_ANSWER = 2, ++ KFWUM_CMD_ID_BOOT_HANDSHAKE = 3, ++ KFWUM_CMD_ID_REPORT_STATUS = 4, ++ KFWUM_CMD_ID_GET_FIRMWARE_STATUS = 7, ++ KFWUM_CMD_ID_START_FIRMWARE_UPDATE = 9, ++ KFWUM_CMD_ID_START_FIRMWARE_IMAGE = 0x0a, ++ KFWUM_CMD_ID_SAVE_FIRMWARE_IMAGE = 0x0b, ++ KFWUM_CMD_ID_FINISH_FIRMWARE_IMAGE = 0x0c, ++ KFWUM_CMD_ID_READ_FIRMWARE_IMAGE = 0x0d, ++ KFWUM_CMD_ID_MANUAL_ROLLBACK = 0x0e, ++ KFWUM_CMD_ID_GET_TRACE_LOG = 0x0f, ++ KFWUM_CMD_ID_STD_MAX_CMD, ++ KFWUM_CMD_ID_EXTENDED_CMD = 0xC0 + } tKFWUM_CmdId; + +- +- +-/****************************************/ +-/** global/static variables definition **/ +-/****************************************/ +- +-/****************************************/ +-/** functions definition **/ +-/****************************************/ +- +-/******************************************************************************* +-* +-* Function Name: KfwumMain +-* +-* Description: This function implements the upload of the firware data +-* received as parameters. +-* +-* Restriction: Called only from main +-* +-* Input: unsigned char * pBuffer[] : The buffers +-* unsigned long bufSize : The size of the buffers +-* +-* Output: None +-* +-* Global: none +-* +-* Return: tIFWU_Status (success or failure) +-* +-*******************************************************************************/ +-static void KfwumMain(struct ipmi_intf * intf, tKFWUM_Task task) ++int ++ipmi_fwum_info(struct ipmi_intf *intf) + { +- tKFWUM_Status status = KFWUM_STATUS_OK; +- tKFWUM_BoardInfo boardInfo; +- tKFWUM_InFirmwareInfo firmInfo = { 0 }; +- unsigned long fileSize = 0; +- static unsigned short padding; +- +- if((status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_INFO)) +- { +- unsigned char notUsed; +- if(verbose) +- { +- printf("Getting Kontron FWUM Info\n"); +- } +- KfwumGetDeviceInfo(intf, 1, &boardInfo); +- KfwumGetInfo(intf, 1, ¬Used); +- +- } +- +- +- if((status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_STATUS)) +- { +- if(verbose) +- { +- printf("Getting Kontron FWUM Status\n"); +- } +- KfwumGetStatus(intf); +- } +- +- if( (status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_ROLLBACK) ) +- { +- status = KfwumManualRollback(intf); +- } +- +- if( +- (status == KFWUM_STATUS_OK) && +- ( +- (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) +- ) +- ) +- { +- status = KfwumGetFileSize(fileName, &fileSize); +- if(status == KFWUM_STATUS_OK) +- { +- status = KfwumSetupBuffersFromFile(fileName, fileSize); +- if(status == KFWUM_STATUS_OK) +- { +- padding = KfwumCalculateChecksumPadding(firmBuf, fileSize); +- } +- } +- if(status == KFWUM_STATUS_OK) +- { +- status = KfwumGetInfoFromFirmware(firmBuf, fileSize, &firmInfo); +- } +- if(status == KFWUM_STATUS_OK) +- { +- status = KfwumGetDeviceInfo(intf, 0, &boardInfo); +- } +- +- if(status == KFWUM_STATUS_OK) +- { +- status = KfwumValidFirmwareForBoard(boardInfo,firmInfo); +- } +- +- if (status == KFWUM_STATUS_OK) +- { +- unsigned char notUsed; +- KfwumGetInfo(intf, 0, ¬Used); +- } +- +- KfwumOutputInfo(boardInfo,firmInfo); +- } +- +- if( +- (status == KFWUM_STATUS_OK) && +- ( +- (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) +- ) +- ) +- { +- status = KfwumStartFirmwareImage(intf, fileSize, padding); +- } +- +- +- if( +- (status == KFWUM_STATUS_OK) && +- ( +- (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) +- ) +- ) +- { +- status = KfwumUploadFirmware(intf, firmBuf, fileSize); +- } +- +- if( +- (status == KFWUM_STATUS_OK) && +- ( +- (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) +- ) +- ) +- { +- status = KfwumFinishFirmwareImage(intf, firmInfo); +- } +- +- if( +- (status == KFWUM_STATUS_OK) && +- ( +- (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) +- ) +- ) +- { +- status = KfwumGetStatus(intf); +- } +- +- if( +- (status == KFWUM_STATUS_OK) && +- ( +- (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_START_UPGRADE) +- ) +- ) +- { +- status = KfwumStartFirmwareUpgrade(intf); +- } +- +- if((status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_TRACELOG)) +- { +- status = KfwumGetTraceLog(intf); +- } ++ tKFWUM_BoardInfo b_info; ++ int rc = 0; ++ unsigned char not_used; ++ if (verbose) { ++ printf("Getting Kontron FWUM Info\n"); ++ } ++ if (KfwumGetDeviceInfo(intf, 1, &b_info) != 0) { ++ rc = (-1); ++ } ++ if (KfwumGetInfo(intf, 1, ¬_used) != 0) { ++ rc = (-1); ++ } ++ return rc; ++} + ++int ++ipmi_fwum_status(struct ipmi_intf *intf) ++{ ++ if (verbose) { ++ printf("Getting Kontron FWUM Status\n"); ++ } ++ if (KfwumGetStatus(intf) != 0) { ++ return (-1); ++ } ++ return 0; ++} + ++/* ipmi_fwum_fwupgrade - function implements download/upload of the firmware ++ * data received as parameters ++ * ++ * @file: fw file ++ * @action: 0 = download, 1 = upload/start upload ++ * ++ * returns 0 on success, otherwise (-1) ++ */ ++int ++ipmi_fwum_fwupgrade(struct ipmi_intf *intf, char *file, int action) ++{ ++ tKFWUM_BoardInfo b_info; ++ tKFWUM_InFirmwareInfo fw_info = { 0 }; ++ unsigned short padding; ++ unsigned long fsize = 0; ++ unsigned char not_used; ++ if (file == NULL) { ++ lprintf(LOG_ERR, "No file given."); ++ return (-1); ++ } ++ if (KfwumGetFileSize(file, &fsize) != 0) { ++ return (-1); ++ } ++ if (KfwumSetupBuffersFromFile(file, fsize) != 0) { ++ return (-1); ++ } ++ padding = KfwumCalculateChecksumPadding(firmBuf, fsize); ++ if (KfwumGetInfoFromFirmware(firmBuf, fsize, &fw_info) != 0) { ++ return (-1); ++ } ++ if (KfwumGetDeviceInfo(intf, 0, &b_info) != 0) { ++ return (-1); ++ } ++ if (ipmi_kfwum_checkfwcompat(b_info, fw_info) != 0) { ++ return (-1); ++ } ++ KfwumGetInfo(intf, 0, ¬_used); ++ printf_kfwum_info(b_info, fw_info); ++ if (KfwumStartFirmwareImage(intf, fsize, padding) != 0) { ++ return (-1); ++ } ++ if (KfwumUploadFirmware(intf, firmBuf, fsize) != 0) { ++ return (-1); ++ } ++ if (KfwumFinishFirmwareImage(intf, fw_info) != 0) { ++ return (-1); ++ } ++ if (KfwumGetStatus(intf) != 0) { ++ return (-1); ++ } ++ if (action != 0) { ++ if (KfwumStartFirmwareUpgrade(intf) != 0) { ++ return (-1); ++ } ++ } ++ return 0; + } + + /* KfwumGetFileSize - gets the file size +@@ -468,31 +305,24 @@ static void KfwumMain(struct ipmi_intf * intf, tKFWUM_Task task) + * @pFileName : filename ptr + * @pFileSize : output ptr for filesize + * +- * returns KFWUM_STATUS_OK or KFWUM_STATUS_ERROR ++ * returns 0 on success, otherwise (-1) + */ +-static tKFWUM_Status KfwumGetFileSize(unsigned char * pFileName, +- unsigned long * pFileSize) ++int ++KfwumGetFileSize(const char *pFileName, unsigned long *pFileSize) + { +- tKFWUM_Status status = KFWUM_STATUS_ERROR; +- FILE * pFileHandle; +- +- pFileHandle = fopen((const char *)pFileName, "rb"); +- +- if(pFileHandle) +- { +- if (fseek(pFileHandle, 0L , SEEK_END) == 0) +- { +- *pFileSize = ftell(pFileHandle); +- +- if( *pFileSize != 0) +- { +- status = KFWUM_STATUS_OK; +- } +- } +- fclose(pFileHandle); +- } +- +- return(status); ++ FILE *pFileHandle = NULL; ++ pFileHandle = fopen(pFileName, "rb"); ++ if (pFileHandle == NULL) { ++ return (-1); ++ } ++ if (fseek(pFileHandle, 0L , SEEK_END) == 0) { ++ *pFileSize = ftell(pFileHandle); ++ } ++ fclose(pFileHandle); ++ if (*pFileSize != 0) { ++ return 0; ++ } ++ return (-1); + } + + /* KfwumSetupBuffersFromFile - small buffers are used to store the file data +@@ -500,1182 +330,803 @@ static tKFWUM_Status KfwumGetFileSize(unsigned char * pFileName, + * @pFileName : filename ptr + * unsigned long : filesize + * +- * returns KFWUM_STATUS_OK or KFWUM_STATUS_ERROR ++ * returns 0 on success, otherwise (-1) + */ +-#define MAX_BUFFER_SIZE 1024*16 +-static tKFWUM_Status KfwumSetupBuffersFromFile(unsigned char * pFileName, +- unsigned long fileSize) ++int ++KfwumSetupBuffersFromFile(const char *pFileName, unsigned long fileSize) + { +- tKFWUM_Status status = KFWUM_STATUS_ERROR; ++ int rc = (-1); + FILE *pFileHandle = NULL; + int count; + int modulus; + int qty = 0; + +- pFileHandle = fopen((const char *)pFileName, "rb"); ++ pFileHandle = fopen(pFileName, "rb"); + if (pFileHandle == NULL) { + lprintf(LOG_ERR, "Failed to open '%s' for reading.", +- (char *)pFileName); +- return KFWUM_STATUS_ERROR; ++ pFileName); ++ return (-1); + } + count = fileSize / MAX_BUFFER_SIZE; + modulus = fileSize % MAX_BUFFER_SIZE; + + rewind(pFileHandle); +- for (qty=0; qty < count; qty++) { +- KfwumShowProgress((const unsigned char *)"Reading Firmware from File", ++ for (qty = 0; qty < count; qty++) { ++ KfwumShowProgress("Reading Firmware from File", + qty, count); + if (fread(&firmBuf[qty * MAX_BUFFER_SIZE], 1, + MAX_BUFFER_SIZE, + pFileHandle) == MAX_BUFFER_SIZE) { +- status = KFWUM_STATUS_OK; ++ rc = 0; + } + } + if (modulus) { + if (fread(&firmBuf[qty * MAX_BUFFER_SIZE], 1, + modulus, pFileHandle) == modulus) { +- status = KFWUM_STATUS_OK; ++ rc = 0; + } + } +- if (status == KFWUM_STATUS_OK) { +- KfwumShowProgress((const unsigned char *)"Reading Firmware from File", +- 100, 100); ++ if (rc == 0) { ++ KfwumShowProgress("Reading Firmware from File", 100, 100); + } + fclose(pFileHandle); +- return status; ++ return rc; + } + + /* KfwumShowProgress - helper routine to display progress bar + * + * Converts current/total in percent +- * ++ * + * *task : string identifying current operation + * current: progress +- * total : limit ++ * total : limit + */ +-#define PROG_LENGTH 42 +-void KfwumShowProgress( const unsigned char * task, unsigned long current , +- unsigned long total) ++void ++KfwumShowProgress(const char *task, unsigned long current, unsigned long total) + { +- static unsigned long staticProgress=0xffffffff; +- +- unsigned char spaces[PROG_LENGTH + 1]; +- unsigned short hash; +- float percent = ((float)current/total); +- unsigned long progress = 100*(percent); +- +- if(staticProgress == progress) +- { +- /* We displayed the same last time.. so don't do it */ +- } +- else +- { +- staticProgress = progress; +- +- +- printf("%-25s : ",task); /* total 20 bytes */ +- +- hash = ( percent * PROG_LENGTH ); +- memset(spaces,'#', hash); +- spaces[ hash ] = '\0'; +- printf("%s", spaces ); +- +- memset(spaces,' ',( PROG_LENGTH - hash ) ); +- spaces[ ( PROG_LENGTH - hash ) ] = '\0'; +- printf("%s", spaces ); +- +- +- printf(" %3ld %%\r",progress); /* total 7 bytes */ +- +- if( progress == 100 ) +- { +- printf("\n"); +- } +- fflush(stdout); +- } ++# define PROG_LENGTH 42 ++ static unsigned long staticProgress=0xffffffff; ++ unsigned char spaces[PROG_LENGTH + 1]; ++ unsigned short hash; ++ float percent = ((float)current / total); ++ unsigned long progress = 100 * (percent); ++ ++ if (staticProgress == progress) { ++ /* We displayed the same last time.. so don't do it */ ++ return; ++ } ++ staticProgress = progress; ++ printf("%-25s : ", task); /* total 20 bytes */ ++ hash = (percent * PROG_LENGTH); ++ memset(spaces, '#', hash); ++ spaces[hash] = '\0'; ++ ++ printf("%s", spaces); ++ memset(spaces, ' ', (PROG_LENGTH - hash)); ++ spaces[(PROG_LENGTH - hash)] = '\0'; ++ printf("%s", spaces ); ++ ++ printf(" %3ld %%\r", progress); /* total 7 bytes */ ++ if (progress == 100) { ++ printf("\n"); ++ } ++ fflush(stdout); + } + +-/* KfwumCalculateChecksumPadding +- * +- * TBD +- * ++/* KfwumCalculateChecksumPadding - TBD + */ +-static unsigned short KfwumCalculateChecksumPadding(unsigned char * pBuffer, +- unsigned long totalSize) ++unsigned short ++KfwumCalculateChecksumPadding(unsigned char *pBuffer, unsigned long totalSize) + { +- unsigned short sumOfBytes = 0; +- unsigned short padding; +- unsigned long counter; +- +- for(counter = 0; counter < totalSize; counter ++ ) +- { +- sumOfBytes += pBuffer[counter]; +- } +- +- padding = 0 - sumOfBytes; +- return padding; ++ unsigned short sumOfBytes = 0; ++ unsigned short padding; ++ unsigned long counter; ++ for (counter = 0; counter < totalSize; counter ++) { ++ sumOfBytes += pBuffer[counter]; ++ } ++ padding = 0 - sumOfBytes; ++ return padding; + } + +-/****************************************************************************** +-******************************* COMMANDS ************************************** +-******************************************************************************/ +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(1) +-#endif +-struct KfwumGetInfoResp { +- unsigned char protocolRevision; +- unsigned char controllerDeviceId; +- struct +- { +- unsigned char mode:1; +- unsigned char seqAdd:1; +- unsigned char res : 6; +- } byte; +- unsigned char firmRev1; +- unsigned char firmRev2; +- unsigned char numBank; +-} ATTRIBUTE_PACKING; +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(0) +-#endif +- +- +- + /* KfwumGetInfo - Get Firmware Update Manager (FWUM) information +- * +- * * intf : IPMI interface ++ * ++ * *intf : IPMI interface + * output : when set to non zero, queried information is displayed + * pNumBank: output ptr for number of banks ++ * ++ * returns 0 on success, otherwise (-1) + */ +-static tKFWUM_Status KfwumGetInfo(struct ipmi_intf * intf, unsigned char output, +- unsigned char *pNumBank) ++int ++KfwumGetInfo(struct ipmi_intf *intf, unsigned char output, ++ unsigned char *pNumBank) + { +- tKFWUM_Status status = KFWUM_STATUS_OK; +- static struct KfwumGetInfoResp *pGetInfo; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_FIRMWARE; +- req.msg.cmd = KFWUM_CMD_ID_GET_FIRMWARE_INFO; +- req.msg.data_len = 0; +- +- rsp = intf->sendrecv(intf, &req); +- +- if (!rsp) +- { +- printf("Error in FWUM Firmware Get Info Command\n"); +- status = KFWUM_STATUS_ERROR; +- } +- else if (rsp->ccode) +- { +- printf("FWUM Firmware Get Info returned %x\n", rsp->ccode); +- status = KFWUM_STATUS_ERROR; +- } +- +- if(status == KFWUM_STATUS_OK) +- { +- pGetInfo = (struct KfwumGetInfoResp *) rsp->data; +- if(output) +- { +- printf("\nFWUM info\n"); +- printf("=========\n"); +- printf("Protocol Revision : %02Xh\n", +- pGetInfo->protocolRevision); +- printf("Controller Device Id : %02Xh\n", +- pGetInfo->controllerDeviceId); +- printf("Firmware Revision : %u.%u%u", +- pGetInfo->firmRev1, pGetInfo->firmRev2 >> 4, +- pGetInfo->firmRev2 & 0x0f); +- if(pGetInfo->byte.mode != 0) +- { +- printf(" - DEBUG BUILD\n"); +- } +- else +- { +- printf("\n"); +- } +- printf("Number Of Memory Bank : %u\n",pGetInfo->numBank); +- } +- * pNumBank = pGetInfo->numBank; +- +- /* Determine wich type of download to use: */ +- /* Old FWUM or Old IPMC fw (data_len < 7) --> +- Address with small buffer size */ +- if ( (pGetInfo->protocolRevision) <= 0x05 || (rsp->data_len < 7 ) ) +- { +- saveFirmwareInfo.downloadType = KFWUM_DOWNLOAD_TYPE_ADDRESS; +- saveFirmwareInfo.bufferSize = KFWUM_SMALL_BUFFER; +- saveFirmwareInfo.overheadSize = KFWUM_OLD_CMD_OVERHEAD; +- +- if(verbose) +- { +- printf("Protocol Revision :"); +- printf(" <= 5 detected, adjusting buffers\n"); +- } +- } +- else /* Both fw are using the new protocol */ +- { +- saveFirmwareInfo.downloadType = KFWUM_DOWNLOAD_TYPE_SEQUENCE; +- saveFirmwareInfo.overheadSize = KFWUM_NEW_CMD_OVERHEAD; +- /* Buffer size depending on access type (Local or remote) */ +- /* Look if we run remote or locally */ +- +- if(verbose) +- { +- printf("Protocol Revision :"); +- printf(" > 5 optimizing buffers\n"); +- } +- +- if(strstr(intf->name,"lan")!= NULL) /* also covers lanplus */ +- { +- saveFirmwareInfo.bufferSize = KFWUM_SMALL_BUFFER; +- if(verbose) +- { +- printf("IOL payload size : %d\n" , +- saveFirmwareInfo.bufferSize); +- } +- } +- else if +- ( +- (strstr(intf->name,"open")!= NULL) +- && +- intf->target_addr != IPMI_BMC_SLAVE_ADDR +- && +- ( +- intf->target_addr != intf->my_addr +- ) +- ) +- { +- saveFirmwareInfo.bufferSize = KFWUM_SMALL_BUFFER; +- if(verbose) +- { +- printf("IPMB payload size : %d\n" , +- saveFirmwareInfo.bufferSize); +- } +- } +- else +- { +- saveFirmwareInfo.bufferSize = KFWUM_BIG_BUFFER; +- if(verbose) +- { +- printf("SMI payload size : %d\n", +- saveFirmwareInfo.bufferSize); +- } +- } +- } +- } +- return status; ++ int rc = 0; ++ static struct KfwumGetInfoResp *pGetInfo; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_FIRMWARE; ++ req.msg.cmd = KFWUM_CMD_ID_GET_FIRMWARE_INFO; ++ req.msg.data_len = 0; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (!rsp) { ++ lprintf(LOG_ERR, "Error in FWUM Firmware Get Info Command."); ++ return (-1); ++ } else if (rsp->ccode != 0) { ++ lprintf(LOG_ERR, "FWUM Firmware Get Info returned %x", ++ rsp->ccode); ++ return (-1); ++ } ++ ++ pGetInfo = (struct KfwumGetInfoResp *)rsp->data; ++ if (output) { ++ printf("\nFWUM info\n"); ++ printf("=========\n"); ++ printf("Protocol Revision : %02Xh\n", ++ pGetInfo->protocolRevision); ++ printf("Controller Device Id : %02Xh\n", ++ pGetInfo->controllerDeviceId); ++ printf("Firmware Revision : %u.%u%u", ++ pGetInfo->firmRev1, pGetInfo->firmRev2 >> 4, ++ pGetInfo->firmRev2 & 0x0f); ++ if (pGetInfo->byte.mode != 0) { ++ printf(" - DEBUG BUILD\n"); ++ } else { ++ printf("\n"); ++ } ++ printf("Number Of Memory Bank : %u\n", pGetInfo->numBank); ++ } ++ *pNumBank = pGetInfo->numBank; ++ /* Determine wich type of download to use: */ ++ /* Old FWUM or Old IPMC fw (data_len < 7) ++ * --> Address with small buffer size ++ */ ++ if ((pGetInfo->protocolRevision) <= 0x05 || (rsp->data_len < 7 )) { ++ save_fw_nfo.downloadType = KFWUM_DOWNLOAD_TYPE_ADDRESS; ++ save_fw_nfo.bufferSize = KFWUM_SMALL_BUFFER; ++ save_fw_nfo.overheadSize = KFWUM_OLD_CMD_OVERHEAD; ++ if (verbose) { ++ printf("Protocol Revision :"); ++ printf(" <= 5 detected, adjusting buffers\n"); ++ } ++ } else { ++ /* Both fw are using the new protocol */ ++ save_fw_nfo.downloadType = KFWUM_DOWNLOAD_TYPE_SEQUENCE; ++ save_fw_nfo.overheadSize = KFWUM_NEW_CMD_OVERHEAD; ++ /* Buffer size depending on access type (Local or remote) */ ++ /* Look if we run remote or locally */ ++ if (verbose) { ++ printf("Protocol Revision :"); ++ printf(" > 5 optimizing buffers\n"); ++ } ++ if (strstr(intf->name,"lan") != NULL) { ++ /* also covers lanplus */ ++ save_fw_nfo.bufferSize = KFWUM_SMALL_BUFFER; ++ if (verbose) { ++ printf("IOL payload size : %d\n", ++ save_fw_nfo.bufferSize); ++ } ++ } else if ((strstr(intf->name,"open")!= NULL) ++ && intf->target_addr != IPMI_BMC_SLAVE_ADDR ++ && (intf->target_addr != intf->my_addr)) { ++ save_fw_nfo.bufferSize = KFWUM_SMALL_BUFFER; ++ if (verbose) { ++ printf("IPMB payload size : %d\n", ++ save_fw_nfo.bufferSize); ++ } ++ } else { ++ save_fw_nfo.bufferSize = KFWUM_BIG_BUFFER; ++ if (verbose) { ++ printf("SMI payload size : %d\n", ++ save_fw_nfo.bufferSize); ++ } ++ } ++ } ++ return rc; + } + +-/* KfwumGetDeviceInfo - Get IPMC/Board information +- * +- * * intf : IPMI interface +- * output : when set to non zero, queried information is displayed ++/* KfwumGetDeviceInfo - Get IPMC/Board information ++ * ++ * *intf: IPMI interface ++ * output: when set to non zero, queried information is displayed + * tKFWUM_BoardInfo: output ptr for IPMC/Board information ++ * ++ * returns 0 on success, otherwise (-1) + */ +-static tKFWUM_Status KfwumGetDeviceInfo(struct ipmi_intf * intf, +- unsigned char output, tKFWUM_BoardInfo * pBoardInfo) ++int ++KfwumGetDeviceInfo(struct ipmi_intf *intf, unsigned char output, ++ tKFWUM_BoardInfo *pBoardInfo) + { +- struct ipm_devid_rsp *pGetDevId; +- tKFWUM_Status status = KFWUM_STATUS_OK; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- +- /* Send Get Device Id */ +- if(status == KFWUM_STATUS_OK) +- { +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_APP; +- req.msg.cmd = BMC_GET_DEVICE_ID; +- req.msg.data_len = 0; +- +- rsp = intf->sendrecv(intf, &req); +- if (!rsp) +- { +- printf("Error in Get Device Id Command\n"); +- status = KFWUM_STATUS_ERROR; +- } +- else if (rsp->ccode) +- { +- printf("Get Device Id returned %x\n", rsp->ccode); +- status = KFWUM_STATUS_ERROR; +- } +- } +- +- if(status == KFWUM_STATUS_OK) +- { +- pGetDevId = (struct ipm_devid_rsp *) rsp->data; +- pBoardInfo->iana = IPM_DEV_MANUFACTURER_ID(pGetDevId->manufacturer_id); +- pBoardInfo->boardId = buf2short(pGetDevId->product_id); +- if(output) +- { +- printf("\nIPMC Info\n"); +- printf("=========\n"); +- printf("Manufacturer Id : %u\n",pBoardInfo->iana); +- printf("Board Id : %u\n",pBoardInfo->boardId); +- printf("Firmware Revision : %u.%u%u", +- pGetDevId->fw_rev1, pGetDevId->fw_rev2 >> 4, +- pGetDevId->fw_rev2 & 0x0f); +- if( +- ( +- ( pBoardInfo->iana == KFWUM_IANA_KONTRON) +- && +- (pBoardInfo->boardId = KFWUM_BOARD_KONTRON_5002) +- ) +- ) +- { +- printf(" SDR %u\n", pGetDevId->aux_fw_rev[0]); +- } +- else +- { +- printf("\n"); +- } +- } +- } +- +- return status; ++ struct ipm_devid_rsp *pGetDevId; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ /* Send Get Device Id */ ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_APP; ++ req.msg.cmd = BMC_GET_DEVICE_ID; ++ req.msg.data_len = 0; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error in Get Device Id Command"); ++ return (-1); ++ } else if (rsp->ccode != 0) { ++ lprintf(LOG_ERR, "Get Device Id returned %x", ++ rsp->ccode); ++ return (-1); ++ } ++ pGetDevId = (struct ipm_devid_rsp *)rsp->data; ++ pBoardInfo->iana = IPM_DEV_MANUFACTURER_ID(pGetDevId->manufacturer_id); ++ pBoardInfo->boardId = buf2short(pGetDevId->product_id); ++ if (output) { ++ printf("\nIPMC Info\n"); ++ printf("=========\n"); ++ printf("Manufacturer Id : %u\n", ++ pBoardInfo->iana); ++ printf("Board Id : %u\n", ++ pBoardInfo->boardId); ++ printf("Firmware Revision : %u.%u%u", ++ pGetDevId->fw_rev1, pGetDevId->fw_rev2 >> 4, ++ pGetDevId->fw_rev2 & 0x0f); ++ if (((pBoardInfo->iana == IPMI_OEM_KONTRON) ++ && (pBoardInfo->boardId = KFWUM_BOARD_KONTRON_5002))) { ++ printf(" SDR %u", pGetDevId->aux_fw_rev[0]); ++ } ++ printf("\n"); ++ } ++ return 0; + } + +- +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(1) +-#endif +-struct KfwumGetStatusResp { +- unsigned char bankState; +- unsigned char firmLengthLSB; +- unsigned char firmLengthMid; +- unsigned char firmLengthMSB; +- unsigned char firmRev1; +- unsigned char firmRev2; +- unsigned char firmRev3; +-} ATTRIBUTE_PACKING; +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(0) +-#endif +- +- +-const struct valstr bankStateValS[] = { +- { 0x00, "Not programmed" }, +- { 0x01, "New firmware" }, +- { 0x02, "Wait for validation" }, +- { 0x03, "Last Known Good" }, +- { 0x04, "Previous Good" } +-}; +- + /* KfwumGetStatus - Get (and prints) FWUM banks information +- * +- * * intf : IPMI interface ++ * ++ * *intf : IPMI interface ++ * ++ * returns 0 on success, otherwise (-1) + */ +-static tKFWUM_Status KfwumGetStatus(struct ipmi_intf * intf) ++int ++KfwumGetStatus(struct ipmi_intf * intf) + { +- tKFWUM_Status status = KFWUM_STATUS_OK; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- struct KfwumGetStatusResp *pGetStatus; +- unsigned char numBank; +- unsigned char counter; +- +- if(verbose) +- { +- printf(" Getting Status!\n"); +- } +- +- /* Retreive the number of bank */ +- status = KfwumGetInfo(intf, 0, &numBank); +- +- for( +- counter = 0; +- (counter < numBank) && (status == KFWUM_STATUS_OK); +- counter ++ +- ) +- { +- /* Retreive the status of each bank */ +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_FIRMWARE; +- req.msg.cmd = KFWUM_CMD_ID_GET_FIRMWARE_STATUS; +- req.msg.data = &counter; +- req.msg.data_len = 1; +- +- rsp = intf->sendrecv(intf, &req); +- +- if (!rsp) +- { +- printf("Error in FWUM Firmware Get Status Command\n"); +- status = KFWUM_STATUS_ERROR; +- } +- else if (rsp->ccode) +- { +- printf("FWUM Firmware Get Status returned %x\n", rsp->ccode); +- status = KFWUM_STATUS_ERROR; +- } +- +- +- if(status == KFWUM_STATUS_OK) +- { +- pGetStatus = (struct KfwumGetStatusResp *) rsp->data; +- printf("\nBank State %d : %s\n", counter, val2str( +- pGetStatus->bankState, bankStateValS)); +- if(pGetStatus->bankState) +- { +- unsigned long firmLength; +- firmLength = pGetStatus->firmLengthMSB; +- firmLength = firmLength << 8; +- firmLength |= pGetStatus->firmLengthMid; +- firmLength = firmLength << 8; +- firmLength |= pGetStatus->firmLengthLSB; +- +- printf("Firmware Length : %ld bytes\n", firmLength); +- printf("Firmware Revision : %u.%u%u SDR %u\n", +- pGetStatus->firmRev1, pGetStatus->firmRev2 >> 4, +- pGetStatus->firmRev2 & 0x0f, pGetStatus->firmRev3); +- } +- } +- } +- printf("\n"); +- return status; ++ int rc = 0; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ struct KfwumGetStatusResp *pGetStatus; ++ unsigned char numBank; ++ unsigned char counter; ++ unsigned long firmLength; ++ if (verbose) { ++ printf(" Getting Status!\n"); ++ } ++ /* Retreive the number of bank */ ++ rc = KfwumGetInfo(intf, 0, &numBank); ++ for(counter = 0; ++ (counter < numBank) && (rc == 0); ++ counter ++) { ++ /* Retreive the status of each bank */ ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_FIRMWARE; ++ req.msg.cmd = KFWUM_CMD_ID_GET_FIRMWARE_STATUS; ++ req.msg.data = &counter; ++ req.msg.data_len = 1; ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, ++ "Error in FWUM Firmware Get Status Command."); ++ rc = (-1); ++ break; ++ } else if (rsp->ccode) { ++ lprintf(LOG_ERR, ++ "FWUM Firmware Get Status returned %x", ++ rsp->ccode); ++ rc = (-1); ++ break; ++ } ++ pGetStatus = (struct KfwumGetStatusResp *) rsp->data; ++ printf("\nBank State %d : %s\n", ++ counter, ++ val2str(pGetStatus->bankState, bankStateValS)); ++ if (!pGetStatus->bankState) { ++ continue; ++ } ++ firmLength = pGetStatus->firmLengthMSB; ++ firmLength = firmLength << 8; ++ firmLength |= pGetStatus->firmLengthMid; ++ firmLength = firmLength << 8; ++ firmLength |= pGetStatus->firmLengthLSB; ++ printf("Firmware Length : %ld bytes\n", ++ firmLength); ++ printf("Firmware Revision : %u.%u%u SDR %u\n", ++ pGetStatus->firmRev1, ++ pGetStatus->firmRev2 >> 4, ++ pGetStatus->firmRev2 & 0x0f, ++ pGetStatus->firmRev3); ++ } ++ printf("\n"); ++ return rc; + } + +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(1) +-#endif +-struct KfwumManualRollbackReq{ +- unsigned char type; +-} ATTRIBUTE_PACKING; +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(0) +-#endif +- +- + /* KfwumManualRollback - Ask IPMC to rollback to previous version +- * +- * * intf : IPMI interface ++ * ++ * *intf : IPMI interface ++ * ++ * returns 0 on success ++ * returns (-1) on error + */ +-static tKFWUM_Status KfwumManualRollback(struct ipmi_intf * intf) ++int ++KfwumManualRollback(struct ipmi_intf *intf) + { +- tKFWUM_Status status = KFWUM_STATUS_OK; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- struct KfwumManualRollbackReq thisReq; +- +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_FIRMWARE; +- req.msg.cmd = KFWUM_CMD_ID_MANUAL_ROLLBACK; +- +- thisReq.type = 0; /* Wait BMC shutdown */ +- +- req.msg.data = (unsigned char *) &thisReq; +- req.msg.data_len = 1; +- +- rsp = intf->sendrecv(intf, &req); +- +- if (!rsp) +- { +- printf("Error in FWUM Manual Rollback Command\n"); +- status = KFWUM_STATUS_ERROR; +- } +- else if (rsp->ccode) +- { +- printf("Error in FWUM Manual Rollback Command returned %x\n", +- rsp->ccode); +- status = KFWUM_STATUS_ERROR; +- } +- +- if(status == KFWUM_STATUS_OK) +- { +- printf("FWUM Starting Manual Rollback \n"); +- } +- return status; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ struct KfwumManualRollbackReq thisReq; ++ ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_FIRMWARE; ++ req.msg.cmd = KFWUM_CMD_ID_MANUAL_ROLLBACK; ++ thisReq.type = 0; /* Wait BMC shutdown */ ++ req.msg.data = (unsigned char *)&thisReq; ++ req.msg.data_len = 1; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error in FWUM Manual Rollback Command."); ++ return (-1); ++ } else if (rsp->ccode != 0) { ++ lprintf(LOG_ERR, ++ "Error in FWUM Manual Rollback Command returned %x", ++ rsp->ccode); ++ return (-1); ++ } ++ printf("FWUM Starting Manual Rollback \n"); ++ return 0; + } + +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(1) +-#endif +-struct KfwumStartFirmwareDownloadReq{ +- unsigned char lengthLSB; +- unsigned char lengthMid; +- unsigned char lengthMSB; +- unsigned char paddingLSB; +- unsigned char paddingMSB; +- unsigned char useSequence; +-} ATTRIBUTE_PACKING; +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(0) +-#endif +- +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(1) +-#endif +-struct KfwumStartFirmwareDownloadResp { +- unsigned char bank; +-} ATTRIBUTE_PACKING; +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(0) +-#endif +- +-static tKFWUM_Status KfwumStartFirmwareImage(struct ipmi_intf * intf, +- unsigned long length,unsigned short padding) ++int ++KfwumStartFirmwareImage(struct ipmi_intf *intf, unsigned long length, ++ unsigned short padding) + { +- tKFWUM_Status status = KFWUM_STATUS_OK; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- struct KfwumStartFirmwareDownloadResp *pResp; +- struct KfwumStartFirmwareDownloadReq thisReq; +- +- thisReq.lengthLSB = length & 0x000000ff; +- thisReq.lengthMid = (length >> 8) & 0x000000ff; +- thisReq.lengthMSB = (length >> 16) & 0x000000ff; +- thisReq.paddingLSB = padding & 0x00ff; +- thisReq.paddingMSB = (padding>> 8) & 0x00ff; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ struct KfwumStartFirmwareDownloadResp *pResp; ++ struct KfwumStartFirmwareDownloadReq thisReq; ++ ++ thisReq.lengthLSB = length & 0x000000ff; ++ thisReq.lengthMid = (length >> 8) & 0x000000ff; ++ thisReq.lengthMSB = (length >> 16) & 0x000000ff; ++ thisReq.paddingLSB = padding & 0x00ff; ++ thisReq.paddingMSB = (padding>> 8) & 0x00ff; + thisReq.useSequence = 0x01; +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_FIRMWARE; +- req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_IMAGE; +- req.msg.data = (unsigned char *) &thisReq; +- +- /* Look for download type */ +- if ( saveFirmwareInfo.downloadType == KFWUM_DOWNLOAD_TYPE_ADDRESS ) +- { +- req.msg.data_len = 5; +- } +- else +- { +- req.msg.data_len = 6; +- } +- +- rsp = intf->sendrecv(intf, &req); +- +- if (!rsp) +- { +- printf("Error in FWUM Firmware Start Firmware Image Download Command\n"); +- status = KFWUM_STATUS_ERROR; +- } +- else if (rsp->ccode) +- { +- printf("FWUM Firmware Start Firmware Image Download returned %x\n", +- rsp->ccode); +- status = KFWUM_STATUS_ERROR; +- } +- +- if(status == KFWUM_STATUS_OK) +- { +- pResp = (struct KfwumStartFirmwareDownloadResp *) rsp->data; +- printf("Bank holding new firmware : %d\n", pResp->bank); +- sleep(5); +- } +- return status; ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_FIRMWARE; ++ req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_IMAGE; ++ req.msg.data = (unsigned char *) &thisReq; ++ /* Look for download type */ ++ if (save_fw_nfo.downloadType == KFWUM_DOWNLOAD_TYPE_ADDRESS) { ++ req.msg.data_len = 5; ++ } else { ++ req.msg.data_len = 6; ++ } ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, ++ "Error in FWUM Firmware Start Firmware Image Download Command."); ++ return (-1); ++ } else if (rsp->ccode) { ++ lprintf(LOG_ERR, ++ "FWUM Firmware Start Firmware Image Download returned %x", ++ rsp->ccode); ++ return (-1); ++ } ++ pResp = (struct KfwumStartFirmwareDownloadResp *)rsp->data; ++ printf("Bank holding new firmware : %d\n", pResp->bank); ++ sleep(5); ++ return 0; + } + +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(1) +-#endif +-struct KfwumSaveFirmwareAddressReq ++int ++KfwumSaveFirmwareImage(struct ipmi_intf *intf, unsigned char sequenceNumber, ++ unsigned long address, unsigned char *pFirmBuf, ++ unsigned char *pInBufLength) + { +- unsigned char addressLSB; +- unsigned char addressMid; +- unsigned char addressMSB; +- unsigned char numBytes; +- unsigned char txBuf[KFWUM_SMALL_BUFFER-KFWUM_OLD_CMD_OVERHEAD]; +-} ATTRIBUTE_PACKING; +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(0) +-#endif +- +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(1) +-#endif +-struct KfwumSaveFirmwareSequenceReq +-{ +- unsigned char sequenceNumber; +- unsigned char txBuf[KFWUM_BIG_BUFFER]; +-} ATTRIBUTE_PACKING; +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(0) +-#endif +- +- +-#define FWUM_SAVE_FIRMWARE_NO_RESPONSE_LIMIT ((unsigned char)6) ++ int rc = 0; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ struct KfwumSaveFirmwareAddressReq addr_req; ++ struct KfwumSaveFirmwareSequenceReq seq_req; ++ int retry = 0; ++ int no_rsp = 0; ++ do { ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_FIRMWARE; ++ req.msg.cmd = KFWUM_CMD_ID_SAVE_FIRMWARE_IMAGE; ++ if (save_fw_nfo.downloadType == KFWUM_DOWNLOAD_TYPE_ADDRESS) { ++ addr_req.addressLSB = address & 0x000000ff; ++ addr_req.addressMid = (address >> 8) & 0x000000ff; ++ addr_req.addressMSB = (address >> 16) & 0x000000ff; ++ addr_req.numBytes = *pInBufLength; ++ memcpy(addr_req.txBuf, pFirmBuf, *pInBufLength); ++ req.msg.data = (unsigned char *)&addr_req; ++ req.msg.data_len = *pInBufLength + 4; ++ } else { ++ seq_req.sequenceNumber = sequenceNumber; ++ memcpy(seq_req.txBuf, pFirmBuf, *pInBufLength); ++ req.msg.data = (unsigned char *)&seq_req; ++ req.msg.data_len = *pInBufLength + sizeof(unsigned char); ++ /* + 1 => sequenceNumber*/ ++ } ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, ++ "Error in FWUM Firmware Save Firmware Image Download Command."); ++ /* We don't receive "C7" on errors with IOL, ++ * instead we receive nothing ++ */ ++ if (strstr(intf->name, "lan") != NULL) { ++ no_rsp++; ++ if (no_rsp < FWUM_SAVE_FIRMWARE_NO_RESPONSE_LIMIT) { ++ *pInBufLength -= 1; ++ continue; ++ } ++ lprintf(LOG_ERR, ++ "Error, too many commands without response."); ++ *pInBufLength = 0; ++ break; ++ } /* For other interface keep trying */ ++ } else if (rsp->ccode != 0) { ++ if (rsp->ccode == 0xc0) { ++ sleep(1); ++ } else if ((rsp->ccode == 0xc7) ++ || ((rsp->ccode == 0xc3) ++ && (sequenceNumber == 0))) { ++ *pInBufLength -= 1; ++ retry = 1; ++ } else if (rsp->ccode == 0x82) { ++ /* Double sent, continue */ ++ rc = 0; ++ break; ++ } else if (rsp->ccode == 0x83) { ++ if (retry == 0) { ++ retry = 1; ++ continue; ++ } ++ rc = (-1); ++ break; ++ } else if (rsp->ccode == 0xcf) { ++ /* Ok if receive duplicated request */ ++ retry = 1; ++ } else if (rsp->ccode == 0xc3) { ++ if (retry == 0) { ++ retry = 1; ++ continue; ++ } ++ rc = (-1); ++ break; ++ } else { ++ lprintf(LOG_ERR, ++ "FWUM Firmware Save Firmware Image Download returned %x", ++ rsp->ccode); ++ rc = (-1); ++ break; ++ } ++ } else { ++ break; ++ } ++ } while (1); ++ return rc; ++} + +-static tKFWUM_Status KfwumSaveFirmwareImage(struct ipmi_intf * intf, +- unsigned char sequenceNumber, unsigned long address, unsigned char *pFirmBuf, +- unsigned char * pInBufLength) ++int ++KfwumFinishFirmwareImage(struct ipmi_intf *intf, tKFWUM_InFirmwareInfo firmInfo) + { +- tKFWUM_Status status = KFWUM_STATUS_OK; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- unsigned char out = 0; +- unsigned char retry = 0; +- unsigned char noResponse = 0 ; +- +- struct KfwumSaveFirmwareAddressReq addressReq; +- struct KfwumSaveFirmwareSequenceReq sequenceReq; +- +- do +- { +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_FIRMWARE; +- req.msg.cmd = KFWUM_CMD_ID_SAVE_FIRMWARE_IMAGE; +- +- if (saveFirmwareInfo.downloadType == KFWUM_DOWNLOAD_TYPE_ADDRESS ) +- { +- addressReq.addressLSB = address & 0x000000ff; +- addressReq.addressMid = (address >> 8) & 0x000000ff; +- addressReq.addressMSB = (address >> 16) & 0x000000ff; +- addressReq.numBytes = (* pInBufLength); +- memcpy(addressReq.txBuf, pFirmBuf, (* pInBufLength)); +- req.msg.data = (unsigned char *) &addressReq; +- req.msg.data_len = (* pInBufLength)+4; +- } +- else +- { +- sequenceReq.sequenceNumber = sequenceNumber; +- memcpy(sequenceReq.txBuf, pFirmBuf, (* pInBufLength)); +- req.msg.data = (unsigned char *) &sequenceReq; +- req.msg.data_len = (* pInBufLength)+sizeof(unsigned char); /* + 1 => sequenceNumber*/ +- } +- +- rsp = intf->sendrecv(intf, &req); +- +- if (!rsp) +- { +- printf("Error in FWUM Firmware Save Firmware Image Download Command\n"); +- +- out = 0; +- status = KFWUM_STATUS_OK; +- +- /* With IOL, we don't receive "C7" on errors, instead we receive +- nothing */ +- if(strstr(intf->name,"lan")!= NULL) +- { +- noResponse++; +- +- if(noResponse < FWUM_SAVE_FIRMWARE_NO_RESPONSE_LIMIT ) +- { +- (* pInBufLength) -= 1; +- out = 0; +- } +- else +- { +- printf("Error, too many commands without response\n"); +- (* pInBufLength) = 0 ; +- out = 1; +- } +- } /* For other interface keep trying */ +- } +- else if (rsp->ccode) +- { +- if(rsp->ccode == 0xc0) +- { +- status = KFWUM_STATUS_OK; +- sleep(1); +- } +- else if( +- (rsp->ccode == 0xc7) +- || +- ( +- (rsp->ccode == 0xC3) && +- (sequenceNumber == 0) +- ) +- ) +- { +- (* pInBufLength) -= 1; +- status = KFWUM_STATUS_OK; +- retry = 1; +- } +- else if(rsp->ccode == 0x82) +- { +- /* Double sent, continue */ +- status = KFWUM_STATUS_OK; +- out = 1; +- } +- else if(rsp->ccode == 0x83) +- { +- if(retry == 0) +- { +- retry = 1; +- status = KFWUM_STATUS_OK; +- } +- else +- { +- status = KFWUM_STATUS_ERROR; +- out = 1; +- } +- } +- else if(rsp->ccode == 0xcf) /* Ok if receive duplicated request */ +- { +- retry = 1; +- status = KFWUM_STATUS_OK; +- } +- else if(rsp->ccode == 0xC3) +- { +- if(retry == 0) +- { +- retry = 1; +- status = KFWUM_STATUS_OK; +- } +- else +- { +- status = KFWUM_STATUS_ERROR; +- out = 1; +- } +- } +- else +- { +- printf("FWUM Firmware Save Firmware Image Download returned %x\n", +- rsp->ccode); +- status = KFWUM_STATUS_ERROR; +- out = 1; +- } +- } +- else +- { +- out = 1; +- } +- }while(out == 0); +- return status; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ struct KfwumFinishFirmwareDownloadReq thisReq; ++ ++ thisReq.versionMaj = firmInfo.versMajor; ++ thisReq.versionMinSub = ((firmInfo.versMinor <<4) ++ | firmInfo.versSubMinor); ++ thisReq.versionSdr = firmInfo.sdrRev; ++ thisReq.reserved = 0; ++ /* Byte 4 reserved, write 0 */ ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_FIRMWARE; ++ req.msg.cmd = KFWUM_CMD_ID_FINISH_FIRMWARE_IMAGE; ++ req.msg.data = (unsigned char *)&thisReq; ++ req.msg.data_len = 4; ++ /* Infinite loop if BMC doesn't reply or replies 0xc0 every time. */ ++ do { ++ rsp = intf->sendrecv(intf, &req); ++ } while (rsp == NULL || rsp->ccode == 0xc0); ++ if (!rsp) { ++ lprintf(LOG_ERR, ++ "Error in FWUM Firmware Finish Firmware Image Download Command."); ++ return (-1); ++ } else if (rsp->ccode != 0) { ++ lprintf(LOG_ERR, ++ "FWUM Firmware Finish Firmware Image Download returned %x", ++ rsp->ccode); ++ return (-1); ++ } ++ return 0; + } + +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(1) +-#endif +-struct KfwumFinishFirmwareDownloadReq{ +- unsigned char versionMaj; +- unsigned char versionMinSub; +- unsigned char versionSdr; +- unsigned char reserved; +-} ATTRIBUTE_PACKING; +-#ifdef HAVE_PRAGMA_PACK +-#pragma pack(0) +-#endif +- +-static tKFWUM_Status KfwumFinishFirmwareImage(struct ipmi_intf * intf, +- tKFWUM_InFirmwareInfo firmInfo) ++int ++KfwumUploadFirmware(struct ipmi_intf *intf, unsigned char *pBuffer, ++ unsigned long totalSize) + { +- tKFWUM_Status status = KFWUM_STATUS_OK; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- struct KfwumFinishFirmwareDownloadReq thisReq; +- +- thisReq.versionMaj = firmInfo.versMajor; +- thisReq.versionMinSub = ((firmInfo.versMinor <<4) | firmInfo.versSubMinor); +- thisReq.versionSdr = firmInfo.sdrRev; +- thisReq.reserved = 0; +- /* Byte 4 reserved, write 0 */ +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_FIRMWARE; +- req.msg.cmd = KFWUM_CMD_ID_FINISH_FIRMWARE_IMAGE; +- req.msg.data = (unsigned char *) &thisReq; +- req.msg.data_len = 4; +- +- do +- { +- rsp = intf->sendrecv(intf, &req); +- }while (rsp == NULL || rsp->ccode == 0xc0); +- +- if (!rsp) +- { +- printf("Error in FWUM Firmware Finish Firmware Image Download Command\n"); +- status = KFWUM_STATUS_ERROR; +- } +- else if (rsp->ccode) +- { +- printf("FWUM Firmware Finish Firmware Image Download returned %x\n", +- rsp->ccode); +- status = KFWUM_STATUS_ERROR; +- } +- +- return status; ++ int rc = (-1); ++ unsigned long address = 0x0; ++ unsigned char writeSize; ++ unsigned char oldWriteSize; ++ unsigned long lastAddress = 0; ++ unsigned char sequenceNumber = 0; ++ unsigned char retry = FWUM_MAX_UPLOAD_RETRY; ++ unsigned char isLengthValid = 1; ++ do { ++ writeSize = save_fw_nfo.bufferSize - save_fw_nfo.overheadSize; ++ /* Reach the end */ ++ if (address + writeSize > totalSize) { ++ writeSize = (totalSize - address); ++ } else if (((address % KFWUM_PAGE_SIZE) ++ + writeSize) > KFWUM_PAGE_SIZE) { ++ /* Reach boundary end */ ++ writeSize = (KFWUM_PAGE_SIZE - (address % KFWUM_PAGE_SIZE)); ++ } ++ oldWriteSize = writeSize; ++ rc = KfwumSaveFirmwareImage(intf, sequenceNumber, ++ address, &pBuffer[address], &writeSize); ++ if ((rc != 0) && (retry-- != 0)) { ++ address = lastAddress; ++ rc = 0; ++ } else if ( writeSize == 0) { ++ rc = (-1); ++ } else { ++ if (writeSize != oldWriteSize) { ++ printf("Adjusting length to %d bytes \n", ++ writeSize); ++ save_fw_nfo.bufferSize -= (oldWriteSize - writeSize); ++ } ++ retry = FWUM_MAX_UPLOAD_RETRY; ++ lastAddress = address; ++ address+= writeSize; ++ } ++ if (rc == 0) { ++ if ((address % 1024) == 0) { ++ KfwumShowProgress("Writting Firmware in Flash", ++ address, totalSize); ++ } ++ sequenceNumber++; ++ } ++ } while ((rc == 0) && (address < totalSize)); ++ if (rc == 0) { ++ KfwumShowProgress("Writting Firmware in Flash", ++ 100, 100); ++ } ++ return rc; + } + +- +-#define FWUM_MAX_UPLOAD_RETRY 6 +-static tKFWUM_Status KfwumUploadFirmware(struct ipmi_intf * intf, +- unsigned char * pBuffer, unsigned long totalSize) ++int ++KfwumStartFirmwareUpgrade(struct ipmi_intf *intf) + { +- tKFWUM_Status status = KFWUM_STATUS_ERROR; +- unsigned long address = 0x0; +- unsigned char writeSize; +- unsigned char oldWriteSize; +- unsigned long lastAddress = 0; +- unsigned char sequenceNumber = 0; +- unsigned char retry = FWUM_MAX_UPLOAD_RETRY; +- unsigned char isLengthValid = 1; +- +- do +- { +- writeSize = saveFirmwareInfo.bufferSize - saveFirmwareInfo.overheadSize; +- +- /* Reach the end */ +- if( address + writeSize > totalSize ) +- { +- writeSize = (totalSize - address); +- } +- /* Reach boundary end */ +- else if(((address % KFWUM_PAGE_SIZE) + writeSize) > KFWUM_PAGE_SIZE) +- { +- writeSize = (KFWUM_PAGE_SIZE - (address % KFWUM_PAGE_SIZE)); +- } +- +- oldWriteSize = writeSize; +- status = KfwumSaveFirmwareImage(intf, sequenceNumber, address, +- &pBuffer[address], &writeSize); +- +- if((status != KFWUM_STATUS_OK) && (retry-- != 0)) +- { +- address = lastAddress; +- status = KFWUM_STATUS_OK; +- } +- else if( writeSize == 0 ) +- { +- status = KFWUM_STATUS_ERROR; +- } +- else +- { +- if(writeSize != oldWriteSize) +- { +- printf("Adjusting length to %d bytes \n", writeSize); +- saveFirmwareInfo.bufferSize -= (oldWriteSize - writeSize); +- } +- +- retry = FWUM_MAX_UPLOAD_RETRY; +- lastAddress = address; +- address+= writeSize; +- } +- +- if(status == KFWUM_STATUS_OK) +- { +- if((address % 1024) == 0) +- { +- KfwumShowProgress((const unsigned char *)\ +- "Writting Firmware in Flash",address,totalSize); +- } +- sequenceNumber++; +- } +- +- }while((status == KFWUM_STATUS_OK) && (address < totalSize )); +- +- if(status == KFWUM_STATUS_OK) +- { +- KfwumShowProgress((const unsigned char *)\ +- "Writting Firmware in Flash", 100 , 100 ); +- } +- +- return(status); ++ int rc = 0; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ /* Upgrade type, wait BMC shutdown */ ++ unsigned char upgType = 0 ; ++ ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_FIRMWARE; ++ req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_UPDATE; ++ req.msg.data = (unsigned char *) &upgType; ++ req.msg.data_len = 1; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, ++ "Error in FWUM Firmware Start Firmware Upgrade Command"); ++ rc = (-1); ++ } else if (rsp->ccode) { ++ if (rsp->ccode == 0xd5) { ++ lprintf(LOG_ERR, ++ "No firmware available for upgrade. Download Firmware first."); ++ } else { ++ lprintf(LOG_ERR, ++ "FWUM Firmware Start Firmware Upgrade returned %x", ++ rsp->ccode); ++ } ++ rc = (-1); ++ } ++ return rc; + } + +-static tKFWUM_Status KfwumStartFirmwareUpgrade(struct ipmi_intf * intf) ++int ++KfwumGetTraceLog(struct ipmi_intf *intf) + { +- tKFWUM_Status status = KFWUM_STATUS_OK; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- unsigned char upgType = 0 ; /* Upgrade type, wait BMC shutdown */ +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_FIRMWARE; +- req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_UPDATE; +- req.msg.data = (unsigned char *) &upgType; +- req.msg.data_len = 1; +- +- rsp = intf->sendrecv(intf, &req); +- +- if (!rsp) +- { +- printf("Error in FWUM Firmware Start Firmware Upgrade Command\n"); +- status = KFWUM_STATUS_ERROR; +- } +- else if (rsp->ccode) +- { +- if(rsp->ccode == 0xd5) +- { +- printf("No firmware available for upgrade. Download Firmware first\n"); +- } +- else +- { +- printf("FWUM Firmware Start Firmware Upgrade returned %x\n", +- rsp->ccode); +- } +- status = KFWUM_STATUS_ERROR; +- } +- +- return status; ++ int rc = 0; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ unsigned char chunkIdx; ++ unsigned char cmdIdx; ++ if (verbose) { ++ printf(" Getting Trace Log!\n"); ++ } ++ for (chunkIdx = 0; ++ (chunkIdx < TRACE_LOG_CHUNK_COUNT) ++ && (rc == 0); ++ chunkIdx++) { ++ /* Retreive each log chunk and print it */ ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_FIRMWARE; ++ req.msg.cmd = KFWUM_CMD_ID_GET_TRACE_LOG; ++ req.msg.data = &chunkIdx; ++ req.msg.data_len = 1; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, ++ "Error in FWUM Firmware Get Trace Log Command"); ++ rc = (-1); ++ break; ++ } else if (rsp->ccode) { ++ lprintf(LOG_ERR, ++ "FWUM Firmware Get Trace Log returned %x", ++ rsp->ccode); ++ rc = (-1); ++ break; ++ } ++ for (cmdIdx=0; cmdIdx < TRACE_LOG_CHUNK_SIZE; cmdIdx++) { ++ /* Don't diplay commands with an invalid state */ ++ if ((rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1] != 0) ++ && (rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx] < KFWUM_CMD_ID_STD_MAX_CMD)) { ++ printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n", ++ CMD_ID_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx]], ++ CMD_STATE_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1]], ++ rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 2]); ++ } else if ((rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1] != 0) ++ && (rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx] >= KFWUM_CMD_ID_EXTENDED_CMD)) { ++ printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n", ++ EXT_CMD_ID_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx] - KFWUM_CMD_ID_EXTENDED_CMD], ++ CMD_STATE_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1]], ++ rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 2]); ++ } ++ } ++ } ++ printf("\n"); ++ return rc; + } + +-#define TRACE_LOG_CHUNK_COUNT 7 +-#define TRACE_LOG_CHUNK_SIZE 7 +-#define TRACE_LOG_ATT_COUNT 3 +-/* String table */ +-/* Must match eFWUM_CmdId */ +-static const char* CMD_ID_STRING[] = { +- "GetFwInfo", +- "KickWatchdog", +- "GetLastAnswer", +- "BootHandshake", +- "ReportStatus", +- "CtrlIPMBLine", +- "SetFwState", +- "GetFwStatus", +- "GetSpiMemStatus", +- "StartFwUpdate", +- "StartFwImage", +- "SaveFwImage", +- "FinishFwImage", +- "ReadFwImage", +- "ManualRollback", +- "GetTraceLog" }; +- +-static const char* EXT_CMD_ID_STRING[] = { +- "FwUpgradeLock", +- "ProcessFwUpg", +- "ProcessFwRb", +- "WaitHSAfterUpg", +- "WaitFirstHSUpg", +- "FwInfoStateChange" }; +- +- +-static const char* CMD_STATE_STRING[] = { +- "Invalid", +- "Begin", +- "Progress", +- "Completed" }; +- +- +-static tKFWUM_Status KfwumGetTraceLog(struct ipmi_intf * intf) ++int ++KfwumGetInfoFromFirmware(unsigned char *pBuf, unsigned long bufSize, ++ tKFWUM_InFirmwareInfo *pInfo) + { +- tKFWUM_Status status = KFWUM_STATUS_OK; +- struct ipmi_rs *rsp; +- struct ipmi_rq req; +- unsigned char chunkIdx; +- unsigned char cmdIdx; +- +- if(verbose) +- { +- printf(" Getting Trace Log!\n"); +- } +- +- for( chunkIdx = 0; (chunkIdx < TRACE_LOG_CHUNK_COUNT) && (status == KFWUM_STATUS_OK); chunkIdx++ ) +- { +- /* Retreive each log chunk and print it */ +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_FIRMWARE; +- req.msg.cmd = KFWUM_CMD_ID_GET_TRACE_LOG; +- req.msg.data = &chunkIdx; +- req.msg.data_len = 1; +- +- rsp = intf->sendrecv(intf, &req); +- +- if (!rsp) +- { +- printf("Error in FWUM Firmware Get Trace Log Command\n"); +- status = KFWUM_STATUS_ERROR; +- } +- else if (rsp->ccode) +- { +- printf("FWUM Firmware Get Trace Log returned %x\n", rsp->ccode); +- status = KFWUM_STATUS_ERROR; +- } +- +- if(status == KFWUM_STATUS_OK) +- { +- for (cmdIdx=0; cmdIdx < TRACE_LOG_CHUNK_SIZE; cmdIdx++) +- { +- /* Don't diplay commands with an invalid state */ +- if ( (rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx+1] != 0) && +- (rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx] < KFWUM_CMD_ID_STD_MAX_CMD)) +- { +- printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n", +- CMD_ID_STRING[rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx]], +- CMD_STATE_STRING[rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx+1]], +- rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx+2]); +- } +- else if ( (rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx+1] != 0) && +- (rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx] >= KFWUM_CMD_ID_EXTENDED_CMD)) +- { +- printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n", +- EXT_CMD_ID_STRING[rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx] - KFWUM_CMD_ID_EXTENDED_CMD], +- CMD_STATE_STRING[rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx+1]], +- rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx+2]); +- } +- } +- } +- } +- printf("\n"); +- return status; +-} ++ unsigned long offset = 0; ++ if (bufSize < (IN_FIRMWARE_INFO_OFFSET_LOCATION + IN_FIRMWARE_INFO_SIZE)) { ++ return (-1); ++ } ++ offset = IN_FIRMWARE_INFO_OFFSET_LOCATION; + ++ /* Now, fill the structure with read informations */ ++ pInfo->checksum = (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + 0 + IN_FIRMWARE_INFO_OFFSET_CHECKSUM ) << 8; + +-/******************************************************************************* +-* Function Name: KfwumGetInfoFromFirmware +-* +-* Description: This function retreive from the firmare the following info : +-* +-* o Checksum +-* o File size (expected) +-* o Board Id +-* o Device Id +-* +-* Restriction: None +-* +-* Input: char * fileName - File to get info from +-* +-* Output: pInfo - container that will hold all the informations gattered. +-* see structure for all details +-* +-* Global: None +-* +-* Return: IFWU_SUCCESS - file ok +-* IFWU_ERROR - file error +-* +-*******************************************************************************/ +-#define IN_FIRMWARE_INFO_OFFSET_LOCATION 0x5a0 +-#define IN_FIRMWARE_INFO_SIZE 20 +-#define IN_FIRMWARE_INFO_OFFSET_FILE_SIZE 0 +-#define IN_FIRMWARE_INFO_OFFSET_CHECKSUM 4 +-#define IN_FIRMWARE_INFO_OFFSET_BOARD_ID 6 +-#define IN_FIRMWARE_INFO_OFFSET_DEVICE_ID 8 +-#define IN_FIRMWARE_INFO_OFFSET_TABLE_VERSION 9 +-#define IN_FIRMWARE_INFO_OFFSET_IMPLEMENT_REV 10 +-#define IN_FIRMWARE_INFO_OFFSET_VERSION_MAJOR 11 +-#define IN_FIRMWARE_INFO_OFFSET_VERSION_MINSUB 12 +-#define IN_FIRMWARE_INFO_OFFSET_SDR_REV 13 +-#define IN_FIRMWARE_INFO_OFFSET_IANA0 14 +-#define IN_FIRMWARE_INFO_OFFSET_IANA1 15 +-#define IN_FIRMWARE_INFO_OFFSET_IANA2 16 +- +-#define KWUM_GET_BYTE_AT_OFFSET(pBuffer,os) pBuffer[os] +- +-tKFWUM_Status KfwumGetInfoFromFirmware(unsigned char * pBuf, +- unsigned long bufSize, tKFWUM_InFirmwareInfo * pInfo) +-{ +- tKFWUM_Status status = KFWUM_STATUS_ERROR; +- +- if(bufSize >= (IN_FIRMWARE_INFO_OFFSET_LOCATION + IN_FIRMWARE_INFO_SIZE)) +- { +- unsigned long offset = IN_FIRMWARE_INFO_OFFSET_LOCATION; +- +- /* Now, fill the structure with read informations */ +- pInfo->checksum = (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+0+IN_FIRMWARE_INFO_OFFSET_CHECKSUM ) << 8; +- pInfo->checksum |= (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+1+IN_FIRMWARE_INFO_OFFSET_CHECKSUM ); +- +- +- pInfo->sumToRemoveFromChecksum= +- KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_CHECKSUM); +- +- pInfo->sumToRemoveFromChecksum+= +- KWUM_GET_BYTE_AT_OFFSET(pBuf , +- offset+IN_FIRMWARE_INFO_OFFSET_CHECKSUM+1); +- +- pInfo->fileSize = +- KWUM_GET_BYTE_AT_OFFSET(pBuf , +- offset+IN_FIRMWARE_INFO_OFFSET_FILE_SIZE+0) << 24; +- pInfo->fileSize |= +- (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_FILE_SIZE+1) << 16; +- pInfo->fileSize |= +- (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_FILE_SIZE+2) << 8; +- pInfo->fileSize |= +- (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_FILE_SIZE+3); +- +- pInfo->boardId = +- KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_BOARD_ID+0) << 8; +- pInfo->boardId |= +- KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_BOARD_ID+1); +- +- pInfo->deviceId = +- KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_DEVICE_ID); +- +- pInfo->tableVers = +- KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_TABLE_VERSION); +- pInfo->implRev = +- KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_IMPLEMENT_REV); +- pInfo->versMajor = +- (KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_VERSION_MAJOR)) & 0x0f; +- pInfo->versMinor = +- (KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_VERSION_MINSUB)>>4) & 0x0f; +- pInfo->versSubMinor = +- (KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_VERSION_MINSUB)) & 0x0f; +- pInfo->sdrRev = +- KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_SDR_REV); +- pInfo->iana = +- KWUM_GET_BYTE_AT_OFFSET(pBuf , +- offset+IN_FIRMWARE_INFO_OFFSET_IANA2) << 16; +- pInfo->iana |= +- (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_IANA1) << 8; +- pInfo->iana |= +- (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, +- offset+IN_FIRMWARE_INFO_OFFSET_IANA0); +- +- KfwumFixTableVersionForOldFirmware(pInfo); +- +- status = KFWUM_STATUS_OK; +- } +- return(status); +-} ++ pInfo->checksum|= (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + 1 + IN_FIRMWARE_INFO_OFFSET_CHECKSUM); + ++ pInfo->sumToRemoveFromChecksum = KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_CHECKSUM); + +-void KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo * pInfo) +-{ +- switch(pInfo->boardId) +- { +- case KFWUM_BOARD_KONTRON_UNKNOWN: +- pInfo->tableVers = 0xff; +- break; +- default: +- /* pInfo->tableVers is already set for the right version */ +- break; +- } +-} ++ pInfo->sumToRemoveFromChecksum+= KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_CHECKSUM + 1); ++ ++ pInfo->fileSize = KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 0) << 24; ++ ++ pInfo->fileSize|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 1) << 16; ++ ++ pInfo->fileSize|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 2) << 8; ++ ++ pInfo->fileSize|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 3); ++ ++ pInfo->boardId = KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_BOARD_ID + 0) << 8; + ++ pInfo->boardId|= KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_BOARD_ID + 1); + +-tKFWUM_Status KfwumValidFirmwareForBoard(tKFWUM_BoardInfo boardInfo, +- tKFWUM_InFirmwareInfo firmInfo) ++ pInfo->deviceId = KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_DEVICE_ID); ++ ++ pInfo->tableVers = KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_TABLE_VERSION); ++ ++ pInfo->implRev = KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_IMPLEMENT_REV); ++ ++ pInfo->versMajor = (KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset ++ + IN_FIRMWARE_INFO_OFFSET_VER_MAJOROR)) & 0x0f; ++ ++ pInfo->versMinor = (KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset ++ + IN_FIRMWARE_INFO_OFFSET_VER_MINORSUB) >> 4) & 0x0f; ++ ++ pInfo->versSubMinor = (KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_VER_MINORSUB)) & 0x0f; ++ ++ pInfo->sdrRev = KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_SDR_REV); ++ ++ pInfo->iana = KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_IANA2) << 16; ++ ++ pInfo->iana|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_IANA1) << 8; ++ ++ pInfo->iana|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, ++ offset + IN_FIRMWARE_INFO_OFFSET_IANA0); ++ ++ KfwumFixTableVersionForOldFirmware(pInfo); ++ return 0; ++} ++ ++void ++KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo * pInfo) + { +- tKFWUM_Status status = KFWUM_STATUS_OK; +- +- if(boardInfo.iana != firmInfo.iana) +- { +- printf("Board IANA does not match firmware IANA\n"); +- status = KFWUM_STATUS_ERROR; +- } +- +- if(boardInfo.boardId != firmInfo.boardId) +- { +- printf("Board IANA does not match firmware IANA\n"); +- status = KFWUM_STATUS_ERROR; +- } +- +- +- if(status == KFWUM_STATUS_ERROR) +- { +- printf("Firmware invalid for target board. Download of upgrade aborted\n"); +- } +- return status; ++ switch(pInfo->boardId) { ++ case KFWUM_BOARD_KONTRON_UNKNOWN: ++ pInfo->tableVers = 0xff; ++ break; ++ default: ++ /* pInfo->tableVers is already set for ++ * the right version ++ */ ++ break; ++ } + } + ++/* ipmi_kfwum_checkfwcompat - check whether firmware we're about to upload is ++ * compatible with board. ++ * ++ * @boardInfo: ++ * @firmInfo: ++ * ++ * returns 0 if compatible, otherwise (-1) ++ */ ++int ++ipmi_kfwum_checkfwcompat(tKFWUM_BoardInfo boardInfo, ++ tKFWUM_InFirmwareInfo firmInfo) ++{ ++ int compatible = 0; ++ if (boardInfo.iana != firmInfo.iana) { ++ lprintf(LOG_ERR, ++ "Board IANA does not match firmware IANA."); ++ compatible = (-1); ++ } ++ if (boardInfo.boardId != firmInfo.boardId) { ++ lprintf(LOG_ERR, ++ "Board IANA does not match firmware IANA."); ++ compatible = (-1); ++ } ++ if (compatible != 0) { ++ lprintf(LOG_ERR, ++ "Firmware invalid for target board. Download of upgrade aborted."); ++ } ++ return compatible; ++} + +-static void KfwumOutputInfo(tKFWUM_BoardInfo boardInfo, +- tKFWUM_InFirmwareInfo firmInfo) ++void ++printf_kfwum_info(tKFWUM_BoardInfo boardInfo, tKFWUM_InFirmwareInfo firmInfo) + { +- printf("Target Board Id : %u\n",boardInfo.boardId); +- printf("Target IANA number : %u\n",boardInfo.iana); +- printf("File Size : %lu bytes\n",firmInfo.fileSize); +- printf("Firmware Version : %d.%d%d SDR %d\n",firmInfo.versMajor, +- firmInfo.versMinor, firmInfo.versSubMinor, firmInfo.sdrRev); ++ printf( ++"Target Board Id : %u\n", boardInfo.boardId); ++ printf( ++"Target IANA number : %u\n", boardInfo.iana); ++ printf( ++"File Size : %lu bytes\n", firmInfo.fileSize); ++ printf( ++"Firmware Version : %d.%d%d SDR %d\n", firmInfo.versMajor, ++firmInfo.versMinor, firmInfo.versSubMinor, firmInfo.sdrRev); + } +diff --git a/ipmitool/lib/ipmi_hpmfwupg.c b/ipmitool/lib/ipmi_hpmfwupg.c +index 630c0e7..0a56857 100644 +--- a/ipmitool/lib/ipmi_hpmfwupg.c ++++ b/ipmitool/lib/ipmi_hpmfwupg.c +@@ -17,7 +17,7 @@ + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * +- * This software is provided "AS IS," without a warranty of any kind. ++ * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. +@@ -40,3940 +40,2605 @@ + #include "../src/plugins/lan/md5.h" + #include + #include ++#include + + #if HAVE_CONFIG_H +- #include ++# include + #endif + +-/**************************************************************************** +-* +-* Copyright (c) 2006 Kontron Canada, Inc. All Rights Reserved. +-* +-* HPM.1 +-* Hardware Platform Management +-* IPM Controller Firmware Upgrade Procedure +-* +-* This module implements an Upgrade Agent for the IPM Controller +-* Firmware Upgrade Procedure (HPM.1) specification version 1.0. +-* +-* author: +-* Frederic.Lelievre@ca.kontron.com +-* Francois.Isabelle@ca.kontron.com +-* Jean-Michel.Audet@ca.kontron.com +-* MarieJosee.Blais@ca.kontron.com +-* +-***************************************************************************** +-* +-* HISTORY +-* =========================================================================== +-* 2007-01-11 +-* +-* - Incremented to version 0.2 +-* - Added lan packet size reduction mechanism to workaround fact +-* that lan iface will not return C7 on excessive length +-* - Fixed some typos +-* - now uses lprintf() +-* +-* - Incremented to version 0.3 +-* - added patch for openipmi si driver V39 (send message in driver does not +-* retry on 82/83 completion code and return 82/83 as response from target +-* [conditionnaly built with ENABLE_OPENIPMI_V39_PATCH] +-* +-* see: ipmi-fix-send-msg-retry.pacth in openipmi-developer mailing list +-* +-* 2007-01-16 +-* +-* - Incremented to version 0.4 +-* - Fixed lan iface inaccesiblity timeout handling. Waiting for firmware +-* activation completion (fixed sleep) before re-opening a session and +-* get the final firmware upgrade status. +-* - Fixed some user interface stuff. +-* +-* 2007-05-09 +-* +-* - Incremented to version 1.0 +-* - Modifications for compliancy with HPM.1 specification version 1.0 +-* +-* 2007-06-05 +-* +-* - Modified the display of upgrade of Firmware version. +-* - Added new options like "check" and "component" and "all" to hpm commands. +-* - By default we skip the upgrade if we have the same firmware version +-* as compared to the Image file (*.hpm).This will ensure that user does +-* not update the target incase its already been updated +-* +-* 2008-01-25 +-* - Reduce buffer length more aggressively when no response from iol. +-* - Incremented version to 1.02 +-* +-* 2009-02-11 +-* - With multi-component HPM file, if one component need to be skipped because +-* the component is already up-to-date, ipmitool sends "Initiate upgrade +-* action / Upload for upgrade" anyway. +-* +-* If the component needs to be skipped, ipmitool will not send "Initiate +-* upgrade action / Upload for upgrade" +-* +-* - Incremented version to 1.03 +-* +-* 2009-02-11 +-* - Fixed side effect introduced by last version, "forced" update didn't +-* work anymore +-* - Incremented version to 1.04 +-* +-* 2009-03-25 +-* - Fix the case where ipmitool loses the iol connection during the upload +-* block process. Once IPMITool was successfully sent the first byte, +-* IPMITool will not resize the block size. +-* +-* 2009-03-26 +-* - Fix the problem when we try to upgrade specific component and the component +-* is already updated, IPMITool sends a "prepare action" but IPMITool skips +-* the upload firmware block process. +-* So, if we specify a specific component, we want to force to upload this +-* specific component. +-* - Incremented version to 1.05 +-* +-* 2009-04-20 +-* - Reworked previous update, when 'component' is specified, the other +-* components are now skipped. +-* - Incremented version to 1.06 +-* +-* =========================================================================== +-* TODO +-* =========================================================================== +-* 2007-01-11 +-* - Add interpretation of GetSelftestResults +-* - Add interpretation of component ID string +-* +-*****************************************************************************/ +- + extern int verbose; + +-/* +- * Agent version +- */ +-#define HPMFWUPG_VERSION_MAJOR 1 +-#define HPMFWUPG_VERSION_MINOR 0 +-#define HPMFWUPG_VERSION_SUBMINOR 8 +- +-/* +- * HPM.1 FIRMWARE UPGRADE COMMANDS (part of PICMG) +- */ +- +-#define HPMFWUPG_GET_TARGET_UPG_CAPABILITIES 0x2E +-#define HPMFWUPG_GET_COMPONENT_PROPERTIES 0x2F +-#define HPMFWUPG_ABORT_UPGRADE 0x30 +-#define HPMFWUPG_INITIATE_UPGRADE_ACTION 0x31 +-#define HPMFWUPG_UPLOAD_FIRMWARE_BLOCK 0x32 +-#define HPMFWUPG_FINISH_FIRMWARE_UPLOAD 0x33 +-#define HPMFWUPG_GET_UPGRADE_STATUS 0x34 +-#define HPMFWUPG_ACTIVATE_FIRMWARE 0x35 +-#define HPMFWUPG_QUERY_SELFTEST_RESULT 0x36 +-#define HPMFWUPG_QUERY_ROLLBACK_STATUS 0x37 +-#define HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK 0x38 +- +-/* +- * HPM.1 SPECIFIC COMPLETION CODES +- */ +-#define HPMFWUPG_ROLLBACK_COMPLETED 0x00 +-#define HPMFWUPG_COMMAND_IN_PROGRESS 0x80 +-#define HPMFWUPG_NOT_SUPPORTED 0x81 +-#define HPMFWUPG_SIZE_MISMATCH 0x81 +-#define HPMFWUPG_ROLLBACK_FAILURE 0x81 +-#define HPMFWUPG_INV_COMP_MASK 0x81 +-#define HPMFWUPG__ABORT_FAILURE 0x81 +-#define HPMFWUPG_INV_COMP_ID 0x82 +-#define HPMFWUPG_INT_CHECKSUM_ERROR 0x82 +-#define HPMFWUPG_INV_UPLOAD_MODE 0x82 +-#define HPMFWUPG_ROLLBACK_OVERRIDE 0x82 +-#define HPMFWUPG_INV_COMP_PROP 0x83 +-#define HPMFWUPG_FW_MISMATCH 0x83 +-#define HPMFWUPG_ROLLBACK_DENIED 0x83 +- +-/* +- * This error code is used as a temporary PATCH to +- * the latest Open ipmi driver. This PATCH +- * will be removed once a new Open IPMI driver is released. +- * (Buggy version = 39) +- */ +-#define ENABLE_OPENIPMI_V39_PATCH +- +-#ifdef ENABLE_OPENIPMI_V39_PATCH +- +-#define RETRY_COUNT_MAX 3 +- +-static int errorCount; +- +-#define HPMFWUPG_IS_RETRYABLE(error) \ +-((((error==0x83)||(error==0x82)||(error==0x80)) && (errorCount++descString,13); +- + /* + * If the cold reset is required then we can display * on it + * so that user is aware that he needs to do payload power + * cycle after upgrade + */ + printf("|%c%c%2d|%-13s|", +- pVersion->coldResetRequired?'*':' ', +- upgradable ? '^': ' ', +- pVersion->componentId,descString); +- +- if (mode & TARGET_VER) +- { +- if ((pVersion->targetMajor == 0xFF || +- (pVersion->targetMajor == 0x7F)) && +- pVersion->targetMinor == 0xFF) ++ pVersion->coldResetRequired ? '*' : ' ', ++ upgradable ? '^' : ' ', ++ pVersion->componentId, pVersion->descString); ++ ++ if (mode & TARGET_VER) { ++ if ((pVersion->targetMajor == 0xFF ++ || (pVersion->targetMajor == 0x7F)) ++ && pVersion->targetMinor == 0xFF) { + printf(" ---.-- -------- |"); +- else ++ } else { + printf(" %3d.%02x %02X%02X%02X%02X |", +- pVersion->targetMajor, +- pVersion->targetMinor, +- pVersion->targetAux[0], +- pVersion->targetAux[1], +- pVersion->targetAux[2], +- pVersion->targetAux[3]); +- +- if (mode & ROLLBACK_VER) +- { +- if ((pVersion->rollbackMajor == 0xFF || +- (pVersion->rollbackMajor == 0x7F)) && +- pVersion->rollbackMinor == 0xFF) ++ pVersion->targetMajor, ++ pVersion->targetMinor, ++ pVersion->targetAux[0], ++ pVersion->targetAux[1], ++ pVersion->targetAux[2], ++ pVersion->targetAux[3]); ++ } ++ if (mode & ROLLBACK_VER) { ++ if ((pVersion->rollbackMajor == 0xFF ++ || (pVersion->rollbackMajor == 0x7F)) ++ && pVersion->rollbackMinor == 0xFF) { + printf(" ---.-- -------- |"); +- else ++ } else { + printf(" %3d.%02x %02X%02X%02X%02X |", +- pVersion->rollbackMajor, +- pVersion->rollbackMinor, +- pVersion->rollbackAux[0], +- pVersion->rollbackAux[1], +- pVersion->rollbackAux[2], +- pVersion->rollbackAux[3]); ++ pVersion->rollbackMajor, ++ pVersion->rollbackMinor, ++ pVersion->rollbackAux[0], ++ pVersion->rollbackAux[1], ++ pVersion->rollbackAux[2], ++ pVersion->rollbackAux[3]); + } +- else ++ } else { + printf(" ---.-- -------- |"); + } +- +- if (mode & IMAGE_VER) +- { +- if ((pVersion->imageMajor == 0xFF || +- (pVersion->imageMajor == 0x7F)) && +- pVersion->imageMinor == 0xFF) ++ } ++ if (mode & IMAGE_VER) { ++ if ((pVersion->imageMajor == 0xFF ++ || (pVersion->imageMajor == 0x7F)) ++ && pVersion->imageMinor == 0xFF) { + printf(" ---.-- |"); +- else ++ } else { + printf(" %3d.%02x %02X%02X%02X%02X |", +- pVersion->imageMajor, +- pVersion->imageMinor, +- pVersion->imageAux[0], +- pVersion->imageAux[1], +- pVersion->imageAux[2], +- pVersion->imageAux[3]); +- } +- else +- { +- if ((pVersion->deferredMajor == 0xFF || +- (pVersion->deferredMajor == 0x7F)) && +- pVersion->deferredMinor == 0xFF) ++ pVersion->imageMajor, ++ pVersion->imageMinor, ++ pVersion->imageAux[0], ++ pVersion->imageAux[1], ++ pVersion->imageAux[2], ++ pVersion->imageAux[3]); ++ } ++ } else { ++ if ((pVersion->deferredMajor == 0xFF ++ || (pVersion->deferredMajor == 0x7F)) ++ && pVersion->deferredMinor == 0xFF) { + printf(" ---.-- -------- |"); +- else ++ } else { + printf(" %3d.%02x %02X%02X%02X%02X |", +- pVersion->deferredMajor, +- pVersion->deferredMinor, +- pVersion->deferredAux[0], +- pVersion->deferredAux[1], +- pVersion->deferredAux[2], +- pVersion->deferredAux[3]); ++ pVersion->deferredMajor, ++ pVersion->deferredMinor, ++ pVersion->deferredAux[0], ++ pVersion->deferredAux[1], ++ pVersion->deferredAux[2], ++ pVersion->deferredAux[3]); + } +-} +- +- +-/**************************************************************************** +-* +-* Function Name: HpmfwupgTargerCheck +-* +-* Description: This function gets the target information and displays it on the +-* screen +-* +-*****************************************************************************/ +-int HpmfwupgTargetCheck(struct ipmi_intf * intf, int option) +-{ +- struct HpmfwupgUpgradeCtx fwupgCtx; +- struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; +- int rc = HPMFWUPG_SUCCESS; +- int componentId = 0; +- int flagColdReset = FALSE; +- struct ipm_devid_rsp devIdrsp; +- struct HpmfwupgGetComponentPropertiesCtx getCompProp; +- int mode = 0; +- +- +- rc = HpmfwupgGetDeviceId(intf, &devIdrsp); +- +- if (rc != HPMFWUPG_SUCCESS) +- { +- lprintf(LOG_NOTICE,"Verify whether the Target board is present \n"); +- return HPMFWUPG_ERROR; +- } +- +- rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd); +- if (rc != HPMFWUPG_SUCCESS) +- { +- /* +- * That indicates the target is not responding to the command +- * May be that there is no HPM support +- */ +- lprintf(LOG_NOTICE,"Board might not be supporting the HPM.1 Standards\n"); +- return rc; +- } +- if (option & VIEW_MODE) +- { +- lprintf(LOG_NOTICE,"-------Target Information-------"); +- lprintf(LOG_NOTICE,"Device Id : 0x%x", devIdrsp.device_id); +- lprintf(LOG_NOTICE,"Device Revision : 0x%x", devIdrsp.device_revision); +- lprintf(LOG_NOTICE,"Product Id : 0x%04x", buf2short(devIdrsp.product_id)); +- lprintf(LOG_NOTICE,"Manufacturer Id : 0x%04x (%s)\n\n", buf2short(devIdrsp.manufacturer_id), +- val2str(buf2short(devIdrsp.manufacturer_id),ipmi_oem_info)); +- HpmDisplayVersionHeader(TARGET_VER|ROLLBACK_VER); +- } +- +- for ( componentId = HPMFWUPG_COMPONENT_ID_0; componentId < HPMFWUPG_COMPONENT_ID_MAX; +- componentId++ ) +- { +- /* If the component is supported */ +- if ( ((1 << componentId) & targetCapCmd.resp.componentsPresent.ComponentBits.byte) ) +- { +- memset((PVERSIONINFO)&gVersionInfo[componentId],0x00,sizeof(VERSIONINFO)); +- +- getCompProp.req.componentId = componentId; +- getCompProp.req.selector = HPMFWUPG_COMP_GEN_PROPERTIES; +- rc = HpmfwupgGetComponentProperties(intf, &getCompProp); +- if (rc != HPMFWUPG_SUCCESS) +- { +- lprintf(LOG_NOTICE,"Get CompGenProp Failed for component Id %d\n",componentId); +- return rc; +- } +- +- gVersionInfo[componentId].rollbackSupported = getCompProp.resp.Response. +- generalPropResp.GeneralCompProperties.bitfield.rollbackBackup; +- gVersionInfo[componentId].coldResetRequired = getCompProp.resp.Response. +- generalPropResp.GeneralCompProperties.bitfield.payloadColdReset; +- +- getCompProp.req.selector = HPMFWUPG_COMP_DESCRIPTION_STRING; +- rc = HpmfwupgGetComponentProperties(intf, &getCompProp); +- if (rc != HPMFWUPG_SUCCESS) +- { +- lprintf(LOG_NOTICE,"Get CompDescString Failed for component Id %d\n",componentId); +- return rc; +- } +- strcpy((char *)&gVersionInfo[componentId].descString, +- getCompProp.resp.Response.descStringResp.descString); +- +- getCompProp.req.selector = HPMFWUPG_COMP_CURRENT_VERSION; +- rc = HpmfwupgGetComponentProperties(intf, &getCompProp); +- if (rc != HPMFWUPG_SUCCESS) +- { +- lprintf(LOG_NOTICE,"Get CompCurrentVersion Failed for component Id %d\n",componentId); +- return rc; +- } +- +- gVersionInfo[componentId].componentId = componentId; +- gVersionInfo[componentId].targetMajor = getCompProp.resp.Response. +- currentVersionResp.currentVersion[0]; +- gVersionInfo[componentId].targetMinor = getCompProp.resp.Response. +- currentVersionResp.currentVersion[1]; +- gVersionInfo[componentId].targetAux[0] = getCompProp.resp.Response. +- currentVersionResp.currentVersion[2]; +- gVersionInfo[componentId].targetAux[1] = getCompProp.resp.Response. +- currentVersionResp.currentVersion[3]; +- gVersionInfo[componentId].targetAux[2] = getCompProp.resp.Response. +- currentVersionResp.currentVersion[4]; +- gVersionInfo[componentId].targetAux[3] = getCompProp.resp.Response. +- currentVersionResp.currentVersion[5]; +- mode = TARGET_VER; +- +- if (gVersionInfo[componentId].rollbackSupported) +- { +- getCompProp.req.selector = HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION; +- rc = HpmfwupgGetComponentProperties(intf, &getCompProp); +- if (rc != HPMFWUPG_SUCCESS) +- { +- lprintf(LOG_NOTICE,"Get CompRollbackVersion Failed for component Id %d\n",componentId); +- } else { +- gVersionInfo[componentId].rollbackMajor = getCompProp.resp +- .Response.rollbackFwVersionResp.rollbackFwVersion[0]; +- gVersionInfo[componentId].rollbackMinor = getCompProp.resp +- .Response.rollbackFwVersionResp.rollbackFwVersion[1]; +- gVersionInfo[componentId].rollbackAux[0] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[2]; +- gVersionInfo[componentId].rollbackAux[1] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[3]; +- gVersionInfo[componentId].rollbackAux[2] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[4]; +- gVersionInfo[componentId].rollbackAux[3] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[5]; +- } +- +- getCompProp.req.selector = HPMFWUPG_COMP_DEFERRED_FIRMWARE_VERSION; +- rc = HpmfwupgGetComponentProperties(intf, &getCompProp); +- if (rc != HPMFWUPG_SUCCESS) +- { +- lprintf(LOG_NOTICE,"Get CompRollbackVersion Failed for component Id %d\n",componentId); +- } else { +- gVersionInfo[componentId].deferredMajor = getCompProp.resp +- .Response.deferredFwVersionResp.deferredFwVersion[0]; +- gVersionInfo[componentId].deferredMinor = getCompProp.resp +- .Response.deferredFwVersionResp.deferredFwVersion[1]; +- gVersionInfo[componentId].deferredAux[0] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[2]; +- gVersionInfo[componentId].deferredAux[1] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[3]; +- gVersionInfo[componentId].deferredAux[2] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[4]; +- gVersionInfo[componentId].deferredAux[3] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[5]; +- } +- mode |= ROLLBACK_VER; +- } +- else +- { +- gVersionInfo[componentId].rollbackMajor = 0xff; +- gVersionInfo[componentId].rollbackMinor = 0xff; +- gVersionInfo[componentId].rollbackAux[0] = 0xff; +- gVersionInfo[componentId].rollbackAux[1] = 0xff; +- gVersionInfo[componentId].rollbackAux[2] = 0xff; +- gVersionInfo[componentId].rollbackAux[3] = 0xff; +- +- gVersionInfo[componentId].deferredMajor = 0xff; +- gVersionInfo[componentId].deferredMinor = 0xff; +- gVersionInfo[componentId].deferredAux[0] = 0xff; +- gVersionInfo[componentId].deferredAux[1] = 0xff; +- gVersionInfo[componentId].deferredAux[2] = 0xff; +- gVersionInfo[componentId].deferredAux[3] = 0xff; +- } +- +- if (gVersionInfo[componentId].coldResetRequired) +- { +- /* +- * If any of the component indicates that the Payload Cold reset is required +- * then set the flag +- */ +- flagColdReset = TRUE; +- } +- if (option & VIEW_MODE) +- { +- HpmDisplayVersion(mode,&gVersionInfo[componentId], 0); +- printf("\n"); +- } +- } +- } +- +- if (option & VIEW_MODE) +- { +- HpmDisplayLine("-",74 ); +- fflush(stdout); +- lprintf(LOG_NOTICE,"(*) Component requires Payload Cold Reset"); +- printf("\n\n"); +- } +- return HPMFWUPG_SUCCESS; +-} +- +-/***************************************************************************** +-* Function Name: HpmfwupgUpgrade +-* +-* Description: This function performs the HPM.1 firmware upgrade procedure as +-* defined the IPM Controller Firmware Upgrade Specification +-* version 1.0 +-* +-*****************************************************************************/ +-int HpmfwupgUpgrade(struct ipmi_intf *intf, char* imageFilename, +- int activate,int componentToUpload, int option) +-{ +- int rc = HPMFWUPG_SUCCESS; +- struct HpmfwupgImageHeader imageHeader; +- struct HpmfwupgUpgradeCtx fwupgCtx; +- +- /* +- * GET IMAGE BUFFER FROM FILE +- */ +- +- rc = HpmfwupgGetBufferFromFile(imageFilename, &fwupgCtx); +- +- /* +- * VALIDATE IMAGE INTEGRITY +- */ +- +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- printf("Validating firmware image integrity..."); +- fflush(stdout); +- rc = HpmfwupgValidateImageIntegrity(&fwupgCtx); +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- printf("OK\n"); +- fflush(stdout); +- } +- else +- { +- free(fwupgCtx.pImageData); +- fwupgCtx.pImageData = NULL; +- } +- } +- +- /* +- * PREPARATION STAGE +- */ +- +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- printf("Performing preparation stage..."); +- fflush(stdout); +- rc = HpmfwupgPreparationStage(intf, &fwupgCtx, option); +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- printf("OK\n"); +- fflush(stdout); +- } +- else +- { +- free(fwupgCtx.pImageData); +- fwupgCtx.pImageData = NULL; +- } +- } +- +- /* +- * UPGRADE STAGE +- */ +- +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- if (option & VIEW_MODE) +- { +- lprintf(LOG_NOTICE,"\nComparing Target & Image File version"); +- } +- else +- { +- lprintf(LOG_NOTICE,"\nPerforming upgrade stage:"); +- } +- if (option & VIEW_MODE) +- { +- rc = HpmfwupgPreUpgradeCheck(intf, &fwupgCtx,componentToUpload,VIEW_MODE); +- } +- else +- { +- rc = HpmfwupgPreUpgradeCheck(intf, &fwupgCtx,componentToUpload,option); +- if (rc == HPMFWUPG_SUCCESS ) +- { +- if( verbose ) { +- printf("Component update mask : 0x%02x\n", fwupgCtx.compUpdateMask.ComponentBits.byte); +- } +- rc = HpmfwupgUpgradeStage(intf, &fwupgCtx,componentToUpload,option); +- } +- } +- +- if ( rc != HPMFWUPG_SUCCESS ) +- { +- free(fwupgCtx.pImageData); +- fwupgCtx.pImageData = NULL; +- } +- } +- +- /* +- * ACTIVATION STAGE +- */ +- if ( rc == HPMFWUPG_SUCCESS && activate ) +- { +- lprintf(LOG_NOTICE,"Performing activation stage: "); +- rc = HpmfwupgActivationStage(intf, &fwupgCtx); +- if ( rc != HPMFWUPG_SUCCESS ) +- { +- free(fwupgCtx.pImageData); +- fwupgCtx.pImageData = NULL; +- } +- } ++ } ++} + +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- if (option & VIEW_MODE) +- { +- // Dont display anything here in case we are just viewing it +- lprintf(LOG_NOTICE," "); +- } +- else +- { +- lprintf(LOG_NOTICE,"\nFirmware upgrade procedure successful\n"); +- } +- free(fwupgCtx.pImageData); +- fwupgCtx.pImageData = NULL; +- } +- else +- { +- lprintf(LOG_NOTICE,"Firmware upgrade procedure failed\n"); +- } ++/* HpmfwupgTargerCheck - get target information and displays it on the screen ++ */ ++int ++HpmfwupgTargetCheck(struct ipmi_intf *intf, int option) ++{ ++ struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; ++ int rc = HPMFWUPG_SUCCESS; ++ int componentId = 0; ++ int flagColdReset = FALSE; ++ struct ipm_devid_rsp devIdrsp; ++ struct HpmfwupgGetComponentPropertiesCtx getCompProp; ++ int mode = 0; ++ rc = HpmfwupgGetDeviceId(intf, &devIdrsp); ++ if (rc != HPMFWUPG_SUCCESS) { ++ lprintf(LOG_NOTICE, ++ "Verify whether the Target board is present \n"); ++ return HPMFWUPG_ERROR; ++ } ++ rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd); ++ if (rc != HPMFWUPG_SUCCESS) { ++ /* That indicates the target is not responding to the command ++ * May be that there is no HPM support ++ */ ++ lprintf(LOG_NOTICE, ++ "Board might not be supporting the HPM.1 Standards\n"); ++ return rc; ++ } ++ if (option & VIEW_MODE) { ++ lprintf(LOG_NOTICE, "-------Target Information-------"); ++ lprintf(LOG_NOTICE, "Device Id : 0x%x", ++ devIdrsp.device_id); ++ lprintf(LOG_NOTICE, "Device Revision : 0x%x", ++ devIdrsp.device_revision); ++ lprintf(LOG_NOTICE, "Product Id : 0x%04x", ++ buf2short(devIdrsp.product_id)); ++ lprintf(LOG_NOTICE, "Manufacturer Id : 0x%04x (%s)\n\n", ++ buf2short(devIdrsp.manufacturer_id), ++ val2str(buf2short(devIdrsp.manufacturer_id),ipmi_oem_info)); ++ HpmDisplayVersionHeader(TARGET_VER|ROLLBACK_VER); ++ } ++ for (componentId = HPMFWUPG_COMPONENT_ID_0; ++ componentId < HPMFWUPG_COMPONENT_ID_MAX; ++ componentId++ ) { ++ /* If the component is supported */ ++ if (((1 << componentId) & targetCapCmd.resp.componentsPresent.ComponentBits.byte)) { ++ memset((PVERSIONINFO)&gVersionInfo[componentId], 0x00, sizeof(VERSIONINFO)); ++ getCompProp.req.componentId = componentId; ++ getCompProp.req.selector = HPMFWUPG_COMP_GEN_PROPERTIES; ++ rc = HpmfwupgGetComponentProperties(intf, &getCompProp); ++ if (rc != HPMFWUPG_SUCCESS) { ++ lprintf(LOG_NOTICE, "Get CompGenProp Failed for component Id %d\n", ++ componentId); ++ return rc; ++ } ++ gVersionInfo[componentId].rollbackSupported = getCompProp.resp.Response. ++ generalPropResp.GeneralCompProperties.bitfield.rollbackBackup; ++ gVersionInfo[componentId].coldResetRequired = getCompProp.resp.Response. ++ generalPropResp.GeneralCompProperties.bitfield.payloadColdReset; ++ getCompProp.req.selector = HPMFWUPG_COMP_DESCRIPTION_STRING; ++ rc = HpmfwupgGetComponentProperties(intf, &getCompProp); ++ if (rc != HPMFWUPG_SUCCESS) { ++ lprintf(LOG_NOTICE, ++ "Get CompDescString Failed for component Id %d\n", ++ componentId); ++ return rc; ++ } ++ memcpy(gVersionInfo[componentId].descString, ++ getCompProp.resp.Response.descStringResp.descString, ++ HPMFWUPG_DESC_STRING_LENGTH); ++ gVersionInfo[componentId].descString[HPMFWUPG_DESC_STRING_LENGTH] = '\0'; ++ getCompProp.req.selector = HPMFWUPG_COMP_CURRENT_VERSION; ++ rc = HpmfwupgGetComponentProperties(intf, &getCompProp); ++ if (rc != HPMFWUPG_SUCCESS) { ++ lprintf(LOG_NOTICE, ++ "Get CompCurrentVersion Failed for component Id %d\n", ++ componentId); ++ return rc; ++ } ++ gVersionInfo[componentId].componentId = componentId; ++ gVersionInfo[componentId].targetMajor = getCompProp.resp.Response. ++ currentVersionResp.currentVersion[0]; ++ gVersionInfo[componentId].targetMinor = getCompProp.resp.Response. ++ currentVersionResp.currentVersion[1]; ++ gVersionInfo[componentId].targetAux[0] = getCompProp.resp.Response. ++ currentVersionResp.currentVersion[2]; ++ gVersionInfo[componentId].targetAux[1] = getCompProp.resp.Response. ++ currentVersionResp.currentVersion[3]; ++ gVersionInfo[componentId].targetAux[2] = getCompProp.resp.Response. ++ currentVersionResp.currentVersion[4]; ++ gVersionInfo[componentId].targetAux[3] = getCompProp.resp.Response. ++ currentVersionResp.currentVersion[5]; ++ mode = TARGET_VER; ++ if (gVersionInfo[componentId].rollbackSupported) { ++ getCompProp.req.selector = HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION; ++ rc = HpmfwupgGetComponentProperties(intf, &getCompProp); ++ if (rc != HPMFWUPG_SUCCESS) { ++ lprintf(LOG_NOTICE, ++ "Get CompRollbackVersion Failed for component Id %d\n", ++ componentId); ++ } else { ++ gVersionInfo[componentId].rollbackMajor = getCompProp.resp ++ .Response.rollbackFwVersionResp.rollbackFwVersion[0]; ++ gVersionInfo[componentId].rollbackMinor = getCompProp.resp ++ .Response.rollbackFwVersionResp.rollbackFwVersion[1]; ++ gVersionInfo[componentId].rollbackAux[0] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[2]; ++ gVersionInfo[componentId].rollbackAux[1] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[3]; ++ gVersionInfo[componentId].rollbackAux[2] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[4]; ++ gVersionInfo[componentId].rollbackAux[3] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[5]; ++ } ++ getCompProp.req.selector = HPMFWUPG_COMP_DEFERRED_FIRMWARE_VERSION; ++ rc = HpmfwupgGetComponentProperties(intf, &getCompProp); ++ if (rc != HPMFWUPG_SUCCESS) { ++ lprintf(LOG_NOTICE, ++ "Get CompRollbackVersion Failed for component Id %d\n", ++ componentId); ++ } else { ++ gVersionInfo[componentId].deferredMajor = getCompProp.resp ++ .Response.deferredFwVersionResp.deferredFwVersion[0]; ++ gVersionInfo[componentId].deferredMinor = getCompProp.resp ++ .Response.deferredFwVersionResp.deferredFwVersion[1]; ++ gVersionInfo[componentId].deferredAux[0] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[2]; ++ gVersionInfo[componentId].deferredAux[1] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[3]; ++ gVersionInfo[componentId].deferredAux[2] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[4]; ++ gVersionInfo[componentId].deferredAux[3] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[5]; ++ } ++ mode |= ROLLBACK_VER; ++ } else { ++ gVersionInfo[componentId].rollbackMajor = 0xff; ++ gVersionInfo[componentId].rollbackMinor = 0xff; ++ gVersionInfo[componentId].rollbackAux[0] = 0xff; ++ gVersionInfo[componentId].rollbackAux[1] = 0xff; ++ gVersionInfo[componentId].rollbackAux[2] = 0xff; ++ gVersionInfo[componentId].rollbackAux[3] = 0xff; ++ gVersionInfo[componentId].deferredMajor = 0xff; ++ gVersionInfo[componentId].deferredMinor = 0xff; ++ gVersionInfo[componentId].deferredAux[0] = 0xff; ++ gVersionInfo[componentId].deferredAux[1] = 0xff; ++ gVersionInfo[componentId].deferredAux[2] = 0xff; ++ gVersionInfo[componentId].deferredAux[3] = 0xff; ++ } ++ if (gVersionInfo[componentId].coldResetRequired) { ++ /* ++ * If any of the component indicates that the Payload Cold reset is required ++ * then set the flag ++ */ ++ flagColdReset = TRUE; ++ } ++ if (option & VIEW_MODE) { ++ HpmDisplayVersion(mode, ++ &gVersionInfo[componentId], ++ 0); ++ printf("\n"); ++ } ++ } ++ } ++ if (option & VIEW_MODE) { ++ HpmDisplayLine("-",74 ); ++ fflush(stdout); ++ lprintf(LOG_NOTICE, ++ "(*) Component requires Payload Cold Reset"); ++ printf("\n\n"); ++ } ++ return HPMFWUPG_SUCCESS; ++} + +- return rc; ++/* HpmfwupgUpgrade - perform the HPM.1 firmware upgrade procedure as defined ++ * the IPM Controller Firmware Upgrade Specification version 1.0 ++ */ ++int ++HpmfwupgUpgrade(struct ipmi_intf *intf, char *imageFilename, int activate, ++ int componentMask, int option) ++{ ++ int rc = HPMFWUPG_SUCCESS; ++ struct HpmfwupgUpgradeCtx fwupgCtx; ++ /* INITIALIZE UPGRADE CONTEXT */ ++ memset(&fwupgCtx, 0, sizeof (fwupgCtx)); ++ /* GET IMAGE BUFFER FROM FILE */ ++ rc = HpmfwupgGetBufferFromFile(imageFilename, &fwupgCtx); ++ /* VALIDATE IMAGE INTEGRITY */ ++ if (rc == HPMFWUPG_SUCCESS) { ++ printf("Validating firmware image integrity..."); ++ fflush(stdout); ++ rc = HpmfwupgValidateImageIntegrity(&fwupgCtx); ++ if (rc == HPMFWUPG_SUCCESS) { ++ printf("OK\n"); ++ fflush(stdout); ++ } ++ } ++ /* PREPARATION STAGE */ ++ if (rc == HPMFWUPG_SUCCESS) { ++ printf("Performing preparation stage..."); ++ fflush(stdout); ++ rc = HpmfwupgPreparationStage(intf, &fwupgCtx, option); ++ if (rc == HPMFWUPG_SUCCESS) { ++ printf("OK\n"); ++ fflush(stdout); ++ } ++ } ++ /* UPGRADE STAGE */ ++ if (rc == HPMFWUPG_SUCCESS) { ++ if (option & VIEW_MODE) { ++ lprintf(LOG_NOTICE, ++ "\nComparing Target & Image File version"); ++ } else if (option & COMPARE_MODE) { ++ lprintf(LOG_NOTICE, ++ "\nPerforming upload for compare stage:"); ++ } else { ++ lprintf(LOG_NOTICE, "\nPerforming upgrade stage:"); ++ } ++ if (option & VIEW_MODE) { ++ rc = HpmfwupgPreUpgradeCheck(intf, ++ &fwupgCtx,componentMask, VIEW_MODE); ++ } else { ++ rc = HpmfwupgPreUpgradeCheck(intf, &fwupgCtx, ++ componentMask, option); ++ if (rc == HPMFWUPG_SUCCESS) { ++ if (verbose) { ++ printf("Component update mask : 0x%02x\n", ++ fwupgCtx.compUpdateMask.ComponentBits.byte); ++ } ++ rc = HpmfwupgUpgradeStage(intf, &fwupgCtx, option); ++ } ++ } ++ } ++ /* ACTIVATION STAGE */ ++ if (rc == HPMFWUPG_SUCCESS && activate) { ++ /* check if upgrade components mask is non-zero */ ++ if (fwupgCtx.compUpdateMask.ComponentBits.byte) { ++ lprintf(LOG_NOTICE, "Performing activation stage: "); ++ rc = HpmfwupgActivationStage(intf, &fwupgCtx); ++ } else { ++ lprintf(LOG_NOTICE, ++ "No components updated. Skipping activation stage.\n"); ++ } ++ } ++ if (rc == HPMFWUPG_SUCCESS) { ++ if (option & VIEW_MODE) { ++ /* Dont display anything here in case we are just viewing it */ ++ lprintf(LOG_NOTICE," "); ++ } else if (option & COMPARE_MODE) { ++ lprintf(LOG_NOTICE, ++ "\nFirmware comparison procedure complete\n"); ++ } else { ++ lprintf(LOG_NOTICE, ++ "\nFirmware upgrade procedure successful\n"); ++ } ++ } else if (option & VIEW_MODE) { ++ /* Dont display anything here in case we are just viewing it */ ++ lprintf(LOG_NOTICE," "); ++ } else if (option & COMPARE_MODE) { ++ lprintf(LOG_NOTICE, ++ "Firmware comparison procedure failed\n"); ++ } else { ++ lprintf(LOG_NOTICE, "Firmware upgrade procedure failed\n"); ++ } ++ if (fwupgCtx.pImageData) { ++ free(fwupgCtx.pImageData); ++ fwupgCtx.pImageData = NULL; ++ } ++ return rc; + } + +-/**************************************************************************** +-* +-* Function Name: HpmfwupgValidateImageIntegrity +-* +-* Description: This function validates a HPM.1 firmware image file as defined +-* in section 4 of the IPM Controller Firmware Upgrade +-* Specification version 1.0 +-* +-*****************************************************************************/ +-int HpmfwupgValidateImageIntegrity(struct HpmfwupgUpgradeCtx* pFwupgCtx) ++/* HpmfwupgValidateImageIntegrity - validate a HPM.1 firmware image file as ++ * defined in section 4 of the IPM Controller Firmware Upgrade Specification ++ * version 1.0 ++ */ ++int ++HpmfwupgValidateImageIntegrity(struct HpmfwupgUpgradeCtx *pFwupgCtx) + { +- int rc = HPMFWUPG_SUCCESS; +- struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) +- pFwupgCtx->pImageData; +- md5_state_t ctx; ++ struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*)pFwupgCtx->pImageData; ++ md5_state_t ctx; + static unsigned char md[HPMFWUPG_MD5_SIGNATURE_LENGTH]; +- unsigned char* pMd5Sig = pFwupgCtx->pImageData + +- (pFwupgCtx->imageSize - +- HPMFWUPG_MD5_SIGNATURE_LENGTH); +- +- /* Validate MD5 checksum */ +- memset(md, 0, HPMFWUPG_MD5_SIGNATURE_LENGTH); +- memset(&ctx, 0, sizeof(md5_state_t)); +- md5_init(&ctx); +- md5_append(&ctx, pFwupgCtx->pImageData, pFwupgCtx->imageSize - +- HPMFWUPG_MD5_SIGNATURE_LENGTH); +- md5_finish(&ctx, md); +- if ( memcmp(md, pMd5Sig,HPMFWUPG_MD5_SIGNATURE_LENGTH) != 0 ) +- { +- lprintf(LOG_NOTICE,"\n Invalid MD5 signature"); +- rc = HPMFWUPG_ERROR; +- } +- +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- /* Validate Header signature */ +- if( strncmp(pImageHeader->signature, HPMFWUPG_IMAGE_SIGNATURE, HPMFWUPG_HEADER_SIGNATURE_LENGTH) == 0 ) +- { +- /* Validate Header image format version */ +- if ( pImageHeader->formatVersion == HPMFWUPG_IMAGE_HEADER_VERSION ) +- { +- /* Validate header checksum */ +- if ( HpmfwupgCalculateChecksum((unsigned char*)pImageHeader, +- sizeof(struct HpmfwupgImageHeader) + +- pImageHeader->oemDataLength + +- sizeof(unsigned char)/*checksum*/) != 0 ) +- { +- lprintf(LOG_NOTICE,"\n Invalid header checksum"); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"\n Unrecognized image version"); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"\n Invalid image signature"); +- rc = HPMFWUPG_ERROR; +- } +- } +- return rc; ++ unsigned char *pMd5Sig = pFwupgCtx->pImageData ++ + (pFwupgCtx->imageSize - HPMFWUPG_MD5_SIGNATURE_LENGTH); ++ /* Validate MD5 checksum */ ++ memset(md, 0, HPMFWUPG_MD5_SIGNATURE_LENGTH); ++ memset(&ctx, 0, sizeof(md5_state_t)); ++ md5_init(&ctx); ++ md5_append(&ctx, pFwupgCtx->pImageData, ++ pFwupgCtx->imageSize - HPMFWUPG_MD5_SIGNATURE_LENGTH); ++ md5_finish(&ctx, md); ++ if (memcmp(md, pMd5Sig, HPMFWUPG_MD5_SIGNATURE_LENGTH) != 0) { ++ lprintf(LOG_NOTICE, "\n Invalid MD5 signature"); ++ return HPMFWUPG_ERROR; ++ } ++ /* Validate Header signature */ ++ if(strncmp(pImageHeader->signature, ++ HPMFWUPG_IMAGE_SIGNATURE, ++ HPMFWUPG_HEADER_SIGNATURE_LENGTH) != 0) { ++ lprintf(LOG_NOTICE,"\n Invalid image signature"); ++ return HPMFWUPG_ERROR; ++ } ++ /* Validate Header image format version */ ++ if (pImageHeader->formatVersion != HPMFWUPG_IMAGE_HEADER_VERSION) { ++ lprintf(LOG_NOTICE,"\n Unrecognized image version"); ++ return HPMFWUPG_ERROR; ++ } ++ /* Validate header checksum */ ++ if (HpmfwupgCalculateChecksum((unsigned char*)pImageHeader, ++ sizeof(struct HpmfwupgImageHeader) ++ + pImageHeader->oemDataLength ++ + sizeof(unsigned char)/*checksum*/) != 0) { ++ lprintf(LOG_NOTICE,"\n Invalid header checksum"); ++ return HPMFWUPG_ERROR; ++ } ++ return HPMFWUPG_SUCCESS; + } + +-/**************************************************************************** +-* +-* Function Name: HpmfwupgPreparationStage +-* +-* Description: This function the preperation stage of a firmware upgrade +-* procedure as defined in section 3.2 of the IPM Controller +-* Firmware Upgrade Specification version 1.0 +-* +-*****************************************************************************/ +-int HpmfwupgPreparationStage(struct ipmi_intf *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx, int option) +-{ +- int rc = HPMFWUPG_SUCCESS; +- struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) +- pFwupgCtx->pImageData; +- +- /* Get device ID */ +- rc = HpmfwupgGetDeviceId(intf, &pFwupgCtx->devId); +- +- /* Match current IPMC IDs with upgrade image */ +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- /* Validate device ID */ +- if ( pImageHeader->deviceId == pFwupgCtx->devId.device_id ) +- { +- /* Validate product ID */ +- if ( memcmp(pImageHeader->prodId, pFwupgCtx->devId.product_id, HPMFWUPG_PRODUCT_ID_LENGTH ) == 0 ) +- { +- /* Validate man ID */ +- if ( memcmp(pImageHeader->manId, pFwupgCtx->devId.manufacturer_id, +- HPMFWUPG_MANUFATURER_ID_LENGTH ) != 0 ) +- { +- lprintf(LOG_NOTICE,"\n Invalid image file for manufacturer %u", +- buf2short(pFwupgCtx->devId.manufacturer_id)); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"\n Invalid image file for product %u", +- buf2short(pFwupgCtx->devId.product_id)); +- rc = HPMFWUPG_ERROR; +- } +- +- } +- else +- { +- lprintf(LOG_NOTICE,"\n Invalid device ID %x", pFwupgCtx->devId.device_id); +- rc = HPMFWUPG_ERROR; +- } +- +- if (rc != HPMFWUPG_SUCCESS) +- { +- /* +- * Giving one more chance to user to check whether its OK to continue even if the +- * product ID does not match. This is helpful as sometimes we just want to update +- * and dont care whether we have a different product Id. If the user says NO then +- * we need to just bail out from here +- */ +- if ( (option & FORCE_MODE) || (option & VIEW_MODE) ) +- { +- printf("\n Image Information"); +- printf("\n Device Id : 0x%x",pImageHeader->deviceId); +- printf("\n Prod Id : 0x%02x%02x",pImageHeader->prodId[1], pImageHeader->prodId[0]); +- printf("\n Manuf Id : 0x%02x%02x%02x",pImageHeader->manId[2], +- pImageHeader->manId[1],pImageHeader->manId[0]); +- printf("\n Board Information"); +- printf("\n Device Id : 0x%x", pFwupgCtx->devId.device_id); +- printf("\n Prod Id : 0x%02x%02x",pFwupgCtx->devId.product_id[1], pFwupgCtx->devId.product_id[0]); +- printf("\n Manuf Id : 0x%02x%02x%02x",pFwupgCtx->devId.manufacturer_id[2], +- pFwupgCtx->devId.manufacturer_id[1],pFwupgCtx->devId.manufacturer_id[0]); +- if (HpmGetUserInput("\n Continue ignoring DeviceID/ProductID/ManufacturingID (Y/N) :")) +- rc = HPMFWUPG_SUCCESS; +- } +- else +- { +- printf("\n\n Use \"force\" option for copying all the components\n"); +- } +- } +- } +- +- /* Validate earliest compatible revision */ +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- /* Validate major & minor revision */ +- if ( pImageHeader->compRevision[0] < pFwupgCtx->devId.fw_rev1 ) +- { +- /* Do nothing, upgrade accepted */ +- } +- else if ( pImageHeader->compRevision[0] == pFwupgCtx->devId.fw_rev1 ) +- { +- /* Must validate minor revision */ +- if ( pImageHeader->compRevision[1] > pFwupgCtx->devId.fw_rev2 ) +- { +- /* Version not compatible for upgrade */ +- lprintf(LOG_NOTICE,"\n Version: Major: %d", pImageHeader->compRevision[0]); +- lprintf(LOG_NOTICE," Minor: %x", pImageHeader->compRevision[1]); +- lprintf(LOG_NOTICE," Not compatible with "); +- lprintf(LOG_NOTICE," Version: Major: %d", pFwupgCtx->devId.fw_rev1); +- lprintf(LOG_NOTICE," Minor: %x", pFwupgCtx->devId.fw_rev2); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- /* Version not compatible for upgrade */ +- lprintf(LOG_NOTICE,"\n Version: Major: %d", pImageHeader->compRevision[0]); +- lprintf(LOG_NOTICE," Minor: %x", pImageHeader->compRevision[1]); +- lprintf(LOG_NOTICE," Not compatible with "); +- lprintf(LOG_NOTICE," Version: Major: %d", pFwupgCtx->devId.fw_rev1); +- lprintf(LOG_NOTICE," Minor: %x", pFwupgCtx->devId.fw_rev2); +- rc = HPMFWUPG_ERROR; +- } +- +- if (rc != HPMFWUPG_SUCCESS) +- { +- /* Confirming it once again */ +- if ( (option & FORCE_MODE) || (option & VIEW_MODE) ) +- { +- if( HpmGetUserInput("\n Continue IGNORING Earliest compatibility (Y/N) :")) +- rc = HPMFWUPG_SUCCESS; +- } +- } +- } +- +- /* Get target upgrade capabilities */ +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; +- +- rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd); +- +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- /* Copy response to context */ +- memcpy(&pFwupgCtx->targetCap, +- &targetCapCmd.resp, +- sizeof(struct HpmfwupgGetTargetUpgCapabilitiesResp)); +- +- if (option & VIEW_MODE) +- { +- return rc; +- } +- else +- { +- /* Make sure all component IDs defined in the upgrade +- image are supported by the IPMC */ +- if ( (pImageHeader->components.ComponentBits.byte & +- pFwupgCtx->targetCap.componentsPresent.ComponentBits.byte ) != +- pImageHeader->components.ComponentBits.byte ) +- { +- lprintf(LOG_NOTICE,"\n Some components present in the image file are not supported by the IPMC"); +- rc = HPMFWUPG_ERROR; +- } +- +- /* Make sure the upgrade is desirable rigth now */ +- if ( pFwupgCtx->targetCap.GlobalCapabilities.bitField.fwUpgUndesirable == 1 ) +- { +- lprintf(LOG_NOTICE,"\n Upgrade undesirable at this moment"); +- rc = HPMFWUPG_ERROR; +- } +- +- /* Get confimation from the user if he wants to continue when service +- affected during upgrade */ +- if ( pFwupgCtx->targetCap.GlobalCapabilities.bitField.servAffectDuringUpg == 1 || +- pImageHeader->imageCapabilities.bitField.servAffected == 1 ) +- { +- if (HpmGetUserInput("\nServices may be affected during upgrade. Do you wish to continue? y/n ")) +- { +- rc = HPMFWUPG_SUCCESS; +- } +- else +- { +- rc = HPMFWUPG_ERROR; +- } +- } +- } +- } +- } +- +- /* Get the general properties of each component present in image */ +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- int componentId; +- +- for ( componentId = HPMFWUPG_COMPONENT_ID_0; +- componentId < HPMFWUPG_COMPONENT_ID_MAX; +- componentId++ ) +- { +- /* Reset component properties */ +- memset(&pFwupgCtx->genCompProp[componentId], 0, sizeof (struct HpmfwupgGetGeneralPropResp)); +- +- if ( (1 << componentId & pImageHeader->components.ComponentBits.byte) ) +- { +- struct HpmfwupgGetComponentPropertiesCtx getCompPropCmd; +- +- /* Get general component properties */ +- getCompPropCmd.req.componentId = componentId; +- getCompPropCmd.req.selector = HPMFWUPG_COMP_GEN_PROPERTIES; +- +- rc = HpmfwupgGetComponentProperties(intf, &getCompPropCmd); +- +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- /* Copy response to context */ +- memcpy(&pFwupgCtx->genCompProp[componentId], +- &getCompPropCmd.resp, +- sizeof(struct HpmfwupgGetGeneralPropResp)); +- } +- } +- } +- } +- +- return rc; ++/* HpmfwupgPreparationStage - prepere stage of a firmware upgrade procedure as ++ * defined in section 3.2 of the IPM Controller Firmware Upgrade Specification ++ * version 1.0 ++ */ ++int ++HpmfwupgPreparationStage(struct ipmi_intf *intf, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx, int option) ++{ ++ int componentId; ++ int rc = HPMFWUPG_SUCCESS; ++ struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; ++ struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*) ++ pFwupgCtx->pImageData; ++ /* Get device ID */ ++ rc = HpmfwupgGetDeviceId(intf, &pFwupgCtx->devId); ++ /* Match current IPMC IDs with upgrade image */ ++ if (rc != HPMFWUPG_SUCCESS) { ++ return HPMFWUPG_ERROR; ++ } ++ /* Validate device ID */ ++ if (pImageHeader->deviceId == pFwupgCtx->devId.device_id) { ++ /* Validate product ID */ ++ if (memcmp(pImageHeader->prodId, ++ pFwupgCtx->devId.product_id, ++ HPMFWUPG_PRODUCT_ID_LENGTH ) == 0) { ++ /* Validate man ID */ ++ if (memcmp(pImageHeader->manId, ++ pFwupgCtx->devId.manufacturer_id, ++ HPMFWUPG_MANUFATURER_ID_LENGTH) != 0) { ++ lprintf(LOG_NOTICE, ++ "\n Invalid image file for manufacturer %u", ++ buf2short(pFwupgCtx->devId.manufacturer_id)); ++ rc = HPMFWUPG_ERROR; ++ } ++ } else { ++ lprintf(LOG_NOTICE, ++ "\n Invalid image file for product %u", ++ buf2short(pFwupgCtx->devId.product_id)); ++ rc = HPMFWUPG_ERROR; ++ } ++ } else { ++ lprintf(LOG_NOTICE, "\n Invalid device ID %x", ++ pFwupgCtx->devId.device_id); ++ rc = HPMFWUPG_ERROR; ++ } ++ if (rc != HPMFWUPG_SUCCESS) { ++ /* Giving one more chance to user to check whether its OK to continue even if the ++ * product ID does not match. This is helpful as sometimes we just want to update ++ * and dont care whether we have a different product Id. If the user says NO then ++ * we need to just bail out from here ++ */ ++ if (!((option & FORCE_MODE) || (option & VIEW_MODE))) { ++ printf("\n\n Use \"force\" option for copying all the components\n"); ++ return HPMFWUPG_ERROR; ++ } ++ printf("\n Image Information"); ++ printf("\n Device Id : 0x%x", pImageHeader->deviceId); ++ printf("\n Prod Id : 0x%02x%02x", ++ pImageHeader->prodId[1], pImageHeader->prodId[0]); ++ printf("\n Manuf Id : 0x%02x%02x%02x", ++ pImageHeader->manId[2], ++ pImageHeader->manId[1], ++ pImageHeader->manId[0]); ++ printf("\n Board Information"); ++ printf("\n Device Id : 0x%x", pFwupgCtx->devId.device_id); ++ printf("\n Prod Id : 0x%02x%02x", ++ pFwupgCtx->devId.product_id[1], pFwupgCtx->devId.product_id[0]); ++ printf("\n Manuf Id : 0x%02x%02x%02x", ++ pFwupgCtx->devId.manufacturer_id[2], ++ pFwupgCtx->devId.manufacturer_id[1], ++ pFwupgCtx->devId.manufacturer_id[0]); ++ if (HpmGetUserInput("\n Continue ignoring DeviceID/ProductID/ManufacturingID (Y/N): ")) { ++ rc = HPMFWUPG_SUCCESS; ++ } else { ++ return HPMFWUPG_ERROR; ++ } ++ } ++ /* Validate earliest compatible revision */ ++ /* Validate major & minor revision */ ++ if (pImageHeader->compRevision[0] > pFwupgCtx->devId.fw_rev1 ++ || (pImageHeader->compRevision[0] == pFwupgCtx->devId.fw_rev1 ++ && pImageHeader->compRevision[1] > pFwupgCtx->devId.fw_rev2)) { ++ /* Version not compatible for upgrade */ ++ lprintf(LOG_NOTICE, "\n Version: Major: %d", pImageHeader->compRevision[0]); ++ lprintf(LOG_NOTICE, " Minor: %x", pImageHeader->compRevision[1]); ++ lprintf(LOG_NOTICE, " Not compatible with "); ++ lprintf(LOG_NOTICE, " Version: Major: %d", pFwupgCtx->devId.fw_rev1); ++ lprintf(LOG_NOTICE, " Minor: %x", pFwupgCtx->devId.fw_rev2); ++ /* Confirming it once again */ ++ if (!((option & FORCE_MODE) || (option & VIEW_MODE))) { ++ return HPMFWUPG_ERROR; ++ } ++ if (HpmGetUserInput("\n Continue IGNORING Earliest compatibility (Y/N): ")) { ++ rc = HPMFWUPG_SUCCESS; ++ } else { ++ return HPMFWUPG_ERROR; ++ } ++ } ++ /* Get target upgrade capabilities */ ++ rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd); ++ if (rc != HPMFWUPG_SUCCESS) { ++ return HPMFWUPG_ERROR; ++ } ++ /* Copy response to context */ ++ memcpy(&pFwupgCtx->targetCap, ++ &targetCapCmd.resp, ++ sizeof(struct HpmfwupgGetTargetUpgCapabilitiesResp)); ++ if (option & VIEW_MODE) { ++ /* do nothing */ ++ } else { ++ /* Make sure all component IDs defined in the ++ * upgrade image are supported by the IPMC ++ */ ++ if ((pImageHeader->components.ComponentBits.byte & ++ pFwupgCtx->targetCap.componentsPresent.ComponentBits.byte) != ++ pImageHeader->components.ComponentBits.byte) { ++ lprintf(LOG_NOTICE, ++ "\n Some components present in the image file are not supported by the IPMC"); ++ return HPMFWUPG_ERROR; ++ } ++ /* Make sure the upgrade is desirable rigth now */ ++ if (pFwupgCtx->targetCap.GlobalCapabilities.bitField.fwUpgUndesirable == 1) { ++ lprintf(LOG_NOTICE, "\n Upgrade undesirable at this moment"); ++ return HPMFWUPG_ERROR; ++ } ++ /* Get confimation from the user if he wants to continue when ++ * service affected during upgrade ++ */ ++ if (!(option & COMPARE_MODE) ++ && (pFwupgCtx->targetCap.GlobalCapabilities.bitField.servAffectDuringUpg == 1 ++ || pImageHeader->imageCapabilities.bitField.servAffected == 1)) { ++ if (HpmGetUserInput("\nServices may be affected during upgrade. Do you wish to continue? (y/n): ")) { ++ rc = HPMFWUPG_SUCCESS; ++ } else { ++ return HPMFWUPG_ERROR; ++ } ++ } ++ } ++ /* Get the general properties of each component present in image */ ++ for (componentId = HPMFWUPG_COMPONENT_ID_0; ++ componentId < HPMFWUPG_COMPONENT_ID_MAX; ++ componentId++) { ++ /* Reset component properties */ ++ memset(&pFwupgCtx->genCompProp[componentId], 0, ++ sizeof (struct HpmfwupgGetGeneralPropResp)); ++ if ((1 << componentId & pImageHeader->components.ComponentBits.byte)) { ++ struct HpmfwupgGetComponentPropertiesCtx getCompPropCmd; ++ /* Get general component properties */ ++ getCompPropCmd.req.componentId = componentId; ++ getCompPropCmd.req.selector = HPMFWUPG_COMP_GEN_PROPERTIES; ++ rc = HpmfwupgGetComponentProperties(intf, &getCompPropCmd); ++ if (rc == HPMFWUPG_SUCCESS) { ++ /* Copy response to context */ ++ memcpy(&pFwupgCtx->genCompProp[componentId], ++ &getCompPropCmd.resp, ++ sizeof(struct HpmfwupgGetGeneralPropResp)); ++ } ++ } ++ } ++ return rc; + } + +-static int image_version_upgradable(VERSIONINFO *pVersionInfo) ++int ++image_version_upgradable(VERSIONINFO *pVersionInfo) + { + /* If the image and active target versions are different, then + * upgrade */ +- if ((pVersionInfo->imageMajor != pVersionInfo->targetMajor) || +- (pVersionInfo->imageMinor != pVersionInfo->targetMinor) || +- (pVersionInfo->imageAux[0] != pVersionInfo->targetAux[0]) || +- (pVersionInfo->imageAux[1] != pVersionInfo->targetAux[1]) || +- (pVersionInfo->imageAux[2] != pVersionInfo->targetAux[2]) || +- (pVersionInfo->imageAux[3] != pVersionInfo->targetAux[3])) ++ if ((pVersionInfo->imageMajor != pVersionInfo->targetMajor) ++ || (pVersionInfo->imageMinor != pVersionInfo->targetMinor) ++ || (pVersionInfo->imageAux[0] != pVersionInfo->targetAux[0]) ++ || (pVersionInfo->imageAux[1] != pVersionInfo->targetAux[1]) ++ || (pVersionInfo->imageAux[2] != pVersionInfo->targetAux[2]) ++ || (pVersionInfo->imageAux[3] != pVersionInfo->targetAux[3])) { + return (1); +- ++ } + /* If the image and active target versions are the same and rollback +- * is not supported, then there's nothing to do, skip the upgrade */ +- if (!pVersionInfo->rollbackSupported) ++ * is not supported, then there's nothing to do, skip the upgrade ++ */ ++ if (!pVersionInfo->rollbackSupported) { + return (0); +- ++ } + /* If the image and rollback target versions are different, then +- * go ahead and upgrade */ +- if ((pVersionInfo->imageMajor != pVersionInfo->rollbackMajor) || +- (pVersionInfo->imageMinor != pVersionInfo->rollbackMinor) || +- (pVersionInfo->imageAux[0] != pVersionInfo->rollbackAux[0]) || +- (pVersionInfo->imageAux[1] != pVersionInfo->rollbackAux[1]) || +- (pVersionInfo->imageAux[2] != pVersionInfo->rollbackAux[2]) || +- (pVersionInfo->imageAux[3] != pVersionInfo->rollbackAux[3])) ++ * go ahead and upgrade ++ */ ++ if ((pVersionInfo->imageMajor != pVersionInfo->rollbackMajor) ++ || (pVersionInfo->imageMinor != pVersionInfo->rollbackMinor) ++ || (pVersionInfo->imageAux[0] != pVersionInfo->rollbackAux[0]) ++ || (pVersionInfo->imageAux[1] != pVersionInfo->rollbackAux[1]) ++ || (pVersionInfo->imageAux[2] != pVersionInfo->rollbackAux[2]) ++ || (pVersionInfo->imageAux[3] != pVersionInfo->rollbackAux[3])) { + return (1); +- ++ } + /* Image and rollback target versions are the same too, skip it */ + return (0); + } + +-/**************************************************************************** +-* +-* Function Name: HpmfwupgPreUpgradeCheck +-* +-* Description: This function the pre Upgrade check, this mainly helps in checking +-* which all version upgrade is skippable because the image version +-* is same as target version. +-* +-*****************************************************************************/ +-int HpmfwupgPreUpgradeCheck(struct ipmi_intf *intf, +- struct HpmfwupgUpgradeCtx* pFwupgCtx, +- int componentToUpload, int option) ++/* HpmfwupgValidateActionRecordChecksum - validate checksum of the specified ++ * action record header. ++ */ ++int ++HpmfwupgValidateActionRecordChecksum(struct HpmfwupgActionRecord *pActionRecord) + { +- unsigned char* pImagePtr; +- struct HpmfwupgActionRecord *pActionRecord; +- int flagColdReset = FALSE; +- struct HpmfwupgImageHeader *pImageHeader; +- +- pImageHeader = (struct HpmfwupgImageHeader*) pFwupgCtx->pImageData; +- +- /* Put pointer after image header */ +- pImagePtr = (unsigned char*) +- (pFwupgCtx->pImageData + sizeof(struct HpmfwupgImageHeader) + +- pImageHeader->oemDataLength + sizeof(unsigned char)/*chksum*/); +- +- if (option & VIEW_MODE) { +- HpmDisplayVersionHeader(TARGET_VER|ROLLBACK_VER|IMAGE_VER); +- } +- +- /* Perform actions defined in the image */ +- while (pImagePtr < (pFwupgCtx->pImageData + pFwupgCtx->imageSize - +- HPMFWUPG_MD5_SIGNATURE_LENGTH)) { +- /* Get action record */ +- pActionRecord = (struct HpmfwupgActionRecord*)pImagePtr; +- ++ int rc = HPMFWUPG_SUCCESS; + /* Validate action record checksum */ + if (HpmfwupgCalculateChecksum((unsigned char*)pActionRecord, +- sizeof(struct HpmfwupgActionRecord)) != 0) { +- lprintf(LOG_NOTICE," Invalid Action record."); +- return HPMFWUPG_ERROR; ++ sizeof(struct HpmfwupgActionRecord)) != 0) { ++ /* Due to ambiguity in the HPM.1 specification, for the case of ++ * the Upload Firmware Image action type, the record header length ++ * might be thought as either the first 3 bytes, or the first 34 bytes ++ * which precede the firmware image data. ++ * For the latter case we re-calculate the Upload Firmware Image ++ * record checksum for the 34 byte header length. ++ */ ++ if (pActionRecord->actionType != HPMFWUPG_ACTION_UPLOAD_FIRMWARE ++ || HpmfwupgCalculateChecksum((unsigned char*)pActionRecord, ++ sizeof(struct HpmfwupgActionRecord) ++ + sizeof(struct HpmfwupgFirmwareImage))) { ++ lprintf(LOG_NOTICE, " Invalid Action record."); ++ rc = HPMFWUPG_ERROR; ++ } + } ++ return rc; ++} + +- switch( pActionRecord->actionType ) +- { +- case HPMFWUPG_ACTION_BACKUP_COMPONENTS: +- { +- pImagePtr += sizeof(struct HpmfwupgActionRecord); ++/* HpmfwupgPreUpgradeCheck - make pre-Upgrade check, this mainly helps in ++ * checking which all version upgrade is skippable because the image version ++ * is same as target version. ++ */ ++int ++HpmfwupgPreUpgradeCheck(struct ipmi_intf *intf, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx, ++ int componentMask, int option) ++{ ++ unsigned char *pImagePtr; ++ struct HpmfwupgActionRecord *pActionRecord; ++ struct HpmfwupgImageHeader *pImageHeader; ++ int componentId; ++ pImageHeader = (struct HpmfwupgImageHeader*)pFwupgCtx->pImageData; ++ /* Put pointer after image header */ ++ pImagePtr = (unsigned char*)(pFwupgCtx->pImageData ++ + sizeof(struct HpmfwupgImageHeader) ++ + pImageHeader->oemDataLength ++ + sizeof(unsigned char)/*chksum*/); ++ if (option & VIEW_MODE) { ++ HpmDisplayVersionHeader(TARGET_VER|ROLLBACK_VER|IMAGE_VER); + } +- break; +- +- case HPMFWUPG_ACTION_PREPARE_COMPONENTS: +- { +- if (componentToUpload != DEFAULT_COMPONENT_UPLOAD) { +- if (!((1 << componentToUpload) & +- pActionRecord->components.ComponentBits.byte)) { +- lprintf(LOG_NOTICE, +- "\nComponent Id given is not supported\n"); +- return HPMFWUPG_ERROR; +- } ++ /* Perform actions defined in the image */ ++ while (pImagePtr < (pFwupgCtx->pImageData + pFwupgCtx->imageSize ++ - HPMFWUPG_MD5_SIGNATURE_LENGTH)) { ++ /* Get action record */ ++ pActionRecord = (struct HpmfwupgActionRecord*)pImagePtr; ++ /* Validate action record checksum */ ++ if (HpmfwupgValidateActionRecordChecksum(pActionRecord) != HPMFWUPG_SUCCESS) { ++ return HPMFWUPG_ERROR; + } +- pImagePtr += sizeof(struct HpmfwupgActionRecord); +- } +- break; +- +- case HPMFWUPG_ACTION_UPLOAD_FIRMWARE: +- /* Upload all firmware blocks */ +- { +- struct HpmfwupgFirmwareImage *pFwImage; +- unsigned char *pData; +- unsigned int firmwareLength; +- unsigned char mode; +- unsigned char componentId; +- unsigned char componentIdByte; +- unsigned int upgrade_comp; +- VERSIONINFO *pVersionInfo; +- struct HpmfwupgGetComponentPropertiesCtx getCompProp; +- +- /* Save component ID on which the upload is done */ +- componentIdByte = pActionRecord->components.ComponentBits.byte; +- +- componentId = 0; +- while ((componentIdByte >>= 1) !=0) { +- componentId++; ++ /* Validate affected components */ ++ if (pActionRecord->components.ComponentBits.byte ++ && !pFwupgCtx->targetCap.componentsPresent.ComponentBits.byte) { ++ lprintf(LOG_NOTICE, ++ " Invalid action record. One or more affected components is not supported"); ++ return HPMFWUPG_ERROR; + } +- pFwupgCtx->componentId = componentId; +- +- pFwImage = (struct HpmfwupgFirmwareImage*)(pImagePtr + +- sizeof(struct HpmfwupgActionRecord)); +- +- pData = ((unsigned char*)pFwImage + +- sizeof(struct HpmfwupgFirmwareImage)); +- +- /* Get firmware length */ +- firmwareLength = pFwImage->length[0]; +- firmwareLength |= (pFwImage->length[1] << 8) & 0xff00; +- firmwareLength |= (pFwImage->length[2] << 16) & 0xff0000; +- firmwareLength |= (pFwImage->length[3] << 24) & 0xff000000; +- +- pVersionInfo = &gVersionInfo[componentId]; +- +- pVersionInfo->imageMajor = pFwImage->version[0]; +- pVersionInfo->imageMinor = pFwImage->version[1]; +- pVersionInfo->imageAux[0] = pFwImage->version[2]; +- pVersionInfo->imageAux[1] = pFwImage->version[3]; +- pVersionInfo->imageAux[2] = pFwImage->version[4]; +- pVersionInfo->imageAux[3] = pFwImage->version[5]; +- +- mode = TARGET_VER | IMAGE_VER; +- +- if (pVersionInfo->coldResetRequired) +- flagColdReset = TRUE; +- +- upgrade_comp = 0; +- if (option & FORCE_MODE_ALL) { +- upgrade_comp = 1; +- } +- else if ((option & FORCE_MODE_COMPONENT) && +- (componentToUpload == componentId)) { +- upgrade_comp = 1; +- } +- else if (image_version_upgradable(pVersionInfo)) { +- upgrade_comp = 1; +- } +- +- if (verbose) +- lprintf(LOG_NOTICE,"%s component %d", +- (upgrade_comp ? "Updating" : "Skipping"), +- componentId); +- +- if (upgrade_comp) +- pFwupgCtx->compUpdateMask.ComponentBits.byte |= +- 1 << componentId; +- +- if (option & VIEW_MODE) { +- if (pVersionInfo->rollbackSupported) +- mode |= ROLLBACK_VER; +- HpmDisplayVersion(mode,pVersionInfo, upgrade_comp); +- printf("\n"); ++ switch (pActionRecord->actionType) { ++ case HPMFWUPG_ACTION_BACKUP_COMPONENTS: ++ { ++ /* Make sure every component specified by ++ * this action record ++ * supports the backup operation ++ */ ++ for (componentId = HPMFWUPG_COMPONENT_ID_0; ++ componentId < HPMFWUPG_COMPONENT_ID_MAX; ++ componentId++) { ++ if (((1 << componentId) & pActionRecord->components.ComponentBits.byte) ++ && pFwupgCtx->genCompProp[componentId].GeneralCompProperties.bitfield.rollbackBackup == 0) { ++ lprintf(LOG_NOTICE, ++ " Component ID %d does not support backup", ++ componentId); ++ return HPMFWUPG_ERROR; ++ } ++ } ++ pImagePtr += sizeof(struct HpmfwupgActionRecord); ++ } ++ break; ++ case HPMFWUPG_ACTION_PREPARE_COMPONENTS: ++ { ++ /* Make sure every components specified by ++ * this action ++ * supports the prepare operation ++ */ ++ for (componentId = HPMFWUPG_COMPONENT_ID_0; ++ componentId < HPMFWUPG_COMPONENT_ID_MAX; ++ componentId++) { ++ if (((1 << componentId) & pActionRecord->components.ComponentBits.byte) ++ && pFwupgCtx->genCompProp[componentId].GeneralCompProperties.bitfield.preparationSupport == 0) { ++ lprintf(LOG_NOTICE, ++ " Component ID %d does not support preparation", ++ componentId); ++ return HPMFWUPG_ERROR; ++ } ++ } ++ pImagePtr += sizeof(struct HpmfwupgActionRecord); ++ } ++ break; ++ case HPMFWUPG_ACTION_UPLOAD_FIRMWARE: ++ /* Upload all firmware blocks */ ++ { ++ struct HpmfwupgFirmwareImage *pFwImage; ++ unsigned char *pData; ++ unsigned int firmwareLength; ++ unsigned char mode; ++ unsigned char componentId; ++ unsigned char componentIdByte; ++ unsigned int upgrade_comp; ++ VERSIONINFO *pVersionInfo; ++ /* Save component ID on which the upload is done */ ++ componentIdByte = pActionRecord->components.ComponentBits.byte; ++ componentId = 0; ++ while ((componentIdByte >>= 1) != 0) { ++ componentId++; ++ } ++ pFwImage = (struct HpmfwupgFirmwareImage*)(pImagePtr ++ + sizeof(struct HpmfwupgActionRecord)); ++ pData = ((unsigned char*)pFwImage ++ + sizeof(struct HpmfwupgFirmwareImage)); ++ /* Get firmware length */ ++ firmwareLength = pFwImage->length[0]; ++ firmwareLength |= (pFwImage->length[1] << 8) & 0xff00; ++ firmwareLength |= (pFwImage->length[2] << 16) & 0xff0000; ++ firmwareLength |= (pFwImage->length[3] << 24) & 0xff000000; ++ ++ pVersionInfo = &gVersionInfo[componentId]; ++ ++ pVersionInfo->imageMajor = pFwImage->version[0]; ++ pVersionInfo->imageMinor = pFwImage->version[1]; ++ pVersionInfo->imageAux[0] = pFwImage->version[2]; ++ pVersionInfo->imageAux[1] = pFwImage->version[3]; ++ pVersionInfo->imageAux[2] = pFwImage->version[4]; ++ pVersionInfo->imageAux[3] = pFwImage->version[5]; ++ ++ mode = TARGET_VER | IMAGE_VER; ++ /* check if component is selected for upgrade */ ++ upgrade_comp = !componentMask ++ || (componentMask & pActionRecord->components.ComponentBits.byte); ++ /* check if current component version requires upgrade */ ++ if (upgrade_comp && !(option & (FORCE_MODE|COMPARE_MODE))) { ++ upgrade_comp = image_version_upgradable(pVersionInfo); ++ } ++ if (verbose) { ++ lprintf(LOG_NOTICE, ++ "%s component %d", ++ (upgrade_comp ? "Updating" : "Skipping"), ++ componentId); ++ } ++ if (upgrade_comp) { ++ pFwupgCtx->compUpdateMask.ComponentBits.byte|= 1 << componentId; ++ } ++ if (option & VIEW_MODE) { ++ if (pVersionInfo->rollbackSupported) { ++ mode|= ROLLBACK_VER; ++ } ++ HpmDisplayVersion(mode,pVersionInfo, upgrade_comp); ++ printf("\n"); ++ } ++ pImagePtr = pData + firmwareLength; ++ } ++ break; ++ default: ++ lprintf(LOG_NOTICE, ++ " Invalid Action type. Cannot continue"); ++ return HPMFWUPG_ERROR; ++ break; + } +- pImagePtr = pData + firmwareLength; + } +- break; +- default: ++ if (option & VIEW_MODE) { ++ HpmDisplayLine("-",74); ++ fflush(stdout); + lprintf(LOG_NOTICE, +- " Invalid Action type. Cannot continue"); +- return HPMFWUPG_ERROR; +- break; ++ "(*) Component requires Payload Cold Reset"); ++ lprintf(LOG_NOTICE, ++ "(^) Indicates component would be upgraded"); + } +- } ++ return HPMFWUPG_SUCCESS; ++} + +- if (option & VIEW_MODE) { +- HpmDisplayLine("-",74); ++/* HpmfwupgUpgradeStage - upgrade stage of a firmware upgrade procedure as ++ * defined in section 3.3 of the IPM Controller Firmware Upgrade Specification ++ * version 1.0 ++ */ ++int ++HpmfwupgUpgradeStage(struct ipmi_intf *intf, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx, int option) ++{ ++ struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*) ++ pFwupgCtx->pImageData; ++ struct HpmfwupgActionRecord* pActionRecord; ++ int rc = HPMFWUPG_SUCCESS; ++ unsigned char *pImagePtr; ++ unsigned int actionsSize; ++ int flagColdReset = FALSE; ++ time_t start,end; ++ /* Put pointer after image header */ ++ pImagePtr = (unsigned char*) ++ (pFwupgCtx->pImageData + sizeof(struct HpmfwupgImageHeader) + ++ pImageHeader->oemDataLength + sizeof(unsigned char)/*checksum*/); ++ /* Deternime actions size */ ++ actionsSize = pFwupgCtx->imageSize - sizeof(struct HpmfwupgImageHeader); ++ if (!(option & VIEW_MODE)) { ++ HpmDisplayUpgradeHeader(); ++ } ++ /* Perform actions defined in the image */ ++ while (( pImagePtr < (pFwupgCtx->pImageData + pFwupgCtx->imageSize - ++ HPMFWUPG_MD5_SIGNATURE_LENGTH)) ++ && (rc == HPMFWUPG_SUCCESS)) { ++ /* Get action record */ ++ pActionRecord = (struct HpmfwupgActionRecord*)pImagePtr; ++ /* Validate action record checksum */ ++ rc = HpmfwupgValidateActionRecordChecksum(pActionRecord); ++ if (rc != HPMFWUPG_SUCCESS) { ++ continue; ++ } ++ switch(pActionRecord->actionType) { ++ case HPMFWUPG_ACTION_BACKUP_COMPONENTS: ++ { ++ if (!(option & COMPARE_MODE)) { ++ /* Send Upgrade Action command */ ++ struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd; ++ /* Affect only selected components */ ++ initUpgActionCmd.req.componentsMask.ComponentBits.byte = ++ pFwupgCtx->compUpdateMask.ComponentBits.byte & ++ pActionRecord->components.ComponentBits.byte; ++ /* Action is prepare components */ ++ if (initUpgActionCmd.req.componentsMask.ComponentBits.byte) { ++ initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_BACKUP; ++ rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx); ++ } ++ } ++ pImagePtr+= sizeof(struct HpmfwupgActionRecord); ++ } ++ break; ++ case HPMFWUPG_ACTION_PREPARE_COMPONENTS: ++ { ++ if (!(option & COMPARE_MODE)) { ++ /* Send prepare components command */ ++ struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd; ++ /* Affect only selected components */ ++ initUpgActionCmd.req.componentsMask.ComponentBits.byte = ++ pFwupgCtx->compUpdateMask.ComponentBits.byte & ++ pActionRecord->components.ComponentBits.byte; ++ if (initUpgActionCmd.req.componentsMask.ComponentBits.byte) { ++ /* Action is prepare components */ ++ initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_PREPARE; ++ rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx); ++ } ++ } ++ pImagePtr+= sizeof(struct HpmfwupgActionRecord); ++ } ++ break; ++ case HPMFWUPG_ACTION_UPLOAD_FIRMWARE: ++ /* Upload all firmware blocks */ ++ rc = HpmFwupgActionUploadFirmware(pActionRecord->components, ++ pFwupgCtx, ++ &pImagePtr, ++ intf, ++ option, ++ &flagColdReset); ++ break; ++ default: ++ lprintf(LOG_NOTICE, " Invalid Action type. Cannot continue"); ++ rc = HPMFWUPG_ERROR; ++ break; ++ } ++ } ++ HpmDisplayLine("-", 79); + fflush(stdout); +- lprintf(LOG_NOTICE,"(*) Component requires Payload Cold Reset"); +- lprintf(LOG_NOTICE,"(^) Indicates component would be upgraded"); +- } +- return HPMFWUPG_SUCCESS; ++ lprintf(LOG_NOTICE, "(*) Component requires Payload Cold Reset"); ++ return rc; + } + +- +-/**************************************************************************** +-* +-* Function Name: HpmfwupgUpgradeStage +-* +-* Description: This function the upgrade stage of a firmware upgrade +-* procedure as defined in section 3.3 of the IPM Controller +-* Firmware Upgrade Specification version 1.0 +-* +-*****************************************************************************/ +-int HpmfwupgUpgradeStage(struct ipmi_intf *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx, +- int componentToUpload, int option) +-{ +- struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) +- pFwupgCtx->pImageData; +- struct HpmfwupgActionRecord* pActionRecord; +- +- int rc = HPMFWUPG_SUCCESS; +- unsigned char* pImagePtr; +- unsigned int actionsSize; +- int flagColdReset = FALSE; +- time_t start,end; +- +- /* Put pointer after image header */ +- pImagePtr = (unsigned char*) +- (pFwupgCtx->pImageData + sizeof(struct HpmfwupgImageHeader) + +- pImageHeader->oemDataLength + sizeof(unsigned char)/*checksum*/); +- +- /* Deternime actions size */ +- actionsSize = pFwupgCtx->imageSize - sizeof(struct HpmfwupgImageHeader); +- +- if (option & VERSIONCHECK_MODE || option & FORCE_MODE) +- { +- HpmDisplayUpgradeHeader(); +- } +- +- /* Perform actions defined in the image */ +- while( ( pImagePtr < (pFwupgCtx->pImageData + pFwupgCtx->imageSize - +- HPMFWUPG_MD5_SIGNATURE_LENGTH)) && +- ( rc == HPMFWUPG_SUCCESS) ) +- { +- /* Get action record */ +- pActionRecord = (struct HpmfwupgActionRecord*)pImagePtr; +- +- /* Validate action record checksum */ +- if ( HpmfwupgCalculateChecksum((unsigned char*)pActionRecord, +- sizeof(struct HpmfwupgActionRecord)) != 0 ) +- { +- lprintf(LOG_NOTICE," Invalid Action record."); +- rc = HPMFWUPG_ERROR; +- } +- +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- switch( pActionRecord->actionType ) +- { +- case HPMFWUPG_ACTION_BACKUP_COMPONENTS: +- { +- /* Send prepare components command */ +- struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd; +- +- initUpgActionCmd.req.componentsMask = pFwupgCtx->compUpdateMask; +- /* Action is prepare components */ +- initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_BACKUP; +- rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx); +- pImagePtr += sizeof(struct HpmfwupgActionRecord); +- +- } +- break; +- case HPMFWUPG_ACTION_PREPARE_COMPONENTS: +- { +- int componentId; +- /* Make sure every components specified by this action +- supports the prepare components */ +- +- /* Component 'filtering' is done in PreUpdateCheck() and pFwupgCtx is set accordiongly */ +- +- for ( componentId = HPMFWUPG_COMPONENT_ID_0; +- componentId < HPMFWUPG_COMPONENT_ID_MAX; +- componentId++ ) +- { +- if ( (1 << componentId & pFwupgCtx->compUpdateMask.ComponentBits.byte) ) +- { +- if ( pFwupgCtx->genCompProp[componentId].GeneralCompProperties.bitfield.preparationSupport == 0 ) +- { +- lprintf(LOG_NOTICE," Prepare component not supported by component ID %d", componentId); +- rc = HPMFWUPG_ERROR; +- break; +- } +- } +- } +- +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- if ( pFwupgCtx->compUpdateMask.ComponentBits.byte != 0x00 ) +- { +- /* Send prepare components command */ +- struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd; +- initUpgActionCmd.req.componentsMask = pFwupgCtx->compUpdateMask; +- /* Action is prepare components */ +- initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_PREPARE; +- rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx); +- +- } +- pImagePtr += sizeof(struct HpmfwupgActionRecord); +- } +- } +- break; +- +- case HPMFWUPG_ACTION_UPLOAD_FIRMWARE: +- /* Upload all firmware blocks */ +- rc = HpmFwupgActionUploadFirmware +- ( +- pActionRecord->components, +- pFwupgCtx, +- &pImagePtr, +- componentToUpload, +- intf, +- option, +- &flagColdReset +- ); +- +- break; +- default: +- lprintf(LOG_NOTICE," Invalid Action type. Cannot continue"); +- rc = HPMFWUPG_ERROR; +- break; +- } +- } +- } +- +- HpmDisplayLine("-",79); +- +- fflush(stdout); +- lprintf(LOG_NOTICE,"(*) Component requires Payload Cold Reset"); +- +- return rc; ++int ++get_max_rq_data_size(struct ipmi_intf *intf) ++{ ++ int bufLength; ++ /* Check if we receive size in parameters */ ++ if(intf->channel_buf_size != 0) { ++ /* Plan for overhead */ ++ if (intf->target_addr == intf->my_addr) { ++ bufLength = intf->channel_buf_size - 9; ++ } else { ++ bufLength = intf->channel_buf_size - 11; ++ } ++ } else if (strstr(intf->name,"lan") != NULL) { ++ /* Find max buffer length according the connection ++ * parameters ++ */ ++ bufLength = HPMFWUPG_SEND_DATA_COUNT_LAN - 2; ++ if (intf->transit_addr != intf->my_addr ++ && intf->transit_addr != 0) { ++ bufLength -= 8; ++ } ++ } else if (strstr(intf->name,"open") != NULL ++ && intf->target_addr == intf->my_addr) { ++ bufLength = HPMFWUPG_SEND_DATA_COUNT_KCS - 2; ++ } else if (intf->target_channel == 7) { ++ bufLength = HPMFWUPG_SEND_DATA_COUNT_IPMBL; ++ } else { ++ bufLength = HPMFWUPG_SEND_DATA_COUNT_IPMB; ++ } ++ return bufLength; + } + +-static int HpmFwupgActionUploadFirmware +-( +- struct HpmfwupgComponentBitMask components, +- struct HpmfwupgUpgradeCtx* pFwupgCtx, +- unsigned char** pImagePtr, +- int componentToUpload, +- struct ipmi_intf *intf, +- int option, +- int *pFlagColdReset +-) +-{ +- struct HpmfwupgFirmwareImage* pFwImage; +- struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd; +- struct HpmfwupgUploadFirmwareBlockCtx uploadCmd; +- struct HpmfwupgFinishFirmwareUploadCtx finishCmd; +- struct HpmfwupgGetComponentPropertiesCtx getCompProp; +- VERSIONINFO *pVersionInfo; +- time_t start,end; +- +- int rc = HPMFWUPG_SUCCESS; +- int skip = TRUE; +- unsigned char* pData, *pDataInitial; +- unsigned char count; +- unsigned int totalSent = 0; +- unsigned char bufLength = 0; +- unsigned int firmwareLength = 0; +- +- unsigned int displayFWLength = 0; +- unsigned char *pDataTemp; +- unsigned int imageOffset = 0x00; +- unsigned int blockLength = 0x00; +- unsigned int lengthOfBlock = 0x00; +- unsigned int numTxPkts = 0; +- unsigned int numRxPkts = 0; +- unsigned char mode = 0; +- unsigned char componentId = 0x00; +- unsigned char componentIdByte = 0x00; +- +- /* Save component ID on which the upload is done */ +- componentIdByte = components.ComponentBits.byte; +- while ((componentIdByte>>=1)!=0) +- { +- componentId++; +- } +- pFwupgCtx->componentId = componentId; +- +- pVersionInfo = (VERSIONINFO*) &gVersionInfo[componentId]; +- +- pFwImage = (struct HpmfwupgFirmwareImage*)((*pImagePtr) + +- sizeof(struct HpmfwupgActionRecord)); +- +- pDataInitial = ((unsigned char*)pFwImage + sizeof(struct HpmfwupgFirmwareImage)); +- pData = pDataInitial; +- +- /* Get firmware length */ +- firmwareLength = pFwImage->length[0]; +- firmwareLength |= (pFwImage->length[1] << 8) & 0xff00; +- firmwareLength |= (pFwImage->length[2] << 16) & 0xff0000; +- firmwareLength |= (pFwImage->length[3] << 24) & 0xff000000; +- +- mode = TARGET_VER | IMAGE_VER; +- +- if (pVersionInfo->rollbackSupported) +- { +- mode |= ROLLBACK_VER; ++int ++HpmFwupgActionUploadFirmware(struct HpmfwupgComponentBitMask components, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx, ++ unsigned char **pImagePtr, ++ struct ipmi_intf *intf, ++ int option, ++ int *pFlagColdReset) ++{ ++ struct HpmfwupgFirmwareImage *pFwImage; ++ struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd; ++ struct HpmfwupgUploadFirmwareBlockCtx uploadCmd; ++ struct HpmfwupgFinishFirmwareUploadCtx finishCmd; ++ VERSIONINFO *pVersionInfo; ++ time_t start,end; ++ ++ int rc = HPMFWUPG_SUCCESS; ++ int skip = TRUE; ++ unsigned char *pData, *pDataInitial; ++ unsigned short count; ++ unsigned int totalSent = 0; ++ unsigned short bufLength = 0; ++ unsigned short bufLengthIsSet = 0; ++ unsigned int firmwareLength = 0; ++ ++ unsigned int displayFWLength = 0; ++ unsigned char *pDataTemp; ++ unsigned int imageOffset = 0x00; ++ unsigned int blockLength = 0x00; ++ unsigned int lengthOfBlock = 0x00; ++ unsigned int numTxPkts = 0; ++ unsigned int numRxPkts = 0; ++ unsigned char mode = 0; ++ unsigned char componentId = 0x00; ++ unsigned char componentIdByte = 0x00; ++ /* Save component ID on which the upload is done */ ++ componentIdByte = components.ComponentBits.byte; ++ while ((componentIdByte>>= 1) != 0) { ++ componentId++; + } +- +- if ((option & DEBUG_MODE)) +- { +- printf("\n\n Comp ID : %d [%-20s]\n",pVersionInfo->componentId,pFwImage->desc); ++ pFwupgCtx->componentId = componentId; ++ pVersionInfo = (VERSIONINFO *)&gVersionInfo[componentId]; ++ pFwImage = (struct HpmfwupgFirmwareImage*)((*pImagePtr) ++ + sizeof(struct HpmfwupgActionRecord)); ++ pDataInitial = ((unsigned char *)pFwImage ++ + sizeof(struct HpmfwupgFirmwareImage)); ++ pData = pDataInitial; ++ /* Find max buffer length according the connection parameters */ ++ bufLength = get_max_rq_data_size(intf); ++ /* Get firmware length */ ++ firmwareLength = pFwImage->length[0]; ++ firmwareLength|= (pFwImage->length[1] << 8) & 0xff00; ++ firmwareLength|= (pFwImage->length[2] << 16) & 0xff0000; ++ firmwareLength|= (pFwImage->length[3] << 24) & 0xff000000; ++ mode = TARGET_VER | IMAGE_VER; ++ if (pVersionInfo->rollbackSupported) { ++ mode |= ROLLBACK_VER; + } +- else +- { +- HpmDisplayVersion(mode,pVersionInfo, 0); ++ if ((option & DEBUG_MODE)) { ++ printf("\n\n Comp ID : %d [%-20s]\n", ++ pVersionInfo->componentId, ++ pFwImage->desc); ++ } else { ++ HpmDisplayVersion(mode, pVersionInfo, 0); + } +- +- if( (1 << componentId) & pFwupgCtx->compUpdateMask.ComponentBits.byte) +- { +- if( verbose ) { +- lprintf(LOG_NOTICE,"Do not skip %d" , componentId); ++ if ((1 << componentId) & pFwupgCtx->compUpdateMask.ComponentBits.byte) { ++ if (verbose) { ++ lprintf(LOG_NOTICE, "Do not skip %d", ++ componentId); + } + skip = FALSE; + } +- +- if(!skip) +- { +- HpmDisplayUpgrade(0,0,1,0); +- /* Initialize parameters */ +- uploadCmd.req.blockNumber = 0; +- +- /* Check if we receive size in parameters */ +- if(intf->channel_buf_size != 0) +- { +- if (intf->target_addr == intf->my_addr) +- { +- bufLength = intf->channel_buf_size - 9; /* Plan for overhead */ +- } +- else +- { +- bufLength = intf->channel_buf_size - 11; /* Plan for overhead */ +- } +- } +- else +- { +- /* Find max buffer length according the connection parameters */ +- if ( strstr(intf->name,"lan") != NULL ) +- { +- bufLength = HPMFWUPG_SEND_DATA_COUNT_LAN - 2; +- if ( intf->transit_addr != intf->my_addr && intf->transit_addr != 0 ) +- bufLength -= 8; +- } +- else +- { +- if +- ( +- strstr(intf->name,"open") != NULL +- && +- ( +- intf->target_addr == intf->my_addr +- ) +- ) +- { +- bufLength = HPMFWUPG_SEND_DATA_COUNT_KCS - 2; +- } +- else +- { +- if ( intf->target_channel == 7 ) +- { +- bufLength = HPMFWUPG_SEND_DATA_COUNT_IPMBL; +- } +- else +- { +- bufLength = HPMFWUPG_SEND_DATA_COUNT_IPMB; +- } +- } +- } +- } +- +- /* Send Initiate Upgrade Action */ +- initUpgActionCmd.req.componentsMask = components; +- /* Action is upgrade */ +- initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_UPGRADE; +- rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx); +- +- if (rc != HPMFWUPG_SUCCESS) +- { +- skip = TRUE; +- } +- +- if ( (pVersionInfo->coldResetRequired) && (!skip)) +- { +- *pFlagColdReset = TRUE; +- } +- /* pDataInitial is the starting pointer of the image data */ +- /* pDataTemp is one which we will move across */ +- pData = pDataInitial; +- pDataTemp = pDataInitial; +- lengthOfBlock = firmwareLength; +- totalSent = 0x00; +- displayFWLength= firmwareLength; +- time(&start); +- +- +- while ( (pData < (pDataTemp+lengthOfBlock)) && (rc == HPMFWUPG_SUCCESS) ) +- { +- if ( (pData+bufLength) <= (pDataTemp+lengthOfBlock) ) +- { +- count = bufLength; +- } +- else +- { +- count = (unsigned char)((pDataTemp+lengthOfBlock) - pData); +- } +- memcpy(&uploadCmd.req.data, pData, bufLength); +- +- imageOffset = 0x00; +- blockLength = 0x00; +- numTxPkts++; +- rc = HpmfwupgUploadFirmwareBlock(intf, &uploadCmd, pFwupgCtx, count, +- &imageOffset,&blockLength); +- numRxPkts++; +- +- if ( rc != HPMFWUPG_SUCCESS) +- { +- if ( rc == HPMFWUPG_UPLOAD_BLOCK_LENGTH ) +- { +- /* Retry with a smaller buffer length */ +- if ( strstr(intf->name,"lan") != NULL ) +- { +- bufLength -= (unsigned char)8; +- lprintf(LOG_INFO,"Trying reduced buffer length: %d", bufLength); +- } +- else +- { +- bufLength -= (unsigned char)1; +- lprintf(LOG_INFO,"Trying reduced buffer length: %d", bufLength); +- } +- rc = HPMFWUPG_SUCCESS; +- } +- else if ( rc == HPMFWUPG_UPLOAD_RETRY ) +- { +- rc = HPMFWUPG_SUCCESS; +- } +- else +- { +- fflush(stdout); +- lprintf(LOG_NOTICE,"\n Error in Upload FIRMWARE command [rc=%d]\n",rc); +- lprintf(LOG_NOTICE,"\n TotalSent:0x%x ",totalSent); +- /* Exiting from the function */ +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- if (blockLength > firmwareLength) +- { +- /* +- * blockLength is the remaining length of the firmware to upload so +- * if its greater than the firmware length then its kind of error +- */ +- lprintf(LOG_NOTICE,"\n Error in Upload FIRMWARE command [rc=%d]\n",rc); +- lprintf(LOG_NOTICE,"\n TotalSent:0x%x Img offset:0x%x Blk length:0x%x Fwlen:0x%x\n", +- totalSent,imageOffset,blockLength,firmwareLength); +- rc = HPMFWUPG_ERROR; +- } +- totalSent += count; +- if (imageOffset != 0x00) +- { +- /* block Length is valid */ +- lengthOfBlock = blockLength; +- pDataTemp = pDataInitial + imageOffset; +- pData = pDataTemp; +- if ( displayFWLength == firmwareLength) +- { +- /* This is basically used only to make sure that we display uptil 100% */ +- displayFWLength = blockLength + totalSent; +- } +- } +- else +- { +- pData += count; +- } +- time(&end); +- /* +- * Just added debug mode in case we need to see exactly how many bytes have +- * gone through - Its a hidden option used mainly should be used for debugging +- */ +- if ( option & DEBUG_MODE) +- { +- fflush(stdout); +- printf(" Blk Num : %02x Bytes : %05x ", +- uploadCmd.req.blockNumber,totalSent); +- if (imageOffset || blockLength) +- { +- printf("\n--> ImgOff : %x BlkLen : %x\n",imageOffset,blockLength); +- } +- if (displayFWLength == totalSent) +- { +- printf("\n Time Taken %02ld:%02ld",(end-start)/60, (end-start)%60); +- printf("\n\n"); +- } +- } +- else +- { +- HpmDisplayUpgrade(0,totalSent,displayFWLength,(end-start)); +- } +- uploadCmd.req.blockNumber++; +- } +- } +- } +- +- if (skip) +- { +- +- HpmDisplayUpgrade(1,0,0,0); +- *pImagePtr = pDataInitial + firmwareLength; +- } +- +- if +- ( +- (rc == HPMFWUPG_SUCCESS) +- && +- (!skip) +- ) +- { +- /* Send finish component */ +- /* Set image length */ +- finishCmd.req.componentId = componentId; +- /* We need to send the actual data that is sent +- * not the comlete firmware image length +- */ +- finishCmd.req.imageLength[0] = totalSent & 0xFF; +- finishCmd.req.imageLength[1] = (totalSent >> 8) & 0xFF; +- finishCmd.req.imageLength[2] = (totalSent >> 16) & 0xFF; +- finishCmd.req.imageLength[3] = (totalSent >> 24) & 0xFF; +- rc = HpmfwupgFinishFirmwareUpload(intf, &finishCmd, pFwupgCtx); +- *pImagePtr = pDataInitial + firmwareLength; +- } +- +- return rc; ++ if (!skip) { ++ HpmDisplayUpgrade(0,0,1,0); ++ /* Initialize parameters */ ++ uploadCmd.req = malloc(get_max_rq_data_size(intf) ++ + sizeof(struct HpmfwupgUploadFirmwareBlockReq)); ++ if (!uploadCmd.req) { ++ lprintf(LOG_ERR, "ipmitool: malloc failure"); ++ return HPMFWUPG_ERROR; ++ } ++ uploadCmd.req->blockNumber = 0; ++ /* Send Initiate Upgrade Action */ ++ initUpgActionCmd.req.componentsMask = components; ++ if (option & COMPARE_MODE) { ++ /* Action is compare */ ++ initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_COMPARE; ++ } else { ++ /* Action is upgrade */ ++ initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_UPGRADE; ++ } ++ rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx); ++ if (rc != HPMFWUPG_SUCCESS) { ++ skip = TRUE; ++ } ++ if ((pVersionInfo->coldResetRequired) && (!skip)) { ++ *pFlagColdReset = TRUE; ++ } ++ /* pDataInitial is the starting pointer of the image data */ ++ /* pDataTemp is one which we will move across */ ++ pData = pDataInitial; ++ pDataTemp = pDataInitial; ++ lengthOfBlock = firmwareLength; ++ totalSent = 0x00; ++ displayFWLength= firmwareLength; ++ time(&start); ++ while ((pData < (pDataTemp+lengthOfBlock)) && (rc == HPMFWUPG_SUCCESS)) { ++ if ((pData+bufLength) <= (pDataTemp+lengthOfBlock)) { ++ count = bufLength; ++ } else { ++ count = (unsigned short)((pDataTemp+lengthOfBlock) - pData); ++ } ++ memcpy(&uploadCmd.req->data, pData, bufLength); ++ imageOffset = 0x00; ++ blockLength = 0x00; ++ numTxPkts++; ++ rc = HpmfwupgUploadFirmwareBlock(intf, &uploadCmd, ++ pFwupgCtx, count, &imageOffset,&blockLength); ++ numRxPkts++; ++ if (rc != HPMFWUPG_SUCCESS) { ++ if (rc == HPMFWUPG_UPLOAD_BLOCK_LENGTH && !bufLengthIsSet) { ++ rc = HPMFWUPG_SUCCESS; ++ /* Retry with a smaller buffer length */ ++ if (strstr(intf->name,"lan") != NULL && bufLength > 8) { ++ bufLength-= 8; ++ lprintf(LOG_INFO, ++ "Trying reduced buffer length: %d", ++ bufLength); ++ } else if (bufLength) { ++ bufLength-= 1; ++ lprintf(LOG_INFO, ++ "Trying reduced buffer length: %d", ++ bufLength); ++ } else { ++ rc = HPMFWUPG_ERROR; ++ } ++ } else if (rc == HPMFWUPG_UPLOAD_RETRY) { ++ rc = HPMFWUPG_SUCCESS; ++ } else { ++ fflush(stdout); ++ lprintf(LOG_NOTICE, ++ "\n Error in Upload FIRMWARE command [rc=%d]\n", ++ rc); ++ lprintf(LOG_NOTICE, ++ "\n TotalSent:0x%x ", ++ totalSent); ++ /* Exiting from the function */ ++ rc = HPMFWUPG_ERROR; ++ } ++ } else { ++ /* success, buf length is valid */ ++ bufLengthIsSet = 1; ++ if (blockLength > firmwareLength) { ++ /* ++ * blockLength is the remaining length of the firmware to upload so ++ * if its greater than the firmware length then its kind of error ++ */ ++ lprintf(LOG_NOTICE, ++ "\n Error in Upload FIRMWARE command [rc=%d]\n", ++ rc); ++ lprintf(LOG_NOTICE, ++ "\n TotalSent:0x%x Img offset:0x%x Blk length:0x%x Fwlen:0x%x\n", ++ totalSent,imageOffset,blockLength,firmwareLength); ++ rc = HPMFWUPG_ERROR; ++ } ++ totalSent += count; ++ if (imageOffset != 0x00) { ++ /* block Length is valid */ ++ lengthOfBlock = blockLength; ++ pDataTemp = pDataInitial + imageOffset; ++ pData = pDataTemp; ++ if (displayFWLength == firmwareLength) { ++ /* This is basically used only to make sure that we display uptil 100% */ ++ displayFWLength = blockLength + totalSent; ++ } ++ } else { ++ pData += count; ++ } ++ time(&end); ++ /* ++ * Just added debug mode in case we need to see exactly how many bytes have ++ * gone through - Its a hidden option used mainly should be used for debugging ++ */ ++ if (option & DEBUG_MODE) { ++ fflush(stdout); ++ printf(" Blk Num : %02x Bytes : %05x ", ++ uploadCmd.req->blockNumber,totalSent); ++ if (imageOffset || blockLength) { ++ printf("\n--> ImgOff : %x BlkLen : %x\n", ++ imageOffset,blockLength); ++ } ++ if (displayFWLength == totalSent) { ++ printf("\n Time Taken %02ld:%02ld", ++ (end-start)/60, (end-start)%60); ++ printf("\n\n"); ++ } ++ } else { ++ HpmDisplayUpgrade(0, totalSent, ++ displayFWLength, (end-start)); ++ } ++ uploadCmd.req->blockNumber++; ++ } ++ } ++ /* free buffer */ ++ free(uploadCmd.req); ++ uploadCmd.req = NULL; ++ } ++ if (skip) { ++ HpmDisplayUpgrade(1,0,0,0); ++ if ((option & COMPARE_MODE) ++ && !pFwupgCtx->genCompProp[pFwupgCtx->componentId].GeneralCompProperties.bitfield.comparisonSupport) { ++ printf("| |Comparison isn't supported for given compenent. |\n"); ++ } ++ *pImagePtr = pDataInitial + firmwareLength; ++ } ++ if (rc == HPMFWUPG_SUCCESS && !skip) { ++ /* Send finish component */ ++ /* Set image length */ ++ finishCmd.req.componentId = componentId; ++ /* We need to send the actual data that is sent ++ * not the comlete firmware image length ++ */ ++ finishCmd.req.imageLength[0] = totalSent & 0xFF; ++ finishCmd.req.imageLength[1] = (totalSent >> 8) & 0xFF; ++ finishCmd.req.imageLength[2] = (totalSent >> 16) & 0xFF; ++ finishCmd.req.imageLength[3] = (totalSent >> 24) & 0xFF; ++ rc = HpmfwupgFinishFirmwareUpload(intf, &finishCmd, ++ pFwupgCtx, option); ++ *pImagePtr = pDataInitial + firmwareLength; ++ } ++ return rc; + } + +-/**************************************************************************** +-* +-* Function Name: HpmfwupgActivationStage +-* +-* Description: This function the validation stage of a firmware upgrade +-* procedure as defined in section 3.4 of the IPM Controller +-* Firmware Upgrade Specification version 1.0 +-* +-*****************************************************************************/ +-static int HpmfwupgActivationStage(struct ipmi_intf *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx) +-{ +- int rc = HPMFWUPG_SUCCESS; +- struct HpmfwupgActivateFirmwareCtx activateCmd; +- struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) +- pFwupgCtx->pImageData; +- +- /* Print out stuf...*/ +- printf(" "); +- fflush(stdout); +- /* Activate new firmware */ +- rc = HpmfwupgActivateFirmware(intf, &activateCmd, pFwupgCtx); +- +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- /* Query self test result if supported by target and new image */ +- if ( (pFwupgCtx->targetCap.GlobalCapabilities.bitField.ipmcSelftestCap == 1) || +- (pImageHeader->imageCapabilities.bitField.imageSelfTest == 1) ) +- { +- struct HpmfwupgQuerySelftestResultCtx selfTestCmd; +- rc = HpmfwupgQuerySelftestResult(intf, &selfTestCmd, pFwupgCtx); +- +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- /* Get the self test result */ +- if ( selfTestCmd.resp.result1 != 0x55 ) +- { +- /* Perform manual rollback if necessary */ +- /* BACKUP/ MANUAL ROLLBACK not supported by this UA */ +- lprintf(LOG_NOTICE," Self test failed:"); +- lprintf(LOG_NOTICE," Result1 = %x", selfTestCmd.resp.result1); +- lprintf(LOG_NOTICE," Result2 = %x", selfTestCmd.resp.result2); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- /* Perform manual rollback if necessary */ +- /* BACKUP / MANUAL ROLLBACK not supported by this UA */ +- lprintf(LOG_NOTICE," Self test failed."); +- } +- } +- } +- +- /* If activation / self test failed, query rollback status if automatic rollback supported */ +- if ( rc == HPMFWUPG_ERROR ) +- { +- if ( (pFwupgCtx->targetCap.GlobalCapabilities.bitField.autRollback == 1) && +- (pFwupgCtx->genCompProp[pFwupgCtx->componentId].GeneralCompProperties.bitfield.rollbackBackup != 0x00) ) +- { +- struct HpmfwupgQueryRollbackStatusCtx rollCmd; +- lprintf(LOG_NOTICE," Getting rollback status..."); +- fflush(stdout); +- rc = HpmfwupgQueryRollbackStatus(intf, &rollCmd, pFwupgCtx); +- } +- } +- +- return rc; ++/* HpmfwupgActivationStage - validate stage of a firmware upgrade procedure as ++ * defined in section 3.4 of the IPM Controller Firmware Upgrade Specification ++ * version 1.0 ++ */ ++int ++HpmfwupgActivationStage(struct ipmi_intf *intf, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx) ++{ ++ int rc = HPMFWUPG_SUCCESS; ++ struct HpmfwupgActivateFirmwareCtx activateCmd; ++ struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*) ++ pFwupgCtx->pImageData; ++ /* Print out stuf...*/ ++ printf(" "); ++ fflush(stdout); ++ /* Activate new firmware */ ++ activateCmd.req.rollback_override = 0; ++ rc = HpmfwupgActivateFirmware(intf, &activateCmd, pFwupgCtx); ++ if (rc == HPMFWUPG_SUCCESS) { ++ /* Query self test result if supported by target and new image */ ++ if ((pFwupgCtx->targetCap.GlobalCapabilities.bitField.ipmcSelftestCap == 1) ++ || (pImageHeader->imageCapabilities.bitField.imageSelfTest == 1)) { ++ struct HpmfwupgQuerySelftestResultCtx selfTestCmd; ++ rc = HpmfwupgQuerySelftestResult(intf, &selfTestCmd, ++ pFwupgCtx); ++ if (rc == HPMFWUPG_SUCCESS) { ++ /* Get the self test result */ ++ if (selfTestCmd.resp.result1 != 0x55) { ++ /* Perform manual rollback if necessary */ ++ /* BACKUP/ MANUAL ROLLBACK not supported by this UA */ ++ lprintf(LOG_NOTICE, " Self test failed:"); ++ lprintf(LOG_NOTICE, " Result1 = %x", ++ selfTestCmd.resp.result1); ++ lprintf(LOG_NOTICE, " Result2 = %x", ++ selfTestCmd.resp.result2); ++ rc = HPMFWUPG_ERROR; ++ } ++ } else { ++ /* Perform manual rollback if necessary */ ++ /* BACKUP / MANUAL ROLLBACK not supported by this UA */ ++ lprintf(LOG_NOTICE," Self test failed."); ++ } ++ } ++ } ++ /* If activation / self test failed, query rollback ++ * status if automatic rollback supported ++ */ ++ if (rc == HPMFWUPG_ERROR) { ++ if ((pFwupgCtx->targetCap.GlobalCapabilities.bitField.autRollback == 1) ++ && (pFwupgCtx->genCompProp[pFwupgCtx->componentId].GeneralCompProperties.bitfield.rollbackBackup != 0x00)) { ++ struct HpmfwupgQueryRollbackStatusCtx rollCmd; ++ lprintf(LOG_NOTICE," Getting rollback status..."); ++ fflush(stdout); ++ rc = HpmfwupgQueryRollbackStatus(intf, ++ &rollCmd, pFwupgCtx); ++ } ++ } ++ return rc; + } + +-int HpmfwupgGetBufferFromFile(char* imageFilename, struct HpmfwupgUpgradeCtx* pFwupgCtx) ++int ++HpmfwupgGetBufferFromFile(char *imageFilename, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx) + { +- int rc = HPMFWUPG_SUCCESS; +- int ret = 0; +- FILE* pImageFile = fopen(imageFilename, "rb"); +- +- if ( pImageFile == NULL ) +- { +- lprintf(LOG_NOTICE,"Cannot open image file %s", imageFilename); +- rc = HPMFWUPG_ERROR; +- } +- +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- /* Get the raw data in file */ +- fseek(pImageFile, 0, SEEK_END); +- pFwupgCtx->imageSize = ftell(pImageFile); +- pFwupgCtx->pImageData = malloc(sizeof(unsigned char)*pFwupgCtx->imageSize); +- pFwupgCtx->compUpdateMask.ComponentBits.byte = 0; +- rewind(pImageFile); +- if ( pFwupgCtx->pImageData != NULL ) +- { +- ret = fread(pFwupgCtx->pImageData, sizeof(unsigned char), +- pFwupgCtx->imageSize, pImageFile); +- if (ret != pFwupgCtx->imageSize) { +- lprintf(LOG_ERROR,"Failed to read file %s size %d", +- imageFilename, pFwupgCtx->imageSize); ++ int rc = HPMFWUPG_SUCCESS; ++ int ret = 0; ++ FILE *pImageFile = fopen(imageFilename, "rb"); ++ if (pImageFile == NULL) { ++ lprintf(LOG_ERR, "Cannot open image file '%s'", ++ imageFilename); ++ return HPMFWUPG_ERROR; ++ } ++ /* Get the raw data in file */ ++ fseek(pImageFile, 0, SEEK_END); ++ pFwupgCtx->imageSize = ftell(pImageFile); ++ pFwupgCtx->pImageData = malloc(sizeof(unsigned char)*pFwupgCtx->imageSize); ++ if (pFwupgCtx->pImageData == NULL) { ++ lprintf(LOG_ERR, "ipmitool: malloc failure"); ++ fclose(pImageFile); ++ return HPMFWUPG_ERROR; ++ } ++ rewind(pImageFile); ++ ret = fread(pFwupgCtx->pImageData, ++ sizeof(unsigned char), ++ pFwupgCtx->imageSize, ++ pImageFile); ++ if (ret != pFwupgCtx->imageSize) { ++ lprintf(LOG_ERR, ++ "Failed to read file %s size %d", ++ imageFilename, ++ pFwupgCtx->imageSize); + rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- rc = HPMFWUPG_ERROR; +- } +- +- fclose(pImageFile); +- } +- +- return rc; ++ } ++ fclose(pImageFile); ++ return rc; + } + +-int HpmfwupgGetDeviceId(struct ipmi_intf *intf, struct ipm_devid_rsp* pGetDevId) ++int ++HpmfwupgGetDeviceId(struct ipmi_intf *intf, struct ipm_devid_rsp *pGetDevId) + { +- int rc = HPMFWUPG_SUCCESS; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_APP; +- req.msg.cmd = BMC_GET_DEVICE_ID; +- req.msg.data_len = 0; +- +- rsp = HpmfwupgSendCmd(intf, req, NULL); +- +- if ( rsp ) +- { +- if ( rsp->ccode == 0x00 ) +- { +- memcpy(pGetDevId, rsp->data, sizeof(struct ipm_devid_rsp)); +- } +- else +- { +- lprintf(LOG_NOTICE,"Error getting device ID"); +- lprintf(LOG_NOTICE,"compcode=0x%x: %s", +- rsp->ccode, +- val2str(rsp->ccode, completion_code_vals)); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error getting device ID\n"); +- rc = HPMFWUPG_ERROR; +- } +- return rc; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_APP; ++ req.msg.cmd = BMC_GET_DEVICE_ID; ++ req.msg.data_len = 0; ++ rsp = HpmfwupgSendCmd(intf, req, NULL); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error getting device ID."); ++ return HPMFWUPG_ERROR; ++ } ++ if (rsp->ccode != 0x00) { ++ lprintf(LOG_ERR, "Error getting device ID."); ++ lprintf(LOG_ERR, "compcode=0x%x: %s", ++ rsp->ccode, ++ val2str(rsp->ccode, completion_code_vals)); ++ return HPMFWUPG_ERROR; ++ } ++ memcpy(pGetDevId, rsp->data, sizeof(struct ipm_devid_rsp)); ++ return HPMFWUPG_SUCCESS; + } + +-int HpmfwupgGetTargetUpgCapabilities(struct ipmi_intf *intf, +- struct HpmfwupgGetTargetUpgCapabilitiesCtx* pCtx) ++int ++HpmfwupgGetTargetUpgCapabilities(struct ipmi_intf *intf, ++ struct HpmfwupgGetTargetUpgCapabilitiesCtx *pCtx) + { +- int rc = HPMFWUPG_SUCCESS; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- +- pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_PICMG; +- req.msg.cmd = HPMFWUPG_GET_TARGET_UPG_CAPABILITIES; +- req.msg.data = (unsigned char*)&pCtx->req; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_PICMG; ++ req.msg.cmd = HPMFWUPG_GET_TARGET_UPG_CAPABILITIES; ++ req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgGetTargetUpgCapabilitiesReq); +- +- rsp = HpmfwupgSendCmd(intf, req, NULL); +- +- if ( rsp ) +- { +- if ( rsp->ccode == 0x00 ) +- { +- memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetTargetUpgCapabilitiesResp)); +- if ( verbose ) +- { +- lprintf(LOG_NOTICE,"TARGET UPGRADE CAPABILITIES"); +- lprintf(LOG_NOTICE,"-------------------------------"); +- lprintf(LOG_NOTICE,"HPM.1 version............%d ", pCtx->resp.hpmVersion); +- lprintf(LOG_NOTICE,"Component 0 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. +- bitField.component0 ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Component 1 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. +- bitField.component1 ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Component 2 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. +- bitField.component2 ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Component 3 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. +- bitField.component3 ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Component 4 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. +- bitField.component4 ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Component 5 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. +- bitField.component5 ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Component 6 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. +- bitField.component6 ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Component 7 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. +- bitField.component7 ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Upgrade undesirable.....[%c] ", pCtx->resp.GlobalCapabilities. +- bitField.fwUpgUndesirable ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Aut rollback override...[%c] ", pCtx->resp.GlobalCapabilities. +- bitField.autRollbackOverride ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"IPMC degraded...........[%c] ", pCtx->resp.GlobalCapabilities. +- bitField.ipmcDegradedDurinUpg ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Defered activation......[%c] ", pCtx->resp.GlobalCapabilities. +- bitField.deferActivation ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Service affected........[%c] ", pCtx->resp.GlobalCapabilities. +- bitField.servAffectDuringUpg ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Manual rollback.........[%c] ", pCtx->resp.GlobalCapabilities. +- bitField.manualRollback ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Automatic rollback......[%c] ", pCtx->resp.GlobalCapabilities. +- bitField.autRollback ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Self test...............[%c] ", pCtx->resp.GlobalCapabilities. +- bitField.ipmcSelftestCap ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Upgrade timeout.........[%d sec] ", pCtx->resp.upgradeTimeout*5); +- lprintf(LOG_NOTICE,"Self test timeout.......[%d sec] ", pCtx->resp.selftestTimeout*5); +- lprintf(LOG_NOTICE,"Rollback timeout........[%d sec] ", pCtx->resp.rollbackTimeout*5); +- lprintf(LOG_NOTICE,"Inaccessibility timeout.[%d sec] \n", pCtx->resp.inaccessTimeout*5); +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error getting target upgrade capabilities\n", rsp->ccode); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error getting target upgrade capabilities\n"); +- rc = HPMFWUPG_ERROR; +- } +- +- +- +- return rc; ++ rsp = HpmfwupgSendCmd(intf, req, NULL); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, ++ "Error getting target upgrade capabilities."); ++ return HPMFWUPG_ERROR; ++ } ++ if (rsp->ccode != 0x00) { ++ lprintf(LOG_ERR, ++ "Error getting target upgrade capabilities, ccode: 0x%x: %s", ++ rsp->ccode, ++ val2str(rsp->ccode, completion_code_vals)); ++ return HPMFWUPG_ERROR; ++ } ++ memcpy(&pCtx->resp, rsp->data, ++ sizeof(struct HpmfwupgGetTargetUpgCapabilitiesResp)); ++ if (verbose) { ++ lprintf(LOG_NOTICE, "TARGET UPGRADE CAPABILITIES"); ++ lprintf(LOG_NOTICE, "-------------------------------"); ++ lprintf(LOG_NOTICE, "HPM.1 version............%d ", ++ pCtx->resp.hpmVersion); ++ lprintf(LOG_NOTICE, "Component 0 presence....[%c] ", ++ pCtx->resp.componentsPresent.ComponentBits.bitField.component0 ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Component 1 presence....[%c] ", ++ pCtx->resp.componentsPresent.ComponentBits.bitField.component1 ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Component 2 presence....[%c] ", ++ pCtx->resp.componentsPresent.ComponentBits.bitField.component2 ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Component 3 presence....[%c] ", ++ pCtx->resp.componentsPresent.ComponentBits.bitField.component3 ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Component 4 presence....[%c] ", ++ pCtx->resp.componentsPresent.ComponentBits.bitField.component4 ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Component 5 presence....[%c] ", ++ pCtx->resp.componentsPresent.ComponentBits.bitField.component5 ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Component 6 presence....[%c] ", ++ pCtx->resp.componentsPresent.ComponentBits.bitField.component6 ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Component 7 presence....[%c] ", ++ pCtx->resp.componentsPresent.ComponentBits.bitField.component7 ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Upgrade undesirable.....[%c] ", ++ pCtx->resp.GlobalCapabilities.bitField.fwUpgUndesirable ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Aut rollback override...[%c] ", ++ pCtx->resp.GlobalCapabilities.bitField.autRollbackOverride ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "IPMC degraded...........[%c] ", ++ pCtx->resp.GlobalCapabilities.bitField.ipmcDegradedDurinUpg ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Defered activation......[%c] ", ++ pCtx->resp.GlobalCapabilities.bitField.deferActivation ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Service affected........[%c] ", ++ pCtx->resp.GlobalCapabilities.bitField.servAffectDuringUpg ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Manual rollback.........[%c] ", ++ pCtx->resp.GlobalCapabilities.bitField.manualRollback ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Automatic rollback......[%c] ", ++ pCtx->resp.GlobalCapabilities.bitField.autRollback ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Self test...............[%c] ", ++ pCtx->resp.GlobalCapabilities.bitField.ipmcSelftestCap ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Upgrade timeout.........[%d sec] ", ++ pCtx->resp.upgradeTimeout*5); ++ lprintf(LOG_NOTICE, "Self test timeout.......[%d sec] ", ++ pCtx->resp.selftestTimeout*5); ++ lprintf(LOG_NOTICE, "Rollback timeout........[%d sec] ", ++ pCtx->resp.rollbackTimeout*5); ++ lprintf(LOG_NOTICE, "Inaccessibility timeout.[%d sec] \n", ++ pCtx->resp.inaccessTimeout*5); ++ } ++ return HPMFWUPG_SUCCESS; + } + +- +-int HpmfwupgGetComponentProperties(struct ipmi_intf *intf, struct HpmfwupgGetComponentPropertiesCtx* pCtx) ++int ++HpmfwupgGetComponentProperties(struct ipmi_intf *intf, ++ struct HpmfwupgGetComponentPropertiesCtx *pCtx) + { +- int rc = HPMFWUPG_SUCCESS; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- +- pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_PICMG; +- req.msg.cmd = HPMFWUPG_GET_COMPONENT_PROPERTIES; +- req.msg.data = (unsigned char*)&pCtx->req; ++ int rc = HPMFWUPG_SUCCESS; ++ struct ipmi_rs * rsp; ++ struct ipmi_rq req; ++ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_PICMG; ++ req.msg.cmd = HPMFWUPG_GET_COMPONENT_PROPERTIES; ++ req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgGetComponentPropertiesReq); +- +- rsp = HpmfwupgSendCmd(intf, req, NULL); +- +- if ( rsp ) +- { +- if ( rsp->ccode == 0x00 ) +- { +- switch ( pCtx->req.selector ) +- { +- case HPMFWUPG_COMP_GEN_PROPERTIES: +- memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetGeneralPropResp)); +- if ( verbose ) +- { +- lprintf(LOG_NOTICE,"GENERAL PROPERTIES"); +- lprintf(LOG_NOTICE,"-------------------------------"); +- lprintf(LOG_NOTICE,"Payload cold reset req....[%c] ", pCtx->resp.Response.generalPropResp. +- GeneralCompProperties.bitfield.payloadColdReset ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Def. activation supported.[%c] ", pCtx->resp.Response.generalPropResp. +- GeneralCompProperties.bitfield.deferredActivation ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Comparison supported......[%c] ", pCtx->resp.Response.generalPropResp. +- GeneralCompProperties.bitfield.comparisonSupport ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Preparation supported.....[%c] ", pCtx->resp.Response.generalPropResp. +- GeneralCompProperties.bitfield.preparationSupport ? 'y' : 'n'); +- lprintf(LOG_NOTICE,"Rollback supported........[%c] \n", pCtx->resp.Response.generalPropResp. +- GeneralCompProperties.bitfield.rollbackBackup ? 'y' : 'n'); +- } +- break; +- case HPMFWUPG_COMP_CURRENT_VERSION: +- memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetCurrentVersionResp)); +- if ( verbose ) +- { +- lprintf(LOG_NOTICE,"Current Version: "); +- lprintf(LOG_NOTICE," Major: %d", pCtx->resp.Response.currentVersionResp.currentVersion[0]); +- lprintf(LOG_NOTICE," Minor: %x", pCtx->resp.Response.currentVersionResp.currentVersion[1]); +- lprintf(LOG_NOTICE," Aux : %03d %03d %03d %03d\n", pCtx->resp.Response.currentVersionResp.currentVersion[2], +- pCtx->resp.Response.currentVersionResp.currentVersion[3], +- pCtx->resp.Response.currentVersionResp.currentVersion[4], +- pCtx->resp.Response.currentVersionResp.currentVersion[5]); +- } +- break; +- case HPMFWUPG_COMP_DESCRIPTION_STRING: +- memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetDescStringResp)); +- if ( verbose ) +- { +- lprintf(LOG_NOTICE,"Description string: %s\n", pCtx->resp.Response.descStringResp.descString); +- } +- break; +- case HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION: +- memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetRollbackFwVersionResp)); +- if ( verbose ) +- { +- lprintf(LOG_NOTICE,"Rollback FW Version: "); +- lprintf(LOG_NOTICE," Major: %d", pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[0]); +- lprintf(LOG_NOTICE," Minor: %x", pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[1]); +- lprintf(LOG_NOTICE," Aux : %03d %03d %03d %03d\n", pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[2], +- pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[3], +- pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[4], +- pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[5]); +- } +- break; +- case HPMFWUPG_COMP_DEFERRED_FIRMWARE_VERSION: +- memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetDeferredFwVersionResp)); +- if ( verbose ) +- { +- lprintf(LOG_NOTICE,"Deferred FW Version: "); +- lprintf(LOG_NOTICE," Major: %d", pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[0]); +- lprintf(LOG_NOTICE," Minor: %x", pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[1]); +- lprintf(LOG_NOTICE," Aux : %03d %03d %03d %03d\n", pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[2], +- pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[3], +- pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[4], +- pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[5]); +- } +- break; +- // OEM Properties command +- case HPMFWUPG_COMP_OEM_PROPERTIES: +- memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetOemProperties)); +- if ( verbose ) +- { +- unsigned char i = 0; +- lprintf(LOG_NOTICE,"OEM Properties: "); +- for (i=0; i < HPMFWUPG_OEM_LENGTH; i++) +- { +- lprintf(LOG_NOTICE," 0x%x ", pCtx->resp.Response.oemProperties.oemRspData[i]); +- } +- } +- break; +- default: +- lprintf(LOG_NOTICE,"Unsupported component selector"); +- rc = HPMFWUPG_ERROR; +- break; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error getting component properties"); +- lprintf(LOG_NOTICE,"compcode=0x%x: %s", +- rsp->ccode, +- val2str(rsp->ccode, completion_code_vals)); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error getting component properties\n"); +- rc = HPMFWUPG_ERROR; +- } +- +- +- return rc; ++ rsp = HpmfwupgSendCmd(intf, req, NULL); ++ if (rsp == NULL) { ++ lprintf(LOG_NOTICE, ++ "Error getting component properties\n"); ++ return HPMFWUPG_ERROR; ++ } ++ if (rsp->ccode != 0x00) { ++ lprintf(LOG_NOTICE, ++ "Error getting component properties"); ++ lprintf(LOG_NOTICE, ++ "compcode=0x%x: %s", ++ rsp->ccode, ++ val2str(rsp->ccode, completion_code_vals)); ++ return HPMFWUPG_ERROR; ++ } ++ switch (pCtx->req.selector) { ++ case HPMFWUPG_COMP_GEN_PROPERTIES: ++ memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetGeneralPropResp)); ++ if (verbose) { ++ lprintf(LOG_NOTICE, "GENERAL PROPERTIES"); ++ lprintf(LOG_NOTICE, "-------------------------------"); ++ lprintf(LOG_NOTICE, "Payload cold reset req....[%c] ", ++ pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.payloadColdReset ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Def. activation supported.[%c] ", ++ pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.deferredActivation ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Comparison supported......[%c] ", ++ pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.comparisonSupport ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Preparation supported.....[%c] ", ++ pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.preparationSupport ? 'y' : 'n'); ++ lprintf(LOG_NOTICE, "Rollback supported........[%c] \n", ++ pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.rollbackBackup ? 'y' : 'n'); ++ } ++ break; ++ case HPMFWUPG_COMP_CURRENT_VERSION: ++ memcpy(&pCtx->resp, rsp->data, ++ sizeof(struct HpmfwupgGetCurrentVersionResp)); ++ if (verbose) { ++ lprintf(LOG_NOTICE, "Current Version: "); ++ lprintf(LOG_NOTICE, " Major: %d", ++ pCtx->resp.Response.currentVersionResp.currentVersion[0]); ++ lprintf(LOG_NOTICE, " Minor: %x", ++ pCtx->resp.Response.currentVersionResp.currentVersion[1]); ++ lprintf(LOG_NOTICE, " Aux : %03d %03d %03d %03d\n", ++ pCtx->resp.Response.currentVersionResp.currentVersion[2], ++ pCtx->resp.Response.currentVersionResp.currentVersion[3], ++ pCtx->resp.Response.currentVersionResp.currentVersion[4], ++ pCtx->resp.Response.currentVersionResp.currentVersion[5]); ++ } ++ break; ++ case HPMFWUPG_COMP_DESCRIPTION_STRING: ++ memcpy(&pCtx->resp, rsp->data, ++ sizeof(struct HpmfwupgGetDescStringResp)); ++ if (verbose) { ++ char descString[HPMFWUPG_DESC_STRING_LENGTH + 1]; ++ memcpy(descString, ++ pCtx->resp.Response.descStringResp.descString, ++ HPMFWUPG_DESC_STRING_LENGTH); ++ descString[HPMFWUPG_DESC_STRING_LENGTH] = '\0'; ++ lprintf(LOG_NOTICE, ++ "Description string: %s\n", ++ descString); ++ } ++ break; ++ case HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION: ++ memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetRollbackFwVersionResp)); ++ if (verbose) { ++ lprintf(LOG_NOTICE, "Rollback FW Version: "); ++ lprintf(LOG_NOTICE, " Major: %d", ++ pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[0]); ++ lprintf(LOG_NOTICE, " Minor: %x", ++ pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[1]); ++ lprintf(LOG_NOTICE, " Aux : %03d %03d %03d %03d\n", ++ pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[2], ++ pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[3], ++ pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[4], ++ pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[5]); ++ } ++ break; ++ case HPMFWUPG_COMP_DEFERRED_FIRMWARE_VERSION: ++ memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetDeferredFwVersionResp)); ++ if (verbose) { ++ lprintf(LOG_NOTICE, "Deferred FW Version: "); ++ lprintf(LOG_NOTICE, " Major: %d", ++ pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[0]); ++ lprintf(LOG_NOTICE, " Minor: %x", ++ pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[1]); ++ lprintf(LOG_NOTICE, " Aux : %03d %03d %03d %03d\n", ++ pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[2], ++ pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[3], ++ pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[4], ++ pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[5]); ++ } ++ break; ++ case HPMFWUPG_COMP_OEM_PROPERTIES: ++ /* OEM Properties command */ ++ memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetOemProperties)); ++ if (verbose) { ++ unsigned char i = 0; ++ lprintf(LOG_NOTICE,"OEM Properties: "); ++ for (i=0; i < HPMFWUPG_OEM_LENGTH; i++) { ++ lprintf(LOG_NOTICE, " 0x%x ", ++ pCtx->resp.Response.oemProperties.oemRspData[i]); ++ } ++ } ++ break; ++ default: ++ lprintf(LOG_NOTICE,"Unsupported component selector"); ++ rc = HPMFWUPG_ERROR; ++ break; ++ } ++ return rc; + } + +-int HpmfwupgAbortUpgrade(struct ipmi_intf *intf, struct HpmfwupgAbortUpgradeCtx* pCtx) ++int ++HpmfwupgAbortUpgrade(struct ipmi_intf *intf, ++ struct HpmfwupgAbortUpgradeCtx *pCtx) + { +- int rc = HPMFWUPG_SUCCESS; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- +- pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_PICMG; +- req.msg.cmd = HPMFWUPG_ABORT_UPGRADE; +- req.msg.data = (unsigned char*)&pCtx->req; ++ int rc = HPMFWUPG_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_PICMG; ++ req.msg.cmd = HPMFWUPG_ABORT_UPGRADE; ++ req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgAbortUpgradeReq); +- +- rsp = HpmfwupgSendCmd(intf, req, NULL); +- +- if ( rsp ) +- { +- if ( rsp->ccode != 0x00 ) +- { +- lprintf(LOG_NOTICE,"Error aborting upgrade"); +- lprintf(LOG_NOTICE,"compcode=0x%x: %s", +- rsp->ccode, +- val2str(rsp->ccode, completion_code_vals)); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error aborting upgrade\n"); +- rc = HPMFWUPG_ERROR; +- } +- return rc; ++ rsp = HpmfwupgSendCmd(intf, req, NULL); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error - aborting upgrade."); ++ return HPMFWUPG_ERROR; ++ } ++ if (rsp->ccode != 0x00) { ++ lprintf(LOG_ERR, "Error aborting upgrade"); ++ lprintf(LOG_ERR, "compcode=0x%x: %s", ++ rsp->ccode, ++ val2str(rsp->ccode, completion_code_vals)); ++ rc = HPMFWUPG_ERROR; ++ } ++ return rc; + } + +-int HpmfwupgInitiateUpgradeAction(struct ipmi_intf *intf, struct HpmfwupgInitiateUpgradeActionCtx* pCtx, +- struct HpmfwupgUpgradeCtx* pFwupgCtx) ++int ++HpmfwupgInitiateUpgradeAction(struct ipmi_intf *intf, ++ struct HpmfwupgInitiateUpgradeActionCtx *pCtx, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx) + { +- int rc = HPMFWUPG_SUCCESS; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- +- pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_PICMG; +- req.msg.cmd = HPMFWUPG_INITIATE_UPGRADE_ACTION; +- req.msg.data = (unsigned char*)&pCtx->req; ++ int rc = HPMFWUPG_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_PICMG; ++ req.msg.cmd = HPMFWUPG_INITIATE_UPGRADE_ACTION; ++ req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgInitiateUpgradeActionReq); +- +- rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); +- +- if ( rsp ) +- { +- /* Long duration command handling */ +- if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS ) +- { +- rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); +- } +- else if ( rsp->ccode != 0x00 ) +- { +- lprintf(LOG_NOTICE,"Error initiating upgrade action"); +- lprintf(LOG_NOTICE,"compcode=0x%x: %s", +- rsp->ccode, +- val2str(rsp->ccode, completion_code_vals)); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error initiating upgrade action\n"); +- rc = HPMFWUPG_ERROR; +- } +- +- return rc; ++ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error initiating upgrade action."); ++ return HPMFWUPG_ERROR; ++ } ++ /* Long duration command handling */ ++ if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) { ++ rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); ++ } else if (rsp->ccode != 0x00) { ++ lprintf(LOG_NOTICE,"Error initiating upgrade action"); ++ lprintf(LOG_NOTICE, "compcode=0x%x: %s", ++ rsp->ccode, ++ val2str(rsp->ccode, completion_code_vals)); ++ rc = HPMFWUPG_ERROR; ++ } ++ return rc; + } + +-int HpmfwupgUploadFirmwareBlock(struct ipmi_intf *intf, struct HpmfwupgUploadFirmwareBlockCtx* pCtx, +- struct HpmfwupgUpgradeCtx* pFwupgCtx, int count +- ,unsigned int *imageOffset, unsigned int *blockLength ) ++int ++HpmfwupgUploadFirmwareBlock(struct ipmi_intf *intf, ++ struct HpmfwupgUploadFirmwareBlockCtx *pCtx, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx, int count, ++ unsigned int *imageOffset, unsigned int *blockLength) + { +- int rc = HPMFWUPG_SUCCESS; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- +- pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_PICMG; +- req.msg.cmd = HPMFWUPG_UPLOAD_FIRMWARE_BLOCK; +- req.msg.data = (unsigned char*)&pCtx->req; +- /* 2 is the size of the upload struct - data */ +- req.msg.data_len = 2 + count; +- +- rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); +- +- if ( rsp ) +- { +- if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS || +- rsp->ccode == 0x00 ) +- { +- /* +- * We need to check if the response also contains the next upload firmware offset +- * and the firmware length in its response - These are optional but very vital +- */ +- if ( rsp->data_len > 1 ) +- { +- /* +- * If the response data length is greater than 1 it should contain both the +- * the Section offset and section length. Because we cannot just have +- * Section offset without section length so the length should be 9 +- */ +- if ( rsp->data_len == 9 ) +- { +- /* rsp->data[1] - LSB rsp->data[2] - rsp->data[3] = MSB */ +- *imageOffset = (rsp->data[4] << 24) + (rsp->data[3] << 16) + (rsp->data[2] << 8) + rsp->data[1]; +- *blockLength = (rsp->data[8] << 24) + (rsp->data[7] << 16) + (rsp->data[6] << 8) + rsp->data[5]; +- } +- else +- { +- /* +- * The Spec does not say much for this kind of errors where the +- * firmware returned only offset and length so currently returning it +- * as 0x82 - Internal CheckSum Error +- */ +- lprintf(LOG_NOTICE,"Error wrong rsp->datalen %d for Upload Firmware block command\n",rsp->data_len); +- rsp->ccode = HPMFWUPG_INT_CHECKSUM_ERROR; +- } +- } +- } +- /* Long duration command handling */ +- if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS ) +- { +- rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); +- } +- else if (rsp->ccode != 0x00) +- { +- /* +- * PATCH --> This validation is to handle retryables errors codes on IPMB bus. +- * This will be fixed in the next release of open ipmi and this +- * check will have to be removed. (Buggy version = 39) +- */ +- if ( HPMFWUPG_IS_RETRYABLE(rsp->ccode) ) +- { +- lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected"); +- rc = HPMFWUPG_UPLOAD_RETRY; +- } +- /* +- * If completion code = 0xc7, we will retry with a reduced buffer length. +- * Do not print error. +- */ +- else if ( rsp->ccode == IPMI_CC_REQ_DATA_INV_LENGTH ) +- { +- rc = HPMFWUPG_UPLOAD_BLOCK_LENGTH; +- } +- else +- { +- lprintf(LOG_NOTICE,"Error uploading firmware block"); +- lprintf(LOG_NOTICE,"compcode=0x%x: %s", +- rsp->ccode, +- val2str(rsp->ccode, completion_code_vals)); +- rc = HPMFWUPG_ERROR; +- } +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error uploading firmware block\n"); +- rc = HPMFWUPG_ERROR; +- } +- +- return rc; ++ int rc = HPMFWUPG_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ pCtx->req->picmgId = HPMFWUPG_PICMG_IDENTIFIER; ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_PICMG; ++ req.msg.cmd = HPMFWUPG_UPLOAD_FIRMWARE_BLOCK; ++ req.msg.data = (unsigned char *)pCtx->req; ++ /* 2 is the size of the upload struct - data */ ++ req.msg.data_len = 2 + count; ++ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); ++ if (rsp == NULL) { ++ lprintf(LOG_NOTICE, "Error uploading firmware block."); ++ return HPMFWUPG_ERROR; ++ } ++ if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS ++ || rsp->ccode == 0x00) { ++ /* ++ * We need to check if the response also contains the next upload firmware offset ++ * and the firmware length in its response - These are optional but very vital ++ */ ++ if (rsp->data_len > 1) { ++ /* ++ * If the response data length is greater than 1 it should contain both the ++ * the Section offset and section length. Because we cannot just have ++ * Section offset without section length so the length should be 9 ++ */ ++ if (rsp->data_len == 9) { ++ /* rsp->data[1] - LSB rsp->data[2] - rsp->data[3] = MSB */ ++ *imageOffset = (rsp->data[4] << 24) + (rsp->data[3] << 16) + (rsp->data[2] << 8) + rsp->data[1]; ++ *blockLength = (rsp->data[8] << 24) + (rsp->data[7] << 16) + (rsp->data[6] << 8) + rsp->data[5]; ++ } else { ++ /* ++ * The Spec does not say much for this kind of errors where the ++ * firmware returned only offset and length so currently returning it ++ * as 0x82 - Internal CheckSum Error ++ */ ++ lprintf(LOG_NOTICE, ++ "Error wrong rsp->datalen %d for Upload Firmware block command\n", ++ rsp->data_len); ++ rsp->ccode = HPMFWUPG_INT_CHECKSUM_ERROR; ++ } ++ } ++ } ++ /* Long duration command handling */ ++ if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) { ++ rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); ++ } else if (rsp->ccode != 0x00) { ++ /* PATCH --> This validation is to handle retryables errors codes on IPMB bus. ++ * This will be fixed in the next release of open ipmi and this ++ * check will have to be removed. (Buggy version = 39) ++ */ ++ if (HPMFWUPG_IS_RETRYABLE(rsp->ccode)) { ++ lprintf(LOG_DEBUG, "HPM: [PATCH]Retryable error detected"); ++ rc = HPMFWUPG_UPLOAD_RETRY; ++ } else if (rsp->ccode == IPMI_CC_REQ_DATA_INV_LENGTH || ++ rsp->ccode == IPMI_CC_REQ_DATA_FIELD_EXCEED) { ++ /* If completion code = 0xc7(0xc8), we will retry with a reduced buffer length. ++ * Do not print error. ++ */ ++ rc = HPMFWUPG_UPLOAD_BLOCK_LENGTH; ++ } else { ++ lprintf(LOG_ERR, "Error uploading firmware block"); ++ lprintf(LOG_ERR, "compcode=0x%x: %s", ++ rsp->ccode, ++ val2str(rsp->ccode, ++ completion_code_vals)); ++ rc = HPMFWUPG_ERROR; ++ } ++ } ++ return rc; + } + +-int HpmfwupgFinishFirmwareUpload(struct ipmi_intf *intf, struct HpmfwupgFinishFirmwareUploadCtx* pCtx, +- struct HpmfwupgUpgradeCtx* pFwupgCtx) ++int ++HpmfwupgFinishFirmwareUpload(struct ipmi_intf *intf, ++ struct HpmfwupgFinishFirmwareUploadCtx *pCtx, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx, int option) + { +- int rc = HPMFWUPG_SUCCESS; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- +- pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_PICMG; +- req.msg.cmd = HPMFWUPG_FINISH_FIRMWARE_UPLOAD; +- req.msg.data = (unsigned char*)&pCtx->req; ++ int rc = HPMFWUPG_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_PICMG; ++ req.msg.cmd = HPMFWUPG_FINISH_FIRMWARE_UPLOAD; ++ req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgFinishFirmwareUploadReq); +- +- rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); +- +- if ( rsp ) +- { +- /* Long duration command handling */ +- if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS ) +- { +- rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); +- } +- else if ( rsp->ccode != IPMI_CC_OK ) +- { +- lprintf(LOG_NOTICE,"Error finishing firmware upload"); +- lprintf(LOG_NOTICE,"compcode=0x%x: %s", +- rsp->ccode, +- val2str(rsp->ccode, completion_code_vals)); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error fininshing firmware upload\n"); +- rc = HPMFWUPG_ERROR; +- } +- +- return rc; ++ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error fininshing firmware upload."); ++ return HPMFWUPG_ERROR; ++ } ++ /* Long duration command handling */ ++ if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) { ++ rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); ++ } else if ((option & COMPARE_MODE) && rsp->ccode == 0x83) { ++ printf("| |Component's active copy doesn't match the upgrade image |\n"); ++ } else if ((option & COMPARE_MODE) && rsp->ccode == IPMI_CC_OK) { ++ printf("| |Comparison passed |\n"); ++ } else if ( rsp->ccode != IPMI_CC_OK ) { ++ lprintf(LOG_ERR, "Error finishing firmware upload"); ++ lprintf(LOG_ERR, "compcode=0x%x: %s", ++ rsp->ccode, ++ val2str(rsp->ccode, completion_code_vals)); ++ rc = HPMFWUPG_ERROR; ++ } ++ return rc; + } + +-int HpmfwupgActivateFirmware(struct ipmi_intf *intf, struct HpmfwupgActivateFirmwareCtx* pCtx, +- struct HpmfwupgUpgradeCtx* pFwupgCtx) ++int ++HpmfwupgActivateFirmware(struct ipmi_intf *intf, ++ struct HpmfwupgActivateFirmwareCtx *pCtx, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx) + { +- int rc = HPMFWUPG_SUCCESS; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- +- pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_PICMG; +- req.msg.cmd = HPMFWUPG_ACTIVATE_FIRMWARE; +- req.msg.data = (unsigned char*)&pCtx->req; +- req.msg.data_len = sizeof(struct HpmfwupgActivateFirmwareReq) - +- (!pCtx->req.rollback_override ? 1 : 0); +- +- rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); +- +- if ( rsp ) +- { +- /* Long duration command handling */ +- if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS ) +- { +- printf("Waiting firmware activation..."); +- fflush(stdout); +- +- rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); +- +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- lprintf(LOG_NOTICE,"OK"); +- } +- else +- { +- lprintf(LOG_NOTICE,"Failed"); +- } +- } +- else if ( rsp->ccode != IPMI_CC_OK ) +- { +- lprintf(LOG_NOTICE,"Error activating firmware"); +- lprintf(LOG_NOTICE,"compcode=0x%x: %s", +- rsp->ccode, +- val2str(rsp->ccode, completion_code_vals)); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error activating firmware\n"); +- rc = HPMFWUPG_ERROR; +- } +- +- return rc; ++ int rc = HPMFWUPG_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_PICMG; ++ req.msg.cmd = HPMFWUPG_ACTIVATE_FIRMWARE; ++ req.msg.data = (unsigned char*)&pCtx->req; ++ req.msg.data_len = sizeof(struct HpmfwupgActivateFirmwareReq) ++ - (!pCtx->req.rollback_override ? 1 : 0); ++ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error activating firmware."); ++ return HPMFWUPG_ERROR; ++ } ++ /* Long duration command handling */ ++ if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) { ++ printf("Waiting firmware activation..."); ++ fflush(stdout); ++ rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); ++ if (rc == HPMFWUPG_SUCCESS) { ++ lprintf(LOG_NOTICE, "OK"); ++ } else { ++ lprintf(LOG_NOTICE, "Failed"); ++ } ++ } else if (rsp->ccode != IPMI_CC_OK) { ++ lprintf(LOG_ERR, "Error activating firmware"); ++ lprintf(LOG_ERR, "compcode=0x%x: %s", ++ rsp->ccode, ++ val2str(rsp->ccode, completion_code_vals)); ++ rc = HPMFWUPG_ERROR; ++ } ++ return rc; + } + +-int HpmfwupgGetUpgradeStatus(struct ipmi_intf *intf, +- struct HpmfwupgGetUpgradeStatusCtx *pCtx, +- struct HpmfwupgUpgradeCtx *pFwupgCtx, +- int silent) ++int ++HpmfwupgGetUpgradeStatus(struct ipmi_intf *intf, ++ struct HpmfwupgGetUpgradeStatusCtx *pCtx, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx, ++ int silent) + { +- int rc = HPMFWUPG_SUCCESS; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- ++ int rc = HPMFWUPG_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; +- + memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_PICMG; +- req.msg.cmd = HPMFWUPG_GET_UPGRADE_STATUS; +- req.msg.data = (unsigned char*)&pCtx->req; ++ req.msg.netfn = IPMI_NETFN_PICMG; ++ req.msg.cmd = HPMFWUPG_GET_UPGRADE_STATUS; ++ req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgGetUpgradeStatusReq); +- + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); +- if (!rsp){ ++ if (!rsp) { + lprintf(LOG_NOTICE, +- "Error getting upgrade status. Failed to get response."); ++ "Error getting upgrade status. Failed to get response."); + return HPMFWUPG_ERROR; + } +- +- if ( rsp->ccode == 0x00 ) { ++ if (rsp->ccode == 0x00) { + memcpy(&pCtx->resp, rsp->data, +- sizeof(struct HpmfwupgGetUpgradeStatusResp)); +- if (!silent) +- { +- lprintf(LOG_NOTICE,"Upgrade status:"); +- lprintf(LOG_NOTICE," Command in progress: %x", +- pCtx->resp.cmdInProcess); +- lprintf(LOG_NOTICE," Last command completion code: %x", +- pCtx->resp.lastCmdCompCode); +- } +- } else if ( HPMFWUPG_IS_RETRYABLE(rsp->ccode) ) { +- /* +- * PATCH --> This validation is to handle retryable errors ++ sizeof(struct HpmfwupgGetUpgradeStatusResp)); ++ if (!silent) { ++ lprintf(LOG_NOTICE, "Upgrade status:"); ++ lprintf(LOG_NOTICE, ++ " Command in progress: %x", ++ pCtx->resp.cmdInProcess); ++ lprintf(LOG_NOTICE, ++ " Last command completion code: %x", ++ pCtx->resp.lastCmdCompCode); ++ } ++ } else if (HPMFWUPG_IS_RETRYABLE(rsp->ccode)) { ++ /* PATCH --> This validation is to handle retryable errors + * codes on the IPMB bus. + * This will be fixed in the next release of + * open ipmi and this check can be removed. + * (Buggy version = 39) + */ +- if (!silent) +- { +- lprintf(LOG_DEBUG,"HPM: Retryable error detected"); +- } ++ if (!silent) { ++ lprintf(LOG_DEBUG, "HPM: Retryable error detected"); ++ } + pCtx->resp.lastCmdCompCode = HPMFWUPG_COMMAND_IN_PROGRESS; + } else { +- lprintf(LOG_NOTICE,"Error getting upgrade status"); +- lprintf(LOG_NOTICE,"compcode=0x%x: %s", +- rsp->ccode, +- val2str(rsp->ccode, completion_code_vals)); ++ lprintf(LOG_NOTICE, "Error getting upgrade status"); ++ lprintf(LOG_NOTICE, "compcode=0x%x: %s", rsp->ccode, ++ val2str(rsp->ccode, completion_code_vals)); + return HPMFWUPG_ERROR; + } +- + return HPMFWUPG_SUCCESS; + } + +-int HpmfwupgManualFirmwareRollback(struct ipmi_intf *intf, struct HpmfwupgManualFirmwareRollbackCtx* pCtx, +- struct HpmfwupgUpgradeCtx* pFwupgCtx) +-{ +- int rc = HPMFWUPG_SUCCESS; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- +- pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_PICMG; +- req.msg.cmd = HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK; +- req.msg.data = (unsigned char*)&pCtx->req; ++int ++HpmfwupgManualFirmwareRollback(struct ipmi_intf *intf, ++ struct HpmfwupgManualFirmwareRollbackCtx *pCtx) ++{ ++ struct HpmfwupgUpgradeCtx fwupgCtx; ++ struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; ++ int rc = HPMFWUPG_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ /* prepare fake upgrade context */ ++ memset(&fwupgCtx, 0, sizeof (fwupgCtx)); ++ verbose--; ++ rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd); ++ verbose++; ++ if (rc != HPMFWUPG_SUCCESS) { ++ return rc; ++ } ++ memcpy(&fwupgCtx.targetCap, &targetCapCmd.resp, sizeof(targetCapCmd.resp)); ++ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_PICMG; ++ req.msg.cmd = HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK; ++ req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgManualFirmwareRollbackReq); +- +- rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); +- +- if ( rsp ) +- { +- /* Long duration command handling */ +- if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS ) +- { +- struct HpmfwupgQueryRollbackStatusCtx resCmd; +- printf("Waiting firmware rollback..."); +- fflush(stdout); +- rc = HpmfwupgQueryRollbackStatus(intf, &resCmd, pFwupgCtx); +- } +- else if ( rsp->ccode != 0x00 ) +- { +- lprintf(LOG_NOTICE,"Error sending manual rollback"); +- lprintf(LOG_NOTICE,"compcode=0x%x: %s", +- rsp->ccode, +- val2str(rsp->ccode, completion_code_vals)); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error sending manual rollback\n"); +- rc = HPMFWUPG_ERROR; +- } +- return rc; ++ rsp = HpmfwupgSendCmd(intf, req, &fwupgCtx); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error sending manual rollback."); ++ return HPMFWUPG_ERROR; ++ } ++ /* Long duration command handling */ ++ if (rsp->ccode == IPMI_CC_OK ++ || rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) { ++ struct HpmfwupgQueryRollbackStatusCtx resCmd; ++ printf("Waiting firmware rollback..."); ++ fflush(stdout); ++ rc = HpmfwupgQueryRollbackStatus(intf, &resCmd, &fwupgCtx); ++ } else if ( rsp->ccode != 0x00 ) { ++ lprintf(LOG_ERR, "Error sending manual rollback"); ++ lprintf(LOG_ERR, "compcode=0x%x: %s", ++ rsp->ccode, ++ val2str(rsp->ccode, completion_code_vals)); ++ rc = HPMFWUPG_ERROR; ++ } ++ return rc; + } + +-int HpmfwupgQueryRollbackStatus(struct ipmi_intf *intf, struct HpmfwupgQueryRollbackStatusCtx* pCtx, +- struct HpmfwupgUpgradeCtx* pFwupgCtx) ++int ++HpmfwupgQueryRollbackStatus(struct ipmi_intf *intf, ++ struct HpmfwupgQueryRollbackStatusCtx *pCtx, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx) + { +- int rc = HPMFWUPG_SUCCESS; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- unsigned int rollbackTimeout = 0; +- unsigned int timeoutSec1, timeoutSec2; +- +- pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_PICMG; +- req.msg.cmd = HPMFWUPG_QUERY_ROLLBACK_STATUS; +- req.msg.data = (unsigned char*)&pCtx->req; ++ int rc = HPMFWUPG_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ unsigned int rollbackTimeout = 0; ++ unsigned int timeoutSec1, timeoutSec2; ++ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_PICMG; ++ req.msg.cmd = HPMFWUPG_QUERY_ROLLBACK_STATUS; ++ req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgQueryRollbackStatusReq); +- +- /* +- * If we are not in upgrade context, we use default timeout values +- */ +- if ( pFwupgCtx != NULL ) +- { +- rollbackTimeout = pFwupgCtx->targetCap.rollbackTimeout*5; +- } +- else +- { +- struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; +- verbose--; +- rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd); +- verbose++; +- if ( rc == HPMFWUPG_SUCCESS ) +- { +- rollbackTimeout = targetCapCmd.resp.rollbackTimeout *5; +- } +- else +- { +- rollbackTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; +- } +- } +- +- /* Poll rollback status until completion or timeout */ +- timeoutSec1 = time(NULL); +- timeoutSec2 = time(NULL); +- do +- { +- /* Must wait at least 100 ms between status requests */ +- usleep(100000); +- rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); +- /* +- * PATCH --> This validation is to handle retryables errors codes on IPMB bus. +- * This will be fixed in the next release of open ipmi and this +- * check will have to be removed. (Buggy version = 39) +- */ +- if ( rsp ) +- { +- if ( HPMFWUPG_IS_RETRYABLE(rsp->ccode) ) +- { +- lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected"); +- rsp->ccode = HPMFWUPG_COMMAND_IN_PROGRESS; +- } +- } +- timeoutSec2 = time(NULL); +- +- }while( rsp && +- ((rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) || +- (rsp->ccode == IPMI_CC_TIMEOUT)) && +- (timeoutSec2 - timeoutSec1 < rollbackTimeout ) ); +- +- if ( rsp ) +- { +- if ( rsp->ccode == 0x00 ) +- { +- memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgQueryRollbackStatusResp)); +- if ( pCtx->resp.rollbackComp.ComponentBits.byte != 0 ) +- { +- /* Rollback occured */ +- lprintf(LOG_NOTICE,"Rollback occured on component mask: 0x%02x", +- pCtx->resp.rollbackComp.ComponentBits.byte); +- } +- else +- { +- lprintf(LOG_NOTICE,"No Firmware rollback occured"); +- } +- } +- else if ( rsp->ccode == 0x81 ) +- { +- lprintf(LOG_NOTICE,"Rollback failed on component mask: 0x%02x", +- pCtx->resp.rollbackComp.ComponentBits.byte); +- rc = HPMFWUPG_ERROR; +- } +- else +- { +- lprintf(LOG_NOTICE,"Error getting rollback status"); +- lprintf(LOG_NOTICE,"compcode=0x%x: %s", +- rsp->ccode, +- val2str(rsp->ccode, completion_code_vals)); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error getting upgrade status\n"); +- rc = HPMFWUPG_ERROR; +- } +- +- return rc; ++ /* If we are not in upgrade context, we use default timeout values */ ++ if (pFwupgCtx != NULL) { ++ struct HpmfwupgImageHeader *pImageHeader; ++ if (pFwupgCtx->pImageData) { ++ pImageHeader = (struct HpmfwupgImageHeader*)pFwupgCtx->pImageData; ++ rollbackTimeout = pImageHeader->rollbackTimeout; ++ } else { ++ rollbackTimeout = 0; ++ } ++ /* Use the greater of the two timeouts (header and target caps) */ ++ rollbackTimeout = MAX(rollbackTimeout, ++ pFwupgCtx->targetCap.rollbackTimeout) * 5; ++ } else { ++ rollbackTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; ++ } ++ /* Poll rollback status until completion or timeout */ ++ timeoutSec1 = time(NULL); ++ timeoutSec2 = time(NULL); ++ do { ++ /* Must wait at least 100 ms between status requests */ ++ usleep(100000); ++ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); ++ /* PATCH --> This validation is to handle retryables errors codes on IPMB bus. ++ * This will be fixed in the next release of open ipmi and this ++ * check will have to be removed. (Buggy version = 39) ++ */ ++ if (rsp) { ++ if (HPMFWUPG_IS_RETRYABLE(rsp->ccode)) { ++ lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected"); ++ rsp->ccode = HPMFWUPG_COMMAND_IN_PROGRESS; ++ } ++ } ++ timeoutSec2 = time(NULL); ++ } while (rsp ++ && ((rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) ++ || (rsp->ccode == IPMI_CC_TIMEOUT)) ++ && (timeoutSec2 - timeoutSec1 < rollbackTimeout)); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error getting upgrade status."); ++ return HPMFWUPG_ERROR; ++ } ++ if (rsp->ccode == 0x00) { ++ memcpy(&pCtx->resp, rsp->data, ++ sizeof(struct HpmfwupgQueryRollbackStatusResp)); ++ if (pCtx->resp.rollbackComp.ComponentBits.byte != 0) { ++ /* Rollback occured */ ++ lprintf(LOG_NOTICE, ++ "Rollback occured on component mask: 0x%02x", ++ pCtx->resp.rollbackComp.ComponentBits.byte); ++ } else { ++ lprintf(LOG_NOTICE, ++ "No Firmware rollback occured"); ++ } ++ } else if (rsp->ccode == 0x81) { ++ lprintf(LOG_ERR, ++ "Rollback failed on component mask: 0x%02x", ++ pCtx->resp.rollbackComp.ComponentBits.byte); ++ rc = HPMFWUPG_ERROR; ++ } else { ++ lprintf(LOG_ERR, ++ "Error getting rollback status"); ++ lprintf(LOG_ERR, ++ "compcode=0x%x: %s", ++ rsp->ccode, ++ val2str(rsp->ccode, completion_code_vals)); ++ rc = HPMFWUPG_ERROR; ++ } ++ return rc; + } + +-int HpmfwupgQuerySelftestResult(struct ipmi_intf *intf, struct HpmfwupgQuerySelftestResultCtx* pCtx, +- struct HpmfwupgUpgradeCtx* pFwupgCtx) ++int ++HpmfwupgQuerySelftestResult(struct ipmi_intf *intf, struct HpmfwupgQuerySelftestResultCtx *pCtx, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx) + { +- int rc = HPMFWUPG_SUCCESS; +- struct ipmi_rs * rsp; +- struct ipmi_rq req; +- unsigned char selfTestTimeout = 0; +- unsigned int timeoutSec1, timeoutSec2; +- +- pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; +- +- /* +- * If we are not in upgrade context, we use default timeout values +- */ +- if ( pFwupgCtx != NULL ) +- { +- /* Getting selftest timeout from new image */ +- struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) +- pFwupgCtx->pImageData; +- selfTestTimeout = pImageHeader->selfTestTimeout; +- } +- else +- { +- selfTestTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; +- } +- +- memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_PICMG; +- req.msg.cmd = HPMFWUPG_QUERY_SELFTEST_RESULT; +- req.msg.data = (unsigned char*)&pCtx->req; ++ int rc = HPMFWUPG_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ unsigned char selfTestTimeout = 0; ++ unsigned int timeoutSec1, timeoutSec2; ++ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; ++ /* If we are not in upgrade context, we use default timeout values */ ++ if (pFwupgCtx != NULL) { ++ /* Getting selftest timeout from new image */ ++ struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*) ++ pFwupgCtx->pImageData; ++ selfTestTimeout = MAX(pImageHeader->selfTestTimeout, ++ pFwupgCtx->targetCap.selftestTimeout) * 5; ++ } else { ++ selfTestTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; ++ } ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_PICMG; ++ req.msg.cmd = HPMFWUPG_QUERY_SELFTEST_RESULT; ++ req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgQuerySelftestResultReq); +- +- +- /* Poll rollback status until completion or timeout */ +- timeoutSec1 = time(NULL); +- timeoutSec2 = time(NULL); +- do +- { +- /* Must wait at least 100 ms between status requests */ +- usleep(100000); +- rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); +- /* +- * PATCH --> This validation is to handle retryables errors codes on IPMB bus. +- * This will be fixed in the next release of open ipmi and this +- * check will have to be removed. (Buggy version = 39) +- */ +- if ( rsp ) +- { +- if ( HPMFWUPG_IS_RETRYABLE(rsp->ccode) ) +- { +- lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected"); +- rsp->ccode = HPMFWUPG_COMMAND_IN_PROGRESS; +- } +- } +- timeoutSec2 = time(NULL); +- +- }while( rsp && +- (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) && +- (timeoutSec2 - timeoutSec1 < selfTestTimeout ) ); +- +- if ( rsp ) +- { +- if ( rsp->ccode == 0x00 ) +- { +- memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgQuerySelftestResultResp)); +- if ( verbose ) +- { +- lprintf(LOG_NOTICE,"Self test results:"); +- lprintf(LOG_NOTICE,"Result1 = %x", pCtx->resp.result1); +- lprintf(LOG_NOTICE,"Result2 = %x", pCtx->resp.result2); +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error getting self test results"); +- lprintf(LOG_NOTICE,"compcode=0x%x: %s", +- rsp->ccode, +- val2str(rsp->ccode, completion_code_vals)); +- rc = HPMFWUPG_ERROR; +- } +- } +- else +- { +- lprintf(LOG_NOTICE,"Error getting upgrade status\n"); +- rc = HPMFWUPG_ERROR; +- } +- +- return rc; ++ /* Poll rollback status until completion or timeout */ ++ timeoutSec1 = time(NULL); ++ timeoutSec2 = time(NULL); ++ do { ++ /* Must wait at least 100 ms between status requests */ ++ usleep(100000); ++ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); ++ /* PATCH --> This validation is to handle retryables errors codes on IPMB bus. ++ * This will be fixed in the next release of open ipmi and this ++ * check will have to be removed. (Buggy version = 39) ++ */ ++ if (rsp) { ++ if (HPMFWUPG_IS_RETRYABLE(rsp->ccode)) { ++ lprintf(LOG_DEBUG, ++ "HPM: [PATCH]Retryable error detected"); ++ rsp->ccode = HPMFWUPG_COMMAND_IN_PROGRESS; ++ } ++ } ++ timeoutSec2 = time(NULL); ++ } while (rsp ++ && (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) ++ && (timeoutSec2 - timeoutSec1 < selfTestTimeout)); ++ if (rsp == NULL) { ++ lprintf(LOG_NOTICE, "Error getting upgrade status\n"); ++ return HPMFWUPG_ERROR; ++ } ++ if (rsp->ccode == 0x00) { ++ memcpy(&pCtx->resp, rsp->data, ++ sizeof(struct HpmfwupgQuerySelftestResultResp)); ++ if (verbose) { ++ lprintf(LOG_NOTICE, "Self test results:"); ++ lprintf(LOG_NOTICE, "Result1 = %x", ++ pCtx->resp.result1); ++ lprintf(LOG_NOTICE, "Result2 = %x", ++ pCtx->resp.result2); ++ } ++ } else { ++ lprintf(LOG_NOTICE, "Error getting self test results"); ++ lprintf(LOG_NOTICE, "compcode=0x%x: %s", ++ rsp->ccode, ++ val2str(rsp->ccode, completion_code_vals)); ++ rc = HPMFWUPG_ERROR; ++ } ++ return rc; + } + +-struct ipmi_rs * HpmfwupgSendCmd(struct ipmi_intf *intf, struct ipmi_rq req, +- struct HpmfwupgUpgradeCtx* pFwupgCtx ) +-{ +- struct ipmi_rs * rsp; +- unsigned int inaccessTimeout = 0, inaccessTimeoutCounter = 0; +- unsigned int upgradeTimeout = 0, upgradeTimeoutCounter = 0; +- unsigned int timeoutSec1, timeoutSec2; +- unsigned char retry = 0; +- +- /* +- * If we are not in upgrade context, we use default timeout values +- */ +- if ( pFwupgCtx != NULL ) +- { +- inaccessTimeout = pFwupgCtx->targetCap.inaccessTimeout*5; +- upgradeTimeout = pFwupgCtx->targetCap.upgradeTimeout*5; +- } +- else +- { +- /* keeping the inaccessTimeout to 60 seconds results in almost 2900 retries +- * So if the target is not available it will be retrying the command for 2900 +- * times which is not effecient -So reducing the Timout to 5 seconds which is +- * almost 200 retries if it continuously recieves 0xC3 as completion code. +- */ +- inaccessTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; +- upgradeTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; +- } +- +- timeoutSec1 = time(NULL); +- +- do +- { +- static unsigned char isValidSize = FALSE; +- rsp = intf->sendrecv(intf, &req); +- +- if( ( rsp == NULL ) ) +- { +- #define HPM_LAN_PACKET_RESIZE_LIMIT 6 +- +- if(strstr(intf->name,"lan")!= NULL) /* also covers lanplus */ +- { +- static int errorCount=0; +- static struct ipmi_rs fakeRsp; +- +- lprintf(LOG_DEBUG,"HPM: no response available"); +- lprintf(LOG_DEBUG,"HPM: the command may be rejected for " \ +- "security reasons"); +- +- if +- ( +- req.msg.netfn == IPMI_NETFN_PICMG +- && +- req.msg.cmd == HPMFWUPG_UPLOAD_FIRMWARE_BLOCK +- && +- errorCount < HPM_LAN_PACKET_RESIZE_LIMIT +- && +- (!isValidSize) +- ) +- { +- lprintf(LOG_DEBUG,"HPM: upload firmware block API called"); +- lprintf(LOG_DEBUG,"HPM: returning length error to force resize"); +- +- fakeRsp.ccode = IPMI_CC_REQ_DATA_INV_LENGTH; +- rsp = &fakeRsp; +- errorCount++; +- } +- else if +- ( +- req.msg.netfn == IPMI_NETFN_PICMG +- && +- ( req.msg.cmd == HPMFWUPG_ACTIVATE_FIRMWARE || +- req.msg.cmd == HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK ) +- ) +- { +- /* +- * rsp == NULL and command activate firmware or manual firmware +- * rollback most likely occurs when we have sent a firmware activation +- * request. Fake a command in progress response. +- */ +- lprintf(LOG_DEBUG,"HPM: activate/rollback firmware API called"); +- lprintf(LOG_DEBUG,"HPM: returning in progress to handle IOL session lost"); +- +- fakeRsp.ccode = HPMFWUPG_COMMAND_IN_PROGRESS; +- rsp = &fakeRsp; +- } +- else if +- ( +- req.msg.netfn == IPMI_NETFN_PICMG +- && +- ( req.msg.cmd == HPMFWUPG_QUERY_ROLLBACK_STATUS || +- req.msg.cmd == HPMFWUPG_GET_UPGRADE_STATUS ) +- ) +- { +- /* +- * rsp == NULL and command get upgrade status or query rollback +- * status most likely occurs when we are waiting for firmware +- * activation. Try to re-open the IOL session (re-open will work +- * once the IPMC recovers from firmware activation. +- */ +- +- lprintf(LOG_DEBUG,"HPM: upg/rollback status firmware API called"); +- lprintf(LOG_DEBUG,"HPM: try to re-open IOL session"); +- +- { +- /* force session re-open */ +- intf->opened = 0; +- intf->session->authtype = IPMI_SESSION_AUTHTYPE_NONE; +- intf->session->session_id = 0; +- intf->session->in_seq = 0; +- intf->session->out_seq = 0; +- intf->session->active = 0; +- intf->session->retry = 10; +- +- while +- ( +- intf->open(intf) == HPMFWUPG_ERROR +- && +- inaccessTimeoutCounter < inaccessTimeout +- ) +- { +- inaccessTimeoutCounter += (time(NULL) - timeoutSec1); +- timeoutSec1 = time(NULL); +- } +- /* Fake timeout to retry command */ +- fakeRsp.ccode = 0xc3; +- rsp = &fakeRsp; +- } +- } +- } +- } +- +- /* Handle inaccessibility timeout (rsp = NULL if IOL) */ +- if ( rsp == NULL || rsp->ccode == 0xff || rsp->ccode == 0xc3 || rsp->ccode == 0xd3 ) +- { +- if ( inaccessTimeoutCounter < inaccessTimeout ) +- { +- timeoutSec2 = time(NULL); +- if ( timeoutSec2 > timeoutSec1 ) +- { +- inaccessTimeoutCounter += timeoutSec2 - timeoutSec1; +- timeoutSec1 = time(NULL); +- } +- usleep(100000); +- retry = 1; +- } +- else +- { +- retry = 0; +- } +- } +- /* Handle node busy timeout */ +- else if ( rsp->ccode == 0xc0 ) +- { +- if ( upgradeTimeoutCounter < upgradeTimeout ) +- { +- timeoutSec2 = time(NULL); +- if ( timeoutSec2 > timeoutSec1 ) +- { +- timeoutSec1 = time(NULL); +- upgradeTimeoutCounter += timeoutSec2 - timeoutSec1; +- } +- usleep(100000); +- retry = 1; +- } +- else +- { +- retry = 0; +- } +- } +- else +- { +- #ifdef ENABLE_OPENIPMI_V39_PATCH +- if( rsp->ccode == IPMI_CC_OK ) +- { +- errorCount = 0 ; +- } +- #endif +- retry = 0; +- +- if +- ( +- req.msg.netfn == IPMI_NETFN_PICMG +- && +- req.msg.cmd == HPMFWUPG_UPLOAD_FIRMWARE_BLOCK +- && +- (!isValidSize) +- ) +- { +- lprintf(LOG_INFO,"Buffer length is now considered valid" ); +- +- isValidSize = TRUE; ++struct ipmi_rs * ++HpmfwupgSendCmd(struct ipmi_intf *intf, struct ipmi_rq req, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx) ++{ ++ struct ipmi_rs *rsp; ++ unsigned int inaccessTimeout = 0, inaccessTimeoutCounter = 0; ++ unsigned int upgradeTimeout = 0, upgradeTimeoutCounter = 0; ++ unsigned int timeoutSec1, timeoutSec2; ++ unsigned char retry = 0; ++ /* If we are not in upgrade context, we use default timeout values */ ++ if (pFwupgCtx != NULL) { ++ inaccessTimeout = pFwupgCtx->targetCap.inaccessTimeout*5; ++ upgradeTimeout = pFwupgCtx->targetCap.upgradeTimeout*5; ++ } else { ++ /* keeping the inaccessTimeout to 60 seconds results in almost 2900 retries ++ * So if the target is not available it will be retrying the command for 2900 ++ * times which is not effecient -So reducing the Timout to 5 seconds which is ++ * almost 200 retries if it continuously recieves 0xC3 as completion code. ++ */ ++ inaccessTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; ++ upgradeTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; + } +- } +- }while( retry ); +- return rsp; ++ timeoutSec1 = time(NULL); ++ do { ++ static unsigned char isValidSize = FALSE; ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ #define HPM_LAN_PACKET_RESIZE_LIMIT 6 ++ /* also covers lanplus */ ++ if (strstr(intf->name, "lan") != NULL) { ++ static int errorCount=0; ++ static struct ipmi_rs fakeRsp; ++ lprintf(LOG_DEBUG, ++ "HPM: no response available"); ++ lprintf(LOG_DEBUG, ++ "HPM: the command may be rejected for security reasons"); ++ if (req.msg.netfn == IPMI_NETFN_PICMG ++ && req.msg.cmd == HPMFWUPG_UPLOAD_FIRMWARE_BLOCK ++ && errorCount < HPM_LAN_PACKET_RESIZE_LIMIT ++ && (!isValidSize)) { ++ lprintf(LOG_DEBUG, ++ "HPM: upload firmware block API called"); ++ lprintf(LOG_DEBUG, ++ "HPM: returning length error to force resize"); ++ fakeRsp.ccode = IPMI_CC_REQ_DATA_INV_LENGTH; ++ rsp = &fakeRsp; ++ errorCount++; ++ } else if (req.msg.netfn == IPMI_NETFN_PICMG ++ && (req.msg.cmd == HPMFWUPG_ACTIVATE_FIRMWARE ++ || req.msg.cmd == HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK)) { ++ /* ++ * rsp == NULL and command activate firmware or manual firmware ++ * rollback most likely occurs when we have sent a firmware activation ++ * request. Fake a command in progress response. ++ */ ++ lprintf(LOG_DEBUG, ++ "HPM: activate/rollback firmware API called"); ++ lprintf(LOG_DEBUG, ++ "HPM: returning in progress to handle IOL session lost"); ++ fakeRsp.ccode = HPMFWUPG_COMMAND_IN_PROGRESS; ++ rsp = &fakeRsp; ++ } else if (req.msg.netfn == IPMI_NETFN_PICMG ++ && (req.msg.cmd == HPMFWUPG_QUERY_ROLLBACK_STATUS ++ || req.msg.cmd == HPMFWUPG_GET_UPGRADE_STATUS ++ || req.msg.cmd == HPMFWUPG_QUERY_SELFTEST_RESULT) ++ && ( !intf->target_addr || intf->target_addr == intf->my_addr)) { ++ /* reopen session only if target IPMC is directly accessed */ ++ /* ++ * rsp == NULL and command get upgrade status or query rollback ++ * status most likely occurs when we are waiting for firmware ++ * activation. Try to re-open the IOL session (re-open will work ++ * once the IPMC recovers from firmware activation. ++ */ ++ lprintf(LOG_DEBUG, "HPM: upg/rollback status firmware API called"); ++ lprintf(LOG_DEBUG, "HPM: try to re-open IOL session"); ++ { ++ /* force session re-open */ ++ intf->opened = 0; ++ intf->session->authtype = IPMI_SESSION_AUTHTYPE_NONE; ++ intf->session->session_id = 0; ++ intf->session->in_seq = 0; ++ intf->session->out_seq = 0; ++ intf->session->active = 0; ++ intf->session->retry = 10; ++ while (intf->open(intf) == HPMFWUPG_ERROR ++ && inaccessTimeoutCounter < inaccessTimeout) { ++ inaccessTimeoutCounter += (time(NULL) - timeoutSec1); ++ timeoutSec1 = time(NULL); ++ } ++ /* Fake timeout to retry command */ ++ fakeRsp.ccode = 0xc3; ++ rsp = &fakeRsp; ++ } ++ } ++ } ++ } ++ /* Handle inaccessibility timeout (rsp = NULL if IOL) */ ++ if (rsp == NULL || rsp->ccode == 0xff || rsp->ccode == 0xc3 || rsp->ccode == 0xd3) { ++ if (inaccessTimeoutCounter < inaccessTimeout) { ++ timeoutSec2 = time(NULL); ++ if (timeoutSec2 > timeoutSec1) { ++ inaccessTimeoutCounter += timeoutSec2 - timeoutSec1; ++ timeoutSec1 = time(NULL); ++ } ++ usleep(100000); ++ retry = 1; ++ } else { ++ retry = 0; ++ } ++ } else if ( rsp->ccode == 0xc0 ) { ++ /* Handle node busy timeout */ ++ if (upgradeTimeoutCounter < upgradeTimeout) { ++ timeoutSec2 = time(NULL); ++ if (timeoutSec2 > timeoutSec1) { ++ timeoutSec1 = time(NULL); ++ upgradeTimeoutCounter += timeoutSec2 - timeoutSec1; ++ } ++ usleep(100000); ++ retry = 1; ++ } else { ++ retry = 0; ++ } ++ } else { ++# ifdef ENABLE_OPENIPMI_V39_PATCH ++ if (rsp->ccode == IPMI_CC_OK) { ++ errorCount = 0 ; ++ } ++# endif ++ retry = 0; ++ if (req.msg.netfn == IPMI_NETFN_PICMG ++ && req.msg.cmd == HPMFWUPG_UPLOAD_FIRMWARE_BLOCK ++ && (!isValidSize)) { ++ lprintf(LOG_INFO, ++ "Buffer length is now considered valid"); ++ isValidSize = TRUE; ++ } ++ } ++ } while (retry); ++ return rsp; + } + +-int HpmfwupgWaitLongDurationCmd(struct ipmi_intf *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx) +-{ +- int rc = HPMFWUPG_SUCCESS; +- unsigned int upgradeTimeout = 0; +- unsigned int timeoutSec1, timeoutSec2; +- struct HpmfwupgGetUpgradeStatusCtx upgStatusCmd; +- +- /* +- * If we are not in upgrade context, we use default timeout values +- */ +- if ( pFwupgCtx != NULL ) +- { +- upgradeTimeout = (unsigned int)(pFwupgCtx->targetCap.upgradeTimeout*5); +- if ( verbose ) +- printf("Use File Upgrade Capabilities: %i seconds\n", upgradeTimeout); +- } +- else +- { +- /* Try to retreive from Caps */ +- struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; +- +- if(HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd) != HPMFWUPG_SUCCESS) +- { +- upgradeTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; +- +- if ( verbose ) +- printf("Use default timeout: %i seconds\n", upgradeTimeout); +- } +- else +- { +- upgradeTimeout = (unsigned int)(targetCapCmd.resp.upgradeTimeout * 5); +- if ( verbose ) +- printf("Use Command Upgrade Capabilities Timeout: %i seconds\n", upgradeTimeout); +- } +- } +- +- if(rc == HPMFWUPG_SUCCESS) +- { +- /* Poll upgrade status until completion or timeout*/ +- timeoutSec1 = time(NULL); +- timeoutSec2 = time(NULL); +- rc = HpmfwupgGetUpgradeStatus(intf, &upgStatusCmd, pFwupgCtx, 1); +- } +- +- while( +- //With KCS: Cover the case where we sometime receive d5 (on the first get status) from the ipmi driver. +- (upgStatusCmd.resp.lastCmdCompCode != 0x00 ) && +- ((timeoutSec2 - timeoutSec1) < upgradeTimeout ) && +- (rc == HPMFWUPG_SUCCESS) +- ) +- { +- /* Must wait at least 1000 ms between status requests */ +- usleep(1000000); +- timeoutSec2 = time(NULL); +- rc = HpmfwupgGetUpgradeStatus(intf, &upgStatusCmd, pFwupgCtx, 1); +- //printf("Get Status: %x - %x = %x _ %x [%x]\n", timeoutSec2, timeoutSec1,(timeoutSec2 - timeoutSec1),upgradeTimeout, rc); +- } +- +- if ( upgStatusCmd.resp.lastCmdCompCode != 0x00 ) +- { +- if ( verbose ) +- { +- lprintf(LOG_NOTICE,"Error waiting for command %x, compcode = %x", +- upgStatusCmd.resp.cmdInProcess, +- upgStatusCmd.resp.lastCmdCompCode); +- } +- rc = HPMFWUPG_ERROR; +- } +- +- return rc; ++int ++HpmfwupgWaitLongDurationCmd(struct ipmi_intf *intf, ++ struct HpmfwupgUpgradeCtx *pFwupgCtx) ++{ ++ int rc = HPMFWUPG_SUCCESS; ++ unsigned int upgradeTimeout = 0; ++ unsigned int timeoutSec1, timeoutSec2; ++ struct HpmfwupgGetUpgradeStatusCtx upgStatusCmd; ++ /* If we are not in upgrade context, we use default timeout values */ ++ if (pFwupgCtx != NULL) { ++ upgradeTimeout = (unsigned int)(pFwupgCtx->targetCap.upgradeTimeout*5); ++ if (verbose) { ++ printf("Use File Upgrade Capabilities: %i seconds\n", ++ upgradeTimeout); ++ } ++ } else { ++ /* Try to retreive from Caps */ ++ struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; ++ if(HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd) != HPMFWUPG_SUCCESS) { ++ upgradeTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; ++ if (verbose) { ++ printf("Use default timeout: %i seconds\n", ++ upgradeTimeout); ++ } ++ } else { ++ upgradeTimeout = (unsigned int)(targetCapCmd.resp.upgradeTimeout * 5); ++ if (verbose) { ++ printf("Use Command Upgrade Capabilities Timeout: %i seconds\n", ++ upgradeTimeout); ++ } ++ } ++ } ++ if (rc == HPMFWUPG_SUCCESS) { ++ /* Poll upgrade status until completion or timeout*/ ++ timeoutSec1 = time(NULL); ++ timeoutSec2 = time(NULL); ++ rc = HpmfwupgGetUpgradeStatus(intf, &upgStatusCmd, ++ pFwupgCtx, 1); ++ } ++ while ( ++ /* With KCS: Cover the case where we sometime ++ * receive d5 (on the first get status) from ++ * the ipmi driver. ++ */ ++ (upgStatusCmd.resp.lastCmdCompCode != 0x00 ) ++ && ((timeoutSec2 - timeoutSec1) < upgradeTimeout ) ++ && (rc == HPMFWUPG_SUCCESS)) { ++ /* Must wait at least 1000 ms between status requests */ ++ usleep(1000000); ++ timeoutSec2 = time(NULL); ++ rc = HpmfwupgGetUpgradeStatus(intf, &upgStatusCmd, pFwupgCtx, 1); ++/* ++ * printf("Get Status: %x - %x = %x _ %x [%x]\n", ++ ( timeoutSec2, timeoutSec1, ++ * (timeoutSec2 - timeoutSec1), ++ * upgradeTimeout, rc); ++ */ ++ } ++ if (upgStatusCmd.resp.lastCmdCompCode != 0x00) { ++ if (verbose) { ++ lprintf(LOG_NOTICE, ++ "Error waiting for command %x, compcode = %x", ++ upgStatusCmd.resp.cmdInProcess, ++ upgStatusCmd.resp.lastCmdCompCode); ++ } ++ rc = HPMFWUPG_ERROR; ++ } ++ return rc; + } + +-unsigned char HpmfwupgCalculateChecksum(unsigned char* pData, unsigned int length) ++unsigned char ++HpmfwupgCalculateChecksum(unsigned char *pData, unsigned int length) + { +- unsigned char checksum = 0; +- int dataIdx = 0; +- +- for ( dataIdx = 0; dataIdx < length; dataIdx++ ) +- { +- checksum += pData[dataIdx]; +- } +- return checksum; ++ unsigned char checksum = 0; ++ int dataIdx = 0; ++ for (dataIdx = 0; dataIdx < length; dataIdx++) { ++ checksum += pData[dataIdx]; ++ } ++ return checksum; + } + +-static void HpmfwupgPrintUsage(void) +-{ +- lprintf(LOG_NOTICE,"help - This help menu."); +- lprintf(LOG_NOTICE,""); +- lprintf(LOG_NOTICE,"check - Check the target information."); +- lprintf(LOG_NOTICE,"check - If the user is unsure of what update is going to be "); +- lprintf(LOG_NOTICE," This will display the existing target version and"); +- lprintf(LOG_NOTICE," image version on the screen"); +- lprintf(LOG_NOTICE,""); +- lprintf(LOG_NOTICE,"upgrade - Copies all the components from a valid HPM.1"); +- lprintf(LOG_NOTICE," image to the target."); +- lprintf(LOG_NOTICE," This compares the versions from both the target"); +- lprintf(LOG_NOTICE," and image and will only perform the copy"); +- lprintf(LOG_NOTICE," if the versions differ."); +- lprintf(LOG_NOTICE,"upgrade activate - Copy and activate the firmware using a valid HPM.1"); +- lprintf(LOG_NOTICE," image ."); +- lprintf(LOG_NOTICE," This compares the versions from both the target"); +- lprintf(LOG_NOTICE," and image and will only perform the copy and"); +- lprintf(LOG_NOTICE," activation if the versions differ."); +- lprintf(LOG_NOTICE,"upgrade force - Copies all the components present in "); +- lprintf(LOG_NOTICE," to the target board without checking the versions."); +- lprintf(LOG_NOTICE," Make sure to check the versions first using the"); +- lprintf(LOG_NOTICE," \"check \" command."); +- lprintf(LOG_NOTICE,"upgrade component x - Copy only component from the given "); +- lprintf(LOG_NOTICE," without checking if the versions differ."); +- lprintf(LOG_NOTICE," For example:"); +- lprintf(LOG_NOTICE," component 0 = Bootloader"); +- lprintf(LOG_NOTICE," component 1 = Firmware"); +- lprintf(LOG_NOTICE," Make sure to check the versions first using the"); +- lprintf(LOG_NOTICE," \"check \" command."); +- lprintf(LOG_NOTICE,"upgstatus - Returns the status of the last long duration command."); +- lprintf(LOG_NOTICE,""); +- lprintf(LOG_NOTICE,"activate - Activate the newly uploaded firmware."); +- lprintf(LOG_NOTICE,"activate norollback - Activate the newly uploaded firmware but inform"); +- lprintf(LOG_NOTICE," the target to not automatically rollback if "); +- lprintf(LOG_NOTICE," the upgrade fails."); +- lprintf(LOG_NOTICE,""); +- lprintf(LOG_NOTICE,"targetcap - Get the target upgrade capabilities."); +- lprintf(LOG_NOTICE,""); +- lprintf(LOG_NOTICE,"compprop - Get specified component properties from the target."); +- lprintf(LOG_NOTICE," Valid component : 0-7 "); +- lprintf(LOG_NOTICE," Properties can be one of the following: "); +- lprintf(LOG_NOTICE," 0- General properties"); +- lprintf(LOG_NOTICE," 1- Current firmware version"); +- lprintf(LOG_NOTICE," 2- Description string"); +- lprintf(LOG_NOTICE," 3- Rollback firmware version"); +- lprintf(LOG_NOTICE," 4- Deferred firmware version"); +- lprintf(LOG_NOTICE,""); +- lprintf(LOG_NOTICE,"abort - Abort the on-going firmware upgrade."); +- lprintf(LOG_NOTICE,""); +- lprintf(LOG_NOTICE,"rollback - Performs a manual rollback on the IPM Controller."); +- lprintf(LOG_NOTICE," firmware"); +- lprintf(LOG_NOTICE,"rollbackstatus - Query the rollback status."); +- lprintf(LOG_NOTICE,""); +- lprintf(LOG_NOTICE,"selftestresult - Query the self test results.\n"); ++void ++HpmfwupgPrintUsage(void) ++{ ++ lprintf(LOG_NOTICE, ++"help - This help menu."); ++ lprintf(LOG_NOTICE, ++""); ++ lprintf(LOG_NOTICE, ++"check - Check the target information."); ++ lprintf(LOG_NOTICE, ++"check - If the user is unsure of what update is going to be "); ++ lprintf(LOG_NOTICE, ++" This will display the existing target version and"); ++ lprintf(LOG_NOTICE, ++" image version on the screen"); ++ lprintf(LOG_NOTICE, ++""); ++ lprintf(LOG_NOTICE, ++"upgrade [component x...] [force] [activate]"); ++ lprintf(LOG_NOTICE, ++" - Copies components from a valid HPM.1 image to the target."); ++ lprintf(LOG_NOTICE, ++" If one or more components specified by \"component\","); ++ lprintf(LOG_NOTICE, ++" only the specified components are copied."); ++ lprintf(LOG_NOTICE, ++" Otherwise, all the image components are copied."); ++ lprintf(LOG_NOTICE, ++" Before copy, each image component undergoes a version check"); ++ lprintf(LOG_NOTICE, ++" and can be skipped if the target component version"); ++ lprintf(LOG_NOTICE, ++" is the same or more recent."); ++ lprintf(LOG_NOTICE, ++" Use \"force\" to bypass the version check results."); ++ lprintf(LOG_NOTICE, ++" Make sure to check the versions first using the"); ++ lprintf(LOG_NOTICE, ++" \"check \" command."); ++ lprintf(LOG_NOTICE, ++" If \"activate\" is specified, the newly uploaded firmware"); ++ lprintf(LOG_NOTICE, ++" is activated."); ++ lprintf(LOG_NOTICE, ++"upgstatus - Returns the status of the last long duration command."); ++ lprintf(LOG_NOTICE, ++""); ++ lprintf(LOG_NOTICE, ++"compare - Perform \"Comparison of the Active Copy\" action for all the"); ++ lprintf(LOG_NOTICE, ++" components present in the file."); ++ lprintf(LOG_NOTICE, ++"compare component x - Compare only component from the given "); ++ lprintf(LOG_NOTICE, ++"activate - Activate the newly uploaded firmware."); ++ lprintf(LOG_NOTICE, ++"activate norollback - Activate the newly uploaded firmware but inform"); ++ lprintf(LOG_NOTICE, ++" the target to not automatically rollback if "); ++ lprintf(LOG_NOTICE, ++" the upgrade fails."); ++ lprintf(LOG_NOTICE, ++""); ++ lprintf(LOG_NOTICE, ++"targetcap - Get the target upgrade capabilities."); ++ lprintf(LOG_NOTICE, ++""); ++ lprintf(LOG_NOTICE, ++"compprop - Get specified component properties from the target."); ++ lprintf(LOG_NOTICE, ++" Valid component : 0-7 "); ++ lprintf(LOG_NOTICE, ++" Properties can be one of the following: "); ++ lprintf(LOG_NOTICE, ++" 0- General properties"); ++ lprintf(LOG_NOTICE, ++" 1- Current firmware version"); ++ lprintf(LOG_NOTICE, ++" 2- Description string"); ++ lprintf(LOG_NOTICE, ++" 3- Rollback firmware version"); ++ lprintf(LOG_NOTICE, ++" 4- Deferred firmware version"); ++ lprintf(LOG_NOTICE, ++""); ++ lprintf(LOG_NOTICE, ++"abort - Abort the on-going firmware upgrade."); ++ lprintf(LOG_NOTICE, ++""); ++ lprintf(LOG_NOTICE, ++"rollback - Performs a manual rollback on the IPM Controller."); ++ lprintf(LOG_NOTICE, ++" firmware"); ++ lprintf(LOG_NOTICE, ++"rollbackstatus - Query the rollback status."); ++ lprintf(LOG_NOTICE, ++""); ++ lprintf(LOG_NOTICE, ++"selftestresult - Query the self test results.\n"); + } + +-int ipmi_hpmfwupg_main(struct ipmi_intf * intf, int argc, char ** argv) +-{ +- int rc = HPMFWUPG_SUCCESS; +- int activateFlag = 0x00; +- int componentId = DEFAULT_COMPONENT_UPLOAD; +- int option = VERSIONCHECK_MODE; +- +- lprintf(LOG_DEBUG,"ipmi_hpmfwupg_main()"); +- +- +- lprintf(LOG_NOTICE,"\nPICMG HPM.1 Upgrade Agent %d.%d.%d: \n", +- HPMFWUPG_VERSION_MAJOR, HPMFWUPG_VERSION_MINOR, HPMFWUPG_VERSION_SUBMINOR); +- +- if ( (argc == 0) || (strcmp(argv[0], "help") == 0) ) +- { +- HpmfwupgPrintUsage(); +- return HPMFWUPG_ERROR; +- } +- if ( (strcmp(argv[0], "check") == 0) ) +- { +- /* hpm check */ +- if (argv[1] == NULL) +- { +- rc = HpmfwupgTargetCheck(intf,VIEW_MODE); +- } +- else +- { +- /* hpm check */ +- rc = HpmfwupgTargetCheck(intf,0); +- if (rc == HPMFWUPG_SUCCESS) +- { +- rc = HpmfwupgUpgrade(intf, argv[1],0,DEFAULT_COMPONENT_UPLOAD,VIEW_MODE); +- } +- } +- } +- +- else if ( strcmp(argv[0], "upgrade") == 0) +- { +- int i =0; +- for (i=1; i< argc ; i++) +- { +- if (strcmp(argv[i],"activate") == 0) +- { +- activateFlag = 1; +- } +- /* hpm upgrade force */ +- if (strcmp(argv[i],"force") == 0) +- { +- option &= ~(VERSIONCHECK_MODE); +- option &= ~(VIEW_MODE); +- option |= FORCE_MODE_ALL; +- } +- /* hpm upgrade component */ +- if (strcmp(argv[i],"component") == 0) +- { +- if (i+1 < argc) +- { +- if (str2int(argv[i+1], &componentId) != 0 || +- componentId < 0 || componentId > 7) { +- lprintf(LOG_ERR, "Given Component ID '%s' is invalid.", +- argv[i+1]); +- lprintf(LOG_ERR, "Valid Compoment ID is: <0..7>"); +- return (-1); +- } +- option &= ~(VERSIONCHECK_MODE); +- option &= ~(VIEW_MODE); +- option |= FORCE_MODE_COMPONENT; +- +- if( verbose ) { +- lprintf(LOG_NOTICE,"Component Id %d provided",componentId ); +- } +- +- /* Error Checking */ +- if (componentId >= HPMFWUPG_COMPONENT_ID_MAX) +- { +- lprintf(LOG_NOTICE,"Given component ID %d exceeds Max Comp ID %d\n", +- componentId, HPMFWUPG_COMPONENT_ID_MAX-1); +- return HPMFWUPG_ERROR; +- } +- } +- if (componentId == DEFAULT_COMPONENT_UPLOAD) +- { +- /* That indicates the user has given component on console but not +- * given any ID */ +- lprintf(LOG_NOTICE,"No component Id provided\n"); +- return HPMFWUPG_ERROR; +- } +- } +- if (strcmp(argv[i],"debug") == 0) +- { +- option |= DEBUG_MODE; +- } +- } +- rc = HpmfwupgTargetCheck(intf,0); +- if (rc == HPMFWUPG_SUCCESS) +- { +- /* Call the Upgrade function to start the upgrade */ +- rc = HpmfwupgUpgrade(intf, argv[1],activateFlag,componentId,option); +- } +- } +- +- else if ( (argc >= 1) && (strcmp(argv[0], "activate") == 0) ) +- { +- struct HpmfwupgActivateFirmwareCtx cmdCtx; +- if ( (argc == 2) && (strcmp(argv[1], "norollback") == 0) ) +- cmdCtx.req.rollback_override = 1; +- else +- cmdCtx.req.rollback_override = 0; +- rc = HpmfwupgActivateFirmware(intf, &cmdCtx, NULL); +- } +- else if ( (argc == 1) && (strcmp(argv[0], "targetcap") == 0) ) +- { +- struct HpmfwupgGetTargetUpgCapabilitiesCtx cmdCtx; +- verbose++; +- rc = HpmfwupgGetTargetUpgCapabilities(intf, &cmdCtx); +- } +- else if ( (argc == 3) && (strcmp(argv[0], "compprop") == 0) ) +- { +- struct HpmfwupgGetComponentPropertiesCtx cmdCtx; +- if (str2uchar(argv[1], &(cmdCtx.req.componentId)) != 0 +- || cmdCtx.req.componentId > 7) { +- lprintf(LOG_ERR, "Given Component ID '%s' is invalid.", argv[1]); +- lprintf(LOG_ERR, "Valid Compoment ID is: <0..7>"); +- return (-1); +- } +- if (str2uchar(argv[2], &(cmdCtx.req.selector)) != 0 +- || cmdCtx.req.selector > 4) { +- lprintf(LOG_ERR, "Given Properties selector '%s' is invalid.", +- argv[2]); +- lprintf(LOG_ERR, "Valid Properties selector is: <0..4>"); +- return (-1); +- } +- verbose++; +- rc = HpmfwupgGetComponentProperties(intf, &cmdCtx); +- } +- else if ( (argc == 1) && (strcmp(argv[0], "abort") == 0) ) +- { +- struct HpmfwupgAbortUpgradeCtx cmdCtx; +- verbose++; +- rc = HpmfwupgAbortUpgrade(intf, &cmdCtx); +- } +- else if ( (argc == 1) && (strcmp(argv[0], "upgstatus") == 0) ) +- { +- struct HpmfwupgGetUpgradeStatusCtx cmdCtx; +- verbose++; +- rc = HpmfwupgGetUpgradeStatus(intf, &cmdCtx, NULL, 0); +- } +- else if ( (argc == 1) && (strcmp(argv[0], "rollback") == 0) ) +- { +- struct HpmfwupgManualFirmwareRollbackCtx cmdCtx; +- verbose++; +- rc = HpmfwupgManualFirmwareRollback(intf, &cmdCtx, NULL); +- } +- else if ( (argc == 1) && (strcmp(argv[0], "rollbackstatus") == 0) ) +- { +- struct HpmfwupgQueryRollbackStatusCtx cmdCtx; +- verbose++; +- rc = HpmfwupgQueryRollbackStatus(intf, &cmdCtx, NULL); +- } +- else if ( (argc == 1) && (strcmp(argv[0], "selftestresult") == 0) ) +- { +- struct HpmfwupgQuerySelftestResultCtx cmdCtx; +- verbose++; +- rc = HpmfwupgQuerySelftestResult(intf, &cmdCtx, NULL); +- } +- else +- { +- HpmfwupgPrintUsage(); +- } +- +- return rc; ++int ++ipmi_hpmfwupg_main(struct ipmi_intf *intf, int argc, char **argv) ++{ ++ int rc = HPMFWUPG_SUCCESS; ++ int activateFlag = 0x00; ++ int componentMask = 0; ++ int componentId = 0; ++ int option = 0; ++ ++ lprintf(LOG_DEBUG,"ipmi_hpmfwupg_main()"); ++ lprintf(LOG_NOTICE, "\nPICMG HPM.1 Upgrade Agent %d.%d.%d: \n", ++ HPMFWUPG_VERSION_MAJOR, HPMFWUPG_VERSION_MINOR, ++ HPMFWUPG_VERSION_SUBMINOR); ++ if (argc < 1) { ++ lprintf(LOG_ERR, "Not enough parameters given."); ++ HpmfwupgPrintUsage(); ++ return HPMFWUPG_ERROR; ++ } ++ if (strcmp(argv[0], "help") == 0) { ++ HpmfwupgPrintUsage(); ++ return HPMFWUPG_SUCCESS; ++ } else if ((strcmp(argv[0], "check") == 0)) { ++ /* hpm check */ ++ if (argv[1] == NULL) { ++ rc = HpmfwupgTargetCheck(intf,VIEW_MODE); ++ } else { ++ /* hpm check */ ++ rc = HpmfwupgTargetCheck(intf,0); ++ if (rc == HPMFWUPG_SUCCESS) { ++ rc = HpmfwupgUpgrade(intf, argv[1], 0, ++ 0, VIEW_MODE); ++ } ++ } ++ } else if (strcmp(argv[0], "upgrade") == 0) { ++ int i =0; ++ for (i=1; i< argc ; i++) { ++ if (strcmp(argv[i],"activate") == 0) { ++ activateFlag = 1; ++ } ++ /* hpm upgrade force */ ++ if (strcmp(argv[i],"force") == 0) { ++ option |= FORCE_MODE; ++ } ++ /* hpm upgrade component */ ++ if (strcmp(argv[i],"component") == 0) { ++ if (i+1 < argc) { ++ /* Error Checking */ ++ if (str2int(argv[i+1], &componentId) != 0 ++ || componentId < 0 ++ || componentId > HPMFWUPG_COMPONENT_ID_MAX) { ++ lprintf(LOG_ERR, ++ "Given Component ID '%s' is invalid.", ++ argv[i+1]); ++ lprintf(LOG_ERR, ++ "Valid Compoment ID is: <0..7>"); ++ return HPMFWUPG_ERROR; ++ } ++ if( verbose ) { ++ lprintf(LOG_NOTICE, ++ "Component Id %d provided", ++ componentId ); ++ } ++ componentMask |= 1 << componentId; ++ } else { ++ /* That indicates the user has ++ * given component on console but ++ * not given any ID ++ */ ++ lprintf(LOG_NOTICE, ++ "No component Id provided\n"); ++ return HPMFWUPG_ERROR; ++ } ++ } ++ if (strcmp(argv[i],"debug") == 0) { ++ option |= DEBUG_MODE; ++ } ++ } ++ rc = HpmfwupgTargetCheck(intf, 0); ++ if (rc == HPMFWUPG_SUCCESS) { ++ /* Call the Upgrade function to start the upgrade */ ++ rc = HpmfwupgUpgrade(intf, argv[1], activateFlag, ++ componentMask, option); ++ } ++ } else if (strcmp(argv[0], "compare") == 0) { ++ int i = 0; ++ for (i=1; i< argc; i++) { ++ /* hpm compare [component x...] */ ++ if (strcmp(argv[i],"component") == 0) { ++ if (i+1 < argc) { ++ /* Error Checking */ ++ if (str2int(argv[i+1], &componentId) != 0 ++ || componentId < 0 ++ || componentId > HPMFWUPG_COMPONENT_ID_MAX) { ++ lprintf(LOG_ERR, ++ "Given Component ID '%s' is invalid.", ++ argv[i+1]); ++ lprintf(LOG_ERR, ++ "Valid Compoment ID is: <0..7>"); ++ return HPMFWUPG_ERROR; ++ } ++ if( verbose ) { ++ lprintf(LOG_NOTICE, ++ "Component Id %d provided", ++ componentId); ++ } ++ componentMask|= 1 << componentId; ++ } else { ++ /* That indicates the user ++ * has given component on ++ * console but not ++ * given any ID ++ */ ++ lprintf(LOG_NOTICE, ++ "No component Id provided\n"); ++ return HPMFWUPG_ERROR; ++ } ++ } else if (strcmp(argv[i],"debug") == 0) { ++ option|= DEBUG_MODE; ++ } ++ } ++ option|= (COMPARE_MODE); ++ rc = HpmfwupgTargetCheck(intf, 0); ++ if (rc == HPMFWUPG_SUCCESS) { ++ rc = HpmfwupgUpgrade(intf, argv[1], 0, ++ componentMask, option); ++ } ++ } else if ((argc >= 1) && (strcmp(argv[0], "activate") == 0)) { ++ struct HpmfwupgActivateFirmwareCtx cmdCtx; ++ if ((argc == 2) && (strcmp(argv[1], "norollback") == 0)) { ++ cmdCtx.req.rollback_override = 1; ++ } else { ++ cmdCtx.req.rollback_override = 0; ++ } ++ rc = HpmfwupgActivateFirmware(intf, &cmdCtx, NULL); ++ } else if ((argc == 1) && (strcmp(argv[0], "targetcap") == 0)) { ++ struct HpmfwupgGetTargetUpgCapabilitiesCtx cmdCtx; ++ verbose++; ++ rc = HpmfwupgGetTargetUpgCapabilities(intf, &cmdCtx); ++ } else if ((argc == 3) && (strcmp(argv[0], "compprop") == 0)) { ++ struct HpmfwupgGetComponentPropertiesCtx cmdCtx; ++ if (str2uchar(argv[1], &(cmdCtx.req.componentId)) != 0 ++ || cmdCtx.req.componentId > 7) { ++ lprintf(LOG_ERR, ++ "Given Component ID '%s' is invalid.", ++ argv[1]); ++ lprintf(LOG_ERR, ++ "Valid Compoment ID is: <0..7>"); ++ return (-1); ++ } ++ if (str2uchar(argv[2], &(cmdCtx.req.selector)) != 0 ++ || cmdCtx.req.selector > 4) { ++ lprintf(LOG_ERR, ++ "Given Properties selector '%s' is invalid.", ++ argv[2]); ++ lprintf(LOG_ERR, ++ "Valid Properties selector is: <0..4>"); ++ return (-1); ++ } ++ verbose++; ++ rc = HpmfwupgGetComponentProperties(intf, &cmdCtx); ++ } else if ((argc == 1) && (strcmp(argv[0], "abort") == 0)) { ++ struct HpmfwupgAbortUpgradeCtx cmdCtx; ++ verbose++; ++ rc = HpmfwupgAbortUpgrade(intf, &cmdCtx); ++ } else if ((argc == 1) && (strcmp(argv[0], "upgstatus") == 0)) { ++ struct HpmfwupgGetUpgradeStatusCtx cmdCtx; ++ verbose++; ++ rc = HpmfwupgGetUpgradeStatus(intf, &cmdCtx, NULL, 0); ++ } else if ((argc == 1) && (strcmp(argv[0], "rollback") == 0)) { ++ struct HpmfwupgManualFirmwareRollbackCtx cmdCtx; ++ verbose++; ++ rc = HpmfwupgManualFirmwareRollback(intf, &cmdCtx); ++ } else if ((argc == 1) && (strcmp(argv[0], "rollbackstatus") == 0)) { ++ struct HpmfwupgQueryRollbackStatusCtx cmdCtx; ++ verbose++; ++ rc = HpmfwupgQueryRollbackStatus(intf, &cmdCtx, NULL); ++ } else if ((argc == 1) && (strcmp(argv[0], "selftestresult") == 0)) { ++ struct HpmfwupgQuerySelftestResultCtx cmdCtx; ++ verbose++; ++ rc = HpmfwupgQuerySelftestResult(intf, &cmdCtx, NULL); ++ } else { ++ lprintf(LOG_ERR, "Invalid HPM command: %s", argv[0]); ++ HpmfwupgPrintUsage(); ++ rc = HPMFWUPG_ERROR; ++ } ++ return rc; + } + +diff --git a/ipmitool/lib/ipmi_kontronoem.c b/ipmitool/lib/ipmi_kontronoem.c +index dac2ced..c154eda 100644 +--- a/ipmitool/lib/ipmi_kontronoem.c ++++ b/ipmitool/lib/ipmi_kontronoem.c +@@ -350,6 +350,7 @@ ipmi_kontron_set_serial_number(struct ipmi_intf * intf) + return(-1); + } + ++ memset(&fru, 0, sizeof(fru)); + fru.size = (rsp->data[1] << 8) | rsp->data[0]; + fru.access = rsp->data[2] & 0x1; + +@@ -637,6 +638,7 @@ ipmi_kontron_set_mfg_date (struct ipmi_intf * intf) + return(-1); + } + ++ memset(&fru, 0, sizeof(fru)); + fru.size = (rsp->data[1] << 8) | rsp->data[0]; + fru.access = rsp->data[2] & 0x1; + +diff --git a/ipmitool/lib/ipmi_main.c b/ipmitool/lib/ipmi_main.c +index 54b80c0..3d0a3b8 100644 +--- a/ipmitool/lib/ipmi_main.c ++++ b/ipmitool/lib/ipmi_main.c +@@ -894,9 +894,11 @@ ipmi_main(int argc, char ** argv, + + /* Open the interface with the specified or default IPMB address */ + ipmi_main_intf->my_addr = arg_addr ? arg_addr : IPMI_BMC_SLAVE_ADDR; +- if (ipmi_main_intf->open != NULL) +- ipmi_main_intf->open(ipmi_main_intf); +- ++ if (ipmi_main_intf->open != NULL) { ++ if (ipmi_main_intf->open(ipmi_main_intf) < 0) { ++ goto out_free; ++ } ++ } + /* + * Attempt picmg discovery of the actual interface address unless + * the users specified an address. +diff --git a/ipmitool/lib/ipmi_sdr.c b/ipmitool/lib/ipmi_sdr.c +index 093d1ec..d44bbbb 100644 +--- a/ipmitool/lib/ipmi_sdr.c ++++ b/ipmitool/lib/ipmi_sdr.c +@@ -456,10 +456,12 @@ ipmi_sdr_get_sensor_thresholds(struct ipmi_intf *intf, uint8_t sensor, + { + struct ipmi_rq req; + struct ipmi_rs *rsp; +- uint32_t save_addr = 0; ++ uint8_t bridged_request = 0; ++ uint32_t save_addr; + uint32_t save_channel; + + if ( BRIDGE_TO_SENSOR(intf, target, channel) ) { ++ bridged_request = 1; + save_addr = intf->target_addr; + intf->target_addr = target; + save_channel = intf->target_channel; +@@ -474,7 +476,7 @@ ipmi_sdr_get_sensor_thresholds(struct ipmi_intf *intf, uint8_t sensor, + req.msg.data_len = sizeof (sensor); + + rsp = intf->sendrecv(intf, &req); +- if ( save_addr ) { ++ if (bridged_request) { + intf->target_addr = save_addr; + intf->target_channel = save_channel; + } +@@ -498,10 +500,12 @@ ipmi_sdr_get_sensor_hysteresis(struct ipmi_intf *intf, uint8_t sensor, + struct ipmi_rq req; + uint8_t rqdata[2]; + struct ipmi_rs *rsp; +- uint32_t save_addr = 0; ++ uint8_t bridged_request = 0; ++ uint32_t save_addr; + uint32_t save_channel; + + if ( BRIDGE_TO_SENSOR(intf, target, channel) ) { ++ bridged_request = 1; + save_addr = intf->target_addr; + intf->target_addr = target; + save_channel = intf->target_channel; +@@ -519,7 +523,7 @@ ipmi_sdr_get_sensor_hysteresis(struct ipmi_intf *intf, uint8_t sensor, + req.msg.data_len = 2; + + rsp = intf->sendrecv(intf, &req); +- if ( save_addr ) { ++ if (bridged_request) { + intf->target_addr = save_addr; + intf->target_channel = save_channel; + } +@@ -564,10 +568,17 @@ ipmi_sdr_get_sensor_reading_ipmb(struct ipmi_intf *intf, uint8_t sensor, + { + struct ipmi_rq req; + struct ipmi_rs *rsp; +- uint32_t save_addr = 0; ++ uint8_t bridged_request = 0; ++ uint32_t save_addr; + uint32_t save_channel; + + if ( BRIDGE_TO_SENSOR(intf, target, channel) ) { ++ lprintf(LOG_DEBUG, ++ "Bridge to Sensor " ++ "Intf my/%#x tgt/%#x:%#x Sdr tgt/%#x:%#x\n", ++ intf->my_addr, intf->target_addr, intf->target_channel, ++ target, channel); ++ bridged_request = 1; + save_addr = intf->target_addr; + intf->target_addr = target; + save_channel = intf->target_channel; +@@ -581,7 +592,7 @@ ipmi_sdr_get_sensor_reading_ipmb(struct ipmi_intf *intf, uint8_t sensor, + req.msg.data_len = 1; + + rsp = intf->sendrecv(intf, &req); +- if ( save_addr ) { ++ if (bridged_request) { + intf->target_addr = save_addr; + intf->target_channel = save_channel; + } +@@ -604,10 +615,12 @@ ipmi_sdr_get_sensor_event_status(struct ipmi_intf *intf, uint8_t sensor, + { + struct ipmi_rq req; + struct ipmi_rs *rsp; +- uint32_t save_addr = 0; ++ uint8_t bridged_request = 0; ++ uint32_t save_addr; + uint32_t save_channel; + + if ( BRIDGE_TO_SENSOR(intf, target, channel) ) { ++ bridged_request = 1; + save_addr = intf->target_addr; + intf->target_addr = target; + save_channel = intf->target_channel; +@@ -621,7 +634,7 @@ ipmi_sdr_get_sensor_event_status(struct ipmi_intf *intf, uint8_t sensor, + req.msg.data_len = 1; + + rsp = intf->sendrecv(intf, &req); +- if ( save_addr ) { ++ if (bridged_request) { + intf->target_addr = save_addr; + intf->target_channel = save_channel; + } +@@ -644,10 +657,12 @@ ipmi_sdr_get_sensor_event_enable(struct ipmi_intf *intf, uint8_t sensor, + { + struct ipmi_rq req; + struct ipmi_rs *rsp; +- uint32_t save_addr = 0; ++ uint8_t bridged_request = 0; ++ uint32_t save_addr; + uint32_t save_channel; + + if ( BRIDGE_TO_SENSOR(intf, target, channel) ) { ++ bridged_request = 1; + save_addr = intf->target_addr; + intf->target_addr = target; + save_channel = intf->target_channel; +@@ -662,7 +677,7 @@ ipmi_sdr_get_sensor_event_enable(struct ipmi_intf *intf, uint8_t sensor, + req.msg.data_len = 1; + + rsp = intf->sendrecv(intf, &req); +- if ( save_addr ) { ++ if (bridged_request) { + intf->target_addr = save_addr; + intf->target_channel = save_channel; + } +@@ -2407,6 +2422,7 @@ ipmi_sdr_print_sensor_oem_intel(struct ipmi_intf *intf, + ("Power Redundancy | PS@%02xh | nr\n", + oem->data[8]); + } ++ break; + case 9: /* SR2300, non-redundant, PSx present */ + if (verbose) { + printf("Power Redundancy : Yes\n"); +diff --git a/ipmitool/lib/ipmi_sel.c b/ipmitool/lib/ipmi_sel.c +index b06a81a..63ecbcf 100644 +--- a/ipmitool/lib/ipmi_sel.c ++++ b/ipmitool/lib/ipmi_sel.c +@@ -322,7 +322,6 @@ ipmi_get_oem(struct ipmi_intf * intf) + return IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id); + } + +- + static int + ipmi_sel_add_entry(struct ipmi_intf * intf, struct sel_event_record * rec) + { +@@ -526,6 +525,115 @@ get_newisys_evt_desc(struct ipmi_intf * intf, struct sel_event_record * rec) + return description; + } + ++char * ++get_supermicro_evt_desc(struct ipmi_intf *intf, struct sel_event_record *rec) ++{ ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ char *desc = NULL; ++ char *str; ++ int chipset_type = 1; ++ int data1; ++ int data2; ++ int data3; ++ int length; ++ int sensor_type; ++ uint8_t i = 0; ++ uint16_t oem_id = 0; ++ /* Get the OEM event Bytes of the SEL Records byte 13, 14, 15 to ++ * data1,data2,data3 ++ */ ++ data1 = rec->sel_type.standard_type.event_data[0]; ++ data2 = rec->sel_type.standard_type.event_data[1]; ++ data3 = rec->sel_type.standard_type.event_data[2]; ++ /* Check for the Standard Event type == 0x6F */ ++ if (rec->sel_type.standard_type.event_type != 0x6F) { ++ return NULL; ++ } ++ /* Allocate mem for te Description string */ ++ desc = (char *)malloc(SIZE_OF_DESC); ++ if (desc == NULL) { ++ lprintf(LOG_ERR, "ipmitool: malloc failure"); ++ return NULL; ++ } ++ memset(desc,0,SIZE_OF_DESC); ++ sensor_type = rec->sel_type.standard_type.sensor_type; ++ switch (sensor_type) { ++ case SENSOR_TYPE_MEMORY: ++ memset(&req, 0, sizeof (req)); ++ req.msg.netfn = IPMI_NETFN_APP; ++ req.msg.lun = 0; ++ req.msg.cmd = BMC_GET_DEVICE_ID; ++ req.msg.data = NULL; ++ req.msg.data_len = 0; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, " Error getting system info"); ++ if (desc != NULL) { ++ free(desc); ++ desc = NULL; ++ } ++ return NULL; ++ } else if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, " Error getting system info: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ if (desc != NULL) { ++ free(desc); ++ desc = NULL; ++ } ++ return NULL; ++ } ++ /* check the chipset type */ ++ oem_id = ipmi_get_oem_id(intf); ++ if (oem_id == 0) { ++ return NULL; ++ } ++ length = sizeof(supermicro_X8); ++ for (i = 0; i < length; i++) { ++ if (oem_id == supermicro_X8[i]) { ++ chipset_type = 0; ++ break; ++ } ++ } ++ length = sizeof(supermicro_x9); ++ for (i = 0; i < length; i++) { ++ if (oem_id == supermicro_x9[i]) { ++ chipset_type = 2; ++ break; ++ } ++ } ++ if (chipset_type == 0) { ++ snprintf(desc, SIZE_OF_DESC, "@DIMM%2X(CPU%x)", ++ data2, ++ (data3 & 0x03) + 1); ++ } else if (chipset_type == 1) { ++ snprintf(desc, SIZE_OF_DESC, "@DIMM%c%c(CPU%x)", ++ (data2 >> 4) + 0x40 + (data3 & 0x3) * 4, ++ (data2 & 0xf) + 0x27, (data3 & 0x03) + 1); ++ } else if (chipset_type == 2) { ++ snprintf(desc, SIZE_OF_DESC, "@DIMM%c%c(CPU%x)", ++ (data2 >> 4) + 0x40 + (data3 & 0x3) * 3, ++ (data2 & 0xf) + 0x27, (data3 & 0x03) + 1); ++ } else { ++ snprintf(desc, SIZE_OF_DESC, ""); ++ } ++ break; ++ case SENSOR_TYPE_SUPERMICRO_OEM: ++ if (data1 == 0x80 && data3 == 0xFF) { ++ if (data2 == 0x0) { ++ snprintf(desc, SIZE_OF_DESC, "BMC unexpected reset"); ++ } else if (data2 == 0x1) { ++ snprintf(desc, SIZE_OF_DESC, "BMC cold reset"); ++ } else if (data2 == 0x2) { ++ snprintf(desc, SIZE_OF_DESC, "BMC warm reset"); ++ } ++ } ++ break; ++ } ++ return desc; ++} ++ + /* + * Function : Decoding the SEL OEM Bytes for the DELL Platforms. + * Description : The below fucntion will decode the SEL Events OEM Bytes for the Dell specific Sensors only. +@@ -1067,6 +1175,10 @@ ipmi_get_oem_desc(struct ipmi_intf * intf, struct sel_event_record * rec) + case IPMI_OEM_DELL: // Dell Decoding of the OEM Bytes from SEL Record. + desc = get_dell_evt_desc(intf, rec); + break; ++ case IPMI_OEM_SUPERMICRO: ++ case IPMI_OEM_SUPERMICRO_47488: ++ desc = get_supermicro_evt_desc(intf, rec); ++ break; + case IPMI_OEM_UNKNOWN: + default: + break; +@@ -1092,7 +1204,6 @@ ipmi_get_event_desc(struct ipmi_intf * intf, struct sel_event_record * rec, char + *desc = ipmi_get_oem_desc(intf, rec); + return; + } else if (rec->sel_type.standard_type.event_type == 0x6f) { +- + if( rec->sel_type.standard_type.sensor_type >= 0xC0 && rec->sel_type.standard_type.sensor_type < 0xF0) { + IPMI_OEM iana = ipmi_get_oem(intf); + +@@ -1116,12 +1227,27 @@ ipmi_get_event_desc(struct ipmi_intf * intf, struct sel_event_record * rec, char + sfx = ipmi_get_oem_desc(intf, rec); + } + break; ++ case IPMI_OEM_SUPERMICRO: ++ case IPMI_OEM_SUPERMICRO_47488: ++ evt = sensor_specific_types; ++ code = rec->sel_type.standard_type.sensor_type; ++ sfx = ipmi_get_oem_desc(intf, rec); ++ break; + /* add your oem sensor assignation here */ + } + if( evt == NULL ){ + lprintf(LOG_DEBUG, "oem sensor type %x using standard type supplied description", + rec->sel_type.standard_type.sensor_type ); + } ++ } else { ++ switch (ipmi_get_oem(intf)) { ++ case IPMI_OEM_SUPERMICRO: ++ case IPMI_OEM_SUPERMICRO_47488: ++ evt = sensor_specific_types; ++ code = rec->sel_type.standard_type.sensor_type; ++ sfx = ipmi_get_oem_desc(intf, rec); ++ break; ++ } + } + if( evt == NULL ){ + evt = sensor_specific_types; +@@ -1210,6 +1336,9 @@ ipmi_get_event_desc(struct ipmi_intf * intf, struct sel_event_record * rec, char + if(0x01 == offset) + flag = 0x01; + break; ++ case SENSOR_TYPE_SUPERMICRO_OEM: ++ flag = 0x02; ++ break; + default: + break; + } +@@ -1222,6 +1351,10 @@ ipmi_get_event_desc(struct ipmi_intf * intf, struct sel_event_record * rec, char + return; + } + memset(*desc, 0, 48 + SIZE_OF_DESC); ++ if (flag == 0x02) { ++ sprintf(*desc, "%s", sfx); ++ return; ++ } + sprintf(*desc, "(%s)",sfx); + } + free(sfx); +@@ -1776,10 +1909,17 @@ ipmi_sel_print_std_entry(struct ipmi_intf * intf, struct sel_event_record * evt) + } + } + else if (evt->sel_type.standard_type.event_type == 0x6f) { ++ int print_sensor = 1; ++ switch (ipmi_get_oem(intf)) { ++ case IPMI_OEM_SUPERMICRO: ++ case IPMI_OEM_SUPERMICRO_47488: ++ print_sensor = 0; ++ break; ++ } + /* + * Sensor-Specific Discrete + */ +- if (evt->sel_type.standard_type.sensor_type == 0xC && ++ if (print_sensor && evt->sel_type.standard_type.sensor_type == 0xC && /*TODO*/ + evt->sel_type.standard_type.sensor_num == 0 && + (evt->sel_type.standard_type.event_data[0] & 0x30) == 0x20) { + /* break down memory ECC reporting if we can */ +diff --git a/ipmitool/lib/ipmi_sensor.c b/ipmitool/lib/ipmi_sensor.c +index 42e8853..4ef5138 100644 +--- a/ipmitool/lib/ipmi_sensor.c ++++ b/ipmitool/lib/ipmi_sensor.c +@@ -110,7 +110,8 @@ ipmi_sensor_set_sensor_thresholds(struct ipmi_intf *intf, + struct ipmi_rq req; + static struct sensor_set_thresh_rq set_thresh_rq; + struct ipmi_rs *rsp; +- uint32_t save_addr = 0; ++ uint8_t bridged_request = 0; ++ uint32_t save_addr; + uint32_t save_channel; + + memset(&set_thresh_rq, 0, sizeof (set_thresh_rq)); +@@ -132,6 +133,7 @@ ipmi_sensor_set_sensor_thresholds(struct ipmi_intf *intf, + return NULL; + + if (BRIDGE_TO_SENSOR(intf, target, channel)) { ++ bridged_request = 1; + save_addr = intf->target_addr; + intf->target_addr = target; + save_channel = intf->target_channel; +@@ -145,7 +147,7 @@ ipmi_sensor_set_sensor_thresholds(struct ipmi_intf *intf, + req.msg.data_len = sizeof (set_thresh_rq); + + rsp = intf->sendrecv(intf, &req); +- if (save_addr) { ++ if (bridged_request) { + intf->target_addr = save_addr; + intf->target_channel = save_channel; + } +diff --git a/ipmitool/lib/ipmi_sol.c b/ipmitool/lib/ipmi_sol.c +index b17b60e..4b829fc 100644 +--- a/ipmitool/lib/ipmi_sol.c ++++ b/ipmitool/lib/ipmi_sol.c +@@ -71,7 +71,7 @@ + #define SOL_PARAMETER_SOL_PAYLOAD_CHANNEL 0x07 + #define SOL_PARAMETER_SOL_PAYLOAD_PORT 0x08 + +-#define MAX_SOL_RETRY 6 ++#define MAX_SOL_RETRY 6 + + const struct valstr sol_parameter_vals[] = { + { SOL_PARAMETER_SET_IN_PROGRESS, "Set In Progress (0)" }, +@@ -100,47 +100,45 @@ extern int verbose; + * ipmi_sol_payload_access + */ + int +-ipmi_sol_payload_access(struct ipmi_intf * intf, +- uint8_t channel, +- uint8_t userid, +- int enable) ++ipmi_sol_payload_access(struct ipmi_intf * intf, uint8_t channel, ++ uint8_t userid, int enable) + { + struct ipmi_rq req; + struct ipmi_rs *rsp; ++ int rc = (-1); + uint8_t data[6]; + + memset(&req, 0, sizeof(req)); +- req.msg.netfn = IPMI_NETFN_APP; +- req.msg.cmd = IPMI_SET_USER_PAYLOAD_ACCESS; +- req.msg.data = data; ++ req.msg.netfn = IPMI_NETFN_APP; ++ req.msg.cmd = IPMI_SET_USER_PAYLOAD_ACCESS; ++ req.msg.data = data; + req.msg.data_len = 6; + + memset(data, 0, 6); +- +- data[0] = channel & 0xf; /* channel */ +- data[1] = userid & 0x3f; /* user id */ +- if (!enable) +- data[1] |= 0x40; /* disable */ +- data[2] = 0x02; /* payload 1 is SOL */ +- ++ /* channel */ ++ data[0] = channel & 0xf; ++ /* user id */ ++ data[1] = userid & 0x3f; ++ if (!enable) { ++ /* disable */ ++ data[1] |= 0x40; ++ } ++ /* payload 1 is SOL */ ++ data[2] = 0x02; + rsp = intf->sendrecv(intf, &req); +- +- if (NULL != rsp) { +- switch (rsp->ccode) { +- case 0x00: +- return 0; +- default: +- lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d: %s", +- enable ? "en" : "dis", userid, channel, +- val2str(rsp->ccode, completion_code_vals)); +- break; +- } +- } else { ++ if (rsp == NULL) { + lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d", +- enable ? "en" : "dis", userid, channel); ++ enable ? "en" : "dis", userid, channel); ++ rc = (-1); ++ } else if (rsp->ccode != 0) { ++ lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d: %s", ++ enable ? "en" : "dis", userid, channel, ++ val2str(rsp->ccode, completion_code_vals)); ++ rc = (-1); ++ } else { ++ rc = 0; + } +- +- return -1; ++ return rc; + } + + int +@@ -1931,29 +1929,21 @@ print_sol_set_usage(void) + + + +-/* +- * ipmi_sol_main +- */ ++/* ipmi_sol_main */ + int + ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv) + { + int retval = 0; +- +- /* +- * Help +- */ +- if (!argc || !strncmp(argv[0], "help", 4)) ++ if (!argc || !strncmp(argv[0], "help", 4)) { ++ /* Help */ + print_sol_usage(); +- +- /* +- * Info +- */ +- else if (!strncmp(argv[0], "info", 4)) { ++ } else if (!strncmp(argv[0], "info", 4)) { ++ /* Info */ + uint8_t channel; +- +- if (argc == 1) +- channel = 0x0E; /* Ask about the current channel */ +- else if (argc == 2) { ++ if (argc == 1) { ++ /* Ask about the current channel */ ++ channel = 0x0E; ++ } else if (argc == 2) { + if (is_ipmi_channel_num(argv[1], &channel) != 0) { + return (-1); + } +@@ -1961,110 +1951,71 @@ ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv) + print_sol_usage(); + return -1; + } +- + retval = ipmi_print_sol_info(intf, channel); +- } +- +- /* +- * Payload enable or disable +- */ +- else if (!strncmp(argv[0], "payload", 7)) { ++ } else if (!strncmp(argv[0], "payload", 7)) { ++ /* Payload enable or disable */ + uint8_t channel = 0xe; + uint8_t userid = 1; + int enable = -1; +- +- if (argc == 1 || argc > 4) +- { ++ if (argc == 1 || argc > 4) { + print_sol_usage(); + return -1; + } +- +- if (argc == 1 || argc > 4) +- { ++ if (argc == 1 || argc > 4) { + print_sol_usage(); + return -1; + } +- + if (argc >= 3) { + if (is_ipmi_channel_num(argv[2], &channel) != 0) { + return (-1); + } + } +- if (argc == 4) +- { ++ if (argc == 4) { + if (is_ipmi_user_id(argv[3], &userid) != 0) { + return (-1); + } + } +- +- if (!strncmp(argv[1], "enable", 6)) +- { ++ if (!strncmp(argv[1], "enable", 6)) { + enable = 1; +- } +- else if (!strncmp(argv[1], "disable", 7)) +- { ++ } else if (!strncmp(argv[1], "disable", 7)) { + enable = 0; +- } +- else if (!strncmp(argv[1], "status", 6)) +- { ++ } else if (!strncmp(argv[1], "status", 6)) { + return ipmi_sol_payload_access_status(intf, channel, userid); +- } +- else +- { ++ } else { + print_sol_usage(); + return -1; + } +- + retval = ipmi_sol_payload_access(intf, channel, userid, enable); +- } +- +- +- /* +- * Set a parameter value +- */ +- else if (!strncmp(argv[0], "set", 3)) { ++ } else if (!strncmp(argv[0], "set", 3)) { ++ /* Set a parameter value */ + uint8_t channel = 0xe; + uint8_t guard = 1; +- +- if (argc == 3) +- { ++ if (argc == 3) { + channel = 0xe; +- } +- else if (argc == 4) +- { +- if (!strncmp(argv[3], "noguard", 7)) ++ } else if (argc == 4) { ++ if (!strncmp(argv[3], "noguard", 7)) { + guard = 0; +- else { ++ } else { + if (is_ipmi_channel_num(argv[3], &channel) != 0) { + return (-1); + } + } +- } +- else if (argc == 5) +- { ++ } else if (argc == 5) { + if (is_ipmi_channel_num(argv[3], &channel) != 0) { + return (-1); + } +- if (!strncmp(argv[4], "noguard", 7)) ++ if (!strncmp(argv[4], "noguard", 7)) { + guard = 0; +- } +- else +- { ++ } ++ } else { + print_sol_set_usage(); + return -1; + } +- + retval = ipmi_sol_set_param(intf, channel, argv[1], argv[2], guard); +- } +- +- +- /* +- * Activate +- */ +- else if (!strncmp(argv[0], "activate", 8)) { ++ } else if (!strncmp(argv[0], "activate", 8)) { ++ /* Activate */ + int i; + uint8_t instance = 1; +- + for (i = 1; i < argc; i++) { + if (!strncmp(argv[i], "usesolkeepalive", 15)) { + _use_sol_for_keepalive = 1; +@@ -2082,20 +2033,16 @@ ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv) + } + } + retval = ipmi_sol_activate(intf, 0, 0, instance); +- } +- +- +- /* +- * Dectivate +- */ +- else if (!strncmp(argv[0], "deactivate", 10)) { ++ } else if (!strncmp(argv[0], "deactivate", 10)) { ++ /* Dectivate */ + int i; + uint8_t instance = 1; +- + for (i = 1; i < argc; i++) { + if (!strncmp(argv[i], "instance=", 9)) { + if (str2uchar(argv[i] + 9, &instance) != 0) { +- lprintf(LOG_ERR, "Given instance '%s' is invalid.", argv[i] + 9); ++ lprintf(LOG_ERR, ++ "Given instance '%s' is invalid.", ++ argv[i] + 9); + print_sol_usage(); + return -1; + } +@@ -2105,66 +2052,58 @@ ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv) + } + } + retval = ipmi_sol_deactivate(intf, instance); +- } +- +- /* +- * SOL loop test: Activate and then Dectivate +- */ +- else if (!strncmp(argv[0], "looptest", 8)) +- { ++ } else if (!strncmp(argv[0], "looptest", 8)) { ++ /* SOL loop test: Activate and then Dectivate */ + int cnt = 200; + int interval = 100; /* Unit is: ms */ +- uint8_t instance; +- +- if (argc > 4) +- { ++ uint8_t instance = 1; ++ if (argc > 4) { + print_sol_usage(); + return -1; + } +- if (argc != 1) /* at least 2 */ +- { ++ if (argc != 1) { ++ /* at least 2 */ + if (str2int(argv[1], &cnt) != 0) { + lprintf(LOG_ERR, "Given cnt '%s' is invalid.", + argv[1]); + return (-1); + } +- if(cnt <= 0) cnt = 200; ++ if (cnt <= 0) { ++ cnt = 200; ++ } + } +- if (argc >= 3) +- { ++ if (argc >= 3) { + if (str2int(argv[2], &interval) != 0) { + lprintf(LOG_ERR, "Given interval '%s' is invalid.", + argv[2]); + return (-1); + } +- if(interval < 0) interval = 0; ++ if (interval < 0) { ++ interval = 0; ++ } + } + if (argc >= 4) { + if (str2uchar(argv[3], &instance) != 0) { +- lprintf(LOG_ERR, "Given instance '%s' is invalid.", argv[3]); ++ lprintf(LOG_ERR, "Given instance '%s' is invalid.", ++ argv[3]); + print_sol_usage(); + return -1; + } + } + +- while (cnt > 0) +- { ++ while (cnt > 0) { + printf("remain loop test counter: %d\n", cnt); + retval = ipmi_sol_activate(intf, 1, interval, instance); +- if (retval) +- { +- printf("SOL looptest failed: %d\n", retval); ++ if (retval) { ++ printf("SOL looptest failed: %d\n", ++ retval); + break; + } + cnt -= 1; + } +- } +- +- else +- { ++ } else { + print_sol_usage(); + retval = -1; + } +- + return retval; + } +diff --git a/ipmitool/lib/ipmi_tsol.c b/ipmitool/lib/ipmi_tsol.c +index be53236..94ea284 100644 +--- a/ipmitool/lib/ipmi_tsol.c ++++ b/ipmitool/lib/ipmi_tsol.c +@@ -381,7 +381,7 @@ int + ipmi_tsol_main(struct ipmi_intf * intf, int argc, char ** argv) + { + struct pollfd fds_wait[3], fds_data_wait[3], *fds; +- struct sockaddr_in sin, myaddr; ++ struct sockaddr_in sin, myaddr, *sa_in; + socklen_t mylen; + char *recvip = NULL; + char out_buff[IPMI_BUF_SIZE * 8], in_buff[IPMI_BUF_SIZE]; +@@ -398,8 +398,11 @@ ipmi_tsol_main(struct ipmi_intf * intf, int argc, char ** argv) + } + + for (i = 0; isession->addr; + result = inet_pton(AF_INET, (const char *)intf->session->hostname, +- &intf->session->addr.sin_addr); ++ &sa_in->sin_addr); + + if (result <= 0) { + struct hostent *host = gethostbyname((const char *)intf->session->hostname); +@@ -444,8 +448,8 @@ ipmi_tsol_main(struct ipmi_intf * intf, int argc, char ** argv) + (host->h_addrtype == AF_INET6) ? "IPv6" : "Unknown"); + return (-1); + } +- intf->session->addr.sin_family = host->h_addrtype; +- memcpy(&intf->session->addr.sin_addr, host->h_addr, host->h_length); ++ sa_in->sin_family = host->h_addrtype; ++ memcpy(&sa_in->sin_addr, host->h_addr, host->h_length); + } + + fd_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); +@@ -455,6 +459,7 @@ ipmi_tsol_main(struct ipmi_intf * intf, int argc, char ** argv) + } + if (-1 == bind(fd_socket, (struct sockaddr *)&sin, sizeof(sin))) { + lprintf(LOG_ERR, "Failed to bind socket."); ++ close(fd_socket); + return -1; + } + +diff --git a/ipmitool/src/plugins/Makefile.am b/ipmitool/src/plugins/Makefile.am +index 9d5c2c2..19b5f11 100644 +--- a/ipmitool/src/plugins/Makefile.am ++++ b/ipmitool/src/plugins/Makefile.am +@@ -32,8 +32,8 @@ MAINTAINERCLEANFILES = Makefile.in + + INCLUDES = -I$(top_srcdir)/include + +-SUBDIRS = @INTF_LAN@ @INTF_LANPLUS@ @INTF_OPEN@ @INTF_LIPMI@ @INTF_IMB@ @INTF_BMC@ @INTF_FREE@ @INTF_SERIAL@ +-DIST_SUBDIRS = lan lanplus open lipmi imb bmc free serial ++SUBDIRS = @INTF_LAN@ @INTF_LANPLUS@ @INTF_OPEN@ @INTF_LIPMI@ @INTF_IMB@ @INTF_BMC@ @INTF_FREE@ @INTF_SERIAL@ @INTF_DUMMY@ ++DIST_SUBDIRS = lan lanplus open lipmi imb bmc free serial dummy + + noinst_LTLIBRARIES = libintf.la + libintf_la_SOURCES = ipmi_intf.c +diff --git a/ipmitool/src/plugins/dummy/Makefile.am b/ipmitool/src/plugins/dummy/Makefile.am +new file mode 100644 +index 0000000..8a53bbe +--- /dev/null ++++ b/ipmitool/src/plugins/dummy/Makefile.am +@@ -0,0 +1,8 @@ ++MAINTAINERCLEANFILES = Makefile.in ++ ++INCLUDES = -I$(top_srcdir)/include ++ ++EXTRA_LTLIBRARIES = libintf_dummy.la ++noinst_LTLIBRARIES = @INTF_DUMMY_LIB@ ++libintf_dummy_la_LIBADD = $(top_builddir)/lib/libipmitool.la ++libintf_dummy_la_SOURCES = dummy.c +diff --git a/ipmitool/src/plugins/dummy/dummy.c b/ipmitool/src/plugins/dummy/dummy.c +new file mode 100644 +index 0000000..eb2d086 +--- /dev/null ++++ b/ipmitool/src/plugins/dummy/dummy.c +@@ -0,0 +1,286 @@ ++/* Copyright (c) 2013 Zdenek Styblik, All Rights Reserved ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * Redistribution of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * Redistribution 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. ++ * ++ * Neither the name of Zdenek Styblik or the names of ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * This software is provided "AS IS," without a warranty of any kind. ++ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, ++ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A ++ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. ++ * Zdenek Styblik SHALL NOT BE LIABLE ++ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING ++ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL ++ * Zdenek Styblik BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, ++ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR ++ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF ++ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, ++ * EVEN IF Zdenek Styblik HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "dummy.h" ++ ++#if defined(HAVE_CONFIG_H) ++# include ++#endif ++ ++extern int verbose; ++ ++/* data_read - read data from socket ++ * ++ * @data_ptr - pointer to memory where to store read data ++ * @data_len - how much to read from socket ++ * ++ * return 0 on success, otherwise (-1) ++ */ ++int ++data_read(int fd, void *data_ptr, int data_len) ++{ ++ int rc = 0; ++ int data_read = 0; ++ int data_total = 0; ++ int try = 1; ++ int errno_save = 0; ++ if (data_len < 0) { ++ return (-1); ++ } ++ while (data_total < data_len && try < 4) { ++ errno = 0; ++ /* TODO - add poll() */ ++ data_read = read(fd, data_ptr, data_len); ++ errno_save = errno; ++ if (data_read > 0) { ++ data_total+= data_read; ++ } ++ if (errno_save != 0) { ++ if (errno_save == EINTR || errno_save == EAGAIN) { ++ try++; ++ sleep(2); ++ continue; ++ } else { ++ errno = errno_save; ++ perror("dummy failed on read(): "); ++ rc = (-1); ++ break; ++ } ++ } ++ } ++ if (try > 3 && data_total != data_len) { ++ rc = (-1); ++ } ++ return rc; ++} ++ ++/* data_write - write data to the socket ++ * ++ * @data_ptr - ptr to data to send ++ * @data_len - how long is the data to send ++ * ++ * returns 0 on success, otherwise (-1) ++ */ ++int ++data_write(int fd, void *data_ptr, int data_len) ++{ ++ int rc = 0; ++ int data_written = 0; ++ int data_total = 0; ++ int try = 1; ++ int errno_save = 0; ++ if (data_len < 0) { ++ return (-1); ++ } ++ while (data_total < data_len && try < 4) { ++ errno = 0; ++ /* TODO - add poll() */ ++ data_written = write(fd, data_ptr, data_len); ++ errno_save = errno; ++ if (data_read > 0) { ++ data_total+= data_written; ++ } ++ if (errno_save != 0) { ++ if (errno_save == EINTR || errno_save == EAGAIN) { ++ try++; ++ sleep(2); ++ continue; ++ } else { ++ errno = errno_save; ++ perror("dummy failed on read(): "); ++ rc = (-1); ++ break; ++ } ++ } ++ } ++ if (try > 3 && data_total != data_len) { ++ rc = (-1); ++ } ++ return rc; ++} ++ ++/* ipmi_dummyipmi_close - send "BYE" and close socket ++ * ++ * @intf - ptr to initialize ipmi_intf struct ++ * ++ * returns void ++ */ ++static void ++ipmi_dummyipmi_close(struct ipmi_intf *intf) ++{ ++ struct dummy_rq req; ++ int data_total = 0; ++ int data_written = 0; ++ int try = 0; ++ if (intf->fd < 0) { ++ return; ++ } ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = 0x3f; ++ req.msg.cmd = 0xff; ++ if (data_write(intf->fd, &req, sizeof(req)) != 0) { ++ lprintf(LOG_ERR, "dummy failed to send 'BYE'"); ++ } ++ close(intf->fd); ++ intf->fd = (-1); ++ intf->opened = 0; ++} ++ ++/* ipmi_dummyipmi_open - open socket and prepare ipmi_intf struct ++ * ++ * @intf - ptr to ipmi_inf struct ++ * ++ * returns 0 on success, (-1) on error ++ */ ++static int ++ipmi_dummyipmi_open(struct ipmi_intf *intf) ++{ ++ struct sockaddr_un address; ++ int len; ++ int rc; ++ ++ if (intf->opened == 1) { ++ return intf->fd; ++ } ++ intf->fd = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (intf->fd == (-1)) { ++ lprintf(LOG_ERR, "dummy failed on socket()"); ++ return (-1); ++ } ++ address.sun_family = AF_UNIX; ++ strcpy(address.sun_path, DUMMY_SOCKET_PATH); ++ len = sizeof(address); ++ rc = connect(intf->fd, (struct sockaddr *)&address, len); ++ if (rc != 0) { ++ perror("dummy failed on connect(): "); ++ return (-1); ++ } ++ intf->opened = 1; ++ return intf->fd; ++} ++ ++/* ipmi_dummyipmi_send_cmd - send IPMI payload and await reply ++ * ++ * @intf - ptr to initialized ipmi_intf struct ++ * @req - ptr to ipmi_rq struct to send ++ * ++ * return pointer to struct ipmi_rs OR NULL on error ++ */ ++static struct ipmi_rs* ++ipmi_dummyipmi_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req) ++{ ++ static struct ipmi_rs rsp; ++ struct dummy_rq req_dummy; ++ struct dummy_rs rsp_dummy; ++ if (intf == NULL || intf->fd < 0 || intf->opened != 1) { ++ lprintf(LOG_ERR, "dummy failed on intf check."); ++ return NULL; ++ } ++ ++ memset(&req_dummy, 0, sizeof(req_dummy)); ++ req_dummy.msg.netfn = req->msg.netfn; ++ req_dummy.msg.lun = req->msg.lun; ++ req_dummy.msg.cmd = req->msg.cmd; ++ req_dummy.msg.target_cmd = req->msg.target_cmd; ++ req_dummy.msg.data_len = req->msg.data_len; ++ req_dummy.msg.data = req->msg.data; ++ if (verbose) { ++ lprintf(LOG_NOTICE, ">>> IPMI req"); ++ lprintf(LOG_NOTICE, "msg.data_len: %i", ++ req_dummy.msg.data_len); ++ lprintf(LOG_NOTICE, "msg.netfn: %x", req_dummy.msg.netfn); ++ lprintf(LOG_NOTICE, "msg.cmd: %x", req_dummy.msg.cmd); ++ lprintf(LOG_NOTICE, "msg.target_cmd: %x", ++ req_dummy.msg.target_cmd); ++ lprintf(LOG_NOTICE, "msg.lun: %x", req_dummy.msg.lun); ++ lprintf(LOG_NOTICE, ">>>"); ++ } ++ if (data_write(intf->fd, &req_dummy, ++ sizeof(struct dummy_rq)) != 0) { ++ return NULL; ++ } ++ if (req->msg.data_len > 0) { ++ if (data_write(intf->fd, (uint8_t *)(req->msg.data), ++ req_dummy.msg.data_len) != 0) { ++ return NULL; ++ } ++ } ++ ++ memset(&rsp_dummy, 0, sizeof(rsp_dummy)); ++ if (data_read(intf->fd, &rsp_dummy, sizeof(struct dummy_rs)) != 0) { ++ return NULL; ++ } ++ if (rsp_dummy.data_len > 0) { ++ if (data_read(intf->fd, (uint8_t *)&rsp.data, ++ rsp_dummy.data_len) != 0) { ++ return NULL; ++ } ++ } ++ rsp.ccode = rsp_dummy.ccode; ++ rsp.data_len = rsp_dummy.data_len; ++ rsp.msg.netfn = rsp_dummy.msg.netfn; ++ rsp.msg.cmd = rsp_dummy.msg.cmd; ++ rsp.msg.seq = rsp_dummy.msg.seq; ++ rsp.msg.lun = rsp_dummy.msg.lun; ++ if (verbose) { ++ lprintf(LOG_NOTICE, "<<< IPMI rsp"); ++ lprintf(LOG_NOTICE, "ccode: %x", rsp.ccode); ++ lprintf(LOG_NOTICE, "data_len: %i", rsp.data_len); ++ lprintf(LOG_NOTICE, "msg.netfn: %x", rsp.msg.netfn); ++ lprintf(LOG_NOTICE, "msg.cmd: %x", rsp.msg.cmd); ++ lprintf(LOG_NOTICE, "msg.seq: %x", rsp.msg.seq); ++ lprintf(LOG_NOTICE, "msg.lun: %x", rsp.msg.lun); ++ lprintf(LOG_NOTICE, "<<<"); ++ } ++ return &rsp; ++} ++ ++struct ipmi_intf ipmi_dummy_intf = { ++ name: "dummy", ++ desc: "Linux DummyIPMI Interface", ++ open: ipmi_dummyipmi_open, ++ close: ipmi_dummyipmi_close, ++ sendrecv: ipmi_dummyipmi_send_cmd, ++ my_addr: IPMI_BMC_SLAVE_ADDR, ++ target_addr: IPMI_BMC_SLAVE_ADDR, ++}; +diff --git a/ipmitool/src/plugins/dummy/dummy.h b/ipmitool/src/plugins/dummy/dummy.h +new file mode 100644 +index 0000000..dac9caa +--- /dev/null ++++ b/ipmitool/src/plugins/dummy/dummy.h +@@ -0,0 +1,30 @@ ++#ifndef IPMI_DUMMYIPMI_H ++# define IPMI_DUMMYIPMI_H ++ ++# define DUMMY_SOCKET_PATH "/tmp/.ipmi_dummy" ++ ++struct dummy_rq { ++ struct { ++ uint8_t netfn; ++ uint8_t lun; ++ uint8_t cmd; ++ uint8_t target_cmd; ++ uint16_t data_len; ++ uint8_t *data; ++ } msg; ++}; ++ ++struct dummy_rs { ++ struct { ++ uint8_t netfn; ++ uint8_t cmd; ++ uint8_t seq; ++ uint8_t lun; ++ } msg; ++ ++ uint8_t ccode; ++ int data_len; ++ uint8_t *data; ++}; ++ ++#endif +diff --git a/ipmitool/src/plugins/ipmi_intf.c b/ipmitool/src/plugins/ipmi_intf.c +index d0c483a..48e2b61 100644 +--- a/ipmitool/src/plugins/ipmi_intf.c ++++ b/ipmitool/src/plugins/ipmi_intf.c +@@ -36,6 +36,18 @@ + #if defined(HAVE_CONFIG_H) + # include + #endif ++ ++#if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS) ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++ + #include + #include + #include +@@ -66,6 +78,9 @@ extern struct ipmi_intf ipmi_free_intf; + extern struct ipmi_intf ipmi_serial_term_intf; + extern struct ipmi_intf ipmi_serial_bm_intf; + #endif ++#ifdef IPMI_INTF_DUMMY ++extern struct ipmi_intf ipmi_dummy_intf; ++#endif + + struct ipmi_intf * ipmi_intf_table[] = { + #ifdef IPMI_INTF_OPEN +@@ -93,6 +108,9 @@ struct ipmi_intf * ipmi_intf_table[] = { + &ipmi_serial_term_intf, + &ipmi_serial_bm_intf, + #endif ++#ifdef IPMI_INTF_DUMMY ++ &ipmi_dummy_intf, ++#endif + NULL + }; + +@@ -315,3 +333,167 @@ ipmi_cleanup(struct ipmi_intf * intf) + { + ipmi_sdr_list_empty(intf); + } ++ ++#if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS) ++int ++ipmi_intf_socket_connect(struct ipmi_intf * intf) ++{ ++ struct ipmi_session *session; ++ ++ struct sockaddr_storage addr; ++ struct addrinfo hints; ++ struct addrinfo *rp0 = NULL, *rp; ++ char service[NI_MAXSERV]; ++ int rc; ++ ++ if (!intf || intf->session == NULL) { ++ return -1; ++ } ++ ++ session = intf->session; ++ ++ if (session->hostname == NULL || strlen((const char *)session->hostname) == 0) { ++ lprintf(LOG_ERR, "No hostname specified!"); ++ return -1; ++ } ++ ++ /* open port to BMC */ ++ memset(&addr, 0, sizeof(addr)); ++ ++ sprintf(service, "%d", session->port); ++ /* Obtain address(es) matching host/port */ ++ memset(&hints, 0, sizeof(hints)); ++ hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ ++ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ ++ hints.ai_flags = 0; /* use AI_NUMERICSERV for no name resolution */ ++ hints.ai_protocol = IPPROTO_UDP; /* */ ++ ++ if (getaddrinfo(session->hostname, service, &hints, &rp0) != 0) { ++ lprintf(LOG_ERR, "Address lookup for %s failed", ++ session->hostname); ++ return -1; ++ } ++ ++ /* getaddrinfo() returns a list of address structures. ++ * Try each address until we successfully connect(2). ++ * If socket(2) (or connect(2)) fails, we (close the socket ++ * and) try the next address. ++ */ ++ ++ session->ai_family = AF_UNSPEC; ++ for (rp = rp0; rp != NULL; rp = rp->ai_next) { ++ /* We are only interested in IPv4 and IPv6 */ ++ if ((rp->ai_family != AF_INET6) && (rp->ai_family != AF_INET)) { ++ continue; ++ } ++ ++ intf->fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); ++ if (intf->fd == -1) { ++ continue; ++ } ++ ++ if (rp->ai_family == AF_INET) { ++ if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) { ++ memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen); ++ session->addrlen = rp->ai_addrlen; ++ session->ai_family = rp->ai_family; ++ break; /* Success */ ++ } ++ } else if (rp->ai_family == AF_INET6) { ++ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)rp->ai_addr; ++ char hbuf[NI_MAXHOST]; ++ socklen_t len; ++ ++ /* The scope was specified on the command line e.g. with -H FE80::219:99FF:FEA0:BD95%eth0 */ ++ if (addr6->sin6_scope_id != 0) { ++ len = sizeof(struct sockaddr_in6); ++ if (getnameinfo((struct sockaddr *)addr6, len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0) { ++ lprintf(LOG_DEBUG, "Trying address: %s scope=%d", ++ hbuf, ++ addr6->sin6_scope_id); ++ } ++ if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) { ++ memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen); ++ session->addrlen = rp->ai_addrlen; ++ session->ai_family = rp->ai_family; ++ break; /* Success */ ++ } ++ } else { ++ /* No scope specified, try to get this from the list of interfaces */ ++ struct ifaddrs *ifaddrs = NULL; ++ struct ifaddrs *ifa = NULL; ++ ++ if (getifaddrs(&ifaddrs) < 0) { ++ lprintf(LOG_ERR, "Interface address lookup for %s failed", ++ session->hostname); ++ break; ++ } ++ ++ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { ++ if (ifa->ifa_addr == NULL) { ++ continue; ++ } ++ ++ if (ifa->ifa_addr->sa_family == AF_INET6) { ++ struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *)ifa->ifa_addr; ++ ++ /* Skip unwanted addresses */ ++ if (IN6_IS_ADDR_MULTICAST(&tmp6->sin6_addr)) { ++ continue; ++ } ++ if (IN6_IS_ADDR_LOOPBACK(&tmp6->sin6_addr)) { ++ continue; ++ } ++ len = sizeof(struct sockaddr_in6); ++ if ( getnameinfo((struct sockaddr *)tmp6, len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0) { ++ lprintf(LOG_DEBUG, "Testing %s interface address: %s scope=%d", ++ ifa->ifa_name != NULL ? ifa->ifa_name : "???", ++ hbuf, ++ tmp6->sin6_scope_id); ++ } ++ ++ if (tmp6->sin6_scope_id != 0) { ++ addr6->sin6_scope_id = tmp6->sin6_scope_id; ++ } else { ++ /* ++ * No scope information in interface address information ++ * On some OS'es, getifaddrs() is returning out the 'kernel' representation ++ * of scoped addresses which stores the scope in the 3rd and 4th ++ * byte. See also this page: ++ * http://www.freebsd.org/doc/en/books/developers-handbook/ipv6.html ++ */ ++ if (IN6_IS_ADDR_LINKLOCAL(&tmp6->sin6_addr) ++ && (tmp6->sin6_addr.s6_addr16[1] != 0)) { ++ addr6->sin6_scope_id = ntohs(tmp6->sin6_addr.s6_addr16[1]); ++ } ++ } ++ ++ /* OK, now try to connect with the scope id from this interface address */ ++ if (addr6->sin6_scope_id != 0) { ++ if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) { ++ memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen); ++ session->addrlen = rp->ai_addrlen; ++ session->ai_family = rp->ai_family; ++ lprintf(LOG_DEBUG, "Successful connected on %s interface with scope id %d", ifa->ifa_name, tmp6->sin6_scope_id); ++ break; /* Success */ ++ } ++ } ++ } ++ } ++ freeifaddrs(ifaddrs); ++ } ++ } ++ if (session->ai_family != AF_UNSPEC) { ++ break; ++ } ++ close(intf->fd); ++ intf->fd = -1; ++ } ++ ++ /* No longer needed */ ++ freeaddrinfo(rp0); ++ ++ return ((intf->fd != -1) ? 0 : -1); ++} ++#endif ++ +diff --git a/ipmitool/src/plugins/lan/lan.c b/ipmitool/src/plugins/lan/lan.c +index e088479..fc90000 100644 +--- a/ipmitool/src/plugins/lan/lan.c ++++ b/ipmitool/src/plugins/lan/lan.c +@@ -2032,44 +2032,14 @@ ipmi_lan_open(struct ipmi_intf * intf) + + intf->session->sol_data.sequence_number = 1; + +- /* open port to BMC */ +- memset(&s->addr, 0, sizeof(struct sockaddr_in)); +- s->addr.sin_family = AF_INET; +- s->addr.sin_port = htons(s->port); +- +- rc = inet_pton(AF_INET, (const char *)s->hostname, &s->addr.sin_addr); +- if (rc <= 0) { +- struct hostent *host = gethostbyname((const char *)s->hostname); +- if (host == NULL) { +- lprintf(LOG_ERR, "Address lookup for %s failed", +- s->hostname); +- return -1; +- } +- if (host->h_addrtype != AF_INET) { +- lprintf(LOG_ERR, +- "Address lookup for %s failed. Got %s, expected IPv4 address.", +- s->hostname, +- (host->h_addrtype == AF_INET6) ? "IPv6" : "Unknown"); +- return (-1); +- } +- s->addr.sin_family = host->h_addrtype; +- memcpy(&s->addr.sin_addr, host->h_addr, host->h_length); +- } +- +- lprintf(LOG_DEBUG, "IPMI LAN host %s port %d", +- s->hostname, ntohs(s->addr.sin_port)); +- +- intf->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); +- if (intf->fd < 0) { +- lperror(LOG_ERR, "Socket failed"); ++ if (ipmi_intf_socket_connect (intf) == -1) { ++ lprintf(LOG_ERR, "Could not open socket!"); + return -1; + } + +- /* connect to UDP socket so we get async errors */ +- rc = connect(intf->fd, (struct sockaddr *)&s->addr, +- sizeof(struct sockaddr_in)); +- if (rc < 0) { +- lperror(LOG_ERR, "Connect failed"); ++ if (intf->fd < 0) { ++ lperror(LOG_ERR, "Connect to %s failed", ++ s->hostname); + intf->close(intf); + return -1; + } +diff --git a/ipmitool/src/plugins/lanplus/lanplus.c b/ipmitool/src/plugins/lanplus/lanplus.c +index acf2410..17d42a4 100644 +--- a/ipmitool/src/plugins/lanplus/lanplus.c ++++ b/ipmitool/src/plugins/lanplus/lanplus.c +@@ -84,14 +84,14 @@ static struct ipmi_rs * ipmi_lanplus_send_ipmi_cmd(struct ipmi_intf * intf, stru + static struct ipmi_rs * ipmi_lanplus_send_payload(struct ipmi_intf * intf, + struct ipmi_v2_payload * payload); + static void getIpmiPayloadWireRep( +- struct ipmi_intf * intf, +- struct ipmi_v2_payload * payload, /* in */ ++ struct ipmi_intf * intf, ++ struct ipmi_v2_payload * payload, /* in */ + uint8_t * out, + struct ipmi_rq * req, + uint8_t rq_seq, +- uint8_t curr_seq); ++ uint8_t curr_seq); + static void getSolPayloadWireRep( +- struct ipmi_intf * intf, ++ struct ipmi_intf * intf, + uint8_t * msg, + struct ipmi_v2_payload * payload); + static void read_open_session_response(struct ipmi_rs * rsp, int offset); +@@ -113,7 +113,7 @@ static void ack_sol_packet( + struct ipmi_intf * intf, + struct ipmi_rs * rsp); + +-static uint8_t bridgePossible = 0; ++static uint8_t bridgePossible = 0; + + struct ipmi_intf ipmi_lanplus_intf = { + name: "lanplus", +@@ -2174,7 +2174,8 @@ ipmi_lanplus_send_payload( + else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST) + { + lprintf(LOG_DEBUG, ">> SENDING AN OPEN SESSION REQUEST\n"); +- assert(session->v2_data.session_state == LANPLUS_STATE_PRESESSION); ++ assert(session->v2_data.session_state == LANPLUS_STATE_PRESESSION ++ || session->v2_data.session_state == LANPLUS_STATE_OPEN_SESSION_SENT); + + ipmi_lanplus_build_v2x_msg(intf, /* in */ + payload, /* in */ +@@ -2858,7 +2859,10 @@ ipmi_lanplus_open_session(struct ipmi_intf * intf) + + free(msg); + msg = NULL; +- ++ if (!rsp) { ++ lprintf(LOG_WARNING, "Error sending open session message."); ++ return -1; ++ } + if (verbose) + lanplus_dump_open_session_response(rsp); + +@@ -3334,7 +3338,6 @@ ipmi_lanplus_open(struct ipmi_intf * intf) + { + int rc; + struct get_channel_auth_cap_rsp auth_cap; +- struct sockaddr_in addr; + struct ipmi_session *session; + + if (!intf || !intf->session) +@@ -3373,46 +3376,14 @@ ipmi_lanplus_open(struct ipmi_intf * intf) + /* Kg is set in ipmi_intf */ + //memset(session->v2_data.kg, 0, IPMI_KG_BUFFER_SIZE); + +- +- /* open port to BMC */ +- memset(&addr, 0, sizeof(struct sockaddr_in)); +- addr.sin_family = AF_INET; +- addr.sin_port = htons(session->port); +- +- rc = inet_pton(AF_INET, (const char *)session->hostname, &addr.sin_addr); +- if (rc <= 0) { +- struct hostent *host = gethostbyname((const char *)session->hostname); +- if (host == NULL) { +- lprintf(LOG_ERR, "Address lookup for %s failed", +- session->hostname); +- return -1; +- } +- if (host->h_addrtype != AF_INET) { +- lprintf(LOG_ERR, +- "Address lookup for %s failed. Got %s, expected IPv4 address.", +- session->hostname, +- (host->h_addrtype == AF_INET6) ? "IPv6" : "Unknown"); +- return (-1); +- } +- addr.sin_family = host->h_addrtype; +- memcpy(&addr.sin_addr, host->h_addr, host->h_length); +- } +- +- lprintf(LOG_DEBUG, "IPMI LAN host %s port %d", +- session->hostname, ntohs(addr.sin_port)); +- +- intf->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); +- if (intf->fd < 0) { +- lperror(LOG_ERR, "Socket failed"); ++ if (ipmi_intf_socket_connect (intf) == -1) { ++ lprintf(LOG_ERR, "Could not open socket!"); + return -1; + } + +- +- /* connect to UDP socket so we get async errors */ +- rc = connect(intf->fd, +- (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); +- if (rc < 0) { +- lperror(LOG_ERR, "Connect failed"); ++ if (intf->fd < 0) { ++ lperror(LOG_ERR, "Connect to %s failed", ++ session->hostname); + intf->close(intf); + return -1; + } +diff --git a/ipmitool/src/plugins/open/open.c b/ipmitool/src/plugins/open/open.c +index 5567992..0fd8c9e 100644 +--- a/ipmitool/src/plugins/open/open.c ++++ b/ipmitool/src/plugins/open/open.c +@@ -187,8 +187,9 @@ ipmi_openipmi_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req) + /* use IPMB address if needed */ + ipmb_addr.slave_addr = intf->target_addr; + ipmb_addr.lun = req->msg.lun; +- lprintf(LOG_DEBUG, "Sending request to " ++ lprintf(LOG_DEBUG, "Sending request 0x%x to " + "IPMB target @ 0x%x:0x%x (from 0x%x)", ++ req->msg.cmd, + intf->target_addr,intf->target_channel, intf->my_addr); + + if(intf->transit_addr != 0 && intf->transit_addr != intf->my_addr) { +@@ -257,8 +258,8 @@ ipmi_openipmi_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req) + _req.addr_len = sizeof(ipmb_addr); + } else { + /* otherwise use system interface */ +- lprintf(LOG_DEBUG+2, "Sending request to " +- "System Interface"); ++ lprintf(LOG_DEBUG+2, "Sending request 0x%x to " ++ "System Interface", req->msg.cmd); + bmc_addr.lun = req->msg.lun; + _req.addr = (unsigned char *) &bmc_addr; + _req.addr_len = sizeof(bmc_addr); +diff --git a/ipmitool/src/plugins/serial/serial_basic.c b/ipmitool/src/plugins/serial/serial_basic.c +index 55681ab..23c98b7 100644 +--- a/ipmitool/src/plugins/serial/serial_basic.c ++++ b/ipmitool/src/plugins/serial/serial_basic.c +@@ -266,8 +266,14 @@ serial_bm_open(struct ipmi_intf * intf) + + /* no flow control */ + ti.c_cflag &= ~CRTSCTS; +- ti.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL | IUCLC | INPCK | ISTRIP ++ ti.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL | INPCK | ISTRIP + | IXON | IXOFF | IXANY); ++#ifdef IUCLC ++ /* Only disable uppercase-to-lowercase mapping on input for ++ platforms supporting the flag. */ ++ ti.c_iflag &= ~(IUCLC); ++#endif ++ + + ti.c_oflag &= ~(OPOST); + ti.c_lflag &= ~(ICANON | ISIG | ECHO | ECHONL | NOFLSH); +@@ -323,7 +329,13 @@ serial_bm_alloc_seq(void) + static int + serial_bm_flush(struct ipmi_intf * intf) + { +- return ioctl(intf->fd, TCFLSH, TCIOFLUSH); ++#if defined(TCFLSH) ++ return ioctl(intf->fd, TCFLSH, TCIOFLUSH); ++#elif defined(TIOCFLUSH) ++ return ioctl(intf->fd, TIOCFLUSH); ++#else ++# error "unsupported platform, missing flush support (TCFLSH/TIOCFLUSH)" ++#endif + } + + /* +diff --git a/ipmitool/src/plugins/serial/serial_terminal.c b/ipmitool/src/plugins/serial/serial_terminal.c +index 10ed942..c82073e 100644 +--- a/ipmitool/src/plugins/serial/serial_terminal.c ++++ b/ipmitool/src/plugins/serial/serial_terminal.c +@@ -211,8 +211,13 @@ ipmi_serial_term_open(struct ipmi_intf * intf) + + /* no flow control */ + ti.c_cflag &= ~CRTSCTS; +- ti.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL | IUCLC | INPCK | ISTRIP ++ ti.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL | INPCK | ISTRIP + | IXON | IXOFF | IXANY); ++#ifdef IUCLC ++ /* Only disable uppercase-to-lowercase mapping on input for ++ platforms supporting the flag. */ ++ ti.c_iflag &= ~(IUCLC); ++#endif + + ti.c_oflag &= ~(OPOST); + ti.c_lflag &= ~(ICANON | ISIG | ECHO | ECHONL | NOFLSH); +@@ -337,7 +342,14 @@ serial_write_line(struct ipmi_intf * intf, const char *str) + static int + serial_flush(struct ipmi_intf * intf) + { ++#if defined(TCFLSH) + return ioctl(intf->fd, TCFLSH, TCIOFLUSH); ++#elif defined(TIOCFLUSH) ++ return ioctl(intf->fd, TIOCFLUSH); ++#else ++# error "unsupported platform, missing flush support (TCFLSH/TIOCFLUSH)" ++#endif ++ + } + + /*