ipmi_gendev.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. /*
  2. * Copyright (c) 2003 Kontron Canada, Inc. All Rights Reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * Redistribution of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * Redistribution in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * Neither the name of Sun Microsystems, Inc. or the names of
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * This software is provided "AS IS," without a warranty of any kind.
  20. * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
  21. * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
  22. * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
  23. * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
  24. * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  25. * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
  26. * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
  27. * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
  28. * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
  29. * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
  30. * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  31. */
  32. #include <string.h>
  33. #include <math.h>
  34. #include <stdio.h>
  35. #include <unistd.h>
  36. #include <sys/types.h>
  37. #include <time.h>
  38. #include <ipmitool/ipmi.h>
  39. #include <ipmitool/log.h>
  40. #include <ipmitool/ipmi_mc.h>
  41. #include <ipmitool/ipmi_sdr.h>
  42. #include <ipmitool/ipmi_gendev.h>
  43. #include <ipmitool/ipmi_intf.h>
  44. #include <ipmitool/ipmi_sel.h>
  45. #include <ipmitool/ipmi_entity.h>
  46. #include <ipmitool/ipmi_constants.h>
  47. #include <ipmitool/ipmi_strings.h>
  48. #include <ipmitool/ipmi_raw.h>
  49. #if HAVE_CONFIG_H
  50. # include <config.h>
  51. #endif
  52. extern int verbose;
  53. #define GENDEV_RETRY_COUNT 5
  54. #define GENDEV_MAX_SIZE 16
  55. typedef struct gendev_eeprom_info
  56. {
  57. uint32_t size;
  58. uint16_t page_size;
  59. uint8_t address_span;
  60. uint8_t address_length;
  61. }t_gendev_eeprom_info;
  62. static int
  63. ipmi_gendev_get_eeprom_size(
  64. struct ipmi_intf *intf,
  65. struct sdr_record_generic_locator *dev,
  66. t_gendev_eeprom_info *info
  67. )
  68. {
  69. int eeprom_size = 0;
  70. /*
  71. lprintf(LOG_ERR, "Gen Device : %s", dev->id_string);
  72. lprintf(LOG_ERR, "Access Addr: %x", dev->dev_access_addr);
  73. lprintf(LOG_ERR, "Slave Addr : %x", dev->dev_slave_addr);
  74. lprintf(LOG_ERR, "Channel Num: %x", dev->channel_num);
  75. lprintf(LOG_ERR, "Lun : %x", dev->lun);
  76. lprintf(LOG_ERR, "Bus : %x", dev->bus);
  77. lprintf(LOG_ERR, "Addr Span : %x", dev->addr_span);
  78. lprintf(LOG_ERR, "DevType : %x", dev->dev_type);
  79. lprintf(LOG_ERR, "DevType Mod: %x", dev->dev_type_modifier);
  80. */
  81. if( info != NULL)
  82. {
  83. switch(dev->dev_type)
  84. {
  85. case 0x08: // 24C01
  86. info->size = 128;
  87. info->page_size = 8;
  88. info->address_span = dev->addr_span;
  89. info->address_length = 1;
  90. break;
  91. case 0x09: // 24C02
  92. info->size = 256;
  93. info->page_size = 8;
  94. info->address_span = dev->addr_span;
  95. info->address_length = 1;
  96. break;
  97. case 0x0A: // 24C04
  98. info->size = 512;
  99. info->page_size = 8;
  100. info->address_span = dev->addr_span;
  101. info->address_length = 2;
  102. break;
  103. case 0x0B: // 24C08
  104. info->size = 1024;
  105. info->page_size = 8;
  106. info->address_span = dev->addr_span;
  107. info->address_length = 2;
  108. break;
  109. case 0x0C: // 24C16
  110. info->size = 2048;
  111. info->page_size = 256;
  112. info->address_span = dev->addr_span;
  113. info->address_length = 2;
  114. break;
  115. case 0x0D: // 24C17
  116. info->size = 2048;
  117. info->page_size = 256;
  118. info->address_span = dev->addr_span;
  119. info->address_length = 2;
  120. break;
  121. case 0x0E: // 24C32
  122. info->size = 4096;
  123. info->page_size = 8;
  124. info->address_span = dev->addr_span;
  125. info->address_length = 2;
  126. break;
  127. case 0x0F: // 24C64
  128. info->size = 8192;
  129. info->page_size = 32;
  130. info->address_span = dev->addr_span;
  131. info->address_length = 2;
  132. break;
  133. case 0xC0: // Proposed OEM Code for 24C128
  134. info->size = 16384;
  135. info->page_size = 64;
  136. info->address_span = dev->addr_span;
  137. info->address_length = 2;
  138. break;
  139. case 0xC1: // Proposed OEM Code for 24C256
  140. info->size = 32748;
  141. info->page_size = 64;
  142. info->address_span = dev->addr_span;
  143. info->address_length = 2;
  144. break;
  145. case 0xC2: // Proposed OEM Code for 24C512
  146. info->size = 65536;
  147. info->page_size = 128;
  148. info->address_span = dev->addr_span;
  149. info->address_length = 2;
  150. break;
  151. case 0xC3: // Proposed OEM Code for 24C1024
  152. info->size = 131072;
  153. info->page_size = 128;
  154. info->address_span = dev->addr_span;
  155. info->address_length = 2;
  156. break;
  157. /* Please reserved up to CFh for future update */
  158. default: // Not a eeprom, return size = 0;
  159. info->size = 0;
  160. info->page_size = 0;
  161. info->address_span = 0;
  162. info->address_length = 0;
  163. break;
  164. }
  165. eeprom_size = info->size;
  166. }
  167. return eeprom_size;
  168. }
  169. static int
  170. ipmi_gendev_read_file(
  171. struct ipmi_intf *intf,
  172. struct sdr_record_generic_locator *dev,
  173. const char *ofile
  174. )
  175. {
  176. int rc = 0;
  177. int eeprom_size;
  178. t_gendev_eeprom_info eeprom_info;
  179. eeprom_size = ipmi_gendev_get_eeprom_size(intf, dev, &eeprom_info);
  180. if(eeprom_size > 0)
  181. {
  182. FILE *fp;
  183. /* now write to file */
  184. fp = ipmi_open_file_write(ofile);
  185. if(fp)
  186. {
  187. struct ipmi_rs *rsp;
  188. int numWrite;
  189. uint32_t counter;
  190. uint8_t msize;
  191. uint8_t channel = dev->channel_num;
  192. uint8_t i2cbus = dev->bus;
  193. uint8_t i2caddr = dev->dev_slave_addr;
  194. uint8_t privatebus = 1;
  195. uint32_t address_span_size;
  196. uint8_t percentCompleted = 0;
  197. /* Handle Address Span */
  198. if( eeprom_info.address_span != 0)
  199. {
  200. address_span_size =
  201. (eeprom_info.size / (eeprom_info.address_span+1));
  202. }
  203. else
  204. {
  205. address_span_size = eeprom_info.size;
  206. }
  207. /* Setup read/write size */
  208. if( eeprom_info.page_size < GENDEV_MAX_SIZE)
  209. {
  210. msize = eeprom_info.page_size;
  211. }
  212. else
  213. {
  214. msize = GENDEV_MAX_SIZE;
  215. // All eeprom with page higher than 32 is on the
  216. // 16 bytes boundary
  217. }
  218. /* Setup i2c bus byte */
  219. i2cbus = ((channel & 0xF) << 4) | ((i2cbus & 7) << 1) | privatebus;
  220. /*
  221. lprintf(LOG_ERR, "Generic device: %s", dev->id_string);
  222. lprintf(LOG_ERR, "I2C Chnl: %x", channel);
  223. lprintf(LOG_ERR, "I2C Bus : %x", i2cbus);
  224. lprintf(LOG_ERR, "I2C Addr: %x", i2caddr); */
  225. for (
  226. counter = 0;
  227. (counter < (eeprom_info.size)) && (rc == 0);
  228. counter+= msize
  229. )
  230. {
  231. uint8_t retryCounter;
  232. for(
  233. retryCounter = 0;
  234. retryCounter<GENDEV_RETRY_COUNT;
  235. retryCounter ++
  236. )
  237. {
  238. uint8_t wrByte[GENDEV_MAX_SIZE+2];
  239. wrByte[0] = (uint8_t) (counter>>0);
  240. if(eeprom_info.address_length > 1)
  241. {
  242. wrByte[1] = (uint8_t) (counter>>8);
  243. }
  244. i2caddr+= (((eeprom_info.size) % address_span_size) * 2);
  245. rsp = ipmi_master_write_read(
  246. intf,
  247. i2cbus,
  248. i2caddr,
  249. (uint8_t *) wrByte,
  250. eeprom_info.address_length,
  251. msize
  252. );
  253. if (rsp != NULL)
  254. {
  255. retryCounter = GENDEV_RETRY_COUNT;
  256. rc = 0;
  257. }
  258. else if(retryCounter < GENDEV_RETRY_COUNT)
  259. {
  260. retryCounter ++;
  261. lprintf(LOG_ERR, "Retry");
  262. sleep(1);
  263. rc = -1;
  264. }
  265. else
  266. {
  267. lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read");
  268. rc = -1;
  269. }
  270. }
  271. if( rc == 0 )
  272. {
  273. static uint8_t previousCompleted = 101;
  274. numWrite = fwrite(rsp->data, 1, msize, fp);
  275. if (numWrite != msize)
  276. {
  277. lprintf(LOG_ERR, "Error writing file %s", ofile);
  278. rc = -1;
  279. break;
  280. }
  281. percentCompleted = ((counter * 100) / eeprom_info.size );
  282. if(percentCompleted != previousCompleted)
  283. {
  284. printf("\r%i percent completed", percentCompleted);
  285. previousCompleted = percentCompleted;
  286. }
  287. }
  288. }
  289. if(counter == (eeprom_info.size))
  290. {
  291. printf("\r%%100 percent completed\n");
  292. }
  293. else
  294. {
  295. printf("\rError: %i percent completed, read not completed \n", percentCompleted);
  296. }
  297. fclose(fp);
  298. }
  299. }
  300. else
  301. {
  302. lprintf(LOG_ERR, "The selected generic device is not an eeprom");
  303. }
  304. return rc;
  305. }
  306. /* ipmi_gendev_write_file - Read raw SDR from binary file
  307. *
  308. * used for writing generic locator device Eeprom type
  309. *
  310. * @intf: ipmi interface
  311. * @dev: generic device to read
  312. * @ofile: output filename
  313. *
  314. * returns 0 on success
  315. * returns -1 on error
  316. */
  317. static int
  318. ipmi_gendev_write_file(
  319. struct ipmi_intf *intf,
  320. struct sdr_record_generic_locator *dev,
  321. const char *ofile
  322. )
  323. {
  324. int rc = 0;
  325. int eeprom_size;
  326. t_gendev_eeprom_info eeprom_info;
  327. eeprom_size = ipmi_gendev_get_eeprom_size(intf, dev, &eeprom_info);
  328. if(eeprom_size > 0)
  329. {
  330. FILE *fp;
  331. uint32_t fileLength = 0;
  332. /* now write to file */
  333. fp = ipmi_open_file_read(ofile);
  334. if(fp)
  335. {
  336. /* Retreive file length, check if it's fits the Eeprom Size */
  337. fseek(fp, 0 ,SEEK_END);
  338. fileLength = ftell(fp);
  339. lprintf(LOG_ERR, "File Size: %i", fileLength);
  340. lprintf(LOG_ERR, "Eeprom Size: %i", eeprom_size);
  341. if(fileLength != eeprom_size)
  342. {
  343. lprintf(LOG_ERR, "File size does not fit Eeprom Size");
  344. fclose(fp);
  345. fp = NULL;
  346. }
  347. else
  348. {
  349. fseek(fp, 0 ,SEEK_SET);
  350. }
  351. }
  352. if(fp)
  353. {
  354. struct ipmi_rs *rsp;
  355. int numRead;
  356. uint32_t counter;
  357. uint8_t msize;
  358. uint8_t channel = dev->channel_num;
  359. uint8_t i2cbus = dev->bus;
  360. uint8_t i2caddr = dev->dev_slave_addr;
  361. uint8_t privatebus = 1;
  362. uint32_t address_span_size;
  363. uint8_t percentCompleted = 0;
  364. /* Handle Address Span */
  365. if( eeprom_info.address_span != 0)
  366. {
  367. address_span_size =
  368. (eeprom_info.size / (eeprom_info.address_span+1));
  369. }
  370. else
  371. {
  372. address_span_size = eeprom_info.size;
  373. }
  374. /* Setup read/write size */
  375. if( eeprom_info.page_size < GENDEV_MAX_SIZE)
  376. {
  377. msize = eeprom_info.page_size;
  378. }
  379. else
  380. {
  381. msize = GENDEV_MAX_SIZE;
  382. // All eeprom with page higher than 32 is on the
  383. // 16 bytes boundary
  384. }
  385. /* Setup i2c bus byte */
  386. i2cbus = ((channel & 0xF) << 4) | ((i2cbus & 7) << 1) | privatebus;
  387. /*
  388. lprintf(LOG_ERR, "Generic device: %s", dev->id_string);
  389. lprintf(LOG_ERR, "I2C Chnl: %x", channel);
  390. lprintf(LOG_ERR, "I2C Bus : %x", i2cbus);
  391. lprintf(LOG_ERR, "I2C Addr: %x", i2caddr); */
  392. for (
  393. counter = 0;
  394. (counter < (eeprom_info.size)) && (rc == 0);
  395. counter+= msize
  396. )
  397. {
  398. uint8_t retryCounter;
  399. uint8_t readByte[GENDEV_MAX_SIZE];
  400. numRead = fread(readByte, 1, msize, fp);
  401. if (numRead != msize)
  402. {
  403. lprintf(LOG_ERR, "Error reading file %s", ofile);
  404. rc = -1;
  405. break;
  406. }
  407. for(
  408. retryCounter = 0;
  409. retryCounter<GENDEV_RETRY_COUNT;
  410. retryCounter ++
  411. )
  412. {
  413. uint8_t wrByte[GENDEV_MAX_SIZE+2];
  414. wrByte[0] = (uint8_t) (counter>>0);
  415. if(eeprom_info.address_length > 1)
  416. {
  417. wrByte[1] = (uint8_t) (counter>>8);
  418. }
  419. memcpy(&wrByte[eeprom_info.address_length], readByte, msize);
  420. i2caddr+= (((eeprom_info.size) % address_span_size) * 2);
  421. rsp = ipmi_master_write_read(intf, i2cbus, i2caddr, (uint8_t *) wrByte, eeprom_info.address_length+msize, 0);
  422. if (rsp != NULL)
  423. {
  424. retryCounter = GENDEV_RETRY_COUNT;
  425. rc = 0;
  426. }
  427. else if(retryCounter < GENDEV_RETRY_COUNT)
  428. {
  429. retryCounter ++;
  430. lprintf(LOG_ERR, "Retry");
  431. sleep(1);
  432. rc = -1;
  433. }
  434. else
  435. {
  436. lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read");
  437. rc = -1;
  438. }
  439. }
  440. if( rc == 0 )
  441. {
  442. static uint8_t previousCompleted = 101;
  443. percentCompleted = ((counter * 100) / eeprom_info.size );
  444. if(percentCompleted != previousCompleted)
  445. {
  446. printf("\r%i percent completed", percentCompleted);
  447. previousCompleted = percentCompleted;
  448. }
  449. }
  450. }
  451. if(counter == (eeprom_info.size))
  452. {
  453. printf("\r%%100 percent completed\n");
  454. }
  455. else
  456. {
  457. printf("\rError: %i percent completed, read not completed \n", percentCompleted);
  458. }
  459. fclose(fp);
  460. }
  461. }
  462. else
  463. {
  464. lprintf(LOG_ERR, "The selected generic device is not an eeprom");
  465. }
  466. return rc;
  467. }
  468. /* ipmi_gendev_main - top-level handler for generic device
  469. *
  470. * @intf: ipmi interface
  471. * @argc: number of arguments
  472. * @argv: argument list
  473. *
  474. * returns 0 on success
  475. * returns -1 on error
  476. */
  477. int
  478. ipmi_gendev_main(struct ipmi_intf *intf, int argc, char **argv)
  479. {
  480. int rc = 0;
  481. /* initialize random numbers used later */
  482. srand(time(NULL));
  483. lprintf(LOG_ERR, "Rx gendev command: %s", argv[0]);
  484. if (
  485. (argc == 0)
  486. ||
  487. (strncmp(argv[0], "help", 4) == 0)
  488. )
  489. {
  490. lprintf(LOG_ERR,
  491. "SDR Commands: list read write");
  492. lprintf(LOG_ERR,
  493. " list List All Generic Device Locators");
  494. lprintf(LOG_ERR,
  495. " read <sdr name> <file> Read to file eeprom specify by Generic Device Locators");
  496. lprintf(LOG_ERR,
  497. " write <sdr name> <file> Write from file eeprom specify by Generic Device Locators");
  498. }
  499. else if ( strncmp(argv[0], "list", 4) == 0)
  500. {
  501. rc = ipmi_sdr_print_sdr(intf,
  502. SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR);
  503. }
  504. else if (strncmp(argv[0], "read", 4) == 0)
  505. {
  506. if (argc < 3)
  507. lprintf(LOG_ERR, "usage: gendev read <gendev> <filename>");
  508. else
  509. {
  510. struct sdr_record_list *sdr;
  511. lprintf(LOG_ERR, "Gendev read sdr name : %s", argv[1]);
  512. printf("Locating sensor record '%s'...\n", argv[1]);
  513. /* lookup by sensor name */
  514. sdr = ipmi_sdr_find_sdr_byid(intf, argv[1]);
  515. if (sdr == NULL)
  516. {
  517. lprintf(LOG_ERR, "Sensor data record not found!");
  518. return -1;
  519. }
  520. if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
  521. {
  522. lprintf(LOG_ERR, "Target SDR is not a generic device locator");
  523. return -1;
  524. }
  525. lprintf(LOG_ERR, "Gendev read file name: %s", argv[2]);
  526. ipmi_gendev_read_file(intf, sdr->record.genloc, argv[2]);
  527. }
  528. }
  529. else if (strncmp(argv[0], "write", 5) == 0)
  530. {
  531. if (argc < 3)
  532. lprintf(LOG_ERR, "usage: gendev write <gendev> <filename>");
  533. else
  534. {
  535. struct sdr_record_list *sdr;
  536. lprintf(LOG_ERR, "Gendev write sdr name : %s", argv[1]);
  537. printf("Locating sensor record '%s'...\n", argv[1]);
  538. /* lookup by sensor name */
  539. sdr = ipmi_sdr_find_sdr_byid(intf, argv[1]);
  540. if (sdr == NULL)
  541. {
  542. lprintf(LOG_ERR, "Sensor data record not found!");
  543. return -1;
  544. }
  545. if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
  546. {
  547. lprintf(LOG_ERR, "Target SDR is not a generic device locator");
  548. return -1;
  549. }
  550. lprintf(LOG_ERR, "Gendev write file name: %s", argv[2]);
  551. ipmi_gendev_write_file(intf, sdr->record.genloc, argv[2]);
  552. }
  553. }
  554. else
  555. {
  556. lprintf(LOG_ERR, "Invalid gendev command: %s", argv[0]);
  557. rc = -1;
  558. }
  559. return rc;
  560. }