diff options
author | Robert Mustacchi <rm@joyent.com> | 2017-05-26 20:35:05 +0000 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2017-06-29 23:32:23 +0000 |
commit | 5732ccacb1877bdbc9366061bb1a43a97c9fde39 (patch) | |
tree | 64945e5ab907aecab0a33bd100cb57f1a05f1d7f | |
parent | 5ad7f810d0a72624056299b85500cdd7a9e5a916 (diff) | |
download | illumos-joyent-5732ccacb1877bdbc9366061bb1a43a97c9fde39.tar.gz |
OS-6180 NIC Transceivers should show up in hc topo
OS-6181 Want library to parse SFP i2c information
Reviewed by: Ryan Zezeski <ryan.zeseski@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Approved by: Bryan Cantrill <bryan@joyent.com>
62 files changed, 6951 insertions, 184 deletions
diff --git a/exception_lists/copyright b/exception_lists/copyright index cd371d5701..34a3ddfa44 100644 --- a/exception_lists/copyright +++ b/exception_lists/copyright @@ -407,6 +407,7 @@ usr/src/lib/libsmbfs/smb/derparse.[ch] usr/src/lib/libsmbfs/smb/spnego.c usr/src/lib/libsmbfs/smb/spnegoparse.[ch] usr/src/test/util-tests/tests/dis/*/*.out +usr/src/test/util-tests/tests/libsff/*.out usr/src/test/zfs-tests/tests/functional/history/*Z usr/src/test/zfs-tests/tests/functional/history/*txt usr/src/tools/btxld/btx.h @@ -4947,6 +4947,7 @@ s usr/lib/amd64/libsecdb.so.1=../../../lib/amd64/libsecdb.so.1 s usr/lib/amd64/libsecdb.so=../../../lib/amd64/libsecdb.so.1 s usr/lib/amd64/libsendfile.so.1=../../../lib/amd64/libsendfile.so.1 s usr/lib/amd64/libsendfile.so=../../../lib/amd64/libsendfile.so.1 +f usr/lib/amd64/libsff.so.1 0755 root bin f usr/lib/amd64/libshare.so.1 0755 root bin s usr/lib/amd64/libshare.so=libshare.so.1 f usr/lib/amd64/libshell.so.1 0755 root bin @@ -5390,6 +5391,7 @@ f usr/lib/fm/topo/plugins/disk.so 0555 root bin f usr/lib/fm/topo/plugins/fac_prov_ipmi.so 0555 root bin f usr/lib/fm/topo/plugins/fac_prov_mptsas.so 0555 root bin f usr/lib/fm/topo/plugins/ipmi.so 0555 root bin +f usr/lib/fm/topo/plugins/nic.so 0555 root bin f usr/lib/fm/topo/plugins/ses.so 0555 root bin f usr/lib/fm/topo/plugins/xfp.so 0555 root bin d usr/lib/fs 0755 root sys @@ -6392,6 +6394,7 @@ s usr/lib/libsecdb.so.1=../../lib/libsecdb.so.1 s usr/lib/libsecdb.so=../../lib/libsecdb.so.1 s usr/lib/libsendfile.so.1=../../lib/libsendfile.so.1 s usr/lib/libsendfile.so=../../lib/libsendfile.so.1 +f usr/lib/libsff.so.1 0755 root bin f usr/lib/libshare.so.1 0755 root bin s usr/lib/libshare.so=libshare.so.1 f usr/lib/libshell.so.1 0755 root bin diff --git a/usr/src/cmd/dlutil/Makefile b/usr/src/cmd/dlutil/Makefile index 49b6933cc7..8644786603 100644 --- a/usr/src/cmd/dlutil/Makefile +++ b/usr/src/cmd/dlutil/Makefile @@ -20,7 +20,7 @@ include ../Makefile.cmd ROOTCMDDIR = $(ROOTLIB)/dl CFLAGS += $(CCVERBOSE) -dltraninfo := LDLIBS += -ldladm +dltraninfo := LDLIBS += -ldladm -lsff -lnvpair dlled := LDLIBS += -ldladm dlsend := LDLIBS += -ldlpi -lsocket -lmd dlrecv := LDLIBS += -ldlpi diff --git a/usr/src/cmd/dlutil/dltraninfo.c b/usr/src/cmd/dlutil/dltraninfo.c index 2e6f7ee2e1..af7f8c80c2 100644 --- a/usr/src/cmd/dlutil/dltraninfo.c +++ b/usr/src/cmd/dlutil/dltraninfo.c @@ -35,81 +35,18 @@ #include <sys/dld.h> #include <sys/dld_ioc.h> #include <sys/dls_mgmt.h> +#include <libsff.h> #define DLTRAN_KIND_LEN 64 static dladm_handle_t dltran_hdl; static char dltran_dlerrmsg[DLADM_STRSIZE]; -static char **dltran_links; -static int dltran_nlinks; /* array size */ -static int dltran_clinks; /* current count */ -static boolean_t dltran_tranid_set; -static int dltran_tranid; static const char *dltran_progname; - -/* ARGSUSED */ -static int -dltran_dump_transceivers(dladm_handle_t hdl, datalink_id_t linkid, void *arg) -{ - dladm_status_t status; - char name[MAXLINKNAMELEN]; - dld_ioc_gettran_t gt; - uint_t count, i; - - if ((status = dladm_datalink_id2info(hdl, linkid, NULL, NULL, NULL, - name, sizeof (name))) != DLADM_STATUS_OK) { - (void) fprintf(stderr, "failed to get datalink name for link " - "%d: %s", linkid, dladm_status2str(status, - dltran_dlerrmsg)); - return (DLADM_WALK_CONTINUE); - } - - if (dltran_nlinks != NULL) { - for (i = 0; i < dltran_clinks; i++) { - if (strcmp(dltran_links[i], name) == 0) - break; - } - if (i == dltran_clinks) - return (DLADM_WALK_CONTINUE); - } - - bzero(>, sizeof (gt)); - gt.dgt_linkid = linkid; - gt.dgt_tran_id = DLDIOC_GETTRAN_GETNTRAN; - - if (ioctl(dladm_dld_fd(hdl), DLDIOC_GETTRAN, >) != 0) { - (void) fprintf(stderr, "failed to get transceiver count " - "for device %s: %s\n", - name, strerror(errno)); - return (DLADM_WALK_CONTINUE); - } - - - count = gt.dgt_tran_id; - (void) printf("%s: discovered %d transceivers\n", name, count); - for (i = 0; i < count; i++) { - if (dltran_tranid_set && i != dltran_tranid) - continue; - bzero(>, sizeof (gt)); - gt.dgt_linkid = linkid; - gt.dgt_tran_id = i; - - if (ioctl(dladm_dld_fd(hdl), DLDIOC_GETTRAN, >) != 0) { - (void) fprintf(stderr, "failed to get tran info for " - "%s: %s\n", name, strerror(errno)); - return (DLADM_WALK_CONTINUE); - } - - (void) printf("\ttransceiver %d present: %s\n", i, - gt.dgt_present ? "yes" : "no"); - if (!gt.dgt_present) - continue; - (void) printf("\ttransceiver %d usable: %s\n", i, - gt.dgt_usable ? "yes" : "no"); - } - - return (DLADM_WALK_CONTINUE); -} +static boolean_t dltran_verbose; +static boolean_t dltran_hex; +static boolean_t dltran_write; +static int dltran_outfd; +static int dltran_errors; /* * This routine basically assumes that we'll have 16 byte aligned output to @@ -161,23 +98,19 @@ dltran_dump_page(uint8_t *buf, size_t nbytes, uint_t page) } } -/* - * We always read 256 bytes even though only the first 128 bytes are sometimes - * significant on a given page and others are reserved. - */ static int dltran_read_page(datalink_id_t link, uint_t tranid, uint_t page, uint8_t *bufp, - size_t buflen) + size_t *buflen) { dld_ioc_tranio_t dti; - bzero(bufp, buflen); + bzero(bufp, *buflen); bzero(&dti, sizeof (dti)); dti.dti_linkid = link; dti.dti_tran_id = tranid; dti.dti_page = page; - dti.dti_nbytes = buflen; + dti.dti_nbytes = *buflen; dti.dti_off = 0; dti.dti_buf = (uintptr_t)(void *)bufp; @@ -187,8 +120,7 @@ dltran_read_page(datalink_id_t link, uint_t tranid, uint_t page, uint8_t *bufp, return (1); } - dltran_dump_page(bufp, dti.dti_nbytes, page); - + *buflen = dti.dti_nbytes; return (0); } @@ -217,45 +149,182 @@ dltran_is_8472(uint8_t *buf) return (B_TRUE); } +static void +dltran_hex_dump(datalink_id_t linkid, uint_t tranid) +{ + uint8_t buf[256]; + size_t buflen = sizeof (buf); + + if (dltran_read_page(linkid, tranid, 0xa0, buf, &buflen) != 0) { + dltran_errors++; + return; + } + + dltran_dump_page(buf, buflen, 0xa0); + + if (!dltran_is_8472(buf)) { + return; + } + + buflen = sizeof (buf); + if (dltran_read_page(linkid, tranid, 0xa2, buf, &buflen) != 0) { + dltran_errors++; + return; + } + + dltran_dump_page(buf, buflen, 0xa2); +} + +static void +dltran_write_page(datalink_id_t linkid, uint_t tranid) +{ + uint8_t buf[256]; + size_t buflen = sizeof (buf); + off_t off; + + if (dltran_read_page(linkid, tranid, 0xa0, buf, &buflen) != 0) { + dltran_errors++; + return; + } + + off = 0; + while (buflen > 0) { + ssize_t ret; + + ret = write(dltran_outfd, buf + off, buflen); + if (ret == -1) { + (void) fprintf(stderr, "failed to write data " + "to output file: %s\n", strerror(errno)); + dltran_errors++; + return; + } + + off += ret; + buflen -= ret; + } +} + +static void +dltran_verbose_dump(datalink_id_t linkid, uint_t tranid) +{ + uint8_t buf[256]; + size_t buflen = sizeof (buf); + int ret; + nvlist_t *nvl; + + if (dltran_read_page(linkid, tranid, 0xa0, buf, &buflen) != 0) { + dltran_errors++; + return; + } + + ret = libsff_parse(buf, buflen, 0xa0, &nvl); + if (ret == 0) { + dump_nvlist(nvl, 8); + nvlist_free(nvl); + } else { + fprintf(stderr, "failed to parse sfp data: %s\n", + strerror(ret)); + dltran_errors++; + } +} + static int -dltran_read_link(const char *link) +dltran_dump_transceivers(dladm_handle_t hdl, datalink_id_t linkid, void *arg) { dladm_status_t status; - datalink_id_t linkid; + char name[MAXLINKNAMELEN]; dld_ioc_gettran_t gt; - uint8_t buf[256]; - int ret; + uint_t count, i, tranid = UINT_MAX; + boolean_t tran_found = B_FALSE; + uint_t *tranidp = arg; - if ((status = dladm_name2info(dltran_hdl, link, &linkid, NULL, NULL, - NULL)) != DLADM_STATUS_OK) { - (void) fprintf(stderr, "failed to get link id for link " - "%s: %s\n", link, - dladm_status2str(status, dltran_dlerrmsg)); - return (1); + if (tranidp != NULL) + tranid = *tranidp; + + if ((status = dladm_datalink_id2info(hdl, linkid, NULL, NULL, NULL, + name, sizeof (name))) != DLADM_STATUS_OK) { + (void) fprintf(stderr, "failed to get datalink name for link " + "%d: %s", linkid, dladm_status2str(status, + dltran_dlerrmsg)); + dltran_errors++; + return (DLADM_WALK_CONTINUE); } + bzero(>, sizeof (gt)); gt.dgt_linkid = linkid; - gt.dgt_tran_id = dltran_tranid; + gt.dgt_tran_id = DLDIOC_GETTRAN_GETNTRAN; - if (ioctl(dladm_dld_fd(dltran_hdl), DLDIOC_GETTRAN, >) != 0) { - (void) fprintf(stderr, "failed to get transceiver information " - "for %s: %s\n", link, strerror(errno)); - return (1); + if (ioctl(dladm_dld_fd(hdl), DLDIOC_GETTRAN, >) != 0) { + if (errno != ENOTSUP) { + (void) fprintf(stderr, "failed to get transceiver " + "count for device %s: %s\n", + name, strerror(errno)); + dltran_errors++; + } + return (DLADM_WALK_CONTINUE); } - if ((ret = dltran_read_page(linkid, dltran_tranid, 0xa0, buf, - sizeof (buf))) != 0) { - return (ret); + count = gt.dgt_tran_id; + (void) printf("%s: discovered %d transceiver%s\n", name, count, + count > 1 ? "s" : ""); + for (i = 0; i < count; i++) { + if (tranid != UINT_MAX && i != tranid) + continue; + if (tranid != UINT_MAX) + tran_found = B_TRUE; + bzero(>, sizeof (gt)); + gt.dgt_linkid = linkid; + gt.dgt_tran_id = i; + + if (ioctl(dladm_dld_fd(hdl), DLDIOC_GETTRAN, >) != 0) { + (void) fprintf(stderr, "failed to get tran info for " + "%s: %s\n", name, strerror(errno)); + dltran_errors++; + return (DLADM_WALK_CONTINUE); + } + + if (dltran_hex && !gt.dgt_present) + continue; + if (!dltran_hex && !dltran_write) { + (void) printf("\ttransceiver %d present: %s\n", i, + gt.dgt_present ? "yes" : "no"); + if (!gt.dgt_present) + continue; + (void) printf("\ttransceiver %d usable: %s\n", i, + gt.dgt_usable ? "yes" : "no"); + } + + if (dltran_verbose) { + dltran_verbose_dump(linkid, i); + } + + if (dltran_write) { + if (!gt.dgt_present) { + (void) fprintf(stderr, "warning: no " + "transceiver present in port %d, not " + "writing\n", i); + dltran_errors++; + continue; + } + dltran_write_page(linkid, i); + } + + if (dltran_hex) { + printf("transceiver %d data:\n", i); + dltran_hex_dump(linkid, i); + } } - if (!dltran_is_8472(buf)) { - return (0); + if (tranid != UINT_MAX && !tran_found) { + dltran_errors++; + (void) fprintf(stderr, "failed to find transceiver %d on " + "link %s\n", tranid, name); } - return (dltran_read_page(linkid, dltran_tranid, 0xa2, buf, - sizeof (buf))); + return (DLADM_WALK_CONTINUE); } + static void dltran_usage(const char *fmt, ...) { @@ -268,11 +337,11 @@ dltran_usage(const char *fmt, ...) va_end(ap); } - (void) fprintf(stderr, "Usage: %s [-i id] [-l link]... [-r]\n" + (void) fprintf(stderr, "Usage: %s [-x | -v | -w file] [tran]...\n" "\n" - "\t-i id specify a transceiver id to operate on\n" - "\t-l link specify a data link to operate on\n" - "\t-r read transceiver page\n", + "\t-v display all transceiver information\n" + "\t-w write transceiver data page 0xa0 to file\n" + "\t-x dump raw hexadecimal for transceiver\n", dltran_progname); } @@ -280,46 +349,23 @@ int main(int argc, char *argv[]) { int c; - char *eptr; - long l; dladm_status_t status; - boolean_t do_read = B_FALSE; + const char *outfile = NULL; + uint_t count = 0; dltran_progname = basename(argv[0]); - while ((c = getopt(argc, argv, ":hi:l:r")) != -1) { + while ((c = getopt(argc, argv, ":xvw:")) != -1) { switch (c) { - case 'i': - errno = 0; - l = strtol(optarg, &eptr, 10); - if (errno != 0 || *eptr != '\0' || l < 0 || - l > INT_MAX) { - (void) fprintf(stderr, "invalid value for -i: " - "%s\n", optarg); - return (2); - } - dltran_tranid = (int)l; - dltran_tranid_set = B_TRUE; + case 'v': + dltran_verbose = B_TRUE; break; - case 'l': - if (dltran_nlinks == dltran_clinks) { - char **p; - dltran_nlinks += 8; - - p = realloc(dltran_links, - sizeof (char **) * dltran_nlinks); - if (p == NULL) { - (void) fprintf(stderr, "failed to " - "allocate space for %d links: %s\n", - dltran_nlinks, strerror(errno)); - return (1); - } - dltran_links = p; - } - dltran_links[dltran_clinks++] = optarg; + case 'x': + dltran_hex = B_TRUE; break; - case 'r': - do_read = B_TRUE; + case 'w': + dltran_write = B_TRUE; + outfile = optarg; break; case ':': dltran_usage("option -%c requires an " @@ -332,25 +378,81 @@ main(int argc, char *argv[]) } } - if (do_read && dltran_clinks != 1) { - (void) fprintf(stderr, "-r requires exactly one link " - "specified with -l\n"); + argc -= optind; + argv += optind; + + if (dltran_verbose) + count++; + if (dltran_hex) + count++; + if (dltran_write) + count++; + if (count > 1) { + (void) fprintf(stderr, "only one of -v, -w, and -x may be " + "specified\n"); return (2); } + if (dltran_write) { + if ((dltran_outfd = open(outfile, O_RDWR | O_TRUNC | O_CREAT, + 0644)) < 0) { + (void) fprintf(stderr, "failed to open output file " + "%s: %s\n", outfile, strerror(errno)); + return (1); + } + } + if ((status = dladm_open(&dltran_hdl)) != DLADM_STATUS_OK) { (void) fprintf(stderr, "failed to open /dev/dld: %s\n", dladm_status2str(status, dltran_dlerrmsg)); return (1); } - if (do_read) { - return (dltran_read_link(dltran_links[0])); - } + if (argc == 0) { + (void) dladm_walk_datalink_id(dltran_dump_transceivers, + dltran_hdl, NULL, DATALINK_CLASS_PHYS, + DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); + } else { + int i; + char *c; + + for (i = 0; i < argc; i++) { + uint_t tran; + uint_t *tranidp = NULL; + datalink_id_t linkid; + + if ((c = strrchr(argv[i], '/')) != NULL) { + unsigned long u; + char *eptr; + + c++; + errno = 0; + u = strtoul(c, &eptr, 10); + if (errno != 0 || *eptr != '\0' || + u >= UINT_MAX) { + (void) fprintf(stderr, "failed to " + "parse link/transceiver: %s\n", + argv[i]); + return (1); + } + c--; + *c = '\0'; + tran = (uint_t)u; + tranidp = &tran; + } - (void) dladm_walk_datalink_id(dltran_dump_transceivers, dltran_hdl, - NULL, DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, - DLADM_OPT_ACTIVE); + if ((status = dladm_name2info(dltran_hdl, argv[i], + &linkid, NULL, NULL, NULL)) != DLADM_STATUS_OK) { + (void) fprintf(stderr, "failed to get link " + "id for link %s: %s\n", argv[i], + dladm_status2str(status, dltran_dlerrmsg)); + return (1); + } - return (0); + (void) dltran_dump_transceivers(dltran_hdl, linkid, + tranidp); + } + } + + return (dltran_errors != 0 ? 1 : 0); } diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index 8bf8ca4c31..0f6aa5a0bf 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -203,6 +203,7 @@ SUBDIRS += \ libsec \ libsecdb \ libsendfile \ + libsff \ libshare \ libshell \ libsip \ @@ -459,6 +460,7 @@ HDRSUBDIRS= \ libsasl \ libscf \ libsec \ + libsff \ libshare \ libshell \ libsip \ @@ -586,7 +588,7 @@ auditd_plugins: libbsm libsecdb libgss libmtmalloc brand: libzonecfg libmapmalloc libipadm libcmdutils libproc librpcsvc cfgadm_plugins: libdevice libdevinfo libhotplug librcm hbaapi libkstat libscf fm: libexacct libipmi libzfs scsi libdevinfo libdevid libcfgadm \ - libcontract libsysevent ../cmd/sgs/libelf + libcontract libsysevent ../cmd/sgs/libelf libdladm $(SPARC_BLD)fm: libpri gss_mechs/mech_dh: libgss gss_mechs/mech_dummy: libgss @@ -662,6 +664,7 @@ libsasl: libgss pkcs11 libsaveargs: libdisasm libscf: libuutil libgen libsmbios libsec: libavl libidmap +libsff: libnvpair libshare: libscf libzfs libuuid libfsmgt libsecdb libumem libsmbfs libshell: libast libcmd libdll libsecdb libsip: libmd5 diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.c b/usr/src/lib/fm/topo/libtopo/common/hc.c index 59b9866285..df718d6490 100644 --- a/usr/src/lib/fm/topo/libtopo/common/hc.c +++ b/usr/src/lib/fm/topo/libtopo/common/hc.c @@ -22,6 +22,7 @@ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Joyent, Inc. */ #include <stdio.h> @@ -179,6 +180,7 @@ static const hcc_t hc_canon[] = { { PCIEX_ROOT, TOPO_STABILITY_PRIVATE }, { PCIEX_SWUP, TOPO_STABILITY_PRIVATE }, { PCIEX_SWDWN, TOPO_STABILITY_PRIVATE }, + { PORT, TOPO_STABILITY_PRIVATE }, { POWERBOARD, TOPO_STABILITY_PRIVATE }, { POWERMODULE, TOPO_STABILITY_PRIVATE }, { PSU, TOPO_STABILITY_PRIVATE }, @@ -194,6 +196,7 @@ static const hcc_t hc_canon[] = { { STRAND, TOPO_STABILITY_PRIVATE }, { SUBCHASSIS, TOPO_STABILITY_PRIVATE }, { SYSTEMBOARD, TOPO_STABILITY_PRIVATE }, + { TRANSCEIVER, TOPO_STABILITY_PRIVATE }, { XAUI, TOPO_STABILITY_PRIVATE }, { XFP, TOPO_STABILITY_PRIVATE } }; @@ -799,7 +802,7 @@ make_hc_pairs(topo_mod_t *mod, char *fmri, int *num) int make_hc_auth(topo_mod_t *mod, char *fmri, char **serial, char **part, -char **rev, nvlist_t **auth) + char **rev, nvlist_t **auth) { char *starti, *startn, *endi, *copy; char *aname = NULL, *aid = NULL, *fs; diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h index 7b29adad69..9de7a86736 100644 --- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h +++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h @@ -21,7 +21,7 @@ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2017, Joyent, Inc. */ #ifndef _TOPO_HC_H @@ -76,6 +76,7 @@ extern "C" { #define PCIEX_ROOT "pciexrc" #define PCIEX_SWUP "pciexswu" #define PCIEX_SWDWN "pciexswd" +#define PORT "port" #define POWERBOARD "powerboard" #define POWERMODULE "powermodule" #define PSU "psu" @@ -90,6 +91,7 @@ extern "C" { #define SP "sp" #define SUBCHASSIS "subchassis" #define SYSTEMBOARD "systemboard" +#define TRANSCEIVER "transceiver" #define XAUI "xaui" #define XFP "xfp" @@ -161,6 +163,20 @@ extern "C" { #define TOPO_PROP_SAS_PHY_MASK "phy-mask" #define TOPO_PROP_SAS_CONNECTOR_TYPE "sas-connector-type" +#define TOPO_PGROUP_PORT "port" +#define TOPO_PROP_PORT_TYPE "type" +#define TOPO_PROP_PORT_TYPE_SFF "sff" + +#define TOPO_PGROUP_TRANSCEIVER "transceiver" +#define TOPO_PROP_TRANSCEIVER_TYPE "type" +#define TOPO_PROP_TRANSCEIVER_USABLE "usable" + +#define TOPO_PGROUP_SFF_TRANSCEIVER "sff-transceiver" +#define TOPO_PORT_SFF_TRANSCEIVER_VENDOR "vendor" +#define TOPO_PORT_SFF_TRANSCEIVER_PN "part-number" +#define TOPO_PORT_SFF_TRANSCEIVER_REV "revision" +#define TOPO_PORT_SFF_TRANSCEIVER_SN "serial-number" + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/fm/topo/modules/Makefile.plugin b/usr/src/lib/fm/topo/modules/Makefile.plugin index 7eef744f46..13d90b8a27 100644 --- a/usr/src/lib/fm/topo/modules/Makefile.plugin +++ b/usr/src/lib/fm/topo/modules/Makefile.plugin @@ -56,7 +56,7 @@ plat_ROOTCONF = $(PLATFORMS:%=$(ROOT)/usr/platform/%/lib/fm/topo/plugins/$(CONF) ROOTCONF = $($(CLASS)_ROOTCONF) LINTFLAGS = -msux -LINTFILES = $(SRCS:%.c=%.ln) +LINTFILES = $(MODULESRCS:%.c=%.ln) $(SHAREDSRCS:%.c=%.ln) CERRWARN += -_gcc=-Wno-uninitialized CERRWARN += -_gcc=-Wno-parentheses @@ -105,6 +105,9 @@ clobber: clean %.ln: ../../common/$(MODULE)/%.c $(LINT.c) -c $< +%.ln: ../../common/$(SHAREDMODULE)/%.c + $(LINT.c) -c $< + %.ln: %.c $(LINT.c) -c $< diff --git a/usr/src/lib/fm/topo/modules/common/Makefile b/usr/src/lib/fm/topo/modules/common/Makefile index fa38496755..d725016aef 100644 --- a/usr/src/lib/fm/topo/modules/common/Makefile +++ b/usr/src/lib/fm/topo/modules/common/Makefile @@ -22,6 +22,7 @@ # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. +# Copyright (c) 2017, Joyent, Inc. # SUBDIRS = \ @@ -29,6 +30,7 @@ SUBDIRS = \ fac_prov_ipmi \ fac_prov_mptsas \ ipmi \ + nic \ ses \ xfp diff --git a/usr/src/lib/fm/topo/modules/common/nic/Makefile b/usr/src/lib/fm/topo/modules/common/nic/Makefile new file mode 100644 index 0000000000..084b49dcd1 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/nic/Makefile @@ -0,0 +1,26 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2017, Joyent, Inc. +# + +MODULE = nic +CLASS = common +SHAREDMODULE = shared + +MODULESRCS = topo_nic.c +SHAREDSRCS = topo_port.c topo_transceiver.c + +include ../../Makefile.plugin + +CPPFLAGS += -I../shared +LDLIBS += -ldevinfo -ldladm -lsff diff --git a/usr/src/lib/fm/topo/modules/common/nic/topo_nic.c b/usr/src/lib/fm/topo/modules/common/nic/topo_nic.c new file mode 100644 index 0000000000..51c37142c5 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/nic/topo_nic.c @@ -0,0 +1,241 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * This module covers enumerating properties of physical NICs. At this time, as + * various devices are discovered that may relate to various networking gear, we + * will attempt to enumerate ports and transceivers under them, if requested. + */ + +#include <strings.h> +#include <libdevinfo.h> +#include <libdladm.h> +#include <libdllink.h> +#include <libsff.h> +#include <unistd.h> +#include <sys/dld_ioc.h> +#include <sys/dld.h> + +#include <sys/fm/protocol.h> +#include <fm/topo_mod.h> +#include <fm/topo_list.h> +#include <fm/topo_method.h> + +#include <topo_port.h> +#include <topo_transceiver.h> + +#include "topo_nic.h" + +/* + * Create an instance of a transceiver with the specified id. We must create + * both its port and the transceiver node. + */ +static int +nic_create_transceiver(topo_mod_t *mod, tnode_t *pnode, dladm_handle_t handle, + datalink_id_t linkid, uint_t tranid) +{ + int ret; + tnode_t *port; + dld_ioc_gettran_t dgt; + dld_ioc_tranio_t dti; + uint8_t buf[256]; + char ouibuf[16]; + char *vendor = NULL, *part = NULL, *rev = NULL, *serial = NULL; + nvlist_t *nvl = NULL; + + if ((ret = port_create_sff(mod, pnode, tranid, &port)) != 0) + return (ret); + + bzero(&dgt, sizeof (dgt)); + dgt.dgt_linkid = linkid; + dgt.dgt_tran_id = tranid; + + if (ioctl(dladm_dld_fd(handle), DLDIOC_GETTRAN, &dgt) != 0) { + if (errno == ENOTSUP) + return (0); + return (-1); + } + + if (dgt.dgt_present == 0) + return (0); + + bzero(&dti, sizeof (dti)); + dti.dti_linkid = linkid; + dti.dti_tran_id = tranid; + dti.dti_page = 0xa0; + dti.dti_nbytes = sizeof (buf); + dti.dti_buf = (uintptr_t)buf; + + if (ioctl(dladm_dld_fd(handle), DLDIOC_READTRAN, &dti) == 0) { + uchar_t *oui; + uint_t nbyte; + + if (libsff_parse(buf, dti.dti_nbytes, dti.dti_page, + &nvl) == 0) { + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_VENDOR, + &vendor)) != 0 && nvlist_lookup_byte_array(nvl, + LIBSFF_KEY_OUI, &oui, &nbyte) == 0 && nbyte == 3) { + if (snprintf(ouibuf, sizeof (ouibuf), + "%02x:%02x:%02x", oui[0], oui[1], oui[2]) < + sizeof (ouibuf)) { + vendor = ouibuf; + } + } else if (ret != 0) { + vendor = NULL; + } + + if (nvlist_lookup_string(nvl, LIBSFF_KEY_PART, + &part) != 0) { + part = NULL; + } + + if (nvlist_lookup_string(nvl, LIBSFF_KEY_REVISION, + &rev) != 0) { + rev = NULL; + } + + if (nvlist_lookup_string(nvl, LIBSFF_KEY_SERIAL, + &serial) != 0) { + serial = NULL; + } + } + } + + if (transceiver_range_create(mod, port, 0, 0) != 0) { + nvlist_free(nvl); + return (-1); + } + + if (transceiver_create_sff(mod, port, 0, dgt.dgt_usable, vendor, part, + rev, serial, NULL) != 0) { + nvlist_free(nvl); + return (-1); + } + + nvlist_free(nvl); + return (0); +} + +/* ARGSUSED */ +static int +nic_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, + topo_instance_t min, topo_instance_t max, void *modarg, void *data) +{ + di_node_t din = data; + datalink_id_t linkid; + dladm_handle_t handle; + dld_ioc_gettran_t dgt; + uint_t ntrans, i; + char dname[MAXNAMELEN]; + + if (strcmp(name, NIC) != 0) { + topo_mod_dprintf(mod, "nic_enum: asked to enumerate unknown " + "component: %s\n", name); + return (-1); + } + + if (din == NULL) { + topo_mod_dprintf(mod, "nic_enum: missing data argument\n"); + return (-1); + } + + if ((handle = topo_mod_getspecific(mod)) == NULL) { + topo_mod_dprintf(mod, "nic_enum: failed to get nic module " + "specific data\n"); + return (-1); + } + + if (snprintf(dname, sizeof (dname), "%s%d", di_driver_name(din), + di_instance(din)) >= sizeof (dname)) { + topo_mod_dprintf(mod, "nic_enum: device name overflowed " + "internal buffer\n"); + return (-1); + } + + if (dladm_dev2linkid(handle, dname, &linkid) != DLADM_STATUS_OK) + return (-1); + + bzero(&dgt, sizeof (dgt)); + dgt.dgt_linkid = linkid; + dgt.dgt_tran_id = DLDIOC_GETTRAN_GETNTRAN; + + if (ioctl(dladm_dld_fd(handle), DLDIOC_GETTRAN, &dgt) != 0) { + if (errno == ENOTSUP) + return (0); + return (-1); + } + + ntrans = dgt.dgt_tran_id; + if (ntrans == 0) + return (0); + + if (port_range_create(mod, pnode, 0, ntrans - 1) != 0) + return (-1); + + for (i = 0; i < ntrans; i++) { + if (nic_create_transceiver(mod, pnode, handle, linkid, i) != 0) + return (-1); + } + + return (0); +} + +static const topo_modops_t nic_ops = { + nic_enum, NULL +}; + +static topo_modinfo_t nic_mod = { + NIC, FM_FMRI_SCHEME_HC, NIC_VERSION, &nic_ops +}; + +int +_topo_init(topo_mod_t *mod, topo_version_t version) +{ + dladm_handle_t handle; + + if (getenv("TOPONICDEBUG") != NULL) + topo_mod_setdebug(mod); + + topo_mod_dprintf(mod, "_mod_init: " + "initializing %s enumerator\n", NIC); + + if (version != NIC_VERSION) { + return (-1); + } + + if (dladm_open(&handle) != 0) + return (-1); + + if (topo_mod_register(mod, &nic_mod, TOPO_VERSION) != 0) { + dladm_close(handle); + return (-1); + } + + topo_mod_setspecific(mod, handle); + + return (0); +} + +void +_topo_fini(topo_mod_t *mod) +{ + dladm_handle_t handle; + + if ((handle = topo_mod_getspecific(mod)) == NULL) + return; + + dladm_close(handle); + topo_mod_setspecific(mod, NULL); +} diff --git a/usr/src/lib/fm/topo/modules/common/nic/topo_nic.h b/usr/src/lib/fm/topo/modules/common/nic/topo_nic.h new file mode 100644 index 0000000000..ba661542c4 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/nic/topo_nic.h @@ -0,0 +1,34 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +#ifndef _TOPO_NIC_H +#define _TOPO_NIC_H + +/* + * Common NIC module header file. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define NIC "nic" +#define NIC_VERSION 1 + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_NIC_H */ diff --git a/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c index 1f3ba4478e..36dc26aa8d 100644 --- a/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c +++ b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Joyent, Inc. */ #include <sys/fm/protocol.h> @@ -43,6 +44,7 @@ #include <did.h> #include <did_props.h> #include <util.h> +#include <topo_nic.h> extern txprop_t Bus_common_props[]; extern txprop_t Dev_common_props[]; @@ -489,40 +491,52 @@ declare_dev_and_fn(topo_mod_t *mod, tnode_t *bus, tnode_t **dev, di_node_t din, */ else if (class == PCI_CLASS_NET && di_uintprop_get(mod, din, DI_VENDIDPROP, &vid) >= 0 && - di_uintprop_get(mod, din, DI_DEVIDPROP, &did) >= 0) { - if (vid == SUN_VENDOR_ID && did == NEPTUNE_DEVICE_ID) { - /* - * Is this an adapter card? Check the bus's physlot - */ - dp = did_find(mod, topo_node_getspecific(bus)); - if (did_physlot(dp) >= 0) { - topo_mod_dprintf(mod, "Found Neptune slot\n"); - (void) topo_mod_enummap(mod, fn, - "xfp", FM_FMRI_SCHEME_HC); + di_uintprop_get(mod, din, DI_DEVIDPROP, &did) >= 0 && + vid == SUN_VENDOR_ID && did == NEPTUNE_DEVICE_ID) { + /* + * Is this an adapter card? Check the bus's physlot + */ + dp = did_find(mod, topo_node_getspecific(bus)); + if (did_physlot(dp) >= 0) { + topo_mod_dprintf(mod, "Found Neptune slot\n"); + (void) topo_mod_enummap(mod, fn, + "xfp", FM_FMRI_SCHEME_HC); + } else { + topo_mod_dprintf(mod, "Found Neptune ASIC\n"); + if (topo_mod_load(mod, XAUI, TOPO_VERSION) == NULL) { + topo_mod_dprintf(mod, "pcibus enum " + "could not load xaui enum\n"); + (void) topo_mod_seterrno(mod, + EMOD_PARTIAL_ENUM); + return; } else { - topo_mod_dprintf(mod, "Found Neptune ASIC\n"); - if (topo_mod_load(mod, XAUI, TOPO_VERSION) == - NULL) { - topo_mod_dprintf(mod, "pcibus enum " - "could not load xaui enum\n"); - (void) topo_mod_seterrno(mod, - EMOD_PARTIAL_ENUM); + if (topo_node_range_create(mod, fn, + XAUI, 0, 1) < 0) { + topo_mod_dprintf(mod, + "child_range_add for " + "XAUI failed: %s\n", + topo_strerror( + topo_mod_errno(mod))); return; - } else { - if (topo_node_range_create(mod, fn, - XAUI, 0, 1) < 0) { - topo_mod_dprintf(mod, - "child_range_add for " - "XAUI failed: %s\n", - topo_strerror( - topo_mod_errno(mod))); - return; - } - (void) topo_mod_enumerate(mod, fn, - XAUI, XAUI, fnno, fnno, fn); } + (void) topo_mod_enumerate(mod, fn, + XAUI, XAUI, fnno, fnno, fn); } } + } else if (class == PCI_CLASS_NET) { + /* + * Ask the nic module if there are any nodes that need to be + * enumerated under this device. This might include things like + * transceivers or some day, LEDs. + */ + if (topo_mod_load(mod, NIC, NIC_VERSION) == NULL) { + topo_mod_dprintf(mod, "pcibus enum could not load " + "nic enum\n"); + (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); + return; + } + + (void) topo_mod_enumerate(mod, fn, NIC, NIC, 0, 0, din); } else if (class == PCI_CLASS_MASS) { di_node_t cn; int niports = 0; diff --git a/usr/src/lib/fm/topo/modules/common/shared/topo_port.c b/usr/src/lib/fm/topo/modules/common/shared/topo_port.c new file mode 100644 index 0000000000..29efcf6bd9 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/shared/topo_port.c @@ -0,0 +1,130 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +#include <sys/fm/protocol.h> +#include <fm/topo_mod.h> +#include <fm/topo_list.h> +#include <fm/topo_method.h> + +#include <topo_port.h> + +/* + * Common routines to create port entries in the topology tree. + */ + +static const topo_pgroup_info_t port_pgroup = { + TOPO_PGROUP_PORT, + TOPO_STABILITY_PRIVATE, + TOPO_STABILITY_PRIVATE, + 1 +}; + +int +port_range_create(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min, + topo_instance_t max) +{ + return (topo_node_range_create(mod, pnode, PORT, min, max)); +} + +/* + * Create a port node, specifying the type of port it is. This will create the + * common port property group and populate it. The caller will need to populate + * the port-specific property group as needed. + */ +static tnode_t * +port_create_common(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst, + const char *type) +{ + int err; + tnode_t *tn = NULL; + nvlist_t *fmri = NULL, *auth = NULL, *presource = NULL; + + if (type == NULL) { + topo_mod_dprintf(mod, "port_create_common missing type " + "argument\n"); + goto error; + } + + if ((auth = topo_mod_auth(mod, pnode)) == NULL) { + topo_mod_dprintf(mod, "topo_mod_auth() failed: %s\n", + topo_mod_errmsg(mod)); + goto error; + } + + if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, PORT, + inst, NULL, auth, NULL, NULL, NULL)) == NULL) { + topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s\n", + topo_mod_errmsg(mod)); + goto error; + } + + if ((tn = topo_node_bind(mod, pnode, PORT, inst, fmri)) == NULL) { + topo_mod_dprintf(mod, "topo_node_bind() failed: %s\n", + topo_mod_errmsg(mod)); + goto error; + } + + /* + * The FRU is always set to the FMRI of the parent device for a port. + */ + if (topo_node_resource(pnode, &presource, &err) != 0) { + topo_mod_dprintf(mod, "topo_node_resource() failed: %s\n", + topo_strerror(err)); + goto error; + } + + if (topo_node_fru_set(tn, presource, 0, &err) != 0) { + topo_mod_dprintf(mod, "topo_node_fru_set() failed: %s\n", + topo_strerror(err)); + goto error; + } + + if (topo_pgroup_create(tn, &port_pgroup, &err) != 0) { + topo_mod_dprintf(mod, "failed to create property group %s: " + "%s\n", TOPO_PGROUP_PORT, topo_strerror(err)); + goto error; + } + + if (topo_prop_set_string(tn, TOPO_PGROUP_PORT, TOPO_PROP_PORT_TYPE, + TOPO_PROP_IMMUTABLE, type, &err) != 0) { + topo_mod_dprintf(mod, "failed to set %s property: %s\n", + TOPO_PROP_PORT_TYPE, topo_strerror(err)); + goto error; + } + + nvlist_free(fmri); + nvlist_free(auth); + nvlist_free(presource); + return (tn); +error: + topo_node_unbind(tn); + nvlist_free(fmri); + nvlist_free(auth); + nvlist_free(presource); + return (tn); +} + +int +port_create_sff(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst, + tnode_t **nodep) +{ + tnode_t *tn; + + tn = port_create_common(mod, pnode, inst, TOPO_PROP_PORT_TYPE_SFF); + if (tn == NULL) + return (-1); + *nodep = tn; + return (0); +} diff --git a/usr/src/lib/fm/topo/modules/common/shared/topo_port.h b/usr/src/lib/fm/topo/modules/common/shared/topo_port.h new file mode 100644 index 0000000000..78ace0b0bb --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/shared/topo_port.h @@ -0,0 +1,36 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +#ifndef _TOPO_PORT_H +#define _TOPO_PORT_H + +/* + * Routines to manage and create ports. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int port_range_create(topo_mod_t *, tnode_t *, topo_instance_t, + topo_instance_t); +extern int port_create_sff(topo_mod_t *, tnode_t *, topo_instance_t, + tnode_t **); + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_PORT_H */ diff --git a/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.c b/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.c new file mode 100644 index 0000000000..25c4276dab --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.c @@ -0,0 +1,185 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +#include <sys/fm/protocol.h> +#include <fm/topo_mod.h> +#include <fm/topo_list.h> +#include <fm/topo_method.h> + +/* + * Common routines to create transceiver entries in the topology tree. + */ + +static const topo_pgroup_info_t transceiver_pgroup = { + TOPO_PGROUP_TRANSCEIVER, + TOPO_STABILITY_PRIVATE, + TOPO_STABILITY_PRIVATE, + 1 +}; + +static const topo_pgroup_info_t sff_transceiver_pgroup = { + TOPO_PGROUP_SFF_TRANSCEIVER, + TOPO_STABILITY_PRIVATE, + TOPO_STABILITY_PRIVATE, + 1 +}; + +int +transceiver_range_create(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min, + topo_instance_t max) +{ + return (topo_node_range_create(mod, pnode, TRANSCEIVER, min, max)); +} + +static tnode_t * +transceiver_create_common(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst, + const char *type, boolean_t usable, const char *part, const char *rev, + const char *serial) +{ + int err; + tnode_t *tn = NULL; + nvlist_t *fmri = NULL, *auth = NULL; + + if (type == NULL) { + topo_mod_dprintf(mod, "transceiver_create_common missing type " + "argument"); + goto error; + } + + if ((auth = topo_mod_auth(mod, pnode)) == NULL) { + topo_mod_dprintf(mod, "topo_mod_auth() failed: %s\n", + topo_mod_errmsg(mod)); + goto error; + } + + if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, + TRANSCEIVER, inst, NULL, auth, part, rev, serial)) == NULL) { + topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s\n", + topo_mod_errmsg(mod)); + goto error; + } + + if ((tn = topo_node_bind(mod, pnode, TRANSCEIVER, inst, fmri)) == + NULL) { + topo_mod_dprintf(mod, "topo_node_bind() failed: %s\n", + topo_mod_errmsg(mod)); + goto error; + } + + /* + * The FRU for a transceiver is always itself. + */ + if (topo_node_fru_set(tn, fmri, 0, &err) != 0) { + topo_mod_dprintf(mod, "topo_node_fru_set() failed: %s\n", + topo_strerror(err)); + goto error; + } + + if (topo_pgroup_create(tn, &transceiver_pgroup, &err) != 0) { + topo_mod_dprintf(mod, "failed to create property group %s: " + "%s\n", TOPO_PGROUP_TRANSCEIVER, topo_strerror(err)); + goto error; + } + + if (topo_prop_set_string(tn, TOPO_PGROUP_TRANSCEIVER, + TOPO_PROP_TRANSCEIVER_TYPE, TOPO_PROP_IMMUTABLE, type, + &err) != 0) { + topo_mod_dprintf(mod, "failed to set %s property: %s\n", + TOPO_PROP_TRANSCEIVER_TYPE, topo_strerror(err)); + goto error; + } + + if (topo_prop_set_string(tn, TOPO_PGROUP_TRANSCEIVER, + TOPO_PROP_TRANSCEIVER_USABLE, TOPO_PROP_IMMUTABLE, + usable ? "true" : "false", &err) != 0) { + topo_mod_dprintf(mod, "failed to set %s property: %s\n", + TOPO_PROP_TRANSCEIVER_USABLE, topo_strerror(err)); + goto error; + } + + nvlist_free(fmri); + nvlist_free(auth); + return (tn); + +error: + topo_node_unbind(tn); + nvlist_free(fmri); + nvlist_free(auth); + return (NULL); +} + +int +transceiver_create_sff(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst, + boolean_t useable, const char *vendor, const char *part, const char *rev, + const char *serial, tnode_t **nodep) +{ + int err; + tnode_t *tn = NULL; + + if ((tn = transceiver_create_common(mod, pnode, inst, + TOPO_PROP_PORT_TYPE_SFF, useable, part, rev, serial)) == NULL) { + return (-1); + } + + /* + * Always create the SFF property group, even if we can't fill in any + * properties. + */ + if (topo_pgroup_create(tn, &sff_transceiver_pgroup, &err) != 0) { + topo_mod_dprintf(mod, "failed to create property group %s: " + "%s\n", TOPO_PGROUP_SFF_TRANSCEIVER, topo_strerror(err)); + goto error; + } + + if (vendor != NULL && topo_prop_set_string(tn, + TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_VENDOR, + TOPO_PROP_IMMUTABLE, vendor, &err) != 0) { + topo_mod_dprintf(mod, "failed to set %s property: %s\n", + TOPO_PORT_SFF_TRANSCEIVER_VENDOR, topo_strerror(err)); + goto error; + } + + if (part != NULL && topo_prop_set_string(tn, + TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_PN, + TOPO_PROP_IMMUTABLE, part, &err) != 0) { + topo_mod_dprintf(mod, "failed to set %s property: %s\n", + TOPO_PORT_SFF_TRANSCEIVER_PN, topo_strerror(err)); + goto error; + } + + if (rev != NULL && topo_prop_set_string(tn, + TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_REV, + TOPO_PROP_IMMUTABLE, rev, &err) != 0) { + topo_mod_dprintf(mod, "failed to set %s property: %s\n", + TOPO_PORT_SFF_TRANSCEIVER_REV, topo_strerror(err)); + goto error; + } + + if (serial != NULL && topo_prop_set_string(tn, + TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_SN, + TOPO_PROP_IMMUTABLE, serial, &err) != 0) { + topo_mod_dprintf(mod, "failed to set %s property: %s\n", + TOPO_PORT_SFF_TRANSCEIVER_SN, topo_strerror(err)); + goto error; + } + + if (nodep != NULL) + *nodep = tn; + return (0); + +error: + topo_node_unbind(tn); + return (-1); +} diff --git a/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.h b/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.h new file mode 100644 index 0000000000..f371598739 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.h @@ -0,0 +1,37 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +#ifndef _TOPO_TRANSCEIVER_H +#define _TOPO_TRANSCEIVER_H + +/* + * Routines to manage and create ports. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int transceiver_range_create(topo_mod_t *, tnode_t *, topo_instance_t, + topo_instance_t); +extern int transceiver_create_sff(topo_mod_t *, tnode_t *, topo_instance_t, + boolean_t, const char *, const char *, const char *, const char *, + tnode_t **); + +#ifdef __cplusplus +} +#endif + +#endif /* _TOPO_TRANSCEIVER_H */ diff --git a/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile b/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile index 1b34ed3510..b41606985a 100644 --- a/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile +++ b/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile @@ -21,6 +21,7 @@ # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, Joyent, Inc. # MODULE = pcibus @@ -28,6 +29,7 @@ ARCH = i86pc CLASS = arch UTILDIR = ../../common/pcibus HBDIR = ../../common/hostbridge +NICDIR = ../../common/nic UTILSRCS = did.c did_hash.c did_props.c util.c PCISRCS = pcibus.c pcibus_labels.c pcibus_hba.c @@ -37,4 +39,4 @@ include ../../Makefile.plugin LDLIBS += -ldevinfo -lsmbios -CPPFLAGS += -I$(UTILDIR) -I$(HBDIR) +CPPFLAGS += -I$(UTILDIR) -I$(HBDIR) -I $(NICDIR) diff --git a/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci b/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci index 277e868277..82ecb535c2 100644 --- a/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci +++ b/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci @@ -27,6 +27,7 @@ MODULE = pcibus CLASS = arch SUN4DIR = ../../sun4/$(MODULE) UTILDIR = ../../common/pcibus +NICDIR = ../../common/nic HBDIR = ../../common/hostbridge UTILSRCS = did.c did_hash.c did_props.c util.c PCISRCS = pcibus.c pcibus_labels.c pci_sun4.c pcibus_hba.c @@ -36,7 +37,7 @@ MODULESRCS = $(PCISRCS) $(UTILSRCS) pci_$(ARCH).c include ../../Makefile.plugin LDLIBS += -ldevinfo -lsmbios -CPPFLAGS += -I$(SUN4DIR) -I$(UTILDIR) -I$(HBDIR) +CPPFLAGS += -I$(SUN4DIR) -I$(UTILDIR) -I$(HBDIR) -I$(NICDIR) %.o: $(SUN4DIR)/%.c $(COMPILE.c) -o $@ $< diff --git a/usr/src/lib/libsff/Makefile b/usr/src/lib/libsff/Makefile new file mode 100644 index 0000000000..39c13c30bf --- /dev/null +++ b/usr/src/lib/libsff/Makefile @@ -0,0 +1,44 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2017 Joyent, Inc. +# + +include ../Makefile.lib + +HDRS = libsff.h +HDRDIR = common +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET = all +clean := TARGET = clean +clobber := TARGET = clobber +install := TARGET = install +lint := TARGET = lint + +.KEEP_STATE: + +all clean clobber lint: $(SUBDIRS) + +install: $(SUBDIRS) $(VARPD_MAPFILES) install_h + +install_h: $(ROOTHDRS) + +check: $(CHECKHDRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include ../Makefile.targ diff --git a/usr/src/lib/libsff/Makefile.com b/usr/src/lib/libsff/Makefile.com new file mode 100644 index 0000000000..dab4bfbca3 --- /dev/null +++ b/usr/src/lib/libsff/Makefile.com @@ -0,0 +1,34 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2017 Joyent, Inc. All rights reserved. +# + +LIBRARY = libsff.a +VERS = .1 +OBJECTS = libsff.o + +include ../../Makefile.lib + +LIBS = $(DYNLIB) $(LINTLIB) +LDLIBS += -lc -lnvpair +CPPFLAGS += -I../common + +SRCDIR = ../common + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +include ../../Makefile.targ diff --git a/usr/src/lib/libsff/amd64/Makefile b/usr/src/lib/libsff/amd64/Makefile new file mode 100644 index 0000000000..4d3cfa1f81 --- /dev/null +++ b/usr/src/lib/libsff/amd64/Makefile @@ -0,0 +1,19 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2017 Joyent, Inc. +# + +include ../Makefile.com +include ../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64) diff --git a/usr/src/lib/libsff/common/libsff.c b/usr/src/lib/libsff/common/libsff.c new file mode 100644 index 0000000000..cd0a1228a6 --- /dev/null +++ b/usr/src/lib/libsff/common/libsff.c @@ -0,0 +1,1412 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Parse raw SFF data into an nvlist that can be processed by users, providing + * them with what can be printable strings. At the moment, we handle the + * majority of parsing page 0xa0 based on SFF 8472 (thus covering INF-8074 and + * friends) and SFF 8636 (thus covering SFF-8436 and friends). Interfaces that + * parse data into logical structures may be useful to add when considering + * monitoring data in page 0xa2. + * + * When parsing, we try to make sure that the user has supplied, or at least + * thinks they have supplied, a buffer of sufficient length. The general design + * is that we require the buffer to be large enough to cover all of the offsets + * that we care about. If the buffer isn't this large, then we leave it be. + * + * This library is private and subject to change at any time. + */ + +#include <assert.h> +#include <strings.h> +#include <libsff.h> +#include <errno.h> + +#include "sff.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +/* + * Maximum size of a string buffer while parsing. + */ +#define SFP_STRBUF 128 + +/* + * Minimum length of the buffer we require to parse the SFP data. + */ +#define SFP_MIN_LEN_8472 96 +#define SFP_MIN_LEN_8636 224 + +/* + * This table is derived from SFF 8024 Section 4.1, Table 4-1. + */ +static const char *sff_8024_id_strs[SFF_8024_NIDS] = { + "Unknown or Unspecified", + "GBIC", + "Module/connector soldered to motherboard", + "SFP/SFP+/SFP28", + "300 pin XBI", + "XENPAK", + "XFP", + "XFF", + "XFP-E", + "XPAK", + "X2", + "DWDM-SFP/SFP+ (not using SFF-8472)", + "QSFP", + "QSFP+ or later", + "CXP or later", + "Shielded Mini Multilane HD 4X", + "Shielded Mini Multilane HD 8X", + "QSFP28 or later", + "CXP2 (aka CXP28) or later", + "CDFP (Style 1/Style2)", + "Shielded Mini Multilane HD 4X Fanout Cable", + "Shielded Mini Multilane HD 8X Fanout Cable", + "CDFP (Style 3)", + "microQSFP" +}; + +/* + * The set of values used for the encoding depends on whether we're a basic SFP + * device or not. The values are inconsistent between SFP and QSFP based + * devices. + * + * This table is derived from SFF 8024 r3.9 Table 4-2. + */ +#define SFF_8024_NENCS 9 +static const char *sff_8024_enc_sfp[] = { + "Unspecified", + "8B/10B", + "4B/5B", + "NRZ", + "Manchester", + "SONET Scrambled", + "64B/66B", + "256B/257B", + "PAM4" +}; + +static const char *sff_8024_enc_qsfp[] = { + "Unspecified", + "8B/10B", + "4B/5B", + "NRZ", + "SONET Scrambled", + "64B/66B", + "Manchester", + "256B/257B", + "PAM4" +}; + +/* + * This table is derived from SFF 8024 r3.9 Section 4.4. + */ +#define SFF_8024_EXT_SPEC_NENTRIES 27 +static const char *sff_8024_ext_spec[] = { + "Unspecified", + "100G AOC or 25GAUI C2M AOC", + "100GBASE-SR4 or 25GBASE-SR", + "100GBASE-LR4 or 25GBASE-LR", + "100GBASE-ER4 or 25GBASE-ER", + "100GBASE-SR10", + "100G CWDM4", + "100G PSM4 Parallel SMF", + "100G ACC or 25GAUI C2M ACC", + "Obsolete", + "Reserved", + "100GBASE-CR4 or 25GBASE-CR CA-L", + "25GBASE-CR CA-S", + "25GBASE-CR CA-N", + "Reserved", + "Reserved", + "40GBASE-ER4", + "4 x 10GBASE-SR", + "40G PSM4 Parallel SMF", + "G959.1 profile P1I1-2D1", + "G959.1 profile P1S1-2D2", + "G959.1 profile P1L1-2D2", + "10GBASE-T with SFI electrical interface", + "100G CLR4", + "100G AOC or 25GAUI C2M AOC", + "100G ACC or 25GAUI C2M ACC", + "100GE-DWDM2" +}; + +typedef struct sff_pair { + uint_t sp_val; + const char *sp_name; +} sff_pair_t; + +/* + * This table is derived from SFF 8024 r3.9 Section 4.3. + */ +static sff_pair_t sff_8024_connectors[] = { + { 0x00, "Unknown" }, + { 0x01, "SC (Subscriber Connector)" }, + { 0x02, "Fibre Channel Style 1 copper connector" }, + { 0x03, "Fibre Channel Style 2 copper connector" }, + { 0x04, "BNC/TNC (Bayonet/Threaded Neill-Concelman)" }, + { 0x05, "Fibre Channel coax headers" }, + { 0x06, "Fiber Jack" }, + { 0x07, "LC (Lucent Connector)" }, + { 0x08, "MT-RJ (Mechanical Transfer - Registered Jack)" }, + { 0x09, "MU (Multiple Optical)" }, + { 0x0A, "SG" }, + { 0x0B, "Optical Pigtail" }, + { 0x0C, "MPO 1x12 (Multifiber Parallel Optic)" }, + { 0x0D, "MPO 2x16" }, + { 0x20, "HSSDC II (High Speed Serial Data Connector)" }, + { 0x21, "Copper pigtail" }, + { 0x22, "RJ45 (Registered Jack)" }, + { 0x23, "No separable connector" }, + { 0x24, "MXC 2x16" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 5-3. + */ +#define SFF_8472_COMP_10GETH_MASK 0xf0 +static sff_pair_t sff_8472_comp_10geth[] = { + { 0x80, "10G Base-ER" }, + { 0x40, "10G Base-LRM" }, + { 0x20, "10G Base-LR" }, + { 0x10, "10G Base-SR" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 5-3. + */ +#define SFF_8472_COMP_IB_MASK 0x0f +static sff_pair_t sff_8472_comp_ib[] = { + { 0x08, "1X SX" }, + { 0x04, "1X LX" }, + { 0x02, "1X Copper Active" }, + { 0x01, "1X Copper Passive" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 5-3. + */ +#define SFF_8472_COMP_ESCON_MASK 0xc0 +static sff_pair_t sff_8472_comp_escon[] = { + { 0x80, "ESCON MMF, 1310nm LED" }, + { 0x40, "ESCON SMF, 1310nm Laser" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 5-3. These values come from both + * bytes 4 and 5. We treat this as a uint16_t with the low byte as byte 4 and + * the high byte as byte 5. + */ +#define SFF_8472_COMP_SOCON_MASK 0x773f +static sff_pair_t sff_8472_comp_sonet[] = { + { 0x20, "OC-192, short reach" }, + { 0x10, "SONET reach specifier bit 1" }, + { 0x08, "ONET reach specifier bit 2" }, + { 0x04, "OC-48, long reach" }, + { 0x02, "OC-48, intermediate reach" }, + { 0x01, "OC-48, short reach" }, + /* 0x8000 is unallocated */ + { 0x4000, "OC-12, single mode, long reach" }, + { 0x2000, "OC-12, single mode, inter. reach" }, + { 0x1000, "OC-12, short reach" }, + /* 0x800 is unallocted */ + { 0x0400, "OC-3, single mode, long reach" }, + { 0x0200, "OC-3, single mode, inter. reach" }, + { 0x0100, "OC-3, short reach" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 5-3. + */ +#define SFF_8472_COMP_ETH_MASK 0xff +static sff_pair_t sff_8472_comp_eth[] = { + { 0x80, "BASE-PX" }, + { 0x40, "BASE-BX10" }, + { 0x20, "100BASE-FX" }, + { 0x10, "100BASE-LX/LX10" }, + { 0x08, "1000BASE-T" }, + { 0x04, "1000BASE-CX" }, + { 0x02, "1000BASE-LX" }, + { 0x01, "1000BASE-SX" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 5-3. + */ +#define SFF_8472_COMP_FCLEN_MASK 0xf8 +static sff_pair_t sff_8472_comp_fclen[] = { + { 0x80, "very long distance (V)" }, + { 0x40, "short distance (S)" }, + { 0x20, "intermeddiate distance (I)" }, + { 0x10, "long distance (L)" }, + { 0x08, "medium distance (M)" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 5-3. These values come from both + * bytes 7 and 8. We treat this as a uint16_t with the low byte as byte 7 and + * the high byte as byte 8. + */ +#define SFF_8472_COMP_TECH_MASK 0xf007 +static sff_pair_t sff_8472_comp_tech[] = { + { 0x4, "Shortwave laser, linear Rx (SA)" }, + { 0x2, "Longwave laser (LC)" }, + { 0x1, "Electrical inter-enclosure (EL)" }, + { 0x8000, "Electrical intra-enclosure (EL)" }, + { 0x4000, "Shortwave laser w/o OFC (SN)" }, + { 0x2000, "Shortwave laser with OFC (SL)" }, + { 0x1000, "Longwave laser (LL)" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 5-3. + */ +#define SFF_8472_COMP_CABLE_MASK 0x0c +#define SFF_8472_COMP_CABLE_ACTIVE 0x08 +#define SFF_8472_COMP_CABLE_PASSIVE 0x04 +static sff_pair_t sff_8472_comp_cable[] = { + { 0x08, "Active Cable" }, + { 0x04, "Passive Cable" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 5-3. + */ +#define SFF_8472_COMP_MEDIA_MASK 0xfd +static sff_pair_t sff_8472_comp_media[] = { + { 0x80, "Twin Axial Pair (TW)" }, + { 0x40, "Twisted Pair (TP)" }, + { 0x20, "Miniature Coax (MI)" }, + { 0x10, "Video Coax (TV)" }, + { 0x08, "Multimode, 62.5um (M6)" }, + { 0x04, "Multimode, 50um (M5, M5E)" }, + /* 0x02 is Unallocated */ + { 0x01, "Single Mode (SM)" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 5-3. + */ +#define SFF_8472_COMP_SPEED_MASK 0xfd +static sff_pair_t sff_8472_comp_speed[] = { + { 0x80, "1200 MBytes/sec" }, + { 0x40, "800 MBytes/sec" }, + { 0x20, "1600 MBytes/sec" }, + { 0x10, "400 MBytes/sec" }, + { 0x08, "3200 MBytes/sec" }, + { 0x04, "200 MBytes/sec" }, + /* 0x02 is Unallocated */ + { 0x01, "100 MBytes/sec" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 8-1. + * Note, only byte 60 is allocated at this time. + */ +#define SFF_8472_PCABLE_COMP_MASK 0x3f +static sff_pair_t sff_8472_pcable_comp[] = { + { 0x20, "Reserved for SFF-8461" }, + { 0x10, "Reserved for SFF-8461" }, + { 0x08, "Reserved for SFF-8461" }, + { 0x04, "Reserved for SFF-8461" }, + { 0x02, "Compliant to FC-PI-4 Appendix H" }, + { 0x01, "Compliant to SFF-8431 Appendix E" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 8-2. + * Note, only byte 60 is allocated at this time. + */ +#define SFF_8472_ACABLE_COMP_MASK 0xf +static sff_pair_t sff_8472_acable_comp[] = { + { 0x08, "Compliant to FC-PI-4 Limiting" }, + { 0x04, "Compliant to SFF-8431 Limiting" }, + { 0x02, "Compliant to FC-PI-4 Appendix H" }, + { 0x01, "Compliant to SFF-8431 Appendix" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8472 r12.2 Table 8-3. + * Note that we combined byte 64 and 65. Byte 64 is the upper bit. + */ +#define SFF_8472_OPTION_MASK 0x3ffe +static sff_pair_t sff_8472_options[] = { + { 0x2000, "Power Level 3 Requirement"}, + { 0x1000, "Paging Implemented"}, + { 0x0800, "Retimer or CDR implemented"}, + { 0x0400, "Cooled Transceiver Implemented"}, + { 0x0200, "Power Level 2 Requirement"}, + { 0x0100, "Linear Receiver Output Implemented"}, + { 0x0080, "Receiver decision threshold implemented"}, + { 0x0040, "Tunable transmitter"}, + { 0x0020, "RATE_SELECT implemented"}, + { 0x0010, "TX_DISABLE implemented"}, + { 0x0008, "TX_FAULT implemented"}, + { 0x0004, "Rx_LOS inverted"}, + { 0x0002, "Rx_LOS implemented"}, +}; + +/* + * This is derived from SFF 8472 r12.2 Table 8-6. + */ +#define SFF_8472_EXTOPT_MASK 0xfe +static sff_pair_t sff_8472_extopts[] = { + { 0x80, "Alarm/Warning flags implemented" }, + { 0x40, "Soft TX_DISABLE implemented" }, + { 0x20, "Soft TX_FAULT implemented" }, + { 0x10, "Soft RX_LOS implemented" }, + { 0x08, "Soft RATE_SELECT implemented" }, + { 0x04, "Application Select implemented" }, + { 0x02, "Soft Rate Select Control Implemented" }, + { 0x01, "" }, +}; + +/* + * This is derived from SFF 8472 r12.2 Table 8-8. + */ +#define SFF_8472_8472_COMP_NENTRIES 9 +static const char *sff_8472_8472_comp[] = { + "Not compliant", + "Rev 9.3", + "Rev 9.5", + "Rev 10.2", + "Rev 10.4", + "Rev 11.0", + "Rev 11.3", + "Rev 11.4", + "Rev 12.0" +}; + +/* + * This is derived from SFF 8636 r2.7 Table 6-17. + */ +#define SFF_8636_COMP_10GETH_MASK 0x7f +static sff_pair_t sff_8636_comp_10geth[] = { + { 0x40, "10GBASE-LRM" }, + { 0x20, "10GBASE-LR" }, + { 0x10, "10GBASE-SR" }, + { 0x08, "40GBASE-CR4" }, + { 0x04, "40GBASE-SR4" }, + { 0x02, "40GBASE-LR4" }, + { 0x01, "40G Active Cable (XLPPI)" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8636 r2.7 Table 6-17. + */ +#define SFF_8636_COMP_SONET_MASK 0x07 +static sff_pair_t sff_8636_comp_sonet[] = { + { 0x04, "OC 48, long reach" }, + { 0x02, "OC 48, intermediate reach" }, + { 0x01, "OC 48 short reach" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8636 r2.7 Table 6-17. + */ +#define SFF_8636_COMP_SAS_MASK 0xf0 +static sff_pair_t sff_8636_comp_sas[] = { + { 0x80, "SAS 24.0 Gb/s" }, + { 0x40, "SAS 12.0 Gb/s" }, + { 0x20, "SAS 6.0 Gb/s" }, + { 0x10, "SAS 3.0 Gb/s" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8636 r2.7 Table 6-17. + */ +#define SFF_8636_COMP_ETH_MASK 0x0f +static sff_pair_t sff_8636_comp_eth[] = { + { 0x08, "1000BASE-T" }, + { 0x04, "1000BASE-CX" }, + { 0x02, "1000BASE-LX" }, + { 0x01, "1000BASE-SX" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8636 r2.7 Table 6-17. + */ +#define SFF_8636_COMP_FCLEN_MASK 0xf8 +static sff_pair_t sff_8636_comp_fclen[] = { + { 0x80, "very long distance (V)" }, + { 0x40, "short distance (S)" }, + { 0x20, "intermeddiate distance (I)" }, + { 0x10, "long distance (L)" }, + { 0x08, "medium distance (M)" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8636 r2.7 Table 6-17. + */ +#define SFF_8636_COMP_TECH_MASK 0xf003 +static sff_pair_t sff_8636_comp_tech[] = { + { 0x2, "Longwave laser (LC)" }, + { 0x1, "Electrical inter-enclosure (EL)" }, + { 0x8000, "Electrical intra-enclosure (EL)" }, + { 0x4000, "Shortwave laser w/o OFC (SN)" }, + { 0x2000, "Shortwave laser with OFC (SL)" }, + { 0x1000, "Longwave laser (LL)" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8636 r2.7 Table 6-17. + */ +#define SFF_8636_COMP_MEDIA_MASK 0xff +static sff_pair_t sff_8636_comp_media[] = { + { 0x80, "Twin Axial Pair (TW)" }, + { 0x40, "Twisted Pair (TP)" }, + { 0x20, "Miniature Coax (MI)" }, + { 0x10, "Video Coax (TV)" }, + { 0x08, "Multimode, 62.5um (M6)" }, + { 0x04, "Multimode, 50m (M5)" }, + { 0x02, "Multimode, 50um (OM3)" }, + { 0x01, "Single Mode (SM)" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8636 r2.7 Table 6-17. + */ +#define SFF_8636_COMP_SPEED_MASK 0xfd +static sff_pair_t sff_8636_comp_speed[] = { + { 0x80, "1200 MBytes/sec" }, + { 0x40, "800 MBytes/sec" }, + { 0x20, "1600 MBytes/sec" }, + { 0x10, "400 MBytes/sec" }, + { 0x08, "3200 MBytes/sec" }, + { 0x04, "200 MBytes/sec" }, + { 0x01, "100 MBytes/sec" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8636 r2.7 Table 6-20. + */ +static const char *sff_8636_trans_tech[] = { + "850 nm VCSEL", + "1310 nm VCSEL", + "1550 nm VCSEL", + "1310 nm FP", + "1310 nm DFB", + "1550 nm DFB", + "1310 nm EML", + "1550 nm EML", + "Other / Undefined", + "1490 nm DFB", + "Copper cable unequalized", + "Copper cable passive equalized", + "Copper cable, near and far end limiting active equalizers", + "Copper cable, far end limiting active equalizers", + "Copper cable, near end limiting active equalizers", + "Copper cable, linear active equalizers" +}; + +/* + * This is derived from SFF 8636 r2.7 Table 6-21. + */ +#define SFF_8636_EXTMOD_CODES 0x1f +static sff_pair_t sff_8636_extmod_codes[] = { + { 0x10, "EDR" }, + { 0x08, "FDR" }, + { 0x04, "QDR" }, + { 0x02, "DDR" }, + { 0x01, "SDR" }, + { 0x00, NULL } +}; + +/* + * This is derived from SFF 8636 r2.7 Table 6-22. This combines bytes 193-195. + * We treat byte 193 as the most significant. + */ +#define SFF_8636_OPTION_MASK 0x0ffffe +static sff_pair_t sff_8636_options[] = { + { 0x080000, "TX Input Equalization Auto Adaptive Capable" }, + { 0x040000, "TX Input Equalization Fixed Programmable" }, + { 0x020000, "RX Output Emphasis Fixed Programmable Settings" }, + { 0x010000, "RX Output Amplitude Fixed Programmable Settings" }, + { 0x008000, "TX CDR On/Off Control implemented" }, + { 0x004000, "RX CDR On/Off Control implemented" }, + { 0x002000, "Tx CDR Loss of Lock Flag implemented" }, + { 0x001000, "Rx CDR Loss of Lock Flag implemented" }, + { 0x000800, "Rx Squelch Disable implemented" }, + { 0x000400, "Rx Output Disable capable" }, + { 0x000200, "Tx Squelch Disable implemented" }, + { 0x000100, "Tx Squelch implemented" }, + { 0x000080, "Memory page 02h provided" }, + { 0x000040, "Memory page 01h provided" }, + { 0x000020, "Rate Select implemented" }, + { 0x000010, "Tx_DISABLE implemented" }, + { 0x000008, "Tx_FAULT implemented" }, + { 0x000004, "Tx Squelch for Pave" }, + { 0x000002, "Tx Loss of Signal implemented" }, + { 0x0, NULL } +}; + +/* + * This is derived from SFF 8636 r2.7 Table 6-25. + */ +#define SFF_8636_ENHANCED_OPTIONS_MASK 0x1c +static sff_pair_t sff_8636_eopt[] = { + { 0x10, "Initialization Complete Flag Implemented" }, + { 0x08, "Extended Rate Selection Supported" }, + { 0x04, "Application Select Table Supported" }, + { 0x0, NULL } +}; + +static const char * +sff_pair_find(uint_t val, sff_pair_t *pairs) +{ + while (pairs->sp_name != NULL) { + if (val == pairs->sp_val) + return (pairs->sp_name); + pairs++; + } + + return (NULL); +} + +static int +sff_parse_id(uint8_t id, nvlist_t *nvl) +{ + const char *val; + + if (id >= SFF_8024_VENDOR) { + val = "Vendor Specific"; + } else if (id >= SFF_8024_NIDS) { + val = "Reserved"; + } else { + val = sff_8024_id_strs[id]; + } + + return (nvlist_add_string(nvl, LIBSFF_KEY_IDENTIFIER, val)); +} + +static int +sff_add_unit_string(uint64_t val, uint64_t factor, const char *unit, + nvlist_t *nvl, const char *key) +{ + char str[SFP_STRBUF]; + + val *= factor; + (void) snprintf(str, sizeof (str), "%" PRIu64 " %s", val, unit); + return (nvlist_add_string(nvl, key, str)); +} + +static int +sff_parse_connector(uint8_t con, nvlist_t *nvl) +{ + const char *val; + + if (con >= 0x80) { + val = "Vendor Specific"; + } else { + if ((val = sff_pair_find(con, sff_8024_connectors)) == NULL) + val = "Reserved"; + } + + return (nvlist_add_string(nvl, LIBSFF_KEY_CONNECTOR, val)); +} + +/* + * Many of the values in the specifications are bitfields of which one or more + * bits may be set. We represent that as an array of strings. One entry will be + * added for each set bit that's found in pairs. + */ +static int +sff_gather_bitfield(uint32_t value, const char *name, sff_pair_t *pairs, + nvlist_t *nvl) +{ + uint32_t i; + const char *vals[32]; + uint_t count; + + count = 0; + for (i = 0; i < 32; i++) { + uint32_t bit; + const char *str; + + bit = 1 << i; + if ((bit & value) == 0) + continue; + + str = sff_pair_find(bit, pairs); + if (str != NULL) { + vals[count++] = str; + } + } + + if (count == 0) + return (0); + + /* + * The nvlist routines don't touch the array, so we end up lying about + * the type of data so that we can avoid a rash of additional + * allocations and strdups. + */ + return (nvlist_add_string_array(nvl, name, (char **)vals, count)); +} + +static int +sff_parse_compliance(const uint8_t *buf, nvlist_t *nvl) +{ + int ret; + uint16_t v; + + if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_10GE] & + SFF_8472_COMP_10GETH_MASK, LIBSFF_KEY_COMPLIANCE_10GBE, + sff_8472_comp_10geth, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_IB] & + SFF_8472_COMP_IB_MASK, LIBSFF_KEY_COMPLIANCE_IB, + sff_8472_comp_ib, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_ESCON] & + SFF_8472_COMP_ESCON_MASK, LIBSFF_KEY_COMPLIANCE_ESCON, + sff_8472_comp_escon, nvl)) != 0) + return (ret); + + v = buf[SFF_8472_COMPLIANCE_SONET_LOW] | + (buf[SFF_8472_COMPLIANCE_SONET_HIGH] << 8); + if ((ret = sff_gather_bitfield(v & SFF_8472_COMP_SOCON_MASK, + LIBSFF_KEY_COMPLIANCE_SONET, sff_8472_comp_sonet, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_ETHERNET] & + SFF_8472_COMP_ETH_MASK, LIBSFF_KEY_COMPLIANCE_GBE, + sff_8472_comp_eth, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_FCLEN] & + SFF_8472_COMP_FCLEN_MASK, LIBSFF_KEY_COMPLIANCE_FC_LEN, + sff_8472_comp_fclen, nvl)) != 0) + return (ret); + + v = buf[SFF_8472_COMPLIANCE_FC_LOW] | + (buf[SFF_8472_COMPLIANCE_FC_HIGH] << 8); + if ((ret = sff_gather_bitfield(v & SFF_8472_COMP_TECH_MASK, + LIBSFF_KEY_COMPLIANCE_FC_TECH, sff_8472_comp_tech, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_SFP] & + SFF_8472_COMP_CABLE_MASK, LIBSFF_KEY_COMPLIANCE_SFP, + sff_8472_comp_cable, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_FC_MEDIA] & + SFF_8472_COMP_MEDIA_MASK, LIBSFF_KEY_COMPLIANCE_FC_MEDIA, + sff_8472_comp_media, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_FC_SPEED] & + SFF_8472_COMP_SPEED_MASK, LIBSFF_KEY_COMPLIANCE_FC_SPEED, + sff_8472_comp_speed, nvl)) != 0) + return (ret); + + return (0); +} + +static int +sff_parse_encoding(uint8_t val, nvlist_t *nvl, boolean_t sfp) +{ + const char *str; + if (val >= SFF_8024_NENCS) { + str = "Reserved"; + } else if (sfp) { + str = sff_8024_enc_sfp[val]; + } else { + str = sff_8024_enc_qsfp[val]; + } + + return (nvlist_add_string(nvl, LIBSFF_KEY_ENCODING, str)); +} + +static int +sff_parse_br(const uint8_t *buf, nvlist_t *nvl) +{ + if (buf[SFF_8472_BR_NOMINAL] == 0xff) { + int ret; + if ((ret = sff_add_unit_string(buf[SFF_8472_BR_MAX], + SFF_8472_BR_MAX_FACTOR, "MBd", nvl, + LIBSFF_KEY_BR_MAX)) != 0) + return (ret); + return (sff_add_unit_string(buf[SFF_8472_BR_MIN], + SFF_8472_BR_MIN_FACTOR, "MBd", nvl, LIBSFF_KEY_BR_MIN)); + } else { + return (sff_add_unit_string(buf[SFF_8472_BR_NOMINAL], + SFF_8472_BR_NOMINAL_FACTOR, "MBd", nvl, + LIBSFF_KEY_BR_NOMINAL)); + } +} + +static int +sff_parse_lengths(const uint8_t *buf, nvlist_t *nvl) +{ + int ret; + + if (buf[SFF_8472_LENGTH_SMF_KM] != 0) { + if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_SMF_KM], + SFF_8472_LENGTH_SMF_KM_FACTOR, "km", nvl, + LIBSFF_KEY_LENGTH_SMF_KM)) != 0) + return (ret); + } + + if (buf[SFF_8472_LENGTH_SMF] != 0) { + if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_SMF], + SFF_8472_LENGTH_SMF_FACTOR, "m", nvl, + LIBSFF_KEY_LENGTH_SMF)) != 0) + return (ret); + } + + if (buf[SFF_8472_LENGTH_50UM] != 0) { + if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_50UM], + SFF_8472_LENGTH_50UM_FACTOR, "m", nvl, + LIBSFF_KEY_LENGTH_OM2)) != 0) + return (ret); + } + + if (buf[SFF_8472_LENGTH_62UM] != 0) { + if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_62UM], + SFF_8472_LENGTH_62UM_FACTOR, "m", nvl, + LIBSFF_KEY_LENGTH_OM1)) != 0) + return (ret); + } + + if (buf[SFF_8472_LENGTH_COPPER] != 0) { + if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_COPPER], + SFF_8472_LENGTH_COPPER_FACTOR, "m", nvl, + LIBSFF_KEY_LENGTH_COPPER)) != 0) + return (ret); + } + + if (buf[SFF_8472_LENGTH_OM3] != 0) { + if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_OM3], + SFF_8472_LENGTH_OM3_FACTOR, "m", nvl, + LIBSFF_KEY_LENGTH_OM3)) != 0) + return (ret); + } + + return (0); +} + +/* + * Strings in the SFF specification are written into fixed sized buffers. The + * strings are padded to the right with spaces (ASCII 0x20) and there is no NUL + * character like in a standard C string. While the string is padded with + * spaces, spaces may appear in the middle of the string and should not be + * confused as padding. + */ +static int +sff_parse_string(const uint8_t *buf, uint_t start, uint_t len, + const char *field, nvlist_t *nvl) +{ + uint_t i; + char strbuf[SFP_STRBUF]; + + assert(len < sizeof (strbuf)); + strbuf[0] = '\0'; + while (len > 0) { + if (buf[start + len - 1] != ' ') + break; + len--; + } + if (len == 0) + return (0); + + /* + * This is supposed to be 7-bit printable ASCII. If we find any + * characters that aren't, don't include this string. + */ + for (i = 0; i < len; i++) { + if (buf[start + i] < ' ' || buf[start + i] > '~') { + return (0); + } + } + bcopy(&buf[start], strbuf, len); + strbuf[len] = '\0'; + + return (nvlist_add_string(nvl, field, strbuf)); +} + +static int +sff_parse_optical(const uint8_t *buf, nvlist_t *nvl) +{ + /* + * The value in byte 8 determines whether we interpret this as + * describing aspects of a copper device or if it describes the + * wavelength. + */ + if (buf[SFF_8472_COMPLIANCE_SFP] & SFF_8472_COMP_CABLE_PASSIVE) { + return (sff_gather_bitfield(buf[SFF_8472_PASSIVE_SPEC] & + SFF_8472_PCABLE_COMP_MASK, LIBSFF_KEY_COMPLIANCE_PASSIVE, + sff_8472_pcable_comp, nvl)); + } else if (buf[SFF_8472_COMPLIANCE_SFP] & SFF_8472_COMP_CABLE_ACTIVE) { + return (sff_gather_bitfield(buf[SFF_8472_ACTIVE_SPEC] & + SFF_8472_ACABLE_COMP_MASK, LIBSFF_KEY_COMPLIANCE_ACTIVE, + sff_8472_acable_comp, nvl)); + + } else { + uint16_t val = (buf[SFF_8472_WAVELENGTH_HI] << 8) | + buf[SFF_8472_WAVELENGTH_LOW]; + + return (sff_add_unit_string(val, SFF_8472_WAVELENGTH_FACTOR, + "nm", nvl, LIBSFF_KEY_WAVELENGTH)); + } +} + +static int +sff_parse_options(const uint8_t *buf, nvlist_t *nvl) +{ + uint16_t val; + + val = (buf[SFF_8472_OPTIONS_HI] << 8) | buf[SFF_8472_OPTIONS_LOW]; + return (sff_gather_bitfield(val & SFF_8472_OPTION_MASK, + LIBSFF_KEY_OPTIONS, sff_8472_options, nvl)); +} + +static int +sff_parse_8472_comp(uint8_t val, nvlist_t *nvl) +{ + const char *str; + + if (val >= SFF_8472_8472_COMP_NENTRIES) { + str = "Unallocated"; + } else { + str = sff_8472_8472_comp[val]; + } + + return (nvlist_add_string(nvl, LIBSFF_KEY_COMPLIANCE_8472, str)); +} + +/* + * Parse an SFP that is either based on INF 8074 or SFF 8472. These are GBIC, + * SFP, SFP+, and SFP28 based devices. + * + * The SFP parsing into an nvlist_t is incomplete. At the moment we're not + * parsing the following pieces from SFF 8472 page 0xa0: + * + * o Rate Selection Logic + * o Diagnostic Monitoring Type + */ +static int +sff_parse_sfp(const uint8_t *buf, nvlist_t *nvl) +{ + int ret; + + if ((ret = sff_parse_id(buf[SFF_8472_IDENTIFIER], nvl)) != 0) + return (ret); + + /* + * The extended identifier is derived from SFF 8472, Table 5-2. It + * generally is just the value 4. The other values are not well defined. + */ + if ((ret = nvlist_add_uint8(nvl, LIBSFF_KEY_8472_EXT_IDENTIFIER, + buf[SFF_8472_EXT_IDENTIFER])) != 0) + return (ret); + + if ((ret = sff_parse_connector(buf[SFF_8472_CONNECTOR], nvl)) != 0) + return (ret); + + if ((ret = sff_parse_compliance(buf, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_encoding(buf[SFF_8472_ENCODING], nvl, + B_TRUE)) != 0) + return (ret); + + if ((ret = sff_parse_br(buf, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_lengths(buf, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_string(buf, SFF_8472_VENDOR, SFF_8472_VENDOR_LEN, + LIBSFF_KEY_VENDOR, nvl)) != 0) + return (ret); + + if ((ret = nvlist_add_byte_array(nvl, LIBSFF_KEY_OUI, + (uchar_t *)&buf[SFF_8472_OUI], SFF_8472_OUI_LEN)) != 0) + return (ret); + + if ((ret = sff_parse_string(buf, SFF_8472_VENDOR_PN, + SFF_8472_VENDOR_PN_LEN, LIBSFF_KEY_PART, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_string(buf, SFF_8472_VENDOR_REV, + SFF_8472_VENDOR_REV_LEN, LIBSFF_KEY_REVISION, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_optical(buf, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_options(buf, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_string(buf, SFF_8472_VENDOR_SN, + SFF_8472_VENDOR_SN_LEN, LIBSFF_KEY_SERIAL, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_string(buf, SFF_8472_DATE_CODE, + SFF_8472_DATE_CODE_LEN, LIBSFF_KEY_DATECODE, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8472_ENHANCED_OPTIONS] & + SFF_8472_EXTOPT_MASK, LIBSFF_KEY_EXTENDED_OPTIONS, + sff_8472_extopts, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_8472_comp(buf[SFF_8472_SFF_8472_COMPLIANCE], + nvl)) != 0) + return (ret); + + return (0); +} + +static int +sff_qsfp_parse_compliance(const uint8_t *buf, nvlist_t *nvl) +{ + int ret; + uint16_t fc_val; + + if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_10GBEP] & + SFF_8636_COMP_10GETH_MASK, LIBSFF_KEY_COMPLIANCE_10GBE, + sff_8636_comp_10geth, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_SONET] & + SFF_8636_COMP_SONET_MASK, LIBSFF_KEY_COMPLIANCE_SONET, + sff_8636_comp_sonet, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_SAS] & + SFF_8636_COMP_SAS_MASK, LIBSFF_KEY_COMPLIANCE_SAS, + sff_8636_comp_sas, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_ETHERNET] & + SFF_8636_COMP_ETH_MASK, LIBSFF_KEY_COMPLIANCE_GBE, + sff_8636_comp_eth, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_FCLEN] & + SFF_8636_COMP_FCLEN_MASK, LIBSFF_KEY_COMPLIANCE_FC_LEN, + sff_8636_comp_fclen, nvl)) != 0) + return (ret); + + fc_val = buf[SFF_8636_COMPLIANCE_FC_LOW] | + (buf[SFF_8636_COMPLIANCE_FC_HIGH] << 8); + if ((ret = sff_gather_bitfield(fc_val & SFF_8636_COMP_TECH_MASK, + LIBSFF_KEY_COMPLIANCE_FC_TECH, sff_8636_comp_tech, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_FC_MEDIA] & + SFF_8636_COMP_MEDIA_MASK, LIBSFF_KEY_COMPLIANCE_FC_MEDIA, + sff_8636_comp_media, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_FC_SPEED] & + SFF_8636_COMP_SPEED_MASK, LIBSFF_KEY_COMPLIANCE_FC_SPEED, + sff_8636_comp_speed, nvl)) != 0) + return (ret); + + return (0); +} + +static int +sff_qsfp_parse_br(const uint8_t *buf, nvlist_t *nvl) +{ + if (buf[SFF_8636_BR_NOMINAL] == 0xff) { + return (sff_add_unit_string(buf[SFF_8636_BR_NOMINAL_EXT], + SFF_8636_BR_NOMINAL_EXT_FACTOR, "Mbps", nvl, + LIBSFF_KEY_BR_NOMINAL)); + } else { + return (sff_add_unit_string(buf[SFF_8636_BR_NOMINAL], + SFF_8636_BR_NOMINAL_FACTOR, "Mbps", nvl, + LIBSFF_KEY_BR_NOMINAL)); + } +} + +static int +sff_qsfp_parse_lengths(const uint8_t *buf, nvlist_t *nvl) +{ + int ret; + + if (buf[SFF_8636_LENGTH_SMF] != 0) { + if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_SMF], + SFF_8636_LENGTH_SMF_FACTOR, "km", nvl, + LIBSFF_KEY_LENGTH_SMF_KM)) != 0) + return (ret); + } + + if (buf[SFF_8636_LENGTH_OM3] != 0) { + if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_OM3], + SFF_8636_LENGTH_OM3_FACTOR, "m", nvl, + LIBSFF_KEY_LENGTH_OM3)) != 0) + return (ret); + } + + if (buf[SFF_8636_LENGTH_OM2] != 0) { + if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_OM2], + SFF_8636_LENGTH_OM2_FACTOR, "m", nvl, + LIBSFF_KEY_LENGTH_OM2)) != 0) + return (ret); + } + + if (buf[SFF_8636_LENGTH_OM1] != 0) { + if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_OM1], + SFF_8636_LENGTH_OM1_FACTOR, "m", nvl, + LIBSFF_KEY_LENGTH_OM1)) != 0) + return (ret); + } + + if (buf[SFF_8636_LENGTH_COPPER] != 0) { + if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_COPPER], + SFF_8636_LENGTH_COPPER_FACTOR, "m", nvl, + LIBSFF_KEY_LENGTH_COPPER)) != 0) + return (ret); + } + + return (0); +} + +static int +sff_qsfp_parse_tech(uint8_t val, nvlist_t *nvl) +{ + const char *strs[5]; + + strs[0] = sff_8636_trans_tech[(val & 0xf0) >> 4]; + if (val & 0x08) { + strs[1] = "Active Wavelength Control"; + } else { + strs[1] = "No Wavelength Control"; + } + + if (val & 0x04) { + strs[2] = "Cooled Transmitter"; + } else { + strs[2] = "Uncooled Transmitter"; + } + + if (val & 0x02) { + strs[3] = "APD Detector"; + } else { + strs[3] = "Pin Detector"; + } + + if (val & 0x01) { + strs[4] = "Transmitter Tunable"; + } else { + strs[4] = "Transmitter Not Tunable"; + } + + /* + * The nvlist routines don't touch the array, so we end up lying about + * the type of data so that we can avoid a rash of additional + * allocations and strdups. + */ + return (nvlist_add_string_array(nvl, LIBSFF_KEY_TRAN_TECH, + (char **)strs, 5)); +} + +static int +sff_qsfp_parse_copperwave(const uint8_t *buf, nvlist_t *nvl) +{ + int ret; + + /* + * The values that we get depend on whether or not we are a copper + * device or not. We can determine this based on the identification + * information in the device technology field. + */ + if ((buf[SFF_8636_DEVICE_TECH] & 0xf0) >= 0xa0) { + if ((ret = sff_add_unit_string(buf[SFF_8636_ATTENUATE_2G], 1, + "dB", nvl, LIBSFF_KEY_ATTENUATE_2G)) != 0) + return (ret); + if ((ret = sff_add_unit_string(buf[SFF_8636_ATTENUATE_5G], 1, + "dB", nvl, LIBSFF_KEY_ATTENUATE_5G)) != 0) + return (ret); + if ((ret = sff_add_unit_string(buf[SFF_8636_ATTENUATE_7G], 1, + "dB", nvl, LIBSFF_KEY_ATTENUATE_7G)) != 0) + return (ret); + if ((ret = sff_add_unit_string(buf[SFF_8636_ATTENUATE_12G], 1, + "dB", nvl, LIBSFF_KEY_ATTENUATE_12G)) != 0) + return (ret); + } else { + uint16_t val; + double d; + char strbuf[SFP_STRBUF]; + + /* + * Because we need to divide the units here into doubles, we + * can't use the standard unit routine. + */ + val = (buf[SFF_8636_WAVELENGTH_NOMINAL_HI] << 8) | + buf[SFF_8636_WAVELENGTH_NOMINAL_LOW]; + if (val != 0) { + d = val / 20.0; + (void) snprintf(strbuf, sizeof (strbuf), "%.3lf nm", d); + if ((ret = nvlist_add_string(nvl, LIBSFF_KEY_WAVELENGTH, + strbuf)) != 0) + return (ret); + } + + val = (buf[SFF_8636_WAVELENGTH_TOLERANCE_HI] << 8) | + buf[SFF_8636_WAVELENGTH_TOLERANCE_LOW]; + if (val != 0) { + d = val / 20.0; + (void) snprintf(strbuf, sizeof (strbuf), "%.3lf nm", d); + if ((ret = nvlist_add_string(nvl, + LIBSFF_KEY_WAVE_TOLERANCE, strbuf)) != 0) + return (ret); + } + } + + return (0); +} + +static int +sff_qsfp_parse_casetemp(uint8_t val, nvlist_t *nvl) +{ + /* + * The default temperature per SFF 8636 r2.7 6.3.21 'Maximum Case + * Temperature' is 70 C. If the value is zero, we're supposed to assume + * it's the default. + */ + if (val == 0) + val = 70; + + return (sff_add_unit_string(val, 1, "C", nvl, + LIBSFF_KEY_MAX_CASE_TEMP)); +} + +static int +sff_qsfp_parse_extcomp(uint8_t val, nvlist_t *nvl) +{ + const char *str; + + if (val >= SFF_8024_EXT_SPEC_NENTRIES) { + str = "Reserved"; + } else { + str = sff_8024_ext_spec[val]; + } + + return (nvlist_add_string(nvl, LIBSFF_KEY_EXT_SPEC, str)); +} + +static int +sff_qsfp_parse_options(const uint8_t *buf, nvlist_t *nvl) +{ + uint_t val; + + val = (buf[SFF_8636_OPTIONS_HI] << 16) | + (buf[SFF_8636_OPTIONS_MID] << 8) | buf[SFF_8636_OPTIONS_LOW]; + + return (sff_gather_bitfield(val & SFF_8636_OPTION_MASK, + LIBSFF_KEY_OPTIONS, sff_8636_options, nvl)); +} + +static int +sff_qsfp_parse_diag(uint8_t val, nvlist_t *nvl) +{ + const char *buf[2]; + uint_t count = 1; + + if (val & 0x08) { + buf[0] = "Received power measurements: Average Power"; + } else { + buf[0] = "Received power measurements: OMA"; + } + + if (val & 0x04) { + count++; + buf[1] = "Transmitter power measurement"; + } + + /* + * The nvlist routines don't touch the array, so we end up lying about + * the type of data so that we can avoid a rash of additional + * allocations and strdups. + */ + return (nvlist_add_string_array(nvl, LIBSFF_KEY_DIAG_MONITOR, + (char **)buf, count)); +} + +/* + * Parse a QSFP family device that is based on SFF-8436 / SFF-8636. Note that we + * ignore the lower half of page 0xa0 at this time and instead focus on the + * upper half of page 0xa0 which has identification information. + * + * For the moment we're not parsing the following fields: + * + * o Extended Identifier (byte 129) + * o Extended Rate Select Compliance (byte 141) + */ +static int +sff_parse_qsfp(const uint8_t *buf, nvlist_t *nvl) +{ + int ret; + + if ((ret = sff_parse_id(buf[SFF_8636_IDENTIFIER], nvl)) != 0) + return (ret); + + if ((ret = sff_parse_connector(buf[SFF_8636_CONNECTOR], nvl)) != 0) + return (ret); + + if ((ret = sff_qsfp_parse_compliance(buf, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_encoding(buf[SFF_8636_ENCODING], nvl, + B_FALSE)) != 0) + return (ret); + + if ((ret = sff_qsfp_parse_br(buf, nvl)) != 0) + return (ret); + + if ((ret = sff_qsfp_parse_lengths(buf, nvl)) != 0) + return (ret); + + if ((ret = sff_qsfp_parse_tech(buf[SFF_8636_DEVICE_TECH], nvl)) != 0) + return (ret); + + if ((ret = sff_parse_string(buf, SFF_8636_VENDOR, SFF_8636_VENDOR_LEN, + LIBSFF_KEY_VENDOR, nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8636_EXTENDED_MODULE] & + SFF_8636_EXTMOD_CODES, LIBSFF_KEY_EXT_MOD_CODES, + sff_8636_extmod_codes, nvl)) != 0) + return (ret); + + if ((ret = nvlist_add_byte_array(nvl, LIBSFF_KEY_OUI, + (uchar_t *)&buf[SFF_8636_OUI], SFF_8636_OUI_LEN)) != 0) + return (ret); + + if ((ret = sff_parse_string(buf, SFF_8636_VENDOR_PN, + SFF_8636_VENDOR_PN_LEN, LIBSFF_KEY_PART, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_string(buf, SFF_8636_VENDOR_REV, + SFF_8636_VENDOR_REV_LEN, LIBSFF_KEY_REVISION, nvl)) != 0) + return (ret); + + if ((ret = sff_qsfp_parse_copperwave(buf, nvl)) != 0) + return (ret); + + if ((ret = sff_qsfp_parse_casetemp(buf[SFF_8636_MAX_CASE_TEMP], + nvl)) != 0) + return (ret); + + if ((ret = sff_qsfp_parse_extcomp(buf[SFF_8636_LINK_CODES], nvl)) != 0) + return (ret); + + if ((ret = sff_qsfp_parse_options(buf, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_string(buf, SFF_8636_VENDOR_SN, + SFF_8636_VENDOR_SN_LEN, LIBSFF_KEY_SERIAL, nvl)) != 0) + return (ret); + + if ((ret = sff_parse_string(buf, SFF_8636_DATE_CODE, + SFF_8636_DATE_CODE_LEN, LIBSFF_KEY_DATECODE, nvl)) != 0) + return (ret); + + if ((ret = sff_qsfp_parse_diag(buf[SFF_8636_DIAG_MONITORING], + nvl)) != 0) + return (ret); + + if ((ret = sff_gather_bitfield(buf[SFF_8636_ENHANCED_OPTIONS] & + SFF_8636_ENHANCED_OPTIONS_MASK, LIBSFF_KEY_ENHANCED_OPTIONS, + sff_8636_eopt, nvl)) != 0) + return (ret); + + return (0); +} + +int +libsff_parse(const uint8_t *buf, size_t len, uint_t page, nvlist_t **nvpp) +{ + int ret; + nvlist_t *nvp = NULL; + uint8_t ubuf[256]; + + /* + * At the moment, we only support page a0. + */ + if (page != 0xa0 || buf == NULL || len == 0 || nvpp == NULL) + return (EINVAL); + + *nvpp = NULL; + + /* + * Make sure that the library has been given valid data to parse. + */ + if (uucopy(buf, ubuf, MIN(sizeof (ubuf), len)) != 0) + return (errno); + + if ((ret = nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0)) != 0) + return (ret); + + switch (buf[0]) { + case SFF_8024_ID_QSFP: + case SFF_8024_ID_QSFP_PLUS: + case SFF_8024_ID_QSFP28: + /* + * For QSFP based products, identification information is spread + * across both the top and bottom half of page 0xa0. + */ + if (len < SFP_MIN_LEN_8636) { + ret = EINVAL; + break; + } + ret = sff_parse_qsfp(ubuf, nvp); + break; + default: + if (len < SFP_MIN_LEN_8472) { + ret = EINVAL; + break; + } + ret = sff_parse_sfp(ubuf, nvp); + break; + } + + if (ret != 0) { + nvlist_free(nvp); + } else { + *nvpp = nvp; + } + return (ret); +} diff --git a/usr/src/lib/libsff/common/libsff.h b/usr/src/lib/libsff/common/libsff.h new file mode 100644 index 0000000000..04812e478f --- /dev/null +++ b/usr/src/lib/libsff/common/libsff.h @@ -0,0 +1,101 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +#ifndef _LIBSFF_H +#define _LIBSFF_H + +/* + * Parse SFF structures and values and return an nvlist_t of keys. This library + * is private and subject to change and break compat at any time. + */ + +#include <libnvpair.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern int libsff_parse(const uint8_t *, size_t, uint_t, nvlist_t **); + +/* + * Supported Keys in the resulting nvlist. Not every key will be present in + * every SFF compatible device. + */ +#define LIBSFF_KEY_IDENTIFIER "Identifier" /* String */ +#define LIBSFF_KEY_CONNECTOR "Connector" /* String */ +#define LIBSFF_KEY_ENCODING "Encoding" /* String */ +#define LIBSFF_KEY_VENDOR "Vendor" /* String */ +#define LIBSFF_KEY_OUI "OUI" /* Byte Array [3] */ +#define LIBSFF_KEY_PART "Part Number" /* String */ +#define LIBSFF_KEY_REVISION "Revision" /* String */ +#define LIBSFF_KEY_SERIAL "Serial Number" /* String */ +#define LIBSFF_KEY_DATECODE "Date Code" /* String */ +#define LIBSFF_KEY_BR_NOMINAL "BR, nominal" /* String */ +#define LIBSFF_KEY_BR_MAX "BR, maximum" /* String */ +#define LIBSFF_KEY_BR_MIN "BR, minimum" /* String */ +#define LIBSFF_KEY_LENGTH_SMF_KM "Length SMF (km)" /* String */ +#define LIBSFF_KEY_LENGTH_SMF "Length SMF (m)" /* String */ +#define LIBSFF_KEY_LENGTH_OM2 "Length 50um OM2" /* String */ +#define LIBSFF_KEY_LENGTH_OM1 "Length 62.5um OM1" /* String */ +#define LIBSFF_KEY_LENGTH_COPPER "Length Copper" /* String */ +#define LIBSFF_KEY_LENGTH_OM3 "Length OM3" /* String */ +#define LIBSFF_KEY_WAVELENGTH "Laser Wavelength" /* String */ +#define LIBSFF_KEY_WAVE_TOLERANCE "Wavelength Tolerance" /* String */ +#define LIBSFF_KEY_OPTIONS "Options" /* String Array */ +#define LIBSFF_KEY_COMPLIANCE_8472 "8472 Compliance" /* String */ +#define LIBSFF_KEY_EXTENDED_OPTIONS "Extended Options" /* String Array */ +#define LIBSFF_KEY_ENHANCED_OPTIONS "Enhanced Options" /* String Array */ +#define LIBSFF_KEY_EXT_MOD_CODES "Extended Module Codes" /* String Array */ +#define LIBSFF_KEY_DIAG_MONITOR "Diagnostic Monitoring" /* String */ +#define LIBSFF_KEY_EXT_SPEC "Extended Specification" /* String */ +#define LIBSFF_KEY_MAX_CASE_TEMP "Maximum Case Temperature" /* String */ +#define LIBSFF_KEY_ATTENUATE_2G "Cable Attenuation at 2.5 GHz" /* String */ +#define LIBSFF_KEY_ATTENUATE_5G "Cable Attenuation at 5.0 GHz" /* String */ +#define LIBSFF_KEY_ATTENUATE_7G "Cable Attenuation at 7.0 GHz" /* String */ +#define LIBSFF_KEY_ATTENUATE_12G "Cable Attenuation at 12.9 GHz" /* String */ +#define LIBSFF_KEY_TRAN_TECH "Transmitter Technology" /* String */ + +/* + * Note, different revisions of the SFF standard have different compliance + * values available. We try to use a common set of compliance keys when + * possible, even if the values will be different. All entries here are String + * Arrays. + */ +#define LIBSFF_KEY_COMPLIANCE_10GBE "10G+ Ethernet Compliance Codes" +#define LIBSFF_KEY_COMPLIANCE_IB "Infiniband Compliance Codes" +#define LIBSFF_KEY_COMPLIANCE_ESCON "ESCON Compliance Codes" +#define LIBSFF_KEY_COMPLIANCE_SONET "SONET Compliance Codes" +#define LIBSFF_KEY_COMPLIANCE_GBE "Ethernet Compliance Codes" +#define LIBSFF_KEY_COMPLIANCE_FC_LEN "Fibre Channel Link Lengths" +#define LIBSFF_KEY_COMPLIANCE_FC_TECH "Fibre Channel Technology" +#define LIBSFF_KEY_COMPLIANCE_SFP "SFP+ Cable Technology" +#define LIBSFF_KEY_COMPLIANCE_FC_MEDIA "Fibre Channel Transmission Media" +#define LIBSFF_KEY_COMPLIANCE_FC_SPEED "Fibre Channel Speed" +#define LIBSFF_KEY_COMPLIANCE_SAS "SAS Compliance Codes" +#define LIBSFF_KEY_COMPLIANCE_ACTIVE "Active Cable Specification Compliance" +#define LIBSFF_KEY_COMPLIANCE_PASSIVE "Passive Cable Specification Compliance" + + +/* + * The following keys have meaning that varies based on the standard. + */ +#define LIBSFF_KEY_8472_EXT_IDENTIFIER "Extended Identifier" /* uint8_t */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBSFF_H */ diff --git a/usr/src/lib/libsff/common/llib-lsff b/usr/src/lib/libsff/common/llib-lsff new file mode 100644 index 0000000000..1636a7e1b0 --- /dev/null +++ b/usr/src/lib/libsff/common/llib-lsff @@ -0,0 +1,19 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017 Joyent, Inc. + */ + +/* LINTLIBRARY */ +/* PROTOLIB1 */ + +#include <libsfp.h> diff --git a/usr/src/lib/libsff/common/mapfile-vers b/usr/src/lib/libsff/common/mapfile-vers new file mode 100644 index 0000000000..7e48256f37 --- /dev/null +++ b/usr/src/lib/libsff/common/mapfile-vers @@ -0,0 +1,37 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2017, Joyent, Inc. +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object versioning must comply with the rules detailed in +# +# usr/src/lib/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +$mapfile_version 2 + +SYMBOL_VERSION SUNWprivate { + global: + libsff_parse; + local: + *; +}; diff --git a/usr/src/lib/libsff/common/sff.h b/usr/src/lib/libsff/common/sff.h new file mode 100644 index 0000000000..d3b64e7fba --- /dev/null +++ b/usr/src/lib/libsff/common/sff.h @@ -0,0 +1,221 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +#ifndef _SFF_H +#define _SFF_H + +/* + * Definitions internal to libsfp for various SFF versions. This generally + * contains offsets for each byte and its purpose. The meaning of the values are + * not generally found in this header. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This table is derived from SFF 8024 Section 4.1, Table 4-1. + */ +typedef enum sff_8024_id { + SFF_8024_ID_UNKNOWN = 0x00, + SFF_8024_ID_GBIC = 0x01, + SFF_8024_ID_SOLDERED = 0x02, + SFF_8024_ID_SFP = 0x03, /* SFP, SFP+, SFP28 */ + SFF_8024_ID_XBI = 0x04, + SFF_8024_ID_XENPAK = 0x05, + SFF_8024_ID_XFP = 0x06, + SFF_8024_ID_XFF = 0x07, + SFF_8024_ID_XFP_E = 0x08, + SFF_8024_ID_XPAK = 0x09, + SFF_8024_ID_X2 = 0x0A, + SFF_8024_ID_DWDM_SFP = 0x0B, + SFF_8024_ID_QSFP = 0x0C, + SFF_8024_ID_QSFP_PLUS = 0x0D, + SFF_8024_ID_CXP = 0x0E, + SFF_8024_ID_SMMHD4X = 0x0F, + SFF_8024_ID_SMMHD8X = 0x10, + SFF_8024_ID_QSFP28 = 0x11, + SFF_8024_ID_CXP2 = 0x12, + SFF_8024_ID_CDFP = 0x13, + SFF_8024_ID_SMMHD4XF = 0x14, + SFF_8024_ID_SMMHD8XF = 0x15, + SFF_8024_ID_CDFP3 = 0x16, + SFF_8024_ID_MICROQSFP = 0x17, + SFF_8024_NIDS = 0x18, + SFF_8024_VENDOR = 0x80 +} sff_8024_id_t; + + +/* + * Byte offsets for SFF-8472. Note that most of this applies to INF-8074. + * Generally speaking, SFF-8472 is a backwards compatible evolution of INF-8074. + */ +#define SFF_8472_IDENTIFIER 0 +#define SFF_8472_EXT_IDENTIFER 1 +#define SFF_8472_CONNECTOR 2 + +/* + * Note that several constants overlap here as the offset is used for multiple + * purposes. + */ +#define SFF_8472_COMPLIANCE_10GE 3 +#define SFF_8472_COMPLIANCE_IB 3 +#define SFF_8472_COMPLIANCE_ESCON 4 +#define SFF_8472_COMPLIANCE_SONET_LOW 4 +#define SFF_8472_COMPLIANCE_SONET_HIGH 5 +#define SFF_8472_COMPLIANCE_ETHERNET 6 +#define SFF_8472_COMPLIANCE_FCLEN 7 +#define SFF_8472_COMPLIANCE_FC_LOW 7 +#define SFF_8472_COMPLIANCE_FC_HIGH 8 +#define SFF_8472_COMPLIANCE_SFP 8 +#define SFF_8472_COMPLIANCE_FC_MEDIA 9 +#define SFF_8472_COMPLIANCE_FC_SPEED 10 + +#define SFF_8472_ENCODING 11 +#define SFF_8472_BR_NOMINAL 12 +#define SFF_8472_RATE_IDENTIFIER 13 +#define SFF_8472_LENGTH_SMF_KM 14 +#define SFF_8472_LENGTH_SMF 15 +#define SFF_8472_LENGTH_50UM 16 +#define SFF_8472_LENGTH_62UM 17 +#define SFF_8472_LENGTH_COPPER 18 +#define SFF_8472_LENGTH_OM3 19 + +#define SFF_8472_VENDOR 20 +#define SFF_8472_VENDOR_LEN 16 +#define SFF_8472_TRANSCEIVER 36 +#define SFF_8472_OUI 37 +#define SFF_8472_OUI_LEN 3 +#define SFF_8472_VENDOR_PN 40 +#define SFF_8472_VENDOR_PN_LEN 16 +#define SFF_8472_VENDOR_REV 56 +#define SFF_8472_VENDOR_REV_LEN 4 + +#define SFF_8472_PASSIVE_SPEC 60 +#define SFF_8472_ACTIVE_SPEC 60 +#define SFF_8472_WAVELENGTH_HI 60 +#define SFF_8472_WAVELENGTH_LOW 61 + +#define SFF_8472_CC_BASE 63 + +#define SFF_8472_OPTIONS_HI 64 +#define SFF_8472_OPTIONS_LOW 65 +#define SFF_8472_BR_MAX 66 +#define SFF_8472_BR_MIN 67 +#define SFF_8472_VENDOR_SN 68 +#define SFF_8472_VENDOR_SN_LEN 16 +#define SFF_8472_DATE_CODE 84 +#define SFF_8472_DATE_CODE_LEN 8 +#define SFF_8472_DIAG_MONITORING 92 +#define SFF_8472_ENHANCED_OPTIONS 93 +#define SFF_8472_SFF_8472_COMPLIANCE 94 + +#define SFF_8472_CC_EXT 95 +#define SFF_8472_VENDOR_SPECIFIC 96 +#define SFF_8472_RESERVED 128 + +/* + * These values are factors by which we should multiple or divide various units. + */ +#define SFF_8472_BR_NOMINAL_FACTOR 100 +#define SFF_8472_BR_MAX_FACTOR 250 +#define SFF_8472_BR_MIN_FACTOR 250 +#define SFF_8472_LENGTH_SMF_KM_FACTOR 1 +#define SFF_8472_LENGTH_SMF_FACTOR 100 +#define SFF_8472_LENGTH_50UM_FACTOR 10 +#define SFF_8472_LENGTH_62UM_FACTOR 10 +#define SFF_8472_LENGTH_COPPER_FACTOR 1 +#define SFF_8472_LENGTH_OM3_FACTOR 10 +#define SFF_8472_WAVELENGTH_FACTOR 1 + + +/* + * SFF 8636 related constants + */ +#define SFF_8636_IDENTIFIER 0 +#define SFF_8636_EXT_IDENTIFIER 129 +#define SFF_8636_CONNECTOR 130 + +#define SFF_8636_COMPLIANCE_10GBEP 131 +#define SFF_8636_COMPLIANCE_SONET 132 +#define SFF_8636_COMPLIANCE_SAS 133 +#define SFF_8636_COMPLIANCE_ETHERNET 134 +#define SFF_8636_COMPLIANCE_FCLEN 135 +#define SFF_8636_COMPLIANCE_FC_LOW 135 +#define SFF_8636_COMPLIANCE_FC_HIGH 136 +#define SFF_8636_COMPLIANCE_FC_MEDIA 137 +#define SFF_8636_COMPLIANCE_FC_SPEED 138 + +#define SFF_8636_ENCODING 139 +#define SFF_8636_BR_NOMINAL 140 +#define SFF_8636_BR_EXT_RATE_SELECT 141 +#define SFF_8636_LENGTH_SMF 142 +#define SFF_8636_LENGTH_OM3 143 +#define SFF_8636_LENGTH_OM2 144 +#define SFF_8636_LENGTH_OM1 145 +#define SFF_8636_LENGTH_COPPER 146 +#define SFF_8636_DEVICE_TECH 147 +#define SFF_8636_VENDOR 148 +#define SFF_8636_VENDOR_LEN 16 +#define SFF_8636_EXTENDED_MODULE 164 +#define SFF_8636_OUI 165 +#define SFF_8636_OUI_LEN 3 +#define SFF_8636_VENDOR_PN 168 +#define SFF_8636_VENDOR_PN_LEN 16 +#define SFF_8636_VENDOR_REV 184 +#define SFF_8636_VENDOR_REV_LEN 2 + +#define SFF_8636_ATTENUATE_2G 186 +#define SFF_8636_ATTENUATE_5G 187 +#define SFF_8636_ATTENUATE_7G 188 +#define SFF_8636_ATTENUATE_12G 189 +#define SFF_8636_WAVELENGTH_NOMINAL_HI 186 +#define SFF_8636_WAVELENGTH_NOMINAL_LOW 187 +#define SFF_8636_WAVELENGTH_TOLERANCE_HI 188 +#define SFF_8636_WAVELENGTH_TOLERANCE_LOW 189 +#define SFF_8636_MAX_CASE_TEMP 190 +#define SFF_8636_CC_BASE 191 + +#define SFF_8636_LINK_CODES 192 +#define SFF_8636_OPTIONS_HI 193 +#define SFF_8636_OPTIONS_MID 194 +#define SFF_8636_OPTIONS_LOW 195 +#define SFF_8636_VENDOR_SN 196 +#define SFF_8636_VENDOR_SN_LEN 16 +#define SFF_8636_DATE_CODE 212 +#define SFF_8636_DATE_CODE_LEN 8 +#define SFF_8636_DIAG_MONITORING 220 +#define SFF_8636_ENHANCED_OPTIONS 221 +#define SFF_8636_BR_NOMINAL_EXT 222 +#define SFF_8636_CC_EXT 223 +#define SFF_866_VENDOR_SPECIFIC 224 + +/* + * SFF 8636 multiplication factors + */ +#define SFF_8636_BR_NOMINAL_FACTOR 100 +#define SFF_8636_BR_NOMINAL_EXT_FACTOR 250 +#define SFF_8636_LENGTH_SMF_FACTOR 1 +#define SFF_8636_LENGTH_OM3_FACTOR 2 +#define SFF_8636_LENGTH_OM2_FACTOR 1 +#define SFF_8636_LENGTH_OM1_FACTOR 1 +#define SFF_8636_LENGTH_COPPER_FACTOR 1 + +#ifdef __cplusplus +} +#endif + +#endif /* _SFF_H */ diff --git a/usr/src/lib/libsff/i386/Makefile b/usr/src/lib/libsff/i386/Makefile new file mode 100644 index 0000000000..0a22fa4dc3 --- /dev/null +++ b/usr/src/lib/libsff/i386/Makefile @@ -0,0 +1,18 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2017 Joyent, Inc. +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libsff/sparc/Makefile b/usr/src/lib/libsff/sparc/Makefile new file mode 100644 index 0000000000..0a22fa4dc3 --- /dev/null +++ b/usr/src/lib/libsff/sparc/Makefile @@ -0,0 +1,18 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2017 Joyent, Inc. +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/test/util-tests/runfiles/default.run b/usr/src/test/util-tests/runfiles/default.run index 800bd21c91..e40b486a85 100644 --- a/usr/src/test/util-tests/runfiles/default.run +++ b/usr/src/test/util-tests/runfiles/default.run @@ -28,6 +28,7 @@ outputdir = /var/tmp/test_results [/opt/util-tests/tests/show-overlay-exit] [/opt/util-tests/tests/vnic-mtu] [/opt/util-tests/tests/bunyan/bunyan] +[/opt/util-tests/tests/libsff/libsff] [/opt/util-tests/tests/xargs_test] diff --git a/usr/src/test/util-tests/tests/Makefile b/usr/src/test/util-tests/tests/Makefile index 4ada2a9b4c..f4b7b90daf 100644 --- a/usr/src/test/util-tests/tests/Makefile +++ b/usr/src/test/util-tests/tests/Makefile @@ -14,6 +14,6 @@ # Copyright 2014 Garrett D'Amore <garrett@damore.org> # -SUBDIRS = dis dladm iconv libnvpair_json printf xargs bunyan mergeq workq +SUBDIRS = dis dladm iconv libnvpair_json libsff printf xargs bunyan mergeq workq include $(SRC)/test/Makefile.com diff --git a/usr/src/test/util-tests/tests/libsff/Makefile b/usr/src/test/util-tests/tests/libsff/Makefile new file mode 100644 index 0000000000..a4134ae739 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/Makefile @@ -0,0 +1,81 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2017, Joyent, Inc. +# + +include $(SRC)/Makefile.master + +ROOTOPTPKG = $(ROOT)/opt/util-tests +TESTDIR = $(ROOTOPTPKG)/tests/libsff + +DIFF_PROGS = \ + libsff_8472 \ + libsff_8636_diag \ + libsff_8636_extspec \ + libsff_8636_tech \ + libsff_8636_temp \ + libsff_br \ + libsff_conn \ + libsff_compliance \ + libsff_enc \ + libsff_ident \ + libsff_lengths \ + libsff_opts \ + libsff_wave + +PROGS = $(DIFF_PROGS) \ + libsff_efault \ + libsff_einval \ + libsff_strings + +SCRIPTS = libsff + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/cmd/Makefile.ctf +include $(SRC)/test/Makefile.com + +CMDS = $(PROGS:%=$(TESTDIR)/%) $(SCRIPTS:%=$(TESTDIR)/%) +OUTFILES = $(DIFF_PROGS:%=$(TESTDIR)/%.out) +$(CMDS) := FILEMODE = 0555 +$(OUTFILES) := FILEMODE = 0444 + +CPPFLAGS += -I$(SRC)/lib/libsff/common +LDLIBS += -lsff -lnvpair + +all: $(PROGS) + +install: all $(CMDS) $(OUTFILES) + +lint: lint_SRCS + +clobber: clean + -$(RM) $(PROGS) + +clean: + +$(CMDS): $(TESTDIR) $(PROG) + +$(TESTDIR): + $(INS.dir) + +$(TESTDIR)/%: % + $(INS.file) + +$(TESTDIR)/%: %.ksh + $(INS.rename) + +%: %.c + $(LINK.c) -o $@ $< $(LDLIBS) + $(POST_PROCESS_O) + + diff --git a/usr/src/test/util-tests/tests/libsff/libsff.ksh b/usr/src/test/util-tests/tests/libsff/libsff.ksh new file mode 100644 index 0000000000..d9974bc10c --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff.ksh @@ -0,0 +1,61 @@ +#! /usr/bin/ksh +# +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2017, Joyent, Inc. +# + +# +# Run all of the various libsff tests. +# + +unalias -a +sff_arg0=$(basename $0) +sff_origwd= +sff_root= +sff_tests="8472 br compliance conn enc ident lengths opts strings wave" +sff_tests="$sff_tests 8636_diag 8636_extspec 8636_tech 8636_temp einval efault" +sff_outfile="/tmp/$sff_arg0.out.$$" + +fatal() +{ + typeset msg="$*" + [[ -z "$msg" ]] && msg="failed" + echo "TEST FAILED: $sff_arg0: $msg" >&2 + rm -f $sff_outfile + exit 1 +} + +sff_origwd=$PWD +cd $(dirname $0) || fatal "failed to cd to test root" +sff_root=$PWD +cd $dt_origwd || fatal "failed to return to original dir" + +for t in $sff_tests; do + difffile= + testfile=$sff_root/libsff_$t + + if ! $testfile > $sff_outfile; then + fatal "failed to run $testfile" + fi + + if [[ -f $testfile.out ]]; then + if ! diff $testfile.out $sff_outfile >/dev/null; then + fatal "$t results differ from expected values" + fi + fi + printf "TEST PASSED: libsff_%s\n" $t +done + +rm -f $sff_outfile || fatal "failed to remove output file" +exit 0 diff --git a/usr/src/test/util-tests/tests/libsff/libsff_8472.c b/usr/src/test/util-tests/tests/libsff/libsff_8472.c new file mode 100644 index 0000000000..5649faabec --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_8472.c @@ -0,0 +1,61 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print all SFF 8472 Compliance levels + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +int +main(void) +{ + uint_t i; + uint8_t buf[256]; + + bzero(buf, sizeof (buf)); + for (i = 0; i < UINT8_MAX; i++) { + int ret; + nvlist_t *nvl; + char *val; + + buf[SFF_8472_SFF_8472_COMPLIANCE] = i; + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP 8472 " + "Compliance value %d: %s\n", i, strerror(ret)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_COMPLIANCE_8472, + &val)) != 0) { + errx(1, "TEST FAILED: failed to find key %s with " + "value %d: %s", LIBSFF_KEY_COMPLIANCE_8472, i, + strerror(ret)); + } + + (void) puts(val); + nvlist_free(nvl); + } + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_8472.out b/usr/src/test/util-tests/tests/libsff/libsff_8472.out new file mode 100644 index 0000000000..f3a878f20a --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_8472.out @@ -0,0 +1,255 @@ +Not compliant +Rev 9.3 +Rev 9.5 +Rev 10.2 +Rev 10.4 +Rev 11.0 +Rev 11.3 +Rev 11.4 +Rev 12.0 +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated +Unallocated diff --git a/usr/src/test/util-tests/tests/libsff/libsff_8636_diag.c b/usr/src/test/util-tests/tests/libsff/libsff_8636_diag.c new file mode 100644 index 0000000000..bf84ea9f39 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_8636_diag.c @@ -0,0 +1,61 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print all SFF 8636 diagnostic monitoring + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +int +main(void) +{ + int ret; + uint8_t buf[256]; + char **vals; + uint_t count, i; + nvlist_t *nvl; + + bzero(buf, sizeof (buf)); + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + buf[SFF_8636_DIAG_MONITORING] = 0xff; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP diagnostics: " + "%s\n", strerror(errno)); + } + + if ((ret = nvlist_lookup_string_array(nvl, LIBSFF_KEY_DIAG_MONITOR, + &vals, &count)) != 0) { + errx(1, "TEST FAILED: failed to find key %s: %s ", + LIBSFF_KEY_EXT_SPEC, strerror(ret)); + } + + for (i = 0; i < count; i++) { + (void) printf("%d\t%s\n", i, vals[i]); + } + + nvlist_free(nvl); + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_8636_diag.out b/usr/src/test/util-tests/tests/libsff/libsff_8636_diag.out new file mode 100644 index 0000000000..b7e47c349e --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_8636_diag.out @@ -0,0 +1,2 @@ +0 Received power measurements: Average Power +1 Transmitter power measurement diff --git a/usr/src/test/util-tests/tests/libsff/libsff_8636_extspec.c b/usr/src/test/util-tests/tests/libsff/libsff_8636_extspec.c new file mode 100644 index 0000000000..03d58658f6 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_8636_extspec.c @@ -0,0 +1,62 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print all SFF 8636 / 8024 extended specification values + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +int +main(void) +{ + uint_t i; + uint8_t buf[256]; + + bzero(buf, sizeof (buf)); + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + for (i = 0; i < UINT8_MAX; i++) { + int ret; + nvlist_t *nvl; + char *val; + + buf[SFF_8636_LINK_CODES] = i; + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP link code " + "%d: %s\n", i, strerror(errno)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_EXT_SPEC, + &val)) != 0) { + errx(1, "TEST FAILED: failed to find key %s with " + "value %d: %s", LIBSFF_KEY_EXT_SPEC, i, + strerror(ret)); + } + + (void) puts(val); + nvlist_free(nvl); + } + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_8636_extspec.out b/usr/src/test/util-tests/tests/libsff/libsff_8636_extspec.out new file mode 100644 index 0000000000..1c55ceb022 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_8636_extspec.out @@ -0,0 +1,255 @@ +Unspecified +100G AOC or 25GAUI C2M AOC +100GBASE-SR4 or 25GBASE-SR +100GBASE-LR4 or 25GBASE-LR +100GBASE-ER4 or 25GBASE-ER +100GBASE-SR10 +100G CWDM4 +100G PSM4 Parallel SMF +100G ACC or 25GAUI C2M ACC +Obsolete +Reserved +100GBASE-CR4 or 25GBASE-CR CA-L +25GBASE-CR CA-S +25GBASE-CR CA-N +Reserved +Reserved +40GBASE-ER4 +4 x 10GBASE-SR +40G PSM4 Parallel SMF +G959.1 profile P1I1-2D1 +G959.1 profile P1S1-2D2 +G959.1 profile P1L1-2D2 +10GBASE-T with SFI electrical interface +100G CLR4 +100G AOC or 25GAUI C2M AOC +100G ACC or 25GAUI C2M ACC +100GE-DWDM2 +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved diff --git a/usr/src/test/util-tests/tests/libsff/libsff_8636_tech.c b/usr/src/test/util-tests/tests/libsff/libsff_8636_tech.c new file mode 100644 index 0000000000..21f02cab8c --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_8636_tech.c @@ -0,0 +1,79 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print SFF 8636 device tech values. + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +static void +lst_print_array(nvlist_t *nvl, const char *key) +{ + int ret; + uint_t i, count; + char **vals; + + if ((ret = nvlist_lookup_string_array(nvl, key, &vals, &count)) != 0) { + errx(1, "TEST FAILED failed to find key %s: %s\n", key, + strerror(ret)); + } + + (void) puts(key); + for (i = 0; i < count; i++) { + (void) printf("\t%d\t%s\n", i, vals[i]); + } +} + +int +main(void) +{ + uint_t i; + uint8_t buf[256]; + + bzero(buf, sizeof (buf)); + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + + /* + * The upper four bits of this value are used as a 4-bit identifier. The + * lower four bits are used as options. + */ + for (i = 0; i < 16; i++) { + int ret; + nvlist_t *nvl; + + buf[SFF_8636_DEVICE_TECH] = i << 4; + buf[SFF_8636_DEVICE_TECH] |= (i % 16); + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP device tech " + "%d: %s\n", i, strerror(errno)); + } + + lst_print_array(nvl, LIBSFF_KEY_TRAN_TECH); + nvlist_free(nvl); + } + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_8636_tech.out b/usr/src/test/util-tests/tests/libsff/libsff_8636_tech.out new file mode 100644 index 0000000000..c8652f21fb --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_8636_tech.out @@ -0,0 +1,96 @@ +Transmitter Technology + 0 850 nm VCSEL + 1 No Wavelength Control + 2 Uncooled Transmitter + 3 Pin Detector + 4 Transmitter Not Tunable +Transmitter Technology + 0 1310 nm VCSEL + 1 No Wavelength Control + 2 Uncooled Transmitter + 3 Pin Detector + 4 Transmitter Tunable +Transmitter Technology + 0 1550 nm VCSEL + 1 No Wavelength Control + 2 Uncooled Transmitter + 3 APD Detector + 4 Transmitter Not Tunable +Transmitter Technology + 0 1310 nm FP + 1 No Wavelength Control + 2 Uncooled Transmitter + 3 APD Detector + 4 Transmitter Tunable +Transmitter Technology + 0 1310 nm DFB + 1 No Wavelength Control + 2 Cooled Transmitter + 3 Pin Detector + 4 Transmitter Not Tunable +Transmitter Technology + 0 1550 nm DFB + 1 No Wavelength Control + 2 Cooled Transmitter + 3 Pin Detector + 4 Transmitter Tunable +Transmitter Technology + 0 1310 nm EML + 1 No Wavelength Control + 2 Cooled Transmitter + 3 APD Detector + 4 Transmitter Not Tunable +Transmitter Technology + 0 1550 nm EML + 1 No Wavelength Control + 2 Cooled Transmitter + 3 APD Detector + 4 Transmitter Tunable +Transmitter Technology + 0 Other / Undefined + 1 Active Wavelength Control + 2 Uncooled Transmitter + 3 Pin Detector + 4 Transmitter Not Tunable +Transmitter Technology + 0 1490 nm DFB + 1 Active Wavelength Control + 2 Uncooled Transmitter + 3 Pin Detector + 4 Transmitter Tunable +Transmitter Technology + 0 Copper cable unequalized + 1 Active Wavelength Control + 2 Uncooled Transmitter + 3 APD Detector + 4 Transmitter Not Tunable +Transmitter Technology + 0 Copper cable passive equalized + 1 Active Wavelength Control + 2 Uncooled Transmitter + 3 APD Detector + 4 Transmitter Tunable +Transmitter Technology + 0 Copper cable, near and far end limiting active equalizers + 1 Active Wavelength Control + 2 Cooled Transmitter + 3 Pin Detector + 4 Transmitter Not Tunable +Transmitter Technology + 0 Copper cable, far end limiting active equalizers + 1 Active Wavelength Control + 2 Cooled Transmitter + 3 Pin Detector + 4 Transmitter Tunable +Transmitter Technology + 0 Copper cable, near end limiting active equalizers + 1 Active Wavelength Control + 2 Cooled Transmitter + 3 APD Detector + 4 Transmitter Not Tunable +Transmitter Technology + 0 Copper cable, linear active equalizers + 1 Active Wavelength Control + 2 Cooled Transmitter + 3 APD Detector + 4 Transmitter Tunable diff --git a/usr/src/test/util-tests/tests/libsff/libsff_8636_temp.c b/usr/src/test/util-tests/tests/libsff/libsff_8636_temp.c new file mode 100644 index 0000000000..5e3ba70cd4 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_8636_temp.c @@ -0,0 +1,61 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print all case temperature values. Remember that 0 is special. + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +int +main(void) +{ + uint_t i; + uint8_t buf[256]; + + bzero(buf, sizeof (buf)); + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + for (i = 0; i < UINT8_MAX; i++) { + int ret; + nvlist_t *nvl; + char *val; + + buf[SFF_8636_MAX_CASE_TEMP] = i; + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP connector " + "%d: %s\n", i, strerror(errno)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_MAX_CASE_TEMP, + &val)) != 0) { + errx(1, "TEST FAILED: failed to find connector when " + "parsing key %d: %s\n", i, strerror(errno)); + } + + (void) puts(val); + nvlist_free(nvl); + } + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_8636_temp.out b/usr/src/test/util-tests/tests/libsff/libsff_8636_temp.out new file mode 100644 index 0000000000..f4838c433b --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_8636_temp.out @@ -0,0 +1,255 @@ +70 C +1 C +2 C +3 C +4 C +5 C +6 C +7 C +8 C +9 C +10 C +11 C +12 C +13 C +14 C +15 C +16 C +17 C +18 C +19 C +20 C +21 C +22 C +23 C +24 C +25 C +26 C +27 C +28 C +29 C +30 C +31 C +32 C +33 C +34 C +35 C +36 C +37 C +38 C +39 C +40 C +41 C +42 C +43 C +44 C +45 C +46 C +47 C +48 C +49 C +50 C +51 C +52 C +53 C +54 C +55 C +56 C +57 C +58 C +59 C +60 C +61 C +62 C +63 C +64 C +65 C +66 C +67 C +68 C +69 C +70 C +71 C +72 C +73 C +74 C +75 C +76 C +77 C +78 C +79 C +80 C +81 C +82 C +83 C +84 C +85 C +86 C +87 C +88 C +89 C +90 C +91 C +92 C +93 C +94 C +95 C +96 C +97 C +98 C +99 C +100 C +101 C +102 C +103 C +104 C +105 C +106 C +107 C +108 C +109 C +110 C +111 C +112 C +113 C +114 C +115 C +116 C +117 C +118 C +119 C +120 C +121 C +122 C +123 C +124 C +125 C +126 C +127 C +128 C +129 C +130 C +131 C +132 C +133 C +134 C +135 C +136 C +137 C +138 C +139 C +140 C +141 C +142 C +143 C +144 C +145 C +146 C +147 C +148 C +149 C +150 C +151 C +152 C +153 C +154 C +155 C +156 C +157 C +158 C +159 C +160 C +161 C +162 C +163 C +164 C +165 C +166 C +167 C +168 C +169 C +170 C +171 C +172 C +173 C +174 C +175 C +176 C +177 C +178 C +179 C +180 C +181 C +182 C +183 C +184 C +185 C +186 C +187 C +188 C +189 C +190 C +191 C +192 C +193 C +194 C +195 C +196 C +197 C +198 C +199 C +200 C +201 C +202 C +203 C +204 C +205 C +206 C +207 C +208 C +209 C +210 C +211 C +212 C +213 C +214 C +215 C +216 C +217 C +218 C +219 C +220 C +221 C +222 C +223 C +224 C +225 C +226 C +227 C +228 C +229 C +230 C +231 C +232 C +233 C +234 C +235 C +236 C +237 C +238 C +239 C +240 C +241 C +242 C +243 C +244 C +245 C +246 C +247 C +248 C +249 C +250 C +251 C +252 C +253 C +254 C diff --git a/usr/src/test/util-tests/tests/libsff/libsff_br.c b/usr/src/test/util-tests/tests/libsff/libsff_br.c new file mode 100644 index 0000000000..f0d3f25db2 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_br.c @@ -0,0 +1,133 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print and tests SFF BR values. + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +int +main(void) +{ + int ret; + uint8_t buf[256]; + nvlist_t *nvl; + char *val; + + /* + * SFF 8472 has two different modes of printing the bit rate. It has a + * nominal bit rate and then if 0xff is in that field it has a max and + * min. + */ + bzero(buf, sizeof (buf)); + buf[SFF_8472_BR_NOMINAL] = 0x42; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP compliance " + "values: %s\n", strerror(ret)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_BR_NOMINAL, &val)) != + 0) { + errx(1, "TEST FAILED: failed to find %s: %s when " + "parsing key %d: %s\n", LIBSFF_KEY_BR_NOMINAL, + strerror(ret)); + } + (void) printf("nominal: %s\n", val); + + /* + * Make sure min, max are missing. + */ + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_BR_MIN, &val)) != + ENOENT) { + errx(1, "TEST FALIED: found unexpected return value for key " + "%s: %d\n", LIBSFF_KEY_BR_MIN, ret); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_BR_MAX, &val)) != + ENOENT) { + errx(1, "TEST FALIED: found unexpected return value for key " + "%s: %d\n", LIBSFF_KEY_BR_MAX, ret); + } + nvlist_free(nvl); + + /* + * Now the opposite. + */ + buf[SFF_8472_BR_NOMINAL] = 0xff; + buf[SFF_8472_BR_MAX] = 0x50; + buf[SFF_8472_BR_MIN] = 0x10; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP compliance " + "values: %s\n", strerror(ret)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_BR_MAX, &val)) != 0) { + errx(1, "TEST FAILED: failed to find %s: %s when " + "parsing key %d: %s\n", LIBSFF_KEY_BR_MAX, + strerror(ret)); + } + (void) printf("max: %s\n", val); + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_BR_MIN, &val)) != 0) { + errx(1, "TEST FAILED: failed to find %s: %s when " + "parsing key %d: %s\n", LIBSFF_KEY_BR_MIN, + strerror(ret)); + } + (void) printf("min: %s\n", val); + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_BR_NOMINAL, &val)) != + ENOENT) { + errx(1, "TEST FALIED: found unexpected return value for key " + "%s: %d\n", LIBSFF_KEY_BR_NOMINAL, ret); + } + nvlist_free(nvl); + + /* + * Now for QSFP+ + */ + (void) puts("\n\nQSFP\n"); + bzero(buf, sizeof (buf)); + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + buf[SFF_8636_BR_NOMINAL] = 0x42; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP BR " + "values: %s\n", strerror(ret)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_BR_NOMINAL, + &val)) != 0) { + errx(1, "TEST FAILED: failed to find %s: %s when " + "parsing key %d: %s\n", LIBSFF_KEY_BR_NOMINAL, + strerror(ret)); + } + (void) printf("nominal: %s\n", val); + + nvlist_free(nvl); + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_br.out b/usr/src/test/util-tests/tests/libsff/libsff_br.out new file mode 100644 index 0000000000..3973fb58aa --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_br.out @@ -0,0 +1,8 @@ +nominal: 6600 MBd +max: 20000 MBd +min: 4000 MBd + + +QSFP + +nominal: 6600 Mbps diff --git a/usr/src/test/util-tests/tests/libsff/libsff_compliance.c b/usr/src/test/util-tests/tests/libsff/libsff_compliance.c new file mode 100644 index 0000000000..9aeb611228 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_compliance.c @@ -0,0 +1,124 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print and tests SFF compliance values. + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +static void +lsc_print_array(nvlist_t *nvl, const char *key) +{ + int ret; + uint_t i, count; + char **vals; + + if ((ret = nvlist_lookup_string_array(nvl, key, &vals, &count)) != 0) { + errx(1, "TEST FAILED failed to find key %s: %s\n", key, + strerror(ret)); + } + + (void) puts(key); + for (i = 0; i < count; i++) { + (void) printf("\t%d\t%s\n", i, vals[i]); + } +} + +int +main(void) +{ + int ret; + uint8_t buf[256]; + nvlist_t *nvl; + + /* + * Set every shared bit for compliance then print them all out. Note we + * include reserved bits so that way if someone ends up adding something + * to one of the reserved fields, we end up printing it. + */ + bzero(buf, sizeof (buf)); + buf[SFF_8472_COMPLIANCE_10GE] = 0xff; + buf[SFF_8472_COMPLIANCE_SONET_LOW] = 0xff; + buf[SFF_8472_COMPLIANCE_SONET_HIGH] = 0xff; + buf[SFF_8472_COMPLIANCE_ETHERNET] = 0xff; + buf[SFF_8472_COMPLIANCE_FC_LOW] = 0xff; + buf[SFF_8472_COMPLIANCE_FC_HIGH] = 0xff; + buf[SFF_8472_COMPLIANCE_FC_MEDIA] = 0xff; + buf[SFF_8472_COMPLIANCE_FC_SPEED] = 0xff; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP compliance " + "values: %s\n", strerror(ret)); + } + + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_10GBE); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_IB); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_ESCON); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_SONET); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_GBE); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_FC_LEN); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_FC_TECH); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_SFP); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_FC_MEDIA); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_FC_SPEED); + + nvlist_free(nvl); + + /* + * Now for QSFP+ + */ + (void) puts("\n\nQSFP\n"); + bzero(buf, sizeof (buf)); + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + buf[SFF_8636_COMPLIANCE_10GBEP] = 0xff; + buf[SFF_8636_COMPLIANCE_SONET] = 0xff; + buf[SFF_8636_COMPLIANCE_SAS] = 0xff; + buf[SFF_8636_COMPLIANCE_ETHERNET] = 0xff; + buf[SFF_8636_COMPLIANCE_FCLEN] = 0xff; + buf[SFF_8636_COMPLIANCE_FC_LOW] = 0xff; + buf[SFF_8636_COMPLIANCE_FC_HIGH] = 0xff; + buf[SFF_8636_COMPLIANCE_FC_MEDIA] = 0xff; + buf[SFF_8636_COMPLIANCE_FC_SPEED] = 0xff; + buf[SFF_8636_EXTENDED_MODULE] = 0xff; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP compliance " + "values: %s\n", strerror(ret)); + } + + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_10GBE); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_SONET); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_SAS); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_GBE); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_FC_LEN); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_FC_TECH); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_FC_MEDIA); + lsc_print_array(nvl, LIBSFF_KEY_COMPLIANCE_FC_SPEED); + lsc_print_array(nvl, LIBSFF_KEY_EXT_MOD_CODES); + + nvlist_free(nvl); + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_compliance.out b/usr/src/test/util-tests/tests/libsff/libsff_compliance.out new file mode 100644 index 0000000000..6f6ec66c44 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_compliance.out @@ -0,0 +1,130 @@ +10G+ Ethernet Compliance Codes + 0 10G Base-SR + 1 10G Base-LR + 2 10G Base-LRM + 3 10G Base-ER +Infiniband Compliance Codes + 0 1X Copper Passive + 1 1X Copper Active + 2 1X LX + 3 1X SX +ESCON Compliance Codes + 0 ESCON SMF, 1310nm Laser + 1 ESCON MMF, 1310nm LED +SONET Compliance Codes + 0 OC-48, short reach + 1 OC-48, intermediate reach + 2 OC-48, long reach + 3 ONET reach specifier bit 2 + 4 SONET reach specifier bit 1 + 5 OC-192, short reach + 6 OC-3, short reach + 7 OC-3, single mode, inter. reach + 8 OC-3, single mode, long reach + 9 OC-12, short reach + 10 OC-12, single mode, inter. reach + 11 OC-12, single mode, long reach +Ethernet Compliance Codes + 0 1000BASE-SX + 1 1000BASE-LX + 2 1000BASE-CX + 3 1000BASE-T + 4 100BASE-LX/LX10 + 5 100BASE-FX + 6 BASE-BX10 + 7 BASE-PX +Fibre Channel Link Lengths + 0 medium distance (M) + 1 long distance (L) + 2 intermeddiate distance (I) + 3 short distance (S) + 4 very long distance (V) +Fibre Channel Technology + 0 Electrical inter-enclosure (EL) + 1 Longwave laser (LC) + 2 Shortwave laser, linear Rx (SA) + 3 Longwave laser (LL) + 4 Shortwave laser with OFC (SL) + 5 Shortwave laser w/o OFC (SN) + 6 Electrical intra-enclosure (EL) +SFP+ Cable Technology + 0 Passive Cable + 1 Active Cable +Fibre Channel Transmission Media + 0 Single Mode (SM) + 1 Multimode, 50um (M5, M5E) + 2 Multimode, 62.5um (M6) + 3 Video Coax (TV) + 4 Miniature Coax (MI) + 5 Twisted Pair (TP) + 6 Twin Axial Pair (TW) +Fibre Channel Speed + 0 100 MBytes/sec + 1 200 MBytes/sec + 2 3200 MBytes/sec + 3 400 MBytes/sec + 4 1600 MBytes/sec + 5 800 MBytes/sec + 6 1200 MBytes/sec + + +QSFP + +10G+ Ethernet Compliance Codes + 0 40G Active Cable (XLPPI) + 1 40GBASE-LR4 + 2 40GBASE-SR4 + 3 40GBASE-CR4 + 4 10GBASE-SR + 5 10GBASE-LR + 6 10GBASE-LRM +SONET Compliance Codes + 0 OC 48 short reach + 1 OC 48, intermediate reach + 2 OC 48, long reach +SAS Compliance Codes + 0 SAS 3.0 Gb/s + 1 SAS 6.0 Gb/s + 2 SAS 12.0 Gb/s + 3 SAS 24.0 Gb/s +Ethernet Compliance Codes + 0 1000BASE-SX + 1 1000BASE-LX + 2 1000BASE-CX + 3 1000BASE-T +Fibre Channel Link Lengths + 0 medium distance (M) + 1 long distance (L) + 2 intermeddiate distance (I) + 3 short distance (S) + 4 very long distance (V) +Fibre Channel Technology + 0 Electrical inter-enclosure (EL) + 1 Longwave laser (LC) + 2 Longwave laser (LL) + 3 Shortwave laser with OFC (SL) + 4 Shortwave laser w/o OFC (SN) + 5 Electrical intra-enclosure (EL) +Fibre Channel Transmission Media + 0 Single Mode (SM) + 1 Multimode, 50um (OM3) + 2 Multimode, 50m (M5) + 3 Multimode, 62.5um (M6) + 4 Video Coax (TV) + 5 Miniature Coax (MI) + 6 Twisted Pair (TP) + 7 Twin Axial Pair (TW) +Fibre Channel Speed + 0 100 MBytes/sec + 1 200 MBytes/sec + 2 3200 MBytes/sec + 3 400 MBytes/sec + 4 1600 MBytes/sec + 5 800 MBytes/sec + 6 1200 MBytes/sec +Extended Module Codes + 0 SDR + 1 DDR + 2 QDR + 3 FDR + 4 EDR diff --git a/usr/src/test/util-tests/tests/libsff/libsff_conn.c b/usr/src/test/util-tests/tests/libsff/libsff_conn.c new file mode 100644 index 0000000000..778eaf1105 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_conn.c @@ -0,0 +1,89 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print all SFF Connector values + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +int +main(void) +{ + uint_t i; + uint8_t buf[256]; + + bzero(buf, sizeof (buf)); + for (i = 0; i < UINT8_MAX; i++) { + int ret; + nvlist_t *nvl; + char *val; + + buf[SFF_8472_CONNECTOR] = i; + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP connector " + "%d: %s\n", i, strerror(ret)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_CONNECTOR, + &val)) != 0) { + errx(1, "TEST FAILED: failed to find key %s with " + "value %d: %s", LIBSFF_KEY_CONNECTOR, i, + strerror(ret)); + } + + (void) puts(val); + nvlist_free(nvl); + } + + /* + * Now for QSFP+ + */ + (void) puts("\n\nQSFP\n"); + bzero(buf, sizeof (buf)); + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + for (i = 0; i < UINT8_MAX; i++) { + int ret; + nvlist_t *nvl; + char *val; + + buf[SFF_8636_CONNECTOR] = i; + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP connector " + "%d: %s\n", i, strerror(errno)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_CONNECTOR, + &val)) != 0) { + errx(1, "TEST FAILED: failed to find key %s with " + "value %d: %s", LIBSFF_KEY_CONNECTOR, i, + strerror(ret)); + } + + (void) puts(val); + nvlist_free(nvl); + } + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_conn.out b/usr/src/test/util-tests/tests/libsff/libsff_conn.out new file mode 100644 index 0000000000..68dfb0e4d5 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_conn.out @@ -0,0 +1,514 @@ +Unknown +SC (Subscriber Connector) +Fibre Channel Style 1 copper connector +Fibre Channel Style 2 copper connector +BNC/TNC (Bayonet/Threaded Neill-Concelman) +Fibre Channel coax headers +Fiber Jack +LC (Lucent Connector) +MT-RJ (Mechanical Transfer - Registered Jack) +MU (Multiple Optical) +SG +Optical Pigtail +MPO 1x12 (Multifiber Parallel Optic) +MPO 2x16 +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +HSSDC II (High Speed Serial Data Connector) +Copper pigtail +RJ45 (Registered Jack) +No separable connector +MXC 2x16 +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific + + +QSFP + +Unknown +SC (Subscriber Connector) +Fibre Channel Style 1 copper connector +Fibre Channel Style 2 copper connector +BNC/TNC (Bayonet/Threaded Neill-Concelman) +Fibre Channel coax headers +Fiber Jack +LC (Lucent Connector) +MT-RJ (Mechanical Transfer - Registered Jack) +MU (Multiple Optical) +SG +Optical Pigtail +MPO 1x12 (Multifiber Parallel Optic) +MPO 2x16 +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +HSSDC II (High Speed Serial Data Connector) +Copper pigtail +RJ45 (Registered Jack) +No separable connector +MXC 2x16 +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific diff --git a/usr/src/test/util-tests/tests/libsff/libsff_efault.c b/usr/src/test/util-tests/tests/libsff/libsff_efault.c new file mode 100644 index 0000000000..7f57529d81 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_efault.c @@ -0,0 +1,54 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Test various error cases all of which should return EFAULT. + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> +#include <unistd.h> +#include <sys/mman.h> + +int +main(void) +{ + int ret; + void *addr; + nvlist_t *nvl; + size_t len = getpagesize(); + + /* + * Get an unreadable page + */ + if ((addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE | MAP_ANON, -1, + 0)) == MAP_FAILED) { + err(1, "TEST FAILED: failed to mmap private page"); + } + + if (mprotect(addr, len, PROT_NONE) != 0) { + err(1, "TEST FAILED: failed to protect private page"); + } + + if ((ret = libsff_parse(addr, 128, 0xa0, &nvl)) != EFAULT) { + errx(1, "TEST FAILED: failed to return EFAULT on bad" + "data buffer\n"); + } + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_einval.c b/usr/src/test/util-tests/tests/libsff/libsff_einval.c new file mode 100644 index 0000000000..ac835f95e7 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_einval.c @@ -0,0 +1,88 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Test various error cases all of which should return EINVAL. + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +#include "sff.h" + +int +main(void) +{ + int ret; + uint8_t buf[256]; + nvlist_t *nvl; + + bzero(buf, sizeof (buf)); + if ((ret = libsff_parse(NULL, sizeof (buf), 0xa0, &nvl)) != EINVAL) { + errx(1, "TEST FAILED: failed to return EINVAL on NULL buffer"); + } + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, NULL)) != EINVAL) { + errx(1, "TEST FAILED: failed to return EINVAL on NULL nvl"); + } + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa1, &nvl)) != EINVAL) { + errx(1, "TEST FAILED: failed to return EINVAL on bad page"); + } + + if ((ret = libsff_parse(buf, sizeof (buf), 0, &nvl)) != EINVAL) { + errx(1, "TEST FAILED: failed to return EINVAL on bad page"); + } + + if ((ret = libsff_parse(buf, sizeof (buf), 0xff, &nvl)) != EINVAL) { + errx(1, "TEST FAILED: failed to return EINVAL on bad page"); + } + + if ((ret = libsff_parse(buf, 0, 0xa0, &nvl)) != EINVAL) { + errx(1, "TEST FAILED: failed to return EINVAL on bad 8476 " + "size"); + } + + if ((ret = libsff_parse(buf, 50, 0xa0, &nvl)) != EINVAL) { + errx(1, "TEST FAILED: failed to return EINVAL on bad 8476 " + "size"); + } + + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + if ((ret = libsff_parse(buf, 0, 0xa0, &nvl)) != EINVAL) { + errx(1, "TEST FAILED: failed to return EINVAL on bad 8476 " + "size"); + } + + if ((ret = libsff_parse(buf, 50, 0xa0, &nvl)) != EINVAL) { + errx(1, "TEST FAILED: failed to return EINVAL on bad 8476 " + "size"); + } + + if ((ret = libsff_parse(buf, 96, 0xa0, &nvl)) != EINVAL) { + errx(1, "TEST FAILED: failed to return EINVAL on bad 8635 " + "size"); + } + + if ((ret = libsff_parse(buf, 128, 0xa0, &nvl)) != EINVAL) { + errx(1, "TEST FAILED: failed to return EINVAL on bad 8635 " + "size"); + } + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_enc.c b/usr/src/test/util-tests/tests/libsff/libsff_enc.c new file mode 100644 index 0000000000..77ac12b2ed --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_enc.c @@ -0,0 +1,89 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print all SFF Encoding values + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +int +main(void) +{ + uint_t i; + uint8_t buf[256]; + + bzero(buf, sizeof (buf)); + for (i = 0; i < UINT8_MAX; i++) { + int ret; + nvlist_t *nvl; + char *val; + + buf[SFF_8472_ENCODING] = i; + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP connector " + "%d: %s\n", i, strerror(ret)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_ENCODING, + &val)) != 0) { + errx(1, "TEST FAILED: failed to find key %s with " + "value %d: %s", LIBSFF_KEY_ENCODING, i, + strerror(ret)); + } + + (void) puts(val); + nvlist_free(nvl); + } + + /* + * Now for QSFP+ + */ + (void) puts("\n\nQSFP\n"); + bzero(buf, sizeof (buf)); + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + for (i = 0; i < UINT8_MAX; i++) { + int ret; + nvlist_t *nvl; + char *val; + + buf[SFF_8636_ENCODING] = i; + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP connector " + "%d: %s\n", i, strerror(errno)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_ENCODING, + &val)) != 0) { + errx(1, "TEST FAILED: failed to find key %s with " + "value %d: %s", LIBSFF_KEY_ENCODING, i, + strerror(ret)); + } + + (void) puts(val); + nvlist_free(nvl); + } + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_enc.out b/usr/src/test/util-tests/tests/libsff/libsff_enc.out new file mode 100644 index 0000000000..b31a565e4e --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_enc.out @@ -0,0 +1,514 @@ +Unspecified +8B/10B +4B/5B +NRZ +Manchester +SONET Scrambled +64B/66B +256B/257B +PAM4 +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved + + +QSFP + +Unspecified +8B/10B +4B/5B +NRZ +SONET Scrambled +64B/66B +Manchester +256B/257B +PAM4 +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved diff --git a/usr/src/test/util-tests/tests/libsff/libsff_ident.c b/usr/src/test/util-tests/tests/libsff/libsff_ident.c new file mode 100644 index 0000000000..0065a6d0e0 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_ident.c @@ -0,0 +1,60 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print all SFF Identifier values + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +int +main(void) +{ + uint_t i; + uint8_t buf[256]; + + bzero(buf, sizeof (buf)); + for (i = 0; i < UINT8_MAX; i++) { + int ret; + nvlist_t *nvl; + char *val; + + buf[SFF_8472_IDENTIFIER] = i; + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse identifier " + "%d: %s\n", i, strerror(ret)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_IDENTIFIER, + &val)) != 0) { + errx(1, "TEST FAILED: failed to find key %s with " + "value %d: %s", LIBSFF_KEY_IDENTIFIER, i, + strerror(ret)); + } + + (void) puts(val); + nvlist_free(nvl); + } + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_ident.out b/usr/src/test/util-tests/tests/libsff/libsff_ident.out new file mode 100644 index 0000000000..360c5966f8 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_ident.out @@ -0,0 +1,255 @@ +Unknown or Unspecified +GBIC +Module/connector soldered to motherboard +SFP/SFP+/SFP28 +300 pin XBI +XENPAK +XFP +XFF +XFP-E +XPAK +X2 +DWDM-SFP/SFP+ (not using SFF-8472) +QSFP +QSFP+ or later +CXP or later +Shielded Mini Multilane HD 4X +Shielded Mini Multilane HD 8X +QSFP28 or later +CXP2 (aka CXP28) or later +CDFP (Style 1/Style2) +Shielded Mini Multilane HD 4X Fanout Cable +Shielded Mini Multilane HD 8X Fanout Cable +CDFP (Style 3) +microQSFP +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Reserved +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific +Vendor Specific diff --git a/usr/src/test/util-tests/tests/libsff/libsff_lengths.c b/usr/src/test/util-tests/tests/libsff/libsff_lengths.c new file mode 100644 index 0000000000..f77b29a397 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_lengths.c @@ -0,0 +1,133 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print and tests SFF length values. + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +int +main(void) +{ + int ret; + uint8_t buf[256]; + nvlist_t *nvl; + char *val; + uint_t i; + const char *lengths_8472[] = { LIBSFF_KEY_LENGTH_SMF_KM, + LIBSFF_KEY_LENGTH_SMF, LIBSFF_KEY_LENGTH_OM2, LIBSFF_KEY_LENGTH_OM1, + LIBSFF_KEY_LENGTH_COPPER, LIBSFF_KEY_LENGTH_OM3, NULL }; + const char *lengths_8636[] = { LIBSFF_KEY_LENGTH_SMF_KM, + LIBSFF_KEY_LENGTH_OM2, LIBSFF_KEY_LENGTH_OM1, + LIBSFF_KEY_LENGTH_COPPER, LIBSFF_KEY_LENGTH_OM3, NULL }; + + /* + * Make sure if lengths are zero that they don't show up. + */ + bzero(buf, sizeof (buf)); + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP length " + "values: %s\n", strerror(ret)); + } + + for (i = 0; lengths_8472[i] != NULL; i++) { + if ((ret = nvlist_lookup_string(nvl, lengths_8472[i], &val)) != + ENOENT) { + errx(1, "TEST FALIED: found unexpected return value " + "for key %s: %d\n", lengths_8472[i], ret); + } + } + + nvlist_free(nvl); + + buf[SFF_8472_LENGTH_SMF_KM] = 0x23; + buf[SFF_8472_LENGTH_SMF] = 0x24; + buf[SFF_8472_LENGTH_50UM] = 0x25; + buf[SFF_8472_LENGTH_62UM] = 0x26; + buf[SFF_8472_LENGTH_COPPER] = 0x27; + buf[SFF_8472_LENGTH_OM3] = 0x28; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP length " + "values: %s\n", strerror(ret)); + } + + for (i = 0; lengths_8472[i] != NULL; i++) { + if ((ret = nvlist_lookup_string(nvl, lengths_8472[i], &val)) != + 0) { + errx(1, "TEST FALIED: failed to find length for key " + "%s: %d\n", lengths_8472[i], ret); + } + (void) printf("%s: %s\n", lengths_8472[i], val); + } + + nvlist_free(nvl); + + /* + * Now for QSFP+ + */ + (void) puts("\n\nQSFP\n"); + bzero(buf, sizeof (buf)); + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP length " + "values: %s\n", strerror(ret)); + } + + for (i = 0; lengths_8472[i] != NULL; i++) { + if ((ret = nvlist_lookup_string(nvl, lengths_8472[i], &val)) != + ENOENT) { + errx(1, "TEST FALIED: found unexpected return value " + "for key %s: %d\n", lengths_8472[i], ret); + } + } + + nvlist_free(nvl); + + buf[SFF_8636_LENGTH_SMF] = 0x23; + buf[SFF_8636_LENGTH_OM3] = 0x24; + buf[SFF_8636_LENGTH_OM2] = 0x25; + buf[SFF_8636_LENGTH_OM1] = 0x26; + buf[SFF_8636_LENGTH_COPPER] = 0x27; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP length " + "values: %s\n", strerror(ret)); + } + + for (i = 0; lengths_8636[i] != NULL; i++) { + if ((ret = nvlist_lookup_string(nvl, lengths_8636[i], &val)) != + 0) { + errx(1, "TEST FALIED: failed to find length for key " + "%s: %d\n", lengths_8472[i], ret); + } + (void) printf("%s: %s\n", lengths_8636[i], val); + } + + nvlist_free(nvl); + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_lengths.out b/usr/src/test/util-tests/tests/libsff/libsff_lengths.out new file mode 100644 index 0000000000..9be9d76804 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_lengths.out @@ -0,0 +1,15 @@ +Length SMF (km): 35 km +Length SMF (m): 3600 m +Length 50um OM2: 370 m +Length 62.5um OM1: 380 m +Length Copper: 39 m +Length OM3: 400 m + + +QSFP + +Length SMF (km): 35 km +Length 50um OM2: 37 m +Length 62.5um OM1: 38 m +Length Copper: 39 m +Length OM3: 72 m diff --git a/usr/src/test/util-tests/tests/libsff/libsff_opts.c b/usr/src/test/util-tests/tests/libsff/libsff_opts.c new file mode 100644 index 0000000000..e91365dc6a --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_opts.c @@ -0,0 +1,98 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print and tests SFF options values. + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +static void +lso_print_array(nvlist_t *nvl, const char *key) +{ + int ret; + uint_t i, count; + char **vals; + + if ((ret = nvlist_lookup_string_array(nvl, key, &vals, &count)) != 0) { + errx(1, "TEST FAILED failed to find key %s: %s\n", key, + strerror(ret)); + } + + (void) puts(key); + for (i = 0; i < count; i++) { + (void) printf("\t%d\t%s\n", i, vals[i]); + } +} + +int +main(void) +{ + int ret; + uint8_t buf[256]; + nvlist_t *nvl; + + /* + * Set every shared bit for options then print them all out. Note we + * include reserved bits so that way if someone ends up adding something + * to one of the reserved fields, we end up printing it. + */ + bzero(buf, sizeof (buf)); + buf[SFF_8472_OPTIONS_HI] = 0xff; + buf[SFF_8472_OPTIONS_LOW] = 0xff; + buf[SFF_8472_ENHANCED_OPTIONS] = 0xff; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP options " + "values: %s\n", strerror(ret)); + } + + lso_print_array(nvl, LIBSFF_KEY_OPTIONS); + lso_print_array(nvl, LIBSFF_KEY_EXTENDED_OPTIONS); + + nvlist_free(nvl); + + /* + * Now for QSFP+ + */ + (void) puts("\n\nQSFP\n"); + bzero(buf, sizeof (buf)); + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + buf[SFF_8636_OPTIONS_HI] = 0xff; + buf[SFF_8636_OPTIONS_MID] = 0xff; + buf[SFF_8636_OPTIONS_LOW] = 0xff; + buf[SFF_8636_ENHANCED_OPTIONS] = 0xff; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP options " + "values: %s\n", strerror(ret)); + } + + lso_print_array(nvl, LIBSFF_KEY_OPTIONS); + lso_print_array(nvl, LIBSFF_KEY_ENHANCED_OPTIONS); + + nvlist_free(nvl); + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_opts.out b/usr/src/test/util-tests/tests/libsff/libsff_opts.out new file mode 100644 index 0000000000..870ea735ac --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_opts.out @@ -0,0 +1,50 @@ +Options + 0 Rx_LOS implemented + 1 Rx_LOS inverted + 2 TX_FAULT implemented + 3 TX_DISABLE implemented + 4 RATE_SELECT implemented + 5 Tunable transmitter + 6 Receiver decision threshold implemented + 7 Linear Receiver Output Implemented + 8 Power Level 2 Requirement + 9 Cooled Transceiver Implemented + 10 Retimer or CDR implemented + 11 Paging Implemented + 12 Power Level 3 Requirement +Extended Options + 0 Soft Rate Select Control Implemented + 1 Application Select implemented + 2 Soft RATE_SELECT implemented + 3 Soft RX_LOS implemented + 4 Soft TX_FAULT implemented + 5 Soft TX_DISABLE implemented + 6 Alarm/Warning flags implemented + + +QSFP + +Options + 0 Tx Loss of Signal implemented + 1 Tx Squelch for Pave + 2 Tx_FAULT implemented + 3 Tx_DISABLE implemented + 4 Rate Select implemented + 5 Memory page 01h provided + 6 Memory page 02h provided + 7 Tx Squelch implemented + 8 Tx Squelch Disable implemented + 9 Rx Output Disable capable + 10 Rx Squelch Disable implemented + 11 Rx CDR Loss of Lock Flag implemented + 12 Tx CDR Loss of Lock Flag implemented + 13 RX CDR On/Off Control implemented + 14 TX CDR On/Off Control implemented + 15 RX Output Amplitude Fixed Programmable Settings + 16 RX Output Emphasis Fixed Programmable Settings + 17 TX Input Equalization Fixed Programmable + 18 TX Input Equalization Auto Adaptive Capable +Enhanced Options + 0 Application Select Table Supported + 1 Extended Rate Selection Supported + 2 Initialization Complete Flag Implemented diff --git a/usr/src/test/util-tests/tests/libsff/libsff_strings.c b/usr/src/test/util-tests/tests/libsff/libsff_strings.c new file mode 100644 index 0000000000..a9d5a2252f --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_strings.c @@ -0,0 +1,133 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Test our ability to parse SFF string values which are space encoded. As this + * is shared between the SFP and QSFP logic, we end up only testing the SFP + * based data. + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. Strings are + * described as having spaces at the end of them. We mostly want to make sure + * that if we have strings without spaces that we parse them sanely as well as + * test what happens with embedded spaces and NUL characters. + */ +#include "sff.h" + +typedef struct { + uint8_t lss_bytes[16]; + const char *lss_parsed; +} lsfs_string_pair_t; + +static const lsfs_string_pair_t lsfs_bad_vals[] = { + /* All NULs */ + { { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' }, + "" }, + /* Embedded NULs */ + { { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + '\0', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, + "" }, + /* Non-ASCII */ + { { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', + 156, 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, + "" }, + /* All padding */ + { { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }, + "" } +}; +#define NBAD (sizeof (lsfs_bad_vals) / sizeof (lsfs_string_pair_t)) + +static const lsfs_string_pair_t lsfs_good_vals[] = { + /* Basic Name */ + { { 'f', 'i', 'n', 'g', 'o', 'l', 'f', 'i', + 'n', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }, + "fingolfin" }, + /* Non-padding Space */ + { { 'G', 'l', 'o', 'b', 'e', 'x', ' ', 'C', + 'o', 'r', 'p', ' ', ' ', ' ', ' ', ' ' }, + "Globex Corp" }, + /* 1-character name to catch off by one */ + { { '~', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }, + "~" }, + /* Use all characters */ + { { '!', '!', '!', '!', '!', '!', '!', '!', + '!', '!', '!', '!', '!', '!', '!', '!' }, + "!!!!!!!!!!!!!!!!" } +}; +#define NGOOD (sizeof (lsfs_good_vals) / sizeof (lsfs_string_pair_t)) + +int +main(void) +{ + int ret, i; + uint8_t buf[256]; + nvlist_t *nvl; + char *val; + + for (i = 0; i < NBAD; i++) { + bzero(buf, sizeof (buf)); + bcopy(lsfs_bad_vals[i].lss_bytes, &buf[SFF_8472_VENDOR], + SFF_8472_VENDOR_LEN); + + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP bad string " + "case %d: %s\n", i, strerror(ret)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_VENDOR, + &val)) != ENOENT) { + errx(1, "TEST FALIED: found unexpected return value " + "for %s: %d\n", LIBSFF_KEY_VENDOR, ret); + } + nvlist_free(nvl); + } + + for (i = 0; i < NGOOD; i++) { + bzero(buf, sizeof (buf)); + bcopy(lsfs_good_vals[i].lss_bytes, &buf[SFF_8472_VENDOR], + SFF_8472_VENDOR_LEN); + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP good string " + "case %d: %s\n", i, strerror(ret)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_VENDOR, + &val)) != 0) { + errx(1, "TEST FALIED: failed to find expected key " + "%s: %d", LIBSFF_KEY_VENDOR, ret); + } + + if (strcmp(val, lsfs_good_vals[i].lss_parsed) != 0) { + errx(1, "TEST FAILED: expected string %s, found %s\n", + lsfs_good_vals[i].lss_parsed, val); + } + + nvlist_free(nvl); + } + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_wave.c b/usr/src/test/util-tests/tests/libsff/libsff_wave.c new file mode 100644 index 0000000000..08b3637e06 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_wave.c @@ -0,0 +1,177 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2017, Joyent, Inc. + */ + +/* + * Print and tests SFF Wavelength values. Note that in both SFF 8472 and SFF + * 8636 the wavelength values also double for various copper complaince values. + * We check both forms here. Note that the copper compliance in SFF 8472 is + * currently tested in libsff_compliance.c. SFF 8636's Copper Attenuation values + * are tested here. + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <err.h> +#include <libsff.h> + +/* + * Pick up private sff header file with offsets from lib/libsff. + */ +#include "sff.h" + +int +main(void) +{ + int ret, i; + uint8_t buf[256]; + nvlist_t *nvl; + char *val; + char *attenuate[] = { LIBSFF_KEY_ATTENUATE_2G, LIBSFF_KEY_ATTENUATE_5G, + LIBSFF_KEY_ATTENUATE_7G, LIBSFF_KEY_ATTENUATE_12G, NULL }; + char *wave[] = { LIBSFF_KEY_WAVELENGTH, LIBSFF_KEY_WAVE_TOLERANCE, + NULL }; + + bzero(buf, sizeof (buf)); + buf[SFF_8472_WAVELENGTH_HI] = 0x12; + buf[SFF_8472_WAVELENGTH_LOW] = 0x34; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP wavelength " + "values: %s\n", strerror(ret)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_WAVELENGTH, &val)) != + 0) { + errx(1, "TEST FAILED: failed to find %s: %s when " + "parsing key %d: %s\n", LIBSFF_KEY_WAVELENGTH, + strerror(ret)); + } + (void) printf("%s: %s\n", LIBSFF_KEY_WAVELENGTH, val); + nvlist_free(nvl); + + /* + * Make sure wavelength is missing if we specify a copper compliance. + */ + bzero(buf, sizeof (buf)); + buf[SFF_8472_COMPLIANCE_SFP] = 0x08; + buf[SFF_8472_WAVELENGTH_HI] = 0x12; + buf[SFF_8472_WAVELENGTH_LOW] = 0x34; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP wavelength " + "values: %s\n", strerror(ret)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_WAVELENGTH, &val)) != + ENOENT) { + errx(1, "TEST FALIED: found unexpected return value for key " + "%s: %d\n", LIBSFF_KEY_WAVELENGTH, ret); + } + + nvlist_free(nvl); + + bzero(buf, sizeof (buf)); + buf[SFF_8472_COMPLIANCE_SFP] = 0x04; + buf[SFF_8472_WAVELENGTH_HI] = 0x12; + buf[SFF_8472_WAVELENGTH_LOW] = 0x34; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse SFP wavelength " + "values: %s\n", strerror(ret)); + } + + if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_WAVELENGTH, &val)) != + ENOENT) { + errx(1, "TEST FALIED: found unexpected return value for key " + "%s: %d\n", LIBSFF_KEY_WAVELENGTH, ret); + } + + nvlist_free(nvl); + + /* + * Now for QSFP+ + */ + (void) puts("\n\nQSFP\n"); + + /* First copper */ + bzero(buf, sizeof (buf)); + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + buf[SFF_8636_DEVICE_TECH] = 0xa0; + + buf[SFF_8636_ATTENUATE_2G] = 0x42; + buf[SFF_8636_ATTENUATE_5G] = 0x43; + buf[SFF_8636_ATTENUATE_7G] = 0x44; + buf[SFF_8636_ATTENUATE_12G] = 0x45; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP BR " + "values: %s\n", strerror(ret)); + } + + for (i = 0; attenuate[i] != NULL; i++) { + if ((ret = nvlist_lookup_string(nvl, attenuate[i], &val)) != + 0) { + errx(1, "TEST FAILED: failed to find %s: %s when " + "parsing key %d: %s\n", attenuate[i], + strerror(ret)); + } + (void) printf("%s: %s\n", attenuate[i], val); + } + + for (i = 0; wave[i] != NULL; i++) { + if ((ret = nvlist_lookup_string(nvl, wave[i], &val)) != + ENOENT) { + errx(1, "TEST FALIED: found unexpected return value " + "for key %s: %d\n", attenuate[i], ret); + } + + } + nvlist_free(nvl); + + /* Now normal wavelengths */ + bzero(buf, sizeof (buf)); + buf[SFF_8472_IDENTIFIER] = SFF_8024_ID_QSFP; + + buf[SFF_8636_WAVELENGTH_NOMINAL_HI] = 0x12; + buf[SFF_8636_WAVELENGTH_NOMINAL_LOW] = 0x34; + buf[SFF_8636_WAVELENGTH_TOLERANCE_HI] = 0x56; + buf[SFF_8636_WAVELENGTH_TOLERANCE_LOW] = 0x78; + + if ((ret = libsff_parse(buf, sizeof (buf), 0xa0, &nvl)) != 0) { + errx(1, "TEST FAILED: failed to parse QSFP Wavelength " + "values: %s\n", strerror(ret)); + } + + for (i = 0; wave[i] != NULL; i++) { + if ((ret = nvlist_lookup_string(nvl, wave[i], &val)) != 0) { + errx(1, "TEST FAILED: failed to find %s: %s when " + "parsing key %d: %s\n", wave[i], strerror(ret)); + } + (void) printf("%s: %s\n", wave[i], val); + } + + for (i = 0; attenuate[i] != NULL; i++) { + if ((ret = nvlist_lookup_string(nvl, attenuate[i], &val)) != + ENOENT) { + errx(1, "TEST FALIED: found unexpected return value " + "for key %s: %d\n", attenuate[i], ret); + } + + } + nvlist_free(nvl); + + return (0); +} diff --git a/usr/src/test/util-tests/tests/libsff/libsff_wave.out b/usr/src/test/util-tests/tests/libsff/libsff_wave.out new file mode 100644 index 0000000000..190e296478 --- /dev/null +++ b/usr/src/test/util-tests/tests/libsff/libsff_wave.out @@ -0,0 +1,11 @@ +Laser Wavelength: 4660 nm + + +QSFP + +Cable Attenuation at 2.5 GHz: 66 dB +Cable Attenuation at 5.0 GHz: 67 dB +Cable Attenuation at 7.0 GHz: 68 dB +Cable Attenuation at 12.9 GHz: 69 dB +Laser Wavelength: 233.000 nm +Wavelength Tolerance: 1106.800 nm |