1 /* 2 * Copyright (c) 2007 Kontron Canada, Inc. All Rights Reserved. 3 * 4 * Base on code from 5 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * Redistribution of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * Redistribution in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * Neither the name of Sun Microsystems, Inc. or the names of 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * This software is provided "AS IS," without a warranty of any kind. 23 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 24 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 25 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 26 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE 27 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING 28 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL 29 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, 30 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR 31 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 32 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 33 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 34 */ 35 36 /**************************************************************************** 37 * 38 * Copyright (c) 2009 Kontron Canada, Inc. All Rights Reserved. 39 * 40 * IME 41 * Intel Manageability Engine 42 * Firmware Update Agent 43 * 44 * The ME is an IPMI-enabled component included in Intel(R) Next Generation 45 * Server Chipset Nehalem-EP platforms. 46 * 47 * These are a few synonyms for the ME : 48 * 49 * - Dynamic Power Node Manager 50 * - Intelligent Power Node Manager 51 * 52 * Consult Intel litterature for more information on this technology. 53 * 54 * The ME firmware resides on the platform boot flash and contains read only 55 * boot code for the ME as well as boot image redundancy support. 56 * 57 * This module implements an Upgrade Agent for the ME firwmare. Because the ME 58 * implements IPMI command handling, the agent speaks directly to the ME. In other 59 * words, in order the reach the ME, the BMC must implement IPMB bridging. 60 * 61 * The update is done through IPMI (this is IPMITOOL right !), not HECI. 62 * 63 * Example: ME available at address 0x88 on IPMI channel 8: 64 * ipmitool -m 0x20 -t 0x88 -b 8 ime info 65 * 66 * !! WARNING - You MUST use an image provided by your board vendor. - WARNING !! 67 * 68 * author: 69 * Jean-Michel.Audet@ca.kontron.com 70 * Francois.Isabelle@ca.kontron.com 71 * 72 *****************************************************************************/ 73 /* 74 * HISTORY 75 * =========================================================================== 76 * 2009-04-20 77 * 78 * First public release of Kontron 79 * 80 */ 81 #include <ipmitool/ipmi_ime.h> 82 #include <ipmitool/log.h> 83 #include <ipmitool/ipmi_intf.h> 84 #include <ipmitool/ipmi_mc.h> 85 #include <ipmitool/helper.h> 86 #include <ipmitool/ipmi_strings.h> 87 88 89 #undef OUTPUT_DEBUG 90 91 #include <stdlib.h> 92 #include <string.h> 93 #include <errno.h> 94 #include <time.h> 95 96 static const int IME_SUCCESS = 0; 97 static const int IME_ERROR = -1; 98 static const int IME_RESTART = -2; 99 100 #define IME_UPGRADE_BUFFER_SIZE 22 101 #define IME_RETRY_COUNT 5 102 103 typedef struct ImeUpdateImageCtx 104 { 105 uint32_t size; 106 uint8_t * pData; 107 uint8_t crc8; 108 }tImeUpdateImageCtx; 109 110 typedef enum eImeState 111 { 112 IME_STATE_IDLE = 0, 113 IME_STATE_UPDATE_REQUESTED = 1, 114 IME_STATE_UPDATE_IN_PROGRESS = 2, 115 IME_STATE_SUCCESS = 3, 116 IME_STATE_FAILED = 4, 117 IME_STATE_ROLLED_BACK = 5, 118 IME_STATE_ABORTED = 6, 119 IME_STATE_INIT_FAILED = 7 120 } tImeStateEnum; 121 122 123 typedef enum tImeUpdateType 124 { 125 IME_UPDTYPE_NORMAL = 1, 126 IME_UPDTYPE_MANUAL_ROLLBACK = 3, 127 IME_UPDTYPE_ABORT = 4 128 } tImeUpdateType; 129 130 131 #ifdef HAVE_PRAGMA_PACK 132 #pragma pack(1) 133 #endif 134 typedef struct sImeStatus { 135 uint8_t image_status; 136 tImeStateEnum update_state; 137 uint8_t update_attempt_status; 138 uint8_t rollback_attempt_status; 139 uint8_t update_type; 140 uint8_t dependent_flag; 141 uint8_t free_area_size[4]; 142 } ATTRIBUTE_PACKING tImeStatus ; 143 #ifdef HAVE_PRAGMA_PACK 144 #pragma pack(0) 145 #endif 146 147 #ifdef HAVE_PRAGMA_PACK 148 #pragma pack(1) 149 #endif 150 typedef struct sImeCaps { 151 uint8_t area_supported; 152 uint8_t special_caps; 153 } ATTRIBUTE_PACKING tImeCaps ; 154 #ifdef HAVE_PRAGMA_PACK 155 #pragma pack(0) 156 #endif 157 158 159 static void ImePrintUsage(void); 160 static int ImeGetInfo(struct ipmi_intf *intf); 161 static int ImeUpgrade(struct ipmi_intf *intf, char* imageFilename); 162 static int ImeManualRollback(struct ipmi_intf *intf); 163 static int ImeUpdatePrepare(struct ipmi_intf *intf); 164 static int ImeUpdateOpenArea(struct ipmi_intf *intf); 165 static int ImeUpdateWriteArea( 166 struct ipmi_intf *intf, 167 uint8_t sequence, 168 uint8_t length, 169 uint8_t * pBuf 170 ); 171 static int ImeUpdateCloseArea( 172 struct ipmi_intf *intf, 173 uint32_t size, 174 uint16_t checksum 175 ); 176 177 static int ImeUpdateGetStatus(struct ipmi_intf *intf, tImeStatus *pStatus); 178 static int ImeUpdateGetCapabilities(struct ipmi_intf *intf, tImeCaps *pCaps ); 179 static int ImeUpdateRegisterUpdate(struct ipmi_intf *intf, tImeUpdateType type); 180 181 static int ImeImageCtxFromFile( 182 char * imageFilename, 183 tImeUpdateImageCtx * pImageCtx); 184 static int ImeUpdateShowStatus(struct ipmi_intf *intf); 185 186 static uint8_t ImeCrc8( uint32_t length, uint8_t * pBuf ); 187 188 189 static int ImeGetInfo(struct ipmi_intf *intf) 190 { 191 int rc = IME_ERROR; 192 struct ipmi_rs * rsp; 193 struct ipmi_rq req; 194 struct ipm_devid_rsp *devid; 195 const char *product=NULL; 196 tImeStatus status; 197 tImeCaps caps; 198 199 memset(&req, 0, sizeof(req)); 200 req.msg.netfn = IPMI_NETFN_APP; 201 req.msg.cmd = BMC_GET_DEVICE_ID; 202 req.msg.data_len = 0; 203 204 rsp = intf->sendrecv(intf, &req); 205 if (rsp == NULL) { 206 lprintf(LOG_ERR, "Get Device ID command failed"); 207 return IME_ERROR; 208 } 209 if (rsp->ccode > 0) { 210 lprintf(LOG_ERR, "Get Device ID command failed: %s", 211 val2str(rsp->ccode, completion_code_vals)); 212 return IME_ERROR; 213 } 214 215 devid = (struct ipm_devid_rsp *) rsp->data; 216 217 lprintf(LOG_DEBUG,"Device ID : %i", devid->device_id); 218 lprintf(LOG_DEBUG,"Device Revision : %i", 219 devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK); 220 221 if( 222 (devid->device_id == 0) 223 && 224 ((devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK) == 0) 225 && 226 ( 227 (devid->manufacturer_id[0] == 0x57) // Intel 228 && 229 (devid->manufacturer_id[1] == 0x01) // Intel 230 && 231 (devid->manufacturer_id[2] == 0x00) // Intel 232 ) 233 && 234 ( 235 (devid->product_id[1] == 0x0b) 236 && 237 (devid->product_id[0] == 0x00) 238 ) 239 ) 240 { 241 rc = IME_SUCCESS; 242 printf("Manufacturer Name : %s\n", 243 val2str( (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id), 244 ipmi_oem_info) ); 245 246 printf("Product ID : %u (0x%02x%02x)\n", 247 buf2short((uint8_t *)(devid->product_id)), 248 devid->product_id[1], devid->product_id[0]); 249 250 product=oemval2str(IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id), 251 (devid->product_id[1]<<8)+devid->product_id[0], 252 ipmi_oem_product_info); 253 254 if (product!=NULL) 255 { 256 printf("Product Name : %s\n", product); 257 } 258 259 printf("Intel ME Firmware Revision : %x.%02x.%02x.%x%x%x.%x\n", 260 ((devid->fw_rev1 & IPM_DEV_FWREV1_MAJOR_MASK ) ), 261 ((devid->fw_rev2 ) >> 4), 262 ((devid->fw_rev2 ) & 0x0f), 263 ((devid->aux_fw_rev[1] ) >> 4), 264 ((devid->aux_fw_rev[1] ) & 0x0f), 265 ((devid->aux_fw_rev[2] ) >> 4), 266 ((devid->aux_fw_rev[2] ) & 0x0f) 267 ); 268 269 printf("SPS FW IPMI cmd version : %x.%x\n", 270 devid->aux_fw_rev[0] >> 4, 271 devid->aux_fw_rev[0] & 0x0f); 272 273 lprintf(LOG_DEBUG,"Flags: %xh", devid->aux_fw_rev[3]); 274 275 printf("Current Image Type : "); 276 switch( (devid->aux_fw_rev[3] & 0x03) ) 277 { 278 case 0: 279 printf("Recovery\n"); 280 break; 281 282 case 1: 283 printf("Operational Image 1\n"); 284 break; 285 286 case 2: 287 printf("Operational Image 2\n"); 288 break; 289 290 case 3: 291 default: 292 printf("Unknown\n"); 293 break; 294 } 295 } 296 else 297 { 298 printf("Supported ME not found\n"); 299 } 300 301 if(rc == IME_SUCCESS) 302 { 303 rc = ImeUpdateGetStatus(intf, &status); 304 305 if(rc == IME_SUCCESS) 306 { 307 rc = ImeUpdateGetCapabilities(intf, &caps); 308 } 309 310 } 311 312 if(rc == IME_SUCCESS) 313 { 314 uint8_t newImage = ((status.image_status >> 1) & 0x01); 315 uint8_t rollImage = ((status.image_status >> 2) & 0x01); 316 uint8_t runArea = ((status.image_status >> 3) & 0x03); 317 uint8_t rollSup = ((caps.special_caps >> 0) & 0x01); 318 uint8_t recovSup = ((caps.special_caps >> 1) & 0x01); 319 320 uint8_t operSup = ((caps.area_supported >> 1) & 0x01); 321 uint8_t piaSup = ((caps.area_supported >> 2) & 0x01); 322 uint8_t sdrSup = ((caps.area_supported >> 3) & 0x01); 323 324 printf("\nSupported Area\n"); 325 printf(" Operation Code : %s\n", (operSup ? "Supported" : "Unsupported")); 326 printf(" PIA : %s\n", (piaSup ? "Supported" : "Unsupported")); 327 printf(" SDR : %s\n", (sdrSup ? "Supported" : "Unsupported")); 328 329 printf("\nSpecial Capabilities\n"); 330 printf(" Rollback : %s\n", (rollSup ? "Supported" : "Unsupported")); 331 printf(" Recovery : %s\n", (recovSup ? "Supported" : "Unsupported")); 332 333 printf("\nImage Status\n"); 334 printf(" Staging (new) : %s\n", (newImage ? "Valid" : "Invalid")); 335 printf(" Rollback : %s\n", (rollImage ? "Valid" : "Invalid")); 336 if(runArea == 0) 337 printf(" Running Image Area : CODE\n"); 338 else 339 printf(" Running Image Area : CODE%d\n", runArea); 340 341 } 342 343 return rc; 344 } 345 346 347 static int ImeUpgrade(struct ipmi_intf *intf, char* imageFilename) 348 { 349 int rc = IME_SUCCESS; 350 tImeUpdateImageCtx imgCtx; 351 tImeStatus imeStatus; 352 time_t start,end,current; 353 354 time(&start); 355 356 memset(&imgCtx, 0, sizeof(tImeUpdateImageCtx)); 357 358 rc = ImeImageCtxFromFile(imageFilename, &imgCtx); 359 360 if( 361 (rc == IME_ERROR) || 362 (imgCtx.pData == NULL) || 363 (imgCtx.size == 0) 364 ) 365 { 366 return IME_ERROR; 367 } 368 369 ImeUpdateGetStatus(intf,&imeStatus); 370 371 if(rc == IME_SUCCESS) 372 { 373 rc = ImeUpdatePrepare(intf); 374 ImeUpdateGetStatus(intf,&imeStatus); 375 } 376 377 if( 378 (rc == IME_SUCCESS) && 379 (imeStatus.update_state == IME_STATE_UPDATE_REQUESTED) 380 ) 381 { 382 rc = ImeUpdateOpenArea(intf); 383 ImeUpdateGetStatus(intf,&imeStatus); 384 } 385 else if(rc == IME_SUCCESS) 386 { 387 lprintf(LOG_ERROR,"ME state error (%i), aborting", imeStatus.update_state); 388 rc = IME_ERROR; 389 } 390 391 392 if( 393 (rc == IME_SUCCESS) && 394 (imeStatus.update_state == IME_STATE_UPDATE_IN_PROGRESS) 395 ) 396 { 397 uint8_t sequence = 0; 398 uint32_t counter = 0; 399 uint8_t retry = 0; 400 uint8_t shownPercent = 0xff; 401 402 while( 403 (counter < imgCtx.size) && 404 (rc == IME_SUCCESS) && 405 (retry < IME_RETRY_COUNT) 406 ) 407 { 408 uint8_t length = IME_UPGRADE_BUFFER_SIZE; 409 uint8_t currentPercent; 410 411 if( (imgCtx.size - counter) < IME_UPGRADE_BUFFER_SIZE ) 412 { 413 length = (imgCtx.size - counter); 414 } 415 416 rc = ImeUpdateWriteArea(intf,sequence,length,&imgCtx.pData[counter]); 417 418 /* 419 As per the flowchart Intel Dynamic Power Node Manager 1.5 IPMI Iface 420 page 65 421 We shall send the GetStatus command each time following a write area 422 but this add too much time to the upgrade 423 */ 424 /* ImeUpdateGetStatus(intf,&imeStatus); */ 425 counter += length; 426 sequence ++; 427 428 429 currentPercent = ((float)counter/imgCtx.size)*100; 430 431 if(currentPercent != shownPercent) 432 { 433 uint16_t timeElapsedSecond; 434 shownPercent = currentPercent; 435 printf("Percent: %02i, ", shownPercent); 436 time(¤t); 437 timeElapsedSecond = (current-start) + ((current-start)%60); 438 printf("Elapsed time %02ld:%02ld\r",((current-start)/60), ((current-start)%60)); 439 fflush(stdout); 440 441 } 442 } 443 ImeUpdateGetStatus(intf,&imeStatus); 444 printf("\n"); 445 } 446 else if(rc == IME_SUCCESS) 447 { 448 lprintf(LOG_ERROR,"ME state error (%i), aborting", imeStatus.update_state); 449 rc = IME_ERROR; 450 } 451 452 if( 453 (rc == IME_SUCCESS) && 454 (imeStatus.update_state == IME_STATE_UPDATE_IN_PROGRESS) 455 ) 456 { 457 rc = ImeUpdateCloseArea(intf, imgCtx.size, imgCtx.crc8); 458 ImeUpdateGetStatus(intf,&imeStatus); 459 } 460 else if(rc == IME_SUCCESS) 461 { 462 lprintf(LOG_ERROR,"ME state error, aborting"); 463 rc = IME_ERROR; 464 } 465 466 if( 467 (rc == IME_SUCCESS) && 468 (imeStatus.update_state == IME_STATE_UPDATE_REQUESTED) 469 ) 470 { 471 printf("UpdateCompleted, Activate now\n"); 472 rc = ImeUpdateRegisterUpdate(intf, IME_UPDTYPE_NORMAL); 473 ImeUpdateGetStatus(intf,&imeStatus); 474 } 475 else if(rc == IME_SUCCESS) 476 { 477 lprintf(LOG_ERROR,"ME state error, aborting"); 478 rc = IME_ERROR; 479 } 480 481 if( 482 (rc == IME_SUCCESS) && 483 (imeStatus.update_state == IME_STATE_SUCCESS) 484 ) 485 { 486 time(&end); 487 printf("Update Completed in %02ld:%02ld\n",(end-start)/60, (end-start)%60); 488 } 489 else 490 { 491 time(&end); 492 printf("Update Error\n"); 493 printf("\nTime Taken %02ld:%02ld\n",(end-start)/60, (end-start)%60); 494 } 495 496 return rc; 497 } 498 499 500 static int ImeUpdatePrepare(struct ipmi_intf *intf) 501 { 502 struct ipmi_rs * rsp; 503 struct ipmi_rq req; 504 505 #ifdef OUTPUT_DEBUG 506 printf("ImeUpdatePrepare\n"); 507 #endif 508 509 memset(&req, 0, sizeof(req)); 510 req.msg.netfn = 0x30; // OEM NetFn 511 req.msg.cmd = 0xA0; 512 req.msg.data_len = 0; 513 514 rsp = intf->sendrecv(intf, &req); 515 if (rsp == NULL) { 516 lprintf(LOG_ERR, "UpdatePrepare command failed"); 517 return IME_ERROR; 518 } 519 if (rsp->ccode > 0) { 520 lprintf(LOG_ERR, "UpdatePrepare command failed: %s", 521 val2str(rsp->ccode, completion_code_vals)); 522 return IME_ERROR; 523 } 524 525 lprintf(LOG_DEBUG, "UpdatePrepare command succeed"); 526 return IME_SUCCESS; 527 } 528 529 static int ImeUpdateOpenArea(struct ipmi_intf *intf) 530 { 531 struct ipmi_rs * rsp; 532 struct ipmi_rq req; 533 uint8_t buffer[ 2 ]; 534 535 #ifdef OUTPUT_DEBUG 536 printf("ImeUpdateOpenArea\n"); 537 #endif 538 539 memset(&req, 0, sizeof(req)); 540 req.msg.netfn = 0x30; // OEM NetFn 541 req.msg.cmd = 0xA1; 542 543 buffer[0] = 0x01; // Area Type : Operational code 544 buffer[1] = 0x00; // Reserved : 0 545 req.msg.data = buffer; 546 547 req.msg.data_len = 2; 548 549 rsp = intf->sendrecv(intf, &req); 550 if (rsp == NULL) { 551 lprintf(LOG_ERR, "UpdateOpenArea command failed"); 552 return IME_ERROR; 553 } 554 if (rsp->ccode > 0) { 555 lprintf(LOG_ERR, "UpdateOpenArea command failed: %s", 556 val2str(rsp->ccode, completion_code_vals)); 557 return IME_ERROR; 558 } 559 560 lprintf(LOG_DEBUG, "UpdateOpenArea command succeed"); 561 return IME_SUCCESS; 562 } 563 564 static int ImeUpdateWriteArea( 565 struct ipmi_intf *intf, 566 uint8_t sequence, 567 uint8_t length, 568 uint8_t * pBuf 569 ) 570 { 571 struct ipmi_rs * rsp; 572 struct ipmi_rq req; 573 uint8_t buffer[ IME_UPGRADE_BUFFER_SIZE + 1 ]; 574 575 // printf("ImeUpdateWriteArea %i\n", sequence); 576 577 if(length > IME_UPGRADE_BUFFER_SIZE) 578 return IME_ERROR; 579 580 buffer[0] = sequence; 581 memcpy(&buffer[1], pBuf, length); 582 583 memset(&req, 0, sizeof(req)); 584 req.msg.netfn = 0x30; // OEM NetFn 585 req.msg.cmd = 0xA2; 586 req.msg.data = buffer; 587 req.msg.data_len = length + 1; 588 589 rsp = intf->sendrecv(intf, &req); 590 if (rsp == NULL) { 591 lprintf(LOG_ERR, "UpdateWriteArea command failed"); 592 return IME_ERROR; 593 } 594 if (rsp->ccode > 0) { 595 lprintf(LOG_ERR, "UpdateWriteArea command failed: %s", 596 val2str(rsp->ccode, completion_code_vals)); 597 if( rsp->ccode == 0x80) // restart operation 598 return IME_RESTART; 599 else 600 return IME_ERROR; 601 } 602 603 lprintf(LOG_DEBUG, "UpdateWriteArea command succeed"); 604 return IME_SUCCESS; 605 } 606 607 static int ImeUpdateCloseArea( 608 struct ipmi_intf *intf, 609 uint32_t size, 610 uint16_t checksum 611 ) 612 { 613 struct ipmi_rs * rsp; 614 struct ipmi_rq req; 615 uint8_t length = sizeof( uint32_t ) + sizeof( uint16_t ); 616 uint8_t buffer[ sizeof( uint32_t ) + sizeof( uint16_t ) ]; 617 618 #ifdef OUTPUT_DEBUG 619 printf( "ImeUpdateCloseArea\n"); 620 #endif 621 622 buffer[0] = (uint8_t)((size & 0x000000ff) >> 0); 623 buffer[1] = (uint8_t)((size & 0x0000ff00) >> 8); 624 buffer[2] = (uint8_t)((size & 0x00ff0000) >> 16); 625 buffer[3] = (uint8_t)((size & 0xff000000) >> 24); 626 627 buffer[4] = (uint8_t)((checksum & 0x00ff) >> 0); 628 buffer[5] = (uint8_t)((checksum & 0xff00) >> 8); 629 630 memset(&req, 0, sizeof(req)); 631 req.msg.netfn = 0x30; // OEM NetFn 632 req.msg.cmd = 0xA3; 633 req.msg.data = buffer; 634 req.msg.data_len = length; 635 636 rsp = intf->sendrecv(intf, &req); 637 if (rsp == NULL) { 638 lprintf(LOG_ERR, "UpdateCloseArea command failed"); 639 return IME_ERROR; 640 } 641 if (rsp->ccode > 0) { 642 lprintf(LOG_ERR, "UpdateCloseArea command failed: %s", 643 val2str(rsp->ccode, completion_code_vals)); 644 return IME_ERROR; 645 } 646 647 lprintf(LOG_DEBUG, "UpdateCloseArea command succeed"); 648 return IME_SUCCESS; 649 } 650 651 static int ImeUpdateGetStatus(struct ipmi_intf *intf, tImeStatus *pStatus ) 652 { 653 struct ipmi_rs * rsp; 654 struct ipmi_rq req; 655 tImeStatus *pGetStatus; 656 657 memset(pStatus, 0, sizeof(tImeStatus)); 658 pStatus->update_state = IME_STATE_ABORTED; 659 660 661 #ifdef OUTPUT_DEBUG 662 printf("ImeUpdateGetStatus: "); 663 #endif 664 665 memset(&req, 0, sizeof(req)); 666 req.msg.netfn = 0x30; // OEM NetFn 667 req.msg.cmd = 0xA6; 668 req.msg.data_len = 0; 669 670 rsp = intf->sendrecv(intf, &req); 671 if (rsp == NULL) { 672 lprintf(LOG_ERR, "UpdatePrepare command failed"); 673 return IME_ERROR; 674 } 675 if (rsp->ccode > 0) { 676 lprintf(LOG_ERR, "UpdatePrepare command failed: %s", 677 val2str(rsp->ccode, completion_code_vals)); 678 return IME_ERROR; 679 } 680 681 lprintf(LOG_DEBUG, "UpdatePrepare command succeed"); 682 683 pGetStatus = (tImeStatus *) rsp->data; 684 685 memcpy( pStatus, pGetStatus, sizeof(tImeStatus)); 686 687 #ifdef OUTPUT_DEBUG 688 printf("%x - ", pStatus->updateState); 689 690 switch( pStatus->update_state ) 691 { 692 case IME_STATE_IDLE: 693 printf("IDLE\n"); 694 break; 695 case IME_STATE_UPDATE_REQUESTED: 696 printf("Update Requested\n"); 697 break; 698 case IME_STATE_UPDATE_IN_PROGRESS: 699 printf("Update in Progress\n"); 700 break; 701 case IME_STATE_SUCCESS: 702 printf("Update Success\n"); 703 break; 704 case IME_STATE_FAILED: 705 printf("Update Failed\n"); 706 break; 707 case IME_STATE_ROLLED_BACK: 708 printf("Update Rolled Back\n"); 709 break; 710 case IME_STATE_ABORTED: 711 printf("Update Aborted\n"); 712 break; 713 case IME_STATE_INIT_FAILED: 714 printf("Update Init Failed\n"); 715 break; 716 default: 717 printf("Unknown, reserved\n"); 718 break; 719 } 720 #endif 721 722 return IME_SUCCESS; 723 } 724 725 static int ImeUpdateGetCapabilities(struct ipmi_intf *intf, tImeCaps *pCaps ) 726 { 727 struct ipmi_rs * rsp; 728 struct ipmi_rq req; 729 tImeCaps * pGetCaps; 730 731 memset(pCaps, 0, sizeof(tImeCaps)); 732 733 734 #ifdef OUTPUT_DEBUG 735 printf("ImeUpdateGetStatus: "); 736 #endif 737 738 memset(&req, 0, sizeof(req)); 739 req.msg.netfn = 0x30; // OEM NetFn 740 req.msg.cmd = 0xA7; 741 req.msg.data_len = 0; 742 743 rsp = intf->sendrecv(intf, &req); 744 if (rsp == NULL) { 745 lprintf(LOG_ERR, "UpdatePrepare command failed"); 746 return IME_ERROR; 747 } 748 if (rsp->ccode > 0) { 749 lprintf(LOG_ERR, "UpdatePrepare command failed: %s", 750 val2str(rsp->ccode, completion_code_vals)); 751 return IME_ERROR; 752 } 753 754 lprintf(LOG_DEBUG, "UpdatePrepare command succeed"); 755 756 pGetCaps = (tImeCaps *) rsp->data; 757 758 memcpy( pCaps, pGetCaps, sizeof(tImeCaps)); 759 760 return IME_SUCCESS; 761 } 762 763 764 static int ImeUpdateRegisterUpdate(struct ipmi_intf *intf, tImeUpdateType type) 765 { 766 struct ipmi_rs * rsp; 767 struct ipmi_rq req; 768 uint8_t buffer[ 2 ]; 769 770 #ifdef OUTPUT_DEBUG 771 printf( "ImeUpdateRegisterUpdate\n"); 772 #endif 773 774 buffer[0] = type; // Normal Update 775 buffer[1] = 0; // Flags, reserved 776 777 memset(&req, 0, sizeof(req)); 778 req.msg.netfn = 0x30; // OEM NetFn 779 req.msg.cmd = 0xA4; 780 req.msg.data = buffer; 781 req.msg.data_len = 2; 782 783 rsp = intf->sendrecv(intf, &req); 784 if (rsp == NULL) { 785 lprintf(LOG_ERR, "ImeUpdateRegisterUpdate command failed"); 786 return IME_ERROR; 787 } 788 if (rsp->ccode > 0) { 789 lprintf(LOG_ERR, "ImeUpdateRegisterUpdate command failed: %s", 790 val2str(rsp->ccode, completion_code_vals)); 791 return IME_ERROR; 792 } 793 794 lprintf(LOG_DEBUG, "ImeUpdateRegisterUpdate command succeed"); 795 return IME_SUCCESS; 796 } 797 798 799 800 801 static int ImeUpdateShowStatus(struct ipmi_intf *intf) 802 { 803 struct ipmi_rs * rsp; 804 struct ipmi_rq req; 805 tImeStatus *pStatus; 806 807 printf("ImeUpdateGetStatus: "); 808 809 memset(&req, 0, sizeof(req)); 810 req.msg.netfn = 0x30; // OEM NetFn 811 req.msg.cmd = 0xA6; 812 req.msg.data_len = 0; 813 814 rsp = intf->sendrecv(intf, &req); 815 if (rsp == NULL) { 816 lprintf(LOG_ERR, "UpdatePrepare command failed"); 817 return IME_ERROR; 818 } 819 if (rsp->ccode > 0) { 820 lprintf(LOG_ERR, "UpdatePrepare command failed: %s", 821 val2str(rsp->ccode, completion_code_vals)); 822 return IME_ERROR; 823 } 824 825 lprintf(LOG_DEBUG, "UpdatePrepare command succeed"); 826 827 pStatus = (tImeStatus *) rsp->data ; 828 829 830 printf("image_status: %x - ", pStatus->image_status); 831 832 printf("update_state: %x - ", pStatus->update_state); 833 834 switch( pStatus->update_state ) 835 { 836 case IME_STATE_IDLE: 837 printf("IDLE\n"); 838 break; 839 case IME_STATE_UPDATE_REQUESTED: 840 printf("Update Requested\n"); 841 break; 842 case IME_STATE_UPDATE_IN_PROGRESS: 843 printf("Update in Progress\n"); 844 break; 845 case IME_STATE_SUCCESS: 846 printf("Update Success\n"); 847 break; 848 case IME_STATE_FAILED: 849 printf("Update Failed\n"); 850 break; 851 case IME_STATE_ROLLED_BACK: 852 printf("Update Rolled Back\n"); 853 break; 854 case IME_STATE_ABORTED: 855 printf("Update Aborted\n"); 856 break; 857 case IME_STATE_INIT_FAILED: 858 printf("Update Init Failed\n"); 859 break; 860 default: 861 printf("Unknown, reserved\n"); 862 break; 863 } 864 printf("update_attempt_status : %x\n", pStatus->update_attempt_status); 865 printf("rollback_attempt_status: %x\n", pStatus->rollback_attempt_status); 866 printf("update_type : %x\n", pStatus->update_type); 867 printf("dependent_flag : %x\n", pStatus->dependent_flag); 868 printf("free_area_size : %x\n", pStatus->free_area_size[0]); 869 printf(" : %x\n", pStatus->free_area_size[1]); 870 printf(" : %x\n", pStatus->free_area_size[2]); 871 printf(" : %x\n", pStatus->free_area_size[3]); 872 873 return IME_SUCCESS; 874 } 875 876 877 static int ImeImageCtxFromFile( 878 char* imageFilename, 879 tImeUpdateImageCtx * pImageCtx 880 ) 881 { 882 int rc = IME_SUCCESS; 883 FILE* pImageFile = fopen(imageFilename, "rb"); 884 885 if ( pImageFile == NULL ) 886 { 887 lprintf(LOG_NOTICE,"Cannot open image file %s", imageFilename); 888 rc = IME_ERROR; 889 } 890 891 if ( rc == IME_SUCCESS ) 892 { 893 /* Get the raw data in file */ 894 fseek(pImageFile, 0, SEEK_END); 895 pImageCtx->size = ftell(pImageFile); 896 if (pImageCtx->size <= 0) { 897 if (pImageCtx->size < 0) 898 lprintf(LOG_ERR, "Error seeking %s. %s\n", imageFilename, strerror(errno)); 899 rc = IME_ERROR; 900 fclose(pImageFile); 901 return rc; 902 } 903 pImageCtx->pData = malloc(sizeof(unsigned char)*pImageCtx->size); 904 rewind(pImageFile); 905 906 if ( pImageCtx->pData != NULL ) 907 { 908 if (pImageCtx->size < fread(pImageCtx->pData, sizeof(unsigned char), 909 pImageCtx->size, pImageFile)) 910 rc = IME_ERROR; 911 } 912 else 913 { 914 rc = IME_ERROR; 915 } 916 } 917 918 // Calculate checksum CRC8 919 if ( rc == IME_SUCCESS ) 920 { 921 pImageCtx->crc8 = ImeCrc8(pImageCtx->size, pImageCtx->pData); 922 } 923 924 925 if( pImageFile != NULL) 926 { 927 fclose(pImageFile); 928 } 929 930 return rc; 931 } 932 933 static uint8_t ImeCrc8( uint32_t length, uint8_t * pBuf ) 934 { 935 uint8_t crc = 0; 936 uint32_t bufCount; 937 938 for ( bufCount = 0; bufCount < length; bufCount++ ) 939 { 940 uint8_t count; 941 942 crc = crc ^ pBuf[bufCount]; 943 944 for ( count = 0; count < 8; count++ ) 945 { 946 if (( crc & 0x80 ) != 0 ) 947 { 948 crc <<= 1; 949 crc ^= 0x07; 950 } 951 else 952 { 953 crc <<= 1; 954 } 955 } 956 } 957 958 lprintf(LOG_DEBUG,"CRC8: %02xh\n", crc); 959 return crc; 960 } 961 962 963 static int ImeManualRollback(struct ipmi_intf *intf) 964 { 965 int rc = IME_SUCCESS; 966 tImeStatus imeStatus; 967 968 rc = ImeUpdateRegisterUpdate(intf, IME_UPDTYPE_MANUAL_ROLLBACK); 969 ImeUpdateGetStatus(intf,&imeStatus); 970 971 972 if( 973 (rc == IME_SUCCESS) && 974 (imeStatus.update_state == IME_STATE_ROLLED_BACK) 975 ) 976 { 977 printf("Manual Rollback Succeed\n"); 978 return IME_SUCCESS; 979 } 980 else 981 { 982 printf("Manual Rollback Completed With Error\n"); 983 return IME_ERROR; 984 } 985 } 986 987 988 989 static void ImePrintUsage(void) 990 { 991 lprintf(LOG_NOTICE,"help - This help menu"); 992 lprintf(LOG_NOTICE,"info - Information about the present Intel ME"); 993 lprintf(LOG_NOTICE,"update <file> - Upgrade the ME firmware from received image <file>"); 994 lprintf(LOG_NOTICE,"rollback - Manual Rollback ME"); 995 // lprintf(LOG_NOTICE,"rollback - Rollback ME Firmware"); 996 } 997 998 999 1000 int ipmi_ime_main(struct ipmi_intf * intf, int argc, char ** argv) 1001 { 1002 int rc = IME_SUCCESS; 1003 1004 lprintf(LOG_DEBUG,"ipmi_ime_main()"); 1005 1006 1007 if ( (argc == 0) || (strcmp(argv[0], "help") == 0) ) 1008 { 1009 ImePrintUsage(); 1010 } 1011 else if ( (argc == 0) || (strcmp(argv[0], "info") == 0) ) 1012 { 1013 rc = ImeGetInfo(intf); 1014 } 1015 else if ( strcmp(argv[0], "update") == 0) 1016 { 1017 if(argc == 2) 1018 { 1019 lprintf(LOG_NOTICE,"Update using file: %s", argv[1]); 1020 rc = ImeUpgrade(intf, argv[1]); 1021 } 1022 else 1023 { 1024 lprintf(LOG_ERROR,"File must be provided with this option, see help\n"); 1025 rc = IME_ERROR; 1026 } 1027 } 1028 else if ( (argc == 0) || (strcmp(argv[0], "rollback") == 0) ) 1029 { 1030 rc = ImeManualRollback(intf); 1031 } 1032 else 1033 { 1034 ImePrintUsage(); 1035 } 1036 1037 return rc; 1038 } 1039 1040 1041 1042