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