ipmi_ime.c 28 KB

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