summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@joyent.com>2017-11-29 00:11:03 +0000
committerRobert Mustacchi <rm@joyent.com>2018-02-10 17:49:45 +0000
commitc1e9c6963a28543aa11d020b08b333df83ad08ac (patch)
treebc7bd99e7d7a3d4e0191e0218b3f20c4375e8036
parentbf5d9f18edeb77c14df996d367853599bdd43fd1 (diff)
downloadillumos-joyent-c1e9c6963a28543aa11d020b08b333df83ad08ac.tar.gz
8871 Want means of toggling data link LEDs
8872 e1000g MAC_CAPAB_LED support 8873 i40e MAC_CAPAB_LED support 8874 igb MAC_CAPAB_LED support Reviewed by: Cody Mello <melloc@joyent.com> Reviewed by: Patrick Mooney <patrick.mooney@joyent.com> Reviewed by: Sebastian Wiedenroth <sebastian.wiedenroth@skylime.net> Reviewed by: Toomas Soome <tsoome@me.com> Reviewed by: Peter Tribble <peter.tribble@gmail.com> Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r--usr/src/cmd/dlutil/Makefile4
-rw-r--r--usr/src/cmd/dlutil/dlled.c285
-rw-r--r--usr/src/man/man9e/Makefile4
-rw-r--r--usr/src/man/man9e/mac_capab_led.9e228
-rw-r--r--usr/src/pkg/manifests/system-kernel.man9e.inc2
-rw-r--r--usr/src/pkg/manifests/system-network.mf1
-rw-r--r--usr/src/uts/common/io/dld/dld_drv.c99
-rw-r--r--usr/src/uts/common/io/e1000g/e1000g_main.c154
-rw-r--r--usr/src/uts/common/io/e1000g/e1000g_sw.h11
-rw-r--r--usr/src/uts/common/io/i40e/i40e_gld.c54
-rw-r--r--usr/src/uts/common/io/i40e/i40e_sw.h7
-rw-r--r--usr/src/uts/common/io/igb/igb_gld.c70
-rw-r--r--usr/src/uts/common/io/igb/igb_sw.h6
-rw-r--r--usr/src/uts/common/io/mac/mac.c108
-rw-r--r--usr/src/uts/common/io/mac/mac_provider.c2
-rw-r--r--usr/src/uts/common/sys/dld.h10
-rw-r--r--usr/src/uts/common/sys/mac.h13
-rw-r--r--usr/src/uts/common/sys/mac_impl.h15
-rw-r--r--usr/src/uts/common/sys/mac_provider.h14
19 files changed, 1080 insertions, 7 deletions
diff --git a/usr/src/cmd/dlutil/Makefile b/usr/src/cmd/dlutil/Makefile
index b037908c60..afbaf3a40d 100644
--- a/usr/src/cmd/dlutil/Makefile
+++ b/usr/src/cmd/dlutil/Makefile
@@ -13,7 +13,7 @@
# Copyright (c) 2017, Joyent, Inc.
#
-PROG= dltraninfo
+PROG= dltraninfo dlled
LINTPROGS= $(PROG:%=%.ln)
include ../Makefile.cmd
@@ -22,7 +22,9 @@ ROOTCMDDIR = $(ROOTLIB)/dl
CFLAGS += $(CCVERBOSE)
dltraninfo := LDLIBS += -ldladm -lsff -lnvpair
+dlled := LDLIBS += -ldladm
dltraninfo.ln := LDLIBS += -ldladm -lsff -lnvpair
+dlled.ln := LDLIBS += -ldladm
ROOTLIBDLFILES = $(PROG:%=$(ROOTLIB)/dl/%)
diff --git a/usr/src/cmd/dlutil/dlled.c b/usr/src/cmd/dlutil/dlled.c
new file mode 100644
index 0000000000..f919ef02e4
--- /dev/null
+++ b/usr/src/cmd/dlutil/dlled.c
@@ -0,0 +1,285 @@
+/*
+ * 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.
+ */
+
+/*
+ * Private utility to get and set LED information on NICs. This should really
+ * all be integrated into FM. Until we have figured out that plumbing, this
+ * allows us to have a little something that we can use to drive work.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <strings.h>
+
+#include <libdladm.h>
+#include <libdllink.h>
+#include <sys/mac.h>
+#include <sys/dld.h>
+#include <sys/dld_ioc.h>
+
+static const char *dlled_progname;
+static dladm_handle_t dlled_hdl;
+static char dlled_dlerrmsg[DLADM_STRSIZE];
+
+typedef struct dlled_led_map {
+ const char *dlm_name;
+ mac_led_mode_t dlm_bits;
+} dlled_led_map_t;
+
+static dlled_led_map_t dlled_map[] = {
+ { "default", MAC_LED_DEFAULT },
+ { "off", MAC_LED_OFF },
+ { "on", MAC_LED_ON },
+ { "ident", MAC_LED_IDENT }
+};
+
+#define DLLED_MAP_NENTRIES \
+ (sizeof (dlled_map) / sizeof (dlled_led_map_t))
+
+static void
+dlled_usage(const char *fmt, ...)
+{
+ if (fmt != NULL) {
+ va_list ap;
+
+ (void) fprintf(stderr, "%s: ", dlled_progname);
+ va_start(ap, fmt);
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+
+ (void) fprintf(stderr, "Usage: %s [-s mode] [link]\n"
+ "\n"
+ "\t-s mode set LED to mode\n",
+ dlled_progname);
+}
+
+static mac_led_mode_t
+dlled_parse_mode(const char *orig)
+{
+ char *mode;
+ char *part;
+ mac_led_mode_t m = 0;
+
+ mode = strdup(orig);
+ if (mode == NULL) {
+ fprintf(stderr, "failed to allocate memory to dup led "
+ "mode: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ part = strtok(mode, ",");
+ while (part != NULL) {
+ int i;
+
+ for (i = 0; i < DLLED_MAP_NENTRIES; i++) {
+ if (strcmp(dlled_map[i].dlm_name, part) == 0) {
+ m |= dlled_map[i].dlm_bits;
+ break;
+ }
+ }
+
+ if (i == DLLED_MAP_NENTRIES) {
+ fprintf(stderr, "unknown LED mode: %s\n", part);
+ exit(1);
+ }
+
+ part = strtok(NULL, ",");
+ }
+
+ free(mode);
+ if (m == 0) {
+ fprintf(stderr, "failed to parse %s: no valid modes "
+ "specified\n", orig);
+ exit(1);
+ }
+
+ return (m);
+}
+
+static void
+dlled_mode2str(mac_led_mode_t mode, char *buf, size_t len)
+{
+ int i;
+ boolean_t first = B_TRUE;
+ mac_led_mode_t orig = mode;
+
+ for (i = 0; i < DLLED_MAP_NENTRIES; i++) {
+ if ((mode & dlled_map[i].dlm_bits) != 0) {
+ if (first) {
+ first = B_FALSE;
+ } else {
+ (void) strlcat(buf, ",", len);
+ }
+ (void) strlcat(buf, dlled_map[i].dlm_name, len);
+ mode &= ~dlled_map[i].dlm_bits;
+ }
+ }
+
+ if (mode != 0) {
+ (void) snprintf(buf, len, "unknown mode: 0x%x\n", orig);
+ }
+}
+
+
+static int
+dlled_set(const char *link, mac_led_mode_t mode)
+{
+ datalink_id_t linkid;
+ dladm_status_t status;
+ dld_ioc_led_t dil;
+
+ if ((status = dladm_name2info(dlled_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, dlled_dlerrmsg));
+ return (1);
+ }
+
+ bzero(&dil, sizeof (dil));
+ dil.dil_linkid = linkid;
+ dil.dil_active = mode;
+
+ if (ioctl(dladm_dld_fd(dlled_hdl), DLDIOC_SETLED, &dil) != 0) {
+ (void) fprintf(stderr, "failed to set LED on "
+ "device %s: %s\n", link, strerror(errno));
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+dlled_get_led(dladm_handle_t hdl, datalink_id_t linkid, void *arg)
+{
+ dladm_status_t status;
+ char name[MAXLINKNAMELEN];
+ char supported[128], active[128];
+ dld_ioc_led_t dil;
+
+ 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,
+ dlled_dlerrmsg));
+ return (DLADM_WALK_CONTINUE);
+ }
+
+
+
+ bzero(&dil, sizeof (dil));
+ dil.dil_linkid = linkid;
+
+ if (ioctl(dladm_dld_fd(hdl), DLDIOC_GETLED, &dil) != 0) {
+ (void) fprintf(stderr, "failed to get LED information for "
+ "device %s: %s\n", name, strerror(errno));
+ return (DLADM_WALK_CONTINUE);
+ }
+
+ active[0] = '\0';
+ supported[0] = '\0';
+ dlled_mode2str(dil.dil_active, active, sizeof (active));
+ dlled_mode2str(dil.dil_supported, supported, sizeof (supported));
+
+ printf("%-20s %-12s %s\n", name, active, supported);
+
+ return (DLADM_WALK_CONTINUE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c, ret;
+ boolean_t opt_s = B_FALSE;
+ mac_led_mode_t set_mode = 0;
+ dladm_status_t status;
+
+ dlled_progname = basename(argv[0]);
+
+ while ((c = getopt(argc, argv, ":s:")) != -1) {
+ switch (c) {
+ case 's':
+ opt_s = B_TRUE;
+ set_mode = dlled_parse_mode(optarg);
+ break;
+ case ':':
+ dlled_usage("option -%c requires an operand\n", optopt);
+ return (2);
+ case '?':
+ default:
+ dlled_usage("unknown option: -%c\n", optopt);
+ return (2);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (opt_s && argc > 1) {
+ dlled_usage("-s only operates on a single datalink\n");
+ return (2);
+ }
+
+ if (opt_s && argc <= 0) {
+ dlled_usage("-s requires a datalink\n");
+ return (2);
+ }
+
+ if ((status = dladm_open(&dlled_hdl)) != DLADM_STATUS_OK) {
+ (void) fprintf(stderr, "failed to open /dev/dld: %s\n",
+ dladm_status2str(status, dlled_dlerrmsg));
+ return (1);
+ }
+
+ if (opt_s) {
+ return (dlled_set(argv[0], set_mode));
+ }
+
+ (void) printf("%-20s %-12s %s\n", "LINK", "ACTIVE", "SUPPORTED");
+
+ ret = 0;
+ if (argc == 0) {
+ (void) dladm_walk_datalink_id(dlled_get_led, dlled_hdl, NULL,
+ DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE,
+ DLADM_OPT_ACTIVE);
+ } else {
+ int i, dlret;
+ datalink_id_t linkid;
+
+ for (i = 0; i < argc; i++) {
+ if ((status = dladm_name2info(dlled_hdl, argv[i],
+ &linkid, NULL, NULL, NULL)) != DLADM_STATUS_OK) {
+ (void) fprintf(stderr, "failed to get link "
+ "id for link %s: %s\n", link,
+ dladm_status2str(status, dlled_dlerrmsg));
+ return (1);
+ }
+
+ dlret = dlled_get_led(dlled_hdl, linkid, NULL);
+ if (dlret != DLADM_WALK_CONTINUE) {
+ ret = 1;
+ break;
+ }
+ }
+ }
+
+ return (ret);
+}
diff --git a/usr/src/man/man9e/Makefile b/usr/src/man/man9e/Makefile
index 0c29674b11..8036f34cda 100644
--- a/usr/src/man/man9e/Makefile
+++ b/usr/src/man/man9e/Makefile
@@ -43,6 +43,7 @@ MANFILES= Intro.9e \
ks_update.9e \
mac.9e \
mac_capab_transceiver.9e \
+ mac_capab_led.9e \
mc_getcapab.9e \
mc_getprop.9e \
mc_getstat.9e \
@@ -112,6 +113,7 @@ MANLINKS= _info.9e \
MAC.9e \
mc_close.9e \
mc_stop.9e \
+ mcl_set.9e \
mct_info.9e \
mct_read.9e \
intro.9e \
@@ -151,6 +153,8 @@ gldm_stop.9e := LINKSRC = gld.9e
mc_close.9e := LINKSRC = mc_open.9e
mc_stop.9e := LINKSRC = mc_start.9e
+mcl_set.9e := LINKSRC = mac_capab_led.9e
+
mct_info.9e := LINKSRC = mac_capab_transceiver.9e
mct_read.9e := LINKSRC = mac_capab_transceiver.9e
diff --git a/usr/src/man/man9e/mac_capab_led.9e b/usr/src/man/man9e/mac_capab_led.9e
new file mode 100644
index 0000000000..cf6b3713d3
--- /dev/null
+++ b/usr/src/man/man9e/mac_capab_led.9e
@@ -0,0 +1,228 @@
+.\"
+.\" 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.
+.\"
+.Dd Feb 21, 2017
+.Dt MAC_CAPAB_LED 9E
+.Os
+.Sh NAME
+.Nm mac_capab_led ,
+.Nm mcl_set
+.Nd MAC LED capability
+.Sh SYNOPSIS
+.In sys/mac_provider.h
+.Vt typedef struct mac_capab_led mac_capab_led_t;
+.Vt typedef enum mac_led_mode mac_led_mode_t;
+.Ft int
+.Fo mcl_set
+.Fa "void *driver"
+.Fa "mac_led_mode_t mode"
+.Fa "uint_t flags"
+.Fc
+.Sh INTERFACE LEVEL
+.Sy Evolving -
+This interface is still evolving.
+API and ABI stability is not guaranteed.
+.Sh PARAMETERS
+.Bl -tag -width Fa
+.It Fa driver
+A pointer to the driver's private data that was passed in via the
+.Sy m_pdata
+member of the
+.Xr mac_register 9S
+structure to the
+.Xr mac_register 9F
+function.
+.It Fa mode
+A value that indicates how the driver should drive the LEDs.
+See the
+.Sx LED MODES
+section for a list of supported modes.
+.It Fa flags
+Reserved for future use.
+.El
+.Sh DESCRIPTION
+The
+.Sy MAC_CAPAB_LED
+capability allows GLDv3 device drivers to expose an interface for
+controlling the LEDs on the device.
+This allows the system to control the LEDs to assist system
+administrators in finding and identifying specific physical devices in
+the system.
+.Pp
+Implementing this capability is optional.
+For more information on how to handle capabilities and how to indicate
+that a capability is not supported, see
+.Xr mc_getcapab 9E .
+.Pp
+This capability should be implemented if the device in question provides
+a way to manipulate its LEDs.
+Generally the LEDs on a device default to indicating link status and
+activity.
+However, they can often be turned off or set to a specific pattern for
+identification purposes.
+.Ss LED MODES
+The system has a notion of different LED modes.
+Each LED mode suggests a different way that a device driver should drive
+the indicator LEDs on the device.
+While we generally want all such LED modes to be as uniform
+as possible, there is a limit to such similarities due to the
+capabilities of NICs.
+Each mode is a member of the
+.Vt mac_led_mode_t
+enumeration.
+The currently defined modes are:
+.Bl -tag -width Dv -offset indent
+.It Dv MAC_LED_DEFAULT
+This mode indicates that the device's default behavior should be used.
+This is usually some form of link status and activity.
+It is device specific and usually is the default behavior after a device
+is powered on.
+.It Dv MAC_LED_OFF
+This mode indicates that the device's LEDs should be turned off and not
+emit any light.
+.It Dv MAC_LED_ON
+This mode indicates that the device's LEDs should be turned on and
+remain solid.
+.It Dv MAC_LED_IDENT
+This mode indicates that the driver should emit some form of
+identification pattern.
+We suggest that devices indicate some form of solid blinking light that
+is on and off at alternating units of time, for example, every 200
+milliseconds.
+If it is possible to use an alternate color from the normal link up and
+activity lighting, that is recommended.
+.El
+.Ss MAC Capability Structure
+When the device driver's
+.Xr mc_getcapab 9E
+function entry point is called with the capability set to
+.Dv MAC_CAPAB_LED ,
+then the value of the capability structure is the following structure:
+.Bd -literal -offset indent
+typedef struct mac_capab_led {
+ uint_t mcl_flags;
+ mac_led_mode_t mcl_modes;
+ int (*mcl_set)(void *driver, mac_led_mode_t mode,
+ uint_t flags);
+} mac_capab_led_t;
+.Ed
+.Pp
+If the driver supports the
+.Dv MAC_CAPAB_LED
+capability, it should fill in this structure, based on the following
+rules:
+.Bl -tag -width Vt
+.It Fa mcl_flags
+The
+.Fa mcl_flags
+member is used to negotiate extensions with the driver.
+MAC will set the value of
+.Fa mcl_flags
+to include all of the currently known extensions.
+The driver should intersect this list with the set that they actually
+support.
+At this time, no such features are defined and the driver should set the
+member to
+.Sy 0 .
+.It Fa mcl_modes
+The
+.Fa mcl_modes
+member represents the support modes of the device driver.
+The device driver should set
+.Vt mcl_modes
+to the bitwise-inclusive-OR of the LED modes listed in
+.Sx LED MODES .
+.Pp
+If the driver does not support anything other than the default behavior
+of
+.Dv MAC_LED_DEFAULT ,
+then the device driver should not indicate that it supports this
+capability.
+.It Fa mcl_set
+The
+.Fa mcl_set
+entry point will be called by the MAC framework when it needs the device
+driver to change how it is driving its LEDs.
+Each call will ask the driver to change the display mode to the
+specified mode.
+The driver does not have to multiplex requests for multiple modes or
+keep track of what has been requested, that is taken care of by the
+system itself.
+.Pp
+The driver should first validate that
+.Fa mode
+is a mode that it supports.
+While the device reports the set of supported modes as a
+bitwise-inclusive-OR, the driver should only receive a single value in
+.Fa mode .
+The value of the
+.Fa flags
+argument is reserved for future use.
+Drivers must check that the value of flags is zero and if not, return
+.Er EINVAL .
+.Pp
+When this entry point is first called on a driver, it should snapshot
+its device registers such that it knows how to restore the default
+behavior.
+Because each method of programming the LEDs is different, it
+is up to the driver itself to take care of this, the broader framework
+cannot take care of it.
+.Pp
+If for some reason the driver is asked to program the same mode that it
+is already driving, then it need not do anything and should simply
+return success.
+.Pp
+Once the driver successfully changes the LED driving mode, it should
+return
+.Sy 0 .
+Otherwise, it should return the appropriate error number.
+For a full list of error numbers, see
+.Xr Intro 2 .
+Common values are:
+.Bl -tag -width Er -offset width
+.It Er EINVAL
+.Fa flag
+contains an unknown value.
+.It Er ENOTSUP
+.Fa mode
+is unsupported.
+.Fa flags
+contains an unsupported or unknown value.
+.It Er EIO
+An I/O error occurred while trying to program the device's registers.
+This could be because a command timed out or an FM-aware driver
+encountered an error.
+.El
+.Pp
+The broader framework will guarantee that only a single call to the
+.Fa mcl_set
+function is ongoing at any time.
+If other parts of the driver refer to the data used by the
+.Fa mcl_set
+function, then the driver must ensure that it is performing sufficient
+locking of its data.
+.El
+.Sh CONTEXT
+The
+.Ft mcl_set
+entry point will only be called from
+.Sy user
+or
+.Sy kernel
+context.
+It will never be called from interrupt context.
+.Sh SEE ALSO
+.Xr Intro 2 ,
+.Xr mac 9E ,
+.Xr mc_getcapab 9E ,
+.Xr mac_register 9F
diff --git a/usr/src/pkg/manifests/system-kernel.man9e.inc b/usr/src/pkg/manifests/system-kernel.man9e.inc
index b45d3cbabe..600a2bf7f9 100644
--- a/usr/src/pkg/manifests/system-kernel.man9e.inc
+++ b/usr/src/pkg/manifests/system-kernel.man9e.inc
@@ -37,6 +37,7 @@ file path=usr/share/man/man9e/ioctl.9e
file path=usr/share/man/man9e/ks_snapshot.9e
file path=usr/share/man/man9e/ks_update.9e
file path=usr/share/man/man9e/mac.9e
+file path=usr/share/man/man9e/mac_capab_led.9e
file path=usr/share/man/man9e/mac_capab_transceiver.9e
file path=usr/share/man/man9e/mc_getcapab.9e
file path=usr/share/man/man9e/mc_getprop.9e
@@ -95,6 +96,7 @@ link path=usr/share/man/man9e/gldv3.9e target=mac.9e
link path=usr/share/man/man9e/intro.9e target=Intro.9e
link path=usr/share/man/man9e/mc_close.9e target=mc_open.9e
link path=usr/share/man/man9e/mc_stop.9e target=mc_start.9e
+link path=usr/share/man/man9e/mcl_set.9e target=mac_capab_led.9e
link path=usr/share/man/man9e/mct_info.9e target=mac_capab_transceiver.9e
link path=usr/share/man/man9e/mct_read.9e target=mac_capab_transceiver.9e
link path=usr/share/man/man9e/tran_destroy_pkt.9e target=tran_init_pkt.9e
diff --git a/usr/src/pkg/manifests/system-network.mf b/usr/src/pkg/manifests/system-network.mf
index fd44515945..4f7a8978ff 100644
--- a/usr/src/pkg/manifests/system-network.mf
+++ b/usr/src/pkg/manifests/system-network.mf
@@ -83,6 +83,7 @@ file path=sbin/dlstat mode=0555
file path=sbin/flowadm mode=0555
file path=sbin/flowstat mode=0555
file path=sbin/ipadm mode=0555
+file path=usr/lib/dl/dlled mode=0555
file path=usr/lib/dl/dltraninfo mode=0555
file path=usr/share/man/man1m/dladm.1m
file path=usr/share/man/man1m/flowadm.1m
diff --git a/usr/src/uts/common/io/dld/dld_drv.c b/usr/src/uts/common/io/dld/dld_drv.c
index a2ca4cfb96..cfe0f78415 100644
--- a/usr/src/uts/common/io/dld/dld_drv.c
+++ b/usr/src/uts/common/io/dld/dld_drv.c
@@ -1407,6 +1407,99 @@ done:
return (ret);
}
+/* ARGSUSED */
+static int
+drv_ioc_getled(void *karg, intptr_t arg, int mode, cred_t *cred,
+ int *rvalp)
+{
+ int ret = 0;
+ mac_perim_handle_t mph = NULL;
+ dls_dl_handle_t dlh = NULL;
+ dls_link_t *dlp = NULL;
+ dld_ioc_led_t *dil = karg;
+
+ if ((mode & FREAD) == 0)
+ return (EBADF);
+
+ if ((ret = dls_devnet_hold_tmp(dil->dil_linkid, &dlh)) != 0)
+ goto done;
+
+ if ((ret = mac_perim_enter_by_macname(dls_devnet_mac(dlh), &mph)) != 0)
+ goto done;
+
+ if ((ret = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0)
+ goto done;
+
+ /*
+ * Make sure that this link belongs to the zone.
+ */
+ if (crgetzoneid(cred) != dls_devnet_getownerzid(dlh)) {
+ ret = ENOENT;
+ goto done;
+ }
+
+ ret = mac_led_get(dlp->dl_mh, &dil->dil_supported, &dil->dil_active);
+
+done:
+ if (dlp != NULL)
+ dls_link_rele(dlp);
+
+ if (mph != NULL)
+ mac_perim_exit(mph);
+
+ if (dlh != NULL)
+ dls_devnet_rele_tmp(dlh);
+
+ return (ret);
+}
+
+/* ARGSUSED */
+static int
+drv_ioc_setled(void *karg, intptr_t arg, int mode, cred_t *cred,
+ int *rvalp)
+{
+ int ret = 0;
+ mac_perim_handle_t mph = NULL;
+ dls_dl_handle_t dlh = NULL;
+ dls_link_t *dlp = NULL;
+ dld_ioc_led_t *dil = karg;
+
+ if ((mode & FWRITE) == 0)
+ return (EBADF);
+
+ if ((ret = dls_devnet_hold_tmp(dil->dil_linkid, &dlh)) != 0)
+ goto done;
+
+ if ((ret = mac_perim_enter_by_macname(dls_devnet_mac(dlh), &mph)) != 0)
+ goto done;
+
+ if ((ret = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0)
+ goto done;
+
+ /*
+ * Make sure that this link belongs to the zone.
+ */
+ if (crgetzoneid(cred) != dls_devnet_getownerzid(dlh)) {
+ ret = ENOENT;
+ goto done;
+ }
+
+ ret = mac_led_set(dlp->dl_mh, dil->dil_active);
+
+done:
+ if (dlp != NULL)
+ dls_link_rele(dlp);
+
+ if (mph != NULL)
+ mac_perim_exit(mph);
+
+ if (dlh != NULL)
+ dls_devnet_rele_tmp(dlh);
+
+ return (ret);
+}
+
+
/*
* Note that ioctls that modify links have a NULL di_priv_func(), as
* privileges can only be checked after we know the class of the link being
@@ -1449,7 +1542,11 @@ static dld_ioc_info_t drv_ioc_list[] = {
{DLDIOC_GETTRAN, DLDCOPYINOUT, sizeof (dld_ioc_gettran_t),
drv_ioc_gettran, NULL },
{DLDIOC_READTRAN, DLDCOPYINOUT, sizeof (dld_ioc_tranio_t),
- drv_ioc_readtran, NULL }
+ drv_ioc_readtran, NULL },
+ {DLDIOC_GETLED, DLDCOPYINOUT, sizeof (dld_ioc_led_t),
+ drv_ioc_getled, NULL },
+ {DLDIOC_SETLED, DLDCOPYIN, sizeof (dld_ioc_led_t),
+ drv_ioc_setled, secpolicy_dl_config}
};
typedef struct dld_ioc_modentry {
diff --git a/usr/src/uts/common/io/e1000g/e1000g_main.c b/usr/src/uts/common/io/e1000g/e1000g_main.c
index f08cde4525..de4ebc2971 100644
--- a/usr/src/uts/common/io/e1000g/e1000g_main.c
+++ b/usr/src/uts/common/io/e1000g/e1000g_main.c
@@ -25,7 +25,7 @@
/*
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- * Copyright 2016 Joyent, Inc.
+ * Copyright (c) 2017, Joyent, Inc.
*/
/*
@@ -1103,6 +1103,11 @@ e1000g_unattach(dev_info_t *devinfo, struct e1000g *Adapter)
private_devi_list_t *devi_node;
int result;
+ if (Adapter->e1000g_blink != NULL) {
+ ddi_periodic_delete(Adapter->e1000g_blink);
+ Adapter->e1000g_blink = NULL;
+ }
+
if (Adapter->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
(void) e1000g_disable_intrs(Adapter);
}
@@ -1265,6 +1270,9 @@ e1000g_init_locks(struct e1000g *Adapter)
mutex_init(&rx_ring->rx_lock, NULL,
MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri));
+
+ mutex_init(&Adapter->e1000g_led_lock, NULL,
+ MUTEX_DRIVER, DDI_INTR_PRI(Adapter->intr_pri));
}
static void
@@ -1273,6 +1281,8 @@ e1000g_destroy_locks(struct e1000g *Adapter)
e1000g_tx_ring_t *tx_ring;
e1000g_rx_ring_t *rx_ring;
+ mutex_destroy(&Adapter->e1000g_led_lock);
+
tx_ring = Adapter->tx_ring;
mutex_destroy(&tx_ring->tx_lock);
mutex_destroy(&tx_ring->usedlist_lock);
@@ -3132,6 +3142,110 @@ e1000g_fill_group(void *arg, mac_ring_type_t rtype, const int grp_index,
mintr->mi_disable = e1000g_rx_group_intr_disable;
}
+static void
+e1000g_led_blink(void *arg)
+{
+ e1000g_t *e1000g = arg;
+
+ mutex_enter(&e1000g->e1000g_led_lock);
+ VERIFY(e1000g->e1000g_emul_blink);
+ if (e1000g->e1000g_emul_state) {
+ (void) e1000_led_on(&e1000g->shared);
+ } else {
+ (void) e1000_led_off(&e1000g->shared);
+ }
+ e1000g->e1000g_emul_state = !e1000g->e1000g_emul_state;
+ mutex_exit(&e1000g->e1000g_led_lock);
+}
+
+static int
+e1000g_led_set(void *arg, mac_led_mode_t mode, uint_t flags)
+{
+ e1000g_t *e1000g = arg;
+
+ if (flags != 0)
+ return (EINVAL);
+
+ if (mode != MAC_LED_DEFAULT &&
+ mode != MAC_LED_IDENT &&
+ mode != MAC_LED_OFF &&
+ mode != MAC_LED_ON)
+ return (ENOTSUP);
+
+ mutex_enter(&e1000g->e1000g_led_lock);
+
+ if ((mode == MAC_LED_IDENT || mode == MAC_LED_OFF ||
+ mode == MAC_LED_ON) &&
+ !e1000g->e1000g_led_setup) {
+ if (e1000_setup_led(&e1000g->shared) != E1000_SUCCESS) {
+ mutex_exit(&e1000g->e1000g_led_lock);
+ return (EIO);
+ }
+
+ e1000g->e1000g_led_setup = B_TRUE;
+ }
+
+ if (mode != MAC_LED_IDENT && e1000g->e1000g_blink != NULL) {
+ ddi_periodic_t id = e1000g->e1000g_blink;
+ e1000g->e1000g_blink = NULL;
+ mutex_exit(&e1000g->e1000g_led_lock);
+ ddi_periodic_delete(id);
+ mutex_enter(&e1000g->e1000g_led_lock);
+ }
+
+ switch (mode) {
+ case MAC_LED_DEFAULT:
+ if (e1000g->e1000g_led_setup) {
+ if (e1000_cleanup_led(&e1000g->shared) !=
+ E1000_SUCCESS) {
+ mutex_exit(&e1000g->e1000g_led_lock);
+ return (EIO);
+ }
+ e1000g->e1000g_led_setup = B_FALSE;
+ }
+ break;
+ case MAC_LED_IDENT:
+ if (e1000g->e1000g_emul_blink) {
+ if (e1000g->e1000g_blink != NULL)
+ break;
+
+ /*
+ * Note, we use a 200 ms period here as that's what
+ * section 10.1.3 8254x Intel Manual (PCI/PCI-X Family
+ * of Gigabit Ethernet Controllers Software Developer's
+ * Manual) indicates that the optional blink hardware
+ * operates at.
+ */
+ e1000g->e1000g_blink =
+ ddi_periodic_add(e1000g_led_blink, e1000g,
+ 200ULL * (NANOSEC / MILLISEC), DDI_IPL_0);
+ } else if (e1000_blink_led(&e1000g->shared) != E1000_SUCCESS) {
+ mutex_exit(&e1000g->e1000g_led_lock);
+ return (EIO);
+ }
+ break;
+ case MAC_LED_OFF:
+ if (e1000_led_off(&e1000g->shared) != E1000_SUCCESS) {
+ mutex_exit(&e1000g->e1000g_led_lock);
+ return (EIO);
+ }
+ break;
+ case MAC_LED_ON:
+ if (e1000_led_on(&e1000g->shared) != E1000_SUCCESS) {
+ mutex_exit(&e1000g->e1000g_led_lock);
+ return (EIO);
+ }
+ break;
+ default:
+ mutex_exit(&e1000g->e1000g_led_lock);
+ return (ENOTSUP);
+ }
+
+ mutex_exit(&e1000g->e1000g_led_lock);
+ return (0);
+
+}
+
static boolean_t
e1000g_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
{
@@ -3174,6 +3288,44 @@ e1000g_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
cap_rings->mr_gget = e1000g_fill_group;
break;
}
+ case MAC_CAPAB_LED: {
+ mac_capab_led_t *cap_led = cap_data;
+
+ cap_led->mcl_flags = 0;
+ cap_led->mcl_modes = MAC_LED_DEFAULT;
+ if (Adapter->shared.mac.ops.blink_led != NULL &&
+ Adapter->shared.mac.ops.blink_led !=
+ e1000_null_ops_generic) {
+ cap_led->mcl_modes |= MAC_LED_IDENT;
+ }
+
+ if (Adapter->shared.mac.ops.led_off != NULL &&
+ Adapter->shared.mac.ops.led_off !=
+ e1000_null_ops_generic) {
+ cap_led->mcl_modes |= MAC_LED_OFF;
+ }
+
+ if (Adapter->shared.mac.ops.led_on != NULL &&
+ Adapter->shared.mac.ops.led_on !=
+ e1000_null_ops_generic) {
+ cap_led->mcl_modes |= MAC_LED_ON;
+ }
+
+ /*
+ * Some hardware doesn't support blinking natively as they're
+ * missing the optional blink circuit. If they have both off and
+ * on then we'll emulate it ourselves.
+ */
+ if (((cap_led->mcl_modes & MAC_LED_IDENT) == 0) &&
+ ((cap_led->mcl_modes & MAC_LED_OFF) != 0) &&
+ ((cap_led->mcl_modes & MAC_LED_ON) != 0)) {
+ cap_led->mcl_modes |= MAC_LED_IDENT;
+ Adapter->e1000g_emul_blink = B_TRUE;
+ }
+
+ cap_led->mcl_set = e1000g_led_set;
+ break;
+ }
default:
return (B_FALSE);
}
diff --git a/usr/src/uts/common/io/e1000g/e1000g_sw.h b/usr/src/uts/common/io/e1000g/e1000g_sw.h
index 261be80b1d..46fd5e964c 100644
--- a/usr/src/uts/common/io/e1000g/e1000g_sw.h
+++ b/usr/src/uts/common/io/e1000g/e1000g_sw.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012 David Höppner. All rights reserved.
- * Copyright 2016 Joyent, Inc.
+ * Copyright (c) 2017, Joyent, Inc.
*/
#ifndef _E1000G_SW_H
@@ -985,6 +985,15 @@ typedef struct e1000g {
uint16_t phy_lp_able; /* contents of PHY_LP_ABILITY */
/*
+ * LED Controls
+ */
+ kmutex_t e1000g_led_lock;
+ boolean_t e1000g_led_setup;
+ boolean_t e1000g_emul_blink;
+ boolean_t e1000g_emul_state;
+ ddi_periodic_t e1000g_blink;
+
+ /*
* FMA capabilities
*/
int fm_capabilities;
diff --git a/usr/src/uts/common/io/i40e/i40e_gld.c b/usr/src/uts/common/io/i40e/i40e_gld.c
index ea0718dfe7..9c7f860081 100644
--- a/usr/src/uts/common/io/i40e/i40e_gld.c
+++ b/usr/src/uts/common/io/i40e/i40e_gld.c
@@ -598,12 +598,57 @@ i40e_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop)
return (0);
}
+static int
+i40e_gld_led_set(void *arg, mac_led_mode_t mode, uint_t flags)
+{
+ i40e_t *i40e = arg;
+ struct i40e_hw *hw = &i40e->i40e_hw_space;
+
+ if (flags != 0)
+ return (EINVAL);
+
+ if (mode != MAC_LED_DEFAULT &&
+ mode != MAC_LED_IDENT &&
+ mode != MAC_LED_OFF &&
+ mode != MAC_LED_ON)
+ return (ENOTSUP);
+
+ if (mode != MAC_LED_DEFAULT && !i40e->i40e_led_saved) {
+ i40e->i40e_led_status = i40e_led_get(hw);
+ i40e->i40e_led_saved = B_TRUE;
+ }
+
+ switch (mode) {
+ case MAC_LED_DEFAULT:
+ if (i40e->i40e_led_saved) {
+ i40e_led_set(hw, i40e->i40e_led_status, B_FALSE);
+ i40e->i40e_led_status = 0;
+ i40e->i40e_led_saved = B_FALSE;
+ }
+ break;
+ case MAC_LED_IDENT:
+ i40e_led_set(hw, 0xf, B_TRUE);
+ break;
+ case MAC_LED_OFF:
+ i40e_led_set(hw, 0x0, B_FALSE);
+ break;
+ case MAC_LED_ON:
+ i40e_led_set(hw, 0xf, B_FALSE);
+ break;
+ default:
+ return (ENOTSUP);
+ }
+
+ return (0);
+}
+
static boolean_t
i40e_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
{
i40e_t *i40e = arg;
mac_capab_rings_t *cap_rings;
mac_capab_transceiver_t *mct;
+ mac_capab_led_t *mcl;
switch (cap) {
case MAC_CAPAB_HCKSUM: {
@@ -660,6 +705,15 @@ i40e_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
mct->mct_read = NULL;
return (B_TRUE);
+ case MAC_CAPAB_LED:
+ mcl = cap_data;
+
+ mcl->mcl_flags = 0;
+ mcl->mcl_modes = MAC_LED_DEFAULT | MAC_LED_IDENT | MAC_LED_OFF |
+ MAC_LED_ON;
+ mcl->mcl_set = i40e_gld_led_set;
+ break;
+
default:
return (B_FALSE);
}
diff --git a/usr/src/uts/common/io/i40e/i40e_sw.h b/usr/src/uts/common/io/i40e/i40e_sw.h
index 3c498623c4..78aced0144 100644
--- a/usr/src/uts/common/io/i40e/i40e_sw.h
+++ b/usr/src/uts/common/io/i40e/i40e_sw.h
@@ -882,6 +882,13 @@ typedef struct i40e {
*/
uint64_t i40e_s_link_status_errs;
uint32_t i40e_s_link_status_lasterr;
+
+ /*
+ * LED information. Note this state is only modified in
+ * i40e_gld_set_led() which is protected by MAC's serializer lock.
+ */
+ uint32_t i40e_led_status;
+ boolean_t i40e_led_saved;
} i40e_t;
/*
diff --git a/usr/src/uts/common/io/igb/igb_gld.c b/usr/src/uts/common/io/igb/igb_gld.c
index e9a75f5dfc..2bb4f99d6f 100644
--- a/usr/src/uts/common/io/igb/igb_gld.c
+++ b/usr/src/uts/common/io/igb/igb_gld.c
@@ -28,6 +28,7 @@
* Copyright 2013, Nexenta Systems, Inc. All rights reserved.
* Copyright 2014 Pluribus Networks Inc.
* Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved.
+ * Copyright (c) 2017, Joyent, Inc.
*/
#include "igb_sw.h"
@@ -887,6 +888,54 @@ igb_fill_group(void *arg, mac_ring_type_t rtype, const int index,
}
}
+static int
+igb_led_set(void *arg, mac_led_mode_t mode, uint_t flags)
+{
+ igb_t *igb = arg;
+
+ if (flags != 0)
+ return (EINVAL);
+
+ if (mode != MAC_LED_DEFAULT &&
+ mode != MAC_LED_IDENT &&
+ mode != MAC_LED_OFF &&
+ mode != MAC_LED_ON)
+ return (ENOTSUP);
+
+ if (mode != MAC_LED_DEFAULT && !igb->igb_led_setup) {
+ if (e1000_setup_led(&igb->hw) != E1000_SUCCESS)
+ return (EIO);
+
+ igb->igb_led_setup = B_TRUE;
+ }
+
+ switch (mode) {
+ case MAC_LED_DEFAULT:
+ if (igb->igb_led_setup) {
+ if (e1000_cleanup_led(&igb->hw) != E1000_SUCCESS)
+ return (EIO);
+ igb->igb_led_setup = B_FALSE;
+ }
+ break;
+ case MAC_LED_IDENT:
+ if (e1000_blink_led(&igb->hw) != E1000_SUCCESS)
+ return (EIO);
+ break;
+ case MAC_LED_OFF:
+ if (e1000_led_off(&igb->hw) != E1000_SUCCESS)
+ return (EIO);
+ break;
+ case MAC_LED_ON:
+ if (e1000_led_on(&igb->hw) != E1000_SUCCESS)
+ return (EIO);
+ break;
+ default:
+ return (ENOTSUP);
+ }
+
+ return (0);
+}
+
/*
* Obtain the MAC's capabilities and associated data from
* the driver.
@@ -951,6 +1000,27 @@ igb_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
break;
}
+ case MAC_CAPAB_LED: {
+ mac_capab_led_t *cap_led = cap_data;
+
+ cap_led->mcl_flags = 0;
+ cap_led->mcl_modes = MAC_LED_DEFAULT;
+ if (igb->hw.mac.ops.blink_led != NULL &&
+ igb->hw.mac.ops.blink_led != e1000_null_ops_generic) {
+ cap_led->mcl_modes |= MAC_LED_IDENT;
+ }
+ if (igb->hw.mac.ops.led_off != NULL &&
+ igb->hw.mac.ops.led_off != e1000_null_ops_generic) {
+ cap_led->mcl_modes |= MAC_LED_OFF;
+ }
+ if (igb->hw.mac.ops.led_on != NULL &&
+ igb->hw.mac.ops.led_on != e1000_null_ops_generic) {
+ cap_led->mcl_modes |= MAC_LED_ON;
+ }
+ cap_led->mcl_set = igb_led_set;
+ break;
+ }
+
default:
return (B_FALSE);
}
diff --git a/usr/src/uts/common/io/igb/igb_sw.h b/usr/src/uts/common/io/igb/igb_sw.h
index e6a0f6c277..f689c44b14 100644
--- a/usr/src/uts/common/io/igb/igb_sw.h
+++ b/usr/src/uts/common/io/igb/igb_sw.h
@@ -26,6 +26,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2014 Pluribus Networks Inc.
+ * Copyright (c) 2017, Joyent, Inc.
*/
#ifndef _IGB_SW_H
@@ -645,6 +646,11 @@ typedef struct igb {
struct ether_addr *mcast_table;
/*
+ * LED related functions
+ */
+ boolean_t igb_led_setup;
+
+ /*
* Kstat definitions
*/
kstat_t *igb_ks;
diff --git a/usr/src/uts/common/io/mac/mac.c b/usr/src/uts/common/io/mac/mac.c
index 1471ddba3e..c386eb2941 100644
--- a/usr/src/uts/common/io/mac/mac.c
+++ b/usr/src/uts/common/io/mac/mac.c
@@ -8146,3 +8146,111 @@ mac_transceiver_read(mac_handle_t mh, uint_t tranid, uint_t page, void *buf,
return (ret);
}
+
+void
+mac_led_init(mac_impl_t *mip)
+{
+ mip->mi_led_modes = MAC_LED_DEFAULT;
+
+ if (!mac_capab_get((mac_handle_t)mip, MAC_CAPAB_LED, &mip->mi_led)) {
+ bzero(&mip->mi_led, sizeof (mac_capab_led_t));
+ return;
+ }
+
+ if (mip->mi_led.mcl_flags != 0) {
+ dev_err(mip->mi_dip, CE_WARN, "driver set led capability "
+ "flags to invalid value: 0x%x, ignoring "
+ "capability", mip->mi_transceiver.mct_flags);
+ bzero(&mip->mi_led, sizeof (mac_capab_led_t));
+ return;
+ }
+
+ if ((mip->mi_led.mcl_modes & ~MAC_LED_ALL) != 0) {
+ dev_err(mip->mi_dip, CE_WARN, "driver set led capability "
+ "supported modes to invalid value: 0x%x, ignoring "
+ "capability", mip->mi_transceiver.mct_flags);
+ bzero(&mip->mi_led, sizeof (mac_capab_led_t));
+ return;
+ }
+}
+
+int
+mac_led_get(mac_handle_t mh, mac_led_mode_t *supported, mac_led_mode_t *active)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ ASSERT(MAC_PERIM_HELD(mh));
+
+ if (mip->mi_led.mcl_set == NULL)
+ return (ENOTSUP);
+
+ *supported = mip->mi_led.mcl_modes;
+ *active = mip->mi_led_modes;
+
+ return (0);
+}
+
+/*
+ * Update and multiplex the various LED requests. We only ever send one LED to
+ * the underlying driver at a time. As such, we end up multiplexing all
+ * requested states and picking one to send down to the driver.
+ */
+int
+mac_led_set(mac_handle_t mh, mac_led_mode_t desired)
+{
+ int ret;
+ mac_led_mode_t driver;
+
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ ASSERT(MAC_PERIM_HELD(mh));
+
+ /*
+ * If we've been passed a desired value of zero, that indicates that
+ * we're basically resetting to the value of zero, which is our default
+ * value.
+ */
+ if (desired == 0)
+ desired = MAC_LED_DEFAULT;
+
+ if (mip->mi_led.mcl_set == NULL)
+ return (ENOTSUP);
+
+ /*
+ * Catch both values that we don't know about and those that the driver
+ * doesn't support.
+ */
+ if ((desired & ~MAC_LED_ALL) != 0)
+ return (EINVAL);
+
+ if ((desired & ~mip->mi_led.mcl_modes) != 0)
+ return (ENOTSUP);
+
+ /*
+ * If we have the same value, then there is nothing to do.
+ */
+ if (desired == mip->mi_led_modes)
+ return (0);
+
+ /*
+ * Based on the desired value, determine what to send to the driver. We
+ * only will send a single bit to the driver at any given time. IDENT
+ * takes priority over OFF or ON. We also let OFF take priority over the
+ * rest.
+ */
+ if (desired & MAC_LED_IDENT) {
+ driver = MAC_LED_IDENT;
+ } else if (desired & MAC_LED_OFF) {
+ driver = MAC_LED_OFF;
+ } else if (desired & MAC_LED_ON) {
+ driver = MAC_LED_ON;
+ } else {
+ driver = MAC_LED_DEFAULT;
+ }
+
+ if ((ret = mip->mi_led.mcl_set(mip->mi_driver, driver, 0)) == 0) {
+ mip->mi_led_modes = desired;
+ }
+
+ return (ret);
+}
diff --git a/usr/src/uts/common/io/mac/mac_provider.c b/usr/src/uts/common/io/mac/mac_provider.c
index e2590ca641..07201afdec 100644
--- a/usr/src/uts/common/io/mac/mac_provider.c
+++ b/usr/src/uts/common/io/mac/mac_provider.c
@@ -355,6 +355,8 @@ mac_register(mac_register_t *mregp, mac_handle_t *mhp)
mac_transceiver_init(mip);
+ mac_led_init(mip);
+
/*
* Enforce the virtrualization level registered.
*/
diff --git a/usr/src/uts/common/sys/dld.h b/usr/src/uts/common/sys/dld.h
index 50febacbd8..06d74804bd 100644
--- a/usr/src/uts/common/sys/dld.h
+++ b/usr/src/uts/common/sys/dld.h
@@ -336,6 +336,16 @@ typedef struct dld_ioc_tranio {
uint64_t dti_buf;
} dld_ioc_tranio_t;
+#define DLDIOC_GETLED DLDIOC(0x20)
+#define DLDIOC_SETLED DLDIOC(0x21)
+
+typedef struct dld_ioc_led {
+ datalink_id_t dil_linkid;
+ mac_led_mode_t dil_supported;
+ mac_led_mode_t dil_active;
+ uint_t dil_pad;
+} dld_ioc_led_t;
+
#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
#pragma pack()
#endif
diff --git a/usr/src/uts/common/sys/mac.h b/usr/src/uts/common/sys/mac.h
index 101d652138..f3e22d660c 100644
--- a/usr/src/uts/common/sys/mac.h
+++ b/usr/src/uts/common/sys/mac.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2016 Joyent, Inc.
+ * Copyright (c) 2017, Joyent, Inc.
* Copyright (c) 2015 Garrett D'Amore <garrett@damore.org>
*/
@@ -242,6 +242,17 @@ typedef enum {
#define MAC_PROP_PERM_RW (MAC_PROP_PERM_READ|MAC_PROP_PERM_WRITE)
#define MAC_PROP_FLAGS_RK (MAC_PROP_PERM_READ|MAC_PROP_MAP_KSTAT)
+/*
+ * Valid LED mode bits
+ */
+typedef enum mac_led_mode {
+ MAC_LED_DEFAULT = (1 << 0),
+ MAC_LED_OFF = (1 << 1),
+ MAC_LED_IDENT = (1 << 2),
+ MAC_LED_ON = (1 << 3)
+} mac_led_mode_t;
+
+
#ifdef _KERNEL
/*
diff --git a/usr/src/uts/common/sys/mac_impl.h b/usr/src/uts/common/sys/mac_impl.h
index 2582a1914f..774c4fad9a 100644
--- a/usr/src/uts/common/sys/mac_impl.h
+++ b/usr/src/uts/common/sys/mac_impl.h
@@ -481,6 +481,12 @@ struct mac_impl_s {
mac_capab_transceiver_t mi_transceiver;
/*
+ * LED Capability information. SL protected.
+ */
+ mac_led_mode_t mi_led_modes;
+ mac_capab_led_t mi_led;
+
+ /*
* MAC address list. SL protected.
*/
mac_address_t *mi_addresses;
@@ -918,6 +924,15 @@ extern int mac_transceiver_info(mac_handle_t, uint_t, boolean_t *, boolean_t *);
extern int mac_transceiver_read(mac_handle_t, uint_t, uint_t, void *, size_t,
off_t, size_t *);
+/*
+ * MAC LED related functions
+ */
+#define MAC_LED_ALL (MAC_LED_DEFAULT | MAC_LED_OFF | MAC_LED_IDENT | \
+ MAC_LED_ON)
+extern void mac_led_init(mac_impl_t *);
+extern int mac_led_get(mac_handle_t, mac_led_mode_t *, mac_led_mode_t *);
+extern int mac_led_set(mac_handle_t, mac_led_mode_t);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/sys/mac_provider.h b/usr/src/uts/common/sys/mac_provider.h
index fb3d74c90f..4c91c03967 100644
--- a/usr/src/uts/common/sys/mac_provider.h
+++ b/usr/src/uts/common/sys/mac_provider.h
@@ -107,8 +107,9 @@ typedef enum {
MAC_CAPAB_NO_NATIVEVLAN = 0x00080000, /* boolean only, no data */
MAC_CAPAB_NO_ZCOPY = 0x00100000, /* boolean only, no data */
MAC_CAPAB_LEGACY = 0x00200000, /* data is mac_capab_legacy_t */
- MAC_CAPAB_VRRP = 0x00400000, /* data is mac_capab_vrrp_t */
- MAC_CAPAB_TRANSCEIVER = 0x01000000 /* mac_capab_transciever_t */
+ MAC_CAPAB_VRRP = 0x00400000, /* data is mac_capab_vrrp_t */
+ MAC_CAPAB_TRANSCEIVER = 0x01000000, /* mac_capab_transciever_t */
+ MAC_CAPAB_LED = 0x02000000 /* data is mac_capab_led_t */
} mac_capab_t;
/*
@@ -447,6 +448,15 @@ typedef struct mac_capab_transceiver {
} mac_capab_transceiver_t;
/*
+ * LED capability
+ */
+typedef struct mac_capab_led {
+ uint_t mcl_flags;
+ mac_led_mode_t mcl_modes;
+ int (*mcl_set)(void *, mac_led_mode_t, uint_t);
+} mac_capab_led_t;
+
+/*
* MAC registration interface
*/
typedef struct mac_register_s {