summaryrefslogtreecommitdiff
path: root/util/ifwum.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/ifwum.c')
-rw-r--r--util/ifwum.c1697
1 files changed, 1697 insertions, 0 deletions
diff --git a/util/ifwum.c b/util/ifwum.c
new file mode 100644
index 0000000..1e7d547
--- /dev/null
+++ b/util/ifwum.c
@@ -0,0 +1,1697 @@
+/*
+ * ifwum.c
+ * Handle firmware update manager IPMI command functions
+ *
+ * Change history:
+ * 08/20/2010 ARCress - ported from ipmitool/lib/ipmi_fwum.c
+ *
+ *---------------------------------------------------------------------
+ */
+/*
+ * Copyright (c) 2004 Kontron Canada, Inc. All Rights Reserved.
+ *
+ * Base on code from
+ * Copyright (c) 2003 Sun Microsystems, Inc. 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 Sun Microsystems, Inc. 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.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS 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
+ * SUN OR ITS LICENSORS 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 SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#include "getopt.h"
+#elif defined(HPUX)
+/* getopt defined in stdio.h */
+#elif defined(MACOS)
+/* getopt is defined in unistd.h */
+#include <unistd.h>
+#else
+#include <getopt.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#ifdef LINUX
+#include <unistd.h>
+#endif
+#include "ipmicmd.h"
+#include "ifwum.h"
+
+/******************************************************************************
+* 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
+*
+*****************************************************************************/
+
+extern int verbose; /*see ipmilanplus.c*/
+extern void lprintf(int level, const char * format, ...); /*ipmilanplus.c*/
+// extern int ipmi_sendrecv(struct ipmi_rq * req, uint8_t *rsp, int *rsp_len);
+extern char * get_mfg_str(uchar *rgmfg, int *pmfg); /*ihealth.c*/
+#ifndef HAVE_LANPLUS
+/* define these routines here if no lanplus/helper.c */
+extern uint16_t buf2short(uint8_t * buf); /*ipmilanplus.c*/
+// const char * val2str(uint16_t val, const struct valstr *vs);
+#endif
+
+#define VERSION_MAJ 1
+#define VERSION_MIN 3
+
+/* global variables */
+static char * progname = "ifwum";
+static char * progver = "1.3";
+static char fdebug = 0;
+static uchar g_bus = PUBLIC_BUS;
+static uchar g_sa = BMC_SA;
+static uchar g_lun = BMC_LUN;
+static uchar g_addrtype = ADDR_SMI;
+
+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;
+
+
+#define KFWUM_STATUS_OK 0
+#define KFWUM_STATUS_ERROR -1
+typedef int tKFWUM_Status;
+//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;
+
+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;
+ 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
+
+static unsigned char fileName[512];
+static unsigned char firmBuf[1024*512];
+static tKFWUM_SaveFirmwareInfo saveFirmwareInfo;
+
+static void KfwumOutputHelp(void);
+static int KfwumMain(void * 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(void * intf, unsigned char output,
+ unsigned char *pNumBank);
+static tKFWUM_Status KfwumGetDeviceInfo(void * intf,
+ unsigned char output, tKFWUM_BoardInfo * pBoardInfo);
+static tKFWUM_Status KfwumGetStatus(void * intf);
+static tKFWUM_Status KfwumManualRollback(void * intf);
+static tKFWUM_Status KfwumStartFirmwareImage(void * intf,
+ unsigned long length,unsigned short padding);
+static tKFWUM_Status KfwumSaveFirmwareImage(void * intf,
+ unsigned char sequenceNumber, unsigned long address,
+ unsigned char *pFirmBuf, unsigned char * pInBufLength);
+static tKFWUM_Status KfwumFinishFirmwareImage(void * intf,
+ tKFWUM_InFirmwareInfo firmInfo);
+static tKFWUM_Status KfwumUploadFirmware(void * intf,
+ unsigned char * pBuffer, unsigned long totalSize);
+static tKFWUM_Status KfwumStartFirmwareUpgrade(void * intf);
+
+static tKFWUM_Status KfwumGetInfoFromFirmware(unsigned char * pBuf,
+ unsigned long bufSize, tKFWUM_InFirmwareInfo * pInfo);
+static void KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo * pInfo);
+
+static tKFWUM_Status KfwumGetTraceLog(void * intf);
+
+tKFWUM_Status KfwumValidFirmwareForBoard(tKFWUM_BoardInfo boardInfo,
+ tKFWUM_InFirmwareInfo firmInfo);
+static void KfwumOutputInfo(tKFWUM_BoardInfo boardInfo,
+ tKFWUM_InFirmwareInfo firmInfo);
+
+
+/* ipmi_fwum_main - entry point for this ipmitool mode
+ *
+ * @intf: ipmi interface
+ * @arc : number of arguments
+ * @argv : point to argument array
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int ipmi_fwum_main(void * intf, int argc, char ** argv)
+{
+ int rv = ERR_USAGE; /*1*/
+ 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))
+ {
+ rv = KfwumMain(intf, KFWUM_TASK_INFO);
+ }
+ else if (!strncmp(argv[0], "status", 6))
+ {
+ rv = KfwumMain(intf, KFWUM_TASK_STATUS);
+ }
+ else if (!strncmp(argv[0], "rollback", 8))
+ {
+ rv = 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);
+
+ rv = 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);
+ rv = KfwumMain(intf, KFWUM_TASK_UPGRADE);
+ }
+ else
+ {
+ fprintf(stderr,"File name must be smaller than 512 bytes\n");
+ }
+ }
+ else
+ {
+ rv = KfwumMain(intf, KFWUM_TASK_START_UPGRADE);
+ }
+
+ }
+ else if (!strncmp(argv[0], "tracelog", 8))
+ {
+ rv = KfwumMain(intf, KFWUM_TASK_TRACELOG);
+ }
+ else
+ {
+ printf("Invalid KFWUM command: %s\n", argv[0]);
+ }
+ }
+ return rv;
+}
+
+
+static void KfwumOutputHelp(void)
+{
+ printf("KFWUM Commands: info status download upgrade rollback tracelog\n");
+}
+
+
+/****************************************/
+/** 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
+} 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 int KfwumMain(void * intf, tKFWUM_Task task)
+{
+ 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");
+ }
+ status = KfwumGetDeviceInfo(intf, 1, &boardInfo);
+ status = KfwumGetInfo(intf, 1, &notUsed);
+
+ }
+
+
+ if((status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_STATUS))
+ {
+ if(verbose)
+ {
+ printf("Getting Kontron FWUM Status\n");
+ }
+ status = 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, &notUsed);
+ }
+
+ 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);
+ }
+
+ return(status);
+}
+
+/* KfwumGetFileSize - gets the file size
+ *
+ * @pFileName : filename ptr
+ * @pFileSize : output ptr for filesize
+ *
+ * returns KFWUM_STATUS_OK or KFWUM_STATUS_ERROR
+ */
+static tKFWUM_Status KfwumGetFileSize(unsigned 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);
+}
+
+/* KfwumSetupBuffersFromFile - small buffers are used to store the file data
+ *
+ * @pFileName : filename ptr
+ * unsigned long : filesize
+ *
+ * returns KFWUM_STATUS_OK or KFWUM_STATUS_ERROR
+ */
+#define MAX_FW_BUFFER_SIZE 1024*16
+static tKFWUM_Status KfwumSetupBuffersFromFile(unsigned char * pFileName,
+ unsigned long fileSize)
+{
+ tKFWUM_Status status = KFWUM_STATUS_OK;
+ FILE * pFileHandle;
+
+ pFileHandle = fopen((const char *)pFileName, "rb");
+
+ if(pFileHandle)
+ {
+ int count = fileSize / MAX_FW_BUFFER_SIZE;
+ int modulus = fileSize % MAX_FW_BUFFER_SIZE;
+ int qty =0;
+
+ rewind(pFileHandle);
+
+ for(qty=0;qty<count;qty++)
+ {
+ KfwumShowProgress((const unsigned char *)"Reading Firmware from File", qty, count );
+ if(fread(&firmBuf[qty*MAX_FW_BUFFER_SIZE], 1, MAX_FW_BUFFER_SIZE ,pFileHandle)
+ == MAX_FW_BUFFER_SIZE)
+ {
+ status = KFWUM_STATUS_OK;
+ }
+ }
+ if( modulus )
+ {
+ if(fread(&firmBuf[qty*MAX_FW_BUFFER_SIZE], 1, modulus, pFileHandle) == modulus)
+ {
+ status = KFWUM_STATUS_OK;
+ }
+ }
+ if(status == KFWUM_STATUS_OK)
+ {
+ KfwumShowProgress((const unsigned char *)"Reading Firmware from File", 100, 100);
+ }
+ fclose(pFileHandle);
+ }
+ return(status);
+}
+
+/* KfwumShowProgress - helper routine to display progress bar
+ *
+ * Converts current/total in percent
+ *
+ * *task : string identifying current operation
+ * current: progress
+ * total : limit
+ */
+#define PROG_LENGTH 42
+void KfwumShowProgress( const unsigned 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;
+
+ progress = 100*((unsigned long)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 = ( (unsigned short)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
+ *
+ */
+static 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;
+}
+
+/******************************************************************************
+******************************* COMMANDS **************************************
+******************************************************************************/
+#pragma pack(1)
+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__ ((packed));
+#pragma pack()
+
+
+/* KfwumGetInfo - Get Firmware Update Manager (FWUM) information
+ *
+ * * intf : IPMI interface
+ * output : when set to non zero, queried information is displayed
+ * pNumBank: output ptr for number of banks
+ */
+static tKFWUM_Status KfwumGetInfo(void * intf, unsigned char output,
+ unsigned char *pNumBank)
+{
+ tKFWUM_Status status = KFWUM_STATUS_OK;
+ static struct KfwumGetInfoResp *pGetInfo;
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ struct ipmi_rq req;
+ int dtype;
+ uchar bus, sa, lun, mtype;
+
+ 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;
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv) {
+ printf("FWUM Firmware Get Info returned %d (0x%02x)\n",rv,rv);
+ status = rv; // KFWUM_STATUS_ERROR
+ }
+
+ if(status == KFWUM_STATUS_OK)
+ {
+ pGetInfo = (struct KfwumGetInfoResp *) rsp;
+ 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_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");
+ }
+
+ ipmi_get_mc(&bus, &sa, &lun, &mtype);
+ dtype = get_driver_type();
+ if(is_remote()) /* covers lan and lanplus */
+ {
+ saveFirmwareInfo.bufferSize = KFWUM_SMALL_BUFFER;
+ if(verbose)
+ {
+ printf("IOL payload size : %d\r\n" ,
+ saveFirmwareInfo.bufferSize);
+ }
+ } else if ( (dtype == DRV_MV) && (sa != IPMI_BMC_SLAVE_ADDR) &&
+ (mtype == ADDR_IPMB) )
+ {
+ saveFirmwareInfo.bufferSize = KFWUM_SMALL_BUFFER;
+ if(verbose)
+ {
+ printf("IPMB payload size : %d\r\n" ,
+ saveFirmwareInfo.bufferSize);
+ }
+ }
+ else
+ {
+ saveFirmwareInfo.bufferSize = KFWUM_BIG_BUFFER;
+ if(verbose)
+ {
+ printf("SMI payload size : %d\r\n",
+ saveFirmwareInfo.bufferSize);
+ }
+ }
+ }
+ }
+ return status;
+}
+
+/* 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
+ */
+static tKFWUM_Status KfwumGetDeviceInfo(void * intf,
+ unsigned char output, tKFWUM_BoardInfo * pBoardInfo)
+{
+ struct ipm_devid_rsp *pGetDevId;
+ tKFWUM_Status status = KFWUM_STATUS_OK;
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ struct ipmi_rq req;
+ char *mstr;
+
+ /* 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;
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv) {
+ printf("Error in Get Device Id Command %d (0x%02x)\n",rv,rv);
+ status = rv; // KFWUM_STATUS_ERROR
+ }
+ }
+
+ if(status == KFWUM_STATUS_OK)
+ {
+ pGetDevId = (struct ipm_devid_rsp *) rsp;
+ pBoardInfo->iana = IPM_DEV_MANUFACTURER_ID(pGetDevId->manufacturer_id);
+ pBoardInfo->boardId = buf2short(pGetDevId->product_id);
+ if(output)
+ {
+ mstr = get_mfg_str(pGetDevId->manufacturer_id,NULL);
+ printf("\nIPMC Info\n");
+ printf("=========\n");
+ printf("Manufacturer Id : %u \t%s\n",pBoardInfo->iana,mstr);
+ 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;
+}
+
+#pragma pack(1)
+struct KfwumGetStatusResp {
+ unsigned char bankState;
+ unsigned char firmLengthLSB;
+ unsigned char firmLengthMid;
+ unsigned char firmLengthMSB;
+ unsigned char firmRev1;
+ unsigned char firmRev2;
+ unsigned char firmRev3;
+}; // __attribute__ ((packed));
+#pragma pack()
+
+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
+ */
+static tKFWUM_Status KfwumGetStatus(void * intf)
+{
+ tKFWUM_Status status = KFWUM_STATUS_OK;
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ 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;
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv) {
+ printf("FWUM Firmware Get Status Error %d (0x%02x)\n",rv,rv);
+ status = rv; // KFWUM_STATUS_ERROR
+ }
+
+ if(status == KFWUM_STATUS_OK)
+ {
+ pGetStatus = (struct KfwumGetStatusResp *) rsp;
+ 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;
+}
+#pragma pack(1)
+struct KfwumManualRollbackReq{
+ unsigned char type;
+}; // __attribute__ ((packed));
+#pragma pack()
+
+
+/* KfwumManualRollback - Ask IPMC to rollback to previous version
+ *
+ * * intf : IPMI interface
+ */
+static tKFWUM_Status KfwumManualRollback(void * intf)
+{
+ tKFWUM_Status status = KFWUM_STATUS_OK;
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ 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;
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv) {
+ printf("Error in FWUM Manual Rollback Command %d (0x%02x)\n",rv,rv);
+ status = rv; // KFWUM_STATUS_ERROR
+ }
+
+ if(status == KFWUM_STATUS_OK)
+ {
+ printf("FWUM Starting Manual Rollback \n");
+ }
+ return status;
+}
+
+#pragma pack(1)
+struct KfwumStartFirmwareDownloadReq{
+ unsigned char lengthLSB;
+ unsigned char lengthMid;
+ unsigned char lengthMSB;
+ unsigned char paddingLSB;
+ unsigned char paddingMSB;
+ unsigned char useSequence;
+}; // __attribute__ ((packed));
+struct KfwumStartFirmwareDownloadResp {
+ unsigned char bank;
+}; // __attribute__ ((packed));
+#pragma pack()
+
+static tKFWUM_Status KfwumStartFirmwareImage(void * intf,
+ unsigned long length,unsigned short padding)
+{
+ tKFWUM_Status status = KFWUM_STATUS_OK;
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ struct ipmi_rq req;
+ struct KfwumStartFirmwareDownloadResp *pResp;
+ struct KfwumStartFirmwareDownloadReq thisReq;
+
+ thisReq.lengthLSB = (uchar)(length & 0x000000ff);
+ thisReq.lengthMid = (uchar)((length >> 8) & 0x000000ff);
+ thisReq.lengthMSB = (uchar)((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;
+ }
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv) {
+ printf("FWUM Firmware Start Firmware Image Download returned %d (0x%02x)\n",rv,rv);
+ status = rv; // KFWUM_STATUS_ERROR
+ }
+
+ if(status == KFWUM_STATUS_OK)
+ {
+ pResp = (struct KfwumStartFirmwareDownloadResp *) rsp;
+ printf("Bank holding new firmware : %d\n", pResp->bank);
+ os_usleep(5,0);
+ }
+ return status;
+}
+
+#pragma pack(1)
+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__ ((packed));
+
+struct KfwumSaveFirmwareSequenceReq
+{
+ unsigned char sequenceNumber;
+ unsigned char txBuf[KFWUM_BIG_BUFFER];
+}; // __attribute__ ((packed));
+#pragma pack()
+
+
+#define FWUM_SAVE_FIRMWARE_NO_RESPONSE_LIMIT ((unsigned char)6)
+
+static tKFWUM_Status KfwumSaveFirmwareImage(void * intf,
+ unsigned char sequenceNumber, unsigned long address, unsigned char *pFirmBuf,
+ unsigned char * pInBufLength)
+{
+ tKFWUM_Status status = KFWUM_STATUS_OK;
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ 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 = (uchar)(address & 0x000000ff);
+ addressReq.addressMid = (uchar)((address >> 8) & 0x000000ff);
+ addressReq.addressMSB = (uchar)((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*/
+ }
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv < 0)
+ {
+ 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(is_remote())
+ {
+ 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 (rv > 0) /*ccode*/
+ {
+ if(rv == 0xc0)
+ {
+ status = KFWUM_STATUS_OK;
+ os_usleep(1,0);
+ }
+ else if(
+ (rv == 0xc7)
+ ||
+ (
+ (rv == 0xC3) &&
+ (sequenceNumber == 0)
+ )
+ )
+ {
+ (* pInBufLength) -= 1;
+ status = KFWUM_STATUS_OK;
+ retry = 1;
+ }
+ else if(rv == 0x82)
+ {
+ /* Double sent, continue */
+ status = KFWUM_STATUS_OK;
+ out = 1;
+ }
+ else if(rv == 0x83)
+ {
+ if(retry == 0)
+ {
+ retry = 1;
+ status = KFWUM_STATUS_OK;
+ }
+ else
+ {
+ status = rv; // KFWUM_STATUS_ERROR
+ out = 1;
+ }
+ }
+ else if(rv == 0xcf) /* Ok if receive duplicated request */
+ {
+ retry = 1;
+ status = KFWUM_STATUS_OK;
+ }
+ else if(rv == 0xC3)
+ {
+ if(retry == 0)
+ {
+ retry = 1;
+ status = KFWUM_STATUS_OK;
+ }
+ else
+ {
+ status = rv; // KFWUM_STATUS_ERROR
+ out = 1;
+ }
+ }
+ else
+ {
+ printf("FWUM Firmware Save Firmware Image Download returned %x\n",
+ rv);
+ status = rv; // KFWUM_STATUS_ERROR
+ out = 1;
+ }
+ }
+ else
+ {
+ out = 1;
+ }
+ }while(out == 0);
+ return status;
+}
+
+#pragma pack(1)
+struct KfwumFinishFirmwareDownloadReq{
+ unsigned char versionMaj;
+ unsigned char versionMinSub;
+ unsigned char versionSdr;
+ unsigned char reserved;
+}; // __attribute__ ((packed));
+#pragma pack()
+static tKFWUM_Status KfwumFinishFirmwareImage(void * intf,
+ tKFWUM_InFirmwareInfo firmInfo)
+{
+ tKFWUM_Status status = KFWUM_STATUS_OK;
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ 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
+ {
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ }while (rv == 0xc0);
+
+ if (rv < 0)
+ {
+ printf("Error in FWUM Firmware Finish Firmware Image Download Command\n");
+ status = rv; // KFWUM_STATUS_ERROR
+ }
+ else if (rv > 0)
+ {
+ printf("FWUM Firmware Finish Firmware Image Download returned %x\n",
+ rv);
+ status = rv; // KFWUM_STATUS_ERROR
+ }
+
+ return status;
+}
+
+
+#define FWUM_MAX_UPLOAD_RETRY 6
+static tKFWUM_Status KfwumUploadFirmware(void * intf,
+ unsigned char * pBuffer, unsigned long totalSize)
+{
+ 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 = (uchar)(totalSize - address);
+ }
+ /* Reach boundary end */
+ else if(((address % KFWUM_PAGE_SIZE) + writeSize) > KFWUM_PAGE_SIZE)
+ {
+ writeSize = (KFWUM_PAGE_SIZE - (uchar)(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 *)\
+ "Writing Firmware in Flash",address,totalSize);
+ }
+ sequenceNumber++;
+ }
+
+ }while((status == KFWUM_STATUS_OK) && (address < totalSize ));
+
+ if(status == KFWUM_STATUS_OK)
+ {
+ KfwumShowProgress((const unsigned char *)\
+ "Writing Firmware in Flash", 100 , 100 );
+ }
+
+ return(status);
+}
+
+static tKFWUM_Status KfwumStartFirmwareUpgrade(void * intf)
+{
+ tKFWUM_Status status = KFWUM_STATUS_OK;
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ 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;
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv < 0)
+ {
+ printf("Error in FWUM Firmware Start Firmware Upgrade Command\n");
+ status = rv; // KFWUM_STATUS_ERROR
+ }
+ else if (rv > 0)
+ {
+ if(rv == 0xd5)
+ {
+ printf("No firmware available for upgrade. Download Firmware first\n");
+ }
+ else
+ {
+ printf("FWUM Firmware Start Firmware Upgrade returned %x\n",
+ rv);
+ }
+ status = rv; // KFWUM_STATUS_ERROR
+ }
+
+ return status;
+}
+
+#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(void * intf)
+{
+ tKFWUM_Status status = KFWUM_STATUS_OK;
+ uchar rsp[IPMI_RSPBUF_SIZE];
+ int rsp_len, rv;
+ 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;
+
+ rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len);
+ if (rv) {
+ printf("FWUM Firmware Get Trace Log returned %d (0x%02x)\n",rv,rv);
+ status = rv; // 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[TRACE_LOG_ATT_COUNT*cmdIdx+1] != 0) &&
+ (rsp[TRACE_LOG_ATT_COUNT*cmdIdx] < KFWUM_CMD_ID_STD_MAX_CMD))
+ {
+ printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n",
+ CMD_ID_STRING[rsp[TRACE_LOG_ATT_COUNT*cmdIdx]],
+ CMD_STATE_STRING[rsp[TRACE_LOG_ATT_COUNT*cmdIdx+1]],
+ rsp[TRACE_LOG_ATT_COUNT*cmdIdx+2]);
+ }
+ else if ( (rsp[TRACE_LOG_ATT_COUNT*cmdIdx+1] != 0) &&
+ (rsp[TRACE_LOG_ATT_COUNT*cmdIdx] >= KFWUM_CMD_ID_EXTENDED_CMD))
+ {
+ printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n",
+ EXT_CMD_ID_STRING[rsp[TRACE_LOG_ATT_COUNT*cmdIdx] - KFWUM_CMD_ID_EXTENDED_CMD],
+ CMD_STATE_STRING[rsp[TRACE_LOG_ATT_COUNT*cmdIdx+1]],
+ rsp[TRACE_LOG_ATT_COUNT*cmdIdx+2]);
+ }
+ }
+ }
+ }
+ printf("\n");
+ return status;
+}
+
+
+/*******************************************************************************
+* 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);
+}
+
+
+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;
+ }
+}
+
+
+tKFWUM_Status KfwumValidFirmwareForBoard(tKFWUM_BoardInfo boardInfo,
+ tKFWUM_InFirmwareInfo firmInfo)
+{
+ 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;
+}
+
+
+static void KfwumOutputInfo(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);
+}
+
+#ifdef METACOMMAND
+int i_fwum(int argc, char **argv)
+#else
+#ifdef WIN32
+int __cdecl
+#else
+int
+#endif
+main(int argc, char **argv)
+#endif
+{
+ void *intf = NULL;
+ int rc = 0;
+ int c, i;
+ char *s1;
+
+ printf("%s ver %s\n", progname,progver);
+
+ while ( (c = getopt( argc, argv,"m:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF )
+ switch (c) {
+ case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */
+ g_bus = htoi(&optarg[0]); /*bus/channel*/
+ g_sa = htoi(&optarg[2]); /*device slave address*/
+ g_lun = htoi(&optarg[4]); /*LUN*/
+ g_addrtype = ADDR_IPMB;
+ if (optarg[6] == 's') {
+ g_addrtype = ADDR_SMI; s1 = "SMI";
+ } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; }
+ ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype);
+ printf("Use MC at %s bus=%x sa=%x lun=%x\n",
+ s1,g_bus,g_sa,g_lun);
+ break;
+ case 'x': fdebug = 1; verbose = 1;
+ break; /* debug messages */
+ case 'N': /* nodename */
+ case 'U': /* remote username */
+ case 'P': /* remote password */
+ case 'R': /* remote password */
+ case 'E': /* get password from IPMI_PASSWORD environment var */
+ case 'F': /* force driver type */
+ case 'T': /* auth type */
+ case 'J': /* cipher suite */
+ case 'V': /* priv level */
+ case 'Y': /* prompt for remote password */
+ case 'Z': /* set local MC address */
+ parse_lan_options(c,optarg,fdebug);
+ break;
+ case '?':
+ KfwumOutputHelp();
+ return ERR_USAGE;
+ break;
+ }
+ for (i = 0; i < optind; i++) { argv++; argc--; }
+
+ rc = ipmi_fwum_main(intf, argc, argv);
+
+ ipmi_close_();
+ // show_outcome(progname,rc);
+ return rc;
+}