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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 232a8164dfSZhong Wang * Use is subject to license terms. 242a8164dfSZhong Wang */ 252a8164dfSZhong Wang 262a8164dfSZhong Wang #include <sys/stat.h> 272a8164dfSZhong Wang #include <sys/types.h> 282a8164dfSZhong Wang #include <netinet/in.h> 292a8164dfSZhong Wang #include <sys/inttypes.h> 302a8164dfSZhong Wang #include <sys/strsun.h> 312a8164dfSZhong Wang #include <sys/mac_client.h> 322a8164dfSZhong Wang 332a8164dfSZhong Wang /* 342a8164dfSZhong Wang * FCoE header files 352a8164dfSZhong Wang */ 362a8164dfSZhong Wang #include <sys/fcoe/fcoeio.h> 372a8164dfSZhong Wang #include <sys/fcoe/fcoe_common.h> 382a8164dfSZhong Wang 392a8164dfSZhong Wang /* 402a8164dfSZhong Wang * Driver's own header files 412a8164dfSZhong Wang */ 422a8164dfSZhong Wang #include <fcoe.h> 432a8164dfSZhong Wang #include <fcoe_eth.h> 442a8164dfSZhong Wang #include <fcoe_fc.h> 452a8164dfSZhong Wang 462a8164dfSZhong Wang static void fcoe_rx(void *arg, mac_resource_handle_t mrh, 472a8164dfSZhong Wang mblk_t *mp, boolean_t loopback); 482a8164dfSZhong Wang static void fcoe_mac_notify(void *arg, mac_notify_type_t type); 492a8164dfSZhong Wang 502a8164dfSZhong Wang /* 512a8164dfSZhong Wang * Global variable definitions 522a8164dfSZhong Wang */ 532a8164dfSZhong Wang 542a8164dfSZhong Wang /* 552a8164dfSZhong Wang * Internal tunable, used to enable p2p mode 562a8164dfSZhong Wang */ 572a8164dfSZhong Wang volatile uint32_t fcoe_enable_p2pmode = 0; 582a8164dfSZhong Wang 592a8164dfSZhong Wang int 602a8164dfSZhong Wang fcoe_open_mac(fcoe_mac_t *mac, int force_promisc, fcoeio_stat_t *err_detail) 612a8164dfSZhong Wang { 622a8164dfSZhong Wang int ret; 632a8164dfSZhong Wang int fcoe_ret; 642a8164dfSZhong Wang char cli_name[MAXNAMELEN]; 652a8164dfSZhong Wang mac_diag_t diag; 662a8164dfSZhong Wang uint16_t fm_open_flag = 0; 672a8164dfSZhong Wang 682a8164dfSZhong Wang *err_detail = 0; 692a8164dfSZhong Wang 702a8164dfSZhong Wang /* 712a8164dfSZhong Wang * Open MAC interface 722a8164dfSZhong Wang */ 73d4401b99SKelly Hu ret = mac_open_by_linkid(mac->fm_linkid, &mac->fm_handle); 742a8164dfSZhong Wang if (ret != 0) { 75d4401b99SKelly Hu FCOE_LOG("fcoe", "mac_open_by_linkname %d failed %x", 76d4401b99SKelly Hu mac->fm_linkid, ret); 772a8164dfSZhong Wang return (FCOE_FAILURE); 782a8164dfSZhong Wang } 792a8164dfSZhong Wang 80d4401b99SKelly Hu (void) sprintf(cli_name, "%s-%d", "fcoe", mac->fm_linkid); 812a8164dfSZhong Wang 822a8164dfSZhong Wang ret = mac_client_open(mac->fm_handle, 832a8164dfSZhong Wang &mac->fm_cli_handle, cli_name, fm_open_flag); 842a8164dfSZhong Wang if (ret != 0) { 852a8164dfSZhong Wang (void) fcoe_close_mac(mac); 862a8164dfSZhong Wang return (FCOE_FAILURE); 872a8164dfSZhong Wang } 882a8164dfSZhong Wang /* 892a8164dfSZhong Wang * Cache the pointer of the immutable MAC inforamtion and 902a8164dfSZhong Wang * the current and primary MAC address 912a8164dfSZhong Wang */ 922a8164dfSZhong Wang mac_unicast_primary_get(mac->fm_handle, mac->fm_primary_addr); 932a8164dfSZhong Wang bcopy(mac->fm_primary_addr, mac->fm_current_addr, 942a8164dfSZhong Wang ETHERADDRL); 952a8164dfSZhong Wang 962a8164dfSZhong Wang if (mac_unicast_add(mac->fm_cli_handle, NULL, MAC_UNICAST_PRIMARY, 972a8164dfSZhong Wang &mac->fm_unicst_handle, 0, &diag)) { 982a8164dfSZhong Wang (void) fcoe_close_mac(mac); 992a8164dfSZhong Wang return (FCOE_FAILURE); 1002a8164dfSZhong Wang } 1012a8164dfSZhong Wang 1022a8164dfSZhong Wang if (force_promisc) { 1032a8164dfSZhong Wang mac->fm_force_promisc = B_TRUE; 1042a8164dfSZhong Wang } 1052a8164dfSZhong Wang 1062a8164dfSZhong Wang /* Get mtu */ 1072a8164dfSZhong Wang mac_sdu_get(mac->fm_handle, NULL, &mac->fm_eport.eport_mtu); 1082a8164dfSZhong Wang if (mac->fm_eport.eport_mtu < FCOE_MIN_MTU_SIZE) { 1092a8164dfSZhong Wang if (!fcoe_enable_p2pmode || mac->fm_eport.eport_mtu < 1500) { 1102a8164dfSZhong Wang /* 1112a8164dfSZhong Wang * Fail open if fail to get mtu, or we are not 1122a8164dfSZhong Wang * using p2p, or we are using p2p, but 1132a8164dfSZhong Wang * the mtu is too small 1142a8164dfSZhong Wang */ 1152a8164dfSZhong Wang (void) fcoe_close_mac(mac); 1162a8164dfSZhong Wang *err_detail = FCOEIOE_NEED_JUMBO_FRAME; 1172a8164dfSZhong Wang return (FCOE_FAILURE); 1182a8164dfSZhong Wang } 1192a8164dfSZhong Wang } 1202a8164dfSZhong Wang 1212a8164dfSZhong Wang mac->fm_eport.eport_link_speed = 1222a8164dfSZhong Wang mac_client_stat_get(mac->fm_cli_handle, MAC_STAT_IFSPEED); 1232a8164dfSZhong Wang 1242a8164dfSZhong Wang cv_init(&mac->fm_tx_cv, NULL, CV_DRIVER, NULL); 1252a8164dfSZhong Wang mutex_init(&mac->fm_mutex, NULL, MUTEX_DRIVER, NULL); 1262a8164dfSZhong Wang mac->fm_running = B_TRUE; 1272a8164dfSZhong Wang 1282a8164dfSZhong Wang fcoe_ret = FCOE_SUCCESS; 1292a8164dfSZhong Wang return (fcoe_ret); 1302a8164dfSZhong Wang } 1312a8164dfSZhong Wang 1322a8164dfSZhong Wang int 1332a8164dfSZhong Wang fcoe_close_mac(fcoe_mac_t *mac) 1342a8164dfSZhong Wang { 1352a8164dfSZhong Wang int ret; 1362a8164dfSZhong Wang 1372a8164dfSZhong Wang if (mac->fm_handle == NULL) { 1382a8164dfSZhong Wang return (FCOE_SUCCESS); 1392a8164dfSZhong Wang } 1402a8164dfSZhong Wang 1412a8164dfSZhong Wang if (mac->fm_running) { 1422a8164dfSZhong Wang cv_destroy(&mac->fm_tx_cv); 1432a8164dfSZhong Wang mutex_destroy(&mac->fm_mutex); 1442a8164dfSZhong Wang mac->fm_running = B_FALSE; 1452a8164dfSZhong Wang } 1462a8164dfSZhong Wang 1472a8164dfSZhong Wang if (mac->fm_promisc_handle != NULL) { 1482a8164dfSZhong Wang mac_promisc_remove(mac->fm_promisc_handle); 1492a8164dfSZhong Wang mac->fm_promisc_handle = NULL; 1502a8164dfSZhong Wang } else { 1512a8164dfSZhong Wang mac_rx_clear(mac->fm_cli_handle); 1522a8164dfSZhong Wang } 1532a8164dfSZhong Wang 1542a8164dfSZhong Wang if (mac->fm_notify_handle != NULL) { 1552a8164dfSZhong Wang ret = mac_notify_remove(mac->fm_notify_handle, B_TRUE); 1562a8164dfSZhong Wang ASSERT(ret == 0); 1572a8164dfSZhong Wang mac->fm_notify_handle = NULL; 1582a8164dfSZhong Wang } 1592a8164dfSZhong Wang 1602a8164dfSZhong Wang if (mac->fm_unicst_handle != NULL) { 1612a8164dfSZhong Wang (void) mac_unicast_remove(mac->fm_cli_handle, 1622a8164dfSZhong Wang mac->fm_unicst_handle); 1632a8164dfSZhong Wang mac->fm_unicst_handle = NULL; 1642a8164dfSZhong Wang } 1652a8164dfSZhong Wang 1662a8164dfSZhong Wang mac_client_close(mac->fm_cli_handle, 0); 1672a8164dfSZhong Wang mac->fm_cli_handle = NULL; 1682a8164dfSZhong Wang 1692a8164dfSZhong Wang (void) mac_close(mac->fm_handle); 1702a8164dfSZhong Wang mac->fm_handle = NULL; 1712a8164dfSZhong Wang 1722a8164dfSZhong Wang return (FCOE_SUCCESS); 1732a8164dfSZhong Wang } 1742a8164dfSZhong Wang 1752a8164dfSZhong Wang int 1762a8164dfSZhong Wang fcoe_enable_callback(fcoe_mac_t *mac) 1772a8164dfSZhong Wang { 1782a8164dfSZhong Wang int ret; 1792a8164dfSZhong Wang 1802a8164dfSZhong Wang /* 1812a8164dfSZhong Wang * Set message callback 1822a8164dfSZhong Wang */ 1832a8164dfSZhong Wang if (mac->fm_force_promisc) { 1842a8164dfSZhong Wang ret = mac_promisc_add(mac->fm_cli_handle, 1852a8164dfSZhong Wang MAC_CLIENT_PROMISC_FILTERED, fcoe_rx, mac, 1862a8164dfSZhong Wang &mac->fm_promisc_handle, 1872a8164dfSZhong Wang MAC_PROMISC_FLAGS_NO_TX_LOOP); 1882a8164dfSZhong Wang if (ret != 0) { 189d4401b99SKelly Hu FCOE_LOG("foce", "mac_promisc_add on %d failed %x", 190d4401b99SKelly Hu mac->fm_linkid, ret); 1912a8164dfSZhong Wang return (FCOE_FAILURE); 1922a8164dfSZhong Wang } 1932a8164dfSZhong Wang } else { 1942a8164dfSZhong Wang mac_rx_set(mac->fm_cli_handle, fcoe_rx, mac); 1952a8164dfSZhong Wang } 1962a8164dfSZhong Wang 1972a8164dfSZhong Wang /* Get the link state, if it's up, we will need to notify client */ 1982a8164dfSZhong Wang mac->fm_link_state = 1992a8164dfSZhong Wang mac_stat_get(mac->fm_handle, MAC_STAT_LINK_UP)? 2002a8164dfSZhong Wang FCOE_MAC_LINK_STATE_UP:FCOE_MAC_LINK_STATE_DOWN; 2012a8164dfSZhong Wang 202*7ff83669SZhong Wang mac->fm_eport.eport_link_speed = 203*7ff83669SZhong Wang mac_client_stat_get(mac->fm_cli_handle, MAC_STAT_IFSPEED); 204*7ff83669SZhong Wang 2052a8164dfSZhong Wang /* 2062a8164dfSZhong Wang * Add a notify function so that we get updates from MAC 2072a8164dfSZhong Wang */ 2082a8164dfSZhong Wang mac->fm_notify_handle = mac_notify_add(mac->fm_handle, 2092a8164dfSZhong Wang fcoe_mac_notify, (void *)mac); 2102a8164dfSZhong Wang return (FCOE_SUCCESS); 2112a8164dfSZhong Wang } 2122a8164dfSZhong Wang 2132a8164dfSZhong Wang int 2142a8164dfSZhong Wang fcoe_disable_callback(fcoe_mac_t *mac) 2152a8164dfSZhong Wang { 2162a8164dfSZhong Wang int ret; 2172a8164dfSZhong Wang 2182a8164dfSZhong Wang if (mac->fm_promisc_handle) { 2192a8164dfSZhong Wang mac_promisc_remove(mac->fm_promisc_handle); 2202a8164dfSZhong Wang mac->fm_promisc_handle = NULL; 2212a8164dfSZhong Wang } else { 2222a8164dfSZhong Wang mac_rx_clear(mac->fm_cli_handle); 2232a8164dfSZhong Wang } 2242a8164dfSZhong Wang 2252a8164dfSZhong Wang if (mac->fm_notify_handle) { 2262a8164dfSZhong Wang ret = mac_notify_remove(mac->fm_notify_handle, B_TRUE); 2272a8164dfSZhong Wang ASSERT(ret == 0); 2282a8164dfSZhong Wang mac->fm_notify_handle = NULL; 2292a8164dfSZhong Wang } 2302a8164dfSZhong Wang 2312a8164dfSZhong Wang ret = fcoe_mac_set_address(&mac->fm_eport, 2322a8164dfSZhong Wang mac->fm_primary_addr, B_FALSE); 2332a8164dfSZhong Wang FCOE_SET_DEFAULT_FPORT_ADDR(mac->fm_eport.eport_efh_dst); 2342a8164dfSZhong Wang return (ret); 2352a8164dfSZhong Wang } 2362a8164dfSZhong Wang 2372a8164dfSZhong Wang /* ARGSUSED */ 2382a8164dfSZhong Wang static void 2392a8164dfSZhong Wang fcoe_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp, boolean_t loopback) 2402a8164dfSZhong Wang { 2412a8164dfSZhong Wang fcoe_mac_t *mac = (fcoe_mac_t *)arg; 2422a8164dfSZhong Wang mblk_t *next; 2432a8164dfSZhong Wang fcoe_frame_t *frm; 2442a8164dfSZhong Wang uint32_t raw_frame_size, frame_size; 2452a8164dfSZhong Wang uint16_t frm_type; 2462a8164dfSZhong Wang 2472a8164dfSZhong Wang while (mp != NULL) { 2482a8164dfSZhong Wang next = mp->b_next; 2492a8164dfSZhong Wang mp->b_next = NULL; 2502a8164dfSZhong Wang frm_type = ntohs(*(uint16_t *)((uintptr_t)mp->b_rptr + 12)); 2512a8164dfSZhong Wang 2522a8164dfSZhong Wang if (frm_type != ETHERTYPE_FCOE) { 2532a8164dfSZhong Wang /* 2542a8164dfSZhong Wang * This mp is not allocated in FCoE, but we must free it 2552a8164dfSZhong Wang */ 2562a8164dfSZhong Wang freeb(mp); 2572a8164dfSZhong Wang mp = next; 2582a8164dfSZhong Wang continue; 2592a8164dfSZhong Wang } 2602a8164dfSZhong Wang 2612a8164dfSZhong Wang raw_frame_size = MBLKL(mp); 2622a8164dfSZhong Wang frame_size = raw_frame_size - PADDING_SIZE; 2632a8164dfSZhong Wang frm = fcoe_allocate_frame(&mac->fm_eport, frame_size, mp); 2642a8164dfSZhong Wang if (frm != NULL) { 265*7ff83669SZhong Wang frm->frm_clock = CURRENT_CLOCK; 2662a8164dfSZhong Wang fcoe_post_frame(frm); 2672a8164dfSZhong Wang } 2682a8164dfSZhong Wang 2692a8164dfSZhong Wang mp = next; 2702a8164dfSZhong Wang } 2712a8164dfSZhong Wang } 2722a8164dfSZhong Wang 2732a8164dfSZhong Wang static void 2742a8164dfSZhong Wang fcoe_mac_notify(void *arg, mac_notify_type_t type) 2752a8164dfSZhong Wang { 2762a8164dfSZhong Wang fcoe_mac_t *mac = (fcoe_mac_t *)arg; 2772a8164dfSZhong Wang 2782a8164dfSZhong Wang /* 2792a8164dfSZhong Wang * We assume that the calls to this notification callback are serialized 2802a8164dfSZhong Wang * by MAC layer 2812a8164dfSZhong Wang */ 2822a8164dfSZhong Wang 2832a8164dfSZhong Wang switch (type) { 2842a8164dfSZhong Wang case MAC_NOTE_LINK: 2852a8164dfSZhong Wang /* 2862a8164dfSZhong Wang * This notification is sent every time the MAC driver 2872a8164dfSZhong Wang * updates the link state. 2882a8164dfSZhong Wang */ 2892a8164dfSZhong Wang if (mac_stat_get(mac->fm_handle, MAC_STAT_LINK_UP) != 0) { 2902a8164dfSZhong Wang if (mac->fm_link_state == FCOE_MAC_LINK_STATE_UP) { 2912a8164dfSZhong Wang break; 2922a8164dfSZhong Wang } 2932a8164dfSZhong Wang /* Get speed */ 2942a8164dfSZhong Wang mac->fm_eport.eport_link_speed = 2952a8164dfSZhong Wang mac_client_stat_get(mac->fm_cli_handle, 2962a8164dfSZhong Wang MAC_STAT_IFSPEED); 2972a8164dfSZhong Wang (void) fcoe_mac_set_address(&mac->fm_eport, 2982a8164dfSZhong Wang mac->fm_primary_addr, B_FALSE); 2992a8164dfSZhong Wang 3002a8164dfSZhong Wang FCOE_SET_DEFAULT_FPORT_ADDR( 3012a8164dfSZhong Wang mac->fm_eport.eport_efh_dst); 3022a8164dfSZhong Wang 3032a8164dfSZhong Wang mac->fm_link_state = FCOE_MAC_LINK_STATE_UP; 304d4401b99SKelly Hu FCOE_LOG(NULL, 305d4401b99SKelly Hu "fcoe_mac_notify: link/%d arg/%p LINK up", 306d4401b99SKelly Hu mac->fm_linkid, arg, type); 3072a8164dfSZhong Wang fcoe_mac_notify_link_up(mac); 3082a8164dfSZhong Wang } else { 3092a8164dfSZhong Wang if (mac->fm_link_state == FCOE_MAC_LINK_STATE_DOWN) { 3102a8164dfSZhong Wang break; 3112a8164dfSZhong Wang } 3122a8164dfSZhong Wang mac->fm_link_state = FCOE_MAC_LINK_STATE_DOWN; 313d4401b99SKelly Hu FCOE_LOG(NULL, 314d4401b99SKelly Hu "fcoe_mac_notify: link/%d arg/%p LINK down", 315d4401b99SKelly Hu mac->fm_linkid, arg, type); 3162a8164dfSZhong Wang fcoe_mac_notify_link_down(mac); 3172a8164dfSZhong Wang } 3182a8164dfSZhong Wang break; 3192a8164dfSZhong Wang 3202a8164dfSZhong Wang case MAC_NOTE_TX: 3212a8164dfSZhong Wang /* 3222a8164dfSZhong Wang * MAC is not so busy now, then wake up fcoe_tx_frame to try 3232a8164dfSZhong Wang */ 3242a8164dfSZhong Wang mutex_enter(&mac->fm_mutex); 3252a8164dfSZhong Wang cv_broadcast(&mac->fm_tx_cv); 3262a8164dfSZhong Wang mutex_exit(&mac->fm_mutex); 3272a8164dfSZhong Wang 3282a8164dfSZhong Wang FCOE_LOG("fcoe_mac_notify", "wake up"); 3292a8164dfSZhong Wang break; 3302a8164dfSZhong Wang 3312a8164dfSZhong Wang default: 3322a8164dfSZhong Wang FCOE_LOG("fcoe_mac_notify", "not supported arg/%p, type/%d", 3332a8164dfSZhong Wang arg, type); 3342a8164dfSZhong Wang break; 3352a8164dfSZhong Wang } 3362a8164dfSZhong Wang } 3372a8164dfSZhong Wang 3382a8164dfSZhong Wang int 3392a8164dfSZhong Wang fcoe_mac_set_address(fcoe_port_t *eport, uint8_t *addr, boolean_t fc_assigned) 3402a8164dfSZhong Wang { 3412a8164dfSZhong Wang fcoe_mac_t *mac = EPORT2MAC(eport); 3422a8164dfSZhong Wang int ret; 3432a8164dfSZhong Wang 3442a8164dfSZhong Wang if (bcmp(addr, mac->fm_current_addr, 6) == 0) { 3452a8164dfSZhong Wang return (FCOE_SUCCESS); 3462a8164dfSZhong Wang } 3472a8164dfSZhong Wang 3482a8164dfSZhong Wang mutex_enter(&mac->fm_mutex); 3492a8164dfSZhong Wang if (mac->fm_promisc_handle == NULL) { 3502a8164dfSZhong Wang ret = mac_unicast_primary_set(mac->fm_handle, addr); 3512a8164dfSZhong Wang if (ret != 0) { 3522a8164dfSZhong Wang mutex_exit(&mac->fm_mutex); 353d4401b99SKelly Hu FCOE_LOG("fcoe", "mac_unicast_primary_set on %d " 354d4401b99SKelly Hu "failed %x", mac->fm_linkid, ret); 3552a8164dfSZhong Wang return (FCOE_FAILURE); 3562a8164dfSZhong Wang } 3572a8164dfSZhong Wang } 3582a8164dfSZhong Wang if (fc_assigned) { 3592a8164dfSZhong Wang bcopy(addr, mac->fm_current_addr, ETHERADDRL); 3602a8164dfSZhong Wang } else { 3612a8164dfSZhong Wang bcopy(mac->fm_primary_addr, 3622a8164dfSZhong Wang mac->fm_current_addr, ETHERADDRL); 3632a8164dfSZhong Wang } 3642a8164dfSZhong Wang mutex_exit(&mac->fm_mutex); 3652a8164dfSZhong Wang return (FCOE_SUCCESS); 3662a8164dfSZhong Wang } 367