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 
ImeGetInfo(struct ipmi_intf * intf)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 
ImeUpgrade(struct ipmi_intf * intf,char * imageFilename)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             shownPercent = currentPercent;
434             printf("Percent: %02i,  ", shownPercent);
435             time(&current);
436             printf("Elapsed time %02ld:%02ld\r",((current-start)/60), ((current-start)%60));
437             fflush(stdout);
438 
439          }
440       }
441       ImeUpdateGetStatus(intf,&imeStatus);
442       printf("\n");
443    }
444    else if(rc == IME_SUCCESS)
445    {
446       lprintf(LOG_ERROR,"ME state error (%i), aborting", imeStatus.update_state);
447       rc = IME_ERROR;
448    }
449 
450    if(
451       (rc == IME_SUCCESS) &&
452       (imeStatus.update_state == IME_STATE_UPDATE_IN_PROGRESS)
453      )
454    {
455       rc = ImeUpdateCloseArea(intf, imgCtx.size, imgCtx.crc8);
456       ImeUpdateGetStatus(intf,&imeStatus);
457    }
458    else if(rc == IME_SUCCESS)
459    {
460       lprintf(LOG_ERROR,"ME state error, aborting");
461       rc = IME_ERROR;
462    }
463 
464    if(
465       (rc == IME_SUCCESS) &&
466       (imeStatus.update_state == IME_STATE_UPDATE_REQUESTED)
467      )
468    {
469       printf("UpdateCompleted, Activate now\n");
470       rc = ImeUpdateRegisterUpdate(intf, IME_UPDTYPE_NORMAL);
471       ImeUpdateGetStatus(intf,&imeStatus);
472    }
473    else if(rc == IME_SUCCESS)
474    {
475       lprintf(LOG_ERROR,"ME state error, aborting");
476       rc = IME_ERROR;
477    }
478 
479    if(
480       (rc == IME_SUCCESS) &&
481       (imeStatus.update_state == IME_STATE_SUCCESS)
482      )
483    {
484       time(&end);
485       printf("Update Completed in %02ld:%02ld\n",(end-start)/60, (end-start)%60);
486    }
487    else
488    {
489       time(&end);
490       printf("Update Error\n");
491       printf("\nTime Taken %02ld:%02ld\n",(end-start)/60, (end-start)%60);
492    }
493 
494    return rc;
495 }
496 
497 
ImeUpdatePrepare(struct ipmi_intf * intf)498 static int ImeUpdatePrepare(struct ipmi_intf *intf)
499 {
500    struct ipmi_rs * rsp;
501    struct ipmi_rq req;
502 
503    #ifdef OUTPUT_DEBUG
504    printf("ImeUpdatePrepare\n");
505    #endif
506 
507    memset(&req, 0, sizeof(req));
508    req.msg.netfn = 0x30;  // OEM NetFn
509    req.msg.cmd = 0xA0;
510    req.msg.data_len = 0;
511 
512    rsp = intf->sendrecv(intf, &req);
513    if (rsp == NULL) {
514       lprintf(LOG_ERR, "UpdatePrepare command failed");
515       return IME_ERROR;
516    }
517    if (rsp->ccode > 0) {
518       lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
519          val2str(rsp->ccode, completion_code_vals));
520       return IME_ERROR;
521    }
522 
523    lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
524    return IME_SUCCESS;
525 }
526 
ImeUpdateOpenArea(struct ipmi_intf * intf)527 static int ImeUpdateOpenArea(struct ipmi_intf *intf)
528 {
529    struct ipmi_rs * rsp;
530    struct ipmi_rq req;
531    uint8_t buffer[ 2 ];
532 
533    #ifdef OUTPUT_DEBUG
534    printf("ImeUpdateOpenArea\n");
535    #endif
536 
537    memset(&req, 0, sizeof(req));
538    req.msg.netfn = 0x30;  // OEM NetFn
539    req.msg.cmd = 0xA1;
540 
541    buffer[0] = 0x01; // Area Type : Operational code
542    buffer[1] = 0x00; // Reserved : 0
543    req.msg.data = buffer;
544 
545    req.msg.data_len = 2;
546 
547    rsp = intf->sendrecv(intf, &req);
548    if (rsp == NULL) {
549       lprintf(LOG_ERR, "UpdateOpenArea command failed");
550       return IME_ERROR;
551    }
552    if (rsp->ccode > 0) {
553       lprintf(LOG_ERR, "UpdateOpenArea command failed: %s",
554          val2str(rsp->ccode, completion_code_vals));
555       return IME_ERROR;
556    }
557 
558    lprintf(LOG_DEBUG, "UpdateOpenArea command succeed");
559    return IME_SUCCESS;
560 }
561 
ImeUpdateWriteArea(struct ipmi_intf * intf,uint8_t sequence,uint8_t length,uint8_t * pBuf)562 static int ImeUpdateWriteArea(
563                               struct ipmi_intf *intf,
564                               uint8_t sequence,
565                               uint8_t length,
566                               uint8_t * pBuf
567                           )
568 {
569    struct ipmi_rs * rsp;
570    struct ipmi_rq req;
571    uint8_t buffer[ IME_UPGRADE_BUFFER_SIZE + 1 ];
572 
573 //   printf("ImeUpdateWriteArea %i\n", sequence);
574 
575    if(length > IME_UPGRADE_BUFFER_SIZE)
576       return IME_ERROR;
577 
578    buffer[0] = sequence;
579    memcpy(&buffer[1], pBuf, length);
580 
581    memset(&req, 0, sizeof(req));
582    req.msg.netfn = 0x30;  // OEM NetFn
583    req.msg.cmd = 0xA2;
584    req.msg.data = buffer;
585    req.msg.data_len = length + 1;
586 
587    rsp = intf->sendrecv(intf, &req);
588    if (rsp == NULL) {
589       lprintf(LOG_ERR, "UpdateWriteArea command failed");
590       return IME_ERROR;
591    }
592    if (rsp->ccode > 0) {
593       lprintf(LOG_ERR, "UpdateWriteArea command failed: %s",
594          val2str(rsp->ccode, completion_code_vals));
595       if( rsp->ccode == 0x80) // restart operation
596          return IME_RESTART;
597       else
598          return IME_ERROR;
599    }
600 
601    lprintf(LOG_DEBUG, "UpdateWriteArea command succeed");
602    return IME_SUCCESS;
603 }
604 
ImeUpdateCloseArea(struct ipmi_intf * intf,uint32_t size,uint16_t checksum)605 static int ImeUpdateCloseArea(
606                               struct ipmi_intf *intf,
607                               uint32_t size,
608                               uint16_t checksum
609                           )
610 {
611    struct ipmi_rs * rsp;
612    struct ipmi_rq req;
613    uint8_t length = sizeof( uint32_t ) + sizeof( uint16_t );
614    uint8_t buffer[ sizeof( uint32_t ) + sizeof( uint16_t ) ];
615 
616    #ifdef OUTPUT_DEBUG
617    printf( "ImeUpdateCloseArea\n");
618    #endif
619 
620    buffer[0] = (uint8_t)((size & 0x000000ff) >>  0);
621    buffer[1] = (uint8_t)((size & 0x0000ff00) >>  8);
622    buffer[2] = (uint8_t)((size & 0x00ff0000) >> 16);
623    buffer[3] = (uint8_t)((size & 0xff000000) >> 24);
624 
625    buffer[4] = (uint8_t)((checksum & 0x00ff) >>  0);
626    buffer[5] = (uint8_t)((checksum & 0xff00) >>  8);
627 
628    memset(&req, 0, sizeof(req));
629    req.msg.netfn = 0x30;  // OEM NetFn
630    req.msg.cmd = 0xA3;
631    req.msg.data = buffer;
632    req.msg.data_len = length;
633 
634    rsp = intf->sendrecv(intf, &req);
635    if (rsp == NULL) {
636       lprintf(LOG_ERR, "UpdateCloseArea command failed");
637       return IME_ERROR;
638    }
639    if (rsp->ccode > 0) {
640       lprintf(LOG_ERR, "UpdateCloseArea command failed: %s",
641          val2str(rsp->ccode, completion_code_vals));
642       return IME_ERROR;
643    }
644 
645    lprintf(LOG_DEBUG, "UpdateCloseArea command succeed");
646    return IME_SUCCESS;
647 }
648 
ImeUpdateGetStatus(struct ipmi_intf * intf,tImeStatus * pStatus)649 static int ImeUpdateGetStatus(struct ipmi_intf *intf, tImeStatus *pStatus )
650 {
651    struct      ipmi_rs * rsp;
652    struct      ipmi_rq req;
653    tImeStatus *pGetStatus;
654 
655    memset(pStatus, 0, sizeof(tImeStatus));
656    pStatus->update_state = IME_STATE_ABORTED;
657 
658 
659    #ifdef OUTPUT_DEBUG
660    printf("ImeUpdateGetStatus: ");
661    #endif
662 
663    memset(&req, 0, sizeof(req));
664    req.msg.netfn = 0x30;  // OEM NetFn
665    req.msg.cmd = 0xA6;
666    req.msg.data_len = 0;
667 
668    rsp = intf->sendrecv(intf, &req);
669    if (rsp == NULL) {
670       lprintf(LOG_ERR, "UpdatePrepare command failed");
671       return IME_ERROR;
672    }
673    if (rsp->ccode > 0) {
674       lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
675          val2str(rsp->ccode, completion_code_vals));
676       return IME_ERROR;
677    }
678 
679    lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
680 
681    pGetStatus = (tImeStatus *) rsp->data;
682 
683    memcpy( pStatus, pGetStatus, sizeof(tImeStatus));
684 
685    #ifdef OUTPUT_DEBUG
686    printf("%x - ", pStatus->updateState);
687 
688    switch( pStatus->update_state )
689    {
690       case IME_STATE_IDLE:
691          printf("IDLE\n");
692       break;
693       case IME_STATE_UPDATE_REQUESTED:
694          printf("Update Requested\n");
695       break;
696       case IME_STATE_UPDATE_IN_PROGRESS:
697          printf("Update in Progress\n");
698       break;
699       case IME_STATE_SUCCESS:
700          printf("Update Success\n");
701       break;
702       case IME_STATE_FAILED:
703          printf("Update Failed\n");
704       break;
705       case IME_STATE_ROLLED_BACK:
706          printf("Update Rolled Back\n");
707       break;
708       case IME_STATE_ABORTED:
709          printf("Update Aborted\n");
710       break;
711       case IME_STATE_INIT_FAILED:
712          printf("Update Init Failed\n");
713       break;
714       default:
715          printf("Unknown, reserved\n");
716       break;
717    }
718    #endif
719 
720    return IME_SUCCESS;
721 }
722 
ImeUpdateGetCapabilities(struct ipmi_intf * intf,tImeCaps * pCaps)723 static int ImeUpdateGetCapabilities(struct ipmi_intf *intf, tImeCaps *pCaps )
724 {
725    struct      ipmi_rs * rsp;
726    struct      ipmi_rq req;
727    tImeCaps *  pGetCaps;
728 
729    memset(pCaps, 0, sizeof(tImeCaps));
730 
731 
732    #ifdef OUTPUT_DEBUG
733    printf("ImeUpdateGetStatus: ");
734    #endif
735 
736    memset(&req, 0, sizeof(req));
737    req.msg.netfn = 0x30;  // OEM NetFn
738    req.msg.cmd = 0xA7;
739    req.msg.data_len = 0;
740 
741    rsp = intf->sendrecv(intf, &req);
742    if (rsp == NULL) {
743       lprintf(LOG_ERR, "UpdatePrepare command failed");
744       return IME_ERROR;
745    }
746    if (rsp->ccode > 0) {
747       lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
748          val2str(rsp->ccode, completion_code_vals));
749       return IME_ERROR;
750    }
751 
752    lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
753 
754    pGetCaps = (tImeCaps *) rsp->data;
755 
756    memcpy( pCaps, pGetCaps, sizeof(tImeCaps));
757 
758    return IME_SUCCESS;
759 }
760 
761 
ImeUpdateRegisterUpdate(struct ipmi_intf * intf,tImeUpdateType type)762 static int ImeUpdateRegisterUpdate(struct ipmi_intf *intf, tImeUpdateType type)
763 {
764    struct ipmi_rs * rsp;
765    struct ipmi_rq req;
766    uint8_t buffer[ 2 ];
767 
768    #ifdef OUTPUT_DEBUG
769    printf( "ImeUpdateRegisterUpdate\n");
770    #endif
771 
772    buffer[0] = type;  // Normal Update
773    buffer[1] = 0;  // Flags, reserved
774 
775    memset(&req, 0, sizeof(req));
776    req.msg.netfn = 0x30;  // OEM NetFn
777    req.msg.cmd = 0xA4;
778    req.msg.data = buffer;
779    req.msg.data_len = 2;
780 
781    rsp = intf->sendrecv(intf, &req);
782    if (rsp == NULL) {
783       lprintf(LOG_ERR, "ImeUpdateRegisterUpdate command failed");
784       return IME_ERROR;
785    }
786    if (rsp->ccode > 0) {
787       lprintf(LOG_ERR, "ImeUpdateRegisterUpdate command failed: %s",
788          val2str(rsp->ccode, completion_code_vals));
789       return IME_ERROR;
790    }
791 
792    lprintf(LOG_DEBUG, "ImeUpdateRegisterUpdate command succeed");
793    return IME_SUCCESS;
794 }
795 
796 
797 
798 
ImeUpdateShowStatus(struct ipmi_intf * intf)799 static int ImeUpdateShowStatus(struct ipmi_intf *intf)
800 {
801    struct ipmi_rs * rsp;
802    struct ipmi_rq req;
803    tImeStatus *pStatus;
804 
805    printf("ImeUpdateGetStatus: ");
806 
807    memset(&req, 0, sizeof(req));
808    req.msg.netfn = 0x30;  // OEM NetFn
809    req.msg.cmd = 0xA6;
810    req.msg.data_len = 0;
811 
812    rsp = intf->sendrecv(intf, &req);
813    if (rsp == NULL) {
814       lprintf(LOG_ERR, "UpdatePrepare command failed");
815       return IME_ERROR;
816    }
817    if (rsp->ccode > 0) {
818       lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
819          val2str(rsp->ccode, completion_code_vals));
820       return IME_ERROR;
821    }
822 
823    lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
824 
825    pStatus = (tImeStatus *) rsp->data ;
826 
827 
828    printf("image_status: %x - ", pStatus->image_status);
829 
830    printf("update_state: %x - ", pStatus->update_state);
831 
832    switch( pStatus->update_state )
833    {
834       case IME_STATE_IDLE:
835          printf("IDLE\n");
836       break;
837       case IME_STATE_UPDATE_REQUESTED:
838          printf("Update Requested\n");
839       break;
840       case IME_STATE_UPDATE_IN_PROGRESS:
841          printf("Update in Progress\n");
842       break;
843       case IME_STATE_SUCCESS:
844          printf("Update Success\n");
845       break;
846       case IME_STATE_FAILED:
847          printf("Update Failed\n");
848       break;
849       case IME_STATE_ROLLED_BACK:
850          printf("Update Rolled Back\n");
851       break;
852       case IME_STATE_ABORTED:
853          printf("Update Aborted\n");
854       break;
855       case IME_STATE_INIT_FAILED:
856          printf("Update Init Failed\n");
857       break;
858       default:
859          printf("Unknown, reserved\n");
860       break;
861    }
862    printf("update_attempt_status  : %x\n", pStatus->update_attempt_status);
863    printf("rollback_attempt_status: %x\n", pStatus->rollback_attempt_status);
864    printf("update_type            : %x\n", pStatus->update_type);
865    printf("dependent_flag         : %x\n", pStatus->dependent_flag);
866    printf("free_area_size         : %x\n", pStatus->free_area_size[0]);
867    printf("                       : %x\n", pStatus->free_area_size[1]);
868    printf("                       : %x\n", pStatus->free_area_size[2]);
869    printf("                       : %x\n", pStatus->free_area_size[3]);
870 
871    return IME_SUCCESS;
872 }
873 
874 
ImeImageCtxFromFile(char * imageFilename,tImeUpdateImageCtx * pImageCtx)875 static int ImeImageCtxFromFile(
876                                  char* imageFilename,
877                                  tImeUpdateImageCtx * pImageCtx
878                                )
879 {
880    int rc = IME_SUCCESS;
881    FILE* pImageFile = fopen(imageFilename, "rb");
882 
883    if ( pImageFile == NULL )
884    {
885       lprintf(LOG_NOTICE,"Cannot open image file %s", imageFilename);
886       rc = IME_ERROR;
887    }
888 
889    if ( rc == IME_SUCCESS )
890    {
891       /* Get the raw data in file */
892       fseek(pImageFile, 0, SEEK_END);
893       pImageCtx->size  = ftell(pImageFile);
894       if (pImageCtx->size <= 0) {
895          if (pImageCtx->size < 0)
896             lprintf(LOG_ERR, "Error seeking %s. %s\n", imageFilename, strerror(errno));
897          rc = IME_ERROR;
898          fclose(pImageFile);
899          return rc;
900       }
901       pImageCtx->pData = malloc(sizeof(unsigned char)*pImageCtx->size);
902       rewind(pImageFile);
903 
904       if ( pImageCtx->pData != NULL )
905       {
906          if (pImageCtx->size < fread(pImageCtx->pData, sizeof(unsigned char),
907                                                    pImageCtx->size, pImageFile))
908             rc = IME_ERROR;
909       }
910       else
911       {
912          rc = IME_ERROR;
913       }
914    }
915 
916    // Calculate checksum CRC8
917    if ( rc == IME_SUCCESS )
918    {
919       pImageCtx->crc8 = ImeCrc8(pImageCtx->size, pImageCtx->pData);
920    }
921 
922 
923    if( pImageFile != NULL)
924    {
925       fclose(pImageFile);
926    }
927 
928    return rc;
929 }
930 
ImeCrc8(uint32_t length,uint8_t * pBuf)931 static uint8_t ImeCrc8( uint32_t length, uint8_t * pBuf )
932 {
933    uint8_t crc = 0;
934    uint32_t bufCount;
935 
936    for ( bufCount = 0; bufCount < length; bufCount++ )
937    {
938       uint8_t count;
939 
940       crc = crc ^ pBuf[bufCount];
941 
942       for ( count = 0; count < 8; count++ )
943       {
944          if (( crc & 0x80 ) != 0 )
945          {
946             crc <<= 1;
947             crc ^= 0x07;
948          }
949          else
950          {
951             crc <<= 1;
952          }
953       }
954    }
955 
956    lprintf(LOG_DEBUG,"CRC8: %02xh\n", crc);
957    return crc;
958 }
959 
960 
ImeManualRollback(struct ipmi_intf * intf)961 static int ImeManualRollback(struct ipmi_intf *intf)
962 {
963    int rc = IME_SUCCESS;
964    tImeStatus imeStatus;
965 
966    rc = ImeUpdateRegisterUpdate(intf, IME_UPDTYPE_MANUAL_ROLLBACK);
967    ImeUpdateGetStatus(intf,&imeStatus);
968 
969 
970    if(
971       (rc == IME_SUCCESS) &&
972       (imeStatus.update_state == IME_STATE_ROLLED_BACK)
973      )
974    {
975       printf("Manual Rollback Succeed\n");
976       return IME_SUCCESS;
977    }
978    else
979    {
980       printf("Manual Rollback Completed With Error\n");
981       return IME_ERROR;
982    }
983 }
984 
985 
986 
ImePrintUsage(void)987 static void ImePrintUsage(void)
988 {
989    lprintf(LOG_NOTICE,"help                    - This help menu");
990    lprintf(LOG_NOTICE,"info                    - Information about the present Intel ME");
991    lprintf(LOG_NOTICE,"update <file>           - Upgrade the ME firmware from received image <file>");
992    lprintf(LOG_NOTICE,"rollback                - Manual Rollback ME");
993 //   lprintf(LOG_NOTICE,"rollback                - Rollback ME Firmware");
994 }
995 
996 
997 
ipmi_ime_main(struct ipmi_intf * intf,int argc,char ** argv)998 int ipmi_ime_main(struct ipmi_intf * intf, int argc, char ** argv)
999 {
1000    int rc = IME_SUCCESS;
1001 
1002    lprintf(LOG_DEBUG,"ipmi_ime_main()");
1003 
1004 
1005    if ( (argc == 0) || (strcmp(argv[0], "help") == 0) )
1006    {
1007       ImePrintUsage();
1008    }
1009    else if ( (argc == 0) || (strcmp(argv[0], "info") == 0) )
1010    {
1011       rc = ImeGetInfo(intf);
1012    }
1013    else if ( strcmp(argv[0], "update") == 0)
1014    {
1015       if(argc == 2)
1016       {
1017          lprintf(LOG_NOTICE,"Update using file: %s", argv[1]);
1018          rc = ImeUpgrade(intf, argv[1]);
1019       }
1020       else
1021       {
1022          lprintf(LOG_ERROR,"File must be provided with this option, see help\n");
1023          rc = IME_ERROR;
1024       }
1025    }
1026    else if ( (argc == 0) || (strcmp(argv[0], "rollback") == 0) )
1027    {
1028       rc = ImeManualRollback(intf);
1029    }
1030    else
1031    {
1032       ImePrintUsage();
1033    }
1034 
1035    return rc;
1036 }
1037 
1038 
1039 
1040