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 841 if (rsp->ccode != 0) { 842 lprintf(LOG_ERR, 843 "FWUM Firmware Finish Firmware Image Download returned %x", 844 rsp->ccode); 845 return (-1); 846 } 847 return 0; 848 } 849 850 int 851 KfwumUploadFirmware(struct ipmi_intf *intf, unsigned char *pBuffer, 852 unsigned long totalSize) 853 { 854 int rc = (-1); 855 unsigned long address = 0x0; 856 unsigned char writeSize; 857 unsigned char oldWriteSize; 858 unsigned long lastAddress = 0; 859 unsigned char sequenceNumber = 0; 860 unsigned char retry = FWUM_MAX_UPLOAD_RETRY; 861 do { 862 writeSize = save_fw_nfo.bufferSize - save_fw_nfo.overheadSize; 863 /* Reach the end */ 864 if (address + writeSize > totalSize) { 865 writeSize = (totalSize - address); 866 } else if (((address % KFWUM_PAGE_SIZE) 867 + writeSize) > KFWUM_PAGE_SIZE) { 868 /* Reach boundary end */ 869 writeSize = (KFWUM_PAGE_SIZE - (address % KFWUM_PAGE_SIZE)); 870 } 871 oldWriteSize = writeSize; 872 rc = KfwumSaveFirmwareImage(intf, sequenceNumber, 873 address, &pBuffer[address], &writeSize); 874 if ((rc != 0) && (retry-- != 0)) { 875 address = lastAddress; 876 rc = 0; 877 } else if ( writeSize == 0) { 878 rc = (-1); 879 } else { 880 if (writeSize != oldWriteSize) { 881 printf("Adjusting length to %d bytes \n", 882 writeSize); 883 save_fw_nfo.bufferSize -= (oldWriteSize - writeSize); 884 } 885 retry = FWUM_MAX_UPLOAD_RETRY; 886 lastAddress = address; 887 address+= writeSize; 888 } 889 if (rc == 0) { 890 if ((address % 1024) == 0) { 891 KfwumShowProgress("Writing Firmware in Flash", 892 address, totalSize); 893 } 894 sequenceNumber++; 895 } 896 } while ((rc == 0) && (address < totalSize)); 897 if (rc == 0) { 898 KfwumShowProgress("Writing Firmware in Flash", 899 100, 100); 900 } 901 return rc; 902 } 903 904 int 905 KfwumStartFirmwareUpgrade(struct ipmi_intf *intf) 906 { 907 int rc = 0; 908 struct ipmi_rs *rsp; 909 struct ipmi_rq req; 910 /* Upgrade type, wait BMC shutdown */ 911 unsigned char upgType = 0 ; 912 913 memset(&req, 0, sizeof(req)); 914 req.msg.netfn = IPMI_NETFN_FIRMWARE; 915 req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_UPDATE; 916 req.msg.data = (unsigned char *) &upgType; 917 req.msg.data_len = 1; 918 919 rsp = intf->sendrecv(intf, &req); 920 if (rsp == NULL) { 921 lprintf(LOG_ERR, 922 "Error in FWUM Firmware Start Firmware Upgrade Command"); 923 rc = (-1); 924 } else if (rsp->ccode) { 925 if (rsp->ccode == 0xd5) { 926 lprintf(LOG_ERR, 927 "No firmware available for upgrade. Download Firmware first."); 928 } else { 929 lprintf(LOG_ERR, 930 "FWUM Firmware Start Firmware Upgrade returned %x", 931 rsp->ccode); 932 } 933 rc = (-1); 934 } 935 return rc; 936 } 937 938 int 939 KfwumGetTraceLog(struct ipmi_intf *intf) 940 { 941 int rc = 0; 942 struct ipmi_rs *rsp; 943 struct ipmi_rq req; 944 unsigned char chunkIdx; 945 unsigned char cmdIdx; 946 if (verbose) { 947 printf(" Getting Trace Log!\n"); 948 } 949 for (chunkIdx = 0; 950 (chunkIdx < TRACE_LOG_CHUNK_COUNT) 951 && (rc == 0); 952 chunkIdx++) { 953 /* Retreive each log chunk and print it */ 954 memset(&req, 0, sizeof(req)); 955 req.msg.netfn = IPMI_NETFN_FIRMWARE; 956 req.msg.cmd = KFWUM_CMD_ID_GET_TRACE_LOG; 957 req.msg.data = &chunkIdx; 958 req.msg.data_len = 1; 959 960 rsp = intf->sendrecv(intf, &req); 961 if (rsp == NULL) { 962 lprintf(LOG_ERR, 963 "Error in FWUM Firmware Get Trace Log Command"); 964 rc = (-1); 965 break; 966 } else if (rsp->ccode) { 967 lprintf(LOG_ERR, 968 "FWUM Firmware Get Trace Log returned %x", 969 rsp->ccode); 970 rc = (-1); 971 break; 972 } 973 for (cmdIdx=0; cmdIdx < TRACE_LOG_CHUNK_SIZE; cmdIdx++) { 974 /* Don't diplay commands with an invalid state */ 975 if ((rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1] != 0) 976 && (rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx] < KFWUM_CMD_ID_STD_MAX_CMD)) { 977 printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n", 978 CMD_ID_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx]], 979 CMD_STATE_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1]], 980 rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 2]); 981 } else if ((rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1] != 0) 982 && (rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx] >= KFWUM_CMD_ID_EXTENDED_CMD)) { 983 printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n", 984 EXT_CMD_ID_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx] - KFWUM_CMD_ID_EXTENDED_CMD], 985 CMD_STATE_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1]], 986 rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 2]); 987 } 988 } 989 } 990 printf("\n"); 991 return rc; 992 } 993 994 int 995 KfwumGetInfoFromFirmware(unsigned char *pBuf, unsigned long bufSize, 996 tKFWUM_InFirmwareInfo *pInfo) 997 { 998 unsigned long offset = 0; 999 if (bufSize < (IN_FIRMWARE_INFO_OFFSET_LOCATION + IN_FIRMWARE_INFO_SIZE)) { 1000 return (-1); 1001 } 1002 offset = IN_FIRMWARE_INFO_OFFSET_LOCATION; 1003 1004 /* Now, fill the structure with read informations */ 1005 pInfo->checksum = (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1006 offset + 0 + IN_FIRMWARE_INFO_OFFSET_CHECKSUM ) << 8; 1007 1008 pInfo->checksum|= (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1009 offset + 1 + IN_FIRMWARE_INFO_OFFSET_CHECKSUM); 1010 1011 pInfo->sumToRemoveFromChecksum = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1012 offset + IN_FIRMWARE_INFO_OFFSET_CHECKSUM); 1013 1014 pInfo->sumToRemoveFromChecksum+= KWUM_GET_BYTE_AT_OFFSET(pBuf, 1015 offset + IN_FIRMWARE_INFO_OFFSET_CHECKSUM + 1); 1016 1017 pInfo->fileSize = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1018 offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 0) << 24; 1019 1020 pInfo->fileSize|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1021 offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 1) << 16; 1022 1023 pInfo->fileSize|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1024 offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 2) << 8; 1025 1026 pInfo->fileSize|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1027 offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 3); 1028 1029 pInfo->boardId = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1030 offset + IN_FIRMWARE_INFO_OFFSET_BOARD_ID + 0) << 8; 1031 1032 pInfo->boardId|= KWUM_GET_BYTE_AT_OFFSET(pBuf, 1033 offset + IN_FIRMWARE_INFO_OFFSET_BOARD_ID + 1); 1034 1035 pInfo->deviceId = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1036 offset + IN_FIRMWARE_INFO_OFFSET_DEVICE_ID); 1037 1038 pInfo->tableVers = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1039 offset + IN_FIRMWARE_INFO_OFFSET_TABLE_VERSION); 1040 1041 pInfo->implRev = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1042 offset + IN_FIRMWARE_INFO_OFFSET_IMPLEMENT_REV); 1043 1044 pInfo->versMajor = (KWUM_GET_BYTE_AT_OFFSET(pBuf, 1045 offset 1046 + IN_FIRMWARE_INFO_OFFSET_VER_MAJOROR)) & 0x0f; 1047 1048 pInfo->versMinor = (KWUM_GET_BYTE_AT_OFFSET(pBuf, 1049 offset 1050 + IN_FIRMWARE_INFO_OFFSET_VER_MINORSUB) >> 4) & 0x0f; 1051 1052 pInfo->versSubMinor = (KWUM_GET_BYTE_AT_OFFSET(pBuf, 1053 offset + IN_FIRMWARE_INFO_OFFSET_VER_MINORSUB)) & 0x0f; 1054 1055 pInfo->sdrRev = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1056 offset + IN_FIRMWARE_INFO_OFFSET_SDR_REV); 1057 1058 pInfo->iana = KWUM_GET_BYTE_AT_OFFSET(pBuf, 1059 offset + IN_FIRMWARE_INFO_OFFSET_IANA2) << 16; 1060 1061 pInfo->iana|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1062 offset + IN_FIRMWARE_INFO_OFFSET_IANA1) << 8; 1063 1064 pInfo->iana|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, 1065 offset + IN_FIRMWARE_INFO_OFFSET_IANA0); 1066 1067 KfwumFixTableVersionForOldFirmware(pInfo); 1068 return 0; 1069 } 1070 1071 void 1072 KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo * pInfo) 1073 { 1074 switch(pInfo->boardId) { 1075 case KFWUM_BOARD_KONTRON_UNKNOWN: 1076 pInfo->tableVers = 0xff; 1077 break; 1078 default: 1079 /* pInfo->tableVers is already set for 1080 * the right version 1081 */ 1082 break; 1083 } 1084 } 1085 1086 /* ipmi_kfwum_checkfwcompat - check whether firmware we're about to upload is 1087 * compatible with board. 1088 * 1089 * @boardInfo: 1090 * @firmInfo: 1091 * 1092 * returns 0 if compatible, otherwise (-1) 1093 */ 1094 int 1095 ipmi_kfwum_checkfwcompat(tKFWUM_BoardInfo boardInfo, 1096 tKFWUM_InFirmwareInfo firmInfo) 1097 { 1098 int compatible = 0; 1099 if (boardInfo.iana != firmInfo.iana) { 1100 lprintf(LOG_ERR, 1101 "Board IANA does not match firmware IANA."); 1102 compatible = (-1); 1103 } 1104 if (boardInfo.boardId != firmInfo.boardId) { 1105 lprintf(LOG_ERR, 1106 "Board IANA does not match firmware IANA."); 1107 compatible = (-1); 1108 } 1109 if (compatible != 0) { 1110 lprintf(LOG_ERR, 1111 "Firmware invalid for target board. Download of upgrade aborted."); 1112 } 1113 return compatible; 1114 } 1115 1116 void 1117 printf_kfwum_info(tKFWUM_BoardInfo boardInfo, tKFWUM_InFirmwareInfo firmInfo) 1118 { 1119 printf( 1120 "Target Board Id : %u\n", boardInfo.boardId); 1121 printf( 1122 "Target IANA number : %u\n", boardInfo.iana); 1123 printf( 1124 "File Size : %lu bytes\n", firmInfo.fileSize); 1125 printf( 1126 "Firmware Version : %d.%d%d SDR %d\n", firmInfo.versMajor, 1127 firmInfo.versMinor, firmInfo.versSubMinor, firmInfo.sdrRev); 1128 } 1129