xref: /onnv-gate/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c (revision 12571:05943d9c379f)
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 /*
22*12571SViswanathan.Kannappan@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
239087SZhong.Wang@Sun.COM  */
249087SZhong.Wang@Sun.COM 
259087SZhong.Wang@Sun.COM /*
269087SZhong.Wang@Sun.COM  * The following notice accompanied the original version of this file:
279087SZhong.Wang@Sun.COM  *
289087SZhong.Wang@Sun.COM  * BSD LICENSE
299087SZhong.Wang@Sun.COM  *
309087SZhong.Wang@Sun.COM  * Copyright(c) 2007 Intel Corporation. All rights reserved.
319087SZhong.Wang@Sun.COM  * All rights reserved.
329087SZhong.Wang@Sun.COM  *
339087SZhong.Wang@Sun.COM  * Redistribution and use in source and binary forms, with or without
349087SZhong.Wang@Sun.COM  * modification, are permitted provided that the following conditions
359087SZhong.Wang@Sun.COM  * are met:
369087SZhong.Wang@Sun.COM  *
379087SZhong.Wang@Sun.COM  *   * Redistributions of source code must retain the above copyright
389087SZhong.Wang@Sun.COM  *     notice, this list of conditions and the following disclaimer.
399087SZhong.Wang@Sun.COM  *   * Redistributions in binary form must reproduce the above copyright
409087SZhong.Wang@Sun.COM  *     notice, this list of conditions and the following disclaimer in
419087SZhong.Wang@Sun.COM  *     the documentation and/or other materials provided with the
429087SZhong.Wang@Sun.COM  *     distribution.
439087SZhong.Wang@Sun.COM  *   * Neither the name of Intel Corporation nor the names of its
449087SZhong.Wang@Sun.COM  *     contributors may be used to endorse or promote products derived
459087SZhong.Wang@Sun.COM  *     from this software without specific prior written permission.
469087SZhong.Wang@Sun.COM  *
479087SZhong.Wang@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
489087SZhong.Wang@Sun.COM  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
499087SZhong.Wang@Sun.COM  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
509087SZhong.Wang@Sun.COM  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
519087SZhong.Wang@Sun.COM  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
529087SZhong.Wang@Sun.COM  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
539087SZhong.Wang@Sun.COM  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
549087SZhong.Wang@Sun.COM  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
559087SZhong.Wang@Sun.COM  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
569087SZhong.Wang@Sun.COM  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
579087SZhong.Wang@Sun.COM  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
589087SZhong.Wang@Sun.COM  */
599087SZhong.Wang@Sun.COM 
609087SZhong.Wang@Sun.COM /*
619087SZhong.Wang@Sun.COM  * Driver kernel header files
629087SZhong.Wang@Sun.COM  */
639087SZhong.Wang@Sun.COM #include <sys/conf.h>
649087SZhong.Wang@Sun.COM #include <sys/ddi.h>
659087SZhong.Wang@Sun.COM #include <sys/stat.h>
669087SZhong.Wang@Sun.COM #include <sys/pci.h>
679087SZhong.Wang@Sun.COM #include <sys/sunddi.h>
689087SZhong.Wang@Sun.COM #include <sys/modctl.h>
699087SZhong.Wang@Sun.COM #include <sys/file.h>
709087SZhong.Wang@Sun.COM #include <sys/cred.h>
719087SZhong.Wang@Sun.COM #include <sys/byteorder.h>
729087SZhong.Wang@Sun.COM #include <sys/atomic.h>
739087SZhong.Wang@Sun.COM #include <sys/modhash.h>
749087SZhong.Wang@Sun.COM #include <sys/scsi/scsi.h>
759087SZhong.Wang@Sun.COM #include <sys/ethernet.h>
769087SZhong.Wang@Sun.COM 
779087SZhong.Wang@Sun.COM /*
789087SZhong.Wang@Sun.COM  * COMSTAR header files
799087SZhong.Wang@Sun.COM  */
809087SZhong.Wang@Sun.COM #include <sys/stmf_defines.h>
819087SZhong.Wang@Sun.COM #include <sys/fct_defines.h>
829087SZhong.Wang@Sun.COM #include <sys/stmf.h>
839087SZhong.Wang@Sun.COM #include <sys/portif.h>
849087SZhong.Wang@Sun.COM #include <sys/fct.h>
859087SZhong.Wang@Sun.COM 
869087SZhong.Wang@Sun.COM /*
879087SZhong.Wang@Sun.COM  * FCoE header files
889087SZhong.Wang@Sun.COM  */
899087SZhong.Wang@Sun.COM #include <sys/fcoe/fcoe_common.h>
909087SZhong.Wang@Sun.COM 
919087SZhong.Wang@Sun.COM /*
929087SZhong.Wang@Sun.COM  * Driver's own header files
939087SZhong.Wang@Sun.COM  */
94*12571SViswanathan.Kannappan@Sun.COM #include "fcoet.h"
95*12571SViswanathan.Kannappan@Sun.COM #include "fcoet_eth.h"
96*12571SViswanathan.Kannappan@Sun.COM #include "fcoet_fc.h"
979087SZhong.Wang@Sun.COM 
989087SZhong.Wang@Sun.COM /*
999087SZhong.Wang@Sun.COM  * static function forward declaration
1009087SZhong.Wang@Sun.COM  */
1019087SZhong.Wang@Sun.COM static int fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1029087SZhong.Wang@Sun.COM static int fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1039087SZhong.Wang@Sun.COM static int fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp);
1049087SZhong.Wang@Sun.COM static int fcoet_close(dev_t dev, int flag, int otype, cred_t *credp);
1059087SZhong.Wang@Sun.COM static int fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
1069087SZhong.Wang@Sun.COM     cred_t *credp, int *rval);
1079087SZhong.Wang@Sun.COM static fct_status_t fcoet_attach_init(fcoet_soft_state_t *ss);
1089087SZhong.Wang@Sun.COM static fct_status_t fcoet_detach_uninit(fcoet_soft_state_t *ss);
1099087SZhong.Wang@Sun.COM static void fcoet_watchdog(void *arg);
1109087SZhong.Wang@Sun.COM static void fcoet_handle_sol_flogi(fcoet_soft_state_t *ss);
1119087SZhong.Wang@Sun.COM static stmf_data_buf_t *fcoet_dbuf_alloc(fct_local_port_t *port,
1129087SZhong.Wang@Sun.COM     uint32_t size, uint32_t *pminsize, uint32_t flags);
1139087SZhong.Wang@Sun.COM static void fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf);
1149087SZhong.Wang@Sun.COM static int fcoet_dbuf_init(fcoet_soft_state_t *ss);
1159087SZhong.Wang@Sun.COM static void fcoet_dbuf_destroy(fcoet_soft_state_t *ss);
1169087SZhong.Wang@Sun.COM static uint_t
1179087SZhong.Wang@Sun.COM fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg);
1189087SZhong.Wang@Sun.COM static uint_t
1199087SZhong.Wang@Sun.COM fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg);
1209087SZhong.Wang@Sun.COM 
1219087SZhong.Wang@Sun.COM /*
1229087SZhong.Wang@Sun.COM  * Driver identificaton stuff
1239087SZhong.Wang@Sun.COM  */
1249087SZhong.Wang@Sun.COM static struct cb_ops fcoet_cb_ops = {
1259087SZhong.Wang@Sun.COM 	fcoet_open,
1269087SZhong.Wang@Sun.COM 	fcoet_close,
1279087SZhong.Wang@Sun.COM 	nodev,
1289087SZhong.Wang@Sun.COM 	nodev,
1299087SZhong.Wang@Sun.COM 	nodev,
1309087SZhong.Wang@Sun.COM 	nodev,
1319087SZhong.Wang@Sun.COM 	nodev,
1329087SZhong.Wang@Sun.COM 	fcoet_ioctl,
1339087SZhong.Wang@Sun.COM 	nodev,
1349087SZhong.Wang@Sun.COM 	nodev,
1359087SZhong.Wang@Sun.COM 	nodev,
1369087SZhong.Wang@Sun.COM 	nochpoll,
1379087SZhong.Wang@Sun.COM 	ddi_prop_op,
1389087SZhong.Wang@Sun.COM 	0,
1399087SZhong.Wang@Sun.COM 	D_MP | D_NEW
1409087SZhong.Wang@Sun.COM };
1419087SZhong.Wang@Sun.COM 
1429087SZhong.Wang@Sun.COM static struct dev_ops fcoet_ops = {
1439087SZhong.Wang@Sun.COM 	DEVO_REV,
1449087SZhong.Wang@Sun.COM 	0,
1459087SZhong.Wang@Sun.COM 	nodev,
1469087SZhong.Wang@Sun.COM 	nulldev,
1479087SZhong.Wang@Sun.COM 	nulldev,
1489087SZhong.Wang@Sun.COM 	fcoet_attach,
1499087SZhong.Wang@Sun.COM 	fcoet_detach,
1509087SZhong.Wang@Sun.COM 	nodev,
1519087SZhong.Wang@Sun.COM 	&fcoet_cb_ops,
1529087SZhong.Wang@Sun.COM 	NULL,
1539328SZhong.Wang@Sun.COM 	ddi_power,
1549328SZhong.Wang@Sun.COM 	ddi_quiesce_not_needed
1559087SZhong.Wang@Sun.COM };
1569087SZhong.Wang@Sun.COM 
1579087SZhong.Wang@Sun.COM static struct modldrv modldrv = {
1589087SZhong.Wang@Sun.COM 	&mod_driverops,
1599087SZhong.Wang@Sun.COM 	FCOET_MOD_NAME,
1609087SZhong.Wang@Sun.COM 	&fcoet_ops,
1619087SZhong.Wang@Sun.COM };
1629087SZhong.Wang@Sun.COM 
1639087SZhong.Wang@Sun.COM static struct modlinkage modlinkage = {
1649087SZhong.Wang@Sun.COM 	MODREV_1, &modldrv, NULL
1659087SZhong.Wang@Sun.COM };
1669087SZhong.Wang@Sun.COM 
1679087SZhong.Wang@Sun.COM /*
1689087SZhong.Wang@Sun.COM  * Driver's global variables
1699087SZhong.Wang@Sun.COM  */
1709087SZhong.Wang@Sun.COM static kmutex_t	 fcoet_mutex;
1719087SZhong.Wang@Sun.COM static void	*fcoet_state = NULL;
1729087SZhong.Wang@Sun.COM 
1739087SZhong.Wang@Sun.COM int fcoet_use_ext_log = 1;
1749087SZhong.Wang@Sun.COM static char				 fcoet_provider_name[] = "fcoet";
1759087SZhong.Wang@Sun.COM static struct stmf_port_provider	*fcoet_pp	= NULL;
1769087SZhong.Wang@Sun.COM 
1779087SZhong.Wang@Sun.COM /*
1789087SZhong.Wang@Sun.COM  * Common loadable module entry points _init, _fini, _info
1799087SZhong.Wang@Sun.COM  */
1809087SZhong.Wang@Sun.COM 
1819087SZhong.Wang@Sun.COM int
_init(void)1829087SZhong.Wang@Sun.COM _init(void)
1839087SZhong.Wang@Sun.COM {
1849087SZhong.Wang@Sun.COM 	int ret;
1859087SZhong.Wang@Sun.COM 
1869087SZhong.Wang@Sun.COM 	ret = ddi_soft_state_init(&fcoet_state, sizeof (fcoet_soft_state_t), 0);
1879087SZhong.Wang@Sun.COM 	if (ret == 0) {
1889087SZhong.Wang@Sun.COM 		fcoet_pp = (stmf_port_provider_t *)
1899087SZhong.Wang@Sun.COM 		    stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0);
1909087SZhong.Wang@Sun.COM 		fcoet_pp->pp_portif_rev = PORTIF_REV_1;
1919087SZhong.Wang@Sun.COM 		fcoet_pp->pp_name = fcoet_provider_name;
1929087SZhong.Wang@Sun.COM 		if (stmf_register_port_provider(fcoet_pp) != STMF_SUCCESS) {
1939087SZhong.Wang@Sun.COM 			stmf_free(fcoet_pp);
1949087SZhong.Wang@Sun.COM 			ddi_soft_state_fini(&fcoet_state);
1959087SZhong.Wang@Sun.COM 			return (EIO);
1969087SZhong.Wang@Sun.COM 		}
1979087SZhong.Wang@Sun.COM 
1989087SZhong.Wang@Sun.COM 		mutex_init(&fcoet_mutex, 0, MUTEX_DRIVER, 0);
1999087SZhong.Wang@Sun.COM 		ret = mod_install(&modlinkage);
2009087SZhong.Wang@Sun.COM 		if (ret) {
20110767SZhong.Wang@Sun.COM 			(void) stmf_deregister_port_provider(fcoet_pp);
2029087SZhong.Wang@Sun.COM 			stmf_free(fcoet_pp);
2039087SZhong.Wang@Sun.COM 			mutex_destroy(&fcoet_mutex);
2049087SZhong.Wang@Sun.COM 			ddi_soft_state_fini(&fcoet_state);
2059087SZhong.Wang@Sun.COM 		}
2069087SZhong.Wang@Sun.COM 	}
2079087SZhong.Wang@Sun.COM 
2089087SZhong.Wang@Sun.COM 	FCOET_LOG("_init", "exit _init with %x", ret);
2099087SZhong.Wang@Sun.COM 	return (ret);
2109087SZhong.Wang@Sun.COM }
2119087SZhong.Wang@Sun.COM 
2129087SZhong.Wang@Sun.COM int
_fini(void)2139087SZhong.Wang@Sun.COM _fini(void)
2149087SZhong.Wang@Sun.COM {
2159087SZhong.Wang@Sun.COM 	int ret;
2169087SZhong.Wang@Sun.COM 
2179087SZhong.Wang@Sun.COM 	ret = mod_remove(&modlinkage);
2189087SZhong.Wang@Sun.COM 	if (ret == 0) {
21910767SZhong.Wang@Sun.COM 		(void) stmf_deregister_port_provider(fcoet_pp);
2209087SZhong.Wang@Sun.COM 		stmf_free(fcoet_pp);
2219087SZhong.Wang@Sun.COM 		mutex_destroy(&fcoet_mutex);
2229087SZhong.Wang@Sun.COM 		ddi_soft_state_fini(&fcoet_state);
2239087SZhong.Wang@Sun.COM 	}
2249087SZhong.Wang@Sun.COM 
2259087SZhong.Wang@Sun.COM 	FCOET_LOG("_fini", "exit _fini with %x", ret);
2269087SZhong.Wang@Sun.COM 	return (ret);
2279087SZhong.Wang@Sun.COM }
2289087SZhong.Wang@Sun.COM 
2299087SZhong.Wang@Sun.COM int
_info(struct modinfo * modinfop)2309087SZhong.Wang@Sun.COM _info(struct modinfo *modinfop)
2319087SZhong.Wang@Sun.COM {
2329087SZhong.Wang@Sun.COM 	return (mod_info(&modlinkage, modinfop));
2339087SZhong.Wang@Sun.COM }
2349087SZhong.Wang@Sun.COM 
2359087SZhong.Wang@Sun.COM /*
2369087SZhong.Wang@Sun.COM  * Autoconfiguration entry points: attach, detach, getinfo
2379087SZhong.Wang@Sun.COM  */
2389087SZhong.Wang@Sun.COM 
2399087SZhong.Wang@Sun.COM static int
fcoet_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2409087SZhong.Wang@Sun.COM fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2419087SZhong.Wang@Sun.COM {
2429087SZhong.Wang@Sun.COM 	int			 ret = DDI_FAILURE;
2439087SZhong.Wang@Sun.COM 	int			 instance;
2449087SZhong.Wang@Sun.COM 	fcoet_soft_state_t	*ss;
2459087SZhong.Wang@Sun.COM 
2469087SZhong.Wang@Sun.COM 	instance = ddi_get_instance(dip);
2479087SZhong.Wang@Sun.COM 	FCOET_LOG("fcoet_attach", "get instance %d", instance);
2489087SZhong.Wang@Sun.COM 
2499087SZhong.Wang@Sun.COM 	switch (cmd) {
2509087SZhong.Wang@Sun.COM 	case DDI_ATTACH:
2519087SZhong.Wang@Sun.COM 		ret = ddi_soft_state_zalloc(fcoet_state, instance);
2529087SZhong.Wang@Sun.COM 		if (ret != DDI_SUCCESS) {
2539087SZhong.Wang@Sun.COM 			return (ret);
2549087SZhong.Wang@Sun.COM 		}
2559087SZhong.Wang@Sun.COM 
2569087SZhong.Wang@Sun.COM 		ss = ddi_get_soft_state(fcoet_state, instance);
2579087SZhong.Wang@Sun.COM 		ss->ss_instance = instance;
2589087SZhong.Wang@Sun.COM 		ss->ss_dip = dip;
2599087SZhong.Wang@Sun.COM 
2609087SZhong.Wang@Sun.COM 		ret = fcoet_attach_init(ss);
2619087SZhong.Wang@Sun.COM 		if (ret != FCOE_SUCCESS) {
2629087SZhong.Wang@Sun.COM 			ddi_soft_state_free(fcoet_state, instance);
2639087SZhong.Wang@Sun.COM 			ret = DDI_FAILURE;
2649087SZhong.Wang@Sun.COM 		}
2659087SZhong.Wang@Sun.COM 
2669087SZhong.Wang@Sun.COM 		FCOET_LOG("fcoet_attach", "end with-%x", ret);
2679087SZhong.Wang@Sun.COM 		break;
2689087SZhong.Wang@Sun.COM 
2699087SZhong.Wang@Sun.COM 	case DDI_RESUME:
2709087SZhong.Wang@Sun.COM 		ret = DDI_SUCCESS;
2719087SZhong.Wang@Sun.COM 		break;
2729087SZhong.Wang@Sun.COM 
2739087SZhong.Wang@Sun.COM 	default:
2749087SZhong.Wang@Sun.COM 		FCOET_LOG("fcoet_attach", "unspported attach cmd-%x", cmd);
2759087SZhong.Wang@Sun.COM 		break;
2769087SZhong.Wang@Sun.COM 	}
2779087SZhong.Wang@Sun.COM 
2789087SZhong.Wang@Sun.COM 	return (ret);
2799087SZhong.Wang@Sun.COM }
2809087SZhong.Wang@Sun.COM 
2819087SZhong.Wang@Sun.COM static int
fcoet_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2829087SZhong.Wang@Sun.COM fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2839087SZhong.Wang@Sun.COM {
2849087SZhong.Wang@Sun.COM 	int			 ret = DDI_FAILURE;
2859087SZhong.Wang@Sun.COM 	int			 fcoe_ret;
2869087SZhong.Wang@Sun.COM 	int			 instance;
2879087SZhong.Wang@Sun.COM 	fcoet_soft_state_t	*ss;
2889087SZhong.Wang@Sun.COM 
2899087SZhong.Wang@Sun.COM 	instance = ddi_get_instance(dip);
2909087SZhong.Wang@Sun.COM 	ss = ddi_get_soft_state(fcoet_state, instance);
2919087SZhong.Wang@Sun.COM 	if (ss == NULL) {
2929087SZhong.Wang@Sun.COM 		return (ret);
2939087SZhong.Wang@Sun.COM 	}
2949087SZhong.Wang@Sun.COM 
2959087SZhong.Wang@Sun.COM 	switch (cmd) {
2969087SZhong.Wang@Sun.COM 	case DDI_DETACH:
2979087SZhong.Wang@Sun.COM 		fcoe_ret = fcoet_detach_uninit(ss);
2989087SZhong.Wang@Sun.COM 		if (fcoe_ret == FCOE_SUCCESS) {
2999087SZhong.Wang@Sun.COM 			ret = DDI_SUCCESS;
3009087SZhong.Wang@Sun.COM 		}
3019087SZhong.Wang@Sun.COM 
3029087SZhong.Wang@Sun.COM 		FCOET_LOG("fcoet_detach", "fcoet_detach_uninit end with-%x",
3039087SZhong.Wang@Sun.COM 		    fcoe_ret);
3049087SZhong.Wang@Sun.COM 		break;
3059087SZhong.Wang@Sun.COM 
3069087SZhong.Wang@Sun.COM 	case DDI_SUSPEND:
3079087SZhong.Wang@Sun.COM 		ret = DDI_SUCCESS;
3089087SZhong.Wang@Sun.COM 		break;
3099087SZhong.Wang@Sun.COM 
3109087SZhong.Wang@Sun.COM 	default:
3119087SZhong.Wang@Sun.COM 		FCOET_LOG("fcoet_detach", "unsupported detach cmd-%x", cmd);
3129087SZhong.Wang@Sun.COM 		break;
3139087SZhong.Wang@Sun.COM 	}
3149087SZhong.Wang@Sun.COM 
3159087SZhong.Wang@Sun.COM 	return (ret);
3169087SZhong.Wang@Sun.COM }
3179087SZhong.Wang@Sun.COM 
3189087SZhong.Wang@Sun.COM /*
3199087SZhong.Wang@Sun.COM  * Device access entry points
3209087SZhong.Wang@Sun.COM  */
3219087SZhong.Wang@Sun.COM static int
fcoet_open(dev_t * devp,int flag,int otype,cred_t * credp)3229087SZhong.Wang@Sun.COM fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp)
3239087SZhong.Wang@Sun.COM {
3249087SZhong.Wang@Sun.COM 	int			 instance;
3259087SZhong.Wang@Sun.COM 	fcoet_soft_state_t	*ss;
3269087SZhong.Wang@Sun.COM 
3279087SZhong.Wang@Sun.COM 	if (otype != OTYP_CHR) {
3289087SZhong.Wang@Sun.COM 		return (EINVAL);
3299087SZhong.Wang@Sun.COM 	}
3309087SZhong.Wang@Sun.COM 
3319087SZhong.Wang@Sun.COM 	/*
3329087SZhong.Wang@Sun.COM 	 * Since this is for debugging only, only allow root to issue ioctl now
3339087SZhong.Wang@Sun.COM 	 */
3349087SZhong.Wang@Sun.COM 	if (drv_priv(credp)) {
3359087SZhong.Wang@Sun.COM 		return (EPERM);
3369087SZhong.Wang@Sun.COM 	}
3379087SZhong.Wang@Sun.COM 
3389087SZhong.Wang@Sun.COM 	instance = (int)getminor(*devp);
3399087SZhong.Wang@Sun.COM 	ss = ddi_get_soft_state(fcoet_state, instance);
3409087SZhong.Wang@Sun.COM 	if (ss == NULL) {
3419087SZhong.Wang@Sun.COM 		return (ENXIO);
3429087SZhong.Wang@Sun.COM 	}
3439087SZhong.Wang@Sun.COM 
3449087SZhong.Wang@Sun.COM 	mutex_enter(&ss->ss_ioctl_mutex);
3459087SZhong.Wang@Sun.COM 	if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_EXCL) {
3469087SZhong.Wang@Sun.COM 		/*
3479087SZhong.Wang@Sun.COM 		 * It is already open for exclusive access.
3489087SZhong.Wang@Sun.COM 		 * So shut the door on this caller.
3499087SZhong.Wang@Sun.COM 		 */
3509087SZhong.Wang@Sun.COM 		mutex_exit(&ss->ss_ioctl_mutex);
3519087SZhong.Wang@Sun.COM 		return (EBUSY);
3529087SZhong.Wang@Sun.COM 	}
3539087SZhong.Wang@Sun.COM 
3549087SZhong.Wang@Sun.COM 	if (flag & FEXCL) {
3559087SZhong.Wang@Sun.COM 		if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) {
3569087SZhong.Wang@Sun.COM 			/*
3579087SZhong.Wang@Sun.COM 			 * Exclusive operation not possible
3589087SZhong.Wang@Sun.COM 			 * as it is already opened
3599087SZhong.Wang@Sun.COM 			 */
3609087SZhong.Wang@Sun.COM 			mutex_exit(&ss->ss_ioctl_mutex);
3619087SZhong.Wang@Sun.COM 			return (EBUSY);
3629087SZhong.Wang@Sun.COM 		}
3639087SZhong.Wang@Sun.COM 		ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_EXCL;
3649087SZhong.Wang@Sun.COM 	}
3659087SZhong.Wang@Sun.COM 	ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_OPEN;
3669087SZhong.Wang@Sun.COM 	mutex_exit(&ss->ss_ioctl_mutex);
3679087SZhong.Wang@Sun.COM 
3689087SZhong.Wang@Sun.COM 	return (0);
3699087SZhong.Wang@Sun.COM }
3709087SZhong.Wang@Sun.COM 
3719087SZhong.Wang@Sun.COM /* ARGSUSED */
3729087SZhong.Wang@Sun.COM static int
fcoet_close(dev_t dev,int flag,int otype,cred_t * credp)3739087SZhong.Wang@Sun.COM fcoet_close(dev_t dev, int flag, int otype, cred_t *credp)
3749087SZhong.Wang@Sun.COM {
3759087SZhong.Wang@Sun.COM 	int			 instance;
3769087SZhong.Wang@Sun.COM 	fcoet_soft_state_t	*ss;
3779087SZhong.Wang@Sun.COM 
3789087SZhong.Wang@Sun.COM 	if (otype != OTYP_CHR) {
3799087SZhong.Wang@Sun.COM 		return (EINVAL);
3809087SZhong.Wang@Sun.COM 	}
3819087SZhong.Wang@Sun.COM 
3829087SZhong.Wang@Sun.COM 	instance = (int)getminor(dev);
3839087SZhong.Wang@Sun.COM 	ss = ddi_get_soft_state(fcoet_state, instance);
3849087SZhong.Wang@Sun.COM 	if (ss == NULL) {
3859087SZhong.Wang@Sun.COM 		return (ENXIO);
3869087SZhong.Wang@Sun.COM 	}
3879087SZhong.Wang@Sun.COM 
3889087SZhong.Wang@Sun.COM 	mutex_enter(&ss->ss_ioctl_mutex);
3899087SZhong.Wang@Sun.COM 	if ((ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) == 0) {
3909087SZhong.Wang@Sun.COM 		mutex_exit(&ss->ss_ioctl_mutex);
3919087SZhong.Wang@Sun.COM 		return (ENODEV);
3929087SZhong.Wang@Sun.COM 	}
3939087SZhong.Wang@Sun.COM 
3949087SZhong.Wang@Sun.COM 	/*
3959087SZhong.Wang@Sun.COM 	 * It looks there's one hole here, maybe there could several concurrent
3969087SZhong.Wang@Sun.COM 	 * shareed open session, but we never check this case.
3979087SZhong.Wang@Sun.COM 	 * But it will not hurt too much, disregard it now.
3989087SZhong.Wang@Sun.COM 	 */
3999087SZhong.Wang@Sun.COM 	ss->ss_ioctl_flags &= ~FCOET_IOCTL_FLAG_MASK;
4009087SZhong.Wang@Sun.COM 	mutex_exit(&ss->ss_ioctl_mutex);
4019087SZhong.Wang@Sun.COM 
4029087SZhong.Wang@Sun.COM 	return (0);
4039087SZhong.Wang@Sun.COM }
4049087SZhong.Wang@Sun.COM 
4059087SZhong.Wang@Sun.COM /* ARGSUSED */
4069087SZhong.Wang@Sun.COM static int
fcoet_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * credp,int * rval)4079087SZhong.Wang@Sun.COM fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
4089087SZhong.Wang@Sun.COM     cred_t *credp, int *rval)
4099087SZhong.Wang@Sun.COM {
4109087SZhong.Wang@Sun.COM 	fcoet_soft_state_t	*ss;
4119087SZhong.Wang@Sun.COM 	int		 ret = 0;
4129087SZhong.Wang@Sun.COM 
4139087SZhong.Wang@Sun.COM 	if (drv_priv(credp) != 0) {
4149087SZhong.Wang@Sun.COM 		return (EPERM);
4159087SZhong.Wang@Sun.COM 	}
4169087SZhong.Wang@Sun.COM 
4179087SZhong.Wang@Sun.COM 	ss = ddi_get_soft_state(fcoet_state, (int32_t)getminor(dev));
4189087SZhong.Wang@Sun.COM 	if (ss == NULL) {
4199087SZhong.Wang@Sun.COM 		return (ENXIO);
4209087SZhong.Wang@Sun.COM 	}
4219087SZhong.Wang@Sun.COM 
4229087SZhong.Wang@Sun.COM 	switch (cmd) {
4239087SZhong.Wang@Sun.COM 	default:
4249087SZhong.Wang@Sun.COM 		FCOET_LOG("fcoet_ioctl", "ioctl-0x%02X", cmd);
4259087SZhong.Wang@Sun.COM 		ret = ENOTTY;
4269087SZhong.Wang@Sun.COM 		break;
4279087SZhong.Wang@Sun.COM 	}
4289087SZhong.Wang@Sun.COM 
4299087SZhong.Wang@Sun.COM 	*rval = ret;
4309087SZhong.Wang@Sun.COM 	return (ret);
4319087SZhong.Wang@Sun.COM }
4329087SZhong.Wang@Sun.COM 
4339087SZhong.Wang@Sun.COM static fct_status_t
fcoet_attach_init(fcoet_soft_state_t * ss)4349087SZhong.Wang@Sun.COM fcoet_attach_init(fcoet_soft_state_t *ss)
4359087SZhong.Wang@Sun.COM {
4369087SZhong.Wang@Sun.COM 	fcoe_client_t		 client_fcoet;
4379087SZhong.Wang@Sun.COM 	fcoe_port_t		*eport;
4389087SZhong.Wang@Sun.COM 	fct_local_port_t	*port;
4399087SZhong.Wang@Sun.COM 	fct_dbuf_store_t	*fds;
440*12571SViswanathan.Kannappan@Sun.COM 	char			 taskq_name[FCOET_TASKQ_NAME_LEN];
4419087SZhong.Wang@Sun.COM 	int			 ret;
4429087SZhong.Wang@Sun.COM 
4439087SZhong.Wang@Sun.COM 	/*
4449087SZhong.Wang@Sun.COM 	 * FCoE (fcoe is fcoet's dependent driver)
4459087SZhong.Wang@Sun.COM 	 * First we need register fcoet to FCoE as one client
4469087SZhong.Wang@Sun.COM 	 */
4479087SZhong.Wang@Sun.COM 	client_fcoet.ect_eport_flags = EPORT_FLAG_TGT_MODE |
4489087SZhong.Wang@Sun.COM 	    EPORT_FLAG_IS_DIRECT_P2P;
4499087SZhong.Wang@Sun.COM 	client_fcoet.ect_max_fc_frame_size = 2136;
4509087SZhong.Wang@Sun.COM 	client_fcoet.ect_private_frame_struct_size = sizeof (fcoet_frame_t);
4519087SZhong.Wang@Sun.COM 	client_fcoet.ect_rx_frame = fcoet_rx_frame;
4529087SZhong.Wang@Sun.COM 	client_fcoet.ect_port_event = fcoet_port_event;
4539087SZhong.Wang@Sun.COM 	client_fcoet.ect_release_sol_frame = fcoet_release_sol_frame;
4549087SZhong.Wang@Sun.COM 	client_fcoet.ect_client_port_struct = ss;
45510264SZhong.Wang@Sun.COM 	client_fcoet.ect_fcoe_ver = FCOE_VER_NOW;
45610264SZhong.Wang@Sun.COM 	FCOET_LOG(__FUNCTION__, "version: %x %x", FCOE_VER_NOW, fcoe_ver_now);
4579307Skelly.hu@Sun.COM 	ret = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip,
4589307Skelly.hu@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1);
4599307Skelly.hu@Sun.COM 	if (ret == -1) {
4609307Skelly.hu@Sun.COM 		FCOET_LOG("fcoet_attach_init", "get mac_id failed");
4619087SZhong.Wang@Sun.COM 		return (DDI_FAILURE);
4629087SZhong.Wang@Sun.COM 	} else {
4639307Skelly.hu@Sun.COM 		client_fcoet.ect_channelid = ret;
4649087SZhong.Wang@Sun.COM 	}
4659307Skelly.hu@Sun.COM 	FCOET_LOG("fcoet_attach_init", "channel_id is %d",
4669307Skelly.hu@Sun.COM 	    client_fcoet.ect_channelid);
4679087SZhong.Wang@Sun.COM 
4689087SZhong.Wang@Sun.COM 	/*
4699087SZhong.Wang@Sun.COM 	 * It's FCoE's responsiblity to initialize eport's all elements
4709087SZhong.Wang@Sun.COM 	 */
4719087SZhong.Wang@Sun.COM 	eport = fcoe_register_client(&client_fcoet);
4729087SZhong.Wang@Sun.COM 	if (eport == NULL) {
4739087SZhong.Wang@Sun.COM 		goto fail_register_client;
4749087SZhong.Wang@Sun.COM 	}
4759087SZhong.Wang@Sun.COM 
4769087SZhong.Wang@Sun.COM 	/*
4779087SZhong.Wang@Sun.COM 	 * Now it's time to register local port to FCT
4789087SZhong.Wang@Sun.COM 	 */
4799087SZhong.Wang@Sun.COM 	if (fcoet_dbuf_init(ss) != FCOE_SUCCESS) {
4809087SZhong.Wang@Sun.COM 		goto fail_init_dbuf;
4819087SZhong.Wang@Sun.COM 	}
4829087SZhong.Wang@Sun.COM 
4839087SZhong.Wang@Sun.COM 	fds = (fct_dbuf_store_t *)fct_alloc(FCT_STRUCT_DBUF_STORE, 0, 0);
4849087SZhong.Wang@Sun.COM 	if (fds == NULL) {
4859087SZhong.Wang@Sun.COM 		goto fail_alloc_dbuf;
4869087SZhong.Wang@Sun.COM 	} else {
4879087SZhong.Wang@Sun.COM 		fds->fds_alloc_data_buf = fcoet_dbuf_alloc;
4889087SZhong.Wang@Sun.COM 		fds->fds_free_data_buf = fcoet_dbuf_free;
4899087SZhong.Wang@Sun.COM 		fds->fds_fca_private = (void *)ss;
4909087SZhong.Wang@Sun.COM 	}
4919087SZhong.Wang@Sun.COM 
4929087SZhong.Wang@Sun.COM 	port = (fct_local_port_t *)fct_alloc(FCT_STRUCT_LOCAL_PORT, 0, 0);
4939087SZhong.Wang@Sun.COM 	if (port == NULL) {
4949087SZhong.Wang@Sun.COM 		goto fail_alloc_port;
4959087SZhong.Wang@Sun.COM 	} else {
4969087SZhong.Wang@Sun.COM 		/*
4979087SZhong.Wang@Sun.COM 		 * Do ss's initialization now
4989087SZhong.Wang@Sun.COM 		 */
4999087SZhong.Wang@Sun.COM 		(void) snprintf(ss->ss_alias, sizeof (ss->ss_alias), "fcoet%d",
5009087SZhong.Wang@Sun.COM 		    ss->ss_instance);
5019087SZhong.Wang@Sun.COM 		ret = ddi_create_minor_node(ss->ss_dip, "admin",
5029087SZhong.Wang@Sun.COM 		    S_IFCHR, ss->ss_instance, DDI_NT_STMF_PP, 0);
5039087SZhong.Wang@Sun.COM 		if (ret != DDI_SUCCESS) {
5049087SZhong.Wang@Sun.COM 			goto fail_minor_node;
5059087SZhong.Wang@Sun.COM 		}
5069087SZhong.Wang@Sun.COM 
5079087SZhong.Wang@Sun.COM 		ss->ss_state = FCT_STATE_OFFLINE;
5089087SZhong.Wang@Sun.COM 		ss->ss_state_not_acked = 1;
5099087SZhong.Wang@Sun.COM 		ss->ss_flags = 0;
5109087SZhong.Wang@Sun.COM 		ss->ss_port = port;
5119087SZhong.Wang@Sun.COM 		ss->ss_eport = eport;
5129087SZhong.Wang@Sun.COM 		FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst);
5139087SZhong.Wang@Sun.COM 
5149087SZhong.Wang@Sun.COM 		ss->ss_rportid_in_dereg = 0;
5159087SZhong.Wang@Sun.COM 		ss->ss_rport_dereg_state = 0;
5169087SZhong.Wang@Sun.COM 
5179087SZhong.Wang@Sun.COM 		ss->ss_next_sol_oxid = 0xFFFF;
5189087SZhong.Wang@Sun.COM 		ss->ss_next_unsol_rxid = 0xFFFF;
5199087SZhong.Wang@Sun.COM 		ss->ss_sol_oxid_hash = mod_hash_create_idhash(
5209087SZhong.Wang@Sun.COM 		    "ss_sol_oxid_hash", FCOET_SOL_HASH_SIZE,
5219087SZhong.Wang@Sun.COM 		    mod_hash_null_valdtor);
5229087SZhong.Wang@Sun.COM 		ss->ss_unsol_rxid_hash = mod_hash_create_idhash(
5239087SZhong.Wang@Sun.COM 		    "ss_unsol_rxid_hash", FCOET_SOL_HASH_SIZE,
5249087SZhong.Wang@Sun.COM 		    mod_hash_null_valdtor);
5259087SZhong.Wang@Sun.COM 
5269087SZhong.Wang@Sun.COM 		ss->ss_watch_count = 0;
5279087SZhong.Wang@Sun.COM 		mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0);
5289087SZhong.Wang@Sun.COM 		cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL);
5299087SZhong.Wang@Sun.COM 
5309087SZhong.Wang@Sun.COM 		list_create(&ss->ss_abort_xchg_list, sizeof (fcoet_exchange_t),
5319087SZhong.Wang@Sun.COM 		    offsetof(fcoet_exchange_t, xch_abort_node));
5329087SZhong.Wang@Sun.COM 
5339087SZhong.Wang@Sun.COM 		ss->ss_sol_flogi = NULL;
5349087SZhong.Wang@Sun.COM 		ss->ss_sol_flogi_state = SFS_WAIT_LINKUP;
5359087SZhong.Wang@Sun.COM 
5369087SZhong.Wang@Sun.COM 		bzero(&ss->ss_link_info, sizeof (fct_link_info_t));
5379087SZhong.Wang@Sun.COM 
5389087SZhong.Wang@Sun.COM 		ss->ss_ioctl_flags = 0;
5399087SZhong.Wang@Sun.COM 		mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0);
5409087SZhong.Wang@Sun.COM 
5419087SZhong.Wang@Sun.COM 		ss->ss_change_state_flags = 0;
5429087SZhong.Wang@Sun.COM 	}
5439087SZhong.Wang@Sun.COM 
5449087SZhong.Wang@Sun.COM 	/*
5459087SZhong.Wang@Sun.COM 	 * Do port's initialization
5469087SZhong.Wang@Sun.COM 	 *
5479087SZhong.Wang@Sun.COM 	 * port_fct_private and port_lport have been initialized by fct_alloc
5489087SZhong.Wang@Sun.COM 	 */
5499087SZhong.Wang@Sun.COM 	port->port_fca_private = ss;
55011231SKevin.Yu@Sun.COM 	port->port_fca_version = FCT_FCA_MODREV_1;
5519087SZhong.Wang@Sun.COM 	bcopy(ss->ss_eport->eport_nodewwn, port->port_nwwn, 8);
5529087SZhong.Wang@Sun.COM 	bcopy(ss->ss_eport->eport_portwwn, port->port_pwwn, 8);
5539087SZhong.Wang@Sun.COM 	port->port_default_alias = ss->ss_alias;
5549087SZhong.Wang@Sun.COM 	port->port_sym_node_name = NULL;
5559087SZhong.Wang@Sun.COM 	port->port_sym_port_name = NULL;
5569087SZhong.Wang@Sun.COM 
5579087SZhong.Wang@Sun.COM 	port->port_pp = fcoet_pp;
5589087SZhong.Wang@Sun.COM 
5599087SZhong.Wang@Sun.COM 	port->port_hard_address = 0;
5609087SZhong.Wang@Sun.COM 	port->port_max_logins = FCOET_MAX_LOGINS;
5619087SZhong.Wang@Sun.COM 	port->port_max_xchges = FCOET_MAX_XCHGES;
5629087SZhong.Wang@Sun.COM 	port->port_fca_fcp_cmd_size = sizeof (fcoet_exchange_t);
5639087SZhong.Wang@Sun.COM 	port->port_fca_rp_private_size = 0;
5649087SZhong.Wang@Sun.COM 	port->port_fca_sol_els_private_size = sizeof (fcoet_exchange_t);
5659087SZhong.Wang@Sun.COM 	port->port_fca_sol_ct_private_size = sizeof (fcoet_exchange_t);
5669087SZhong.Wang@Sun.COM 
5679087SZhong.Wang@Sun.COM 	port->port_fca_abort_timeout = 5 * 1000;	/* 5 seconds */
5689087SZhong.Wang@Sun.COM 	port->port_fds = fds;
5699087SZhong.Wang@Sun.COM 
5709087SZhong.Wang@Sun.COM 	port->port_get_link_info = fcoet_get_link_info;
5719087SZhong.Wang@Sun.COM 	port->port_register_remote_port = fcoet_register_remote_port;
5729087SZhong.Wang@Sun.COM 	port->port_deregister_remote_port = fcoet_deregister_remote_port;
5739087SZhong.Wang@Sun.COM 	port->port_send_cmd = fcoet_send_cmd;
5749087SZhong.Wang@Sun.COM 	port->port_xfer_scsi_data = fcoet_xfer_scsi_data;
5759087SZhong.Wang@Sun.COM 	port->port_send_cmd_response = fcoet_send_cmd_response;
5769087SZhong.Wang@Sun.COM 	port->port_abort_cmd = fcoet_abort_cmd;
5779087SZhong.Wang@Sun.COM 	port->port_ctl = fcoet_ctl;
5789087SZhong.Wang@Sun.COM 	port->port_flogi_xchg = fcoet_do_flogi;
5799087SZhong.Wang@Sun.COM 	port->port_populate_hba_details = fcoet_populate_hba_fru_details;
5809087SZhong.Wang@Sun.COM 	if (fct_register_local_port(port) != FCT_SUCCESS) {
5819087SZhong.Wang@Sun.COM 		goto fail_register_port;
5829087SZhong.Wang@Sun.COM 	}
5839087SZhong.Wang@Sun.COM 
5849087SZhong.Wang@Sun.COM 	/*
5859087SZhong.Wang@Sun.COM 	 * Start watchdog thread
5869087SZhong.Wang@Sun.COM 	 */
587*12571SViswanathan.Kannappan@Sun.COM 	(void) snprintf(taskq_name, sizeof (taskq_name),
588*12571SViswanathan.Kannappan@Sun.COM 	    "stmf_fct_fcoet_%d_taskq", ss->ss_instance);
5899087SZhong.Wang@Sun.COM 	if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL,
5909087SZhong.Wang@Sun.COM 	    taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) {
5919087SZhong.Wang@Sun.COM 		goto fail_create_taskq;
5929087SZhong.Wang@Sun.COM 	}
5939087SZhong.Wang@Sun.COM 
5949087SZhong.Wang@Sun.COM 	atomic_and_32(&ss->ss_flags, ~SS_FLAG_TERMINATE_WATCHDOG);
5959087SZhong.Wang@Sun.COM 	(void) ddi_taskq_dispatch(ss->ss_watchdog_taskq,
5969087SZhong.Wang@Sun.COM 	    fcoet_watchdog, ss, DDI_SLEEP);
5979087SZhong.Wang@Sun.COM 	while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) {
5989087SZhong.Wang@Sun.COM 		delay(10);
5999087SZhong.Wang@Sun.COM 	}
6009087SZhong.Wang@Sun.COM 
6019087SZhong.Wang@Sun.COM 	ddi_report_dev(ss->ss_dip);
6029087SZhong.Wang@Sun.COM 	return (DDI_SUCCESS);
6039087SZhong.Wang@Sun.COM 
6049087SZhong.Wang@Sun.COM fail_create_taskq:
6059087SZhong.Wang@Sun.COM 	if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
6069087SZhong.Wang@Sun.COM 		atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG);
6079087SZhong.Wang@Sun.COM 		cv_broadcast(&ss->ss_watch_cv);
6089087SZhong.Wang@Sun.COM 		while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
6099087SZhong.Wang@Sun.COM 			delay(10);
6109087SZhong.Wang@Sun.COM 		}
6119087SZhong.Wang@Sun.COM 	}
6129087SZhong.Wang@Sun.COM 
6139087SZhong.Wang@Sun.COM 	ddi_taskq_destroy(ss->ss_watchdog_taskq);
6149087SZhong.Wang@Sun.COM 	FCOET_LOG("fcoet_attach_init", "fail_register_port");
6159087SZhong.Wang@Sun.COM 
6169087SZhong.Wang@Sun.COM fail_register_port:
6179087SZhong.Wang@Sun.COM 	mutex_destroy(&ss->ss_ioctl_mutex);
6189087SZhong.Wang@Sun.COM 	mutex_destroy(&ss->ss_watch_mutex);
6199087SZhong.Wang@Sun.COM 	cv_destroy(&ss->ss_watch_cv);
6209087SZhong.Wang@Sun.COM 	mod_hash_destroy_hash(ss->ss_sol_oxid_hash);
6219087SZhong.Wang@Sun.COM 	mod_hash_destroy_hash(ss->ss_unsol_rxid_hash);
6229087SZhong.Wang@Sun.COM 	list_destroy(&ss->ss_abort_xchg_list);
6239087SZhong.Wang@Sun.COM 	FCOET_LOG("fcoet_attach_init", "fail_create_taskq");
6249087SZhong.Wang@Sun.COM 
6259087SZhong.Wang@Sun.COM fail_minor_node:
6269087SZhong.Wang@Sun.COM 	fct_free(port);
6279087SZhong.Wang@Sun.COM 	FCOET_LOG("fcoet_attach_init", "fail_minor_node");
6289087SZhong.Wang@Sun.COM 
6299087SZhong.Wang@Sun.COM fail_alloc_port:
6309087SZhong.Wang@Sun.COM 	fct_free(fds);
6319087SZhong.Wang@Sun.COM 	FCOET_LOG("fcoet_attach_init", "fail_alloc_port");
6329087SZhong.Wang@Sun.COM 
6339087SZhong.Wang@Sun.COM fail_alloc_dbuf:
6349087SZhong.Wang@Sun.COM 	fcoet_dbuf_destroy(ss);
6359087SZhong.Wang@Sun.COM 	FCOET_LOG("fcoet_attach_init", "fail_alloc_dbuf");
6369087SZhong.Wang@Sun.COM 
6379087SZhong.Wang@Sun.COM fail_init_dbuf:
6389087SZhong.Wang@Sun.COM 	ss->ss_eport->eport_deregister_client(ss->ss_eport);
6399087SZhong.Wang@Sun.COM 	FCOET_LOG("fcoet_attach_init", "fail_init_dbuf");
6409087SZhong.Wang@Sun.COM 
6419087SZhong.Wang@Sun.COM fail_register_client:
6429087SZhong.Wang@Sun.COM 	FCOET_LOG("fcoet_attach_init", "fail_register_client");
6439087SZhong.Wang@Sun.COM 	return (DDI_FAILURE);
6449087SZhong.Wang@Sun.COM }
6459087SZhong.Wang@Sun.COM 
6469087SZhong.Wang@Sun.COM static fct_status_t
fcoet_detach_uninit(fcoet_soft_state_t * ss)6479087SZhong.Wang@Sun.COM fcoet_detach_uninit(fcoet_soft_state_t *ss)
6489087SZhong.Wang@Sun.COM {
6499087SZhong.Wang@Sun.COM 	if ((ss->ss_state != FCT_STATE_OFFLINE) ||
6509087SZhong.Wang@Sun.COM 	    ss->ss_state_not_acked) {
6519087SZhong.Wang@Sun.COM 		return (FCOE_FAILURE);
6529087SZhong.Wang@Sun.COM 	}
6539087SZhong.Wang@Sun.COM 
6549087SZhong.Wang@Sun.COM 	/*
6559087SZhong.Wang@Sun.COM 	 * Avoid modunload before running fcinfo remove-target-port
6569087SZhong.Wang@Sun.COM 	 */
6579087SZhong.Wang@Sun.COM 	if (ss->ss_eport != NULL &&
6589087SZhong.Wang@Sun.COM 	    ss->ss_eport->eport_flags & EPORT_FLAG_MAC_IN_USE) {
6599087SZhong.Wang@Sun.COM 		return (FCOE_FAILURE);
6609087SZhong.Wang@Sun.COM 	}
6619087SZhong.Wang@Sun.COM 
6629087SZhong.Wang@Sun.COM 	if (ss->ss_port == NULL) {
6639087SZhong.Wang@Sun.COM 		return (FCOE_SUCCESS);
6649087SZhong.Wang@Sun.COM 	}
6659087SZhong.Wang@Sun.COM 
6669087SZhong.Wang@Sun.COM 	ss->ss_sol_oxid_hash_empty = 1;
6679087SZhong.Wang@Sun.COM 	ss->ss_unsol_rxid_hash_empty = 1;
6689087SZhong.Wang@Sun.COM 	mod_hash_walk(ss->ss_sol_oxid_hash, fcoet_sol_oxid_hash_empty, ss);
6699087SZhong.Wang@Sun.COM 	mod_hash_walk(ss->ss_unsol_rxid_hash, fcoet_unsol_rxid_hash_empty, ss);
6709087SZhong.Wang@Sun.COM 	if ((!ss->ss_sol_oxid_hash_empty) || (!ss->ss_unsol_rxid_hash_empty)) {
6719087SZhong.Wang@Sun.COM 		return (FCOE_FAILURE);
6729087SZhong.Wang@Sun.COM 	}
6739087SZhong.Wang@Sun.COM 
6749087SZhong.Wang@Sun.COM 	/*
6759087SZhong.Wang@Sun.COM 	 * We need offline the port manually, before we want to detach it
6769087SZhong.Wang@Sun.COM 	 * or it will not succeed.
6779087SZhong.Wang@Sun.COM 	 */
6789087SZhong.Wang@Sun.COM 	if (fct_deregister_local_port(ss->ss_port) != FCT_SUCCESS) {
6799087SZhong.Wang@Sun.COM 		FCOET_LOG("fcoet_detach_uninit",
6809087SZhong.Wang@Sun.COM 		    "fct_deregister_local_port failed");
6819087SZhong.Wang@Sun.COM 		return (FCOE_FAILURE);
6829087SZhong.Wang@Sun.COM 	}
6839087SZhong.Wang@Sun.COM 
6849087SZhong.Wang@Sun.COM 	/*
6859087SZhong.Wang@Sun.COM 	 * Stop watchdog
6869087SZhong.Wang@Sun.COM 	 */
6879087SZhong.Wang@Sun.COM 	if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
6889087SZhong.Wang@Sun.COM 		atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG);
6899087SZhong.Wang@Sun.COM 		cv_broadcast(&ss->ss_watch_cv);
6909087SZhong.Wang@Sun.COM 		while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
6919087SZhong.Wang@Sun.COM 			delay(10);
6929087SZhong.Wang@Sun.COM 		}
6939087SZhong.Wang@Sun.COM 	}
6949087SZhong.Wang@Sun.COM 
6959087SZhong.Wang@Sun.COM 	ddi_taskq_destroy(ss->ss_watchdog_taskq);
6969087SZhong.Wang@Sun.COM 
6979087SZhong.Wang@Sun.COM 	/*
6989087SZhong.Wang@Sun.COM 	 * Release all resources
6999087SZhong.Wang@Sun.COM 	 */
7009087SZhong.Wang@Sun.COM 	mutex_destroy(&ss->ss_ioctl_mutex);
7019087SZhong.Wang@Sun.COM 	mutex_destroy(&ss->ss_watch_mutex);
7029087SZhong.Wang@Sun.COM 	cv_destroy(&ss->ss_watch_cv);
7039087SZhong.Wang@Sun.COM 	mod_hash_destroy_hash(ss->ss_sol_oxid_hash);
7049087SZhong.Wang@Sun.COM 	mod_hash_destroy_hash(ss->ss_unsol_rxid_hash);
7059087SZhong.Wang@Sun.COM 	list_destroy(&ss->ss_abort_xchg_list);
7069087SZhong.Wang@Sun.COM 
7079087SZhong.Wang@Sun.COM 	fct_free(ss->ss_port->port_fds);
7089087SZhong.Wang@Sun.COM 	fct_free(ss->ss_port);
7099087SZhong.Wang@Sun.COM 	ss->ss_port = NULL;
7109087SZhong.Wang@Sun.COM 
7119087SZhong.Wang@Sun.COM 	fcoet_dbuf_destroy(ss);
7129087SZhong.Wang@Sun.COM 
7139087SZhong.Wang@Sun.COM 	if (ss->ss_eport != NULL &&
7149087SZhong.Wang@Sun.COM 	    ss->ss_eport->eport_deregister_client != NULL) {
7159087SZhong.Wang@Sun.COM 		ss->ss_eport->eport_deregister_client(ss->ss_eport);
7169087SZhong.Wang@Sun.COM 	}
7179087SZhong.Wang@Sun.COM 	ddi_soft_state_free(fcoet_state, ss->ss_instance);
7189087SZhong.Wang@Sun.COM 	return (FCOE_SUCCESS);
7199087SZhong.Wang@Sun.COM }
7209087SZhong.Wang@Sun.COM 
7219087SZhong.Wang@Sun.COM static void
fcoet_watchdog(void * arg)7229087SZhong.Wang@Sun.COM fcoet_watchdog(void *arg)
7239087SZhong.Wang@Sun.COM {
7249087SZhong.Wang@Sun.COM 	fcoet_soft_state_t	*ss = (fcoet_soft_state_t *)arg;
7259087SZhong.Wang@Sun.COM 	clock_t			 tmp_delay = 0;
7269087SZhong.Wang@Sun.COM 	fcoet_exchange_t	*xchg, *xchg_next;
7279087SZhong.Wang@Sun.COM 
7289087SZhong.Wang@Sun.COM 	FCOET_LOG("fcoet_watchdog", "fcoet_soft_state is %p", ss);
7299087SZhong.Wang@Sun.COM 
7309087SZhong.Wang@Sun.COM 	mutex_enter(&ss->ss_watch_mutex);
7319087SZhong.Wang@Sun.COM 	atomic_or_32(&ss->ss_flags, SS_FLAG_WATCHDOG_RUNNING);
7329087SZhong.Wang@Sun.COM 	tmp_delay = STMF_SEC2TICK(1)/2;
7339087SZhong.Wang@Sun.COM 
7349087SZhong.Wang@Sun.COM 	while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) {
7359087SZhong.Wang@Sun.COM 		ss->ss_watch_count++;
7369087SZhong.Wang@Sun.COM 
7379087SZhong.Wang@Sun.COM 		if (ss->ss_sol_flogi_state != SFS_FLOGI_DONE) {
7389087SZhong.Wang@Sun.COM 			fcoet_handle_sol_flogi(ss);
7399087SZhong.Wang@Sun.COM 		}
7409087SZhong.Wang@Sun.COM 		for (xchg = list_head(&ss->ss_abort_xchg_list); xchg; ) {
7419087SZhong.Wang@Sun.COM 			xchg_next = list_next(&ss->ss_abort_xchg_list, xchg);
7429087SZhong.Wang@Sun.COM 			if (xchg->xch_ref == 0) {
7439087SZhong.Wang@Sun.COM 				list_remove(&ss->ss_abort_xchg_list, xchg);
7449087SZhong.Wang@Sun.COM 				mutex_exit(&ss->ss_watch_mutex);
7459087SZhong.Wang@Sun.COM 				/* xchg abort done */
7469087SZhong.Wang@Sun.COM 				if (xchg->xch_dbuf_num) {
7479087SZhong.Wang@Sun.COM 					kmem_free((void*)xchg->xch_dbufs,
7489087SZhong.Wang@Sun.COM 					    xchg->xch_dbuf_num *
7499087SZhong.Wang@Sun.COM 					    sizeof (void *));
7509087SZhong.Wang@Sun.COM 					xchg->xch_dbufs = NULL;
7519087SZhong.Wang@Sun.COM 					xchg->xch_dbuf_num = 0;
7529087SZhong.Wang@Sun.COM 				}
7539087SZhong.Wang@Sun.COM 				fct_cmd_fca_aborted(xchg->xch_cmd,
7549087SZhong.Wang@Sun.COM 				    FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
7559087SZhong.Wang@Sun.COM 				mutex_enter(&ss->ss_watch_mutex);
7569087SZhong.Wang@Sun.COM 			}
7579087SZhong.Wang@Sun.COM 			xchg = xchg_next;
7589087SZhong.Wang@Sun.COM 		}
7599087SZhong.Wang@Sun.COM 
7609087SZhong.Wang@Sun.COM 		atomic_or_32(&ss->ss_flags, SS_FLAG_DOG_WAITING);
76111066Srafael.vanoni@sun.com 		(void) cv_reltimedwait(&ss->ss_watch_cv, &ss->ss_watch_mutex,
76211066Srafael.vanoni@sun.com 		    (clock_t)tmp_delay, TR_CLOCK_TICK);
7639087SZhong.Wang@Sun.COM 		atomic_and_32(&ss->ss_flags, ~SS_FLAG_DOG_WAITING);
7649087SZhong.Wang@Sun.COM 	}
7659087SZhong.Wang@Sun.COM 
7669087SZhong.Wang@Sun.COM 	/*
7679087SZhong.Wang@Sun.COM 	 * Ensure no ongoing FLOGI, before terminate the watchdog
7689087SZhong.Wang@Sun.COM 	 */
7699087SZhong.Wang@Sun.COM 	if (ss->ss_sol_flogi) {
7709087SZhong.Wang@Sun.COM 		fcoet_clear_sol_exchange(ss->ss_sol_flogi);
7719087SZhong.Wang@Sun.COM 		fct_free(ss->ss_sol_flogi->xch_cmd);
7729087SZhong.Wang@Sun.COM 		ss->ss_sol_flogi = NULL;
7739087SZhong.Wang@Sun.COM 	}
7749087SZhong.Wang@Sun.COM 
7759087SZhong.Wang@Sun.COM 	atomic_and_32(&ss->ss_flags, ~SS_FLAG_WATCHDOG_RUNNING);
7769087SZhong.Wang@Sun.COM 	mutex_exit(&ss->ss_watch_mutex);
7779087SZhong.Wang@Sun.COM }
7789087SZhong.Wang@Sun.COM 
7799087SZhong.Wang@Sun.COM static void
fcoet_handle_sol_flogi(fcoet_soft_state_t * ss)7809087SZhong.Wang@Sun.COM fcoet_handle_sol_flogi(fcoet_soft_state_t *ss)
7819087SZhong.Wang@Sun.COM {
7829087SZhong.Wang@Sun.COM 	clock_t			twosec = STMF_SEC2TICK(2);
7839087SZhong.Wang@Sun.COM 
7849087SZhong.Wang@Sun.COM check_state_again:
7859087SZhong.Wang@Sun.COM 	if (ss->ss_flags & SS_FLAG_PORT_DISABLED) {
7869087SZhong.Wang@Sun.COM 		ss->ss_sol_flogi_state = SFS_WAIT_LINKUP;
7879087SZhong.Wang@Sun.COM 	}
7889087SZhong.Wang@Sun.COM 
7899087SZhong.Wang@Sun.COM 	switch (ss->ss_sol_flogi_state) {
7909087SZhong.Wang@Sun.COM 	case SFS_WAIT_LINKUP:
7919087SZhong.Wang@Sun.COM 		if (ss->ss_sol_flogi) {
7929087SZhong.Wang@Sun.COM 			if (ss->ss_sol_flogi->xch_ref == 0) {
7939087SZhong.Wang@Sun.COM 				fcoet_clear_sol_exchange(ss->ss_sol_flogi);
7949087SZhong.Wang@Sun.COM 				fct_free(ss->ss_sol_flogi->xch_cmd);
7959087SZhong.Wang@Sun.COM 				ss->ss_sol_flogi = NULL;
7969087SZhong.Wang@Sun.COM 			}
7979087SZhong.Wang@Sun.COM 		}
7989087SZhong.Wang@Sun.COM 		break;
7999087SZhong.Wang@Sun.COM 
8009087SZhong.Wang@Sun.COM 	case SFS_FLOGI_INIT:
8019087SZhong.Wang@Sun.COM 		if (ss->ss_sol_flogi) {
8029087SZhong.Wang@Sun.COM 			/*
8039087SZhong.Wang@Sun.COM 			 * wait for the response to finish
8049087SZhong.Wang@Sun.COM 			 */
8059087SZhong.Wang@Sun.COM 			ss->ss_sol_flogi_state = SFS_CLEAR_FLOGI;
8069087SZhong.Wang@Sun.COM 			break;
8079087SZhong.Wang@Sun.COM 		}
8089087SZhong.Wang@Sun.COM 		fcoet_send_sol_flogi(ss);
8099087SZhong.Wang@Sun.COM 		ss->ss_sol_flogi_state++;
8109087SZhong.Wang@Sun.COM 		break;
8119087SZhong.Wang@Sun.COM 
8129087SZhong.Wang@Sun.COM 	case SFS_FLOGI_CHECK_TIMEOUT:
8139087SZhong.Wang@Sun.COM 		if ((ss->ss_sol_flogi->xch_start_time + twosec) <
8149087SZhong.Wang@Sun.COM 		    ddi_get_lbolt()) {
8159087SZhong.Wang@Sun.COM 			ss->ss_sol_flogi_state++;
8169087SZhong.Wang@Sun.COM 		}
8179087SZhong.Wang@Sun.COM 		break;
8189087SZhong.Wang@Sun.COM 
8199087SZhong.Wang@Sun.COM 	case SFS_ABTS_INIT:
8209087SZhong.Wang@Sun.COM 		fcoet_send_sol_abts(ss->ss_sol_flogi);
8219087SZhong.Wang@Sun.COM 		ss->ss_sol_flogi_state++;
8229087SZhong.Wang@Sun.COM 		break;
8239087SZhong.Wang@Sun.COM 
8249087SZhong.Wang@Sun.COM 	case SFS_CLEAR_FLOGI:
8259087SZhong.Wang@Sun.COM 		if (ss->ss_sol_flogi) {
8269087SZhong.Wang@Sun.COM 			if (ss->ss_sol_flogi->xch_ref) {
8279087SZhong.Wang@Sun.COM 				break;
8289087SZhong.Wang@Sun.COM 			}
8299087SZhong.Wang@Sun.COM 			fcoet_clear_sol_exchange(ss->ss_sol_flogi);
8309087SZhong.Wang@Sun.COM 			fct_free(ss->ss_sol_flogi->xch_cmd);
8319087SZhong.Wang@Sun.COM 			ss->ss_sol_flogi = NULL;
8329087SZhong.Wang@Sun.COM 		}
8339087SZhong.Wang@Sun.COM 		ss->ss_sol_flogi_state = SFS_FLOGI_INIT;
8349087SZhong.Wang@Sun.COM 		goto check_state_again;
8359087SZhong.Wang@Sun.COM 
8369087SZhong.Wang@Sun.COM 	case SFS_FLOGI_ACC:
8379087SZhong.Wang@Sun.COM 		ss->ss_sol_flogi_state++;
8389087SZhong.Wang@Sun.COM 		goto check_state_again;
8399087SZhong.Wang@Sun.COM 
8409087SZhong.Wang@Sun.COM 	case SFS_FLOGI_DONE:
8419087SZhong.Wang@Sun.COM 		if (!(ss->ss_flags & SS_FLAG_PORT_DISABLED) &&
8429087SZhong.Wang@Sun.COM 		    ss->ss_sol_flogi) {
8439087SZhong.Wang@Sun.COM 			fcoet_clear_sol_exchange(ss->ss_sol_flogi);
8449087SZhong.Wang@Sun.COM 			fct_free(ss->ss_sol_flogi->xch_cmd);
8459087SZhong.Wang@Sun.COM 			ss->ss_sol_flogi = NULL;
8469087SZhong.Wang@Sun.COM 		}
8479087SZhong.Wang@Sun.COM 
8489087SZhong.Wang@Sun.COM 		/*
8499087SZhong.Wang@Sun.COM 		 * We'd better to offline it first, and delay 0.1 seconds,
8509087SZhong.Wang@Sun.COM 		 * before we say it's on again.
8519087SZhong.Wang@Sun.COM 		 */
8529087SZhong.Wang@Sun.COM 		fct_handle_event(ss->ss_port,
8539087SZhong.Wang@Sun.COM 		    FCT_EVENT_LINK_DOWN, 0, NULL);
8549087SZhong.Wang@Sun.COM 		delay(STMF_SEC2TICK(1)/10);
8559087SZhong.Wang@Sun.COM 		fct_handle_event(ss->ss_port,
8569087SZhong.Wang@Sun.COM 		    FCT_EVENT_LINK_UP, 0, NULL);
8579087SZhong.Wang@Sun.COM 		break;
8589087SZhong.Wang@Sun.COM 
8599087SZhong.Wang@Sun.COM 	default:
8609087SZhong.Wang@Sun.COM 		ASSERT(0);
8619087SZhong.Wang@Sun.COM 		break;
8629087SZhong.Wang@Sun.COM 	}
8639087SZhong.Wang@Sun.COM }
8649087SZhong.Wang@Sun.COM 
8659087SZhong.Wang@Sun.COM /* ARGSUSED */
8669087SZhong.Wang@Sun.COM static int
fcoet_dbuf_init(fcoet_soft_state_t * ss)8679087SZhong.Wang@Sun.COM fcoet_dbuf_init(fcoet_soft_state_t *ss)
8689087SZhong.Wang@Sun.COM {
8699087SZhong.Wang@Sun.COM 	return (FCOE_SUCCESS);
8709087SZhong.Wang@Sun.COM }
8719087SZhong.Wang@Sun.COM 
8729087SZhong.Wang@Sun.COM /* ARGSUSED */
8739087SZhong.Wang@Sun.COM static void
fcoet_dbuf_destroy(fcoet_soft_state_t * ss)8749087SZhong.Wang@Sun.COM fcoet_dbuf_destroy(fcoet_soft_state_t *ss)
8759087SZhong.Wang@Sun.COM {
8769087SZhong.Wang@Sun.COM 
8779087SZhong.Wang@Sun.COM }
8789087SZhong.Wang@Sun.COM 
8799087SZhong.Wang@Sun.COM /* ARGSUSED */
8809087SZhong.Wang@Sun.COM static stmf_data_buf_t *
fcoet_dbuf_alloc(fct_local_port_t * port,uint32_t size,uint32_t * pminsize,uint32_t flags)8819087SZhong.Wang@Sun.COM fcoet_dbuf_alloc(fct_local_port_t *port, uint32_t size, uint32_t *pminsize,
8829087SZhong.Wang@Sun.COM     uint32_t flags)
8839087SZhong.Wang@Sun.COM {
8849087SZhong.Wang@Sun.COM 	stmf_data_buf_t	*dbuf;
8859087SZhong.Wang@Sun.COM 	int		 add_size;
8869087SZhong.Wang@Sun.COM 	int		 sge_num;
8879087SZhong.Wang@Sun.COM 	int		 sge_size;
8889087SZhong.Wang@Sun.COM 	int		 idx;
8899087SZhong.Wang@Sun.COM 	int		 ii;
8909087SZhong.Wang@Sun.COM 	void		*netb;
8919087SZhong.Wang@Sun.COM 	uint8_t		*fc_buf;
8929087SZhong.Wang@Sun.COM 	fcoet_soft_state_t	*ss =
8939087SZhong.Wang@Sun.COM 	    (fcoet_soft_state_t *)port->port_fca_private;
8949087SZhong.Wang@Sun.COM 
8959087SZhong.Wang@Sun.COM 	if (size > FCOET_MAX_DBUF_LEN) {
8969087SZhong.Wang@Sun.COM 		if (*pminsize > FCOET_MAX_DBUF_LEN) {
8979087SZhong.Wang@Sun.COM 			return (NULL);
8989087SZhong.Wang@Sun.COM 		}
8999087SZhong.Wang@Sun.COM 
9009087SZhong.Wang@Sun.COM 		size = FCOET_MAX_DBUF_LEN;
9019087SZhong.Wang@Sun.COM 	}
9029087SZhong.Wang@Sun.COM 
9039087SZhong.Wang@Sun.COM 	sge_num = (size - 1) / ss->ss_fcp_data_payload_size + 1;
9049087SZhong.Wang@Sun.COM 	add_size = (sge_num - 1) * sizeof (struct stmf_sglist_ent) +
9059087SZhong.Wang@Sun.COM 	    sge_num * sizeof (mblk_t *);
9069087SZhong.Wang@Sun.COM 	dbuf = stmf_alloc(STMF_STRUCT_DATA_BUF, add_size, 0);
9079087SZhong.Wang@Sun.COM 	if (dbuf == NULL) {
9089087SZhong.Wang@Sun.COM 		return (NULL);
9099087SZhong.Wang@Sun.COM 	}
9109087SZhong.Wang@Sun.COM 	dbuf->db_buf_size = size;
9119087SZhong.Wang@Sun.COM 	dbuf->db_data_size = size;
9129087SZhong.Wang@Sun.COM 	dbuf->db_sglist_length = 0;
9139087SZhong.Wang@Sun.COM 	dbuf->db_flags |= DB_DONT_REUSE;
9149087SZhong.Wang@Sun.COM 	FCOET_SET_SEG_NUM(dbuf, sge_num);
9159087SZhong.Wang@Sun.COM 
9169087SZhong.Wang@Sun.COM 	/*
9179087SZhong.Wang@Sun.COM 	 * Initialize non-last sg entries
9189087SZhong.Wang@Sun.COM 	 */
9199087SZhong.Wang@Sun.COM 	for (idx = 0; idx < sge_num - 1; idx++) {
9209087SZhong.Wang@Sun.COM 		sge_size = ss->ss_fcp_data_payload_size;
9219087SZhong.Wang@Sun.COM 		netb = ss->ss_eport->eport_alloc_netb(
9229087SZhong.Wang@Sun.COM 		    ss->ss_eport, sizeof (fcoe_fc_frame_header_t) +
9239087SZhong.Wang@Sun.COM 		    sge_size, &fc_buf);
9249087SZhong.Wang@Sun.COM 		if (netb == NULL) {
9259087SZhong.Wang@Sun.COM 			for (ii = 0; ii < idx; ii++) {
9269087SZhong.Wang@Sun.COM 				ss->ss_eport->eport_free_netb(
9279087SZhong.Wang@Sun.COM 				    FCOET_GET_NETB(dbuf, ii));
9289087SZhong.Wang@Sun.COM 			}
9299087SZhong.Wang@Sun.COM 			stmf_free(dbuf);
9309087SZhong.Wang@Sun.COM 			FCOET_LOG("fcoe_dbuf_alloc", "no netb");
9319087SZhong.Wang@Sun.COM 			return (NULL);
9329087SZhong.Wang@Sun.COM 		}
9339087SZhong.Wang@Sun.COM 		FCOET_SET_NETB(dbuf, idx, netb);
9349087SZhong.Wang@Sun.COM 		dbuf->db_sglist[idx].seg_addr = fc_buf +
9359087SZhong.Wang@Sun.COM 		    sizeof (fcoe_fc_frame_header_t);
9369087SZhong.Wang@Sun.COM 		dbuf->db_sglist[idx].seg_length = sge_size;
9379087SZhong.Wang@Sun.COM 	}
9389087SZhong.Wang@Sun.COM 
9399087SZhong.Wang@Sun.COM 	/*
9409087SZhong.Wang@Sun.COM 	 * Initialize the last sg entry
9419087SZhong.Wang@Sun.COM 	 */
9429087SZhong.Wang@Sun.COM 	if (size % ss->ss_fcp_data_payload_size) {
9439087SZhong.Wang@Sun.COM 		sge_size = P2ROUNDUP(size % ss->ss_fcp_data_payload_size, 4);
9449087SZhong.Wang@Sun.COM 	} else {
9459087SZhong.Wang@Sun.COM 		sge_size = ss->ss_fcp_data_payload_size;
9469087SZhong.Wang@Sun.COM 	}
9479087SZhong.Wang@Sun.COM 
9489087SZhong.Wang@Sun.COM 	netb = ss->ss_eport->eport_alloc_netb(
9499087SZhong.Wang@Sun.COM 	    ss->ss_eport,
9509087SZhong.Wang@Sun.COM 	    sizeof (fcoe_fc_frame_header_t) +
9519087SZhong.Wang@Sun.COM 	    sge_size, &fc_buf);
9529087SZhong.Wang@Sun.COM 	if (netb == NULL) {
9539087SZhong.Wang@Sun.COM 		for (ii = 0; ii < idx; ii++) {
9549087SZhong.Wang@Sun.COM 			ss->ss_eport->eport_free_netb(
9559087SZhong.Wang@Sun.COM 			    FCOET_GET_NETB(dbuf, ii));
9569087SZhong.Wang@Sun.COM 		}
9579087SZhong.Wang@Sun.COM 		stmf_free(dbuf);
9589087SZhong.Wang@Sun.COM 		FCOET_LOG("fcoe_dbuf_alloc", "no netb");
9599087SZhong.Wang@Sun.COM 		return (NULL);
9609087SZhong.Wang@Sun.COM 	}
9619087SZhong.Wang@Sun.COM 
9629087SZhong.Wang@Sun.COM 	FCOET_SET_NETB(dbuf, idx, netb);
9639087SZhong.Wang@Sun.COM 	dbuf->db_sglist[idx].seg_addr = fc_buf +
9649087SZhong.Wang@Sun.COM 	    sizeof (fcoe_fc_frame_header_t);
9659087SZhong.Wang@Sun.COM 	dbuf->db_sglist[idx].seg_length = sge_size;
9669087SZhong.Wang@Sun.COM 
9679087SZhong.Wang@Sun.COM 	/*
9689087SZhong.Wang@Sun.COM 	 * Let COMSTAR know how many sg entries we will use
9699087SZhong.Wang@Sun.COM 	 */
9709087SZhong.Wang@Sun.COM 	dbuf->db_sglist_length = idx + 1;
9719087SZhong.Wang@Sun.COM 
9729087SZhong.Wang@Sun.COM 	return (dbuf);
9739087SZhong.Wang@Sun.COM }
9749087SZhong.Wang@Sun.COM 
9759087SZhong.Wang@Sun.COM static void
fcoet_dbuf_free(fct_dbuf_store_t * fds,stmf_data_buf_t * dbuf)9769087SZhong.Wang@Sun.COM fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf)
9779087SZhong.Wang@Sun.COM {
9789087SZhong.Wang@Sun.COM 	int	idx;
9799087SZhong.Wang@Sun.COM 	fcoet_soft_state_t	*ss =
9809087SZhong.Wang@Sun.COM 	    (fcoet_soft_state_t *)fds->fds_fca_private;
9819087SZhong.Wang@Sun.COM 
9829087SZhong.Wang@Sun.COM 	for (idx = 0; idx < FCOET_GET_SEG_NUM(dbuf); idx++) {
9839087SZhong.Wang@Sun.COM 		if (FCOET_GET_NETB(dbuf, idx)) {
9849087SZhong.Wang@Sun.COM 			ss->ss_eport->eport_free_netb(
9859087SZhong.Wang@Sun.COM 			    FCOET_GET_NETB(dbuf, idx));
9869087SZhong.Wang@Sun.COM 		}
9879087SZhong.Wang@Sun.COM 	}
9889087SZhong.Wang@Sun.COM 
9899087SZhong.Wang@Sun.COM 	stmf_free(dbuf);
9909087SZhong.Wang@Sun.COM }
9919087SZhong.Wang@Sun.COM 
9929087SZhong.Wang@Sun.COM /*
9939087SZhong.Wang@Sun.COM  * We should have initialized fcoe_frame_t before
9949087SZhong.Wang@Sun.COM  */
9959087SZhong.Wang@Sun.COM void
fcoet_init_tfm(fcoe_frame_t * frm,fcoet_exchange_t * xch)9969087SZhong.Wang@Sun.COM fcoet_init_tfm(fcoe_frame_t *frm, fcoet_exchange_t *xch)
9979087SZhong.Wang@Sun.COM {
9989087SZhong.Wang@Sun.COM 	FRM2TFM(frm)->tfm_fcoe_frame = frm;
9999087SZhong.Wang@Sun.COM 	FRM2TFM(frm)->tfm_xch = xch;
10009087SZhong.Wang@Sun.COM 	FRM2TFM(frm)->tfm_seq = NULL;
10019087SZhong.Wang@Sun.COM }
10029087SZhong.Wang@Sun.COM 
10039087SZhong.Wang@Sun.COM /* ARGSUSED */
10049087SZhong.Wang@Sun.COM static uint_t
fcoet_sol_oxid_hash_empty(mod_hash_key_t key,mod_hash_val_t * val,void * arg)10059087SZhong.Wang@Sun.COM fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
10069087SZhong.Wang@Sun.COM {
10079087SZhong.Wang@Sun.COM 	fcoet_soft_state_t	*ss = (fcoet_soft_state_t *)arg;
10089087SZhong.Wang@Sun.COM 
10099087SZhong.Wang@Sun.COM 	ss->ss_sol_oxid_hash_empty = 0;
10109087SZhong.Wang@Sun.COM 	FCOET_LOG("fcoet_sol_oxid_hash_empty", "one ongoing xch: %p", val);
10119087SZhong.Wang@Sun.COM 	return (MH_WALK_CONTINUE);
10129087SZhong.Wang@Sun.COM }
10139087SZhong.Wang@Sun.COM 
10149087SZhong.Wang@Sun.COM /* ARGSUSED */
10159087SZhong.Wang@Sun.COM static uint_t
fcoet_unsol_rxid_hash_empty(mod_hash_key_t key,mod_hash_val_t * val,void * arg)10169087SZhong.Wang@Sun.COM fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
10179087SZhong.Wang@Sun.COM {
10189087SZhong.Wang@Sun.COM 	fcoet_soft_state_t	*ss = (fcoet_soft_state_t *)arg;
10199087SZhong.Wang@Sun.COM 
10209087SZhong.Wang@Sun.COM 	ss->ss_sol_oxid_hash_empty = 0;
10219087SZhong.Wang@Sun.COM 	FCOET_LOG("fcoet_unsol_rxid_hash_empty", "one ongoing xch: %p", val);
10229087SZhong.Wang@Sun.COM 	return (MH_WALK_CONTINUE);
10239087SZhong.Wang@Sun.COM }
10249087SZhong.Wang@Sun.COM 
10259087SZhong.Wang@Sun.COM /* ARGSUSED */
10269087SZhong.Wang@Sun.COM void
fcoet_modhash_find_cb(mod_hash_key_t key,mod_hash_val_t val)10279087SZhong.Wang@Sun.COM fcoet_modhash_find_cb(mod_hash_key_t key, mod_hash_val_t val)
10289087SZhong.Wang@Sun.COM {
10299087SZhong.Wang@Sun.COM 	ASSERT(val != NULL);
10309087SZhong.Wang@Sun.COM 	fcoet_exchange_t *xch = (fcoet_exchange_t *)val;
10319087SZhong.Wang@Sun.COM 	FCOET_BUSY_XCHG(xch);
10329087SZhong.Wang@Sun.COM }
1033