xref: /onnv-gate/usr/src/uts/common/io/fcoe/fcoe_fc.c (revision 11066:cebb50cbe4f9)
19087SZhong.Wang@Sun.COM /*
29087SZhong.Wang@Sun.COM  * CDDL HEADER START
39087SZhong.Wang@Sun.COM  *
49087SZhong.Wang@Sun.COM  * The contents of this file are subject to the terms of the
59087SZhong.Wang@Sun.COM  * Common Development and Distribution License (the "License").
69087SZhong.Wang@Sun.COM  * You may not use this file except in compliance with the License.
79087SZhong.Wang@Sun.COM  *
89087SZhong.Wang@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99087SZhong.Wang@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109087SZhong.Wang@Sun.COM  * See the License for the specific language governing permissions
119087SZhong.Wang@Sun.COM  * and limitations under the License.
129087SZhong.Wang@Sun.COM  *
139087SZhong.Wang@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149087SZhong.Wang@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159087SZhong.Wang@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169087SZhong.Wang@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179087SZhong.Wang@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189087SZhong.Wang@Sun.COM  *
199087SZhong.Wang@Sun.COM  * CDDL HEADER END
209087SZhong.Wang@Sun.COM  */
219087SZhong.Wang@Sun.COM 
229087SZhong.Wang@Sun.COM /*
239087SZhong.Wang@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
249087SZhong.Wang@Sun.COM  * Use is subject to license terms.
259087SZhong.Wang@Sun.COM  */
269087SZhong.Wang@Sun.COM 
279087SZhong.Wang@Sun.COM /*
289087SZhong.Wang@Sun.COM  * This file defines interfaces between fcoe and its clients (FCoEI/FCoET)
299087SZhong.Wang@Sun.COM  */
309087SZhong.Wang@Sun.COM 
319087SZhong.Wang@Sun.COM #include <sys/ddi.h>
329087SZhong.Wang@Sun.COM #include <sys/sunddi.h>
339087SZhong.Wang@Sun.COM #include <sys/sunndi.h>
349087SZhong.Wang@Sun.COM #include <sys/byteorder.h>
359087SZhong.Wang@Sun.COM #include <sys/atomic.h>
369087SZhong.Wang@Sun.COM #include <sys/sysmacros.h>
379087SZhong.Wang@Sun.COM #include <sys/cmn_err.h>
389087SZhong.Wang@Sun.COM #include <sys/crc32.h>
399087SZhong.Wang@Sun.COM #include <sys/fcntl.h>
409087SZhong.Wang@Sun.COM #include <sys/unistd.h>
419087SZhong.Wang@Sun.COM #include <sys/mac_client.h>
429087SZhong.Wang@Sun.COM 
439087SZhong.Wang@Sun.COM /*
449087SZhong.Wang@Sun.COM  * FCoE header files
459087SZhong.Wang@Sun.COM  */
469087SZhong.Wang@Sun.COM #include <sys/fcoe/fcoeio.h>
479087SZhong.Wang@Sun.COM #include <sys/fcoe/fcoe_common.h>
489087SZhong.Wang@Sun.COM 
499087SZhong.Wang@Sun.COM /*
509087SZhong.Wang@Sun.COM  * Driver's own header files
519087SZhong.Wang@Sun.COM  */
529087SZhong.Wang@Sun.COM #include <fcoe.h>
539087SZhong.Wang@Sun.COM #include <fcoe_fc.h>
549087SZhong.Wang@Sun.COM #include <fcoe_eth.h>
559087SZhong.Wang@Sun.COM 
569087SZhong.Wang@Sun.COM static void fcoe_fill_frame_headers(fcoe_frame_t *frm);
579087SZhong.Wang@Sun.COM static void fcoe_fill_frame_tailers(fcoe_frame_t *frm);
589087SZhong.Wang@Sun.COM static void fcoe_deregister_client(fcoe_port_t *eport);
599087SZhong.Wang@Sun.COM static int fcoe_ctl(fcoe_port_t *eport, int cmd, void *arg);
609087SZhong.Wang@Sun.COM static void fcoe_tx_frame(fcoe_frame_t *frm);
619087SZhong.Wang@Sun.COM static void *fcoe_alloc_netb(fcoe_port_t *eport,
629087SZhong.Wang@Sun.COM     uint32_t fc_frame_size, uint8_t **ppfc);
639087SZhong.Wang@Sun.COM static void fcoe_free_netb(void *netb);
649087SZhong.Wang@Sun.COM 
659087SZhong.Wang@Sun.COM /*
669087SZhong.Wang@Sun.COM  * Only this function will be called explicitly by clients
679087SZhong.Wang@Sun.COM  * Register the specified client port (fcoei/fcoet)
689087SZhong.Wang@Sun.COM  */
699087SZhong.Wang@Sun.COM fcoe_port_t *
fcoe_register_client(fcoe_client_t * client)709087SZhong.Wang@Sun.COM fcoe_register_client(fcoe_client_t *client)
719087SZhong.Wang@Sun.COM {
729087SZhong.Wang@Sun.COM 	fcoe_mac_t	*mac;
739087SZhong.Wang@Sun.COM 	fcoe_port_t	*eport;
749087SZhong.Wang@Sun.COM 
7510264SZhong.Wang@Sun.COM 	if (client->ect_fcoe_ver != fcoe_ver_now) {
7610264SZhong.Wang@Sun.COM 		cmn_err(CE_WARN, "FCoE modules version mismatch, "
7710264SZhong.Wang@Sun.COM 		    "fail registering client.");
7810264SZhong.Wang@Sun.COM 		return (NULL);
7910264SZhong.Wang@Sun.COM 	}
809087SZhong.Wang@Sun.COM 
819087SZhong.Wang@Sun.COM 	/*
829087SZhong.Wang@Sun.COM 	 * We will not come here, when someone is changing ss_mac_list,
839087SZhong.Wang@Sun.COM 	 * so it's safe to go through ss_mac_list.
849087SZhong.Wang@Sun.COM 	 */
859087SZhong.Wang@Sun.COM 	for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
869087SZhong.Wang@Sun.COM 	    mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
879307Skelly.hu@Sun.COM 		if (client->ect_channelid == mac->fm_linkid) {
889087SZhong.Wang@Sun.COM 			break;
899087SZhong.Wang@Sun.COM 		}
909087SZhong.Wang@Sun.COM 	}
919087SZhong.Wang@Sun.COM 
929087SZhong.Wang@Sun.COM 	if (mac == NULL) {
939087SZhong.Wang@Sun.COM 		FCOE_LOG(0, "can't find the MAC you want to bind");
949087SZhong.Wang@Sun.COM 		return (NULL);
959087SZhong.Wang@Sun.COM 	}
969087SZhong.Wang@Sun.COM 
979087SZhong.Wang@Sun.COM 	if (mac->fm_flags & FCOE_MAC_FLAG_BOUND) {
989087SZhong.Wang@Sun.COM 		FCOE_LOG(0, "the MAC you want to bind is bound already");
999087SZhong.Wang@Sun.COM 		return (NULL);
1009087SZhong.Wang@Sun.COM 	}
1019087SZhong.Wang@Sun.COM 
1029087SZhong.Wang@Sun.COM 	atomic_or_32(&mac->fm_flags, FCOE_MAC_FLAG_BOUND);
1039087SZhong.Wang@Sun.COM 	bcopy(client, &mac->fm_client, sizeof (fcoe_client_t));
1049087SZhong.Wang@Sun.COM 
1059087SZhong.Wang@Sun.COM 	/*
1069087SZhong.Wang@Sun.COM 	 * fcoe_port_t initialization
1079087SZhong.Wang@Sun.COM 	 */
1089087SZhong.Wang@Sun.COM 	eport = &mac->fm_eport;
1099087SZhong.Wang@Sun.COM 	eport->eport_flags = client->ect_eport_flags | EPORT_FLAG_MAC_IN_USE;
1109087SZhong.Wang@Sun.COM 	eport->eport_fcoe_private = mac;
1119087SZhong.Wang@Sun.COM 	eport->eport_client_private = client->ect_client_port_struct;
1129087SZhong.Wang@Sun.COM 	eport->eport_max_fc_frame_size = 2136;
1139087SZhong.Wang@Sun.COM 	eport->eport_tx_frame = fcoe_tx_frame;
1149087SZhong.Wang@Sun.COM 	eport->eport_alloc_frame = fcoe_allocate_frame;
1159087SZhong.Wang@Sun.COM 	eport->eport_release_frame = fcoe_release_frame;
1169087SZhong.Wang@Sun.COM 	eport->eport_alloc_netb = fcoe_alloc_netb;
1179087SZhong.Wang@Sun.COM 	eport->eport_free_netb = fcoe_free_netb;
1189087SZhong.Wang@Sun.COM 	eport->eport_deregister_client = fcoe_deregister_client;
1199087SZhong.Wang@Sun.COM 	eport->eport_ctl = fcoe_ctl;
1209087SZhong.Wang@Sun.COM 	eport->eport_set_mac_address = fcoe_mac_set_address;
1219087SZhong.Wang@Sun.COM 
1229087SZhong.Wang@Sun.COM 	return (eport);
1239087SZhong.Wang@Sun.COM }
1249087SZhong.Wang@Sun.COM 
1259087SZhong.Wang@Sun.COM /*
1269087SZhong.Wang@Sun.COM  * The following routines will be called through vectors in fcoe_port_t
1279087SZhong.Wang@Sun.COM  */
1289087SZhong.Wang@Sun.COM 
1299087SZhong.Wang@Sun.COM /*
1309087SZhong.Wang@Sun.COM  * Deregister fcoet/fcoei modules, client should make sure the port is in
1319087SZhong.Wang@Sun.COM  * offline status already
1329087SZhong.Wang@Sun.COM  */
1339087SZhong.Wang@Sun.COM static void
fcoe_deregister_client(fcoe_port_t * eport)1349087SZhong.Wang@Sun.COM fcoe_deregister_client(fcoe_port_t *eport)
1359087SZhong.Wang@Sun.COM {
1369087SZhong.Wang@Sun.COM 	fcoe_mac_t	*mac = EPORT2MAC(eport);
1379087SZhong.Wang@Sun.COM 
1389087SZhong.Wang@Sun.COM 	/*
1399087SZhong.Wang@Sun.COM 	 * Wait for all the related frame to be freed, this should be fast
1409087SZhong.Wang@Sun.COM 	 * because before deregister fcoei/fcoet will make sure its port
1419087SZhong.Wang@Sun.COM 	 * is already in offline status so no frame will be received or sent
1429087SZhong.Wang@Sun.COM 	 * any more
1439087SZhong.Wang@Sun.COM 	 */
1449087SZhong.Wang@Sun.COM 	while (mac->fm_frm_cnt > 0) {
1459087SZhong.Wang@Sun.COM 		delay(10);
1469087SZhong.Wang@Sun.COM 	}
1479087SZhong.Wang@Sun.COM 
1489087SZhong.Wang@Sun.COM 	atomic_and_32(&EPORT2MAC(eport)->fm_flags, ~FCOE_MAC_FLAG_BOUND);
14910264SZhong.Wang@Sun.COM 	atomic_and_32(&mac->fm_eport.eport_flags, ~EPORT_FLAG_MAC_IN_USE);
15010264SZhong.Wang@Sun.COM 	if (!(EPORT2MAC(eport)->fm_flags & FCOE_MAC_FLAG_USER_DEL)) {
15110264SZhong.Wang@Sun.COM 		(void) fcoe_close_mac(mac);
15210264SZhong.Wang@Sun.COM 		fcoe_destroy_mac(mac);
15310264SZhong.Wang@Sun.COM 	}
1549087SZhong.Wang@Sun.COM }
1559087SZhong.Wang@Sun.COM 
1569087SZhong.Wang@Sun.COM /* ARGSUSED */
1579087SZhong.Wang@Sun.COM static int
fcoe_ctl(fcoe_port_t * eport,int cmd,void * arg)1589087SZhong.Wang@Sun.COM fcoe_ctl(fcoe_port_t *eport, int cmd, void *arg)
1599087SZhong.Wang@Sun.COM {
1609087SZhong.Wang@Sun.COM 	fcoe_mac_t	*mac = EPORT2MAC(eport);
1619087SZhong.Wang@Sun.COM 
1629087SZhong.Wang@Sun.COM 	switch (cmd) {
1639087SZhong.Wang@Sun.COM 		case FCOE_CMD_PORT_ONLINE:
1649087SZhong.Wang@Sun.COM 			/*
1659087SZhong.Wang@Sun.COM 			 * client ask us to online, so it's safe to post event
1669087SZhong.Wang@Sun.COM 			 * and data up
1679087SZhong.Wang@Sun.COM 			 */
1689087SZhong.Wang@Sun.COM 			if (fcoe_enable_callback(mac) == FCOE_FAILURE) {
1699087SZhong.Wang@Sun.COM 				return (FCOE_FAILURE);
1709087SZhong.Wang@Sun.COM 			}
1719087SZhong.Wang@Sun.COM 			mac->fm_state = FCOE_MAC_STATE_ONLINE;
1729087SZhong.Wang@Sun.COM 			if (mac->fm_link_state == FCOE_MAC_LINK_STATE_UP)
1739087SZhong.Wang@Sun.COM 				(void) ddi_taskq_dispatch(
1749087SZhong.Wang@Sun.COM 				    fcoe_global_ss->ss_watchdog_taskq,
1759087SZhong.Wang@Sun.COM 				    fcoe_mac_notify_link_up, mac, DDI_SLEEP);
1769087SZhong.Wang@Sun.COM 			break;
1779087SZhong.Wang@Sun.COM 		case FCOE_CMD_PORT_OFFLINE:
1789087SZhong.Wang@Sun.COM 			if (fcoe_disable_callback(mac) == FCOE_FAILURE) {
1799087SZhong.Wang@Sun.COM 				return (FCOE_FAILURE);
1809087SZhong.Wang@Sun.COM 			}
1819087SZhong.Wang@Sun.COM 			mac->fm_state = FCOE_MAC_STATE_OFFLINE;
1829087SZhong.Wang@Sun.COM 			// in case there are threads waiting
1839087SZhong.Wang@Sun.COM 			mutex_enter(&mac->fm_mutex);
1849087SZhong.Wang@Sun.COM 			cv_broadcast(&mac->fm_tx_cv);
1859087SZhong.Wang@Sun.COM 			mutex_exit(&mac->fm_mutex);
1869087SZhong.Wang@Sun.COM 			break;
1879087SZhong.Wang@Sun.COM 		default:
1889087SZhong.Wang@Sun.COM 			FCOE_LOG("fcoe", "fcoe_ctl, unsupported cmd %x", cmd);
1899087SZhong.Wang@Sun.COM 			break;
1909087SZhong.Wang@Sun.COM 	}
1919087SZhong.Wang@Sun.COM 
1929087SZhong.Wang@Sun.COM 	return (FCOE_SUCCESS);
1939087SZhong.Wang@Sun.COM }
1949087SZhong.Wang@Sun.COM 
1959087SZhong.Wang@Sun.COM /*
1969087SZhong.Wang@Sun.COM  * Transmit the specified frame to the link
1979087SZhong.Wang@Sun.COM  */
1989087SZhong.Wang@Sun.COM static void
fcoe_tx_frame(fcoe_frame_t * frm)1999087SZhong.Wang@Sun.COM fcoe_tx_frame(fcoe_frame_t *frm)
2009087SZhong.Wang@Sun.COM {
2019087SZhong.Wang@Sun.COM 	mblk_t		*ret_mblk = NULL;
2029087SZhong.Wang@Sun.COM 	fcoe_mac_t	*mac = FRM2MAC(frm);
2039087SZhong.Wang@Sun.COM 	mac_tx_cookie_t	ret_cookie;
2049087SZhong.Wang@Sun.COM 
2059087SZhong.Wang@Sun.COM 	fcoe_fill_frame_headers(frm);
2069087SZhong.Wang@Sun.COM 	fcoe_fill_frame_tailers(frm);
2079087SZhong.Wang@Sun.COM 
2089087SZhong.Wang@Sun.COM tx_frame:
2099087SZhong.Wang@Sun.COM 	ret_cookie = mac_tx(mac->fm_cli_handle, FRM2MBLK(frm), 0,
2109087SZhong.Wang@Sun.COM 	    MAC_TX_NO_ENQUEUE, &ret_mblk);
2119087SZhong.Wang@Sun.COM 	if (ret_cookie != NULL) {
2129087SZhong.Wang@Sun.COM 		mutex_enter(&mac->fm_mutex);
213*11066Srafael.vanoni@sun.com 		(void) cv_reltimedwait(&mac->fm_tx_cv, &mac->fm_mutex,
214*11066Srafael.vanoni@sun.com 		    drv_usectohz(100000), TR_CLOCK_TICK);
2159087SZhong.Wang@Sun.COM 		mutex_exit(&mac->fm_mutex);
2169087SZhong.Wang@Sun.COM 
2179087SZhong.Wang@Sun.COM 		if (mac->fm_state == FCOE_MAC_STATE_OFFLINE) {
2189087SZhong.Wang@Sun.COM 			/*
2199087SZhong.Wang@Sun.COM 			 * we are doing offline, so just tell the upper that
2209087SZhong.Wang@Sun.COM 			 * this is finished, the cmd will be aborted soon.
2219087SZhong.Wang@Sun.COM 			 */
2229087SZhong.Wang@Sun.COM 			fcoe_free_netb(ret_mblk);
2239087SZhong.Wang@Sun.COM 		} else {
2249087SZhong.Wang@Sun.COM 			goto tx_frame;
2259087SZhong.Wang@Sun.COM 		}
2269087SZhong.Wang@Sun.COM 	}
2279087SZhong.Wang@Sun.COM 
2289087SZhong.Wang@Sun.COM 	/*
2299087SZhong.Wang@Sun.COM 	 * MAC driver will release the mblk of the frame
2309087SZhong.Wang@Sun.COM 	 * We need only release the frame itself
2319087SZhong.Wang@Sun.COM 	 */
2329087SZhong.Wang@Sun.COM 	mutex_enter(&FRM2MAC(frm)->fm_ss->ss_watch_mutex);
2339087SZhong.Wang@Sun.COM 	list_insert_tail(&FRM2MAC(frm)->fm_ss->ss_pfrm_list,
2349087SZhong.Wang@Sun.COM 	    FRM2FMI(frm));
2359087SZhong.Wang@Sun.COM 	mac->fm_frm_cnt ++;
2369087SZhong.Wang@Sun.COM 	if (FRM2MAC(frm)->fm_ss->ss_flags & SS_FLAG_DOG_WAITING) {
2379087SZhong.Wang@Sun.COM 		cv_signal(&FRM2MAC(frm)->fm_ss->ss_watch_cv);
2389087SZhong.Wang@Sun.COM 	}
2399087SZhong.Wang@Sun.COM 	mutex_exit(&FRM2MAC(frm)->fm_ss->ss_watch_mutex);
2409087SZhong.Wang@Sun.COM }
2419087SZhong.Wang@Sun.COM 
2429087SZhong.Wang@Sun.COM /*
2439087SZhong.Wang@Sun.COM  * Consider cache allocation in the future
2449087SZhong.Wang@Sun.COM  */
2459087SZhong.Wang@Sun.COM void
fcoe_release_frame(fcoe_frame_t * frame)2469087SZhong.Wang@Sun.COM fcoe_release_frame(fcoe_frame_t *frame)
2479087SZhong.Wang@Sun.COM {
2489087SZhong.Wang@Sun.COM 	kmem_free(frame, frame->frm_alloc_size);
2499087SZhong.Wang@Sun.COM }
2509087SZhong.Wang@Sun.COM 
2519087SZhong.Wang@Sun.COM static void *
fcoe_alloc_netb(fcoe_port_t * eport,uint32_t fc_frame_size,uint8_t ** ppfc)2529087SZhong.Wang@Sun.COM fcoe_alloc_netb(fcoe_port_t *eport, uint32_t fc_frame_size, uint8_t **ppfc)
2539087SZhong.Wang@Sun.COM {
2549087SZhong.Wang@Sun.COM 	mblk_t *mp;
2559087SZhong.Wang@Sun.COM 
2569087SZhong.Wang@Sun.COM 	mp = fcoe_get_mblk(eport->eport_fcoe_private,
2579087SZhong.Wang@Sun.COM 	    fc_frame_size + PADDING_SIZE);
2589087SZhong.Wang@Sun.COM 	if (mp != NULL) {
2599087SZhong.Wang@Sun.COM 		*ppfc = mp->b_rptr + PADDING_HEADER_SIZE;
2609087SZhong.Wang@Sun.COM 	}
2619087SZhong.Wang@Sun.COM 
2629087SZhong.Wang@Sun.COM 	return (mp);
2639087SZhong.Wang@Sun.COM }
2649087SZhong.Wang@Sun.COM 
2659087SZhong.Wang@Sun.COM static void
fcoe_free_netb(void * netb)2669087SZhong.Wang@Sun.COM fcoe_free_netb(void *netb)
2679087SZhong.Wang@Sun.COM {
2689087SZhong.Wang@Sun.COM 	freeb((mblk_t *)netb);
2699087SZhong.Wang@Sun.COM }
2709087SZhong.Wang@Sun.COM 
2719087SZhong.Wang@Sun.COM fcoe_frame_t *
fcoe_allocate_frame(fcoe_port_t * eport,uint32_t fc_frame_size,void * xmp)2729087SZhong.Wang@Sun.COM fcoe_allocate_frame(fcoe_port_t *eport, uint32_t fc_frame_size, void *xmp)
2739087SZhong.Wang@Sun.COM {
2749087SZhong.Wang@Sun.COM 	fcoe_frame_t	*frm;
2759087SZhong.Wang@Sun.COM 	fcoe_i_frame_t	*fmi;
2769087SZhong.Wang@Sun.COM 	mblk_t		*mp = xmp;
2779087SZhong.Wang@Sun.COM 	uint32_t	 alloc_size;
2789087SZhong.Wang@Sun.COM 	uint32_t	 raw_frame_size;
2799087SZhong.Wang@Sun.COM 
2809087SZhong.Wang@Sun.COM 	if (fc_frame_size > 2136) {
2819087SZhong.Wang@Sun.COM 		FCOE_LOG("fcoe", "fcoe_allocate_frame %d > 2136",
2829087SZhong.Wang@Sun.COM 		    fc_frame_size);
2839087SZhong.Wang@Sun.COM 		return (NULL);
2849087SZhong.Wang@Sun.COM 	}
2859087SZhong.Wang@Sun.COM 
2869087SZhong.Wang@Sun.COM 	if (mp == NULL) {
2879087SZhong.Wang@Sun.COM 		/*
2889087SZhong.Wang@Sun.COM 		 * We are allocating solicited frame now
2899087SZhong.Wang@Sun.COM 		 */
2909087SZhong.Wang@Sun.COM 		raw_frame_size = PADDING_SIZE + fc_frame_size;
2919087SZhong.Wang@Sun.COM 		mp = fcoe_get_mblk(EPORT2MAC(eport), raw_frame_size);
2929087SZhong.Wang@Sun.COM 		if (mp == NULL) {
2939087SZhong.Wang@Sun.COM 			return (NULL);
2949087SZhong.Wang@Sun.COM 		}
2959087SZhong.Wang@Sun.COM 	}
2969087SZhong.Wang@Sun.COM 
2979087SZhong.Wang@Sun.COM 	alloc_size = sizeof (fcoe_frame_t) + sizeof (fcoe_i_frame_t) +
2989087SZhong.Wang@Sun.COM 	    EPORT2MAC(eport)->fm_client.ect_private_frame_struct_size;
2999087SZhong.Wang@Sun.COM 
3009087SZhong.Wang@Sun.COM 	/*
3019087SZhong.Wang@Sun.COM 	 * fcoe_frame_t initialization
3029087SZhong.Wang@Sun.COM 	 */
3039087SZhong.Wang@Sun.COM 	frm = (fcoe_frame_t *)kmem_alloc(alloc_size, KM_SLEEP);
3049087SZhong.Wang@Sun.COM 	frm->frm_alloc_size = alloc_size;
3059087SZhong.Wang@Sun.COM 	frm->frm_fc_frame_size = fc_frame_size;
3069087SZhong.Wang@Sun.COM 	frm->frm_payload_size = fc_frame_size -
3079087SZhong.Wang@Sun.COM 	    sizeof (fcoe_fc_frame_header_t);
3089087SZhong.Wang@Sun.COM 	frm->frm_fcoe_private = sizeof (fcoe_frame_t) + (uint8_t *)frm;
3099087SZhong.Wang@Sun.COM 	frm->frm_client_private = sizeof (fcoe_i_frame_t) +
3109087SZhong.Wang@Sun.COM 	    (uint8_t *)frm->frm_fcoe_private;
3119087SZhong.Wang@Sun.COM 	frm->frm_flags = 0;
3129087SZhong.Wang@Sun.COM 	frm->frm_eport = eport;
3139087SZhong.Wang@Sun.COM 	frm->frm_netb = mp;
3149087SZhong.Wang@Sun.COM 
3159087SZhong.Wang@Sun.COM 	/*
3169087SZhong.Wang@Sun.COM 	 * fcoe_i_frame_t initialization
3179087SZhong.Wang@Sun.COM 	 */
3189087SZhong.Wang@Sun.COM 	fmi = FRM2FMI(frm);
3199087SZhong.Wang@Sun.COM 	fmi->fmi_frame = frm;
3209087SZhong.Wang@Sun.COM 	fmi->fmi_mac = EPORT2MAC(eport);
3219087SZhong.Wang@Sun.COM 	fmi->fmi_efh = (void *)mp->b_rptr;
3229087SZhong.Wang@Sun.COM 
3239087SZhong.Wang@Sun.COM 	fmi->fmi_ffh = (fcoe_frame_header_t *)
3249087SZhong.Wang@Sun.COM 	    (sizeof (struct ether_header) + (uint8_t *)fmi->fmi_efh);
3259087SZhong.Wang@Sun.COM 
3269087SZhong.Wang@Sun.COM 	fmi->fmi_fc_frame = sizeof (fcoe_frame_header_t) +
3279087SZhong.Wang@Sun.COM 	    (uint8_t *)fmi->fmi_ffh;
3289087SZhong.Wang@Sun.COM 	fmi->fmi_fft = (fcoe_frame_tailer_t *)
3299087SZhong.Wang@Sun.COM 	    (fc_frame_size + (uint8_t *)fmi->fmi_fc_frame);
3309087SZhong.Wang@Sun.COM 
3319087SZhong.Wang@Sun.COM 	/*
3329087SZhong.Wang@Sun.COM 	 * Continue to initialize fcoe_frame_t
3339087SZhong.Wang@Sun.COM 	 */
3349087SZhong.Wang@Sun.COM 	frm->frm_hdr = (fcoe_fc_frame_header_t *)fmi->fmi_fc_frame;
3359087SZhong.Wang@Sun.COM 	frm->frm_ofh1 = NULL;
3369087SZhong.Wang@Sun.COM 	frm->frm_ofh2 = NULL;
3379087SZhong.Wang@Sun.COM 	frm->frm_fc_frame = (uint8_t *)frm->frm_hdr;
3389087SZhong.Wang@Sun.COM 	frm->frm_payload = sizeof (fcoe_fc_frame_header_t) +
3399087SZhong.Wang@Sun.COM 	    (uint8_t *)frm->frm_fc_frame;
3409087SZhong.Wang@Sun.COM 	return (frm);
3419087SZhong.Wang@Sun.COM }
3429087SZhong.Wang@Sun.COM 
3439087SZhong.Wang@Sun.COM /*
3449087SZhong.Wang@Sun.COM  * Sub routines called by interface functions
3459087SZhong.Wang@Sun.COM  */
3469087SZhong.Wang@Sun.COM 
3479087SZhong.Wang@Sun.COM /*
3489087SZhong.Wang@Sun.COM  * According to spec, fill EthernetII frame header, FCoE frame header
3499087SZhong.Wang@Sun.COM  * VLAN (not included for now)
3509087SZhong.Wang@Sun.COM  */
3519087SZhong.Wang@Sun.COM static void
fcoe_fill_frame_headers(fcoe_frame_t * frm)3529087SZhong.Wang@Sun.COM fcoe_fill_frame_headers(fcoe_frame_t *frm)
3539087SZhong.Wang@Sun.COM {
3549087SZhong.Wang@Sun.COM 	fcoe_i_frame_t *fmi = FRM2FMI(frm);
3559087SZhong.Wang@Sun.COM 
3569087SZhong.Wang@Sun.COM 	/*
3579087SZhong.Wang@Sun.COM 	 * Initialize ethernet frame header
3589087SZhong.Wang@Sun.COM 	 */
3599087SZhong.Wang@Sun.COM 	bcopy(FRM2MAC(frm)->fm_current_addr, &fmi->fmi_efh->ether_shost,
3609087SZhong.Wang@Sun.COM 	    ETHERADDRL);
3619087SZhong.Wang@Sun.COM 	bcopy(frm->frm_eport->eport_efh_dst,
3629087SZhong.Wang@Sun.COM 	    &fmi->fmi_efh->ether_dhost, ETHERADDRL);
3639087SZhong.Wang@Sun.COM 	fmi->fmi_efh->ether_type = htons(ETHERTYPE_FCOE);
3649087SZhong.Wang@Sun.COM 
3659087SZhong.Wang@Sun.COM 	/*
3669087SZhong.Wang@Sun.COM 	 * Initialize FCoE frame header
3679087SZhong.Wang@Sun.COM 	 */
3689087SZhong.Wang@Sun.COM 	bzero(fmi->fmi_ffh, sizeof (fcoe_frame_header_t));
3699087SZhong.Wang@Sun.COM 	FCOE_ENCAPS_VER(fmi->fmi_ffh, FCOE_VER);
3709087SZhong.Wang@Sun.COM 	/* set to SOFi3 for the first frame of a sequence */
3719087SZhong.Wang@Sun.COM 	if (FRM_SEQ_CNT(frm) == 0) {
3729087SZhong.Wang@Sun.COM 		FCOE_V2B_1(0x2E, fmi->fmi_ffh->ffh_sof);
3739087SZhong.Wang@Sun.COM 	} else {
3749087SZhong.Wang@Sun.COM 		FCOE_V2B_1(0x36, fmi->fmi_ffh->ffh_sof);
3759087SZhong.Wang@Sun.COM 	}
3769087SZhong.Wang@Sun.COM }
3779087SZhong.Wang@Sun.COM 
3789087SZhong.Wang@Sun.COM /*
3799087SZhong.Wang@Sun.COM  * According to spec, fill FCOE frame tailer including CRC
3809087SZhong.Wang@Sun.COM  * VLAN (not included for now)
3819087SZhong.Wang@Sun.COM  */
3829087SZhong.Wang@Sun.COM static void
fcoe_fill_frame_tailers(fcoe_frame_t * frm)3839087SZhong.Wang@Sun.COM fcoe_fill_frame_tailers(fcoe_frame_t *frm)
3849087SZhong.Wang@Sun.COM {
3859087SZhong.Wang@Sun.COM 	uint32_t crc;
3869087SZhong.Wang@Sun.COM 
3879087SZhong.Wang@Sun.COM 	/*
3889087SZhong.Wang@Sun.COM 	 * Initialize FCoE frame tailer
3899087SZhong.Wang@Sun.COM 	 * CRC is not big endian, can't use macro V2B
3909087SZhong.Wang@Sun.COM 	 */
3919087SZhong.Wang@Sun.COM 	CRC32(crc, frm->frm_fc_frame, frm->frm_fc_frame_size,
3929087SZhong.Wang@Sun.COM 	    (uint32_t)~0, crc32_table);
3939087SZhong.Wang@Sun.COM 	FRM2FMI(frm)->fmi_fft->fft_crc[0] = 0xFF & (~crc);
3949087SZhong.Wang@Sun.COM 	FRM2FMI(frm)->fmi_fft->fft_crc[1] = 0xFF & (~crc >> 8);
3959087SZhong.Wang@Sun.COM 	FRM2FMI(frm)->fmi_fft->fft_crc[2] = 0xFF & (~crc >> 16);
3969087SZhong.Wang@Sun.COM 	FRM2FMI(frm)->fmi_fft->fft_crc[3] = 0xFF & (~crc >> 24);
3979087SZhong.Wang@Sun.COM 	if (FRM_F_CTL(frm) & 0x080000) {
3989087SZhong.Wang@Sun.COM 		FCOE_V2B_1(0x42, FRM2FMI(frm)->fmi_fft->fft_eof);
3999087SZhong.Wang@Sun.COM 	} else {
4009087SZhong.Wang@Sun.COM 		FCOE_V2B_1(0x41, FRM2FMI(frm)->fmi_fft->fft_eof);
4019087SZhong.Wang@Sun.COM 	}
4029087SZhong.Wang@Sun.COM 
4039087SZhong.Wang@Sun.COM 	FRM2FMI(frm)->fmi_fft->fft_resvd[0] = 0;
4049087SZhong.Wang@Sun.COM 	FRM2FMI(frm)->fmi_fft->fft_resvd[1] = 0;
4059087SZhong.Wang@Sun.COM 	FRM2FMI(frm)->fmi_fft->fft_resvd[2] = 0;
4069087SZhong.Wang@Sun.COM }
4079087SZhong.Wang@Sun.COM 
4089087SZhong.Wang@Sun.COM void
fcoe_mac_notify_link_up(void * arg)4099087SZhong.Wang@Sun.COM fcoe_mac_notify_link_up(void *arg)
4109087SZhong.Wang@Sun.COM {
4119087SZhong.Wang@Sun.COM 	fcoe_mac_t *mac = (fcoe_mac_t *)arg;
4129087SZhong.Wang@Sun.COM 
4139087SZhong.Wang@Sun.COM 	ASSERT(mac->fm_flags & FCOE_MAC_FLAG_BOUND);
4149087SZhong.Wang@Sun.COM 
4159087SZhong.Wang@Sun.COM 	mac->fm_client.ect_port_event(&mac->fm_eport,
4169087SZhong.Wang@Sun.COM 	    FCOE_NOTIFY_EPORT_LINK_UP);
4179087SZhong.Wang@Sun.COM }
4189087SZhong.Wang@Sun.COM void
fcoe_mac_notify_link_down(void * arg)4199087SZhong.Wang@Sun.COM fcoe_mac_notify_link_down(void *arg)
4209087SZhong.Wang@Sun.COM {
4219087SZhong.Wang@Sun.COM 	fcoe_mac_t *mac = (fcoe_mac_t *)arg;
4229087SZhong.Wang@Sun.COM 
4239087SZhong.Wang@Sun.COM 	if (mac->fm_flags & FCOE_MAC_FLAG_BOUND) {
4249087SZhong.Wang@Sun.COM 		mac->fm_client.ect_port_event(&mac->fm_eport,
4259087SZhong.Wang@Sun.COM 		    FCOE_NOTIFY_EPORT_LINK_DOWN);
4269087SZhong.Wang@Sun.COM 	}
4279087SZhong.Wang@Sun.COM }
4289087SZhong.Wang@Sun.COM 
4299087SZhong.Wang@Sun.COM int
fcoe_create_port(dev_info_t * parent,fcoe_mac_t * mac,int is_target)4309087SZhong.Wang@Sun.COM fcoe_create_port(dev_info_t *parent, fcoe_mac_t *mac, int is_target)
4319087SZhong.Wang@Sun.COM {
4329087SZhong.Wang@Sun.COM 	int		 rval	  = 0;
4339087SZhong.Wang@Sun.COM 	dev_info_t	*child	  = NULL;
4349087SZhong.Wang@Sun.COM 	char *devname = is_target ? FCOET_DRIVER_NAME : FCOEI_DRIVER_NAME;
4359087SZhong.Wang@Sun.COM 
4369087SZhong.Wang@Sun.COM 	ndi_devi_alloc_sleep(parent, devname, DEVI_PSEUDO_NODEID, &child);
4379087SZhong.Wang@Sun.COM 	if (child == NULL) {
4389087SZhong.Wang@Sun.COM 		FCOE_LOG("fcoe", "fail to create new devinfo");
4399087SZhong.Wang@Sun.COM 		return (NDI_FAILURE);
4409087SZhong.Wang@Sun.COM 	}
4419087SZhong.Wang@Sun.COM 
4429307Skelly.hu@Sun.COM 	if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
4439307Skelly.hu@Sun.COM 	    "mac_id", mac->fm_linkid) != DDI_PROP_SUCCESS) {
4449087SZhong.Wang@Sun.COM 		FCOE_LOG("fcoe",
4459307Skelly.hu@Sun.COM 		    "fcoe%d: prop_update port mac id failed for mac %d",
4469307Skelly.hu@Sun.COM 		    ddi_get_instance(parent), mac->fm_linkid);
4479087SZhong.Wang@Sun.COM 		(void) ndi_devi_free(child);
4489087SZhong.Wang@Sun.COM 		return (NDI_FAILURE);
4499087SZhong.Wang@Sun.COM 	}
4509087SZhong.Wang@Sun.COM 
4519087SZhong.Wang@Sun.COM 	rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
4529087SZhong.Wang@Sun.COM 	if (rval != NDI_SUCCESS) {
4539307Skelly.hu@Sun.COM 		FCOE_LOG("fcoe", "fcoe%d: online_driver failed for mac %d",
4549307Skelly.hu@Sun.COM 		    ddi_get_instance(parent), mac->fm_linkid);
4559087SZhong.Wang@Sun.COM 		return (NDI_FAILURE);
4569087SZhong.Wang@Sun.COM 	}
4579087SZhong.Wang@Sun.COM 	mac->fm_client_dev = child;
4589087SZhong.Wang@Sun.COM 
4599087SZhong.Wang@Sun.COM 	return (rval);
4609087SZhong.Wang@Sun.COM }
4619087SZhong.Wang@Sun.COM 
4629087SZhong.Wang@Sun.COM int
fcoe_delete_port(dev_info_t * parent,fcoeio_t * fcoeio,datalink_id_t linkid,uint64_t * is_target)4639895SKevin.Yu@Sun.COM fcoe_delete_port(dev_info_t *parent, fcoeio_t *fcoeio, datalink_id_t linkid,
4649895SKevin.Yu@Sun.COM     uint64_t *is_target)
4659087SZhong.Wang@Sun.COM {
4669087SZhong.Wang@Sun.COM 	int		 rval = 0;
4679087SZhong.Wang@Sun.COM 	fcoe_mac_t	*mac;
4689087SZhong.Wang@Sun.COM 
4699307Skelly.hu@Sun.COM 	mac = fcoe_lookup_mac_by_id(linkid);
4709087SZhong.Wang@Sun.COM 	if (mac == NULL) {
4719087SZhong.Wang@Sun.COM 		fcoeio->fcoeio_status = FCOEIOE_MAC_NOT_FOUND;
4729087SZhong.Wang@Sun.COM 		return (EINVAL);
4739087SZhong.Wang@Sun.COM 	}
4749087SZhong.Wang@Sun.COM 
4759895SKevin.Yu@Sun.COM 	*is_target = EPORT_CLT_TYPE(&mac->fm_eport);
4769087SZhong.Wang@Sun.COM 	if ((mac->fm_flags & FCOE_MAC_FLAG_ENABLED) != FCOE_MAC_FLAG_ENABLED) {
4779087SZhong.Wang@Sun.COM 		fcoeio->fcoeio_status = FCOEIOE_ALREADY;
4789087SZhong.Wang@Sun.COM 		return (EALREADY);
4799087SZhong.Wang@Sun.COM 	}
4809087SZhong.Wang@Sun.COM 
48110264SZhong.Wang@Sun.COM 	if (!(mac->fm_flags & FCOE_MAC_FLAG_BOUND)) {
48210264SZhong.Wang@Sun.COM 		/*
48310264SZhong.Wang@Sun.COM 		 * It means that deferred detach has finished
48410264SZhong.Wang@Sun.COM 		 * of last delete operation
48510264SZhong.Wang@Sun.COM 		 */
48610264SZhong.Wang@Sun.COM 		goto skip_devi_offline;
48710264SZhong.Wang@Sun.COM 	}
48810264SZhong.Wang@Sun.COM 
4899087SZhong.Wang@Sun.COM 	atomic_and_32(&mac->fm_eport.eport_flags, ~EPORT_FLAG_MAC_IN_USE);
49010264SZhong.Wang@Sun.COM 	mac->fm_flags |= FCOE_MAC_FLAG_USER_DEL;
4919087SZhong.Wang@Sun.COM 	rval = ndi_devi_offline(mac->fm_client_dev, NDI_DEVI_REMOVE);
4929087SZhong.Wang@Sun.COM 	if (rval != NDI_SUCCESS) {
4939087SZhong.Wang@Sun.COM 		FCOE_LOG("fcoe", "fcoe%d: offline_driver %s failed",
4949087SZhong.Wang@Sun.COM 		    ddi_get_instance(parent),
4959087SZhong.Wang@Sun.COM 		    ddi_get_name(mac->fm_client_dev));
4969087SZhong.Wang@Sun.COM 		atomic_or_32(&mac->fm_eport.eport_flags,
4979087SZhong.Wang@Sun.COM 		    EPORT_FLAG_MAC_IN_USE);
4989087SZhong.Wang@Sun.COM 
4999087SZhong.Wang@Sun.COM 		fcoeio->fcoeio_status = FCOEIOE_OFFLINE_FAILURE;
5009087SZhong.Wang@Sun.COM 		return (EBUSY);
5019087SZhong.Wang@Sun.COM 	}
50210264SZhong.Wang@Sun.COM 
50310264SZhong.Wang@Sun.COM skip_devi_offline:
5049087SZhong.Wang@Sun.COM 	(void) fcoe_close_mac(mac);
5059087SZhong.Wang@Sun.COM 	fcoe_destroy_mac(mac);
5069087SZhong.Wang@Sun.COM 	return (0);
5079087SZhong.Wang@Sun.COM }
508