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
27 #define _WANT_SFF_8024_ID
28
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33
34 #include <net/if.h>
35 #include <net/cmis.h>
36 #include <net/sff8436.h>
37 #include <net/sff8472.h>
38
39 #include <math.h>
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdbool.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48
49 #include <libifconfig.h>
50 #include <libifconfig_internal.h>
51 #include <libifconfig_sfp.h>
52 #include <libifconfig_sfp_tables_internal.h>
53
54 #define SFF_8636_EXT_COMPLIANCE 0x80
55
56 struct i2c_info {
57 struct ifreq ifr;
58 ifconfig_handle_t *h;
59 int error; /* Store first error */
60 enum sfp_id id; /* Module type */
61 };
62
63 static uint8_t
find_zero_bit(const struct sfp_enum_metadata * table,int value,int sz)64 find_zero_bit(const struct sfp_enum_metadata *table, int value, int sz)
65 {
66 int v, m;
67
68 for (v = 1, m = 1 << (8 * sz); v < m; v <<= 1) {
69 if ((value & v) == 0)
70 continue;
71 if (find_metadata(table, value & v) != NULL) {
72 return (value & v);
73 }
74 }
75 return (0);
76 }
77
78 /*
79 * Reads i2c data from opened kernel socket.
80 */
81 static int
read_i2c(struct i2c_info * ii,uint8_t addr,uint8_t off,uint8_t len,uint8_t * buf)82 read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len,
83 uint8_t *buf)
84 {
85 struct ifi2creq req;
86 int i, l;
87
88 if (ii->error != 0)
89 return (ii->error);
90
91 ii->ifr.ifr_data = (caddr_t)&req;
92
93 i = 0;
94 l = 0;
95 memset(&req, 0, sizeof(req));
96 req.dev_addr = addr;
97 req.offset = off;
98 req.len = len;
99
100 while (len > 0) {
101 l = MIN(sizeof(req.data), len);
102 req.len = l;
103 if (ifconfig_ioctlwrap(ii->h, AF_LOCAL, SIOCGI2C,
104 &ii->ifr) != 0) {
105 ii->error = errno;
106 return (errno);
107 }
108
109 memcpy(&buf[i], req.data, l);
110 len -= l;
111 i += l;
112 req.offset += l;
113 }
114
115 return (0);
116 }
117
118 /*
119 * Reads i2c data with CMIS page/bank selection.
120 * For upper memory (offset >= 128), the page and bank fields select
121 * which CMIS register page is mapped into the 128-255 address range.
122 */
123 static int
read_i2c_page(struct i2c_info * ii,uint8_t addr,uint8_t page,uint8_t bank,uint8_t off,uint8_t len,uint8_t * buf)124 read_i2c_page(struct i2c_info *ii, uint8_t addr, uint8_t page, uint8_t bank,
125 uint8_t off, uint8_t len, uint8_t *buf)
126 {
127 struct ifi2creq req;
128 int i, l;
129
130 if (ii->error != 0)
131 return (ii->error);
132
133 ii->ifr.ifr_data = (caddr_t)&req;
134
135 i = 0;
136 l = 0;
137 memset(&req, 0, sizeof(req));
138 req.dev_addr = addr;
139 req.offset = off;
140 req.len = len;
141 req.page = page;
142 req.bank = bank;
143
144 while (len > 0) {
145 l = MIN(sizeof(req.data), len);
146 req.len = l;
147 if (ifconfig_ioctlwrap(ii->h, AF_LOCAL, SIOCGI2CPB,
148 &ii->ifr) != 0) {
149 ii->error = errno;
150 return (errno);
151 }
152
153 memcpy(&buf[i], req.data, l);
154 len -= l;
155 i += l;
156 req.offset += l;
157 }
158
159 return (0);
160 }
161
162 static int
i2c_info_init(struct i2c_info * ii,ifconfig_handle_t * h,const char * name)163 i2c_info_init(struct i2c_info *ii, ifconfig_handle_t *h, const char *name)
164 {
165 uint8_t id_byte;
166
167 memset(ii, 0, sizeof(*ii));
168 strlcpy(ii->ifr.ifr_name, name, sizeof(ii->ifr.ifr_name));
169 ii->h = h;
170
171 /*
172 * Try to read byte 0 from i2c:
173 * Both SFF-8472 and SFF-8436 use it as
174 * 'identification byte'.
175 * Stop reading status on zero as value -
176 * this might happen in case of empty transceiver slot.
177 */
178 id_byte = 0;
179 read_i2c(ii, SFF_8472_BASE, SFF_8472_ID, 1, &id_byte);
180 if (ii->error != 0)
181 return (-1);
182 if (id_byte == 0) {
183 h->error.errtype = OTHER;
184 h->error.errcode = ENOENT;
185 return (-1);
186 }
187 ii->id = id_byte;
188 return (0);
189 }
190
191 static int
get_sfp_info(struct i2c_info * ii,struct ifconfig_sfp_info * sfp)192 get_sfp_info(struct i2c_info *ii, struct ifconfig_sfp_info *sfp)
193 {
194 uint8_t code;
195
196 read_i2c(ii, SFF_8472_BASE, SFF_8472_ID, 1, &sfp->sfp_id);
197 read_i2c(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, &sfp->sfp_conn);
198
199 /* Use extended compliance code if it's valid */
200 read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS, 1, &sfp->sfp_eth_ext);
201 if (sfp->sfp_eth_ext == 0) {
202 /* Next, check 10G Ethernet/IB CCs */
203 read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, &code);
204 sfp->sfp_eth_10g = find_zero_bit(sfp_eth_10g_table, code, 1);
205 if (sfp->sfp_eth_10g == 0) {
206 /* No match. Try Ethernet 1G */
207 read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3,
208 1, &code);
209 sfp->sfp_eth = find_zero_bit(sfp_eth_table, code, 1);
210 }
211 }
212
213 return (ii->error);
214 }
215
216 static int
get_qsfp_info(struct i2c_info * ii,struct ifconfig_sfp_info * sfp)217 get_qsfp_info(struct i2c_info *ii, struct ifconfig_sfp_info *sfp)
218 {
219 uint8_t code;
220
221 read_i2c(ii, SFF_8436_BASE, SFF_8436_ID, 1, &sfp->sfp_id);
222 read_i2c(ii, SFF_8436_BASE, SFF_8436_CONNECTOR, 1, &sfp->sfp_conn);
223
224 read_i2c(ii, SFF_8436_BASE, SFF_8436_STATUS, 1, &sfp->sfp_rev);
225
226 /* Check for extended specification compliance */
227 read_i2c(ii, SFF_8436_BASE, SFF_8436_CODE_E1040100G, 1, &code);
228 if (code & SFF_8636_EXT_COMPLIANCE) {
229 read_i2c(ii, SFF_8436_BASE, SFF_8436_OPTIONS_START, 1,
230 &sfp->sfp_eth_ext);
231 sfp->sfp_eth_1040g = code;
232 } else {
233 /* Check 10/40G Ethernet class only */
234 sfp->sfp_eth_1040g =
235 find_zero_bit(sfp_eth_1040g_table, code, 1);
236 }
237
238 return (ii->error);
239 }
240
241 static int
get_cmis_info(struct i2c_info * ii,struct ifconfig_sfp_info * sfp)242 get_cmis_info(struct i2c_info *ii, struct ifconfig_sfp_info *sfp)
243 {
244 uint8_t app_desc[CMIS_APP_DESC_SIZE];
245 uint8_t dpconfig, appsel;
246 uint8_t app_off;
247
248 /* Module ID from lower memory byte 0 */
249 read_i2c(ii, CMIS_BASE, CMIS_ID, 1, &sfp->sfp_id);
250
251 /* Connector type from Page 00h byte 203 */
252 read_i2c_page(ii, CMIS_BASE, 0x00, 0,
253 CMIS_P0_CONNECTOR, 1, &sfp->sfp_conn);
254
255 /* Media type from lower memory byte 85 */
256 read_i2c(ii, CMIS_BASE, CMIS_MEDIA_TYPE, 1,
257 &sfp->sfp_cmis_media_type);
258
259 /*
260 * Read the active AppSel code from the Active Control Set
261 * (Page 11h, byte 206, bits 7:4). This tells us which
262 * Application Descriptor is actually in use.
263 * AppSel is 1-based; 0 means no application selected.
264 */
265 dpconfig = 0;
266 read_i2c_page(ii, CMIS_BASE, 0x11, 0,
267 CMIS_P11_ACS_DPCONFIG1, 1, &dpconfig);
268 appsel = (dpconfig & CMIS_ACS_APPSEL_MASK) >> CMIS_ACS_APPSEL_SHIFT;
269
270 /* Fall back to first descriptor if AppSel is 0 or out of range */
271 if (appsel == 0 || appsel > CMIS_MAX_APP_DESC)
272 appsel = 1;
273
274 /* Read the active Application Descriptor */
275 app_off = CMIS_APP_DESC_START + (appsel - 1) * CMIS_APP_DESC_SIZE;
276 read_i2c(ii, CMIS_BASE, app_off, CMIS_APP_DESC_SIZE, app_desc);
277 if (ii->error != 0)
278 return (ii->error);
279
280 /* Store MediaInterfaceID based on media type */
281 switch (sfp->sfp_cmis_media_type) {
282 case SFP_CMIS_MEDIA_TYPE_SMF:
283 sfp->sfp_cmis_smf = app_desc[CMIS_APP_MEDIA_IF_ID];
284 break;
285 case SFP_CMIS_MEDIA_TYPE_MMF:
286 sfp->sfp_cmis_mmf = app_desc[CMIS_APP_MEDIA_IF_ID];
287 break;
288 }
289
290 /* Extract media lane count from app descriptor byte 2, bits 3:0 */
291 sfp->sfp_cmis_lanes = app_desc[CMIS_APP_LANE_COUNT] & 0x0F;
292
293 return (ii->error);
294 }
295
296 int
ifconfig_sfp_get_sfp_info(ifconfig_handle_t * h,const char * name,struct ifconfig_sfp_info * sfp)297 ifconfig_sfp_get_sfp_info(ifconfig_handle_t *h,
298 const char *name, struct ifconfig_sfp_info *sfp)
299 {
300 struct i2c_info ii;
301 uint8_t buf[8];
302
303 memset(sfp, 0, sizeof(*sfp));
304
305 if (i2c_info_init(&ii, h, name) != 0)
306 return (-1);
307
308 if (ifconfig_sfp_id_is_cmis(ii.id))
309 return (get_cmis_info(&ii, sfp));
310
311 /* Read bytes 3-10 at once */
312 read_i2c(&ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, buf);
313 if (ii.error != 0)
314 return (ii.error);
315
316 /* Check 10G ethernet first */
317 sfp->sfp_eth_10g = find_zero_bit(sfp_eth_10g_table, buf[0], 1);
318 if (sfp->sfp_eth_10g == 0) {
319 /* No match. Try 1G */
320 sfp->sfp_eth = find_zero_bit(sfp_eth_table, buf[3], 1);
321 }
322 sfp->sfp_fc_len = find_zero_bit(sfp_fc_len_table, buf[4], 1);
323 sfp->sfp_fc_media = find_zero_bit(sfp_fc_media_table, buf[6], 1);
324 sfp->sfp_fc_speed = find_zero_bit(sfp_fc_speed_table, buf[7], 1);
325 sfp->sfp_cab_tech =
326 find_zero_bit(sfp_cab_tech_table, (buf[4] << 8) | buf[5], 2);
327
328 if (ifconfig_sfp_id_is_qsfp(ii.id))
329 return (get_qsfp_info(&ii, sfp));
330 return (get_sfp_info(&ii, sfp));
331 }
332
333 static size_t
channel_count(enum sfp_id id)334 channel_count(enum sfp_id id)
335 {
336 /* TODO: other ids */
337 switch (id) {
338 case SFP_ID_UNKNOWN:
339 return (0);
340 case SFP_ID_QSFP:
341 case SFP_ID_QSFPPLUS:
342 case SFP_ID_QSFP28:
343 return (4);
344 default:
345 return (1);
346 }
347 }
348
349 size_t
ifconfig_sfp_channel_count(const struct ifconfig_sfp_info * sfp)350 ifconfig_sfp_channel_count(const struct ifconfig_sfp_info *sfp)
351 {
352 /* CMIS modules: use lane count from Application Descriptor */
353 if (ifconfig_sfp_id_is_cmis(sfp->sfp_id)) {
354 if (sfp->sfp_cmis_lanes > 0)
355 return (sfp->sfp_cmis_lanes);
356 return (0);
357 }
358 return (channel_count(sfp->sfp_id));
359 }
360
361 /*
362 * Print SFF-8472/SFF-8436 string to supplied buffer.
363 * All (vendor-specific) strings are padded right with '0x20'.
364 */
365 static void
get_sff_string(struct i2c_info * ii,uint8_t addr,uint8_t off,char * dst)366 get_sff_string(struct i2c_info *ii, uint8_t addr, uint8_t off, char *dst)
367 {
368 read_i2c(ii, addr, off, SFF_VENDOR_STRING_SIZE, (uint8_t *)dst);
369 dst += SFF_VENDOR_STRING_SIZE;
370 do { *dst-- = '\0'; } while (*dst == 0x20);
371 }
372
373 static void
get_sff_date(struct i2c_info * ii,uint8_t addr,uint8_t off,char * dst)374 get_sff_date(struct i2c_info *ii, uint8_t addr, uint8_t off, char *dst)
375 {
376 uint8_t buf[SFF_VENDOR_DATE_SIZE];
377
378 read_i2c(ii, addr, off, SFF_VENDOR_DATE_SIZE, buf);
379 sprintf(dst, "20%c%c-%c%c-%c%c", buf[0], buf[1], buf[2], buf[3],
380 buf[4], buf[5]);
381 }
382
383 static int
get_sfp_vendor_info(struct i2c_info * ii,struct ifconfig_sfp_vendor_info * vi)384 get_sfp_vendor_info(struct i2c_info *ii, struct ifconfig_sfp_vendor_info *vi)
385 {
386 get_sff_string(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, vi->name);
387 get_sff_string(ii, SFF_8472_BASE, SFF_8472_PN_START, vi->pn);
388 get_sff_string(ii, SFF_8472_BASE, SFF_8472_SN_START, vi->sn);
389 get_sff_date(ii, SFF_8472_BASE, SFF_8472_DATE_START, vi->date);
390 return (ii->error);
391 }
392
393 static int
get_qsfp_vendor_info(struct i2c_info * ii,struct ifconfig_sfp_vendor_info * vi)394 get_qsfp_vendor_info(struct i2c_info *ii, struct ifconfig_sfp_vendor_info *vi)
395 {
396 get_sff_string(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, vi->name);
397 get_sff_string(ii, SFF_8436_BASE, SFF_8436_PN_START, vi->pn);
398 get_sff_string(ii, SFF_8436_BASE, SFF_8436_SN_START, vi->sn);
399 get_sff_date(ii, SFF_8436_BASE, SFF_8436_DATE_START, vi->date);
400 return (ii->error);
401 }
402
403 /*
404 * Read CMIS vendor strings from Page 00h (upper memory).
405 * Vendor info uses the same ASCII format as SFF-8436 but at
406 * different offsets and requires page selection.
407 */
408 static void
get_cmis_string(struct i2c_info * ii,uint8_t off,char * dst)409 get_cmis_string(struct i2c_info *ii, uint8_t off, char *dst)
410 {
411 read_i2c_page(ii, CMIS_BASE, 0x00, 0, off,
412 SFF_VENDOR_STRING_SIZE, dst);
413 dst += SFF_VENDOR_STRING_SIZE;
414 do { *dst-- = '\0'; } while (*dst == 0x20);
415 }
416
417 static void
get_cmis_date(struct i2c_info * ii,uint8_t off,char * dst)418 get_cmis_date(struct i2c_info *ii, uint8_t off, char *dst)
419 {
420 char buf[SFF_VENDOR_DATE_SIZE];
421
422 read_i2c_page(ii, CMIS_BASE, 0x00, 0, off,
423 SFF_VENDOR_DATE_SIZE, buf);
424 sprintf(dst, "20%c%c-%c%c-%c%c", buf[0], buf[1], buf[2], buf[3],
425 buf[4], buf[5]);
426 }
427
428 static int
get_cmis_vendor_info(struct i2c_info * ii,struct ifconfig_sfp_vendor_info * vi)429 get_cmis_vendor_info(struct i2c_info *ii, struct ifconfig_sfp_vendor_info *vi)
430 {
431 get_cmis_string(ii, CMIS_P0_VENDOR_NAME, vi->name);
432 get_cmis_string(ii, CMIS_P0_VENDOR_PN, vi->pn);
433 get_cmis_string(ii, CMIS_P0_VENDOR_SN, vi->sn);
434 get_cmis_date(ii, CMIS_P0_DATE_CODE, vi->date);
435 return (ii->error);
436 }
437
438 int
ifconfig_sfp_get_sfp_vendor_info(ifconfig_handle_t * h,const char * name,struct ifconfig_sfp_vendor_info * vi)439 ifconfig_sfp_get_sfp_vendor_info(ifconfig_handle_t *h,
440 const char *name, struct ifconfig_sfp_vendor_info *vi)
441 {
442 struct i2c_info ii;
443
444 memset(vi, 0, sizeof(*vi));
445
446 if (i2c_info_init(&ii, h, name) != 0)
447 return (-1);
448
449 if (ifconfig_sfp_id_is_cmis(ii.id))
450 return (get_cmis_vendor_info(&ii, vi));
451 if (ifconfig_sfp_id_is_qsfp(ii.id))
452 return (get_qsfp_vendor_info(&ii, vi));
453 return (get_sfp_vendor_info(&ii, vi));
454 }
455
456 /*
457 * Converts internal temperature (SFF-8472, SFF-8436)
458 * 16-bit unsigned value to human-readable representation:
459 *
460 * Internally measured Module temperature are represented
461 * as a 16-bit signed twos complement value in increments of
462 * 1/256 degrees Celsius, yielding a total range of –128C to +128C
463 * that is considered valid between –40 and +125C.
464 */
465 static double
get_sff_temp(struct i2c_info * ii,uint8_t addr,uint8_t off)466 get_sff_temp(struct i2c_info *ii, uint8_t addr, uint8_t off)
467 {
468 double d;
469 uint8_t buf[2];
470
471 read_i2c(ii, addr, off, 2, buf);
472 d = (double)buf[0];
473 d += (double)buf[1] / 256;
474 return (d);
475 }
476
477 /*
478 * Retrieves supplied voltage (SFF-8472, SFF-8436).
479 * 16-bit usigned value, treated as range 0..+6.55 Volts
480 */
481 static double
get_sff_voltage(struct i2c_info * ii,uint8_t addr,uint8_t off)482 get_sff_voltage(struct i2c_info *ii, uint8_t addr, uint8_t off)
483 {
484 double d;
485 uint8_t buf[2];
486
487 read_i2c(ii, addr, off, 2, buf);
488 d = (double)((buf[0] << 8) | buf[1]);
489 return (d / 10000);
490 }
491
492 /*
493 * The following conversions assume internally-calibrated data.
494 * This is always true for SFF-8346, and explicitly checked for SFF-8472.
495 */
496
497 double
power_mW(uint16_t power)498 power_mW(uint16_t power)
499 {
500 /* Power is specified in units of 0.1 uW. */
501 return (1.0 * power / 10000);
502 }
503
504 double
power_dBm(uint16_t power)505 power_dBm(uint16_t power)
506 {
507 return (10.0 * log10(power_mW(power)));
508 }
509
510 double
bias_mA(uint16_t bias)511 bias_mA(uint16_t bias)
512 {
513 /* Bias current is specified in units of 2 uA. */
514 return (1.0 * bias / 500);
515 }
516
517 static uint16_t
get_sff_channel(struct i2c_info * ii,uint8_t addr,uint8_t off)518 get_sff_channel(struct i2c_info *ii, uint8_t addr, uint8_t off)
519 {
520 uint8_t buf[2];
521
522 read_i2c(ii, addr, off, 2, buf);
523 if (ii->error != 0)
524 return (0);
525
526 return ((buf[0] << 8) + buf[1]);
527 }
528
529 static int
get_sfp_status(struct i2c_info * ii,struct ifconfig_sfp_status * ss)530 get_sfp_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss)
531 {
532 uint8_t diag_type, flags;
533
534 /* Read diagnostic monitoring type */
535 read_i2c(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, &diag_type);
536 if (ii->error != 0)
537 return (-1);
538
539 /*
540 * Read monitoring data IFF it is supplied AND is
541 * internally calibrated
542 */
543 flags = SFF_8472_DDM_DONE | SFF_8472_DDM_INTERNAL;
544 if ((diag_type & flags) != flags) {
545 ii->h->error.errtype = OTHER;
546 ii->h->error.errcode = ENXIO;
547 return (-1);
548 }
549
550 ss->temp = get_sff_temp(ii, SFF_8472_DIAG, SFF_8472_TEMP);
551 ss->voltage = get_sff_voltage(ii, SFF_8472_DIAG, SFF_8472_VCC);
552 ss->channel = calloc(channel_count(ii->id), sizeof(*ss->channel));
553 if (ss->channel == NULL) {
554 ii->h->error.errtype = OTHER;
555 ii->h->error.errcode = ENOMEM;
556 return (-1);
557 }
558 ss->channel[0].rx = get_sff_channel(ii, SFF_8472_DIAG, SFF_8472_RX_POWER);
559 ss->channel[0].tx = get_sff_channel(ii, SFF_8472_DIAG, SFF_8472_TX_BIAS);
560 return (ii->error);
561 }
562
563 static uint32_t
get_qsfp_bitrate(struct i2c_info * ii)564 get_qsfp_bitrate(struct i2c_info *ii)
565 {
566 uint8_t code;
567 uint32_t rate;
568
569 code = 0;
570 read_i2c(ii, SFF_8436_BASE, SFF_8436_BITRATE, 1, &code);
571 rate = code * 100;
572 if (code == 0xFF) {
573 read_i2c(ii, SFF_8436_BASE, SFF_8636_BITRATE, 1, &code);
574 rate = code * 250;
575 }
576
577 return (rate);
578 }
579
580 static int
get_qsfp_status(struct i2c_info * ii,struct ifconfig_sfp_status * ss)581 get_qsfp_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss)
582 {
583 size_t channels;
584
585 ss->temp = get_sff_temp(ii, SFF_8436_BASE, SFF_8436_TEMP);
586 ss->voltage = get_sff_voltage(ii, SFF_8436_BASE, SFF_8436_VCC);
587 channels = channel_count(ii->id);
588 ss->channel = calloc(channels, sizeof(*ss->channel));
589 if (ss->channel == NULL) {
590 ii->h->error.errtype = OTHER;
591 ii->h->error.errcode = ENOMEM;
592 return (-1);
593 }
594 for (size_t chan = 0; chan < channels; ++chan) {
595 uint8_t rxoffs = SFF_8436_RX_CH1_MSB + chan * sizeof(uint16_t);
596 uint8_t txoffs = SFF_8436_TX_CH1_MSB + chan * sizeof(uint16_t);
597 ss->channel[chan].rx =
598 get_sff_channel(ii, SFF_8436_BASE, rxoffs);
599 ss->channel[chan].tx =
600 get_sff_channel(ii, SFF_8436_BASE, txoffs);
601 }
602 ss->bitrate = get_qsfp_bitrate(ii);
603 return (ii->error);
604 }
605
606 /*
607 * Read CMIS module status: temperature and voltage from lower memory,
608 * per-lane TX power, TX bias, and RX power from Page 11h Bank 0.
609 */
610 static int
get_cmis_status(struct i2c_info * ii,struct ifconfig_sfp_status * ss,size_t channels)611 get_cmis_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss,
612 size_t channels)
613 {
614 /* Temperature and voltage are in lower memory (same format as SFF) */
615 ss->temp = get_sff_temp(ii, CMIS_BASE, CMIS_TEMP);
616 ss->voltage = get_sff_voltage(ii, CMIS_BASE, CMIS_VCC);
617
618 if (channels == 0)
619 return (ii->error);
620
621 ss->channel = calloc(channels, sizeof(*ss->channel));
622 if (ss->channel == NULL) {
623 ii->h->error.errtype = OTHER;
624 ii->h->error.errcode = ENOMEM;
625 return (-1);
626 }
627
628 /* Read per-lane monitors from Page 11h Bank 0 */
629 for (size_t chan = 0; chan < channels; ++chan) {
630 uint8_t off;
631 uint8_t buf[2];
632
633 /* RX optical power */
634 off = CMIS_P11_RX_PWR_1 + chan * CMIS_LANE_MON_SIZE;
635 read_i2c_page(ii, CMIS_BASE, 0x11, 0, off, 2, buf);
636 ss->channel[chan].rx = (buf[0] << 8) | buf[1];
637
638 /* TX bias current */
639 off = CMIS_P11_TX_BIAS_1 + chan * CMIS_LANE_MON_SIZE;
640 read_i2c_page(ii, CMIS_BASE, 0x11, 0, off, 2, buf);
641 ss->channel[chan].tx = (buf[0] << 8) | buf[1];
642 }
643
644 return (ii->error);
645 }
646
647 int
ifconfig_sfp_get_sfp_status(ifconfig_handle_t * h,const char * name,struct ifconfig_sfp_status * ss)648 ifconfig_sfp_get_sfp_status(ifconfig_handle_t *h, const char *name,
649 struct ifconfig_sfp_status *ss)
650 {
651 struct i2c_info ii;
652
653 memset(ss, 0, sizeof(*ss));
654
655 if (i2c_info_init(&ii, h, name) != 0)
656 return (-1);
657
658 if (ifconfig_sfp_id_is_cmis(ii.id)) {
659 /*
660 * For CMIS, we need the lane count from the module info.
661 * Read the first Application Descriptor to get it.
662 */
663 uint8_t app_desc[CMIS_APP_DESC_SIZE];
664 size_t channels;
665
666 read_i2c(&ii, CMIS_BASE, CMIS_APP_DESC_START,
667 CMIS_APP_DESC_SIZE, app_desc);
668 channels = app_desc[CMIS_APP_LANE_COUNT] & 0x0F;
669 return (get_cmis_status(&ii, ss, channels));
670 }
671
672 if (ifconfig_sfp_id_is_qsfp(ii.id))
673 return (get_qsfp_status(&ii, ss));
674 return (get_sfp_status(&ii, ss));
675 }
676
677 void
ifconfig_sfp_free_sfp_status(struct ifconfig_sfp_status * ss)678 ifconfig_sfp_free_sfp_status(struct ifconfig_sfp_status *ss)
679 {
680 if (ss != NULL)
681 free(ss->channel);
682 }
683
684 static const char *
sfp_id_string_alt(uint8_t value)685 sfp_id_string_alt(uint8_t value)
686 {
687 const char *id;
688
689 if (value <= SFF_8024_ID_LAST)
690 id = sff_8024_id[value];
691 else if (value > 0x80)
692 id = "Vendor specific";
693 else
694 id = "Reserved";
695
696 return (id);
697 }
698
699 static const char *
sfp_conn_string_alt(uint8_t value)700 sfp_conn_string_alt(uint8_t value)
701 {
702 const char *conn;
703
704 if (value >= 0x0D && value <= 0x1F)
705 conn = "Unallocated";
706 else if (value >= 0x24 && value <= 0x7F)
707 conn = "Unallocated";
708 else
709 conn = "Vendor specific";
710
711 return (conn);
712 }
713
714 void
ifconfig_sfp_get_sfp_info_strings(const struct ifconfig_sfp_info * sfp,struct ifconfig_sfp_info_strings * strings)715 ifconfig_sfp_get_sfp_info_strings(const struct ifconfig_sfp_info *sfp,
716 struct ifconfig_sfp_info_strings *strings)
717 {
718 get_sfp_info_strings(sfp, strings);
719 if (strings->sfp_id == NULL)
720 strings->sfp_id = sfp_id_string_alt(sfp->sfp_id);
721 if (strings->sfp_conn == NULL)
722 strings->sfp_conn = sfp_conn_string_alt(sfp->sfp_conn);
723 if (strings->sfp_rev == NULL)
724 strings->sfp_rev = "Unallocated";
725 }
726
727 const char *
ifconfig_sfp_physical_spec(const struct ifconfig_sfp_info * sfp,const struct ifconfig_sfp_info_strings * strings)728 ifconfig_sfp_physical_spec(const struct ifconfig_sfp_info *sfp,
729 const struct ifconfig_sfp_info_strings *strings)
730 {
731 /* CMIS modules: look up media interface ID based on media type */
732 if (ifconfig_sfp_id_is_cmis(sfp->sfp_id)) {
733 switch (sfp->sfp_cmis_media_type) {
734 case SFP_CMIS_MEDIA_TYPE_SMF:
735 if (strings->sfp_cmis_smf != NULL)
736 return (strings->sfp_cmis_smf);
737 break;
738 case SFP_CMIS_MEDIA_TYPE_MMF:
739 if (strings->sfp_cmis_mmf != NULL)
740 return (strings->sfp_cmis_mmf);
741 break;
742 }
743 return ("Unknown");
744 }
745
746 switch (sfp->sfp_id) {
747 case SFP_ID_UNKNOWN:
748 break;
749 case SFP_ID_QSFP:
750 case SFP_ID_QSFPPLUS:
751 case SFP_ID_QSFP28:
752 if (sfp->sfp_eth_1040g & SFP_ETH_1040G_EXTENDED)
753 return (strings->sfp_eth_ext);
754 else if (sfp->sfp_eth_1040g)
755 return (strings->sfp_eth_1040g);
756 break;
757 default:
758 if (sfp->sfp_eth_ext)
759 return (strings->sfp_eth_ext);
760 else if (sfp->sfp_eth_10g)
761 return (strings->sfp_eth_10g);
762 else if (sfp->sfp_eth)
763 return (strings->sfp_eth);
764 break;
765 }
766 return ("Unknown");
767 }
768
769 int
ifconfig_sfp_get_sfp_dump(ifconfig_handle_t * h,const char * name,struct ifconfig_sfp_dump * dump)770 ifconfig_sfp_get_sfp_dump(ifconfig_handle_t *h, const char *name,
771 struct ifconfig_sfp_dump *dump)
772 {
773 struct i2c_info ii;
774 uint8_t *buf = dump->data;
775
776 memset(buf, 0, sizeof(dump->data));
777
778 if (i2c_info_init(&ii, h, name) != 0)
779 return (-1);
780
781 if (ifconfig_sfp_id_is_cmis(ii.id)) {
782 /* Lower memory (0-127), Page 00h (128-255), Page 11h */
783 read_i2c(&ii, CMIS_BASE, 0, 128, buf);
784 read_i2c_page(&ii, CMIS_BASE, 0x00, 0, 128, 128,
785 buf + 128);
786 read_i2c_page(&ii, CMIS_BASE, 0x11, 0, 128, 128,
787 buf + CMIS_DUMP_P11);
788 } else if (ifconfig_sfp_id_is_qsfp(ii.id)) {
789 read_i2c(&ii, SFF_8436_BASE, QSFP_DUMP0_START, QSFP_DUMP0_SIZE,
790 buf + QSFP_DUMP0_START);
791 read_i2c(&ii, SFF_8436_BASE, QSFP_DUMP1_START, QSFP_DUMP1_SIZE,
792 buf + QSFP_DUMP1_START);
793 } else {
794 read_i2c(&ii, SFF_8472_BASE, SFP_DUMP_START, SFP_DUMP_SIZE,
795 buf + SFP_DUMP_START);
796 }
797
798 return (ii.error != 0 ? -1 : 0);
799 }
800
801 size_t
ifconfig_sfp_dump_region_count(const struct ifconfig_sfp_dump * dp)802 ifconfig_sfp_dump_region_count(const struct ifconfig_sfp_dump *dp)
803 {
804 uint8_t id_byte = dp->data[0];
805
806 if (ifconfig_sfp_id_is_cmis((enum sfp_id)id_byte))
807 return (3);
808
809 switch ((enum sfp_id)id_byte) {
810 case SFP_ID_UNKNOWN:
811 return (0);
812 case SFP_ID_QSFP:
813 case SFP_ID_QSFPPLUS:
814 case SFP_ID_QSFP28:
815 return (2);
816 default:
817 return (1);
818 }
819 }
820