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