1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright (c) 2017, Joyent, Inc.
14 */
15
16 /*
17 * Parse raw SFF data into an nvlist that can be processed by users, providing
18 * them with what can be printable strings. At the moment, we handle the
19 * majority of parsing page 0xa0 based on SFF 8472 (thus covering INF-8074 and
20 * friends) and SFF 8636 (thus covering SFF-8436 and friends). Interfaces that
21 * parse data into logical structures may be useful to add when considering
22 * monitoring data in page 0xa2.
23 *
24 * When parsing, we try to make sure that the user has supplied, or at least
25 * thinks they have supplied, a buffer of sufficient length. The general design
26 * is that we require the buffer to be large enough to cover all of the offsets
27 * that we care about. If the buffer isn't this large, then we leave it be.
28 *
29 * This library is private and subject to change at any time.
30 */
31
32 #include <assert.h>
33 #include <strings.h>
34 #include <libsff.h>
35 #include <errno.h>
36 #include <ctype.h>
37
38 #include "sff.h"
39
40 #define MIN(a, b) ((a) < (b) ? (a) : (b))
41
42 /*
43 * Maximum size of a string buffer while parsing.
44 */
45 #define SFP_STRBUF 128
46
47 /*
48 * Minimum length of the buffer we require to parse the SFP data.
49 */
50 #define SFP_MIN_LEN_8472 96
51 #define SFP_MIN_LEN_8636 224
52
53 /*
54 * This table is derived from SFF 8024 Section 4.1, Table 4-1.
55 */
56 static const char *sff_8024_id_strs[SFF_8024_NIDS] = {
57 "Unknown or Unspecified",
58 "GBIC",
59 "Module/connector soldered to motherboard",
60 "SFP/SFP+/SFP28",
61 "300 pin XBI",
62 "XENPAK",
63 "XFP",
64 "XFF",
65 "XFP-E",
66 "XPAK",
67 "X2",
68 "DWDM-SFP/SFP+ (not using SFF-8472)",
69 "QSFP",
70 "QSFP+ or later",
71 "CXP or later",
72 "Shielded Mini Multilane HD 4X",
73 "Shielded Mini Multilane HD 8X",
74 "QSFP28 or later",
75 "CXP2 (aka CXP28) or later",
76 "CDFP (Style 1/Style2)",
77 "Shielded Mini Multilane HD 4X Fanout Cable",
78 "Shielded Mini Multilane HD 8X Fanout Cable",
79 "CDFP (Style 3)",
80 "microQSFP"
81 };
82
83 /*
84 * The set of values used for the encoding depends on whether we're a basic SFP
85 * device or not. The values are inconsistent between SFP and QSFP based
86 * devices.
87 *
88 * This table is derived from SFF 8024 r3.9 Table 4-2.
89 */
90 #define SFF_8024_NENCS 9
91 static const char *sff_8024_enc_sfp[] = {
92 "Unspecified",
93 "8B/10B",
94 "4B/5B",
95 "NRZ",
96 "Manchester",
97 "SONET Scrambled",
98 "64B/66B",
99 "256B/257B",
100 "PAM4"
101 };
102
103 static const char *sff_8024_enc_qsfp[] = {
104 "Unspecified",
105 "8B/10B",
106 "4B/5B",
107 "NRZ",
108 "SONET Scrambled",
109 "64B/66B",
110 "Manchester",
111 "256B/257B",
112 "PAM4"
113 };
114
115 /*
116 * This table is derived from SFF 8024 r3.9 Section 4.4.
117 */
118 #define SFF_8024_EXT_SPEC_NENTRIES 27
119 static const char *sff_8024_ext_spec[] = {
120 "Unspecified",
121 "100G AOC or 25GAUI C2M AOC",
122 "100GBASE-SR4 or 25GBASE-SR",
123 "100GBASE-LR4 or 25GBASE-LR",
124 "100GBASE-ER4 or 25GBASE-ER",
125 "100GBASE-SR10",
126 "100G CWDM4",
127 "100G PSM4 Parallel SMF",
128 "100G ACC or 25GAUI C2M ACC",
129 "Obsolete",
130 "Reserved",
131 "100GBASE-CR4 or 25GBASE-CR CA-L",
132 "25GBASE-CR CA-S",
133 "25GBASE-CR CA-N",
134 "Reserved",
135 "Reserved",
136 "40GBASE-ER4",
137 "4 x 10GBASE-SR",
138 "40G PSM4 Parallel SMF",
139 "G959.1 profile P1I1-2D1",
140 "G959.1 profile P1S1-2D2",
141 "G959.1 profile P1L1-2D2",
142 "10GBASE-T with SFI electrical interface",
143 "100G CLR4",
144 "100G AOC or 25GAUI C2M AOC",
145 "100G ACC or 25GAUI C2M ACC",
146 "100GE-DWDM2"
147 };
148
149 typedef struct sff_pair {
150 uint_t sp_val;
151 const char *sp_name;
152 } sff_pair_t;
153
154 /*
155 * This table is derived from SFF 8024 r3.9 Section 4.3.
156 */
157 static sff_pair_t sff_8024_connectors[] = {
158 { 0x00, "Unknown" },
159 { 0x01, "SC (Subscriber Connector)" },
160 { 0x02, "Fibre Channel Style 1 copper connector" },
161 { 0x03, "Fibre Channel Style 2 copper connector" },
162 { 0x04, "BNC/TNC (Bayonet/Threaded Neill-Concelman)" },
163 { 0x05, "Fibre Channel coax headers" },
164 { 0x06, "Fiber Jack" },
165 { 0x07, "LC (Lucent Connector)" },
166 { 0x08, "MT-RJ (Mechanical Transfer - Registered Jack)" },
167 { 0x09, "MU (Multiple Optical)" },
168 { 0x0A, "SG" },
169 { 0x0B, "Optical Pigtail" },
170 { 0x0C, "MPO 1x12 (Multifiber Parallel Optic)" },
171 { 0x0D, "MPO 2x16" },
172 { 0x20, "HSSDC II (High Speed Serial Data Connector)" },
173 { 0x21, "Copper pigtail" },
174 { 0x22, "RJ45 (Registered Jack)" },
175 { 0x23, "No separable connector" },
176 { 0x24, "MXC 2x16" },
177 { 0x0, NULL }
178 };
179
180 /*
181 * This is derived from SFF 8472 r12.2 Table 5-3.
182 */
183 #define SFF_8472_COMP_10GETH_MASK 0xf0
184 static sff_pair_t sff_8472_comp_10geth[] = {
185 { 0x80, "10G Base-ER" },
186 { 0x40, "10G Base-LRM" },
187 { 0x20, "10G Base-LR" },
188 { 0x10, "10G Base-SR" },
189 { 0x0, NULL }
190 };
191
192 /*
193 * This is derived from SFF 8472 r12.2 Table 5-3.
194 */
195 #define SFF_8472_COMP_IB_MASK 0x0f
196 static sff_pair_t sff_8472_comp_ib[] = {
197 { 0x08, "1X SX" },
198 { 0x04, "1X LX" },
199 { 0x02, "1X Copper Active" },
200 { 0x01, "1X Copper Passive" },
201 { 0x0, NULL }
202 };
203
204 /*
205 * This is derived from SFF 8472 r12.2 Table 5-3.
206 */
207 #define SFF_8472_COMP_ESCON_MASK 0xc0
208 static sff_pair_t sff_8472_comp_escon[] = {
209 { 0x80, "ESCON MMF, 1310nm LED" },
210 { 0x40, "ESCON SMF, 1310nm Laser" },
211 { 0x0, NULL }
212 };
213
214 /*
215 * This is derived from SFF 8472 r12.2 Table 5-3. These values come from both
216 * bytes 4 and 5. We treat this as a uint16_t with the low byte as byte 4 and
217 * the high byte as byte 5.
218 */
219 #define SFF_8472_COMP_SOCON_MASK 0x773f
220 static sff_pair_t sff_8472_comp_sonet[] = {
221 { 0x20, "OC-192, short reach" },
222 { 0x10, "SONET reach specifier bit 1" },
223 { 0x08, "ONET reach specifier bit 2" },
224 { 0x04, "OC-48, long reach" },
225 { 0x02, "OC-48, intermediate reach" },
226 { 0x01, "OC-48, short reach" },
227 /* 0x8000 is unallocated */
228 { 0x4000, "OC-12, single mode, long reach" },
229 { 0x2000, "OC-12, single mode, inter. reach" },
230 { 0x1000, "OC-12, short reach" },
231 /* 0x800 is unallocted */
232 { 0x0400, "OC-3, single mode, long reach" },
233 { 0x0200, "OC-3, single mode, inter. reach" },
234 { 0x0100, "OC-3, short reach" },
235 { 0x0, NULL }
236 };
237
238 /*
239 * This is derived from SFF 8472 r12.2 Table 5-3.
240 */
241 #define SFF_8472_COMP_ETH_MASK 0xff
242 static sff_pair_t sff_8472_comp_eth[] = {
243 { 0x80, "BASE-PX" },
244 { 0x40, "BASE-BX10" },
245 { 0x20, "100BASE-FX" },
246 { 0x10, "100BASE-LX/LX10" },
247 { 0x08, "1000BASE-T" },
248 { 0x04, "1000BASE-CX" },
249 { 0x02, "1000BASE-LX" },
250 { 0x01, "1000BASE-SX" },
251 { 0x0, NULL }
252 };
253
254 /*
255 * This is derived from SFF 8472 r12.2 Table 5-3.
256 */
257 #define SFF_8472_COMP_FCLEN_MASK 0xf8
258 static sff_pair_t sff_8472_comp_fclen[] = {
259 { 0x80, "very long distance (V)" },
260 { 0x40, "short distance (S)" },
261 { 0x20, "intermeddiate distance (I)" },
262 { 0x10, "long distance (L)" },
263 { 0x08, "medium distance (M)" },
264 { 0x0, NULL }
265 };
266
267 /*
268 * This is derived from SFF 8472 r12.2 Table 5-3. These values come from both
269 * bytes 7 and 8. We treat this as a uint16_t with the low byte as byte 7 and
270 * the high byte as byte 8.
271 */
272 #define SFF_8472_COMP_TECH_MASK 0xf007
273 static sff_pair_t sff_8472_comp_tech[] = {
274 { 0x4, "Shortwave laser, linear Rx (SA)" },
275 { 0x2, "Longwave laser (LC)" },
276 { 0x1, "Electrical inter-enclosure (EL)" },
277 { 0x8000, "Electrical intra-enclosure (EL)" },
278 { 0x4000, "Shortwave laser w/o OFC (SN)" },
279 { 0x2000, "Shortwave laser with OFC (SL)" },
280 { 0x1000, "Longwave laser (LL)" },
281 { 0x0, NULL }
282 };
283
284 /*
285 * This is derived from SFF 8472 r12.2 Table 5-3.
286 */
287 #define SFF_8472_COMP_CABLE_MASK 0x0c
288 #define SFF_8472_COMP_CABLE_ACTIVE 0x08
289 #define SFF_8472_COMP_CABLE_PASSIVE 0x04
290 static sff_pair_t sff_8472_comp_cable[] = {
291 { 0x08, "Active Cable" },
292 { 0x04, "Passive Cable" },
293 { 0x0, NULL }
294 };
295
296 /*
297 * This is derived from SFF 8472 r12.2 Table 5-3.
298 */
299 #define SFF_8472_COMP_MEDIA_MASK 0xfd
300 static sff_pair_t sff_8472_comp_media[] = {
301 { 0x80, "Twin Axial Pair (TW)" },
302 { 0x40, "Twisted Pair (TP)" },
303 { 0x20, "Miniature Coax (MI)" },
304 { 0x10, "Video Coax (TV)" },
305 { 0x08, "Multimode, 62.5um (M6)" },
306 { 0x04, "Multimode, 50um (M5, M5E)" },
307 /* 0x02 is Unallocated */
308 { 0x01, "Single Mode (SM)" },
309 { 0x0, NULL }
310 };
311
312 /*
313 * This is derived from SFF 8472 r12.2 Table 5-3.
314 */
315 #define SFF_8472_COMP_SPEED_MASK 0xfd
316 static sff_pair_t sff_8472_comp_speed[] = {
317 { 0x80, "1200 MBytes/sec" },
318 { 0x40, "800 MBytes/sec" },
319 { 0x20, "1600 MBytes/sec" },
320 { 0x10, "400 MBytes/sec" },
321 { 0x08, "3200 MBytes/sec" },
322 { 0x04, "200 MBytes/sec" },
323 /* 0x02 is Unallocated */
324 { 0x01, "100 MBytes/sec" },
325 { 0x0, NULL }
326 };
327
328 /*
329 * This is derived from SFF 8472 r12.2 Table 8-1.
330 * Note, only byte 60 is allocated at this time.
331 */
332 #define SFF_8472_PCABLE_COMP_MASK 0x3f
333 static sff_pair_t sff_8472_pcable_comp[] = {
334 { 0x20, "Reserved for SFF-8461" },
335 { 0x10, "Reserved for SFF-8461" },
336 { 0x08, "Reserved for SFF-8461" },
337 { 0x04, "Reserved for SFF-8461" },
338 { 0x02, "Compliant to FC-PI-4 Appendix H" },
339 { 0x01, "Compliant to SFF-8431 Appendix E" },
340 { 0x0, NULL }
341 };
342
343 /*
344 * This is derived from SFF 8472 r12.2 Table 8-2.
345 * Note, only byte 60 is allocated at this time.
346 */
347 #define SFF_8472_ACABLE_COMP_MASK 0xf
348 static sff_pair_t sff_8472_acable_comp[] = {
349 { 0x08, "Compliant to FC-PI-4 Limiting" },
350 { 0x04, "Compliant to SFF-8431 Limiting" },
351 { 0x02, "Compliant to FC-PI-4 Appendix H" },
352 { 0x01, "Compliant to SFF-8431 Appendix" },
353 { 0x0, NULL }
354 };
355
356 /*
357 * This is derived from SFF 8472 r12.2 Table 8-3.
358 * Note that we combined byte 64 and 65. Byte 64 is the upper bit.
359 */
360 #define SFF_8472_OPTION_MASK 0x3ffe
361 static sff_pair_t sff_8472_options[] = {
362 { 0x2000, "Power Level 3 Requirement"},
363 { 0x1000, "Paging Implemented"},
364 { 0x0800, "Retimer or CDR implemented"},
365 { 0x0400, "Cooled Transceiver Implemented"},
366 { 0x0200, "Power Level 2 Requirement"},
367 { 0x0100, "Linear Receiver Output Implemented"},
368 { 0x0080, "Receiver decision threshold implemented"},
369 { 0x0040, "Tunable transmitter"},
370 { 0x0020, "RATE_SELECT implemented"},
371 { 0x0010, "TX_DISABLE implemented"},
372 { 0x0008, "TX_FAULT implemented"},
373 { 0x0004, "Rx_LOS inverted"},
374 { 0x0002, "Rx_LOS implemented"},
375 };
376
377 /*
378 * This is derived from SFF 8472 r12.2 Table 8-6.
379 */
380 #define SFF_8472_EXTOPT_MASK 0xfe
381 static sff_pair_t sff_8472_extopts[] = {
382 { 0x80, "Alarm/Warning flags implemented" },
383 { 0x40, "Soft TX_DISABLE implemented" },
384 { 0x20, "Soft TX_FAULT implemented" },
385 { 0x10, "Soft RX_LOS implemented" },
386 { 0x08, "Soft RATE_SELECT implemented" },
387 { 0x04, "Application Select implemented" },
388 { 0x02, "Soft Rate Select Control Implemented" },
389 { 0x01, "" },
390 };
391
392 /*
393 * This is derived from SFF 8472 r12.2 Table 8-8.
394 */
395 #define SFF_8472_8472_COMP_NENTRIES 9
396 static const char *sff_8472_8472_comp[] = {
397 "Not compliant",
398 "Rev 9.3",
399 "Rev 9.5",
400 "Rev 10.2",
401 "Rev 10.4",
402 "Rev 11.0",
403 "Rev 11.3",
404 "Rev 11.4",
405 "Rev 12.0"
406 };
407
408 /*
409 * This is derived from SFF 8636 r2.7 Table 6-17.
410 */
411 #define SFF_8636_COMP_10GETH_MASK 0x7f
412 static sff_pair_t sff_8636_comp_10geth[] = {
413 { 0x40, "10GBASE-LRM" },
414 { 0x20, "10GBASE-LR" },
415 { 0x10, "10GBASE-SR" },
416 { 0x08, "40GBASE-CR4" },
417 { 0x04, "40GBASE-SR4" },
418 { 0x02, "40GBASE-LR4" },
419 { 0x01, "40G Active Cable (XLPPI)" },
420 { 0x0, NULL }
421 };
422
423 /*
424 * This is derived from SFF 8636 r2.7 Table 6-17.
425 */
426 #define SFF_8636_COMP_SONET_MASK 0x07
427 static sff_pair_t sff_8636_comp_sonet[] = {
428 { 0x04, "OC 48, long reach" },
429 { 0x02, "OC 48, intermediate reach" },
430 { 0x01, "OC 48 short reach" },
431 { 0x0, NULL }
432 };
433
434 /*
435 * This is derived from SFF 8636 r2.7 Table 6-17.
436 */
437 #define SFF_8636_COMP_SAS_MASK 0xf0
438 static sff_pair_t sff_8636_comp_sas[] = {
439 { 0x80, "SAS 24.0 Gb/s" },
440 { 0x40, "SAS 12.0 Gb/s" },
441 { 0x20, "SAS 6.0 Gb/s" },
442 { 0x10, "SAS 3.0 Gb/s" },
443 { 0x0, NULL }
444 };
445
446 /*
447 * This is derived from SFF 8636 r2.7 Table 6-17.
448 */
449 #define SFF_8636_COMP_ETH_MASK 0x0f
450 static sff_pair_t sff_8636_comp_eth[] = {
451 { 0x08, "1000BASE-T" },
452 { 0x04, "1000BASE-CX" },
453 { 0x02, "1000BASE-LX" },
454 { 0x01, "1000BASE-SX" },
455 { 0x0, NULL }
456 };
457
458 /*
459 * This is derived from SFF 8636 r2.7 Table 6-17.
460 */
461 #define SFF_8636_COMP_FCLEN_MASK 0xf8
462 static sff_pair_t sff_8636_comp_fclen[] = {
463 { 0x80, "very long distance (V)" },
464 { 0x40, "short distance (S)" },
465 { 0x20, "intermeddiate distance (I)" },
466 { 0x10, "long distance (L)" },
467 { 0x08, "medium distance (M)" },
468 { 0x0, NULL }
469 };
470
471 /*
472 * This is derived from SFF 8636 r2.7 Table 6-17.
473 */
474 #define SFF_8636_COMP_TECH_MASK 0xf003
475 static sff_pair_t sff_8636_comp_tech[] = {
476 { 0x2, "Longwave laser (LC)" },
477 { 0x1, "Electrical inter-enclosure (EL)" },
478 { 0x8000, "Electrical intra-enclosure (EL)" },
479 { 0x4000, "Shortwave laser w/o OFC (SN)" },
480 { 0x2000, "Shortwave laser with OFC (SL)" },
481 { 0x1000, "Longwave laser (LL)" },
482 { 0x0, NULL }
483 };
484
485 /*
486 * This is derived from SFF 8636 r2.7 Table 6-17.
487 */
488 #define SFF_8636_COMP_MEDIA_MASK 0xff
489 static sff_pair_t sff_8636_comp_media[] = {
490 { 0x80, "Twin Axial Pair (TW)" },
491 { 0x40, "Twisted Pair (TP)" },
492 { 0x20, "Miniature Coax (MI)" },
493 { 0x10, "Video Coax (TV)" },
494 { 0x08, "Multimode, 62.5um (M6)" },
495 { 0x04, "Multimode, 50m (M5)" },
496 { 0x02, "Multimode, 50um (OM3)" },
497 { 0x01, "Single Mode (SM)" },
498 { 0x0, NULL }
499 };
500
501 /*
502 * This is derived from SFF 8636 r2.7 Table 6-17.
503 */
504 #define SFF_8636_COMP_SPEED_MASK 0xfd
505 static sff_pair_t sff_8636_comp_speed[] = {
506 { 0x80, "1200 MBytes/sec" },
507 { 0x40, "800 MBytes/sec" },
508 { 0x20, "1600 MBytes/sec" },
509 { 0x10, "400 MBytes/sec" },
510 { 0x08, "3200 MBytes/sec" },
511 { 0x04, "200 MBytes/sec" },
512 { 0x01, "100 MBytes/sec" },
513 { 0x0, NULL }
514 };
515
516 /*
517 * This is derived from SFF 8636 r2.7 Table 6-20.
518 */
519 static const char *sff_8636_trans_tech[] = {
520 "850 nm VCSEL",
521 "1310 nm VCSEL",
522 "1550 nm VCSEL",
523 "1310 nm FP",
524 "1310 nm DFB",
525 "1550 nm DFB",
526 "1310 nm EML",
527 "1550 nm EML",
528 "Other / Undefined",
529 "1490 nm DFB",
530 "Copper cable unequalized",
531 "Copper cable passive equalized",
532 "Copper cable, near and far end limiting active equalizers",
533 "Copper cable, far end limiting active equalizers",
534 "Copper cable, near end limiting active equalizers",
535 "Copper cable, linear active equalizers"
536 };
537
538 /*
539 * This is derived from SFF 8636 r2.7 Table 6-21.
540 */
541 #define SFF_8636_EXTMOD_CODES 0x1f
542 static sff_pair_t sff_8636_extmod_codes[] = {
543 { 0x10, "EDR" },
544 { 0x08, "FDR" },
545 { 0x04, "QDR" },
546 { 0x02, "DDR" },
547 { 0x01, "SDR" },
548 { 0x00, NULL }
549 };
550
551 /*
552 * This is derived from SFF 8636 r2.7 Table 6-22. This combines bytes 193-195.
553 * We treat byte 193 as the most significant.
554 */
555 #define SFF_8636_OPTION_MASK 0x0ffffe
556 static sff_pair_t sff_8636_options[] = {
557 { 0x080000, "TX Input Equalization Auto Adaptive Capable" },
558 { 0x040000, "TX Input Equalization Fixed Programmable" },
559 { 0x020000, "RX Output Emphasis Fixed Programmable Settings" },
560 { 0x010000, "RX Output Amplitude Fixed Programmable Settings" },
561 { 0x008000, "TX CDR On/Off Control implemented" },
562 { 0x004000, "RX CDR On/Off Control implemented" },
563 { 0x002000, "Tx CDR Loss of Lock Flag implemented" },
564 { 0x001000, "Rx CDR Loss of Lock Flag implemented" },
565 { 0x000800, "Rx Squelch Disable implemented" },
566 { 0x000400, "Rx Output Disable capable" },
567 { 0x000200, "Tx Squelch Disable implemented" },
568 { 0x000100, "Tx Squelch implemented" },
569 { 0x000080, "Memory page 02h provided" },
570 { 0x000040, "Memory page 01h provided" },
571 { 0x000020, "Rate Select implemented" },
572 { 0x000010, "Tx_DISABLE implemented" },
573 { 0x000008, "Tx_FAULT implemented" },
574 { 0x000004, "Tx Squelch for Pave" },
575 { 0x000002, "Tx Loss of Signal implemented" },
576 { 0x0, NULL }
577 };
578
579 /*
580 * This is derived from SFF 8636 r2.7 Table 6-25.
581 */
582 #define SFF_8636_ENHANCED_OPTIONS_MASK 0x1c
583 static sff_pair_t sff_8636_eopt[] = {
584 { 0x10, "Initialization Complete Flag Implemented" },
585 { 0x08, "Extended Rate Selection Supported" },
586 { 0x04, "Application Select Table Supported" },
587 { 0x0, NULL }
588 };
589
590 static const char *
sff_pair_find(uint_t val,sff_pair_t * pairs)591 sff_pair_find(uint_t val, sff_pair_t *pairs)
592 {
593 while (pairs->sp_name != NULL) {
594 if (val == pairs->sp_val)
595 return (pairs->sp_name);
596 pairs++;
597 }
598
599 return (NULL);
600 }
601
602 static int
sff_parse_id(uint8_t id,nvlist_t * nvl)603 sff_parse_id(uint8_t id, nvlist_t *nvl)
604 {
605 const char *val;
606
607 if (id >= SFF_8024_VENDOR) {
608 val = "Vendor Specific";
609 } else if (id >= SFF_8024_NIDS) {
610 val = "Reserved";
611 } else {
612 val = sff_8024_id_strs[id];
613 }
614
615 return (nvlist_add_string(nvl, LIBSFF_KEY_IDENTIFIER, val));
616 }
617
618 static int
sff_add_unit_string(uint64_t val,uint64_t factor,const char * unit,nvlist_t * nvl,const char * key)619 sff_add_unit_string(uint64_t val, uint64_t factor, const char *unit,
620 nvlist_t *nvl, const char *key)
621 {
622 char str[SFP_STRBUF];
623
624 val *= factor;
625 (void) snprintf(str, sizeof (str), "%" PRIu64 " %s", val, unit);
626 return (nvlist_add_string(nvl, key, str));
627 }
628
629 static int
sff_parse_connector(uint8_t con,nvlist_t * nvl)630 sff_parse_connector(uint8_t con, nvlist_t *nvl)
631 {
632 const char *val;
633
634 if (con >= 0x80) {
635 val = "Vendor Specific";
636 } else {
637 if ((val = sff_pair_find(con, sff_8024_connectors)) == NULL)
638 val = "Reserved";
639 }
640
641 return (nvlist_add_string(nvl, LIBSFF_KEY_CONNECTOR, val));
642 }
643
644 /*
645 * Many of the values in the specifications are bitfields of which one or more
646 * bits may be set. We represent that as an array of strings. One entry will be
647 * added for each set bit that's found in pairs.
648 */
649 static int
sff_gather_bitfield(uint32_t value,const char * name,sff_pair_t * pairs,nvlist_t * nvl)650 sff_gather_bitfield(uint32_t value, const char *name, sff_pair_t *pairs,
651 nvlist_t *nvl)
652 {
653 uint32_t i;
654 const char *vals[32];
655 uint_t count;
656
657 count = 0;
658 for (i = 0; i < 32; i++) {
659 uint32_t bit;
660 const char *str;
661
662 bit = 1 << i;
663 if ((bit & value) == 0)
664 continue;
665
666 str = sff_pair_find(bit, pairs);
667 if (str != NULL) {
668 vals[count++] = str;
669 }
670 }
671
672 if (count == 0)
673 return (0);
674
675 /*
676 * The nvlist routines don't touch the array, so we end up lying about
677 * the type of data so that we can avoid a rash of additional
678 * allocations and strdups.
679 */
680 return (nvlist_add_string_array(nvl, name, (char **)vals, count));
681 }
682
683 static int
sff_parse_compliance(const uint8_t * buf,nvlist_t * nvl)684 sff_parse_compliance(const uint8_t *buf, nvlist_t *nvl)
685 {
686 int ret;
687 uint16_t v;
688
689 if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_10GE] &
690 SFF_8472_COMP_10GETH_MASK, LIBSFF_KEY_COMPLIANCE_10GBE,
691 sff_8472_comp_10geth, nvl)) != 0)
692 return (ret);
693
694 if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_IB] &
695 SFF_8472_COMP_IB_MASK, LIBSFF_KEY_COMPLIANCE_IB,
696 sff_8472_comp_ib, nvl)) != 0)
697 return (ret);
698
699 if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_ESCON] &
700 SFF_8472_COMP_ESCON_MASK, LIBSFF_KEY_COMPLIANCE_ESCON,
701 sff_8472_comp_escon, nvl)) != 0)
702 return (ret);
703
704 v = buf[SFF_8472_COMPLIANCE_SONET_LOW] |
705 (buf[SFF_8472_COMPLIANCE_SONET_HIGH] << 8);
706 if ((ret = sff_gather_bitfield(v & SFF_8472_COMP_SOCON_MASK,
707 LIBSFF_KEY_COMPLIANCE_SONET, sff_8472_comp_sonet, nvl)) != 0)
708 return (ret);
709
710 if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_ETHERNET] &
711 SFF_8472_COMP_ETH_MASK, LIBSFF_KEY_COMPLIANCE_GBE,
712 sff_8472_comp_eth, nvl)) != 0)
713 return (ret);
714
715 if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_FCLEN] &
716 SFF_8472_COMP_FCLEN_MASK, LIBSFF_KEY_COMPLIANCE_FC_LEN,
717 sff_8472_comp_fclen, nvl)) != 0)
718 return (ret);
719
720 v = buf[SFF_8472_COMPLIANCE_FC_LOW] |
721 (buf[SFF_8472_COMPLIANCE_FC_HIGH] << 8);
722 if ((ret = sff_gather_bitfield(v & SFF_8472_COMP_TECH_MASK,
723 LIBSFF_KEY_COMPLIANCE_FC_TECH, sff_8472_comp_tech, nvl)) != 0)
724 return (ret);
725
726 if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_SFP] &
727 SFF_8472_COMP_CABLE_MASK, LIBSFF_KEY_COMPLIANCE_SFP,
728 sff_8472_comp_cable, nvl)) != 0)
729 return (ret);
730
731 if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_FC_MEDIA] &
732 SFF_8472_COMP_MEDIA_MASK, LIBSFF_KEY_COMPLIANCE_FC_MEDIA,
733 sff_8472_comp_media, nvl)) != 0)
734 return (ret);
735
736 if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_FC_SPEED] &
737 SFF_8472_COMP_SPEED_MASK, LIBSFF_KEY_COMPLIANCE_FC_SPEED,
738 sff_8472_comp_speed, nvl)) != 0)
739 return (ret);
740
741 return (0);
742 }
743
744 static int
sff_parse_encoding(uint8_t val,nvlist_t * nvl,boolean_t sfp)745 sff_parse_encoding(uint8_t val, nvlist_t *nvl, boolean_t sfp)
746 {
747 const char *str;
748 if (val >= SFF_8024_NENCS) {
749 str = "Reserved";
750 } else if (sfp) {
751 str = sff_8024_enc_sfp[val];
752 } else {
753 str = sff_8024_enc_qsfp[val];
754 }
755
756 return (nvlist_add_string(nvl, LIBSFF_KEY_ENCODING, str));
757 }
758
759 static int
sff_parse_br(const uint8_t * buf,nvlist_t * nvl)760 sff_parse_br(const uint8_t *buf, nvlist_t *nvl)
761 {
762 if (buf[SFF_8472_BR_NOMINAL] == 0xff) {
763 int ret;
764 if ((ret = sff_add_unit_string(buf[SFF_8472_BR_MAX],
765 SFF_8472_BR_MAX_FACTOR, "MBd", nvl,
766 LIBSFF_KEY_BR_MAX)) != 0)
767 return (ret);
768 return (sff_add_unit_string(buf[SFF_8472_BR_MIN],
769 SFF_8472_BR_MIN_FACTOR, "MBd", nvl, LIBSFF_KEY_BR_MIN));
770 } else {
771 return (sff_add_unit_string(buf[SFF_8472_BR_NOMINAL],
772 SFF_8472_BR_NOMINAL_FACTOR, "MBd", nvl,
773 LIBSFF_KEY_BR_NOMINAL));
774 }
775 }
776
777 static int
sff_parse_lengths(const uint8_t * buf,nvlist_t * nvl)778 sff_parse_lengths(const uint8_t *buf, nvlist_t *nvl)
779 {
780 int ret;
781
782 if (buf[SFF_8472_LENGTH_SMF_KM] != 0) {
783 if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_SMF_KM],
784 SFF_8472_LENGTH_SMF_KM_FACTOR, "km", nvl,
785 LIBSFF_KEY_LENGTH_SMF_KM)) != 0)
786 return (ret);
787 }
788
789 if (buf[SFF_8472_LENGTH_SMF] != 0) {
790 if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_SMF],
791 SFF_8472_LENGTH_SMF_FACTOR, "m", nvl,
792 LIBSFF_KEY_LENGTH_SMF)) != 0)
793 return (ret);
794 }
795
796 if (buf[SFF_8472_LENGTH_50UM] != 0) {
797 if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_50UM],
798 SFF_8472_LENGTH_50UM_FACTOR, "m", nvl,
799 LIBSFF_KEY_LENGTH_OM2)) != 0)
800 return (ret);
801 }
802
803 if (buf[SFF_8472_LENGTH_62UM] != 0) {
804 if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_62UM],
805 SFF_8472_LENGTH_62UM_FACTOR, "m", nvl,
806 LIBSFF_KEY_LENGTH_OM1)) != 0)
807 return (ret);
808 }
809
810 if (buf[SFF_8472_LENGTH_COPPER] != 0) {
811 if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_COPPER],
812 SFF_8472_LENGTH_COPPER_FACTOR, "m", nvl,
813 LIBSFF_KEY_LENGTH_COPPER)) != 0)
814 return (ret);
815 }
816
817 if (buf[SFF_8472_LENGTH_OM3] != 0) {
818 if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_OM3],
819 SFF_8472_LENGTH_OM3_FACTOR, "m", nvl,
820 LIBSFF_KEY_LENGTH_OM3)) != 0)
821 return (ret);
822 }
823
824 return (0);
825 }
826
827 /*
828 * Strings in the SFF specification are written into fixed sized buffers. The
829 * strings are padded to the right with spaces (ASCII 0x20) and there is no NUL
830 * character like in a standard C string. While the string is padded with
831 * spaces, spaces may appear in the middle of the string and should not be
832 * confused as padding.
833 */
834 static int
sff_parse_string(const uint8_t * buf,uint_t start,uint_t len,const char * field,nvlist_t * nvl)835 sff_parse_string(const uint8_t *buf, uint_t start, uint_t len,
836 const char *field, nvlist_t *nvl)
837 {
838 uint_t i;
839 char strbuf[SFP_STRBUF];
840
841 assert(len < sizeof (strbuf));
842 strbuf[0] = '\0';
843 while (len > 0) {
844 if (buf[start + len - 1] != ' ')
845 break;
846 len--;
847 }
848 if (len == 0)
849 return (0);
850
851 /*
852 * This is supposed to be 7-bit printable ASCII. If we find any
853 * characters that aren't, don't include this string.
854 */
855 for (i = 0; i < len; i++) {
856 if (isascii(buf[start + i]) == 0 ||
857 isprint(buf[start + i]) == 0) {
858 return (0);
859 }
860 }
861 bcopy(&buf[start], strbuf, len);
862 strbuf[len] = '\0';
863
864 return (nvlist_add_string(nvl, field, strbuf));
865 }
866
867 static int
sff_parse_optical(const uint8_t * buf,nvlist_t * nvl)868 sff_parse_optical(const uint8_t *buf, nvlist_t *nvl)
869 {
870 /*
871 * The value in byte 8 determines whether we interpret this as
872 * describing aspects of a copper device or if it describes the
873 * wavelength.
874 */
875 if (buf[SFF_8472_COMPLIANCE_SFP] & SFF_8472_COMP_CABLE_PASSIVE) {
876 return (sff_gather_bitfield(buf[SFF_8472_PASSIVE_SPEC] &
877 SFF_8472_PCABLE_COMP_MASK, LIBSFF_KEY_COMPLIANCE_PASSIVE,
878 sff_8472_pcable_comp, nvl));
879 } else if (buf[SFF_8472_COMPLIANCE_SFP] & SFF_8472_COMP_CABLE_ACTIVE) {
880 return (sff_gather_bitfield(buf[SFF_8472_ACTIVE_SPEC] &
881 SFF_8472_ACABLE_COMP_MASK, LIBSFF_KEY_COMPLIANCE_ACTIVE,
882 sff_8472_acable_comp, nvl));
883
884 } else {
885 uint16_t val = (buf[SFF_8472_WAVELENGTH_HI] << 8) |
886 buf[SFF_8472_WAVELENGTH_LOW];
887
888 return (sff_add_unit_string(val, SFF_8472_WAVELENGTH_FACTOR,
889 "nm", nvl, LIBSFF_KEY_WAVELENGTH));
890 }
891 }
892
893 static int
sff_parse_options(const uint8_t * buf,nvlist_t * nvl)894 sff_parse_options(const uint8_t *buf, nvlist_t *nvl)
895 {
896 uint16_t val;
897
898 val = (buf[SFF_8472_OPTIONS_HI] << 8) | buf[SFF_8472_OPTIONS_LOW];
899 return (sff_gather_bitfield(val & SFF_8472_OPTION_MASK,
900 LIBSFF_KEY_OPTIONS, sff_8472_options, nvl));
901 }
902
903 static int
sff_parse_8472_comp(uint8_t val,nvlist_t * nvl)904 sff_parse_8472_comp(uint8_t val, nvlist_t *nvl)
905 {
906 const char *str;
907
908 if (val >= SFF_8472_8472_COMP_NENTRIES) {
909 str = "Unallocated";
910 } else {
911 str = sff_8472_8472_comp[val];
912 }
913
914 return (nvlist_add_string(nvl, LIBSFF_KEY_COMPLIANCE_8472, str));
915 }
916
917 /*
918 * Parse an SFP that is either based on INF 8074 or SFF 8472. These are GBIC,
919 * SFP, SFP+, and SFP28 based devices.
920 *
921 * The SFP parsing into an nvlist_t is incomplete. At the moment we're not
922 * parsing the following pieces from SFF 8472 page 0xa0:
923 *
924 * o Rate Selection Logic
925 * o Diagnostic Monitoring Type
926 */
927 static int
sff_parse_sfp(const uint8_t * buf,nvlist_t * nvl)928 sff_parse_sfp(const uint8_t *buf, nvlist_t *nvl)
929 {
930 int ret;
931
932 if ((ret = sff_parse_id(buf[SFF_8472_IDENTIFIER], nvl)) != 0)
933 return (ret);
934
935 /*
936 * The extended identifier is derived from SFF 8472, Table 5-2. It
937 * generally is just the value 4. The other values are not well defined.
938 */
939 if ((ret = nvlist_add_uint8(nvl, LIBSFF_KEY_8472_EXT_IDENTIFIER,
940 buf[SFF_8472_EXT_IDENTIFER])) != 0)
941 return (ret);
942
943 if ((ret = sff_parse_connector(buf[SFF_8472_CONNECTOR], nvl)) != 0)
944 return (ret);
945
946 if ((ret = sff_parse_compliance(buf, nvl)) != 0)
947 return (ret);
948
949 if ((ret = sff_parse_encoding(buf[SFF_8472_ENCODING], nvl,
950 B_TRUE)) != 0)
951 return (ret);
952
953 if ((ret = sff_parse_br(buf, nvl)) != 0)
954 return (ret);
955
956 if ((ret = sff_parse_lengths(buf, nvl)) != 0)
957 return (ret);
958
959 if ((ret = sff_parse_string(buf, SFF_8472_VENDOR, SFF_8472_VENDOR_LEN,
960 LIBSFF_KEY_VENDOR, nvl)) != 0)
961 return (ret);
962
963 if ((ret = nvlist_add_byte_array(nvl, LIBSFF_KEY_OUI,
964 (uchar_t *)&buf[SFF_8472_OUI], SFF_8472_OUI_LEN)) != 0)
965 return (ret);
966
967 if ((ret = sff_parse_string(buf, SFF_8472_VENDOR_PN,
968 SFF_8472_VENDOR_PN_LEN, LIBSFF_KEY_PART, nvl)) != 0)
969 return (ret);
970
971 if ((ret = sff_parse_string(buf, SFF_8472_VENDOR_REV,
972 SFF_8472_VENDOR_REV_LEN, LIBSFF_KEY_REVISION, nvl)) != 0)
973 return (ret);
974
975 if ((ret = sff_parse_optical(buf, nvl)) != 0)
976 return (ret);
977
978 if ((ret = sff_parse_options(buf, nvl)) != 0)
979 return (ret);
980
981 if ((ret = sff_parse_string(buf, SFF_8472_VENDOR_SN,
982 SFF_8472_VENDOR_SN_LEN, LIBSFF_KEY_SERIAL, nvl)) != 0)
983 return (ret);
984
985 if ((ret = sff_parse_string(buf, SFF_8472_DATE_CODE,
986 SFF_8472_DATE_CODE_LEN, LIBSFF_KEY_DATECODE, nvl)) != 0)
987 return (ret);
988
989 if ((ret = sff_gather_bitfield(buf[SFF_8472_ENHANCED_OPTIONS] &
990 SFF_8472_EXTOPT_MASK, LIBSFF_KEY_EXTENDED_OPTIONS,
991 sff_8472_extopts, nvl)) != 0)
992 return (ret);
993
994 if ((ret = sff_parse_8472_comp(buf[SFF_8472_SFF_8472_COMPLIANCE],
995 nvl)) != 0)
996 return (ret);
997
998 return (0);
999 }
1000
1001 static int
sff_qsfp_parse_compliance(const uint8_t * buf,nvlist_t * nvl)1002 sff_qsfp_parse_compliance(const uint8_t *buf, nvlist_t *nvl)
1003 {
1004 int ret;
1005 uint16_t fc_val;
1006
1007 if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_10GBEP] &
1008 SFF_8636_COMP_10GETH_MASK, LIBSFF_KEY_COMPLIANCE_10GBE,
1009 sff_8636_comp_10geth, nvl)) != 0)
1010 return (ret);
1011
1012 if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_SONET] &
1013 SFF_8636_COMP_SONET_MASK, LIBSFF_KEY_COMPLIANCE_SONET,
1014 sff_8636_comp_sonet, nvl)) != 0)
1015 return (ret);
1016
1017 if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_SAS] &
1018 SFF_8636_COMP_SAS_MASK, LIBSFF_KEY_COMPLIANCE_SAS,
1019 sff_8636_comp_sas, nvl)) != 0)
1020 return (ret);
1021
1022 if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_ETHERNET] &
1023 SFF_8636_COMP_ETH_MASK, LIBSFF_KEY_COMPLIANCE_GBE,
1024 sff_8636_comp_eth, nvl)) != 0)
1025 return (ret);
1026
1027 if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_FCLEN] &
1028 SFF_8636_COMP_FCLEN_MASK, LIBSFF_KEY_COMPLIANCE_FC_LEN,
1029 sff_8636_comp_fclen, nvl)) != 0)
1030 return (ret);
1031
1032 fc_val = buf[SFF_8636_COMPLIANCE_FC_LOW] |
1033 (buf[SFF_8636_COMPLIANCE_FC_HIGH] << 8);
1034 if ((ret = sff_gather_bitfield(fc_val & SFF_8636_COMP_TECH_MASK,
1035 LIBSFF_KEY_COMPLIANCE_FC_TECH, sff_8636_comp_tech, nvl)) != 0)
1036 return (ret);
1037
1038 if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_FC_MEDIA] &
1039 SFF_8636_COMP_MEDIA_MASK, LIBSFF_KEY_COMPLIANCE_FC_MEDIA,
1040 sff_8636_comp_media, nvl)) != 0)
1041 return (ret);
1042
1043 if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_FC_SPEED] &
1044 SFF_8636_COMP_SPEED_MASK, LIBSFF_KEY_COMPLIANCE_FC_SPEED,
1045 sff_8636_comp_speed, nvl)) != 0)
1046 return (ret);
1047
1048 return (0);
1049 }
1050
1051 static int
sff_qsfp_parse_br(const uint8_t * buf,nvlist_t * nvl)1052 sff_qsfp_parse_br(const uint8_t *buf, nvlist_t *nvl)
1053 {
1054 if (buf[SFF_8636_BR_NOMINAL] == 0xff) {
1055 return (sff_add_unit_string(buf[SFF_8636_BR_NOMINAL_EXT],
1056 SFF_8636_BR_NOMINAL_EXT_FACTOR, "Mbps", nvl,
1057 LIBSFF_KEY_BR_NOMINAL));
1058 } else {
1059 return (sff_add_unit_string(buf[SFF_8636_BR_NOMINAL],
1060 SFF_8636_BR_NOMINAL_FACTOR, "Mbps", nvl,
1061 LIBSFF_KEY_BR_NOMINAL));
1062 }
1063 }
1064
1065 static int
sff_qsfp_parse_lengths(const uint8_t * buf,nvlist_t * nvl)1066 sff_qsfp_parse_lengths(const uint8_t *buf, nvlist_t *nvl)
1067 {
1068 int ret;
1069
1070 if (buf[SFF_8636_LENGTH_SMF] != 0) {
1071 if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_SMF],
1072 SFF_8636_LENGTH_SMF_FACTOR, "km", nvl,
1073 LIBSFF_KEY_LENGTH_SMF_KM)) != 0)
1074 return (ret);
1075 }
1076
1077 if (buf[SFF_8636_LENGTH_OM3] != 0) {
1078 if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_OM3],
1079 SFF_8636_LENGTH_OM3_FACTOR, "m", nvl,
1080 LIBSFF_KEY_LENGTH_OM3)) != 0)
1081 return (ret);
1082 }
1083
1084 if (buf[SFF_8636_LENGTH_OM2] != 0) {
1085 if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_OM2],
1086 SFF_8636_LENGTH_OM2_FACTOR, "m", nvl,
1087 LIBSFF_KEY_LENGTH_OM2)) != 0)
1088 return (ret);
1089 }
1090
1091 if (buf[SFF_8636_LENGTH_OM1] != 0) {
1092 if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_OM1],
1093 SFF_8636_LENGTH_OM1_FACTOR, "m", nvl,
1094 LIBSFF_KEY_LENGTH_OM1)) != 0)
1095 return (ret);
1096 }
1097
1098 if (buf[SFF_8636_LENGTH_COPPER] != 0) {
1099 if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_COPPER],
1100 SFF_8636_LENGTH_COPPER_FACTOR, "m", nvl,
1101 LIBSFF_KEY_LENGTH_COPPER)) != 0)
1102 return (ret);
1103 }
1104
1105 return (0);
1106 }
1107
1108 static int
sff_qsfp_parse_tech(uint8_t val,nvlist_t * nvl)1109 sff_qsfp_parse_tech(uint8_t val, nvlist_t *nvl)
1110 {
1111 const char *strs[5];
1112
1113 strs[0] = sff_8636_trans_tech[(val & 0xf0) >> 4];
1114 if (val & 0x08) {
1115 strs[1] = "Active Wavelength Control";
1116 } else {
1117 strs[1] = "No Wavelength Control";
1118 }
1119
1120 if (val & 0x04) {
1121 strs[2] = "Cooled Transmitter";
1122 } else {
1123 strs[2] = "Uncooled Transmitter";
1124 }
1125
1126 if (val & 0x02) {
1127 strs[3] = "APD Detector";
1128 } else {
1129 strs[3] = "Pin Detector";
1130 }
1131
1132 if (val & 0x01) {
1133 strs[4] = "Transmitter Tunable";
1134 } else {
1135 strs[4] = "Transmitter Not Tunable";
1136 }
1137
1138 /*
1139 * The nvlist routines don't touch the array, so we end up lying about
1140 * the type of data so that we can avoid a rash of additional
1141 * allocations and strdups.
1142 */
1143 return (nvlist_add_string_array(nvl, LIBSFF_KEY_TRAN_TECH,
1144 (char **)strs, 5));
1145 }
1146
1147 static int
sff_qsfp_parse_copperwave(const uint8_t * buf,nvlist_t * nvl)1148 sff_qsfp_parse_copperwave(const uint8_t *buf, nvlist_t *nvl)
1149 {
1150 int ret;
1151
1152 /*
1153 * The values that we get depend on whether or not we are a copper
1154 * device or not. We can determine this based on the identification
1155 * information in the device technology field.
1156 */
1157 if ((buf[SFF_8636_DEVICE_TECH] & 0xf0) >= 0xa0) {
1158 if ((ret = sff_add_unit_string(buf[SFF_8636_ATTENUATE_2G], 1,
1159 "dB", nvl, LIBSFF_KEY_ATTENUATE_2G)) != 0)
1160 return (ret);
1161 if ((ret = sff_add_unit_string(buf[SFF_8636_ATTENUATE_5G], 1,
1162 "dB", nvl, LIBSFF_KEY_ATTENUATE_5G)) != 0)
1163 return (ret);
1164 if ((ret = sff_add_unit_string(buf[SFF_8636_ATTENUATE_7G], 1,
1165 "dB", nvl, LIBSFF_KEY_ATTENUATE_7G)) != 0)
1166 return (ret);
1167 if ((ret = sff_add_unit_string(buf[SFF_8636_ATTENUATE_12G], 1,
1168 "dB", nvl, LIBSFF_KEY_ATTENUATE_12G)) != 0)
1169 return (ret);
1170 } else {
1171 uint16_t val;
1172 double d;
1173 char strbuf[SFP_STRBUF];
1174
1175 /*
1176 * Because we need to divide the units here into doubles, we
1177 * can't use the standard unit routine.
1178 */
1179 val = (buf[SFF_8636_WAVELENGTH_NOMINAL_HI] << 8) |
1180 buf[SFF_8636_WAVELENGTH_NOMINAL_LOW];
1181 if (val != 0) {
1182 d = val / 20.0;
1183 (void) snprintf(strbuf, sizeof (strbuf), "%.3lf nm", d);
1184 if ((ret = nvlist_add_string(nvl, LIBSFF_KEY_WAVELENGTH,
1185 strbuf)) != 0)
1186 return (ret);
1187 }
1188
1189 val = (buf[SFF_8636_WAVELENGTH_TOLERANCE_HI] << 8) |
1190 buf[SFF_8636_WAVELENGTH_TOLERANCE_LOW];
1191 if (val != 0) {
1192 d = val / 20.0;
1193 (void) snprintf(strbuf, sizeof (strbuf), "%.3lf nm", d);
1194 if ((ret = nvlist_add_string(nvl,
1195 LIBSFF_KEY_WAVE_TOLERANCE, strbuf)) != 0)
1196 return (ret);
1197 }
1198 }
1199
1200 return (0);
1201 }
1202
1203 static int
sff_qsfp_parse_casetemp(uint8_t val,nvlist_t * nvl)1204 sff_qsfp_parse_casetemp(uint8_t val, nvlist_t *nvl)
1205 {
1206 /*
1207 * The default temperature per SFF 8636 r2.7 6.3.21 'Maximum Case
1208 * Temperature' is 70 C. If the value is zero, we're supposed to assume
1209 * it's the default.
1210 */
1211 if (val == 0)
1212 val = 70;
1213
1214 return (sff_add_unit_string(val, 1, "C", nvl,
1215 LIBSFF_KEY_MAX_CASE_TEMP));
1216 }
1217
1218 static int
sff_qsfp_parse_extcomp(uint8_t val,nvlist_t * nvl)1219 sff_qsfp_parse_extcomp(uint8_t val, nvlist_t *nvl)
1220 {
1221 const char *str;
1222
1223 if (val >= SFF_8024_EXT_SPEC_NENTRIES) {
1224 str = "Reserved";
1225 } else {
1226 str = sff_8024_ext_spec[val];
1227 }
1228
1229 return (nvlist_add_string(nvl, LIBSFF_KEY_EXT_SPEC, str));
1230 }
1231
1232 static int
sff_qsfp_parse_options(const uint8_t * buf,nvlist_t * nvl)1233 sff_qsfp_parse_options(const uint8_t *buf, nvlist_t *nvl)
1234 {
1235 uint_t val;
1236
1237 val = (buf[SFF_8636_OPTIONS_HI] << 16) |
1238 (buf[SFF_8636_OPTIONS_MID] << 8) | buf[SFF_8636_OPTIONS_LOW];
1239
1240 return (sff_gather_bitfield(val & SFF_8636_OPTION_MASK,
1241 LIBSFF_KEY_OPTIONS, sff_8636_options, nvl));
1242 }
1243
1244 static int
sff_qsfp_parse_diag(uint8_t val,nvlist_t * nvl)1245 sff_qsfp_parse_diag(uint8_t val, nvlist_t *nvl)
1246 {
1247 const char *buf[2];
1248 uint_t count = 1;
1249
1250 if (val & 0x08) {
1251 buf[0] = "Received power measurements: Average Power";
1252 } else {
1253 buf[0] = "Received power measurements: OMA";
1254 }
1255
1256 if (val & 0x04) {
1257 count++;
1258 buf[1] = "Transmitter power measurement";
1259 }
1260
1261 /*
1262 * The nvlist routines don't touch the array, so we end up lying about
1263 * the type of data so that we can avoid a rash of additional
1264 * allocations and strdups.
1265 */
1266 return (nvlist_add_string_array(nvl, LIBSFF_KEY_DIAG_MONITOR,
1267 (char **)buf, count));
1268 }
1269
1270 /*
1271 * Parse a QSFP family device that is based on SFF-8436 / SFF-8636. Note that we
1272 * ignore the lower half of page 0xa0 at this time and instead focus on the
1273 * upper half of page 0xa0 which has identification information.
1274 *
1275 * For the moment we're not parsing the following fields:
1276 *
1277 * o Extended Identifier (byte 129)
1278 * o Extended Rate Select Compliance (byte 141)
1279 */
1280 static int
sff_parse_qsfp(const uint8_t * buf,nvlist_t * nvl)1281 sff_parse_qsfp(const uint8_t *buf, nvlist_t *nvl)
1282 {
1283 int ret;
1284
1285 if ((ret = sff_parse_id(buf[SFF_8636_IDENTIFIER], nvl)) != 0)
1286 return (ret);
1287
1288 if ((ret = sff_parse_connector(buf[SFF_8636_CONNECTOR], nvl)) != 0)
1289 return (ret);
1290
1291 if ((ret = sff_qsfp_parse_compliance(buf, nvl)) != 0)
1292 return (ret);
1293
1294 if ((ret = sff_parse_encoding(buf[SFF_8636_ENCODING], nvl,
1295 B_FALSE)) != 0)
1296 return (ret);
1297
1298 if ((ret = sff_qsfp_parse_br(buf, nvl)) != 0)
1299 return (ret);
1300
1301 if ((ret = sff_qsfp_parse_lengths(buf, nvl)) != 0)
1302 return (ret);
1303
1304 if ((ret = sff_qsfp_parse_tech(buf[SFF_8636_DEVICE_TECH], nvl)) != 0)
1305 return (ret);
1306
1307 if ((ret = sff_parse_string(buf, SFF_8636_VENDOR, SFF_8636_VENDOR_LEN,
1308 LIBSFF_KEY_VENDOR, nvl)) != 0)
1309 return (ret);
1310
1311 if ((ret = sff_gather_bitfield(buf[SFF_8636_EXTENDED_MODULE] &
1312 SFF_8636_EXTMOD_CODES, LIBSFF_KEY_EXT_MOD_CODES,
1313 sff_8636_extmod_codes, nvl)) != 0)
1314 return (ret);
1315
1316 if ((ret = nvlist_add_byte_array(nvl, LIBSFF_KEY_OUI,
1317 (uchar_t *)&buf[SFF_8636_OUI], SFF_8636_OUI_LEN)) != 0)
1318 return (ret);
1319
1320 if ((ret = sff_parse_string(buf, SFF_8636_VENDOR_PN,
1321 SFF_8636_VENDOR_PN_LEN, LIBSFF_KEY_PART, nvl)) != 0)
1322 return (ret);
1323
1324 if ((ret = sff_parse_string(buf, SFF_8636_VENDOR_REV,
1325 SFF_8636_VENDOR_REV_LEN, LIBSFF_KEY_REVISION, nvl)) != 0)
1326 return (ret);
1327
1328 if ((ret = sff_qsfp_parse_copperwave(buf, nvl)) != 0)
1329 return (ret);
1330
1331 if ((ret = sff_qsfp_parse_casetemp(buf[SFF_8636_MAX_CASE_TEMP],
1332 nvl)) != 0)
1333 return (ret);
1334
1335 if ((ret = sff_qsfp_parse_extcomp(buf[SFF_8636_LINK_CODES], nvl)) != 0)
1336 return (ret);
1337
1338 if ((ret = sff_qsfp_parse_options(buf, nvl)) != 0)
1339 return (ret);
1340
1341 if ((ret = sff_parse_string(buf, SFF_8636_VENDOR_SN,
1342 SFF_8636_VENDOR_SN_LEN, LIBSFF_KEY_SERIAL, nvl)) != 0)
1343 return (ret);
1344
1345 if ((ret = sff_parse_string(buf, SFF_8636_DATE_CODE,
1346 SFF_8636_DATE_CODE_LEN, LIBSFF_KEY_DATECODE, nvl)) != 0)
1347 return (ret);
1348
1349 if ((ret = sff_qsfp_parse_diag(buf[SFF_8636_DIAG_MONITORING],
1350 nvl)) != 0)
1351 return (ret);
1352
1353 if ((ret = sff_gather_bitfield(buf[SFF_8636_ENHANCED_OPTIONS] &
1354 SFF_8636_ENHANCED_OPTIONS_MASK, LIBSFF_KEY_ENHANCED_OPTIONS,
1355 sff_8636_eopt, nvl)) != 0)
1356 return (ret);
1357
1358 return (0);
1359 }
1360
1361 int
libsff_parse(const uint8_t * buf,size_t len,uint_t page,nvlist_t ** nvpp)1362 libsff_parse(const uint8_t *buf, size_t len, uint_t page, nvlist_t **nvpp)
1363 {
1364 int ret;
1365 nvlist_t *nvp = NULL;
1366 uint8_t ubuf[256];
1367
1368 /*
1369 * At the moment, we only support page a0.
1370 */
1371 if (page != 0xa0 || buf == NULL || len == 0 || nvpp == NULL)
1372 return (EINVAL);
1373
1374 *nvpp = NULL;
1375
1376 /*
1377 * Make sure that the library has been given valid data to parse.
1378 */
1379 if (uucopy(buf, ubuf, MIN(sizeof (ubuf), len)) != 0)
1380 return (errno);
1381
1382 if ((ret = nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0)) != 0)
1383 return (ret);
1384
1385 switch (buf[0]) {
1386 case SFF_8024_ID_QSFP:
1387 case SFF_8024_ID_QSFP_PLUS:
1388 case SFF_8024_ID_QSFP28:
1389 /*
1390 * For QSFP based products, identification information is spread
1391 * across both the top and bottom half of page 0xa0.
1392 */
1393 if (len < SFP_MIN_LEN_8636) {
1394 ret = EINVAL;
1395 break;
1396 }
1397 ret = sff_parse_qsfp(ubuf, nvp);
1398 break;
1399 default:
1400 if (len < SFP_MIN_LEN_8472) {
1401 ret = EINVAL;
1402 break;
1403 }
1404 ret = sff_parse_sfp(ubuf, nvp);
1405 break;
1406 }
1407
1408 if (ret != 0) {
1409 nvlist_free(nvp);
1410 } else {
1411 *nvpp = nvp;
1412 }
1413 return (ret);
1414 }
1415