1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2022 Intel Corporation 3 * Implements SFF-8079 optics diagnostics. 4 */ 5 6 #include <stdio.h> 7 8 #include "sff_common.h" 9 10 static void sff_8079_show_identifier(const uint8_t *data, struct rte_tel_data *d) 11 { 12 sff_8024_show_identifier(data, 0, d); 13 } 14 15 static void sff_8079_show_ext_identifier(const uint8_t *data, struct rte_tel_data *d) 16 { 17 char val_string[SFF_ITEM_VAL_COMPOSE_SIZE]; 18 19 snprintf(val_string, sizeof(val_string), "0x%02x", data[1]); 20 if (data[1] == 0x00) 21 strlcat(val_string, " (GBIC not specified / not MOD_DEF compliant)", 22 sizeof(val_string)); 23 else if (data[1] == 0x04) 24 strlcat(val_string, " (GBIC/SFP defined by 2-wire interface ID)", 25 sizeof(val_string)); 26 else if (data[1] <= 0x07) { 27 char tmp[SFF_ITEM_VAL_COMPOSE_SIZE]; 28 snprintf(tmp, sizeof(tmp), " (GBIC compliant with MOD_DEF %u)", data[1]); 29 strlcat(val_string, tmp, sizeof(val_string)); 30 } else 31 strlcat(val_string, " (unknown)", sizeof(val_string)); 32 ssf_add_dict_string(d, "Extended identifier", val_string); 33 } 34 35 static void sff_8079_show_connector(const uint8_t *data, struct rte_tel_data *d) 36 { 37 sff_8024_show_connector(data, 2, d); 38 } 39 40 static void sff_8079_show_transceiver(const uint8_t *data, struct rte_tel_data *d) 41 { 42 static const char *name = "Transceiver type"; 43 char val_string[SFF_ITEM_VAL_COMPOSE_SIZE]; 44 45 snprintf(val_string, sizeof(val_string), 46 "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", 47 data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[36]); 48 ssf_add_dict_string(d, "Transceiver codes", val_string); 49 50 /* 10G Ethernet Compliance Codes */ 51 if (data[3] & (1 << 7)) 52 ssf_add_dict_string(d, "10G Ethernet transceiver type", 53 "10G Ethernet: 10G Base-ER [SFF-8472 rev10.4 onwards]"); 54 if (data[3] & (1 << 6)) 55 ssf_add_dict_string(d, name, "10G Ethernet: 10G Base-LRM"); 56 if (data[3] & (1 << 5)) 57 ssf_add_dict_string(d, name, "10G Ethernet: 10G Base-LR"); 58 if (data[3] & (1 << 4)) 59 ssf_add_dict_string(d, name, "10G Ethernet: 10G Base-SR"); 60 61 /* Infiniband Compliance Codes */ 62 if (data[3] & (1 << 3)) 63 ssf_add_dict_string(d, name, "Infiniband: 1X SX"); 64 if (data[3] & (1 << 2)) 65 ssf_add_dict_string(d, name, "Infiniband: 1X LX"); 66 if (data[3] & (1 << 1)) 67 ssf_add_dict_string(d, name, "Infiniband: 1X Copper Active"); 68 if (data[3] & (1 << 0)) 69 ssf_add_dict_string(d, name, "Infiniband: 1X Copper Passive"); 70 71 /* ESCON Compliance Codes */ 72 if (data[4] & (1 << 7)) 73 ssf_add_dict_string(d, name, "ESCON: ESCON MMF, 1310nm LED"); 74 if (data[4] & (1 << 6)) 75 ssf_add_dict_string(d, name, "ESCON: ESCON SMF, 1310nm Laser"); 76 77 /* SONET Compliance Codes */ 78 if (data[4] & (1 << 5)) 79 ssf_add_dict_string(d, name, "SONET: OC-192, short reach"); 80 if (data[4] & (1 << 4)) 81 ssf_add_dict_string(d, name, "SONET: SONET reach specifier bit 1"); 82 if (data[4] & (1 << 3)) 83 ssf_add_dict_string(d, name, "SONET: SONET reach specifier bit 2"); 84 if (data[4] & (1 << 2)) 85 ssf_add_dict_string(d, name, "SONET: OC-48, long reach"); 86 if (data[4] & (1 << 1)) 87 ssf_add_dict_string(d, name, "SONET: OC-48, intermediate reach"); 88 if (data[4] & (1 << 0)) 89 ssf_add_dict_string(d, name, "SONET: OC-48, short reach"); 90 if (data[5] & (1 << 6)) 91 ssf_add_dict_string(d, name, "SONET: OC-12, single mode, long reach"); 92 if (data[5] & (1 << 5)) 93 ssf_add_dict_string(d, name, "SONET: OC-12, single mode, inter. reach"); 94 if (data[5] & (1 << 4)) 95 ssf_add_dict_string(d, name, "SONET: OC-12, short reach"); 96 if (data[5] & (1 << 2)) 97 ssf_add_dict_string(d, name, "SONET: OC-3, single mode, long reach"); 98 if (data[5] & (1 << 1)) 99 ssf_add_dict_string(d, name, "SONET: OC-3, single mode, inter. reach"); 100 if (data[5] & (1 << 0)) 101 ssf_add_dict_string(d, name, "SONET: OC-3, short reach"); 102 103 /* Ethernet Compliance Codes */ 104 if (data[6] & (1 << 7)) 105 ssf_add_dict_string(d, name, "Ethernet: BASE-PX"); 106 if (data[6] & (1 << 6)) 107 ssf_add_dict_string(d, name, "Ethernet: BASE-BX10"); 108 if (data[6] & (1 << 5)) 109 ssf_add_dict_string(d, name, "Ethernet: 100BASE-FX"); 110 if (data[6] & (1 << 4)) 111 ssf_add_dict_string(d, name, "Ethernet: 100BASE-LX/LX10"); 112 if (data[6] & (1 << 3)) 113 ssf_add_dict_string(d, name, "Ethernet: 1000BASE-T"); 114 if (data[6] & (1 << 2)) 115 ssf_add_dict_string(d, name, "Ethernet: 1000BASE-CX"); 116 if (data[6] & (1 << 1)) 117 ssf_add_dict_string(d, name, "Ethernet: 1000BASE-LX"); 118 if (data[6] & (1 << 0)) 119 ssf_add_dict_string(d, name, "Ethernet: 1000BASE-SX"); 120 121 /* Fibre Channel link length */ 122 if (data[7] & (1 << 7)) 123 ssf_add_dict_string(d, name, "FC: very long distance (V)"); 124 if (data[7] & (1 << 6)) 125 ssf_add_dict_string(d, name, "FC: short distance (S)"); 126 if (data[7] & (1 << 5)) 127 ssf_add_dict_string(d, name, "FC: intermediate distance (I)"); 128 if (data[7] & (1 << 4)) 129 ssf_add_dict_string(d, name, "FC: long distance (L)"); 130 if (data[7] & (1 << 3)) 131 ssf_add_dict_string(d, name, "FC: medium distance (M)"); 132 133 /* Fibre Channel transmitter technology */ 134 if (data[7] & (1 << 2)) 135 ssf_add_dict_string(d, name, "FC: Shortwave laser, linear Rx (SA)"); 136 if (data[7] & (1 << 1)) 137 ssf_add_dict_string(d, name, "FC: Longwave laser (LC)"); 138 if (data[7] & (1 << 0)) 139 ssf_add_dict_string(d, name, "FC: Electrical inter-enclosure (EL)"); 140 if (data[8] & (1 << 7)) 141 ssf_add_dict_string(d, name, "FC: Electrical intra-enclosure (EL)"); 142 if (data[8] & (1 << 6)) 143 ssf_add_dict_string(d, name, "FC: Shortwave laser w/o OFC (SN)"); 144 if (data[8] & (1 << 5)) 145 ssf_add_dict_string(d, name, "FC: Shortwave laser with OFC (SL)"); 146 if (data[8] & (1 << 4)) 147 ssf_add_dict_string(d, name, "FC: Longwave laser (LL)"); 148 if (data[8] & (1 << 3)) 149 ssf_add_dict_string(d, name, "Active Cable"); 150 if (data[8] & (1 << 2)) 151 ssf_add_dict_string(d, name, "Passive Cable"); 152 if (data[8] & (1 << 1)) 153 ssf_add_dict_string(d, name, "FC: Copper FC-BaseT"); 154 155 /* Fibre Channel transmission media */ 156 if (data[9] & (1 << 7)) 157 ssf_add_dict_string(d, name, "FC: Twin Axial Pair (TW)"); 158 if (data[9] & (1 << 6)) 159 ssf_add_dict_string(d, name, "FC: Twisted Pair (TP)"); 160 if (data[9] & (1 << 5)) 161 ssf_add_dict_string(d, name, "FC: Miniature Coax (MI)"); 162 if (data[9] & (1 << 4)) 163 ssf_add_dict_string(d, name, "FC: Video Coax (TV)"); 164 if (data[9] & (1 << 3)) 165 ssf_add_dict_string(d, name, "FC: Multimode, 62.5um (M6)"); 166 if (data[9] & (1 << 2)) 167 ssf_add_dict_string(d, name, "FC: Multimode, 50um (M5)"); 168 if (data[9] & (1 << 0)) 169 ssf_add_dict_string(d, name, "FC: Single Mode (SM)"); 170 171 /* Fibre Channel speed */ 172 if (data[10] & (1 << 7)) 173 ssf_add_dict_string(d, name, "FC: 1200 MBytes/sec"); 174 if (data[10] & (1 << 6)) 175 ssf_add_dict_string(d, name, "FC: 800 MBytes/sec"); 176 if (data[10] & (1 << 4)) 177 ssf_add_dict_string(d, name, "FC: 400 MBytes/sec"); 178 if (data[10] & (1 << 2)) 179 ssf_add_dict_string(d, name, "FC: 200 MBytes/sec"); 180 if (data[10] & (1 << 0)) 181 ssf_add_dict_string(d, name, "FC: 100 MBytes/sec"); 182 183 /* Extended Specification Compliance Codes from SFF-8024 */ 184 switch (data[36]) { 185 case 0x1: 186 ssf_add_dict_string(d, name, 187 "Extended: 100G AOC or 25GAUI C2M AOC with worst BER of 5x10^(-5)"); 188 break; 189 case 0x2: 190 ssf_add_dict_string(d, name, "Extended: 100G Base-SR4 or 25GBase-SR"); 191 break; 192 case 0x3: 193 ssf_add_dict_string(d, name, "Extended: 100G Base-LR4 or 25GBase-LR"); 194 break; 195 case 0x4: 196 ssf_add_dict_string(d, name, "Extended: 100G Base-ER4 or 25GBase-ER"); 197 break; 198 case 0x8: 199 ssf_add_dict_string(d, name, 200 "Extended: 100G ACC or 25GAUI C2M ACC with worst BER of 5x10^(-5)"); 201 break; 202 case 0xb: 203 ssf_add_dict_string(d, name, "Extended: 100G Base-CR4 or 25G Base-CR CA-L"); 204 break; 205 case 0xc: 206 ssf_add_dict_string(d, name, "Extended: 25G Base-CR CA-S"); 207 break; 208 case 0xd: 209 ssf_add_dict_string(d, name, "Extended: 25G Base-CR CA-N"); 210 break; 211 case 0x16: 212 ssf_add_dict_string(d, name, "Extended: 10Gbase-T with SFI electrical interface"); 213 break; 214 case 0x18: 215 ssf_add_dict_string(d, name, 216 "Extended: 100G AOC or 25GAUI C2M AOC with worst BER of 10^(-12)"); 217 break; 218 case 0x19: 219 ssf_add_dict_string(d, name, 220 "Extended: 100G ACC or 25GAUI C2M ACC with worst BER of 10^(-12)"); 221 break; 222 case 0x1c: 223 ssf_add_dict_string(d, name, "Extended: 10Gbase-T Short Reach"); 224 break; 225 default: 226 break; 227 } 228 } 229 230 static void sff_8079_show_encoding(const uint8_t *data, struct rte_tel_data *d) 231 { 232 sff_8024_show_encoding(data, 11, RTE_ETH_MODULE_SFF_8472, d); 233 } 234 235 static void sff_8079_show_rate_identifier(const uint8_t *data, struct rte_tel_data *d) 236 { 237 char val_string[SFF_ITEM_VAL_COMPOSE_SIZE]; 238 239 snprintf(val_string, sizeof(val_string), "0x%02x", data[13]); 240 241 switch (data[13]) { 242 case 0x00: 243 strlcat(val_string, " (unspecified)", sizeof(val_string)); 244 break; 245 case 0x01: 246 strlcat(val_string, " (4/2/1G Rate_Select & AS0/AS1)", sizeof(val_string)); 247 break; 248 case 0x02: 249 strlcat(val_string, " (8/4/2G Rx Rate_Select only)", sizeof(val_string)); 250 break; 251 case 0x03: 252 strlcat(val_string, " (8/4/2G Independent Rx & Tx Rate_Select)", 253 sizeof(val_string)); 254 break; 255 case 0x04: 256 strlcat(val_string, " (8/4/2G Tx Rate_Select only)", sizeof(val_string)); 257 break; 258 default: 259 strlcat(val_string, " (reserved or unknown)", sizeof(val_string)); 260 break; 261 } 262 ssf_add_dict_string(d, "Rate identifier", val_string); 263 } 264 265 static void sff_8079_show_oui(const uint8_t *data, struct rte_tel_data *d) 266 { 267 sff_8024_show_oui(data, 37, d); 268 } 269 270 static void 271 sff_8079_show_wavelength_or_copper_compliance(const uint8_t *data, 272 struct rte_tel_data *d) 273 { 274 char val_string[SFF_ITEM_VAL_COMPOSE_SIZE]; 275 276 if (data[8] & (1 << 2)) { 277 snprintf(val_string, sizeof(val_string), "0x%02x", data[60]); 278 switch (data[60]) { 279 case 0x00: 280 strlcat(val_string, " (unspecified)", sizeof(val_string)); 281 break; 282 case 0x01: 283 strlcat(val_string, " (SFF-8431 appendix E)", sizeof(val_string)); 284 break; 285 default: 286 strlcat(val_string, " (unknown)", sizeof(val_string)); 287 break; 288 } 289 strlcat(val_string, " [SFF-8472 rev10.4 only]", sizeof(val_string)); 290 ssf_add_dict_string(d, "Passive Cu cmplnce.", val_string); 291 } else if (data[8] & (1 << 3)) { 292 snprintf(val_string, sizeof(val_string), "0x%02x", data[60]); 293 switch (data[60]) { 294 case 0x00: 295 strlcat(val_string, " (unspecified)", sizeof(val_string)); 296 break; 297 case 0x01: 298 strlcat(val_string, " (SFF-8431 appendix E)", sizeof(val_string)); 299 break; 300 case 0x04: 301 strlcat(val_string, " (SFF-8431 limiting)", sizeof(val_string)); 302 break; 303 default: 304 strlcat(val_string, " (unknown)", sizeof(val_string)); 305 break; 306 } 307 strlcat(val_string, " [SFF-8472 rev10.4 only]", sizeof(val_string)); 308 ssf_add_dict_string(d, "Active Cu cmplnce.", val_string); 309 } else { 310 snprintf(val_string, sizeof(val_string), "%unm", (data[60] << 8) | data[61]); 311 ssf_add_dict_string(d, "Laser wavelength", val_string); 312 } 313 } 314 315 static void sff_8079_show_options(const uint8_t *data, struct rte_tel_data *d) 316 { 317 static const char *name = "Option"; 318 char val_string[SFF_ITEM_VAL_COMPOSE_SIZE]; 319 320 snprintf(val_string, sizeof(val_string), "0x%02x 0x%02x", data[64], data[65]); 321 ssf_add_dict_string(d, "Option values", val_string); 322 323 if (data[65] & (1 << 1)) 324 ssf_add_dict_string(d, name, "RX_LOS implemented"); 325 if (data[65] & (1 << 2)) 326 ssf_add_dict_string(d, name, "RX_LOS implemented, inverted"); 327 if (data[65] & (1 << 3)) 328 ssf_add_dict_string(d, name, "TX_FAULT implemented"); 329 if (data[65] & (1 << 4)) 330 ssf_add_dict_string(d, name, "TX_DISABLE implemented"); 331 if (data[65] & (1 << 5)) 332 ssf_add_dict_string(d, name, "RATE_SELECT implemented"); 333 if (data[65] & (1 << 6)) 334 ssf_add_dict_string(d, name, "Tunable transmitter technology"); 335 if (data[65] & (1 << 7)) 336 ssf_add_dict_string(d, name, "Receiver decision threshold implemented"); 337 if (data[64] & (1 << 0)) 338 ssf_add_dict_string(d, name, "Linear receiver output implemented"); 339 if (data[64] & (1 << 1)) 340 ssf_add_dict_string(d, name, "Power level 2 requirement"); 341 if (data[64] & (1 << 2)) 342 ssf_add_dict_string(d, name, "Cooled transceiver implemented"); 343 if (data[64] & (1 << 3)) 344 ssf_add_dict_string(d, name, "Retimer or CDR implemented"); 345 if (data[64] & (1 << 4)) 346 ssf_add_dict_string(d, name, "Paging implemented"); 347 if (data[64] & (1 << 5)) 348 ssf_add_dict_string(d, name, "Power level 3 requirement"); 349 } 350 351 void sff_8079_show_all(const uint8_t *data, struct rte_tel_data *d) 352 { 353 sff_8079_show_identifier(data, d); 354 if (((data[0] == 0x02) || (data[0] == 0x03)) && (data[1] == 0x04)) { 355 unsigned int br_nom, br_min, br_max; 356 char val_string[SFF_ITEM_VAL_COMPOSE_SIZE]; 357 358 if (data[12] == 0) { 359 br_nom = br_min = br_max = 0; 360 } else if (data[12] == 255) { 361 br_nom = data[66] * 250; 362 br_max = data[67]; 363 br_min = data[67]; 364 } else { 365 br_nom = data[12] * 100; 366 br_max = data[66]; 367 br_min = data[67]; 368 } 369 sff_8079_show_ext_identifier(data, d); 370 sff_8079_show_connector(data, d); 371 sff_8079_show_transceiver(data, d); 372 sff_8079_show_encoding(data, d); 373 374 snprintf(val_string, sizeof(val_string), "%uMBd", br_nom); 375 ssf_add_dict_string(d, "BR, Nominal", val_string); 376 377 sff_8079_show_rate_identifier(data, d); 378 sff_show_value_with_unit(data, 14, 379 "Length (SMF,km)", 1, "km", d); 380 sff_show_value_with_unit(data, 15, "Length (SMF)", 100, "m", d); 381 sff_show_value_with_unit(data, 16, "Length (50um)", 10, "m", d); 382 sff_show_value_with_unit(data, 17, 383 "Length (62.5um)", 10, "m", d); 384 sff_show_value_with_unit(data, 18, "Length (Copper)", 1, "m", d); 385 sff_show_value_with_unit(data, 19, "Length (OM3)", 10, "m", d); 386 sff_8079_show_wavelength_or_copper_compliance(data, d); 387 sff_show_ascii(data, 20, 35, "Vendor name", d); 388 sff_8079_show_oui(data, d); 389 sff_show_ascii(data, 40, 55, "Vendor PN", d); 390 sff_show_ascii(data, 56, 59, "Vendor rev", d); 391 sff_8079_show_options(data, d); 392 393 snprintf(val_string, sizeof(val_string), "%u%%", br_max); 394 ssf_add_dict_string(d, "BR margin, max", val_string); 395 snprintf(val_string, sizeof(val_string), "%u%%", br_min); 396 ssf_add_dict_string(d, "BR margin, min", val_string); 397 398 sff_show_ascii(data, 68, 83, "Vendor SN", d); 399 sff_show_ascii(data, 84, 91, "Date code", d); 400 } 401 } 402