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 /* Count active host lanes (nonzero AppSelCode) in the Active Control Set. */
242 static uint8_t
get_cmis_active_lanes(struct i2c_info * ii)243 get_cmis_active_lanes(struct i2c_info *ii)
244 {
245 uint8_t dpconfig[CMIS_MAX_LANES];
246 uint8_t lanes;
247 int i;
248
249 lanes = 0;
250 read_i2c_page(ii, CMIS_BASE, 0x11, 0, CMIS_P11_ACS_DPCONFIG1,
251 sizeof(dpconfig), dpconfig);
252 if (ii->error != 0)
253 return (0);
254
255 for (i = 0; i < CMIS_MAX_LANES; i++) {
256 if ((dpconfig[i] & CMIS_ACS_APPSEL_MASK) != 0)
257 lanes++;
258 }
259 return (lanes);
260 }
261
262 static int
get_cmis_info(struct i2c_info * ii,struct ifconfig_sfp_info * sfp)263 get_cmis_info(struct i2c_info *ii, struct ifconfig_sfp_info *sfp)
264 {
265 uint8_t app_desc[CMIS_APP_DESC_SIZE];
266 uint8_t dpconfig, appsel;
267 uint8_t app_off;
268
269 /* Module ID from lower memory byte 0 */
270 read_i2c(ii, CMIS_BASE, CMIS_ID, 1, &sfp->sfp_id);
271
272 /* Connector type from Page 00h byte 203 */
273 read_i2c_page(ii, CMIS_BASE, 0x00, 0,
274 CMIS_P0_CONNECTOR, 1, &sfp->sfp_conn);
275
276 /* Media type from lower memory byte 85 */
277 read_i2c(ii, CMIS_BASE, CMIS_MEDIA_TYPE, 1,
278 &sfp->sfp_cmis_media_type);
279
280 /*
281 * Read the active AppSel code from the Active Control Set
282 * (Page 11h, byte 206, bits 7:4). This tells us which
283 * Application Descriptor is actually in use.
284 * AppSel is 1-based; 0 means no application selected.
285 */
286 dpconfig = 0;
287 read_i2c_page(ii, CMIS_BASE, 0x11, 0,
288 CMIS_P11_ACS_DPCONFIG1, 1, &dpconfig);
289 appsel = (dpconfig & CMIS_ACS_APPSEL_MASK) >> CMIS_ACS_APPSEL_SHIFT;
290
291 /* Fall back to first descriptor if AppSel is 0 or out of range */
292 if (appsel == 0 || appsel > CMIS_MAX_APP_DESC)
293 appsel = 1;
294
295 /* Read the active Application Descriptor */
296 app_off = CMIS_APP_DESC_START + (appsel - 1) * CMIS_APP_DESC_SIZE;
297 read_i2c(ii, CMIS_BASE, app_off, CMIS_APP_DESC_SIZE, app_desc);
298 if (ii->error != 0)
299 return (ii->error);
300
301 /* Store MediaInterfaceID based on media type */
302 switch (sfp->sfp_cmis_media_type) {
303 case SFP_CMIS_MEDIA_TYPE_SMF:
304 sfp->sfp_cmis_smf = app_desc[CMIS_APP_MEDIA_IF_ID];
305 break;
306 case SFP_CMIS_MEDIA_TYPE_MMF:
307 sfp->sfp_cmis_mmf = app_desc[CMIS_APP_MEDIA_IF_ID];
308 break;
309 }
310
311 /* Count active lanes; fall back to the descriptor's media lane count. */
312 sfp->sfp_cmis_lanes = get_cmis_active_lanes(ii);
313 if (sfp->sfp_cmis_lanes == 0)
314 sfp->sfp_cmis_lanes = app_desc[CMIS_APP_LANE_COUNT] & 0x0F;
315
316 return (ii->error);
317 }
318
319 int
ifconfig_sfp_get_sfp_info(ifconfig_handle_t * h,const char * name,struct ifconfig_sfp_info * sfp)320 ifconfig_sfp_get_sfp_info(ifconfig_handle_t *h,
321 const char *name, struct ifconfig_sfp_info *sfp)
322 {
323 struct i2c_info ii;
324 uint8_t buf[8];
325
326 memset(sfp, 0, sizeof(*sfp));
327
328 if (i2c_info_init(&ii, h, name) != 0)
329 return (-1);
330
331 if (ifconfig_sfp_id_is_cmis(ii.id))
332 return (get_cmis_info(&ii, sfp));
333
334 /* Read bytes 3-10 at once */
335 read_i2c(&ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, buf);
336 if (ii.error != 0)
337 return (ii.error);
338
339 /* Check 10G ethernet first */
340 sfp->sfp_eth_10g = find_zero_bit(sfp_eth_10g_table, buf[0], 1);
341 if (sfp->sfp_eth_10g == 0) {
342 /* No match. Try 1G */
343 sfp->sfp_eth = find_zero_bit(sfp_eth_table, buf[3], 1);
344 }
345 sfp->sfp_fc_len = find_zero_bit(sfp_fc_len_table, buf[4], 1);
346 sfp->sfp_fc_media = find_zero_bit(sfp_fc_media_table, buf[6], 1);
347 sfp->sfp_fc_speed = find_zero_bit(sfp_fc_speed_table, buf[7], 1);
348 sfp->sfp_cab_tech =
349 find_zero_bit(sfp_cab_tech_table, (buf[4] << 8) | buf[5], 2);
350
351 if (ifconfig_sfp_id_is_qsfp(ii.id))
352 return (get_qsfp_info(&ii, sfp));
353 return (get_sfp_info(&ii, sfp));
354 }
355
356 static size_t
channel_count(enum sfp_id id)357 channel_count(enum sfp_id id)
358 {
359 /* TODO: other ids */
360 switch (id) {
361 case SFP_ID_UNKNOWN:
362 return (0);
363 case SFP_ID_QSFP:
364 case SFP_ID_QSFPPLUS:
365 case SFP_ID_QSFP28:
366 return (4);
367 default:
368 return (1);
369 }
370 }
371
372 size_t
ifconfig_sfp_channel_count(const struct ifconfig_sfp_info * sfp)373 ifconfig_sfp_channel_count(const struct ifconfig_sfp_info *sfp)
374 {
375 /* CMIS modules: use lane count from Application Descriptor */
376 if (ifconfig_sfp_id_is_cmis(sfp->sfp_id)) {
377 if (sfp->sfp_cmis_lanes > 0)
378 return (sfp->sfp_cmis_lanes);
379 return (0);
380 }
381 return (channel_count(sfp->sfp_id));
382 }
383
384 /*
385 * Print SFF-8472/SFF-8436 string to supplied buffer.
386 * All (vendor-specific) strings are padded right with '0x20'.
387 */
388 static void
get_sff_string(struct i2c_info * ii,uint8_t addr,uint8_t off,char * dst)389 get_sff_string(struct i2c_info *ii, uint8_t addr, uint8_t off, char *dst)
390 {
391 read_i2c(ii, addr, off, SFF_VENDOR_STRING_SIZE, (uint8_t *)dst);
392 dst += SFF_VENDOR_STRING_SIZE;
393 do { *dst-- = '\0'; } while (*dst == 0x20);
394 }
395
396 static void
get_sff_date(struct i2c_info * ii,uint8_t addr,uint8_t off,char * dst)397 get_sff_date(struct i2c_info *ii, uint8_t addr, uint8_t off, char *dst)
398 {
399 uint8_t buf[SFF_VENDOR_DATE_SIZE];
400
401 read_i2c(ii, addr, off, SFF_VENDOR_DATE_SIZE, buf);
402 sprintf(dst, "20%c%c-%c%c-%c%c", buf[0], buf[1], buf[2], buf[3],
403 buf[4], buf[5]);
404 }
405
406 static int
get_sfp_vendor_info(struct i2c_info * ii,struct ifconfig_sfp_vendor_info * vi)407 get_sfp_vendor_info(struct i2c_info *ii, struct ifconfig_sfp_vendor_info *vi)
408 {
409 get_sff_string(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, vi->name);
410 get_sff_string(ii, SFF_8472_BASE, SFF_8472_PN_START, vi->pn);
411 get_sff_string(ii, SFF_8472_BASE, SFF_8472_SN_START, vi->sn);
412 get_sff_date(ii, SFF_8472_BASE, SFF_8472_DATE_START, vi->date);
413 return (ii->error);
414 }
415
416 static int
get_qsfp_vendor_info(struct i2c_info * ii,struct ifconfig_sfp_vendor_info * vi)417 get_qsfp_vendor_info(struct i2c_info *ii, struct ifconfig_sfp_vendor_info *vi)
418 {
419 get_sff_string(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, vi->name);
420 get_sff_string(ii, SFF_8436_BASE, SFF_8436_PN_START, vi->pn);
421 get_sff_string(ii, SFF_8436_BASE, SFF_8436_SN_START, vi->sn);
422 get_sff_date(ii, SFF_8436_BASE, SFF_8436_DATE_START, vi->date);
423 return (ii->error);
424 }
425
426 /*
427 * Read CMIS vendor strings from Page 00h (upper memory).
428 * Vendor info uses the same ASCII format as SFF-8436 but at
429 * different offsets and requires page selection.
430 */
431 static void
get_cmis_string(struct i2c_info * ii,uint8_t off,char * dst)432 get_cmis_string(struct i2c_info *ii, uint8_t off, char *dst)
433 {
434 read_i2c_page(ii, CMIS_BASE, 0x00, 0, off,
435 SFF_VENDOR_STRING_SIZE, dst);
436 dst += SFF_VENDOR_STRING_SIZE;
437 do { *dst-- = '\0'; } while (*dst == 0x20);
438 }
439
440 static void
get_cmis_date(struct i2c_info * ii,uint8_t off,char * dst)441 get_cmis_date(struct i2c_info *ii, uint8_t off, char *dst)
442 {
443 char buf[SFF_VENDOR_DATE_SIZE];
444
445 read_i2c_page(ii, CMIS_BASE, 0x00, 0, off,
446 SFF_VENDOR_DATE_SIZE, buf);
447 sprintf(dst, "20%c%c-%c%c-%c%c", buf[0], buf[1], buf[2], buf[3],
448 buf[4], buf[5]);
449 }
450
451 static int
get_cmis_vendor_info(struct i2c_info * ii,struct ifconfig_sfp_vendor_info * vi)452 get_cmis_vendor_info(struct i2c_info *ii, struct ifconfig_sfp_vendor_info *vi)
453 {
454 get_cmis_string(ii, CMIS_P0_VENDOR_NAME, vi->name);
455 get_cmis_string(ii, CMIS_P0_VENDOR_PN, vi->pn);
456 get_cmis_string(ii, CMIS_P0_VENDOR_SN, vi->sn);
457 get_cmis_date(ii, CMIS_P0_DATE_CODE, vi->date);
458 return (ii->error);
459 }
460
461 int
ifconfig_sfp_get_sfp_vendor_info(ifconfig_handle_t * h,const char * name,struct ifconfig_sfp_vendor_info * vi)462 ifconfig_sfp_get_sfp_vendor_info(ifconfig_handle_t *h,
463 const char *name, struct ifconfig_sfp_vendor_info *vi)
464 {
465 struct i2c_info ii;
466
467 memset(vi, 0, sizeof(*vi));
468
469 if (i2c_info_init(&ii, h, name) != 0)
470 return (-1);
471
472 if (ifconfig_sfp_id_is_cmis(ii.id))
473 return (get_cmis_vendor_info(&ii, vi));
474 if (ifconfig_sfp_id_is_qsfp(ii.id))
475 return (get_qsfp_vendor_info(&ii, vi));
476 return (get_sfp_vendor_info(&ii, vi));
477 }
478
479 /*
480 * Converts internal temperature (SFF-8472, SFF-8436)
481 * 16-bit unsigned value to human-readable representation:
482 *
483 * Internally measured Module temperature are represented
484 * as a 16-bit signed twos complement value in increments of
485 * 1/256 degrees Celsius, yielding a total range of –128C to +128C
486 * that is considered valid between –40 and +125C.
487 */
488 static double
get_sff_temp(struct i2c_info * ii,uint8_t addr,uint8_t off)489 get_sff_temp(struct i2c_info *ii, uint8_t addr, uint8_t off)
490 {
491 double d;
492 uint8_t buf[2];
493
494 read_i2c(ii, addr, off, 2, buf);
495 d = (double)buf[0];
496 d += (double)buf[1] / 256;
497 return (d);
498 }
499
500 /*
501 * Retrieves supplied voltage (SFF-8472, SFF-8436).
502 * 16-bit usigned value, treated as range 0..+6.55 Volts
503 */
504 static double
get_sff_voltage(struct i2c_info * ii,uint8_t addr,uint8_t off)505 get_sff_voltage(struct i2c_info *ii, uint8_t addr, uint8_t off)
506 {
507 double d;
508 uint8_t buf[2];
509
510 read_i2c(ii, addr, off, 2, buf);
511 d = (double)((buf[0] << 8) | buf[1]);
512 return (d / 10000);
513 }
514
515 /*
516 * The following conversions assume internally-calibrated data.
517 * This is always true for SFF-8346, and explicitly checked for SFF-8472.
518 */
519
520 double
power_mW(uint16_t power)521 power_mW(uint16_t power)
522 {
523 /* Power is specified in units of 0.1 uW. */
524 return (1.0 * power / 10000);
525 }
526
527 double
power_dBm(uint16_t power)528 power_dBm(uint16_t power)
529 {
530 return (10.0 * log10(power_mW(power)));
531 }
532
533 double
bias_mA(uint16_t bias)534 bias_mA(uint16_t bias)
535 {
536 /* Bias current is specified in units of 2 uA. */
537 return (1.0 * bias / 500);
538 }
539
540 static uint16_t
get_sff_channel(struct i2c_info * ii,uint8_t addr,uint8_t off)541 get_sff_channel(struct i2c_info *ii, uint8_t addr, uint8_t off)
542 {
543 uint8_t buf[2];
544
545 read_i2c(ii, addr, off, 2, buf);
546 if (ii->error != 0)
547 return (0);
548
549 return ((buf[0] << 8) + buf[1]);
550 }
551
552 static int
get_sfp_status(struct i2c_info * ii,struct ifconfig_sfp_status * ss)553 get_sfp_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss)
554 {
555 uint8_t diag_type, flags;
556
557 /* Read diagnostic monitoring type */
558 read_i2c(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, &diag_type);
559 if (ii->error != 0)
560 return (-1);
561
562 /*
563 * Read monitoring data IFF it is supplied AND is
564 * internally calibrated
565 */
566 flags = SFF_8472_DDM_DONE | SFF_8472_DDM_INTERNAL;
567 if ((diag_type & flags) != flags) {
568 ii->h->error.errtype = OTHER;
569 ii->h->error.errcode = ENXIO;
570 return (-1);
571 }
572
573 ss->temp = get_sff_temp(ii, SFF_8472_DIAG, SFF_8472_TEMP);
574 ss->voltage = get_sff_voltage(ii, SFF_8472_DIAG, SFF_8472_VCC);
575 ss->channel = calloc(channel_count(ii->id), sizeof(*ss->channel));
576 if (ss->channel == NULL) {
577 ii->h->error.errtype = OTHER;
578 ii->h->error.errcode = ENOMEM;
579 return (-1);
580 }
581 ss->channel[0].rx = get_sff_channel(ii, SFF_8472_DIAG, SFF_8472_RX_POWER);
582 ss->channel[0].tx = get_sff_channel(ii, SFF_8472_DIAG, SFF_8472_TX_BIAS);
583 return (ii->error);
584 }
585
586 static uint32_t
get_qsfp_bitrate(struct i2c_info * ii)587 get_qsfp_bitrate(struct i2c_info *ii)
588 {
589 uint8_t code;
590 uint32_t rate;
591
592 code = 0;
593 read_i2c(ii, SFF_8436_BASE, SFF_8436_BITRATE, 1, &code);
594 rate = code * 100;
595 if (code == 0xFF) {
596 read_i2c(ii, SFF_8436_BASE, SFF_8636_BITRATE, 1, &code);
597 rate = code * 250;
598 }
599
600 return (rate);
601 }
602
603 static int
get_qsfp_status(struct i2c_info * ii,struct ifconfig_sfp_status * ss)604 get_qsfp_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss)
605 {
606 size_t channels;
607
608 ss->temp = get_sff_temp(ii, SFF_8436_BASE, SFF_8436_TEMP);
609 ss->voltage = get_sff_voltage(ii, SFF_8436_BASE, SFF_8436_VCC);
610 channels = channel_count(ii->id);
611 ss->channel = calloc(channels, sizeof(*ss->channel));
612 if (ss->channel == NULL) {
613 ii->h->error.errtype = OTHER;
614 ii->h->error.errcode = ENOMEM;
615 return (-1);
616 }
617 for (size_t chan = 0; chan < channels; ++chan) {
618 uint8_t rxoffs = SFF_8436_RX_CH1_MSB + chan * sizeof(uint16_t);
619 uint8_t txoffs = SFF_8436_TX_CH1_MSB + chan * sizeof(uint16_t);
620 ss->channel[chan].rx =
621 get_sff_channel(ii, SFF_8436_BASE, rxoffs);
622 ss->channel[chan].tx =
623 get_sff_channel(ii, SFF_8436_BASE, txoffs);
624 }
625 ss->bitrate = get_qsfp_bitrate(ii);
626 return (ii->error);
627 }
628
629 /*
630 * Read CMIS module status: temperature and voltage from lower memory,
631 * per-lane TX power, TX bias, and RX power from Page 11h Bank 0.
632 */
633 static int
get_cmis_status(struct i2c_info * ii,struct ifconfig_sfp_status * ss,size_t channels)634 get_cmis_status(struct i2c_info *ii, struct ifconfig_sfp_status *ss,
635 size_t channels)
636 {
637 /* Temperature and voltage are in lower memory (same format as SFF) */
638 ss->temp = get_sff_temp(ii, CMIS_BASE, CMIS_TEMP);
639 ss->voltage = get_sff_voltage(ii, CMIS_BASE, CMIS_VCC);
640
641 if (channels == 0)
642 return (ii->error);
643
644 ss->channel = calloc(channels, sizeof(*ss->channel));
645 if (ss->channel == NULL) {
646 ii->h->error.errtype = OTHER;
647 ii->h->error.errcode = ENOMEM;
648 return (-1);
649 }
650
651 /* Read per-lane monitors from Page 11h Bank 0 */
652 for (size_t chan = 0; chan < channels; ++chan) {
653 uint8_t off;
654 uint8_t buf[2];
655
656 /* RX optical power */
657 off = CMIS_P11_RX_PWR_1 + chan * CMIS_LANE_MON_SIZE;
658 read_i2c_page(ii, CMIS_BASE, 0x11, 0, off, 2, buf);
659 ss->channel[chan].rx = (buf[0] << 8) | buf[1];
660
661 /* TX bias current */
662 off = CMIS_P11_TX_BIAS_1 + chan * CMIS_LANE_MON_SIZE;
663 read_i2c_page(ii, CMIS_BASE, 0x11, 0, off, 2, buf);
664 ss->channel[chan].tx = (buf[0] << 8) | buf[1];
665 }
666
667 return (ii->error);
668 }
669
670 int
ifconfig_sfp_get_sfp_status(ifconfig_handle_t * h,const char * name,struct ifconfig_sfp_status * ss)671 ifconfig_sfp_get_sfp_status(ifconfig_handle_t *h, const char *name,
672 struct ifconfig_sfp_status *ss)
673 {
674 struct i2c_info ii;
675
676 memset(ss, 0, sizeof(*ss));
677
678 if (i2c_info_init(&ii, h, name) != 0)
679 return (-1);
680
681 if (ifconfig_sfp_id_is_cmis(ii.id)) {
682 /*
683 * Match the active-lane count reported by get_cmis_info();
684 * fall back to the first descriptor's media lane count.
685 */
686 uint8_t app_desc[CMIS_APP_DESC_SIZE];
687 size_t channels;
688
689 channels = get_cmis_active_lanes(&ii);
690 if (channels == 0) {
691 read_i2c(&ii, CMIS_BASE, CMIS_APP_DESC_START,
692 CMIS_APP_DESC_SIZE, app_desc);
693 channels = app_desc[CMIS_APP_LANE_COUNT] & 0x0F;
694 }
695 return (get_cmis_status(&ii, ss, channels));
696 }
697
698 if (ifconfig_sfp_id_is_qsfp(ii.id))
699 return (get_qsfp_status(&ii, ss));
700 return (get_sfp_status(&ii, ss));
701 }
702
703 void
ifconfig_sfp_free_sfp_status(struct ifconfig_sfp_status * ss)704 ifconfig_sfp_free_sfp_status(struct ifconfig_sfp_status *ss)
705 {
706 if (ss != NULL)
707 free(ss->channel);
708 }
709
710 static const char *
sfp_id_string_alt(uint8_t value)711 sfp_id_string_alt(uint8_t value)
712 {
713 const char *id;
714
715 if (value <= SFF_8024_ID_LAST)
716 id = sff_8024_id[value];
717 else if (value > 0x80)
718 id = "Vendor specific";
719 else
720 id = "Reserved";
721
722 return (id);
723 }
724
725 static const char *
sfp_conn_string_alt(uint8_t value)726 sfp_conn_string_alt(uint8_t value)
727 {
728 const char *conn;
729
730 if (value >= 0x0D && value <= 0x1F)
731 conn = "Unallocated";
732 else if (value >= 0x24 && value <= 0x7F)
733 conn = "Unallocated";
734 else
735 conn = "Vendor specific";
736
737 return (conn);
738 }
739
740 void
ifconfig_sfp_get_sfp_info_strings(const struct ifconfig_sfp_info * sfp,struct ifconfig_sfp_info_strings * strings)741 ifconfig_sfp_get_sfp_info_strings(const struct ifconfig_sfp_info *sfp,
742 struct ifconfig_sfp_info_strings *strings)
743 {
744 get_sfp_info_strings(sfp, strings);
745 if (strings->sfp_id == NULL)
746 strings->sfp_id = sfp_id_string_alt(sfp->sfp_id);
747 if (strings->sfp_conn == NULL)
748 strings->sfp_conn = sfp_conn_string_alt(sfp->sfp_conn);
749 if (strings->sfp_rev == NULL)
750 strings->sfp_rev = "Unallocated";
751 }
752
753 const char *
ifconfig_sfp_physical_spec(const struct ifconfig_sfp_info * sfp,const struct ifconfig_sfp_info_strings * strings)754 ifconfig_sfp_physical_spec(const struct ifconfig_sfp_info *sfp,
755 const struct ifconfig_sfp_info_strings *strings)
756 {
757 /* CMIS modules: look up media interface ID based on media type */
758 if (ifconfig_sfp_id_is_cmis(sfp->sfp_id)) {
759 switch (sfp->sfp_cmis_media_type) {
760 case SFP_CMIS_MEDIA_TYPE_SMF:
761 if (strings->sfp_cmis_smf != NULL)
762 return (strings->sfp_cmis_smf);
763 break;
764 case SFP_CMIS_MEDIA_TYPE_MMF:
765 if (strings->sfp_cmis_mmf != NULL)
766 return (strings->sfp_cmis_mmf);
767 break;
768 }
769 return ("Unknown");
770 }
771
772 switch (sfp->sfp_id) {
773 case SFP_ID_UNKNOWN:
774 break;
775 case SFP_ID_QSFP:
776 case SFP_ID_QSFPPLUS:
777 case SFP_ID_QSFP28:
778 if (sfp->sfp_eth_1040g & SFP_ETH_1040G_EXTENDED)
779 return (strings->sfp_eth_ext);
780 else if (sfp->sfp_eth_1040g)
781 return (strings->sfp_eth_1040g);
782 break;
783 default:
784 if (sfp->sfp_eth_ext)
785 return (strings->sfp_eth_ext);
786 else if (sfp->sfp_eth_10g)
787 return (strings->sfp_eth_10g);
788 else if (sfp->sfp_eth)
789 return (strings->sfp_eth);
790 break;
791 }
792 return ("Unknown");
793 }
794
795 int
ifconfig_sfp_get_sfp_dump(ifconfig_handle_t * h,const char * name,struct ifconfig_sfp_dump * dump)796 ifconfig_sfp_get_sfp_dump(ifconfig_handle_t *h, const char *name,
797 struct ifconfig_sfp_dump *dump)
798 {
799 struct i2c_info ii;
800 uint8_t *buf = dump->data;
801
802 memset(buf, 0, sizeof(dump->data));
803
804 if (i2c_info_init(&ii, h, name) != 0)
805 return (-1);
806
807 if (ifconfig_sfp_id_is_cmis(ii.id)) {
808 /* Lower memory (0-127), Page 00h, Page 11h, Page 10h */
809 read_i2c(&ii, CMIS_BASE, 0, 128, buf);
810 read_i2c_page(&ii, CMIS_BASE, 0x00, 0, 128, 128,
811 buf + 128);
812 read_i2c_page(&ii, CMIS_BASE, 0x11, 0, 128, 128,
813 buf + CMIS_DUMP_P11);
814 read_i2c_page(&ii, CMIS_BASE, 0x10, 0, 128, 128,
815 buf + CMIS_DUMP_P10);
816 } else if (ifconfig_sfp_id_is_qsfp(ii.id)) {
817 read_i2c(&ii, SFF_8436_BASE, QSFP_DUMP0_START, QSFP_DUMP0_SIZE,
818 buf + QSFP_DUMP0_START);
819 read_i2c(&ii, SFF_8436_BASE, QSFP_DUMP1_START, QSFP_DUMP1_SIZE,
820 buf + QSFP_DUMP1_START);
821 } else {
822 read_i2c(&ii, SFF_8472_BASE, SFP_DUMP_START, SFP_DUMP_SIZE,
823 buf + SFP_DUMP_START);
824 }
825
826 return (ii.error != 0 ? -1 : 0);
827 }
828
829 size_t
ifconfig_sfp_dump_region_count(const struct ifconfig_sfp_dump * dp)830 ifconfig_sfp_dump_region_count(const struct ifconfig_sfp_dump *dp)
831 {
832 uint8_t id_byte = dp->data[0];
833
834 if (ifconfig_sfp_id_is_cmis((enum sfp_id)id_byte))
835 return (4);
836
837 switch ((enum sfp_id)id_byte) {
838 case SFP_ID_UNKNOWN:
839 return (0);
840 case SFP_ID_QSFP:
841 case SFP_ID_QSFPPLUS:
842 case SFP_ID_QSFP28:
843 return (2);
844 default:
845 return (1);
846 }
847 }
848