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*c59adfc6SAlexander V. Chernikov #include <net/sff8436.h> 38f88c9741SAlexander V. Chernikov #include <net/sff8472.h> 39f732123eSAlexander V. Chernikov 40f732123eSAlexander V. Chernikov #include <math.h> 41f732123eSAlexander V. Chernikov #include <err.h> 42f732123eSAlexander V. Chernikov #include <errno.h> 43*c59adfc6SAlexander V. Chernikov #include <fcntl.h> 44f732123eSAlexander V. Chernikov #include <stdio.h> 45f732123eSAlexander V. Chernikov #include <stdlib.h> 46f732123eSAlexander V. Chernikov #include <string.h> 47f732123eSAlexander V. Chernikov #include <unistd.h> 48f732123eSAlexander V. Chernikov 49f732123eSAlexander V. Chernikov #include "ifconfig.h" 50f732123eSAlexander V. Chernikov 51f732123eSAlexander V. Chernikov struct i2c_info; 52f732123eSAlexander V. Chernikov typedef int (read_i2c)(struct i2c_info *ii, uint8_t addr, uint8_t off, 53f732123eSAlexander V. Chernikov uint8_t len, caddr_t buf); 54f732123eSAlexander V. Chernikov 55f732123eSAlexander V. Chernikov struct i2c_info { 56f732123eSAlexander V. Chernikov int s; 57f732123eSAlexander V. Chernikov int error; 58*c59adfc6SAlexander V. Chernikov int bshift; 59*c59adfc6SAlexander V. Chernikov int qsfp; 60*c59adfc6SAlexander V. Chernikov int do_diag; 61f732123eSAlexander V. Chernikov struct ifreq *ifr; 62f732123eSAlexander V. Chernikov read_i2c *f; 63f732123eSAlexander V. Chernikov char *textbuf; 64f732123eSAlexander V. Chernikov size_t bufsize; 65*c59adfc6SAlexander V. Chernikov int cfd; 66*c59adfc6SAlexander V. Chernikov int port_id; 67*c59adfc6SAlexander V. Chernikov int chip_id; 68f732123eSAlexander V. Chernikov }; 69f732123eSAlexander V. Chernikov 70f732123eSAlexander V. Chernikov struct _nv { 71f732123eSAlexander V. Chernikov int v; 72f732123eSAlexander V. Chernikov const char *n; 73f732123eSAlexander V. Chernikov }; 74f732123eSAlexander V. Chernikov 75f732123eSAlexander V. Chernikov const char *find_value(struct _nv *x, int value); 76f732123eSAlexander V. Chernikov const char *find_zero_bit(struct _nv *x, int value, int sz); 77f732123eSAlexander V. Chernikov 78f732123eSAlexander V. Chernikov /* SFF-8472 Rev. 11.4 table 3.4: Connector values */ 79f732123eSAlexander V. Chernikov static struct _nv conn[] = { 80f732123eSAlexander V. Chernikov { 0x00, "Unknown" }, 81f732123eSAlexander V. Chernikov { 0x01, "SC" }, 82f732123eSAlexander V. Chernikov { 0x02, "Fibre Channel Style 1 copper" }, 83f732123eSAlexander V. Chernikov { 0x03, "Fibre Channel Style 2 copper" }, 84f732123eSAlexander V. Chernikov { 0x04, "BNC/TNC" }, 85f732123eSAlexander V. Chernikov { 0x05, "Fibre Channel coaxial" }, 86f732123eSAlexander V. Chernikov { 0x06, "FiberJack" }, 87f732123eSAlexander V. Chernikov { 0x07, "LC" }, 88f732123eSAlexander V. Chernikov { 0x08, "MT-RJ" }, 89f732123eSAlexander V. Chernikov { 0x09, "MU" }, 90f732123eSAlexander V. Chernikov { 0x0A, "SG" }, 91f732123eSAlexander V. Chernikov { 0x0B, "Optical pigtail" }, 92f732123eSAlexander V. Chernikov { 0x0C, "MPO Parallel Optic" }, 93f732123eSAlexander V. Chernikov { 0x20, "HSSDC II" }, 94f732123eSAlexander V. Chernikov { 0x21, "Copper pigtail" }, 95f732123eSAlexander V. Chernikov { 0x22, "RJ45" }, 96*c59adfc6SAlexander V. Chernikov { 0x23, "No separate connector" }, /* SFF-8436 */ 97f732123eSAlexander V. Chernikov { 0, NULL } 98f732123eSAlexander V. Chernikov }; 99f732123eSAlexander V. Chernikov 100f732123eSAlexander V. Chernikov /* SFF-8472 Rev. 11.4 table 3.5: Transceiver codes */ 101*c59adfc6SAlexander V. Chernikov /* 10G Ethernet/IB compliance codes, byte 3 */ 102f732123eSAlexander V. Chernikov static struct _nv eth_10g[] = { 103f732123eSAlexander V. Chernikov { 0x80, "10G Base-ER" }, 104f732123eSAlexander V. Chernikov { 0x40, "10G Base-LRM" }, 105f732123eSAlexander V. Chernikov { 0x20, "10G Base-LR" }, 106f732123eSAlexander V. Chernikov { 0x10, "10G Base-SR" }, 107f732123eSAlexander V. Chernikov { 0x08, "1X SX" }, 108f732123eSAlexander V. Chernikov { 0x04, "1X LX" }, 109f732123eSAlexander V. Chernikov { 0x02, "1X Copper Active" }, 110f732123eSAlexander V. Chernikov { 0x01, "1X Copper Passive" }, 111f732123eSAlexander V. Chernikov { 0, NULL } 112f732123eSAlexander V. Chernikov }; 113f732123eSAlexander V. Chernikov 114f732123eSAlexander V. Chernikov /* Ethernet compliance codes, byte 6 */ 115f732123eSAlexander V. Chernikov static struct _nv eth_compat[] = { 116f732123eSAlexander V. Chernikov { 0x80, "BASE-PX" }, 117f732123eSAlexander V. Chernikov { 0x40, "BASE-BX10" }, 118f732123eSAlexander V. Chernikov { 0x20, "100BASE-FX" }, 119f732123eSAlexander V. Chernikov { 0x10, "100BASE-LX/LX10" }, 120f732123eSAlexander V. Chernikov { 0x08, "1000BASE-T" }, 121f732123eSAlexander V. Chernikov { 0x04, "1000BASE-CX" }, 122f732123eSAlexander V. Chernikov { 0x02, "1000BASE-LX" }, 123f732123eSAlexander V. Chernikov { 0x01, "1000BASE-SX" }, 124f732123eSAlexander V. Chernikov { 0, NULL } 125f732123eSAlexander V. Chernikov }; 126f732123eSAlexander V. Chernikov 127f732123eSAlexander V. Chernikov /* FC link length, byte 7 */ 128f732123eSAlexander V. Chernikov static struct _nv fc_len[] = { 129f732123eSAlexander V. Chernikov { 0x80, "very long distance" }, 130f732123eSAlexander V. Chernikov { 0x40, "short distance" }, 131f732123eSAlexander V. Chernikov { 0x20, "intermediate distance" }, 132f732123eSAlexander V. Chernikov { 0x10, "long distance" }, 133f732123eSAlexander V. Chernikov { 0x08, "medium distance" }, 134f732123eSAlexander V. Chernikov { 0, NULL } 135f732123eSAlexander V. Chernikov }; 136f732123eSAlexander V. Chernikov 137f732123eSAlexander V. Chernikov /* Channel/Cable technology, byte 7-8 */ 138f732123eSAlexander V. Chernikov static struct _nv cab_tech[] = { 139f732123eSAlexander V. Chernikov { 0x0400, "Shortwave laser (SA)" }, 140f732123eSAlexander V. Chernikov { 0x0200, "Longwave laser (LC)" }, 141f732123eSAlexander V. Chernikov { 0x0100, "Electrical inter-enclosure (EL)" }, 142f732123eSAlexander V. Chernikov { 0x80, "Electrical intra-enclosure (EL)" }, 143f732123eSAlexander V. Chernikov { 0x40, "Shortwave laser (SN)" }, 144f732123eSAlexander V. Chernikov { 0x20, "Shortwave laser (SL)" }, 145f732123eSAlexander V. Chernikov { 0x10, "Longwave laser (LL)" }, 146f732123eSAlexander V. Chernikov { 0x08, "Active Cable" }, 147f732123eSAlexander V. Chernikov { 0x04, "Passive Cable" }, 148f732123eSAlexander V. Chernikov { 0, NULL } 149f732123eSAlexander V. Chernikov }; 150f732123eSAlexander V. Chernikov 151f732123eSAlexander V. Chernikov /* FC Transmission media, byte 9 */ 152f732123eSAlexander V. Chernikov static struct _nv fc_media[] = { 153f732123eSAlexander V. Chernikov { 0x80, "Twin Axial Pair" }, 154f732123eSAlexander V. Chernikov { 0x40, "Twisted Pair" }, 155f732123eSAlexander V. Chernikov { 0x20, "Miniature Coax" }, 156f732123eSAlexander V. Chernikov { 0x10, "Viao Coax" }, 157f732123eSAlexander V. Chernikov { 0x08, "Miltimode, 62.5um" }, 158f732123eSAlexander V. Chernikov { 0x04, "Multimode, 50um" }, 159f732123eSAlexander V. Chernikov { 0x02, "" }, 160f732123eSAlexander V. Chernikov { 0x01, "Single Mode" }, 161f732123eSAlexander V. Chernikov { 0, NULL } 162f732123eSAlexander V. Chernikov }; 163f732123eSAlexander V. Chernikov 164f732123eSAlexander V. Chernikov /* FC Speed, byte 10 */ 165f732123eSAlexander V. Chernikov static struct _nv fc_speed[] = { 166f732123eSAlexander V. Chernikov { 0x80, "1200 MBytes/sec" }, 167f732123eSAlexander V. Chernikov { 0x40, "800 MBytes/sec" }, 168f732123eSAlexander V. Chernikov { 0x20, "1600 MBytes/sec" }, 169f732123eSAlexander V. Chernikov { 0x10, "400 MBytes/sec" }, 170f732123eSAlexander V. Chernikov { 0x08, "3200 MBytes/sec" }, 171f732123eSAlexander V. Chernikov { 0x04, "200 MBytes/sec" }, 172f732123eSAlexander V. Chernikov { 0x01, "100 MBytes/sec" }, 173f732123eSAlexander V. Chernikov { 0, NULL } 174f732123eSAlexander V. Chernikov }; 175f732123eSAlexander V. Chernikov 176*c59adfc6SAlexander V. Chernikov /* SFF-8436 Rev. 4.8 table 33: Specification compliance */ 177*c59adfc6SAlexander V. Chernikov 178*c59adfc6SAlexander V. Chernikov /* 10/40G Ethernet compliance codes, byte 128 + 3 */ 179*c59adfc6SAlexander V. Chernikov static struct _nv eth_1040g[] = { 180*c59adfc6SAlexander V. Chernikov { 0x80, "Reserved" }, 181*c59adfc6SAlexander V. Chernikov { 0x40, "10GBASE-LRM" }, 182*c59adfc6SAlexander V. Chernikov { 0x20, "10GBASE-LR" }, 183*c59adfc6SAlexander V. Chernikov { 0x10, "10GBASE-SR" }, 184*c59adfc6SAlexander V. Chernikov { 0x08, "40GBASE-CR4" }, 185*c59adfc6SAlexander V. Chernikov { 0x04, "40GBASE-SR4" }, 186*c59adfc6SAlexander V. Chernikov { 0x02, "40GBASE-LR4" }, 187*c59adfc6SAlexander V. Chernikov { 0x01, "40G Active Cable" }, 188*c59adfc6SAlexander V. Chernikov { 0, NULL } 189*c59adfc6SAlexander V. Chernikov }; 190*c59adfc6SAlexander V. Chernikov 191f88c9741SAlexander V. Chernikov const char * 192f88c9741SAlexander V. Chernikov find_value(struct _nv *x, int value) 193f88c9741SAlexander V. Chernikov { 194f88c9741SAlexander V. Chernikov for (; x->n != NULL; x++) 195f88c9741SAlexander V. Chernikov if (x->v == value) 196f88c9741SAlexander V. Chernikov return (x->n); 197f88c9741SAlexander V. Chernikov return (NULL); 198f88c9741SAlexander V. Chernikov } 199f88c9741SAlexander V. Chernikov 200f88c9741SAlexander V. Chernikov const char * 201f88c9741SAlexander V. Chernikov find_zero_bit(struct _nv *x, int value, int sz) 202f88c9741SAlexander V. Chernikov { 203f88c9741SAlexander V. Chernikov int v, m; 204f88c9741SAlexander V. Chernikov const char *s; 205f88c9741SAlexander V. Chernikov 206f88c9741SAlexander V. Chernikov v = 1; 207f88c9741SAlexander V. Chernikov for (v = 1, m = 1 << (8 * sz); v < m; v *= 2) { 208f88c9741SAlexander V. Chernikov if ((value & v) == 0) 209f88c9741SAlexander V. Chernikov continue; 210f88c9741SAlexander V. Chernikov if ((s = find_value(x, value & v)) != NULL) { 211f88c9741SAlexander V. Chernikov value &= ~v; 212f88c9741SAlexander V. Chernikov return (s); 213f88c9741SAlexander V. Chernikov } 214f88c9741SAlexander V. Chernikov } 215f88c9741SAlexander V. Chernikov 216f88c9741SAlexander V. Chernikov return (NULL); 217f88c9741SAlexander V. Chernikov } 218f88c9741SAlexander V. Chernikov 219f88c9741SAlexander V. Chernikov static void 220*c59adfc6SAlexander V. Chernikov convert_sff_identifier(char *buf, size_t size, uint8_t value) 221f88c9741SAlexander V. Chernikov { 222f88c9741SAlexander V. Chernikov const char *x; 223f88c9741SAlexander V. Chernikov 224f88c9741SAlexander V. Chernikov x = NULL; 225*c59adfc6SAlexander V. Chernikov if (value <= SFF_8024_ID_LAST) 226*c59adfc6SAlexander V. Chernikov x = sff_8024_id[value]; 22746c9382cSAlexander V. Chernikov else { 228*c59adfc6SAlexander V. Chernikov if (value > 0x80) 229f88c9741SAlexander V. Chernikov x = "Vendor specific"; 230f88c9741SAlexander V. Chernikov else 231f88c9741SAlexander V. Chernikov x = "Reserved"; 232f88c9741SAlexander V. Chernikov } 233f88c9741SAlexander V. Chernikov 234f88c9741SAlexander V. Chernikov snprintf(buf, size, "%s", x); 235f88c9741SAlexander V. Chernikov } 236f88c9741SAlexander V. Chernikov 237f88c9741SAlexander V. Chernikov static void 238*c59adfc6SAlexander V. Chernikov convert_sff_connector(char *buf, size_t size, uint8_t value) 239f88c9741SAlexander V. Chernikov { 240f88c9741SAlexander V. Chernikov const char *x; 241f88c9741SAlexander V. Chernikov 242*c59adfc6SAlexander V. Chernikov if ((x = find_value(conn, value)) == NULL) { 243*c59adfc6SAlexander V. Chernikov if (value >= 0x0D && value <= 0x1F) 244f88c9741SAlexander V. Chernikov x = "Unallocated"; 245*c59adfc6SAlexander V. Chernikov else if (value >= 0x24 && value <= 0x7F) 246f88c9741SAlexander V. Chernikov x = "Unallocated"; 247f88c9741SAlexander V. Chernikov else 248f88c9741SAlexander V. Chernikov x = "Vendor specific"; 249f88c9741SAlexander V. Chernikov } 250f88c9741SAlexander V. Chernikov 251f88c9741SAlexander V. Chernikov snprintf(buf, size, "%s", x); 252f88c9741SAlexander V. Chernikov } 253f88c9741SAlexander V. Chernikov 254f732123eSAlexander V. Chernikov static void 255*c59adfc6SAlexander V. Chernikov get_sfp_identifier(struct i2c_info *ii, char *buf, size_t size) 256*c59adfc6SAlexander V. Chernikov { 257*c59adfc6SAlexander V. Chernikov uint8_t data; 258*c59adfc6SAlexander V. Chernikov 259*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_ID, 1, (caddr_t)&data); 260*c59adfc6SAlexander V. Chernikov convert_sff_identifier(buf, size, data); 261*c59adfc6SAlexander V. Chernikov } 262*c59adfc6SAlexander V. Chernikov 263*c59adfc6SAlexander V. Chernikov static void 264*c59adfc6SAlexander V. Chernikov get_sfp_connector(struct i2c_info *ii, char *buf, size_t size) 265*c59adfc6SAlexander V. Chernikov { 266*c59adfc6SAlexander V. Chernikov uint8_t data; 267*c59adfc6SAlexander V. Chernikov 268*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, (caddr_t)&data); 269*c59adfc6SAlexander V. Chernikov convert_sff_connector(buf, size, data); 270*c59adfc6SAlexander V. Chernikov } 271*c59adfc6SAlexander V. Chernikov 272*c59adfc6SAlexander V. Chernikov static void 273*c59adfc6SAlexander V. Chernikov get_qsfp_identifier(struct i2c_info *ii, char *buf, size_t size) 274*c59adfc6SAlexander V. Chernikov { 275*c59adfc6SAlexander V. Chernikov uint8_t data; 276*c59adfc6SAlexander V. Chernikov 277*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8436_BASE, SFF_8436_ID, 1, (caddr_t)&data); 278*c59adfc6SAlexander V. Chernikov convert_sff_identifier(buf, size, data); 279*c59adfc6SAlexander V. Chernikov } 280*c59adfc6SAlexander V. Chernikov 281*c59adfc6SAlexander V. Chernikov static void 282*c59adfc6SAlexander V. Chernikov get_qsfp_connector(struct i2c_info *ii, char *buf, size_t size) 283*c59adfc6SAlexander V. Chernikov { 284*c59adfc6SAlexander V. Chernikov uint8_t data; 285*c59adfc6SAlexander V. Chernikov 286*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8436_BASE, SFF_8436_CONNECTOR, 1, (caddr_t)&data); 287*c59adfc6SAlexander V. Chernikov convert_sff_connector(buf, size, data); 288*c59adfc6SAlexander V. Chernikov } 289*c59adfc6SAlexander V. Chernikov 290*c59adfc6SAlexander V. Chernikov static void 291f732123eSAlexander V. Chernikov printf_sfp_transceiver_descr(struct i2c_info *ii, char *buf, size_t size) 292f732123eSAlexander V. Chernikov { 293f732123eSAlexander V. Chernikov char xbuf[12]; 294f732123eSAlexander V. Chernikov const char *tech_class, *tech_len, *tech_tech, *tech_media, *tech_speed; 295f732123eSAlexander V. Chernikov 296f732123eSAlexander V. Chernikov tech_class = NULL; 297f732123eSAlexander V. Chernikov tech_len = NULL; 298f732123eSAlexander V. Chernikov tech_tech = NULL; 299f732123eSAlexander V. Chernikov tech_media = NULL; 300f732123eSAlexander V. Chernikov tech_speed = NULL; 301f732123eSAlexander V. Chernikov 302f732123eSAlexander V. Chernikov /* Read bytes 3-10 at once */ 303f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, &xbuf[3]); 304f732123eSAlexander V. Chernikov 30546c9382cSAlexander V. Chernikov /* Check 10G ethernet first */ 306f732123eSAlexander V. Chernikov tech_class = find_zero_bit(eth_10g, xbuf[3], 1); 307f732123eSAlexander V. Chernikov if (tech_class == NULL) { 308f732123eSAlexander V. Chernikov /* No match. Try 1G */ 309f732123eSAlexander V. Chernikov tech_class = find_zero_bit(eth_compat, xbuf[6], 1); 310f732123eSAlexander V. Chernikov } 311f732123eSAlexander V. Chernikov 312f732123eSAlexander V. Chernikov tech_len = find_zero_bit(fc_len, xbuf[7], 1); 313f732123eSAlexander V. Chernikov tech_tech = find_zero_bit(cab_tech, xbuf[7] << 8 | xbuf[8], 2); 314f732123eSAlexander V. Chernikov tech_media = find_zero_bit(fc_media, xbuf[9], 1); 315f732123eSAlexander V. Chernikov tech_speed = find_zero_bit(fc_speed, xbuf[10], 1); 316f732123eSAlexander V. Chernikov 317f732123eSAlexander V. Chernikov printf("Class: %s\n", tech_class); 318f732123eSAlexander V. Chernikov printf("Length: %s\n", tech_len); 319f732123eSAlexander V. Chernikov printf("Tech: %s\n", tech_tech); 320f732123eSAlexander V. Chernikov printf("Media: %s\n", tech_media); 321f732123eSAlexander V. Chernikov printf("Speed: %s\n", tech_speed); 322f732123eSAlexander V. Chernikov } 323f732123eSAlexander V. Chernikov 324f732123eSAlexander V. Chernikov static void 325f732123eSAlexander V. Chernikov get_sfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size) 326f732123eSAlexander V. Chernikov { 327f732123eSAlexander V. Chernikov const char *tech_class; 328f732123eSAlexander V. Chernikov uint8_t code; 329f732123eSAlexander V. Chernikov 330f732123eSAlexander V. Chernikov /* Check 10G Ethernet/IB first */ 331f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, (caddr_t)&code); 332f732123eSAlexander V. Chernikov tech_class = find_zero_bit(eth_10g, code, 1); 333f732123eSAlexander V. Chernikov if (tech_class == NULL) { 334f732123eSAlexander V. Chernikov /* No match. Try Ethernet 1G */ 335f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3, 336f88c9741SAlexander V. Chernikov 1, (caddr_t)&code); 337f732123eSAlexander V. Chernikov tech_class = find_zero_bit(eth_compat, code, 1); 338f732123eSAlexander V. Chernikov } 339f732123eSAlexander V. Chernikov 340f732123eSAlexander V. Chernikov if (tech_class == NULL) 341f732123eSAlexander V. Chernikov tech_class = "Unknown"; 342f732123eSAlexander V. Chernikov 343f732123eSAlexander V. Chernikov snprintf(buf, size, "%s", tech_class); 344f732123eSAlexander V. Chernikov } 345f732123eSAlexander V. Chernikov 346*c59adfc6SAlexander V. Chernikov static void 347*c59adfc6SAlexander V. Chernikov get_qsfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size) 348*c59adfc6SAlexander V. Chernikov { 349*c59adfc6SAlexander V. Chernikov const char *tech_class; 350*c59adfc6SAlexander V. Chernikov uint8_t code; 351*c59adfc6SAlexander V. Chernikov 352*c59adfc6SAlexander V. Chernikov /* Check 10/40G Ethernet class only */ 353*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8436_BASE, SFF_8436_CODE_E1040G, 1, (caddr_t)&code); 354*c59adfc6SAlexander V. Chernikov tech_class = find_zero_bit(eth_1040g, code, 1); 355*c59adfc6SAlexander V. Chernikov if (tech_class == NULL) 356*c59adfc6SAlexander V. Chernikov tech_class = "Unknown"; 357*c59adfc6SAlexander V. Chernikov 358*c59adfc6SAlexander V. Chernikov snprintf(buf, size, "%s", tech_class); 359*c59adfc6SAlexander V. Chernikov } 360*c59adfc6SAlexander V. Chernikov 361*c59adfc6SAlexander V. Chernikov /* 362*c59adfc6SAlexander V. Chernikov * Print SFF-8472/SFF-8436 string to supplied buffer. 363*c59adfc6SAlexander V. Chernikov * All (vendor-specific) strings are padded right with '0x20'. 364*c59adfc6SAlexander V. Chernikov */ 365*c59adfc6SAlexander V. Chernikov static void 366*c59adfc6SAlexander V. Chernikov convert_sff_name(char *buf, size_t size, char *xbuf) 367*c59adfc6SAlexander V. Chernikov { 368*c59adfc6SAlexander V. Chernikov char *p; 369*c59adfc6SAlexander V. Chernikov 370*c59adfc6SAlexander V. Chernikov for (p = &xbuf[16]; *(p - 1) == 0x20; p--) 371*c59adfc6SAlexander V. Chernikov ; 372*c59adfc6SAlexander V. Chernikov *p = '\0'; 373*c59adfc6SAlexander V. Chernikov snprintf(buf, size, "%s", xbuf); 374*c59adfc6SAlexander V. Chernikov } 375*c59adfc6SAlexander V. Chernikov 376*c59adfc6SAlexander V. Chernikov static void 377*c59adfc6SAlexander V. Chernikov convert_sff_date(char *buf, size_t size, char *xbuf) 378*c59adfc6SAlexander V. Chernikov { 379*c59adfc6SAlexander V. Chernikov 380*c59adfc6SAlexander V. Chernikov snprintf(buf, size, "20%c%c-%c%c-%c%c", xbuf[0], xbuf[1], 381*c59adfc6SAlexander V. Chernikov xbuf[2], xbuf[3], xbuf[4], xbuf[5]); 382*c59adfc6SAlexander V. Chernikov } 383f732123eSAlexander V. Chernikov 384f732123eSAlexander V. Chernikov static void 385f732123eSAlexander V. Chernikov get_sfp_vendor_name(struct i2c_info *ii, char *buf, size_t size) 386f732123eSAlexander V. Chernikov { 387*c59adfc6SAlexander V. Chernikov char xbuf[17]; 388f732123eSAlexander V. Chernikov 389f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 390f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, 16, xbuf); 391*c59adfc6SAlexander V. Chernikov convert_sff_name(buf, size, xbuf); 392f732123eSAlexander V. Chernikov } 393f732123eSAlexander V. Chernikov 394f732123eSAlexander V. Chernikov static void 395f732123eSAlexander V. Chernikov get_sfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size) 396f732123eSAlexander V. Chernikov { 397*c59adfc6SAlexander V. Chernikov char xbuf[17]; 398f732123eSAlexander V. Chernikov 399f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 400f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_PN_START, 16, xbuf); 401*c59adfc6SAlexander V. Chernikov convert_sff_name(buf, size, xbuf); 402f732123eSAlexander V. Chernikov } 403f732123eSAlexander V. Chernikov 404f732123eSAlexander V. Chernikov static void 405f732123eSAlexander V. Chernikov get_sfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size) 406f732123eSAlexander V. Chernikov { 407*c59adfc6SAlexander V. Chernikov char xbuf[17]; 408f732123eSAlexander V. Chernikov 409f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 410f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_SN_START, 16, xbuf); 411*c59adfc6SAlexander V. Chernikov convert_sff_name(buf, size, xbuf); 412f732123eSAlexander V. Chernikov } 413f732123eSAlexander V. Chernikov 414f732123eSAlexander V. Chernikov static void 415f732123eSAlexander V. Chernikov get_sfp_vendor_date(struct i2c_info *ii, char *buf, size_t size) 416f732123eSAlexander V. Chernikov { 417f732123eSAlexander V. Chernikov char xbuf[6]; 418f732123eSAlexander V. Chernikov 419f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 420f732123eSAlexander V. Chernikov /* Date code, see Table 3.8 for description */ 421f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_DATE_START, 6, xbuf); 422*c59adfc6SAlexander V. Chernikov convert_sff_date(buf, size, xbuf); 423*c59adfc6SAlexander V. Chernikov } 424*c59adfc6SAlexander V. Chernikov 425*c59adfc6SAlexander V. Chernikov static void 426*c59adfc6SAlexander V. Chernikov get_qsfp_vendor_name(struct i2c_info *ii, char *buf, size_t size) 427*c59adfc6SAlexander V. Chernikov { 428*c59adfc6SAlexander V. Chernikov char xbuf[17]; 429*c59adfc6SAlexander V. Chernikov 430*c59adfc6SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 431*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, 16, xbuf); 432*c59adfc6SAlexander V. Chernikov convert_sff_name(buf, size, xbuf); 433*c59adfc6SAlexander V. Chernikov } 434*c59adfc6SAlexander V. Chernikov 435*c59adfc6SAlexander V. Chernikov static void 436*c59adfc6SAlexander V. Chernikov get_qsfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size) 437*c59adfc6SAlexander V. Chernikov { 438*c59adfc6SAlexander V. Chernikov char xbuf[17]; 439*c59adfc6SAlexander V. Chernikov 440*c59adfc6SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 441*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8436_BASE, SFF_8436_PN_START, 16, xbuf); 442*c59adfc6SAlexander V. Chernikov convert_sff_name(buf, size, xbuf); 443*c59adfc6SAlexander V. Chernikov } 444*c59adfc6SAlexander V. Chernikov 445*c59adfc6SAlexander V. Chernikov static void 446*c59adfc6SAlexander V. Chernikov get_qsfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size) 447*c59adfc6SAlexander V. Chernikov { 448*c59adfc6SAlexander V. Chernikov char xbuf[17]; 449*c59adfc6SAlexander V. Chernikov 450*c59adfc6SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 451*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8436_BASE, SFF_8436_SN_START, 16, xbuf); 452*c59adfc6SAlexander V. Chernikov convert_sff_name(buf, size, xbuf); 453*c59adfc6SAlexander V. Chernikov } 454*c59adfc6SAlexander V. Chernikov 455*c59adfc6SAlexander V. Chernikov static void 456*c59adfc6SAlexander V. Chernikov get_qsfp_vendor_date(struct i2c_info *ii, char *buf, size_t size) 457*c59adfc6SAlexander V. Chernikov { 458*c59adfc6SAlexander V. Chernikov char xbuf[6]; 459*c59adfc6SAlexander V. Chernikov 460*c59adfc6SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 461*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8436_BASE, SFF_8436_DATE_START, 6, xbuf); 462*c59adfc6SAlexander V. Chernikov convert_sff_date(buf, size, xbuf); 463f732123eSAlexander V. Chernikov } 464f732123eSAlexander V. Chernikov 465f732123eSAlexander V. Chernikov static void 466f732123eSAlexander V. Chernikov print_sfp_vendor(struct i2c_info *ii, char *buf, size_t size) 467f732123eSAlexander V. Chernikov { 468f732123eSAlexander V. Chernikov char xbuf[80]; 469f732123eSAlexander V. Chernikov 470f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 471*c59adfc6SAlexander V. Chernikov if (ii->qsfp != 0) { 472*c59adfc6SAlexander V. Chernikov get_qsfp_vendor_name(ii, xbuf, 20); 473*c59adfc6SAlexander V. Chernikov get_qsfp_vendor_pn(ii, &xbuf[20], 20); 474*c59adfc6SAlexander V. Chernikov get_qsfp_vendor_sn(ii, &xbuf[40], 20); 475*c59adfc6SAlexander V. Chernikov get_qsfp_vendor_date(ii, &xbuf[60], 20); 476*c59adfc6SAlexander V. Chernikov } else { 477f732123eSAlexander V. Chernikov get_sfp_vendor_name(ii, xbuf, 20); 478f732123eSAlexander V. Chernikov get_sfp_vendor_pn(ii, &xbuf[20], 20); 479f732123eSAlexander V. Chernikov get_sfp_vendor_sn(ii, &xbuf[40], 20); 480f732123eSAlexander V. Chernikov get_sfp_vendor_date(ii, &xbuf[60], 20); 481*c59adfc6SAlexander V. Chernikov } 482f732123eSAlexander V. Chernikov 483f732123eSAlexander V. Chernikov snprintf(buf, size, "vendor: %s PN: %s SN: %s DATE: %s", 484f732123eSAlexander V. Chernikov xbuf, &xbuf[20], &xbuf[40], &xbuf[60]); 485f732123eSAlexander V. Chernikov } 486f732123eSAlexander V. Chernikov 487*c59adfc6SAlexander V. Chernikov /* 488*c59adfc6SAlexander V. Chernikov * Converts internal templerature (SFF-8472, SFF-8436) 489*c59adfc6SAlexander V. Chernikov * 16-bit unsigned value to human-readable representation: 490*c59adfc6SAlexander V. Chernikov * 491*c59adfc6SAlexander V. Chernikov * Internally measured Module temperature are represented 492*c59adfc6SAlexander V. Chernikov * as a 16-bit signed twos complement value in increments of 493*c59adfc6SAlexander V. Chernikov * 1/256 degrees Celsius, yielding a total range of –128C to +128C 494*c59adfc6SAlexander V. Chernikov * that is considered valid between –40 and +125C. 495*c59adfc6SAlexander V. Chernikov * 496*c59adfc6SAlexander V. Chernikov */ 497f732123eSAlexander V. Chernikov static void 498*c59adfc6SAlexander V. Chernikov convert_sff_temp(char *buf, size_t size, char *xbuf) 499f732123eSAlexander V. Chernikov { 500*c59adfc6SAlexander V. Chernikov double d; 501f732123eSAlexander V. Chernikov 502*c59adfc6SAlexander V. Chernikov d = (double)(int8_t)xbuf[0]; 503*c59adfc6SAlexander V. Chernikov d += (double)(uint8_t)xbuf[1] / 256; 504f732123eSAlexander V. Chernikov 505*c59adfc6SAlexander V. Chernikov snprintf(buf, size, "%.2f C", d); 506*c59adfc6SAlexander V. Chernikov } 507f732123eSAlexander V. Chernikov 508*c59adfc6SAlexander V. Chernikov /* 509*c59adfc6SAlexander V. Chernikov * Retrieves supplied voltage (SFF-8472, SFF-8436). 510*c59adfc6SAlexander V. Chernikov * 16-bit usigned value, treated as range 0..+6.55 Volts 511*c59adfc6SAlexander V. Chernikov */ 512*c59adfc6SAlexander V. Chernikov static void 513*c59adfc6SAlexander V. Chernikov convert_sff_voltage(char *buf, size_t size, char *xbuf) 514*c59adfc6SAlexander V. Chernikov { 515*c59adfc6SAlexander V. Chernikov double d; 516f732123eSAlexander V. Chernikov 517*c59adfc6SAlexander V. Chernikov d = (double)(((uint8_t)xbuf[0] << 8) | (uint8_t)xbuf[1]); 518*c59adfc6SAlexander V. Chernikov snprintf(buf, size, "%.2f Volts", d / 10000); 519f732123eSAlexander V. Chernikov } 520f732123eSAlexander V. Chernikov 52146c9382cSAlexander V. Chernikov /* 52246c9382cSAlexander V. Chernikov * Converts value in @xbuf to both milliwats and dBm 52346c9382cSAlexander V. Chernikov * human representation. 52446c9382cSAlexander V. Chernikov */ 525f732123eSAlexander V. Chernikov static void 526*c59adfc6SAlexander V. Chernikov convert_sff_power(struct i2c_info *ii, char *buf, size_t size, char *xbuf) 527f732123eSAlexander V. Chernikov { 528f732123eSAlexander V. Chernikov uint16_t mW; 529f732123eSAlexander V. Chernikov double dbm; 530f732123eSAlexander V. Chernikov 531f732123eSAlexander V. Chernikov mW = ((uint8_t)xbuf[0] << 8) + (uint8_t)xbuf[1]; 532f732123eSAlexander V. Chernikov 533f732123eSAlexander V. Chernikov /* Convert mw to dbm */ 534f732123eSAlexander V. Chernikov dbm = 10.0 * log10(1.0 * mW / 10000); 535f732123eSAlexander V. Chernikov 536*c59adfc6SAlexander V. Chernikov /* 537*c59adfc6SAlexander V. Chernikov * Assume internally-calibrated data. 538*c59adfc6SAlexander V. Chernikov * This is always true for SFF-8346, and explicitly 539*c59adfc6SAlexander V. Chernikov * checked for SFF-8472. 540*c59adfc6SAlexander V. Chernikov */ 541*c59adfc6SAlexander V. Chernikov 542f732123eSAlexander V. Chernikov /* Table 3.9, bit 5 is set, internally calibrated */ 543f732123eSAlexander V. Chernikov snprintf(buf, size, "%d.%02d mW (%.2f dBm)", 544f732123eSAlexander V. Chernikov mW / 10000, (mW % 10000) / 100, dbm); 545f732123eSAlexander V. Chernikov } 546*c59adfc6SAlexander V. Chernikov 547*c59adfc6SAlexander V. Chernikov static void 548*c59adfc6SAlexander V. Chernikov get_sfp_temp(struct i2c_info *ii, char *buf, size_t size) 549*c59adfc6SAlexander V. Chernikov { 550*c59adfc6SAlexander V. Chernikov char xbuf[2]; 551*c59adfc6SAlexander V. Chernikov 552*c59adfc6SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 553*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8472_DIAG, SFF_8472_TEMP, 2, xbuf); 554*c59adfc6SAlexander V. Chernikov convert_sff_temp(buf, size, xbuf); 555*c59adfc6SAlexander V. Chernikov } 556*c59adfc6SAlexander V. Chernikov 557*c59adfc6SAlexander V. Chernikov static void 558*c59adfc6SAlexander V. Chernikov get_sfp_voltage(struct i2c_info *ii, char *buf, size_t size) 559*c59adfc6SAlexander V. Chernikov { 560*c59adfc6SAlexander V. Chernikov char xbuf[2]; 561*c59adfc6SAlexander V. Chernikov 562*c59adfc6SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 563*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8472_DIAG, SFF_8472_VCC, 2, xbuf); 564*c59adfc6SAlexander V. Chernikov convert_sff_voltage(buf, size, xbuf); 565*c59adfc6SAlexander V. Chernikov } 566*c59adfc6SAlexander V. Chernikov 567*c59adfc6SAlexander V. Chernikov static void 568*c59adfc6SAlexander V. Chernikov get_qsfp_temp(struct i2c_info *ii, char *buf, size_t size) 569*c59adfc6SAlexander V. Chernikov { 570*c59adfc6SAlexander V. Chernikov char xbuf[2]; 571*c59adfc6SAlexander V. Chernikov 572*c59adfc6SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 573*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8436_BASE, SFF_8436_TEMP, 2, xbuf); 574*c59adfc6SAlexander V. Chernikov convert_sff_temp(buf, size, xbuf); 575*c59adfc6SAlexander V. Chernikov } 576*c59adfc6SAlexander V. Chernikov 577*c59adfc6SAlexander V. Chernikov static void 578*c59adfc6SAlexander V. Chernikov get_qsfp_voltage(struct i2c_info *ii, char *buf, size_t size) 579*c59adfc6SAlexander V. Chernikov { 580*c59adfc6SAlexander V. Chernikov char xbuf[2]; 581*c59adfc6SAlexander V. Chernikov 582*c59adfc6SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 583*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8436_BASE, SFF_8436_VCC, 2, xbuf); 584*c59adfc6SAlexander V. Chernikov convert_sff_voltage(buf, size, xbuf); 585f732123eSAlexander V. Chernikov } 586f732123eSAlexander V. Chernikov 587f732123eSAlexander V. Chernikov static void 588f732123eSAlexander V. Chernikov get_sfp_rx_power(struct i2c_info *ii, char *buf, size_t size) 589f732123eSAlexander V. Chernikov { 590f732123eSAlexander V. Chernikov char xbuf[2]; 591f732123eSAlexander V. Chernikov 592f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 593f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_DIAG, SFF_8472_RX_POWER, 2, xbuf); 594*c59adfc6SAlexander V. Chernikov convert_sff_power(ii, buf, size, xbuf); 595f732123eSAlexander V. Chernikov } 596f732123eSAlexander V. Chernikov 597f732123eSAlexander V. Chernikov static void 598f732123eSAlexander V. Chernikov get_sfp_tx_power(struct i2c_info *ii, char *buf, size_t size) 599f732123eSAlexander V. Chernikov { 600f732123eSAlexander V. Chernikov char xbuf[2]; 601f732123eSAlexander V. Chernikov 602f732123eSAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 603f88c9741SAlexander V. Chernikov ii->f(ii, SFF_8472_DIAG, SFF_8472_TX_POWER, 2, xbuf); 604*c59adfc6SAlexander V. Chernikov convert_sff_power(ii, buf, size, xbuf); 605*c59adfc6SAlexander V. Chernikov } 606*c59adfc6SAlexander V. Chernikov 607*c59adfc6SAlexander V. Chernikov static void 608*c59adfc6SAlexander V. Chernikov get_qsfp_rx_power(struct i2c_info *ii, char *buf, size_t size, int chan) 609*c59adfc6SAlexander V. Chernikov { 610*c59adfc6SAlexander V. Chernikov char xbuf[2]; 611*c59adfc6SAlexander V. Chernikov 612*c59adfc6SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 613*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8436_BASE, SFF_8436_RX_CH1_MSB + (chan - 1) * 2, 2, xbuf); 614*c59adfc6SAlexander V. Chernikov convert_sff_power(ii, buf, size, xbuf); 615*c59adfc6SAlexander V. Chernikov } 616*c59adfc6SAlexander V. Chernikov 617*c59adfc6SAlexander V. Chernikov static void 618*c59adfc6SAlexander V. Chernikov get_qsfp_tx_power(struct i2c_info *ii, char *buf, size_t size, int chan) 619*c59adfc6SAlexander V. Chernikov { 620*c59adfc6SAlexander V. Chernikov char xbuf[2]; 621*c59adfc6SAlexander V. Chernikov 622*c59adfc6SAlexander V. Chernikov memset(xbuf, 0, sizeof(xbuf)); 623*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8436_BASE, SFF_8436_TX_CH1_MSB + (chan -1) * 2, 2, xbuf); 624*c59adfc6SAlexander V. Chernikov convert_sff_power(ii, buf, size, xbuf); 625f732123eSAlexander V. Chernikov } 626f732123eSAlexander V. Chernikov 627f732123eSAlexander V. Chernikov /* Intel ixgbe-specific structures and handlers */ 628f732123eSAlexander V. Chernikov struct ixgbe_i2c_req { 629f732123eSAlexander V. Chernikov uint8_t dev_addr; 630f732123eSAlexander V. Chernikov uint8_t offset; 631f732123eSAlexander V. Chernikov uint8_t len; 632f732123eSAlexander V. Chernikov uint8_t data[8]; 633f732123eSAlexander V. Chernikov }; 634f732123eSAlexander V. Chernikov #define SIOCGI2C SIOCGIFGENERIC 635f732123eSAlexander V. Chernikov 636f732123eSAlexander V. Chernikov static int 637f732123eSAlexander V. Chernikov read_i2c_ixgbe(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len, 638f732123eSAlexander V. Chernikov caddr_t buf) 639f732123eSAlexander V. Chernikov { 640f732123eSAlexander V. Chernikov struct ixgbe_i2c_req ixreq; 641f732123eSAlexander V. Chernikov int i; 642f732123eSAlexander V. Chernikov 643f732123eSAlexander V. Chernikov if (ii->error != 0) 644f732123eSAlexander V. Chernikov return (ii->error); 645f732123eSAlexander V. Chernikov 646f732123eSAlexander V. Chernikov ii->ifr->ifr_data = (caddr_t)&ixreq; 647f732123eSAlexander V. Chernikov 648f732123eSAlexander V. Chernikov memset(&ixreq, 0, sizeof(ixreq)); 649f732123eSAlexander V. Chernikov ixreq.dev_addr = addr; 650f732123eSAlexander V. Chernikov 651f732123eSAlexander V. Chernikov for (i = 0; i < len; i += 1) { 652f732123eSAlexander V. Chernikov ixreq.offset = off + i; 653f732123eSAlexander V. Chernikov ixreq.len = 1; 6547d6fa255SAlexander V. Chernikov ixreq.data[0] = '\0'; 655f732123eSAlexander V. Chernikov 656f732123eSAlexander V. Chernikov if (ioctl(ii->s, SIOCGI2C, ii->ifr) != 0) { 657f732123eSAlexander V. Chernikov ii->error = errno; 658f732123eSAlexander V. Chernikov return (errno); 659f732123eSAlexander V. Chernikov } 660f732123eSAlexander V. Chernikov memcpy(&buf[i], ixreq.data, 1); 661f732123eSAlexander V. Chernikov } 662f732123eSAlexander V. Chernikov 663f732123eSAlexander V. Chernikov return (0); 664f732123eSAlexander V. Chernikov } 665f732123eSAlexander V. Chernikov 666*c59adfc6SAlexander V. Chernikov /* Generic handler */ 667*c59adfc6SAlexander V. Chernikov static int 668*c59adfc6SAlexander V. Chernikov read_i2c_generic(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len, 669*c59adfc6SAlexander V. Chernikov caddr_t buf) 670*c59adfc6SAlexander V. Chernikov { 671*c59adfc6SAlexander V. Chernikov 672*c59adfc6SAlexander V. Chernikov ii->error = EINVAL; 673*c59adfc6SAlexander V. Chernikov return (-1); 674*c59adfc6SAlexander V. Chernikov } 675*c59adfc6SAlexander V. Chernikov 676*c59adfc6SAlexander V. Chernikov static void 677*c59adfc6SAlexander V. Chernikov print_qsfp_status(struct i2c_info *ii, int verbose) 678*c59adfc6SAlexander V. Chernikov { 679*c59adfc6SAlexander V. Chernikov char buf[80], buf2[40], buf3[40]; 680*c59adfc6SAlexander V. Chernikov uint8_t diag_type; 681*c59adfc6SAlexander V. Chernikov int i; 682*c59adfc6SAlexander V. Chernikov 683*c59adfc6SAlexander V. Chernikov /* Read diagnostic monitoring type */ 684*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8436_BASE, SFF_8436_DIAG_TYPE, 1, (caddr_t)&diag_type); 685*c59adfc6SAlexander V. Chernikov if (ii->error != 0) 686*c59adfc6SAlexander V. Chernikov return; 687*c59adfc6SAlexander V. Chernikov 688*c59adfc6SAlexander V. Chernikov /* 689*c59adfc6SAlexander V. Chernikov * Read monitoring data it is supplied. 690*c59adfc6SAlexander V. Chernikov * XXX: It is not exactly clear from standard 691*c59adfc6SAlexander V. Chernikov * how one can specify lack of measurements (passive cables case). 692*c59adfc6SAlexander V. Chernikov */ 693*c59adfc6SAlexander V. Chernikov if (diag_type != 0) 694*c59adfc6SAlexander V. Chernikov ii->do_diag = 1; 695*c59adfc6SAlexander V. Chernikov ii->qsfp = 1; 696*c59adfc6SAlexander V. Chernikov 697*c59adfc6SAlexander V. Chernikov /* Transceiver type */ 698*c59adfc6SAlexander V. Chernikov get_qsfp_identifier(ii, buf, sizeof(buf)); 699*c59adfc6SAlexander V. Chernikov get_qsfp_transceiver_class(ii, buf2, sizeof(buf2)); 700*c59adfc6SAlexander V. Chernikov get_qsfp_connector(ii, buf3, sizeof(buf3)); 701*c59adfc6SAlexander V. Chernikov if (ii->error == 0) 702*c59adfc6SAlexander V. Chernikov printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3); 703*c59adfc6SAlexander V. Chernikov print_sfp_vendor(ii, buf, sizeof(buf)); 704*c59adfc6SAlexander V. Chernikov if (ii->error == 0) 705*c59adfc6SAlexander V. Chernikov printf("\t%s\n", buf); 706*c59adfc6SAlexander V. Chernikov 707*c59adfc6SAlexander V. Chernikov /* Request current measurements if they are provided: */ 708*c59adfc6SAlexander V. Chernikov if (ii->do_diag != 0) { 709*c59adfc6SAlexander V. Chernikov get_qsfp_temp(ii, buf, sizeof(buf)); 710*c59adfc6SAlexander V. Chernikov get_qsfp_voltage(ii, buf2, sizeof(buf2)); 711*c59adfc6SAlexander V. Chernikov printf("\tmodule temperature: %s voltage: %s\n", buf, buf2); 712*c59adfc6SAlexander V. Chernikov for (i = 1; i <= 4; i++) { 713*c59adfc6SAlexander V. Chernikov get_qsfp_rx_power(ii, buf, sizeof(buf), i); 714*c59adfc6SAlexander V. Chernikov get_qsfp_tx_power(ii, buf2, sizeof(buf2), i); 715*c59adfc6SAlexander V. Chernikov printf("\tlane %d: RX: %s TX: %s\n", i, buf, buf2); 716*c59adfc6SAlexander V. Chernikov } 717*c59adfc6SAlexander V. Chernikov } 718*c59adfc6SAlexander V. Chernikov } 719*c59adfc6SAlexander V. Chernikov 720*c59adfc6SAlexander V. Chernikov static void 721*c59adfc6SAlexander V. Chernikov print_sfp_status(struct i2c_info *ii, int verbose) 722*c59adfc6SAlexander V. Chernikov { 723*c59adfc6SAlexander V. Chernikov char buf[80], buf2[40], buf3[40]; 724*c59adfc6SAlexander V. Chernikov uint8_t diag_type, flags; 725*c59adfc6SAlexander V. Chernikov 726*c59adfc6SAlexander V. Chernikov /* Read diagnostic monitoring type */ 727*c59adfc6SAlexander V. Chernikov ii->f(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&diag_type); 728*c59adfc6SAlexander V. Chernikov if (ii->error != 0) 729*c59adfc6SAlexander V. Chernikov return; 730*c59adfc6SAlexander V. Chernikov 731*c59adfc6SAlexander V. Chernikov /* 732*c59adfc6SAlexander V. Chernikov * Read monitoring data IFF it is supplied AND is 733*c59adfc6SAlexander V. Chernikov * internally calibrated 734*c59adfc6SAlexander V. Chernikov */ 735*c59adfc6SAlexander V. Chernikov flags = SFF_8472_DDM_DONE | SFF_8472_DDM_INTERNAL; 736*c59adfc6SAlexander V. Chernikov if ((diag_type & flags) == flags) 737*c59adfc6SAlexander V. Chernikov ii->do_diag = 1; 738*c59adfc6SAlexander V. Chernikov 739*c59adfc6SAlexander V. Chernikov /* Transceiver type */ 740*c59adfc6SAlexander V. Chernikov get_sfp_identifier(ii, buf, sizeof(buf)); 741*c59adfc6SAlexander V. Chernikov get_sfp_transceiver_class(ii, buf2, sizeof(buf2)); 742*c59adfc6SAlexander V. Chernikov get_sfp_connector(ii, buf3, sizeof(buf3)); 743*c59adfc6SAlexander V. Chernikov if (ii->error == 0) 744*c59adfc6SAlexander V. Chernikov printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3); 745*c59adfc6SAlexander V. Chernikov if (verbose > 2) 746*c59adfc6SAlexander V. Chernikov printf_sfp_transceiver_descr(ii, buf, sizeof(buf)); 747*c59adfc6SAlexander V. Chernikov print_sfp_vendor(ii, buf, sizeof(buf)); 748*c59adfc6SAlexander V. Chernikov if (ii->error == 0) 749*c59adfc6SAlexander V. Chernikov printf("\t%s\n", buf); 750*c59adfc6SAlexander V. Chernikov 751*c59adfc6SAlexander V. Chernikov /* 752*c59adfc6SAlexander V. Chernikov * Request current measurements iff they are provided: 753*c59adfc6SAlexander V. Chernikov */ 754*c59adfc6SAlexander V. Chernikov if (ii->do_diag != 0) { 755*c59adfc6SAlexander V. Chernikov get_sfp_temp(ii, buf, sizeof(buf)); 756*c59adfc6SAlexander V. Chernikov get_sfp_voltage(ii, buf2, sizeof(buf2)); 757*c59adfc6SAlexander V. Chernikov printf("\tmodule temperature: %s Voltage: %s\n", buf, buf2); 758*c59adfc6SAlexander V. Chernikov get_sfp_rx_power(ii, buf, sizeof(buf)); 759*c59adfc6SAlexander V. Chernikov get_sfp_tx_power(ii, buf2, sizeof(buf2)); 760*c59adfc6SAlexander V. Chernikov printf("\tRX: %s TX: %s\n", buf, buf2); 761*c59adfc6SAlexander V. Chernikov } 762*c59adfc6SAlexander V. Chernikov } 763*c59adfc6SAlexander V. Chernikov 764f732123eSAlexander V. Chernikov void 765f732123eSAlexander V. Chernikov sfp_status(int s, struct ifreq *ifr, int verbose) 766f732123eSAlexander V. Chernikov { 767f732123eSAlexander V. Chernikov struct i2c_info ii; 768*c59adfc6SAlexander V. Chernikov 769*c59adfc6SAlexander V. Chernikov /* Prepare necessary into to pass to NIC handler */ 770*c59adfc6SAlexander V. Chernikov ii.s = s; 771*c59adfc6SAlexander V. Chernikov ii.ifr = ifr; 772f732123eSAlexander V. Chernikov 773f732123eSAlexander V. Chernikov /* 774f732123eSAlexander V. Chernikov * Check if we have i2c support for particular driver. 775f732123eSAlexander V. Chernikov * TODO: Determine driver by original name. 776f732123eSAlexander V. Chernikov */ 777f732123eSAlexander V. Chernikov memset(&ii, 0, sizeof(ii)); 778f732123eSAlexander V. Chernikov if (strncmp(ifr->ifr_name, "ix", 2) == 0) { 779f732123eSAlexander V. Chernikov ii.f = read_i2c_ixgbe; 780*c59adfc6SAlexander V. Chernikov print_sfp_status(&ii, verbose); 781*c59adfc6SAlexander V. Chernikov } else if (strncmp(ifr->ifr_name, "cxl", 3) == 0) { 782*c59adfc6SAlexander V. Chernikov ii.port_id = atoi(&ifr->ifr_name[3]); 783*c59adfc6SAlexander V. Chernikov ii.f = read_i2c_generic; 784*c59adfc6SAlexander V. Chernikov ii.cfd = -1; 785*c59adfc6SAlexander V. Chernikov print_qsfp_status(&ii, verbose); 786f732123eSAlexander V. Chernikov } else 787f732123eSAlexander V. Chernikov return; 788f732123eSAlexander V. Chernikov } 789f732123eSAlexander V. Chernikov 790