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