1 /* 2 * Copyright (c) 2004 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 #include <string.h> 37 #include <math.h> 38 #include <time.h> 39 #include <unistd.h> 40 41 #include <ipmitool/log.h> 42 #include <ipmitool/helper.h> 43 #include <ipmitool/ipmi.h> 44 #include <ipmitool/ipmi_fwum.h> 45 #include <ipmitool/ipmi_intf.h> 46 #include <ipmitool/ipmi_mc.h> 47 48 extern int verbose; 49 unsigned char firmBuf[1024*512]; 50 tKFWUM_SaveFirmwareInfo save_fw_nfo; 51 52 int KfwumGetFileSize(const char *pFileName, 53 unsigned long *pFileSize); 54 int KfwumSetupBuffersFromFile(const char *pFileName, 55 unsigned long fileSize); 56 void KfwumShowProgress(const char *task, unsigned long current, 57 unsigned long total); 58 unsigned short KfwumCalculateChecksumPadding(unsigned char *pBuffer, 59 unsigned long totalSize); 60 int KfwumGetInfo(struct ipmi_intf *intf, unsigned char output, 61 unsigned char *pNumBank); 62 int KfwumGetDeviceInfo(struct ipmi_intf *intf, 63 unsigned char output, tKFWUM_BoardInfo *pBoardInfo); 64 int KfwumGetStatus(struct ipmi_intf *intf); 65 int KfwumManualRollback(struct ipmi_intf *intf); 66 int KfwumStartFirmwareImage(struct ipmi_intf *intf, 67 unsigned long length, unsigned short padding); 68 int KfwumSaveFirmwareImage(struct ipmi_intf *intf, 69 unsigned char sequenceNumber, unsigned long address, 70 unsigned char *pFirmBuf, unsigned char *pInBufLength); 71 int KfwumFinishFirmwareImage(struct ipmi_intf *intf, 72 tKFWUM_InFirmwareInfo firmInfo); 73 int KfwumUploadFirmware(struct ipmi_intf *intf, 74 unsigned char *pBuffer, unsigned long totalSize); 75 int KfwumStartFirmwareUpgrade(struct ipmi_intf *intf); 76 int KfwumGetInfoFromFirmware(unsigned char *pBuf, 77 unsigned long bufSize, tKFWUM_InFirmwareInfo *pInfo); 78 void KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo *pInfo); 79 int KfwumGetTraceLog(struct ipmi_intf *intf); 80 int ipmi_kfwum_checkfwcompat(tKFWUM_BoardInfo boardInfo, 81 tKFWUM_InFirmwareInfo firmInfo); 82 83 int ipmi_fwum_fwupgrade(struct ipmi_intf *intf, char *file, int action); 84 int ipmi_fwum_info(struct ipmi_intf *intf); 85 int ipmi_fwum_status(struct ipmi_intf *intf); 86 void printf_kfwum_help(void); 87 void printf_kfwum_info(tKFWUM_BoardInfo boardInfo, 88 tKFWUM_InFirmwareInfo firmInfo); 89 90 /* String table */ 91 /* Must match eFWUM_CmdId */ 92 const char *CMD_ID_STRING[] = { 93 "GetFwInfo", 94 "KickWatchdog", 95 "GetLastAnswer", 96 "BootHandshake", 97 "ReportStatus", 98 "CtrlIPMBLine", 99 "SetFwState", 100 "GetFwStatus", 101 "GetSpiMemStatus", 102 "StartFwUpdate", 103 "StartFwImage", 104 "SaveFwImage", 105 "FinishFwImage", 106 "ReadFwImage", 107 "ManualRollback", 108 "GetTraceLog" 109 }; 110 111 const char *EXT_CMD_ID_STRING[] = { 112 "FwUpgradeLock", 113 "ProcessFwUpg", 114 "ProcessFwRb", 115 "WaitHSAfterUpg", 116 "WaitFirstHSUpg", 117 "FwInfoStateChange" 118 }; 119 120 const char *CMD_STATE_STRING[] = { 121 "Invalid", 122 "Begin", 123 "Progress", 124 "Completed" 125 }; 126 127 const struct valstr bankStateValS[] = { 128 { 0x00, "Not programmed" }, 129 { 0x01, "New firmware" }, 130 { 0x02, "Wait for validation" }, 131 { 0x03, "Last Known Good" }, 132 { 0x04, "Previous Good" } 133 }; 134 135 /* ipmi_fwum_main - entry point for this ipmitool mode 136 * 137 * @intf: ipmi interface 138 * @arc: number of arguments 139 * @argv: point to argument array 140 * 141 * returns 0 on success 142 * returns -1 on error 143 */ 144 int 145 ipmi_fwum_main(struct ipmi_intf *intf, int argc, char **argv) 146 { 147 int rc = 0; 148 printf("FWUM extension Version %d.%d\n", VER_MAJOR, VER_MINOR); 149 if (argc < 1) { 150 lprintf(LOG_ERR, "Not enough parameters given."); 151 printf_kfwum_help(); 152 return (-1); 153 } 154 if (strncmp(argv[0], "help", 4) == 0) { 155 printf_kfwum_help(); 156 rc = 0; 157 } else if (strncmp(argv[0], "info", 4) == 0) { 158 rc = ipmi_fwum_info(intf); 159 } else if (strncmp(argv[0], "status", 6) == 0) { 160 rc = ipmi_fwum_status(intf); 161 } else if (strncmp(argv[0], "rollback", 8) == 0) { 162 rc = KfwumManualRollback(intf); 163 } else if (strncmp(argv[0], "download", 8) == 0) { 164 if ((argc < 2) || (strlen(argv[1]) < 1)) { 165 lprintf(LOG_ERR, 166 "Path and file name must be specified."); 167 return (-1); 168 } 169 printf("Firmware File Name : %s\n", argv[1]); 170 rc = ipmi_fwum_fwupgrade(intf, argv[1], 0); 171 } else if (strncmp(argv[0], "upgrade", 7) == 0) { 172 if ((argc >= 2) && (strlen(argv[1]) > 0)) { 173 printf("Upgrading using file name %s\n", argv[1]); 174 rc = ipmi_fwum_fwupgrade(intf, argv[1], 1); 175 } else { 176 rc = KfwumStartFirmwareUpgrade(intf); 177 } 178 } else if (strncmp(argv[0], "tracelog", 8) == 0) { 179 rc = KfwumGetTraceLog(intf); 180 } else { 181 lprintf(LOG_ERR, "Invalid KFWUM command: %s", argv[0]); 182 printf_kfwum_help(); 183 rc = (-1); 184 } 185 return rc; 186 } 187 188 void 189 printf_kfwum_help(void) 190 { 191 lprintf(LOG_NOTICE, 192 "KFWUM Commands: info status download upgrade rollback tracelog"); 193 } 194 195 /* private definitions and macros */ 196 typedef enum eFWUM_CmdId 197 { 198 KFWUM_CMD_ID_GET_FIRMWARE_INFO = 0, 199 KFWUM_CMD_ID_KICK_IPMC_WATCHDOG = 1, 200 KFWUM_CMD_ID_GET_LAST_ANSWER = 2, 201 KFWUM_CMD_ID_BOOT_HANDSHAKE = 3, 202 KFWUM_CMD_ID_REPORT_STATUS = 4, 203 KFWUM_CMD_ID_GET_FIRMWARE_STATUS = 7, 204 KFWUM_CMD_ID_START_FIRMWARE_UPDATE = 9, 205 KFWUM_CMD_ID_START_FIRMWARE_IMAGE = 0x0a, 206 KFWUM_CMD_ID_SAVE_FIRMWARE_IMAGE = 0x0b, 207 KFWUM_CMD_ID_FINISH_FIRMWARE_IMAGE = 0x0c, 208 KFWUM_CMD_ID_READ_FIRMWARE_IMAGE = 0x0d, 209 KFWUM_CMD_ID_MANUAL_ROLLBACK = 0x0e, 210 KFWUM_CMD_ID_GET_TRACE_LOG = 0x0f, 211 KFWUM_CMD_ID_STD_MAX_CMD, 212 KFWUM_CMD_ID_EXTENDED_CMD = 0xC0 213 } tKFWUM_CmdId; 214 215 int 216 ipmi_fwum_info(struct ipmi_intf *intf) 217 { 218 tKFWUM_BoardInfo b_info; 219 int rc = 0; 220 unsigned char not_used; 221 if (verbose) { 222 printf("Getting Kontron FWUM Info\n"); 223 } 224 if (KfwumGetDeviceInfo(intf, 1, &b_info) != 0) { 225 rc = (-1); 226 } 227 if (KfwumGetInfo(intf, 1, ¬_used) != 0) { 228 rc = (-1); 229 } 230 return rc; 231 } 232 233 int 234 ipmi_fwum_status(struct ipmi_intf *intf) 235 { 236 if (verbose) { 237 printf("Getting Kontron FWUM Status\n"); 238 } 239 if (KfwumGetStatus(intf) != 0) { 240 return (-1); 241 } 242 return 0; 243 } 244 245 /* ipmi_fwum_fwupgrade - function implements download/upload of the firmware 246 * data received as parameters 247 * 248 * @file: fw file 249 * @action: 0 = download, 1 = upload/start upload 250 * 251 * returns 0 on success, otherwise (-1) 252 */ 253 int 254 ipmi_fwum_fwupgrade(struct ipmi_intf *intf, char *file, int action) 255 { 256 tKFWUM_BoardInfo b_info; 257 tKFWUM_InFirmwareInfo fw_info = { 0 }; 258 unsigned short padding; 259 unsigned long fsize = 0; 260 unsigned char not_used; 261 if (file == NULL) { 262 lprintf(LOG_ERR, "No file given."); 263 return (-1); 264 } 265 if (KfwumGetFileSize(file, &fsize) != 0) { 266 return (-1); 267 } 268 if (KfwumSetupBuffersFromFile(file, fsize) != 0) { 269 return (-1); 270 } 271 padding = KfwumCalculateChecksumPadding(firmBuf, fsize); 272 if (KfwumGetInfoFromFirmware(firmBuf, fsize, &fw_info) != 0) { 273 return (-1); 274 } 275 if (KfwumGetDeviceInfo(intf, 0, &b_info) != 0) { 276 return (-1); 277 } 278 if (ipmi_kfwum_checkfwcompat(b_info, fw_info) != 0) { 279 return (-1); 280 } 281 KfwumGetInfo(intf, 0, ¬_used); 282 printf_kfwum_info(b_info, fw_info); 283 if (KfwumStartFirmwareImage(intf, fsize, padding) != 0) { 284 return (-1); 285 } 286 if (KfwumUploadFirmware(intf, firmBuf, fsize) != 0) { 287 return (-1); 288 } 289 if (KfwumFinishFirmwareImage(intf, fw_info) != 0) { 290 return (-1); 291 } 292 if (KfwumGetStatus(intf) != 0) { 293 return (-1); 294 } 295 if (action != 0) { 296 if (KfwumStartFirmwareUpgrade(intf) != 0) { 297 return (-1); 298 } 299 } 300 return 0; 301 } 302 303 /* KfwumGetFileSize - gets the file size 304 * 305 * @pFileName : filename ptr 306 * @pFileSize : output ptr for filesize 307 * 308 * returns 0 on success, otherwise (-1) 309 */ 310 int 311 KfwumGetFileSize(const char *pFileName, unsigned long *pFileSize) 312 { 313 FILE *pFileHandle = NULL; 314 pFileHandle = fopen(pFileName, "rb"); 315 if (pFileHandle == NULL) { 316 return (-1); 317 } 318 if (fseek(pFileHandle, 0L , SEEK_END) == 0) { 319 *pFileSize = ftell(pFileHandle); 320 } 321 fclose(pFileHandle); 322 if (*pFileSize != 0) { 323 return 0; 324 } 325 return (-1); 326 } 327 328 /* KfwumSetupBuffersFromFile - small buffers are used to store the file data 329 * 330 * @pFileName : filename ptr 331 * unsigned long : filesize 332 * 333 * returns 0 on success, otherwise (-1) 334 */ 335 int 336 KfwumSetupBuffersFromFile(const char *pFileName, unsigned long fileSize) 337 { 338 int rc = (-1); 339 FILE *pFileHandle = NULL; 340 int count; 341 int modulus; 342 int qty = 0; 343 344 pFileHandle = fopen(pFileName, "rb"); 345 if (pFileHandle == NULL) { 346 lprintf(LOG_ERR, "Failed to open '%s' for reading.", 347 pFileName); 348 return (-1); 349 } 350 count = fileSize / MAX_BUFFER_SIZE; 351 modulus = fileSize % MAX_BUFFER_SIZE; 352 353 rewind(pFileHandle); 354 for (qty = 0; qty < count; qty++) { 355 KfwumShowProgress("Reading Firmware from File", 356 qty, count); 357 if (fread(&firmBuf[qty * MAX_BUFFER_SIZE], 1, 358 MAX_BUFFER_SIZE, 359 pFileHandle) == MAX_BUFFER_SIZE) { 360 rc = 0; 361 } 362 } 363 if (modulus) { 364 if (fread(&firmBuf[qty * MAX_BUFFER_SIZE], 1, 365 modulus, pFileHandle) == modulus) { 366 rc = 0; 367 } 368 } 369 if (rc == 0) { 370 KfwumShowProgress("Reading Firmware from File", 100, 100); 371 } 372 fclose(pFileHandle); 373 return rc; 374 } 375 376 /* KfwumShowProgress - helper routine to display progress bar 377 * 378 * Converts current/total in percent 379 * 380 * *task : string identifying current operation 381 * current: progress 382 * total : limit 383 */ 384 void 385 KfwumShowProgress(const char *task, unsigned long current, unsigned long total) 386 { 387 # define PROG_LENGTH 42 388 static unsigned long staticProgress=0xffffffff; 389 unsigned char spaces[PROG_LENGTH + 1]; 390 unsigned short hash; 391 float percent = ((float)current / total); 392 unsigned long progress = 100 * (percent); 393 394 if (staticProgress == progress) { 395 /* We displayed the same last time.. so don't do it */ 396 return; 397 } 398 staticProgress = progress; 399 printf("%-25s : ", task); /* total 20 bytes */ 400 hash = (percent * PROG_LENGTH); 401 memset(spaces, '#', hash); 402 spaces[hash] = '\0'; 403 404 printf("%s", spaces); 405 memset(spaces, ' ', (PROG_LENGTH - hash)); 406 spaces[(PROG_LENGTH - hash)] = '\0'; 407 printf("%s", spaces ); 408 409 printf(" %3ld %%\r", progress); /* total 7 bytes */ 410 if (progress == 100) { 411 printf("\n"); 412 } 413 fflush(stdout); 414 } 415 416 /* KfwumCalculateChecksumPadding - TBD 417 */ 418 unsigned short 419 KfwumCalculateChecksumPadding(unsigned char *pBuffer, unsigned long totalSize) 420 { 421 unsigned short sumOfBytes = 0; 422 unsigned short padding; 423 unsigned long counter; 424 for (counter = 0; counter < totalSize; counter ++) { 425 sumOfBytes += pBuffer[counter]; 426 } 427 padding = 0 - sumOfBytes; 428 return padding; 429 } 430 431 /* KfwumGetInfo - Get Firmware Update Manager (FWUM) information 432 * 433 * *intf : IPMI interface 434 * output : when set to non zero, queried information is displayed 435 * pNumBank: output ptr for number of banks 436 * 437 * returns 0 on success, otherwise (-1) 438 */ 439 int 440 KfwumGetInfo(struct ipmi_intf *intf, unsigned char output, 441 unsigned char *pNumBank) 442 { 443 int rc = 0; 444 static struct KfwumGetInfoResp *pGetInfo; 445 struct ipmi_rs *rsp; 446 struct ipmi_rq req; 447 448 memset(&req, 0, sizeof(req)); 449 req.msg.netfn = IPMI_NETFN_FIRMWARE; 450 req.msg.cmd = KFWUM_CMD_ID_GET_FIRMWARE_INFO; 451 req.msg.data_len = 0; 452 453 rsp = intf->sendrecv(intf, &req); 454 if (!rsp) { 455 lprintf(LOG_ERR, "Error in FWUM Firmware Get Info Command."); 456 return (-1); 457 } else if (rsp->ccode != 0) { 458 lprintf(LOG_ERR, "FWUM Firmware Get Info returned %x", 459 rsp->ccode); 460 return (-1); 461 } 462 463 pGetInfo = (struct KfwumGetInfoResp *)rsp->data; 464 if (output) { 465 printf("\nFWUM info\n"); 466 printf("=========\n"); 467 printf("Protocol Revision : %02Xh\n", 468 pGetInfo->protocolRevision); 469 printf("Controller Device Id : %02Xh\n", 470 pGetInfo->controllerDeviceId); 471 printf("Firmware Revision : %u.%u%u", 472 pGetInfo->firmRev1, pGetInfo->firmRev2 >> 4, 473 pGetInfo->firmRev2 & 0x0f); 474 if (pGetInfo->byte.mode != 0) { 475 printf(" - DEBUG BUILD\n"); 476 } else { 477 printf("\n"); 478 } 479 printf("Number Of Memory Bank : %u\n", pGetInfo->numBank); 480 } 481 *pNumBank = pGetInfo->numBank; 482 /* Determine wich type of download to use: */ 483 /* Old FWUM or Old IPMC fw (data_len < 7) 484 * --> Address with small buffer size 485 */ 486 if ((pGetInfo->protocolRevision) <= 0x05 || (rsp->data_len < 7 )) { 487 save_fw_nfo.downloadType = KFWUM_DOWNLOAD_TYPE_ADDRESS; 488 save_fw_nfo.bufferSize = KFWUM_SMALL_BUFFER; 489 save_fw_nfo.overheadSize = KFWUM_OLD_CMD_OVERHEAD; 490 if (verbose) { 491 printf("Protocol Revision :"); 492 printf(" <= 5 detected, adjusting buffers\n"); 493 } 494 } else { 495 /* Both fw are using the new protocol */ 496 save_fw_nfo.downloadType = KFWUM_DOWNLOAD_TYPE_SEQUENCE; 497 save_fw_nfo.overheadSize = KFWUM_NEW_CMD_OVERHEAD; 498 /* Buffer size depending on access type (Local or remote) */ 499 /* Look if we run remote or locally */ 500 if (verbose) { 501 printf("Protocol Revision :"); 502 printf(" > 5 optimizing buffers\n"); 503 } 504 if (strstr(intf->name,"lan") != NULL) { 505 /* also covers lanplus */ 506 save_fw_nfo.bufferSize = KFWUM_SMALL_BUFFER; 507 if (verbose) { 508 printf("IOL payload size : %d\n", 509 save_fw_nfo.bufferSize); 510 } 511 } else if ((strstr(intf->name,"open")!= NULL) 512 && intf->target_addr != IPMI_BMC_SLAVE_ADDR 513 && (intf->target_addr != intf->my_addr)) { 514 save_fw_nfo.bufferSize = KFWUM_SMALL_BUFFER; 515 if (verbose) { 516 printf("IPMB payload size : %d\n", 517 save_fw_nfo.bufferSize); 518 } 519 } else { 520 save_fw_nfo.bufferSize = KFWUM_BIG_BUFFER; 521 if (verbose) { 522 printf("SMI payload size : %d\n", 523 save_fw_nfo.bufferSize); 524 } 525 } 526 } 527 return rc; 528 } 529 530 /* KfwumGetDeviceInfo - Get IPMC/Board information 531 * 532 * *intf: IPMI interface 533 * output: when set to non zero, queried information is displayed 534 * tKFWUM_BoardInfo: output ptr for IPMC/Board information 535 * 536 * returns 0 on success, otherwise (-1) 537 */ 538 int 539 KfwumGetDeviceInfo(struct ipmi_intf *intf, unsigned char output, 540 tKFWUM_BoardInfo *pBoardInfo) 541 { 542 struct ipm_devid_rsp *pGetDevId; 543 struct ipmi_rs *rsp; 544 struct ipmi_rq req; 545 /* Send Get Device Id */ 546 memset(&req, 0, sizeof(req)); 547 req.msg.netfn = IPMI_NETFN_APP; 548 req.msg.cmd = BMC_GET_DEVICE_ID; 549 req.msg.data_len = 0; 550 551 rsp = intf->sendrecv(intf, &req); 552 if (rsp == NULL) { 553 lprintf(LOG_ERR, "Error in Get Device Id Command"); 554 return (-1); 555 } else if (rsp->ccode != 0) { 556 lprintf(LOG_ERR, "Get Device Id returned %x", 557 rsp->ccode); 558 return (-1); 559 } 560 pGetDevId = (struct ipm_devid_rsp *)rsp->data; 561 pBoardInfo->iana = IPM_DEV_MANUFACTURER_ID(pGetDevId->manufacturer_id); 562 pBoardInfo->boardId = buf2short(pGetDevId->product_id); 563 if (output) { 564 printf("\nIPMC Info\n"); 565 printf("=========\n"); 566 printf("Manufacturer Id : %u\n", 567 pBoardInfo->iana); 568 printf("Board Id : %u\n", 569 pBoardInfo->boardId); 570 printf("Firmware Revision : %u.%u%u", 571 pGetDevId->fw_rev1, pGetDevId->fw_rev2 >> 4, 572 pGetDevId->fw_rev2 & 0x0f); 573 if (((pBoardInfo->iana == IPMI_OEM_KONTRON) 574 && (pBoardInfo->boardId = KFWUM_BOARD_KONTRON_5002))) { 575 printf(" SDR %u", pGetDevId->aux_fw_rev[0]); 576 } 577 printf("\n"); 578 } 579 return 0; 580 } 581 582 /* KfwumGetStatus - Get (and prints) FWUM banks information 583 * 584 * *intf : IPMI interface 585 * 586 * returns 0 on success, otherwise (-1) 587 */ 588 int 589 KfwumGetStatus(struct ipmi_intf * intf) 590 { 591 int rc = 0; 592 struct ipmi_rs *rsp; 593 struct ipmi_rq req; 594 struct KfwumGetStatusResp *pGetStatus; 595 unsigned char numBank; 596 unsigned char counter; 597 unsigned long firmLength; 598 if (verbose) { 599 printf(" Getting Status!\n"); 600 } 601 /* Retreive the number of bank */ 602 rc = KfwumGetInfo(intf, 0, &numBank); 603 for(counter = 0; 604 (counter < numBank) && (rc == 0); 605 counter ++) { 606 /* Retreive the status of each bank */ 607 memset(&req, 0, sizeof(req)); 608 req.msg.netfn = IPMI_NETFN_FIRMWARE; 609 req.msg.cmd = KFWUM_CMD_ID_GET_FIRMWARE_STATUS; 610 req.msg.data = &counter; 611 req.msg.data_len = 1; 612 rsp = intf->sendrecv(intf, &req); 613 if (rsp == NULL) { 614 lprintf(LOG_ERR, 615 "Error in FWUM Firmware Get Status Command."); 616 rc = (-1); 617 break; 618 } else if (rsp->ccode) { 619 lprintf(LOG_ERR, 620 "FWUM Firmware Get Status returned %x", 621 rsp->ccode); 622 rc = (-1); 623 break; 624 } 625 pGetStatus = (struct KfwumGetStatusResp *) rsp->data; 626 printf("\nBank State %d : %s\n", 627 counter, 628 val2str(pGetStatus->bankState, bankStateValS)); 629 if (!pGetStatus->bankState) { 630 continue; 631 } 632 firmLength = pGetStatus->firmLengthMSB; 633 firmLength = firmLength << 8; 634 firmLength |= pGetStatus->firmLengthMid; 635 firmLength = firmLength << 8; 636 firmLength |= pGetStatus->firmLengthLSB; 637 printf("Firmware Length : %ld bytes\n", 638 firmLength); 639 printf("Firmware Revision : %u.%u%u SDR %u\n", 640 pGetStatus->firmRev1, 641 pGetStatus->firmRev2 >> 4, 642 pGetStatus->firmRev2 & 0x0f, 643 pGetStatus->firmRev3); 644 } 645 printf("\n"); 646 return rc; 647 } 648 649 /* KfwumManualRollback - Ask IPMC to rollback to previous version 650 * 651 * *intf : IPMI interface 652 * 653 * returns 0 on success 654 * returns (-1) on error 655 */ 656 int 657 KfwumManualRollback(struct ipmi_intf *intf) 658 { 659 struct ipmi_rs *rsp; 660 struct ipmi_rq req; 661 struct KfwumManualRollbackReq thisReq; 662 663 memset(&req, 0, sizeof(req)); 664 req.msg.netfn = IPMI_NETFN_FIRMWARE; 665 req.msg.cmd = KFWUM_CMD_ID_MANUAL_ROLLBACK; 666 thisReq.type = 0; /* Wait BMC shutdown */ 667 req.msg.data = (unsigned char *)&thisReq; 668 req.msg.data_len = 1; 669 670 rsp = intf->sendrecv(intf, &req); 671 if (rsp == NULL) { 672 lprintf(LOG_ERR, "Error in FWUM Manual Rollback Command."); 673 return (-1); 674 } else if (rsp->ccode != 0) { 675 lprintf(LOG_ERR, 676 "Error in FWUM Manual Rollback Command returned %x", 677 rsp->ccode); 678 return (-1); 679 } 680 printf("FWUM Starting Manual Rollback \n"); 681 return 0; 682 } 683 684 int 685 KfwumStartFirmwareImage(struct ipmi_intf *intf, unsigned long length, 686 unsigned short padding) 687 { 688 struct ipmi_rs *rsp; 689 struct ipmi_rq req; 690 struct KfwumStartFirmwareDownloadResp *pResp; 691 struct KfwumStartFirmwareDownloadReq thisReq; 692 693 thisReq.lengthLSB = length & 0x000000ff; 694 thisReq.lengthMid = (length >> 8) & 0x000000ff; 695 thisReq.lengthMSB = (length >> 16) & 0x000000ff; 696 thisReq.paddingLSB = padding & 0x00ff; 697 thisReq.paddingMSB = (padding>> 8) & 0x00ff; 698 thisReq.useSequence = 0x01; 699 memset(&req, 0, sizeof(req)); 700 req.msg.netfn = IPMI_NETFN_FIRMWARE; 701 req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_IMAGE; 702 req.msg.data = (unsigned char *) &thisReq; 703 /* Look for download type */ 704 if (save_fw_nfo.downloadType == KFWUM_DOWNLOAD_TYPE_ADDRESS) { 705 req.msg.data_len = 5; 706 } else { 707 req.msg.data_len = 6; 708 } 709 rsp = intf->sendrecv(intf, &req); 710 if (rsp == NULL) { 711 lprintf(LOG_ERR, 712 "Error in FWUM Firmware Start Firmware Image Download Command."); 713 return (-1); 714 } else if (rsp->ccode) { 715 lprintf(LOG_ERR, 716 "FWUM Firmware Start Firmware Image Download returned %x", 717 rsp->ccode); 718 return (-1); 719 } 720 pResp = (struct KfwumStartFirmwareDownloadResp *)rsp->data; 721 printf("Bank holding new firmware : %d\n", pResp->bank); 722 sleep(5); 723 return 0; 724 } 725 726 int 727 KfwumSaveFirmwareImage(struct ipmi_intf *intf, unsigned char sequenceNumber, 728 unsigned long address, unsigned char *pFirmBuf, 729 unsigned char *pInBufLength) 730 { 731 int rc = 0; 732 struct ipmi_rs *rsp; 733 struct ipmi_rq req; 734 struct KfwumSaveFirmwareAddressReq addr_req; 735 struct KfwumSaveFirmwareSequenceReq seq_req; 736 int retry = 0; 737 int no_rsp = 0; 738 do { 739 memset(&req, 0, sizeof(req)); 740 req.msg.netfn = IPMI_NETFN_FIRMWARE; 741 req.msg.cmd = KFWUM_CMD_ID_SAVE_FIRMWARE_IMAGE; 742 if (save_fw_nfo.downloadType == KFWUM_DOWNLOAD_TYPE_ADDRESS) { 743 addr_req.addressLSB = address & 0x000000ff; 744 addr_req.addressMid = (address >> 8) & 0x000000ff; 745 addr_req.addressMSB = (address >> 16) & 0x000000ff; 746 addr_req.numBytes = *pInBufLength; 747 memcpy(addr_req.txBuf, pFirmBuf, *pInBufLength); 748 req.msg.data = (unsigned char *)&addr_req; 749 req.msg.data_len = *pInBufLength + 4; 750 } else { 751 seq_req.sequenceNumber = sequenceNumber; 752 memcpy(seq_req.txBuf, pFirmBuf, *pInBufLength); 753 req.msg.data = (unsigned char *)&seq_req; 754 req.msg.data_len = *pInBufLength + sizeof(unsigned char); 755 /* + 1 => sequenceNumber*/ 756 } 757 rsp = intf->sendrecv(intf, &req); 758 if (rsp == NULL) { 759 lprintf(LOG_ERR, 760 "Error in FWUM Firmware Save Firmware Image Download Command."); 761 /* We don't receive "C7" on errors with IOL, 762 * instead we receive nothing 763 */ 764 if (strstr(intf->name, "lan") != NULL) { 765 no_rsp++; 766 if (no_rsp < FWUM_SAVE_FIRMWARE_NO_RESPONSE_LIMIT) { 767 *pInBufLength -= 1; 768 continue; 769 } 770 lprintf(LOG_ERR, 771 "Error, too many commands without response."); 772 *pInBufLength = 0; 773 break; 774 } /* For other interface keep trying */ 775 } else if (rsp->ccode != 0) { 776 if (rsp->ccode == 0xc0) { 777 sleep(1); 778 } else if ((rsp->ccode == 0xc7) 779 || ((rsp->ccode == 0xc3) 780 && (sequenceNumber == 0))) { 781 *pInBufLength -= 1; 782 retry = 1; 783 } else if (rsp->ccode == 0x82) { 784 /* Double sent, continue */ 785 rc = 0; 786 break; 787 } else if (rsp->ccode == 0x83) { 788 if (retry == 0) { 789 retry = 1; 790 continue; 791 } 792 rc = (-1); 793 break; 794 } else if (rsp->ccode == 0xcf) { 795 /* Ok if receive duplicated request */ 796 retry = 1; 797 } else if (rsp->ccode == 0xc3) { 798 if (retry == 0) { 799 retry = 1; 800 continue; 801 } 802 rc = (-1); 803 break; 804 } else { 805 lprintf(LOG_ERR, 806 "FWUM Firmware Save Firmware Image Download returned %x", 807 rsp->ccode); 808 rc = (-1); 809 break; 810 } 811 } else { 812 break; 813 } 814 } while (1); 815 return rc; 816 } 817 818 int 819 KfwumFinishFirmwareImage(struct ipmi_intf *intf, tKFWUM_InFirmwareInfo firmInfo) 820 { 821 struct ipmi_rs *rsp; 822 struct ipmi_rq req; 823 struct KfwumFinishFirmwareDownloadReq thisReq; 824 825 thisReq.versionMaj = firmInfo.versMajor; 826 thisReq.versionMinSub = ((firmInfo.versMinor <<4) 827 | firmInfo.versSubMinor); 828 thisReq.versionSdr = firmInfo.sdrRev; 829 thisReq.reserved = 0; 830 /* Byte 4 reserved, write 0 */ 831 memset(&req, 0, sizeof(req)); 832 req.msg.netfn = IPMI_NETFN_FIRMWARE; 833 req.msg.cmd = KFWUM_CMD_ID_FINISH_FIRMWARE_IMAGE; 834 req.msg.data = (unsigned char *)&thisReq; 835 req.msg.data_len = 4; 836 /* Infinite loop if BMC doesn't reply or replies 0xc0 every time. */ 837 do { 838 rsp = intf->sendrecv(intf, &req); 839 } while (rsp == NULL || rsp->ccode == 0xc0); 840 if (!rsp) { 841 lprintf(LOG_ERR, 842 "Error in FWUM Firmware Finish Firmware Image Download Command."); 843 return (-1); 844 } else if (rsp->ccode != 0) { 845 lprintf(LOG_ERR, 846 "FWUM Firmware Finish Firmware Image Download returned %x", 847 rsp->ccode); 848 return (-1); 849 } 850 return 0; 851 } 852 853 int 854 KfwumUploadFirmware(struct ipmi_intf *intf, unsigned char *pBuffer, 855 unsigned long totalSize) 856 { 857 int rc = (-1); 858 unsigned long address = 0x0; 859 unsigned char writeSize; 860 unsigned char oldWriteSize; 861 unsigned long lastAddress = 0; 862 unsigned char sequenceNumber = 0; 863 unsigned char retry = FWUM_MAX_UPLOAD_RETRY; 864 unsigned char isLengthValid = 1; 865 do { 866 writeSize = save_fw_nfo.bufferSize - save_fw_nfo.overheadSize; 867 /* Reach the end */ 868 if (address + writeSize > totalSize) { 869 writeSize = (totalSize - address); 870 } else if (((address % KFWUM_PAGE_SIZE) 871 + writeSize) > KFWUM_PAGE_SIZE) { 872 /* Reach boundary end */ 873 writeSize = (KFWUM_PAGE_SIZE - (address % KFWUM_PAGE_SIZE)); 874 } 875 oldWriteSize = writeSize; 876 rc = KfwumSaveFirmwareImage(intf, sequenceNumber, 877 address, &pBuffer[address], &writeSize); 878 if ((rc != 0) && (retry-- != 0)) { 879 address = lastAddress; 880 rc = 0; 881 } else if ( writeSize == 0) { 882 rc = (-1); 883 } else { 884 if (writeSize != oldWriteSize) { 885 printf("Adjusting length to %d bytes \n", 886 writeSize); 887 save_fw_nfo.bufferSize -= (oldWriteSize - writeSize); 888 } 889 retry = FWUM_MAX_UPLOAD_RETRY; 890 lastAddress = address; 891 address+= writeSize; 892 } 893 if (rc == 0) { 894 if ((address % 1024) == 0) { 895 KfwumShowProgress("Writing Firmware in Flash", 896 address, totalSize); 897 } 898 sequenceNumber++; 899 } 900 } while ((rc == 0) && (address < totalSize)); 901 if (rc == 0) { 902 KfwumShowProgress("Writing Firmware in Flash", 903 100, 100); 904 } 905 return rc; 906 } 907 908 int 909 KfwumStartFirmwareUpgrade(struct ipmi_intf *intf) 910 { 911 int rc = 0; 912 struct ipmi_rs *rsp; 913 struct ipmi_rq req; 914 /* Upgrade type, wait BMC shutdown */ 915 unsigned char upgType = 0 ; 916 917 memset(&req, 0, sizeof(req)); 918 req.msg.netfn = IPMI_NETFN_FIRMWARE; 919 req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_UPDATE; 920 req.msg.data = (unsigned char *) &upgType; 921 req.msg.data_len = 1; 922 923 rsp = intf->sendrecv(intf, &req); 924 if (rsp == NULL) { 925 lprintf(LOG_ERR, 926 "Error in FWUM Firmware Start Firmware Upgrade Command"); 927 rc = (-1); 928 } else if (rsp->ccode) { 929 if (rsp->ccode == 0xd5) { 930 lprintf(LOG_ERR, 931 "No firmware available for upgrade. Download Firmware first."); 932 } else { 933 lprintf(LOG_ERR, 934 "FWUM Firmware Start Firmware Upgrade returned %x", 935 rsp->ccode); 936 } 937 rc = (-1); 938 } 939 return rc; 940 } 941 942 int 943 KfwumGetTraceLog(struct ipmi_intf *intf) 944 { 945 int rc = 0; 946 struct ipmi_rs *rsp; 947 struct ipmi_rq req; 948 unsigned char chunkIdx; 949 unsigned char cmdIdx; 950 if (verbose) { 951 printf(" Getting Trace Log!\n"); 952 } 953 for (chunkIdx = 0; 954 (chunkIdx < TRACE_LOG_CHUNK_COUNT) 955 && (rc == 0); 956 chunkIdx++) { 957 /* Retreive each log chunk and print it */ 958 memset(&req, 0, sizeof(req)); 959 req.msg.netfn = IPMI_NETFN_FIRMWARE; 960 req.msg.cmd = KFWUM_CMD_ID_GET_TRACE_LOG; 961 req.msg.data = &chunkIdx; 962 req.msg.data_len = 1; 963 964 rsp = intf->sendrecv(intf, &req); 965 if (rsp == NULL) { 966 lprintf(LOG_ERR, 967 "Error in FWUM Firmware Get Trace Log Command"); 968 rc = (-1); 969 break; 970 } else if (rsp->ccode) { 971 lprintf(LOG_ERR, 972 "FWUM Firmware Get Trace Log returned %x", 973 rsp->ccode); 974 rc = (-1); 975 break; 976 } 977 for (cmdIdx=0; cmdIdx < TRACE_LOG_CHUNK_SIZE; cmdIdx++) { 978 /* Don't diplay commands with an invalid state */ 979 if ((rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1] != 0) 980 && (rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx] < KFWUM_CMD_ID_STD_MAX_CMD)) { 981 printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n", 982 CMD_ID_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx]], 983 CMD_STATE_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1]], 984 rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 2]); 985 } else if ((rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1] != 0) 986 && (rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx] >= KFWUM_CMD_ID_EXTENDED_CMD)) { 987 printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n", 988 EXT_CMD_ID_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx] - KFWUM_CMD_ID_EXTENDED_CMD], 989 CMD_STATE_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1]], 990 rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 2]); 991 } 992 } 993 } 994 printf("\n"); 995 return rc; 996 } 997 998 int 999 KfwumGetInfoFromFirmware(unsigned char *pBuf, unsigned long bufSize, 1000 tKFWUM_InFirmwareInfo *pInfo) 1001 { 1002 unsigned long offset = 0; 1003 if (bufSize < (IN_FIRMWARE_INFO_OFFSET_LOCATION + IN_FIRMWARE_INFO_SIZE)) { 1004 return (-1); 1005 } 1006 offset = IN_FIRMWARE_INFO_OFFSET_LOCATION; 1007 1008 /* Now, fill the structure with read informations */ 1009 pInfo->checksum = (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1010 offset + 0 + IN_FIRMWARE_INFO_OFFSET_CHECKSUM ) << 8; 1011 1012 pInfo->checksum|= (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1013 offset + 1 + IN_FIRMWARE_INFO_OFFSET_CHECKSUM); 1014 1015 pInfo->sumToRemoveFromChecksum = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1016 offset + IN_FIRMWARE_INFO_OFFSET_CHECKSUM); 1017 1018 pInfo->sumToRemoveFromChecksum+= KWUM_GET_BYTE_AT_OFFSET(pBuf, 1019 offset + IN_FIRMWARE_INFO_OFFSET_CHECKSUM + 1); 1020 1021 pInfo->fileSize = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1022 offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 0) << 24; 1023 1024 pInfo->fileSize|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1025 offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 1) << 16; 1026 1027 pInfo->fileSize|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1028 offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 2) << 8; 1029 1030 pInfo->fileSize|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1031 offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 3); 1032 1033 pInfo->boardId = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1034 offset + IN_FIRMWARE_INFO_OFFSET_BOARD_ID + 0) << 8; 1035 1036 pInfo->boardId|= KWUM_GET_BYTE_AT_OFFSET(pBuf, 1037 offset + IN_FIRMWARE_INFO_OFFSET_BOARD_ID + 1); 1038 1039 pInfo->deviceId = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1040 offset + IN_FIRMWARE_INFO_OFFSET_DEVICE_ID); 1041 1042 pInfo->tableVers = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1043 offset + IN_FIRMWARE_INFO_OFFSET_TABLE_VERSION); 1044 1045 pInfo->implRev = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1046 offset + IN_FIRMWARE_INFO_OFFSET_IMPLEMENT_REV); 1047 1048 pInfo->versMajor = (KWUM_GET_BYTE_AT_OFFSET(pBuf, 1049 offset 1050 + IN_FIRMWARE_INFO_OFFSET_VER_MAJOROR)) & 0x0f; 1051 1052 pInfo->versMinor = (KWUM_GET_BYTE_AT_OFFSET(pBuf, 1053 offset 1054 + IN_FIRMWARE_INFO_OFFSET_VER_MINORSUB) >> 4) & 0x0f; 1055 1056 pInfo->versSubMinor = (KWUM_GET_BYTE_AT_OFFSET(pBuf, 1057 offset + IN_FIRMWARE_INFO_OFFSET_VER_MINORSUB)) & 0x0f; 1058 1059 pInfo->sdrRev = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1060 offset + IN_FIRMWARE_INFO_OFFSET_SDR_REV); 1061 1062 pInfo->iana = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1063 offset + IN_FIRMWARE_INFO_OFFSET_IANA2) << 16; 1064 1065 pInfo->iana|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1066 offset + IN_FIRMWARE_INFO_OFFSET_IANA1) << 8; 1067 1068 pInfo->iana|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1069 offset + IN_FIRMWARE_INFO_OFFSET_IANA0); 1070 1071 KfwumFixTableVersionForOldFirmware(pInfo); 1072 return 0; 1073 } 1074 1075 void 1076 KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo * pInfo) 1077 { 1078 switch(pInfo->boardId) { 1079 case KFWUM_BOARD_KONTRON_UNKNOWN: 1080 pInfo->tableVers = 0xff; 1081 break; 1082 default: 1083 /* pInfo->tableVers is already set for 1084 * the right version 1085 */ 1086 break; 1087 } 1088 } 1089 1090 /* ipmi_kfwum_checkfwcompat - check whether firmware we're about to upload is 1091 * compatible with board. 1092 * 1093 * @boardInfo: 1094 * @firmInfo: 1095 * 1096 * returns 0 if compatible, otherwise (-1) 1097 */ 1098 int 1099 ipmi_kfwum_checkfwcompat(tKFWUM_BoardInfo boardInfo, 1100 tKFWUM_InFirmwareInfo firmInfo) 1101 { 1102 int compatible = 0; 1103 if (boardInfo.iana != firmInfo.iana) { 1104 lprintf(LOG_ERR, 1105 "Board IANA does not match firmware IANA."); 1106 compatible = (-1); 1107 } 1108 if (boardInfo.boardId != firmInfo.boardId) { 1109 lprintf(LOG_ERR, 1110 "Board IANA does not match firmware IANA."); 1111 compatible = (-1); 1112 } 1113 if (compatible != 0) { 1114 lprintf(LOG_ERR, 1115 "Firmware invalid for target board. Download of upgrade aborted."); 1116 } 1117 return compatible; 1118 } 1119 1120 void 1121 printf_kfwum_info(tKFWUM_BoardInfo boardInfo, tKFWUM_InFirmwareInfo firmInfo) 1122 { 1123 printf( 1124 "Target Board Id : %u\n", boardInfo.boardId); 1125 printf( 1126 "Target IANA number : %u\n", boardInfo.iana); 1127 printf( 1128 "File Size : %lu bytes\n", firmInfo.fileSize); 1129 printf( 1130 "Firmware Version : %d.%d%d SDR %d\n", firmInfo.versMajor, 1131 firmInfo.versMinor, firmInfo.versSubMinor, firmInfo.sdrRev); 1132 } 1133