1 /*
2 * qsfp.c: Implements SFF-8636 based QSFP+/QSFP28 Diagnostics Memory map.
3 *
4 * Copyright 2010 Solarflare Communications Inc.
5 * Aurelien Guillaume <[email protected]> (C) 2012
6 * Copyright (C) 2014 Cumulus networks Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Freeoftware Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * Vidya Ravipati <[email protected]>
14 * This implementation is loosely based on current SFP parser
15 * and SFF-8636 spec Rev 2.7 (ftp://ftp.seagate.com/pub/sff/SFF-8636.PDF)
16 * by SFF Committee.
17 */
18
19 /*
20 * Description:
21 * a) The register/memory layout is up to 5 128 byte pages defined by
22 * a "pages valid" register and switched via a "page select"
23 * register. Memory of 256 bytes can be memory mapped at a time
24 * according to SFF 8636.
25 * b) SFF 8636 based 640 bytes memory layout is presented for parser
26 *
27 * SFF 8636 based QSFP Memory Map
28 *
29 * 2-Wire Serial Address: 1010000x
30 *
31 * Lower Page 00h (128 bytes)
32 * ======================
33 * | |
34 * |Page Select Byte(127)|
35 * ======================
36 * |
37 * V
38 * ----------------------------------------
39 * | | | |
40 * V V V V
41 * ---------- ---------- --------- ------------
42 * | Upper | | Upper | | Upper | | Upper |
43 * | Page 00h | | Page 01h | | Page 02h | | Page 03h |
44 * | | |(Optional)| |(Optional)| | (Optional) |
45 * | | | | | | | |
46 * | | | | | | | |
47 * | ID | | AST | | User | | For |
48 * | Fields | | Table | | EEPROM | | Cable |
49 * | | | | | Data | | Assemblies |
50 * | | | | | | | |
51 * | | | | | | | |
52 * ----------- ----------- ---------- --------------
53 *
54 *
55 **/
56 #include <stdio.h>
57 #include <math.h>
58 #include <errno.h>
59 #include "internal.h"
60 #include "sff-common.h"
61 #include "qsfp.h"
62 #include "cmis.h"
63 #include "netlink/extapi.h"
64
65 struct sff8636_memory_map {
66 const __u8 *lower_memory;
67 const __u8 *upper_memory[4];
68 #define page_00h upper_memory[0x0]
69 #define page_03h upper_memory[0x3]
70 };
71
72 #define SFF8636_PAGE_SIZE 0x80
73 #define SFF8636_I2C_ADDRESS 0x50
74 #define SFF8636_MAX_CHANNEL_NUM 4
75
76 #define MAX_DESC_SIZE 42
77
78 static struct sff8636_aw_flags {
79 const char *str; /* Human-readable string, null at the end */
80 int offset;
81 __u8 value; /* Alarm is on if (offset & value) != 0. */
82 } sff8636_aw_flags[] = {
83 { "Laser bias current high alarm (Chan 1)",
84 SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_1_HALARM) },
85 { "Laser bias current low alarm (Chan 1)",
86 SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_1_LALARM) },
87 { "Laser bias current high warning (Chan 1)",
88 SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_1_HWARN) },
89 { "Laser bias current low warning (Chan 1)",
90 SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_1_LWARN) },
91
92 { "Laser bias current high alarm (Chan 2)",
93 SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_2_HALARM) },
94 { "Laser bias current low alarm (Chan 2)",
95 SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_2_LALARM) },
96 { "Laser bias current high warning (Chan 2)",
97 SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_2_HWARN) },
98 { "Laser bias current low warning (Chan 2)",
99 SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_2_LWARN) },
100
101 { "Laser bias current high alarm (Chan 3)",
102 SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_3_HALARM) },
103 { "Laser bias current low alarm (Chan 3)",
104 SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_3_LALARM) },
105 { "Laser bias current high warning (Chan 3)",
106 SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_3_HWARN) },
107 { "Laser bias current low warning (Chan 3)",
108 SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_3_LWARN) },
109
110 { "Laser bias current high alarm (Chan 4)",
111 SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_4_HALARM) },
112 { "Laser bias current low alarm (Chan 4)",
113 SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_4_LALARM) },
114 { "Laser bias current high warning (Chan 4)",
115 SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_4_HWARN) },
116 { "Laser bias current low warning (Chan 4)",
117 SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_4_LWARN) },
118
119 { "Module temperature high alarm",
120 SFF8636_TEMP_AW_OFFSET, (SFF8636_TEMP_HALARM_STATUS) },
121 { "Module temperature low alarm",
122 SFF8636_TEMP_AW_OFFSET, (SFF8636_TEMP_LALARM_STATUS) },
123 { "Module temperature high warning",
124 SFF8636_TEMP_AW_OFFSET, (SFF8636_TEMP_HWARN_STATUS) },
125 { "Module temperature low warning",
126 SFF8636_TEMP_AW_OFFSET, (SFF8636_TEMP_LWARN_STATUS) },
127
128 { "Module voltage high alarm",
129 SFF8636_VCC_AW_OFFSET, (SFF8636_VCC_HALARM_STATUS) },
130 { "Module voltage low alarm",
131 SFF8636_VCC_AW_OFFSET, (SFF8636_VCC_LALARM_STATUS) },
132 { "Module voltage high warning",
133 SFF8636_VCC_AW_OFFSET, (SFF8636_VCC_HWARN_STATUS) },
134 { "Module voltage low warning",
135 SFF8636_VCC_AW_OFFSET, (SFF8636_VCC_LWARN_STATUS) },
136
137 { "Laser tx power high alarm (Channel 1)",
138 SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_1_HALARM) },
139 { "Laser tx power low alarm (Channel 1)",
140 SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_1_LALARM) },
141 { "Laser tx power high warning (Channel 1)",
142 SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_1_HWARN) },
143 { "Laser tx power low warning (Channel 1)",
144 SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_1_LWARN) },
145
146 { "Laser tx power high alarm (Channel 2)",
147 SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_2_HALARM) },
148 { "Laser tx power low alarm (Channel 2)",
149 SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_2_LALARM) },
150 { "Laser tx power high warning (Channel 2)",
151 SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_2_HWARN) },
152 { "Laser tx power low warning (Channel 2)",
153 SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_2_LWARN) },
154
155 { "Laser tx power high alarm (Channel 3)",
156 SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_3_HALARM) },
157 { "Laser tx power low alarm (Channel 3)",
158 SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_3_LALARM) },
159 { "Laser tx power high warning (Channel 3)",
160 SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_3_HWARN) },
161 { "Laser tx power low warning (Channel 3)",
162 SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_3_LWARN) },
163
164 { "Laser tx power high alarm (Channel 4)",
165 SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_4_HALARM) },
166 { "Laser tx power low alarm (Channel 4)",
167 SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_4_LALARM) },
168 { "Laser tx power high warning (Channel 4)",
169 SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_4_HWARN) },
170 { "Laser tx power low warning (Channel 4)",
171 SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_4_LWARN) },
172
173 { "Laser rx power high alarm (Channel 1)",
174 SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_1_HALARM) },
175 { "Laser rx power low alarm (Channel 1)",
176 SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_1_LALARM) },
177 { "Laser rx power high warning (Channel 1)",
178 SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_1_HWARN) },
179 { "Laser rx power low warning (Channel 1)",
180 SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_1_LWARN) },
181
182 { "Laser rx power high alarm (Channel 2)",
183 SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_2_HALARM) },
184 { "Laser rx power low alarm (Channel 2)",
185 SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_2_LALARM) },
186 { "Laser rx power high warning (Channel 2)",
187 SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_2_HWARN) },
188 { "Laser rx power low warning (Channel 2)",
189 SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_2_LWARN) },
190
191 { "Laser rx power high alarm (Channel 3)",
192 SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_3_HALARM) },
193 { "Laser rx power low alarm (Channel 3)",
194 SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_3_LALARM) },
195 { "Laser rx power high warning (Channel 3)",
196 SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_3_HWARN) },
197 { "Laser rx power low warning (Channel 3)",
198 SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_3_LWARN) },
199
200 { "Laser rx power high alarm (Channel 4)",
201 SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_4_HALARM) },
202 { "Laser rx power low alarm (Channel 4)",
203 SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_4_LALARM) },
204 { "Laser rx power high warning (Channel 4)",
205 SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_4_HWARN) },
206 { "Laser rx power low warning (Channel 4)",
207 SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_4_LWARN) },
208
209 { NULL, 0, 0 },
210 };
211
sff8636_show_identifier(const struct sff8636_memory_map * map)212 static void sff8636_show_identifier(const struct sff8636_memory_map *map)
213 {
214 sff8024_show_identifier(map->lower_memory, SFF8636_ID_OFFSET);
215 }
216
sff8636_show_ext_identifier(const struct sff8636_memory_map * map)217 static void sff8636_show_ext_identifier(const struct sff8636_memory_map *map)
218 {
219 printf("\t%-41s : 0x%02x\n", "Extended identifier",
220 map->page_00h[SFF8636_EXT_ID_OFFSET]);
221
222 static const char *pfx =
223 "\tExtended identifier description :";
224
225 switch (map->page_00h[SFF8636_EXT_ID_OFFSET] &
226 SFF8636_EXT_ID_PWR_CLASS_MASK) {
227 case SFF8636_EXT_ID_PWR_CLASS_1:
228 printf("%s 1.5W max. Power consumption\n", pfx);
229 break;
230 case SFF8636_EXT_ID_PWR_CLASS_2:
231 printf("%s 2.0W max. Power consumption\n", pfx);
232 break;
233 case SFF8636_EXT_ID_PWR_CLASS_3:
234 printf("%s 2.5W max. Power consumption\n", pfx);
235 break;
236 case SFF8636_EXT_ID_PWR_CLASS_4:
237 printf("%s 3.5W max. Power consumption\n", pfx);
238 break;
239 }
240
241 if (map->page_00h[SFF8636_EXT_ID_OFFSET] & SFF8636_EXT_ID_CDR_TX_MASK)
242 printf("%s CDR present in TX,", pfx);
243 else
244 printf("%s No CDR in TX,", pfx);
245
246 if (map->page_00h[SFF8636_EXT_ID_OFFSET] & SFF8636_EXT_ID_CDR_RX_MASK)
247 printf(" CDR present in RX\n");
248 else
249 printf(" No CDR in RX\n");
250
251 switch (map->page_00h[SFF8636_EXT_ID_OFFSET] &
252 SFF8636_EXT_ID_EPWR_CLASS_MASK) {
253 case SFF8636_EXT_ID_PWR_CLASS_LEGACY:
254 printf("%s", pfx);
255 break;
256 case SFF8636_EXT_ID_PWR_CLASS_5:
257 printf("%s 4.0W max. Power consumption,", pfx);
258 break;
259 case SFF8636_EXT_ID_PWR_CLASS_6:
260 printf("%s 4.5W max. Power consumption, ", pfx);
261 break;
262 case SFF8636_EXT_ID_PWR_CLASS_7:
263 printf("%s 5.0W max. Power consumption, ", pfx);
264 break;
265 }
266 if (map->lower_memory[SFF8636_PWR_MODE_OFFSET] &
267 SFF8636_HIGH_PWR_ENABLE)
268 printf(" High Power Class (> 3.5 W) enabled\n");
269 else
270 printf(" High Power Class (> 3.5 W) not enabled\n");
271 printf("\t%-41s : ", "Power set");
272 printf("%s\n", ONOFF(map->lower_memory[SFF8636_PWR_MODE_OFFSET] &
273 SFF8636_LOW_PWR_SET));
274 printf("\t%-41s : ", "Power override");
275 printf("%s\n", ONOFF(map->lower_memory[SFF8636_PWR_MODE_OFFSET] &
276 SFF8636_PWR_OVERRIDE));
277 }
278
sff8636_show_connector(const struct sff8636_memory_map * map)279 static void sff8636_show_connector(const struct sff8636_memory_map *map)
280 {
281 sff8024_show_connector(map->page_00h, SFF8636_CTOR_OFFSET);
282 }
283
sff8636_show_transceiver(const struct sff8636_memory_map * map)284 static void sff8636_show_transceiver(const struct sff8636_memory_map *map)
285 {
286 static const char *pfx =
287 "\tTransceiver type :";
288
289 printf("\t%-41s : 0x%02x 0x%02x 0x%02x " \
290 "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
291 "Transceiver codes",
292 map->page_00h[SFF8636_ETHERNET_COMP_OFFSET],
293 map->page_00h[SFF8636_SONET_COMP_OFFSET],
294 map->page_00h[SFF8636_SAS_COMP_OFFSET],
295 map->page_00h[SFF8636_GIGE_COMP_OFFSET],
296 map->page_00h[SFF8636_FC_LEN_OFFSET],
297 map->page_00h[SFF8636_FC_TECH_OFFSET],
298 map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET],
299 map->page_00h[SFF8636_FC_SPEED_OFFSET]);
300
301 /* 10G/40G Ethernet Compliance Codes */
302 if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
303 SFF8636_ETHERNET_10G_LRM)
304 printf("%s 10G Ethernet: 10G Base-LRM\n", pfx);
305 if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
306 SFF8636_ETHERNET_10G_LR)
307 printf("%s 10G Ethernet: 10G Base-LR\n", pfx);
308 if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
309 SFF8636_ETHERNET_10G_SR)
310 printf("%s 10G Ethernet: 10G Base-SR\n", pfx);
311 if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
312 SFF8636_ETHERNET_40G_CR4)
313 printf("%s 40G Ethernet: 40G Base-CR4\n", pfx);
314 if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
315 SFF8636_ETHERNET_40G_SR4)
316 printf("%s 40G Ethernet: 40G Base-SR4\n", pfx);
317 if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
318 SFF8636_ETHERNET_40G_LR4)
319 printf("%s 40G Ethernet: 40G Base-LR4\n", pfx);
320 if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
321 SFF8636_ETHERNET_40G_ACTIVE)
322 printf("%s 40G Ethernet: 40G Active Cable (XLPPI)\n", pfx);
323 /* Extended Specification Compliance Codes from SFF-8024 */
324 if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
325 SFF8636_ETHERNET_RSRVD) {
326 switch (map->page_00h[SFF8636_OPTION_1_OFFSET]) {
327 case SFF8636_ETHERNET_UNSPECIFIED:
328 printf("%s (reserved or unknown)\n", pfx);
329 break;
330 case SFF8636_ETHERNET_100G_AOC:
331 printf("%s 100G Ethernet: 100G AOC or 25GAUI C2M AOC with worst BER of 5x10^(-5)\n",
332 pfx);
333 break;
334 case SFF8636_ETHERNET_100G_SR4:
335 printf("%s 100G Ethernet: 100G Base-SR4 or 25GBase-SR\n",
336 pfx);
337 break;
338 case SFF8636_ETHERNET_100G_LR4:
339 printf("%s 100G Ethernet: 100G Base-LR4\n", pfx);
340 break;
341 case SFF8636_ETHERNET_100G_ER4:
342 printf("%s 100G Ethernet: 100G Base-ER4\n", pfx);
343 break;
344 case SFF8636_ETHERNET_100G_SR10:
345 printf("%s 100G Ethernet: 100G Base-SR10\n", pfx);
346 break;
347 case SFF8636_ETHERNET_100G_CWDM4_FEC:
348 printf("%s 100G Ethernet: 100G CWDM4 MSA with FEC\n", pfx);
349 break;
350 case SFF8636_ETHERNET_100G_PSM4:
351 printf("%s 100G Ethernet: 100G PSM4 Parallel SMF\n", pfx);
352 break;
353 case SFF8636_ETHERNET_100G_ACC:
354 printf("%s 100G Ethernet: 100G ACC or 25GAUI C2M ACC with worst BER of 5x10^(-5)\n",
355 pfx);
356 break;
357 case SFF8636_ETHERNET_100G_CWDM4_NO_FEC:
358 printf("%s 100G Ethernet: 100G CWDM4 MSA without FEC\n", pfx);
359 break;
360 case SFF8636_ETHERNET_100G_RSVD1:
361 printf("%s (reserved or unknown)\n", pfx);
362 break;
363 case SFF8636_ETHERNET_100G_CR4:
364 printf("%s 100G Ethernet: 100G Base-CR4 or 25G Base-CR CA-L\n",
365 pfx);
366 break;
367 case SFF8636_ETHERNET_25G_CR_CA_S:
368 printf("%s 25G Ethernet: 25G Base-CR CA-S\n", pfx);
369 break;
370 case SFF8636_ETHERNET_25G_CR_CA_N:
371 printf("%s 25G Ethernet: 25G Base-CR CA-N\n", pfx);
372 break;
373 case SFF8636_ETHERNET_40G_ER4:
374 printf("%s 40G Ethernet: 40G Base-ER4\n", pfx);
375 break;
376 case SFF8636_ETHERNET_4X10_SR:
377 printf("%s 4x10G Ethernet: 10G Base-SR\n", pfx);
378 break;
379 case SFF8636_ETHERNET_40G_PSM4:
380 printf("%s 40G Ethernet: 40G PSM4 Parallel SMF\n", pfx);
381 break;
382 case SFF8636_ETHERNET_G959_P1I1_2D1:
383 printf("%s Ethernet: G959.1 profile P1I1-2D1 (10709 MBd, 2km, 1310nm SM)\n",
384 pfx);
385 break;
386 case SFF8636_ETHERNET_G959_P1S1_2D2:
387 printf("%s Ethernet: G959.1 profile P1S1-2D2 (10709 MBd, 40km, 1550nm SM)\n",
388 pfx);
389 break;
390 case SFF8636_ETHERNET_G959_P1L1_2D2:
391 printf("%s Ethernet: G959.1 profile P1L1-2D2 (10709 MBd, 80km, 1550nm SM)\n",
392 pfx);
393 break;
394 case SFF8636_ETHERNET_10GT_SFI:
395 printf("%s 10G Ethernet: 10G Base-T with SFI electrical interface\n",
396 pfx);
397 break;
398 case SFF8636_ETHERNET_100G_CLR4:
399 printf("%s 100G Ethernet: 100G CLR4\n", pfx);
400 break;
401 case SFF8636_ETHERNET_100G_AOC2:
402 printf("%s 100G Ethernet: 100G AOC or 25GAUI C2M AOC with worst BER of 10^(-12)\n",
403 pfx);
404 break;
405 case SFF8636_ETHERNET_100G_ACC2:
406 printf("%s 100G Ethernet: 100G ACC or 25GAUI C2M ACC with worst BER of 10^(-12)\n",
407 pfx);
408 break;
409 case SFF8636_ETHERNET_100GE_DWDM2:
410 printf("%s 100GE-DWDM2 (DWDM transceiver using 2 wavelengths on a 1550 nm DWDM grid with a reach up to 80 km)\n",
411 pfx);
412 break;
413 case SFF8636_ETHERNET_100G_1550NM_WDM:
414 printf("%s 100G 1550nm WDM (4 wavelengths)\n", pfx);
415 break;
416 case SFF8636_ETHERNET_10G_BASET_SR:
417 printf("%s 10GBASE-T Short Reach (30 meters)\n", pfx);
418 break;
419 case SFF8636_ETHERNET_5G_BASET:
420 printf("%s 5GBASE-T\n", pfx);
421 break;
422 case SFF8636_ETHERNET_2HALFG_BASET:
423 printf("%s 2.5GBASE-T\n", pfx);
424 break;
425 case SFF8636_ETHERNET_40G_SWDM4:
426 printf("%s 40G SWDM4\n", pfx);
427 break;
428 case SFF8636_ETHERNET_100G_SWDM4:
429 printf("%s 100G SWDM4\n", pfx);
430 break;
431 case SFF8636_ETHERNET_100G_PAM4_BIDI:
432 printf("%s 100G PAM4 BiDi\n", pfx);
433 break;
434 case SFF8636_ETHERNET_4WDM10_MSA:
435 printf("%s 4WDM-10 MSA (10km version of 100G CWDM4 with same RS(528,514) FEC in host system)\n",
436 pfx);
437 break;
438 case SFF8636_ETHERNET_4WDM20_MSA:
439 printf("%s 4WDM-20 MSA (20km version of 100GBASE-LR4 with RS(528,514) FEC in host system)\n",
440 pfx);
441 break;
442 case SFF8636_ETHERNET_4WDM40_MSA:
443 printf("%s 4WDM-40 MSA (40km reach with APD receiver and RS(528,514) FEC in host system)\n",
444 pfx);
445 break;
446 case SFF8636_ETHERNET_100G_DR:
447 printf("%s 100GBASE-DR (clause 140), CAUI-4 (no FEC)\n", pfx);
448 break;
449 case SFF8636_ETHERNET_100G_FR_NOFEC:
450 printf("%s 100G-FR or 100GBASE-FR1 (clause 140), CAUI-4 (no FEC)\n", pfx);
451 break;
452 case SFF8636_ETHERNET_100G_LR_NOFEC:
453 printf("%s 100G-LR or 100GBASE-LR1 (clause 140), CAUI-4 (no FEC)\n", pfx);
454 break;
455 case SFF8636_ETHERNET_200G_ACC1:
456 printf("%s Active Copper Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 10-6 or below\n",
457 pfx);
458 break;
459 case SFF8636_ETHERNET_200G_AOC1:
460 printf("%s Active Optical Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 10-6 or below\n",
461 pfx);
462 break;
463 case SFF8636_ETHERNET_200G_ACC2:
464 printf("%s Active Copper Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 2.6x10-4 for ACC, 10-5 for AUI, or below\n",
465 pfx);
466 break;
467 case SFF8636_ETHERNET_200G_A0C2:
468 printf("%s Active Optical Cable with 50GAUI, 100GAUI-2 or 200GAUI-4 C2M. Providing a worst BER of 2.6x10-4 for ACC, 10-5 for AUI, or below\n",
469 pfx);
470 break;
471 case SFF8636_ETHERNET_200G_CR4:
472 printf("%s 50GBASE-CR, 100GBASE-CR2, or 200GBASE-CR4\n", pfx);
473 break;
474 case SFF8636_ETHERNET_200G_SR4:
475 printf("%s 50GBASE-SR, 100GBASE-SR2, or 200GBASE-SR4\n", pfx);
476 break;
477 case SFF8636_ETHERNET_200G_DR4:
478 printf("%s 50GBASE-FR or 200GBASE-DR4\n", pfx);
479 break;
480 case SFF8636_ETHERNET_200G_FR4:
481 printf("%s 200GBASE-FR4\n", pfx);
482 break;
483 case SFF8636_ETHERNET_200G_PSM4:
484 printf("%s 200G 1550 nm PSM4\n", pfx);
485 break;
486 case SFF8636_ETHERNET_50G_LR:
487 printf("%s 50GBASE-LR\n", pfx);
488 break;
489 case SFF8636_ETHERNET_200G_LR4:
490 printf("%s 200GBASE-LR4\n", pfx);
491 break;
492 case SFF8636_ETHERNET_64G_EA:
493 printf("%s 64GFC EA\n", pfx);
494 break;
495 case SFF8636_ETHERNET_64G_SW:
496 printf("%s 64GFC SW\n", pfx);
497 break;
498 case SFF8636_ETHERNET_64G_LW:
499 printf("%s 64GFC LW\n", pfx);
500 break;
501 case SFF8636_ETHERNET_128FC_EA:
502 printf("%s 128GFC EA\n", pfx);
503 break;
504 case SFF8636_ETHERNET_128FC_SW:
505 printf("%s 128GFC SW\n", pfx);
506 break;
507 case SFF8636_ETHERNET_128FC_LW:
508 printf("%s 128GFC LW\n", pfx);
509 break;
510 default:
511 printf("%s (reserved or unknown)\n", pfx);
512 break;
513 }
514 }
515
516 /* SONET Compliance Codes */
517 if (map->page_00h[SFF8636_SONET_COMP_OFFSET] &
518 (SFF8636_SONET_40G_OTN))
519 printf("%s 40G OTN (OTU3B/OTU3C)\n", pfx);
520 if (map->page_00h[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_OC48_LR))
521 printf("%s SONET: OC-48, long reach\n", pfx);
522 if (map->page_00h[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_OC48_IR))
523 printf("%s SONET: OC-48, intermediate reach\n", pfx);
524 if (map->page_00h[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_OC48_SR))
525 printf("%s SONET: OC-48, short reach\n", pfx);
526
527 /* SAS/SATA Compliance Codes */
528 if (map->page_00h[SFF8636_SAS_COMP_OFFSET] & (SFF8636_SAS_6G))
529 printf("%s SAS 6.0G\n", pfx);
530 if (map->page_00h[SFF8636_SAS_COMP_OFFSET] & (SFF8636_SAS_3G))
531 printf("%s SAS 3.0G\n", pfx);
532
533 /* Ethernet Compliance Codes */
534 if (map->page_00h[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_T)
535 printf("%s Ethernet: 1000BASE-T\n", pfx);
536 if (map->page_00h[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_CX)
537 printf("%s Ethernet: 1000BASE-CX\n", pfx);
538 if (map->page_00h[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_LX)
539 printf("%s Ethernet: 1000BASE-LX\n", pfx);
540 if (map->page_00h[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_SX)
541 printf("%s Ethernet: 1000BASE-SX\n", pfx);
542
543 /* Fibre Channel link length */
544 if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_VERY_LONG)
545 printf("%s FC: very long distance (V)\n", pfx);
546 if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_SHORT)
547 printf("%s FC: short distance (S)\n", pfx);
548 if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_INT)
549 printf("%s FC: intermediate distance (I)\n", pfx);
550 if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_LONG)
551 printf("%s FC: long distance (L)\n", pfx);
552 if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_MED)
553 printf("%s FC: medium distance (M)\n", pfx);
554
555 /* Fibre Channel transmitter technology */
556 if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_TECH_LONG_LC)
557 printf("%s FC: Longwave laser (LC)\n", pfx);
558 if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_TECH_ELEC_INTER)
559 printf("%s FC: Electrical inter-enclosure (EL)\n", pfx);
560 if (map->page_00h[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_ELEC_INTRA)
561 printf("%s FC: Electrical intra-enclosure (EL)\n", pfx);
562 if (map->page_00h[SFF8636_FC_TECH_OFFSET] &
563 SFF8636_FC_TECH_SHORT_WO_OFC)
564 printf("%s FC: Shortwave laser w/o OFC (SN)\n", pfx);
565 if (map->page_00h[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_SHORT_W_OFC)
566 printf("%s FC: Shortwave laser with OFC (SL)\n", pfx);
567 if (map->page_00h[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_LONG_LL)
568 printf("%s FC: Longwave laser (LL)\n", pfx);
569
570 /* Fibre Channel transmission media */
571 if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
572 SFF8636_FC_TRANS_MEDIA_TW)
573 printf("%s FC: Twin Axial Pair (TW)\n", pfx);
574 if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
575 SFF8636_FC_TRANS_MEDIA_TP)
576 printf("%s FC: Twisted Pair (TP)\n", pfx);
577 if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
578 SFF8636_FC_TRANS_MEDIA_MI)
579 printf("%s FC: Miniature Coax (MI)\n", pfx);
580 if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
581 SFF8636_FC_TRANS_MEDIA_TV)
582 printf("%s FC: Video Coax (TV)\n", pfx);
583 if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
584 SFF8636_FC_TRANS_MEDIA_M6)
585 printf("%s FC: Multimode, 62.5m (M6)\n", pfx);
586 if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
587 SFF8636_FC_TRANS_MEDIA_M5)
588 printf("%s FC: Multimode, 50m (M5)\n", pfx);
589 if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
590 SFF8636_FC_TRANS_MEDIA_OM3)
591 printf("%s FC: Multimode, 50um (OM3)\n", pfx);
592 if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
593 SFF8636_FC_TRANS_MEDIA_SM)
594 printf("%s FC: Single Mode (SM)\n", pfx);
595
596 /* Fibre Channel speed */
597 if (map->page_00h[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_1200_MBPS)
598 printf("%s FC: 1200 MBytes/sec\n", pfx);
599 if (map->page_00h[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_800_MBPS)
600 printf("%s FC: 800 MBytes/sec\n", pfx);
601 if (map->page_00h[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_1600_MBPS)
602 printf("%s FC: 1600 MBytes/sec\n", pfx);
603 if (map->page_00h[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_400_MBPS)
604 printf("%s FC: 400 MBytes/sec\n", pfx);
605 if (map->page_00h[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_200_MBPS)
606 printf("%s FC: 200 MBytes/sec\n", pfx);
607 if (map->page_00h[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_100_MBPS)
608 printf("%s FC: 100 MBytes/sec\n", pfx);
609 }
610
sff8636_show_encoding(const struct sff8636_memory_map * map)611 static void sff8636_show_encoding(const struct sff8636_memory_map *map)
612 {
613 sff8024_show_encoding(map->page_00h, SFF8636_ENCODING_OFFSET,
614 ETH_MODULE_SFF_8636);
615 }
616
sff8636_show_rate_identifier(const struct sff8636_memory_map * map)617 static void sff8636_show_rate_identifier(const struct sff8636_memory_map *map)
618 {
619 /* TODO: Need to fix rate select logic */
620 printf("\t%-41s : 0x%02x\n", "Rate identifier",
621 map->page_00h[SFF8636_EXT_RS_OFFSET]);
622 }
623
624 static void
sff8636_show_wavelength_or_copper_compliance(const struct sff8636_memory_map * map)625 sff8636_show_wavelength_or_copper_compliance(const struct sff8636_memory_map *map)
626 {
627 printf("\t%-41s : 0x%02x", "Transmitter technology",
628 map->page_00h[SFF8636_DEVICE_TECH_OFFSET] &
629 SFF8636_TRANS_TECH_MASK);
630
631 switch (map->page_00h[SFF8636_DEVICE_TECH_OFFSET] &
632 SFF8636_TRANS_TECH_MASK) {
633 case SFF8636_TRANS_850_VCSEL:
634 printf(" (850 nm VCSEL)\n");
635 break;
636 case SFF8636_TRANS_1310_VCSEL:
637 printf(" (1310 nm VCSEL)\n");
638 break;
639 case SFF8636_TRANS_1550_VCSEL:
640 printf(" (1550 nm VCSEL)\n");
641 break;
642 case SFF8636_TRANS_1310_FP:
643 printf(" (1310 nm FP)\n");
644 break;
645 case SFF8636_TRANS_1310_DFB:
646 printf(" (1310 nm DFB)\n");
647 break;
648 case SFF8636_TRANS_1550_DFB:
649 printf(" (1550 nm DFB)\n");
650 break;
651 case SFF8636_TRANS_1310_EML:
652 printf(" (1310 nm EML)\n");
653 break;
654 case SFF8636_TRANS_1550_EML:
655 printf(" (1550 nm EML)\n");
656 break;
657 case SFF8636_TRANS_OTHERS:
658 printf(" (Others/Undefined)\n");
659 break;
660 case SFF8636_TRANS_1490_DFB:
661 printf(" (1490 nm DFB)\n");
662 break;
663 case SFF8636_TRANS_COPPER_PAS_UNEQUAL:
664 printf(" (Copper cable unequalized)\n");
665 break;
666 case SFF8636_TRANS_COPPER_PAS_EQUAL:
667 printf(" (Copper cable passive equalized)\n");
668 break;
669 case SFF8636_TRANS_COPPER_LNR_FAR_EQUAL:
670 printf(" (Copper cable, near and far end limiting active equalizers)\n");
671 break;
672 case SFF8636_TRANS_COPPER_FAR_EQUAL:
673 printf(" (Copper cable, far end limiting active equalizers)\n");
674 break;
675 case SFF8636_TRANS_COPPER_NEAR_EQUAL:
676 printf(" (Copper cable, near end limiting active equalizers)\n");
677 break;
678 case SFF8636_TRANS_COPPER_LNR_EQUAL:
679 printf(" (Copper cable, linear active equalizers)\n");
680 break;
681 }
682
683 if ((map->page_00h[SFF8636_DEVICE_TECH_OFFSET] &
684 SFF8636_TRANS_TECH_MASK) >= SFF8636_TRANS_COPPER_PAS_UNEQUAL) {
685 printf("\t%-41s : %udb\n", "Attenuation at 2.5GHz",
686 map->page_00h[SFF8636_WAVELEN_HIGH_BYTE_OFFSET]);
687 printf("\t%-41s : %udb\n", "Attenuation at 5.0GHz",
688 map->page_00h[SFF8636_WAVELEN_LOW_BYTE_OFFSET]);
689 printf("\t%-41s : %udb\n", "Attenuation at 7.0GHz",
690 map->page_00h[SFF8636_WAVE_TOL_HIGH_BYTE_OFFSET]);
691 printf("\t%-41s : %udb\n", "Attenuation at 12.9GHz",
692 map->page_00h[SFF8636_WAVE_TOL_LOW_BYTE_OFFSET]);
693 } else {
694 printf("\t%-41s : %.3lfnm\n", "Laser wavelength",
695 (((map->page_00h[SFF8636_WAVELEN_HIGH_BYTE_OFFSET] << 8) |
696 map->page_00h[SFF8636_WAVELEN_LOW_BYTE_OFFSET]) * 0.05));
697 printf("\t%-41s : %.3lfnm\n", "Laser wavelength tolerance",
698 (((map->page_00h[SFF8636_WAVE_TOL_HIGH_BYTE_OFFSET] << 8) |
699 map->page_00h[SFF8636_WAVE_TOL_LOW_BYTE_OFFSET]) * 0.005));
700 }
701 }
702
703 /*
704 * 2-byte internal temperature conversions:
705 * First byte is a signed 8-bit integer, which is the temp decimal part
706 * Second byte are 1/256th of degree, which are added to the dec part.
707 */
708 #define SFF8636_OFFSET_TO_TEMP(offset) ((__s16)OFFSET_TO_U16(offset))
709
sff8636_dom_parse(const struct sff8636_memory_map * map,struct sff_diags * sd)710 static void sff8636_dom_parse(const struct sff8636_memory_map *map,
711 struct sff_diags *sd)
712 {
713 const __u8 *id = map->lower_memory;
714 int i = 0;
715
716 /* Monitoring Thresholds for Alarms and Warnings */
717 sd->sfp_voltage[MCURR] = OFFSET_TO_U16_PTR(id, SFF8636_VCC_CURR);
718 sd->sfp_temp[MCURR] = SFF8636_OFFSET_TO_TEMP(SFF8636_TEMP_CURR);
719
720 if (!map->page_03h)
721 goto out;
722
723 sd->sfp_voltage[HALRM] = OFFSET_TO_U16_PTR(map->page_03h,
724 SFF8636_VCC_HALRM);
725 sd->sfp_voltage[LALRM] = OFFSET_TO_U16_PTR(map->page_03h,
726 SFF8636_VCC_LALRM);
727 sd->sfp_voltage[HWARN] = OFFSET_TO_U16_PTR(map->page_03h,
728 SFF8636_VCC_HWARN);
729 sd->sfp_voltage[LWARN] = OFFSET_TO_U16_PTR(map->page_03h,
730 SFF8636_VCC_LWARN);
731
732 sd->sfp_temp[HALRM] = (__s16)OFFSET_TO_U16_PTR(map->page_03h,
733 SFF8636_TEMP_HALRM);
734 sd->sfp_temp[LALRM] = (__s16)OFFSET_TO_U16_PTR(map->page_03h,
735 SFF8636_TEMP_LALRM);
736 sd->sfp_temp[HWARN] = (__s16)OFFSET_TO_U16_PTR(map->page_03h,
737 SFF8636_TEMP_HWARN);
738 sd->sfp_temp[LWARN] = (__s16)OFFSET_TO_U16_PTR(map->page_03h,
739 SFF8636_TEMP_LWARN);
740
741 sd->bias_cur[HALRM] = OFFSET_TO_U16_PTR(map->page_03h,
742 SFF8636_TX_BIAS_HALRM);
743 sd->bias_cur[LALRM] = OFFSET_TO_U16_PTR(map->page_03h,
744 SFF8636_TX_BIAS_LALRM);
745 sd->bias_cur[HWARN] = OFFSET_TO_U16_PTR(map->page_03h,
746 SFF8636_TX_BIAS_HWARN);
747 sd->bias_cur[LWARN] = OFFSET_TO_U16_PTR(map->page_03h,
748 SFF8636_TX_BIAS_LWARN);
749
750 sd->tx_power[HALRM] = OFFSET_TO_U16_PTR(map->page_03h,
751 SFF8636_TX_PWR_HALRM);
752 sd->tx_power[LALRM] = OFFSET_TO_U16_PTR(map->page_03h,
753 SFF8636_TX_PWR_LALRM);
754 sd->tx_power[HWARN] = OFFSET_TO_U16_PTR(map->page_03h,
755 SFF8636_TX_PWR_HWARN);
756 sd->tx_power[LWARN] = OFFSET_TO_U16_PTR(map->page_03h,
757 SFF8636_TX_PWR_LWARN);
758
759 sd->rx_power[HALRM] = OFFSET_TO_U16_PTR(map->page_03h,
760 SFF8636_RX_PWR_HALRM);
761 sd->rx_power[LALRM] = OFFSET_TO_U16_PTR(map->page_03h,
762 SFF8636_RX_PWR_LALRM);
763 sd->rx_power[HWARN] = OFFSET_TO_U16_PTR(map->page_03h,
764 SFF8636_RX_PWR_HWARN);
765 sd->rx_power[LWARN] = OFFSET_TO_U16_PTR(map->page_03h,
766 SFF8636_RX_PWR_LWARN);
767
768 out:
769 /* Channel Specific Data */
770 for (i = 0; i < SFF8636_MAX_CHANNEL_NUM; i++) {
771 u8 rx_power_offset, tx_bias_offset;
772 u8 tx_power_offset;
773
774 switch (i) {
775 case 0:
776 rx_power_offset = SFF8636_RX_PWR_1_OFFSET;
777 tx_power_offset = SFF8636_TX_PWR_1_OFFSET;
778 tx_bias_offset = SFF8636_TX_BIAS_1_OFFSET;
779 break;
780 case 1:
781 rx_power_offset = SFF8636_RX_PWR_2_OFFSET;
782 tx_power_offset = SFF8636_TX_PWR_2_OFFSET;
783 tx_bias_offset = SFF8636_TX_BIAS_2_OFFSET;
784 break;
785 case 2:
786 rx_power_offset = SFF8636_RX_PWR_3_OFFSET;
787 tx_power_offset = SFF8636_TX_PWR_3_OFFSET;
788 tx_bias_offset = SFF8636_TX_BIAS_3_OFFSET;
789 break;
790 case 3:
791 rx_power_offset = SFF8636_RX_PWR_4_OFFSET;
792 tx_power_offset = SFF8636_TX_PWR_4_OFFSET;
793 tx_bias_offset = SFF8636_TX_BIAS_4_OFFSET;
794 break;
795 }
796 sd->scd[i].bias_cur = OFFSET_TO_U16(tx_bias_offset);
797 sd->scd[i].rx_power = OFFSET_TO_U16(rx_power_offset);
798 sd->scd[i].tx_power = OFFSET_TO_U16(tx_power_offset);
799 }
800 }
801
sff8636_show_dom(const struct sff8636_memory_map * map)802 static void sff8636_show_dom(const struct sff8636_memory_map *map)
803 {
804 struct sff_diags sd = {0};
805 char *rx_power_string = NULL;
806 char power_string[MAX_DESC_SIZE];
807 int i;
808
809 /*
810 * There is no clear identifier to signify the existence of
811 * optical diagnostics similar to SFF-8472. So checking existence
812 * of page 3, will provide the gurantee for existence of alarms
813 * and thresholds
814 * If pagging support exists, then supports_alarms is marked as 1
815 */
816 if (map->page_03h)
817 sd.supports_alarms = 1;
818
819 sd.rx_power_type = map->page_00h[SFF8636_DIAG_TYPE_OFFSET] &
820 SFF8636_RX_PWR_TYPE_MASK;
821 sd.tx_power_type = map->page_00h[SFF8636_DIAG_TYPE_OFFSET] &
822 SFF8636_RX_PWR_TYPE_MASK;
823
824 sff8636_dom_parse(map, &sd);
825
826 PRINT_TEMP("Module temperature", sd.sfp_temp[MCURR]);
827 PRINT_VCC("Module voltage", sd.sfp_voltage[MCURR]);
828
829 /*
830 * SFF-8636/8436 spec is not clear whether RX power/ TX bias
831 * current fields are supported or not. A valid temperature
832 * reading is used as existence for TX/RX power.
833 */
834 if ((sd.sfp_temp[MCURR] == 0x0) ||
835 (sd.sfp_temp[MCURR] == (__s16)0xFFFF))
836 return;
837
838 printf("\t%-41s : %s\n", "Alarm/warning flags implemented",
839 (sd.supports_alarms ? "Yes" : "No"));
840
841 for (i = 0; i < SFF8636_MAX_CHANNEL_NUM; i++) {
842 snprintf(power_string, MAX_DESC_SIZE, "%s (Channel %d)",
843 "Laser tx bias current", i+1);
844 PRINT_BIAS(power_string, sd.scd[i].bias_cur);
845 }
846
847 for (i = 0; i < SFF8636_MAX_CHANNEL_NUM; i++) {
848 snprintf(power_string, MAX_DESC_SIZE, "%s (Channel %d)",
849 "Transmit avg optical power", i+1);
850 PRINT_xX_PWR(power_string, sd.scd[i].tx_power);
851 }
852
853 if (!sd.rx_power_type)
854 rx_power_string = "Receiver signal OMA";
855 else
856 rx_power_string = "Rcvr signal avg optical power";
857
858 for (i = 0; i < SFF8636_MAX_CHANNEL_NUM; i++) {
859 snprintf(power_string, MAX_DESC_SIZE, "%s(Channel %d)",
860 rx_power_string, i+1);
861 PRINT_xX_PWR(power_string, sd.scd[i].rx_power);
862 }
863
864 if (sd.supports_alarms) {
865 for (i = 0; sff8636_aw_flags[i].str; ++i) {
866 printf("\t%-41s : %s\n", sff8636_aw_flags[i].str,
867 map->lower_memory[sff8636_aw_flags[i].offset]
868 & sff8636_aw_flags[i].value ? "On" : "Off");
869 }
870
871 sff_show_thresholds(sd);
872 }
873 }
874
sff8636_show_signals(const struct sff8636_memory_map * map)875 static void sff8636_show_signals(const struct sff8636_memory_map *map)
876 {
877 unsigned int v;
878
879 /* There appears to be no Rx LOS support bit, use Tx for both */
880 if (map->page_00h[SFF8636_OPTION_4_OFFSET] & SFF8636_O4_TX_LOS) {
881 v = map->lower_memory[SFF8636_LOS_AW_OFFSET] & 0xf;
882 sff_show_lane_status("Rx loss of signal", 4, "Yes", "No", v);
883 v = map->lower_memory[SFF8636_LOS_AW_OFFSET] >> 4;
884 sff_show_lane_status("Tx loss of signal", 4, "Yes", "No", v);
885 }
886
887 v = map->lower_memory[SFF8636_LOL_AW_OFFSET] & 0xf;
888 if (map->page_00h[SFF8636_OPTION_3_OFFSET] & SFF8636_O3_RX_LOL)
889 sff_show_lane_status("Rx loss of lock", 4, "Yes", "No", v);
890
891 v = map->lower_memory[SFF8636_LOL_AW_OFFSET] >> 4;
892 if (map->page_00h[SFF8636_OPTION_3_OFFSET] & SFF8636_O3_TX_LOL)
893 sff_show_lane_status("Tx loss of lock", 4, "Yes", "No", v);
894
895 v = map->lower_memory[SFF8636_FAULT_AW_OFFSET] & 0xf;
896 if (map->page_00h[SFF8636_OPTION_4_OFFSET] & SFF8636_O4_TX_FAULT)
897 sff_show_lane_status("Tx fault", 4, "Yes", "No", v);
898
899 v = map->lower_memory[SFF8636_FAULT_AW_OFFSET] >> 4;
900 if (map->page_00h[SFF8636_OPTION_2_OFFSET] & SFF8636_O2_TX_EQ_AUTO)
901 sff_show_lane_status("Tx adaptive eq fault", 4, "Yes", "No", v);
902 }
903
sff8636_show_page_zero(const struct sff8636_memory_map * map)904 static void sff8636_show_page_zero(const struct sff8636_memory_map *map)
905 {
906 sff8636_show_ext_identifier(map);
907 sff8636_show_connector(map);
908 sff8636_show_transceiver(map);
909 sff8636_show_encoding(map);
910 sff_show_value_with_unit(map->page_00h, SFF8636_BR_NOMINAL_OFFSET,
911 "BR, Nominal", 100, "Mbps");
912 sff8636_show_rate_identifier(map);
913 sff_show_value_with_unit(map->page_00h, SFF8636_SM_LEN_OFFSET,
914 "Length (SMF,km)", 1, "km");
915 sff_show_value_with_unit(map->page_00h, SFF8636_OM3_LEN_OFFSET,
916 "Length (OM3 50um)", 2, "m");
917 sff_show_value_with_unit(map->page_00h, SFF8636_OM2_LEN_OFFSET,
918 "Length (OM2 50um)", 1, "m");
919 sff_show_value_with_unit(map->page_00h, SFF8636_OM1_LEN_OFFSET,
920 "Length (OM1 62.5um)", 1, "m");
921 sff_show_value_with_unit(map->page_00h, SFF8636_CBL_LEN_OFFSET,
922 "Length (Copper or Active cable)", 1, "m");
923 sff8636_show_wavelength_or_copper_compliance(map);
924 sff_show_ascii(map->page_00h, SFF8636_VENDOR_NAME_START_OFFSET,
925 SFF8636_VENDOR_NAME_END_OFFSET, "Vendor name");
926 sff8024_show_oui(map->page_00h, SFF8636_VENDOR_OUI_OFFSET);
927 sff_show_ascii(map->page_00h, SFF8636_VENDOR_PN_START_OFFSET,
928 SFF8636_VENDOR_PN_END_OFFSET, "Vendor PN");
929 sff_show_ascii(map->page_00h, SFF8636_VENDOR_REV_START_OFFSET,
930 SFF8636_VENDOR_REV_END_OFFSET, "Vendor rev");
931 sff_show_ascii(map->page_00h, SFF8636_VENDOR_SN_START_OFFSET,
932 SFF8636_VENDOR_SN_END_OFFSET, "Vendor SN");
933 sff_show_ascii(map->page_00h, SFF8636_DATE_YEAR_OFFSET,
934 SFF8636_DATE_VENDOR_LOT_OFFSET + 1, "Date code");
935 sff_show_revision_compliance(map->lower_memory,
936 SFF8636_REV_COMPLIANCE_OFFSET);
937 sff8636_show_signals(map);
938 }
939
sff8636_show_all_common(const struct sff8636_memory_map * map)940 static void sff8636_show_all_common(const struct sff8636_memory_map *map)
941 {
942 sff8636_show_identifier(map);
943 switch (map->lower_memory[SFF8636_ID_OFFSET]) {
944 case SFF8024_ID_QSFP:
945 case SFF8024_ID_QSFP_PLUS:
946 case SFF8024_ID_QSFP28:
947 sff8636_show_page_zero(map);
948 sff8636_show_dom(map);
949 break;
950 }
951 }
952
sff8636_memory_map_init_buf(struct sff8636_memory_map * map,const __u8 * id,__u32 eeprom_len)953 static void sff8636_memory_map_init_buf(struct sff8636_memory_map *map,
954 const __u8 *id, __u32 eeprom_len)
955 {
956 /* Lower Memory and Page 00h are always present.
957 *
958 * Offset into Upper Memory is between page size and twice the page
959 * size. Therefore, set the base address of each page to base address
960 * plus page size multiplied by the page number.
961 */
962 map->lower_memory = id;
963 map->page_00h = id;
964
965 /* Page 03h is only present when the module memory model is paged and
966 * not flat and when we got a big enough buffer from the kernel.
967 */
968 if (map->lower_memory[SFF8636_STATUS_2_OFFSET] &
969 SFF8636_STATUS_PAGE_3_PRESENT ||
970 eeprom_len != ETH_MODULE_SFF_8636_MAX_LEN)
971 return;
972
973 map->page_03h = id + 3 * SFF8636_PAGE_SIZE;
974 }
975
sff8636_show_all_ioctl(const __u8 * id,__u32 eeprom_len)976 void sff8636_show_all_ioctl(const __u8 *id, __u32 eeprom_len)
977 {
978 struct sff8636_memory_map map = {};
979
980 if (id[SFF8636_ID_OFFSET] == SFF8024_ID_QSFP_DD ||
981 id[SFF8636_ID_OFFSET] == SFF8024_ID_OSFP ||
982 id[SFF8636_ID_OFFSET] == SFF8024_ID_DSFP) {
983 cmis_show_all_ioctl(id);
984 return;
985 }
986
987 sff8636_memory_map_init_buf(&map, id, eeprom_len);
988 sff8636_show_all_common(&map);
989 }
990
sff8636_request_init(struct ethtool_module_eeprom * request,u8 page,u32 offset)991 static void sff8636_request_init(struct ethtool_module_eeprom *request, u8 page,
992 u32 offset)
993 {
994 request->offset = offset;
995 request->length = SFF8636_PAGE_SIZE;
996 request->page = page;
997 request->bank = 0;
998 request->i2c_address = SFF8636_I2C_ADDRESS;
999 request->data = NULL;
1000 }
1001
1002 static int
sff8636_memory_map_init_pages(struct cmd_context * ctx,struct sff8636_memory_map * map)1003 sff8636_memory_map_init_pages(struct cmd_context *ctx,
1004 struct sff8636_memory_map *map)
1005 {
1006 struct ethtool_module_eeprom request;
1007 int ret;
1008
1009 /* Lower Memory and Page 00h are always present.
1010 *
1011 * Offset into Upper Memory is between page size and twice the page
1012 * size. Therefore, set the base address of each page to its base
1013 * address minus page size.
1014 */
1015 sff8636_request_init(&request, 0x0, 0);
1016 ret = nl_get_eeprom_page(ctx, &request);
1017 if (ret < 0)
1018 return ret;
1019 map->lower_memory = request.data;
1020
1021 sff8636_request_init(&request, 0x0, SFF8636_PAGE_SIZE);
1022 ret = nl_get_eeprom_page(ctx, &request);
1023 if (ret < 0)
1024 return ret;
1025 map->page_00h = request.data - SFF8636_PAGE_SIZE;
1026
1027 /* Page 03h is only present when the module memory model is paged and
1028 * not flat.
1029 */
1030 if (map->lower_memory[SFF8636_STATUS_2_OFFSET] &
1031 SFF8636_STATUS_PAGE_3_PRESENT)
1032 return 0;
1033
1034 sff8636_request_init(&request, 0x3, SFF8636_PAGE_SIZE);
1035 ret = nl_get_eeprom_page(ctx, &request);
1036 if (ret < 0)
1037 return ret;
1038 map->page_03h = request.data - SFF8636_PAGE_SIZE;
1039
1040 return 0;
1041 }
1042
sff8636_show_all_nl(struct cmd_context * ctx)1043 int sff8636_show_all_nl(struct cmd_context *ctx)
1044 {
1045 struct sff8636_memory_map map = {};
1046 int ret;
1047
1048 ret = sff8636_memory_map_init_pages(ctx, &map);
1049 if (ret < 0)
1050 return ret;
1051 sff8636_show_all_common(&map);
1052
1053 return 0;
1054 }
1055