]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sbin/ifconfig/sfp.c
MFC r288305:
[FreeBSD/stable/10.git] / sbin / ifconfig / sfp.c
1 /*-
2  * Copyright (c) 2014 Alexander V. Chernikov. 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #ifndef lint
27 static const char rcsid[] =
28   "$FreeBSD$";
29 #endif /* not lint */
30
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
35
36 #include <net/if.h>
37 #include <net/sff8436.h>
38 #include <net/sff8472.h>
39
40 #include <math.h>
41 #include <err.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48
49 #include "ifconfig.h"
50
51 struct i2c_info {
52         int fd;                 /* fd to issue SIOCGI2C */
53         int error;              /* Store first error */
54         int qsfp;               /* True if transceiver is QSFP */
55         int do_diag;            /* True if we need to request DDM */
56         struct ifreq *ifr;      /* Pointer to pre-filled ifreq */
57 };
58
59 static int read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off,
60     uint8_t len, uint8_t *buf);
61 static void dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off,
62     uint8_t len);
63
64 struct _nv {
65         int v;
66         const char *n;
67 };
68
69 const char *find_value(struct _nv *x, int value);
70 const char *find_zero_bit(struct _nv *x, int value, int sz);
71
72 /* SFF-8472 Rev. 11.4 table 3.4: Connector values */
73 static struct _nv conn[] = {
74         { 0x00, "Unknown" },
75         { 0x01, "SC" },
76         { 0x02, "Fibre Channel Style 1 copper" },
77         { 0x03, "Fibre Channel Style 2 copper" },
78         { 0x04, "BNC/TNC" },
79         { 0x05, "Fibre Channel coaxial" },
80         { 0x06, "FiberJack" },
81         { 0x07, "LC" },
82         { 0x08, "MT-RJ" },
83         { 0x09, "MU" },
84         { 0x0A, "SG" },
85         { 0x0B, "Optical pigtail" },
86         { 0x0C, "MPO Parallel Optic" },
87         { 0x20, "HSSDC II" },
88         { 0x21, "Copper pigtail" },
89         { 0x22, "RJ45" },
90         { 0x23, "No separate connector" }, /* SFF-8436 */
91         { 0, NULL }
92 };
93
94 /* SFF-8472 Rev. 11.4 table 3.5: Transceiver codes */
95 /* 10G Ethernet/IB compliance codes, byte 3 */
96 static struct _nv eth_10g[] = {
97         { 0x80, "10G Base-ER" },
98         { 0x40, "10G Base-LRM" },
99         { 0x20, "10G Base-LR" },
100         { 0x10, "10G Base-SR" },
101         { 0x08, "1X SX" },
102         { 0x04, "1X LX" },
103         { 0x02, "1X Copper Active" },
104         { 0x01, "1X Copper Passive" },
105         { 0, NULL }
106 };
107
108 /* Ethernet compliance codes, byte 6 */
109 static struct _nv eth_compat[] = {
110         { 0x80, "BASE-PX" },
111         { 0x40, "BASE-BX10" },
112         { 0x20, "100BASE-FX" },
113         { 0x10, "100BASE-LX/LX10" },
114         { 0x08, "1000BASE-T" },
115         { 0x04, "1000BASE-CX" },
116         { 0x02, "1000BASE-LX" },
117         { 0x01, "1000BASE-SX" },
118         { 0, NULL }
119 };
120
121 /* FC link length, byte 7 */
122 static struct _nv fc_len[] = {
123         { 0x80, "very long distance" },
124         { 0x40, "short distance" },
125         { 0x20, "intermediate distance" },
126         { 0x10, "long distance" },
127         { 0x08, "medium distance" },
128         { 0, NULL }
129 };
130
131 /* Channel/Cable technology, byte 7-8 */
132 static struct _nv cab_tech[] = {
133         { 0x0400, "Shortwave laser (SA)" },
134         { 0x0200, "Longwave laser (LC)" },
135         { 0x0100, "Electrical inter-enclosure (EL)" },
136         { 0x80, "Electrical intra-enclosure (EL)" },
137         { 0x40, "Shortwave laser (SN)" },
138         { 0x20, "Shortwave laser (SL)" },
139         { 0x10, "Longwave laser (LL)" },
140         { 0x08, "Active Cable" },
141         { 0x04, "Passive Cable" },
142         { 0, NULL }
143 };
144
145 /* FC Transmission media, byte 9 */
146 static struct _nv fc_media[] = {
147         { 0x80, "Twin Axial Pair" },
148         { 0x40, "Twisted Pair" },
149         { 0x20, "Miniature Coax" },
150         { 0x10, "Viao Coax" },
151         { 0x08, "Miltimode, 62.5um" },
152         { 0x04, "Multimode, 50um" },
153         { 0x02, "" },
154         { 0x01, "Single Mode" },
155         { 0, NULL }
156 };
157
158 /* FC Speed, byte 10 */
159 static struct _nv fc_speed[] = {
160         { 0x80, "1200 MBytes/sec" },
161         { 0x40, "800 MBytes/sec" },
162         { 0x20, "1600 MBytes/sec" },
163         { 0x10, "400 MBytes/sec" },
164         { 0x08, "3200 MBytes/sec" },
165         { 0x04, "200 MBytes/sec" },
166         { 0x01, "100 MBytes/sec" },
167         { 0, NULL }
168 };
169
170 /* SFF-8436 Rev. 4.8 table 33: Specification compliance  */
171
172 /* 10/40G Ethernet compliance codes, byte 128 + 3 */
173 static struct _nv eth_1040g[] = {
174         { 0x80, "Reserved" },
175         { 0x40, "10GBASE-LRM" },
176         { 0x20, "10GBASE-LR" },
177         { 0x10, "10GBASE-SR" },
178         { 0x08, "40GBASE-CR4" },
179         { 0x04, "40GBASE-SR4" },
180         { 0x02, "40GBASE-LR4" },
181         { 0x01, "40G Active Cable" },
182         { 0, NULL }
183 };
184
185 /* SFF-8636 Rev. 2.5 table 6.3: Revision compliance */
186 static struct _nv rev_compl[] = {
187         { 0x1, "SFF-8436 rev <=4.8" },
188         { 0x2, "SFF-8436 rev <=4.8" },
189         { 0x3, "SFF-8636 rev <=1.3" },
190         { 0x4, "SFF-8636 rev <=1.4" },
191         { 0x5, "SFF-8636 rev <=1.5" },
192         { 0x6, "SFF-8636 rev <=2.0" },
193         { 0x7, "SFF-8636 rev <=2.5" },
194         { 0x0, "Unspecified" }
195 };
196
197 const char *
198 find_value(struct _nv *x, int value)
199 {
200         for (; x->n != NULL; x++)
201                 if (x->v == value)
202                         return (x->n);
203         return (NULL);
204 }
205
206 const char *
207 find_zero_bit(struct _nv *x, int value, int sz)
208 {
209         int v, m;
210         const char *s;
211
212         v = 1;
213         for (v = 1, m = 1 << (8 * sz); v < m; v *= 2) {
214                 if ((value & v) == 0)
215                         continue;
216                 if ((s = find_value(x, value & v)) != NULL) {
217                         value &= ~v;
218                         return (s);
219                 }
220         }
221
222         return (NULL);
223 }
224
225 static void
226 convert_sff_identifier(char *buf, size_t size, uint8_t value)
227 {
228         const char *x;
229
230         x = NULL;
231         if (value <= SFF_8024_ID_LAST)
232                 x = sff_8024_id[value];
233         else {
234                 if (value > 0x80)
235                         x = "Vendor specific";
236                 else
237                         x = "Reserved";
238         }
239
240         snprintf(buf, size, "%s", x);
241 }
242
243 static void
244 convert_sff_connector(char *buf, size_t size, uint8_t value)
245 {
246         const char *x;
247
248         if ((x = find_value(conn, value)) == NULL) {
249                 if (value >= 0x0D && value <= 0x1F)
250                         x = "Unallocated";
251                 else if (value >= 0x24 && value <= 0x7F)
252                         x = "Unallocated";
253                 else
254                         x = "Vendor specific";
255         }
256
257         snprintf(buf, size, "%s", x);
258 }
259
260 static void
261 convert_sff_rev_compliance(char *buf, size_t size, uint8_t value)
262 {
263         const char *x;
264
265         if (value > 0x07)
266                 x = "Unallocated";
267         else
268                 x = find_value(rev_compl, value);
269
270         snprintf(buf, size, "%s", x);
271 }
272
273 static void
274 get_sfp_identifier(struct i2c_info *ii, char *buf, size_t size)
275 {
276         uint8_t data;
277
278         read_i2c(ii, SFF_8472_BASE, SFF_8472_ID, 1, &data);
279         convert_sff_identifier(buf, size, data);
280 }
281
282 static void
283 get_sfp_connector(struct i2c_info *ii, char *buf, size_t size)
284 {
285         uint8_t data;
286
287         read_i2c(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, &data);
288         convert_sff_connector(buf, size, data);
289 }
290
291 static void
292 get_qsfp_identifier(struct i2c_info *ii, char *buf, size_t size)
293 {
294         uint8_t data;
295
296         read_i2c(ii, SFF_8436_BASE, SFF_8436_ID, 1, &data);
297         convert_sff_identifier(buf, size, data);
298 }
299
300 static void
301 get_qsfp_connector(struct i2c_info *ii, char *buf, size_t size)
302 {
303         uint8_t data;
304
305         read_i2c(ii, SFF_8436_BASE, SFF_8436_CONNECTOR, 1, &data);
306         convert_sff_connector(buf, size, data);
307 }
308
309 static void
310 printf_sfp_transceiver_descr(struct i2c_info *ii, char *buf, size_t size)
311 {
312         char xbuf[12];
313         const char *tech_class, *tech_len, *tech_tech, *tech_media, *tech_speed;
314
315         tech_class = NULL;
316         tech_len = NULL;
317         tech_tech = NULL;
318         tech_media = NULL;
319         tech_speed = NULL;
320
321         /* Read bytes 3-10 at once */
322         read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, &xbuf[3]);
323
324         /* Check 10G ethernet first */
325         tech_class = find_zero_bit(eth_10g, xbuf[3], 1);
326         if (tech_class == NULL) {
327                 /* No match. Try 1G */
328                 tech_class = find_zero_bit(eth_compat, xbuf[6], 1);
329         }
330
331         tech_len = find_zero_bit(fc_len, xbuf[7], 1);
332         tech_tech = find_zero_bit(cab_tech, xbuf[7] << 8 | xbuf[8], 2);
333         tech_media = find_zero_bit(fc_media, xbuf[9], 1);
334         tech_speed = find_zero_bit(fc_speed, xbuf[10], 1);
335
336         printf("Class: %s\n", tech_class);
337         printf("Length: %s\n", tech_len);
338         printf("Tech: %s\n", tech_tech);
339         printf("Media: %s\n", tech_media);
340         printf("Speed: %s\n", tech_speed);
341 }
342
343 static void
344 get_sfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size)
345 {
346         const char *tech_class;
347         uint8_t code;
348
349         unsigned char qbuf[8];
350         read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, (uint8_t *)qbuf);
351
352         /* Check 10G Ethernet/IB first */
353         read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, &code);
354         tech_class = find_zero_bit(eth_10g, code, 1);
355         if (tech_class == NULL) {
356                 /* No match. Try Ethernet 1G */
357                 read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3,
358                     1, (caddr_t)&code);
359                 tech_class = find_zero_bit(eth_compat, code, 1);
360         }
361
362         if (tech_class == NULL)
363                 tech_class = "Unknown";
364
365         snprintf(buf, size, "%s", tech_class);
366 }
367
368 static void
369 get_qsfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size)
370 {
371         const char *tech_class;
372         uint8_t code;
373
374         /* Check 10/40G Ethernet class only */
375         read_i2c(ii, SFF_8436_BASE, SFF_8436_CODE_E1040G, 1, &code);
376         tech_class = find_zero_bit(eth_1040g, code, 1);
377         if (tech_class == NULL)
378                 tech_class = "Unknown";
379
380         snprintf(buf, size, "%s", tech_class);
381 }
382
383 /*
384  * Print SFF-8472/SFF-8436 string to supplied buffer.
385  * All (vendor-specific) strings are padded right with '0x20'.
386  */
387 static void
388 convert_sff_name(char *buf, size_t size, char *xbuf)
389 {
390         char *p;
391
392         for (p = &xbuf[16]; *(p - 1) == 0x20; p--)
393                 ;
394         *p = '\0';
395         snprintf(buf, size, "%s", xbuf);
396 }
397
398 static void
399 convert_sff_date(char *buf, size_t size, char *xbuf)
400 {
401
402         snprintf(buf, size, "20%c%c-%c%c-%c%c", xbuf[0], xbuf[1],
403             xbuf[2], xbuf[3], xbuf[4], xbuf[5]);
404 }
405
406 static void
407 get_sfp_vendor_name(struct i2c_info *ii, char *buf, size_t size)
408 {
409         char xbuf[17];
410
411         memset(xbuf, 0, sizeof(xbuf));
412         read_i2c(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, 16, (uint8_t *)xbuf);
413         convert_sff_name(buf, size, xbuf);
414 }
415
416 static void
417 get_sfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size)
418 {
419         char xbuf[17];
420
421         memset(xbuf, 0, sizeof(xbuf));
422         read_i2c(ii, SFF_8472_BASE, SFF_8472_PN_START, 16, (uint8_t *)xbuf);
423         convert_sff_name(buf, size, xbuf);
424 }
425
426 static void
427 get_sfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size)
428 {
429         char xbuf[17];
430
431         memset(xbuf, 0, sizeof(xbuf));
432         read_i2c(ii, SFF_8472_BASE, SFF_8472_SN_START, 16, (uint8_t *)xbuf);
433         convert_sff_name(buf, size, xbuf);
434 }
435
436 static void
437 get_sfp_vendor_date(struct i2c_info *ii, char *buf, size_t size)
438 {
439         char xbuf[6];
440
441         memset(xbuf, 0, sizeof(xbuf));
442         /* Date code, see Table 3.8 for description */
443         read_i2c(ii, SFF_8472_BASE, SFF_8472_DATE_START, 6, (uint8_t *)xbuf);
444         convert_sff_date(buf, size, xbuf);
445 }
446
447 static void
448 get_qsfp_vendor_name(struct i2c_info *ii, char *buf, size_t size)
449 {
450         char xbuf[17];
451
452         memset(xbuf, 0, sizeof(xbuf));
453         read_i2c(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, 16, (uint8_t *)xbuf);
454         convert_sff_name(buf, size, xbuf);
455 }
456
457 static void
458 get_qsfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size)
459 {
460         char xbuf[17];
461
462         memset(xbuf, 0, sizeof(xbuf));
463         read_i2c(ii, SFF_8436_BASE, SFF_8436_PN_START, 16, (uint8_t *)xbuf);
464         convert_sff_name(buf, size, xbuf);
465 }
466
467 static void
468 get_qsfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size)
469 {
470         char xbuf[17];
471
472         memset(xbuf, 0, sizeof(xbuf));
473         read_i2c(ii, SFF_8436_BASE, SFF_8436_SN_START, 16, (uint8_t *)xbuf);
474         convert_sff_name(buf, size, xbuf);
475 }
476
477 static void
478 get_qsfp_vendor_date(struct i2c_info *ii, char *buf, size_t size)
479 {
480         char xbuf[6];
481
482         memset(xbuf, 0, sizeof(xbuf));
483         read_i2c(ii, SFF_8436_BASE, SFF_8436_DATE_START, 6, (uint8_t *)xbuf);
484         convert_sff_date(buf, size, xbuf);
485 }
486
487 static void
488 print_sfp_vendor(struct i2c_info *ii, char *buf, size_t size)
489 {
490         char xbuf[80];
491
492         memset(xbuf, 0, sizeof(xbuf));
493         if (ii->qsfp != 0) {
494                 get_qsfp_vendor_name(ii, xbuf, 20);
495                 get_qsfp_vendor_pn(ii, &xbuf[20], 20);
496                 get_qsfp_vendor_sn(ii, &xbuf[40], 20);
497                 get_qsfp_vendor_date(ii, &xbuf[60], 20);
498         } else {
499                 get_sfp_vendor_name(ii, xbuf, 20);
500                 get_sfp_vendor_pn(ii, &xbuf[20], 20);
501                 get_sfp_vendor_sn(ii, &xbuf[40], 20);
502                 get_sfp_vendor_date(ii, &xbuf[60], 20);
503         }
504
505         snprintf(buf, size, "vendor: %s PN: %s SN: %s DATE: %s",
506             xbuf, &xbuf[20],  &xbuf[40], &xbuf[60]);
507 }
508
509 /*
510  * Converts internal templerature (SFF-8472, SFF-8436)
511  * 16-bit unsigned value to human-readable representation:
512  * 
513  * Internally measured Module temperature are represented
514  * as a 16-bit signed twos complement value in increments of
515  * 1/256 degrees Celsius, yielding a total range of â€“128C to +128C
516  * that is considered valid between â€“40 and +125C.
517  *
518  */
519 static void
520 convert_sff_temp(char *buf, size_t size, uint8_t *xbuf)
521 {
522         double d;
523
524         d = (double)xbuf[0];
525         d += (double)xbuf[1] / 256;
526
527         snprintf(buf, size, "%.2f C", d);
528 }
529
530 /*
531  * Retrieves supplied voltage (SFF-8472, SFF-8436).
532  * 16-bit usigned value, treated as range 0..+6.55 Volts
533  */
534 static void
535 convert_sff_voltage(char *buf, size_t size, uint8_t *xbuf)
536 {
537         double d;
538
539         d = (double)((xbuf[0] << 8) | xbuf[1]);
540         snprintf(buf, size, "%.2f Volts", d / 10000);
541 }
542
543 /*
544  * Converts value in @xbuf to both milliwats and dBm
545  * human representation.
546  */
547 static void
548 convert_sff_power(struct i2c_info *ii, char *buf, size_t size, uint8_t *xbuf)
549 {
550         uint16_t mW;
551         double dbm;
552
553         mW = (xbuf[0] << 8) + xbuf[1];
554
555         /* Convert mw to dbm */
556         dbm = 10.0 * log10(1.0 * mW / 10000);
557
558         /*
559          * Assume internally-calibrated data.
560          * This is always true for SFF-8346, and explicitly
561          * checked for SFF-8472.
562          */
563
564         /* Table 3.9, bit 5 is set, internally calibrated */
565         snprintf(buf, size, "%d.%02d mW (%.2f dBm)",
566             mW / 10000, (mW % 10000) / 100, dbm);
567 }
568
569 static void
570 get_sfp_temp(struct i2c_info *ii, char *buf, size_t size)
571 {
572         uint8_t xbuf[2];
573
574         memset(xbuf, 0, sizeof(xbuf));
575         read_i2c(ii, SFF_8472_DIAG, SFF_8472_TEMP, 2, xbuf);
576         convert_sff_temp(buf, size, xbuf);
577 }
578
579 static void
580 get_sfp_voltage(struct i2c_info *ii, char *buf, size_t size)
581 {
582         uint8_t xbuf[2];
583
584         memset(xbuf, 0, sizeof(xbuf));
585         read_i2c(ii, SFF_8472_DIAG, SFF_8472_VCC, 2, xbuf);
586         convert_sff_voltage(buf, size, xbuf);
587 }
588
589 static void
590 get_qsfp_temp(struct i2c_info *ii, char *buf, size_t size)
591 {
592         uint8_t xbuf[2];
593
594         memset(xbuf, 0, sizeof(xbuf));
595         read_i2c(ii, SFF_8436_BASE, SFF_8436_TEMP, 2, xbuf);
596         convert_sff_temp(buf, size, xbuf);
597 }
598
599 static void
600 get_qsfp_voltage(struct i2c_info *ii, char *buf, size_t size)
601 {
602         uint8_t xbuf[2];
603
604         memset(xbuf, 0, sizeof(xbuf));
605         read_i2c(ii, SFF_8436_BASE, SFF_8436_VCC, 2, xbuf);
606         convert_sff_voltage(buf, size, xbuf);
607 }
608
609 static void
610 get_sfp_rx_power(struct i2c_info *ii, char *buf, size_t size)
611 {
612         uint8_t xbuf[2];
613
614         memset(xbuf, 0, sizeof(xbuf));
615         read_i2c(ii, SFF_8472_DIAG, SFF_8472_RX_POWER, 2, xbuf);
616         convert_sff_power(ii, buf, size, xbuf);
617 }
618
619 static void
620 get_sfp_tx_power(struct i2c_info *ii, char *buf, size_t size)
621 {
622         uint8_t xbuf[2];
623
624         memset(xbuf, 0, sizeof(xbuf));
625         read_i2c(ii, SFF_8472_DIAG, SFF_8472_TX_POWER, 2, xbuf);
626         convert_sff_power(ii, buf, size, xbuf);
627 }
628
629 static void
630 get_qsfp_rx_power(struct i2c_info *ii, char *buf, size_t size, int chan)
631 {
632         uint8_t xbuf[2];
633
634         memset(xbuf, 0, sizeof(xbuf));
635         read_i2c(ii, SFF_8436_BASE, SFF_8436_RX_CH1_MSB + (chan-1)*2, 2, xbuf);
636         convert_sff_power(ii, buf, size, xbuf);
637 }
638
639 static void
640 get_qsfp_tx_power(struct i2c_info *ii, char *buf, size_t size, int chan)
641 {
642         uint8_t xbuf[2];
643
644         memset(xbuf, 0, sizeof(xbuf));
645         read_i2c(ii, SFF_8436_BASE, SFF_8436_TX_CH1_MSB + (chan-1)*2, 2, xbuf);
646         convert_sff_power(ii, buf, size, xbuf);
647 }
648
649 static void
650 get_qsfp_rev_compliance(struct i2c_info *ii, char *buf, size_t size)
651 {
652         uint8_t xbuf;
653
654         xbuf = 0;
655         read_i2c(ii, SFF_8436_BASE, SFF_8436_STATUS, 1, &xbuf);
656         convert_sff_rev_compliance(buf, size, xbuf);
657 }
658
659 static uint32_t 
660 get_qsfp_br(struct i2c_info *ii)
661 {
662         uint8_t xbuf;
663         uint32_t rate;
664
665         xbuf = 0;
666         read_i2c(ii, SFF_8436_BASE, SFF_8436_BITRATE, 1, &xbuf);
667         rate = xbuf * 100;
668         if (xbuf == 0xFF) {
669                 read_i2c(ii, SFF_8436_BASE, SFF_8636_BITRATE, 1, &xbuf);
670                 rate = xbuf * 250;
671         }
672
673         return (rate);
674 }
675
676 /*
677  * Reads i2c data from opened kernel socket.
678  */
679 static int
680 read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len,
681     uint8_t *buf)
682 {
683         struct ifi2creq req;
684         int i, l;
685
686         if (ii->error != 0)
687                 return (ii->error);
688
689         ii->ifr->ifr_data = (caddr_t)&req;
690
691         i = 0;
692         l = 0;
693         memset(&req, 0, sizeof(req));
694         req.dev_addr = addr;
695         req.offset = off;
696         req.len = len;
697
698         while (len > 0) {
699                 l = (len > sizeof(req.data)) ? sizeof(req.data) : len;
700                 req.len = l;
701                 if (ioctl(ii->fd, SIOCGI2C, ii->ifr) != 0) {
702                         ii->error = errno;
703                         return (errno);
704                 }
705
706                 memcpy(&buf[i], req.data, l);
707                 len -= l;
708                 i += l;
709                 req.offset += l;
710         }
711
712         return (0);
713 }
714
715 static void
716 dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len)
717 {
718         unsigned char buf[16];
719         int i, read;
720
721         while (len > 0) {
722                 memset(buf, 0, sizeof(buf));
723                 read = (len > sizeof(buf)) ? sizeof(buf) : len;
724                 read_i2c(ii, addr, off, read, buf);
725                 if (ii->error != 0) {
726                         fprintf(stderr, "Error reading i2c info\n");
727                         return;
728                 }
729
730                 printf("\t");
731                 for (i = 0; i < read; i++)
732                         printf("%02X ", buf[i]);
733                 printf("\n");
734                 len -= read;
735                 off += read;
736         }
737 }
738
739 static void
740 print_qsfp_status(struct i2c_info *ii, int verbose)
741 {
742         char buf[80], buf2[40], buf3[40];
743         uint8_t diag_type;
744         uint32_t bitrate;
745         int i;
746
747         /* Read diagnostic monitoring type */
748         read_i2c(ii, SFF_8436_BASE, SFF_8436_DIAG_TYPE, 1, (caddr_t)&diag_type);
749         if (ii->error != 0)
750                 return;
751
752         /*
753          * Read monitoring data it is supplied.
754          * XXX: It is not exactly clear from standard
755          * how one can specify lack of measurements (passive cables case).
756          */
757         if (diag_type != 0)
758                 ii->do_diag = 1;
759         ii->qsfp = 1;
760
761         /* Transceiver type */
762         get_qsfp_identifier(ii, buf, sizeof(buf));
763         get_qsfp_transceiver_class(ii, buf2, sizeof(buf2));
764         get_qsfp_connector(ii, buf3, sizeof(buf3));
765         if (ii->error == 0)
766                 printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3);
767         print_sfp_vendor(ii, buf, sizeof(buf));
768         if (ii->error == 0)
769                 printf("\t%s\n", buf);
770
771         if (verbose > 1) {
772                 get_qsfp_rev_compliance(ii, buf, sizeof(buf));
773                 if (ii->error == 0)
774                         printf("\tcompliance level: %s\n", buf);
775
776                 bitrate = get_qsfp_br(ii);
777                 if (ii->error == 0 && bitrate > 0)
778                         printf("\tnominal bitrate: %u Mbps\n", bitrate);
779         }
780
781         /* Request current measurements if they are provided: */
782         if (ii->do_diag != 0) {
783                 get_qsfp_temp(ii, buf, sizeof(buf));
784                 get_qsfp_voltage(ii, buf2, sizeof(buf2));
785                 printf("\tmodule temperature: %s voltage: %s\n", buf, buf2);
786                 for (i = 1; i <= 4; i++) {
787                         get_qsfp_rx_power(ii, buf, sizeof(buf), i);
788                         get_qsfp_tx_power(ii, buf2, sizeof(buf2), i);
789                         printf("\tlane %d: RX: %s TX: %s\n", i, buf, buf2);
790                 }
791         }
792
793         if (verbose > 2) {
794                 printf("\n\tSFF8436 DUMP (0xA0 128..255 range):\n");
795                 dump_i2c_data(ii, SFF_8436_BASE, 128, 128);
796                 printf("\n\tSFF8436 DUMP (0xA0 0..81 range):\n");
797                 dump_i2c_data(ii, SFF_8436_BASE, 0, 82);
798         }
799 }
800
801 static void
802 print_sfp_status(struct i2c_info *ii, int verbose)
803 {
804         char buf[80], buf2[40], buf3[40];
805         uint8_t diag_type, flags;
806
807         /* Read diagnostic monitoring type */
808         read_i2c(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&diag_type);
809         if (ii->error != 0)
810                 return;
811
812         /*
813          * Read monitoring data IFF it is supplied AND is
814          * internally calibrated
815          */
816         flags = SFF_8472_DDM_DONE | SFF_8472_DDM_INTERNAL;
817         if ((diag_type & flags) == flags)
818                 ii->do_diag = 1;
819
820         /* Transceiver type */
821         get_sfp_identifier(ii, buf, sizeof(buf));
822         get_sfp_transceiver_class(ii, buf2, sizeof(buf2));
823         get_sfp_connector(ii, buf3, sizeof(buf3));
824         if (ii->error == 0)
825                 printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3);
826         print_sfp_vendor(ii, buf, sizeof(buf));
827         if (ii->error == 0)
828                 printf("\t%s\n", buf);
829
830         if (verbose > 5)
831                 printf_sfp_transceiver_descr(ii, buf, sizeof(buf));
832         /*
833          * Request current measurements iff they are provided:
834          */
835         if (ii->do_diag != 0) {
836                 get_sfp_temp(ii, buf, sizeof(buf));
837                 get_sfp_voltage(ii, buf2, sizeof(buf2));
838                 printf("\tmodule temperature: %s Voltage: %s\n", buf, buf2);
839                 get_sfp_rx_power(ii, buf, sizeof(buf));
840                 get_sfp_tx_power(ii, buf2, sizeof(buf2));
841                 printf("\tRX: %s TX: %s\n", buf, buf2);
842         }
843
844         if (verbose > 2) {
845                 printf("\n\tSFF8472 DUMP (0xA0 0..127 range):\n");
846                 dump_i2c_data(ii, SFF_8472_BASE, 0, 128);
847         }
848 }
849
850 void
851 sfp_status(int s, struct ifreq *ifr, int verbose)
852 {
853         struct i2c_info ii;
854         uint8_t id_byte;
855
856         /* Prepare necessary into pass to i2c reader */
857         memset(&ii, 0, sizeof(ii));
858         ii.fd = s;
859         ii.ifr = ifr;
860
861         /*
862          * Try to read byte 0 from i2c:
863          * Both SFF-8472 and SFF-8436 use it as
864          * 'identification byte'.
865          * Stop reading status on zero as value - 
866          * this might happen in case of empty transceiver slot.
867          */
868         id_byte = 0;
869         read_i2c(&ii, SFF_8472_BASE, SFF_8472_ID, 1, (caddr_t)&id_byte);
870         if (ii.error != 0 || id_byte == 0)
871                 return;
872
873         switch (id_byte) {
874         case SFF_8024_ID_QSFP:
875         case SFF_8024_ID_QSFPPLUS:
876                 print_qsfp_status(&ii, verbose);
877                 break;
878         default:
879                 print_sfp_status(&ii, verbose);
880         };
881 }
882