libifconfig_sfp.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. /*-
  2. * Copyright (c) 2014, Alexander V. Chernikov
  3. * Copyright (c) 2020, Ryan Moeller <freqlabs@FreeBSD.org>
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. * SUCH DAMAGE.
  25. */
  26. #include <sys/types.h>
  27. #include <sys/param.h>
  28. #include <sys/ioctl.h>
  29. #include <sys/socket.h>
  30. #include <net/if.h>
  31. #include <net/sff8436.h>
  32. #include <net/sff8472.h>
  33. #include <math.h>
  34. #include <err.h>
  35. #include <errno.h>
  36. #include <fcntl.h>
  37. #include <stdbool.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <unistd.h>
  42. #include <libifconfig.h>
  43. #include <libifconfig_internal.h>
  44. #include <libifconfig_sfp.h>
  45. #include <libifconfig_sfp_tables_internal.h>
  46. #define SFF_8636_EXT_COMPLIANCE 0x80
  47. struct i2c_info {
  48. struct ifreq ifr;
  49. ifconfig_handle_t *h;
  50. int error; /* Store first error */
  51. enum sfp_id id; /* Module type */
  52. };
  53. static uint8_t
  54. find_zero_bit(const struct sfp_enum_metadata *table, int value, int sz)
  55. {
  56. int v, m;
  57. for (v = 1, m = 1 << (8 * sz); v < m; v <<= 1) {
  58. if ((value & v) == 0)
  59. continue;
  60. if (find_metadata(table, value & v) != NULL) {
  61. return (value & v);
  62. }
  63. }
  64. return (0);
  65. }
  66. /*
  67. * Reads i2c data from opened kernel socket.
  68. */
  69. static int
  70. read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len,
  71. uint8_t *buf)
  72. {
  73. struct ifi2creq req;
  74. int i, l;
  75. if (ii->error != 0)
  76. return (ii->error);
  77. ii->ifr.ifr_data = (caddr_t)&req;
  78. i = 0;
  79. l = 0;
  80. memset(&req, 0, sizeof(req));
  81. req.dev_addr = addr;
  82. req.offset = off;
  83. req.len = len;
  84. while (len > 0) {
  85. l = MIN(sizeof(req.data), len);
  86. req.len = l;
  87. if (ifconfig_ioctlwrap(ii->h, AF_LOCAL, SIOCGI2C,
  88. &ii->ifr) != 0) {
  89. ii->error = errno;
  90. return (errno);
  91. }
  92. memcpy(&buf[i], req.data, l);
  93. len -= l;
  94. i += l;
  95. req.offset += l;
  96. }
  97. return (0);
  98. }
  99. static int
  100. i2c_info_init(struct i2c_info *ii, ifconfig_handle_t *h, const char *name)
  101. {
  102. uint8_t id_byte;
  103. memset(ii, 0, sizeof(*ii));
  104. strlcpy(ii->ifr.ifr_name, name, sizeof(ii->ifr.ifr_name));
  105. ii->h = h;
  106. /*
  107. * Try to read byte 0 from i2c:
  108. * Both SFF-8472 and SFF-8436 use it as
  109. * 'identification byte'.
  110. * Stop reading status on zero as value -
  111. * this might happen in case of empty transceiver slot.
  112. */
  113. id_byte = 0;
  114. read_i2c(ii, SFF_8472_BASE, SFF_8472_ID, 1, &id_byte);
  115. if (ii->error != 0)
  116. return (-1);
  117. if (id_byte == 0) {
  118. h->error.errtype = OTHER;
  119. h->error.errcode = ENOENT;
  120. return (-1);
  121. }
  122. ii->id = id_byte;
  123. return (0);
  124. }
  125. static int
  126. get_sfp_info(struct i2c_info *ii, struct ifconfig_sfp_info *sfp)
  127. {
  128. uint8_t code;
  129. read_i2c(ii, SFF_8472_BASE, SFF_8472_ID, 1, &sfp->sfp_id);
  130. read_i2c(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, &sfp->sfp_conn);
  131. /* Use extended compliance code if it's valid */
  132. read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS, 1, &sfp->sfp_eth_ext);
  133. if (sfp->sfp_eth_ext == 0) {
  134. /* Next, check 10G Ethernet/IB CCs */
  135. read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, &code);
  136. sfp->sfp_eth_10g = find_zero_bit(sfp_eth_10g_table, code, 1);
  137. if (sfp->sfp_eth_10g == 0) {
  138. /* No match. Try Ethernet 1G */
  139. read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3,
  140. 1, &code);
  141. sfp->sfp_eth = find_zero_bit(sfp_eth_table, code, 1);
  142. }
  143. }
  144. return (ii->error);
  145. }
  146. static int
  147. get_qsfp_info(struct i2c_info *ii, struct ifconfig_sfp_info *sfp)
  148. {
  149. uint8_t code;
  150. read_i2c(ii, SFF_8436_BASE, SFF_8436_ID, 1, &sfp->sfp_id);
  151. read_i2c(ii, SFF_8436_BASE, SFF_8436_CONNECTOR, 1, &sfp->sfp_conn);
  152. read_i2c(ii, SFF_8436_BASE, SFF_8436_STATUS, 1, &sfp->sfp_rev);
  153. /* Check for extended specification compliance */
  154. read_i2c(ii, SFF_8436_BASE, SFF_8436_CODE_E1040100G, 1, &code);
  155. if (code & SFF_8636_EXT_COMPLIANCE) {
  156. read_i2c(ii, SFF_8436_BASE, SFF_8436_OPTIONS_START, 1,
  157. &sfp->sfp_eth_ext);
  158. } else {
  159. /* Check 10/40G Ethernet class only */
  160. sfp->sfp_eth_1040g =
  161. find_zero_bit(sfp_eth_1040g_table, code, 1);
  162. }
  163. return (ii->error);
  164. }
  165. int
  166. ifconfig_sfp_get_sfp_info(ifconfig_handle_t *h,
  167. const char *name, struct ifconfig_sfp_info *sfp)
  168. {
  169. struct i2c_info ii;
  170. char buf[8];
  171. memset(sfp, 0, sizeof(*sfp));
  172. if (i2c_info_init(&ii, h, name) != 0)
  173. return (-1);
  174. /* Read bytes 3-10 at once */
  175. read_i2c(&ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, buf);
  176. if (ii.error != 0)
  177. return (ii.error);
  178. /* Check 10G ethernet first */
  179. sfp->sfp_eth_10g = find_zero_bit(sfp_eth_10g_table, buf[0], 1);
  180. if (sfp->sfp_eth_10g == 0) {
  181. /* No match. Try 1G */
  182. sfp->sfp_eth = find_zero_bit(sfp_eth_table, buf[3], 1);
  183. }
  184. sfp->sfp_fc_len = find_zero_bit(sfp_fc_len_table, buf[4], 1);
  185. sfp->sfp_fc_media = find_zero_bit(sfp_fc_media_table, buf[6], 1);
  186. sfp->sfp_fc_speed = find_zero_bit(sfp_fc_speed_table, buf[7], 1);
  187. sfp->sfp_cab_tech =
  188. find_zero_bit(sfp_cab_tech_table, (buf[4] << 8) | buf[5], 2);
  189. if (ifconfig_sfp_id_is_qsfp(ii.id))
  190. return (get_qsfp_info(&ii, sfp));
  191. return (get_sfp_info(&ii, sfp));
  192. }
  193. static size_t
  194. channel_count(enum sfp_id id)
  195. {
  196. /* TODO: other ids */
  197. switch (id) {
  198. case SFP_ID_UNKNOWN:
  199. return (0);
  200. case SFP_ID_QSFP:
  201. case SFP_ID_QSFPPLUS:
  202. case SFP_ID_QSFP28:
  203. return (4);
  204. default:
  205. return (1);
  206. }
  207. }
  208. size_t
  209. ifconfig_sfp_channel_count(const struct ifconfig_sfp_info *sfp)
  210. {
  211. return (channel_count(sfp->sfp_id));
  212. }
  213. /*
  214. * Print SFF-8472/SFF-8436 string to supplied buffer.
  215. * All (vendor-specific) strings are padded right with '0x20'.
  216. */
  217. static void
  218. get_sff_string(struct i2c_info *ii, uint8_t addr, uint8_t off, char *dst)
  219. {
  220. read_i2c(ii, addr, off, SFF_VENDOR_STRING_SIZE, dst);
  221. dst += SFF_VENDOR_STRING_SIZE;
  222. do { *dst-- = '\0'; } while (*dst == 0x20);
  223. }
  224. static void
  225. get_sff_date(struct i2c_info *ii, uint8_t addr, uint8_t off, char *dst)
  226. {
  227. char buf[SFF_VENDOR_DATE_SIZE];
  228. read_i2c(ii, addr, off, SFF_VENDOR_DATE_SIZE, buf);
  229. sprintf(dst, "20%c%c-%c%c-%c%c", buf[0], buf[1], buf[2], buf[3],
  230. buf[4], buf[5]);
  231. }
  232. static int
  233. get_sfp_vendor_info(struct i2c_info *ii, struct ifconfig_sfp_vendor_info *vi)
  234. {
  235. get_sff_string(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, vi->name);
  236. get_sff_string(ii, SFF_8472_BASE, SFF_8472_PN_START, vi->pn);
  237. get_sff_string(ii, SFF_8472_BASE, SFF_8472_SN_START, vi->sn);
  238. get_sff_date(ii, SFF_8472_BASE, SFF_8472_DATE_START, vi->date);
  239. return (ii->error);
  240. }
  241. static int
  242. get_qsfp_vendor_info(struct i2c_info *ii, struct ifconfig_sfp_vendor_info *vi)
  243. {
  244. get_sff_string(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, vi->name);
  245. get_sff_string(ii, SFF_8436_BASE, SFF_8436_PN_START, vi->pn);
  246. get_sff_string(ii, SFF_8436_BASE, SFF_8436_SN_START, vi->sn);
  247. get_sff_date(ii, SFF_8436_BASE, SFF_8436_DATE_START, vi->date);
  248. return (ii->error);
  249. }
  250. int
  251. ifconfig_sfp_get_sfp_vendor_info(ifconfig_handle_t *h,
  252. const char *name, struct ifconfig_sfp_vendor_info *vi)
  253. {
  254. struct i2c_info ii;
  255. memset(vi, 0, sizeof(*vi));
  256. if (i2c_info_init(&ii, h, name) != 0)
  257. return (-1);
  258. if (ifconfig_sfp_id_is_qsfp(ii.id))
  259. return (get_qsfp_vendor_info(&ii, vi));
  260. return (get_sfp_vendor_info(&ii, vi));
  261. }
  262. /*
  263. * Converts internal temperature (SFF-8472, SFF-8436)
  264. * 16-bit unsigned value to human-readable representation:
  265. *
  266. * Internally measured Module temperature are represented
  267. * as a 16-bit signed twos complement value in increments of
  268. * 1/256 degrees Celsius, yielding a total range of –128C to +128C
  269. * that is considered valid between –40 and +125C.
  270. */
  271. static double
  272. get_sff_temp(struct i2c_info *ii, uint8_t addr, uint8_t off)
  273. {
  274. double d;
  275. uint8_t buf[2];
  276. read_i2c(ii, addr, off, 2, buf);
  277. d = (double)buf[0];
  278. d += (double)buf[1] / 256;
  279. return (d);
  280. }
  281. /*
  282. * Retrieves supplied voltage (SFF-8472, SFF-8436).
  283. * 16-bit usigned value, treated as range 0..+6.55 Volts
  284. */
  285. static double
  286. get_sff_voltage(struct i2c_info *ii, uint8_t addr, uint8_t off)
  287. {
  288. double d;
  289. uint8_t buf[2];
  290. read_i2c(ii, addr, off, 2, buf);
  291. d = (double)((buf[0] << 8) | buf[1]);
  292. return (d / 10000);
  293. }
  294. /*
  295. * The following conversions assume internally-calibrated data.
  296. * This is always true for SFF-8346, and explicitly checked for SFF-8472.
  297. */
  298. double
  299. power_mW(uint16_t power)
  300. {
  301. /* Power is specified in units of 0.1 uW. */
  302. return (1.0 * power / 10000);
  303. }
  304. double
  305. power_dBm(uint16_t power)
  306. {
  307. return (10.0 * log10(power_mW(power)));
  308. }
  309. double
  310. bias_mA(uint16_t bias)
  311. {
  312. /* Bias current is specified in units of 2 uA. */
  313. return (1.0 * bias / 500);
  314. }
  315. static uint16_t
  316. get_sff_channel(struct i2c_info *ii, uint8_t addr, uint8_t off)
  317. {
  318. uint8_t buf[2];
  319. read_i2c(ii, addr, off, 2, buf);
  320. if (ii->error != 0)
  321. return (0);
  322. return ((buf[0] << 8) + buf[1]);
  323. }
  324. static int
  325. get_sfp_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss)
  326. {
  327. uint8_t diag_type, flags;
  328. /* Read diagnostic monitoring type */
  329. read_i2c(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&diag_type);
  330. if (ii->error != 0)
  331. return (-1);
  332. /*
  333. * Read monitoring data IFF it is supplied AND is
  334. * internally calibrated
  335. */
  336. flags = SFF_8472_DDM_DONE | SFF_8472_DDM_INTERNAL;
  337. if ((diag_type & flags) != flags) {
  338. ii->h->error.errtype = OTHER;
  339. ii->h->error.errcode = ENXIO;
  340. return (-1);
  341. }
  342. ss->temp = get_sff_temp(ii, SFF_8472_DIAG, SFF_8472_TEMP);
  343. ss->voltage = get_sff_voltage(ii, SFF_8472_DIAG, SFF_8472_VCC);
  344. ss->channel = calloc(channel_count(ii->id), sizeof(*ss->channel));
  345. if (ss->channel == NULL) {
  346. ii->h->error.errtype = OTHER;
  347. ii->h->error.errcode = ENOMEM;
  348. return (-1);
  349. }
  350. ss->channel[0].rx = get_sff_channel(ii, SFF_8472_DIAG, SFF_8472_RX_POWER);
  351. ss->channel[0].tx = get_sff_channel(ii, SFF_8472_DIAG, SFF_8472_TX_BIAS);
  352. return (ii->error);
  353. }
  354. static uint32_t
  355. get_qsfp_bitrate(struct i2c_info *ii)
  356. {
  357. uint8_t code;
  358. uint32_t rate;
  359. code = 0;
  360. read_i2c(ii, SFF_8436_BASE, SFF_8436_BITRATE, 1, &code);
  361. rate = code * 100;
  362. if (code == 0xFF) {
  363. read_i2c(ii, SFF_8436_BASE, SFF_8636_BITRATE, 1, &code);
  364. rate = code * 250;
  365. }
  366. return (rate);
  367. }
  368. static int
  369. get_qsfp_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss)
  370. {
  371. size_t channels;
  372. ss->temp = get_sff_temp(ii, SFF_8436_BASE, SFF_8436_TEMP);
  373. ss->voltage = get_sff_voltage(ii, SFF_8436_BASE, SFF_8436_VCC);
  374. channels = channel_count(ii->id);
  375. ss->channel = calloc(channels, sizeof(*ss->channel));
  376. if (ss->channel == NULL) {
  377. ii->h->error.errtype = OTHER;
  378. ii->h->error.errcode = ENOMEM;
  379. return (-1);
  380. }
  381. for (size_t chan = 0; chan < channels; ++chan) {
  382. uint8_t rxoffs = SFF_8436_RX_CH1_MSB + chan * sizeof(uint16_t);
  383. uint8_t txoffs = SFF_8436_TX_CH1_MSB + chan * sizeof(uint16_t);
  384. ss->channel[chan].rx =
  385. get_sff_channel(ii, SFF_8436_BASE, rxoffs);
  386. ss->channel[chan].tx =
  387. get_sff_channel(ii, SFF_8436_BASE, txoffs);
  388. }
  389. ss->bitrate = get_qsfp_bitrate(ii);
  390. return (ii->error);
  391. }
  392. int
  393. ifconfig_sfp_get_sfp_status(ifconfig_handle_t *h, const char *name,
  394. struct ifconfig_sfp_status *ss)
  395. {
  396. struct i2c_info ii;
  397. memset(ss, 0, sizeof(*ss));
  398. if (i2c_info_init(&ii, h, name) != 0)
  399. return (-1);
  400. if (ifconfig_sfp_id_is_qsfp(ii.id))
  401. return (get_qsfp_status(&ii, ss));
  402. return (get_sfp_status(&ii, ss));
  403. }
  404. void
  405. ifconfig_sfp_free_sfp_status(struct ifconfig_sfp_status *ss)
  406. {
  407. if (ss != NULL)
  408. free(ss->channel);
  409. }
  410. static const char *
  411. sfp_id_string_alt(uint8_t value)
  412. {
  413. const char *id;
  414. if (value <= SFF_8024_ID_LAST)
  415. id = sff_8024_id[value];
  416. else if (value > 0x80)
  417. id = "Vendor specific";
  418. else
  419. id = "Reserved";
  420. return (id);
  421. }
  422. static const char *
  423. sfp_conn_string_alt(uint8_t value)
  424. {
  425. const char *conn;
  426. if (value >= 0x0D && value <= 0x1F)
  427. conn = "Unallocated";
  428. else if (value >= 0x24 && value <= 0x7F)
  429. conn = "Unallocated";
  430. else
  431. conn = "Vendor specific";
  432. return (conn);
  433. }
  434. void
  435. ifconfig_sfp_get_sfp_info_strings(const struct ifconfig_sfp_info *sfp,
  436. struct ifconfig_sfp_info_strings *strings)
  437. {
  438. get_sfp_info_strings(sfp, strings);
  439. if (strings->sfp_id == NULL)
  440. strings->sfp_id = sfp_id_string_alt(sfp->sfp_id);
  441. if (strings->sfp_conn == NULL)
  442. strings->sfp_conn = sfp_conn_string_alt(sfp->sfp_conn);
  443. if (strings->sfp_rev == NULL)
  444. strings->sfp_rev = "Unallocated";
  445. }
  446. const char *
  447. ifconfig_sfp_physical_spec(const struct ifconfig_sfp_info *sfp,
  448. const struct ifconfig_sfp_info_strings *strings)
  449. {
  450. switch (sfp->sfp_id) {
  451. case SFP_ID_UNKNOWN:
  452. break;
  453. case SFP_ID_QSFP:
  454. case SFP_ID_QSFPPLUS:
  455. case SFP_ID_QSFP28:
  456. if (sfp->sfp_eth_1040g & SFP_ETH_1040G_EXTENDED)
  457. return (strings->sfp_eth_ext);
  458. else if (sfp->sfp_eth_1040g)
  459. return (strings->sfp_eth_1040g);
  460. break;
  461. default:
  462. if (sfp->sfp_eth_ext)
  463. return (strings->sfp_eth_ext);
  464. else if (sfp->sfp_eth_10g)
  465. return (strings->sfp_eth_10g);
  466. else if (sfp->sfp_eth)
  467. return (strings->sfp_eth);
  468. break;
  469. }
  470. return ("Unknown");
  471. }
  472. int
  473. ifconfig_sfp_get_sfp_dump(ifconfig_handle_t *h, const char *name,
  474. struct ifconfig_sfp_dump *dump)
  475. {
  476. struct i2c_info ii;
  477. uint8_t *buf = dump->data;
  478. memset(dump->data, 0, sizeof(dump->data));
  479. if (i2c_info_init(&ii, h, name) != 0)
  480. return (-1);
  481. if (ifconfig_sfp_id_is_qsfp(ii.id)) {
  482. read_i2c(&ii, SFF_8436_BASE, QSFP_DUMP0_START, QSFP_DUMP0_SIZE,
  483. buf + QSFP_DUMP0_START);
  484. read_i2c(&ii, SFF_8436_BASE, QSFP_DUMP1_START, QSFP_DUMP1_SIZE,
  485. buf + QSFP_DUMP1_START);
  486. } else {
  487. read_i2c(&ii, SFF_8472_BASE, SFP_DUMP_START, SFP_DUMP_SIZE,
  488. buf + SFP_DUMP_START);
  489. }
  490. return (ii.error != 0 ? -1 : 0);
  491. }
  492. size_t
  493. ifconfig_sfp_dump_region_count(const struct ifconfig_sfp_dump *dp)
  494. {
  495. uint8_t id_byte = dp->data[0];
  496. switch ((enum sfp_id)id_byte) {
  497. case SFP_ID_UNKNOWN:
  498. return (0);
  499. case SFP_ID_QSFP:
  500. case SFP_ID_QSFPPLUS:
  501. case SFP_ID_QSFP28:
  502. return (2);
  503. default:
  504. return (1);
  505. }
  506. }