xref: /illumos-gate/usr/src/uts/common/io/fcoe/fcoe_fc.c (revision c61a1653)
12a8164dfSZhong Wang /*
22a8164dfSZhong Wang  * CDDL HEADER START
32a8164dfSZhong Wang  *
42a8164dfSZhong Wang  * The contents of this file are subject to the terms of the
52a8164dfSZhong Wang  * Common Development and Distribution License (the "License").
62a8164dfSZhong Wang  * You may not use this file except in compliance with the License.
72a8164dfSZhong Wang  *
82a8164dfSZhong Wang  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92a8164dfSZhong Wang  * or http://www.opensolaris.org/os/licensing.
102a8164dfSZhong Wang  * See the License for the specific language governing permissions
112a8164dfSZhong Wang  * and limitations under the License.
122a8164dfSZhong Wang  *
132a8164dfSZhong Wang  * When distributing Covered Code, include this CDDL HEADER in each
142a8164dfSZhong Wang  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152a8164dfSZhong Wang  * If applicable, add the following below this CDDL HEADER, with the
162a8164dfSZhong Wang  * fields enclosed by brackets "[]" replaced with your own identifying
172a8164dfSZhong Wang  * information: Portions Copyright [yyyy] [name of copyright owner]
182a8164dfSZhong Wang  *
192a8164dfSZhong Wang  * CDDL HEADER END
202a8164dfSZhong Wang  */
212a8164dfSZhong Wang 
222a8164dfSZhong Wang /*
232a8164dfSZhong Wang  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
242a8164dfSZhong Wang  * Use is subject to license terms.
25*c61a1653SRyan Zezeski  * Copyright 2019 Joyent, Inc.
262a8164dfSZhong Wang  */
272a8164dfSZhong Wang 
282a8164dfSZhong Wang /*
292a8164dfSZhong Wang  * This file defines interfaces between fcoe and its clients (FCoEI/FCoET)
302a8164dfSZhong Wang  */
312a8164dfSZhong Wang 
322a8164dfSZhong Wang #include <sys/ddi.h>
332a8164dfSZhong Wang #include <sys/sunddi.h>
342a8164dfSZhong Wang #include <sys/sunndi.h>
352a8164dfSZhong Wang #include <sys/byteorder.h>
362a8164dfSZhong Wang #include <sys/atomic.h>
372a8164dfSZhong Wang #include <sys/sysmacros.h>
382a8164dfSZhong Wang #include <sys/cmn_err.h>
392a8164dfSZhong Wang #include <sys/crc32.h>
402a8164dfSZhong Wang #include <sys/fcntl.h>
412a8164dfSZhong Wang #include <sys/unistd.h>
422a8164dfSZhong Wang #include <sys/mac_client.h>
43*c61a1653SRyan Zezeski #include <sys/strsubr.h>
442a8164dfSZhong Wang 
452a8164dfSZhong Wang /*
462a8164dfSZhong Wang  * FCoE header files
472a8164dfSZhong Wang  */
482a8164dfSZhong Wang #include <sys/fcoe/fcoeio.h>
492a8164dfSZhong Wang #include <sys/fcoe/fcoe_common.h>
502a8164dfSZhong Wang 
512a8164dfSZhong Wang /*
522a8164dfSZhong Wang  * Driver's own header files
532a8164dfSZhong Wang  */
542a8164dfSZhong Wang #include <fcoe.h>
552a8164dfSZhong Wang #include <fcoe_fc.h>
562a8164dfSZhong Wang #include <fcoe_eth.h>
572a8164dfSZhong Wang 
582a8164dfSZhong Wang static void fcoe_fill_frame_headers(fcoe_frame_t *frm);
592a8164dfSZhong Wang static void fcoe_fill_frame_tailers(fcoe_frame_t *frm);
602a8164dfSZhong Wang static void fcoe_deregister_client(fcoe_port_t *eport);
612a8164dfSZhong Wang static int fcoe_ctl(fcoe_port_t *eport, int cmd, void *arg);
622a8164dfSZhong Wang static void fcoe_tx_frame(fcoe_frame_t *frm);
632a8164dfSZhong Wang static void *fcoe_alloc_netb(fcoe_port_t *eport,
642a8164dfSZhong Wang     uint32_t fc_frame_size, uint8_t **ppfc);
652a8164dfSZhong Wang static void fcoe_free_netb(void *netb);
662a8164dfSZhong Wang 
672a8164dfSZhong Wang /*
682a8164dfSZhong Wang  * Only this function will be called explicitly by clients
692a8164dfSZhong Wang  * Register the specified client port (fcoei/fcoet)
702a8164dfSZhong Wang  */
712a8164dfSZhong Wang fcoe_port_t *
fcoe_register_client(fcoe_client_t * client)722a8164dfSZhong Wang fcoe_register_client(fcoe_client_t *client)
732a8164dfSZhong Wang {
742a8164dfSZhong Wang 	fcoe_mac_t	*mac;
752a8164dfSZhong Wang 	fcoe_port_t	*eport;
762a8164dfSZhong Wang 
777ff83669SZhong Wang 	if (client->ect_fcoe_ver != fcoe_ver_now) {
787ff83669SZhong Wang 		cmn_err(CE_WARN, "FCoE modules version mismatch, "
797ff83669SZhong Wang 		    "fail registering client.");
807ff83669SZhong Wang 		return (NULL);
817ff83669SZhong Wang 	}
822a8164dfSZhong Wang 
832a8164dfSZhong Wang 	/*
842a8164dfSZhong Wang 	 * We will not come here, when someone is changing ss_mac_list,
852a8164dfSZhong Wang 	 * so it's safe to go through ss_mac_list.
862a8164dfSZhong Wang 	 */
872a8164dfSZhong Wang 	for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
882a8164dfSZhong Wang 	    mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
89d4401b99SKelly Hu 		if (client->ect_channelid == mac->fm_linkid) {
902a8164dfSZhong Wang 			break;
912a8164dfSZhong Wang 		}
922a8164dfSZhong Wang 	}
932a8164dfSZhong Wang 
942a8164dfSZhong Wang 	if (mac == NULL) {
952a8164dfSZhong Wang 		FCOE_LOG(0, "can't find the MAC you want to bind");
962a8164dfSZhong Wang 		return (NULL);
972a8164dfSZhong Wang 	}
982a8164dfSZhong Wang 
992a8164dfSZhong Wang 	if (mac->fm_flags & FCOE_MAC_FLAG_BOUND) {
1002a8164dfSZhong Wang 		FCOE_LOG(0, "the MAC you want to bind is bound already");
1012a8164dfSZhong Wang 		return (NULL);
1022a8164dfSZhong Wang 	}
1032a8164dfSZhong Wang 
1042a8164dfSZhong Wang 	atomic_or_32(&mac->fm_flags, FCOE_MAC_FLAG_BOUND);
1052a8164dfSZhong Wang 	bcopy(client, &mac->fm_client, sizeof (fcoe_client_t));
1062a8164dfSZhong Wang 
1072a8164dfSZhong Wang 	/*
1082a8164dfSZhong Wang 	 * fcoe_port_t initialization
1092a8164dfSZhong Wang 	 */
1102a8164dfSZhong Wang 	eport = &mac->fm_eport;
1112a8164dfSZhong Wang 	eport->eport_flags = client->ect_eport_flags | EPORT_FLAG_MAC_IN_USE;
1122a8164dfSZhong Wang 	eport->eport_fcoe_private = mac;
1132a8164dfSZhong Wang 	eport->eport_client_private = client->ect_client_port_struct;
1142a8164dfSZhong Wang 	eport->eport_max_fc_frame_size = 2136;
1152a8164dfSZhong Wang 	eport->eport_tx_frame = fcoe_tx_frame;
1162a8164dfSZhong Wang 	eport->eport_alloc_frame = fcoe_allocate_frame;
1172a8164dfSZhong Wang 	eport->eport_release_frame = fcoe_release_frame;
1182a8164dfSZhong Wang 	eport->eport_alloc_netb = fcoe_alloc_netb;
1192a8164dfSZhong Wang 	eport->eport_free_netb = fcoe_free_netb;
1202a8164dfSZhong Wang 	eport->eport_deregister_client = fcoe_deregister_client;
1212a8164dfSZhong Wang 	eport->eport_ctl = fcoe_ctl;
1222a8164dfSZhong Wang 	eport->eport_set_mac_address = fcoe_mac_set_address;
1232a8164dfSZhong Wang 
1242a8164dfSZhong Wang 	return (eport);
1252a8164dfSZhong Wang }
1262a8164dfSZhong Wang 
1272a8164dfSZhong Wang /*
1282a8164dfSZhong Wang  * The following routines will be called through vectors in fcoe_port_t
1292a8164dfSZhong Wang  */
1302a8164dfSZhong Wang 
1312a8164dfSZhong Wang /*
1322a8164dfSZhong Wang  * Deregister fcoet/fcoei modules, client should make sure the port is in
1332a8164dfSZhong Wang  * offline status already
1342a8164dfSZhong Wang  */
1352a8164dfSZhong Wang static void
fcoe_deregister_client(fcoe_port_t * eport)1362a8164dfSZhong Wang fcoe_deregister_client(fcoe_port_t *eport)
1372a8164dfSZhong Wang {
1382a8164dfSZhong Wang 	fcoe_mac_t	*mac = EPORT2MAC(eport);
1392a8164dfSZhong Wang 
1402a8164dfSZhong Wang 	/*
1412a8164dfSZhong Wang 	 * Wait for all the related frame to be freed, this should be fast
1422a8164dfSZhong Wang 	 * because before deregister fcoei/fcoet will make sure its port
1432a8164dfSZhong Wang 	 * is already in offline status so no frame will be received or sent
1442a8164dfSZhong Wang 	 * any more
1452a8164dfSZhong Wang 	 */
1462a8164dfSZhong Wang 	while (mac->fm_frm_cnt > 0) {
1472a8164dfSZhong Wang 		delay(10);
1482a8164dfSZhong Wang 	}
1492a8164dfSZhong Wang 
1502a8164dfSZhong Wang 	atomic_and_32(&EPORT2MAC(eport)->fm_flags, ~FCOE_MAC_FLAG_BOUND);
1517ff83669SZhong Wang 	atomic_and_32(&mac->fm_eport.eport_flags, ~EPORT_FLAG_MAC_IN_USE);
1527ff83669SZhong Wang 	if (!(EPORT2MAC(eport)->fm_flags & FCOE_MAC_FLAG_USER_DEL)) {
1537ff83669SZhong Wang 		(void) fcoe_close_mac(mac);
1547ff83669SZhong Wang 		fcoe_destroy_mac(mac);
1557ff83669SZhong Wang 	}
1562a8164dfSZhong Wang }
1572a8164dfSZhong Wang 
1582a8164dfSZhong Wang /* ARGSUSED */
1592a8164dfSZhong Wang static int
fcoe_ctl(fcoe_port_t * eport,int cmd,void * arg)1602a8164dfSZhong Wang fcoe_ctl(fcoe_port_t *eport, int cmd, void *arg)
1612a8164dfSZhong Wang {
1622a8164dfSZhong Wang 	fcoe_mac_t	*mac = EPORT2MAC(eport);
1632a8164dfSZhong Wang 
1642a8164dfSZhong Wang 	switch (cmd) {
1652a8164dfSZhong Wang 		case FCOE_CMD_PORT_ONLINE:
1662a8164dfSZhong Wang 			/*
1672a8164dfSZhong Wang 			 * client ask us to online, so it's safe to post event
1682a8164dfSZhong Wang 			 * and data up
1692a8164dfSZhong Wang 			 */
1702a8164dfSZhong Wang 			if (fcoe_enable_callback(mac) == FCOE_FAILURE) {
1712a8164dfSZhong Wang 				return (FCOE_FAILURE);
1722a8164dfSZhong Wang 			}
1732a8164dfSZhong Wang 			mac->fm_state = FCOE_MAC_STATE_ONLINE;
1742a8164dfSZhong Wang 			if (mac->fm_link_state == FCOE_MAC_LINK_STATE_UP)
1752a8164dfSZhong Wang 				(void) ddi_taskq_dispatch(
1762a8164dfSZhong Wang 				    fcoe_global_ss->ss_watchdog_taskq,
1772a8164dfSZhong Wang 				    fcoe_mac_notify_link_up, mac, DDI_SLEEP);
1782a8164dfSZhong Wang 			break;
1792a8164dfSZhong Wang 		case FCOE_CMD_PORT_OFFLINE:
1802a8164dfSZhong Wang 			if (fcoe_disable_callback(mac) == FCOE_FAILURE) {
1812a8164dfSZhong Wang 				return (FCOE_FAILURE);
1822a8164dfSZhong Wang 			}
1832a8164dfSZhong Wang 			mac->fm_state = FCOE_MAC_STATE_OFFLINE;
1842a8164dfSZhong Wang 			// in case there are threads waiting
1852a8164dfSZhong Wang 			mutex_enter(&mac->fm_mutex);
1862a8164dfSZhong Wang 			cv_broadcast(&mac->fm_tx_cv);
1872a8164dfSZhong Wang 			mutex_exit(&mac->fm_mutex);
1882a8164dfSZhong Wang 			break;
1892a8164dfSZhong Wang 		default:
1902a8164dfSZhong Wang 			FCOE_LOG("fcoe", "fcoe_ctl, unsupported cmd %x", cmd);
1912a8164dfSZhong Wang 			break;
1922a8164dfSZhong Wang 	}
1932a8164dfSZhong Wang 
1942a8164dfSZhong Wang 	return (FCOE_SUCCESS);
1952a8164dfSZhong Wang }
1962a8164dfSZhong Wang 
1972a8164dfSZhong Wang /*
1982a8164dfSZhong Wang  * Transmit the specified frame to the link
1992a8164dfSZhong Wang  */
2002a8164dfSZhong Wang static void
fcoe_tx_frame(fcoe_frame_t * frm)2012a8164dfSZhong Wang fcoe_tx_frame(fcoe_frame_t *frm)
2022a8164dfSZhong Wang {
2032a8164dfSZhong Wang 	mblk_t		*ret_mblk = NULL;
2042a8164dfSZhong Wang 	fcoe_mac_t	*mac = FRM2MAC(frm);
2052a8164dfSZhong Wang 	mac_tx_cookie_t	ret_cookie;
2062a8164dfSZhong Wang 
2072a8164dfSZhong Wang 	fcoe_fill_frame_headers(frm);
2082a8164dfSZhong Wang 	fcoe_fill_frame_tailers(frm);
2092a8164dfSZhong Wang 
2102a8164dfSZhong Wang tx_frame:
2112a8164dfSZhong Wang 	ret_cookie = mac_tx(mac->fm_cli_handle, FRM2MBLK(frm), 0,
2122a8164dfSZhong Wang 	    MAC_TX_NO_ENQUEUE, &ret_mblk);
213ed74d7a1SToomas Soome 	if (ret_cookie != (mac_tx_cookie_t)NULL) {
214*c61a1653SRyan Zezeski 		frm->frm_netb = ret_mblk;
2152a8164dfSZhong Wang 		mutex_enter(&mac->fm_mutex);
216d3d50737SRafael Vanoni 		(void) cv_reltimedwait(&mac->fm_tx_cv, &mac->fm_mutex,
217d3d50737SRafael Vanoni 		    drv_usectohz(100000), TR_CLOCK_TICK);
2182a8164dfSZhong Wang 		mutex_exit(&mac->fm_mutex);
2192a8164dfSZhong Wang 
2202a8164dfSZhong Wang 		if (mac->fm_state == FCOE_MAC_STATE_OFFLINE) {
2212a8164dfSZhong Wang 			/*
2222a8164dfSZhong Wang 			 * we are doing offline, so just tell the upper that
2232a8164dfSZhong Wang 			 * this is finished, the cmd will be aborted soon.
2242a8164dfSZhong Wang 			 */
2252a8164dfSZhong Wang 			fcoe_free_netb(ret_mblk);
2262a8164dfSZhong Wang 		} else {
2272a8164dfSZhong Wang 			goto tx_frame;
2282a8164dfSZhong Wang 		}
2292a8164dfSZhong Wang 	}
2302a8164dfSZhong Wang 
2312a8164dfSZhong Wang 	/*
2322a8164dfSZhong Wang 	 * MAC driver will release the mblk of the frame
2332a8164dfSZhong Wang 	 * We need only release the frame itself
2342a8164dfSZhong Wang 	 */
2352a8164dfSZhong Wang 	mutex_enter(&FRM2MAC(frm)->fm_ss->ss_watch_mutex);
2362a8164dfSZhong Wang 	list_insert_tail(&FRM2MAC(frm)->fm_ss->ss_pfrm_list,
2372a8164dfSZhong Wang 	    FRM2FMI(frm));
2382a8164dfSZhong Wang 	mac->fm_frm_cnt ++;
2392a8164dfSZhong Wang 	if (FRM2MAC(frm)->fm_ss->ss_flags & SS_FLAG_DOG_WAITING) {
2402a8164dfSZhong Wang 		cv_signal(&FRM2MAC(frm)->fm_ss->ss_watch_cv);
2412a8164dfSZhong Wang 	}
2422a8164dfSZhong Wang 	mutex_exit(&FRM2MAC(frm)->fm_ss->ss_watch_mutex);
2432a8164dfSZhong Wang }
2442a8164dfSZhong Wang 
2452a8164dfSZhong Wang /*
2462a8164dfSZhong Wang  * Consider cache allocation in the future
2472a8164dfSZhong Wang  */
2482a8164dfSZhong Wang void
fcoe_release_frame(fcoe_frame_t * frame)2492a8164dfSZhong Wang fcoe_release_frame(fcoe_frame_t *frame)
2502a8164dfSZhong Wang {
2512a8164dfSZhong Wang 	kmem_free(frame, frame->frm_alloc_size);
2522a8164dfSZhong Wang }
2532a8164dfSZhong Wang 
2542a8164dfSZhong Wang static void *
fcoe_alloc_netb(fcoe_port_t * eport,uint32_t fc_frame_size,uint8_t ** ppfc)2552a8164dfSZhong Wang fcoe_alloc_netb(fcoe_port_t *eport, uint32_t fc_frame_size, uint8_t **ppfc)
2562a8164dfSZhong Wang {
2572a8164dfSZhong Wang 	mblk_t *mp;
2582a8164dfSZhong Wang 
2592a8164dfSZhong Wang 	mp = fcoe_get_mblk(eport->eport_fcoe_private,
2602a8164dfSZhong Wang 	    fc_frame_size + PADDING_SIZE);
2612a8164dfSZhong Wang 	if (mp != NULL) {
2622a8164dfSZhong Wang 		*ppfc = mp->b_rptr + PADDING_HEADER_SIZE;
2632a8164dfSZhong Wang 	}
2642a8164dfSZhong Wang 
2652a8164dfSZhong Wang 	return (mp);
2662a8164dfSZhong Wang }
2672a8164dfSZhong Wang 
2682a8164dfSZhong Wang static void
fcoe_free_netb(void * netb)2692a8164dfSZhong Wang fcoe_free_netb(void *netb)
2702a8164dfSZhong Wang {
271*c61a1653SRyan Zezeski 	freemsgchain((mblk_t *)netb);
2722a8164dfSZhong Wang }
2732a8164dfSZhong Wang 
2742a8164dfSZhong Wang fcoe_frame_t *
fcoe_allocate_frame(fcoe_port_t * eport,uint32_t fc_frame_size,void * xmp)2752a8164dfSZhong Wang fcoe_allocate_frame(fcoe_port_t *eport, uint32_t fc_frame_size, void *xmp)
2762a8164dfSZhong Wang {
2772a8164dfSZhong Wang 	fcoe_frame_t	*frm;
2782a8164dfSZhong Wang 	fcoe_i_frame_t	*fmi;
2792a8164dfSZhong Wang 	mblk_t		*mp = xmp;
2802a8164dfSZhong Wang 	uint32_t	 alloc_size;
2812a8164dfSZhong Wang 	uint32_t	 raw_frame_size;
2822a8164dfSZhong Wang 
2832a8164dfSZhong Wang 	if (fc_frame_size > 2136) {
2842a8164dfSZhong Wang 		FCOE_LOG("fcoe", "fcoe_allocate_frame %d > 2136",
2852a8164dfSZhong Wang 		    fc_frame_size);
2862a8164dfSZhong Wang 		return (NULL);
2872a8164dfSZhong Wang 	}
2882a8164dfSZhong Wang 
2892a8164dfSZhong Wang 	if (mp == NULL) {
2902a8164dfSZhong Wang 		/*
2912a8164dfSZhong Wang 		 * We are allocating solicited frame now
2922a8164dfSZhong Wang 		 */
2932a8164dfSZhong Wang 		raw_frame_size = PADDING_SIZE + fc_frame_size;
2942a8164dfSZhong Wang 		mp = fcoe_get_mblk(EPORT2MAC(eport), raw_frame_size);
2952a8164dfSZhong Wang 		if (mp == NULL) {
2962a8164dfSZhong Wang 			return (NULL);
2972a8164dfSZhong Wang 		}
2982a8164dfSZhong Wang 	}
2992a8164dfSZhong Wang 
3002a8164dfSZhong Wang 	alloc_size = sizeof (fcoe_frame_t) + sizeof (fcoe_i_frame_t) +
3012a8164dfSZhong Wang 	    EPORT2MAC(eport)->fm_client.ect_private_frame_struct_size;
3022a8164dfSZhong Wang 
3032a8164dfSZhong Wang 	/*
3042a8164dfSZhong Wang 	 * fcoe_frame_t initialization
3052a8164dfSZhong Wang 	 */
3062a8164dfSZhong Wang 	frm = (fcoe_frame_t *)kmem_alloc(alloc_size, KM_SLEEP);
3072a8164dfSZhong Wang 	frm->frm_alloc_size = alloc_size;
3082a8164dfSZhong Wang 	frm->frm_fc_frame_size = fc_frame_size;
3092a8164dfSZhong Wang 	frm->frm_payload_size = fc_frame_size -
3102a8164dfSZhong Wang 	    sizeof (fcoe_fc_frame_header_t);
3112a8164dfSZhong Wang 	frm->frm_fcoe_private = sizeof (fcoe_frame_t) + (uint8_t *)frm;
3122a8164dfSZhong Wang 	frm->frm_client_private = sizeof (fcoe_i_frame_t) +
3132a8164dfSZhong Wang 	    (uint8_t *)frm->frm_fcoe_private;
3142a8164dfSZhong Wang 	frm->frm_flags = 0;
3152a8164dfSZhong Wang 	frm->frm_eport = eport;
3162a8164dfSZhong Wang 	frm->frm_netb = mp;
3172a8164dfSZhong Wang 
3182a8164dfSZhong Wang 	/*
3192a8164dfSZhong Wang 	 * fcoe_i_frame_t initialization
3202a8164dfSZhong Wang 	 */
3212a8164dfSZhong Wang 	fmi = FRM2FMI(frm);
3222a8164dfSZhong Wang 	fmi->fmi_frame = frm;
3232a8164dfSZhong Wang 	fmi->fmi_mac = EPORT2MAC(eport);
3242a8164dfSZhong Wang 	fmi->fmi_efh = (void *)mp->b_rptr;
3252a8164dfSZhong Wang 
3262a8164dfSZhong Wang 	fmi->fmi_ffh = (fcoe_frame_header_t *)
3272a8164dfSZhong Wang 	    (sizeof (struct ether_header) + (uint8_t *)fmi->fmi_efh);
3282a8164dfSZhong Wang 
3292a8164dfSZhong Wang 	fmi->fmi_fc_frame = sizeof (fcoe_frame_header_t) +
3302a8164dfSZhong Wang 	    (uint8_t *)fmi->fmi_ffh;
3312a8164dfSZhong Wang 	fmi->fmi_fft = (fcoe_frame_tailer_t *)
3322a8164dfSZhong Wang 	    (fc_frame_size + (uint8_t *)fmi->fmi_fc_frame);
3332a8164dfSZhong Wang 
3342a8164dfSZhong Wang 	/*
3352a8164dfSZhong Wang 	 * Continue to initialize fcoe_frame_t
3362a8164dfSZhong Wang 	 */
3372a8164dfSZhong Wang 	frm->frm_hdr = (fcoe_fc_frame_header_t *)fmi->fmi_fc_frame;
3382a8164dfSZhong Wang 	frm->frm_ofh1 = NULL;
3392a8164dfSZhong Wang 	frm->frm_ofh2 = NULL;
3402a8164dfSZhong Wang 	frm->frm_fc_frame = (uint8_t *)frm->frm_hdr;
3412a8164dfSZhong Wang 	frm->frm_payload = sizeof (fcoe_fc_frame_header_t) +
3422a8164dfSZhong Wang 	    (uint8_t *)frm->frm_fc_frame;
3432a8164dfSZhong Wang 	return (frm);
3442a8164dfSZhong Wang }
3452a8164dfSZhong Wang 
3462a8164dfSZhong Wang /*
3472a8164dfSZhong Wang  * Sub routines called by interface functions
3482a8164dfSZhong Wang  */
3492a8164dfSZhong Wang 
3502a8164dfSZhong Wang /*
3512a8164dfSZhong Wang  * According to spec, fill EthernetII frame header, FCoE frame header
3522a8164dfSZhong Wang  * VLAN (not included for now)
3532a8164dfSZhong Wang  */
3542a8164dfSZhong Wang static void
fcoe_fill_frame_headers(fcoe_frame_t * frm)3552a8164dfSZhong Wang fcoe_fill_frame_headers(fcoe_frame_t *frm)
3562a8164dfSZhong Wang {
3572a8164dfSZhong Wang 	fcoe_i_frame_t *fmi = FRM2FMI(frm);
3582a8164dfSZhong Wang 
3592a8164dfSZhong Wang 	/*
3602a8164dfSZhong Wang 	 * Initialize ethernet frame header
3612a8164dfSZhong Wang 	 */
3622a8164dfSZhong Wang 	bcopy(FRM2MAC(frm)->fm_current_addr, &fmi->fmi_efh->ether_shost,
3632a8164dfSZhong Wang 	    ETHERADDRL);
3642a8164dfSZhong Wang 	bcopy(frm->frm_eport->eport_efh_dst,
3652a8164dfSZhong Wang 	    &fmi->fmi_efh->ether_dhost, ETHERADDRL);
3662a8164dfSZhong Wang 	fmi->fmi_efh->ether_type = htons(ETHERTYPE_FCOE);
3672a8164dfSZhong Wang 
3682a8164dfSZhong Wang 	/*
3692a8164dfSZhong Wang 	 * Initialize FCoE frame header
3702a8164dfSZhong Wang 	 */
3712a8164dfSZhong Wang 	bzero(fmi->fmi_ffh, sizeof (fcoe_frame_header_t));
3722a8164dfSZhong Wang 	FCOE_ENCAPS_VER(fmi->fmi_ffh, FCOE_VER);
3732a8164dfSZhong Wang 	/* set to SOFi3 for the first frame of a sequence */
3742a8164dfSZhong Wang 	if (FRM_SEQ_CNT(frm) == 0) {
3752a8164dfSZhong Wang 		FCOE_V2B_1(0x2E, fmi->fmi_ffh->ffh_sof);
3762a8164dfSZhong Wang 	} else {
3772a8164dfSZhong Wang 		FCOE_V2B_1(0x36, fmi->fmi_ffh->ffh_sof);
3782a8164dfSZhong Wang 	}
3792a8164dfSZhong Wang }
3802a8164dfSZhong Wang 
3812a8164dfSZhong Wang /*
3822a8164dfSZhong Wang  * According to spec, fill FCOE frame tailer including CRC
3832a8164dfSZhong Wang  * VLAN (not included for now)
3842a8164dfSZhong Wang  */
3852a8164dfSZhong Wang static void
fcoe_fill_frame_tailers(fcoe_frame_t * frm)3862a8164dfSZhong Wang fcoe_fill_frame_tailers(fcoe_frame_t *frm)
3872a8164dfSZhong Wang {
3882a8164dfSZhong Wang 	uint32_t crc;
3892a8164dfSZhong Wang 
3902a8164dfSZhong Wang 	/*
3912a8164dfSZhong Wang 	 * Initialize FCoE frame tailer
3922a8164dfSZhong Wang 	 * CRC is not big endian, can't use macro V2B
3932a8164dfSZhong Wang 	 */
3942a8164dfSZhong Wang 	CRC32(crc, frm->frm_fc_frame, frm->frm_fc_frame_size,
3952a8164dfSZhong Wang 	    (uint32_t)~0, crc32_table);
3962a8164dfSZhong Wang 	FRM2FMI(frm)->fmi_fft->fft_crc[0] = 0xFF & (~crc);
3972a8164dfSZhong Wang 	FRM2FMI(frm)->fmi_fft->fft_crc[1] = 0xFF & (~crc >> 8);
3982a8164dfSZhong Wang 	FRM2FMI(frm)->fmi_fft->fft_crc[2] = 0xFF & (~crc >> 16);
3992a8164dfSZhong Wang 	FRM2FMI(frm)->fmi_fft->fft_crc[3] = 0xFF & (~crc >> 24);
4002a8164dfSZhong Wang 	if (FRM_F_CTL(frm) & 0x080000) {
4012a8164dfSZhong Wang 		FCOE_V2B_1(0x42, FRM2FMI(frm)->fmi_fft->fft_eof);
4022a8164dfSZhong Wang 	} else {
4032a8164dfSZhong Wang 		FCOE_V2B_1(0x41, FRM2FMI(frm)->fmi_fft->fft_eof);
4042a8164dfSZhong Wang 	}
4052a8164dfSZhong Wang 
4062a8164dfSZhong Wang 	FRM2FMI(frm)->fmi_fft->fft_resvd[0] = 0;
4072a8164dfSZhong Wang 	FRM2FMI(frm)->fmi_fft->fft_resvd[1] = 0;
4082a8164dfSZhong Wang 	FRM2FMI(frm)->fmi_fft->fft_resvd[2] = 0;
4092a8164dfSZhong Wang }
4102a8164dfSZhong Wang 
4112a8164dfSZhong Wang void
fcoe_mac_notify_link_up(void * arg)4122a8164dfSZhong Wang fcoe_mac_notify_link_up(void *arg)
4132a8164dfSZhong Wang {
4142a8164dfSZhong Wang 	fcoe_mac_t *mac = (fcoe_mac_t *)arg;
4152a8164dfSZhong Wang 
4162a8164dfSZhong Wang 	ASSERT(mac->fm_flags & FCOE_MAC_FLAG_BOUND);
4172a8164dfSZhong Wang 
4182a8164dfSZhong Wang 	mac->fm_client.ect_port_event(&mac->fm_eport,
4192a8164dfSZhong Wang 	    FCOE_NOTIFY_EPORT_LINK_UP);
4202a8164dfSZhong Wang }
4212a8164dfSZhong Wang void
fcoe_mac_notify_link_down(void * arg)4222a8164dfSZhong Wang fcoe_mac_notify_link_down(void *arg)
4232a8164dfSZhong Wang {
4242a8164dfSZhong Wang 	fcoe_mac_t *mac = (fcoe_mac_t *)arg;
4252a8164dfSZhong Wang 
4262a8164dfSZhong Wang 	if (mac->fm_flags & FCOE_MAC_FLAG_BOUND) {
4272a8164dfSZhong Wang 		mac->fm_client.ect_port_event(&mac->fm_eport,
4282a8164dfSZhong Wang 		    FCOE_NOTIFY_EPORT_LINK_DOWN);
4292a8164dfSZhong Wang 	}
4302a8164dfSZhong Wang }
4312a8164dfSZhong Wang 
4322a8164dfSZhong Wang int
fcoe_create_port(dev_info_t * parent,fcoe_mac_t * mac,int is_target)4332a8164dfSZhong Wang fcoe_create_port(dev_info_t *parent, fcoe_mac_t *mac, int is_target)
4342a8164dfSZhong Wang {
4352a8164dfSZhong Wang 	int		 rval	  = 0;
4362a8164dfSZhong Wang 	dev_info_t	*child	  = NULL;
4372a8164dfSZhong Wang 	char *devname = is_target ? FCOET_DRIVER_NAME : FCOEI_DRIVER_NAME;
4382a8164dfSZhong Wang 
4392a8164dfSZhong Wang 	ndi_devi_alloc_sleep(parent, devname, DEVI_PSEUDO_NODEID, &child);
4402a8164dfSZhong Wang 	if (child == NULL) {
4412a8164dfSZhong Wang 		FCOE_LOG("fcoe", "fail to create new devinfo");
4422a8164dfSZhong Wang 		return (NDI_FAILURE);
4432a8164dfSZhong Wang 	}
4442a8164dfSZhong Wang 
445d4401b99SKelly Hu 	if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
446d4401b99SKelly Hu 	    "mac_id", mac->fm_linkid) != DDI_PROP_SUCCESS) {
4472a8164dfSZhong Wang 		FCOE_LOG("fcoe",
448d4401b99SKelly Hu 		    "fcoe%d: prop_update port mac id failed for mac %d",
449d4401b99SKelly Hu 		    ddi_get_instance(parent), mac->fm_linkid);
4502a8164dfSZhong Wang 		(void) ndi_devi_free(child);
4512a8164dfSZhong Wang 		return (NDI_FAILURE);
4522a8164dfSZhong Wang 	}
4532a8164dfSZhong Wang 
4542a8164dfSZhong Wang 	rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
4552a8164dfSZhong Wang 	if (rval != NDI_SUCCESS) {
456d4401b99SKelly Hu 		FCOE_LOG("fcoe", "fcoe%d: online_driver failed for mac %d",
457d4401b99SKelly Hu 		    ddi_get_instance(parent), mac->fm_linkid);
4582a8164dfSZhong Wang 		return (NDI_FAILURE);
4592a8164dfSZhong Wang 	}
4602a8164dfSZhong Wang 	mac->fm_client_dev = child;
4612a8164dfSZhong Wang 
4622a8164dfSZhong Wang 	return (rval);
4632a8164dfSZhong Wang }
4642a8164dfSZhong Wang 
4652a8164dfSZhong Wang int
fcoe_delete_port(dev_info_t * parent,fcoeio_t * fcoeio,datalink_id_t linkid,uint64_t * is_target)466e6eb57e7SKevin Yu fcoe_delete_port(dev_info_t *parent, fcoeio_t *fcoeio, datalink_id_t linkid,
467e6eb57e7SKevin Yu     uint64_t *is_target)
4682a8164dfSZhong Wang {
4692a8164dfSZhong Wang 	int		 rval = 0;
4702a8164dfSZhong Wang 	fcoe_mac_t	*mac;
4712a8164dfSZhong Wang 
472d4401b99SKelly Hu 	mac = fcoe_lookup_mac_by_id(linkid);
4732a8164dfSZhong Wang 	if (mac == NULL) {
4742a8164dfSZhong Wang 		fcoeio->fcoeio_status = FCOEIOE_MAC_NOT_FOUND;
4752a8164dfSZhong Wang 		return (EINVAL);
4762a8164dfSZhong Wang 	}
4772a8164dfSZhong Wang 
478e6eb57e7SKevin Yu 	*is_target = EPORT_CLT_TYPE(&mac->fm_eport);
4792a8164dfSZhong Wang 	if ((mac->fm_flags & FCOE_MAC_FLAG_ENABLED) != FCOE_MAC_FLAG_ENABLED) {
4802a8164dfSZhong Wang 		fcoeio->fcoeio_status = FCOEIOE_ALREADY;
4812a8164dfSZhong Wang 		return (EALREADY);
4822a8164dfSZhong Wang 	}
4832a8164dfSZhong Wang 
4847ff83669SZhong Wang 	if (!(mac->fm_flags & FCOE_MAC_FLAG_BOUND)) {
4857ff83669SZhong Wang 		/*
4867ff83669SZhong Wang 		 * It means that deferred detach has finished
4877ff83669SZhong Wang 		 * of last delete operation
4887ff83669SZhong Wang 		 */
4897ff83669SZhong Wang 		goto skip_devi_offline;
4907ff83669SZhong Wang 	}
4912a8164dfSZhong Wang 
4927ff83669SZhong Wang 	atomic_and_32(&mac->fm_eport.eport_flags, ~EPORT_FLAG_MAC_IN_USE);
4937ff83669SZhong Wang 	mac->fm_flags |= FCOE_MAC_FLAG_USER_DEL;
4942a8164dfSZhong Wang 	rval = ndi_devi_offline(mac->fm_client_dev, NDI_DEVI_REMOVE);
4952a8164dfSZhong Wang 	if (rval != NDI_SUCCESS) {
4962a8164dfSZhong Wang 		FCOE_LOG("fcoe", "fcoe%d: offline_driver %s failed",
4972a8164dfSZhong Wang 		    ddi_get_instance(parent),
4982a8164dfSZhong Wang 		    ddi_get_name(mac->fm_client_dev));
4992a8164dfSZhong Wang 		atomic_or_32(&mac->fm_eport.eport_flags,
5002a8164dfSZhong Wang 		    EPORT_FLAG_MAC_IN_USE);
5012a8164dfSZhong Wang 
5022a8164dfSZhong Wang 		fcoeio->fcoeio_status = FCOEIOE_OFFLINE_FAILURE;
5032a8164dfSZhong Wang 		return (EBUSY);
5042a8164dfSZhong Wang 	}
5057ff83669SZhong Wang 
5067ff83669SZhong Wang skip_devi_offline:
5072a8164dfSZhong Wang 	(void) fcoe_close_mac(mac);
5082a8164dfSZhong Wang 	fcoe_destroy_mac(mac);
5092a8164dfSZhong Wang 	return (0);
5102a8164dfSZhong Wang }
511