ipmi_kontronoem.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. /*
  2. * Copyright (c) 2004 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. * Tue Mar 7 14:36:12 2006
  37. * <stephane.filion@ca.kontron.com>
  38. *
  39. * This code implements an Kontron OEM proprietary commands.
  40. */
  41. #include <string.h>
  42. #include <ipmitool/helper.h>
  43. #include <ipmitool/log.h>
  44. #include <ipmitool/ipmi.h>
  45. #include <ipmitool/ipmi_intf.h>
  46. #include <ipmitool/ipmi_fru.h>
  47. extern int verbose;
  48. extern int read_fru_area(struct ipmi_intf *intf, struct fru_info *fru,
  49. uint8_t id, uint32_t offset, uint32_t length,
  50. uint8_t *frubuf);
  51. extern int write_fru_area(struct ipmi_intf * intf, struct fru_info *fru,
  52. uint8_t id, uint16_t soffset,
  53. uint16_t doffset, uint16_t length,
  54. uint8_t *pFrubuf);
  55. extern char *get_fru_area_str(uint8_t *data, uint32_t *offset);
  56. static void ipmi_kontron_help(void);
  57. static int ipmi_kontron_set_serial_number(struct ipmi_intf *intf);
  58. static int ipmi_kontron_set_mfg_date (struct ipmi_intf *intf);
  59. static void ipmi_kontron_nextboot_help(void);
  60. static int ipmi_kontron_nextboot_set(struct ipmi_intf *intf, int argc,
  61. char **argv);
  62. static int ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf *intf,
  63. unsigned char channel, unsigned char size);
  64. static char *bootdev[] = {"BIOS", "FDD", "HDD", "CDROM", "network", 0};
  65. int
  66. ipmi_kontronoem_main(struct ipmi_intf *intf, int argc, char **argv)
  67. {
  68. int rc = 0;
  69. if (argc == 0) {
  70. lprintf(LOG_ERR, "Not enough parameters given.");
  71. ipmi_kontron_help();
  72. return (-1);
  73. }
  74. if (strncmp(argv[0], "help", 4) == 0) {
  75. ipmi_kontron_help();
  76. rc = 0;
  77. } else if (!strncmp(argv[0], "setsn", 5)) {
  78. if (argc < 1) {
  79. printf("fru setsn\n");
  80. return (-1);
  81. }
  82. if (ipmi_kontron_set_serial_number(intf) > 0) {
  83. printf("FRU serial number setted successfully\n");
  84. } else {
  85. printf("FRU serial number set failed\n");
  86. rc = (-1);
  87. }
  88. } else if (!strncmp(argv[0], "setmfgdate", 10)) {
  89. if (argc < 1) {
  90. printf("fru setmfgdate\n");
  91. return (-1);
  92. }
  93. if (ipmi_kontron_set_mfg_date(intf) > 0) {
  94. printf("FRU manufacturing date setted successfully\n");
  95. } else {
  96. printf("FRU manufacturing date set failed\n");
  97. rc = (-1);
  98. }
  99. } else if (!strncmp(argv[0], "nextboot", 8)) {
  100. if (argc < 2) {
  101. lprintf(LOG_ERR, "Not enough parameters given.");
  102. ipmi_kontron_nextboot_help();
  103. return (-1);
  104. }
  105. rc = ipmi_kontron_nextboot_set(intf, (argc - 1), (argv + 1));
  106. if (rc == 0) {
  107. printf("Nextboot set successfully\n");
  108. } else {
  109. printf("Nextboot set failed\n");
  110. rc = (-1);
  111. }
  112. } else {
  113. lprintf(LOG_ERR, "Invalid Kontron command: %s", argv[0]);
  114. ipmi_kontron_help();
  115. rc = (-1);
  116. }
  117. return rc;
  118. }
  119. static void
  120. ipmi_kontron_help(void)
  121. {
  122. printf("Kontron Commands: setsn setmfgdate nextboot\n");
  123. }
  124. int
  125. ipmi_kontronoem_set_large_buffer(struct ipmi_intf *intf, unsigned char size)
  126. {
  127. uint8_t error_occurs = 0;
  128. uint32_t prev_target_addr = intf->target_addr ;
  129. if (intf->target_addr > 0 && (intf->target_addr != intf->my_addr)) {
  130. intf->target_addr = intf->my_addr;
  131. printf("Set local big buffer\n");
  132. if (ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, size) == 0) {
  133. printf("Set local big buffer:success\n");
  134. } else {
  135. error_occurs = 1;
  136. }
  137. if (error_occurs == 0) {
  138. if (ipmi_kontronoem_send_set_large_buffer(intf, 0x00, size) == 0) {
  139. printf("IPMB was set\n");
  140. } else {
  141. /* Revert back the previous set large buffer */
  142. error_occurs = 1;
  143. ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, 0 );
  144. }
  145. }
  146. /* Restore target address */
  147. intf->target_addr = prev_target_addr;
  148. }
  149. if (error_occurs == 0) {
  150. if(ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, size) == 0) {
  151. /* printf("Set remote big buffer\n"); */
  152. } else {
  153. if (intf->target_addr > 0 && (intf->target_addr != intf->my_addr)) {
  154. /* Error occurs revert back the previous set large buffer */
  155. intf->target_addr = intf->my_addr;
  156. /* ipmi_kontronoem_send_set_large_buffer(intf, 0x00, 0); */
  157. ipmi_kontronoem_send_set_large_buffer(intf, 0x0e, 0);
  158. intf->target_addr = prev_target_addr;
  159. }
  160. }
  161. }
  162. return error_occurs;
  163. }
  164. int
  165. ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf *intf,
  166. unsigned char channel, unsigned char size)
  167. {
  168. struct ipmi_rs *rsp;
  169. struct ipmi_rq req;
  170. uint8_t msg_data[2];
  171. memset(msg_data, 0, sizeof(msg_data));
  172. /* channel =~ 0x0e => Currently running interface */
  173. msg_data[0] = channel;
  174. msg_data[1] = size;
  175. memset(&req, 0, sizeof(req));
  176. req.msg.netfn = 0x3E;
  177. /* Set Channel Buffer Length - OEM */
  178. req.msg.cmd = 0x82;
  179. req.msg.data = msg_data;
  180. req.msg.data_len = 2;
  181. req.msg.lun = 0x00;
  182. rsp = intf->sendrecv(intf, &req);
  183. if (rsp == NULL) {
  184. printf("Cannot send large buffer command\n");
  185. return(-1);
  186. } else if (rsp->ccode > 0) {
  187. printf("Invalid length for the selected interface (%s) %d\n",
  188. val2str(rsp->ccode, completion_code_vals), rsp->ccode);
  189. return(-1);
  190. }
  191. return 0;
  192. }
  193. /* ipmi_fru_set_serial_number - Set the Serial Number in FRU
  194. *
  195. * @intf: ipmi interface
  196. * @id: fru id
  197. *
  198. * returns -1 on error
  199. * returns 1 if successful
  200. */
  201. static int
  202. ipmi_kontron_set_serial_number(struct ipmi_intf *intf)
  203. {
  204. struct fru_header header;
  205. struct fru_info fru;
  206. struct ipmi_rs *rsp;
  207. struct ipmi_rq req;
  208. char *sn;
  209. char *fru_area;
  210. uint8_t checksum;
  211. uint8_t *fru_data;
  212. uint8_t msg_data[4];
  213. uint8_t sn_size;
  214. uint32_t board_sec_len;
  215. uint32_t fru_data_offset;
  216. uint32_t fru_data_offset_tmp;
  217. uint32_t i;
  218. uint32_t prod_sec_len;
  219. sn = NULL;
  220. fru_data = NULL;
  221. memset(msg_data, 0, 4);
  222. msg_data[0] = 0xb4;
  223. msg_data[1] = 0x90;
  224. msg_data[2] = 0x91;
  225. msg_data[3] = 0x8b;
  226. memset(&req, 0, sizeof(req));
  227. req.msg.netfn = 0x3E;
  228. req.msg.cmd = 0x0C;
  229. req.msg.data = msg_data;
  230. req.msg.data_len = 4;
  231. /* Set Lun, necessary for this oem command */
  232. req.msg.lun = 0x03;
  233. rsp = intf->sendrecv(intf, &req);
  234. if (rsp == NULL) {
  235. printf(" Device not present (No Response)\n");
  236. return (-1);
  237. } else if (rsp->ccode > 0) {
  238. printf(" This option is not implemented for this board\n");
  239. return (-1);
  240. }
  241. sn_size = rsp->data_len;
  242. sn = malloc(sn_size + 1);
  243. if (sn == NULL) {
  244. lprintf(LOG_ERR, "ipmitool: malloc failure");
  245. return (-1);
  246. }
  247. memset(sn, 0, sn_size + 1);
  248. memcpy(sn, rsp->data, sn_size);
  249. if (verbose >= 1) {
  250. printf("Original serial number is : [%s]\n", sn);
  251. }
  252. memset(msg_data, 0, 4);
  253. msg_data[0] = 0;
  254. memset(&req, 0, sizeof(req));
  255. req.msg.netfn = IPMI_NETFN_STORAGE;
  256. req.msg.cmd = GET_FRU_INFO;
  257. req.msg.data = msg_data;
  258. req.msg.data_len = 1;
  259. rsp = intf->sendrecv(intf, &req);
  260. if (rsp == NULL) {
  261. printf(" Device not present (No Response)\n");
  262. free(sn);
  263. sn = NULL;
  264. return (-1);
  265. } else if (rsp->ccode > 0) {
  266. printf(" Device not present (%s)\n",
  267. val2str(rsp->ccode, completion_code_vals));
  268. free(sn);
  269. sn = NULL;
  270. return (-1);
  271. }
  272. memset(&fru, 0, sizeof(fru));
  273. fru.size = (rsp->data[1] << 8) | rsp->data[0];
  274. fru.access = rsp->data[2] & 0x1;
  275. if (fru.size < 1) {
  276. printf(" Invalid FRU size %d", fru.size);
  277. free(sn);
  278. sn = NULL;
  279. return (-1);
  280. }
  281. /* retrieve the FRU header */
  282. msg_data[0] = 0;
  283. msg_data[1] = 0;
  284. msg_data[2] = 0;
  285. msg_data[3] = 8;
  286. memset(&req, 0, sizeof(req));
  287. req.msg.netfn = IPMI_NETFN_STORAGE;
  288. req.msg.cmd = GET_FRU_DATA;
  289. req.msg.data = msg_data;
  290. req.msg.data_len = 4;
  291. rsp = intf->sendrecv(intf, &req);
  292. if (rsp == NULL) {
  293. printf(" Device not present (No Response)\n");
  294. free(sn);
  295. sn = NULL;
  296. return (-1);
  297. } else if (rsp->ccode > 0) {
  298. printf(" Device not present (%s)\n",
  299. val2str(rsp->ccode, completion_code_vals));
  300. free(sn);
  301. sn = NULL;
  302. return (-1);
  303. }
  304. if (verbose > 1) {
  305. printbuf(rsp->data, rsp->data_len, "FRU DATA");
  306. }
  307. memcpy(&header, rsp->data + 1, 8);
  308. if (header.version != 1) {
  309. printf(" Unknown FRU header version 0x%02x",
  310. header.version);
  311. free(sn);
  312. sn = NULL;
  313. return(-1);
  314. }
  315. /* Set the Board Section */
  316. board_sec_len = (header.offset.product * 8) - (header.offset.board * 8);
  317. fru_data = malloc(fru.size);
  318. if (fru_data == NULL) {
  319. lprintf(LOG_ERR, "ipmitool: malloc failure");
  320. free(sn);
  321. sn = NULL;
  322. return (-1);
  323. }
  324. memset(fru_data, 0, fru.size);
  325. if (read_fru_area(intf, &fru, 0, (header.offset.board * 8),
  326. board_sec_len, fru_data) < 0) {
  327. free(sn);
  328. sn = NULL;
  329. free(fru_data);
  330. fru_data = NULL;
  331. return (-1);
  332. }
  333. /* Position at Board Manufacturer */
  334. fru_data_offset = (header.offset.board * 8) + 6;
  335. fru_area = get_fru_area_str(fru_data, &fru_data_offset);
  336. if (fru_area != NULL) {
  337. free(fru_area);
  338. fru_area = NULL;
  339. }
  340. /* Position at Board Product Name */
  341. fru_area = get_fru_area_str(fru_data, &fru_data_offset);
  342. if (fru_area != NULL) {
  343. free(fru_area);
  344. fru_area = NULL;
  345. }
  346. fru_data_offset_tmp = fru_data_offset;
  347. /* Position at Serial Number */
  348. fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp);
  349. if (fru_area == NULL) {
  350. lprintf(LOG_ERR, "Failed to read FRU Area string.");
  351. free(fru_data);
  352. fru_data = NULL;
  353. free(sn);
  354. sn = NULL;
  355. return (-1);
  356. }
  357. fru_data_offset++;
  358. if (strlen(fru_area) != sn_size) {
  359. printf("The length of the serial number in the FRU Board Area is wrong.\n");
  360. free(sn);
  361. sn = NULL;
  362. free(fru_data);
  363. fru_data = NULL;
  364. free(fru_area);
  365. fru_area = NULL;
  366. return(-1);
  367. } else {
  368. free(fru_area);
  369. fru_area = NULL;
  370. }
  371. /* Copy the new serial number in the board section saved in memory*/
  372. memcpy(fru_data + fru_data_offset, sn, sn_size);
  373. checksum = 0;
  374. /* Calculate Header Checksum */
  375. for(i = (header.offset.board * 8);
  376. i < (((header.offset.board * 8) + board_sec_len) - 2);
  377. i++) {
  378. checksum += fru_data[i];
  379. }
  380. checksum = (~checksum) + 1;
  381. fru_data[(header.offset.board * 8) + board_sec_len - 1] = checksum;
  382. /* Write the new FRU Board section */
  383. if (write_fru_area(intf, &fru, 0, (header.offset.board * 8),
  384. (header.offset.board * 8),
  385. board_sec_len, fru_data) < 0) {
  386. free(sn);
  387. sn = NULL;
  388. free(fru_data);
  389. fru_data = NULL;
  390. free(fru_area);
  391. fru_area = NULL;
  392. return(-1);
  393. }
  394. /* Set the Product Section */
  395. prod_sec_len = (header.offset.multi * 8) - (header.offset.product * 8);
  396. if (read_fru_area(intf, &fru, 0, (header.offset.product * 8),
  397. prod_sec_len, fru_data) < 0) {
  398. free(sn);
  399. sn = NULL;
  400. free(fru_data);
  401. fru_data = NULL;
  402. free(fru_area);
  403. fru_area = NULL;
  404. return(-1);
  405. }
  406. /* Position at Product Manufacturer */
  407. fru_data_offset = (header.offset.product * 8) + 3;
  408. fru_area = get_fru_area_str(fru_data, &fru_data_offset);
  409. if (fru_area != NULL) {
  410. free(fru_area);
  411. fru_area = NULL;
  412. }
  413. /* Position at Product Name */
  414. fru_area = get_fru_area_str(fru_data, &fru_data_offset);
  415. if (fru_area != NULL) {
  416. free(fru_area);
  417. fru_area = NULL;
  418. }
  419. /* Position at Product Part */
  420. fru_area = get_fru_area_str(fru_data, &fru_data_offset);
  421. if (fru_area != NULL) {
  422. free(fru_area);
  423. fru_area = NULL;
  424. }
  425. /* Position at Product Version */
  426. fru_area = get_fru_area_str(fru_data, &fru_data_offset);
  427. if (fru_area != NULL) {
  428. free(fru_area);
  429. fru_area = NULL;
  430. }
  431. fru_data_offset_tmp = fru_data_offset;
  432. /* Position at Serial Number */
  433. fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp);
  434. if (fru_area == NULL) {
  435. lprintf(LOG_ERR, "Failed to read FRU Area string.");
  436. free(sn);
  437. sn = NULL;
  438. free(fru_data);
  439. fru_data = NULL;
  440. return (-1);
  441. }
  442. fru_data_offset ++;
  443. if (strlen(fru_area) != sn_size) {
  444. free(sn);
  445. sn = NULL;
  446. free(fru_data);
  447. fru_data = NULL;
  448. free(fru_area);
  449. fru_area = NULL;
  450. printf("The length of the serial number in the FRU Product Area is wrong.\n");
  451. return(-1);
  452. }
  453. /* Copy the new serial number in the product section saved in memory*/
  454. memcpy(fru_data + fru_data_offset, sn, sn_size);
  455. checksum = 0;
  456. /* Calculate Header Checksum */
  457. for (i = (header.offset.product * 8);
  458. i < (((header.offset.product * 8) + prod_sec_len) - 2);
  459. i ++) {
  460. checksum += fru_data[i];
  461. }
  462. checksum = (~checksum) + 1;
  463. fru_data[(header.offset.product * 8)+prod_sec_len - 1] = checksum;
  464. /* Write the new FRU Board section */
  465. if (write_fru_area(intf, &fru, 0, (header.offset.product * 8),
  466. (header.offset.product * 8),
  467. prod_sec_len, fru_data) < 0) {
  468. free(sn);
  469. sn = NULL;
  470. free(fru_data);
  471. fru_data = NULL;
  472. free(fru_area);
  473. fru_area = NULL;
  474. return -1;
  475. }
  476. free(sn);
  477. sn = NULL;
  478. free(fru_data);
  479. fru_data = NULL;
  480. free(fru_area);
  481. fru_area = NULL;
  482. return(1);
  483. }
  484. /* ipmi_fru_set_mfg_date - Set the Manufacturing Date in FRU
  485. *
  486. * @intf: ipmi interface
  487. * @id: fru id
  488. *
  489. * returns -1 on error
  490. * returns 1 if successful
  491. */
  492. static int
  493. ipmi_kontron_set_mfg_date (struct ipmi_intf *intf)
  494. {
  495. struct fru_header header;
  496. struct fru_info fru;
  497. struct ipmi_rs *rsp;
  498. struct ipmi_rq req;
  499. uint8_t *fru_data;
  500. uint8_t checksum;
  501. uint8_t msg_data[4];
  502. uint8_t mfg_date[3];
  503. uint32_t board_sec_len;
  504. uint32_t i;
  505. memset(msg_data, 0, 4);
  506. msg_data[0] = 0xb4;
  507. msg_data[1] = 0x90;
  508. msg_data[2] = 0x91;
  509. msg_data[3] = 0x8b;
  510. memset(&req, 0, sizeof(req));
  511. req.msg.netfn = 0x3E;
  512. req.msg.cmd = 0x0E;
  513. req.msg.data = msg_data;
  514. req.msg.data_len = 4;
  515. /* Set Lun temporary, necessary for this oem command */
  516. req.msg.lun = 0x03;
  517. rsp = intf->sendrecv(intf, &req);
  518. if (rsp == NULL) {
  519. printf("Device not present (No Response)\n");
  520. return(-1);
  521. } else if (rsp->ccode > 0) {
  522. printf("This option is not implemented for this board\n");
  523. return(-1);
  524. }
  525. if (rsp->data_len != 3) {
  526. printf("Invalid response for the Manufacturing date\n");
  527. return(-1);
  528. }
  529. memset(mfg_date, 0, 3);
  530. memcpy(mfg_date, rsp->data, 3);
  531. memset(msg_data, 0, 4);
  532. msg_data[0] = 0;
  533. memset(&req, 0, sizeof(req));
  534. req.msg.netfn = IPMI_NETFN_STORAGE;
  535. req.msg.cmd = GET_FRU_INFO;
  536. req.msg.data = msg_data;
  537. req.msg.data_len = 1;
  538. rsp = intf->sendrecv(intf, &req);
  539. if (rsp == NULL) {
  540. printf(" Device not present (No Response)\n");
  541. return(-1);
  542. } else if (rsp->ccode > 0) {
  543. printf(" Device not present (%s)\n",
  544. val2str(rsp->ccode, completion_code_vals));
  545. return(-1);
  546. }
  547. memset(&fru, 0, sizeof(fru));
  548. fru.size = (rsp->data[1] << 8) | rsp->data[0];
  549. fru.access = rsp->data[2] & 0x1;
  550. if (fru.size < 1) {
  551. printf(" Invalid FRU size %d", fru.size);
  552. return(-1);
  553. }
  554. /* retrieve the FRU header */
  555. msg_data[0] = 0;
  556. msg_data[1] = 0;
  557. msg_data[2] = 0;
  558. msg_data[3] = 8;
  559. memset(&req, 0, sizeof(req));
  560. req.msg.netfn = IPMI_NETFN_STORAGE;
  561. req.msg.cmd = GET_FRU_DATA;
  562. req.msg.data = msg_data;
  563. req.msg.data_len = 4;
  564. rsp = intf->sendrecv(intf, &req);
  565. if (rsp == NULL) {
  566. printf(" Device not present (No Response)\n");
  567. return (-1);
  568. } else if (rsp->ccode > 0) {
  569. printf(" Device not present (%s)\n",
  570. val2str(rsp->ccode, completion_code_vals));
  571. return (-1);
  572. }
  573. if (verbose > 1) {
  574. printbuf(rsp->data, rsp->data_len, "FRU DATA");
  575. }
  576. memcpy(&header, rsp->data + 1, 8);
  577. if (header.version != 1) {
  578. printf(" Unknown FRU header version 0x%02x",
  579. header.version);
  580. return(-1);
  581. }
  582. board_sec_len = (header.offset.product * 8) - (header.offset.board * 8);
  583. fru_data = malloc(fru.size);
  584. if(fru_data == NULL) {
  585. lprintf(LOG_ERR, "ipmitool: malloc failure");
  586. return(-1);
  587. }
  588. memset(fru_data, 0, fru.size);
  589. if (read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8),
  590. board_sec_len ,fru_data) < 0) {
  591. free(fru_data);
  592. fru_data = NULL;
  593. return(-1);
  594. }
  595. /* Copy the new manufacturing date in the board section saved in memory*/
  596. memcpy(fru_data + (header.offset.board * 8) + 3, mfg_date, 3);
  597. checksum = 0;
  598. /* Calculate Header Checksum */
  599. for (i = (header.offset.board * 8);
  600. i < (((header.offset.board * 8) + board_sec_len) - 2);
  601. i ++ ) {
  602. checksum += fru_data[i];
  603. }
  604. checksum = (~checksum) + 1;
  605. fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum;
  606. /* Write the new FRU Board section */
  607. if (write_fru_area(intf, &fru, 0, (header.offset.board * 8),
  608. (header.offset.board * 8),
  609. board_sec_len, fru_data) < 0) {
  610. free(fru_data);
  611. fru_data = NULL;
  612. return (-1);
  613. }
  614. free(fru_data);
  615. fru_data = NULL;
  616. return (1);
  617. }
  618. static void
  619. ipmi_kontron_nextboot_help(void)
  620. {
  621. int i;
  622. printf("nextboot <device>\n"
  623. "Supported devices:\n");
  624. for (i = 0; bootdev[i] != 0; i++) {
  625. printf("- %s\n", bootdev[i]);
  626. }
  627. }
  628. /* ipmi_kontron_next_boot_set - Select the next boot order on CP6012
  629. *
  630. * @intf: ipmi interface
  631. * @id: fru id
  632. *
  633. * returns -1 on error
  634. * returns 1 if successful
  635. */
  636. static int
  637. ipmi_kontron_nextboot_set(struct ipmi_intf *intf, int argc, char **argv)
  638. {
  639. struct ipmi_rs *rsp;
  640. struct ipmi_rq req;
  641. uint8_t msg_data[8];
  642. int i;
  643. memset(msg_data, 0, sizeof(msg_data));
  644. msg_data[0] = 0xb4;
  645. msg_data[1] = 0x90;
  646. msg_data[2] = 0x91;
  647. msg_data[3] = 0x8b;
  648. msg_data[4] = 0x9d;
  649. msg_data[5] = 0xFF;
  650. msg_data[6] = 0xFF; /* any */
  651. for (i = 0; bootdev[i] != 0; i++) {
  652. if (strcmp(argv[0], bootdev[i]) == 0) {
  653. msg_data[5] = i;
  654. break;
  655. }
  656. }
  657. /* Invalid device selected? */
  658. if (msg_data[5] == 0xFF) {
  659. printf("Unknown boot device: %s\n", argv[0]);
  660. return (-1);
  661. }
  662. memset(&req, 0, sizeof(req));
  663. req.msg.netfn = 0x3E;
  664. req.msg.cmd = 0x02;
  665. req.msg.data = msg_data;
  666. req.msg.data_len = 7;
  667. /* Set Lun temporary, necessary for this oem command */
  668. req.msg.lun = 0x03;
  669. rsp = intf->sendrecv(intf, &req);
  670. if (rsp == NULL) {
  671. printf("Device not present (No Response)\n");
  672. return(-1);
  673. } else if (rsp->ccode > 0) {
  674. printf("Device not present (%s)\n",
  675. val2str(rsp->ccode, completion_code_vals));
  676. return (-1);
  677. }
  678. return 0;
  679. }