xref: /illumos-gate/usr/src/uts/common/io/i40e/i40e_gld.c (revision 6158afa4)
19d26e4fcSRobert Mustacchi /*
29d26e4fcSRobert Mustacchi  * This file and its contents are supplied under the terms of the
39d26e4fcSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
49d26e4fcSRobert Mustacchi  * You may only use this file in accordance with the terms of version
59d26e4fcSRobert Mustacchi  * 1.0 of the CDDL.
69d26e4fcSRobert Mustacchi  *
79d26e4fcSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
89d26e4fcSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
99d26e4fcSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
109d26e4fcSRobert Mustacchi  */
119d26e4fcSRobert Mustacchi 
129d26e4fcSRobert Mustacchi /*
139d26e4fcSRobert Mustacchi  * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
14*6158afa4SDan McDonald  * Copyright 2022 Joyent, Inc.
15396505afSPaul Winder  * Copyright 2017 Tegile Systems, Inc.  All rights reserved.
1688628b1bSRyan Zezeski  * Copyright 2020 Ryan Zezeski
17aa2a44afSPaul Winder  * Copyright 2020 RackTop Systems, Inc.
18df36e06dSRobert Mustacchi  * Copyright 2021 Oxide Computer Company
199d26e4fcSRobert Mustacchi  */
209d26e4fcSRobert Mustacchi 
219d26e4fcSRobert Mustacchi /*
229d26e4fcSRobert Mustacchi  * For more information, please see the big theory statement in i40e_main.c.
239d26e4fcSRobert Mustacchi  */
249d26e4fcSRobert Mustacchi 
259d26e4fcSRobert Mustacchi #include "i40e_sw.h"
269d26e4fcSRobert Mustacchi 
279d26e4fcSRobert Mustacchi #define	I40E_PROP_RX_DMA_THRESH	"_rx_dma_threshold"
289d26e4fcSRobert Mustacchi #define	I40E_PROP_TX_DMA_THRESH	"_tx_dma_threshold"
299d26e4fcSRobert Mustacchi #define	I40E_PROP_RX_ITR	"_rx_intr_throttle"
309d26e4fcSRobert Mustacchi #define	I40E_PROP_TX_ITR	"_tx_intr_throttle"
319d26e4fcSRobert Mustacchi #define	I40E_PROP_OTHER_ITR	"_other_intr_throttle"
329d26e4fcSRobert Mustacchi 
339d26e4fcSRobert Mustacchi char *i40e_priv_props[] = {
349d26e4fcSRobert Mustacchi 	I40E_PROP_RX_DMA_THRESH,
359d26e4fcSRobert Mustacchi 	I40E_PROP_TX_DMA_THRESH,
369d26e4fcSRobert Mustacchi 	I40E_PROP_RX_ITR,
379d26e4fcSRobert Mustacchi 	I40E_PROP_TX_ITR,
389d26e4fcSRobert Mustacchi 	I40E_PROP_OTHER_ITR,
399d26e4fcSRobert Mustacchi 	NULL
409d26e4fcSRobert Mustacchi };
419d26e4fcSRobert Mustacchi 
429d26e4fcSRobert Mustacchi static int
i40e_group_remove_mac(void * arg,const uint8_t * mac_addr)439d26e4fcSRobert Mustacchi i40e_group_remove_mac(void *arg, const uint8_t *mac_addr)
449d26e4fcSRobert Mustacchi {
4509aee612SRyan Zezeski 	i40e_rx_group_t *rxg = arg;
4609aee612SRyan Zezeski 	i40e_t *i40e = rxg->irg_i40e;
479d26e4fcSRobert Mustacchi 	struct i40e_aqc_remove_macvlan_element_data filt;
489d26e4fcSRobert Mustacchi 	struct i40e_hw *hw = &i40e->i40e_hw_space;
499d26e4fcSRobert Mustacchi 	int ret, i, last;
509d26e4fcSRobert Mustacchi 	i40e_uaddr_t *iua;
519d26e4fcSRobert Mustacchi 
529d26e4fcSRobert Mustacchi 	if (I40E_IS_MULTICAST(mac_addr))
539d26e4fcSRobert Mustacchi 		return (EINVAL);
549d26e4fcSRobert Mustacchi 
559d26e4fcSRobert Mustacchi 	mutex_enter(&i40e->i40e_general_lock);
569d26e4fcSRobert Mustacchi 
579d26e4fcSRobert Mustacchi 	if (i40e->i40e_state & I40E_SUSPENDED) {
589d26e4fcSRobert Mustacchi 		ret = ECANCELED;
599d26e4fcSRobert Mustacchi 		goto done;
609d26e4fcSRobert Mustacchi 	}
619d26e4fcSRobert Mustacchi 
629d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt_used; i++) {
639d26e4fcSRobert Mustacchi 		if (bcmp(mac_addr, i40e->i40e_uaddrs[i].iua_mac,
649d26e4fcSRobert Mustacchi 		    ETHERADDRL) == 0)
659d26e4fcSRobert Mustacchi 			break;
669d26e4fcSRobert Mustacchi 	}
679d26e4fcSRobert Mustacchi 
689d26e4fcSRobert Mustacchi 	if (i == i40e->i40e_resources.ifr_nmacfilt_used) {
699d26e4fcSRobert Mustacchi 		ret = ENOENT;
709d26e4fcSRobert Mustacchi 		goto done;
719d26e4fcSRobert Mustacchi 	}
729d26e4fcSRobert Mustacchi 
739d26e4fcSRobert Mustacchi 	iua = &i40e->i40e_uaddrs[i];
749d26e4fcSRobert Mustacchi 	ASSERT(i40e->i40e_resources.ifr_nmacfilt_used > 0);
759d26e4fcSRobert Mustacchi 
769d26e4fcSRobert Mustacchi 	bzero(&filt, sizeof (filt));
779d26e4fcSRobert Mustacchi 	bcopy(mac_addr, filt.mac_addr, ETHERADDRL);
789d26e4fcSRobert Mustacchi 	filt.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH |
799d26e4fcSRobert Mustacchi 	    I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
809d26e4fcSRobert Mustacchi 
819d26e4fcSRobert Mustacchi 	if (i40e_aq_remove_macvlan(hw, iua->iua_vsi, &filt, 1, NULL) !=
829d26e4fcSRobert Mustacchi 	    I40E_SUCCESS) {
839d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to remove mac address "
84*6158afa4SDan McDonald 		    "%02x:%02x:%02x:%02x:%02x:%02x from unicast filter: %d",
859d26e4fcSRobert Mustacchi 		    mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
869d26e4fcSRobert Mustacchi 		    mac_addr[4], mac_addr[5], filt.error_code);
879d26e4fcSRobert Mustacchi 		ret = EIO;
889d26e4fcSRobert Mustacchi 		goto done;
899d26e4fcSRobert Mustacchi 	}
909d26e4fcSRobert Mustacchi 
919d26e4fcSRobert Mustacchi 	last = i40e->i40e_resources.ifr_nmacfilt_used - 1;
929d26e4fcSRobert Mustacchi 	if (i != last) {
939d26e4fcSRobert Mustacchi 		i40e_uaddr_t *src = &i40e->i40e_uaddrs[last];
949d26e4fcSRobert Mustacchi 		bcopy(src, iua, sizeof (i40e_uaddr_t));
959d26e4fcSRobert Mustacchi 	}
969d26e4fcSRobert Mustacchi 
979d26e4fcSRobert Mustacchi 	/*
989d26e4fcSRobert Mustacchi 	 * Set the multicast bit in the last one to indicate to ourselves that
999d26e4fcSRobert Mustacchi 	 * it's invalid.
1009d26e4fcSRobert Mustacchi 	 */
1019d26e4fcSRobert Mustacchi 	bzero(&i40e->i40e_uaddrs[last], sizeof (i40e_uaddr_t));
1029d26e4fcSRobert Mustacchi 	i40e->i40e_uaddrs[last].iua_mac[0] = 0x01;
1039d26e4fcSRobert Mustacchi 	i40e->i40e_resources.ifr_nmacfilt_used--;
1049d26e4fcSRobert Mustacchi 	ret = 0;
1059d26e4fcSRobert Mustacchi done:
1069d26e4fcSRobert Mustacchi 	mutex_exit(&i40e->i40e_general_lock);
1079d26e4fcSRobert Mustacchi 
1089d26e4fcSRobert Mustacchi 	return (ret);
1099d26e4fcSRobert Mustacchi }
1109d26e4fcSRobert Mustacchi 
1119d26e4fcSRobert Mustacchi static int
i40e_group_add_mac(void * arg,const uint8_t * mac_addr)1129d26e4fcSRobert Mustacchi i40e_group_add_mac(void *arg, const uint8_t *mac_addr)
1139d26e4fcSRobert Mustacchi {
11409aee612SRyan Zezeski 	i40e_rx_group_t	*rxg = arg;
11509aee612SRyan Zezeski 	i40e_t		*i40e = rxg->irg_i40e;
11609aee612SRyan Zezeski 	struct i40e_hw	*hw = &i40e->i40e_hw_space;
11709aee612SRyan Zezeski 	int		i, ret;
11809aee612SRyan Zezeski 	i40e_uaddr_t	*iua;
1199d26e4fcSRobert Mustacchi 	struct i40e_aqc_add_macvlan_element_data filt;
1209d26e4fcSRobert Mustacchi 
1219d26e4fcSRobert Mustacchi 	if (I40E_IS_MULTICAST(mac_addr))
1229d26e4fcSRobert Mustacchi 		return (EINVAL);
1239d26e4fcSRobert Mustacchi 
1249d26e4fcSRobert Mustacchi 	mutex_enter(&i40e->i40e_general_lock);
1259d26e4fcSRobert Mustacchi 	if (i40e->i40e_state & I40E_SUSPENDED) {
1269d26e4fcSRobert Mustacchi 		ret = ECANCELED;
1279d26e4fcSRobert Mustacchi 		goto done;
1289d26e4fcSRobert Mustacchi 	}
1299d26e4fcSRobert Mustacchi 
1309d26e4fcSRobert Mustacchi 	if (i40e->i40e_resources.ifr_nmacfilt ==
1319d26e4fcSRobert Mustacchi 	    i40e->i40e_resources.ifr_nmacfilt_used) {
1329d26e4fcSRobert Mustacchi 		ret = ENOSPC;
1339d26e4fcSRobert Mustacchi 		goto done;
1349d26e4fcSRobert Mustacchi 	}
1359d26e4fcSRobert Mustacchi 
1369d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt_used; i++) {
1379d26e4fcSRobert Mustacchi 		if (bcmp(mac_addr, i40e->i40e_uaddrs[i].iua_mac,
1389d26e4fcSRobert Mustacchi 		    ETHERADDRL) == 0) {
1399d26e4fcSRobert Mustacchi 			ret = EEXIST;
1409d26e4fcSRobert Mustacchi 			goto done;
1419d26e4fcSRobert Mustacchi 		}
1429d26e4fcSRobert Mustacchi 	}
1439d26e4fcSRobert Mustacchi 
1449d26e4fcSRobert Mustacchi 	bzero(&filt, sizeof (filt));
1459d26e4fcSRobert Mustacchi 	bcopy(mac_addr, filt.mac_addr, ETHERADDRL);
1469d26e4fcSRobert Mustacchi 	filt.flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH	|
1479d26e4fcSRobert Mustacchi 	    I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
1489d26e4fcSRobert Mustacchi 
14909aee612SRyan Zezeski 	if ((ret = i40e_aq_add_macvlan(hw, rxg->irg_vsi_seid, &filt, 1,
1509d26e4fcSRobert Mustacchi 	    NULL)) != I40E_SUCCESS) {
1519d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to add mac address "
152*6158afa4SDan McDonald 		    "%02x:%02x:%02x:%02x:%02x:%02x to unicast filter: %d",
1539d26e4fcSRobert Mustacchi 		    mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
1549d26e4fcSRobert Mustacchi 		    mac_addr[4], mac_addr[5], ret);
1559d26e4fcSRobert Mustacchi 		ret = EIO;
1569d26e4fcSRobert Mustacchi 		goto done;
1579d26e4fcSRobert Mustacchi 	}
1589d26e4fcSRobert Mustacchi 
1599d26e4fcSRobert Mustacchi 	iua = &i40e->i40e_uaddrs[i40e->i40e_resources.ifr_nmacfilt_used];
1609d26e4fcSRobert Mustacchi 	bcopy(mac_addr, iua->iua_mac, ETHERADDRL);
16109aee612SRyan Zezeski 	iua->iua_vsi = rxg->irg_vsi_seid;
1629d26e4fcSRobert Mustacchi 	i40e->i40e_resources.ifr_nmacfilt_used++;
1639d26e4fcSRobert Mustacchi 	ASSERT(i40e->i40e_resources.ifr_nmacfilt_used <=
1649d26e4fcSRobert Mustacchi 	    i40e->i40e_resources.ifr_nmacfilt);
1659d26e4fcSRobert Mustacchi 	ret = 0;
1669d26e4fcSRobert Mustacchi done:
1679d26e4fcSRobert Mustacchi 	mutex_exit(&i40e->i40e_general_lock);
1689d26e4fcSRobert Mustacchi 	return (ret);
1699d26e4fcSRobert Mustacchi }
1709d26e4fcSRobert Mustacchi 
1719d26e4fcSRobert Mustacchi static int
i40e_m_start(void * arg)1729d26e4fcSRobert Mustacchi i40e_m_start(void *arg)
1739d26e4fcSRobert Mustacchi {
1749d26e4fcSRobert Mustacchi 	i40e_t *i40e = arg;
1759d26e4fcSRobert Mustacchi 	int rc = 0;
1769d26e4fcSRobert Mustacchi 
1779d26e4fcSRobert Mustacchi 	mutex_enter(&i40e->i40e_general_lock);
1789d26e4fcSRobert Mustacchi 	if (i40e->i40e_state & I40E_SUSPENDED) {
1799d26e4fcSRobert Mustacchi 		rc = ECANCELED;
1809d26e4fcSRobert Mustacchi 		goto done;
1819d26e4fcSRobert Mustacchi 	}
1829d26e4fcSRobert Mustacchi 
183aa2a44afSPaul Winder 	if (!i40e_start(i40e)) {
1849d26e4fcSRobert Mustacchi 		rc = EIO;
1859d26e4fcSRobert Mustacchi 		goto done;
1869d26e4fcSRobert Mustacchi 	}
1879d26e4fcSRobert Mustacchi 
1889d26e4fcSRobert Mustacchi 	atomic_or_32(&i40e->i40e_state, I40E_STARTED);
1899d26e4fcSRobert Mustacchi done:
1909d26e4fcSRobert Mustacchi 	mutex_exit(&i40e->i40e_general_lock);
1919d26e4fcSRobert Mustacchi 
1929d26e4fcSRobert Mustacchi 	return (rc);
1939d26e4fcSRobert Mustacchi }
1949d26e4fcSRobert Mustacchi 
1959d26e4fcSRobert Mustacchi static void
i40e_m_stop(void * arg)1969d26e4fcSRobert Mustacchi i40e_m_stop(void *arg)
1979d26e4fcSRobert Mustacchi {
1989d26e4fcSRobert Mustacchi 	i40e_t *i40e = arg;
1999d26e4fcSRobert Mustacchi 
2009d26e4fcSRobert Mustacchi 	mutex_enter(&i40e->i40e_general_lock);
2019d26e4fcSRobert Mustacchi 
2029d26e4fcSRobert Mustacchi 	if (i40e->i40e_state & I40E_SUSPENDED)
2039d26e4fcSRobert Mustacchi 		goto done;
2049d26e4fcSRobert Mustacchi 
2059d26e4fcSRobert Mustacchi 	atomic_and_32(&i40e->i40e_state, ~I40E_STARTED);
206aa2a44afSPaul Winder 	i40e_stop(i40e);
2079d26e4fcSRobert Mustacchi done:
2089d26e4fcSRobert Mustacchi 	mutex_exit(&i40e->i40e_general_lock);
2099d26e4fcSRobert Mustacchi }
2109d26e4fcSRobert Mustacchi 
2119d26e4fcSRobert Mustacchi /*
2129d26e4fcSRobert Mustacchi  * Enable and disable promiscuous mode as requested. We have to toggle both
2139d26e4fcSRobert Mustacchi  * unicast and multicast. Note that multicast may already be enabled due to the
2149d26e4fcSRobert Mustacchi  * i40e_m_multicast may toggle it itself. See i40e_main.c for more information
2159d26e4fcSRobert Mustacchi  * on this.
2169d26e4fcSRobert Mustacchi  */
2179d26e4fcSRobert Mustacchi static int
i40e_m_promisc(void * arg,boolean_t on)2189d26e4fcSRobert Mustacchi i40e_m_promisc(void *arg, boolean_t on)
2199d26e4fcSRobert Mustacchi {
2209d26e4fcSRobert Mustacchi 	i40e_t *i40e = arg;
2219d26e4fcSRobert Mustacchi 	struct i40e_hw *hw = &i40e->i40e_hw_space;
2229d26e4fcSRobert Mustacchi 	int ret = 0, err = 0;
2239d26e4fcSRobert Mustacchi 
2249d26e4fcSRobert Mustacchi 	mutex_enter(&i40e->i40e_general_lock);
2259d26e4fcSRobert Mustacchi 	if (i40e->i40e_state & I40E_SUSPENDED) {
2269d26e4fcSRobert Mustacchi 		ret = ECANCELED;
2279d26e4fcSRobert Mustacchi 		goto done;
2289d26e4fcSRobert Mustacchi 	}
2299d26e4fcSRobert Mustacchi 
2309d26e4fcSRobert Mustacchi 
23109aee612SRyan Zezeski 	ret = i40e_aq_set_vsi_unicast_promiscuous(hw, I40E_DEF_VSI_SEID(i40e),
2323d75a287SRobert Mustacchi 	    on, NULL, B_FALSE);
2339d26e4fcSRobert Mustacchi 	if (ret != I40E_SUCCESS) {
2349d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to %s unicast promiscuity on "
2359d26e4fcSRobert Mustacchi 		    "the default VSI: %d", on == B_TRUE ? "enable" : "disable",
2369d26e4fcSRobert Mustacchi 		    ret);
2379d26e4fcSRobert Mustacchi 		err = EIO;
2389d26e4fcSRobert Mustacchi 		goto done;
2399d26e4fcSRobert Mustacchi 	}
2409d26e4fcSRobert Mustacchi 
2419d26e4fcSRobert Mustacchi 	/*
2429d26e4fcSRobert Mustacchi 	 * If we have a non-zero mcast_promisc_count, then it has already been
2439d26e4fcSRobert Mustacchi 	 * enabled or we need to leave it that way and not touch it.
2449d26e4fcSRobert Mustacchi 	 */
2459d26e4fcSRobert Mustacchi 	if (i40e->i40e_mcast_promisc_count > 0) {
2469d26e4fcSRobert Mustacchi 		i40e->i40e_promisc_on = on;
2479d26e4fcSRobert Mustacchi 		goto done;
2489d26e4fcSRobert Mustacchi 	}
2499d26e4fcSRobert Mustacchi 
25009aee612SRyan Zezeski 	ret = i40e_aq_set_vsi_multicast_promiscuous(hw, I40E_DEF_VSI_SEID(i40e),
2519d26e4fcSRobert Mustacchi 	    on, NULL);
2529d26e4fcSRobert Mustacchi 	if (ret != I40E_SUCCESS) {
2539d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to %s multicast promiscuity on "
2549d26e4fcSRobert Mustacchi 		    "the default VSI: %d", on == B_TRUE ? "enable" : "disable",
2559d26e4fcSRobert Mustacchi 		    ret);
2569d26e4fcSRobert Mustacchi 
2579d26e4fcSRobert Mustacchi 		/*
2589d26e4fcSRobert Mustacchi 		 * Try our best to put us back into a state that MAC expects us
2599d26e4fcSRobert Mustacchi 		 * to be in.
2609d26e4fcSRobert Mustacchi 		 */
26109aee612SRyan Zezeski 		ret = i40e_aq_set_vsi_unicast_promiscuous(hw,
26209aee612SRyan Zezeski 		    I40E_DEF_VSI_SEID(i40e), !on, NULL, B_FALSE);
2639d26e4fcSRobert Mustacchi 		if (ret != I40E_SUCCESS) {
2649d26e4fcSRobert Mustacchi 			i40e_error(i40e, "failed to %s unicast promiscuity on "
2659d26e4fcSRobert Mustacchi 			    "the default VSI after toggling multicast failed: "
2669d26e4fcSRobert Mustacchi 			    "%d", on == B_TRUE ? "disable" : "enable", ret);
2679d26e4fcSRobert Mustacchi 		}
2689d26e4fcSRobert Mustacchi 
2699d26e4fcSRobert Mustacchi 		err = EIO;
2709d26e4fcSRobert Mustacchi 		goto done;
2719d26e4fcSRobert Mustacchi 	} else {
2729d26e4fcSRobert Mustacchi 		i40e->i40e_promisc_on = on;
2739d26e4fcSRobert Mustacchi 	}
2749d26e4fcSRobert Mustacchi 
2759d26e4fcSRobert Mustacchi done:
2769d26e4fcSRobert Mustacchi 	mutex_exit(&i40e->i40e_general_lock);
2779d26e4fcSRobert Mustacchi 	return (err);
2789d26e4fcSRobert Mustacchi }
2799d26e4fcSRobert Mustacchi 
2809d26e4fcSRobert Mustacchi /*
2819d26e4fcSRobert Mustacchi  * See the big theory statement in i40e_main.c for multicast address management.
2829d26e4fcSRobert Mustacchi  */
2839d26e4fcSRobert Mustacchi static int
i40e_multicast_add(i40e_t * i40e,const uint8_t * multicast_address)2849d26e4fcSRobert Mustacchi i40e_multicast_add(i40e_t *i40e, const uint8_t *multicast_address)
2859d26e4fcSRobert Mustacchi {
2869d26e4fcSRobert Mustacchi 	struct i40e_hw *hw = &i40e->i40e_hw_space;
2879d26e4fcSRobert Mustacchi 	struct i40e_aqc_add_macvlan_element_data filt;
2889d26e4fcSRobert Mustacchi 	i40e_maddr_t *mc;
2899d26e4fcSRobert Mustacchi 	int ret;
2909d26e4fcSRobert Mustacchi 
2919d26e4fcSRobert Mustacchi 	ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
2929d26e4fcSRobert Mustacchi 
2939d26e4fcSRobert Mustacchi 	if (i40e->i40e_resources.ifr_nmcastfilt_used ==
2949d26e4fcSRobert Mustacchi 	    i40e->i40e_resources.ifr_nmcastfilt) {
2959d26e4fcSRobert Mustacchi 		if (i40e->i40e_mcast_promisc_count == 0 &&
2969d26e4fcSRobert Mustacchi 		    i40e->i40e_promisc_on == B_FALSE) {
2979d26e4fcSRobert Mustacchi 			ret = i40e_aq_set_vsi_multicast_promiscuous(hw,
29809aee612SRyan Zezeski 			    I40E_DEF_VSI_SEID(i40e), B_TRUE, NULL);
2999d26e4fcSRobert Mustacchi 			if (ret != I40E_SUCCESS) {
3009d26e4fcSRobert Mustacchi 				i40e_error(i40e, "failed to enable multicast "
3019d26e4fcSRobert Mustacchi 				    "promiscuous mode on VSI %d: %d",
30209aee612SRyan Zezeski 				    I40E_DEF_VSI_SEID(i40e), ret);
3039d26e4fcSRobert Mustacchi 				return (EIO);
3049d26e4fcSRobert Mustacchi 			}
3059d26e4fcSRobert Mustacchi 		}
3069d26e4fcSRobert Mustacchi 		i40e->i40e_mcast_promisc_count++;
3079d26e4fcSRobert Mustacchi 		return (0);
3089d26e4fcSRobert Mustacchi 	}
3099d26e4fcSRobert Mustacchi 
3109d26e4fcSRobert Mustacchi 	mc = &i40e->i40e_maddrs[i40e->i40e_resources.ifr_nmcastfilt_used];
3119d26e4fcSRobert Mustacchi 	bzero(&filt, sizeof (filt));
3129d26e4fcSRobert Mustacchi 	bcopy(multicast_address, filt.mac_addr, ETHERADDRL);
3139d26e4fcSRobert Mustacchi 	filt.flags = I40E_AQC_MACVLAN_ADD_HASH_MATCH |
3149d26e4fcSRobert Mustacchi 	    I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
3159d26e4fcSRobert Mustacchi 
31609aee612SRyan Zezeski 	if ((ret = i40e_aq_add_macvlan(hw, I40E_DEF_VSI_SEID(i40e), &filt, 1,
3179d26e4fcSRobert Mustacchi 	    NULL)) != I40E_SUCCESS) {
3189d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to add mac address "
319*6158afa4SDan McDonald 		    "%02x:%02x:%02x:%02x:%02x:%02x to multicast filter: %d",
3209d26e4fcSRobert Mustacchi 		    multicast_address[0], multicast_address[1],
3219d26e4fcSRobert Mustacchi 		    multicast_address[2], multicast_address[3],
3229d26e4fcSRobert Mustacchi 		    multicast_address[4], multicast_address[5],
3239d26e4fcSRobert Mustacchi 		    ret);
3249d26e4fcSRobert Mustacchi 		return (EIO);
3259d26e4fcSRobert Mustacchi 	}
3269d26e4fcSRobert Mustacchi 
3279d26e4fcSRobert Mustacchi 	bcopy(multicast_address, mc->ima_mac, ETHERADDRL);
3289d26e4fcSRobert Mustacchi 	i40e->i40e_resources.ifr_nmcastfilt_used++;
3299d26e4fcSRobert Mustacchi 	return (0);
3309d26e4fcSRobert Mustacchi }
3319d26e4fcSRobert Mustacchi 
3329d26e4fcSRobert Mustacchi /*
3339d26e4fcSRobert Mustacchi  * See the big theory statement in i40e_main.c for multicast address management.
3349d26e4fcSRobert Mustacchi  */
3359d26e4fcSRobert Mustacchi static int
i40e_multicast_remove(i40e_t * i40e,const uint8_t * multicast_address)3369d26e4fcSRobert Mustacchi i40e_multicast_remove(i40e_t *i40e, const uint8_t *multicast_address)
3379d26e4fcSRobert Mustacchi {
3389d26e4fcSRobert Mustacchi 	int i, ret;
3399d26e4fcSRobert Mustacchi 	struct i40e_hw *hw = &i40e->i40e_hw_space;
3409d26e4fcSRobert Mustacchi 
3419d26e4fcSRobert Mustacchi 	ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
3429d26e4fcSRobert Mustacchi 
3439d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_resources.ifr_nmcastfilt_used; i++) {
3449d26e4fcSRobert Mustacchi 		struct i40e_aqc_remove_macvlan_element_data filt;
3459d26e4fcSRobert Mustacchi 		int last;
3469d26e4fcSRobert Mustacchi 
3479d26e4fcSRobert Mustacchi 		if (bcmp(multicast_address, i40e->i40e_maddrs[i].ima_mac,
3489d26e4fcSRobert Mustacchi 		    ETHERADDRL) != 0) {
3499d26e4fcSRobert Mustacchi 			continue;
3509d26e4fcSRobert Mustacchi 		}
3519d26e4fcSRobert Mustacchi 
3529d26e4fcSRobert Mustacchi 		bzero(&filt, sizeof (filt));
3539d26e4fcSRobert Mustacchi 		bcopy(multicast_address, filt.mac_addr, ETHERADDRL);
3549d26e4fcSRobert Mustacchi 		filt.flags = I40E_AQC_MACVLAN_DEL_HASH_MATCH |
3559d26e4fcSRobert Mustacchi 		    I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
3569d26e4fcSRobert Mustacchi 
35709aee612SRyan Zezeski 		if (i40e_aq_remove_macvlan(hw, I40E_DEF_VSI_SEID(i40e), &filt,
35809aee612SRyan Zezeski 		    1, NULL) != I40E_SUCCESS) {
3599d26e4fcSRobert Mustacchi 			i40e_error(i40e, "failed to remove mac address "
360*6158afa4SDan McDonald 			    "%02x:%02x:%02x:%02x:%02x:%02x from multicast "
3619d26e4fcSRobert Mustacchi 			    "filter: %d",
3629d26e4fcSRobert Mustacchi 			    multicast_address[0], multicast_address[1],
3639d26e4fcSRobert Mustacchi 			    multicast_address[2], multicast_address[3],
3649d26e4fcSRobert Mustacchi 			    multicast_address[4], multicast_address[5],
3659d26e4fcSRobert Mustacchi 			    filt.error_code);
3669d26e4fcSRobert Mustacchi 			return (EIO);
3679d26e4fcSRobert Mustacchi 		}
3689d26e4fcSRobert Mustacchi 
3699d26e4fcSRobert Mustacchi 		last = i40e->i40e_resources.ifr_nmcastfilt_used - 1;
3709d26e4fcSRobert Mustacchi 		if (i != last) {
3719d26e4fcSRobert Mustacchi 			bcopy(&i40e->i40e_maddrs[last], &i40e->i40e_maddrs[i],
3729d26e4fcSRobert Mustacchi 			    sizeof (i40e_maddr_t));
3739d26e4fcSRobert Mustacchi 			bzero(&i40e->i40e_maddrs[last], sizeof (i40e_maddr_t));
3749d26e4fcSRobert Mustacchi 		}
3759d26e4fcSRobert Mustacchi 
3769d26e4fcSRobert Mustacchi 		ASSERT(i40e->i40e_resources.ifr_nmcastfilt_used > 0);
3779d26e4fcSRobert Mustacchi 		i40e->i40e_resources.ifr_nmcastfilt_used--;
3789d26e4fcSRobert Mustacchi 		return (0);
3799d26e4fcSRobert Mustacchi 	}
3809d26e4fcSRobert Mustacchi 
3819d26e4fcSRobert Mustacchi 	if (i40e->i40e_mcast_promisc_count > 0) {
3829d26e4fcSRobert Mustacchi 		if (i40e->i40e_mcast_promisc_count == 1 &&
3839d26e4fcSRobert Mustacchi 		    i40e->i40e_promisc_on == B_FALSE) {
3849d26e4fcSRobert Mustacchi 			ret = i40e_aq_set_vsi_multicast_promiscuous(hw,
38509aee612SRyan Zezeski 			    I40E_DEF_VSI_SEID(i40e), B_FALSE, NULL);
3869d26e4fcSRobert Mustacchi 			if (ret != I40E_SUCCESS) {
3879d26e4fcSRobert Mustacchi 				i40e_error(i40e, "failed to disable "
3889d26e4fcSRobert Mustacchi 				    "multicast promiscuous mode on VSI %d: %d",
38909aee612SRyan Zezeski 				    I40E_DEF_VSI_SEID(i40e), ret);
3909d26e4fcSRobert Mustacchi 				return (EIO);
3919d26e4fcSRobert Mustacchi 			}
3929d26e4fcSRobert Mustacchi 		}
3939d26e4fcSRobert Mustacchi 		i40e->i40e_mcast_promisc_count--;
3949d26e4fcSRobert Mustacchi 
3959d26e4fcSRobert Mustacchi 		return (0);
3969d26e4fcSRobert Mustacchi 	}
3979d26e4fcSRobert Mustacchi 
3989d26e4fcSRobert Mustacchi 	return (ENOENT);
3999d26e4fcSRobert Mustacchi }
4009d26e4fcSRobert Mustacchi 
4019d26e4fcSRobert Mustacchi static int
i40e_m_multicast(void * arg,boolean_t add,const uint8_t * multicast_address)4029d26e4fcSRobert Mustacchi i40e_m_multicast(void *arg, boolean_t add, const uint8_t *multicast_address)
4039d26e4fcSRobert Mustacchi {
4049d26e4fcSRobert Mustacchi 	i40e_t *i40e = arg;
4059d26e4fcSRobert Mustacchi 	int rc;
4069d26e4fcSRobert Mustacchi 
4079d26e4fcSRobert Mustacchi 	mutex_enter(&i40e->i40e_general_lock);
4089d26e4fcSRobert Mustacchi 
4099d26e4fcSRobert Mustacchi 	if (i40e->i40e_state & I40E_SUSPENDED) {
4109d26e4fcSRobert Mustacchi 		mutex_exit(&i40e->i40e_general_lock);
4119d26e4fcSRobert Mustacchi 		return (ECANCELED);
4129d26e4fcSRobert Mustacchi 	}
4139d26e4fcSRobert Mustacchi 
4149d26e4fcSRobert Mustacchi 	if (add == B_TRUE) {
4159d26e4fcSRobert Mustacchi 		rc = i40e_multicast_add(i40e, multicast_address);
4169d26e4fcSRobert Mustacchi 	} else {
4179d26e4fcSRobert Mustacchi 		rc = i40e_multicast_remove(i40e, multicast_address);
4189d26e4fcSRobert Mustacchi 	}
4199d26e4fcSRobert Mustacchi 
4209d26e4fcSRobert Mustacchi 	mutex_exit(&i40e->i40e_general_lock);
4219d26e4fcSRobert Mustacchi 	return (rc);
4229d26e4fcSRobert Mustacchi }
4239d26e4fcSRobert Mustacchi 
4249d26e4fcSRobert Mustacchi /* ARGSUSED */
4259d26e4fcSRobert Mustacchi static void
i40e_m_ioctl(void * arg,queue_t * q,mblk_t * mp)4269d26e4fcSRobert Mustacchi i40e_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
4279d26e4fcSRobert Mustacchi {
4289d26e4fcSRobert Mustacchi 	/*
4299d26e4fcSRobert Mustacchi 	 * At this time, we don't support toggling i40e into loopback mode. It's
4309d26e4fcSRobert Mustacchi 	 * questionable how much value this has when there's no clear way to
4319d26e4fcSRobert Mustacchi 	 * toggle this behavior from a supported way in userland.
4329d26e4fcSRobert Mustacchi 	 */
4339d26e4fcSRobert Mustacchi 	miocnak(q, mp, 0, EINVAL);
4349d26e4fcSRobert Mustacchi }
4359d26e4fcSRobert Mustacchi 
4369d26e4fcSRobert Mustacchi static int
i40e_ring_start(mac_ring_driver_t rh,uint64_t gen_num)4379d26e4fcSRobert Mustacchi i40e_ring_start(mac_ring_driver_t rh, uint64_t gen_num)
4389d26e4fcSRobert Mustacchi {
4399d26e4fcSRobert Mustacchi 	i40e_trqpair_t *itrq = (i40e_trqpair_t *)rh;
440aa2a44afSPaul Winder 	int rv;
441aa2a44afSPaul Winder 
442aa2a44afSPaul Winder 	if ((rv = i40e_setup_ring(itrq)) != 0)
443aa2a44afSPaul Winder 		return (rv);
4449d26e4fcSRobert Mustacchi 
4459d26e4fcSRobert Mustacchi 	/*
4469d26e4fcSRobert Mustacchi 	 * GLDv3 requires we keep track of a generation number, as it uses
4479d26e4fcSRobert Mustacchi 	 * that number to keep track of whether or not a ring is active.
4489d26e4fcSRobert Mustacchi 	 */
4499d26e4fcSRobert Mustacchi 	mutex_enter(&itrq->itrq_rx_lock);
4509d26e4fcSRobert Mustacchi 	itrq->itrq_rxgen = gen_num;
4519d26e4fcSRobert Mustacchi 	mutex_exit(&itrq->itrq_rx_lock);
4529d26e4fcSRobert Mustacchi 	return (0);
4539d26e4fcSRobert Mustacchi }
4549d26e4fcSRobert Mustacchi 
455aa2a44afSPaul Winder static void
i40e_ring_stop(mac_ring_driver_t rh)456aa2a44afSPaul Winder i40e_ring_stop(mac_ring_driver_t rh)
457aa2a44afSPaul Winder {
458aa2a44afSPaul Winder 	i40e_trqpair_t *itrq = (i40e_trqpair_t *)rh;
459aa2a44afSPaul Winder 
460aa2a44afSPaul Winder 	if (!i40e_shutdown_ring(itrq)) {
461aa2a44afSPaul Winder 		i40e_t *i40e = itrq->itrq_i40e;
462aa2a44afSPaul Winder 
463aa2a44afSPaul Winder 		ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST);
464aa2a44afSPaul Winder 		i40e_error(i40e, "Failed to stop ring %u", itrq->itrq_index);
465aa2a44afSPaul Winder 	}
466aa2a44afSPaul Winder }
467aa2a44afSPaul Winder 
4689d26e4fcSRobert Mustacchi /* ARGSUSED */
4699d26e4fcSRobert Mustacchi static int
i40e_rx_ring_intr_enable(mac_intr_handle_t intrh)4709d26e4fcSRobert Mustacchi i40e_rx_ring_intr_enable(mac_intr_handle_t intrh)
4719d26e4fcSRobert Mustacchi {
4729d26e4fcSRobert Mustacchi 	i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh;
4739d26e4fcSRobert Mustacchi 
474396505afSPaul Winder 	mutex_enter(&itrq->itrq_rx_lock);
475396505afSPaul Winder 	ASSERT(itrq->itrq_intr_poll == B_TRUE);
476338749cbSRobert Mustacchi 	i40e_intr_rx_queue_enable(itrq);
477396505afSPaul Winder 	itrq->itrq_intr_poll = B_FALSE;
478396505afSPaul Winder 	mutex_exit(&itrq->itrq_rx_lock);
4799d26e4fcSRobert Mustacchi 
4809d26e4fcSRobert Mustacchi 	return (0);
4819d26e4fcSRobert Mustacchi }
4829d26e4fcSRobert Mustacchi 
4839d26e4fcSRobert Mustacchi /* ARGSUSED */
4849d26e4fcSRobert Mustacchi static int
i40e_rx_ring_intr_disable(mac_intr_handle_t intrh)4859d26e4fcSRobert Mustacchi i40e_rx_ring_intr_disable(mac_intr_handle_t intrh)
4869d26e4fcSRobert Mustacchi {
4879d26e4fcSRobert Mustacchi 	i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh;
4889d26e4fcSRobert Mustacchi 
489396505afSPaul Winder 	mutex_enter(&itrq->itrq_rx_lock);
490338749cbSRobert Mustacchi 	i40e_intr_rx_queue_disable(itrq);
491396505afSPaul Winder 	itrq->itrq_intr_poll = B_TRUE;
492396505afSPaul Winder 	mutex_exit(&itrq->itrq_rx_lock);
4939d26e4fcSRobert Mustacchi 
4949d26e4fcSRobert Mustacchi 	return (0);
4959d26e4fcSRobert Mustacchi }
4969d26e4fcSRobert Mustacchi 
4979d26e4fcSRobert Mustacchi /* ARGSUSED */
4989d26e4fcSRobert Mustacchi static void
i40e_fill_tx_ring(void * arg,mac_ring_type_t rtype,const int group_index,const int ring_index,mac_ring_info_t * infop,mac_ring_handle_t rh)4999d26e4fcSRobert Mustacchi i40e_fill_tx_ring(void *arg, mac_ring_type_t rtype, const int group_index,
5009d26e4fcSRobert Mustacchi     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
5019d26e4fcSRobert Mustacchi {
5029d26e4fcSRobert Mustacchi 	i40e_t *i40e = arg;
5039d26e4fcSRobert Mustacchi 	mac_intr_t *mintr = &infop->mri_intr;
5049d26e4fcSRobert Mustacchi 	i40e_trqpair_t *itrq = &(i40e->i40e_trqpairs[ring_index]);
5059d26e4fcSRobert Mustacchi 
5069d26e4fcSRobert Mustacchi 	/*
5079d26e4fcSRobert Mustacchi 	 * Note the group index here is expected to be -1 due to the fact that
5089d26e4fcSRobert Mustacchi 	 * we're not actually grouping things tx-wise at this time.
5099d26e4fcSRobert Mustacchi 	 */
5109d26e4fcSRobert Mustacchi 	ASSERT(group_index == -1);
51109aee612SRyan Zezeski 	ASSERT(ring_index < i40e->i40e_num_trqpairs_per_vsi);
5129d26e4fcSRobert Mustacchi 
5139d26e4fcSRobert Mustacchi 	itrq->itrq_mactxring = rh;
5149d26e4fcSRobert Mustacchi 	infop->mri_driver = (mac_ring_driver_t)itrq;
5159d26e4fcSRobert Mustacchi 	infop->mri_start = NULL;
5169d26e4fcSRobert Mustacchi 	infop->mri_stop = NULL;
5179d26e4fcSRobert Mustacchi 	infop->mri_tx = i40e_ring_tx;
5189d26e4fcSRobert Mustacchi 	infop->mri_stat = i40e_tx_ring_stat;
5199d26e4fcSRobert Mustacchi 
5209d26e4fcSRobert Mustacchi 	/*
5219d26e4fcSRobert Mustacchi 	 * We only provide the handle in cases where we have MSI-X interrupts,
5229d26e4fcSRobert Mustacchi 	 * to indicate that we'd actually support retargetting.
5239d26e4fcSRobert Mustacchi 	 */
5249d26e4fcSRobert Mustacchi 	if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) {
5259d26e4fcSRobert Mustacchi 		mintr->mi_ddi_handle =
5269d26e4fcSRobert Mustacchi 		    i40e->i40e_intr_handles[itrq->itrq_tx_intrvec];
5279d26e4fcSRobert Mustacchi 	}
5289d26e4fcSRobert Mustacchi }
5299d26e4fcSRobert Mustacchi 
5309d26e4fcSRobert Mustacchi /* ARGSUSED */
5319d26e4fcSRobert Mustacchi static void
i40e_fill_rx_ring(void * arg,mac_ring_type_t rtype,const int group_index,const int ring_index,mac_ring_info_t * infop,mac_ring_handle_t rh)5329d26e4fcSRobert Mustacchi i40e_fill_rx_ring(void *arg, mac_ring_type_t rtype, const int group_index,
5339d26e4fcSRobert Mustacchi     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
5349d26e4fcSRobert Mustacchi {
5359d26e4fcSRobert Mustacchi 	i40e_t *i40e = arg;
5369d26e4fcSRobert Mustacchi 	mac_intr_t *mintr = &infop->mri_intr;
53709aee612SRyan Zezeski 	uint_t trqpair_index;
53809aee612SRyan Zezeski 	i40e_trqpair_t *itrq;
5399d26e4fcSRobert Mustacchi 
54009aee612SRyan Zezeski 	/* This assumes static groups. */
54109aee612SRyan Zezeski 	ASSERT3S(group_index, >=, 0);
54209aee612SRyan Zezeski 	ASSERT3S(ring_index, >=, 0);
54309aee612SRyan Zezeski 	trqpair_index = (group_index * i40e->i40e_num_trqpairs_per_vsi) +
54409aee612SRyan Zezeski 	    ring_index;
54509aee612SRyan Zezeski 	ASSERT3U(trqpair_index, <, i40e->i40e_num_trqpairs);
54609aee612SRyan Zezeski 	itrq = &i40e->i40e_trqpairs[trqpair_index];
5479d26e4fcSRobert Mustacchi 
5489d26e4fcSRobert Mustacchi 	itrq->itrq_macrxring = rh;
5499d26e4fcSRobert Mustacchi 	infop->mri_driver = (mac_ring_driver_t)itrq;
5509d26e4fcSRobert Mustacchi 	infop->mri_start = i40e_ring_start;
551aa2a44afSPaul Winder 	infop->mri_stop = i40e_ring_stop;
5529d26e4fcSRobert Mustacchi 	infop->mri_poll = i40e_ring_rx_poll;
5539d26e4fcSRobert Mustacchi 	infop->mri_stat = i40e_rx_ring_stat;
5549d26e4fcSRobert Mustacchi 	mintr->mi_handle = (mac_intr_handle_t)itrq;
5559d26e4fcSRobert Mustacchi 	mintr->mi_enable = i40e_rx_ring_intr_enable;
5569d26e4fcSRobert Mustacchi 	mintr->mi_disable = i40e_rx_ring_intr_disable;
5579d26e4fcSRobert Mustacchi 
5589d26e4fcSRobert Mustacchi 	/*
5599d26e4fcSRobert Mustacchi 	 * We only provide the handle in cases where we have MSI-X interrupts,
5609d26e4fcSRobert Mustacchi 	 * to indicate that we'd actually support retargetting.
5619d26e4fcSRobert Mustacchi 	 */
5629d26e4fcSRobert Mustacchi 	if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) {
5639d26e4fcSRobert Mustacchi 		mintr->mi_ddi_handle =
5649d26e4fcSRobert Mustacchi 		    i40e->i40e_intr_handles[itrq->itrq_rx_intrvec];
5659d26e4fcSRobert Mustacchi 	}
5669d26e4fcSRobert Mustacchi }
5679d26e4fcSRobert Mustacchi 
5689d26e4fcSRobert Mustacchi /* ARGSUSED */
5699d26e4fcSRobert Mustacchi static void
i40e_fill_rx_group(void * arg,mac_ring_type_t rtype,const int index,mac_group_info_t * infop,mac_group_handle_t gh)5709d26e4fcSRobert Mustacchi i40e_fill_rx_group(void *arg, mac_ring_type_t rtype, const int index,
5719d26e4fcSRobert Mustacchi     mac_group_info_t *infop, mac_group_handle_t gh)
5729d26e4fcSRobert Mustacchi {
5739d26e4fcSRobert Mustacchi 	i40e_t *i40e = arg;
57409aee612SRyan Zezeski 	i40e_rx_group_t *rxg;
5759d26e4fcSRobert Mustacchi 
5769d26e4fcSRobert Mustacchi 	if (rtype != MAC_RING_TYPE_RX)
5779d26e4fcSRobert Mustacchi 		return;
5789d26e4fcSRobert Mustacchi 
57909aee612SRyan Zezeski 	rxg = &i40e->i40e_rx_groups[index];
58009aee612SRyan Zezeski 	rxg->irg_grp_hdl = gh;
58109aee612SRyan Zezeski 
58209aee612SRyan Zezeski 	infop->mgi_driver = (mac_group_driver_t)rxg;
5839d26e4fcSRobert Mustacchi 	infop->mgi_start = NULL;
5849d26e4fcSRobert Mustacchi 	infop->mgi_stop = NULL;
5859d26e4fcSRobert Mustacchi 	infop->mgi_addmac = i40e_group_add_mac;
5869d26e4fcSRobert Mustacchi 	infop->mgi_remmac = i40e_group_remove_mac;
5879d26e4fcSRobert Mustacchi 
58888628b1bSRyan Zezeski 	ASSERT3U(i40e->i40e_num_rx_groups, <=, I40E_MAX_NUM_RX_GROUPS);
58909aee612SRyan Zezeski 	infop->mgi_count = i40e->i40e_num_trqpairs_per_vsi;
5909d26e4fcSRobert Mustacchi }
5919d26e4fcSRobert Mustacchi 
59245d3dd98SRobert Mustacchi static int
i40e_transceiver_info(void * arg,uint_t id,mac_transceiver_info_t * infop)59345d3dd98SRobert Mustacchi i40e_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop)
59445d3dd98SRobert Mustacchi {
59545d3dd98SRobert Mustacchi 	boolean_t present, usable;
59645d3dd98SRobert Mustacchi 	i40e_t *i40e = arg;
59745d3dd98SRobert Mustacchi 
59845d3dd98SRobert Mustacchi 	if (id != 0 || infop == NULL)
59945d3dd98SRobert Mustacchi 		return (EINVAL);
60045d3dd98SRobert Mustacchi 
60145d3dd98SRobert Mustacchi 	mutex_enter(&i40e->i40e_general_lock);
602286d309cSRobert Mustacchi 	switch (i40e->i40e_hw_space.phy.link_info.module_type[0]) {
603286d309cSRobert Mustacchi 	case I40E_MODULE_TYPE_SFP:
604286d309cSRobert Mustacchi 	case I40E_MODULE_TYPE_QSFP:
605286d309cSRobert Mustacchi 		break;
606286d309cSRobert Mustacchi 	default:
607286d309cSRobert Mustacchi 		mutex_exit(&i40e->i40e_general_lock);
608286d309cSRobert Mustacchi 		return (ENOTSUP);
609286d309cSRobert Mustacchi 	}
610286d309cSRobert Mustacchi 
61145d3dd98SRobert Mustacchi 	present = !!(i40e->i40e_hw_space.phy.link_info.link_info &
61245d3dd98SRobert Mustacchi 	    I40E_AQ_MEDIA_AVAILABLE);
61345d3dd98SRobert Mustacchi 	if (present) {
61445d3dd98SRobert Mustacchi 		usable = !!(i40e->i40e_hw_space.phy.link_info.an_info &
61545d3dd98SRobert Mustacchi 		    I40E_AQ_QUALIFIED_MODULE);
61645d3dd98SRobert Mustacchi 	} else {
61745d3dd98SRobert Mustacchi 		usable = B_FALSE;
61845d3dd98SRobert Mustacchi 	}
61945d3dd98SRobert Mustacchi 	mutex_exit(&i40e->i40e_general_lock);
62045d3dd98SRobert Mustacchi 
62145d3dd98SRobert Mustacchi 	mac_transceiver_info_set_usable(infop, usable);
62245d3dd98SRobert Mustacchi 	mac_transceiver_info_set_present(infop, present);
62345d3dd98SRobert Mustacchi 
62445d3dd98SRobert Mustacchi 	return (0);
62545d3dd98SRobert Mustacchi }
62645d3dd98SRobert Mustacchi 
627286d309cSRobert Mustacchi static int
i40e_transceiver_read(void * arg,uint_t id,uint_t page,void * buf,size_t nbytes,off_t offset,size_t * nread)628286d309cSRobert Mustacchi i40e_transceiver_read(void *arg, uint_t id, uint_t page, void *buf,
629286d309cSRobert Mustacchi     size_t nbytes, off_t offset, size_t *nread)
630286d309cSRobert Mustacchi {
631286d309cSRobert Mustacchi 	i40e_t *i40e = arg;
632286d309cSRobert Mustacchi 	struct i40e_hw *hw = &i40e->i40e_hw_space;
633286d309cSRobert Mustacchi 	uint8_t *buf8 = buf;
634286d309cSRobert Mustacchi 	size_t i;
635286d309cSRobert Mustacchi 
636286d309cSRobert Mustacchi 	if (id != 0 || buf == NULL || nbytes == 0 || nread == NULL ||
637286d309cSRobert Mustacchi 	    (page != 0xa0 && page != 0xa2) || offset < 0)
638286d309cSRobert Mustacchi 		return (EINVAL);
639286d309cSRobert Mustacchi 
640286d309cSRobert Mustacchi 	/*
641286d309cSRobert Mustacchi 	 * Both supported pages have a length of 256 bytes, ensure nothing asks
642286d309cSRobert Mustacchi 	 * us to go beyond that.
643286d309cSRobert Mustacchi 	 */
644286d309cSRobert Mustacchi 	if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256)) {
645286d309cSRobert Mustacchi 		return (EINVAL);
646286d309cSRobert Mustacchi 	}
647286d309cSRobert Mustacchi 
648286d309cSRobert Mustacchi 	mutex_enter(&i40e->i40e_general_lock);
649286d309cSRobert Mustacchi 	switch (i40e->i40e_hw_space.phy.link_info.module_type[0]) {
650286d309cSRobert Mustacchi 	case I40E_MODULE_TYPE_SFP:
651286d309cSRobert Mustacchi 	case I40E_MODULE_TYPE_QSFP:
652286d309cSRobert Mustacchi 		break;
653286d309cSRobert Mustacchi 	default:
654286d309cSRobert Mustacchi 		mutex_exit(&i40e->i40e_general_lock);
655286d309cSRobert Mustacchi 		return (ENOTSUP);
656286d309cSRobert Mustacchi 	}
657286d309cSRobert Mustacchi 
658286d309cSRobert Mustacchi 	/*
659286d309cSRobert Mustacchi 	 * Make sure we have a sufficiently new firmware version to run this
660286d309cSRobert Mustacchi 	 * command. This was introduced in firmware API 1.7. This is apparently
661286d309cSRobert Mustacchi 	 * only supported on the XL710 MAC, not the XL722.
662286d309cSRobert Mustacchi 	 */
663286d309cSRobert Mustacchi 	if (hw->mac.type != I40E_MAC_XL710 || hw->aq.api_maj_ver != 1 ||
664286d309cSRobert Mustacchi 	    hw->aq.api_min_ver < 7) {
665286d309cSRobert Mustacchi 		mutex_exit(&i40e->i40e_general_lock);
666286d309cSRobert Mustacchi 		return (ENOTSUP);
667286d309cSRobert Mustacchi 	}
668286d309cSRobert Mustacchi 
669286d309cSRobert Mustacchi 	for (i = 0; i < nbytes; i++, offset++) {
670286d309cSRobert Mustacchi 		enum i40e_status_code status;
671286d309cSRobert Mustacchi 		uint32_t val;
672286d309cSRobert Mustacchi 
673286d309cSRobert Mustacchi 		status = i40e_aq_get_phy_register(hw,
674df36e06dSRobert Mustacchi 		    I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE, page, TRUE, offset,
675286d309cSRobert Mustacchi 		    &val, NULL);
676286d309cSRobert Mustacchi 		if (status != I40E_SUCCESS) {
677286d309cSRobert Mustacchi 			mutex_exit(&i40e->i40e_general_lock);
678286d309cSRobert Mustacchi 			return (EIO);
679286d309cSRobert Mustacchi 		}
680286d309cSRobert Mustacchi 
681286d309cSRobert Mustacchi 		buf8[i] = (uint8_t)val;
682286d309cSRobert Mustacchi 	}
683286d309cSRobert Mustacchi 
684286d309cSRobert Mustacchi 	mutex_exit(&i40e->i40e_general_lock);
685286d309cSRobert Mustacchi 	*nread = nbytes;
686286d309cSRobert Mustacchi 
687286d309cSRobert Mustacchi 	return (0);
688286d309cSRobert Mustacchi }
689286d309cSRobert Mustacchi 
690c1e9c696SRobert Mustacchi static int
i40e_gld_led_set(void * arg,mac_led_mode_t mode,uint_t flags)691c1e9c696SRobert Mustacchi i40e_gld_led_set(void *arg, mac_led_mode_t mode, uint_t flags)
692c1e9c696SRobert Mustacchi {
693c1e9c696SRobert Mustacchi 	i40e_t *i40e = arg;
694c1e9c696SRobert Mustacchi 	struct i40e_hw *hw = &i40e->i40e_hw_space;
695c1e9c696SRobert Mustacchi 
696c1e9c696SRobert Mustacchi 	if (flags != 0)
697c1e9c696SRobert Mustacchi 		return (EINVAL);
698c1e9c696SRobert Mustacchi 
699c1e9c696SRobert Mustacchi 	if (mode != MAC_LED_DEFAULT &&
700c1e9c696SRobert Mustacchi 	    mode != MAC_LED_IDENT &&
701c1e9c696SRobert Mustacchi 	    mode != MAC_LED_OFF &&
702c1e9c696SRobert Mustacchi 	    mode != MAC_LED_ON)
703c1e9c696SRobert Mustacchi 		return (ENOTSUP);
704c1e9c696SRobert Mustacchi 
705c1e9c696SRobert Mustacchi 	if (mode != MAC_LED_DEFAULT && !i40e->i40e_led_saved) {
706c1e9c696SRobert Mustacchi 		i40e->i40e_led_status = i40e_led_get(hw);
707c1e9c696SRobert Mustacchi 		i40e->i40e_led_saved = B_TRUE;
708c1e9c696SRobert Mustacchi 	}
709c1e9c696SRobert Mustacchi 
710c1e9c696SRobert Mustacchi 	switch (mode) {
711c1e9c696SRobert Mustacchi 	case MAC_LED_DEFAULT:
712c1e9c696SRobert Mustacchi 		if (i40e->i40e_led_saved) {
713c1e9c696SRobert Mustacchi 			i40e_led_set(hw, i40e->i40e_led_status, B_FALSE);
714c1e9c696SRobert Mustacchi 			i40e->i40e_led_status = 0;
715c1e9c696SRobert Mustacchi 			i40e->i40e_led_saved = B_FALSE;
716c1e9c696SRobert Mustacchi 		}
717c1e9c696SRobert Mustacchi 		break;
718c1e9c696SRobert Mustacchi 	case MAC_LED_IDENT:
719c1e9c696SRobert Mustacchi 		i40e_led_set(hw, 0xf, B_TRUE);
720c1e9c696SRobert Mustacchi 		break;
721c1e9c696SRobert Mustacchi 	case MAC_LED_OFF:
722c1e9c696SRobert Mustacchi 		i40e_led_set(hw, 0x0, B_FALSE);
723c1e9c696SRobert Mustacchi 		break;
724