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 * 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 759307Skelly.hu@Sun.COM ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 769087SZhong.Wang@Sun.COM 779087SZhong.Wang@Sun.COM /* 789087SZhong.Wang@Sun.COM * We will not come here, when someone is changing ss_mac_list, 799087SZhong.Wang@Sun.COM * so it's safe to go through ss_mac_list. 809087SZhong.Wang@Sun.COM */ 819087SZhong.Wang@Sun.COM for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; 829087SZhong.Wang@Sun.COM mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { 839307Skelly.hu@Sun.COM if (client->ect_channelid == mac->fm_linkid) { 849087SZhong.Wang@Sun.COM break; 859087SZhong.Wang@Sun.COM } 869087SZhong.Wang@Sun.COM } 879087SZhong.Wang@Sun.COM 889087SZhong.Wang@Sun.COM if (mac == NULL) { 899087SZhong.Wang@Sun.COM FCOE_LOG(0, "can't find the MAC you want to bind"); 909087SZhong.Wang@Sun.COM return (NULL); 919087SZhong.Wang@Sun.COM } 929087SZhong.Wang@Sun.COM 939087SZhong.Wang@Sun.COM if (mac->fm_flags & FCOE_MAC_FLAG_BOUND) { 949087SZhong.Wang@Sun.COM FCOE_LOG(0, "the MAC you want to bind is bound already"); 959087SZhong.Wang@Sun.COM return (NULL); 969087SZhong.Wang@Sun.COM } 979087SZhong.Wang@Sun.COM 989087SZhong.Wang@Sun.COM atomic_or_32(&mac->fm_flags, FCOE_MAC_FLAG_BOUND); 999087SZhong.Wang@Sun.COM bcopy(client, &mac->fm_client, sizeof (fcoe_client_t)); 1009087SZhong.Wang@Sun.COM 1019087SZhong.Wang@Sun.COM /* 1029087SZhong.Wang@Sun.COM * fcoe_port_t initialization 1039087SZhong.Wang@Sun.COM */ 1049087SZhong.Wang@Sun.COM eport = &mac->fm_eport; 1059087SZhong.Wang@Sun.COM eport->eport_flags = client->ect_eport_flags | EPORT_FLAG_MAC_IN_USE; 1069087SZhong.Wang@Sun.COM eport->eport_fcoe_private = mac; 1079087SZhong.Wang@Sun.COM eport->eport_client_private = client->ect_client_port_struct; 1089087SZhong.Wang@Sun.COM eport->eport_max_fc_frame_size = 2136; 1099087SZhong.Wang@Sun.COM eport->eport_tx_frame = fcoe_tx_frame; 1109087SZhong.Wang@Sun.COM eport->eport_alloc_frame = fcoe_allocate_frame; 1119087SZhong.Wang@Sun.COM eport->eport_release_frame = fcoe_release_frame; 1129087SZhong.Wang@Sun.COM eport->eport_alloc_netb = fcoe_alloc_netb; 1139087SZhong.Wang@Sun.COM eport->eport_free_netb = fcoe_free_netb; 1149087SZhong.Wang@Sun.COM eport->eport_deregister_client = fcoe_deregister_client; 1159087SZhong.Wang@Sun.COM eport->eport_ctl = fcoe_ctl; 1169087SZhong.Wang@Sun.COM eport->eport_set_mac_address = fcoe_mac_set_address; 1179087SZhong.Wang@Sun.COM 1189087SZhong.Wang@Sun.COM return (eport); 1199087SZhong.Wang@Sun.COM } 1209087SZhong.Wang@Sun.COM 1219087SZhong.Wang@Sun.COM /* 1229087SZhong.Wang@Sun.COM * The following routines will be called through vectors in fcoe_port_t 1239087SZhong.Wang@Sun.COM */ 1249087SZhong.Wang@Sun.COM 1259087SZhong.Wang@Sun.COM /* 1269087SZhong.Wang@Sun.COM * Deregister fcoet/fcoei modules, client should make sure the port is in 1279087SZhong.Wang@Sun.COM * offline status already 1289087SZhong.Wang@Sun.COM */ 1299087SZhong.Wang@Sun.COM static void 1309087SZhong.Wang@Sun.COM fcoe_deregister_client(fcoe_port_t *eport) 1319087SZhong.Wang@Sun.COM { 1329087SZhong.Wang@Sun.COM fcoe_mac_t *mac = EPORT2MAC(eport); 1339087SZhong.Wang@Sun.COM 1349307Skelly.hu@Sun.COM ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 1359087SZhong.Wang@Sun.COM 1369087SZhong.Wang@Sun.COM /* 1379087SZhong.Wang@Sun.COM * Wait for all the related frame to be freed, this should be fast 1389087SZhong.Wang@Sun.COM * because before deregister fcoei/fcoet will make sure its port 1399087SZhong.Wang@Sun.COM * is already in offline status so no frame will be received or sent 1409087SZhong.Wang@Sun.COM * any more 1419087SZhong.Wang@Sun.COM */ 1429087SZhong.Wang@Sun.COM while (mac->fm_frm_cnt > 0) { 1439087SZhong.Wang@Sun.COM delay(10); 1449087SZhong.Wang@Sun.COM } 1459087SZhong.Wang@Sun.COM 1469087SZhong.Wang@Sun.COM atomic_and_32(&EPORT2MAC(eport)->fm_flags, ~FCOE_MAC_FLAG_BOUND); 1479087SZhong.Wang@Sun.COM } 1489087SZhong.Wang@Sun.COM 1499087SZhong.Wang@Sun.COM /* ARGSUSED */ 1509087SZhong.Wang@Sun.COM static int 1519087SZhong.Wang@Sun.COM fcoe_ctl(fcoe_port_t *eport, int cmd, void *arg) 1529087SZhong.Wang@Sun.COM { 1539087SZhong.Wang@Sun.COM fcoe_mac_t *mac = EPORT2MAC(eport); 1549087SZhong.Wang@Sun.COM 1559087SZhong.Wang@Sun.COM switch (cmd) { 1569087SZhong.Wang@Sun.COM case FCOE_CMD_PORT_ONLINE: 1579087SZhong.Wang@Sun.COM /* 1589087SZhong.Wang@Sun.COM * client ask us to online, so it's safe to post event 1599087SZhong.Wang@Sun.COM * and data up 1609087SZhong.Wang@Sun.COM */ 1619087SZhong.Wang@Sun.COM if (fcoe_enable_callback(mac) == FCOE_FAILURE) { 1629087SZhong.Wang@Sun.COM return (FCOE_FAILURE); 1639087SZhong.Wang@Sun.COM } 1649087SZhong.Wang@Sun.COM mac->fm_state = FCOE_MAC_STATE_ONLINE; 1659087SZhong.Wang@Sun.COM if (mac->fm_link_state == FCOE_MAC_LINK_STATE_UP) 1669087SZhong.Wang@Sun.COM (void) ddi_taskq_dispatch( 1679087SZhong.Wang@Sun.COM fcoe_global_ss->ss_watchdog_taskq, 1689087SZhong.Wang@Sun.COM fcoe_mac_notify_link_up, mac, DDI_SLEEP); 1699087SZhong.Wang@Sun.COM break; 1709087SZhong.Wang@Sun.COM case FCOE_CMD_PORT_OFFLINE: 1719087SZhong.Wang@Sun.COM if (fcoe_disable_callback(mac) == FCOE_FAILURE) { 1729087SZhong.Wang@Sun.COM return (FCOE_FAILURE); 1739087SZhong.Wang@Sun.COM } 1749087SZhong.Wang@Sun.COM mac->fm_state = FCOE_MAC_STATE_OFFLINE; 1759087SZhong.Wang@Sun.COM // in case there are threads waiting 1769087SZhong.Wang@Sun.COM mutex_enter(&mac->fm_mutex); 1779087SZhong.Wang@Sun.COM cv_broadcast(&mac->fm_tx_cv); 1789087SZhong.Wang@Sun.COM mutex_exit(&mac->fm_mutex); 1799087SZhong.Wang@Sun.COM break; 1809087SZhong.Wang@Sun.COM default: 1819087SZhong.Wang@Sun.COM FCOE_LOG("fcoe", "fcoe_ctl, unsupported cmd %x", cmd); 1829087SZhong.Wang@Sun.COM break; 1839087SZhong.Wang@Sun.COM } 1849087SZhong.Wang@Sun.COM 1859087SZhong.Wang@Sun.COM return (FCOE_SUCCESS); 1869087SZhong.Wang@Sun.COM } 1879087SZhong.Wang@Sun.COM 1889087SZhong.Wang@Sun.COM /* 1899087SZhong.Wang@Sun.COM * Transmit the specified frame to the link 1909087SZhong.Wang@Sun.COM */ 1919087SZhong.Wang@Sun.COM static void 1929087SZhong.Wang@Sun.COM fcoe_tx_frame(fcoe_frame_t *frm) 1939087SZhong.Wang@Sun.COM { 1949087SZhong.Wang@Sun.COM mblk_t *ret_mblk = NULL; 1959087SZhong.Wang@Sun.COM fcoe_mac_t *mac = FRM2MAC(frm); 1969087SZhong.Wang@Sun.COM mac_tx_cookie_t ret_cookie; 1979087SZhong.Wang@Sun.COM 1989087SZhong.Wang@Sun.COM fcoe_fill_frame_headers(frm); 1999087SZhong.Wang@Sun.COM fcoe_fill_frame_tailers(frm); 2009087SZhong.Wang@Sun.COM 2019087SZhong.Wang@Sun.COM tx_frame: 2029087SZhong.Wang@Sun.COM ret_cookie = mac_tx(mac->fm_cli_handle, FRM2MBLK(frm), 0, 2039087SZhong.Wang@Sun.COM MAC_TX_NO_ENQUEUE, &ret_mblk); 2049087SZhong.Wang@Sun.COM if (ret_cookie != NULL) { 2059087SZhong.Wang@Sun.COM mutex_enter(&mac->fm_mutex); 2069087SZhong.Wang@Sun.COM (void) cv_timedwait(&mac->fm_tx_cv, &mac->fm_mutex, 2079087SZhong.Wang@Sun.COM ddi_get_lbolt() + drv_usectohz(100000)); 2089087SZhong.Wang@Sun.COM mutex_exit(&mac->fm_mutex); 2099087SZhong.Wang@Sun.COM 2109087SZhong.Wang@Sun.COM if (mac->fm_state == FCOE_MAC_STATE_OFFLINE) { 2119087SZhong.Wang@Sun.COM /* 2129087SZhong.Wang@Sun.COM * we are doing offline, so just tell the upper that 2139087SZhong.Wang@Sun.COM * this is finished, the cmd will be aborted soon. 2149087SZhong.Wang@Sun.COM */ 2159087SZhong.Wang@Sun.COM fcoe_free_netb(ret_mblk); 2169087SZhong.Wang@Sun.COM } else { 2179087SZhong.Wang@Sun.COM goto tx_frame; 2189087SZhong.Wang@Sun.COM } 2199087SZhong.Wang@Sun.COM } 2209087SZhong.Wang@Sun.COM 2219087SZhong.Wang@Sun.COM /* 2229087SZhong.Wang@Sun.COM * MAC driver will release the mblk of the frame 2239087SZhong.Wang@Sun.COM * We need only release the frame itself 2249087SZhong.Wang@Sun.COM */ 2259087SZhong.Wang@Sun.COM mutex_enter(&FRM2MAC(frm)->fm_ss->ss_watch_mutex); 2269087SZhong.Wang@Sun.COM list_insert_tail(&FRM2MAC(frm)->fm_ss->ss_pfrm_list, 2279087SZhong.Wang@Sun.COM FRM2FMI(frm)); 2289087SZhong.Wang@Sun.COM mac->fm_frm_cnt ++; 2299087SZhong.Wang@Sun.COM if (FRM2MAC(frm)->fm_ss->ss_flags & SS_FLAG_DOG_WAITING) { 2309087SZhong.Wang@Sun.COM cv_signal(&FRM2MAC(frm)->fm_ss->ss_watch_cv); 2319087SZhong.Wang@Sun.COM } 2329087SZhong.Wang@Sun.COM mutex_exit(&FRM2MAC(frm)->fm_ss->ss_watch_mutex); 2339087SZhong.Wang@Sun.COM } 2349087SZhong.Wang@Sun.COM 2359087SZhong.Wang@Sun.COM /* 2369087SZhong.Wang@Sun.COM * Consider cache allocation in the future 2379087SZhong.Wang@Sun.COM */ 2389087SZhong.Wang@Sun.COM void 2399087SZhong.Wang@Sun.COM fcoe_release_frame(fcoe_frame_t *frame) 2409087SZhong.Wang@Sun.COM { 2419087SZhong.Wang@Sun.COM kmem_free(frame, frame->frm_alloc_size); 2429087SZhong.Wang@Sun.COM } 2439087SZhong.Wang@Sun.COM 2449087SZhong.Wang@Sun.COM static void * 2459087SZhong.Wang@Sun.COM fcoe_alloc_netb(fcoe_port_t *eport, uint32_t fc_frame_size, uint8_t **ppfc) 2469087SZhong.Wang@Sun.COM { 2479087SZhong.Wang@Sun.COM mblk_t *mp; 2489087SZhong.Wang@Sun.COM 2499087SZhong.Wang@Sun.COM mp = fcoe_get_mblk(eport->eport_fcoe_private, 2509087SZhong.Wang@Sun.COM fc_frame_size + PADDING_SIZE); 2519087SZhong.Wang@Sun.COM if (mp != NULL) { 2529087SZhong.Wang@Sun.COM *ppfc = mp->b_rptr + PADDING_HEADER_SIZE; 2539087SZhong.Wang@Sun.COM } 2549087SZhong.Wang@Sun.COM 2559087SZhong.Wang@Sun.COM return (mp); 2569087SZhong.Wang@Sun.COM } 2579087SZhong.Wang@Sun.COM 2589087SZhong.Wang@Sun.COM static void 2599087SZhong.Wang@Sun.COM fcoe_free_netb(void *netb) 2609087SZhong.Wang@Sun.COM { 2619087SZhong.Wang@Sun.COM freeb((mblk_t *)netb); 2629087SZhong.Wang@Sun.COM } 2639087SZhong.Wang@Sun.COM 2649087SZhong.Wang@Sun.COM fcoe_frame_t * 2659087SZhong.Wang@Sun.COM fcoe_allocate_frame(fcoe_port_t *eport, uint32_t fc_frame_size, void *xmp) 2669087SZhong.Wang@Sun.COM { 2679087SZhong.Wang@Sun.COM fcoe_frame_t *frm; 2689087SZhong.Wang@Sun.COM fcoe_i_frame_t *fmi; 2699087SZhong.Wang@Sun.COM mblk_t *mp = xmp; 2709087SZhong.Wang@Sun.COM uint32_t alloc_size; 2719087SZhong.Wang@Sun.COM uint32_t raw_frame_size; 2729087SZhong.Wang@Sun.COM 2739087SZhong.Wang@Sun.COM if (fc_frame_size > 2136) { 2749087SZhong.Wang@Sun.COM FCOE_LOG("fcoe", "fcoe_allocate_frame %d > 2136", 2759087SZhong.Wang@Sun.COM fc_frame_size); 2769087SZhong.Wang@Sun.COM return (NULL); 2779087SZhong.Wang@Sun.COM } 2789087SZhong.Wang@Sun.COM 2799087SZhong.Wang@Sun.COM if (mp == NULL) { 2809087SZhong.Wang@Sun.COM /* 2819087SZhong.Wang@Sun.COM * We are allocating solicited frame now 2829087SZhong.Wang@Sun.COM */ 2839087SZhong.Wang@Sun.COM raw_frame_size = PADDING_SIZE + fc_frame_size; 2849087SZhong.Wang@Sun.COM mp = fcoe_get_mblk(EPORT2MAC(eport), raw_frame_size); 2859087SZhong.Wang@Sun.COM if (mp == NULL) { 2869087SZhong.Wang@Sun.COM return (NULL); 2879087SZhong.Wang@Sun.COM } 2889087SZhong.Wang@Sun.COM } 2899087SZhong.Wang@Sun.COM 2909087SZhong.Wang@Sun.COM alloc_size = sizeof (fcoe_frame_t) + sizeof (fcoe_i_frame_t) + 2919087SZhong.Wang@Sun.COM EPORT2MAC(eport)->fm_client.ect_private_frame_struct_size; 2929087SZhong.Wang@Sun.COM 2939087SZhong.Wang@Sun.COM /* 2949087SZhong.Wang@Sun.COM * fcoe_frame_t initialization 2959087SZhong.Wang@Sun.COM */ 2969087SZhong.Wang@Sun.COM frm = (fcoe_frame_t *)kmem_alloc(alloc_size, KM_SLEEP); 2979087SZhong.Wang@Sun.COM frm->frm_alloc_size = alloc_size; 2989087SZhong.Wang@Sun.COM frm->frm_fc_frame_size = fc_frame_size; 2999087SZhong.Wang@Sun.COM frm->frm_payload_size = fc_frame_size - 3009087SZhong.Wang@Sun.COM sizeof (fcoe_fc_frame_header_t); 3019087SZhong.Wang@Sun.COM frm->frm_fcoe_private = sizeof (fcoe_frame_t) + (uint8_t *)frm; 3029087SZhong.Wang@Sun.COM frm->frm_client_private = sizeof (fcoe_i_frame_t) + 3039087SZhong.Wang@Sun.COM (uint8_t *)frm->frm_fcoe_private; 3049087SZhong.Wang@Sun.COM frm->frm_flags = 0; 3059087SZhong.Wang@Sun.COM frm->frm_eport = eport; 3069087SZhong.Wang@Sun.COM frm->frm_netb = mp; 3079087SZhong.Wang@Sun.COM 3089087SZhong.Wang@Sun.COM /* 3099087SZhong.Wang@Sun.COM * fcoe_i_frame_t initialization 3109087SZhong.Wang@Sun.COM */ 3119087SZhong.Wang@Sun.COM fmi = FRM2FMI(frm); 3129087SZhong.Wang@Sun.COM fmi->fmi_frame = frm; 3139087SZhong.Wang@Sun.COM fmi->fmi_mac = EPORT2MAC(eport); 3149087SZhong.Wang@Sun.COM fmi->fmi_efh = (void *)mp->b_rptr; 3159087SZhong.Wang@Sun.COM 3169087SZhong.Wang@Sun.COM fmi->fmi_ffh = (fcoe_frame_header_t *) 3179087SZhong.Wang@Sun.COM (sizeof (struct ether_header) + (uint8_t *)fmi->fmi_efh); 3189087SZhong.Wang@Sun.COM 3199087SZhong.Wang@Sun.COM fmi->fmi_fc_frame = sizeof (fcoe_frame_header_t) + 3209087SZhong.Wang@Sun.COM (uint8_t *)fmi->fmi_ffh; 3219087SZhong.Wang@Sun.COM fmi->fmi_fft = (fcoe_frame_tailer_t *) 3229087SZhong.Wang@Sun.COM (fc_frame_size + (uint8_t *)fmi->fmi_fc_frame); 3239087SZhong.Wang@Sun.COM 3249087SZhong.Wang@Sun.COM /* 3259087SZhong.Wang@Sun.COM * Continue to initialize fcoe_frame_t 3269087SZhong.Wang@Sun.COM */ 3279087SZhong.Wang@Sun.COM frm->frm_hdr = (fcoe_fc_frame_header_t *)fmi->fmi_fc_frame; 3289087SZhong.Wang@Sun.COM frm->frm_ofh1 = NULL; 3299087SZhong.Wang@Sun.COM frm->frm_ofh2 = NULL; 3309087SZhong.Wang@Sun.COM frm->frm_fc_frame = (uint8_t *)frm->frm_hdr; 3319087SZhong.Wang@Sun.COM frm->frm_payload = sizeof (fcoe_fc_frame_header_t) + 3329087SZhong.Wang@Sun.COM (uint8_t *)frm->frm_fc_frame; 3339087SZhong.Wang@Sun.COM return (frm); 3349087SZhong.Wang@Sun.COM } 3359087SZhong.Wang@Sun.COM 3369087SZhong.Wang@Sun.COM /* 3379087SZhong.Wang@Sun.COM * Sub routines called by interface functions 3389087SZhong.Wang@Sun.COM */ 3399087SZhong.Wang@Sun.COM 3409087SZhong.Wang@Sun.COM /* 3419087SZhong.Wang@Sun.COM * According to spec, fill EthernetII frame header, FCoE frame header 3429087SZhong.Wang@Sun.COM * VLAN (not included for now) 3439087SZhong.Wang@Sun.COM */ 3449087SZhong.Wang@Sun.COM static void 3459087SZhong.Wang@Sun.COM fcoe_fill_frame_headers(fcoe_frame_t *frm) 3469087SZhong.Wang@Sun.COM { 3479087SZhong.Wang@Sun.COM fcoe_i_frame_t *fmi = FRM2FMI(frm); 3489087SZhong.Wang@Sun.COM 3499087SZhong.Wang@Sun.COM /* 3509087SZhong.Wang@Sun.COM * Initialize ethernet frame header 3519087SZhong.Wang@Sun.COM */ 3529087SZhong.Wang@Sun.COM bcopy(FRM2MAC(frm)->fm_current_addr, &fmi->fmi_efh->ether_shost, 3539087SZhong.Wang@Sun.COM ETHERADDRL); 3549087SZhong.Wang@Sun.COM bcopy(frm->frm_eport->eport_efh_dst, 3559087SZhong.Wang@Sun.COM &fmi->fmi_efh->ether_dhost, ETHERADDRL); 3569087SZhong.Wang@Sun.COM fmi->fmi_efh->ether_type = htons(ETHERTYPE_FCOE); 3579087SZhong.Wang@Sun.COM 3589087SZhong.Wang@Sun.COM /* 3599087SZhong.Wang@Sun.COM * Initialize FCoE frame header 3609087SZhong.Wang@Sun.COM */ 3619087SZhong.Wang@Sun.COM bzero(fmi->fmi_ffh, sizeof (fcoe_frame_header_t)); 3629087SZhong.Wang@Sun.COM FCOE_ENCAPS_VER(fmi->fmi_ffh, FCOE_VER); 3639087SZhong.Wang@Sun.COM /* set to SOFi3 for the first frame of a sequence */ 3649087SZhong.Wang@Sun.COM if (FRM_SEQ_CNT(frm) == 0) { 3659087SZhong.Wang@Sun.COM FCOE_V2B_1(0x2E, fmi->fmi_ffh->ffh_sof); 3669087SZhong.Wang@Sun.COM } else { 3679087SZhong.Wang@Sun.COM FCOE_V2B_1(0x36, fmi->fmi_ffh->ffh_sof); 3689087SZhong.Wang@Sun.COM } 3699087SZhong.Wang@Sun.COM } 3709087SZhong.Wang@Sun.COM 3719087SZhong.Wang@Sun.COM /* 3729087SZhong.Wang@Sun.COM * According to spec, fill FCOE frame tailer including CRC 3739087SZhong.Wang@Sun.COM * VLAN (not included for now) 3749087SZhong.Wang@Sun.COM */ 3759087SZhong.Wang@Sun.COM static void 3769087SZhong.Wang@Sun.COM fcoe_fill_frame_tailers(fcoe_frame_t *frm) 3779087SZhong.Wang@Sun.COM { 3789087SZhong.Wang@Sun.COM uint32_t crc; 3799087SZhong.Wang@Sun.COM 3809087SZhong.Wang@Sun.COM /* 3819087SZhong.Wang@Sun.COM * Initialize FCoE frame tailer 3829087SZhong.Wang@Sun.COM * CRC is not big endian, can't use macro V2B 3839087SZhong.Wang@Sun.COM */ 3849087SZhong.Wang@Sun.COM CRC32(crc, frm->frm_fc_frame, frm->frm_fc_frame_size, 3859087SZhong.Wang@Sun.COM (uint32_t)~0, crc32_table); 3869087SZhong.Wang@Sun.COM FRM2FMI(frm)->fmi_fft->fft_crc[0] = 0xFF & (~crc); 3879087SZhong.Wang@Sun.COM FRM2FMI(frm)->fmi_fft->fft_crc[1] = 0xFF & (~crc >> 8); 3889087SZhong.Wang@Sun.COM FRM2FMI(frm)->fmi_fft->fft_crc[2] = 0xFF & (~crc >> 16); 3899087SZhong.Wang@Sun.COM FRM2FMI(frm)->fmi_fft->fft_crc[3] = 0xFF & (~crc >> 24); 3909087SZhong.Wang@Sun.COM if (FRM_F_CTL(frm) & 0x080000) { 3919087SZhong.Wang@Sun.COM FCOE_V2B_1(0x42, FRM2FMI(frm)->fmi_fft->fft_eof); 3929087SZhong.Wang@Sun.COM } else { 3939087SZhong.Wang@Sun.COM FCOE_V2B_1(0x41, FRM2FMI(frm)->fmi_fft->fft_eof); 3949087SZhong.Wang@Sun.COM } 3959087SZhong.Wang@Sun.COM 3969087SZhong.Wang@Sun.COM FRM2FMI(frm)->fmi_fft->fft_resvd[0] = 0; 3979087SZhong.Wang@Sun.COM FRM2FMI(frm)->fmi_fft->fft_resvd[1] = 0; 3989087SZhong.Wang@Sun.COM FRM2FMI(frm)->fmi_fft->fft_resvd[2] = 0; 3999087SZhong.Wang@Sun.COM } 4009087SZhong.Wang@Sun.COM 4019087SZhong.Wang@Sun.COM void 4029087SZhong.Wang@Sun.COM fcoe_mac_notify_link_up(void *arg) 4039087SZhong.Wang@Sun.COM { 4049087SZhong.Wang@Sun.COM fcoe_mac_t *mac = (fcoe_mac_t *)arg; 4059087SZhong.Wang@Sun.COM 4069087SZhong.Wang@Sun.COM ASSERT(mac->fm_flags & FCOE_MAC_FLAG_BOUND); 4079087SZhong.Wang@Sun.COM 4089087SZhong.Wang@Sun.COM mac->fm_client.ect_port_event(&mac->fm_eport, 4099087SZhong.Wang@Sun.COM FCOE_NOTIFY_EPORT_LINK_UP); 4109087SZhong.Wang@Sun.COM } 4119087SZhong.Wang@Sun.COM void 4129087SZhong.Wang@Sun.COM fcoe_mac_notify_link_down(void *arg) 4139087SZhong.Wang@Sun.COM { 4149087SZhong.Wang@Sun.COM fcoe_mac_t *mac = (fcoe_mac_t *)arg; 4159087SZhong.Wang@Sun.COM 4169087SZhong.Wang@Sun.COM if (mac->fm_flags & FCOE_MAC_FLAG_BOUND) { 4179087SZhong.Wang@Sun.COM mac->fm_client.ect_port_event(&mac->fm_eport, 4189087SZhong.Wang@Sun.COM FCOE_NOTIFY_EPORT_LINK_DOWN); 4199087SZhong.Wang@Sun.COM } 4209087SZhong.Wang@Sun.COM } 4219087SZhong.Wang@Sun.COM 4229087SZhong.Wang@Sun.COM int 4239087SZhong.Wang@Sun.COM fcoe_create_port(dev_info_t *parent, fcoe_mac_t *mac, int is_target) 4249087SZhong.Wang@Sun.COM { 4259087SZhong.Wang@Sun.COM int rval = 0; 4269087SZhong.Wang@Sun.COM dev_info_t *child = NULL; 4279087SZhong.Wang@Sun.COM char *devname = is_target ? FCOET_DRIVER_NAME : FCOEI_DRIVER_NAME; 4289087SZhong.Wang@Sun.COM 4299087SZhong.Wang@Sun.COM ndi_devi_alloc_sleep(parent, devname, DEVI_PSEUDO_NODEID, &child); 4309087SZhong.Wang@Sun.COM if (child == NULL) { 4319087SZhong.Wang@Sun.COM FCOE_LOG("fcoe", "fail to create new devinfo"); 4329087SZhong.Wang@Sun.COM return (NDI_FAILURE); 4339087SZhong.Wang@Sun.COM } 4349087SZhong.Wang@Sun.COM 4359307Skelly.hu@Sun.COM if (ddi_prop_update_int(DDI_DEV_T_NONE, child, 4369307Skelly.hu@Sun.COM "mac_id", mac->fm_linkid) != DDI_PROP_SUCCESS) { 4379087SZhong.Wang@Sun.COM FCOE_LOG("fcoe", 4389307Skelly.hu@Sun.COM "fcoe%d: prop_update port mac id failed for mac %d", 4399307Skelly.hu@Sun.COM ddi_get_instance(parent), mac->fm_linkid); 4409087SZhong.Wang@Sun.COM (void) ndi_devi_free(child); 4419087SZhong.Wang@Sun.COM return (NDI_FAILURE); 4429087SZhong.Wang@Sun.COM } 4439087SZhong.Wang@Sun.COM 4449087SZhong.Wang@Sun.COM rval = ndi_devi_online(child, NDI_ONLINE_ATTACH); 4459087SZhong.Wang@Sun.COM if (rval != NDI_SUCCESS) { 4469307Skelly.hu@Sun.COM FCOE_LOG("fcoe", "fcoe%d: online_driver failed for mac %d", 4479307Skelly.hu@Sun.COM ddi_get_instance(parent), mac->fm_linkid); 4489087SZhong.Wang@Sun.COM return (NDI_FAILURE); 4499087SZhong.Wang@Sun.COM } 4509087SZhong.Wang@Sun.COM mac->fm_client_dev = child; 4519087SZhong.Wang@Sun.COM 4529087SZhong.Wang@Sun.COM return (rval); 4539087SZhong.Wang@Sun.COM } 4549087SZhong.Wang@Sun.COM 4559087SZhong.Wang@Sun.COM int 456*9895SKevin.Yu@Sun.COM fcoe_delete_port(dev_info_t *parent, fcoeio_t *fcoeio, datalink_id_t linkid, 457*9895SKevin.Yu@Sun.COM uint64_t *is_target) 4589087SZhong.Wang@Sun.COM { 4599087SZhong.Wang@Sun.COM int rval = 0; 4609087SZhong.Wang@Sun.COM fcoe_mac_t *mac; 4619087SZhong.Wang@Sun.COM 4629307Skelly.hu@Sun.COM mac = fcoe_lookup_mac_by_id(linkid); 4639087SZhong.Wang@Sun.COM if (mac == NULL) { 4649087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_MAC_NOT_FOUND; 4659087SZhong.Wang@Sun.COM return (EINVAL); 4669087SZhong.Wang@Sun.COM } 4679087SZhong.Wang@Sun.COM 468*9895SKevin.Yu@Sun.COM *is_target = EPORT_CLT_TYPE(&mac->fm_eport); 469*9895SKevin.Yu@Sun.COM 4709087SZhong.Wang@Sun.COM if ((mac->fm_flags & FCOE_MAC_FLAG_ENABLED) != FCOE_MAC_FLAG_ENABLED) { 4719087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_ALREADY; 4729087SZhong.Wang@Sun.COM return (EALREADY); 4739087SZhong.Wang@Sun.COM } 4749087SZhong.Wang@Sun.COM 4759087SZhong.Wang@Sun.COM atomic_and_32(&mac->fm_eport.eport_flags, ~EPORT_FLAG_MAC_IN_USE); 4769087SZhong.Wang@Sun.COM 4779087SZhong.Wang@Sun.COM rval = ndi_devi_offline(mac->fm_client_dev, NDI_DEVI_REMOVE); 4789087SZhong.Wang@Sun.COM if (rval != NDI_SUCCESS) { 4799087SZhong.Wang@Sun.COM FCOE_LOG("fcoe", "fcoe%d: offline_driver %s failed", 4809087SZhong.Wang@Sun.COM ddi_get_instance(parent), 4819087SZhong.Wang@Sun.COM ddi_get_name(mac->fm_client_dev)); 4829087SZhong.Wang@Sun.COM atomic_or_32(&mac->fm_eport.eport_flags, 4839087SZhong.Wang@Sun.COM EPORT_FLAG_MAC_IN_USE); 4849087SZhong.Wang@Sun.COM 4859087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_OFFLINE_FAILURE; 4869087SZhong.Wang@Sun.COM return (EBUSY); 4879087SZhong.Wang@Sun.COM } 4889087SZhong.Wang@Sun.COM (void) fcoe_close_mac(mac); 4899087SZhong.Wang@Sun.COM fcoe_destroy_mac(mac); 4909087SZhong.Wang@Sun.COM return (0); 4919087SZhong.Wang@Sun.COM } 492