xref: /onnv-gate/usr/src/uts/common/io/fcoe/fcoe.c (revision 11231:7f165444fae6)
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);
126*11231SKevin.Yu@Sun.COM static boolean_t fcoe_mac_existed(fcoe_mac_t *pmac);
1279087SZhong.Wang@Sun.COM 
1289087SZhong.Wang@Sun.COM /*
1299087SZhong.Wang@Sun.COM  * Driver identificaton stuff
1309087SZhong.Wang@Sun.COM  */
1319087SZhong.Wang@Sun.COM static struct cb_ops fcoe_cb_ops = {
1329087SZhong.Wang@Sun.COM 	fcoe_open,
1339087SZhong.Wang@Sun.COM 	fcoe_close,
1349087SZhong.Wang@Sun.COM 	nodev,
1359087SZhong.Wang@Sun.COM 	nodev,
1369087SZhong.Wang@Sun.COM 	nodev,
1379087SZhong.Wang@Sun.COM 	nodev,
1389087SZhong.Wang@Sun.COM 	nodev,
1399087SZhong.Wang@Sun.COM 	fcoe_ioctl,
1409087SZhong.Wang@Sun.COM 	nodev,
1419087SZhong.Wang@Sun.COM 	nodev,
1429087SZhong.Wang@Sun.COM 	nodev,
1439087SZhong.Wang@Sun.COM 	nochpoll,
1449087SZhong.Wang@Sun.COM 	ddi_prop_op,
1459087SZhong.Wang@Sun.COM 	0,
1469087SZhong.Wang@Sun.COM 	D_MP | D_NEW | D_HOTPLUG,
1479087SZhong.Wang@Sun.COM 	CB_REV,
1489087SZhong.Wang@Sun.COM 	nodev,
1499087SZhong.Wang@Sun.COM 	nodev
1509087SZhong.Wang@Sun.COM };
1519087SZhong.Wang@Sun.COM 
1529087SZhong.Wang@Sun.COM static struct bus_ops fcoe_busops = {
1539087SZhong.Wang@Sun.COM 	BUSO_REV,
1549087SZhong.Wang@Sun.COM 	nullbusmap,			/* bus_map */
1559087SZhong.Wang@Sun.COM 	NULL,				/* bus_get_intrspec */
1569087SZhong.Wang@Sun.COM 	NULL,				/* bus_add_intrspec */
1579087SZhong.Wang@Sun.COM 	NULL,				/* bus_remove_intrspec */
1589087SZhong.Wang@Sun.COM 	i_ddi_map_fault,		/* bus_map_fault */
1599087SZhong.Wang@Sun.COM 	ddi_dma_map,			/* bus_dma_map */
1609087SZhong.Wang@Sun.COM 	ddi_dma_allochdl,		/* bus_dma_allochdl */
1619087SZhong.Wang@Sun.COM 	ddi_dma_freehdl,		/* bus_dma_freehdl */
1629087SZhong.Wang@Sun.COM 	ddi_dma_bindhdl,		/* bus_dma_bindhdl */
1639087SZhong.Wang@Sun.COM 	ddi_dma_unbindhdl,		/* bus_unbindhdl */
1649087SZhong.Wang@Sun.COM 	ddi_dma_flush,			/* bus_dma_flush */
1659087SZhong.Wang@Sun.COM 	ddi_dma_win,			/* bus_dma_win */
1669087SZhong.Wang@Sun.COM 	ddi_dma_mctl,			/* bus_dma_ctl */
1679087SZhong.Wang@Sun.COM 	fcoe_bus_ctl,			/* bus_ctl */
1689087SZhong.Wang@Sun.COM 	ddi_bus_prop_op,		/* bus_prop_op */
1699087SZhong.Wang@Sun.COM 	NULL,				/* bus_get_eventcookie */
1709087SZhong.Wang@Sun.COM 	NULL,				/* bus_add_eventcall */
1719087SZhong.Wang@Sun.COM 	NULL,				/* bus_remove_event */
1729087SZhong.Wang@Sun.COM 	NULL,				/* bus_post_event */
1739087SZhong.Wang@Sun.COM 	NULL,				/* bus_intr_ctl */
1749087SZhong.Wang@Sun.COM 	NULL,				/* bus_config */
1759087SZhong.Wang@Sun.COM 	NULL,				/* bus_unconfig */
1769087SZhong.Wang@Sun.COM 	NULL,				/* bus_fm_init */
1779087SZhong.Wang@Sun.COM 	NULL,				/* bus_fm_fini */
1789087SZhong.Wang@Sun.COM 	NULL,				/* bus_fm_access_enter */
1799087SZhong.Wang@Sun.COM 	NULL,				/* bus_fm_access_exit */
1809087SZhong.Wang@Sun.COM 	NULL,				/* bus_power */
1819087SZhong.Wang@Sun.COM 	NULL
1829087SZhong.Wang@Sun.COM };
1839087SZhong.Wang@Sun.COM 
1849087SZhong.Wang@Sun.COM static struct dev_ops fcoe_ops = {
1859087SZhong.Wang@Sun.COM 	DEVO_REV,
1869087SZhong.Wang@Sun.COM 	0,
1879087SZhong.Wang@Sun.COM 	nodev,
1889087SZhong.Wang@Sun.COM 	nulldev,
1899087SZhong.Wang@Sun.COM 	nulldev,
1909087SZhong.Wang@Sun.COM 	fcoe_attach,
1919087SZhong.Wang@Sun.COM 	fcoe_detach,
1929087SZhong.Wang@Sun.COM 	nodev,
1939087SZhong.Wang@Sun.COM 	&fcoe_cb_ops,
1949087SZhong.Wang@Sun.COM 	&fcoe_busops,
1959328SZhong.Wang@Sun.COM 	ddi_power,
1969328SZhong.Wang@Sun.COM 	ddi_quiesce_not_needed
1979087SZhong.Wang@Sun.COM };
1989087SZhong.Wang@Sun.COM 
199*11231SKevin.Yu@Sun.COM #define	FCOE_VERSION	"20091123-1.02"
2009087SZhong.Wang@Sun.COM #define	FCOE_NAME	"FCoE Transport v" FCOE_VERSION
2019087SZhong.Wang@Sun.COM #define	TASKQ_NAME_LEN	32
2029087SZhong.Wang@Sun.COM 
2039087SZhong.Wang@Sun.COM static struct modldrv modldrv = {
2049087SZhong.Wang@Sun.COM 	&mod_driverops,
2059087SZhong.Wang@Sun.COM 	FCOE_NAME,
2069087SZhong.Wang@Sun.COM 	&fcoe_ops,
2079087SZhong.Wang@Sun.COM };
2089087SZhong.Wang@Sun.COM 
2099087SZhong.Wang@Sun.COM static struct modlinkage modlinkage = {
2109087SZhong.Wang@Sun.COM 	MODREV_1, &modldrv, NULL
2119087SZhong.Wang@Sun.COM };
2129087SZhong.Wang@Sun.COM 
2139087SZhong.Wang@Sun.COM /*
2149087SZhong.Wang@Sun.COM  * TRACE for all FCoE related modules
2159087SZhong.Wang@Sun.COM  */
2169087SZhong.Wang@Sun.COM static kmutex_t fcoe_trace_buf_lock;
2179087SZhong.Wang@Sun.COM static int	fcoe_trace_buf_curndx	= 0;
2189087SZhong.Wang@Sun.COM static int	fcoe_trace_on		= 1;
2199087SZhong.Wang@Sun.COM static caddr_t	fcoe_trace_buf		= NULL;
2209087SZhong.Wang@Sun.COM static clock_t	fcoe_trace_start	= 0;
2219087SZhong.Wang@Sun.COM static caddr_t	ftb			= NULL;
2229087SZhong.Wang@Sun.COM static int	fcoe_trace_buf_size	= (1 * 1024 * 1024);
2239087SZhong.Wang@Sun.COM 
2249087SZhong.Wang@Sun.COM /*
2259087SZhong.Wang@Sun.COM  * Driver's global variables
2269087SZhong.Wang@Sun.COM  */
22710264SZhong.Wang@Sun.COM const fcoe_ver_e	 fcoe_ver_now	  = FCOE_VER_NOW;
2289087SZhong.Wang@Sun.COM static void		*fcoe_state	  = NULL;
2299087SZhong.Wang@Sun.COM fcoe_soft_state_t	*fcoe_global_ss	  = NULL;
2309087SZhong.Wang@Sun.COM int			 fcoe_use_ext_log = 1;
2319087SZhong.Wang@Sun.COM 
2329087SZhong.Wang@Sun.COM static ddi_taskq_t	*fcoe_worker_taskq;
2339087SZhong.Wang@Sun.COM static fcoe_worker_t	*fcoe_workers;
2349087SZhong.Wang@Sun.COM static uint32_t		fcoe_nworkers_running;
2359087SZhong.Wang@Sun.COM 
2369087SZhong.Wang@Sun.COM const char		*fcoe_workers_num = "workers-number";
2379087SZhong.Wang@Sun.COM volatile int		fcoe_nworkers;
2389087SZhong.Wang@Sun.COM 
2399087SZhong.Wang@Sun.COM /*
2409087SZhong.Wang@Sun.COM  * Common loadable module entry points _init, _fini, _info
2419087SZhong.Wang@Sun.COM  */
2429087SZhong.Wang@Sun.COM 
2439087SZhong.Wang@Sun.COM int
_init(void)2449087SZhong.Wang@Sun.COM _init(void)
2459087SZhong.Wang@Sun.COM {
2469087SZhong.Wang@Sun.COM 	int ret;
2479087SZhong.Wang@Sun.COM 
2489087SZhong.Wang@Sun.COM 	ret = ddi_soft_state_init(&fcoe_state, sizeof (fcoe_soft_state_t), 0);
2499087SZhong.Wang@Sun.COM 	if (ret == 0) {
2509087SZhong.Wang@Sun.COM 		ret = mod_install(&modlinkage);
2519087SZhong.Wang@Sun.COM 		if (ret != 0) {
2529087SZhong.Wang@Sun.COM 			ddi_soft_state_fini(&fcoe_state);
2539087SZhong.Wang@Sun.COM 		} else {
2549087SZhong.Wang@Sun.COM 			fcoe_trace_start = ddi_get_lbolt();
2559087SZhong.Wang@Sun.COM 			ftb = kmem_zalloc(fcoe_trace_buf_size,
2569087SZhong.Wang@Sun.COM 			    KM_SLEEP);
2579087SZhong.Wang@Sun.COM 			fcoe_trace_buf = ftb;
2589087SZhong.Wang@Sun.COM 			mutex_init(&fcoe_trace_buf_lock, NULL, MUTEX_DRIVER, 0);
2599087SZhong.Wang@Sun.COM 		}
2609087SZhong.Wang@Sun.COM 	}
2619087SZhong.Wang@Sun.COM 
2629087SZhong.Wang@Sun.COM 	FCOE_LOG("fcoe", "exit _init with %x", ret);
2639087SZhong.Wang@Sun.COM 
2649087SZhong.Wang@Sun.COM 	return (ret);
2659087SZhong.Wang@Sun.COM }
2669087SZhong.Wang@Sun.COM 
2679087SZhong.Wang@Sun.COM int
_fini(void)2689087SZhong.Wang@Sun.COM _fini(void)
2699087SZhong.Wang@Sun.COM {
2709087SZhong.Wang@Sun.COM 	int ret;
2719087SZhong.Wang@Sun.COM 
2729087SZhong.Wang@Sun.COM 	ret = mod_remove(&modlinkage);
2739087SZhong.Wang@Sun.COM 	if (ret == 0) {
2749087SZhong.Wang@Sun.COM 		ddi_soft_state_fini(&fcoe_state);
2759087SZhong.Wang@Sun.COM 	}
2769087SZhong.Wang@Sun.COM 
2779087SZhong.Wang@Sun.COM 	FCOE_LOG("fcoe", "exit _fini with %x", ret);
2789087SZhong.Wang@Sun.COM 	if (ret == 0) {
2799087SZhong.Wang@Sun.COM 		kmem_free(fcoe_trace_buf, fcoe_trace_buf_size);
2809087SZhong.Wang@Sun.COM 		mutex_destroy(&fcoe_trace_buf_lock);
2819087SZhong.Wang@Sun.COM 	}
2829087SZhong.Wang@Sun.COM 
2839087SZhong.Wang@Sun.COM 	return (ret);
2849087SZhong.Wang@Sun.COM }
2859087SZhong.Wang@Sun.COM 
2869087SZhong.Wang@Sun.COM int
_info(struct modinfo * modinfop)2879087SZhong.Wang@Sun.COM _info(struct modinfo *modinfop)
2889087SZhong.Wang@Sun.COM {
2899087SZhong.Wang@Sun.COM 	return (mod_info(&modlinkage, modinfop));
2909087SZhong.Wang@Sun.COM }
2919087SZhong.Wang@Sun.COM 
2929087SZhong.Wang@Sun.COM /*
2939087SZhong.Wang@Sun.COM  * Autoconfiguration entry points: attach, detach, getinfo
2949087SZhong.Wang@Sun.COM  */
2959087SZhong.Wang@Sun.COM 
2969087SZhong.Wang@Sun.COM static int
fcoe_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2979087SZhong.Wang@Sun.COM fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2989087SZhong.Wang@Sun.COM {
2999087SZhong.Wang@Sun.COM 	int			 ret = DDI_FAILURE;
3009087SZhong.Wang@Sun.COM 	int			 fcoe_ret;
3019087SZhong.Wang@Sun.COM 	int			 instance;
3029087SZhong.Wang@Sun.COM 	fcoe_soft_state_t	*ss;
3039087SZhong.Wang@Sun.COM 
3049087SZhong.Wang@Sun.COM 	instance = ddi_get_instance(dip);
3059087SZhong.Wang@Sun.COM 	switch (cmd) {
3069087SZhong.Wang@Sun.COM 	case DDI_ATTACH:
3079087SZhong.Wang@Sun.COM 		ret = ddi_soft_state_zalloc(fcoe_state, instance);
3089087SZhong.Wang@Sun.COM 		if (ret == DDI_FAILURE) {
3099087SZhong.Wang@Sun.COM 			FCOE_LOG(0, "soft_state_zalloc-%x/%x", ret, instance);
3109087SZhong.Wang@Sun.COM 			return (ret);
3119087SZhong.Wang@Sun.COM 		}
3129087SZhong.Wang@Sun.COM 
3139087SZhong.Wang@Sun.COM 		ss = ddi_get_soft_state(fcoe_state, instance);
3149087SZhong.Wang@Sun.COM 		ss->ss_dip = dip;
3159087SZhong.Wang@Sun.COM 
3169087SZhong.Wang@Sun.COM 		ASSERT(fcoe_global_ss == NULL);
3179087SZhong.Wang@Sun.COM 		fcoe_global_ss = ss;
3189087SZhong.Wang@Sun.COM 		fcoe_ret = fcoe_attach_init(ss);
3199087SZhong.Wang@Sun.COM 		if (fcoe_ret == FCOE_SUCCESS) {
3209087SZhong.Wang@Sun.COM 			ret = DDI_SUCCESS;
3219087SZhong.Wang@Sun.COM 		}
3229087SZhong.Wang@Sun.COM 
3239087SZhong.Wang@Sun.COM 		FCOE_LOG("fcoe", "fcoe_attach_init end with-%x", fcoe_ret);
3249087SZhong.Wang@Sun.COM 		break;
3259087SZhong.Wang@Sun.COM 
3269087SZhong.Wang@Sun.COM 	case DDI_RESUME:
3279087SZhong.Wang@Sun.COM 		ret = DDI_SUCCESS;
3289087SZhong.Wang@Sun.COM 		break;
3299087SZhong.Wang@Sun.COM 
3309087SZhong.Wang@Sun.COM 	default:
3319087SZhong.Wang@Sun.COM 		FCOE_LOG("fcoe", "unsupported attach cmd-%x", cmd);
3329087SZhong.Wang@Sun.COM 		break;
3339087SZhong.Wang@Sun.COM 	}
3349087SZhong.Wang@Sun.COM 
3359087SZhong.Wang@Sun.COM 	return (ret);
3369087SZhong.Wang@Sun.COM }
3379087SZhong.Wang@Sun.COM 
3389087SZhong.Wang@Sun.COM static int
fcoe_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3399087SZhong.Wang@Sun.COM fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3409087SZhong.Wang@Sun.COM {
3419087SZhong.Wang@Sun.COM 	int			 ret = DDI_FAILURE;
3429087SZhong.Wang@Sun.COM 	int			 fcoe_ret;
3439087SZhong.Wang@Sun.COM 	int			 instance;
3449087SZhong.Wang@Sun.COM 	fcoe_soft_state_t	*ss;
3459087SZhong.Wang@Sun.COM 
3469087SZhong.Wang@Sun.COM 	instance = ddi_get_instance(dip);
3479087SZhong.Wang@Sun.COM 	ss = ddi_get_soft_state(fcoe_state, instance);
3489087SZhong.Wang@Sun.COM 	if (ss == NULL) {
3499087SZhong.Wang@Sun.COM 		return (ret);
3509087SZhong.Wang@Sun.COM 	}
3519087SZhong.Wang@Sun.COM 
3529087SZhong.Wang@Sun.COM 	ASSERT(fcoe_global_ss != NULL);
3539087SZhong.Wang@Sun.COM 	ASSERT(dip == fcoe_global_ss->ss_dip);
3549087SZhong.Wang@Sun.COM 	switch (cmd) {
3559087SZhong.Wang@Sun.COM 	case DDI_DETACH:
3569087SZhong.Wang@Sun.COM 		fcoe_ret = fcoe_detach_uninit(ss);
3579087SZhong.Wang@Sun.COM 		if (fcoe_ret == FCOE_SUCCESS) {
3589087SZhong.Wang@Sun.COM 			ret = DDI_SUCCESS;
3599087SZhong.Wang@Sun.COM 			fcoe_global_ss = NULL;
3609087SZhong.Wang@Sun.COM 		}
3619087SZhong.Wang@Sun.COM 
3629087SZhong.Wang@Sun.COM 		break;
3639087SZhong.Wang@Sun.COM 
3649087SZhong.Wang@Sun.COM 	case DDI_SUSPEND:
3659087SZhong.Wang@Sun.COM 		ret = DDI_SUCCESS;
3669087SZhong.Wang@Sun.COM 		break;
3679087SZhong.Wang@Sun.COM 
3689087SZhong.Wang@Sun.COM 	default:
3699087SZhong.Wang@Sun.COM 		FCOE_LOG(0, "unsupported detach cmd-%x", cmd);
3709087SZhong.Wang@Sun.COM 		break;
3719087SZhong.Wang@Sun.COM 	}
3729087SZhong.Wang@Sun.COM 
3739087SZhong.Wang@Sun.COM 	return (ret);
3749087SZhong.Wang@Sun.COM }
3759087SZhong.Wang@Sun.COM 
3769087SZhong.Wang@Sun.COM /*
3779087SZhong.Wang@Sun.COM  * FCA driver's intercepted bus control operations.
3789087SZhong.Wang@Sun.COM  */
3799087SZhong.Wang@Sun.COM static int
fcoe_bus_ctl(dev_info_t * fcoe_dip,dev_info_t * rip,ddi_ctl_enum_t op,void * clientarg,void * result)3809087SZhong.Wang@Sun.COM fcoe_bus_ctl(dev_info_t *fcoe_dip, dev_info_t *rip,
3819087SZhong.Wang@Sun.COM     ddi_ctl_enum_t op, void *clientarg, void *result)
3829087SZhong.Wang@Sun.COM {
3839087SZhong.Wang@Sun.COM 	int ret;
3849087SZhong.Wang@Sun.COM 	switch (op) {
3859087SZhong.Wang@Sun.COM 	case DDI_CTLOPS_REPORTDEV:
3869087SZhong.Wang@Sun.COM 	case DDI_CTLOPS_IOMIN:
3879087SZhong.Wang@Sun.COM 		ret = DDI_SUCCESS;
3889087SZhong.Wang@Sun.COM 		break;
3899087SZhong.Wang@Sun.COM 
3909087SZhong.Wang@Sun.COM 	case DDI_CTLOPS_INITCHILD:
3919087SZhong.Wang@Sun.COM 		ret = fcoe_initchild(fcoe_dip, (dev_info_t *)clientarg);
3929087SZhong.Wang@Sun.COM 		break;
3939087SZhong.Wang@Sun.COM 
3949087SZhong.Wang@Sun.COM 	case DDI_CTLOPS_UNINITCHILD:
3959087SZhong.Wang@Sun.COM 		ret = fcoe_uninitchild(fcoe_dip, (dev_info_t *)clientarg);
3969087SZhong.Wang@Sun.COM 		break;
3979087SZhong.Wang@Sun.COM 
3989087SZhong.Wang@Sun.COM 	default:
3999087SZhong.Wang@Sun.COM 		ret = ddi_ctlops(fcoe_dip, rip, op, clientarg, result);
4009087SZhong.Wang@Sun.COM 		break;
4019087SZhong.Wang@Sun.COM 	}
4029087SZhong.Wang@Sun.COM 
4039087SZhong.Wang@Sun.COM 	return (ret);
4049087SZhong.Wang@Sun.COM }
4059087SZhong.Wang@Sun.COM 
4069087SZhong.Wang@Sun.COM /*
4079087SZhong.Wang@Sun.COM  * We need specify the dev address for client driver's instance, or we
4089087SZhong.Wang@Sun.COM  * can't online client driver's instance.
4099087SZhong.Wang@Sun.COM  */
4109087SZhong.Wang@Sun.COM /* ARGSUSED */
4119087SZhong.Wang@Sun.COM static int
fcoe_initchild(dev_info_t * fcoe_dip,dev_info_t * client_dip)4129087SZhong.Wang@Sun.COM fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip)
4139087SZhong.Wang@Sun.COM {
41410264SZhong.Wang@Sun.COM 	char	client_addr[FCOE_STR_LEN];
41510264SZhong.Wang@Sun.COM 	int	rval;
4169087SZhong.Wang@Sun.COM 
41710264SZhong.Wang@Sun.COM 	rval = ddi_prop_get_int(DDI_DEV_T_ANY, client_dip,
41810264SZhong.Wang@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1);
41910264SZhong.Wang@Sun.COM 	if (rval == -1) {
42010264SZhong.Wang@Sun.COM 		FCOE_LOG(__FUNCTION__, "no mac_id property: %p", client_dip);
42110264SZhong.Wang@Sun.COM 		return (DDI_FAILURE);
4229087SZhong.Wang@Sun.COM 	}
4239087SZhong.Wang@Sun.COM 
42410264SZhong.Wang@Sun.COM 	bzero(client_addr, FCOE_STR_LEN);
42510264SZhong.Wang@Sun.COM 	(void) sprintf((char *)client_addr, "%x,0", rval);
42610264SZhong.Wang@Sun.COM 	ddi_set_name_addr(client_dip, client_addr);
4279087SZhong.Wang@Sun.COM 	return (DDI_SUCCESS);
4289087SZhong.Wang@Sun.COM }
4299087SZhong.Wang@Sun.COM 
4309087SZhong.Wang@Sun.COM /* ARGSUSED */
4319087SZhong.Wang@Sun.COM static int
fcoe_uninitchild(dev_info_t * fcoe_dip,dev_info_t * client_dip)4329087SZhong.Wang@Sun.COM fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip)
4339087SZhong.Wang@Sun.COM {
4349087SZhong.Wang@Sun.COM 	ddi_set_name_addr(client_dip, NULL);
4359087SZhong.Wang@Sun.COM 	return (DDI_SUCCESS);
4369087SZhong.Wang@Sun.COM }
4379087SZhong.Wang@Sun.COM 
4389087SZhong.Wang@Sun.COM /*
4399087SZhong.Wang@Sun.COM  * Device access entry points
4409087SZhong.Wang@Sun.COM  */
4419087SZhong.Wang@Sun.COM static int
fcoe_open(dev_t * devp,int flag,int otype,cred_t * credp)4429087SZhong.Wang@Sun.COM fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp)
4439087SZhong.Wang@Sun.COM {
4449087SZhong.Wang@Sun.COM 	int			 instance;
4459087SZhong.Wang@Sun.COM 	fcoe_soft_state_t	*ss;
4469087SZhong.Wang@Sun.COM 
4479087SZhong.Wang@Sun.COM 	if (otype != OTYP_CHR) {
4489087SZhong.Wang@Sun.COM 		return (EINVAL);
4499087SZhong.Wang@Sun.COM 	}
4509087SZhong.Wang@Sun.COM 
4519087SZhong.Wang@Sun.COM 	/*
4529087SZhong.Wang@Sun.COM 	 * Since this is for debugging only, only allow root to issue ioctl now
4539087SZhong.Wang@Sun.COM 	 */
4549087SZhong.Wang@Sun.COM 	if (drv_priv(credp) != 0) {
4559087SZhong.Wang@Sun.COM 		return (EPERM);
4569087SZhong.Wang@Sun.COM 	}
4579087SZhong.Wang@Sun.COM 
4589087SZhong.Wang@Sun.COM 	instance = (int)getminor(*devp);
4599087SZhong.Wang@Sun.COM 	ss = ddi_get_soft_state(fcoe_state, instance);
4609087SZhong.Wang@Sun.COM 	if (ss == NULL) {
4619087SZhong.Wang@Sun.COM 		return (ENXIO);
4629087SZhong.Wang@Sun.COM 	}
4639087SZhong.Wang@Sun.COM 
4649087SZhong.Wang@Sun.COM 	mutex_enter(&ss->ss_ioctl_mutex);
4659087SZhong.Wang@Sun.COM 	if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) {
4669087SZhong.Wang@Sun.COM 		/*
4679087SZhong.Wang@Sun.COM 		 * It is already open for exclusive access.
4689087SZhong.Wang@Sun.COM 		 * So shut the door on this caller.
4699087SZhong.Wang@Sun.COM 		 */
4709087SZhong.Wang@Sun.COM 		mutex_exit(&ss->ss_ioctl_mutex);
4719087SZhong.Wang@Sun.COM 		return (EBUSY);
4729087SZhong.Wang@Sun.COM 	}
4739087SZhong.Wang@Sun.COM 
4749087SZhong.Wang@Sun.COM 	if (flag & FEXCL) {
4759087SZhong.Wang@Sun.COM 		if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) {
4769087SZhong.Wang@Sun.COM 			/*
4779087SZhong.Wang@Sun.COM 			 * Exclusive operation not possible
4789087SZhong.Wang@Sun.COM 			 * as it is already opened
4799087SZhong.Wang@Sun.COM 			 */
4809087SZhong.Wang@Sun.COM 			mutex_exit(&ss->ss_ioctl_mutex);
4819087SZhong.Wang@Sun.COM 			return (EBUSY);
4829087SZhong.Wang@Sun.COM 		}
4839087SZhong.Wang@Sun.COM 		ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL;
4849087SZhong.Wang@Sun.COM 	}
4859087SZhong.Wang@Sun.COM 
4869087SZhong.Wang@Sun.COM 	ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_OPEN;
4879087SZhong.Wang@Sun.COM 	mutex_exit(&ss->ss_ioctl_mutex);
4889087SZhong.Wang@Sun.COM 
4899087SZhong.Wang@Sun.COM 	return (0);
4909087SZhong.Wang@Sun.COM }
4919087SZhong.Wang@Sun.COM 
4929087SZhong.Wang@Sun.COM /* ARGSUSED */
4939087SZhong.Wang@Sun.COM static int
fcoe_close(dev_t dev,int flag,int otype,cred_t * credp)4949087SZhong.Wang@Sun.COM fcoe_close(dev_t dev, int flag, int otype, cred_t *credp)
4959087SZhong.Wang@Sun.COM {
4969087SZhong.Wang@Sun.COM 	int			 instance;
4979087SZhong.Wang@Sun.COM 	fcoe_soft_state_t	*ss;
4989087SZhong.Wang@Sun.COM 
4999087SZhong.Wang@Sun.COM 	if (otype != OTYP_CHR) {
5009087SZhong.Wang@Sun.COM 		return (EINVAL);
5019087SZhong.Wang@Sun.COM 	}
5029087SZhong.Wang@Sun.COM 
5039087SZhong.Wang@Sun.COM 	instance = (int)getminor(dev);
5049087SZhong.Wang@Sun.COM 	ss = ddi_get_soft_state(fcoe_state, instance);
5059087SZhong.Wang@Sun.COM 	if (ss == NULL) {
5069087SZhong.Wang@Sun.COM 		return (ENXIO);
5079087SZhong.Wang@Sun.COM 	}
5089087SZhong.Wang@Sun.COM 
5099087SZhong.Wang@Sun.COM 	mutex_enter(&ss->ss_ioctl_mutex);
5109087SZhong.Wang@Sun.COM 	if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) {
5119087SZhong.Wang@Sun.COM 		mutex_exit(&ss->ss_ioctl_mutex);
5129087SZhong.Wang@Sun.COM 		return (ENODEV);
5139087SZhong.Wang@Sun.COM 	}
5149087SZhong.Wang@Sun.COM 
5159087SZhong.Wang@Sun.COM 	ss->ss_ioctl_flags &= ~FCOE_IOCTL_FLAG_MASK;
5169087SZhong.Wang@Sun.COM 	mutex_exit(&ss->ss_ioctl_mutex);
5179087SZhong.Wang@Sun.COM 
5189087SZhong.Wang@Sun.COM 	return (0);
5199087SZhong.Wang@Sun.COM }
5209087SZhong.Wang@Sun.COM 
5219087SZhong.Wang@Sun.COM /* ARGSUSED */
5229087SZhong.Wang@Sun.COM static int
fcoe_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * credp,int * rval)5239087SZhong.Wang@Sun.COM fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
5249087SZhong.Wang@Sun.COM     cred_t *credp, int *rval)
5259087SZhong.Wang@Sun.COM {
5269087SZhong.Wang@Sun.COM 	fcoe_soft_state_t	*ss;
5279087SZhong.Wang@Sun.COM 	int			 ret = 0;
5289087SZhong.Wang@Sun.COM 
5299087SZhong.Wang@Sun.COM 	if (drv_priv(credp) != 0) {
5309087SZhong.Wang@Sun.COM 		return (EPERM);
5319087SZhong.Wang@Sun.COM 	}
5329087SZhong.Wang@Sun.COM 
5339087SZhong.Wang@Sun.COM 	ss = ddi_get_soft_state(fcoe_state, (int32_t)getminor(dev));
5349087SZhong.Wang@Sun.COM 	if (ss == NULL) {
5359087SZhong.Wang@Sun.COM 		return (ENXIO);
5369087SZhong.Wang@Sun.COM 	}
5379087SZhong.Wang@Sun.COM 
5389087SZhong.Wang@Sun.COM 	mutex_enter(&ss->ss_ioctl_mutex);
5399087SZhong.Wang@Sun.COM 	if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) {
5409087SZhong.Wang@Sun.COM 		mutex_exit(&ss->ss_ioctl_mutex);
5419087SZhong.Wang@Sun.COM 		return (ENXIO);
5429087SZhong.Wang@Sun.COM 	}
5439087SZhong.Wang@Sun.COM 	mutex_exit(&ss->ss_ioctl_mutex);
5449087SZhong.Wang@Sun.COM 
5459087SZhong.Wang@Sun.COM 	switch (cmd) {
5469087SZhong.Wang@Sun.COM 	case FCOEIO_CMD:
5479087SZhong.Wang@Sun.COM 		ret = fcoe_iocmd(ss, data, mode);
5489087SZhong.Wang@Sun.COM 		break;
5499087SZhong.Wang@Sun.COM 	default:
5509087SZhong.Wang@Sun.COM 		FCOE_LOG(0, "fcoe_ioctl: ioctl-0x%02X", cmd);
5519087SZhong.Wang@Sun.COM 		ret = ENOTTY;
5529087SZhong.Wang@Sun.COM 		break;
5539087SZhong.Wang@Sun.COM 	}
5549087SZhong.Wang@Sun.COM 
5559087SZhong.Wang@Sun.COM 	return (ret);
5569087SZhong.Wang@Sun.COM }
5579087SZhong.Wang@Sun.COM 
5589087SZhong.Wang@Sun.COM static int
fcoe_copyin_iocdata(intptr_t data,int mode,fcoeio_t ** fcoeio,void ** ibuf,void ** abuf,void ** obuf)5599087SZhong.Wang@Sun.COM fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio,
5609087SZhong.Wang@Sun.COM     void **ibuf, void **abuf, void **obuf)
5619087SZhong.Wang@Sun.COM {
5629087SZhong.Wang@Sun.COM 	int ret = 0;
5639087SZhong.Wang@Sun.COM 
5649087SZhong.Wang@Sun.COM 	*ibuf = NULL;
5659087SZhong.Wang@Sun.COM 	*abuf = NULL;
5669087SZhong.Wang@Sun.COM 	*obuf = NULL;
5679087SZhong.Wang@Sun.COM 	*fcoeio = kmem_zalloc(sizeof (fcoeio_t), KM_SLEEP);
5689087SZhong.Wang@Sun.COM 	if (ddi_copyin((void *)data, *fcoeio, sizeof (fcoeio_t), mode) != 0) {
5699087SZhong.Wang@Sun.COM 		ret = EFAULT;
5709087SZhong.Wang@Sun.COM 		goto copyin_iocdata_fail;
5719087SZhong.Wang@Sun.COM 	}
5729087SZhong.Wang@Sun.COM 
5739087SZhong.Wang@Sun.COM 	if ((*fcoeio)->fcoeio_ilen > FCOEIO_MAX_BUF_LEN ||
5749087SZhong.Wang@Sun.COM 	    (*fcoeio)->fcoeio_alen > FCOEIO_MAX_BUF_LEN ||
5759087SZhong.Wang@Sun.COM 	    (*fcoeio)->fcoeio_olen > FCOEIO_MAX_BUF_LEN) {
5769087SZhong.Wang@Sun.COM 		ret = EFAULT;
5779087SZhong.Wang@Sun.COM 		goto copyin_iocdata_fail;
5789087SZhong.Wang@Sun.COM 	}
5799087SZhong.Wang@Sun.COM 
5809087SZhong.Wang@Sun.COM 	if ((*fcoeio)->fcoeio_ilen) {
5819087SZhong.Wang@Sun.COM 		*ibuf = kmem_zalloc((*fcoeio)->fcoeio_ilen, KM_SLEEP);
5829087SZhong.Wang@Sun.COM 		if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_ibuf,
5839087SZhong.Wang@Sun.COM 		    *ibuf, (*fcoeio)->fcoeio_ilen, mode) != 0) {
5849087SZhong.Wang@Sun.COM 			ret = EFAULT;
5859087SZhong.Wang@Sun.COM 			goto copyin_iocdata_fail;
5869087SZhong.Wang@Sun.COM 		}
5879087SZhong.Wang@Sun.COM 	}
5889087SZhong.Wang@Sun.COM 
5899087SZhong.Wang@Sun.COM 	if ((*fcoeio)->fcoeio_alen) {
5909087SZhong.Wang@Sun.COM 		*abuf = kmem_zalloc((*fcoeio)->fcoeio_alen, KM_SLEEP);
5919087SZhong.Wang@Sun.COM 		if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_abuf,
5929087SZhong.Wang@Sun.COM 		    *abuf, (*fcoeio)->fcoeio_alen, mode) != 0) {
5939087SZhong.Wang@Sun.COM 			ret = EFAULT;
5949087SZhong.Wang@Sun.COM 			goto copyin_iocdata_fail;
5959087SZhong.Wang@Sun.COM 		}
5969087SZhong.Wang@Sun.COM 	}
5979087SZhong.Wang@Sun.COM 
5989087SZhong.Wang@Sun.COM 	if ((*fcoeio)->fcoeio_olen) {
5999087SZhong.Wang@Sun.COM 		*obuf = kmem_zalloc((*fcoeio)->fcoeio_olen, KM_SLEEP);
6009087SZhong.Wang@Sun.COM 	}
6019087SZhong.Wang@Sun.COM 	return (ret);
6029087SZhong.Wang@Sun.COM 
6039087SZhong.Wang@Sun.COM copyin_iocdata_fail:
6049087SZhong.Wang@Sun.COM 	if (*abuf) {
6059087SZhong.Wang@Sun.COM 		kmem_free(*abuf, (*fcoeio)->fcoeio_alen);
6069087SZhong.Wang@Sun.COM 		*abuf = NULL;
6079087SZhong.Wang@Sun.COM 	}
6089087SZhong.Wang@Sun.COM 
6099087SZhong.Wang@Sun.COM 	if (*ibuf) {
6109087SZhong.Wang@Sun.COM 		kmem_free(*ibuf, (*fcoeio)->fcoeio_ilen);
6119087SZhong.Wang@Sun.COM 		*ibuf = NULL;
6129087SZhong.Wang@Sun.COM 	}
6139087SZhong.Wang@Sun.COM 
6149087SZhong.Wang@Sun.COM 	kmem_free(*fcoeio, sizeof (fcoeio_t));
6159087SZhong.Wang@Sun.COM 	return (ret);
6169087SZhong.Wang@Sun.COM }
6179087SZhong.Wang@Sun.COM 
6189087SZhong.Wang@Sun.COM static int
fcoe_copyout_iocdata(intptr_t data,int mode,fcoeio_t * fcoeio,void * obuf)6199087SZhong.Wang@Sun.COM fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio, void *obuf)
6209087SZhong.Wang@Sun.COM {
6219087SZhong.Wang@Sun.COM 	if (fcoeio->fcoeio_olen) {
6229087SZhong.Wang@Sun.COM 		if (ddi_copyout(obuf,
6239087SZhong.Wang@Sun.COM 		    (void *)(unsigned long)fcoeio->fcoeio_obuf,
6249087SZhong.Wang@Sun.COM 		    fcoeio->fcoeio_olen, mode) != 0) {
6259087SZhong.Wang@Sun.COM 			return (EFAULT);
6269087SZhong.Wang@Sun.COM 		}
6279087SZhong.Wang@Sun.COM 	}
6289087SZhong.Wang@Sun.COM 
6299087SZhong.Wang@Sun.COM 	if (ddi_copyout(fcoeio, (void *)data, sizeof (fcoeio_t), mode) != 0) {
6309087SZhong.Wang@Sun.COM 		return (EFAULT);
6319087SZhong.Wang@Sun.COM 	}
6329087SZhong.Wang@Sun.COM 	return (0);
6339087SZhong.Wang@Sun.COM }
6349087SZhong.Wang@Sun.COM 
6359087SZhong.Wang@Sun.COM static int
fcoe_iocmd(fcoe_soft_state_t * ss,intptr_t data,int mode)6369087SZhong.Wang@Sun.COM fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode)
6379087SZhong.Wang@Sun.COM {
6389087SZhong.Wang@Sun.COM 	int		ret;
6399087SZhong.Wang@Sun.COM 	fcoe_mac_t	*fcoe_mac;
6409087SZhong.Wang@Sun.COM 	void		*ibuf = NULL;
6419087SZhong.Wang@Sun.COM 	void		*obuf = NULL;
6429087SZhong.Wang@Sun.COM 	void		*abuf = NULL;
6439087SZhong.Wang@Sun.COM 	fcoeio_t	*fcoeio;
6449087SZhong.Wang@Sun.COM 
6459087SZhong.Wang@Sun.COM 	ret = fcoe_copyin_iocdata(data, mode, &fcoeio, &ibuf, &abuf, &obuf);
6469087SZhong.Wang@Sun.COM 	if (ret != 0) {
6479087SZhong.Wang@Sun.COM 		goto fcoeiocmd_release_buf;
6489087SZhong.Wang@Sun.COM 	}
6499087SZhong.Wang@Sun.COM 
6509087SZhong.Wang@Sun.COM 	/*
6519087SZhong.Wang@Sun.COM 	 * If an exclusive open was demanded during open, ensure that
6529087SZhong.Wang@Sun.COM 	 * only one thread can execute an ioctl at a time
6539087SZhong.Wang@Sun.COM 	 */
6549087SZhong.Wang@Sun.COM 	mutex_enter(&ss->ss_ioctl_mutex);
6559087SZhong.Wang@Sun.COM 	if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) {
6569087SZhong.Wang@Sun.COM 		if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL_BUSY) {
6579087SZhong.Wang@Sun.COM 			mutex_exit(&ss->ss_ioctl_mutex);
6589087SZhong.Wang@Sun.COM 			fcoeio->fcoeio_status = FCOEIOE_BUSY;
6599087SZhong.Wang@Sun.COM 			ret = EBUSY;
6609087SZhong.Wang@Sun.COM 			goto fcoeiocmd_release_buf;
6619087SZhong.Wang@Sun.COM 		}
6629087SZhong.Wang@Sun.COM 		ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL_BUSY;
6639087SZhong.Wang@Sun.COM 	}
6649087SZhong.Wang@Sun.COM 	mutex_exit(&ss->ss_ioctl_mutex);
6659087SZhong.Wang@Sun.COM 
6669087SZhong.Wang@Sun.COM 	fcoeio->fcoeio_status = 0;
6679087SZhong.Wang@Sun.COM 
6689087SZhong.Wang@Sun.COM 	switch (fcoeio->fcoeio_cmd) {
6699087SZhong.Wang@Sun.COM 	case FCOEIO_CREATE_FCOE_PORT: {
6709087SZhong.Wang@Sun.COM 		fcoeio_create_port_param_t	*param =
6719087SZhong.Wang@Sun.COM 		    (fcoeio_create_port_param_t *)ibuf;
6729087SZhong.Wang@Sun.COM 		int		cmpwwn = 0;
6739087SZhong.Wang@Sun.COM 		fcoe_port_t	*eport;
6749087SZhong.Wang@Sun.COM 
6759087SZhong.Wang@Sun.COM 		if (fcoeio->fcoeio_ilen !=
6769087SZhong.Wang@Sun.COM 		    sizeof (fcoeio_create_port_param_t) ||
6779087SZhong.Wang@Sun.COM 		    fcoeio->fcoeio_xfer != FCOEIO_XFER_WRITE) {
6789087SZhong.Wang@Sun.COM 			fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG;
6799087SZhong.Wang@Sun.COM 			ret = EINVAL;
6809087SZhong.Wang@Sun.COM 			break;
6819087SZhong.Wang@Sun.COM 		}
6829087SZhong.Wang@Sun.COM 
6839087SZhong.Wang@Sun.COM 		mutex_enter(&ss->ss_ioctl_mutex);
6849307Skelly.hu@Sun.COM 		fcoe_mac = fcoe_create_mac_by_id(param->fcp_mac_linkid);
6859087SZhong.Wang@Sun.COM 		if (fcoe_mac == NULL) {
6869087SZhong.Wang@Sun.COM 			mutex_exit(&ss->ss_ioctl_mutex);
6879087SZhong.Wang@Sun.COM 			fcoeio->fcoeio_status = FCOEIOE_CREATE_MAC;
6889087SZhong.Wang@Sun.COM 			ret = EIO;
6899087SZhong.Wang@Sun.COM 			break;
6909087SZhong.Wang@Sun.COM 		}
6919087SZhong.Wang@Sun.COM 
6929087SZhong.Wang@Sun.COM 		if (fcoe_mac->fm_flags & FCOE_MAC_FLAG_ENABLED) {
6939087SZhong.Wang@Sun.COM 			mutex_exit(&ss->ss_ioctl_mutex);
6949087SZhong.Wang@Sun.COM 			fcoeio->fcoeio_status = FCOEIOE_ALREADY;
6959087SZhong.Wang@Sun.COM 			ret = EALREADY;
6969087SZhong.Wang@Sun.COM 			break;
6979087SZhong.Wang@Sun.COM 		} else {
6989087SZhong.Wang@Sun.COM 			ret = fcoe_open_mac(fcoe_mac, param->fcp_force_promisc,
6999087SZhong.Wang@Sun.COM 			    &fcoeio->fcoeio_status);
7009087SZhong.Wang@Sun.COM 			if (ret != 0) {
7019087SZhong.Wang@Sun.COM 				fcoe_destroy_mac(fcoe_mac);
7029087SZhong.Wang@Sun.COM 				mutex_exit(&ss->ss_ioctl_mutex);
7039087SZhong.Wang@Sun.COM 				if (fcoeio->fcoeio_status == 0) {
7049087SZhong.Wang@Sun.COM 					fcoeio->fcoeio_status =
7059087SZhong.Wang@Sun.COM 					    FCOEIOE_OPEN_MAC;
7069087SZhong.Wang@Sun.COM 				}
7079087SZhong.Wang@Sun.COM 				ret = EIO;
7089087SZhong.Wang@Sun.COM 				break;
7099087SZhong.Wang@Sun.COM 			} else {
7109087SZhong.Wang@Sun.COM 				fcoe_mac->fm_flags |= FCOE_MAC_FLAG_ENABLED;
7119087SZhong.Wang@Sun.COM 			}
7129087SZhong.Wang@Sun.COM 		}
7139087SZhong.Wang@Sun.COM 
7149087SZhong.Wang@Sun.COM 		/*
7159087SZhong.Wang@Sun.COM 		 * Provide PWWN and NWWN based on mac address
7169087SZhong.Wang@Sun.COM 		 */
7179087SZhong.Wang@Sun.COM 		eport = &fcoe_mac->fm_eport;
7189087SZhong.Wang@Sun.COM 		if (!param->fcp_pwwn_provided) {
7199087SZhong.Wang@Sun.COM 			fcoe_init_wwn_from_mac(eport->eport_portwwn,
7209087SZhong.Wang@Sun.COM 			    fcoe_mac->fm_current_addr, 1, 0);
7219087SZhong.Wang@Sun.COM 		} else {
7229087SZhong.Wang@Sun.COM 			(void) memcpy(eport->eport_portwwn, param->fcp_pwwn, 8);
7239087SZhong.Wang@Sun.COM 		}
7249087SZhong.Wang@Sun.COM 
7259087SZhong.Wang@Sun.COM 		if (!param->fcp_nwwn_provided) {
7269087SZhong.Wang@Sun.COM 			fcoe_init_wwn_from_mac(eport->eport_nodewwn,
7279087SZhong.Wang@Sun.COM 			    fcoe_mac->fm_current_addr, 0, 0);
7289087SZhong.Wang@Sun.COM 		} else {
7299087SZhong.Wang@Sun.COM 			(void) memcpy(eport->eport_nodewwn, param->fcp_nwwn, 8);
7309087SZhong.Wang@Sun.COM 		}
7319087SZhong.Wang@Sun.COM 
7329087SZhong.Wang@Sun.COM 		cmpwwn = fcoe_cmp_wwn(fcoe_mac);
7339087SZhong.Wang@Sun.COM 
7349087SZhong.Wang@Sun.COM 		if (cmpwwn != 0) {
7359087SZhong.Wang@Sun.COM 			if (cmpwwn == 1) {
7369087SZhong.Wang@Sun.COM 				fcoeio->fcoeio_status = FCOEIOE_PWWN_CONFLICTED;
7379087SZhong.Wang@Sun.COM 			} else if (cmpwwn == -1) {
7389087SZhong.Wang@Sun.COM 				fcoeio->fcoeio_status = FCOEIOE_NWWN_CONFLICTED;
7399087SZhong.Wang@Sun.COM 			}
7409087SZhong.Wang@Sun.COM 			(void) fcoe_close_mac(fcoe_mac);
7419087SZhong.Wang@Sun.COM 			fcoe_destroy_mac(fcoe_mac);
7429087SZhong.Wang@Sun.COM 			mutex_exit(&ss->ss_ioctl_mutex);
7439087SZhong.Wang@Sun.COM 			ret = ENOTUNIQ;
7449087SZhong.Wang@Sun.COM 			break;
7459087SZhong.Wang@Sun.COM 		}
7469087SZhong.Wang@Sun.COM 
7479087SZhong.Wang@Sun.COM 		if (ret == 0) {
7489087SZhong.Wang@Sun.COM 			ret = fcoe_create_port(ss->ss_dip,
7499087SZhong.Wang@Sun.COM 			    fcoe_mac,
7509087SZhong.Wang@Sun.COM 			    (param->fcp_port_type == FCOE_CLIENT_TARGET));
7519087SZhong.Wang@Sun.COM 			if (ret != 0) {
752*11231SKevin.Yu@Sun.COM 				if (fcoe_mac_existed(fcoe_mac) == B_TRUE) {
753*11231SKevin.Yu@Sun.COM 					(void) fcoe_close_mac(fcoe_mac);
754*11231SKevin.Yu@Sun.COM 					fcoe_destroy_mac(fcoe_mac);
755*11231SKevin.Yu@Sun.COM 				}
7569087SZhong.Wang@Sun.COM 				fcoeio->fcoeio_status = FCOEIOE_CREATE_PORT;
7579087SZhong.Wang@Sun.COM 				ret = EIO;
7589087SZhong.Wang@Sun.COM 			}
7599087SZhong.Wang@Sun.COM 		}
7609087SZhong.Wang@Sun.COM 		mutex_exit(&ss->ss_ioctl_mutex);
7619087SZhong.Wang@Sun.COM 
7629087SZhong.Wang@Sun.COM 		break;
7639087SZhong.Wang@Sun.COM 	}
7649087SZhong.Wang@Sun.COM 
7659087SZhong.Wang@Sun.COM 	case FCOEIO_DELETE_FCOE_PORT: {
7669307Skelly.hu@Sun.COM 		fcoeio_delete_port_param_t *del_port_param =
7679307Skelly.hu@Sun.COM 		    (fcoeio_delete_port_param_t *)ibuf;
7689895SKevin.Yu@Sun.COM 		uint64_t *is_target = (uint64_t *)obuf;
7699087SZhong.Wang@Sun.COM 
7709307Skelly.hu@Sun.COM 		if (fcoeio->fcoeio_ilen < sizeof (fcoeio_delete_port_param_t) ||
7719895SKevin.Yu@Sun.COM 		    fcoeio->fcoeio_olen != sizeof (uint64_t) ||
7729895SKevin.Yu@Sun.COM 		    fcoeio->fcoeio_xfer != FCOEIO_XFER_RW) {
7739087SZhong.Wang@Sun.COM 			fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG;
7749087SZhong.Wang@Sun.COM 			ret = EINVAL;
7759087SZhong.Wang@Sun.COM 			break;
7769087SZhong.Wang@Sun.COM 		}
7779087SZhong.Wang@Sun.COM 
7789087SZhong.Wang@Sun.COM 		mutex_enter(&ss->ss_ioctl_mutex);
7799307Skelly.hu@Sun.COM 		ret = fcoe_delete_port(ss->ss_dip, fcoeio,
7809895SKevin.Yu@Sun.COM 		    del_port_param->fdp_mac_linkid, is_target);
7819087SZhong.Wang@Sun.COM 		mutex_exit(&ss->ss_ioctl_mutex);
78210264SZhong.Wang@Sun.COM 		FCOE_LOG("fcoe", "fcoe_delete_port %x return: %d",
78310264SZhong.Wang@Sun.COM 		    del_port_param->fdp_mac_linkid, ret);
7849087SZhong.Wang@Sun.COM 		break;
7859087SZhong.Wang@Sun.COM 	}
7869087SZhong.Wang@Sun.COM 
7879087SZhong.Wang@Sun.COM 	case FCOEIO_GET_FCOE_PORT_LIST: {
7889087SZhong.Wang@Sun.COM 		fcoe_port_list_t *list = (fcoe_port_list_t *)obuf;
7899087SZhong.Wang@Sun.COM 		int		count;
7909087SZhong.Wang@Sun.COM 
7919087SZhong.Wang@Sun.COM 		if (fcoeio->fcoeio_xfer != FCOEIO_XFER_READ ||
7929087SZhong.Wang@Sun.COM 		    fcoeio->fcoeio_olen < sizeof (fcoe_port_list_t)) {
7939087SZhong.Wang@Sun.COM 			fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG;
7949087SZhong.Wang@Sun.COM 			ret = EINVAL;
7959087SZhong.Wang@Sun.COM 			break;
7969087SZhong.Wang@Sun.COM 		}
7979087SZhong.Wang@Sun.COM 		mutex_enter(&ss->ss_ioctl_mutex);
7989087SZhong.Wang@Sun.COM 
7999087SZhong.Wang@Sun.COM 		list->numPorts = 1 + (fcoeio->fcoeio_olen -
8009087SZhong.Wang@Sun.COM 		    sizeof (fcoe_port_list_t))/sizeof (fcoe_port_instance_t);
8019087SZhong.Wang@Sun.COM 
8029087SZhong.Wang@Sun.COM 		count = fcoe_get_port_list(list->ports, list->numPorts);
8039087SZhong.Wang@Sun.COM 
8049087SZhong.Wang@Sun.COM 		if (count > list->numPorts) {
8059087SZhong.Wang@Sun.COM 			fcoeio->fcoeio_status = FCOEIOE_MORE_DATA;
8069087SZhong.Wang@Sun.COM 			ret = ENOSPC;
8079087SZhong.Wang@Sun.COM 		}
8089087SZhong.Wang@Sun.COM 		list->numPorts = count;
8099087SZhong.Wang@Sun.COM 		mutex_exit(&ss->ss_ioctl_mutex);
8109087SZhong.Wang@Sun.COM 
8119087SZhong.Wang@Sun.COM 		break;
8129087SZhong.Wang@Sun.COM 
8139087SZhong.Wang@Sun.COM 	}
8149087SZhong.Wang@Sun.COM 
8159087SZhong.Wang@Sun.COM 	default:
8169087SZhong.Wang@Sun.COM 		return (ENOTTY);
8179087SZhong.Wang@Sun.COM 	}
8189087SZhong.Wang@Sun.COM 
81910264SZhong.Wang@Sun.COM 	FCOE_LOG("fcoe", "fcoe_ioctl %x returned %d, fcoeio_status = %d",
82010264SZhong.Wang@Sun.COM 	    fcoeio->fcoeio_cmd, ret, fcoeio->fcoeio_status);
8219087SZhong.Wang@Sun.COM 
8229087SZhong.Wang@Sun.COM fcoeiocmd_release_buf:
8239087SZhong.Wang@Sun.COM 	if (ret == 0) {
8249087SZhong.Wang@Sun.COM 		ret = fcoe_copyout_iocdata(data, mode, fcoeio, obuf);
8259087SZhong.Wang@Sun.COM 	} else if (fcoeio->fcoeio_status) {
8269087SZhong.Wang@Sun.COM 		(void) fcoe_copyout_iocdata(data, mode, fcoeio, obuf);
8279087SZhong.Wang@Sun.COM 	}
8289087SZhong.Wang@Sun.COM 
8299087SZhong.Wang@Sun.COM 	if (obuf != NULL) {
8309087SZhong.Wang@Sun.COM 		kmem_free(obuf, fcoeio->fcoeio_olen);
8319087SZhong.Wang@Sun.COM 		obuf = NULL;
8329087SZhong.Wang@Sun.COM 	}
8339087SZhong.Wang@Sun.COM 	if (abuf != NULL) {
8349087SZhong.Wang@Sun.COM 		kmem_free(abuf, fcoeio->fcoeio_alen);
8359087SZhong.Wang@Sun.COM 		abuf = NULL;
8369087SZhong.Wang@Sun.COM 	}
8379087SZhong.Wang@Sun.COM 
8389087SZhong.Wang@Sun.COM 	if (ibuf != NULL) {
8399087SZhong.Wang@Sun.COM 		kmem_free(ibuf, fcoeio->fcoeio_ilen);
8409087SZhong.Wang@Sun.COM 		ibuf = NULL;
8419087SZhong.Wang@Sun.COM 	}
8429087SZhong.Wang@Sun.COM 	kmem_free(fcoeio, sizeof (fcoeio_t));
8439087SZhong.Wang@Sun.COM 
8449087SZhong.Wang@Sun.COM 	return (ret);
8459087SZhong.Wang@Sun.COM }
8469087SZhong.Wang@Sun.COM 
8479087SZhong.Wang@Sun.COM /*
8489087SZhong.Wang@Sun.COM  * Finish final initialization
8499087SZhong.Wang@Sun.COM  */
8509087SZhong.Wang@Sun.COM static int
fcoe_attach_init(fcoe_soft_state_t * ss)8519087SZhong.Wang@Sun.COM fcoe_attach_init(fcoe_soft_state_t *ss)
8529087SZhong.Wang@Sun.COM {
8539087SZhong.Wang@Sun.COM 	char taskq_name[TASKQ_NAME_LEN];
8549087SZhong.Wang@Sun.COM 
8559087SZhong.Wang@Sun.COM 	if (ddi_create_minor_node(ss->ss_dip, "admin", S_IFCHR,
8569087SZhong.Wang@Sun.COM 	    ddi_get_instance(ss->ss_dip), DDI_PSEUDO, 0) != DDI_SUCCESS) {
8579087SZhong.Wang@Sun.COM 		FCOE_LOG("FCOE", "ddi_create_minor_node failed");
8589087SZhong.Wang@Sun.COM 		return (FCOE_FAILURE);
8599087SZhong.Wang@Sun.COM 	}
8609087SZhong.Wang@Sun.COM 
8619087SZhong.Wang@Sun.COM 	/*
8629087SZhong.Wang@Sun.COM 	 * watchdog responsible for release frame and dispatch events
8639087SZhong.Wang@Sun.COM 	 */
8649087SZhong.Wang@Sun.COM 	(void) snprintf(taskq_name, sizeof (taskq_name), "fcoe_mac");
8659087SZhong.Wang@Sun.COM 	taskq_name[TASKQ_NAME_LEN - 1] = 0;
8669087SZhong.Wang@Sun.COM 	if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL,
8679087SZhong.Wang@Sun.COM 	    taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) {
8689087SZhong.Wang@Sun.COM 		return (FCOE_FAILURE);
8699087SZhong.Wang@Sun.COM 	}
8709087SZhong.Wang@Sun.COM 
8719087SZhong.Wang@Sun.COM 	ss->ss_ioctl_flags = 0;
8729087SZhong.Wang@Sun.COM 	mutex_init(&ss->ss_ioctl_mutex, NULL, MUTEX_DRIVER, NULL);
8739087SZhong.Wang@Sun.COM 	list_create(&ss->ss_mac_list, sizeof (fcoe_mac_t),
8749087SZhong.Wang@Sun.COM 	    offsetof(fcoe_mac_t, fm_ss_node));
8759087SZhong.Wang@Sun.COM 	list_create(&ss->ss_pfrm_list, sizeof (fcoe_i_frame_t),
8769087SZhong.Wang@Sun.COM 	    offsetof(fcoe_i_frame_t, fmi_pending_node));
8779087SZhong.Wang@Sun.COM 
8789087SZhong.Wang@Sun.COM 	mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0);
8799087SZhong.Wang@Sun.COM 	cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL);
8809087SZhong.Wang@Sun.COM 	ss->ss_flags &= ~SS_FLAG_TERMINATE_WATCHDOG;
8819087SZhong.Wang@Sun.COM 	(void) ddi_taskq_dispatch(ss->ss_watchdog_taskq,
8829087SZhong.Wang@Sun.COM 	    fcoe_watchdog, ss, DDI_SLEEP);
8839087SZhong.Wang@Sun.COM 	while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) {
8849087SZhong.Wang@Sun.COM 		delay(10);
8859087SZhong.Wang@Sun.COM 	}
8869087SZhong.Wang@Sun.COM 	fcoe_nworkers = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip,
8879087SZhong.Wang@Sun.COM 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, (char *)fcoe_workers_num, 4);
8889087SZhong.Wang@Sun.COM 	if (fcoe_nworkers < 1) {
8899087SZhong.Wang@Sun.COM 		fcoe_nworkers = 4;
8909087SZhong.Wang@Sun.COM 	}
8919087SZhong.Wang@Sun.COM 	fcoe_worker_init();
8929087SZhong.Wang@Sun.COM 
8939087SZhong.Wang@Sun.COM 	ddi_report_dev(ss->ss_dip);
8949087SZhong.Wang@Sun.COM 	return (FCOE_SUCCESS);
8959087SZhong.Wang@Sun.COM }
8969087SZhong.Wang@Sun.COM 
8979087SZhong.Wang@Sun.COM /*
8989087SZhong.Wang@Sun.COM  * Finish final uninitialization
8999087SZhong.Wang@Sun.COM  */
9009087SZhong.Wang@Sun.COM static int
fcoe_detach_uninit(fcoe_soft_state_t * ss)9019087SZhong.Wang@Sun.COM fcoe_detach_uninit(fcoe_soft_state_t *ss)
9029087SZhong.Wang@Sun.COM {
9039087SZhong.Wang@Sun.COM 	int ret;
9049087SZhong.Wang@Sun.COM 	if (!list_is_empty(&ss->ss_mac_list)) {
9059087SZhong.Wang@Sun.COM 		FCOE_LOG("fcoe", "ss_mac_list is not empty when detach");
9069087SZhong.Wang@Sun.COM 		return (FCOE_FAILURE);
9079087SZhong.Wang@Sun.COM 	}
9089087SZhong.Wang@Sun.COM 
9099087SZhong.Wang@Sun.COM 	if ((ret = fcoe_worker_fini()) != FCOE_SUCCESS) {
9109087SZhong.Wang@Sun.COM 		return (ret);
9119087SZhong.Wang@Sun.COM 	}
9129087SZhong.Wang@Sun.COM 
9139087SZhong.Wang@Sun.COM 	/*
9149087SZhong.Wang@Sun.COM 	 * Stop watchdog
9159087SZhong.Wang@Sun.COM 	 */
9169087SZhong.Wang@Sun.COM 	if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
9179087SZhong.Wang@Sun.COM 		mutex_enter(&ss->ss_watch_mutex);
9189087SZhong.Wang@Sun.COM 		ss->ss_flags |= SS_FLAG_TERMINATE_WATCHDOG;
9199087SZhong.Wang@Sun.COM 		cv_broadcast(&ss->ss_watch_cv);
9209087SZhong.Wang@Sun.COM 		mutex_exit(&ss->ss_watch_mutex);
9219087SZhong.Wang@Sun.COM 		while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
9229087SZhong.Wang@Sun.COM 			delay(10);
9239087SZhong.Wang@Sun.COM 		}
9249087SZhong.Wang@Sun.COM 	}
9259087SZhong.Wang@Sun.COM 
9269087SZhong.Wang@Sun.COM 	ddi_taskq_destroy(ss->ss_watchdog_taskq);
9279087SZhong.Wang@Sun.COM 	mutex_destroy(&ss->ss_watch_mutex);
9289087SZhong.Wang@Sun.COM 	cv_destroy(&ss->ss_watch_cv);
9299087SZhong.Wang@Sun.COM 
9309087SZhong.Wang@Sun.COM 	ddi_remove_minor_node(ss->ss_dip, NULL);
9319087SZhong.Wang@Sun.COM 	mutex_destroy(&ss->ss_ioctl_mutex);
9329087SZhong.Wang@Sun.COM 	list_destroy(&ss->ss_mac_list);
9339087SZhong.Wang@Sun.COM 
9349087SZhong.Wang@Sun.COM 	return (FCOE_SUCCESS);
9359087SZhong.Wang@Sun.COM }
9369087SZhong.Wang@Sun.COM 
9379087SZhong.Wang@Sun.COM /*
9389087SZhong.Wang@Sun.COM  * Return mac instance if it exist, or else return NULL.
9399087SZhong.Wang@Sun.COM  */
9409087SZhong.Wang@Sun.COM fcoe_mac_t *
fcoe_lookup_mac_by_id(datalink_id_t linkid)9419307Skelly.hu@Sun.COM fcoe_lookup_mac_by_id(datalink_id_t linkid)
9429087SZhong.Wang@Sun.COM {
9439087SZhong.Wang@Sun.COM 	fcoe_mac_t	*mac = NULL;
9449087SZhong.Wang@Sun.COM 
9459307Skelly.hu@Sun.COM 	ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex));
9469087SZhong.Wang@Sun.COM 	for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
9479087SZhong.Wang@Sun.COM 	    mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
9489307Skelly.hu@Sun.COM 		if (linkid != mac->fm_linkid) {
9499087SZhong.Wang@Sun.COM 			continue;
9509087SZhong.Wang@Sun.COM 		}
9519087SZhong.Wang@Sun.COM 		return (mac);
9529087SZhong.Wang@Sun.COM 	}
9539087SZhong.Wang@Sun.COM 	return (NULL);
9549087SZhong.Wang@Sun.COM }
9559087SZhong.Wang@Sun.COM 
9569087SZhong.Wang@Sun.COM /*
957*11231SKevin.Yu@Sun.COM  * Return B_TRUE if mac exists, or else return B_FALSE
958*11231SKevin.Yu@Sun.COM  */
959*11231SKevin.Yu@Sun.COM static boolean_t
fcoe_mac_existed(fcoe_mac_t * pmac)960*11231SKevin.Yu@Sun.COM fcoe_mac_existed(fcoe_mac_t *pmac)
961*11231SKevin.Yu@Sun.COM {
962*11231SKevin.Yu@Sun.COM 	fcoe_mac_t	*mac = NULL;
963*11231SKevin.Yu@Sun.COM 
964*11231SKevin.Yu@Sun.COM 	ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex));
965*11231SKevin.Yu@Sun.COM 	for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
966*11231SKevin.Yu@Sun.COM 	    mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
967*11231SKevin.Yu@Sun.COM 		if (mac == pmac) {
968*11231SKevin.Yu@Sun.COM 			return (B_TRUE);
969*11231SKevin.Yu@Sun.COM 		}
970*11231SKevin.Yu@Sun.COM 	}
971*11231SKevin.Yu@Sun.COM 	return (B_FALSE);
972*11231SKevin.Yu@Sun.COM }
973*11231SKevin.Yu@Sun.COM 
974*11231SKevin.Yu@Sun.COM /*
9759087SZhong.Wang@Sun.COM  * port wwn will start with 20:..., node wwn will start with 10:...
9769087SZhong.Wang@Sun.COM  */
9779087SZhong.Wang@Sun.COM static void
fcoe_init_wwn_from_mac(uint8_t * wwn,uint8_t * mac,int is_pwwn,uint8_t idx)9789087SZhong.Wang@Sun.COM fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac, int is_pwwn, uint8_t idx)
9799087SZhong.Wang@Sun.COM {
9809087SZhong.Wang@Sun.COM 	ASSERT(wwn != NULL);
9819087SZhong.Wang@Sun.COM 	ASSERT(mac != NULL);
9829087SZhong.Wang@Sun.COM 	wwn[0] = (is_pwwn + 1) << 4;
9839087SZhong.Wang@Sun.COM 	wwn[1] = idx;
9849087SZhong.Wang@Sun.COM 	bcopy(mac, wwn + 2, ETHERADDRL);
9859087SZhong.Wang@Sun.COM }
9869087SZhong.Wang@Sun.COM 
9879087SZhong.Wang@Sun.COM /*
9889087SZhong.Wang@Sun.COM  * Return fcoe_mac if it exists, otherwise create a new one
9899087SZhong.Wang@Sun.COM  */
9909087SZhong.Wang@Sun.COM static fcoe_mac_t *
fcoe_create_mac_by_id(datalink_id_t linkid)9919307Skelly.hu@Sun.COM fcoe_create_mac_by_id(datalink_id_t linkid)
9929087SZhong.Wang@Sun.COM {
9939087SZhong.Wang@Sun.COM 	fcoe_mac_t	*mac = NULL;
9949307Skelly.hu@Sun.COM 	ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex));
9959087SZhong.Wang@Sun.COM 
9969307Skelly.hu@Sun.COM 	mac = fcoe_lookup_mac_by_id(linkid);
9979087SZhong.Wang@Sun.COM 	if (mac != NULL) {
9989307Skelly.hu@Sun.COM 		FCOE_LOG("fcoe", "fcoe_create_mac_by_id found one mac %d",
9999307Skelly.hu@Sun.COM 		    linkid);
10009087SZhong.Wang@Sun.COM 		return (mac);
10019087SZhong.Wang@Sun.COM 	}
10029087SZhong.Wang@Sun.COM 
10039087SZhong.Wang@Sun.COM 	mac = kmem_zalloc(sizeof (fcoe_mac_t), KM_SLEEP);
10049307Skelly.hu@Sun.COM 	mac->fm_linkid = linkid;
10059087SZhong.Wang@Sun.COM 	mac->fm_flags = 0;
10069087SZhong.Wang@Sun.COM 	mac->fm_ss = fcoe_global_ss;
10079087SZhong.Wang@Sun.COM 	list_insert_tail(&mac->fm_ss->ss_mac_list, mac);
10089307Skelly.hu@Sun.COM 	FCOE_LOG("fcoe", "fcoe_create_mac_by_id created one mac %d", linkid);
10099087SZhong.Wang@Sun.COM 	return (mac);
10109087SZhong.Wang@Sun.COM }
10119087SZhong.Wang@Sun.COM 
10129087SZhong.Wang@Sun.COM void
fcoe_destroy_mac(fcoe_mac_t * mac)10139087SZhong.Wang@Sun.COM fcoe_destroy_mac(fcoe_mac_t *mac)
10149087SZhong.Wang@Sun.COM {
10159087SZhong.Wang@Sun.COM 	ASSERT(mac != NULL);
10169087SZhong.Wang@Sun.COM 	list_remove(&mac->fm_ss->ss_mac_list, mac);
10179087SZhong.Wang@Sun.COM 	kmem_free(mac, sizeof (fcoe_mac_t));
10189087SZhong.Wang@Sun.COM }
10199087SZhong.Wang@Sun.COM 
10209087SZhong.Wang@Sun.COM /*
10219087SZhong.Wang@Sun.COM  * raw frame layout:
10229087SZhong.Wang@Sun.COM  * ethernet header + vlan header (optional) + FCoE header +
10239087SZhong.Wang@Sun.COM  * FC frame + FCoE tailer
10249087SZhong.Wang@Sun.COM  */
10259087SZhong.Wang@Sun.COM /* ARGSUSED */
10269087SZhong.Wang@Sun.COM mblk_t *
fcoe_get_mblk(fcoe_mac_t * mac,uint32_t raw_frame_size)10279087SZhong.Wang@Sun.COM fcoe_get_mblk(fcoe_mac_t *mac, uint32_t raw_frame_size)
10289087SZhong.Wang@Sun.COM {
10299087SZhong.Wang@Sun.COM 	mblk_t	*mp;
10309087SZhong.Wang@Sun.COM 	int	 err;
10319087SZhong.Wang@Sun.COM 
10329087SZhong.Wang@Sun.COM 	/*
10339087SZhong.Wang@Sun.COM 	 * FCFH_SIZE + PADDING_SIZE
10349087SZhong.Wang@Sun.COM 	 */
10359087SZhong.Wang@Sun.COM 	ASSERT(raw_frame_size >= 60);
10369087SZhong.Wang@Sun.COM 	while ((mp = allocb((size_t)raw_frame_size, 0)) == NULL) {
10379087SZhong.Wang@Sun.COM 		if ((err = strwaitbuf((size_t)raw_frame_size, BPRI_LO)) != 0) {
10389087SZhong.Wang@Sun.COM 			FCOE_LOG("fcoe_get_mblk", "strwaitbuf return %d", err);
10399087SZhong.Wang@Sun.COM 			return (NULL);
10409087SZhong.Wang@Sun.COM 		}
10419087SZhong.Wang@Sun.COM 	}
10429087SZhong.Wang@Sun.COM 	mp->b_wptr = mp->b_rptr + raw_frame_size;
10439087SZhong.Wang@Sun.COM 
10449087SZhong.Wang@Sun.COM 	/*
10459087SZhong.Wang@Sun.COM 	 * We should always zero FC frame header
10469087SZhong.Wang@Sun.COM 	 */
10479087SZhong.Wang@Sun.COM 	bzero(mp->b_rptr + PADDING_HEADER_SIZE,
10489087SZhong.Wang@Sun.COM 	    sizeof (fcoe_fc_frame_header_t));
10499087SZhong.Wang@Sun.COM 	return (mp);
10509087SZhong.Wang@Sun.COM }
10519087SZhong.Wang@Sun.COM 
10529087SZhong.Wang@Sun.COM static void
fcoe_watchdog(void * arg)10539087SZhong.Wang@Sun.COM fcoe_watchdog(void *arg)
10549087SZhong.Wang@Sun.COM {
10559087SZhong.Wang@Sun.COM 	fcoe_soft_state_t	*ss	   = (fcoe_soft_state_t *)arg;
10569087SZhong.Wang@Sun.COM 	fcoe_i_frame_t		*fmi;
10579087SZhong.Wang@Sun.COM 	fcoe_mac_t		*mac = NULL;
10589087SZhong.Wang@Sun.COM 
10599087SZhong.Wang@Sun.COM 	FCOE_LOG("fcoe", "fcoe_soft_state is %p", ss);
10609087SZhong.Wang@Sun.COM 
10619087SZhong.Wang@Sun.COM 	mutex_enter(&ss->ss_watch_mutex);
10629087SZhong.Wang@Sun.COM 	ss->ss_flags |= SS_FLAG_WATCHDOG_RUNNING;
10639087SZhong.Wang@Sun.COM 	while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) {
10649087SZhong.Wang@Sun.COM 		while (fmi = (fcoe_i_frame_t *)list_head(&ss->ss_pfrm_list)) {
10659087SZhong.Wang@Sun.COM 			list_remove(&ss->ss_pfrm_list, fmi);
10669087SZhong.Wang@Sun.COM 			mutex_exit(&ss->ss_watch_mutex);
10679087SZhong.Wang@Sun.COM 
10689087SZhong.Wang@Sun.COM 			mac = EPORT2MAC(fmi->fmi_frame->frm_eport);
10699087SZhong.Wang@Sun.COM 			mac->fm_client.ect_release_sol_frame(fmi->fmi_frame);
10709087SZhong.Wang@Sun.COM 
10719087SZhong.Wang@Sun.COM 			mutex_enter(&ss->ss_watch_mutex);
10729087SZhong.Wang@Sun.COM 			mac->fm_frm_cnt--;
10739087SZhong.Wang@Sun.COM 		}
10749087SZhong.Wang@Sun.COM 
10759087SZhong.Wang@Sun.COM 		ss->ss_flags |= SS_FLAG_DOG_WAITING;
10769087SZhong.Wang@Sun.COM 		(void) cv_wait(&ss->ss_watch_cv, &ss->ss_watch_mutex);
10779087SZhong.Wang@Sun.COM 		ss->ss_flags &= ~SS_FLAG_DOG_WAITING;
10789087SZhong.Wang@Sun.COM 	}
10799087SZhong.Wang@Sun.COM 
10809087SZhong.Wang@Sun.COM 	ss->ss_flags &= ~SS_FLAG_WATCHDOG_RUNNING;
10819087SZhong.Wang@Sun.COM 	mutex_exit(&ss->ss_watch_mutex);
10829087SZhong.Wang@Sun.COM }
10839087SZhong.Wang@Sun.COM 
10849087SZhong.Wang@Sun.COM static void
fcoe_worker_init()10859087SZhong.Wang@Sun.COM fcoe_worker_init()
10869087SZhong.Wang@Sun.COM {
10879087SZhong.Wang@Sun.COM 	uint32_t i;
10889087SZhong.Wang@Sun.COM 
10899087SZhong.Wang@Sun.COM 	fcoe_nworkers_running = 0;
10909087SZhong.Wang@Sun.COM 	fcoe_worker_taskq = ddi_taskq_create(0, "FCOE_WORKER_TASKQ",
10919087SZhong.Wang@Sun.COM 	    fcoe_nworkers, TASKQ_DEFAULTPRI, 0);
10929087SZhong.Wang@Sun.COM 	fcoe_workers = (fcoe_worker_t *)kmem_zalloc(sizeof (fcoe_worker_t) *
10939087SZhong.Wang@Sun.COM 	    fcoe_nworkers, KM_SLEEP);
10949087SZhong.Wang@Sun.COM 	for (i = 0; i < fcoe_nworkers; i++) {
10959087SZhong.Wang@Sun.COM 		fcoe_worker_t *w = &fcoe_workers[i];
10969087SZhong.Wang@Sun.COM 		mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL);
10979087SZhong.Wang@Sun.COM 		cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL);
10989087SZhong.Wang@Sun.COM 		w->worker_flags &= ~FCOE_WORKER_TERMINATE;
10999087SZhong.Wang@Sun.COM 		list_create(&w->worker_frm_list, sizeof (fcoe_i_frame_t),
11009087SZhong.Wang@Sun.COM 		    offsetof(fcoe_i_frame_t, fmi_pending_node));
11019087SZhong.Wang@Sun.COM 		(void) ddi_taskq_dispatch(fcoe_worker_taskq, fcoe_worker_frame,
11029087SZhong.Wang@Sun.COM 		    w, DDI_SLEEP);
11039087SZhong.Wang@Sun.COM 	}
11049087SZhong.Wang@Sun.COM 	while (fcoe_nworkers_running != fcoe_nworkers) {
11059087SZhong.Wang@Sun.COM 		delay(10);
11069087SZhong.Wang@Sun.COM 	}
11079087SZhong.Wang@Sun.COM }
11089087SZhong.Wang@Sun.COM 
11099087SZhong.Wang@Sun.COM static int
fcoe_worker_fini()11109087SZhong.Wang@Sun.COM fcoe_worker_fini()
11119087SZhong.Wang@Sun.COM {
11129087SZhong.Wang@Sun.COM 	uint32_t i;
11139087SZhong.Wang@Sun.COM 
11149087SZhong.Wang@Sun.COM 	for (i = 0; i < fcoe_nworkers; i++) {
11159087SZhong.Wang@Sun.COM 		fcoe_worker_t *w = &fcoe_workers[i];
11169087SZhong.Wang@Sun.COM 		mutex_enter(&w->worker_lock);
11179087SZhong.Wang@Sun.COM 		if (w->worker_flags & FCOE_WORKER_STARTED) {
11189087SZhong.Wang@Sun.COM 			w->worker_flags |= FCOE_WORKER_TERMINATE;
11199087SZhong.Wang@Sun.COM 			cv_signal(&w->worker_cv);
11209087SZhong.Wang@Sun.COM 		}
11219087SZhong.Wang@Sun.COM 		mutex_exit(&w->worker_lock);
11229087SZhong.Wang@Sun.COM 	}
11239087SZhong.Wang@Sun.COM 
11249087SZhong.Wang@Sun.COM 	while (fcoe_nworkers_running != 0) {
11259087SZhong.Wang@Sun.COM 		delay(drv_usectohz(10000));
11269087SZhong.Wang@Sun.COM 	}
11279087SZhong.Wang@Sun.COM 
11289087SZhong.Wang@Sun.COM 	ddi_taskq_destroy(fcoe_worker_taskq);
11299087SZhong.Wang@Sun.COM 	kmem_free(fcoe_workers, sizeof (fcoe_worker_t) * fcoe_nworkers);
11309087SZhong.Wang@Sun.COM 	fcoe_workers = NULL;
11319087SZhong.Wang@Sun.COM 	return (FCOE_SUCCESS);
11329087SZhong.Wang@Sun.COM }
11339087SZhong.Wang@Sun.COM 
11349087SZhong.Wang@Sun.COM static int
fcoe_crc_verify(fcoe_frame_t * frm)11359087SZhong.Wang@Sun.COM fcoe_crc_verify(fcoe_frame_t *frm)
11369087SZhong.Wang@Sun.COM {
11379087SZhong.Wang@Sun.COM 	uint32_t crc;
11389087SZhong.Wang@Sun.COM 	uint8_t *crc_array = FRM2FMI(frm)->fmi_fft->fft_crc;
11399087SZhong.Wang@Sun.COM 	uint32_t crc_from_frame = ~(crc_array[0] | (crc_array[1] << 8) |
11409087SZhong.Wang@Sun.COM 	    (crc_array[2] << 16) | (crc_array[3] << 24));
11419087SZhong.Wang@Sun.COM 	CRC32(crc, frm->frm_fc_frame, frm->frm_fc_frame_size, -1U, crc32_table);
11429087SZhong.Wang@Sun.COM 	return (crc == crc_from_frame ? FCOE_SUCCESS : FCOE_FAILURE);
11439087SZhong.Wang@Sun.COM }
11449087SZhong.Wang@Sun.COM 
11459087SZhong.Wang@Sun.COM static void
fcoe_worker_frame(void * arg)11469087SZhong.Wang@Sun.COM fcoe_worker_frame(void *arg)
11479087SZhong.Wang@Sun.COM {
11489087SZhong.Wang@Sun.COM 	fcoe_worker_t	*w = (fcoe_worker_t *)arg;
11499087SZhong.Wang@Sun.COM 	fcoe_i_frame_t	*fmi;
11509087SZhong.Wang@Sun.COM 	int		ret;
11519087SZhong.Wang@Sun.COM 
11529087SZhong.Wang@Sun.COM 	atomic_add_32(&fcoe_nworkers_running, 1);
11539087SZhong.Wang@Sun.COM 	mutex_enter(&w->worker_lock);
11549087SZhong.Wang@Sun.COM 	w->worker_flags |= FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE;
11559087SZhong.Wang@Sun.COM 	while ((w->worker_flags & FCOE_WORKER_TERMINATE) == 0) {
11569087SZhong.Wang@Sun.COM 		/*
11579087SZhong.Wang@Sun.COM 		 * loop through the frames
11589087SZhong.Wang@Sun.COM 		 */
11599087SZhong.Wang@Sun.COM 		while (fmi = list_head(&w->worker_frm_list)) {
11609087SZhong.Wang@Sun.COM 			list_remove(&w->worker_frm_list, fmi);
11619087SZhong.Wang@Sun.COM 			mutex_exit(&w->worker_lock);
11629087SZhong.Wang@Sun.COM 			/*
11639087SZhong.Wang@Sun.COM 			 * do the checksum
11649087SZhong.Wang@Sun.COM 			 */
11659087SZhong.Wang@Sun.COM 			ret = fcoe_crc_verify(fmi->fmi_frame);
11669087SZhong.Wang@Sun.COM 			if (ret == FCOE_SUCCESS) {
11679087SZhong.Wang@Sun.COM 				fmi->fmi_mac->fm_client.ect_rx_frame(
11689087SZhong.Wang@Sun.COM 				    fmi->fmi_frame);
11699087SZhong.Wang@Sun.COM 			} else {
11709087SZhong.Wang@Sun.COM 				fcoe_release_frame(fmi->fmi_frame);
11719087SZhong.Wang@Sun.COM 			}
11729087SZhong.Wang@Sun.COM 			mutex_enter(&w->worker_lock);
11739087SZhong.Wang@Sun.COM 			w->worker_ntasks--;
11749087SZhong.Wang@Sun.COM 		}
11759087SZhong.Wang@Sun.COM 		w->worker_flags &= ~FCOE_WORKER_ACTIVE;
11769087SZhong.Wang@Sun.COM 		cv_wait(&w->worker_cv, &w->worker_lock);
11779087SZhong.Wang@Sun.COM 		w->worker_flags |= FCOE_WORKER_ACTIVE;
11789087SZhong.Wang@Sun.COM 	}
11799087SZhong.Wang@Sun.COM 	w->worker_flags &= ~(FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE);
11809087SZhong.Wang@Sun.COM 	mutex_exit(&w->worker_lock);
11819087SZhong.Wang@Sun.COM 	atomic_add_32(&fcoe_nworkers_running, -1);
11829087SZhong.Wang@Sun.COM 	list_destroy(&w->worker_frm_list);
11839087SZhong.Wang@Sun.COM }
11849087SZhong.Wang@Sun.COM 
11859087SZhong.Wang@Sun.COM void
fcoe_post_frame(fcoe_frame_t * frm)11869087SZhong.Wang@Sun.COM fcoe_post_frame(fcoe_frame_t *frm)
11879087SZhong.Wang@Sun.COM {
11889087SZhong.Wang@Sun.COM 	fcoe_worker_t *w;
11899087SZhong.Wang@Sun.COM 	uint16_t	oxid = FRM_OXID(frm);
11909087SZhong.Wang@Sun.COM 
11919087SZhong.Wang@Sun.COM 	w = &fcoe_workers[oxid % fcoe_nworkers_running];
11929087SZhong.Wang@Sun.COM 	mutex_enter(&w->worker_lock);
11939087SZhong.Wang@Sun.COM 	list_insert_tail(&w->worker_frm_list, frm->frm_fcoe_private);
11949087SZhong.Wang@Sun.COM 	w->worker_ntasks++;
11959087SZhong.Wang@Sun.COM 	if ((w->worker_flags & FCOE_WORKER_ACTIVE) == 0) {
11969087SZhong.Wang@Sun.COM 		cv_signal(&w->worker_cv);
11979087SZhong.Wang@Sun.COM 	}
11989087SZhong.Wang@Sun.COM 	mutex_exit(&w->worker_lock);
11999087SZhong.Wang@Sun.COM }
12009087SZhong.Wang@Sun.COM 
12019087SZhong.Wang@Sun.COM /*
12029087SZhong.Wang@Sun.COM  * The max length of every LOG is 158
12039087SZhong.Wang@Sun.COM  */
12049087SZhong.Wang@Sun.COM void
fcoe_trace(caddr_t ident,const char * fmt,...)12059087SZhong.Wang@Sun.COM fcoe_trace(caddr_t ident, const char *fmt, ...)
12069087SZhong.Wang@Sun.COM {
12079087SZhong.Wang@Sun.COM 	va_list args;
12089087SZhong.Wang@Sun.COM 	char	tbuf[160];
12099087SZhong.Wang@Sun.COM 	int	len;
12109087SZhong.Wang@Sun.COM 	clock_t curclock;
12119087SZhong.Wang@Sun.COM 	clock_t usec;
12129087SZhong.Wang@Sun.COM 
12139087SZhong.Wang@Sun.COM 	if (fcoe_trace_on == 0) {
12149087SZhong.Wang@Sun.COM 		return;
12159087SZhong.Wang@Sun.COM 	}
12169087SZhong.Wang@Sun.COM 
12179087SZhong.Wang@Sun.COM 	curclock = ddi_get_lbolt();
12189087SZhong.Wang@Sun.COM 	usec = (curclock - fcoe_trace_start) * usec_per_tick;
12199087SZhong.Wang@Sun.COM 	len = snprintf(tbuf, 158, "%lu.%03lus 0t%lu %s ", (usec /
12209087SZhong.Wang@Sun.COM 	    (1000 * 1000)), ((usec % (1000 * 1000)) / 1000),
12219087SZhong.Wang@Sun.COM 	    curclock, (ident ? ident : "unknown"));
12229087SZhong.Wang@Sun.COM 	va_start(args, fmt);
12239087SZhong.Wang@Sun.COM 	len += vsnprintf(tbuf + len, 158 - len, fmt, args);
12249087SZhong.Wang@Sun.COM 	va_end(args);
12259087SZhong.Wang@Sun.COM 
12269087SZhong.Wang@Sun.COM 	if (len > 158) {
12279087SZhong.Wang@Sun.COM 		len = 158;
12289087SZhong.Wang@Sun.COM 	}
12299087SZhong.Wang@Sun.COM 	tbuf[len++] = '\n';
12309087SZhong.Wang@Sun.COM 	tbuf[len] = 0;
12319087SZhong.Wang@Sun.COM 
12329087SZhong.Wang@Sun.COM 	mutex_enter(&fcoe_trace_buf_lock);
12339087SZhong.Wang@Sun.COM 	bcopy(tbuf, &fcoe_trace_buf[fcoe_trace_buf_curndx], len+1);
12349087SZhong.Wang@Sun.COM 	fcoe_trace_buf_curndx += len;
12359087SZhong.Wang@Sun.COM 	if (fcoe_trace_buf_curndx > (fcoe_trace_buf_size - 320)) {
12369087SZhong.Wang@Sun.COM 		fcoe_trace_buf_curndx = 0;
12379087SZhong.Wang@Sun.COM 	}
12389087SZhong.Wang@Sun.COM 	mutex_exit(&fcoe_trace_buf_lock);
12399087SZhong.Wang@Sun.COM }
12409087SZhong.Wang@Sun.COM 
12419087SZhong.Wang@Sun.COM /*
12429087SZhong.Wang@Sun.COM  * Check whether the pwwn or nwwn already exist or not
12439087SZhong.Wang@Sun.COM  * Return value:
12449087SZhong.Wang@Sun.COM  * 1: PWWN conflicted
12459087SZhong.Wang@Sun.COM  * -1: NWWN conflicted
12469087SZhong.Wang@Sun.COM  * 0: No conflict
12479087SZhong.Wang@Sun.COM  */
12489087SZhong.Wang@Sun.COM static int
fcoe_cmp_wwn(fcoe_mac_t * checkedmac)12499087SZhong.Wang@Sun.COM fcoe_cmp_wwn(fcoe_mac_t *checkedmac)
12509087SZhong.Wang@Sun.COM {
12519087SZhong.Wang@Sun.COM 	fcoe_mac_t	*mac;
12529087SZhong.Wang@Sun.COM 	uint8_t		*nwwn, *pwwn, *cnwwn, *cpwwn;
12539087SZhong.Wang@Sun.COM 
12549087SZhong.Wang@Sun.COM 	cnwwn = checkedmac->fm_eport.eport_nodewwn;
12559087SZhong.Wang@Sun.COM 	cpwwn = checkedmac->fm_eport.eport_portwwn;
12569307Skelly.hu@Sun.COM 	ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex));
12579087SZhong.Wang@Sun.COM 
12589087SZhong.Wang@Sun.COM 	for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
12599087SZhong.Wang@Sun.COM 	    mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
12609087SZhong.Wang@Sun.COM 		if (mac == checkedmac) {
12619087SZhong.Wang@Sun.COM 			continue;
12629087SZhong.Wang@Sun.COM 		}
12639087SZhong.Wang@Sun.COM 		nwwn = mac->fm_eport.eport_nodewwn;
12649087SZhong.Wang@Sun.COM 		pwwn = mac->fm_eport.eport_portwwn;
12659087SZhong.Wang@Sun.COM 
12669087SZhong.Wang@Sun.COM 		if (memcmp(nwwn, cnwwn, 8) == 0) {
12679087SZhong.Wang@Sun.COM 			return (-1);
12689087SZhong.Wang@Sun.COM 		}
12699087SZhong.Wang@Sun.COM 
12709087SZhong.Wang@Sun.COM 		if (memcmp(pwwn, cpwwn, 8) == 0) {
12719087SZhong.Wang@Sun.COM 			return (1);
12729087SZhong.Wang@Sun.COM 		}
12739087SZhong.Wang@Sun.COM 	}
12749087SZhong.Wang@Sun.COM 	return (0);
12759087SZhong.Wang@Sun.COM }
12769087SZhong.Wang@Sun.COM 
12779087SZhong.Wang@Sun.COM static int
fcoe_get_port_list(fcoe_port_instance_t * ports,int count)12789087SZhong.Wang@Sun.COM fcoe_get_port_list(fcoe_port_instance_t *ports, int count)
12799087SZhong.Wang@Sun.COM {
12809087SZhong.Wang@Sun.COM 	fcoe_mac_t	*mac = NULL;
12819087SZhong.Wang@Sun.COM 	int		i = 0;
12829087SZhong.Wang@Sun.COM 
12839087SZhong.Wang@Sun.COM 	ASSERT(ports != NULL);
12849307Skelly.hu@Sun.COM 	ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex));
12859087SZhong.Wang@Sun.COM 
12869087SZhong.Wang@Sun.COM 	for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
12879087SZhong.Wang@Sun.COM 	    mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
12889087SZhong.Wang@Sun.COM 		if (i < count) {
12899087SZhong.Wang@Sun.COM 			bcopy(mac->fm_eport.eport_portwwn,
12909087SZhong.Wang@Sun.COM 			    ports[i].fpi_pwwn, 8);
12919307Skelly.hu@Sun.COM 			ports[i].fpi_mac_linkid = mac->fm_linkid;
12929087SZhong.Wang@Sun.COM 			bcopy(mac->fm_current_addr,
12939087SZhong.Wang@Sun.COM 			    ports[i].fpi_mac_current_addr, ETHERADDRL);
12949087SZhong.Wang@Sun.COM 			bcopy(mac->fm_primary_addr,
12959087SZhong.Wang@Sun.COM 			    ports[i].fpi_mac_factory_addr, ETHERADDRL);
12969087SZhong.Wang@Sun.COM 			ports[i].fpi_port_type =
12979087SZhong.Wang@Sun.COM 			    EPORT_CLT_TYPE(&mac->fm_eport);
12989087SZhong.Wang@Sun.COM 			ports[i].fpi_mtu_size =
12999087SZhong.Wang@Sun.COM 			    mac->fm_eport.eport_mtu;
13009087SZhong.Wang@Sun.COM 			ports[i].fpi_mac_promisc =
13019087SZhong.Wang@Sun.COM 			    mac->fm_promisc_handle != NULL ? 1 : 0;
13029087SZhong.Wang@Sun.COM 		}
13039087SZhong.Wang@Sun.COM 		i++;
13049087SZhong.Wang@Sun.COM 	}
13059087SZhong.Wang@Sun.COM 	return (i);
13069087SZhong.Wang@Sun.COM }
1307