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 */ 25cd21e7c5SGarrett D'Amore /* 26cd21e7c5SGarrett D'Amore * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 27cd21e7c5SGarrett D'Amore */ 282a8164dfSZhong Wang 292a8164dfSZhong Wang /* 302a8164dfSZhong Wang * The following notice accompanied the original version of this file: 312a8164dfSZhong Wang * 322a8164dfSZhong Wang * BSD LICENSE 332a8164dfSZhong Wang * 342a8164dfSZhong Wang * Copyright(c) 2007 Intel Corporation. All rights reserved. 352a8164dfSZhong Wang * All rights reserved. 362a8164dfSZhong Wang * 372a8164dfSZhong Wang * Redistribution and use in source and binary forms, with or without 382a8164dfSZhong Wang * modification, are permitted provided that the following conditions 392a8164dfSZhong Wang * are met: 402a8164dfSZhong Wang * 412a8164dfSZhong Wang * * Redistributions of source code must retain the above copyright 422a8164dfSZhong Wang * notice, this list of conditions and the following disclaimer. 432a8164dfSZhong Wang * * Redistributions in binary form must reproduce the above copyright 442a8164dfSZhong Wang * notice, this list of conditions and the following disclaimer in 452a8164dfSZhong Wang * the documentation and/or other materials provided with the 462a8164dfSZhong Wang * distribution. 472a8164dfSZhong Wang * * Neither the name of Intel Corporation nor the names of its 482a8164dfSZhong Wang * contributors may be used to endorse or promote products derived 492a8164dfSZhong Wang * from this software without specific prior written permission. 502a8164dfSZhong Wang * 512a8164dfSZhong Wang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 522a8164dfSZhong Wang * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 532a8164dfSZhong Wang * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 542a8164dfSZhong Wang * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 552a8164dfSZhong Wang * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 562a8164dfSZhong Wang * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 572a8164dfSZhong Wang * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 582a8164dfSZhong Wang * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 592a8164dfSZhong Wang * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 602a8164dfSZhong Wang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 612a8164dfSZhong Wang * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 622a8164dfSZhong Wang */ 632a8164dfSZhong Wang 642a8164dfSZhong Wang /* 652a8164dfSZhong Wang * Common FCoE interface interacts with MAC and FCoE clients, managing 662a8164dfSZhong Wang * FCoE ports, doing MAC address discovery/managment, and FC frame 672a8164dfSZhong Wang * encapsulation/decapsulation 682a8164dfSZhong Wang */ 692a8164dfSZhong Wang 702a8164dfSZhong Wang #include <sys/stat.h> 712a8164dfSZhong Wang #include <sys/conf.h> 722a8164dfSZhong Wang #include <sys/file.h> 732a8164dfSZhong Wang #include <sys/cred.h> 742a8164dfSZhong Wang 752a8164dfSZhong Wang #include <sys/ddi.h> 762a8164dfSZhong Wang #include <sys/sunddi.h> 772a8164dfSZhong Wang #include <sys/sunndi.h> 782a8164dfSZhong Wang #include <sys/byteorder.h> 792a8164dfSZhong Wang #include <sys/atomic.h> 802a8164dfSZhong Wang #include <sys/sysmacros.h> 812a8164dfSZhong Wang #include <sys/cmn_err.h> 822a8164dfSZhong Wang #include <sys/crc32.h> 832a8164dfSZhong Wang #include <sys/strsubr.h> 842a8164dfSZhong Wang 852a8164dfSZhong Wang #include <sys/mac_client.h> 862a8164dfSZhong Wang 872a8164dfSZhong Wang /* 882a8164dfSZhong Wang * FCoE header files 892a8164dfSZhong Wang */ 902a8164dfSZhong Wang #include <sys/fcoe/fcoeio.h> 912a8164dfSZhong Wang #include <sys/fcoe/fcoe_common.h> 922a8164dfSZhong Wang 932a8164dfSZhong Wang /* 942a8164dfSZhong Wang * Driver's own header files 952a8164dfSZhong Wang */ 962a8164dfSZhong Wang #include <fcoe.h> 972a8164dfSZhong Wang #include <fcoe_fc.h> 982a8164dfSZhong Wang #include <fcoe_eth.h> 992a8164dfSZhong Wang 1002a8164dfSZhong Wang /* 1012a8164dfSZhong Wang * Function forward declaration 1022a8164dfSZhong Wang */ 1032a8164dfSZhong Wang static int fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 1042a8164dfSZhong Wang static int fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 1052a8164dfSZhong Wang static int fcoe_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip, 1062a8164dfSZhong Wang ddi_ctl_enum_t op, void *arg, void *result); 1072a8164dfSZhong Wang static int fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp); 1082a8164dfSZhong Wang static int fcoe_close(dev_t dev, int flag, int otype, cred_t *credp); 1092a8164dfSZhong Wang static int fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 1102a8164dfSZhong Wang cred_t *credp, int *rval); 1112a8164dfSZhong Wang static int fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio, 1122a8164dfSZhong Wang void **ibuf, void **abuf, void **obuf); 1132a8164dfSZhong Wang static int fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio, 1142a8164dfSZhong Wang void *obuf); 1152a8164dfSZhong Wang static int fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode); 1162a8164dfSZhong Wang static int fcoe_attach_init(fcoe_soft_state_t *this_ss); 1172a8164dfSZhong Wang static int fcoe_detach_uninit(fcoe_soft_state_t *this_ss); 1182a8164dfSZhong Wang static int fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip); 1192a8164dfSZhong Wang static int fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip); 1202a8164dfSZhong Wang static void fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac, 1212a8164dfSZhong Wang int is_pwwn, uint8_t idx); 122d4401b99SKelly Hu static fcoe_mac_t *fcoe_create_mac_by_id(datalink_id_t linkid); 1232a8164dfSZhong Wang static int fcoe_cmp_wwn(fcoe_mac_t *checkedmac); 1242a8164dfSZhong Wang static void fcoe_watchdog(void *arg); 1252a8164dfSZhong Wang static void fcoe_worker_init(); 1262a8164dfSZhong Wang static int fcoe_worker_fini(); 1272a8164dfSZhong Wang static void fcoe_worker_frame(); 1282a8164dfSZhong Wang static int fcoe_get_port_list(fcoe_port_instance_t *ports, int count); 12987dcbdbdSKevin Yu static boolean_t fcoe_mac_existed(fcoe_mac_t *pmac); 1302a8164dfSZhong Wang 1312a8164dfSZhong Wang /* 1322a8164dfSZhong Wang * Driver identificaton stuff 1332a8164dfSZhong Wang */ 1342a8164dfSZhong Wang static struct cb_ops fcoe_cb_ops = { 1352a8164dfSZhong Wang fcoe_open, 1362a8164dfSZhong Wang fcoe_close, 1372a8164dfSZhong Wang nodev, 1382a8164dfSZhong Wang nodev, 1392a8164dfSZhong Wang nodev, 1402a8164dfSZhong Wang nodev, 1412a8164dfSZhong Wang nodev, 1422a8164dfSZhong Wang fcoe_ioctl, 1432a8164dfSZhong Wang nodev, 1442a8164dfSZhong Wang nodev, 1452a8164dfSZhong Wang nodev, 1462a8164dfSZhong Wang nochpoll, 1472a8164dfSZhong Wang ddi_prop_op, 1482a8164dfSZhong Wang 0, 1492a8164dfSZhong Wang D_MP | D_NEW | D_HOTPLUG, 1502a8164dfSZhong Wang CB_REV, 1512a8164dfSZhong Wang nodev, 1522a8164dfSZhong Wang nodev 1532a8164dfSZhong Wang }; 1542a8164dfSZhong Wang 1552a8164dfSZhong Wang static struct bus_ops fcoe_busops = { 1562a8164dfSZhong Wang BUSO_REV, 1572a8164dfSZhong Wang nullbusmap, /* bus_map */ 1582a8164dfSZhong Wang NULL, /* bus_get_intrspec */ 1592a8164dfSZhong Wang NULL, /* bus_add_intrspec */ 1602a8164dfSZhong Wang NULL, /* bus_remove_intrspec */ 1612a8164dfSZhong Wang i_ddi_map_fault, /* bus_map_fault */ 162cd21e7c5SGarrett D'Amore NULL, /* bus_dma_map */ 1632a8164dfSZhong Wang ddi_dma_allochdl, /* bus_dma_allochdl */ 1642a8164dfSZhong Wang ddi_dma_freehdl, /* bus_dma_freehdl */ 1652a8164dfSZhong Wang ddi_dma_bindhdl, /* bus_dma_bindhdl */ 1662a8164dfSZhong Wang ddi_dma_unbindhdl, /* bus_unbindhdl */ 1672a8164dfSZhong Wang ddi_dma_flush, /* bus_dma_flush */ 1682a8164dfSZhong Wang ddi_dma_win, /* bus_dma_win */ 1692a8164dfSZhong Wang ddi_dma_mctl, /* bus_dma_ctl */ 1702a8164dfSZhong Wang fcoe_bus_ctl, /* bus_ctl */ 1712a8164dfSZhong Wang ddi_bus_prop_op, /* bus_prop_op */ 1722a8164dfSZhong Wang NULL, /* bus_get_eventcookie */ 1732a8164dfSZhong Wang NULL, /* bus_add_eventcall */ 1742a8164dfSZhong Wang NULL, /* bus_remove_event */ 1752a8164dfSZhong Wang NULL, /* bus_post_event */ 1762a8164dfSZhong Wang NULL, /* bus_intr_ctl */ 1772a8164dfSZhong Wang NULL, /* bus_config */ 1782a8164dfSZhong Wang NULL, /* bus_unconfig */ 1792a8164dfSZhong Wang NULL, /* bus_fm_init */ 1802a8164dfSZhong Wang NULL, /* bus_fm_fini */ 1812a8164dfSZhong Wang NULL, /* bus_fm_access_enter */ 1822a8164dfSZhong Wang NULL, /* bus_fm_access_exit */ 1832a8164dfSZhong Wang NULL, /* bus_power */ 1842a8164dfSZhong Wang NULL 1852a8164dfSZhong Wang }; 1862a8164dfSZhong Wang 1872a8164dfSZhong Wang static struct dev_ops fcoe_ops = { 1882a8164dfSZhong Wang DEVO_REV, 1892a8164dfSZhong Wang 0, 1902a8164dfSZhong Wang nodev, 1912a8164dfSZhong Wang nulldev, 1922a8164dfSZhong Wang nulldev, 1932a8164dfSZhong Wang fcoe_attach, 1942a8164dfSZhong Wang fcoe_detach, 1952a8164dfSZhong Wang nodev, 1962a8164dfSZhong Wang &fcoe_cb_ops, 1972a8164dfSZhong Wang &fcoe_busops, 1983b753e05SZhong Wang ddi_power, 1993b753e05SZhong Wang ddi_quiesce_not_needed 2002a8164dfSZhong Wang }; 2012a8164dfSZhong Wang 20287dcbdbdSKevin Yu #define FCOE_VERSION "20091123-1.02" 2032a8164dfSZhong Wang #define FCOE_NAME "FCoE Transport v" FCOE_VERSION 2042a8164dfSZhong Wang #define TASKQ_NAME_LEN 32 2052a8164dfSZhong Wang 2062a8164dfSZhong Wang static struct modldrv modldrv = { 2072a8164dfSZhong Wang &mod_driverops, 2082a8164dfSZhong Wang FCOE_NAME, 2092a8164dfSZhong Wang &fcoe_ops, 2102a8164dfSZhong Wang }; 2112a8164dfSZhong Wang 2122a8164dfSZhong Wang static struct modlinkage modlinkage = { 2132a8164dfSZhong Wang MODREV_1, &modldrv, NULL 2142a8164dfSZhong Wang }; 2152a8164dfSZhong Wang 2162a8164dfSZhong Wang /* 2172a8164dfSZhong Wang * TRACE for all FCoE related modules 2182a8164dfSZhong Wang */ 2192a8164dfSZhong Wang static kmutex_t fcoe_trace_buf_lock; 2202a8164dfSZhong Wang static int fcoe_trace_buf_curndx = 0; 2212a8164dfSZhong Wang static int fcoe_trace_on = 1; 2222a8164dfSZhong Wang static caddr_t fcoe_trace_buf = NULL; 2232a8164dfSZhong Wang static clock_t fcoe_trace_start = 0; 2242a8164dfSZhong Wang static caddr_t ftb = NULL; 2252a8164dfSZhong Wang static int fcoe_trace_buf_size = (1 * 1024 * 1024); 2262a8164dfSZhong Wang 2272a8164dfSZhong Wang /* 2282a8164dfSZhong Wang * Driver's global variables 2292a8164dfSZhong Wang */ 2307ff83669SZhong Wang const fcoe_ver_e fcoe_ver_now = FCOE_VER_NOW; 2312a8164dfSZhong Wang static void *fcoe_state = NULL; 2322a8164dfSZhong Wang fcoe_soft_state_t *fcoe_global_ss = NULL; 2332a8164dfSZhong Wang int fcoe_use_ext_log = 1; 2342a8164dfSZhong Wang 2352a8164dfSZhong Wang static ddi_taskq_t *fcoe_worker_taskq; 2362a8164dfSZhong Wang static fcoe_worker_t *fcoe_workers; 2372a8164dfSZhong Wang static uint32_t fcoe_nworkers_running; 2382a8164dfSZhong Wang 2392a8164dfSZhong Wang const char *fcoe_workers_num = "workers-number"; 2402a8164dfSZhong Wang volatile int fcoe_nworkers; 2412a8164dfSZhong Wang 2422a8164dfSZhong Wang /* 2432a8164dfSZhong Wang * Common loadable module entry points _init, _fini, _info 2442a8164dfSZhong Wang */ 2452a8164dfSZhong Wang 2462a8164dfSZhong Wang int 2472a8164dfSZhong Wang _init(void) 2482a8164dfSZhong Wang { 2492a8164dfSZhong Wang int ret; 2502a8164dfSZhong Wang 2512a8164dfSZhong Wang ret = ddi_soft_state_init(&fcoe_state, sizeof (fcoe_soft_state_t), 0); 2522a8164dfSZhong Wang if (ret == 0) { 2532a8164dfSZhong Wang ret = mod_install(&modlinkage); 2542a8164dfSZhong Wang if (ret != 0) { 2552a8164dfSZhong Wang ddi_soft_state_fini(&fcoe_state); 2562a8164dfSZhong Wang } else { 2572a8164dfSZhong Wang fcoe_trace_start = ddi_get_lbolt(); 2582a8164dfSZhong Wang ftb = kmem_zalloc(fcoe_trace_buf_size, 2592a8164dfSZhong Wang KM_SLEEP); 2602a8164dfSZhong Wang fcoe_trace_buf = ftb; 2612a8164dfSZhong Wang mutex_init(&fcoe_trace_buf_lock, NULL, MUTEX_DRIVER, 0); 2622a8164dfSZhong Wang } 2632a8164dfSZhong Wang } 2642a8164dfSZhong Wang 2652a8164dfSZhong Wang FCOE_LOG("fcoe", "exit _init with %x", ret); 2662a8164dfSZhong Wang 2672a8164dfSZhong Wang return (ret); 2682a8164dfSZhong Wang } 2692a8164dfSZhong Wang 2702a8164dfSZhong Wang int 2712a8164dfSZhong Wang _fini(void) 2722a8164dfSZhong Wang { 2732a8164dfSZhong Wang int ret; 2742a8164dfSZhong Wang 2752a8164dfSZhong Wang ret = mod_remove(&modlinkage); 2762a8164dfSZhong Wang if (ret == 0) { 2772a8164dfSZhong Wang ddi_soft_state_fini(&fcoe_state); 2782a8164dfSZhong Wang } 2792a8164dfSZhong Wang 2802a8164dfSZhong Wang FCOE_LOG("fcoe", "exit _fini with %x", ret); 2812a8164dfSZhong Wang if (ret == 0) { 2822a8164dfSZhong Wang kmem_free(fcoe_trace_buf, fcoe_trace_buf_size); 2832a8164dfSZhong Wang mutex_destroy(&fcoe_trace_buf_lock); 2842a8164dfSZhong Wang } 2852a8164dfSZhong Wang 2862a8164dfSZhong Wang return (ret); 2872a8164dfSZhong Wang } 2882a8164dfSZhong Wang 2892a8164dfSZhong Wang int 2902a8164dfSZhong Wang _info(struct modinfo *modinfop) 2912a8164dfSZhong Wang { 2922a8164dfSZhong Wang return (mod_info(&modlinkage, modinfop)); 2932a8164dfSZhong Wang } 2942a8164dfSZhong Wang 2952a8164dfSZhong Wang /* 2962a8164dfSZhong Wang * Autoconfiguration entry points: attach, detach, getinfo 2972a8164dfSZhong Wang */ 2982a8164dfSZhong Wang 2992a8164dfSZhong Wang static int 3002a8164dfSZhong Wang fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3012a8164dfSZhong Wang { 3022a8164dfSZhong Wang int ret = DDI_FAILURE; 3032a8164dfSZhong Wang int fcoe_ret; 3042a8164dfSZhong Wang int instance; 3052a8164dfSZhong Wang fcoe_soft_state_t *ss; 3062a8164dfSZhong Wang 3072a8164dfSZhong Wang instance = ddi_get_instance(dip); 3082a8164dfSZhong Wang switch (cmd) { 3092a8164dfSZhong Wang case DDI_ATTACH: 3102a8164dfSZhong Wang ret = ddi_soft_state_zalloc(fcoe_state, instance); 3112a8164dfSZhong Wang if (ret == DDI_FAILURE) { 3122a8164dfSZhong Wang FCOE_LOG(0, "soft_state_zalloc-%x/%x", ret, instance); 3132a8164dfSZhong Wang return (ret); 3142a8164dfSZhong Wang } 3152a8164dfSZhong Wang 3162a8164dfSZhong Wang ss = ddi_get_soft_state(fcoe_state, instance); 3172a8164dfSZhong Wang ss->ss_dip = dip; 3182a8164dfSZhong Wang 3192a8164dfSZhong Wang ASSERT(fcoe_global_ss == NULL); 3202a8164dfSZhong Wang fcoe_global_ss = ss; 3212a8164dfSZhong Wang fcoe_ret = fcoe_attach_init(ss); 3222a8164dfSZhong Wang if (fcoe_ret == FCOE_SUCCESS) { 3232a8164dfSZhong Wang ret = DDI_SUCCESS; 3242a8164dfSZhong Wang } 3252a8164dfSZhong Wang 3262a8164dfSZhong Wang FCOE_LOG("fcoe", "fcoe_attach_init end with-%x", fcoe_ret); 3272a8164dfSZhong Wang break; 3282a8164dfSZhong Wang 3292a8164dfSZhong Wang case DDI_RESUME: 3302a8164dfSZhong Wang ret = DDI_SUCCESS; 3312a8164dfSZhong Wang break; 3322a8164dfSZhong Wang 3332a8164dfSZhong Wang default: 3342a8164dfSZhong Wang FCOE_LOG("fcoe", "unsupported attach cmd-%x", cmd); 3352a8164dfSZhong Wang break; 3362a8164dfSZhong Wang } 3372a8164dfSZhong Wang 3382a8164dfSZhong Wang return (ret); 3392a8164dfSZhong Wang } 3402a8164dfSZhong Wang 3412a8164dfSZhong Wang static int 3422a8164dfSZhong Wang fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3432a8164dfSZhong Wang { 3442a8164dfSZhong Wang int ret = DDI_FAILURE; 3452a8164dfSZhong Wang int fcoe_ret; 3462a8164dfSZhong Wang int instance; 3472a8164dfSZhong Wang fcoe_soft_state_t *ss; 3482a8164dfSZhong Wang 3492a8164dfSZhong Wang instance = ddi_get_instance(dip); 3502a8164dfSZhong Wang ss = ddi_get_soft_state(fcoe_state, instance); 3512a8164dfSZhong Wang if (ss == NULL) { 3522a8164dfSZhong Wang return (ret); 3532a8164dfSZhong Wang } 3542a8164dfSZhong Wang 3552a8164dfSZhong Wang ASSERT(fcoe_global_ss != NULL); 3562a8164dfSZhong Wang ASSERT(dip == fcoe_global_ss->ss_dip); 3572a8164dfSZhong Wang switch (cmd) { 3582a8164dfSZhong Wang case DDI_DETACH: 3592a8164dfSZhong Wang fcoe_ret = fcoe_detach_uninit(ss); 3602a8164dfSZhong Wang if (fcoe_ret == FCOE_SUCCESS) { 3612a8164dfSZhong Wang ret = DDI_SUCCESS; 3622a8164dfSZhong Wang fcoe_global_ss = NULL; 3632a8164dfSZhong Wang } 3642a8164dfSZhong Wang 3652a8164dfSZhong Wang break; 3662a8164dfSZhong Wang 3672a8164dfSZhong Wang case DDI_SUSPEND: 3682a8164dfSZhong Wang ret = DDI_SUCCESS; 3692a8164dfSZhong Wang break; 3702a8164dfSZhong Wang 3712a8164dfSZhong Wang default: 3722a8164dfSZhong Wang FCOE_LOG(0, "unsupported detach cmd-%x", cmd); 3732a8164dfSZhong Wang break; 3742a8164dfSZhong Wang } 3752a8164dfSZhong Wang 3762a8164dfSZhong Wang return (ret); 3772a8164dfSZhong Wang } 3782a8164dfSZhong Wang 3792a8164dfSZhong Wang /* 3802a8164dfSZhong Wang * FCA driver's intercepted bus control operations. 3812a8164dfSZhong Wang */ 3822a8164dfSZhong Wang static int 3832a8164dfSZhong Wang fcoe_bus_ctl(dev_info_t *fcoe_dip, dev_info_t *rip, 3842a8164dfSZhong Wang ddi_ctl_enum_t op, void *clientarg, void *result) 3852a8164dfSZhong Wang { 3862a8164dfSZhong Wang int ret; 3872a8164dfSZhong Wang switch (op) { 3882a8164dfSZhong Wang case DDI_CTLOPS_REPORTDEV: 3892a8164dfSZhong Wang case DDI_CTLOPS_IOMIN: 3902a8164dfSZhong Wang ret = DDI_SUCCESS; 3912a8164dfSZhong Wang break; 3922a8164dfSZhong Wang 3932a8164dfSZhong Wang case DDI_CTLOPS_INITCHILD: 3942a8164dfSZhong Wang ret = fcoe_initchild(fcoe_dip, (dev_info_t *)clientarg); 3952a8164dfSZhong Wang break; 3962a8164dfSZhong Wang 3972a8164dfSZhong Wang case DDI_CTLOPS_UNINITCHILD: 3982a8164dfSZhong Wang ret = fcoe_uninitchild(fcoe_dip, (dev_info_t *)clientarg); 3992a8164dfSZhong Wang break; 4002a8164dfSZhong Wang 4012a8164dfSZhong Wang default: 4022a8164dfSZhong Wang ret = ddi_ctlops(fcoe_dip, rip, op, clientarg, result); 4032a8164dfSZhong Wang break; 4042a8164dfSZhong Wang } 4052a8164dfSZhong Wang 4062a8164dfSZhong Wang return (ret); 4072a8164dfSZhong Wang } 4082a8164dfSZhong Wang 4092a8164dfSZhong Wang /* 4102a8164dfSZhong Wang * We need specify the dev address for client driver's instance, or we 4112a8164dfSZhong Wang * can't online client driver's instance. 4122a8164dfSZhong Wang */ 4132a8164dfSZhong Wang /* ARGSUSED */ 4142a8164dfSZhong Wang static int 4152a8164dfSZhong Wang fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip) 4162a8164dfSZhong Wang { 4177ff83669SZhong Wang char client_addr[FCOE_STR_LEN]; 4187ff83669SZhong Wang int rval; 4192a8164dfSZhong Wang 4207ff83669SZhong Wang rval = ddi_prop_get_int(DDI_DEV_T_ANY, client_dip, 4217ff83669SZhong Wang DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1); 4227ff83669SZhong Wang if (rval == -1) { 4237ff83669SZhong Wang FCOE_LOG(__FUNCTION__, "no mac_id property: %p", client_dip); 4247ff83669SZhong Wang return (DDI_FAILURE); 4252a8164dfSZhong Wang } 4262a8164dfSZhong Wang 4277ff83669SZhong Wang bzero(client_addr, FCOE_STR_LEN); 4287ff83669SZhong Wang (void) sprintf((char *)client_addr, "%x,0", rval); 4297ff83669SZhong Wang ddi_set_name_addr(client_dip, client_addr); 4302a8164dfSZhong Wang return (DDI_SUCCESS); 4312a8164dfSZhong Wang } 4322a8164dfSZhong Wang 4332a8164dfSZhong Wang /* ARGSUSED */ 4342a8164dfSZhong Wang static int 4352a8164dfSZhong Wang fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip) 4362a8164dfSZhong Wang { 4372a8164dfSZhong Wang ddi_set_name_addr(client_dip, NULL); 4382a8164dfSZhong Wang return (DDI_SUCCESS); 4392a8164dfSZhong Wang } 4402a8164dfSZhong Wang 4412a8164dfSZhong Wang /* 4422a8164dfSZhong Wang * Device access entry points 4432a8164dfSZhong Wang */ 4442a8164dfSZhong Wang static int 4452a8164dfSZhong Wang fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp) 4462a8164dfSZhong Wang { 4472a8164dfSZhong Wang int instance; 4482a8164dfSZhong Wang fcoe_soft_state_t *ss; 4492a8164dfSZhong Wang 4502a8164dfSZhong Wang if (otype != OTYP_CHR) { 4512a8164dfSZhong Wang return (EINVAL); 4522a8164dfSZhong Wang } 4532a8164dfSZhong Wang 4542a8164dfSZhong Wang /* 4552a8164dfSZhong Wang * Since this is for debugging only, only allow root to issue ioctl now 4562a8164dfSZhong Wang */ 4572a8164dfSZhong Wang if (drv_priv(credp) != 0) { 4582a8164dfSZhong Wang return (EPERM); 4592a8164dfSZhong Wang } 4602a8164dfSZhong Wang 4612a8164dfSZhong Wang instance = (int)getminor(*devp); 4622a8164dfSZhong Wang ss = ddi_get_soft_state(fcoe_state, instance); 4632a8164dfSZhong Wang if (ss == NULL) { 4642a8164dfSZhong Wang return (ENXIO); 4652a8164dfSZhong Wang } 4662a8164dfSZhong Wang 4672a8164dfSZhong Wang mutex_enter(&ss->ss_ioctl_mutex); 4682a8164dfSZhong Wang if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) { 4692a8164dfSZhong Wang /* 4702a8164dfSZhong Wang * It is already open for exclusive access. 4712a8164dfSZhong Wang * So shut the door on this caller. 4722a8164dfSZhong Wang */ 4732a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 4742a8164dfSZhong Wang return (EBUSY); 4752a8164dfSZhong Wang } 4762a8164dfSZhong Wang 4772a8164dfSZhong Wang if (flag & FEXCL) { 4782a8164dfSZhong Wang if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) { 4792a8164dfSZhong Wang /* 4802a8164dfSZhong Wang * Exclusive operation not possible 4812a8164dfSZhong Wang * as it is already opened 4822a8164dfSZhong Wang */ 4832a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 4842a8164dfSZhong Wang return (EBUSY); 4852a8164dfSZhong Wang } 4862a8164dfSZhong Wang ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL; 4872a8164dfSZhong Wang } 4882a8164dfSZhong Wang 4892a8164dfSZhong Wang ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_OPEN; 4902a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 4912a8164dfSZhong Wang 4922a8164dfSZhong Wang return (0); 4932a8164dfSZhong Wang } 4942a8164dfSZhong Wang 4952a8164dfSZhong Wang /* ARGSUSED */ 4962a8164dfSZhong Wang static int 4972a8164dfSZhong Wang fcoe_close(dev_t dev, int flag, int otype, cred_t *credp) 4982a8164dfSZhong Wang { 4992a8164dfSZhong Wang int instance; 5002a8164dfSZhong Wang fcoe_soft_state_t *ss; 5012a8164dfSZhong Wang 5022a8164dfSZhong Wang if (otype != OTYP_CHR) { 5032a8164dfSZhong Wang return (EINVAL); 5042a8164dfSZhong Wang } 5052a8164dfSZhong Wang 5062a8164dfSZhong Wang instance = (int)getminor(dev); 5072a8164dfSZhong Wang ss = ddi_get_soft_state(fcoe_state, instance); 5082a8164dfSZhong Wang if (ss == NULL) { 5092a8164dfSZhong Wang return (ENXIO); 5102a8164dfSZhong Wang } 5112a8164dfSZhong Wang 5122a8164dfSZhong Wang mutex_enter(&ss->ss_ioctl_mutex); 5132a8164dfSZhong Wang if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) { 5142a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 5152a8164dfSZhong Wang return (ENODEV); 5162a8164dfSZhong Wang } 5172a8164dfSZhong Wang 5182a8164dfSZhong Wang ss->ss_ioctl_flags &= ~FCOE_IOCTL_FLAG_MASK; 5192a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 5202a8164dfSZhong Wang 5212a8164dfSZhong Wang return (0); 5222a8164dfSZhong Wang } 5232a8164dfSZhong Wang 5242a8164dfSZhong Wang /* ARGSUSED */ 5252a8164dfSZhong Wang static int 5262a8164dfSZhong Wang fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 5272a8164dfSZhong Wang cred_t *credp, int *rval) 5282a8164dfSZhong Wang { 5292a8164dfSZhong Wang fcoe_soft_state_t *ss; 5302a8164dfSZhong Wang int ret = 0; 5312a8164dfSZhong Wang 5322a8164dfSZhong Wang if (drv_priv(credp) != 0) { 5332a8164dfSZhong Wang return (EPERM); 5342a8164dfSZhong Wang } 5352a8164dfSZhong Wang 5362a8164dfSZhong Wang ss = ddi_get_soft_state(fcoe_state, (int32_t)getminor(dev)); 5372a8164dfSZhong Wang if (ss == NULL) { 5382a8164dfSZhong Wang return (ENXIO); 5392a8164dfSZhong Wang } 5402a8164dfSZhong Wang 5412a8164dfSZhong Wang mutex_enter(&ss->ss_ioctl_mutex); 5422a8164dfSZhong Wang if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) { 5432a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 5442a8164dfSZhong Wang return (ENXIO); 5452a8164dfSZhong Wang } 5462a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 5472a8164dfSZhong Wang 5482a8164dfSZhong Wang switch (cmd) { 5492a8164dfSZhong Wang case FCOEIO_CMD: 5502a8164dfSZhong Wang ret = fcoe_iocmd(ss, data, mode); 5512a8164dfSZhong Wang break; 5522a8164dfSZhong Wang default: 5532a8164dfSZhong Wang FCOE_LOG(0, "fcoe_ioctl: ioctl-0x%02X", cmd); 5542a8164dfSZhong Wang ret = ENOTTY; 5552a8164dfSZhong Wang break; 5562a8164dfSZhong Wang } 5572a8164dfSZhong Wang 5582a8164dfSZhong Wang return (ret); 5592a8164dfSZhong Wang } 5602a8164dfSZhong Wang 5612a8164dfSZhong Wang static int 5622a8164dfSZhong Wang fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio, 5632a8164dfSZhong Wang void **ibuf, void **abuf, void **obuf) 5642a8164dfSZhong Wang { 5652a8164dfSZhong Wang int ret = 0; 5662a8164dfSZhong Wang 5672a8164dfSZhong Wang *ibuf = NULL; 5682a8164dfSZhong Wang *abuf = NULL; 5692a8164dfSZhong Wang *obuf = NULL; 5702a8164dfSZhong Wang *fcoeio = kmem_zalloc(sizeof (fcoeio_t), KM_SLEEP); 5712a8164dfSZhong Wang if (ddi_copyin((void *)data, *fcoeio, sizeof (fcoeio_t), mode) != 0) { 5722a8164dfSZhong Wang ret = EFAULT; 5732a8164dfSZhong Wang goto copyin_iocdata_fail; 5742a8164dfSZhong Wang } 5752a8164dfSZhong Wang 5762a8164dfSZhong Wang if ((*fcoeio)->fcoeio_ilen > FCOEIO_MAX_BUF_LEN || 5772a8164dfSZhong Wang (*fcoeio)->fcoeio_alen > FCOEIO_MAX_BUF_LEN || 5782a8164dfSZhong Wang (*fcoeio)->fcoeio_olen > FCOEIO_MAX_BUF_LEN) { 5792a8164dfSZhong Wang ret = EFAULT; 5802a8164dfSZhong Wang goto copyin_iocdata_fail; 5812a8164dfSZhong Wang } 5822a8164dfSZhong Wang 5832a8164dfSZhong Wang if ((*fcoeio)->fcoeio_ilen) { 5842a8164dfSZhong Wang *ibuf = kmem_zalloc((*fcoeio)->fcoeio_ilen, KM_SLEEP); 5852a8164dfSZhong Wang if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_ibuf, 5862a8164dfSZhong Wang *ibuf, (*fcoeio)->fcoeio_ilen, mode) != 0) { 5872a8164dfSZhong Wang ret = EFAULT; 5882a8164dfSZhong Wang goto copyin_iocdata_fail; 5892a8164dfSZhong Wang } 5902a8164dfSZhong Wang } 5912a8164dfSZhong Wang 5922a8164dfSZhong Wang if ((*fcoeio)->fcoeio_alen) { 5932a8164dfSZhong Wang *abuf = kmem_zalloc((*fcoeio)->fcoeio_alen, KM_SLEEP); 5942a8164dfSZhong Wang if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_abuf, 5952a8164dfSZhong Wang *abuf, (*fcoeio)->fcoeio_alen, mode) != 0) { 5962a8164dfSZhong Wang ret = EFAULT; 5972a8164dfSZhong Wang goto copyin_iocdata_fail; 5982a8164dfSZhong Wang } 5992a8164dfSZhong Wang } 6002a8164dfSZhong Wang 6012a8164dfSZhong Wang if ((*fcoeio)->fcoeio_olen) { 6022a8164dfSZhong Wang *obuf = kmem_zalloc((*fcoeio)->fcoeio_olen, KM_SLEEP); 6032a8164dfSZhong Wang } 6042a8164dfSZhong Wang return (ret); 6052a8164dfSZhong Wang 6062a8164dfSZhong Wang copyin_iocdata_fail: 6072a8164dfSZhong Wang if (*abuf) { 6082a8164dfSZhong Wang kmem_free(*abuf, (*fcoeio)->fcoeio_alen); 6092a8164dfSZhong Wang *abuf = NULL; 6102a8164dfSZhong Wang } 6112a8164dfSZhong Wang 6122a8164dfSZhong Wang if (*ibuf) { 6132a8164dfSZhong Wang kmem_free(*ibuf, (*fcoeio)->fcoeio_ilen); 6142a8164dfSZhong Wang *ibuf = NULL; 6152a8164dfSZhong Wang } 6162a8164dfSZhong Wang 6172a8164dfSZhong Wang kmem_free(*fcoeio, sizeof (fcoeio_t)); 6182a8164dfSZhong Wang return (ret); 6192a8164dfSZhong Wang } 6202a8164dfSZhong Wang 6212a8164dfSZhong Wang static int 6222a8164dfSZhong Wang fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio, void *obuf) 6232a8164dfSZhong Wang { 6242a8164dfSZhong Wang if (fcoeio->fcoeio_olen) { 6252a8164dfSZhong Wang if (ddi_copyout(obuf, 6262a8164dfSZhong Wang (void *)(unsigned long)fcoeio->fcoeio_obuf, 6272a8164dfSZhong Wang fcoeio->fcoeio_olen, mode) != 0) { 6282a8164dfSZhong Wang return (EFAULT); 6292a8164dfSZhong Wang } 6302a8164dfSZhong Wang } 6312a8164dfSZhong Wang 6322a8164dfSZhong Wang if (ddi_copyout(fcoeio, (void *)data, sizeof (fcoeio_t), mode) != 0) { 6332a8164dfSZhong Wang return (EFAULT); 6342a8164dfSZhong Wang } 6352a8164dfSZhong Wang return (0); 6362a8164dfSZhong Wang } 6372a8164dfSZhong Wang 6382a8164dfSZhong Wang static int 6392a8164dfSZhong Wang fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode) 6402a8164dfSZhong Wang { 6412a8164dfSZhong Wang int ret; 6422a8164dfSZhong Wang fcoe_mac_t *fcoe_mac; 6432a8164dfSZhong Wang void *ibuf = NULL; 6442a8164dfSZhong Wang void *obuf = NULL; 6452a8164dfSZhong Wang void *abuf = NULL; 6462a8164dfSZhong Wang fcoeio_t *fcoeio; 6472a8164dfSZhong Wang 6482a8164dfSZhong Wang ret = fcoe_copyin_iocdata(data, mode, &fcoeio, &ibuf, &abuf, &obuf); 6492a8164dfSZhong Wang if (ret != 0) { 6502a8164dfSZhong Wang goto fcoeiocmd_release_buf; 6512a8164dfSZhong Wang } 6522a8164dfSZhong Wang 6532a8164dfSZhong Wang /* 6542a8164dfSZhong Wang * If an exclusive open was demanded during open, ensure that 6552a8164dfSZhong Wang * only one thread can execute an ioctl at a time 6562a8164dfSZhong Wang */ 6572a8164dfSZhong Wang mutex_enter(&ss->ss_ioctl_mutex); 6582a8164dfSZhong Wang if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) { 6592a8164dfSZhong Wang if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL_BUSY) { 6602a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 6612a8164dfSZhong Wang fcoeio->fcoeio_status = FCOEIOE_BUSY; 6622a8164dfSZhong Wang ret = EBUSY; 6632a8164dfSZhong Wang goto fcoeiocmd_release_buf; 6642a8164dfSZhong Wang } 6652a8164dfSZhong Wang ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL_BUSY; 6662a8164dfSZhong Wang } 6672a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 6682a8164dfSZhong Wang 6692a8164dfSZhong Wang fcoeio->fcoeio_status = 0; 6702a8164dfSZhong Wang 6712a8164dfSZhong Wang switch (fcoeio->fcoeio_cmd) { 6722a8164dfSZhong Wang case FCOEIO_CREATE_FCOE_PORT: { 6732a8164dfSZhong Wang fcoeio_create_port_param_t *param = 6742a8164dfSZhong Wang (fcoeio_create_port_param_t *)ibuf; 6752a8164dfSZhong Wang int cmpwwn = 0; 6762a8164dfSZhong Wang fcoe_port_t *eport; 6772a8164dfSZhong Wang 6782a8164dfSZhong Wang if (fcoeio->fcoeio_ilen != 6792a8164dfSZhong Wang sizeof (fcoeio_create_port_param_t) || 6802a8164dfSZhong Wang fcoeio->fcoeio_xfer != FCOEIO_XFER_WRITE) { 6812a8164dfSZhong Wang fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG; 6822a8164dfSZhong Wang ret = EINVAL; 6832a8164dfSZhong Wang break; 6842a8164dfSZhong Wang } 6852a8164dfSZhong Wang 6862a8164dfSZhong Wang mutex_enter(&ss->ss_ioctl_mutex); 687d4401b99SKelly Hu fcoe_mac = fcoe_create_mac_by_id(param->fcp_mac_linkid); 6882a8164dfSZhong Wang if (fcoe_mac == NULL) { 6892a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 6902a8164dfSZhong Wang fcoeio->fcoeio_status = FCOEIOE_CREATE_MAC; 6912a8164dfSZhong Wang ret = EIO; 6922a8164dfSZhong Wang break; 6932a8164dfSZhong Wang } 6942a8164dfSZhong Wang 6952a8164dfSZhong Wang if (fcoe_mac->fm_flags & FCOE_MAC_FLAG_ENABLED) { 6962a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 6972a8164dfSZhong Wang fcoeio->fcoeio_status = FCOEIOE_ALREADY; 6982a8164dfSZhong Wang ret = EALREADY; 6992a8164dfSZhong Wang break; 7002a8164dfSZhong Wang } else { 7012a8164dfSZhong Wang ret = fcoe_open_mac(fcoe_mac, param->fcp_force_promisc, 7022a8164dfSZhong Wang &fcoeio->fcoeio_status); 7032a8164dfSZhong Wang if (ret != 0) { 7042a8164dfSZhong Wang fcoe_destroy_mac(fcoe_mac); 7052a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 7062a8164dfSZhong Wang if (fcoeio->fcoeio_status == 0) { 7072a8164dfSZhong Wang fcoeio->fcoeio_status = 7082a8164dfSZhong Wang FCOEIOE_OPEN_MAC; 7092a8164dfSZhong Wang } 7102a8164dfSZhong Wang ret = EIO; 7112a8164dfSZhong Wang break; 7122a8164dfSZhong Wang } else { 7132a8164dfSZhong Wang fcoe_mac->fm_flags |= FCOE_MAC_FLAG_ENABLED; 7142a8164dfSZhong Wang } 7152a8164dfSZhong Wang } 7162a8164dfSZhong Wang 7172a8164dfSZhong Wang /* 7182a8164dfSZhong Wang * Provide PWWN and NWWN based on mac address 7192a8164dfSZhong Wang */ 7202a8164dfSZhong Wang eport = &fcoe_mac->fm_eport; 7212a8164dfSZhong Wang if (!param->fcp_pwwn_provided) { 7222a8164dfSZhong Wang fcoe_init_wwn_from_mac(eport->eport_portwwn, 7232a8164dfSZhong Wang fcoe_mac->fm_current_addr, 1, 0); 7242a8164dfSZhong Wang } else { 7252a8164dfSZhong Wang (void) memcpy(eport->eport_portwwn, param->fcp_pwwn, 8); 7262a8164dfSZhong Wang } 7272a8164dfSZhong Wang 7282a8164dfSZhong Wang if (!param->fcp_nwwn_provided) { 7292a8164dfSZhong Wang fcoe_init_wwn_from_mac(eport->eport_nodewwn, 7302a8164dfSZhong Wang fcoe_mac->fm_current_addr, 0, 0); 7312a8164dfSZhong Wang } else { 7322a8164dfSZhong Wang (void) memcpy(eport->eport_nodewwn, param->fcp_nwwn, 8); 7332a8164dfSZhong Wang } 7342a8164dfSZhong Wang 7352a8164dfSZhong Wang cmpwwn = fcoe_cmp_wwn(fcoe_mac); 7362a8164dfSZhong Wang 7372a8164dfSZhong Wang if (cmpwwn != 0) { 7382a8164dfSZhong Wang if (cmpwwn == 1) { 7392a8164dfSZhong Wang fcoeio->fcoeio_status = FCOEIOE_PWWN_CONFLICTED; 7402a8164dfSZhong Wang } else if (cmpwwn == -1) { 7412a8164dfSZhong Wang fcoeio->fcoeio_status = FCOEIOE_NWWN_CONFLICTED; 7422a8164dfSZhong Wang } 7432a8164dfSZhong Wang (void) fcoe_close_mac(fcoe_mac); 7442a8164dfSZhong Wang fcoe_destroy_mac(fcoe_mac); 7452a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 7462a8164dfSZhong Wang ret = ENOTUNIQ; 7472a8164dfSZhong Wang break; 7482a8164dfSZhong Wang } 7492a8164dfSZhong Wang 7502a8164dfSZhong Wang if (ret == 0) { 7512a8164dfSZhong Wang ret = fcoe_create_port(ss->ss_dip, 7522a8164dfSZhong Wang fcoe_mac, 7532a8164dfSZhong Wang (param->fcp_port_type == FCOE_CLIENT_TARGET)); 7542a8164dfSZhong Wang if (ret != 0) { 75587dcbdbdSKevin Yu if (fcoe_mac_existed(fcoe_mac) == B_TRUE) { 7562a8164dfSZhong Wang (void) fcoe_close_mac(fcoe_mac); 7572a8164dfSZhong Wang fcoe_destroy_mac(fcoe_mac); 75887dcbdbdSKevin Yu } 7592a8164dfSZhong Wang fcoeio->fcoeio_status = FCOEIOE_CREATE_PORT; 7602a8164dfSZhong Wang ret = EIO; 7612a8164dfSZhong Wang } 7622a8164dfSZhong Wang } 7632a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 7642a8164dfSZhong Wang 7652a8164dfSZhong Wang break; 7662a8164dfSZhong Wang } 7672a8164dfSZhong Wang 7682a8164dfSZhong Wang case FCOEIO_DELETE_FCOE_PORT: { 769d4401b99SKelly Hu fcoeio_delete_port_param_t *del_port_param = 770d4401b99SKelly Hu (fcoeio_delete_port_param_t *)ibuf; 771e6eb57e7SKevin Yu uint64_t *is_target = (uint64_t *)obuf; 7722a8164dfSZhong Wang 773d4401b99SKelly Hu if (fcoeio->fcoeio_ilen < sizeof (fcoeio_delete_port_param_t) || 774e6eb57e7SKevin Yu fcoeio->fcoeio_olen != sizeof (uint64_t) || 775e6eb57e7SKevin Yu fcoeio->fcoeio_xfer != FCOEIO_XFER_RW) { 7762a8164dfSZhong Wang fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG; 7772a8164dfSZhong Wang ret = EINVAL; 7782a8164dfSZhong Wang break; 7792a8164dfSZhong Wang } 7802a8164dfSZhong Wang 7812a8164dfSZhong Wang mutex_enter(&ss->ss_ioctl_mutex); 782d4401b99SKelly Hu ret = fcoe_delete_port(ss->ss_dip, fcoeio, 783e6eb57e7SKevin Yu del_port_param->fdp_mac_linkid, is_target); 7842a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 7857ff83669SZhong Wang FCOE_LOG("fcoe", "fcoe_delete_port %x return: %d", 7867ff83669SZhong Wang del_port_param->fdp_mac_linkid, ret); 7872a8164dfSZhong Wang break; 7882a8164dfSZhong Wang } 7892a8164dfSZhong Wang 7902a8164dfSZhong Wang case FCOEIO_GET_FCOE_PORT_LIST: { 7912a8164dfSZhong Wang fcoe_port_list_t *list = (fcoe_port_list_t *)obuf; 7922a8164dfSZhong Wang int count; 7932a8164dfSZhong Wang 7942a8164dfSZhong Wang if (fcoeio->fcoeio_xfer != FCOEIO_XFER_READ || 7952a8164dfSZhong Wang fcoeio->fcoeio_olen < sizeof (fcoe_port_list_t)) { 7962a8164dfSZhong Wang fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG; 7972a8164dfSZhong Wang ret = EINVAL; 7982a8164dfSZhong Wang break; 7992a8164dfSZhong Wang } 8002a8164dfSZhong Wang mutex_enter(&ss->ss_ioctl_mutex); 8012a8164dfSZhong Wang 8022a8164dfSZhong Wang list->numPorts = 1 + (fcoeio->fcoeio_olen - 8032a8164dfSZhong Wang sizeof (fcoe_port_list_t))/sizeof (fcoe_port_instance_t); 8042a8164dfSZhong Wang 8052a8164dfSZhong Wang count = fcoe_get_port_list(list->ports, list->numPorts); 8062a8164dfSZhong Wang 8072a8164dfSZhong Wang if (count > list->numPorts) { 8082a8164dfSZhong Wang fcoeio->fcoeio_status = FCOEIOE_MORE_DATA; 8092a8164dfSZhong Wang ret = ENOSPC; 8102a8164dfSZhong Wang } 8112a8164dfSZhong Wang list->numPorts = count; 8122a8164dfSZhong Wang mutex_exit(&ss->ss_ioctl_mutex); 8132a8164dfSZhong Wang 8142a8164dfSZhong Wang break; 8152a8164dfSZhong Wang 8162a8164dfSZhong Wang } 8172a8164dfSZhong Wang 8182a8164dfSZhong Wang default: 8192a8164dfSZhong Wang return (ENOTTY); 8202a8164dfSZhong Wang } 8212a8164dfSZhong Wang 8227ff83669SZhong Wang FCOE_LOG("fcoe", "fcoe_ioctl %x returned %d, fcoeio_status = %d", 8237ff83669SZhong Wang fcoeio->fcoeio_cmd, ret, fcoeio->fcoeio_status); 8242a8164dfSZhong Wang 8252a8164dfSZhong Wang fcoeiocmd_release_buf: 8262a8164dfSZhong Wang if (ret == 0) { 8272a8164dfSZhong Wang ret = fcoe_copyout_iocdata(data, mode, fcoeio, obuf); 8282a8164dfSZhong Wang } else if (fcoeio->fcoeio_status) { 8292a8164dfSZhong Wang (void) fcoe_copyout_iocdata(data, mode, fcoeio, obuf); 8302a8164dfSZhong Wang } 8312a8164dfSZhong Wang 8322a8164dfSZhong Wang if (obuf != NULL) { 8332a8164dfSZhong Wang kmem_free(obuf, fcoeio->fcoeio_olen); 8342a8164dfSZhong Wang obuf = NULL; 8352a8164dfSZhong Wang } 8362a8164dfSZhong Wang if (abuf != NULL) { 8372a8164dfSZhong Wang kmem_free(abuf, fcoeio->fcoeio_alen); 8382a8164dfSZhong Wang abuf = NULL; 8392a8164dfSZhong Wang } 8402a8164dfSZhong Wang 8412a8164dfSZhong Wang if (ibuf != NULL) { 8422a8164dfSZhong Wang kmem_free(ibuf, fcoeio->fcoeio_ilen); 8432a8164dfSZhong Wang ibuf = NULL; 8442a8164dfSZhong Wang } 8452a8164dfSZhong Wang kmem_free(fcoeio, sizeof (fcoeio_t)); 8462a8164dfSZhong Wang 8472a8164dfSZhong Wang return (ret); 8482a8164dfSZhong Wang } 8492a8164dfSZhong Wang 8502a8164dfSZhong Wang /* 8512a8164dfSZhong Wang * Finish final initialization 8522a8164dfSZhong Wang */ 8532a8164dfSZhong Wang static int 8542a8164dfSZhong Wang fcoe_attach_init(fcoe_soft_state_t *ss) 8552a8164dfSZhong Wang { 8562a8164dfSZhong Wang char taskq_name[TASKQ_NAME_LEN]; 8572a8164dfSZhong Wang 8582a8164dfSZhong Wang if (ddi_create_minor_node(ss->ss_dip, "admin", S_IFCHR, 8592a8164dfSZhong Wang ddi_get_instance(ss->ss_dip), DDI_PSEUDO, 0) != DDI_SUCCESS) { 8602a8164dfSZhong Wang FCOE_LOG("FCOE", "ddi_create_minor_node failed"); 8612a8164dfSZhong Wang return (FCOE_FAILURE); 8622a8164dfSZhong Wang } 8632a8164dfSZhong Wang 8642a8164dfSZhong Wang /* 8652a8164dfSZhong Wang * watchdog responsible for release frame and dispatch events 8662a8164dfSZhong Wang */ 8672a8164dfSZhong Wang (void) snprintf(taskq_name, sizeof (taskq_name), "fcoe_mac"); 8682a8164dfSZhong Wang taskq_name[TASKQ_NAME_LEN - 1] = 0; 8692a8164dfSZhong Wang if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL, 8702a8164dfSZhong Wang taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) { 8712a8164dfSZhong Wang return (FCOE_FAILURE); 8722a8164dfSZhong Wang } 8732a8164dfSZhong Wang 8742a8164dfSZhong Wang ss->ss_ioctl_flags = 0; 8752a8164dfSZhong Wang mutex_init(&ss->ss_ioctl_mutex, NULL, MUTEX_DRIVER, NULL); 8762a8164dfSZhong Wang list_create(&ss->ss_mac_list, sizeof (fcoe_mac_t), 8772a8164dfSZhong Wang offsetof(fcoe_mac_t, fm_ss_node)); 8782a8164dfSZhong Wang list_create(&ss->ss_pfrm_list, sizeof (fcoe_i_frame_t), 8792a8164dfSZhong Wang offsetof(fcoe_i_frame_t, fmi_pending_node)); 8802a8164dfSZhong Wang 8812a8164dfSZhong Wang mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0); 8822a8164dfSZhong Wang cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL); 8832a8164dfSZhong Wang ss->ss_flags &= ~SS_FLAG_TERMINATE_WATCHDOG; 8842a8164dfSZhong Wang (void) ddi_taskq_dispatch(ss->ss_watchdog_taskq, 8852a8164dfSZhong Wang fcoe_watchdog, ss, DDI_SLEEP); 8862a8164dfSZhong Wang while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) { 8872a8164dfSZhong Wang delay(10); 8882a8164dfSZhong Wang } 8892a8164dfSZhong Wang fcoe_nworkers = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip, 8902a8164dfSZhong Wang DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, (char *)fcoe_workers_num, 4); 8912a8164dfSZhong Wang if (fcoe_nworkers < 1) { 8922a8164dfSZhong Wang fcoe_nworkers = 4; 8932a8164dfSZhong Wang } 8942a8164dfSZhong Wang fcoe_worker_init(); 8952a8164dfSZhong Wang 8962a8164dfSZhong Wang ddi_report_dev(ss->ss_dip); 8972a8164dfSZhong Wang return (FCOE_SUCCESS); 8982a8164dfSZhong Wang } 8992a8164dfSZhong Wang 9002a8164dfSZhong Wang /* 9012a8164dfSZhong Wang * Finish final uninitialization 9022a8164dfSZhong Wang */ 9032a8164dfSZhong Wang static int 9042a8164dfSZhong Wang fcoe_detach_uninit(fcoe_soft_state_t *ss) 9052a8164dfSZhong Wang { 9062a8164dfSZhong Wang int ret; 9072a8164dfSZhong Wang if (!list_is_empty(&ss->ss_mac_list)) { 9082a8164dfSZhong Wang FCOE_LOG("fcoe", "ss_mac_list is not empty when detach"); 9092a8164dfSZhong Wang return (FCOE_FAILURE); 9102a8164dfSZhong Wang } 9112a8164dfSZhong Wang 9122a8164dfSZhong Wang if ((ret = fcoe_worker_fini()) != FCOE_SUCCESS) { 9132a8164dfSZhong Wang return (ret); 9142a8164dfSZhong Wang } 9152a8164dfSZhong Wang 9162a8164dfSZhong Wang /* 9172a8164dfSZhong Wang * Stop watchdog 9182a8164dfSZhong Wang */ 9192a8164dfSZhong Wang if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 9202a8164dfSZhong Wang mutex_enter(&ss->ss_watch_mutex); 9212a8164dfSZhong Wang ss->ss_flags |= SS_FLAG_TERMINATE_WATCHDOG; 9222a8164dfSZhong Wang cv_broadcast(&ss->ss_watch_cv); 9232a8164dfSZhong Wang mutex_exit(&ss->ss_watch_mutex); 9242a8164dfSZhong Wang while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 9252a8164dfSZhong Wang delay(10); 9262a8164dfSZhong Wang } 9272a8164dfSZhong Wang } 9282a8164dfSZhong Wang 9292a8164dfSZhong Wang ddi_taskq_destroy(ss->ss_watchdog_taskq); 9302a8164dfSZhong Wang mutex_destroy(&ss->ss_watch_mutex); 9312a8164dfSZhong Wang cv_destroy(&ss->ss_watch_cv); 9322a8164dfSZhong Wang 9332a8164dfSZhong Wang ddi_remove_minor_node(ss->ss_dip, NULL); 9342a8164dfSZhong Wang mutex_destroy(&ss->ss_ioctl_mutex); 9352a8164dfSZhong Wang list_destroy(&ss->ss_mac_list); 9362a8164dfSZhong Wang 9372a8164dfSZhong Wang return (FCOE_SUCCESS); 9382a8164dfSZhong Wang } 9392a8164dfSZhong Wang 9402a8164dfSZhong Wang /* 9412a8164dfSZhong Wang * Return mac instance if it exist, or else return NULL. 9422a8164dfSZhong Wang */ 9432a8164dfSZhong Wang fcoe_mac_t * 944d4401b99SKelly Hu fcoe_lookup_mac_by_id(datalink_id_t linkid) 9452a8164dfSZhong Wang { 9462a8164dfSZhong Wang fcoe_mac_t *mac = NULL; 9472a8164dfSZhong Wang 948d4401b99SKelly Hu ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 9492a8164dfSZhong Wang for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; 9502a8164dfSZhong Wang mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { 951d4401b99SKelly Hu if (linkid != mac->fm_linkid) { 9522a8164dfSZhong Wang continue; 9532a8164dfSZhong Wang } 9542a8164dfSZhong Wang return (mac); 9552a8164dfSZhong Wang } 9562a8164dfSZhong Wang return (NULL); 9572a8164dfSZhong Wang } 9582a8164dfSZhong Wang 9592a8164dfSZhong Wang /* 96087dcbdbdSKevin Yu * Return B_TRUE if mac exists, or else return B_FALSE 96187dcbdbdSKevin Yu */ 96287dcbdbdSKevin Yu static boolean_t 96387dcbdbdSKevin Yu fcoe_mac_existed(fcoe_mac_t *pmac) 96487dcbdbdSKevin Yu { 96587dcbdbdSKevin Yu fcoe_mac_t *mac = NULL; 96687dcbdbdSKevin Yu 96787dcbdbdSKevin Yu ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 96887dcbdbdSKevin Yu for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; 96987dcbdbdSKevin Yu mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { 97087dcbdbdSKevin Yu if (mac == pmac) { 97187dcbdbdSKevin Yu return (B_TRUE); 97287dcbdbdSKevin Yu } 97387dcbdbdSKevin Yu } 97487dcbdbdSKevin Yu return (B_FALSE); 97587dcbdbdSKevin Yu } 97687dcbdbdSKevin Yu 97787dcbdbdSKevin Yu /* 9782a8164dfSZhong Wang * port wwn will start with 20:..., node wwn will start with 10:... 9792a8164dfSZhong Wang */ 9802a8164dfSZhong Wang static void 9812a8164dfSZhong Wang fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac, int is_pwwn, uint8_t idx) 9822a8164dfSZhong Wang { 9832a8164dfSZhong Wang ASSERT(wwn != NULL); 9842a8164dfSZhong Wang ASSERT(mac != NULL); 9852a8164dfSZhong Wang wwn[0] = (is_pwwn + 1) << 4; 9862a8164dfSZhong Wang wwn[1] = idx; 9872a8164dfSZhong Wang bcopy(mac, wwn + 2, ETHERADDRL); 9882a8164dfSZhong Wang } 9892a8164dfSZhong Wang 9902a8164dfSZhong Wang /* 9912a8164dfSZhong Wang * Return fcoe_mac if it exists, otherwise create a new one 9922a8164dfSZhong Wang */ 9932a8164dfSZhong Wang static fcoe_mac_t * 994d4401b99SKelly Hu fcoe_create_mac_by_id(datalink_id_t linkid) 9952a8164dfSZhong Wang { 9962a8164dfSZhong Wang fcoe_mac_t *mac = NULL; 997d4401b99SKelly Hu ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 9982a8164dfSZhong Wang 999d4401b99SKelly Hu mac = fcoe_lookup_mac_by_id(linkid); 10002a8164dfSZhong Wang if (mac != NULL) { 1001d4401b99SKelly Hu FCOE_LOG("fcoe", "fcoe_create_mac_by_id found one mac %d", 1002d4401b99SKelly Hu linkid); 10032a8164dfSZhong Wang return (mac); 10042a8164dfSZhong Wang } 10052a8164dfSZhong Wang 10062a8164dfSZhong Wang mac = kmem_zalloc(sizeof (fcoe_mac_t), KM_SLEEP); 1007d4401b99SKelly Hu mac->fm_linkid = linkid; 10082a8164dfSZhong Wang mac->fm_flags = 0; 10092a8164dfSZhong Wang mac->fm_ss = fcoe_global_ss; 10102a8164dfSZhong Wang list_insert_tail(&mac->fm_ss->ss_mac_list, mac); 1011d4401b99SKelly Hu FCOE_LOG("fcoe", "fcoe_create_mac_by_id created one mac %d", linkid); 10122a8164dfSZhong Wang return (mac); 10132a8164dfSZhong Wang } 10142a8164dfSZhong Wang 10152a8164dfSZhong Wang void 10162a8164dfSZhong Wang fcoe_destroy_mac(fcoe_mac_t *mac) 10172a8164dfSZhong Wang { 10182a8164dfSZhong Wang ASSERT(mac != NULL); 10192a8164dfSZhong Wang list_remove(&mac->fm_ss->ss_mac_list, mac); 10202a8164dfSZhong Wang kmem_free(mac, sizeof (fcoe_mac_t)); 10212a8164dfSZhong Wang } 10222a8164dfSZhong Wang 10232a8164dfSZhong Wang /* 10242a8164dfSZhong Wang * raw frame layout: 10252a8164dfSZhong Wang * ethernet header + vlan header (optional) + FCoE header + 10262a8164dfSZhong Wang * FC frame + FCoE tailer 10272a8164dfSZhong Wang */ 10282a8164dfSZhong Wang /* ARGSUSED */ 10292a8164dfSZhong Wang mblk_t * 10302a8164dfSZhong Wang fcoe_get_mblk(fcoe_mac_t *mac, uint32_t raw_frame_size) 10312a8164dfSZhong Wang { 10322a8164dfSZhong Wang mblk_t *mp; 10332a8164dfSZhong Wang int err; 10342a8164dfSZhong Wang 10352a8164dfSZhong Wang /* 10362a8164dfSZhong Wang * FCFH_SIZE + PADDING_SIZE 10372a8164dfSZhong Wang */ 10382a8164dfSZhong Wang ASSERT(raw_frame_size >= 60); 10392a8164dfSZhong Wang while ((mp = allocb((size_t)raw_frame_size, 0)) == NULL) { 10402a8164dfSZhong Wang if ((err = strwaitbuf((size_t)raw_frame_size, BPRI_LO)) != 0) { 10412a8164dfSZhong Wang FCOE_LOG("fcoe_get_mblk", "strwaitbuf return %d", err); 10422a8164dfSZhong Wang return (NULL); 10432a8164dfSZhong Wang } 10442a8164dfSZhong Wang } 10452a8164dfSZhong Wang mp->b_wptr = mp->b_rptr + raw_frame_size; 10462a8164dfSZhong Wang 10472a8164dfSZhong Wang /* 10482a8164dfSZhong Wang * We should always zero FC frame header 10492a8164dfSZhong Wang */ 10502a8164dfSZhong Wang bzero(mp->b_rptr + PADDING_HEADER_SIZE, 10512a8164dfSZhong Wang sizeof (fcoe_fc_frame_header_t)); 10522a8164dfSZhong Wang return (mp); 10532a8164dfSZhong Wang } 10542a8164dfSZhong Wang 10552a8164dfSZhong Wang static void 10562a8164dfSZhong Wang fcoe_watchdog(void *arg) 10572a8164dfSZhong Wang { 10582a8164dfSZhong Wang fcoe_soft_state_t *ss = (fcoe_soft_state_t *)arg; 10592a8164dfSZhong Wang fcoe_i_frame_t *fmi; 10602a8164dfSZhong Wang fcoe_mac_t *mac = NULL; 10612a8164dfSZhong Wang 10622a8164dfSZhong Wang FCOE_LOG("fcoe", "fcoe_soft_state is %p", ss); 10632a8164dfSZhong Wang 10642a8164dfSZhong Wang mutex_enter(&ss->ss_watch_mutex); 10652a8164dfSZhong Wang ss->ss_flags |= SS_FLAG_WATCHDOG_RUNNING; 10662a8164dfSZhong Wang while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) { 10672a8164dfSZhong Wang while (fmi = (fcoe_i_frame_t *)list_head(&ss->ss_pfrm_list)) { 10682a8164dfSZhong Wang list_remove(&ss->ss_pfrm_list, fmi); 10692a8164dfSZhong Wang mutex_exit(&ss->ss_watch_mutex); 10702a8164dfSZhong Wang 10712a8164dfSZhong Wang mac = EPORT2MAC(fmi->fmi_frame->frm_eport); 10722a8164dfSZhong Wang mac->fm_client.ect_release_sol_frame(fmi->fmi_frame); 10732a8164dfSZhong Wang 10742a8164dfSZhong Wang mutex_enter(&ss->ss_watch_mutex); 10752a8164dfSZhong Wang mac->fm_frm_cnt--; 10762a8164dfSZhong Wang } 10772a8164dfSZhong Wang 10782a8164dfSZhong Wang ss->ss_flags |= SS_FLAG_DOG_WAITING; 10792a8164dfSZhong Wang (void) cv_wait(&ss->ss_watch_cv, &ss->ss_watch_mutex); 10802a8164dfSZhong Wang ss->ss_flags &= ~SS_FLAG_DOG_WAITING; 10812a8164dfSZhong Wang } 10822a8164dfSZhong Wang 10832a8164dfSZhong Wang ss->ss_flags &= ~SS_FLAG_WATCHDOG_RUNNING; 10842a8164dfSZhong Wang mutex_exit(&ss->ss_watch_mutex); 10852a8164dfSZhong Wang } 10862a8164dfSZhong Wang 10872a8164dfSZhong Wang static void 10882a8164dfSZhong Wang fcoe_worker_init() 10892a8164dfSZhong Wang { 10902a8164dfSZhong Wang uint32_t i; 10912a8164dfSZhong Wang 10922a8164dfSZhong Wang fcoe_nworkers_running = 0; 10932a8164dfSZhong Wang fcoe_worker_taskq = ddi_taskq_create(0, "FCOE_WORKER_TASKQ", 10942a8164dfSZhong Wang fcoe_nworkers, TASKQ_DEFAULTPRI, 0); 10952a8164dfSZhong Wang fcoe_workers = (fcoe_worker_t *)kmem_zalloc(sizeof (fcoe_worker_t) * 10962a8164dfSZhong Wang fcoe_nworkers, KM_SLEEP); 10972a8164dfSZhong Wang for (i = 0; i < fcoe_nworkers; i++) { 10982a8164dfSZhong Wang fcoe_worker_t *w = &fcoe_workers[i]; 10992a8164dfSZhong Wang mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL); 11002a8164dfSZhong Wang cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL); 11012a8164dfSZhong Wang w->worker_flags &= ~FCOE_WORKER_TERMINATE; 11022a8164dfSZhong Wang list_create(&w->worker_frm_list, sizeof (fcoe_i_frame_t), 11032a8164dfSZhong Wang offsetof(fcoe_i_frame_t, fmi_pending_node)); 11042a8164dfSZhong Wang (void) ddi_taskq_dispatch(fcoe_worker_taskq, fcoe_worker_frame, 11052a8164dfSZhong Wang w, DDI_SLEEP); 11062a8164dfSZhong Wang } 11072a8164dfSZhong Wang while (fcoe_nworkers_running != fcoe_nworkers) { 11082a8164dfSZhong Wang delay(10); 11092a8164dfSZhong Wang } 11102a8164dfSZhong Wang } 11112a8164dfSZhong Wang 11122a8164dfSZhong Wang static int 11132a8164dfSZhong Wang fcoe_worker_fini() 11142a8164dfSZhong Wang { 11152a8164dfSZhong Wang uint32_t i; 11162a8164dfSZhong Wang 11172a8164dfSZhong Wang for (i = 0; i < fcoe_nworkers; i++) { 11182a8164dfSZhong Wang fcoe_worker_t *w = &fcoe_workers[i]; 11192a8164dfSZhong Wang mutex_enter(&w->worker_lock); 11202a8164dfSZhong Wang if (w->worker_flags & FCOE_WORKER_STARTED) { 11212a8164dfSZhong Wang w->worker_flags |= FCOE_WORKER_TERMINATE; 11222a8164dfSZhong Wang cv_signal(&w->worker_cv); 11232a8164dfSZhong Wang } 11242a8164dfSZhong Wang mutex_exit(&w->worker_lock); 11252a8164dfSZhong Wang } 11262a8164dfSZhong Wang 11272a8164dfSZhong Wang while (fcoe_nworkers_running != 0) { 11282a8164dfSZhong Wang delay(drv_usectohz(10000)); 11292a8164dfSZhong Wang } 11302a8164dfSZhong Wang 11312a8164dfSZhong Wang ddi_taskq_destroy(fcoe_worker_taskq); 11322a8164dfSZhong Wang kmem_free(fcoe_workers, sizeof (fcoe_worker_t) * fcoe_nworkers); 11332a8164dfSZhong Wang fcoe_workers = NULL; 11342a8164dfSZhong Wang return (FCOE_SUCCESS); 11352a8164dfSZhong Wang } 11362a8164dfSZhong Wang 11372a8164dfSZhong Wang static int 11382a8164dfSZhong Wang fcoe_crc_verify(fcoe_frame_t *frm) 11392a8164dfSZhong Wang { 11402a8164dfSZhong Wang uint32_t crc; 11412a8164dfSZhong Wang uint8_t *crc_array = FRM2FMI(frm)->fmi_fft->fft_crc; 11422a8164dfSZhong Wang uint32_t crc_from_frame = ~(crc_array[0] | (crc_array[1] << 8) | 11432a8164dfSZhong Wang (crc_array[2] << 16) | (crc_array[3] << 24)); 11442a8164dfSZhong Wang CRC32(crc, frm->frm_fc_frame, frm->frm_fc_frame_size, -1U, crc32_table); 11452a8164dfSZhong Wang return (crc == crc_from_frame ? FCOE_SUCCESS : FCOE_FAILURE); 11462a8164dfSZhong Wang } 11472a8164dfSZhong Wang 11482a8164dfSZhong Wang static void 11492a8164dfSZhong Wang fcoe_worker_frame(void *arg) 11502a8164dfSZhong Wang { 11512a8164dfSZhong Wang fcoe_worker_t *w = (fcoe_worker_t *)arg; 11522a8164dfSZhong Wang fcoe_i_frame_t *fmi; 11532a8164dfSZhong Wang int ret; 11542a8164dfSZhong Wang 1155*1a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&fcoe_nworkers_running); 11562a8164dfSZhong Wang mutex_enter(&w->worker_lock); 11572a8164dfSZhong Wang w->worker_flags |= FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE; 11582a8164dfSZhong Wang while ((w->worker_flags & FCOE_WORKER_TERMINATE) == 0) { 11592a8164dfSZhong Wang /* 11602a8164dfSZhong Wang * loop through the frames 11612a8164dfSZhong Wang */ 11622a8164dfSZhong Wang while (fmi = list_head(&w->worker_frm_list)) { 11632a8164dfSZhong Wang list_remove(&w->worker_frm_list, fmi); 11642a8164dfSZhong Wang mutex_exit(&w->worker_lock); 11652a8164dfSZhong Wang /* 11662a8164dfSZhong Wang * do the checksum 11672a8164dfSZhong Wang */ 11682a8164dfSZhong Wang ret = fcoe_crc_verify(fmi->fmi_frame); 11692a8164dfSZhong Wang if (ret == FCOE_SUCCESS) { 11702a8164dfSZhong Wang fmi->fmi_mac->fm_client.ect_rx_frame( 11712a8164dfSZhong Wang fmi->fmi_frame); 11722a8164dfSZhong Wang } else { 11732a8164dfSZhong Wang fcoe_release_frame(fmi->fmi_frame); 11742a8164dfSZhong Wang } 11752a8164dfSZhong Wang mutex_enter(&w->worker_lock); 11762a8164dfSZhong Wang w->worker_ntasks--; 11772a8164dfSZhong Wang } 11782a8164dfSZhong Wang w->worker_flags &= ~FCOE_WORKER_ACTIVE; 11792a8164dfSZhong Wang cv_wait(&w->worker_cv, &w->worker_lock); 11802a8164dfSZhong Wang w->worker_flags |= FCOE_WORKER_ACTIVE; 11812a8164dfSZhong Wang } 11822a8164dfSZhong Wang w->worker_flags &= ~(FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE); 11832a8164dfSZhong Wang mutex_exit(&w->worker_lock); 1184*1a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&fcoe_nworkers_running); 11852a8164dfSZhong Wang list_destroy(&w->worker_frm_list); 11862a8164dfSZhong Wang } 11872a8164dfSZhong Wang 11882a8164dfSZhong Wang void 11892a8164dfSZhong Wang fcoe_post_frame(fcoe_frame_t *frm) 11902a8164dfSZhong Wang { 11912a8164dfSZhong Wang fcoe_worker_t *w; 11922a8164dfSZhong Wang uint16_t oxid = FRM_OXID(frm); 11932a8164dfSZhong Wang 11942a8164dfSZhong Wang w = &fcoe_workers[oxid % fcoe_nworkers_running]; 11952a8164dfSZhong Wang mutex_enter(&w->worker_lock); 11962a8164dfSZhong Wang list_insert_tail(&w->worker_frm_list, frm->frm_fcoe_private); 11972a8164dfSZhong Wang w->worker_ntasks++; 11982a8164dfSZhong Wang if ((w->worker_flags & FCOE_WORKER_ACTIVE) == 0) { 11992a8164dfSZhong Wang cv_signal(&w->worker_cv); 12002a8164dfSZhong Wang } 12012a8164dfSZhong Wang mutex_exit(&w->worker_lock); 12022a8164dfSZhong Wang } 12032a8164dfSZhong Wang 12042a8164dfSZhong Wang /* 12052a8164dfSZhong Wang * The max length of every LOG is 158 12062a8164dfSZhong Wang */ 12072a8164dfSZhong Wang void 12082a8164dfSZhong Wang fcoe_trace(caddr_t ident, const char *fmt, ...) 12092a8164dfSZhong Wang { 12102a8164dfSZhong Wang va_list args; 12112a8164dfSZhong Wang char tbuf[160]; 12122a8164dfSZhong Wang int len; 12132a8164dfSZhong Wang clock_t curclock; 12142a8164dfSZhong Wang clock_t usec; 12152a8164dfSZhong Wang 12162a8164dfSZhong Wang if (fcoe_trace_on == 0) { 12172a8164dfSZhong Wang return; 12182a8164dfSZhong Wang } 12192a8164dfSZhong Wang 12202a8164dfSZhong Wang curclock = ddi_get_lbolt(); 12212a8164dfSZhong Wang usec = (curclock - fcoe_trace_start) * usec_per_tick; 12222a8164dfSZhong Wang len = snprintf(tbuf, 158, "%lu.%03lus 0t%lu %s ", (usec / 12232a8164dfSZhong Wang (1000 * 1000)), ((usec % (1000 * 1000)) / 1000), 12242a8164dfSZhong Wang curclock, (ident ? ident : "unknown")); 12252a8164dfSZhong Wang va_start(args, fmt); 12262a8164dfSZhong Wang len += vsnprintf(tbuf + len, 158 - len, fmt, args); 12272a8164dfSZhong Wang va_end(args); 12282a8164dfSZhong Wang 12292a8164dfSZhong Wang if (len > 158) { 12302a8164dfSZhong Wang len = 158; 12312a8164dfSZhong Wang } 12322a8164dfSZhong Wang tbuf[len++] = '\n'; 12332a8164dfSZhong Wang tbuf[len] = 0; 12342a8164dfSZhong Wang 12352a8164dfSZhong Wang mutex_enter(&fcoe_trace_buf_lock); 12362a8164dfSZhong Wang bcopy(tbuf, &fcoe_trace_buf[fcoe_trace_buf_curndx], len+1); 12372a8164dfSZhong Wang fcoe_trace_buf_curndx += len; 12382a8164dfSZhong Wang if (fcoe_trace_buf_curndx > (fcoe_trace_buf_size - 320)) { 12392a8164dfSZhong Wang fcoe_trace_buf_curndx = 0; 12402a8164dfSZhong Wang } 12412a8164dfSZhong Wang mutex_exit(&fcoe_trace_buf_lock); 12422a8164dfSZhong Wang } 12432a8164dfSZhong Wang 12442a8164dfSZhong Wang /* 12452a8164dfSZhong Wang * Check whether the pwwn or nwwn already exist or not 12462a8164dfSZhong Wang * Return value: 12472a8164dfSZhong Wang * 1: PWWN conflicted 12482a8164dfSZhong Wang * -1: NWWN conflicted 12492a8164dfSZhong Wang * 0: No conflict 12502a8164dfSZhong Wang */ 12512a8164dfSZhong Wang static int 12522a8164dfSZhong Wang fcoe_cmp_wwn(fcoe_mac_t *checkedmac) 12532a8164dfSZhong Wang { 12542a8164dfSZhong Wang fcoe_mac_t *mac; 12552a8164dfSZhong Wang uint8_t *nwwn, *pwwn, *cnwwn, *cpwwn; 12562a8164dfSZhong Wang 12572a8164dfSZhong Wang cnwwn = checkedmac->fm_eport.eport_nodewwn; 12582a8164dfSZhong Wang cpwwn = checkedmac->fm_eport.eport_portwwn; 1259d4401b99SKelly Hu ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 12602a8164dfSZhong Wang 12612a8164dfSZhong Wang for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; 12622a8164dfSZhong Wang mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { 12632a8164dfSZhong Wang if (mac == checkedmac) { 12642a8164dfSZhong Wang continue; 12652a8164dfSZhong Wang } 12662a8164dfSZhong Wang nwwn = mac->fm_eport.eport_nodewwn; 12672a8164dfSZhong Wang pwwn = mac->fm_eport.eport_portwwn; 12682a8164dfSZhong Wang 12692a8164dfSZhong Wang if (memcmp(nwwn, cnwwn, 8) == 0) { 12702a8164dfSZhong Wang return (-1); 12712a8164dfSZhong Wang } 12722a8164dfSZhong Wang 12732a8164dfSZhong Wang if (memcmp(pwwn, cpwwn, 8) == 0) { 12742a8164dfSZhong Wang return (1); 12752a8164dfSZhong Wang } 12762a8164dfSZhong Wang } 12772a8164dfSZhong Wang return (0); 12782a8164dfSZhong Wang } 12792a8164dfSZhong Wang 12802a8164dfSZhong Wang static int 12812a8164dfSZhong Wang fcoe_get_port_list(fcoe_port_instance_t *ports, int count) 12822a8164dfSZhong Wang { 12832a8164dfSZhong Wang fcoe_mac_t *mac = NULL; 12842a8164dfSZhong Wang int i = 0; 12852a8164dfSZhong Wang 12862a8164dfSZhong Wang ASSERT(ports != NULL); 1287d4401b99SKelly Hu ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 12882a8164dfSZhong Wang 12892a8164dfSZhong Wang for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; 12902a8164dfSZhong Wang mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { 12912a8164dfSZhong Wang if (i < count) { 12922a8164dfSZhong Wang bcopy(mac->fm_eport.eport_portwwn, 12932a8164dfSZhong Wang ports[i].fpi_pwwn, 8); 1294d4401b99SKelly Hu ports[i].fpi_mac_linkid = mac->fm_linkid; 12952a8164dfSZhong Wang bcopy(mac->fm_current_addr, 12962a8164dfSZhong Wang ports[i].fpi_mac_current_addr, ETHERADDRL); 12972a8164dfSZhong Wang bcopy(mac->fm_primary_addr, 12982a8164dfSZhong Wang ports[i].fpi_mac_factory_addr, ETHERADDRL); 12992a8164dfSZhong Wang ports[i].fpi_port_type = 13002a8164dfSZhong Wang EPORT_CLT_TYPE(&mac->fm_eport); 13012a8164dfSZhong Wang ports[i].fpi_mtu_size = 13022a8164dfSZhong Wang mac->fm_eport.eport_mtu; 13032a8164dfSZhong Wang ports[i].fpi_mac_promisc = 13042a8164dfSZhong Wang mac->fm_promisc_handle != NULL ? 1 : 0; 13052a8164dfSZhong Wang } 13062a8164dfSZhong Wang i++; 13072a8164dfSZhong Wang } 13082a8164dfSZhong Wang return (i); 13092a8164dfSZhong Wang } 1310