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
ipmi_fwum_main(struct ipmi_intf * intf,int argc,char ** argv)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
printf_kfwum_help(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
ipmi_fwum_info(struct ipmi_intf * intf)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
ipmi_fwum_status(struct ipmi_intf * intf)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
ipmi_fwum_fwupgrade(struct ipmi_intf * intf,char * file,int action)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
KfwumGetFileSize(const char * pFileName,unsigned long * pFileSize)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
KfwumSetupBuffersFromFile(const char * pFileName,unsigned long fileSize)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
KfwumShowProgress(const char * task,unsigned long current,unsigned long total)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
KfwumCalculateChecksumPadding(unsigned char * pBuffer,unsigned long totalSize)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
KfwumGetInfo(struct ipmi_intf * intf,unsigned char output,unsigned char * pNumBank)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
KfwumGetDeviceInfo(struct ipmi_intf * intf,unsigned char output,tKFWUM_BoardInfo * pBoardInfo)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
KfwumGetStatus(struct ipmi_intf * intf)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
KfwumManualRollback(struct ipmi_intf * intf)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
KfwumStartFirmwareImage(struct ipmi_intf * intf,unsigned long length,unsigned short padding)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
KfwumSaveFirmwareImage(struct ipmi_intf * intf,unsigned char sequenceNumber,unsigned long address,unsigned char * pFirmBuf,unsigned char * pInBufLength)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
KfwumFinishFirmwareImage(struct ipmi_intf * intf,tKFWUM_InFirmwareInfo firmInfo)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
KfwumUploadFirmware(struct ipmi_intf * intf,unsigned char * pBuffer,unsigned long totalSize)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
KfwumStartFirmwareUpgrade(struct ipmi_intf * intf)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
KfwumGetTraceLog(struct ipmi_intf * intf)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
KfwumGetInfoFromFirmware(unsigned char * pBuf,unsigned long bufSize,tKFWUM_InFirmwareInfo * pInfo)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
KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo * pInfo)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
ipmi_kfwum_checkfwcompat(tKFWUM_BoardInfo boardInfo,tKFWUM_InFirmwareInfo firmInfo)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
printf_kfwum_info(tKFWUM_BoardInfo boardInfo,tKFWUM_InFirmwareInfo firmInfo)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