diff options
| author | Robert Mustacchi <rm@joyent.com> | 2017-11-29 00:11:03 +0000 |
|---|---|---|
| committer | Robert Mustacchi <rm@joyent.com> | 2018-02-10 17:49:45 +0000 |
| commit | c1e9c6963a28543aa11d020b08b333df83ad08ac (patch) | |
| tree | bc7bd99e7d7a3d4e0191e0218b3f20c4375e8036 | |
| parent | bf5d9f18edeb77c14df996d367853599bdd43fd1 (diff) | |
| download | illumos-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/Makefile | 4 | ||||
| -rw-r--r-- | usr/src/cmd/dlutil/dlled.c | 285 | ||||
| -rw-r--r-- | usr/src/man/man9e/Makefile | 4 | ||||
| -rw-r--r-- | usr/src/man/man9e/mac_capab_led.9e | 228 | ||||
| -rw-r--r-- | usr/src/pkg/manifests/system-kernel.man9e.inc | 2 | ||||
| -rw-r--r-- | usr/src/pkg/manifests/system-network.mf | 1 | ||||
| -rw-r--r-- | usr/src/uts/common/io/dld/dld_drv.c | 99 | ||||
| -rw-r--r-- | usr/src/uts/common/io/e1000g/e1000g_main.c | 154 | ||||
| -rw-r--r-- | usr/src/uts/common/io/e1000g/e1000g_sw.h | 11 | ||||
| -rw-r--r-- | usr/src/uts/common/io/i40e/i40e_gld.c | 54 | ||||
| -rw-r--r-- | usr/src/uts/common/io/i40e/i40e_sw.h | 7 | ||||
| -rw-r--r-- | usr/src/uts/common/io/igb/igb_gld.c | 70 | ||||
| -rw-r--r-- | usr/src/uts/common/io/igb/igb_sw.h | 6 | ||||
| -rw-r--r-- | usr/src/uts/common/io/mac/mac.c | 108 | ||||
| -rw-r--r-- | usr/src/uts/common/io/mac/mac_provider.c | 2 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/dld.h | 10 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/mac.h | 13 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/mac_impl.h | 15 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/mac_provider.h | 14 |
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 { |
