diff options
Diffstat (limited to 'lib/ipmi_ime.c')
-rwxr-xr-x | lib/ipmi_ime.c | 1044 |
1 files changed, 1044 insertions, 0 deletions
diff --git a/lib/ipmi_ime.c b/lib/ipmi_ime.c new file mode 100755 index 0000000..b520ce5 --- /dev/null +++ b/lib/ipmi_ime.c @@ -0,0 +1,1044 @@ +/* + * Copyright (c) 2007 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. + */ + +/**************************************************************************** +* +* Copyright (c) 2009 Kontron Canada, Inc. All Rights Reserved. +* +* IME +* Intel Manageability Engine +* Firmware Update Agent +* +* The ME is an IPMI-enabled component included in Intel(R) Next Generation +* Server Chipset Nehalem-EP platforms. +* +* These are a few synonyms for the ME : +* +* - Dynamic Power Node Manager +* - Intelligent Power Node Manager +* +* Consult Intel litterature for more information on this technology. +* +* The ME firmware resides on the platform boot flash and contains read only +* boot code for the ME as well as boot image redundancy support. +* +* This module implements an Upgrade Agent for the ME firwmare. Because the ME +* implements IPMI command handling, the agent speaks directly to the ME. In other +* words, in order the reach the ME, the BMC must implement IPMB bridging. +* +* The update is done through IPMI (this is IPMITOOL right !), not HECI. +* +* Example: ME available at address 0x88 on IPMI channel 8: +* ipmitool -m 0x20 -t 0x88 -b 8 ime info +* +* !! WARNING - You MUST use an image provided by your board vendor. - WARNING !! +* +* author: +* Jean-Michel.Audet@ca.kontron.com +* Francois.Isabelle@ca.kontron.com +* +*****************************************************************************/ +/* + * HISTORY + * =========================================================================== + * 2009-04-20 + * + * First public release of Kontron + * +*/ +#include <ipmitool/ipmi_ime.h> +#include <ipmitool/log.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi_mc.h> +#include <ipmitool/helper.h> +#include <ipmitool/ipmi_strings.h> + + +#undef OUTPUT_DEBUG + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <time.h> + +static const int IME_SUCCESS = 0; +static const int IME_ERROR = -1; +static const int IME_RESTART = -2; + +#define IME_UPGRADE_BUFFER_SIZE 22 +#define IME_RETRY_COUNT 5 + +typedef struct ImeUpdateImageCtx +{ + uint32_t size; + uint8_t * pData; + uint8_t crc8; +}tImeUpdateImageCtx; + +typedef enum eImeState +{ + IME_STATE_IDLE = 0, + IME_STATE_UPDATE_REQUESTED = 1, + IME_STATE_UPDATE_IN_PROGRESS = 2, + IME_STATE_SUCCESS = 3, + IME_STATE_FAILED = 4, + IME_STATE_ROLLED_BACK = 5, + IME_STATE_ABORTED = 6, + IME_STATE_INIT_FAILED = 7 +} tImeStateEnum; + + +typedef enum tImeUpdateType +{ + IME_UPDTYPE_NORMAL = 1, + IME_UPDTYPE_MANUAL_ROLLBACK = 3, + IME_UPDTYPE_ABORT = 4 +} tImeUpdateType; + + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +typedef struct sImeStatus { + uint8_t image_status; + tImeStateEnum update_state; + uint8_t update_attempt_status; + uint8_t rollback_attempt_status; + uint8_t update_type; + uint8_t dependent_flag; + uint8_t free_area_size[4]; +} ATTRIBUTE_PACKING tImeStatus ; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +typedef struct sImeCaps { + uint8_t area_supported; + uint8_t special_caps; +} ATTRIBUTE_PACKING tImeCaps ; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + + +static void ImePrintUsage(void); +static int ImeGetInfo(struct ipmi_intf *intf); +static int ImeUpgrade(struct ipmi_intf *intf, char* imageFilename); +static int ImeManualRollback(struct ipmi_intf *intf); +static int ImeUpdatePrepare(struct ipmi_intf *intf); +static int ImeUpdateOpenArea(struct ipmi_intf *intf); +static int ImeUpdateWriteArea( + struct ipmi_intf *intf, + uint8_t sequence, + uint8_t length, + uint8_t * pBuf + ); +static int ImeUpdateCloseArea( + struct ipmi_intf *intf, + uint32_t size, + uint16_t checksum + ); + +static int ImeUpdateGetStatus(struct ipmi_intf *intf, tImeStatus *pStatus); +static int ImeUpdateGetCapabilities(struct ipmi_intf *intf, tImeCaps *pCaps ); +static int ImeUpdateRegisterUpdate(struct ipmi_intf *intf, tImeUpdateType type); + +static int ImeImageCtxFromFile( + char * imageFilename, + tImeUpdateImageCtx * pImageCtx); +static int ImeUpdateShowStatus(struct ipmi_intf *intf); + +static uint8_t ImeCrc8( uint32_t length, uint8_t * pBuf ); + + +static int ImeGetInfo(struct ipmi_intf *intf) +{ + int rc = IME_ERROR; + struct ipmi_rs * rsp; + struct ipmi_rq req; + struct ipm_devid_rsp *devid; + const char *product=NULL; + tImeStatus status; + tImeCaps caps; + + 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, "Get Device ID command failed"); + return IME_ERROR; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Get Device ID command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return IME_ERROR; + } + + devid = (struct ipm_devid_rsp *) rsp->data; + + lprintf(LOG_DEBUG,"Device ID : %i", devid->device_id); + lprintf(LOG_DEBUG,"Device Revision : %i", + devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK); + + if( + (devid->device_id == 0) + && + ((devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK) == 0) + && + ( + (devid->manufacturer_id[0] == 0x57) // Intel + && + (devid->manufacturer_id[1] == 0x01) // Intel + && + (devid->manufacturer_id[2] == 0x00) // Intel + ) + && + ( + (devid->product_id[1] == 0x0b) + && + (devid->product_id[0] == 0x00) + ) + ) + { + rc = IME_SUCCESS; + printf("Manufacturer Name : %s\n", + val2str( (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id), + ipmi_oem_info) ); + + printf("Product ID : %u (0x%02x%02x)\n", + buf2short((uint8_t *)(devid->product_id)), + devid->product_id[1], devid->product_id[0]); + + product=oemval2str(IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id), + (devid->product_id[1]<<8)+devid->product_id[0], + ipmi_oem_product_info); + + if (product!=NULL) + { + printf("Product Name : %s\n", product); + } + + printf("Intel ME Firmware Revision : %x.%02x.%02x.%x%x%x.%x\n", + ((devid->fw_rev1 & IPM_DEV_FWREV1_MAJOR_MASK ) ), + ((devid->fw_rev2 ) >> 4), + ((devid->fw_rev2 ) & 0x0f), + ((devid->aux_fw_rev[1] ) >> 4), + ((devid->aux_fw_rev[1] ) & 0x0f), + ((devid->aux_fw_rev[2] ) >> 4), + ((devid->aux_fw_rev[2] ) & 0x0f) + ); + + printf("SPS FW IPMI cmd version : %x.%x\n", + devid->aux_fw_rev[0] >> 4, + devid->aux_fw_rev[0] & 0x0f); + + lprintf(LOG_DEBUG,"Flags: %xh", devid->aux_fw_rev[3]); + + printf("Current Image Type : "); + switch( (devid->aux_fw_rev[3] & 0x03) ) + { + case 0: + printf("Recovery\n"); + break; + + case 1: + printf("Operational Image 1\n"); + break; + + case 2: + printf("Operational Image 2\n"); + break; + + case 3: + default: + printf("Unknown\n"); + break; + } + } + else + { + printf("Supported ME not found\n"); + } + + if(rc == IME_SUCCESS) + { + rc = ImeUpdateGetStatus(intf, &status); + + if(rc == IME_SUCCESS) + { + rc = ImeUpdateGetCapabilities(intf, &caps); + } + + } + + if(rc == IME_SUCCESS) + { + uint8_t newImage = ((status.image_status >> 1) & 0x01); + uint8_t rollImage = ((status.image_status >> 2) & 0x01); + uint8_t runArea = ((status.image_status >> 3) & 0x03); + uint8_t rollSup = ((caps.special_caps >> 0) & 0x01); + uint8_t recovSup = ((caps.special_caps >> 1) & 0x01); + + uint8_t operSup = ((caps.area_supported >> 1) & 0x01); + uint8_t piaSup = ((caps.area_supported >> 2) & 0x01); + uint8_t sdrSup = ((caps.area_supported >> 3) & 0x01); + + printf("\nSupported Area\n"); + printf(" Operation Code : %s\n", (operSup ? "Supported" : "Unsupported")); + printf(" PIA : %s\n", (piaSup ? "Supported" : "Unsupported")); + printf(" SDR : %s\n", (sdrSup ? "Supported" : "Unsupported")); + + printf("\nSpecial Capabilities\n"); + printf(" Rollback : %s\n", (rollSup ? "Supported" : "Unsupported")); + printf(" Recovery : %s\n", (recovSup ? "Supported" : "Unsupported")); + + printf("\nImage Status\n"); + printf(" Staging (new) : %s\n", (newImage ? "Valid" : "Invalid")); + printf(" Rollback : %s\n", (rollImage ? "Valid" : "Invalid")); + if(runArea == 0) + printf(" Running Image Area : CODE\n"); + else + printf(" Running Image Area : CODE%d\n", runArea); + + } + + return rc; +} + + +static int ImeUpgrade(struct ipmi_intf *intf, char* imageFilename) +{ + int rc = IME_SUCCESS; + tImeUpdateImageCtx imgCtx; + tImeStatus imeStatus; + time_t start,end,current; + + time(&start); + + memset(&imgCtx, 0, sizeof(tImeUpdateImageCtx)); + + rc = ImeImageCtxFromFile(imageFilename, &imgCtx); + + if( + (rc == IME_ERROR) || + (imgCtx.pData == NULL) || + (imgCtx.size == 0) + ) + { + return IME_ERROR; + } + + ImeUpdateGetStatus(intf,&imeStatus); + + if(rc == IME_SUCCESS) + { + rc = ImeUpdatePrepare(intf); + ImeUpdateGetStatus(intf,&imeStatus); + } + + if( + (rc == IME_SUCCESS) && + (imeStatus.update_state == IME_STATE_UPDATE_REQUESTED) + ) + { + rc = ImeUpdateOpenArea(intf); + ImeUpdateGetStatus(intf,&imeStatus); + } + else if(rc == IME_SUCCESS) + { + lprintf(LOG_ERROR,"ME state error (%i), aborting", imeStatus.update_state); + rc = IME_ERROR; + } + + + if( + (rc == IME_SUCCESS) && + (imeStatus.update_state == IME_STATE_UPDATE_IN_PROGRESS) + ) + { + uint8_t sequence = 0; + uint32_t counter = 0; + uint8_t retry = 0; + uint8_t shownPercent = 0xff; + + while( + (counter < imgCtx.size) && + (rc == IME_SUCCESS) && + (retry < IME_RETRY_COUNT) + ) + { + uint8_t length = IME_UPGRADE_BUFFER_SIZE; + uint8_t currentPercent; + + if( (imgCtx.size - counter) < IME_UPGRADE_BUFFER_SIZE ) + { + length = (imgCtx.size - counter); + } + + rc = ImeUpdateWriteArea(intf,sequence,length,&imgCtx.pData[counter]); + + /* + As per the flowchart Intel Dynamic Power Node Manager 1.5 IPMI Iface + page 65 + We shall send the GetStatus command each time following a write area + but this add too much time to the upgrade + */ + /* ImeUpdateGetStatus(intf,&imeStatus); */ + counter += length; + sequence ++; + + + currentPercent = ((float)counter/imgCtx.size)*100; + + if(currentPercent != shownPercent) + { + uint16_t timeElapsedSecond; + uint16_t timeRemainingSecond; + shownPercent = currentPercent; + printf("Percent: %02i, ", shownPercent); + time(¤t); + timeElapsedSecond = (current-start) + ((current-start)%60); + printf("Elapsed time %02ld:%02ld\r",((current-start)/60), ((current-start)%60)); + fflush(stdout); + + } + } + ImeUpdateGetStatus(intf,&imeStatus); + printf("\n"); + } + else if(rc == IME_SUCCESS) + { + lprintf(LOG_ERROR,"ME state error (%i), aborting", imeStatus.update_state); + rc = IME_ERROR; + } + + if( + (rc == IME_SUCCESS) && + (imeStatus.update_state == IME_STATE_UPDATE_IN_PROGRESS) + ) + { + rc = ImeUpdateCloseArea(intf, imgCtx.size, imgCtx.crc8); + ImeUpdateGetStatus(intf,&imeStatus); + } + else if(rc == IME_SUCCESS) + { + lprintf(LOG_ERROR,"ME state error, aborting"); + rc = IME_ERROR; + } + + if( + (rc == IME_SUCCESS) && + (imeStatus.update_state == IME_STATE_UPDATE_REQUESTED) + ) + { + printf("UpdateCompleted, Activate now\n"); + rc = ImeUpdateRegisterUpdate(intf, IME_UPDTYPE_NORMAL); + ImeUpdateGetStatus(intf,&imeStatus); + } + else if(rc == IME_SUCCESS) + { + lprintf(LOG_ERROR,"ME state error, aborting"); + rc = IME_ERROR; + } + + if( + (rc == IME_SUCCESS) && + (imeStatus.update_state == IME_STATE_SUCCESS) + ) + { + time(&end); + printf("Update Completed in %02ld:%02ld\n",(end-start)/60, (end-start)%60); + } + else + { + time(&end); + printf("Update Error\n"); + printf("\nTime Taken %02ld:%02ld\n",(end-start)/60, (end-start)%60); + } + + return rc; +} + + +static int ImeUpdatePrepare(struct ipmi_intf *intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + + #ifdef OUTPUT_DEBUG + printf("ImeUpdatePrepare\n"); + #endif + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x30; // OEM NetFn + req.msg.cmd = 0xA0; + req.msg.data_len = 0; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "UpdatePrepare command failed"); + return IME_ERROR; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "UpdatePrepare command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return IME_ERROR; + } + + lprintf(LOG_DEBUG, "UpdatePrepare command succeed"); + return IME_SUCCESS; +} + +static int ImeUpdateOpenArea(struct ipmi_intf *intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t buffer[ 2 ]; + + #ifdef OUTPUT_DEBUG + printf("ImeUpdateOpenArea\n"); + #endif + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x30; // OEM NetFn + req.msg.cmd = 0xA1; + + buffer[0] = 0x01; // Area Type : Operational code + buffer[1] = 0x00; // Reserved : 0 + req.msg.data = buffer; + + req.msg.data_len = 2; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "UpdateOpenArea command failed"); + return IME_ERROR; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "UpdateOpenArea command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return IME_ERROR; + } + + lprintf(LOG_DEBUG, "UpdateOpenArea command succeed"); + return IME_SUCCESS; +} + +static int ImeUpdateWriteArea( + struct ipmi_intf *intf, + uint8_t sequence, + uint8_t length, + uint8_t * pBuf + ) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t buffer[ IME_UPGRADE_BUFFER_SIZE + 1 ]; + +// printf("ImeUpdateWriteArea %i\n", sequence); + + if(length > IME_UPGRADE_BUFFER_SIZE) + return IME_ERROR; + + buffer[0] = sequence; + memcpy(&buffer[1], pBuf, length); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x30; // OEM NetFn + req.msg.cmd = 0xA2; + req.msg.data = buffer; + req.msg.data_len = length + 1; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "UpdateWriteArea command failed"); + return IME_ERROR; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "UpdateWriteArea command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + if( rsp->ccode == 0x80) // restart operation + return IME_RESTART; + else + return IME_ERROR; + } + + lprintf(LOG_DEBUG, "UpdateWriteArea command succeed"); + return IME_SUCCESS; +} + +static int ImeUpdateCloseArea( + struct ipmi_intf *intf, + uint32_t size, + uint16_t checksum + ) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t length = sizeof( uint32_t ) + sizeof( uint16_t ); + uint8_t buffer[ sizeof( uint32_t ) + sizeof( uint16_t ) ]; + + #ifdef OUTPUT_DEBUG + printf( "ImeUpdateCloseArea\n"); + #endif + + buffer[0] = (uint8_t)((size & 0x000000ff) >> 0); + buffer[1] = (uint8_t)((size & 0x0000ff00) >> 8); + buffer[2] = (uint8_t)((size & 0x00ff0000) >> 16); + buffer[3] = (uint8_t)((size & 0xff000000) >> 24); + + buffer[4] = (uint8_t)((checksum & 0x00ff) >> 0); + buffer[5] = (uint8_t)((checksum & 0xff00) >> 8); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x30; // OEM NetFn + req.msg.cmd = 0xA3; + req.msg.data = buffer; + req.msg.data_len = length; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "UpdateCloseArea command failed"); + return IME_ERROR; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "UpdateCloseArea command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return IME_ERROR; + } + + lprintf(LOG_DEBUG, "UpdateCloseArea command succeed"); + return IME_SUCCESS; +} + +static int ImeUpdateGetStatus(struct ipmi_intf *intf, tImeStatus *pStatus ) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + tImeStatus *pGetStatus; + + memset(pStatus, 0, sizeof(tImeStatus)); + pStatus->update_state = IME_STATE_ABORTED; + + + #ifdef OUTPUT_DEBUG + printf("ImeUpdateGetStatus: "); + #endif + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x30; // OEM NetFn + req.msg.cmd = 0xA6; + req.msg.data_len = 0; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "UpdatePrepare command failed"); + return IME_ERROR; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "UpdatePrepare command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return IME_ERROR; + } + + lprintf(LOG_DEBUG, "UpdatePrepare command succeed"); + + pGetStatus = (tImeStatus *) rsp->data; + + memcpy( pStatus, pGetStatus, sizeof(tImeStatus)); + + #ifdef OUTPUT_DEBUG + printf("%x - ", pStatus->updateState); + + switch( pStatus->update_state ) + { + case IME_STATE_IDLE: + printf("IDLE\n"); + break; + case IME_STATE_UPDATE_REQUESTED: + printf("Update Requested\n"); + break; + case IME_STATE_UPDATE_IN_PROGRESS: + printf("Update in Progress\n"); + break; + case IME_STATE_SUCCESS: + printf("Update Success\n"); + break; + case IME_STATE_FAILED: + printf("Update Failed\n"); + break; + case IME_STATE_ROLLED_BACK: + printf("Update Rolled Back\n"); + break; + case IME_STATE_ABORTED: + printf("Update Aborted\n"); + break; + case IME_STATE_INIT_FAILED: + printf("Update Init Failed\n"); + break; + default: + printf("Unknown, reserved\n"); + break; + } + #endif + + return IME_SUCCESS; +} + +static int ImeUpdateGetCapabilities(struct ipmi_intf *intf, tImeCaps *pCaps ) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + tImeCaps * pGetCaps; + + memset(pCaps, 0, sizeof(tImeCaps)); + + + #ifdef OUTPUT_DEBUG + printf("ImeUpdateGetStatus: "); + #endif + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x30; // OEM NetFn + req.msg.cmd = 0xA7; + req.msg.data_len = 0; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "UpdatePrepare command failed"); + return IME_ERROR; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "UpdatePrepare command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return IME_ERROR; + } + + lprintf(LOG_DEBUG, "UpdatePrepare command succeed"); + + pGetCaps = (tImeCaps *) rsp->data; + + memcpy( pCaps, pGetCaps, sizeof(tImeCaps)); + + return IME_SUCCESS; +} + + +static int ImeUpdateRegisterUpdate(struct ipmi_intf *intf, tImeUpdateType type) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t buffer[ 2 ]; + + #ifdef OUTPUT_DEBUG + printf( "ImeUpdateRegisterUpdate\n"); + #endif + + buffer[0] = type; // Normal Update + buffer[1] = 0; // Flags, reserved + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x30; // OEM NetFn + req.msg.cmd = 0xA4; + req.msg.data = buffer; + req.msg.data_len = 2; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "ImeUpdateRegisterUpdate command failed"); + return IME_ERROR; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "ImeUpdateRegisterUpdate command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return IME_ERROR; + } + + lprintf(LOG_DEBUG, "ImeUpdateRegisterUpdate command succeed"); + return IME_SUCCESS; +} + + + + +static int ImeUpdateShowStatus(struct ipmi_intf *intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + tImeStatus *pStatus; + + printf("ImeUpdateGetStatus: "); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x30; // OEM NetFn + req.msg.cmd = 0xA6; + req.msg.data_len = 0; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "UpdatePrepare command failed"); + return IME_ERROR; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "UpdatePrepare command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return IME_ERROR; + } + + lprintf(LOG_DEBUG, "UpdatePrepare command succeed"); + + pStatus = (tImeStatus *) rsp->data ; + + + printf("image_status: %x - ", pStatus->image_status); + + printf("update_state: %x - ", pStatus->update_state); + + switch( pStatus->update_state ) + { + case IME_STATE_IDLE: + printf("IDLE\n"); + break; + case IME_STATE_UPDATE_REQUESTED: + printf("Update Requested\n"); + break; + case IME_STATE_UPDATE_IN_PROGRESS: + printf("Update in Progress\n"); + break; + case IME_STATE_SUCCESS: + printf("Update Success\n"); + break; + case IME_STATE_FAILED: + printf("Update Failed\n"); + break; + case IME_STATE_ROLLED_BACK: + printf("Update Rolled Back\n"); + break; + case IME_STATE_ABORTED: + printf("Update Aborted\n"); + break; + case IME_STATE_INIT_FAILED: + printf("Update Init Failed\n"); + break; + default: + printf("Unknown, reserved\n"); + break; + } + printf("update_attempt_status : %x\n", pStatus->update_attempt_status); + printf("rollback_attempt_status: %x\n", pStatus->rollback_attempt_status); + printf("update_type : %x\n", pStatus->update_type); + printf("dependent_flag : %x\n", pStatus->dependent_flag); + printf("free_area_size : %x\n", pStatus->free_area_size[0]); + printf(" : %x\n", pStatus->free_area_size[1]); + printf(" : %x\n", pStatus->free_area_size[2]); + printf(" : %x\n", pStatus->free_area_size[3]); + + return IME_SUCCESS; +} + + +static int ImeImageCtxFromFile( + char* imageFilename, + tImeUpdateImageCtx * pImageCtx + ) +{ + int rc = IME_SUCCESS; + FILE* pImageFile = fopen(imageFilename, "rb"); + + if ( pImageFile == NULL ) + { + lprintf(LOG_NOTICE,"Cannot open image file %s", imageFilename); + rc = IME_ERROR; + } + + if ( rc == IME_SUCCESS ) + { + /* Get the raw data in file */ + fseek(pImageFile, 0, SEEK_END); + pImageCtx->size = ftell(pImageFile); + if (pImageCtx->size <= 0) { + if (pImageCtx->size < 0) + lprintf(LOG_ERR, "Error seeking %s. %s\n", imageFilename, strerror(errno)); + rc = IME_ERROR; + fclose(pImageFile); + return rc; + } + pImageCtx->pData = malloc(sizeof(unsigned char)*pImageCtx->size); + rewind(pImageFile); + + if ( pImageCtx->pData != NULL ) + { + if (pImageCtx->size < fread(pImageCtx->pData, sizeof(unsigned char), + pImageCtx->size, pImageFile)) + rc = IME_ERROR; + } + else + { + rc = IME_ERROR; + } + } + + // Calculate checksum CRC8 + if ( rc == IME_SUCCESS ) + { + pImageCtx->crc8 = ImeCrc8(pImageCtx->size, pImageCtx->pData); + } + + + if( pImageFile != NULL) + { + fclose(pImageFile); + } + + return rc; +} + +static uint8_t ImeCrc8( uint32_t length, uint8_t * pBuf ) +{ + uint8_t crc = 0; + uint32_t bufCount; + + for ( bufCount = 0; bufCount < length; bufCount++ ) + { + uint8_t count; + + crc = crc ^ pBuf[bufCount]; + + for ( count = 0; count < 8; count++ ) + { + if (( crc & 0x80 ) != 0 ) + { + crc <<= 1; + crc ^= 0x07; + } + else + { + crc <<= 1; + } + } + } + + lprintf(LOG_DEBUG,"CRC8: %02xh\n", crc); + return crc; +} + + +static int ImeManualRollback(struct ipmi_intf *intf) +{ + int rc = IME_SUCCESS; + tImeStatus imeStatus; + time_t start,end,current; + + + rc = ImeUpdateRegisterUpdate(intf, IME_UPDTYPE_MANUAL_ROLLBACK); + ImeUpdateGetStatus(intf,&imeStatus); + + + if( + (rc == IME_SUCCESS) && + (imeStatus.update_state == IME_STATE_ROLLED_BACK) + ) + { + printf("Manual Rollback Succeed\n"); + return IME_SUCCESS; + } + else + { + printf("Manual Rollback Completed With Error\n"); + return IME_ERROR; + } +} + + + +static void ImePrintUsage(void) +{ + lprintf(LOG_NOTICE,"help - This help menu"); + lprintf(LOG_NOTICE,"info - Information about the present Intel ME"); + lprintf(LOG_NOTICE,"update <file> - Upgrade the ME firmware from received image <file>"); + lprintf(LOG_NOTICE,"rollback - Manual Rollback ME"); +// lprintf(LOG_NOTICE,"rollback - Rollback ME Firmware"); +} + + + +int ipmi_ime_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + int rc = IME_SUCCESS; + + lprintf(LOG_DEBUG,"ipmi_ime_main()"); + + + if ( (argc == 0) || (strcmp(argv[0], "help") == 0) ) + { + ImePrintUsage(); + } + else if ( (argc == 0) || (strcmp(argv[0], "info") == 0) ) + { + rc = ImeGetInfo(intf); + } + else if ( strcmp(argv[0], "update") == 0) + { + if(argc == 2) + { + lprintf(LOG_NOTICE,"Update using file: %s", argv[1]); + rc = ImeUpgrade(intf, argv[1]); + } + else + { + lprintf(LOG_ERROR,"File must be provided with this option, see help\n"); + rc = IME_ERROR; + } + } + else if ( (argc == 0) || (strcmp(argv[0], "rollback") == 0) ) + { + rc = ImeManualRollback(intf); + } + else + { + ImePrintUsage(); + } + + return rc; +} + + + |