Here's a complete diff. Tested on amd64 with ix, working great there.
distrib/special/ifconfig still builds okay, I'll run a full mkr later on
i386/amd64.

This is extremely useful for the bgpd "target market" ;)

Index: sbin/ifconfig/Makefile
===================================================================
RCS file: /cvs/src/sbin/ifconfig/Makefile,v
retrieving revision 1.14
diff -u -p -r1.14 Makefile
--- sbin/ifconfig/Makefile      3 May 2016 17:52:33 -0000       1.14
+++ sbin/ifconfig/Makefile      8 Apr 2019 12:45:33 -0000
@@ -1,10 +1,10 @@
 #      $OpenBSD: Makefile,v 1.14 2016/05/03 17:52:33 jca Exp $
 
 PROG=  ifconfig
-SRCS=  ifconfig.c brconfig.c
+SRCS=  ifconfig.c brconfig.c sff.c
 MAN=   ifconfig.8
 
-LDADD= -lutil
+LDADD= -lutil -lm
 DPADD= ${LIBUTIL}
 
 .include <bsd.prog.mk>
Index: sbin/ifconfig/ifconfig.c
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.397
diff -u -p -r1.397 ifconfig.c
--- sbin/ifconfig/ifconfig.c    11 Mar 2019 11:25:48 -0000      1.397
+++ sbin/ifconfig/ifconfig.c    8 Apr 2019 12:45:33 -0000
@@ -340,6 +340,8 @@ void        umb_setclass(const char *, int);
 void   umb_roaming(const char *, int);
 void   utf16_to_char(uint16_t *, int, char *, size_t);
 int    char_to_utf16(const char *, uint16_t *, size_t);
+void   transceiver(const char *, int);
+void   transceiverdump(const char *, int);
 #else
 void   setignore(const char *, int);
 #endif
@@ -589,6 +591,9 @@ const struct        cmd {
        { "datapath",   NEXTARG,        0,              switch_datapathid },
        { "portno",     NEXTARG2,       0,              NULL, switch_portno },
        { "addlocal",   NEXTARG,        0,              addlocal },
+       { "transceiver", 0,             0,              transceiver },
+       { "sff",        0,              0,              transceiver },
+       { "sffdump",    0,              0,              transceiverdump },
 #else /* SMALL */
        { "powersave",  NEXTARG0,       0,              setignore },
        { "priority",   NEXTARG,        0,              setignore },
@@ -4033,6 +4038,22 @@ unsetpwe3neighbor(const char *val, int d
 
        if (ioctl(s, SIOCDPWE3NEIGHBOR, &req) == -1)
                warn("-pweneighbor");
+}
+
+int    if_sff_info(int, const char *, int);
+
+void
+transceiver(const char *value, int d)
+{
+       if (if_sff_info(s, name, 0) == -1)
+               err(1, "%s %s", name, __func__);
+}
+
+void
+transceiverdump(const char *value, int d)
+{
+       if (if_sff_info(s, name, 1) == -1)
+               err(1, "%s transceiver", name);
 }
 #endif /* SMALL */
 
Index: sbin/ifconfig/sff.c
===================================================================
RCS file: sbin/ifconfig/sff.c
diff -N sbin/ifconfig/sff.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sbin/ifconfig/sff.c 8 Apr 2019 12:45:33 -0000
@@ -0,0 +1,464 @@
+/*     $OpenBSD$ */
+
+/*
+ * Copyright (c) David Gwynne <d...@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SMALL
+
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+
+#include <math.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <vis.h>
+
+#ifndef nitems
+#define nitems(_a)     (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
+#ifndef ISSET
+#define ISSET(_w, _m)  ((_w) & (_m))
+#endif
+
+#define SFF8024_ID_UNKNOWN     0x00
+#define SFF8024_ID_GBIC                0x01
+#define SFF8024_ID_MOBO                0x02 /* Module/connector soldered to 
mobo */
+                                    /* using SFF-8472 */
+#define SFF8024_ID_SFP         0x03 /* SFP/SFP+/SFP28 */
+#define SFF8024_ID_300PIN_XBI  0x04 /* 300 pin XBI */
+#define SFF8024_ID_XENPAK      0x05
+#define SFF8024_ID_XFP         0x06
+#define SFF8024_ID_XFF         0x07
+#define SFF8024_ID_XFPE                0x08 /* XFP-E */
+#define SFF8024_ID_XPAK                0x09
+#define SFF8024_ID_X2          0x0a
+#define SFF8024_ID_DWDM_SFP    0x0b /* DWDM-SFP/SFP+ */
+                                    /* not using SFF-8472 */
+#define SFF8024_ID_QSFP                0x0c
+#define SFF8024_ID_QSFP_PLUS   0x0d /* or later */
+                                    /* using SFF-8436/8665/8685 et al */
+#define SFF8024_ID_CXP         0x0e /* or later */
+#define SFF8024_ID_HD4X                0x0f /* shielded mini multilane HD 4X */
+#define SFF8024_ID_HD8X                0x10 /* shielded mini multilane HD 8X */
+#define SFF8024_ID_QSFP28      0x11 /* or later */
+                                    /* using SFF-8665 et al */
+#define SFF8024_ID_CXP2                0x12 /* aka CXP28, or later */
+#define SFF8024_ID_CDFP                0x13 /* style 1/style 2 */
+#define SFF8024_ID_HD4X_FAN    0x14 /* shielded mini multilane HD 4X fanout */ 
+#define SFF8024_ID_HD8X_FAN    0x15 /* shielded mini multilane HD 8X fanout */ 
+#define SFF8024_ID_CDFP3       0x16 /* style 3 */
+#define SFF8024_ID_uQSFP       0x17 /* microQSFP */
+#define SFF8024_ID_QSFP_DD     0x18 /* QSFP-DD double density 8x */
+                                    /* INF-8628 */
+#define SFF8024_ID_RESERVED    0x7f /* up to here is reserved */
+                                    /* 0x80 to 0xff is vendor specific */
+
+#define SFF8024_ID_IS_RESERVED(_id)    ((_id) <= SFF8024_ID_RESERVED)
+#define SFF8024_ID_IS_VENDOR(_id)      ((_id) > SFF8024_ID_RESERVED)
+
+#define SFF8024_CON_UNKNOWN    0x00
+#define SFF8024_CON_SC         0x01 /* Subscriber Connector */
+#define SFF8024_CON_FC_1       0x02 /* Fibre Channel Style 1 copper */
+#define SFF8024_CON_FC_2       0x03 /* Fibre Channel Style 2 copper */
+#define SFF8024_CON_BNC_TNC    0x04 /* BNC/TNC */
+#define SFF8024_CON_FC_COAX    0x05 /* Fibre Channel coax headers */
+#define SFF8024_CON_FJ         0x06 /* Fibre Jack */
+#define SFF8024_CON_LC         0x07 /* Lucent Connector */
+#define SFF8024_CON_MT_RJ      0x08 /* Mechanical Transfer - Registered Jack */
+#define SFF8024_CON_MU         0x09 /* Multiple Optical */
+#define SFF8024_CON_SG         0x0a
+#define SFF8024_CON_O_PIGTAIL  0x0b /* Optical Pigtail */
+#define SFF8024_CON_MPO_1x12   0x0c /* Multifiber Parallel Optic 1x12 */
+#define SFF8024_CON_MPO_2x16   0x0e /* Multifiber Parallel Optic 2x16 */
+#define SFF8024_CON_HSSDC2     0x20 /* High Speed Serial Data Connector */
+#define SFF8024_CON_Cu_PIGTAIL 0x21 /* Copper Pigtail */
+#define SFF8024_CON_RJ45       0x22
+#define SFF8024_CON_NO         0x23 /* No separable connector */
+#define SFF8024_CON_MXC_2x16   0x24
+#define SFF8024_CON_RESERVED   0x7f /* up to here is reserved */
+                                    /* 0x80 to 0xff is vendor specific */
+
+#define SFF8024_CON_IS_RESERVED(_id)   ((_id) <= SFF8024_CON_RESERVED)
+#define SFF8024_CON_IS_VENDOR(_id)     ((_id) > SFF8024_CON_RESERVED)
+
+static const char *sff8024_id_names[] = {
+       [SFF8024_ID_UNKNOWN]    = "Unknown",
+       [SFF8024_ID_GBIC]       = "GBIC",
+       [SFF8024_ID_SFP]        = "SFP",
+       [SFF8024_ID_300PIN_XBI] = "300 pin XBI",
+       [SFF8024_ID_XENPAK]     = "XENPAK",
+       [SFF8024_ID_XFP]        = "XFP",
+       [SFF8024_ID_XFF]        = "XFF",
+       [SFF8024_ID_XFPE]       = "XFPE",
+       [SFF8024_ID_XPAK]       = "XPAK",
+       [SFF8024_ID_X2]         = "X2",
+       [SFF8024_ID_DWDM_SFP]   = "DWDM-SFP",
+       [SFF8024_ID_QSFP]       = "QSFP",
+       [SFF8024_ID_QSFP_PLUS]  = "QSFP+",
+       [SFF8024_ID_CXP]        = "CXP",
+       [SFF8024_ID_HD4X]       = "Shielded Mini Multilane HD 4X",
+       [SFF8024_ID_HD8X]       = "Shielded Mini Multilane HD 8X",
+       [SFF8024_ID_QSFP28]     = "QSFP28",
+       [SFF8024_ID_CXP2]       = "CXP2",
+       [SFF8024_ID_CDFP]       = "CDFP Style 1/2",
+       [SFF8024_ID_HD4X_FAN]   = "Shielded Mini Multilane HD 4X Fanout Cable",
+       [SFF8024_ID_HD8X_FAN]   = "Shielded Mini Multilane HD 8X Fanout Cable",
+       [SFF8024_ID_CDFP3]      = "CDFP Style 3",
+       [SFF8024_ID_uQSFP]      = "microQSFP",
+       [SFF8024_ID_QSFP_DD]    = "QSFP Double-Density",
+};
+
+static const char *sff8024_con_names[] = {
+       [SFF8024_CON_UNKNOWN]   = "Unknown",
+       [SFF8024_CON_SC]        = "SC",
+       [SFF8024_CON_FC_1]      = "Fibre Channel style 1",
+       [SFF8024_CON_FC_2]      = "Fibre Channel style 2",
+       [SFF8024_CON_BNC_TNC]   = "BNC/TNC",
+       [SFF8024_CON_FC_COAX]   = "Fibre Channel coax headers",
+       [SFF8024_CON_FJ]        = "Fiber Jack",
+       [SFF8024_CON_LC]        = "LC",
+       [SFF8024_CON_MT_RJ]     = "MT-RJ",
+       [SFF8024_CON_MU]        = "MU",
+       [SFF8024_CON_SG]        = "SG",
+       [SFF8024_CON_O_PIGTAIL] = "Optical Pigtail",
+       [SFF8024_CON_MPO_1x12]  = "MPO 2x16",
+       [SFF8024_CON_MPO_2x16]  = "MPO 1x12",
+       [SFF8024_CON_HSSDC2]    = "HSSDC II",
+       [SFF8024_CON_Cu_PIGTAIL]
+                               = "Copper Pigtail",
+       [SFF8024_CON_RJ45]      = "RJ45",
+       [SFF8024_CON_NO]        = "No separable connector",
+       [SFF8024_CON_MXC_2x16]  = "MXC 2x16",
+};
+
+#define SFF8472_ID                     0 /* SFF8027 for identifier values */
+#define SFF8472_EXT_ID                 1
+#define SFF8472_EXT_ID_UNSPECIFIED             0x00
+#define SFF8472_EXT_ID_MOD_DEF_1               0x01
+#define SFF8472_EXT_ID_MOD_DEF_2               0x02
+#define SFF8472_EXT_ID_MOD_DEF_3               0x03
+#define SFF8472_EXT_ID_2WIRE                   0x04
+#define SFF8472_EXT_ID_MOD_DEF_5               0x05
+#define SFF8472_EXT_ID_MOD_DEF_6               0x06
+#define SFF8472_EXT_ID_MOD_DEF_7               0x07
+#define SFF8472_CON                    2 /* SFF8027 for connector values */
+#define SFF8472_VENDOR_START           20
+#define SFF8472_VENDOR_END             35
+#define SFF8472_PRODUCT_START          40
+#define SFF8472_PRODUCT_END            55
+#define SFF8472_REVISION_START         56
+#define SFF8472_REVISION_END           59
+#define SFF8472_SERIAL_START           68
+#define SFF8472_SERIAL_END             83
+#define SFF8472_DATECODE               84
+#define SFF8472_DDM_TYPE               92
+#define SFF8472_DDM_TYPE_AVG_POWER             (1U << 3)
+#define SFF8472_DDM_TYPE_CAL_EXT               (1U << 4)
+#define SFF8472_DDM_TYPE_CAL_INT               (1U << 5)
+#define SFF8472_DDM_TYPE_IMPL                  (1U << 6)
+#define SFF8472_COMPLIANCE             94
+#define SFF8472_COMPLIANCE_NONE                        0x00
+#define SFF8472_COMPLIANCE_9_3                 0x01 /* SFF-8472 Rev 9.3 */
+#define SFF8472_COMPLIANCE_9_5                 0x02 /* SFF-8472 Rev 9.5 */
+#define SFF8472_COMPLIANCE_10_2                        0x03 /* SFF-8472 Rev 
10.2 */
+#define SFF8472_COMPLIANCE_10_4                        0x04 /* SFF-8472 Rev 
10.4 */
+#define SFF8472_COMPLIANCE_11_0                        0x05 /* SFF-8472 Rev 
11.0 */
+#define SFF8472_COMPLIANCE_11_3                        0x06 /* SFF-8472 Rev 
11.3 */
+#define SFF8472_COMPLIANCE_11_4                        0x07 /* SFF-8472 Rev 
11.4 */
+#define SFF8472_COMPLIANCE_12_3                        0x08 /* SFF-8472 Rev 
12.3 */
+
+/*
+ * page 0xa2
+ */
+#define SFF8472_DDM_TEMP               96
+#define SFF8472_DDM_VCC                        98
+#define SFF8472_DDM_TX_BIAS            100
+#define SFF8472_DDM_TX_POWER           102
+#define SFF8472_DDM_RX_POWER           104
+#define SFF8472_DDM_LASER              106 /* laser temp/wavelength */
+                                           /* optional */
+#define SFF8472_DDM_TEC                        108 /* Measured TEC current */
+                                           /* optional */
+
+#define SFF_TEMP_FACTOR                256.0
+#define SFF_VCC_FACTOR         10000.0
+#define SFF_BIAS_FACTOR                500.0
+#define SFF_POWER_FACTOR       10000.0
+
+static void    hexdump(const void *, size_t);
+static int     if_sff8472(int, const char *, int, const struct if_sffpage *);
+
+static const char *
+sff_id_name(uint8_t id)
+{
+       const char *name = NULL;
+
+       if (id < nitems(sff8024_id_names)) {
+               name = sff8024_id_names[id];
+               if (name != NULL)
+                       return (name);
+       }
+
+       if (SFF8024_ID_IS_VENDOR(id))
+               return ("Vendor Specific");
+
+       return ("Reserved");
+}
+
+static const char *
+sff_con_name(uint8_t id)
+{
+       const char *name = NULL;
+
+       if (id < nitems(sff8024_con_names)) {
+               name = sff8024_con_names[id];
+               if (name != NULL)
+                       return (name);
+       }
+
+       if (SFF8024_CON_IS_VENDOR(id))
+               return ("Vendor Specific");
+
+       return ("Reserved");
+}
+
+static void
+if_sffpage_init(struct if_sffpage *sff, const char *ifname,
+    uint8_t addr, uint8_t page)
+{
+       memset(sff, 0, sizeof(*sff));
+
+       if (strlcpy(sff->sff_ifname, ifname, sizeof(sff->sff_ifname)) >=
+           sizeof(sff->sff_ifname))
+               errx(1, "interface name too long");
+
+       sff->sff_addr = addr;
+       sff->sff_page = page;
+}
+
+static void
+if_sffpage_dump(const char *ifname, const struct if_sffpage *sff)
+{
+       printf("%s: addr %02x", ifname, sff->sff_addr);
+       if (sff->sff_addr == IFSFF_ADDR_EEPROM)
+               printf(" page %u", sff->sff_page);
+       putchar('\n');
+       hexdump(sff->sff_data, sizeof(sff->sff_data));
+}
+
+int
+if_sff_info(int s, const char *ifname, int dump)
+{
+       struct if_sffpage pg0;
+       int error = 0;
+       uint8_t id, ext_id;
+
+       if_sffpage_init(&pg0, ifname, IFSFF_ADDR_EEPROM, 0);
+
+       if (ioctl(s, SIOCGIFSFFPAGE, (caddr_t)&pg0) == -1)
+               return (-1);
+
+       if (dump)
+               if_sffpage_dump(ifname, &pg0);
+
+       id = pg0.sff_data[0]; /* SFF8472_ID */
+
+       printf("%s: identifier %s (%02x)\n", ifname, sff_id_name(id), id);
+       switch (id) {
+       case SFF8024_ID_SFP:
+               ext_id = pg0.sff_data[SFF8472_EXT_ID];
+               if (ext_id != SFF8472_EXT_ID_2WIRE) {
+                       printf("\textended-id: %02xh\n", ext_id);
+                       break;
+               }
+               /* FALLTHROUGH */
+       case SFF8024_ID_GBIC:
+               error = if_sff8472(s, ifname, dump, &pg0);
+               break;
+       }
+
+       return (error);
+}
+
+static void
+if_sff_ascii_print(const struct if_sffpage *sff, const char *name,
+    size_t start, size_t end)
+{
+       const uint8_t *d = sff->sff_data;
+       int ch;
+
+       printf("\t%s: ", name);
+
+       for (;;) {
+               ch = d[start];
+               if (!isspace(ch) && ch != '\0')
+                       break;
+
+               start++;
+               if (start == end) {
+                       printf("(unknown)\n");
+                       return;
+               }
+       }
+
+       for (;;) {
+               int ch = d[end];
+               if (!isspace(ch) && ch != '\0')
+                       break;
+
+               end--;
+       }
+
+       do {
+               char dst[8];
+               vis(dst, d[start], VIS_TAB | VIS_NL, 0);
+               printf("%s", dst);
+       } while (++start <= end);
+       putchar('\n');
+}
+
+static void
+if_sff_date_print(const struct if_sffpage *sff, const char *name,
+    size_t start)
+{
+       const uint8_t *d = sff->sff_data + start;
+       size_t i;
+
+       /* YYMMDD */
+       for (i = 0; i < 6; i++) {
+               if (!isdigit(d[i])) {
+                       if_sff_ascii_print(sff, name, start, start + 5);
+                       return;
+               }
+       }
+
+       printf("\t%s: 20%c%c-%c%c-%c%c\n", name,
+           d[0], d[1], d[2], d[3], d[4], d[5]);
+}
+
+static int16_t
+if_sff_int(const struct if_sffpage *sff, size_t start)
+{
+       const uint8_t *d = sff->sff_data + start;
+
+       return (d[0] << 8 | d[1]);
+}
+
+static uint16_t
+if_sff_uint(const struct if_sffpage *sff, size_t start)
+{
+       const uint8_t *d = sff->sff_data + start;
+
+       return (d[0] << 8 | d[1]);
+}
+
+static float
+if_sff_power2dbm(uint16_t power)
+{
+       return (10.0 * log10f((float)power / 10000.0));
+}
+
+static int
+if_sff8472(int s, const char *ifname, int dump, const struct if_sffpage *pg0)
+{
+       struct if_sffpage ddm;
+       uint8_t con, ddm_types;
+
+       con = pg0->sff_data[SFF8472_CON];
+       printf("\tconnector: %s (%02x)\n", sff_con_name(con), con);
+
+       if_sff_ascii_print(pg0, "vendor",
+           SFF8472_VENDOR_START, SFF8472_VENDOR_END);
+       if_sff_ascii_print(pg0, "product",
+           SFF8472_PRODUCT_START, SFF8472_PRODUCT_END);
+       if_sff_ascii_print(pg0, "revision",
+           SFF8472_REVISION_START, SFF8472_REVISION_END);
+       if_sff_ascii_print(pg0, "serial",
+           SFF8472_SERIAL_START, SFF8472_SERIAL_END);
+       if_sff_date_print(pg0, "date", SFF8472_DATECODE);
+
+       ddm_types = pg0->sff_data[SFF8472_DDM_TYPE];
+       if (pg0->sff_data[SFF8472_COMPLIANCE] == SFF8472_COMPLIANCE_NONE ||
+           !ISSET(ddm_types, SFF8472_DDM_TYPE_IMPL))
+               return (0);
+
+       if_sffpage_init(&ddm, ifname, IFSFF_ADDR_DDM, 0);
+       if (ioctl(s, SIOCGIFSFFPAGE, (caddr_t)&ddm) == -1)
+               return (-1);
+
+       if (dump)
+               if_sffpage_dump(ifname, &ddm);
+
+       if (ISSET(ddm_types, SFF8472_DDM_TYPE_CAL_EXT)) {
+               printf("\tcalibration: external "
+                   "(WARNING: needs more code)\n");
+       }
+
+       printf("\ttemperature: %.02f C\n",
+           if_sff_int(&ddm, SFF8472_DDM_TEMP) / SFF_TEMP_FACTOR);
+       printf("\tvcc: %.02f V\n",
+           if_sff_uint(&ddm, SFF8472_DDM_VCC) / SFF_VCC_FACTOR);
+       printf("\ttx-bias: %.02f mA\n",
+           if_sff_uint(&ddm, SFF8472_DDM_TX_BIAS) / SFF_BIAS_FACTOR);
+       printf("\ttx-power: %.02f dBm\n",
+           if_sff_power2dbm(if_sff_uint(&ddm, SFF8472_DDM_TX_POWER)));
+       printf("\trx-power: %.02f dBm %s\n",
+           if_sff_power2dbm(if_sff_uint(&ddm, SFF8472_DDM_RX_POWER)),
+           ISSET(ddm_types, SFF8472_DDM_TYPE_AVG_POWER) ? "average" : "OMA");
+
+       return (0);
+}
+
+static int
+printable(int ch)
+{
+       if (ch == '\0')
+               return ('_');
+       if (!isprint(ch))
+               return ('~');
+
+       return (ch);
+}
+
+static void
+hexdump(const void *d, size_t datalen)
+{
+       const uint8_t *data = d;
+       int i, j = 0;
+
+       for (i = 0; i < datalen; i += j) {
+               printf("% 4d: ", i);
+               for (j = 0; j < 16 && i+j < datalen; j++)
+                       printf("%02x ", data[i + j]);
+               while (j++ < 16)
+                       printf("   ");
+               printf("|");
+               for (j = 0; j < 16 && i+j < datalen; j++)
+                       putchar(printable(data[i + j]));
+               printf("|\n");
+       }
+}
+
+#endif /* SMALL */
Index: sys/dev/pci/if_ix.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_ix.c,v
retrieving revision 1.156
diff -u -p -r1.156 if_ix.c
--- sys/dev/pci/if_ix.c 1 Mar 2019 06:15:59 -0000       1.156
+++ sys/dev/pci/if_ix.c 8 Apr 2019 12:45:33 -0000
@@ -96,6 +96,7 @@ int   ixgbe_detach(struct device *, int);
 void   ixgbe_start(struct ifqueue *);
 int    ixgbe_ioctl(struct ifnet *, u_long, caddr_t);
 int    ixgbe_rxrinfo(struct ix_softc *, struct if_rxrinfo *);
+int    ixgbe_get_sffpage(struct ix_softc *, struct if_sffpage *);
 void   ixgbe_watchdog(struct ifnet *);
 void   ixgbe_init(void *);
 void   ixgbe_stop(void *);
@@ -225,6 +226,8 @@ ixgbe_attach(struct device *parent, stru
        sc->osdep.os_sc = sc;
        sc->osdep.os_pa = *pa;
 
+       rw_init(&sc->sfflock, "ixsff");
+
        /* Set up the timer callout */
        timeout_set(&sc->timer, ixgbe_local_timer, sc);
        timeout_set(&sc->rx_refill, ixgbe_rxrefill, sc);
@@ -498,6 +501,15 @@ ixgbe_ioctl(struct ifnet * ifp, u_long c
                error = ixgbe_rxrinfo(sc, (struct if_rxrinfo *)ifr->ifr_data);
                break;
 
+       case SIOCGIFSFFPAGE:
+               error = rw_enter(&sc->sfflock, RW_WRITE|RW_INTR);
+               if (error != 0)
+                       break;
+
+               error = ixgbe_get_sffpage(sc, (struct if_sffpage *)data);
+               rw_exit(&sc->sfflock);
+               break;
+
        default:
                error = ether_ioctl(ifp, &sc->arpcom, command, data);
        }
@@ -512,6 +524,50 @@ ixgbe_ioctl(struct ifnet * ifp, u_long c
        }
 
        splx(s);
+       return (error);
+}
+
+int
+ixgbe_get_sffpage(struct ix_softc *sc, struct if_sffpage *sff)
+{
+       struct ixgbe_hw *hw = &sc->hw;
+       uint32_t swfw_mask = hw->phy.phy_semaphore_mask;
+       uint8_t page;
+       size_t i;
+       int error = EIO;
+
+       if (hw->phy.type == ixgbe_phy_fw)
+               return (ENODEV);
+
+       if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
+               return (EBUSY); /* XXX */
+
+       if (sff->sff_addr == IFSFF_ADDR_EEPROM) {
+               if (hw->phy.ops.read_i2c_byte_unlocked(hw, 127,
+                   IFSFF_ADDR_EEPROM, &page))
+                       goto error;
+               if (page != sff->sff_page &&
+                   hw->phy.ops.write_i2c_byte_unlocked(hw, 127,
+                   IFSFF_ADDR_EEPROM, sff->sff_page))
+                       goto error;
+       }
+
+       for (i = 0; i < sizeof(sff->sff_data); i++) {
+               if (hw->phy.ops.read_i2c_byte_unlocked(hw, i,
+                   sff->sff_addr, &sff->sff_data[i]))
+                       goto error;
+       }
+
+       if (sff->sff_addr == IFSFF_ADDR_EEPROM) {
+               if (page != sff->sff_page &&
+                   hw->phy.ops.write_i2c_byte_unlocked(hw, 127,
+                   IFSFF_ADDR_EEPROM, page))
+                       goto error;
+       }
+
+       error = 0;
+error:
+       hw->mac.ops.release_swfw_sync(hw, swfw_mask);
        return (error);
 }
 
Index: sys/dev/pci/if_ixl.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_ixl.c,v
retrieving revision 1.34
diff -u -p -r1.34 if_ixl.c
--- sys/dev/pci/if_ixl.c        1 Apr 2019 03:01:14 -0000       1.34
+++ sys/dev/pci/if_ixl.c        8 Apr 2019 12:45:33 -0000
@@ -170,6 +170,8 @@ struct ixl_aq_desc {
 #define IXL_AQ_OP_PHY_RESTART_AN       0x0605
 #define IXL_AQ_OP_PHY_LINK_STATUS      0x0607
 #define IXL_AQ_OP_PHY_SET_EVENT_MASK   0x0613
+#define IXL_AQ_OP_PHY_SET_REGISTER     0x0628
+#define IXL_AQ_OP_PHY_GET_REGISTER     0x0629
 #define IXL_AQ_OP_LLDP_GET_MIB         0x0a00
 #define IXL_AQ_OP_LLDP_MIB_CHG_EV      0x0a01
 #define IXL_AQ_OP_LLDP_ADD_TLV         0x0a02
@@ -596,6 +598,18 @@ struct ixl_aq_veb_reply {
 #define IXL_AQ_PHY_REPORT_QUAL         (1 << 0)
 #define IXL_AQ_PHY_REPORT_INIT         (1 << 1)
 
+struct ixl_aq_phy_reg_access {
+       uint8_t         phy_iface;
+#define IXL_AQ_PHY_IF_INTERNAL         0
+#define IXL_AQ_PHY_IF_EXTERNAL         1
+#define IXL_AQ_PHY_IF_MODULE           2
+       uint8_t         dev_addr;
+       uint16_t        _reserved1;
+       uint32_t        reg;
+       uint32_t        val;
+       uint32_t        _reserved2;
+} __packed __aligned(16);
+
 /* RESTART_AN param[0] */
 #define IXL_AQ_PHY_RESTART_AN          (1 << 1)
 #define IXL_AQ_PHY_LINK_ENABLE         (1 << 2)
@@ -1124,6 +1138,8 @@ struct ixl_softc {
 
        struct rwlock            sc_cfg_lock;
        unsigned int             sc_dead;
+
+       struct rwlock            sc_sff_lock;
 };
 #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
 
@@ -1171,6 +1187,12 @@ static void      ixl_arq(void *);
 static void    ixl_hmc_pack(void *, const void *,
                    const struct ixl_hmc_pack *, unsigned int);
 
+static int     ixl_get_sffpage(struct ixl_softc *, struct if_sffpage *);
+static int     ixl_sff_get_byte(struct ixl_softc *, uint8_t, uint32_t,
+                   uint8_t *);
+static int     ixl_sff_set_byte(struct ixl_softc *, uint8_t, uint32_t,
+                   uint8_t);
+
 static int     ixl_match(struct device *, void *, void *);
 static void    ixl_attach(struct device *, struct device *, void *);
 
@@ -1347,6 +1369,8 @@ ixl_aq_dva(struct ixl_aq_desc *iaq, bus_
 #define HTOLE16(_x)    (_x)
 #endif
 
+static struct rwlock ixl_sff_lock = RWLOCK_INITIALIZER("ixlsff");
+
 static const struct pci_matchid ixl_devices[] = {
 #ifdef notyet
        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_XL710_VF },
@@ -1771,6 +1795,15 @@ ixl_ioctl(struct ifnet *ifp, u_long cmd,
                }
                break;
 
+       case SIOCGIFSFFPAGE:
+               error = rw_enter(&ixl_sff_lock, RW_WRITE|RW_INTR);
+               if (error != 0)
+                       break;
+
+               error = ixl_get_sffpage(sc, (struct if_sffpage *)data);
+               rw_exit(&ixl_sff_lock);
+               break;
+
        default:
                error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
                break;
@@ -3427,6 +3460,115 @@ ixl_get_link_status(struct ixl_softc *sc
        }
 
        sc->sc_ac.ac_if.if_link_state = ixl_set_link_status(sc, &iaq);
+
+       return (0);
+}
+
+static int
+ixl_get_sffpage(struct ixl_softc *sc, struct if_sffpage *sff)
+{
+       uint8_t page;
+       size_t i;
+       int error;
+
+       if (sff->sff_addr == IFSFF_ADDR_EEPROM) {
+               error = ixl_sff_get_byte(sc, IFSFF_ADDR_EEPROM, 127, &page);
+               if (error != 0)
+                       return (error);
+               if (page != sff->sff_page) {
+                       error = ixl_sff_set_byte(sc, IFSFF_ADDR_EEPROM, 127,
+                           sff->sff_page);
+                       if (error != 0)
+                               return (error);
+               }
+       }
+
+       for (i = 0; i < sizeof(sff->sff_data); i++) {
+               error = ixl_sff_get_byte(sc, sff->sff_addr, i,
+                   &sff->sff_data[i]);
+               if (error != 0)
+                       return (error);
+       }
+
+       if (sff->sff_addr == IFSFF_ADDR_EEPROM) {
+               if (page != sff->sff_page) {
+                       error = ixl_sff_set_byte(sc, IFSFF_ADDR_EEPROM, 127,
+                           page);
+                       if (error != 0)
+                               return (error);
+               }
+       }
+
+       return (0);
+}
+
+static int
+ixl_sff_get_byte(struct ixl_softc *sc, uint8_t dev, uint32_t reg, uint8_t *p)
+{
+       struct ixl_atq iatq;
+       struct ixl_aq_desc *iaq;
+       struct ixl_aq_phy_reg_access *param;
+
+       memset(&iatq, 0, sizeof(iatq));
+       iaq = &iatq.iatq_desc;
+       iaq->iaq_opcode = htole16(IXL_AQ_OP_PHY_GET_REGISTER);
+       param = (struct ixl_aq_phy_reg_access *)iaq->iaq_param;
+       param->phy_iface = IXL_AQ_PHY_IF_MODULE;
+       param->dev_addr = dev;
+       htolem32(&param->reg, reg);
+
+       ixl_atq_exec(sc, &iatq, "ixlsffget");
+
+       switch (iaq->iaq_retval) {
+       case htole16(IXL_AQ_RC_OK):
+               break;
+       case htole16(IXL_AQ_RC_EBUSY):
+               return (EBUSY);
+       case htole16(IXL_AQ_RC_ESRCH):
+               return (ENODEV);
+       case htole16(IXL_AQ_RC_EIO):
+       case htole16(IXL_AQ_RC_EINVAL):
+       default:
+               printf("%s: %u\n", __func__, lemtoh16(&iaq->iaq_retval));
+               return (EIO);
+       }
+
+       *p = lemtoh32(&param->val);
+
+       return (0);
+}
+
+
+static int
+ixl_sff_set_byte(struct ixl_softc *sc, uint8_t dev, uint32_t reg, uint8_t v)
+{
+       struct ixl_atq iatq;
+       struct ixl_aq_desc *iaq;
+       struct ixl_aq_phy_reg_access *param;
+
+       memset(&iatq, 0, sizeof(iatq));
+       iaq = &iatq.iatq_desc;
+       iaq->iaq_opcode = htole16(IXL_AQ_OP_PHY_SET_REGISTER);
+       param = (struct ixl_aq_phy_reg_access *)iaq->iaq_param;
+       param->phy_iface = IXL_AQ_PHY_IF_MODULE;
+       param->dev_addr = dev;
+       htolem32(&param->reg, reg);
+       htolem32(&param->val, v);
+
+       ixl_atq_exec(sc, &iatq, "ixlsffset");
+
+       switch (iaq->iaq_retval) {
+       case htole16(IXL_AQ_RC_OK):
+               break;
+       case htole16(IXL_AQ_RC_EBUSY):
+               return (EBUSY);
+       case htole16(IXL_AQ_RC_ESRCH):
+               return (ENODEV);
+       case htole16(IXL_AQ_RC_EIO):
+       case htole16(IXL_AQ_RC_EINVAL):
+       default:
+               return (EIO);
+       }
 
        return (0);
 }
Index: sys/dev/pci/ixgbe_type.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/ixgbe_type.h,v
retrieving revision 1.31
diff -u -p -r1.31 ixgbe_type.h
--- sys/dev/pci/ixgbe_type.h    18 Nov 2016 14:16:10 -0000      1.31
+++ sys/dev/pci/ixgbe_type.h    8 Apr 2019 12:45:33 -0000
@@ -3142,7 +3142,9 @@ enum ixgbe_phy_type {
        ixgbe_phy_aq,
        ixgbe_phy_x550em_kr,
        ixgbe_phy_x550em_kx4,
+       ixgbe_phy_x550em_xfi,
        ixgbe_phy_x550em_ext_t,
+       ixgbe_phy_ext_1g_t,
        ixgbe_phy_cu_unknown,
        ixgbe_phy_qt,
        ixgbe_phy_xaui,
@@ -3160,6 +3162,8 @@ enum ixgbe_phy_type {
        ixgbe_phy_qsfp_intel,
        ixgbe_phy_qsfp_unknown,
        ixgbe_phy_sfp_unsupported, /*Enforce bit set with unsupported module*/
+       ixgbe_phy_sgmii,
+       ixgbe_phy_fw,
        ixgbe_phy_generic
 };
 
Index: sys/net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.573
diff -u -p -r1.573 if.c
--- sys/net/if.c        1 Mar 2019 04:47:32 -0000       1.573
+++ sys/net/if.c        8 Apr 2019 12:45:33 -0000
@@ -144,6 +144,8 @@ int if_detached_ioctl(struct ifnet *, u_
 
 int    ifioctl_get(u_long, caddr_t);
 int    ifconf(caddr_t);
+static int
+       if_sffpage_check(const caddr_t);
 
 int    if_getgroup(caddr_t, struct ifnet *);
 int    if_getgroupmembers(caddr_t);
@@ -2143,6 +2145,19 @@ ifioctl(struct socket *so, u_long cmd, c
                NET_UNLOCK();
                break;
 
+       case SIOCGIFSFFPAGE:
+               error = suser(p);
+               if (error != 0)
+                       break;
+
+               error = if_sffpage_check(data);
+               if (error != 0)
+                       break;
+
+               /* don't take NET_LOCK because i2c reads take a long time */
+               error = ((*ifp->if_ioctl)(ifp, cmd, data));
+               break;
+
        case SIOCSETKALIVE:
        case SIOCDIFPHYADDR:
        case SIOCSLIFPHYADDR:
@@ -2302,6 +2317,22 @@ ifioctl_get(u_long cmd, caddr_t data)
        NET_RUNLOCK();
 
        return (error);
+}
+
+static int
+if_sffpage_check(const caddr_t data)
+{
+       const struct if_sffpage *sff = (const struct if_sffpage *)data;
+
+       switch (sff->sff_addr) {
+       case IFSFF_ADDR_EEPROM:
+       case IFSFF_ADDR_DDM:
+               break;
+       default:
+               return (EINVAL);
+       }
+
+       return (0);
 }
 
 /*
Index: sys/net/if.h
===================================================================
RCS file: /cvs/src/sys/net/if.h,v
retrieving revision 1.199
diff -u -p -r1.199 if.h
--- sys/net/if.h        23 Jan 2019 08:23:18 -0000      1.199
+++ sys/net/if.h        8 Apr 2019 12:45:33 -0000
@@ -501,6 +501,20 @@ struct if_parent {
        char            ifp_parent[IFNAMSIZ];
 };
 
+/* SIOCGIFSFFPAGE */
+
+#define IFSFF_ADDR_EEPROM      0xa0
+#define IFSFF_ADDR_DDM         0xa2
+
+#define IFSFF_DATA_LEN         256
+
+struct if_sffpage {
+       char             sff_ifname[IFNAMSIZ];  /* u -> k */
+       uint8_t          sff_addr;              /* u -> k */
+       uint8_t          sff_page;              /* u -> k */
+       uint8_t          sff_data[256];         /* k -> u */
+};
+
 #include <net/if_arp.h>
 
 #ifdef _KERNEL
Index: sys/sys/sockio.h
===================================================================
RCS file: /cvs/src/sys/sys/sockio.h,v
retrieving revision 1.80
diff -u -p -r1.80 sockio.h
--- sys/sys/sockio.h    26 Feb 2019 03:19:11 -0000      1.80
+++ sys/sys/sockio.h    8 Apr 2019 12:45:33 -0000
@@ -68,6 +68,7 @@
 /* 53 and 54 used to be SIOC[SG]IFMEDIA with a 32 bit media word */
 #define        SIOCSIFMEDIA    _IOWR('i', 55, struct ifreq)    /* set net 
media */
 #define        SIOCGIFMEDIA    _IOWR('i', 56, struct ifmediareq) /* get net 
media */
+#define        SIOCGIFSFFPAGE  _IOWR('i', 57, struct if_sffpage) /* get SFF 
page */
 
 #define        SIOCDIFPHYADDR   _IOW('i', 73, struct ifreq)    /* delete gif 
addrs */
 #define        SIOCSLIFPHYADDR  _IOW('i', 74, struct if_laddrreq) /* set gif 
addrs */

Reply via email to