xref: /onnv-gate/usr/src/uts/common/io/fcoe/fcoe.c (revision 10264:1196af6129ec)
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