diff options
Diffstat (limited to 'util/ifwum.c')
-rw-r--r-- | util/ifwum.c | 1697 |
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, ¬Used); + + } + + + 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, ¬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); + } + + 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; +} |