1f732123eSAlexander V. Chernikov /*- 2f732123eSAlexander V. Chernikov * Copyright (c) 2014 Alexander V. Chernikov. All rights reserved. 3f732123eSAlexander V. Chernikov * 4f732123eSAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 5f732123eSAlexander V. Chernikov * modification, are permitted provided that the following conditions 6f732123eSAlexander V. Chernikov * are met: 7f732123eSAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 8f732123eSAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 9f732123eSAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 10f732123eSAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 11f732123eSAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 12f732123eSAlexander V. Chernikov * 13f732123eSAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14f732123eSAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15f732123eSAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16f732123eSAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17f732123eSAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18f732123eSAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19f732123eSAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20f732123eSAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21f732123eSAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22f732123eSAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23f732123eSAlexander V. Chernikov * SUCH DAMAGE. 24f732123eSAlexander V. Chernikov */ 25f732123eSAlexander V. Chernikov 26f732123eSAlexander V. Chernikov #ifndef lint 27f732123eSAlexander V. Chernikov static const char rcsid[] = 28f732123eSAlexander V. Chernikov "$FreeBSD$"; 29f732123eSAlexander V. Chernikov #endif /* not lint */ 30f732123eSAlexander V. Chernikov 31f732123eSAlexander V. Chernikov #include <sys/types.h> 32f732123eSAlexander V. Chernikov #include <sys/param.h> 33f732123eSAlexander V. Chernikov #include <sys/ioctl.h> 34f732123eSAlexander V. Chernikov #include <sys/socket.h> 35f732123eSAlexander V. Chernikov 36f732123eSAlexander V. Chernikov #include <net/if.h> 37*f88c9741SAlexander V. Chernikov #include <net/sff8472.h> 38f732123eSAlexander V. Chernikov 39f732123eSAlexander V. Chernikov #include <math.h> 40f732123eSAlexander V. Chernikov #include <err.h> 41f732123eSAlexander V. Chernikov #include <errno.h> 42f732123eSAlexander V. Chernikov #include <stdio.h> 43f732123eSAlexander V. Chernikov #include <stdlib.h> 44f732123eSAlexander V. Chernikov #include <string.h> 45f732123eSAlexander V. Chernikov #include <unistd.h> 46f732123eSAlexander V. Chernikov 47f732123eSAlexander V. Chernikov #include "ifconfig.h" 48f732123eSAlexander V. Chernikov 49f732123eSAlexander V. Chernikov /* Definitions from Table 3.1 */ 50f732123eSAlexander V. Chernikov #define SFP_MSA_IDENTIFIER 0 /* Type of transceiver (T. 3.2), 1B */ 51f732123eSAlexander V. Chernikov #define SFP_MSA_CONNECTOR 2 /* Connector type (T. 3.3), 1B */ 52f732123eSAlexander V. Chernikov 53f732123eSAlexander V. Chernikov #define SFP_MSA_TRANSCEIVER_CLASS 3 /* Ethernet/Sonet/IB code, 1B */ 54f732123eSAlexander V. Chernikov 55f732123eSAlexander V. Chernikov #define SFP_MSA_VENDOR_NAME 20 /* ASCII vendor name, 16B */ 56f732123eSAlexander V. Chernikov #define SFP_MSA_VENDOR_PN 40 /* ASCII vendor partnum, 16B */ 57f732123eSAlexander V. Chernikov #define SFP_MSA_VENDOR_SN 68 /* ASCII vendor serialnum, 16B */ 58f732123eSAlexander V. Chernikov #define SFP_MSA_VENDOR_DATE 84 /* Vendor's date code, 8B */ 59f732123eSAlexander V. Chernikov #define SFP_MSA_DMONTYPE 92 /* Type of disagnostic monitoring, 1B */ 60f732123eSAlexander V. Chernikov 61f732123eSAlexander V. Chernikov /* Definitions from table 3.17 */ 62f732123eSAlexander V. Chernikov #define SFP_DDM_TEMP 96 /* Module temperature, 2B */ 63f732123eSAlexander V. Chernikov #define SFP_DDM_TXPOWER 102 /* Measured TX output power, 2B */ 64f732123eSAlexander V. Chernikov #define SFP_DDM_RXPOWER 104 /* Measured RX input power, 2B */ 65f732123eSAlexander V. Chernikov 66f732123eSAlexander V. Chernikov struct i2c_info; 67f732123eSAlexander V. Chernikov typedef int (read_i2c)(struct i2c_info *ii, uint8_t addr, uint8_t off, 68f732123eSAlexander V. Chernikov uint8_t len, caddr_t buf); 69f732123eSAlexander V. Chernikov 70f732123eSAlexander V. Chernikov struct i2c_info { 71f732123eSAlexander V. Chernikov int s; 72f732123eSAlexander V. Chernikov int error; 73f732123eSAlexander V. Chernikov struct ifreq *ifr; 74f732123eSAlexander V. Chernikov read_i2c *f; 75f732123eSAlexander V. Chernikov uint8_t diag_type; 76f732123eSAlexander V. Chernikov char *textbuf; 77f732123eSAlexander V. Chernikov size_t bufsize; 78f732123eSAlexander V. Chernikov }; 79f732123eSAlexander V. Chernikov 80f732123eSAlexander V. Chernikov struct _nv { 81f732123eSAlexander V. Chernikov int v; 82f732123eSAlexander V. Chernikov const char *n; 83f732123eSAlexander V. Chernikov }; 84f732123eSAlexander V. Chernikov 85f732123eSAlexander V. Chernikov const char *find_value(struct _nv *x, int value); 86f732123eSAlexander V. Chernikov const char *find_zero_bit(struct _nv *x, int value, int sz); 87f732123eSAlexander V. Chernikov 88f732123eSAlexander V. Chernikov /* SFF-8472 Rev. 11.4 table 3.4: Connector values */ 89f732123eSAlexander V. Chernikov static struct _nv conn[] = { 90f732123eSAlexander V. Chernikov { 0x00, "Unknown" }, 91f732123eSAlexander V. Chernikov { 0x01, "SC" }, 92f732123eSAlexander V. Chernikov { 0x02, "Fibre Channel Style 1 copper" }, 93f732123eSAlexander V. Chernikov { 0x03, "Fibre Channel Style 2 copper" }, 94f732123eSAlexander V. Chernikov { 0x04, "BNC/TNC" }, 95f732123eSAlexander V. Chernikov { 0x05, "Fibre Channel coaxial" }, 96f732123eSAlexander V. Chernikov { 0x06, "FiberJack" }, 97f732123eSAlexander V. Chernikov { 0x07, "LC" }, 98f732123eSAlexander V. Chernikov { 0x08, "MT-RJ" }, 99f732123eSAlexander V. Chernikov { 0x09, "MU" }, 100f732123eSAlexander V. Chernikov { 0x0A, "SG" }, 101f732123eSAlexander V. Chernikov { 0x0B, "Optical pigtail" }, 102f732123eSAlexander V. Chernikov { 0x0C, "MPO Parallel Optic" }, 103f732123eSAlexander V. Chernikov { 0x20, "HSSDC II" }, 104f732123eSAlexander V. Chernikov { 0x21, "Copper pigtail" }, 105f732123eSAlexander V. Chernikov { 0x22, "RJ45" }, 106f732123eSAlexander V. Chernikov { 0, NULL } 107f732123eSAlexander V. Chernikov }; 108f732123eSAlexander V. Chernikov 109f732123eSAlexander V. Chernikov /* SFF-8472 Rev. 11.4 table 3.5: Transceiver codes */ 110f732123eSAlexander V. Chernikov /* 10G Ethernet compliance codes, byte 3 */ 111f732123eSAlexander V. Chernikov static struct _nv eth_10g[] = { 112f732123eSAlexander V. Chernikov { 0x80, "10G Base-ER" }, 113f732123eSAlexander V. Chernikov { 0x40, "10G Base-LRM" }, 114f732123eSAlexander V. Chernikov { 0x20, "10G Base-LR" }, 115f732123eSAlexander V. Chernikov { 0x10, "10G Base-SR" }, 116f732123eSAlexander V. Chernikov { 0x08, "1X SX" }, 117f732123eSAlexander V. Chernikov { 0x04, "1X LX" }, 118f732123eSAlexander V. Chernikov { 0x02, "1X Copper Active" }, 119f732123eSAlexander V. Chernikov { 0x01, "1X Copper Passive" }, 120f732123eSAlexander V. Chernikov { 0, NULL } 121f732123eSAlexander V. Chernikov }; 122f732123eSAlexander V. Chernikov 123f732123eSAlexander V. Chernikov /* Ethernet compliance codes, byte 6 */ 124f732123eSAlexander V. Chernikov static struct _nv eth_compat[] = { 125f732123eSAlexander V. Chernikov { 0x80, "BASE-PX" }, 126f732123eSAlexander V. Chernikov { 0x40, "BASE-BX10" }, 127f732123eSAlexander V. Chernikov { 0x20, "100BASE-FX" }, 128f732123eSAlexander V. Chernikov { 0x10, "100BASE-LX/LX10" }, 129f732123eSAlexander V. Chernikov { 0x08, "1000BASE-T" }, 130f732123eSAlexander V. Chernikov { 0x04, "1000BASE-CX" }, 131f732123eSAlexander V. Chernikov { 0x02, "1000BASE-LX" }, 132f732123eSAlexander V. Chernikov { 0x01, "1000BASE-SX" }, 133f732123eSAlexander V. Chernikov { 0, NULL } 134f732123eSAlexander V. Chernikov }; 135f732123eSAlexander V. Chernikov 136f732123eSAlexander V. Chernikov /* FC link length, byte 7 */ 137f732123eSAlexander V. Chernikov static struct _nv fc_len[] = { 138f732123eSAlexander V. Chernikov { 0x80, "very long distance" }, 139f732123eSAlexander V. Chernikov { 0x40, "short distance" }, 140f732123eSAlexander V. Chernikov { 0x20, "intermediate distance" }, 141f732123eSAlexander V. Chernikov { 0x10, "long distance" }, 142f732123eSAlexander V. Chernikov { 0x08, "medium distance" }, 143f732123eSAlexander V. Chernikov { 0, NULL } 144f732123eSAlexander V. Chernikov }; 145f732123eSAlexander V. Chernikov 146f732123eSAlexander V. Chernikov /* Channel/Cable technology, byte 7-8 */ 147f732123eSAlexander V. Chernikov static struct _nv cab_tech[] = { 148f732123eSAlexander V. Chernikov { 0x0400, "Shortwave laser (SA)" }, 149f732123eSAlexander V. Chernikov { 0x0200, "Longwave laser (LC)" }, 150f732123eSAlexander V. Chernikov { 0x0100, "Electrical inter-enclosure (EL)" }, 151f732123eSAlexander V. Chernikov { 0x80, "Electrical intra-enclosure (EL)" }, 152f732123eSAlexander V. Chernikov { 0x40, "Shortwave laser (SN)" }, 153f732123eSAlexander V. Chernikov { 0x20, "Shortwave laser (SL)" }, 154f732123eSAlexander V. Chernikov { 0x10, "Longwave laser (LL)" }, 155f732123eSAlexander V. Chernikov { 0x08, "Active Cable" }, 156f732123eSAlexander V. Chernikov { 0x04, "Passive Cable" }, 157f732123eSAlexander V. Chernikov { 0, NULL } 158f732123eSAlexander V. Chernikov }; 159f732123eSAlexander V. Chernikov 160f732123eSAlexander V. Chernikov /* FC Transmission media, byte 9 */ 161f732123eSAlexander V. Chernikov static struct _nv fc_media[] = { 162f732123eSAlexander V. Chernikov { 0x80, "Twin Axial Pair" }, 163f732123eSAlexander V. Chernikov { 0x40, "Twisted Pair" }, 164f732123eSAlexander V. Chernikov { 0x20, "Miniature Coax" }, 165f732123eSAlexander V. Chernikov { 0x10, "Viao Coax" }, 166f732123eSAlexander V. Chernikov { 0x08, "Miltimode, 62.5um" }, 167f732123eSAlexander V. Chernikov { 0x04, "Multimode, 50um" }, 168f732123eSAlexander V. Chernikov { 0x02, "" }, 169f732123eSAlexander V. Chernikov { 0x01, "Single Mode" }, 170f732123eSAlexander V. Chernikov { 0, NULL } 171f732123eSAlexander V. Chernikov }; 172f732123eSAlexander V. Chernikov 173f732123eSAlexander V. Chernikov /* FC Speed, byte 10 */ 174f732123eSAlexander V. Chernikov static struct _nv fc_speed[] = { 175f732123eSAlexander V. Chernikov { 0x80, "1200 MBytes/sec" }, 176f732123eSAlexander V. Chernikov { 0x40, "800 MBytes/sec" }, 177f732123eSAlexander V. Chernikov { 0x20, "1600 MBytes/sec" }, 178f732123eSAlexander V. Chernikov { 0x10, "400 MBytes/sec" }, 179f732123eSAlexander V. Chernikov { 0x08, "3200 MBytes/sec" }, 180f732123eSAlexander V. Chernikov { 0x04, "200 MBytes/sec" }, 181f732123eSAlexander V. Chernikov { 0x01, "100 MBytes/sec" }, 182f732123eSAlexander V. Chernikov { 0, NULL } 183f732123eSAlexander V. Chernikov }; 184f732123eSAlexander V. Chernikov 185*f88c9741SAlexander V. Chernikov const char * 186*f88c9741SAlexander V. Chernikov find_value(struct _nv *x, int value) 187*f88c9741SAlexander V. Chernikov { 188*f88c9741SAlexander V. Chernikov for (; x->n != NULL; x++) 189*f88c9741SAlexander V. Chernikov if (x->v == value) 190*f88c9741SAlexander V. Chernikov return (x->n); 191*f88c9741SAlexander V. Chernikov return (NULL); 192*f88c9741SAlexander V. Chernikov } 193*f88c9741SAlexander V. Chernikov 194*f88c9741SAlexander V. Chernikov const char * 195*f88c9741SAlexander V. Chernikov find_zero_bit(struct _nv *x, int value, int sz) 196*f88c9741SAlexander V. Chernikov { 197*f88c9741SAlexander V. Chernikov int v, m; 198*f88c9741SAlexander V. Chernikov const char *s; 199*f88c9741SAlexander V. Chernikov 200*f88c9741SAlexander V. Chernikov v = 1; 201*f88c9741SAlexander V. Chernikov for (v = 1, m = 1 << (8 * sz); v < m; v *= 2) { 202*f88c9741SAlexander V. Chernikov if ((value & v) == 0) 203*f88c9741SAlexander V. Chernikov continue; 204*f88c9741SAlexander V. Chernikov if ((s = find_value(x, value & v)) != NULL) { 205*f88c9741SAlexander V. Chernikov value &= ~v; 206*f88c9741SAlexander V. Chernikov return (s); 207*f88c9741SAlexander V. Chernikov } 208*f88c9741SAlexander V. Chernikov } 209*f88c9741SAlexander V. Chernikov 210*f88c9741SAlexander V. Chernikov return (NULL); 211*f88c9741SAlexander V. Chernikov } 212*f88c9741SAlexander V. Chernikov 213*f88c9741SAlexander V. Chernikov static void 214*f88c9741SAlexander V. Chernikov get_sfp_identifier(struct i2c_info *ii, char *buf, size_t size) 215*f88c9741SAlexander V. Chernikov { 216*f88c9741SAlexander V. Chernikov const char *x; 217*f88c9741SAlexander V. Chernikov uint8_t data; 218*f88c9741SAlexander V. Chernikov 219*f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_ID, 1, (caddr_t)&data); 220*f88c9741SAlexander V. Chernikov 221*f88c9741SAlexander V. Chernikov x = NULL; 222*f88c9741SAlexander V. Chernikov if (data <= SFF_8472_ID_LAST) { 223*f88c9741SAlexander V. Chernikov x = NULL; 224*f88c9741SAlexander V. Chernikov //x = sff_8472_id[data]; 225*f88c9741SAlexander V. Chernikov } else { 226*f88c9741SAlexander V. Chernikov if (data > 0x80) 227*f88c9741SAlexander V. Chernikov x = "Vendor specific"; 228*f88c9741SAlexander V. Chernikov else 229*f88c9741SAlexander V. Chernikov x = "Reserved"; 230*f88c9741SAlexander V. Chernikov } 231*f88c9741SAlexander V. Chernikov 232*f88c9741SAlexander V. Chernikov snprintf(buf, size, "%s", x); 233*f88c9741SAlexander V. Chernikov } 234*f88c9741SAlexander V. Chernikov 235*f88c9741SAlexander V. Chernikov static void 236*f88c9741SAlexander V. Chernikov get_sfp_connector(struct i2c_info *ii, char *buf, size_t size) 237*f88c9741SAlexander V. Chernikov { 238*f88c9741SAlexander V. Chernikov const char *x; 239*f88c9741SAlexander V. Chernikov uint8_t data; 240*f88c9741SAlexander V. Chernikov 241*f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, (caddr_t)&data); 242*f88c9741SAlexander V. Chernikov 243*f88c9741SAlexander V. Chernikov if ((x = find_value(conn, data)) == NULL) { 244*f88c9741SAlexander V. Chernikov if (data >= 0x0D && data <= 0x1F) 245*f88c9741SAlexander V. Chernikov x = "Unallocated"; 246*f88c9741SAlexander V. Chernikov else if (data >= 0x23 && data <= 0x7F) 247*f88c9741SAlexander V. Chernikov x = "Unallocated"; 248*f88c9741SAlexander V. Chernikov else 249*f88c9741SAlexander V. Chernikov x = "Vendor specific"; 250*f88c9741SAlexander V. Chernikov } 251*f88c9741SAlexander V. Chernikov 252*f88c9741SAlexander V. Chernikov snprintf(buf, size, "%s", x); 253*f88c9741SAlexander V. Chernikov } 254*f88c9741SAlexander V. Chernikov 255f732123eSAlexander V. Chernikov static void 256f732123eSAlexander V. Chernikov printf_sfp_transceiver_descr(struct i2c_info *ii, char *buf, size_t size) 257f732123eSAlexander V. Chernikov { 258f732123eSAlexander V. Chernikov char xbuf[12]; 259f732123eSAlexander V. Chernikov const char *tech_class, *tech_len, *tech_tech, *tech_media, *tech_speed; 260f732123eSAlexander V. Chernikov 261f732123eSAlexander V. Chernikov tech_class = NULL; 262f732123eSAlexander V. Chernikov tech_len = NULL; 263f732123eSAlexander V. Chernikov tech_tech = NULL; 264f732123eSAlexander V. Chernikov tech_media = NULL; 265f732123eSAlexander V. Chernikov tech_speed = NULL; 266f732123eSAlexander V. Chernikov 267f732123eSAlexander V. Chernikov /* Read bytes 3-10 at once */ 268*f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, &xbuf[3]); 269f732123eSAlexander V. Chernikov 270f732123eSAlexander V. Chernikov /* Check 10G first */ 271f732123eSAlexander V. Chernikov tech_class = find_zero_bit(eth_10g, xbuf[3], 1); 272f732123eSAlexander V. Chernikov if (tech_class == NULL) { 273f732123eSAlexander V. Chernikov /* No match. Try 1G */ 274f732123eSAlexander V. Chernikov tech_class = find_zero_bit(eth_compat, xbuf[6], 1); 275f732123eSAlexander V. Chernikov } 276f732123eSAlexander V. Chernikov 277f732123eSAlexander V. Chernikov tech_len = find_zero_bit(fc_len, xbuf[7], 1); 278f732123eSAlexander V. Chernikov tech_tech = find_zero_bit(cab_tech, xbuf[7] << 8 | xbuf[8], 2); 279f732123eSAlexander V. Chernikov tech_media = find_zero_bit(fc_media, xbuf[9], 1); 280f732123eSAlexander V. Chernikov tech_speed = find_zero_bit(fc_speed, xbuf[10], 1); 281f732123eSAlexander V. Chernikov 282f732123eSAlexander V. Chernikov printf("Class: %s\n", tech_class); 283f732123eSAlexander V. Chernikov printf("Length: %s\n", tech_len); 284f732123eSAlexander V. Chernikov printf("Tech: %s\n", tech_tech); 285f732123eSAlexander V. Chernikov printf("Media: %s\n", tech_media); 286f732123eSAlexander V. Chernikov printf("Speed: %s\n", tech_speed); 287f732123eSAlexander V. Chernikov } 288f732123eSAlexander V. Chernikov 289f732123eSAlexander V. Chernikov static void 290f732123eSAlexander V. Chernikov get_sfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size) 291f732123eSAlexander V. Chernikov { 292f732123eSAlexander V. Chernikov const char *tech_class; 293f732123eSAlexander V. Chernikov uint8_t code; 294f732123eSAlexander V. Chernikov 295f732123eSAlexander V. Chernikov /* Check 10G Ethernet/IB first */ 296*f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, (caddr_t)&code); 297f732123eSAlexander V. Chernikov tech_class = find_zero_bit(eth_10g, code, 1); 298f732123eSAlexander V. Chernikov if (tech_class == NULL) { 299f732123eSAlexander V. Chernikov /* No match. Try Ethernet 1G */ 300*f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3, 301*f88c9741SAlexander V. Chernikov 1, (caddr_t)&code); 302f732123eSAlexander V. Chernikov tech_class = find_zero_bit(eth_compat, code, 1); 303f732123eSAlexander V. Chernikov } 304f732123eSAlexander V. Chernikov 305f732123eSAlexander V. Chernikov if (tech_class == NULL) 306f732123eSAlexander V. Chernikov tech_class = "Unknown"; 307f732123eSAlexander V. Chernikov 308f732123eSAlexander V. Chernikov snprintf(buf, size, "%s", tech_class); 309f732123eSAlexander V. Chernikov } 310f732123eSAlexander V. Chernikov 311f732123eSAlexander V. Chernikov 312f732123eSAlexander V. Chernikov static void 313f732123eSAlexander V. Chernikov get_sfp_vendor_name(struct i2c_info *ii, char *buf, size_t size) 314f732123eSAlexander V. Chernikov { 315f732123eSAlexander V. Chernikov char xbuf[17], *p; 316f732123eSAlexander V. Chernikov 317f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 318f732123eSAlexander V. Chernikov /* ASCII String, right-padded with 0x20 */ 319*f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, 16, xbuf); 320f732123eSAlexander V. Chernikov for (p = &xbuf[16]; *(p - 1) == 0x20; p--) 321f732123eSAlexander V. Chernikov ; 322f732123eSAlexander V. Chernikov *p = '\0'; 323f732123eSAlexander V. Chernikov 324f732123eSAlexander V. Chernikov snprintf(buf, size, "%s", xbuf); 325f732123eSAlexander V. Chernikov } 326f732123eSAlexander V. Chernikov 327f732123eSAlexander V. Chernikov static void 328f732123eSAlexander V. Chernikov get_sfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size) 329f732123eSAlexander V. Chernikov { 330f732123eSAlexander V. Chernikov char xbuf[17], *p; 331f732123eSAlexander V. Chernikov 332f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 333f732123eSAlexander V. Chernikov /* ASCII String, right-padded with 0x20 */ 334*f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_PN_START, 16, xbuf); 335f732123eSAlexander V. Chernikov for (p = &xbuf[16]; *(p - 1) == 0x20; p--) 336f732123eSAlexander V. Chernikov ; 337f732123eSAlexander V. Chernikov *p = '\0'; 338f732123eSAlexander V. Chernikov 339f732123eSAlexander V. Chernikov snprintf(buf, size, "%s", xbuf); 340f732123eSAlexander V. Chernikov } 341f732123eSAlexander V. Chernikov 342f732123eSAlexander V. Chernikov static void 343f732123eSAlexander V. Chernikov get_sfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size) 344f732123eSAlexander V. Chernikov { 345f732123eSAlexander V. Chernikov char xbuf[17], *p; 346f732123eSAlexander V. Chernikov 347f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 348f732123eSAlexander V. Chernikov /* ASCII String, right-padded with 0x20 */ 349*f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_SN_START, 16, xbuf); 350f732123eSAlexander V. Chernikov for (p = &xbuf[16]; *(p - 1) == 0x20; p--) 351f732123eSAlexander V. Chernikov ; 352f732123eSAlexander V. Chernikov *p = '\0'; 353f732123eSAlexander V. Chernikov snprintf(buf, size, "%s", xbuf); 354f732123eSAlexander V. Chernikov } 355f732123eSAlexander V. Chernikov 356f732123eSAlexander V. Chernikov static void 357f732123eSAlexander V. Chernikov get_sfp_vendor_date(struct i2c_info *ii, char *buf, size_t size) 358f732123eSAlexander V. Chernikov { 359f732123eSAlexander V. Chernikov char xbuf[6]; 360f732123eSAlexander V. Chernikov 361f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 362f732123eSAlexander V. Chernikov /* Date code, see Table 3.8 for description */ 363*f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_DATE_START, 6, xbuf); 364f732123eSAlexander V. Chernikov snprintf(buf, size, "20%c%c-%c%c-%c%c", xbuf[0], xbuf[1], 365f732123eSAlexander V. Chernikov xbuf[2], xbuf[3], xbuf[4], xbuf[5]); 366f732123eSAlexander V. Chernikov } 367f732123eSAlexander V. Chernikov 368f732123eSAlexander V. Chernikov static void 369f732123eSAlexander V. Chernikov print_sfp_vendor(struct i2c_info *ii, char *buf, size_t size) 370f732123eSAlexander V. Chernikov { 371f732123eSAlexander V. Chernikov char xbuf[80]; 372f732123eSAlexander V. Chernikov 373f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 374f732123eSAlexander V. Chernikov get_sfp_vendor_name(ii, xbuf, 20); 375f732123eSAlexander V. Chernikov get_sfp_vendor_pn(ii, &xbuf[20], 20); 376f732123eSAlexander V. Chernikov get_sfp_vendor_sn(ii, &xbuf[40], 20); 377f732123eSAlexander V. Chernikov get_sfp_vendor_date(ii, &xbuf[60], 20); 378f732123eSAlexander V. Chernikov 379f732123eSAlexander V. Chernikov snprintf(buf, size, "vendor: %s PN: %s SN: %s DATE: %s", 380f732123eSAlexander V. Chernikov xbuf, &xbuf[20], &xbuf[40], &xbuf[60]); 381f732123eSAlexander V. Chernikov } 382f732123eSAlexander V. Chernikov 383f732123eSAlexander V. Chernikov static void 384f732123eSAlexander V. Chernikov get_sfp_temp(struct i2c_info *ii, char *buf, size_t size) 385f732123eSAlexander V. Chernikov { 386f732123eSAlexander V. Chernikov char xbuf[2]; 387f732123eSAlexander V. Chernikov 388f732123eSAlexander V. Chernikov int8_t major; 389f732123eSAlexander V. Chernikov uint8_t minor; 390f732123eSAlexander V. Chernikov int k; 391f732123eSAlexander V. Chernikov 392f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 393*f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_DIAG, SFF_8472_TEMP, 2, xbuf); 394f732123eSAlexander V. Chernikov 395f732123eSAlexander V. Chernikov /* Convert temperature to string according to table 3.13 */ 396f732123eSAlexander V. Chernikov major = (int8_t)xbuf[0]; 397f732123eSAlexander V. Chernikov minor = (uint8_t)buf[1]; 398f732123eSAlexander V. Chernikov k = minor * 1000 / 256; 399f732123eSAlexander V. Chernikov 400f732123eSAlexander V. Chernikov snprintf(buf, size, "%d.%d C", major, k / 100); 401f732123eSAlexander V. Chernikov } 402f732123eSAlexander V. Chernikov 403f732123eSAlexander V. Chernikov static void 404f732123eSAlexander V. Chernikov convert_power(struct i2c_info *ii, char *xbuf, char *buf, size_t size) 405f732123eSAlexander V. Chernikov { 406f732123eSAlexander V. Chernikov uint16_t mW; 407f732123eSAlexander V. Chernikov double dbm; 408f732123eSAlexander V. Chernikov 409f732123eSAlexander V. Chernikov mW = ((uint8_t)xbuf[0] << 8) + (uint8_t)xbuf[1]; 410f732123eSAlexander V. Chernikov 411f732123eSAlexander V. Chernikov /* Convert mw to dbm */ 412f732123eSAlexander V. Chernikov dbm = 10.0 * log10(1.0 * mW / 10000); 413f732123eSAlexander V. Chernikov 414f732123eSAlexander V. Chernikov /* Table 3.9, bit 5 is set, internally calibrated */ 415f732123eSAlexander V. Chernikov if ((ii->diag_type & 0x20) != 0) { 416f732123eSAlexander V. Chernikov snprintf(buf, size, "%d.%02d mW (%.2f dBm)", 417f732123eSAlexander V. Chernikov mW / 10000, (mW % 10000) / 100, dbm); 418f732123eSAlexander V. Chernikov } 419f732123eSAlexander V. Chernikov } 420f732123eSAlexander V. Chernikov 421f732123eSAlexander V. Chernikov static void 422f732123eSAlexander V. Chernikov get_sfp_rx_power(struct i2c_info *ii, char *buf, size_t size) 423f732123eSAlexander V. Chernikov { 424f732123eSAlexander V. Chernikov char xbuf[2]; 425f732123eSAlexander V. Chernikov 426f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 427*f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_DIAG, SFF_8472_RX_POWER, 2, xbuf); 428f732123eSAlexander V. Chernikov convert_power(ii, xbuf, buf, size); 429f732123eSAlexander V. Chernikov } 430f732123eSAlexander V. Chernikov 431f732123eSAlexander V. Chernikov static void 432f732123eSAlexander V. Chernikov get_sfp_tx_power(struct i2c_info *ii, char *buf, size_t size) 433f732123eSAlexander V. Chernikov { 434f732123eSAlexander V. Chernikov char xbuf[2]; 435f732123eSAlexander V. Chernikov 436f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 437*f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_DIAG, SFF_8472_TX_POWER, 2, xbuf); 438f732123eSAlexander V. Chernikov convert_power(ii, xbuf, buf, size); 439f732123eSAlexander V. Chernikov } 440f732123eSAlexander V. Chernikov 441f732123eSAlexander V. Chernikov /* Intel ixgbe-specific structures and handlers */ 442f732123eSAlexander V. Chernikov struct ixgbe_i2c_req { 443f732123eSAlexander V. Chernikov uint8_t dev_addr; 444f732123eSAlexander V. Chernikov uint8_t offset; 445f732123eSAlexander V. Chernikov uint8_t len; 446f732123eSAlexander V. Chernikov uint8_t data[8]; 447f732123eSAlexander V. Chernikov }; 448f732123eSAlexander V. Chernikov #define SIOCGI2C SIOCGIFGENERIC 449f732123eSAlexander V. Chernikov 450f732123eSAlexander V. Chernikov static int 451f732123eSAlexander V. Chernikov read_i2c_ixgbe(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len, 452f732123eSAlexander V. Chernikov caddr_t buf) 453f732123eSAlexander V. Chernikov { 454f732123eSAlexander V. Chernikov struct ixgbe_i2c_req ixreq; 455f732123eSAlexander V. Chernikov int i; 456f732123eSAlexander V. Chernikov 457f732123eSAlexander V. Chernikov if (ii->error != 0) 458f732123eSAlexander V. Chernikov return (ii->error); 459f732123eSAlexander V. Chernikov 460f732123eSAlexander V. Chernikov ii->ifr->ifr_data = (caddr_t)&ixreq; 461f732123eSAlexander V. Chernikov 462f732123eSAlexander V. Chernikov memset(&ixreq, 0, sizeof(ixreq)); 463f732123eSAlexander V. Chernikov ixreq.dev_addr = addr; 464f732123eSAlexander V. Chernikov 465f732123eSAlexander V. Chernikov for (i = 0; i < len; i += 1) { 466f732123eSAlexander V. Chernikov ixreq.offset = off + i; 467f732123eSAlexander V. Chernikov ixreq.len = 1; 468f732123eSAlexander V. Chernikov 469f732123eSAlexander V. Chernikov if (ioctl(ii->s, SIOCGI2C, ii->ifr) != 0) { 470f732123eSAlexander V. Chernikov ii->error = errno; 471f732123eSAlexander V. Chernikov return (errno); 472f732123eSAlexander V. Chernikov } 473f732123eSAlexander V. Chernikov memcpy(&buf[i], ixreq.data, 1); 474f732123eSAlexander V. Chernikov } 475f732123eSAlexander V. Chernikov 476f732123eSAlexander V. Chernikov return (0); 477f732123eSAlexander V. Chernikov } 478f732123eSAlexander V. Chernikov 479f732123eSAlexander V. Chernikov void 480f732123eSAlexander V. Chernikov sfp_status(int s, struct ifreq *ifr, int verbose) 481f732123eSAlexander V. Chernikov { 482f732123eSAlexander V. Chernikov struct i2c_info ii; 483f732123eSAlexander V. Chernikov char buf[80], buf2[40], buf3[40]; 484f732123eSAlexander V. Chernikov 485f732123eSAlexander V. Chernikov /* 486f732123eSAlexander V. Chernikov * Check if we have i2c support for particular driver. 487f732123eSAlexander V. Chernikov * TODO: Determine driver by original name. 488f732123eSAlexander V. Chernikov */ 489f732123eSAlexander V. Chernikov memset(&ii, 0, sizeof(ii)); 490f732123eSAlexander V. Chernikov if (strncmp(ifr->ifr_name, "ix", 2) == 0) { 491f732123eSAlexander V. Chernikov ii.f = read_i2c_ixgbe; 492f732123eSAlexander V. Chernikov } else 493f732123eSAlexander V. Chernikov return; 494f732123eSAlexander V. Chernikov 495f732123eSAlexander V. Chernikov /* Prepare necessary into to pass to NIC handler */ 496f732123eSAlexander V. Chernikov ii.s = s; 497f732123eSAlexander V. Chernikov ii.ifr = ifr; 498f732123eSAlexander V. Chernikov 499f732123eSAlexander V. Chernikov /* Read diagnostic monitoring type */ 500*f88c9741SAlexander V. Chernikov ii.f(&ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&ii.diag_type); 501f732123eSAlexander V. Chernikov 502f732123eSAlexander V. Chernikov /* Transceiver type */ 503f732123eSAlexander V. Chernikov get_sfp_identifier(&ii, buf, sizeof(buf)); 504f732123eSAlexander V. Chernikov get_sfp_transceiver_class(&ii, buf2, sizeof(buf2)); 505f732123eSAlexander V. Chernikov get_sfp_connector(&ii, buf3, sizeof(buf3)); 506f732123eSAlexander V. Chernikov if (ii.error == 0) 507f732123eSAlexander V. Chernikov printf("\ti2c: %s %s (%s)\n", buf, buf2, buf3); 508f732123eSAlexander V. Chernikov if (verbose > 2) 509f732123eSAlexander V. Chernikov printf_sfp_transceiver_descr(&ii, buf, sizeof(buf)); 510f732123eSAlexander V. Chernikov print_sfp_vendor(&ii, buf, sizeof(buf)); 511f732123eSAlexander V. Chernikov if (ii.error == 0) 512f732123eSAlexander V. Chernikov printf("\t%s\n", buf); 513*f88c9741SAlexander V. Chernikov 514f732123eSAlexander V. Chernikov /* 515*f88c9741SAlexander V. Chernikov * Request current measurements iff they are provided: 516f732123eSAlexander V. Chernikov * Bit 6 must be set. 517f732123eSAlexander V. Chernikov */ 518f732123eSAlexander V. Chernikov if ((ii.diag_type & 0x40) != 0) { 519f732123eSAlexander V. Chernikov get_sfp_temp(&ii, buf, sizeof(buf)); 520f732123eSAlexander V. Chernikov get_sfp_rx_power(&ii, buf2, sizeof(buf2)); 521f732123eSAlexander V. Chernikov get_sfp_tx_power(&ii, buf3, sizeof(buf3)); 522f732123eSAlexander V. Chernikov printf("\tTemp: %s RX: %s TX: %s\n", buf, buf2, buf3); 523f732123eSAlexander V. Chernikov } 524f732123eSAlexander V. Chernikov } 525f732123eSAlexander V. Chernikov 526