1 /* $OpenBSD: sff.c,v 1.23 2019/10/24 18:54:10 bluhm Exp $ */ 2 3 /* 4 * Copyright (c) 2019 David Gwynne <dlg@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #ifndef SMALL 20 21 #include <sys/ioctl.h> 22 23 #include <net/if.h> 24 25 #include <math.h> 26 #include <ctype.h> 27 #include <err.h> 28 #include <errno.h> 29 #include <stdio.h> 30 #include <stdint.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 #include <limits.h> 35 #include <vis.h> 36 37 #include "ifconfig.h" 38 39 #ifndef nitems 40 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 41 #endif 42 43 #ifndef ISSET 44 #define ISSET(_w, _m) ((_w) & (_m)) 45 #endif 46 47 #define SFF_THRESH_HI_ALARM 0 48 #define SFF_THRESH_LO_ALARM 1 49 #define SFF_THRESH_HI_WARN 2 50 #define SFF_THRESH_LO_WARN 3 51 #define SFF_THRESH_COUNT 4 52 53 #define SFF_THRESH_REG(_i) ((_i) * 2) 54 55 struct sff_thresholds { 56 float thresholds[SFF_THRESH_COUNT]; 57 }; 58 59 struct sff_media_map { 60 float factor_wavelength; 61 int scale_om1; 62 int scale_om2; 63 int scale_om3; 64 uint8_t connector_type; 65 uint8_t wavelength; 66 uint8_t dist_smf_m; 67 uint8_t dist_smf_km; 68 uint8_t dist_om1; 69 uint8_t dist_om2; 70 uint8_t dist_om3; 71 uint8_t dist_cu; 72 }; 73 74 #define SFF8024_ID_UNKNOWN 0x00 75 #define SFF8024_ID_GBIC 0x01 76 #define SFF8024_ID_MOBO 0x02 /* Module/connector soldered to mobo */ 77 /* using SFF-8472 */ 78 #define SFF8024_ID_SFP 0x03 /* SFP/SFP+/SFP28 */ 79 #define SFF8024_ID_300PIN_XBI 0x04 /* 300 pin XBI */ 80 #define SFF8024_ID_XENPAK 0x05 81 #define SFF8024_ID_XFP 0x06 82 #define SFF8024_ID_XFF 0x07 83 #define SFF8024_ID_XFPE 0x08 /* XFP-E */ 84 #define SFF8024_ID_XPAK 0x09 85 #define SFF8024_ID_X2 0x0a 86 #define SFF8024_ID_DWDM_SFP 0x0b /* DWDM-SFP/SFP+ */ 87 /* not using SFF-8472 */ 88 #define SFF8024_ID_QSFP 0x0c 89 #define SFF8024_ID_QSFP_PLUS 0x0d /* or later */ 90 /* using SFF-8436/8665/8685 et al */ 91 #define SFF8024_ID_CXP 0x0e /* or later */ 92 #define SFF8024_ID_HD4X 0x0f /* shielded mini multilane HD 4X */ 93 #define SFF8024_ID_HD8X 0x10 /* shielded mini multilane HD 8X */ 94 #define SFF8024_ID_QSFP28 0x11 /* or later */ 95 /* using SFF-8665 et al */ 96 #define SFF8024_ID_CXP2 0x12 /* aka CXP28, or later */ 97 #define SFF8024_ID_CDFP 0x13 /* style 1/style 2 */ 98 #define SFF8024_ID_HD4X_FAN 0x14 /* shielded mini multilane HD 4X fanout */ 99 #define SFF8024_ID_HD8X_FAN 0x15 /* shielded mini multilane HD 8X fanout */ 100 #define SFF8024_ID_CDFP3 0x16 /* style 3 */ 101 #define SFF8024_ID_uQSFP 0x17 /* microQSFP */ 102 #define SFF8024_ID_QSFP_DD 0x18 /* QSFP-DD double density 8x */ 103 /* INF-8628 */ 104 #define SFF8024_ID_RESERVED 0x7f /* up to here is reserved */ 105 /* 0x80 to 0xff is vendor specific */ 106 107 #define SFF8024_ID_IS_RESERVED(_id) ((_id) <= SFF8024_ID_RESERVED) 108 #define SFF8024_ID_IS_VENDOR(_id) ((_id) > SFF8024_ID_RESERVED) 109 110 #define SFF8024_CON_UNKNOWN 0x00 111 #define SFF8024_CON_SC 0x01 /* Subscriber Connector */ 112 #define SFF8024_CON_FC_1 0x02 /* Fibre Channel Style 1 copper */ 113 #define SFF8024_CON_FC_2 0x03 /* Fibre Channel Style 2 copper */ 114 #define SFF8024_CON_BNC_TNC 0x04 /* BNC/TNC */ 115 #define SFF8024_CON_FC_COAX 0x05 /* Fibre Channel coax headers */ 116 #define SFF8024_CON_FJ 0x06 /* Fibre Jack */ 117 #define SFF8024_CON_LC 0x07 /* Lucent Connector */ 118 #define SFF8024_CON_MT_RJ 0x08 /* Mechanical Transfer - Registered Jack */ 119 #define SFF8024_CON_MU 0x09 /* Multiple Optical */ 120 #define SFF8024_CON_SG 0x0a 121 #define SFF8024_CON_O_PIGTAIL 0x0b /* Optical Pigtail */ 122 #define SFF8024_CON_MPO_1x12 0x0c /* Multifiber Parallel Optic 1x12 */ 123 #define SFF8024_CON_MPO_2x16 0x0e /* Multifiber Parallel Optic 2x16 */ 124 #define SFF8024_CON_HSSDC2 0x20 /* High Speed Serial Data Connector */ 125 #define SFF8024_CON_Cu_PIGTAIL 0x21 /* Copper Pigtail */ 126 #define SFF8024_CON_RJ45 0x22 127 #define SFF8024_CON_NO 0x23 /* No separable connector */ 128 #define SFF8024_CON_MXC_2x16 0x24 129 #define SFF8024_CON_RESERVED 0x7f /* up to here is reserved */ 130 /* 0x80 to 0xff is vendor specific */ 131 132 #define SFF8024_CON_IS_RESERVED(_id) ((_id) <= SFF8024_CON_RESERVED) 133 #define SFF8024_CON_IS_VENDOR(_id) ((_id) > SFF8024_CON_RESERVED) 134 135 static const char *sff8024_id_names[] = { 136 [SFF8024_ID_UNKNOWN] = "Unknown", 137 [SFF8024_ID_GBIC] = "GBIC", 138 [SFF8024_ID_SFP] = "SFP", 139 [SFF8024_ID_300PIN_XBI] = "XBI", 140 [SFF8024_ID_XENPAK] = "XENPAK", 141 [SFF8024_ID_XFP] = "XFP", 142 [SFF8024_ID_XFF] = "XFF", 143 [SFF8024_ID_XFPE] = "XFPE", 144 [SFF8024_ID_XPAK] = "XPAK", 145 [SFF8024_ID_X2] = "X2", 146 [SFF8024_ID_DWDM_SFP] = "DWDM-SFP", 147 [SFF8024_ID_QSFP] = "QSFP", 148 [SFF8024_ID_QSFP_PLUS] = "QSFP+", 149 [SFF8024_ID_CXP] = "CXP", 150 [SFF8024_ID_HD4X] = "HD 4X", 151 [SFF8024_ID_HD8X] = "HD 8X", 152 [SFF8024_ID_QSFP28] = "QSFP28", 153 [SFF8024_ID_CXP2] = "CXP2", 154 [SFF8024_ID_CDFP] = "CDFP Style 1/2", 155 [SFF8024_ID_HD4X_FAN] = "HD 4X Fanout", 156 [SFF8024_ID_HD8X_FAN] = "HD 8X Fanout", 157 [SFF8024_ID_CDFP3] = "CDFP Style 3", 158 [SFF8024_ID_uQSFP] = "microQSFP", 159 [SFF8024_ID_QSFP_DD] = "QSFP-DD", 160 }; 161 162 static const char *sff8024_con_names[] = { 163 [SFF8024_CON_UNKNOWN] = "Unknown", 164 [SFF8024_CON_SC] = "SC", 165 [SFF8024_CON_FC_1] = "FC Style 1", 166 [SFF8024_CON_FC_2] = "FC Style 2", 167 [SFF8024_CON_BNC_TNC] = "BNC/TNC", 168 [SFF8024_CON_FC_COAX] = "FC coax headers", 169 [SFF8024_CON_FJ] = "FJ", 170 [SFF8024_CON_LC] = "LC", 171 [SFF8024_CON_MT_RJ] = "MT-RJ", 172 [SFF8024_CON_MU] = "MU", 173 [SFF8024_CON_SG] = "SG", 174 [SFF8024_CON_O_PIGTAIL] = "AOC", 175 [SFF8024_CON_MPO_1x12] = "MPO 1x12", 176 [SFF8024_CON_MPO_2x16] = "MPO 2x16", 177 [SFF8024_CON_HSSDC2] = "HSSDC II", 178 [SFF8024_CON_Cu_PIGTAIL] 179 = "DAC", 180 [SFF8024_CON_RJ45] = "RJ45", 181 [SFF8024_CON_NO] = "No connector", 182 [SFF8024_CON_MXC_2x16] = "MXC 2x16", 183 }; 184 185 #define SFF8472_ID 0 /* SFF8027 for identifier values */ 186 #define SFF8472_EXT_ID 1 187 #define SFF8472_EXT_ID_UNSPECIFIED 0x00 188 #define SFF8472_EXT_ID_MOD_DEF_1 0x01 189 #define SFF8472_EXT_ID_MOD_DEF_2 0x02 190 #define SFF8472_EXT_ID_MOD_DEF_3 0x03 191 #define SFF8472_EXT_ID_2WIRE 0x04 192 #define SFF8472_EXT_ID_MOD_DEF_5 0x05 193 #define SFF8472_EXT_ID_MOD_DEF_6 0x06 194 #define SFF8472_EXT_ID_MOD_DEF_7 0x07 195 #define SFF8472_CON 2 /* SFF8027 for connector values */ 196 #define SFF8472_DIST_SMF_KM 14 197 #define SFF8472_DIST_SMF_M 15 198 #define SFF8472_DIST_OM2 16 199 #define SFF8472_DIST_OM1 17 200 #define SFF8472_DIST_CU 18 201 #define SFF8472_DIST_OM3 19 202 #define SFF8472_VENDOR_START 20 203 #define SFF8472_VENDOR_END 35 204 #define SFF8472_PRODUCT_START 40 205 #define SFF8472_PRODUCT_END 55 206 #define SFF8472_REVISION_START 56 207 #define SFF8472_REVISION_END 59 208 #define SFF8472_WAVELENGTH 60 209 #define SFF8472_SERIAL_START 68 210 #define SFF8472_SERIAL_END 83 211 #define SFF8472_DATECODE 84 212 #define SFF8472_DDM_TYPE 92 213 #define SFF8472_DDM_TYPE_AVG_POWER (1U << 3) 214 #define SFF8472_DDM_TYPE_CAL_EXT (1U << 4) 215 #define SFF8472_DDM_TYPE_CAL_INT (1U << 5) 216 #define SFF8472_DDM_TYPE_IMPL (1U << 6) 217 #define SFF8472_COMPLIANCE 94 218 #define SFF8472_COMPLIANCE_NONE 0x00 219 #define SFF8472_COMPLIANCE_9_3 0x01 /* SFF-8472 Rev 9.3 */ 220 #define SFF8472_COMPLIANCE_9_5 0x02 /* SFF-8472 Rev 9.5 */ 221 #define SFF8472_COMPLIANCE_10_2 0x03 /* SFF-8472 Rev 10.2 */ 222 #define SFF8472_COMPLIANCE_10_4 0x04 /* SFF-8472 Rev 10.4 */ 223 #define SFF8472_COMPLIANCE_11_0 0x05 /* SFF-8472 Rev 11.0 */ 224 #define SFF8472_COMPLIANCE_11_3 0x06 /* SFF-8472 Rev 11.3 */ 225 #define SFF8472_COMPLIANCE_11_4 0x07 /* SFF-8472 Rev 11.4 */ 226 #define SFF8472_COMPLIANCE_12_3 0x08 /* SFF-8472 Rev 12.3 */ 227 228 static const struct sff_media_map sff8472_media_map = { 229 .connector_type = SFF8472_CON, 230 .wavelength = SFF8472_WAVELENGTH, 231 .factor_wavelength = 1.0, 232 .dist_smf_m = SFF8472_DIST_SMF_M, 233 .dist_smf_km = SFF8472_DIST_SMF_KM, 234 .dist_om1 = SFF8472_DIST_OM1, 235 .scale_om1 = 10, 236 .dist_om2 = SFF8472_DIST_OM2, 237 .scale_om2 = 10, 238 .dist_om3 = SFF8472_DIST_OM3, 239 .scale_om3 = 20, 240 .dist_cu = SFF8472_DIST_CU, 241 }; 242 243 /* 244 * page 0xa2 245 */ 246 #define SFF8472_AW_TEMP 0 247 #define SFF8472_AW_VCC 8 248 #define SFF8472_AW_TX_BIAS 16 249 #define SFF8472_AW_TX_POWER 24 250 #define SFF8472_AW_RX_POWER 32 251 #define ALRM_HIGH 0 252 #define ALRM_LOW 2 253 #define WARN_HIGH 4 254 #define WARN_LOW 6 255 #define SFF8472_DDM_TEMP 96 256 #define SFF8472_DDM_VCC 98 257 #define SFF8472_DDM_TX_BIAS 100 258 #define SFF8472_DDM_TX_POWER 102 259 #define SFF8472_DDM_RX_POWER 104 260 #define SFF8472_DDM_LASER 106 /* laser temp/wavelength */ 261 /* optional */ 262 #define SFF8472_DDM_TEC 108 /* Measured TEC current */ 263 /* optional */ 264 265 #define SFF_TEMP_FACTOR 256.0 266 #define SFF_VCC_FACTOR 10000.0 267 #define SFF_BIAS_FACTOR 500.0 268 #define SFF_POWER_FACTOR 10000.0 269 270 /* 271 * QSFP is defined by SFF-8436, but the management interface is 272 * updated and maintained by SFF-8636. 273 */ 274 275 #define SFF8436_STATUS1 1 276 #define SFF8436_STATUS2 2 277 #define SFF8436_STATUS2_DNR (1 << 0) /* Data_Not_Ready */ 278 #define SFF8436_STATUS2_INTL (1 << 1) /* Interrupt output state */ 279 #define SFF8436_STATUS2_FLAT_MEM (1 << 2) /* Upper memory flat/paged */ 280 281 #define SFF8436_TEMP 22 282 #define SFF8436_VCC 26 283 284 #define SFF8436_CHANNELS 4 /* number of TX and RX channels */ 285 #define SFF8436_RX_POWER_BASE 34 286 #define SFF8436_RX_POWER(_i) (SFF8436_RX_POWER_BASE + ((_i) * 2)) 287 #define SFF8436_TX_BIAS_BASE 42 288 #define SFF8436_TX_BIAS(_i) (SFF8436_TX_BIAS_BASE + ((_i) * 2)) 289 #define SFF8436_TX_POWER_BASE 50 290 #define SFF8436_TX_POWER(_i) (SFF8436_TX_POWER_BASE + ((_i) * 2)) 291 292 /* Upper Page 00h */ 293 294 #define SFF8436_MAXCASETEMP 190 /* C */ 295 #define SFF8436_MAXCASETEMP_DEFAULT 70 /* if SFF8436_MAXCASETEMP is 0 */ 296 297 /* Upper page 03h */ 298 299 #define SFF8436_AW_TEMP 128 300 #define SFF8436_AW_VCC 144 301 #define SFF8436_AW_RX_POWER 176 302 #define SFF8436_AW_TX_BIAS 184 303 #define SFF8436_AW_TX_POWER 192 304 305 /* 306 * XFP stuff is defined by INF-8077. 307 * 308 * The "Serial ID Memory Map" on page 1 contains the interesting strings 309 */ 310 311 /* SFF-8636 and INF-8077 share a layout for various strings */ 312 313 #define UPPER_CON 130 /* connector type */ 314 #define UPPER_DIST_SMF 142 315 #define UPPER_DIST_OM3 143 316 #define UPPER_DIST_OM2 144 317 #define UPPER_DIST_OM1 145 318 #define UPPER_DIST_CU 146 319 #define UPPER_WAVELENGTH 186 320 321 #define UPPER_VENDOR_START 148 322 #define UPPER_VENDOR_END 163 323 #define UPPER_PRODUCT_START 168 324 #define UPPER_PRODUCT_END 183 325 #define UPPER_REVISION_START 184 326 #define UPPER_REVISION_END 185 327 #define UPPER_SERIAL_START 196 328 #define UPPER_SERIAL_END 211 329 #define UPPER_DATECODE 212 330 #define UPPER_LOT_START 218 331 #define UPPER_LOT_END 219 332 333 static const struct sff_media_map upper_media_map = { 334 .connector_type = UPPER_CON, 335 .wavelength = UPPER_WAVELENGTH, 336 .factor_wavelength = 20.0, 337 .dist_smf_m = 0, 338 .dist_smf_km = UPPER_DIST_SMF, 339 .dist_om1 = UPPER_DIST_OM1, 340 .scale_om1 = 1, 341 .dist_om2 = UPPER_DIST_OM1, 342 .scale_om2 = 1, 343 .dist_om3 = UPPER_DIST_OM3, 344 .scale_om3 = 2, 345 .dist_cu = UPPER_DIST_CU, 346 }; 347 348 static void hexdump(const void *, size_t); 349 static int if_sff8472(int, const struct if_sffpage *); 350 static int if_sff8636(int, const struct if_sffpage *); 351 static int if_inf8077(int, const struct if_sffpage *); 352 353 static const char * 354 sff_id_name(uint8_t id) 355 { 356 const char *name = NULL; 357 358 if (id < nitems(sff8024_id_names)) { 359 name = sff8024_id_names[id]; 360 if (name != NULL) 361 return (name); 362 } 363 364 if (SFF8024_ID_IS_VENDOR(id)) 365 return ("Vendor Specific"); 366 367 return ("Reserved"); 368 } 369 370 static const char * 371 sff_con_name(uint8_t id) 372 { 373 const char *name = NULL; 374 375 if (id < nitems(sff8024_con_names)) { 376 name = sff8024_con_names[id]; 377 if (name != NULL) 378 return (name); 379 } 380 381 if (SFF8024_CON_IS_VENDOR(id)) 382 return ("Vendor Specific"); 383 384 return ("Reserved"); 385 } 386 387 static void 388 if_sffpage_init(struct if_sffpage *sff, uint8_t addr, uint8_t page) 389 { 390 memset(sff, 0, sizeof(*sff)); 391 392 if (strlcpy(sff->sff_ifname, ifname, sizeof(sff->sff_ifname)) >= 393 sizeof(sff->sff_ifname)) 394 errx(1, "interface name too long"); 395 396 sff->sff_addr = addr; 397 sff->sff_page = page; 398 } 399 400 static void 401 if_sffpage_dump(const struct if_sffpage *sff) 402 { 403 printf("%s: addr %02x", ifname, sff->sff_addr); 404 if (sff->sff_addr == IFSFF_ADDR_EEPROM) 405 printf(" page %u", sff->sff_page); 406 putchar('\n'); 407 hexdump(sff->sff_data, sizeof(sff->sff_data)); 408 } 409 410 int 411 if_sff_info(int dump) 412 { 413 struct if_sffpage pg0; 414 int error = 0; 415 uint8_t id, ext_id; 416 417 if_sffpage_init(&pg0, IFSFF_ADDR_EEPROM, 0); 418 if (ioctl(sock, SIOCGIFSFFPAGE, (caddr_t)&pg0) == -1) { 419 if (errno == ENXIO) { 420 /* try 1 for XFP cos myx which can't switch pages... */ 421 if_sffpage_init(&pg0, IFSFF_ADDR_EEPROM, 1); 422 if (ioctl(sock, SIOCGIFSFFPAGE, (caddr_t)&pg0) == -1) 423 return (-1); 424 } else 425 return (-1); 426 } 427 428 if (dump) 429 if_sffpage_dump(&pg0); 430 431 id = pg0.sff_data[0]; /* SFF8472_ID */ 432 433 printf("\ttransceiver: %s ", sff_id_name(id)); 434 switch (id) { 435 case SFF8024_ID_SFP: 436 ext_id = pg0.sff_data[SFF8472_EXT_ID]; 437 if (ext_id != SFF8472_EXT_ID_2WIRE) { 438 printf("extended-id %02xh\n", ext_id); 439 break; 440 } 441 /* FALLTHROUGH */ 442 case SFF8024_ID_GBIC: 443 error = if_sff8472(dump, &pg0); 444 break; 445 case SFF8024_ID_XFP: 446 if (pg0.sff_page != 1) { 447 if_sffpage_init(&pg0, IFSFF_ADDR_EEPROM, 1); 448 if (ioctl(sock, SIOCGIFSFFPAGE, (caddr_t)&pg0) == -1) 449 return (-1); 450 if (dump) 451 if_sffpage_dump(&pg0); 452 } 453 error = if_inf8077(dump, &pg0); 454 break; 455 case SFF8024_ID_QSFP: 456 case SFF8024_ID_QSFP_PLUS: 457 case SFF8024_ID_QSFP28: 458 error = if_sff8636(dump, &pg0); 459 break; 460 default: 461 printf("\n"); 462 break; 463 } 464 465 return (error); 466 } 467 468 static void 469 if_sff_ascii_print(const struct if_sffpage *sff, const char *name, 470 size_t start, size_t end, const char *trailer) 471 { 472 const uint8_t *d = sff->sff_data; 473 int ch; 474 475 for (;;) { 476 ch = d[start]; 477 if (!isspace(ch) && ch != '\0') 478 break; 479 480 start++; 481 if (start == end) 482 return; 483 } 484 485 printf("%s", name); 486 487 for (;;) { 488 ch = d[end]; 489 if (!isspace(ch) && ch != '\0') 490 break; 491 492 end--; 493 } 494 495 do { 496 char dst[8]; 497 vis(dst, d[start], VIS_TAB | VIS_NL, 0); 498 printf("%s", dst); 499 } while (++start <= end); 500 501 printf("%s", trailer); 502 } 503 504 static void 505 if_sff_date_print(const struct if_sffpage *sff, const char *name, 506 size_t start, const char *trailer) 507 { 508 const uint8_t *d = sff->sff_data + start; 509 size_t i; 510 511 /* YYMMDD */ 512 for (i = 0; i < 6; i++) { 513 if (!isdigit(d[i])) { 514 if_sff_ascii_print(sff, name, start, 515 start + 5, trailer); 516 return; 517 } 518 } 519 520 printf("%s20%c%c-%c%c-%c%c%s", name, 521 d[0], d[1], d[2], d[3], d[4], d[5], trailer); 522 } 523 524 static int16_t 525 if_sff_int(const struct if_sffpage *sff, size_t start) 526 { 527 const uint8_t *d = sff->sff_data + start; 528 529 return (d[0] << 8 | d[1]); 530 } 531 532 static uint16_t 533 if_sff_uint(const struct if_sffpage *sff, size_t start) 534 { 535 const uint8_t *d = sff->sff_data + start; 536 537 return (d[0] << 8 | d[1]); 538 } 539 540 static float 541 if_sff_power2dbm(const struct if_sffpage *sff, size_t start) 542 { 543 const uint8_t *d = sff->sff_data + start; 544 545 int power = d[0] << 8 | d[1]; 546 return (10.0 * log10f((float)power / 10000.0)); 547 } 548 549 static void 550 if_sff_printalarm(const char *unit, int range, float actual, 551 float alrm_high, float alrm_low, float warn_high, float warn_log) 552 { 553 printf("%.02f%s", actual, unit); 554 if (range == 1) 555 printf(" (low %.02f%s, high %.02f%s)", alrm_low, 556 unit, alrm_high, unit); 557 558 if(actual > alrm_high || actual < alrm_low) 559 printf(" [ALARM]"); 560 else if(actual > warn_high || actual < warn_log) 561 printf(" [WARNING]"); 562 } 563 564 static void 565 if_sff_printdist(const char *type, int value, int scale) 566 { 567 int distance = value * scale; 568 569 if (value == 0) 570 return; 571 572 if (distance < 10000) 573 printf (", %s%u%s", value > 254 ? ">" : "", distance, type); 574 else 575 printf (", %s%0.1fk%s", value > 254 ? ">" : "", 576 distance / 1000.0, type); 577 } 578 579 static void 580 if_sff_printmedia(const struct if_sffpage *pg, const struct sff_media_map *m) 581 { 582 uint8_t con; 583 unsigned int wavelength; 584 585 con = pg->sff_data[m->connector_type]; 586 printf("%s", sff_con_name(con)); 587 588 wavelength = if_sff_uint(pg, m->wavelength); 589 switch (wavelength) { 590 case 0x0000: 591 /* not known or is unavailable */ 592 break; 593 /* Copper Cable */ 594 case 0x0100: /* SFF-8431 Appendix E */ 595 case 0x0400: /* SFF-8431 limiting */ 596 case 0x0c00: /* SFF-8431 limiting and FC-PI-4 limiting */ 597 break; 598 default: 599 printf(", %.f nm", wavelength / m->factor_wavelength); 600 } 601 602 if (m->dist_smf_m != 0 && 603 pg->sff_data[m->dist_smf_m] > 0 && 604 pg->sff_data[m->dist_smf_m] < 255) 605 if_sff_printdist("m SMF", pg->sff_data[m->dist_smf_m], 100); 606 else 607 if_sff_printdist("km SMF", pg->sff_data[m->dist_smf_km], 1); 608 if_sff_printdist("m OM1", pg->sff_data[m->dist_om1], m->scale_om1); 609 if_sff_printdist("m OM2", pg->sff_data[m->dist_om2], m->scale_om2); 610 if_sff_printdist("m OM3", pg->sff_data[m->dist_om3], m->scale_om3); 611 if_sff_printdist("m", pg->sff_data[m->dist_cu], 1); 612 } 613 614 static int 615 if_sff8472(int dump, const struct if_sffpage *pg0) 616 { 617 struct if_sffpage ddm; 618 uint8_t ddm_types; 619 620 if_sff_printmedia(pg0, &sff8472_media_map); 621 622 printf("\n\tmodel: "); 623 if_sff_ascii_print(pg0, "", 624 SFF8472_VENDOR_START, SFF8472_VENDOR_END, " "); 625 if_sff_ascii_print(pg0, "", 626 SFF8472_PRODUCT_START, SFF8472_PRODUCT_END, ""); 627 if_sff_ascii_print(pg0, " rev ", 628 SFF8472_REVISION_START, SFF8472_REVISION_END, ""); 629 630 if_sff_ascii_print(pg0, "\n\tserial: ", 631 SFF8472_SERIAL_START, SFF8472_SERIAL_END, ", "); 632 if_sff_date_print(pg0, "date: ", SFF8472_DATECODE, "\n"); 633 634 ddm_types = pg0->sff_data[SFF8472_DDM_TYPE]; 635 if (pg0->sff_data[SFF8472_COMPLIANCE] == SFF8472_COMPLIANCE_NONE || 636 !ISSET(ddm_types, SFF8472_DDM_TYPE_IMPL)) 637 return (0); 638 639 if_sffpage_init(&ddm, IFSFF_ADDR_DDM, 0); 640 if (ioctl(sock, SIOCGIFSFFPAGE, (caddr_t)&ddm) == -1) 641 return (-1); 642 643 if (dump) 644 if_sffpage_dump(&ddm); 645 646 if (ISSET(ddm_types, SFF8472_DDM_TYPE_CAL_EXT)) { 647 printf("\tcalibration: external " 648 "(WARNING: needs more code)\n"); 649 } 650 651 printf("\tvoltage: "); 652 if_sff_printalarm(" V", 0, 653 if_sff_uint(&ddm, SFF8472_DDM_VCC) / SFF_VCC_FACTOR, 654 if_sff_uint(&ddm, SFF8472_AW_VCC + ALRM_HIGH) / SFF_VCC_FACTOR, 655 if_sff_uint(&ddm, SFF8472_AW_VCC + ALRM_LOW) / SFF_VCC_FACTOR, 656 if_sff_uint(&ddm, SFF8472_AW_VCC + WARN_HIGH) / SFF_VCC_FACTOR, 657 if_sff_uint(&ddm, SFF8472_AW_VCC + WARN_LOW) / SFF_VCC_FACTOR); 658 659 printf(", bias current: "); 660 if_sff_printalarm(" mA", 0, 661 if_sff_uint(&ddm, SFF8472_DDM_TX_BIAS) / SFF_BIAS_FACTOR, 662 if_sff_uint(&ddm, SFF8472_AW_TX_BIAS + ALRM_HIGH) / SFF_BIAS_FACTOR, 663 if_sff_uint(&ddm, SFF8472_AW_TX_BIAS + ALRM_LOW) / SFF_BIAS_FACTOR, 664 if_sff_uint(&ddm, SFF8472_AW_TX_BIAS + WARN_HIGH) / SFF_BIAS_FACTOR, 665 if_sff_uint(&ddm, SFF8472_AW_TX_BIAS + WARN_LOW) / SFF_BIAS_FACTOR); 666 667 printf("\n\ttemp: "); 668 if_sff_printalarm(" C", 1, 669 if_sff_int(&ddm, SFF8472_DDM_TEMP) / SFF_TEMP_FACTOR, 670 if_sff_int(&ddm, SFF8472_AW_TEMP + ALRM_HIGH) / SFF_TEMP_FACTOR, 671 if_sff_int(&ddm, SFF8472_AW_TEMP + ALRM_LOW) / SFF_TEMP_FACTOR, 672 if_sff_int(&ddm, SFF8472_AW_TEMP + WARN_HIGH) / SFF_TEMP_FACTOR, 673 if_sff_int(&ddm, SFF8472_AW_TEMP + WARN_LOW) / SFF_TEMP_FACTOR); 674 675 printf("\n\ttx: "); 676 if_sff_printalarm(" dBm", 1, 677 if_sff_power2dbm(&ddm, SFF8472_DDM_TX_POWER), 678 if_sff_power2dbm(&ddm, SFF8472_AW_TX_POWER + ALRM_HIGH), 679 if_sff_power2dbm(&ddm, SFF8472_AW_TX_POWER + ALRM_LOW), 680 if_sff_power2dbm(&ddm, SFF8472_AW_TX_POWER + WARN_HIGH), 681 if_sff_power2dbm(&ddm, SFF8472_AW_TX_POWER + WARN_LOW)); 682 683 printf("\n\trx: "); 684 if_sff_printalarm(" dBm", 1, 685 if_sff_power2dbm(&ddm, SFF8472_DDM_RX_POWER), 686 if_sff_power2dbm(&ddm, SFF8472_AW_RX_POWER + ALRM_HIGH), 687 if_sff_power2dbm(&ddm, SFF8472_AW_RX_POWER + ALRM_LOW), 688 if_sff_power2dbm(&ddm, SFF8472_AW_RX_POWER + WARN_HIGH), 689 if_sff_power2dbm(&ddm, SFF8472_AW_RX_POWER + WARN_LOW)); 690 691 putchar('\n'); 692 return (0); 693 } 694 695 static void 696 if_upper_strings(const struct if_sffpage *pg) 697 { 698 if_sff_printmedia(pg, &upper_media_map); 699 700 printf("\n\tmodel: "); 701 if_sff_ascii_print(pg, "", 702 UPPER_VENDOR_START, UPPER_VENDOR_END, " "); 703 if_sff_ascii_print(pg, "", 704 UPPER_PRODUCT_START, UPPER_PRODUCT_END, ""); 705 if_sff_ascii_print(pg, " rev ", 706 UPPER_REVISION_START, UPPER_REVISION_END, ""); 707 708 if_sff_ascii_print(pg, "\n\tserial: ", 709 UPPER_SERIAL_START, UPPER_SERIAL_END, " "); 710 if_sff_date_print(pg, "date: ", UPPER_DATECODE, " "); 711 if_sff_ascii_print(pg, "lot: ", 712 UPPER_LOT_START, UPPER_LOT_END, ""); 713 714 putchar('\n'); 715 } 716 717 static int 718 if_inf8077(int dump, const struct if_sffpage *pg1) 719 { 720 if_upper_strings(pg1); 721 722 return (0); 723 } 724 725 static int 726 if_sff8636_thresh(int dump, const struct if_sffpage *pg0) 727 { 728 struct if_sffpage pg3; 729 unsigned int i; 730 struct sff_thresholds temp, vcc, tx, rx, bias; 731 732 if_sffpage_init(&pg3, IFSFF_ADDR_EEPROM, 3); 733 if (ioctl(sock, SIOCGIFSFFPAGE, (caddr_t)&pg3) == -1) { 734 if (dump) 735 warn("%s SIOCGIFSFFPAGE page 3", ifname); 736 return (-1); 737 } 738 739 if (dump) 740 if_sffpage_dump(&pg3); 741 742 if (pg3.sff_data[0x7f] != 3) { /* just in case... */ 743 if (dump) { 744 warnx("%s SIOCGIFSFFPAGE: page select unsupported", 745 ifname); 746 } 747 return (-1); 748 } 749 750 for (i = 0; i < SFF_THRESH_COUNT; i++) { 751 temp.thresholds[i] = if_sff_int(&pg3, 752 SFF8436_AW_TEMP + SFF_THRESH_REG(i)) / SFF_TEMP_FACTOR; 753 754 vcc.thresholds[i] = if_sff_uint(&pg3, 755 SFF8436_AW_VCC + SFF_THRESH_REG(i)) / SFF_VCC_FACTOR; 756 757 rx.thresholds[i] = if_sff_power2dbm(&pg3, 758 SFF8436_AW_RX_POWER + SFF_THRESH_REG(i)); 759 760 bias.thresholds[i] = if_sff_uint(&pg3, 761 SFF8436_AW_TX_BIAS + SFF_THRESH_REG(i)) / SFF_BIAS_FACTOR; 762 763 tx.thresholds[i] = if_sff_power2dbm(&pg3, 764 SFF8436_AW_TX_POWER + SFF_THRESH_REG(i)); 765 } 766 767 printf("\ttemp: "); 768 if_sff_printalarm(" C", 1, 769 if_sff_int(&pg3, SFF8436_TEMP) / SFF_TEMP_FACTOR, 770 temp.thresholds[SFF_THRESH_HI_ALARM], 771 temp.thresholds[SFF_THRESH_LO_ALARM], 772 temp.thresholds[SFF_THRESH_HI_WARN], 773 temp.thresholds[SFF_THRESH_LO_WARN]); 774 printf("\n"); 775 776 printf("\tvoltage: "); 777 if_sff_printalarm(" V", 1, 778 if_sff_uint(&pg3, SFF8436_VCC) / SFF_VCC_FACTOR, 779 vcc.thresholds[SFF_THRESH_HI_ALARM], 780 vcc.thresholds[SFF_THRESH_LO_ALARM], 781 vcc.thresholds[SFF_THRESH_HI_WARN], 782 vcc.thresholds[SFF_THRESH_LO_WARN]); 783 printf("\n"); 784 785 for (i = 0; i < SFF8436_CHANNELS; i++) { 786 unsigned int channel = i + 1; 787 788 printf("\tchannel %u bias current: ", channel); 789 if_sff_printalarm(" mA", 1, 790 if_sff_uint(&pg3, SFF8436_TX_BIAS(i)) / SFF_BIAS_FACTOR, 791 bias.thresholds[SFF_THRESH_HI_ALARM], 792 bias.thresholds[SFF_THRESH_LO_ALARM], 793 bias.thresholds[SFF_THRESH_HI_WARN], 794 bias.thresholds[SFF_THRESH_LO_WARN]); 795 printf("\n"); 796 797 printf("\tchannel %u tx: ", channel); 798 if_sff_printalarm(" dBm", 1, 799 if_sff_power2dbm(&pg3, SFF8436_TX_POWER(i)), 800 tx.thresholds[SFF_THRESH_HI_ALARM], 801 tx.thresholds[SFF_THRESH_LO_ALARM], 802 tx.thresholds[SFF_THRESH_HI_WARN], 803 tx.thresholds[SFF_THRESH_LO_WARN]); 804 printf("\n"); 805 806 printf("\tchannel %u rx: ", channel); 807 if_sff_printalarm(" dBm", 1, 808 if_sff_power2dbm(&pg3, SFF8436_RX_POWER(i)), 809 rx.thresholds[SFF_THRESH_HI_ALARM], 810 rx.thresholds[SFF_THRESH_LO_ALARM], 811 rx.thresholds[SFF_THRESH_HI_WARN], 812 rx.thresholds[SFF_THRESH_LO_WARN]); 813 printf("\n"); 814 } 815 816 return (0); 817 } 818 819 static int 820 if_sff8636(int dump, const struct if_sffpage *pg0) 821 { 822 int16_t temp; 823 uint8_t maxcasetemp; 824 uint8_t flat; 825 unsigned int i; 826 827 if_upper_strings(pg0); 828 829 if (pg0->sff_data[SFF8436_STATUS2] & SFF8436_STATUS2_DNR) { 830 printf("\tmonitor data not ready\n"); 831 return (0); 832 } 833 834 maxcasetemp = pg0->sff_data[SFF8436_MAXCASETEMP]; 835 if (maxcasetemp == 0x00) 836 maxcasetemp = SFF8436_MAXCASETEMP_DEFAULT; 837 printf("\tmax case temp: %u C\n", maxcasetemp); 838 839 temp = if_sff_int(pg0, SFF8436_TEMP); 840 /* the temp reading look unset, assume the rest will be unset too */ 841 if ((uint16_t)temp == 0 || (uint16_t)temp == 0xffffU) { 842 if (!dump) 843 return (0); 844 } 845 846 flat = pg0->sff_data[SFF8436_STATUS2] & SFF8436_STATUS2_FLAT_MEM; 847 if (!flat && if_sff8636_thresh(dump, pg0) == 0) { 848 if (!dump) 849 return (0); 850 } 851 852 printf("\t"); 853 printf("temp: %.02f%s", temp / SFF_TEMP_FACTOR, " C"); 854 printf(", "); 855 printf("voltage: %.02f%s", 856 if_sff_uint(pg0, SFF8436_VCC) / SFF_VCC_FACTOR, " V"); 857 printf("\n"); 858 859 for (i = 0; i < SFF8436_CHANNELS; i++) { 860 printf("\t"); 861 printf("channel %u: ", i + 1); 862 printf("bias current: %.02f mA", 863 if_sff_uint(pg0, SFF8436_TX_BIAS(i)) / SFF_BIAS_FACTOR); 864 printf(", "); 865 printf("rx: %.02f dBm", 866 if_sff_power2dbm(pg0, SFF8436_RX_POWER(i))); 867 printf(", "); 868 printf("tx: %.02f dBm", 869 if_sff_power2dbm(pg0, SFF8436_TX_POWER(i))); 870 printf("\n"); 871 } 872 873 return (0); 874 } 875 876 static int 877 printable(int ch) 878 { 879 if (ch == '\0') 880 return ('_'); 881 if (!isprint(ch)) 882 return ('~'); 883 884 return (ch); 885 } 886 887 static void 888 hexdump(const void *d, size_t datalen) 889 { 890 const uint8_t *data = d; 891 int i, j = 0; 892 893 for (i = 0; i < datalen; i += j) { 894 printf("% 4d: ", i); 895 for (j = 0; j < 16 && i+j < datalen; j++) 896 printf("%02x ", data[i + j]); 897 while (j++ < 16) 898 printf(" "); 899 printf("|"); 900 for (j = 0; j < 16 && i+j < datalen; j++) 901 putchar(printable(data[i + j])); 902 printf("|\n"); 903 } 904 } 905 906 #endif /* SMALL */ 907