xref: /openbmc/ipmitool/lib/ipmi_ime.c (revision 531569ec)
1 /*
2  * Copyright (c) 2007 Kontron Canada, Inc.  All Rights Reserved.
3  *
4  * Base on code from
5  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * Redistribution of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * Redistribution in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  *
18  * Neither the name of Sun Microsystems, Inc. or the names of
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * This software is provided "AS IS," without a warranty of any kind.
23  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
24  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
25  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
26  * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
27  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
28  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
29  * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
30  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
31  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
32  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
33  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34  */
35 
36 /****************************************************************************
37 *
38 *       Copyright (c) 2009 Kontron Canada, Inc.  All Rights Reserved.
39 *
40 *                              IME
41 *                    Intel Manageability Engine
42 *                      Firmware Update Agent
43 *
44 * The ME is an IPMI-enabled component included in Intel(R) Next Generation
45 *  Server Chipset Nehalem-EP platforms.
46 *
47 * These are a few synonyms for the ME :
48 *
49 * - Dynamic Power Node Manager
50 * - Intelligent Power Node Manager
51 *
52 * Consult Intel litterature for more information on this technology.
53 *
54 * The ME firmware resides on the platform boot flash and contains read only
55 * boot code for the ME as well as boot image redundancy support.
56 *
57 * This module implements an Upgrade Agent for the ME firwmare. Because the ME
58 * implements IPMI command handling, the agent speaks directly to the ME. In other
59 * words, in order the reach the ME, the BMC must implement IPMB bridging.
60 *
61 * The update is done through IPMI (this is IPMITOOL right !), not HECI.
62 *
63 * Example: ME available at address 0x88 on IPMI channel 8:
64 *   ipmitool  -m 0x20 -t 0x88 -b 8 ime info
65 *
66 * !! WARNING - You MUST use an image provided by your board vendor. - WARNING !!
67 *
68 * author:
69 *  Jean-Michel.Audet@ca.kontron.com
70 *  Francois.Isabelle@ca.kontron.com
71 *
72 *****************************************************************************/
73 /*
74  * HISTORY
75  * ===========================================================================
76  * 2009-04-20
77  *
78  * First public release of Kontron
79  *
80 */
81 #include <ipmitool/ipmi_ime.h>
82 #include <ipmitool/log.h>
83 #include <ipmitool/ipmi_intf.h>
84 #include <ipmitool/ipmi_mc.h>
85 #include <ipmitool/helper.h>
86 #include <ipmitool/ipmi_strings.h>
87 
88 
89 #undef OUTPUT_DEBUG
90 
91 #include <stdlib.h>
92 #include <string.h>
93 #include <errno.h>
94 #include <time.h>
95 
96 static const int IME_SUCCESS              = 0;
97 static const int IME_ERROR                = -1;
98 static const int IME_RESTART              = -2;
99 
100 #define IME_UPGRADE_BUFFER_SIZE           22
101 #define IME_RETRY_COUNT                   5
102 
103 typedef struct ImeUpdateImageCtx
104 {
105    uint32_t   size;
106    uint8_t *  pData;
107    uint8_t    crc8;
108 }tImeUpdateImageCtx;
109 
110 typedef enum eImeState
111 {
112    IME_STATE_IDLE                = 0,
113    IME_STATE_UPDATE_REQUESTED    = 1,
114    IME_STATE_UPDATE_IN_PROGRESS  = 2,
115    IME_STATE_SUCCESS             = 3,
116    IME_STATE_FAILED              = 4,
117    IME_STATE_ROLLED_BACK         = 5,
118    IME_STATE_ABORTED             = 6,
119    IME_STATE_INIT_FAILED         = 7
120 } tImeStateEnum;
121 
122 
123 typedef enum tImeUpdateType
124 {
125    IME_UPDTYPE_NORMAL            = 1,
126    IME_UPDTYPE_MANUAL_ROLLBACK   = 3,
127    IME_UPDTYPE_ABORT             = 4
128 } tImeUpdateType;
129 
130 
131 #ifdef HAVE_PRAGMA_PACK
132 #pragma pack(1)
133 #endif
134 typedef struct sImeStatus {
135    uint8_t image_status;
136    tImeStateEnum update_state;
137    uint8_t update_attempt_status;
138    uint8_t rollback_attempt_status;
139    uint8_t update_type;
140    uint8_t dependent_flag;
141    uint8_t free_area_size[4];
142 } ATTRIBUTE_PACKING tImeStatus ;
143 #ifdef HAVE_PRAGMA_PACK
144 #pragma pack(0)
145 #endif
146 
147 #ifdef HAVE_PRAGMA_PACK
148 #pragma pack(1)
149 #endif
150 typedef struct sImeCaps {
151    uint8_t area_supported;
152    uint8_t special_caps;
153 } ATTRIBUTE_PACKING tImeCaps ;
154 #ifdef HAVE_PRAGMA_PACK
155 #pragma pack(0)
156 #endif
157 
158 
159 static void ImePrintUsage(void);
160 static int  ImeGetInfo(struct ipmi_intf *intf);
161 static int  ImeUpgrade(struct ipmi_intf *intf, char* imageFilename);
162 static int  ImeManualRollback(struct ipmi_intf *intf);
163 static int  ImeUpdatePrepare(struct ipmi_intf *intf);
164 static int  ImeUpdateOpenArea(struct ipmi_intf *intf);
165 static int  ImeUpdateWriteArea(
166                               struct ipmi_intf *intf,
167                               uint8_t sequence,
168                               uint8_t length,
169                               uint8_t * pBuf
170                           );
171 static int  ImeUpdateCloseArea(
172                               struct ipmi_intf *intf,
173                               uint32_t size,
174                               uint16_t checksum
175                           );
176 
177 static int ImeUpdateGetStatus(struct ipmi_intf *intf, tImeStatus *pStatus);
178 static int ImeUpdateGetCapabilities(struct ipmi_intf *intf, tImeCaps *pCaps );
179 static int  ImeUpdateRegisterUpdate(struct ipmi_intf *intf, tImeUpdateType type);
180 
181 static int  ImeImageCtxFromFile(
182                                  char * imageFilename,
183                                  tImeUpdateImageCtx * pImageCtx);
184 static int ImeUpdateShowStatus(struct ipmi_intf *intf);
185 
186 static uint8_t ImeCrc8( uint32_t length, uint8_t * pBuf );
187 
188 
189 static int ImeGetInfo(struct ipmi_intf *intf)
190 {
191    int rc = IME_ERROR;
192    struct ipmi_rs * rsp;
193    struct ipmi_rq req;
194    struct ipm_devid_rsp *devid;
195    const char *product=NULL;
196    tImeStatus status;
197    tImeCaps caps;
198 
199    memset(&req, 0, sizeof(req));
200    req.msg.netfn = IPMI_NETFN_APP;
201    req.msg.cmd = BMC_GET_DEVICE_ID;
202    req.msg.data_len = 0;
203 
204    rsp = intf->sendrecv(intf, &req);
205    if (rsp == NULL) {
206       lprintf(LOG_ERR, "Get Device ID command failed");
207       return IME_ERROR;
208    }
209    if (rsp->ccode > 0) {
210       lprintf(LOG_ERR, "Get Device ID command failed: %s",
211          val2str(rsp->ccode, completion_code_vals));
212       return IME_ERROR;
213    }
214 
215    devid = (struct ipm_devid_rsp *) rsp->data;
216 
217    lprintf(LOG_DEBUG,"Device ID                 : %i", devid->device_id);
218    lprintf(LOG_DEBUG,"Device Revision           : %i",
219                            devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK);
220 
221    if(
222       (devid->device_id == 0)
223       &&
224       ((devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK) == 0)
225       &&
226       (
227          (devid->manufacturer_id[0] == 0x57) // Intel
228          &&
229          (devid->manufacturer_id[1] == 0x01) // Intel
230          &&
231          (devid->manufacturer_id[2] == 0x00) // Intel
232       )
233       &&
234       (
235          (devid->product_id[1] == 0x0b)
236          &&
237          (devid->product_id[0] == 0x00)
238       )
239      )
240    {
241       rc = IME_SUCCESS;
242       printf("Manufacturer Name          : %s\n",
243                val2str( (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id),
244                ipmi_oem_info) );
245 
246       printf("Product ID                 : %u (0x%02x%02x)\n",
247          buf2short((uint8_t *)(devid->product_id)),
248          devid->product_id[1], devid->product_id[0]);
249 
250       product=oemval2str(IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id),
251                       (devid->product_id[1]<<8)+devid->product_id[0],
252                       ipmi_oem_product_info);
253 
254       if (product!=NULL)
255       {
256          printf("Product Name               : %s\n", product);
257       }
258 
259       printf("Intel ME Firmware Revision : %x.%02x.%02x.%x%x%x.%x\n",
260             ((devid->fw_rev1 & IPM_DEV_FWREV1_MAJOR_MASK )         ),
261             ((devid->fw_rev2                             ) >>     4),
262             ((devid->fw_rev2                             )  &  0x0f),
263             ((devid->aux_fw_rev[1]                       ) >>     4),
264             ((devid->aux_fw_rev[1]                       )  &  0x0f),
265             ((devid->aux_fw_rev[2]                       ) >>     4),
266             ((devid->aux_fw_rev[2]                       )  &  0x0f)
267       );
268 
269       printf("SPS FW IPMI cmd version    : %x.%x\n",
270          devid->aux_fw_rev[0] >>     4,
271          devid->aux_fw_rev[0] &  0x0f);
272 
273       lprintf(LOG_DEBUG,"Flags: %xh", devid->aux_fw_rev[3]);
274 
275       printf("Current Image Type         : ");
276       switch( (devid->aux_fw_rev[3] & 0x03) )
277       {
278          case 0:
279             printf("Recovery\n");
280          break;
281 
282          case 1:
283             printf("Operational Image 1\n");
284          break;
285 
286          case 2:
287             printf("Operational Image 2\n");
288          break;
289 
290          case 3:
291          default:
292             printf("Unknown\n");
293          break;
294       }
295    }
296    else
297    {
298          printf("Supported ME not found\n");
299    }
300 
301    if(rc == IME_SUCCESS)
302    {
303       rc = ImeUpdateGetStatus(intf, &status);
304 
305       if(rc == IME_SUCCESS)
306       {
307          rc = ImeUpdateGetCapabilities(intf, &caps);
308       }
309 
310    }
311 
312    if(rc == IME_SUCCESS)
313    {
314       uint8_t newImage  = ((status.image_status >> 1) & 0x01);
315       uint8_t rollImage = ((status.image_status >> 2) & 0x01);
316       uint8_t runArea   = ((status.image_status >> 3) & 0x03);
317       uint8_t rollSup   = ((caps.special_caps   >> 0) & 0x01);
318       uint8_t recovSup  = ((caps.special_caps   >> 1) & 0x01);
319 
320       uint8_t operSup   = ((caps.area_supported   >> 1) & 0x01);
321       uint8_t piaSup    = ((caps.area_supported   >> 2) & 0x01);
322       uint8_t sdrSup    = ((caps.area_supported   >> 3) & 0x01);
323 
324       printf("\nSupported Area\n");
325       printf("   Operation Code          : %s\n", (operSup ? "Supported" : "Unsupported"));
326       printf("   PIA                     : %s\n", (piaSup ? "Supported" : "Unsupported"));
327       printf("   SDR                     : %s\n", (sdrSup ? "Supported" : "Unsupported"));
328 
329       printf("\nSpecial Capabilities\n");
330       printf("   Rollback                : %s\n", (rollSup ? "Supported" : "Unsupported"));
331       printf("   Recovery                : %s\n", (recovSup ? "Supported" : "Unsupported"));
332 
333       printf("\nImage Status\n");
334       printf("   Staging (new)           : %s\n", (newImage ? "Valid" : "Invalid"));
335       printf("   Rollback                : %s\n", (rollImage ? "Valid" : "Invalid"));
336       if(runArea == 0)
337          printf("   Running Image Area      : CODE\n");
338       else
339          printf("   Running Image Area      : CODE%d\n", runArea);
340 
341   }
342 
343    return rc;
344 }
345 
346 
347 static int ImeUpgrade(struct ipmi_intf *intf, char* imageFilename)
348 {
349    int rc = IME_SUCCESS;
350    tImeUpdateImageCtx imgCtx;
351    tImeStatus imeStatus;
352    time_t start,end,current;
353 
354    time(&start);
355 
356    memset(&imgCtx, 0, sizeof(tImeUpdateImageCtx));
357 
358    rc = ImeImageCtxFromFile(imageFilename, &imgCtx);
359 
360    if(
361       (rc == IME_ERROR) ||
362       (imgCtx.pData == NULL) ||
363       (imgCtx.size == 0)
364      )
365    {
366       return IME_ERROR;
367    }
368 
369    ImeUpdateGetStatus(intf,&imeStatus);
370 
371    if(rc == IME_SUCCESS)
372    {
373       rc = ImeUpdatePrepare(intf);
374       ImeUpdateGetStatus(intf,&imeStatus);
375    }
376 
377    if(
378       (rc == IME_SUCCESS) &&
379       (imeStatus.update_state == IME_STATE_UPDATE_REQUESTED)
380      )
381    {
382       rc = ImeUpdateOpenArea(intf);
383       ImeUpdateGetStatus(intf,&imeStatus);
384    }
385    else if(rc == IME_SUCCESS)
386    {
387       lprintf(LOG_ERROR,"ME state error (%i), aborting", imeStatus.update_state);
388       rc = IME_ERROR;
389    }
390 
391 
392    if(
393       (rc == IME_SUCCESS) &&
394       (imeStatus.update_state == IME_STATE_UPDATE_IN_PROGRESS)
395      )
396    {
397       uint8_t sequence = 0;
398       uint32_t counter = 0;
399       uint8_t retry = 0;
400       uint8_t shownPercent = 0xff;
401 
402       while(
403             (counter < imgCtx.size) &&
404             (rc == IME_SUCCESS) &&
405             (retry < IME_RETRY_COUNT)
406            )
407       {
408          uint8_t length = IME_UPGRADE_BUFFER_SIZE;
409          uint8_t currentPercent;
410 
411          if( (imgCtx.size - counter) < IME_UPGRADE_BUFFER_SIZE )
412          {
413             length = (imgCtx.size - counter);
414          }
415 
416          rc = ImeUpdateWriteArea(intf,sequence,length,&imgCtx.pData[counter]);
417 
418          /*
419          As per the flowchart Intel Dynamic Power Node Manager 1.5 IPMI Iface
420          page 65
421          We shall send the GetStatus command each time following a write area
422          but this add too much time to the upgrade
423          */
424          /*  ImeUpdateGetStatus(intf,&imeStatus); */
425          counter += length;
426          sequence ++;
427 
428 
429          currentPercent = ((float)counter/imgCtx.size)*100;
430 
431          if(currentPercent != shownPercent)
432          {
433             uint16_t timeElapsedSecond;
434             shownPercent = currentPercent;
435             printf("Percent: %02i,  ", shownPercent);
436             time(&current);
437             timeElapsedSecond = (current-start) + ((current-start)%60);
438             printf("Elapsed time %02ld:%02ld\r",((current-start)/60), ((current-start)%60));
439             fflush(stdout);
440 
441          }
442       }
443       ImeUpdateGetStatus(intf,&imeStatus);
444       printf("\n");
445    }
446    else if(rc == IME_SUCCESS)
447    {
448       lprintf(LOG_ERROR,"ME state error (%i), aborting", imeStatus.update_state);
449       rc = IME_ERROR;
450    }
451 
452    if(
453       (rc == IME_SUCCESS) &&
454       (imeStatus.update_state == IME_STATE_UPDATE_IN_PROGRESS)
455      )
456    {
457       rc = ImeUpdateCloseArea(intf, imgCtx.size, imgCtx.crc8);
458       ImeUpdateGetStatus(intf,&imeStatus);
459    }
460    else if(rc == IME_SUCCESS)
461    {
462       lprintf(LOG_ERROR,"ME state error, aborting");
463       rc = IME_ERROR;
464    }
465 
466    if(
467       (rc == IME_SUCCESS) &&
468       (imeStatus.update_state == IME_STATE_UPDATE_REQUESTED)
469      )
470    {
471       printf("UpdateCompleted, Activate now\n");
472       rc = ImeUpdateRegisterUpdate(intf, IME_UPDTYPE_NORMAL);
473       ImeUpdateGetStatus(intf,&imeStatus);
474    }
475    else if(rc == IME_SUCCESS)
476    {
477       lprintf(LOG_ERROR,"ME state error, aborting");
478       rc = IME_ERROR;
479    }
480 
481    if(
482       (rc == IME_SUCCESS) &&
483       (imeStatus.update_state == IME_STATE_SUCCESS)
484      )
485    {
486       time(&end);
487       printf("Update Completed in %02ld:%02ld\n",(end-start)/60, (end-start)%60);
488    }
489    else
490    {
491       time(&end);
492       printf("Update Error\n");
493       printf("\nTime Taken %02ld:%02ld\n",(end-start)/60, (end-start)%60);
494    }
495 
496    return rc;
497 }
498 
499 
500 static int ImeUpdatePrepare(struct ipmi_intf *intf)
501 {
502    struct ipmi_rs * rsp;
503    struct ipmi_rq req;
504 
505    #ifdef OUTPUT_DEBUG
506    printf("ImeUpdatePrepare\n");
507    #endif
508 
509    memset(&req, 0, sizeof(req));
510    req.msg.netfn = 0x30;  // OEM NetFn
511    req.msg.cmd = 0xA0;
512    req.msg.data_len = 0;
513 
514    rsp = intf->sendrecv(intf, &req);
515    if (rsp == NULL) {
516       lprintf(LOG_ERR, "UpdatePrepare command failed");
517       return IME_ERROR;
518    }
519    if (rsp->ccode > 0) {
520       lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
521          val2str(rsp->ccode, completion_code_vals));
522       return IME_ERROR;
523    }
524 
525    lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
526    return IME_SUCCESS;
527 }
528 
529 static int ImeUpdateOpenArea(struct ipmi_intf *intf)
530 {
531    struct ipmi_rs * rsp;
532    struct ipmi_rq req;
533    uint8_t buffer[ 2 ];
534 
535    #ifdef OUTPUT_DEBUG
536    printf("ImeUpdateOpenArea\n");
537    #endif
538 
539    memset(&req, 0, sizeof(req));
540    req.msg.netfn = 0x30;  // OEM NetFn
541    req.msg.cmd = 0xA1;
542 
543    buffer[0] = 0x01; // Area Type : Operational code
544    buffer[1] = 0x00; // Reserved : 0
545    req.msg.data = buffer;
546 
547    req.msg.data_len = 2;
548 
549    rsp = intf->sendrecv(intf, &req);
550    if (rsp == NULL) {
551       lprintf(LOG_ERR, "UpdateOpenArea command failed");
552       return IME_ERROR;
553    }
554    if (rsp->ccode > 0) {
555       lprintf(LOG_ERR, "UpdateOpenArea command failed: %s",
556          val2str(rsp->ccode, completion_code_vals));
557       return IME_ERROR;
558    }
559 
560    lprintf(LOG_DEBUG, "UpdateOpenArea command succeed");
561    return IME_SUCCESS;
562 }
563 
564 static int ImeUpdateWriteArea(
565                               struct ipmi_intf *intf,
566                               uint8_t sequence,
567                               uint8_t length,
568                               uint8_t * pBuf
569                           )
570 {
571    struct ipmi_rs * rsp;
572    struct ipmi_rq req;
573    uint8_t buffer[ IME_UPGRADE_BUFFER_SIZE + 1 ];
574 
575 //   printf("ImeUpdateWriteArea %i\n", sequence);
576 
577    if(length > IME_UPGRADE_BUFFER_SIZE)
578       return IME_ERROR;
579 
580    buffer[0] = sequence;
581    memcpy(&buffer[1], pBuf, length);
582 
583    memset(&req, 0, sizeof(req));
584    req.msg.netfn = 0x30;  // OEM NetFn
585    req.msg.cmd = 0xA2;
586    req.msg.data = buffer;
587    req.msg.data_len = length + 1;
588 
589    rsp = intf->sendrecv(intf, &req);
590    if (rsp == NULL) {
591       lprintf(LOG_ERR, "UpdateWriteArea command failed");
592       return IME_ERROR;
593    }
594    if (rsp->ccode > 0) {
595       lprintf(LOG_ERR, "UpdateWriteArea command failed: %s",
596          val2str(rsp->ccode, completion_code_vals));
597       if( rsp->ccode == 0x80) // restart operation
598          return IME_RESTART;
599       else
600          return IME_ERROR;
601    }
602 
603    lprintf(LOG_DEBUG, "UpdateWriteArea command succeed");
604    return IME_SUCCESS;
605 }
606 
607 static int ImeUpdateCloseArea(
608                               struct ipmi_intf *intf,
609                               uint32_t size,
610                               uint16_t checksum
611                           )
612 {
613    struct ipmi_rs * rsp;
614    struct ipmi_rq req;
615    uint8_t length = sizeof( uint32_t ) + sizeof( uint16_t );
616    uint8_t buffer[ sizeof( uint32_t ) + sizeof( uint16_t ) ];
617 
618    #ifdef OUTPUT_DEBUG
619    printf( "ImeUpdateCloseArea\n");
620    #endif
621 
622    buffer[0] = (uint8_t)((size & 0x000000ff) >>  0);
623    buffer[1] = (uint8_t)((size & 0x0000ff00) >>  8);
624    buffer[2] = (uint8_t)((size & 0x00ff0000) >> 16);
625    buffer[3] = (uint8_t)((size & 0xff000000) >> 24);
626 
627    buffer[4] = (uint8_t)((checksum & 0x00ff) >>  0);
628    buffer[5] = (uint8_t)((checksum & 0xff00) >>  8);
629 
630    memset(&req, 0, sizeof(req));
631    req.msg.netfn = 0x30;  // OEM NetFn
632    req.msg.cmd = 0xA3;
633    req.msg.data = buffer;
634    req.msg.data_len = length;
635 
636    rsp = intf->sendrecv(intf, &req);
637    if (rsp == NULL) {
638       lprintf(LOG_ERR, "UpdateCloseArea command failed");
639       return IME_ERROR;
640    }
641    if (rsp->ccode > 0) {
642       lprintf(LOG_ERR, "UpdateCloseArea command failed: %s",
643          val2str(rsp->ccode, completion_code_vals));
644       return IME_ERROR;
645    }
646 
647    lprintf(LOG_DEBUG, "UpdateCloseArea command succeed");
648    return IME_SUCCESS;
649 }
650 
651 static int ImeUpdateGetStatus(struct ipmi_intf *intf, tImeStatus *pStatus )
652 {
653    struct      ipmi_rs * rsp;
654    struct      ipmi_rq req;
655    tImeStatus *pGetStatus;
656 
657    memset(pStatus, 0, sizeof(tImeStatus));
658    pStatus->update_state = IME_STATE_ABORTED;
659 
660 
661    #ifdef OUTPUT_DEBUG
662    printf("ImeUpdateGetStatus: ");
663    #endif
664 
665    memset(&req, 0, sizeof(req));
666    req.msg.netfn = 0x30;  // OEM NetFn
667    req.msg.cmd = 0xA6;
668    req.msg.data_len = 0;
669 
670    rsp = intf->sendrecv(intf, &req);
671    if (rsp == NULL) {
672       lprintf(LOG_ERR, "UpdatePrepare command failed");
673       return IME_ERROR;
674    }
675    if (rsp->ccode > 0) {
676       lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
677          val2str(rsp->ccode, completion_code_vals));
678       return IME_ERROR;
679    }
680 
681    lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
682 
683    pGetStatus = (tImeStatus *) rsp->data;
684 
685    memcpy( pStatus, pGetStatus, sizeof(tImeStatus));
686 
687    #ifdef OUTPUT_DEBUG
688    printf("%x - ", pStatus->updateState);
689 
690    switch( pStatus->update_state )
691    {
692       case IME_STATE_IDLE:
693          printf("IDLE\n");
694       break;
695       case IME_STATE_UPDATE_REQUESTED:
696          printf("Update Requested\n");
697       break;
698       case IME_STATE_UPDATE_IN_PROGRESS:
699          printf("Update in Progress\n");
700       break;
701       case IME_STATE_SUCCESS:
702          printf("Update Success\n");
703       break;
704       case IME_STATE_FAILED:
705          printf("Update Failed\n");
706       break;
707       case IME_STATE_ROLLED_BACK:
708          printf("Update Rolled Back\n");
709       break;
710       case IME_STATE_ABORTED:
711          printf("Update Aborted\n");
712       break;
713       case IME_STATE_INIT_FAILED:
714          printf("Update Init Failed\n");
715       break;
716       default:
717          printf("Unknown, reserved\n");
718       break;
719    }
720    #endif
721 
722    return IME_SUCCESS;
723 }
724 
725 static int ImeUpdateGetCapabilities(struct ipmi_intf *intf, tImeCaps *pCaps )
726 {
727    struct      ipmi_rs * rsp;
728    struct      ipmi_rq req;
729    tImeCaps *  pGetCaps;
730 
731    memset(pCaps, 0, sizeof(tImeCaps));
732 
733 
734    #ifdef OUTPUT_DEBUG
735    printf("ImeUpdateGetStatus: ");
736    #endif
737 
738    memset(&req, 0, sizeof(req));
739    req.msg.netfn = 0x30;  // OEM NetFn
740    req.msg.cmd = 0xA7;
741    req.msg.data_len = 0;
742 
743    rsp = intf->sendrecv(intf, &req);
744    if (rsp == NULL) {
745       lprintf(LOG_ERR, "UpdatePrepare command failed");
746       return IME_ERROR;
747    }
748    if (rsp->ccode > 0) {
749       lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
750          val2str(rsp->ccode, completion_code_vals));
751       return IME_ERROR;
752    }
753 
754    lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
755 
756    pGetCaps = (tImeCaps *) rsp->data;
757 
758    memcpy( pCaps, pGetCaps, sizeof(tImeCaps));
759 
760    return IME_SUCCESS;
761 }
762 
763 
764 static int ImeUpdateRegisterUpdate(struct ipmi_intf *intf, tImeUpdateType type)
765 {
766    struct ipmi_rs * rsp;
767    struct ipmi_rq req;
768    uint8_t buffer[ 2 ];
769 
770    #ifdef OUTPUT_DEBUG
771    printf( "ImeUpdateRegisterUpdate\n");
772    #endif
773 
774    buffer[0] = type;  // Normal Update
775    buffer[1] = 0;  // Flags, reserved
776 
777    memset(&req, 0, sizeof(req));
778    req.msg.netfn = 0x30;  // OEM NetFn
779    req.msg.cmd = 0xA4;
780    req.msg.data = buffer;
781    req.msg.data_len = 2;
782 
783    rsp = intf->sendrecv(intf, &req);
784    if (rsp == NULL) {
785       lprintf(LOG_ERR, "ImeUpdateRegisterUpdate command failed");
786       return IME_ERROR;
787    }
788    if (rsp->ccode > 0) {
789       lprintf(LOG_ERR, "ImeUpdateRegisterUpdate command failed: %s",
790          val2str(rsp->ccode, completion_code_vals));
791       return IME_ERROR;
792    }
793 
794    lprintf(LOG_DEBUG, "ImeUpdateRegisterUpdate command succeed");
795    return IME_SUCCESS;
796 }
797 
798 
799 
800 
801 static int ImeUpdateShowStatus(struct ipmi_intf *intf)
802 {
803    struct ipmi_rs * rsp;
804    struct ipmi_rq req;
805    tImeStatus *pStatus;
806 
807    printf("ImeUpdateGetStatus: ");
808 
809    memset(&req, 0, sizeof(req));
810    req.msg.netfn = 0x30;  // OEM NetFn
811    req.msg.cmd = 0xA6;
812    req.msg.data_len = 0;
813 
814    rsp = intf->sendrecv(intf, &req);
815    if (rsp == NULL) {
816       lprintf(LOG_ERR, "UpdatePrepare command failed");
817       return IME_ERROR;
818    }
819    if (rsp->ccode > 0) {
820       lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
821          val2str(rsp->ccode, completion_code_vals));
822       return IME_ERROR;
823    }
824 
825    lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
826 
827    pStatus = (tImeStatus *) rsp->data ;
828 
829 
830    printf("image_status: %x - ", pStatus->image_status);
831 
832    printf("update_state: %x - ", pStatus->update_state);
833 
834    switch( pStatus->update_state )
835    {
836       case IME_STATE_IDLE:
837          printf("IDLE\n");
838       break;
839       case IME_STATE_UPDATE_REQUESTED:
840          printf("Update Requested\n");
841       break;
842       case IME_STATE_UPDATE_IN_PROGRESS:
843          printf("Update in Progress\n");
844       break;
845       case IME_STATE_SUCCESS:
846          printf("Update Success\n");
847       break;
848       case IME_STATE_FAILED:
849          printf("Update Failed\n");
850       break;
851       case IME_STATE_ROLLED_BACK:
852          printf("Update Rolled Back\n");
853       break;
854       case IME_STATE_ABORTED:
855          printf("Update Aborted\n");
856       break;
857       case IME_STATE_INIT_FAILED:
858          printf("Update Init Failed\n");
859       break;
860       default:
861          printf("Unknown, reserved\n");
862       break;
863    }
864    printf("update_attempt_status  : %x\n", pStatus->update_attempt_status);
865    printf("rollback_attempt_status: %x\n", pStatus->rollback_attempt_status);
866    printf("update_type            : %x\n", pStatus->update_type);
867    printf("dependent_flag         : %x\n", pStatus->dependent_flag);
868    printf("free_area_size         : %x\n", pStatus->free_area_size[0]);
869    printf("                       : %x\n", pStatus->free_area_size[1]);
870    printf("                       : %x\n", pStatus->free_area_size[2]);
871    printf("                       : %x\n", pStatus->free_area_size[3]);
872 
873    return IME_SUCCESS;
874 }
875 
876 
877 static int ImeImageCtxFromFile(
878                                  char* imageFilename,
879                                  tImeUpdateImageCtx * pImageCtx
880                                )
881 {
882    int rc = IME_SUCCESS;
883    FILE* pImageFile = fopen(imageFilename, "rb");
884 
885    if ( pImageFile == NULL )
886    {
887       lprintf(LOG_NOTICE,"Cannot open image file %s", imageFilename);
888       rc = IME_ERROR;
889    }
890 
891    if ( rc == IME_SUCCESS )
892    {
893       /* Get the raw data in file */
894       fseek(pImageFile, 0, SEEK_END);
895       pImageCtx->size  = ftell(pImageFile);
896       if (pImageCtx->size <= 0) {
897          if (pImageCtx->size < 0)
898             lprintf(LOG_ERR, "Error seeking %s. %s\n", imageFilename, strerror(errno));
899          rc = IME_ERROR;
900          fclose(pImageFile);
901          return rc;
902       }
903       pImageCtx->pData = malloc(sizeof(unsigned char)*pImageCtx->size);
904       rewind(pImageFile);
905 
906       if ( pImageCtx->pData != NULL )
907       {
908          if (pImageCtx->size < fread(pImageCtx->pData, sizeof(unsigned char),
909                                                    pImageCtx->size, pImageFile))
910             rc = IME_ERROR;
911       }
912       else
913       {
914          rc = IME_ERROR;
915       }
916    }
917 
918    // Calculate checksum CRC8
919    if ( rc == IME_SUCCESS )
920    {
921       pImageCtx->crc8 = ImeCrc8(pImageCtx->size, pImageCtx->pData);
922    }
923 
924 
925    if( pImageFile != NULL)
926    {
927       fclose(pImageFile);
928    }
929 
930    return rc;
931 }
932 
933 static uint8_t ImeCrc8( uint32_t length, uint8_t * pBuf )
934 {
935    uint8_t crc = 0;
936    uint32_t bufCount;
937 
938    for ( bufCount = 0; bufCount < length; bufCount++ )
939    {
940       uint8_t count;
941 
942       crc = crc ^ pBuf[bufCount];
943 
944       for ( count = 0; count < 8; count++ )
945       {
946          if (( crc & 0x80 ) != 0 )
947          {
948             crc <<= 1;
949             crc ^= 0x07;
950          }
951          else
952          {
953             crc <<= 1;
954          }
955       }
956    }
957 
958    lprintf(LOG_DEBUG,"CRC8: %02xh\n", crc);
959    return crc;
960 }
961 
962 
963 static int ImeManualRollback(struct ipmi_intf *intf)
964 {
965    int rc = IME_SUCCESS;
966    tImeStatus imeStatus;
967 
968    rc = ImeUpdateRegisterUpdate(intf, IME_UPDTYPE_MANUAL_ROLLBACK);
969    ImeUpdateGetStatus(intf,&imeStatus);
970 
971 
972    if(
973       (rc == IME_SUCCESS) &&
974       (imeStatus.update_state == IME_STATE_ROLLED_BACK)
975      )
976    {
977       printf("Manual Rollback Succeed\n");
978       return IME_SUCCESS;
979    }
980    else
981    {
982       printf("Manual Rollback Completed With Error\n");
983       return IME_ERROR;
984    }
985 }
986 
987 
988 
989 static void ImePrintUsage(void)
990 {
991    lprintf(LOG_NOTICE,"help                    - This help menu");
992    lprintf(LOG_NOTICE,"info                    - Information about the present Intel ME");
993    lprintf(LOG_NOTICE,"update <file>           - Upgrade the ME firmware from received image <file>");
994    lprintf(LOG_NOTICE,"rollback                - Manual Rollback ME");
995 //   lprintf(LOG_NOTICE,"rollback                - Rollback ME Firmware");
996 }
997 
998 
999 
1000 int ipmi_ime_main(struct ipmi_intf * intf, int argc, char ** argv)
1001 {
1002    int rc = IME_SUCCESS;
1003 
1004    lprintf(LOG_DEBUG,"ipmi_ime_main()");
1005 
1006 
1007    if ( (argc == 0) || (strcmp(argv[0], "help") == 0) )
1008    {
1009       ImePrintUsage();
1010    }
1011    else if ( (argc == 0) || (strcmp(argv[0], "info") == 0) )
1012    {
1013       rc = ImeGetInfo(intf);
1014    }
1015    else if ( strcmp(argv[0], "update") == 0)
1016    {
1017       if(argc == 2)
1018       {
1019          lprintf(LOG_NOTICE,"Update using file: %s", argv[1]);
1020          rc = ImeUpgrade(intf, argv[1]);
1021       }
1022       else
1023       {
1024          lprintf(LOG_ERROR,"File must be provided with this option, see help\n");
1025          rc = IME_ERROR;
1026       }
1027    }
1028    else if ( (argc == 0) || (strcmp(argv[0], "rollback") == 0) )
1029    {
1030       rc = ImeManualRollback(intf);
1031    }
1032    else
1033    {
1034       ImePrintUsage();
1035    }
1036 
1037    return rc;
1038 }
1039 
1040 
1041 
1042