1270064Smelifaro/*-
2270064Smelifaro * Copyright (c) 2014 Alexander V. Chernikov. All rights reserved.
3270064Smelifaro *
4270064Smelifaro * Redistribution and use in source and binary forms, with or without
5270064Smelifaro * modification, are permitted provided that the following conditions
6270064Smelifaro * are met:
7270064Smelifaro * 1. Redistributions of source code must retain the above copyright
8270064Smelifaro *    notice, this list of conditions and the following disclaimer.
9270064Smelifaro * 2. Redistributions in binary form must reproduce the above copyright
10270064Smelifaro *    notice, this list of conditions and the following disclaimer in the
11270064Smelifaro *    documentation and/or other materials provided with the distribution.
12270064Smelifaro *
13270064Smelifaro * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14270064Smelifaro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15270064Smelifaro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16270064Smelifaro * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17270064Smelifaro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18270064Smelifaro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19270064Smelifaro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20270064Smelifaro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21270064Smelifaro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22270064Smelifaro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23270064Smelifaro * SUCH DAMAGE.
24270064Smelifaro */
25270064Smelifaro
26270064Smelifaro#ifndef lint
27270064Smelifarostatic const char rcsid[] =
28270064Smelifaro  "$FreeBSD$";
29270064Smelifaro#endif /* not lint */
30270064Smelifaro
31270064Smelifaro#include <sys/types.h>
32270064Smelifaro#include <sys/param.h>
33270064Smelifaro#include <sys/ioctl.h>
34270064Smelifaro#include <sys/socket.h>
35270064Smelifaro
36270064Smelifaro#include <net/if.h>
37286810Smelifaro#include <net/sff8436.h>
38286810Smelifaro#include <net/sff8472.h>
39270064Smelifaro
40270064Smelifaro#include <math.h>
41270064Smelifaro#include <err.h>
42270064Smelifaro#include <errno.h>
43286810Smelifaro#include <fcntl.h>
44270064Smelifaro#include <stdio.h>
45270064Smelifaro#include <stdlib.h>
46270064Smelifaro#include <string.h>
47270064Smelifaro#include <unistd.h>
48270064Smelifaro
49270064Smelifaro#include "ifconfig.h"
50270064Smelifaro
51270064Smelifarostruct i2c_info {
52286810Smelifaro	int fd;			/* fd to issue SIOCGI2C */
53286810Smelifaro	int error;		/* Store first error */
54286810Smelifaro	int qsfp;		/* True if transceiver is QSFP */
55286810Smelifaro	int do_diag;		/* True if we need to request DDM */
56286810Smelifaro	struct ifreq *ifr;	/* Pointer to pre-filled ifreq */
57270064Smelifaro};
58270064Smelifaro
59286810Smelifarostatic int read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off,
60286810Smelifaro    uint8_t len, uint8_t *buf);
61286810Smelifarostatic void dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off,
62286810Smelifaro    uint8_t len);
63286810Smelifaro
64270064Smelifarostruct _nv {
65270064Smelifaro	int v;
66270064Smelifaro	const char *n;
67270064Smelifaro};
68270064Smelifaro
69270064Smelifaroconst char *find_value(struct _nv *x, int value);
70270064Smelifaroconst char *find_zero_bit(struct _nv *x, int value, int sz);
71270064Smelifaro
72270064Smelifaro/* SFF-8472 Rev. 11.4 table 3.4: Connector values */
73270064Smelifarostatic struct _nv conn[] = {
74270064Smelifaro	{ 0x00, "Unknown" },
75270064Smelifaro	{ 0x01, "SC" },
76270064Smelifaro	{ 0x02, "Fibre Channel Style 1 copper" },
77270064Smelifaro	{ 0x03, "Fibre Channel Style 2 copper" },
78270064Smelifaro	{ 0x04, "BNC/TNC" },
79270064Smelifaro	{ 0x05, "Fibre Channel coaxial" },
80270064Smelifaro	{ 0x06, "FiberJack" },
81270064Smelifaro	{ 0x07, "LC" },
82270064Smelifaro	{ 0x08, "MT-RJ" },
83270064Smelifaro	{ 0x09, "MU" },
84270064Smelifaro	{ 0x0A, "SG" },
85270064Smelifaro	{ 0x0B, "Optical pigtail" },
86270064Smelifaro	{ 0x0C, "MPO Parallel Optic" },
87270064Smelifaro	{ 0x20, "HSSDC II" },
88270064Smelifaro	{ 0x21, "Copper pigtail" },
89270064Smelifaro	{ 0x22, "RJ45" },
90286810Smelifaro	{ 0x23, "No separate connector" }, /* SFF-8436 */
91270064Smelifaro	{ 0, NULL }
92270064Smelifaro};
93270064Smelifaro
94270064Smelifaro/* SFF-8472 Rev. 11.4 table 3.5: Transceiver codes */
95286810Smelifaro/* 10G Ethernet/IB compliance codes, byte 3 */
96270064Smelifarostatic struct _nv eth_10g[] = {
97270064Smelifaro	{ 0x80, "10G Base-ER" },
98270064Smelifaro	{ 0x40, "10G Base-LRM" },
99270064Smelifaro	{ 0x20, "10G Base-LR" },
100270064Smelifaro	{ 0x10, "10G Base-SR" },
101270064Smelifaro	{ 0x08, "1X SX" },
102270064Smelifaro	{ 0x04, "1X LX" },
103270064Smelifaro	{ 0x02, "1X Copper Active" },
104270064Smelifaro	{ 0x01, "1X Copper Passive" },
105270064Smelifaro	{ 0, NULL }
106270064Smelifaro};
107270064Smelifaro
108270064Smelifaro/* Ethernet compliance codes, byte 6 */
109270064Smelifarostatic struct _nv eth_compat[] = {
110270064Smelifaro	{ 0x80, "BASE-PX" },
111270064Smelifaro	{ 0x40, "BASE-BX10" },
112270064Smelifaro	{ 0x20, "100BASE-FX" },
113270064Smelifaro	{ 0x10, "100BASE-LX/LX10" },
114270064Smelifaro	{ 0x08, "1000BASE-T" },
115270064Smelifaro	{ 0x04, "1000BASE-CX" },
116270064Smelifaro	{ 0x02, "1000BASE-LX" },
117270064Smelifaro	{ 0x01, "1000BASE-SX" },
118270064Smelifaro	{ 0, NULL }
119270064Smelifaro};
120270064Smelifaro
121270064Smelifaro/* FC link length, byte 7 */
122270064Smelifarostatic struct _nv fc_len[] = {
123270064Smelifaro	{ 0x80, "very long distance" },
124270064Smelifaro	{ 0x40, "short distance" },
125270064Smelifaro	{ 0x20, "intermediate distance" },
126270064Smelifaro	{ 0x10, "long distance" },
127270064Smelifaro	{ 0x08, "medium distance" },
128270064Smelifaro	{ 0, NULL }
129270064Smelifaro};
130270064Smelifaro
131270064Smelifaro/* Channel/Cable technology, byte 7-8 */
132270064Smelifarostatic struct _nv cab_tech[] = {
133270064Smelifaro	{ 0x0400, "Shortwave laser (SA)" },
134270064Smelifaro	{ 0x0200, "Longwave laser (LC)" },
135270064Smelifaro	{ 0x0100, "Electrical inter-enclosure (EL)" },
136270064Smelifaro	{ 0x80, "Electrical intra-enclosure (EL)" },
137270064Smelifaro	{ 0x40, "Shortwave laser (SN)" },
138270064Smelifaro	{ 0x20, "Shortwave laser (SL)" },
139270064Smelifaro	{ 0x10, "Longwave laser (LL)" },
140270064Smelifaro	{ 0x08, "Active Cable" },
141270064Smelifaro	{ 0x04, "Passive Cable" },
142270064Smelifaro	{ 0, NULL }
143270064Smelifaro};
144270064Smelifaro
145270064Smelifaro/* FC Transmission media, byte 9 */
146270064Smelifarostatic struct _nv fc_media[] = {
147270064Smelifaro	{ 0x80, "Twin Axial Pair" },
148270064Smelifaro	{ 0x40, "Twisted Pair" },
149270064Smelifaro	{ 0x20, "Miniature Coax" },
150270064Smelifaro	{ 0x10, "Viao Coax" },
151270064Smelifaro	{ 0x08, "Miltimode, 62.5um" },
152270064Smelifaro	{ 0x04, "Multimode, 50um" },
153270064Smelifaro	{ 0x02, "" },
154270064Smelifaro	{ 0x01, "Single Mode" },
155270064Smelifaro	{ 0, NULL }
156270064Smelifaro};
157270064Smelifaro
158270064Smelifaro/* FC Speed, byte 10 */
159270064Smelifarostatic struct _nv fc_speed[] = {
160270064Smelifaro	{ 0x80, "1200 MBytes/sec" },
161270064Smelifaro	{ 0x40, "800 MBytes/sec" },
162270064Smelifaro	{ 0x20, "1600 MBytes/sec" },
163270064Smelifaro	{ 0x10, "400 MBytes/sec" },
164270064Smelifaro	{ 0x08, "3200 MBytes/sec" },
165270064Smelifaro	{ 0x04, "200 MBytes/sec" },
166270064Smelifaro	{ 0x01, "100 MBytes/sec" },
167270064Smelifaro	{ 0, NULL }
168270064Smelifaro};
169270064Smelifaro
170286810Smelifaro/* SFF-8436 Rev. 4.8 table 33: Specification compliance  */
171286810Smelifaro
172286810Smelifaro/* 10/40G Ethernet compliance codes, byte 128 + 3 */
173286810Smelifarostatic struct _nv eth_1040g[] = {
174294202Smelifaro	{ 0x80, "Extended" },
175286810Smelifaro	{ 0x40, "10GBASE-LRM" },
176286810Smelifaro	{ 0x20, "10GBASE-LR" },
177286810Smelifaro	{ 0x10, "10GBASE-SR" },
178286810Smelifaro	{ 0x08, "40GBASE-CR4" },
179286810Smelifaro	{ 0x04, "40GBASE-SR4" },
180286810Smelifaro	{ 0x02, "40GBASE-LR4" },
181286810Smelifaro	{ 0x01, "40G Active Cable" },
182286810Smelifaro	{ 0, NULL }
183286810Smelifaro};
184294202Smelifaro#define	SFF_8636_EXT_COMPLIANCE	0x80
185286810Smelifaro
186294202Smelifaro/* SFF-8024 Rev. 3.4 table 4.4: Extended Specification Compliance */
187294202Smelifarostatic struct _nv eth_extended_comp[] = {
188294202Smelifaro	{ 0xFF, "Reserved" },
189294202Smelifaro	{ 0x1A, "2 lambda DWDM 100G" },
190294202Smelifaro	{ 0x19, "100G ACC or 25GAUI C2M ACC" },
191294202Smelifaro	{ 0x18, "100G AOC or 25GAUI C2M AOC" },
192294202Smelifaro	{ 0x17, "100G CLR4" },
193294202Smelifaro	{ 0x16, "10GBASE-T with SFI electrical interface" },
194294202Smelifaro	{ 0x15, "G959.1 profile P1L1-2D2" },
195294202Smelifaro	{ 0x14, "G959.1 profile P1S1-2D2" },
196294202Smelifaro	{ 0x13, "G959.1 profile P1I1-2D1" },
197294202Smelifaro	{ 0x12, "40G PSM4 Parallel SMF" },
198294202Smelifaro	{ 0x11, "4 x 10GBASE-SR" },
199294202Smelifaro	{ 0x10, "40GBASE-ER4" },
200294202Smelifaro	{ 0x0F, "Reserved" },
201294202Smelifaro	{ 0x0D, "25GBASE-CR CA-N" },
202294202Smelifaro	{ 0x0C, "25GBASE-CR CA-S" },
203294202Smelifaro	{ 0x0B, "100GBASE-CR4 or 25GBASE-CR CA-L" },
204294202Smelifaro	{ 0x0A, "Reserved" },
205294202Smelifaro	{ 0x09, "100G CWDM4 MSA without FEC" },
206294202Smelifaro	{ 0x08, "100G ACC (Active Copper Cable)" },
207294202Smelifaro	{ 0x07, "100G PSM4 Parallel SMF" },
208294202Smelifaro	{ 0x06, "100G CWDM4 MSA with FEC" },
209294202Smelifaro	{ 0x05, "100GBASE-SR10" },
210294202Smelifaro	{ 0x04, "100GBASE-ER4" },
211294202Smelifaro	{ 0x03, "100GBASE-LR4" },
212294202Smelifaro	{ 0x02, "100GBASE-SR4" },
213294202Smelifaro	{ 0x01, "100G AOC (Active Optical Cable) or 25GAUI C2M ACC" },
214294202Smelifaro	{ 0x00, "Unspecified" }
215294202Smelifaro};
216294202Smelifaro
217286810Smelifaro/* SFF-8636 Rev. 2.5 table 6.3: Revision compliance */
218286810Smelifarostatic struct _nv rev_compl[] = {
219286810Smelifaro	{ 0x1, "SFF-8436 rev <=4.8" },
220286810Smelifaro	{ 0x2, "SFF-8436 rev <=4.8" },
221286810Smelifaro	{ 0x3, "SFF-8636 rev <=1.3" },
222286810Smelifaro	{ 0x4, "SFF-8636 rev <=1.4" },
223286810Smelifaro	{ 0x5, "SFF-8636 rev <=1.5" },
224286810Smelifaro	{ 0x6, "SFF-8636 rev <=2.0" },
225286810Smelifaro	{ 0x7, "SFF-8636 rev <=2.5" },
226286810Smelifaro	{ 0x0, "Unspecified" }
227286810Smelifaro};
228286810Smelifaro
229286810Smelifaroconst char *
230286810Smelifarofind_value(struct _nv *x, int value)
231286810Smelifaro{
232286810Smelifaro	for (; x->n != NULL; x++)
233286810Smelifaro		if (x->v == value)
234286810Smelifaro			return (x->n);
235286810Smelifaro	return (NULL);
236286810Smelifaro}
237286810Smelifaro
238286810Smelifaroconst char *
239286810Smelifarofind_zero_bit(struct _nv *x, int value, int sz)
240286810Smelifaro{
241286810Smelifaro	int v, m;
242286810Smelifaro	const char *s;
243286810Smelifaro
244286810Smelifaro	v = 1;
245286810Smelifaro	for (v = 1, m = 1 << (8 * sz); v < m; v *= 2) {
246286810Smelifaro		if ((value & v) == 0)
247286810Smelifaro			continue;
248286810Smelifaro		if ((s = find_value(x, value & v)) != NULL) {
249286810Smelifaro			value &= ~v;
250286810Smelifaro			return (s);
251286810Smelifaro		}
252286810Smelifaro	}
253286810Smelifaro
254286810Smelifaro	return (NULL);
255286810Smelifaro}
256286810Smelifaro
257270064Smelifarostatic void
258286810Smelifaroconvert_sff_identifier(char *buf, size_t size, uint8_t value)
259286810Smelifaro{
260286810Smelifaro	const char *x;
261286810Smelifaro
262286810Smelifaro	x = NULL;
263286810Smelifaro	if (value <= SFF_8024_ID_LAST)
264286810Smelifaro		x = sff_8024_id[value];
265286810Smelifaro	else {
266286810Smelifaro		if (value > 0x80)
267286810Smelifaro			x = "Vendor specific";
268286810Smelifaro		else
269286810Smelifaro			x = "Reserved";
270286810Smelifaro	}
271286810Smelifaro
272286810Smelifaro	snprintf(buf, size, "%s", x);
273286810Smelifaro}
274286810Smelifaro
275286810Smelifarostatic void
276286810Smelifaroconvert_sff_connector(char *buf, size_t size, uint8_t value)
277286810Smelifaro{
278286810Smelifaro	const char *x;
279286810Smelifaro
280286810Smelifaro	if ((x = find_value(conn, value)) == NULL) {
281286810Smelifaro		if (value >= 0x0D && value <= 0x1F)
282286810Smelifaro			x = "Unallocated";
283286810Smelifaro		else if (value >= 0x24 && value <= 0x7F)
284286810Smelifaro			x = "Unallocated";
285286810Smelifaro		else
286286810Smelifaro			x = "Vendor specific";
287286810Smelifaro	}
288286810Smelifaro
289286810Smelifaro	snprintf(buf, size, "%s", x);
290286810Smelifaro}
291286810Smelifaro
292286810Smelifarostatic void
293286810Smelifaroconvert_sff_rev_compliance(char *buf, size_t size, uint8_t value)
294286810Smelifaro{
295286810Smelifaro	const char *x;
296286810Smelifaro
297286810Smelifaro	if (value > 0x07)
298286810Smelifaro		x = "Unallocated";
299286810Smelifaro	else
300286810Smelifaro		x = find_value(rev_compl, value);
301286810Smelifaro
302286810Smelifaro	snprintf(buf, size, "%s", x);
303286810Smelifaro}
304286810Smelifaro
305286810Smelifarostatic void
306286810Smelifaroget_sfp_identifier(struct i2c_info *ii, char *buf, size_t size)
307286810Smelifaro{
308286810Smelifaro	uint8_t data;
309286810Smelifaro
310286810Smelifaro	read_i2c(ii, SFF_8472_BASE, SFF_8472_ID, 1, &data);
311286810Smelifaro	convert_sff_identifier(buf, size, data);
312286810Smelifaro}
313286810Smelifaro
314286810Smelifarostatic void
315286810Smelifaroget_sfp_connector(struct i2c_info *ii, char *buf, size_t size)
316286810Smelifaro{
317286810Smelifaro	uint8_t data;
318286810Smelifaro
319286810Smelifaro	read_i2c(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, &data);
320286810Smelifaro	convert_sff_connector(buf, size, data);
321286810Smelifaro}
322286810Smelifaro
323286810Smelifarostatic void
324286810Smelifaroget_qsfp_identifier(struct i2c_info *ii, char *buf, size_t size)
325286810Smelifaro{
326286810Smelifaro	uint8_t data;
327286810Smelifaro
328286810Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_ID, 1, &data);
329286810Smelifaro	convert_sff_identifier(buf, size, data);
330286810Smelifaro}
331286810Smelifaro
332286810Smelifarostatic void
333286810Smelifaroget_qsfp_connector(struct i2c_info *ii, char *buf, size_t size)
334286810Smelifaro{
335286810Smelifaro	uint8_t data;
336286810Smelifaro
337286810Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_CONNECTOR, 1, &data);
338286810Smelifaro	convert_sff_connector(buf, size, data);
339286810Smelifaro}
340286810Smelifaro
341286810Smelifarostatic void
342270064Smelifaroprintf_sfp_transceiver_descr(struct i2c_info *ii, char *buf, size_t size)
343270064Smelifaro{
344270064Smelifaro	char xbuf[12];
345270064Smelifaro	const char *tech_class, *tech_len, *tech_tech, *tech_media, *tech_speed;
346270064Smelifaro
347270064Smelifaro	tech_class = NULL;
348270064Smelifaro	tech_len = NULL;
349270064Smelifaro	tech_tech = NULL;
350270064Smelifaro	tech_media = NULL;
351270064Smelifaro	tech_speed = NULL;
352270064Smelifaro
353270064Smelifaro	/* Read bytes 3-10 at once */
354286810Smelifaro	read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, &xbuf[3]);
355270064Smelifaro
356286810Smelifaro	/* Check 10G ethernet first */
357270064Smelifaro	tech_class = find_zero_bit(eth_10g, xbuf[3], 1);
358270064Smelifaro	if (tech_class == NULL) {
359270064Smelifaro		/* No match. Try 1G */
360270064Smelifaro		tech_class = find_zero_bit(eth_compat, xbuf[6], 1);
361270064Smelifaro	}
362270064Smelifaro
363270064Smelifaro	tech_len = find_zero_bit(fc_len, xbuf[7], 1);
364270064Smelifaro	tech_tech = find_zero_bit(cab_tech, xbuf[7] << 8 | xbuf[8], 2);
365270064Smelifaro	tech_media = find_zero_bit(fc_media, xbuf[9], 1);
366270064Smelifaro	tech_speed = find_zero_bit(fc_speed, xbuf[10], 1);
367270064Smelifaro
368270064Smelifaro	printf("Class: %s\n", tech_class);
369270064Smelifaro	printf("Length: %s\n", tech_len);
370270064Smelifaro	printf("Tech: %s\n", tech_tech);
371270064Smelifaro	printf("Media: %s\n", tech_media);
372270064Smelifaro	printf("Speed: %s\n", tech_speed);
373270064Smelifaro}
374270064Smelifaro
375270064Smelifarostatic void
376270064Smelifaroget_sfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size)
377270064Smelifaro{
378270064Smelifaro	const char *tech_class;
379270064Smelifaro	uint8_t code;
380270064Smelifaro
381286810Smelifaro	unsigned char qbuf[8];
382286810Smelifaro	read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, (uint8_t *)qbuf);
383286810Smelifaro
384270064Smelifaro	/* Check 10G Ethernet/IB first */
385286810Smelifaro	read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, &code);
386270064Smelifaro	tech_class = find_zero_bit(eth_10g, code, 1);
387270064Smelifaro	if (tech_class == NULL) {
388270064Smelifaro		/* No match. Try Ethernet 1G */
389286810Smelifaro		read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3,
390286810Smelifaro		    1, (caddr_t)&code);
391270064Smelifaro		tech_class = find_zero_bit(eth_compat, code, 1);
392270064Smelifaro	}
393270064Smelifaro
394270064Smelifaro	if (tech_class == NULL)
395270064Smelifaro		tech_class = "Unknown";
396270064Smelifaro
397270064Smelifaro	snprintf(buf, size, "%s", tech_class);
398270064Smelifaro}
399270064Smelifaro
400286810Smelifarostatic void
401286810Smelifaroget_qsfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size)
402286810Smelifaro{
403286810Smelifaro	const char *tech_class;
404286810Smelifaro	uint8_t code;
405270064Smelifaro
406294202Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_CODE_E1040100G, 1, &code);
407294202Smelifaro
408294202Smelifaro	/* Check for extended specification compliance */
409294202Smelifaro	if (code & SFF_8636_EXT_COMPLIANCE) {
410294202Smelifaro		read_i2c(ii, SFF_8436_BASE, SFF_8436_OPTIONS_START, 1, &code);
411294202Smelifaro		tech_class = find_value(eth_extended_comp, code);
412294202Smelifaro	} else
413294202Smelifaro		/* Check 10/40G Ethernet class only */
414294202Smelifaro		tech_class = find_zero_bit(eth_1040g, code, 1);
415294202Smelifaro
416286810Smelifaro	if (tech_class == NULL)
417286810Smelifaro		tech_class = "Unknown";
418286810Smelifaro
419286810Smelifaro	snprintf(buf, size, "%s", tech_class);
420286810Smelifaro}
421286810Smelifaro
422286810Smelifaro/*
423286810Smelifaro * Print SFF-8472/SFF-8436 string to supplied buffer.
424286810Smelifaro * All (vendor-specific) strings are padded right with '0x20'.
425286810Smelifaro */
426270064Smelifarostatic void
427286810Smelifaroconvert_sff_name(char *buf, size_t size, char *xbuf)
428270064Smelifaro{
429286810Smelifaro	char *p;
430270064Smelifaro
431270064Smelifaro	for (p = &xbuf[16]; *(p - 1) == 0x20; p--)
432270064Smelifaro		;
433270064Smelifaro	*p = '\0';
434270064Smelifaro	snprintf(buf, size, "%s", xbuf);
435270064Smelifaro}
436270064Smelifaro
437270064Smelifarostatic void
438286810Smelifaroconvert_sff_date(char *buf, size_t size, char *xbuf)
439286810Smelifaro{
440286810Smelifaro
441286810Smelifaro	snprintf(buf, size, "20%c%c-%c%c-%c%c", xbuf[0], xbuf[1],
442286810Smelifaro	    xbuf[2], xbuf[3], xbuf[4], xbuf[5]);
443286810Smelifaro}
444286810Smelifaro
445286810Smelifarostatic void
446286810Smelifaroget_sfp_vendor_name(struct i2c_info *ii, char *buf, size_t size)
447286810Smelifaro{
448286810Smelifaro	char xbuf[17];
449286810Smelifaro
450286810Smelifaro	memset(xbuf, 0, sizeof(xbuf));
451286810Smelifaro	read_i2c(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, 16, (uint8_t *)xbuf);
452286810Smelifaro	convert_sff_name(buf, size, xbuf);
453286810Smelifaro}
454286810Smelifaro
455286810Smelifarostatic void
456270064Smelifaroget_sfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size)
457270064Smelifaro{
458286810Smelifaro	char xbuf[17];
459270064Smelifaro
460270064Smelifaro	memset(xbuf, 0, sizeof(xbuf));
461286810Smelifaro	read_i2c(ii, SFF_8472_BASE, SFF_8472_PN_START, 16, (uint8_t *)xbuf);
462286810Smelifaro	convert_sff_name(buf, size, xbuf);
463270064Smelifaro}
464270064Smelifaro
465270064Smelifarostatic void
466270064Smelifaroget_sfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size)
467270064Smelifaro{
468286810Smelifaro	char xbuf[17];
469270064Smelifaro
470270064Smelifaro	memset(xbuf, 0, sizeof(xbuf));
471286810Smelifaro	read_i2c(ii, SFF_8472_BASE, SFF_8472_SN_START, 16, (uint8_t *)xbuf);
472286810Smelifaro	convert_sff_name(buf, size, xbuf);
473270064Smelifaro}
474270064Smelifaro
475270064Smelifarostatic void
476270064Smelifaroget_sfp_vendor_date(struct i2c_info *ii, char *buf, size_t size)
477270064Smelifaro{
478270064Smelifaro	char xbuf[6];
479270064Smelifaro
480270064Smelifaro	memset(xbuf, 0, sizeof(xbuf));
481270064Smelifaro	/* Date code, see Table 3.8 for description */
482286810Smelifaro	read_i2c(ii, SFF_8472_BASE, SFF_8472_DATE_START, 6, (uint8_t *)xbuf);
483286810Smelifaro	convert_sff_date(buf, size, xbuf);
484270064Smelifaro}
485270064Smelifaro
486270064Smelifarostatic void
487286810Smelifaroget_qsfp_vendor_name(struct i2c_info *ii, char *buf, size_t size)
488286810Smelifaro{
489286810Smelifaro	char xbuf[17];
490286810Smelifaro
491286810Smelifaro	memset(xbuf, 0, sizeof(xbuf));
492286810Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, 16, (uint8_t *)xbuf);
493286810Smelifaro	convert_sff_name(buf, size, xbuf);
494286810Smelifaro}
495286810Smelifaro
496286810Smelifarostatic void
497286810Smelifaroget_qsfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size)
498286810Smelifaro{
499286810Smelifaro	char xbuf[17];
500286810Smelifaro
501286810Smelifaro	memset(xbuf, 0, sizeof(xbuf));
502286810Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_PN_START, 16, (uint8_t *)xbuf);
503286810Smelifaro	convert_sff_name(buf, size, xbuf);
504286810Smelifaro}
505286810Smelifaro
506286810Smelifarostatic void
507286810Smelifaroget_qsfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size)
508286810Smelifaro{
509286810Smelifaro	char xbuf[17];
510286810Smelifaro
511286810Smelifaro	memset(xbuf, 0, sizeof(xbuf));
512286810Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_SN_START, 16, (uint8_t *)xbuf);
513286810Smelifaro	convert_sff_name(buf, size, xbuf);
514286810Smelifaro}
515286810Smelifaro
516286810Smelifarostatic void
517286810Smelifaroget_qsfp_vendor_date(struct i2c_info *ii, char *buf, size_t size)
518286810Smelifaro{
519286810Smelifaro	char xbuf[6];
520286810Smelifaro
521286810Smelifaro	memset(xbuf, 0, sizeof(xbuf));
522286810Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_DATE_START, 6, (uint8_t *)xbuf);
523286810Smelifaro	convert_sff_date(buf, size, xbuf);
524286810Smelifaro}
525286810Smelifaro
526286810Smelifarostatic void
527270064Smelifaroprint_sfp_vendor(struct i2c_info *ii, char *buf, size_t size)
528270064Smelifaro{
529270064Smelifaro	char xbuf[80];
530270064Smelifaro
531270064Smelifaro	memset(xbuf, 0, sizeof(xbuf));
532286810Smelifaro	if (ii->qsfp != 0) {
533286810Smelifaro		get_qsfp_vendor_name(ii, xbuf, 20);
534286810Smelifaro		get_qsfp_vendor_pn(ii, &xbuf[20], 20);
535286810Smelifaro		get_qsfp_vendor_sn(ii, &xbuf[40], 20);
536286810Smelifaro		get_qsfp_vendor_date(ii, &xbuf[60], 20);
537286810Smelifaro	} else {
538286810Smelifaro		get_sfp_vendor_name(ii, xbuf, 20);
539286810Smelifaro		get_sfp_vendor_pn(ii, &xbuf[20], 20);
540286810Smelifaro		get_sfp_vendor_sn(ii, &xbuf[40], 20);
541286810Smelifaro		get_sfp_vendor_date(ii, &xbuf[60], 20);
542286810Smelifaro	}
543270064Smelifaro
544270064Smelifaro	snprintf(buf, size, "vendor: %s PN: %s SN: %s DATE: %s",
545270064Smelifaro	    xbuf, &xbuf[20],  &xbuf[40], &xbuf[60]);
546270064Smelifaro}
547270064Smelifaro
548286810Smelifaro/*
549286810Smelifaro * Converts internal templerature (SFF-8472, SFF-8436)
550286810Smelifaro * 16-bit unsigned value to human-readable representation:
551286810Smelifaro *
552286810Smelifaro * Internally measured Module temperature are represented
553286810Smelifaro * as a 16-bit signed twos complement value in increments of
554286810Smelifaro * 1/256 degrees Celsius, yielding a total range of ���128C to +128C
555286810Smelifaro * that is considered valid between ���40 and +125C.
556286810Smelifaro *
557286810Smelifaro */
558270064Smelifarostatic void
559286810Smelifaroconvert_sff_temp(char *buf, size_t size, uint8_t *xbuf)
560270064Smelifaro{
561286810Smelifaro	double d;
562270064Smelifaro
563286810Smelifaro	d = (double)xbuf[0];
564286810Smelifaro	d += (double)xbuf[1] / 256;
565270064Smelifaro
566286810Smelifaro	snprintf(buf, size, "%.2f C", d);
567286810Smelifaro}
568270064Smelifaro
569286810Smelifaro/*
570286810Smelifaro * Retrieves supplied voltage (SFF-8472, SFF-8436).
571286810Smelifaro * 16-bit usigned value, treated as range 0..+6.55 Volts
572286810Smelifaro */
573286810Smelifarostatic void
574286810Smelifaroconvert_sff_voltage(char *buf, size_t size, uint8_t *xbuf)
575286810Smelifaro{
576286810Smelifaro	double d;
577270064Smelifaro
578286810Smelifaro	d = (double)((xbuf[0] << 8) | xbuf[1]);
579286810Smelifaro	snprintf(buf, size, "%.2f Volts", d / 10000);
580270064Smelifaro}
581270064Smelifaro
582286810Smelifaro/*
583286810Smelifaro * Converts value in @xbuf to both milliwats and dBm
584286810Smelifaro * human representation.
585286810Smelifaro */
586270064Smelifarostatic void
587286810Smelifaroconvert_sff_power(struct i2c_info *ii, char *buf, size_t size, uint8_t *xbuf)
588270064Smelifaro{
589270064Smelifaro	uint16_t mW;
590270064Smelifaro	double dbm;
591270064Smelifaro
592286810Smelifaro	mW = (xbuf[0] << 8) + xbuf[1];
593270064Smelifaro
594270064Smelifaro	/* Convert mw to dbm */
595270064Smelifaro	dbm = 10.0 * log10(1.0 * mW / 10000);
596270064Smelifaro
597286810Smelifaro	/*
598286810Smelifaro	 * Assume internally-calibrated data.
599286810Smelifaro	 * This is always true for SFF-8346, and explicitly
600286810Smelifaro	 * checked for SFF-8472.
601286810Smelifaro	 */
602286810Smelifaro
603270064Smelifaro	/* Table 3.9, bit 5 is set, internally calibrated */
604286810Smelifaro	snprintf(buf, size, "%d.%02d mW (%.2f dBm)",
605286810Smelifaro    	    mW / 10000, (mW % 10000) / 100, dbm);
606270064Smelifaro}
607270064Smelifaro
608270064Smelifarostatic void
609286810Smelifaroget_sfp_temp(struct i2c_info *ii, char *buf, size_t size)
610286810Smelifaro{
611286810Smelifaro	uint8_t xbuf[2];
612286810Smelifaro
613286810Smelifaro	memset(xbuf, 0, sizeof(xbuf));
614286810Smelifaro	read_i2c(ii, SFF_8472_DIAG, SFF_8472_TEMP, 2, xbuf);
615286810Smelifaro	convert_sff_temp(buf, size, xbuf);
616286810Smelifaro}
617286810Smelifaro
618286810Smelifarostatic void
619286810Smelifaroget_sfp_voltage(struct i2c_info *ii, char *buf, size_t size)
620286810Smelifaro{
621286810Smelifaro	uint8_t xbuf[2];
622286810Smelifaro
623286810Smelifaro	memset(xbuf, 0, sizeof(xbuf));
624286810Smelifaro	read_i2c(ii, SFF_8472_DIAG, SFF_8472_VCC, 2, xbuf);
625286810Smelifaro	convert_sff_voltage(buf, size, xbuf);
626286810Smelifaro}
627286810Smelifaro
628297640Shselaskystatic int
629286810Smelifaroget_qsfp_temp(struct i2c_info *ii, char *buf, size_t size)
630286810Smelifaro{
631286810Smelifaro	uint8_t xbuf[2];
632286810Smelifaro
633286810Smelifaro	memset(xbuf, 0, sizeof(xbuf));
634286810Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_TEMP, 2, xbuf);
635297640Shselasky	if ((xbuf[0] == 0xFF && xbuf[1] == 0xFF) || (xbuf[0] == 0 && xbuf[1] == 0))
636297640Shselasky		return (-1);
637286810Smelifaro	convert_sff_temp(buf, size, xbuf);
638297640Shselasky	return (0);
639286810Smelifaro}
640286810Smelifaro
641286810Smelifarostatic void
642286810Smelifaroget_qsfp_voltage(struct i2c_info *ii, char *buf, size_t size)
643286810Smelifaro{
644286810Smelifaro	uint8_t xbuf[2];
645286810Smelifaro
646286810Smelifaro	memset(xbuf, 0, sizeof(xbuf));
647286810Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_VCC, 2, xbuf);
648286810Smelifaro	convert_sff_voltage(buf, size, xbuf);
649286810Smelifaro}
650286810Smelifaro
651286810Smelifarostatic void
652270064Smelifaroget_sfp_rx_power(struct i2c_info *ii, char *buf, size_t size)
653270064Smelifaro{
654286810Smelifaro	uint8_t xbuf[2];
655270064Smelifaro
656270064Smelifaro	memset(xbuf, 0, sizeof(xbuf));
657286810Smelifaro	read_i2c(ii, SFF_8472_DIAG, SFF_8472_RX_POWER, 2, xbuf);
658286810Smelifaro	convert_sff_power(ii, buf, size, xbuf);
659270064Smelifaro}
660270064Smelifaro
661270064Smelifarostatic void
662270064Smelifaroget_sfp_tx_power(struct i2c_info *ii, char *buf, size_t size)
663270064Smelifaro{
664286810Smelifaro	uint8_t xbuf[2];
665270064Smelifaro
666270064Smelifaro	memset(xbuf, 0, sizeof(xbuf));
667286810Smelifaro	read_i2c(ii, SFF_8472_DIAG, SFF_8472_TX_POWER, 2, xbuf);
668286810Smelifaro	convert_sff_power(ii, buf, size, xbuf);
669270064Smelifaro}
670270064Smelifaro
671286810Smelifarostatic void
672286810Smelifaroget_qsfp_rx_power(struct i2c_info *ii, char *buf, size_t size, int chan)
673286810Smelifaro{
674286810Smelifaro	uint8_t xbuf[2];
675270064Smelifaro
676286810Smelifaro	memset(xbuf, 0, sizeof(xbuf));
677286810Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_RX_CH1_MSB + (chan-1)*2, 2, xbuf);
678286810Smelifaro	convert_sff_power(ii, buf, size, xbuf);
679286810Smelifaro}
680286810Smelifaro
681286810Smelifarostatic void
682286810Smelifaroget_qsfp_tx_power(struct i2c_info *ii, char *buf, size_t size, int chan)
683286810Smelifaro{
684286810Smelifaro	uint8_t xbuf[2];
685286810Smelifaro
686286810Smelifaro	memset(xbuf, 0, sizeof(xbuf));
687286810Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_TX_CH1_MSB + (chan-1)*2, 2, xbuf);
688286810Smelifaro	convert_sff_power(ii, buf, size, xbuf);
689286810Smelifaro}
690286810Smelifaro
691286810Smelifarostatic void
692286810Smelifaroget_qsfp_rev_compliance(struct i2c_info *ii, char *buf, size_t size)
693286810Smelifaro{
694286810Smelifaro	uint8_t xbuf;
695286810Smelifaro
696286810Smelifaro	xbuf = 0;
697286810Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_STATUS, 1, &xbuf);
698286810Smelifaro	convert_sff_rev_compliance(buf, size, xbuf);
699286810Smelifaro}
700286810Smelifaro
701286810Smelifarostatic uint32_t
702286810Smelifaroget_qsfp_br(struct i2c_info *ii)
703286810Smelifaro{
704286810Smelifaro	uint8_t xbuf;
705286810Smelifaro	uint32_t rate;
706286810Smelifaro
707286810Smelifaro	xbuf = 0;
708286810Smelifaro	read_i2c(ii, SFF_8436_BASE, SFF_8436_BITRATE, 1, &xbuf);
709286810Smelifaro	rate = xbuf * 100;
710286810Smelifaro	if (xbuf == 0xFF) {
711286810Smelifaro		read_i2c(ii, SFF_8436_BASE, SFF_8636_BITRATE, 1, &xbuf);
712286810Smelifaro		rate = xbuf * 250;
713286810Smelifaro	}
714286810Smelifaro
715286810Smelifaro	return (rate);
716286810Smelifaro}
717286810Smelifaro
718286810Smelifaro/*
719286810Smelifaro * Reads i2c data from opened kernel socket.
720286810Smelifaro */
721270064Smelifarostatic int
722286810Smelifaroread_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len,
723286810Smelifaro    uint8_t *buf)
724270064Smelifaro{
725286810Smelifaro	struct ifi2creq req;
726286810Smelifaro	int i, l;
727270064Smelifaro
728270064Smelifaro	if (ii->error != 0)
729270064Smelifaro		return (ii->error);
730270064Smelifaro
731286810Smelifaro	ii->ifr->ifr_data = (caddr_t)&req;
732270064Smelifaro
733286810Smelifaro	i = 0;
734286810Smelifaro	l = 0;
735286810Smelifaro	memset(&req, 0, sizeof(req));
736286810Smelifaro	req.dev_addr = addr;
737286810Smelifaro	req.offset = off;
738286810Smelifaro	req.len = len;
739270064Smelifaro
740286810Smelifaro	while (len > 0) {
741286810Smelifaro		l = (len > sizeof(req.data)) ? sizeof(req.data) : len;
742286810Smelifaro		req.len = l;
743286810Smelifaro		if (ioctl(ii->fd, SIOCGI2C, ii->ifr) != 0) {
744270064Smelifaro			ii->error = errno;
745270064Smelifaro			return (errno);
746270064Smelifaro		}
747286810Smelifaro
748286810Smelifaro		memcpy(&buf[i], req.data, l);
749286810Smelifaro		len -= l;
750286810Smelifaro		i += l;
751286810Smelifaro		req.offset += l;
752270064Smelifaro	}
753270064Smelifaro
754270064Smelifaro	return (0);
755270064Smelifaro}
756270064Smelifaro
757286810Smelifarostatic void
758286810Smelifarodump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len)
759270064Smelifaro{
760286810Smelifaro	unsigned char buf[16];
761286810Smelifaro	int i, read;
762286810Smelifaro
763286810Smelifaro	while (len > 0) {
764286810Smelifaro		memset(buf, 0, sizeof(buf));
765286810Smelifaro		read = (len > sizeof(buf)) ? sizeof(buf) : len;
766286810Smelifaro		read_i2c(ii, addr, off, read, buf);
767286810Smelifaro		if (ii->error != 0) {
768286810Smelifaro			fprintf(stderr, "Error reading i2c info\n");
769286810Smelifaro			return;
770286810Smelifaro		}
771286810Smelifaro
772286810Smelifaro		printf("\t");
773286810Smelifaro		for (i = 0; i < read; i++)
774286810Smelifaro			printf("%02X ", buf[i]);
775286810Smelifaro		printf("\n");
776286810Smelifaro		len -= read;
777286810Smelifaro		off += read;
778286810Smelifaro	}
779286810Smelifaro}
780286810Smelifaro
781286810Smelifarostatic void
782286810Smelifaroprint_qsfp_status(struct i2c_info *ii, int verbose)
783286810Smelifaro{
784270064Smelifaro	char buf[80], buf2[40], buf3[40];
785286810Smelifaro	uint32_t bitrate;
786286810Smelifaro	int i;
787270064Smelifaro
788286810Smelifaro	ii->qsfp = 1;
789270064Smelifaro
790286810Smelifaro	/* Transceiver type */
791286810Smelifaro	get_qsfp_identifier(ii, buf, sizeof(buf));
792286810Smelifaro	get_qsfp_transceiver_class(ii, buf2, sizeof(buf2));
793286810Smelifaro	get_qsfp_connector(ii, buf3, sizeof(buf3));
794286810Smelifaro	if (ii->error == 0)
795286810Smelifaro		printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3);
796286810Smelifaro	print_sfp_vendor(ii, buf, sizeof(buf));
797286810Smelifaro	if (ii->error == 0)
798286810Smelifaro		printf("\t%s\n", buf);
799270064Smelifaro
800286810Smelifaro	if (verbose > 1) {
801286810Smelifaro		get_qsfp_rev_compliance(ii, buf, sizeof(buf));
802286810Smelifaro		if (ii->error == 0)
803286810Smelifaro			printf("\tcompliance level: %s\n", buf);
804286810Smelifaro
805286810Smelifaro		bitrate = get_qsfp_br(ii);
806286810Smelifaro		if (ii->error == 0 && bitrate > 0)
807286810Smelifaro			printf("\tnominal bitrate: %u Mbps\n", bitrate);
808286810Smelifaro	}
809286810Smelifaro
810297640Shselasky	/*
811297640Shselasky	 * The standards in this area are not clear when the
812297640Shselasky	 * additional measurements are present or not. Use a valid
813297640Shselasky	 * temperature reading as an indicator for the presence of
814297640Shselasky	 * voltage and TX/RX power measurements.
815297640Shselasky	 */
816297640Shselasky	if (get_qsfp_temp(ii, buf, sizeof(buf)) == 0) {
817286810Smelifaro		get_qsfp_voltage(ii, buf2, sizeof(buf2));
818286810Smelifaro		printf("\tmodule temperature: %s voltage: %s\n", buf, buf2);
819286810Smelifaro		for (i = 1; i <= 4; i++) {
820286810Smelifaro			get_qsfp_rx_power(ii, buf, sizeof(buf), i);
821286810Smelifaro			get_qsfp_tx_power(ii, buf2, sizeof(buf2), i);
822286810Smelifaro			printf("\tlane %d: RX: %s TX: %s\n", i, buf, buf2);
823286810Smelifaro		}
824286810Smelifaro	}
825286810Smelifaro
826286810Smelifaro	if (verbose > 2) {
827286810Smelifaro		printf("\n\tSFF8436 DUMP (0xA0 128..255 range):\n");
828286810Smelifaro		dump_i2c_data(ii, SFF_8436_BASE, 128, 128);
829286810Smelifaro		printf("\n\tSFF8436 DUMP (0xA0 0..81 range):\n");
830286810Smelifaro		dump_i2c_data(ii, SFF_8436_BASE, 0, 82);
831286810Smelifaro	}
832286810Smelifaro}
833286810Smelifaro
834286810Smelifarostatic void
835286810Smelifaroprint_sfp_status(struct i2c_info *ii, int verbose)
836286810Smelifaro{
837286810Smelifaro	char buf[80], buf2[40], buf3[40];
838286810Smelifaro	uint8_t diag_type, flags;
839286810Smelifaro
840270064Smelifaro	/* Read diagnostic monitoring type */
841286810Smelifaro	read_i2c(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&diag_type);
842286810Smelifaro	if (ii->error != 0)
843286810Smelifaro		return;
844270064Smelifaro
845286810Smelifaro	/*
846286810Smelifaro	 * Read monitoring data IFF it is supplied AND is
847286810Smelifaro	 * internally calibrated
848286810Smelifaro	 */
849286810Smelifaro	flags = SFF_8472_DDM_DONE | SFF_8472_DDM_INTERNAL;
850286810Smelifaro	if ((diag_type & flags) == flags)
851286810Smelifaro		ii->do_diag = 1;
852286810Smelifaro
853270064Smelifaro	/* Transceiver type */
854286810Smelifaro	get_sfp_identifier(ii, buf, sizeof(buf));
855286810Smelifaro	get_sfp_transceiver_class(ii, buf2, sizeof(buf2));
856286810Smelifaro	get_sfp_connector(ii, buf3, sizeof(buf3));
857286810Smelifaro	if (ii->error == 0)
858286810Smelifaro		printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3);
859286810Smelifaro	print_sfp_vendor(ii, buf, sizeof(buf));
860286810Smelifaro	if (ii->error == 0)
861270064Smelifaro		printf("\t%s\n", buf);
862286810Smelifaro
863286810Smelifaro	if (verbose > 5)
864286810Smelifaro		printf_sfp_transceiver_descr(ii, buf, sizeof(buf));
865270064Smelifaro	/*
866286810Smelifaro	 * Request current measurements iff they are provided:
867270064Smelifaro	 */
868286810Smelifaro	if (ii->do_diag != 0) {
869286810Smelifaro		get_sfp_temp(ii, buf, sizeof(buf));
870286810Smelifaro		get_sfp_voltage(ii, buf2, sizeof(buf2));
871286810Smelifaro		printf("\tmodule temperature: %s Voltage: %s\n", buf, buf2);
872286810Smelifaro		get_sfp_rx_power(ii, buf, sizeof(buf));
873286810Smelifaro		get_sfp_tx_power(ii, buf2, sizeof(buf2));
874286810Smelifaro		printf("\tRX: %s TX: %s\n", buf, buf2);
875270064Smelifaro	}
876270064Smelifaro
877286810Smelifaro	if (verbose > 2) {
878286810Smelifaro		printf("\n\tSFF8472 DUMP (0xA0 0..127 range):\n");
879286810Smelifaro		dump_i2c_data(ii, SFF_8472_BASE, 0, 128);
880286810Smelifaro	}
881270064Smelifaro}
882270064Smelifaro
883286810Smelifarovoid
884286810Smelifarosfp_status(int s, struct ifreq *ifr, int verbose)
885286810Smelifaro{
886286810Smelifaro	struct i2c_info ii;
887286810Smelifaro	uint8_t id_byte;
888286810Smelifaro
889286810Smelifaro	/* Prepare necessary into pass to i2c reader */
890286810Smelifaro	memset(&ii, 0, sizeof(ii));
891286810Smelifaro	ii.fd = s;
892286810Smelifaro	ii.ifr = ifr;
893286810Smelifaro
894286810Smelifaro	/*
895286810Smelifaro	 * Try to read byte 0 from i2c:
896286810Smelifaro	 * Both SFF-8472 and SFF-8436 use it as
897286810Smelifaro	 * 'identification byte'.
898286810Smelifaro	 * Stop reading status on zero as value -
899286810Smelifaro	 * this might happen in case of empty transceiver slot.
900286810Smelifaro	 */
901286810Smelifaro	id_byte = 0;
902286810Smelifaro	read_i2c(&ii, SFF_8472_BASE, SFF_8472_ID, 1, (caddr_t)&id_byte);
903286810Smelifaro	if (ii.error != 0 || id_byte == 0)
904286810Smelifaro		return;
905286810Smelifaro
906286810Smelifaro	switch (id_byte) {
907286810Smelifaro	case SFF_8024_ID_QSFP:
908286810Smelifaro	case SFF_8024_ID_QSFPPLUS:
909294202Smelifaro	case SFF_8024_ID_QSFP28:
910286810Smelifaro		print_qsfp_status(&ii, verbose);
911286810Smelifaro		break;
912286810Smelifaro	default:
913286810Smelifaro		print_sfp_status(&ii, verbose);
914286810Smelifaro	};
915286810Smelifaro}
916286810Smelifaro
917