1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
2240b706cfSMilan Jurik  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce44SJohn Forte  * Use is subject to license terms.
24fcf3ce44SJohn Forte  */
25fcf3ce44SJohn Forte 
26fcf3ce44SJohn Forte /*
27fcf3ce44SJohn Forte  * fcsm - ULP Module for Fibre Channel SAN Management
28fcf3ce44SJohn Forte  */
29fcf3ce44SJohn Forte 
30fcf3ce44SJohn Forte #include <sys/types.h>
31fcf3ce44SJohn Forte #include <sys/file.h>
32fcf3ce44SJohn Forte #include <sys/kmem.h>
33fcf3ce44SJohn Forte #include <sys/scsi/scsi.h>
34fcf3ce44SJohn Forte #include <sys/var.h>
35fcf3ce44SJohn Forte #include <sys/byteorder.h>
36fcf3ce44SJohn Forte #include <sys/fibre-channel/fc.h>
37fcf3ce44SJohn Forte #include <sys/fibre-channel/impl/fc_ulpif.h>
38fcf3ce44SJohn Forte #include <sys/fibre-channel/ulp/fcsm.h>
39fcf3ce44SJohn Forte 
40fcf3ce44SJohn Forte /* Definitions */
417ff83669SZhong Wang #define	FCSM_VERSION		"20090729-1.28"
42fcf3ce44SJohn Forte #define	FCSM_NAME_VERSION	"SunFC FCSM v" FCSM_VERSION
43fcf3ce44SJohn Forte 
44fcf3ce44SJohn Forte /* Global Variables */
45fcf3ce44SJohn Forte static char		fcsm_name[] = "FCSM";
46fcf3ce44SJohn Forte static void		*fcsm_state = NULL;
47fcf3ce44SJohn Forte static kmutex_t		fcsm_global_mutex;
48fcf3ce44SJohn Forte static uint32_t		fcsm_flag = FCSM_IDLE;
49fcf3ce44SJohn Forte static dev_info_t	*fcsm_dip = NULL;
50fcf3ce44SJohn Forte static fcsm_t		*fcsm_port_head = NULL;
51fcf3ce44SJohn Forte static kmem_cache_t	*fcsm_job_cache = NULL;
52fcf3ce44SJohn Forte static int		fcsm_num_attaching = 0;
53fcf3ce44SJohn Forte static int		fcsm_num_detaching = 0;
54fcf3ce44SJohn Forte static int		fcsm_detached = 0;
55fcf3ce44SJohn Forte 
56fcf3ce44SJohn Forte static int		fcsm_max_cmd_retries = FCSM_MAX_CMD_RETRIES;
57fcf3ce44SJohn Forte static int		fcsm_retry_interval = FCSM_RETRY_INTERVAL;
58fcf3ce44SJohn Forte static int		fcsm_retry_ticker = FCSM_RETRY_TICKER;
59fcf3ce44SJohn Forte static int		fcsm_offline_ticker = FCSM_OFFLINE_TICKER;
60fcf3ce44SJohn Forte static int		fcsm_max_job_retries = FCSM_MAX_JOB_RETRIES;
61fcf3ce44SJohn Forte static clock_t		fcsm_retry_ticks;
62fcf3ce44SJohn Forte static clock_t		fcsm_offline_ticks;
63fcf3ce44SJohn Forte 
64fcf3ce44SJohn Forte 
65fcf3ce44SJohn Forte 
66fcf3ce44SJohn Forte #ifdef DEBUG
6798ea43c5SYuri Pankov uint32_t		fcsm_debug = 0;
68fcf3ce44SJohn Forte #endif
69fcf3ce44SJohn Forte 
70fcf3ce44SJohn Forte 
71fcf3ce44SJohn Forte /* Character/Block entry points */
72fcf3ce44SJohn Forte struct cb_ops	fcsm_cb_ops = {
73fcf3ce44SJohn Forte 	fcsm_open,	/* open */
74fcf3ce44SJohn Forte 	fcsm_close,	/* close */
75fcf3ce44SJohn Forte 	nodev,		/* strategy */
76fcf3ce44SJohn Forte 	nodev,		/* print */
77fcf3ce44SJohn Forte 	nodev,		/* dump */
78fcf3ce44SJohn Forte 	nodev,		/* read */
79fcf3ce44SJohn Forte 	nodev,		/* write */
80fcf3ce44SJohn Forte 	fcsm_ioctl,	/* ioctl */
81fcf3ce44SJohn Forte 	nodev,		/* devmap */
82fcf3ce44SJohn Forte 	nodev,		/* mmap */
83fcf3ce44SJohn Forte 	nodev,		/* segmap */
84fcf3ce44SJohn Forte 	nochpoll,	/* poll */
85fcf3ce44SJohn Forte 	ddi_prop_op,
86fcf3ce44SJohn Forte 	NULL,		/* streams info */
87fcf3ce44SJohn Forte 	D_NEW | D_MP,
88fcf3ce44SJohn Forte 	CB_REV,
89fcf3ce44SJohn Forte 	nodev,		/* aread */
90fcf3ce44SJohn Forte 	nodev		/* awrite */
91fcf3ce44SJohn Forte };
92fcf3ce44SJohn Forte 
93fcf3ce44SJohn Forte struct dev_ops fcsm_ops = {
94fcf3ce44SJohn Forte 	DEVO_REV,
95fcf3ce44SJohn Forte 	0,		/* refcnt */
96fcf3ce44SJohn Forte 	fcsm_getinfo,	/* get info */
97fcf3ce44SJohn Forte 	nulldev,	/* identify (obsolete) */
98fcf3ce44SJohn Forte 	nulldev,	/* probe (not required for self-identifying devices) */
99fcf3ce44SJohn Forte 	fcsm_attach,	/* attach */
100fcf3ce44SJohn Forte 	fcsm_detach,	/* detach */
101fcf3ce44SJohn Forte 	nodev,		/* reset */
102fcf3ce44SJohn Forte 	&fcsm_cb_ops,	/* char/block entry points structure for leaf drivers */
103fcf3ce44SJohn Forte 	NULL,		/* bus operations for nexus driver */
104fcf3ce44SJohn Forte 	NULL		/* power management */
105fcf3ce44SJohn Forte };
106fcf3ce44SJohn Forte 
107fcf3ce44SJohn Forte 
108fcf3ce44SJohn Forte struct modldrv modldrv = {
109fcf3ce44SJohn Forte 	&mod_driverops,
110fcf3ce44SJohn Forte 	FCSM_NAME_VERSION,
111fcf3ce44SJohn Forte 	&fcsm_ops
112fcf3ce44SJohn Forte };
113fcf3ce44SJohn Forte 
114fcf3ce44SJohn Forte struct modlinkage modlinkage = {
115fcf3ce44SJohn Forte 	MODREV_1,
116fcf3ce44SJohn Forte 	&modldrv,
117fcf3ce44SJohn Forte 	NULL
118fcf3ce44SJohn Forte };
119fcf3ce44SJohn Forte 
120fcf3ce44SJohn Forte static fc_ulp_modinfo_t fcsm_modinfo = {
121fcf3ce44SJohn Forte 	&fcsm_modinfo,		/* ulp_handle */
122fcf3ce44SJohn Forte 	FCTL_ULP_MODREV_4,	/* ulp_rev */
123fcf3ce44SJohn Forte 	FC_TYPE_FC_SERVICES,	/* ulp_type */
124fcf3ce44SJohn Forte 	fcsm_name,		/* ulp_name */
125fcf3ce44SJohn Forte 	0,			/* ulp_statec_mask: get all statec callbacks */
126fcf3ce44SJohn Forte 	fcsm_port_attach,	/* ulp_port_attach */
127fcf3ce44SJohn Forte 	fcsm_port_detach,	/* ulp_port_detach */
128fcf3ce44SJohn Forte 	fcsm_port_ioctl,	/* ulp_port_ioctl */
129fcf3ce44SJohn Forte 	fcsm_els_cb,		/* ulp_els_callback */
130fcf3ce44SJohn Forte 	fcsm_data_cb,		/* ulp_data_callback */
131fcf3ce44SJohn Forte 	fcsm_statec_cb		/* ulp_statec_callback */
132fcf3ce44SJohn Forte };
133fcf3ce44SJohn Forte 
134fcf3ce44SJohn Forte struct fcsm_xlat_pkt_state {
135fcf3ce44SJohn Forte 	uchar_t	xlat_state;
136fcf3ce44SJohn Forte 	int	xlat_rval;
137fcf3ce44SJohn Forte } fcsm_xlat_pkt_state [] = {
138fcf3ce44SJohn Forte 	{ FC_PKT_SUCCESS,		FC_SUCCESS },
139fcf3ce44SJohn Forte 	{ FC_PKT_REMOTE_STOP,		FC_FAILURE },
140fcf3ce44SJohn Forte 	{ FC_PKT_LOCAL_RJT,		FC_TRANSPORT_ERROR },
141fcf3ce44SJohn Forte 	{ FC_PKT_NPORT_RJT,		FC_PREJECT },
142fcf3ce44SJohn Forte 	{ FC_PKT_FABRIC_RJT,		FC_FREJECT },
143fcf3ce44SJohn Forte 	{ FC_PKT_LOCAL_BSY,		FC_TRAN_BUSY },
144fcf3ce44SJohn Forte 	{ FC_PKT_TRAN_BSY,		FC_TRAN_BUSY },
145fcf3ce44SJohn Forte 	{ FC_PKT_NPORT_BSY,		FC_PBUSY },
146fcf3ce44SJohn Forte 	{ FC_PKT_FABRIC_BSY,		FC_FBUSY },
147fcf3ce44SJohn Forte 	{ FC_PKT_LS_RJT,		FC_PREJECT },
148fcf3ce44SJohn Forte 	{ FC_PKT_BA_RJT,		FC_PREJECT },
149fcf3ce44SJohn Forte 	{ FC_PKT_TIMEOUT,		FC_FAILURE },
150fcf3ce44SJohn Forte 	{ FC_PKT_FS_RJT,		FC_FAILURE },
151fcf3ce44SJohn Forte 	{ FC_PKT_TRAN_ERROR,		FC_TRANSPORT_ERROR },
152fcf3ce44SJohn Forte 	{ FC_PKT_FAILURE,		FC_FAILURE },
153fcf3ce44SJohn Forte 	{ FC_PKT_PORT_OFFLINE,		FC_OFFLINE },
154fcf3ce44SJohn Forte 	{ FC_PKT_ELS_IN_PROGRESS,	FC_FAILURE }
155fcf3ce44SJohn Forte };
156fcf3ce44SJohn Forte 
157fcf3ce44SJohn Forte struct fcsm_xlat_port_state {
158fcf3ce44SJohn Forte 	uint32_t	xlat_pstate;
159fcf3ce44SJohn Forte 	caddr_t		xlat_state_str;
160fcf3ce44SJohn Forte } fcsm_xlat_port_state [] = {
161fcf3ce44SJohn Forte 	{ FC_STATE_OFFLINE,		"OFFLINE" },
162fcf3ce44SJohn Forte 	{ FC_STATE_ONLINE,		"ONLINE" },
163fcf3ce44SJohn Forte 	{ FC_STATE_LOOP,		"LOOP" },
164fcf3ce44SJohn Forte 	{ FC_STATE_NAMESERVICE,		"NAMESERVICE" },
165fcf3ce44SJohn Forte 	{ FC_STATE_RESET,		"RESET" },
166fcf3ce44SJohn Forte 	{ FC_STATE_RESET_REQUESTED,	"RESET_REQUESTED" },
167fcf3ce44SJohn Forte 	{ FC_STATE_LIP,			"LIP" },
168fcf3ce44SJohn Forte 	{ FC_STATE_LIP_LBIT_SET,	"LIP_LBIT_SET" },
169fcf3ce44SJohn Forte 	{ FC_STATE_DEVICE_CHANGE,	"DEVICE_CHANGE" },
170fcf3ce44SJohn Forte 	{ FC_STATE_TARGET_PORT_RESET,	"TARGET_PORT_RESET" }
171fcf3ce44SJohn Forte };
172fcf3ce44SJohn Forte 
173fcf3ce44SJohn Forte struct fcsm_xlat_topology {
174fcf3ce44SJohn Forte 	uint32_t	xlat_top;
175fcf3ce44SJohn Forte 	caddr_t		xlat_top_str;
176fcf3ce44SJohn Forte } fcsm_xlat_topology [] = {
177fcf3ce44SJohn Forte 	{ FC_TOP_UNKNOWN,	"UNKNOWN" },
178fcf3ce44SJohn Forte 	{ FC_TOP_PRIVATE_LOOP,	"Private Loop" },
179fcf3ce44SJohn Forte 	{ FC_TOP_PUBLIC_LOOP,	"Public Loop" },
180fcf3ce44SJohn Forte 	{ FC_TOP_FABRIC,	"Fabric" },
181fcf3ce44SJohn Forte 	{ FC_TOP_PT_PT,		"Point-to-Point" },
182fcf3ce44SJohn Forte 	{ FC_TOP_NO_NS,		"NO_NS" }
183fcf3ce44SJohn Forte };
184fcf3ce44SJohn Forte 
185fcf3ce44SJohn Forte struct fcsm_xlat_dev_type {
186fcf3ce44SJohn Forte 	uint32_t	xlat_type;
187fcf3ce44SJohn Forte 	caddr_t		xlat_str;
188fcf3ce44SJohn Forte } fcsm_xlat_dev_type [] = {
189fcf3ce44SJohn Forte 	{ PORT_DEVICE_NOCHANGE,		"No Change" },
190fcf3ce44SJohn Forte 	{ PORT_DEVICE_NEW,		"New" },
191fcf3ce44SJohn Forte 	{ PORT_DEVICE_OLD,		"Old" },
192fcf3ce44SJohn Forte 	{ PORT_DEVICE_CHANGED,		"Changed" },
193fcf3ce44SJohn Forte 	{ PORT_DEVICE_DELETE,		"Delete" },
194fcf3ce44SJohn Forte 	{ PORT_DEVICE_USER_LOGIN,	"User Login" },
195fcf3ce44SJohn Forte 	{ PORT_DEVICE_USER_LOGOUT,	"User Logout" },
196fcf3ce44SJohn Forte 	{ PORT_DEVICE_USER_CREATE,	"User Create" },
197fcf3ce44SJohn Forte 	{ PORT_DEVICE_USER_DELETE,	"User Delete" }
198fcf3ce44SJohn Forte };
199fcf3ce44SJohn Forte 
200fcf3ce44SJohn Forte int
_init(void)201fcf3ce44SJohn Forte _init(void)
202fcf3ce44SJohn Forte {
203fcf3ce44SJohn Forte 	int		rval;
204fcf3ce44SJohn Forte 
205fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "_init"));
206fcf3ce44SJohn Forte 
207fcf3ce44SJohn Forte 	fcsm_retry_ticks = drv_usectohz(fcsm_retry_ticker * 1000 * 1000);
208fcf3ce44SJohn Forte 	fcsm_offline_ticks = drv_usectohz(fcsm_offline_ticker * 1000 * 1000);
209fcf3ce44SJohn Forte 
210fcf3ce44SJohn Forte 	if (rval = ddi_soft_state_init(&fcsm_state, sizeof (fcsm_t),
211fcf3ce44SJohn Forte 	    FCSM_INIT_INSTANCES)) {
212fcf3ce44SJohn Forte 		fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
213fcf3ce44SJohn Forte 		    "_init: ddi_soft_state_init failed");
214fcf3ce44SJohn Forte 		return (ENOMEM);
215fcf3ce44SJohn Forte 	}
216fcf3ce44SJohn Forte 
217fcf3ce44SJohn Forte 	mutex_init(&fcsm_global_mutex, NULL, MUTEX_DRIVER, NULL);
218fcf3ce44SJohn Forte 
219fcf3ce44SJohn Forte 	fcsm_job_cache = kmem_cache_create("fcsm_job_cache",
220fcf3ce44SJohn Forte 	    sizeof (fcsm_job_t), 8, fcsm_job_cache_constructor,
221fcf3ce44SJohn Forte 	    fcsm_job_cache_destructor, NULL, NULL, NULL, 0);
222fcf3ce44SJohn Forte 
223fcf3ce44SJohn Forte 	if (fcsm_job_cache == NULL) {
224fcf3ce44SJohn Forte 		mutex_destroy(&fcsm_global_mutex);
225fcf3ce44SJohn Forte 		ddi_soft_state_fini(&fcsm_state);
226fcf3ce44SJohn Forte 		return (ENOMEM);
227fcf3ce44SJohn Forte 	}
228fcf3ce44SJohn Forte 
229fcf3ce44SJohn Forte 	/*
230fcf3ce44SJohn Forte 	 * Now call fc_ulp_add to add this ULP in the transport layer
231fcf3ce44SJohn Forte 	 * database. This will cause 'ulp_port_attach' callback function
232fcf3ce44SJohn Forte 	 * to be called.
233fcf3ce44SJohn Forte 	 */
234fcf3ce44SJohn Forte 	rval = fc_ulp_add(&fcsm_modinfo);
235fcf3ce44SJohn Forte 	if (rval != 0) {
236fcf3ce44SJohn Forte 		switch (rval) {
237fcf3ce44SJohn Forte 		case FC_ULP_SAMEMODULE:
238fcf3ce44SJohn Forte 			fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
239fcf3ce44SJohn Forte 			    "_init: FC SAN Management module is already "
240fcf3ce44SJohn Forte 			    "registered with transport layer");
241fcf3ce44SJohn Forte 			rval = EEXIST;
242fcf3ce44SJohn Forte 			break;
243fcf3ce44SJohn Forte 
244fcf3ce44SJohn Forte 		case FC_ULP_SAMETYPE:
245fcf3ce44SJohn Forte 			fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
246fcf3ce44SJohn Forte 			    "_init: Another module with same type 0x%x is "
247fcf3ce44SJohn Forte 			    "already registered with transport layer",
248fcf3ce44SJohn Forte 			    fcsm_modinfo.ulp_type);
249fcf3ce44SJohn Forte 			rval = EEXIST;
250fcf3ce44SJohn Forte 			break;
251fcf3ce44SJohn Forte 
252fcf3ce44SJohn Forte 		case FC_BADULP:
253fcf3ce44SJohn Forte 			fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
254fcf3ce44SJohn Forte 			    "_init: Please upgrade this module. Current "
255fcf3ce44SJohn Forte 			    "version 0x%x is not the most recent version",
256fcf3ce44SJohn Forte 			    fcsm_modinfo.ulp_rev);
257fcf3ce44SJohn Forte 			rval = EIO;
258fcf3ce44SJohn Forte 			break;
259fcf3ce44SJohn Forte 		default:
260fcf3ce44SJohn Forte 			fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
261fcf3ce44SJohn Forte 			    "_init: fc_ulp_add failed with status 0x%x", rval);
262fcf3ce44SJohn Forte 			rval = EIO;
263fcf3ce44SJohn Forte 			break;
264fcf3ce44SJohn Forte 		}
265fcf3ce44SJohn Forte 		kmem_cache_destroy(fcsm_job_cache);
266fcf3ce44SJohn Forte 		mutex_destroy(&fcsm_global_mutex);
267fcf3ce44SJohn Forte 		ddi_soft_state_fini(&fcsm_state);
268fcf3ce44SJohn Forte 		return (rval);
269fcf3ce44SJohn Forte 	}
270fcf3ce44SJohn Forte 
271fcf3ce44SJohn Forte 	if ((rval = mod_install(&modlinkage)) != 0) {
272fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL, NULL,
273fcf3ce44SJohn Forte 		    "_init: mod_install failed with status 0x%x", rval));
274fcf3ce44SJohn Forte 		(void) fc_ulp_remove(&fcsm_modinfo);
275fcf3ce44SJohn Forte 		kmem_cache_destroy(fcsm_job_cache);
276fcf3ce44SJohn Forte 		mutex_destroy(&fcsm_global_mutex);
277fcf3ce44SJohn Forte 		ddi_soft_state_fini(&fcsm_state);
278fcf3ce44SJohn Forte 		return (rval);
279fcf3ce44SJohn Forte 	}
280fcf3ce44SJohn Forte 
281fcf3ce44SJohn Forte 	return (rval);
282fcf3ce44SJohn Forte }
283fcf3ce44SJohn Forte 
284fcf3ce44SJohn Forte int
_fini(void)285fcf3ce44SJohn Forte _fini(void)
286fcf3ce44SJohn Forte {
287fcf3ce44SJohn Forte 	int	rval;
2887ff83669SZhong Wang #ifdef	DEBUG
289fcf3ce44SJohn Forte 	int	status;
290fcf3ce44SJohn Forte #endif /* DEBUG */
291fcf3ce44SJohn Forte 
292fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "_fini"));
293fcf3ce44SJohn Forte 
294fcf3ce44SJohn Forte 	/*
295fcf3ce44SJohn Forte 	 * don't start cleaning up until we know that the module remove
296fcf3ce44SJohn Forte 	 * has worked  -- if this works, then we know that each instance
297fcf3ce44SJohn Forte 	 * has successfully been DDI_DETACHed
298fcf3ce44SJohn Forte 	 */
299fcf3ce44SJohn Forte 	if ((rval = mod_remove(&modlinkage)) != 0) {
300fcf3ce44SJohn Forte 		return (rval);
301fcf3ce44SJohn Forte 	}
302fcf3ce44SJohn Forte 
303fcf3ce44SJohn Forte #ifdef DEBUG
304fcf3ce44SJohn Forte 	status = fc_ulp_remove(&fcsm_modinfo);
305fcf3ce44SJohn Forte 	if (status != 0) {
306fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL, NULL,
307fcf3ce44SJohn Forte 		    "_fini: fc_ulp_remove failed with status 0x%x", status));
308fcf3ce44SJohn Forte 	}
309fcf3ce44SJohn Forte #else
310fcf3ce44SJohn Forte 	(void) fc_ulp_remove(&fcsm_modinfo);
311fcf3ce44SJohn Forte #endif /* DEBUG */
312fcf3ce44SJohn Forte 
313fcf3ce44SJohn Forte 	fcsm_detached = 0;
314fcf3ce44SJohn Forte 
315fcf3ce44SJohn Forte 	/*
316fcf3ce44SJohn Forte 	 * It is possible to modunload fcsm manually, which will cause
317fcf3ce44SJohn Forte 	 * a bypass of all the port_detach functionality.  We may need
318fcf3ce44SJohn Forte 	 * to force that code path to be executed to properly clean up
319fcf3ce44SJohn Forte 	 * in that case.
320fcf3ce44SJohn Forte 	 */
321fcf3ce44SJohn Forte 	fcsm_force_port_detach_all();
322fcf3ce44SJohn Forte 
323fcf3ce44SJohn Forte 	kmem_cache_destroy(fcsm_job_cache);
324fcf3ce44SJohn Forte 	mutex_destroy(&fcsm_global_mutex);
325fcf3ce44SJohn Forte 	ddi_soft_state_fini(&fcsm_state);
326fcf3ce44SJohn Forte 
327fcf3ce44SJohn Forte 	return (rval);
328fcf3ce44SJohn Forte }
329fcf3ce44SJohn Forte 
330fcf3ce44SJohn Forte 
331fcf3ce44SJohn Forte int
_info(struct modinfo * modinfop)332fcf3ce44SJohn Forte _info(struct modinfo *modinfop)
333fcf3ce44SJohn Forte {
334fcf3ce44SJohn Forte 	return (mod_info(&modlinkage, modinfop));
335fcf3ce44SJohn Forte }
336fcf3ce44SJohn Forte 
337fcf3ce44SJohn Forte /* ARGSUSED */
338fcf3ce44SJohn Forte static int
fcsm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)339fcf3ce44SJohn Forte fcsm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
340fcf3ce44SJohn Forte {
341fcf3ce44SJohn Forte 	int rval = DDI_FAILURE;
342fcf3ce44SJohn Forte 
343fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
344fcf3ce44SJohn Forte 	    "attach: cmd 0x%x", cmd));
345fcf3ce44SJohn Forte 
346fcf3ce44SJohn Forte 	switch (cmd) {
347fcf3ce44SJohn Forte 	case DDI_ATTACH:
348fcf3ce44SJohn Forte 		mutex_enter(&fcsm_global_mutex);
349fcf3ce44SJohn Forte 		if (fcsm_dip != NULL) {
350fcf3ce44SJohn Forte 			mutex_exit(&fcsm_global_mutex);
351fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
352fcf3ce44SJohn Forte 			    "attach: duplicate attach of fcsm!!"));
353fcf3ce44SJohn Forte 			break;
354fcf3ce44SJohn Forte 		}
355fcf3ce44SJohn Forte 
356fcf3ce44SJohn Forte 		fcsm_dip = dip;
357fcf3ce44SJohn Forte 
358fcf3ce44SJohn Forte 		/*
359fcf3ce44SJohn Forte 		 * The detach routine cleans up all the port instances
360fcf3ce44SJohn Forte 		 * i.e. it detaches all ports.
361fcf3ce44SJohn Forte 		 * If _fini never got called after detach, then
362fcf3ce44SJohn Forte 		 * perform an fc_ulp_remove() followed by fc_ulp_add()
363fcf3ce44SJohn Forte 		 * to ensure that port_attach callbacks are called
364fcf3ce44SJohn Forte 		 * again.
365fcf3ce44SJohn Forte 		 */
366fcf3ce44SJohn Forte 		if (fcsm_detached) {
367fcf3ce44SJohn Forte 			int status;
368fcf3ce44SJohn Forte 
369fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
370fcf3ce44SJohn Forte 			    "attach: rebinding to transport driver"));
371fcf3ce44SJohn Forte 
372fcf3ce44SJohn Forte 			mutex_exit(&fcsm_global_mutex);
373fcf3ce44SJohn Forte 
374fcf3ce44SJohn Forte 			(void) fc_ulp_remove(&fcsm_modinfo);
375fcf3ce44SJohn Forte 
376fcf3ce44SJohn Forte 			/*
377fcf3ce44SJohn Forte 			 * Reset the detached flag, so that ports can attach
378fcf3ce44SJohn Forte 			 */
379fcf3ce44SJohn Forte 			mutex_enter(&fcsm_global_mutex);
380fcf3ce44SJohn Forte 			fcsm_detached = 0;
381fcf3ce44SJohn Forte 			mutex_exit(&fcsm_global_mutex);
382fcf3ce44SJohn Forte 
383fcf3ce44SJohn Forte 			status = fc_ulp_add(&fcsm_modinfo);
384fcf3ce44SJohn Forte 
385fcf3ce44SJohn Forte 			if (status != 0) {
386fcf3ce44SJohn Forte 				/*
387fcf3ce44SJohn Forte 				 * ULP add failed. So set the
388fcf3ce44SJohn Forte 				 * detached flag again
389fcf3ce44SJohn Forte 				 */
390fcf3ce44SJohn Forte 				mutex_enter(&fcsm_global_mutex);
391fcf3ce44SJohn Forte 				fcsm_detached = 1;
392fcf3ce44SJohn Forte 				mutex_exit(&fcsm_global_mutex);
393fcf3ce44SJohn Forte 
394fcf3ce44SJohn Forte 				switch (status) {
395fcf3ce44SJohn Forte 				case FC_ULP_SAMEMODULE:
396fcf3ce44SJohn Forte 					fcsm_display(CE_WARN, SM_LOG, NULL,
397fcf3ce44SJohn Forte 					    NULL, "attach: FC SAN Management "
398fcf3ce44SJohn Forte 					    "module is already "
399fcf3ce44SJohn Forte 					    "registered with transport layer");
400fcf3ce44SJohn Forte 					break;
401fcf3ce44SJohn Forte 
402fcf3ce44SJohn Forte 				case FC_ULP_SAMETYPE:
403fcf3ce44SJohn Forte 					fcsm_display(CE_WARN, SM_LOG, NULL,
404fcf3ce44SJohn Forte 					    NULL, "attach: Another module with "
405fcf3ce44SJohn Forte 					    "same type 0x%x is already "
406fcf3ce44SJohn Forte 					    "registered with transport layer",
407fcf3ce44SJohn Forte 					    fcsm_modinfo.ulp_type);
408fcf3ce44SJohn Forte 					break;
409fcf3ce44SJohn Forte 
410fcf3ce44SJohn Forte 				case FC_BADULP:
411fcf3ce44SJohn Forte 					fcsm_display(CE_WARN, SM_LOG, NULL,
412fcf3ce44SJohn Forte 					    NULL, "attach: Please upgrade this "
413fcf3ce44SJohn Forte 					    "module. Current version 0x%x is "
414fcf3ce44SJohn Forte 					    "not the most recent version",
415fcf3ce44SJohn Forte 					    fcsm_modinfo.ulp_rev);
416fcf3ce44SJohn Forte 					break;
417fcf3ce44SJohn Forte 				default:
418fcf3ce44SJohn Forte 					fcsm_display(CE_WARN, SM_LOG, NULL,
419fcf3ce44SJohn Forte 					    NULL, "attach: fc_ulp_add failed "
420fcf3ce44SJohn Forte 					    "with status 0x%x", status);
421fcf3ce44SJohn Forte 					break;
422fcf3ce44SJohn Forte 				}
423fcf3ce44SJohn Forte 
424fcf3ce44SJohn Forte 				/* Return failure */
425fcf3ce44SJohn Forte 				break;
426fcf3ce44SJohn Forte 			}
427fcf3ce44SJohn Forte 
428fcf3ce44SJohn Forte 			mutex_enter(&fcsm_global_mutex);
429fcf3ce44SJohn Forte 		}
430fcf3ce44SJohn Forte 
431fcf3ce44SJohn Forte 		/* Create a minor node */
432fcf3ce44SJohn Forte 		if (ddi_create_minor_node(fcsm_dip, "fcsm", S_IFCHR,
433*483e494aSToomas Soome 		    0, DDI_PSEUDO, 0) == DDI_SUCCESS) {
434fcf3ce44SJohn Forte 			/* Announce presence of the device */
435fcf3ce44SJohn Forte 			mutex_exit(&fcsm_global_mutex);
436fcf3ce44SJohn Forte 			ddi_report_dev(dip);
437fcf3ce44SJohn Forte 			rval = DDI_SUCCESS;
438fcf3ce44SJohn Forte 		} else {
439fcf3ce44SJohn Forte 			fcsm_dip = NULL;
440fcf3ce44SJohn Forte 			mutex_exit(&fcsm_global_mutex);
441fcf3ce44SJohn Forte 			fcsm_display(CE_WARN, SM_LOG_AND_CONSOLE,
442fcf3ce44SJohn Forte 			    NULL, NULL, "attach: create minor node failed");
443fcf3ce44SJohn Forte 		}
444fcf3ce44SJohn Forte 		break;
445fcf3ce44SJohn Forte 
446fcf3ce44SJohn Forte 	case DDI_RESUME:
447fcf3ce44SJohn Forte 		rval = DDI_SUCCESS;
448fcf3ce44SJohn Forte 		break;
449fcf3ce44SJohn Forte 
450fcf3ce44SJohn Forte 	default:
451fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
452fcf3ce44SJohn Forte 		    "attach: unknown cmd 0x%x dip 0x%p", cmd, dip));
453fcf3ce44SJohn Forte 		break;
454fcf3ce44SJohn Forte 	}
455fcf3ce44SJohn Forte 
456fcf3ce44SJohn Forte 	return (rval);
457fcf3ce44SJohn Forte }
458fcf3ce44SJohn Forte 
459fcf3ce44SJohn Forte /* ARGSUSED */
460fcf3ce44SJohn Forte static int
fcsm_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)461fcf3ce44SJohn Forte fcsm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
462fcf3ce44SJohn Forte {
463fcf3ce44SJohn Forte 	int	instance;
464fcf3ce44SJohn Forte 	int	rval = DDI_SUCCESS;
465fcf3ce44SJohn Forte 
466fcf3ce44SJohn Forte 	instance = getminor((dev_t)arg);
467fcf3ce44SJohn Forte 
468fcf3ce44SJohn Forte 	switch (cmd) {
469fcf3ce44SJohn Forte 	case DDI_INFO_DEVT2INSTANCE:
470fcf3ce44SJohn Forte 		*result = (void *)(long)instance; /* minor number is instance */
471fcf3ce44SJohn Forte 		break;
472fcf3ce44SJohn Forte 
473fcf3ce44SJohn Forte 	case DDI_INFO_DEVT2DEVINFO:
474fcf3ce44SJohn Forte 		mutex_enter(&fcsm_global_mutex);
475fcf3ce44SJohn Forte 		*result = (void *)fcsm_dip;
476fcf3ce44SJohn Forte 		mutex_exit(&fcsm_global_mutex);
477fcf3ce44SJohn Forte 		break;
478fcf3ce44SJohn Forte 
479fcf3ce44SJohn Forte 	default:
480fcf3ce44SJohn Forte 		rval = DDI_FAILURE;
481fcf3ce44SJohn Forte 		break;
482fcf3ce44SJohn Forte 	}
483fcf3ce44SJohn Forte 
484fcf3ce44SJohn Forte 	return (rval);
485fcf3ce44SJohn Forte }
486fcf3ce44SJohn Forte 
487fcf3ce44SJohn Forte 
488fcf3ce44SJohn Forte /* ARGSUSED */
489fcf3ce44SJohn Forte static int
fcsm_port_attach(opaque_t ulph,fc_ulp_port_info_t * pinfo,fc_attach_cmd_t cmd,uint32_t s_id)490fcf3ce44SJohn Forte fcsm_port_attach(opaque_t ulph, fc_ulp_port_info_t *pinfo,
491fcf3ce44SJohn Forte     fc_attach_cmd_t cmd, uint32_t s_id)
492fcf3ce44SJohn Forte {
493fcf3ce44SJohn Forte 	int	instance;
494fcf3ce44SJohn Forte 	int	rval = FC_FAILURE;
495fcf3ce44SJohn Forte 
496fcf3ce44SJohn Forte 	instance = ddi_get_instance(pinfo->port_dip);
497fcf3ce44SJohn Forte 
498fcf3ce44SJohn Forte 	/*
499fcf3ce44SJohn Forte 	 * Set the attaching flag, so that fcsm_detach will fail, if
500fcf3ce44SJohn Forte 	 * port attach is in progress.
501fcf3ce44SJohn Forte 	 */
502fcf3ce44SJohn Forte 	mutex_enter(&fcsm_global_mutex);
503fcf3ce44SJohn Forte 	if (fcsm_detached) {
504fcf3ce44SJohn Forte 		mutex_exit(&fcsm_global_mutex);
505fcf3ce44SJohn Forte 
506fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
507fcf3ce44SJohn Forte 		    "port_attach: end. detach in progress. failing attach "
508fcf3ce44SJohn Forte 		    "instance 0x%x", instance));
509fcf3ce44SJohn Forte 		return (((cmd == FC_CMD_POWER_UP) || (cmd == FC_CMD_RESUME)) ?
510fcf3ce44SJohn Forte 		    FC_FAILURE_SILENT : FC_FAILURE);
511fcf3ce44SJohn Forte 	}
512fcf3ce44SJohn Forte 
513fcf3ce44SJohn Forte 	fcsm_num_attaching++;
514fcf3ce44SJohn Forte 	mutex_exit(&fcsm_global_mutex);
515fcf3ce44SJohn Forte 
516fcf3ce44SJohn Forte 	switch (cmd) {
517fcf3ce44SJohn Forte 	case FC_CMD_ATTACH:
518fcf3ce44SJohn Forte 		if (fcsm_handle_port_attach(pinfo, s_id, instance)
519fcf3ce44SJohn Forte 		    != DDI_SUCCESS) {
520fcf3ce44SJohn Forte 			ASSERT(ddi_get_soft_state(fcsm_state,
521fcf3ce44SJohn Forte 			    instance) == NULL);
522fcf3ce44SJohn Forte 			break;
523fcf3ce44SJohn Forte 		}
524fcf3ce44SJohn Forte 		rval = FC_SUCCESS;
525fcf3ce44SJohn Forte 		break;
526fcf3ce44SJohn Forte 
527fcf3ce44SJohn Forte 	case FC_CMD_RESUME:
528fcf3ce44SJohn Forte 	case FC_CMD_POWER_UP: {
529fcf3ce44SJohn Forte 		fcsm_t	*fcsm;
530fcf3ce44SJohn Forte 		char fcsm_pathname[MAXPATHLEN];
531fcf3ce44SJohn Forte 
532fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
533fcf3ce44SJohn Forte 		    "port_attach: cmd 0x%x instance 0x%x", cmd, instance));
534fcf3ce44SJohn Forte 
535fcf3ce44SJohn Forte 		/* Get the soft state structure */
536fcf3ce44SJohn Forte 		if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) {
537fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
538fcf3ce44SJohn Forte 			    "port_attach: instance 0x%x, cmd 0x%x "
539fcf3ce44SJohn Forte 			    "get softstate failed", instance, cmd));
540fcf3ce44SJohn Forte 			break;
541fcf3ce44SJohn Forte 		}
542fcf3ce44SJohn Forte 
543fcf3ce44SJohn Forte 		ASSERT(fcsm->sm_instance == instance);
544fcf3ce44SJohn Forte 
545fcf3ce44SJohn Forte 		/* If this instance is not attached, then return failure */
546fcf3ce44SJohn Forte 		mutex_enter(&fcsm->sm_mutex);
547fcf3ce44SJohn Forte 		if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) {
548fcf3ce44SJohn Forte 			mutex_exit(&fcsm->sm_mutex);
549fcf3ce44SJohn Forte 			fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
550fcf3ce44SJohn Forte 			    "port_detach: port is not attached");
551fcf3ce44SJohn Forte 			break;
552fcf3ce44SJohn Forte 		}
553fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
554fcf3ce44SJohn Forte 
555fcf3ce44SJohn Forte 		if (fcsm_handle_port_resume(ulph, pinfo, cmd, s_id, fcsm) !=
556fcf3ce44SJohn Forte 		    DDI_SUCCESS) {
557fcf3ce44SJohn Forte 			break;
558fcf3ce44SJohn Forte 		}
559fcf3ce44SJohn Forte 
560fcf3ce44SJohn Forte 		(void) ddi_pathname(fcsm->sm_port_info.port_dip, fcsm_pathname);
561fcf3ce44SJohn Forte 		fcsm_display(CE_NOTE, SM_LOG, fcsm, NULL,
562fcf3ce44SJohn Forte 		    "attached to path %s", fcsm_pathname);
563fcf3ce44SJohn Forte 		rval = FC_SUCCESS;
564fcf3ce44SJohn Forte 		break;
565fcf3ce44SJohn Forte 	}
566fcf3ce44SJohn Forte 
567fcf3ce44SJohn Forte 	default:
568fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
569fcf3ce44SJohn Forte 		    "port_attach: unknown cmd 0x%x for port 0x%x",
570fcf3ce44SJohn Forte 		    cmd, instance));
571fcf3ce44SJohn Forte 		break;
572fcf3ce44SJohn Forte 	}
573fcf3ce44SJohn Forte 
574fcf3ce44SJohn Forte 	mutex_enter(&fcsm_global_mutex);
575fcf3ce44SJohn Forte 	fcsm_num_attaching--;
576fcf3ce44SJohn Forte 	mutex_exit(&fcsm_global_mutex);
577fcf3ce44SJohn Forte 	return (rval);
578fcf3ce44SJohn Forte }
579fcf3ce44SJohn Forte 
580fcf3ce44SJohn Forte 
581fcf3ce44SJohn Forte static int
fcsm_handle_port_attach(fc_ulp_port_info_t * pinfo,uint32_t s_id,int instance)582fcf3ce44SJohn Forte fcsm_handle_port_attach(fc_ulp_port_info_t *pinfo, uint32_t s_id, int instance)
583fcf3ce44SJohn Forte {
584fcf3ce44SJohn Forte 	fcsm_t		*fcsm;
585fcf3ce44SJohn Forte 	kthread_t	*thread;
586fcf3ce44SJohn Forte 	char		name[32];
587fcf3ce44SJohn Forte 	char fcsm_pathname[MAXPATHLEN];
588fcf3ce44SJohn Forte 
589fcf3ce44SJohn Forte 	/* Allocate a soft state structure for the port */
590fcf3ce44SJohn Forte 	if (ddi_soft_state_zalloc(fcsm_state, instance) != DDI_SUCCESS) {
591fcf3ce44SJohn Forte 		fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
592fcf3ce44SJohn Forte 		    "port_attach: instance 0x%x, soft state alloc failed",
593fcf3ce44SJohn Forte 		    instance);
594fcf3ce44SJohn Forte 		return (DDI_FAILURE);
595fcf3ce44SJohn Forte 	}
596fcf3ce44SJohn Forte 
597fcf3ce44SJohn Forte 	if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) {
598fcf3ce44SJohn Forte 		fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
599fcf3ce44SJohn Forte 		    "port_attach: instance 0x%x, get soft state failed",
600fcf3ce44SJohn Forte 		    instance);
601fcf3ce44SJohn Forte 		ddi_soft_state_free(fcsm_state, instance);
602fcf3ce44SJohn Forte 		return (DDI_FAILURE);
603fcf3ce44SJohn Forte 	}
604fcf3ce44SJohn Forte 
605fcf3ce44SJohn Forte 
606fcf3ce44SJohn Forte 	/* Initialize the mutex */
607fcf3ce44SJohn Forte 	mutex_init(&fcsm->sm_mutex, NULL, MUTEX_DRIVER, NULL);
608fcf3ce44SJohn Forte 	cv_init(&fcsm->sm_job_cv, NULL, CV_DRIVER, NULL);
609fcf3ce44SJohn Forte 
610fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
611fcf3ce44SJohn Forte 	fcsm->sm_flags		|= FCSM_ATTACHING;
612fcf3ce44SJohn Forte 	fcsm->sm_sid		= s_id;
613fcf3ce44SJohn Forte 	fcsm->sm_instance	= instance;
614fcf3ce44SJohn Forte 	fcsm->sm_port_state	= pinfo->port_state;
615fcf3ce44SJohn Forte 
616fcf3ce44SJohn Forte 	/*
617fcf3ce44SJohn Forte 	 * Make a copy of the port_information structure, since fctl
618fcf3ce44SJohn Forte 	 * uses a temporary structure.
619fcf3ce44SJohn Forte 	 */
620fcf3ce44SJohn Forte 	fcsm->sm_port_info	= *pinfo;	/* Structure copy !!! */
621fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
622fcf3ce44SJohn Forte 
623fcf3ce44SJohn Forte 
624fcf3ce44SJohn Forte 	(void) sprintf(name, "fcsm%d_cmd_cache", fcsm->sm_instance);
625fcf3ce44SJohn Forte 	fcsm->sm_cmd_cache = kmem_cache_create(name,
626fcf3ce44SJohn Forte 	    sizeof (fcsm_cmd_t) + pinfo->port_fca_pkt_size, 8,
627fcf3ce44SJohn Forte 	    fcsm_cmd_cache_constructor, fcsm_cmd_cache_destructor,
628fcf3ce44SJohn Forte 	    NULL, (void *)fcsm, NULL, 0);
629fcf3ce44SJohn Forte 	if (fcsm->sm_cmd_cache == NULL) {
630fcf3ce44SJohn Forte 		fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
631fcf3ce44SJohn Forte 		    "port_attach: pkt cache create failed");
632fcf3ce44SJohn Forte 		cv_destroy(&fcsm->sm_job_cv);
633fcf3ce44SJohn Forte 		mutex_destroy(&fcsm->sm_mutex);
634fcf3ce44SJohn Forte 		ddi_soft_state_free(fcsm_state, instance);
635fcf3ce44SJohn Forte 		return (DDI_FAILURE);
636fcf3ce44SJohn Forte 	}
637fcf3ce44SJohn Forte 
638fcf3ce44SJohn Forte 	thread = thread_create((caddr_t)NULL, 0, fcsm_job_thread,
639fcf3ce44SJohn Forte 	    (caddr_t)fcsm, 0, &p0, TS_RUN, v.v_maxsyspri-2);
640fcf3ce44SJohn Forte 	if (thread == NULL) {
641fcf3ce44SJohn Forte 		fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
642fcf3ce44SJohn Forte 		    "port_attach: job thread create failed");
643fcf3ce44SJohn Forte 		kmem_cache_destroy(fcsm->sm_cmd_cache);
644fcf3ce44SJohn Forte 		cv_destroy(&fcsm->sm_job_cv);
645fcf3ce44SJohn Forte 		mutex_destroy(&fcsm->sm_mutex);
646fcf3ce44SJohn Forte 		ddi_soft_state_free(fcsm_state, instance);
647fcf3ce44SJohn Forte 		return (DDI_FAILURE);
648fcf3ce44SJohn Forte 	}
649fcf3ce44SJohn Forte 
650fcf3ce44SJohn Forte 	fcsm->sm_thread = thread;
651fcf3ce44SJohn Forte 
652fcf3ce44SJohn Forte 	/* Add this structure to fcsm global linked list */
653fcf3ce44SJohn Forte 	mutex_enter(&fcsm_global_mutex);
654fcf3ce44SJohn Forte 	if (fcsm_port_head == NULL) {
655fcf3ce44SJohn Forte 		fcsm_port_head = fcsm;
656fcf3ce44SJohn Forte 	} else {
657fcf3ce44SJohn Forte 		fcsm->sm_next = fcsm_port_head;
658fcf3ce44SJohn Forte 		fcsm_port_head = fcsm;
659fcf3ce44SJohn Forte 	}
660fcf3ce44SJohn Forte 	mutex_exit(&fcsm_global_mutex);
661fcf3ce44SJohn Forte 
662fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
663fcf3ce44SJohn Forte 	fcsm->sm_flags &= ~FCSM_ATTACHING;
664fcf3ce44SJohn Forte 	fcsm->sm_flags |= FCSM_ATTACHED;
665fcf3ce44SJohn Forte 	fcsm->sm_port_top = pinfo->port_flags;
666fcf3ce44SJohn Forte 	fcsm->sm_port_state = pinfo->port_state;
6677ff83669SZhong Wang 	if (pinfo->port_acc_attr == NULL) {
6687ff83669SZhong Wang 		/*
6697ff83669SZhong Wang 		 * The corresponding FCA doesn't support DMA at all
6707ff83669SZhong Wang 		 */
6717ff83669SZhong Wang 		fcsm->sm_flags |= FCSM_USING_NODMA_FCA;
6727ff83669SZhong Wang 	}
673fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
674fcf3ce44SJohn Forte 
675fcf3ce44SJohn Forte 	(void) ddi_pathname(fcsm->sm_port_info.port_dip, fcsm_pathname);
676fcf3ce44SJohn Forte 	fcsm_display(CE_NOTE, SM_LOG, fcsm, NULL,
677fcf3ce44SJohn Forte 	    "attached to path %s", fcsm_pathname);
678fcf3ce44SJohn Forte 
679fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
680fcf3ce44SJohn Forte 	    "port_attach: state <%s>(0x%x) topology <%s>(0x%x)",
681fcf3ce44SJohn Forte 	    fcsm_port_state_to_str(FC_PORT_STATE_MASK(pinfo->port_state)),
682fcf3ce44SJohn Forte 	    pinfo->port_state,
683fcf3ce44SJohn Forte 	    fcsm_topology_to_str(pinfo->port_flags), pinfo->port_flags));
684fcf3ce44SJohn Forte 
685fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
686fcf3ce44SJohn Forte }
687fcf3ce44SJohn Forte 
688fcf3ce44SJohn Forte 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)689fcf3ce44SJohn Forte fcsm_handle_port_resume(opaque_t ulph, fc_ulp_port_info_t *pinfo,
690fcf3ce44SJohn Forte     fc_attach_cmd_t cmd, uint32_t s_id, fcsm_t *fcsm)
691fcf3ce44SJohn Forte {
692fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
693fcf3ce44SJohn Forte 	    "port_resume: cmd 0x%x", cmd));
694fcf3ce44SJohn Forte 
695fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
696fcf3ce44SJohn Forte 
697fcf3ce44SJohn Forte 	switch (cmd) {
698fcf3ce44SJohn Forte 	case FC_CMD_RESUME:
699fcf3ce44SJohn Forte 		ASSERT(!(fcsm->sm_flags & FCSM_POWER_DOWN));
700fcf3ce44SJohn Forte 		fcsm->sm_flags &= ~FCSM_SUSPENDED;
701fcf3ce44SJohn Forte 		break;
702fcf3ce44SJohn Forte 
703fcf3ce44SJohn Forte 	case FC_CMD_POWER_UP:
704fcf3ce44SJohn Forte 		/* If port is suspended, then no need to resume */
705fcf3ce44SJohn Forte 		fcsm->sm_flags &= ~FCSM_POWER_DOWN;
706fcf3ce44SJohn Forte 		if (fcsm->sm_flags & FCSM_SUSPENDED) {
707fcf3ce44SJohn Forte 			mutex_exit(&fcsm->sm_mutex);
708fcf3ce44SJohn Forte 			return (DDI_SUCCESS);
709fcf3ce44SJohn Forte 		}
710fcf3ce44SJohn Forte 		break;
711fcf3ce44SJohn Forte 	default:
712fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
713fcf3ce44SJohn Forte 		return (DDI_FAILURE);
714fcf3ce44SJohn Forte 	}
715fcf3ce44SJohn Forte 
716fcf3ce44SJohn Forte 	fcsm->sm_sid = s_id;
717fcf3ce44SJohn Forte 
718fcf3ce44SJohn Forte 	/*
719fcf3ce44SJohn Forte 	 * Make a copy of the new port_information structure
720fcf3ce44SJohn Forte 	 */
721fcf3ce44SJohn Forte 	fcsm->sm_port_info	= *pinfo;	/* Structure copy !!! */
722fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
723fcf3ce44SJohn Forte 
724fcf3ce44SJohn Forte 	fcsm_resume_port(fcsm);
725fcf3ce44SJohn Forte 
726fcf3ce44SJohn Forte 	/*
727fcf3ce44SJohn Forte 	 * Invoke state change processing.
728fcf3ce44SJohn Forte 	 * This will ensure that
729fcf3ce44SJohn Forte 	 *    - offline timer is started if new port state changed to offline.
730fcf3ce44SJohn Forte 	 *    - MGMT_SERVER_LOGIN flag is reset.
731fcf3ce44SJohn Forte 	 *    - Port topology is updated.
732fcf3ce44SJohn Forte 	 */
733fcf3ce44SJohn Forte 	fcsm_statec_cb(ulph, (opaque_t)pinfo->port_handle, pinfo->port_state,
734fcf3ce44SJohn Forte 	    pinfo->port_flags, NULL, 0, s_id);
735fcf3ce44SJohn Forte 
736fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
737fcf3ce44SJohn Forte }
738fcf3ce44SJohn Forte 
739fcf3ce44SJohn Forte 
740fcf3ce44SJohn Forte /* ARGSUSED */
741fcf3ce44SJohn Forte static int
fcsm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)742fcf3ce44SJohn Forte fcsm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
743fcf3ce44SJohn Forte {
744fcf3ce44SJohn Forte 	int	rval = DDI_SUCCESS;
745fcf3ce44SJohn Forte 
746fcf3ce44SJohn Forte 	switch (cmd) {
747fcf3ce44SJohn Forte 	case DDI_DETACH: {
748fcf3ce44SJohn Forte 		fcsm_t	*fcsm;
749fcf3ce44SJohn Forte 
750fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
751fcf3ce44SJohn Forte 		    "detach: start. cmd <DETACH>", cmd));
752fcf3ce44SJohn Forte 
753fcf3ce44SJohn Forte 		mutex_enter(&fcsm_global_mutex);
754fcf3ce44SJohn Forte 
755fcf3ce44SJohn Forte 		/*
756fcf3ce44SJohn Forte 		 * If port attach/detach in progress, then wait for 5 seconds
757fcf3ce44SJohn Forte 		 * for them to complete.
758fcf3ce44SJohn Forte 		 */
759fcf3ce44SJohn Forte 		if (fcsm_num_attaching || fcsm_num_detaching) {
760fcf3ce44SJohn Forte 			int count;
761fcf3ce44SJohn Forte 
762fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
763fcf3ce44SJohn Forte 			    "detach: wait for port attach/detach to complete"));
764fcf3ce44SJohn Forte 
765fcf3ce44SJohn Forte 			count = 0;
766fcf3ce44SJohn Forte 			while ((count++ <= 30) &&
767fcf3ce44SJohn Forte 			    (fcsm_num_attaching || fcsm_num_detaching)) {
768fcf3ce44SJohn Forte 				mutex_exit(&fcsm_global_mutex);
769fcf3ce44SJohn Forte 				delay(drv_usectohz(1000000));
770fcf3ce44SJohn Forte 				mutex_enter(&fcsm_global_mutex);
771fcf3ce44SJohn Forte 			}
772fcf3ce44SJohn Forte 
773fcf3ce44SJohn Forte 			/* Port attach/detach still in prog, so fail detach */
774fcf3ce44SJohn Forte 			if (fcsm_num_attaching || fcsm_num_detaching) {
775fcf3ce44SJohn Forte 				mutex_exit(&fcsm_global_mutex);
776fcf3ce44SJohn Forte 				FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL,
777fcf3ce44SJohn Forte 				    NULL, "detach: Failing detach. port "
778fcf3ce44SJohn Forte 				    "attach/detach in progress"));
779fcf3ce44SJohn Forte 				rval = DDI_FAILURE;
780fcf3ce44SJohn Forte 				break;
781fcf3ce44SJohn Forte 			}
782fcf3ce44SJohn Forte 		}
783fcf3ce44SJohn Forte 
784fcf3ce44SJohn Forte 		if (fcsm_port_head == NULL) {
785fcf3ce44SJohn Forte 			/* Not much do, Succeed to detach. */
786fcf3ce44SJohn Forte 			ddi_remove_minor_node(fcsm_dip, NULL);
787fcf3ce44SJohn Forte 			fcsm_dip = NULL;
788fcf3ce44SJohn Forte 			fcsm_detached = 0;
789fcf3ce44SJohn Forte 			mutex_exit(&fcsm_global_mutex);
790fcf3ce44SJohn Forte 			break;
791fcf3ce44SJohn Forte 		}
792fcf3ce44SJohn Forte 
793fcf3ce44SJohn Forte 		/*
794fcf3ce44SJohn Forte 		 * Check to see, if any ports are active.
795fcf3ce44SJohn Forte 		 * If not, then set the DETACHING flag to indicate
796fcf3ce44SJohn Forte 		 * that they are being detached.
797fcf3ce44SJohn Forte 		 */
798fcf3ce44SJohn Forte 		fcsm = fcsm_port_head;
799fcf3ce44SJohn Forte 		while (fcsm != NULL) {
800fcf3ce44SJohn Forte 
801fcf3ce44SJohn Forte 			mutex_enter(&fcsm->sm_mutex);
802fcf3ce44SJohn Forte 			if (!(fcsm->sm_flags & FCSM_ATTACHED) ||
803fcf3ce44SJohn Forte 			    fcsm->sm_ncmds || fcsm->sm_cb_count) {
804fcf3ce44SJohn Forte 				/* port is busy. We can't detach */
805fcf3ce44SJohn Forte 				mutex_exit(&fcsm->sm_mutex);
806fcf3ce44SJohn Forte 				break;
807fcf3ce44SJohn Forte 			}
808fcf3ce44SJohn Forte 
809fcf3ce44SJohn Forte 			fcsm->sm_flags |= FCSM_DETACHING;
810fcf3ce44SJohn Forte 			mutex_exit(&fcsm->sm_mutex);
811fcf3ce44SJohn Forte 
812fcf3ce44SJohn Forte 			fcsm = fcsm->sm_next;
813fcf3ce44SJohn Forte 		}
814fcf3ce44SJohn Forte 
815fcf3ce44SJohn Forte 		/*
816fcf3ce44SJohn Forte 		 * If all ports could not be marked for detaching,
817fcf3ce44SJohn Forte 		 * then clear the flags and fail the detach.
818fcf3ce44SJohn Forte 		 * Also if a port attach is currently in progress
819fcf3ce44SJohn Forte 		 * then fail the detach.
820fcf3ce44SJohn Forte 		 */
821fcf3ce44SJohn Forte 		if (fcsm != NULL || fcsm_num_attaching || fcsm_num_detaching) {
822fcf3ce44SJohn Forte 			/*
823fcf3ce44SJohn Forte 			 * Some ports were busy, so can't detach.
824fcf3ce44SJohn Forte 			 * Clear the DETACHING flag and return failure
825fcf3ce44SJohn Forte 			 */
826fcf3ce44SJohn Forte 			fcsm = fcsm_port_head;
827fcf3ce44SJohn Forte 			while (fcsm != NULL) {
828fcf3ce44SJohn Forte 				mutex_enter(&fcsm->sm_mutex);
829fcf3ce44SJohn Forte 				if (fcsm->sm_flags & FCSM_DETACHING) {
830fcf3ce44SJohn Forte 					fcsm->sm_flags &= ~FCSM_DETACHING;
831fcf3ce44SJohn Forte 				}
832fcf3ce44SJohn Forte 				mutex_exit(&fcsm->sm_mutex);
833fcf3ce44SJohn Forte 
834fcf3ce44SJohn Forte 				fcsm = fcsm->sm_next;
835fcf3ce44SJohn Forte 			}
836fcf3ce44SJohn Forte 			mutex_exit(&fcsm_global_mutex);
837fcf3ce44SJohn Forte 			return (DDI_FAILURE);
838fcf3ce44SJohn Forte 		} else {
839fcf3ce44SJohn Forte 			fcsm_detached = 1;
840fcf3ce44SJohn Forte 			/*
841fcf3ce44SJohn Forte 			 * Mark all the detaching ports as detached, as we
842fcf3ce44SJohn Forte 			 * will be detaching them
843fcf3ce44SJohn Forte 			 */
844fcf3ce44SJohn Forte 			fcsm = fcsm_port_head;
845fcf3ce44SJohn Forte 			while (fcsm != NULL) {
846fcf3ce44SJohn Forte 				mutex_enter(&fcsm->sm_mutex);
847fcf3ce44SJohn Forte 				fcsm->sm_flags &= ~FCSM_DETACHING;
848fcf3ce44SJohn Forte 				fcsm->sm_flags |= FCSM_DETACHED;
849fcf3ce44SJohn Forte 				mutex_exit(&fcsm->sm_mutex);
850fcf3ce44SJohn Forte 
851fcf3ce44SJohn Forte 				fcsm = fcsm->sm_next;
852fcf3ce44SJohn Forte 			}
853fcf3ce44SJohn Forte 		}
854fcf3ce44SJohn Forte 		mutex_exit(&fcsm_global_mutex);
855fcf3ce44SJohn Forte 
856fcf3ce44SJohn Forte 
857fcf3ce44SJohn Forte 		/*
858fcf3ce44SJohn Forte 		 * Go ahead and detach the ports
859fcf3ce44SJohn Forte 		 */
860fcf3ce44SJohn Forte 		mutex_enter(&fcsm_global_mutex);
861fcf3ce44SJohn Forte 		while (fcsm_port_head != NULL) {
862fcf3ce44SJohn Forte 			fcsm = fcsm_port_head;
863fcf3ce44SJohn Forte 			mutex_exit(&fcsm_global_mutex);
864fcf3ce44SJohn Forte 
865fcf3ce44SJohn Forte 			/*
866fcf3ce44SJohn Forte 			 * Call fcsm_cleanup_port(). This cleansup and
867fcf3ce44SJohn Forte 			 * removes the fcsm structure from global linked list
868fcf3ce44SJohn Forte 			 */
869fcf3ce44SJohn Forte 			fcsm_cleanup_port(fcsm);
870fcf3ce44SJohn Forte 
871fcf3ce44SJohn Forte 			/*
872fcf3ce44SJohn Forte 			 * Soft state cleanup done.
873fcf3ce44SJohn Forte 			 * Remember that fcsm struct doesn't exist anymore.
874fcf3ce44SJohn Forte 			 */
875fcf3ce44SJohn Forte 
876fcf3ce44SJohn Forte 			mutex_enter(&fcsm_global_mutex);
877fcf3ce44SJohn Forte 		}
878fcf3ce44SJohn Forte 
879fcf3ce44SJohn Forte 		ddi_remove_minor_node(fcsm_dip, NULL);
880fcf3ce44SJohn Forte 		fcsm_dip = NULL;
881fcf3ce44SJohn Forte 		mutex_exit(&fcsm_global_mutex);
882fcf3ce44SJohn Forte 		break;
883fcf3ce44SJohn Forte 	}
884fcf3ce44SJohn Forte 
885fcf3ce44SJohn Forte 	case DDI_SUSPEND:
886fcf3ce44SJohn Forte 		rval = DDI_SUCCESS;
887fcf3ce44SJohn Forte 		break;
888fcf3ce44SJohn Forte 
889fcf3ce44SJohn Forte 	default:
890fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
891fcf3ce44SJohn Forte 		    "detach: unknown cmd 0x%x", cmd));
892fcf3ce44SJohn Forte 		rval = DDI_FAILURE;
893fcf3ce44SJohn Forte 		break;
894fcf3ce44SJohn Forte 	}
895fcf3ce44SJohn Forte 
896fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
897fcf3ce44SJohn Forte 	    "detach: end. cmd 0x%x, rval 0x%x", cmd, rval));
898fcf3ce44SJohn Forte 
899fcf3ce44SJohn Forte 	return (rval);
900fcf3ce44SJohn Forte }
901fcf3ce44SJohn Forte 
902fcf3ce44SJohn Forte 
903fcf3ce44SJohn Forte /* ARGSUSED */
904fcf3ce44SJohn Forte static void
fcsm_force_port_detach_all(void)905fcf3ce44SJohn Forte fcsm_force_port_detach_all(void)
906fcf3ce44SJohn Forte {
907fcf3ce44SJohn Forte 	fcsm_t	*fcsm;
908fcf3ce44SJohn Forte 
909fcf3ce44SJohn Forte 	fcsm = fcsm_port_head;
910fcf3ce44SJohn Forte 
911fcf3ce44SJohn Forte 	while (fcsm) {
912fcf3ce44SJohn Forte 		fcsm_cleanup_port(fcsm);
913fcf3ce44SJohn Forte 		/*
914fcf3ce44SJohn Forte 		 * fcsm_cleanup_port will remove the current fcsm structure
915fcf3ce44SJohn Forte 		 * from the list, which will cause fcsm_port_head to point
916fcf3ce44SJohn Forte 		 * to what would have been the next structure on the list.
917fcf3ce44SJohn Forte 		 */
918fcf3ce44SJohn Forte 		fcsm = fcsm_port_head;
919fcf3ce44SJohn Forte 	}
920fcf3ce44SJohn Forte }
921fcf3ce44SJohn Forte 
922fcf3ce44SJohn Forte 
923fcf3ce44SJohn Forte /* ARGSUSED */
924fcf3ce44SJohn Forte static int
fcsm_port_detach(opaque_t ulph,fc_ulp_port_info_t * pinfo,fc_detach_cmd_t cmd)925fcf3ce44SJohn Forte fcsm_port_detach(opaque_t ulph, fc_ulp_port_info_t *pinfo, fc_detach_cmd_t cmd)
926fcf3ce44SJohn Forte {
927fcf3ce44SJohn Forte 	int	instance;
928fcf3ce44SJohn Forte 	int	rval = FC_FAILURE;
929fcf3ce44SJohn Forte 	fcsm_t	*fcsm;
930fcf3ce44SJohn Forte 
931fcf3ce44SJohn Forte 	instance = ddi_get_instance(pinfo->port_dip);
932fcf3ce44SJohn Forte 
933fcf3ce44SJohn Forte 	mutex_enter(&fcsm_global_mutex);
934fcf3ce44SJohn Forte 	if (fcsm_detached) {
935fcf3ce44SJohn Forte 		mutex_exit(&fcsm_global_mutex);
936fcf3ce44SJohn Forte 
937fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
938fcf3ce44SJohn Forte 		    "port_detach: end. instance 0x%x, fcsm is detached",
939fcf3ce44SJohn Forte 		    instance));
940fcf3ce44SJohn Forte 		return (FC_SUCCESS);
941fcf3ce44SJohn Forte 	}
942fcf3ce44SJohn Forte 	fcsm_num_detaching++;	/* Set the flag */
943fcf3ce44SJohn Forte 	mutex_exit(&fcsm_global_mutex);
944fcf3ce44SJohn Forte 
945fcf3ce44SJohn Forte 	/* Get the soft state structure */
946fcf3ce44SJohn Forte 	if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) {
947fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
948fcf3ce44SJohn Forte 		    "port_detach: instance 0x%x, cmd 0x%x get softstate failed",
949fcf3ce44SJohn Forte 		    instance, cmd));
950fcf3ce44SJohn Forte 		mutex_enter(&fcsm_global_mutex);
951fcf3ce44SJohn Forte 		fcsm_num_detaching--;
952fcf3ce44SJohn Forte 		mutex_exit(&fcsm_global_mutex);
953fcf3ce44SJohn Forte 		return (rval);
954fcf3ce44SJohn Forte 	}
955fcf3ce44SJohn Forte 
956fcf3ce44SJohn Forte 	ASSERT(fcsm->sm_instance == instance);
957fcf3ce44SJohn Forte 
958fcf3ce44SJohn Forte 	/* If this instance is not attached, then fail the detach */
959fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
960fcf3ce44SJohn Forte 	if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) {
961fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
962fcf3ce44SJohn Forte 		fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
963fcf3ce44SJohn Forte 		    "port_detach: port is not attached");
964fcf3ce44SJohn Forte 		mutex_enter(&fcsm_global_mutex);
965fcf3ce44SJohn Forte 		fcsm_num_detaching--;
966fcf3ce44SJohn Forte 		mutex_exit(&fcsm_global_mutex);
967fcf3ce44SJohn Forte 		return (rval);
968fcf3ce44SJohn Forte 	}
969fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
970fcf3ce44SJohn Forte 
971fcf3ce44SJohn Forte 	/*
972fcf3ce44SJohn Forte 	 * If fcsm has been detached, then all instance has already been
973fcf3ce44SJohn Forte 	 * detached or are being detached. So succeed this detach.
974fcf3ce44SJohn Forte 	 */
975fcf3ce44SJohn Forte 
976fcf3ce44SJohn Forte 	switch (cmd) {
9777ff83669SZhong Wang 	case FC_CMD_DETACH:
9787ff83669SZhong Wang 	case FC_CMD_SUSPEND:
9797ff83669SZhong Wang 	case FC_CMD_POWER_DOWN:
9807ff83669SZhong Wang 		break;
981fcf3ce44SJohn Forte 
9827ff83669SZhong Wang 	default:
9837ff83669SZhong Wang 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
9847ff83669SZhong Wang 		    "port_detach: port unknown cmd 0x%x", cmd));
9857ff83669SZhong Wang 		mutex_enter(&fcsm_global_mutex);
9867ff83669SZhong Wang 		fcsm_num_detaching--;
9877ff83669SZhong Wang 		mutex_exit(&fcsm_global_mutex);
9887ff83669SZhong Wang 		return (rval);
989fcf3ce44SJohn Forte 	};
990fcf3ce44SJohn Forte 
991fcf3ce44SJohn Forte 	if (fcsm_handle_port_detach(pinfo, fcsm, cmd) == DDI_SUCCESS) {
992fcf3ce44SJohn Forte 		rval = FC_SUCCESS;
993fcf3ce44SJohn Forte 	}
994fcf3ce44SJohn Forte 
995fcf3ce44SJohn Forte 	mutex_enter(&fcsm_global_mutex);
996fcf3ce44SJohn Forte 	fcsm_num_detaching--;
997fcf3ce44SJohn Forte 	mutex_exit(&fcsm_global_mutex);
998fcf3ce44SJohn Forte 
999fcf3ce44SJohn Forte 	/* If it was a detach, then fcsm state structure no longer exists */
1000fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1001fcf3ce44SJohn Forte 	    "port_detach: end. cmd 0x%x rval 0x%x", cmd, rval));
1002fcf3ce44SJohn Forte 	return (rval);
1003fcf3ce44SJohn Forte }
1004fcf3ce44SJohn Forte 
1005fcf3ce44SJohn Forte 
1006fcf3ce44SJohn Forte static int
fcsm_handle_port_detach(fc_ulp_port_info_t * pinfo,fcsm_t * fcsm,fc_detach_cmd_t cmd)1007fcf3ce44SJohn Forte fcsm_handle_port_detach(fc_ulp_port_info_t *pinfo, fcsm_t *fcsm,
1008fcf3ce44SJohn Forte     fc_detach_cmd_t cmd)
1009fcf3ce44SJohn Forte {
1010fcf3ce44SJohn Forte 	uint32_t	flag;
1011fcf3ce44SJohn Forte 	int		count;
1012fcf3ce44SJohn Forte #ifdef DEBUG
1013fcf3ce44SJohn Forte 	char		pathname[MAXPATHLEN];
1014fcf3ce44SJohn Forte #endif /* DEBUG */
1015fcf3ce44SJohn Forte 
1016fcf3ce44SJohn Forte 	/*
1017fcf3ce44SJohn Forte 	 * If port is already powered down OR suspended and there is nothing
1018fcf3ce44SJohn Forte 	 * else to do then just return.
1019fcf3ce44SJohn Forte 	 * Otherwise, set the flag, so that no more new activity will be
1020fcf3ce44SJohn Forte 	 * initiated on this port.
1021fcf3ce44SJohn Forte 	 */
1022fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
1023fcf3ce44SJohn Forte 
1024fcf3ce44SJohn Forte 	switch (cmd) {
10257ff83669SZhong Wang 	case FC_CMD_DETACH:
10267ff83669SZhong Wang 		flag = FCSM_DETACHING;
10277ff83669SZhong Wang 		break;
1028fcf3ce44SJohn Forte 
10297ff83669SZhong Wang 	case FC_CMD_SUSPEND:
10307ff83669SZhong Wang 	case FC_CMD_POWER_DOWN:
10317ff83669SZhong Wang 		((cmd == FC_CMD_SUSPEND) ? (flag = FCSM_SUSPENDED) :
10327ff83669SZhong Wang 		    (flag = FCSM_POWER_DOWN));
10337ff83669SZhong Wang 		if (fcsm->sm_flags &
10347ff83669SZhong Wang 		    (FCSM_POWER_DOWN | FCSM_SUSPENDED)) {
10357ff83669SZhong Wang 			fcsm->sm_flags |= flag;
1036fcf3ce44SJohn Forte 			mutex_exit(&fcsm->sm_mutex);
10377ff83669SZhong Wang 			return (DDI_SUCCESS);
10387ff83669SZhong Wang 		}
10397ff83669SZhong Wang 		break;
10407ff83669SZhong Wang 
10417ff83669SZhong Wang 	default:
10427ff83669SZhong Wang 		mutex_exit(&fcsm->sm_mutex);
10437ff83669SZhong Wang 		return (DDI_FAILURE);
1044fcf3ce44SJohn Forte 	};
1045fcf3ce44SJohn Forte 
1046fcf3ce44SJohn Forte 	fcsm->sm_flags |= flag;
1047fcf3ce44SJohn Forte 
1048fcf3ce44SJohn Forte 	/*
1049fcf3ce44SJohn Forte 	 * If some commands are pending OR callback in progress, then
1050fcf3ce44SJohn Forte 	 * wait for some finite amount of time for their completion.
1051fcf3ce44SJohn Forte 	 * TODO: add more checks here to check for cmd timeout, offline
1052fcf3ce44SJohn Forte 	 * timeout and other (??) threads.
1053fcf3ce44SJohn Forte 	 */
1054fcf3ce44SJohn Forte 	count = 0;
1055fcf3ce44SJohn Forte 	while ((count++ <= 30) && (fcsm->sm_ncmds || fcsm->sm_cb_count)) {
1056fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
1057fcf3ce44SJohn Forte 		delay(drv_usectohz(1000000));
1058fcf3ce44SJohn Forte 		mutex_enter(&fcsm->sm_mutex);
1059fcf3ce44SJohn Forte 	}
1060fcf3ce44SJohn Forte 	if (fcsm->sm_ncmds || fcsm->sm_cb_count) {
1061fcf3ce44SJohn Forte 		fcsm->sm_flags &= ~flag;
1062fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
1063fcf3ce44SJohn Forte 		fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
1064fcf3ce44SJohn Forte 		    "port_detach: Failing suspend, port is busy");
1065fcf3ce44SJohn Forte 		return (DDI_FAILURE);
1066fcf3ce44SJohn Forte 	}
1067fcf3ce44SJohn Forte 	if (flag == FCSM_DETACHING) {
1068fcf3ce44SJohn Forte 		fcsm->sm_flags &= ~FCSM_DETACHING;
1069fcf3ce44SJohn Forte 		fcsm->sm_flags |= FCSM_DETACHED;
1070fcf3ce44SJohn Forte 	}
1071fcf3ce44SJohn Forte 
1072fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
1073fcf3ce44SJohn Forte 
1074fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL,
1075fcf3ce44SJohn Forte 	    "port_detach: cmd 0x%x pathname <%s>",
1076fcf3ce44SJohn Forte 	    cmd, ddi_pathname(pinfo->port_dip, pathname)));
1077fcf3ce44SJohn Forte 
1078fcf3ce44SJohn Forte 	if (cmd == FC_CMD_DETACH) {
1079fcf3ce44SJohn Forte 		fcsm_cleanup_port(fcsm);
1080fcf3ce44SJohn Forte 		/*
1081fcf3ce44SJohn Forte 		 * Soft state cleanup done.
1082fcf3ce44SJohn Forte 		 * Always remember that fcsm struct doesn't exist anymore.
1083fcf3ce44SJohn Forte 		 */
1084fcf3ce44SJohn Forte 	} else {
1085fcf3ce44SJohn Forte 		fcsm_suspend_port(fcsm);
1086fcf3ce44SJohn Forte 	}
1087fcf3ce44SJohn Forte 
1088fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
1089fcf3ce44SJohn Forte }
1090fcf3ce44SJohn Forte 
1091fcf3ce44SJohn Forte static void
fcsm_suspend_port(fcsm_t * fcsm)1092fcf3ce44SJohn Forte fcsm_suspend_port(fcsm_t *fcsm)
1093fcf3ce44SJohn Forte {
1094fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
1095fcf3ce44SJohn Forte 
1096fcf3ce44SJohn Forte 	if (fcsm->sm_offline_tid != NULL) {
1097fcf3ce44SJohn Forte 		timeout_id_t	tid;
1098fcf3ce44SJohn Forte 
1099fcf3ce44SJohn Forte 		tid = fcsm->sm_offline_tid;
1100fcf3ce44SJohn Forte 		fcsm->sm_offline_tid = (timeout_id_t)NULL;
1101fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
1102fcf3ce44SJohn Forte 		(void) untimeout(tid);
1103fcf3ce44SJohn Forte 		mutex_enter(&fcsm->sm_mutex);
1104fcf3ce44SJohn Forte 		fcsm->sm_flags |= FCSM_RESTORE_OFFLINE_TIMEOUT;
1105fcf3ce44SJohn Forte 	}
1106fcf3ce44SJohn Forte 
1107fcf3ce44SJohn Forte 	if (fcsm->sm_retry_tid != NULL) {
1108fcf3ce44SJohn Forte 		timeout_id_t	tid;
1109fcf3ce44SJohn Forte 
1110fcf3ce44SJohn Forte 		tid = fcsm->sm_retry_tid;
1111fcf3ce44SJohn Forte 		fcsm->sm_retry_tid = (timeout_id_t)NULL;
1112fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
1113fcf3ce44SJohn Forte 		(void) untimeout(tid);
1114fcf3ce44SJohn Forte 		mutex_enter(&fcsm->sm_mutex);
1115fcf3ce44SJohn Forte 		fcsm->sm_flags |= FCSM_RESTORE_RETRY_TIMEOUT;
1116fcf3ce44SJohn Forte 	}
1117fcf3ce44SJohn Forte 
1118fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
1119fcf3ce44SJohn Forte }
1120fcf3ce44SJohn Forte 
1121fcf3ce44SJohn Forte static void
fcsm_resume_port(fcsm_t * fcsm)1122fcf3ce44SJohn Forte fcsm_resume_port(fcsm_t *fcsm)
1123fcf3ce44SJohn Forte {
1124fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
1125fcf3ce44SJohn Forte 
1126fcf3ce44SJohn Forte 	if (fcsm->sm_flags & FCSM_RESTORE_OFFLINE_TIMEOUT) {
1127fcf3ce44SJohn Forte 		fcsm->sm_flags &= ~FCSM_RESTORE_OFFLINE_TIMEOUT;
1128fcf3ce44SJohn Forte 
1129fcf3ce44SJohn Forte 		/*
1130fcf3ce44SJohn Forte 		 * If port if offline, link is not marked down and offline
1131fcf3ce44SJohn Forte 		 * timer is not already running, then restart offline timer.
1132fcf3ce44SJohn Forte 		 */
1133fcf3ce44SJohn Forte 		if (!(fcsm->sm_flags & FCSM_LINK_DOWN) &&
1134fcf3ce44SJohn Forte 		    fcsm->sm_offline_tid == NULL &&
1135fcf3ce44SJohn Forte 		    (fcsm->sm_flags & FCSM_PORT_OFFLINE)) {
1136fcf3ce44SJohn Forte 			fcsm->sm_offline_tid = timeout(fcsm_offline_timeout,
1137fcf3ce44SJohn Forte 			    (caddr_t)fcsm, fcsm_offline_ticks);
1138fcf3ce44SJohn Forte 		}
1139fcf3ce44SJohn Forte 	}
1140fcf3ce44SJohn Forte 
1141fcf3ce44SJohn Forte 	if (fcsm->sm_flags & FCSM_RESTORE_RETRY_TIMEOUT) {
1142fcf3ce44SJohn Forte 		fcsm->sm_flags &= ~FCSM_RESTORE_RETRY_TIMEOUT;
1143fcf3ce44SJohn Forte 
1144fcf3ce44SJohn Forte 		/*
1145fcf3ce44SJohn Forte 		 * If retry queue is not suspended and some cmds are waiting
1146fcf3ce44SJohn Forte 		 * to be retried, then restart the retry timer
1147fcf3ce44SJohn Forte 		 */
1148fcf3ce44SJohn Forte 		if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) {
1149fcf3ce44SJohn Forte 			fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
1150fcf3ce44SJohn Forte 			    (caddr_t)fcsm, fcsm_retry_ticks);
1151fcf3ce44SJohn Forte 		}
1152fcf3ce44SJohn Forte 	}
1153fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
1154fcf3ce44SJohn Forte }
1155fcf3ce44SJohn Forte 
1156fcf3ce44SJohn Forte static void
fcsm_cleanup_port(fcsm_t * fcsm)1157fcf3ce44SJohn Forte fcsm_cleanup_port(fcsm_t *fcsm)
1158fcf3ce44SJohn Forte {
1159fcf3ce44SJohn Forte 	fcsm_t		*curr, *prev;
1160fcf3ce44SJohn Forte 	int		status;
1161fcf3ce44SJohn Forte 	fcsm_job_t	*job;
1162fcf3ce44SJohn Forte 
1163fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1164fcf3ce44SJohn Forte 	    "fcsm_cleanup_port: entered"));
1165fcf3ce44SJohn Forte 
1166fcf3ce44SJohn Forte 	/*
1167fcf3ce44SJohn Forte 	 * Kill the job thread
1168fcf3ce44SJohn Forte 	 */
1169fcf3ce44SJohn Forte 	job = fcsm_alloc_job(KM_SLEEP);
1170fcf3ce44SJohn Forte 	ASSERT(job != NULL);
1171fcf3ce44SJohn Forte 	fcsm_init_job(job, fcsm->sm_instance, FCSM_JOB_THREAD_SHUTDOWN,
1172fcf3ce44SJohn Forte 	    FCSM_JOBFLAG_SYNC, NULL, NULL, NULL, NULL);
1173fcf3ce44SJohn Forte 
1174fcf3ce44SJohn Forte 	status = fcsm_process_job(job, 0);
1175fcf3ce44SJohn Forte 	ASSERT(status == FC_SUCCESS);
1176fcf3ce44SJohn Forte 
1177fcf3ce44SJohn Forte 	ASSERT(job->job_result == FC_SUCCESS);
1178fcf3ce44SJohn Forte 	fcsm_dealloc_job(job);
1179fcf3ce44SJohn Forte 
1180fcf3ce44SJohn Forte 	/*
1181fcf3ce44SJohn Forte 	 * We got here after ensuring the no commands are pending or active.
1182fcf3ce44SJohn Forte 	 * Therefore retry timeout thread should NOT be running.
1183fcf3ce44SJohn Forte 	 * Kill the offline timeout thread if currently running.
1184fcf3ce44SJohn Forte 	 */
1185fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
1186fcf3ce44SJohn Forte 
1187fcf3ce44SJohn Forte 	ASSERT(fcsm->sm_retry_tid == NULL);
1188fcf3ce44SJohn Forte 
1189fcf3ce44SJohn Forte 	if (fcsm->sm_offline_tid != NULL) {
1190fcf3ce44SJohn Forte 		timeout_id_t	tid;
1191fcf3ce44SJohn Forte 
1192fcf3ce44SJohn Forte 		tid = fcsm->sm_offline_tid;
1193fcf3ce44SJohn Forte 		fcsm->sm_offline_tid = (timeout_id_t)NULL;
1194fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
1195fcf3ce44SJohn Forte 		(void) untimeout(tid);
1196fcf3ce44SJohn Forte 	} else {
1197fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
1198fcf3ce44SJohn Forte 	}
1199fcf3ce44SJohn Forte 
1200fcf3ce44SJohn Forte 	/* Remove from the fcsm state structure from global linked list */
1201fcf3ce44SJohn Forte 	mutex_enter(&fcsm_global_mutex);
1202fcf3ce44SJohn Forte 	curr = fcsm_port_head;
1203fcf3ce44SJohn Forte 	prev = NULL;
1204fcf3ce44SJohn Forte 	while (curr != fcsm && curr != NULL) {
1205fcf3ce44SJohn Forte 		prev = curr;
1206fcf3ce44SJohn Forte 		curr = curr->sm_next;
1207fcf3ce44SJohn Forte 	}
1208fcf3ce44SJohn Forte 	ASSERT(curr != NULL);
1209fcf3ce44SJohn Forte 
1210fcf3ce44SJohn Forte 	if (prev == NULL) {
1211fcf3ce44SJohn Forte 		fcsm_port_head = curr->sm_next;
1212fcf3ce44SJohn Forte 	} else {
1213fcf3ce44SJohn Forte 		prev->sm_next = curr->sm_next;
1214fcf3ce44SJohn Forte 	}
1215fcf3ce44SJohn Forte 	mutex_exit(&fcsm_global_mutex);
1216fcf3ce44SJohn Forte 
1217fcf3ce44SJohn Forte 	if (fcsm->sm_cmd_cache != NULL) {
1218fcf3ce44SJohn Forte 		kmem_cache_destroy(fcsm->sm_cmd_cache);
1219fcf3ce44SJohn Forte 	}
1220fcf3ce44SJohn Forte 	cv_destroy(&fcsm->sm_job_cv);
1221fcf3ce44SJohn Forte 	mutex_destroy(&fcsm->sm_mutex);
1222fcf3ce44SJohn Forte 
1223fcf3ce44SJohn Forte 	/* Free the fcsm state structure */
1224fcf3ce44SJohn Forte 	ddi_soft_state_free(fcsm_state, fcsm->sm_instance);
1225fcf3ce44SJohn Forte }
1226fcf3ce44SJohn Forte 
1227fcf3ce44SJohn Forte 
1228fcf3ce44SJohn Forte /* ARGSUSED */
1229fcf3ce44SJohn Forte 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)1230fcf3ce44SJohn Forte fcsm_statec_cb(opaque_t ulph, opaque_t port_handle, uint32_t port_state,
1231fcf3ce44SJohn Forte     uint32_t port_top, fc_portmap_t *devlist, uint32_t dev_cnt,
1232fcf3ce44SJohn Forte     uint32_t port_sid)
1233fcf3ce44SJohn Forte {
1234fcf3ce44SJohn Forte 	fcsm_t		*fcsm;
1235fcf3ce44SJohn Forte 	timeout_id_t	offline_tid, retry_tid;
1236fcf3ce44SJohn Forte 
1237fcf3ce44SJohn Forte 	mutex_enter(&fcsm_global_mutex);
1238fcf3ce44SJohn Forte 	if (fcsm_detached) {
1239fcf3ce44SJohn Forte 		mutex_exit(&fcsm_global_mutex);
1240fcf3ce44SJohn Forte 		return;
1241fcf3ce44SJohn Forte 	}
1242fcf3ce44SJohn Forte 
1243fcf3ce44SJohn Forte 	fcsm = ddi_get_soft_state(fcsm_state,
1244fcf3ce44SJohn Forte 	    fc_ulp_get_port_instance(port_handle));
1245fcf3ce44SJohn Forte 	if (fcsm == NULL) {
1246fcf3ce44SJohn Forte 		mutex_exit(&fcsm_global_mutex);
1247fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, NULL, NULL,
1248fcf3ce44SJohn Forte 		    "statec_cb: instance 0x%x not found",
1249fcf3ce44SJohn Forte 		    fc_ulp_get_port_instance(port_handle)));
1250fcf3ce44SJohn Forte 		return;
1251fcf3ce44SJohn Forte 	}
1252fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
1253fcf3ce44SJohn Forte 	ASSERT(fcsm->sm_instance == fc_ulp_get_port_instance(port_handle));
1254fcf3ce44SJohn Forte 	if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) {
1255fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
1256fcf3ce44SJohn Forte 		mutex_exit(&fcsm_global_mutex);
1257fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, fcsm, NULL,
1258fcf3ce44SJohn Forte 		    "statec_cb: port not attached"));
1259fcf3ce44SJohn Forte 		return;
1260fcf3ce44SJohn Forte 	}
1261fcf3ce44SJohn Forte 
1262fcf3ce44SJohn Forte 	ASSERT(fcsm->sm_cb_count >= 0);
1263fcf3ce44SJohn Forte 
1264fcf3ce44SJohn Forte 	fcsm->sm_cb_count++;
1265fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
1266fcf3ce44SJohn Forte 	mutex_exit(&fcsm_global_mutex);
1267fcf3ce44SJohn Forte 
1268fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1269fcf3ce44SJohn Forte 	    "statec_cb: state <%s>(0x%x) topology <%s>(0x%x) dev_cnt %d",
1270fcf3ce44SJohn Forte 	    fcsm_port_state_to_str(FC_PORT_STATE_MASK(port_state)), port_state,
1271fcf3ce44SJohn Forte 	    fcsm_topology_to_str(port_top), port_top, dev_cnt));
1272fcf3ce44SJohn Forte 
1273fcf3ce44SJohn Forte 	fcsm_disp_devlist(fcsm, devlist, dev_cnt);
1274fcf3ce44SJohn Forte 
1275fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
1276fcf3ce44SJohn Forte 
1277fcf3ce44SJohn Forte 	/*
1278fcf3ce44SJohn Forte 	 * Reset the Mgmt server Login flag, so that login is performed again.
1279fcf3ce44SJohn Forte 	 */
1280fcf3ce44SJohn Forte 	fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGGED_IN;
1281fcf3ce44SJohn Forte 
1282fcf3ce44SJohn Forte 	fcsm->sm_sid = port_sid;
1283fcf3ce44SJohn Forte 	fcsm->sm_port_top = port_top;
1284fcf3ce44SJohn Forte 	fcsm->sm_port_state = port_state;
1285fcf3ce44SJohn Forte 
1286fcf3ce44SJohn Forte 	switch (port_state) {
1287fcf3ce44SJohn Forte 	case FC_STATE_OFFLINE:
1288fcf3ce44SJohn Forte 	case FC_STATE_RESET:
1289fcf3ce44SJohn Forte 	case FC_STATE_RESET_REQUESTED:
1290fcf3ce44SJohn Forte 		fcsm->sm_flags |= FCSM_PORT_OFFLINE;
1291fcf3ce44SJohn Forte 		break;
1292fcf3ce44SJohn Forte 
1293fcf3ce44SJohn Forte 	case FC_STATE_ONLINE:
1294fcf3ce44SJohn Forte 	case FC_STATE_LOOP:
1295fcf3ce44SJohn Forte 	case FC_STATE_LIP:
1296fcf3ce44SJohn Forte 	case FC_STATE_LIP_LBIT_SET:
1297fcf3ce44SJohn Forte 		fcsm->sm_flags &= ~FCSM_PORT_OFFLINE;
1298fcf3ce44SJohn Forte 		fcsm->sm_flags &= ~FCSM_LINK_DOWN;
1299fcf3ce44SJohn Forte 		break;
1300fcf3ce44SJohn Forte 
1301fcf3ce44SJohn Forte 	case FC_STATE_NAMESERVICE:
1302fcf3ce44SJohn Forte 	case FC_STATE_DEVICE_CHANGE:
1303fcf3ce44SJohn Forte 	case FC_STATE_TARGET_PORT_RESET:
1304fcf3ce44SJohn Forte 	default:
1305fcf3ce44SJohn Forte 		/* Do nothing */
1306fcf3ce44SJohn Forte 		break;
1307fcf3ce44SJohn Forte 	}
1308fcf3ce44SJohn Forte 
1309fcf3ce44SJohn Forte 	offline_tid = retry_tid = NULL;
1310fcf3ce44SJohn Forte 	if (fcsm->sm_flags & FCSM_PORT_OFFLINE) {
1311fcf3ce44SJohn Forte 		/*
1312fcf3ce44SJohn Forte 		 * Port is offline.
1313fcf3ce44SJohn Forte 		 * Suspend cmd processing and start offline timeout thread.
1314fcf3ce44SJohn Forte 		 */
1315fcf3ce44SJohn Forte 		if (fcsm->sm_offline_tid == NULL) {
1316fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1317fcf3ce44SJohn Forte 			    "statec_cb: schedule offline timeout thread"));
1318fcf3ce44SJohn Forte 			fcsm->sm_flags |= FCSM_CMD_RETRY_Q_SUSPENDED;
1319fcf3ce44SJohn Forte 			/* Stop the cmd retry thread */
1320fcf3ce44SJohn Forte 			retry_tid = fcsm->sm_retry_tid;
1321fcf3ce44SJohn Forte 			fcsm->sm_retry_tid = (timeout_id_t)NULL;
1322fcf3ce44SJohn Forte 
1323fcf3ce44SJohn Forte 			fcsm->sm_offline_tid = timeout(fcsm_offline_timeout,
1324fcf3ce44SJohn Forte 			    (caddr_t)fcsm, fcsm_offline_ticks);
1325fcf3ce44SJohn Forte 		}
1326fcf3ce44SJohn Forte 
1327fcf3ce44SJohn Forte 	} else {
1328fcf3ce44SJohn Forte 		/*
1329fcf3ce44SJohn Forte 		 * Port is online.
1330fcf3ce44SJohn Forte 		 * Cancel offline timeout thread and resume command processing.
1331fcf3ce44SJohn Forte 		 */
1332fcf3ce44SJohn Forte 		if (fcsm->sm_offline_tid) {
1333fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1334fcf3ce44SJohn Forte 			    "statec_cb: cancel offline timeout thread"));
1335fcf3ce44SJohn Forte 			offline_tid = fcsm->sm_offline_tid;
1336fcf3ce44SJohn Forte 			fcsm->sm_offline_tid = (timeout_id_t)NULL;
1337fcf3ce44SJohn Forte 		}
1338fcf3ce44SJohn Forte 
1339fcf3ce44SJohn Forte 		fcsm->sm_flags &= ~FCSM_CMD_RETRY_Q_SUSPENDED;
1340fcf3ce44SJohn Forte 		/* Start retry thread if needed */
1341fcf3ce44SJohn Forte 		if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) {
1342fcf3ce44SJohn Forte 			fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
1343fcf3ce44SJohn Forte 			    (caddr_t)fcsm, fcsm_retry_ticks);
1344fcf3ce44SJohn Forte 		}
1345fcf3ce44SJohn Forte 	}
1346fcf3ce44SJohn Forte 
1347fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
1348fcf3ce44SJohn Forte 
1349fcf3ce44SJohn Forte 	if (offline_tid != NULL) {
1350fcf3ce44SJohn Forte 		(void) untimeout(offline_tid);
1351fcf3ce44SJohn Forte 	}
1352fcf3ce44SJohn Forte 
1353fcf3ce44SJohn Forte 	if (retry_tid != NULL) {
1354fcf3ce44SJohn Forte 		(void) untimeout(retry_tid);
1355fcf3ce44SJohn Forte 	}
1356fcf3ce44SJohn Forte 
1357fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
1358fcf3ce44SJohn Forte 	fcsm->sm_cb_count--;
1359fcf3ce44SJohn Forte 	ASSERT(fcsm->sm_cb_count >= 0);
1360fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
1361fcf3ce44SJohn Forte }
1362fcf3ce44SJohn Forte 
1363fcf3ce44SJohn Forte 
1364fcf3ce44SJohn Forte static void
fcsm_offline_timeout(void * handle)1365fcf3ce44SJohn Forte fcsm_offline_timeout(void *handle)
1366fcf3ce44SJohn Forte {
1367fcf3ce44SJohn Forte 	fcsm_t	*fcsm = (fcsm_t *)handle;
1368fcf3ce44SJohn Forte 
1369fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1370fcf3ce44SJohn Forte 	    "offline_timeout"));
1371fcf3ce44SJohn Forte 
1372fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
1373fcf3ce44SJohn Forte 	if (fcsm->sm_flags & FCSM_PORT_OFFLINE) {
1374fcf3ce44SJohn Forte 		fcsm->sm_flags |= FCSM_LINK_DOWN;
1375fcf3ce44SJohn Forte 	}
1376fcf3ce44SJohn Forte 	fcsm->sm_offline_tid = (timeout_id_t)NULL;
1377fcf3ce44SJohn Forte 	fcsm->sm_flags &= ~FCSM_CMD_RETRY_Q_SUSPENDED;
1378fcf3ce44SJohn Forte 
1379fcf3ce44SJohn Forte 	/* Start the retry thread if needed */
1380fcf3ce44SJohn Forte 	if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) {
1381fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1382fcf3ce44SJohn Forte 		    "offline_timeout: reschedule cmd retry thread"));
1383fcf3ce44SJohn Forte 		ASSERT(fcsm->sm_retry_tid == NULL);
1384fcf3ce44SJohn Forte 		fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
1385fcf3ce44SJohn Forte 		    (caddr_t)fcsm, fcsm_retry_ticks);
1386fcf3ce44SJohn Forte 	}
1387fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
1388fcf3ce44SJohn Forte }
1389fcf3ce44SJohn Forte 
1390fcf3ce44SJohn Forte /* ARGSUSED */
1391fcf3ce44SJohn Forte static int
fcsm_els_cb(opaque_t ulph,opaque_t port_handle,fc_unsol_buf_t * buf,uint32_t claimed)1392fcf3ce44SJohn Forte fcsm_els_cb(opaque_t ulph, opaque_t port_handle, fc_unsol_buf_t *buf,
1393fcf3ce44SJohn Forte     uint32_t claimed)
1394fcf3ce44SJohn Forte {
1395fcf3ce44SJohn Forte 	return (FC_UNCLAIMED);
1396fcf3ce44SJohn Forte }
1397fcf3ce44SJohn Forte 
1398fcf3ce44SJohn Forte 
1399fcf3ce44SJohn Forte /* ARGSUSED */
1400fcf3ce44SJohn Forte static int
fcsm_data_cb(opaque_t ulph,opaque_t port_handle,fc_unsol_buf_t * buf,uint32_t claimed)1401fcf3ce44SJohn Forte fcsm_data_cb(opaque_t ulph, opaque_t port_handle, fc_unsol_buf_t *buf,
1402fcf3ce44SJohn Forte     uint32_t claimed)
1403fcf3ce44SJohn Forte {
1404fcf3ce44SJohn Forte 	return (FC_UNCLAIMED);
1405fcf3ce44SJohn Forte }
1406fcf3ce44SJohn Forte 
1407fcf3ce44SJohn Forte 
1408fcf3ce44SJohn Forte /* ARGSUSED */
1409fcf3ce44SJohn Forte static int
fcsm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rval_p)1410fcf3ce44SJohn Forte fcsm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1411fcf3ce44SJohn Forte     int *rval_p)
1412fcf3ce44SJohn Forte {
1413fcf3ce44SJohn Forte 	int retval = 0;
1414fcf3ce44SJohn Forte 
1415fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "ioctl: start"));
1416fcf3ce44SJohn Forte 
1417fcf3ce44SJohn Forte 	mutex_enter(&fcsm_global_mutex);
1418fcf3ce44SJohn Forte 	if (!(fcsm_flag & FCSM_OPEN)) {
1419fcf3ce44SJohn Forte 		mutex_exit(&fcsm_global_mutex);
1420fcf3ce44SJohn Forte 		return (ENXIO);
1421fcf3ce44SJohn Forte 	}
1422fcf3ce44SJohn Forte 	mutex_exit(&fcsm_global_mutex);
1423fcf3ce44SJohn Forte 
1424fcf3ce44SJohn Forte 	/* Allow only root to talk */
1425fcf3ce44SJohn Forte 	if (drv_priv(credp)) {
1426fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1427fcf3ce44SJohn Forte 		    "ioctl: end (disallowing underprivileged user)"));
1428fcf3ce44SJohn Forte 		return (EPERM);
1429fcf3ce44SJohn Forte 	}
1430fcf3ce44SJohn Forte 
1431fcf3ce44SJohn Forte 	switch (cmd) {
1432fcf3ce44SJohn Forte 
1433fcf3ce44SJohn Forte 	case FCSMIO_CMD: {
1434fcf3ce44SJohn Forte 		fcio_t	fcio;
1435fcf3ce44SJohn Forte 		int	status;
1436fcf3ce44SJohn Forte #ifdef	_MULTI_DATAMODEL
1437fcf3ce44SJohn Forte 		switch (ddi_model_convert_from(mode & FMODELS)) {
1438fcf3ce44SJohn Forte 		case DDI_MODEL_ILP32: {
1439fcf3ce44SJohn Forte 			struct fcio32 fcio32;
1440fcf3ce44SJohn Forte 
1441fcf3ce44SJohn Forte 			if (status = ddi_copyin((void *)arg, (void *)&fcio32,
1442fcf3ce44SJohn Forte 			    sizeof (struct fcio32), mode)) {
1443fcf3ce44SJohn Forte 				retval = EFAULT;
1444fcf3ce44SJohn Forte 				break;
1445fcf3ce44SJohn Forte 			}
1446fcf3ce44SJohn Forte 			fcio.fcio_xfer = fcio32.fcio_xfer;
1447fcf3ce44SJohn Forte 			fcio.fcio_cmd = fcio32.fcio_cmd;
1448fcf3ce44SJohn Forte 			fcio.fcio_flags = fcio32.fcio_flags;
1449fcf3ce44SJohn Forte 			fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags;
1450fcf3ce44SJohn Forte 			fcio.fcio_ilen = (size_t)fcio32.fcio_ilen;
1451fcf3ce44SJohn Forte 			fcio.fcio_ibuf = (caddr_t)(long)fcio32.fcio_ibuf;
1452fcf3ce44SJohn Forte 			fcio.fcio_olen = (size_t)fcio32.fcio_olen;
1453fcf3ce44SJohn Forte 			fcio.fcio_obuf = (caddr_t)(long)fcio32.fcio_obuf;
1454fcf3ce44SJohn Forte 			fcio.fcio_alen = (size_t)fcio32.fcio_alen;
1455fcf3ce44SJohn Forte 			fcio.fcio_abuf = (caddr_t)(long)fcio32.fcio_abuf;
1456fcf3ce44SJohn Forte 			fcio.fcio_errno = fcio32.fcio_errno;
1457fcf3ce44SJohn Forte 			break;
1458fcf3ce44SJohn Forte 		}
1459fcf3ce44SJohn Forte 
1460fcf3ce44SJohn Forte 		case DDI_MODEL_NONE:
1461fcf3ce44SJohn Forte 			if (status = ddi_copyin((void *)arg, (void *)&fcio,
1462fcf3ce44SJohn Forte 			    sizeof (fcio_t), mode)) {
1463fcf3ce44SJohn Forte 				retval = EFAULT;
1464fcf3ce44SJohn Forte 			}
1465fcf3ce44SJohn Forte 			break;
1466fcf3ce44SJohn Forte 		}
1467fcf3ce44SJohn Forte #else	/* _MULTI_DATAMODEL */
1468fcf3ce44SJohn Forte 		if (status = ddi_copyin((void *)arg, (void *)&fcio,
1469fcf3ce44SJohn Forte 		    sizeof (fcio_t), mode)) {
1470fcf3ce44SJohn Forte 			retval = EFAULT;
1471fcf3ce44SJohn Forte 			break;
1472fcf3ce44SJohn Forte 		}
1473fcf3ce44SJohn Forte #endif	/* _MULTI_DATAMODEL */
1474fcf3ce44SJohn Forte 		if (!status) {
1475fcf3ce44SJohn Forte 			retval = fcsm_fciocmd(arg, mode, credp, &fcio);
1476fcf3ce44SJohn Forte 		}
1477fcf3ce44SJohn Forte 		break;
1478fcf3ce44SJohn Forte 	}
1479fcf3ce44SJohn Forte 
1480fcf3ce44SJohn Forte 	default:
1481fcf3ce44SJohn Forte 		retval = ENOTTY;
1482fcf3ce44SJohn Forte 		break;
1483fcf3ce44SJohn Forte 	}
1484fcf3ce44SJohn Forte 
1485fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "ioctl: end"));
1486fcf3ce44SJohn Forte 	return (retval);
1487fcf3ce44SJohn Forte }
1488fcf3ce44SJohn Forte 
1489fcf3ce44SJohn Forte /* ARGSUSED */
1490fcf3ce44SJohn Forte 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)1491fcf3ce44SJohn Forte fcsm_port_ioctl(opaque_t ulph, opaque_t port_handle, dev_t dev, int cmd,
1492fcf3ce44SJohn Forte     intptr_t arg, int mode, cred_t *credp, int *rval, uint32_t claimed)
1493fcf3ce44SJohn Forte {
1494fcf3ce44SJohn Forte 	return (FC_UNCLAIMED);
1495fcf3ce44SJohn Forte }
1496fcf3ce44SJohn Forte 
1497fcf3ce44SJohn Forte 
1498fcf3ce44SJohn Forte /* ARGSUSED */
1499fcf3ce44SJohn Forte static int
fcsm_fciocmd(intptr_t arg,int mode,cred_t * credp,fcio_t * fcio)1500fcf3ce44SJohn Forte fcsm_fciocmd(intptr_t arg, int mode, cred_t *credp, fcio_t *fcio)
1501fcf3ce44SJohn Forte {
1502fcf3ce44SJohn Forte 	int  retval = 0;
1503fcf3ce44SJohn Forte 
1504fcf3ce44SJohn Forte 	switch (fcio->fcio_cmd) {
1505fcf3ce44SJohn Forte 	case  FCSMIO_CT_CMD: {
1506fcf3ce44SJohn Forte 		fcsm_t		*fcsm;
1507fcf3ce44SJohn Forte 		caddr_t		user_ibuf, user_obuf;
1508fcf3ce44SJohn Forte 		caddr_t		req_iu, rsp_iu, abuf;
1509fcf3ce44SJohn Forte 		int		status, instance, count;
1510fcf3ce44SJohn Forte 
1511fcf3ce44SJohn Forte 		if ((fcio->fcio_xfer != FCIO_XFER_RW) ||
1512fcf3ce44SJohn Forte 		    (fcio->fcio_ilen == 0) || (fcio->fcio_ibuf == 0) ||
1513fcf3ce44SJohn Forte 		    (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0) ||
1514fcf3ce44SJohn Forte 		    (fcio->fcio_alen == 0) || (fcio->fcio_abuf == 0) ||
1515fcf3ce44SJohn Forte 		    (fcio->fcio_flags != 0) || (fcio->fcio_cmd_flags != 0) ||
1516fcf3ce44SJohn Forte 		    (fcio->fcio_ilen > FCSM_MAX_CT_SIZE) ||
1517fcf3ce44SJohn Forte 		    (fcio->fcio_olen > FCSM_MAX_CT_SIZE) ||
1518fcf3ce44SJohn Forte 		    (fcio->fcio_alen > MAXPATHLEN)) {
1519fcf3ce44SJohn Forte 			retval = EINVAL;
1520fcf3ce44SJohn Forte 			break;
1521fcf3ce44SJohn Forte 		}
1522fcf3ce44SJohn Forte 
1523fcf3ce44SJohn Forte 		/*
1524fcf3ce44SJohn Forte 		 * Get the destination port for which this ioctl
1525fcf3ce44SJohn Forte 		 * is targeted. The abuf will have the fp_minor
1526fcf3ce44SJohn Forte 		 * number.
1527fcf3ce44SJohn Forte 		 */
1528fcf3ce44SJohn Forte 		abuf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP);
1529fcf3ce44SJohn Forte 		ASSERT(abuf != NULL);
1530fcf3ce44SJohn Forte 		if (ddi_copyin(fcio->fcio_abuf, abuf, fcio->fcio_alen, mode)) {
1531fcf3ce44SJohn Forte 			retval = EFAULT;
1532fcf3ce44SJohn Forte 			kmem_free(abuf, fcio->fcio_alen);
1533fcf3ce44SJohn Forte 			break;
1534fcf3ce44SJohn Forte 		}
1535fcf3ce44SJohn Forte 
1536fcf3ce44SJohn Forte 		instance = *((int *)abuf);
1537fcf3ce44SJohn Forte 		kmem_free(abuf, fcio->fcio_alen);
1538fcf3ce44SJohn Forte 
1539fcf3ce44SJohn Forte 		if (instance < 0) {
1540fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
1541fcf3ce44SJohn Forte 			    "fciocmd: instance 0x%x, invalid instance",
1542fcf3ce44SJohn Forte 			    instance));
1543fcf3ce44SJohn Forte 			retval = ENXIO;
1544fcf3ce44SJohn Forte 			break;
1545fcf3ce44SJohn Forte 		}
1546fcf3ce44SJohn Forte 
1547fcf3ce44SJohn Forte 		/*
1548fcf3ce44SJohn Forte 		 * We confirmed that path corresponds to our port driver
1549fcf3ce44SJohn Forte 		 * and a valid instance.
1550fcf3ce44SJohn Forte 		 * If this port instance is not yet attached, then wait
1551fcf3ce44SJohn Forte 		 * for a finite time for attach to complete
1552fcf3ce44SJohn Forte 		 */
1553fcf3ce44SJohn Forte 		fcsm = ddi_get_soft_state(fcsm_state, instance);
1554fcf3ce44SJohn Forte 		count = 0;
1555fcf3ce44SJohn Forte 		while (count++ <= 30) {
1556fcf3ce44SJohn Forte 			if (fcsm != NULL) {
1557fcf3ce44SJohn Forte 				mutex_enter(&fcsm->sm_mutex);
1558fcf3ce44SJohn Forte 				if (fcsm->sm_flags & FCSM_ATTACHED) {
1559fcf3ce44SJohn Forte 					mutex_exit(&fcsm->sm_mutex);
1560fcf3ce44SJohn Forte 					break;
1561fcf3ce44SJohn Forte 				}
1562fcf3ce44SJohn Forte 				mutex_exit(&fcsm->sm_mutex);
1563fcf3ce44SJohn Forte 			}
1564fcf3ce44SJohn Forte 			if (count == 1) {
1565fcf3ce44SJohn Forte 				FCSM_DEBUG(SMDL_TRACE,
1566fcf3ce44SJohn Forte 				    (CE_WARN, SM_LOG, NULL, NULL,
1567fcf3ce44SJohn Forte 				    "fciocmd: instance 0x%x, "
1568fcf3ce44SJohn Forte 				    "wait for port attach", instance));
1569fcf3ce44SJohn Forte 			}
1570fcf3ce44SJohn Forte 			delay(drv_usectohz(1000000));
1571fcf3ce44SJohn Forte 			fcsm = ddi_get_soft_state(fcsm_state, instance);
1572fcf3ce44SJohn Forte 		}
1573fcf3ce44SJohn Forte 		if (count > 30) {
1574fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
1575fcf3ce44SJohn Forte 			    "fciocmd: instance 0x%x, port not attached",
1576fcf3ce44SJohn Forte 			    instance));
1577fcf3ce44SJohn Forte 			retval = ENXIO;
1578fcf3ce44SJohn Forte 			break;
1579fcf3ce44SJohn Forte 		}
1580fcf3ce44SJohn Forte 
1581fcf3ce44SJohn Forte 		req_iu = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
1582fcf3ce44SJohn Forte 		rsp_iu = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
1583fcf3ce44SJohn Forte 		ASSERT((req_iu != NULL) && (rsp_iu != NULL));
1584fcf3ce44SJohn Forte 
1585fcf3ce44SJohn Forte 		if (ddi_copyin(fcio->fcio_ibuf, req_iu,
1586fcf3ce44SJohn Forte 		    fcio->fcio_ilen, mode)) {
1587fcf3ce44SJohn Forte 			retval = EFAULT;
1588fcf3ce44SJohn Forte 			kmem_free(req_iu, fcio->fcio_ilen);
1589fcf3ce44SJohn Forte 			kmem_free(rsp_iu, fcio->fcio_olen);
1590fcf3ce44SJohn Forte 			break;
1591fcf3ce44SJohn Forte 		}
1592fcf3ce44SJohn Forte 
1593fcf3ce44SJohn Forte 		user_ibuf = fcio->fcio_ibuf;
1594fcf3ce44SJohn Forte 		user_obuf = fcio->fcio_obuf;
1595fcf3ce44SJohn Forte 		fcio->fcio_ibuf = req_iu;
1596fcf3ce44SJohn Forte 		fcio->fcio_obuf = rsp_iu;
1597fcf3ce44SJohn Forte 
1598fcf3ce44SJohn Forte 		status = fcsm_ct_passthru(fcsm->sm_instance, fcio, KM_SLEEP,
1599fcf3ce44SJohn Forte 		    FCSM_JOBFLAG_SYNC, NULL);
1600fcf3ce44SJohn Forte 		if (status != FC_SUCCESS) {
1601fcf3ce44SJohn Forte 			retval = EIO;
1602fcf3ce44SJohn Forte 		}
1603fcf3ce44SJohn Forte 
1604fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1605fcf3ce44SJohn Forte 		    "fciocmd: cmd 0x%x completion status 0x%x",
1606fcf3ce44SJohn Forte 		    fcio->fcio_cmd, status));
1607fcf3ce44SJohn Forte 		fcio->fcio_errno = status;
1608fcf3ce44SJohn Forte 		fcio->fcio_ibuf = user_ibuf;
1609fcf3ce44SJohn Forte 		fcio->fcio_obuf = user_obuf;
1610fcf3ce44SJohn Forte 
1611fcf3ce44SJohn Forte 		if (ddi_copyout(rsp_iu, fcio->fcio_obuf,
1612fcf3ce44SJohn Forte 		    fcio->fcio_olen, mode)) {
1613fcf3ce44SJohn Forte 			retval = EFAULT;
1614fcf3ce44SJohn Forte 			kmem_free(req_iu, fcio->fcio_ilen);
1615fcf3ce44SJohn Forte 			kmem_free(rsp_iu, fcio->fcio_olen);
1616fcf3ce44SJohn Forte 			break;
1617fcf3ce44SJohn Forte 		}
1618fcf3ce44SJohn Forte 
1619fcf3ce44SJohn Forte 		kmem_free(req_iu, fcio->fcio_ilen);
1620fcf3ce44SJohn Forte 		kmem_free(rsp_iu, fcio->fcio_olen);
1621fcf3ce44SJohn Forte 
1622fcf3ce44SJohn Forte 		if (fcsm_fcio_copyout(fcio, arg, mode)) {
1623fcf3ce44SJohn Forte 			retval = EFAULT;
1624fcf3ce44SJohn Forte 		}
1625fcf3ce44SJohn Forte 		break;
1626fcf3ce44SJohn Forte 	}
1627fcf3ce44SJohn Forte 
1628fcf3ce44SJohn Forte 	case  FCSMIO_ADAPTER_LIST: {
162940b706cfSMilan Jurik 		fc_hba_list_t	*list;
16307ff83669SZhong Wang 		int			count;
1631fcf3ce44SJohn Forte 
163240b706cfSMilan Jurik 		if ((fcio->fcio_xfer != FCIO_XFER_RW) ||
1633fcf3ce44SJohn Forte 		    (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
163440b706cfSMilan Jurik 			retval = EINVAL;
163540b706cfSMilan Jurik 			break;
163640b706cfSMilan Jurik 		}
1637fcf3ce44SJohn Forte 
163840b706cfSMilan Jurik 		list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
1639fcf3ce44SJohn Forte 
164040b706cfSMilan Jurik 		if (ddi_copyin(fcio->fcio_obuf, list, fcio->fcio_olen, mode)) {
164140b706cfSMilan Jurik 			retval = EFAULT;
164240b706cfSMilan Jurik 			break;
164340b706cfSMilan Jurik 		}
164440b706cfSMilan Jurik 		list->version = FC_HBA_LIST_VERSION;
1645fcf3ce44SJohn Forte 
164640b706cfSMilan Jurik 		if (fcio->fcio_olen < MAXPATHLEN * list->numAdapters) {
164740b706cfSMilan Jurik 			retval = EFAULT;
164840b706cfSMilan Jurik 			break;
164940b706cfSMilan Jurik 		}
1650fcf3ce44SJohn Forte 
165140b706cfSMilan Jurik 		count = fc_ulp_get_adapter_paths((char *)list->hbaPaths,
165240b706cfSMilan Jurik 		    list->numAdapters);
16537ff83669SZhong Wang 		if (count < 0) {
16547ff83669SZhong Wang 			/* Did something go wrong? */
165540b706cfSMilan Jurik 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
165640b706cfSMilan Jurik 			    "Error fetching adapter list."));
165740b706cfSMilan Jurik 			retval = ENXIO;
165840b706cfSMilan Jurik 			kmem_free(list, fcio->fcio_olen);
165940b706cfSMilan Jurik 			break;
166040b706cfSMilan Jurik 		}
166140b706cfSMilan Jurik 		/* Sucess (or short buffer) */
166240b706cfSMilan Jurik 		list->numAdapters = count;
166340b706cfSMilan Jurik 		if (ddi_copyout(list, fcio->fcio_obuf,
166440b706cfSMilan Jurik 		    fcio->fcio_olen, mode)) {
166540b706cfSMilan Jurik 			retval = EFAULT;
166640b706cfSMilan Jurik 		}
1667fcf3ce44SJohn Forte 		kmem_free(list, fcio->fcio_olen);
1668fcf3ce44SJohn Forte 		break;
1669fcf3ce44SJohn Forte 	}
1670fcf3ce44SJohn Forte 
1671fcf3ce44SJohn Forte 	default:
1672fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, NULL, NULL,
1673fcf3ce44SJohn Forte 		    "fciocmd: unknown cmd <0x%x>", fcio->fcio_cmd));
1674fcf3ce44SJohn Forte 		retval = ENOTTY;
1675fcf3ce44SJohn Forte 		break;
1676fcf3ce44SJohn Forte 	}
1677fcf3ce44SJohn Forte 
1678fcf3ce44SJohn Forte 	return (retval);
1679fcf3ce44SJohn Forte }
1680fcf3ce44SJohn Forte 
1681fcf3ce44SJohn Forte static int
fcsm_fcio_copyout(fcio_t * fcio,intptr_t arg,int mode)1682fcf3ce44SJohn Forte fcsm_fcio_copyout(fcio_t *fcio, intptr_t arg, int mode)
1683fcf3ce44SJohn Forte {
1684fcf3ce44SJohn Forte 	int status;
1685fcf3ce44SJohn Forte 
1686fcf3ce44SJohn Forte #ifdef	_MULTI_DATAMODEL
1687fcf3ce44SJohn Forte 	switch (ddi_model_convert_from(mode & FMODELS)) {
1688fcf3ce44SJohn Forte 	case DDI_MODEL_ILP32: {
1689fcf3ce44SJohn Forte 		struct fcio32 fcio32;
1690fcf3ce44SJohn Forte 
1691fcf3ce44SJohn Forte 		fcio32.fcio_xfer = fcio->fcio_xfer;
1692fcf3ce44SJohn Forte 		fcio32.fcio_cmd = fcio->fcio_cmd;
1693fcf3ce44SJohn Forte 		fcio32.fcio_flags = fcio->fcio_flags;
1694fcf3ce44SJohn Forte 		fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags;
1695fcf3ce44SJohn Forte 		fcio32.fcio_ilen = fcio->fcio_ilen;
1696fcf3ce44SJohn Forte 		fcio32.fcio_ibuf = (caddr32_t)(long)fcio->fcio_ibuf;
1697fcf3ce44SJohn Forte 		fcio32.fcio_olen = fcio->fcio_olen;
1698fcf3ce44SJohn Forte 		fcio32.fcio_obuf = (caddr32_t)(long)fcio->fcio_obuf;
1699fcf3ce44SJohn Forte 		fcio32.fcio_alen = fcio->fcio_alen;
1700fcf3ce44SJohn Forte 		fcio32.fcio_abuf = (caddr32_t)(long)fcio->fcio_abuf;
1701fcf3ce44SJohn Forte 		fcio32.fcio_errno = fcio->fcio_errno;
1702fcf3ce44SJohn Forte 
1703fcf3ce44SJohn Forte 		status = ddi_copyout((void *)&fcio32, (void *)arg,
1704fcf3ce44SJohn Forte 		    sizeof (struct fcio32), mode);
1705fcf3ce44SJohn Forte 		break;
1706fcf3ce44SJohn Forte 	}
1707fcf3ce44SJohn Forte 	case DDI_MODEL_NONE:
1708fcf3ce44SJohn Forte 		status = ddi_copyout((void *)fcio, (void *)arg,
1709fcf3ce44SJohn Forte 		    sizeof (fcio_t), mode);
1710fcf3ce44SJohn Forte 		break;
1711fcf3ce44SJohn Forte 	}
1712fcf3ce44SJohn Forte #else	/* _MULTI_DATAMODEL */
1713fcf3ce44SJohn Forte 	status = ddi_copyout((void *)fcio, (void *)arg, sizeof (fcio_t), mode);
1714fcf3ce44SJohn Forte #endif	/* _MULTI_DATAMODEL */
1715fcf3ce44SJohn Forte 
1716fcf3ce44SJohn Forte 	return (status);
1717fcf3ce44SJohn Forte }
1718fcf3ce44SJohn Forte 
1719fcf3ce44SJohn Forte 
1720fcf3ce44SJohn Forte /* ARGSUSED */
1721fcf3ce44SJohn Forte static int
fcsm_open(dev_t * devp,int flags,int otyp,cred_t * credp)1722fcf3ce44SJohn Forte fcsm_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1723fcf3ce44SJohn Forte {
1724fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "open"));
1725fcf3ce44SJohn Forte 
1726fcf3ce44SJohn Forte 	if (otyp != OTYP_CHR) {
1727fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1728fcf3ce44SJohn Forte 		    "fcsm_open: failed. open type 0x%x for minor 0x%x is not "
1729fcf3ce44SJohn Forte 		    "OTYP_CHR", otyp, getminor(*devp)));
1730fcf3ce44SJohn Forte 		return (EINVAL);
1731fcf3ce44SJohn Forte 	}
1732fcf3ce44SJohn Forte 
1733fcf3ce44SJohn Forte 	/*
1734fcf3ce44SJohn Forte 	 * Allow anybody to open (both root and non-root users).
1735fcf3ce44SJohn Forte 	 * Previlege level checks are made on the per ioctl basis.
1736fcf3ce44SJohn Forte 	 */
1737fcf3ce44SJohn Forte 	mutex_enter(&fcsm_global_mutex);
1738fcf3ce44SJohn Forte 	if (flags & FEXCL) {
1739fcf3ce44SJohn Forte 		if (fcsm_flag & FCSM_OPEN) {
1740fcf3ce44SJohn Forte 			mutex_exit(&fcsm_global_mutex);
1741fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1742fcf3ce44SJohn Forte 			    "fcsm_open: exclusive open of 0x%x failed",
1743fcf3ce44SJohn Forte 			    getminor(*devp)));
1744fcf3ce44SJohn Forte 			return (EBUSY);
1745fcf3ce44SJohn Forte 		} else {
1746fcf3ce44SJohn Forte 			ASSERT(fcsm_flag == FCSM_IDLE);
1747fcf3ce44SJohn Forte 			fcsm_flag |= FCSM_EXCL;
1748fcf3ce44SJohn Forte 		}
1749fcf3ce44SJohn Forte 	} else {
1750fcf3ce44SJohn Forte 		if (fcsm_flag & FCSM_EXCL) {
1751fcf3ce44SJohn Forte 			mutex_exit(&fcsm_global_mutex);
1752fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1753fcf3ce44SJohn Forte 			    "fcsm_open: failed. Device minor 0x%x is in "
1754fcf3ce44SJohn Forte 			    "exclusive open mode", getminor(*devp)));
1755fcf3ce44SJohn Forte 			return (EBUSY);
1756fcf3ce44SJohn Forte 		}
1757fcf3ce44SJohn Forte 
1758fcf3ce44SJohn Forte 	}
1759fcf3ce44SJohn Forte 	fcsm_flag |= FCSM_OPEN;
1760fcf3ce44SJohn Forte 	mutex_exit(&fcsm_global_mutex);
1761fcf3ce44SJohn Forte 	return (0);
1762fcf3ce44SJohn Forte }
1763fcf3ce44SJohn Forte 
1764fcf3ce44SJohn Forte 
1765fcf3ce44SJohn Forte /* ARGSUSED */
1766fcf3ce44SJohn Forte static int
fcsm_close(dev_t dev,int flag,int otyp,cred_t * credp)1767fcf3ce44SJohn Forte fcsm_close(dev_t dev, int flag, int otyp, cred_t *credp)
1768fcf3ce44SJohn Forte {
1769fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "close"));
1770fcf3ce44SJohn Forte 
1771fcf3ce44SJohn Forte 	if (otyp != OTYP_CHR) {
1772fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1773fcf3ce44SJohn Forte 		    "fcsm_close: failed. close type 0x%x for minor 0x%x is not "
1774fcf3ce44SJohn Forte 		    "OTYP_CHR", otyp, getminor(dev)));
1775fcf3ce44SJohn Forte 		return (EINVAL);
1776fcf3ce44SJohn Forte 	}
1777fcf3ce44SJohn Forte 
1778fcf3ce44SJohn Forte 	mutex_enter(&fcsm_global_mutex);
1779fcf3ce44SJohn Forte 	if ((fcsm_flag & FCSM_OPEN) == 0) {
1780fcf3ce44SJohn Forte 		mutex_exit(&fcsm_global_mutex);
1781fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1782fcf3ce44SJohn Forte 		    "fcsm_close: failed. minor 0x%x is already closed",
1783fcf3ce44SJohn Forte 		    getminor(dev)));
1784fcf3ce44SJohn Forte 		return (ENODEV);
1785fcf3ce44SJohn Forte 	}
1786fcf3ce44SJohn Forte 	fcsm_flag = FCSM_IDLE;
1787fcf3ce44SJohn Forte 	mutex_exit(&fcsm_global_mutex);
1788fcf3ce44SJohn Forte 	return (0);
1789fcf3ce44SJohn Forte }
1790fcf3ce44SJohn Forte 
1791fcf3ce44SJohn Forte 
1792fcf3ce44SJohn Forte /* ARGSUSED */
1793fcf3ce44SJohn Forte static void
fcsm_disp_devlist(fcsm_t * fcsm,fc_portmap_t * devlist,uint32_t dev_cnt)1794fcf3ce44SJohn Forte fcsm_disp_devlist(fcsm_t *fcsm, fc_portmap_t *devlist, uint32_t dev_cnt)
1795fcf3ce44SJohn Forte {
1796fcf3ce44SJohn Forte 	fc_portmap_t	*map;
1797fcf3ce44SJohn Forte 	uint32_t	i;
1798fcf3ce44SJohn Forte 
1799fcf3ce44SJohn Forte 	if (dev_cnt == 0) {
1800fcf3ce44SJohn Forte 		return;
1801fcf3ce44SJohn Forte 	}
1802fcf3ce44SJohn Forte 
1803fcf3ce44SJohn Forte 	ASSERT(devlist != NULL);
1804fcf3ce44SJohn Forte 	for (i = 0; i < dev_cnt; i++) {
1805fcf3ce44SJohn Forte 		map = &devlist[i];
1806fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1807fcf3ce44SJohn Forte 		    "list[%d]: ID 0x%x WWN %x:%x:%x:%x:%x:%x:%x:%x "
1808fcf3ce44SJohn Forte 		    "state (0x%x) "
1809fcf3ce44SJohn Forte 		    "type <%s>(0x%x) "
1810fcf3ce44SJohn Forte 		    "flags (0x%x)",
1811fcf3ce44SJohn Forte 		    i, map->map_did.port_id,
1812fcf3ce44SJohn Forte 		    map->map_pwwn.raw_wwn[0], map->map_pwwn.raw_wwn[1],
1813fcf3ce44SJohn Forte 		    map->map_pwwn.raw_wwn[2], map->map_pwwn.raw_wwn[3],
1814fcf3ce44SJohn Forte 		    map->map_pwwn.raw_wwn[4], map->map_pwwn.raw_wwn[5],
1815fcf3ce44SJohn Forte 		    map->map_pwwn.raw_wwn[6], map->map_pwwn.raw_wwn[7],
1816fcf3ce44SJohn Forte 		    map->map_state,
1817fcf3ce44SJohn Forte 		    fcsm_dev_type_to_str(map->map_type), map->map_type,
1818fcf3ce44SJohn Forte 		    map->map_flags));
1819fcf3ce44SJohn Forte 	}
1820fcf3ce44SJohn Forte }
1821fcf3ce44SJohn Forte 
1822fcf3ce44SJohn Forte /* ARGSUSED */
1823fcf3ce44SJohn Forte static void
fcsm_display(int level,int flags,fcsm_t * fcsm,fc_packet_t * pkt,const char * fmt,...)1824fcf3ce44SJohn Forte fcsm_display(int level, int flags, fcsm_t *fcsm, fc_packet_t *pkt,
1825fcf3ce44SJohn Forte     const char *fmt, ...)
1826fcf3ce44SJohn Forte {
1827fcf3ce44SJohn Forte 	caddr_t	buf;
1828fcf3ce44SJohn Forte 	va_list	ap;
1829fcf3ce44SJohn Forte 
1830fcf3ce44SJohn Forte 	buf = kmem_zalloc(256, KM_NOSLEEP);
1831fcf3ce44SJohn Forte 	if (buf == NULL) {
1832fcf3ce44SJohn Forte 		return;
1833fcf3ce44SJohn Forte 	}
1834fcf3ce44SJohn Forte 
1835fcf3ce44SJohn Forte 	if (fcsm) {
1836fcf3ce44SJohn Forte 		(void) sprintf(buf + strlen(buf), "fcsm(%d): ",
1837fcf3ce44SJohn Forte 		    ddi_get_instance(fcsm->sm_port_info.port_dip));
1838fcf3ce44SJohn Forte 	} else {
1839fcf3ce44SJohn Forte 		(void) sprintf(buf, "fcsm: ");
1840fcf3ce44SJohn Forte 	}
1841fcf3ce44SJohn Forte 
1842fcf3ce44SJohn Forte 	va_start(ap, fmt);
1843fcf3ce44SJohn Forte 	(void) vsprintf(buf + strlen(buf), fmt, ap);
1844fcf3ce44SJohn Forte 	va_end(ap);
1845fcf3ce44SJohn Forte 
1846fcf3ce44SJohn Forte 	if (pkt) {
1847fcf3ce44SJohn Forte 		caddr_t state, reason, action, expln;
1848fcf3ce44SJohn Forte 
1849fcf3ce44SJohn Forte 		(void) fc_ulp_pkt_error(pkt, &state, &reason, &action, &expln);
1850fcf3ce44SJohn Forte 
1851fcf3ce44SJohn Forte 		(void) sprintf(buf + strlen(buf),
1852fcf3ce44SJohn Forte 		    " state: %s(0x%x); reason: %s(0x%x)",
1853fcf3ce44SJohn Forte 		    state, pkt->pkt_state, reason, pkt->pkt_reason);
1854fcf3ce44SJohn Forte 	}
1855fcf3ce44SJohn Forte 
1856fcf3ce44SJohn Forte 	switch (flags) {
18577ff83669SZhong Wang 	case SM_LOG:
18587ff83669SZhong Wang 		cmn_err(level, "!%s", buf);
18597ff83669SZhong Wang 		break;
1860fcf3ce44SJohn Forte 
18617ff83669SZhong Wang 	case SM_CONSOLE:
18627ff83669SZhong Wang 		cmn_err(level, "^%s", buf);
18637ff83669SZhong Wang 		break;
1864fcf3ce44SJohn Forte 
18657ff83669SZhong Wang 	default:
18667ff83669SZhong Wang 		cmn_err(level, "%s", buf);
18677ff83669SZhong Wang 		break;
1868fcf3ce44SJohn Forte 	}
1869fcf3ce44SJohn Forte 
1870fcf3ce44SJohn Forte 	kmem_free(buf, 256);
1871fcf3ce44SJohn Forte }
1872fcf3ce44SJohn Forte 
1873fcf3ce44SJohn Forte 
1874fcf3ce44SJohn Forte /*
1875fcf3ce44SJohn Forte  * Convert FC packet state to FC errno
1876fcf3ce44SJohn Forte  */
1877fcf3ce44SJohn Forte int
fcsm_pkt_state_to_rval(uchar_t state,uint32_t reason)1878fcf3ce44SJohn Forte fcsm_pkt_state_to_rval(uchar_t state, uint32_t reason)
1879fcf3ce44SJohn Forte {
1880fcf3ce44SJohn Forte 	int count;
1881fcf3ce44SJohn Forte 
1882fcf3ce44SJohn Forte 	if (state == FC_PKT_LOCAL_RJT && (reason == FC_REASON_NO_CONNECTION ||
1883fcf3ce44SJohn Forte 	    reason == FC_REASON_LOGIN_REQUIRED)) {
1884fcf3ce44SJohn Forte 		return (FC_LOGINREQ);
1885fcf3ce44SJohn Forte 	} else if (state == FC_PKT_PORT_OFFLINE &&
1886fcf3ce44SJohn Forte 	    reason == FC_REASON_LOGIN_REQUIRED) {
1887fcf3ce44SJohn Forte 		return (FC_LOGINREQ);
1888fcf3ce44SJohn Forte 	}
1889fcf3ce44SJohn Forte 
1890fcf3ce44SJohn Forte 	for (count = 0; count < sizeof (fcsm_xlat_pkt_state) /
1891fcf3ce44SJohn Forte 	    sizeof (fcsm_xlat_pkt_state[0]); count++) {
1892fcf3ce44SJohn Forte 		if (fcsm_xlat_pkt_state[count].xlat_state == state) {
1893fcf3ce44SJohn Forte 			return (fcsm_xlat_pkt_state[count].xlat_rval);
1894fcf3ce44SJohn Forte 		}
1895fcf3ce44SJohn Forte 	}
1896fcf3ce44SJohn Forte 
1897fcf3ce44SJohn Forte 	return (FC_FAILURE);
1898fcf3ce44SJohn Forte }
1899fcf3ce44SJohn Forte 
1900fcf3ce44SJohn Forte 
1901fcf3ce44SJohn Forte /*
1902fcf3ce44SJohn Forte  * Convert port state state to descriptive string
1903fcf3ce44SJohn Forte  */
1904fcf3ce44SJohn Forte caddr_t
fcsm_port_state_to_str(uint32_t port_state)1905fcf3ce44SJohn Forte fcsm_port_state_to_str(uint32_t port_state)
1906fcf3ce44SJohn Forte {
1907fcf3ce44SJohn Forte 	int count;
1908fcf3ce44SJohn Forte 
1909fcf3ce44SJohn Forte 	for (count = 0; count < sizeof (fcsm_xlat_port_state) /
1910fcf3ce44SJohn Forte 	    sizeof (fcsm_xlat_port_state[0]); count++) {
1911fcf3ce44SJohn Forte 		if (fcsm_xlat_port_state[count].xlat_pstate == port_state) {
1912fcf3ce44SJohn Forte 			return (fcsm_xlat_port_state[count].xlat_state_str);
1913fcf3ce44SJohn Forte 		}
1914fcf3ce44SJohn Forte 	}
1915fcf3ce44SJohn Forte 
1916fcf3ce44SJohn Forte 	return (NULL);
1917fcf3ce44SJohn Forte }
1918fcf3ce44SJohn Forte 
1919fcf3ce44SJohn Forte 
1920fcf3ce44SJohn Forte /*
1921fcf3ce44SJohn Forte  * Convert port topology state to descriptive string
1922fcf3ce44SJohn Forte  */
1923fcf3ce44SJohn Forte caddr_t
fcsm_topology_to_str(uint32_t topology)1924fcf3ce44SJohn Forte fcsm_topology_to_str(uint32_t topology)
1925fcf3ce44SJohn Forte {
1926fcf3ce44SJohn Forte 	int count;
1927fcf3ce44SJohn Forte 
1928fcf3ce44SJohn Forte 	for (count = 0; count < sizeof (fcsm_xlat_topology) /
1929fcf3ce44SJohn Forte 	    sizeof (fcsm_xlat_topology[0]); count++) {
1930fcf3ce44SJohn Forte 		if (fcsm_xlat_topology[count].xlat_top == topology) {
1931fcf3ce44SJohn Forte 			return (fcsm_xlat_topology[count].xlat_top_str);
1932fcf3ce44SJohn Forte 		}
1933fcf3ce44SJohn Forte 	}
1934fcf3ce44SJohn Forte 
1935fcf3ce44SJohn Forte 	return (NULL);
1936fcf3ce44SJohn Forte }
1937fcf3ce44SJohn Forte 
1938fcf3ce44SJohn Forte 
1939fcf3ce44SJohn Forte /*
1940fcf3ce44SJohn Forte  * Convert port topology state to descriptive string
1941fcf3ce44SJohn Forte  */
1942fcf3ce44SJohn Forte static caddr_t
fcsm_dev_type_to_str(uint32_t type)1943fcf3ce44SJohn Forte fcsm_dev_type_to_str(uint32_t type)
1944fcf3ce44SJohn Forte {
1945fcf3ce44SJohn Forte 	int count;
1946fcf3ce44SJohn Forte 
1947fcf3ce44SJohn Forte 	for (count = 0; count < sizeof (fcsm_xlat_dev_type) /
1948fcf3ce44SJohn Forte 	    sizeof (fcsm_xlat_dev_type[0]); count++) {
1949fcf3ce44SJohn Forte 		if (fcsm_xlat_dev_type[count].xlat_type == type) {
1950fcf3ce44SJohn Forte 			return (fcsm_xlat_dev_type[count].xlat_str);
1951fcf3ce44SJohn Forte 		}
1952fcf3ce44SJohn Forte 	}
1953fcf3ce44SJohn Forte 
1954fcf3ce44SJohn Forte 	return (NULL);
1955fcf3ce44SJohn Forte }
1956fcf3ce44SJohn Forte 
1957fcf3ce44SJohn Forte static int
fcsm_cmd_cache_constructor(void * buf,void * cdarg,int kmflags)1958fcf3ce44SJohn Forte fcsm_cmd_cache_constructor(void *buf, void *cdarg, int kmflags)
1959fcf3ce44SJohn Forte {
1960fcf3ce44SJohn Forte 	fcsm_cmd_t		*cmd = (fcsm_cmd_t *)buf;
1961fcf3ce44SJohn Forte 	fcsm_t			*fcsm = (fcsm_t *)cdarg;
1962fcf3ce44SJohn Forte 	int			(*callback)(caddr_t);
1963fcf3ce44SJohn Forte 	fc_packet_t		*pkt;
1964fcf3ce44SJohn Forte 	fc_ulp_port_info_t	*pinfo;
1965fcf3ce44SJohn Forte 
1966fcf3ce44SJohn Forte 	ASSERT(fcsm != NULL && buf != NULL);
1967fcf3ce44SJohn Forte 	callback = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT;
1968fcf3ce44SJohn Forte 
1969fcf3ce44SJohn Forte 	cmd->cmd_fp_pkt		= &cmd->cmd_fc_packet;
1970fcf3ce44SJohn Forte 	cmd->cmd_job		= NULL;
1971fcf3ce44SJohn Forte 	cmd->cmd_fcsm		= fcsm;
1972fcf3ce44SJohn Forte 	cmd->cmd_dma_flags	= 0;
1973fcf3ce44SJohn Forte 
1974fcf3ce44SJohn Forte 	pkt = &cmd->cmd_fc_packet;
1975fcf3ce44SJohn Forte 
1976fcf3ce44SJohn Forte 	pkt->pkt_ulp_rscn_infop = NULL;
1977fcf3ce44SJohn Forte 	pkt->pkt_fca_private = (opaque_t)((caddr_t)cmd + sizeof (fcsm_cmd_t));
1978fcf3ce44SJohn Forte 	pkt->pkt_ulp_private = (opaque_t)cmd;
1979fcf3ce44SJohn Forte 
19807ff83669SZhong Wang 	if (!(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
19817ff83669SZhong Wang 		pinfo = &fcsm->sm_port_info;
19827ff83669SZhong Wang 		if (ddi_dma_alloc_handle(pinfo->port_dip,
19837ff83669SZhong Wang 		    pinfo->port_cmd_dma_attr,
19847ff83669SZhong Wang 		    callback, NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
19857ff83669SZhong Wang 			return (1);
19867ff83669SZhong Wang 		}
1987fcf3ce44SJohn Forte 
19887ff83669SZhong Wang 		if (ddi_dma_alloc_handle(pinfo->port_dip,
19897ff83669SZhong Wang 		    pinfo->port_resp_dma_attr,
19907ff83669SZhong Wang 		    callback, NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) {
19917ff83669SZhong Wang 			ddi_dma_free_handle(&pkt->pkt_cmd_dma);
19927ff83669SZhong Wang 			return (1);
19937ff83669SZhong Wang 		}
19947ff83669SZhong Wang 	} else {
19957ff83669SZhong Wang 		pkt->pkt_cmd_dma  = NULL;
19967ff83669SZhong Wang 		pkt->pkt_cmd	  = NULL;
19977ff83669SZhong Wang 		pkt->pkt_resp_dma = NULL;
19987ff83669SZhong Wang 		pkt->pkt_resp	  = NULL;
1999fcf3ce44SJohn Forte 	}
2000fcf3ce44SJohn Forte 
2001fcf3ce44SJohn Forte 	pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
2002fcf3ce44SJohn Forte 	pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt =
2003fcf3ce44SJohn Forte 	    pkt->pkt_data_cookie_cnt = 0;
2004fcf3ce44SJohn Forte 	pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie =
2005fcf3ce44SJohn Forte 	    pkt->pkt_data_cookie = NULL;
2006fcf3ce44SJohn Forte 
2007fcf3ce44SJohn Forte 	return (0);
2008fcf3ce44SJohn Forte }
2009fcf3ce44SJohn Forte 
2010fcf3ce44SJohn Forte 
2011fcf3ce44SJohn Forte /* ARGSUSED */
2012fcf3ce44SJohn Forte static void
fcsm_cmd_cache_destructor(void * buf,void * cdarg)2013fcf3ce44SJohn Forte fcsm_cmd_cache_destructor(void *buf, void *cdarg)
2014fcf3ce44SJohn Forte {
2015fcf3ce44SJohn Forte 	fcsm_cmd_t	*cmd = (fcsm_cmd_t *)buf;
2016fcf3ce44SJohn Forte 	fcsm_t		*fcsm = (fcsm_t *)cdarg;
2017fcf3ce44SJohn Forte 	fc_packet_t	*pkt;
2018fcf3ce44SJohn Forte 
2019fcf3ce44SJohn Forte 	ASSERT(fcsm == cmd->cmd_fcsm);
2020fcf3ce44SJohn Forte 
2021fcf3ce44SJohn Forte 	pkt = cmd->cmd_fp_pkt;
2022fcf3ce44SJohn Forte 
2023fcf3ce44SJohn Forte 	if (pkt->pkt_cmd_dma != NULL) {
2024fcf3ce44SJohn Forte 		ddi_dma_free_handle(&pkt->pkt_cmd_dma);
2025fcf3ce44SJohn Forte 	}
2026fcf3ce44SJohn Forte 
2027fcf3ce44SJohn Forte 	if (pkt->pkt_resp_dma != NULL) {
2028fcf3ce44SJohn Forte 		ddi_dma_free_handle(&pkt->pkt_resp_dma);
2029fcf3ce44SJohn Forte 	}
2030fcf3ce44SJohn Forte }
2031fcf3ce44SJohn Forte 
2032fcf3ce44SJohn Forte 
2033fcf3ce44SJohn Forte static fcsm_cmd_t *
fcsm_alloc_cmd(fcsm_t * fcsm,uint32_t cmd_len,uint32_t resp_len,int sleep)2034fcf3ce44SJohn Forte fcsm_alloc_cmd(fcsm_t *fcsm, uint32_t cmd_len, uint32_t resp_len, int sleep)
2035fcf3ce44SJohn Forte {
2036fcf3ce44SJohn Forte 	fcsm_cmd_t	*cmd;
2037fcf3ce44SJohn Forte 	fc_packet_t	*pkt;
2038fcf3ce44SJohn Forte 	int		rval;
2039fcf3ce44SJohn Forte 	ulong_t		real_len;
2040fcf3ce44SJohn Forte 	int		(*callback)(caddr_t);
2041fcf3ce44SJohn Forte 	ddi_dma_cookie_t	pkt_cookie;
2042fcf3ce44SJohn Forte 	ddi_dma_cookie_t	*cp;
2043fcf3ce44SJohn Forte 	uint32_t		cnt;
2044fcf3ce44SJohn Forte 	fc_ulp_port_info_t	*pinfo;
2045fcf3ce44SJohn Forte 
2046fcf3ce44SJohn Forte 	ASSERT(fcsm != NULL);
2047fcf3ce44SJohn Forte 	pinfo = &fcsm->sm_port_info;
2048fcf3ce44SJohn Forte 
2049fcf3ce44SJohn Forte 	callback = (sleep == KM_SLEEP) ? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT;
2050fcf3ce44SJohn Forte 
2051fcf3ce44SJohn Forte 	cmd = (fcsm_cmd_t *)kmem_cache_alloc(fcsm->sm_cmd_cache, sleep);
2052fcf3ce44SJohn Forte 	if (cmd == NULL) {
2053fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, fcsm, NULL,
2054fcf3ce44SJohn Forte 		    "alloc_cmd: kmem_cache_alloc failed"));
2055fcf3ce44SJohn Forte 		return (NULL);
2056fcf3ce44SJohn Forte 	}
2057fcf3ce44SJohn Forte 
2058fcf3ce44SJohn Forte 	cmd->cmd_retry_count	= 0;
2059fcf3ce44SJohn Forte 	cmd->cmd_max_retries	= 0;
2060fcf3ce44SJohn Forte 	cmd->cmd_retry_interval	= 0;
2061fcf3ce44SJohn Forte 	cmd->cmd_transport	= NULL;
2062fcf3ce44SJohn Forte 
2063fcf3ce44SJohn Forte 	ASSERT(cmd->cmd_dma_flags == 0);
2064fcf3ce44SJohn Forte 	ASSERT(cmd->cmd_fp_pkt == &cmd->cmd_fc_packet);
2065fcf3ce44SJohn Forte 	pkt = cmd->cmd_fp_pkt;
2066fcf3ce44SJohn Forte 
2067fcf3ce44SJohn Forte 	/* Zero out the important fc_packet fields */
2068fcf3ce44SJohn Forte 	pkt->pkt_pd		= NULL;
2069fcf3ce44SJohn Forte 	pkt->pkt_datalen	= 0;
2070fcf3ce44SJohn Forte 	pkt->pkt_data		= NULL;
2071fcf3ce44SJohn Forte 	pkt->pkt_state		= 0;
2072fcf3ce44SJohn Forte 	pkt->pkt_action		= 0;
2073fcf3ce44SJohn Forte 	pkt->pkt_reason		= 0;
2074fcf3ce44SJohn Forte 	pkt->pkt_expln		= 0;
2075fcf3ce44SJohn Forte 
2076fcf3ce44SJohn Forte 	/*
2077fcf3ce44SJohn Forte 	 * Now that pkt_pd is initialized, we can call fc_ulp_init_packet
2078fcf3ce44SJohn Forte 	 */
2079fcf3ce44SJohn Forte 
2080fcf3ce44SJohn Forte 	if (fc_ulp_init_packet((opaque_t)pinfo->port_handle, pkt, sleep)
2081fcf3ce44SJohn Forte 	    != FC_SUCCESS) {
2082fcf3ce44SJohn Forte 		kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2083fcf3ce44SJohn Forte 		return (NULL);
2084fcf3ce44SJohn Forte 	}
2085fcf3ce44SJohn Forte 
20867ff83669SZhong Wang 	if ((cmd_len) && !(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
2087fcf3ce44SJohn Forte 		ASSERT(pkt->pkt_cmd_dma != NULL);
2088fcf3ce44SJohn Forte 
2089fcf3ce44SJohn Forte 		rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
2090fcf3ce44SJohn Forte 		    fcsm->sm_port_info.port_acc_attr, DDI_DMA_CONSISTENT,
2091fcf3ce44SJohn Forte 		    callback, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len,
2092fcf3ce44SJohn Forte 		    &pkt->pkt_cmd_acc);
2093fcf3ce44SJohn Forte 
2094fcf3ce44SJohn Forte 		if (rval != DDI_SUCCESS) {
2095fcf3ce44SJohn Forte 			(void) fc_ulp_uninit_packet(
2096fcf3ce44SJohn Forte 			    (opaque_t)pinfo->port_handle, pkt);
2097fcf3ce44SJohn Forte 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2098fcf3ce44SJohn Forte 			fcsm_free_cmd_dma(cmd);
2099fcf3ce44SJohn Forte 			return (NULL);
2100fcf3ce44SJohn Forte 		}
2101fcf3ce44SJohn Forte 
2102fcf3ce44SJohn Forte 		cmd->cmd_dma_flags |= FCSM_CF_CMD_VALID_DMA_MEM;
2103fcf3ce44SJohn Forte 
2104fcf3ce44SJohn Forte 		if (real_len < cmd_len) {
2105fcf3ce44SJohn Forte 			(void) fc_ulp_uninit_packet(
2106fcf3ce44SJohn Forte 			    (opaque_t)pinfo->port_handle, pkt);
2107fcf3ce44SJohn Forte 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2108fcf3ce44SJohn Forte 			fcsm_free_cmd_dma(cmd);
2109fcf3ce44SJohn Forte 			return (NULL);
2110fcf3ce44SJohn Forte 		}
2111fcf3ce44SJohn Forte 
2112fcf3ce44SJohn Forte 		rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
2113fcf3ce44SJohn Forte 		    pkt->pkt_cmd, real_len, DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
2114fcf3ce44SJohn Forte 		    callback, NULL, &pkt_cookie, &pkt->pkt_cmd_cookie_cnt);
2115fcf3ce44SJohn Forte 
2116fcf3ce44SJohn Forte 		if (rval != DDI_DMA_MAPPED) {
2117fcf3ce44SJohn Forte 			(void) fc_ulp_uninit_packet(
2118fcf3ce44SJohn Forte 			    (opaque_t)pinfo->port_handle, pkt);
2119fcf3ce44SJohn Forte 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2120fcf3ce44SJohn Forte 			fcsm_free_cmd_dma(cmd);
2121fcf3ce44SJohn Forte 			return (NULL);
2122fcf3ce44SJohn Forte 		}
2123fcf3ce44SJohn Forte 
2124fcf3ce44SJohn Forte 		cmd->cmd_dma_flags |= FCSM_CF_CMD_VALID_DMA_BIND;
2125fcf3ce44SJohn Forte 
2126fcf3ce44SJohn Forte 		if (pkt->pkt_cmd_cookie_cnt >
2127fcf3ce44SJohn Forte 		    pinfo->port_cmd_dma_attr->dma_attr_sgllen) {
2128fcf3ce44SJohn Forte 			(void) fc_ulp_uninit_packet(
2129fcf3ce44SJohn Forte 			    (opaque_t)pinfo->port_handle, pkt);
2130fcf3ce44SJohn Forte 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2131fcf3ce44SJohn Forte 			fcsm_free_cmd_dma(cmd);
2132fcf3ce44SJohn Forte 			return (NULL);
2133fcf3ce44SJohn Forte 		}
2134fcf3ce44SJohn Forte 
2135fcf3ce44SJohn Forte 		ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2136fcf3ce44SJohn Forte 
2137fcf3ce44SJohn Forte 		cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2138fcf3ce44SJohn Forte 		    pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
2139fcf3ce44SJohn Forte 		    KM_NOSLEEP);
2140fcf3ce44SJohn Forte 
2141fcf3ce44SJohn Forte 		if (cp == NULL) {
2142fcf3ce44SJohn Forte 			(void) fc_ulp_uninit_packet(
2143fcf3ce44SJohn Forte 			    (opaque_t)pinfo->port_handle, pkt);
2144fcf3ce44SJohn Forte 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2145fcf3ce44SJohn Forte 			fcsm_free_cmd_dma(cmd);
2146fcf3ce44SJohn Forte 			return (NULL);
2147fcf3ce44SJohn Forte 		}
2148fcf3ce44SJohn Forte 
2149fcf3ce44SJohn Forte 		*cp = pkt_cookie;
2150fcf3ce44SJohn Forte 		cp++;
2151fcf3ce44SJohn Forte 		for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
2152fcf3ce44SJohn Forte 			ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
2153fcf3ce44SJohn Forte 			*cp = pkt_cookie;
2154fcf3ce44SJohn Forte 		}
21557ff83669SZhong Wang 	} else if (cmd_len != 0) {
21567ff83669SZhong Wang 		pkt->pkt_cmd = kmem_zalloc(cmd_len, KM_SLEEP);
2157fcf3ce44SJohn Forte 	}
2158fcf3ce44SJohn Forte 
21597ff83669SZhong Wang 	if ((resp_len) && !(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
2160fcf3ce44SJohn Forte 		ASSERT(pkt->pkt_resp_dma != NULL);
2161fcf3ce44SJohn Forte 
2162fcf3ce44SJohn Forte 		rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
2163fcf3ce44SJohn Forte 		    fcsm->sm_port_info.port_acc_attr, DDI_DMA_CONSISTENT,
2164fcf3ce44SJohn Forte 		    callback, NULL, (caddr_t *)&pkt->pkt_resp, &real_len,
2165fcf3ce44SJohn Forte 		    &pkt->pkt_resp_acc);
2166fcf3ce44SJohn Forte 
2167fcf3ce44SJohn Forte 		if (rval != DDI_SUCCESS) {
2168fcf3ce44SJohn Forte 			(void) fc_ulp_uninit_packet(
2169fcf3ce44SJohn Forte 			    (opaque_t)pinfo->port_handle, pkt);
2170fcf3ce44SJohn Forte 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2171fcf3ce44SJohn Forte 			fcsm_free_cmd_dma(cmd);
2172fcf3ce44SJohn Forte 			return (NULL);
2173fcf3ce44SJohn Forte 		}
2174fcf3ce44SJohn Forte 
2175fcf3ce44SJohn Forte 		cmd->cmd_dma_flags |= FCSM_CF_RESP_VALID_DMA_MEM;
2176fcf3ce44SJohn Forte 
2177fcf3ce44SJohn Forte 		if (real_len < resp_len) {
2178fcf3ce44SJohn Forte 			(void) fc_ulp_uninit_packet(
2179fcf3ce44SJohn Forte 			    (opaque_t)pinfo->port_handle, pkt);
2180fcf3ce44SJohn Forte 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2181fcf3ce44SJohn Forte 			fcsm_free_cmd_dma(cmd);
2182fcf3ce44SJohn Forte 			return (NULL);
2183fcf3ce44SJohn Forte 		}
2184fcf3ce44SJohn Forte 
2185fcf3ce44SJohn Forte 		rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
2186fcf3ce44SJohn Forte 		    pkt->pkt_resp, real_len, DDI_DMA_READ | DDI_DMA_CONSISTENT,
2187fcf3ce44SJohn Forte 		    callback, NULL, &pkt_cookie, &pkt->pkt_resp_cookie_cnt);
2188fcf3ce44SJohn Forte 
2189fcf3ce44SJohn Forte 		if (rval != DDI_DMA_MAPPED) {
2190fcf3ce44SJohn Forte 			(void) fc_ulp_uninit_packet(
2191fcf3ce44SJohn Forte 			    (opaque_t)pinfo->port_handle, pkt);
2192fcf3ce44SJohn Forte 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2193fcf3ce44SJohn Forte 			fcsm_free_cmd_dma(cmd);
2194fcf3ce44SJohn Forte 			return (NULL);
2195fcf3ce44SJohn Forte 		}
2196fcf3ce44SJohn Forte 
2197fcf3ce44SJohn Forte 		cmd->cmd_dma_flags |= FCSM_CF_RESP_VALID_DMA_BIND;
2198fcf3ce44SJohn Forte 
2199fcf3ce44SJohn Forte 		if (pkt->pkt_resp_cookie_cnt >
2200fcf3ce44SJohn Forte 		    pinfo->port_resp_dma_attr->dma_attr_sgllen) {
2201fcf3ce44SJohn Forte 			(void) fc_ulp_uninit_packet(
2202fcf3ce44SJohn Forte 			    (opaque_t)pinfo->port_handle, pkt);
2203fcf3ce44SJohn Forte 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2204fcf3ce44SJohn Forte 			fcsm_free_cmd_dma(cmd);
2205fcf3ce44SJohn Forte 			return (NULL);
2206fcf3ce44SJohn Forte 		}
2207fcf3ce44SJohn Forte 
2208fcf3ce44SJohn Forte 		ASSERT(pkt->pkt_resp_cookie_cnt != 0);
2209fcf3ce44SJohn Forte 
2210fcf3ce44SJohn Forte 		cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2211fcf3ce44SJohn Forte 		    pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie),
2212fcf3ce44SJohn Forte 		    KM_NOSLEEP);
2213fcf3ce44SJohn Forte 
2214fcf3ce44SJohn Forte 		if (cp == NULL) {
2215fcf3ce44SJohn Forte 			(void) fc_ulp_uninit_packet(
2216fcf3ce44SJohn Forte 			    (opaque_t)pinfo->port_handle, pkt);
2217fcf3ce44SJohn Forte 			kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2218fcf3ce44SJohn Forte 			fcsm_free_cmd_dma(cmd);
2219fcf3ce44SJohn Forte 			return (NULL);
2220fcf3ce44SJohn Forte 		}
2221fcf3ce44SJohn Forte 
2222fcf3ce44SJohn Forte 		*cp = pkt_cookie;
2223fcf3ce44SJohn Forte 		cp++;
2224fcf3ce44SJohn Forte 		for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) {
2225fcf3ce44SJohn Forte 			ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
2226fcf3ce44SJohn Forte 			*cp = pkt_cookie;
2227fcf3ce44SJohn Forte 		}
22287ff83669SZhong Wang 	} else if (resp_len != 0) {
22297ff83669SZhong Wang 		pkt->pkt_resp = kmem_zalloc(resp_len, KM_SLEEP);
2230fcf3ce44SJohn Forte 	}
2231fcf3ce44SJohn Forte 
2232fcf3ce44SJohn Forte 	pkt->pkt_cmdlen = cmd_len;
2233fcf3ce44SJohn Forte 	pkt->pkt_rsplen = resp_len;
2234fcf3ce44SJohn Forte 
2235fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2236fcf3ce44SJohn Forte 	    "alloc_cmd: cmd 0x%p", (void *)cmd));
2237fcf3ce44SJohn Forte 	return (cmd);
2238fcf3ce44SJohn Forte }
2239fcf3ce44SJohn Forte 
2240fcf3ce44SJohn Forte static void
fcsm_free_cmd(fcsm_cmd_t * cmd)2241fcf3ce44SJohn Forte fcsm_free_cmd(fcsm_cmd_t *cmd)
2242fcf3ce44SJohn Forte {
2243fcf3ce44SJohn Forte 	fcsm_t		*fcsm;
2244fcf3ce44SJohn Forte 
2245fcf3ce44SJohn Forte 	fcsm = cmd->cmd_fcsm;
2246fcf3ce44SJohn Forte 	ASSERT(fcsm != NULL);
2247fcf3ce44SJohn Forte 
2248fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2249fcf3ce44SJohn Forte 	    "free_cmd: cmd 0x%p", (void *)cmd));
2250fcf3ce44SJohn Forte 
2251fcf3ce44SJohn Forte 	fcsm_free_cmd_dma(cmd);
2252fcf3ce44SJohn Forte 
2253fcf3ce44SJohn Forte 	(void) fc_ulp_uninit_packet((opaque_t)fcsm->sm_port_info.port_handle,
2254fcf3ce44SJohn Forte 	    cmd->cmd_fp_pkt);
2255fcf3ce44SJohn Forte 	kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2256fcf3ce44SJohn Forte }
2257fcf3ce44SJohn Forte 
2258fcf3ce44SJohn Forte static void
fcsm_free_cmd_dma(fcsm_cmd_t * cmd)2259fcf3ce44SJohn Forte fcsm_free_cmd_dma(fcsm_cmd_t *cmd)
2260fcf3ce44SJohn Forte {
2261fcf3ce44SJohn Forte 	fc_packet_t	*pkt;
2262fcf3ce44SJohn Forte 
2263fcf3ce44SJohn Forte 	pkt = cmd->cmd_fp_pkt;
2264fcf3ce44SJohn Forte 	ASSERT(pkt != NULL);
2265fcf3ce44SJohn Forte 
22667ff83669SZhong Wang 	if (cmd->cmd_fcsm->sm_flags & FCSM_USING_NODMA_FCA) {
22677ff83669SZhong Wang 		if (pkt->pkt_cmd) {
22687ff83669SZhong Wang 			kmem_free(pkt->pkt_cmd, pkt->pkt_cmdlen);
22697ff83669SZhong Wang 			pkt->pkt_cmd = NULL;
22707ff83669SZhong Wang 		}
22717ff83669SZhong Wang 
22727ff83669SZhong Wang 		if (pkt->pkt_resp) {
22737ff83669SZhong Wang 			kmem_free(pkt->pkt_resp, pkt->pkt_rsplen);
22747ff83669SZhong Wang 			pkt->pkt_resp = NULL;
22757ff83669SZhong Wang 		}
22767ff83669SZhong Wang 	}
22777ff83669SZhong Wang 
2278fcf3ce44SJohn Forte 	pkt->pkt_cmdlen = 0;
2279fcf3ce44SJohn Forte 	pkt->pkt_rsplen = 0;
2280fcf3ce44SJohn Forte 	pkt->pkt_tran_type = 0;
2281fcf3ce44SJohn Forte 	pkt->pkt_tran_flags = 0;
2282fcf3ce44SJohn Forte 
2283fcf3ce44SJohn Forte 	if (pkt->pkt_cmd_cookie != NULL) {
2284fcf3ce44SJohn Forte 		kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt *
2285fcf3ce44SJohn Forte 		    sizeof (ddi_dma_cookie_t));
2286fcf3ce44SJohn Forte 		pkt->pkt_cmd_cookie = NULL;
2287fcf3ce44SJohn Forte 	}
2288fcf3ce44SJohn Forte 
2289fcf3ce44SJohn Forte 	if (pkt->pkt_resp_cookie != NULL) {
2290fcf3ce44SJohn Forte 		kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt *
2291fcf3ce44SJohn Forte 		    sizeof (ddi_dma_cookie_t));
2292fcf3ce44SJohn Forte 		pkt->pkt_resp_cookie = NULL;
2293fcf3ce44SJohn Forte 	}
2294fcf3ce44SJohn Forte 
2295fcf3ce44SJohn Forte 	if (cmd->cmd_dma_flags & FCSM_CF_CMD_VALID_DMA_BIND) {
2296fcf3ce44SJohn Forte 		(void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
2297fcf3ce44SJohn Forte 	}
2298fcf3ce44SJohn Forte 
2299fcf3ce44SJohn Forte 	if (cmd->cmd_dma_flags & FCSM_CF_CMD_VALID_DMA_MEM) {
2300fcf3ce44SJohn Forte 		if (pkt->pkt_cmd_acc) {
2301fcf3ce44SJohn Forte 			ddi_dma_mem_free(&pkt->pkt_cmd_acc);
2302fcf3ce44SJohn Forte 		}
2303fcf3ce44SJohn Forte 	}
2304fcf3ce44SJohn Forte 
2305fcf3ce44SJohn Forte 	if (cmd->cmd_dma_flags & FCSM_CF_RESP_VALID_DMA_BIND) {
2306fcf3ce44SJohn Forte 		(void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
2307fcf3ce44SJohn Forte 	}
2308fcf3ce44SJohn Forte 
2309fcf3ce44SJohn Forte 	if (cmd->cmd_dma_flags & FCSM_CF_RESP_VALID_DMA_MEM) {
2310fcf3ce44SJohn Forte 		if (pkt->pkt_resp_acc) {
2311fcf3ce44SJohn Forte 			ddi_dma_mem_free(&pkt->pkt_resp_acc);
2312fcf3ce44SJohn Forte 		}
2313fcf3ce44SJohn Forte 	}
2314fcf3ce44SJohn Forte 
2315fcf3ce44SJohn Forte 	cmd->cmd_dma_flags = 0;
2316fcf3ce44SJohn Forte }
2317fcf3ce44SJohn Forte 
2318fcf3ce44SJohn Forte /* ARGSUSED */
2319fcf3ce44SJohn Forte static int
fcsm_job_cache_constructor(void * buf,void * cdarg,int kmflag)2320fcf3ce44SJohn Forte fcsm_job_cache_constructor(void *buf, void *cdarg, int kmflag)
2321fcf3ce44SJohn Forte {
2322fcf3ce44SJohn Forte 	fcsm_job_t *job = (fcsm_job_t *)buf;
2323fcf3ce44SJohn Forte 
2324fcf3ce44SJohn Forte 	mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL);
2325fcf3ce44SJohn Forte 	sema_init(&job->job_sema, 0, NULL, SEMA_DEFAULT, NULL);
2326fcf3ce44SJohn Forte 
2327fcf3ce44SJohn Forte 	return (0);
2328fcf3ce44SJohn Forte }
2329fcf3ce44SJohn Forte 
2330fcf3ce44SJohn Forte /* ARGSUSED */
2331fcf3ce44SJohn Forte static void
fcsm_job_cache_destructor(void * buf,void * cdarg)2332fcf3ce44SJohn Forte fcsm_job_cache_destructor(void *buf, void *cdarg)
2333fcf3ce44SJohn Forte {
2334fcf3ce44SJohn Forte 	fcsm_job_t *job = (fcsm_job_t *)buf;
2335fcf3ce44SJohn Forte 
2336fcf3ce44SJohn Forte 	sema_destroy(&job->job_sema);
2337fcf3ce44SJohn Forte 	mutex_destroy(&job->job_mutex);
2338fcf3ce44SJohn Forte }
2339fcf3ce44SJohn Forte 
2340fcf3ce44SJohn Forte 
2341fcf3ce44SJohn Forte static fcsm_job_t *
fcsm_alloc_job(int sleep)2342fcf3ce44SJohn Forte fcsm_alloc_job(int sleep)
2343fcf3ce44SJohn Forte {
2344fcf3ce44SJohn Forte 	fcsm_job_t	*job;
2345fcf3ce44SJohn Forte 
2346fcf3ce44SJohn Forte 	job = (fcsm_job_t *)kmem_cache_alloc(fcsm_job_cache, sleep);
2347fcf3ce44SJohn Forte 	if (job != NULL) {
2348fcf3ce44SJohn Forte 		job->job_code		= FCSM_JOB_NONE;
2349fcf3ce44SJohn Forte 		job->job_flags		= 0;
2350fcf3ce44SJohn Forte 		job->job_port_instance	= -1;
23517ff83669SZhong Wang 		job->job_result		= -1;
2352fcf3ce44SJohn Forte 		job->job_arg		= (opaque_t)0;
2353fcf3ce44SJohn Forte 		job->job_caller_priv	= (opaque_t)0;
2354fcf3ce44SJohn Forte 		job->job_comp		= NULL;
2355fcf3ce44SJohn Forte 		job->job_comp_arg	= (opaque_t)0;
2356fcf3ce44SJohn Forte 		job->job_priv		= (void *)0;
2357fcf3ce44SJohn Forte 		job->job_priv_flags	= 0;
2358fcf3ce44SJohn Forte 		job->job_next		= 0;
2359fcf3ce44SJohn Forte 	}
2360fcf3ce44SJohn Forte 
2361fcf3ce44SJohn Forte 	return (job);
2362fcf3ce44SJohn Forte }
2363fcf3ce44SJohn Forte 
2364fcf3ce44SJohn Forte static void
fcsm_dealloc_job(fcsm_job_t * job)2365fcf3ce44SJohn Forte fcsm_dealloc_job(fcsm_job_t *job)
2366fcf3ce44SJohn Forte {
2367fcf3ce44SJohn Forte 	kmem_cache_free(fcsm_job_cache, (void *)job);
2368fcf3ce44SJohn Forte }
2369fcf3ce44SJohn Forte 
2370fcf3ce44SJohn Forte 
2371fcf3ce44SJohn Forte 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)2372fcf3ce44SJohn Forte fcsm_init_job(fcsm_job_t *job, int instance, uint32_t command, uint32_t flags,
2373fcf3ce44SJohn Forte     opaque_t arg, opaque_t caller_priv,
2374fcf3ce44SJohn Forte     void (*comp)(opaque_t, fcsm_job_t *, int), opaque_t comp_arg)
2375fcf3ce44SJohn Forte {
2376fcf3ce44SJohn Forte 	ASSERT(job != NULL);
2377fcf3ce44SJohn Forte 	job->job_port_instance	= instance;
2378fcf3ce44SJohn Forte 	job->job_code		= command;
2379fcf3ce44SJohn Forte 	job->job_flags		= flags;
23807ff83669SZhong Wang 	job->job_arg		= arg;
23817ff83669SZhong Wang 	job->job_caller_priv	= caller_priv;
2382fcf3ce44SJohn Forte 	job->job_comp		= comp;
2383fcf3ce44SJohn Forte 	job->job_comp_arg	= comp_arg;
2384fcf3ce44SJohn Forte 	job->job_retry_count	= 0;
2385fcf3ce44SJohn Forte }
2386fcf3ce44SJohn Forte 
2387fcf3ce44SJohn Forte static int
fcsm_process_job(fcsm_job_t * job,int priority_flag)2388fcf3ce44SJohn Forte fcsm_process_job(fcsm_job_t *job, int priority_flag)
2389fcf3ce44SJohn Forte {
2390fcf3ce44SJohn Forte 	fcsm_t	*fcsm;
2391fcf3ce44SJohn Forte 	int	sync;
2392fcf3ce44SJohn Forte 
2393fcf3ce44SJohn Forte 	ASSERT(job != NULL);
2394fcf3ce44SJohn Forte 	ASSERT(!MUTEX_HELD(&job->job_mutex));
2395fcf3ce44SJohn Forte 
2396fcf3ce44SJohn Forte 	fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
2397fcf3ce44SJohn Forte 
2398fcf3ce44SJohn Forte 	if (fcsm == NULL) {
2399fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
2400fcf3ce44SJohn Forte 		    "process_job: port instance 0x%x not found",
2401fcf3ce44SJohn Forte 		    job->job_port_instance));
2402fcf3ce44SJohn Forte 		return (FC_BADDEV);
2403fcf3ce44SJohn Forte 	}
2404fcf3ce44SJohn Forte 
2405fcf3ce44SJohn Forte 	mutex_enter(&job->job_mutex);
2406fcf3ce44SJohn Forte 	/* Both SYNC and ASYNC flags should not be set */
2407fcf3ce44SJohn Forte 	ASSERT(((job->job_flags & (FCSM_JOBFLAG_SYNC | FCSM_JOBFLAG_ASYNC)) ==
2408fcf3ce44SJohn Forte 	    FCSM_JOBFLAG_SYNC) || ((job->job_flags &
2409fcf3ce44SJohn Forte 	    (FCSM_JOBFLAG_SYNC | FCSM_JOBFLAG_ASYNC)) == FCSM_JOBFLAG_ASYNC));
2410fcf3ce44SJohn Forte 	/*
2411fcf3ce44SJohn Forte 	 * Check if job is a synchronous job. We might not be able to
2412fcf3ce44SJohn Forte 	 * check it reliably after enque_job(), if job is an ASYNC job.
2413fcf3ce44SJohn Forte 	 */
2414fcf3ce44SJohn Forte 	sync = job->job_flags & FCSM_JOBFLAG_SYNC;
2415fcf3ce44SJohn Forte 	mutex_exit(&job->job_mutex);
2416fcf3ce44SJohn Forte 
2417fcf3ce44SJohn Forte 	/* Queue the job for processing by job thread */
2418fcf3ce44SJohn Forte 	fcsm_enque_job(fcsm, job, priority_flag);
2419fcf3ce44SJohn Forte 
2420fcf3ce44SJohn Forte 	/* Wait for job completion, if it is a synchronous job */
2421fcf3ce44SJohn Forte 	if (sync) {
2422fcf3ce44SJohn Forte 		/*
2423fcf3ce44SJohn Forte 		 * This is a Synchronous Job. So job structure is available.
2424fcf3ce44SJohn Forte 		 * Caller is responsible for freeing it.
2425fcf3ce44SJohn Forte 		 */
2426fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_ERR, (CE_CONT, SM_LOG, fcsm, NULL,
2427fcf3ce44SJohn Forte 		    "process_job: Waiting for sync job <%p> completion",
2428fcf3ce44SJohn Forte 		    (void *)job));
2429fcf3ce44SJohn Forte 		sema_p(&job->job_sema);
2430fcf3ce44SJohn Forte 	}
2431fcf3ce44SJohn Forte 
2432fcf3ce44SJohn Forte 	return (FC_SUCCESS);
2433fcf3ce44SJohn Forte }
2434fcf3ce44SJohn Forte 
2435fcf3ce44SJohn Forte static void
fcsm_enque_job(fcsm_t * fcsm,fcsm_job_t * job,int priority_flag)2436fcf3ce44SJohn Forte fcsm_enque_job(fcsm_t *fcsm, fcsm_job_t *job, int priority_flag)
2437fcf3ce44SJohn Forte {
2438fcf3ce44SJohn Forte 	ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
2439fcf3ce44SJohn Forte 
2440fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
2441fcf3ce44SJohn Forte 	/* Queue the job at the head or tail depending on the job priority */
2442fcf3ce44SJohn Forte 	if (priority_flag) {
2443fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL,
2444fcf3ce44SJohn Forte 		    "enque_job: job 0x%p is high priority", job));
2445fcf3ce44SJohn Forte 		/* Queue at the head */
2446fcf3ce44SJohn Forte 		if (fcsm->sm_job_tail == NULL) {
2447fcf3ce44SJohn Forte 			ASSERT(fcsm->sm_job_head == NULL);
2448fcf3ce44SJohn Forte 			fcsm->sm_job_head = fcsm->sm_job_tail = job;
2449fcf3ce44SJohn Forte 		} else {
2450fcf3ce44SJohn Forte 			ASSERT(fcsm->sm_job_head != NULL);
2451fcf3ce44SJohn Forte 			job->job_next = fcsm->sm_job_head;
2452fcf3ce44SJohn Forte 			fcsm->sm_job_head = job;
2453fcf3ce44SJohn Forte 		}
2454fcf3ce44SJohn Forte 	} else {
2455fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL,
2456fcf3ce44SJohn Forte 		    "enque_job: job 0x%p is normal", job));
2457fcf3ce44SJohn Forte 		/* Queue at the tail */
2458fcf3ce44SJohn Forte 		if (fcsm->sm_job_tail == NULL) {
2459fcf3ce44SJohn Forte 			ASSERT(fcsm->sm_job_head == NULL);
2460fcf3ce44SJohn Forte 			fcsm->sm_job_head = fcsm->sm_job_tail = job;
2461fcf3ce44SJohn Forte 		} else {
2462fcf3ce44SJohn Forte 			ASSERT(fcsm->sm_job_head != NULL);
2463fcf3ce44SJohn Forte 			fcsm->sm_job_tail->job_next = job;
2464fcf3ce44SJohn Forte 			fcsm->sm_job_tail = job;
2465fcf3ce44SJohn Forte 		}
2466fcf3ce44SJohn Forte 		job->job_next = NULL;
2467fcf3ce44SJohn Forte 	}
2468fcf3ce44SJohn Forte 
2469fcf3ce44SJohn Forte 	/* Signal the job thread to process the job */
2470fcf3ce44SJohn Forte 	cv_signal(&fcsm->sm_job_cv);
2471fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
2472fcf3ce44SJohn Forte }
2473fcf3ce44SJohn Forte 
2474fcf3ce44SJohn Forte static int
fcsm_retry_job(fcsm_t * fcsm,fcsm_job_t * job)2475fcf3ce44SJohn Forte fcsm_retry_job(fcsm_t *fcsm, fcsm_job_t *job)
2476fcf3ce44SJohn Forte {
2477fcf3ce44SJohn Forte 	/*
2478fcf3ce44SJohn Forte 	 * If it is a CT passthru job and status is login required, then
2479fcf3ce44SJohn Forte 	 * retry the job so that login can be performed again.
2480fcf3ce44SJohn Forte 	 * Ensure that this retry is performed a finite number of times,
2481fcf3ce44SJohn Forte 	 * so that a faulty fabric does not cause us to retry forever.
2482fcf3ce44SJohn Forte 	 */
2483fcf3ce44SJohn Forte 
2484fcf3ce44SJohn Forte 	switch (job->job_code) {
2485fcf3ce44SJohn Forte 	case FCSM_JOB_CT_PASSTHRU: {
2486fcf3ce44SJohn Forte 		uint32_t	jobflag;
2487fcf3ce44SJohn Forte 		fc_ct_header_t	*ct_header;
2488fcf3ce44SJohn Forte 
2489fcf3ce44SJohn Forte 		if (job->job_result != FC_LOGINREQ) {
2490fcf3ce44SJohn Forte 			break;
2491fcf3ce44SJohn Forte 		}
2492fcf3ce44SJohn Forte 
2493fcf3ce44SJohn Forte 		/*
2494fcf3ce44SJohn Forte 		 * If it is a management server command
2495fcf3ce44SJohn Forte 		 * then Reset the Management server login flag, so that login
2496fcf3ce44SJohn Forte 		 * gets re-established.
2497fcf3ce44SJohn Forte 		 * If it is a Name server command,
2498fcf3ce44SJohn Forte 		 * then it is 'fp' responsibility to perform the login.
2499fcf3ce44SJohn Forte 		 */
2500fcf3ce44SJohn Forte 		ASSERT(job->job_arg != NULL);
2501fcf3ce44SJohn Forte 		ct_header =
2502fcf3ce44SJohn Forte 		    (fc_ct_header_t *)((fcio_t *)job->job_arg)->fcio_ibuf;
2503fcf3ce44SJohn Forte 		if (ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) {
2504fcf3ce44SJohn Forte 			mutex_enter(&fcsm->sm_mutex);
2505fcf3ce44SJohn Forte 			fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGGED_IN;
2506fcf3ce44SJohn Forte 			mutex_exit(&fcsm->sm_mutex);
2507fcf3ce44SJohn Forte 		}
2508fcf3ce44SJohn Forte 
2509fcf3ce44SJohn Forte 		if (job->job_retry_count >= fcsm_max_job_retries) {
2510fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2511fcf3ce44SJohn Forte 			    "retry_job: job 0x%p max retries (%d) reached",
2512fcf3ce44SJohn Forte 			    (void *)job, job->job_retry_count));
2513fcf3ce44SJohn Forte 			break;
2514fcf3ce44SJohn Forte 		}
2515fcf3ce44SJohn Forte 
2516fcf3ce44SJohn Forte 		/*
2517fcf3ce44SJohn Forte 		 * Login is required again. Retry the command, so that
2518fcf3ce44SJohn Forte 		 * login will get performed again.
2519fcf3ce44SJohn Forte 		 */
2520fcf3ce44SJohn Forte 		mutex_enter(&job->job_mutex);
2521fcf3ce44SJohn Forte 		job->job_retry_count++;
2522fcf3ce44SJohn Forte 		jobflag = job->job_flags;
2523fcf3ce44SJohn Forte 		mutex_exit(&job->job_mutex);
2524fcf3ce44SJohn Forte 
2525fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2526fcf3ce44SJohn Forte 		    "retry_job: retry(%d) job 0x%p",
2527fcf3ce44SJohn Forte 		    job->job_retry_count, (void *)job));
2528fcf3ce44SJohn Forte 		/*
2529fcf3ce44SJohn Forte 		 * This job should get picked up before the
2530fcf3ce44SJohn Forte 		 * other jobs sitting in the queue.
2531fcf3ce44SJohn Forte 		 * Requeue the command at the head and then
2532fcf3ce44SJohn Forte 		 * reset the SERIALIZE flag.
2533fcf3ce44SJohn Forte 		 */
2534fcf3ce44SJohn Forte 		fcsm_enque_job(fcsm, job, 1);
2535fcf3ce44SJohn Forte 		if (jobflag & FCSM_JOBFLAG_SERIALIZE) {
2536fcf3ce44SJohn Forte 			mutex_enter(&fcsm->sm_mutex);
2537fcf3ce44SJohn Forte 			ASSERT(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD);
2538fcf3ce44SJohn Forte 			fcsm->sm_flags &= ~FCSM_SERIALIZE_JOBTHREAD;
2539fcf3ce44SJohn Forte 
2540fcf3ce44SJohn Forte 			/* Signal the job thread to process the job */
2541fcf3ce44SJohn Forte 			cv_signal(&fcsm->sm_job_cv);
2542fcf3ce44SJohn Forte 			mutex_exit(&fcsm->sm_mutex);
2543fcf3ce44SJohn Forte 		}
2544fcf3ce44SJohn Forte 
2545fcf3ce44SJohn Forte 		/* Command is queued for retrying */
2546fcf3ce44SJohn Forte 		return (0);
2547fcf3ce44SJohn Forte 	}
2548fcf3ce44SJohn Forte 
2549fcf3ce44SJohn Forte 	default:
2550fcf3ce44SJohn Forte 		break;
2551fcf3ce44SJohn Forte 	}
2552fcf3ce44SJohn Forte 	return (1);
2553fcf3ce44SJohn Forte }
2554fcf3ce44SJohn Forte 
2555fcf3ce44SJohn Forte static void
fcsm_jobdone(fcsm_job_t * job)2556fcf3ce44SJohn Forte fcsm_jobdone(fcsm_job_t *job)
2557fcf3ce44SJohn Forte {
2558fcf3ce44SJohn Forte 	fcsm_t	*fcsm;
2559fcf3ce44SJohn Forte 
2560fcf3ce44SJohn Forte 	fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
2561fcf3ce44SJohn Forte 	ASSERT(fcsm != NULL);
2562fcf3ce44SJohn Forte 
2563fcf3ce44SJohn Forte 	if (job->job_result != FC_SUCCESS) {
2564fcf3ce44SJohn Forte 		if (fcsm_retry_job(fcsm, job) == 0) {
2565fcf3ce44SJohn Forte 			/* Job retried. so just return from here */
2566fcf3ce44SJohn Forte 			return;
2567fcf3ce44SJohn Forte 		}
2568fcf3ce44SJohn Forte 	}
2569fcf3ce44SJohn Forte 
2570fcf3ce44SJohn Forte 	if (job->job_comp) {
2571fcf3ce44SJohn Forte 		job->job_comp(job->job_comp_arg, job, job->job_result);
2572fcf3ce44SJohn Forte 	}
2573fcf3ce44SJohn Forte 
2574fcf3ce44SJohn Forte 	mutex_enter(&job->job_mutex);
2575fcf3ce44SJohn Forte 	if (job->job_flags & FCSM_JOBFLAG_SERIALIZE) {
2576fcf3ce44SJohn Forte 		mutex_exit(&job->job_mutex);
2577fcf3ce44SJohn Forte 		mutex_enter(&fcsm->sm_mutex);
2578fcf3ce44SJohn Forte 		ASSERT(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD);
2579fcf3ce44SJohn Forte 		fcsm->sm_flags &= ~FCSM_SERIALIZE_JOBTHREAD;
2580fcf3ce44SJohn Forte 
2581fcf3ce44SJohn Forte 		/* Signal the job thread to process the job */
2582fcf3ce44SJohn Forte 		cv_signal(&fcsm->sm_job_cv);
2583fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
2584fcf3ce44SJohn Forte 		mutex_enter(&job->job_mutex);
2585fcf3ce44SJohn Forte 	}
2586fcf3ce44SJohn Forte 
2587fcf3ce44SJohn Forte 	if (job->job_flags & FCSM_JOBFLAG_SYNC) {
2588fcf3ce44SJohn Forte 		mutex_exit(&job->job_mutex);
2589fcf3ce44SJohn Forte 		sema_v(&job->job_sema);
2590fcf3ce44SJohn Forte 	} else {
2591fcf3ce44SJohn Forte 		mutex_exit(&job->job_mutex);
2592fcf3ce44SJohn Forte 		/* Async job, free the job structure */
2593fcf3ce44SJohn Forte 		fcsm_dealloc_job(job);
2594fcf3ce44SJohn Forte 	}
2595fcf3ce44SJohn Forte }
2596fcf3ce44SJohn Forte 
2597fcf3ce44SJohn Forte fcsm_job_t *
fcsm_deque_job(fcsm_t * fcsm)2598fcf3ce44SJohn Forte fcsm_deque_job(fcsm_t *fcsm)
2599fcf3ce44SJohn Forte {
2600fcf3ce44SJohn Forte 	fcsm_job_t	*job;
2601fcf3ce44SJohn Forte 
2602fcf3ce44SJohn Forte 	ASSERT(MUTEX_HELD(&fcsm->sm_mutex));
2603fcf3ce44SJohn Forte 
2604fcf3ce44SJohn Forte 	if (fcsm->sm_job_head == NULL) {
2605fcf3ce44SJohn Forte 		ASSERT(fcsm->sm_job_tail == NULL);
2606fcf3ce44SJohn Forte 		job = NULL;
2607fcf3ce44SJohn Forte 	} else {
2608fcf3ce44SJohn Forte 		ASSERT(fcsm->sm_job_tail != NULL);
2609fcf3ce44SJohn Forte 		job = fcsm->sm_job_head;
2610fcf3ce44SJohn Forte 		if (job->job_next == NULL) {
2611fcf3ce44SJohn Forte 			ASSERT(fcsm->sm_job_tail == job);
2612fcf3ce44SJohn Forte 			fcsm->sm_job_tail = NULL;
2613fcf3ce44SJohn Forte 		}
2614fcf3ce44SJohn Forte 		fcsm->sm_job_head = job->job_next;
2615fcf3ce44SJohn Forte 		job->job_next = NULL;
2616fcf3ce44SJohn Forte 	}
2617fcf3ce44SJohn Forte 
2618fcf3ce44SJohn Forte 	return (job);
2619fcf3ce44SJohn Forte }
2620fcf3ce44SJohn Forte 
2621fcf3ce44SJohn Forte 
2622fcf3ce44SJohn Forte /* Dedicated per port thread to process various commands */
2623fcf3ce44SJohn Forte static void
fcsm_job_thread(fcsm_t * fcsm)2624fcf3ce44SJohn Forte fcsm_job_thread(fcsm_t *fcsm)
2625fcf3ce44SJohn Forte {
2626fcf3ce44SJohn Forte 	fcsm_job_t	*job;
2627fcf3ce44SJohn Forte 
2628fcf3ce44SJohn Forte 	ASSERT(fcsm != NULL);
2629fcf3ce44SJohn Forte #ifndef __lock_lint
2630fcf3ce44SJohn Forte 	CALLB_CPR_INIT(&fcsm->sm_cpr_info, &fcsm->sm_mutex,
2631fcf3ce44SJohn Forte 	    callb_generic_cpr, "fcsm_job_thread");
2632fcf3ce44SJohn Forte #endif /* __lock_lint */
2633fcf3ce44SJohn Forte 
2634fcf3ce44SJohn Forte 	for (;;) {
2635fcf3ce44SJohn Forte 		mutex_enter(&fcsm->sm_mutex);
2636fcf3ce44SJohn Forte 
2637fcf3ce44SJohn Forte 		while (fcsm->sm_job_head == NULL ||
2638fcf3ce44SJohn Forte 		    fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD) {
2639fcf3ce44SJohn Forte 			CALLB_CPR_SAFE_BEGIN(&fcsm->sm_cpr_info);
2640fcf3ce44SJohn Forte 			cv_wait(&fcsm->sm_job_cv, &fcsm->sm_mutex);
2641fcf3ce44SJohn Forte 			CALLB_CPR_SAFE_END(&fcsm->sm_cpr_info, &fcsm->sm_mutex);
2642fcf3ce44SJohn Forte 		}
2643fcf3ce44SJohn Forte 
2644fcf3ce44SJohn Forte 		job = fcsm_deque_job(fcsm);
2645fcf3ce44SJohn Forte 
2646fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
2647fcf3ce44SJohn Forte 
2648fcf3ce44SJohn Forte 		mutex_enter(&job->job_mutex);
2649fcf3ce44SJohn Forte 		if (job->job_flags & FCSM_JOBFLAG_SERIALIZE) {
2650fcf3ce44SJohn Forte 			mutex_exit(&job->job_mutex);
2651fcf3ce44SJohn Forte 
2652fcf3ce44SJohn Forte 			mutex_enter(&fcsm->sm_mutex);
2653fcf3ce44SJohn Forte 			ASSERT(!(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD));
2654fcf3ce44SJohn Forte 			fcsm->sm_flags |= FCSM_SERIALIZE_JOBTHREAD;
2655fcf3ce44SJohn Forte 			mutex_exit(&fcsm->sm_mutex);
2656fcf3ce44SJohn Forte 		} else {
2657fcf3ce44SJohn Forte 			mutex_exit(&job->job_mutex);
2658fcf3ce44SJohn Forte 		}
2659fcf3ce44SJohn Forte 
2660fcf3ce44SJohn Forte 		ASSERT(fcsm->sm_instance == job->job_port_instance);
2661fcf3ce44SJohn Forte 
2662fcf3ce44SJohn Forte 		switch (job->job_code) {
2663fcf3ce44SJohn Forte 		case FCSM_JOB_NONE:
2664fcf3ce44SJohn Forte 			fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
2665fcf3ce44SJohn Forte 			    "job_thread: uninitialized job code");
2666fcf3ce44SJohn Forte 			job->job_result = FC_FAILURE;
2667fcf3ce44SJohn Forte 			fcsm_jobdone(job);
2668fcf3ce44SJohn Forte 			break;
2669fcf3ce44SJohn Forte 
2670fcf3ce44SJohn Forte 		case FCSM_JOB_THREAD_SHUTDOWN:
2671fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2672fcf3ce44SJohn Forte 			    "job_thread: job code <JOB PORT SHUTDOWN>"));
2673fcf3ce44SJohn Forte 
2674fcf3ce44SJohn Forte 			/*
2675fcf3ce44SJohn Forte 			 * There should not be any pending jobs, when this
2676fcf3ce44SJohn Forte 			 * is being called.
2677fcf3ce44SJohn Forte 			 */
2678fcf3ce44SJohn Forte 			mutex_enter(&fcsm->sm_mutex);
2679fcf3ce44SJohn Forte 			ASSERT(fcsm->sm_job_head == NULL);
2680fcf3ce44SJohn Forte 			ASSERT(fcsm->sm_job_tail == NULL);
2681fcf3ce44SJohn Forte 			ASSERT(fcsm->sm_retry_head == NULL);
2682fcf3ce44SJohn Forte 			ASSERT(fcsm->sm_retry_tail == NULL);
2683fcf3ce44SJohn Forte 			job->job_result = FC_SUCCESS;
2684fcf3ce44SJohn Forte #ifndef __lock_lint
2685fcf3ce44SJohn Forte 			CALLB_CPR_EXIT(&fcsm->sm_cpr_info);
2686fcf3ce44SJohn Forte #endif
2687fcf3ce44SJohn Forte 			/* CPR_EXIT has also dropped the fcsm->sm_mutex */
2688fcf3ce44SJohn Forte 
2689fcf3ce44SJohn Forte 			fcsm_jobdone(job);
2690fcf3ce44SJohn Forte 			thread_exit();
2691fcf3ce44SJohn Forte 			/* NOTREACHED */
2692fcf3ce44SJohn Forte 			break;
2693fcf3ce44SJohn Forte 
2694fcf3ce44SJohn Forte 		case FCSM_JOB_LOGIN_NAME_SERVER:
2695fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2696fcf3ce44SJohn Forte 			    "job_thread: job code <LOGIN_NAME_SERVER>"));
2697fcf3ce44SJohn Forte 			job->job_result = FC_SUCCESS;
2698fcf3ce44SJohn Forte 			fcsm_jobdone(job);
2699fcf3ce44SJohn Forte 			break;
2700fcf3ce44SJohn Forte 
2701fcf3ce44SJohn Forte 		case FCSM_JOB_LOGIN_MGMT_SERVER:
2702fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2703fcf3ce44SJohn Forte 			    "job_thread: job code <LOGIN_MGMT_SERVER>"));
2704fcf3ce44SJohn Forte 			fcsm_job_login_mgmt_server(job);
2705fcf3ce44SJohn Forte 			break;
2706fcf3ce44SJohn Forte 
2707fcf3ce44SJohn Forte 		case FCSM_JOB_CT_PASSTHRU:
2708fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2709fcf3ce44SJohn Forte 			    "job_thread: job code <CT_PASSTHRU>"));
2710fcf3ce44SJohn Forte 			fcsm_job_ct_passthru(job);
2711fcf3ce44SJohn Forte 			break;
2712fcf3ce44SJohn Forte 
2713fcf3ce44SJohn Forte 		default:
2714fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2715fcf3ce44SJohn Forte 			    "job_thread: job code <UNKNOWN>"));
2716fcf3ce44SJohn Forte 			job->job_result = FC_FAILURE;
2717fcf3ce44SJohn Forte 			fcsm_jobdone(job);
2718fcf3ce44SJohn Forte 			break;
2719fcf3ce44SJohn Forte 		}
2720fcf3ce44SJohn Forte 	}
2721fcf3ce44SJohn Forte 
2722fcf3ce44SJohn Forte 	/* NOTREACHED */
2723fcf3ce44SJohn Forte }
2724fcf3ce44SJohn Forte 
2725fcf3ce44SJohn Forte 
2726fcf3ce44SJohn Forte 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)())2727fcf3ce44SJohn Forte fcsm_ct_init(fcsm_t *fcsm, fcsm_cmd_t *cmd, fc_ct_aiu_t *req_iu, size_t req_len,
2728fcf3ce44SJohn Forte     void (*comp_func)())
2729fcf3ce44SJohn Forte {
2730fcf3ce44SJohn Forte 	fc_packet_t	*pkt;
2731fcf3ce44SJohn Forte 
2732fcf3ce44SJohn Forte 	pkt = cmd->cmd_fp_pkt;
2733fcf3ce44SJohn Forte 	ASSERT(pkt != NULL);
2734fcf3ce44SJohn Forte 
2735fcf3ce44SJohn Forte 	ASSERT(req_iu->aiu_header.ct_fcstype == FCSTYPE_MGMTSERVICE ||
2736fcf3ce44SJohn Forte 	    (req_iu->aiu_header.ct_fcstype == FCSTYPE_DIRECTORY &&
2737fcf3ce44SJohn Forte 	    req_iu->aiu_header.ct_fcssubtype == FCSSUB_DS_NAME_SERVER));
2738fcf3ce44SJohn Forte 
2739fcf3ce44SJohn Forte 
2740fcf3ce44SJohn Forte 	/* Set the pkt d_id properly */
2741fcf3ce44SJohn Forte 	if (req_iu->aiu_header.ct_fcstype == FCSTYPE_MGMTSERVICE) {
2742fcf3ce44SJohn Forte 		pkt->pkt_cmd_fhdr.d_id	= FS_MANAGEMENT_SERVER;
2743fcf3ce44SJohn Forte 	} else {
2744fcf3ce44SJohn Forte 		pkt->pkt_cmd_fhdr.d_id	= FS_NAME_SERVER;
2745fcf3ce44SJohn Forte 	}
2746fcf3ce44SJohn Forte 
2747fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.r_ctl	= R_CTL_UNSOL_CONTROL;
2748fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.rsvd	= 0;
2749fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.s_id	= fcsm->sm_sid;
2750fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.type	= FC_TYPE_FC_SERVICES;
2751fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.f_ctl	= F_CTL_SEQ_INITIATIVE |
2752fcf3ce44SJohn Forte 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ;
2753fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.seq_id = 0;
2754fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.df_ctl = 0;
2755fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
2756fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
2757fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
2758fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.ro	= 0;
2759fcf3ce44SJohn Forte 
2760fcf3ce44SJohn Forte 	pkt->pkt_timeout	= FCSM_MS_TIMEOUT;
2761fcf3ce44SJohn Forte 	pkt->pkt_comp		= comp_func;
2762fcf3ce44SJohn Forte 
2763fcf3ce44SJohn Forte 	FCSM_REP_WR(pkt->pkt_cmd_acc, req_iu, pkt->pkt_cmd, req_len);
2764fcf3ce44SJohn Forte 
2765fcf3ce44SJohn Forte 	cmd->cmd_transport = fc_ulp_transport;
2766fcf3ce44SJohn Forte }
2767fcf3ce44SJohn Forte 
2768fcf3ce44SJohn Forte static void
fcsm_ct_intr(fcsm_cmd_t * cmd)2769fcf3ce44SJohn Forte fcsm_ct_intr(fcsm_cmd_t *cmd)
2770fcf3ce44SJohn Forte {
2771fcf3ce44SJohn Forte 	fc_packet_t	*pkt;
2772fcf3ce44SJohn Forte 	fcsm_job_t	*job;
2773fcf3ce44SJohn Forte 	fcio_t		*fcio;
27747ff83669SZhong Wang 	fcsm_t		*fcsm;
2775fcf3ce44SJohn Forte 
2776fcf3ce44SJohn Forte 	pkt = cmd->cmd_fp_pkt;
2777fcf3ce44SJohn Forte 	job = cmd->cmd_job;
2778fcf3ce44SJohn Forte 	ASSERT(job != NULL);
2779fcf3ce44SJohn Forte 
2780fcf3ce44SJohn Forte 	fcio = job->job_arg;
2781fcf3ce44SJohn Forte 	ASSERT(fcio != NULL);
2782fcf3ce44SJohn Forte 
2783fcf3ce44SJohn Forte 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
278440b706cfSMilan Jurik 		FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, cmd->cmd_fcsm, pkt,
2785fcf3ce44SJohn Forte 		    "ct_intr: CT command <0x%x> to did 0x%x failed",
2786fcf3ce44SJohn Forte 		    ((fc_ct_aiu_t *)fcio->fcio_ibuf)->aiu_header.ct_cmdrsp,
278740b706cfSMilan Jurik 		    pkt->pkt_cmd_fhdr.d_id));
2788fcf3ce44SJohn Forte 	} else {
2789fcf3ce44SJohn Forte 		/* Get the CT response payload */
27907ff83669SZhong Wang 		fcsm = cmd->cmd_fcsm;
2791fcf3ce44SJohn Forte 		FCSM_REP_RD(pkt->pkt_resp_acc, fcio->fcio_obuf,
2792fcf3ce44SJohn Forte 		    pkt->pkt_resp, fcio->fcio_olen);
2793fcf3ce44SJohn Forte 	}
2794fcf3ce44SJohn Forte 
2795fcf3ce44SJohn Forte 	job->job_result =
2796fcf3ce44SJohn Forte 	    fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
2797fcf3ce44SJohn Forte 
2798fcf3ce44SJohn Forte 	fcsm_free_cmd(cmd);
2799fcf3ce44SJohn Forte 
2800fcf3ce44SJohn Forte 	fcsm_jobdone(job);
2801fcf3ce44SJohn Forte }
2802fcf3ce44SJohn Forte 
2803fcf3ce44SJohn Forte 
2804fcf3ce44SJohn Forte static void
fcsm_job_ct_passthru(fcsm_job_t * job)2805fcf3ce44SJohn Forte fcsm_job_ct_passthru(fcsm_job_t *job)
2806fcf3ce44SJohn Forte {
2807fcf3ce44SJohn Forte 	fcsm_t		*fcsm;
2808fcf3ce44SJohn Forte 	fcio_t		*fcio;
2809fcf3ce44SJohn Forte 	fcsm_cmd_t	*cmd;
2810fcf3ce44SJohn Forte 	int		status;
2811fcf3ce44SJohn Forte 	fc_ct_header_t	*ct_header;
2812fcf3ce44SJohn Forte 
2813fcf3ce44SJohn Forte 	ASSERT(job != NULL);
2814fcf3ce44SJohn Forte 	ASSERT(job->job_port_instance != -1);
2815fcf3ce44SJohn Forte 
2816fcf3ce44SJohn Forte 	job->job_result = FC_FAILURE;
2817fcf3ce44SJohn Forte 	fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
2818fcf3ce44SJohn Forte 	if (fcsm == NULL) {
2819fcf3ce44SJohn Forte 		fcsm_jobdone(job);
2820fcf3ce44SJohn Forte 		return;
2821fcf3ce44SJohn Forte 	}
2822fcf3ce44SJohn Forte 
2823fcf3ce44SJohn Forte 	/*
2824fcf3ce44SJohn Forte 	 * Process the CT Passthru job only if port is attached
2825fcf3ce44SJohn Forte 	 * to a FABRIC.
2826fcf3ce44SJohn Forte 	 */
2827fcf3ce44SJohn Forte 	if (!FC_TOP_EXTERNAL(fcsm->sm_port_top)) {
2828fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2829fcf3ce44SJohn Forte 		    "job_ct_passthru: end (non-fabric port)"));
2830fcf3ce44SJohn Forte 		job->job_result = FC_BADDEV;
2831fcf3ce44SJohn Forte 		fcsm_jobdone(job);
2832fcf3ce44SJohn Forte 		return;
2833fcf3ce44SJohn Forte 	}
2834fcf3ce44SJohn Forte 
2835fcf3ce44SJohn Forte 	fcio = job->job_arg;
2836fcf3ce44SJohn Forte 	ASSERT(fcio != NULL);
2837fcf3ce44SJohn Forte 
2838fcf3ce44SJohn Forte 	/*
2839fcf3ce44SJohn Forte 	 * If it is NOT a Management Seriver (MS) or Name Server (NS) command
2840fcf3ce44SJohn Forte 	 * then complete the command with failure.
2841fcf3ce44SJohn Forte 	 */
2842fcf3ce44SJohn Forte 	ct_header = (fc_ct_header_t *)fcio->fcio_ibuf;
2843fcf3ce44SJohn Forte 
2844fcf3ce44SJohn Forte 	/*
2845fcf3ce44SJohn Forte 	 * According to libHBAAPI spec, CT header from libHBAAPI would always
2846fcf3ce44SJohn Forte 	 * be big endian, so we must swap CT header before continue in little
2847fcf3ce44SJohn Forte 	 * endian platforms.
2848fcf3ce44SJohn Forte 	 */
2849fcf3ce44SJohn Forte 	mutex_enter(&job->job_mutex);
2850fcf3ce44SJohn Forte 	if (!(job->job_flags & FCSM_JOBFLAG_CTHEADER_BE)) {
2851fcf3ce44SJohn Forte 		job->job_flags |= FCSM_JOBFLAG_CTHEADER_BE;
2852fcf3ce44SJohn Forte 		*((uint32_t *)((uint32_t *)ct_header + 0)) =
2853fcf3ce44SJohn Forte 		    BE_32(*((uint32_t *)((uint32_t *)ct_header + 0)));
2854fcf3ce44SJohn Forte 		*((uint32_t *)((uint32_t *)ct_header + 1)) =
2855fcf3ce44SJohn Forte 		    BE_32(*((uint32_t *)((uint32_t *)ct_header + 1)));
2856fcf3ce44SJohn Forte 		*((uint32_t *)((uint32_t *)ct_header + 2)) =
2857fcf3ce44SJohn Forte 		    BE_32(*((uint32_t *)((uint32_t *)ct_header + 2)));
2858fcf3ce44SJohn Forte 		*((uint32_t *)((uint32_t *)ct_header + 3)) =
2859fcf3ce44SJohn Forte 		    BE_32(*((uint32_t *)((uint32_t *)ct_header + 3)));
2860fcf3ce44SJohn Forte 	}
2861fcf3ce44SJohn Forte 	mutex_exit(&job->job_mutex);
2862fcf3ce44SJohn Forte 
2863fcf3ce44SJohn Forte 	if (ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) {
2864fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2865fcf3ce44SJohn Forte 		    "job_ct_passthru: Management Server Cmd"));
2866fcf3ce44SJohn Forte 	} else if (ct_header->ct_fcstype == FCSTYPE_DIRECTORY) {
2867fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2868fcf3ce44SJohn Forte 		    "job_ct_passthru: Name Server Cmd"));
2869fcf3ce44SJohn Forte 	} else {
2870fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2871fcf3ce44SJohn Forte 		    "job_ct_passthru: Unsupported Destination "
2872fcf3ce44SJohn Forte 		    "gs_type <0x%x> gs_subtype <0x%x>",
2873fcf3ce44SJohn Forte 		    ct_header->ct_fcstype, ct_header->ct_fcssubtype));
2874fcf3ce44SJohn Forte 	}
2875fcf3ce44SJohn Forte 
2876fcf3ce44SJohn Forte 	if (ct_header->ct_fcstype != FCSTYPE_MGMTSERVICE &&
2877fcf3ce44SJohn Forte 	    (ct_header->ct_fcstype != FCSTYPE_DIRECTORY ||
2878fcf3ce44SJohn Forte 	    ct_header->ct_fcssubtype != FCSSUB_DS_NAME_SERVER)) {
2879fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2880fcf3ce44SJohn Forte 		    "job_ct_passthru: end (Not a Name Server OR "
2881fcf3ce44SJohn Forte 		    "Mgmt Server Cmd)"));
2882fcf3ce44SJohn Forte 		job->job_result = FC_BADCMD;
2883fcf3ce44SJohn Forte 		fcsm_jobdone(job);
2884fcf3ce44SJohn Forte 		return;
2885fcf3ce44SJohn Forte 	}
2886fcf3ce44SJohn Forte 
2887fcf3ce44SJohn Forte 	/*
2888fcf3ce44SJohn Forte 	 * If it is an MS command and we are not logged in to the management
2889fcf3ce44SJohn Forte 	 * server, then start the login and requeue the command.
2890fcf3ce44SJohn Forte 	 * If login to management server is in progress, then reque the
2891fcf3ce44SJohn Forte 	 * command to wait for login to complete.
2892fcf3ce44SJohn Forte 	 */
2893fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
2894fcf3ce44SJohn Forte 	if ((ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) &&
2895fcf3ce44SJohn Forte 	    !(fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN)) {
2896fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
2897fcf3ce44SJohn Forte 		if (fcsm_login_and_process_job(fcsm, job) != FC_SUCCESS) {
2898fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2899fcf3ce44SJohn Forte 			    "job_ct_passthru: perform login failed"));
2900fcf3ce44SJohn Forte 			job->job_result = FC_FAILURE;
2901fcf3ce44SJohn Forte 			fcsm_jobdone(job);
2902fcf3ce44SJohn Forte 		}
2903fcf3ce44SJohn Forte 		return;
2904fcf3ce44SJohn Forte 	}
2905fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
2906fcf3ce44SJohn Forte 
2907fcf3ce44SJohn Forte 	/*
2908fcf3ce44SJohn Forte 	 * We are already logged in to the management server.
2909fcf3ce44SJohn Forte 	 * Issue the CT Passthru command
2910fcf3ce44SJohn Forte 	 */
2911fcf3ce44SJohn Forte 	cmd = fcsm_alloc_cmd(fcsm, fcio->fcio_ilen, fcio->fcio_olen, KM_SLEEP);
2912fcf3ce44SJohn Forte 	if (cmd == NULL) {
2913fcf3ce44SJohn Forte 		job->job_result = FC_NOMEM;
2914fcf3ce44SJohn Forte 		fcsm_jobdone(job);
2915fcf3ce44SJohn Forte 		return;
2916fcf3ce44SJohn Forte 	}
2917fcf3ce44SJohn Forte 
2918fcf3ce44SJohn Forte 	FCSM_INIT_CMD(cmd, job, FC_TRAN_INTR | FC_TRAN_CLASS3, FC_PKT_EXCHANGE,
2919fcf3ce44SJohn Forte 	    fcsm_max_cmd_retries, fcsm_ct_intr);
2920fcf3ce44SJohn Forte 
2921fcf3ce44SJohn Forte 	fcsm_ct_init(fcsm, cmd, (fc_ct_aiu_t *)fcio->fcio_ibuf, fcio->fcio_ilen,
2922fcf3ce44SJohn Forte 	    fcsm_pkt_common_intr);
2923fcf3ce44SJohn Forte 
2924fcf3ce44SJohn Forte 	if ((status = fcsm_issue_cmd(cmd)) != FC_SUCCESS) {
2925fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
2926fcf3ce44SJohn Forte 		    "job_ct_passthru: issue CT Passthru failed, status 0x%x",
2927fcf3ce44SJohn Forte 		    status));
2928fcf3ce44SJohn Forte 		job->job_result = status;
2929fcf3ce44SJohn Forte 		fcsm_free_cmd(cmd);
2930fcf3ce44SJohn Forte 		fcsm_jobdone(job);
2931fcf3ce44SJohn Forte 		return;
2932fcf3ce44SJohn Forte 	}
2933fcf3ce44SJohn Forte }
2934fcf3ce44SJohn Forte 
2935fcf3ce44SJohn Forte static int
fcsm_login_and_process_job(fcsm_t * fcsm,fcsm_job_t * orig_job)2936fcf3ce44SJohn Forte fcsm_login_and_process_job(fcsm_t *fcsm, fcsm_job_t *orig_job)
2937fcf3ce44SJohn Forte {
2938fcf3ce44SJohn Forte 	fcsm_job_t	*login_job;
2939fcf3ce44SJohn Forte #ifdef DEBUG
2940fcf3ce44SJohn Forte 	int		status;
2941fcf3ce44SJohn Forte #endif /* DEBUG */
2942fcf3ce44SJohn Forte 
2943fcf3ce44SJohn Forte 	if (orig_job->job_code != FCSM_JOB_CT_PASSTHRU) {
2944fcf3ce44SJohn Forte 		return (FC_FAILURE);
2945fcf3ce44SJohn Forte 	}
2946fcf3ce44SJohn Forte 
2947fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2948fcf3ce44SJohn Forte 	    "login_and_process_job: start login."));
2949fcf3ce44SJohn Forte 
2950fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
2951fcf3ce44SJohn Forte 	if (fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN) {
2952fcf3ce44SJohn Forte 		/*
2953fcf3ce44SJohn Forte 		 * Directory server login completed just now, while the
2954fcf3ce44SJohn Forte 		 * mutex was dropped. Just queue the command again for
2955fcf3ce44SJohn Forte 		 * processing.
2956fcf3ce44SJohn Forte 		 */
2957fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
2958fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2959fcf3ce44SJohn Forte 		    "login_and_process_job: got job 0x%p. login just "
2960fcf3ce44SJohn Forte 		    "completed", (void *)orig_job));
2961fcf3ce44SJohn Forte 		fcsm_enque_job(fcsm, orig_job, 0);
2962fcf3ce44SJohn Forte 		return (FC_SUCCESS);
2963fcf3ce44SJohn Forte 	}
2964fcf3ce44SJohn Forte 
2965fcf3ce44SJohn Forte 	if (fcsm->sm_flags & FCSM_MGMT_SERVER_LOGIN_IN_PROG) {
2966fcf3ce44SJohn Forte 		/*
2967fcf3ce44SJohn Forte 		 * Ideally we shouldn't have come here, since login
2968fcf3ce44SJohn Forte 		 * job has the serialize flag set.
2969fcf3ce44SJohn Forte 		 * Anyway, put the command back on the queue.
2970fcf3ce44SJohn Forte 		 */
2971fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
2972fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2973fcf3ce44SJohn Forte 		    "login_and_process_job: got job 0x%p while login to "
2974fcf3ce44SJohn Forte 		    "management server in progress", (void *)orig_job));
2975fcf3ce44SJohn Forte 		fcsm_enque_job(fcsm, orig_job, 0);
2976fcf3ce44SJohn Forte 		return (FC_SUCCESS);
2977fcf3ce44SJohn Forte 	}
2978fcf3ce44SJohn Forte 
2979fcf3ce44SJohn Forte 	fcsm->sm_flags |= FCSM_MGMT_SERVER_LOGIN_IN_PROG;
2980fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
2981fcf3ce44SJohn Forte 
2982fcf3ce44SJohn Forte 	login_job = fcsm_alloc_job(KM_SLEEP);
2983fcf3ce44SJohn Forte 	ASSERT(login_job != NULL);
2984fcf3ce44SJohn Forte 
2985fcf3ce44SJohn Forte 	/*
2986fcf3ce44SJohn Forte 	 * Mark the login job as SERIALIZE, so that all other jobs will
2987fcf3ce44SJohn Forte 	 * be processed after completing the login.
2988fcf3ce44SJohn Forte 	 * Save the original job (CT Passthru job) in the caller private
2989fcf3ce44SJohn Forte 	 * field in the job structure, so that CT command can be issued
2990fcf3ce44SJohn Forte 	 * after login has completed.
2991fcf3ce44SJohn Forte 	 */
2992fcf3ce44SJohn Forte 	fcsm_init_job(login_job, fcsm->sm_instance, FCSM_JOB_LOGIN_MGMT_SERVER,
2993fcf3ce44SJohn Forte 	    FCSM_JOBFLAG_ASYNC | FCSM_JOBFLAG_SERIALIZE,
2994fcf3ce44SJohn Forte 	    (opaque_t)NULL, (opaque_t)orig_job, fcsm_login_ms_comp, NULL);
2995fcf3ce44SJohn Forte 	orig_job->job_priv = (void *)login_job;
2996fcf3ce44SJohn Forte 
2997fcf3ce44SJohn Forte #ifdef DEBUG
2998fcf3ce44SJohn Forte 	status = fcsm_process_job(login_job, 1);
2999fcf3ce44SJohn Forte 	ASSERT(status == FC_SUCCESS);
3000fcf3ce44SJohn Forte #else /* DEBUG */
3001fcf3ce44SJohn Forte 	(void) fcsm_process_job(login_job, 1);
3002fcf3ce44SJohn Forte #endif /* DEBUG */
3003fcf3ce44SJohn Forte 	return (FC_SUCCESS);
3004fcf3ce44SJohn Forte }
3005fcf3ce44SJohn Forte 
3006fcf3ce44SJohn Forte 
3007fcf3ce44SJohn Forte /* ARGSUSED */
3008fcf3ce44SJohn Forte static void
fcsm_login_ms_comp(opaque_t comp_arg,fcsm_job_t * login_job,int result)3009fcf3ce44SJohn Forte fcsm_login_ms_comp(opaque_t comp_arg, fcsm_job_t *login_job, int result)
3010fcf3ce44SJohn Forte {
3011fcf3ce44SJohn Forte 	fcsm_t		*fcsm;
3012fcf3ce44SJohn Forte 	fcsm_job_t	*orig_job;
3013fcf3ce44SJohn Forte 
3014fcf3ce44SJohn Forte 	ASSERT(login_job != NULL);
3015fcf3ce44SJohn Forte 
3016fcf3ce44SJohn Forte 	orig_job = (fcsm_job_t *)login_job->job_caller_priv;
3017fcf3ce44SJohn Forte 
3018fcf3ce44SJohn Forte 	ASSERT(orig_job != NULL);
3019fcf3ce44SJohn Forte 	ASSERT(orig_job->job_priv == (void *)login_job);
3020fcf3ce44SJohn Forte 	orig_job->job_priv = NULL;
3021fcf3ce44SJohn Forte 
3022fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3023fcf3ce44SJohn Forte 	    "login_ms_comp: result 0x%x", login_job->job_result));
3024fcf3ce44SJohn Forte 
3025fcf3ce44SJohn Forte 	/* Set the login flag in the per port fcsm structure */
3026fcf3ce44SJohn Forte 	ASSERT(login_job->job_port_instance == orig_job->job_port_instance);
3027fcf3ce44SJohn Forte 	fcsm = ddi_get_soft_state(fcsm_state, login_job->job_port_instance);
3028fcf3ce44SJohn Forte 	ASSERT(fcsm != NULL);
3029fcf3ce44SJohn Forte 
3030fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
3031fcf3ce44SJohn Forte 	ASSERT((fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN) == 0);
3032fcf3ce44SJohn Forte 	ASSERT(fcsm->sm_flags & FCSM_MGMT_SERVER_LOGIN_IN_PROG);
3033fcf3ce44SJohn Forte 	fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGIN_IN_PROG;
3034fcf3ce44SJohn Forte 	if (login_job->job_result != FC_SUCCESS) {
3035fcf3ce44SJohn Forte 		caddr_t	msg;
3036fcf3ce44SJohn Forte 
3037fcf3ce44SJohn Forte 		/*
3038fcf3ce44SJohn Forte 		 * Login failed. Complete the original job with FC_LOGINREQ
3039fcf3ce44SJohn Forte 		 * status. Retry of that job will cause login to be
3040fcf3ce44SJohn Forte 		 * retried.
3041fcf3ce44SJohn Forte 		 */
3042fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
3043fcf3ce44SJohn Forte 		orig_job->job_result = FC_LOGINREQ;
3044fcf3ce44SJohn Forte 		fcsm_jobdone(orig_job);
3045fcf3ce44SJohn Forte 
3046fcf3ce44SJohn Forte 		(void) fc_ulp_error(login_job->job_result, &msg);
3047fcf3ce44SJohn Forte 		fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
3048fcf3ce44SJohn Forte 		    "login_ms_comp: Management server login failed: <%s>", msg);
3049fcf3ce44SJohn Forte 		return;
3050fcf3ce44SJohn Forte 	}
3051fcf3ce44SJohn Forte 	fcsm->sm_flags |= FCSM_MGMT_SERVER_LOGGED_IN;
3052fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
3053fcf3ce44SJohn Forte 
3054fcf3ce44SJohn Forte 	/*
3055fcf3ce44SJohn Forte 	 * Queue the original job at the head of the queue for processing.
3056fcf3ce44SJohn Forte 	 */
3057fcf3ce44SJohn Forte 	fcsm_enque_job(fcsm, orig_job, 1);
3058fcf3ce44SJohn Forte }
3059fcf3ce44SJohn Forte 
3060fcf3ce44SJohn Forte 
3061fcf3ce44SJohn Forte static void
fcsm_els_init(fcsm_cmd_t * cmd,uint32_t d_id)3062fcf3ce44SJohn Forte fcsm_els_init(fcsm_cmd_t *cmd, uint32_t d_id)
3063fcf3ce44SJohn Forte {
3064fcf3ce44SJohn Forte 	fc_packet_t	*pkt;
3065fcf3ce44SJohn Forte 	fcsm_t		*fcsm;
3066fcf3ce44SJohn Forte 
3067fcf3ce44SJohn Forte 	fcsm = cmd->cmd_fcsm;
3068fcf3ce44SJohn Forte 	pkt = cmd->cmd_fp_pkt;
3069fcf3ce44SJohn Forte 	ASSERT(fcsm != NULL && pkt != NULL);
3070fcf3ce44SJohn Forte 
3071fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.r_ctl	= R_CTL_ELS_REQ;
3072fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.d_id	= d_id;
3073fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.rsvd	= 0;
3074fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.s_id	= fcsm->sm_sid;
3075fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.type	= FC_TYPE_EXTENDED_LS;
3076fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.f_ctl	= F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
3077fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.seq_id = 0;
3078fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.df_ctl = 0;
3079fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
3080fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
3081fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
3082fcf3ce44SJohn Forte 	pkt->pkt_cmd_fhdr.ro	= 0;
3083fcf3ce44SJohn Forte 
3084fcf3ce44SJohn Forte 	pkt->pkt_timeout	= FCSM_ELS_TIMEOUT;
3085fcf3ce44SJohn Forte }
3086fcf3ce44SJohn Forte 
3087fcf3ce44SJohn Forte 
3088fcf3ce44SJohn Forte static int
fcsm_xlogi_init(fcsm_t * fcsm,fcsm_cmd_t * cmd,uint32_t d_id,void (* comp_func)(),uchar_t ls_code)3089fcf3ce44SJohn Forte fcsm_xlogi_init(fcsm_t *fcsm, fcsm_cmd_t *cmd, uint32_t d_id,
3090fcf3ce44SJohn Forte     void (*comp_func)(), uchar_t ls_code)
3091fcf3ce44SJohn Forte {
3092fcf3ce44SJohn Forte 	ls_code_t	payload;
3093fcf3ce44SJohn Forte 	fc_packet_t	*pkt;
3094fcf3ce44SJohn Forte 	la_els_logi_t	*login_params;
3095fcf3ce44SJohn Forte 	int		status;
3096fcf3ce44SJohn Forte 
3097fcf3ce44SJohn Forte 	login_params = (la_els_logi_t *)
3098fcf3ce44SJohn Forte 	    kmem_zalloc(sizeof (la_els_logi_t), KM_SLEEP);
3099fcf3ce44SJohn Forte 	if (login_params == NULL) {
3100fcf3ce44SJohn Forte 		return (FC_NOMEM);
3101fcf3ce44SJohn Forte 	}
3102fcf3ce44SJohn Forte 
3103fcf3ce44SJohn Forte 	status = fc_ulp_get_port_login_params(fcsm->sm_port_info.port_handle,
3104fcf3ce44SJohn Forte 	    login_params);
3105fcf3ce44SJohn Forte 	if (status != FC_SUCCESS) {
3106fcf3ce44SJohn Forte 		kmem_free(login_params, sizeof (la_els_logi_t));
3107fcf3ce44SJohn Forte 		return (status);
3108fcf3ce44SJohn Forte 	}
3109fcf3ce44SJohn Forte 
3110fcf3ce44SJohn Forte 	pkt = cmd->cmd_fp_pkt;
3111fcf3ce44SJohn Forte 
3112fcf3ce44SJohn Forte 	fcsm_els_init(cmd, d_id);
3113fcf3ce44SJohn Forte 	pkt->pkt_comp = comp_func;
3114fcf3ce44SJohn Forte 
3115fcf3ce44SJohn Forte 	payload.ls_code = ls_code;
3116fcf3ce44SJohn Forte 	payload.mbz = 0;
3117fcf3ce44SJohn Forte 
3118fcf3ce44SJohn Forte 	FCSM_REP_WR(pkt->pkt_cmd_acc, login_params,
3119fcf3ce44SJohn Forte 	    pkt->pkt_cmd, sizeof (la_els_logi_t));
3120fcf3ce44SJohn Forte 	FCSM_REP_WR(pkt->pkt_cmd_acc, &payload,
3121fcf3ce44SJohn Forte 	    pkt->pkt_cmd, sizeof (payload));
3122fcf3ce44SJohn Forte 
3123fcf3ce44SJohn Forte 	cmd->cmd_transport = fc_ulp_issue_els;
3124fcf3ce44SJohn Forte 
3125fcf3ce44SJohn Forte 	kmem_free(login_params, sizeof (la_els_logi_t));
3126fcf3ce44SJohn Forte 
3127fcf3ce44SJohn Forte 	return (FC_SUCCESS);
3128fcf3ce44SJohn Forte }
3129fcf3ce44SJohn Forte 
3130fcf3ce44SJohn Forte static void
fcsm_xlogi_intr(fcsm_cmd_t * cmd)3131fcf3ce44SJohn Forte fcsm_xlogi_intr(fcsm_cmd_t *cmd)
3132fcf3ce44SJohn Forte {
3133fcf3ce44SJohn Forte 	fc_packet_t	*pkt;
3134fcf3ce44SJohn Forte 	fcsm_job_t	*job;
3135fcf3ce44SJohn Forte 	fcsm_t		*fcsm;
3136fcf3ce44SJohn Forte 
3137fcf3ce44SJohn Forte 	pkt = cmd->cmd_fp_pkt;
3138fcf3ce44SJohn Forte 	job = cmd->cmd_job;
3139fcf3ce44SJohn Forte 	ASSERT(job != NULL);
3140fcf3ce44SJohn Forte 
3141fcf3ce44SJohn Forte 	fcsm = cmd->cmd_fcsm;
3142fcf3ce44SJohn Forte 	ASSERT(fcsm != NULL);
3143fcf3ce44SJohn Forte 
3144fcf3ce44SJohn Forte 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
3145fcf3ce44SJohn Forte 		fcsm_display(CE_WARN, SM_LOG, fcsm, pkt,
3146fcf3ce44SJohn Forte 		    "xlogi_intr: login to DID 0x%x failed",
3147fcf3ce44SJohn Forte 		    pkt->pkt_cmd_fhdr.d_id);
3148fcf3ce44SJohn Forte 	} else {
3149fcf3ce44SJohn Forte 		/* Get the Login parameters of the Management Server */
3150fcf3ce44SJohn Forte 		FCSM_REP_RD(pkt->pkt_resp_acc, &fcsm->sm_ms_service_params,
3151fcf3ce44SJohn Forte 		    pkt->pkt_resp, sizeof (la_els_logi_t));
3152fcf3ce44SJohn Forte 	}
3153fcf3ce44SJohn Forte 
3154fcf3ce44SJohn Forte 	job->job_result =
3155fcf3ce44SJohn Forte 	    fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
3156fcf3ce44SJohn Forte 
3157fcf3ce44SJohn Forte 	fcsm_free_cmd(cmd);
3158fcf3ce44SJohn Forte 
3159fcf3ce44SJohn Forte 	fcsm_jobdone(job);
3160fcf3ce44SJohn Forte }
3161fcf3ce44SJohn Forte 
3162fcf3ce44SJohn Forte static void
fcsm_job_login_mgmt_server(fcsm_job_t * job)3163fcf3ce44SJohn Forte fcsm_job_login_mgmt_server(fcsm_job_t *job)
3164fcf3ce44SJohn Forte {
3165fcf3ce44SJohn Forte 	fcsm_t		*fcsm;
3166fcf3ce44SJohn Forte 	fcsm_cmd_t	*cmd;
3167fcf3ce44SJohn Forte 	int		status;
3168fcf3ce44SJohn Forte 
3169fcf3ce44SJohn Forte 	ASSERT(job != NULL);
3170fcf3ce44SJohn Forte 	ASSERT(job->job_port_instance != -1);
3171fcf3ce44SJohn Forte 
3172fcf3ce44SJohn Forte 	fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
3173fcf3ce44SJohn Forte 	if (fcsm == NULL) {
3174fcf3ce44SJohn Forte 		job->job_result = FC_NOMEM;
3175fcf3ce44SJohn Forte 		fcsm_jobdone(job);
3176fcf3ce44SJohn Forte 		return;
3177fcf3ce44SJohn Forte 	}
3178fcf3ce44SJohn Forte 
3179fcf3ce44SJohn Forte 	/*
3180fcf3ce44SJohn Forte 	 * Issue the  Login command to the management server.
3181fcf3ce44SJohn Forte 	 */
3182fcf3ce44SJohn Forte 	cmd = fcsm_alloc_cmd(fcsm, sizeof (la_els_logi_t),
3183fcf3ce44SJohn Forte 	    sizeof (la_els_logi_t), KM_SLEEP);
3184fcf3ce44SJohn Forte 	if (cmd == NULL) {
3185fcf3ce44SJohn Forte 		job->job_result = FC_NOMEM;
3186fcf3ce44SJohn Forte 		fcsm_jobdone(job);
3187fcf3ce44SJohn Forte 		return;
3188fcf3ce44SJohn Forte 	}
3189fcf3ce44SJohn Forte 
3190fcf3ce44SJohn Forte 	FCSM_INIT_CMD(cmd, job, FC_TRAN_INTR | FC_TRAN_CLASS3, FC_PKT_EXCHANGE,
3191fcf3ce44SJohn Forte 	    fcsm_max_cmd_retries, fcsm_xlogi_intr);
3192fcf3ce44SJohn Forte 
3193fcf3ce44SJohn Forte 	status = fcsm_xlogi_init(fcsm, cmd, FS_MANAGEMENT_SERVER,
3194fcf3ce44SJohn Forte 	    fcsm_pkt_common_intr, LA_ELS_PLOGI);
3195fcf3ce44SJohn Forte 
3196fcf3ce44SJohn Forte 	if (status != FC_SUCCESS) {
3197fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
3198fcf3ce44SJohn Forte 		    "job_login_mgmt_server: plogi init failed. status 0x%x",
3199fcf3ce44SJohn Forte 		    status));
3200fcf3ce44SJohn Forte 		job->job_result = status;
3201fcf3ce44SJohn Forte 		fcsm_free_cmd(cmd);
3202fcf3ce44SJohn Forte 		fcsm_jobdone(job);
3203fcf3ce44SJohn Forte 		return;
3204fcf3ce44SJohn Forte 	}
3205fcf3ce44SJohn Forte 
3206fcf3ce44SJohn Forte 	if ((status = fcsm_issue_cmd(cmd)) != FC_SUCCESS) {
3207fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
3208fcf3ce44SJohn Forte 		    "job_ct_passthru: issue login cmd failed, status 0x%x",
3209fcf3ce44SJohn Forte 		    status));
3210fcf3ce44SJohn Forte 		job->job_result = status;
3211fcf3ce44SJohn Forte 		fcsm_free_cmd(cmd);
3212fcf3ce44SJohn Forte 		fcsm_jobdone(job);
3213fcf3ce44SJohn Forte 		return;
3214fcf3ce44SJohn Forte 	}
3215fcf3ce44SJohn Forte }
3216fcf3ce44SJohn Forte 
3217fcf3ce44SJohn Forte 
3218fcf3ce44SJohn Forte int
fcsm_ct_passthru(int instance,fcio_t * fcio,int sleep,int job_flags,void (* func)(fcio_t *))3219fcf3ce44SJohn Forte fcsm_ct_passthru(int instance, fcio_t *fcio, int sleep, int job_flags,
3220fcf3ce44SJohn Forte     void (*func)(fcio_t *))
3221fcf3ce44SJohn Forte {
3222fcf3ce44SJohn Forte 	fcsm_job_t	*job;
3223fcf3ce44SJohn Forte 	int		status;
3224fcf3ce44SJohn Forte 
3225fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3226fcf3ce44SJohn Forte 	    "ct_passthru: instance 0x%x fcio 0x%p", instance, fcio));
3227fcf3ce44SJohn Forte 	job = fcsm_alloc_job(sleep);
3228fcf3ce44SJohn Forte 	ASSERT(sleep == KM_NOSLEEP || job != NULL);
3229fcf3ce44SJohn Forte 
3230fcf3ce44SJohn Forte 	fcsm_init_job(job, instance, FCSM_JOB_CT_PASSTHRU, job_flags,
3231fcf3ce44SJohn Forte 	    (opaque_t)fcio, (opaque_t)func, fcsm_ct_passthru_comp, NULL);
3232fcf3ce44SJohn Forte 	status = fcsm_process_job(job, 0);
3233fcf3ce44SJohn Forte 	if (status != FC_SUCCESS) {
3234fcf3ce44SJohn Forte 		/* Job could not be issued. So free the job and return */
3235fcf3ce44SJohn Forte 		fcsm_dealloc_job(job);
3236fcf3ce44SJohn Forte 		return (status);
3237fcf3ce44SJohn Forte 	}
3238fcf3ce44SJohn Forte 
3239fcf3ce44SJohn Forte 	if (job_flags & FCSM_JOBFLAG_SYNC) {
3240fcf3ce44SJohn Forte 		status = job->job_result;
3241fcf3ce44SJohn Forte 		fcsm_dealloc_job(job);
3242fcf3ce44SJohn Forte 	}
3243fcf3ce44SJohn Forte 
3244fcf3ce44SJohn Forte 	return (status);
3245fcf3ce44SJohn Forte }
3246fcf3ce44SJohn Forte 
3247fcf3ce44SJohn Forte 
3248fcf3ce44SJohn Forte /* ARGSUSED */
3249fcf3ce44SJohn Forte static void
fcsm_ct_passthru_comp(opaque_t comp_arg,fcsm_job_t * job,int result)3250fcf3ce44SJohn Forte fcsm_ct_passthru_comp(opaque_t comp_arg, fcsm_job_t *job, int result)
3251fcf3ce44SJohn Forte {
3252fcf3ce44SJohn Forte 	ASSERT(job != NULL);
3253fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3254fcf3ce44SJohn Forte 	    "ct_passthru_comp: result 0x%x port 0x%x",
3255fcf3ce44SJohn Forte 	    job->job_result, job->job_port_instance));
3256fcf3ce44SJohn Forte }
3257fcf3ce44SJohn Forte 
3258fcf3ce44SJohn Forte 
3259fcf3ce44SJohn Forte static void
fcsm_pkt_common_intr(fc_packet_t * pkt)3260fcf3ce44SJohn Forte fcsm_pkt_common_intr(fc_packet_t *pkt)
3261fcf3ce44SJohn Forte {
3262fcf3ce44SJohn Forte 	fcsm_cmd_t	*cmd;
3263fcf3ce44SJohn Forte 	int		jobstatus;
3264fcf3ce44SJohn Forte 	fcsm_t		*fcsm;
3265fcf3ce44SJohn Forte 
3266fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3267fcf3ce44SJohn Forte 	    "pkt_common_intr"));
3268fcf3ce44SJohn Forte 
3269fcf3ce44SJohn Forte 	cmd = (fcsm_cmd_t *)pkt->pkt_ulp_private;
3270fcf3ce44SJohn Forte 	ASSERT(cmd != NULL);
3271fcf3ce44SJohn Forte 
3272fcf3ce44SJohn Forte 	if (pkt->pkt_state == FC_PKT_SUCCESS) {
3273fcf3ce44SJohn Forte 		/* Command completed successfully. Just complete the command */
3274fcf3ce44SJohn Forte 		cmd->cmd_comp(cmd);
3275fcf3ce44SJohn Forte 		return;
3276fcf3ce44SJohn Forte 	}
3277fcf3ce44SJohn Forte 
3278fcf3ce44SJohn Forte 	fcsm = cmd->cmd_fcsm;
3279fcf3ce44SJohn Forte 	ASSERT(fcsm != NULL);
3280fcf3ce44SJohn Forte 
328140b706cfSMilan Jurik 	FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, cmd->cmd_fcsm, pkt,
3282fcf3ce44SJohn Forte 	    "fc packet to DID 0x%x failed for pkt 0x%p",
328340b706cfSMilan Jurik 	    pkt->pkt_cmd_fhdr.d_id, pkt));
3284fcf3ce44SJohn Forte 
3285fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
3286fcf3ce44SJohn Forte 	if (fcsm->sm_flags & FCSM_LINK_DOWN) {
3287fcf3ce44SJohn Forte 		/*
3288fcf3ce44SJohn Forte 		 * No need to retry the command. The link previously
32897ff83669SZhong Wang 		 * suffered an offline	timeout.
3290fcf3ce44SJohn Forte 		 */
3291fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
3292fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
3293fcf3ce44SJohn Forte 		    "pkt_common_intr: end. Link is down"));
3294fcf3ce44SJohn Forte 		cmd->cmd_comp(cmd);
3295fcf3ce44SJohn Forte 		return;
3296fcf3ce44SJohn Forte 	}
3297fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
3298fcf3ce44SJohn Forte 
3299fcf3ce44SJohn Forte 	jobstatus = fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
3300fcf3ce44SJohn Forte 	if (jobstatus == FC_LOGINREQ) {
3301fcf3ce44SJohn Forte 		/*
3302fcf3ce44SJohn Forte 		 * Login to the destination is required. No need to
3303fcf3ce44SJohn Forte 		 * retry this cmd again.
3304fcf3ce44SJohn Forte 		 */
3305fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
3306fcf3ce44SJohn Forte 		    "pkt_common_intr: end. LOGIN required"));
3307fcf3ce44SJohn Forte 		cmd->cmd_comp(cmd);
3308fcf3ce44SJohn Forte 		return;
3309fcf3ce44SJohn Forte 	}
3310fcf3ce44SJohn Forte 
3311fcf3ce44SJohn Forte 	switch (pkt->pkt_state) {
3312fcf3ce44SJohn Forte 	case FC_PKT_PORT_OFFLINE:
3313fcf3ce44SJohn Forte 	case FC_PKT_LOCAL_RJT:
3314fcf3ce44SJohn Forte 	case FC_PKT_TIMEOUT: {
3315fcf3ce44SJohn Forte 		uchar_t		pkt_state;
3316fcf3ce44SJohn Forte 
3317fcf3ce44SJohn Forte 		pkt_state = pkt->pkt_state;
3318fcf3ce44SJohn Forte 		cmd->cmd_retry_interval = fcsm_retry_interval;
3319fcf3ce44SJohn Forte 		if (fcsm_retry_cmd(cmd) != 0) {
3320fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG,
3321fcf3ce44SJohn Forte 			    cmd->cmd_fcsm, NULL,
3322fcf3ce44SJohn Forte 			    "common_intr: max retries(%d) reached, status 0x%x",
3323fcf3ce44SJohn Forte 			    cmd->cmd_retry_count));
3324fcf3ce44SJohn Forte 
3325fcf3ce44SJohn Forte 			/*
3326fcf3ce44SJohn Forte 			 * Restore the pkt_state to the actual failure status
3327fcf3ce44SJohn Forte 			 * received at the time of pkt completion.
3328fcf3ce44SJohn Forte 			 */
3329fcf3ce44SJohn Forte 			pkt->pkt_state = pkt_state;
3330fcf3ce44SJohn Forte 			pkt->pkt_reason = 0;
3331fcf3ce44SJohn Forte 			cmd->cmd_comp(cmd);
3332fcf3ce44SJohn Forte 		} else {
3333fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG,
3334fcf3ce44SJohn Forte 			    cmd->cmd_fcsm, NULL,
3335fcf3ce44SJohn Forte 			    "pkt_common_intr: retry(%d) on pkt state (0x%x)",
3336fcf3ce44SJohn Forte 			    cmd->cmd_retry_count, pkt_state));
3337fcf3ce44SJohn Forte 		}
3338fcf3ce44SJohn Forte 		break;
3339fcf3ce44SJohn Forte 	}
3340fcf3ce44SJohn Forte 	default:
3341fcf3ce44SJohn Forte 		cmd->cmd_comp(cmd);
3342fcf3ce44SJohn Forte 		break;
3343fcf3ce44SJohn Forte 	}
3344fcf3ce44SJohn Forte }
3345fcf3ce44SJohn Forte 
3346fcf3ce44SJohn Forte static int
fcsm_issue_cmd(fcsm_cmd_t * cmd)3347fcf3ce44SJohn Forte fcsm_issue_cmd(fcsm_cmd_t *cmd)
3348fcf3ce44SJohn Forte {
3349fcf3ce44SJohn Forte 	fc_packet_t	*pkt;
3350fcf3ce44SJohn Forte 	fcsm_t		*fcsm;
3351fcf3ce44SJohn Forte 	int		status;
3352fcf3ce44SJohn Forte 
3353fcf3ce44SJohn Forte 	pkt = cmd->cmd_fp_pkt;
3354fcf3ce44SJohn Forte 	fcsm = cmd->cmd_fcsm;
3355fcf3ce44SJohn Forte 
3356fcf3ce44SJohn Forte 	/* Explicitly invalidate this field till fcsm decides to use it */
3357fcf3ce44SJohn Forte 	pkt->pkt_ulp_rscn_infop = NULL;
3358fcf3ce44SJohn Forte 
3359fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3360fcf3ce44SJohn Forte 	    "issue_cmd: entry"));
3361fcf3ce44SJohn Forte 
3362fcf3ce44SJohn Forte 	ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
3363fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
3364fcf3ce44SJohn Forte 	if (fcsm->sm_flags & FCSM_LINK_DOWN) {
3365fcf3ce44SJohn Forte 		/*
3366fcf3ce44SJohn Forte 		 * Update the pkt_state/pkt_reason appropriately.
3367fcf3ce44SJohn Forte 		 * Caller of this function can decide whether to call
3368fcf3ce44SJohn Forte 		 * 'pkt->pkt_comp' or use the 'status' returned by this func.
3369fcf3ce44SJohn Forte 		 */
3370fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
3371fcf3ce44SJohn Forte 		pkt->pkt_state = FC_PKT_PORT_OFFLINE;
3372fcf3ce44SJohn Forte 		pkt->pkt_reason = FC_REASON_OFFLINE;
3373fcf3ce44SJohn Forte 		return (FC_OFFLINE);
3374fcf3ce44SJohn Forte 	}
3375fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
3376fcf3ce44SJohn Forte 
3377fcf3ce44SJohn Forte 	ASSERT(cmd->cmd_transport != NULL);
3378fcf3ce44SJohn Forte 	status = cmd->cmd_transport(fcsm->sm_port_info.port_handle, pkt);
3379fcf3ce44SJohn Forte 	if (status != FC_SUCCESS) {
3380fcf3ce44SJohn Forte 		switch (status) {
3381fcf3ce44SJohn Forte 		case FC_LOGINREQ:
3382fcf3ce44SJohn Forte 			/*
3383fcf3ce44SJohn Forte 			 * No need to retry. Return the cause of failure.
3384fcf3ce44SJohn Forte 			 * Also update the pkt_state/pkt_reason. Caller of
3385fcf3ce44SJohn Forte 			 * this function can decide, whether to call
3386fcf3ce44SJohn Forte 			 * 'pkt->pkt_comp' or use the 'status' code returned
3387fcf3ce44SJohn Forte 			 * by this function.
3388fcf3ce44SJohn Forte 			 */
3389fcf3ce44SJohn Forte 			pkt->pkt_state = FC_PKT_LOCAL_RJT;
3390fcf3ce44SJohn Forte 			pkt->pkt_reason = FC_REASON_LOGIN_REQUIRED;
3391fcf3ce44SJohn Forte 			break;
3392fcf3ce44SJohn Forte 
3393fcf3ce44SJohn Forte 		case FC_DEVICE_BUSY_NEW_RSCN:
3394fcf3ce44SJohn Forte 			/*
3395fcf3ce44SJohn Forte 			 * There was a newer RSCN than what fcsm knows about.
3396fcf3ce44SJohn Forte 			 * So, just retry again
3397fcf3ce44SJohn Forte 			 */
3398fcf3ce44SJohn Forte 			cmd->cmd_retry_count = 0;
3399fcf3ce44SJohn Forte 			/*FALLTHROUGH*/
3400fcf3ce44SJohn Forte 		case FC_OFFLINE:
3401fcf3ce44SJohn Forte 		case FC_STATEC_BUSY:
3402fcf3ce44SJohn Forte 			/*
3403fcf3ce44SJohn Forte 			 * TODO: set flag, so that command is retried after
3404fcf3ce44SJohn Forte 			 * port is back online.
3405fcf3ce44SJohn Forte 			 * FALL Through for now.
3406fcf3ce44SJohn Forte 			 */
3407fcf3ce44SJohn Forte 
3408fcf3ce44SJohn Forte 		case FC_TRAN_BUSY:
3409fcf3ce44SJohn Forte 		case FC_NOMEM:
3410fcf3ce44SJohn Forte 		case FC_DEVICE_BUSY:
3411fcf3ce44SJohn Forte 			cmd->cmd_retry_interval = fcsm_retry_interval;
3412fcf3ce44SJohn Forte 			if (fcsm_retry_cmd(cmd) != 0) {
3413fcf3ce44SJohn Forte 				FCSM_DEBUG(SMDL_TRACE,
3414fcf3ce44SJohn Forte 				    (CE_WARN, SM_LOG, fcsm, NULL,
3415fcf3ce44SJohn Forte 				    "issue_cmd: max retries (%d) reached",
3416fcf3ce44SJohn Forte 				    cmd->cmd_retry_count));
3417fcf3ce44SJohn Forte 
3418fcf3ce44SJohn Forte 				/*
3419fcf3ce44SJohn Forte 				 * status variable is not changed here.
3420fcf3ce44SJohn Forte 				 * Return the cause of the original
3421fcf3ce44SJohn Forte 				 * cmd_transport failure.
3422fcf3ce44SJohn Forte 				 * Update the pkt_state/pkt_reason. Caller
3423fcf3ce44SJohn Forte 				 * of this function can decide whether to
3424fcf3ce44SJohn Forte 				 * call 'pkt->pkt_comp' or use the 'status'
3425fcf3ce44SJohn Forte 				 * code returned by this function.
3426fcf3ce44SJohn Forte 				 */
3427fcf3ce44SJohn Forte 				pkt->pkt_state = FC_PKT_TRAN_BSY;
3428fcf3ce44SJohn Forte 				pkt->pkt_reason = 0;
3429fcf3ce44SJohn Forte 			} else {
3430fcf3ce44SJohn Forte 				FCSM_DEBUG(SMDL_TRACE,
3431fcf3ce44SJohn Forte 				    (CE_WARN, SM_LOG, fcsm, NULL,
3432fcf3ce44SJohn Forte 				    "issue_cmd: retry (%d) on fc status (0x%x)",
3433fcf3ce44SJohn Forte 				    cmd->cmd_retry_count, status));
3434fcf3ce44SJohn Forte 
3435fcf3ce44SJohn Forte 				status = FC_SUCCESS;
3436fcf3ce44SJohn Forte 			}
3437fcf3ce44SJohn Forte 			break;
3438fcf3ce44SJohn Forte 
3439fcf3ce44SJohn Forte 		default:
3440fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
3441fcf3ce44SJohn Forte 			    "issue_cmd: failure status 0x%x", status));
3442fcf3ce44SJohn Forte 
3443fcf3ce44SJohn Forte 			pkt->pkt_state = FC_PKT_TRAN_ERROR;
3444fcf3ce44SJohn Forte 			pkt->pkt_reason = 0;
3445fcf3ce44SJohn Forte 			break;
3446fcf3ce44SJohn Forte 
3447fcf3ce44SJohn Forte 
3448fcf3ce44SJohn Forte 		}
3449fcf3ce44SJohn Forte 	}
3450fcf3ce44SJohn Forte 
3451fcf3ce44SJohn Forte 	return (status);
3452fcf3ce44SJohn Forte }
3453fcf3ce44SJohn Forte 
3454fcf3ce44SJohn Forte 
3455fcf3ce44SJohn Forte static int
fcsm_retry_cmd(fcsm_cmd_t * cmd)3456fcf3ce44SJohn Forte fcsm_retry_cmd(fcsm_cmd_t *cmd)
3457fcf3ce44SJohn Forte {
3458fcf3ce44SJohn Forte 	if (cmd->cmd_retry_count < cmd->cmd_max_retries) {
3459fcf3ce44SJohn Forte 		cmd->cmd_retry_count++;
3460fcf3ce44SJohn Forte 		fcsm_enque_cmd(cmd->cmd_fcsm, cmd);
3461fcf3ce44SJohn Forte 		return (0);
3462fcf3ce44SJohn Forte 	}
3463fcf3ce44SJohn Forte 
3464fcf3ce44SJohn Forte 	return (1);
3465fcf3ce44SJohn Forte }
3466fcf3ce44SJohn Forte 
3467fcf3ce44SJohn Forte static void
fcsm_enque_cmd(fcsm_t * fcsm,fcsm_cmd_t * cmd)3468fcf3ce44SJohn Forte fcsm_enque_cmd(fcsm_t *fcsm, fcsm_cmd_t *cmd)
3469fcf3ce44SJohn Forte {
3470fcf3ce44SJohn Forte 	ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
3471fcf3ce44SJohn Forte 
3472fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "enque_cmd"));
3473fcf3ce44SJohn Forte 
3474fcf3ce44SJohn Forte 	cmd->cmd_next = NULL;
3475fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
3476fcf3ce44SJohn Forte 	if (fcsm->sm_retry_tail) {
3477fcf3ce44SJohn Forte 		ASSERT(fcsm->sm_retry_head != NULL);
3478fcf3ce44SJohn Forte 		fcsm->sm_retry_tail->cmd_next = cmd;
3479fcf3ce44SJohn Forte 		fcsm->sm_retry_tail = cmd;
3480fcf3ce44SJohn Forte 	} else {
3481fcf3ce44SJohn Forte 		ASSERT(fcsm->sm_retry_tail == NULL);
3482fcf3ce44SJohn Forte 		fcsm->sm_retry_head = fcsm->sm_retry_tail = cmd;
3483fcf3ce44SJohn Forte 
3484fcf3ce44SJohn Forte 		/* Schedule retry thread, if not already running */
3485fcf3ce44SJohn Forte 		if (fcsm->sm_retry_tid == NULL) {
3486fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3487fcf3ce44SJohn Forte 			    "enque_cmd: schedule retry thread"));
3488fcf3ce44SJohn Forte 			fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
3489fcf3ce44SJohn Forte 			    (caddr_t)fcsm, fcsm_retry_ticks);
3490fcf3ce44SJohn Forte 		}
3491fcf3ce44SJohn Forte 	}
3492fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
3493fcf3ce44SJohn Forte }
3494fcf3ce44SJohn Forte 
3495fcf3ce44SJohn Forte 
3496fcf3ce44SJohn Forte static fcsm_cmd_t *
fcsm_deque_cmd(fcsm_t * fcsm)3497fcf3ce44SJohn Forte fcsm_deque_cmd(fcsm_t *fcsm)
3498fcf3ce44SJohn Forte {
3499fcf3ce44SJohn Forte 	fcsm_cmd_t	*cmd;
3500fcf3ce44SJohn Forte 
3501fcf3ce44SJohn Forte 	ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
3502fcf3ce44SJohn Forte 
3503fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "deque_cmd"));
3504fcf3ce44SJohn Forte 
3505fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
3506fcf3ce44SJohn Forte 	if (fcsm->sm_retry_head == NULL) {
3507fcf3ce44SJohn Forte 		ASSERT(fcsm->sm_retry_tail == NULL);
3508fcf3ce44SJohn Forte 		cmd = NULL;
3509fcf3ce44SJohn Forte 	} else {
3510fcf3ce44SJohn Forte 		cmd = fcsm->sm_retry_head;
3511fcf3ce44SJohn Forte 		fcsm->sm_retry_head = cmd->cmd_next;
3512fcf3ce44SJohn Forte 		if (fcsm->sm_retry_head == NULL) {
3513fcf3ce44SJohn Forte 			fcsm->sm_retry_tail = NULL;
3514fcf3ce44SJohn Forte 		}
3515fcf3ce44SJohn Forte 		cmd->cmd_next = NULL;
3516fcf3ce44SJohn Forte 	}
3517fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
3518fcf3ce44SJohn Forte 
3519fcf3ce44SJohn Forte 	return (cmd);
3520fcf3ce44SJohn Forte }
3521fcf3ce44SJohn Forte 
3522fcf3ce44SJohn Forte static void
fcsm_retry_timeout(void * handle)3523fcf3ce44SJohn Forte fcsm_retry_timeout(void *handle)
3524fcf3ce44SJohn Forte {
3525fcf3ce44SJohn Forte 	fcsm_t		*fcsm;
3526fcf3ce44SJohn Forte 	fcsm_cmd_t	*curr_tail;
3527fcf3ce44SJohn Forte 	fcsm_cmd_t	*cmd;
3528fcf3ce44SJohn Forte 	int		done = 0;
3529fcf3ce44SJohn Forte 	int		linkdown;
3530fcf3ce44SJohn Forte 
3531fcf3ce44SJohn Forte 	fcsm = (fcsm_t *)handle;
3532fcf3ce44SJohn Forte 
3533fcf3ce44SJohn Forte 	FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "retry_timeout"));
3534fcf3ce44SJohn Forte 
3535fcf3ce44SJohn Forte 	/*
3536fcf3ce44SJohn Forte 	 * If retry cmd queue is suspended, then go away.
3537fcf3ce44SJohn Forte 	 * This retry thread will be restarted, when cmd queue resumes.
3538fcf3ce44SJohn Forte 	 */
3539fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
3540fcf3ce44SJohn Forte 	if (fcsm->sm_flags & FCSM_CMD_RETRY_Q_SUSPENDED) {
3541fcf3ce44SJohn Forte 		/*
3542fcf3ce44SJohn Forte 		 * Clear the retry_tid, to indicate that this routine is not
3543fcf3ce44SJohn Forte 		 * currently being rescheduled.
3544fcf3ce44SJohn Forte 		 */
3545fcf3ce44SJohn Forte 		fcsm->sm_retry_tid = (timeout_id_t)NULL;
3546fcf3ce44SJohn Forte 		mutex_exit(&fcsm->sm_mutex);
3547fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3548fcf3ce44SJohn Forte 		    "retry_timeout: end. No processing. "
3549fcf3ce44SJohn Forte 		    "Queue is currently suspended for this instance"));
3550fcf3ce44SJohn Forte 		return;
3551fcf3ce44SJohn Forte 	}
3552fcf3ce44SJohn Forte 
3553fcf3ce44SJohn Forte 	linkdown = (fcsm->sm_flags & FCSM_LINK_DOWN) ? 1 : 0;
3554fcf3ce44SJohn Forte 
3555fcf3ce44SJohn Forte 	/*
3556fcf3ce44SJohn Forte 	 * Save the curr_tail, so that we only process the commands
3557fcf3ce44SJohn Forte 	 * which are in the queue at this time.
3558fcf3ce44SJohn Forte 	 */
3559fcf3ce44SJohn Forte 	curr_tail = fcsm->sm_retry_tail;
3560fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
3561fcf3ce44SJohn Forte 
3562fcf3ce44SJohn Forte 	/*
3563fcf3ce44SJohn Forte 	 * Check for done flag before dequeing the command.
3564fcf3ce44SJohn Forte 	 * Dequeing before checking the done flag will cause a command
3565fcf3ce44SJohn Forte 	 * to be lost.
3566fcf3ce44SJohn Forte 	 */
3567fcf3ce44SJohn Forte 	while ((!done) && ((cmd = fcsm_deque_cmd(fcsm)) != NULL)) {
3568fcf3ce44SJohn Forte 
3569fcf3ce44SJohn Forte 		if (cmd == curr_tail) {
3570fcf3ce44SJohn Forte 			done = 1;
3571fcf3ce44SJohn Forte 		}
3572fcf3ce44SJohn Forte 
3573fcf3ce44SJohn Forte 		cmd->cmd_retry_interval -= fcsm_retry_ticker;
3574fcf3ce44SJohn Forte 
3575fcf3ce44SJohn Forte 		if (linkdown) {
3576fcf3ce44SJohn Forte 			fc_packet_t *pkt;
3577fcf3ce44SJohn Forte 
3578fcf3ce44SJohn Forte 			/*
3579fcf3ce44SJohn Forte 			 * No need to retry the command. The link has
35807ff83669SZhong Wang 			 * suffered an offline	timeout.
3581fcf3ce44SJohn Forte 			 */
3582fcf3ce44SJohn Forte 			pkt = cmd->cmd_fp_pkt;
3583fcf3ce44SJohn Forte 			pkt->pkt_state = FC_PKT_PORT_OFFLINE;
3584fcf3ce44SJohn Forte 			pkt->pkt_reason = FC_REASON_OFFLINE;
3585fcf3ce44SJohn Forte 			pkt->pkt_comp(pkt);
3586fcf3ce44SJohn Forte 			continue;
3587fcf3ce44SJohn Forte 		}
3588fcf3ce44SJohn Forte 
3589fcf3ce44SJohn Forte 		if (cmd->cmd_retry_interval <= 0) {
3590fcf3ce44SJohn Forte 			/* Retry the command */
3591fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3592fcf3ce44SJohn Forte 			    "retry_timeout: issue cmd 0x%p", (void *)cmd));
3593fcf3ce44SJohn Forte 			if (fcsm_issue_cmd(cmd) != FC_SUCCESS) {
3594fcf3ce44SJohn Forte 				cmd->cmd_fp_pkt->pkt_comp(cmd->cmd_fp_pkt);
3595fcf3ce44SJohn Forte 			}
3596fcf3ce44SJohn Forte 		} else {
3597fcf3ce44SJohn Forte 			/*
3598fcf3ce44SJohn Forte 			 * Put the command back on the queue. Retry time
3599fcf3ce44SJohn Forte 			 * has not yet reached.
3600fcf3ce44SJohn Forte 			 */
3601fcf3ce44SJohn Forte 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3602fcf3ce44SJohn Forte 			    "retry_timeout: queue cmd 0x%p", (void *)cmd));
3603fcf3ce44SJohn Forte 			fcsm_enque_cmd(fcsm, cmd);
3604fcf3ce44SJohn Forte 		}
3605fcf3ce44SJohn Forte 	}
3606fcf3ce44SJohn Forte 
3607fcf3ce44SJohn Forte 	mutex_enter(&fcsm->sm_mutex);
3608fcf3ce44SJohn Forte 	if (fcsm->sm_retry_head) {
3609fcf3ce44SJohn Forte 		/* Activate timer */
3610fcf3ce44SJohn Forte 		fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
3611fcf3ce44SJohn Forte 		    (caddr_t)fcsm, fcsm_retry_ticks);
3612fcf3ce44SJohn Forte 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3613fcf3ce44SJohn Forte 		    "retry_timeout: retry thread rescheduled"));
3614fcf3ce44SJohn Forte 	} else {
3615fcf3ce44SJohn Forte 		/*
3616fcf3ce44SJohn Forte 		 * Reset the tid variable. The first thread which queues the
3617fcf3ce44SJohn Forte 		 * command, will restart the timer.
3618fcf3ce44SJohn Forte 		 */
3619fcf3ce44SJohn Forte 		fcsm->sm_retry_tid = (timeout_id_t)NULL;
3620fcf3ce44SJohn Forte 	}
3621fcf3ce44SJohn Forte 	mutex_exit(&fcsm->sm_mutex);
3622fcf3ce44SJohn Forte }
3623