1270064Smelifaro/*- 2270064Smelifaro * Copyright (c) 2014 Alexander V. Chernikov. All rights reserved. 3270064Smelifaro * 4270064Smelifaro * Redistribution and use in source and binary forms, with or without 5270064Smelifaro * modification, are permitted provided that the following conditions 6270064Smelifaro * are met: 7270064Smelifaro * 1. Redistributions of source code must retain the above copyright 8270064Smelifaro * notice, this list of conditions and the following disclaimer. 9270064Smelifaro * 2. Redistributions in binary form must reproduce the above copyright 10270064Smelifaro * notice, this list of conditions and the following disclaimer in the 11270064Smelifaro * documentation and/or other materials provided with the distribution. 12270064Smelifaro * 13270064Smelifaro * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14270064Smelifaro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15270064Smelifaro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16270064Smelifaro * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17270064Smelifaro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18270064Smelifaro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19270064Smelifaro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20270064Smelifaro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21270064Smelifaro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22270064Smelifaro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23270064Smelifaro * SUCH DAMAGE. 24270064Smelifaro */ 25270064Smelifaro 26270064Smelifaro#ifndef lint 27270064Smelifarostatic const char rcsid[] = 28270064Smelifaro "$FreeBSD$"; 29270064Smelifaro#endif /* not lint */ 30270064Smelifaro 31270064Smelifaro#include <sys/types.h> 32270064Smelifaro#include <sys/param.h> 33270064Smelifaro#include <sys/ioctl.h> 34270064Smelifaro#include <sys/socket.h> 35270064Smelifaro 36270064Smelifaro#include <net/if.h> 37286810Smelifaro#include <net/sff8436.h> 38286810Smelifaro#include <net/sff8472.h> 39270064Smelifaro 40270064Smelifaro#include <math.h> 41270064Smelifaro#include <err.h> 42270064Smelifaro#include <errno.h> 43286810Smelifaro#include <fcntl.h> 44270064Smelifaro#include <stdio.h> 45270064Smelifaro#include <stdlib.h> 46270064Smelifaro#include <string.h> 47270064Smelifaro#include <unistd.h> 48270064Smelifaro 49270064Smelifaro#include "ifconfig.h" 50270064Smelifaro 51270064Smelifarostruct i2c_info { 52286810Smelifaro int fd; /* fd to issue SIOCGI2C */ 53286810Smelifaro int error; /* Store first error */ 54286810Smelifaro int qsfp; /* True if transceiver is QSFP */ 55286810Smelifaro int do_diag; /* True if we need to request DDM */ 56286810Smelifaro struct ifreq *ifr; /* Pointer to pre-filled ifreq */ 57270064Smelifaro}; 58270064Smelifaro 59286810Smelifarostatic int read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, 60286810Smelifaro uint8_t len, uint8_t *buf); 61286810Smelifarostatic void dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off, 62286810Smelifaro uint8_t len); 63286810Smelifaro 64270064Smelifarostruct _nv { 65270064Smelifaro int v; 66270064Smelifaro const char *n; 67270064Smelifaro}; 68270064Smelifaro 69270064Smelifaroconst char *find_value(struct _nv *x, int value); 70270064Smelifaroconst char *find_zero_bit(struct _nv *x, int value, int sz); 71270064Smelifaro 72270064Smelifaro/* SFF-8472 Rev. 11.4 table 3.4: Connector values */ 73270064Smelifarostatic struct _nv conn[] = { 74270064Smelifaro { 0x00, "Unknown" }, 75270064Smelifaro { 0x01, "SC" }, 76270064Smelifaro { 0x02, "Fibre Channel Style 1 copper" }, 77270064Smelifaro { 0x03, "Fibre Channel Style 2 copper" }, 78270064Smelifaro { 0x04, "BNC/TNC" }, 79270064Smelifaro { 0x05, "Fibre Channel coaxial" }, 80270064Smelifaro { 0x06, "FiberJack" }, 81270064Smelifaro { 0x07, "LC" }, 82270064Smelifaro { 0x08, "MT-RJ" }, 83270064Smelifaro { 0x09, "MU" }, 84270064Smelifaro { 0x0A, "SG" }, 85270064Smelifaro { 0x0B, "Optical pigtail" }, 86270064Smelifaro { 0x0C, "MPO Parallel Optic" }, 87270064Smelifaro { 0x20, "HSSDC II" }, 88270064Smelifaro { 0x21, "Copper pigtail" }, 89270064Smelifaro { 0x22, "RJ45" }, 90286810Smelifaro { 0x23, "No separate connector" }, /* SFF-8436 */ 91270064Smelifaro { 0, NULL } 92270064Smelifaro}; 93270064Smelifaro 94270064Smelifaro/* SFF-8472 Rev. 11.4 table 3.5: Transceiver codes */ 95286810Smelifaro/* 10G Ethernet/IB compliance codes, byte 3 */ 96270064Smelifarostatic struct _nv eth_10g[] = { 97270064Smelifaro { 0x80, "10G Base-ER" }, 98270064Smelifaro { 0x40, "10G Base-LRM" }, 99270064Smelifaro { 0x20, "10G Base-LR" }, 100270064Smelifaro { 0x10, "10G Base-SR" }, 101270064Smelifaro { 0x08, "1X SX" }, 102270064Smelifaro { 0x04, "1X LX" }, 103270064Smelifaro { 0x02, "1X Copper Active" }, 104270064Smelifaro { 0x01, "1X Copper Passive" }, 105270064Smelifaro { 0, NULL } 106270064Smelifaro}; 107270064Smelifaro 108270064Smelifaro/* Ethernet compliance codes, byte 6 */ 109270064Smelifarostatic struct _nv eth_compat[] = { 110270064Smelifaro { 0x80, "BASE-PX" }, 111270064Smelifaro { 0x40, "BASE-BX10" }, 112270064Smelifaro { 0x20, "100BASE-FX" }, 113270064Smelifaro { 0x10, "100BASE-LX/LX10" }, 114270064Smelifaro { 0x08, "1000BASE-T" }, 115270064Smelifaro { 0x04, "1000BASE-CX" }, 116270064Smelifaro { 0x02, "1000BASE-LX" }, 117270064Smelifaro { 0x01, "1000BASE-SX" }, 118270064Smelifaro { 0, NULL } 119270064Smelifaro}; 120270064Smelifaro 121270064Smelifaro/* FC link length, byte 7 */ 122270064Smelifarostatic struct _nv fc_len[] = { 123270064Smelifaro { 0x80, "very long distance" }, 124270064Smelifaro { 0x40, "short distance" }, 125270064Smelifaro { 0x20, "intermediate distance" }, 126270064Smelifaro { 0x10, "long distance" }, 127270064Smelifaro { 0x08, "medium distance" }, 128270064Smelifaro { 0, NULL } 129270064Smelifaro}; 130270064Smelifaro 131270064Smelifaro/* Channel/Cable technology, byte 7-8 */ 132270064Smelifarostatic struct _nv cab_tech[] = { 133270064Smelifaro { 0x0400, "Shortwave laser (SA)" }, 134270064Smelifaro { 0x0200, "Longwave laser (LC)" }, 135270064Smelifaro { 0x0100, "Electrical inter-enclosure (EL)" }, 136270064Smelifaro { 0x80, "Electrical intra-enclosure (EL)" }, 137270064Smelifaro { 0x40, "Shortwave laser (SN)" }, 138270064Smelifaro { 0x20, "Shortwave laser (SL)" }, 139270064Smelifaro { 0x10, "Longwave laser (LL)" }, 140270064Smelifaro { 0x08, "Active Cable" }, 141270064Smelifaro { 0x04, "Passive Cable" }, 142270064Smelifaro { 0, NULL } 143270064Smelifaro}; 144270064Smelifaro 145270064Smelifaro/* FC Transmission media, byte 9 */ 146270064Smelifarostatic struct _nv fc_media[] = { 147270064Smelifaro { 0x80, "Twin Axial Pair" }, 148270064Smelifaro { 0x40, "Twisted Pair" }, 149270064Smelifaro { 0x20, "Miniature Coax" }, 150270064Smelifaro { 0x10, "Viao Coax" }, 151270064Smelifaro { 0x08, "Miltimode, 62.5um" }, 152270064Smelifaro { 0x04, "Multimode, 50um" }, 153270064Smelifaro { 0x02, "" }, 154270064Smelifaro { 0x01, "Single Mode" }, 155270064Smelifaro { 0, NULL } 156270064Smelifaro}; 157270064Smelifaro 158270064Smelifaro/* FC Speed, byte 10 */ 159270064Smelifarostatic struct _nv fc_speed[] = { 160270064Smelifaro { 0x80, "1200 MBytes/sec" }, 161270064Smelifaro { 0x40, "800 MBytes/sec" }, 162270064Smelifaro { 0x20, "1600 MBytes/sec" }, 163270064Smelifaro { 0x10, "400 MBytes/sec" }, 164270064Smelifaro { 0x08, "3200 MBytes/sec" }, 165270064Smelifaro { 0x04, "200 MBytes/sec" }, 166270064Smelifaro { 0x01, "100 MBytes/sec" }, 167270064Smelifaro { 0, NULL } 168270064Smelifaro}; 169270064Smelifaro 170286810Smelifaro/* SFF-8436 Rev. 4.8 table 33: Specification compliance */ 171286810Smelifaro 172286810Smelifaro/* 10/40G Ethernet compliance codes, byte 128 + 3 */ 173286810Smelifarostatic struct _nv eth_1040g[] = { 174294202Smelifaro { 0x80, "Extended" }, 175286810Smelifaro { 0x40, "10GBASE-LRM" }, 176286810Smelifaro { 0x20, "10GBASE-LR" }, 177286810Smelifaro { 0x10, "10GBASE-SR" }, 178286810Smelifaro { 0x08, "40GBASE-CR4" }, 179286810Smelifaro { 0x04, "40GBASE-SR4" }, 180286810Smelifaro { 0x02, "40GBASE-LR4" }, 181286810Smelifaro { 0x01, "40G Active Cable" }, 182286810Smelifaro { 0, NULL } 183286810Smelifaro}; 184294202Smelifaro#define SFF_8636_EXT_COMPLIANCE 0x80 185286810Smelifaro 186294202Smelifaro/* SFF-8024 Rev. 3.4 table 4.4: Extended Specification Compliance */ 187294202Smelifarostatic struct _nv eth_extended_comp[] = { 188294202Smelifaro { 0xFF, "Reserved" }, 189294202Smelifaro { 0x1A, "2 lambda DWDM 100G" }, 190294202Smelifaro { 0x19, "100G ACC or 25GAUI C2M ACC" }, 191294202Smelifaro { 0x18, "100G AOC or 25GAUI C2M AOC" }, 192294202Smelifaro { 0x17, "100G CLR4" }, 193294202Smelifaro { 0x16, "10GBASE-T with SFI electrical interface" }, 194294202Smelifaro { 0x15, "G959.1 profile P1L1-2D2" }, 195294202Smelifaro { 0x14, "G959.1 profile P1S1-2D2" }, 196294202Smelifaro { 0x13, "G959.1 profile P1I1-2D1" }, 197294202Smelifaro { 0x12, "40G PSM4 Parallel SMF" }, 198294202Smelifaro { 0x11, "4 x 10GBASE-SR" }, 199294202Smelifaro { 0x10, "40GBASE-ER4" }, 200294202Smelifaro { 0x0F, "Reserved" }, 201294202Smelifaro { 0x0D, "25GBASE-CR CA-N" }, 202294202Smelifaro { 0x0C, "25GBASE-CR CA-S" }, 203294202Smelifaro { 0x0B, "100GBASE-CR4 or 25GBASE-CR CA-L" }, 204294202Smelifaro { 0x0A, "Reserved" }, 205294202Smelifaro { 0x09, "100G CWDM4 MSA without FEC" }, 206294202Smelifaro { 0x08, "100G ACC (Active Copper Cable)" }, 207294202Smelifaro { 0x07, "100G PSM4 Parallel SMF" }, 208294202Smelifaro { 0x06, "100G CWDM4 MSA with FEC" }, 209294202Smelifaro { 0x05, "100GBASE-SR10" }, 210294202Smelifaro { 0x04, "100GBASE-ER4" }, 211294202Smelifaro { 0x03, "100GBASE-LR4" }, 212294202Smelifaro { 0x02, "100GBASE-SR4" }, 213294202Smelifaro { 0x01, "100G AOC (Active Optical Cable) or 25GAUI C2M ACC" }, 214294202Smelifaro { 0x00, "Unspecified" } 215294202Smelifaro}; 216294202Smelifaro 217286810Smelifaro/* SFF-8636 Rev. 2.5 table 6.3: Revision compliance */ 218286810Smelifarostatic struct _nv rev_compl[] = { 219286810Smelifaro { 0x1, "SFF-8436 rev <=4.8" }, 220286810Smelifaro { 0x2, "SFF-8436 rev <=4.8" }, 221286810Smelifaro { 0x3, "SFF-8636 rev <=1.3" }, 222286810Smelifaro { 0x4, "SFF-8636 rev <=1.4" }, 223286810Smelifaro { 0x5, "SFF-8636 rev <=1.5" }, 224286810Smelifaro { 0x6, "SFF-8636 rev <=2.0" }, 225286810Smelifaro { 0x7, "SFF-8636 rev <=2.5" }, 226286810Smelifaro { 0x0, "Unspecified" } 227286810Smelifaro}; 228286810Smelifaro 229286810Smelifaroconst char * 230286810Smelifarofind_value(struct _nv *x, int value) 231286810Smelifaro{ 232286810Smelifaro for (; x->n != NULL; x++) 233286810Smelifaro if (x->v == value) 234286810Smelifaro return (x->n); 235286810Smelifaro return (NULL); 236286810Smelifaro} 237286810Smelifaro 238286810Smelifaroconst char * 239286810Smelifarofind_zero_bit(struct _nv *x, int value, int sz) 240286810Smelifaro{ 241286810Smelifaro int v, m; 242286810Smelifaro const char *s; 243286810Smelifaro 244286810Smelifaro v = 1; 245286810Smelifaro for (v = 1, m = 1 << (8 * sz); v < m; v *= 2) { 246286810Smelifaro if ((value & v) == 0) 247286810Smelifaro continue; 248286810Smelifaro if ((s = find_value(x, value & v)) != NULL) { 249286810Smelifaro value &= ~v; 250286810Smelifaro return (s); 251286810Smelifaro } 252286810Smelifaro } 253286810Smelifaro 254286810Smelifaro return (NULL); 255286810Smelifaro} 256286810Smelifaro 257270064Smelifarostatic void 258286810Smelifaroconvert_sff_identifier(char *buf, size_t size, uint8_t value) 259286810Smelifaro{ 260286810Smelifaro const char *x; 261286810Smelifaro 262286810Smelifaro x = NULL; 263286810Smelifaro if (value <= SFF_8024_ID_LAST) 264286810Smelifaro x = sff_8024_id[value]; 265286810Smelifaro else { 266286810Smelifaro if (value > 0x80) 267286810Smelifaro x = "Vendor specific"; 268286810Smelifaro else 269286810Smelifaro x = "Reserved"; 270286810Smelifaro } 271286810Smelifaro 272286810Smelifaro snprintf(buf, size, "%s", x); 273286810Smelifaro} 274286810Smelifaro 275286810Smelifarostatic void 276286810Smelifaroconvert_sff_connector(char *buf, size_t size, uint8_t value) 277286810Smelifaro{ 278286810Smelifaro const char *x; 279286810Smelifaro 280286810Smelifaro if ((x = find_value(conn, value)) == NULL) { 281286810Smelifaro if (value >= 0x0D && value <= 0x1F) 282286810Smelifaro x = "Unallocated"; 283286810Smelifaro else if (value >= 0x24 && value <= 0x7F) 284286810Smelifaro x = "Unallocated"; 285286810Smelifaro else 286286810Smelifaro x = "Vendor specific"; 287286810Smelifaro } 288286810Smelifaro 289286810Smelifaro snprintf(buf, size, "%s", x); 290286810Smelifaro} 291286810Smelifaro 292286810Smelifarostatic void 293286810Smelifaroconvert_sff_rev_compliance(char *buf, size_t size, uint8_t value) 294286810Smelifaro{ 295286810Smelifaro const char *x; 296286810Smelifaro 297286810Smelifaro if (value > 0x07) 298286810Smelifaro x = "Unallocated"; 299286810Smelifaro else 300286810Smelifaro x = find_value(rev_compl, value); 301286810Smelifaro 302286810Smelifaro snprintf(buf, size, "%s", x); 303286810Smelifaro} 304286810Smelifaro 305286810Smelifarostatic void 306286810Smelifaroget_sfp_identifier(struct i2c_info *ii, char *buf, size_t size) 307286810Smelifaro{ 308286810Smelifaro uint8_t data; 309286810Smelifaro 310286810Smelifaro read_i2c(ii, SFF_8472_BASE, SFF_8472_ID, 1, &data); 311286810Smelifaro convert_sff_identifier(buf, size, data); 312286810Smelifaro} 313286810Smelifaro 314286810Smelifarostatic void 315286810Smelifaroget_sfp_connector(struct i2c_info *ii, char *buf, size_t size) 316286810Smelifaro{ 317286810Smelifaro uint8_t data; 318286810Smelifaro 319286810Smelifaro read_i2c(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, &data); 320286810Smelifaro convert_sff_connector(buf, size, data); 321286810Smelifaro} 322286810Smelifaro 323286810Smelifarostatic void 324286810Smelifaroget_qsfp_identifier(struct i2c_info *ii, char *buf, size_t size) 325286810Smelifaro{ 326286810Smelifaro uint8_t data; 327286810Smelifaro 328286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_ID, 1, &data); 329286810Smelifaro convert_sff_identifier(buf, size, data); 330286810Smelifaro} 331286810Smelifaro 332286810Smelifarostatic void 333286810Smelifaroget_qsfp_connector(struct i2c_info *ii, char *buf, size_t size) 334286810Smelifaro{ 335286810Smelifaro uint8_t data; 336286810Smelifaro 337286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_CONNECTOR, 1, &data); 338286810Smelifaro convert_sff_connector(buf, size, data); 339286810Smelifaro} 340286810Smelifaro 341286810Smelifarostatic void 342270064Smelifaroprintf_sfp_transceiver_descr(struct i2c_info *ii, char *buf, size_t size) 343270064Smelifaro{ 344270064Smelifaro char xbuf[12]; 345270064Smelifaro const char *tech_class, *tech_len, *tech_tech, *tech_media, *tech_speed; 346270064Smelifaro 347270064Smelifaro tech_class = NULL; 348270064Smelifaro tech_len = NULL; 349270064Smelifaro tech_tech = NULL; 350270064Smelifaro tech_media = NULL; 351270064Smelifaro tech_speed = NULL; 352270064Smelifaro 353270064Smelifaro /* Read bytes 3-10 at once */ 354286810Smelifaro read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, &xbuf[3]); 355270064Smelifaro 356286810Smelifaro /* Check 10G ethernet first */ 357270064Smelifaro tech_class = find_zero_bit(eth_10g, xbuf[3], 1); 358270064Smelifaro if (tech_class == NULL) { 359270064Smelifaro /* No match. Try 1G */ 360270064Smelifaro tech_class = find_zero_bit(eth_compat, xbuf[6], 1); 361270064Smelifaro } 362270064Smelifaro 363270064Smelifaro tech_len = find_zero_bit(fc_len, xbuf[7], 1); 364270064Smelifaro tech_tech = find_zero_bit(cab_tech, xbuf[7] << 8 | xbuf[8], 2); 365270064Smelifaro tech_media = find_zero_bit(fc_media, xbuf[9], 1); 366270064Smelifaro tech_speed = find_zero_bit(fc_speed, xbuf[10], 1); 367270064Smelifaro 368270064Smelifaro printf("Class: %s\n", tech_class); 369270064Smelifaro printf("Length: %s\n", tech_len); 370270064Smelifaro printf("Tech: %s\n", tech_tech); 371270064Smelifaro printf("Media: %s\n", tech_media); 372270064Smelifaro printf("Speed: %s\n", tech_speed); 373270064Smelifaro} 374270064Smelifaro 375270064Smelifarostatic void 376270064Smelifaroget_sfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size) 377270064Smelifaro{ 378270064Smelifaro const char *tech_class; 379270064Smelifaro uint8_t code; 380270064Smelifaro 381286810Smelifaro unsigned char qbuf[8]; 382286810Smelifaro read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, (uint8_t *)qbuf); 383286810Smelifaro 384270064Smelifaro /* Check 10G Ethernet/IB first */ 385286810Smelifaro read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, &code); 386270064Smelifaro tech_class = find_zero_bit(eth_10g, code, 1); 387270064Smelifaro if (tech_class == NULL) { 388270064Smelifaro /* No match. Try Ethernet 1G */ 389286810Smelifaro read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3, 390286810Smelifaro 1, (caddr_t)&code); 391270064Smelifaro tech_class = find_zero_bit(eth_compat, code, 1); 392270064Smelifaro } 393270064Smelifaro 394270064Smelifaro if (tech_class == NULL) 395270064Smelifaro tech_class = "Unknown"; 396270064Smelifaro 397270064Smelifaro snprintf(buf, size, "%s", tech_class); 398270064Smelifaro} 399270064Smelifaro 400286810Smelifarostatic void 401286810Smelifaroget_qsfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size) 402286810Smelifaro{ 403286810Smelifaro const char *tech_class; 404286810Smelifaro uint8_t code; 405270064Smelifaro 406294202Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_CODE_E1040100G, 1, &code); 407294202Smelifaro 408294202Smelifaro /* Check for extended specification compliance */ 409294202Smelifaro if (code & SFF_8636_EXT_COMPLIANCE) { 410294202Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_OPTIONS_START, 1, &code); 411294202Smelifaro tech_class = find_value(eth_extended_comp, code); 412294202Smelifaro } else 413294202Smelifaro /* Check 10/40G Ethernet class only */ 414294202Smelifaro tech_class = find_zero_bit(eth_1040g, code, 1); 415294202Smelifaro 416286810Smelifaro if (tech_class == NULL) 417286810Smelifaro tech_class = "Unknown"; 418286810Smelifaro 419286810Smelifaro snprintf(buf, size, "%s", tech_class); 420286810Smelifaro} 421286810Smelifaro 422286810Smelifaro/* 423286810Smelifaro * Print SFF-8472/SFF-8436 string to supplied buffer. 424286810Smelifaro * All (vendor-specific) strings are padded right with '0x20'. 425286810Smelifaro */ 426270064Smelifarostatic void 427286810Smelifaroconvert_sff_name(char *buf, size_t size, char *xbuf) 428270064Smelifaro{ 429286810Smelifaro char *p; 430270064Smelifaro 431270064Smelifaro for (p = &xbuf[16]; *(p - 1) == 0x20; p--) 432270064Smelifaro ; 433270064Smelifaro *p = '\0'; 434270064Smelifaro snprintf(buf, size, "%s", xbuf); 435270064Smelifaro} 436270064Smelifaro 437270064Smelifarostatic void 438286810Smelifaroconvert_sff_date(char *buf, size_t size, char *xbuf) 439286810Smelifaro{ 440286810Smelifaro 441286810Smelifaro snprintf(buf, size, "20%c%c-%c%c-%c%c", xbuf[0], xbuf[1], 442286810Smelifaro xbuf[2], xbuf[3], xbuf[4], xbuf[5]); 443286810Smelifaro} 444286810Smelifaro 445286810Smelifarostatic void 446286810Smelifaroget_sfp_vendor_name(struct i2c_info *ii, char *buf, size_t size) 447286810Smelifaro{ 448286810Smelifaro char xbuf[17]; 449286810Smelifaro 450286810Smelifaro memset(xbuf, 0, sizeof(xbuf)); 451286810Smelifaro read_i2c(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, 16, (uint8_t *)xbuf); 452286810Smelifaro convert_sff_name(buf, size, xbuf); 453286810Smelifaro} 454286810Smelifaro 455286810Smelifarostatic void 456270064Smelifaroget_sfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size) 457270064Smelifaro{ 458286810Smelifaro char xbuf[17]; 459270064Smelifaro 460270064Smelifaro memset(xbuf, 0, sizeof(xbuf)); 461286810Smelifaro read_i2c(ii, SFF_8472_BASE, SFF_8472_PN_START, 16, (uint8_t *)xbuf); 462286810Smelifaro convert_sff_name(buf, size, xbuf); 463270064Smelifaro} 464270064Smelifaro 465270064Smelifarostatic void 466270064Smelifaroget_sfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size) 467270064Smelifaro{ 468286810Smelifaro char xbuf[17]; 469270064Smelifaro 470270064Smelifaro memset(xbuf, 0, sizeof(xbuf)); 471286810Smelifaro read_i2c(ii, SFF_8472_BASE, SFF_8472_SN_START, 16, (uint8_t *)xbuf); 472286810Smelifaro convert_sff_name(buf, size, xbuf); 473270064Smelifaro} 474270064Smelifaro 475270064Smelifarostatic void 476270064Smelifaroget_sfp_vendor_date(struct i2c_info *ii, char *buf, size_t size) 477270064Smelifaro{ 478270064Smelifaro char xbuf[6]; 479270064Smelifaro 480270064Smelifaro memset(xbuf, 0, sizeof(xbuf)); 481270064Smelifaro /* Date code, see Table 3.8 for description */ 482286810Smelifaro read_i2c(ii, SFF_8472_BASE, SFF_8472_DATE_START, 6, (uint8_t *)xbuf); 483286810Smelifaro convert_sff_date(buf, size, xbuf); 484270064Smelifaro} 485270064Smelifaro 486270064Smelifarostatic void 487286810Smelifaroget_qsfp_vendor_name(struct i2c_info *ii, char *buf, size_t size) 488286810Smelifaro{ 489286810Smelifaro char xbuf[17]; 490286810Smelifaro 491286810Smelifaro memset(xbuf, 0, sizeof(xbuf)); 492286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, 16, (uint8_t *)xbuf); 493286810Smelifaro convert_sff_name(buf, size, xbuf); 494286810Smelifaro} 495286810Smelifaro 496286810Smelifarostatic void 497286810Smelifaroget_qsfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size) 498286810Smelifaro{ 499286810Smelifaro char xbuf[17]; 500286810Smelifaro 501286810Smelifaro memset(xbuf, 0, sizeof(xbuf)); 502286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_PN_START, 16, (uint8_t *)xbuf); 503286810Smelifaro convert_sff_name(buf, size, xbuf); 504286810Smelifaro} 505286810Smelifaro 506286810Smelifarostatic void 507286810Smelifaroget_qsfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size) 508286810Smelifaro{ 509286810Smelifaro char xbuf[17]; 510286810Smelifaro 511286810Smelifaro memset(xbuf, 0, sizeof(xbuf)); 512286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_SN_START, 16, (uint8_t *)xbuf); 513286810Smelifaro convert_sff_name(buf, size, xbuf); 514286810Smelifaro} 515286810Smelifaro 516286810Smelifarostatic void 517286810Smelifaroget_qsfp_vendor_date(struct i2c_info *ii, char *buf, size_t size) 518286810Smelifaro{ 519286810Smelifaro char xbuf[6]; 520286810Smelifaro 521286810Smelifaro memset(xbuf, 0, sizeof(xbuf)); 522286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_DATE_START, 6, (uint8_t *)xbuf); 523286810Smelifaro convert_sff_date(buf, size, xbuf); 524286810Smelifaro} 525286810Smelifaro 526286810Smelifarostatic void 527270064Smelifaroprint_sfp_vendor(struct i2c_info *ii, char *buf, size_t size) 528270064Smelifaro{ 529270064Smelifaro char xbuf[80]; 530270064Smelifaro 531270064Smelifaro memset(xbuf, 0, sizeof(xbuf)); 532286810Smelifaro if (ii->qsfp != 0) { 533286810Smelifaro get_qsfp_vendor_name(ii, xbuf, 20); 534286810Smelifaro get_qsfp_vendor_pn(ii, &xbuf[20], 20); 535286810Smelifaro get_qsfp_vendor_sn(ii, &xbuf[40], 20); 536286810Smelifaro get_qsfp_vendor_date(ii, &xbuf[60], 20); 537286810Smelifaro } else { 538286810Smelifaro get_sfp_vendor_name(ii, xbuf, 20); 539286810Smelifaro get_sfp_vendor_pn(ii, &xbuf[20], 20); 540286810Smelifaro get_sfp_vendor_sn(ii, &xbuf[40], 20); 541286810Smelifaro get_sfp_vendor_date(ii, &xbuf[60], 20); 542286810Smelifaro } 543270064Smelifaro 544270064Smelifaro snprintf(buf, size, "vendor: %s PN: %s SN: %s DATE: %s", 545270064Smelifaro xbuf, &xbuf[20], &xbuf[40], &xbuf[60]); 546270064Smelifaro} 547270064Smelifaro 548286810Smelifaro/* 549286810Smelifaro * Converts internal templerature (SFF-8472, SFF-8436) 550286810Smelifaro * 16-bit unsigned value to human-readable representation: 551286810Smelifaro * 552286810Smelifaro * Internally measured Module temperature are represented 553286810Smelifaro * as a 16-bit signed twos complement value in increments of 554286810Smelifaro * 1/256 degrees Celsius, yielding a total range of ���128C to +128C 555286810Smelifaro * that is considered valid between ���40 and +125C. 556286810Smelifaro * 557286810Smelifaro */ 558270064Smelifarostatic void 559286810Smelifaroconvert_sff_temp(char *buf, size_t size, uint8_t *xbuf) 560270064Smelifaro{ 561286810Smelifaro double d; 562270064Smelifaro 563286810Smelifaro d = (double)xbuf[0]; 564286810Smelifaro d += (double)xbuf[1] / 256; 565270064Smelifaro 566286810Smelifaro snprintf(buf, size, "%.2f C", d); 567286810Smelifaro} 568270064Smelifaro 569286810Smelifaro/* 570286810Smelifaro * Retrieves supplied voltage (SFF-8472, SFF-8436). 571286810Smelifaro * 16-bit usigned value, treated as range 0..+6.55 Volts 572286810Smelifaro */ 573286810Smelifarostatic void 574286810Smelifaroconvert_sff_voltage(char *buf, size_t size, uint8_t *xbuf) 575286810Smelifaro{ 576286810Smelifaro double d; 577270064Smelifaro 578286810Smelifaro d = (double)((xbuf[0] << 8) | xbuf[1]); 579286810Smelifaro snprintf(buf, size, "%.2f Volts", d / 10000); 580270064Smelifaro} 581270064Smelifaro 582286810Smelifaro/* 583286810Smelifaro * Converts value in @xbuf to both milliwats and dBm 584286810Smelifaro * human representation. 585286810Smelifaro */ 586270064Smelifarostatic void 587286810Smelifaroconvert_sff_power(struct i2c_info *ii, char *buf, size_t size, uint8_t *xbuf) 588270064Smelifaro{ 589270064Smelifaro uint16_t mW; 590270064Smelifaro double dbm; 591270064Smelifaro 592286810Smelifaro mW = (xbuf[0] << 8) + xbuf[1]; 593270064Smelifaro 594270064Smelifaro /* Convert mw to dbm */ 595270064Smelifaro dbm = 10.0 * log10(1.0 * mW / 10000); 596270064Smelifaro 597286810Smelifaro /* 598286810Smelifaro * Assume internally-calibrated data. 599286810Smelifaro * This is always true for SFF-8346, and explicitly 600286810Smelifaro * checked for SFF-8472. 601286810Smelifaro */ 602286810Smelifaro 603270064Smelifaro /* Table 3.9, bit 5 is set, internally calibrated */ 604286810Smelifaro snprintf(buf, size, "%d.%02d mW (%.2f dBm)", 605286810Smelifaro mW / 10000, (mW % 10000) / 100, dbm); 606270064Smelifaro} 607270064Smelifaro 608270064Smelifarostatic void 609286810Smelifaroget_sfp_temp(struct i2c_info *ii, char *buf, size_t size) 610286810Smelifaro{ 611286810Smelifaro uint8_t xbuf[2]; 612286810Smelifaro 613286810Smelifaro memset(xbuf, 0, sizeof(xbuf)); 614286810Smelifaro read_i2c(ii, SFF_8472_DIAG, SFF_8472_TEMP, 2, xbuf); 615286810Smelifaro convert_sff_temp(buf, size, xbuf); 616286810Smelifaro} 617286810Smelifaro 618286810Smelifarostatic void 619286810Smelifaroget_sfp_voltage(struct i2c_info *ii, char *buf, size_t size) 620286810Smelifaro{ 621286810Smelifaro uint8_t xbuf[2]; 622286810Smelifaro 623286810Smelifaro memset(xbuf, 0, sizeof(xbuf)); 624286810Smelifaro read_i2c(ii, SFF_8472_DIAG, SFF_8472_VCC, 2, xbuf); 625286810Smelifaro convert_sff_voltage(buf, size, xbuf); 626286810Smelifaro} 627286810Smelifaro 628297640Shselaskystatic int 629286810Smelifaroget_qsfp_temp(struct i2c_info *ii, char *buf, size_t size) 630286810Smelifaro{ 631286810Smelifaro uint8_t xbuf[2]; 632286810Smelifaro 633286810Smelifaro memset(xbuf, 0, sizeof(xbuf)); 634286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_TEMP, 2, xbuf); 635297640Shselasky if ((xbuf[0] == 0xFF && xbuf[1] == 0xFF) || (xbuf[0] == 0 && xbuf[1] == 0)) 636297640Shselasky return (-1); 637286810Smelifaro convert_sff_temp(buf, size, xbuf); 638297640Shselasky return (0); 639286810Smelifaro} 640286810Smelifaro 641286810Smelifarostatic void 642286810Smelifaroget_qsfp_voltage(struct i2c_info *ii, char *buf, size_t size) 643286810Smelifaro{ 644286810Smelifaro uint8_t xbuf[2]; 645286810Smelifaro 646286810Smelifaro memset(xbuf, 0, sizeof(xbuf)); 647286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_VCC, 2, xbuf); 648286810Smelifaro convert_sff_voltage(buf, size, xbuf); 649286810Smelifaro} 650286810Smelifaro 651286810Smelifarostatic void 652270064Smelifaroget_sfp_rx_power(struct i2c_info *ii, char *buf, size_t size) 653270064Smelifaro{ 654286810Smelifaro uint8_t xbuf[2]; 655270064Smelifaro 656270064Smelifaro memset(xbuf, 0, sizeof(xbuf)); 657286810Smelifaro read_i2c(ii, SFF_8472_DIAG, SFF_8472_RX_POWER, 2, xbuf); 658286810Smelifaro convert_sff_power(ii, buf, size, xbuf); 659270064Smelifaro} 660270064Smelifaro 661270064Smelifarostatic void 662270064Smelifaroget_sfp_tx_power(struct i2c_info *ii, char *buf, size_t size) 663270064Smelifaro{ 664286810Smelifaro uint8_t xbuf[2]; 665270064Smelifaro 666270064Smelifaro memset(xbuf, 0, sizeof(xbuf)); 667286810Smelifaro read_i2c(ii, SFF_8472_DIAG, SFF_8472_TX_POWER, 2, xbuf); 668286810Smelifaro convert_sff_power(ii, buf, size, xbuf); 669270064Smelifaro} 670270064Smelifaro 671286810Smelifarostatic void 672286810Smelifaroget_qsfp_rx_power(struct i2c_info *ii, char *buf, size_t size, int chan) 673286810Smelifaro{ 674286810Smelifaro uint8_t xbuf[2]; 675270064Smelifaro 676286810Smelifaro memset(xbuf, 0, sizeof(xbuf)); 677286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_RX_CH1_MSB + (chan-1)*2, 2, xbuf); 678286810Smelifaro convert_sff_power(ii, buf, size, xbuf); 679286810Smelifaro} 680286810Smelifaro 681286810Smelifarostatic void 682286810Smelifaroget_qsfp_tx_power(struct i2c_info *ii, char *buf, size_t size, int chan) 683286810Smelifaro{ 684286810Smelifaro uint8_t xbuf[2]; 685286810Smelifaro 686286810Smelifaro memset(xbuf, 0, sizeof(xbuf)); 687286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_TX_CH1_MSB + (chan-1)*2, 2, xbuf); 688286810Smelifaro convert_sff_power(ii, buf, size, xbuf); 689286810Smelifaro} 690286810Smelifaro 691286810Smelifarostatic void 692286810Smelifaroget_qsfp_rev_compliance(struct i2c_info *ii, char *buf, size_t size) 693286810Smelifaro{ 694286810Smelifaro uint8_t xbuf; 695286810Smelifaro 696286810Smelifaro xbuf = 0; 697286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_STATUS, 1, &xbuf); 698286810Smelifaro convert_sff_rev_compliance(buf, size, xbuf); 699286810Smelifaro} 700286810Smelifaro 701286810Smelifarostatic uint32_t 702286810Smelifaroget_qsfp_br(struct i2c_info *ii) 703286810Smelifaro{ 704286810Smelifaro uint8_t xbuf; 705286810Smelifaro uint32_t rate; 706286810Smelifaro 707286810Smelifaro xbuf = 0; 708286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8436_BITRATE, 1, &xbuf); 709286810Smelifaro rate = xbuf * 100; 710286810Smelifaro if (xbuf == 0xFF) { 711286810Smelifaro read_i2c(ii, SFF_8436_BASE, SFF_8636_BITRATE, 1, &xbuf); 712286810Smelifaro rate = xbuf * 250; 713286810Smelifaro } 714286810Smelifaro 715286810Smelifaro return (rate); 716286810Smelifaro} 717286810Smelifaro 718286810Smelifaro/* 719286810Smelifaro * Reads i2c data from opened kernel socket. 720286810Smelifaro */ 721270064Smelifarostatic int 722286810Smelifaroread_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len, 723286810Smelifaro uint8_t *buf) 724270064Smelifaro{ 725286810Smelifaro struct ifi2creq req; 726286810Smelifaro int i, l; 727270064Smelifaro 728270064Smelifaro if (ii->error != 0) 729270064Smelifaro return (ii->error); 730270064Smelifaro 731286810Smelifaro ii->ifr->ifr_data = (caddr_t)&req; 732270064Smelifaro 733286810Smelifaro i = 0; 734286810Smelifaro l = 0; 735286810Smelifaro memset(&req, 0, sizeof(req)); 736286810Smelifaro req.dev_addr = addr; 737286810Smelifaro req.offset = off; 738286810Smelifaro req.len = len; 739270064Smelifaro 740286810Smelifaro while (len > 0) { 741286810Smelifaro l = (len > sizeof(req.data)) ? sizeof(req.data) : len; 742286810Smelifaro req.len = l; 743286810Smelifaro if (ioctl(ii->fd, SIOCGI2C, ii->ifr) != 0) { 744270064Smelifaro ii->error = errno; 745270064Smelifaro return (errno); 746270064Smelifaro } 747286810Smelifaro 748286810Smelifaro memcpy(&buf[i], req.data, l); 749286810Smelifaro len -= l; 750286810Smelifaro i += l; 751286810Smelifaro req.offset += l; 752270064Smelifaro } 753270064Smelifaro 754270064Smelifaro return (0); 755270064Smelifaro} 756270064Smelifaro 757286810Smelifarostatic void 758286810Smelifarodump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len) 759270064Smelifaro{ 760286810Smelifaro unsigned char buf[16]; 761286810Smelifaro int i, read; 762286810Smelifaro 763286810Smelifaro while (len > 0) { 764286810Smelifaro memset(buf, 0, sizeof(buf)); 765286810Smelifaro read = (len > sizeof(buf)) ? sizeof(buf) : len; 766286810Smelifaro read_i2c(ii, addr, off, read, buf); 767286810Smelifaro if (ii->error != 0) { 768286810Smelifaro fprintf(stderr, "Error reading i2c info\n"); 769286810Smelifaro return; 770286810Smelifaro } 771286810Smelifaro 772286810Smelifaro printf("\t"); 773286810Smelifaro for (i = 0; i < read; i++) 774286810Smelifaro printf("%02X ", buf[i]); 775286810Smelifaro printf("\n"); 776286810Smelifaro len -= read; 777286810Smelifaro off += read; 778286810Smelifaro } 779286810Smelifaro} 780286810Smelifaro 781286810Smelifarostatic void 782286810Smelifaroprint_qsfp_status(struct i2c_info *ii, int verbose) 783286810Smelifaro{ 784270064Smelifaro char buf[80], buf2[40], buf3[40]; 785286810Smelifaro uint32_t bitrate; 786286810Smelifaro int i; 787270064Smelifaro 788286810Smelifaro ii->qsfp = 1; 789270064Smelifaro 790286810Smelifaro /* Transceiver type */ 791286810Smelifaro get_qsfp_identifier(ii, buf, sizeof(buf)); 792286810Smelifaro get_qsfp_transceiver_class(ii, buf2, sizeof(buf2)); 793286810Smelifaro get_qsfp_connector(ii, buf3, sizeof(buf3)); 794286810Smelifaro if (ii->error == 0) 795286810Smelifaro printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3); 796286810Smelifaro print_sfp_vendor(ii, buf, sizeof(buf)); 797286810Smelifaro if (ii->error == 0) 798286810Smelifaro printf("\t%s\n", buf); 799270064Smelifaro 800286810Smelifaro if (verbose > 1) { 801286810Smelifaro get_qsfp_rev_compliance(ii, buf, sizeof(buf)); 802286810Smelifaro if (ii->error == 0) 803286810Smelifaro printf("\tcompliance level: %s\n", buf); 804286810Smelifaro 805286810Smelifaro bitrate = get_qsfp_br(ii); 806286810Smelifaro if (ii->error == 0 && bitrate > 0) 807286810Smelifaro printf("\tnominal bitrate: %u Mbps\n", bitrate); 808286810Smelifaro } 809286810Smelifaro 810297640Shselasky /* 811297640Shselasky * The standards in this area are not clear when the 812297640Shselasky * additional measurements are present or not. Use a valid 813297640Shselasky * temperature reading as an indicator for the presence of 814297640Shselasky * voltage and TX/RX power measurements. 815297640Shselasky */ 816297640Shselasky if (get_qsfp_temp(ii, buf, sizeof(buf)) == 0) { 817286810Smelifaro get_qsfp_voltage(ii, buf2, sizeof(buf2)); 818286810Smelifaro printf("\tmodule temperature: %s voltage: %s\n", buf, buf2); 819286810Smelifaro for (i = 1; i <= 4; i++) { 820286810Smelifaro get_qsfp_rx_power(ii, buf, sizeof(buf), i); 821286810Smelifaro get_qsfp_tx_power(ii, buf2, sizeof(buf2), i); 822286810Smelifaro printf("\tlane %d: RX: %s TX: %s\n", i, buf, buf2); 823286810Smelifaro } 824286810Smelifaro } 825286810Smelifaro 826286810Smelifaro if (verbose > 2) { 827286810Smelifaro printf("\n\tSFF8436 DUMP (0xA0 128..255 range):\n"); 828286810Smelifaro dump_i2c_data(ii, SFF_8436_BASE, 128, 128); 829286810Smelifaro printf("\n\tSFF8436 DUMP (0xA0 0..81 range):\n"); 830286810Smelifaro dump_i2c_data(ii, SFF_8436_BASE, 0, 82); 831286810Smelifaro } 832286810Smelifaro} 833286810Smelifaro 834286810Smelifarostatic void 835286810Smelifaroprint_sfp_status(struct i2c_info *ii, int verbose) 836286810Smelifaro{ 837286810Smelifaro char buf[80], buf2[40], buf3[40]; 838286810Smelifaro uint8_t diag_type, flags; 839286810Smelifaro 840270064Smelifaro /* Read diagnostic monitoring type */ 841286810Smelifaro read_i2c(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&diag_type); 842286810Smelifaro if (ii->error != 0) 843286810Smelifaro return; 844270064Smelifaro 845286810Smelifaro /* 846286810Smelifaro * Read monitoring data IFF it is supplied AND is 847286810Smelifaro * internally calibrated 848286810Smelifaro */ 849286810Smelifaro flags = SFF_8472_DDM_DONE | SFF_8472_DDM_INTERNAL; 850286810Smelifaro if ((diag_type & flags) == flags) 851286810Smelifaro ii->do_diag = 1; 852286810Smelifaro 853270064Smelifaro /* Transceiver type */ 854286810Smelifaro get_sfp_identifier(ii, buf, sizeof(buf)); 855286810Smelifaro get_sfp_transceiver_class(ii, buf2, sizeof(buf2)); 856286810Smelifaro get_sfp_connector(ii, buf3, sizeof(buf3)); 857286810Smelifaro if (ii->error == 0) 858286810Smelifaro printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3); 859286810Smelifaro print_sfp_vendor(ii, buf, sizeof(buf)); 860286810Smelifaro if (ii->error == 0) 861270064Smelifaro printf("\t%s\n", buf); 862286810Smelifaro 863286810Smelifaro if (verbose > 5) 864286810Smelifaro printf_sfp_transceiver_descr(ii, buf, sizeof(buf)); 865270064Smelifaro /* 866286810Smelifaro * Request current measurements iff they are provided: 867270064Smelifaro */ 868286810Smelifaro if (ii->do_diag != 0) { 869286810Smelifaro get_sfp_temp(ii, buf, sizeof(buf)); 870286810Smelifaro get_sfp_voltage(ii, buf2, sizeof(buf2)); 871286810Smelifaro printf("\tmodule temperature: %s Voltage: %s\n", buf, buf2); 872286810Smelifaro get_sfp_rx_power(ii, buf, sizeof(buf)); 873286810Smelifaro get_sfp_tx_power(ii, buf2, sizeof(buf2)); 874286810Smelifaro printf("\tRX: %s TX: %s\n", buf, buf2); 875270064Smelifaro } 876270064Smelifaro 877286810Smelifaro if (verbose > 2) { 878286810Smelifaro printf("\n\tSFF8472 DUMP (0xA0 0..127 range):\n"); 879286810Smelifaro dump_i2c_data(ii, SFF_8472_BASE, 0, 128); 880286810Smelifaro } 881270064Smelifaro} 882270064Smelifaro 883286810Smelifarovoid 884286810Smelifarosfp_status(int s, struct ifreq *ifr, int verbose) 885286810Smelifaro{ 886286810Smelifaro struct i2c_info ii; 887286810Smelifaro uint8_t id_byte; 888286810Smelifaro 889286810Smelifaro /* Prepare necessary into pass to i2c reader */ 890286810Smelifaro memset(&ii, 0, sizeof(ii)); 891286810Smelifaro ii.fd = s; 892286810Smelifaro ii.ifr = ifr; 893286810Smelifaro 894286810Smelifaro /* 895286810Smelifaro * Try to read byte 0 from i2c: 896286810Smelifaro * Both SFF-8472 and SFF-8436 use it as 897286810Smelifaro * 'identification byte'. 898286810Smelifaro * Stop reading status on zero as value - 899286810Smelifaro * this might happen in case of empty transceiver slot. 900286810Smelifaro */ 901286810Smelifaro id_byte = 0; 902286810Smelifaro read_i2c(&ii, SFF_8472_BASE, SFF_8472_ID, 1, (caddr_t)&id_byte); 903286810Smelifaro if (ii.error != 0 || id_byte == 0) 904286810Smelifaro return; 905286810Smelifaro 906286810Smelifaro switch (id_byte) { 907286810Smelifaro case SFF_8024_ID_QSFP: 908286810Smelifaro case SFF_8024_ID_QSFPPLUS: 909294202Smelifaro case SFF_8024_ID_QSFP28: 910286810Smelifaro print_qsfp_status(&ii, verbose); 911286810Smelifaro break; 912286810Smelifaro default: 913286810Smelifaro print_sfp_status(&ii, verbose); 914286810Smelifaro }; 915286810Smelifaro} 916286810Smelifaro 917