xref: /onnv-gate/usr/src/uts/common/io/fibre-channel/ulp/fcsm.c (revision 10264:1196af6129ec)
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 /*
2210110SMilan.Jurik@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  */
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM /*
277836SJohn.Forte@Sun.COM  * fcsm - ULP Module for Fibre Channel SAN Management
287836SJohn.Forte@Sun.COM  */
297836SJohn.Forte@Sun.COM 
307836SJohn.Forte@Sun.COM #include <sys/types.h>
317836SJohn.Forte@Sun.COM #include <sys/file.h>
327836SJohn.Forte@Sun.COM #include <sys/kmem.h>
337836SJohn.Forte@Sun.COM #include <sys/scsi/scsi.h>
347836SJohn.Forte@Sun.COM #include <sys/var.h>
357836SJohn.Forte@Sun.COM #include <sys/byteorder.h>
367836SJohn.Forte@Sun.COM #include <sys/fibre-channel/fc.h>
377836SJohn.Forte@Sun.COM #include <sys/fibre-channel/impl/fc_ulpif.h>
387836SJohn.Forte@Sun.COM #include <sys/fibre-channel/ulp/fcsm.h>
397836SJohn.Forte@Sun.COM 
407836SJohn.Forte@Sun.COM /* Definitions */
41*10264SZhong.Wang@Sun.COM #define	FCSM_VERSION		"20090729-1.28"
427836SJohn.Forte@Sun.COM #define	FCSM_NAME_VERSION	"SunFC FCSM v" FCSM_VERSION
437836SJohn.Forte@Sun.COM 
447836SJohn.Forte@Sun.COM /* Global Variables */
457836SJohn.Forte@Sun.COM static char		fcsm_name[] = "FCSM";
467836SJohn.Forte@Sun.COM static void		*fcsm_state = NULL;
477836SJohn.Forte@Sun.COM static kmutex_t		fcsm_global_mutex;
487836SJohn.Forte@Sun.COM static uint32_t		fcsm_flag = FCSM_IDLE;
497836SJohn.Forte@Sun.COM static dev_info_t	*fcsm_dip = NULL;
507836SJohn.Forte@Sun.COM static fcsm_t		*fcsm_port_head = NULL;
517836SJohn.Forte@Sun.COM static kmem_cache_t	*fcsm_job_cache = NULL;
527836SJohn.Forte@Sun.COM static int		fcsm_num_attaching = 0;
537836SJohn.Forte@Sun.COM static int		fcsm_num_detaching = 0;
547836SJohn.Forte@Sun.COM static int		fcsm_detached = 0;
557836SJohn.Forte@Sun.COM 
567836SJohn.Forte@Sun.COM static int		fcsm_max_cmd_retries = FCSM_MAX_CMD_RETRIES;
577836SJohn.Forte@Sun.COM static int		fcsm_retry_interval = FCSM_RETRY_INTERVAL;
587836SJohn.Forte@Sun.COM static int		fcsm_retry_ticker = FCSM_RETRY_TICKER;
597836SJohn.Forte@Sun.COM static int		fcsm_offline_ticker = FCSM_OFFLINE_TICKER;
607836SJohn.Forte@Sun.COM static int		fcsm_max_job_retries = FCSM_MAX_JOB_RETRIES;
617836SJohn.Forte@Sun.COM static clock_t		fcsm_retry_ticks;
627836SJohn.Forte@Sun.COM static clock_t		fcsm_offline_ticks;
637836SJohn.Forte@Sun.COM 
647836SJohn.Forte@Sun.COM 
657836SJohn.Forte@Sun.COM 
667836SJohn.Forte@Sun.COM #ifdef DEBUG
677836SJohn.Forte@Sun.COM uint32_t		fcsm_debug = (SMDL_TRACE | SMDL_IO |
68*10264SZhong.Wang@Sun.COM     SMDL_ERR | SMDL_INFO);
697836SJohn.Forte@Sun.COM #endif
707836SJohn.Forte@Sun.COM 
717836SJohn.Forte@Sun.COM 
727836SJohn.Forte@Sun.COM /* Character/Block entry points */
737836SJohn.Forte@Sun.COM struct cb_ops	fcsm_cb_ops = {
747836SJohn.Forte@Sun.COM 	fcsm_open,	/* open */
757836SJohn.Forte@Sun.COM 	fcsm_close,	/* close */
767836SJohn.Forte@Sun.COM 	nodev,		/* strategy */
777836SJohn.Forte@Sun.COM 	nodev,		/* print */
787836SJohn.Forte@Sun.COM 	nodev,		/* dump */
797836SJohn.Forte@Sun.COM 	nodev,		/* read */
807836SJohn.Forte@Sun.COM 	nodev,		/* write */
817836SJohn.Forte@Sun.COM 	fcsm_ioctl,	/* ioctl */
827836SJohn.Forte@Sun.COM 	nodev,		/* devmap */
837836SJohn.Forte@Sun.COM 	nodev,		/* mmap */
847836SJohn.Forte@Sun.COM 	nodev,		/* segmap */
857836SJohn.Forte@Sun.COM 	nochpoll,	/* poll */
867836SJohn.Forte@Sun.COM 	ddi_prop_op,
877836SJohn.Forte@Sun.COM 	NULL,		/* streams info */
887836SJohn.Forte@Sun.COM 	D_NEW | D_MP,
897836SJohn.Forte@Sun.COM 	CB_REV,
907836SJohn.Forte@Sun.COM 	nodev,		/* aread */
917836SJohn.Forte@Sun.COM 	nodev		/* awrite */
927836SJohn.Forte@Sun.COM };
937836SJohn.Forte@Sun.COM 
947836SJohn.Forte@Sun.COM struct dev_ops fcsm_ops = {
957836SJohn.Forte@Sun.COM 	DEVO_REV,
967836SJohn.Forte@Sun.COM 	0,		/* refcnt */
977836SJohn.Forte@Sun.COM 	fcsm_getinfo,	/* get info */
987836SJohn.Forte@Sun.COM 	nulldev,	/* identify (obsolete) */
997836SJohn.Forte@Sun.COM 	nulldev,	/* probe (not required for self-identifying devices) */
1007836SJohn.Forte@Sun.COM 	fcsm_attach,	/* attach */
1017836SJohn.Forte@Sun.COM 	fcsm_detach,	/* detach */
1027836SJohn.Forte@Sun.COM 	nodev,		/* reset */
1037836SJohn.Forte@Sun.COM 	&fcsm_cb_ops,	/* char/block entry points structure for leaf drivers */
1047836SJohn.Forte@Sun.COM 	NULL,		/* bus operations for nexus driver */
1057836SJohn.Forte@Sun.COM 	NULL		/* power management */
1067836SJohn.Forte@Sun.COM };
1077836SJohn.Forte@Sun.COM 
1087836SJohn.Forte@Sun.COM 
1097836SJohn.Forte@Sun.COM struct modldrv modldrv = {
1107836SJohn.Forte@Sun.COM 	&mod_driverops,
1117836SJohn.Forte@Sun.COM 	FCSM_NAME_VERSION,
1127836SJohn.Forte@Sun.COM 	&fcsm_ops
1137836SJohn.Forte@Sun.COM };
1147836SJohn.Forte@Sun.COM 
1157836SJohn.Forte@Sun.COM struct modlinkage modlinkage = {
1167836SJohn.Forte@Sun.COM 	MODREV_1,
1177836SJohn.Forte@Sun.COM 	&modldrv,
1187836SJohn.Forte@Sun.COM 	NULL
1197836SJohn.Forte@Sun.COM };
1207836SJohn.Forte@Sun.COM 
1217836SJohn.Forte@Sun.COM static fc_ulp_modinfo_t fcsm_modinfo = {
1227836SJohn.Forte@Sun.COM 	&fcsm_modinfo,		/* ulp_handle */
1237836SJohn.Forte@Sun.COM 	FCTL_ULP_MODREV_4,	/* ulp_rev */
1247836SJohn.Forte@Sun.COM 	FC_TYPE_FC_SERVICES,	/* ulp_type */
1257836SJohn.Forte@Sun.COM 	fcsm_name,		/* ulp_name */
1267836SJohn.Forte@Sun.COM 	0,			/* ulp_statec_mask: get all statec callbacks */
1277836SJohn.Forte@Sun.COM 	fcsm_port_attach,	/* ulp_port_attach */
1287836SJohn.Forte@Sun.COM 	fcsm_port_detach,	/* ulp_port_detach */
1297836SJohn.Forte@Sun.COM 	fcsm_port_ioctl,	/* ulp_port_ioctl */
1307836SJohn.Forte@Sun.COM 	fcsm_els_cb,		/* ulp_els_callback */
1317836SJohn.Forte@Sun.COM 	fcsm_data_cb,		/* ulp_data_callback */
1327836SJohn.Forte@Sun.COM 	fcsm_statec_cb		/* ulp_statec_callback */
1337836SJohn.Forte@Sun.COM };
1347836SJohn.Forte@Sun.COM 
1357836SJohn.Forte@Sun.COM struct fcsm_xlat_pkt_state {
1367836SJohn.Forte@Sun.COM 	uchar_t	xlat_state;
1377836SJohn.Forte@Sun.COM 	int	xlat_rval;
1387836SJohn.Forte@Sun.COM } fcsm_xlat_pkt_state [] = {
1397836SJohn.Forte@Sun.COM 	{ FC_PKT_SUCCESS,		FC_SUCCESS },
1407836SJohn.Forte@Sun.COM 	{ FC_PKT_REMOTE_STOP,		FC_FAILURE },
1417836SJohn.Forte@Sun.COM 	{ FC_PKT_LOCAL_RJT,		FC_TRANSPORT_ERROR },
1427836SJohn.Forte@Sun.COM 	{ FC_PKT_NPORT_RJT,		FC_PREJECT },
1437836SJohn.Forte@Sun.COM 	{ FC_PKT_FABRIC_RJT,		FC_FREJECT },
1447836SJohn.Forte@Sun.COM 	{ FC_PKT_LOCAL_BSY,		FC_TRAN_BUSY },
1457836SJohn.Forte@Sun.COM 	{ FC_PKT_TRAN_BSY,		FC_TRAN_BUSY },
1467836SJohn.Forte@Sun.COM 	{ FC_PKT_NPORT_BSY,		FC_PBUSY },
1477836SJohn.Forte@Sun.COM 	{ FC_PKT_FABRIC_BSY,		FC_FBUSY },
1487836SJohn.Forte@Sun.COM 	{ FC_PKT_LS_RJT,		FC_PREJECT },
1497836SJohn.Forte@Sun.COM 	{ FC_PKT_BA_RJT,		FC_PREJECT },
1507836SJohn.Forte@Sun.COM 	{ FC_PKT_TIMEOUT,		FC_FAILURE },
1517836SJohn.Forte@Sun.COM 	{ FC_PKT_FS_RJT,		FC_FAILURE },
1527836SJohn.Forte@Sun.COM 	{ FC_PKT_TRAN_ERROR,		FC_TRANSPORT_ERROR },
1537836SJohn.Forte@Sun.COM 	{ FC_PKT_FAILURE,		FC_FAILURE },
1547836SJohn.Forte@Sun.COM 	{ FC_PKT_PORT_OFFLINE,		FC_OFFLINE },
1557836SJohn.Forte@Sun.COM 	{ FC_PKT_ELS_IN_PROGRESS,	FC_FAILURE }
1567836SJohn.Forte@Sun.COM };
1577836SJohn.Forte@Sun.COM 
1587836SJohn.Forte@Sun.COM struct fcsm_xlat_port_state {
1597836SJohn.Forte@Sun.COM 	uint32_t	xlat_pstate;
1607836SJohn.Forte@Sun.COM 	caddr_t		xlat_state_str;
1617836SJohn.Forte@Sun.COM } fcsm_xlat_port_state [] = {
1627836SJohn.Forte@Sun.COM 	{ FC_STATE_OFFLINE,		"OFFLINE" },
1637836SJohn.Forte@Sun.COM 	{ FC_STATE_ONLINE,		"ONLINE" },
1647836SJohn.Forte@Sun.COM 	{ FC_STATE_LOOP,		"LOOP" },
1657836SJohn.Forte@Sun.COM 	{ FC_STATE_NAMESERVICE,		"NAMESERVICE" },
1667836SJohn.Forte@Sun.COM 	{ FC_STATE_RESET,		"RESET" },
1677836SJohn.Forte@Sun.COM 	{ FC_STATE_RESET_REQUESTED,	"RESET_REQUESTED" },
1687836SJohn.Forte@Sun.COM 	{ FC_STATE_LIP,			"LIP" },
1697836SJohn.Forte@Sun.COM 	{ FC_STATE_LIP_LBIT_SET,	"LIP_LBIT_SET" },
1707836SJohn.Forte@Sun.COM 	{ FC_STATE_DEVICE_CHANGE,	"DEVICE_CHANGE" },
1717836SJohn.Forte@Sun.COM 	{ FC_STATE_TARGET_PORT_RESET,	"TARGET_PORT_RESET" }
1727836SJohn.Forte@Sun.COM };
1737836SJohn.Forte@Sun.COM 
1747836SJohn.Forte@Sun.COM struct fcsm_xlat_topology {
1757836SJohn.Forte@Sun.COM 	uint32_t	xlat_top;
1767836SJohn.Forte@Sun.COM 	caddr_t		xlat_top_str;
1777836SJohn.Forte@Sun.COM } fcsm_xlat_topology [] = {
1787836SJohn.Forte@Sun.COM 	{ FC_TOP_UNKNOWN,	"UNKNOWN" },
1797836SJohn.Forte@Sun.COM 	{ FC_TOP_PRIVATE_LOOP,	"Private Loop" },
1807836SJohn.Forte@Sun.COM 	{ FC_TOP_PUBLIC_LOOP,	"Public Loop" },
1817836SJohn.Forte@Sun.COM 	{ FC_TOP_FABRIC,	"Fabric" },
1827836SJohn.Forte@Sun.COM 	{ FC_TOP_PT_PT,		"Point-to-Point" },
1837836SJohn.Forte@Sun.COM 	{ FC_TOP_NO_NS,		"NO_NS" }
1847836SJohn.Forte@Sun.COM };
1857836SJohn.Forte@Sun.COM 
1867836SJohn.Forte@Sun.COM struct fcsm_xlat_dev_type {
1877836SJohn.Forte@Sun.COM 	uint32_t	xlat_type;
1887836SJohn.Forte@Sun.COM 	caddr_t		xlat_str;
1897836SJohn.Forte@Sun.COM } fcsm_xlat_dev_type [] = {
1907836SJohn.Forte@Sun.COM 	{ PORT_DEVICE_NOCHANGE,		"No Change" },
1917836SJohn.Forte@Sun.COM 	{ PORT_DEVICE_NEW,		"New" },
1927836SJohn.Forte@Sun.COM 	{ PORT_DEVICE_OLD,		"Old" },
1937836SJohn.Forte@Sun.COM 	{ PORT_DEVICE_CHANGED,		"Changed" },
1947836SJohn.Forte@Sun.COM 	{ PORT_DEVICE_DELETE,		"Delete" },
1957836SJohn.Forte@Sun.COM 	{ PORT_DEVICE_USER_LOGIN,	"User Login" },
1967836SJohn.Forte@Sun.COM 	{ PORT_DEVICE_USER_LOGOUT,	"User Logout" },
1977836SJohn.Forte@Sun.COM 	{ PORT_DEVICE_USER_CREATE,	"User Create" },
1987836SJohn.Forte@Sun.COM 	{ PORT_DEVICE_USER_DELETE,	"User Delete" }
1997836SJohn.Forte@Sun.COM };
2007836SJohn.Forte@Sun.COM 
2017836SJohn.Forte@Sun.COM int
_init(void)2027836SJohn.Forte@Sun.COM _init(void)
2037836SJohn.Forte@Sun.COM {
2047836SJohn.Forte@Sun.COM 	int		rval;
2057836SJohn.Forte@Sun.COM 
2067836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "_init"));
2077836SJohn.Forte@Sun.COM 
2087836SJohn.Forte@Sun.COM 	fcsm_retry_ticks = drv_usectohz(fcsm_retry_ticker * 1000 * 1000);
2097836SJohn.Forte@Sun.COM 	fcsm_offline_ticks = drv_usectohz(fcsm_offline_ticker * 1000 * 1000);
2107836SJohn.Forte@Sun.COM 
2117836SJohn.Forte@Sun.COM 	if (rval = ddi_soft_state_init(&fcsm_state, sizeof (fcsm_t),
2127836SJohn.Forte@Sun.COM 	    FCSM_INIT_INSTANCES)) {
2137836SJohn.Forte@Sun.COM 		fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
2147836SJohn.Forte@Sun.COM 		    "_init: ddi_soft_state_init failed");
2157836SJohn.Forte@Sun.COM 		return (ENOMEM);
2167836SJohn.Forte@Sun.COM 	}
2177836SJohn.Forte@Sun.COM 
2187836SJohn.Forte@Sun.COM 	mutex_init(&fcsm_global_mutex, NULL, MUTEX_DRIVER, NULL);
2197836SJohn.Forte@Sun.COM 
2207836SJohn.Forte@Sun.COM 	fcsm_job_cache = kmem_cache_create("fcsm_job_cache",
2217836SJohn.Forte@Sun.COM 	    sizeof (fcsm_job_t), 8, fcsm_job_cache_constructor,
2227836SJohn.Forte@Sun.COM 	    fcsm_job_cache_destructor, NULL, NULL, NULL, 0);
2237836SJohn.Forte@Sun.COM 
2247836SJohn.Forte@Sun.COM 	if (fcsm_job_cache == NULL) {
2257836SJohn.Forte@Sun.COM 		mutex_destroy(&fcsm_global_mutex);
2267836SJohn.Forte@Sun.COM 		ddi_soft_state_fini(&fcsm_state);
2277836SJohn.Forte@Sun.COM 		return (ENOMEM);
2287836SJohn.Forte@Sun.COM 	}
2297836SJohn.Forte@Sun.COM 
2307836SJohn.Forte@Sun.COM 	/*
2317836SJohn.Forte@Sun.COM 	 * Now call fc_ulp_add to add this ULP in the transport layer
2327836SJohn.Forte@Sun.COM 	 * database. This will cause 'ulp_port_attach' callback function
2337836SJohn.Forte@Sun.COM 	 * to be called.
2347836SJohn.Forte@Sun.COM 	 */
2357836SJohn.Forte@Sun.COM 	rval = fc_ulp_add(&fcsm_modinfo);
2367836SJohn.Forte@Sun.COM 	if (rval != 0) {
2377836SJohn.Forte@Sun.COM 		switch (rval) {
2387836SJohn.Forte@Sun.COM 		case FC_ULP_SAMEMODULE:
2397836SJohn.Forte@Sun.COM 			fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
2407836SJohn.Forte@Sun.COM 			    "_init: FC SAN Management module is already "
2417836SJohn.Forte@Sun.COM 			    "registered with transport layer");
2427836SJohn.Forte@Sun.COM 			rval = EEXIST;
2437836SJohn.Forte@Sun.COM 			break;
2447836SJohn.Forte@Sun.COM 
2457836SJohn.Forte@Sun.COM 		case FC_ULP_SAMETYPE:
2467836SJohn.Forte@Sun.COM 			fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
2477836SJohn.Forte@Sun.COM 			    "_init: Another module with same type 0x%x is "
2487836SJohn.Forte@Sun.COM 			    "already registered with transport layer",
2497836SJohn.Forte@Sun.COM 			    fcsm_modinfo.ulp_type);
2507836SJohn.Forte@Sun.COM 			rval = EEXIST;
2517836SJohn.Forte@Sun.COM 			break;
2527836SJohn.Forte@Sun.COM 
2537836SJohn.Forte@Sun.COM 		case FC_BADULP:
2547836SJohn.Forte@Sun.COM 			fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
2557836SJohn.Forte@Sun.COM 			    "_init: Please upgrade this module. Current "
2567836SJohn.Forte@Sun.COM 			    "version 0x%x is not the most recent version",
2577836SJohn.Forte@Sun.COM 			    fcsm_modinfo.ulp_rev);
2587836SJohn.Forte@Sun.COM 			rval = EIO;
2597836SJohn.Forte@Sun.COM 			break;
2607836SJohn.Forte@Sun.COM 		default:
2617836SJohn.Forte@Sun.COM 			fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
2627836SJohn.Forte@Sun.COM 			    "_init: fc_ulp_add failed with status 0x%x", rval);
2637836SJohn.Forte@Sun.COM 			rval = EIO;
2647836SJohn.Forte@Sun.COM 			break;
2657836SJohn.Forte@Sun.COM 		}
2667836SJohn.Forte@Sun.COM 		kmem_cache_destroy(fcsm_job_cache);
2677836SJohn.Forte@Sun.COM 		mutex_destroy(&fcsm_global_mutex);
2687836SJohn.Forte@Sun.COM 		ddi_soft_state_fini(&fcsm_state);
2697836SJohn.Forte@Sun.COM 		return (rval);
2707836SJohn.Forte@Sun.COM 	}
2717836SJohn.Forte@Sun.COM 
2727836SJohn.Forte@Sun.COM 	if ((rval = mod_install(&modlinkage)) != 0) {
2737836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL, NULL,
2747836SJohn.Forte@Sun.COM 		    "_init: mod_install failed with status 0x%x", rval));
2757836SJohn.Forte@Sun.COM 		(void) fc_ulp_remove(&fcsm_modinfo);
2767836SJohn.Forte@Sun.COM 		kmem_cache_destroy(fcsm_job_cache);
2777836SJohn.Forte@Sun.COM 		mutex_destroy(&fcsm_global_mutex);
2787836SJohn.Forte@Sun.COM 		ddi_soft_state_fini(&fcsm_state);
2797836SJohn.Forte@Sun.COM 		return (rval);
2807836SJohn.Forte@Sun.COM 	}
2817836SJohn.Forte@Sun.COM 
2827836SJohn.Forte@Sun.COM 	return (rval);
2837836SJohn.Forte@Sun.COM }
2847836SJohn.Forte@Sun.COM 
2857836SJohn.Forte@Sun.COM int
_fini(void)2867836SJohn.Forte@Sun.COM _fini(void)
2877836SJohn.Forte@Sun.COM {
2887836SJohn.Forte@Sun.COM 	int	rval;
289*10264SZhong.Wang@Sun.COM #ifdef	DEBUG
2907836SJohn.Forte@Sun.COM 	int	status;
2917836SJohn.Forte@Sun.COM #endif /* DEBUG */
2927836SJohn.Forte@Sun.COM 
2937836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "_fini"));
2947836SJohn.Forte@Sun.COM 
2957836SJohn.Forte@Sun.COM 	/*
2967836SJohn.Forte@Sun.COM 	 * don't start cleaning up until we know that the module remove
2977836SJohn.Forte@Sun.COM 	 * has worked  -- if this works, then we know that each instance
2987836SJohn.Forte@Sun.COM 	 * has successfully been DDI_DETACHed
2997836SJohn.Forte@Sun.COM 	 */
3007836SJohn.Forte@Sun.COM 	if ((rval = mod_remove(&modlinkage)) != 0) {
3017836SJohn.Forte@Sun.COM 		return (rval);
3027836SJohn.Forte@Sun.COM 	}
3037836SJohn.Forte@Sun.COM 
3047836SJohn.Forte@Sun.COM #ifdef DEBUG
3057836SJohn.Forte@Sun.COM 	status = fc_ulp_remove(&fcsm_modinfo);
3067836SJohn.Forte@Sun.COM 	if (status != 0) {
3077836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL, NULL,
3087836SJohn.Forte@Sun.COM 		    "_fini: fc_ulp_remove failed with status 0x%x", status));
3097836SJohn.Forte@Sun.COM 	}
3107836SJohn.Forte@Sun.COM #else
3117836SJohn.Forte@Sun.COM 	(void) fc_ulp_remove(&fcsm_modinfo);
3127836SJohn.Forte@Sun.COM #endif /* DEBUG */
3137836SJohn.Forte@Sun.COM 
3147836SJohn.Forte@Sun.COM 	fcsm_detached = 0;
3157836SJohn.Forte@Sun.COM 
3167836SJohn.Forte@Sun.COM 	/*
3177836SJohn.Forte@Sun.COM 	 * It is possible to modunload fcsm manually, which will cause
3187836SJohn.Forte@Sun.COM 	 * a bypass of all the port_detach functionality.  We may need
3197836SJohn.Forte@Sun.COM 	 * to force that code path to be executed to properly clean up
3207836SJohn.Forte@Sun.COM 	 * in that case.
3217836SJohn.Forte@Sun.COM 	 */
3227836SJohn.Forte@Sun.COM 	fcsm_force_port_detach_all();
3237836SJohn.Forte@Sun.COM 
3247836SJohn.Forte@Sun.COM 	kmem_cache_destroy(fcsm_job_cache);
3257836SJohn.Forte@Sun.COM 	mutex_destroy(&fcsm_global_mutex);
3267836SJohn.Forte@Sun.COM 	ddi_soft_state_fini(&fcsm_state);
3277836SJohn.Forte@Sun.COM 
3287836SJohn.Forte@Sun.COM 	return (rval);
3297836SJohn.Forte@Sun.COM }
3307836SJohn.Forte@Sun.COM 
3317836SJohn.Forte@Sun.COM 
3327836SJohn.Forte@Sun.COM int
_info(struct modinfo * modinfop)3337836SJohn.Forte@Sun.COM _info(struct modinfo *modinfop)
3347836SJohn.Forte@Sun.COM {
3357836SJohn.Forte@Sun.COM 	return (mod_info(&modlinkage, modinfop));
3367836SJohn.Forte@Sun.COM }
3377836SJohn.Forte@Sun.COM 
3387836SJohn.Forte@Sun.COM /* ARGSUSED */
3397836SJohn.Forte@Sun.COM static int
fcsm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3407836SJohn.Forte@Sun.COM fcsm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3417836SJohn.Forte@Sun.COM {
3427836SJohn.Forte@Sun.COM 	int rval = DDI_FAILURE;
3437836SJohn.Forte@Sun.COM 
3447836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3457836SJohn.Forte@Sun.COM 	    "attach: cmd 0x%x", cmd));
3467836SJohn.Forte@Sun.COM 
3477836SJohn.Forte@Sun.COM 	switch (cmd) {
3487836SJohn.Forte@Sun.COM 	case DDI_ATTACH:
3497836SJohn.Forte@Sun.COM 		mutex_enter(&fcsm_global_mutex);
3507836SJohn.Forte@Sun.COM 		if (fcsm_dip != NULL) {
3517836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm_global_mutex);
3527836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3537836SJohn.Forte@Sun.COM 			    "attach: duplicate attach of fcsm!!"));
3547836SJohn.Forte@Sun.COM 			break;
3557836SJohn.Forte@Sun.COM 		}
3567836SJohn.Forte@Sun.COM 
3577836SJohn.Forte@Sun.COM 		fcsm_dip = dip;
3587836SJohn.Forte@Sun.COM 
3597836SJohn.Forte@Sun.COM 		/*
3607836SJohn.Forte@Sun.COM 		 * The detach routine cleans up all the port instances
3617836SJohn.Forte@Sun.COM 		 * i.e. it detaches all ports.
3627836SJohn.Forte@Sun.COM 		 * If _fini never got called after detach, then
3637836SJohn.Forte@Sun.COM 		 * perform an fc_ulp_remove() followed by fc_ulp_add()
3647836SJohn.Forte@Sun.COM 		 * to ensure that port_attach callbacks are called
3657836SJohn.Forte@Sun.COM 		 * again.
3667836SJohn.Forte@Sun.COM 		 */
3677836SJohn.Forte@Sun.COM 		if (fcsm_detached) {
3687836SJohn.Forte@Sun.COM 			int status;
3697836SJohn.Forte@Sun.COM 
3707836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3717836SJohn.Forte@Sun.COM 			    "attach: rebinding to transport driver"));
3727836SJohn.Forte@Sun.COM 
3737836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm_global_mutex);
3747836SJohn.Forte@Sun.COM 
3757836SJohn.Forte@Sun.COM 			(void) fc_ulp_remove(&fcsm_modinfo);
3767836SJohn.Forte@Sun.COM 
3777836SJohn.Forte@Sun.COM 			/*
3787836SJohn.Forte@Sun.COM 			 * Reset the detached flag, so that ports can attach
3797836SJohn.Forte@Sun.COM 			 */
3807836SJohn.Forte@Sun.COM 			mutex_enter(&fcsm_global_mutex);
3817836SJohn.Forte@Sun.COM 			fcsm_detached = 0;
3827836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm_global_mutex);
3837836SJohn.Forte@Sun.COM 
3847836SJohn.Forte@Sun.COM 			status = fc_ulp_add(&fcsm_modinfo);
3857836SJohn.Forte@Sun.COM 
3867836SJohn.Forte@Sun.COM 			if (status != 0) {
3877836SJohn.Forte@Sun.COM 				/*
3887836SJohn.Forte@Sun.COM 				 * ULP add failed. So set the
3897836SJohn.Forte@Sun.COM 				 * detached flag again
3907836SJohn.Forte@Sun.COM 				 */
3917836SJohn.Forte@Sun.COM 				mutex_enter(&fcsm_global_mutex);
3927836SJohn.Forte@Sun.COM 				fcsm_detached = 1;
3937836SJohn.Forte@Sun.COM 				mutex_exit(&fcsm_global_mutex);
3947836SJohn.Forte@Sun.COM 
3957836SJohn.Forte@Sun.COM 				switch (status) {
3967836SJohn.Forte@Sun.COM 				case FC_ULP_SAMEMODULE:
3977836SJohn.Forte@Sun.COM 					fcsm_display(CE_WARN, SM_LOG, NULL,
3987836SJohn.Forte@Sun.COM 					    NULL, "attach: FC SAN Management "
3997836SJohn.Forte@Sun.COM 					    "module is already "
4007836SJohn.Forte@Sun.COM 					    "registered with transport layer");
4017836SJohn.Forte@Sun.COM 					break;
4027836SJohn.Forte@Sun.COM 
4037836SJohn.Forte@Sun.COM 				case FC_ULP_SAMETYPE:
4047836SJohn.Forte@Sun.COM 					fcsm_display(CE_WARN, SM_LOG, NULL,
4057836SJohn.Forte@Sun.COM 					    NULL, "attach: Another module with "
4067836SJohn.Forte@Sun.COM 					    "same type 0x%x is already "
4077836SJohn.Forte@Sun.COM 					    "registered with transport layer",
4087836SJohn.Forte@Sun.COM 					    fcsm_modinfo.ulp_type);
4097836SJohn.Forte@Sun.COM 					break;
4107836SJohn.Forte@Sun.COM 
4117836SJohn.Forte@Sun.COM 				case FC_BADULP:
4127836SJohn.Forte@Sun.COM 					fcsm_display(CE_WARN, SM_LOG, NULL,
4137836SJohn.Forte@Sun.COM 					    NULL, "attach: Please upgrade this "
4147836SJohn.Forte@Sun.COM 					    "module. Current version 0x%x is "
4157836SJohn.Forte@Sun.COM 					    "not the most recent version",
4167836SJohn.Forte@Sun.COM 					    fcsm_modinfo.ulp_rev);
4177836SJohn.Forte@Sun.COM 					break;
4187836SJohn.Forte@Sun.COM 				default:
4197836SJohn.Forte@Sun.COM 					fcsm_display(CE_WARN, SM_LOG, NULL,
4207836SJohn.Forte@Sun.COM 					    NULL, "attach: fc_ulp_add failed "
4217836SJohn.Forte@Sun.COM 					    "with status 0x%x", status);
4227836SJohn.Forte@Sun.COM 					break;
4237836SJohn.Forte@Sun.COM 				}
4247836SJohn.Forte@Sun.COM 
4257836SJohn.Forte@Sun.COM 				/* Return failure */
4267836SJohn.Forte@Sun.COM 				break;
4277836SJohn.Forte@Sun.COM 			}
4287836SJohn.Forte@Sun.COM 
4297836SJohn.Forte@Sun.COM 			mutex_enter(&fcsm_global_mutex);
4307836SJohn.Forte@Sun.COM 		}
4317836SJohn.Forte@Sun.COM 
4327836SJohn.Forte@Sun.COM 		/* Create a minor node */
4337836SJohn.Forte@Sun.COM 		if (ddi_create_minor_node(fcsm_dip, "fcsm", S_IFCHR,
4347836SJohn.Forte@Sun.COM 		    NULL, DDI_PSEUDO, 0) == DDI_SUCCESS) {
4357836SJohn.Forte@Sun.COM 			/* Announce presence of the device */
4367836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm_global_mutex);
4377836SJohn.Forte@Sun.COM 			ddi_report_dev(dip);
4387836SJohn.Forte@Sun.COM 			rval = DDI_SUCCESS;
4397836SJohn.Forte@Sun.COM 		} else {
4407836SJohn.Forte@Sun.COM 			fcsm_dip = NULL;
4417836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm_global_mutex);
4427836SJohn.Forte@Sun.COM 			fcsm_display(CE_WARN, SM_LOG_AND_CONSOLE,
4437836SJohn.Forte@Sun.COM 			    NULL, NULL, "attach: create minor node failed");
4447836SJohn.Forte@Sun.COM 		}
4457836SJohn.Forte@Sun.COM 		break;
4467836SJohn.Forte@Sun.COM 
4477836SJohn.Forte@Sun.COM 	case DDI_RESUME:
4487836SJohn.Forte@Sun.COM 		rval = DDI_SUCCESS;
4497836SJohn.Forte@Sun.COM 		break;
4507836SJohn.Forte@Sun.COM 
4517836SJohn.Forte@Sun.COM 	default:
4527836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
4537836SJohn.Forte@Sun.COM 		    "attach: unknown cmd 0x%x dip 0x%p", cmd, dip));
4547836SJohn.Forte@Sun.COM 		break;
4557836SJohn.Forte@Sun.COM 	}
4567836SJohn.Forte@Sun.COM 
4577836SJohn.Forte@Sun.COM 	return (rval);
4587836SJohn.Forte@Sun.COM }
4597836SJohn.Forte@Sun.COM 
4607836SJohn.Forte@Sun.COM /* ARGSUSED */
4617836SJohn.Forte@Sun.COM static int
fcsm_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)4627836SJohn.Forte@Sun.COM fcsm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
4637836SJohn.Forte@Sun.COM {
4647836SJohn.Forte@Sun.COM 	int	instance;
4657836SJohn.Forte@Sun.COM 	int	rval = DDI_SUCCESS;
4667836SJohn.Forte@Sun.COM 
4677836SJohn.Forte@Sun.COM 	instance = getminor((dev_t)arg);
4687836SJohn.Forte@Sun.COM 
4697836SJohn.Forte@Sun.COM 	switch (cmd) {
4707836SJohn.Forte@Sun.COM 	case DDI_INFO_DEVT2INSTANCE:
4717836SJohn.Forte@Sun.COM 		*result = (void *)(long)instance; /* minor number is instance */
4727836SJohn.Forte@Sun.COM 		break;
4737836SJohn.Forte@Sun.COM 
4747836SJohn.Forte@Sun.COM 	case DDI_INFO_DEVT2DEVINFO:
4757836SJohn.Forte@Sun.COM 		mutex_enter(&fcsm_global_mutex);
4767836SJohn.Forte@Sun.COM 		*result = (void *)fcsm_dip;
4777836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm_global_mutex);
4787836SJohn.Forte@Sun.COM 		break;
4797836SJohn.Forte@Sun.COM 
4807836SJohn.Forte@Sun.COM 	default:
4817836SJohn.Forte@Sun.COM 		rval = DDI_FAILURE;
4827836SJohn.Forte@Sun.COM 		break;
4837836SJohn.Forte@Sun.COM 	}
4847836SJohn.Forte@Sun.COM 
4857836SJohn.Forte@Sun.COM 	return (rval);
4867836SJohn.Forte@Sun.COM }
4877836SJohn.Forte@Sun.COM 
4887836SJohn.Forte@Sun.COM 
4897836SJohn.Forte@Sun.COM /* ARGSUSED */
4907836SJohn.Forte@Sun.COM static int
fcsm_port_attach(opaque_t ulph,fc_ulp_port_info_t * pinfo,fc_attach_cmd_t cmd,uint32_t s_id)4917836SJohn.Forte@Sun.COM fcsm_port_attach(opaque_t ulph, fc_ulp_port_info_t *pinfo,
4927836SJohn.Forte@Sun.COM     fc_attach_cmd_t cmd, uint32_t s_id)
4937836SJohn.Forte@Sun.COM {
4947836SJohn.Forte@Sun.COM 	int	instance;
4957836SJohn.Forte@Sun.COM 	int	rval = FC_FAILURE;
4967836SJohn.Forte@Sun.COM 
4977836SJohn.Forte@Sun.COM 	instance = ddi_get_instance(pinfo->port_dip);
4987836SJohn.Forte@Sun.COM 
4997836SJohn.Forte@Sun.COM 	/*
5007836SJohn.Forte@Sun.COM 	 * Set the attaching flag, so that fcsm_detach will fail, if
5017836SJohn.Forte@Sun.COM 	 * port attach is in progress.
5027836SJohn.Forte@Sun.COM 	 */
5037836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm_global_mutex);
5047836SJohn.Forte@Sun.COM 	if (fcsm_detached) {
5057836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm_global_mutex);
5067836SJohn.Forte@Sun.COM 
5077836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
5087836SJohn.Forte@Sun.COM 		    "port_attach: end. detach in progress. failing attach "
5097836SJohn.Forte@Sun.COM 		    "instance 0x%x", instance));
5107836SJohn.Forte@Sun.COM 		return (((cmd == FC_CMD_POWER_UP) || (cmd == FC_CMD_RESUME)) ?
5117836SJohn.Forte@Sun.COM 		    FC_FAILURE_SILENT : FC_FAILURE);
5127836SJohn.Forte@Sun.COM 	}
5137836SJohn.Forte@Sun.COM 
5147836SJohn.Forte@Sun.COM 	fcsm_num_attaching++;
5157836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm_global_mutex);
5167836SJohn.Forte@Sun.COM 
5177836SJohn.Forte@Sun.COM 	switch (cmd) {
5187836SJohn.Forte@Sun.COM 	case FC_CMD_ATTACH:
5197836SJohn.Forte@Sun.COM 		if (fcsm_handle_port_attach(pinfo, s_id, instance)
5207836SJohn.Forte@Sun.COM 		    != DDI_SUCCESS) {
5217836SJohn.Forte@Sun.COM 			ASSERT(ddi_get_soft_state(fcsm_state,
5227836SJohn.Forte@Sun.COM 			    instance) == NULL);
5237836SJohn.Forte@Sun.COM 			break;
5247836SJohn.Forte@Sun.COM 		}
5257836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
5267836SJohn.Forte@Sun.COM 		break;
5277836SJohn.Forte@Sun.COM 
5287836SJohn.Forte@Sun.COM 	case FC_CMD_RESUME:
5297836SJohn.Forte@Sun.COM 	case FC_CMD_POWER_UP: {
5307836SJohn.Forte@Sun.COM 		fcsm_t	*fcsm;
5317836SJohn.Forte@Sun.COM 		char fcsm_pathname[MAXPATHLEN];
5327836SJohn.Forte@Sun.COM 
5337836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
5347836SJohn.Forte@Sun.COM 		    "port_attach: cmd 0x%x instance 0x%x", cmd, instance));
5357836SJohn.Forte@Sun.COM 
5367836SJohn.Forte@Sun.COM 		/* Get the soft state structure */
5377836SJohn.Forte@Sun.COM 		if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) {
5387836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
5397836SJohn.Forte@Sun.COM 			    "port_attach: instance 0x%x, cmd 0x%x "
5407836SJohn.Forte@Sun.COM 			    "get softstate failed", instance, cmd));
5417836SJohn.Forte@Sun.COM 			break;
5427836SJohn.Forte@Sun.COM 		}
5437836SJohn.Forte@Sun.COM 
5447836SJohn.Forte@Sun.COM 		ASSERT(fcsm->sm_instance == instance);
5457836SJohn.Forte@Sun.COM 
5467836SJohn.Forte@Sun.COM 		/* If this instance is not attached, then return failure */
5477836SJohn.Forte@Sun.COM 		mutex_enter(&fcsm->sm_mutex);
5487836SJohn.Forte@Sun.COM 		if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) {
5497836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm->sm_mutex);
5507836SJohn.Forte@Sun.COM 			fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
5517836SJohn.Forte@Sun.COM 			    "port_detach: port is not attached");
5527836SJohn.Forte@Sun.COM 			break;
5537836SJohn.Forte@Sun.COM 		}
5547836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
5557836SJohn.Forte@Sun.COM 
5567836SJohn.Forte@Sun.COM 		if (fcsm_handle_port_resume(ulph, pinfo, cmd, s_id, fcsm) !=
5577836SJohn.Forte@Sun.COM 		    DDI_SUCCESS) {
5587836SJohn.Forte@Sun.COM 			break;
5597836SJohn.Forte@Sun.COM 		}
5607836SJohn.Forte@Sun.COM 
5617836SJohn.Forte@Sun.COM 		(void) ddi_pathname(fcsm->sm_port_info.port_dip, fcsm_pathname);
5627836SJohn.Forte@Sun.COM 		fcsm_display(CE_NOTE, SM_LOG, fcsm, NULL,
5637836SJohn.Forte@Sun.COM 		    "attached to path %s", fcsm_pathname);
5647836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
5657836SJohn.Forte@Sun.COM 		break;
5667836SJohn.Forte@Sun.COM 	}
5677836SJohn.Forte@Sun.COM 
5687836SJohn.Forte@Sun.COM 	default:
5697836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
5707836SJohn.Forte@Sun.COM 		    "port_attach: unknown cmd 0x%x for port 0x%x",
5717836SJohn.Forte@Sun.COM 		    cmd, instance));
5727836SJohn.Forte@Sun.COM 		break;
5737836SJohn.Forte@Sun.COM 	}
5747836SJohn.Forte@Sun.COM 
5757836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm_global_mutex);
5767836SJohn.Forte@Sun.COM 	fcsm_num_attaching--;
5777836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm_global_mutex);
5787836SJohn.Forte@Sun.COM 	return (rval);
5797836SJohn.Forte@Sun.COM }
5807836SJohn.Forte@Sun.COM 
5817836SJohn.Forte@Sun.COM 
5827836SJohn.Forte@Sun.COM static int
fcsm_handle_port_attach(fc_ulp_port_info_t * pinfo,uint32_t s_id,int instance)5837836SJohn.Forte@Sun.COM fcsm_handle_port_attach(fc_ulp_port_info_t *pinfo, uint32_t s_id, int instance)
5847836SJohn.Forte@Sun.COM {
5857836SJohn.Forte@Sun.COM 	fcsm_t		*fcsm;
5867836SJohn.Forte@Sun.COM 	kthread_t	*thread;
5877836SJohn.Forte@Sun.COM 	char		name[32];
5887836SJohn.Forte@Sun.COM 	char fcsm_pathname[MAXPATHLEN];
5897836SJohn.Forte@Sun.COM 
5907836SJohn.Forte@Sun.COM 	/* Allocate a soft state structure for the port */
5917836SJohn.Forte@Sun.COM 	if (ddi_soft_state_zalloc(fcsm_state, instance) != DDI_SUCCESS) {
5927836SJohn.Forte@Sun.COM 		fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
5937836SJohn.Forte@Sun.COM 		    "port_attach: instance 0x%x, soft state alloc failed",
5947836SJohn.Forte@Sun.COM 		    instance);
5957836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
5967836SJohn.Forte@Sun.COM 	}
5977836SJohn.Forte@Sun.COM 
5987836SJohn.Forte@Sun.COM 	if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) {
5997836SJohn.Forte@Sun.COM 		fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
6007836SJohn.Forte@Sun.COM 		    "port_attach: instance 0x%x, get soft state failed",
6017836SJohn.Forte@Sun.COM 		    instance);
6027836SJohn.Forte@Sun.COM 		ddi_soft_state_free(fcsm_state, instance);
6037836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
6047836SJohn.Forte@Sun.COM 	}
6057836SJohn.Forte@Sun.COM 
6067836SJohn.Forte@Sun.COM 
6077836SJohn.Forte@Sun.COM 	/* Initialize the mutex */
6087836SJohn.Forte@Sun.COM 	mutex_init(&fcsm->sm_mutex, NULL, MUTEX_DRIVER, NULL);
6097836SJohn.Forte@Sun.COM 	cv_init(&fcsm->sm_job_cv, NULL, CV_DRIVER, NULL);
6107836SJohn.Forte@Sun.COM 
6117836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
6127836SJohn.Forte@Sun.COM 	fcsm->sm_flags		|= FCSM_ATTACHING;
6137836SJohn.Forte@Sun.COM 	fcsm->sm_sid		= s_id;
6147836SJohn.Forte@Sun.COM 	fcsm->sm_instance	= instance;
6157836SJohn.Forte@Sun.COM 	fcsm->sm_port_state	= pinfo->port_state;
6167836SJohn.Forte@Sun.COM 
6177836SJohn.Forte@Sun.COM 	/*
6187836SJohn.Forte@Sun.COM 	 * Make a copy of the port_information structure, since fctl
6197836SJohn.Forte@Sun.COM 	 * uses a temporary structure.
6207836SJohn.Forte@Sun.COM 	 */
6217836SJohn.Forte@Sun.COM 	fcsm->sm_port_info	= *pinfo;	/* Structure copy !!! */
6227836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
6237836SJohn.Forte@Sun.COM 
6247836SJohn.Forte@Sun.COM 
6257836SJohn.Forte@Sun.COM 	(void) sprintf(name, "fcsm%d_cmd_cache", fcsm->sm_instance);
6267836SJohn.Forte@Sun.COM 	fcsm->sm_cmd_cache = kmem_cache_create(name,
6277836SJohn.Forte@Sun.COM 	    sizeof (fcsm_cmd_t) + pinfo->port_fca_pkt_size, 8,
6287836SJohn.Forte@Sun.COM 	    fcsm_cmd_cache_constructor, fcsm_cmd_cache_destructor,
6297836SJohn.Forte@Sun.COM 	    NULL, (void *)fcsm, NULL, 0);
6307836SJohn.Forte@Sun.COM 	if (fcsm->sm_cmd_cache == NULL) {
6317836SJohn.Forte@Sun.COM 		fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
6327836SJohn.Forte@Sun.COM 		    "port_attach: pkt cache create failed");
6337836SJohn.Forte@Sun.COM 		cv_destroy(&fcsm->sm_job_cv);
6347836SJohn.Forte@Sun.COM 		mutex_destroy(&fcsm->sm_mutex);
6357836SJohn.Forte@Sun.COM 		ddi_soft_state_free(fcsm_state, instance);
6367836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
6377836SJohn.Forte@Sun.COM 	}
6387836SJohn.Forte@Sun.COM 
6397836SJohn.Forte@Sun.COM 	thread = thread_create((caddr_t)NULL, 0, fcsm_job_thread,
6407836SJohn.Forte@Sun.COM 	    (caddr_t)fcsm, 0, &p0, TS_RUN, v.v_maxsyspri-2);
6417836SJohn.Forte@Sun.COM 	if (thread == NULL) {
6427836SJohn.Forte@Sun.COM 		fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
6437836SJohn.Forte@Sun.COM 		    "port_attach: job thread create failed");
6447836SJohn.Forte@Sun.COM 		kmem_cache_destroy(fcsm->sm_cmd_cache);
6457836SJohn.Forte@Sun.COM 		cv_destroy(&fcsm->sm_job_cv);
6467836SJohn.Forte@Sun.COM 		mutex_destroy(&fcsm->sm_mutex);
6477836SJohn.Forte@Sun.COM 		ddi_soft_state_free(fcsm_state, instance);
6487836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
6497836SJohn.Forte@Sun.COM 	}
6507836SJohn.Forte@Sun.COM 
6517836SJohn.Forte@Sun.COM 	fcsm->sm_thread = thread;
6527836SJohn.Forte@Sun.COM 
6537836SJohn.Forte@Sun.COM 	/* Add this structure to fcsm global linked list */
6547836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm_global_mutex);
6557836SJohn.Forte@Sun.COM 	if (fcsm_port_head == NULL) {
6567836SJohn.Forte@Sun.COM 		fcsm_port_head = fcsm;
6577836SJohn.Forte@Sun.COM 	} else {
6587836SJohn.Forte@Sun.COM 		fcsm->sm_next = fcsm_port_head;
6597836SJohn.Forte@Sun.COM 		fcsm_port_head = fcsm;
6607836SJohn.Forte@Sun.COM 	}
6617836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm_global_mutex);
6627836SJohn.Forte@Sun.COM 
6637836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
6647836SJohn.Forte@Sun.COM 	fcsm->sm_flags &= ~FCSM_ATTACHING;
6657836SJohn.Forte@Sun.COM 	fcsm->sm_flags |= FCSM_ATTACHED;
6667836SJohn.Forte@Sun.COM 	fcsm->sm_port_top = pinfo->port_flags;
6677836SJohn.Forte@Sun.COM 	fcsm->sm_port_state = pinfo->port_state;
668*10264SZhong.Wang@Sun.COM 	if (pinfo->port_acc_attr == NULL) {
669*10264SZhong.Wang@Sun.COM 		/*
670*10264SZhong.Wang@Sun.COM 		 * The corresponding FCA doesn't support DMA at all
671*10264SZhong.Wang@Sun.COM 		 */
672*10264SZhong.Wang@Sun.COM 		fcsm->sm_flags |= FCSM_USING_NODMA_FCA;
673*10264SZhong.Wang@Sun.COM 	}
6747836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
6757836SJohn.Forte@Sun.COM 
6767836SJohn.Forte@Sun.COM 	(void) ddi_pathname(fcsm->sm_port_info.port_dip, fcsm_pathname);
6777836SJohn.Forte@Sun.COM 	fcsm_display(CE_NOTE, SM_LOG, fcsm, NULL,
6787836SJohn.Forte@Sun.COM 	    "attached to path %s", fcsm_pathname);
6797836SJohn.Forte@Sun.COM 
6807836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
6817836SJohn.Forte@Sun.COM 	    "port_attach: state <%s>(0x%x) topology <%s>(0x%x)",
6827836SJohn.Forte@Sun.COM 	    fcsm_port_state_to_str(FC_PORT_STATE_MASK(pinfo->port_state)),
6837836SJohn.Forte@Sun.COM 	    pinfo->port_state,
6847836SJohn.Forte@Sun.COM 	    fcsm_topology_to_str(pinfo->port_flags), pinfo->port_flags));
6857836SJohn.Forte@Sun.COM 
6867836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
6877836SJohn.Forte@Sun.COM }
6887836SJohn.Forte@Sun.COM 
6897836SJohn.Forte@Sun.COM static int
fcsm_handle_port_resume(opaque_t ulph,fc_ulp_port_info_t * pinfo,fc_attach_cmd_t cmd,uint32_t s_id,fcsm_t * fcsm)6907836SJohn.Forte@Sun.COM fcsm_handle_port_resume(opaque_t ulph, fc_ulp_port_info_t *pinfo,
6917836SJohn.Forte@Sun.COM     fc_attach_cmd_t cmd, uint32_t s_id, fcsm_t *fcsm)
6927836SJohn.Forte@Sun.COM {
6937836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
6947836SJohn.Forte@Sun.COM 	    "port_resume: cmd 0x%x", cmd));
6957836SJohn.Forte@Sun.COM 
6967836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
6977836SJohn.Forte@Sun.COM 
6987836SJohn.Forte@Sun.COM 	switch (cmd) {
6997836SJohn.Forte@Sun.COM 	case FC_CMD_RESUME:
7007836SJohn.Forte@Sun.COM 		ASSERT(!(fcsm->sm_flags & FCSM_POWER_DOWN));
7017836SJohn.Forte@Sun.COM 		fcsm->sm_flags &= ~FCSM_SUSPENDED;
7027836SJohn.Forte@Sun.COM 		break;
7037836SJohn.Forte@Sun.COM 
7047836SJohn.Forte@Sun.COM 	case FC_CMD_POWER_UP:
7057836SJohn.Forte@Sun.COM 		/* If port is suspended, then no need to resume */
7067836SJohn.Forte@Sun.COM 		fcsm->sm_flags &= ~FCSM_POWER_DOWN;
7077836SJohn.Forte@Sun.COM 		if (fcsm->sm_flags & FCSM_SUSPENDED) {
7087836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm->sm_mutex);
7097836SJohn.Forte@Sun.COM 			return (DDI_SUCCESS);
7107836SJohn.Forte@Sun.COM 		}
7117836SJohn.Forte@Sun.COM 		break;
7127836SJohn.Forte@Sun.COM 	default:
7137836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
7147836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
7157836SJohn.Forte@Sun.COM 	}
7167836SJohn.Forte@Sun.COM 
7177836SJohn.Forte@Sun.COM 	fcsm->sm_sid = s_id;
7187836SJohn.Forte@Sun.COM 
7197836SJohn.Forte@Sun.COM 	/*
7207836SJohn.Forte@Sun.COM 	 * Make a copy of the new port_information structure
7217836SJohn.Forte@Sun.COM 	 */
7227836SJohn.Forte@Sun.COM 	fcsm->sm_port_info	= *pinfo;	/* Structure copy !!! */
7237836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
7247836SJohn.Forte@Sun.COM 
7257836SJohn.Forte@Sun.COM 	fcsm_resume_port(fcsm);
7267836SJohn.Forte@Sun.COM 
7277836SJohn.Forte@Sun.COM 	/*
7287836SJohn.Forte@Sun.COM 	 * Invoke state change processing.
7297836SJohn.Forte@Sun.COM 	 * This will ensure that
7307836SJohn.Forte@Sun.COM 	 *    - offline timer is started if new port state changed to offline.
7317836SJohn.Forte@Sun.COM 	 *    - MGMT_SERVER_LOGIN flag is reset.
7327836SJohn.Forte@Sun.COM 	 *    - Port topology is updated.
7337836SJohn.Forte@Sun.COM 	 */
7347836SJohn.Forte@Sun.COM 	fcsm_statec_cb(ulph, (opaque_t)pinfo->port_handle, pinfo->port_state,
7357836SJohn.Forte@Sun.COM 	    pinfo->port_flags, NULL, 0, s_id);
7367836SJohn.Forte@Sun.COM 
7377836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
7387836SJohn.Forte@Sun.COM }
7397836SJohn.Forte@Sun.COM 
7407836SJohn.Forte@Sun.COM 
7417836SJohn.Forte@Sun.COM /* ARGSUSED */
7427836SJohn.Forte@Sun.COM static int
fcsm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)7437836SJohn.Forte@Sun.COM fcsm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
7447836SJohn.Forte@Sun.COM {
7457836SJohn.Forte@Sun.COM 	int	rval = DDI_SUCCESS;
7467836SJohn.Forte@Sun.COM 
7477836SJohn.Forte@Sun.COM 	switch (cmd) {
7487836SJohn.Forte@Sun.COM 	case DDI_DETACH: {
7497836SJohn.Forte@Sun.COM 		fcsm_t	*fcsm;
7507836SJohn.Forte@Sun.COM 
7517836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
7527836SJohn.Forte@Sun.COM 		    "detach: start. cmd <DETACH>", cmd));
7537836SJohn.Forte@Sun.COM 
7547836SJohn.Forte@Sun.COM 		mutex_enter(&fcsm_global_mutex);
7557836SJohn.Forte@Sun.COM 
7567836SJohn.Forte@Sun.COM 		/*
7577836SJohn.Forte@Sun.COM 		 * If port attach/detach in progress, then wait for 5 seconds
7587836SJohn.Forte@Sun.COM 		 * for them to complete.
7597836SJohn.Forte@Sun.COM 		 */
7607836SJohn.Forte@Sun.COM 		if (fcsm_num_attaching || fcsm_num_detaching) {
7617836SJohn.Forte@Sun.COM 			int count;
7627836SJohn.Forte@Sun.COM 
7637836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
7647836SJohn.Forte@Sun.COM 			    "detach: wait for port attach/detach to complete"));
7657836SJohn.Forte@Sun.COM 
7667836SJohn.Forte@Sun.COM 			count = 0;
7677836SJohn.Forte@Sun.COM 			while ((count++ <= 30) &&
7687836SJohn.Forte@Sun.COM 			    (fcsm_num_attaching || fcsm_num_detaching)) {
7697836SJohn.Forte@Sun.COM 				mutex_exit(&fcsm_global_mutex);
7707836SJohn.Forte@Sun.COM 				delay(drv_usectohz(1000000));
7717836SJohn.Forte@Sun.COM 				mutex_enter(&fcsm_global_mutex);
7727836SJohn.Forte@Sun.COM 			}
7737836SJohn.Forte@Sun.COM 
7747836SJohn.Forte@Sun.COM 			/* Port attach/detach still in prog, so fail detach */
7757836SJohn.Forte@Sun.COM 			if (fcsm_num_attaching || fcsm_num_detaching) {
7767836SJohn.Forte@Sun.COM 				mutex_exit(&fcsm_global_mutex);
7777836SJohn.Forte@Sun.COM 				FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL,
7787836SJohn.Forte@Sun.COM 				    NULL, "detach: Failing detach. port "
7797836SJohn.Forte@Sun.COM 				    "attach/detach in progress"));
7807836SJohn.Forte@Sun.COM 				rval = DDI_FAILURE;
7817836SJohn.Forte@Sun.COM 				break;
7827836SJohn.Forte@Sun.COM 			}
7837836SJohn.Forte@Sun.COM 		}
7847836SJohn.Forte@Sun.COM 
7857836SJohn.Forte@Sun.COM 		if (fcsm_port_head == NULL) {
7867836SJohn.Forte@Sun.COM 			/* Not much do, Succeed to detach. */
7877836SJohn.Forte@Sun.COM 			ddi_remove_minor_node(fcsm_dip, NULL);
7887836SJohn.Forte@Sun.COM 			fcsm_dip = NULL;
7897836SJohn.Forte@Sun.COM 			fcsm_detached = 0;
7907836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm_global_mutex);
7917836SJohn.Forte@Sun.COM 			break;
7927836SJohn.Forte@Sun.COM 		}
7937836SJohn.Forte@Sun.COM 
7947836SJohn.Forte@Sun.COM 		/*
7957836SJohn.Forte@Sun.COM 		 * Check to see, if any ports are active.
7967836SJohn.Forte@Sun.COM 		 * If not, then set the DETACHING flag to indicate
7977836SJohn.Forte@Sun.COM 		 * that they are being detached.
7987836SJohn.Forte@Sun.COM 		 */
7997836SJohn.Forte@Sun.COM 		fcsm = fcsm_port_head;
8007836SJohn.Forte@Sun.COM 		while (fcsm != NULL) {
8017836SJohn.Forte@Sun.COM 
8027836SJohn.Forte@Sun.COM 			mutex_enter(&fcsm->sm_mutex);
8037836SJohn.Forte@Sun.COM 			if (!(fcsm->sm_flags & FCSM_ATTACHED) ||
8047836SJohn.Forte@Sun.COM 			    fcsm->sm_ncmds || fcsm->sm_cb_count) {
8057836SJohn.Forte@Sun.COM 				/* port is busy. We can't detach */
8067836SJohn.Forte@Sun.COM 				mutex_exit(&fcsm->sm_mutex);
8077836SJohn.Forte@Sun.COM 				break;
8087836SJohn.Forte@Sun.COM 			}
8097836SJohn.Forte@Sun.COM 
8107836SJohn.Forte@Sun.COM 			fcsm->sm_flags |= FCSM_DETACHING;
8117836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm->sm_mutex);
8127836SJohn.Forte@Sun.COM 
8137836SJohn.Forte@Sun.COM 			fcsm = fcsm->sm_next;
8147836SJohn.Forte@Sun.COM 		}
8157836SJohn.Forte@Sun.COM 
8167836SJohn.Forte@Sun.COM 		/*
8177836SJohn.Forte@Sun.COM 		 * If all ports could not be marked for detaching,
8187836SJohn.Forte@Sun.COM 		 * then clear the flags and fail the detach.
8197836SJohn.Forte@Sun.COM 		 * Also if a port attach is currently in progress
8207836SJohn.Forte@Sun.COM 		 * then fail the detach.
8217836SJohn.Forte@Sun.COM 		 */
8227836SJohn.Forte@Sun.COM 		if (fcsm != NULL || fcsm_num_attaching || fcsm_num_detaching) {
8237836SJohn.Forte@Sun.COM 			/*
8247836SJohn.Forte@Sun.COM 			 * Some ports were busy, so can't detach.
8257836SJohn.Forte@Sun.COM 			 * Clear the DETACHING flag and return failure
8267836SJohn.Forte@Sun.COM 			 */
8277836SJohn.Forte@Sun.COM 			fcsm = fcsm_port_head;
8287836SJohn.Forte@Sun.COM 			while (fcsm != NULL) {
8297836SJohn.Forte@Sun.COM 				mutex_enter(&fcsm->sm_mutex);
8307836SJohn.Forte@Sun.COM 				if (fcsm->sm_flags & FCSM_DETACHING) {
8317836SJohn.Forte@Sun.COM 					fcsm->sm_flags &= ~FCSM_DETACHING;
8327836SJohn.Forte@Sun.COM 				}
8337836SJohn.Forte@Sun.COM 				mutex_exit(&fcsm->sm_mutex);
8347836SJohn.Forte@Sun.COM 
8357836SJohn.Forte@Sun.COM 				fcsm = fcsm->sm_next;
8367836SJohn.Forte@Sun.COM 			}
8377836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm_global_mutex);
8387836SJohn.Forte@Sun.COM 			return (DDI_FAILURE);
8397836SJohn.Forte@Sun.COM 		} else {
8407836SJohn.Forte@Sun.COM 			fcsm_detached = 1;
8417836SJohn.Forte@Sun.COM 			/*
8427836SJohn.Forte@Sun.COM 			 * Mark all the detaching ports as detached, as we
8437836SJohn.Forte@Sun.COM 			 * will be detaching them
8447836SJohn.Forte@Sun.COM 			 */
8457836SJohn.Forte@Sun.COM 			fcsm = fcsm_port_head;
8467836SJohn.Forte@Sun.COM 			while (fcsm != NULL) {
8477836SJohn.Forte@Sun.COM 				mutex_enter(&fcsm->sm_mutex);
8487836SJohn.Forte@Sun.COM 				fcsm->sm_flags &= ~FCSM_DETACHING;
8497836SJohn.Forte@Sun.COM 				fcsm->sm_flags |= FCSM_DETACHED;
8507836SJohn.Forte@Sun.COM 				mutex_exit(&fcsm->sm_mutex);
8517836SJohn.Forte@Sun.COM 
8527836SJohn.Forte@Sun.COM 				fcsm = fcsm->sm_next;
8537836SJohn.Forte@Sun.COM 			}
8547836SJohn.Forte@Sun.COM 		}
8557836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm_global_mutex);
8567836SJohn.Forte@Sun.COM 
8577836SJohn.Forte@Sun.COM 
8587836SJohn.Forte@Sun.COM 		/*
8597836SJohn.Forte@Sun.COM 		 * Go ahead and detach the ports
8607836SJohn.Forte@Sun.COM 		 */
8617836SJohn.Forte@Sun.COM 		mutex_enter(&fcsm_global_mutex);
8627836SJohn.Forte@Sun.COM 		while (fcsm_port_head != NULL) {
8637836SJohn.Forte@Sun.COM 			fcsm = fcsm_port_head;
8647836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm_global_mutex);
8657836SJohn.Forte@Sun.COM 
8667836SJohn.Forte@Sun.COM 			/*
8677836SJohn.Forte@Sun.COM 			 * Call fcsm_cleanup_port(). This cleansup and
8687836SJohn.Forte@Sun.COM 			 * removes the fcsm structure from global linked list
8697836SJohn.Forte@Sun.COM 			 */
8707836SJohn.Forte@Sun.COM 			fcsm_cleanup_port(fcsm);
8717836SJohn.Forte@Sun.COM 
8727836SJohn.Forte@Sun.COM 			/*
8737836SJohn.Forte@Sun.COM 			 * Soft state cleanup done.
8747836SJohn.Forte@Sun.COM 			 * Remember that fcsm struct doesn't exist anymore.
8757836SJohn.Forte@Sun.COM 			 */
8767836SJohn.Forte@Sun.COM 
8777836SJohn.Forte@Sun.COM 			mutex_enter(&fcsm_global_mutex);
8787836SJohn.Forte@Sun.COM 		}
8797836SJohn.Forte@Sun.COM 
8807836SJohn.Forte@Sun.COM 		ddi_remove_minor_node(fcsm_dip, NULL);
8817836SJohn.Forte@Sun.COM 		fcsm_dip = NULL;
8827836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm_global_mutex);
8837836SJohn.Forte@Sun.COM 		break;
8847836SJohn.Forte@Sun.COM 	}
8857836SJohn.Forte@Sun.COM 
8867836SJohn.Forte@Sun.COM 	case DDI_SUSPEND:
8877836SJohn.Forte@Sun.COM 		rval = DDI_SUCCESS;
8887836SJohn.Forte@Sun.COM 		break;
8897836SJohn.Forte@Sun.COM 
8907836SJohn.Forte@Sun.COM 	default:
8917836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
8927836SJohn.Forte@Sun.COM 		    "detach: unknown cmd 0x%x", cmd));
8937836SJohn.Forte@Sun.COM 		rval = DDI_FAILURE;
8947836SJohn.Forte@Sun.COM 		break;
8957836SJohn.Forte@Sun.COM 	}
8967836SJohn.Forte@Sun.COM 
8977836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
8987836SJohn.Forte@Sun.COM 	    "detach: end. cmd 0x%x, rval 0x%x", cmd, rval));
8997836SJohn.Forte@Sun.COM 
9007836SJohn.Forte@Sun.COM 	return (rval);
9017836SJohn.Forte@Sun.COM }
9027836SJohn.Forte@Sun.COM 
9037836SJohn.Forte@Sun.COM 
9047836SJohn.Forte@Sun.COM /* ARGSUSED */
9057836SJohn.Forte@Sun.COM static void
fcsm_force_port_detach_all(void)9067836SJohn.Forte@Sun.COM fcsm_force_port_detach_all(void)
9077836SJohn.Forte@Sun.COM {
9087836SJohn.Forte@Sun.COM 	fcsm_t	*fcsm;
9097836SJohn.Forte@Sun.COM 
9107836SJohn.Forte@Sun.COM 	fcsm = fcsm_port_head;
9117836SJohn.Forte@Sun.COM 
9127836SJohn.Forte@Sun.COM 	while (fcsm) {
9137836SJohn.Forte@Sun.COM 		fcsm_cleanup_port(fcsm);
9147836SJohn.Forte@Sun.COM 		/*
9157836SJohn.Forte@Sun.COM 		 * fcsm_cleanup_port will remove the current fcsm structure
9167836SJohn.Forte@Sun.COM 		 * from the list, which will cause fcsm_port_head to point
9177836SJohn.Forte@Sun.COM 		 * to what would have been the next structure on the list.
9187836SJohn.Forte@Sun.COM 		 */
9197836SJohn.Forte@Sun.COM 		fcsm = fcsm_port_head;
9207836SJohn.Forte@Sun.COM 	}
9217836SJohn.Forte@Sun.COM }
9227836SJohn.Forte@Sun.COM 
9237836SJohn.Forte@Sun.COM 
9247836SJohn.Forte@Sun.COM /* ARGSUSED */
9257836SJohn.Forte@Sun.COM static int
fcsm_port_detach(opaque_t ulph,fc_ulp_port_info_t * pinfo,fc_detach_cmd_t cmd)9267836SJohn.Forte@Sun.COM fcsm_port_detach(opaque_t ulph, fc_ulp_port_info_t *pinfo, fc_detach_cmd_t cmd)
9277836SJohn.Forte@Sun.COM {
9287836SJohn.Forte@Sun.COM 	int	instance;
9297836SJohn.Forte@Sun.COM 	int	rval = FC_FAILURE;
9307836SJohn.Forte@Sun.COM 	fcsm_t	*fcsm;
9317836SJohn.Forte@Sun.COM 
9327836SJohn.Forte@Sun.COM 	instance = ddi_get_instance(pinfo->port_dip);
9337836SJohn.Forte@Sun.COM 
9347836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm_global_mutex);
9357836SJohn.Forte@Sun.COM 	if (fcsm_detached) {
9367836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm_global_mutex);
9377836SJohn.Forte@Sun.COM 
9387836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
9397836SJohn.Forte@Sun.COM 		    "port_detach: end. instance 0x%x, fcsm is detached",
9407836SJohn.Forte@Sun.COM 		    instance));
9417836SJohn.Forte@Sun.COM 		return (FC_SUCCESS);
9427836SJohn.Forte@Sun.COM 	}
9437836SJohn.Forte@Sun.COM 	fcsm_num_detaching++;	/* Set the flag */
9447836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm_global_mutex);
9457836SJohn.Forte@Sun.COM 
9467836SJohn.Forte@Sun.COM 	/* Get the soft state structure */
9477836SJohn.Forte@Sun.COM 	if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) {
9487836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
9497836SJohn.Forte@Sun.COM 		    "port_detach: instance 0x%x, cmd 0x%x get softstate failed",
9507836SJohn.Forte@Sun.COM 		    instance, cmd));
9517836SJohn.Forte@Sun.COM 		mutex_enter(&fcsm_global_mutex);
9527836SJohn.Forte@Sun.COM 		fcsm_num_detaching--;
9537836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm_global_mutex);
9547836SJohn.Forte@Sun.COM 		return (rval);
9557836SJohn.Forte@Sun.COM 	}
9567836SJohn.Forte@Sun.COM 
9577836SJohn.Forte@Sun.COM 	ASSERT(fcsm->sm_instance == instance);
9587836SJohn.Forte@Sun.COM 
9597836SJohn.Forte@Sun.COM 	/* If this instance is not attached, then fail the detach */
9607836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
9617836SJohn.Forte@Sun.COM 	if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) {
9627836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
9637836SJohn.Forte@Sun.COM 		fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
9647836SJohn.Forte@Sun.COM 		    "port_detach: port is not attached");
9657836SJohn.Forte@Sun.COM 		mutex_enter(&fcsm_global_mutex);
9667836SJohn.Forte@Sun.COM 		fcsm_num_detaching--;
9677836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm_global_mutex);
9687836SJohn.Forte@Sun.COM 		return (rval);
9697836SJohn.Forte@Sun.COM 	}
9707836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
9717836SJohn.Forte@Sun.COM 
9727836SJohn.Forte@Sun.COM 	/*
9737836SJohn.Forte@Sun.COM 	 * If fcsm has been detached, then all instance has already been
9747836SJohn.Forte@Sun.COM 	 * detached or are being detached. So succeed this detach.
9757836SJohn.Forte@Sun.COM 	 */
9767836SJohn.Forte@Sun.COM 
9777836SJohn.Forte@Sun.COM 	switch (cmd) {
978*10264SZhong.Wang@Sun.COM 	case FC_CMD_DETACH:
979*10264SZhong.Wang@Sun.COM 	case FC_CMD_SUSPEND:
980*10264SZhong.Wang@Sun.COM 	case FC_CMD_POWER_DOWN:
981*10264SZhong.Wang@Sun.COM 		break;
982*10264SZhong.Wang@Sun.COM 
983*10264SZhong.Wang@Sun.COM 	default:
984*10264SZhong.Wang@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
985*10264SZhong.Wang@Sun.COM 		    "port_detach: port unknown cmd 0x%x", cmd));
986*10264SZhong.Wang@Sun.COM 		mutex_enter(&fcsm_global_mutex);
987*10264SZhong.Wang@Sun.COM 		fcsm_num_detaching--;
988*10264SZhong.Wang@Sun.COM 		mutex_exit(&fcsm_global_mutex);
989*10264SZhong.Wang@Sun.COM 		return (rval);
9907836SJohn.Forte@Sun.COM 	};
9917836SJohn.Forte@Sun.COM 
9927836SJohn.Forte@Sun.COM 	if (fcsm_handle_port_detach(pinfo, fcsm, cmd) == DDI_SUCCESS) {
9937836SJohn.Forte@Sun.COM 		rval = FC_SUCCESS;
9947836SJohn.Forte@Sun.COM 	}
9957836SJohn.Forte@Sun.COM 
9967836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm_global_mutex);
9977836SJohn.Forte@Sun.COM 	fcsm_num_detaching--;
9987836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm_global_mutex);
9997836SJohn.Forte@Sun.COM 
10007836SJohn.Forte@Sun.COM 	/* If it was a detach, then fcsm state structure no longer exists */
10017836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
10027836SJohn.Forte@Sun.COM 	    "port_detach: end. cmd 0x%x rval 0x%x", cmd, rval));
10037836SJohn.Forte@Sun.COM 	return (rval);
10047836SJohn.Forte@Sun.COM }
10057836SJohn.Forte@Sun.COM 
10067836SJohn.Forte@Sun.COM 
10077836SJohn.Forte@Sun.COM static int
fcsm_handle_port_detach(fc_ulp_port_info_t * pinfo,fcsm_t * fcsm,fc_detach_cmd_t cmd)10087836SJohn.Forte@Sun.COM fcsm_handle_port_detach(fc_ulp_port_info_t *pinfo, fcsm_t *fcsm,
10097836SJohn.Forte@Sun.COM     fc_detach_cmd_t cmd)
10107836SJohn.Forte@Sun.COM {
10117836SJohn.Forte@Sun.COM 	uint32_t	flag;
10127836SJohn.Forte@Sun.COM 	int		count;
10137836SJohn.Forte@Sun.COM #ifdef DEBUG
10147836SJohn.Forte@Sun.COM 	char		pathname[MAXPATHLEN];
10157836SJohn.Forte@Sun.COM #endif /* DEBUG */
10167836SJohn.Forte@Sun.COM 
10177836SJohn.Forte@Sun.COM 	/*
10187836SJohn.Forte@Sun.COM 	 * If port is already powered down OR suspended and there is nothing
10197836SJohn.Forte@Sun.COM 	 * else to do then just return.
10207836SJohn.Forte@Sun.COM 	 * Otherwise, set the flag, so that no more new activity will be
10217836SJohn.Forte@Sun.COM 	 * initiated on this port.
10227836SJohn.Forte@Sun.COM 	 */
10237836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
10247836SJohn.Forte@Sun.COM 
10257836SJohn.Forte@Sun.COM 	switch (cmd) {
1026*10264SZhong.Wang@Sun.COM 	case FC_CMD_DETACH:
1027*10264SZhong.Wang@Sun.COM 		flag = FCSM_DETACHING;
1028*10264SZhong.Wang@Sun.COM 		break;
1029*10264SZhong.Wang@Sun.COM 
1030*10264SZhong.Wang@Sun.COM 	case FC_CMD_SUSPEND:
1031*10264SZhong.Wang@Sun.COM 	case FC_CMD_POWER_DOWN:
1032*10264SZhong.Wang@Sun.COM 		((cmd == FC_CMD_SUSPEND) ? (flag = FCSM_SUSPENDED) :
1033*10264SZhong.Wang@Sun.COM 		    (flag = FCSM_POWER_DOWN));
1034*10264SZhong.Wang@Sun.COM 		if (fcsm->sm_flags &
1035*10264SZhong.Wang@Sun.COM 		    (FCSM_POWER_DOWN | FCSM_SUSPENDED)) {
1036*10264SZhong.Wang@Sun.COM 			fcsm->sm_flags |= flag;
10377836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm->sm_mutex);
1038*10264SZhong.Wang@Sun.COM 			return (DDI_SUCCESS);
1039*10264SZhong.Wang@Sun.COM 		}
1040*10264SZhong.Wang@Sun.COM 		break;
1041*10264SZhong.Wang@Sun.COM 
1042*10264SZhong.Wang@Sun.COM 	default:
1043*10264SZhong.Wang@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
1044*10264SZhong.Wang@Sun.COM 		return (DDI_FAILURE);
10457836SJohn.Forte@Sun.COM 	};
10467836SJohn.Forte@Sun.COM 
10477836SJohn.Forte@Sun.COM 	fcsm->sm_flags |= flag;
10487836SJohn.Forte@Sun.COM 
10497836SJohn.Forte@Sun.COM 	/*
10507836SJohn.Forte@Sun.COM 	 * If some commands are pending OR callback in progress, then
10517836SJohn.Forte@Sun.COM 	 * wait for some finite amount of time for their completion.
10527836SJohn.Forte@Sun.COM 	 * TODO: add more checks here to check for cmd timeout, offline
10537836SJohn.Forte@Sun.COM 	 * timeout and other (??) threads.
10547836SJohn.Forte@Sun.COM 	 */
10557836SJohn.Forte@Sun.COM 	count = 0;
10567836SJohn.Forte@Sun.COM 	while ((count++ <= 30) && (fcsm->sm_ncmds || fcsm->sm_cb_count)) {
10577836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
10587836SJohn.Forte@Sun.COM 		delay(drv_usectohz(1000000));
10597836SJohn.Forte@Sun.COM 		mutex_enter(&fcsm->sm_mutex);
10607836SJohn.Forte@Sun.COM 	}
10617836SJohn.Forte@Sun.COM 	if (fcsm->sm_ncmds || fcsm->sm_cb_count) {
10627836SJohn.Forte@Sun.COM 		fcsm->sm_flags &= ~flag;
10637836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
10647836SJohn.Forte@Sun.COM 		fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
10657836SJohn.Forte@Sun.COM 		    "port_detach: Failing suspend, port is busy");
10667836SJohn.Forte@Sun.COM 		return (DDI_FAILURE);
10677836SJohn.Forte@Sun.COM 	}
10687836SJohn.Forte@Sun.COM 	if (flag == FCSM_DETACHING) {
10697836SJohn.Forte@Sun.COM 		fcsm->sm_flags &= ~FCSM_DETACHING;
10707836SJohn.Forte@Sun.COM 		fcsm->sm_flags |= FCSM_DETACHED;
10717836SJohn.Forte@Sun.COM 	}
10727836SJohn.Forte@Sun.COM 
10737836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
10747836SJohn.Forte@Sun.COM 
10757836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL,
10767836SJohn.Forte@Sun.COM 	    "port_detach: cmd 0x%x pathname <%s>",
10777836SJohn.Forte@Sun.COM 	    cmd, ddi_pathname(pinfo->port_dip, pathname)));
10787836SJohn.Forte@Sun.COM 
10797836SJohn.Forte@Sun.COM 	if (cmd == FC_CMD_DETACH) {
10807836SJohn.Forte@Sun.COM 		fcsm_cleanup_port(fcsm);
10817836SJohn.Forte@Sun.COM 		/*
10827836SJohn.Forte@Sun.COM 		 * Soft state cleanup done.
10837836SJohn.Forte@Sun.COM 		 * Always remember that fcsm struct doesn't exist anymore.
10847836SJohn.Forte@Sun.COM 		 */
10857836SJohn.Forte@Sun.COM 	} else {
10867836SJohn.Forte@Sun.COM 		fcsm_suspend_port(fcsm);
10877836SJohn.Forte@Sun.COM 	}
10887836SJohn.Forte@Sun.COM 
10897836SJohn.Forte@Sun.COM 	return (DDI_SUCCESS);
10907836SJohn.Forte@Sun.COM }
10917836SJohn.Forte@Sun.COM 
10927836SJohn.Forte@Sun.COM static void
fcsm_suspend_port(fcsm_t * fcsm)10937836SJohn.Forte@Sun.COM fcsm_suspend_port(fcsm_t *fcsm)
10947836SJohn.Forte@Sun.COM {
10957836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
10967836SJohn.Forte@Sun.COM 
10977836SJohn.Forte@Sun.COM 	if (fcsm->sm_offline_tid != NULL) {
10987836SJohn.Forte@Sun.COM 		timeout_id_t	tid;
10997836SJohn.Forte@Sun.COM 
11007836SJohn.Forte@Sun.COM 		tid = fcsm->sm_offline_tid;
11017836SJohn.Forte@Sun.COM 		fcsm->sm_offline_tid = (timeout_id_t)NULL;
11027836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
11037836SJohn.Forte@Sun.COM 		(void) untimeout(tid);
11047836SJohn.Forte@Sun.COM 		mutex_enter(&fcsm->sm_mutex);
11057836SJohn.Forte@Sun.COM 		fcsm->sm_flags |= FCSM_RESTORE_OFFLINE_TIMEOUT;
11067836SJohn.Forte@Sun.COM 	}
11077836SJohn.Forte@Sun.COM 
11087836SJohn.Forte@Sun.COM 	if (fcsm->sm_retry_tid != NULL) {
11097836SJohn.Forte@Sun.COM 		timeout_id_t	tid;
11107836SJohn.Forte@Sun.COM 
11117836SJohn.Forte@Sun.COM 		tid = fcsm->sm_retry_tid;
11127836SJohn.Forte@Sun.COM 		fcsm->sm_retry_tid = (timeout_id_t)NULL;
11137836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
11147836SJohn.Forte@Sun.COM 		(void) untimeout(tid);
11157836SJohn.Forte@Sun.COM 		mutex_enter(&fcsm->sm_mutex);
11167836SJohn.Forte@Sun.COM 		fcsm->sm_flags |= FCSM_RESTORE_RETRY_TIMEOUT;
11177836SJohn.Forte@Sun.COM 	}
11187836SJohn.Forte@Sun.COM 
11197836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
11207836SJohn.Forte@Sun.COM }
11217836SJohn.Forte@Sun.COM 
11227836SJohn.Forte@Sun.COM static void
fcsm_resume_port(fcsm_t * fcsm)11237836SJohn.Forte@Sun.COM fcsm_resume_port(fcsm_t *fcsm)
11247836SJohn.Forte@Sun.COM {
11257836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
11267836SJohn.Forte@Sun.COM 
11277836SJohn.Forte@Sun.COM 	if (fcsm->sm_flags & FCSM_RESTORE_OFFLINE_TIMEOUT) {
11287836SJohn.Forte@Sun.COM 		fcsm->sm_flags &= ~FCSM_RESTORE_OFFLINE_TIMEOUT;
11297836SJohn.Forte@Sun.COM 
11307836SJohn.Forte@Sun.COM 		/*
11317836SJohn.Forte@Sun.COM 		 * If port if offline, link is not marked down and offline
11327836SJohn.Forte@Sun.COM 		 * timer is not already running, then restart offline timer.
11337836SJohn.Forte@Sun.COM 		 */
11347836SJohn.Forte@Sun.COM 		if (!(fcsm->sm_flags & FCSM_LINK_DOWN) &&
11357836SJohn.Forte@Sun.COM 		    fcsm->sm_offline_tid == NULL &&
11367836SJohn.Forte@Sun.COM 		    (fcsm->sm_flags & FCSM_PORT_OFFLINE)) {
11377836SJohn.Forte@Sun.COM 			fcsm->sm_offline_tid = timeout(fcsm_offline_timeout,
11387836SJohn.Forte@Sun.COM 			    (caddr_t)fcsm, fcsm_offline_ticks);
11397836SJohn.Forte@Sun.COM 		}
11407836SJohn.Forte@Sun.COM 	}
11417836SJohn.Forte@Sun.COM 
11427836SJohn.Forte@Sun.COM 	if (fcsm->sm_flags & FCSM_RESTORE_RETRY_TIMEOUT) {
11437836SJohn.Forte@Sun.COM 		fcsm->sm_flags &= ~FCSM_RESTORE_RETRY_TIMEOUT;
11447836SJohn.Forte@Sun.COM 
11457836SJohn.Forte@Sun.COM 		/*
11467836SJohn.Forte@Sun.COM 		 * If retry queue is not suspended and some cmds are waiting
11477836SJohn.Forte@Sun.COM 		 * to be retried, then restart the retry timer
11487836SJohn.Forte@Sun.COM 		 */
11497836SJohn.Forte@Sun.COM 		if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) {
11507836SJohn.Forte@Sun.COM 			fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
11517836SJohn.Forte@Sun.COM 			    (caddr_t)fcsm, fcsm_retry_ticks);
11527836SJohn.Forte@Sun.COM 		}
11537836SJohn.Forte@Sun.COM 	}
11547836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
11557836SJohn.Forte@Sun.COM }
11567836SJohn.Forte@Sun.COM 
11577836SJohn.Forte@Sun.COM static void
fcsm_cleanup_port(fcsm_t * fcsm)11587836SJohn.Forte@Sun.COM fcsm_cleanup_port(fcsm_t *fcsm)
11597836SJohn.Forte@Sun.COM {
11607836SJohn.Forte@Sun.COM 	fcsm_t		*curr, *prev;
11617836SJohn.Forte@Sun.COM 	int		status;
11627836SJohn.Forte@Sun.COM 	fcsm_job_t	*job;
11637836SJohn.Forte@Sun.COM 
11647836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
11657836SJohn.Forte@Sun.COM 	    "fcsm_cleanup_port: entered"));
11667836SJohn.Forte@Sun.COM 
11677836SJohn.Forte@Sun.COM 	/*
11687836SJohn.Forte@Sun.COM 	 * Kill the job thread
11697836SJohn.Forte@Sun.COM 	 */
11707836SJohn.Forte@Sun.COM 	job = fcsm_alloc_job(KM_SLEEP);
11717836SJohn.Forte@Sun.COM 	ASSERT(job != NULL);
11727836SJohn.Forte@Sun.COM 	fcsm_init_job(job, fcsm->sm_instance, FCSM_JOB_THREAD_SHUTDOWN,
11737836SJohn.Forte@Sun.COM 	    FCSM_JOBFLAG_SYNC, NULL, NULL, NULL, NULL);
11747836SJohn.Forte@Sun.COM 
11757836SJohn.Forte@Sun.COM 	status = fcsm_process_job(job, 0);
11767836SJohn.Forte@Sun.COM 	ASSERT(status == FC_SUCCESS);
11777836SJohn.Forte@Sun.COM 
11787836SJohn.Forte@Sun.COM 	ASSERT(job->job_result == FC_SUCCESS);
11797836SJohn.Forte@Sun.COM 	fcsm_dealloc_job(job);
11807836SJohn.Forte@Sun.COM 
11817836SJohn.Forte@Sun.COM 	/*
11827836SJohn.Forte@Sun.COM 	 * We got here after ensuring the no commands are pending or active.
11837836SJohn.Forte@Sun.COM 	 * Therefore retry timeout thread should NOT be running.
11847836SJohn.Forte@Sun.COM 	 * Kill the offline timeout thread if currently running.
11857836SJohn.Forte@Sun.COM 	 */
11867836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
11877836SJohn.Forte@Sun.COM 
11887836SJohn.Forte@Sun.COM 	ASSERT(fcsm->sm_retry_tid == NULL);
11897836SJohn.Forte@Sun.COM 
11907836SJohn.Forte@Sun.COM 	if (fcsm->sm_offline_tid != NULL) {
11917836SJohn.Forte@Sun.COM 		timeout_id_t	tid;
11927836SJohn.Forte@Sun.COM 
11937836SJohn.Forte@Sun.COM 		tid = fcsm->sm_offline_tid;
11947836SJohn.Forte@Sun.COM 		fcsm->sm_offline_tid = (timeout_id_t)NULL;
11957836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
11967836SJohn.Forte@Sun.COM 		(void) untimeout(tid);
11977836SJohn.Forte@Sun.COM 	} else {
11987836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
11997836SJohn.Forte@Sun.COM 	}
12007836SJohn.Forte@Sun.COM 
12017836SJohn.Forte@Sun.COM 	/* Remove from the fcsm state structure from global linked list */
12027836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm_global_mutex);
12037836SJohn.Forte@Sun.COM 	curr = fcsm_port_head;
12047836SJohn.Forte@Sun.COM 	prev = NULL;
12057836SJohn.Forte@Sun.COM 	while (curr != fcsm && curr != NULL) {
12067836SJohn.Forte@Sun.COM 		prev = curr;
12077836SJohn.Forte@Sun.COM 		curr = curr->sm_next;
12087836SJohn.Forte@Sun.COM 	}
12097836SJohn.Forte@Sun.COM 	ASSERT(curr != NULL);
12107836SJohn.Forte@Sun.COM 
12117836SJohn.Forte@Sun.COM 	if (prev == NULL) {
12127836SJohn.Forte@Sun.COM 		fcsm_port_head = curr->sm_next;
12137836SJohn.Forte@Sun.COM 	} else {
12147836SJohn.Forte@Sun.COM 		prev->sm_next = curr->sm_next;
12157836SJohn.Forte@Sun.COM 	}
12167836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm_global_mutex);
12177836SJohn.Forte@Sun.COM 
12187836SJohn.Forte@Sun.COM 	if (fcsm->sm_cmd_cache != NULL) {
12197836SJohn.Forte@Sun.COM 		kmem_cache_destroy(fcsm->sm_cmd_cache);
12207836SJohn.Forte@Sun.COM 	}
12217836SJohn.Forte@Sun.COM 	cv_destroy(&fcsm->sm_job_cv);
12227836SJohn.Forte@Sun.COM 	mutex_destroy(&fcsm->sm_mutex);
12237836SJohn.Forte@Sun.COM 
12247836SJohn.Forte@Sun.COM 	/* Free the fcsm state structure */
12257836SJohn.Forte@Sun.COM 	ddi_soft_state_free(fcsm_state, fcsm->sm_instance);
12267836SJohn.Forte@Sun.COM }
12277836SJohn.Forte@Sun.COM 
12287836SJohn.Forte@Sun.COM 
12297836SJohn.Forte@Sun.COM /* ARGSUSED */
12307836SJohn.Forte@Sun.COM static void
fcsm_statec_cb(opaque_t ulph,opaque_t port_handle,uint32_t port_state,uint32_t port_top,fc_portmap_t * devlist,uint32_t dev_cnt,uint32_t port_sid)12317836SJohn.Forte@Sun.COM fcsm_statec_cb(opaque_t ulph, opaque_t port_handle, uint32_t port_state,
12327836SJohn.Forte@Sun.COM     uint32_t port_top, fc_portmap_t *devlist, uint32_t dev_cnt,
12337836SJohn.Forte@Sun.COM     uint32_t port_sid)
12347836SJohn.Forte@Sun.COM {
12357836SJohn.Forte@Sun.COM 	fcsm_t		*fcsm;
12367836SJohn.Forte@Sun.COM 	timeout_id_t	offline_tid, retry_tid;
12377836SJohn.Forte@Sun.COM 
12387836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm_global_mutex);
12397836SJohn.Forte@Sun.COM 	if (fcsm_detached) {
12407836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm_global_mutex);
12417836SJohn.Forte@Sun.COM 		return;
12427836SJohn.Forte@Sun.COM 	}
12437836SJohn.Forte@Sun.COM 
12447836SJohn.Forte@Sun.COM 	fcsm = ddi_get_soft_state(fcsm_state,
12457836SJohn.Forte@Sun.COM 	    fc_ulp_get_port_instance(port_handle));
12467836SJohn.Forte@Sun.COM 	if (fcsm == NULL) {
12477836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm_global_mutex);
12487836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, NULL, NULL,
12497836SJohn.Forte@Sun.COM 		    "statec_cb: instance 0x%x not found",
12507836SJohn.Forte@Sun.COM 		    fc_ulp_get_port_instance(port_handle)));
12517836SJohn.Forte@Sun.COM 		return;
12527836SJohn.Forte@Sun.COM 	}
12537836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
12547836SJohn.Forte@Sun.COM 	ASSERT(fcsm->sm_instance == fc_ulp_get_port_instance(port_handle));
12557836SJohn.Forte@Sun.COM 	if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) {
12567836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
12577836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm_global_mutex);
12587836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, fcsm, NULL,
12597836SJohn.Forte@Sun.COM 		    "statec_cb: port not attached"));
12607836SJohn.Forte@Sun.COM 		return;
12617836SJohn.Forte@Sun.COM 	}
12627836SJohn.Forte@Sun.COM 
12637836SJohn.Forte@Sun.COM 	ASSERT(fcsm->sm_cb_count >= 0);
12647836SJohn.Forte@Sun.COM 
12657836SJohn.Forte@Sun.COM 	fcsm->sm_cb_count++;
12667836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
12677836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm_global_mutex);
12687836SJohn.Forte@Sun.COM 
12697836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
12707836SJohn.Forte@Sun.COM 	    "statec_cb: state <%s>(0x%x) topology <%s>(0x%x) dev_cnt %d",
12717836SJohn.Forte@Sun.COM 	    fcsm_port_state_to_str(FC_PORT_STATE_MASK(port_state)), port_state,
12727836SJohn.Forte@Sun.COM 	    fcsm_topology_to_str(port_top), port_top, dev_cnt));
12737836SJohn.Forte@Sun.COM 
12747836SJohn.Forte@Sun.COM 	fcsm_disp_devlist(fcsm, devlist, dev_cnt);
12757836SJohn.Forte@Sun.COM 
12767836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
12777836SJohn.Forte@Sun.COM 
12787836SJohn.Forte@Sun.COM 	/*
12797836SJohn.Forte@Sun.COM 	 * Reset the Mgmt server Login flag, so that login is performed again.
12807836SJohn.Forte@Sun.COM 	 */
12817836SJohn.Forte@Sun.COM 	fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGGED_IN;
12827836SJohn.Forte@Sun.COM 
12837836SJohn.Forte@Sun.COM 	fcsm->sm_sid = port_sid;
12847836SJohn.Forte@Sun.COM 	fcsm->sm_port_top = port_top;
12857836SJohn.Forte@Sun.COM 	fcsm->sm_port_state = port_state;
12867836SJohn.Forte@Sun.COM 
12877836SJohn.Forte@Sun.COM 	switch (port_state) {
12887836SJohn.Forte@Sun.COM 	case FC_STATE_OFFLINE:
12897836SJohn.Forte@Sun.COM 	case FC_STATE_RESET:
12907836SJohn.Forte@Sun.COM 	case FC_STATE_RESET_REQUESTED:
12917836SJohn.Forte@Sun.COM 		fcsm->sm_flags |= FCSM_PORT_OFFLINE;
12927836SJohn.Forte@Sun.COM 		break;
12937836SJohn.Forte@Sun.COM 
12947836SJohn.Forte@Sun.COM 	case FC_STATE_ONLINE:
12957836SJohn.Forte@Sun.COM 	case FC_STATE_LOOP:
12967836SJohn.Forte@Sun.COM 	case FC_STATE_LIP:
12977836SJohn.Forte@Sun.COM 	case FC_STATE_LIP_LBIT_SET:
12987836SJohn.Forte@Sun.COM 		fcsm->sm_flags &= ~FCSM_PORT_OFFLINE;
12997836SJohn.Forte@Sun.COM 		fcsm->sm_flags &= ~FCSM_LINK_DOWN;
13007836SJohn.Forte@Sun.COM 		break;
13017836SJohn.Forte@Sun.COM 
13027836SJohn.Forte@Sun.COM 	case FC_STATE_NAMESERVICE:
13037836SJohn.Forte@Sun.COM 	case FC_STATE_DEVICE_CHANGE:
13047836SJohn.Forte@Sun.COM 	case FC_STATE_TARGET_PORT_RESET:
13057836SJohn.Forte@Sun.COM 	default:
13067836SJohn.Forte@Sun.COM 		/* Do nothing */
13077836SJohn.Forte@Sun.COM 		break;
13087836SJohn.Forte@Sun.COM 	}
13097836SJohn.Forte@Sun.COM 
13107836SJohn.Forte@Sun.COM 	offline_tid = retry_tid = NULL;
13117836SJohn.Forte@Sun.COM 	if (fcsm->sm_flags & FCSM_PORT_OFFLINE) {
13127836SJohn.Forte@Sun.COM 		/*
13137836SJohn.Forte@Sun.COM 		 * Port is offline.
13147836SJohn.Forte@Sun.COM 		 * Suspend cmd processing and start offline timeout thread.
13157836SJohn.Forte@Sun.COM 		 */
13167836SJohn.Forte@Sun.COM 		if (fcsm->sm_offline_tid == NULL) {
13177836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
13187836SJohn.Forte@Sun.COM 			    "statec_cb: schedule offline timeout thread"));
13197836SJohn.Forte@Sun.COM 			fcsm->sm_flags |= FCSM_CMD_RETRY_Q_SUSPENDED;
13207836SJohn.Forte@Sun.COM 			/* Stop the cmd retry thread */
13217836SJohn.Forte@Sun.COM 			retry_tid = fcsm->sm_retry_tid;
13227836SJohn.Forte@Sun.COM 			fcsm->sm_retry_tid = (timeout_id_t)NULL;
13237836SJohn.Forte@Sun.COM 
13247836SJohn.Forte@Sun.COM 			fcsm->sm_offline_tid = timeout(fcsm_offline_timeout,
13257836SJohn.Forte@Sun.COM 			    (caddr_t)fcsm, fcsm_offline_ticks);
13267836SJohn.Forte@Sun.COM 		}
13277836SJohn.Forte@Sun.COM 
13287836SJohn.Forte@Sun.COM 	} else {
13297836SJohn.Forte@Sun.COM 		/*
13307836SJohn.Forte@Sun.COM 		 * Port is online.
13317836SJohn.Forte@Sun.COM 		 * Cancel offline timeout thread and resume command processing.
13327836SJohn.Forte@Sun.COM 		 */
13337836SJohn.Forte@Sun.COM 		if (fcsm->sm_offline_tid) {
13347836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
13357836SJohn.Forte@Sun.COM 			    "statec_cb: cancel offline timeout thread"));
13367836SJohn.Forte@Sun.COM 			offline_tid = fcsm->sm_offline_tid;
13377836SJohn.Forte@Sun.COM 			fcsm->sm_offline_tid = (timeout_id_t)NULL;
13387836SJohn.Forte@Sun.COM 		}
13397836SJohn.Forte@Sun.COM 
13407836SJohn.Forte@Sun.COM 		fcsm->sm_flags &= ~FCSM_CMD_RETRY_Q_SUSPENDED;
13417836SJohn.Forte@Sun.COM 		/* Start retry thread if needed */
13427836SJohn.Forte@Sun.COM 		if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) {
13437836SJohn.Forte@Sun.COM 			fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
13447836SJohn.Forte@Sun.COM 			    (caddr_t)fcsm, fcsm_retry_ticks);
13457836SJohn.Forte@Sun.COM 		}
13467836SJohn.Forte@Sun.COM 	}
13477836SJohn.Forte@Sun.COM 
13487836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
13497836SJohn.Forte@Sun.COM 
13507836SJohn.Forte@Sun.COM 	if (offline_tid != NULL) {
13517836SJohn.Forte@Sun.COM 		(void) untimeout(offline_tid);
13527836SJohn.Forte@Sun.COM 	}
13537836SJohn.Forte@Sun.COM 
13547836SJohn.Forte@Sun.COM 	if (retry_tid != NULL) {
13557836SJohn.Forte@Sun.COM 		(void) untimeout(retry_tid);
13567836SJohn.Forte@Sun.COM 	}
13577836SJohn.Forte@Sun.COM 
13587836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
13597836SJohn.Forte@Sun.COM 	fcsm->sm_cb_count--;
13607836SJohn.Forte@Sun.COM 	ASSERT(fcsm->sm_cb_count >= 0);
13617836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
13627836SJohn.Forte@Sun.COM }
13637836SJohn.Forte@Sun.COM 
13647836SJohn.Forte@Sun.COM 
13657836SJohn.Forte@Sun.COM static void
fcsm_offline_timeout(void * handle)13667836SJohn.Forte@Sun.COM fcsm_offline_timeout(void *handle)
13677836SJohn.Forte@Sun.COM {
13687836SJohn.Forte@Sun.COM 	fcsm_t	*fcsm = (fcsm_t *)handle;
13697836SJohn.Forte@Sun.COM 
13707836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
13717836SJohn.Forte@Sun.COM 	    "offline_timeout"));
13727836SJohn.Forte@Sun.COM 
13737836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
13747836SJohn.Forte@Sun.COM 	if (fcsm->sm_flags & FCSM_PORT_OFFLINE) {
13757836SJohn.Forte@Sun.COM 		fcsm->sm_flags |= FCSM_LINK_DOWN;
13767836SJohn.Forte@Sun.COM 	}
13777836SJohn.Forte@Sun.COM 	fcsm->sm_offline_tid = (timeout_id_t)NULL;
13787836SJohn.Forte@Sun.COM 	fcsm->sm_flags &= ~FCSM_CMD_RETRY_Q_SUSPENDED;
13797836SJohn.Forte@Sun.COM 
13807836SJohn.Forte@Sun.COM 	/* Start the retry thread if needed */
13817836SJohn.Forte@Sun.COM 	if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) {
13827836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
13837836SJohn.Forte@Sun.COM 		    "offline_timeout: reschedule cmd retry thread"));
13847836SJohn.Forte@Sun.COM 		ASSERT(fcsm->sm_retry_tid == NULL);
13857836SJohn.Forte@Sun.COM 		fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
13867836SJohn.Forte@Sun.COM 		    (caddr_t)fcsm, fcsm_retry_ticks);
13877836SJohn.Forte@Sun.COM 	}
13887836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
13897836SJohn.Forte@Sun.COM }
13907836SJohn.Forte@Sun.COM 
13917836SJohn.Forte@Sun.COM /* ARGSUSED */
13927836SJohn.Forte@Sun.COM static int
fcsm_els_cb(opaque_t ulph,opaque_t port_handle,fc_unsol_buf_t * buf,uint32_t claimed)13937836SJohn.Forte@Sun.COM fcsm_els_cb(opaque_t ulph, opaque_t port_handle, fc_unsol_buf_t *buf,
13947836SJohn.Forte@Sun.COM     uint32_t claimed)
13957836SJohn.Forte@Sun.COM {
13967836SJohn.Forte@Sun.COM 	return (FC_UNCLAIMED);
13977836SJohn.Forte@Sun.COM }
13987836SJohn.Forte@Sun.COM 
13997836SJohn.Forte@Sun.COM 
14007836SJohn.Forte@Sun.COM /* ARGSUSED */
14017836SJohn.Forte@Sun.COM static int
fcsm_data_cb(opaque_t ulph,opaque_t port_handle,fc_unsol_buf_t * buf,uint32_t claimed)14027836SJohn.Forte@Sun.COM fcsm_data_cb(opaque_t ulph, opaque_t port_handle, fc_unsol_buf_t *buf,
14037836SJohn.Forte@Sun.COM     uint32_t claimed)
14047836SJohn.Forte@Sun.COM {
14057836SJohn.Forte@Sun.COM 	return (FC_UNCLAIMED);
14067836SJohn.Forte@Sun.COM }
14077836SJohn.Forte@Sun.COM 
14087836SJohn.Forte@Sun.COM 
14097836SJohn.Forte@Sun.COM /* ARGSUSED */
14107836SJohn.Forte@Sun.COM static int
fcsm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rval_p)14117836SJohn.Forte@Sun.COM fcsm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
14127836SJohn.Forte@Sun.COM     int *rval_p)
14137836SJohn.Forte@Sun.COM {
14147836SJohn.Forte@Sun.COM 	int retval = 0;
14157836SJohn.Forte@Sun.COM 
14167836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "ioctl: start"));
14177836SJohn.Forte@Sun.COM 
14187836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm_global_mutex);
14197836SJohn.Forte@Sun.COM 	if (!(fcsm_flag & FCSM_OPEN)) {
14207836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm_global_mutex);
14217836SJohn.Forte@Sun.COM 		return (ENXIO);
14227836SJohn.Forte@Sun.COM 	}
14237836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm_global_mutex);
14247836SJohn.Forte@Sun.COM 
14257836SJohn.Forte@Sun.COM 	/* Allow only root to talk */
14267836SJohn.Forte@Sun.COM 	if (drv_priv(credp)) {
14277836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
14287836SJohn.Forte@Sun.COM 		    "ioctl: end (disallowing underprivileged user)"));
14297836SJohn.Forte@Sun.COM 		return (EPERM);
14307836SJohn.Forte@Sun.COM 	}
14317836SJohn.Forte@Sun.COM 
14327836SJohn.Forte@Sun.COM 	switch (cmd) {
14337836SJohn.Forte@Sun.COM 
14347836SJohn.Forte@Sun.COM 	case FCSMIO_CMD: {
14357836SJohn.Forte@Sun.COM 		fcio_t	fcio;
14367836SJohn.Forte@Sun.COM 		int	status;
14377836SJohn.Forte@Sun.COM #ifdef	_MULTI_DATAMODEL
14387836SJohn.Forte@Sun.COM 		switch (ddi_model_convert_from(mode & FMODELS)) {
14397836SJohn.Forte@Sun.COM 		case DDI_MODEL_ILP32: {
14407836SJohn.Forte@Sun.COM 			struct fcio32 fcio32;
14417836SJohn.Forte@Sun.COM 
14427836SJohn.Forte@Sun.COM 			if (status = ddi_copyin((void *)arg, (void *)&fcio32,
14437836SJohn.Forte@Sun.COM 			    sizeof (struct fcio32), mode)) {
14447836SJohn.Forte@Sun.COM 				retval = EFAULT;
14457836SJohn.Forte@Sun.COM 				break;
14467836SJohn.Forte@Sun.COM 			}
14477836SJohn.Forte@Sun.COM 			fcio.fcio_xfer = fcio32.fcio_xfer;
14487836SJohn.Forte@Sun.COM 			fcio.fcio_cmd = fcio32.fcio_cmd;
14497836SJohn.Forte@Sun.COM 			fcio.fcio_flags = fcio32.fcio_flags;
14507836SJohn.Forte@Sun.COM 			fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags;
14517836SJohn.Forte@Sun.COM 			fcio.fcio_ilen = (size_t)fcio32.fcio_ilen;
14527836SJohn.Forte@Sun.COM 			fcio.fcio_ibuf = (caddr_t)(long)fcio32.fcio_ibuf;
14537836SJohn.Forte@Sun.COM 			fcio.fcio_olen = (size_t)fcio32.fcio_olen;
14547836SJohn.Forte@Sun.COM 			fcio.fcio_obuf = (caddr_t)(long)fcio32.fcio_obuf;
14557836SJohn.Forte@Sun.COM 			fcio.fcio_alen = (size_t)fcio32.fcio_alen;
14567836SJohn.Forte@Sun.COM 			fcio.fcio_abuf = (caddr_t)(long)fcio32.fcio_abuf;
14577836SJohn.Forte@Sun.COM 			fcio.fcio_errno = fcio32.fcio_errno;
14587836SJohn.Forte@Sun.COM 			break;
14597836SJohn.Forte@Sun.COM 		}
14607836SJohn.Forte@Sun.COM 
14617836SJohn.Forte@Sun.COM 		case DDI_MODEL_NONE:
14627836SJohn.Forte@Sun.COM 			if (status = ddi_copyin((void *)arg, (void *)&fcio,
14637836SJohn.Forte@Sun.COM 			    sizeof (fcio_t), mode)) {
14647836SJohn.Forte@Sun.COM 				retval = EFAULT;
14657836SJohn.Forte@Sun.COM 			}
14667836SJohn.Forte@Sun.COM 			break;
14677836SJohn.Forte@Sun.COM 		}
14687836SJohn.Forte@Sun.COM #else	/* _MULTI_DATAMODEL */
14697836SJohn.Forte@Sun.COM 		if (status = ddi_copyin((void *)arg, (void *)&fcio,
14707836SJohn.Forte@Sun.COM 		    sizeof (fcio_t), mode)) {
14717836SJohn.Forte@Sun.COM 			retval = EFAULT;
14727836SJohn.Forte@Sun.COM 			break;
14737836SJohn.Forte@Sun.COM 		}
14747836SJohn.Forte@Sun.COM #endif	/* _MULTI_DATAMODEL */
14757836SJohn.Forte@Sun.COM 		if (!status) {
14767836SJohn.Forte@Sun.COM 			retval = fcsm_fciocmd(arg, mode, credp, &fcio);
14777836SJohn.Forte@Sun.COM 		}
14787836SJohn.Forte@Sun.COM 		break;
14797836SJohn.Forte@Sun.COM 	}
14807836SJohn.Forte@Sun.COM 
14817836SJohn.Forte@Sun.COM 	default:
14827836SJohn.Forte@Sun.COM 		retval = ENOTTY;
14837836SJohn.Forte@Sun.COM 		break;
14847836SJohn.Forte@Sun.COM 	}
14857836SJohn.Forte@Sun.COM 
14867836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "ioctl: end"));
14877836SJohn.Forte@Sun.COM 	return (retval);
14887836SJohn.Forte@Sun.COM }
14897836SJohn.Forte@Sun.COM 
14907836SJohn.Forte@Sun.COM /* ARGSUSED */
14917836SJohn.Forte@Sun.COM static int
fcsm_port_ioctl(opaque_t ulph,opaque_t port_handle,dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rval,uint32_t claimed)14927836SJohn.Forte@Sun.COM fcsm_port_ioctl(opaque_t ulph, opaque_t port_handle, dev_t dev, int cmd,
14937836SJohn.Forte@Sun.COM     intptr_t arg, int mode, cred_t *credp, int *rval, uint32_t claimed)
14947836SJohn.Forte@Sun.COM {
14957836SJohn.Forte@Sun.COM 	return (FC_UNCLAIMED);
14967836SJohn.Forte@Sun.COM }
14977836SJohn.Forte@Sun.COM 
14987836SJohn.Forte@Sun.COM 
14997836SJohn.Forte@Sun.COM /* ARGSUSED */
15007836SJohn.Forte@Sun.COM static int
fcsm_fciocmd(intptr_t arg,int mode,cred_t * credp,fcio_t * fcio)15017836SJohn.Forte@Sun.COM fcsm_fciocmd(intptr_t arg, int mode, cred_t *credp, fcio_t *fcio)
15027836SJohn.Forte@Sun.COM {
15037836SJohn.Forte@Sun.COM 	int  retval = 0;
15047836SJohn.Forte@Sun.COM 
15057836SJohn.Forte@Sun.COM 	switch (fcio->fcio_cmd) {
15067836SJohn.Forte@Sun.COM 	case  FCSMIO_CT_CMD: {
15077836SJohn.Forte@Sun.COM 		fcsm_t		*fcsm;
15087836SJohn.Forte@Sun.COM 		caddr_t		user_ibuf, user_obuf;
15097836SJohn.Forte@Sun.COM 		caddr_t		req_iu, rsp_iu, abuf;
15107836SJohn.Forte@Sun.COM 		int		status, instance, count;
15117836SJohn.Forte@Sun.COM 
15127836SJohn.Forte@Sun.COM 		if ((fcio->fcio_xfer != FCIO_XFER_RW) ||
15137836SJohn.Forte@Sun.COM 		    (fcio->fcio_ilen == 0) || (fcio->fcio_ibuf == 0) ||
15147836SJohn.Forte@Sun.COM 		    (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0) ||
15157836SJohn.Forte@Sun.COM 		    (fcio->fcio_alen == 0) || (fcio->fcio_abuf == 0) ||
15167836SJohn.Forte@Sun.COM 		    (fcio->fcio_flags != 0) || (fcio->fcio_cmd_flags != 0) ||
15177836SJohn.Forte@Sun.COM 		    (fcio->fcio_ilen > FCSM_MAX_CT_SIZE) ||
15187836SJohn.Forte@Sun.COM 		    (fcio->fcio_olen > FCSM_MAX_CT_SIZE) ||
15197836SJohn.Forte@Sun.COM 		    (fcio->fcio_alen > MAXPATHLEN)) {
15207836SJohn.Forte@Sun.COM 			retval = EINVAL;
15217836SJohn.Forte@Sun.COM 			break;
15227836SJohn.Forte@Sun.COM 		}
15237836SJohn.Forte@Sun.COM 
15247836SJohn.Forte@Sun.COM 		/*
15257836SJohn.Forte@Sun.COM 		 * Get the destination port for which this ioctl
15267836SJohn.Forte@Sun.COM 		 * is targeted. The abuf will have the fp_minor
15277836SJohn.Forte@Sun.COM 		 * number.
15287836SJohn.Forte@Sun.COM 		 */
15297836SJohn.Forte@Sun.COM 		abuf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP);
15307836SJohn.Forte@Sun.COM 		ASSERT(abuf != NULL);
15317836SJohn.Forte@Sun.COM 		if (ddi_copyin(fcio->fcio_abuf, abuf, fcio->fcio_alen, mode)) {
15327836SJohn.Forte@Sun.COM 			retval = EFAULT;
15337836SJohn.Forte@Sun.COM 			kmem_free(abuf, fcio->fcio_alen);
15347836SJohn.Forte@Sun.COM 			break;
15357836SJohn.Forte@Sun.COM 		}
15367836SJohn.Forte@Sun.COM 
15377836SJohn.Forte@Sun.COM 		instance = *((int *)abuf);
15387836SJohn.Forte@Sun.COM 		kmem_free(abuf, fcio->fcio_alen);
15397836SJohn.Forte@Sun.COM 
15407836SJohn.Forte@Sun.COM 		if (instance < 0) {
15417836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
15427836SJohn.Forte@Sun.COM 			    "fciocmd: instance 0x%x, invalid instance",
15437836SJohn.Forte@Sun.COM 			    instance));
15447836SJohn.Forte@Sun.COM 			retval = ENXIO;
15457836SJohn.Forte@Sun.COM 			break;
15467836SJohn.Forte@Sun.COM 		}
15477836SJohn.Forte@Sun.COM 
15487836SJohn.Forte@Sun.COM 		/*
15497836SJohn.Forte@Sun.COM 		 * We confirmed that path corresponds to our port driver
15507836SJohn.Forte@Sun.COM 		 * and a valid instance.
15517836SJohn.Forte@Sun.COM 		 * If this port instance is not yet attached, then wait
15527836SJohn.Forte@Sun.COM 		 * for a finite time for attach to complete
15537836SJohn.Forte@Sun.COM 		 */
15547836SJohn.Forte@Sun.COM 		fcsm = ddi_get_soft_state(fcsm_state, instance);
15557836SJohn.Forte@Sun.COM 		count = 0;
15567836SJohn.Forte@Sun.COM 		while (count++ <= 30) {
15577836SJohn.Forte@Sun.COM 			if (fcsm != NULL) {
15587836SJohn.Forte@Sun.COM 				mutex_enter(&fcsm->sm_mutex);
15597836SJohn.Forte@Sun.COM 				if (fcsm->sm_flags & FCSM_ATTACHED) {
15607836SJohn.Forte@Sun.COM 					mutex_exit(&fcsm->sm_mutex);
15617836SJohn.Forte@Sun.COM 					break;
15627836SJohn.Forte@Sun.COM 				}
15637836SJohn.Forte@Sun.COM 				mutex_exit(&fcsm->sm_mutex);
15647836SJohn.Forte@Sun.COM 			}
15657836SJohn.Forte@Sun.COM 			if (count == 1) {
15667836SJohn.Forte@Sun.COM 				FCSM_DEBUG(SMDL_TRACE,
15677836SJohn.Forte@Sun.COM 				    (CE_WARN, SM_LOG, NULL, NULL,
15687836SJohn.Forte@Sun.COM 				    "fciocmd: instance 0x%x, "
15697836SJohn.Forte@Sun.COM 				    "wait for port attach", instance));
15707836SJohn.Forte@Sun.COM 			}
15717836SJohn.Forte@Sun.COM 			delay(drv_usectohz(1000000));
15727836SJohn.Forte@Sun.COM 			fcsm = ddi_get_soft_state(fcsm_state, instance);
15737836SJohn.Forte@Sun.COM 		}
15747836SJohn.Forte@Sun.COM 		if (count > 30) {
15757836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
15767836SJohn.Forte@Sun.COM 			    "fciocmd: instance 0x%x, port not attached",
15777836SJohn.Forte@Sun.COM 			    instance));
15787836SJohn.Forte@Sun.COM 			retval = ENXIO;
15797836SJohn.Forte@Sun.COM 			break;
15807836SJohn.Forte@Sun.COM 		}
15817836SJohn.Forte@Sun.COM 
15827836SJohn.Forte@Sun.COM 		req_iu = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
15837836SJohn.Forte@Sun.COM 		rsp_iu = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
15847836SJohn.Forte@Sun.COM 		ASSERT((req_iu != NULL) && (rsp_iu != NULL));
15857836SJohn.Forte@Sun.COM 
15867836SJohn.Forte@Sun.COM 		if (ddi_copyin(fcio->fcio_ibuf, req_iu,
15877836SJohn.Forte@Sun.COM 		    fcio->fcio_ilen, mode)) {
15887836SJohn.Forte@Sun.COM 			retval = EFAULT;
15897836SJohn.Forte@Sun.COM 			kmem_free(req_iu, fcio->fcio_ilen);
15907836SJohn.Forte@Sun.COM 			kmem_free(rsp_iu, fcio->fcio_olen);
15917836SJohn.Forte@Sun.COM 			break;
15927836SJohn.Forte@Sun.COM 		}
15937836SJohn.Forte@Sun.COM 
15947836SJohn.Forte@Sun.COM 		user_ibuf = fcio->fcio_ibuf;
15957836SJohn.Forte@Sun.COM 		user_obuf = fcio->fcio_obuf;
15967836SJohn.Forte@Sun.COM 		fcio->fcio_ibuf = req_iu;
15977836SJohn.Forte@Sun.COM 		fcio->fcio_obuf = rsp_iu;
15987836SJohn.Forte@Sun.COM 
15997836SJohn.Forte@Sun.COM 		status = fcsm_ct_passthru(fcsm->sm_instance, fcio, KM_SLEEP,
16007836SJohn.Forte@Sun.COM 		    FCSM_JOBFLAG_SYNC, NULL);
16017836SJohn.Forte@Sun.COM 		if (status != FC_SUCCESS) {
16027836SJohn.Forte@Sun.COM 			retval = EIO;
16037836SJohn.Forte@Sun.COM 		}
16047836SJohn.Forte@Sun.COM 
16057836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
16067836SJohn.Forte@Sun.COM 		    "fciocmd: cmd 0x%x completion status 0x%x",
16077836SJohn.Forte@Sun.COM 		    fcio->fcio_cmd, status));
16087836SJohn.Forte@Sun.COM 		fcio->fcio_errno = status;
16097836SJohn.Forte@Sun.COM 		fcio->fcio_ibuf = user_ibuf;
16107836SJohn.Forte@Sun.COM 		fcio->fcio_obuf = user_obuf;
16117836SJohn.Forte@Sun.COM 
16127836SJohn.Forte@Sun.COM 		if (ddi_copyout(rsp_iu, fcio->fcio_obuf,
16137836SJohn.Forte@Sun.COM 		    fcio->fcio_olen, mode)) {
16147836SJohn.Forte@Sun.COM 			retval = EFAULT;
16157836SJohn.Forte@Sun.COM 			kmem_free(req_iu, fcio->fcio_ilen);
16167836SJohn.Forte@Sun.COM 			kmem_free(rsp_iu, fcio->fcio_olen);
16177836SJohn.Forte@Sun.COM 			break;
16187836SJohn.Forte@Sun.COM 		}
16197836SJohn.Forte@Sun.COM 
16207836SJohn.Forte@Sun.COM 		kmem_free(req_iu, fcio->fcio_ilen);
16217836SJohn.Forte@Sun.COM 		kmem_free(rsp_iu, fcio->fcio_olen);
16227836SJohn.Forte@Sun.COM 
16237836SJohn.Forte@Sun.COM 		if (fcsm_fcio_copyout(fcio, arg, mode)) {
16247836SJohn.Forte@Sun.COM 			retval = EFAULT;
16257836SJohn.Forte@Sun.COM 		}
16267836SJohn.Forte@Sun.COM 		break;
16277836SJohn.Forte@Sun.COM 	}
16287836SJohn.Forte@Sun.COM 
16297836SJohn.Forte@Sun.COM 	case  FCSMIO_ADAPTER_LIST: {
163010110SMilan.Jurik@Sun.COM 		fc_hba_list_t	*list;
1631*10264SZhong.Wang@Sun.COM 		int			count;
163210110SMilan.Jurik@Sun.COM 
163310110SMilan.Jurik@Sun.COM 		if ((fcio->fcio_xfer != FCIO_XFER_RW) ||
16347836SJohn.Forte@Sun.COM 		    (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
163510110SMilan.Jurik@Sun.COM 			retval = EINVAL;
163610110SMilan.Jurik@Sun.COM 			break;
163710110SMilan.Jurik@Sun.COM 		}
163810110SMilan.Jurik@Sun.COM 
163910110SMilan.Jurik@Sun.COM 		list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
164010110SMilan.Jurik@Sun.COM 
164110110SMilan.Jurik@Sun.COM 		if (ddi_copyin(fcio->fcio_obuf, list, fcio->fcio_olen, mode)) {
164210110SMilan.Jurik@Sun.COM 			retval = EFAULT;
164310110SMilan.Jurik@Sun.COM 			break;
164410110SMilan.Jurik@Sun.COM 		}
164510110SMilan.Jurik@Sun.COM 		list->version = FC_HBA_LIST_VERSION;
164610110SMilan.Jurik@Sun.COM 
164710110SMilan.Jurik@Sun.COM 		if (fcio->fcio_olen < MAXPATHLEN * list->numAdapters) {
164810110SMilan.Jurik@Sun.COM 			retval = EFAULT;
164910110SMilan.Jurik@Sun.COM 			break;
165010110SMilan.Jurik@Sun.COM 		}
165110110SMilan.Jurik@Sun.COM 
165210110SMilan.Jurik@Sun.COM 		count = fc_ulp_get_adapter_paths((char *)list->hbaPaths,
165310110SMilan.Jurik@Sun.COM 		    list->numAdapters);
1654*10264SZhong.Wang@Sun.COM 		if (count < 0) {
1655*10264SZhong.Wang@Sun.COM 			/* Did something go wrong? */
165610110SMilan.Jurik@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
165710110SMilan.Jurik@Sun.COM 			    "Error fetching adapter list."));
165810110SMilan.Jurik@Sun.COM 			retval = ENXIO;
165910110SMilan.Jurik@Sun.COM 			kmem_free(list, fcio->fcio_olen);
166010110SMilan.Jurik@Sun.COM 			break;
166110110SMilan.Jurik@Sun.COM 		}
166210110SMilan.Jurik@Sun.COM 		/* Sucess (or short buffer) */
166310110SMilan.Jurik@Sun.COM 		list->numAdapters = count;
166410110SMilan.Jurik@Sun.COM 		if (ddi_copyout(list, fcio->fcio_obuf,
166510110SMilan.Jurik@Sun.COM 		    fcio->fcio_olen, mode)) {
166610110SMilan.Jurik@Sun.COM 			retval = EFAULT;
166710110SMilan.Jurik@Sun.COM 		}
16687836SJohn.Forte@Sun.COM 		kmem_free(list, fcio->fcio_olen);
16697836SJohn.Forte@Sun.COM 		break;
16707836SJohn.Forte@Sun.COM 	}
16717836SJohn.Forte@Sun.COM 
16727836SJohn.Forte@Sun.COM 	default:
16737836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, NULL, NULL,
16747836SJohn.Forte@Sun.COM 		    "fciocmd: unknown cmd <0x%x>", fcio->fcio_cmd));
16757836SJohn.Forte@Sun.COM 		retval = ENOTTY;
16767836SJohn.Forte@Sun.COM 		break;
16777836SJohn.Forte@Sun.COM 	}
16787836SJohn.Forte@Sun.COM 
16797836SJohn.Forte@Sun.COM 	return (retval);
16807836SJohn.Forte@Sun.COM }
16817836SJohn.Forte@Sun.COM 
16827836SJohn.Forte@Sun.COM static int
fcsm_fcio_copyout(fcio_t * fcio,intptr_t arg,int mode)16837836SJohn.Forte@Sun.COM fcsm_fcio_copyout(fcio_t *fcio, intptr_t arg, int mode)
16847836SJohn.Forte@Sun.COM {
16857836SJohn.Forte@Sun.COM 	int status;
16867836SJohn.Forte@Sun.COM 
16877836SJohn.Forte@Sun.COM #ifdef	_MULTI_DATAMODEL
16887836SJohn.Forte@Sun.COM 	switch (ddi_model_convert_from(mode & FMODELS)) {
16897836SJohn.Forte@Sun.COM 	case DDI_MODEL_ILP32: {
16907836SJohn.Forte@Sun.COM 		struct fcio32 fcio32;
16917836SJohn.Forte@Sun.COM 
16927836SJohn.Forte@Sun.COM 		fcio32.fcio_xfer = fcio->fcio_xfer;
16937836SJohn.Forte@Sun.COM 		fcio32.fcio_cmd = fcio->fcio_cmd;
16947836SJohn.Forte@Sun.COM 		fcio32.fcio_flags = fcio->fcio_flags;
16957836SJohn.Forte@Sun.COM 		fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags;
16967836SJohn.Forte@Sun.COM 		fcio32.fcio_ilen = fcio->fcio_ilen;
16977836SJohn.Forte@Sun.COM 		fcio32.fcio_ibuf = (caddr32_t)(long)fcio->fcio_ibuf;
16987836SJohn.Forte@Sun.COM 		fcio32.fcio_olen = fcio->fcio_olen;
16997836SJohn.Forte@Sun.COM 		fcio32.fcio_obuf = (caddr32_t)(long)fcio->fcio_obuf;
17007836SJohn.Forte@Sun.COM 		fcio32.fcio_alen = fcio->fcio_alen;
17017836SJohn.Forte@Sun.COM 		fcio32.fcio_abuf = (caddr32_t)(long)fcio->fcio_abuf;
17027836SJohn.Forte@Sun.COM 		fcio32.fcio_errno = fcio->fcio_errno;
17037836SJohn.Forte@Sun.COM 
17047836SJohn.Forte@Sun.COM 		status = ddi_copyout((void *)&fcio32, (void *)arg,
17057836SJohn.Forte@Sun.COM 		    sizeof (struct fcio32), mode);
17067836SJohn.Forte@Sun.COM 		break;
17077836SJohn.Forte@Sun.COM 	}
17087836SJohn.Forte@Sun.COM 	case DDI_MODEL_NONE:
17097836SJohn.Forte@Sun.COM 		status = ddi_copyout((void *)fcio, (void *)arg,
17107836SJohn.Forte@Sun.COM 		    sizeof (fcio_t), mode);
17117836SJohn.Forte@Sun.COM 		break;
17127836SJohn.Forte@Sun.COM 	}
17137836SJohn.Forte@Sun.COM #else	/* _MULTI_DATAMODEL */
17147836SJohn.Forte@Sun.COM 	status = ddi_copyout((void *)fcio, (void *)arg, sizeof (fcio_t), mode);
17157836SJohn.Forte@Sun.COM #endif	/* _MULTI_DATAMODEL */
17167836SJohn.Forte@Sun.COM 
17177836SJohn.Forte@Sun.COM 	return (status);
17187836SJohn.Forte@Sun.COM }
17197836SJohn.Forte@Sun.COM 
17207836SJohn.Forte@Sun.COM 
17217836SJohn.Forte@Sun.COM /* ARGSUSED */
17227836SJohn.Forte@Sun.COM static int
fcsm_open(dev_t * devp,int flags,int otyp,cred_t * credp)17237836SJohn.Forte@Sun.COM fcsm_open(dev_t *devp, int flags, int otyp, cred_t *credp)
17247836SJohn.Forte@Sun.COM {
17257836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "open"));
17267836SJohn.Forte@Sun.COM 
17277836SJohn.Forte@Sun.COM 	if (otyp != OTYP_CHR) {
17287836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
17297836SJohn.Forte@Sun.COM 		    "fcsm_open: failed. open type 0x%x for minor 0x%x is not "
17307836SJohn.Forte@Sun.COM 		    "OTYP_CHR", otyp, getminor(*devp)));
17317836SJohn.Forte@Sun.COM 		return (EINVAL);
17327836SJohn.Forte@Sun.COM 	}
17337836SJohn.Forte@Sun.COM 
17347836SJohn.Forte@Sun.COM 	/*
17357836SJohn.Forte@Sun.COM 	 * Allow anybody to open (both root and non-root users).
17367836SJohn.Forte@Sun.COM 	 * Previlege level checks are made on the per ioctl basis.
17377836SJohn.Forte@Sun.COM 	 */
17387836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm_global_mutex);
17397836SJohn.Forte@Sun.COM 	if (flags & FEXCL) {
17407836SJohn.Forte@Sun.COM 		if (fcsm_flag & FCSM_OPEN) {
17417836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm_global_mutex);
17427836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
17437836SJohn.Forte@Sun.COM 			    "fcsm_open: exclusive open of 0x%x failed",
17447836SJohn.Forte@Sun.COM 			    getminor(*devp)));
17457836SJohn.Forte@Sun.COM 			return (EBUSY);
17467836SJohn.Forte@Sun.COM 		} else {
17477836SJohn.Forte@Sun.COM 			ASSERT(fcsm_flag == FCSM_IDLE);
17487836SJohn.Forte@Sun.COM 			fcsm_flag |= FCSM_EXCL;
17497836SJohn.Forte@Sun.COM 		}
17507836SJohn.Forte@Sun.COM 	} else {
17517836SJohn.Forte@Sun.COM 		if (fcsm_flag & FCSM_EXCL) {
17527836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm_global_mutex);
17537836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
17547836SJohn.Forte@Sun.COM 			    "fcsm_open: failed. Device minor 0x%x is in "
17557836SJohn.Forte@Sun.COM 			    "exclusive open mode", getminor(*devp)));
17567836SJohn.Forte@Sun.COM 			return (EBUSY);
17577836SJohn.Forte@Sun.COM 		}
17587836SJohn.Forte@Sun.COM 
17597836SJohn.Forte@Sun.COM 	}
17607836SJohn.Forte@Sun.COM 	fcsm_flag |= FCSM_OPEN;
17617836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm_global_mutex);
17627836SJohn.Forte@Sun.COM 	return (0);
17637836SJohn.Forte@Sun.COM }
17647836SJohn.Forte@Sun.COM 
17657836SJohn.Forte@Sun.COM 
17667836SJohn.Forte@Sun.COM /* ARGSUSED */
17677836SJohn.Forte@Sun.COM static int
fcsm_close(dev_t dev,int flag,int otyp,cred_t * credp)17687836SJohn.Forte@Sun.COM fcsm_close(dev_t dev, int flag, int otyp, cred_t *credp)
17697836SJohn.Forte@Sun.COM {
17707836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "close"));
17717836SJohn.Forte@Sun.COM 
17727836SJohn.Forte@Sun.COM 	if (otyp != OTYP_CHR) {
17737836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
17747836SJohn.Forte@Sun.COM 		    "fcsm_close: failed. close type 0x%x for minor 0x%x is not "
17757836SJohn.Forte@Sun.COM 		    "OTYP_CHR", otyp, getminor(dev)));
17767836SJohn.Forte@Sun.COM 		return (EINVAL);
17777836SJohn.Forte@Sun.COM 	}
17787836SJohn.Forte@Sun.COM 
17797836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm_global_mutex);
17807836SJohn.Forte@Sun.COM 	if ((fcsm_flag & FCSM_OPEN) == 0) {
17817836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm_global_mutex);
17827836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
17837836SJohn.Forte@Sun.COM 		    "fcsm_close: failed. minor 0x%x is already closed",
17847836SJohn.Forte@Sun.COM 		    getminor(dev)));
17857836SJohn.Forte@Sun.COM 		return (ENODEV);
17867836SJohn.Forte@Sun.COM 	}
17877836SJohn.Forte@Sun.COM 	fcsm_flag = FCSM_IDLE;
17887836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm_global_mutex);
17897836SJohn.Forte@Sun.COM 	return (0);
17907836SJohn.Forte@Sun.COM }
17917836SJohn.Forte@Sun.COM 
17927836SJohn.Forte@Sun.COM 
17937836SJohn.Forte@Sun.COM /* ARGSUSED */
17947836SJohn.Forte@Sun.COM static void
fcsm_disp_devlist(fcsm_t * fcsm,fc_portmap_t * devlist,uint32_t dev_cnt)17957836SJohn.Forte@Sun.COM fcsm_disp_devlist(fcsm_t *fcsm, fc_portmap_t *devlist, uint32_t dev_cnt)
17967836SJohn.Forte@Sun.COM {
17977836SJohn.Forte@Sun.COM 	fc_portmap_t	*map;
17987836SJohn.Forte@Sun.COM 	uint32_t	i;
17997836SJohn.Forte@Sun.COM 
18007836SJohn.Forte@Sun.COM 	if (dev_cnt == 0) {
18017836SJohn.Forte@Sun.COM 		return;
18027836SJohn.Forte@Sun.COM 	}
18037836SJohn.Forte@Sun.COM 
18047836SJohn.Forte@Sun.COM 	ASSERT(devlist != NULL);
18057836SJohn.Forte@Sun.COM 	for (i = 0; i < dev_cnt; i++) {
18067836SJohn.Forte@Sun.COM 		map = &devlist[i];
18077836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
18087836SJohn.Forte@Sun.COM 		    "list[%d]: ID 0x%x WWN %x:%x:%x:%x:%x:%x:%x:%x "
18097836SJohn.Forte@Sun.COM 		    "state (0x%x) "
18107836SJohn.Forte@Sun.COM 		    "type <%s>(0x%x) "
18117836SJohn.Forte@Sun.COM 		    "flags (0x%x)",
18127836SJohn.Forte@Sun.COM 		    i, map->map_did.port_id,
18137836SJohn.Forte@Sun.COM 		    map->map_pwwn.raw_wwn[0], map->map_pwwn.raw_wwn[1],
18147836SJohn.Forte@Sun.COM 		    map->map_pwwn.raw_wwn[2], map->map_pwwn.raw_wwn[3],
18157836SJohn.Forte@Sun.COM 		    map->map_pwwn.raw_wwn[4], map->map_pwwn.raw_wwn[5],
18167836SJohn.Forte@Sun.COM 		    map->map_pwwn.raw_wwn[6], map->map_pwwn.raw_wwn[7],
18177836SJohn.Forte@Sun.COM 		    map->map_state,
18187836SJohn.Forte@Sun.COM 		    fcsm_dev_type_to_str(map->map_type), map->map_type,
18197836SJohn.Forte@Sun.COM 		    map->map_flags));
18207836SJohn.Forte@Sun.COM 	}
18217836SJohn.Forte@Sun.COM }
18227836SJohn.Forte@Sun.COM 
18237836SJohn.Forte@Sun.COM /* ARGSUSED */
18247836SJohn.Forte@Sun.COM static void
fcsm_display(int level,int flags,fcsm_t * fcsm,fc_packet_t * pkt,const char * fmt,...)18257836SJohn.Forte@Sun.COM fcsm_display(int level, int flags, fcsm_t *fcsm, fc_packet_t *pkt,
18267836SJohn.Forte@Sun.COM     const char *fmt, ...)
18277836SJohn.Forte@Sun.COM {
18287836SJohn.Forte@Sun.COM 	caddr_t	buf;
18297836SJohn.Forte@Sun.COM 	va_list	ap;
18307836SJohn.Forte@Sun.COM 
18317836SJohn.Forte@Sun.COM 	buf = kmem_zalloc(256, KM_NOSLEEP);
18327836SJohn.Forte@Sun.COM 	if (buf == NULL) {
18337836SJohn.Forte@Sun.COM 		return;
18347836SJohn.Forte@Sun.COM 	}
18357836SJohn.Forte@Sun.COM 
18367836SJohn.Forte@Sun.COM 	if (fcsm) {
18377836SJohn.Forte@Sun.COM 		(void) sprintf(buf + strlen(buf), "fcsm(%d): ",
18387836SJohn.Forte@Sun.COM 		    ddi_get_instance(fcsm->sm_port_info.port_dip));
18397836SJohn.Forte@Sun.COM 	} else {
18407836SJohn.Forte@Sun.COM 		(void) sprintf(buf, "fcsm: ");
18417836SJohn.Forte@Sun.COM 	}
18427836SJohn.Forte@Sun.COM 
18437836SJohn.Forte@Sun.COM 	va_start(ap, fmt);
18447836SJohn.Forte@Sun.COM 	(void) vsprintf(buf + strlen(buf), fmt, ap);
18457836SJohn.Forte@Sun.COM 	va_end(ap);
18467836SJohn.Forte@Sun.COM 
18477836SJohn.Forte@Sun.COM 	if (pkt) {
18487836SJohn.Forte@Sun.COM 		caddr_t state, reason, action, expln;
18497836SJohn.Forte@Sun.COM 
18507836SJohn.Forte@Sun.COM 		(void) fc_ulp_pkt_error(pkt, &state, &reason, &action, &expln);
18517836SJohn.Forte@Sun.COM 
18527836SJohn.Forte@Sun.COM 		(void) sprintf(buf + strlen(buf),
18537836SJohn.Forte@Sun.COM 		    " state: %s(0x%x); reason: %s(0x%x)",
18547836SJohn.Forte@Sun.COM 		    state, pkt->pkt_state, reason, pkt->pkt_reason);
18557836SJohn.Forte@Sun.COM 	}
18567836SJohn.Forte@Sun.COM 
18577836SJohn.Forte@Sun.COM 	switch (flags) {
1858*10264SZhong.Wang@Sun.COM 	case SM_LOG:
1859*10264SZhong.Wang@Sun.COM 		cmn_err(level, "!%s", buf);
1860*10264SZhong.Wang@Sun.COM 		break;
1861*10264SZhong.Wang@Sun.COM 
1862*10264SZhong.Wang@Sun.COM 	case SM_CONSOLE:
1863*10264SZhong.Wang@Sun.COM 		cmn_err(level, "^%s", buf);
1864*10264SZhong.Wang@Sun.COM 		break;
1865*10264SZhong.Wang@Sun.COM 
1866*10264SZhong.Wang@Sun.COM 	default:
1867*10264SZhong.Wang@Sun.COM 		cmn_err(level, "%s", buf);
1868*10264SZhong.Wang@Sun.COM 		break;
18697836SJohn.Forte@Sun.COM 	}
18707836SJohn.Forte@Sun.COM 
18717836SJohn.Forte@Sun.COM 	kmem_free(buf, 256);
18727836SJohn.Forte@Sun.COM }
18737836SJohn.Forte@Sun.COM 
18747836SJohn.Forte@Sun.COM 
18757836SJohn.Forte@Sun.COM /*
18767836SJohn.Forte@Sun.COM  * Convert FC packet state to FC errno
18777836SJohn.Forte@Sun.COM  */
18787836SJohn.Forte@Sun.COM int
fcsm_pkt_state_to_rval(uchar_t state,uint32_t reason)18797836SJohn.Forte@Sun.COM fcsm_pkt_state_to_rval(uchar_t state, uint32_t reason)
18807836SJohn.Forte@Sun.COM {
18817836SJohn.Forte@Sun.COM 	int count;
18827836SJohn.Forte@Sun.COM 
18837836SJohn.Forte@Sun.COM 	if (state == FC_PKT_LOCAL_RJT && (reason == FC_REASON_NO_CONNECTION ||
18847836SJohn.Forte@Sun.COM 	    reason == FC_REASON_LOGIN_REQUIRED)) {
18857836SJohn.Forte@Sun.COM 		return (FC_LOGINREQ);
18867836SJohn.Forte@Sun.COM 	} else if (state == FC_PKT_PORT_OFFLINE &&
18877836SJohn.Forte@Sun.COM 	    reason == FC_REASON_LOGIN_REQUIRED) {
18887836SJohn.Forte@Sun.COM 		return (FC_LOGINREQ);
18897836SJohn.Forte@Sun.COM 	}
18907836SJohn.Forte@Sun.COM 
18917836SJohn.Forte@Sun.COM 	for (count = 0; count < sizeof (fcsm_xlat_pkt_state) /
18927836SJohn.Forte@Sun.COM 	    sizeof (fcsm_xlat_pkt_state[0]); count++) {
18937836SJohn.Forte@Sun.COM 		if (fcsm_xlat_pkt_state[count].xlat_state == state) {
18947836SJohn.Forte@Sun.COM 			return (fcsm_xlat_pkt_state[count].xlat_rval);
18957836SJohn.Forte@Sun.COM 		}
18967836SJohn.Forte@Sun.COM 	}
18977836SJohn.Forte@Sun.COM 
18987836SJohn.Forte@Sun.COM 	return (FC_FAILURE);
18997836SJohn.Forte@Sun.COM }
19007836SJohn.Forte@Sun.COM 
19017836SJohn.Forte@Sun.COM 
19027836SJohn.Forte@Sun.COM /*
19037836SJohn.Forte@Sun.COM  * Convert port state state to descriptive string
19047836SJohn.Forte@Sun.COM  */
19057836SJohn.Forte@Sun.COM caddr_t
fcsm_port_state_to_str(uint32_t port_state)19067836SJohn.Forte@Sun.COM fcsm_port_state_to_str(uint32_t port_state)
19077836SJohn.Forte@Sun.COM {
19087836SJohn.Forte@Sun.COM 	int count;
19097836SJohn.Forte@Sun.COM 
19107836SJohn.Forte@Sun.COM 	for (count = 0; count < sizeof (fcsm_xlat_port_state) /
19117836SJohn.Forte@Sun.COM 	    sizeof (fcsm_xlat_port_state[0]); count++) {
19127836SJohn.Forte@Sun.COM 		if (fcsm_xlat_port_state[count].xlat_pstate == port_state) {
19137836SJohn.Forte@Sun.COM 			return (fcsm_xlat_port_state[count].xlat_state_str);
19147836SJohn.Forte@Sun.COM 		}
19157836SJohn.Forte@Sun.COM 	}
19167836SJohn.Forte@Sun.COM 
19177836SJohn.Forte@Sun.COM 	return (NULL);
19187836SJohn.Forte@Sun.COM }
19197836SJohn.Forte@Sun.COM 
19207836SJohn.Forte@Sun.COM 
19217836SJohn.Forte@Sun.COM /*
19227836SJohn.Forte@Sun.COM  * Convert port topology state to descriptive string
19237836SJohn.Forte@Sun.COM  */
19247836SJohn.Forte@Sun.COM caddr_t
fcsm_topology_to_str(uint32_t topology)19257836SJohn.Forte@Sun.COM fcsm_topology_to_str(uint32_t topology)
19267836SJohn.Forte@Sun.COM {
19277836SJohn.Forte@Sun.COM 	int count;
19287836SJohn.Forte@Sun.COM 
19297836SJohn.Forte@Sun.COM 	for (count = 0; count < sizeof (fcsm_xlat_topology) /
19307836SJohn.Forte@Sun.COM 	    sizeof (fcsm_xlat_topology[0]); count++) {
19317836SJohn.Forte@Sun.COM 		if (fcsm_xlat_topology[count].xlat_top == topology) {
19327836SJohn.Forte@Sun.COM 			return (fcsm_xlat_topology[count].xlat_top_str);
19337836SJohn.Forte@Sun.COM 		}
19347836SJohn.Forte@Sun.COM 	}
19357836SJohn.Forte@Sun.COM 
19367836SJohn.Forte@Sun.COM 	return (NULL);
19377836SJohn.Forte@Sun.COM }
19387836SJohn.Forte@Sun.COM 
19397836SJohn.Forte@Sun.COM 
19407836SJohn.Forte@Sun.COM /*
19417836SJohn.Forte@Sun.COM  * Convert port topology state to descriptive string
19427836SJohn.Forte@Sun.COM  */
19437836SJohn.Forte@Sun.COM static caddr_t
fcsm_dev_type_to_str(uint32_t type)19447836SJohn.Forte@Sun.COM fcsm_dev_type_to_str(uint32_t type)
19457836SJohn.Forte@Sun.COM {
19467836SJohn.Forte@Sun.COM 	int count;
19477836SJohn.Forte@Sun.COM 
19487836SJohn.Forte@Sun.COM 	for (count = 0; count < sizeof (fcsm_xlat_dev_type) /
19497836SJohn.Forte@Sun.COM 	    sizeof (fcsm_xlat_dev_type[0]); count++) {
19507836SJohn.Forte@Sun.COM 		if (fcsm_xlat_dev_type[count].xlat_type == type) {
19517836SJohn.Forte@Sun.COM 			return (fcsm_xlat_dev_type[count].xlat_str);
19527836SJohn.Forte@Sun.COM 		}
19537836SJohn.Forte@Sun.COM 	}
19547836SJohn.Forte@Sun.COM 
19557836SJohn.Forte@Sun.COM 	return (NULL);
19567836SJohn.Forte@Sun.COM }
19577836SJohn.Forte@Sun.COM 
19587836SJohn.Forte@Sun.COM static int
fcsm_cmd_cache_constructor(void * buf,void * cdarg,int kmflags)19597836SJohn.Forte@Sun.COM fcsm_cmd_cache_constructor(void *buf, void *cdarg, int kmflags)
19607836SJohn.Forte@Sun.COM {
19617836SJohn.Forte@Sun.COM 	fcsm_cmd_t		*cmd = (fcsm_cmd_t *)buf;
19627836SJohn.Forte@Sun.COM 	fcsm_t			*fcsm = (fcsm_t *)cdarg;
19637836SJohn.Forte@Sun.COM 	int			(*callback)(caddr_t);
19647836SJohn.Forte@Sun.COM 	fc_packet_t		*pkt;
19657836SJohn.Forte@Sun.COM 	fc_ulp_port_info_t	*pinfo;
19667836SJohn.Forte@Sun.COM 
19677836SJohn.Forte@Sun.COM 	ASSERT(fcsm != NULL && buf != NULL);
19687836SJohn.Forte@Sun.COM 	callback = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT;
19697836SJohn.Forte@Sun.COM 
19707836SJohn.Forte@Sun.COM 	cmd->cmd_fp_pkt		= &cmd->cmd_fc_packet;
19717836SJohn.Forte@Sun.COM 	cmd->cmd_job		= NULL;
19727836SJohn.Forte@Sun.COM 	cmd->cmd_fcsm		= fcsm;
19737836SJohn.Forte@Sun.COM 	cmd->cmd_dma_flags	= 0;
19747836SJohn.Forte@Sun.COM 
19757836SJohn.Forte@Sun.COM 	pkt = &cmd->cmd_fc_packet;
19767836SJohn.Forte@Sun.COM 
19777836SJohn.Forte@Sun.COM 	pkt->pkt_ulp_rscn_infop = NULL;
19787836SJohn.Forte@Sun.COM 	pkt->pkt_fca_private = (opaque_t)((caddr_t)cmd + sizeof (fcsm_cmd_t));
19797836SJohn.Forte@Sun.COM 	pkt->pkt_ulp_private = (opaque_t)cmd;
19807836SJohn.Forte@Sun.COM 
1981*10264SZhong.Wang@Sun.COM 	if (!(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
1982*10264SZhong.Wang@Sun.COM 		pinfo = &fcsm->sm_port_info;
1983*10264SZhong.Wang@Sun.COM 		if (ddi_dma_alloc_handle(pinfo->port_dip,
1984*10264SZhong.Wang@Sun.COM 		    pinfo->port_cmd_dma_attr,
1985*10264SZhong.Wang@Sun.COM 		    callback, NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
1986*10264SZhong.Wang@Sun.COM 			return (1);
1987*10264SZhong.Wang@Sun.COM 		}
1988*10264SZhong.Wang@Sun.COM 
1989*10264SZhong.Wang@Sun.COM 		if (ddi_dma_alloc_handle(pinfo->port_dip,
1990*10264SZhong.Wang@Sun.COM 		    pinfo->port_resp_dma_attr,
1991*10264SZhong.Wang@Sun.COM 		    callback, NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) {
1992*10264SZhong.Wang@Sun.COM 			ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1993*10264SZhong.Wang@Sun.COM 			return (1);
1994*10264SZhong.Wang@Sun.COM 		}
1995*10264SZhong.Wang@Sun.COM 	} else {
1996*10264SZhong.Wang@Sun.COM 		pkt->pkt_cmd_dma  = NULL;
1997*10264SZhong.Wang@Sun.COM 		pkt->pkt_cmd	  = NULL;
1998*10264SZhong.Wang@Sun.COM 		pkt->pkt_resp_dma = NULL;
1999*10264SZhong.Wang@Sun.COM 		pkt->pkt_resp	  = NULL;
20007836SJohn.Forte@Sun.COM 	}
20017836SJohn.Forte@Sun.COM 
20027836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
20037836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt =
20047836SJohn.Forte@Sun.COM 	    pkt->pkt_data_cookie_cnt = 0;
20057836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie =
20067836SJohn.Forte@Sun.COM 	    pkt->pkt_data_cookie = NULL;
20077836SJohn.Forte@Sun.COM 
20087836SJohn.Forte@Sun.COM 	return (0);
20097836SJohn.Forte@Sun.COM }
20107836SJohn.Forte@Sun.COM 
20117836SJohn.Forte@Sun.COM 
20127836SJohn.Forte@Sun.COM /* ARGSUSED */
20137836SJohn.Forte@Sun.COM static void
fcsm_cmd_cache_destructor(void * buf,void * cdarg)20147836SJohn.Forte@Sun.COM fcsm_cmd_cache_destructor(void *buf, void *cdarg)
20157836SJohn.Forte@Sun.COM {
20167836SJohn.Forte@Sun.COM 	fcsm_cmd_t	*cmd = (fcsm_cmd_t *)buf;
20177836SJohn.Forte@Sun.COM 	fcsm_t		*fcsm = (fcsm_t *)cdarg;
20187836SJohn.Forte@Sun.COM 	fc_packet_t	*pkt;
20197836SJohn.Forte@Sun.COM 
20207836SJohn.Forte@Sun.COM 	ASSERT(fcsm == cmd->cmd_fcsm);
20217836SJohn.Forte@Sun.COM 
20227836SJohn.Forte@Sun.COM 	pkt = cmd->cmd_fp_pkt;
20237836SJohn.Forte@Sun.COM 
20247836SJohn.Forte@Sun.COM 	if (pkt->pkt_cmd_dma != NULL) {
20257836SJohn.Forte@Sun.COM 		ddi_dma_free_handle(&pkt->pkt_cmd_dma);
20267836SJohn.Forte@Sun.COM 	}
20277836SJohn.Forte@Sun.COM 
20287836SJohn.Forte@Sun.COM 	if (pkt->pkt_resp_dma != NULL) {
20297836SJohn.Forte@Sun.COM 		ddi_dma_free_handle(&pkt->pkt_resp_dma);
20307836SJohn.Forte@Sun.COM 	}
20317836SJohn.Forte@Sun.COM }
20327836SJohn.Forte@Sun.COM 
20337836SJohn.Forte@Sun.COM 
20347836SJohn.Forte@Sun.COM static fcsm_cmd_t *
fcsm_alloc_cmd(fcsm_t * fcsm,uint32_t cmd_len,uint32_t resp_len,int sleep)20357836SJohn.Forte@Sun.COM fcsm_alloc_cmd(fcsm_t *fcsm, uint32_t cmd_len, uint32_t resp_len, int sleep)
20367836SJohn.Forte@Sun.COM {
20377836SJohn.Forte@Sun.COM 	fcsm_cmd_t	*cmd;
20387836SJohn.Forte@Sun.COM 	fc_packet_t	*pkt;
20397836SJohn.Forte@Sun.COM 	int		rval;
20407836SJohn.Forte@Sun.COM 	ulong_t		real_len;
20417836SJohn.Forte@Sun.COM 	int		(*callback)(caddr_t);
20427836SJohn.Forte@Sun.COM 	ddi_dma_cookie_t	pkt_cookie;
20437836SJohn.Forte@Sun.COM 	ddi_dma_cookie_t	*cp;
20447836SJohn.Forte@Sun.COM 	uint32_t		cnt;
20457836SJohn.Forte@Sun.COM 	fc_ulp_port_info_t	*pinfo;
20467836SJohn.Forte@Sun.COM 
20477836SJohn.Forte@Sun.COM 	ASSERT(fcsm != NULL);
20487836SJohn.Forte@Sun.COM 	pinfo = &fcsm->sm_port_info;
20497836SJohn.Forte@Sun.COM 
20507836SJohn.Forte@Sun.COM 	callback = (sleep == KM_SLEEP) ? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT;
20517836SJohn.Forte@Sun.COM 
20527836SJohn.Forte@Sun.COM 	cmd = (fcsm_cmd_t *)kmem_cache_alloc(fcsm->sm_cmd_cache, sleep);
20537836SJohn.Forte@Sun.COM 	if (cmd == NULL) {
20547836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, fcsm, NULL,
20557836SJohn.Forte@Sun.COM 		    "alloc_cmd: kmem_cache_alloc failed"));
20567836SJohn.Forte@Sun.COM 		return (NULL);
20577836SJohn.Forte@Sun.COM 	}
20587836SJohn.Forte@Sun.COM 
20597836SJohn.Forte@Sun.COM 	cmd->cmd_retry_count	= 0;
20607836SJohn.Forte@Sun.COM 	cmd->cmd_max_retries	= 0;
20617836SJohn.Forte@Sun.COM 	cmd->cmd_retry_interval	= 0;
20627836SJohn.Forte@Sun.COM 	cmd->cmd_transport	= NULL;
20637836SJohn.Forte@Sun.COM 
20647836SJohn.Forte@Sun.COM 	ASSERT(cmd->cmd_dma_flags == 0);
20657836SJohn.Forte@Sun.COM 	ASSERT(cmd->cmd_fp_pkt == &cmd->cmd_fc_packet);
20667836SJohn.Forte@Sun.COM 	pkt = cmd->cmd_fp_pkt;
20677836SJohn.Forte@Sun.COM 
20687836SJohn.Forte@Sun.COM 	/* Zero out the important fc_packet fields */
20697836SJohn.Forte@Sun.COM 	pkt->pkt_pd		= NULL;
20707836SJohn.Forte@Sun.COM 	pkt->pkt_datalen	= 0;
20717836SJohn.Forte@Sun.COM 	pkt->pkt_data		= NULL;
20727836SJohn.Forte@Sun.COM 	pkt->pkt_state		= 0;
20737836SJohn.Forte@Sun.COM 	pkt->pkt_action		= 0;
20747836SJohn.Forte@Sun.COM 	pkt->pkt_reason		= 0;
20757836SJohn.Forte@Sun.COM 	pkt->pkt_expln		= 0;
20767836SJohn.Forte@Sun.COM 
20777836SJohn.Forte@Sun.COM 	/*
20787836SJohn.Forte@Sun.COM 	 * Now that pkt_pd is initialized, we can call fc_ulp_init_packet
20797836SJohn.Forte@Sun.COM 	 */
20807836SJohn.Forte@Sun.COM 
20817836SJohn.Forte@Sun.COM 	if (fc_ulp_init_packet((opaque_t)pinfo->port_handle, pkt, sleep)
20827836SJohn.Forte@Sun.COM 	    != FC_SUCCESS) {
20837836SJohn.Forte@Sun.COM 		kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
20847836SJohn.Forte@Sun.COM 		return (NULL);
20857836SJohn.Forte@Sun.COM 	}
20867836SJohn.Forte@Sun.COM 
2087*10264SZhong.Wang@Sun.COM 	if ((cmd_len) && !(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
20887836SJohn.Forte@Sun.COM 		ASSERT(pkt->pkt_cmd_dma != NULL);
20897836SJohn.Forte@Sun.COM 
20907836SJohn.Forte@Sun.COM 		rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
20917836SJohn.Forte@Sun.COM 		    fcsm->sm_port_info.port_acc_attr, DDI_DMA_CONSISTENT,
20927836SJohn.Forte@Sun.COM 		    callback, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len,
20937836SJohn.Forte@Sun.COM 		    &pkt->pkt_cmd_acc);
20947836SJohn.Forte@Sun.COM 
20957836SJohn.Forte@Sun.COM 		if (rval != DDI_SUCCESS) {
20967836SJohn.Forte@Sun.COM 			(void) fc_ulp_uninit_packet(
20977836SJohn.Forte@Sun.COM 			    (opaque_t)pinfo->port_handle, pkt);
20987836SJohn.Forte@Sun.COM 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
20997836SJohn.Forte@Sun.COM 			fcsm_free_cmd_dma(cmd);
21007836SJohn.Forte@Sun.COM 			return (NULL);
21017836SJohn.Forte@Sun.COM 		}
21027836SJohn.Forte@Sun.COM 
21037836SJohn.Forte@Sun.COM 		cmd->cmd_dma_flags |= FCSM_CF_CMD_VALID_DMA_MEM;
21047836SJohn.Forte@Sun.COM 
21057836SJohn.Forte@Sun.COM 		if (real_len < cmd_len) {
21067836SJohn.Forte@Sun.COM 			(void) fc_ulp_uninit_packet(
21077836SJohn.Forte@Sun.COM 			    (opaque_t)pinfo->port_handle, pkt);
21087836SJohn.Forte@Sun.COM 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
21097836SJohn.Forte@Sun.COM 			fcsm_free_cmd_dma(cmd);
21107836SJohn.Forte@Sun.COM 			return (NULL);
21117836SJohn.Forte@Sun.COM 		}
21127836SJohn.Forte@Sun.COM 
21137836SJohn.Forte@Sun.COM 		rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
21147836SJohn.Forte@Sun.COM 		    pkt->pkt_cmd, real_len, DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
21157836SJohn.Forte@Sun.COM 		    callback, NULL, &pkt_cookie, &pkt->pkt_cmd_cookie_cnt);
21167836SJohn.Forte@Sun.COM 
21177836SJohn.Forte@Sun.COM 		if (rval != DDI_DMA_MAPPED) {
21187836SJohn.Forte@Sun.COM 			(void) fc_ulp_uninit_packet(
21197836SJohn.Forte@Sun.COM 			    (opaque_t)pinfo->port_handle, pkt);
21207836SJohn.Forte@Sun.COM 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
21217836SJohn.Forte@Sun.COM 			fcsm_free_cmd_dma(cmd);
21227836SJohn.Forte@Sun.COM 			return (NULL);
21237836SJohn.Forte@Sun.COM 		}
21247836SJohn.Forte@Sun.COM 
21257836SJohn.Forte@Sun.COM 		cmd->cmd_dma_flags |= FCSM_CF_CMD_VALID_DMA_BIND;
21267836SJohn.Forte@Sun.COM 
21277836SJohn.Forte@Sun.COM 		if (pkt->pkt_cmd_cookie_cnt >
21287836SJohn.Forte@Sun.COM 		    pinfo->port_cmd_dma_attr->dma_attr_sgllen) {
21297836SJohn.Forte@Sun.COM 			(void) fc_ulp_uninit_packet(
21307836SJohn.Forte@Sun.COM 			    (opaque_t)pinfo->port_handle, pkt);
21317836SJohn.Forte@Sun.COM 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
21327836SJohn.Forte@Sun.COM 			fcsm_free_cmd_dma(cmd);
21337836SJohn.Forte@Sun.COM 			return (NULL);
21347836SJohn.Forte@Sun.COM 		}
21357836SJohn.Forte@Sun.COM 
21367836SJohn.Forte@Sun.COM 		ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
21377836SJohn.Forte@Sun.COM 
21387836SJohn.Forte@Sun.COM 		cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
21397836SJohn.Forte@Sun.COM 		    pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
21407836SJohn.Forte@Sun.COM 		    KM_NOSLEEP);
21417836SJohn.Forte@Sun.COM 
21427836SJohn.Forte@Sun.COM 		if (cp == NULL) {
21437836SJohn.Forte@Sun.COM 			(void) fc_ulp_uninit_packet(
21447836SJohn.Forte@Sun.COM 			    (opaque_t)pinfo->port_handle, pkt);
21457836SJohn.Forte@Sun.COM 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
21467836SJohn.Forte@Sun.COM 			fcsm_free_cmd_dma(cmd);
21477836SJohn.Forte@Sun.COM 			return (NULL);
21487836SJohn.Forte@Sun.COM 		}
21497836SJohn.Forte@Sun.COM 
21507836SJohn.Forte@Sun.COM 		*cp = pkt_cookie;
21517836SJohn.Forte@Sun.COM 		cp++;
21527836SJohn.Forte@Sun.COM 		for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
21537836SJohn.Forte@Sun.COM 			ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
21547836SJohn.Forte@Sun.COM 			*cp = pkt_cookie;
21557836SJohn.Forte@Sun.COM 		}
2156*10264SZhong.Wang@Sun.COM 	} else if (cmd_len != 0) {
2157*10264SZhong.Wang@Sun.COM 		pkt->pkt_cmd = kmem_zalloc(cmd_len, KM_SLEEP);
21587836SJohn.Forte@Sun.COM 	}
21597836SJohn.Forte@Sun.COM 
2160*10264SZhong.Wang@Sun.COM 	if ((resp_len) && !(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
21617836SJohn.Forte@Sun.COM 		ASSERT(pkt->pkt_resp_dma != NULL);
21627836SJohn.Forte@Sun.COM 
21637836SJohn.Forte@Sun.COM 		rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
21647836SJohn.Forte@Sun.COM 		    fcsm->sm_port_info.port_acc_attr, DDI_DMA_CONSISTENT,
21657836SJohn.Forte@Sun.COM 		    callback, NULL, (caddr_t *)&pkt->pkt_resp, &real_len,
21667836SJohn.Forte@Sun.COM 		    &pkt->pkt_resp_acc);
21677836SJohn.Forte@Sun.COM 
21687836SJohn.Forte@Sun.COM 		if (rval != DDI_SUCCESS) {
21697836SJohn.Forte@Sun.COM 			(void) fc_ulp_uninit_packet(
21707836SJohn.Forte@Sun.COM 			    (opaque_t)pinfo->port_handle, pkt);
21717836SJohn.Forte@Sun.COM 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
21727836SJohn.Forte@Sun.COM 			fcsm_free_cmd_dma(cmd);
21737836SJohn.Forte@Sun.COM 			return (NULL);
21747836SJohn.Forte@Sun.COM 		}
21757836SJohn.Forte@Sun.COM 
21767836SJohn.Forte@Sun.COM 		cmd->cmd_dma_flags |= FCSM_CF_RESP_VALID_DMA_MEM;
21777836SJohn.Forte@Sun.COM 
21787836SJohn.Forte@Sun.COM 		if (real_len < resp_len) {
21797836SJohn.Forte@Sun.COM 			(void) fc_ulp_uninit_packet(
21807836SJohn.Forte@Sun.COM 			    (opaque_t)pinfo->port_handle, pkt);
21817836SJohn.Forte@Sun.COM 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
21827836SJohn.Forte@Sun.COM 			fcsm_free_cmd_dma(cmd);
21837836SJohn.Forte@Sun.COM 			return (NULL);
21847836SJohn.Forte@Sun.COM 		}
21857836SJohn.Forte@Sun.COM 
21867836SJohn.Forte@Sun.COM 		rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
21877836SJohn.Forte@Sun.COM 		    pkt->pkt_resp, real_len, DDI_DMA_READ | DDI_DMA_CONSISTENT,
21887836SJohn.Forte@Sun.COM 		    callback, NULL, &pkt_cookie, &pkt->pkt_resp_cookie_cnt);
21897836SJohn.Forte@Sun.COM 
21907836SJohn.Forte@Sun.COM 		if (rval != DDI_DMA_MAPPED) {
21917836SJohn.Forte@Sun.COM 			(void) fc_ulp_uninit_packet(
21927836SJohn.Forte@Sun.COM 			    (opaque_t)pinfo->port_handle, pkt);
21937836SJohn.Forte@Sun.COM 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
21947836SJohn.Forte@Sun.COM 			fcsm_free_cmd_dma(cmd);
21957836SJohn.Forte@Sun.COM 			return (NULL);
21967836SJohn.Forte@Sun.COM 		}
21977836SJohn.Forte@Sun.COM 
21987836SJohn.Forte@Sun.COM 		cmd->cmd_dma_flags |= FCSM_CF_RESP_VALID_DMA_BIND;
21997836SJohn.Forte@Sun.COM 
22007836SJohn.Forte@Sun.COM 		if (pkt->pkt_resp_cookie_cnt >
22017836SJohn.Forte@Sun.COM 		    pinfo->port_resp_dma_attr->dma_attr_sgllen) {
22027836SJohn.Forte@Sun.COM 			(void) fc_ulp_uninit_packet(
22037836SJohn.Forte@Sun.COM 			    (opaque_t)pinfo->port_handle, pkt);
22047836SJohn.Forte@Sun.COM 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
22057836SJohn.Forte@Sun.COM 			fcsm_free_cmd_dma(cmd);
22067836SJohn.Forte@Sun.COM 			return (NULL);
22077836SJohn.Forte@Sun.COM 		}
22087836SJohn.Forte@Sun.COM 
22097836SJohn.Forte@Sun.COM 		ASSERT(pkt->pkt_resp_cookie_cnt != 0);
22107836SJohn.Forte@Sun.COM 
22117836SJohn.Forte@Sun.COM 		cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc(
22127836SJohn.Forte@Sun.COM 		    pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie),
22137836SJohn.Forte@Sun.COM 		    KM_NOSLEEP);
22147836SJohn.Forte@Sun.COM 
22157836SJohn.Forte@Sun.COM 		if (cp == NULL) {
22167836SJohn.Forte@Sun.COM 			(void) fc_ulp_uninit_packet(
22177836SJohn.Forte@Sun.COM 			    (opaque_t)pinfo->port_handle, pkt);
22187836SJohn.Forte@Sun.COM 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
22197836SJohn.Forte@Sun.COM 			fcsm_free_cmd_dma(cmd);
22207836SJohn.Forte@Sun.COM 			return (NULL);
22217836SJohn.Forte@Sun.COM 		}
22227836SJohn.Forte@Sun.COM 
22237836SJohn.Forte@Sun.COM 		*cp = pkt_cookie;
22247836SJohn.Forte@Sun.COM 		cp++;
22257836SJohn.Forte@Sun.COM 		for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) {
22267836SJohn.Forte@Sun.COM 			ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
22277836SJohn.Forte@Sun.COM 			*cp = pkt_cookie;
22287836SJohn.Forte@Sun.COM 		}
2229*10264SZhong.Wang@Sun.COM 	} else if (resp_len != 0) {
2230*10264SZhong.Wang@Sun.COM 		pkt->pkt_resp = kmem_zalloc(resp_len, KM_SLEEP);
22317836SJohn.Forte@Sun.COM 	}
22327836SJohn.Forte@Sun.COM 
22337836SJohn.Forte@Sun.COM 	pkt->pkt_cmdlen = cmd_len;
22347836SJohn.Forte@Sun.COM 	pkt->pkt_rsplen = resp_len;
22357836SJohn.Forte@Sun.COM 
22367836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
22377836SJohn.Forte@Sun.COM 	    "alloc_cmd: cmd 0x%p", (void *)cmd));
22387836SJohn.Forte@Sun.COM 	return (cmd);
22397836SJohn.Forte@Sun.COM }
22407836SJohn.Forte@Sun.COM 
22417836SJohn.Forte@Sun.COM static void
fcsm_free_cmd(fcsm_cmd_t * cmd)22427836SJohn.Forte@Sun.COM fcsm_free_cmd(fcsm_cmd_t *cmd)
22437836SJohn.Forte@Sun.COM {
22447836SJohn.Forte@Sun.COM 	fcsm_t		*fcsm;
22457836SJohn.Forte@Sun.COM 
22467836SJohn.Forte@Sun.COM 	fcsm = cmd->cmd_fcsm;
22477836SJohn.Forte@Sun.COM 	ASSERT(fcsm != NULL);
22487836SJohn.Forte@Sun.COM 
22497836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
22507836SJohn.Forte@Sun.COM 	    "free_cmd: cmd 0x%p", (void *)cmd));
22517836SJohn.Forte@Sun.COM 
22527836SJohn.Forte@Sun.COM 	fcsm_free_cmd_dma(cmd);
22537836SJohn.Forte@Sun.COM 
22547836SJohn.Forte@Sun.COM 	(void) fc_ulp_uninit_packet((opaque_t)fcsm->sm_port_info.port_handle,
22557836SJohn.Forte@Sun.COM 	    cmd->cmd_fp_pkt);
22567836SJohn.Forte@Sun.COM 	kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
22577836SJohn.Forte@Sun.COM }
22587836SJohn.Forte@Sun.COM 
22597836SJohn.Forte@Sun.COM static void
fcsm_free_cmd_dma(fcsm_cmd_t * cmd)22607836SJohn.Forte@Sun.COM fcsm_free_cmd_dma(fcsm_cmd_t *cmd)
22617836SJohn.Forte@Sun.COM {
22627836SJohn.Forte@Sun.COM 	fc_packet_t	*pkt;
22637836SJohn.Forte@Sun.COM 
22647836SJohn.Forte@Sun.COM 	pkt = cmd->cmd_fp_pkt;
22657836SJohn.Forte@Sun.COM 	ASSERT(pkt != NULL);
22667836SJohn.Forte@Sun.COM 
2267*10264SZhong.Wang@Sun.COM 	if (cmd->cmd_fcsm->sm_flags & FCSM_USING_NODMA_FCA) {
2268*10264SZhong.Wang@Sun.COM 		if (pkt->pkt_cmd) {
2269*10264SZhong.Wang@Sun.COM 			kmem_free(pkt->pkt_cmd, pkt->pkt_cmdlen);
2270*10264SZhong.Wang@Sun.COM 			pkt->pkt_cmd = NULL;
2271*10264SZhong.Wang@Sun.COM 		}
2272*10264SZhong.Wang@Sun.COM 
2273*10264SZhong.Wang@Sun.COM 		if (pkt->pkt_resp) {
2274*10264SZhong.Wang@Sun.COM 			kmem_free(pkt->pkt_resp, pkt->pkt_rsplen);
2275*10264SZhong.Wang@Sun.COM 			pkt->pkt_resp = NULL;
2276*10264SZhong.Wang@Sun.COM 		}
2277*10264SZhong.Wang@Sun.COM 	}
2278*10264SZhong.Wang@Sun.COM 
22797836SJohn.Forte@Sun.COM 	pkt->pkt_cmdlen = 0;
22807836SJohn.Forte@Sun.COM 	pkt->pkt_rsplen = 0;
22817836SJohn.Forte@Sun.COM 	pkt->pkt_tran_type = 0;
22827836SJohn.Forte@Sun.COM 	pkt->pkt_tran_flags = 0;
22837836SJohn.Forte@Sun.COM 
22847836SJohn.Forte@Sun.COM 	if (pkt->pkt_cmd_cookie != NULL) {
22857836SJohn.Forte@Sun.COM 		kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt *
22867836SJohn.Forte@Sun.COM 		    sizeof (ddi_dma_cookie_t));
22877836SJohn.Forte@Sun.COM 		pkt->pkt_cmd_cookie = NULL;
22887836SJohn.Forte@Sun.COM 	}
22897836SJohn.Forte@Sun.COM 
22907836SJohn.Forte@Sun.COM 	if (pkt->pkt_resp_cookie != NULL) {
22917836SJohn.Forte@Sun.COM 		kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt *
22927836SJohn.Forte@Sun.COM 		    sizeof (ddi_dma_cookie_t));
22937836SJohn.Forte@Sun.COM 		pkt->pkt_resp_cookie = NULL;
22947836SJohn.Forte@Sun.COM 	}
22957836SJohn.Forte@Sun.COM 
22967836SJohn.Forte@Sun.COM 	if (cmd->cmd_dma_flags & FCSM_CF_CMD_VALID_DMA_BIND) {
22977836SJohn.Forte@Sun.COM 		(void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
22987836SJohn.Forte@Sun.COM 	}
22997836SJohn.Forte@Sun.COM 
23007836SJohn.Forte@Sun.COM 	if (cmd->cmd_dma_flags & FCSM_CF_CMD_VALID_DMA_MEM) {
23017836SJohn.Forte@Sun.COM 		if (pkt->pkt_cmd_acc) {
23027836SJohn.Forte@Sun.COM 			ddi_dma_mem_free(&pkt->pkt_cmd_acc);
23037836SJohn.Forte@Sun.COM 		}
23047836SJohn.Forte@Sun.COM 	}
23057836SJohn.Forte@Sun.COM 
23067836SJohn.Forte@Sun.COM 	if (cmd->cmd_dma_flags & FCSM_CF_RESP_VALID_DMA_BIND) {
23077836SJohn.Forte@Sun.COM 		(void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
23087836SJohn.Forte@Sun.COM 	}
23097836SJohn.Forte@Sun.COM 
23107836SJohn.Forte@Sun.COM 	if (cmd->cmd_dma_flags & FCSM_CF_RESP_VALID_DMA_MEM) {
23117836SJohn.Forte@Sun.COM 		if (pkt->pkt_resp_acc) {
23127836SJohn.Forte@Sun.COM 			ddi_dma_mem_free(&pkt->pkt_resp_acc);
23137836SJohn.Forte@Sun.COM 		}
23147836SJohn.Forte@Sun.COM 	}
23157836SJohn.Forte@Sun.COM 
23167836SJohn.Forte@Sun.COM 	cmd->cmd_dma_flags = 0;
23177836SJohn.Forte@Sun.COM }
23187836SJohn.Forte@Sun.COM 
23197836SJohn.Forte@Sun.COM /* ARGSUSED */
23207836SJohn.Forte@Sun.COM static int
fcsm_job_cache_constructor(void * buf,void * cdarg,int kmflag)23217836SJohn.Forte@Sun.COM fcsm_job_cache_constructor(void *buf, void *cdarg, int kmflag)
23227836SJohn.Forte@Sun.COM {
23237836SJohn.Forte@Sun.COM 	fcsm_job_t *job = (fcsm_job_t *)buf;
23247836SJohn.Forte@Sun.COM 
23257836SJohn.Forte@Sun.COM 	mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL);
23267836SJohn.Forte@Sun.COM 	sema_init(&job->job_sema, 0, NULL, SEMA_DEFAULT, NULL);
23277836SJohn.Forte@Sun.COM 
23287836SJohn.Forte@Sun.COM 	return (0);
23297836SJohn.Forte@Sun.COM }
23307836SJohn.Forte@Sun.COM 
23317836SJohn.Forte@Sun.COM /* ARGSUSED */
23327836SJohn.Forte@Sun.COM static void
fcsm_job_cache_destructor(void * buf,void * cdarg)23337836SJohn.Forte@Sun.COM fcsm_job_cache_destructor(void *buf, void *cdarg)
23347836SJohn.Forte@Sun.COM {
23357836SJohn.Forte@Sun.COM 	fcsm_job_t *job = (fcsm_job_t *)buf;
23367836SJohn.Forte@Sun.COM 
23377836SJohn.Forte@Sun.COM 	sema_destroy(&job->job_sema);
23387836SJohn.Forte@Sun.COM 	mutex_destroy(&job->job_mutex);
23397836SJohn.Forte@Sun.COM }
23407836SJohn.Forte@Sun.COM 
23417836SJohn.Forte@Sun.COM 
23427836SJohn.Forte@Sun.COM static fcsm_job_t *
fcsm_alloc_job(int sleep)23437836SJohn.Forte@Sun.COM fcsm_alloc_job(int sleep)
23447836SJohn.Forte@Sun.COM {
23457836SJohn.Forte@Sun.COM 	fcsm_job_t	*job;
23467836SJohn.Forte@Sun.COM 
23477836SJohn.Forte@Sun.COM 	job = (fcsm_job_t *)kmem_cache_alloc(fcsm_job_cache, sleep);
23487836SJohn.Forte@Sun.COM 	if (job != NULL) {
23497836SJohn.Forte@Sun.COM 		job->job_code		= FCSM_JOB_NONE;
23507836SJohn.Forte@Sun.COM 		job->job_flags		= 0;
23517836SJohn.Forte@Sun.COM 		job->job_port_instance	= -1;
2352*10264SZhong.Wang@Sun.COM 		job->job_result		= -1;
23537836SJohn.Forte@Sun.COM 		job->job_arg		= (opaque_t)0;
23547836SJohn.Forte@Sun.COM 		job->job_caller_priv	= (opaque_t)0;
23557836SJohn.Forte@Sun.COM 		job->job_comp		= NULL;
23567836SJohn.Forte@Sun.COM 		job->job_comp_arg	= (opaque_t)0;
23577836SJohn.Forte@Sun.COM 		job->job_priv		= (void *)0;
23587836SJohn.Forte@Sun.COM 		job->job_priv_flags	= 0;
23597836SJohn.Forte@Sun.COM 		job->job_next		= 0;
23607836SJohn.Forte@Sun.COM 	}
23617836SJohn.Forte@Sun.COM 
23627836SJohn.Forte@Sun.COM 	return (job);
23637836SJohn.Forte@Sun.COM }
23647836SJohn.Forte@Sun.COM 
23657836SJohn.Forte@Sun.COM static void
fcsm_dealloc_job(fcsm_job_t * job)23667836SJohn.Forte@Sun.COM fcsm_dealloc_job(fcsm_job_t *job)
23677836SJohn.Forte@Sun.COM {
23687836SJohn.Forte@Sun.COM 	kmem_cache_free(fcsm_job_cache, (void *)job);
23697836SJohn.Forte@Sun.COM }
23707836SJohn.Forte@Sun.COM 
23717836SJohn.Forte@Sun.COM 
23727836SJohn.Forte@Sun.COM static void
fcsm_init_job(fcsm_job_t * job,int instance,uint32_t command,uint32_t flags,opaque_t arg,opaque_t caller_priv,void (* comp)(opaque_t,fcsm_job_t *,int),opaque_t comp_arg)23737836SJohn.Forte@Sun.COM fcsm_init_job(fcsm_job_t *job, int instance, uint32_t command, uint32_t flags,
23747836SJohn.Forte@Sun.COM     opaque_t arg, opaque_t caller_priv,
23757836SJohn.Forte@Sun.COM     void (*comp)(opaque_t, fcsm_job_t *, int), opaque_t comp_arg)
23767836SJohn.Forte@Sun.COM {
23777836SJohn.Forte@Sun.COM 	ASSERT(job != NULL);
23787836SJohn.Forte@Sun.COM 	job->job_port_instance	= instance;
23797836SJohn.Forte@Sun.COM 	job->job_code		= command;
23807836SJohn.Forte@Sun.COM 	job->job_flags		= flags;
2381*10264SZhong.Wang@Sun.COM 	job->job_arg		= arg;
2382*10264SZhong.Wang@Sun.COM 	job->job_caller_priv	= caller_priv;
23837836SJohn.Forte@Sun.COM 	job->job_comp		= comp;
23847836SJohn.Forte@Sun.COM 	job->job_comp_arg	= comp_arg;
23857836SJohn.Forte@Sun.COM 	job->job_retry_count	= 0;
23867836SJohn.Forte@Sun.COM }
23877836SJohn.Forte@Sun.COM 
23887836SJohn.Forte@Sun.COM static int
fcsm_process_job(fcsm_job_t * job,int priority_flag)23897836SJohn.Forte@Sun.COM fcsm_process_job(fcsm_job_t *job, int priority_flag)
23907836SJohn.Forte@Sun.COM {
23917836SJohn.Forte@Sun.COM 	fcsm_t	*fcsm;
23927836SJohn.Forte@Sun.COM 	int	sync;
23937836SJohn.Forte@Sun.COM 
23947836SJohn.Forte@Sun.COM 	ASSERT(job != NULL);
23957836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&job->job_mutex));
23967836SJohn.Forte@Sun.COM 
23977836SJohn.Forte@Sun.COM 	fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
23987836SJohn.Forte@Sun.COM 
23997836SJohn.Forte@Sun.COM 	if (fcsm == NULL) {
24007836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
24017836SJohn.Forte@Sun.COM 		    "process_job: port instance 0x%x not found",
24027836SJohn.Forte@Sun.COM 		    job->job_port_instance));
24037836SJohn.Forte@Sun.COM 		return (FC_BADDEV);
24047836SJohn.Forte@Sun.COM 	}
24057836SJohn.Forte@Sun.COM 
24067836SJohn.Forte@Sun.COM 	mutex_enter(&job->job_mutex);
24077836SJohn.Forte@Sun.COM 	/* Both SYNC and ASYNC flags should not be set */
24087836SJohn.Forte@Sun.COM 	ASSERT(((job->job_flags & (FCSM_JOBFLAG_SYNC | FCSM_JOBFLAG_ASYNC)) ==
24097836SJohn.Forte@Sun.COM 	    FCSM_JOBFLAG_SYNC) || ((job->job_flags &
24107836SJohn.Forte@Sun.COM 	    (FCSM_JOBFLAG_SYNC | FCSM_JOBFLAG_ASYNC)) == FCSM_JOBFLAG_ASYNC));
24117836SJohn.Forte@Sun.COM 	/*
24127836SJohn.Forte@Sun.COM 	 * Check if job is a synchronous job. We might not be able to
24137836SJohn.Forte@Sun.COM 	 * check it reliably after enque_job(), if job is an ASYNC job.
24147836SJohn.Forte@Sun.COM 	 */
24157836SJohn.Forte@Sun.COM 	sync = job->job_flags & FCSM_JOBFLAG_SYNC;
24167836SJohn.Forte@Sun.COM 	mutex_exit(&job->job_mutex);
24177836SJohn.Forte@Sun.COM 
24187836SJohn.Forte@Sun.COM 	/* Queue the job for processing by job thread */
24197836SJohn.Forte@Sun.COM 	fcsm_enque_job(fcsm, job, priority_flag);
24207836SJohn.Forte@Sun.COM 
24217836SJohn.Forte@Sun.COM 	/* Wait for job completion, if it is a synchronous job */
24227836SJohn.Forte@Sun.COM 	if (sync) {
24237836SJohn.Forte@Sun.COM 		/*
24247836SJohn.Forte@Sun.COM 		 * This is a Synchronous Job. So job structure is available.
24257836SJohn.Forte@Sun.COM 		 * Caller is responsible for freeing it.
24267836SJohn.Forte@Sun.COM 		 */
24277836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_ERR, (CE_CONT, SM_LOG, fcsm, NULL,
24287836SJohn.Forte@Sun.COM 		    "process_job: Waiting for sync job <%p> completion",
24297836SJohn.Forte@Sun.COM 		    (void *)job));
24307836SJohn.Forte@Sun.COM 		sema_p(&job->job_sema);
24317836SJohn.Forte@Sun.COM 	}
24327836SJohn.Forte@Sun.COM 
24337836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
24347836SJohn.Forte@Sun.COM }
24357836SJohn.Forte@Sun.COM 
24367836SJohn.Forte@Sun.COM static void
fcsm_enque_job(fcsm_t * fcsm,fcsm_job_t * job,int priority_flag)24377836SJohn.Forte@Sun.COM fcsm_enque_job(fcsm_t *fcsm, fcsm_job_t *job, int priority_flag)
24387836SJohn.Forte@Sun.COM {
24397836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
24407836SJohn.Forte@Sun.COM 
24417836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
24427836SJohn.Forte@Sun.COM 	/* Queue the job at the head or tail depending on the job priority */
24437836SJohn.Forte@Sun.COM 	if (priority_flag) {
24447836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL,
24457836SJohn.Forte@Sun.COM 		    "enque_job: job 0x%p is high priority", job));
24467836SJohn.Forte@Sun.COM 		/* Queue at the head */
24477836SJohn.Forte@Sun.COM 		if (fcsm->sm_job_tail == NULL) {
24487836SJohn.Forte@Sun.COM 			ASSERT(fcsm->sm_job_head == NULL);
24497836SJohn.Forte@Sun.COM 			fcsm->sm_job_head = fcsm->sm_job_tail = job;
24507836SJohn.Forte@Sun.COM 		} else {
24517836SJohn.Forte@Sun.COM 			ASSERT(fcsm->sm_job_head != NULL);
24527836SJohn.Forte@Sun.COM 			job->job_next = fcsm->sm_job_head;
24537836SJohn.Forte@Sun.COM 			fcsm->sm_job_head = job;
24547836SJohn.Forte@Sun.COM 		}
24557836SJohn.Forte@Sun.COM 	} else {
24567836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL,
24577836SJohn.Forte@Sun.COM 		    "enque_job: job 0x%p is normal", job));
24587836SJohn.Forte@Sun.COM 		/* Queue at the tail */
24597836SJohn.Forte@Sun.COM 		if (fcsm->sm_job_tail == NULL) {
24607836SJohn.Forte@Sun.COM 			ASSERT(fcsm->sm_job_head == NULL);
24617836SJohn.Forte@Sun.COM 			fcsm->sm_job_head = fcsm->sm_job_tail = job;
24627836SJohn.Forte@Sun.COM 		} else {
24637836SJohn.Forte@Sun.COM 			ASSERT(fcsm->sm_job_head != NULL);
24647836SJohn.Forte@Sun.COM 			fcsm->sm_job_tail->job_next = job;
24657836SJohn.Forte@Sun.COM 			fcsm->sm_job_tail = job;
24667836SJohn.Forte@Sun.COM 		}
24677836SJohn.Forte@Sun.COM 		job->job_next = NULL;
24687836SJohn.Forte@Sun.COM 	}
24697836SJohn.Forte@Sun.COM 
24707836SJohn.Forte@Sun.COM 	/* Signal the job thread to process the job */
24717836SJohn.Forte@Sun.COM 	cv_signal(&fcsm->sm_job_cv);
24727836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
24737836SJohn.Forte@Sun.COM }
24747836SJohn.Forte@Sun.COM 
24757836SJohn.Forte@Sun.COM static int
fcsm_retry_job(fcsm_t * fcsm,fcsm_job_t * job)24767836SJohn.Forte@Sun.COM fcsm_retry_job(fcsm_t *fcsm, fcsm_job_t *job)
24777836SJohn.Forte@Sun.COM {
24787836SJohn.Forte@Sun.COM 	/*
24797836SJohn.Forte@Sun.COM 	 * If it is a CT passthru job and status is login required, then
24807836SJohn.Forte@Sun.COM 	 * retry the job so that login can be performed again.
24817836SJohn.Forte@Sun.COM 	 * Ensure that this retry is performed a finite number of times,
24827836SJohn.Forte@Sun.COM 	 * so that a faulty fabric does not cause us to retry forever.
24837836SJohn.Forte@Sun.COM 	 */
24847836SJohn.Forte@Sun.COM 
24857836SJohn.Forte@Sun.COM 	switch (job->job_code) {
24867836SJohn.Forte@Sun.COM 	case FCSM_JOB_CT_PASSTHRU: {
24877836SJohn.Forte@Sun.COM 		uint32_t	jobflag;
24887836SJohn.Forte@Sun.COM 		fc_ct_header_t	*ct_header;
24897836SJohn.Forte@Sun.COM 
24907836SJohn.Forte@Sun.COM 		if (job->job_result != FC_LOGINREQ) {
24917836SJohn.Forte@Sun.COM 			break;
24927836SJohn.Forte@Sun.COM 		}
24937836SJohn.Forte@Sun.COM 
24947836SJohn.Forte@Sun.COM 		/*
24957836SJohn.Forte@Sun.COM 		 * If it is a management server command
24967836SJohn.Forte@Sun.COM 		 * then Reset the Management server login flag, so that login
24977836SJohn.Forte@Sun.COM 		 * gets re-established.
24987836SJohn.Forte@Sun.COM 		 * If it is a Name server command,
24997836SJohn.Forte@Sun.COM 		 * then it is 'fp' responsibility to perform the login.
25007836SJohn.Forte@Sun.COM 		 */
25017836SJohn.Forte@Sun.COM 		ASSERT(job->job_arg != NULL);
25027836SJohn.Forte@Sun.COM 		ct_header =
25037836SJohn.Forte@Sun.COM 		    (fc_ct_header_t *)((fcio_t *)job->job_arg)->fcio_ibuf;
25047836SJohn.Forte@Sun.COM 		if (ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) {
25057836SJohn.Forte@Sun.COM 			mutex_enter(&fcsm->sm_mutex);
25067836SJohn.Forte@Sun.COM 			fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGGED_IN;
25077836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm->sm_mutex);
25087836SJohn.Forte@Sun.COM 		}
25097836SJohn.Forte@Sun.COM 
25107836SJohn.Forte@Sun.COM 		if (job->job_retry_count >= fcsm_max_job_retries) {
25117836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
25127836SJohn.Forte@Sun.COM 			    "retry_job: job 0x%p max retries (%d) reached",
25137836SJohn.Forte@Sun.COM 			    (void *)job, job->job_retry_count));
25147836SJohn.Forte@Sun.COM 			break;
25157836SJohn.Forte@Sun.COM 		}
25167836SJohn.Forte@Sun.COM 
25177836SJohn.Forte@Sun.COM 		/*
25187836SJohn.Forte@Sun.COM 		 * Login is required again. Retry the command, so that
25197836SJohn.Forte@Sun.COM 		 * login will get performed again.
25207836SJohn.Forte@Sun.COM 		 */
25217836SJohn.Forte@Sun.COM 		mutex_enter(&job->job_mutex);
25227836SJohn.Forte@Sun.COM 		job->job_retry_count++;
25237836SJohn.Forte@Sun.COM 		jobflag = job->job_flags;
25247836SJohn.Forte@Sun.COM 		mutex_exit(&job->job_mutex);
25257836SJohn.Forte@Sun.COM 
25267836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
25277836SJohn.Forte@Sun.COM 		    "retry_job: retry(%d) job 0x%p",
25287836SJohn.Forte@Sun.COM 		    job->job_retry_count, (void *)job));
25297836SJohn.Forte@Sun.COM 		/*
25307836SJohn.Forte@Sun.COM 		 * This job should get picked up before the
25317836SJohn.Forte@Sun.COM 		 * other jobs sitting in the queue.
25327836SJohn.Forte@Sun.COM 		 * Requeue the command at the head and then
25337836SJohn.Forte@Sun.COM 		 * reset the SERIALIZE flag.
25347836SJohn.Forte@Sun.COM 		 */
25357836SJohn.Forte@Sun.COM 		fcsm_enque_job(fcsm, job, 1);
25367836SJohn.Forte@Sun.COM 		if (jobflag & FCSM_JOBFLAG_SERIALIZE) {
25377836SJohn.Forte@Sun.COM 			mutex_enter(&fcsm->sm_mutex);
25387836SJohn.Forte@Sun.COM 			ASSERT(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD);
25397836SJohn.Forte@Sun.COM 			fcsm->sm_flags &= ~FCSM_SERIALIZE_JOBTHREAD;
25407836SJohn.Forte@Sun.COM 
25417836SJohn.Forte@Sun.COM 			/* Signal the job thread to process the job */
25427836SJohn.Forte@Sun.COM 			cv_signal(&fcsm->sm_job_cv);
25437836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm->sm_mutex);
25447836SJohn.Forte@Sun.COM 		}
25457836SJohn.Forte@Sun.COM 
25467836SJohn.Forte@Sun.COM 		/* Command is queued for retrying */
25477836SJohn.Forte@Sun.COM 		return (0);
25487836SJohn.Forte@Sun.COM 	}
25497836SJohn.Forte@Sun.COM 
25507836SJohn.Forte@Sun.COM 	default:
25517836SJohn.Forte@Sun.COM 		break;
25527836SJohn.Forte@Sun.COM 	}
25537836SJohn.Forte@Sun.COM 	return (1);
25547836SJohn.Forte@Sun.COM }
25557836SJohn.Forte@Sun.COM 
25567836SJohn.Forte@Sun.COM static void
fcsm_jobdone(fcsm_job_t * job)25577836SJohn.Forte@Sun.COM fcsm_jobdone(fcsm_job_t *job)
25587836SJohn.Forte@Sun.COM {
25597836SJohn.Forte@Sun.COM 	fcsm_t	*fcsm;
25607836SJohn.Forte@Sun.COM 
25617836SJohn.Forte@Sun.COM 	fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
25627836SJohn.Forte@Sun.COM 	ASSERT(fcsm != NULL);
25637836SJohn.Forte@Sun.COM 
25647836SJohn.Forte@Sun.COM 	if (job->job_result != FC_SUCCESS) {
25657836SJohn.Forte@Sun.COM 		if (fcsm_retry_job(fcsm, job) == 0) {
25667836SJohn.Forte@Sun.COM 			/* Job retried. so just return from here */
25677836SJohn.Forte@Sun.COM 			return;
25687836SJohn.Forte@Sun.COM 		}
25697836SJohn.Forte@Sun.COM 	}
25707836SJohn.Forte@Sun.COM 
25717836SJohn.Forte@Sun.COM 	if (job->job_comp) {
25727836SJohn.Forte@Sun.COM 		job->job_comp(job->job_comp_arg, job, job->job_result);
25737836SJohn.Forte@Sun.COM 	}
25747836SJohn.Forte@Sun.COM 
25757836SJohn.Forte@Sun.COM 	mutex_enter(&job->job_mutex);
25767836SJohn.Forte@Sun.COM 	if (job->job_flags & FCSM_JOBFLAG_SERIALIZE) {
25777836SJohn.Forte@Sun.COM 		mutex_exit(&job->job_mutex);
25787836SJohn.Forte@Sun.COM 		mutex_enter(&fcsm->sm_mutex);
25797836SJohn.Forte@Sun.COM 		ASSERT(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD);
25807836SJohn.Forte@Sun.COM 		fcsm->sm_flags &= ~FCSM_SERIALIZE_JOBTHREAD;
25817836SJohn.Forte@Sun.COM 
25827836SJohn.Forte@Sun.COM 		/* Signal the job thread to process the job */
25837836SJohn.Forte@Sun.COM 		cv_signal(&fcsm->sm_job_cv);
25847836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
25857836SJohn.Forte@Sun.COM 		mutex_enter(&job->job_mutex);
25867836SJohn.Forte@Sun.COM 	}
25877836SJohn.Forte@Sun.COM 
25887836SJohn.Forte@Sun.COM 	if (job->job_flags & FCSM_JOBFLAG_SYNC) {
25897836SJohn.Forte@Sun.COM 		mutex_exit(&job->job_mutex);
25907836SJohn.Forte@Sun.COM 		sema_v(&job->job_sema);
25917836SJohn.Forte@Sun.COM 	} else {
25927836SJohn.Forte@Sun.COM 		mutex_exit(&job->job_mutex);
25937836SJohn.Forte@Sun.COM 		/* Async job, free the job structure */
25947836SJohn.Forte@Sun.COM 		fcsm_dealloc_job(job);
25957836SJohn.Forte@Sun.COM 	}
25967836SJohn.Forte@Sun.COM }
25977836SJohn.Forte@Sun.COM 
25987836SJohn.Forte@Sun.COM fcsm_job_t *
fcsm_deque_job(fcsm_t * fcsm)25997836SJohn.Forte@Sun.COM fcsm_deque_job(fcsm_t *fcsm)
26007836SJohn.Forte@Sun.COM {
26017836SJohn.Forte@Sun.COM 	fcsm_job_t	*job;
26027836SJohn.Forte@Sun.COM 
26037836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&fcsm->sm_mutex));
26047836SJohn.Forte@Sun.COM 
26057836SJohn.Forte@Sun.COM 	if (fcsm->sm_job_head == NULL) {
26067836SJohn.Forte@Sun.COM 		ASSERT(fcsm->sm_job_tail == NULL);
26077836SJohn.Forte@Sun.COM 		job = NULL;
26087836SJohn.Forte@Sun.COM 	} else {
26097836SJohn.Forte@Sun.COM 		ASSERT(fcsm->sm_job_tail != NULL);
26107836SJohn.Forte@Sun.COM 		job = fcsm->sm_job_head;
26117836SJohn.Forte@Sun.COM 		if (job->job_next == NULL) {
26127836SJohn.Forte@Sun.COM 			ASSERT(fcsm->sm_job_tail == job);
26137836SJohn.Forte@Sun.COM 			fcsm->sm_job_tail = NULL;
26147836SJohn.Forte@Sun.COM 		}
26157836SJohn.Forte@Sun.COM 		fcsm->sm_job_head = job->job_next;
26167836SJohn.Forte@Sun.COM 		job->job_next = NULL;
26177836SJohn.Forte@Sun.COM 	}
26187836SJohn.Forte@Sun.COM 
26197836SJohn.Forte@Sun.COM 	return (job);
26207836SJohn.Forte@Sun.COM }
26217836SJohn.Forte@Sun.COM 
26227836SJohn.Forte@Sun.COM 
26237836SJohn.Forte@Sun.COM /* Dedicated per port thread to process various commands */
26247836SJohn.Forte@Sun.COM static void
fcsm_job_thread(fcsm_t * fcsm)26257836SJohn.Forte@Sun.COM fcsm_job_thread(fcsm_t *fcsm)
26267836SJohn.Forte@Sun.COM {
26277836SJohn.Forte@Sun.COM 	fcsm_job_t	*job;
26287836SJohn.Forte@Sun.COM 
26297836SJohn.Forte@Sun.COM 	ASSERT(fcsm != NULL);
26307836SJohn.Forte@Sun.COM #ifndef __lock_lint
26317836SJohn.Forte@Sun.COM 	CALLB_CPR_INIT(&fcsm->sm_cpr_info, &fcsm->sm_mutex,
26327836SJohn.Forte@Sun.COM 	    callb_generic_cpr, "fcsm_job_thread");
26337836SJohn.Forte@Sun.COM #endif /* __lock_lint */
26347836SJohn.Forte@Sun.COM 
26357836SJohn.Forte@Sun.COM 	for (;;) {
26367836SJohn.Forte@Sun.COM 		mutex_enter(&fcsm->sm_mutex);
26377836SJohn.Forte@Sun.COM 
26387836SJohn.Forte@Sun.COM 		while (fcsm->sm_job_head == NULL ||
26397836SJohn.Forte@Sun.COM 		    fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD) {
26407836SJohn.Forte@Sun.COM 			CALLB_CPR_SAFE_BEGIN(&fcsm->sm_cpr_info);
26417836SJohn.Forte@Sun.COM 			cv_wait(&fcsm->sm_job_cv, &fcsm->sm_mutex);
26427836SJohn.Forte@Sun.COM 			CALLB_CPR_SAFE_END(&fcsm->sm_cpr_info, &fcsm->sm_mutex);
26437836SJohn.Forte@Sun.COM 		}
26447836SJohn.Forte@Sun.COM 
26457836SJohn.Forte@Sun.COM 		job = fcsm_deque_job(fcsm);
26467836SJohn.Forte@Sun.COM 
26477836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
26487836SJohn.Forte@Sun.COM 
26497836SJohn.Forte@Sun.COM 		mutex_enter(&job->job_mutex);
26507836SJohn.Forte@Sun.COM 		if (job->job_flags & FCSM_JOBFLAG_SERIALIZE) {
26517836SJohn.Forte@Sun.COM 			mutex_exit(&job->job_mutex);
26527836SJohn.Forte@Sun.COM 
26537836SJohn.Forte@Sun.COM 			mutex_enter(&fcsm->sm_mutex);
26547836SJohn.Forte@Sun.COM 			ASSERT(!(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD));
26557836SJohn.Forte@Sun.COM 			fcsm->sm_flags |= FCSM_SERIALIZE_JOBTHREAD;
26567836SJohn.Forte@Sun.COM 			mutex_exit(&fcsm->sm_mutex);
26577836SJohn.Forte@Sun.COM 		} else {
26587836SJohn.Forte@Sun.COM 			mutex_exit(&job->job_mutex);
26597836SJohn.Forte@Sun.COM 		}
26607836SJohn.Forte@Sun.COM 
26617836SJohn.Forte@Sun.COM 		ASSERT(fcsm->sm_instance == job->job_port_instance);
26627836SJohn.Forte@Sun.COM 
26637836SJohn.Forte@Sun.COM 		switch (job->job_code) {
26647836SJohn.Forte@Sun.COM 		case FCSM_JOB_NONE:
26657836SJohn.Forte@Sun.COM 			fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
26667836SJohn.Forte@Sun.COM 			    "job_thread: uninitialized job code");
26677836SJohn.Forte@Sun.COM 			job->job_result = FC_FAILURE;
26687836SJohn.Forte@Sun.COM 			fcsm_jobdone(job);
26697836SJohn.Forte@Sun.COM 			break;
26707836SJohn.Forte@Sun.COM 
26717836SJohn.Forte@Sun.COM 		case FCSM_JOB_THREAD_SHUTDOWN:
26727836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
26737836SJohn.Forte@Sun.COM 			    "job_thread: job code <JOB PORT SHUTDOWN>"));
26747836SJohn.Forte@Sun.COM 
26757836SJohn.Forte@Sun.COM 			/*
26767836SJohn.Forte@Sun.COM 			 * There should not be any pending jobs, when this
26777836SJohn.Forte@Sun.COM 			 * is being called.
26787836SJohn.Forte@Sun.COM 			 */
26797836SJohn.Forte@Sun.COM 			mutex_enter(&fcsm->sm_mutex);
26807836SJohn.Forte@Sun.COM 			ASSERT(fcsm->sm_job_head == NULL);
26817836SJohn.Forte@Sun.COM 			ASSERT(fcsm->sm_job_tail == NULL);
26827836SJohn.Forte@Sun.COM 			ASSERT(fcsm->sm_retry_head == NULL);
26837836SJohn.Forte@Sun.COM 			ASSERT(fcsm->sm_retry_tail == NULL);
26847836SJohn.Forte@Sun.COM 			job->job_result = FC_SUCCESS;
26857836SJohn.Forte@Sun.COM #ifndef __lock_lint
26867836SJohn.Forte@Sun.COM 			CALLB_CPR_EXIT(&fcsm->sm_cpr_info);
26877836SJohn.Forte@Sun.COM #endif
26887836SJohn.Forte@Sun.COM 			/* CPR_EXIT has also dropped the fcsm->sm_mutex */
26897836SJohn.Forte@Sun.COM 
26907836SJohn.Forte@Sun.COM 			fcsm_jobdone(job);
26917836SJohn.Forte@Sun.COM 			thread_exit();
26927836SJohn.Forte@Sun.COM 			/* NOTREACHED */
26937836SJohn.Forte@Sun.COM 			break;
26947836SJohn.Forte@Sun.COM 
26957836SJohn.Forte@Sun.COM 		case FCSM_JOB_LOGIN_NAME_SERVER:
26967836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
26977836SJohn.Forte@Sun.COM 			    "job_thread: job code <LOGIN_NAME_SERVER>"));
26987836SJohn.Forte@Sun.COM 			job->job_result = FC_SUCCESS;
26997836SJohn.Forte@Sun.COM 			fcsm_jobdone(job);
27007836SJohn.Forte@Sun.COM 			break;
27017836SJohn.Forte@Sun.COM 
27027836SJohn.Forte@Sun.COM 		case FCSM_JOB_LOGIN_MGMT_SERVER:
27037836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
27047836SJohn.Forte@Sun.COM 			    "job_thread: job code <LOGIN_MGMT_SERVER>"));
27057836SJohn.Forte@Sun.COM 			fcsm_job_login_mgmt_server(job);
27067836SJohn.Forte@Sun.COM 			break;
27077836SJohn.Forte@Sun.COM 
27087836SJohn.Forte@Sun.COM 		case FCSM_JOB_CT_PASSTHRU:
27097836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
27107836SJohn.Forte@Sun.COM 			    "job_thread: job code <CT_PASSTHRU>"));
27117836SJohn.Forte@Sun.COM 			fcsm_job_ct_passthru(job);
27127836SJohn.Forte@Sun.COM 			break;
27137836SJohn.Forte@Sun.COM 
27147836SJohn.Forte@Sun.COM 		default:
27157836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
27167836SJohn.Forte@Sun.COM 			    "job_thread: job code <UNKNOWN>"));
27177836SJohn.Forte@Sun.COM 			job->job_result = FC_FAILURE;
27187836SJohn.Forte@Sun.COM 			fcsm_jobdone(job);
27197836SJohn.Forte@Sun.COM 			break;
27207836SJohn.Forte@Sun.COM 		}
27217836SJohn.Forte@Sun.COM 	}
27227836SJohn.Forte@Sun.COM 
27237836SJohn.Forte@Sun.COM 	/* NOTREACHED */
27247836SJohn.Forte@Sun.COM }
27257836SJohn.Forte@Sun.COM 
27267836SJohn.Forte@Sun.COM 
27277836SJohn.Forte@Sun.COM static void
fcsm_ct_init(fcsm_t * fcsm,fcsm_cmd_t * cmd,fc_ct_aiu_t * req_iu,size_t req_len,void (* comp_func)())27287836SJohn.Forte@Sun.COM fcsm_ct_init(fcsm_t *fcsm, fcsm_cmd_t *cmd, fc_ct_aiu_t *req_iu, size_t req_len,
27297836SJohn.Forte@Sun.COM     void (*comp_func)())
27307836SJohn.Forte@Sun.COM {
27317836SJohn.Forte@Sun.COM 	fc_packet_t	*pkt;
27327836SJohn.Forte@Sun.COM 
27337836SJohn.Forte@Sun.COM 	pkt = cmd->cmd_fp_pkt;
27347836SJohn.Forte@Sun.COM 	ASSERT(pkt != NULL);
27357836SJohn.Forte@Sun.COM 
27367836SJohn.Forte@Sun.COM 	ASSERT(req_iu->aiu_header.ct_fcstype == FCSTYPE_MGMTSERVICE ||
27377836SJohn.Forte@Sun.COM 	    (req_iu->aiu_header.ct_fcstype == FCSTYPE_DIRECTORY &&
27387836SJohn.Forte@Sun.COM 	    req_iu->aiu_header.ct_fcssubtype == FCSSUB_DS_NAME_SERVER));
27397836SJohn.Forte@Sun.COM 
27407836SJohn.Forte@Sun.COM 
27417836SJohn.Forte@Sun.COM 	/* Set the pkt d_id properly */
27427836SJohn.Forte@Sun.COM 	if (req_iu->aiu_header.ct_fcstype == FCSTYPE_MGMTSERVICE) {
27437836SJohn.Forte@Sun.COM 		pkt->pkt_cmd_fhdr.d_id	= FS_MANAGEMENT_SERVER;
27447836SJohn.Forte@Sun.COM 	} else {
27457836SJohn.Forte@Sun.COM 		pkt->pkt_cmd_fhdr.d_id	= FS_NAME_SERVER;
27467836SJohn.Forte@Sun.COM 	}
27477836SJohn.Forte@Sun.COM 
27487836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.r_ctl	= R_CTL_UNSOL_CONTROL;
27497836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.rsvd	= 0;
27507836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.s_id	= fcsm->sm_sid;
27517836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.type	= FC_TYPE_FC_SERVICES;
27527836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.f_ctl	= F_CTL_SEQ_INITIATIVE |
27537836SJohn.Forte@Sun.COM 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ;
27547836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.seq_id = 0;
27557836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.df_ctl = 0;
27567836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
27577836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
27587836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
27597836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.ro	= 0;
27607836SJohn.Forte@Sun.COM 
27617836SJohn.Forte@Sun.COM 	pkt->pkt_timeout	= FCSM_MS_TIMEOUT;
27627836SJohn.Forte@Sun.COM 	pkt->pkt_comp		= comp_func;
27637836SJohn.Forte@Sun.COM 
27647836SJohn.Forte@Sun.COM 	FCSM_REP_WR(pkt->pkt_cmd_acc, req_iu, pkt->pkt_cmd, req_len);
27657836SJohn.Forte@Sun.COM 
27667836SJohn.Forte@Sun.COM 	cmd->cmd_transport = fc_ulp_transport;
27677836SJohn.Forte@Sun.COM }
27687836SJohn.Forte@Sun.COM 
27697836SJohn.Forte@Sun.COM static void
fcsm_ct_intr(fcsm_cmd_t * cmd)27707836SJohn.Forte@Sun.COM fcsm_ct_intr(fcsm_cmd_t *cmd)
27717836SJohn.Forte@Sun.COM {
27727836SJohn.Forte@Sun.COM 	fc_packet_t	*pkt;
27737836SJohn.Forte@Sun.COM 	fcsm_job_t	*job;
27747836SJohn.Forte@Sun.COM 	fcio_t		*fcio;
2775*10264SZhong.Wang@Sun.COM 	fcsm_t		*fcsm;
27767836SJohn.Forte@Sun.COM 
27777836SJohn.Forte@Sun.COM 	pkt = cmd->cmd_fp_pkt;
27787836SJohn.Forte@Sun.COM 	job = cmd->cmd_job;
27797836SJohn.Forte@Sun.COM 	ASSERT(job != NULL);
27807836SJohn.Forte@Sun.COM 
27817836SJohn.Forte@Sun.COM 	fcio = job->job_arg;
27827836SJohn.Forte@Sun.COM 	ASSERT(fcio != NULL);
27837836SJohn.Forte@Sun.COM 
27847836SJohn.Forte@Sun.COM 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
278510110SMilan.Jurik@Sun.COM 		FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, cmd->cmd_fcsm, pkt,
27867836SJohn.Forte@Sun.COM 		    "ct_intr: CT command <0x%x> to did 0x%x failed",
27877836SJohn.Forte@Sun.COM 		    ((fc_ct_aiu_t *)fcio->fcio_ibuf)->aiu_header.ct_cmdrsp,
278810110SMilan.Jurik@Sun.COM 		    pkt->pkt_cmd_fhdr.d_id));
27897836SJohn.Forte@Sun.COM 	} else {
27907836SJohn.Forte@Sun.COM 		/* Get the CT response payload */
2791*10264SZhong.Wang@Sun.COM 		fcsm = cmd->cmd_fcsm;
27927836SJohn.Forte@Sun.COM 		FCSM_REP_RD(pkt->pkt_resp_acc, fcio->fcio_obuf,
27937836SJohn.Forte@Sun.COM 		    pkt->pkt_resp, fcio->fcio_olen);
27947836SJohn.Forte@Sun.COM 	}
27957836SJohn.Forte@Sun.COM 
27967836SJohn.Forte@Sun.COM 	job->job_result =
27977836SJohn.Forte@Sun.COM 	    fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
27987836SJohn.Forte@Sun.COM 
27997836SJohn.Forte@Sun.COM 	fcsm_free_cmd(cmd);
28007836SJohn.Forte@Sun.COM 
28017836SJohn.Forte@Sun.COM 	fcsm_jobdone(job);
28027836SJohn.Forte@Sun.COM }
28037836SJohn.Forte@Sun.COM 
28047836SJohn.Forte@Sun.COM 
28057836SJohn.Forte@Sun.COM static void
fcsm_job_ct_passthru(fcsm_job_t * job)28067836SJohn.Forte@Sun.COM fcsm_job_ct_passthru(fcsm_job_t *job)
28077836SJohn.Forte@Sun.COM {
28087836SJohn.Forte@Sun.COM 	fcsm_t		*fcsm;
28097836SJohn.Forte@Sun.COM 	fcio_t		*fcio;
28107836SJohn.Forte@Sun.COM 	fcsm_cmd_t	*cmd;
28117836SJohn.Forte@Sun.COM 	int		status;
28127836SJohn.Forte@Sun.COM 	fc_ct_header_t	*ct_header;
28137836SJohn.Forte@Sun.COM 
28147836SJohn.Forte@Sun.COM 	ASSERT(job != NULL);
28157836SJohn.Forte@Sun.COM 	ASSERT(job->job_port_instance != -1);
28167836SJohn.Forte@Sun.COM 
28177836SJohn.Forte@Sun.COM 	job->job_result = FC_FAILURE;
28187836SJohn.Forte@Sun.COM 	fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
28197836SJohn.Forte@Sun.COM 	if (fcsm == NULL) {
28207836SJohn.Forte@Sun.COM 		fcsm_jobdone(job);
28217836SJohn.Forte@Sun.COM 		return;
28227836SJohn.Forte@Sun.COM 	}
28237836SJohn.Forte@Sun.COM 
28247836SJohn.Forte@Sun.COM 	/*
28257836SJohn.Forte@Sun.COM 	 * Process the CT Passthru job only if port is attached
28267836SJohn.Forte@Sun.COM 	 * to a FABRIC.
28277836SJohn.Forte@Sun.COM 	 */
28287836SJohn.Forte@Sun.COM 	if (!FC_TOP_EXTERNAL(fcsm->sm_port_top)) {
28297836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
28307836SJohn.Forte@Sun.COM 		    "job_ct_passthru: end (non-fabric port)"));
28317836SJohn.Forte@Sun.COM 		job->job_result = FC_BADDEV;
28327836SJohn.Forte@Sun.COM 		fcsm_jobdone(job);
28337836SJohn.Forte@Sun.COM 		return;
28347836SJohn.Forte@Sun.COM 	}
28357836SJohn.Forte@Sun.COM 
28367836SJohn.Forte@Sun.COM 	fcio = job->job_arg;
28377836SJohn.Forte@Sun.COM 	ASSERT(fcio != NULL);
28387836SJohn.Forte@Sun.COM 
28397836SJohn.Forte@Sun.COM 	/*
28407836SJohn.Forte@Sun.COM 	 * If it is NOT a Management Seriver (MS) or Name Server (NS) command
28417836SJohn.Forte@Sun.COM 	 * then complete the command with failure.
28427836SJohn.Forte@Sun.COM 	 */
28437836SJohn.Forte@Sun.COM 	ct_header = (fc_ct_header_t *)fcio->fcio_ibuf;
28447836SJohn.Forte@Sun.COM 
28457836SJohn.Forte@Sun.COM 	/*
28467836SJohn.Forte@Sun.COM 	 * According to libHBAAPI spec, CT header from libHBAAPI would always
28477836SJohn.Forte@Sun.COM 	 * be big endian, so we must swap CT header before continue in little
28487836SJohn.Forte@Sun.COM 	 * endian platforms.
28497836SJohn.Forte@Sun.COM 	 */
28507836SJohn.Forte@Sun.COM 	mutex_enter(&job->job_mutex);
28517836SJohn.Forte@Sun.COM 	if (!(job->job_flags & FCSM_JOBFLAG_CTHEADER_BE)) {
28527836SJohn.Forte@Sun.COM 		job->job_flags |= FCSM_JOBFLAG_CTHEADER_BE;
28537836SJohn.Forte@Sun.COM 		*((uint32_t *)((uint32_t *)ct_header + 0)) =
28547836SJohn.Forte@Sun.COM 		    BE_32(*((uint32_t *)((uint32_t *)ct_header + 0)));
28557836SJohn.Forte@Sun.COM 		*((uint32_t *)((uint32_t *)ct_header + 1)) =
28567836SJohn.Forte@Sun.COM 		    BE_32(*((uint32_t *)((uint32_t *)ct_header + 1)));
28577836SJohn.Forte@Sun.COM 		*((uint32_t *)((uint32_t *)ct_header + 2)) =
28587836SJohn.Forte@Sun.COM 		    BE_32(*((uint32_t *)((uint32_t *)ct_header + 2)));
28597836SJohn.Forte@Sun.COM 		*((uint32_t *)((uint32_t *)ct_header + 3)) =
28607836SJohn.Forte@Sun.COM 		    BE_32(*((uint32_t *)((uint32_t *)ct_header + 3)));
28617836SJohn.Forte@Sun.COM 	}
28627836SJohn.Forte@Sun.COM 	mutex_exit(&job->job_mutex);
28637836SJohn.Forte@Sun.COM 
28647836SJohn.Forte@Sun.COM 	if (ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) {
28657836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
28667836SJohn.Forte@Sun.COM 		    "job_ct_passthru: Management Server Cmd"));
28677836SJohn.Forte@Sun.COM 	} else if (ct_header->ct_fcstype == FCSTYPE_DIRECTORY) {
28687836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
28697836SJohn.Forte@Sun.COM 		    "job_ct_passthru: Name Server Cmd"));
28707836SJohn.Forte@Sun.COM 	} else {
28717836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
28727836SJohn.Forte@Sun.COM 		    "job_ct_passthru: Unsupported Destination "
28737836SJohn.Forte@Sun.COM 		    "gs_type <0x%x> gs_subtype <0x%x>",
28747836SJohn.Forte@Sun.COM 		    ct_header->ct_fcstype, ct_header->ct_fcssubtype));
28757836SJohn.Forte@Sun.COM 	}
28767836SJohn.Forte@Sun.COM 
28777836SJohn.Forte@Sun.COM 	if (ct_header->ct_fcstype != FCSTYPE_MGMTSERVICE &&
28787836SJohn.Forte@Sun.COM 	    (ct_header->ct_fcstype != FCSTYPE_DIRECTORY ||
28797836SJohn.Forte@Sun.COM 	    ct_header->ct_fcssubtype != FCSSUB_DS_NAME_SERVER)) {
28807836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
28817836SJohn.Forte@Sun.COM 		    "job_ct_passthru: end (Not a Name Server OR "
28827836SJohn.Forte@Sun.COM 		    "Mgmt Server Cmd)"));
28837836SJohn.Forte@Sun.COM 		job->job_result = FC_BADCMD;
28847836SJohn.Forte@Sun.COM 		fcsm_jobdone(job);
28857836SJohn.Forte@Sun.COM 		return;
28867836SJohn.Forte@Sun.COM 	}
28877836SJohn.Forte@Sun.COM 
28887836SJohn.Forte@Sun.COM 	/*
28897836SJohn.Forte@Sun.COM 	 * If it is an MS command and we are not logged in to the management
28907836SJohn.Forte@Sun.COM 	 * server, then start the login and requeue the command.
28917836SJohn.Forte@Sun.COM 	 * If login to management server is in progress, then reque the
28927836SJohn.Forte@Sun.COM 	 * command to wait for login to complete.
28937836SJohn.Forte@Sun.COM 	 */
28947836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
28957836SJohn.Forte@Sun.COM 	if ((ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) &&
28967836SJohn.Forte@Sun.COM 	    !(fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN)) {
28977836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
28987836SJohn.Forte@Sun.COM 		if (fcsm_login_and_process_job(fcsm, job) != FC_SUCCESS) {
28997836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
29007836SJohn.Forte@Sun.COM 			    "job_ct_passthru: perform login failed"));
29017836SJohn.Forte@Sun.COM 			job->job_result = FC_FAILURE;
29027836SJohn.Forte@Sun.COM 			fcsm_jobdone(job);
29037836SJohn.Forte@Sun.COM 		}
29047836SJohn.Forte@Sun.COM 		return;
29057836SJohn.Forte@Sun.COM 	}
29067836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
29077836SJohn.Forte@Sun.COM 
29087836SJohn.Forte@Sun.COM 	/*
29097836SJohn.Forte@Sun.COM 	 * We are already logged in to the management server.
29107836SJohn.Forte@Sun.COM 	 * Issue the CT Passthru command
29117836SJohn.Forte@Sun.COM 	 */
29127836SJohn.Forte@Sun.COM 	cmd = fcsm_alloc_cmd(fcsm, fcio->fcio_ilen, fcio->fcio_olen, KM_SLEEP);
29137836SJohn.Forte@Sun.COM 	if (cmd == NULL) {
29147836SJohn.Forte@Sun.COM 		job->job_result = FC_NOMEM;
29157836SJohn.Forte@Sun.COM 		fcsm_jobdone(job);
29167836SJohn.Forte@Sun.COM 		return;
29177836SJohn.Forte@Sun.COM 	}
29187836SJohn.Forte@Sun.COM 
29197836SJohn.Forte@Sun.COM 	FCSM_INIT_CMD(cmd, job, FC_TRAN_INTR | FC_TRAN_CLASS3, FC_PKT_EXCHANGE,
29207836SJohn.Forte@Sun.COM 	    fcsm_max_cmd_retries, fcsm_ct_intr);
29217836SJohn.Forte@Sun.COM 
29227836SJohn.Forte@Sun.COM 	fcsm_ct_init(fcsm, cmd, (fc_ct_aiu_t *)fcio->fcio_ibuf, fcio->fcio_ilen,
29237836SJohn.Forte@Sun.COM 	    fcsm_pkt_common_intr);
29247836SJohn.Forte@Sun.COM 
29257836SJohn.Forte@Sun.COM 	if ((status = fcsm_issue_cmd(cmd)) != FC_SUCCESS) {
29267836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
29277836SJohn.Forte@Sun.COM 		    "job_ct_passthru: issue CT Passthru failed, status 0x%x",
29287836SJohn.Forte@Sun.COM 		    status));
29297836SJohn.Forte@Sun.COM 		job->job_result = status;
29307836SJohn.Forte@Sun.COM 		fcsm_free_cmd(cmd);
29317836SJohn.Forte@Sun.COM 		fcsm_jobdone(job);
29327836SJohn.Forte@Sun.COM 		return;
29337836SJohn.Forte@Sun.COM 	}
29347836SJohn.Forte@Sun.COM }
29357836SJohn.Forte@Sun.COM 
29367836SJohn.Forte@Sun.COM static int
fcsm_login_and_process_job(fcsm_t * fcsm,fcsm_job_t * orig_job)29377836SJohn.Forte@Sun.COM fcsm_login_and_process_job(fcsm_t *fcsm, fcsm_job_t *orig_job)
29387836SJohn.Forte@Sun.COM {
29397836SJohn.Forte@Sun.COM 	fcsm_job_t	*login_job;
29407836SJohn.Forte@Sun.COM #ifdef DEBUG
29417836SJohn.Forte@Sun.COM 	int		status;
29427836SJohn.Forte@Sun.COM #endif /* DEBUG */
29437836SJohn.Forte@Sun.COM 
29447836SJohn.Forte@Sun.COM 	if (orig_job->job_code != FCSM_JOB_CT_PASSTHRU) {
29457836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
29467836SJohn.Forte@Sun.COM 	}
29477836SJohn.Forte@Sun.COM 
29487836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
29497836SJohn.Forte@Sun.COM 	    "login_and_process_job: start login."));
29507836SJohn.Forte@Sun.COM 
29517836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
29527836SJohn.Forte@Sun.COM 	if (fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN) {
29537836SJohn.Forte@Sun.COM 		/*
29547836SJohn.Forte@Sun.COM 		 * Directory server login completed just now, while the
29557836SJohn.Forte@Sun.COM 		 * mutex was dropped. Just queue the command again for
29567836SJohn.Forte@Sun.COM 		 * processing.
29577836SJohn.Forte@Sun.COM 		 */
29587836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
29597836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
29607836SJohn.Forte@Sun.COM 		    "login_and_process_job: got job 0x%p. login just "
29617836SJohn.Forte@Sun.COM 		    "completed", (void *)orig_job));
29627836SJohn.Forte@Sun.COM 		fcsm_enque_job(fcsm, orig_job, 0);
29637836SJohn.Forte@Sun.COM 		return (FC_SUCCESS);
29647836SJohn.Forte@Sun.COM 	}
29657836SJohn.Forte@Sun.COM 
29667836SJohn.Forte@Sun.COM 	if (fcsm->sm_flags & FCSM_MGMT_SERVER_LOGIN_IN_PROG) {
29677836SJohn.Forte@Sun.COM 		/*
29687836SJohn.Forte@Sun.COM 		 * Ideally we shouldn't have come here, since login
29697836SJohn.Forte@Sun.COM 		 * job has the serialize flag set.
29707836SJohn.Forte@Sun.COM 		 * Anyway, put the command back on the queue.
29717836SJohn.Forte@Sun.COM 		 */
29727836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
29737836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
29747836SJohn.Forte@Sun.COM 		    "login_and_process_job: got job 0x%p while login to "
29757836SJohn.Forte@Sun.COM 		    "management server in progress", (void *)orig_job));
29767836SJohn.Forte@Sun.COM 		fcsm_enque_job(fcsm, orig_job, 0);
29777836SJohn.Forte@Sun.COM 		return (FC_SUCCESS);
29787836SJohn.Forte@Sun.COM 	}
29797836SJohn.Forte@Sun.COM 
29807836SJohn.Forte@Sun.COM 	fcsm->sm_flags |= FCSM_MGMT_SERVER_LOGIN_IN_PROG;
29817836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
29827836SJohn.Forte@Sun.COM 
29837836SJohn.Forte@Sun.COM 	login_job = fcsm_alloc_job(KM_SLEEP);
29847836SJohn.Forte@Sun.COM 	ASSERT(login_job != NULL);
29857836SJohn.Forte@Sun.COM 
29867836SJohn.Forte@Sun.COM 	/*
29877836SJohn.Forte@Sun.COM 	 * Mark the login job as SERIALIZE, so that all other jobs will
29887836SJohn.Forte@Sun.COM 	 * be processed after completing the login.
29897836SJohn.Forte@Sun.COM 	 * Save the original job (CT Passthru job) in the caller private
29907836SJohn.Forte@Sun.COM 	 * field in the job structure, so that CT command can be issued
29917836SJohn.Forte@Sun.COM 	 * after login has completed.
29927836SJohn.Forte@Sun.COM 	 */
29937836SJohn.Forte@Sun.COM 	fcsm_init_job(login_job, fcsm->sm_instance, FCSM_JOB_LOGIN_MGMT_SERVER,
29947836SJohn.Forte@Sun.COM 	    FCSM_JOBFLAG_ASYNC | FCSM_JOBFLAG_SERIALIZE,
29957836SJohn.Forte@Sun.COM 	    (opaque_t)NULL, (opaque_t)orig_job, fcsm_login_ms_comp, NULL);
29967836SJohn.Forte@Sun.COM 	orig_job->job_priv = (void *)login_job;
29977836SJohn.Forte@Sun.COM 
29987836SJohn.Forte@Sun.COM #ifdef DEBUG
29997836SJohn.Forte@Sun.COM 	status = fcsm_process_job(login_job, 1);
30007836SJohn.Forte@Sun.COM 	ASSERT(status == FC_SUCCESS);
30017836SJohn.Forte@Sun.COM #else /* DEBUG */
30027836SJohn.Forte@Sun.COM 	(void) fcsm_process_job(login_job, 1);
30037836SJohn.Forte@Sun.COM #endif /* DEBUG */
30047836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
30057836SJohn.Forte@Sun.COM }
30067836SJohn.Forte@Sun.COM 
30077836SJohn.Forte@Sun.COM 
30087836SJohn.Forte@Sun.COM /* ARGSUSED */
30097836SJohn.Forte@Sun.COM static void
fcsm_login_ms_comp(opaque_t comp_arg,fcsm_job_t * login_job,int result)30107836SJohn.Forte@Sun.COM fcsm_login_ms_comp(opaque_t comp_arg, fcsm_job_t *login_job, int result)
30117836SJohn.Forte@Sun.COM {
30127836SJohn.Forte@Sun.COM 	fcsm_t		*fcsm;
30137836SJohn.Forte@Sun.COM 	fcsm_job_t	*orig_job;
30147836SJohn.Forte@Sun.COM 
30157836SJohn.Forte@Sun.COM 	ASSERT(login_job != NULL);
30167836SJohn.Forte@Sun.COM 
30177836SJohn.Forte@Sun.COM 	orig_job = (fcsm_job_t *)login_job->job_caller_priv;
30187836SJohn.Forte@Sun.COM 
30197836SJohn.Forte@Sun.COM 	ASSERT(orig_job != NULL);
30207836SJohn.Forte@Sun.COM 	ASSERT(orig_job->job_priv == (void *)login_job);
30217836SJohn.Forte@Sun.COM 	orig_job->job_priv = NULL;
30227836SJohn.Forte@Sun.COM 
30237836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
30247836SJohn.Forte@Sun.COM 	    "login_ms_comp: result 0x%x", login_job->job_result));
30257836SJohn.Forte@Sun.COM 
30267836SJohn.Forte@Sun.COM 	/* Set the login flag in the per port fcsm structure */
30277836SJohn.Forte@Sun.COM 	ASSERT(login_job->job_port_instance == orig_job->job_port_instance);
30287836SJohn.Forte@Sun.COM 	fcsm = ddi_get_soft_state(fcsm_state, login_job->job_port_instance);
30297836SJohn.Forte@Sun.COM 	ASSERT(fcsm != NULL);
30307836SJohn.Forte@Sun.COM 
30317836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
30327836SJohn.Forte@Sun.COM 	ASSERT((fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN) == 0);
30337836SJohn.Forte@Sun.COM 	ASSERT(fcsm->sm_flags & FCSM_MGMT_SERVER_LOGIN_IN_PROG);
30347836SJohn.Forte@Sun.COM 	fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGIN_IN_PROG;
30357836SJohn.Forte@Sun.COM 	if (login_job->job_result != FC_SUCCESS) {
30367836SJohn.Forte@Sun.COM 		caddr_t	msg;
30377836SJohn.Forte@Sun.COM 
30387836SJohn.Forte@Sun.COM 		/*
30397836SJohn.Forte@Sun.COM 		 * Login failed. Complete the original job with FC_LOGINREQ
30407836SJohn.Forte@Sun.COM 		 * status. Retry of that job will cause login to be
30417836SJohn.Forte@Sun.COM 		 * retried.
30427836SJohn.Forte@Sun.COM 		 */
30437836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
30447836SJohn.Forte@Sun.COM 		orig_job->job_result = FC_LOGINREQ;
30457836SJohn.Forte@Sun.COM 		fcsm_jobdone(orig_job);
30467836SJohn.Forte@Sun.COM 
30477836SJohn.Forte@Sun.COM 		(void) fc_ulp_error(login_job->job_result, &msg);
30487836SJohn.Forte@Sun.COM 		fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
30497836SJohn.Forte@Sun.COM 		    "login_ms_comp: Management server login failed: <%s>", msg);
30507836SJohn.Forte@Sun.COM 		return;
30517836SJohn.Forte@Sun.COM 	}
30527836SJohn.Forte@Sun.COM 	fcsm->sm_flags |= FCSM_MGMT_SERVER_LOGGED_IN;
30537836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
30547836SJohn.Forte@Sun.COM 
30557836SJohn.Forte@Sun.COM 	/*
30567836SJohn.Forte@Sun.COM 	 * Queue the original job at the head of the queue for processing.
30577836SJohn.Forte@Sun.COM 	 */
30587836SJohn.Forte@Sun.COM 	fcsm_enque_job(fcsm, orig_job, 1);
30597836SJohn.Forte@Sun.COM }
30607836SJohn.Forte@Sun.COM 
30617836SJohn.Forte@Sun.COM 
30627836SJohn.Forte@Sun.COM static void
fcsm_els_init(fcsm_cmd_t * cmd,uint32_t d_id)30637836SJohn.Forte@Sun.COM fcsm_els_init(fcsm_cmd_t *cmd, uint32_t d_id)
30647836SJohn.Forte@Sun.COM {
30657836SJohn.Forte@Sun.COM 	fc_packet_t	*pkt;
30667836SJohn.Forte@Sun.COM 	fcsm_t		*fcsm;
30677836SJohn.Forte@Sun.COM 
30687836SJohn.Forte@Sun.COM 	fcsm = cmd->cmd_fcsm;
30697836SJohn.Forte@Sun.COM 	pkt = cmd->cmd_fp_pkt;
30707836SJohn.Forte@Sun.COM 	ASSERT(fcsm != NULL && pkt != NULL);
30717836SJohn.Forte@Sun.COM 
30727836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.r_ctl	= R_CTL_ELS_REQ;
30737836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.d_id	= d_id;
30747836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.rsvd	= 0;
30757836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.s_id	= fcsm->sm_sid;
30767836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.type	= FC_TYPE_EXTENDED_LS;
30777836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.f_ctl	= F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
30787836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.seq_id = 0;
30797836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.df_ctl = 0;
30807836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
30817836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
30827836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
30837836SJohn.Forte@Sun.COM 	pkt->pkt_cmd_fhdr.ro	= 0;
30847836SJohn.Forte@Sun.COM 
30857836SJohn.Forte@Sun.COM 	pkt->pkt_timeout	= FCSM_ELS_TIMEOUT;
30867836SJohn.Forte@Sun.COM }
30877836SJohn.Forte@Sun.COM 
30887836SJohn.Forte@Sun.COM 
30897836SJohn.Forte@Sun.COM static int
fcsm_xlogi_init(fcsm_t * fcsm,fcsm_cmd_t * cmd,uint32_t d_id,void (* comp_func)(),uchar_t ls_code)30907836SJohn.Forte@Sun.COM fcsm_xlogi_init(fcsm_t *fcsm, fcsm_cmd_t *cmd, uint32_t d_id,
30917836SJohn.Forte@Sun.COM     void (*comp_func)(), uchar_t ls_code)
30927836SJohn.Forte@Sun.COM {
30937836SJohn.Forte@Sun.COM 	ls_code_t	payload;
30947836SJohn.Forte@Sun.COM 	fc_packet_t	*pkt;
30957836SJohn.Forte@Sun.COM 	la_els_logi_t	*login_params;
30967836SJohn.Forte@Sun.COM 	int		status;
30977836SJohn.Forte@Sun.COM 
30987836SJohn.Forte@Sun.COM 	login_params = (la_els_logi_t *)
30997836SJohn.Forte@Sun.COM 	    kmem_zalloc(sizeof (la_els_logi_t), KM_SLEEP);
31007836SJohn.Forte@Sun.COM 	if (login_params == NULL) {
31017836SJohn.Forte@Sun.COM 		return (FC_NOMEM);
31027836SJohn.Forte@Sun.COM 	}
31037836SJohn.Forte@Sun.COM 
31047836SJohn.Forte@Sun.COM 	status = fc_ulp_get_port_login_params(fcsm->sm_port_info.port_handle,
31057836SJohn.Forte@Sun.COM 	    login_params);
31067836SJohn.Forte@Sun.COM 	if (status != FC_SUCCESS) {
31077836SJohn.Forte@Sun.COM 		kmem_free(login_params, sizeof (la_els_logi_t));
31087836SJohn.Forte@Sun.COM 		return (status);
31097836SJohn.Forte@Sun.COM 	}
31107836SJohn.Forte@Sun.COM 
31117836SJohn.Forte@Sun.COM 	pkt = cmd->cmd_fp_pkt;
31127836SJohn.Forte@Sun.COM 
31137836SJohn.Forte@Sun.COM 	fcsm_els_init(cmd, d_id);
31147836SJohn.Forte@Sun.COM 	pkt->pkt_comp = comp_func;
31157836SJohn.Forte@Sun.COM 
31167836SJohn.Forte@Sun.COM 	payload.ls_code = ls_code;
31177836SJohn.Forte@Sun.COM 	payload.mbz = 0;
31187836SJohn.Forte@Sun.COM 
31197836SJohn.Forte@Sun.COM 	FCSM_REP_WR(pkt->pkt_cmd_acc, login_params,
31207836SJohn.Forte@Sun.COM 	    pkt->pkt_cmd, sizeof (la_els_logi_t));
31217836SJohn.Forte@Sun.COM 	FCSM_REP_WR(pkt->pkt_cmd_acc, &payload,
31227836SJohn.Forte@Sun.COM 	    pkt->pkt_cmd, sizeof (payload));
31237836SJohn.Forte@Sun.COM 
31247836SJohn.Forte@Sun.COM 	cmd->cmd_transport = fc_ulp_issue_els;
31257836SJohn.Forte@Sun.COM 
31267836SJohn.Forte@Sun.COM 	kmem_free(login_params, sizeof (la_els_logi_t));
31277836SJohn.Forte@Sun.COM 
31287836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
31297836SJohn.Forte@Sun.COM }
31307836SJohn.Forte@Sun.COM 
31317836SJohn.Forte@Sun.COM static void
fcsm_xlogi_intr(fcsm_cmd_t * cmd)31327836SJohn.Forte@Sun.COM fcsm_xlogi_intr(fcsm_cmd_t *cmd)
31337836SJohn.Forte@Sun.COM {
31347836SJohn.Forte@Sun.COM 	fc_packet_t	*pkt;
31357836SJohn.Forte@Sun.COM 	fcsm_job_t	*job;
31367836SJohn.Forte@Sun.COM 	fcsm_t		*fcsm;
31377836SJohn.Forte@Sun.COM 
31387836SJohn.Forte@Sun.COM 	pkt = cmd->cmd_fp_pkt;
31397836SJohn.Forte@Sun.COM 	job = cmd->cmd_job;
31407836SJohn.Forte@Sun.COM 	ASSERT(job != NULL);
31417836SJohn.Forte@Sun.COM 
31427836SJohn.Forte@Sun.COM 	fcsm = cmd->cmd_fcsm;
31437836SJohn.Forte@Sun.COM 	ASSERT(fcsm != NULL);
31447836SJohn.Forte@Sun.COM 
31457836SJohn.Forte@Sun.COM 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
31467836SJohn.Forte@Sun.COM 		fcsm_display(CE_WARN, SM_LOG, fcsm, pkt,
31477836SJohn.Forte@Sun.COM 		    "xlogi_intr: login to DID 0x%x failed",
31487836SJohn.Forte@Sun.COM 		    pkt->pkt_cmd_fhdr.d_id);
31497836SJohn.Forte@Sun.COM 	} else {
31507836SJohn.Forte@Sun.COM 		/* Get the Login parameters of the Management Server */
31517836SJohn.Forte@Sun.COM 		FCSM_REP_RD(pkt->pkt_resp_acc, &fcsm->sm_ms_service_params,
31527836SJohn.Forte@Sun.COM 		    pkt->pkt_resp, sizeof (la_els_logi_t));
31537836SJohn.Forte@Sun.COM 	}
31547836SJohn.Forte@Sun.COM 
31557836SJohn.Forte@Sun.COM 	job->job_result =
31567836SJohn.Forte@Sun.COM 	    fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
31577836SJohn.Forte@Sun.COM 
31587836SJohn.Forte@Sun.COM 	fcsm_free_cmd(cmd);
31597836SJohn.Forte@Sun.COM 
31607836SJohn.Forte@Sun.COM 	fcsm_jobdone(job);
31617836SJohn.Forte@Sun.COM }
31627836SJohn.Forte@Sun.COM 
31637836SJohn.Forte@Sun.COM static void
fcsm_job_login_mgmt_server(fcsm_job_t * job)31647836SJohn.Forte@Sun.COM fcsm_job_login_mgmt_server(fcsm_job_t *job)
31657836SJohn.Forte@Sun.COM {
31667836SJohn.Forte@Sun.COM 	fcsm_t		*fcsm;
31677836SJohn.Forte@Sun.COM 	fcsm_cmd_t	*cmd;
31687836SJohn.Forte@Sun.COM 	int		status;
31697836SJohn.Forte@Sun.COM 
31707836SJohn.Forte@Sun.COM 	ASSERT(job != NULL);
31717836SJohn.Forte@Sun.COM 	ASSERT(job->job_port_instance != -1);
31727836SJohn.Forte@Sun.COM 
31737836SJohn.Forte@Sun.COM 	fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
31747836SJohn.Forte@Sun.COM 	if (fcsm == NULL) {
31757836SJohn.Forte@Sun.COM 		job->job_result = FC_NOMEM;
31767836SJohn.Forte@Sun.COM 		fcsm_jobdone(job);
31777836SJohn.Forte@Sun.COM 		return;
31787836SJohn.Forte@Sun.COM 	}
31797836SJohn.Forte@Sun.COM 
31807836SJohn.Forte@Sun.COM 	/*
31817836SJohn.Forte@Sun.COM 	 * Issue the  Login command to the management server.
31827836SJohn.Forte@Sun.COM 	 */
31837836SJohn.Forte@Sun.COM 	cmd = fcsm_alloc_cmd(fcsm, sizeof (la_els_logi_t),
31847836SJohn.Forte@Sun.COM 	    sizeof (la_els_logi_t), KM_SLEEP);
31857836SJohn.Forte@Sun.COM 	if (cmd == NULL) {
31867836SJohn.Forte@Sun.COM 		job->job_result = FC_NOMEM;
31877836SJohn.Forte@Sun.COM 		fcsm_jobdone(job);
31887836SJohn.Forte@Sun.COM 		return;
31897836SJohn.Forte@Sun.COM 	}
31907836SJohn.Forte@Sun.COM 
31917836SJohn.Forte@Sun.COM 	FCSM_INIT_CMD(cmd, job, FC_TRAN_INTR | FC_TRAN_CLASS3, FC_PKT_EXCHANGE,
31927836SJohn.Forte@Sun.COM 	    fcsm_max_cmd_retries, fcsm_xlogi_intr);
31937836SJohn.Forte@Sun.COM 
31947836SJohn.Forte@Sun.COM 	status = fcsm_xlogi_init(fcsm, cmd, FS_MANAGEMENT_SERVER,
31957836SJohn.Forte@Sun.COM 	    fcsm_pkt_common_intr, LA_ELS_PLOGI);
31967836SJohn.Forte@Sun.COM 
31977836SJohn.Forte@Sun.COM 	if (status != FC_SUCCESS) {
31987836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
31997836SJohn.Forte@Sun.COM 		    "job_login_mgmt_server: plogi init failed. status 0x%x",
32007836SJohn.Forte@Sun.COM 		    status));
32017836SJohn.Forte@Sun.COM 		job->job_result = status;
32027836SJohn.Forte@Sun.COM 		fcsm_free_cmd(cmd);
32037836SJohn.Forte@Sun.COM 		fcsm_jobdone(job);
32047836SJohn.Forte@Sun.COM 		return;
32057836SJohn.Forte@Sun.COM 	}
32067836SJohn.Forte@Sun.COM 
32077836SJohn.Forte@Sun.COM 	if ((status = fcsm_issue_cmd(cmd)) != FC_SUCCESS) {
32087836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
32097836SJohn.Forte@Sun.COM 		    "job_ct_passthru: issue login cmd failed, status 0x%x",
32107836SJohn.Forte@Sun.COM 		    status));
32117836SJohn.Forte@Sun.COM 		job->job_result = status;
32127836SJohn.Forte@Sun.COM 		fcsm_free_cmd(cmd);
32137836SJohn.Forte@Sun.COM 		fcsm_jobdone(job);
32147836SJohn.Forte@Sun.COM 		return;
32157836SJohn.Forte@Sun.COM 	}
32167836SJohn.Forte@Sun.COM }
32177836SJohn.Forte@Sun.COM 
32187836SJohn.Forte@Sun.COM 
32197836SJohn.Forte@Sun.COM int
fcsm_ct_passthru(int instance,fcio_t * fcio,int sleep,int job_flags,void (* func)(fcio_t *))32207836SJohn.Forte@Sun.COM fcsm_ct_passthru(int instance, fcio_t *fcio, int sleep, int job_flags,
32217836SJohn.Forte@Sun.COM     void (*func)(fcio_t *))
32227836SJohn.Forte@Sun.COM {
32237836SJohn.Forte@Sun.COM 	fcsm_job_t	*job;
32247836SJohn.Forte@Sun.COM 	int		status;
32257836SJohn.Forte@Sun.COM 
32267836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
32277836SJohn.Forte@Sun.COM 	    "ct_passthru: instance 0x%x fcio 0x%p", instance, fcio));
32287836SJohn.Forte@Sun.COM 	job = fcsm_alloc_job(sleep);
32297836SJohn.Forte@Sun.COM 	ASSERT(sleep == KM_NOSLEEP || job != NULL);
32307836SJohn.Forte@Sun.COM 
32317836SJohn.Forte@Sun.COM 	fcsm_init_job(job, instance, FCSM_JOB_CT_PASSTHRU, job_flags,
32327836SJohn.Forte@Sun.COM 	    (opaque_t)fcio, (opaque_t)func, fcsm_ct_passthru_comp, NULL);
32337836SJohn.Forte@Sun.COM 	status = fcsm_process_job(job, 0);
32347836SJohn.Forte@Sun.COM 	if (status != FC_SUCCESS) {
32357836SJohn.Forte@Sun.COM 		/* Job could not be issued. So free the job and return */
32367836SJohn.Forte@Sun.COM 		fcsm_dealloc_job(job);
32377836SJohn.Forte@Sun.COM 		return (status);
32387836SJohn.Forte@Sun.COM 	}
32397836SJohn.Forte@Sun.COM 
32407836SJohn.Forte@Sun.COM 	if (job_flags & FCSM_JOBFLAG_SYNC) {
32417836SJohn.Forte@Sun.COM 		status = job->job_result;
32427836SJohn.Forte@Sun.COM 		fcsm_dealloc_job(job);
32437836SJohn.Forte@Sun.COM 	}
32447836SJohn.Forte@Sun.COM 
32457836SJohn.Forte@Sun.COM 	return (status);
32467836SJohn.Forte@Sun.COM }
32477836SJohn.Forte@Sun.COM 
32487836SJohn.Forte@Sun.COM 
32497836SJohn.Forte@Sun.COM /* ARGSUSED */
32507836SJohn.Forte@Sun.COM static void
fcsm_ct_passthru_comp(opaque_t comp_arg,fcsm_job_t * job,int result)32517836SJohn.Forte@Sun.COM fcsm_ct_passthru_comp(opaque_t comp_arg, fcsm_job_t *job, int result)
32527836SJohn.Forte@Sun.COM {
32537836SJohn.Forte@Sun.COM 	ASSERT(job != NULL);
32547836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
32557836SJohn.Forte@Sun.COM 	    "ct_passthru_comp: result 0x%x port 0x%x",
32567836SJohn.Forte@Sun.COM 	    job->job_result, job->job_port_instance));
32577836SJohn.Forte@Sun.COM }
32587836SJohn.Forte@Sun.COM 
32597836SJohn.Forte@Sun.COM 
32607836SJohn.Forte@Sun.COM static void
fcsm_pkt_common_intr(fc_packet_t * pkt)32617836SJohn.Forte@Sun.COM fcsm_pkt_common_intr(fc_packet_t *pkt)
32627836SJohn.Forte@Sun.COM {
32637836SJohn.Forte@Sun.COM 	fcsm_cmd_t	*cmd;
32647836SJohn.Forte@Sun.COM 	int		jobstatus;
32657836SJohn.Forte@Sun.COM 	fcsm_t		*fcsm;
32667836SJohn.Forte@Sun.COM 
32677836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
32687836SJohn.Forte@Sun.COM 	    "pkt_common_intr"));
32697836SJohn.Forte@Sun.COM 
32707836SJohn.Forte@Sun.COM 	cmd = (fcsm_cmd_t *)pkt->pkt_ulp_private;
32717836SJohn.Forte@Sun.COM 	ASSERT(cmd != NULL);
32727836SJohn.Forte@Sun.COM 
32737836SJohn.Forte@Sun.COM 	if (pkt->pkt_state == FC_PKT_SUCCESS) {
32747836SJohn.Forte@Sun.COM 		/* Command completed successfully. Just complete the command */
32757836SJohn.Forte@Sun.COM 		cmd->cmd_comp(cmd);
32767836SJohn.Forte@Sun.COM 		return;
32777836SJohn.Forte@Sun.COM 	}
32787836SJohn.Forte@Sun.COM 
32797836SJohn.Forte@Sun.COM 	fcsm = cmd->cmd_fcsm;
32807836SJohn.Forte@Sun.COM 	ASSERT(fcsm != NULL);
32817836SJohn.Forte@Sun.COM 
328210110SMilan.Jurik@Sun.COM 	FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, cmd->cmd_fcsm, pkt,
32837836SJohn.Forte@Sun.COM 	    "fc packet to DID 0x%x failed for pkt 0x%p",
328410110SMilan.Jurik@Sun.COM 	    pkt->pkt_cmd_fhdr.d_id, pkt));
32857836SJohn.Forte@Sun.COM 
32867836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
32877836SJohn.Forte@Sun.COM 	if (fcsm->sm_flags & FCSM_LINK_DOWN) {
32887836SJohn.Forte@Sun.COM 		/*
32897836SJohn.Forte@Sun.COM 		 * No need to retry the command. The link previously
3290*10264SZhong.Wang@Sun.COM 		 * suffered an offline	timeout.
32917836SJohn.Forte@Sun.COM 		 */
32927836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
32937836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
32947836SJohn.Forte@Sun.COM 		    "pkt_common_intr: end. Link is down"));
32957836SJohn.Forte@Sun.COM 		cmd->cmd_comp(cmd);
32967836SJohn.Forte@Sun.COM 		return;
32977836SJohn.Forte@Sun.COM 	}
32987836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
32997836SJohn.Forte@Sun.COM 
33007836SJohn.Forte@Sun.COM 	jobstatus = fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
33017836SJohn.Forte@Sun.COM 	if (jobstatus == FC_LOGINREQ) {
33027836SJohn.Forte@Sun.COM 		/*
33037836SJohn.Forte@Sun.COM 		 * Login to the destination is required. No need to
33047836SJohn.Forte@Sun.COM 		 * retry this cmd again.
33057836SJohn.Forte@Sun.COM 		 */
33067836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
33077836SJohn.Forte@Sun.COM 		    "pkt_common_intr: end. LOGIN required"));
33087836SJohn.Forte@Sun.COM 		cmd->cmd_comp(cmd);
33097836SJohn.Forte@Sun.COM 		return;
33107836SJohn.Forte@Sun.COM 	}
33117836SJohn.Forte@Sun.COM 
33127836SJohn.Forte@Sun.COM 	switch (pkt->pkt_state) {
33137836SJohn.Forte@Sun.COM 	case FC_PKT_PORT_OFFLINE:
33147836SJohn.Forte@Sun.COM 	case FC_PKT_LOCAL_RJT:
33157836SJohn.Forte@Sun.COM 	case FC_PKT_TIMEOUT: {
33167836SJohn.Forte@Sun.COM 		uchar_t		pkt_state;
33177836SJohn.Forte@Sun.COM 
33187836SJohn.Forte@Sun.COM 		pkt_state = pkt->pkt_state;
33197836SJohn.Forte@Sun.COM 		cmd->cmd_retry_interval = fcsm_retry_interval;
33207836SJohn.Forte@Sun.COM 		if (fcsm_retry_cmd(cmd) != 0) {
33217836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG,
33227836SJohn.Forte@Sun.COM 			    cmd->cmd_fcsm, NULL,
33237836SJohn.Forte@Sun.COM 			    "common_intr: max retries(%d) reached, status 0x%x",
33247836SJohn.Forte@Sun.COM 			    cmd->cmd_retry_count));
33257836SJohn.Forte@Sun.COM 
33267836SJohn.Forte@Sun.COM 			/*
33277836SJohn.Forte@Sun.COM 			 * Restore the pkt_state to the actual failure status
33287836SJohn.Forte@Sun.COM 			 * received at the time of pkt completion.
33297836SJohn.Forte@Sun.COM 			 */
33307836SJohn.Forte@Sun.COM 			pkt->pkt_state = pkt_state;
33317836SJohn.Forte@Sun.COM 			pkt->pkt_reason = 0;
33327836SJohn.Forte@Sun.COM 			cmd->cmd_comp(cmd);
33337836SJohn.Forte@Sun.COM 		} else {
33347836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG,
33357836SJohn.Forte@Sun.COM 			    cmd->cmd_fcsm, NULL,
33367836SJohn.Forte@Sun.COM 			    "pkt_common_intr: retry(%d) on pkt state (0x%x)",
33377836SJohn.Forte@Sun.COM 			    cmd->cmd_retry_count, pkt_state));
33387836SJohn.Forte@Sun.COM 		}
33397836SJohn.Forte@Sun.COM 		break;
33407836SJohn.Forte@Sun.COM 	}
33417836SJohn.Forte@Sun.COM 	default:
33427836SJohn.Forte@Sun.COM 		cmd->cmd_comp(cmd);
33437836SJohn.Forte@Sun.COM 		break;
33447836SJohn.Forte@Sun.COM 	}
33457836SJohn.Forte@Sun.COM }
33467836SJohn.Forte@Sun.COM 
33477836SJohn.Forte@Sun.COM static int
fcsm_issue_cmd(fcsm_cmd_t * cmd)33487836SJohn.Forte@Sun.COM fcsm_issue_cmd(fcsm_cmd_t *cmd)
33497836SJohn.Forte@Sun.COM {
33507836SJohn.Forte@Sun.COM 	fc_packet_t	*pkt;
33517836SJohn.Forte@Sun.COM 	fcsm_t		*fcsm;
33527836SJohn.Forte@Sun.COM 	int		status;
33537836SJohn.Forte@Sun.COM 
33547836SJohn.Forte@Sun.COM 	pkt = cmd->cmd_fp_pkt;
33557836SJohn.Forte@Sun.COM 	fcsm = cmd->cmd_fcsm;
33567836SJohn.Forte@Sun.COM 
33577836SJohn.Forte@Sun.COM 	/* Explicitly invalidate this field till fcsm decides to use it */
33587836SJohn.Forte@Sun.COM 	pkt->pkt_ulp_rscn_infop = NULL;
33597836SJohn.Forte@Sun.COM 
33607836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
33617836SJohn.Forte@Sun.COM 	    "issue_cmd: entry"));
33627836SJohn.Forte@Sun.COM 
33637836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
33647836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
33657836SJohn.Forte@Sun.COM 	if (fcsm->sm_flags & FCSM_LINK_DOWN) {
33667836SJohn.Forte@Sun.COM 		/*
33677836SJohn.Forte@Sun.COM 		 * Update the pkt_state/pkt_reason appropriately.
33687836SJohn.Forte@Sun.COM 		 * Caller of this function can decide whether to call
33697836SJohn.Forte@Sun.COM 		 * 'pkt->pkt_comp' or use the 'status' returned by this func.
33707836SJohn.Forte@Sun.COM 		 */
33717836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
33727836SJohn.Forte@Sun.COM 		pkt->pkt_state = FC_PKT_PORT_OFFLINE;
33737836SJohn.Forte@Sun.COM 		pkt->pkt_reason = FC_REASON_OFFLINE;
33747836SJohn.Forte@Sun.COM 		return (FC_OFFLINE);
33757836SJohn.Forte@Sun.COM 	}
33767836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
33777836SJohn.Forte@Sun.COM 
33787836SJohn.Forte@Sun.COM 	ASSERT(cmd->cmd_transport != NULL);
33797836SJohn.Forte@Sun.COM 	status = cmd->cmd_transport(fcsm->sm_port_info.port_handle, pkt);
33807836SJohn.Forte@Sun.COM 	if (status != FC_SUCCESS) {
33817836SJohn.Forte@Sun.COM 		switch (status) {
33827836SJohn.Forte@Sun.COM 		case FC_LOGINREQ:
33837836SJohn.Forte@Sun.COM 			/*
33847836SJohn.Forte@Sun.COM 			 * No need to retry. Return the cause of failure.
33857836SJohn.Forte@Sun.COM 			 * Also update the pkt_state/pkt_reason. Caller of
33867836SJohn.Forte@Sun.COM 			 * this function can decide, whether to call
33877836SJohn.Forte@Sun.COM 			 * 'pkt->pkt_comp' or use the 'status' code returned
33887836SJohn.Forte@Sun.COM 			 * by this function.
33897836SJohn.Forte@Sun.COM 			 */
33907836SJohn.Forte@Sun.COM 			pkt->pkt_state = FC_PKT_LOCAL_RJT;
33917836SJohn.Forte@Sun.COM 			pkt->pkt_reason = FC_REASON_LOGIN_REQUIRED;
33927836SJohn.Forte@Sun.COM 			break;
33937836SJohn.Forte@Sun.COM 
33947836SJohn.Forte@Sun.COM 		case FC_DEVICE_BUSY_NEW_RSCN:
33957836SJohn.Forte@Sun.COM 			/*
33967836SJohn.Forte@Sun.COM 			 * There was a newer RSCN than what fcsm knows about.
33977836SJohn.Forte@Sun.COM 			 * So, just retry again
33987836SJohn.Forte@Sun.COM 			 */
33997836SJohn.Forte@Sun.COM 			cmd->cmd_retry_count = 0;
34007836SJohn.Forte@Sun.COM 			/*FALLTHROUGH*/
34017836SJohn.Forte@Sun.COM 		case FC_OFFLINE:
34027836SJohn.Forte@Sun.COM 		case FC_STATEC_BUSY:
34037836SJohn.Forte@Sun.COM 			/*
34047836SJohn.Forte@Sun.COM 			 * TODO: set flag, so that command is retried after
34057836SJohn.Forte@Sun.COM 			 * port is back online.
34067836SJohn.Forte@Sun.COM 			 * FALL Through for now.
34077836SJohn.Forte@Sun.COM 			 */
34087836SJohn.Forte@Sun.COM 
34097836SJohn.Forte@Sun.COM 		case FC_TRAN_BUSY:
34107836SJohn.Forte@Sun.COM 		case FC_NOMEM:
34117836SJohn.Forte@Sun.COM 		case FC_DEVICE_BUSY:
34127836SJohn.Forte@Sun.COM 			cmd->cmd_retry_interval = fcsm_retry_interval;
34137836SJohn.Forte@Sun.COM 			if (fcsm_retry_cmd(cmd) != 0) {
34147836SJohn.Forte@Sun.COM 				FCSM_DEBUG(SMDL_TRACE,
34157836SJohn.Forte@Sun.COM 				    (CE_WARN, SM_LOG, fcsm, NULL,
34167836SJohn.Forte@Sun.COM 				    "issue_cmd: max retries (%d) reached",
34177836SJohn.Forte@Sun.COM 				    cmd->cmd_retry_count));
34187836SJohn.Forte@Sun.COM 
34197836SJohn.Forte@Sun.COM 				/*
34207836SJohn.Forte@Sun.COM 				 * status variable is not changed here.
34217836SJohn.Forte@Sun.COM 				 * Return the cause of the original
34227836SJohn.Forte@Sun.COM 				 * cmd_transport failure.
34237836SJohn.Forte@Sun.COM 				 * Update the pkt_state/pkt_reason. Caller
34247836SJohn.Forte@Sun.COM 				 * of this function can decide whether to
34257836SJohn.Forte@Sun.COM 				 * call 'pkt->pkt_comp' or use the 'status'
34267836SJohn.Forte@Sun.COM 				 * code returned by this function.
34277836SJohn.Forte@Sun.COM 				 */
34287836SJohn.Forte@Sun.COM 				pkt->pkt_state = FC_PKT_TRAN_BSY;
34297836SJohn.Forte@Sun.COM 				pkt->pkt_reason = 0;
34307836SJohn.Forte@Sun.COM 			} else {
34317836SJohn.Forte@Sun.COM 				FCSM_DEBUG(SMDL_TRACE,
34327836SJohn.Forte@Sun.COM 				    (CE_WARN, SM_LOG, fcsm, NULL,
34337836SJohn.Forte@Sun.COM 				    "issue_cmd: retry (%d) on fc status (0x%x)",
34347836SJohn.Forte@Sun.COM 				    cmd->cmd_retry_count, status));
34357836SJohn.Forte@Sun.COM 
34367836SJohn.Forte@Sun.COM 				status = FC_SUCCESS;
34377836SJohn.Forte@Sun.COM 			}
34387836SJohn.Forte@Sun.COM 			break;
34397836SJohn.Forte@Sun.COM 
34407836SJohn.Forte@Sun.COM 		default:
34417836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
34427836SJohn.Forte@Sun.COM 			    "issue_cmd: failure status 0x%x", status));
34437836SJohn.Forte@Sun.COM 
34447836SJohn.Forte@Sun.COM 			pkt->pkt_state = FC_PKT_TRAN_ERROR;
34457836SJohn.Forte@Sun.COM 			pkt->pkt_reason = 0;
34467836SJohn.Forte@Sun.COM 			break;
34477836SJohn.Forte@Sun.COM 
34487836SJohn.Forte@Sun.COM 
34497836SJohn.Forte@Sun.COM 		}
34507836SJohn.Forte@Sun.COM 	}
34517836SJohn.Forte@Sun.COM 
34527836SJohn.Forte@Sun.COM 	return (status);
34537836SJohn.Forte@Sun.COM }
34547836SJohn.Forte@Sun.COM 
34557836SJohn.Forte@Sun.COM 
34567836SJohn.Forte@Sun.COM static int
fcsm_retry_cmd(fcsm_cmd_t * cmd)34577836SJohn.Forte@Sun.COM fcsm_retry_cmd(fcsm_cmd_t *cmd)
34587836SJohn.Forte@Sun.COM {
34597836SJohn.Forte@Sun.COM 	if (cmd->cmd_retry_count < cmd->cmd_max_retries) {
34607836SJohn.Forte@Sun.COM 		cmd->cmd_retry_count++;
34617836SJohn.Forte@Sun.COM 		fcsm_enque_cmd(cmd->cmd_fcsm, cmd);
34627836SJohn.Forte@Sun.COM 		return (0);
34637836SJohn.Forte@Sun.COM 	}
34647836SJohn.Forte@Sun.COM 
34657836SJohn.Forte@Sun.COM 	return (1);
34667836SJohn.Forte@Sun.COM }
34677836SJohn.Forte@Sun.COM 
34687836SJohn.Forte@Sun.COM static void
fcsm_enque_cmd(fcsm_t * fcsm,fcsm_cmd_t * cmd)34697836SJohn.Forte@Sun.COM fcsm_enque_cmd(fcsm_t *fcsm, fcsm_cmd_t *cmd)
34707836SJohn.Forte@Sun.COM {
34717836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
34727836SJohn.Forte@Sun.COM 
34737836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "enque_cmd"));
34747836SJohn.Forte@Sun.COM 
34757836SJohn.Forte@Sun.COM 	cmd->cmd_next = NULL;
34767836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
34777836SJohn.Forte@Sun.COM 	if (fcsm->sm_retry_tail) {
34787836SJohn.Forte@Sun.COM 		ASSERT(fcsm->sm_retry_head != NULL);
34797836SJohn.Forte@Sun.COM 		fcsm->sm_retry_tail->cmd_next = cmd;
34807836SJohn.Forte@Sun.COM 		fcsm->sm_retry_tail = cmd;
34817836SJohn.Forte@Sun.COM 	} else {
34827836SJohn.Forte@Sun.COM 		ASSERT(fcsm->sm_retry_tail == NULL);
34837836SJohn.Forte@Sun.COM 		fcsm->sm_retry_head = fcsm->sm_retry_tail = cmd;
34847836SJohn.Forte@Sun.COM 
34857836SJohn.Forte@Sun.COM 		/* Schedule retry thread, if not already running */
34867836SJohn.Forte@Sun.COM 		if (fcsm->sm_retry_tid == NULL) {
34877836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
34887836SJohn.Forte@Sun.COM 			    "enque_cmd: schedule retry thread"));
34897836SJohn.Forte@Sun.COM 			fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
34907836SJohn.Forte@Sun.COM 			    (caddr_t)fcsm, fcsm_retry_ticks);
34917836SJohn.Forte@Sun.COM 		}
34927836SJohn.Forte@Sun.COM 	}
34937836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
34947836SJohn.Forte@Sun.COM }
34957836SJohn.Forte@Sun.COM 
34967836SJohn.Forte@Sun.COM 
34977836SJohn.Forte@Sun.COM static fcsm_cmd_t *
fcsm_deque_cmd(fcsm_t * fcsm)34987836SJohn.Forte@Sun.COM fcsm_deque_cmd(fcsm_t *fcsm)
34997836SJohn.Forte@Sun.COM {
35007836SJohn.Forte@Sun.COM 	fcsm_cmd_t	*cmd;
35017836SJohn.Forte@Sun.COM 
35027836SJohn.Forte@Sun.COM 	ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
35037836SJohn.Forte@Sun.COM 
35047836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "deque_cmd"));
35057836SJohn.Forte@Sun.COM 
35067836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
35077836SJohn.Forte@Sun.COM 	if (fcsm->sm_retry_head == NULL) {
35087836SJohn.Forte@Sun.COM 		ASSERT(fcsm->sm_retry_tail == NULL);
35097836SJohn.Forte@Sun.COM 		cmd = NULL;
35107836SJohn.Forte@Sun.COM 	} else {
35117836SJohn.Forte@Sun.COM 		cmd = fcsm->sm_retry_head;
35127836SJohn.Forte@Sun.COM 		fcsm->sm_retry_head = cmd->cmd_next;
35137836SJohn.Forte@Sun.COM 		if (fcsm->sm_retry_head == NULL) {
35147836SJohn.Forte@Sun.COM 			fcsm->sm_retry_tail = NULL;
35157836SJohn.Forte@Sun.COM 		}
35167836SJohn.Forte@Sun.COM 		cmd->cmd_next = NULL;
35177836SJohn.Forte@Sun.COM 	}
35187836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
35197836SJohn.Forte@Sun.COM 
35207836SJohn.Forte@Sun.COM 	return (cmd);
35217836SJohn.Forte@Sun.COM }
35227836SJohn.Forte@Sun.COM 
35237836SJohn.Forte@Sun.COM static void
fcsm_retry_timeout(void * handle)35247836SJohn.Forte@Sun.COM fcsm_retry_timeout(void *handle)
35257836SJohn.Forte@Sun.COM {
35267836SJohn.Forte@Sun.COM 	fcsm_t		*fcsm;
35277836SJohn.Forte@Sun.COM 	fcsm_cmd_t	*curr_tail;
35287836SJohn.Forte@Sun.COM 	fcsm_cmd_t	*cmd;
35297836SJohn.Forte@Sun.COM 	int		done = 0;
35307836SJohn.Forte@Sun.COM 	int		linkdown;
35317836SJohn.Forte@Sun.COM 
35327836SJohn.Forte@Sun.COM 	fcsm = (fcsm_t *)handle;
35337836SJohn.Forte@Sun.COM 
35347836SJohn.Forte@Sun.COM 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "retry_timeout"));
35357836SJohn.Forte@Sun.COM 
35367836SJohn.Forte@Sun.COM 	/*
35377836SJohn.Forte@Sun.COM 	 * If retry cmd queue is suspended, then go away.
35387836SJohn.Forte@Sun.COM 	 * This retry thread will be restarted, when cmd queue resumes.
35397836SJohn.Forte@Sun.COM 	 */
35407836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
35417836SJohn.Forte@Sun.COM 	if (fcsm->sm_flags & FCSM_CMD_RETRY_Q_SUSPENDED) {
35427836SJohn.Forte@Sun.COM 		/*
35437836SJohn.Forte@Sun.COM 		 * Clear the retry_tid, to indicate that this routine is not
35447836SJohn.Forte@Sun.COM 		 * currently being rescheduled.
35457836SJohn.Forte@Sun.COM 		 */
35467836SJohn.Forte@Sun.COM 		fcsm->sm_retry_tid = (timeout_id_t)NULL;
35477836SJohn.Forte@Sun.COM 		mutex_exit(&fcsm->sm_mutex);
35487836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
35497836SJohn.Forte@Sun.COM 		    "retry_timeout: end. No processing. "
35507836SJohn.Forte@Sun.COM 		    "Queue is currently suspended for this instance"));
35517836SJohn.Forte@Sun.COM 		return;
35527836SJohn.Forte@Sun.COM 	}
35537836SJohn.Forte@Sun.COM 
35547836SJohn.Forte@Sun.COM 	linkdown = (fcsm->sm_flags & FCSM_LINK_DOWN) ? 1 : 0;
35557836SJohn.Forte@Sun.COM 
35567836SJohn.Forte@Sun.COM 	/*
35577836SJohn.Forte@Sun.COM 	 * Save the curr_tail, so that we only process the commands
35587836SJohn.Forte@Sun.COM 	 * which are in the queue at this time.
35597836SJohn.Forte@Sun.COM 	 */
35607836SJohn.Forte@Sun.COM 	curr_tail = fcsm->sm_retry_tail;
35617836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
35627836SJohn.Forte@Sun.COM 
35637836SJohn.Forte@Sun.COM 	/*
35647836SJohn.Forte@Sun.COM 	 * Check for done flag before dequeing the command.
35657836SJohn.Forte@Sun.COM 	 * Dequeing before checking the done flag will cause a command
35667836SJohn.Forte@Sun.COM 	 * to be lost.
35677836SJohn.Forte@Sun.COM 	 */
35687836SJohn.Forte@Sun.COM 	while ((!done) && ((cmd = fcsm_deque_cmd(fcsm)) != NULL)) {
35697836SJohn.Forte@Sun.COM 
35707836SJohn.Forte@Sun.COM 		if (cmd == curr_tail) {
35717836SJohn.Forte@Sun.COM 			done = 1;
35727836SJohn.Forte@Sun.COM 		}
35737836SJohn.Forte@Sun.COM 
35747836SJohn.Forte@Sun.COM 		cmd->cmd_retry_interval -= fcsm_retry_ticker;
35757836SJohn.Forte@Sun.COM 
35767836SJohn.Forte@Sun.COM 		if (linkdown) {
35777836SJohn.Forte@Sun.COM 			fc_packet_t *pkt;
35787836SJohn.Forte@Sun.COM 
35797836SJohn.Forte@Sun.COM 			/*
35807836SJohn.Forte@Sun.COM 			 * No need to retry the command. The link has
3581*10264SZhong.Wang@Sun.COM 			 * suffered an offline	timeout.
35827836SJohn.Forte@Sun.COM 			 */
35837836SJohn.Forte@Sun.COM 			pkt = cmd->cmd_fp_pkt;
35847836SJohn.Forte@Sun.COM 			pkt->pkt_state = FC_PKT_PORT_OFFLINE;
35857836SJohn.Forte@Sun.COM 			pkt->pkt_reason = FC_REASON_OFFLINE;
35867836SJohn.Forte@Sun.COM 			pkt->pkt_comp(pkt);
35877836SJohn.Forte@Sun.COM 			continue;
35887836SJohn.Forte@Sun.COM 		}
35897836SJohn.Forte@Sun.COM 
35907836SJohn.Forte@Sun.COM 		if (cmd->cmd_retry_interval <= 0) {
35917836SJohn.Forte@Sun.COM 			/* Retry the command */
35927836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
35937836SJohn.Forte@Sun.COM 			    "retry_timeout: issue cmd 0x%p", (void *)cmd));
35947836SJohn.Forte@Sun.COM 			if (fcsm_issue_cmd(cmd) != FC_SUCCESS) {
35957836SJohn.Forte@Sun.COM 				cmd->cmd_fp_pkt->pkt_comp(cmd->cmd_fp_pkt);
35967836SJohn.Forte@Sun.COM 			}
35977836SJohn.Forte@Sun.COM 		} else {
35987836SJohn.Forte@Sun.COM 			/*
35997836SJohn.Forte@Sun.COM 			 * Put the command back on the queue. Retry time
36007836SJohn.Forte@Sun.COM 			 * has not yet reached.
36017836SJohn.Forte@Sun.COM 			 */
36027836SJohn.Forte@Sun.COM 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
36037836SJohn.Forte@Sun.COM 			    "retry_timeout: queue cmd 0x%p", (void *)cmd));
36047836SJohn.Forte@Sun.COM 			fcsm_enque_cmd(fcsm, cmd);
36057836SJohn.Forte@Sun.COM 		}
36067836SJohn.Forte@Sun.COM 	}
36077836SJohn.Forte@Sun.COM 
36087836SJohn.Forte@Sun.COM 	mutex_enter(&fcsm->sm_mutex);
36097836SJohn.Forte@Sun.COM 	if (fcsm->sm_retry_head) {
36107836SJohn.Forte@Sun.COM 		/* Activate timer */
36117836SJohn.Forte@Sun.COM 		fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
36127836SJohn.Forte@Sun.COM 		    (caddr_t)fcsm, fcsm_retry_ticks);
36137836SJohn.Forte@Sun.COM 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
36147836SJohn.Forte@Sun.COM 		    "retry_timeout: retry thread rescheduled"));
36157836SJohn.Forte@Sun.COM 	} else {
36167836SJohn.Forte@Sun.COM 		/*
36177836SJohn.Forte@Sun.COM 		 * Reset the tid variable. The first thread which queues the
36187836SJohn.Forte@Sun.COM 		 * command, will restart the timer.
36197836SJohn.Forte@Sun.COM 		 */
36207836SJohn.Forte@Sun.COM 		fcsm->sm_retry_tid = (timeout_id_t)NULL;
36217836SJohn.Forte@Sun.COM 	}
36227836SJohn.Forte@Sun.COM 	mutex_exit(&fcsm->sm_mutex);
36237836SJohn.Forte@Sun.COM }
3624