sfp.c revision 286810
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
27static const char rcsid[] =
28  "$FreeBSD: stable/10/sbin/ifconfig/sfp.c 286810 2015-08-15 17:52:55Z melifaro $";
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
51struct 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
59static int read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off,
60    uint8_t len, uint8_t *buf);
61static void dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off,
62    uint8_t len);
63
64struct _nv {
65	int v;
66	const char *n;
67};
68
69const char *find_value(struct _nv *x, int value);
70const char *find_zero_bit(struct _nv *x, int value, int sz);
71
72/* SFF-8472 Rev. 11.4 table 3.4: Connector values */
73static 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 */
96static 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 */
109static 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 */
122static 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 */
132static 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 */
146static 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 */
159static 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 */
173static 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 */
186static 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
197const char *
198find_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
206const char *
207find_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
225static void
226convert_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
243static void
244convert_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
260static void
261convert_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
273static void
274get_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
282static void
283get_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
291static void
292get_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
300static void
301get_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
309static void
310printf_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
343static void
344get_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
368static void
369get_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 */
387static void
388convert_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
398static void
399convert_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
406static void
407get_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
416static void
417get_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
426static void
427get_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
436static void
437get_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
447static void
448get_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
457static void
458get_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
467static void
468get_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
477static void
478get_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
487static void
488print_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 */
519static void
520convert_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 */
534static void
535convert_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 */
547static void
548convert_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
569static void
570get_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
579static void
580get_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
589static void
590get_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
599static void
600get_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
609static void
610get_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
619static void
620get_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
629static void
630get_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
639static void
640get_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
649static void
650get_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
659static uint32_t
660get_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 */
679static int
680read_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
715static void
716dump_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
739static void
740print_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
801static void
802print_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
850void
851sfp_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
883