xref: /onnv-gate/usr/src/uts/common/io/comstar/port/fct/fct.c (revision 12571:05943d9c379f)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
2212314SJames.Moore@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
237836SJohn.Forte@Sun.COM  */
247836SJohn.Forte@Sun.COM 
257836SJohn.Forte@Sun.COM #include <sys/conf.h>
267836SJohn.Forte@Sun.COM #include <sys/file.h>
277836SJohn.Forte@Sun.COM #include <sys/ddi.h>
287836SJohn.Forte@Sun.COM #include <sys/sunddi.h>
297836SJohn.Forte@Sun.COM #include <sys/modctl.h>
307836SJohn.Forte@Sun.COM #include <sys/scsi/scsi.h>
317836SJohn.Forte@Sun.COM #include <sys/scsi/impl/scsi_reset_notify.h>
327836SJohn.Forte@Sun.COM #include <sys/disp.h>
337836SJohn.Forte@Sun.COM #include <sys/byteorder.h>
347836SJohn.Forte@Sun.COM #include <sys/varargs.h>
357836SJohn.Forte@Sun.COM #include <sys/atomic.h>
369578SSam.Cramer@Sun.COM #include <sys/sdt.h>
377836SJohn.Forte@Sun.COM 
38*12571SViswanathan.Kannappan@Sun.COM #include <sys/stmf.h>
39*12571SViswanathan.Kannappan@Sun.COM #include <sys/stmf_ioctl.h>
40*12571SViswanathan.Kannappan@Sun.COM #include <sys/portif.h>
41*12571SViswanathan.Kannappan@Sun.COM #include <sys/fct.h>
42*12571SViswanathan.Kannappan@Sun.COM #include <sys/fctio.h>
43*12571SViswanathan.Kannappan@Sun.COM 
44*12571SViswanathan.Kannappan@Sun.COM #include "fct_impl.h"
45*12571SViswanathan.Kannappan@Sun.COM #include "discovery.h"
467836SJohn.Forte@Sun.COM 
477836SJohn.Forte@Sun.COM static int fct_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
487836SJohn.Forte@Sun.COM static int fct_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
497836SJohn.Forte@Sun.COM static int fct_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
507836SJohn.Forte@Sun.COM     void **result);
517836SJohn.Forte@Sun.COM static int fct_open(dev_t *devp, int flag, int otype, cred_t *credp);
527836SJohn.Forte@Sun.COM static int fct_close(dev_t dev, int flag, int otype, cred_t *credp);
537836SJohn.Forte@Sun.COM static int fct_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
547836SJohn.Forte@Sun.COM     cred_t *credp, int *rval);
557836SJohn.Forte@Sun.COM static int fct_fctiocmd(intptr_t data, int mode);
5610088SAllan.Ou@Sun.COM void fct_init_kstats(fct_i_local_port_t *iport);
577836SJohn.Forte@Sun.COM 
587836SJohn.Forte@Sun.COM static dev_info_t *fct_dip;
597836SJohn.Forte@Sun.COM static struct cb_ops fct_cb_ops = {
607836SJohn.Forte@Sun.COM 	fct_open,			/* open */
617836SJohn.Forte@Sun.COM 	fct_close,			/* close */
627836SJohn.Forte@Sun.COM 	nodev,				/* strategy */
637836SJohn.Forte@Sun.COM 	nodev,				/* print */
647836SJohn.Forte@Sun.COM 	nodev,				/* dump */
657836SJohn.Forte@Sun.COM 	nodev,				/* read */
667836SJohn.Forte@Sun.COM 	nodev,				/* write */
677836SJohn.Forte@Sun.COM 	fct_ioctl,			/* ioctl */
687836SJohn.Forte@Sun.COM 	nodev,				/* devmap */
697836SJohn.Forte@Sun.COM 	nodev,				/* mmap */
707836SJohn.Forte@Sun.COM 	nodev,				/* segmap */
717836SJohn.Forte@Sun.COM 	nochpoll,			/* chpoll */
727836SJohn.Forte@Sun.COM 	ddi_prop_op,			/* cb_prop_op */
737836SJohn.Forte@Sun.COM 	0,				/* streamtab */
747836SJohn.Forte@Sun.COM 	D_NEW | D_MP,			/* cb_flag */
757836SJohn.Forte@Sun.COM 	CB_REV,				/* rev */
767836SJohn.Forte@Sun.COM 	nodev,				/* aread */
777836SJohn.Forte@Sun.COM 	nodev				/* awrite */
787836SJohn.Forte@Sun.COM };
797836SJohn.Forte@Sun.COM 
807836SJohn.Forte@Sun.COM static struct dev_ops fct_ops = {
817836SJohn.Forte@Sun.COM 	DEVO_REV,
827836SJohn.Forte@Sun.COM 	0,
837836SJohn.Forte@Sun.COM 	fct_getinfo,
847836SJohn.Forte@Sun.COM 	nulldev,		/* identify */
857836SJohn.Forte@Sun.COM 	nulldev,		/* probe */
867836SJohn.Forte@Sun.COM 	fct_attach,
877836SJohn.Forte@Sun.COM 	fct_detach,
887836SJohn.Forte@Sun.COM 	nodev,			/* reset */
897836SJohn.Forte@Sun.COM 	&fct_cb_ops,
907836SJohn.Forte@Sun.COM 	NULL,			/* bus_ops */
917836SJohn.Forte@Sun.COM 	NULL			/* power */
927836SJohn.Forte@Sun.COM };
937836SJohn.Forte@Sun.COM 
947836SJohn.Forte@Sun.COM #define	FCT_NAME	"COMSTAR FCT"
9510088SAllan.Ou@Sun.COM #define	FCT_MODULE_NAME	"fct"
967836SJohn.Forte@Sun.COM 
977836SJohn.Forte@Sun.COM extern struct mod_ops mod_driverops;
987836SJohn.Forte@Sun.COM static struct modldrv modldrv = {
997836SJohn.Forte@Sun.COM 	&mod_driverops,
1007836SJohn.Forte@Sun.COM 	FCT_NAME,
1017836SJohn.Forte@Sun.COM 	&fct_ops
1027836SJohn.Forte@Sun.COM };
1037836SJohn.Forte@Sun.COM 
1047836SJohn.Forte@Sun.COM static struct modlinkage modlinkage = {
1057836SJohn.Forte@Sun.COM 	MODREV_1,
1067836SJohn.Forte@Sun.COM 	&modldrv,
1077836SJohn.Forte@Sun.COM 	NULL
1087836SJohn.Forte@Sun.COM };
1097836SJohn.Forte@Sun.COM 
1107836SJohn.Forte@Sun.COM static uint32_t	rportid_table_size = FCT_HASH_TABLE_SIZE;
1117836SJohn.Forte@Sun.COM static int max_cached_ncmds = FCT_MAX_CACHED_CMDS;
1127836SJohn.Forte@Sun.COM static fct_i_local_port_t *fct_iport_list = NULL;
1137836SJohn.Forte@Sun.COM static kmutex_t fct_global_mutex;
1147836SJohn.Forte@Sun.COM uint32_t fct_rscn_options = RSCN_OPTION_VERIFY;
1157836SJohn.Forte@Sun.COM 
1167836SJohn.Forte@Sun.COM int
_init(void)1177836SJohn.Forte@Sun.COM _init(void)
1187836SJohn.Forte@Sun.COM {
1197836SJohn.Forte@Sun.COM 	int ret;
1207836SJohn.Forte@Sun.COM 
1217836SJohn.Forte@Sun.COM 	ret = mod_install(&modlinkage);
1227836SJohn.Forte@Sun.COM 	if (ret)
1237836SJohn.Forte@Sun.COM 		return (ret);
1247836SJohn.Forte@Sun.COM 	/* XXX */
1257836SJohn.Forte@Sun.COM 	mutex_init(&fct_global_mutex, NULL, MUTEX_DRIVER, NULL);
1267836SJohn.Forte@Sun.COM 	return (ret);
1277836SJohn.Forte@Sun.COM }
1287836SJohn.Forte@Sun.COM 
1297836SJohn.Forte@Sun.COM int
_fini(void)1307836SJohn.Forte@Sun.COM _fini(void)
1317836SJohn.Forte@Sun.COM {
1327836SJohn.Forte@Sun.COM 	int ret;
1337836SJohn.Forte@Sun.COM 
1347836SJohn.Forte@Sun.COM 	ret = mod_remove(&modlinkage);
1357836SJohn.Forte@Sun.COM 	if (ret)
1367836SJohn.Forte@Sun.COM 		return (ret);
1377836SJohn.Forte@Sun.COM 	/* XXX */
1387836SJohn.Forte@Sun.COM 	mutex_destroy(&fct_global_mutex);
1397836SJohn.Forte@Sun.COM 	return (ret);
1407836SJohn.Forte@Sun.COM }
1417836SJohn.Forte@Sun.COM 
1427836SJohn.Forte@Sun.COM int
_info(struct modinfo * modinfop)1437836SJohn.Forte@Sun.COM _info(struct modinfo *modinfop)
1447836SJohn.Forte@Sun.COM {
1457836SJohn.Forte@Sun.COM 	return (mod_info(&modlinkage, modinfop));
1467836SJohn.Forte@Sun.COM }
1477836SJohn.Forte@Sun.COM 
1487836SJohn.Forte@Sun.COM /* ARGSUSED */
1497836SJohn.Forte@Sun.COM static int
fct_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)1507836SJohn.Forte@Sun.COM fct_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
1517836SJohn.Forte@Sun.COM {
1527836SJohn.Forte@Sun.COM 	switch (cmd) {
1537836SJohn.Forte@Sun.COM 	case DDI_INFO_DEVT2DEVINFO:
1547836SJohn.Forte@Sun.COM 		*result = fct_dip;
1557836SJohn.Forte@Sun.COM 		break;
1567836SJohn.Forte@Sun.COM 	case DDI_INFO_DEVT2INSTANCE:
1579585STim.Szeto@Sun.COM 		*result = (void *)(uintptr_t)ddi_get_instance(fct_dip);
1587836SJohn.Forte@Sun.COM 		break;
1597836SJohn.Forte@Sun.COM 	default:
1607836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
1617836SJohn.Forte@Sun.COM 	}
1627836SJohn.Forte@Sun.COM 
1637836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
1647836SJohn.Forte@Sun.COM }
1657836SJohn.Forte@Sun.COM 
1667836SJohn.Forte@Sun.COM static int
fct_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1677836SJohn.Forte@Sun.COM fct_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1687836SJohn.Forte@Sun.COM {
1697836SJohn.Forte@Sun.COM 	switch (cmd) {
1707836SJohn.Forte@Sun.COM 	case DDI_ATTACH:
1717836SJohn.Forte@Sun.COM 		fct_dip = dip;
1727836SJohn.Forte@Sun.COM 
1737836SJohn.Forte@Sun.COM 		if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0,
1747836SJohn.Forte@Sun.COM 		    DDI_NT_STMF_PP, 0) != DDI_SUCCESS) {
1757836SJohn.Forte@Sun.COM 			break;
1767836SJohn.Forte@Sun.COM 		}
1777836SJohn.Forte@Sun.COM 		ddi_report_dev(dip);
1787836SJohn.Forte@Sun.COM 		return (DDI_SUCCESS);
1797836SJohn.Forte@Sun.COM 	}
1807836SJohn.Forte@Sun.COM 
1817836SJohn.Forte@Sun.COM 	return (DDI_FAILURE);
1827836SJohn.Forte@Sun.COM }
1837836SJohn.Forte@Sun.COM 
1847836SJohn.Forte@Sun.COM static int
fct_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)1857836SJohn.Forte@Sun.COM fct_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1867836SJohn.Forte@Sun.COM {
1877836SJohn.Forte@Sun.COM 	switch (cmd) {
1887836SJohn.Forte@Sun.COM 	case DDI_DETACH:
1897836SJohn.Forte@Sun.COM 		ddi_remove_minor_node(dip, 0);
1907836SJohn.Forte@Sun.COM 		return (DDI_SUCCESS);
1917836SJohn.Forte@Sun.COM 	}
1927836SJohn.Forte@Sun.COM 
1937836SJohn.Forte@Sun.COM 	return (DDI_FAILURE);
1947836SJohn.Forte@Sun.COM }
1957836SJohn.Forte@Sun.COM 
1967836SJohn.Forte@Sun.COM /* ARGSUSED */
1977836SJohn.Forte@Sun.COM static int
fct_open(dev_t * devp,int flag,int otype,cred_t * credp)1987836SJohn.Forte@Sun.COM fct_open(dev_t *devp, int flag, int otype, cred_t *credp)
1997836SJohn.Forte@Sun.COM {
2007836SJohn.Forte@Sun.COM 	if (otype != OTYP_CHR)
2017836SJohn.Forte@Sun.COM 		return (EINVAL);
2027836SJohn.Forte@Sun.COM 	return (0);
2037836SJohn.Forte@Sun.COM }
2047836SJohn.Forte@Sun.COM 
2057836SJohn.Forte@Sun.COM /* ARGSUSED */
2067836SJohn.Forte@Sun.COM static int
fct_close(dev_t dev,int flag,int otype,cred_t * credp)2077836SJohn.Forte@Sun.COM fct_close(dev_t dev, int flag, int otype, cred_t *credp)
2087836SJohn.Forte@Sun.COM {
2097836SJohn.Forte@Sun.COM 	return (0);
2107836SJohn.Forte@Sun.COM }
2117836SJohn.Forte@Sun.COM 
2127836SJohn.Forte@Sun.COM /* ARGSUSED */
2137836SJohn.Forte@Sun.COM static int
fct_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * credp,int * rval)2147836SJohn.Forte@Sun.COM fct_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
2157836SJohn.Forte@Sun.COM     cred_t *credp, int *rval)
2167836SJohn.Forte@Sun.COM {
2177836SJohn.Forte@Sun.COM 	int		ret = 0;
2187836SJohn.Forte@Sun.COM 
2197836SJohn.Forte@Sun.COM 	if ((cmd & 0xff000000) != FCT_IOCTL) {
2207836SJohn.Forte@Sun.COM 		return (ENOTTY);
2217836SJohn.Forte@Sun.COM 	}
2227836SJohn.Forte@Sun.COM 
2237836SJohn.Forte@Sun.COM 	if (drv_priv(credp) != 0) {
2247836SJohn.Forte@Sun.COM 		return (EPERM);
2257836SJohn.Forte@Sun.COM 	}
2267836SJohn.Forte@Sun.COM 
2277836SJohn.Forte@Sun.COM 	switch (cmd) {
2287836SJohn.Forte@Sun.COM 	case FCTIO_CMD:
2297836SJohn.Forte@Sun.COM 		ret = fct_fctiocmd(data, mode);
2307836SJohn.Forte@Sun.COM 		break;
2317836SJohn.Forte@Sun.COM 	default:
2327836SJohn.Forte@Sun.COM 		ret = ENOTTY;
2337836SJohn.Forte@Sun.COM 		break;
2347836SJohn.Forte@Sun.COM 	}
2357836SJohn.Forte@Sun.COM 
2367836SJohn.Forte@Sun.COM 	return (ret);
2377836SJohn.Forte@Sun.COM }
2387836SJohn.Forte@Sun.COM 
2397836SJohn.Forte@Sun.COM int
fct_copyin_iocdata(intptr_t data,int mode,fctio_t ** fctio,void ** ibuf,void ** abuf,void ** obuf)2407836SJohn.Forte@Sun.COM fct_copyin_iocdata(intptr_t data, int mode, fctio_t **fctio,
2417836SJohn.Forte@Sun.COM     void **ibuf, void **abuf, void **obuf)
2427836SJohn.Forte@Sun.COM {
2437836SJohn.Forte@Sun.COM 	int ret = 0;
2447836SJohn.Forte@Sun.COM 
2457836SJohn.Forte@Sun.COM 	*ibuf = NULL;
2467836SJohn.Forte@Sun.COM 	*abuf = NULL;
2477836SJohn.Forte@Sun.COM 	*obuf = NULL;
2487836SJohn.Forte@Sun.COM 	*fctio = kmem_zalloc(sizeof (fctio_t), KM_SLEEP);
2497836SJohn.Forte@Sun.COM 	if (ddi_copyin((void *)data, *fctio, sizeof (fctio_t), mode)) {
2507836SJohn.Forte@Sun.COM 		ret = EFAULT;
2517836SJohn.Forte@Sun.COM 		goto copyin_iocdata_done;
2527836SJohn.Forte@Sun.COM 	}
2537836SJohn.Forte@Sun.COM 
2547836SJohn.Forte@Sun.COM 	if ((*fctio)->fctio_ilen) {
2557836SJohn.Forte@Sun.COM 		*ibuf = kmem_zalloc((*fctio)->fctio_ilen, KM_SLEEP);
2567836SJohn.Forte@Sun.COM 		if (ddi_copyin((void *)(unsigned long)(*fctio)->fctio_ibuf,
2577836SJohn.Forte@Sun.COM 		    *ibuf, (*fctio)->fctio_ilen, mode)) {
2587836SJohn.Forte@Sun.COM 			ret = EFAULT;
2597836SJohn.Forte@Sun.COM 			goto copyin_iocdata_done;
2607836SJohn.Forte@Sun.COM 		}
2617836SJohn.Forte@Sun.COM 	}
2627836SJohn.Forte@Sun.COM 	if ((*fctio)->fctio_alen) {
2637836SJohn.Forte@Sun.COM 		*abuf = kmem_zalloc((*fctio)->fctio_alen, KM_SLEEP);
2647836SJohn.Forte@Sun.COM 		if (ddi_copyin((void *)(unsigned long)(*fctio)->fctio_abuf,
2657836SJohn.Forte@Sun.COM 		    *abuf, (*fctio)->fctio_alen, mode)) {
2667836SJohn.Forte@Sun.COM 			ret = EFAULT;
2677836SJohn.Forte@Sun.COM 			goto copyin_iocdata_done;
2687836SJohn.Forte@Sun.COM 		}
2697836SJohn.Forte@Sun.COM 	}
2707836SJohn.Forte@Sun.COM 	if ((*fctio)->fctio_olen)
2717836SJohn.Forte@Sun.COM 		*obuf = kmem_zalloc((*fctio)->fctio_olen, KM_SLEEP);
2727836SJohn.Forte@Sun.COM 	if (ret == 0)
2737836SJohn.Forte@Sun.COM 		return (0);
2747836SJohn.Forte@Sun.COM 	ret = EFAULT;
2757836SJohn.Forte@Sun.COM copyin_iocdata_done:
2767836SJohn.Forte@Sun.COM 	if (*obuf) {
2777836SJohn.Forte@Sun.COM 		kmem_free(*obuf, (*fctio)->fctio_olen);
2787836SJohn.Forte@Sun.COM 		*obuf = NULL;
2797836SJohn.Forte@Sun.COM 	}
2807836SJohn.Forte@Sun.COM 	if (*abuf) {
2817836SJohn.Forte@Sun.COM 		kmem_free(*abuf, (*fctio)->fctio_alen);
2827836SJohn.Forte@Sun.COM 		*abuf = NULL;
2837836SJohn.Forte@Sun.COM 	}
2847836SJohn.Forte@Sun.COM 	if (*ibuf) {
2857836SJohn.Forte@Sun.COM 		kmem_free(*ibuf, (*fctio)->fctio_ilen);
2867836SJohn.Forte@Sun.COM 		*ibuf = NULL;
2877836SJohn.Forte@Sun.COM 	}
2887836SJohn.Forte@Sun.COM 	kmem_free(*fctio, sizeof (fctio_t));
2897836SJohn.Forte@Sun.COM 	return (ret);
2907836SJohn.Forte@Sun.COM }
2917836SJohn.Forte@Sun.COM 
2927836SJohn.Forte@Sun.COM int
fct_copyout_iocdata(intptr_t data,int mode,fctio_t * fctio,void * obuf)2937836SJohn.Forte@Sun.COM fct_copyout_iocdata(intptr_t data, int mode, fctio_t *fctio, void *obuf)
2947836SJohn.Forte@Sun.COM {
2957836SJohn.Forte@Sun.COM 	int ret = 0;
2967836SJohn.Forte@Sun.COM 
2977836SJohn.Forte@Sun.COM 	if (fctio->fctio_olen) {
2987836SJohn.Forte@Sun.COM 		ret = ddi_copyout(obuf,
2997836SJohn.Forte@Sun.COM 		    (void *)(unsigned long)fctio->fctio_obuf, fctio->fctio_olen,
3007836SJohn.Forte@Sun.COM 		    mode);
3017836SJohn.Forte@Sun.COM 		if (ret) {
3027836SJohn.Forte@Sun.COM 			return (EFAULT);
3037836SJohn.Forte@Sun.COM 		}
3047836SJohn.Forte@Sun.COM 	}
3057836SJohn.Forte@Sun.COM 	ret = ddi_copyout(fctio, (void *)data, sizeof (fctio_t), mode);
3067836SJohn.Forte@Sun.COM 	if (ret) {
3077836SJohn.Forte@Sun.COM 		return (EFAULT);
3087836SJohn.Forte@Sun.COM 	}
3097836SJohn.Forte@Sun.COM 	return (0);
3107836SJohn.Forte@Sun.COM }
3117836SJohn.Forte@Sun.COM 
3127836SJohn.Forte@Sun.COM int
fct_get_port_list(char * pathList,int count)3137836SJohn.Forte@Sun.COM fct_get_port_list(char *pathList, int count)
3147836SJohn.Forte@Sun.COM {
3157836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport;
3167836SJohn.Forte@Sun.COM 	int	i = 0, maxPorts = 0;
3177836SJohn.Forte@Sun.COM 
3187836SJohn.Forte@Sun.COM 	ASSERT(pathList != NULL);
3197836SJohn.Forte@Sun.COM 
3207836SJohn.Forte@Sun.COM 	mutex_enter(&fct_global_mutex);
3217836SJohn.Forte@Sun.COM 	for (iport = fct_iport_list; iport; iport = iport->iport_next) {
3227836SJohn.Forte@Sun.COM 		if (i < count)
3237836SJohn.Forte@Sun.COM 			bcopy(iport->iport_port->port_pwwn,
3247836SJohn.Forte@Sun.COM 			    pathList + 8 * i, 8);
3257836SJohn.Forte@Sun.COM 		maxPorts ++;
3267836SJohn.Forte@Sun.COM 		i++;
3277836SJohn.Forte@Sun.COM 	}
3287836SJohn.Forte@Sun.COM 	mutex_exit(&fct_global_mutex);
3297836SJohn.Forte@Sun.COM 	return (maxPorts);
3307836SJohn.Forte@Sun.COM }
3317836SJohn.Forte@Sun.COM 
3327836SJohn.Forte@Sun.COM /* invoked with fct_global_mutex locked */
3337836SJohn.Forte@Sun.COM fct_i_local_port_t *
fct_get_iport_per_wwn(uint8_t * pwwn)3347836SJohn.Forte@Sun.COM fct_get_iport_per_wwn(uint8_t *pwwn)
3357836SJohn.Forte@Sun.COM {
3367836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport;
3377836SJohn.Forte@Sun.COM 
3387836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&fct_global_mutex));
3397836SJohn.Forte@Sun.COM 	for (iport = fct_iport_list; iport; iport = iport->iport_next) {
3407836SJohn.Forte@Sun.COM 		if (bcmp(iport->iport_port->port_pwwn, pwwn, 8) == 0)
3417836SJohn.Forte@Sun.COM 			return (iport);
3427836SJohn.Forte@Sun.COM 	}
3437836SJohn.Forte@Sun.COM 	return (NULL);
3447836SJohn.Forte@Sun.COM }
3457836SJohn.Forte@Sun.COM 
3467836SJohn.Forte@Sun.COM int
fct_get_adapter_attr(uint8_t * pwwn,fc_tgt_hba_adapter_attributes_t * hba_attr,uint32_t * err_detail)3477836SJohn.Forte@Sun.COM fct_get_adapter_attr(uint8_t *pwwn, fc_tgt_hba_adapter_attributes_t *hba_attr,
3487836SJohn.Forte@Sun.COM     uint32_t *err_detail)
3497836SJohn.Forte@Sun.COM {
3507836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport;
3517836SJohn.Forte@Sun.COM 	fct_port_attrs_t *attr;
3527836SJohn.Forte@Sun.COM 
3537836SJohn.Forte@Sun.COM 	hba_attr->version = FCT_HBA_ADAPTER_ATTRIBUTES_VERSION;
3547836SJohn.Forte@Sun.COM 	iport = fct_get_iport_per_wwn(pwwn);
3557836SJohn.Forte@Sun.COM 	if (!iport) {
3567836SJohn.Forte@Sun.COM 		*err_detail = FCTIO_BADWWN;
3577836SJohn.Forte@Sun.COM 		return (ENXIO);
3587836SJohn.Forte@Sun.COM 	}
3597836SJohn.Forte@Sun.COM 
3607836SJohn.Forte@Sun.COM 	attr = (fct_port_attrs_t *)kmem_zalloc(sizeof (fct_port_attrs_t),
3617836SJohn.Forte@Sun.COM 	    KM_SLEEP);
3627836SJohn.Forte@Sun.COM 	mutex_exit(&fct_global_mutex);
3637836SJohn.Forte@Sun.COM 	iport->iport_port->port_populate_hba_details(iport->iport_port, attr);
3647836SJohn.Forte@Sun.COM 	mutex_enter(&fct_global_mutex);
3657836SJohn.Forte@Sun.COM 
3667836SJohn.Forte@Sun.COM 	bcopy(attr->manufacturer, hba_attr->Manufacturer,
3677836SJohn.Forte@Sun.COM 	    sizeof (hba_attr->Manufacturer));
3687836SJohn.Forte@Sun.COM 	bcopy(attr->serial_number, hba_attr->SerialNumber,
3697836SJohn.Forte@Sun.COM 	    sizeof (hba_attr->SerialNumber));
3707836SJohn.Forte@Sun.COM 	bcopy(attr->model, hba_attr->Model, sizeof (hba_attr->Model));
3717836SJohn.Forte@Sun.COM 	bcopy(attr->model_description, hba_attr->ModelDescription,
3727836SJohn.Forte@Sun.COM 	    sizeof (hba_attr->ModelDescription));
3737836SJohn.Forte@Sun.COM 	if (iport->iport_port->port_sym_node_name)
3747836SJohn.Forte@Sun.COM 		bcopy(iport->iport_port->port_sym_node_name,
3757836SJohn.Forte@Sun.COM 		    hba_attr->NodeSymbolicName,
3767836SJohn.Forte@Sun.COM 		    strlen(iport->iport_port->port_sym_node_name));
3777836SJohn.Forte@Sun.COM 	else
3787836SJohn.Forte@Sun.COM 		bcopy(utsname.nodename, hba_attr->NodeSymbolicName,
3797836SJohn.Forte@Sun.COM 		    strlen(utsname.nodename));
3807836SJohn.Forte@Sun.COM 	bcopy(attr->hardware_version, hba_attr->HardwareVersion,
3817836SJohn.Forte@Sun.COM 	    sizeof (hba_attr->HardwareVersion));
3827836SJohn.Forte@Sun.COM 	bcopy(attr->option_rom_version, hba_attr->OptionROMVersion,
3837836SJohn.Forte@Sun.COM 	    sizeof (hba_attr->OptionROMVersion));
3847836SJohn.Forte@Sun.COM 	bcopy(attr->firmware_version, hba_attr->FirmwareVersion,
3857836SJohn.Forte@Sun.COM 	    sizeof (hba_attr->FirmwareVersion));
3867836SJohn.Forte@Sun.COM 	hba_attr->VendorSpecificID = attr->vendor_specific_id;
3877836SJohn.Forte@Sun.COM 	bcopy(iport->iport_port->port_nwwn, hba_attr->NodeWWN,
3887836SJohn.Forte@Sun.COM 	    sizeof (hba_attr->NodeWWN));
3897836SJohn.Forte@Sun.COM 
3907836SJohn.Forte@Sun.COM 	bcopy(attr->driver_name, hba_attr->DriverName,
3917836SJohn.Forte@Sun.COM 	    sizeof (hba_attr->DriverName));
3927836SJohn.Forte@Sun.COM 	bcopy(attr->driver_version, hba_attr->DriverVersion,
3937836SJohn.Forte@Sun.COM 	    sizeof (hba_attr->DriverVersion));
3947836SJohn.Forte@Sun.COM 
3957836SJohn.Forte@Sun.COM 
3967836SJohn.Forte@Sun.COM 	/* hba_attr->NumberOfPorts = fct_count_fru_ports(iport); */
3977836SJohn.Forte@Sun.COM 	hba_attr->NumberOfPorts = 1;
3987836SJohn.Forte@Sun.COM 
3997836SJohn.Forte@Sun.COM 	kmem_free(attr, sizeof (fct_port_attrs_t));
4007836SJohn.Forte@Sun.COM 	return (0);
4017836SJohn.Forte@Sun.COM }
4027836SJohn.Forte@Sun.COM 
4037836SJohn.Forte@Sun.COM int
fct_get_adapter_port_attr(fct_i_local_port_t * ilport,uint8_t * pwwn,fc_tgt_hba_port_attributes_t * port_attr,uint32_t * err_detail)4047836SJohn.Forte@Sun.COM fct_get_adapter_port_attr(fct_i_local_port_t *ilport, uint8_t *pwwn,
4057836SJohn.Forte@Sun.COM     fc_tgt_hba_port_attributes_t *port_attr, uint32_t *err_detail)
4067836SJohn.Forte@Sun.COM {
4077836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport = ilport;
4087836SJohn.Forte@Sun.COM 	fct_i_remote_port_t *irp = NULL;
4097836SJohn.Forte@Sun.COM 	fct_port_attrs_t *attr;
4107836SJohn.Forte@Sun.COM 	int i = 0;
4117836SJohn.Forte@Sun.COM 
4127836SJohn.Forte@Sun.COM 	port_attr->version = FCT_HBA_PORT_ATTRIBUTES_VERSION;
4137836SJohn.Forte@Sun.COM 
4147836SJohn.Forte@Sun.COM 	if (!ilport) {
4157836SJohn.Forte@Sun.COM 		iport = fct_get_iport_per_wwn(pwwn);
4167836SJohn.Forte@Sun.COM 		if (!iport) {
4177836SJohn.Forte@Sun.COM 			*err_detail = FCTIO_BADWWN;
4187836SJohn.Forte@Sun.COM 			return (ENXIO);
4197836SJohn.Forte@Sun.COM 		}
4207836SJohn.Forte@Sun.COM 	}
4217836SJohn.Forte@Sun.COM 
4227836SJohn.Forte@Sun.COM 	attr = (fct_port_attrs_t *)kmem_zalloc(sizeof (fct_port_attrs_t),
4237836SJohn.Forte@Sun.COM 	    KM_SLEEP);
4247836SJohn.Forte@Sun.COM 	mutex_exit(&fct_global_mutex);
4257836SJohn.Forte@Sun.COM 	iport->iport_port->port_populate_hba_details(iport->iport_port, attr);
4267836SJohn.Forte@Sun.COM 	mutex_enter(&fct_global_mutex);
4277836SJohn.Forte@Sun.COM 
4287836SJohn.Forte@Sun.COM 	port_attr->lastChange = iport->iport_last_change;
4297836SJohn.Forte@Sun.COM 	bcopy(iport->iport_port->port_nwwn, port_attr->NodeWWN,
4307836SJohn.Forte@Sun.COM 	    sizeof (port_attr->NodeWWN));
4317836SJohn.Forte@Sun.COM 	bcopy(iport->iport_port->port_pwwn, port_attr->PortWWN,
4327836SJohn.Forte@Sun.COM 	    sizeof (port_attr->PortWWN));
4337836SJohn.Forte@Sun.COM 	bzero(port_attr->FabricName, sizeof (port_attr->FabricName));
4347836SJohn.Forte@Sun.COM 	port_attr->PortFcId = iport->iport_link_info.portid;
4359844SAllan.Ou@Sun.COM 	if ((iport->iport_link_state & S_LINK_ONLINE) ||
4369844SAllan.Ou@Sun.COM 	    (iport->iport_link_state & S_RCVD_LINK_UP)) {
4379844SAllan.Ou@Sun.COM 		port_attr->PortState = FC_HBA_PORTSTATE_ONLINE;
4389844SAllan.Ou@Sun.COM 	} else {
4399844SAllan.Ou@Sun.COM 		port_attr->PortState = FC_HBA_PORTSTATE_OFFLINE;
4407836SJohn.Forte@Sun.COM 	}
4417836SJohn.Forte@Sun.COM 	switch (iport->iport_link_info.port_topology) {
4427836SJohn.Forte@Sun.COM 		case PORT_TOPOLOGY_PT_TO_PT:
4437836SJohn.Forte@Sun.COM 			port_attr->PortType = FC_HBA_PORTTYPE_PTP;
4447836SJohn.Forte@Sun.COM 			break;
4457836SJohn.Forte@Sun.COM 		case PORT_TOPOLOGY_PRIVATE_LOOP:
4467836SJohn.Forte@Sun.COM 			port_attr->PortType = FC_HBA_PORTTYPE_LPORT;
4477836SJohn.Forte@Sun.COM 			break;
4487836SJohn.Forte@Sun.COM 		case PORT_TOPOLOGY_PUBLIC_LOOP:
4497836SJohn.Forte@Sun.COM 			port_attr->PortType = FC_HBA_PORTTYPE_NLPORT;
4507836SJohn.Forte@Sun.COM 			break;
4517836SJohn.Forte@Sun.COM 		case PORT_TOPOLOGY_FABRIC_PT_TO_PT:
4527836SJohn.Forte@Sun.COM 			port_attr->PortType = FC_HBA_PORTTYPE_FPORT;
4537836SJohn.Forte@Sun.COM 			break;
4547836SJohn.Forte@Sun.COM 		default:
4557836SJohn.Forte@Sun.COM 			port_attr->PortType = FC_HBA_PORTTYPE_UNKNOWN;
4567836SJohn.Forte@Sun.COM 			break;
4577836SJohn.Forte@Sun.COM 	}
4587836SJohn.Forte@Sun.COM 	port_attr->PortSupportedClassofService = attr->supported_cos;
4597836SJohn.Forte@Sun.COM 	port_attr->PortSupportedFc4Types[0] = 0;
4607836SJohn.Forte@Sun.COM 	port_attr->PortActiveFc4Types[2] = 1;
4617836SJohn.Forte@Sun.COM 	if (iport->iport_port->port_sym_port_name)
4627836SJohn.Forte@Sun.COM 		bcopy(iport->iport_port->port_sym_port_name,
4637836SJohn.Forte@Sun.COM 		    port_attr->PortSymbolicName,
4647836SJohn.Forte@Sun.COM 		    strlen(iport->iport_port->port_sym_port_name));
4657836SJohn.Forte@Sun.COM 	else if (iport->iport_port->port_default_alias)
4667836SJohn.Forte@Sun.COM 		bcopy(iport->iport_port->port_default_alias,
4677836SJohn.Forte@Sun.COM 		    port_attr->PortSymbolicName,
4687836SJohn.Forte@Sun.COM 		    strlen(iport->iport_port->port_default_alias));
4697836SJohn.Forte@Sun.COM 	else
4707836SJohn.Forte@Sun.COM 		port_attr->PortSymbolicName[0] = 0;
4717836SJohn.Forte@Sun.COM 	/* the definition is different so need to translate */
4727836SJohn.Forte@Sun.COM 	if (attr->supported_speed & PORT_SPEED_1G)
4737836SJohn.Forte@Sun.COM 		port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_1GBIT;
4747836SJohn.Forte@Sun.COM 	if (attr->supported_speed & PORT_SPEED_2G)
4757836SJohn.Forte@Sun.COM 		port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_2GBIT;
4767836SJohn.Forte@Sun.COM 	if (attr->supported_speed & PORT_SPEED_4G)
4777836SJohn.Forte@Sun.COM 		port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_4GBIT;
4787836SJohn.Forte@Sun.COM 	if (attr->supported_speed & PORT_SPEED_8G)
4797836SJohn.Forte@Sun.COM 		port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_8GBIT;
4809087SZhong.Wang@Sun.COM 	if (attr->supported_speed & PORT_SPEED_10G)
4819087SZhong.Wang@Sun.COM 		port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_10GBIT;
4827836SJohn.Forte@Sun.COM 	switch (iport->iport_link_info.port_speed) {
4837836SJohn.Forte@Sun.COM 		case PORT_SPEED_1G:
4847836SJohn.Forte@Sun.COM 			port_attr->PortSpeed = FC_HBA_PORTSPEED_1GBIT;
4857836SJohn.Forte@Sun.COM 			break;
4867836SJohn.Forte@Sun.COM 		case PORT_SPEED_2G:
4877836SJohn.Forte@Sun.COM 			port_attr->PortSpeed = FC_HBA_PORTSPEED_2GBIT;
4887836SJohn.Forte@Sun.COM 			break;
4897836SJohn.Forte@Sun.COM 		case PORT_SPEED_4G:
4907836SJohn.Forte@Sun.COM 			port_attr->PortSpeed = FC_HBA_PORTSPEED_4GBIT;
4917836SJohn.Forte@Sun.COM 			break;
4927836SJohn.Forte@Sun.COM 		case PORT_SPEED_8G:
4937836SJohn.Forte@Sun.COM 			port_attr->PortSpeed = FC_HBA_PORTSPEED_8GBIT;
4947836SJohn.Forte@Sun.COM 			break;
4959087SZhong.Wang@Sun.COM 		case PORT_SPEED_10G:
4969087SZhong.Wang@Sun.COM 			port_attr->PortSpeed = FC_HBA_PORTSPEED_10GBIT;
4979087SZhong.Wang@Sun.COM 			break;
4987836SJohn.Forte@Sun.COM 		default:
4997836SJohn.Forte@Sun.COM 			port_attr->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
5007836SJohn.Forte@Sun.COM 			break;
5017836SJohn.Forte@Sun.COM 	}
5027836SJohn.Forte@Sun.COM 	port_attr->PortMaxFrameSize = attr->max_frame_size;
5037836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_READER);
5047836SJohn.Forte@Sun.COM 	port_attr->NumberofDiscoveredPorts = iport->iport_nrps_login;
5057836SJohn.Forte@Sun.COM 	for (; i < iport->iport_port->port_max_logins; i++) {
5067836SJohn.Forte@Sun.COM 		irp = iport->iport_rp_slots[i];
5077836SJohn.Forte@Sun.COM 		if (irp && irp->irp_flags & IRP_PLOGI_DONE) {
5087836SJohn.Forte@Sun.COM 			if (FC_WELL_KNOWN_ADDR(irp->irp_portid))
5097836SJohn.Forte@Sun.COM 				port_attr->NumberofDiscoveredPorts --;
5107836SJohn.Forte@Sun.COM 		}
5117836SJohn.Forte@Sun.COM 	}
5127836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
5137836SJohn.Forte@Sun.COM 
5147836SJohn.Forte@Sun.COM 	kmem_free(attr, sizeof (fct_port_attrs_t));
5157836SJohn.Forte@Sun.COM 
5167836SJohn.Forte@Sun.COM 	return (0);
5177836SJohn.Forte@Sun.COM }
5187836SJohn.Forte@Sun.COM 
5197836SJohn.Forte@Sun.COM int
fct_get_discovered_port_attr(fct_i_remote_port_t * remote_port,uint8_t * port_wwn,uint32_t index,fc_tgt_hba_port_attributes_t * port_attr,uint32_t * error_detail)5207836SJohn.Forte@Sun.COM fct_get_discovered_port_attr(fct_i_remote_port_t *remote_port,
5217836SJohn.Forte@Sun.COM     uint8_t *port_wwn, uint32_t index, fc_tgt_hba_port_attributes_t *port_attr,
5227836SJohn.Forte@Sun.COM     uint32_t *error_detail)
5237836SJohn.Forte@Sun.COM {
5247836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport;
5257836SJohn.Forte@Sun.COM 	fct_i_remote_port_t *irp = remote_port;
5267836SJohn.Forte@Sun.COM 	int	count = 0, i = 0;
5277836SJohn.Forte@Sun.COM 
5287836SJohn.Forte@Sun.COM 	port_attr->version = FCT_HBA_PORT_ATTRIBUTES_VERSION;
5297836SJohn.Forte@Sun.COM 	if (!remote_port) {
5307836SJohn.Forte@Sun.COM 		iport = fct_get_iport_per_wwn(port_wwn);
5317836SJohn.Forte@Sun.COM 		if (!iport) {
5327836SJohn.Forte@Sun.COM 			*error_detail = FCTIO_BADWWN;
5337836SJohn.Forte@Sun.COM 			return (ENXIO);
5347836SJohn.Forte@Sun.COM 		}
5357836SJohn.Forte@Sun.COM 
5367836SJohn.Forte@Sun.COM 		rw_enter(&iport->iport_lock, RW_READER);
5377836SJohn.Forte@Sun.COM 
5387836SJohn.Forte@Sun.COM 		if (index >= iport->iport_nrps_login) {
5397836SJohn.Forte@Sun.COM 			rw_exit(&iport->iport_lock);
5407836SJohn.Forte@Sun.COM 			*error_detail = FCTIO_OUTOFBOUNDS;
5417836SJohn.Forte@Sun.COM 			return (EINVAL);
5427836SJohn.Forte@Sun.COM 		}
5437836SJohn.Forte@Sun.COM 		for (; i < iport->iport_port->port_max_logins; i++) {
5447836SJohn.Forte@Sun.COM 			irp = iport->iport_rp_slots[i];
5457836SJohn.Forte@Sun.COM 			if (irp && irp->irp_flags & IRP_PLOGI_DONE &&
5467836SJohn.Forte@Sun.COM 			    !FC_WELL_KNOWN_ADDR(irp->irp_portid)) {
5477836SJohn.Forte@Sun.COM 				count ++;
5487836SJohn.Forte@Sun.COM 				if ((index + 1) <= count)
5497836SJohn.Forte@Sun.COM 					break;
5507836SJohn.Forte@Sun.COM 			}
5517836SJohn.Forte@Sun.COM 		}
5527836SJohn.Forte@Sun.COM 		if (i >= iport->iport_port->port_max_logins) {
5537836SJohn.Forte@Sun.COM 			rw_exit(&iport->iport_lock);
5547836SJohn.Forte@Sun.COM 			*error_detail = FCTIO_OUTOFBOUNDS;
5557836SJohn.Forte@Sun.COM 			return (EINVAL);
5567836SJohn.Forte@Sun.COM 		}
5577836SJohn.Forte@Sun.COM 		ASSERT(irp);
5587836SJohn.Forte@Sun.COM 	} else {
5597836SJohn.Forte@Sun.COM 		iport = (fct_i_local_port_t *)
5607836SJohn.Forte@Sun.COM 		    irp->irp_rp->rp_port->port_fct_private;
5617836SJohn.Forte@Sun.COM 	}
5627836SJohn.Forte@Sun.COM 	port_attr->lastChange = iport->iport_last_change;
5637836SJohn.Forte@Sun.COM 	rw_enter(&irp->irp_lock, RW_READER);
5647836SJohn.Forte@Sun.COM 	bcopy(irp->irp_rp->rp_pwwn, port_attr->PortWWN,
5657836SJohn.Forte@Sun.COM 	    sizeof (port_attr->PortWWN));
5667836SJohn.Forte@Sun.COM 	bcopy(irp->irp_rp->rp_nwwn, port_attr->NodeWWN,
5677836SJohn.Forte@Sun.COM 	    sizeof (port_attr->NodeWWN));
5687836SJohn.Forte@Sun.COM 	port_attr->PortFcId = irp->irp_portid;
5697836SJohn.Forte@Sun.COM 	if (irp->irp_spn)
5707836SJohn.Forte@Sun.COM 		(void) strncpy(port_attr->PortSymbolicName, irp->irp_spn,
5717836SJohn.Forte@Sun.COM 		    strlen(irp->irp_spn));
5727836SJohn.Forte@Sun.COM 	else
5737836SJohn.Forte@Sun.COM 		port_attr->PortSymbolicName[0] = '\0';
5747836SJohn.Forte@Sun.COM 	port_attr->PortSupportedClassofService = irp->irp_cos;
5757836SJohn.Forte@Sun.COM 	bcopy((caddr_t)irp->irp_fc4types, port_attr->PortActiveFc4Types,
5767836SJohn.Forte@Sun.COM 	    sizeof (irp->irp_fc4types));
5777836SJohn.Forte@Sun.COM 	bcopy((caddr_t)irp->irp_fc4types, port_attr->PortSupportedFc4Types,
5787836SJohn.Forte@Sun.COM 	    sizeof (irp->irp_fc4types));
5797836SJohn.Forte@Sun.COM 	if (irp->irp_flags & IRP_PLOGI_DONE)
5807836SJohn.Forte@Sun.COM 		port_attr->PortState = FC_HBA_PORTSTATE_ONLINE;
5817836SJohn.Forte@Sun.COM 	else
5827836SJohn.Forte@Sun.COM 		port_attr->PortState = FC_HBA_PORTSTATE_UNKNOWN;
5837836SJohn.Forte@Sun.COM 
5847836SJohn.Forte@Sun.COM 	port_attr->PortType = FC_HBA_PORTTYPE_UNKNOWN;
5857836SJohn.Forte@Sun.COM 	port_attr->PortSupportedSpeed = FC_HBA_PORTSPEED_UNKNOWN;
5867836SJohn.Forte@Sun.COM 	port_attr->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
5877836SJohn.Forte@Sun.COM 	port_attr->PortMaxFrameSize = 0;
5887836SJohn.Forte@Sun.COM 	port_attr->NumberofDiscoveredPorts = 0;
5897836SJohn.Forte@Sun.COM 	rw_exit(&irp->irp_lock);
5907836SJohn.Forte@Sun.COM 	if (!remote_port) {
5917836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
5927836SJohn.Forte@Sun.COM 	}
5937836SJohn.Forte@Sun.COM 	return (0);
5947836SJohn.Forte@Sun.COM }
5957836SJohn.Forte@Sun.COM 
5967836SJohn.Forte@Sun.COM int
fct_get_port_attr(uint8_t * port_wwn,fc_tgt_hba_port_attributes_t * port_attr,uint32_t * error_detail)5977836SJohn.Forte@Sun.COM fct_get_port_attr(uint8_t *port_wwn,
5987836SJohn.Forte@Sun.COM     fc_tgt_hba_port_attributes_t *port_attr, uint32_t *error_detail)
5997836SJohn.Forte@Sun.COM {
6007836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport;
6017836SJohn.Forte@Sun.COM 	fct_i_remote_port_t *irp;
6027836SJohn.Forte@Sun.COM 	int i, ret;
6037836SJohn.Forte@Sun.COM 
6047836SJohn.Forte@Sun.COM 	iport = fct_get_iport_per_wwn(port_wwn);
6057836SJohn.Forte@Sun.COM 	if (iport) {
6067836SJohn.Forte@Sun.COM 		return (fct_get_adapter_port_attr(iport, port_wwn,
6077836SJohn.Forte@Sun.COM 		    port_attr, error_detail));
6087836SJohn.Forte@Sun.COM 	}
6097836SJohn.Forte@Sun.COM 	/* else */
6107836SJohn.Forte@Sun.COM 	for (iport = fct_iport_list; iport; iport = iport->iport_next) {
6117836SJohn.Forte@Sun.COM 		rw_enter(&iport->iport_lock, RW_READER);
6127836SJohn.Forte@Sun.COM 		for (i = 0; i < rportid_table_size; i++) {
6137836SJohn.Forte@Sun.COM 			irp = iport->iport_rp_tb[i];
6147836SJohn.Forte@Sun.COM 			while (irp) {
6157836SJohn.Forte@Sun.COM 				if (bcmp(irp->irp_rp->rp_pwwn,
6167836SJohn.Forte@Sun.COM 				    port_wwn, 8) == 0 &&
6177836SJohn.Forte@Sun.COM 				    irp->irp_flags & IRP_PLOGI_DONE) {
6187836SJohn.Forte@Sun.COM 					ret = fct_get_discovered_port_attr(
6197836SJohn.Forte@Sun.COM 					    irp, NULL, 0, port_attr,
6207836SJohn.Forte@Sun.COM 					    error_detail);
6217836SJohn.Forte@Sun.COM 					rw_exit(&iport->iport_lock);
6227836SJohn.Forte@Sun.COM 					return (ret);
6237836SJohn.Forte@Sun.COM 				}
6247836SJohn.Forte@Sun.COM 				irp = irp->irp_next;
6257836SJohn.Forte@Sun.COM 			}
6267836SJohn.Forte@Sun.COM 		}
6277836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
6287836SJohn.Forte@Sun.COM 	}
6297836SJohn.Forte@Sun.COM 	*error_detail = FCTIO_BADWWN;
6307836SJohn.Forte@Sun.COM 	return (ENXIO);
6317836SJohn.Forte@Sun.COM }
6327836SJohn.Forte@Sun.COM 
6337836SJohn.Forte@Sun.COM /* ARGSUSED */
6347836SJohn.Forte@Sun.COM int
fct_get_port_stats(uint8_t * port_wwn,fc_tgt_hba_adapter_port_stats_t * port_stats,uint32_t * error_detail)6357836SJohn.Forte@Sun.COM fct_get_port_stats(uint8_t *port_wwn,
6367836SJohn.Forte@Sun.COM     fc_tgt_hba_adapter_port_stats_t *port_stats, uint32_t *error_detail)
6377836SJohn.Forte@Sun.COM {
63810088SAllan.Ou@Sun.COM 	int ret;
6397836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn);
64010088SAllan.Ou@Sun.COM 	fct_port_link_status_t	stat;
64110088SAllan.Ou@Sun.COM 	uint32_t buf_size = sizeof (fc_tgt_hba_adapter_port_stats_t);
6427836SJohn.Forte@Sun.COM 
6437836SJohn.Forte@Sun.COM 	if (!iport)
6447836SJohn.Forte@Sun.COM 		return (ENXIO);
6457836SJohn.Forte@Sun.COM 	port_stats->version = FCT_HBA_ADAPTER_PORT_STATS_VERSION;
64610088SAllan.Ou@Sun.COM 
64710088SAllan.Ou@Sun.COM 	if (iport->iport_port->port_info == NULL) {
64810088SAllan.Ou@Sun.COM 		*error_detail = FCTIO_FAILURE;
64910088SAllan.Ou@Sun.COM 		return (EIO);
65010088SAllan.Ou@Sun.COM 	}
65110088SAllan.Ou@Sun.COM 	ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
65210088SAllan.Ou@Sun.COM 	    iport->iport_port, NULL, (uint8_t *)&stat, &buf_size);
65310088SAllan.Ou@Sun.COM 	if (ret != STMF_SUCCESS) {
65410088SAllan.Ou@Sun.COM 		*error_detail = FCTIO_FAILURE;
65510088SAllan.Ou@Sun.COM 		return (EIO);
65610088SAllan.Ou@Sun.COM 	}
65710088SAllan.Ou@Sun.COM 
65810088SAllan.Ou@Sun.COM 	port_stats->SecondsSinceLastReset = 0;
65910088SAllan.Ou@Sun.COM 	port_stats->TxFrames = 0;
66010088SAllan.Ou@Sun.COM 	port_stats->TxWords = 0;
66110088SAllan.Ou@Sun.COM 	port_stats->RxFrames = 0;
66210088SAllan.Ou@Sun.COM 	port_stats->RxWords = 0;
66310088SAllan.Ou@Sun.COM 	port_stats->LIPCount = 0;
66410088SAllan.Ou@Sun.COM 	port_stats->NOSCount = 0;
66510088SAllan.Ou@Sun.COM 	port_stats->ErrorFrames = 0;
66610088SAllan.Ou@Sun.COM 	port_stats->DumpedFrames = 0;
66710088SAllan.Ou@Sun.COM 	port_stats->LinkFailureCount = stat.LinkFailureCount;
66810088SAllan.Ou@Sun.COM 	port_stats->LossOfSyncCount = stat.LossOfSyncCount;
66910088SAllan.Ou@Sun.COM 	port_stats->LossOfSignalCount = stat.LossOfSignalsCount;
67010088SAllan.Ou@Sun.COM 	port_stats->PrimitiveSeqProtocolErrCount =
67110088SAllan.Ou@Sun.COM 	    stat.PrimitiveSeqProtocolErrorCount;
67210088SAllan.Ou@Sun.COM 	port_stats->InvalidTxWordCount =
67310088SAllan.Ou@Sun.COM 	    stat.InvalidTransmissionWordCount;
67410088SAllan.Ou@Sun.COM 	port_stats->InvalidCRCCount = stat.InvalidCRCCount;
67510088SAllan.Ou@Sun.COM 
67610088SAllan.Ou@Sun.COM 	return (ret);
67710088SAllan.Ou@Sun.COM }
67810088SAllan.Ou@Sun.COM 
67910088SAllan.Ou@Sun.COM int
fct_get_link_status(uint8_t * port_wwn,uint64_t * dest_id,fct_port_link_status_t * link_status,uint32_t * error_detail)68010088SAllan.Ou@Sun.COM fct_get_link_status(uint8_t *port_wwn, uint64_t *dest_id,
68110088SAllan.Ou@Sun.COM     fct_port_link_status_t *link_status, uint32_t *error_detail)
68210088SAllan.Ou@Sun.COM {
68310088SAllan.Ou@Sun.COM 	fct_i_local_port_t *iport = fct_get_iport_per_wwn(port_wwn);
68410088SAllan.Ou@Sun.COM 	fct_i_remote_port_t *irp = NULL;
68510088SAllan.Ou@Sun.COM 	uint32_t buf_size = sizeof (fct_port_link_status_t);
68610088SAllan.Ou@Sun.COM 	stmf_status_t ret = 0;
68710088SAllan.Ou@Sun.COM 	int i;
68810088SAllan.Ou@Sun.COM 	fct_cmd_t *cmd = NULL;
68910088SAllan.Ou@Sun.COM 
69010088SAllan.Ou@Sun.COM 	if (!iport) {
69110088SAllan.Ou@Sun.COM 		*error_detail = FCTIO_BADWWN;
69210088SAllan.Ou@Sun.COM 		return (ENXIO);
69310088SAllan.Ou@Sun.COM 	}
69410088SAllan.Ou@Sun.COM 
6957836SJohn.Forte@Sun.COM 	/*
69610088SAllan.Ou@Sun.COM 	 * If what we are requesting is zero or same as local port,
69710088SAllan.Ou@Sun.COM 	 * then we use port_info()
69810088SAllan.Ou@Sun.COM 	 */
69910088SAllan.Ou@Sun.COM 	if (dest_id == NULL || *dest_id == iport->iport_link_info.portid) {
70010088SAllan.Ou@Sun.COM 		if (iport->iport_port->port_info == NULL) {
70110088SAllan.Ou@Sun.COM 			*error_detail = FCTIO_FAILURE;
70210088SAllan.Ou@Sun.COM 			return (EIO);
70310088SAllan.Ou@Sun.COM 		}
70410088SAllan.Ou@Sun.COM 		ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
70510088SAllan.Ou@Sun.COM 		    iport->iport_port, NULL,
70610088SAllan.Ou@Sun.COM 		    (uint8_t *)link_status, &buf_size);
70710088SAllan.Ou@Sun.COM 		if (ret == STMF_SUCCESS) {
70810088SAllan.Ou@Sun.COM 			return (0);
70910088SAllan.Ou@Sun.COM 		} else {
71010088SAllan.Ou@Sun.COM 			*error_detail = FCTIO_FAILURE;
71110088SAllan.Ou@Sun.COM 			return (EIO);
71210088SAllan.Ou@Sun.COM 		}
71310088SAllan.Ou@Sun.COM 	}
71410088SAllan.Ou@Sun.COM 
71510088SAllan.Ou@Sun.COM 	/*
71610088SAllan.Ou@Sun.COM 	 * For remote port, we will send RLS
7177836SJohn.Forte@Sun.COM 	 */
71810088SAllan.Ou@Sun.COM 	for (i = 0; i < rportid_table_size; i++) {
71910088SAllan.Ou@Sun.COM 		irp = iport->iport_rp_tb[i];
72010088SAllan.Ou@Sun.COM 		while (irp) {
72110088SAllan.Ou@Sun.COM 			if (irp->irp_rp->rp_id == *dest_id &&
72210088SAllan.Ou@Sun.COM 			    irp->irp_flags & IRP_PLOGI_DONE) {
72310088SAllan.Ou@Sun.COM 				goto SEND_RLS_ELS;
72410088SAllan.Ou@Sun.COM 			}
72510088SAllan.Ou@Sun.COM 			irp = irp->irp_next;
72610088SAllan.Ou@Sun.COM 		}
72710088SAllan.Ou@Sun.COM 	}
72810088SAllan.Ou@Sun.COM 	return (ENXIO);
72910088SAllan.Ou@Sun.COM 
73010088SAllan.Ou@Sun.COM SEND_RLS_ELS:
73110088SAllan.Ou@Sun.COM 	cmd = fct_create_solels(iport->iport_port,
73210088SAllan.Ou@Sun.COM 	    irp->irp_rp, 0, ELS_OP_RLS,
73310088SAllan.Ou@Sun.COM 	    0, fct_rls_cb);
73410088SAllan.Ou@Sun.COM 	if (!cmd)
73510088SAllan.Ou@Sun.COM 		return (ENOMEM);
73610088SAllan.Ou@Sun.COM 	iport->iport_rls_cb_data.fct_link_status = link_status;
73710088SAllan.Ou@Sun.COM 	CMD_TO_ICMD(cmd)->icmd_cb_private = &iport->iport_rls_cb_data;
73810088SAllan.Ou@Sun.COM 	fct_post_to_solcmd_queue(iport->iport_port, cmd);
73910088SAllan.Ou@Sun.COM 	sema_p(&iport->iport_rls_sema);
74010088SAllan.Ou@Sun.COM 	if (iport->iport_rls_cb_data.fct_els_res != FCT_SUCCESS)
74110088SAllan.Ou@Sun.COM 		ret = EIO;
74210088SAllan.Ou@Sun.COM 	return (ret);
7437836SJohn.Forte@Sun.COM }
7447836SJohn.Forte@Sun.COM 
7457836SJohn.Forte@Sun.COM static int
fct_forcelip(uint8_t * port_wwn,uint32_t * fctio_errno)74610275SReed.Liu@Sun.COM fct_forcelip(uint8_t *port_wwn, uint32_t *fctio_errno)
74710275SReed.Liu@Sun.COM {
74810275SReed.Liu@Sun.COM 	fct_status_t		 rval;
74910275SReed.Liu@Sun.COM 	fct_i_local_port_t	*iport;
75010275SReed.Liu@Sun.COM 
75110275SReed.Liu@Sun.COM 	mutex_enter(&fct_global_mutex);
75210275SReed.Liu@Sun.COM 	iport = fct_get_iport_per_wwn(port_wwn);
75310275SReed.Liu@Sun.COM 	mutex_exit(&fct_global_mutex);
75410275SReed.Liu@Sun.COM 	if (iport == NULL) {
75510275SReed.Liu@Sun.COM 		return (-1);
75610275SReed.Liu@Sun.COM 	}
75710275SReed.Liu@Sun.COM 
75810275SReed.Liu@Sun.COM 	iport->iport_port->port_ctl(iport->iport_port,
75910275SReed.Liu@Sun.COM 	    FCT_CMD_FORCE_LIP, &rval);
76010275SReed.Liu@Sun.COM 	if (rval != FCT_SUCCESS) {
76110275SReed.Liu@Sun.COM 		*fctio_errno = FCTIO_FAILURE;
76210275SReed.Liu@Sun.COM 	} else {
76310275SReed.Liu@Sun.COM 		*fctio_errno = 0;
76410275SReed.Liu@Sun.COM 	}
76510275SReed.Liu@Sun.COM 
76610275SReed.Liu@Sun.COM 	return (0);
76710275SReed.Liu@Sun.COM }
76810275SReed.Liu@Sun.COM 
76910275SReed.Liu@Sun.COM static int
fct_fctiocmd(intptr_t data,int mode)7707836SJohn.Forte@Sun.COM fct_fctiocmd(intptr_t data, int mode)
7717836SJohn.Forte@Sun.COM {
7727836SJohn.Forte@Sun.COM 	int ret	 = 0;
7737836SJohn.Forte@Sun.COM 	void		*ibuf = NULL;
7747836SJohn.Forte@Sun.COM 	void		*obuf = NULL;
7757836SJohn.Forte@Sun.COM 	void		*abuf = NULL;
7767836SJohn.Forte@Sun.COM 	fctio_t		*fctio;
7777836SJohn.Forte@Sun.COM 	uint32_t	attr_length;
7787836SJohn.Forte@Sun.COM 
7797836SJohn.Forte@Sun.COM 	ret = fct_copyin_iocdata(data, mode, &fctio, &ibuf, &abuf, &obuf);
7807836SJohn.Forte@Sun.COM 	if (ret) {
7817836SJohn.Forte@Sun.COM 		return (ret);
7827836SJohn.Forte@Sun.COM 	}
7837836SJohn.Forte@Sun.COM 
7847836SJohn.Forte@Sun.COM 	switch (fctio->fctio_cmd) {
7857836SJohn.Forte@Sun.COM 	case FCTIO_ADAPTER_LIST: {
7867836SJohn.Forte@Sun.COM 		fc_tgt_hba_list_t *list = (fc_tgt_hba_list_t *)obuf;
7877836SJohn.Forte@Sun.COM 		int		count;
7887836SJohn.Forte@Sun.COM 
7897836SJohn.Forte@Sun.COM 		if (fctio->fctio_olen < sizeof (fc_tgt_hba_list_t)) {
7907836SJohn.Forte@Sun.COM 			ret = EINVAL;
7917836SJohn.Forte@Sun.COM 			break;
7927836SJohn.Forte@Sun.COM 		}
7937836SJohn.Forte@Sun.COM 		list->numPorts = (fctio->fctio_olen -
7947836SJohn.Forte@Sun.COM 		    sizeof (fc_tgt_hba_list_t))/8 + 1;
7957836SJohn.Forte@Sun.COM 
7967836SJohn.Forte@Sun.COM 		list->version = FCT_HBA_LIST_VERSION;
7977836SJohn.Forte@Sun.COM 		count = fct_get_port_list((char *)list->port_wwn,
7987836SJohn.Forte@Sun.COM 		    list->numPorts);
7997836SJohn.Forte@Sun.COM 		if (count < 0) {
8007836SJohn.Forte@Sun.COM 			ret = ENXIO;
8017836SJohn.Forte@Sun.COM 			break;
8027836SJohn.Forte@Sun.COM 		}
8037836SJohn.Forte@Sun.COM 		if (count > list->numPorts) {
8047836SJohn.Forte@Sun.COM 			fctio->fctio_errno = FCTIO_MOREDATA;
8057836SJohn.Forte@Sun.COM 			ret = ENOSPC;
8067836SJohn.Forte@Sun.COM 		}
8077836SJohn.Forte@Sun.COM 		list->numPorts = count;
8087836SJohn.Forte@Sun.COM 		break;
8097836SJohn.Forte@Sun.COM 		}
8107836SJohn.Forte@Sun.COM 	case FCTIO_GET_ADAPTER_ATTRIBUTES: {
8117836SJohn.Forte@Sun.COM 		fc_tgt_hba_adapter_attributes_t *hba_attr;
8127836SJohn.Forte@Sun.COM 		uint8_t	*port_wwn = (uint8_t *)ibuf;
8137836SJohn.Forte@Sun.COM 
8147836SJohn.Forte@Sun.COM 		attr_length = sizeof (fc_tgt_hba_adapter_attributes_t);
8157836SJohn.Forte@Sun.COM 		if (fctio->fctio_olen < attr_length ||
8167836SJohn.Forte@Sun.COM 		    fctio->fctio_xfer != FCTIO_XFER_READ) {
8177836SJohn.Forte@Sun.COM 			ret = EINVAL;
8187836SJohn.Forte@Sun.COM 			break;
8197836SJohn.Forte@Sun.COM 		}
8207836SJohn.Forte@Sun.COM 		hba_attr = (fc_tgt_hba_adapter_attributes_t *)obuf;
8217836SJohn.Forte@Sun.COM 
8227836SJohn.Forte@Sun.COM 		mutex_enter(&fct_global_mutex);
8237836SJohn.Forte@Sun.COM 		ret = fct_get_adapter_attr(port_wwn, hba_attr,
8247836SJohn.Forte@Sun.COM 		    &fctio->fctio_errno);
8257836SJohn.Forte@Sun.COM 		mutex_exit(&fct_global_mutex);
8267836SJohn.Forte@Sun.COM 
8277836SJohn.Forte@Sun.COM 		break;
8287836SJohn.Forte@Sun.COM 		}
8297836SJohn.Forte@Sun.COM 	case FCTIO_GET_ADAPTER_PORT_ATTRIBUTES: {
8307836SJohn.Forte@Sun.COM 		fc_tgt_hba_port_attributes_t *port_attr;
8317836SJohn.Forte@Sun.COM 
8327836SJohn.Forte@Sun.COM 		uint8_t *port_wwn = (uint8_t *)ibuf;
8337836SJohn.Forte@Sun.COM 
8347836SJohn.Forte@Sun.COM 		attr_length = sizeof (fc_tgt_hba_port_attributes_t);
8357836SJohn.Forte@Sun.COM 		if (fctio->fctio_olen < attr_length ||
8367836SJohn.Forte@Sun.COM 		    fctio->fctio_xfer != FCTIO_XFER_READ) {
8377836SJohn.Forte@Sun.COM 			ret = EINVAL;
8387836SJohn.Forte@Sun.COM 			break;
8397836SJohn.Forte@Sun.COM 		}
8407836SJohn.Forte@Sun.COM 		port_attr = (fc_tgt_hba_port_attributes_t *)obuf;
8417836SJohn.Forte@Sun.COM 
8427836SJohn.Forte@Sun.COM 		mutex_enter(&fct_global_mutex);
8437836SJohn.Forte@Sun.COM 		ret = fct_get_adapter_port_attr(NULL, port_wwn, port_attr,
8447836SJohn.Forte@Sun.COM 		    &fctio->fctio_errno);
8457836SJohn.Forte@Sun.COM 		mutex_exit(&fct_global_mutex);
8467836SJohn.Forte@Sun.COM 
8477836SJohn.Forte@Sun.COM 		break;
8487836SJohn.Forte@Sun.COM 		}
8497836SJohn.Forte@Sun.COM 	case FCTIO_GET_DISCOVERED_PORT_ATTRIBUTES: {
8507836SJohn.Forte@Sun.COM 		uint8_t *port_wwn = (uint8_t *)ibuf;
8517836SJohn.Forte@Sun.COM 		uint32_t *port_index = (uint32_t *)abuf;
8527836SJohn.Forte@Sun.COM 		fc_tgt_hba_port_attributes_t *port_attr;
8537836SJohn.Forte@Sun.COM 
8547836SJohn.Forte@Sun.COM 		attr_length = sizeof (fc_tgt_hba_port_attributes_t);
8557836SJohn.Forte@Sun.COM 		if (fctio->fctio_olen < attr_length ||
8567836SJohn.Forte@Sun.COM 		    fctio->fctio_xfer != FCTIO_XFER_READ) {
8577836SJohn.Forte@Sun.COM 			ret = EINVAL;
8587836SJohn.Forte@Sun.COM 			break;
8597836SJohn.Forte@Sun.COM 		}
8607836SJohn.Forte@Sun.COM 		port_attr = (fc_tgt_hba_port_attributes_t *)obuf;
8617836SJohn.Forte@Sun.COM 
8627836SJohn.Forte@Sun.COM 		mutex_enter(&fct_global_mutex);
8637836SJohn.Forte@Sun.COM 		ret = fct_get_discovered_port_attr(NULL, port_wwn,
8647836SJohn.Forte@Sun.COM 		    *port_index, port_attr, &fctio->fctio_errno);
8657836SJohn.Forte@Sun.COM 		mutex_exit(&fct_global_mutex);
8667836SJohn.Forte@Sun.COM 
8677836SJohn.Forte@Sun.COM 		break;
8687836SJohn.Forte@Sun.COM 		}
8697836SJohn.Forte@Sun.COM 	case FCTIO_GET_PORT_ATTRIBUTES: {
8707836SJohn.Forte@Sun.COM 		uint8_t *port_wwn = (uint8_t *)ibuf;
8717836SJohn.Forte@Sun.COM 		fc_tgt_hba_port_attributes_t *port_attr;
8727836SJohn.Forte@Sun.COM 
8737836SJohn.Forte@Sun.COM 		attr_length = sizeof (fc_tgt_hba_port_attributes_t);
8747836SJohn.Forte@Sun.COM 		if (fctio->fctio_olen < attr_length ||
8757836SJohn.Forte@Sun.COM 		    fctio->fctio_xfer != FCTIO_XFER_READ) {
8767836SJohn.Forte@Sun.COM 			ret = EINVAL;
8777836SJohn.Forte@Sun.COM 			break;
8787836SJohn.Forte@Sun.COM 		}
8797836SJohn.Forte@Sun.COM 
8807836SJohn.Forte@Sun.COM 		port_attr = (fc_tgt_hba_port_attributes_t *)obuf;
8817836SJohn.Forte@Sun.COM 
8827836SJohn.Forte@Sun.COM 		mutex_enter(&fct_global_mutex);
8837836SJohn.Forte@Sun.COM 		ret = fct_get_port_attr(port_wwn, port_attr,
8847836SJohn.Forte@Sun.COM 		    &fctio->fctio_errno);
8857836SJohn.Forte@Sun.COM 		mutex_exit(&fct_global_mutex);
8867836SJohn.Forte@Sun.COM 
8877836SJohn.Forte@Sun.COM 		break;
8887836SJohn.Forte@Sun.COM 		}
8897836SJohn.Forte@Sun.COM 	case FCTIO_GET_ADAPTER_PORT_STATS: {
8907836SJohn.Forte@Sun.COM 		uint8_t *port_wwn = (uint8_t *)ibuf;
8917836SJohn.Forte@Sun.COM 		fc_tgt_hba_adapter_port_stats_t *port_stats =
8927836SJohn.Forte@Sun.COM 		    (fc_tgt_hba_adapter_port_stats_t *)obuf;
8937836SJohn.Forte@Sun.COM 		mutex_enter(&fct_global_mutex);
8947836SJohn.Forte@Sun.COM 		ret = fct_get_port_stats(port_wwn, port_stats,
8957836SJohn.Forte@Sun.COM 		    &fctio->fctio_errno);
8967836SJohn.Forte@Sun.COM 		mutex_exit(&fct_global_mutex);
8977836SJohn.Forte@Sun.COM 		break;
8987836SJohn.Forte@Sun.COM 		}
89910088SAllan.Ou@Sun.COM 	case FCTIO_GET_LINK_STATUS: {
90010088SAllan.Ou@Sun.COM 		uint8_t *port_wwn = (uint8_t *)ibuf;
90110088SAllan.Ou@Sun.COM 		fct_port_link_status_t *link_status =
90210088SAllan.Ou@Sun.COM 		    (fct_port_link_status_t *)obuf;
90310088SAllan.Ou@Sun.COM 		uint64_t *dest_id = abuf;
90410088SAllan.Ou@Sun.COM 
90510088SAllan.Ou@Sun.COM 		mutex_enter(&fct_global_mutex);
90610088SAllan.Ou@Sun.COM 		ret = fct_get_link_status(port_wwn, dest_id, link_status,
90710088SAllan.Ou@Sun.COM 		    &fctio->fctio_errno);
90810088SAllan.Ou@Sun.COM 		mutex_exit(&fct_global_mutex);
90910088SAllan.Ou@Sun.COM 		break;
91010088SAllan.Ou@Sun.COM 		}
91110088SAllan.Ou@Sun.COM 
91210275SReed.Liu@Sun.COM 	case FCTIO_FORCE_LIP:
91310275SReed.Liu@Sun.COM 		ret = fct_forcelip((uint8_t *)ibuf, &fctio->fctio_errno);
91410275SReed.Liu@Sun.COM 		break;
91510275SReed.Liu@Sun.COM 
9167836SJohn.Forte@Sun.COM 	default:
9177836SJohn.Forte@Sun.COM 		break;
9187836SJohn.Forte@Sun.COM 	}
9197836SJohn.Forte@Sun.COM 	if (ret == 0) {
9207836SJohn.Forte@Sun.COM 		ret = fct_copyout_iocdata(data, mode, fctio, obuf);
9217836SJohn.Forte@Sun.COM 	} else if (fctio->fctio_errno) {
9227836SJohn.Forte@Sun.COM 		(void) fct_copyout_iocdata(data, mode, fctio, obuf);
9237836SJohn.Forte@Sun.COM 	}
9247836SJohn.Forte@Sun.COM 
9257836SJohn.Forte@Sun.COM 	if (obuf) {
9267836SJohn.Forte@Sun.COM 		kmem_free(obuf, fctio->fctio_olen);
9277836SJohn.Forte@Sun.COM 		obuf = NULL;
9287836SJohn.Forte@Sun.COM 	}
9297836SJohn.Forte@Sun.COM 	if (abuf) {
9307836SJohn.Forte@Sun.COM 		kmem_free(abuf, fctio->fctio_alen);
9317836SJohn.Forte@Sun.COM 		abuf = NULL;
9327836SJohn.Forte@Sun.COM 	}
9337836SJohn.Forte@Sun.COM 
9347836SJohn.Forte@Sun.COM 	if (ibuf) {
9357836SJohn.Forte@Sun.COM 		kmem_free(ibuf, fctio->fctio_ilen);
9367836SJohn.Forte@Sun.COM 		ibuf = NULL;
9377836SJohn.Forte@Sun.COM 	}
9387836SJohn.Forte@Sun.COM 	kmem_free(fctio, sizeof (fctio_t));
9397836SJohn.Forte@Sun.COM 	return (ret);
9407836SJohn.Forte@Sun.COM }
9417836SJohn.Forte@Sun.COM 
9427836SJohn.Forte@Sun.COM typedef struct {
9437836SJohn.Forte@Sun.COM 	void	*bp;	/* back pointer from internal struct to main struct */
9447836SJohn.Forte@Sun.COM 	int	alloc_size;
9457836SJohn.Forte@Sun.COM 	fct_struct_id_t struct_id;
9467836SJohn.Forte@Sun.COM } __ifct_t;
9477836SJohn.Forte@Sun.COM 
9487836SJohn.Forte@Sun.COM typedef struct {
9497836SJohn.Forte@Sun.COM 	__ifct_t	*fp;	/* Framework private */
9507836SJohn.Forte@Sun.COM 	void		*cp;	/* Caller private */
9517836SJohn.Forte@Sun.COM 	void		*ss;	/* struct specific */
9527836SJohn.Forte@Sun.COM } __fct_t;
9537836SJohn.Forte@Sun.COM 
9547836SJohn.Forte@Sun.COM static struct {
9557836SJohn.Forte@Sun.COM 	int shared;
9567836SJohn.Forte@Sun.COM 	int fw_private;
9577836SJohn.Forte@Sun.COM 	int struct_specific;
9587836SJohn.Forte@Sun.COM } fct_sizes[] = { { 0, 0, 0 },
9597836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(fct_local_port_t),
9607836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(fct_i_local_port_t), 0 },
9617836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(fct_remote_port_t),
9627836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(fct_i_remote_port_t), 0 },
9637836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(fct_cmd_t),
9647836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(fct_i_cmd_t), GET_STRUCT_SIZE(fct_els_t) },
9657836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(fct_cmd_t),
9667836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(fct_i_cmd_t), GET_STRUCT_SIZE(fct_els_t) },
9677836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(fct_cmd_t),
9687836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(fct_i_cmd_t), GET_STRUCT_SIZE(fct_sol_ct_t) },
9697836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(fct_cmd_t), GET_STRUCT_SIZE(fct_i_cmd_t),
9707836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(fct_rcvd_abts_t) },
9717836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(fct_cmd_t),	/* FCT_STRUCT_CMD_FCP_XCHG */
9727836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(fct_i_cmd_t), 0 },
9737836SJohn.Forte@Sun.COM 	{ GET_STRUCT_SIZE(fct_dbuf_store_t),
9747836SJohn.Forte@Sun.COM 		GET_STRUCT_SIZE(__ifct_t), 0 }
9757836SJohn.Forte@Sun.COM };
9767836SJohn.Forte@Sun.COM 
9777836SJohn.Forte@Sun.COM void *
fct_alloc(fct_struct_id_t struct_id,int additional_size,int flags)9787836SJohn.Forte@Sun.COM fct_alloc(fct_struct_id_t struct_id, int additional_size, int flags)
9797836SJohn.Forte@Sun.COM {
9807836SJohn.Forte@Sun.COM 	int fct_size;
9817836SJohn.Forte@Sun.COM 	int kmem_flag;
9827836SJohn.Forte@Sun.COM 	__fct_t *sh;
9837836SJohn.Forte@Sun.COM 
9847836SJohn.Forte@Sun.COM 	if ((struct_id == 0) || (struct_id >= FCT_MAX_STRUCT_IDS))
9857836SJohn.Forte@Sun.COM 		return (NULL);
9867836SJohn.Forte@Sun.COM 
9877836SJohn.Forte@Sun.COM 	if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) {
9887836SJohn.Forte@Sun.COM 		kmem_flag = KM_NOSLEEP;
9897836SJohn.Forte@Sun.COM 	} else {
9907836SJohn.Forte@Sun.COM 		kmem_flag = KM_SLEEP;
9917836SJohn.Forte@Sun.COM 	}
9927836SJohn.Forte@Sun.COM 
9937836SJohn.Forte@Sun.COM 	additional_size = (additional_size + 7) & (~7);
9947836SJohn.Forte@Sun.COM 	fct_size = fct_sizes[struct_id].shared +
9959578SSam.Cramer@Sun.COM 	    fct_sizes[struct_id].fw_private +
9969578SSam.Cramer@Sun.COM 	    fct_sizes[struct_id].struct_specific + additional_size;
9977836SJohn.Forte@Sun.COM 
9987836SJohn.Forte@Sun.COM 	if (struct_id == FCT_STRUCT_LOCAL_PORT) {
9997836SJohn.Forte@Sun.COM 		stmf_local_port_t *lport;
10007836SJohn.Forte@Sun.COM 
10017836SJohn.Forte@Sun.COM 		lport = (stmf_local_port_t *)stmf_alloc(
10029578SSam.Cramer@Sun.COM 		    STMF_STRUCT_STMF_LOCAL_PORT, fct_size, flags);
10037836SJohn.Forte@Sun.COM 		if (lport) {
10047836SJohn.Forte@Sun.COM 			sh = (__fct_t *)lport->lport_port_private;
10057836SJohn.Forte@Sun.COM 			sh->ss = lport;
10067836SJohn.Forte@Sun.COM 		} else {
10077836SJohn.Forte@Sun.COM 			return (NULL);
10087836SJohn.Forte@Sun.COM 		}
10097836SJohn.Forte@Sun.COM 	} else if (struct_id == FCT_STRUCT_DBUF_STORE) {
10107836SJohn.Forte@Sun.COM 		stmf_dbuf_store_t *ds;
10117836SJohn.Forte@Sun.COM 
10127836SJohn.Forte@Sun.COM 		ds = (stmf_dbuf_store_t *)stmf_alloc(STMF_STRUCT_DBUF_STORE,
10139578SSam.Cramer@Sun.COM 		    fct_size, flags);
10147836SJohn.Forte@Sun.COM 		if (ds) {
10157836SJohn.Forte@Sun.COM 			sh = (__fct_t *)ds->ds_port_private;
10167836SJohn.Forte@Sun.COM 			sh->ss = ds;
10177836SJohn.Forte@Sun.COM 		} else {
10187836SJohn.Forte@Sun.COM 			return (NULL);
10197836SJohn.Forte@Sun.COM 		}
10207836SJohn.Forte@Sun.COM 	} else {
10217836SJohn.Forte@Sun.COM 		sh = (__fct_t *)kmem_zalloc(fct_size, kmem_flag);
10227836SJohn.Forte@Sun.COM 	}
10237836SJohn.Forte@Sun.COM 
10247836SJohn.Forte@Sun.COM 	if (sh == NULL)
10257836SJohn.Forte@Sun.COM 		return (NULL);
10267836SJohn.Forte@Sun.COM 
10277836SJohn.Forte@Sun.COM 	sh->fp = (__ifct_t *)GET_BYTE_OFFSET(sh, fct_sizes[struct_id].shared);
10287836SJohn.Forte@Sun.COM 	sh->cp = GET_BYTE_OFFSET(sh->fp, fct_sizes[struct_id].fw_private);
10297836SJohn.Forte@Sun.COM 	if (fct_sizes[struct_id].struct_specific)
10307836SJohn.Forte@Sun.COM 		sh->ss = GET_BYTE_OFFSET(sh->cp, additional_size);
10317836SJohn.Forte@Sun.COM 
10327836SJohn.Forte@Sun.COM 	sh->fp->bp = sh;
10337836SJohn.Forte@Sun.COM 	sh->fp->alloc_size = fct_size;
10347836SJohn.Forte@Sun.COM 	sh->fp->struct_id = struct_id;
10357836SJohn.Forte@Sun.COM 
10367836SJohn.Forte@Sun.COM 	if (struct_id == FCT_STRUCT_CMD_FCP_XCHG) {
10377836SJohn.Forte@Sun.COM 		((fct_cmd_t *)sh)->cmd_type = FCT_CMD_FCP_XCHG;
10387836SJohn.Forte@Sun.COM 	} else if (struct_id == FCT_STRUCT_CMD_RCVD_ELS) {
10397836SJohn.Forte@Sun.COM 		((fct_cmd_t *)sh)->cmd_type = FCT_CMD_RCVD_ELS;
10407836SJohn.Forte@Sun.COM 	} else if (struct_id == FCT_STRUCT_CMD_SOL_ELS) {
10417836SJohn.Forte@Sun.COM 		((fct_cmd_t *)sh)->cmd_type = FCT_CMD_SOL_ELS;
10427836SJohn.Forte@Sun.COM 	} else if (struct_id == FCT_STRUCT_CMD_RCVD_ABTS) {
10437836SJohn.Forte@Sun.COM 		((fct_cmd_t *)sh)->cmd_type = FCT_CMD_RCVD_ABTS;
10447836SJohn.Forte@Sun.COM 	} else if (struct_id == FCT_STRUCT_CMD_SOL_CT) {
10457836SJohn.Forte@Sun.COM 		((fct_cmd_t *)sh)->cmd_type = FCT_CMD_SOL_CT;
10467836SJohn.Forte@Sun.COM 	}
10477836SJohn.Forte@Sun.COM 
10487836SJohn.Forte@Sun.COM 	return (sh);
10497836SJohn.Forte@Sun.COM }
10507836SJohn.Forte@Sun.COM 
10517836SJohn.Forte@Sun.COM void
fct_free(void * ptr)10527836SJohn.Forte@Sun.COM fct_free(void *ptr)
10537836SJohn.Forte@Sun.COM {
10547836SJohn.Forte@Sun.COM 	__fct_t *sh = (__fct_t *)ptr;
10557836SJohn.Forte@Sun.COM 	fct_struct_id_t struct_id = sh->fp->struct_id;
10567836SJohn.Forte@Sun.COM 
10577836SJohn.Forte@Sun.COM 	if (struct_id == FCT_STRUCT_CMD_SOL_CT) {
10587836SJohn.Forte@Sun.COM 		fct_sol_ct_t *ct = (fct_sol_ct_t *)
10597836SJohn.Forte@Sun.COM 		    ((fct_cmd_t *)ptr)->cmd_specific;
10607836SJohn.Forte@Sun.COM 
10617836SJohn.Forte@Sun.COM 		if (ct->ct_req_alloc_size) {
10627836SJohn.Forte@Sun.COM 			kmem_free(ct->ct_req_payload, ct->ct_req_alloc_size);
10637836SJohn.Forte@Sun.COM 		}
10647836SJohn.Forte@Sun.COM 		if (ct->ct_resp_alloc_size) {
10657836SJohn.Forte@Sun.COM 			kmem_free(ct->ct_resp_payload, ct->ct_resp_alloc_size);
10667836SJohn.Forte@Sun.COM 		}
10677836SJohn.Forte@Sun.COM 	} else if ((struct_id == FCT_STRUCT_CMD_RCVD_ELS) ||
10687836SJohn.Forte@Sun.COM 	    (struct_id == FCT_STRUCT_CMD_SOL_ELS)) {
10697836SJohn.Forte@Sun.COM 		fct_els_t *els = (fct_els_t *)
10707836SJohn.Forte@Sun.COM 			((fct_cmd_t *)ptr)->cmd_specific;
10717836SJohn.Forte@Sun.COM 		if (els->els_req_alloc_size)
10727836SJohn.Forte@Sun.COM 			kmem_free(els->els_req_payload,
10737836SJohn.Forte@Sun.COM 				els->els_req_alloc_size);
10747836SJohn.Forte@Sun.COM 		if (els->els_resp_alloc_size)
10757836SJohn.Forte@Sun.COM 			kmem_free(els->els_resp_payload,
10767836SJohn.Forte@Sun.COM 				els->els_resp_alloc_size);
10777836SJohn.Forte@Sun.COM 	}
10787836SJohn.Forte@Sun.COM 
10797836SJohn.Forte@Sun.COM 	if (struct_id == FCT_STRUCT_LOCAL_PORT) {
10807836SJohn.Forte@Sun.COM 		stmf_free(((fct_local_port_t *)ptr)->port_lport);
10817836SJohn.Forte@Sun.COM 	} else if (struct_id == FCT_STRUCT_DBUF_STORE) {
10827836SJohn.Forte@Sun.COM 		stmf_free(((fct_dbuf_store_t *)ptr)->fds_ds);
10837836SJohn.Forte@Sun.COM 	} else {
10847836SJohn.Forte@Sun.COM 		kmem_free(ptr, sh->fp->alloc_size);
10857836SJohn.Forte@Sun.COM 	}
10867836SJohn.Forte@Sun.COM }
10877836SJohn.Forte@Sun.COM 
10887836SJohn.Forte@Sun.COM stmf_data_buf_t *
fct_alloc_dbuf(scsi_task_t * task,uint32_t size,uint32_t * pminsize,uint32_t flags)10897836SJohn.Forte@Sun.COM fct_alloc_dbuf(scsi_task_t *task, uint32_t size, uint32_t *pminsize,
10907836SJohn.Forte@Sun.COM     uint32_t flags)
10917836SJohn.Forte@Sun.COM {
10927836SJohn.Forte@Sun.COM 	fct_local_port_t *port = (fct_local_port_t *)
10939578SSam.Cramer@Sun.COM 	    task->task_lport->lport_port_private;
10947836SJohn.Forte@Sun.COM 
10957836SJohn.Forte@Sun.COM 	return (port->port_fds->fds_alloc_data_buf(port, size,
10967836SJohn.Forte@Sun.COM 	    pminsize, flags));
10977836SJohn.Forte@Sun.COM }
10987836SJohn.Forte@Sun.COM 
109912314SJames.Moore@Sun.COM stmf_status_t
fct_setup_dbuf(scsi_task_t * task,stmf_data_buf_t * dbuf,uint32_t flags)110012314SJames.Moore@Sun.COM fct_setup_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t flags)
110112314SJames.Moore@Sun.COM {
110212314SJames.Moore@Sun.COM 	fct_local_port_t *port = (fct_local_port_t *)
110312314SJames.Moore@Sun.COM 	    task->task_lport->lport_port_private;
110412314SJames.Moore@Sun.COM 
110512314SJames.Moore@Sun.COM 	ASSERT(port->port_fds->fds_setup_dbuf != NULL);
110612314SJames.Moore@Sun.COM 	if (port->port_fds->fds_setup_dbuf == NULL)
110712314SJames.Moore@Sun.COM 		return (STMF_FAILURE);
110812314SJames.Moore@Sun.COM 
110912314SJames.Moore@Sun.COM 	return (port->port_fds->fds_setup_dbuf(port, dbuf, flags));
111012314SJames.Moore@Sun.COM }
111112314SJames.Moore@Sun.COM 
111212314SJames.Moore@Sun.COM void
fct_teardown_dbuf(stmf_dbuf_store_t * ds,stmf_data_buf_t * dbuf)111312314SJames.Moore@Sun.COM fct_teardown_dbuf(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf)
111412314SJames.Moore@Sun.COM {
111512314SJames.Moore@Sun.COM 	fct_dbuf_store_t *fds = ds->ds_port_private;
111612314SJames.Moore@Sun.COM 
111712314SJames.Moore@Sun.COM 	fds->fds_teardown_dbuf(fds, dbuf);
111812314SJames.Moore@Sun.COM }
111912314SJames.Moore@Sun.COM 
11207836SJohn.Forte@Sun.COM void
fct_free_dbuf(stmf_dbuf_store_t * ds,stmf_data_buf_t * dbuf)11217836SJohn.Forte@Sun.COM fct_free_dbuf(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf)
11227836SJohn.Forte@Sun.COM {
11237836SJohn.Forte@Sun.COM 	fct_dbuf_store_t *fds;
11247836SJohn.Forte@Sun.COM 
11257836SJohn.Forte@Sun.COM 	fds = (fct_dbuf_store_t *)ds->ds_port_private;
11267836SJohn.Forte@Sun.COM 
11277836SJohn.Forte@Sun.COM 	fds->fds_free_data_buf(fds, dbuf);
11287836SJohn.Forte@Sun.COM }
11297836SJohn.Forte@Sun.COM 
11307836SJohn.Forte@Sun.COM static uint32_t taskq_cntr = 0;
11317836SJohn.Forte@Sun.COM 
11327836SJohn.Forte@Sun.COM fct_status_t
fct_register_local_port(fct_local_port_t * port)11337836SJohn.Forte@Sun.COM fct_register_local_port(fct_local_port_t *port)
11347836SJohn.Forte@Sun.COM {
11357836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport;
11367836SJohn.Forte@Sun.COM 	stmf_local_port_t	*lport;
11377836SJohn.Forte@Sun.COM 	fct_cmd_slot_t		*slot;
11387836SJohn.Forte@Sun.COM 	int			i;
1139*12571SViswanathan.Kannappan@Sun.COM 	char			taskq_name[FCT_TASKQ_NAME_LEN];
11407836SJohn.Forte@Sun.COM 
11417836SJohn.Forte@Sun.COM 	iport = (fct_i_local_port_t *)port->port_fct_private;
114210936SAllan.Ou@Sun.COM 	if (port->port_fca_version != FCT_FCA_MODREV_1) {
114310936SAllan.Ou@Sun.COM 		cmn_err(CE_WARN,
114410936SAllan.Ou@Sun.COM 		    "fct: %s driver version mismatch",
114510936SAllan.Ou@Sun.COM 		    port->port_default_alias);
114610936SAllan.Ou@Sun.COM 		return (FCT_FAILURE);
114710936SAllan.Ou@Sun.COM 	}
11487836SJohn.Forte@Sun.COM 	if (port->port_default_alias) {
11497836SJohn.Forte@Sun.COM 		int l = strlen(port->port_default_alias);
11507836SJohn.Forte@Sun.COM 
11517836SJohn.Forte@Sun.COM 		if (l < 16) {
11527836SJohn.Forte@Sun.COM 			iport->iport_alias = iport->iport_alias_mem;
11537836SJohn.Forte@Sun.COM 		} else {
11547836SJohn.Forte@Sun.COM 			iport->iport_alias =
11559578SSam.Cramer@Sun.COM 			    (char *)kmem_zalloc(l+1, KM_SLEEP);
11567836SJohn.Forte@Sun.COM 		}
11577836SJohn.Forte@Sun.COM 		(void) strcpy(iport->iport_alias, port->port_default_alias);
11587836SJohn.Forte@Sun.COM 	} else {
11597836SJohn.Forte@Sun.COM 		iport->iport_alias = NULL;
11607836SJohn.Forte@Sun.COM 	}
11617836SJohn.Forte@Sun.COM 	stmf_wwn_to_devid_desc((scsi_devid_desc_t *)iport->iport_id,
11627836SJohn.Forte@Sun.COM 	    port->port_pwwn, PROTOCOL_FIBRE_CHANNEL);
1163*12571SViswanathan.Kannappan@Sun.COM 	(void) snprintf(taskq_name, sizeof (taskq_name), "stmf_fct_taskq_%d",
11649578SSam.Cramer@Sun.COM 	    atomic_add_32_nv(&taskq_cntr, 1));
11657836SJohn.Forte@Sun.COM 	if ((iport->iport_worker_taskq = ddi_taskq_create(NULL,
11667836SJohn.Forte@Sun.COM 	    taskq_name, 1, TASKQ_DEFAULTPRI, 0)) == NULL) {
11677836SJohn.Forte@Sun.COM 		return (FCT_FAILURE);
11687836SJohn.Forte@Sun.COM 	}
11697836SJohn.Forte@Sun.COM 	mutex_init(&iport->iport_worker_lock, NULL, MUTEX_DRIVER, NULL);
11707836SJohn.Forte@Sun.COM 	cv_init(&iport->iport_worker_cv, NULL, CV_DRIVER, NULL);
11717836SJohn.Forte@Sun.COM 	rw_init(&iport->iport_lock, NULL, RW_DRIVER, NULL);
117210088SAllan.Ou@Sun.COM 	sema_init(&iport->iport_rls_sema, 0, NULL, SEMA_DRIVER, NULL);
11737836SJohn.Forte@Sun.COM 
11747836SJohn.Forte@Sun.COM 	/* Remote port mgmt */
11757836SJohn.Forte@Sun.COM 	iport->iport_rp_slots = (fct_i_remote_port_t **)kmem_zalloc(
11767836SJohn.Forte@Sun.COM 	    port->port_max_logins * sizeof (fct_i_remote_port_t *), KM_SLEEP);
11777836SJohn.Forte@Sun.COM 	iport->iport_rp_tb = kmem_zalloc(rportid_table_size *
11789578SSam.Cramer@Sun.COM 	    sizeof (fct_i_remote_port_t *), KM_SLEEP);
11797836SJohn.Forte@Sun.COM 
11807836SJohn.Forte@Sun.COM 	/* fct_cmds for SCSI traffic */
11817836SJohn.Forte@Sun.COM 	iport->iport_total_alloced_ncmds = 0;
11827836SJohn.Forte@Sun.COM 	iport->iport_cached_ncmds = 0;
11837836SJohn.Forte@Sun.COM 	port->port_fca_fcp_cmd_size =
11849578SSam.Cramer@Sun.COM 	    (port->port_fca_fcp_cmd_size + 7) & ~7;
11857836SJohn.Forte@Sun.COM 	iport->iport_cached_cmdlist = NULL;
11867836SJohn.Forte@Sun.COM 	mutex_init(&iport->iport_cached_cmd_lock, NULL, MUTEX_DRIVER, NULL);
11877836SJohn.Forte@Sun.COM 
11887836SJohn.Forte@Sun.COM 	/* Initialize cmd slots */
11897836SJohn.Forte@Sun.COM 	iport->iport_cmd_slots = (fct_cmd_slot_t *)kmem_zalloc(
11909578SSam.Cramer@Sun.COM 	    port->port_max_xchges * sizeof (fct_cmd_slot_t), KM_SLEEP);
11917836SJohn.Forte@Sun.COM 	iport->iport_next_free_slot = 0;
11927836SJohn.Forte@Sun.COM 	for (i = 0; i < port->port_max_xchges; ) {
11937836SJohn.Forte@Sun.COM 		slot = &iport->iport_cmd_slots[i];
11947836SJohn.Forte@Sun.COM 		slot->slot_no = (uint16_t)i;
11957836SJohn.Forte@Sun.COM 		slot->slot_next = (uint16_t)(++i);
11967836SJohn.Forte@Sun.COM 	}
11977836SJohn.Forte@Sun.COM 	slot->slot_next = FCT_SLOT_EOL;
11987836SJohn.Forte@Sun.COM 	iport->iport_nslots_free = port->port_max_xchges;
11997836SJohn.Forte@Sun.COM 
12007836SJohn.Forte@Sun.COM 	iport->iport_task_green_limit =
12019578SSam.Cramer@Sun.COM 	    (port->port_max_xchges * FCT_TASK_GREEN_LIMIT) / 100;
12027836SJohn.Forte@Sun.COM 	iport->iport_task_yellow_limit =
12039578SSam.Cramer@Sun.COM 	    (port->port_max_xchges * FCT_TASK_YELLOW_LIMIT) / 100;
12047836SJohn.Forte@Sun.COM 	iport->iport_task_red_limit =
12059578SSam.Cramer@Sun.COM 	    (port->port_max_xchges * FCT_TASK_RED_LIMIT) / 100;
12067836SJohn.Forte@Sun.COM 
12077836SJohn.Forte@Sun.COM 	/* Start worker thread */
12087836SJohn.Forte@Sun.COM 	atomic_and_32(&iport->iport_flags, ~IPORT_TERMINATE_WORKER);
12097836SJohn.Forte@Sun.COM 	(void) ddi_taskq_dispatch(iport->iport_worker_taskq,
12109578SSam.Cramer@Sun.COM 	    fct_port_worker, port, DDI_SLEEP);
12117836SJohn.Forte@Sun.COM 	/* Wait for taskq to start */
12127836SJohn.Forte@Sun.COM 	while ((iport->iport_flags & IPORT_WORKER_RUNNING) == 0) {
12137836SJohn.Forte@Sun.COM 		delay(1);
12147836SJohn.Forte@Sun.COM 	}
12157836SJohn.Forte@Sun.COM 
12167836SJohn.Forte@Sun.COM 	lport = port->port_lport;
12177836SJohn.Forte@Sun.COM 	lport->lport_id = (scsi_devid_desc_t *)iport->iport_id;
12187836SJohn.Forte@Sun.COM 	lport->lport_alias = iport->iport_alias;
12197836SJohn.Forte@Sun.COM 	lport->lport_pp = port->port_pp;
12207836SJohn.Forte@Sun.COM 	port->port_fds->fds_ds->ds_alloc_data_buf = fct_alloc_dbuf;
12217836SJohn.Forte@Sun.COM 	port->port_fds->fds_ds->ds_free_data_buf = fct_free_dbuf;
122212314SJames.Moore@Sun.COM 	port->port_fds->fds_ds->ds_setup_dbuf = fct_setup_dbuf;
122312314SJames.Moore@Sun.COM 	port->port_fds->fds_ds->ds_teardown_dbuf = fct_teardown_dbuf;
12247836SJohn.Forte@Sun.COM 	lport->lport_ds = port->port_fds->fds_ds;
12257836SJohn.Forte@Sun.COM 	lport->lport_xfer_data = fct_xfer_scsi_data;
12267836SJohn.Forte@Sun.COM 	lport->lport_send_status = fct_send_scsi_status;
12277836SJohn.Forte@Sun.COM 	lport->lport_task_free = fct_scsi_task_free;
12287836SJohn.Forte@Sun.COM 	lport->lport_abort = fct_scsi_abort;
12297836SJohn.Forte@Sun.COM 	lport->lport_ctl = fct_ctl;
12307836SJohn.Forte@Sun.COM 	lport->lport_info = fct_info;
12317836SJohn.Forte@Sun.COM 	lport->lport_event_handler = fct_event_handler;
123211116SJohn.Forte@Sun.COM 	/* set up as alua participating port */
123311116SJohn.Forte@Sun.COM 	stmf_set_port_alua(lport);
12347836SJohn.Forte@Sun.COM 	if (stmf_register_local_port(port->port_lport) != FCT_SUCCESS) {
12357836SJohn.Forte@Sun.COM 		goto fct_regport_fail1;
12367836SJohn.Forte@Sun.COM 	}
12377836SJohn.Forte@Sun.COM 	(void) stmf_lport_add_event(lport, LPORT_EVENT_INITIAL_LUN_MAPPED);
12387836SJohn.Forte@Sun.COM 
12397836SJohn.Forte@Sun.COM 	mutex_enter(&fct_global_mutex);
12407836SJohn.Forte@Sun.COM 	iport->iport_next = fct_iport_list;
12417836SJohn.Forte@Sun.COM 	iport->iport_prev = NULL;
12427836SJohn.Forte@Sun.COM 	if (iport->iport_next)
12437836SJohn.Forte@Sun.COM 		iport->iport_next->iport_prev = iport;
12447836SJohn.Forte@Sun.COM 	fct_iport_list = iport;
12457836SJohn.Forte@Sun.COM 	mutex_exit(&fct_global_mutex);
12467836SJohn.Forte@Sun.COM 
124710088SAllan.Ou@Sun.COM 	fct_init_kstats(iport);
124810088SAllan.Ou@Sun.COM 
12497836SJohn.Forte@Sun.COM 	fct_log_local_port_event(port, ESC_SUNFC_PORT_ATTACH);
12507836SJohn.Forte@Sun.COM 
12517836SJohn.Forte@Sun.COM 	return (FCT_SUCCESS);
12527836SJohn.Forte@Sun.COM 
12537836SJohn.Forte@Sun.COM fct_regport_fail1:;
12547836SJohn.Forte@Sun.COM 	/* Stop the taskq 1st */
12557836SJohn.Forte@Sun.COM 	if (iport->iport_flags & IPORT_WORKER_RUNNING) {
12567836SJohn.Forte@Sun.COM 		atomic_or_32(&iport->iport_flags, IPORT_TERMINATE_WORKER);
12577836SJohn.Forte@Sun.COM 		cv_broadcast(&iport->iport_worker_cv);
12587836SJohn.Forte@Sun.COM 		while (iport->iport_flags & IPORT_WORKER_RUNNING) {
12597836SJohn.Forte@Sun.COM 			delay(1);
12607836SJohn.Forte@Sun.COM 		}
12617836SJohn.Forte@Sun.COM 	}
12627836SJohn.Forte@Sun.COM 	ddi_taskq_destroy(iport->iport_worker_taskq);
12637836SJohn.Forte@Sun.COM 	if (iport->iport_rp_tb) {
12647836SJohn.Forte@Sun.COM 		kmem_free(iport->iport_rp_tb, rportid_table_size *
12659578SSam.Cramer@Sun.COM 		    sizeof (fct_i_remote_port_t *));
12667836SJohn.Forte@Sun.COM 	}
12677836SJohn.Forte@Sun.COM 	return (FCT_FAILURE);
12687836SJohn.Forte@Sun.COM }
12697836SJohn.Forte@Sun.COM 
12707836SJohn.Forte@Sun.COM fct_status_t
fct_deregister_local_port(fct_local_port_t * port)12717836SJohn.Forte@Sun.COM fct_deregister_local_port(fct_local_port_t *port)
12727836SJohn.Forte@Sun.COM {
12737836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport;
12747836SJohn.Forte@Sun.COM 	fct_i_cmd_t		*icmd, *next_icmd;
12757836SJohn.Forte@Sun.COM 	int			ndx;
12767836SJohn.Forte@Sun.COM 
12777836SJohn.Forte@Sun.COM 	iport = (fct_i_local_port_t *)port->port_fct_private;
12787836SJohn.Forte@Sun.COM 
12797836SJohn.Forte@Sun.COM 	if ((iport->iport_state != FCT_STATE_OFFLINE) ||
12809578SSam.Cramer@Sun.COM 	    iport->iport_state_not_acked) {
12817836SJohn.Forte@Sun.COM 		return (FCT_FAILURE);
12827836SJohn.Forte@Sun.COM 	}
12837836SJohn.Forte@Sun.COM 
12847836SJohn.Forte@Sun.COM 	/* Stop the taskq 1st */
12857836SJohn.Forte@Sun.COM 	if (iport->iport_flags & IPORT_WORKER_RUNNING) {
12867836SJohn.Forte@Sun.COM 		atomic_or_32(&iport->iport_flags, IPORT_TERMINATE_WORKER);
12877836SJohn.Forte@Sun.COM 		cv_broadcast(&iport->iport_worker_cv);
12887836SJohn.Forte@Sun.COM 		for (ndx = 0; ndx < 100; ndx++) {
12897836SJohn.Forte@Sun.COM 			if ((iport->iport_flags & IPORT_WORKER_RUNNING)
12909578SSam.Cramer@Sun.COM 			    == 0) {
12917836SJohn.Forte@Sun.COM 				break;
12927836SJohn.Forte@Sun.COM 			}
12937836SJohn.Forte@Sun.COM 			delay(drv_usectohz(10000));
12947836SJohn.Forte@Sun.COM 		}
12957836SJohn.Forte@Sun.COM 		if (ndx == 100) {
12967836SJohn.Forte@Sun.COM 			atomic_and_32(&iport->iport_flags,
12979578SSam.Cramer@Sun.COM 			    ~IPORT_TERMINATE_WORKER);
12987836SJohn.Forte@Sun.COM 			return (FCT_WORKER_STUCK);
12997836SJohn.Forte@Sun.COM 		}
13007836SJohn.Forte@Sun.COM 	}
13017836SJohn.Forte@Sun.COM 
13027836SJohn.Forte@Sun.COM 	if (stmf_deregister_local_port(port->port_lport) != FCT_SUCCESS) {
13037836SJohn.Forte@Sun.COM 		goto fct_deregport_fail1;
13047836SJohn.Forte@Sun.COM 	}
13057836SJohn.Forte@Sun.COM 
13067836SJohn.Forte@Sun.COM 	mutex_enter(&fct_global_mutex);
13077836SJohn.Forte@Sun.COM 	if (iport->iport_next)
13087836SJohn.Forte@Sun.COM 		iport->iport_next->iport_prev = iport->iport_prev;
13097836SJohn.Forte@Sun.COM 	if (iport->iport_prev)
13107836SJohn.Forte@Sun.COM 		iport->iport_prev->iport_next = iport->iport_next;
13117836SJohn.Forte@Sun.COM 	else
13127836SJohn.Forte@Sun.COM 		fct_iport_list = iport->iport_next;
13137836SJohn.Forte@Sun.COM 	mutex_exit(&fct_global_mutex);
13147836SJohn.Forte@Sun.COM 	/*
13157836SJohn.Forte@Sun.COM 	 * At this time, there should be no outstanding and pending
13167836SJohn.Forte@Sun.COM 	 * I/Os, so we can just release resources.
13177836SJohn.Forte@Sun.COM 	 */
13187836SJohn.Forte@Sun.COM 	ASSERT(iport->iport_total_alloced_ncmds == iport->iport_cached_ncmds);
13197836SJohn.Forte@Sun.COM 	for (icmd = iport->iport_cached_cmdlist; icmd; icmd = next_icmd) {
13207836SJohn.Forte@Sun.COM 		next_icmd = icmd->icmd_next;
13217836SJohn.Forte@Sun.COM 		fct_free(icmd->icmd_cmd);
13227836SJohn.Forte@Sun.COM 	}
13237836SJohn.Forte@Sun.COM 	mutex_destroy(&iport->iport_cached_cmd_lock);
13247836SJohn.Forte@Sun.COM 	kmem_free(iport->iport_cmd_slots, port->port_max_xchges *
13259578SSam.Cramer@Sun.COM 	    sizeof (fct_cmd_slot_t));
13267836SJohn.Forte@Sun.COM 	kmem_free(iport->iport_rp_slots, port->port_max_logins *
13279578SSam.Cramer@Sun.COM 	    sizeof (fct_i_remote_port_t *));
13287836SJohn.Forte@Sun.COM 	rw_destroy(&iport->iport_lock);
13297836SJohn.Forte@Sun.COM 	cv_destroy(&iport->iport_worker_cv);
133010088SAllan.Ou@Sun.COM 	sema_destroy(&iport->iport_rls_sema);
13317836SJohn.Forte@Sun.COM 	mutex_destroy(&iport->iport_worker_lock);
13327836SJohn.Forte@Sun.COM 	ddi_taskq_destroy(iport->iport_worker_taskq);
13337836SJohn.Forte@Sun.COM 	if (iport->iport_rp_tb) {
13347836SJohn.Forte@Sun.COM 		kmem_free(iport->iport_rp_tb, rportid_table_size *
13359578SSam.Cramer@Sun.COM 		    sizeof (fct_i_remote_port_t *));
13367836SJohn.Forte@Sun.COM 	}
13377836SJohn.Forte@Sun.COM 
133810088SAllan.Ou@Sun.COM 	if (iport->iport_kstat_portstat) {
133910088SAllan.Ou@Sun.COM 		kstat_delete(iport->iport_kstat_portstat);
134010088SAllan.Ou@Sun.COM 	}
134110088SAllan.Ou@Sun.COM 
13427836SJohn.Forte@Sun.COM 	fct_log_local_port_event(port, ESC_SUNFC_PORT_DETACH);
13437836SJohn.Forte@Sun.COM 	return (FCT_SUCCESS);
13447836SJohn.Forte@Sun.COM 
13457836SJohn.Forte@Sun.COM fct_deregport_fail1:;
13467836SJohn.Forte@Sun.COM 	/* Restart the worker */
13477836SJohn.Forte@Sun.COM 	atomic_and_32(&iport->iport_flags, ~IPORT_TERMINATE_WORKER);
13487836SJohn.Forte@Sun.COM 	(void) ddi_taskq_dispatch(iport->iport_worker_taskq,
13499578SSam.Cramer@Sun.COM 	    fct_port_worker, port, DDI_SLEEP);
13507836SJohn.Forte@Sun.COM 	/* Wait for taskq to start */
13517836SJohn.Forte@Sun.COM 	while ((iport->iport_flags & IPORT_WORKER_RUNNING) == 0) {
13527836SJohn.Forte@Sun.COM 		delay(1);
13537836SJohn.Forte@Sun.COM 	}
13547836SJohn.Forte@Sun.COM 	return (FCT_FAILURE);
13557836SJohn.Forte@Sun.COM }
13567836SJohn.Forte@Sun.COM 
13577836SJohn.Forte@Sun.COM /* ARGSUSED */
13587836SJohn.Forte@Sun.COM void
fct_handle_event(fct_local_port_t * port,int event_id,uint32_t event_flags,caddr_t arg)13597836SJohn.Forte@Sun.COM fct_handle_event(fct_local_port_t *port, int event_id, uint32_t event_flags,
13607836SJohn.Forte@Sun.COM 		caddr_t arg)
13617836SJohn.Forte@Sun.COM {
1362*12571SViswanathan.Kannappan@Sun.COM 	char			info[FCT_INFO_LEN];
13637836SJohn.Forte@Sun.COM 	fct_i_event_t		*e;
13647836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
13657836SJohn.Forte@Sun.COM 	    port->port_fct_private;
13667836SJohn.Forte@Sun.COM 
13677836SJohn.Forte@Sun.COM 	e = kmem_zalloc(sizeof (fct_i_event_t), KM_NOSLEEP);
13687836SJohn.Forte@Sun.COM 
13697836SJohn.Forte@Sun.COM 	if (e == NULL) {
13707836SJohn.Forte@Sun.COM 		/*
13717836SJohn.Forte@Sun.COM 		 * XXX Throw HBA fatal error event
13727836SJohn.Forte@Sun.COM 		 */
1373*12571SViswanathan.Kannappan@Sun.COM 		(void) snprintf(info, sizeof (info),
13747836SJohn.Forte@Sun.COM 		    "fct_handle_event: iport-%p, allocation "
13757836SJohn.Forte@Sun.COM 		    "of fct_i_event failed", (void *)iport);
13767836SJohn.Forte@Sun.COM 		(void) fct_port_shutdown(iport->iport_port,
13777836SJohn.Forte@Sun.COM 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
13787836SJohn.Forte@Sun.COM 		return;
13797836SJohn.Forte@Sun.COM 	}
13807836SJohn.Forte@Sun.COM 	/* Just queue the event */
13817836SJohn.Forte@Sun.COM 	e->event_type = event_id;
13827836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
13837836SJohn.Forte@Sun.COM 	if (iport->iport_event_head == NULL) {
13847836SJohn.Forte@Sun.COM 		iport->iport_event_head = iport->iport_event_tail = e;
13857836SJohn.Forte@Sun.COM 	} else {
13867836SJohn.Forte@Sun.COM 		iport->iport_event_tail->event_next = e;
13877836SJohn.Forte@Sun.COM 		iport->iport_event_tail = e;
13887836SJohn.Forte@Sun.COM 	}
13897836SJohn.Forte@Sun.COM 	if (IS_WORKER_SLEEPING(iport))
13907836SJohn.Forte@Sun.COM 		cv_signal(&iport->iport_worker_cv);
13917836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
13927836SJohn.Forte@Sun.COM }
13937836SJohn.Forte@Sun.COM 
13947836SJohn.Forte@Sun.COM /*
13957836SJohn.Forte@Sun.COM  * Called with iport_lock held as reader.
13967836SJohn.Forte@Sun.COM  */
13977836SJohn.Forte@Sun.COM fct_i_remote_port_t *
fct_portid_to_portptr(fct_i_local_port_t * iport,uint32_t portid)13987836SJohn.Forte@Sun.COM fct_portid_to_portptr(fct_i_local_port_t *iport, uint32_t portid)
13997836SJohn.Forte@Sun.COM {
14007836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp;
14017836SJohn.Forte@Sun.COM 
14027836SJohn.Forte@Sun.COM 	irp = iport->iport_rp_tb[FCT_PORTID_HASH_FUNC(portid)];
14037836SJohn.Forte@Sun.COM 	for (; irp != NULL; irp = irp->irp_next) {
14047836SJohn.Forte@Sun.COM 		if (irp->irp_portid == portid)
14057836SJohn.Forte@Sun.COM 			return (irp);
14067836SJohn.Forte@Sun.COM 	}
14077836SJohn.Forte@Sun.COM 
14087836SJohn.Forte@Sun.COM 	return (NULL);
14097836SJohn.Forte@Sun.COM 
14107836SJohn.Forte@Sun.COM }
14117836SJohn.Forte@Sun.COM 
14127836SJohn.Forte@Sun.COM /*
14137836SJohn.Forte@Sun.COM  * Called with irp_lock held as writer.
14147836SJohn.Forte@Sun.COM  */
14157836SJohn.Forte@Sun.COM void
fct_queue_rp(fct_i_local_port_t * iport,fct_i_remote_port_t * irp)14167836SJohn.Forte@Sun.COM fct_queue_rp(fct_i_local_port_t *iport, fct_i_remote_port_t *irp)
14177836SJohn.Forte@Sun.COM {
14187836SJohn.Forte@Sun.COM 	int hash_key =
14197836SJohn.Forte@Sun.COM 	    FCT_PORTID_HASH_FUNC(irp->irp_portid);
14207836SJohn.Forte@Sun.COM 
14217836SJohn.Forte@Sun.COM 	irp->irp_next = iport->iport_rp_tb[hash_key];
14227836SJohn.Forte@Sun.COM 	iport->iport_rp_tb[hash_key] = irp;
14237836SJohn.Forte@Sun.COM 	iport->iport_nrps++;
14247836SJohn.Forte@Sun.COM }
14257836SJohn.Forte@Sun.COM 
14267836SJohn.Forte@Sun.COM /*
14277836SJohn.Forte@Sun.COM  * Called with irp_lock and iport_lock held as writer.
14287836SJohn.Forte@Sun.COM  */
14297836SJohn.Forte@Sun.COM void
fct_deque_rp(fct_i_local_port_t * iport,fct_i_remote_port_t * irp)14307836SJohn.Forte@Sun.COM fct_deque_rp(fct_i_local_port_t *iport, fct_i_remote_port_t *irp)
14317836SJohn.Forte@Sun.COM {
14327836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp_next = NULL;
14337836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp_last = NULL;
14347836SJohn.Forte@Sun.COM 	int hash_key			  =
14357836SJohn.Forte@Sun.COM 	    FCT_PORTID_HASH_FUNC(irp->irp_portid);
14367836SJohn.Forte@Sun.COM 
14377836SJohn.Forte@Sun.COM 	irp_next = iport->iport_rp_tb[hash_key];
14387836SJohn.Forte@Sun.COM 	irp_last = NULL;
14397836SJohn.Forte@Sun.COM 	while (irp_next != NULL) {
14407836SJohn.Forte@Sun.COM 		if (irp == irp_next) {
144111535SRenia.Miao@Sun.COM 			if (irp->irp_flags & IRP_PLOGI_DONE) {
144211535SRenia.Miao@Sun.COM 				atomic_add_32(&iport->iport_nrps_login, -1);
144311535SRenia.Miao@Sun.COM 			}
144411535SRenia.Miao@Sun.COM 			atomic_and_32(&irp->irp_flags,
144511535SRenia.Miao@Sun.COM 			    ~(IRP_PLOGI_DONE | IRP_PRLI_DONE));
14467836SJohn.Forte@Sun.COM 			break;
14477836SJohn.Forte@Sun.COM 		}
14487836SJohn.Forte@Sun.COM 		irp_last = irp_next;
14497836SJohn.Forte@Sun.COM 		irp_next = irp_next->irp_next;
14507836SJohn.Forte@Sun.COM 	}
14517836SJohn.Forte@Sun.COM 
14527836SJohn.Forte@Sun.COM 	if (irp_next) {
14537836SJohn.Forte@Sun.COM 		if (irp_last == NULL) {
14547836SJohn.Forte@Sun.COM 			iport->iport_rp_tb[hash_key] =
14559578SSam.Cramer@Sun.COM 			    irp->irp_next;
14567836SJohn.Forte@Sun.COM 		} else {
14577836SJohn.Forte@Sun.COM 			irp_last->irp_next = irp->irp_next;
14587836SJohn.Forte@Sun.COM 		}
14597836SJohn.Forte@Sun.COM 		irp->irp_next = NULL;
14607836SJohn.Forte@Sun.COM 		iport->iport_nrps--;
14617836SJohn.Forte@Sun.COM 	}
14627836SJohn.Forte@Sun.COM }
14637836SJohn.Forte@Sun.COM 
14647836SJohn.Forte@Sun.COM int
fct_is_irp_logging_out(fct_i_remote_port_t * irp,int force_implicit)14657836SJohn.Forte@Sun.COM fct_is_irp_logging_out(fct_i_remote_port_t *irp, int force_implicit)
14667836SJohn.Forte@Sun.COM {
14677836SJohn.Forte@Sun.COM 	int logging_out = 0;
14687836SJohn.Forte@Sun.COM 
14697836SJohn.Forte@Sun.COM 	rw_enter(&irp->irp_lock, RW_WRITER);
14707836SJohn.Forte@Sun.COM 	if ((irp->irp_flags & IRP_IN_DISCOVERY_QUEUE) == 0) {
14717836SJohn.Forte@Sun.COM 		logging_out = 0;
14727836SJohn.Forte@Sun.COM 		goto ilo_done;
14737836SJohn.Forte@Sun.COM 	}
14747836SJohn.Forte@Sun.COM 	if ((irp->irp_els_list == NULL) && (irp->irp_deregister_timer)) {
14757836SJohn.Forte@Sun.COM 		if (force_implicit && irp->irp_nonfcp_xchg_count) {
14767836SJohn.Forte@Sun.COM 			logging_out = 0;
14777836SJohn.Forte@Sun.COM 		} else {
14787836SJohn.Forte@Sun.COM 			logging_out = 1;
14797836SJohn.Forte@Sun.COM 		}
14807836SJohn.Forte@Sun.COM 		goto ilo_done;
14817836SJohn.Forte@Sun.COM 	}
14827836SJohn.Forte@Sun.COM 	if (irp->irp_els_list) {
14837836SJohn.Forte@Sun.COM 		fct_i_cmd_t *icmd;
14847836SJohn.Forte@Sun.COM 		/* Last session affecting ELS should be a LOGO */
14857836SJohn.Forte@Sun.COM 		for (icmd = irp->irp_els_list; icmd; icmd = icmd->icmd_next) {
14867836SJohn.Forte@Sun.COM 			uint8_t op = (ICMD_TO_ELS(icmd))->els_req_payload[0];
14877836SJohn.Forte@Sun.COM 			if (op == ELS_OP_LOGO) {
14887836SJohn.Forte@Sun.COM 				if (force_implicit) {
14897836SJohn.Forte@Sun.COM 					if (icmd->icmd_flags & ICMD_IMPLICIT)
14907836SJohn.Forte@Sun.COM 						logging_out = 1;
14917836SJohn.Forte@Sun.COM 					else
14927836SJohn.Forte@Sun.COM 						logging_out = 0;
14937836SJohn.Forte@Sun.COM 				} else {
14947836SJohn.Forte@Sun.COM 					logging_out = 1;
14957836SJohn.Forte@Sun.COM 				}
14967836SJohn.Forte@Sun.COM 			} else if ((op == ELS_OP_PLOGI) ||
14977836SJohn.Forte@Sun.COM 			    (op == ELS_OP_PRLI) ||
14987836SJohn.Forte@Sun.COM 			    (op == ELS_OP_PRLO) || (op == ELS_OP_TPRLO)) {
14997836SJohn.Forte@Sun.COM 				logging_out = 0;
15007836SJohn.Forte@Sun.COM 			}
15017836SJohn.Forte@Sun.COM 		}
15027836SJohn.Forte@Sun.COM 	}
15037836SJohn.Forte@Sun.COM ilo_done:;
15047836SJohn.Forte@Sun.COM 	rw_exit(&irp->irp_lock);
15057836SJohn.Forte@Sun.COM 
15067836SJohn.Forte@Sun.COM 	return (logging_out);
15077836SJohn.Forte@Sun.COM }
15087836SJohn.Forte@Sun.COM 
15097836SJohn.Forte@Sun.COM /*
15107836SJohn.Forte@Sun.COM  * The force_implicit flag enforces the implicit semantics which may be
15117836SJohn.Forte@Sun.COM  * needed if a received logout got stuck e.g. a response to a received
15127836SJohn.Forte@Sun.COM  * LOGO never came back from the FCA.
15137836SJohn.Forte@Sun.COM  */
15147836SJohn.Forte@Sun.COM int
fct_implicitly_logo_all(fct_i_local_port_t * iport,int force_implicit)15157836SJohn.Forte@Sun.COM fct_implicitly_logo_all(fct_i_local_port_t *iport, int force_implicit)
15167836SJohn.Forte@Sun.COM {
15177836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp = NULL;
15187836SJohn.Forte@Sun.COM 	fct_cmd_t		*cmd = NULL;
15197836SJohn.Forte@Sun.COM 	int			 i   = 0;
15207836SJohn.Forte@Sun.COM 	int			nports = 0;
15217836SJohn.Forte@Sun.COM 
15227836SJohn.Forte@Sun.COM 	if (!iport->iport_nrps) {
15237836SJohn.Forte@Sun.COM 		return (nports);
15247836SJohn.Forte@Sun.COM 	}
15257836SJohn.Forte@Sun.COM 
15267836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_WRITER);
15277836SJohn.Forte@Sun.COM 	for (i = 0; i < rportid_table_size; i++) {
15287836SJohn.Forte@Sun.COM 		irp = iport->iport_rp_tb[i];
15297836SJohn.Forte@Sun.COM 		while (irp) {
15307836SJohn.Forte@Sun.COM 			if ((!(irp->irp_flags & IRP_PLOGI_DONE)) &&
15317836SJohn.Forte@Sun.COM 			    (fct_is_irp_logging_out(irp, force_implicit))) {
15327836SJohn.Forte@Sun.COM 				irp = irp->irp_next;
15337836SJohn.Forte@Sun.COM 				continue;
15347836SJohn.Forte@Sun.COM 			}
15357836SJohn.Forte@Sun.COM 
15367836SJohn.Forte@Sun.COM 			cmd = fct_create_solels(iport->iport_port, irp->irp_rp,
15377836SJohn.Forte@Sun.COM 			    1, ELS_OP_LOGO, 0, fct_logo_cb);
15387836SJohn.Forte@Sun.COM 			if (cmd == NULL) {
15397836SJohn.Forte@Sun.COM 				stmf_trace(iport->iport_alias,
15407836SJohn.Forte@Sun.COM 				    "fct_implictly_logo_all: cmd null");
15417836SJohn.Forte@Sun.COM 				rw_exit(&iport->iport_lock);
15427836SJohn.Forte@Sun.COM 
15437836SJohn.Forte@Sun.COM 				return (nports);
15447836SJohn.Forte@Sun.COM 			}
15457836SJohn.Forte@Sun.COM 
15467836SJohn.Forte@Sun.COM 			fct_post_implicit_logo(cmd);
15477836SJohn.Forte@Sun.COM 			nports++;
15487836SJohn.Forte@Sun.COM 			irp = irp->irp_next;
15497836SJohn.Forte@Sun.COM 		}
15507836SJohn.Forte@Sun.COM 	}
15517836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
15527836SJohn.Forte@Sun.COM 
15537836SJohn.Forte@Sun.COM 	return (nports);
15547836SJohn.Forte@Sun.COM }
15557836SJohn.Forte@Sun.COM 
15567836SJohn.Forte@Sun.COM void
fct_rehash(fct_i_local_port_t * iport)15577836SJohn.Forte@Sun.COM fct_rehash(fct_i_local_port_t *iport)
15587836SJohn.Forte@Sun.COM {
15597836SJohn.Forte@Sun.COM 	fct_i_remote_port_t **iport_rp_tb_tmp;
15607836SJohn.Forte@Sun.COM 	fct_i_remote_port_t **iport_rp_tb_new;
15617836SJohn.Forte@Sun.COM 	fct_i_remote_port_t *irp;
15627836SJohn.Forte@Sun.COM 	fct_i_remote_port_t *irp_next;
15637836SJohn.Forte@Sun.COM 	int i;
15647836SJohn.Forte@Sun.COM 
15657836SJohn.Forte@Sun.COM 	iport_rp_tb_new = kmem_zalloc(rportid_table_size *
15669578SSam.Cramer@Sun.COM 	    sizeof (fct_i_remote_port_t *), KM_SLEEP);
15677836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_WRITER);
15687836SJohn.Forte@Sun.COM 	/* reconstruct the hash table */
15697836SJohn.Forte@Sun.COM 	iport_rp_tb_tmp = iport->iport_rp_tb;
15707836SJohn.Forte@Sun.COM 	iport->iport_rp_tb = iport_rp_tb_new;
15717836SJohn.Forte@Sun.COM 	iport->iport_nrps = 0;
15727836SJohn.Forte@Sun.COM 	for (i = 0; i < rportid_table_size; i++) {
15737836SJohn.Forte@Sun.COM 		irp = iport_rp_tb_tmp[i];
15747836SJohn.Forte@Sun.COM 		while (irp) {
15757836SJohn.Forte@Sun.COM 			irp_next = irp->irp_next;
15767836SJohn.Forte@Sun.COM 			fct_queue_rp(iport, irp);
15777836SJohn.Forte@Sun.COM 			irp = irp_next;
15787836SJohn.Forte@Sun.COM 		}
15797836SJohn.Forte@Sun.COM 	}
15807836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
15817836SJohn.Forte@Sun.COM 	kmem_free(iport_rp_tb_tmp, rportid_table_size *
15829578SSam.Cramer@Sun.COM 	    sizeof (fct_i_remote_port_t *));
15837836SJohn.Forte@Sun.COM 
15847836SJohn.Forte@Sun.COM }
15857836SJohn.Forte@Sun.COM 
15867836SJohn.Forte@Sun.COM uint8_t
fct_local_port_cleanup_done(fct_i_local_port_t * iport)15877836SJohn.Forte@Sun.COM fct_local_port_cleanup_done(fct_i_local_port_t *iport)
15887836SJohn.Forte@Sun.COM {
15897836SJohn.Forte@Sun.COM 	fct_i_remote_port_t *irp;
15907836SJohn.Forte@Sun.COM 	int i;
15917836SJohn.Forte@Sun.COM 
15927836SJohn.Forte@Sun.COM 	if (iport->iport_nrps_login)
15937836SJohn.Forte@Sun.COM 		return (0);
15947836SJohn.Forte@Sun.COM 	/* loop all rps to check if the cmd have already been drained */
15957836SJohn.Forte@Sun.COM 	for (i = 0; i < rportid_table_size; i++) {
15967836SJohn.Forte@Sun.COM 		irp = iport->iport_rp_tb[i];
15977836SJohn.Forte@Sun.COM 		while (irp) {
15987836SJohn.Forte@Sun.COM 			if (irp->irp_fcp_xchg_count ||
15997836SJohn.Forte@Sun.COM 			    irp->irp_nonfcp_xchg_count)
16007836SJohn.Forte@Sun.COM 				return (0);
16017836SJohn.Forte@Sun.COM 			irp = irp->irp_next;
16027836SJohn.Forte@Sun.COM 		}
16037836SJohn.Forte@Sun.COM 	}
16047836SJohn.Forte@Sun.COM 	return (1);
16057836SJohn.Forte@Sun.COM }
16067836SJohn.Forte@Sun.COM 
16077836SJohn.Forte@Sun.COM fct_cmd_t *
fct_scsi_task_alloc(fct_local_port_t * port,uint16_t rp_handle,uint32_t rportid,uint8_t * lun,uint16_t cdb_length,uint16_t task_ext)16087836SJohn.Forte@Sun.COM fct_scsi_task_alloc(fct_local_port_t *port, uint16_t rp_handle,
16097836SJohn.Forte@Sun.COM 		uint32_t rportid, uint8_t *lun, uint16_t cdb_length,
16107836SJohn.Forte@Sun.COM 		uint16_t task_ext)
16117836SJohn.Forte@Sun.COM {
16127836SJohn.Forte@Sun.COM 	fct_cmd_t *cmd;
16137836SJohn.Forte@Sun.COM 	fct_i_cmd_t *icmd;
16147836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport =
16159578SSam.Cramer@Sun.COM 	    (fct_i_local_port_t *)port->port_fct_private;
16167836SJohn.Forte@Sun.COM 	fct_i_remote_port_t *irp;
16177836SJohn.Forte@Sun.COM 	scsi_task_t *task;
16187836SJohn.Forte@Sun.COM 	fct_remote_port_t *rp;
16197836SJohn.Forte@Sun.COM 	uint16_t cmd_slot;
16207836SJohn.Forte@Sun.COM 
16217836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_READER);
16227836SJohn.Forte@Sun.COM 	if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
16237836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
16247836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "cmd alloc called while the port"
16259578SSam.Cramer@Sun.COM 		    " was offline");
16267836SJohn.Forte@Sun.COM 		return (NULL);
16277836SJohn.Forte@Sun.COM 	}
16287836SJohn.Forte@Sun.COM 
16297836SJohn.Forte@Sun.COM 	if (rp_handle == FCT_HANDLE_NONE) {
16307836SJohn.Forte@Sun.COM 		irp = fct_portid_to_portptr(iport, rportid);
16317836SJohn.Forte@Sun.COM 		if (irp == NULL) {
16327836SJohn.Forte@Sun.COM 			rw_exit(&iport->iport_lock);
16337836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "cmd received from "
16347836SJohn.Forte@Sun.COM 			    "non existent port %x", rportid);
16357836SJohn.Forte@Sun.COM 			return (NULL);
16367836SJohn.Forte@Sun.COM 		}
16377836SJohn.Forte@Sun.COM 	} else {
16387836SJohn.Forte@Sun.COM 		if ((rp_handle >= port->port_max_logins) ||
16397836SJohn.Forte@Sun.COM 		    ((irp = iport->iport_rp_slots[rp_handle]) == NULL)) {
16407836SJohn.Forte@Sun.COM 			rw_exit(&iport->iport_lock);
16417836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "cmd received from "
16427836SJohn.Forte@Sun.COM 			    "invalid port handle %x", rp_handle);
16437836SJohn.Forte@Sun.COM 			return (NULL);
16447836SJohn.Forte@Sun.COM 		}
16457836SJohn.Forte@Sun.COM 	}
16467836SJohn.Forte@Sun.COM 	rp = irp->irp_rp;
16477836SJohn.Forte@Sun.COM 
16487836SJohn.Forte@Sun.COM 	rw_enter(&irp->irp_lock, RW_READER);
16497836SJohn.Forte@Sun.COM 	if ((irp->irp_flags & IRP_PRLI_DONE) == 0) {
16507836SJohn.Forte@Sun.COM 		rw_exit(&irp->irp_lock);
16517836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
16527836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "cmd alloc called while fcp "
16537836SJohn.Forte@Sun.COM 		    "login was not done. portid=%x, rp=%p", rp->rp_id, rp);
16547836SJohn.Forte@Sun.COM 		return (NULL);
16557836SJohn.Forte@Sun.COM 	}
16567836SJohn.Forte@Sun.COM 
16577836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_cached_cmd_lock);
16587836SJohn.Forte@Sun.COM 	if ((icmd = iport->iport_cached_cmdlist) != NULL) {
16597836SJohn.Forte@Sun.COM 		iport->iport_cached_cmdlist = icmd->icmd_next;
16607836SJohn.Forte@Sun.COM 		iport->iport_cached_ncmds--;
16617836SJohn.Forte@Sun.COM 		cmd = icmd->icmd_cmd;
16627836SJohn.Forte@Sun.COM 	} else {
16637836SJohn.Forte@Sun.COM 		icmd = NULL;
16647836SJohn.Forte@Sun.COM 	}
16657836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_cached_cmd_lock);
16667836SJohn.Forte@Sun.COM 	if (icmd == NULL) {
16677836SJohn.Forte@Sun.COM 		cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_FCP_XCHG,
16689578SSam.Cramer@Sun.COM 		    port->port_fca_fcp_cmd_size, 0);
16697836SJohn.Forte@Sun.COM 		if (cmd == NULL) {
16707836SJohn.Forte@Sun.COM 			rw_exit(&irp->irp_lock);
16717836SJohn.Forte@Sun.COM 			rw_exit(&iport->iport_lock);
16727836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "Ran out of "
16739578SSam.Cramer@Sun.COM 			    "memory, port=%p", port);
16747836SJohn.Forte@Sun.COM 			return (NULL);
16757836SJohn.Forte@Sun.COM 		}
16767836SJohn.Forte@Sun.COM 
16777836SJohn.Forte@Sun.COM 		icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
16787836SJohn.Forte@Sun.COM 		icmd->icmd_next = NULL;
16797836SJohn.Forte@Sun.COM 		cmd->cmd_port = port;
16807836SJohn.Forte@Sun.COM 		atomic_add_32(&iport->iport_total_alloced_ncmds, 1);
16817836SJohn.Forte@Sun.COM 	}
16827836SJohn.Forte@Sun.COM 
16837836SJohn.Forte@Sun.COM 	/*
16847836SJohn.Forte@Sun.COM 	 * The accuracy of iport_max_active_ncmds is not important
16857836SJohn.Forte@Sun.COM 	 */
16867836SJohn.Forte@Sun.COM 	if ((iport->iport_total_alloced_ncmds - iport->iport_cached_ncmds) >
16877836SJohn.Forte@Sun.COM 	    iport->iport_max_active_ncmds) {
16887836SJohn.Forte@Sun.COM 		iport->iport_max_active_ncmds =
16897836SJohn.Forte@Sun.COM 		    iport->iport_total_alloced_ncmds -
16907836SJohn.Forte@Sun.COM 		    iport->iport_cached_ncmds;
16917836SJohn.Forte@Sun.COM 	}
16927836SJohn.Forte@Sun.COM 
16937836SJohn.Forte@Sun.COM 	/* Lets get a slot */
16947836SJohn.Forte@Sun.COM 	cmd_slot = fct_alloc_cmd_slot(iport, cmd);
16957836SJohn.Forte@Sun.COM 	if (cmd_slot == FCT_SLOT_EOL) {
16967836SJohn.Forte@Sun.COM 		rw_exit(&irp->irp_lock);
16977836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
16987836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "Ran out of xchg resources");
16997836SJohn.Forte@Sun.COM 		cmd->cmd_handle = 0;
17007836SJohn.Forte@Sun.COM 		fct_cmd_free(cmd);
17017836SJohn.Forte@Sun.COM 		return (NULL);
17027836SJohn.Forte@Sun.COM 	}
17037836SJohn.Forte@Sun.COM 	atomic_add_16(&irp->irp_fcp_xchg_count, 1);
17047836SJohn.Forte@Sun.COM 	cmd->cmd_rp = rp;
17057836SJohn.Forte@Sun.COM 	icmd->icmd_flags |= ICMD_IN_TRANSITION | ICMD_KNOWN_TO_FCA;
17067836SJohn.Forte@Sun.COM 	rw_exit(&irp->irp_lock);
17077836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
17087836SJohn.Forte@Sun.COM 
17097836SJohn.Forte@Sun.COM 	icmd->icmd_start_time = ddi_get_lbolt();
17107836SJohn.Forte@Sun.COM 
17117836SJohn.Forte@Sun.COM 	cmd->cmd_specific = stmf_task_alloc(port->port_lport, irp->irp_session,
17129578SSam.Cramer@Sun.COM 	    lun, cdb_length, task_ext);
17137836SJohn.Forte@Sun.COM 	if ((task = (scsi_task_t *)cmd->cmd_specific) != NULL) {
17147836SJohn.Forte@Sun.COM 		task->task_port_private = cmd;
17157836SJohn.Forte@Sun.COM 		return (cmd);
17167836SJohn.Forte@Sun.COM 	}
17177836SJohn.Forte@Sun.COM 
17187836SJohn.Forte@Sun.COM 	fct_cmd_free(cmd);
17197836SJohn.Forte@Sun.COM 
17207836SJohn.Forte@Sun.COM 	return (NULL);
17217836SJohn.Forte@Sun.COM }
17227836SJohn.Forte@Sun.COM 
17237836SJohn.Forte@Sun.COM void
fct_scsi_task_free(scsi_task_t * task)17247836SJohn.Forte@Sun.COM fct_scsi_task_free(scsi_task_t *task)
17257836SJohn.Forte@Sun.COM {
17267836SJohn.Forte@Sun.COM 	fct_cmd_t *cmd = (fct_cmd_t *)task->task_port_private;
17277836SJohn.Forte@Sun.COM 
17287836SJohn.Forte@Sun.COM 	cmd->cmd_comp_status = task->task_completion_status;
17297836SJohn.Forte@Sun.COM 	fct_cmd_free(cmd);
17307836SJohn.Forte@Sun.COM }
17317836SJohn.Forte@Sun.COM 
17327836SJohn.Forte@Sun.COM void
fct_post_rcvd_cmd(fct_cmd_t * cmd,stmf_data_buf_t * dbuf)17337836SJohn.Forte@Sun.COM fct_post_rcvd_cmd(fct_cmd_t *cmd, stmf_data_buf_t *dbuf)
17347836SJohn.Forte@Sun.COM {
173512314SJames.Moore@Sun.COM 	fct_dbuf_store_t *fds;
173612314SJames.Moore@Sun.COM 
17377836SJohn.Forte@Sun.COM 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
17387836SJohn.Forte@Sun.COM 		fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
17397836SJohn.Forte@Sun.COM 		fct_i_local_port_t *iport =
17409578SSam.Cramer@Sun.COM 		    (fct_i_local_port_t *)cmd->cmd_port->port_fct_private;
17417836SJohn.Forte@Sun.COM 		fct_i_remote_port_t *irp =
17429578SSam.Cramer@Sun.COM 		    (fct_i_remote_port_t *)cmd->cmd_rp->rp_fct_private;
17437836SJohn.Forte@Sun.COM 		scsi_task_t *task = (scsi_task_t *)cmd->cmd_specific;
17447836SJohn.Forte@Sun.COM 
17457836SJohn.Forte@Sun.COM 		uint16_t irp_task = irp->irp_fcp_xchg_count;
17467836SJohn.Forte@Sun.COM 		uint32_t load = iport->iport_total_alloced_ncmds -
17479578SSam.Cramer@Sun.COM 		    iport->iport_cached_ncmds;
17489578SSam.Cramer@Sun.COM 
17499578SSam.Cramer@Sun.COM 		DTRACE_FC_4(scsi__command,
17509578SSam.Cramer@Sun.COM 		    fct_cmd_t, cmd,
17519578SSam.Cramer@Sun.COM 		    fct_i_local_port_t, iport,
17529578SSam.Cramer@Sun.COM 		    scsi_task_t, task,
17539578SSam.Cramer@Sun.COM 		    fct_i_remote_port_t, irp);
17547836SJohn.Forte@Sun.COM 
17557836SJohn.Forte@Sun.COM 		if (load >= iport->iport_task_green_limit) {
17567836SJohn.Forte@Sun.COM 			if ((load < iport->iport_task_yellow_limit &&
17577836SJohn.Forte@Sun.COM 			    irp_task >= 4) ||
17587836SJohn.Forte@Sun.COM 			    (load >= iport->iport_task_yellow_limit &&
17597836SJohn.Forte@Sun.COM 			    load < iport->iport_task_red_limit &&
17607836SJohn.Forte@Sun.COM 			    irp_task >= 1) ||
17617836SJohn.Forte@Sun.COM 			    (load >= iport->iport_task_red_limit))
17627836SJohn.Forte@Sun.COM 				task->task_additional_flags |=
17639578SSam.Cramer@Sun.COM 				    TASK_AF_PORT_LOAD_HIGH;
17647836SJohn.Forte@Sun.COM 		}
176512314SJames.Moore@Sun.COM 		/*
176612314SJames.Moore@Sun.COM 		 * If the target driver accepts sglists, fill in task fields.
176712314SJames.Moore@Sun.COM 		 */
176812314SJames.Moore@Sun.COM 		fds = cmd->cmd_port->port_fds;
176912314SJames.Moore@Sun.COM 		if (fds->fds_setup_dbuf != NULL) {
177012314SJames.Moore@Sun.COM 			task->task_additional_flags |= TASK_AF_ACCEPT_LU_DBUF;
177112314SJames.Moore@Sun.COM 			task->task_copy_threshold = fds->fds_copy_threshold;
177212314SJames.Moore@Sun.COM 			task->task_max_xfer_len = fds->fds_max_sgl_xfer_len;
177312314SJames.Moore@Sun.COM 			/*
177412314SJames.Moore@Sun.COM 			 * A single stream load encounters a little extra
177512314SJames.Moore@Sun.COM 			 * latency if large xfers are done in 1 chunk.
177612314SJames.Moore@Sun.COM 			 * Give a hint to the LU that starting the xfer
177712314SJames.Moore@Sun.COM 			 * with a smaller chunk would be better in this case.
177812314SJames.Moore@Sun.COM 			 * For any other load, use maximum chunk size.
177912314SJames.Moore@Sun.COM 			 */
178012314SJames.Moore@Sun.COM 			if (load == 1) {
178112314SJames.Moore@Sun.COM 				/* estimate */
178212314SJames.Moore@Sun.COM 				task->task_1st_xfer_len = 128*1024;
178312314SJames.Moore@Sun.COM 			} else {
178412314SJames.Moore@Sun.COM 				/* zero means no hint */
178512314SJames.Moore@Sun.COM 				task->task_1st_xfer_len = 0;
178612314SJames.Moore@Sun.COM 			}
178712314SJames.Moore@Sun.COM 		}
178812314SJames.Moore@Sun.COM 
17897836SJohn.Forte@Sun.COM 		stmf_post_task((scsi_task_t *)cmd->cmd_specific, dbuf);
17907836SJohn.Forte@Sun.COM 		atomic_and_32(&icmd->icmd_flags, ~ICMD_IN_TRANSITION);
17917836SJohn.Forte@Sun.COM 		return;
17927836SJohn.Forte@Sun.COM 	}
17937836SJohn.Forte@Sun.COM 	/* We dont need dbuf for other cmds */
17947836SJohn.Forte@Sun.COM 	if (dbuf) {
17957836SJohn.Forte@Sun.COM 		cmd->cmd_port->port_fds->fds_free_data_buf(
17967836SJohn.Forte@Sun.COM 		    cmd->cmd_port->port_fds, dbuf);
17977836SJohn.Forte@Sun.COM 		dbuf = NULL;
17987836SJohn.Forte@Sun.COM 	}
17997836SJohn.Forte@Sun.COM 	if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
18007836SJohn.Forte@Sun.COM 		fct_handle_els(cmd);
18017836SJohn.Forte@Sun.COM 		return;
18027836SJohn.Forte@Sun.COM 	}
18037836SJohn.Forte@Sun.COM 	if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) {
18047836SJohn.Forte@Sun.COM 		fct_handle_rcvd_abts(cmd);
18057836SJohn.Forte@Sun.COM 		return;
18067836SJohn.Forte@Sun.COM 	}
18077836SJohn.Forte@Sun.COM 
18087836SJohn.Forte@Sun.COM 	ASSERT(0);
18097836SJohn.Forte@Sun.COM }
18107836SJohn.Forte@Sun.COM 
18117836SJohn.Forte@Sun.COM /*
18127836SJohn.Forte@Sun.COM  * This function bypasses fct_handle_els()
18137836SJohn.Forte@Sun.COM  */
18147836SJohn.Forte@Sun.COM void
fct_post_implicit_logo(fct_cmd_t * cmd)18157836SJohn.Forte@Sun.COM fct_post_implicit_logo(fct_cmd_t *cmd)
18167836SJohn.Forte@Sun.COM {
18177836SJohn.Forte@Sun.COM 	fct_local_port_t *port = cmd->cmd_port;
18187836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport =
18199578SSam.Cramer@Sun.COM 	    (fct_i_local_port_t *)port->port_fct_private;
18207836SJohn.Forte@Sun.COM 	fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
18217836SJohn.Forte@Sun.COM 	fct_remote_port_t *rp = cmd->cmd_rp;
18227836SJohn.Forte@Sun.COM 	fct_i_remote_port_t *irp = (fct_i_remote_port_t *)rp->rp_fct_private;
18237836SJohn.Forte@Sun.COM 
18247836SJohn.Forte@Sun.COM 	icmd->icmd_start_time = ddi_get_lbolt();
18257836SJohn.Forte@Sun.COM 
18267836SJohn.Forte@Sun.COM 	rw_enter(&irp->irp_lock, RW_WRITER);
18277836SJohn.Forte@Sun.COM 	atomic_or_32(&icmd->icmd_flags, ICMD_IMPLICIT_CMD_HAS_RESOURCE);
18287836SJohn.Forte@Sun.COM 	atomic_add_16(&irp->irp_nonfcp_xchg_count, 1);
18297836SJohn.Forte@Sun.COM 	atomic_add_16(&irp->irp_sa_elses_count, 1);
18307836SJohn.Forte@Sun.COM 	/*
18317836SJohn.Forte@Sun.COM 	 * An implicit LOGO can also be posted to a irp where a PLOGI might
18327836SJohn.Forte@Sun.COM 	 * be in process. That PLOGI will reset this flag and decrement the
18337836SJohn.Forte@Sun.COM 	 * iport_nrps_login counter.
18347836SJohn.Forte@Sun.COM 	 */
18357836SJohn.Forte@Sun.COM 	if (irp->irp_flags & IRP_PLOGI_DONE) {
18367836SJohn.Forte@Sun.COM 		atomic_add_32(&iport->iport_nrps_login, -1);
18377836SJohn.Forte@Sun.COM 	}
18387836SJohn.Forte@Sun.COM 	atomic_and_32(&irp->irp_flags, ~(IRP_PLOGI_DONE | IRP_PRLI_DONE));
18397836SJohn.Forte@Sun.COM 	atomic_or_32(&icmd->icmd_flags, ICMD_SESSION_AFFECTING);
18407836SJohn.Forte@Sun.COM 	fct_post_to_discovery_queue(iport, irp, icmd);
18417836SJohn.Forte@Sun.COM 	rw_exit(&irp->irp_lock);
18427836SJohn.Forte@Sun.COM }
18437836SJohn.Forte@Sun.COM 
18447836SJohn.Forte@Sun.COM /*
18457836SJohn.Forte@Sun.COM  * called with iport_lock held, return the slot number
18467836SJohn.Forte@Sun.COM  */
18477836SJohn.Forte@Sun.COM uint16_t
fct_alloc_cmd_slot(fct_i_local_port_t * iport,fct_cmd_t * cmd)18487836SJohn.Forte@Sun.COM fct_alloc_cmd_slot(fct_i_local_port_t *iport, fct_cmd_t *cmd)
18497836SJohn.Forte@Sun.COM {
18507836SJohn.Forte@Sun.COM 	uint16_t cmd_slot;
18517836SJohn.Forte@Sun.COM 	uint32_t old, new;
18527836SJohn.Forte@Sun.COM 	fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
18537836SJohn.Forte@Sun.COM 
18547836SJohn.Forte@Sun.COM 	do {
18557836SJohn.Forte@Sun.COM 		old = iport->iport_next_free_slot;
18567836SJohn.Forte@Sun.COM 		cmd_slot = old & 0xFFFF;
18577836SJohn.Forte@Sun.COM 		if (cmd_slot == FCT_SLOT_EOL)
18587836SJohn.Forte@Sun.COM 			return (cmd_slot);
18597836SJohn.Forte@Sun.COM 		/*
18607836SJohn.Forte@Sun.COM 		 * We use high order 16 bits as a counter which keeps on
18617836SJohn.Forte@Sun.COM 		 * incrementing to avoid ABA issues with atomic lists.
18627836SJohn.Forte@Sun.COM 		 */
18637836SJohn.Forte@Sun.COM 		new = ((old + (0x10000)) & 0xFFFF0000);
18647836SJohn.Forte@Sun.COM 		new |= iport->iport_cmd_slots[cmd_slot].slot_next;
18657836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&iport->iport_next_free_slot, old, new) != old);
18667836SJohn.Forte@Sun.COM 
18677836SJohn.Forte@Sun.COM 	atomic_add_16(&iport->iport_nslots_free, -1);
18687836SJohn.Forte@Sun.COM 	iport->iport_cmd_slots[cmd_slot].slot_cmd = icmd;
18697836SJohn.Forte@Sun.COM 	cmd->cmd_handle = (uint32_t)cmd_slot | 0x80000000 |
18707836SJohn.Forte@Sun.COM 	    (((uint32_t)(iport->iport_cmd_slots[cmd_slot].slot_uniq_cntr))
18719578SSam.Cramer@Sun.COM 	    << 24);
18727836SJohn.Forte@Sun.COM 	return (cmd_slot);
18737836SJohn.Forte@Sun.COM }
18747836SJohn.Forte@Sun.COM 
18757836SJohn.Forte@Sun.COM /*
18767836SJohn.Forte@Sun.COM  * If icmd is not NULL, irp_lock must be held
18777836SJohn.Forte@Sun.COM  */
18787836SJohn.Forte@Sun.COM void
fct_post_to_discovery_queue(fct_i_local_port_t * iport,fct_i_remote_port_t * irp,fct_i_cmd_t * icmd)18797836SJohn.Forte@Sun.COM fct_post_to_discovery_queue(fct_i_local_port_t *iport,
18807836SJohn.Forte@Sun.COM     fct_i_remote_port_t *irp, fct_i_cmd_t *icmd)
18817836SJohn.Forte@Sun.COM {
18827836SJohn.Forte@Sun.COM 	fct_i_cmd_t	**p;
18837836SJohn.Forte@Sun.COM 
18847836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&iport->iport_worker_lock));
18857836SJohn.Forte@Sun.COM 	if (icmd) {
18867836SJohn.Forte@Sun.COM 		icmd->icmd_next = NULL;
18877836SJohn.Forte@Sun.COM 		for (p = &irp->irp_els_list; *p != NULL;
18889578SSam.Cramer@Sun.COM 		    p = &((*p)->icmd_next))
18899578SSam.Cramer@Sun.COM 			;
18909591STim.Szeto@Sun.COM 
18917836SJohn.Forte@Sun.COM 		*p = icmd;
18927836SJohn.Forte@Sun.COM 		atomic_or_32(&icmd->icmd_flags, ICMD_IN_IRP_QUEUE);
18937836SJohn.Forte@Sun.COM 	}
18947836SJohn.Forte@Sun.COM 
18957836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
18967836SJohn.Forte@Sun.COM 	if ((irp->irp_flags & IRP_IN_DISCOVERY_QUEUE) == 0) {
18977836SJohn.Forte@Sun.COM 
18987836SJohn.Forte@Sun.COM 		/*
18997836SJohn.Forte@Sun.COM 		 * CAUTION: do not grab local_port/remote_port locks after
19007836SJohn.Forte@Sun.COM 		 * grabbing the worker lock.
19017836SJohn.Forte@Sun.COM 		 */
19027836SJohn.Forte@Sun.COM 		irp->irp_discovery_next = NULL;
19037836SJohn.Forte@Sun.COM 		if (iport->iport_rpwe_tail) {
19047836SJohn.Forte@Sun.COM 			iport->iport_rpwe_tail->irp_discovery_next = irp;
19057836SJohn.Forte@Sun.COM 			iport->iport_rpwe_tail = irp;
19067836SJohn.Forte@Sun.COM 		} else {
19077836SJohn.Forte@Sun.COM 			iport->iport_rpwe_head = iport->iport_rpwe_tail = irp;
19087836SJohn.Forte@Sun.COM 		}
19097836SJohn.Forte@Sun.COM 
19107836SJohn.Forte@Sun.COM 		atomic_or_32(&irp->irp_flags, IRP_IN_DISCOVERY_QUEUE);
19117836SJohn.Forte@Sun.COM 	}
19127836SJohn.Forte@Sun.COM 
19137836SJohn.Forte@Sun.COM 	/*
19147836SJohn.Forte@Sun.COM 	 * We need always signal the port worker irrespective of the fact that
19157836SJohn.Forte@Sun.COM 	 * irp is already in discovery queue or not.
19167836SJohn.Forte@Sun.COM 	 */
19177836SJohn.Forte@Sun.COM 	if (IS_WORKER_SLEEPING(iport)) {
19187836SJohn.Forte@Sun.COM 		cv_signal(&iport->iport_worker_cv);
19197836SJohn.Forte@Sun.COM 	}
19207836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
19217836SJohn.Forte@Sun.COM }
19227836SJohn.Forte@Sun.COM 
19237836SJohn.Forte@Sun.COM stmf_status_t
fct_xfer_scsi_data(scsi_task_t * task,stmf_data_buf_t * dbuf,uint32_t ioflags)19247836SJohn.Forte@Sun.COM fct_xfer_scsi_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags)
19257836SJohn.Forte@Sun.COM {
19267836SJohn.Forte@Sun.COM 	fct_cmd_t *cmd = (fct_cmd_t *)task->task_port_private;
19277836SJohn.Forte@Sun.COM 
19289578SSam.Cramer@Sun.COM 	DTRACE_FC_5(xfer__start,
19299578SSam.Cramer@Sun.COM 	    fct_cmd_t, cmd,
19309578SSam.Cramer@Sun.COM 	    fct_i_local_port_t, cmd->cmd_port->port_fct_private,
19319578SSam.Cramer@Sun.COM 	    scsi_task_t, task,
19329578SSam.Cramer@Sun.COM 	    fct_i_remote_port_t, cmd->cmd_rp->rp_fct_private,
19339578SSam.Cramer@Sun.COM 	    stmf_data_buf_t, dbuf);
19349578SSam.Cramer@Sun.COM 
19357836SJohn.Forte@Sun.COM 	return (cmd->cmd_port->port_xfer_scsi_data(cmd, dbuf, ioflags));
19367836SJohn.Forte@Sun.COM }
19377836SJohn.Forte@Sun.COM 
19387836SJohn.Forte@Sun.COM void
fct_scsi_data_xfer_done(fct_cmd_t * cmd,stmf_data_buf_t * dbuf,uint32_t ioflags)19397836SJohn.Forte@Sun.COM fct_scsi_data_xfer_done(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags)
19407836SJohn.Forte@Sun.COM {
19417836SJohn.Forte@Sun.COM 	fct_i_cmd_t	*icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
19427836SJohn.Forte@Sun.COM 	uint32_t	old, new;
19437836SJohn.Forte@Sun.COM 	uint32_t	iof = 0;
19447836SJohn.Forte@Sun.COM 
19459578SSam.Cramer@Sun.COM 	DTRACE_FC_5(xfer__done,
19469578SSam.Cramer@Sun.COM 	    fct_cmd_t, cmd,
19479578SSam.Cramer@Sun.COM 	    fct_i_local_port_t, cmd->cmd_port->port_fct_private,
19489578SSam.Cramer@Sun.COM 	    scsi_task_t, ((scsi_task_t *)cmd->cmd_specific),
19499578SSam.Cramer@Sun.COM 	    fct_i_remote_port_t, cmd->cmd_rp->rp_fct_private,
19509578SSam.Cramer@Sun.COM 	    stmf_data_buf_t, dbuf);
19519578SSam.Cramer@Sun.COM 
19527836SJohn.Forte@Sun.COM 	if (ioflags & FCT_IOF_FCA_DONE) {
19537836SJohn.Forte@Sun.COM 		do {
19547836SJohn.Forte@Sun.COM 			old = new = icmd->icmd_flags;
19557836SJohn.Forte@Sun.COM 			if (old & ICMD_BEING_ABORTED) {
19567836SJohn.Forte@Sun.COM 				return;
19577836SJohn.Forte@Sun.COM 			}
19587836SJohn.Forte@Sun.COM 			new &= ~ICMD_KNOWN_TO_FCA;
19597836SJohn.Forte@Sun.COM 		} while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
19607836SJohn.Forte@Sun.COM 		iof = STMF_IOF_LPORT_DONE;
19617836SJohn.Forte@Sun.COM 		cmd->cmd_comp_status = dbuf->db_xfer_status;
19627836SJohn.Forte@Sun.COM 	}
19637836SJohn.Forte@Sun.COM 
19647836SJohn.Forte@Sun.COM 	if (icmd->icmd_flags & ICMD_BEING_ABORTED)
19657836SJohn.Forte@Sun.COM 		return;
19667836SJohn.Forte@Sun.COM 	stmf_data_xfer_done((scsi_task_t *)cmd->cmd_specific, dbuf, iof);
19677836SJohn.Forte@Sun.COM }
19687836SJohn.Forte@Sun.COM 
19697836SJohn.Forte@Sun.COM stmf_status_t
fct_send_scsi_status(scsi_task_t * task,uint32_t ioflags)19707836SJohn.Forte@Sun.COM fct_send_scsi_status(scsi_task_t *task, uint32_t ioflags)
19717836SJohn.Forte@Sun.COM {
19727836SJohn.Forte@Sun.COM 	fct_cmd_t *cmd = (fct_cmd_t *)task->task_port_private;
19737836SJohn.Forte@Sun.COM 
19749578SSam.Cramer@Sun.COM 	DTRACE_FC_4(scsi__response,
19759578SSam.Cramer@Sun.COM 	    fct_cmd_t, cmd,
19769578SSam.Cramer@Sun.COM 	    fct_i_local_port_t,
19779578SSam.Cramer@Sun.COM 	    (fct_i_local_port_t *)cmd->cmd_port->port_fct_private,
19789578SSam.Cramer@Sun.COM 	    scsi_task_t, task,
19799578SSam.Cramer@Sun.COM 	    fct_i_remote_port_t,
19809578SSam.Cramer@Sun.COM 	    (fct_i_remote_port_t *)cmd->cmd_rp->rp_fct_private);
19819578SSam.Cramer@Sun.COM 
19827836SJohn.Forte@Sun.COM 	return (cmd->cmd_port->port_send_cmd_response(cmd, ioflags));
19837836SJohn.Forte@Sun.COM }
19847836SJohn.Forte@Sun.COM 
19857836SJohn.Forte@Sun.COM void
fct_send_response_done(fct_cmd_t * cmd,fct_status_t s,uint32_t ioflags)19867836SJohn.Forte@Sun.COM fct_send_response_done(fct_cmd_t *cmd, fct_status_t s, uint32_t ioflags)
19877836SJohn.Forte@Sun.COM {
19887836SJohn.Forte@Sun.COM 	fct_i_cmd_t	*icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
19897836SJohn.Forte@Sun.COM 	fct_local_port_t *port = cmd->cmd_port;
19907836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport = (fct_i_local_port_t *)
19919578SSam.Cramer@Sun.COM 	    port->port_fct_private;
19927836SJohn.Forte@Sun.COM 	uint32_t old, new;
19937836SJohn.Forte@Sun.COM 
19947836SJohn.Forte@Sun.COM 	if ((ioflags & FCT_IOF_FCA_DONE) == 0) {
19957836SJohn.Forte@Sun.COM 		/* Until we support confirmed completions, this is an error */
19967836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd, s);
19977836SJohn.Forte@Sun.COM 		return;
19987836SJohn.Forte@Sun.COM 	}
19997836SJohn.Forte@Sun.COM 	do {
20007836SJohn.Forte@Sun.COM 		old = new = icmd->icmd_flags;
20017836SJohn.Forte@Sun.COM 		if (old & ICMD_BEING_ABORTED) {
20027836SJohn.Forte@Sun.COM 			return;
20037836SJohn.Forte@Sun.COM 		}
20047836SJohn.Forte@Sun.COM 		new &= ~ICMD_KNOWN_TO_FCA;
20057836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
20067836SJohn.Forte@Sun.COM 
20077836SJohn.Forte@Sun.COM 	cmd->cmd_comp_status = s;
20087836SJohn.Forte@Sun.COM 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
20097836SJohn.Forte@Sun.COM 		stmf_send_status_done((scsi_task_t *)cmd->cmd_specific, s,
20109578SSam.Cramer@Sun.COM 		    STMF_IOF_LPORT_DONE);
20117836SJohn.Forte@Sun.COM 		return;
20127836SJohn.Forte@Sun.COM 	}
20137836SJohn.Forte@Sun.COM 
20147836SJohn.Forte@Sun.COM 	if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
20157836SJohn.Forte@Sun.COM 		fct_cmd_free(cmd);
20167836SJohn.Forte@Sun.COM 		return;
20177836SJohn.Forte@Sun.COM 	} else if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
20187836SJohn.Forte@Sun.COM 		fct_handle_sol_els_completion(iport, icmd);
20197836SJohn.Forte@Sun.COM 	} else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
20207836SJohn.Forte@Sun.COM 		/* Tell the caller that we are done */
20217836SJohn.Forte@Sun.COM 		atomic_or_32(&icmd->icmd_flags, ICMD_CMD_COMPLETE);
20227836SJohn.Forte@Sun.COM 	} else {
20237836SJohn.Forte@Sun.COM 		ASSERT(0);
20247836SJohn.Forte@Sun.COM 	}
20257836SJohn.Forte@Sun.COM }
20267836SJohn.Forte@Sun.COM 
20277836SJohn.Forte@Sun.COM void
fct_cmd_free(fct_cmd_t * cmd)20287836SJohn.Forte@Sun.COM fct_cmd_free(fct_cmd_t *cmd)
20297836SJohn.Forte@Sun.COM {
2030*12571SViswanathan.Kannappan@Sun.COM 	char			info[FCT_INFO_LEN];
20317836SJohn.Forte@Sun.COM 	fct_i_cmd_t		*icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
20327836SJohn.Forte@Sun.COM 	fct_local_port_t	*port = cmd->cmd_port;
20337836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
20347836SJohn.Forte@Sun.COM 	    port->port_fct_private;
20357836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp = NULL;
20367836SJohn.Forte@Sun.COM 	int			do_abts_acc = 0;
20377836SJohn.Forte@Sun.COM 	uint32_t		old, new;
20387836SJohn.Forte@Sun.COM 
20397836SJohn.Forte@Sun.COM 	ASSERT(!mutex_owned(&iport->iport_worker_lock));
20407836SJohn.Forte@Sun.COM 	/* Give the slot back */
20417836SJohn.Forte@Sun.COM 	if (CMD_HANDLE_VALID(cmd->cmd_handle)) {
20427836SJohn.Forte@Sun.COM 		uint16_t n = CMD_HANDLE_SLOT_INDEX(cmd->cmd_handle);
20437836SJohn.Forte@Sun.COM 		fct_cmd_slot_t *slot;
20447836SJohn.Forte@Sun.COM 
20457836SJohn.Forte@Sun.COM 		/*
20467836SJohn.Forte@Sun.COM 		 * If anything went wrong, grab the lock as writer. This is
20477836SJohn.Forte@Sun.COM 		 * probably unnecessary.
20487836SJohn.Forte@Sun.COM 		 */
20497836SJohn.Forte@Sun.COM 		if ((cmd->cmd_comp_status != FCT_SUCCESS) ||
20507836SJohn.Forte@Sun.COM 		    (icmd->icmd_flags & ICMD_ABTS_RECEIVED)) {
20517836SJohn.Forte@Sun.COM 			rw_enter(&iport->iport_lock, RW_WRITER);
20527836SJohn.Forte@Sun.COM 		} else {
20537836SJohn.Forte@Sun.COM 			rw_enter(&iport->iport_lock, RW_READER);
20547836SJohn.Forte@Sun.COM 		}
20557836SJohn.Forte@Sun.COM 
20567836SJohn.Forte@Sun.COM 		if ((icmd->icmd_flags & ICMD_ABTS_RECEIVED) &&
20577836SJohn.Forte@Sun.COM 		    (cmd->cmd_link != NULL)) {
20587836SJohn.Forte@Sun.COM 			do_abts_acc = 1;
20597836SJohn.Forte@Sun.COM 		}
20607836SJohn.Forte@Sun.COM 
20617836SJohn.Forte@Sun.COM 		/* XXX Validate slot before freeing */
20627836SJohn.Forte@Sun.COM 
20637836SJohn.Forte@Sun.COM 		slot = &iport->iport_cmd_slots[n];
20647836SJohn.Forte@Sun.COM 		slot->slot_uniq_cntr++;
20657836SJohn.Forte@Sun.COM 		slot->slot_cmd = NULL;
20667836SJohn.Forte@Sun.COM 		do {
20677836SJohn.Forte@Sun.COM 			old = iport->iport_next_free_slot;
20687836SJohn.Forte@Sun.COM 			slot->slot_next = old & 0xFFFF;
20697836SJohn.Forte@Sun.COM 			new = (old + 0x10000) & 0xFFFF0000;
20707836SJohn.Forte@Sun.COM 			new |= slot->slot_no;
20717836SJohn.Forte@Sun.COM 		} while (atomic_cas_32(&iport->iport_next_free_slot,
20727836SJohn.Forte@Sun.COM 		    old, new) != old);
20737836SJohn.Forte@Sun.COM 		cmd->cmd_handle = 0;
20747836SJohn.Forte@Sun.COM 		atomic_add_16(&iport->iport_nslots_free, 1);
20757836SJohn.Forte@Sun.COM 		if (cmd->cmd_rp) {
20767836SJohn.Forte@Sun.COM 			irp = (fct_i_remote_port_t *)
20779578SSam.Cramer@Sun.COM 			    cmd->cmd_rp->rp_fct_private;
20787836SJohn.Forte@Sun.COM 			if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
20797836SJohn.Forte@Sun.COM 				atomic_add_16(&irp->irp_fcp_xchg_count, -1);
20807836SJohn.Forte@Sun.COM 			else
20817836SJohn.Forte@Sun.COM 				atomic_add_16(&irp->irp_nonfcp_xchg_count, -1);
20827836SJohn.Forte@Sun.COM 		}
20837836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
20847836SJohn.Forte@Sun.COM 	} else if ((icmd->icmd_flags & ICMD_IMPLICIT) &&
20857836SJohn.Forte@Sun.COM 	    (icmd->icmd_flags & ICMD_IMPLICIT_CMD_HAS_RESOURCE)) {
20867836SJohn.Forte@Sun.COM 		/* for implicit cmd, no cmd slot is used */
20877836SJohn.Forte@Sun.COM 		if (cmd->cmd_rp) {
20887836SJohn.Forte@Sun.COM 			irp = (fct_i_remote_port_t *)
20899578SSam.Cramer@Sun.COM 			    cmd->cmd_rp->rp_fct_private;
20907836SJohn.Forte@Sun.COM 			if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
20917836SJohn.Forte@Sun.COM 				atomic_add_16(&irp->irp_fcp_xchg_count, -1);
20927836SJohn.Forte@Sun.COM 			else
20937836SJohn.Forte@Sun.COM 				atomic_add_16(&irp->irp_nonfcp_xchg_count, -1);
20947836SJohn.Forte@Sun.COM 		}
20957836SJohn.Forte@Sun.COM 	}
20967836SJohn.Forte@Sun.COM 
20977836SJohn.Forte@Sun.COM 	if (do_abts_acc) {
20987836SJohn.Forte@Sun.COM 		fct_cmd_t *lcmd = cmd->cmd_link;
20997836SJohn.Forte@Sun.COM 		fct_fill_abts_acc(lcmd);
21007836SJohn.Forte@Sun.COM 		if (port->port_send_cmd_response(lcmd,
21017836SJohn.Forte@Sun.COM 		    FCT_IOF_FORCE_FCA_DONE) != FCT_SUCCESS) {
21027836SJohn.Forte@Sun.COM 			/*
21037836SJohn.Forte@Sun.COM 			 * XXX Throw HBA fatal error event
21047836SJohn.Forte@Sun.COM 			 * Later shutdown svc will terminate the ABTS in the end
21057836SJohn.Forte@Sun.COM 			 */
2106*12571SViswanathan.Kannappan@Sun.COM 			(void) snprintf(info, sizeof (info),
21077836SJohn.Forte@Sun.COM 			    "fct_cmd_free: iport-%p, ABTS_ACC"
21087836SJohn.Forte@Sun.COM 			    " port_send_cmd_response failed", (void *)iport);
21097836SJohn.Forte@Sun.COM 			(void) fct_port_shutdown(iport->iport_port,
21107836SJohn.Forte@Sun.COM 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
21117836SJohn.Forte@Sun.COM 			return;
21127836SJohn.Forte@Sun.COM 		} else {
21137836SJohn.Forte@Sun.COM 			fct_cmd_free(lcmd);
21147836SJohn.Forte@Sun.COM 			cmd->cmd_link = NULL;
21157836SJohn.Forte@Sun.COM 		}
21167836SJohn.Forte@Sun.COM 	}
21177836SJohn.Forte@Sun.COM 
21187836SJohn.Forte@Sun.COM 	/* Free the cmd */
21197836SJohn.Forte@Sun.COM 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
21207836SJohn.Forte@Sun.COM 		if (iport->iport_cached_ncmds < max_cached_ncmds) {
21217836SJohn.Forte@Sun.COM 			icmd->icmd_flags = 0;
21227836SJohn.Forte@Sun.COM 			mutex_enter(&iport->iport_cached_cmd_lock);
21237836SJohn.Forte@Sun.COM 			icmd->icmd_next = iport->iport_cached_cmdlist;
21247836SJohn.Forte@Sun.COM 			iport->iport_cached_cmdlist = icmd;
21257836SJohn.Forte@Sun.COM 			iport->iport_cached_ncmds++;
21267836SJohn.Forte@Sun.COM 			mutex_exit(&iport->iport_cached_cmd_lock);
21277836SJohn.Forte@Sun.COM 		} else {
21287836SJohn.Forte@Sun.COM 			atomic_add_32(&iport->iport_total_alloced_ncmds, -1);
21297836SJohn.Forte@Sun.COM 			fct_free(cmd);
21307836SJohn.Forte@Sun.COM 		}
21317836SJohn.Forte@Sun.COM 	} else {
21327836SJohn.Forte@Sun.COM 		fct_free(cmd);
21337836SJohn.Forte@Sun.COM 	}
21347836SJohn.Forte@Sun.COM }
21357836SJohn.Forte@Sun.COM 
21367836SJohn.Forte@Sun.COM /* ARGSUSED */
21377836SJohn.Forte@Sun.COM stmf_status_t
fct_scsi_abort(stmf_local_port_t * lport,int abort_cmd,void * arg,uint32_t flags)21387836SJohn.Forte@Sun.COM fct_scsi_abort(stmf_local_port_t *lport, int abort_cmd, void *arg,
21397836SJohn.Forte@Sun.COM 							uint32_t flags)
21407836SJohn.Forte@Sun.COM {
21417836SJohn.Forte@Sun.COM 	stmf_status_t ret = STMF_SUCCESS;
21427836SJohn.Forte@Sun.COM 	scsi_task_t *task;
21437836SJohn.Forte@Sun.COM 	fct_cmd_t *cmd;
21447836SJohn.Forte@Sun.COM 	fct_i_cmd_t *icmd;
21457836SJohn.Forte@Sun.COM 	fct_local_port_t *port;
21467836SJohn.Forte@Sun.COM 	uint32_t old, new;
21477836SJohn.Forte@Sun.COM 
21487836SJohn.Forte@Sun.COM 	ASSERT(abort_cmd == STMF_LPORT_ABORT_TASK);
21497836SJohn.Forte@Sun.COM 
21507836SJohn.Forte@Sun.COM 	task = (scsi_task_t *)arg;
21517836SJohn.Forte@Sun.COM 	cmd = (fct_cmd_t *)task->task_port_private;
21527836SJohn.Forte@Sun.COM 	icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
21537836SJohn.Forte@Sun.COM 	port = (fct_local_port_t *)lport->lport_port_private;
21547836SJohn.Forte@Sun.COM 
21557836SJohn.Forte@Sun.COM 	do {
21567836SJohn.Forte@Sun.COM 		old = new = icmd->icmd_flags;
21577836SJohn.Forte@Sun.COM 		if ((old & ICMD_KNOWN_TO_FCA) == 0)
21587836SJohn.Forte@Sun.COM 			return (STMF_NOT_FOUND);
21597836SJohn.Forte@Sun.COM 		ASSERT((old & ICMD_FCA_ABORT_CALLED) == 0);
21607836SJohn.Forte@Sun.COM 		new |= ICMD_BEING_ABORTED | ICMD_FCA_ABORT_CALLED;
21617836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
21627836SJohn.Forte@Sun.COM 	ret = port->port_abort_cmd(port, cmd, 0);
21637836SJohn.Forte@Sun.COM 	if ((ret == FCT_NOT_FOUND) || (ret == FCT_ABORT_SUCCESS)) {
21647836SJohn.Forte@Sun.COM 		atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
21657836SJohn.Forte@Sun.COM 	} else if (ret == FCT_BUSY) {
21667836SJohn.Forte@Sun.COM 		atomic_and_32(&icmd->icmd_flags, ~ICMD_FCA_ABORT_CALLED);
21677836SJohn.Forte@Sun.COM 	}
21687836SJohn.Forte@Sun.COM 
21697836SJohn.Forte@Sun.COM 	return (ret);
21707836SJohn.Forte@Sun.COM }
21717836SJohn.Forte@Sun.COM 
21727836SJohn.Forte@Sun.COM void
fct_ctl(struct stmf_local_port * lport,int cmd,void * arg)21737836SJohn.Forte@Sun.COM fct_ctl(struct stmf_local_port *lport, int cmd, void *arg)
21747836SJohn.Forte@Sun.COM {
21757836SJohn.Forte@Sun.COM 	fct_local_port_t *port;
21767836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport;
21777836SJohn.Forte@Sun.COM 	stmf_change_status_t st;
21787836SJohn.Forte@Sun.COM 	stmf_change_status_t *pst;
21797836SJohn.Forte@Sun.COM 
21807836SJohn.Forte@Sun.COM 	ASSERT((cmd == STMF_CMD_LPORT_ONLINE) ||
21817836SJohn.Forte@Sun.COM 	    (cmd == STMF_ACK_LPORT_ONLINE_COMPLETE) ||
21827836SJohn.Forte@Sun.COM 	    (cmd == STMF_CMD_LPORT_OFFLINE) ||
21837836SJohn.Forte@Sun.COM 	    (cmd == STMF_ACK_LPORT_OFFLINE_COMPLETE) ||
21847836SJohn.Forte@Sun.COM 	    (cmd == FCT_CMD_PORT_ONLINE_COMPLETE) ||
21857836SJohn.Forte@Sun.COM 	    (cmd == FCT_CMD_PORT_OFFLINE_COMPLETE));
21867836SJohn.Forte@Sun.COM 
21877836SJohn.Forte@Sun.COM 	port = (fct_local_port_t *)lport->lport_port_private;
21887836SJohn.Forte@Sun.COM 	pst = (stmf_change_status_t *)arg;
21897836SJohn.Forte@Sun.COM 	st.st_completion_status = STMF_SUCCESS;
21907836SJohn.Forte@Sun.COM 	st.st_additional_info = NULL;
21917836SJohn.Forte@Sun.COM 
21927836SJohn.Forte@Sun.COM 	iport = (fct_i_local_port_t *)port->port_fct_private;
21937836SJohn.Forte@Sun.COM 	/*
21947836SJohn.Forte@Sun.COM 	 * We are mostly a passthrough, except during offline.
21957836SJohn.Forte@Sun.COM 	 */
21967836SJohn.Forte@Sun.COM 	switch (cmd) {
21977836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_ONLINE:
21987836SJohn.Forte@Sun.COM 		if (iport->iport_state == FCT_STATE_ONLINE)
21997836SJohn.Forte@Sun.COM 			st.st_completion_status = STMF_ALREADY;
22007836SJohn.Forte@Sun.COM 		else if (iport->iport_state != FCT_STATE_OFFLINE)
22017836SJohn.Forte@Sun.COM 			st.st_completion_status = STMF_INVALID_ARG;
22027836SJohn.Forte@Sun.COM 		if (st.st_completion_status != STMF_SUCCESS) {
22037836SJohn.Forte@Sun.COM 			(void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport,
22047836SJohn.Forte@Sun.COM 			    &st);
22057836SJohn.Forte@Sun.COM 			break;
22067836SJohn.Forte@Sun.COM 		}
22077836SJohn.Forte@Sun.COM 		iport->iport_state_not_acked = 1;
22087836SJohn.Forte@Sun.COM 		iport->iport_state = FCT_STATE_ONLINING;
22097836SJohn.Forte@Sun.COM 		port->port_ctl(port, FCT_CMD_PORT_ONLINE, arg);
22107836SJohn.Forte@Sun.COM 		break;
22117836SJohn.Forte@Sun.COM 	case FCT_CMD_PORT_ONLINE_COMPLETE:
22127836SJohn.Forte@Sun.COM 		ASSERT(iport->iport_state == FCT_STATE_ONLINING);
22137836SJohn.Forte@Sun.COM 		if (pst->st_completion_status != FCT_SUCCESS) {
22147836SJohn.Forte@Sun.COM 			iport->iport_state = FCT_STATE_OFFLINE;
22157836SJohn.Forte@Sun.COM 			iport->iport_state_not_acked = 0;
22167836SJohn.Forte@Sun.COM 		} else {
22177836SJohn.Forte@Sun.COM 			iport->iport_state = FCT_STATE_ONLINE;
22187836SJohn.Forte@Sun.COM 		}
22197836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport, arg);
22207836SJohn.Forte@Sun.COM 		break;
22217836SJohn.Forte@Sun.COM 	case STMF_ACK_LPORT_ONLINE_COMPLETE:
22227836SJohn.Forte@Sun.COM 		ASSERT(iport->iport_state == FCT_STATE_ONLINE);
22237836SJohn.Forte@Sun.COM 		iport->iport_state_not_acked = 0;
22247836SJohn.Forte@Sun.COM 		port->port_ctl(port, FCT_ACK_PORT_ONLINE_COMPLETE, arg);
22257836SJohn.Forte@Sun.COM 		break;
22267836SJohn.Forte@Sun.COM 
22277836SJohn.Forte@Sun.COM 	case STMF_CMD_LPORT_OFFLINE:
22287836SJohn.Forte@Sun.COM 		if (iport->iport_state == FCT_STATE_OFFLINE)
22297836SJohn.Forte@Sun.COM 			st.st_completion_status = STMF_ALREADY;
22307836SJohn.Forte@Sun.COM 		else if (iport->iport_state != FCT_STATE_ONLINE)
22317836SJohn.Forte@Sun.COM 			st.st_completion_status = STMF_INVALID_ARG;
22327836SJohn.Forte@Sun.COM 		if (st.st_completion_status != STMF_SUCCESS) {
22337836SJohn.Forte@Sun.COM 			(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE, lport,
22347836SJohn.Forte@Sun.COM 			    &st);
22357836SJohn.Forte@Sun.COM 			break;
22367836SJohn.Forte@Sun.COM 		}
22377836SJohn.Forte@Sun.COM 		iport->iport_state_not_acked = 1;
22387836SJohn.Forte@Sun.COM 		iport->iport_state = FCT_STATE_OFFLINING;
22397836SJohn.Forte@Sun.COM 		port->port_ctl(port, FCT_CMD_PORT_OFFLINE, arg);
22407836SJohn.Forte@Sun.COM 		break;
22417836SJohn.Forte@Sun.COM 	case FCT_CMD_PORT_OFFLINE_COMPLETE:
22427836SJohn.Forte@Sun.COM 		ASSERT(iport->iport_state == FCT_STATE_OFFLINING);
22437836SJohn.Forte@Sun.COM 		if (pst->st_completion_status != FCT_SUCCESS) {
22447836SJohn.Forte@Sun.COM 			iport->iport_state = FCT_STATE_ONLINE;
22457836SJohn.Forte@Sun.COM 			iport->iport_state_not_acked = 0;
22467836SJohn.Forte@Sun.COM 			(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE, lport,
22477836SJohn.Forte@Sun.COM 			    pst);
22487836SJohn.Forte@Sun.COM 			break;
22497836SJohn.Forte@Sun.COM 		}
22507836SJohn.Forte@Sun.COM 
22517836SJohn.Forte@Sun.COM 		/*
22527836SJohn.Forte@Sun.COM 		 * If FCA's offline was successful, we dont tell stmf yet.
22537836SJohn.Forte@Sun.COM 		 * Becasue now we have to do the cleanup before we go upto
22547836SJohn.Forte@Sun.COM 		 * stmf. That cleanup is done by the worker thread.
22557836SJohn.Forte@Sun.COM 		 */
22567836SJohn.Forte@Sun.COM 
22577836SJohn.Forte@Sun.COM 		/* FCA is offline, post a link down, its harmless anyway */
22587836SJohn.Forte@Sun.COM 		fct_handle_event(port, FCT_EVENT_LINK_DOWN, 0, 0);
22597836SJohn.Forte@Sun.COM 
22607836SJohn.Forte@Sun.COM 		/* Trigger port offline processing by the worker */
22617836SJohn.Forte@Sun.COM 		iport->iport_offline_prstate = FCT_OPR_START;
22627836SJohn.Forte@Sun.COM 		break;
22637836SJohn.Forte@Sun.COM 	case STMF_ACK_LPORT_OFFLINE_COMPLETE:
22647836SJohn.Forte@Sun.COM 		ASSERT(iport->iport_state == FCT_STATE_OFFLINE);
22657836SJohn.Forte@Sun.COM 		iport->iport_state_not_acked = 0;
22667836SJohn.Forte@Sun.COM 		port->port_ctl(port, FCT_ACK_PORT_OFFLINE_COMPLETE, arg);
22677836SJohn.Forte@Sun.COM 		break;
22687836SJohn.Forte@Sun.COM 	}
22697836SJohn.Forte@Sun.COM }
22707836SJohn.Forte@Sun.COM 
22717836SJohn.Forte@Sun.COM /* ARGSUSED */
22727836SJohn.Forte@Sun.COM stmf_status_t
fct_info(uint32_t cmd,stmf_local_port_t * lport,void * arg,uint8_t * buf,uint32_t * bufsizep)22737836SJohn.Forte@Sun.COM fct_info(uint32_t cmd, stmf_local_port_t *lport, void *arg, uint8_t *buf,
22747836SJohn.Forte@Sun.COM 						uint32_t *bufsizep)
22757836SJohn.Forte@Sun.COM {
22767836SJohn.Forte@Sun.COM 	return (STMF_NOT_SUPPORTED);
22777836SJohn.Forte@Sun.COM }
22787836SJohn.Forte@Sun.COM 
22797836SJohn.Forte@Sun.COM /*
22807836SJohn.Forte@Sun.COM  * implicit: if it's true, it means it will only be used in fct module, or else
22817836SJohn.Forte@Sun.COM  * it will be sent to the link.
22827836SJohn.Forte@Sun.COM  */
22837836SJohn.Forte@Sun.COM fct_cmd_t *
fct_create_solels(fct_local_port_t * port,fct_remote_port_t * rp,int implicit,uchar_t elsop,uint32_t wkdid,fct_icmd_cb_t icmdcb)22847836SJohn.Forte@Sun.COM fct_create_solels(fct_local_port_t *port, fct_remote_port_t *rp, int implicit,
22857836SJohn.Forte@Sun.COM     uchar_t elsop, uint32_t wkdid, fct_icmd_cb_t icmdcb)
22867836SJohn.Forte@Sun.COM {
22877836SJohn.Forte@Sun.COM 	fct_cmd_t		*cmd	= NULL;
22887836SJohn.Forte@Sun.COM 	fct_i_cmd_t		*icmd	= NULL;
22897836SJohn.Forte@Sun.COM 	fct_els_t		*els	= NULL;
22907836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp	= NULL;
22917836SJohn.Forte@Sun.COM 	uint8_t			*p	= NULL;
22927836SJohn.Forte@Sun.COM 	uint32_t		 ptid	= 0;
22937836SJohn.Forte@Sun.COM 
22947836SJohn.Forte@Sun.COM 	cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_SOL_ELS,
22957836SJohn.Forte@Sun.COM 	    port->port_fca_sol_els_private_size, 0);
22967836SJohn.Forte@Sun.COM 	if (!cmd) {
22977836SJohn.Forte@Sun.COM 		return (NULL);
22987836SJohn.Forte@Sun.COM 	}
22997836SJohn.Forte@Sun.COM 
23007836SJohn.Forte@Sun.COM 	if (rp) {
23017836SJohn.Forte@Sun.COM 		irp = RP_TO_IRP(rp);
23027836SJohn.Forte@Sun.COM 	} else if (((irp = fct_portid_to_portptr(PORT_TO_IPORT(port),
23037836SJohn.Forte@Sun.COM 	    wkdid)) == NULL) && (elsop != ELS_OP_PLOGI)) {
23047836SJohn.Forte@Sun.COM 		stmf_trace(PORT_TO_IPORT(port)->iport_alias,
23057836SJohn.Forte@Sun.COM 		    "fct_create_solels: Must PLOGI to %x first", wkdid);
23067836SJohn.Forte@Sun.COM 		fct_free(cmd);
23077836SJohn.Forte@Sun.COM 		return (NULL);
23087836SJohn.Forte@Sun.COM 	}
23097836SJohn.Forte@Sun.COM 
23107836SJohn.Forte@Sun.COM 	cmd->cmd_port	= port;
23117836SJohn.Forte@Sun.COM 	cmd->cmd_oxid	= PTR2INT(cmd, uint16_t);
23127836SJohn.Forte@Sun.COM 	cmd->cmd_rxid	= 0xFFFF;
23137836SJohn.Forte@Sun.COM 	cmd->cmd_handle = 0;
23147836SJohn.Forte@Sun.COM 	icmd		= CMD_TO_ICMD(cmd);
23157836SJohn.Forte@Sun.COM 	els		= ICMD_TO_ELS(icmd);
23167836SJohn.Forte@Sun.COM 	icmd->icmd_cb	= icmdcb;
23177836SJohn.Forte@Sun.COM 	if (irp) {
23187836SJohn.Forte@Sun.COM 		cmd->cmd_rp	   = irp->irp_rp;
23197836SJohn.Forte@Sun.COM 		cmd->cmd_rp_handle = irp->irp_rp->rp_handle;
23207836SJohn.Forte@Sun.COM 		cmd->cmd_rportid   = irp->irp_rp->rp_id;
23217836SJohn.Forte@Sun.COM 	} else {
23227836SJohn.Forte@Sun.COM 		cmd->cmd_rp_handle = FCT_HANDLE_NONE;
23237836SJohn.Forte@Sun.COM 		cmd->cmd_rportid   = wkdid;
23247836SJohn.Forte@Sun.COM 	}
23257836SJohn.Forte@Sun.COM 	cmd->cmd_lportid = (PORT_TO_IPORT(port))->iport_link_info.portid;
23267836SJohn.Forte@Sun.COM 
23277836SJohn.Forte@Sun.COM 	if (implicit) {
23287836SJohn.Forte@Sun.COM 		/*
23297836SJohn.Forte@Sun.COM 		 * Since we will not send it to FCA, so we only allocate space
23307836SJohn.Forte@Sun.COM 		 */
23317836SJohn.Forte@Sun.COM 		ASSERT(elsop & (ELS_OP_LOGO | ELS_OP_PLOGI));
23327836SJohn.Forte@Sun.COM 		icmd->icmd_flags |= ICMD_IMPLICIT;
23337836SJohn.Forte@Sun.COM 		if (elsop == ELS_OP_LOGO) {
23347836SJohn.Forte@Sun.COM 			/*
23357836SJohn.Forte@Sun.COM 			 * Handling implicit LOGO should dependent on as less
23367836SJohn.Forte@Sun.COM 			 * as resources. So a trick here.
23377836SJohn.Forte@Sun.COM 			 */
23387836SJohn.Forte@Sun.COM 			els->els_req_size = 1;
23397836SJohn.Forte@Sun.COM 			els->els_req_payload = cmd->cmd_fca_private;
23407836SJohn.Forte@Sun.COM 		} else {
23417836SJohn.Forte@Sun.COM 			els->els_req_alloc_size = els->els_req_size = 116;
23427836SJohn.Forte@Sun.COM 			els->els_resp_alloc_size = els->els_resp_size = 116;
23437836SJohn.Forte@Sun.COM 			els->els_req_payload = (uint8_t *)
23447836SJohn.Forte@Sun.COM 			    kmem_zalloc(els->els_req_size, KM_SLEEP);
23457836SJohn.Forte@Sun.COM 			els->els_resp_payload = (uint8_t *)
23467836SJohn.Forte@Sun.COM 			    kmem_zalloc(els->els_resp_size, KM_SLEEP);
23477836SJohn.Forte@Sun.COM 		}
23487836SJohn.Forte@Sun.COM 	} else {
23497836SJohn.Forte@Sun.COM 		/*
23507836SJohn.Forte@Sun.COM 		 * Allocate space for its request and response
23517836SJohn.Forte@Sun.COM 		 * Fill the request payload according to spec.
23527836SJohn.Forte@Sun.COM 		 */
23537836SJohn.Forte@Sun.COM 		switch (elsop) {
23547836SJohn.Forte@Sun.COM 		case ELS_OP_LOGO:
23557836SJohn.Forte@Sun.COM 			els->els_resp_alloc_size = els->els_resp_size = 4;
23567836SJohn.Forte@Sun.COM 			els->els_resp_payload = (uint8_t *)kmem_zalloc(
23577836SJohn.Forte@Sun.COM 			    els->els_resp_size, KM_SLEEP);
23587836SJohn.Forte@Sun.COM 			els->els_req_alloc_size = els->els_req_size = 16;
23597836SJohn.Forte@Sun.COM 			els->els_req_payload = (uint8_t *)kmem_zalloc(
23607836SJohn.Forte@Sun.COM 			    els->els_req_size, KM_SLEEP);
23617836SJohn.Forte@Sun.COM 			ptid = PORT_TO_IPORT(port)->iport_link_info.portid;
23627836SJohn.Forte@Sun.COM 			fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3);
23637836SJohn.Forte@Sun.COM 			bcopy(port->port_pwwn, els->els_req_payload + 8, 8);
23647836SJohn.Forte@Sun.COM 			break;
23657836SJohn.Forte@Sun.COM 
23667836SJohn.Forte@Sun.COM 		case ELS_OP_RSCN:
23677836SJohn.Forte@Sun.COM 			els->els_resp_alloc_size = els->els_resp_size = 4;
23687836SJohn.Forte@Sun.COM 			els->els_resp_payload = (uint8_t *)kmem_zalloc(
23697836SJohn.Forte@Sun.COM 			    els->els_resp_size, KM_SLEEP);
23707836SJohn.Forte@Sun.COM 			els->els_req_size = els->els_req_alloc_size = 8;
23717836SJohn.Forte@Sun.COM 			els->els_req_payload = (uint8_t *)kmem_zalloc(
23727836SJohn.Forte@Sun.COM 			    els->els_req_size, KM_SLEEP);
23737836SJohn.Forte@Sun.COM 			els->els_req_payload[1] = 0x04;
23747836SJohn.Forte@Sun.COM 			els->els_req_payload[3] = 0x08;
23757836SJohn.Forte@Sun.COM 			els->els_req_payload[4] |= 0x80;
23767836SJohn.Forte@Sun.COM 			ptid = PORT_TO_IPORT(port)->iport_link_info.portid;
23777836SJohn.Forte@Sun.COM 			fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3);
23787836SJohn.Forte@Sun.COM 			break;
23797836SJohn.Forte@Sun.COM 
23807836SJohn.Forte@Sun.COM 		case ELS_OP_PLOGI:
23817836SJohn.Forte@Sun.COM 			els->els_resp_alloc_size = els->els_resp_size = 116;
23827836SJohn.Forte@Sun.COM 			els->els_resp_payload = (uint8_t *)
23837836SJohn.Forte@Sun.COM 			    kmem_zalloc(els->els_resp_size, KM_SLEEP);
23847836SJohn.Forte@Sun.COM 			els->els_req_alloc_size = els->els_req_size = 116;
23857836SJohn.Forte@Sun.COM 			p = els->els_req_payload = (uint8_t *)
23867836SJohn.Forte@Sun.COM 			    kmem_zalloc(els->els_req_size, KM_SLEEP);
23877836SJohn.Forte@Sun.COM 			bcopy(port->port_pwwn, p + 20, 8);
23887836SJohn.Forte@Sun.COM 			bcopy(port->port_nwwn, p + 28, 8);
23897836SJohn.Forte@Sun.COM 
23907836SJohn.Forte@Sun.COM 			/*
23917836SJohn.Forte@Sun.COM 			 * Common service parameters
23927836SJohn.Forte@Sun.COM 			 */
23937836SJohn.Forte@Sun.COM 			p[0x04] = 0x09;		/* high version */
23947836SJohn.Forte@Sun.COM 			p[0x05] = 0x08;		/* low version */
23957836SJohn.Forte@Sun.COM 			p[0x06] = 0x00;		/* BB credit: 0x0065 */
23967836SJohn.Forte@Sun.COM 			p[0x07] = 0x65;
23977836SJohn.Forte@Sun.COM 
23987836SJohn.Forte@Sun.COM 			/* CI0: Continuously Increasing Offset - 1 */
23997836SJohn.Forte@Sun.COM 			/* RRO: Randomly Relative Offset - 0 */
24007836SJohn.Forte@Sun.COM 			/* VVV: Vendor Version Level - 0 */
24017836SJohn.Forte@Sun.COM 			/* N-F: N or F Port Payload Sender - 0 (N) */
24027836SJohn.Forte@Sun.COM 			/* BBM: BB Credit Management - 0 (Normal) */
24037836SJohn.Forte@Sun.COM 			p[0x08] = 0x80;
24047836SJohn.Forte@Sun.COM 			p[0x09] = 0x00;
24057836SJohn.Forte@Sun.COM 
24067836SJohn.Forte@Sun.COM 			/* Max RX size */
24077836SJohn.Forte@Sun.COM 			p[0x0A] = 0x08;
24087836SJohn.Forte@Sun.COM 			p[0x0B] = 0x00;
24097836SJohn.Forte@Sun.COM 
24107836SJohn.Forte@Sun.COM 			/* NPTCS: N Port Total Concurrent Sequences - 0x0000 */
24117836SJohn.Forte@Sun.COM 			p[0x0C] = 0x00;
24127836SJohn.Forte@Sun.COM 			p[0x0D] = 0x00;
24137836SJohn.Forte@Sun.COM 
24147836SJohn.Forte@Sun.COM 			/* ROIC: Relative Offset By Info - 0xFFFF */
24157836SJohn.Forte@Sun.COM 			p[0x0E] = 0xFF;
24167836SJohn.Forte@Sun.COM 			p[0x0F] = 0xFF;
24177836SJohn.Forte@Sun.COM 
24187836SJohn.Forte@Sun.COM 			/* EDTOV: Error Detect Timeout - 0x000007D0 */
24197836SJohn.Forte@Sun.COM 			p[0x10] = 0x00;
24207836SJohn.Forte@Sun.COM 			p[0x11] = 0x00;
24217836SJohn.Forte@Sun.COM 			p[0x12] = 0x07;
24227836SJohn.Forte@Sun.COM 			p[0x13] = 0xD0;
24237836SJohn.Forte@Sun.COM 
24247836SJohn.Forte@Sun.COM 			/*
24257836SJohn.Forte@Sun.COM 			 * Class-3 Parameters
24267836SJohn.Forte@Sun.COM 			 */
24277836SJohn.Forte@Sun.COM 			/* C3-VAL: Class 3 Value - 1 */
24287836SJohn.Forte@Sun.COM 			/* C3-XID: X_ID Reassignment - 0 */
24297836SJohn.Forte@Sun.COM 			/* C3-IPA: Initial Process Assignment */
24307836SJohn.Forte@Sun.COM 			/* C3-AI-DCC: Data compression capable */
24317836SJohn.Forte@Sun.COM 			/* C3-AI-DC-HB: Data compression history buffer size */
24327836SJohn.Forte@Sun.COM 			/* C3-AI-DCE: Data encrytion capable */
24337836SJohn.Forte@Sun.COM 			/* C3-AI-CSC: Clock synchronization capable */
24347836SJohn.Forte@Sun.COM 			/* C3-ErrPol: Error pliciy */
24357836SJohn.Forte@Sun.COM 			/* C3-CatSeq: Information Cat. Per Sequence */
24367836SJohn.Forte@Sun.COM 			/* C3-AR-DCC: */
24377836SJohn.Forte@Sun.COM 			/* C3-AR-DC-HB: */
24387836SJohn.Forte@Sun.COM 			/* C3-AR-DCE: */
24397836SJohn.Forte@Sun.COM 			/* C3-AR-CSC */
24407836SJohn.Forte@Sun.COM 			p[0x44] = 0x80;
24417836SJohn.Forte@Sun.COM 			p[0x45] = 0x00;
24427836SJohn.Forte@Sun.COM 			p[0x46] = 0x00;
24437836SJohn.Forte@Sun.COM 			p[0x47] = 0x00;
24447836SJohn.Forte@Sun.COM 			p[0x48] = 0x00;
24457836SJohn.Forte@Sun.COM 			p[0x49] = 0x00;
24467836SJohn.Forte@Sun.COM 
24477836SJohn.Forte@Sun.COM 			/* C3-RxSize: Class 3 receive data size */
24487836SJohn.Forte@Sun.COM 			p[0x4A] = 0x08;
24497836SJohn.Forte@Sun.COM 			p[0x4B] = 0x00;
24507836SJohn.Forte@Sun.COM 
24517836SJohn.Forte@Sun.COM 			/* C3-ConSeq: Class 3 Concourrent sequences */
24527836SJohn.Forte@Sun.COM 			p[0x4C] = 0x00;
24537836SJohn.Forte@Sun.COM 			p[0x4D] = 0xFF;
24547836SJohn.Forte@Sun.COM 
24557836SJohn.Forte@Sun.COM 			/* C3-OSPE: Class 3 open sequence per exchange */
24567836SJohn.Forte@Sun.COM 			p[0x50] = 0x00;
24577836SJohn.Forte@Sun.COM 			p[0x51] = 0x01;
24587836SJohn.Forte@Sun.COM 
24597836SJohn.Forte@Sun.COM 			break;
24607836SJohn.Forte@Sun.COM 
24617836SJohn.Forte@Sun.COM 		case ELS_OP_SCR:
24627836SJohn.Forte@Sun.COM 			els->els_resp_alloc_size = els->els_resp_size = 4;
24637836SJohn.Forte@Sun.COM 			els->els_resp_payload = (uint8_t *)
24647836SJohn.Forte@Sun.COM 			    kmem_zalloc(els->els_resp_size, KM_SLEEP);
24657836SJohn.Forte@Sun.COM 			els->els_req_alloc_size = els->els_req_size = 8;
24667836SJohn.Forte@Sun.COM 			p = els->els_req_payload = (uint8_t *)
24677836SJohn.Forte@Sun.COM 			    kmem_zalloc(els->els_req_size, KM_SLEEP);
24687836SJohn.Forte@Sun.COM 			p[7] = FC_SCR_FULL_REGISTRATION;
24697836SJohn.Forte@Sun.COM 			break;
247010088SAllan.Ou@Sun.COM 		case ELS_OP_RLS:
247110088SAllan.Ou@Sun.COM 			els->els_resp_alloc_size = els->els_resp_size = 28;
247210088SAllan.Ou@Sun.COM 			els->els_resp_payload = (uint8_t *)
247310088SAllan.Ou@Sun.COM 			    kmem_zalloc(els->els_resp_size, KM_SLEEP);
247410088SAllan.Ou@Sun.COM 			els->els_req_alloc_size = els->els_req_size = 8;
247510088SAllan.Ou@Sun.COM 			p = els->els_req_payload = (uint8_t *)
247610088SAllan.Ou@Sun.COM 			    kmem_zalloc(els->els_req_size, KM_SLEEP);
247710088SAllan.Ou@Sun.COM 			ptid = PORT_TO_IPORT(port)->iport_link_info.portid;
247810088SAllan.Ou@Sun.COM 			fct_value_to_netbuf(ptid, els->els_req_payload + 5, 3);
247910088SAllan.Ou@Sun.COM 			break;
24807836SJohn.Forte@Sun.COM 
24817836SJohn.Forte@Sun.COM 		default:
24827836SJohn.Forte@Sun.COM 			ASSERT(0);
24837836SJohn.Forte@Sun.COM 		}
24847836SJohn.Forte@Sun.COM 	}
24857836SJohn.Forte@Sun.COM 
24867836SJohn.Forte@Sun.COM 	els->els_req_payload[0] = elsop;
24877836SJohn.Forte@Sun.COM 	return (cmd);
24887836SJohn.Forte@Sun.COM }
24897836SJohn.Forte@Sun.COM 
24907836SJohn.Forte@Sun.COM fct_cmd_t *
fct_create_solct(fct_local_port_t * port,fct_remote_port_t * query_rp,uint16_t ctop,fct_icmd_cb_t icmdcb)24917836SJohn.Forte@Sun.COM fct_create_solct(fct_local_port_t *port, fct_remote_port_t *query_rp,
24927836SJohn.Forte@Sun.COM     uint16_t ctop, fct_icmd_cb_t icmdcb)
24937836SJohn.Forte@Sun.COM {
24947836SJohn.Forte@Sun.COM 	fct_cmd_t		*cmd	 = NULL;
24957836SJohn.Forte@Sun.COM 	fct_i_cmd_t		*icmd	 = NULL;
24967836SJohn.Forte@Sun.COM 	fct_sol_ct_t		*ct	 = NULL;
24977836SJohn.Forte@Sun.COM 	uint8_t			*p	 = NULL;
24987836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp	 = NULL;
24997836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport	 = NULL;
25007836SJohn.Forte@Sun.COM 	char			*nname	 = NULL;
25017836SJohn.Forte@Sun.COM 	int			 namelen = 0;
25027836SJohn.Forte@Sun.COM 
25037836SJohn.Forte@Sun.COM 	/*
25047836SJohn.Forte@Sun.COM 	 * Allocate space
25057836SJohn.Forte@Sun.COM 	 */
25067836SJohn.Forte@Sun.COM 	cmd = fct_alloc(FCT_STRUCT_CMD_SOL_CT,
25077836SJohn.Forte@Sun.COM 	    port->port_fca_sol_ct_private_size, 0);
25087836SJohn.Forte@Sun.COM 	if (!cmd) {
25097836SJohn.Forte@Sun.COM 		return (NULL);
25107836SJohn.Forte@Sun.COM 	}
25117836SJohn.Forte@Sun.COM 
25127836SJohn.Forte@Sun.COM 	/*
25137836SJohn.Forte@Sun.COM 	 * We should have PLOGIed to the name server (0xFFFFFC)
25147836SJohn.Forte@Sun.COM 	 * Caution: this irp is not query_rp->rp_fct_private.
25157836SJohn.Forte@Sun.COM 	 */
25167836SJohn.Forte@Sun.COM 	irp = fct_portid_to_portptr((fct_i_local_port_t *)
25177836SJohn.Forte@Sun.COM 	    port->port_fct_private, FS_NAME_SERVER);
25187836SJohn.Forte@Sun.COM 	if (irp == NULL) {
25197836SJohn.Forte@Sun.COM 		stmf_trace(PORT_TO_IPORT(port)->iport_alias,
25207836SJohn.Forte@Sun.COM 		    "fct_create_solct: Must PLOGI name server first");
25217836SJohn.Forte@Sun.COM 		fct_free(cmd);
25227836SJohn.Forte@Sun.COM 		return (NULL);
25237836SJohn.Forte@Sun.COM 	}
25247836SJohn.Forte@Sun.COM 
25257836SJohn.Forte@Sun.COM 	cmd->cmd_port	   = port;
25267836SJohn.Forte@Sun.COM 	cmd->cmd_rp	   = irp->irp_rp;
25277836SJohn.Forte@Sun.COM 	cmd->cmd_rp_handle = irp->irp_rp->rp_handle;
25287836SJohn.Forte@Sun.COM 	cmd->cmd_rportid   = irp->irp_rp->rp_id;
25297836SJohn.Forte@Sun.COM 	cmd->cmd_lportid   = (PORT_TO_IPORT(port))->iport_link_info.portid;
25307836SJohn.Forte@Sun.COM 	cmd->cmd_oxid	   = PTR2INT(cmd, uint16_t);
25317836SJohn.Forte@Sun.COM 	cmd->cmd_rxid	   = 0xFFFF;
25327836SJohn.Forte@Sun.COM 	cmd->cmd_handle	   = 0;
25337836SJohn.Forte@Sun.COM 	icmd		   = CMD_TO_ICMD(cmd);
25347836SJohn.Forte@Sun.COM 	ct		   = ICMD_TO_CT(icmd);
25357836SJohn.Forte@Sun.COM 	icmd->icmd_cb	   = icmdcb;
25367836SJohn.Forte@Sun.COM 	iport		   = ICMD_TO_IPORT(icmd);
25377836SJohn.Forte@Sun.COM 
25387836SJohn.Forte@Sun.COM 	switch (ctop) {
25397836SJohn.Forte@Sun.COM 	case NS_GSNN_NN:
25407836SJohn.Forte@Sun.COM 		/*
25417836SJohn.Forte@Sun.COM 		 * Allocate max space for its sybolic name
25427836SJohn.Forte@Sun.COM 		 */
25437836SJohn.Forte@Sun.COM 		ct->ct_resp_alloc_size = ct->ct_resp_size = 272;
25447836SJohn.Forte@Sun.COM 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
25457836SJohn.Forte@Sun.COM 		    KM_SLEEP);
25467836SJohn.Forte@Sun.COM 
25477836SJohn.Forte@Sun.COM 		ct->ct_req_size = ct->ct_req_alloc_size = 24;
25487836SJohn.Forte@Sun.COM 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
25497836SJohn.Forte@Sun.COM 		    KM_SLEEP);
25507836SJohn.Forte@Sun.COM 
25517836SJohn.Forte@Sun.COM 		bcopy(query_rp->rp_nwwn, p + 16, 8);
25527836SJohn.Forte@Sun.COM 		break;
25537836SJohn.Forte@Sun.COM 
25547836SJohn.Forte@Sun.COM 	case NS_RNN_ID:
25557836SJohn.Forte@Sun.COM 		ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
25567836SJohn.Forte@Sun.COM 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
25577836SJohn.Forte@Sun.COM 		    KM_SLEEP);
25587836SJohn.Forte@Sun.COM 		ct->ct_req_size = ct->ct_req_alloc_size = 28;
25597836SJohn.Forte@Sun.COM 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
25607836SJohn.Forte@Sun.COM 		    KM_SLEEP);
25617836SJohn.Forte@Sun.COM 
25627836SJohn.Forte@Sun.COM 		/*
25637836SJohn.Forte@Sun.COM 		 * Port Identifier
25647836SJohn.Forte@Sun.COM 		 */
25657836SJohn.Forte@Sun.COM 		p[17] = (iport->iport_link_info.portid >> 16) & 0xFF;
25667836SJohn.Forte@Sun.COM 		p[18] = (iport->iport_link_info.portid >>  8) & 0xFF;
25677836SJohn.Forte@Sun.COM 		p[19] = (iport->iport_link_info.portid >>  0) & 0xFF;
25687836SJohn.Forte@Sun.COM 
25697836SJohn.Forte@Sun.COM 		/*
25707836SJohn.Forte@Sun.COM 		 * Node Name
25717836SJohn.Forte@Sun.COM 		 */
25727836SJohn.Forte@Sun.COM 		bcopy(port->port_nwwn, p + 20, 8);
25737836SJohn.Forte@Sun.COM 		break;
25747836SJohn.Forte@Sun.COM 
25757836SJohn.Forte@Sun.COM 	case NS_RCS_ID:
25767836SJohn.Forte@Sun.COM 		ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
25777836SJohn.Forte@Sun.COM 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
25787836SJohn.Forte@Sun.COM 		    KM_SLEEP);
25797836SJohn.Forte@Sun.COM 		ct->ct_req_size = ct->ct_req_alloc_size = 24;
25807836SJohn.Forte@Sun.COM 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
25817836SJohn.Forte@Sun.COM 		    KM_SLEEP);
25827836SJohn.Forte@Sun.COM 
25837836SJohn.Forte@Sun.COM 		/*
25847836SJohn.Forte@Sun.COM 		 * Port Identifier
25857836SJohn.Forte@Sun.COM 		 */
25867836SJohn.Forte@Sun.COM 		p[17] = (iport->iport_link_info.portid >> 16) & 0xFF;
25877836SJohn.Forte@Sun.COM 		p[18] = (iport->iport_link_info.portid >>  8) & 0xFF;
25887836SJohn.Forte@Sun.COM 		p[19] = (iport->iport_link_info.portid >>  0) & 0xFF;
25897836SJohn.Forte@Sun.COM 
25907836SJohn.Forte@Sun.COM 		/*
25917836SJohn.Forte@Sun.COM 		 * Class of Service
25927836SJohn.Forte@Sun.COM 		 */
25937836SJohn.Forte@Sun.COM 		*(p + 23) = FC_NS_CLASS3;
25947836SJohn.Forte@Sun.COM 		break;
25957836SJohn.Forte@Sun.COM 
25967836SJohn.Forte@Sun.COM 	case NS_RFT_ID:
25977836SJohn.Forte@Sun.COM 		ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
25987836SJohn.Forte@Sun.COM 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
25997836SJohn.Forte@Sun.COM 		    KM_SLEEP);
26007836SJohn.Forte@Sun.COM 		ct->ct_req_size = ct->ct_req_alloc_size = 52;
26017836SJohn.Forte@Sun.COM 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
26027836SJohn.Forte@Sun.COM 		    KM_SLEEP);
26037836SJohn.Forte@Sun.COM 
26047836SJohn.Forte@Sun.COM 		/*
26057836SJohn.Forte@Sun.COM 		 * Port Identifier
26067836SJohn.Forte@Sun.COM 		 */
26077836SJohn.Forte@Sun.COM 		p[17] = (iport->iport_link_info.portid >> 16) & 0xFF;
26087836SJohn.Forte@Sun.COM 		p[18] = (iport->iport_link_info.portid >>  8) & 0xFF;
26097836SJohn.Forte@Sun.COM 		p[19] = (iport->iport_link_info.portid >>  0) & 0xFF;
26107836SJohn.Forte@Sun.COM 
26117836SJohn.Forte@Sun.COM 		/*
26127836SJohn.Forte@Sun.COM 		 * FC-4 Protocol Types
26137836SJohn.Forte@Sun.COM 		 */
26147836SJohn.Forte@Sun.COM 		*(p + 22) = 0x1;	/* 0x100 */
26157836SJohn.Forte@Sun.COM 		break;
26167836SJohn.Forte@Sun.COM 
26177836SJohn.Forte@Sun.COM 	case NS_RSPN_ID:
26187836SJohn.Forte@Sun.COM 		/*
26197836SJohn.Forte@Sun.COM 		 * If we get here, port->port_sym_port_name is always not NULL.
26207836SJohn.Forte@Sun.COM 		 */
26217836SJohn.Forte@Sun.COM 		ASSERT(port->port_sym_port_name);
26227836SJohn.Forte@Sun.COM 		namelen = strlen(port->port_sym_port_name);
26237836SJohn.Forte@Sun.COM 		ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
26247836SJohn.Forte@Sun.COM 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
26257836SJohn.Forte@Sun.COM 		    KM_SLEEP);
26267836SJohn.Forte@Sun.COM 		ct->ct_req_size = ct->ct_req_alloc_size =
26279578SSam.Cramer@Sun.COM 		    (21 + namelen + 3) & ~3;
26287836SJohn.Forte@Sun.COM 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
26297836SJohn.Forte@Sun.COM 		    KM_SLEEP);
26307836SJohn.Forte@Sun.COM 
26317836SJohn.Forte@Sun.COM 		/*
26327836SJohn.Forte@Sun.COM 		 * Port Identifier
26337836SJohn.Forte@Sun.COM 		 */
26347836SJohn.Forte@Sun.COM 		p[17] = (iport->iport_link_info.portid >> 16) & 0xFF;
26357836SJohn.Forte@Sun.COM 		p[18] = (iport->iport_link_info.portid >>  8) & 0xFF;
26367836SJohn.Forte@Sun.COM 		p[19] = (iport->iport_link_info.portid >>  0) & 0xFF;
26377836SJohn.Forte@Sun.COM 
26387836SJohn.Forte@Sun.COM 		/*
26397836SJohn.Forte@Sun.COM 		 * String length
26407836SJohn.Forte@Sun.COM 		 */
26417836SJohn.Forte@Sun.COM 		p[20] = namelen;
26427836SJohn.Forte@Sun.COM 
26437836SJohn.Forte@Sun.COM 		/*
26447836SJohn.Forte@Sun.COM 		 * Symbolic port name
26457836SJohn.Forte@Sun.COM 		 */
26467836SJohn.Forte@Sun.COM 		bcopy(port->port_sym_port_name, p + 21, ct->ct_req_size - 21);
26477836SJohn.Forte@Sun.COM 		break;
26487836SJohn.Forte@Sun.COM 
26497836SJohn.Forte@Sun.COM 	case NS_RSNN_NN:
26507836SJohn.Forte@Sun.COM 		namelen = port->port_sym_node_name == NULL ?
26517836SJohn.Forte@Sun.COM 		    strlen(utsname.nodename) :
26527836SJohn.Forte@Sun.COM 		    strlen(port->port_sym_node_name);
26537836SJohn.Forte@Sun.COM 		nname = port->port_sym_node_name == NULL ?
26547836SJohn.Forte@Sun.COM 		    utsname.nodename : port->port_sym_node_name;
26557836SJohn.Forte@Sun.COM 
26567836SJohn.Forte@Sun.COM 		ct->ct_resp_alloc_size = ct->ct_resp_size = 16;
26577836SJohn.Forte@Sun.COM 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
26587836SJohn.Forte@Sun.COM 		    KM_SLEEP);
26597836SJohn.Forte@Sun.COM 		ct->ct_req_size = ct->ct_req_alloc_size =
26607836SJohn.Forte@Sun.COM 		    (25 + namelen + 3) & ~3;
26617836SJohn.Forte@Sun.COM 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
26627836SJohn.Forte@Sun.COM 		    KM_SLEEP);
26637836SJohn.Forte@Sun.COM 
26647836SJohn.Forte@Sun.COM 		/*
26657836SJohn.Forte@Sun.COM 		 * Node name
26667836SJohn.Forte@Sun.COM 		 */
26677836SJohn.Forte@Sun.COM 		bcopy(port->port_nwwn, p + 16, 8);
26687836SJohn.Forte@Sun.COM 
26697836SJohn.Forte@Sun.COM 		/*
26707836SJohn.Forte@Sun.COM 		 * String length
26717836SJohn.Forte@Sun.COM 		 */
26727836SJohn.Forte@Sun.COM 		p[24] = namelen;
26737836SJohn.Forte@Sun.COM 
26747836SJohn.Forte@Sun.COM 		/*
26757836SJohn.Forte@Sun.COM 		 * Symbolic node name
26767836SJohn.Forte@Sun.COM 		 */
26777836SJohn.Forte@Sun.COM 		bcopy(nname, p + 25, ct->ct_req_size - 25);
26787836SJohn.Forte@Sun.COM 		break;
26797836SJohn.Forte@Sun.COM 
26807836SJohn.Forte@Sun.COM 	case NS_GSPN_ID:
26817836SJohn.Forte@Sun.COM 		ct->ct_resp_alloc_size = ct->ct_resp_size = 272;
26827836SJohn.Forte@Sun.COM 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
26837836SJohn.Forte@Sun.COM 		    KM_SLEEP);
26847836SJohn.Forte@Sun.COM 		ct->ct_req_size = ct->ct_req_alloc_size = 20;
26857836SJohn.Forte@Sun.COM 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
26867836SJohn.Forte@Sun.COM 		    KM_SLEEP);
26877836SJohn.Forte@Sun.COM 		/*
26887836SJohn.Forte@Sun.COM 		 * Port Identifier
26897836SJohn.Forte@Sun.COM 		 */
26907836SJohn.Forte@Sun.COM 		p[17] = (query_rp->rp_id >> 16) & 0xFF;
26917836SJohn.Forte@Sun.COM 		p[18] = (query_rp->rp_id >>  8) & 0xFF;
26927836SJohn.Forte@Sun.COM 		p[19] = (query_rp->rp_id >>  0) & 0xFF;
26937836SJohn.Forte@Sun.COM 		break;
26947836SJohn.Forte@Sun.COM 
26957836SJohn.Forte@Sun.COM 	case NS_GCS_ID:
26967836SJohn.Forte@Sun.COM 		ct->ct_resp_alloc_size = ct->ct_resp_size = 20;
26977836SJohn.Forte@Sun.COM 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
26987836SJohn.Forte@Sun.COM 		    KM_SLEEP);
26997836SJohn.Forte@Sun.COM 		ct->ct_req_size = ct->ct_req_alloc_size = 20;
27007836SJohn.Forte@Sun.COM 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
27017836SJohn.Forte@Sun.COM 		    KM_SLEEP);
27027836SJohn.Forte@Sun.COM 		/*
27037836SJohn.Forte@Sun.COM 		 * Port Identifier
27047836SJohn.Forte@Sun.COM 		 */
27057836SJohn.Forte@Sun.COM 		p[17] = (query_rp->rp_id >> 16) & 0xFF;
27067836SJohn.Forte@Sun.COM 		p[18] = (query_rp->rp_id >>  8) & 0xFF;
27077836SJohn.Forte@Sun.COM 		p[19] = (query_rp->rp_id >>  0) & 0xFF;
27087836SJohn.Forte@Sun.COM 		break;
27097836SJohn.Forte@Sun.COM 
27107836SJohn.Forte@Sun.COM 	case NS_GFT_ID:
27117836SJohn.Forte@Sun.COM 		ct->ct_resp_alloc_size = ct->ct_resp_size = 48;
27127836SJohn.Forte@Sun.COM 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
27137836SJohn.Forte@Sun.COM 		    KM_SLEEP);
27147836SJohn.Forte@Sun.COM 		ct->ct_req_size = ct->ct_req_alloc_size = 20;
27157836SJohn.Forte@Sun.COM 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
27167836SJohn.Forte@Sun.COM 		    KM_SLEEP);
27177836SJohn.Forte@Sun.COM 		/*
27187836SJohn.Forte@Sun.COM 		 * Port Identifier
27197836SJohn.Forte@Sun.COM 		 */
27207836SJohn.Forte@Sun.COM 		p[17] = (query_rp->rp_id >> 16) & 0xFF;
27217836SJohn.Forte@Sun.COM 		p[18] = (query_rp->rp_id >>  8) & 0xFF;
27227836SJohn.Forte@Sun.COM 		p[19] = (query_rp->rp_id >>  0) & 0xFF;
27237836SJohn.Forte@Sun.COM 		break;
27247836SJohn.Forte@Sun.COM 
27257836SJohn.Forte@Sun.COM 	case NS_GID_PN:
27267836SJohn.Forte@Sun.COM 		ct->ct_resp_alloc_size = ct->ct_resp_size = 20;
27277836SJohn.Forte@Sun.COM 		ct->ct_resp_payload = (uint8_t *)kmem_zalloc(ct->ct_resp_size,
27287836SJohn.Forte@Sun.COM 		    KM_SLEEP);
27297836SJohn.Forte@Sun.COM 
27307836SJohn.Forte@Sun.COM 		ct->ct_req_size = ct->ct_req_alloc_size = 24;
27317836SJohn.Forte@Sun.COM 		p = ct->ct_req_payload = (uint8_t *)kmem_zalloc(ct->ct_req_size,
27327836SJohn.Forte@Sun.COM 		    KM_SLEEP);
27337836SJohn.Forte@Sun.COM 
27347836SJohn.Forte@Sun.COM 		bcopy(query_rp->rp_pwwn, p + 16, 8);
27357836SJohn.Forte@Sun.COM 		break;
27367836SJohn.Forte@Sun.COM 
27377836SJohn.Forte@Sun.COM 	default:
27387836SJohn.Forte@Sun.COM 		/* CONSTCOND */
27397836SJohn.Forte@Sun.COM 		ASSERT(0);
27407836SJohn.Forte@Sun.COM 	}
27417836SJohn.Forte@Sun.COM 
27427836SJohn.Forte@Sun.COM 	FCT_FILL_CTIU_PREAMPLE(p, ctop);
27437836SJohn.Forte@Sun.COM 	return (cmd);
27447836SJohn.Forte@Sun.COM }
27457836SJohn.Forte@Sun.COM 
27467836SJohn.Forte@Sun.COM /*
27477836SJohn.Forte@Sun.COM  * Cmd can only be solicited CT/ELS. They will be dispatched to the discovery
27487836SJohn.Forte@Sun.COM  * queue eventually too.
27497836SJohn.Forte@Sun.COM  * We queue solicited cmds here to track solicited cmds and to take full use
27507836SJohn.Forte@Sun.COM  * of single thread mechanism.
27517836SJohn.Forte@Sun.COM  * But in current implmentation, we don't use  this mechanism on SOL_CT, PLOGI.
27527836SJohn.Forte@Sun.COM  * To avoid to interrupt current flow, ICMD_IN_SOLCMD_QUEUE is used here.
27537836SJohn.Forte@Sun.COM  */
27547836SJohn.Forte@Sun.COM void
fct_post_to_solcmd_queue(fct_local_port_t * port,fct_cmd_t * cmd)27557836SJohn.Forte@Sun.COM fct_post_to_solcmd_queue(fct_local_port_t *port, fct_cmd_t *cmd)
27567836SJohn.Forte@Sun.COM {
27577836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport	= (fct_i_local_port_t *)
27587836SJohn.Forte@Sun.COM 	    port->port_fct_private;
27597836SJohn.Forte@Sun.COM 	fct_i_cmd_t *icmd		= (fct_i_cmd_t *)cmd->cmd_fct_private;
27607836SJohn.Forte@Sun.COM 
27617836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
27627836SJohn.Forte@Sun.COM 	icmd->icmd_solcmd_next = iport->iport_solcmd_queue;
27637836SJohn.Forte@Sun.COM 	iport->iport_solcmd_queue = icmd;
27647836SJohn.Forte@Sun.COM 	atomic_or_32(&icmd->icmd_flags, ICMD_IN_SOLCMD_QUEUE | ICMD_SOLCMD_NEW);
27657836SJohn.Forte@Sun.COM 	if (IS_WORKER_SLEEPING(iport)) {
27667836SJohn.Forte@Sun.COM 		cv_signal(&iport->iport_worker_cv);
27677836SJohn.Forte@Sun.COM 	}
27687836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
27697836SJohn.Forte@Sun.COM }
27707836SJohn.Forte@Sun.COM 
27717836SJohn.Forte@Sun.COM /* ARGSUSED */
27727836SJohn.Forte@Sun.COM void
fct_event_handler(stmf_local_port_t * lport,int eventid,void * arg,uint32_t flags)27737836SJohn.Forte@Sun.COM fct_event_handler(stmf_local_port_t *lport, int eventid, void *arg,
27747836SJohn.Forte@Sun.COM     uint32_t flags)
27757836SJohn.Forte@Sun.COM {
27767836SJohn.Forte@Sun.COM 	fct_local_port_t	*port  = (fct_local_port_t *)
27777836SJohn.Forte@Sun.COM 	    lport->lport_port_private;
27787836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
27797836SJohn.Forte@Sun.COM 	    port->port_fct_private;
27807836SJohn.Forte@Sun.COM 	stmf_scsi_session_t	*ss;
27817836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp;
27827836SJohn.Forte@Sun.COM 
27837836SJohn.Forte@Sun.COM 	switch (eventid) {
27847836SJohn.Forte@Sun.COM 	case LPORT_EVENT_INITIAL_LUN_MAPPED:
27857836SJohn.Forte@Sun.COM 		ss = (stmf_scsi_session_t *)arg;
27867836SJohn.Forte@Sun.COM 		irp = (fct_i_remote_port_t *)ss->ss_port_private;
27877836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias,
27887836SJohn.Forte@Sun.COM 		    "Initial LUN mapped to session ss-%p, irp-%p", ss, irp);
27897836SJohn.Forte@Sun.COM 		break;
27907836SJohn.Forte@Sun.COM 
27917836SJohn.Forte@Sun.COM 	default:
27927836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias,
27937836SJohn.Forte@Sun.COM 		    "Unknown event received, %d", eventid);
27947836SJohn.Forte@Sun.COM 	}
27957836SJohn.Forte@Sun.COM }
27967836SJohn.Forte@Sun.COM 
27977836SJohn.Forte@Sun.COM void
fct_send_cmd_done(fct_cmd_t * cmd,fct_status_t s,uint32_t ioflags)27987836SJohn.Forte@Sun.COM fct_send_cmd_done(fct_cmd_t *cmd, fct_status_t s, uint32_t ioflags)
27997836SJohn.Forte@Sun.COM {
28007836SJohn.Forte@Sun.COM 	/* XXX For now just call send_resp_done() */
28017836SJohn.Forte@Sun.COM 	fct_send_response_done(cmd, s, ioflags);
28027836SJohn.Forte@Sun.COM }
28037836SJohn.Forte@Sun.COM 
28047836SJohn.Forte@Sun.COM void
fct_cmd_fca_aborted(fct_cmd_t * cmd,fct_status_t s,uint32_t ioflags)28057836SJohn.Forte@Sun.COM fct_cmd_fca_aborted(fct_cmd_t *cmd, fct_status_t s, uint32_t ioflags)
28067836SJohn.Forte@Sun.COM {
28077836SJohn.Forte@Sun.COM 	fct_i_cmd_t		*icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2808*12571SViswanathan.Kannappan@Sun.COM 	char			info[FCT_INFO_LEN];
28097836SJohn.Forte@Sun.COM 	unsigned long long	st;
28107836SJohn.Forte@Sun.COM 
28117836SJohn.Forte@Sun.COM 	st = s;	/* To make gcc happy */
28127836SJohn.Forte@Sun.COM 	ASSERT(icmd->icmd_flags & ICMD_BEING_ABORTED);
28137836SJohn.Forte@Sun.COM 	if ((((s != FCT_ABORT_SUCCESS) && (s != FCT_NOT_FOUND))) ||
28147836SJohn.Forte@Sun.COM 	    ((ioflags & FCT_IOF_FCA_DONE) == 0)) {
2815*12571SViswanathan.Kannappan@Sun.COM 		(void) snprintf(info, sizeof (info),
2816*12571SViswanathan.Kannappan@Sun.COM 		    "fct_cmd_fca_aborted: cmd-%p, "
28177836SJohn.Forte@Sun.COM 		    "s-%llx, iofalgs-%x", (void *)cmd, st, ioflags);
28187836SJohn.Forte@Sun.COM 		(void) fct_port_shutdown(cmd->cmd_port,
28197836SJohn.Forte@Sun.COM 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
28207836SJohn.Forte@Sun.COM 		return;
28217836SJohn.Forte@Sun.COM 	}
28227836SJohn.Forte@Sun.COM 
28237836SJohn.Forte@Sun.COM 	atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
28247836SJohn.Forte@Sun.COM 	/* For non FCP Rest of the work is done by the terminator */
28257836SJohn.Forte@Sun.COM 	/* For FCP stuff just call stmf */
28267836SJohn.Forte@Sun.COM 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
28277836SJohn.Forte@Sun.COM 		stmf_task_lport_aborted((scsi_task_t *)cmd->cmd_specific,
28287836SJohn.Forte@Sun.COM 		    s, STMF_IOF_LPORT_DONE);
28297836SJohn.Forte@Sun.COM 	}
28307836SJohn.Forte@Sun.COM }
28317836SJohn.Forte@Sun.COM 
28327836SJohn.Forte@Sun.COM /*
28337836SJohn.Forte@Sun.COM  * FCA drivers will use it, when they want to abort some FC transactions
28347836SJohn.Forte@Sun.COM  * due to lack of resource.
28357836SJohn.Forte@Sun.COM  */
28367836SJohn.Forte@Sun.COM uint16_t
fct_get_rp_handle(fct_local_port_t * port,uint32_t rportid)28377836SJohn.Forte@Sun.COM fct_get_rp_handle(fct_local_port_t *port, uint32_t rportid)
28387836SJohn.Forte@Sun.COM {
28397836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp;
28407836SJohn.Forte@Sun.COM 
28417836SJohn.Forte@Sun.COM 	irp = fct_portid_to_portptr(
28427836SJohn.Forte@Sun.COM 	    (fct_i_local_port_t *)(port->port_fct_private), rportid);
28437836SJohn.Forte@Sun.COM 	if (irp == NULL) {
28447836SJohn.Forte@Sun.COM 		return (0xFFFF);
28457836SJohn.Forte@Sun.COM 	} else {
28467836SJohn.Forte@Sun.COM 		return (irp->irp_rp->rp_handle);
28477836SJohn.Forte@Sun.COM 	}
28487836SJohn.Forte@Sun.COM }
28497836SJohn.Forte@Sun.COM 
28507836SJohn.Forte@Sun.COM fct_cmd_t *
fct_handle_to_cmd(fct_local_port_t * port,uint32_t fct_handle)28517836SJohn.Forte@Sun.COM fct_handle_to_cmd(fct_local_port_t *port, uint32_t fct_handle)
28527836SJohn.Forte@Sun.COM {
28537836SJohn.Forte@Sun.COM 	fct_cmd_slot_t *slot;
28547836SJohn.Forte@Sun.COM 	uint16_t ndx;
28557836SJohn.Forte@Sun.COM 
28567836SJohn.Forte@Sun.COM 	if (!CMD_HANDLE_VALID(fct_handle))
28577836SJohn.Forte@Sun.COM 		return (NULL);
28587836SJohn.Forte@Sun.COM 	if ((ndx = CMD_HANDLE_SLOT_INDEX(fct_handle)) >= port->port_max_xchges)
28597836SJohn.Forte@Sun.COM 		return (NULL);
28607836SJohn.Forte@Sun.COM 
28617836SJohn.Forte@Sun.COM 	slot = &((fct_i_local_port_t *)port->port_fct_private)->iport_cmd_slots[
28629578SSam.Cramer@Sun.COM 	    ndx];
28637836SJohn.Forte@Sun.COM 
28647836SJohn.Forte@Sun.COM 	if ((slot->slot_uniq_cntr | 0x80) != (fct_handle >> 24))
28657836SJohn.Forte@Sun.COM 		return (NULL);
28667836SJohn.Forte@Sun.COM 	return (slot->slot_cmd->icmd_cmd);
28677836SJohn.Forte@Sun.COM }
28687836SJohn.Forte@Sun.COM 
28697836SJohn.Forte@Sun.COM void
fct_queue_scsi_task_for_termination(fct_cmd_t * cmd,fct_status_t s)28707836SJohn.Forte@Sun.COM fct_queue_scsi_task_for_termination(fct_cmd_t *cmd, fct_status_t s)
28717836SJohn.Forte@Sun.COM {
28727836SJohn.Forte@Sun.COM 	fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
28737836SJohn.Forte@Sun.COM 
28747836SJohn.Forte@Sun.COM 	uint32_t old, new;
28757836SJohn.Forte@Sun.COM 
28767836SJohn.Forte@Sun.COM 	do {
28777836SJohn.Forte@Sun.COM 		old = icmd->icmd_flags;
28787836SJohn.Forte@Sun.COM 		if ((old & (ICMD_BEING_ABORTED | ICMD_KNOWN_TO_FCA)) !=
28797836SJohn.Forte@Sun.COM 		    ICMD_KNOWN_TO_FCA)
28807836SJohn.Forte@Sun.COM 			return;
28817836SJohn.Forte@Sun.COM 		new = old | ICMD_BEING_ABORTED;
28827836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
28837836SJohn.Forte@Sun.COM 	stmf_abort(STMF_QUEUE_TASK_ABORT, (scsi_task_t *)cmd->cmd_specific,
28849578SSam.Cramer@Sun.COM 	    s, NULL);
28857836SJohn.Forte@Sun.COM }
28867836SJohn.Forte@Sun.COM 
28877836SJohn.Forte@Sun.COM void
fct_fill_abts_acc(fct_cmd_t * cmd)28887836SJohn.Forte@Sun.COM fct_fill_abts_acc(fct_cmd_t *cmd)
28897836SJohn.Forte@Sun.COM {
28907836SJohn.Forte@Sun.COM 	fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific;
28917836SJohn.Forte@Sun.COM 	uint8_t *p;
28927836SJohn.Forte@Sun.COM 
28937836SJohn.Forte@Sun.COM 	abts->abts_resp_rctl = BLS_OP_BA_ACC;
28947836SJohn.Forte@Sun.COM 	p = abts->abts_resp_payload;
28957836SJohn.Forte@Sun.COM 	bzero(p, 12);
28967836SJohn.Forte@Sun.COM 	*((uint16_t *)(p+4)) = BE_16(cmd->cmd_oxid);
28977836SJohn.Forte@Sun.COM 	*((uint16_t *)(p+6)) = BE_16(cmd->cmd_rxid);
28987836SJohn.Forte@Sun.COM 	p[10] = p[11] = 0xff;
28997836SJohn.Forte@Sun.COM }
29007836SJohn.Forte@Sun.COM 
29017836SJohn.Forte@Sun.COM void
fct_handle_rcvd_abts(fct_cmd_t * cmd)29027836SJohn.Forte@Sun.COM fct_handle_rcvd_abts(fct_cmd_t *cmd)
29037836SJohn.Forte@Sun.COM {
2904*12571SViswanathan.Kannappan@Sun.COM 	char			info[FCT_INFO_LEN];
29057836SJohn.Forte@Sun.COM 	fct_local_port_t	*port = cmd->cmd_port;
29067836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport =
29077836SJohn.Forte@Sun.COM 	    (fct_i_local_port_t *)port->port_fct_private;
29087836SJohn.Forte@Sun.COM 	fct_i_cmd_t		*icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
29097836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp;
29107836SJohn.Forte@Sun.COM 	fct_cmd_t		*c = NULL;
29117836SJohn.Forte@Sun.COM 	fct_i_cmd_t		*ic = NULL;
29127836SJohn.Forte@Sun.COM 	int			found = 0;
29137836SJohn.Forte@Sun.COM 	int			i;
29147836SJohn.Forte@Sun.COM 
29157836SJohn.Forte@Sun.COM 	icmd->icmd_start_time = ddi_get_lbolt();
29167836SJohn.Forte@Sun.COM 	icmd->icmd_flags |= ICMD_KNOWN_TO_FCA;
29177836SJohn.Forte@Sun.COM 
29187836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_WRITER);
29197836SJohn.Forte@Sun.COM 	/* Make sure local port is sane */
29207836SJohn.Forte@Sun.COM 	if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
29217836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
29227836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "ABTS not posted becasue"
29237836SJohn.Forte@Sun.COM 		    "port state was %x", iport->iport_link_state);
29247836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE);
29257836SJohn.Forte@Sun.COM 		return;
29267836SJohn.Forte@Sun.COM 	}
29277836SJohn.Forte@Sun.COM 
29287836SJohn.Forte@Sun.COM 	if (cmd->cmd_rp_handle == FCT_HANDLE_NONE)
29297836SJohn.Forte@Sun.COM 		irp = fct_portid_to_portptr(iport, cmd->cmd_rportid);
29307836SJohn.Forte@Sun.COM 	else if (cmd->cmd_rp_handle < port->port_max_logins)
29317836SJohn.Forte@Sun.COM 		irp = iport->iport_rp_slots[cmd->cmd_rp_handle];
29327836SJohn.Forte@Sun.COM 	else
29337836SJohn.Forte@Sun.COM 		irp = NULL;
29347836SJohn.Forte@Sun.COM 	if (irp == NULL) {
29357836SJohn.Forte@Sun.COM 		/* XXX Throw a logout to the initiator */
29367836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
29377836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "ABTS received from"
29387836SJohn.Forte@Sun.COM 		    " %x without a session", cmd->cmd_rportid);
29397836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN);
29407836SJohn.Forte@Sun.COM 		return;
29417836SJohn.Forte@Sun.COM 	}
294210088SAllan.Ou@Sun.COM 
294310088SAllan.Ou@Sun.COM 	DTRACE_FC_3(abts__receive,
294410088SAllan.Ou@Sun.COM 	    fct_cmd_t, cmd,
294510088SAllan.Ou@Sun.COM 	    fct_local_port_t, port,
294610088SAllan.Ou@Sun.COM 	    fct_i_remote_port_t, irp);
294710088SAllan.Ou@Sun.COM 
29487836SJohn.Forte@Sun.COM 	cmd->cmd_rp = irp->irp_rp;
29497836SJohn.Forte@Sun.COM 
29507836SJohn.Forte@Sun.COM 	/*
29517836SJohn.Forte@Sun.COM 	 * No need to allocate an xchg resource. ABTSes use the same
29527836SJohn.Forte@Sun.COM 	 * xchg resource as the cmd they are aborting.
29537836SJohn.Forte@Sun.COM 	 */
29547836SJohn.Forte@Sun.COM 	rw_enter(&irp->irp_lock, RW_WRITER);
29557836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
29567836SJohn.Forte@Sun.COM 	/* Lets find the command first */
29577836SJohn.Forte@Sun.COM 	for (i = 0; i < port->port_max_xchges; i++) {
29587836SJohn.Forte@Sun.COM 		if ((ic = iport->iport_cmd_slots[i].slot_cmd) == NULL)
29597836SJohn.Forte@Sun.COM 			continue;
29607836SJohn.Forte@Sun.COM 		if ((ic->icmd_flags & ICMD_KNOWN_TO_FCA) == 0)
29617836SJohn.Forte@Sun.COM 			continue;
29627836SJohn.Forte@Sun.COM 		c = ic->icmd_cmd;
29637836SJohn.Forte@Sun.COM 		if (!CMD_HANDLE_VALID(c->cmd_handle))
29647836SJohn.Forte@Sun.COM 			continue;
29657836SJohn.Forte@Sun.COM 		if ((c->cmd_rportid != cmd->cmd_rportid) ||
29667836SJohn.Forte@Sun.COM 		    (c->cmd_oxid != cmd->cmd_oxid))
29677836SJohn.Forte@Sun.COM 			continue;
29687836SJohn.Forte@Sun.COM 		/* Found the command */
29697836SJohn.Forte@Sun.COM 		found = 1;
29707836SJohn.Forte@Sun.COM 		break;
29717836SJohn.Forte@Sun.COM 	}
29727836SJohn.Forte@Sun.COM 	if (!found) {
29737836SJohn.Forte@Sun.COM 		mutex_exit(&iport->iport_worker_lock);
29747836SJohn.Forte@Sun.COM 		rw_exit(&irp->irp_lock);
29757836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
29767836SJohn.Forte@Sun.COM 		/* Dont even bother queueing it. Just respond */
29777836SJohn.Forte@Sun.COM 		fct_fill_abts_acc(cmd);
29787836SJohn.Forte@Sun.COM 		if (port->port_send_cmd_response(cmd,
29797836SJohn.Forte@Sun.COM 		    FCT_IOF_FORCE_FCA_DONE) != FCT_SUCCESS) {
29807836SJohn.Forte@Sun.COM 			/*
29817836SJohn.Forte@Sun.COM 			 * XXX Throw HBA fatal error event
29827836SJohn.Forte@Sun.COM 			 * Later shutdown svc will terminate the ABTS in the end
29837836SJohn.Forte@Sun.COM 			 */
2984*12571SViswanathan.Kannappan@Sun.COM 			(void) snprintf(info, sizeof (info),
29857836SJohn.Forte@Sun.COM 			    "fct_handle_rcvd_abts: iport-%p, "
29867836SJohn.Forte@Sun.COM 			    "ABTS_ACC port_send_cmd_response failed",
29877836SJohn.Forte@Sun.COM 			    (void *)iport);
29887836SJohn.Forte@Sun.COM 			(void) fct_port_shutdown(iport->iport_port,
29897836SJohn.Forte@Sun.COM 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
29907836SJohn.Forte@Sun.COM 		} else {
29917836SJohn.Forte@Sun.COM 			fct_cmd_free(cmd);
29927836SJohn.Forte@Sun.COM 		}
29937836SJohn.Forte@Sun.COM 		return;
29947836SJohn.Forte@Sun.COM 	}
29957836SJohn.Forte@Sun.COM 
29967836SJohn.Forte@Sun.COM 	/* Check if this an abts retry */
29977836SJohn.Forte@Sun.COM 	if (c->cmd_link && (ic->icmd_flags & ICMD_ABTS_RECEIVED)) {
29987836SJohn.Forte@Sun.COM 		/* Kill this abts. */
29997836SJohn.Forte@Sun.COM 		fct_q_for_termination_lock_held(iport, icmd, FCT_ABORTED);
30007836SJohn.Forte@Sun.COM 		if (IS_WORKER_SLEEPING(iport))
30017836SJohn.Forte@Sun.COM 			cv_signal(&iport->iport_worker_cv);
30027836SJohn.Forte@Sun.COM 		mutex_exit(&iport->iport_worker_lock);
30037836SJohn.Forte@Sun.COM 		rw_exit(&irp->irp_lock);
30047836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
30057836SJohn.Forte@Sun.COM 		return;
30067836SJohn.Forte@Sun.COM 	}
30077836SJohn.Forte@Sun.COM 	c->cmd_link = cmd;
30087836SJohn.Forte@Sun.COM 	atomic_or_32(&ic->icmd_flags, ICMD_ABTS_RECEIVED);
30097836SJohn.Forte@Sun.COM 	cmd->cmd_link = c;
30107836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
30117836SJohn.Forte@Sun.COM 	rw_exit(&irp->irp_lock);
30127836SJohn.Forte@Sun.COM 	fct_queue_cmd_for_termination(c, FCT_ABTS_RECEIVED);
30137836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
30147836SJohn.Forte@Sun.COM }
30157836SJohn.Forte@Sun.COM 
30167836SJohn.Forte@Sun.COM void
fct_queue_cmd_for_termination(fct_cmd_t * cmd,fct_status_t s)30177836SJohn.Forte@Sun.COM fct_queue_cmd_for_termination(fct_cmd_t *cmd, fct_status_t s)
30187836SJohn.Forte@Sun.COM {
30197836SJohn.Forte@Sun.COM 	fct_local_port_t *port = cmd->cmd_port;
30207836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport = (fct_i_local_port_t *)
30219578SSam.Cramer@Sun.COM 	    port->port_fct_private;
30227836SJohn.Forte@Sun.COM 	fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
30237836SJohn.Forte@Sun.COM 
30247836SJohn.Forte@Sun.COM 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
30257836SJohn.Forte@Sun.COM 		fct_queue_scsi_task_for_termination(cmd, s);
30267836SJohn.Forte@Sun.COM 		return;
30277836SJohn.Forte@Sun.COM 	}
30287836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
30297836SJohn.Forte@Sun.COM 	fct_q_for_termination_lock_held(iport, icmd, s);
30307836SJohn.Forte@Sun.COM 	if (IS_WORKER_SLEEPING(iport))
30317836SJohn.Forte@Sun.COM 		cv_signal(&iport->iport_worker_cv);
30327836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
30337836SJohn.Forte@Sun.COM }
30347836SJohn.Forte@Sun.COM 
30357836SJohn.Forte@Sun.COM /*
30367836SJohn.Forte@Sun.COM  * This function will not be called for SCSI CMDS
30377836SJohn.Forte@Sun.COM  */
30387836SJohn.Forte@Sun.COM void
fct_q_for_termination_lock_held(fct_i_local_port_t * iport,fct_i_cmd_t * icmd,fct_status_t s)30397836SJohn.Forte@Sun.COM fct_q_for_termination_lock_held(fct_i_local_port_t *iport, fct_i_cmd_t *icmd,
30407836SJohn.Forte@Sun.COM 		fct_status_t s)
30417836SJohn.Forte@Sun.COM {
30427836SJohn.Forte@Sun.COM 	uint32_t old, new;
30437836SJohn.Forte@Sun.COM 	fct_i_cmd_t **ppicmd;
30447836SJohn.Forte@Sun.COM 
30457836SJohn.Forte@Sun.COM 	do {
30467836SJohn.Forte@Sun.COM 		old = icmd->icmd_flags;
30477836SJohn.Forte@Sun.COM 		if (old & ICMD_BEING_ABORTED)
30487836SJohn.Forte@Sun.COM 			return;
30497836SJohn.Forte@Sun.COM 		new = old | ICMD_BEING_ABORTED;
30507836SJohn.Forte@Sun.COM 	} while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
30517836SJohn.Forte@Sun.COM 
30527836SJohn.Forte@Sun.COM 	icmd->icmd_start_time = ddi_get_lbolt();
30537836SJohn.Forte@Sun.COM 	icmd->icmd_cmd->cmd_comp_status = s;
30547836SJohn.Forte@Sun.COM 
30557836SJohn.Forte@Sun.COM 	icmd->icmd_next = NULL;
30567836SJohn.Forte@Sun.COM 	for (ppicmd = &(iport->iport_abort_queue); *ppicmd != NULL;
30579578SSam.Cramer@Sun.COM 	    ppicmd = &((*ppicmd)->icmd_next))
30589578SSam.Cramer@Sun.COM 		;
30599591STim.Szeto@Sun.COM 
30607836SJohn.Forte@Sun.COM 	*ppicmd = icmd;
30617836SJohn.Forte@Sun.COM }
30627836SJohn.Forte@Sun.COM 
30637836SJohn.Forte@Sun.COM /*
30647836SJohn.Forte@Sun.COM  * For those cmds, for which we called fca_abort but it has not yet completed,
30657836SJohn.Forte@Sun.COM  * reset the FCA_ABORT_CALLED flag, so that abort can be called again.
30667836SJohn.Forte@Sun.COM  * This is done after a FCA offline. The reason is that after offline, the
30677836SJohn.Forte@Sun.COM  * firmware is not running so abort will never complete. But if we call it
30687836SJohn.Forte@Sun.COM  * again, the FCA will detect that it is not offline and it will
30697836SJohn.Forte@Sun.COM  * not call the firmware at all. Most likely it will abort in a synchronous
30707836SJohn.Forte@Sun.COM  * manner i.e. return FCT_ABORT_SUCCESS or FCT_NOT_FOUND.
30717836SJohn.Forte@Sun.COM  */
30727836SJohn.Forte@Sun.COM void
fct_reset_flag_abort_called(fct_i_local_port_t * iport)30737836SJohn.Forte@Sun.COM fct_reset_flag_abort_called(fct_i_local_port_t *iport)
30747836SJohn.Forte@Sun.COM {
30757836SJohn.Forte@Sun.COM 	fct_i_cmd_t *icmd;
30767836SJohn.Forte@Sun.COM 	uint32_t old, new;
30777836SJohn.Forte@Sun.COM 	int i, do_clear;
30787836SJohn.Forte@Sun.COM 
30797836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&iport->iport_worker_lock));
30807836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
30817836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_WRITER);
30827836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
30837836SJohn.Forte@Sun.COM 
30847836SJohn.Forte@Sun.COM 	for (i = 0; i < iport->iport_port->port_max_xchges; i++) {
30857836SJohn.Forte@Sun.COM 		if (iport->iport_cmd_slots[i].slot_cmd == NULL)
30867836SJohn.Forte@Sun.COM 			continue;
30877836SJohn.Forte@Sun.COM 
30887836SJohn.Forte@Sun.COM 		icmd = iport->iport_cmd_slots[i].slot_cmd;
30897836SJohn.Forte@Sun.COM 
30907836SJohn.Forte@Sun.COM 		do {
30917836SJohn.Forte@Sun.COM 			old = new = icmd->icmd_flags;
30927836SJohn.Forte@Sun.COM 			if ((old & (ICMD_KNOWN_TO_FCA |
30937836SJohn.Forte@Sun.COM 			    ICMD_FCA_ABORT_CALLED)) == (ICMD_KNOWN_TO_FCA |
30947836SJohn.Forte@Sun.COM 			    ICMD_FCA_ABORT_CALLED)) {
30957836SJohn.Forte@Sun.COM 				new &= ~ICMD_FCA_ABORT_CALLED;
30967836SJohn.Forte@Sun.COM 				do_clear = 1;
30977836SJohn.Forte@Sun.COM 			} else {
30987836SJohn.Forte@Sun.COM 				do_clear = 0;
30997836SJohn.Forte@Sun.COM 				break;
31007836SJohn.Forte@Sun.COM 			}
31017836SJohn.Forte@Sun.COM 		} while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
31027836SJohn.Forte@Sun.COM 		if (do_clear &&
31037836SJohn.Forte@Sun.COM 		    (icmd->icmd_cmd->cmd_type == FCT_CMD_FCP_XCHG)) {
31047836SJohn.Forte@Sun.COM 			stmf_abort(STMF_REQUEUE_TASK_ABORT_LPORT,
31057836SJohn.Forte@Sun.COM 			    icmd->icmd_cmd->cmd_specific, 0, NULL);
31067836SJohn.Forte@Sun.COM 		}
31077836SJohn.Forte@Sun.COM 	}
31087836SJohn.Forte@Sun.COM 
31097836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
31107836SJohn.Forte@Sun.COM }
31117836SJohn.Forte@Sun.COM 
31127836SJohn.Forte@Sun.COM /*
31137836SJohn.Forte@Sun.COM  * Modify the irp_deregister_timer such that the ports start deregistering
31147836SJohn.Forte@Sun.COM  * quickly.
31157836SJohn.Forte@Sun.COM  */
31167836SJohn.Forte@Sun.COM void
fct_irp_deregister_speedup(fct_i_local_port_t * iport)31177836SJohn.Forte@Sun.COM fct_irp_deregister_speedup(fct_i_local_port_t *iport)
31187836SJohn.Forte@Sun.COM {
31197836SJohn.Forte@Sun.COM 	fct_i_remote_port_t *irp;
31207836SJohn.Forte@Sun.COM 	int i;
31217836SJohn.Forte@Sun.COM 
31227836SJohn.Forte@Sun.COM 	if (!iport->iport_nrps)
31237836SJohn.Forte@Sun.COM 		return;
31247836SJohn.Forte@Sun.COM 
31257836SJohn.Forte@Sun.COM 	for (i = 0; i < rportid_table_size; i++) {
31267836SJohn.Forte@Sun.COM 		irp = iport->iport_rp_tb[i];
31277836SJohn.Forte@Sun.COM 		while (irp) {
31287836SJohn.Forte@Sun.COM 			irp->irp_deregister_timer = ddi_get_lbolt() - 1;
31297836SJohn.Forte@Sun.COM 			irp = irp->irp_next;
31307836SJohn.Forte@Sun.COM 		}
31317836SJohn.Forte@Sun.COM 	}
31327836SJohn.Forte@Sun.COM }
31337836SJohn.Forte@Sun.COM 
31347836SJohn.Forte@Sun.COM disc_action_t
fct_handle_port_offline(fct_i_local_port_t * iport)31357836SJohn.Forte@Sun.COM fct_handle_port_offline(fct_i_local_port_t *iport)
31367836SJohn.Forte@Sun.COM {
31377836SJohn.Forte@Sun.COM 	if (iport->iport_offline_prstate == FCT_OPR_START) {
31387836SJohn.Forte@Sun.COM 		fct_reset_flag_abort_called(iport);
31397836SJohn.Forte@Sun.COM 		iport->iport_offline_prstate = FCT_OPR_CMD_CLEANUP_WAIT;
31407836SJohn.Forte@Sun.COM 		/* fct_ctl has already submitted a link offline event */
31417836SJohn.Forte@Sun.COM 		return (DISC_ACTION_DELAY_RESCAN);
31427836SJohn.Forte@Sun.COM 	}
31437836SJohn.Forte@Sun.COM 	if (iport->iport_offline_prstate == FCT_OPR_CMD_CLEANUP_WAIT) {
31447836SJohn.Forte@Sun.COM 		if (iport->iport_link_state != PORT_STATE_LINK_DOWN)
31457836SJohn.Forte@Sun.COM 			return (DISC_ACTION_DELAY_RESCAN);
31467836SJohn.Forte@Sun.COM 		/*
31477836SJohn.Forte@Sun.COM 		 * All I/Os have been killed at this time. Lets speedup
31487836SJohn.Forte@Sun.COM 		 * the port deregister process.
31497836SJohn.Forte@Sun.COM 		 */
31507836SJohn.Forte@Sun.COM 		mutex_exit(&iport->iport_worker_lock);
31517836SJohn.Forte@Sun.COM 		rw_enter(&iport->iport_lock, RW_WRITER);
31527836SJohn.Forte@Sun.COM 		fct_irp_deregister_speedup(iport);
31537836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
31547836SJohn.Forte@Sun.COM 		mutex_enter(&iport->iport_worker_lock);
31557836SJohn.Forte@Sun.COM 		iport->iport_offline_prstate = FCT_OPR_INT_CLEANUP_WAIT;
31567836SJohn.Forte@Sun.COM 		return (DISC_ACTION_RESCAN);
31577836SJohn.Forte@Sun.COM 	}
31587836SJohn.Forte@Sun.COM 	if (iport->iport_offline_prstate == FCT_OPR_INT_CLEANUP_WAIT) {
31597836SJohn.Forte@Sun.COM 		stmf_change_status_t st;
31607836SJohn.Forte@Sun.COM 
31617836SJohn.Forte@Sun.COM 		if (iport->iport_solcmd_queue) {
31627836SJohn.Forte@Sun.COM 			return (DISC_ACTION_DELAY_RESCAN);
31637836SJohn.Forte@Sun.COM 		}
31647836SJohn.Forte@Sun.COM 
31657836SJohn.Forte@Sun.COM 		if (iport->iport_nrps) {
31667836SJohn.Forte@Sun.COM 			/*
31677836SJohn.Forte@Sun.COM 			 * A port logout may have gone when implicit logo all
31687836SJohn.Forte@Sun.COM 			 * was retried. So do the port speedup again here.
31697836SJohn.Forte@Sun.COM 			 */
31707836SJohn.Forte@Sun.COM 			mutex_exit(&iport->iport_worker_lock);
31717836SJohn.Forte@Sun.COM 			rw_enter(&iport->iport_lock, RW_WRITER);
31727836SJohn.Forte@Sun.COM 			fct_irp_deregister_speedup(iport);
31737836SJohn.Forte@Sun.COM 			rw_exit(&iport->iport_lock);
31747836SJohn.Forte@Sun.COM 			mutex_enter(&iport->iport_worker_lock);
31757836SJohn.Forte@Sun.COM 			return (DISC_ACTION_DELAY_RESCAN);
31767836SJohn.Forte@Sun.COM 		}
31777836SJohn.Forte@Sun.COM 
31787836SJohn.Forte@Sun.COM 		if (iport->iport_event_head != NULL) {
31797836SJohn.Forte@Sun.COM 			return (DISC_ACTION_DELAY_RESCAN);
31807836SJohn.Forte@Sun.COM 		}
31817836SJohn.Forte@Sun.COM 
31827836SJohn.Forte@Sun.COM 		st.st_completion_status = STMF_SUCCESS;
31837836SJohn.Forte@Sun.COM 		st.st_additional_info = NULL;
31847836SJohn.Forte@Sun.COM 		iport->iport_offline_prstate = FCT_OPR_DONE;
31857836SJohn.Forte@Sun.COM 		iport->iport_state = FCT_STATE_OFFLINE;
31867836SJohn.Forte@Sun.COM 		mutex_exit(&iport->iport_worker_lock);
31877836SJohn.Forte@Sun.COM 		(void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
31889578SSam.Cramer@Sun.COM 		    iport->iport_port->port_lport, &st);
31897836SJohn.Forte@Sun.COM 		mutex_enter(&iport->iport_worker_lock);
31907836SJohn.Forte@Sun.COM 		return (DISC_ACTION_DELAY_RESCAN);
31917836SJohn.Forte@Sun.COM 	}
31927836SJohn.Forte@Sun.COM 
31937836SJohn.Forte@Sun.COM 	/* NOTREACHED */
31947836SJohn.Forte@Sun.COM 	return (0);
31957836SJohn.Forte@Sun.COM }
31967836SJohn.Forte@Sun.COM 
31977836SJohn.Forte@Sun.COM /*
31987836SJohn.Forte@Sun.COM  * See stmf.h for information on rflags. Additional info is just a text
31997836SJohn.Forte@Sun.COM  * description of the reason for this call. Additional_info can be NULL.
32007836SJohn.Forte@Sun.COM  * Also the caller can declare additional info on the stack. stmf_ctl
32017836SJohn.Forte@Sun.COM  * makes a copy of it before returning.
32027836SJohn.Forte@Sun.COM  */
32037836SJohn.Forte@Sun.COM fct_status_t
fct_port_initialize(fct_local_port_t * port,uint32_t rflags,char * additional_info)32047836SJohn.Forte@Sun.COM fct_port_initialize(fct_local_port_t *port, uint32_t rflags,
32057836SJohn.Forte@Sun.COM 				char *additional_info)
32067836SJohn.Forte@Sun.COM {
32077836SJohn.Forte@Sun.COM 	stmf_state_change_info_t st;
32087836SJohn.Forte@Sun.COM 
32097836SJohn.Forte@Sun.COM 	st.st_rflags = rflags;
32107836SJohn.Forte@Sun.COM 	st.st_additional_info = additional_info;
32117836SJohn.Forte@Sun.COM 	stmf_trace(NULL, "fct_port_initialize: port-%p, %s", port,
32127836SJohn.Forte@Sun.COM 	    additional_info? additional_info : "no more information");
32137836SJohn.Forte@Sun.COM 	return (stmf_ctl(STMF_CMD_LPORT_ONLINE, port->port_lport, &st));
32147836SJohn.Forte@Sun.COM }
32157836SJohn.Forte@Sun.COM 
32167836SJohn.Forte@Sun.COM fct_status_t
fct_port_shutdown(fct_local_port_t * port,uint32_t rflags,char * additional_info)32177836SJohn.Forte@Sun.COM fct_port_shutdown(fct_local_port_t *port, uint32_t rflags,
32187836SJohn.Forte@Sun.COM 				char *additional_info)
32197836SJohn.Forte@Sun.COM {
32207836SJohn.Forte@Sun.COM 	stmf_state_change_info_t st;
32217836SJohn.Forte@Sun.COM 
32227836SJohn.Forte@Sun.COM 	st.st_rflags = rflags;
32237836SJohn.Forte@Sun.COM 	st.st_additional_info = additional_info;
32247836SJohn.Forte@Sun.COM 	stmf_trace(NULL, "fct_port_shutdown: port-%p, %s", port,
32257836SJohn.Forte@Sun.COM 	    additional_info? additional_info : "no more information");
32267836SJohn.Forte@Sun.COM 	return (stmf_ctl(STMF_CMD_LPORT_OFFLINE, port->port_lport, &st));
32277836SJohn.Forte@Sun.COM }
32287836SJohn.Forte@Sun.COM 
32297836SJohn.Forte@Sun.COM /*
32307836SJohn.Forte@Sun.COM  * Called by worker thread. The aim is to terminate the command
32317836SJohn.Forte@Sun.COM  * using whatever means it takes.
32327836SJohn.Forte@Sun.COM  * Called with worker lock held.
32337836SJohn.Forte@Sun.COM  */
32347836SJohn.Forte@Sun.COM disc_action_t
fct_cmd_terminator(fct_i_local_port_t * iport)32357836SJohn.Forte@Sun.COM fct_cmd_terminator(fct_i_local_port_t *iport)
32367836SJohn.Forte@Sun.COM {
3237*12571SViswanathan.Kannappan@Sun.COM 	char			info[FCT_INFO_LEN];
32387836SJohn.Forte@Sun.COM 	clock_t			endtime;
32397836SJohn.Forte@Sun.COM 	fct_i_cmd_t		**ppicmd;
32407836SJohn.Forte@Sun.COM 	fct_i_cmd_t		*icmd;
32417836SJohn.Forte@Sun.COM 	fct_cmd_t		*cmd;
32427836SJohn.Forte@Sun.COM 	fct_local_port_t	*port = iport->iport_port;
32437836SJohn.Forte@Sun.COM 	disc_action_t		ret = DISC_ACTION_NO_WORK;
32447836SJohn.Forte@Sun.COM 	fct_status_t		abort_ret;
32457836SJohn.Forte@Sun.COM 	int			fca_done, fct_done, cmd_implicit = 0;
32467836SJohn.Forte@Sun.COM 	int			flags;
32477836SJohn.Forte@Sun.COM 	unsigned long long	st;
32487836SJohn.Forte@Sun.COM 
32497836SJohn.Forte@Sun.COM 	/* Lets Limit each run to 20ms max. */
32507836SJohn.Forte@Sun.COM 	endtime = ddi_get_lbolt() + drv_usectohz(20000);
32517836SJohn.Forte@Sun.COM 
32527836SJohn.Forte@Sun.COM 	/* Start from where we left off last time */
32537836SJohn.Forte@Sun.COM 	if (iport->iport_ppicmd_term) {
32547836SJohn.Forte@Sun.COM 		ppicmd = iport->iport_ppicmd_term;
32557836SJohn.Forte@Sun.COM 		iport->iport_ppicmd_term = NULL;
32567836SJohn.Forte@Sun.COM 	} else {
32577836SJohn.Forte@Sun.COM 		ppicmd = &iport->iport_abort_queue;
32587836SJohn.Forte@Sun.COM 	}
32597836SJohn.Forte@Sun.COM 
32607836SJohn.Forte@Sun.COM 	/*
32617836SJohn.Forte@Sun.COM 	 * Once a command gets on discovery queue, this is the only thread
32627836SJohn.Forte@Sun.COM 	 * which can access it. So no need for the lock here.
32637836SJohn.Forte@Sun.COM 	 */
32647836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
32657836SJohn.Forte@Sun.COM 
32667836SJohn.Forte@Sun.COM 	while ((icmd = *ppicmd) != NULL) {
32677836SJohn.Forte@Sun.COM 		cmd = icmd->icmd_cmd;
32687836SJohn.Forte@Sun.COM 
32697836SJohn.Forte@Sun.COM 		/* Always remember that cmd->cmd_rp can be NULL */
32707836SJohn.Forte@Sun.COM 		if ((icmd->icmd_flags & (ICMD_KNOWN_TO_FCA |
32717836SJohn.Forte@Sun.COM 		    ICMD_FCA_ABORT_CALLED)) == ICMD_KNOWN_TO_FCA) {
32727836SJohn.Forte@Sun.COM 			atomic_or_32(&icmd->icmd_flags, ICMD_FCA_ABORT_CALLED);
32737836SJohn.Forte@Sun.COM 			if (CMD_HANDLE_VALID(cmd->cmd_handle))
32747836SJohn.Forte@Sun.COM 				flags = 0;
32757836SJohn.Forte@Sun.COM 			else
32767836SJohn.Forte@Sun.COM 				flags = FCT_IOF_FORCE_FCA_DONE;
32777836SJohn.Forte@Sun.COM 			abort_ret = port->port_abort_cmd(port, cmd, flags);
32787836SJohn.Forte@Sun.COM 			if ((abort_ret != FCT_SUCCESS) &&
32797836SJohn.Forte@Sun.COM 			    (abort_ret != FCT_ABORT_SUCCESS) &&
32807836SJohn.Forte@Sun.COM 			    (abort_ret != FCT_NOT_FOUND)) {
32817836SJohn.Forte@Sun.COM 				if (flags & FCT_IOF_FORCE_FCA_DONE) {
32827836SJohn.Forte@Sun.COM 					/*
32837836SJohn.Forte@Sun.COM 					 * XXX trigger port fatal,
32847836SJohn.Forte@Sun.COM 					 * Abort the termination, and shutdown
32857836SJohn.Forte@Sun.COM 					 * svc will trigger fct_cmd_termination
32867836SJohn.Forte@Sun.COM 					 * again.
32877836SJohn.Forte@Sun.COM 					 */
3288*12571SViswanathan.Kannappan@Sun.COM 					(void) snprintf(info, sizeof (info),
32897836SJohn.Forte@Sun.COM 					    "fct_cmd_terminator:"
32907836SJohn.Forte@Sun.COM 					    " iport-%p, port_abort_cmd with "
32917836SJohn.Forte@Sun.COM 					    "FORCE_FCA_DONE failed",
32927836SJohn.Forte@Sun.COM 					    (void *)iport);
32937836SJohn.Forte@Sun.COM 					(void) fct_port_shutdown(
32947836SJohn.Forte@Sun.COM 					    iport->iport_port,
32957836SJohn.Forte@Sun.COM 					    STMF_RFLAG_FATAL_ERROR |
32967836SJohn.Forte@Sun.COM 					    STMF_RFLAG_RESET, info);
32977836SJohn.Forte@Sun.COM 
32987836SJohn.Forte@Sun.COM 					mutex_enter(&iport->iport_worker_lock);
32997836SJohn.Forte@Sun.COM 					iport->iport_ppicmd_term = ppicmd;
33007836SJohn.Forte@Sun.COM 					return (DISC_ACTION_DELAY_RESCAN);
33017836SJohn.Forte@Sun.COM 				}
33027836SJohn.Forte@Sun.COM 				atomic_and_32(&icmd->icmd_flags,
33039578SSam.Cramer@Sun.COM 				    ~ICMD_FCA_ABORT_CALLED);
33047836SJohn.Forte@Sun.COM 			} else if ((flags & FCT_IOF_FORCE_FCA_DONE) ||
33057836SJohn.Forte@Sun.COM 			    (abort_ret == FCT_ABORT_SUCCESS) ||
33067836SJohn.Forte@Sun.COM 			    (abort_ret == FCT_NOT_FOUND)) {
33077836SJohn.Forte@Sun.COM 				atomic_and_32(&icmd->icmd_flags,
33089578SSam.Cramer@Sun.COM 				    ~ICMD_KNOWN_TO_FCA);
33097836SJohn.Forte@Sun.COM 			}
33107836SJohn.Forte@Sun.COM 			ret |= DISC_ACTION_DELAY_RESCAN;
33117836SJohn.Forte@Sun.COM 		} else if (icmd->icmd_flags & ICMD_IMPLICIT) {
33127836SJohn.Forte@Sun.COM 			if (cmd->cmd_type == FCT_CMD_SOL_ELS)
33137836SJohn.Forte@Sun.COM 				cmd->cmd_comp_status = FCT_ABORTED;
33147836SJohn.Forte@Sun.COM 			atomic_or_32(&icmd->icmd_flags, ICMD_FCA_ABORT_CALLED);
33157836SJohn.Forte@Sun.COM 			cmd_implicit = 1;
33167836SJohn.Forte@Sun.COM 		}
33177836SJohn.Forte@Sun.COM 		if ((icmd->icmd_flags & ICMD_KNOWN_TO_FCA) == 0)
33187836SJohn.Forte@Sun.COM 			fca_done = 1;
33197836SJohn.Forte@Sun.COM 		else
33207836SJohn.Forte@Sun.COM 			fca_done = 0;
33217836SJohn.Forte@Sun.COM 		if ((icmd->icmd_flags & ICMD_IN_IRP_QUEUE) == 0)
33227836SJohn.Forte@Sun.COM 			fct_done = 1;
33237836SJohn.Forte@Sun.COM 		else
33247836SJohn.Forte@Sun.COM 			fct_done = 0;
33257836SJohn.Forte@Sun.COM 		if ((fca_done || cmd_implicit) && fct_done) {
33267836SJohn.Forte@Sun.COM 			mutex_enter(&iport->iport_worker_lock);
33277836SJohn.Forte@Sun.COM 			ASSERT(*ppicmd == icmd);
33287836SJohn.Forte@Sun.COM 			*ppicmd = (*ppicmd)->icmd_next;
33297836SJohn.Forte@Sun.COM 			mutex_exit(&iport->iport_worker_lock);
33307836SJohn.Forte@Sun.COM 			if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) ||
33317836SJohn.Forte@Sun.COM 			    (cmd->cmd_type == FCT_CMD_RCVD_ABTS)) {
33327836SJohn.Forte@Sun.COM 				/* Free the cmd */
33337836SJohn.Forte@Sun.COM 				fct_cmd_free(cmd);
33347836SJohn.Forte@Sun.COM 			} else if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
33357836SJohn.Forte@Sun.COM 				fct_handle_sol_els_completion(iport, icmd);
33367836SJohn.Forte@Sun.COM 				if (icmd->icmd_flags & ICMD_IMPLICIT) {
33377836SJohn.Forte@Sun.COM 					if (IS_LOGO_ELS(icmd)) {
33387836SJohn.Forte@Sun.COM 						/* IMPLICIT LOGO is special */
33397836SJohn.Forte@Sun.COM 						fct_cmd_free(cmd);
33407836SJohn.Forte@Sun.COM 					}
33417836SJohn.Forte@Sun.COM 				}
33427836SJohn.Forte@Sun.COM 			} else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
33437836SJohn.Forte@Sun.COM 				fct_sol_ct_t *ct = ICMD_TO_CT(icmd);
33447836SJohn.Forte@Sun.COM 
33457836SJohn.Forte@Sun.COM 				/* Tell the caller that we are done */
33467836SJohn.Forte@Sun.COM 				atomic_or_32(&icmd->icmd_flags,
33477836SJohn.Forte@Sun.COM 				    ICMD_CMD_COMPLETE);
33487836SJohn.Forte@Sun.COM 				if (fct_netbuf_to_value(
33497836SJohn.Forte@Sun.COM 				    ct->ct_req_payload + 8, 2) == NS_GID_PN) {
33507836SJohn.Forte@Sun.COM 					fct_i_remote_port_t *irp;
33517836SJohn.Forte@Sun.COM 
33527836SJohn.Forte@Sun.COM 					rw_enter(&iport->iport_lock, RW_READER);
33537836SJohn.Forte@Sun.COM 					irp = fct_lookup_irp_by_portwwn(iport,
33547836SJohn.Forte@Sun.COM 					    ct->ct_req_payload + 16);
33557836SJohn.Forte@Sun.COM 
33567836SJohn.Forte@Sun.COM 					if (irp) {
33577836SJohn.Forte@Sun.COM 						atomic_and_32(&irp->irp_flags,
33587836SJohn.Forte@Sun.COM 						    ~IRP_RSCN_QUEUED);
33597836SJohn.Forte@Sun.COM 					}
33607836SJohn.Forte@Sun.COM 					rw_exit(&iport->iport_lock);
33617836SJohn.Forte@Sun.COM 				}
33627836SJohn.Forte@Sun.COM 			} else {
33637836SJohn.Forte@Sun.COM 				ASSERT(0);
33647836SJohn.Forte@Sun.COM 			}
33657836SJohn.Forte@Sun.COM 		} else {
33667836SJohn.Forte@Sun.COM 			clock_t	timeout_ticks;
33677836SJohn.Forte@Sun.COM 			if (port->port_fca_abort_timeout)
33687836SJohn.Forte@Sun.COM 				timeout_ticks = drv_usectohz(
33697836SJohn.Forte@Sun.COM 				    port->port_fca_abort_timeout*1000);
33707836SJohn.Forte@Sun.COM 			else
33717836SJohn.Forte@Sun.COM 				/* 10 seconds by default */
33727836SJohn.Forte@Sun.COM 				timeout_ticks = drv_usectohz(10 * 1000000);
33737836SJohn.Forte@Sun.COM 			if ((ddi_get_lbolt() >
33747836SJohn.Forte@Sun.COM 			    (icmd->icmd_start_time+timeout_ticks)) &&
33757836SJohn.Forte@Sun.COM 			    iport->iport_state == FCT_STATE_ONLINE) {
33767836SJohn.Forte@Sun.COM 				/* timeout, reset the port */
33777836SJohn.Forte@Sun.COM 				char cmd_type[10];
33787836SJohn.Forte@Sun.COM 				if (cmd->cmd_type == FCT_CMD_RCVD_ELS ||
33797836SJohn.Forte@Sun.COM 				    cmd->cmd_type == FCT_CMD_SOL_ELS) {
33807836SJohn.Forte@Sun.COM 					fct_els_t *els = cmd->cmd_specific;
33817836SJohn.Forte@Sun.COM 					(void) snprintf(cmd_type,
33827836SJohn.Forte@Sun.COM 					    sizeof (cmd_type), "%x.%x",
33837836SJohn.Forte@Sun.COM 					    cmd->cmd_type,
33847836SJohn.Forte@Sun.COM 					    els->els_req_payload[0]);
33857836SJohn.Forte@Sun.COM 				} else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
33867836SJohn.Forte@Sun.COM 					fct_sol_ct_t *ct = cmd->cmd_specific;
33877836SJohn.Forte@Sun.COM 					(void) snprintf(cmd_type,
33887836SJohn.Forte@Sun.COM 					    sizeof (cmd_type), "%x.%02x%02x",
33897836SJohn.Forte@Sun.COM 					    cmd->cmd_type,
33907836SJohn.Forte@Sun.COM 					    ct->ct_req_payload[8],
33917836SJohn.Forte@Sun.COM 					    ct->ct_req_payload[9]);
33927836SJohn.Forte@Sun.COM 				} else {
33937836SJohn.Forte@Sun.COM 					cmd_type[0] = 0;
33947836SJohn.Forte@Sun.COM 				}
33957836SJohn.Forte@Sun.COM 				st = cmd->cmd_comp_status;	/* gcc fix */
3396*12571SViswanathan.Kannappan@Sun.COM 				(void) snprintf(info, sizeof (info),
3397*12571SViswanathan.Kannappan@Sun.COM 				    "fct_cmd_terminator:"
33987836SJohn.Forte@Sun.COM 				    " iport-%p, cmd_type(0x%s),"
33997836SJohn.Forte@Sun.COM 				    " reason(%llx)", (void *)iport, cmd_type,
34007836SJohn.Forte@Sun.COM 				    st);
34017836SJohn.Forte@Sun.COM 				(void) fct_port_shutdown(port,
34027836SJohn.Forte@Sun.COM 				    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET,
34037836SJohn.Forte@Sun.COM 				    info);
34047836SJohn.Forte@Sun.COM 			}
34057836SJohn.Forte@Sun.COM 			ppicmd = &((*ppicmd)->icmd_next);
34067836SJohn.Forte@Sun.COM 		}
34077836SJohn.Forte@Sun.COM 
34087836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > endtime) {
34097836SJohn.Forte@Sun.COM 			mutex_enter(&iport->iport_worker_lock);
34107836SJohn.Forte@Sun.COM 			iport->iport_ppicmd_term = ppicmd;
34117836SJohn.Forte@Sun.COM 			return (DISC_ACTION_DELAY_RESCAN);
34127836SJohn.Forte@Sun.COM 		}
34137836SJohn.Forte@Sun.COM 	}
34147836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
34157836SJohn.Forte@Sun.COM 	if (iport->iport_abort_queue)
34167836SJohn.Forte@Sun.COM 		return (DISC_ACTION_DELAY_RESCAN);
34177836SJohn.Forte@Sun.COM 	if (ret == DISC_ACTION_NO_WORK)
34187836SJohn.Forte@Sun.COM 		return (DISC_ACTION_RESCAN);
34197836SJohn.Forte@Sun.COM 	return (ret);
34207836SJohn.Forte@Sun.COM }
34217836SJohn.Forte@Sun.COM 
34227836SJohn.Forte@Sun.COM /*
34237836SJohn.Forte@Sun.COM  * Send a syslog event for adapter port level events.
34247836SJohn.Forte@Sun.COM  */
34257836SJohn.Forte@Sun.COM void
fct_log_local_port_event(fct_local_port_t * port,char * subclass)34267836SJohn.Forte@Sun.COM fct_log_local_port_event(fct_local_port_t *port, char *subclass)
34277836SJohn.Forte@Sun.COM {
34287836SJohn.Forte@Sun.COM 	nvlist_t *attr_list;
34297836SJohn.Forte@Sun.COM 	int port_instance;
34307836SJohn.Forte@Sun.COM 
34317836SJohn.Forte@Sun.COM 	if (!fct_dip)
34327836SJohn.Forte@Sun.COM 		return;
34337836SJohn.Forte@Sun.COM 	port_instance = ddi_get_instance(fct_dip);
34347836SJohn.Forte@Sun.COM 
34357836SJohn.Forte@Sun.COM 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
34367836SJohn.Forte@Sun.COM 	    KM_SLEEP) != DDI_SUCCESS) {
34377836SJohn.Forte@Sun.COM 		goto alloc_failed;
34387836SJohn.Forte@Sun.COM 	}
34397836SJohn.Forte@Sun.COM 
34407836SJohn.Forte@Sun.COM 	if (nvlist_add_uint32(attr_list, "instance", port_instance)
34417836SJohn.Forte@Sun.COM 	    != DDI_SUCCESS) {
34427836SJohn.Forte@Sun.COM 		goto error;
34437836SJohn.Forte@Sun.COM 	}
34447836SJohn.Forte@Sun.COM 
34457836SJohn.Forte@Sun.COM 	if (nvlist_add_byte_array(attr_list, "port-wwn",
34467836SJohn.Forte@Sun.COM 	    port->port_pwwn, 8) != DDI_SUCCESS) {
34477836SJohn.Forte@Sun.COM 		goto error;
34487836SJohn.Forte@Sun.COM 	}
34497836SJohn.Forte@Sun.COM 
34507836SJohn.Forte@Sun.COM 	(void) ddi_log_sysevent(fct_dip, DDI_VENDOR_SUNW, EC_SUNFC,
34517836SJohn.Forte@Sun.COM 	    subclass, attr_list, NULL, DDI_SLEEP);
34527836SJohn.Forte@Sun.COM 
34537836SJohn.Forte@Sun.COM 	nvlist_free(attr_list);
34547836SJohn.Forte@Sun.COM 	return;
34557836SJohn.Forte@Sun.COM 
34567836SJohn.Forte@Sun.COM error:
34577836SJohn.Forte@Sun.COM 	nvlist_free(attr_list);
34587836SJohn.Forte@Sun.COM alloc_failed:
34597836SJohn.Forte@Sun.COM 	stmf_trace(((fct_i_local_port_t *)port->port_fct_private)->iport_alias,
34607836SJohn.Forte@Sun.COM 	    "Unable to send %s event", subclass);
34617836SJohn.Forte@Sun.COM }
34627836SJohn.Forte@Sun.COM 
34637836SJohn.Forte@Sun.COM void
fct_log_remote_port_event(fct_local_port_t * port,char * subclass,uint8_t * rp_pwwn,uint32_t rp_id)34647836SJohn.Forte@Sun.COM fct_log_remote_port_event(fct_local_port_t *port, char *subclass,
34657836SJohn.Forte@Sun.COM     uint8_t *rp_pwwn, uint32_t rp_id)
34667836SJohn.Forte@Sun.COM {
34677836SJohn.Forte@Sun.COM 	nvlist_t *attr_list;
34687836SJohn.Forte@Sun.COM 	int port_instance;
34697836SJohn.Forte@Sun.COM 
34707836SJohn.Forte@Sun.COM 	if (!fct_dip)
34717836SJohn.Forte@Sun.COM 		return;
34727836SJohn.Forte@Sun.COM 	port_instance = ddi_get_instance(fct_dip);
34737836SJohn.Forte@Sun.COM 
34747836SJohn.Forte@Sun.COM 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
34757836SJohn.Forte@Sun.COM 	    KM_SLEEP) != DDI_SUCCESS) {
34767836SJohn.Forte@Sun.COM 		goto alloc_failed;
34777836SJohn.Forte@Sun.COM 	}
34787836SJohn.Forte@Sun.COM 
34797836SJohn.Forte@Sun.COM 	if (nvlist_add_uint32(attr_list, "instance", port_instance)
34807836SJohn.Forte@Sun.COM 	    != DDI_SUCCESS) {
34817836SJohn.Forte@Sun.COM 		goto error;
34827836SJohn.Forte@Sun.COM 	}
34837836SJohn.Forte@Sun.COM 
34847836SJohn.Forte@Sun.COM 	if (nvlist_add_byte_array(attr_list, "port-wwn",
34857836SJohn.Forte@Sun.COM 	    port->port_pwwn, 8) != DDI_SUCCESS) {
34867836SJohn.Forte@Sun.COM 		goto error;
34877836SJohn.Forte@Sun.COM 	}
34887836SJohn.Forte@Sun.COM 
34897836SJohn.Forte@Sun.COM 	if (nvlist_add_byte_array(attr_list, "target-port-wwn",
34907836SJohn.Forte@Sun.COM 	    rp_pwwn, 8) != DDI_SUCCESS) {
34917836SJohn.Forte@Sun.COM 		goto error;
34927836SJohn.Forte@Sun.COM 	}
34937836SJohn.Forte@Sun.COM 
34947836SJohn.Forte@Sun.COM 	if (nvlist_add_uint32(attr_list, "target-port-id",
34957836SJohn.Forte@Sun.COM 	    rp_id) != DDI_SUCCESS) {
34967836SJohn.Forte@Sun.COM 		goto error;
34977836SJohn.Forte@Sun.COM 	}
34987836SJohn.Forte@Sun.COM 
34997836SJohn.Forte@Sun.COM 	(void) ddi_log_sysevent(fct_dip, DDI_VENDOR_SUNW, EC_SUNFC,
35007836SJohn.Forte@Sun.COM 	    subclass, attr_list, NULL, DDI_SLEEP);
35017836SJohn.Forte@Sun.COM 
35027836SJohn.Forte@Sun.COM 	nvlist_free(attr_list);
35037836SJohn.Forte@Sun.COM 	return;
35047836SJohn.Forte@Sun.COM 
35057836SJohn.Forte@Sun.COM error:
35067836SJohn.Forte@Sun.COM 	nvlist_free(attr_list);
35077836SJohn.Forte@Sun.COM alloc_failed:
35087836SJohn.Forte@Sun.COM 	stmf_trace(((fct_i_local_port_t *)port->port_fct_private)->iport_alias,
35097836SJohn.Forte@Sun.COM 	    "Unable to send %s event", subclass);
35107836SJohn.Forte@Sun.COM }
35117836SJohn.Forte@Sun.COM 
35127836SJohn.Forte@Sun.COM uint64_t
fct_netbuf_to_value(uint8_t * buf,uint8_t nbytes)35137836SJohn.Forte@Sun.COM fct_netbuf_to_value(uint8_t *buf, uint8_t nbytes)
35147836SJohn.Forte@Sun.COM {
35157836SJohn.Forte@Sun.COM 	uint64_t	ret = 0;
35167836SJohn.Forte@Sun.COM 	uint8_t		idx = 0;
35177836SJohn.Forte@Sun.COM 
35187836SJohn.Forte@Sun.COM 	do {
35197836SJohn.Forte@Sun.COM 		ret |= (buf[idx] << (8 * (nbytes -idx - 1)));
35207836SJohn.Forte@Sun.COM 	} while (++idx < nbytes);
35217836SJohn.Forte@Sun.COM 
35227836SJohn.Forte@Sun.COM 	return (ret);
35237836SJohn.Forte@Sun.COM }
35247836SJohn.Forte@Sun.COM 
35257836SJohn.Forte@Sun.COM void
fct_value_to_netbuf(uint64_t value,uint8_t * buf,uint8_t nbytes)35267836SJohn.Forte@Sun.COM fct_value_to_netbuf(uint64_t value, uint8_t *buf, uint8_t nbytes)
35277836SJohn.Forte@Sun.COM {
35287836SJohn.Forte@Sun.COM 	uint8_t		idx = 0;
35297836SJohn.Forte@Sun.COM 
35307836SJohn.Forte@Sun.COM 	for (idx = 0; idx < nbytes; idx++) {
35317836SJohn.Forte@Sun.COM 		buf[idx] = 0xFF & (value >> (8 * (nbytes - idx - 1)));
35327836SJohn.Forte@Sun.COM 	}
35337836SJohn.Forte@Sun.COM }
35349578SSam.Cramer@Sun.COM 
35359578SSam.Cramer@Sun.COM /*
35369578SSam.Cramer@Sun.COM  * from_ptr: ptr to uchar_t array of size WWN_SIZE
35379578SSam.Cramer@Sun.COM  * to_ptr: char ptr to string of size WWN_SIZE*2+1
35389578SSam.Cramer@Sun.COM  */
35399578SSam.Cramer@Sun.COM void
fct_wwn_to_str(char * to_ptr,const uint8_t * from_ptr)35409578SSam.Cramer@Sun.COM fct_wwn_to_str(char *to_ptr, const uint8_t *from_ptr)
35419578SSam.Cramer@Sun.COM {
35429578SSam.Cramer@Sun.COM 	ASSERT(to_ptr != NULL && from_ptr != NULL);
35439578SSam.Cramer@Sun.COM 
35449578SSam.Cramer@Sun.COM 	(void) sprintf(to_ptr, "%02x%02x%02x%02x%02x%02x%02x%02x",
35459578SSam.Cramer@Sun.COM 	    from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
35469578SSam.Cramer@Sun.COM 	    from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
35479578SSam.Cramer@Sun.COM }
354810088SAllan.Ou@Sun.COM 
354910088SAllan.Ou@Sun.COM static int
fct_update_stats(kstat_t * ks,int rw)355010088SAllan.Ou@Sun.COM fct_update_stats(kstat_t *ks, int rw)
355110088SAllan.Ou@Sun.COM {
355210088SAllan.Ou@Sun.COM 	fct_i_local_port_t *iport;
355310088SAllan.Ou@Sun.COM 	fct_port_stat_t *port_kstat;
355410088SAllan.Ou@Sun.COM 	fct_port_link_status_t stat;
355510088SAllan.Ou@Sun.COM 	uint32_t	buf_size = sizeof (stat);
355610088SAllan.Ou@Sun.COM 	int		ret;
355710088SAllan.Ou@Sun.COM 
355810088SAllan.Ou@Sun.COM 	if (rw == KSTAT_WRITE)
355910088SAllan.Ou@Sun.COM 		return (EACCES);
356010088SAllan.Ou@Sun.COM 
356110088SAllan.Ou@Sun.COM 	iport = (fct_i_local_port_t *)ks->ks_private;
356210088SAllan.Ou@Sun.COM 	port_kstat = (fct_port_stat_t *)ks->ks_data;
356310088SAllan.Ou@Sun.COM 
356410088SAllan.Ou@Sun.COM 	if (iport->iport_port->port_info == NULL) {
356510088SAllan.Ou@Sun.COM 		return (EIO);
356610088SAllan.Ou@Sun.COM 	}
356710088SAllan.Ou@Sun.COM 	ret = iport->iport_port->port_info(FC_TGT_PORT_RLS,
356810088SAllan.Ou@Sun.COM 	    iport->iport_port, NULL, (uint8_t *)&stat, &buf_size);
356910088SAllan.Ou@Sun.COM 	if (ret != STMF_SUCCESS) {
357010088SAllan.Ou@Sun.COM 		return (EIO);
357110088SAllan.Ou@Sun.COM 	}
357210088SAllan.Ou@Sun.COM 
357310088SAllan.Ou@Sun.COM 	port_kstat->link_failure_cnt.value.ui32 =
357410088SAllan.Ou@Sun.COM 	    stat.LinkFailureCount;
357510088SAllan.Ou@Sun.COM 	port_kstat->loss_of_sync_cnt.value.ui32 =
357610088SAllan.Ou@Sun.COM 	    stat.LossOfSyncCount;
357710088SAllan.Ou@Sun.COM 	port_kstat->loss_of_signals_cnt.value.ui32 =
357810088SAllan.Ou@Sun.COM 	    stat.LossOfSignalsCount;
357910088SAllan.Ou@Sun.COM 	port_kstat->prim_seq_protocol_err_cnt.value.ui32 =
358010088SAllan.Ou@Sun.COM 	    stat.PrimitiveSeqProtocolErrorCount;
358110088SAllan.Ou@Sun.COM 	port_kstat->invalid_tx_word_cnt.value.ui32 =
358210088SAllan.Ou@Sun.COM 	    stat.InvalidTransmissionWordCount;
358310088SAllan.Ou@Sun.COM 	port_kstat->invalid_crc_cnt.value.ui32 =
358410088SAllan.Ou@Sun.COM 	    stat.InvalidCRCCount;
358510088SAllan.Ou@Sun.COM 
358610088SAllan.Ou@Sun.COM 	return (0);
358710088SAllan.Ou@Sun.COM }
358810088SAllan.Ou@Sun.COM 
358910088SAllan.Ou@Sun.COM void
fct_init_kstats(fct_i_local_port_t * iport)359010088SAllan.Ou@Sun.COM fct_init_kstats(fct_i_local_port_t *iport)
359110088SAllan.Ou@Sun.COM {
359210088SAllan.Ou@Sun.COM 	kstat_t *ks;
359310088SAllan.Ou@Sun.COM 	fct_port_stat_t *port_kstat;
359410088SAllan.Ou@Sun.COM 	char	name[256];
359510088SAllan.Ou@Sun.COM 
359610088SAllan.Ou@Sun.COM 	if (iport->iport_alias)
359710088SAllan.Ou@Sun.COM 		(void) sprintf(name, "iport_%s", iport->iport_alias);
359810088SAllan.Ou@Sun.COM 	else
359910088SAllan.Ou@Sun.COM 		(void) sprintf(name, "iport_%"PRIxPTR"", (uintptr_t)iport);
360010088SAllan.Ou@Sun.COM 	ks = kstat_create(FCT_MODULE_NAME, 0, name, "rawdata",
360110088SAllan.Ou@Sun.COM 	    KSTAT_TYPE_NAMED, sizeof (fct_port_stat_t) / sizeof (kstat_named_t),
360210088SAllan.Ou@Sun.COM 	    0);
360310088SAllan.Ou@Sun.COM 
360410088SAllan.Ou@Sun.COM 	if (ks == NULL) {
360510088SAllan.Ou@Sun.COM 		return;
360610088SAllan.Ou@Sun.COM 	}
360710088SAllan.Ou@Sun.COM 	port_kstat = (fct_port_stat_t *)ks->ks_data;
360810088SAllan.Ou@Sun.COM 
360910088SAllan.Ou@Sun.COM 	iport->iport_kstat_portstat = ks;
361010088SAllan.Ou@Sun.COM 	kstat_named_init(&port_kstat->link_failure_cnt,
361110088SAllan.Ou@Sun.COM 	    "Link_failure_cnt", KSTAT_DATA_UINT32);
361210088SAllan.Ou@Sun.COM 	kstat_named_init(&port_kstat->loss_of_sync_cnt,
361310088SAllan.Ou@Sun.COM 	    "Loss_of_sync_cnt", KSTAT_DATA_UINT32);
361410088SAllan.Ou@Sun.COM 	kstat_named_init(&port_kstat->loss_of_signals_cnt,
361510088SAllan.Ou@Sun.COM 	    "Loss_of_signals_cnt", KSTAT_DATA_UINT32);
361610088SAllan.Ou@Sun.COM 	kstat_named_init(&port_kstat->prim_seq_protocol_err_cnt,
361710088SAllan.Ou@Sun.COM 	    "Prim_seq_protocol_err_cnt", KSTAT_DATA_UINT32);
361810088SAllan.Ou@Sun.COM 	kstat_named_init(&port_kstat->invalid_tx_word_cnt,
361910088SAllan.Ou@Sun.COM 	    "Invalid_tx_word_cnt", KSTAT_DATA_UINT32);
362010088SAllan.Ou@Sun.COM 	kstat_named_init(&port_kstat->invalid_crc_cnt,
362110088SAllan.Ou@Sun.COM 	    "Invalid_crc_cnt", KSTAT_DATA_UINT32);
362210088SAllan.Ou@Sun.COM 	ks->ks_update = fct_update_stats;
362310088SAllan.Ou@Sun.COM 	ks->ks_private = (void *)iport;
362410088SAllan.Ou@Sun.COM 	kstat_install(ks);
362510088SAllan.Ou@Sun.COM 
362610088SAllan.Ou@Sun.COM }
3627