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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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>
36 #include <sys/fcoe/fcoeio.h>
37 #include <sys/fcoe/fcoe_common.h>
40 * Driver's own header files
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;
60 fcoe_open_mac(fcoe_mac_t
*mac
, int force_promisc
, fcoeio_stat_t
*err_detail
)
64 char cli_name
[MAXNAMELEN
];
66 uint16_t fm_open_flag
= 0;
73 ret
= mac_open_by_linkid(mac
->fm_linkid
, &mac
->fm_handle
);
75 FCOE_LOG("fcoe", "mac_open_by_linkname %d failed %x",
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
);
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
,
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
);
103 mac
->fm_force_promisc
= B_TRUE
;
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
;
133 fcoe_close_mac(fcoe_mac_t
*mac
)
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
;
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
);
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
)
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
);
189 FCOE_LOG("foce", "mac_promisc_add on %d failed %x",
190 mac
->fm_linkid
, ret
);
191 return (FCOE_FAILURE
);
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 */
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
)
218 if (mac
->fm_promisc_handle
) {
219 mac_promisc_remove(mac
->fm_promisc_handle
);
220 mac
->fm_promisc_handle
= NULL
;
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
);
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
);
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
;
244 uint32_t raw_frame_size
, frame_size
;
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
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
);
265 frm
->frm_clock
= CURRENT_CLOCK
;
266 fcoe_post_frame(frm
);
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
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
) {
294 mac
->fm_eport
.eport_link_speed
=
295 mac_client_stat_get(mac
->fm_cli_handle
,
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
;
305 "fcoe_mac_notify: link/%d arg/%p LINK up",
306 mac
->fm_linkid
, arg
, type
);
307 fcoe_mac_notify_link_up(mac
);
309 if (mac
->fm_link_state
== FCOE_MAC_LINK_STATE_DOWN
) {
312 mac
->fm_link_state
= FCOE_MAC_LINK_STATE_DOWN
;
314 "fcoe_mac_notify: link/%d arg/%p LINK down",
315 mac
->fm_linkid
, arg
, type
);
316 fcoe_mac_notify_link_down(mac
);
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");
332 FCOE_LOG("fcoe_mac_notify", "not supported arg/%p, type/%d",
339 fcoe_mac_set_address(fcoe_port_t
*eport
, uint8_t *addr
, boolean_t fc_assigned
)
341 fcoe_mac_t
*mac
= EPORT2MAC(eport
);
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
);
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
);
359 bcopy(addr
, mac
->fm_current_addr
, ETHERADDRL
);
361 bcopy(mac
->fm_primary_addr
,
362 mac
->fm_current_addr
, ETHERADDRL
);
364 mutex_exit(&mac
->fm_mutex
);
365 return (FCOE_SUCCESS
);