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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 239087SZhong.Wang@Sun.COM * Use is subject to license terms. 249087SZhong.Wang@Sun.COM */ 259087SZhong.Wang@Sun.COM 269087SZhong.Wang@Sun.COM /* 279087SZhong.Wang@Sun.COM * The following notice accompanied the original version of this file: 289087SZhong.Wang@Sun.COM * 299087SZhong.Wang@Sun.COM * BSD LICENSE 309087SZhong.Wang@Sun.COM * 319087SZhong.Wang@Sun.COM * Copyright(c) 2007 Intel Corporation. All rights reserved. 329087SZhong.Wang@Sun.COM * All rights reserved. 339087SZhong.Wang@Sun.COM * 349087SZhong.Wang@Sun.COM * Redistribution and use in source and binary forms, with or without 359087SZhong.Wang@Sun.COM * modification, are permitted provided that the following conditions 369087SZhong.Wang@Sun.COM * are met: 379087SZhong.Wang@Sun.COM * 389087SZhong.Wang@Sun.COM * * Redistributions of source code must retain the above copyright 399087SZhong.Wang@Sun.COM * notice, this list of conditions and the following disclaimer. 409087SZhong.Wang@Sun.COM * * Redistributions in binary form must reproduce the above copyright 419087SZhong.Wang@Sun.COM * notice, this list of conditions and the following disclaimer in 429087SZhong.Wang@Sun.COM * the documentation and/or other materials provided with the 439087SZhong.Wang@Sun.COM * distribution. 449087SZhong.Wang@Sun.COM * * Neither the name of Intel Corporation nor the names of its 459087SZhong.Wang@Sun.COM * contributors may be used to endorse or promote products derived 469087SZhong.Wang@Sun.COM * from this software without specific prior written permission. 479087SZhong.Wang@Sun.COM * 489087SZhong.Wang@Sun.COM * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 499087SZhong.Wang@Sun.COM * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 509087SZhong.Wang@Sun.COM * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 519087SZhong.Wang@Sun.COM * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 529087SZhong.Wang@Sun.COM * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 539087SZhong.Wang@Sun.COM * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 549087SZhong.Wang@Sun.COM * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 559087SZhong.Wang@Sun.COM * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 569087SZhong.Wang@Sun.COM * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 579087SZhong.Wang@Sun.COM * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 589087SZhong.Wang@Sun.COM * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 599087SZhong.Wang@Sun.COM */ 609087SZhong.Wang@Sun.COM 619087SZhong.Wang@Sun.COM /* 629087SZhong.Wang@Sun.COM * Common FCoE interface interacts with MAC and FCoE clients, managing 639087SZhong.Wang@Sun.COM * FCoE ports, doing MAC address discovery/managment, and FC frame 649087SZhong.Wang@Sun.COM * encapsulation/decapsulation 659087SZhong.Wang@Sun.COM */ 669087SZhong.Wang@Sun.COM 679087SZhong.Wang@Sun.COM #include <sys/stat.h> 689087SZhong.Wang@Sun.COM #include <sys/conf.h> 699087SZhong.Wang@Sun.COM #include <sys/file.h> 709087SZhong.Wang@Sun.COM #include <sys/cred.h> 719087SZhong.Wang@Sun.COM 729087SZhong.Wang@Sun.COM #include <sys/ddi.h> 739087SZhong.Wang@Sun.COM #include <sys/sunddi.h> 749087SZhong.Wang@Sun.COM #include <sys/sunndi.h> 759087SZhong.Wang@Sun.COM #include <sys/byteorder.h> 769087SZhong.Wang@Sun.COM #include <sys/atomic.h> 779087SZhong.Wang@Sun.COM #include <sys/sysmacros.h> 789087SZhong.Wang@Sun.COM #include <sys/cmn_err.h> 799087SZhong.Wang@Sun.COM #include <sys/crc32.h> 809087SZhong.Wang@Sun.COM #include <sys/strsubr.h> 819087SZhong.Wang@Sun.COM 829087SZhong.Wang@Sun.COM #include <sys/mac_client.h> 839087SZhong.Wang@Sun.COM 849087SZhong.Wang@Sun.COM /* 859087SZhong.Wang@Sun.COM * FCoE header files 869087SZhong.Wang@Sun.COM */ 879087SZhong.Wang@Sun.COM #include <sys/fcoe/fcoeio.h> 889087SZhong.Wang@Sun.COM #include <sys/fcoe/fcoe_common.h> 899087SZhong.Wang@Sun.COM 909087SZhong.Wang@Sun.COM /* 919087SZhong.Wang@Sun.COM * Driver's own header files 929087SZhong.Wang@Sun.COM */ 939087SZhong.Wang@Sun.COM #include <fcoe.h> 949087SZhong.Wang@Sun.COM #include <fcoe_fc.h> 959087SZhong.Wang@Sun.COM #include <fcoe_eth.h> 969087SZhong.Wang@Sun.COM 979087SZhong.Wang@Sun.COM /* 989087SZhong.Wang@Sun.COM * Function forward declaration 999087SZhong.Wang@Sun.COM */ 1009087SZhong.Wang@Sun.COM static int fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 1019087SZhong.Wang@Sun.COM static int fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 1029087SZhong.Wang@Sun.COM static int fcoe_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip, 1039087SZhong.Wang@Sun.COM ddi_ctl_enum_t op, void *arg, void *result); 1049087SZhong.Wang@Sun.COM static int fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp); 1059087SZhong.Wang@Sun.COM static int fcoe_close(dev_t dev, int flag, int otype, cred_t *credp); 1069087SZhong.Wang@Sun.COM static int fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 1079087SZhong.Wang@Sun.COM cred_t *credp, int *rval); 1089087SZhong.Wang@Sun.COM static int fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio, 1099087SZhong.Wang@Sun.COM void **ibuf, void **abuf, void **obuf); 1109087SZhong.Wang@Sun.COM static int fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio, 1119087SZhong.Wang@Sun.COM void *obuf); 1129087SZhong.Wang@Sun.COM static int fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode); 1139087SZhong.Wang@Sun.COM static int fcoe_attach_init(fcoe_soft_state_t *this_ss); 1149087SZhong.Wang@Sun.COM static int fcoe_detach_uninit(fcoe_soft_state_t *this_ss); 1159087SZhong.Wang@Sun.COM static int fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip); 1169087SZhong.Wang@Sun.COM static int fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip); 1179087SZhong.Wang@Sun.COM static void fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac, 1189087SZhong.Wang@Sun.COM int is_pwwn, uint8_t idx); 1199307Skelly.hu@Sun.COM static fcoe_mac_t *fcoe_create_mac_by_id(datalink_id_t linkid); 1209087SZhong.Wang@Sun.COM static int fcoe_cmp_wwn(fcoe_mac_t *checkedmac); 1219087SZhong.Wang@Sun.COM static void fcoe_watchdog(void *arg); 1229087SZhong.Wang@Sun.COM static void fcoe_worker_init(); 1239087SZhong.Wang@Sun.COM static int fcoe_worker_fini(); 1249087SZhong.Wang@Sun.COM static void fcoe_worker_frame(); 1259087SZhong.Wang@Sun.COM static int fcoe_get_port_list(fcoe_port_instance_t *ports, int count); 1269087SZhong.Wang@Sun.COM 1279087SZhong.Wang@Sun.COM /* 1289087SZhong.Wang@Sun.COM * Driver identificaton stuff 1299087SZhong.Wang@Sun.COM */ 1309087SZhong.Wang@Sun.COM static struct cb_ops fcoe_cb_ops = { 1319087SZhong.Wang@Sun.COM fcoe_open, 1329087SZhong.Wang@Sun.COM fcoe_close, 1339087SZhong.Wang@Sun.COM nodev, 1349087SZhong.Wang@Sun.COM nodev, 1359087SZhong.Wang@Sun.COM nodev, 1369087SZhong.Wang@Sun.COM nodev, 1379087SZhong.Wang@Sun.COM nodev, 1389087SZhong.Wang@Sun.COM fcoe_ioctl, 1399087SZhong.Wang@Sun.COM nodev, 1409087SZhong.Wang@Sun.COM nodev, 1419087SZhong.Wang@Sun.COM nodev, 1429087SZhong.Wang@Sun.COM nochpoll, 1439087SZhong.Wang@Sun.COM ddi_prop_op, 1449087SZhong.Wang@Sun.COM 0, 1459087SZhong.Wang@Sun.COM D_MP | D_NEW | D_HOTPLUG, 1469087SZhong.Wang@Sun.COM CB_REV, 1479087SZhong.Wang@Sun.COM nodev, 1489087SZhong.Wang@Sun.COM nodev 1499087SZhong.Wang@Sun.COM }; 1509087SZhong.Wang@Sun.COM 1519087SZhong.Wang@Sun.COM static struct bus_ops fcoe_busops = { 1529087SZhong.Wang@Sun.COM BUSO_REV, 1539087SZhong.Wang@Sun.COM nullbusmap, /* bus_map */ 1549087SZhong.Wang@Sun.COM NULL, /* bus_get_intrspec */ 1559087SZhong.Wang@Sun.COM NULL, /* bus_add_intrspec */ 1569087SZhong.Wang@Sun.COM NULL, /* bus_remove_intrspec */ 1579087SZhong.Wang@Sun.COM i_ddi_map_fault, /* bus_map_fault */ 1589087SZhong.Wang@Sun.COM ddi_dma_map, /* bus_dma_map */ 1599087SZhong.Wang@Sun.COM ddi_dma_allochdl, /* bus_dma_allochdl */ 1609087SZhong.Wang@Sun.COM ddi_dma_freehdl, /* bus_dma_freehdl */ 1619087SZhong.Wang@Sun.COM ddi_dma_bindhdl, /* bus_dma_bindhdl */ 1629087SZhong.Wang@Sun.COM ddi_dma_unbindhdl, /* bus_unbindhdl */ 1639087SZhong.Wang@Sun.COM ddi_dma_flush, /* bus_dma_flush */ 1649087SZhong.Wang@Sun.COM ddi_dma_win, /* bus_dma_win */ 1659087SZhong.Wang@Sun.COM ddi_dma_mctl, /* bus_dma_ctl */ 1669087SZhong.Wang@Sun.COM fcoe_bus_ctl, /* bus_ctl */ 1679087SZhong.Wang@Sun.COM ddi_bus_prop_op, /* bus_prop_op */ 1689087SZhong.Wang@Sun.COM NULL, /* bus_get_eventcookie */ 1699087SZhong.Wang@Sun.COM NULL, /* bus_add_eventcall */ 1709087SZhong.Wang@Sun.COM NULL, /* bus_remove_event */ 1719087SZhong.Wang@Sun.COM NULL, /* bus_post_event */ 1729087SZhong.Wang@Sun.COM NULL, /* bus_intr_ctl */ 1739087SZhong.Wang@Sun.COM NULL, /* bus_config */ 1749087SZhong.Wang@Sun.COM NULL, /* bus_unconfig */ 1759087SZhong.Wang@Sun.COM NULL, /* bus_fm_init */ 1769087SZhong.Wang@Sun.COM NULL, /* bus_fm_fini */ 1779087SZhong.Wang@Sun.COM NULL, /* bus_fm_access_enter */ 1789087SZhong.Wang@Sun.COM NULL, /* bus_fm_access_exit */ 1799087SZhong.Wang@Sun.COM NULL, /* bus_power */ 1809087SZhong.Wang@Sun.COM NULL 1819087SZhong.Wang@Sun.COM }; 1829087SZhong.Wang@Sun.COM 1839087SZhong.Wang@Sun.COM static struct dev_ops fcoe_ops = { 1849087SZhong.Wang@Sun.COM DEVO_REV, 1859087SZhong.Wang@Sun.COM 0, 1869087SZhong.Wang@Sun.COM nodev, 1879087SZhong.Wang@Sun.COM nulldev, 1889087SZhong.Wang@Sun.COM nulldev, 1899087SZhong.Wang@Sun.COM fcoe_attach, 1909087SZhong.Wang@Sun.COM fcoe_detach, 1919087SZhong.Wang@Sun.COM nodev, 1929087SZhong.Wang@Sun.COM &fcoe_cb_ops, 1939087SZhong.Wang@Sun.COM &fcoe_busops, 1949328SZhong.Wang@Sun.COM ddi_power, 1959328SZhong.Wang@Sun.COM ddi_quiesce_not_needed 1969087SZhong.Wang@Sun.COM }; 1979087SZhong.Wang@Sun.COM 198*10264SZhong.Wang@Sun.COM #define FCOE_VERSION "20090729-1.01" 1999087SZhong.Wang@Sun.COM #define FCOE_NAME "FCoE Transport v" FCOE_VERSION 2009087SZhong.Wang@Sun.COM #define TASKQ_NAME_LEN 32 2019087SZhong.Wang@Sun.COM 2029087SZhong.Wang@Sun.COM static struct modldrv modldrv = { 2039087SZhong.Wang@Sun.COM &mod_driverops, 2049087SZhong.Wang@Sun.COM FCOE_NAME, 2059087SZhong.Wang@Sun.COM &fcoe_ops, 2069087SZhong.Wang@Sun.COM }; 2079087SZhong.Wang@Sun.COM 2089087SZhong.Wang@Sun.COM static struct modlinkage modlinkage = { 2099087SZhong.Wang@Sun.COM MODREV_1, &modldrv, NULL 2109087SZhong.Wang@Sun.COM }; 2119087SZhong.Wang@Sun.COM 2129087SZhong.Wang@Sun.COM /* 2139087SZhong.Wang@Sun.COM * TRACE for all FCoE related modules 2149087SZhong.Wang@Sun.COM */ 2159087SZhong.Wang@Sun.COM static kmutex_t fcoe_trace_buf_lock; 2169087SZhong.Wang@Sun.COM static int fcoe_trace_buf_curndx = 0; 2179087SZhong.Wang@Sun.COM static int fcoe_trace_on = 1; 2189087SZhong.Wang@Sun.COM static caddr_t fcoe_trace_buf = NULL; 2199087SZhong.Wang@Sun.COM static clock_t fcoe_trace_start = 0; 2209087SZhong.Wang@Sun.COM static caddr_t ftb = NULL; 2219087SZhong.Wang@Sun.COM static int fcoe_trace_buf_size = (1 * 1024 * 1024); 2229087SZhong.Wang@Sun.COM 2239087SZhong.Wang@Sun.COM /* 2249087SZhong.Wang@Sun.COM * Driver's global variables 2259087SZhong.Wang@Sun.COM */ 226*10264SZhong.Wang@Sun.COM const fcoe_ver_e fcoe_ver_now = FCOE_VER_NOW; 2279087SZhong.Wang@Sun.COM static void *fcoe_state = NULL; 2289087SZhong.Wang@Sun.COM fcoe_soft_state_t *fcoe_global_ss = NULL; 2299087SZhong.Wang@Sun.COM int fcoe_use_ext_log = 1; 2309087SZhong.Wang@Sun.COM 2319087SZhong.Wang@Sun.COM static ddi_taskq_t *fcoe_worker_taskq; 2329087SZhong.Wang@Sun.COM static fcoe_worker_t *fcoe_workers; 2339087SZhong.Wang@Sun.COM static uint32_t fcoe_nworkers_running; 2349087SZhong.Wang@Sun.COM 2359087SZhong.Wang@Sun.COM const char *fcoe_workers_num = "workers-number"; 2369087SZhong.Wang@Sun.COM volatile int fcoe_nworkers; 2379087SZhong.Wang@Sun.COM 2389087SZhong.Wang@Sun.COM /* 2399087SZhong.Wang@Sun.COM * Common loadable module entry points _init, _fini, _info 2409087SZhong.Wang@Sun.COM */ 2419087SZhong.Wang@Sun.COM 2429087SZhong.Wang@Sun.COM int 2439087SZhong.Wang@Sun.COM _init(void) 2449087SZhong.Wang@Sun.COM { 2459087SZhong.Wang@Sun.COM int ret; 2469087SZhong.Wang@Sun.COM 2479087SZhong.Wang@Sun.COM ret = ddi_soft_state_init(&fcoe_state, sizeof (fcoe_soft_state_t), 0); 2489087SZhong.Wang@Sun.COM if (ret == 0) { 2499087SZhong.Wang@Sun.COM ret = mod_install(&modlinkage); 2509087SZhong.Wang@Sun.COM if (ret != 0) { 2519087SZhong.Wang@Sun.COM ddi_soft_state_fini(&fcoe_state); 2529087SZhong.Wang@Sun.COM } else { 2539087SZhong.Wang@Sun.COM fcoe_trace_start = ddi_get_lbolt(); 2549087SZhong.Wang@Sun.COM ftb = kmem_zalloc(fcoe_trace_buf_size, 2559087SZhong.Wang@Sun.COM KM_SLEEP); 2569087SZhong.Wang@Sun.COM fcoe_trace_buf = ftb; 2579087SZhong.Wang@Sun.COM mutex_init(&fcoe_trace_buf_lock, NULL, MUTEX_DRIVER, 0); 2589087SZhong.Wang@Sun.COM } 2599087SZhong.Wang@Sun.COM } 2609087SZhong.Wang@Sun.COM 2619087SZhong.Wang@Sun.COM FCOE_LOG("fcoe", "exit _init with %x", ret); 2629087SZhong.Wang@Sun.COM 2639087SZhong.Wang@Sun.COM return (ret); 2649087SZhong.Wang@Sun.COM } 2659087SZhong.Wang@Sun.COM 2669087SZhong.Wang@Sun.COM int 2679087SZhong.Wang@Sun.COM _fini(void) 2689087SZhong.Wang@Sun.COM { 2699087SZhong.Wang@Sun.COM int ret; 2709087SZhong.Wang@Sun.COM 2719087SZhong.Wang@Sun.COM ret = mod_remove(&modlinkage); 2729087SZhong.Wang@Sun.COM if (ret == 0) { 2739087SZhong.Wang@Sun.COM ddi_soft_state_fini(&fcoe_state); 2749087SZhong.Wang@Sun.COM } 2759087SZhong.Wang@Sun.COM 2769087SZhong.Wang@Sun.COM FCOE_LOG("fcoe", "exit _fini with %x", ret); 2779087SZhong.Wang@Sun.COM if (ret == 0) { 2789087SZhong.Wang@Sun.COM kmem_free(fcoe_trace_buf, fcoe_trace_buf_size); 2799087SZhong.Wang@Sun.COM mutex_destroy(&fcoe_trace_buf_lock); 2809087SZhong.Wang@Sun.COM } 2819087SZhong.Wang@Sun.COM 2829087SZhong.Wang@Sun.COM return (ret); 2839087SZhong.Wang@Sun.COM } 2849087SZhong.Wang@Sun.COM 2859087SZhong.Wang@Sun.COM int 2869087SZhong.Wang@Sun.COM _info(struct modinfo *modinfop) 2879087SZhong.Wang@Sun.COM { 2889087SZhong.Wang@Sun.COM return (mod_info(&modlinkage, modinfop)); 2899087SZhong.Wang@Sun.COM } 2909087SZhong.Wang@Sun.COM 2919087SZhong.Wang@Sun.COM /* 2929087SZhong.Wang@Sun.COM * Autoconfiguration entry points: attach, detach, getinfo 2939087SZhong.Wang@Sun.COM */ 2949087SZhong.Wang@Sun.COM 2959087SZhong.Wang@Sun.COM static int 2969087SZhong.Wang@Sun.COM fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2979087SZhong.Wang@Sun.COM { 2989087SZhong.Wang@Sun.COM int ret = DDI_FAILURE; 2999087SZhong.Wang@Sun.COM int fcoe_ret; 3009087SZhong.Wang@Sun.COM int instance; 3019087SZhong.Wang@Sun.COM fcoe_soft_state_t *ss; 3029087SZhong.Wang@Sun.COM 3039087SZhong.Wang@Sun.COM instance = ddi_get_instance(dip); 3049087SZhong.Wang@Sun.COM switch (cmd) { 3059087SZhong.Wang@Sun.COM case DDI_ATTACH: 3069087SZhong.Wang@Sun.COM ret = ddi_soft_state_zalloc(fcoe_state, instance); 3079087SZhong.Wang@Sun.COM if (ret == DDI_FAILURE) { 3089087SZhong.Wang@Sun.COM FCOE_LOG(0, "soft_state_zalloc-%x/%x", ret, instance); 3099087SZhong.Wang@Sun.COM return (ret); 3109087SZhong.Wang@Sun.COM } 3119087SZhong.Wang@Sun.COM 3129087SZhong.Wang@Sun.COM ss = ddi_get_soft_state(fcoe_state, instance); 3139087SZhong.Wang@Sun.COM ss->ss_dip = dip; 3149087SZhong.Wang@Sun.COM 3159087SZhong.Wang@Sun.COM ASSERT(fcoe_global_ss == NULL); 3169087SZhong.Wang@Sun.COM fcoe_global_ss = ss; 3179087SZhong.Wang@Sun.COM fcoe_ret = fcoe_attach_init(ss); 3189087SZhong.Wang@Sun.COM if (fcoe_ret == FCOE_SUCCESS) { 3199087SZhong.Wang@Sun.COM ret = DDI_SUCCESS; 3209087SZhong.Wang@Sun.COM } 3219087SZhong.Wang@Sun.COM 3229087SZhong.Wang@Sun.COM FCOE_LOG("fcoe", "fcoe_attach_init end with-%x", fcoe_ret); 3239087SZhong.Wang@Sun.COM break; 3249087SZhong.Wang@Sun.COM 3259087SZhong.Wang@Sun.COM case DDI_RESUME: 3269087SZhong.Wang@Sun.COM ret = DDI_SUCCESS; 3279087SZhong.Wang@Sun.COM break; 3289087SZhong.Wang@Sun.COM 3299087SZhong.Wang@Sun.COM default: 3309087SZhong.Wang@Sun.COM FCOE_LOG("fcoe", "unsupported attach cmd-%x", cmd); 3319087SZhong.Wang@Sun.COM break; 3329087SZhong.Wang@Sun.COM } 3339087SZhong.Wang@Sun.COM 3349087SZhong.Wang@Sun.COM return (ret); 3359087SZhong.Wang@Sun.COM } 3369087SZhong.Wang@Sun.COM 3379087SZhong.Wang@Sun.COM static int 3389087SZhong.Wang@Sun.COM fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3399087SZhong.Wang@Sun.COM { 3409087SZhong.Wang@Sun.COM int ret = DDI_FAILURE; 3419087SZhong.Wang@Sun.COM int fcoe_ret; 3429087SZhong.Wang@Sun.COM int instance; 3439087SZhong.Wang@Sun.COM fcoe_soft_state_t *ss; 3449087SZhong.Wang@Sun.COM 3459087SZhong.Wang@Sun.COM instance = ddi_get_instance(dip); 3469087SZhong.Wang@Sun.COM ss = ddi_get_soft_state(fcoe_state, instance); 3479087SZhong.Wang@Sun.COM if (ss == NULL) { 3489087SZhong.Wang@Sun.COM return (ret); 3499087SZhong.Wang@Sun.COM } 3509087SZhong.Wang@Sun.COM 3519087SZhong.Wang@Sun.COM ASSERT(fcoe_global_ss != NULL); 3529087SZhong.Wang@Sun.COM ASSERT(dip == fcoe_global_ss->ss_dip); 3539087SZhong.Wang@Sun.COM switch (cmd) { 3549087SZhong.Wang@Sun.COM case DDI_DETACH: 3559087SZhong.Wang@Sun.COM fcoe_ret = fcoe_detach_uninit(ss); 3569087SZhong.Wang@Sun.COM if (fcoe_ret == FCOE_SUCCESS) { 3579087SZhong.Wang@Sun.COM ret = DDI_SUCCESS; 3589087SZhong.Wang@Sun.COM fcoe_global_ss = NULL; 3599087SZhong.Wang@Sun.COM } 3609087SZhong.Wang@Sun.COM 3619087SZhong.Wang@Sun.COM break; 3629087SZhong.Wang@Sun.COM 3639087SZhong.Wang@Sun.COM case DDI_SUSPEND: 3649087SZhong.Wang@Sun.COM ret = DDI_SUCCESS; 3659087SZhong.Wang@Sun.COM break; 3669087SZhong.Wang@Sun.COM 3679087SZhong.Wang@Sun.COM default: 3689087SZhong.Wang@Sun.COM FCOE_LOG(0, "unsupported detach cmd-%x", cmd); 3699087SZhong.Wang@Sun.COM break; 3709087SZhong.Wang@Sun.COM } 3719087SZhong.Wang@Sun.COM 3729087SZhong.Wang@Sun.COM return (ret); 3739087SZhong.Wang@Sun.COM } 3749087SZhong.Wang@Sun.COM 3759087SZhong.Wang@Sun.COM /* 3769087SZhong.Wang@Sun.COM * FCA driver's intercepted bus control operations. 3779087SZhong.Wang@Sun.COM */ 3789087SZhong.Wang@Sun.COM static int 3799087SZhong.Wang@Sun.COM fcoe_bus_ctl(dev_info_t *fcoe_dip, dev_info_t *rip, 3809087SZhong.Wang@Sun.COM ddi_ctl_enum_t op, void *clientarg, void *result) 3819087SZhong.Wang@Sun.COM { 3829087SZhong.Wang@Sun.COM int ret; 3839087SZhong.Wang@Sun.COM switch (op) { 3849087SZhong.Wang@Sun.COM case DDI_CTLOPS_REPORTDEV: 3859087SZhong.Wang@Sun.COM case DDI_CTLOPS_IOMIN: 3869087SZhong.Wang@Sun.COM ret = DDI_SUCCESS; 3879087SZhong.Wang@Sun.COM break; 3889087SZhong.Wang@Sun.COM 3899087SZhong.Wang@Sun.COM case DDI_CTLOPS_INITCHILD: 3909087SZhong.Wang@Sun.COM ret = fcoe_initchild(fcoe_dip, (dev_info_t *)clientarg); 3919087SZhong.Wang@Sun.COM break; 3929087SZhong.Wang@Sun.COM 3939087SZhong.Wang@Sun.COM case DDI_CTLOPS_UNINITCHILD: 3949087SZhong.Wang@Sun.COM ret = fcoe_uninitchild(fcoe_dip, (dev_info_t *)clientarg); 3959087SZhong.Wang@Sun.COM break; 3969087SZhong.Wang@Sun.COM 3979087SZhong.Wang@Sun.COM default: 3989087SZhong.Wang@Sun.COM ret = ddi_ctlops(fcoe_dip, rip, op, clientarg, result); 3999087SZhong.Wang@Sun.COM break; 4009087SZhong.Wang@Sun.COM } 4019087SZhong.Wang@Sun.COM 4029087SZhong.Wang@Sun.COM return (ret); 4039087SZhong.Wang@Sun.COM } 4049087SZhong.Wang@Sun.COM 4059087SZhong.Wang@Sun.COM /* 4069087SZhong.Wang@Sun.COM * We need specify the dev address for client driver's instance, or we 4079087SZhong.Wang@Sun.COM * can't online client driver's instance. 4089087SZhong.Wang@Sun.COM */ 4099087SZhong.Wang@Sun.COM /* ARGSUSED */ 4109087SZhong.Wang@Sun.COM static int 4119087SZhong.Wang@Sun.COM fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip) 4129087SZhong.Wang@Sun.COM { 413*10264SZhong.Wang@Sun.COM char client_addr[FCOE_STR_LEN]; 414*10264SZhong.Wang@Sun.COM int rval; 4159087SZhong.Wang@Sun.COM 416*10264SZhong.Wang@Sun.COM rval = ddi_prop_get_int(DDI_DEV_T_ANY, client_dip, 417*10264SZhong.Wang@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1); 418*10264SZhong.Wang@Sun.COM if (rval == -1) { 419*10264SZhong.Wang@Sun.COM FCOE_LOG(__FUNCTION__, "no mac_id property: %p", client_dip); 420*10264SZhong.Wang@Sun.COM return (DDI_FAILURE); 4219087SZhong.Wang@Sun.COM } 4229087SZhong.Wang@Sun.COM 423*10264SZhong.Wang@Sun.COM bzero(client_addr, FCOE_STR_LEN); 424*10264SZhong.Wang@Sun.COM (void) sprintf((char *)client_addr, "%x,0", rval); 425*10264SZhong.Wang@Sun.COM ddi_set_name_addr(client_dip, client_addr); 4269087SZhong.Wang@Sun.COM return (DDI_SUCCESS); 4279087SZhong.Wang@Sun.COM } 4289087SZhong.Wang@Sun.COM 4299087SZhong.Wang@Sun.COM /* ARGSUSED */ 4309087SZhong.Wang@Sun.COM static int 4319087SZhong.Wang@Sun.COM fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip) 4329087SZhong.Wang@Sun.COM { 4339087SZhong.Wang@Sun.COM ddi_set_name_addr(client_dip, NULL); 4349087SZhong.Wang@Sun.COM return (DDI_SUCCESS); 4359087SZhong.Wang@Sun.COM } 4369087SZhong.Wang@Sun.COM 4379087SZhong.Wang@Sun.COM /* 4389087SZhong.Wang@Sun.COM * Device access entry points 4399087SZhong.Wang@Sun.COM */ 4409087SZhong.Wang@Sun.COM static int 4419087SZhong.Wang@Sun.COM fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp) 4429087SZhong.Wang@Sun.COM { 4439087SZhong.Wang@Sun.COM int instance; 4449087SZhong.Wang@Sun.COM fcoe_soft_state_t *ss; 4459087SZhong.Wang@Sun.COM 4469087SZhong.Wang@Sun.COM if (otype != OTYP_CHR) { 4479087SZhong.Wang@Sun.COM return (EINVAL); 4489087SZhong.Wang@Sun.COM } 4499087SZhong.Wang@Sun.COM 4509087SZhong.Wang@Sun.COM /* 4519087SZhong.Wang@Sun.COM * Since this is for debugging only, only allow root to issue ioctl now 4529087SZhong.Wang@Sun.COM */ 4539087SZhong.Wang@Sun.COM if (drv_priv(credp) != 0) { 4549087SZhong.Wang@Sun.COM return (EPERM); 4559087SZhong.Wang@Sun.COM } 4569087SZhong.Wang@Sun.COM 4579087SZhong.Wang@Sun.COM instance = (int)getminor(*devp); 4589087SZhong.Wang@Sun.COM ss = ddi_get_soft_state(fcoe_state, instance); 4599087SZhong.Wang@Sun.COM if (ss == NULL) { 4609087SZhong.Wang@Sun.COM return (ENXIO); 4619087SZhong.Wang@Sun.COM } 4629087SZhong.Wang@Sun.COM 4639087SZhong.Wang@Sun.COM mutex_enter(&ss->ss_ioctl_mutex); 4649087SZhong.Wang@Sun.COM if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) { 4659087SZhong.Wang@Sun.COM /* 4669087SZhong.Wang@Sun.COM * It is already open for exclusive access. 4679087SZhong.Wang@Sun.COM * So shut the door on this caller. 4689087SZhong.Wang@Sun.COM */ 4699087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 4709087SZhong.Wang@Sun.COM return (EBUSY); 4719087SZhong.Wang@Sun.COM } 4729087SZhong.Wang@Sun.COM 4739087SZhong.Wang@Sun.COM if (flag & FEXCL) { 4749087SZhong.Wang@Sun.COM if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) { 4759087SZhong.Wang@Sun.COM /* 4769087SZhong.Wang@Sun.COM * Exclusive operation not possible 4779087SZhong.Wang@Sun.COM * as it is already opened 4789087SZhong.Wang@Sun.COM */ 4799087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 4809087SZhong.Wang@Sun.COM return (EBUSY); 4819087SZhong.Wang@Sun.COM } 4829087SZhong.Wang@Sun.COM ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL; 4839087SZhong.Wang@Sun.COM } 4849087SZhong.Wang@Sun.COM 4859087SZhong.Wang@Sun.COM ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_OPEN; 4869087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 4879087SZhong.Wang@Sun.COM 4889087SZhong.Wang@Sun.COM return (0); 4899087SZhong.Wang@Sun.COM } 4909087SZhong.Wang@Sun.COM 4919087SZhong.Wang@Sun.COM /* ARGSUSED */ 4929087SZhong.Wang@Sun.COM static int 4939087SZhong.Wang@Sun.COM fcoe_close(dev_t dev, int flag, int otype, cred_t *credp) 4949087SZhong.Wang@Sun.COM { 4959087SZhong.Wang@Sun.COM int instance; 4969087SZhong.Wang@Sun.COM fcoe_soft_state_t *ss; 4979087SZhong.Wang@Sun.COM 4989087SZhong.Wang@Sun.COM if (otype != OTYP_CHR) { 4999087SZhong.Wang@Sun.COM return (EINVAL); 5009087SZhong.Wang@Sun.COM } 5019087SZhong.Wang@Sun.COM 5029087SZhong.Wang@Sun.COM instance = (int)getminor(dev); 5039087SZhong.Wang@Sun.COM ss = ddi_get_soft_state(fcoe_state, instance); 5049087SZhong.Wang@Sun.COM if (ss == NULL) { 5059087SZhong.Wang@Sun.COM return (ENXIO); 5069087SZhong.Wang@Sun.COM } 5079087SZhong.Wang@Sun.COM 5089087SZhong.Wang@Sun.COM mutex_enter(&ss->ss_ioctl_mutex); 5099087SZhong.Wang@Sun.COM if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) { 5109087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 5119087SZhong.Wang@Sun.COM return (ENODEV); 5129087SZhong.Wang@Sun.COM } 5139087SZhong.Wang@Sun.COM 5149087SZhong.Wang@Sun.COM ss->ss_ioctl_flags &= ~FCOE_IOCTL_FLAG_MASK; 5159087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 5169087SZhong.Wang@Sun.COM 5179087SZhong.Wang@Sun.COM return (0); 5189087SZhong.Wang@Sun.COM } 5199087SZhong.Wang@Sun.COM 5209087SZhong.Wang@Sun.COM /* ARGSUSED */ 5219087SZhong.Wang@Sun.COM static int 5229087SZhong.Wang@Sun.COM fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 5239087SZhong.Wang@Sun.COM cred_t *credp, int *rval) 5249087SZhong.Wang@Sun.COM { 5259087SZhong.Wang@Sun.COM fcoe_soft_state_t *ss; 5269087SZhong.Wang@Sun.COM int ret = 0; 5279087SZhong.Wang@Sun.COM 5289087SZhong.Wang@Sun.COM if (drv_priv(credp) != 0) { 5299087SZhong.Wang@Sun.COM return (EPERM); 5309087SZhong.Wang@Sun.COM } 5319087SZhong.Wang@Sun.COM 5329087SZhong.Wang@Sun.COM ss = ddi_get_soft_state(fcoe_state, (int32_t)getminor(dev)); 5339087SZhong.Wang@Sun.COM if (ss == NULL) { 5349087SZhong.Wang@Sun.COM return (ENXIO); 5359087SZhong.Wang@Sun.COM } 5369087SZhong.Wang@Sun.COM 5379087SZhong.Wang@Sun.COM mutex_enter(&ss->ss_ioctl_mutex); 5389087SZhong.Wang@Sun.COM if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) { 5399087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 5409087SZhong.Wang@Sun.COM return (ENXIO); 5419087SZhong.Wang@Sun.COM } 5429087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 5439087SZhong.Wang@Sun.COM 5449087SZhong.Wang@Sun.COM switch (cmd) { 5459087SZhong.Wang@Sun.COM case FCOEIO_CMD: 5469087SZhong.Wang@Sun.COM ret = fcoe_iocmd(ss, data, mode); 5479087SZhong.Wang@Sun.COM break; 5489087SZhong.Wang@Sun.COM default: 5499087SZhong.Wang@Sun.COM FCOE_LOG(0, "fcoe_ioctl: ioctl-0x%02X", cmd); 5509087SZhong.Wang@Sun.COM ret = ENOTTY; 5519087SZhong.Wang@Sun.COM break; 5529087SZhong.Wang@Sun.COM } 5539087SZhong.Wang@Sun.COM 5549087SZhong.Wang@Sun.COM return (ret); 5559087SZhong.Wang@Sun.COM } 5569087SZhong.Wang@Sun.COM 5579087SZhong.Wang@Sun.COM static int 5589087SZhong.Wang@Sun.COM fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio, 5599087SZhong.Wang@Sun.COM void **ibuf, void **abuf, void **obuf) 5609087SZhong.Wang@Sun.COM { 5619087SZhong.Wang@Sun.COM int ret = 0; 5629087SZhong.Wang@Sun.COM 5639087SZhong.Wang@Sun.COM *ibuf = NULL; 5649087SZhong.Wang@Sun.COM *abuf = NULL; 5659087SZhong.Wang@Sun.COM *obuf = NULL; 5669087SZhong.Wang@Sun.COM *fcoeio = kmem_zalloc(sizeof (fcoeio_t), KM_SLEEP); 5679087SZhong.Wang@Sun.COM if (ddi_copyin((void *)data, *fcoeio, sizeof (fcoeio_t), mode) != 0) { 5689087SZhong.Wang@Sun.COM ret = EFAULT; 5699087SZhong.Wang@Sun.COM goto copyin_iocdata_fail; 5709087SZhong.Wang@Sun.COM } 5719087SZhong.Wang@Sun.COM 5729087SZhong.Wang@Sun.COM if ((*fcoeio)->fcoeio_ilen > FCOEIO_MAX_BUF_LEN || 5739087SZhong.Wang@Sun.COM (*fcoeio)->fcoeio_alen > FCOEIO_MAX_BUF_LEN || 5749087SZhong.Wang@Sun.COM (*fcoeio)->fcoeio_olen > FCOEIO_MAX_BUF_LEN) { 5759087SZhong.Wang@Sun.COM ret = EFAULT; 5769087SZhong.Wang@Sun.COM goto copyin_iocdata_fail; 5779087SZhong.Wang@Sun.COM } 5789087SZhong.Wang@Sun.COM 5799087SZhong.Wang@Sun.COM if ((*fcoeio)->fcoeio_ilen) { 5809087SZhong.Wang@Sun.COM *ibuf = kmem_zalloc((*fcoeio)->fcoeio_ilen, KM_SLEEP); 5819087SZhong.Wang@Sun.COM if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_ibuf, 5829087SZhong.Wang@Sun.COM *ibuf, (*fcoeio)->fcoeio_ilen, mode) != 0) { 5839087SZhong.Wang@Sun.COM ret = EFAULT; 5849087SZhong.Wang@Sun.COM goto copyin_iocdata_fail; 5859087SZhong.Wang@Sun.COM } 5869087SZhong.Wang@Sun.COM } 5879087SZhong.Wang@Sun.COM 5889087SZhong.Wang@Sun.COM if ((*fcoeio)->fcoeio_alen) { 5899087SZhong.Wang@Sun.COM *abuf = kmem_zalloc((*fcoeio)->fcoeio_alen, KM_SLEEP); 5909087SZhong.Wang@Sun.COM if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_abuf, 5919087SZhong.Wang@Sun.COM *abuf, (*fcoeio)->fcoeio_alen, mode) != 0) { 5929087SZhong.Wang@Sun.COM ret = EFAULT; 5939087SZhong.Wang@Sun.COM goto copyin_iocdata_fail; 5949087SZhong.Wang@Sun.COM } 5959087SZhong.Wang@Sun.COM } 5969087SZhong.Wang@Sun.COM 5979087SZhong.Wang@Sun.COM if ((*fcoeio)->fcoeio_olen) { 5989087SZhong.Wang@Sun.COM *obuf = kmem_zalloc((*fcoeio)->fcoeio_olen, KM_SLEEP); 5999087SZhong.Wang@Sun.COM } 6009087SZhong.Wang@Sun.COM return (ret); 6019087SZhong.Wang@Sun.COM 6029087SZhong.Wang@Sun.COM copyin_iocdata_fail: 6039087SZhong.Wang@Sun.COM if (*abuf) { 6049087SZhong.Wang@Sun.COM kmem_free(*abuf, (*fcoeio)->fcoeio_alen); 6059087SZhong.Wang@Sun.COM *abuf = NULL; 6069087SZhong.Wang@Sun.COM } 6079087SZhong.Wang@Sun.COM 6089087SZhong.Wang@Sun.COM if (*ibuf) { 6099087SZhong.Wang@Sun.COM kmem_free(*ibuf, (*fcoeio)->fcoeio_ilen); 6109087SZhong.Wang@Sun.COM *ibuf = NULL; 6119087SZhong.Wang@Sun.COM } 6129087SZhong.Wang@Sun.COM 6139087SZhong.Wang@Sun.COM kmem_free(*fcoeio, sizeof (fcoeio_t)); 6149087SZhong.Wang@Sun.COM return (ret); 6159087SZhong.Wang@Sun.COM } 6169087SZhong.Wang@Sun.COM 6179087SZhong.Wang@Sun.COM static int 6189087SZhong.Wang@Sun.COM fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio, void *obuf) 6199087SZhong.Wang@Sun.COM { 6209087SZhong.Wang@Sun.COM if (fcoeio->fcoeio_olen) { 6219087SZhong.Wang@Sun.COM if (ddi_copyout(obuf, 6229087SZhong.Wang@Sun.COM (void *)(unsigned long)fcoeio->fcoeio_obuf, 6239087SZhong.Wang@Sun.COM fcoeio->fcoeio_olen, mode) != 0) { 6249087SZhong.Wang@Sun.COM return (EFAULT); 6259087SZhong.Wang@Sun.COM } 6269087SZhong.Wang@Sun.COM } 6279087SZhong.Wang@Sun.COM 6289087SZhong.Wang@Sun.COM if (ddi_copyout(fcoeio, (void *)data, sizeof (fcoeio_t), mode) != 0) { 6299087SZhong.Wang@Sun.COM return (EFAULT); 6309087SZhong.Wang@Sun.COM } 6319087SZhong.Wang@Sun.COM return (0); 6329087SZhong.Wang@Sun.COM } 6339087SZhong.Wang@Sun.COM 6349087SZhong.Wang@Sun.COM static int 6359087SZhong.Wang@Sun.COM fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode) 6369087SZhong.Wang@Sun.COM { 6379087SZhong.Wang@Sun.COM int ret; 6389087SZhong.Wang@Sun.COM fcoe_mac_t *fcoe_mac; 6399087SZhong.Wang@Sun.COM void *ibuf = NULL; 6409087SZhong.Wang@Sun.COM void *obuf = NULL; 6419087SZhong.Wang@Sun.COM void *abuf = NULL; 6429087SZhong.Wang@Sun.COM fcoeio_t *fcoeio; 6439087SZhong.Wang@Sun.COM 6449087SZhong.Wang@Sun.COM ret = fcoe_copyin_iocdata(data, mode, &fcoeio, &ibuf, &abuf, &obuf); 6459087SZhong.Wang@Sun.COM if (ret != 0) { 6469087SZhong.Wang@Sun.COM goto fcoeiocmd_release_buf; 6479087SZhong.Wang@Sun.COM } 6489087SZhong.Wang@Sun.COM 6499087SZhong.Wang@Sun.COM /* 6509087SZhong.Wang@Sun.COM * If an exclusive open was demanded during open, ensure that 6519087SZhong.Wang@Sun.COM * only one thread can execute an ioctl at a time 6529087SZhong.Wang@Sun.COM */ 6539087SZhong.Wang@Sun.COM mutex_enter(&ss->ss_ioctl_mutex); 6549087SZhong.Wang@Sun.COM if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) { 6559087SZhong.Wang@Sun.COM if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL_BUSY) { 6569087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 6579087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_BUSY; 6589087SZhong.Wang@Sun.COM ret = EBUSY; 6599087SZhong.Wang@Sun.COM goto fcoeiocmd_release_buf; 6609087SZhong.Wang@Sun.COM } 6619087SZhong.Wang@Sun.COM ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL_BUSY; 6629087SZhong.Wang@Sun.COM } 6639087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 6649087SZhong.Wang@Sun.COM 6659087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = 0; 6669087SZhong.Wang@Sun.COM 6679087SZhong.Wang@Sun.COM switch (fcoeio->fcoeio_cmd) { 6689087SZhong.Wang@Sun.COM case FCOEIO_CREATE_FCOE_PORT: { 6699087SZhong.Wang@Sun.COM fcoeio_create_port_param_t *param = 6709087SZhong.Wang@Sun.COM (fcoeio_create_port_param_t *)ibuf; 6719087SZhong.Wang@Sun.COM int cmpwwn = 0; 6729087SZhong.Wang@Sun.COM fcoe_port_t *eport; 6739087SZhong.Wang@Sun.COM 6749087SZhong.Wang@Sun.COM if (fcoeio->fcoeio_ilen != 6759087SZhong.Wang@Sun.COM sizeof (fcoeio_create_port_param_t) || 6769087SZhong.Wang@Sun.COM fcoeio->fcoeio_xfer != FCOEIO_XFER_WRITE) { 6779087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG; 6789087SZhong.Wang@Sun.COM ret = EINVAL; 6799087SZhong.Wang@Sun.COM break; 6809087SZhong.Wang@Sun.COM } 6819087SZhong.Wang@Sun.COM 6829087SZhong.Wang@Sun.COM mutex_enter(&ss->ss_ioctl_mutex); 6839307Skelly.hu@Sun.COM fcoe_mac = fcoe_create_mac_by_id(param->fcp_mac_linkid); 6849087SZhong.Wang@Sun.COM if (fcoe_mac == NULL) { 6859087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 6869087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_CREATE_MAC; 6879087SZhong.Wang@Sun.COM ret = EIO; 6889087SZhong.Wang@Sun.COM break; 6899087SZhong.Wang@Sun.COM } 6909087SZhong.Wang@Sun.COM 6919087SZhong.Wang@Sun.COM if (fcoe_mac->fm_flags & FCOE_MAC_FLAG_ENABLED) { 6929087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 6939087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_ALREADY; 6949087SZhong.Wang@Sun.COM ret = EALREADY; 6959087SZhong.Wang@Sun.COM break; 6969087SZhong.Wang@Sun.COM } else { 6979087SZhong.Wang@Sun.COM ret = fcoe_open_mac(fcoe_mac, param->fcp_force_promisc, 6989087SZhong.Wang@Sun.COM &fcoeio->fcoeio_status); 6999087SZhong.Wang@Sun.COM if (ret != 0) { 7009087SZhong.Wang@Sun.COM fcoe_destroy_mac(fcoe_mac); 7019087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 7029087SZhong.Wang@Sun.COM if (fcoeio->fcoeio_status == 0) { 7039087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = 7049087SZhong.Wang@Sun.COM FCOEIOE_OPEN_MAC; 7059087SZhong.Wang@Sun.COM } 7069087SZhong.Wang@Sun.COM ret = EIO; 7079087SZhong.Wang@Sun.COM break; 7089087SZhong.Wang@Sun.COM } else { 7099087SZhong.Wang@Sun.COM fcoe_mac->fm_flags |= FCOE_MAC_FLAG_ENABLED; 7109087SZhong.Wang@Sun.COM } 7119087SZhong.Wang@Sun.COM } 7129087SZhong.Wang@Sun.COM 7139087SZhong.Wang@Sun.COM /* 7149087SZhong.Wang@Sun.COM * Provide PWWN and NWWN based on mac address 7159087SZhong.Wang@Sun.COM */ 7169087SZhong.Wang@Sun.COM eport = &fcoe_mac->fm_eport; 7179087SZhong.Wang@Sun.COM if (!param->fcp_pwwn_provided) { 7189087SZhong.Wang@Sun.COM fcoe_init_wwn_from_mac(eport->eport_portwwn, 7199087SZhong.Wang@Sun.COM fcoe_mac->fm_current_addr, 1, 0); 7209087SZhong.Wang@Sun.COM } else { 7219087SZhong.Wang@Sun.COM (void) memcpy(eport->eport_portwwn, param->fcp_pwwn, 8); 7229087SZhong.Wang@Sun.COM } 7239087SZhong.Wang@Sun.COM 7249087SZhong.Wang@Sun.COM if (!param->fcp_nwwn_provided) { 7259087SZhong.Wang@Sun.COM fcoe_init_wwn_from_mac(eport->eport_nodewwn, 7269087SZhong.Wang@Sun.COM fcoe_mac->fm_current_addr, 0, 0); 7279087SZhong.Wang@Sun.COM } else { 7289087SZhong.Wang@Sun.COM (void) memcpy(eport->eport_nodewwn, param->fcp_nwwn, 8); 7299087SZhong.Wang@Sun.COM } 7309087SZhong.Wang@Sun.COM 7319087SZhong.Wang@Sun.COM cmpwwn = fcoe_cmp_wwn(fcoe_mac); 7329087SZhong.Wang@Sun.COM 7339087SZhong.Wang@Sun.COM if (cmpwwn != 0) { 7349087SZhong.Wang@Sun.COM if (cmpwwn == 1) { 7359087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_PWWN_CONFLICTED; 7369087SZhong.Wang@Sun.COM } else if (cmpwwn == -1) { 7379087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_NWWN_CONFLICTED; 7389087SZhong.Wang@Sun.COM } 7399087SZhong.Wang@Sun.COM (void) fcoe_close_mac(fcoe_mac); 7409087SZhong.Wang@Sun.COM fcoe_destroy_mac(fcoe_mac); 7419087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 7429087SZhong.Wang@Sun.COM ret = ENOTUNIQ; 7439087SZhong.Wang@Sun.COM break; 7449087SZhong.Wang@Sun.COM } 7459087SZhong.Wang@Sun.COM 7469087SZhong.Wang@Sun.COM if (ret == 0) { 7479087SZhong.Wang@Sun.COM ret = fcoe_create_port(ss->ss_dip, 7489087SZhong.Wang@Sun.COM fcoe_mac, 7499087SZhong.Wang@Sun.COM (param->fcp_port_type == FCOE_CLIENT_TARGET)); 7509087SZhong.Wang@Sun.COM if (ret != 0) { 7519087SZhong.Wang@Sun.COM (void) fcoe_close_mac(fcoe_mac); 7529087SZhong.Wang@Sun.COM fcoe_destroy_mac(fcoe_mac); 7539087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_CREATE_PORT; 7549087SZhong.Wang@Sun.COM ret = EIO; 7559087SZhong.Wang@Sun.COM } 7569087SZhong.Wang@Sun.COM } 7579087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 7589087SZhong.Wang@Sun.COM 7599087SZhong.Wang@Sun.COM break; 7609087SZhong.Wang@Sun.COM } 7619087SZhong.Wang@Sun.COM 7629087SZhong.Wang@Sun.COM case FCOEIO_DELETE_FCOE_PORT: { 7639307Skelly.hu@Sun.COM fcoeio_delete_port_param_t *del_port_param = 7649307Skelly.hu@Sun.COM (fcoeio_delete_port_param_t *)ibuf; 7659895SKevin.Yu@Sun.COM uint64_t *is_target = (uint64_t *)obuf; 7669087SZhong.Wang@Sun.COM 7679307Skelly.hu@Sun.COM if (fcoeio->fcoeio_ilen < sizeof (fcoeio_delete_port_param_t) || 7689895SKevin.Yu@Sun.COM fcoeio->fcoeio_olen != sizeof (uint64_t) || 7699895SKevin.Yu@Sun.COM fcoeio->fcoeio_xfer != FCOEIO_XFER_RW) { 7709087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG; 7719087SZhong.Wang@Sun.COM ret = EINVAL; 7729087SZhong.Wang@Sun.COM break; 7739087SZhong.Wang@Sun.COM } 7749087SZhong.Wang@Sun.COM 7759087SZhong.Wang@Sun.COM mutex_enter(&ss->ss_ioctl_mutex); 7769307Skelly.hu@Sun.COM ret = fcoe_delete_port(ss->ss_dip, fcoeio, 7779895SKevin.Yu@Sun.COM del_port_param->fdp_mac_linkid, is_target); 7789087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 779*10264SZhong.Wang@Sun.COM FCOE_LOG("fcoe", "fcoe_delete_port %x return: %d", 780*10264SZhong.Wang@Sun.COM del_port_param->fdp_mac_linkid, ret); 7819087SZhong.Wang@Sun.COM break; 7829087SZhong.Wang@Sun.COM } 7839087SZhong.Wang@Sun.COM 7849087SZhong.Wang@Sun.COM case FCOEIO_GET_FCOE_PORT_LIST: { 7859087SZhong.Wang@Sun.COM fcoe_port_list_t *list = (fcoe_port_list_t *)obuf; 7869087SZhong.Wang@Sun.COM int count; 7879087SZhong.Wang@Sun.COM 7889087SZhong.Wang@Sun.COM if (fcoeio->fcoeio_xfer != FCOEIO_XFER_READ || 7899087SZhong.Wang@Sun.COM fcoeio->fcoeio_olen < sizeof (fcoe_port_list_t)) { 7909087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG; 7919087SZhong.Wang@Sun.COM ret = EINVAL; 7929087SZhong.Wang@Sun.COM break; 7939087SZhong.Wang@Sun.COM } 7949087SZhong.Wang@Sun.COM mutex_enter(&ss->ss_ioctl_mutex); 7959087SZhong.Wang@Sun.COM 7969087SZhong.Wang@Sun.COM list->numPorts = 1 + (fcoeio->fcoeio_olen - 7979087SZhong.Wang@Sun.COM sizeof (fcoe_port_list_t))/sizeof (fcoe_port_instance_t); 7989087SZhong.Wang@Sun.COM 7999087SZhong.Wang@Sun.COM count = fcoe_get_port_list(list->ports, list->numPorts); 8009087SZhong.Wang@Sun.COM 8019087SZhong.Wang@Sun.COM if (count > list->numPorts) { 8029087SZhong.Wang@Sun.COM fcoeio->fcoeio_status = FCOEIOE_MORE_DATA; 8039087SZhong.Wang@Sun.COM ret = ENOSPC; 8049087SZhong.Wang@Sun.COM } 8059087SZhong.Wang@Sun.COM list->numPorts = count; 8069087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_ioctl_mutex); 8079087SZhong.Wang@Sun.COM 8089087SZhong.Wang@Sun.COM break; 8099087SZhong.Wang@Sun.COM 8109087SZhong.Wang@Sun.COM } 8119087SZhong.Wang@Sun.COM 8129087SZhong.Wang@Sun.COM default: 8139087SZhong.Wang@Sun.COM return (ENOTTY); 8149087SZhong.Wang@Sun.COM } 8159087SZhong.Wang@Sun.COM 816*10264SZhong.Wang@Sun.COM FCOE_LOG("fcoe", "fcoe_ioctl %x returned %d, fcoeio_status = %d", 817*10264SZhong.Wang@Sun.COM fcoeio->fcoeio_cmd, ret, fcoeio->fcoeio_status); 8189087SZhong.Wang@Sun.COM 8199087SZhong.Wang@Sun.COM fcoeiocmd_release_buf: 8209087SZhong.Wang@Sun.COM if (ret == 0) { 8219087SZhong.Wang@Sun.COM ret = fcoe_copyout_iocdata(data, mode, fcoeio, obuf); 8229087SZhong.Wang@Sun.COM } else if (fcoeio->fcoeio_status) { 8239087SZhong.Wang@Sun.COM (void) fcoe_copyout_iocdata(data, mode, fcoeio, obuf); 8249087SZhong.Wang@Sun.COM } 8259087SZhong.Wang@Sun.COM 8269087SZhong.Wang@Sun.COM if (obuf != NULL) { 8279087SZhong.Wang@Sun.COM kmem_free(obuf, fcoeio->fcoeio_olen); 8289087SZhong.Wang@Sun.COM obuf = NULL; 8299087SZhong.Wang@Sun.COM } 8309087SZhong.Wang@Sun.COM if (abuf != NULL) { 8319087SZhong.Wang@Sun.COM kmem_free(abuf, fcoeio->fcoeio_alen); 8329087SZhong.Wang@Sun.COM abuf = NULL; 8339087SZhong.Wang@Sun.COM } 8349087SZhong.Wang@Sun.COM 8359087SZhong.Wang@Sun.COM if (ibuf != NULL) { 8369087SZhong.Wang@Sun.COM kmem_free(ibuf, fcoeio->fcoeio_ilen); 8379087SZhong.Wang@Sun.COM ibuf = NULL; 8389087SZhong.Wang@Sun.COM } 8399087SZhong.Wang@Sun.COM kmem_free(fcoeio, sizeof (fcoeio_t)); 8409087SZhong.Wang@Sun.COM 8419087SZhong.Wang@Sun.COM return (ret); 8429087SZhong.Wang@Sun.COM } 8439087SZhong.Wang@Sun.COM 8449087SZhong.Wang@Sun.COM /* 8459087SZhong.Wang@Sun.COM * Finish final initialization 8469087SZhong.Wang@Sun.COM */ 8479087SZhong.Wang@Sun.COM static int 8489087SZhong.Wang@Sun.COM fcoe_attach_init(fcoe_soft_state_t *ss) 8499087SZhong.Wang@Sun.COM { 8509087SZhong.Wang@Sun.COM char taskq_name[TASKQ_NAME_LEN]; 8519087SZhong.Wang@Sun.COM 8529087SZhong.Wang@Sun.COM if (ddi_create_minor_node(ss->ss_dip, "admin", S_IFCHR, 8539087SZhong.Wang@Sun.COM ddi_get_instance(ss->ss_dip), DDI_PSEUDO, 0) != DDI_SUCCESS) { 8549087SZhong.Wang@Sun.COM FCOE_LOG("FCOE", "ddi_create_minor_node failed"); 8559087SZhong.Wang@Sun.COM return (FCOE_FAILURE); 8569087SZhong.Wang@Sun.COM } 8579087SZhong.Wang@Sun.COM 8589087SZhong.Wang@Sun.COM /* 8599087SZhong.Wang@Sun.COM * watchdog responsible for release frame and dispatch events 8609087SZhong.Wang@Sun.COM */ 8619087SZhong.Wang@Sun.COM (void) snprintf(taskq_name, sizeof (taskq_name), "fcoe_mac"); 8629087SZhong.Wang@Sun.COM taskq_name[TASKQ_NAME_LEN - 1] = 0; 8639087SZhong.Wang@Sun.COM if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL, 8649087SZhong.Wang@Sun.COM taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) { 8659087SZhong.Wang@Sun.COM return (FCOE_FAILURE); 8669087SZhong.Wang@Sun.COM } 8679087SZhong.Wang@Sun.COM 8689087SZhong.Wang@Sun.COM ss->ss_ioctl_flags = 0; 8699087SZhong.Wang@Sun.COM mutex_init(&ss->ss_ioctl_mutex, NULL, MUTEX_DRIVER, NULL); 8709087SZhong.Wang@Sun.COM list_create(&ss->ss_mac_list, sizeof (fcoe_mac_t), 8719087SZhong.Wang@Sun.COM offsetof(fcoe_mac_t, fm_ss_node)); 8729087SZhong.Wang@Sun.COM list_create(&ss->ss_pfrm_list, sizeof (fcoe_i_frame_t), 8739087SZhong.Wang@Sun.COM offsetof(fcoe_i_frame_t, fmi_pending_node)); 8749087SZhong.Wang@Sun.COM 8759087SZhong.Wang@Sun.COM mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0); 8769087SZhong.Wang@Sun.COM cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL); 8779087SZhong.Wang@Sun.COM ss->ss_flags &= ~SS_FLAG_TERMINATE_WATCHDOG; 8789087SZhong.Wang@Sun.COM (void) ddi_taskq_dispatch(ss->ss_watchdog_taskq, 8799087SZhong.Wang@Sun.COM fcoe_watchdog, ss, DDI_SLEEP); 8809087SZhong.Wang@Sun.COM while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) { 8819087SZhong.Wang@Sun.COM delay(10); 8829087SZhong.Wang@Sun.COM } 8839087SZhong.Wang@Sun.COM fcoe_nworkers = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip, 8849087SZhong.Wang@Sun.COM DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, (char *)fcoe_workers_num, 4); 8859087SZhong.Wang@Sun.COM if (fcoe_nworkers < 1) { 8869087SZhong.Wang@Sun.COM fcoe_nworkers = 4; 8879087SZhong.Wang@Sun.COM } 8889087SZhong.Wang@Sun.COM fcoe_worker_init(); 8899087SZhong.Wang@Sun.COM 8909087SZhong.Wang@Sun.COM ddi_report_dev(ss->ss_dip); 8919087SZhong.Wang@Sun.COM return (FCOE_SUCCESS); 8929087SZhong.Wang@Sun.COM } 8939087SZhong.Wang@Sun.COM 8949087SZhong.Wang@Sun.COM /* 8959087SZhong.Wang@Sun.COM * Finish final uninitialization 8969087SZhong.Wang@Sun.COM */ 8979087SZhong.Wang@Sun.COM static int 8989087SZhong.Wang@Sun.COM fcoe_detach_uninit(fcoe_soft_state_t *ss) 8999087SZhong.Wang@Sun.COM { 9009087SZhong.Wang@Sun.COM int ret; 9019087SZhong.Wang@Sun.COM if (!list_is_empty(&ss->ss_mac_list)) { 9029087SZhong.Wang@Sun.COM FCOE_LOG("fcoe", "ss_mac_list is not empty when detach"); 9039087SZhong.Wang@Sun.COM return (FCOE_FAILURE); 9049087SZhong.Wang@Sun.COM } 9059087SZhong.Wang@Sun.COM 9069087SZhong.Wang@Sun.COM if ((ret = fcoe_worker_fini()) != FCOE_SUCCESS) { 9079087SZhong.Wang@Sun.COM return (ret); 9089087SZhong.Wang@Sun.COM } 9099087SZhong.Wang@Sun.COM 9109087SZhong.Wang@Sun.COM /* 9119087SZhong.Wang@Sun.COM * Stop watchdog 9129087SZhong.Wang@Sun.COM */ 9139087SZhong.Wang@Sun.COM if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 9149087SZhong.Wang@Sun.COM mutex_enter(&ss->ss_watch_mutex); 9159087SZhong.Wang@Sun.COM ss->ss_flags |= SS_FLAG_TERMINATE_WATCHDOG; 9169087SZhong.Wang@Sun.COM cv_broadcast(&ss->ss_watch_cv); 9179087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_watch_mutex); 9189087SZhong.Wang@Sun.COM while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 9199087SZhong.Wang@Sun.COM delay(10); 9209087SZhong.Wang@Sun.COM } 9219087SZhong.Wang@Sun.COM } 9229087SZhong.Wang@Sun.COM 9239087SZhong.Wang@Sun.COM ddi_taskq_destroy(ss->ss_watchdog_taskq); 9249087SZhong.Wang@Sun.COM mutex_destroy(&ss->ss_watch_mutex); 9259087SZhong.Wang@Sun.COM cv_destroy(&ss->ss_watch_cv); 9269087SZhong.Wang@Sun.COM 9279087SZhong.Wang@Sun.COM ddi_remove_minor_node(ss->ss_dip, NULL); 9289087SZhong.Wang@Sun.COM mutex_destroy(&ss->ss_ioctl_mutex); 9299087SZhong.Wang@Sun.COM list_destroy(&ss->ss_mac_list); 9309087SZhong.Wang@Sun.COM 9319087SZhong.Wang@Sun.COM return (FCOE_SUCCESS); 9329087SZhong.Wang@Sun.COM } 9339087SZhong.Wang@Sun.COM 9349087SZhong.Wang@Sun.COM /* 9359087SZhong.Wang@Sun.COM * Return mac instance if it exist, or else return NULL. 9369087SZhong.Wang@Sun.COM */ 9379087SZhong.Wang@Sun.COM fcoe_mac_t * 9389307Skelly.hu@Sun.COM fcoe_lookup_mac_by_id(datalink_id_t linkid) 9399087SZhong.Wang@Sun.COM { 9409087SZhong.Wang@Sun.COM fcoe_mac_t *mac = NULL; 9419087SZhong.Wang@Sun.COM 9429307Skelly.hu@Sun.COM ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 9439087SZhong.Wang@Sun.COM for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; 9449087SZhong.Wang@Sun.COM mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { 9459307Skelly.hu@Sun.COM if (linkid != mac->fm_linkid) { 9469087SZhong.Wang@Sun.COM continue; 9479087SZhong.Wang@Sun.COM } 9489087SZhong.Wang@Sun.COM return (mac); 9499087SZhong.Wang@Sun.COM } 9509087SZhong.Wang@Sun.COM return (NULL); 9519087SZhong.Wang@Sun.COM } 9529087SZhong.Wang@Sun.COM 9539087SZhong.Wang@Sun.COM /* 9549087SZhong.Wang@Sun.COM * port wwn will start with 20:..., node wwn will start with 10:... 9559087SZhong.Wang@Sun.COM */ 9569087SZhong.Wang@Sun.COM static void 9579087SZhong.Wang@Sun.COM fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac, int is_pwwn, uint8_t idx) 9589087SZhong.Wang@Sun.COM { 9599087SZhong.Wang@Sun.COM ASSERT(wwn != NULL); 9609087SZhong.Wang@Sun.COM ASSERT(mac != NULL); 9619087SZhong.Wang@Sun.COM wwn[0] = (is_pwwn + 1) << 4; 9629087SZhong.Wang@Sun.COM wwn[1] = idx; 9639087SZhong.Wang@Sun.COM bcopy(mac, wwn + 2, ETHERADDRL); 9649087SZhong.Wang@Sun.COM } 9659087SZhong.Wang@Sun.COM 9669087SZhong.Wang@Sun.COM /* 9679087SZhong.Wang@Sun.COM * Return fcoe_mac if it exists, otherwise create a new one 9689087SZhong.Wang@Sun.COM */ 9699087SZhong.Wang@Sun.COM static fcoe_mac_t * 9709307Skelly.hu@Sun.COM fcoe_create_mac_by_id(datalink_id_t linkid) 9719087SZhong.Wang@Sun.COM { 9729087SZhong.Wang@Sun.COM fcoe_mac_t *mac = NULL; 9739307Skelly.hu@Sun.COM ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 9749087SZhong.Wang@Sun.COM 9759307Skelly.hu@Sun.COM mac = fcoe_lookup_mac_by_id(linkid); 9769087SZhong.Wang@Sun.COM if (mac != NULL) { 9779307Skelly.hu@Sun.COM FCOE_LOG("fcoe", "fcoe_create_mac_by_id found one mac %d", 9789307Skelly.hu@Sun.COM linkid); 9799087SZhong.Wang@Sun.COM return (mac); 9809087SZhong.Wang@Sun.COM } 9819087SZhong.Wang@Sun.COM 9829087SZhong.Wang@Sun.COM mac = kmem_zalloc(sizeof (fcoe_mac_t), KM_SLEEP); 9839307Skelly.hu@Sun.COM mac->fm_linkid = linkid; 9849087SZhong.Wang@Sun.COM mac->fm_flags = 0; 9859087SZhong.Wang@Sun.COM mac->fm_ss = fcoe_global_ss; 9869087SZhong.Wang@Sun.COM list_insert_tail(&mac->fm_ss->ss_mac_list, mac); 9879307Skelly.hu@Sun.COM FCOE_LOG("fcoe", "fcoe_create_mac_by_id created one mac %d", linkid); 9889087SZhong.Wang@Sun.COM return (mac); 9899087SZhong.Wang@Sun.COM } 9909087SZhong.Wang@Sun.COM 9919087SZhong.Wang@Sun.COM void 9929087SZhong.Wang@Sun.COM fcoe_destroy_mac(fcoe_mac_t *mac) 9939087SZhong.Wang@Sun.COM { 9949087SZhong.Wang@Sun.COM ASSERT(mac != NULL); 9959087SZhong.Wang@Sun.COM list_remove(&mac->fm_ss->ss_mac_list, mac); 9969087SZhong.Wang@Sun.COM kmem_free(mac, sizeof (fcoe_mac_t)); 9979087SZhong.Wang@Sun.COM } 9989087SZhong.Wang@Sun.COM 9999087SZhong.Wang@Sun.COM /* 10009087SZhong.Wang@Sun.COM * raw frame layout: 10019087SZhong.Wang@Sun.COM * ethernet header + vlan header (optional) + FCoE header + 10029087SZhong.Wang@Sun.COM * FC frame + FCoE tailer 10039087SZhong.Wang@Sun.COM */ 10049087SZhong.Wang@Sun.COM /* ARGSUSED */ 10059087SZhong.Wang@Sun.COM mblk_t * 10069087SZhong.Wang@Sun.COM fcoe_get_mblk(fcoe_mac_t *mac, uint32_t raw_frame_size) 10079087SZhong.Wang@Sun.COM { 10089087SZhong.Wang@Sun.COM mblk_t *mp; 10099087SZhong.Wang@Sun.COM int err; 10109087SZhong.Wang@Sun.COM 10119087SZhong.Wang@Sun.COM /* 10129087SZhong.Wang@Sun.COM * FCFH_SIZE + PADDING_SIZE 10139087SZhong.Wang@Sun.COM */ 10149087SZhong.Wang@Sun.COM ASSERT(raw_frame_size >= 60); 10159087SZhong.Wang@Sun.COM while ((mp = allocb((size_t)raw_frame_size, 0)) == NULL) { 10169087SZhong.Wang@Sun.COM if ((err = strwaitbuf((size_t)raw_frame_size, BPRI_LO)) != 0) { 10179087SZhong.Wang@Sun.COM FCOE_LOG("fcoe_get_mblk", "strwaitbuf return %d", err); 10189087SZhong.Wang@Sun.COM return (NULL); 10199087SZhong.Wang@Sun.COM } 10209087SZhong.Wang@Sun.COM } 10219087SZhong.Wang@Sun.COM mp->b_wptr = mp->b_rptr + raw_frame_size; 10229087SZhong.Wang@Sun.COM 10239087SZhong.Wang@Sun.COM /* 10249087SZhong.Wang@Sun.COM * We should always zero FC frame header 10259087SZhong.Wang@Sun.COM */ 10269087SZhong.Wang@Sun.COM bzero(mp->b_rptr + PADDING_HEADER_SIZE, 10279087SZhong.Wang@Sun.COM sizeof (fcoe_fc_frame_header_t)); 10289087SZhong.Wang@Sun.COM return (mp); 10299087SZhong.Wang@Sun.COM } 10309087SZhong.Wang@Sun.COM 10319087SZhong.Wang@Sun.COM static void 10329087SZhong.Wang@Sun.COM fcoe_watchdog(void *arg) 10339087SZhong.Wang@Sun.COM { 10349087SZhong.Wang@Sun.COM fcoe_soft_state_t *ss = (fcoe_soft_state_t *)arg; 10359087SZhong.Wang@Sun.COM fcoe_i_frame_t *fmi; 10369087SZhong.Wang@Sun.COM fcoe_mac_t *mac = NULL; 10379087SZhong.Wang@Sun.COM 10389087SZhong.Wang@Sun.COM FCOE_LOG("fcoe", "fcoe_soft_state is %p", ss); 10399087SZhong.Wang@Sun.COM 10409087SZhong.Wang@Sun.COM mutex_enter(&ss->ss_watch_mutex); 10419087SZhong.Wang@Sun.COM ss->ss_flags |= SS_FLAG_WATCHDOG_RUNNING; 10429087SZhong.Wang@Sun.COM while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) { 10439087SZhong.Wang@Sun.COM while (fmi = (fcoe_i_frame_t *)list_head(&ss->ss_pfrm_list)) { 10449087SZhong.Wang@Sun.COM list_remove(&ss->ss_pfrm_list, fmi); 10459087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_watch_mutex); 10469087SZhong.Wang@Sun.COM 10479087SZhong.Wang@Sun.COM mac = EPORT2MAC(fmi->fmi_frame->frm_eport); 10489087SZhong.Wang@Sun.COM mac->fm_client.ect_release_sol_frame(fmi->fmi_frame); 10499087SZhong.Wang@Sun.COM 10509087SZhong.Wang@Sun.COM mutex_enter(&ss->ss_watch_mutex); 10519087SZhong.Wang@Sun.COM mac->fm_frm_cnt--; 10529087SZhong.Wang@Sun.COM } 10539087SZhong.Wang@Sun.COM 10549087SZhong.Wang@Sun.COM ss->ss_flags |= SS_FLAG_DOG_WAITING; 10559087SZhong.Wang@Sun.COM (void) cv_wait(&ss->ss_watch_cv, &ss->ss_watch_mutex); 10569087SZhong.Wang@Sun.COM ss->ss_flags &= ~SS_FLAG_DOG_WAITING; 10579087SZhong.Wang@Sun.COM } 10589087SZhong.Wang@Sun.COM 10599087SZhong.Wang@Sun.COM ss->ss_flags &= ~SS_FLAG_WATCHDOG_RUNNING; 10609087SZhong.Wang@Sun.COM mutex_exit(&ss->ss_watch_mutex); 10619087SZhong.Wang@Sun.COM } 10629087SZhong.Wang@Sun.COM 10639087SZhong.Wang@Sun.COM static void 10649087SZhong.Wang@Sun.COM fcoe_worker_init() 10659087SZhong.Wang@Sun.COM { 10669087SZhong.Wang@Sun.COM uint32_t i; 10679087SZhong.Wang@Sun.COM 10689087SZhong.Wang@Sun.COM fcoe_nworkers_running = 0; 10699087SZhong.Wang@Sun.COM fcoe_worker_taskq = ddi_taskq_create(0, "FCOE_WORKER_TASKQ", 10709087SZhong.Wang@Sun.COM fcoe_nworkers, TASKQ_DEFAULTPRI, 0); 10719087SZhong.Wang@Sun.COM fcoe_workers = (fcoe_worker_t *)kmem_zalloc(sizeof (fcoe_worker_t) * 10729087SZhong.Wang@Sun.COM fcoe_nworkers, KM_SLEEP); 10739087SZhong.Wang@Sun.COM for (i = 0; i < fcoe_nworkers; i++) { 10749087SZhong.Wang@Sun.COM fcoe_worker_t *w = &fcoe_workers[i]; 10759087SZhong.Wang@Sun.COM mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL); 10769087SZhong.Wang@Sun.COM cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL); 10779087SZhong.Wang@Sun.COM w->worker_flags &= ~FCOE_WORKER_TERMINATE; 10789087SZhong.Wang@Sun.COM list_create(&w->worker_frm_list, sizeof (fcoe_i_frame_t), 10799087SZhong.Wang@Sun.COM offsetof(fcoe_i_frame_t, fmi_pending_node)); 10809087SZhong.Wang@Sun.COM (void) ddi_taskq_dispatch(fcoe_worker_taskq, fcoe_worker_frame, 10819087SZhong.Wang@Sun.COM w, DDI_SLEEP); 10829087SZhong.Wang@Sun.COM } 10839087SZhong.Wang@Sun.COM while (fcoe_nworkers_running != fcoe_nworkers) { 10849087SZhong.Wang@Sun.COM delay(10); 10859087SZhong.Wang@Sun.COM } 10869087SZhong.Wang@Sun.COM } 10879087SZhong.Wang@Sun.COM 10889087SZhong.Wang@Sun.COM static int 10899087SZhong.Wang@Sun.COM fcoe_worker_fini() 10909087SZhong.Wang@Sun.COM { 10919087SZhong.Wang@Sun.COM uint32_t i; 10929087SZhong.Wang@Sun.COM 10939087SZhong.Wang@Sun.COM for (i = 0; i < fcoe_nworkers; i++) { 10949087SZhong.Wang@Sun.COM fcoe_worker_t *w = &fcoe_workers[i]; 10959087SZhong.Wang@Sun.COM mutex_enter(&w->worker_lock); 10969087SZhong.Wang@Sun.COM if (w->worker_flags & FCOE_WORKER_STARTED) { 10979087SZhong.Wang@Sun.COM w->worker_flags |= FCOE_WORKER_TERMINATE; 10989087SZhong.Wang@Sun.COM cv_signal(&w->worker_cv); 10999087SZhong.Wang@Sun.COM } 11009087SZhong.Wang@Sun.COM mutex_exit(&w->worker_lock); 11019087SZhong.Wang@Sun.COM } 11029087SZhong.Wang@Sun.COM 11039087SZhong.Wang@Sun.COM while (fcoe_nworkers_running != 0) { 11049087SZhong.Wang@Sun.COM delay(drv_usectohz(10000)); 11059087SZhong.Wang@Sun.COM } 11069087SZhong.Wang@Sun.COM 11079087SZhong.Wang@Sun.COM ddi_taskq_destroy(fcoe_worker_taskq); 11089087SZhong.Wang@Sun.COM kmem_free(fcoe_workers, sizeof (fcoe_worker_t) * fcoe_nworkers); 11099087SZhong.Wang@Sun.COM fcoe_workers = NULL; 11109087SZhong.Wang@Sun.COM return (FCOE_SUCCESS); 11119087SZhong.Wang@Sun.COM } 11129087SZhong.Wang@Sun.COM 11139087SZhong.Wang@Sun.COM static int 11149087SZhong.Wang@Sun.COM fcoe_crc_verify(fcoe_frame_t *frm) 11159087SZhong.Wang@Sun.COM { 11169087SZhong.Wang@Sun.COM uint32_t crc; 11179087SZhong.Wang@Sun.COM uint8_t *crc_array = FRM2FMI(frm)->fmi_fft->fft_crc; 11189087SZhong.Wang@Sun.COM uint32_t crc_from_frame = ~(crc_array[0] | (crc_array[1] << 8) | 11199087SZhong.Wang@Sun.COM (crc_array[2] << 16) | (crc_array[3] << 24)); 11209087SZhong.Wang@Sun.COM CRC32(crc, frm->frm_fc_frame, frm->frm_fc_frame_size, -1U, crc32_table); 11219087SZhong.Wang@Sun.COM return (crc == crc_from_frame ? FCOE_SUCCESS : FCOE_FAILURE); 11229087SZhong.Wang@Sun.COM } 11239087SZhong.Wang@Sun.COM 11249087SZhong.Wang@Sun.COM static void 11259087SZhong.Wang@Sun.COM fcoe_worker_frame(void *arg) 11269087SZhong.Wang@Sun.COM { 11279087SZhong.Wang@Sun.COM fcoe_worker_t *w = (fcoe_worker_t *)arg; 11289087SZhong.Wang@Sun.COM fcoe_i_frame_t *fmi; 11299087SZhong.Wang@Sun.COM int ret; 11309087SZhong.Wang@Sun.COM 11319087SZhong.Wang@Sun.COM atomic_add_32(&fcoe_nworkers_running, 1); 11329087SZhong.Wang@Sun.COM mutex_enter(&w->worker_lock); 11339087SZhong.Wang@Sun.COM w->worker_flags |= FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE; 11349087SZhong.Wang@Sun.COM while ((w->worker_flags & FCOE_WORKER_TERMINATE) == 0) { 11359087SZhong.Wang@Sun.COM /* 11369087SZhong.Wang@Sun.COM * loop through the frames 11379087SZhong.Wang@Sun.COM */ 11389087SZhong.Wang@Sun.COM while (fmi = list_head(&w->worker_frm_list)) { 11399087SZhong.Wang@Sun.COM list_remove(&w->worker_frm_list, fmi); 11409087SZhong.Wang@Sun.COM mutex_exit(&w->worker_lock); 11419087SZhong.Wang@Sun.COM /* 11429087SZhong.Wang@Sun.COM * do the checksum 11439087SZhong.Wang@Sun.COM */ 11449087SZhong.Wang@Sun.COM ret = fcoe_crc_verify(fmi->fmi_frame); 11459087SZhong.Wang@Sun.COM if (ret == FCOE_SUCCESS) { 11469087SZhong.Wang@Sun.COM fmi->fmi_mac->fm_client.ect_rx_frame( 11479087SZhong.Wang@Sun.COM fmi->fmi_frame); 11489087SZhong.Wang@Sun.COM } else { 11499087SZhong.Wang@Sun.COM fcoe_release_frame(fmi->fmi_frame); 11509087SZhong.Wang@Sun.COM } 11519087SZhong.Wang@Sun.COM mutex_enter(&w->worker_lock); 11529087SZhong.Wang@Sun.COM w->worker_ntasks--; 11539087SZhong.Wang@Sun.COM } 11549087SZhong.Wang@Sun.COM w->worker_flags &= ~FCOE_WORKER_ACTIVE; 11559087SZhong.Wang@Sun.COM cv_wait(&w->worker_cv, &w->worker_lock); 11569087SZhong.Wang@Sun.COM w->worker_flags |= FCOE_WORKER_ACTIVE; 11579087SZhong.Wang@Sun.COM } 11589087SZhong.Wang@Sun.COM w->worker_flags &= ~(FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE); 11599087SZhong.Wang@Sun.COM mutex_exit(&w->worker_lock); 11609087SZhong.Wang@Sun.COM atomic_add_32(&fcoe_nworkers_running, -1); 11619087SZhong.Wang@Sun.COM list_destroy(&w->worker_frm_list); 11629087SZhong.Wang@Sun.COM } 11639087SZhong.Wang@Sun.COM 11649087SZhong.Wang@Sun.COM void 11659087SZhong.Wang@Sun.COM fcoe_post_frame(fcoe_frame_t *frm) 11669087SZhong.Wang@Sun.COM { 11679087SZhong.Wang@Sun.COM fcoe_worker_t *w; 11689087SZhong.Wang@Sun.COM uint16_t oxid = FRM_OXID(frm); 11699087SZhong.Wang@Sun.COM 11709087SZhong.Wang@Sun.COM w = &fcoe_workers[oxid % fcoe_nworkers_running]; 11719087SZhong.Wang@Sun.COM mutex_enter(&w->worker_lock); 11729087SZhong.Wang@Sun.COM list_insert_tail(&w->worker_frm_list, frm->frm_fcoe_private); 11739087SZhong.Wang@Sun.COM w->worker_ntasks++; 11749087SZhong.Wang@Sun.COM if ((w->worker_flags & FCOE_WORKER_ACTIVE) == 0) { 11759087SZhong.Wang@Sun.COM cv_signal(&w->worker_cv); 11769087SZhong.Wang@Sun.COM } 11779087SZhong.Wang@Sun.COM mutex_exit(&w->worker_lock); 11789087SZhong.Wang@Sun.COM } 11799087SZhong.Wang@Sun.COM 11809087SZhong.Wang@Sun.COM /* 11819087SZhong.Wang@Sun.COM * The max length of every LOG is 158 11829087SZhong.Wang@Sun.COM */ 11839087SZhong.Wang@Sun.COM void 11849087SZhong.Wang@Sun.COM fcoe_trace(caddr_t ident, const char *fmt, ...) 11859087SZhong.Wang@Sun.COM { 11869087SZhong.Wang@Sun.COM va_list args; 11879087SZhong.Wang@Sun.COM char tbuf[160]; 11889087SZhong.Wang@Sun.COM int len; 11899087SZhong.Wang@Sun.COM clock_t curclock; 11909087SZhong.Wang@Sun.COM clock_t usec; 11919087SZhong.Wang@Sun.COM 11929087SZhong.Wang@Sun.COM if (fcoe_trace_on == 0) { 11939087SZhong.Wang@Sun.COM return; 11949087SZhong.Wang@Sun.COM } 11959087SZhong.Wang@Sun.COM 11969087SZhong.Wang@Sun.COM curclock = ddi_get_lbolt(); 11979087SZhong.Wang@Sun.COM usec = (curclock - fcoe_trace_start) * usec_per_tick; 11989087SZhong.Wang@Sun.COM len = snprintf(tbuf, 158, "%lu.%03lus 0t%lu %s ", (usec / 11999087SZhong.Wang@Sun.COM (1000 * 1000)), ((usec % (1000 * 1000)) / 1000), 12009087SZhong.Wang@Sun.COM curclock, (ident ? ident : "unknown")); 12019087SZhong.Wang@Sun.COM va_start(args, fmt); 12029087SZhong.Wang@Sun.COM len += vsnprintf(tbuf + len, 158 - len, fmt, args); 12039087SZhong.Wang@Sun.COM va_end(args); 12049087SZhong.Wang@Sun.COM 12059087SZhong.Wang@Sun.COM if (len > 158) { 12069087SZhong.Wang@Sun.COM len = 158; 12079087SZhong.Wang@Sun.COM } 12089087SZhong.Wang@Sun.COM tbuf[len++] = '\n'; 12099087SZhong.Wang@Sun.COM tbuf[len] = 0; 12109087SZhong.Wang@Sun.COM 12119087SZhong.Wang@Sun.COM mutex_enter(&fcoe_trace_buf_lock); 12129087SZhong.Wang@Sun.COM bcopy(tbuf, &fcoe_trace_buf[fcoe_trace_buf_curndx], len+1); 12139087SZhong.Wang@Sun.COM fcoe_trace_buf_curndx += len; 12149087SZhong.Wang@Sun.COM if (fcoe_trace_buf_curndx > (fcoe_trace_buf_size - 320)) { 12159087SZhong.Wang@Sun.COM fcoe_trace_buf_curndx = 0; 12169087SZhong.Wang@Sun.COM } 12179087SZhong.Wang@Sun.COM mutex_exit(&fcoe_trace_buf_lock); 12189087SZhong.Wang@Sun.COM } 12199087SZhong.Wang@Sun.COM 12209087SZhong.Wang@Sun.COM /* 12219087SZhong.Wang@Sun.COM * Check whether the pwwn or nwwn already exist or not 12229087SZhong.Wang@Sun.COM * Return value: 12239087SZhong.Wang@Sun.COM * 1: PWWN conflicted 12249087SZhong.Wang@Sun.COM * -1: NWWN conflicted 12259087SZhong.Wang@Sun.COM * 0: No conflict 12269087SZhong.Wang@Sun.COM */ 12279087SZhong.Wang@Sun.COM static int 12289087SZhong.Wang@Sun.COM fcoe_cmp_wwn(fcoe_mac_t *checkedmac) 12299087SZhong.Wang@Sun.COM { 12309087SZhong.Wang@Sun.COM fcoe_mac_t *mac; 12319087SZhong.Wang@Sun.COM uint8_t *nwwn, *pwwn, *cnwwn, *cpwwn; 12329087SZhong.Wang@Sun.COM 12339087SZhong.Wang@Sun.COM cnwwn = checkedmac->fm_eport.eport_nodewwn; 12349087SZhong.Wang@Sun.COM cpwwn = checkedmac->fm_eport.eport_portwwn; 12359307Skelly.hu@Sun.COM ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 12369087SZhong.Wang@Sun.COM 12379087SZhong.Wang@Sun.COM for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; 12389087SZhong.Wang@Sun.COM mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { 12399087SZhong.Wang@Sun.COM if (mac == checkedmac) { 12409087SZhong.Wang@Sun.COM continue; 12419087SZhong.Wang@Sun.COM } 12429087SZhong.Wang@Sun.COM nwwn = mac->fm_eport.eport_nodewwn; 12439087SZhong.Wang@Sun.COM pwwn = mac->fm_eport.eport_portwwn; 12449087SZhong.Wang@Sun.COM 12459087SZhong.Wang@Sun.COM if (memcmp(nwwn, cnwwn, 8) == 0) { 12469087SZhong.Wang@Sun.COM return (-1); 12479087SZhong.Wang@Sun.COM } 12489087SZhong.Wang@Sun.COM 12499087SZhong.Wang@Sun.COM if (memcmp(pwwn, cpwwn, 8) == 0) { 12509087SZhong.Wang@Sun.COM return (1); 12519087SZhong.Wang@Sun.COM } 12529087SZhong.Wang@Sun.COM } 12539087SZhong.Wang@Sun.COM return (0); 12549087SZhong.Wang@Sun.COM } 12559087SZhong.Wang@Sun.COM 12569087SZhong.Wang@Sun.COM static int 12579087SZhong.Wang@Sun.COM fcoe_get_port_list(fcoe_port_instance_t *ports, int count) 12589087SZhong.Wang@Sun.COM { 12599087SZhong.Wang@Sun.COM fcoe_mac_t *mac = NULL; 12609087SZhong.Wang@Sun.COM int i = 0; 12619087SZhong.Wang@Sun.COM 12629087SZhong.Wang@Sun.COM ASSERT(ports != NULL); 12639307Skelly.hu@Sun.COM ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 12649087SZhong.Wang@Sun.COM 12659087SZhong.Wang@Sun.COM for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; 12669087SZhong.Wang@Sun.COM mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { 12679087SZhong.Wang@Sun.COM if (i < count) { 12689087SZhong.Wang@Sun.COM bcopy(mac->fm_eport.eport_portwwn, 12699087SZhong.Wang@Sun.COM ports[i].fpi_pwwn, 8); 12709307Skelly.hu@Sun.COM ports[i].fpi_mac_linkid = mac->fm_linkid; 12719087SZhong.Wang@Sun.COM bcopy(mac->fm_current_addr, 12729087SZhong.Wang@Sun.COM ports[i].fpi_mac_current_addr, ETHERADDRL); 12739087SZhong.Wang@Sun.COM bcopy(mac->fm_primary_addr, 12749087SZhong.Wang@Sun.COM ports[i].fpi_mac_factory_addr, ETHERADDRL); 12759087SZhong.Wang@Sun.COM ports[i].fpi_port_type = 12769087SZhong.Wang@Sun.COM EPORT_CLT_TYPE(&mac->fm_eport); 12779087SZhong.Wang@Sun.COM ports[i].fpi_mtu_size = 12789087SZhong.Wang@Sun.COM mac->fm_eport.eport_mtu; 12799087SZhong.Wang@Sun.COM ports[i].fpi_mac_promisc = 12809087SZhong.Wang@Sun.COM mac->fm_promisc_handle != NULL ? 1 : 0; 12819087SZhong.Wang@Sun.COM } 12829087SZhong.Wang@Sun.COM i++; 12839087SZhong.Wang@Sun.COM } 12849087SZhong.Wang@Sun.COM return (i); 12859087SZhong.Wang@Sun.COM } 1286