Print this page
MFV: illumos-joyent@61dc3dec4f82a3e13e94609a0a83d5f66c64e760
OS-6846 want i40e multi-group support
OS-7372 i40e_alloc_ring_mem() unwinds when it shouldn't
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Author: Ryan Zezeski <rpz@joyent.com>
MFV: illumos-joyent@9e30beee2f0c127bf41868db46257124206e28d6
OS-5225 Want Fortville TSO support
Reviewed by: Ryan Zezeski <rpz@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Patrick Mooney <patrick.mooney@joyent.com>
Author: Rob Johnston <rob.johnston@joyent.com>
MFV: illumos-gate@286d309c80aad9eac1fdbcb0388ed194d995d837
9805 i40e should read SFP data when firmware supports it
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Rob Johnston <rob.johnston@joyent.com>
Reviewed by: Dale Ghent <dale.ghent@joyent.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Approved by: Dan McDonald <danmcd@joyent.com>
Author: Robert Mustacchi <rm@joyent.com>
NEX-13226 xvv710 25Gb NIC panics system under load
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-7822 40Gb Intel XL710 NIC performance data
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>

*** 9,19 **** * http://www.illumos.org/license/CDDL. */ /* * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. ! * Copyright (c) 2017, Joyent, Inc. * Copyright 2017 Tegile Systems, Inc. All rights reserved. */ /* * For more information, please see the big theory statement in i40e_main.c. --- 9,19 ---- * http://www.illumos.org/license/CDDL. */ /* * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. ! * Copyright (c) 2018, Joyent, Inc. * Copyright 2017 Tegile Systems, Inc. All rights reserved. */ /* * For more information, please see the big theory statement in i40e_main.c.
*** 37,47 **** }; static int i40e_group_remove_mac(void *arg, const uint8_t *mac_addr) { ! i40e_t *i40e = arg; struct i40e_aqc_remove_macvlan_element_data filt; struct i40e_hw *hw = &i40e->i40e_hw_space; int ret, i, last; i40e_uaddr_t *iua; --- 37,48 ---- }; static int i40e_group_remove_mac(void *arg, const uint8_t *mac_addr) { ! i40e_rx_group_t *rxg = arg; ! i40e_t *i40e = rxg->irg_i40e; struct i40e_aqc_remove_macvlan_element_data filt; struct i40e_hw *hw = &i40e->i40e_hw_space; int ret, i, last; i40e_uaddr_t *iua;
*** 105,115 **** } static int i40e_group_add_mac(void *arg, const uint8_t *mac_addr) { ! i40e_t *i40e = arg; struct i40e_hw *hw = &i40e->i40e_hw_space; int i, ret; i40e_uaddr_t *iua; struct i40e_aqc_add_macvlan_element_data filt; --- 106,117 ---- } static int i40e_group_add_mac(void *arg, const uint8_t *mac_addr) { ! i40e_rx_group_t *rxg = arg; ! i40e_t *i40e = rxg->irg_i40e; struct i40e_hw *hw = &i40e->i40e_hw_space; int i, ret; i40e_uaddr_t *iua; struct i40e_aqc_add_macvlan_element_data filt;
*** 134,153 **** ret = EEXIST; goto done; } } - /* - * Note, the general use of the i40e_vsi_id will have to be refactored - * when we have proper group support. - */ bzero(&filt, sizeof (filt)); bcopy(mac_addr, filt.mac_addr, ETHERADDRL); filt.flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH | I40E_AQC_MACVLAN_ADD_IGNORE_VLAN; ! if ((ret = i40e_aq_add_macvlan(hw, i40e->i40e_vsi_id, &filt, 1, NULL)) != I40E_SUCCESS) { i40e_error(i40e, "failed to add mac address " "%2x:%2x:%2x:%2x:%2x:%2x to unicast filter: %d", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], ret); --- 136,151 ---- ret = EEXIST; goto done; } } bzero(&filt, sizeof (filt)); bcopy(mac_addr, filt.mac_addr, ETHERADDRL); filt.flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH | I40E_AQC_MACVLAN_ADD_IGNORE_VLAN; ! if ((ret = i40e_aq_add_macvlan(hw, rxg->irg_vsi_seid, &filt, 1, NULL)) != I40E_SUCCESS) { i40e_error(i40e, "failed to add mac address " "%2x:%2x:%2x:%2x:%2x:%2x to unicast filter: %d", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], ret);
*** 155,165 **** goto done; } iua = &i40e->i40e_uaddrs[i40e->i40e_resources.ifr_nmacfilt_used]; bcopy(mac_addr, iua->iua_mac, ETHERADDRL); ! iua->iua_vsi = i40e->i40e_vsi_id; i40e->i40e_resources.ifr_nmacfilt_used++; ASSERT(i40e->i40e_resources.ifr_nmacfilt_used <= i40e->i40e_resources.ifr_nmacfilt); ret = 0; done: --- 153,163 ---- goto done; } iua = &i40e->i40e_uaddrs[i40e->i40e_resources.ifr_nmacfilt_used]; bcopy(mac_addr, iua->iua_mac, ETHERADDRL); ! iua->iua_vsi = rxg->irg_vsi_seid; i40e->i40e_resources.ifr_nmacfilt_used++; ASSERT(i40e->i40e_resources.ifr_nmacfilt_used <= i40e->i40e_resources.ifr_nmacfilt); ret = 0; done:
*** 225,235 **** ret = ECANCELED; goto done; } ! ret = i40e_aq_set_vsi_unicast_promiscuous(hw, i40e->i40e_vsi_id, on, NULL, B_FALSE); if (ret != I40E_SUCCESS) { i40e_error(i40e, "failed to %s unicast promiscuity on " "the default VSI: %d", on == B_TRUE ? "enable" : "disable", ret); --- 223,233 ---- ret = ECANCELED; goto done; } ! ret = i40e_aq_set_vsi_unicast_promiscuous(hw, I40E_DEF_VSI_SEID(i40e), on, NULL, B_FALSE); if (ret != I40E_SUCCESS) { i40e_error(i40e, "failed to %s unicast promiscuity on " "the default VSI: %d", on == B_TRUE ? "enable" : "disable", ret);
*** 244,254 **** if (i40e->i40e_mcast_promisc_count > 0) { i40e->i40e_promisc_on = on; goto done; } ! ret = i40e_aq_set_vsi_multicast_promiscuous(hw, i40e->i40e_vsi_id, on, NULL); if (ret != I40E_SUCCESS) { i40e_error(i40e, "failed to %s multicast promiscuity on " "the default VSI: %d", on == B_TRUE ? "enable" : "disable", ret); --- 242,252 ---- if (i40e->i40e_mcast_promisc_count > 0) { i40e->i40e_promisc_on = on; goto done; } ! ret = i40e_aq_set_vsi_multicast_promiscuous(hw, I40E_DEF_VSI_SEID(i40e), on, NULL); if (ret != I40E_SUCCESS) { i40e_error(i40e, "failed to %s multicast promiscuity on " "the default VSI: %d", on == B_TRUE ? "enable" : "disable", ret);
*** 255,266 **** /* * Try our best to put us back into a state that MAC expects us * to be in. */ ! ret = i40e_aq_set_vsi_unicast_promiscuous(hw, i40e->i40e_vsi_id, ! !on, NULL, B_FALSE); if (ret != I40E_SUCCESS) { i40e_error(i40e, "failed to %s unicast promiscuity on " "the default VSI after toggling multicast failed: " "%d", on == B_TRUE ? "disable" : "enable", ret); } --- 253,264 ---- /* * Try our best to put us back into a state that MAC expects us * to be in. */ ! ret = i40e_aq_set_vsi_unicast_promiscuous(hw, ! I40E_DEF_VSI_SEID(i40e), !on, NULL, B_FALSE); if (ret != I40E_SUCCESS) { i40e_error(i40e, "failed to %s unicast promiscuity on " "the default VSI after toggling multicast failed: " "%d", on == B_TRUE ? "disable" : "enable", ret); }
*** 292,306 **** if (i40e->i40e_resources.ifr_nmcastfilt_used == i40e->i40e_resources.ifr_nmcastfilt) { if (i40e->i40e_mcast_promisc_count == 0 && i40e->i40e_promisc_on == B_FALSE) { ret = i40e_aq_set_vsi_multicast_promiscuous(hw, ! i40e->i40e_vsi_id, B_TRUE, NULL); if (ret != I40E_SUCCESS) { i40e_error(i40e, "failed to enable multicast " "promiscuous mode on VSI %d: %d", ! i40e->i40e_vsi_id, ret); return (EIO); } } i40e->i40e_mcast_promisc_count++; return (0); --- 290,304 ---- if (i40e->i40e_resources.ifr_nmcastfilt_used == i40e->i40e_resources.ifr_nmcastfilt) { if (i40e->i40e_mcast_promisc_count == 0 && i40e->i40e_promisc_on == B_FALSE) { ret = i40e_aq_set_vsi_multicast_promiscuous(hw, ! I40E_DEF_VSI_SEID(i40e), B_TRUE, NULL); if (ret != I40E_SUCCESS) { i40e_error(i40e, "failed to enable multicast " "promiscuous mode on VSI %d: %d", ! I40E_DEF_VSI_SEID(i40e), ret); return (EIO); } } i40e->i40e_mcast_promisc_count++; return (0);
*** 310,320 **** bzero(&filt, sizeof (filt)); bcopy(multicast_address, filt.mac_addr, ETHERADDRL); filt.flags = I40E_AQC_MACVLAN_ADD_HASH_MATCH | I40E_AQC_MACVLAN_ADD_IGNORE_VLAN; ! if ((ret = i40e_aq_add_macvlan(hw, i40e->i40e_vsi_id, &filt, 1, NULL)) != I40E_SUCCESS) { i40e_error(i40e, "failed to add mac address " "%2x:%2x:%2x:%2x:%2x:%2x to multicast filter: %d", multicast_address[0], multicast_address[1], multicast_address[2], multicast_address[3], --- 308,318 ---- bzero(&filt, sizeof (filt)); bcopy(multicast_address, filt.mac_addr, ETHERADDRL); filt.flags = I40E_AQC_MACVLAN_ADD_HASH_MATCH | I40E_AQC_MACVLAN_ADD_IGNORE_VLAN; ! if ((ret = i40e_aq_add_macvlan(hw, I40E_DEF_VSI_SEID(i40e), &filt, 1, NULL)) != I40E_SUCCESS) { i40e_error(i40e, "failed to add mac address " "%2x:%2x:%2x:%2x:%2x:%2x to multicast filter: %d", multicast_address[0], multicast_address[1], multicast_address[2], multicast_address[3],
*** 351,362 **** bzero(&filt, sizeof (filt)); bcopy(multicast_address, filt.mac_addr, ETHERADDRL); filt.flags = I40E_AQC_MACVLAN_DEL_HASH_MATCH | I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; ! if (i40e_aq_remove_macvlan(hw, i40e->i40e_vsi_id, ! &filt, 1, NULL) != I40E_SUCCESS) { i40e_error(i40e, "failed to remove mac address " "%2x:%2x:%2x:%2x:%2x:%2x from multicast " "filter: %d", multicast_address[0], multicast_address[1], multicast_address[2], multicast_address[3], --- 349,360 ---- bzero(&filt, sizeof (filt)); bcopy(multicast_address, filt.mac_addr, ETHERADDRL); filt.flags = I40E_AQC_MACVLAN_DEL_HASH_MATCH | I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; ! if (i40e_aq_remove_macvlan(hw, I40E_DEF_VSI_SEID(i40e), &filt, ! 1, NULL) != I40E_SUCCESS) { i40e_error(i40e, "failed to remove mac address " "%2x:%2x:%2x:%2x:%2x:%2x from multicast " "filter: %d", multicast_address[0], multicast_address[1], multicast_address[2], multicast_address[3],
*** 379,393 **** if (i40e->i40e_mcast_promisc_count > 0) { if (i40e->i40e_mcast_promisc_count == 1 && i40e->i40e_promisc_on == B_FALSE) { ret = i40e_aq_set_vsi_multicast_promiscuous(hw, ! i40e->i40e_vsi_id, B_FALSE, NULL); if (ret != I40E_SUCCESS) { i40e_error(i40e, "failed to disable " "multicast promiscuous mode on VSI %d: %d", ! i40e->i40e_vsi_id, ret); return (EIO); } } i40e->i40e_mcast_promisc_count--; --- 377,391 ---- if (i40e->i40e_mcast_promisc_count > 0) { if (i40e->i40e_mcast_promisc_count == 1 && i40e->i40e_promisc_on == B_FALSE) { ret = i40e_aq_set_vsi_multicast_promiscuous(hw, ! I40E_DEF_VSI_SEID(i40e), B_FALSE, NULL); if (ret != I40E_SUCCESS) { i40e_error(i40e, "failed to disable " "multicast promiscuous mode on VSI %d: %d", ! I40E_DEF_VSI_SEID(i40e), ret); return (EIO); } } i40e->i40e_mcast_promisc_count--;
*** 488,498 **** /* * Note the group index here is expected to be -1 due to the fact that * we're not actually grouping things tx-wise at this time. */ ASSERT(group_index == -1); ! ASSERT(ring_index < i40e->i40e_num_trqpairs); itrq->itrq_mactxring = rh; infop->mri_driver = (mac_ring_driver_t)itrq; infop->mri_start = NULL; infop->mri_stop = NULL; --- 486,496 ---- /* * Note the group index here is expected to be -1 due to the fact that * we're not actually grouping things tx-wise at this time. */ ASSERT(group_index == -1); ! ASSERT(ring_index < i40e->i40e_num_trqpairs_per_vsi); itrq->itrq_mactxring = rh; infop->mri_driver = (mac_ring_driver_t)itrq; infop->mri_start = NULL; infop->mri_stop = NULL;
*** 514,532 **** 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) { i40e_t *i40e = arg; mac_intr_t *mintr = &infop->mri_intr; ! i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[ring_index]; ! /* ! * We assert the group number and ring index to help sanity check ! * ourselves and mark that we'll need to rework this when we have ! * multiple groups. ! */ ! ASSERT3S(group_index, ==, 0); ! ASSERT3S(ring_index, <, i40e->i40e_num_trqpairs); itrq->itrq_macrxring = rh; infop->mri_driver = (mac_ring_driver_t)itrq; infop->mri_start = i40e_ring_start; infop->mri_stop = NULL; --- 512,531 ---- 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) { i40e_t *i40e = arg; mac_intr_t *mintr = &infop->mri_intr; ! uint_t trqpair_index; ! i40e_trqpair_t *itrq; ! /* This assumes static groups. */ ! ASSERT3S(group_index, >=, 0); ! ASSERT3S(ring_index, >=, 0); ! trqpair_index = (group_index * i40e->i40e_num_trqpairs_per_vsi) + ! ring_index; ! ASSERT3U(trqpair_index, <, i40e->i40e_num_trqpairs); ! itrq = &i40e->i40e_trqpairs[trqpair_index]; itrq->itrq_macrxring = rh; infop->mri_driver = (mac_ring_driver_t)itrq; infop->mri_start = i40e_ring_start; infop->mri_stop = NULL;
*** 550,577 **** 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) { i40e_t *i40e = arg; if (rtype != MAC_RING_TYPE_RX) return; ! /* ! * Note, this is a simplified view of a group, given that we only have a ! * single group and a single ring at the moment. We'll want to expand ! * upon this as we leverage more hardware functionality. ! */ ! i40e->i40e_rx_group_handle = gh; ! infop->mgi_driver = (mac_group_driver_t)i40e; infop->mgi_start = NULL; infop->mgi_stop = NULL; infop->mgi_addmac = i40e_group_add_mac; infop->mgi_remmac = i40e_group_remove_mac; ! ASSERT(i40e->i40e_num_rx_groups == I40E_GROUP_MAX); ! infop->mgi_count = i40e->i40e_num_trqpairs; } static int i40e_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop) { --- 549,574 ---- 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) { i40e_t *i40e = arg; + i40e_rx_group_t *rxg; if (rtype != MAC_RING_TYPE_RX) return; ! rxg = &i40e->i40e_rx_groups[index]; ! rxg->irg_grp_hdl = gh; ! ! infop->mgi_driver = (mac_group_driver_t)rxg; infop->mgi_start = NULL; infop->mgi_stop = NULL; infop->mgi_addmac = i40e_group_add_mac; infop->mgi_remmac = i40e_group_remove_mac; ! ASSERT(i40e->i40e_num_rx_groups <= I40E_GROUP_MAX); ! infop->mgi_count = i40e->i40e_num_trqpairs_per_vsi; } static int i40e_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop) {
*** 580,589 **** --- 577,595 ---- if (id != 0 || infop == NULL) return (EINVAL); mutex_enter(&i40e->i40e_general_lock); + switch (i40e->i40e_hw_space.phy.link_info.module_type[0]) { + case I40E_MODULE_TYPE_SFP: + case I40E_MODULE_TYPE_QSFP: + break; + default: + mutex_exit(&i40e->i40e_general_lock); + return (ENOTSUP); + } + present = !!(i40e->i40e_hw_space.phy.link_info.link_info & I40E_AQ_MEDIA_AVAILABLE); if (present) { usable = !!(i40e->i40e_hw_space.phy.link_info.an_info & I40E_AQ_QUALIFIED_MODULE);
*** 597,606 **** --- 603,675 ---- return (0); } static int + i40e_transceiver_read(void *arg, uint_t id, uint_t page, void *buf, + size_t nbytes, off_t offset, size_t *nread) + { + i40e_t *i40e = arg; + struct i40e_hw *hw = &i40e->i40e_hw_space; + uint8_t *buf8 = buf; + size_t i; + + if (id != 0 || buf == NULL || nbytes == 0 || nread == NULL || + (page != 0xa0 && page != 0xa2) || offset < 0) + return (EINVAL); + + /* + * Both supported pages have a length of 256 bytes, ensure nothing asks + * us to go beyond that. + */ + if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256)) { + return (EINVAL); + } + + mutex_enter(&i40e->i40e_general_lock); + switch (i40e->i40e_hw_space.phy.link_info.module_type[0]) { + case I40E_MODULE_TYPE_SFP: + case I40E_MODULE_TYPE_QSFP: + break; + default: + mutex_exit(&i40e->i40e_general_lock); + return (ENOTSUP); + } + + /* + * Make sure we have a sufficiently new firmware version to run this + * command. This was introduced in firmware API 1.7. This is apparently + * only supported on the XL710 MAC, not the XL722. + */ + if (hw->mac.type != I40E_MAC_XL710 || hw->aq.api_maj_ver != 1 || + hw->aq.api_min_ver < 7) { + mutex_exit(&i40e->i40e_general_lock); + return (ENOTSUP); + } + + for (i = 0; i < nbytes; i++, offset++) { + enum i40e_status_code status; + uint32_t val; + + status = i40e_aq_get_phy_register(hw, + I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE, page, offset, + &val, NULL); + if (status != I40E_SUCCESS) { + mutex_exit(&i40e->i40e_general_lock); + return (EIO); + } + + buf8[i] = (uint8_t)val; + } + + mutex_exit(&i40e->i40e_general_lock); + *nread = nbytes; + + 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;
*** 658,690 **** if (i40e->i40e_tx_hcksum_enable == B_TRUE) *txflags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM; break; } case MAC_CAPAB_RINGS: cap_rings = cap_data; cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; switch (cap_rings->mr_type) { case MAC_RING_TYPE_TX: /* ! * Note, saying we have no rings, but some number of ! * groups indicates to MAC that it should create ! * psuedo-groups with one for each TX ring. This may not ! * be the long term behavior we want, but it'll work for ! * now. */ cap_rings->mr_gnum = 0; ! cap_rings->mr_rnum = i40e->i40e_num_trqpairs; cap_rings->mr_rget = i40e_fill_tx_ring; cap_rings->mr_gget = NULL; cap_rings->mr_gaddring = NULL; cap_rings->mr_gremring = NULL; break; case MAC_RING_TYPE_RX: cap_rings->mr_rnum = i40e->i40e_num_trqpairs; cap_rings->mr_rget = i40e_fill_rx_ring; ! cap_rings->mr_gnum = I40E_GROUP_MAX; cap_rings->mr_gget = i40e_fill_rx_group; cap_rings->mr_gaddring = NULL; cap_rings->mr_gremring = NULL; break; default: --- 727,771 ---- if (i40e->i40e_tx_hcksum_enable == B_TRUE) *txflags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM; break; } + case MAC_CAPAB_LSO: { + mac_capab_lso_t *cap_lso = cap_data; + + if (i40e->i40e_tx_lso_enable == B_TRUE) { + cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; + cap_lso->lso_basic_tcp_ipv4.lso_max = I40E_LSO_MAXLEN; + } else { + return (B_FALSE); + } + break; + } + case MAC_CAPAB_RINGS: cap_rings = cap_data; cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; switch (cap_rings->mr_type) { case MAC_RING_TYPE_TX: /* ! * Note, saying we have no groups, but some ! * number of rings indicates to MAC that it ! * should create psuedo-groups with one for ! * each TX ring. This may not be the long term ! * behavior we want, but it'll work for now. */ cap_rings->mr_gnum = 0; ! cap_rings->mr_rnum = i40e->i40e_num_trqpairs_per_vsi; cap_rings->mr_rget = i40e_fill_tx_ring; cap_rings->mr_gget = NULL; cap_rings->mr_gaddring = NULL; cap_rings->mr_gremring = NULL; break; case MAC_RING_TYPE_RX: cap_rings->mr_rnum = i40e->i40e_num_trqpairs; cap_rings->mr_rget = i40e_fill_rx_ring; ! cap_rings->mr_gnum = i40e->i40e_num_rx_groups; cap_rings->mr_gget = i40e_fill_rx_group; cap_rings->mr_gaddring = NULL; cap_rings->mr_gremring = NULL; break; default:
*** 700,710 **** * advertise the support for this capability. */ mct->mct_flags = 0; mct->mct_ntransceivers = 1; mct->mct_info = i40e_transceiver_info; ! mct->mct_read = NULL; return (B_TRUE); case MAC_CAPAB_LED: mcl = cap_data; --- 781,791 ---- * advertise the support for this capability. */ mct->mct_flags = 0; mct->mct_ntransceivers = 1; mct->mct_info = i40e_transceiver_info; ! mct->mct_read = i40e_transceiver_read; return (B_TRUE); case MAC_CAPAB_LED: mcl = cap_data;