xref: /openbmc/ipmitool/lib/ipmi_hpmfwupg.c (revision 531569ec)
1 /*
2  * Copyright (c) 2006 Kontron Canada, Inc.  All Rights Reserved.
3  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * Redistribution of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * Redistribution in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of Sun Microsystems, Inc. or the names of
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * This software is provided "AS IS," without a warranty of any kind.
21  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
22  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
23  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
24  * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
25  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
26  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
27  * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
28  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
29  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
30  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
31  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32  */
33 
34 #include <ipmitool/ipmi_intf.h>
35 #include <ipmitool/ipmi_mc.h>
36 #include <ipmitool/ipmi_hpmfwupg.h>
37 #include <ipmitool/helper.h>
38 #include <ipmitool/ipmi_strings.h>
39 #include <ipmitool/log.h>
40 #include "../src/plugins/lan/md5.h"
41 #include <stdio.h>
42 #include <time.h>
43 #include <sys/param.h>
44 
45 #if HAVE_CONFIG_H
46 # include <config.h>
47 #endif
48 
49 extern int verbose;
50 
51 int HpmfwupgUpgrade(struct ipmi_intf *intf, char *imageFilename,
52 		int activate, int, int);
53 int HpmfwupgValidateImageIntegrity(struct HpmfwupgUpgradeCtx *pFwupgCtx);
54 int HpmfwupgPreparationStage(struct ipmi_intf *intf,
55 		struct HpmfwupgUpgradeCtx *pFwupgCtx, int option);
56 int HpmfwupgUpgradeStage(struct ipmi_intf *intf,
57 		struct HpmfwupgUpgradeCtx *pFwupgCtx, int option);
58 int HpmfwupgActivationStage(struct ipmi_intf *intf,
59 		struct HpmfwupgUpgradeCtx *pFwupgCtx);
60 int HpmfwupgGetTargetUpgCapabilities(struct ipmi_intf *intf,
61 		struct HpmfwupgGetTargetUpgCapabilitiesCtx *pCtx);
62 int HpmfwupgGetComponentProperties(struct ipmi_intf *intf,
63 		struct HpmfwupgGetComponentPropertiesCtx *pCtx);
64 int HpmfwupgQuerySelftestResult(struct ipmi_intf *intf,
65 		struct HpmfwupgQuerySelftestResultCtx *pCtx,
66 		struct HpmfwupgUpgradeCtx *pFwupgCtx);
67 int HpmfwupgQueryRollbackStatus(struct ipmi_intf *intf,
68 		struct HpmfwupgQueryRollbackStatusCtx *pCtx,
69 		struct HpmfwupgUpgradeCtx *pFwupgCtx);
70 int HpmfwupgAbortUpgrade(struct ipmi_intf *intf,
71 		struct HpmfwupgAbortUpgradeCtx *pCtx);
72 int HpmfwupgInitiateUpgradeAction(struct ipmi_intf *intf,
73 		struct HpmfwupgInitiateUpgradeActionCtx *pCtx,
74 		struct HpmfwupgUpgradeCtx *pFwupgCtx);
75 int HpmfwupgUploadFirmwareBlock(struct ipmi_intf *intf,
76 		struct HpmfwupgUploadFirmwareBlockCtx *pCtx,
77 		struct HpmfwupgUpgradeCtx *pFwupgCtx, int count,
78 		unsigned int *pOffset, unsigned int *blockLen);
79 int HpmfwupgFinishFirmwareUpload(struct ipmi_intf *intf,
80 		struct HpmfwupgFinishFirmwareUploadCtx *pCtx,
81 		struct HpmfwupgUpgradeCtx *pFwupgCtx, int option);
82 int HpmfwupgActivateFirmware(struct ipmi_intf *intf,
83 		struct HpmfwupgActivateFirmwareCtx *pCtx,
84 		struct HpmfwupgUpgradeCtx *pFwupgCtx);
85 int HpmfwupgGetUpgradeStatus(struct ipmi_intf *intf,
86 		struct HpmfwupgGetUpgradeStatusCtx *pCtxstruct,
87 		struct HpmfwupgUpgradeCtx *pFwupgCtx, int silent);
88 int HpmfwupgManualFirmwareRollback(struct ipmi_intf *intf,
89 		struct HpmfwupgManualFirmwareRollbackCtx *pCtx);
90 void HpmfwupgPrintUsage(void);
91 unsigned char HpmfwupgCalculateChecksum(unsigned char *pData,
92 		unsigned int length);
93 int HpmfwupgGetDeviceId(struct ipmi_intf *intf,
94 		struct ipm_devid_rsp *pGetDevId);
95 int HpmfwupgGetBufferFromFile(char *imageFilename,
96 		struct HpmfwupgUpgradeCtx *pFwupgCtx);
97 int HpmfwupgWaitLongDurationCmd(struct ipmi_intf *intf,
98 		struct HpmfwupgUpgradeCtx *pFwupgCtx);
99 struct ipmi_rs *HpmfwupgSendCmd(struct ipmi_intf *intf,
100 		struct ipmi_rq req, struct HpmfwupgUpgradeCtx* pFwupgCtx);
101 
102 
103 int HpmFwupgActionUploadFirmware(struct HpmfwupgComponentBitMask components,
104 		struct HpmfwupgUpgradeCtx* pFwupgCtx,
105 		unsigned char **pImagePtr,
106 		struct ipmi_intf *intf,
107 		int option,
108 		int *pFlagColdReset);
109 
110 /* HpmGetuserInput - get input from user
111  *
112  * returns TRUE if its Yes or FALSE if its No
113  */
114 int
115 HpmGetUserInput(char *str)
116 {
117 	char userInput[2];
118 	int ret;
119 
120 	printf("%s", str);
121 	ret = scanf("%s", userInput);
122 	if (!ret) {
123 		return 1;
124 	}
125 	if (toupper(userInput[0]) == 'Y') {
126 		return 1;
127 	}
128 	return 0;
129 }
130 
131 /* HpmDisplayLine - display the line with the given character
132  */
133 void
134 HpmDisplayLine(char *s, int n)
135 {
136 	while (n--) {
137 		printf ("%c", *s);
138 	}
139 	printf("\n");
140 }
141 
142 /* HpmDisplayUpgradeHeader - display the Upgrade header information
143  */
144 void
145 HpmDisplayUpgradeHeader(void)
146 {
147 	printf("\n");
148 	HpmDisplayLine("-", 79);
149 	printf(
150 "|ID  | Name        |                     Versions                        | %%  |\n");
151 	printf(
152 "|    |             |      Active     |      Backup     |      File       |    |\n");
153 	printf(
154 "|----|-------------|-----------------|-----------------|-----------------|----|\n");
155 }
156 
157 /* HpmDisplayUpgrade - display the progress of the upgrade; prints the "."
158  * for every 5% of its completion.
159  */
160 void
161 HpmDisplayUpgrade(int skip, unsigned int totalSent,
162 		unsigned int displayFWLength, time_t timeElapsed)
163 {
164 	int percent;
165 	static int old_percent = -1;
166 	if (skip) {
167 		printf("Skip|\n");
168 		return;
169 	}
170 	fflush(stdout);
171 
172 	percent = ((float)totalSent / displayFWLength) * 100;
173 	if (percent != old_percent) {
174 		if (old_percent != -1) {
175 			printf("\b\b\b\b\b");
176 		}
177 		printf("%3d%%|", percent);
178 		old_percent = percent;
179 	}
180 	if (totalSent == displayFWLength) {
181 		/* Display the time taken to complete the upgrade */
182 		printf(
183 "\n|    |Upload Time: %02ld:%02ld             | Image Size: %7d bytes              |\n",
184 			timeElapsed / 60, timeElapsed % 60, totalSent);
185 		old_percent = -1;
186 	}
187 }
188 
189 /* HpmDisplayVersionHeader - display the information about version header
190  */
191 void
192 HpmDisplayVersionHeader(int mode)
193 {
194 	if (mode & IMAGE_VER) {
195 		HpmDisplayLine("-", 74);
196 		printf(
197 "|ID  | Name        |                     Versions                        |\n");
198 		printf(
199 "|    |             |     Active      |     Backup      |      File       |\n");
200 		HpmDisplayLine("-", 74);
201 	} else {
202 		HpmDisplayLine("-",74 );
203 		printf(
204 "|ID  | Name        |                     Versions                        |\n");
205 		printf(
206 "|    |             |     Active      |     Backup      |      Deferred   |\n");
207 		HpmDisplayLine("-", 74);
208 	}
209 }
210 
211 /* HpmDisplayVersion - display the version of the image and target
212  */
213 void
214 HpmDisplayVersion(int mode, VERSIONINFO *pVersion, int upgradable)
215 {
216 	/*
217 	 * If the cold reset is required then we can display * on it
218 	 * so that user is aware that he needs to do payload power
219 	 * cycle after upgrade
220 	 */
221 	printf("|%c%c%2d|%-13s|",
222 			pVersion->coldResetRequired ? '*' : ' ',
223 			upgradable ? '^' : ' ',
224 			pVersion->componentId, pVersion->descString);
225 
226 	if (mode & TARGET_VER) {
227 		if ((pVersion->targetMajor == 0xFF
228 					|| (pVersion->targetMajor == 0x7F))
229 				&& pVersion->targetMinor == 0xFF) {
230 			printf(" ---.-- -------- |");
231 		} else {
232 			printf(" %3d.%02x %02X%02X%02X%02X |",
233 					pVersion->targetMajor,
234 					pVersion->targetMinor,
235 					pVersion->targetAux[0],
236 					pVersion->targetAux[1],
237 					pVersion->targetAux[2],
238 					pVersion->targetAux[3]);
239 		}
240 		if (mode & ROLLBACK_VER) {
241 			if ((pVersion->rollbackMajor == 0xFF
242 						|| (pVersion->rollbackMajor == 0x7F))
243 					&& pVersion->rollbackMinor == 0xFF) {
244 				printf(" ---.-- -------- |");
245 			} else {
246 				printf(" %3d.%02x %02X%02X%02X%02X |",
247 						pVersion->rollbackMajor,
248 						pVersion->rollbackMinor,
249 						pVersion->rollbackAux[0],
250 						pVersion->rollbackAux[1],
251 						pVersion->rollbackAux[2],
252 						pVersion->rollbackAux[3]);
253 			}
254 		} else {
255 			printf(" ---.-- -------- |");
256 		}
257 	}
258 	if (mode & IMAGE_VER) {
259 		if ((pVersion->imageMajor == 0xFF
260 					|| (pVersion->imageMajor == 0x7F))
261 				&& pVersion->imageMinor == 0xFF) {
262 			printf(" ---.-- |");
263 		} else {
264 			printf(" %3d.%02x %02X%02X%02X%02X |",
265 					pVersion->imageMajor,
266 					pVersion->imageMinor,
267 					pVersion->imageAux[0],
268 					pVersion->imageAux[1],
269 					pVersion->imageAux[2],
270 					pVersion->imageAux[3]);
271 		}
272 	} else {
273 		if ((pVersion->deferredMajor == 0xFF
274 					|| (pVersion->deferredMajor == 0x7F))
275 				&& pVersion->deferredMinor == 0xFF) {
276 			printf(" ---.-- -------- |");
277 		} else {
278 			printf(" %3d.%02x %02X%02X%02X%02X |",
279 					pVersion->deferredMajor,
280 					pVersion->deferredMinor,
281 					pVersion->deferredAux[0],
282 					pVersion->deferredAux[1],
283 					pVersion->deferredAux[2],
284 					pVersion->deferredAux[3]);
285 		}
286 	}
287 }
288 
289 /* HpmfwupgTargerCheck - get target information and displays it on the screen
290  */
291 int
292 HpmfwupgTargetCheck(struct ipmi_intf *intf, int option)
293 {
294 	struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd;
295 	int rc = HPMFWUPG_SUCCESS;
296 	int componentId = 0;
297 	int flagColdReset = FALSE;
298 	struct ipm_devid_rsp devIdrsp;
299 	struct HpmfwupgGetComponentPropertiesCtx getCompProp;
300 	int mode = 0;
301 	rc = HpmfwupgGetDeviceId(intf, &devIdrsp);
302 	if (rc != HPMFWUPG_SUCCESS) {
303 		lprintf(LOG_NOTICE,
304 				"Verify whether the Target board is present \n");
305 		return HPMFWUPG_ERROR;
306 	}
307 	rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd);
308 	if (rc != HPMFWUPG_SUCCESS) {
309 		/* That indicates the target is not responding to the command
310 		 * May be that there is no HPM support
311 		 */
312 		lprintf(LOG_NOTICE,
313 				"Board might not be supporting the HPM.1 Standards\n");
314 		return rc;
315 	}
316 	if (option & VIEW_MODE) {
317 		lprintf(LOG_NOTICE, "-------Target Information-------");
318 		lprintf(LOG_NOTICE, "Device Id          : 0x%x",
319 				devIdrsp.device_id);
320 		lprintf(LOG_NOTICE, "Device Revision    : 0x%x",
321 				devIdrsp.device_revision);
322 		lprintf(LOG_NOTICE, "Product Id         : 0x%04x",
323 				buf2short(devIdrsp.product_id));
324 		lprintf(LOG_NOTICE, "Manufacturer Id    : 0x%04x (%s)\n\n",
325 				buf2short(devIdrsp.manufacturer_id),
326 				val2str(buf2short(devIdrsp.manufacturer_id),ipmi_oem_info));
327 		HpmDisplayVersionHeader(TARGET_VER|ROLLBACK_VER);
328 	}
329 	for (componentId = HPMFWUPG_COMPONENT_ID_0;
330 			componentId < HPMFWUPG_COMPONENT_ID_MAX;
331 			componentId++ ) {
332 		/* If the component is supported */
333 		if (((1 << componentId) & targetCapCmd.resp.componentsPresent.ComponentBits.byte)) {
334 			memset((PVERSIONINFO)&gVersionInfo[componentId], 0x00, sizeof(VERSIONINFO));
335 			getCompProp.req.componentId = componentId;
336 			getCompProp.req.selector = HPMFWUPG_COMP_GEN_PROPERTIES;
337 			rc = HpmfwupgGetComponentProperties(intf, &getCompProp);
338 			if (rc != HPMFWUPG_SUCCESS) {
339 				lprintf(LOG_NOTICE, "Get CompGenProp Failed for component Id %d\n",
340 						componentId);
341 				return rc;
342 			}
343 			gVersionInfo[componentId].rollbackSupported = getCompProp.resp.Response.
344 				generalPropResp.GeneralCompProperties.bitfield.rollbackBackup;
345 			gVersionInfo[componentId].coldResetRequired =  getCompProp.resp.Response.
346 				generalPropResp.GeneralCompProperties.bitfield.payloadColdReset;
347 			gVersionInfo[componentId].deferredActivationSupported =  getCompProp.resp.Response.
348 				generalPropResp.GeneralCompProperties.bitfield.deferredActivation;
349 			getCompProp.req.selector = HPMFWUPG_COMP_DESCRIPTION_STRING;
350 			rc = HpmfwupgGetComponentProperties(intf, &getCompProp);
351 			if (rc != HPMFWUPG_SUCCESS) {
352 				lprintf(LOG_NOTICE,
353 						"Get CompDescString Failed for component Id %d\n",
354 						componentId);
355 				return rc;
356 			}
357 			memcpy(gVersionInfo[componentId].descString,
358 					getCompProp.resp.Response.descStringResp.descString,
359 					HPMFWUPG_DESC_STRING_LENGTH);
360 			gVersionInfo[componentId].descString[HPMFWUPG_DESC_STRING_LENGTH] = '\0';
361 			getCompProp.req.selector = HPMFWUPG_COMP_CURRENT_VERSION;
362 			rc = HpmfwupgGetComponentProperties(intf, &getCompProp);
363 			if (rc != HPMFWUPG_SUCCESS) {
364 				lprintf(LOG_NOTICE,
365 						"Get CompCurrentVersion Failed for component Id %d\n",
366 						componentId);
367 				return rc;
368 			}
369 			gVersionInfo[componentId].componentId = componentId;
370 			gVersionInfo[componentId].targetMajor = getCompProp.resp.Response.
371 				currentVersionResp.currentVersion[0];
372 			gVersionInfo[componentId].targetMinor = getCompProp.resp.Response.
373 				currentVersionResp.currentVersion[1];
374 			gVersionInfo[componentId].targetAux[0] = getCompProp.resp.Response.
375 				currentVersionResp.currentVersion[2];
376 			gVersionInfo[componentId].targetAux[1] = getCompProp.resp.Response.
377 				currentVersionResp.currentVersion[3];
378 			gVersionInfo[componentId].targetAux[2] = getCompProp.resp.Response.
379 				currentVersionResp.currentVersion[4];
380 			gVersionInfo[componentId].targetAux[3] = getCompProp.resp.Response.
381 				currentVersionResp.currentVersion[5];
382 			mode = TARGET_VER;
383 			if (gVersionInfo[componentId].rollbackSupported) {
384 				getCompProp.req.selector = HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION;
385 				rc = HpmfwupgGetComponentProperties(intf, &getCompProp);
386 				if (rc != HPMFWUPG_SUCCESS) {
387 					lprintf(LOG_NOTICE,
388 							"Get CompRollbackVersion Failed for component Id %d\n",
389 							componentId);
390 				} else {
391 					gVersionInfo[componentId].rollbackMajor = getCompProp.resp
392 						.Response.rollbackFwVersionResp.rollbackFwVersion[0];
393 					gVersionInfo[componentId].rollbackMinor = getCompProp.resp
394 						.Response.rollbackFwVersionResp.rollbackFwVersion[1];
395 					gVersionInfo[componentId].rollbackAux[0] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[2];
396 					gVersionInfo[componentId].rollbackAux[1] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[3];
397 					gVersionInfo[componentId].rollbackAux[2] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[4];
398 					gVersionInfo[componentId].rollbackAux[3] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[5];
399 				}
400 				mode |= ROLLBACK_VER;
401 			} else {
402 				gVersionInfo[componentId].rollbackMajor = 0xff;
403 				gVersionInfo[componentId].rollbackMinor = 0xff;
404 				gVersionInfo[componentId].rollbackAux[0] = 0xff;
405 				gVersionInfo[componentId].rollbackAux[1] = 0xff;
406 				gVersionInfo[componentId].rollbackAux[2] = 0xff;
407 				gVersionInfo[componentId].rollbackAux[3] = 0xff;
408 			}
409 			if (gVersionInfo[componentId].deferredActivationSupported) {
410 				getCompProp.req.selector = HPMFWUPG_COMP_DEFERRED_FIRMWARE_VERSION;
411 				rc = HpmfwupgGetComponentProperties(intf, &getCompProp);
412 				if (rc != HPMFWUPG_SUCCESS) {
413 					lprintf(LOG_NOTICE,
414 							"Get CompRollbackVersion Failed for component Id %d\n",
415 							componentId);
416 				} else {
417 					gVersionInfo[componentId].deferredMajor = getCompProp.resp
418 						.Response.deferredFwVersionResp.deferredFwVersion[0];
419 					gVersionInfo[componentId].deferredMinor = getCompProp.resp
420 						.Response.deferredFwVersionResp.deferredFwVersion[1];
421 					gVersionInfo[componentId].deferredAux[0] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[2];
422 					gVersionInfo[componentId].deferredAux[1] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[3];
423 					gVersionInfo[componentId].deferredAux[2] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[4];
424 					gVersionInfo[componentId].deferredAux[3] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[5];
425 				}
426 			} else {
427 				gVersionInfo[componentId].deferredMajor = 0xff;
428 				gVersionInfo[componentId].deferredMinor = 0xff;
429 				gVersionInfo[componentId].deferredAux[0] = 0xff;
430 				gVersionInfo[componentId].deferredAux[1] = 0xff;
431 				gVersionInfo[componentId].deferredAux[2] = 0xff;
432 				gVersionInfo[componentId].deferredAux[3] = 0xff;
433 			}
434 			if (gVersionInfo[componentId].coldResetRequired) {
435 				/*
436 				 * If any of the component indicates that the Payload Cold reset is required
437 				 * then set the flag
438 				 */
439 				flagColdReset = TRUE;
440 			}
441 			if (option & VIEW_MODE) {
442 				HpmDisplayVersion(mode,
443 						&gVersionInfo[componentId],
444 						0);
445 				printf("\n");
446 			}
447 		}
448 	}
449 	if (option & VIEW_MODE) {
450 		HpmDisplayLine("-",74 );
451 		fflush(stdout);
452 		lprintf(LOG_NOTICE,
453 				"(*) Component requires Payload Cold Reset");
454 		printf("\n\n");
455 	}
456 	return HPMFWUPG_SUCCESS;
457 }
458 
459 /* HpmfwupgUpgrade - perform the HPM.1 firmware upgrade procedure as defined
460  * the IPM Controller Firmware Upgrade Specification version 1.0
461  */
462 int
463 HpmfwupgUpgrade(struct ipmi_intf *intf, char *imageFilename, int activate,
464 		int componentMask, int option)
465 {
466 	int rc = HPMFWUPG_SUCCESS;
467 	struct HpmfwupgUpgradeCtx  fwupgCtx;
468 	/* INITIALIZE UPGRADE CONTEXT */
469 	memset(&fwupgCtx, 0, sizeof (fwupgCtx));
470 	/* GET IMAGE BUFFER FROM FILE */
471 	rc = HpmfwupgGetBufferFromFile(imageFilename, &fwupgCtx);
472 	/* VALIDATE IMAGE INTEGRITY */
473 	if (rc == HPMFWUPG_SUCCESS) {
474 		printf("Validating firmware image integrity...");
475 		fflush(stdout);
476 		rc = HpmfwupgValidateImageIntegrity(&fwupgCtx);
477 		if (rc == HPMFWUPG_SUCCESS) {
478 			printf("OK\n");
479 			fflush(stdout);
480 		}
481 	}
482 	/* PREPARATION STAGE */
483 	if (rc == HPMFWUPG_SUCCESS) {
484 		printf("Performing preparation stage...");
485 		fflush(stdout);
486 		rc = HpmfwupgPreparationStage(intf, &fwupgCtx, option);
487 		if (rc == HPMFWUPG_SUCCESS) {
488 			printf("OK\n");
489 			fflush(stdout);
490 		}
491 	}
492 	/* UPGRADE STAGE */
493 	if (rc == HPMFWUPG_SUCCESS) {
494 		if (option & VIEW_MODE) {
495 			lprintf(LOG_NOTICE,
496 					"\nComparing Target & Image File version");
497 		} else if (option & COMPARE_MODE) {
498 			lprintf(LOG_NOTICE,
499 					"\nPerforming upload for compare stage:");
500 		} else {
501 			lprintf(LOG_NOTICE, "\nPerforming upgrade stage:");
502 		}
503 		if (option & VIEW_MODE) {
504 			rc = HpmfwupgPreUpgradeCheck(intf,
505 					&fwupgCtx,componentMask, VIEW_MODE);
506 		} else {
507 			rc = HpmfwupgPreUpgradeCheck(intf, &fwupgCtx,
508 					componentMask, option);
509 			if (rc == HPMFWUPG_SUCCESS) {
510 				if (verbose) {
511 					printf("Component update mask : 0x%02x\n",
512 							fwupgCtx.compUpdateMask.ComponentBits.byte);
513 				}
514 				rc = HpmfwupgUpgradeStage(intf, &fwupgCtx, option);
515 			}
516 		}
517 	}
518 	/* ACTIVATION STAGE */
519 	if (rc == HPMFWUPG_SUCCESS && activate) {
520 		/* check if upgrade components mask is non-zero */
521 		if (fwupgCtx.compUpdateMask.ComponentBits.byte) {
522 			lprintf(LOG_NOTICE, "Performing activation stage: ");
523 			rc = HpmfwupgActivationStage(intf, &fwupgCtx);
524 		} else {
525 			lprintf(LOG_NOTICE,
526 					"No components updated. Skipping activation stage.\n");
527 		}
528 	}
529 	if (rc == HPMFWUPG_SUCCESS) {
530 		if (option & VIEW_MODE) {
531 		/* Dont display anything here in case we are just viewing it */
532 		lprintf(LOG_NOTICE," ");
533 		} else if (option & COMPARE_MODE) {
534 			lprintf(LOG_NOTICE,
535 					"\nFirmware comparison procedure complete\n");
536 		} else {
537 			lprintf(LOG_NOTICE,
538 					"\nFirmware upgrade procedure successful\n");
539 		}
540 	} else if (option & VIEW_MODE) {
541 		/* Dont display anything here in case we are just viewing it */
542 		lprintf(LOG_NOTICE," ");
543 	} else if (option & COMPARE_MODE) {
544 		lprintf(LOG_NOTICE,
545 				"Firmware comparison procedure failed\n");
546 	} else {
547 		lprintf(LOG_NOTICE, "Firmware upgrade procedure failed\n");
548 	}
549 	if (fwupgCtx.pImageData) {
550 		free(fwupgCtx.pImageData);
551 		fwupgCtx.pImageData = NULL;
552 	}
553 	return rc;
554 }
555 
556 /* HpmfwupgValidateImageIntegrity - validate a HPM.1 firmware image file as
557  * defined in section 4 of the IPM Controller Firmware Upgrade Specification
558  * version 1.0
559  */
560 int
561 HpmfwupgValidateImageIntegrity(struct HpmfwupgUpgradeCtx *pFwupgCtx)
562 {
563 	struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*)pFwupgCtx->pImageData;
564 	md5_state_t ctx;
565 	static unsigned char md[HPMFWUPG_MD5_SIGNATURE_LENGTH];
566 	unsigned char *pMd5Sig = pFwupgCtx->pImageData
567 		+ (pFwupgCtx->imageSize - HPMFWUPG_MD5_SIGNATURE_LENGTH);
568 	/* Validate MD5 checksum */
569 	memset(md, 0, HPMFWUPG_MD5_SIGNATURE_LENGTH);
570 	memset(&ctx, 0, sizeof(md5_state_t));
571 	md5_init(&ctx);
572 	md5_append(&ctx, pFwupgCtx->pImageData,
573 			pFwupgCtx->imageSize - HPMFWUPG_MD5_SIGNATURE_LENGTH);
574 	md5_finish(&ctx, md);
575 	if (memcmp(md, pMd5Sig, HPMFWUPG_MD5_SIGNATURE_LENGTH) != 0) {
576 		lprintf(LOG_NOTICE, "\n    Invalid MD5 signature");
577 		return HPMFWUPG_ERROR;
578 	}
579 	/* Validate Header signature */
580 	if(strncmp(pImageHeader->signature,
581 				HPMFWUPG_IMAGE_SIGNATURE,
582 				HPMFWUPG_HEADER_SIGNATURE_LENGTH) != 0) {
583 		lprintf(LOG_NOTICE,"\n    Invalid image signature");
584 		return HPMFWUPG_ERROR;
585 	}
586 	/* Validate Header image format version */
587 	if (pImageHeader->formatVersion != HPMFWUPG_IMAGE_HEADER_VERSION) {
588 		lprintf(LOG_NOTICE,"\n    Unrecognized image version");
589 		return HPMFWUPG_ERROR;
590 	}
591 	/* Validate header checksum */
592 	if (HpmfwupgCalculateChecksum((unsigned char*)pImageHeader,
593 				sizeof(struct HpmfwupgImageHeader)
594 				+ pImageHeader->oemDataLength
595 				+ sizeof(unsigned char)/*checksum*/) != 0) {
596 		lprintf(LOG_NOTICE,"\n    Invalid header checksum");
597 		return HPMFWUPG_ERROR;
598 	}
599 	return HPMFWUPG_SUCCESS;
600 }
601 
602 /* HpmfwupgPreparationStage - prepere stage of a firmware upgrade procedure as
603  * defined in section 3.2 of the IPM Controller Firmware Upgrade Specification
604  * version 1.0
605  */
606 int
607 HpmfwupgPreparationStage(struct ipmi_intf *intf,
608 		struct HpmfwupgUpgradeCtx *pFwupgCtx, int option)
609 {
610 	int componentId;
611 	int rc = HPMFWUPG_SUCCESS;
612 	struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd;
613 	struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*)
614 		pFwupgCtx->pImageData;
615 	/* Get device ID */
616 	rc = HpmfwupgGetDeviceId(intf, &pFwupgCtx->devId);
617 	/* Match current IPMC IDs with upgrade image */
618 	if (rc != HPMFWUPG_SUCCESS) {
619 		return HPMFWUPG_ERROR;
620 	}
621 	/* Validate device ID */
622 	if (pImageHeader->deviceId == pFwupgCtx->devId.device_id) {
623 		/* Validate product ID */
624 		if (memcmp(pImageHeader->prodId,
625 					pFwupgCtx->devId.product_id,
626 					HPMFWUPG_PRODUCT_ID_LENGTH ) == 0) {
627 			/* Validate man ID */
628 			if (memcmp(pImageHeader->manId,
629 						pFwupgCtx->devId.manufacturer_id,
630 						HPMFWUPG_MANUFATURER_ID_LENGTH) != 0) {
631 				lprintf(LOG_NOTICE,
632 						"\n    Invalid image file for manufacturer %u",
633 						buf2short(pFwupgCtx->devId.manufacturer_id));
634 				rc = HPMFWUPG_ERROR;
635 			}
636 		} else {
637 			lprintf(LOG_NOTICE,
638 					"\n    Invalid image file for product %u",
639 					buf2short(pFwupgCtx->devId.product_id));
640 			rc = HPMFWUPG_ERROR;
641 		}
642 	} else {
643 		lprintf(LOG_NOTICE, "\n    Invalid device ID %x",
644 				pFwupgCtx->devId.device_id);
645 		rc = HPMFWUPG_ERROR;
646 	}
647 	if (rc != HPMFWUPG_SUCCESS) {
648 		/* Giving one more chance to user to check whether its OK to continue even if the
649 		 * product ID does not match. This is helpful as sometimes we just want to update
650 		 * and dont care whether we have a different product Id. If the user says NO then
651 		 * we need to just bail out from here
652 		 */
653 		if (!((option & FORCE_MODE) || (option & VIEW_MODE))) {
654 			printf("\n\n Use \"force\" option for copying all the components\n");
655 			return HPMFWUPG_ERROR;
656 		}
657 		printf("\n    Image Information");
658 		printf("\n        Device Id : 0x%x", pImageHeader->deviceId);
659 		printf("\n        Prod   Id : 0x%02x%02x",
660 				pImageHeader->prodId[1], pImageHeader->prodId[0]);
661 		printf("\n        Manuf  Id : 0x%02x%02x%02x",
662 				pImageHeader->manId[2],
663 				pImageHeader->manId[1],
664 				pImageHeader->manId[0]);
665 		printf("\n    Board Information");
666 		printf("\n        Device Id : 0x%x", pFwupgCtx->devId.device_id);
667 		printf("\n        Prod   Id : 0x%02x%02x",
668 				pFwupgCtx->devId.product_id[1], pFwupgCtx->devId.product_id[0]);
669 		printf("\n        Manuf  Id : 0x%02x%02x%02x",
670 				pFwupgCtx->devId.manufacturer_id[2],
671 				pFwupgCtx->devId.manufacturer_id[1],
672 				pFwupgCtx->devId.manufacturer_id[0]);
673 		if (HpmGetUserInput("\n Continue ignoring DeviceID/ProductID/ManufacturingID (Y/N): ")) {
674 			rc = HPMFWUPG_SUCCESS;
675 		} else {
676 			return HPMFWUPG_ERROR;
677 		}
678 	}
679 	/* Validate earliest compatible revision */
680 	/* Validate major & minor revision */
681 	if (pImageHeader->compRevision[0] > pFwupgCtx->devId.fw_rev1
682 			|| (pImageHeader->compRevision[0] == pFwupgCtx->devId.fw_rev1
683 				&& pImageHeader->compRevision[1] > pFwupgCtx->devId.fw_rev2)) {
684 		/* Version not compatible for upgrade */
685 		lprintf(LOG_NOTICE, "\n    Version: Major: %d", pImageHeader->compRevision[0]);
686 		lprintf(LOG_NOTICE, "             Minor: %x", pImageHeader->compRevision[1]);
687 		lprintf(LOG_NOTICE, "    Not compatible with ");
688 		lprintf(LOG_NOTICE, "    Version: Major: %d", pFwupgCtx->devId.fw_rev1);
689 		lprintf(LOG_NOTICE, "             Minor: %x", pFwupgCtx->devId.fw_rev2);
690 		/* Confirming it once again */
691 		if (!((option & FORCE_MODE) || (option & VIEW_MODE))) {
692 			return HPMFWUPG_ERROR;
693 		}
694 		if (HpmGetUserInput("\n Continue IGNORING Earliest compatibility (Y/N): ")) {
695 			rc = HPMFWUPG_SUCCESS;
696 		} else {
697 			return HPMFWUPG_ERROR;
698 		}
699 	}
700 	/* Get target upgrade capabilities */
701 	rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd);
702 	if (rc != HPMFWUPG_SUCCESS) {
703 		return HPMFWUPG_ERROR;
704 	}
705 	/* Copy response to context */
706 	memcpy(&pFwupgCtx->targetCap,
707 			&targetCapCmd.resp,
708 			sizeof(struct HpmfwupgGetTargetUpgCapabilitiesResp));
709 	if (option & VIEW_MODE) {
710 		/* do nothing */
711 	} else {
712 		/* Make sure all component IDs defined in the
713 		 * upgrade image are supported by the IPMC
714 		 */
715 		if ((pImageHeader->components.ComponentBits.byte &
716 					pFwupgCtx->targetCap.componentsPresent.ComponentBits.byte) !=
717 					pImageHeader->components.ComponentBits.byte) {
718 			lprintf(LOG_NOTICE,
719 					"\n    Some components present in the image file are not supported by the IPMC");
720 			return HPMFWUPG_ERROR;
721 		}
722 		/* Make sure the upgrade is desirable rigth now */
723 		if (pFwupgCtx->targetCap.GlobalCapabilities.bitField.fwUpgUndesirable == 1) {
724 			lprintf(LOG_NOTICE, "\n    Upgrade undesirable at this moment");
725 			return HPMFWUPG_ERROR;
726 		}
727 		/* Get confimation from the user if he wants to continue when
728 		 * service affected during upgrade
729 		 */
730 		if (!(option & COMPARE_MODE)
731 				&& (pFwupgCtx->targetCap.GlobalCapabilities.bitField.servAffectDuringUpg == 1
732 					|| pImageHeader->imageCapabilities.bitField.servAffected == 1)) {
733 			if (HpmGetUserInput("\nServices may be affected during upgrade. Do you wish to continue? (y/n): ")) {
734 				rc = HPMFWUPG_SUCCESS;
735 			} else {
736 				return HPMFWUPG_ERROR;
737 			}
738 		}
739 	}
740 	/* Get the general properties of each component present in image */
741 	for (componentId = HPMFWUPG_COMPONENT_ID_0;
742 			componentId < HPMFWUPG_COMPONENT_ID_MAX;
743 			componentId++) {
744 		/* Reset component properties */
745 		memset(&pFwupgCtx->genCompProp[componentId], 0,
746 				sizeof (struct HpmfwupgGetGeneralPropResp));
747 		if ((1 << componentId & pImageHeader->components.ComponentBits.byte)) {
748 			struct HpmfwupgGetComponentPropertiesCtx getCompPropCmd;
749 			/* Get general component properties */
750 			getCompPropCmd.req.componentId = componentId;
751 			getCompPropCmd.req.selector = HPMFWUPG_COMP_GEN_PROPERTIES;
752 			rc = HpmfwupgGetComponentProperties(intf, &getCompPropCmd);
753 			if (rc == HPMFWUPG_SUCCESS) {
754 				/* Copy response to context */
755 				memcpy(&pFwupgCtx->genCompProp[componentId],
756 						&getCompPropCmd.resp,
757 						sizeof(struct HpmfwupgGetGeneralPropResp));
758 			}
759 		}
760 	}
761 	return rc;
762 }
763 
764 int
765 image_version_upgradable(VERSIONINFO *pVersionInfo)
766 {
767 	/* If the image and active target versions are different, then
768 	 * upgrade */
769 	if ((pVersionInfo->imageMajor != pVersionInfo->targetMajor)
770 			|| (pVersionInfo->imageMinor != pVersionInfo->targetMinor)
771 			|| (pVersionInfo->imageAux[0] != pVersionInfo->targetAux[0])
772 			|| (pVersionInfo->imageAux[1] != pVersionInfo->targetAux[1])
773 			|| (pVersionInfo->imageAux[2] != pVersionInfo->targetAux[2])
774 			|| (pVersionInfo->imageAux[3] != pVersionInfo->targetAux[3])) {
775 		return (1);
776 	}
777 	/* If the image and active target versions are the same and rollback
778 	 * is not supported, then there's nothing to do, skip the upgrade
779 	 */
780 	if (!pVersionInfo->rollbackSupported) {
781 		return (0);
782 	}
783 	/* If the image and rollback target versions are different, then
784 	 * go ahead and upgrade
785 	 */
786 	if ((pVersionInfo->imageMajor != pVersionInfo->rollbackMajor)
787 			|| (pVersionInfo->imageMinor != pVersionInfo->rollbackMinor)
788 			|| (pVersionInfo->imageAux[0] != pVersionInfo->rollbackAux[0])
789 			|| (pVersionInfo->imageAux[1] != pVersionInfo->rollbackAux[1])
790 			|| (pVersionInfo->imageAux[2] != pVersionInfo->rollbackAux[2])
791 			|| (pVersionInfo->imageAux[3] != pVersionInfo->rollbackAux[3])) {
792 		return (1);
793 	}
794 	/* Image and rollback target versions are the same too, skip it */
795 	return (0);
796 }
797 
798 /* HpmfwupgValidateActionRecordChecksum - validate checksum of the specified
799  * action record header.
800  */
801 int
802 HpmfwupgValidateActionRecordChecksum(struct HpmfwupgActionRecord *pActionRecord)
803 {
804 	int rc = HPMFWUPG_SUCCESS;
805 	/* Validate action record checksum */
806 	if (HpmfwupgCalculateChecksum((unsigned char*)pActionRecord,
807 				sizeof(struct HpmfwupgActionRecord)) != 0) {
808 	/* Due to ambiguity in the HPM.1 specification, for the case of
809 	 * the Upload Firmware Image action type, the record header length
810 	 * might be thought as either the first 3 bytes, or the first 34 bytes
811 	 * which precede the firmware image data.
812 	 * For the latter case we re-calculate the Upload Firmware Image
813 	 * record checksum for the 34 byte header length.
814 	 */
815 		if (pActionRecord->actionType != HPMFWUPG_ACTION_UPLOAD_FIRMWARE
816 				|| HpmfwupgCalculateChecksum((unsigned char*)pActionRecord,
817 					sizeof(struct HpmfwupgActionRecord)
818 					+ sizeof(struct HpmfwupgFirmwareImage))) {
819 			lprintf(LOG_NOTICE, "    Invalid Action record.");
820 			rc = HPMFWUPG_ERROR;
821 		}
822 	}
823 	return rc;
824 }
825 
826 /* HpmfwupgPreUpgradeCheck - make pre-Upgrade check, this mainly helps in
827  * checking which all version upgrade is skippable because the image version
828  * is same as target version.
829  */
830 int
831 HpmfwupgPreUpgradeCheck(struct ipmi_intf *intf,
832 		struct HpmfwupgUpgradeCtx *pFwupgCtx,
833 		int componentMask, int option)
834 {
835 	unsigned char *pImagePtr;
836 	struct HpmfwupgActionRecord *pActionRecord;
837 	struct HpmfwupgImageHeader *pImageHeader;
838 	int componentId;
839 	pImageHeader = (struct HpmfwupgImageHeader*)pFwupgCtx->pImageData;
840 	/* Put pointer after image header */
841 	pImagePtr = (unsigned char*)(pFwupgCtx->pImageData
842 			+ sizeof(struct HpmfwupgImageHeader)
843 			+ pImageHeader->oemDataLength
844 			+ sizeof(unsigned char)/*chksum*/);
845 	if (option & VIEW_MODE) {
846 		HpmDisplayVersionHeader(TARGET_VER|ROLLBACK_VER|IMAGE_VER);
847 	}
848 	/* Perform actions defined in the image */
849 	while (pImagePtr < (pFwupgCtx->pImageData + pFwupgCtx->imageSize
850 				- HPMFWUPG_MD5_SIGNATURE_LENGTH)) {
851 		/* Get action record */
852 		pActionRecord = (struct HpmfwupgActionRecord*)pImagePtr;
853 		/* Validate action record checksum */
854 		if (HpmfwupgValidateActionRecordChecksum(pActionRecord) != HPMFWUPG_SUCCESS) {
855 			return HPMFWUPG_ERROR;
856 		}
857 		/* Validate affected components */
858 		if (pActionRecord->components.ComponentBits.byte
859 				&& !pFwupgCtx->targetCap.componentsPresent.ComponentBits.byte) {
860 			lprintf(LOG_NOTICE,
861 					"    Invalid action record. One or more affected components is not supported");
862 			return HPMFWUPG_ERROR;
863 		}
864 		switch (pActionRecord->actionType) {
865 		case HPMFWUPG_ACTION_BACKUP_COMPONENTS:
866 			{
867 				/* Make sure every component specified by
868 				 * this action record
869 				 * supports the backup operation
870 				 */
871 				for (componentId = HPMFWUPG_COMPONENT_ID_0;
872 						componentId < HPMFWUPG_COMPONENT_ID_MAX;
873 						componentId++) {
874 					if (((1 << componentId) & pActionRecord->components.ComponentBits.byte)
875 							&& pFwupgCtx->genCompProp[componentId].GeneralCompProperties.bitfield.rollbackBackup == 0) {
876 						lprintf(LOG_NOTICE,
877 								"    Component ID %d does not support backup",
878 								componentId);
879 						return HPMFWUPG_ERROR;
880 					}
881 				}
882 				pImagePtr += sizeof(struct HpmfwupgActionRecord);
883 			}
884 			break;
885 		case HPMFWUPG_ACTION_PREPARE_COMPONENTS:
886 			{
887 				/* Make sure every components specified by
888 				 * this action
889 				 * supports the prepare operation
890 				 */
891 				for (componentId = HPMFWUPG_COMPONENT_ID_0;
892 						componentId < HPMFWUPG_COMPONENT_ID_MAX;
893 						componentId++) {
894 					if (((1 << componentId) & pActionRecord->components.ComponentBits.byte)
895 							&& pFwupgCtx->genCompProp[componentId].GeneralCompProperties.bitfield.preparationSupport == 0) {
896 						lprintf(LOG_NOTICE,
897 								"    Component ID %d does not support preparation",
898 								componentId);
899 						return HPMFWUPG_ERROR;
900 					}
901 				}
902 				pImagePtr += sizeof(struct HpmfwupgActionRecord);
903 			}
904 			break;
905 		case HPMFWUPG_ACTION_UPLOAD_FIRMWARE:
906 			/* Upload all firmware blocks */
907 			{
908 				struct HpmfwupgFirmwareImage *pFwImage;
909 				unsigned char *pData;
910 				unsigned int firmwareLength;
911 				unsigned char mode;
912 				unsigned char componentId;
913 				unsigned char componentIdByte;
914 				unsigned int upgrade_comp;
915 				VERSIONINFO *pVersionInfo;
916 				/* Save component ID on which the upload is done */
917 				componentIdByte = pActionRecord->components.ComponentBits.byte;
918 				componentId = 0;
919 				while ((componentIdByte >>= 1) != 0) {
920 					componentId++;
921 				}
922 				pFwImage = (struct HpmfwupgFirmwareImage*)(pImagePtr
923 						+ sizeof(struct HpmfwupgActionRecord));
924 				pData = ((unsigned char*)pFwImage
925 						+ sizeof(struct HpmfwupgFirmwareImage));
926 				/* Get firmware length */
927 				firmwareLength  =  pFwImage->length[0];
928 				firmwareLength |= (pFwImage->length[1] << 8)  & 0xff00;
929 				firmwareLength |= (pFwImage->length[2] << 16) & 0xff0000;
930 				firmwareLength |= (pFwImage->length[3] << 24) & 0xff000000;
931 
932 				pVersionInfo = &gVersionInfo[componentId];
933 
934 				pVersionInfo->imageMajor   = pFwImage->version[0];
935 				pVersionInfo->imageMinor   = pFwImage->version[1];
936 				pVersionInfo->imageAux[0]  = pFwImage->version[2];
937 				pVersionInfo->imageAux[1]  = pFwImage->version[3];
938 				pVersionInfo->imageAux[2]  = pFwImage->version[4];
939 				pVersionInfo->imageAux[3]  = pFwImage->version[5];
940 
941 				mode = TARGET_VER | IMAGE_VER;
942 				/* check if component is selected for upgrade */
943 				upgrade_comp = !componentMask
944 					|| (componentMask & pActionRecord->components.ComponentBits.byte);
945 				/* check if current component version requires upgrade */
946 				if (upgrade_comp && !(option & (FORCE_MODE|COMPARE_MODE))) {
947 					upgrade_comp = image_version_upgradable(pVersionInfo);
948 				}
949 				if (verbose) {
950 					lprintf(LOG_NOTICE,
951 							"%s component %d",
952 							(upgrade_comp ? "Updating" : "Skipping"),
953 							componentId);
954 				}
955 				if (upgrade_comp) {
956 					pFwupgCtx->compUpdateMask.ComponentBits.byte|= 1 << componentId;
957 				}
958 				if (option & VIEW_MODE) {
959 					if (pVersionInfo->rollbackSupported) {
960 						mode|= ROLLBACK_VER;
961 					}
962 					HpmDisplayVersion(mode,pVersionInfo, upgrade_comp);
963 					printf("\n");
964 				}
965 				pImagePtr = pData + firmwareLength;
966 			}
967 			break;
968 		default:
969 			lprintf(LOG_NOTICE,
970 					"    Invalid Action type. Cannot continue");
971 			return HPMFWUPG_ERROR;
972 			break;
973 		}
974 	}
975 	if (option & VIEW_MODE) {
976 		HpmDisplayLine("-",74);
977 		fflush(stdout);
978 		lprintf(LOG_NOTICE,
979 				"(*) Component requires Payload Cold Reset");
980 		lprintf(LOG_NOTICE,
981 				"(^) Indicates component would be upgraded");
982 	}
983 	return HPMFWUPG_SUCCESS;
984 }
985 
986 /* HpmfwupgUpgradeStage - upgrade stage of a firmware upgrade procedure as
987  * defined in section 3.3 of the IPM Controller Firmware Upgrade Specification
988  * version 1.0
989  */
990 int
991 HpmfwupgUpgradeStage(struct ipmi_intf *intf,
992 		struct HpmfwupgUpgradeCtx *pFwupgCtx, int option)
993 {
994 	struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*)
995 		pFwupgCtx->pImageData;
996 	struct HpmfwupgActionRecord* pActionRecord;
997 	int rc = HPMFWUPG_SUCCESS;
998 	unsigned char *pImagePtr;
999 	unsigned int actionsSize;
1000 	int flagColdReset = FALSE;
1001 	/* Put pointer after image header */
1002 	pImagePtr = (unsigned char*)
1003 		(pFwupgCtx->pImageData + sizeof(struct HpmfwupgImageHeader) +
1004 		pImageHeader->oemDataLength + sizeof(unsigned char)/*checksum*/);
1005 	/* Deternime actions size */
1006 	actionsSize = pFwupgCtx->imageSize - sizeof(struct HpmfwupgImageHeader);
1007 	if (!(option & VIEW_MODE)) {
1008 		HpmDisplayUpgradeHeader();
1009 	}
1010 	/* Perform actions defined in the image */
1011 	while (( pImagePtr < (pFwupgCtx->pImageData + pFwupgCtx->imageSize -
1012 					HPMFWUPG_MD5_SIGNATURE_LENGTH))
1013 			&& (rc == HPMFWUPG_SUCCESS)) {
1014 		/* Get action record */
1015 		pActionRecord = (struct HpmfwupgActionRecord*)pImagePtr;
1016 		/* Validate action record checksum */
1017 		rc = HpmfwupgValidateActionRecordChecksum(pActionRecord);
1018 		if (rc != HPMFWUPG_SUCCESS) {
1019 			continue;
1020 		}
1021 		switch(pActionRecord->actionType) {
1022 		case HPMFWUPG_ACTION_BACKUP_COMPONENTS:
1023 			{
1024 				if (!(option & COMPARE_MODE)) {
1025 					/* Send Upgrade Action command */
1026 					struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd;
1027 					/* Affect only selected components */
1028 					initUpgActionCmd.req.componentsMask.ComponentBits.byte =
1029 						pFwupgCtx->compUpdateMask.ComponentBits.byte &
1030 						pActionRecord->components.ComponentBits.byte;
1031 					/* Action is prepare components */
1032 					if (initUpgActionCmd.req.componentsMask.ComponentBits.byte) {
1033 						initUpgActionCmd.req.upgradeAction  = HPMFWUPG_UPGRADE_ACTION_BACKUP;
1034 						rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx);
1035 					}
1036 				}
1037 				pImagePtr+= sizeof(struct HpmfwupgActionRecord);
1038 			}
1039 			break;
1040 		case HPMFWUPG_ACTION_PREPARE_COMPONENTS:
1041 			{
1042 				if (!(option & COMPARE_MODE)) {
1043 					/* Send prepare components command */
1044 					struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd;
1045 					/* Affect only selected components */
1046 					initUpgActionCmd.req.componentsMask.ComponentBits.byte =
1047 						pFwupgCtx->compUpdateMask.ComponentBits.byte &
1048 						pActionRecord->components.ComponentBits.byte;
1049 					if (initUpgActionCmd.req.componentsMask.ComponentBits.byte) {
1050 						/* Action is prepare components */
1051 						initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_PREPARE;
1052 						rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx);
1053 					}
1054 				}
1055 				pImagePtr+= sizeof(struct HpmfwupgActionRecord);
1056 			}
1057 			break;
1058 		case HPMFWUPG_ACTION_UPLOAD_FIRMWARE:
1059 			/* Upload all firmware blocks */
1060 			rc = HpmFwupgActionUploadFirmware(pActionRecord->components,
1061 					pFwupgCtx,
1062 					&pImagePtr,
1063 					intf,
1064 					option,
1065 					&flagColdReset);
1066 			break;
1067 		default:
1068 			lprintf(LOG_NOTICE, "    Invalid Action type. Cannot continue");
1069 			rc = HPMFWUPG_ERROR;
1070 			break;
1071 		}
1072 	}
1073 	HpmDisplayLine("-", 79);
1074 	fflush(stdout);
1075 	lprintf(LOG_NOTICE, "(*) Component requires Payload Cold Reset");
1076 	return rc;
1077 }
1078 
1079 int
1080 HpmFwupgActionUploadFirmware(struct HpmfwupgComponentBitMask components,
1081 		struct HpmfwupgUpgradeCtx *pFwupgCtx,
1082 		unsigned char **pImagePtr,
1083 		struct ipmi_intf *intf,
1084 		int option,
1085 		int *pFlagColdReset)
1086 {
1087 	struct HpmfwupgFirmwareImage *pFwImage;
1088 	struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd;
1089 	struct HpmfwupgUploadFirmwareBlockCtx uploadCmd;
1090 	struct HpmfwupgFinishFirmwareUploadCtx finishCmd;
1091 	VERSIONINFO *pVersionInfo;
1092 	time_t start,end;
1093 
1094 	int rc = HPMFWUPG_SUCCESS;
1095 	int skip = TRUE;
1096 	unsigned char *pData, *pDataInitial;
1097 	unsigned short count;
1098 	unsigned int totalSent = 0;
1099 	unsigned short bufLength = 0;
1100 	unsigned short bufLengthIsSet = 0;
1101 	unsigned int firmwareLength = 0;
1102 
1103 	unsigned int displayFWLength = 0;
1104 	unsigned char *pDataTemp;
1105 	unsigned int imageOffset = 0x00;
1106 	unsigned int blockLength = 0x00;
1107 	unsigned int lengthOfBlock = 0x00;
1108 	unsigned int numTxPkts = 0;
1109 	unsigned int numRxPkts = 0;
1110 	unsigned char mode = 0;
1111 	unsigned char componentId = 0x00;
1112 	unsigned char componentIdByte = 0x00;
1113 	uint16_t max_rq_size;
1114 
1115 	/* Save component ID on which the upload is done */
1116 	componentIdByte = components.ComponentBits.byte;
1117 	while ((componentIdByte>>= 1) != 0) {
1118 		componentId++;
1119 	}
1120 	pFwupgCtx->componentId = componentId;
1121 	pVersionInfo = (VERSIONINFO *)&gVersionInfo[componentId];
1122 	pFwImage = (struct HpmfwupgFirmwareImage*)((*pImagePtr)
1123 			+ sizeof(struct HpmfwupgActionRecord));
1124 	pDataInitial = ((unsigned char *)pFwImage
1125 			+ sizeof(struct HpmfwupgFirmwareImage));
1126 	pData = pDataInitial;
1127 
1128 	/* Find max buffer length according the connection parameters */
1129 	max_rq_size = ipmi_intf_get_max_request_data_size(intf);
1130 
1131 	/* validate lower bound of max request size */
1132 	if (max_rq_size <= sizeof(struct HpmfwupgUploadFirmwareBlockReq)) {
1133 		lprintf(LOG_ERROR, "Maximum request size is too small to "
1134 				"send a upload request.");
1135 		return HPMFWUPG_ERROR;
1136 	}
1137 
1138 	bufLength = max_rq_size - sizeof(struct HpmfwupgUploadFirmwareBlockReq);
1139 
1140 	/* Get firmware length */
1141 	firmwareLength =  pFwImage->length[0];
1142 	firmwareLength|= (pFwImage->length[1] << 8)  & 0xff00;
1143 	firmwareLength|= (pFwImage->length[2] << 16) & 0xff0000;
1144 	firmwareLength|= (pFwImage->length[3] << 24) & 0xff000000;
1145 	mode = TARGET_VER | IMAGE_VER;
1146 	if (pVersionInfo->rollbackSupported) {
1147 		mode |= ROLLBACK_VER;
1148 	}
1149 	if ((option & DEBUG_MODE)) {
1150 		printf("\n\n Comp ID : %d	 [%-20s]\n",
1151 				pVersionInfo->componentId,
1152 				pFwImage->desc);
1153 	} else {
1154 		HpmDisplayVersion(mode, pVersionInfo, 0);
1155 	}
1156 	if ((1 << componentId) & pFwupgCtx->compUpdateMask.ComponentBits.byte) {
1157 		if (verbose) {
1158 			lprintf(LOG_NOTICE, "Do not skip %d",
1159 					componentId);
1160 		}
1161 		skip = FALSE;
1162 	}
1163 	if (!skip) {
1164 		HpmDisplayUpgrade(0,0,1,0);
1165 		/* Initialize parameters */
1166 		uploadCmd.req = malloc(max_rq_size);
1167 		if (!uploadCmd.req) {
1168 			lprintf(LOG_ERR, "ipmitool: malloc failure");
1169 			return HPMFWUPG_ERROR;
1170 		}
1171 		uploadCmd.req->blockNumber = 0;
1172 		/* Send Initiate Upgrade Action */
1173 		initUpgActionCmd.req.componentsMask = components;
1174 		if (option & COMPARE_MODE) {
1175 			/* Action is compare */
1176 			initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_COMPARE;
1177 		} else {
1178 			/* Action is upgrade */
1179 			initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_UPGRADE;
1180 		}
1181 		rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx);
1182 		if (rc != HPMFWUPG_SUCCESS) {
1183 			skip = TRUE;
1184 		}
1185 		if ((pVersionInfo->coldResetRequired) && (!skip)) {
1186 			*pFlagColdReset = TRUE;
1187 		}
1188 		/* pDataInitial is the starting pointer of the image data  */
1189 		/* pDataTemp is one which we will move across */
1190 		pData = pDataInitial;
1191 		pDataTemp = pDataInitial;
1192 		lengthOfBlock = firmwareLength;
1193 		totalSent = 0x00;
1194 		displayFWLength= firmwareLength;
1195 		time(&start);
1196 		while ((pData < (pDataTemp+lengthOfBlock)) && (rc == HPMFWUPG_SUCCESS)) {
1197 			if ((pData+bufLength) <= (pDataTemp+lengthOfBlock)) {
1198 				count = bufLength;
1199 			} else {
1200 				count = (unsigned short)((pDataTemp+lengthOfBlock) - pData);
1201 			}
1202 			memcpy(&uploadCmd.req->data, pData, bufLength);
1203 			imageOffset = 0x00;
1204 			blockLength = 0x00;
1205 			numTxPkts++;
1206 			rc = HpmfwupgUploadFirmwareBlock(intf, &uploadCmd,
1207 					pFwupgCtx, count, &imageOffset,&blockLength);
1208 			numRxPkts++;
1209 			if (rc != HPMFWUPG_SUCCESS) {
1210 				if (rc == HPMFWUPG_UPLOAD_BLOCK_LENGTH && !bufLengthIsSet) {
1211 					rc = HPMFWUPG_SUCCESS;
1212 					/* Retry with a smaller buffer length */
1213 					if (strstr(intf->name,"lan") != NULL && bufLength > 8) {
1214 						bufLength-= 8;
1215 						lprintf(LOG_INFO,
1216 								"Trying reduced buffer length: %d",
1217 								bufLength);
1218 					} else if (bufLength) {
1219 						bufLength-= 1;
1220 						lprintf(LOG_INFO,
1221 								"Trying reduced buffer length: %d",
1222 								bufLength);
1223 					} else {
1224 						rc = HPMFWUPG_ERROR;
1225 					}
1226 				} else if (rc == HPMFWUPG_UPLOAD_RETRY) {
1227 					rc = HPMFWUPG_SUCCESS;
1228 				} else {
1229 					fflush(stdout);
1230 					lprintf(LOG_NOTICE,
1231 							"\n Error in Upload FIRMWARE command [rc=%d]\n",
1232 							rc);
1233 					lprintf(LOG_NOTICE,
1234 							"\n TotalSent:0x%x ",
1235 							totalSent);
1236 					/* Exiting from the function */
1237 					rc = HPMFWUPG_ERROR;
1238 				}
1239 			} else {
1240 				/* success, buf length is valid */
1241 				bufLengthIsSet = 1;
1242 				if (imageOffset + blockLength > firmwareLength ||
1243 						imageOffset + blockLength < blockLength) {
1244 					/*
1245 					 * blockLength is the remaining length of the firmware to upload so
1246 					 * if imageOffset and blockLength sum is greater than the firmware
1247 					 * length then its kind of error
1248 					 */
1249 					lprintf(LOG_NOTICE,
1250 							"\n Error in Upload FIRMWARE command [rc=%d]\n",
1251 							rc);
1252 					lprintf(LOG_NOTICE,
1253 							"\n TotalSent:0x%x Img offset:0x%x  Blk length:0x%x  Fwlen:0x%x\n",
1254 							totalSent,imageOffset,blockLength,firmwareLength);
1255 					rc = HPMFWUPG_ERROR;
1256 					continue;
1257 				}
1258 				totalSent += count;
1259 				if (imageOffset != 0x00) {
1260 					/* block Length is valid  */
1261 					lengthOfBlock = blockLength;
1262 					pDataTemp = pDataInitial + imageOffset;
1263 					pData = pDataTemp;
1264 					if (displayFWLength == firmwareLength) {
1265 						/* This is basically used only to make sure that we display uptil 100% */
1266 						displayFWLength = blockLength + totalSent;
1267 					}
1268 				} else {
1269 					pData += count;
1270 				}
1271 				time(&end);
1272 				/*
1273 				 * Just added debug mode in case we need to see exactly how many bytes have
1274 				 * gone through - Its a hidden option used mainly should be used for debugging
1275 				 */
1276 				if (option & DEBUG_MODE) {
1277 					fflush(stdout);
1278 					printf(" Blk Num : %02x        Bytes : %05x ",
1279 							uploadCmd.req->blockNumber,totalSent);
1280 					if (imageOffset || blockLength) {
1281 						printf("\n--> ImgOff : %x BlkLen : %x\n",
1282 								imageOffset,blockLength);
1283 					}
1284 					if (displayFWLength == totalSent) {
1285 						printf("\n Time Taken %02ld:%02ld",
1286 								(end-start)/60, (end-start)%60);
1287 						printf("\n\n");
1288 					}
1289 				} else {
1290 					HpmDisplayUpgrade(0, totalSent,
1291 							displayFWLength, (end-start));
1292 				}
1293 				uploadCmd.req->blockNumber++;
1294 			}
1295 		}
1296 		/* free buffer */
1297 		free(uploadCmd.req);
1298 		uploadCmd.req = NULL;
1299 	}
1300 	if (skip) {
1301 		HpmDisplayUpgrade(1,0,0,0);
1302 		if ((option & COMPARE_MODE)
1303 				&& !pFwupgCtx->genCompProp[pFwupgCtx->componentId].GeneralCompProperties.bitfield.comparisonSupport) {
1304 			printf("|    |Comparison isn't supported for given compenent.                        |\n");
1305 		}
1306 		*pImagePtr = pDataInitial + firmwareLength;
1307 	}
1308 	if (rc == HPMFWUPG_SUCCESS && !skip) {
1309 		/* Send finish component */
1310 		/* Set image length */
1311 		finishCmd.req.componentId = componentId;
1312 		/* We need to send the actual data that is sent
1313 		 * not the comlete firmware image length
1314 		 */
1315 		finishCmd.req.imageLength[0] = totalSent & 0xFF;
1316 		finishCmd.req.imageLength[1] = (totalSent >> 8) & 0xFF;
1317 		finishCmd.req.imageLength[2] = (totalSent >> 16) & 0xFF;
1318 		finishCmd.req.imageLength[3] = (totalSent >> 24) & 0xFF;
1319 		rc = HpmfwupgFinishFirmwareUpload(intf, &finishCmd,
1320 				pFwupgCtx, option);
1321 		*pImagePtr = pDataInitial + firmwareLength;
1322 	}
1323 	return rc;
1324 }
1325 
1326 /* HpmfwupgActivationStage - validate stage of a firmware upgrade procedure as
1327  * defined in section 3.4 of the IPM Controller Firmware Upgrade Specification
1328  * version 1.0
1329  */
1330 int
1331 HpmfwupgActivationStage(struct ipmi_intf *intf,
1332 		struct HpmfwupgUpgradeCtx *pFwupgCtx)
1333 {
1334 	int rc = HPMFWUPG_SUCCESS;
1335 	struct HpmfwupgActivateFirmwareCtx activateCmd;
1336 	struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*)
1337 		pFwupgCtx->pImageData;
1338 	/* Print out stuf...*/
1339 	printf("    ");
1340 	fflush(stdout);
1341 	/* Activate new firmware */
1342 	activateCmd.req.rollback_override = 0;
1343 	rc = HpmfwupgActivateFirmware(intf, &activateCmd, pFwupgCtx);
1344 	if (rc == HPMFWUPG_SUCCESS) {
1345 		/* Query self test result if supported by target and new image */
1346 		if ((pFwupgCtx->targetCap.GlobalCapabilities.bitField.ipmcSelftestCap == 1)
1347 				|| (pImageHeader->imageCapabilities.bitField.imageSelfTest == 1)) {
1348 			struct HpmfwupgQuerySelftestResultCtx selfTestCmd;
1349 			rc = HpmfwupgQuerySelftestResult(intf, &selfTestCmd,
1350 					pFwupgCtx);
1351 			if (rc == HPMFWUPG_SUCCESS) {
1352 				/* Get the self test result */
1353 				if (selfTestCmd.resp.result1 != 0x55) {
1354 					/* Perform manual rollback if necessary */
1355 					/* BACKUP/ MANUAL ROLLBACK not supported by this UA */
1356 					lprintf(LOG_NOTICE, "    Self test failed:");
1357 					lprintf(LOG_NOTICE, "    Result1 = %x",
1358 							selfTestCmd.resp.result1);
1359 					lprintf(LOG_NOTICE, "    Result2 = %x",
1360 							selfTestCmd.resp.result2);
1361 					rc = HPMFWUPG_ERROR;
1362 				}
1363 			} else {
1364 				/* Perform manual rollback if necessary */
1365 				/* BACKUP / MANUAL ROLLBACK not supported by this UA */
1366 				lprintf(LOG_NOTICE,"    Self test failed.");
1367 			}
1368 		}
1369 	}
1370 	/* If activation / self test failed, query rollback
1371 	 * status if automatic rollback supported
1372 	 */
1373 	if (rc == HPMFWUPG_ERROR) {
1374 		if ((pFwupgCtx->targetCap.GlobalCapabilities.bitField.autRollback == 1)
1375 				&& (pFwupgCtx->genCompProp[pFwupgCtx->componentId].GeneralCompProperties.bitfield.rollbackBackup != 0x00)) {
1376 			struct HpmfwupgQueryRollbackStatusCtx rollCmd;
1377 			lprintf(LOG_NOTICE,"    Getting rollback status...");
1378 			fflush(stdout);
1379 			rc = HpmfwupgQueryRollbackStatus(intf,
1380 					&rollCmd, pFwupgCtx);
1381 		}
1382 	}
1383 	return rc;
1384 }
1385 
1386 int
1387 HpmfwupgGetBufferFromFile(char *imageFilename,
1388 		struct HpmfwupgUpgradeCtx *pFwupgCtx)
1389 {
1390 	int rc = HPMFWUPG_SUCCESS;
1391 	int ret = 0;
1392 	FILE *pImageFile = fopen(imageFilename, "rb");
1393 	if (pImageFile == NULL) {
1394 		lprintf(LOG_ERR, "Cannot open image file '%s'",
1395 				imageFilename);
1396 		return HPMFWUPG_ERROR;
1397 	}
1398 	/* Get the raw data in file */
1399 	fseek(pImageFile, 0, SEEK_END);
1400 	pFwupgCtx->imageSize  = ftell(pImageFile);
1401 	pFwupgCtx->pImageData = malloc(sizeof(unsigned char)*pFwupgCtx->imageSize);
1402 	if (pFwupgCtx->pImageData == NULL) {
1403 		lprintf(LOG_ERR, "ipmitool: malloc failure");
1404 		fclose(pImageFile);
1405 		return HPMFWUPG_ERROR;
1406 	}
1407 	rewind(pImageFile);
1408 	ret = fread(pFwupgCtx->pImageData,
1409 			sizeof(unsigned char),
1410 			pFwupgCtx->imageSize,
1411 			pImageFile);
1412 	if (ret != pFwupgCtx->imageSize) {
1413 		lprintf(LOG_ERR,
1414 				"Failed to read file %s size %d",
1415 				imageFilename,
1416 				pFwupgCtx->imageSize);
1417 		rc = HPMFWUPG_ERROR;
1418 	}
1419 	fclose(pImageFile);
1420 	return rc;
1421 }
1422 
1423 int
1424 HpmfwupgGetDeviceId(struct ipmi_intf *intf, struct ipm_devid_rsp *pGetDevId)
1425 {
1426 	struct ipmi_rs *rsp;
1427 	struct ipmi_rq req;
1428 	memset(&req, 0, sizeof(req));
1429 	req.msg.netfn = IPMI_NETFN_APP;
1430 	req.msg.cmd = BMC_GET_DEVICE_ID;
1431 	req.msg.data_len = 0;
1432 	rsp = HpmfwupgSendCmd(intf, req, NULL);
1433 	if (rsp == NULL) {
1434 		lprintf(LOG_ERR, "Error getting device ID.");
1435 		return HPMFWUPG_ERROR;
1436 	}
1437 	if (rsp->ccode != 0x00) {
1438 		lprintf(LOG_ERR, "Error getting device ID.");
1439 		lprintf(LOG_ERR, "compcode=0x%x: %s",
1440 				rsp->ccode,
1441 				val2str(rsp->ccode, completion_code_vals));
1442 		return HPMFWUPG_ERROR;
1443 	}
1444 	memcpy(pGetDevId, rsp->data, sizeof(struct ipm_devid_rsp));
1445 	return HPMFWUPG_SUCCESS;
1446 }
1447 
1448 int
1449 HpmfwupgGetTargetUpgCapabilities(struct ipmi_intf *intf,
1450 		struct HpmfwupgGetTargetUpgCapabilitiesCtx *pCtx)
1451 {
1452 	struct ipmi_rs *rsp;
1453 	struct ipmi_rq req;
1454 	pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
1455 	memset(&req, 0, sizeof(req));
1456 	req.msg.netfn = IPMI_NETFN_PICMG;
1457 	req.msg.cmd = HPMFWUPG_GET_TARGET_UPG_CAPABILITIES;
1458 	req.msg.data = (unsigned char*)&pCtx->req;
1459 	req.msg.data_len = sizeof(struct HpmfwupgGetTargetUpgCapabilitiesReq);
1460 	rsp = HpmfwupgSendCmd(intf, req, NULL);
1461 	if (rsp == NULL) {
1462 		lprintf(LOG_ERR,
1463 				"Error getting target upgrade capabilities.");
1464 		return HPMFWUPG_ERROR;
1465 	}
1466 	if (rsp->ccode != 0x00) {
1467 		lprintf(LOG_ERR,
1468 				"Error getting target upgrade capabilities, ccode: 0x%x: %s",
1469 				rsp->ccode,
1470 				val2str(rsp->ccode, completion_code_vals));
1471 		return HPMFWUPG_ERROR;
1472 	}
1473 	memcpy(&pCtx->resp, rsp->data,
1474 			sizeof(struct HpmfwupgGetTargetUpgCapabilitiesResp));
1475 	if (verbose) {
1476 		lprintf(LOG_NOTICE, "TARGET UPGRADE CAPABILITIES");
1477 		lprintf(LOG_NOTICE, "-------------------------------");
1478 		lprintf(LOG_NOTICE, "HPM.1 version............%d    ",
1479 				pCtx->resp.hpmVersion);
1480 		lprintf(LOG_NOTICE, "Component 0 presence....[%c]   ",
1481 				pCtx->resp.componentsPresent.ComponentBits.bitField.component0 ? 'y' : 'n');
1482 		lprintf(LOG_NOTICE, "Component 1 presence....[%c]   ",
1483 				pCtx->resp.componentsPresent.ComponentBits.bitField.component1 ? 'y' : 'n');
1484 		lprintf(LOG_NOTICE, "Component 2 presence....[%c]   ",
1485 				pCtx->resp.componentsPresent.ComponentBits.bitField.component2 ? 'y' : 'n');
1486 		lprintf(LOG_NOTICE, "Component 3 presence....[%c]   ",
1487 				pCtx->resp.componentsPresent.ComponentBits.bitField.component3 ? 'y' : 'n');
1488 		lprintf(LOG_NOTICE, "Component 4 presence....[%c]   ",
1489 				pCtx->resp.componentsPresent.ComponentBits.bitField.component4 ? 'y' : 'n');
1490 		lprintf(LOG_NOTICE, "Component 5 presence....[%c]   ",
1491 				pCtx->resp.componentsPresent.ComponentBits.bitField.component5 ? 'y' : 'n');
1492 		lprintf(LOG_NOTICE, "Component 6 presence....[%c]   ",
1493 				pCtx->resp.componentsPresent.ComponentBits.bitField.component6 ? 'y' : 'n');
1494 		lprintf(LOG_NOTICE, "Component 7 presence....[%c]   ",
1495 				pCtx->resp.componentsPresent.ComponentBits.bitField.component7 ? 'y' : 'n');
1496 		lprintf(LOG_NOTICE, "Upgrade undesirable.....[%c]   ",
1497 				pCtx->resp.GlobalCapabilities.bitField.fwUpgUndesirable ? 'y' : 'n');
1498 		lprintf(LOG_NOTICE, "Aut rollback override...[%c]   ",
1499 				pCtx->resp.GlobalCapabilities.bitField.autRollbackOverride ? 'y' : 'n');
1500 		lprintf(LOG_NOTICE, "IPMC degraded...........[%c]   ",
1501 				pCtx->resp.GlobalCapabilities.bitField.ipmcDegradedDurinUpg ? 'y' : 'n');
1502 		lprintf(LOG_NOTICE, "Defered activation......[%c]   ",
1503 				pCtx->resp.GlobalCapabilities.bitField.deferActivation ? 'y' : 'n');
1504 		lprintf(LOG_NOTICE, "Service affected........[%c]   ",
1505 				pCtx->resp.GlobalCapabilities.bitField.servAffectDuringUpg ? 'y' : 'n');
1506 		lprintf(LOG_NOTICE, "Manual rollback.........[%c]   ",
1507 				pCtx->resp.GlobalCapabilities.bitField.manualRollback ? 'y' : 'n');
1508 		lprintf(LOG_NOTICE, "Automatic rollback......[%c]   ",
1509 				pCtx->resp.GlobalCapabilities.bitField.autRollback ? 'y' : 'n');
1510 		lprintf(LOG_NOTICE, "Self test...............[%c]   ",
1511 				pCtx->resp.GlobalCapabilities.bitField.ipmcSelftestCap ? 'y' : 'n');
1512 		lprintf(LOG_NOTICE, "Upgrade timeout.........[%d sec] ",
1513 				pCtx->resp.upgradeTimeout*5);
1514 		lprintf(LOG_NOTICE, "Self test timeout.......[%d sec] ",
1515 				pCtx->resp.selftestTimeout*5);
1516 		lprintf(LOG_NOTICE, "Rollback timeout........[%d sec] ",
1517 				pCtx->resp.rollbackTimeout*5);
1518 		lprintf(LOG_NOTICE, "Inaccessibility timeout.[%d sec] \n",
1519 				pCtx->resp.inaccessTimeout*5);
1520 	}
1521 	return HPMFWUPG_SUCCESS;
1522 }
1523 
1524 int
1525 HpmfwupgGetComponentProperties(struct ipmi_intf *intf,
1526 		struct HpmfwupgGetComponentPropertiesCtx *pCtx)
1527 {
1528 	int rc = HPMFWUPG_SUCCESS;
1529 	struct ipmi_rs * rsp;
1530 	struct ipmi_rq req;
1531 	pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
1532 	memset(&req, 0, sizeof(req));
1533 	req.msg.netfn = IPMI_NETFN_PICMG;
1534 	req.msg.cmd = HPMFWUPG_GET_COMPONENT_PROPERTIES;
1535 	req.msg.data = (unsigned char*)&pCtx->req;
1536 	req.msg.data_len = sizeof(struct HpmfwupgGetComponentPropertiesReq);
1537 	rsp = HpmfwupgSendCmd(intf, req, NULL);
1538 	if (rsp == NULL) {
1539 		lprintf(LOG_NOTICE,
1540 				"Error getting component properties\n");
1541 		return HPMFWUPG_ERROR;
1542 	}
1543 	if (rsp->ccode != 0x00) {
1544 		lprintf(LOG_NOTICE,
1545 				"Error getting component properties");
1546 		lprintf(LOG_NOTICE,
1547 				"compcode=0x%x: %s",
1548 				rsp->ccode,
1549 				val2str(rsp->ccode, completion_code_vals));
1550 		return HPMFWUPG_ERROR;
1551 	}
1552 	switch (pCtx->req.selector) {
1553 	case HPMFWUPG_COMP_GEN_PROPERTIES:
1554 		memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetGeneralPropResp));
1555 		if (verbose) {
1556 			lprintf(LOG_NOTICE, "GENERAL PROPERTIES");
1557 			lprintf(LOG_NOTICE, "-------------------------------");
1558 			lprintf(LOG_NOTICE, "Payload cold reset req....[%c]   ",
1559 					pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.payloadColdReset ? 'y' : 'n');
1560 			lprintf(LOG_NOTICE, "Def. activation supported.[%c]   ",
1561 					pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.deferredActivation ? 'y' : 'n');
1562 			lprintf(LOG_NOTICE, "Comparison supported......[%c]   ",
1563 					pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.comparisonSupport ? 'y' : 'n');
1564 			lprintf(LOG_NOTICE, "Preparation supported.....[%c]   ",
1565 					pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.preparationSupport ? 'y' : 'n');
1566 			lprintf(LOG_NOTICE, "Rollback supported........[%c]   \n",
1567 					pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.rollbackBackup ? 'y' : 'n');
1568 		}
1569 		break;
1570 	case HPMFWUPG_COMP_CURRENT_VERSION:
1571 		memcpy(&pCtx->resp, rsp->data,
1572 				sizeof(struct HpmfwupgGetCurrentVersionResp));
1573 		if (verbose) {
1574 			lprintf(LOG_NOTICE, "Current Version: ");
1575 			lprintf(LOG_NOTICE, " Major: %d",
1576 					pCtx->resp.Response.currentVersionResp.currentVersion[0]);
1577 			lprintf(LOG_NOTICE, " Minor: %x",
1578 					pCtx->resp.Response.currentVersionResp.currentVersion[1]);
1579 			lprintf(LOG_NOTICE, " Aux  : %03d %03d %03d %03d\n",
1580 					pCtx->resp.Response.currentVersionResp.currentVersion[2],
1581 					pCtx->resp.Response.currentVersionResp.currentVersion[3],
1582 					pCtx->resp.Response.currentVersionResp.currentVersion[4],
1583 					pCtx->resp.Response.currentVersionResp.currentVersion[5]);
1584 		}
1585 		break;
1586 	case HPMFWUPG_COMP_DESCRIPTION_STRING:
1587 		memcpy(&pCtx->resp, rsp->data,
1588 				sizeof(struct HpmfwupgGetDescStringResp));
1589 		if (verbose) {
1590 			char descString[HPMFWUPG_DESC_STRING_LENGTH + 1];
1591 			memcpy(descString,
1592 					pCtx->resp.Response.descStringResp.descString,
1593 					HPMFWUPG_DESC_STRING_LENGTH);
1594 			descString[HPMFWUPG_DESC_STRING_LENGTH] = '\0';
1595 			lprintf(LOG_NOTICE,
1596 					"Description string: %s\n",
1597 					descString);
1598 		}
1599 		break;
1600 	case HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION:
1601 		memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetRollbackFwVersionResp));
1602 		if (verbose) {
1603 			lprintf(LOG_NOTICE, "Rollback FW Version: ");
1604 			lprintf(LOG_NOTICE, " Major: %d",
1605 					pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[0]);
1606 			lprintf(LOG_NOTICE, " Minor: %x",
1607 					pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[1]);
1608 			lprintf(LOG_NOTICE, " Aux  : %03d %03d %03d %03d\n",
1609 					pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[2],
1610 					pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[3],
1611 					pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[4],
1612 					pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[5]);
1613 		}
1614 		break;
1615 	case HPMFWUPG_COMP_DEFERRED_FIRMWARE_VERSION:
1616 		memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetDeferredFwVersionResp));
1617 		if (verbose) {
1618 			lprintf(LOG_NOTICE, "Deferred FW Version: ");
1619 			lprintf(LOG_NOTICE, " Major: %d",
1620 					pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[0]);
1621 			lprintf(LOG_NOTICE, " Minor: %x",
1622 					pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[1]);
1623 			lprintf(LOG_NOTICE, " Aux  : %03d %03d %03d %03d\n",
1624 					pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[2],
1625 					pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[3],
1626 					pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[4],
1627 					pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[5]);
1628 		}
1629 		break;
1630 	case HPMFWUPG_COMP_OEM_PROPERTIES:
1631 		/* OEM Properties command */
1632 		memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetOemProperties));
1633 		if (verbose) {
1634 			unsigned char i = 0;
1635 			lprintf(LOG_NOTICE,"OEM Properties: ");
1636 			for (i=0; i < HPMFWUPG_OEM_LENGTH; i++) {
1637 				lprintf(LOG_NOTICE, " 0x%x ",
1638 						pCtx->resp.Response.oemProperties.oemRspData[i]);
1639 			}
1640 		}
1641 		break;
1642 	default:
1643 		lprintf(LOG_NOTICE,"Unsupported component selector");
1644 		rc = HPMFWUPG_ERROR;
1645 		break;
1646 	}
1647 	return rc;
1648 }
1649 
1650 int
1651 HpmfwupgAbortUpgrade(struct ipmi_intf *intf,
1652 		struct HpmfwupgAbortUpgradeCtx *pCtx)
1653 {
1654 	int rc = HPMFWUPG_SUCCESS;
1655 	struct ipmi_rs *rsp;
1656 	struct ipmi_rq req;
1657 	pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
1658 	memset(&req, 0, sizeof(req));
1659 	req.msg.netfn = IPMI_NETFN_PICMG;
1660 	req.msg.cmd = HPMFWUPG_ABORT_UPGRADE;
1661 	req.msg.data = (unsigned char*)&pCtx->req;
1662 	req.msg.data_len = sizeof(struct HpmfwupgAbortUpgradeReq);
1663 	rsp = HpmfwupgSendCmd(intf, req, NULL);
1664 	if (rsp == NULL) {
1665 		lprintf(LOG_ERR, "Error - aborting upgrade.");
1666 		return HPMFWUPG_ERROR;
1667 	}
1668 	if (rsp->ccode != 0x00) {
1669 		lprintf(LOG_ERR, "Error aborting upgrade");
1670 		lprintf(LOG_ERR, "compcode=0x%x: %s",
1671 				rsp->ccode,
1672 				val2str(rsp->ccode, completion_code_vals));
1673 		rc = HPMFWUPG_ERROR;
1674 	}
1675 	return rc;
1676 }
1677 
1678 int
1679 HpmfwupgInitiateUpgradeAction(struct ipmi_intf *intf,
1680 		struct HpmfwupgInitiateUpgradeActionCtx *pCtx,
1681 		struct HpmfwupgUpgradeCtx *pFwupgCtx)
1682 {
1683 	int rc = HPMFWUPG_SUCCESS;
1684 	struct ipmi_rs *rsp;
1685 	struct ipmi_rq req;
1686 	pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
1687 	memset(&req, 0, sizeof(req));
1688 	req.msg.netfn = IPMI_NETFN_PICMG;
1689 	req.msg.cmd = HPMFWUPG_INITIATE_UPGRADE_ACTION;
1690 	req.msg.data = (unsigned char*)&pCtx->req;
1691 	req.msg.data_len = sizeof(struct HpmfwupgInitiateUpgradeActionReq);
1692 	rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
1693 	if (rsp == NULL) {
1694 		lprintf(LOG_ERR, "Error initiating upgrade action.");
1695 		return HPMFWUPG_ERROR;
1696 	}
1697 	/* Long duration command handling */
1698 	if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) {
1699 		rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx);
1700 	} else if (rsp->ccode != 0x00) {
1701 		lprintf(LOG_NOTICE,"Error initiating upgrade action");
1702 		lprintf(LOG_NOTICE, "compcode=0x%x: %s",
1703 				rsp->ccode,
1704 				val2str(rsp->ccode, completion_code_vals));
1705 		rc = HPMFWUPG_ERROR;
1706 	}
1707 	return rc;
1708 }
1709 
1710 int
1711 HpmfwupgUploadFirmwareBlock(struct ipmi_intf *intf,
1712 		struct HpmfwupgUploadFirmwareBlockCtx *pCtx,
1713 		struct HpmfwupgUpgradeCtx *pFwupgCtx, int count,
1714 		unsigned int *imageOffset, unsigned int *blockLength)
1715 {
1716 	int rc = HPMFWUPG_SUCCESS;
1717 	struct ipmi_rs *rsp;
1718 	struct ipmi_rq req;
1719 	pCtx->req->picmgId = HPMFWUPG_PICMG_IDENTIFIER;
1720 	memset(&req, 0, sizeof(req));
1721 	req.msg.netfn = IPMI_NETFN_PICMG;
1722 	req.msg.cmd = HPMFWUPG_UPLOAD_FIRMWARE_BLOCK;
1723 	req.msg.data = (unsigned char *)pCtx->req;
1724 	/* 2 is the size of the upload struct - data */
1725 	req.msg.data_len = 2 + count;
1726 	rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
1727 	if (rsp == NULL) {
1728 		lprintf(LOG_NOTICE, "Error uploading firmware block.");
1729 		return HPMFWUPG_ERROR;
1730 	}
1731 	if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS
1732 			|| rsp->ccode == 0x00) {
1733 		/*
1734 		 * We need to check if the response also contains the next upload firmware offset
1735 		 * and the firmware length in its response - These are optional but very vital
1736 		 */
1737 		if (rsp->data_len > 1) {
1738 			/*
1739 			 * If the response data length is greater than 1 it should contain both the
1740 			 * the Section offset and section length. Because we cannot just have
1741 			 * Section offset without section length so the length should be 9
1742 			 */
1743 			if (rsp->data_len == 9) {
1744 				/* rsp->data[1] - LSB  rsp->data[2]  - rsp->data[3] = MSB */
1745 				*imageOffset = (rsp->data[4] << 24) + (rsp->data[3] << 16) + (rsp->data[2] << 8) + rsp->data[1];
1746 				*blockLength = (rsp->data[8] << 24) + (rsp->data[7] << 16) + (rsp->data[6] << 8) + rsp->data[5];
1747 			} else {
1748 				 /*
1749 				 * The Spec does not say much for this kind of errors where the
1750 				 * firmware returned only offset and length so currently returning it
1751 				 * as 0x82 - Internal CheckSum Error
1752 				 */
1753 				lprintf(LOG_NOTICE,
1754 						"Error wrong rsp->datalen %d for Upload Firmware block command\n",
1755 						rsp->data_len);
1756 				rsp->ccode = HPMFWUPG_INT_CHECKSUM_ERROR;
1757 			}
1758 		}
1759 	}
1760 	/* Long duration command handling */
1761 	if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) {
1762 		rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx);
1763 	} else if (rsp->ccode != 0x00)  {
1764 		/* PATCH --> This validation is to handle retryables errors codes on IPMB bus.
1765 		 *           This will be fixed in the next release of open ipmi and this
1766 		 *           check will have to be removed. (Buggy version = 39)
1767 		 */
1768 		if (HPMFWUPG_IS_RETRYABLE(rsp->ccode)) {
1769 			lprintf(LOG_DEBUG, "HPM: [PATCH]Retryable error detected");
1770 			rc = HPMFWUPG_UPLOAD_RETRY;
1771 		} else if (rsp->ccode == IPMI_CC_REQ_DATA_INV_LENGTH ||
1772 				rsp->ccode == IPMI_CC_REQ_DATA_FIELD_EXCEED) {
1773 			/* If completion code = 0xc7(0xc8), we will retry with a reduced buffer length.
1774 			 * Do not print error.
1775 			 */
1776 			rc = HPMFWUPG_UPLOAD_BLOCK_LENGTH;
1777 		} else {
1778 			lprintf(LOG_ERR, "Error uploading firmware block");
1779 			lprintf(LOG_ERR, "compcode=0x%x: %s",
1780 					rsp->ccode,
1781 					val2str(rsp->ccode,
1782 						completion_code_vals));
1783 			rc = HPMFWUPG_ERROR;
1784 		}
1785 	}
1786 	return rc;
1787 }
1788 
1789 int
1790 HpmfwupgFinishFirmwareUpload(struct ipmi_intf *intf,
1791 		struct HpmfwupgFinishFirmwareUploadCtx *pCtx,
1792 		struct HpmfwupgUpgradeCtx *pFwupgCtx, int option)
1793 {
1794 	int rc = HPMFWUPG_SUCCESS;
1795 	struct ipmi_rs *rsp;
1796 	struct ipmi_rq req;
1797 	pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
1798 	memset(&req, 0, sizeof(req));
1799 	req.msg.netfn = IPMI_NETFN_PICMG;
1800 	req.msg.cmd = HPMFWUPG_FINISH_FIRMWARE_UPLOAD;
1801 	req.msg.data = (unsigned char*)&pCtx->req;
1802 	req.msg.data_len = sizeof(struct HpmfwupgFinishFirmwareUploadReq);
1803 	rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
1804 	if (rsp == NULL) {
1805 		lprintf(LOG_ERR, "Error fininshing firmware upload.");
1806 		return HPMFWUPG_ERROR;
1807 	}
1808 	/* Long duration command handling */
1809 	if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) {
1810 		rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx);
1811 	} else if ((option & COMPARE_MODE) && rsp->ccode == 0x83) {
1812 		printf("|    |Component's active copy doesn't match the upgrade image                 |\n");
1813 	} else if ((option & COMPARE_MODE) && rsp->ccode == IPMI_CC_OK) {
1814 		printf("|    |Comparison passed                                                       |\n");
1815 	} else if ( rsp->ccode != IPMI_CC_OK ) {
1816 		lprintf(LOG_ERR, "Error finishing firmware upload");
1817 		lprintf(LOG_ERR, "compcode=0x%x: %s",
1818 				rsp->ccode,
1819 				val2str(rsp->ccode, completion_code_vals));
1820 		rc = HPMFWUPG_ERROR;
1821 	}
1822 	return rc;
1823 }
1824 
1825 int
1826 HpmfwupgActivateFirmware(struct ipmi_intf *intf,
1827 		struct HpmfwupgActivateFirmwareCtx *pCtx,
1828 		struct HpmfwupgUpgradeCtx *pFwupgCtx)
1829 {
1830 	int rc = HPMFWUPG_SUCCESS;
1831 	struct ipmi_rs *rsp;
1832 	struct ipmi_rq req;
1833 	pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
1834 	memset(&req, 0, sizeof(req));
1835 	req.msg.netfn = IPMI_NETFN_PICMG;
1836 	req.msg.cmd = HPMFWUPG_ACTIVATE_FIRMWARE;
1837 	req.msg.data = (unsigned char*)&pCtx->req;
1838 	req.msg.data_len = sizeof(struct HpmfwupgActivateFirmwareReq)
1839 		- (!pCtx->req.rollback_override ? 1 : 0);
1840 	rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
1841 	if (rsp == NULL) {
1842 		lprintf(LOG_ERR, "Error activating firmware.");
1843 		return HPMFWUPG_ERROR;
1844 	}
1845 	/* Long duration command handling */
1846 	if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) {
1847 		printf("Waiting firmware activation...");
1848 		fflush(stdout);
1849 		rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx);
1850 		if (rc == HPMFWUPG_SUCCESS) {
1851 			lprintf(LOG_NOTICE, "OK");
1852 		} else {
1853 			lprintf(LOG_NOTICE, "Failed");
1854 		}
1855 	} else if (rsp->ccode != IPMI_CC_OK) {
1856 		lprintf(LOG_ERR, "Error activating firmware");
1857 		lprintf(LOG_ERR, "compcode=0x%x: %s",
1858 				rsp->ccode,
1859 				val2str(rsp->ccode, completion_code_vals));
1860 		rc = HPMFWUPG_ERROR;
1861 	}
1862 	return rc;
1863 }
1864 
1865 int
1866 HpmfwupgGetUpgradeStatus(struct ipmi_intf *intf,
1867 		struct HpmfwupgGetUpgradeStatusCtx *pCtx,
1868 		struct HpmfwupgUpgradeCtx *pFwupgCtx,
1869 		int silent)
1870 {
1871 	struct ipmi_rs *rsp;
1872 	struct ipmi_rq req;
1873 	pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
1874 	memset(&req, 0, sizeof(req));
1875 	req.msg.netfn = IPMI_NETFN_PICMG;
1876 	req.msg.cmd = HPMFWUPG_GET_UPGRADE_STATUS;
1877 	req.msg.data = (unsigned char*)&pCtx->req;
1878 	req.msg.data_len = sizeof(struct HpmfwupgGetUpgradeStatusReq);
1879 	rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
1880 	if (!rsp) {
1881 		lprintf(LOG_NOTICE,
1882 				"Error getting upgrade status. Failed to get response.");
1883 		return HPMFWUPG_ERROR;
1884 	}
1885 	if (rsp->ccode == 0x00) {
1886 		memcpy(&pCtx->resp, rsp->data,
1887 				sizeof(struct HpmfwupgGetUpgradeStatusResp));
1888 		if (!silent) {
1889 			lprintf(LOG_NOTICE, "Upgrade status:");
1890 			lprintf(LOG_NOTICE,
1891 					" Command in progress:          %x",
1892 					pCtx->resp.cmdInProcess);
1893 			lprintf(LOG_NOTICE,
1894 					" Last command completion code: %x",
1895 					pCtx->resp.lastCmdCompCode);
1896 		}
1897 	} else if (HPMFWUPG_IS_RETRYABLE(rsp->ccode)) {
1898 		/* PATCH --> This validation is to handle retryable errors
1899 		 *           codes on the IPMB bus.
1900 		 *           This will be fixed in the next release of
1901 		 *           open ipmi and this check can be removed.
1902 		 *           (Buggy version = 39)
1903 		 */
1904 		if (!silent) {
1905 			lprintf(LOG_DEBUG, "HPM: Retryable error detected");
1906 		}
1907 		pCtx->resp.lastCmdCompCode = HPMFWUPG_COMMAND_IN_PROGRESS;
1908 	} else {
1909 		lprintf(LOG_NOTICE, "Error getting upgrade status");
1910 		lprintf(LOG_NOTICE, "compcode=0x%x: %s", rsp->ccode,
1911 				val2str(rsp->ccode, completion_code_vals));
1912 		return HPMFWUPG_ERROR;
1913 	}
1914 	return HPMFWUPG_SUCCESS;
1915 }
1916 
1917 int
1918 HpmfwupgManualFirmwareRollback(struct ipmi_intf *intf,
1919 		struct HpmfwupgManualFirmwareRollbackCtx *pCtx)
1920 {
1921 	struct HpmfwupgUpgradeCtx fwupgCtx;
1922 	struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd;
1923 	int rc = HPMFWUPG_SUCCESS;
1924 	struct ipmi_rs *rsp;
1925 	struct ipmi_rq req;
1926 	/* prepare fake upgrade context */
1927 	memset(&fwupgCtx, 0, sizeof (fwupgCtx));
1928 	verbose--;
1929 	rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd);
1930 	verbose++;
1931 	if (rc != HPMFWUPG_SUCCESS) {
1932 		return rc;
1933 	}
1934 	memcpy(&fwupgCtx.targetCap, &targetCapCmd.resp, sizeof(targetCapCmd.resp));
1935 	pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
1936 	memset(&req, 0, sizeof(req));
1937 	req.msg.netfn = IPMI_NETFN_PICMG;
1938 	req.msg.cmd = HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK;
1939 	req.msg.data = (unsigned char*)&pCtx->req;
1940 	req.msg.data_len = sizeof(struct HpmfwupgManualFirmwareRollbackReq);
1941 	rsp = HpmfwupgSendCmd(intf, req, &fwupgCtx);
1942 	if (rsp == NULL) {
1943 		lprintf(LOG_ERR, "Error sending manual rollback.");
1944 		return HPMFWUPG_ERROR;
1945 	}
1946 	/* Long duration command handling */
1947 	if (rsp->ccode == IPMI_CC_OK
1948 			|| rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) {
1949 		struct HpmfwupgQueryRollbackStatusCtx resCmd;
1950 		printf("Waiting firmware rollback...");
1951 		fflush(stdout);
1952 		rc = HpmfwupgQueryRollbackStatus(intf, &resCmd, &fwupgCtx);
1953 	} else if ( rsp->ccode != 0x00 ) {
1954 		lprintf(LOG_ERR, "Error sending manual rollback");
1955 		lprintf(LOG_ERR, "compcode=0x%x: %s",
1956 				rsp->ccode,
1957 				val2str(rsp->ccode, completion_code_vals));
1958 		rc = HPMFWUPG_ERROR;
1959 	}
1960 	return rc;
1961 }
1962 
1963 int
1964 HpmfwupgQueryRollbackStatus(struct ipmi_intf *intf,
1965 		struct HpmfwupgQueryRollbackStatusCtx *pCtx,
1966 		struct HpmfwupgUpgradeCtx *pFwupgCtx)
1967 {
1968 	int rc = HPMFWUPG_SUCCESS;
1969 	struct ipmi_rs *rsp;
1970 	struct ipmi_rq req;
1971 	unsigned int rollbackTimeout = 0;
1972 	unsigned int timeoutSec1, timeoutSec2;
1973 	pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
1974 	memset(&req, 0, sizeof(req));
1975 	req.msg.netfn = IPMI_NETFN_PICMG;
1976 	req.msg.cmd = HPMFWUPG_QUERY_ROLLBACK_STATUS;
1977 	req.msg.data = (unsigned char*)&pCtx->req;
1978 	req.msg.data_len = sizeof(struct HpmfwupgQueryRollbackStatusReq);
1979 	/* If we are not in upgrade context, we use default timeout values */
1980 	if (pFwupgCtx != NULL) {
1981 		struct HpmfwupgImageHeader *pImageHeader;
1982 		if (pFwupgCtx->pImageData) {
1983 			pImageHeader = (struct HpmfwupgImageHeader*)pFwupgCtx->pImageData;
1984 			rollbackTimeout = pImageHeader->rollbackTimeout;
1985 		} else {
1986 			rollbackTimeout = 0;
1987 		}
1988 		/* Use the greater of the two timeouts (header and target caps) */
1989 		rollbackTimeout = MAX(rollbackTimeout,
1990 				pFwupgCtx->targetCap.rollbackTimeout) * 5;
1991 	} else {
1992 		rollbackTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT;
1993 	}
1994 	/* Poll rollback status until completion or timeout */
1995 	timeoutSec1 = time(NULL);
1996 	timeoutSec2 = time(NULL);
1997 	do {
1998 		/* Must wait at least 100 ms between status requests */
1999 		usleep(100000);
2000 		rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
2001 		/* PATCH --> This validation is to handle retryables errors codes on IPMB bus.
2002 		 *           This will be fixed in the next release of open ipmi and this
2003 		 *           check will have to be removed. (Buggy version = 39)
2004 		 */
2005 		if (rsp) {
2006 			if (HPMFWUPG_IS_RETRYABLE(rsp->ccode)) {
2007 				lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected");
2008 				rsp->ccode = HPMFWUPG_COMMAND_IN_PROGRESS;
2009 			}
2010 		}
2011 		timeoutSec2 = time(NULL);
2012 	} while (rsp
2013 			&& ((rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS)
2014 				|| (rsp->ccode == IPMI_CC_TIMEOUT))
2015 			&& (timeoutSec2 - timeoutSec1 < rollbackTimeout));
2016 	if (rsp == NULL) {
2017 		lprintf(LOG_ERR, "Error getting upgrade status.");
2018 		return HPMFWUPG_ERROR;
2019 	}
2020 	if (rsp->ccode == 0x00) {
2021 		memcpy(&pCtx->resp, rsp->data,
2022 				sizeof(struct HpmfwupgQueryRollbackStatusResp));
2023 		if (pCtx->resp.rollbackComp.ComponentBits.byte != 0) {
2024 			/* Rollback occured */
2025 			lprintf(LOG_NOTICE,
2026 					"Rollback occured on component mask: 0x%02x",
2027 					pCtx->resp.rollbackComp.ComponentBits.byte);
2028 		} else {
2029 			lprintf(LOG_NOTICE,
2030 					"No Firmware rollback occured");
2031 		}
2032 	} else if (rsp->ccode == 0x81) {
2033 		lprintf(LOG_ERR,
2034 				"Rollback failed on component mask: 0x%02x",
2035 				pCtx->resp.rollbackComp.ComponentBits.byte);
2036 		rc = HPMFWUPG_ERROR;
2037 	} else {
2038 		lprintf(LOG_ERR,
2039 				"Error getting rollback status");
2040 		lprintf(LOG_ERR,
2041 				"compcode=0x%x: %s",
2042 				rsp->ccode,
2043 				val2str(rsp->ccode, completion_code_vals));
2044 		rc = HPMFWUPG_ERROR;
2045 	}
2046 	return rc;
2047 }
2048 
2049 int
2050 HpmfwupgQuerySelftestResult(struct ipmi_intf *intf, struct HpmfwupgQuerySelftestResultCtx *pCtx,
2051 		struct HpmfwupgUpgradeCtx *pFwupgCtx)
2052 {
2053 	int rc = HPMFWUPG_SUCCESS;
2054 	struct ipmi_rs *rsp;
2055 	struct ipmi_rq req;
2056 	unsigned char selfTestTimeout = 0;
2057 	unsigned int timeoutSec1, timeoutSec2;
2058 	pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
2059 	/* If we are not in upgrade context, we use default timeout values */
2060 	if (pFwupgCtx != NULL) {
2061 		/* Getting selftest timeout from new image */
2062 		struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*)
2063 			pFwupgCtx->pImageData;
2064 		selfTestTimeout = MAX(pImageHeader->selfTestTimeout,
2065 		pFwupgCtx->targetCap.selftestTimeout) * 5;
2066 	} else {
2067 		selfTestTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT;
2068 	}
2069 	memset(&req, 0, sizeof(req));
2070 	req.msg.netfn = IPMI_NETFN_PICMG;
2071 	req.msg.cmd = HPMFWUPG_QUERY_SELFTEST_RESULT;
2072 	req.msg.data = (unsigned char*)&pCtx->req;
2073 	req.msg.data_len = sizeof(struct HpmfwupgQuerySelftestResultReq);
2074 	/* Poll rollback status until completion or timeout */
2075 	timeoutSec1 = time(NULL);
2076 	timeoutSec2 = time(NULL);
2077 	do {
2078 		/* Must wait at least 100 ms between status requests */
2079 		usleep(100000);
2080 		rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
2081 		/* PATCH --> This validation is to handle retryables errors codes on IPMB bus.
2082 		 *           This will be fixed in the next release of open ipmi and this
2083 		 *           check will have to be removed. (Buggy version = 39)
2084 		 */
2085 		if (rsp) {
2086 			if (HPMFWUPG_IS_RETRYABLE(rsp->ccode)) {
2087 				lprintf(LOG_DEBUG,
2088 						"HPM: [PATCH]Retryable error detected");
2089 				rsp->ccode = HPMFWUPG_COMMAND_IN_PROGRESS;
2090 			}
2091 		}
2092 		timeoutSec2 = time(NULL);
2093 	} while (rsp
2094 			&& (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS)
2095 			&& (timeoutSec2 - timeoutSec1 < selfTestTimeout));
2096 	if (rsp == NULL) {
2097 		lprintf(LOG_NOTICE, "Error getting upgrade status\n");
2098 		return HPMFWUPG_ERROR;
2099 	}
2100 	if (rsp->ccode == 0x00) {
2101 		memcpy(&pCtx->resp, rsp->data,
2102 				sizeof(struct HpmfwupgQuerySelftestResultResp));
2103 		if (verbose) {
2104 			lprintf(LOG_NOTICE, "Self test results:");
2105 			lprintf(LOG_NOTICE, "Result1 = %x",
2106 					pCtx->resp.result1);
2107 			lprintf(LOG_NOTICE, "Result2 = %x",
2108 					pCtx->resp.result2);
2109 		}
2110 	} else {
2111 		lprintf(LOG_NOTICE, "Error getting self test results");
2112 		lprintf(LOG_NOTICE, "compcode=0x%x: %s",
2113 				rsp->ccode,
2114 				val2str(rsp->ccode, completion_code_vals));
2115 		rc = HPMFWUPG_ERROR;
2116 	}
2117 	return rc;
2118 }
2119 
2120 struct ipmi_rs *
2121 HpmfwupgSendCmd(struct ipmi_intf *intf, struct ipmi_rq req,
2122 		struct HpmfwupgUpgradeCtx *pFwupgCtx)
2123 {
2124 	struct ipmi_rs *rsp;
2125 	unsigned int inaccessTimeout = 0, inaccessTimeoutCounter = 0;
2126 	unsigned int upgradeTimeout  = 0, upgradeTimeoutCounter  = 0;
2127 	unsigned int  timeoutSec1, timeoutSec2;
2128 	unsigned char retry = 0;
2129 	/* If we are not in upgrade context, we use default timeout values */
2130 	if (pFwupgCtx != NULL) {
2131 		inaccessTimeout = pFwupgCtx->targetCap.inaccessTimeout*5;
2132 		upgradeTimeout  = pFwupgCtx->targetCap.upgradeTimeout*5;
2133 	} else {
2134 		/* keeping the inaccessTimeout to 60 seconds results in almost 2900 retries
2135 		 * So if the target is not available it will be retrying the command for 2900
2136 		 * times which is not effecient -So reducing the Timout to 5 seconds which is
2137 		 * almost 200 retries if it continuously recieves 0xC3 as completion code.
2138 		 */
2139 		inaccessTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT;
2140 		upgradeTimeout  = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT;
2141 	}
2142 	timeoutSec1 = time(NULL);
2143 	do {
2144 		static unsigned char isValidSize = FALSE;
2145 		rsp = intf->sendrecv(intf, &req);
2146 		if (rsp == NULL) {
2147 			#define HPM_LAN_PACKET_RESIZE_LIMIT 6
2148 			/* also covers lanplus */
2149 			if (strstr(intf->name, "lan") != NULL) {
2150 				static int errorCount=0;
2151 				static struct ipmi_rs fakeRsp;
2152 				lprintf(LOG_DEBUG,
2153 						"HPM: no response available");
2154 				lprintf(LOG_DEBUG,
2155 						"HPM: the command may be rejected for security reasons");
2156 				if (req.msg.netfn == IPMI_NETFN_PICMG
2157 						&& req.msg.cmd == HPMFWUPG_UPLOAD_FIRMWARE_BLOCK
2158 						&& errorCount < HPM_LAN_PACKET_RESIZE_LIMIT
2159 						&& (!isValidSize)) {
2160 					lprintf(LOG_DEBUG,
2161 							"HPM: upload firmware block API called");
2162 					lprintf(LOG_DEBUG,
2163 							"HPM: returning length error to force resize");
2164 					fakeRsp.ccode = IPMI_CC_REQ_DATA_INV_LENGTH;
2165 					rsp = &fakeRsp;
2166 					errorCount++;
2167 				} else if (req.msg.netfn == IPMI_NETFN_PICMG
2168 						&& (req.msg.cmd == HPMFWUPG_ACTIVATE_FIRMWARE
2169 							|| req.msg.cmd == HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK)) {
2170 					/*
2171 					 * rsp == NULL and command activate firmware or manual firmware
2172 					 * rollback most likely occurs when we have sent a firmware activation
2173 					 * request. Fake a command in progress response.
2174 					 */
2175 					lprintf(LOG_DEBUG,
2176 							"HPM: activate/rollback firmware API called");
2177 					lprintf(LOG_DEBUG,
2178 							"HPM: returning in progress to handle IOL session lost");
2179 					fakeRsp.ccode = HPMFWUPG_COMMAND_IN_PROGRESS;
2180 					rsp = &fakeRsp;
2181 				} else if (req.msg.netfn == IPMI_NETFN_PICMG
2182 						&& (req.msg.cmd == HPMFWUPG_QUERY_ROLLBACK_STATUS
2183 							|| req.msg.cmd == HPMFWUPG_GET_UPGRADE_STATUS
2184 							|| req.msg.cmd == HPMFWUPG_QUERY_SELFTEST_RESULT)
2185 						&& ( !intf->target_addr || intf->target_addr == intf->my_addr)) {
2186 					/* reopen session only if target IPMC is directly accessed */
2187 					/*
2188 					 * rsp == NULL and command get upgrade status or query rollback
2189 					 * status most likely occurs when we are waiting for firmware
2190 					 * activation. Try to re-open the IOL session (re-open will work
2191 					 * once the IPMC recovers from firmware activation.
2192 					 */
2193 					lprintf(LOG_DEBUG, "HPM: upg/rollback status firmware API called");
2194 					lprintf(LOG_DEBUG, "HPM: try to re-open IOL session");
2195 					{
2196 						/* force session re-open */
2197 						intf->opened = 0;
2198 						intf->session->authtype = IPMI_SESSION_AUTHTYPE_NONE;
2199 						intf->session->session_id = 0;
2200 						intf->session->in_seq = 0;
2201 						intf->session->out_seq = 0;
2202 						intf->session->active = 0;
2203 						intf->session->retry = 10;
2204 						while (intf->open(intf) == HPMFWUPG_ERROR
2205 								&& inaccessTimeoutCounter < inaccessTimeout) {
2206 							inaccessTimeoutCounter += (time(NULL) - timeoutSec1);
2207 							timeoutSec1 = time(NULL);
2208 						}
2209 						/* Fake timeout to retry command */
2210 						fakeRsp.ccode = 0xc3;
2211 						rsp = &fakeRsp;
2212 					}
2213 				}
2214 			}
2215 		}
2216 		/* Handle inaccessibility timeout (rsp = NULL if IOL) */
2217 		if (rsp == NULL || rsp->ccode == 0xff || rsp->ccode == 0xc3 || rsp->ccode == 0xd3) {
2218 			if (inaccessTimeoutCounter < inaccessTimeout) {
2219 				timeoutSec2 = time(NULL);
2220 				if (timeoutSec2 > timeoutSec1) {
2221 					inaccessTimeoutCounter += timeoutSec2 - timeoutSec1;
2222 					timeoutSec1 = time(NULL);
2223 				}
2224 				usleep(100000);
2225 				retry = 1;
2226 			} else {
2227 				retry = 0;
2228 			}
2229 		} else if ( rsp->ccode == 0xc0 ) {
2230 			/* Handle node busy timeout */
2231 			if (upgradeTimeoutCounter < upgradeTimeout) {
2232 				timeoutSec2 = time(NULL);
2233 				if (timeoutSec2 > timeoutSec1) {
2234 					timeoutSec1 = time(NULL);
2235 					upgradeTimeoutCounter += timeoutSec2 - timeoutSec1;
2236 				}
2237 				usleep(100000);
2238 				retry = 1;
2239 			} else {
2240 				retry = 0;
2241 			}
2242 		} else {
2243 # ifdef ENABLE_OPENIPMI_V39_PATCH
2244 			if (rsp->ccode == IPMI_CC_OK) {
2245 				errorCount = 0 ;
2246 			}
2247 # endif
2248 			retry = 0;
2249 			if (req.msg.netfn == IPMI_NETFN_PICMG
2250 					&& req.msg.cmd == HPMFWUPG_UPLOAD_FIRMWARE_BLOCK
2251 					&& (!isValidSize)) {
2252 				lprintf(LOG_INFO,
2253 						"Buffer length is now considered valid");
2254 				isValidSize = TRUE;
2255 			}
2256 		}
2257 	} while (retry);
2258 	return rsp;
2259 }
2260 
2261 int
2262 HpmfwupgWaitLongDurationCmd(struct ipmi_intf *intf,
2263 		struct HpmfwupgUpgradeCtx *pFwupgCtx)
2264 {
2265 	int rc = HPMFWUPG_SUCCESS;
2266 	unsigned int upgradeTimeout = 0;
2267 	unsigned int  timeoutSec1, timeoutSec2;
2268 	struct HpmfwupgGetUpgradeStatusCtx upgStatusCmd;
2269 	/* If we are not in upgrade context, we use default timeout values */
2270 	if (pFwupgCtx != NULL) {
2271 		upgradeTimeout = (unsigned int)(pFwupgCtx->targetCap.upgradeTimeout*5);
2272 		if (verbose) {
2273 			printf("Use File Upgrade Capabilities: %i seconds\n",
2274 					upgradeTimeout);
2275 		}
2276 	} else {
2277 		/* Try to retreive from Caps */
2278 		struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd;
2279 		if(HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd) != HPMFWUPG_SUCCESS) {
2280 			upgradeTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT;
2281 			if (verbose) {
2282 				printf("Use default timeout: %i seconds\n",
2283 						upgradeTimeout);
2284 			}
2285 		} else {
2286 			upgradeTimeout = (unsigned int)(targetCapCmd.resp.upgradeTimeout * 5);
2287 			if (verbose) {
2288 				printf("Use Command Upgrade Capabilities Timeout: %i seconds\n",
2289 						upgradeTimeout);
2290 			}
2291 		}
2292 	}
2293 	if (rc == HPMFWUPG_SUCCESS) {
2294 		/* Poll upgrade status until completion or timeout*/
2295 		timeoutSec1 = time(NULL);
2296 		timeoutSec2 = time(NULL);
2297 		rc = HpmfwupgGetUpgradeStatus(intf, &upgStatusCmd,
2298 				pFwupgCtx, 1);
2299 	}
2300 	while (
2301 			/* With KCS: Cover the case where we sometime
2302 			 * receive d5 (on the first get status) from
2303 			 * the ipmi driver.
2304 			 */
2305 			(upgStatusCmd.resp.lastCmdCompCode == 0x80 ||
2306 					upgStatusCmd.resp.lastCmdCompCode == 0xD5)
2307 			&& ((timeoutSec2 - timeoutSec1) < upgradeTimeout )
2308 			&& (rc == HPMFWUPG_SUCCESS)) {
2309 		/* Must wait at least 1000 ms between status requests */
2310 		usleep(1000000);
2311 		timeoutSec2 = time(NULL);
2312 		rc = HpmfwupgGetUpgradeStatus(intf, &upgStatusCmd, pFwupgCtx, 1);
2313 /*
2314  *		printf("Get Status: %x - %x = %x _ %x [%x]\n",
2315  (				timeoutSec2, timeoutSec1,
2316  *				(timeoutSec2 - timeoutSec1),
2317  *				upgradeTimeout, rc);
2318  */
2319 	}
2320 	if (upgStatusCmd.resp.lastCmdCompCode != 0x00) {
2321 		if (verbose) {
2322 			lprintf(LOG_NOTICE,
2323 					"Error waiting for command %x, compcode = %x",
2324 					upgStatusCmd.resp.cmdInProcess,
2325 					upgStatusCmd.resp.lastCmdCompCode);
2326 		}
2327 		rc = HPMFWUPG_ERROR;
2328 	}
2329 	return rc;
2330 }
2331 
2332 unsigned char
2333 HpmfwupgCalculateChecksum(unsigned char *pData, unsigned int length)
2334 {
2335 	unsigned char checksum = 0;
2336 	int dataIdx = 0;
2337 	for (dataIdx = 0; dataIdx < length; dataIdx++) {
2338 		checksum += pData[dataIdx];
2339 	}
2340 	return checksum;
2341 }
2342 
2343 void
2344 HpmfwupgPrintUsage(void)
2345 {
2346 	lprintf(LOG_NOTICE,
2347 "help                    - This help menu.");
2348 	lprintf(LOG_NOTICE,
2349 "");
2350 	lprintf(LOG_NOTICE,
2351 "check                   - Check the target information.");
2352 	lprintf(LOG_NOTICE,
2353 "check <file>            - If the user is unsure of what update is going to be ");
2354 	lprintf(LOG_NOTICE,
2355 "                          This will display the existing target version and");
2356 	lprintf(LOG_NOTICE,
2357 "                          image version on the screen");
2358 	lprintf(LOG_NOTICE,
2359 "");
2360 	lprintf(LOG_NOTICE,
2361 "upgrade <file> [component x...] [force] [activate]");
2362 	lprintf(LOG_NOTICE,
2363 "                        - Copies components from a valid HPM.1 image to the target.");
2364 	lprintf(LOG_NOTICE,
2365 "                          If one or more components specified by \"component\",");
2366 	lprintf(LOG_NOTICE,
2367 "                          only the specified components are copied.");
2368 	lprintf(LOG_NOTICE,
2369 "                          Otherwise, all the image components are copied.");
2370 	lprintf(LOG_NOTICE,
2371 "                          Before copy, each image component undergoes a version check");
2372 	lprintf(LOG_NOTICE,
2373 "                          and can be skipped if the target component version");
2374 	lprintf(LOG_NOTICE,
2375 "                          is the same or more recent.");
2376 	lprintf(LOG_NOTICE,
2377 "                          Use \"force\" to bypass the version check results.");
2378 	lprintf(LOG_NOTICE,
2379 "                          Make sure to check the versions first using the");
2380 	lprintf(LOG_NOTICE,
2381 "                          \"check <file>\" command.");
2382 	lprintf(LOG_NOTICE,
2383 "                          If \"activate\" is specified, the newly uploaded firmware");
2384 	lprintf(LOG_NOTICE,
2385 "                          is activated.");
2386 	lprintf(LOG_NOTICE,
2387 "upgstatus               - Returns the status of the last long duration command.");
2388 	lprintf(LOG_NOTICE,
2389 "");
2390 	lprintf(LOG_NOTICE,
2391 "compare <file>          - Perform \"Comparison of the Active Copy\" action for all the");
2392 	lprintf(LOG_NOTICE,
2393 "                          components present in the file.");
2394 	lprintf(LOG_NOTICE,
2395 "compare <file> component x - Compare only component <x> from the given <file>");
2396 	lprintf(LOG_NOTICE,
2397 "activate                - Activate the newly uploaded firmware.");
2398 	lprintf(LOG_NOTICE,
2399 "activate norollback     - Activate the newly uploaded firmware but inform");
2400 	lprintf(LOG_NOTICE,
2401 "                          the target to not automatically rollback if ");
2402 	lprintf(LOG_NOTICE,
2403 "                          the upgrade fails.");
2404 	lprintf(LOG_NOTICE,
2405 "");
2406 	lprintf(LOG_NOTICE,
2407 "targetcap               - Get the target upgrade capabilities.");
2408 	lprintf(LOG_NOTICE,
2409 "");
2410 	lprintf(LOG_NOTICE,
2411 "compprop <id> <prop>    - Get specified component properties from the target.");
2412 	lprintf(LOG_NOTICE,
2413 "                          Valid component <id>: 0-7 ");
2414 	lprintf(LOG_NOTICE,
2415 "                          Properties <prop> can be one of the following: ");
2416 	lprintf(LOG_NOTICE,
2417 "                          0- General properties");
2418 	lprintf(LOG_NOTICE,
2419 "                          1- Current firmware version");
2420 	lprintf(LOG_NOTICE,
2421 "                          2- Description string");
2422 	lprintf(LOG_NOTICE,
2423 "                          3- Rollback firmware version");
2424 	lprintf(LOG_NOTICE,
2425 "                          4- Deferred firmware version");
2426 	lprintf(LOG_NOTICE,
2427 "");
2428 	lprintf(LOG_NOTICE,
2429 "abort                   - Abort the on-going firmware upgrade.");
2430 	lprintf(LOG_NOTICE,
2431 "");
2432 	lprintf(LOG_NOTICE,
2433 "rollback                - Performs a manual rollback on the IPM Controller.");
2434 	lprintf(LOG_NOTICE,
2435 "                          firmware");
2436 	lprintf(LOG_NOTICE,
2437 "rollbackstatus          - Query the rollback status.");
2438 	lprintf(LOG_NOTICE,
2439 "");
2440 	lprintf(LOG_NOTICE,
2441 "selftestresult          - Query the self test results.\n");
2442 }
2443 
2444 int
2445 ipmi_hpmfwupg_main(struct ipmi_intf *intf, int argc, char **argv)
2446 {
2447 	int rc = HPMFWUPG_SUCCESS;
2448 	int activateFlag = 0x00;
2449 	int componentMask = 0;
2450 	int componentId = 0;
2451 	int option = 0;
2452 
2453 	lprintf(LOG_DEBUG,"ipmi_hpmfwupg_main()");
2454 	lprintf(LOG_NOTICE, "\nPICMG HPM.1 Upgrade Agent %d.%d.%d: \n",
2455 			HPMFWUPG_VERSION_MAJOR, HPMFWUPG_VERSION_MINOR,
2456 			HPMFWUPG_VERSION_SUBMINOR);
2457 	if (argc < 1) {
2458 		lprintf(LOG_ERR, "Not enough parameters given.");
2459 		HpmfwupgPrintUsage();
2460 		return HPMFWUPG_ERROR;
2461 	}
2462 	if (strcmp(argv[0], "help") == 0) {
2463 		HpmfwupgPrintUsage();
2464 		return HPMFWUPG_SUCCESS;
2465 	} else if ((strcmp(argv[0], "check") == 0)) {
2466 		/* hpm check */
2467 		if (argv[1] == NULL) {
2468 			rc = HpmfwupgTargetCheck(intf,VIEW_MODE);
2469 		} else {
2470 			/* hpm check <filename> */
2471 			rc = HpmfwupgTargetCheck(intf,0);
2472 			if (rc == HPMFWUPG_SUCCESS) {
2473 				rc = HpmfwupgUpgrade(intf, argv[1], 0,
2474 						0, VIEW_MODE);
2475 			}
2476 		}
2477 	} else if (strcmp(argv[0], "upgrade") == 0) {
2478 		int i =0;
2479 		for (i=1; i< argc ; i++) {
2480 			if (strcmp(argv[i],"activate") == 0) {
2481 				activateFlag = 1;
2482 			}
2483 			/* hpm upgrade <filename> force */
2484 			if (strcmp(argv[i],"force") == 0) {
2485 				option |= FORCE_MODE;
2486 			}
2487 			/* hpm upgrade <filename> component <comp Id> */
2488 			if (strcmp(argv[i],"component") == 0) {
2489 				if (i+1 < argc) {
2490 					/* Error Checking */
2491 					if (str2int(argv[i+1], &componentId) != 0
2492 							|| componentId < 0
2493 							|| componentId > HPMFWUPG_COMPONENT_ID_MAX) {
2494 						lprintf(LOG_ERR,
2495 								"Given Component ID '%s' is invalid.",
2496 								argv[i+1]);
2497 						lprintf(LOG_ERR,
2498 								"Valid Compoment ID is: <0..7>");
2499 						return HPMFWUPG_ERROR;
2500 					}
2501 					if( verbose ) {
2502 						lprintf(LOG_NOTICE,
2503 								"Component Id %d provided",
2504 								componentId );
2505 					}
2506 					componentMask |= 1 << componentId;
2507 				} else {
2508 					/* That indicates the user has
2509 					 * given component on console but
2510 					 * not given any ID
2511 					 */
2512 					lprintf(LOG_NOTICE,
2513 							"No component Id provided\n");
2514 					return  HPMFWUPG_ERROR;
2515 				}
2516 			}
2517 			if (strcmp(argv[i],"debug") == 0) {
2518 				option |= DEBUG_MODE;
2519 			}
2520 		}
2521 		rc = HpmfwupgTargetCheck(intf, 0);
2522 		if (rc == HPMFWUPG_SUCCESS) {
2523 			/* Call the Upgrade function to start the upgrade */
2524 			rc = HpmfwupgUpgrade(intf, argv[1], activateFlag,
2525 					componentMask, option);
2526 		}
2527 	} else if (strcmp(argv[0], "compare") == 0) {
2528 		int i = 0;
2529 		for (i=1; i< argc; i++) {
2530 			/* hpm compare <file> [component x...] */
2531 			if (strcmp(argv[i],"component") == 0) {
2532 				if (i+1 < argc) {
2533 					/* Error Checking */
2534 					if (str2int(argv[i+1], &componentId) != 0
2535 							|| componentId < 0
2536 							|| componentId > HPMFWUPG_COMPONENT_ID_MAX) {
2537 						lprintf(LOG_ERR,
2538 								"Given Component ID '%s' is invalid.",
2539 								argv[i+1]);
2540 						lprintf(LOG_ERR,
2541 								"Valid Compoment ID is: <0..7>");
2542 						return HPMFWUPG_ERROR;
2543 					}
2544 					if( verbose ) {
2545 						lprintf(LOG_NOTICE,
2546 								"Component Id %d provided",
2547 								componentId);
2548 					}
2549 					componentMask|= 1 << componentId;
2550 				} else {
2551 					/* That indicates the user
2552 					 * has given component on
2553 					 * console but not
2554 					 * given any ID
2555 					 */
2556 					lprintf(LOG_NOTICE,
2557 							"No component Id provided\n");
2558 					return  HPMFWUPG_ERROR;
2559 				}
2560 			} else if (strcmp(argv[i],"debug") == 0) {
2561 				option|= DEBUG_MODE;
2562 			}
2563 		}
2564 		option|= (COMPARE_MODE);
2565 		rc = HpmfwupgTargetCheck(intf, 0);
2566 		if (rc == HPMFWUPG_SUCCESS) {
2567 			rc = HpmfwupgUpgrade(intf, argv[1], 0,
2568 					componentMask, option);
2569 		}
2570 	} else if ((argc >= 1) && (strcmp(argv[0], "activate") == 0)) {
2571 		struct HpmfwupgActivateFirmwareCtx cmdCtx;
2572 		if ((argc == 2) && (strcmp(argv[1], "norollback") == 0)) {
2573 			cmdCtx.req.rollback_override = 1;
2574 		} else {
2575 			cmdCtx.req.rollback_override = 0;
2576 		}
2577 		rc = HpmfwupgActivateFirmware(intf, &cmdCtx, NULL);
2578 	} else if ((argc == 1) && (strcmp(argv[0], "targetcap") == 0)) {
2579 		struct HpmfwupgGetTargetUpgCapabilitiesCtx cmdCtx;
2580 		verbose++;
2581 		rc = HpmfwupgGetTargetUpgCapabilities(intf, &cmdCtx);
2582 	} else if ((argc == 3) && (strcmp(argv[0], "compprop") == 0)) {
2583 		struct HpmfwupgGetComponentPropertiesCtx cmdCtx;
2584 		if (str2uchar(argv[1], &(cmdCtx.req.componentId)) != 0
2585 				|| cmdCtx.req.componentId > 7) {
2586 			lprintf(LOG_ERR,
2587 					"Given Component ID '%s' is invalid.",
2588 					argv[1]);
2589 			lprintf(LOG_ERR,
2590 					"Valid Compoment ID is: <0..7>");
2591 			return (-1);
2592 		}
2593 		if (str2uchar(argv[2], &(cmdCtx.req.selector)) != 0
2594 				|| cmdCtx.req.selector > 4) {
2595 			lprintf(LOG_ERR,
2596 					"Given Properties selector '%s' is invalid.",
2597 					argv[2]);
2598 			lprintf(LOG_ERR,
2599 					"Valid Properties selector is: <0..4>");
2600 			return (-1);
2601 		}
2602 		verbose++;
2603 		rc = HpmfwupgGetComponentProperties(intf, &cmdCtx);
2604 	} else if ((argc == 1) && (strcmp(argv[0], "abort") == 0)) {
2605 		struct HpmfwupgAbortUpgradeCtx cmdCtx;
2606 		verbose++;
2607 		rc = HpmfwupgAbortUpgrade(intf, &cmdCtx);
2608 	} else if ((argc == 1) && (strcmp(argv[0], "upgstatus") == 0)) {
2609 		struct HpmfwupgGetUpgradeStatusCtx cmdCtx;
2610 		verbose++;
2611 		rc = HpmfwupgGetUpgradeStatus(intf, &cmdCtx, NULL, 0);
2612 	} else if ((argc == 1) && (strcmp(argv[0], "rollback") == 0)) {
2613 		struct HpmfwupgManualFirmwareRollbackCtx cmdCtx;
2614 		verbose++;
2615 		rc = HpmfwupgManualFirmwareRollback(intf, &cmdCtx);
2616 	} else if ((argc == 1) && (strcmp(argv[0], "rollbackstatus") == 0)) {
2617 		struct HpmfwupgQueryRollbackStatusCtx  cmdCtx;
2618 		verbose++;
2619 		rc = HpmfwupgQueryRollbackStatus(intf, &cmdCtx, NULL);
2620 	} else if ((argc == 1) && (strcmp(argv[0], "selftestresult") == 0)) {
2621 		struct HpmfwupgQuerySelftestResultCtx cmdCtx;
2622 		verbose++;
2623 		rc = HpmfwupgQuerySelftestResult(intf, &cmdCtx, NULL);
2624 	} else {
2625 		lprintf(LOG_ERR, "Invalid HPM command: %s", argv[0]);
2626 		HpmfwupgPrintUsage();
2627 		rc = HPMFWUPG_ERROR;
2628 	}
2629 	return rc;
2630 }
2631 
2632