1*4cfa599eSbluhm /* $OpenBSD: sff.c,v 1.23 2019/10/24 18:54:10 bluhm Exp $ */
24ce43bedSdlg
34ce43bedSdlg /*
44ce43bedSdlg * Copyright (c) 2019 David Gwynne <dlg@openbsd.org>
54ce43bedSdlg *
64ce43bedSdlg * Permission to use, copy, modify, and distribute this software for any
74ce43bedSdlg * purpose with or without fee is hereby granted, provided that the above
84ce43bedSdlg * copyright notice and this permission notice appear in all copies.
94ce43bedSdlg *
104ce43bedSdlg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
114ce43bedSdlg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
124ce43bedSdlg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
134ce43bedSdlg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
144ce43bedSdlg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
154ce43bedSdlg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
164ce43bedSdlg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
174ce43bedSdlg */
184ce43bedSdlg
194ce43bedSdlg #ifndef SMALL
204ce43bedSdlg
214ce43bedSdlg #include <sys/ioctl.h>
224ce43bedSdlg
234ce43bedSdlg #include <net/if.h>
244ce43bedSdlg
254ce43bedSdlg #include <math.h>
264ce43bedSdlg #include <ctype.h>
274ce43bedSdlg #include <err.h>
284ce43bedSdlg #include <errno.h>
294ce43bedSdlg #include <stdio.h>
304ce43bedSdlg #include <stdint.h>
314ce43bedSdlg #include <stdlib.h>
324ce43bedSdlg #include <string.h>
334ce43bedSdlg #include <unistd.h>
344ce43bedSdlg #include <limits.h>
354ce43bedSdlg #include <vis.h>
364ce43bedSdlg
37d6a6566dSbluhm #include "ifconfig.h"
38d6a6566dSbluhm
394ce43bedSdlg #ifndef nitems
404ce43bedSdlg #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
414ce43bedSdlg #endif
424ce43bedSdlg
434ce43bedSdlg #ifndef ISSET
444ce43bedSdlg #define ISSET(_w, _m) ((_w) & (_m))
454ce43bedSdlg #endif
464ce43bedSdlg
47b46ace34Sdlg #define SFF_THRESH_HI_ALARM 0
48b46ace34Sdlg #define SFF_THRESH_LO_ALARM 1
49b46ace34Sdlg #define SFF_THRESH_HI_WARN 2
50b46ace34Sdlg #define SFF_THRESH_LO_WARN 3
51b46ace34Sdlg #define SFF_THRESH_COUNT 4
52b46ace34Sdlg
53b46ace34Sdlg #define SFF_THRESH_REG(_i) ((_i) * 2)
54b46ace34Sdlg
55b46ace34Sdlg struct sff_thresholds {
56b46ace34Sdlg float thresholds[SFF_THRESH_COUNT];
57b46ace34Sdlg };
58b46ace34Sdlg
594662fdbeSdlg struct sff_media_map {
604662fdbeSdlg float factor_wavelength;
614662fdbeSdlg int scale_om1;
624662fdbeSdlg int scale_om2;
634662fdbeSdlg int scale_om3;
644662fdbeSdlg uint8_t connector_type;
654662fdbeSdlg uint8_t wavelength;
664662fdbeSdlg uint8_t dist_smf_m;
674662fdbeSdlg uint8_t dist_smf_km;
684662fdbeSdlg uint8_t dist_om1;
694662fdbeSdlg uint8_t dist_om2;
704662fdbeSdlg uint8_t dist_om3;
714662fdbeSdlg uint8_t dist_cu;
724662fdbeSdlg };
734662fdbeSdlg
744ce43bedSdlg #define SFF8024_ID_UNKNOWN 0x00
754ce43bedSdlg #define SFF8024_ID_GBIC 0x01
764ce43bedSdlg #define SFF8024_ID_MOBO 0x02 /* Module/connector soldered to mobo */
774ce43bedSdlg /* using SFF-8472 */
784ce43bedSdlg #define SFF8024_ID_SFP 0x03 /* SFP/SFP+/SFP28 */
794ce43bedSdlg #define SFF8024_ID_300PIN_XBI 0x04 /* 300 pin XBI */
804ce43bedSdlg #define SFF8024_ID_XENPAK 0x05
814ce43bedSdlg #define SFF8024_ID_XFP 0x06
824ce43bedSdlg #define SFF8024_ID_XFF 0x07
834ce43bedSdlg #define SFF8024_ID_XFPE 0x08 /* XFP-E */
844ce43bedSdlg #define SFF8024_ID_XPAK 0x09
854ce43bedSdlg #define SFF8024_ID_X2 0x0a
864ce43bedSdlg #define SFF8024_ID_DWDM_SFP 0x0b /* DWDM-SFP/SFP+ */
874ce43bedSdlg /* not using SFF-8472 */
884ce43bedSdlg #define SFF8024_ID_QSFP 0x0c
894ce43bedSdlg #define SFF8024_ID_QSFP_PLUS 0x0d /* or later */
904ce43bedSdlg /* using SFF-8436/8665/8685 et al */
914ce43bedSdlg #define SFF8024_ID_CXP 0x0e /* or later */
924ce43bedSdlg #define SFF8024_ID_HD4X 0x0f /* shielded mini multilane HD 4X */
934ce43bedSdlg #define SFF8024_ID_HD8X 0x10 /* shielded mini multilane HD 8X */
944ce43bedSdlg #define SFF8024_ID_QSFP28 0x11 /* or later */
954ce43bedSdlg /* using SFF-8665 et al */
964ce43bedSdlg #define SFF8024_ID_CXP2 0x12 /* aka CXP28, or later */
974ce43bedSdlg #define SFF8024_ID_CDFP 0x13 /* style 1/style 2 */
984ce43bedSdlg #define SFF8024_ID_HD4X_FAN 0x14 /* shielded mini multilane HD 4X fanout */
994ce43bedSdlg #define SFF8024_ID_HD8X_FAN 0x15 /* shielded mini multilane HD 8X fanout */
1004ce43bedSdlg #define SFF8024_ID_CDFP3 0x16 /* style 3 */
1014ce43bedSdlg #define SFF8024_ID_uQSFP 0x17 /* microQSFP */
1024ce43bedSdlg #define SFF8024_ID_QSFP_DD 0x18 /* QSFP-DD double density 8x */
1034ce43bedSdlg /* INF-8628 */
1044ce43bedSdlg #define SFF8024_ID_RESERVED 0x7f /* up to here is reserved */
1054ce43bedSdlg /* 0x80 to 0xff is vendor specific */
1064ce43bedSdlg
1074ce43bedSdlg #define SFF8024_ID_IS_RESERVED(_id) ((_id) <= SFF8024_ID_RESERVED)
1084ce43bedSdlg #define SFF8024_ID_IS_VENDOR(_id) ((_id) > SFF8024_ID_RESERVED)
1094ce43bedSdlg
1104ce43bedSdlg #define SFF8024_CON_UNKNOWN 0x00
1114ce43bedSdlg #define SFF8024_CON_SC 0x01 /* Subscriber Connector */
1124ce43bedSdlg #define SFF8024_CON_FC_1 0x02 /* Fibre Channel Style 1 copper */
1134ce43bedSdlg #define SFF8024_CON_FC_2 0x03 /* Fibre Channel Style 2 copper */
1144ce43bedSdlg #define SFF8024_CON_BNC_TNC 0x04 /* BNC/TNC */
1154ce43bedSdlg #define SFF8024_CON_FC_COAX 0x05 /* Fibre Channel coax headers */
1164ce43bedSdlg #define SFF8024_CON_FJ 0x06 /* Fibre Jack */
1174ce43bedSdlg #define SFF8024_CON_LC 0x07 /* Lucent Connector */
1184ce43bedSdlg #define SFF8024_CON_MT_RJ 0x08 /* Mechanical Transfer - Registered Jack */
1194ce43bedSdlg #define SFF8024_CON_MU 0x09 /* Multiple Optical */
1204ce43bedSdlg #define SFF8024_CON_SG 0x0a
1214ce43bedSdlg #define SFF8024_CON_O_PIGTAIL 0x0b /* Optical Pigtail */
1224ce43bedSdlg #define SFF8024_CON_MPO_1x12 0x0c /* Multifiber Parallel Optic 1x12 */
1234ce43bedSdlg #define SFF8024_CON_MPO_2x16 0x0e /* Multifiber Parallel Optic 2x16 */
1244ce43bedSdlg #define SFF8024_CON_HSSDC2 0x20 /* High Speed Serial Data Connector */
1254ce43bedSdlg #define SFF8024_CON_Cu_PIGTAIL 0x21 /* Copper Pigtail */
1264ce43bedSdlg #define SFF8024_CON_RJ45 0x22
1274ce43bedSdlg #define SFF8024_CON_NO 0x23 /* No separable connector */
1284ce43bedSdlg #define SFF8024_CON_MXC_2x16 0x24
1294ce43bedSdlg #define SFF8024_CON_RESERVED 0x7f /* up to here is reserved */
1304ce43bedSdlg /* 0x80 to 0xff is vendor specific */
1314ce43bedSdlg
1324ce43bedSdlg #define SFF8024_CON_IS_RESERVED(_id) ((_id) <= SFF8024_CON_RESERVED)
1334ce43bedSdlg #define SFF8024_CON_IS_VENDOR(_id) ((_id) > SFF8024_CON_RESERVED)
1344ce43bedSdlg
1354ce43bedSdlg static const char *sff8024_id_names[] = {
1364ce43bedSdlg [SFF8024_ID_UNKNOWN] = "Unknown",
1374ce43bedSdlg [SFF8024_ID_GBIC] = "GBIC",
1384ce43bedSdlg [SFF8024_ID_SFP] = "SFP",
139d2ae8f01Ssthen [SFF8024_ID_300PIN_XBI] = "XBI",
1404ce43bedSdlg [SFF8024_ID_XENPAK] = "XENPAK",
1414ce43bedSdlg [SFF8024_ID_XFP] = "XFP",
1424ce43bedSdlg [SFF8024_ID_XFF] = "XFF",
1434ce43bedSdlg [SFF8024_ID_XFPE] = "XFPE",
1444ce43bedSdlg [SFF8024_ID_XPAK] = "XPAK",
1454ce43bedSdlg [SFF8024_ID_X2] = "X2",
1464ce43bedSdlg [SFF8024_ID_DWDM_SFP] = "DWDM-SFP",
1474ce43bedSdlg [SFF8024_ID_QSFP] = "QSFP",
1484ce43bedSdlg [SFF8024_ID_QSFP_PLUS] = "QSFP+",
1494ce43bedSdlg [SFF8024_ID_CXP] = "CXP",
150d2ae8f01Ssthen [SFF8024_ID_HD4X] = "HD 4X",
151d2ae8f01Ssthen [SFF8024_ID_HD8X] = "HD 8X",
1524ce43bedSdlg [SFF8024_ID_QSFP28] = "QSFP28",
1534ce43bedSdlg [SFF8024_ID_CXP2] = "CXP2",
1544ce43bedSdlg [SFF8024_ID_CDFP] = "CDFP Style 1/2",
155d2ae8f01Ssthen [SFF8024_ID_HD4X_FAN] = "HD 4X Fanout",
156d2ae8f01Ssthen [SFF8024_ID_HD8X_FAN] = "HD 8X Fanout",
1574ce43bedSdlg [SFF8024_ID_CDFP3] = "CDFP Style 3",
1584ce43bedSdlg [SFF8024_ID_uQSFP] = "microQSFP",
159d2ae8f01Ssthen [SFF8024_ID_QSFP_DD] = "QSFP-DD",
1604ce43bedSdlg };
1614ce43bedSdlg
1624ce43bedSdlg static const char *sff8024_con_names[] = {
1634ce43bedSdlg [SFF8024_CON_UNKNOWN] = "Unknown",
1644ce43bedSdlg [SFF8024_CON_SC] = "SC",
165d2ae8f01Ssthen [SFF8024_CON_FC_1] = "FC Style 1",
166d2ae8f01Ssthen [SFF8024_CON_FC_2] = "FC Style 2",
1674ce43bedSdlg [SFF8024_CON_BNC_TNC] = "BNC/TNC",
168d2ae8f01Ssthen [SFF8024_CON_FC_COAX] = "FC coax headers",
169d2ae8f01Ssthen [SFF8024_CON_FJ] = "FJ",
1704ce43bedSdlg [SFF8024_CON_LC] = "LC",
1714ce43bedSdlg [SFF8024_CON_MT_RJ] = "MT-RJ",
1724ce43bedSdlg [SFF8024_CON_MU] = "MU",
1734ce43bedSdlg [SFF8024_CON_SG] = "SG",
174d630c397Sderaadt [SFF8024_CON_O_PIGTAIL] = "AOC",
175f52625bcSderaadt [SFF8024_CON_MPO_1x12] = "MPO 1x12",
176f52625bcSderaadt [SFF8024_CON_MPO_2x16] = "MPO 2x16",
1774ce43bedSdlg [SFF8024_CON_HSSDC2] = "HSSDC II",
1784ce43bedSdlg [SFF8024_CON_Cu_PIGTAIL]
179d630c397Sderaadt = "DAC",
1804ce43bedSdlg [SFF8024_CON_RJ45] = "RJ45",
18120428388Sdlg [SFF8024_CON_NO] = "No connector",
1824ce43bedSdlg [SFF8024_CON_MXC_2x16] = "MXC 2x16",
1834ce43bedSdlg };
1844ce43bedSdlg
1854ce43bedSdlg #define SFF8472_ID 0 /* SFF8027 for identifier values */
1864ce43bedSdlg #define SFF8472_EXT_ID 1
1874ce43bedSdlg #define SFF8472_EXT_ID_UNSPECIFIED 0x00
1884ce43bedSdlg #define SFF8472_EXT_ID_MOD_DEF_1 0x01
1894ce43bedSdlg #define SFF8472_EXT_ID_MOD_DEF_2 0x02
1904ce43bedSdlg #define SFF8472_EXT_ID_MOD_DEF_3 0x03
1914ce43bedSdlg #define SFF8472_EXT_ID_2WIRE 0x04
1924ce43bedSdlg #define SFF8472_EXT_ID_MOD_DEF_5 0x05
1934ce43bedSdlg #define SFF8472_EXT_ID_MOD_DEF_6 0x06
1944ce43bedSdlg #define SFF8472_EXT_ID_MOD_DEF_7 0x07
1954ce43bedSdlg #define SFF8472_CON 2 /* SFF8027 for connector values */
19623a4e4a1Ssthen #define SFF8472_DIST_SMF_KM 14
19723a4e4a1Ssthen #define SFF8472_DIST_SMF_M 15
19823a4e4a1Ssthen #define SFF8472_DIST_OM2 16
19923a4e4a1Ssthen #define SFF8472_DIST_OM1 17
20023a4e4a1Ssthen #define SFF8472_DIST_CU 18
20123a4e4a1Ssthen #define SFF8472_DIST_OM3 19
2024ce43bedSdlg #define SFF8472_VENDOR_START 20
2034ce43bedSdlg #define SFF8472_VENDOR_END 35
2044ce43bedSdlg #define SFF8472_PRODUCT_START 40
2054ce43bedSdlg #define SFF8472_PRODUCT_END 55
2064ce43bedSdlg #define SFF8472_REVISION_START 56
2074ce43bedSdlg #define SFF8472_REVISION_END 59
208d2ae8f01Ssthen #define SFF8472_WAVELENGTH 60
2094ce43bedSdlg #define SFF8472_SERIAL_START 68
2104ce43bedSdlg #define SFF8472_SERIAL_END 83
2114ce43bedSdlg #define SFF8472_DATECODE 84
2124ce43bedSdlg #define SFF8472_DDM_TYPE 92
2134ce43bedSdlg #define SFF8472_DDM_TYPE_AVG_POWER (1U << 3)
2144ce43bedSdlg #define SFF8472_DDM_TYPE_CAL_EXT (1U << 4)
2154ce43bedSdlg #define SFF8472_DDM_TYPE_CAL_INT (1U << 5)
2164ce43bedSdlg #define SFF8472_DDM_TYPE_IMPL (1U << 6)
2174ce43bedSdlg #define SFF8472_COMPLIANCE 94
2184ce43bedSdlg #define SFF8472_COMPLIANCE_NONE 0x00
2194ce43bedSdlg #define SFF8472_COMPLIANCE_9_3 0x01 /* SFF-8472 Rev 9.3 */
2204ce43bedSdlg #define SFF8472_COMPLIANCE_9_5 0x02 /* SFF-8472 Rev 9.5 */
2214ce43bedSdlg #define SFF8472_COMPLIANCE_10_2 0x03 /* SFF-8472 Rev 10.2 */
2224ce43bedSdlg #define SFF8472_COMPLIANCE_10_4 0x04 /* SFF-8472 Rev 10.4 */
2234ce43bedSdlg #define SFF8472_COMPLIANCE_11_0 0x05 /* SFF-8472 Rev 11.0 */
2244ce43bedSdlg #define SFF8472_COMPLIANCE_11_3 0x06 /* SFF-8472 Rev 11.3 */
2254ce43bedSdlg #define SFF8472_COMPLIANCE_11_4 0x07 /* SFF-8472 Rev 11.4 */
2264ce43bedSdlg #define SFF8472_COMPLIANCE_12_3 0x08 /* SFF-8472 Rev 12.3 */
2274ce43bedSdlg
2284662fdbeSdlg static const struct sff_media_map sff8472_media_map = {
2294662fdbeSdlg .connector_type = SFF8472_CON,
2304662fdbeSdlg .wavelength = SFF8472_WAVELENGTH,
2314662fdbeSdlg .factor_wavelength = 1.0,
2324662fdbeSdlg .dist_smf_m = SFF8472_DIST_SMF_M,
2334662fdbeSdlg .dist_smf_km = SFF8472_DIST_SMF_KM,
2344662fdbeSdlg .dist_om1 = SFF8472_DIST_OM1,
2354662fdbeSdlg .scale_om1 = 10,
2364662fdbeSdlg .dist_om2 = SFF8472_DIST_OM2,
2374662fdbeSdlg .scale_om2 = 10,
2384662fdbeSdlg .dist_om3 = SFF8472_DIST_OM3,
2394662fdbeSdlg .scale_om3 = 20,
2404662fdbeSdlg .dist_cu = SFF8472_DIST_CU,
2414662fdbeSdlg };
2424662fdbeSdlg
2434ce43bedSdlg /*
2444ce43bedSdlg * page 0xa2
2454ce43bedSdlg */
246d2ae8f01Ssthen #define SFF8472_AW_TEMP 0
247d2ae8f01Ssthen #define SFF8472_AW_VCC 8
248d2ae8f01Ssthen #define SFF8472_AW_TX_BIAS 16
249d2ae8f01Ssthen #define SFF8472_AW_TX_POWER 24
250d2ae8f01Ssthen #define SFF8472_AW_RX_POWER 32
251d2ae8f01Ssthen #define ALRM_HIGH 0
252d2ae8f01Ssthen #define ALRM_LOW 2
253d2ae8f01Ssthen #define WARN_HIGH 4
254d2ae8f01Ssthen #define WARN_LOW 6
2554ce43bedSdlg #define SFF8472_DDM_TEMP 96
2564ce43bedSdlg #define SFF8472_DDM_VCC 98
2574ce43bedSdlg #define SFF8472_DDM_TX_BIAS 100
2584ce43bedSdlg #define SFF8472_DDM_TX_POWER 102
2594ce43bedSdlg #define SFF8472_DDM_RX_POWER 104
2604ce43bedSdlg #define SFF8472_DDM_LASER 106 /* laser temp/wavelength */
2614ce43bedSdlg /* optional */
2624ce43bedSdlg #define SFF8472_DDM_TEC 108 /* Measured TEC current */
263d2ae8f01Ssthen /* optional */
2644ce43bedSdlg
2654ce43bedSdlg #define SFF_TEMP_FACTOR 256.0
2664ce43bedSdlg #define SFF_VCC_FACTOR 10000.0
2674ce43bedSdlg #define SFF_BIAS_FACTOR 500.0
2684ce43bedSdlg #define SFF_POWER_FACTOR 10000.0
2694ce43bedSdlg
2704dc28db5Sdlg /*
271e2fee34bSdlg * QSFP is defined by SFF-8436, but the management interface is
272e2fee34bSdlg * updated and maintained by SFF-8636.
273e2fee34bSdlg */
274e2fee34bSdlg
275392b4b93Sdlg #define SFF8436_STATUS1 1
276392b4b93Sdlg #define SFF8436_STATUS2 2
277392b4b93Sdlg #define SFF8436_STATUS2_DNR (1 << 0) /* Data_Not_Ready */
278392b4b93Sdlg #define SFF8436_STATUS2_INTL (1 << 1) /* Interrupt output state */
279392b4b93Sdlg #define SFF8436_STATUS2_FLAT_MEM (1 << 2) /* Upper memory flat/paged */
280392b4b93Sdlg
281392b4b93Sdlg #define SFF8436_TEMP 22
282b46ace34Sdlg #define SFF8436_VCC 26
283b46ace34Sdlg
284b46ace34Sdlg #define SFF8436_CHANNELS 4 /* number of TX and RX channels */
285b46ace34Sdlg #define SFF8436_RX_POWER_BASE 34
286b46ace34Sdlg #define SFF8436_RX_POWER(_i) (SFF8436_RX_POWER_BASE + ((_i) * 2))
287b46ace34Sdlg #define SFF8436_TX_BIAS_BASE 42
288b46ace34Sdlg #define SFF8436_TX_BIAS(_i) (SFF8436_TX_BIAS_BASE + ((_i) * 2))
289b46ace34Sdlg #define SFF8436_TX_POWER_BASE 50
290b46ace34Sdlg #define SFF8436_TX_POWER(_i) (SFF8436_TX_POWER_BASE + ((_i) * 2))
291b46ace34Sdlg
292bf12d07dSdlg /* Upper Page 00h */
293bf12d07dSdlg
294bf12d07dSdlg #define SFF8436_MAXCASETEMP 190 /* C */
295bf12d07dSdlg #define SFF8436_MAXCASETEMP_DEFAULT 70 /* if SFF8436_MAXCASETEMP is 0 */
296bf12d07dSdlg
297bf12d07dSdlg /* Upper page 03h */
298bf12d07dSdlg
299b46ace34Sdlg #define SFF8436_AW_TEMP 128
300b46ace34Sdlg #define SFF8436_AW_VCC 144
301b46ace34Sdlg #define SFF8436_AW_RX_POWER 176
302b46ace34Sdlg #define SFF8436_AW_TX_BIAS 184
303b46ace34Sdlg #define SFF8436_AW_TX_POWER 192
304392b4b93Sdlg
305e2fee34bSdlg /*
3064dc28db5Sdlg * XFP stuff is defined by INF-8077.
3074dc28db5Sdlg *
3084dc28db5Sdlg * The "Serial ID Memory Map" on page 1 contains the interesting strings
3094dc28db5Sdlg */
3104dc28db5Sdlg
311e2fee34bSdlg /* SFF-8636 and INF-8077 share a layout for various strings */
312e2fee34bSdlg
3134662fdbeSdlg #define UPPER_CON 130 /* connector type */
3144662fdbeSdlg #define UPPER_DIST_SMF 142
3154662fdbeSdlg #define UPPER_DIST_OM3 143
3164662fdbeSdlg #define UPPER_DIST_OM2 144
3174662fdbeSdlg #define UPPER_DIST_OM1 145
3184662fdbeSdlg #define UPPER_DIST_CU 146
3194662fdbeSdlg #define UPPER_WAVELENGTH 186
3204662fdbeSdlg
321e2fee34bSdlg #define UPPER_VENDOR_START 148
322e2fee34bSdlg #define UPPER_VENDOR_END 163
323e2fee34bSdlg #define UPPER_PRODUCT_START 168
324e2fee34bSdlg #define UPPER_PRODUCT_END 183
325e2fee34bSdlg #define UPPER_REVISION_START 184
326e2fee34bSdlg #define UPPER_REVISION_END 185
327e2fee34bSdlg #define UPPER_SERIAL_START 196
328e2fee34bSdlg #define UPPER_SERIAL_END 211
329e2fee34bSdlg #define UPPER_DATECODE 212
330e2fee34bSdlg #define UPPER_LOT_START 218
331e2fee34bSdlg #define UPPER_LOT_END 219
3324dc28db5Sdlg
3334662fdbeSdlg static const struct sff_media_map upper_media_map = {
3344662fdbeSdlg .connector_type = UPPER_CON,
3354662fdbeSdlg .wavelength = UPPER_WAVELENGTH,
3364662fdbeSdlg .factor_wavelength = 20.0,
3374662fdbeSdlg .dist_smf_m = 0,
3384662fdbeSdlg .dist_smf_km = UPPER_DIST_SMF,
3394662fdbeSdlg .dist_om1 = UPPER_DIST_OM1,
3404662fdbeSdlg .scale_om1 = 1,
3414662fdbeSdlg .dist_om2 = UPPER_DIST_OM1,
3424662fdbeSdlg .scale_om2 = 1,
3434662fdbeSdlg .dist_om3 = UPPER_DIST_OM3,
3444662fdbeSdlg .scale_om3 = 2,
3454662fdbeSdlg .dist_cu = UPPER_DIST_CU,
3464662fdbeSdlg };
3474662fdbeSdlg
3484ce43bedSdlg static void hexdump(const void *, size_t);
349*4cfa599eSbluhm static int if_sff8472(int, const struct if_sffpage *);
350*4cfa599eSbluhm static int if_sff8636(int, const struct if_sffpage *);
351*4cfa599eSbluhm static int if_inf8077(int, const struct if_sffpage *);
3524ce43bedSdlg
3534ce43bedSdlg static const char *
sff_id_name(uint8_t id)3544ce43bedSdlg sff_id_name(uint8_t id)
3554ce43bedSdlg {
3564ce43bedSdlg const char *name = NULL;
3574ce43bedSdlg
3584ce43bedSdlg if (id < nitems(sff8024_id_names)) {
3594ce43bedSdlg name = sff8024_id_names[id];
3604ce43bedSdlg if (name != NULL)
3614ce43bedSdlg return (name);
3624ce43bedSdlg }
3634ce43bedSdlg
3644ce43bedSdlg if (SFF8024_ID_IS_VENDOR(id))
3654ce43bedSdlg return ("Vendor Specific");
3664ce43bedSdlg
3674ce43bedSdlg return ("Reserved");
3684ce43bedSdlg }
3694ce43bedSdlg
3704ce43bedSdlg static const char *
sff_con_name(uint8_t id)3714ce43bedSdlg sff_con_name(uint8_t id)
3724ce43bedSdlg {
3734ce43bedSdlg const char *name = NULL;
3744ce43bedSdlg
3754ce43bedSdlg if (id < nitems(sff8024_con_names)) {
3764ce43bedSdlg name = sff8024_con_names[id];
3774ce43bedSdlg if (name != NULL)
3784ce43bedSdlg return (name);
3794ce43bedSdlg }
3804ce43bedSdlg
3814ce43bedSdlg if (SFF8024_CON_IS_VENDOR(id))
3824ce43bedSdlg return ("Vendor Specific");
3834ce43bedSdlg
3844ce43bedSdlg return ("Reserved");
3854ce43bedSdlg }
3864ce43bedSdlg
3874ce43bedSdlg static void
if_sffpage_init(struct if_sffpage * sff,uint8_t addr,uint8_t page)388*4cfa599eSbluhm if_sffpage_init(struct if_sffpage *sff, uint8_t addr, uint8_t page)
3894ce43bedSdlg {
3904ce43bedSdlg memset(sff, 0, sizeof(*sff));
3914ce43bedSdlg
3924ce43bedSdlg if (strlcpy(sff->sff_ifname, ifname, sizeof(sff->sff_ifname)) >=
3934ce43bedSdlg sizeof(sff->sff_ifname))
3944ce43bedSdlg errx(1, "interface name too long");
3954ce43bedSdlg
3964ce43bedSdlg sff->sff_addr = addr;
3974ce43bedSdlg sff->sff_page = page;
3984ce43bedSdlg }
3994ce43bedSdlg
4004ce43bedSdlg static void
if_sffpage_dump(const struct if_sffpage * sff)401*4cfa599eSbluhm if_sffpage_dump(const struct if_sffpage *sff)
4024ce43bedSdlg {
4034ce43bedSdlg printf("%s: addr %02x", ifname, sff->sff_addr);
4044ce43bedSdlg if (sff->sff_addr == IFSFF_ADDR_EEPROM)
4054ce43bedSdlg printf(" page %u", sff->sff_page);
4064ce43bedSdlg putchar('\n');
4074ce43bedSdlg hexdump(sff->sff_data, sizeof(sff->sff_data));
4084ce43bedSdlg }
4094ce43bedSdlg
4104ce43bedSdlg int
if_sff_info(int dump)411*4cfa599eSbluhm if_sff_info(int dump)
4124ce43bedSdlg {
4134ce43bedSdlg struct if_sffpage pg0;
4144ce43bedSdlg int error = 0;
4154ce43bedSdlg uint8_t id, ext_id;
4164ce43bedSdlg
417*4cfa599eSbluhm if_sffpage_init(&pg0, IFSFF_ADDR_EEPROM, 0);
418d6a6566dSbluhm if (ioctl(sock, SIOCGIFSFFPAGE, (caddr_t)&pg0) == -1) {
4194dc28db5Sdlg if (errno == ENXIO) {
4204dc28db5Sdlg /* try 1 for XFP cos myx which can't switch pages... */
421*4cfa599eSbluhm if_sffpage_init(&pg0, IFSFF_ADDR_EEPROM, 1);
422d6a6566dSbluhm if (ioctl(sock, SIOCGIFSFFPAGE, (caddr_t)&pg0) == -1)
4234ce43bedSdlg return (-1);
4249262558cSdlg } else
4259262558cSdlg return (-1);
4264dc28db5Sdlg }
4274ce43bedSdlg
4284ce43bedSdlg if (dump)
429*4cfa599eSbluhm if_sffpage_dump(&pg0);
4304ce43bedSdlg
4314ce43bedSdlg id = pg0.sff_data[0]; /* SFF8472_ID */
4324ce43bedSdlg
4333561a859Ssthen printf("\ttransceiver: %s ", sff_id_name(id));
4344ce43bedSdlg switch (id) {
4354ce43bedSdlg case SFF8024_ID_SFP:
4364ce43bedSdlg ext_id = pg0.sff_data[SFF8472_EXT_ID];
4374ce43bedSdlg if (ext_id != SFF8472_EXT_ID_2WIRE) {
438d2ae8f01Ssthen printf("extended-id %02xh\n", ext_id);
4394ce43bedSdlg break;
4404ce43bedSdlg }
4414ce43bedSdlg /* FALLTHROUGH */
4424ce43bedSdlg case SFF8024_ID_GBIC:
443*4cfa599eSbluhm error = if_sff8472(dump, &pg0);
4444ce43bedSdlg break;
4454dc28db5Sdlg case SFF8024_ID_XFP:
4464dc28db5Sdlg if (pg0.sff_page != 1) {
447*4cfa599eSbluhm if_sffpage_init(&pg0, IFSFF_ADDR_EEPROM, 1);
448d6a6566dSbluhm if (ioctl(sock, SIOCGIFSFFPAGE, (caddr_t)&pg0) == -1)
4494dc28db5Sdlg return (-1);
4504dc28db5Sdlg if (dump)
451*4cfa599eSbluhm if_sffpage_dump(&pg0);
4524dc28db5Sdlg }
453*4cfa599eSbluhm error = if_inf8077(dump, &pg0);
4544dc28db5Sdlg break;
4555866b5bcSdlg case SFF8024_ID_QSFP:
456e2fee34bSdlg case SFF8024_ID_QSFP_PLUS:
4575866b5bcSdlg case SFF8024_ID_QSFP28:
458*4cfa599eSbluhm error = if_sff8636(dump, &pg0);
459e2fee34bSdlg break;
46043716df3Sdenis default:
46143716df3Sdenis printf("\n");
46243716df3Sdenis break;
4634ce43bedSdlg }
4644ce43bedSdlg
4654ce43bedSdlg return (error);
4664ce43bedSdlg }
4674ce43bedSdlg
4684ce43bedSdlg static void
if_sff_ascii_print(const struct if_sffpage * sff,const char * name,size_t start,size_t end,const char * trailer)469d2ae8f01Ssthen if_sff_ascii_print(const struct if_sffpage *sff, const char *name,
470d2ae8f01Ssthen size_t start, size_t end, const char *trailer)
4714ce43bedSdlg {
4724ce43bedSdlg const uint8_t *d = sff->sff_data;
4734ce43bedSdlg int ch;
4744ce43bedSdlg
4754ce43bedSdlg for (;;) {
4764ce43bedSdlg ch = d[start];
4774ce43bedSdlg if (!isspace(ch) && ch != '\0')
4784ce43bedSdlg break;
4794ce43bedSdlg
4804ce43bedSdlg start++;
481d2ae8f01Ssthen if (start == end)
4824ce43bedSdlg return;
4834ce43bedSdlg }
484d2ae8f01Ssthen
485d2ae8f01Ssthen printf("%s", name);
4864ce43bedSdlg
4874ce43bedSdlg for (;;) {
488d6a6566dSbluhm ch = d[end];
4894ce43bedSdlg if (!isspace(ch) && ch != '\0')
4904ce43bedSdlg break;
4914ce43bedSdlg
4924ce43bedSdlg end--;
4934ce43bedSdlg }
4944ce43bedSdlg
4954ce43bedSdlg do {
4964ce43bedSdlg char dst[8];
4974ce43bedSdlg vis(dst, d[start], VIS_TAB | VIS_NL, 0);
4984ce43bedSdlg printf("%s", dst);
4994ce43bedSdlg } while (++start <= end);
500d2ae8f01Ssthen
501d2ae8f01Ssthen printf("%s", trailer);
5024ce43bedSdlg }
5034ce43bedSdlg
5044ce43bedSdlg static void
if_sff_date_print(const struct if_sffpage * sff,const char * name,size_t start,const char * trailer)505d2ae8f01Ssthen if_sff_date_print(const struct if_sffpage *sff, const char *name,
506d2ae8f01Ssthen size_t start, const char *trailer)
5074ce43bedSdlg {
5084ce43bedSdlg const uint8_t *d = sff->sff_data + start;
5094ce43bedSdlg size_t i;
5104ce43bedSdlg
5114ce43bedSdlg /* YYMMDD */
5124ce43bedSdlg for (i = 0; i < 6; i++) {
5134ce43bedSdlg if (!isdigit(d[i])) {
514d2ae8f01Ssthen if_sff_ascii_print(sff, name, start,
515d2ae8f01Ssthen start + 5, trailer);
5164ce43bedSdlg return;
5174ce43bedSdlg }
5184ce43bedSdlg }
5194ce43bedSdlg
520d2ae8f01Ssthen printf("%s20%c%c-%c%c-%c%c%s", name,
521d2ae8f01Ssthen d[0], d[1], d[2], d[3], d[4], d[5], trailer);
5224ce43bedSdlg }
5234ce43bedSdlg
5244ce43bedSdlg static int16_t
if_sff_int(const struct if_sffpage * sff,size_t start)5254ce43bedSdlg if_sff_int(const struct if_sffpage *sff, size_t start)
5264ce43bedSdlg {
5274ce43bedSdlg const uint8_t *d = sff->sff_data + start;
5284ce43bedSdlg
5294ce43bedSdlg return (d[0] << 8 | d[1]);
5304ce43bedSdlg }
5314ce43bedSdlg
5324ce43bedSdlg static uint16_t
if_sff_uint(const struct if_sffpage * sff,size_t start)5334ce43bedSdlg if_sff_uint(const struct if_sffpage *sff, size_t start)
5344ce43bedSdlg {
5354ce43bedSdlg const uint8_t *d = sff->sff_data + start;
5364ce43bedSdlg
5374ce43bedSdlg return (d[0] << 8 | d[1]);
5384ce43bedSdlg }
5394ce43bedSdlg
5404ce43bedSdlg static float
if_sff_power2dbm(const struct if_sffpage * sff,size_t start)541d2ae8f01Ssthen if_sff_power2dbm(const struct if_sffpage *sff, size_t start)
5424ce43bedSdlg {
543d2ae8f01Ssthen const uint8_t *d = sff->sff_data + start;
544d2ae8f01Ssthen
545d2ae8f01Ssthen int power = d[0] << 8 | d[1];
5464ce43bedSdlg return (10.0 * log10f((float)power / 10000.0));
5474ce43bedSdlg }
5484ce43bedSdlg
549d2ae8f01Ssthen static void
if_sff_printalarm(const char * unit,int range,float actual,float alrm_high,float alrm_low,float warn_high,float warn_log)550d2ae8f01Ssthen if_sff_printalarm(const char *unit, int range, float actual,
551d2ae8f01Ssthen float alrm_high, float alrm_low, float warn_high, float warn_log)
552d2ae8f01Ssthen {
5533519233cSsthen printf("%.02f%s", actual, unit);
554d2ae8f01Ssthen if (range == 1)
5553561a859Ssthen printf(" (low %.02f%s, high %.02f%s)", alrm_low,
556d2ae8f01Ssthen unit, alrm_high, unit);
557d2ae8f01Ssthen
558d2ae8f01Ssthen if(actual > alrm_high || actual < alrm_low)
559d2ae8f01Ssthen printf(" [ALARM]");
560d2ae8f01Ssthen else if(actual > warn_high || actual < warn_log)
561d2ae8f01Ssthen printf(" [WARNING]");
562d2ae8f01Ssthen }
563d2ae8f01Ssthen
56423a4e4a1Ssthen static void
if_sff_printdist(const char * type,int value,int scale)56523a4e4a1Ssthen if_sff_printdist(const char *type, int value, int scale)
56623a4e4a1Ssthen {
56723a4e4a1Ssthen int distance = value * scale;
56823a4e4a1Ssthen
56923a4e4a1Ssthen if (value == 0)
57023a4e4a1Ssthen return;
57123a4e4a1Ssthen
57223a4e4a1Ssthen if (distance < 10000)
57323a4e4a1Ssthen printf (", %s%u%s", value > 254 ? ">" : "", distance, type);
57423a4e4a1Ssthen else
57523a4e4a1Ssthen printf (", %s%0.1fk%s", value > 254 ? ">" : "",
57623a4e4a1Ssthen distance / 1000.0, type);
57723a4e4a1Ssthen }
57823a4e4a1Ssthen
5794662fdbeSdlg static void
if_sff_printmedia(const struct if_sffpage * pg,const struct sff_media_map * m)5804662fdbeSdlg if_sff_printmedia(const struct if_sffpage *pg, const struct sff_media_map *m)
5814ce43bedSdlg {
582d6a6566dSbluhm uint8_t con;
5834662fdbeSdlg unsigned int wavelength;
5844ce43bedSdlg
5854662fdbeSdlg con = pg->sff_data[m->connector_type];
5863561a859Ssthen printf("%s", sff_con_name(con));
587d2ae8f01Ssthen
5884662fdbeSdlg wavelength = if_sff_uint(pg, m->wavelength);
5894662fdbeSdlg switch (wavelength) {
5904662fdbeSdlg case 0x0000:
5914662fdbeSdlg /* not known or is unavailable */
5924662fdbeSdlg break;
593d2ae8f01Ssthen /* Copper Cable */
594d2ae8f01Ssthen case 0x0100: /* SFF-8431 Appendix E */
595d2ae8f01Ssthen case 0x0400: /* SFF-8431 limiting */
596d2ae8f01Ssthen case 0x0c00: /* SFF-8431 limiting and FC-PI-4 limiting */
597d2ae8f01Ssthen break;
598d2ae8f01Ssthen default:
5994662fdbeSdlg printf(", %.f nm", wavelength / m->factor_wavelength);
6004ce43bedSdlg }
6014ce43bedSdlg
6024662fdbeSdlg if (m->dist_smf_m != 0 &&
603da9583c4Sdlg pg->sff_data[m->dist_smf_m] > 0 &&
6044662fdbeSdlg pg->sff_data[m->dist_smf_m] < 255)
6054662fdbeSdlg if_sff_printdist("m SMF", pg->sff_data[m->dist_smf_m], 100);
60623a4e4a1Ssthen else
6074662fdbeSdlg if_sff_printdist("km SMF", pg->sff_data[m->dist_smf_km], 1);
6084662fdbeSdlg if_sff_printdist("m OM1", pg->sff_data[m->dist_om1], m->scale_om1);
609f81e3884Sdlg if_sff_printdist("m OM2", pg->sff_data[m->dist_om2], m->scale_om2);
6104662fdbeSdlg if_sff_printdist("m OM3", pg->sff_data[m->dist_om3], m->scale_om3);
6114662fdbeSdlg if_sff_printdist("m", pg->sff_data[m->dist_cu], 1);
6124662fdbeSdlg }
6134662fdbeSdlg
6144662fdbeSdlg static int
if_sff8472(int dump,const struct if_sffpage * pg0)615*4cfa599eSbluhm if_sff8472(int dump, const struct if_sffpage *pg0)
6164662fdbeSdlg {
6174662fdbeSdlg struct if_sffpage ddm;
6184662fdbeSdlg uint8_t ddm_types;
6194662fdbeSdlg
6204662fdbeSdlg if_sff_printmedia(pg0, &sff8472_media_map);
62123a4e4a1Ssthen
6223561a859Ssthen printf("\n\tmodel: ");
6233561a859Ssthen if_sff_ascii_print(pg0, "",
6243561a859Ssthen SFF8472_VENDOR_START, SFF8472_VENDOR_END, " ");
6253561a859Ssthen if_sff_ascii_print(pg0, "",
6263561a859Ssthen SFF8472_PRODUCT_START, SFF8472_PRODUCT_END, "");
6273561a859Ssthen if_sff_ascii_print(pg0, " rev ",
6283561a859Ssthen SFF8472_REVISION_START, SFF8472_REVISION_END, "");
629d2ae8f01Ssthen
6303561a859Ssthen if_sff_ascii_print(pg0, "\n\tserial: ",
631d2ae8f01Ssthen SFF8472_SERIAL_START, SFF8472_SERIAL_END, ", ");
6323561a859Ssthen if_sff_date_print(pg0, "date: ", SFF8472_DATECODE, "\n");
6334ce43bedSdlg
6344ce43bedSdlg ddm_types = pg0->sff_data[SFF8472_DDM_TYPE];
6354ce43bedSdlg if (pg0->sff_data[SFF8472_COMPLIANCE] == SFF8472_COMPLIANCE_NONE ||
6364ce43bedSdlg !ISSET(ddm_types, SFF8472_DDM_TYPE_IMPL))
6374ce43bedSdlg return (0);
6384ce43bedSdlg
639*4cfa599eSbluhm if_sffpage_init(&ddm, IFSFF_ADDR_DDM, 0);
640d6a6566dSbluhm if (ioctl(sock, SIOCGIFSFFPAGE, (caddr_t)&ddm) == -1)
6414ce43bedSdlg return (-1);
6424ce43bedSdlg
6434ce43bedSdlg if (dump)
644*4cfa599eSbluhm if_sffpage_dump(&ddm);
6454ce43bedSdlg
6464ce43bedSdlg if (ISSET(ddm_types, SFF8472_DDM_TYPE_CAL_EXT)) {
6474ce43bedSdlg printf("\tcalibration: external "
6484ce43bedSdlg "(WARNING: needs more code)\n");
6494ce43bedSdlg }
6504ce43bedSdlg
6513561a859Ssthen printf("\tvoltage: ");
652d2ae8f01Ssthen if_sff_printalarm(" V", 0,
653d2ae8f01Ssthen if_sff_uint(&ddm, SFF8472_DDM_VCC) / SFF_VCC_FACTOR,
654d2ae8f01Ssthen if_sff_uint(&ddm, SFF8472_AW_VCC + ALRM_HIGH) / SFF_VCC_FACTOR,
655d2ae8f01Ssthen if_sff_uint(&ddm, SFF8472_AW_VCC + ALRM_LOW) / SFF_VCC_FACTOR,
656d2ae8f01Ssthen if_sff_uint(&ddm, SFF8472_AW_VCC + WARN_HIGH) / SFF_VCC_FACTOR,
657d2ae8f01Ssthen if_sff_uint(&ddm, SFF8472_AW_VCC + WARN_LOW) / SFF_VCC_FACTOR);
6584ce43bedSdlg
6593561a859Ssthen printf(", bias current: ");
660d2ae8f01Ssthen if_sff_printalarm(" mA", 0,
661d2ae8f01Ssthen if_sff_uint(&ddm, SFF8472_DDM_TX_BIAS) / SFF_BIAS_FACTOR,
662d2ae8f01Ssthen if_sff_uint(&ddm, SFF8472_AW_TX_BIAS + ALRM_HIGH) / SFF_BIAS_FACTOR,
663d2ae8f01Ssthen if_sff_uint(&ddm, SFF8472_AW_TX_BIAS + ALRM_LOW) / SFF_BIAS_FACTOR,
664d2ae8f01Ssthen if_sff_uint(&ddm, SFF8472_AW_TX_BIAS + WARN_HIGH) / SFF_BIAS_FACTOR,
665d2ae8f01Ssthen if_sff_uint(&ddm, SFF8472_AW_TX_BIAS + WARN_LOW) / SFF_BIAS_FACTOR);
666d2ae8f01Ssthen
6673561a859Ssthen printf("\n\ttemp: ");
668d2ae8f01Ssthen if_sff_printalarm(" C", 1,
669d2ae8f01Ssthen if_sff_int(&ddm, SFF8472_DDM_TEMP) / SFF_TEMP_FACTOR,
670d2ae8f01Ssthen if_sff_int(&ddm, SFF8472_AW_TEMP + ALRM_HIGH) / SFF_TEMP_FACTOR,
671d2ae8f01Ssthen if_sff_int(&ddm, SFF8472_AW_TEMP + ALRM_LOW) / SFF_TEMP_FACTOR,
672d2ae8f01Ssthen if_sff_int(&ddm, SFF8472_AW_TEMP + WARN_HIGH) / SFF_TEMP_FACTOR,
673d2ae8f01Ssthen if_sff_int(&ddm, SFF8472_AW_TEMP + WARN_LOW) / SFF_TEMP_FACTOR);
674d2ae8f01Ssthen
6753561a859Ssthen printf("\n\ttx: ");
676d2ae8f01Ssthen if_sff_printalarm(" dBm", 1,
677d2ae8f01Ssthen if_sff_power2dbm(&ddm, SFF8472_DDM_TX_POWER),
678d2ae8f01Ssthen if_sff_power2dbm(&ddm, SFF8472_AW_TX_POWER + ALRM_HIGH),
679d2ae8f01Ssthen if_sff_power2dbm(&ddm, SFF8472_AW_TX_POWER + ALRM_LOW),
680d2ae8f01Ssthen if_sff_power2dbm(&ddm, SFF8472_AW_TX_POWER + WARN_HIGH),
681d2ae8f01Ssthen if_sff_power2dbm(&ddm, SFF8472_AW_TX_POWER + WARN_LOW));
682d2ae8f01Ssthen
6833561a859Ssthen printf("\n\trx: ");
684d2ae8f01Ssthen if_sff_printalarm(" dBm", 1,
685d2ae8f01Ssthen if_sff_power2dbm(&ddm, SFF8472_DDM_RX_POWER),
686d2ae8f01Ssthen if_sff_power2dbm(&ddm, SFF8472_AW_RX_POWER + ALRM_HIGH),
687d2ae8f01Ssthen if_sff_power2dbm(&ddm, SFF8472_AW_RX_POWER + ALRM_LOW),
688d2ae8f01Ssthen if_sff_power2dbm(&ddm, SFF8472_AW_RX_POWER + WARN_HIGH),
689d2ae8f01Ssthen if_sff_power2dbm(&ddm, SFF8472_AW_RX_POWER + WARN_LOW));
690d2ae8f01Ssthen
691d2ae8f01Ssthen putchar('\n');
6924ce43bedSdlg return (0);
6934ce43bedSdlg }
6944ce43bedSdlg
695e2fee34bSdlg static void
if_upper_strings(const struct if_sffpage * pg)696e2fee34bSdlg if_upper_strings(const struct if_sffpage *pg)
697e2fee34bSdlg {
6984662fdbeSdlg if_sff_printmedia(pg, &upper_media_map);
6994662fdbeSdlg
700e2fee34bSdlg printf("\n\tmodel: ");
701e2fee34bSdlg if_sff_ascii_print(pg, "",
702e2fee34bSdlg UPPER_VENDOR_START, UPPER_VENDOR_END, " ");
703e2fee34bSdlg if_sff_ascii_print(pg, "",
704e2fee34bSdlg UPPER_PRODUCT_START, UPPER_PRODUCT_END, "");
705e2fee34bSdlg if_sff_ascii_print(pg, " rev ",
706e2fee34bSdlg UPPER_REVISION_START, UPPER_REVISION_END, "");
707e2fee34bSdlg
708e2fee34bSdlg if_sff_ascii_print(pg, "\n\tserial: ",
709e2fee34bSdlg UPPER_SERIAL_START, UPPER_SERIAL_END, " ");
710e2fee34bSdlg if_sff_date_print(pg, "date: ", UPPER_DATECODE, " ");
711e2fee34bSdlg if_sff_ascii_print(pg, "lot: ",
712e2fee34bSdlg UPPER_LOT_START, UPPER_LOT_END, "");
713e2fee34bSdlg
714e2fee34bSdlg putchar('\n');
715e2fee34bSdlg }
716e2fee34bSdlg
7174ce43bedSdlg static int
if_inf8077(int dump,const struct if_sffpage * pg1)718*4cfa599eSbluhm if_inf8077(int dump, const struct if_sffpage *pg1)
7194dc28db5Sdlg {
720e2fee34bSdlg if_upper_strings(pg1);
7214dc28db5Sdlg
722e2fee34bSdlg return (0);
723e2fee34bSdlg }
7244dc28db5Sdlg
725e2fee34bSdlg static int
if_sff8636_thresh(int dump,const struct if_sffpage * pg0)726*4cfa599eSbluhm if_sff8636_thresh(int dump, const struct if_sffpage *pg0)
727392b4b93Sdlg {
728392b4b93Sdlg struct if_sffpage pg3;
729b46ace34Sdlg unsigned int i;
730b46ace34Sdlg struct sff_thresholds temp, vcc, tx, rx, bias;
731392b4b93Sdlg
732*4cfa599eSbluhm if_sffpage_init(&pg3, IFSFF_ADDR_EEPROM, 3);
733d6a6566dSbluhm if (ioctl(sock, SIOCGIFSFFPAGE, (caddr_t)&pg3) == -1) {
734392b4b93Sdlg if (dump)
735392b4b93Sdlg warn("%s SIOCGIFSFFPAGE page 3", ifname);
736392b4b93Sdlg return (-1);
737392b4b93Sdlg }
738392b4b93Sdlg
739392b4b93Sdlg if (dump)
740*4cfa599eSbluhm if_sffpage_dump(&pg3);
741392b4b93Sdlg
742392b4b93Sdlg if (pg3.sff_data[0x7f] != 3) { /* just in case... */
743392b4b93Sdlg if (dump) {
744392b4b93Sdlg warnx("%s SIOCGIFSFFPAGE: page select unsupported",
745392b4b93Sdlg ifname);
746392b4b93Sdlg }
747392b4b93Sdlg return (-1);
748392b4b93Sdlg }
749392b4b93Sdlg
750b46ace34Sdlg for (i = 0; i < SFF_THRESH_COUNT; i++) {
751b46ace34Sdlg temp.thresholds[i] = if_sff_int(&pg3,
752b46ace34Sdlg SFF8436_AW_TEMP + SFF_THRESH_REG(i)) / SFF_TEMP_FACTOR;
753b46ace34Sdlg
754b46ace34Sdlg vcc.thresholds[i] = if_sff_uint(&pg3,
755b46ace34Sdlg SFF8436_AW_VCC + SFF_THRESH_REG(i)) / SFF_VCC_FACTOR;
756b46ace34Sdlg
757b46ace34Sdlg rx.thresholds[i] = if_sff_power2dbm(&pg3,
758b46ace34Sdlg SFF8436_AW_RX_POWER + SFF_THRESH_REG(i));
759b46ace34Sdlg
760b46ace34Sdlg bias.thresholds[i] = if_sff_uint(&pg3,
761b46ace34Sdlg SFF8436_AW_TX_BIAS + SFF_THRESH_REG(i)) / SFF_BIAS_FACTOR;
762b46ace34Sdlg
763b46ace34Sdlg tx.thresholds[i] = if_sff_power2dbm(&pg3,
764b46ace34Sdlg SFF8436_AW_TX_POWER + SFF_THRESH_REG(i));
765b46ace34Sdlg }
766b46ace34Sdlg
767b46ace34Sdlg printf("\ttemp: ");
768bf12d07dSdlg if_sff_printalarm(" C", 1,
769b46ace34Sdlg if_sff_int(&pg3, SFF8436_TEMP) / SFF_TEMP_FACTOR,
770b46ace34Sdlg temp.thresholds[SFF_THRESH_HI_ALARM],
771b46ace34Sdlg temp.thresholds[SFF_THRESH_LO_ALARM],
772b46ace34Sdlg temp.thresholds[SFF_THRESH_HI_WARN],
773b46ace34Sdlg temp.thresholds[SFF_THRESH_LO_WARN]);
774b46ace34Sdlg printf("\n");
775b46ace34Sdlg
776b46ace34Sdlg printf("\tvoltage: ");
777bf12d07dSdlg if_sff_printalarm(" V", 1,
778b46ace34Sdlg if_sff_uint(&pg3, SFF8436_VCC) / SFF_VCC_FACTOR,
779b46ace34Sdlg vcc.thresholds[SFF_THRESH_HI_ALARM],
780b46ace34Sdlg vcc.thresholds[SFF_THRESH_LO_ALARM],
781b46ace34Sdlg vcc.thresholds[SFF_THRESH_HI_WARN],
782b46ace34Sdlg vcc.thresholds[SFF_THRESH_LO_WARN]);
783b46ace34Sdlg printf("\n");
784b46ace34Sdlg
785b46ace34Sdlg for (i = 0; i < SFF8436_CHANNELS; i++) {
786b46ace34Sdlg unsigned int channel = i + 1;
787b46ace34Sdlg
788b46ace34Sdlg printf("\tchannel %u bias current: ", channel);
789b46ace34Sdlg if_sff_printalarm(" mA", 1,
790b46ace34Sdlg if_sff_uint(&pg3, SFF8436_TX_BIAS(i)) / SFF_BIAS_FACTOR,
791b46ace34Sdlg bias.thresholds[SFF_THRESH_HI_ALARM],
792b46ace34Sdlg bias.thresholds[SFF_THRESH_LO_ALARM],
793b46ace34Sdlg bias.thresholds[SFF_THRESH_HI_WARN],
794b46ace34Sdlg bias.thresholds[SFF_THRESH_LO_WARN]);
795b46ace34Sdlg printf("\n");
796b46ace34Sdlg
797b46ace34Sdlg printf("\tchannel %u tx: ", channel);
798b46ace34Sdlg if_sff_printalarm(" dBm", 1,
799b46ace34Sdlg if_sff_power2dbm(&pg3, SFF8436_TX_POWER(i)),
800b46ace34Sdlg tx.thresholds[SFF_THRESH_HI_ALARM],
801b46ace34Sdlg tx.thresholds[SFF_THRESH_LO_ALARM],
802b46ace34Sdlg tx.thresholds[SFF_THRESH_HI_WARN],
803b46ace34Sdlg tx.thresholds[SFF_THRESH_LO_WARN]);
804b46ace34Sdlg printf("\n");
805b46ace34Sdlg
806b46ace34Sdlg printf("\tchannel %u rx: ", channel);
807b46ace34Sdlg if_sff_printalarm(" dBm", 1,
808b46ace34Sdlg if_sff_power2dbm(&pg3, SFF8436_RX_POWER(i)),
809b46ace34Sdlg rx.thresholds[SFF_THRESH_HI_ALARM],
810b46ace34Sdlg rx.thresholds[SFF_THRESH_LO_ALARM],
811b46ace34Sdlg rx.thresholds[SFF_THRESH_HI_WARN],
812b46ace34Sdlg rx.thresholds[SFF_THRESH_LO_WARN]);
813b46ace34Sdlg printf("\n");
814b46ace34Sdlg }
815b46ace34Sdlg
816b46ace34Sdlg return (0);
817392b4b93Sdlg }
818392b4b93Sdlg
819392b4b93Sdlg static int
if_sff8636(int dump,const struct if_sffpage * pg0)820*4cfa599eSbluhm if_sff8636(int dump, const struct if_sffpage *pg0)
821e2fee34bSdlg {
822392b4b93Sdlg int16_t temp;
823bf12d07dSdlg uint8_t maxcasetemp;
824392b4b93Sdlg uint8_t flat;
825b46ace34Sdlg unsigned int i;
826392b4b93Sdlg
827e2fee34bSdlg if_upper_strings(pg0);
8284dc28db5Sdlg
829392b4b93Sdlg if (pg0->sff_data[SFF8436_STATUS2] & SFF8436_STATUS2_DNR) {
830392b4b93Sdlg printf("\tmonitor data not ready\n");
831392b4b93Sdlg return (0);
832392b4b93Sdlg }
833392b4b93Sdlg
834bf12d07dSdlg maxcasetemp = pg0->sff_data[SFF8436_MAXCASETEMP];
835bf12d07dSdlg if (maxcasetemp == 0x00)
836bf12d07dSdlg maxcasetemp = SFF8436_MAXCASETEMP_DEFAULT;
837bf12d07dSdlg printf("\tmax case temp: %u C\n", maxcasetemp);
838bf12d07dSdlg
839392b4b93Sdlg temp = if_sff_int(pg0, SFF8436_TEMP);
840392b4b93Sdlg /* the temp reading look unset, assume the rest will be unset too */
841392b4b93Sdlg if ((uint16_t)temp == 0 || (uint16_t)temp == 0xffffU) {
842392b4b93Sdlg if (!dump)
843392b4b93Sdlg return (0);
844392b4b93Sdlg }
845392b4b93Sdlg
846392b4b93Sdlg flat = pg0->sff_data[SFF8436_STATUS2] & SFF8436_STATUS2_FLAT_MEM;
847*4cfa599eSbluhm if (!flat && if_sff8636_thresh(dump, pg0) == 0) {
848b46ace34Sdlg if (!dump)
849392b4b93Sdlg return (0);
850b46ace34Sdlg }
851392b4b93Sdlg
852392b4b93Sdlg printf("\t");
853392b4b93Sdlg printf("temp: %.02f%s", temp / SFF_TEMP_FACTOR, " C");
854392b4b93Sdlg printf(", ");
855392b4b93Sdlg printf("voltage: %.02f%s",
856b46ace34Sdlg if_sff_uint(pg0, SFF8436_VCC) / SFF_VCC_FACTOR, " V");
857392b4b93Sdlg printf("\n");
858392b4b93Sdlg
859b46ace34Sdlg for (i = 0; i < SFF8436_CHANNELS; i++) {
860b46ace34Sdlg printf("\t");
861b46ace34Sdlg printf("channel %u: ", i + 1);
862b46ace34Sdlg printf("bias current: %.02f mA",
863b46ace34Sdlg if_sff_uint(pg0, SFF8436_TX_BIAS(i)) / SFF_BIAS_FACTOR);
864b46ace34Sdlg printf(", ");
865b46ace34Sdlg printf("rx: %.02f dBm",
866b46ace34Sdlg if_sff_power2dbm(pg0, SFF8436_RX_POWER(i)));
867b46ace34Sdlg printf(", ");
868b46ace34Sdlg printf("tx: %.02f dBm",
869b46ace34Sdlg if_sff_power2dbm(pg0, SFF8436_TX_POWER(i)));
870b46ace34Sdlg printf("\n");
871b46ace34Sdlg }
872b46ace34Sdlg
8734dc28db5Sdlg return (0);
8744dc28db5Sdlg }
8754dc28db5Sdlg
8764dc28db5Sdlg static int
printable(int ch)8774ce43bedSdlg printable(int ch)
8784ce43bedSdlg {
8794ce43bedSdlg if (ch == '\0')
8804ce43bedSdlg return ('_');
8814ce43bedSdlg if (!isprint(ch))
8824ce43bedSdlg return ('~');
8834ce43bedSdlg
8844ce43bedSdlg return (ch);
8854ce43bedSdlg }
8864ce43bedSdlg
8874ce43bedSdlg static void
hexdump(const void * d,size_t datalen)8884ce43bedSdlg hexdump(const void *d, size_t datalen)
8894ce43bedSdlg {
8904ce43bedSdlg const uint8_t *data = d;
8914ce43bedSdlg int i, j = 0;
8924ce43bedSdlg
8934ce43bedSdlg for (i = 0; i < datalen; i += j) {
8944ce43bedSdlg printf("% 4d: ", i);
8954ce43bedSdlg for (j = 0; j < 16 && i+j < datalen; j++)
8964ce43bedSdlg printf("%02x ", data[i + j]);
8974ce43bedSdlg while (j++ < 16)
8984ce43bedSdlg printf(" ");
8994ce43bedSdlg printf("|");
9004ce43bedSdlg for (j = 0; j < 16 && i+j < datalen; j++)
9014ce43bedSdlg putchar(printable(data[i + j]));
9024ce43bedSdlg printf("|\n");
9034ce43bedSdlg }
9044ce43bedSdlg }
9054ce43bedSdlg
9064ce43bedSdlg #endif /* SMALL */
907