12a8164dfSZhong Wang /*
22a8164dfSZhong Wang  * CDDL HEADER START
32a8164dfSZhong Wang  *
42a8164dfSZhong Wang  * The contents of this file are subject to the terms of the
52a8164dfSZhong Wang  * Common Development and Distribution License (the "License").
62a8164dfSZhong Wang  * You may not use this file except in compliance with the License.
72a8164dfSZhong Wang  *
82a8164dfSZhong Wang  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92a8164dfSZhong Wang  * or http://www.opensolaris.org/os/licensing.
102a8164dfSZhong Wang  * See the License for the specific language governing permissions
112a8164dfSZhong Wang  * and limitations under the License.
122a8164dfSZhong Wang  *
132a8164dfSZhong Wang  * When distributing Covered Code, include this CDDL HEADER in each
142a8164dfSZhong Wang  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152a8164dfSZhong Wang  * If applicable, add the following below this CDDL HEADER, with the
162a8164dfSZhong Wang  * fields enclosed by brackets "[]" replaced with your own identifying
172a8164dfSZhong Wang  * information: Portions Copyright [yyyy] [name of copyright owner]
182a8164dfSZhong Wang  *
192a8164dfSZhong Wang  * CDDL HEADER END
202a8164dfSZhong Wang  */
212a8164dfSZhong Wang /*
22*4558d122SViswanathan Kannappan  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
232a8164dfSZhong Wang  */
242a8164dfSZhong Wang 
252a8164dfSZhong Wang /*
262a8164dfSZhong Wang  * The following notice accompanied the original version of this file:
272a8164dfSZhong Wang  *
282a8164dfSZhong Wang  * BSD LICENSE
292a8164dfSZhong Wang  *
302a8164dfSZhong Wang  * Copyright(c) 2007 Intel Corporation. All rights reserved.
312a8164dfSZhong Wang  * All rights reserved.
322a8164dfSZhong Wang  *
332a8164dfSZhong Wang  * Redistribution and use in source and binary forms, with or without
342a8164dfSZhong Wang  * modification, are permitted provided that the following conditions
352a8164dfSZhong Wang  * are met:
362a8164dfSZhong Wang  *
372a8164dfSZhong Wang  *   * Redistributions of source code must retain the above copyright
382a8164dfSZhong Wang  *     notice, this list of conditions and the following disclaimer.
392a8164dfSZhong Wang  *   * Redistributions in binary form must reproduce the above copyright
402a8164dfSZhong Wang  *     notice, this list of conditions and the following disclaimer in
412a8164dfSZhong Wang  *     the documentation and/or other materials provided with the
422a8164dfSZhong Wang  *     distribution.
432a8164dfSZhong Wang  *   * Neither the name of Intel Corporation nor the names of its
442a8164dfSZhong Wang  *     contributors may be used to endorse or promote products derived
452a8164dfSZhong Wang  *     from this software without specific prior written permission.
462a8164dfSZhong Wang  *
472a8164dfSZhong Wang  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
482a8164dfSZhong Wang  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
492a8164dfSZhong Wang  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
502a8164dfSZhong Wang  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
512a8164dfSZhong Wang  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
522a8164dfSZhong Wang  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
532a8164dfSZhong Wang  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
542a8164dfSZhong Wang  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
552a8164dfSZhong Wang  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
562a8164dfSZhong Wang  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
572a8164dfSZhong Wang  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
582a8164dfSZhong Wang  */
592a8164dfSZhong Wang 
602a8164dfSZhong Wang /*
612a8164dfSZhong Wang  * Driver kernel header files
622a8164dfSZhong Wang  */
632a8164dfSZhong Wang #include <sys/conf.h>
642a8164dfSZhong Wang #include <sys/ddi.h>
652a8164dfSZhong Wang #include <sys/stat.h>
662a8164dfSZhong Wang #include <sys/pci.h>
672a8164dfSZhong Wang #include <sys/sunddi.h>
682a8164dfSZhong Wang #include <sys/modctl.h>
692a8164dfSZhong Wang #include <sys/file.h>
702a8164dfSZhong Wang #include <sys/cred.h>
712a8164dfSZhong Wang #include <sys/byteorder.h>
722a8164dfSZhong Wang #include <sys/atomic.h>
732a8164dfSZhong Wang #include <sys/modhash.h>
742a8164dfSZhong Wang #include <sys/scsi/scsi.h>
752a8164dfSZhong Wang #include <sys/ethernet.h>
762a8164dfSZhong Wang 
772a8164dfSZhong Wang /*
782a8164dfSZhong Wang  * COMSTAR header files
792a8164dfSZhong Wang  */
802a8164dfSZhong Wang #include <sys/stmf_defines.h>
812a8164dfSZhong Wang #include <sys/fct_defines.h>
822a8164dfSZhong Wang #include <sys/stmf.h>
832a8164dfSZhong Wang #include <sys/portif.h>
842a8164dfSZhong Wang #include <sys/fct.h>
852a8164dfSZhong Wang 
862a8164dfSZhong Wang /*
872a8164dfSZhong Wang  * FCoE header files
882a8164dfSZhong Wang  */
892a8164dfSZhong Wang #include <sys/fcoe/fcoe_common.h>
902a8164dfSZhong Wang 
912a8164dfSZhong Wang /*
922a8164dfSZhong Wang  * Driver's own header files
932a8164dfSZhong Wang  */
94*4558d122SViswanathan Kannappan #include "fcoet.h"
95*4558d122SViswanathan Kannappan #include "fcoet_eth.h"
96*4558d122SViswanathan Kannappan #include "fcoet_fc.h"
972a8164dfSZhong Wang 
982a8164dfSZhong Wang /*
992a8164dfSZhong Wang  * static function forward declaration
1002a8164dfSZhong Wang  */
1012a8164dfSZhong Wang static int fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1022a8164dfSZhong Wang static int fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1032a8164dfSZhong Wang static int fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp);
1042a8164dfSZhong Wang static int fcoet_close(dev_t dev, int flag, int otype, cred_t *credp);
1052a8164dfSZhong Wang static int fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
1062a8164dfSZhong Wang     cred_t *credp, int *rval);
1072a8164dfSZhong Wang static fct_status_t fcoet_attach_init(fcoet_soft_state_t *ss);
1082a8164dfSZhong Wang static fct_status_t fcoet_detach_uninit(fcoet_soft_state_t *ss);
1092a8164dfSZhong Wang static void fcoet_watchdog(void *arg);
1102a8164dfSZhong Wang static void fcoet_handle_sol_flogi(fcoet_soft_state_t *ss);
1112a8164dfSZhong Wang static stmf_data_buf_t *fcoet_dbuf_alloc(fct_local_port_t *port,
1122a8164dfSZhong Wang     uint32_t size, uint32_t *pminsize, uint32_t flags);
1132a8164dfSZhong Wang static void fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf);
1142a8164dfSZhong Wang static int fcoet_dbuf_init(fcoet_soft_state_t *ss);
1152a8164dfSZhong Wang static void fcoet_dbuf_destroy(fcoet_soft_state_t *ss);
1162a8164dfSZhong Wang static uint_t
1172a8164dfSZhong Wang fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg);
1182a8164dfSZhong Wang static uint_t
1192a8164dfSZhong Wang fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg);
1202a8164dfSZhong Wang 
1212a8164dfSZhong Wang /*
1222a8164dfSZhong Wang  * Driver identificaton stuff
1232a8164dfSZhong Wang  */
1242a8164dfSZhong Wang static struct cb_ops fcoet_cb_ops = {
1252a8164dfSZhong Wang 	fcoet_open,
1262a8164dfSZhong Wang 	fcoet_close,
1272a8164dfSZhong Wang 	nodev,
1282a8164dfSZhong Wang 	nodev,
1292a8164dfSZhong Wang 	nodev,
1302a8164dfSZhong Wang 	nodev,
1312a8164dfSZhong Wang 	nodev,
1322a8164dfSZhong Wang 	fcoet_ioctl,
1332a8164dfSZhong Wang 	nodev,
1342a8164dfSZhong Wang 	nodev,
1352a8164dfSZhong Wang 	nodev,
1362a8164dfSZhong Wang 	nochpoll,
1372a8164dfSZhong Wang 	ddi_prop_op,
1382a8164dfSZhong Wang 	0,
1392a8164dfSZhong Wang 	D_MP | D_NEW
1402a8164dfSZhong Wang };
1412a8164dfSZhong Wang 
1422a8164dfSZhong Wang static struct dev_ops fcoet_ops = {
1432a8164dfSZhong Wang 	DEVO_REV,
1442a8164dfSZhong Wang 	0,
1452a8164dfSZhong Wang 	nodev,
1462a8164dfSZhong Wang 	nulldev,
1472a8164dfSZhong Wang 	nulldev,
1482a8164dfSZhong Wang 	fcoet_attach,
1492a8164dfSZhong Wang 	fcoet_detach,
1502a8164dfSZhong Wang 	nodev,
1512a8164dfSZhong Wang 	&fcoet_cb_ops,
1522a8164dfSZhong Wang 	NULL,
1533b753e05SZhong Wang 	ddi_power,
1543b753e05SZhong Wang 	ddi_quiesce_not_needed
1552a8164dfSZhong Wang };
1562a8164dfSZhong Wang 
1572a8164dfSZhong Wang static struct modldrv modldrv = {
1582a8164dfSZhong Wang 	&mod_driverops,
1592a8164dfSZhong Wang 	FCOET_MOD_NAME,
1602a8164dfSZhong Wang 	&fcoet_ops,
1612a8164dfSZhong Wang };
1622a8164dfSZhong Wang 
1632a8164dfSZhong Wang static struct modlinkage modlinkage = {
1642a8164dfSZhong Wang 	MODREV_1, &modldrv, NULL
1652a8164dfSZhong Wang };
1662a8164dfSZhong Wang 
1672a8164dfSZhong Wang /*
1682a8164dfSZhong Wang  * Driver's global variables
1692a8164dfSZhong Wang  */
1702a8164dfSZhong Wang static kmutex_t	 fcoet_mutex;
1712a8164dfSZhong Wang static void	*fcoet_state = NULL;
1722a8164dfSZhong Wang 
1732a8164dfSZhong Wang int fcoet_use_ext_log = 1;
1742a8164dfSZhong Wang static char				 fcoet_provider_name[] = "fcoet";
1752a8164dfSZhong Wang static struct stmf_port_provider	*fcoet_pp	= NULL;
1762a8164dfSZhong Wang 
1772a8164dfSZhong Wang /*
1782a8164dfSZhong Wang  * Common loadable module entry points _init, _fini, _info
1792a8164dfSZhong Wang  */
1802a8164dfSZhong Wang 
1812a8164dfSZhong Wang int
_init(void)1822a8164dfSZhong Wang _init(void)
1832a8164dfSZhong Wang {
1842a8164dfSZhong Wang 	int ret;
1852a8164dfSZhong Wang 
1862a8164dfSZhong Wang 	ret = ddi_soft_state_init(&fcoet_state, sizeof (fcoet_soft_state_t), 0);
1872a8164dfSZhong Wang 	if (ret == 0) {
1882a8164dfSZhong Wang 		fcoet_pp = (stmf_port_provider_t *)
1892a8164dfSZhong Wang 		    stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0);
1902a8164dfSZhong Wang 		fcoet_pp->pp_portif_rev = PORTIF_REV_1;
1912a8164dfSZhong Wang 		fcoet_pp->pp_name = fcoet_provider_name;
1922a8164dfSZhong Wang 		if (stmf_register_port_provider(fcoet_pp) != STMF_SUCCESS) {
1932a8164dfSZhong Wang 			stmf_free(fcoet_pp);
1942a8164dfSZhong Wang 			ddi_soft_state_fini(&fcoet_state);
1952a8164dfSZhong Wang 			return (EIO);
1962a8164dfSZhong Wang 		}
1972a8164dfSZhong Wang 
1982a8164dfSZhong Wang 		mutex_init(&fcoet_mutex, 0, MUTEX_DRIVER, 0);
1992a8164dfSZhong Wang 		ret = mod_install(&modlinkage);
2002a8164dfSZhong Wang 		if (ret) {
201ef4cb712SZhong Wang 			(void) stmf_deregister_port_provider(fcoet_pp);
2022a8164dfSZhong Wang 			stmf_free(fcoet_pp);
2032a8164dfSZhong Wang 			mutex_destroy(&fcoet_mutex);
2042a8164dfSZhong Wang 			ddi_soft_state_fini(&fcoet_state);
2052a8164dfSZhong Wang 		}
2062a8164dfSZhong Wang 	}
2072a8164dfSZhong Wang 
2082a8164dfSZhong Wang 	FCOET_LOG("_init", "exit _init with %x", ret);
2092a8164dfSZhong Wang 	return (ret);
2102a8164dfSZhong Wang }
2112a8164dfSZhong Wang 
2122a8164dfSZhong Wang int
_fini(void)2132a8164dfSZhong Wang _fini(void)
2142a8164dfSZhong Wang {
2152a8164dfSZhong Wang 	int ret;
2162a8164dfSZhong Wang 
2172a8164dfSZhong Wang 	ret = mod_remove(&modlinkage);
2182a8164dfSZhong Wang 	if (ret == 0) {
219ef4cb712SZhong Wang 		(void) stmf_deregister_port_provider(fcoet_pp);
2202a8164dfSZhong Wang 		stmf_free(fcoet_pp);
2212a8164dfSZhong Wang 		mutex_destroy(&fcoet_mutex);
2222a8164dfSZhong Wang 		ddi_soft_state_fini(&fcoet_state);
2232a8164dfSZhong Wang 	}
2242a8164dfSZhong Wang 
2252a8164dfSZhong Wang 	FCOET_LOG("_fini", "exit _fini with %x", ret);
2262a8164dfSZhong Wang 	return (ret);
2272a8164dfSZhong Wang }
2282a8164dfSZhong Wang 
2292a8164dfSZhong Wang int
_info(struct modinfo * modinfop)2302a8164dfSZhong Wang _info(struct modinfo *modinfop)
2312a8164dfSZhong Wang {
2322a8164dfSZhong Wang 	return (mod_info(&modlinkage, modinfop));
2332a8164dfSZhong Wang }
2342a8164dfSZhong Wang 
2352a8164dfSZhong Wang /*
2362a8164dfSZhong Wang  * Autoconfiguration entry points: attach, detach, getinfo
2372a8164dfSZhong Wang  */
2382a8164dfSZhong Wang 
2392a8164dfSZhong Wang static int
fcoet_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2402a8164dfSZhong Wang fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2412a8164dfSZhong Wang {
2422a8164dfSZhong Wang 	int			 ret = DDI_FAILURE;
2432a8164dfSZhong Wang 	int			 instance;
2442a8164dfSZhong Wang 	fcoet_soft_state_t	*ss;
2452a8164dfSZhong Wang 
2462a8164dfSZhong Wang 	instance = ddi_get_instance(dip);
2472a8164dfSZhong Wang 	FCOET_LOG("fcoet_attach", "get instance %d", instance);
2482a8164dfSZhong Wang 
2492a8164dfSZhong Wang 	switch (cmd) {
2502a8164dfSZhong Wang 	case DDI_ATTACH:
2512a8164dfSZhong Wang 		ret = ddi_soft_state_zalloc(fcoet_state, instance);
2522a8164dfSZhong Wang 		if (ret != DDI_SUCCESS) {
2532a8164dfSZhong Wang 			return (ret);
2542a8164dfSZhong Wang 		}
2552a8164dfSZhong Wang 
2562a8164dfSZhong Wang 		ss = ddi_get_soft_state(fcoet_state, instance);
2572a8164dfSZhong Wang 		ss->ss_instance = instance;
2582a8164dfSZhong Wang 		ss->ss_dip = dip;
2592a8164dfSZhong Wang 
2602a8164dfSZhong Wang 		ret = fcoet_attach_init(ss);
2612a8164dfSZhong Wang 		if (ret != FCOE_SUCCESS) {
2622a8164dfSZhong Wang 			ddi_soft_state_free(fcoet_state, instance);
2632a8164dfSZhong Wang 			ret = DDI_FAILURE;
2642a8164dfSZhong Wang 		}
2652a8164dfSZhong Wang 
2662a8164dfSZhong Wang 		FCOET_LOG("fcoet_attach", "end with-%x", ret);
2672a8164dfSZhong Wang 		break;
2682a8164dfSZhong Wang 
2692a8164dfSZhong Wang 	case DDI_RESUME:
2702a8164dfSZhong Wang 		ret = DDI_SUCCESS;
2712a8164dfSZhong Wang 		break;
2722a8164dfSZhong Wang 
2732a8164dfSZhong Wang 	default:
2742a8164dfSZhong Wang 		FCOET_LOG("fcoet_attach", "unspported attach cmd-%x", cmd);
2752a8164dfSZhong Wang 		break;
2762a8164dfSZhong Wang 	}
2772a8164dfSZhong Wang 
2782a8164dfSZhong Wang 	return (ret);
2792a8164dfSZhong Wang }
2802a8164dfSZhong Wang 
2812a8164dfSZhong Wang static int
fcoet_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2822a8164dfSZhong Wang fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2832a8164dfSZhong Wang {
2842a8164dfSZhong Wang 	int			 ret = DDI_FAILURE;
2852a8164dfSZhong Wang 	int			 fcoe_ret;
2862a8164dfSZhong Wang 	int			 instance;
2872a8164dfSZhong Wang 	fcoet_soft_state_t	*ss;
2882a8164dfSZhong Wang 
2892a8164dfSZhong Wang 	instance = ddi_get_instance(dip);
2902a8164dfSZhong Wang 	ss = ddi_get_soft_state(fcoet_state, instance);
2912a8164dfSZhong Wang 	if (ss == NULL) {
2922a8164dfSZhong Wang 		return (ret);
2932a8164dfSZhong Wang 	}
2942a8164dfSZhong Wang 
2952a8164dfSZhong Wang 	switch (cmd) {
2962a8164dfSZhong Wang 	case DDI_DETACH:
2972a8164dfSZhong Wang 		fcoe_ret = fcoet_detach_uninit(ss);
2982a8164dfSZhong Wang 		if (fcoe_ret == FCOE_SUCCESS) {
2992a8164dfSZhong Wang 			ret = DDI_SUCCESS;
3002a8164dfSZhong Wang 		}
3012a8164dfSZhong Wang 
3022a8164dfSZhong Wang 		FCOET_LOG("fcoet_detach", "fcoet_detach_uninit end with-%x",
3032a8164dfSZhong Wang 		    fcoe_ret);
3042a8164dfSZhong Wang 		break;
3052a8164dfSZhong Wang 
3062a8164dfSZhong Wang 	case DDI_SUSPEND:
3072a8164dfSZhong Wang 		ret = DDI_SUCCESS;
3082a8164dfSZhong Wang 		break;
3092a8164dfSZhong Wang 
3102a8164dfSZhong Wang 	default:
3112a8164dfSZhong Wang 		FCOET_LOG("fcoet_detach", "unsupported detach cmd-%x", cmd);
3122a8164dfSZhong Wang 		break;
3132a8164dfSZhong Wang 	}
3142a8164dfSZhong Wang 
3152a8164dfSZhong Wang 	return (ret);
3162a8164dfSZhong Wang }
3172a8164dfSZhong Wang 
3182a8164dfSZhong Wang /*
3192a8164dfSZhong Wang  * Device access entry points
3202a8164dfSZhong Wang  */
3212a8164dfSZhong Wang static int
fcoet_open(dev_t * devp,int flag,int otype,cred_t * credp)3222a8164dfSZhong Wang fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp)
3232a8164dfSZhong Wang {
3242a8164dfSZhong Wang 	int			 instance;
3252a8164dfSZhong Wang 	fcoet_soft_state_t	*ss;
3262a8164dfSZhong Wang 
3272a8164dfSZhong Wang 	if (otype != OTYP_CHR) {
3282a8164dfSZhong Wang 		return (EINVAL);
3292a8164dfSZhong Wang 	}
3302a8164dfSZhong Wang 
3312a8164dfSZhong Wang 	/*
3322a8164dfSZhong Wang 	 * Since this is for debugging only, only allow root to issue ioctl now
3332a8164dfSZhong Wang 	 */
3342a8164dfSZhong Wang 	if (drv_priv(credp)) {
3352a8164dfSZhong Wang 		return (EPERM);
3362a8164dfSZhong Wang 	}
3372a8164dfSZhong Wang 
3382a8164dfSZhong Wang 	instance = (int)getminor(*devp);
3392a8164dfSZhong Wang 	ss = ddi_get_soft_state(fcoet_state, instance);
3402a8164dfSZhong Wang 	if (ss == NULL) {
3412a8164dfSZhong Wang 		return (ENXIO);
3422a8164dfSZhong Wang 	}
3432a8164dfSZhong Wang 
3442a8164dfSZhong Wang 	mutex_enter(&ss->ss_ioctl_mutex);
3452a8164dfSZhong Wang 	if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_EXCL) {
3462a8164dfSZhong Wang 		/*
3472a8164dfSZhong Wang 		 * It is already open for exclusive access.
3482a8164dfSZhong Wang 		 * So shut the door on this caller.
3492a8164dfSZhong Wang 		 */
3502a8164dfSZhong Wang 		mutex_exit(&ss->ss_ioctl_mutex);
3512a8164dfSZhong Wang 		return (EBUSY);
3522a8164dfSZhong Wang 	}
3532a8164dfSZhong Wang 
3542a8164dfSZhong Wang 	if (flag & FEXCL) {
3552a8164dfSZhong Wang 		if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) {
3562a8164dfSZhong Wang 			/*
3572a8164dfSZhong Wang 			 * Exclusive operation not possible
3582a8164dfSZhong Wang 			 * as it is already opened
3592a8164dfSZhong Wang 			 */
3602a8164dfSZhong Wang 			mutex_exit(&ss->ss_ioctl_mutex);
3612a8164dfSZhong Wang 			return (EBUSY);
3622a8164dfSZhong Wang 		}
3632a8164dfSZhong Wang 		ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_EXCL;
3642a8164dfSZhong Wang 	}
3652a8164dfSZhong Wang 	ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_OPEN;
3662a8164dfSZhong Wang 	mutex_exit(&ss->ss_ioctl_mutex);
3672a8164dfSZhong Wang 
3682a8164dfSZhong Wang 	return (0);
3692a8164dfSZhong Wang }
3702a8164dfSZhong Wang 
3712a8164dfSZhong Wang /* ARGSUSED */
3722a8164dfSZhong Wang static int
fcoet_close(dev_t dev,int flag,int otype,cred_t * credp)3732a8164dfSZhong Wang fcoet_close(dev_t dev, int flag, int otype, cred_t *credp)
3742a8164dfSZhong Wang {
3752a8164dfSZhong Wang 	int			 instance;
3762a8164dfSZhong Wang 	fcoet_soft_state_t	*ss;
3772a8164dfSZhong Wang 
3782a8164dfSZhong Wang 	if (otype != OTYP_CHR) {
3792a8164dfSZhong Wang 		return (EINVAL);
3802a8164dfSZhong Wang 	}
3812a8164dfSZhong Wang 
3822a8164dfSZhong Wang 	instance = (int)getminor(dev);
3832a8164dfSZhong Wang 	ss = ddi_get_soft_state(fcoet_state, instance);
3842a8164dfSZhong Wang 	if (ss == NULL) {
3852a8164dfSZhong Wang 		return (ENXIO);
3862a8164dfSZhong Wang 	}
3872a8164dfSZhong Wang 
3882a8164dfSZhong Wang 	mutex_enter(&ss->ss_ioctl_mutex);
3892a8164dfSZhong Wang 	if ((ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) == 0) {
3902a8164dfSZhong Wang 		mutex_exit(&ss->ss_ioctl_mutex);
3912a8164dfSZhong Wang 		return (ENODEV);
3922a8164dfSZhong Wang 	}
3932a8164dfSZhong Wang 
3942a8164dfSZhong Wang 	/*
3952a8164dfSZhong Wang 	 * It looks there's one hole here, maybe there could several concurrent
3962a8164dfSZhong Wang 	 * shareed open session, but we never check this case.
3972a8164dfSZhong Wang 	 * But it will not hurt too much, disregard it now.
3982a8164dfSZhong Wang 	 */
3992a8164dfSZhong Wang 	ss->ss_ioctl_flags &= ~FCOET_IOCTL_FLAG_MASK;
4002a8164dfSZhong Wang 	mutex_exit(&ss->ss_ioctl_mutex);
4012a8164dfSZhong Wang 
4022a8164dfSZhong Wang 	return (0);
4032a8164dfSZhong Wang }
4042a8164dfSZhong Wang 
4052a8164dfSZhong Wang /* ARGSUSED */
4062a8164dfSZhong Wang static int
fcoet_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * credp,int * rval)4072a8164dfSZhong Wang fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
4082a8164dfSZhong Wang     cred_t *credp, int *rval)
4092a8164dfSZhong Wang {
4102a8164dfSZhong Wang 	fcoet_soft_state_t	*ss;
4112a8164dfSZhong Wang 	int		 ret = 0;
4122a8164dfSZhong Wang 
4132a8164dfSZhong Wang 	if (drv_priv(credp) != 0) {
4142a8164dfSZhong Wang 		return (EPERM);
4152a8164dfSZhong Wang 	}
4162a8164dfSZhong Wang 
4172a8164dfSZhong Wang 	ss = ddi_get_soft_state(fcoet_state, (int32_t)getminor(dev));
4182a8164dfSZhong Wang 	if (ss == NULL) {
4192a8164dfSZhong Wang 		return (ENXIO);
4202a8164dfSZhong Wang 	}
4212a8164dfSZhong Wang 
4222a8164dfSZhong Wang 	switch (cmd) {
4232a8164dfSZhong Wang 	default:
4242a8164dfSZhong Wang 		FCOET_LOG("fcoet_ioctl", "ioctl-0x%02X", cmd);
4252a8164dfSZhong Wang 		ret = ENOTTY;
4262a8164dfSZhong Wang 		break;
4272a8164dfSZhong Wang 	}
4282a8164dfSZhong Wang 
4292a8164dfSZhong Wang 	*rval = ret;
4302a8164dfSZhong Wang 	return (ret);
4312a8164dfSZhong Wang }
4322a8164dfSZhong Wang 
4332a8164dfSZhong Wang static fct_status_t
fcoet_attach_init(fcoet_soft_state_t * ss)4342a8164dfSZhong Wang fcoet_attach_init(fcoet_soft_state_t *ss)
4352a8164dfSZhong Wang {
4362a8164dfSZhong Wang 	fcoe_client_t		 client_fcoet;
4372a8164dfSZhong Wang 	fcoe_port_t		*eport;
4382a8164dfSZhong Wang 	fct_local_port_t	*port;
4392a8164dfSZhong Wang 	fct_dbuf_store_t	*fds;
440*4558d122SViswanathan Kannappan 	char			 taskq_name[FCOET_TASKQ_NAME_LEN];
4412a8164dfSZhong Wang 	int			 ret;
4422a8164dfSZhong Wang 
4432a8164dfSZhong Wang 	/*
4442a8164dfSZhong Wang 	 * FCoE (fcoe is fcoet's dependent driver)
4452a8164dfSZhong Wang 	 * First we need register fcoet to FCoE as one client
4462a8164dfSZhong Wang 	 */
4472a8164dfSZhong Wang 	client_fcoet.ect_eport_flags = EPORT_FLAG_TGT_MODE |
4482a8164dfSZhong Wang 	    EPORT_FLAG_IS_DIRECT_P2P;
4492a8164dfSZhong Wang 	client_fcoet.ect_max_fc_frame_size = 2136;
4502a8164dfSZhong Wang 	client_fcoet.ect_private_frame_struct_size = sizeof (fcoet_frame_t);
4512a8164dfSZhong Wang 	client_fcoet.ect_rx_frame = fcoet_rx_frame;
4522a8164dfSZhong Wang 	client_fcoet.ect_port_event = fcoet_port_event;
4532a8164dfSZhong Wang 	client_fcoet.ect_release_sol_frame = fcoet_release_sol_frame;
4542a8164dfSZhong Wang 	client_fcoet.ect_client_port_struct = ss;
4557ff83669SZhong Wang 	client_fcoet.ect_fcoe_ver = FCOE_VER_NOW;
4567ff83669SZhong Wang 	FCOET_LOG(__FUNCTION__, "version: %x %x", FCOE_VER_NOW, fcoe_ver_now);
457d4401b99SKelly Hu 	ret = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip,
458d4401b99SKelly Hu 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1);
459d4401b99SKelly Hu 	if (ret == -1) {
460d4401b99SKelly Hu 		FCOET_LOG("fcoet_attach_init", "get mac_id failed");
4612a8164dfSZhong Wang 		return (DDI_FAILURE);
4622a8164dfSZhong Wang 	} else {
463d4401b99SKelly Hu 		client_fcoet.ect_channelid = ret;
4642a8164dfSZhong Wang 	}
465d4401b99SKelly Hu 	FCOET_LOG("fcoet_attach_init", "channel_id is %d",
466d4401b99SKelly Hu 	    client_fcoet.ect_channelid);
4672a8164dfSZhong Wang 
4682a8164dfSZhong Wang 	/*
4692a8164dfSZhong Wang 	 * It's FCoE's responsiblity to initialize eport's all elements
4702a8164dfSZhong Wang 	 */
4712a8164dfSZhong Wang 	eport = fcoe_register_client(&client_fcoet);
4722a8164dfSZhong Wang 	if (eport == NULL) {
4732a8164dfSZhong Wang 		goto fail_register_client;
4742a8164dfSZhong Wang 	}
4752a8164dfSZhong Wang 
4762a8164dfSZhong Wang 	/*
4772a8164dfSZhong Wang 	 * Now it's time to register local port to FCT
4782a8164dfSZhong Wang 	 */
4792a8164dfSZhong Wang 	if (fcoet_dbuf_init(ss) != FCOE_SUCCESS) {
4802a8164dfSZhong Wang 		goto fail_init_dbuf;
4812a8164dfSZhong Wang 	}
4822a8164dfSZhong Wang 
4832a8164dfSZhong Wang 	fds = (fct_dbuf_store_t *)fct_alloc(FCT_STRUCT_DBUF_STORE, 0, 0);
4842a8164dfSZhong Wang 	if (fds == NULL) {
4852a8164dfSZhong Wang 		goto fail_alloc_dbuf;
4862a8164dfSZhong Wang 	} else {
4872a8164dfSZhong Wang 		fds->fds_alloc_data_buf = fcoet_dbuf_alloc;
4882a8164dfSZhong Wang 		fds->fds_free_data_buf = fcoet_dbuf_free;
4892a8164dfSZhong Wang 		fds->fds_fca_private = (void *)ss;
4902a8164dfSZhong Wang 	}
4912a8164dfSZhong Wang 
4922a8164dfSZhong Wang 	port = (fct_local_port_t *)fct_alloc(FCT_STRUCT_LOCAL_PORT, 0, 0);
4932a8164dfSZhong Wang 	if (port == NULL) {
4942a8164dfSZhong Wang 		goto fail_alloc_port;
4952a8164dfSZhong Wang 	} else {
4962a8164dfSZhong Wang 		/*
4972a8164dfSZhong Wang 		 * Do ss's initialization now
4982a8164dfSZhong Wang 		 */
4992a8164dfSZhong Wang 		(void) snprintf(ss->ss_alias, sizeof (ss->ss_alias), "fcoet%d",
5002a8164dfSZhong Wang 		    ss->ss_instance);
5012a8164dfSZhong Wang 		ret = ddi_create_minor_node(ss->ss_dip, "admin",
5022a8164dfSZhong Wang 		    S_IFCHR, ss->ss_instance, DDI_NT_STMF_PP, 0);
5032a8164dfSZhong Wang 		if (ret != DDI_SUCCESS) {
5042a8164dfSZhong Wang 			goto fail_minor_node;
5052a8164dfSZhong Wang 		}
5062a8164dfSZhong Wang 
5072a8164dfSZhong Wang 		ss->ss_state = FCT_STATE_OFFLINE;
5082a8164dfSZhong Wang 		ss->ss_state_not_acked = 1;
5092a8164dfSZhong Wang 		ss->ss_flags = 0;
5102a8164dfSZhong Wang 		ss->ss_port = port;
5112a8164dfSZhong Wang 		ss->ss_eport = eport;
5122a8164dfSZhong Wang 		FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst);
5132a8164dfSZhong Wang 
5142a8164dfSZhong Wang 		ss->ss_rportid_in_dereg = 0;
5152a8164dfSZhong Wang 		ss->ss_rport_dereg_state = 0;
5162a8164dfSZhong Wang 
5172a8164dfSZhong Wang 		ss->ss_next_sol_oxid = 0xFFFF;
5182a8164dfSZhong Wang 		ss->ss_next_unsol_rxid = 0xFFFF;
5192a8164dfSZhong Wang 		ss->ss_sol_oxid_hash = mod_hash_create_idhash(
5202a8164dfSZhong Wang 		    "ss_sol_oxid_hash", FCOET_SOL_HASH_SIZE,
5212a8164dfSZhong Wang 		    mod_hash_null_valdtor);
5222a8164dfSZhong Wang 		ss->ss_unsol_rxid_hash = mod_hash_create_idhash(
5232a8164dfSZhong Wang 		    "ss_unsol_rxid_hash", FCOET_SOL_HASH_SIZE,
5242a8164dfSZhong Wang 		    mod_hash_null_valdtor);
5252a8164dfSZhong Wang 
5262a8164dfSZhong Wang 		ss->ss_watch_count = 0;
5272a8164dfSZhong Wang 		mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0);
5282a8164dfSZhong Wang 		cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL);
5292a8164dfSZhong Wang 
5302a8164dfSZhong Wang 		list_create(&ss->ss_abort_xchg_list, sizeof (fcoet_exchange_t),
5312a8164dfSZhong Wang 		    offsetof(fcoet_exchange_t, xch_abort_node));
5322a8164dfSZhong Wang 
5332a8164dfSZhong Wang 		ss->ss_sol_flogi = NULL;
5342a8164dfSZhong Wang 		ss->ss_sol_flogi_state = SFS_WAIT_LINKUP;
5352a8164dfSZhong Wang 
5362a8164dfSZhong Wang 		bzero(&ss->ss_link_info, sizeof (fct_link_info_t));
5372a8164dfSZhong Wang 
5382a8164dfSZhong Wang 		ss->ss_ioctl_flags = 0;
5392a8164dfSZhong Wang 		mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0);
5402a8164dfSZhong Wang 
5412a8164dfSZhong Wang 		ss->ss_change_state_flags = 0;
5422a8164dfSZhong Wang 	}
5432a8164dfSZhong Wang 
5442a8164dfSZhong Wang 	/*
5452a8164dfSZhong Wang 	 * Do port's initialization
5462a8164dfSZhong Wang 	 *
5472a8164dfSZhong Wang 	 * port_fct_private and port_lport have been initialized by fct_alloc
5482a8164dfSZhong Wang 	 */
5492a8164dfSZhong Wang 	port->port_fca_private = ss;
55087dcbdbdSKevin Yu 	port->port_fca_version = FCT_FCA_MODREV_1;
5512a8164dfSZhong Wang 	bcopy(ss->ss_eport->eport_nodewwn, port->port_nwwn, 8);
5522a8164dfSZhong Wang 	bcopy(ss->ss_eport->eport_portwwn, port->port_pwwn, 8);
5532a8164dfSZhong Wang 	port->port_default_alias = ss->ss_alias;
5542a8164dfSZhong Wang 	port->port_sym_node_name = NULL;
5552a8164dfSZhong Wang 	port->port_sym_port_name = NULL;
5562a8164dfSZhong Wang 
5572a8164dfSZhong Wang 	port->port_pp = fcoet_pp;
5582a8164dfSZhong Wang 
5592a8164dfSZhong Wang 	port->port_hard_address = 0;
5602a8164dfSZhong Wang 	port->port_max_logins = FCOET_MAX_LOGINS;
5612a8164dfSZhong Wang 	port->port_max_xchges = FCOET_MAX_XCHGES;
5622a8164dfSZhong Wang 	port->port_fca_fcp_cmd_size = sizeof (fcoet_exchange_t);
5632a8164dfSZhong Wang 	port->port_fca_rp_private_size = 0;
5642a8164dfSZhong Wang 	port->port_fca_sol_els_private_size = sizeof (fcoet_exchange_t);
5652a8164dfSZhong Wang 	port->port_fca_sol_ct_private_size = sizeof (fcoet_exchange_t);
5662a8164dfSZhong Wang 
5672a8164dfSZhong Wang 	port->port_fca_abort_timeout = 5 * 1000;	/* 5 seconds */
5682a8164dfSZhong Wang 	port->port_fds = fds;
5692a8164dfSZhong Wang 
5702a8164dfSZhong Wang 	port->port_get_link_info = fcoet_get_link_info;
5712a8164dfSZhong Wang 	port->port_register_remote_port = fcoet_register_remote_port;
5722a8164dfSZhong Wang 	port->port_deregister_remote_port = fcoet_deregister_remote_port;
5732a8164dfSZhong Wang 	port->port_send_cmd = fcoet_send_cmd;
5742a8164dfSZhong Wang 	port->port_xfer_scsi_data = fcoet_xfer_scsi_data;
5752a8164dfSZhong Wang 	port->port_send_cmd_response = fcoet_send_cmd_response;
5762a8164dfSZhong Wang 	port->port_abort_cmd = fcoet_abort_cmd;
5772a8164dfSZhong Wang 	port->port_ctl = fcoet_ctl;
5782a8164dfSZhong Wang 	port->port_flogi_xchg = fcoet_do_flogi;
5792a8164dfSZhong Wang 	port->port_populate_hba_details = fcoet_populate_hba_fru_details;
5802a8164dfSZhong Wang 	if (fct_register_local_port(port) != FCT_SUCCESS) {
5812a8164dfSZhong Wang 		goto fail_register_port;
5822a8164dfSZhong Wang 	}
5832a8164dfSZhong Wang 
5842a8164dfSZhong Wang 	/*
5852a8164dfSZhong Wang 	 * Start watchdog thread
5862a8164dfSZhong Wang 	 */
587*4558d122SViswanathan Kannappan 	(void) snprintf(taskq_name, sizeof (taskq_name),
588*4558d122SViswanathan Kannappan 	    "stmf_fct_fcoet_%d_taskq", ss->ss_instance);
5892a8164dfSZhong Wang 	if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL,
5902a8164dfSZhong Wang 	    taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) {
5912a8164dfSZhong Wang 		goto fail_create_taskq;
5922a8164dfSZhong Wang 	}
5932a8164dfSZhong Wang 
5942a8164dfSZhong Wang 	atomic_and_32(&ss->ss_flags, ~SS_FLAG_TERMINATE_WATCHDOG);
5952a8164dfSZhong Wang 	(void) ddi_taskq_dispatch(ss->ss_watchdog_taskq,
5962a8164dfSZhong Wang 	    fcoet_watchdog, ss, DDI_SLEEP);
5972a8164dfSZhong Wang 	while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) {
5982a8164dfSZhong Wang 		delay(10);
5992a8164dfSZhong Wang 	}
6002a8164dfSZhong Wang 
6012a8164dfSZhong Wang 	ddi_report_dev(ss->ss_dip);
6022a8164dfSZhong Wang 	return (DDI_SUCCESS);
6032a8164dfSZhong Wang 
6042a8164dfSZhong Wang fail_create_taskq:
6052a8164dfSZhong Wang 	if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
6062a8164dfSZhong Wang 		atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG);
6072a8164dfSZhong Wang 		cv_broadcast(&ss->ss_watch_cv);
6082a8164dfSZhong Wang 		while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
6092a8164dfSZhong Wang 			delay(10);
6102a8164dfSZhong Wang 		}
6112a8164dfSZhong Wang 	}
6122a8164dfSZhong Wang 
6132a8164dfSZhong Wang 	ddi_taskq_destroy(ss->ss_watchdog_taskq);
6142a8164dfSZhong Wang 	FCOET_LOG("fcoet_attach_init", "fail_register_port");
6152a8164dfSZhong Wang 
6162a8164dfSZhong Wang fail_register_port:
6172a8164dfSZhong Wang 	mutex_destroy(&ss->ss_ioctl_mutex);
6182a8164dfSZhong Wang 	mutex_destroy(&ss->ss_watch_mutex);
6192a8164dfSZhong Wang 	cv_destroy(&ss->ss_watch_cv);
6202a8164dfSZhong Wang 	mod_hash_destroy_hash(ss->ss_sol_oxid_hash);
6212a8164dfSZhong Wang 	mod_hash_destroy_hash(ss->ss_unsol_rxid_hash);
6222a8164dfSZhong Wang 	list_destroy(&ss->ss_abort_xchg_list);
6232a8164dfSZhong Wang 	FCOET_LOG("fcoet_attach_init", "fail_create_taskq");
6242a8164dfSZhong Wang 
6252a8164dfSZhong Wang fail_minor_node:
6262a8164dfSZhong Wang 	fct_free(port);
6272a8164dfSZhong Wang 	FCOET_LOG("fcoet_attach_init", "fail_minor_node");
6282a8164dfSZhong Wang 
6292a8164dfSZhong Wang fail_alloc_port:
6302a8164dfSZhong Wang 	fct_free(fds);
6312a8164dfSZhong Wang 	FCOET_LOG("fcoet_attach_init", "fail_alloc_port");
6322a8164dfSZhong Wang 
6332a8164dfSZhong Wang fail_alloc_dbuf:
6342a8164dfSZhong Wang 	fcoet_dbuf_destroy(ss);
6352a8164dfSZhong Wang 	FCOET_LOG("fcoet_attach_init", "fail_alloc_dbuf");
6362a8164dfSZhong Wang 
6372a8164dfSZhong Wang fail_init_dbuf:
6382a8164dfSZhong Wang 	ss->ss_eport->eport_deregister_client(ss->ss_eport);
6392a8164dfSZhong Wang 	FCOET_LOG("fcoet_attach_init", "fail_init_dbuf");
6402a8164dfSZhong Wang 
6412a8164dfSZhong Wang fail_register_client:
6422a8164dfSZhong Wang 	FCOET_LOG("fcoet_attach_init", "fail_register_client");
6432a8164dfSZhong Wang 	return (DDI_FAILURE);
6442a8164dfSZhong Wang }
6452a8164dfSZhong Wang 
6462a8164dfSZhong Wang static fct_status_t
fcoet_detach_uninit(fcoet_soft_state_t * ss)6472a8164dfSZhong Wang fcoet_detach_uninit(fcoet_soft_state_t *ss)
6482a8164dfSZhong Wang {
6492a8164dfSZhong Wang 	if ((ss->ss_state != FCT_STATE_OFFLINE) ||
6502a8164dfSZhong Wang 	    ss->ss_state_not_acked) {
6512a8164dfSZhong Wang 		return (FCOE_FAILURE);
6522a8164dfSZhong Wang 	}
6532a8164dfSZhong Wang 
6542a8164dfSZhong Wang 	/*
6552a8164dfSZhong Wang 	 * Avoid modunload before running fcinfo remove-target-port
6562a8164dfSZhong Wang 	 */
6572a8164dfSZhong Wang 	if (ss->ss_eport != NULL &&
6582a8164dfSZhong Wang 	    ss->ss_eport->eport_flags & EPORT_FLAG_MAC_IN_USE) {
6592a8164dfSZhong Wang 		return (FCOE_FAILURE);
6602a8164dfSZhong Wang 	}
6612a8164dfSZhong Wang 
6622a8164dfSZhong Wang 	if (ss->ss_port == NULL) {
6632a8164dfSZhong Wang 		return (FCOE_SUCCESS);
6642a8164dfSZhong Wang 	}
6652a8164dfSZhong Wang 
6662a8164dfSZhong Wang 	ss->ss_sol_oxid_hash_empty = 1;
6672a8164dfSZhong Wang 	ss->ss_unsol_rxid_hash_empty = 1;
6682a8164dfSZhong Wang 	mod_hash_walk(ss->ss_sol_oxid_hash, fcoet_sol_oxid_hash_empty, ss);
6692a8164dfSZhong Wang 	mod_hash_walk(ss->ss_unsol_rxid_hash, fcoet_unsol_rxid_hash_empty, ss);
6702a8164dfSZhong Wang 	if ((!ss->ss_sol_oxid_hash_empty) || (!ss->ss_unsol_rxid_hash_empty)) {
6712a8164dfSZhong Wang 		return (FCOE_FAILURE);
6722a8164dfSZhong Wang 	}
6732a8164dfSZhong Wang 
6742a8164dfSZhong Wang 	/*
6752a8164dfSZhong Wang 	 * We need offline the port manually, before we want to detach it
6762a8164dfSZhong Wang 	 * or it will not succeed.
6772a8164dfSZhong Wang 	 */
6782a8164dfSZhong Wang 	if (fct_deregister_local_port(ss->ss_port) != FCT_SUCCESS) {
6792a8164dfSZhong Wang 		FCOET_LOG("fcoet_detach_uninit",
6802a8164dfSZhong Wang 		    "fct_deregister_local_port failed");
6812a8164dfSZhong Wang 		return (FCOE_FAILURE);
6822a8164dfSZhong Wang 	}
6832a8164dfSZhong Wang 
6842a8164dfSZhong Wang 	/*
6852a8164dfSZhong Wang 	 * Stop watchdog
6862a8164dfSZhong Wang 	 */
6872a8164dfSZhong Wang 	if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
6882a8164dfSZhong Wang 		atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG);
6892a8164dfSZhong Wang 		cv_broadcast(&ss->ss_watch_cv);
6902a8164dfSZhong Wang 		while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
6912a8164dfSZhong Wang 			delay(10);
6922a8164dfSZhong Wang 		}
6932a8164dfSZhong Wang 	}
6942a8164dfSZhong Wang 
6952a8164dfSZhong Wang 	ddi_taskq_destroy(ss->ss_watchdog_taskq);
6962a8164dfSZhong Wang 
6972a8164dfSZhong Wang 	/*
6982a8164dfSZhong Wang 	 * Release all resources
6992a8164dfSZhong Wang 	 */
7002a8164dfSZhong Wang 	mutex_destroy(&ss->ss_ioctl_mutex);
7012a8164dfSZhong Wang 	mutex_destroy(&ss->ss_watch_mutex);
7022a8164dfSZhong Wang 	cv_destroy(&ss->ss_watch_cv);
7032a8164dfSZhong Wang 	mod_hash_destroy_hash(ss->ss_sol_oxid_hash);
7042a8164dfSZhong Wang 	mod_hash_destroy_hash(ss->ss_unsol_rxid_hash);
7052a8164dfSZhong Wang 	list_destroy(&ss->ss_abort_xchg_list);
7062a8164dfSZhong Wang 
7072a8164dfSZhong Wang 	fct_free(ss->ss_port->port_fds);
7082a8164dfSZhong Wang 	fct_free(ss->ss_port);
7092a8164dfSZhong Wang 	ss->ss_port = NULL;
7102a8164dfSZhong Wang 
7112a8164dfSZhong Wang 	fcoet_dbuf_destroy(ss);
7122a8164dfSZhong Wang 
7132a8164dfSZhong Wang 	if (ss->ss_eport != NULL &&
7142a8164dfSZhong Wang 	    ss->ss_eport->eport_deregister_client != NULL) {
7152a8164dfSZhong Wang 		ss->ss_eport->eport_deregister_client(ss->ss_eport);
7162a8164dfSZhong Wang 	}
7172a8164dfSZhong Wang 	ddi_soft_state_free(fcoet_state, ss->ss_instance);
7182a8164dfSZhong Wang 	return (FCOE_SUCCESS);
7192a8164dfSZhong Wang }
7202a8164dfSZhong Wang 
7212a8164dfSZhong Wang static void
fcoet_watchdog(void * arg)7222a8164dfSZhong Wang fcoet_watchdog(void *arg)
7232a8164dfSZhong Wang {
7242a8164dfSZhong Wang 	fcoet_soft_state_t	*ss = (fcoet_soft_state_t *)arg;
7252a8164dfSZhong Wang 	clock_t			 tmp_delay = 0;
7262a8164dfSZhong Wang 	fcoet_exchange_t	*xchg, *xchg_next;
7272a8164dfSZhong Wang 
7282a8164dfSZhong Wang 	FCOET_LOG("fcoet_watchdog", "fcoet_soft_state is %p", ss);
7292a8164dfSZhong Wang 
7302a8164dfSZhong Wang 	mutex_enter(&ss->ss_watch_mutex);
7312a8164dfSZhong Wang 	atomic_or_32(&ss->ss_flags, SS_FLAG_WATCHDOG_RUNNING);
7322a8164dfSZhong Wang 	tmp_delay = STMF_SEC2TICK(1)/2;
7332a8164dfSZhong Wang 
7342a8164dfSZhong Wang 	while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) {
7352a8164dfSZhong Wang 		ss->ss_watch_count++;
7362a8164dfSZhong Wang 
7372a8164dfSZhong Wang 		if (ss->ss_sol_flogi_state != SFS_FLOGI_DONE) {
7382a8164dfSZhong Wang 			fcoet_handle_sol_flogi(ss);
7392a8164dfSZhong Wang 		}
7402a8164dfSZhong Wang 		for (xchg = list_head(&ss->ss_abort_xchg_list); xchg; ) {
7412a8164dfSZhong Wang 			xchg_next = list_next(&ss->ss_abort_xchg_list, xchg);
7422a8164dfSZhong Wang 			if (xchg->xch_ref == 0) {
7432a8164dfSZhong Wang 				list_remove(&ss->ss_abort_xchg_list, xchg);
7442a8164dfSZhong Wang 				mutex_exit(&ss->ss_watch_mutex);
7452a8164dfSZhong Wang 				/* xchg abort done */
7462a8164dfSZhong Wang 				if (xchg->xch_dbuf_num) {
7472a8164dfSZhong Wang 					kmem_free((void*)xchg->xch_dbufs,
7482a8164dfSZhong Wang 					    xchg->xch_dbuf_num *
7492a8164dfSZhong Wang 					    sizeof (void *));
7502a8164dfSZhong Wang 					xchg->xch_dbufs = NULL;
7512a8164dfSZhong Wang 					xchg->xch_dbuf_num = 0;
7522a8164dfSZhong Wang 				}
7532a8164dfSZhong Wang 				fct_cmd_fca_aborted(xchg->xch_cmd,
7542a8164dfSZhong Wang 				    FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
7552a8164dfSZhong Wang 				mutex_enter(&ss->ss_watch_mutex);
7562a8164dfSZhong Wang 			}
7572a8164dfSZhong Wang 			xchg = xchg_next;
7582a8164dfSZhong Wang 		}
7592a8164dfSZhong Wang 
7602a8164dfSZhong Wang 		atomic_or_32(&ss->ss_flags, SS_FLAG_DOG_WAITING);
761d3d50737SRafael Vanoni 		(void) cv_reltimedwait(&ss->ss_watch_cv, &ss->ss_watch_mutex,
762d3d50737SRafael Vanoni 		    (clock_t)tmp_delay, TR_CLOCK_TICK);
7632a8164dfSZhong Wang 		atomic_and_32(&ss->ss_flags, ~SS_FLAG_DOG_WAITING);
7642a8164dfSZhong Wang 	}
7652a8164dfSZhong Wang 
7662a8164dfSZhong Wang 	/*
7672a8164dfSZhong Wang 	 * Ensure no ongoing FLOGI, before terminate the watchdog
7682a8164dfSZhong Wang 	 */
7692a8164dfSZhong Wang 	if (ss->ss_sol_flogi) {
7702a8164dfSZhong Wang 		fcoet_clear_sol_exchange(ss->ss_sol_flogi);
7712a8164dfSZhong Wang 		fct_free(ss->ss_sol_flogi->xch_cmd);
7722a8164dfSZhong Wang 		ss->ss_sol_flogi = NULL;
7732a8164dfSZhong Wang 	}
7742a8164dfSZhong Wang 
7752a8164dfSZhong Wang 	atomic_and_32(&ss->ss_flags, ~SS_FLAG_WATCHDOG_RUNNING);
7762a8164dfSZhong Wang 	mutex_exit(&ss->ss_watch_mutex);
7772a8164dfSZhong Wang }
7782a8164dfSZhong Wang 
7792a8164dfSZhong Wang static void
fcoet_handle_sol_flogi(fcoet_soft_state_t * ss)7802a8164dfSZhong Wang fcoet_handle_sol_flogi(fcoet_soft_state_t *ss)
7812a8164dfSZhong Wang {
7822a8164dfSZhong Wang 	clock_t			twosec = STMF_SEC2TICK(2);
7832a8164dfSZhong Wang 
7842a8164dfSZhong Wang check_state_again:
7852a8164dfSZhong Wang 	if (ss->ss_flags & SS_FLAG_PORT_DISABLED) {
7862a8164dfSZhong Wang 		ss->ss_sol_flogi_state = SFS_WAIT_LINKUP;
7872a8164dfSZhong Wang 	}
7882a8164dfSZhong Wang 
7892a8164dfSZhong Wang 	switch (ss->ss_sol_flogi_state) {
7902a8164dfSZhong Wang 	case SFS_WAIT_LINKUP:
7912a8164dfSZhong Wang 		if (ss->ss_sol_flogi) {
7922a8164dfSZhong Wang 			if (ss->ss_sol_flogi->xch_ref == 0) {
7932a8164dfSZhong Wang 				fcoet_clear_sol_exchange(ss->ss_sol_flogi);
7942a8164dfSZhong Wang 				fct_free(ss->ss_sol_flogi->xch_cmd);
7952a8164dfSZhong Wang 				ss->ss_sol_flogi = NULL;
7962a8164dfSZhong Wang 			}
7972a8164dfSZhong Wang 		}
7982a8164dfSZhong Wang 		break;
7992a8164dfSZhong Wang 
8002a8164dfSZhong Wang 	case SFS_FLOGI_INIT:
8012a8164dfSZhong Wang 		if (ss->ss_sol_flogi) {
8022a8164dfSZhong Wang 			/*
8032a8164dfSZhong Wang 			 * wait for the response to finish
8042a8164dfSZhong Wang 			 */
8052a8164dfSZhong Wang 			ss->ss_sol_flogi_state = SFS_CLEAR_FLOGI;
8062a8164dfSZhong Wang 			break;
8072a8164dfSZhong Wang 		}
8082a8164dfSZhong Wang 		fcoet_send_sol_flogi(ss);
8092a8164dfSZhong Wang 		ss->ss_sol_flogi_state++;
8102a8164dfSZhong Wang 		break;
8112a8164dfSZhong Wang 
8122a8164dfSZhong Wang 	case SFS_FLOGI_CHECK_TIMEOUT:
8132a8164dfSZhong Wang 		if ((ss->ss_sol_flogi->xch_start_time + twosec) <
8142a8164dfSZhong Wang 		    ddi_get_lbolt()) {
8152a8164dfSZhong Wang 			ss->ss_sol_flogi_state++;
8162a8164dfSZhong Wang 		}
8172a8164dfSZhong Wang 		break;
8182a8164dfSZhong Wang 
8192a8164dfSZhong Wang 	case SFS_ABTS_INIT:
8202a8164dfSZhong Wang 		fcoet_send_sol_abts(ss->ss_sol_flogi);
8212a8164dfSZhong Wang 		ss->ss_sol_flogi_state++;
8222a8164dfSZhong Wang 		break;
8232a8164dfSZhong Wang 
8242a8164dfSZhong Wang 	case SFS_CLEAR_FLOGI:
8252a8164dfSZhong Wang 		if (ss->ss_sol_flogi) {
8262a8164dfSZhong Wang 			if (ss->ss_sol_flogi->xch_ref) {
8272a8164dfSZhong Wang 				break;
8282a8164dfSZhong Wang 			}
8292a8164dfSZhong Wang 			fcoet_clear_sol_exchange(ss->ss_sol_flogi);
8302a8164dfSZhong Wang 			fct_free(ss->ss_sol_flogi->xch_cmd);
8312a8164dfSZhong Wang 			ss->ss_sol_flogi = NULL;
8322a8164dfSZhong Wang 		}
8332a8164dfSZhong Wang 		ss->ss_sol_flogi_state = SFS_FLOGI_INIT;
8342a8164dfSZhong Wang 		goto check_state_again;
8352a8164dfSZhong Wang 
8362a8164dfSZhong Wang 	case SFS_FLOGI_ACC:
8372a8164dfSZhong Wang 		ss->ss_sol_flogi_state++;
8382a8164dfSZhong Wang 		goto check_state_again;
8392a8164dfSZhong Wang 
8402a8164dfSZhong Wang 	case SFS_FLOGI_DONE:
8412a8164dfSZhong Wang 		if (!(ss->ss_flags & SS_FLAG_PORT_DISABLED) &&
8422a8164dfSZhong Wang 		    ss->ss_sol_flogi) {
8432a8164dfSZhong Wang 			fcoet_clear_sol_exchange(ss->ss_sol_flogi);
8442a8164dfSZhong Wang 			fct_free(ss->ss_sol_flogi->xch_cmd);
8452a8164dfSZhong Wang 			ss->ss_sol_flogi = NULL;
8462a8164dfSZhong Wang 		}
8472a8164dfSZhong Wang 
8482a8164dfSZhong Wang 		/*
8492a8164dfSZhong Wang 		 * We'd better to offline it first, and delay 0.1 seconds,
8502a8164dfSZhong Wang 		 * before we say it's on again.
8512a8164dfSZhong Wang 		 */
8522a8164dfSZhong Wang 		fct_handle_event(ss->ss_port,
8532a8164dfSZhong Wang 		    FCT_EVENT_LINK_DOWN, 0, NULL);
8542a8164dfSZhong Wang 		delay(STMF_SEC2TICK(1)/10);
8552a8164dfSZhong Wang 		fct_handle_event(ss->ss_port,
8562a8164dfSZhong Wang 		    FCT_EVENT_LINK_UP, 0, NULL);
8572a8164dfSZhong Wang 		break;
8582a8164dfSZhong Wang 
8592a8164dfSZhong Wang 	default:
8602a8164dfSZhong Wang 		ASSERT(0);
8612a8164dfSZhong Wang 		break;
8622a8164dfSZhong Wang 	}
8632a8164dfSZhong Wang }
8642a8164dfSZhong Wang 
8652a8164dfSZhong Wang /* ARGSUSED */
8662a8164dfSZhong Wang static int
fcoet_dbuf_init(fcoet_soft_state_t * ss)8672a8164dfSZhong Wang fcoet_dbuf_init(fcoet_soft_state_t *ss)
8682a8164dfSZhong Wang {
8692a8164dfSZhong Wang 	return (FCOE_SUCCESS);
8702a8164dfSZhong Wang }
8712a8164dfSZhong Wang 
8722a8164dfSZhong Wang /* ARGSUSED */
8732a8164dfSZhong Wang static void
fcoet_dbuf_destroy(fcoet_soft_state_t * ss)8742a8164dfSZhong Wang fcoet_dbuf_destroy(fcoet_soft_state_t *ss)
8752a8164dfSZhong Wang {
8762a8164dfSZhong Wang 
8772a8164dfSZhong Wang }
8782a8164dfSZhong Wang 
8792a8164dfSZhong Wang /* ARGSUSED */
8802a8164dfSZhong Wang static stmf_data_buf_t *
fcoet_dbuf_alloc(fct_local_port_t * port,uint32_t size,uint32_t * pminsize,uint32_t flags)8812a8164dfSZhong Wang fcoet_dbuf_alloc(fct_local_port_t *port, uint32_t size, uint32_t *pminsize,
8822a8164dfSZhong Wang     uint32_t flags)
8832a8164dfSZhong Wang {
8842a8164dfSZhong Wang 	stmf_data_buf_t	*dbuf;
8852a8164dfSZhong Wang 	int		 add_size;
8862a8164dfSZhong Wang 	int		 sge_num;
8872a8164dfSZhong Wang 	int		 sge_size;
8882a8164dfSZhong Wang 	int		 idx;
8892a8164dfSZhong Wang 	int		 ii;
8902a8164dfSZhong Wang 	void		*netb;
8912a8164dfSZhong Wang 	uint8_t		*fc_buf;
8922a8164dfSZhong Wang 	fcoet_soft_state_t	*ss =
8932a8164dfSZhong Wang 	    (fcoet_soft_state_t *)port->port_fca_private;
8942a8164dfSZhong Wang 
8952a8164dfSZhong Wang 	if (size > FCOET_MAX_DBUF_LEN) {
8962a8164dfSZhong Wang 		if (*pminsize > FCOET_MAX_DBUF_LEN) {
8972a8164dfSZhong Wang 			return (NULL);
8982a8164dfSZhong Wang 		}
8992a8164dfSZhong Wang 
9002a8164dfSZhong Wang 		size = FCOET_MAX_DBUF_LEN;
9012a8164dfSZhong Wang 	}
9022a8164dfSZhong Wang 
9032a8164dfSZhong Wang 	sge_num = (size - 1) / ss->ss_fcp_data_payload_size + 1;
9042a8164dfSZhong Wang 	add_size = (sge_num - 1) * sizeof (struct stmf_sglist_ent) +
9052a8164dfSZhong Wang 	    sge_num * sizeof (mblk_t *);
9062a8164dfSZhong Wang 	dbuf = stmf_alloc(STMF_STRUCT_DATA_BUF, add_size, 0);
9072a8164dfSZhong Wang 	if (dbuf == NULL) {
9082a8164dfSZhong Wang 		return (NULL);
9092a8164dfSZhong Wang 	}
9102a8164dfSZhong Wang 	dbuf->db_buf_size = size;
9112a8164dfSZhong Wang 	dbuf->db_data_size = size;
9122a8164dfSZhong Wang 	dbuf->db_sglist_length = 0;
9132a8164dfSZhong Wang 	dbuf->db_flags |= DB_DONT_REUSE;
9142a8164dfSZhong Wang 	FCOET_SET_SEG_NUM(dbuf, sge_num);
9152a8164dfSZhong Wang 
9162a8164dfSZhong Wang 	/*
9172a8164dfSZhong Wang 	 * Initialize non-last sg entries
9182a8164dfSZhong Wang 	 */
9192a8164dfSZhong Wang 	for (idx = 0; idx < sge_num - 1; idx++) {
9202a8164dfSZhong Wang 		sge_size = ss->ss_fcp_data_payload_size;
9212a8164dfSZhong Wang 		netb = ss->ss_eport->eport_alloc_netb(
9222a8164dfSZhong Wang 		    ss->ss_eport, sizeof (fcoe_fc_frame_header_t) +
9232a8164dfSZhong Wang 		    sge_size, &fc_buf);
9242a8164dfSZhong Wang 		if (netb == NULL) {
9252a8164dfSZhong Wang 			for (ii = 0; ii < idx; ii++) {
9262a8164dfSZhong Wang 				ss->ss_eport->eport_free_netb(
9272a8164dfSZhong Wang 				    FCOET_GET_NETB(dbuf, ii));
9282a8164dfSZhong Wang 			}
9292a8164dfSZhong Wang 			stmf_free(dbuf);
9302a8164dfSZhong Wang 			FCOET_LOG("fcoe_dbuf_alloc", "no netb");
9312a8164dfSZhong Wang 			return (NULL);
9322a8164dfSZhong Wang 		}
9332a8164dfSZhong Wang 		FCOET_SET_NETB(dbuf, idx, netb);
9342a8164dfSZhong Wang 		dbuf->db_sglist[idx].seg_addr = fc_buf +
9352a8164dfSZhong Wang 		    sizeof (fcoe_fc_frame_header_t);
9362a8164dfSZhong Wang 		dbuf->db_sglist[idx].seg_length = sge_size;
9372a8164dfSZhong Wang 	}
9382a8164dfSZhong Wang 
9392a8164dfSZhong Wang 	/*
9402a8164dfSZhong Wang 	 * Initialize the last sg entry
9412a8164dfSZhong Wang 	 */
9422a8164dfSZhong Wang 	if (size % ss->ss_fcp_data_payload_size) {
9432a8164dfSZhong Wang 		sge_size = P2ROUNDUP(size % ss->ss_fcp_data_payload_size, 4);
9442a8164dfSZhong Wang 	} else {
9452a8164dfSZhong Wang 		sge_size = ss->ss_fcp_data_payload_size;
9462a8164dfSZhong Wang 	}
9472a8164dfSZhong Wang 
9482a8164dfSZhong Wang 	netb = ss->ss_eport->eport_alloc_netb(
9492a8164dfSZhong Wang 	    ss->ss_eport,
9502a8164dfSZhong Wang 	    sizeof (fcoe_fc_frame_header_t) +
9512a8164dfSZhong Wang 	    sge_size, &fc_buf);
9522a8164dfSZhong Wang 	if (netb == NULL) {
9532a8164dfSZhong Wang 		for (ii = 0; ii < idx; ii++) {
9542a8164dfSZhong Wang 			ss->ss_eport->eport_free_netb(
9552a8164dfSZhong Wang 			    FCOET_GET_NETB(dbuf, ii));
9562a8164dfSZhong Wang 		}
9572a8164dfSZhong Wang 		stmf_free(dbuf);
9582a8164dfSZhong Wang 		FCOET_LOG("fcoe_dbuf_alloc", "no netb");
9592a8164dfSZhong Wang 		return (NULL);
9602a8164dfSZhong Wang 	}
9612a8164dfSZhong Wang 
9622a8164dfSZhong Wang 	FCOET_SET_NETB(dbuf, idx, netb);
9632a8164dfSZhong Wang 	dbuf->db_sglist[idx].seg_addr = fc_buf +
9642a8164dfSZhong Wang 	    sizeof (fcoe_fc_frame_header_t);
9652a8164dfSZhong Wang 	dbuf->db_sglist[idx].seg_length = sge_size;
9662a8164dfSZhong Wang 
9672a8164dfSZhong Wang 	/*
9682a8164dfSZhong Wang 	 * Let COMSTAR know how many sg entries we will use
9692a8164dfSZhong Wang 	 */
9702a8164dfSZhong Wang 	dbuf->db_sglist_length = idx + 1;
9712a8164dfSZhong Wang 
9722a8164dfSZhong Wang 	return (dbuf);
9732a8164dfSZhong Wang }
9742a8164dfSZhong Wang 
9752a8164dfSZhong Wang static void
fcoet_dbuf_free(fct_dbuf_store_t * fds,stmf_data_buf_t * dbuf)9762a8164dfSZhong Wang fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf)
9772a8164dfSZhong Wang {
9782a8164dfSZhong Wang 	int	idx;
9792a8164dfSZhong Wang 	fcoet_soft_state_t	*ss =
9802a8164dfSZhong Wang 	    (fcoet_soft_state_t *)fds->fds_fca_private;
9812a8164dfSZhong Wang 
9822a8164dfSZhong Wang 	for (idx = 0; idx < FCOET_GET_SEG_NUM(dbuf); idx++) {
9832a8164dfSZhong Wang 		if (FCOET_GET_NETB(dbuf, idx)) {
9842a8164dfSZhong Wang 			ss->ss_eport->eport_free_netb(
9852a8164dfSZhong Wang 			    FCOET_GET_NETB(dbuf, idx));
9862a8164dfSZhong Wang 		}
9872a8164dfSZhong Wang 	}
9882a8164dfSZhong Wang 
9892a8164dfSZhong Wang 	stmf_free(dbuf);
9902a8164dfSZhong Wang }
9912a8164dfSZhong Wang 
9922a8164dfSZhong Wang /*
9932a8164dfSZhong Wang  * We should have initialized fcoe_frame_t before
9942a8164dfSZhong Wang  */
9952a8164dfSZhong Wang void
fcoet_init_tfm(fcoe_frame_t * frm,fcoet_exchange_t * xch)9962a8164dfSZhong Wang fcoet_init_tfm(fcoe_frame_t *frm, fcoet_exchange_t *xch)
9972a8164dfSZhong Wang {
9982a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_fcoe_frame = frm;
9992a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_xch = xch;
10002a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_seq = NULL;
10012a8164dfSZhong Wang }
10022a8164dfSZhong Wang 
10032a8164dfSZhong Wang /* ARGSUSED */
10042a8164dfSZhong Wang static uint_t
fcoet_sol_oxid_hash_empty(mod_hash_key_t key,mod_hash_val_t * val,void * arg)10052a8164dfSZhong Wang fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
10062a8164dfSZhong Wang {
10072a8164dfSZhong Wang 	fcoet_soft_state_t	*ss = (fcoet_soft_state_t *)arg;
10082a8164dfSZhong Wang 
10092a8164dfSZhong Wang 	ss->ss_sol_oxid_hash_empty = 0;
10102a8164dfSZhong Wang 	FCOET_LOG("fcoet_sol_oxid_hash_empty", "one ongoing xch: %p", val);
10112a8164dfSZhong Wang 	return (MH_WALK_CONTINUE);
10122a8164dfSZhong Wang }
10132a8164dfSZhong Wang 
10142a8164dfSZhong Wang /* ARGSUSED */
10152a8164dfSZhong Wang static uint_t
fcoet_unsol_rxid_hash_empty(mod_hash_key_t key,mod_hash_val_t * val,void * arg)10162a8164dfSZhong Wang fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
10172a8164dfSZhong Wang {
10182a8164dfSZhong Wang 	fcoet_soft_state_t	*ss = (fcoet_soft_state_t *)arg;
10192a8164dfSZhong Wang 
10202a8164dfSZhong Wang 	ss->ss_sol_oxid_hash_empty = 0;
10212a8164dfSZhong Wang 	FCOET_LOG("fcoet_unsol_rxid_hash_empty", "one ongoing xch: %p", val);
10222a8164dfSZhong Wang 	return (MH_WALK_CONTINUE);
10232a8164dfSZhong Wang }
10242a8164dfSZhong Wang 
10252a8164dfSZhong Wang /* ARGSUSED */
10262a8164dfSZhong Wang void
fcoet_modhash_find_cb(mod_hash_key_t key,mod_hash_val_t val)10272a8164dfSZhong Wang fcoet_modhash_find_cb(mod_hash_key_t key, mod_hash_val_t val)
10282a8164dfSZhong Wang {
10292a8164dfSZhong Wang 	ASSERT(val != NULL);
10302a8164dfSZhong Wang 	fcoet_exchange_t *xch = (fcoet_exchange_t *)val;
10312a8164dfSZhong Wang 	FCOET_BUSY_XCHG(xch);
10322a8164dfSZhong Wang }
1033