8866 bnxe MAC_CAPAB_TRANSCEIVER support
[unleashed.git] / usr / src / uts / common / io / bnxe / bnxe_illumos.c
blob089fd773a8dbf274ef0b9b2945739eade2746739
1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright (c) 2017, Joyent, Inc.
17 * illumos specific bnxe related functions.
20 #include "bnxe.h"
23 * Try to figure out which phy we should be using at this time based on the
24 * requested transceiver.
26 static uint_t
27 bnxe_get_phy_id(um_device_t *um)
29 if (um->lm_dev.params.link.num_phys <= 1)
30 return (ELINK_INT_PHY);
32 if (um->lm_dev.vars.link.link_up) {
33 if ((um->lm_dev.vars.link.link_status &
34 LINK_STATUS_SERDES_LINK) &&
35 (um->lm_dev.params.link.phy[ELINK_EXT_PHY2].supported &
36 ELINK_SUPPORTED_FIBRE))
37 return (ELINK_EXT_PHY2);
38 return (ELINK_EXT_PHY1);
39 } else {
40 switch (elink_phy_selection(&um->lm_dev.params.link)) {
41 case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
42 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
43 case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
44 return (ELINK_EXT_PHY1);
45 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
46 case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
47 return (ELINK_EXT_PHY2);
49 * The above hardware types are the only ones currently defined
50 * by the specification and common code. If we end up with an
51 * unknown value, then we default to what the hardware considers
52 * the default, which is PHY1.
54 default:
55 return (ELINK_EXT_PHY1);
60 static int
61 bnxe_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop)
63 uint_t phyid;
64 um_device_t *um = arg;
65 struct elink_params *params;
66 struct elink_phy *phy;
67 boolean_t present = B_FALSE, usable = B_FALSE;
68 elink_status_t ret;
69 uint8_t buf;
71 if (id != 0 || arg == NULL || infop == NULL)
72 return (EINVAL);
74 BNXE_LOCK_ENTER_PHY(um);
75 phyid = bnxe_get_phy_id(um);
76 params = &um->lm_dev.params.link;
77 phy = &params->phy[phyid];
78 if (phy->media_type == ELINK_ETH_PHY_BASE_T) {
79 BNXE_LOCK_EXIT_PHY(um);
80 return (ENOTSUP);
84 * Right now, the core OS-independent code from QLogic doesn't quite
85 * track whether or not the phy is plugged in, though it easily could.
86 * As such, the best way to determine whether or not the phy is present
87 * is to see if we can read the first byte from page 0xa0. We expect to
88 * get an explicit timeout if the device isn't present. We'll propagate
89 * EIO on any other error as we're not in a good state to understand
90 * what happened.
92 PHY_HW_LOCK(&um->lm_dev);
93 ret = elink_read_sfp_module_eeprom(phy, params, 0xa0, 0, sizeof (buf),
94 &buf);
95 PHY_HW_UNLOCK(&um->lm_dev);
96 if (ret != ELINK_STATUS_OK && ret != ELINK_STATUS_TIMEOUT) {
97 BNXE_LOCK_EXIT_PHY(um);
98 return (EIO);
100 if (ret == ELINK_STATUS_OK) {
101 present = B_TRUE;
102 if ((phy->flags & ELINK_FLAGS_SFP_NOT_APPROVED) == 0)
103 usable = B_TRUE;
105 BNXE_LOCK_EXIT_PHY(um);
107 mac_transceiver_info_set_present(infop, present);
108 mac_transceiver_info_set_usable(infop, usable);
110 return (0);
113 static int
114 bnxe_transceiver_read(void *arg, uint_t id, uint_t page, void *bp,
115 size_t nbytes, off_t offset, size_t *nread)
117 uint_t phyid;
118 um_device_t *um = arg;
119 struct elink_phy *phy;
120 struct elink_params *params;
121 elink_status_t ret;
123 if (id != 0 || bp == NULL || nbytes == 0 || nread == NULL ||
124 (page != 0xa0 && page != 0xa2) || offset < 0)
125 return (EINVAL);
128 * Sanity check length params.
130 if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256)) {
131 return (EINVAL);
134 BNXE_LOCK_ENTER_PHY(um);
135 phyid = bnxe_get_phy_id(um);
136 params = &um->lm_dev.params.link;
137 phy = &um->lm_dev.params.link.phy[phyid];
139 if (phy->media_type == ELINK_ETH_PHY_BASE_T) {
140 BNXE_LOCK_EXIT_PHY(um);
141 return (ENOTSUP);
145 PHY_HW_LOCK(&um->lm_dev);
146 ret = elink_read_sfp_module_eeprom(phy, params, (uint8_t)page,
147 (uint16_t)offset, (uint16_t)nbytes, bp);
148 PHY_HW_UNLOCK(&um->lm_dev);
150 BNXE_LOCK_EXIT_PHY(um);
152 switch (ret) {
153 case ELINK_STATUS_OK:
154 *nread = nbytes;
155 return (0);
156 case ELINK_OP_NOT_SUPPORTED:
157 return (ENOTSUP);
158 default:
159 return (EIO);
163 boolean_t
164 bnxe_fill_transceiver(um_device_t *um, void *arg)
166 uint_t ntran = 1;
167 mac_capab_transceiver_t *mct = arg;
169 mct->mct_flags = 0;
171 * While there is nominally a dual-phy version of bnxe out there (see
172 * ELINK_DUAL_MEDIA and related macros), these haven't been seen in the
173 * wild. For now, only assume that we have a single phy.
175 mct->mct_ntransceivers = 1;
176 mct->mct_info = bnxe_transceiver_info;
177 mct->mct_read = bnxe_transceiver_read;
179 return (B_TRUE);