6324 Add an `ndp' tool for manipulating the neighbors table
[illumos-gate.git] / usr / src / uts / common / io / fcoe / fcoe_eth.c
blob6332327f5ec9669db376f77eafebebbecf57b93a
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <sys/inttypes.h>
30 #include <sys/strsun.h>
31 #include <sys/mac_client.h>
34 * FCoE header files
36 #include <sys/fcoe/fcoeio.h>
37 #include <sys/fcoe/fcoe_common.h>
40 * Driver's own header files
42 #include <fcoe.h>
43 #include <fcoe_eth.h>
44 #include <fcoe_fc.h>
46 static void fcoe_rx(void *arg, mac_resource_handle_t mrh,
47 mblk_t *mp, boolean_t loopback);
48 static void fcoe_mac_notify(void *arg, mac_notify_type_t type);
51 * Global variable definitions
55 * Internal tunable, used to enable p2p mode
57 volatile uint32_t fcoe_enable_p2pmode = 0;
59 int
60 fcoe_open_mac(fcoe_mac_t *mac, int force_promisc, fcoeio_stat_t *err_detail)
62 int ret;
63 int fcoe_ret;
64 char cli_name[MAXNAMELEN];
65 mac_diag_t diag;
66 uint16_t fm_open_flag = 0;
68 *err_detail = 0;
71 * Open MAC interface
73 ret = mac_open_by_linkid(mac->fm_linkid, &mac->fm_handle);
74 if (ret != 0) {
75 FCOE_LOG("fcoe", "mac_open_by_linkname %d failed %x",
76 mac->fm_linkid, ret);
77 return (FCOE_FAILURE);
80 (void) sprintf(cli_name, "%s-%d", "fcoe", mac->fm_linkid);
82 ret = mac_client_open(mac->fm_handle,
83 &mac->fm_cli_handle, cli_name, fm_open_flag);
84 if (ret != 0) {
85 (void) fcoe_close_mac(mac);
86 return (FCOE_FAILURE);
89 * Cache the pointer of the immutable MAC inforamtion and
90 * the current and primary MAC address
92 mac_unicast_primary_get(mac->fm_handle, mac->fm_primary_addr);
93 bcopy(mac->fm_primary_addr, mac->fm_current_addr,
94 ETHERADDRL);
96 if (mac_unicast_add(mac->fm_cli_handle, NULL, MAC_UNICAST_PRIMARY,
97 &mac->fm_unicst_handle, 0, &diag)) {
98 (void) fcoe_close_mac(mac);
99 return (FCOE_FAILURE);
102 if (force_promisc) {
103 mac->fm_force_promisc = B_TRUE;
106 /* Get mtu */
107 mac_sdu_get(mac->fm_handle, NULL, &mac->fm_eport.eport_mtu);
108 if (mac->fm_eport.eport_mtu < FCOE_MIN_MTU_SIZE) {
109 if (!fcoe_enable_p2pmode || mac->fm_eport.eport_mtu < 1500) {
111 * Fail open if fail to get mtu, or we are not
112 * using p2p, or we are using p2p, but
113 * the mtu is too small
115 (void) fcoe_close_mac(mac);
116 *err_detail = FCOEIOE_NEED_JUMBO_FRAME;
117 return (FCOE_FAILURE);
121 mac->fm_eport.eport_link_speed =
122 mac_client_stat_get(mac->fm_cli_handle, MAC_STAT_IFSPEED);
124 cv_init(&mac->fm_tx_cv, NULL, CV_DRIVER, NULL);
125 mutex_init(&mac->fm_mutex, NULL, MUTEX_DRIVER, NULL);
126 mac->fm_running = B_TRUE;
128 fcoe_ret = FCOE_SUCCESS;
129 return (fcoe_ret);
133 fcoe_close_mac(fcoe_mac_t *mac)
135 int ret;
137 if (mac->fm_handle == NULL) {
138 return (FCOE_SUCCESS);
141 if (mac->fm_running) {
142 cv_destroy(&mac->fm_tx_cv);
143 mutex_destroy(&mac->fm_mutex);
144 mac->fm_running = B_FALSE;
147 if (mac->fm_promisc_handle != NULL) {
148 mac_promisc_remove(mac->fm_promisc_handle);
149 mac->fm_promisc_handle = NULL;
150 } else {
151 mac_rx_clear(mac->fm_cli_handle);
154 if (mac->fm_notify_handle != NULL) {
155 ret = mac_notify_remove(mac->fm_notify_handle, B_TRUE);
156 ASSERT(ret == 0);
157 mac->fm_notify_handle = NULL;
160 if (mac->fm_unicst_handle != NULL) {
161 (void) mac_unicast_remove(mac->fm_cli_handle,
162 mac->fm_unicst_handle);
163 mac->fm_unicst_handle = NULL;
166 mac_client_close(mac->fm_cli_handle, 0);
167 mac->fm_cli_handle = NULL;
169 (void) mac_close(mac->fm_handle);
170 mac->fm_handle = NULL;
172 return (FCOE_SUCCESS);
176 fcoe_enable_callback(fcoe_mac_t *mac)
178 int ret;
181 * Set message callback
183 if (mac->fm_force_promisc) {
184 ret = mac_promisc_add(mac->fm_cli_handle,
185 MAC_CLIENT_PROMISC_FILTERED, fcoe_rx, mac,
186 &mac->fm_promisc_handle,
187 MAC_PROMISC_FLAGS_NO_TX_LOOP);
188 if (ret != 0) {
189 FCOE_LOG("foce", "mac_promisc_add on %d failed %x",
190 mac->fm_linkid, ret);
191 return (FCOE_FAILURE);
193 } else {
194 mac_rx_set(mac->fm_cli_handle, fcoe_rx, mac);
197 /* Get the link state, if it's up, we will need to notify client */
198 mac->fm_link_state =
199 mac_stat_get(mac->fm_handle, MAC_STAT_LINK_UP)?
200 FCOE_MAC_LINK_STATE_UP:FCOE_MAC_LINK_STATE_DOWN;
202 mac->fm_eport.eport_link_speed =
203 mac_client_stat_get(mac->fm_cli_handle, MAC_STAT_IFSPEED);
206 * Add a notify function so that we get updates from MAC
208 mac->fm_notify_handle = mac_notify_add(mac->fm_handle,
209 fcoe_mac_notify, (void *)mac);
210 return (FCOE_SUCCESS);
214 fcoe_disable_callback(fcoe_mac_t *mac)
216 int ret;
218 if (mac->fm_promisc_handle) {
219 mac_promisc_remove(mac->fm_promisc_handle);
220 mac->fm_promisc_handle = NULL;
221 } else {
222 mac_rx_clear(mac->fm_cli_handle);
225 if (mac->fm_notify_handle) {
226 ret = mac_notify_remove(mac->fm_notify_handle, B_TRUE);
227 ASSERT(ret == 0);
228 mac->fm_notify_handle = NULL;
231 ret = fcoe_mac_set_address(&mac->fm_eport,
232 mac->fm_primary_addr, B_FALSE);
233 FCOE_SET_DEFAULT_FPORT_ADDR(mac->fm_eport.eport_efh_dst);
234 return (ret);
237 /* ARGSUSED */
238 static void
239 fcoe_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp, boolean_t loopback)
241 fcoe_mac_t *mac = (fcoe_mac_t *)arg;
242 mblk_t *next;
243 fcoe_frame_t *frm;
244 uint32_t raw_frame_size, frame_size;
245 uint16_t frm_type;
247 while (mp != NULL) {
248 next = mp->b_next;
249 mp->b_next = NULL;
250 frm_type = ntohs(*(uint16_t *)((uintptr_t)mp->b_rptr + 12));
252 if (frm_type != ETHERTYPE_FCOE) {
254 * This mp is not allocated in FCoE, but we must free it
256 freeb(mp);
257 mp = next;
258 continue;
261 raw_frame_size = MBLKL(mp);
262 frame_size = raw_frame_size - PADDING_SIZE;
263 frm = fcoe_allocate_frame(&mac->fm_eport, frame_size, mp);
264 if (frm != NULL) {
265 frm->frm_clock = CURRENT_CLOCK;
266 fcoe_post_frame(frm);
269 mp = next;
273 static void
274 fcoe_mac_notify(void *arg, mac_notify_type_t type)
276 fcoe_mac_t *mac = (fcoe_mac_t *)arg;
279 * We assume that the calls to this notification callback are serialized
280 * by MAC layer
283 switch (type) {
284 case MAC_NOTE_LINK:
286 * This notification is sent every time the MAC driver
287 * updates the link state.
289 if (mac_stat_get(mac->fm_handle, MAC_STAT_LINK_UP) != 0) {
290 if (mac->fm_link_state == FCOE_MAC_LINK_STATE_UP) {
291 break;
293 /* Get speed */
294 mac->fm_eport.eport_link_speed =
295 mac_client_stat_get(mac->fm_cli_handle,
296 MAC_STAT_IFSPEED);
297 (void) fcoe_mac_set_address(&mac->fm_eport,
298 mac->fm_primary_addr, B_FALSE);
300 FCOE_SET_DEFAULT_FPORT_ADDR(
301 mac->fm_eport.eport_efh_dst);
303 mac->fm_link_state = FCOE_MAC_LINK_STATE_UP;
304 FCOE_LOG(NULL,
305 "fcoe_mac_notify: link/%d arg/%p LINK up",
306 mac->fm_linkid, arg, type);
307 fcoe_mac_notify_link_up(mac);
308 } else {
309 if (mac->fm_link_state == FCOE_MAC_LINK_STATE_DOWN) {
310 break;
312 mac->fm_link_state = FCOE_MAC_LINK_STATE_DOWN;
313 FCOE_LOG(NULL,
314 "fcoe_mac_notify: link/%d arg/%p LINK down",
315 mac->fm_linkid, arg, type);
316 fcoe_mac_notify_link_down(mac);
318 break;
320 case MAC_NOTE_TX:
322 * MAC is not so busy now, then wake up fcoe_tx_frame to try
324 mutex_enter(&mac->fm_mutex);
325 cv_broadcast(&mac->fm_tx_cv);
326 mutex_exit(&mac->fm_mutex);
328 FCOE_LOG("fcoe_mac_notify", "wake up");
329 break;
331 default:
332 FCOE_LOG("fcoe_mac_notify", "not supported arg/%p, type/%d",
333 arg, type);
334 break;
339 fcoe_mac_set_address(fcoe_port_t *eport, uint8_t *addr, boolean_t fc_assigned)
341 fcoe_mac_t *mac = EPORT2MAC(eport);
342 int ret;
344 if (bcmp(addr, mac->fm_current_addr, 6) == 0) {
345 return (FCOE_SUCCESS);
348 mutex_enter(&mac->fm_mutex);
349 if (mac->fm_promisc_handle == NULL) {
350 ret = mac_unicast_primary_set(mac->fm_handle, addr);
351 if (ret != 0) {
352 mutex_exit(&mac->fm_mutex);
353 FCOE_LOG("fcoe", "mac_unicast_primary_set on %d "
354 "failed %x", mac->fm_linkid, ret);
355 return (FCOE_FAILURE);
358 if (fc_assigned) {
359 bcopy(addr, mac->fm_current_addr, ETHERADDRL);
360 } else {
361 bcopy(mac->fm_primary_addr,
362 mac->fm_current_addr, ETHERADDRL);
364 mutex_exit(&mac->fm_mutex);
365 return (FCOE_SUCCESS);