1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Emulex.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <emlxs.h>
29 
30 #ifdef SFCT_SUPPORT
31 
32 
33 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
34 EMLXS_MSG_DEF(EMLXS_FCT_C);
35 
36 static fct_status_t emlxs_fct_cmd_acquire(emlxs_port_t *port,
37 	fct_cmd_t *fct_cmd, uint16_t fct_state);
38 static fct_status_t emlxs_fct_cmd_accept(emlxs_port_t *port,
39 	fct_cmd_t *fct_cmd, uint16_t fct_state);
40 static void emlxs_fct_cmd_release(emlxs_port_t *port, fct_cmd_t *fct_cmd,
41 	uint16_t fct_state);
42 
43 static void emlxs_fct_handle_acc(emlxs_port_t *port, emlxs_buf_t *sbp,
44     IOCBQ *iocbq);
45 static void emlxs_fct_handle_reject(emlxs_port_t *port, emlxs_buf_t *sbp,
46     IOCBQ *iocbq);
47 static emlxs_buf_t *emlxs_fct_cmd_init(emlxs_port_t *port,
48     fct_cmd_t *fct_cmd, uint32_t fct_state);
49 static void emlxs_fct_cmd_done(emlxs_port_t *port, fct_cmd_t *fct_cmd,
50 	uint16_t fct_state);
51 static void emlxs_fct_cmd_post(emlxs_port_t *port, fct_cmd_t *fct_cmd,
52 	uint16_t fct_state);
53 
54 static fct_status_t emlxs_fct_flogi_xchg(struct fct_local_port *fct_port,
55     struct fct_flogi_xchg *fx);
56 static fct_status_t emlxs_fct_get_link_info(fct_local_port_t *fct_port,
57     fct_link_info_t *link);
58 static fct_status_t emlxs_fct_deregister_remote_port(fct_local_port_t *fct_port,
59     fct_remote_port_t *port_handle);
60 static fct_status_t emlxs_fct_send_cmd(fct_cmd_t *fct_cmd);
61 static fct_status_t emlxs_fct_send_fcp_data(fct_cmd_t *fct_cmd,
62     stmf_data_buf_t *dbuf, uint32_t ioflags);
63 static fct_status_t emlxs_fct_send_cmd_rsp(fct_cmd_t *fct_cmd, uint32_t flags);
64 static fct_status_t emlxs_fct_abort(fct_local_port_t *fct_port,
65     fct_cmd_t *cmd, uint32_t flags);
66 static void emlxs_fct_ctl(fct_local_port_t *fct_port, int cmd, void *arg);
67 static fct_status_t emlxs_fct_register_remote_port(fct_local_port_t *fct_port,
68     fct_remote_port_t *port_handle, fct_cmd_t *plogi);
69 static fct_status_t emlxs_fct_send_els_cmd(fct_cmd_t *fct_cmd);
70 static fct_status_t emlxs_fct_send_ct_cmd(fct_cmd_t *fct_cmd);
71 static fct_status_t emlxs_fct_send_fcp_status(fct_cmd_t *fct_cmd);
72 static fct_status_t emlxs_fct_send_els_rsp(fct_cmd_t *fct_cmd);
73 static void emlxs_fct_pkt_comp(fc_packet_t *pkt);
74 static void emlxs_fct_populate_hba_details(fct_local_port_t *fct_port,
75     fct_port_attrs_t *port_attrs);
76 static fct_status_t emlxs_fct_port_info(uint32_t cmd,
77     fct_local_port_t *fct_port, void *arg, uint8_t *buffer, uint32_t *size);
78 
79 static fct_status_t emlxs_fct_dmem_init(emlxs_port_t *port);
80 static void emlxs_fct_dmem_fini(emlxs_port_t *port);
81 
82 static stmf_data_buf_t *emlxs_fct_dbuf_alloc(fct_local_port_t *fct_port,
83     uint32_t size, uint32_t *pminsize, uint32_t flags);
84 static void emlxs_fct_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf);
85 
86 static int emlxs_fct_dbuf_dma_sync(emlxs_hba_t *hba, stmf_data_buf_t *dbuf,
87     uint_t sync_type);
88 static emlxs_buf_t *emlxs_fct_pkt_init(emlxs_port_t *port,
89     fct_cmd_t *fct_cmd, fc_packet_t *pkt);
90 
91 static void emlxs_fct_unsol_flush(emlxs_port_t *port);
92 static uint32_t emlxs_fct_process_unsol_flogi(emlxs_port_t *port,
93     CHANNEL *cp, IOCBQ *iocbq, MATCHMAP *mp, uint32_t size);
94 static uint32_t emlxs_fct_process_unsol_plogi(emlxs_port_t *port,
95     CHANNEL *cp, IOCBQ *iocbq, MATCHMAP *mp, uint32_t size);
96 static uint32_t emlxs_fct_pkt_abort_txq(emlxs_port_t *port,
97     emlxs_buf_t *cmd_sbp);
98 static fct_status_t emlxs_fct_send_qfull_reply(emlxs_port_t *port,
99     emlxs_node_t *ndlp, uint16_t xid, uint32_t class, emlxs_fcp_cmd_t *fcp_cmd);
100 
101 #ifdef FCT_IO_TRACE
102 uint8_t *emlxs_iotrace = 0;	/* global for mdb */
103 int emlxs_iotrace_cnt = 0;
104 
105 /*
106  *
107  * FCT_CMD  (cmd_sbp->fct_state)
108  *
109  * STATE				LOCK STATUS			OWNER
110  * -----------------------------------------------------------------------------
111  * EMLXS_FCT_ABORT_DONE			Lock Destroyed			COMSTAR
112  * EMLXS_FCT_IO_DONE			Lock Destroyed			COMSTAR
113  *
114  * EMLXS_FCT_CMD_POSTED			Lock Released			COMSTAR
115  * EMLXS_FCT_OWNED			Lock Released			COMSTAR
116  *
117  * EMLXS_FCT_CMD_WAITQ			Lock Released			DRIVER
118  * EMLXS_FCT_RSP_PENDING		Lock Released			DRIVER
119  * EMLXS_FCT_REQ_PENDING		Lock Released			DRIVER
120  * EMLXS_FCT_REG_PENDING		Lock Released			DRIVER
121  * EMLXS_FCT_DATA_PENDING		Lock Released			DRIVER
122  * EMLXS_FCT_STATUS_PENDING		Lock Released			DRIVER
123  * EMLXS_FCT_CLOSE_PENDING		Lock Released			DRIVER
124  * EMLXS_FCT_ABORT_PENDING		Lock Released			DRIVER
125  *
126  * EMLXS_FCT_FCP_CMD_RECEIVED		Transistional, lock held	DRIVER
127  * EMLXS_FCT_ELS_CMD_RECEIVED		Transistional, lock held	DRIVER
128  * EMLXS_FCT_SEND_CMD_RSP		Transistional, lock held	DRIVER
129  * EMLXS_FCT_SEND_ELS_RSP		Transistional, lock held	DRIVER
130  * EMLXS_FCT_SEND_ELS_REQ		Transistional, lock held	DRIVER
131  * EMLXS_FCT_SEND_CT_REQ		Transistional, lock held	DRIVER
132  * EMLXS_FCT_REG_COMPLETE		Transistional, lock held	DRIVER
133  * EMLXS_FCT_SEND_FCP_DATA		Transistional, lock held	DRIVER
134  * EMLXS_FCT_SEND_FCP_STATUS		Transistional, lock held	DRIVER
135  * EMLXS_FCT_PKT_COMPLETE		Transistional, lock held	DRIVER
136  * EMLXS_FCT_PKT_FCPRSP_COMPLETE	Transistional, lock held	DRIVER
137  * EMLXS_FCT_PKT_ELSRSP_COMPLETE	Transistional, lock held	DRIVER
138  * EMLXS_FCT_PKT_ELSCMD_COMPLETE	Transistional, lock held	DRIVER
139  * EMLXS_FCT_PKT_CTCMD_COMPLETE		Transistional, lock held	DRIVER
140  * EMLXS_FCT_REQ_COMPLETE		Transistional, lock held	DRIVER
141  *
142  *
143  * 	COMSTAR OWNED	DRIVER OWNED
144  * 	-------------	---------------------------------------------------
145  * 	------- >	@	   Accept---- >Release  @   Acquire--- >+
146  *									|
147  *	< -------	@	Post/Done< ----Acquire  @   Release< ---+
148  *
149  * 	@  :Indicates COMSTAR use of emlxs_fct_abort()
150  *	    Abort requests set the EMLXS_FCT_ABORT_INP flag.
151  *
152  * 	Accept		:Indicates use of emlxs_fct_cmd_accept()
153  * 	Acquire		:Indicates use of emlxs_fct_cmd_acquire()
154  * 	Post		:Indicates use of emlxs_fct_cmd_post()
155  * 	Done		:Indicates use of emlxs_fct_cmd_done()
156  */
157 
158 void
159 emlxs_fct_io_trace(emlxs_port_t *port, fct_cmd_t *fct_cmd, uint32_t data)
160 {
161 	emlxs_iotrace_t *iop = port->iotrace;
162 	uint16_t iotrace_cnt;
163 	uint16_t iotrace_index;
164 	int i;
165 
166 	if (!iop) {
167 		return;
168 	}
169 
170 	mutex_enter(&port->iotrace_mtx);
171 	iotrace_cnt = port->iotrace_cnt;
172 	iotrace_index = port->iotrace_index;
173 
174 	switch (data) {
175 
176 		/* New entry */
177 	case EMLXS_FCT_ELS_CMD_RECEIVED:
178 	case EMLXS_FCT_FCP_CMD_RECEIVED:
179 	case EMLXS_FCT_SEND_ELS_REQ:
180 	case EMLXS_FCT_SEND_CT_REQ:
181 		for (i = 0; i < iotrace_cnt; i++) {
182 			if ((iop->fct_cmd == fct_cmd) &&
183 			    (iop->trc[0] != (uint8_t)(0)))
184 				break;
185 			iop++;
186 		}
187 		if (i < iotrace_cnt) {
188 			/* New entry already exists */
189 			mutex_exit(&port->iotrace_mtx);
190 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
191 			    "IOTRACE: New entry already exists: fct_cmd: %p",
192 			    fct_cmd);
193 			return;
194 		}
195 		iop = port->iotrace + iotrace_index;
196 		for (i = 0; i < iotrace_cnt; i++) {
197 			if (iop->trc[0] == (uint8_t)(0))
198 				break;
199 
200 			iop++;
201 			if (iop == (port->iotrace + iotrace_cnt))
202 				iop = port->iotrace;
203 		}
204 		if (i >= iotrace_cnt) {
205 			/* No new slots available */
206 			mutex_exit(&port->iotrace_mtx);
207 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
208 			    "IOTRACE: No new slots: fct_cmd: %p data: %d",
209 			    fct_cmd, data);
210 			return;
211 		}
212 		port->iotrace_index++;
213 		if (port->iotrace_index >= iotrace_cnt)
214 			port->iotrace_index = 0;
215 
216 		bzero((uint8_t *)iop, sizeof (emlxs_iotrace_t));
217 		iop->fct_cmd = fct_cmd;
218 		iop->xri = fct_cmd->cmd_rxid;
219 		iop->marker = 0xff;
220 		iop->trc[0] = 2;
221 		iop->trc[1] = data;
222 		mutex_exit(&port->iotrace_mtx);
223 		return;
224 	}
225 
226 	for (i = 0; i < iotrace_cnt; i++) {
227 		if ((iop->fct_cmd == fct_cmd) &&
228 		    (iop->trc[0] != (uint8_t)(0)))
229 			break;
230 		iop++;
231 	}
232 	if (i >= iotrace_cnt) {
233 		/* Cannot find existing slot for fct_cmd */
234 		mutex_exit(&port->iotrace_mtx);
235 
236 		if ((data != EMLXS_FCT_REG_PENDING) &&
237 		    (data != EMLXS_FCT_REG_COMPLETE)) {
238 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
239 			    "IOTRACE: Missing slot: fct_cmd: %p data: %d",
240 			    fct_cmd, data);
241 		}
242 		return;
243 	}
244 
245 	if (iop->trc[0] >= MAX_IO_TRACE) {
246 		/* trc overrun for fct_cmd */
247 		mutex_exit(&port->iotrace_mtx);
248 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
249 		    "IOTRACE: trc overrun slot: fct_cmd: %p data: %d",
250 		    fct_cmd, data);
251 		return;
252 	}
253 
254 	if (iop->xri != fct_cmd->cmd_rxid) {
255 		/* xri mismatch for fct_cmd */
256 		mutex_exit(&port->iotrace_mtx);
257 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
258 		    "IOTRACE: xri mismatch %x != %x: fct_cmd: %p data: %d",
259 		    iop->xri, fct_cmd->cmd_rxid, fct_cmd, data);
260 		return;
261 	}
262 
263 	iop->trc[iop->trc[0]] = data;
264 	if ((data == EMLXS_FCT_IO_DONE) || (data == EMLXS_FCT_ABORT_DONE)) {
265 		/* IOCB ULPCOMMAND is saved after EMLXS_FCT_IOCB_ISSUED */
266 		if (iop->trc[iop->trc[0]-1] == EMLXS_FCT_IOCB_ISSUED) {
267 			iop->trc[0]++;
268 		} else {
269 			iop->trc[0] = 0;
270 	} else {
271 		iop->trc[0]++;
272 	}
273 	mutex_exit(&port->iotrace_mtx);
274 
275 	return;
276 
277 } /* emlxs_fct_io_trace() */
278 #endif /* FCT_IO_TRACE */
279 
280 #ifdef MODSYM_SUPPORT
281 
282 extern int
283 emlxs_fct_modopen()
284 {
285 	int err;
286 
287 	mutex_enter(&emlxs_device.lock);
288 
289 	if (emlxs_modsym.fct_modopen) {
290 		mutex_exit(&emlxs_device.lock);
291 		return (0);
292 	}
293 
294 	emlxs_modsym.fct_modopen++;
295 
296 	/* Comstar (fct) */
297 	err = 0;
298 	emlxs_modsym.mod_fct = ddi_modopen("drv/fct", KRTLD_MODE_FIRST, &err);
299 	if (!emlxs_modsym.mod_fct) {
300 
301 		cmn_err(CE_WARN, "?%s: ddi_modopen drv/fct failed: err %d",
302 		    DRIVER_NAME, err);
303 		goto failed;
304 	}
305 
306 	/* Comstar (stmf) */
307 	err = 0;
308 	emlxs_modsym.mod_stmf =
309 	    ddi_modopen("drv/stmf", KRTLD_MODE_FIRST, &err);
310 	if (!emlxs_modsym.mod_stmf) {
311 
312 		cmn_err(CE_WARN, "?%s: ddi_modopen drv/stmf failed: err %d",
313 		    DRIVER_NAME, err);
314 		goto failed;
315 	}
316 
317 	err = 0;
318 	/* Check if the fct fct_alloc is present */
319 	emlxs_modsym.fct_alloc = (void *(*)())ddi_modsym(emlxs_modsym.mod_fct,
320 	    "fct_alloc", &err);
321 	if ((void *)emlxs_modsym.fct_alloc == NULL) {
322 		cmn_err(CE_WARN,
323 		    "?%s: drv/fct: fct_alloc not present", DRIVER_NAME);
324 		goto failed;
325 	}
326 
327 	err = 0;
328 	/* Check if the fct fct_free is present */
329 	emlxs_modsym.fct_free = (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
330 	    "fct_free", &err);
331 	if ((void *)emlxs_modsym.fct_free == NULL) {
332 		cmn_err(CE_WARN,
333 		    "?%s: drv/fct: fct_free not present", DRIVER_NAME);
334 		goto failed;
335 	}
336 
337 	err = 0;
338 	/* Check if the fct fct_scsi_task_alloc is present */
339 	emlxs_modsym.fct_scsi_task_alloc =
340 	    (void *(*)(void *, uint16_t, uint32_t, uint8_t *,
341 	    uint16_t, uint16_t))ddi_modsym(emlxs_modsym.mod_fct,
342 	    "fct_scsi_task_alloc", &err);
343 	if ((void *)emlxs_modsym.fct_scsi_task_alloc == NULL) {
344 		cmn_err(CE_WARN,
345 		    "?%s: drv/fct: fct_scsi_task_alloc not present",
346 		    DRIVER_NAME);
347 		goto failed;
348 	}
349 
350 	err = 0;
351 	/* Check if the fct fct_register_local_port is present */
352 	emlxs_modsym.fct_register_local_port =
353 	    (int (*)())ddi_modsym(emlxs_modsym.mod_fct,
354 	    "fct_register_local_port", &err);
355 	if ((void *)emlxs_modsym.fct_register_local_port == NULL) {
356 		cmn_err(CE_WARN,
357 		    "?%s: drv/fct: fct_register_local_port not present",
358 		    DRIVER_NAME);
359 		goto failed;
360 	}
361 
362 	err = 0;
363 	/* Check if the fct fct_deregister_local_port is present */
364 	emlxs_modsym.fct_deregister_local_port =
365 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
366 	    "fct_deregister_local_port", &err);
367 	if ((void *)emlxs_modsym.fct_deregister_local_port == NULL) {
368 		cmn_err(CE_WARN,
369 		    "?%s: drv/fct: fct_deregister_local_port not present",
370 		    DRIVER_NAME);
371 		goto failed;
372 	}
373 
374 	err = 0;
375 	/* Check if the fct fct_handle_event is present */
376 	emlxs_modsym.fct_handle_event =
377 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct, "fct_handle_event",
378 	    &err);
379 	if ((void *)emlxs_modsym.fct_handle_event == NULL) {
380 		cmn_err(CE_WARN,
381 		    "?%s: drv/fct: fct_handle_event not present",
382 		    DRIVER_NAME);
383 		goto failed;
384 	}
385 
386 	err = 0;
387 	/* Check if the fct fct_post_rcvd_cmd is present */
388 	emlxs_modsym.fct_post_rcvd_cmd =
389 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct, "fct_post_rcvd_cmd",
390 	    &err);
391 	if ((void *)emlxs_modsym.fct_post_rcvd_cmd == NULL) {
392 		cmn_err(CE_WARN,
393 		    "?%s: drv/fct: fct_post_rcvd_cmd not present",
394 		    DRIVER_NAME);
395 		goto failed;
396 	}
397 	err = 0;
398 	/* Check if the fct fct_alloc is present */
399 	emlxs_modsym.fct_ctl = (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
400 	    "fct_ctl", &err);
401 	if ((void *)emlxs_modsym.fct_ctl == NULL) {
402 		cmn_err(CE_WARN,
403 		    "?%s: drv/fct: fct_ctl not present", DRIVER_NAME);
404 		goto failed;
405 	}
406 	err = 0;
407 	/* Check if the fct fct_queue_cmd_for_termination is present */
408 	emlxs_modsym.fct_queue_cmd_for_termination =
409 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
410 	    "fct_queue_cmd_for_termination", &err);
411 	if ((void *)emlxs_modsym.fct_queue_cmd_for_termination == NULL) {
412 		cmn_err(CE_WARN,
413 		    "?%s: drv/fct: fct_queue_cmd_for_termination not present",
414 		    DRIVER_NAME);
415 		goto failed;
416 	}
417 	err = 0;
418 	/* Check if the fct fct_send_response_done is present */
419 	emlxs_modsym.fct_send_response_done =
420 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
421 	    "fct_send_response_done", &err);
422 	if ((void *)emlxs_modsym.fct_send_response_done == NULL) {
423 		cmn_err(CE_WARN,
424 		    "?%s: drv/fct: fct_send_response_done not present",
425 		    DRIVER_NAME);
426 		goto failed;
427 	}
428 	err = 0;
429 	/* Check if the fct fct_send_cmd_done is present */
430 	emlxs_modsym.fct_send_cmd_done =
431 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct, "fct_send_cmd_done",
432 	    &err);
433 	if ((void *)emlxs_modsym.fct_send_cmd_done == NULL) {
434 		cmn_err(CE_WARN,
435 		    "?%s: drv/fct: fct_send_cmd_done not present",
436 		    DRIVER_NAME);
437 		goto failed;
438 	}
439 	err = 0;
440 	/* Check if the fct fct_scsi_xfer_data_done is present */
441 	emlxs_modsym.fct_scsi_data_xfer_done =
442 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
443 	    "fct_scsi_data_xfer_done", &err);
444 	if ((void *)emlxs_modsym.fct_scsi_data_xfer_done == NULL) {
445 		cmn_err(CE_WARN,
446 		    "?%s: drv/fct: fct_scsi_data_xfer_done not present",
447 		    DRIVER_NAME);
448 		goto failed;
449 	}
450 	err = 0;
451 	/* Check if the fct fct_port_shutdown is present */
452 	emlxs_modsym.fct_port_shutdown =
453 	    (fct_status_t(*)())ddi_modsym(emlxs_modsym.mod_fct,
454 	    "fct_port_shutdown", &err);
455 	if ((void *)emlxs_modsym.fct_port_shutdown == NULL) {
456 		cmn_err(CE_WARN,
457 		    "?%s: drv/fct: fct_port_shutdown not present",
458 		    DRIVER_NAME);
459 		goto failed;
460 	}
461 
462 	err = 0;
463 	/* Check if the fct fct_port_initialize is present */
464 	emlxs_modsym.fct_port_initialize =
465 	    (fct_status_t(*)())ddi_modsym(emlxs_modsym.mod_fct,
466 	    "fct_port_initialize", &err);
467 	if ((void *)emlxs_modsym.fct_port_initialize == NULL) {
468 		cmn_err(CE_WARN,
469 		    "?%s: drv/fct: fct_port_initialize not present",
470 		    DRIVER_NAME);
471 		goto failed;
472 	}
473 
474 	err = 0;
475 	/* Check if the fct fct_cmd_fca_aborted is present */
476 	emlxs_modsym.fct_cmd_fca_aborted =
477 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
478 	    "fct_cmd_fca_aborted", &err);
479 	if ((void *)emlxs_modsym.fct_cmd_fca_aborted == NULL) {
480 		cmn_err(CE_WARN,
481 		    "?%s: drv/fct: fct_cmd_fca_aborted not present",
482 		    DRIVER_NAME);
483 		goto failed;
484 	}
485 
486 	err = 0;
487 	/* Check if the fct fct_handle_rcvd_flogi is present */
488 	emlxs_modsym.fct_handle_rcvd_flogi =
489 	    (fct_status_t(*)())ddi_modsym(emlxs_modsym.mod_fct,
490 	    "fct_handle_rcvd_flogi", &err);
491 	if ((void *)emlxs_modsym.fct_handle_rcvd_flogi == NULL) {
492 		cmn_err(CE_WARN,
493 		    "?%s: drv/fct: fct_handle_rcvd_flogi not present",
494 		    DRIVER_NAME);
495 		goto failed;
496 	}
497 
498 	/* Comstar (stmf) */
499 	err = 0;
500 	/* Check if the stmf stmf_alloc is present */
501 	emlxs_modsym.stmf_alloc =
502 	    (void *(*)())ddi_modsym(emlxs_modsym.mod_stmf, "stmf_alloc",
503 	    &err);
504 	if ((void *)emlxs_modsym.stmf_alloc == NULL) {
505 		cmn_err(CE_WARN,
506 		    "?%s: drv/stmf: stmf_alloc not present", DRIVER_NAME);
507 		goto failed;
508 	}
509 
510 	err = 0;
511 	/* Check if the stmf stmf_free is present */
512 	emlxs_modsym.stmf_free = (void (*)())ddi_modsym(emlxs_modsym.mod_stmf,
513 	    "stmf_free", &err);
514 	if ((void *)emlxs_modsym.stmf_free == NULL) {
515 		cmn_err(CE_WARN,
516 		    "?%s: drv/stmf: stmf_free not present", DRIVER_NAME);
517 		goto failed;
518 	}
519 
520 	err = 0;
521 	/* Check if the stmf stmf_deregister_port_provider is present */
522 	emlxs_modsym.stmf_deregister_port_provider =
523 	    (void (*)())ddi_modsym(emlxs_modsym.mod_stmf,
524 	    "stmf_deregister_port_provider", &err);
525 	if ((void *)emlxs_modsym.stmf_deregister_port_provider == NULL) {
526 		cmn_err(CE_WARN,
527 		    "?%s: drv/stmf: stmf_deregister_port_provider not present",
528 		    DRIVER_NAME);
529 		goto failed;
530 	}
531 
532 	err = 0;
533 	/* Check if the stmf stmf_register_port_provider is present */
534 	emlxs_modsym.stmf_register_port_provider =
535 	    (int (*)())ddi_modsym(emlxs_modsym.mod_stmf,
536 	    "stmf_register_port_provider", &err);
537 	if ((void *)emlxs_modsym.stmf_register_port_provider == NULL) {
538 		cmn_err(CE_WARN,
539 		    "?%s: drv/stmf: stmf_register_port_provider not present",
540 		    DRIVER_NAME);
541 		goto failed;
542 	}
543 
544 	mutex_exit(&emlxs_device.lock);
545 	return (0);
546 
547 failed:
548 
549 	mutex_exit(&emlxs_device.lock);
550 	emlxs_fct_modclose();
551 	return (1);
552 
553 } /* emlxs_fct_modopen() */
554 
555 
556 extern void
557 emlxs_fct_modclose()
558 {
559 	mutex_enter(&emlxs_device.lock);
560 
561 	if (emlxs_modsym.fct_modopen == 0) {
562 		mutex_exit(&emlxs_device.lock);
563 		return;
564 	}
565 
566 	emlxs_modsym.fct_modopen--;
567 
568 	if (emlxs_modsym.fct_modopen) {
569 		mutex_exit(&emlxs_device.lock);
570 		return;
571 	}
572 
573 	if (emlxs_modsym.mod_fct) {
574 		(void) ddi_modclose(emlxs_modsym.mod_fct);
575 		emlxs_modsym.mod_fct = 0;
576 	}
577 
578 	if (emlxs_modsym.mod_stmf) {
579 		(void) ddi_modclose(emlxs_modsym.mod_stmf);
580 		emlxs_modsym.mod_stmf = 0;
581 	}
582 
583 	emlxs_modsym.fct_alloc = NULL;
584 	emlxs_modsym.fct_free = NULL;
585 	emlxs_modsym.fct_scsi_task_alloc = NULL;
586 	emlxs_modsym.fct_register_local_port = NULL;
587 	emlxs_modsym.fct_deregister_local_port = NULL;
588 	emlxs_modsym.fct_handle_event = NULL;
589 	emlxs_modsym.fct_ctl = NULL;
590 	emlxs_modsym.fct_queue_cmd_for_termination = NULL;
591 	emlxs_modsym.fct_send_response_done = NULL;
592 	emlxs_modsym.fct_send_cmd_done = NULL;
593 	emlxs_modsym.fct_scsi_data_xfer_done = NULL;
594 	emlxs_modsym.fct_port_shutdown = NULL;
595 	emlxs_modsym.fct_port_initialize = NULL;
596 	emlxs_modsym.fct_cmd_fca_aborted = NULL;
597 	emlxs_modsym.fct_handle_rcvd_flogi = NULL;
598 
599 	emlxs_modsym.stmf_alloc = NULL;
600 	emlxs_modsym.stmf_free = NULL;
601 	emlxs_modsym.stmf_deregister_port_provider = NULL;
602 	emlxs_modsym.stmf_register_port_provider = NULL;
603 
604 	mutex_exit(&emlxs_device.lock);
605 
606 } /* emlxs_fct_modclose() */
607 
608 #endif /* MODSYM_SUPPORT */
609 
610 /*
611  * This routine is called to handle an unsol FLOGI exchange
612  *	fx	save
613  *	0	1	Process or save port->fx
614  *	0	0	Process or reject port->fx
615  *	1	1	Process port->fx, Process or save fx
616  *	1	0	Process or reject port->fx, Process or reject fx
617  */
618 static void
619 emlxs_fct_handle_unsol_flogi(emlxs_port_t *port, fct_flogi_xchg_t *fx,
620     uint32_t save)
621 {
622 	emlxs_hba_t *hba = HBA;
623 	fct_status_t status;
624 	IOCBQ iocbq;
625 	fct_flogi_xchg_t fxchg;
626 
627 begin:
628 	mutex_enter(&EMLXS_PORT_LOCK);
629 
630 	/* Check if there is an old saved FLOGI */
631 	if (port->fx.fx_op) {
632 		/* Get it now */
633 		bcopy(&port->fx, &fxchg, sizeof (fct_flogi_xchg_t));
634 
635 		if (fx) {
636 			/* Save new FLOGI */
637 			bcopy(fx, &port->fx, sizeof (fct_flogi_xchg_t));
638 
639 			/* Reject old stale FLOGI */
640 			fx = &fxchg;
641 			goto reject_it;
642 
643 		} else {
644 			bzero(&port->fx, sizeof (fct_flogi_xchg_t));
645 			fx = &fxchg;
646 		}
647 
648 	} else if (!fx) {
649 		/* Nothing to do, just return */
650 		mutex_exit(&EMLXS_PORT_LOCK);
651 		return;
652 	}
653 
654 	/* We have a valid FLOGI here */
655 	/* There is no saved FLOGI at this point either */
656 
657 	/* Check if COMSTAR is ready to accept it */
658 	if (port->fct_flags & FCT_STATE_LINK_UP_ACKED) {
659 		mutex_exit(&EMLXS_PORT_LOCK);
660 
661 		bzero((uint8_t *)&iocbq, sizeof (IOCBQ));
662 		iocbq.iocb.un.elsreq.remoteID = fx->fx_sid;
663 		iocbq.iocb.un.elsreq.myID = fx->fx_did;
664 		iocbq.iocb.ULPCONTEXT = (uint16_t)fx->rsvd2;
665 		fx->rsvd2 = 0; /* Clear the reserved field now */
666 
667 		status = MODSYM(fct_handle_rcvd_flogi) (port->fct_port, fx);
668 
669 #ifdef FCT_API_TRACE
670 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
671 		    "fct_handle_rcvd_flogi %p: status=%x",
672 		    port->fct_port, status);
673 #endif /* FCT_API_TRACE */
674 
675 		if (status == FCT_SUCCESS) {
676 			if (fx->fx_op == ELS_OP_ACC) {
677 				(void) emlxs_els_reply(port, &iocbq,
678 				    ELS_CMD_ACC, ELS_CMD_FLOGI, 0, 0);
679 
680 			} else {	/* ELS_OP_LSRJT */
681 				(void) emlxs_els_reply(port, &iocbq,
682 				    ELS_CMD_LS_RJT, ELS_CMD_FLOGI,
683 				    fx->fx_rjt_reason, fx->fx_rjt_expl);
684 			}
685 		} else {
686 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
687 			    "FLOGI: sid=%x xid=%x. "
688 			    "fct_handle_rcvd_flogi failed. Rejecting.",
689 			    fx->fx_sid, iocbq.iocb.ULPCONTEXT);
690 
691 			(void) emlxs_els_reply(port, &iocbq,
692 			    ELS_CMD_LS_RJT, ELS_CMD_FLOGI,
693 			    LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
694 		}
695 
696 		return;
697 	}
698 
699 	if (save) {
700 		/* Save FLOGI for later */
701 		bcopy(fx, &port->fx, sizeof (fct_flogi_xchg_t));
702 		mutex_exit(&EMLXS_PORT_LOCK);
703 		return;
704 	}
705 
706 reject_it:
707 
708 	mutex_exit(&EMLXS_PORT_LOCK);
709 
710 	if (port->fct_flags & FCT_STATE_LINK_UP) {
711 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
712 		    "FLOGI: sid=%x xid=%x. Stale. Rejecting.",
713 		    fx->fx_sid, fx->rsvd2);
714 
715 		bzero((uint8_t *)&iocbq, sizeof (IOCBQ));
716 		iocbq.iocb.un.elsreq.remoteID = fx->fx_sid;
717 		iocbq.iocb.un.elsreq.myID = fx->fx_did;
718 		iocbq.iocb.ULPCONTEXT = fx->rsvd2;
719 
720 		(void) emlxs_els_reply(port, &iocbq,
721 		    ELS_CMD_LS_RJT, ELS_CMD_FLOGI,
722 		    LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
723 
724 		/* If we have an FLOGI saved, try sending it now */
725 		if (port->fx.fx_op) {
726 			fx = NULL;
727 			goto begin;
728 		}
729 
730 	} else {
731 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
732 		    "FLOGI: sid=%x xid=%x. Link down. "
733 		    "Dropping.",
734 		    fx->fx_sid, fx->rsvd2);
735 	}
736 
737 	return;
738 
739 } /* emlxs_fct_handle_unsol_flogi() */
740 
741 
742 /* This is called at port online and offline */
743 static void
744 emlxs_fct_unsol_flush(emlxs_port_t *port)
745 {
746 	emlxs_hba_t *hba = HBA;
747 	emlxs_buf_t *cmd_sbp;
748 	emlxs_buf_t *next;
749 	fct_cmd_t *fct_cmd;
750 	fct_status_t rval;
751 	uint32_t cmd_code;
752 
753 	if (!port->fct_port) {
754 		return;
755 	}
756 
757 	/* First handle any pending FLOGI */
758 	emlxs_fct_handle_unsol_flogi(port, NULL, 0);
759 
760 	/* Wait queue */
761 	mutex_enter(&EMLXS_PORT_LOCK);
762 	cmd_sbp = port->fct_wait_head;
763 	port->fct_wait_head = NULL;
764 	port->fct_wait_tail = NULL;
765 	mutex_exit(&EMLXS_PORT_LOCK);
766 
767 	/*
768 	 * Next process any outstanding ELS commands. It doesn't
769 	 * matter if the Link is up or not, always post them to FCT.
770 	 */
771 	while (cmd_sbp) {
772 		next = cmd_sbp->next;
773 		fct_cmd = cmd_sbp->fct_cmd;
774 
775 		cmd_code = (fct_cmd->cmd_oxid << ELS_CMD_SHIFT);
776 
777 		/* Reacquire ownership of the fct_cmd */
778 		rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
779 		if (rval) {
780 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
781 			    "emlxs_fct_unsol_flush: %s: sid=%x xid=%x "
782 			    "Unable to reacquire fct_cmd.",
783 			    emlxs_elscmd_xlate(cmd_code),
784 			    fct_cmd->cmd_rxid, fct_cmd->cmd_rportid);
785 
786 			cmd_sbp = next;
787 			continue;
788 		}
789 		/* mutex_enter(&cmd_sbp->fct_mtx); */
790 
791 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
792 		    "Completing %s: sid=%x xid=%x %p",
793 		    emlxs_elscmd_xlate(cmd_code),
794 		    fct_cmd->cmd_rportid, fct_cmd->cmd_rxid,
795 		    fct_cmd);
796 
797 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
798 		/* mutex_exit(&cmd_sbp->fct_mtx); */
799 
800 #ifdef FCT_API_TRACE
801 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
802 		    "fct_post_rcvd_cmd:2 %p: portid x%x", fct_cmd,
803 		    fct_cmd->cmd_lportid);
804 #endif /* FCT_API_TRACE */
805 
806 		MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
807 
808 		cmd_sbp = next;
809 
810 	}	/* while () */
811 
812 	return;
813 
814 } /* emlxs_fct_unsol_flush() */
815 
816 
817 int
818 emlxs_is_digit(uint8_t chr)
819 {
820 	if ((chr >= '0') && (chr <= '9')) {
821 		return (1);
822 	}
823 
824 	return (0);
825 
826 } /* emlxs_is_digit */
827 
828 
829 /*
830  *   Convert an ASCII decimal numeric string to integer.
831  *   Negation character '-' is not handled.
832  */
833 uint32_t
834 emlxs_str_atoi(uint8_t *string)
835 {
836 	uint32_t num = 0;
837 	int i = 0;
838 
839 	while (string[i]) {
840 		if (!emlxs_is_digit(string[i])) {
841 			return (num);
842 		}
843 
844 		num = num * 10 + (string[i++] - '0');
845 	}
846 
847 	return (num);
848 
849 } /* emlxs_str_atoi() */
850 
851 
852 static void
853 emlxs_init_fct_bufpool(emlxs_hba_t *hba, char **arrayp, uint32_t cnt)
854 {
855 	emlxs_port_t *port = &PPORT;
856 	uint8_t *datap;
857 	int i;
858 	int bck;
859 	int nbufs;
860 	int maxbufs;
861 	int size;
862 
863 	bzero((uint8_t *)port->dmem_bucket, sizeof (port->dmem_bucket));
864 	bck = 0;
865 	for (i = 0; i < cnt; i++) {
866 		datap = (uint8_t *)arrayp[i];
867 		if (datap == 0)
868 			break;
869 
870 		while (*datap == ' ')	/* Skip spaces */
871 			datap++;
872 
873 		size = emlxs_str_atoi(datap);
874 
875 		while ((*datap != ':') && (*datap != 0))
876 			datap++;
877 		if (*datap == ':')	/* Skip past delimeter */
878 			datap++;
879 		while (*datap == ' ')	/* Skip spaces */
880 			datap++;
881 
882 		nbufs = emlxs_str_atoi(datap);
883 
884 		/* Check for a bad entry */
885 		if (!size || !nbufs) {
886 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
887 			    "Bad fct-bufpool entry %d %d", size, nbufs);
888 
889 			port->dmem_bucket[bck].dmem_buf_size = 0;
890 			port->dmem_bucket[bck].dmem_nbufs = 0;
891 			size = 0;
892 			nbufs = 0;
893 		}
894 
895 		while (nbufs) {
896 			port->dmem_bucket[bck].dmem_buf_size = size;
897 			port->dmem_bucket[bck].dmem_nbufs = nbufs;
898 
899 			/*
900 			 * We are not going to try to allocate a chunk
901 			 * of memory > FCT_DMEM_MAX_BUF_SEGMENT
902 			 * to accomidate the buffer pool of the
903 			 * requested size.
904 			 */
905 			maxbufs = (FCT_DMEM_MAX_BUF_SEGMENT / size);
906 
907 			if (nbufs > maxbufs) {
908 				port->dmem_bucket[bck].dmem_nbufs = maxbufs;
909 				nbufs -= maxbufs;
910 				bck++;
911 				if (bck >= FCT_MAX_BUCKETS)
912 					break;
913 			} else {
914 				bck++;
915 				nbufs = 0;
916 			}
917 		}
918 
919 		if (bck >= FCT_MAX_BUCKETS) {
920 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
921 			    "fct-bufpool entry %d %d Exceeds available buckets",
922 			    size, nbufs);
923 			break;
924 		}
925 	}
926 }
927 
928 
929 static void
930 emlxs_fct_cfg_init(emlxs_hba_t *hba)
931 {
932 	emlxs_port_t *port = &PPORT;
933 	char **arrayp;
934 	uint32_t cnt;
935 	char buf[32];
936 	int status;
937 
938 	bzero((void *)buf, 32);
939 	cnt = 0;
940 	arrayp = NULL;
941 
942 	(void) sprintf(buf, "emlxs%d-fct-bufpool", ddi_get_instance(hba->dip));
943 	status = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, hba->dip,
944 	    (DDI_PROP_DONTPASS), buf, &arrayp, &cnt);
945 
946 	if ((status == DDI_PROP_SUCCESS) && cnt && arrayp) {
947 		emlxs_init_fct_bufpool(hba, arrayp, cnt);
948 	} else {
949 		status = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, hba->dip,
950 		    (DDI_PROP_DONTPASS), "fct-bufpool", &arrayp, &cnt);
951 
952 		if ((status == DDI_PROP_SUCCESS) && cnt && arrayp) {
953 			emlxs_init_fct_bufpool(hba, arrayp, cnt);
954 		} else {
955 			bzero((uint8_t *)port->dmem_bucket,
956 			    sizeof (port->dmem_bucket));
957 			port->dmem_bucket[0].dmem_buf_size = 512;
958 			port->dmem_bucket[0].dmem_nbufs = FCT_BUF_COUNT_512;
959 			port->dmem_bucket[1].dmem_buf_size = (2 * 65536);
960 			port->dmem_bucket[1].dmem_nbufs = FCT_BUF_COUNT_128K;
961 		}
962 	}
963 
964 	bzero((void *)buf, 32);
965 	cnt = 0;
966 
967 	/*
968 	 * 0 means use HBA throttle for target queue depth,
969 	 * non-0 value is the actual target queue depth,
970 	 * default is EMLXS_FCT_DFLT_QDEPTH.
971 	 */
972 	(void) sprintf(buf, "emlxs%d-fct-queue-depth",
973 	    ddi_get_instance(hba->dip));
974 	cnt = ddi_prop_get_int(DDI_DEV_T_ANY, hba->dip,
975 	    (DDI_PROP_DONTPASS), buf, EMLXS_FCT_DFLT_QDEPTH);
976 
977 	if ((cnt == DDI_PROP_NOT_FOUND) || (cnt == EMLXS_FCT_DFLT_QDEPTH)) {
978 		cnt = ddi_prop_get_int(DDI_DEV_T_ANY, hba->dip,
979 		    (DDI_PROP_DONTPASS), "fct-queue-depth",
980 		    EMLXS_FCT_DFLT_QDEPTH);
981 
982 		if (cnt == DDI_PROP_NOT_FOUND) {
983 			cnt = EMLXS_FCT_DFLT_QDEPTH;
984 		}
985 	}
986 
987 	port->fct_queue_depth = cnt;
988 
989 #ifdef FCT_IO_TRACE
990 	port->iotrace_cnt = 1024;
991 	port->iotrace_index = 0;
992 	if (cnt)
993 		port->iotrace_cnt = (2 * cnt);
994 	port->iotrace =
995 	    kmem_zalloc(port->iotrace_cnt * sizeof (emlxs_iotrace_t),
996 	    KM_SLEEP);
997 
998 	mutex_init(&port->iotrace_mtx, NULL, MUTEX_DRIVER,
999 	    (void *)hba->intr_arg);
1000 	emlxs_iotrace = (uint8_t *)port->iotrace;
1001 	emlxs_iotrace_cnt = port->iotrace_cnt;
1002 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1003 	    "IOTRACE: init:%p cnt:%d", emlxs_iotrace, emlxs_iotrace_cnt);
1004 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1005 	    "FCT_ABORT_SUCCESS:%lx FCT_SUCCESS:%lx", FCT_ABORT_SUCCESS,
1006 	    FCT_SUCCESS);
1007 #endif /* FCT_IO_TRACE */
1008 	return;
1009 
1010 } /* emlxs_fct_cfg_init() */
1011 
1012 
1013 extern void
1014 emlxs_fct_init(emlxs_hba_t *hba)
1015 {
1016 	emlxs_port_t *port = &PPORT;
1017 	emlxs_config_t *cfg = &CFG;
1018 	emlxs_port_t *vport;
1019 	uint32_t i;
1020 
1021 	if (!hba->tgt_mode) {
1022 		return;
1023 	}
1024 
1025 	/* Check if COMSTAR is present */
1026 	if (((void *)MODSYM(stmf_alloc) == NULL) ||
1027 	    ((void *)MODSYM(fct_alloc) == NULL)) {
1028 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_attach_debug_msg,
1029 		    "Comstar not present. Target mode disabled.");
1030 		goto failed;
1031 	}
1032 
1033 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_attach_debug_msg,
1034 	    "Comstar present. Target mode enabled.");
1035 
1036 	if (cfg[CFG_NPIV_ENABLE].current) {
1037 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
1038 		    "enable-npiv: Not supported in target mode. Disabling.");
1039 
1040 		/* Temporary patch to disable npiv */
1041 		cfg[CFG_NPIV_ENABLE].current = 0;
1042 	}
1043 
1044 #ifdef DHCHAP_SUPPORT
1045 	if (cfg[CFG_AUTH_ENABLE].current) {
1046 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
1047 		    "enable-auth: Not supported in target mode. Disabling.");
1048 
1049 		/* Temporary patch to disable auth */
1050 		cfg[CFG_AUTH_ENABLE].current = 0;
1051 	}
1052 #endif /* DHCHAP_SUPPORT */
1053 
1054 	emlxs_fct_cfg_init(hba);
1055 	return;
1056 
1057 failed:
1058 
1059 	hba->tgt_mode = 0;
1060 	for (i = 0; i < MAX_VPORTS; i++) {
1061 		vport = &VPORT(i);
1062 		vport->tgt_mode = 0;
1063 		vport->fct_flags = 0;
1064 	}
1065 
1066 	return;
1067 
1068 } /* emlxs_fct_init() */
1069 
1070 
1071 extern void
1072 emlxs_fct_attach(emlxs_hba_t *hba)
1073 {
1074 	emlxs_port_t *port = &PPORT;
1075 	uint32_t vpi;
1076 
1077 	if (!hba->tgt_mode) {
1078 		return;
1079 	}
1080 
1081 	/* Bind the physical port */
1082 	emlxs_fct_bind_port(port);
1083 
1084 	/* Bind virtual ports */
1085 	if (hba->flag & FC_NPIV_ENABLED) {
1086 		for (vpi = 1; vpi <= hba->vpi_high; vpi++) {
1087 			port = &VPORT(vpi);
1088 
1089 			if (!(port->flag & EMLXS_PORT_ENABLE)) {
1090 				continue;
1091 			}
1092 
1093 			emlxs_fct_bind_port(port);
1094 		}
1095 	}
1096 
1097 	return;
1098 
1099 } /* emlxs_fct_attach() */
1100 
1101 
1102 extern void
1103 emlxs_fct_detach(emlxs_hba_t *hba)
1104 {
1105 	uint32_t i;
1106 	emlxs_port_t *vport;
1107 
1108 	if (hba->tgt_mode) {
1109 		for (i = 0; i < MAX_VPORTS; i++) {
1110 			vport = &VPORT(i);
1111 
1112 			if (!vport->tgt_mode) {
1113 				continue;
1114 			}
1115 
1116 			emlxs_fct_unbind_port(vport);
1117 			vport->tgt_mode = 0;
1118 		}
1119 
1120 
1121 		hba->tgt_mode = 0;
1122 	}
1123 #ifdef FCT_IO_TRACE
1124 	{
1125 		emlxs_port_t *port = &PPORT;
1126 
1127 		mutex_destroy(&port->iotrace_mtx);
1128 		if (port->iotrace)
1129 			kmem_free(port->iotrace,
1130 			    (port->iotrace_cnt * sizeof (emlxs_iotrace_t)));
1131 		port->iotrace = NULL;
1132 	}
1133 #endif /* FCT_IO_TRACE */
1134 
1135 	return;
1136 
1137 } /* emlxs_fct_detach() */
1138 
1139 
1140 extern void
1141 emlxs_fct_unbind_port(emlxs_port_t *port)
1142 {
1143 	emlxs_hba_t *hba = HBA;
1144 	char node_name[32];
1145 
1146 	if (!port->tgt_mode) {
1147 		return;
1148 	}
1149 
1150 	mutex_enter(&EMLXS_PORT_LOCK);
1151 	if (!(port->flag & EMLXS_PORT_BOUND)) {
1152 		mutex_exit(&EMLXS_PORT_LOCK);
1153 		return;
1154 	}
1155 
1156 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1157 	    "emlxs_fct_unbind_port: port=%d", port->vpi);
1158 
1159 	/* Destroy & flush all port nodes, if they exist */
1160 	if (port->node_count) {
1161 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1162 			(void) emlxs_sli4_unreg_all_rpi_by_port(port);
1163 		} else {
1164 			(void) emlxs_mb_unreg_rpi(port, 0xffff, 0, 0,
1165 			    0);
1166 		}
1167 	}
1168 
1169 	port->flag &= ~EMLXS_PORT_BOUND;
1170 	hba->num_of_ports--;
1171 	mutex_exit(&EMLXS_PORT_LOCK);
1172 
1173 	if (port->fct_port) {
1174 		emlxs_fct_link_down(port);
1175 		emlxs_fct_unsol_flush(port);
1176 
1177 #ifdef FCT_API_TRACE
1178 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1179 		    "fct_deregister_local_port %p", port->fct_port);
1180 #endif /* FCT_API_TRACE */
1181 		MODSYM(fct_deregister_local_port) (port->fct_port);
1182 
1183 		if (port->fct_port->port_fds) {
1184 #ifdef FCT_API_TRACE
1185 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1186 			    "fct_free:3 %p", port->fct_port->port_fds);
1187 #endif /* FCT_API_TRACE */
1188 			MODSYM(fct_free) (port->fct_port->port_fds);
1189 			port->fct_port->port_fds = NULL;
1190 		}
1191 #ifdef FCT_API_TRACE
1192 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1193 		    "fct_free:4 %p", port->fct_port);
1194 #endif /* FCT_API_TRACE */
1195 		MODSYM(fct_free) (port->fct_port);
1196 		port->fct_port = NULL;
1197 		port->fct_flags = 0;
1198 	}
1199 
1200 	if (port->port_provider) {
1201 #ifdef FCT_API_TRACE
1202 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1203 		    "stmf_deregister_port_provider:1 %p",
1204 		    port->port_provider);
1205 #endif /* FCT_API_TRACE */
1206 		MODSYM(stmf_deregister_port_provider) (port->port_provider);
1207 
1208 #ifdef FCT_API_TRACE
1209 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1210 		    "stmf_free:1 %p", port->port_provider);
1211 #endif /* FCT_API_TRACE */
1212 		MODSYM(stmf_free) (port->port_provider);
1213 		port->port_provider = NULL;
1214 	}
1215 
1216 	if (port->dmem_bucket) {
1217 		emlxs_fct_dmem_fini(port);
1218 	}
1219 
1220 	(void) sprintf(node_name, "%d,%d:SFCT", hba->ddiinst, port->vpi);
1221 	(void) ddi_remove_minor_node(hba->dip, node_name);
1222 
1223 	return;
1224 
1225 } /* emlxs_fct_unbind_port() */
1226 
1227 
1228 extern void
1229 emlxs_fct_bind_port(emlxs_port_t *port)
1230 {
1231 	emlxs_hba_t *hba = HBA;
1232 	fct_local_port_t *fct_port;
1233 	uint32_t flag = 0;
1234 	emlxs_config_t *cfg = &CFG;
1235 	fct_dbuf_store_t *fds;
1236 	char node_name[32];
1237 	uint8_t *bptr;
1238 
1239 	mutex_enter(&EMLXS_PORT_LOCK);
1240 
1241 	if (!hba->tgt_mode || !port->tgt_mode) {
1242 		mutex_exit(&EMLXS_PORT_LOCK);
1243 		return;
1244 	}
1245 
1246 	if (port->flag & EMLXS_PORT_BOUND) {
1247 		mutex_exit(&EMLXS_PORT_LOCK);
1248 		return;
1249 	}
1250 
1251 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1252 	    "emlxs_fct_bind_port: port=%d", port->vpi);
1253 
1254 	/* Perform generic port initialization */
1255 	emlxs_port_init(port);
1256 
1257 	if (port->vpi == 0) {
1258 		(void) sprintf(port->cfd_name, "%s%d", DRIVER_NAME,
1259 		    hba->ddiinst);
1260 	} else {
1261 		(void) sprintf(port->cfd_name, "%s%d.%d", DRIVER_NAME,
1262 		    hba->ddiinst, port->vpi);
1263 	}
1264 
1265 	if (emlxs_fct_dmem_init(port) != FCT_SUCCESS) {
1266 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1267 		    "emlxs_fct_bind_port: Unable to allocate fct memory.");
1268 		goto failed;
1269 	}
1270 	flag |= 0x00000001;
1271 
1272 	port->port_provider =
1273 	    (stmf_port_provider_t *)
1274 	    MODSYM(stmf_alloc) (STMF_STRUCT_PORT_PROVIDER, 0, 0);
1275 #ifdef FCT_API_TRACE
1276 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1277 	    "stmf_alloc port_provider %p", port->port_provider);
1278 #endif /* FCT_API_TRACE */
1279 
1280 	if (port->port_provider == NULL) {
1281 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1282 		    "emlxs_fct_bind_port: Unable to allocate port provider.");
1283 		goto failed;
1284 	}
1285 	flag |= 0x00000002;
1286 
1287 	port->port_provider->pp_portif_rev = PORTIF_REV_1;
1288 	port->port_provider->pp_name = port->cfd_name;
1289 	port->port_provider->pp_provider_private = port;
1290 
1291 #ifdef FCT_API_TRACE
1292 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1293 	    "stmf_register_port_provider %p", port->port_provider);
1294 #endif /* FCT_API_TRACE */
1295 	/* register port provider with framework */
1296 	if (MODSYM(stmf_register_port_provider) (port->port_provider) !=
1297 	    STMF_SUCCESS) {
1298 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1299 		    "emlxs_fct_bind_port: Unable to register port provider.");
1300 		goto failed;
1301 	}
1302 	flag |= 0x00000004;
1303 
1304 	port->fct_port =
1305 	    (fct_local_port_t *)MODSYM(fct_alloc) (FCT_STRUCT_LOCAL_PORT, 0,
1306 	    0);
1307 #ifdef FCT_API_TRACE
1308 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1309 	    "fct_alloc fct_port %p", port->fct_port);
1310 #endif /* FCT_API_TRACE */
1311 
1312 	if (port->fct_port == NULL) {
1313 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1314 		    "emlxs_fct_bind_port: Unable to allocate fct port.");
1315 		goto failed;
1316 	}
1317 	flag |= 0x00000008;
1318 
1319 	port->fct_port->port_fds =
1320 	    (fct_dbuf_store_t *)MODSYM(fct_alloc) (FCT_STRUCT_DBUF_STORE, 0,
1321 	    0);
1322 #ifdef FCT_API_TRACE
1323 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1324 	    "fct_alloc port_fds %p", port->fct_port->port_fds);
1325 #endif /* FCT_API_TRACE */
1326 
1327 	if (port->fct_port->port_fds == NULL) {
1328 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1329 		    "emlxs_fct_bind_port: Unable to allocate dbuf store.");
1330 		goto failed;
1331 	}
1332 	flag |= 0x00000010;
1333 
1334 	(void) sprintf(node_name, "%d,%d:SFCT", hba->ddiinst, port->vpi);
1335 	if (ddi_create_minor_node(hba->dip, node_name, S_IFCHR, hba->ddiinst,
1336 	    NULL, 0) == DDI_FAILURE) {
1337 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1338 		    "Unable to create SFCT device node.");
1339 		goto failed;
1340 	}
1341 	flag |= 0x00000020;
1342 
1343 	/* Intialize */
1344 	fct_port = port->fct_port;
1345 	fct_port->port_fca_version = FCT_FCA_MODREV_1;
1346 	fct_port->port_fca_private = port;
1347 	fct_port->port_fca_abort_timeout = 30 * 1000;	/* 30 seconds */
1348 
1349 	bcopy((uint8_t *)&port->wwpn, (uint8_t *)fct_port->port_pwwn, 8);
1350 	bcopy((uint8_t *)&port->wwnn, (uint8_t *)fct_port->port_nwwn, 8);
1351 
1352 	bptr = (uint8_t *)&port->wwnn;
1353 	(void) sprintf(fct_port->port_nwwn_str,
1354 	    "%02x%02x%02x%02x%02x%02x%02x%02x",
1355 	    bptr[0], bptr[1], bptr[2], bptr[3],
1356 	    bptr[4], bptr[5], bptr[6], bptr[7]);
1357 
1358 	bptr = (uint8_t *)&port->wwpn;
1359 	(void) sprintf(fct_port->port_pwwn_str,
1360 	    "%02x%02x%02x%02x%02x%02x%02x%02x",
1361 	    bptr[0], bptr[1], bptr[2], bptr[3],
1362 	    bptr[4], bptr[5], bptr[6], bptr[7]);
1363 
1364 	fct_port->port_sym_node_name = port->snn;
1365 	fct_port->port_sym_port_name = port->spn;
1366 	fct_port->port_hard_address = cfg[CFG_ASSIGN_ALPA].current;
1367 	fct_port->port_default_alias = port->cfd_name;
1368 	fct_port->port_pp = port->port_provider;
1369 	fct_port->port_max_logins = hba->max_nodes;
1370 
1371 	if ((port->fct_queue_depth) &&
1372 	    (port->fct_queue_depth < hba->io_throttle)) {
1373 		fct_port->port_max_xchges = port->fct_queue_depth;
1374 	} else {
1375 		fct_port->port_max_xchges = hba->io_throttle;
1376 	}
1377 
1378 	fct_port->port_fca_fcp_cmd_size = sizeof (emlxs_buf_t);
1379 	fct_port->port_fca_rp_private_size = sizeof (uintptr_t);
1380 	fct_port->port_fca_sol_els_private_size = sizeof (emlxs_buf_t);
1381 	fct_port->port_fca_sol_ct_private_size = sizeof (emlxs_buf_t);
1382 	fct_port->port_get_link_info = emlxs_fct_get_link_info;
1383 	fct_port->port_register_remote_port = emlxs_fct_register_remote_port;
1384 	fct_port->port_deregister_remote_port =
1385 	    emlxs_fct_deregister_remote_port;
1386 	fct_port->port_send_cmd = emlxs_fct_send_cmd;
1387 	fct_port->port_xfer_scsi_data = emlxs_fct_send_fcp_data;
1388 	fct_port->port_send_cmd_response = emlxs_fct_send_cmd_rsp;
1389 	fct_port->port_abort_cmd = emlxs_fct_abort;
1390 	fct_port->port_ctl = emlxs_fct_ctl;
1391 	fct_port->port_flogi_xchg = emlxs_fct_flogi_xchg;
1392 	fct_port->port_populate_hba_details = emlxs_fct_populate_hba_details;
1393 	fct_port->port_info = emlxs_fct_port_info;
1394 
1395 	fds = port->fct_port->port_fds;
1396 	fds->fds_fca_private = port;
1397 	fds->fds_alloc_data_buf = emlxs_fct_dbuf_alloc;
1398 	fds->fds_free_data_buf = emlxs_fct_dbuf_free;
1399 
1400 #ifdef FCT_API_TRACE
1401 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1402 	    "fct_register_local_port %p", fct_port);
1403 #endif /* FCT_API_TRACE */
1404 	/* register this local port with the fct module */
1405 	if (MODSYM(fct_register_local_port) (fct_port) != FCT_SUCCESS) {
1406 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1407 		    "emlxs_fct_bind_port: Unable to register fct port.");
1408 		goto failed;
1409 	}
1410 
1411 	/* Set the bound flag */
1412 	port->flag |= EMLXS_PORT_BOUND;
1413 	hba->num_of_ports++;
1414 
1415 	mutex_exit(&EMLXS_PORT_LOCK);
1416 
1417 	return;
1418 
1419 failed:
1420 
1421 	if (flag & 0x20) {
1422 		(void) ddi_remove_minor_node(hba->dip, node_name);
1423 	}
1424 
1425 	if (flag & 0x10) {
1426 #ifdef FCT_API_TRACE
1427 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1428 		    "fct_free:5 %p", port->fct_port->port_fds);
1429 #endif /* FCT_API_TRACE */
1430 		MODSYM(fct_free) (port->fct_port->port_fds);
1431 		port->fct_port->port_fds = NULL;
1432 	}
1433 
1434 	if (flag & 0x8) {
1435 #ifdef FCT_API_TRACE
1436 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1437 		    "fct_free:6 %p", port->fct_port);
1438 #endif /* FCT_API_TRACE */
1439 		MODSYM(fct_free) (port->fct_port);
1440 		port->fct_port = NULL;
1441 		port->fct_flags = 0;
1442 	}
1443 
1444 	if (flag & 0x4) {
1445 #ifdef FCT_API_TRACE
1446 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1447 		    "stmf_deregister_port_provider:2 %p",
1448 		    port->port_provider);
1449 #endif /* FCT_API_TRACE */
1450 		MODSYM(stmf_deregister_port_provider) (port->port_provider);
1451 	}
1452 
1453 	if (flag & 0x2) {
1454 #ifdef FCT_API_TRACE
1455 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1456 		    "stmf_free:2 %p", port->port_provider);
1457 #endif /* FCT_API_TRACE */
1458 		MODSYM(stmf_free) (port->port_provider);
1459 		port->port_provider = NULL;
1460 	}
1461 
1462 	if (flag & 0x1) {
1463 		emlxs_fct_dmem_fini(port);
1464 	}
1465 
1466 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1467 	    "Target mode disabled.");
1468 
1469 	mutex_exit(&EMLXS_PORT_LOCK);
1470 
1471 	return;
1472 
1473 } /* emlxs_fct_bind_port() */
1474 
1475 
1476 /* COMSTAR ENTER POINT */
1477 /*ARGSUSED*/
1478 static fct_status_t
1479 emlxs_fct_port_info(uint32_t cmd, fct_local_port_t *fct_port, void *arg,
1480     uint8_t *buffer, uint32_t *size)
1481 {
1482 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1483 	emlxs_hba_t *hba = HBA;
1484 	fct_status_t rval = FCT_SUCCESS;
1485 	fct_port_link_status_t *link_status;
1486 	MAILBOX *mb;
1487 	MAILBOXQ *mbq;
1488 
1489 	switch (cmd) {
1490 	case FC_TGT_PORT_RLS:
1491 		bzero(buffer, *size);
1492 
1493 		if ((*size) < sizeof (fct_port_link_status_t)) {
1494 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1495 			    "FC_TGT_PORT_RLS: Buffer too small. %d < %d",
1496 			    *size, sizeof (fct_port_link_status_t));
1497 
1498 			rval = FCT_FAILURE;
1499 			break;
1500 		}
1501 
1502 		if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1)) == 0) {
1503 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1504 			    "FC_TGT_PORT_RLS: Unable to allocate mailbox.");
1505 
1506 			rval = FCT_ALLOC_FAILURE;
1507 			break;
1508 		}
1509 		mb = (MAILBOX *)mbq;
1510 
1511 		emlxs_mb_read_lnk_stat(hba, mbq);
1512 		if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0)
1513 		    != MBX_SUCCESS) {
1514 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1515 			    "FC_TGT_PORT_RLS: Unable to send request.");
1516 
1517 			rval = FCT_BUSY;
1518 		} else {
1519 			link_status = (fct_port_link_status_t *)buffer;
1520 			link_status->LinkFailureCount =
1521 			    mb->un.varRdLnk.linkFailureCnt;
1522 			link_status->LossOfSyncCount =
1523 			    mb->un.varRdLnk.lossSyncCnt;
1524 			link_status->LossOfSignalsCount =
1525 			    mb->un.varRdLnk.lossSignalCnt;
1526 			link_status->PrimitiveSeqProtocolErrorCount =
1527 			    mb->un.varRdLnk.primSeqErrCnt;
1528 			link_status->InvalidTransmissionWordCount =
1529 			    mb->un.varRdLnk.invalidXmitWord;
1530 			link_status->InvalidCRCCount =
1531 			    mb->un.varRdLnk.crcCnt;
1532 		}
1533 
1534 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
1535 		break;
1536 
1537 	default:
1538 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1539 		    "emlxs_fct_port_info: Invalid request. cmd=%x",
1540 		    cmd);
1541 
1542 		rval = FCT_FAILURE;
1543 		break;
1544 
1545 	}
1546 
1547 	return (rval);
1548 
1549 } /* emlxs_fct_port_info() */
1550 
1551 
1552 /* COMSTAR ENTER POINT */
1553 static void
1554 emlxs_fct_populate_hba_details(fct_local_port_t *fct_port,
1555     fct_port_attrs_t *port_attrs)
1556 {
1557 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1558 	emlxs_hba_t *hba = HBA;
1559 	emlxs_vpd_t *vpd = &VPD;
1560 
1561 	(void) strcpy(port_attrs->manufacturer, "Emulex");
1562 	(void) strcpy(port_attrs->serial_number, vpd->serial_num);
1563 	(void) strcpy(port_attrs->model, hba->model_info.model);
1564 	(void) strcpy(port_attrs->model_description,
1565 	    hba->model_info.model_desc);
1566 	(void) sprintf(port_attrs->hardware_version, "%x", vpd->biuRev);
1567 	(void) sprintf(port_attrs->driver_version, "%s (%s)", emlxs_version,
1568 	    emlxs_revision);
1569 	(void) strcpy(port_attrs->option_rom_version, vpd->fcode_version);
1570 	(void) sprintf(port_attrs->firmware_version, "%s (%s)", vpd->fw_version,
1571 	    vpd->fw_label);
1572 	(void) strcpy(port_attrs->driver_name, DRIVER_NAME);
1573 	port_attrs->vendor_specific_id =
1574 	    ((hba->model_info.device_id << 16) | PCI_VENDOR_ID_EMULEX);
1575 	port_attrs->supported_cos = LE_SWAP32(FC_NS_CLASS3);
1576 
1577 	port_attrs->max_frame_size = FF_FRAME_SIZE;
1578 
1579 	if (vpd->link_speed & LMT_10GB_CAPABLE) {
1580 		port_attrs->supported_speed |= PORT_SPEED_10G;
1581 	}
1582 	if (vpd->link_speed & LMT_8GB_CAPABLE) {
1583 		port_attrs->supported_speed |= PORT_SPEED_8G;
1584 	}
1585 	if (vpd->link_speed & LMT_4GB_CAPABLE) {
1586 		port_attrs->supported_speed |= PORT_SPEED_4G;
1587 	}
1588 	if (vpd->link_speed & LMT_2GB_CAPABLE) {
1589 		port_attrs->supported_speed |= PORT_SPEED_2G;
1590 	}
1591 	if (vpd->link_speed & LMT_1GB_CAPABLE) {
1592 		port_attrs->supported_speed |= PORT_SPEED_1G;
1593 	}
1594 
1595 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1596 	    "Port attr: manufacturer       = %s", port_attrs->manufacturer);
1597 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1598 	    "Port attr: serial_num         = %s", port_attrs->serial_number);
1599 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1600 	    "Port attr: model              = %s", port_attrs->model);
1601 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1602 	    "Port attr: model_description  = %s",
1603 	    port_attrs->model_description);
1604 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1605 	    "Port attr: hardware_version   = %s",
1606 	    port_attrs->hardware_version);
1607 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1608 	    "Port attr: driver_version     = %s", port_attrs->driver_version);
1609 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1610 	    "Port attr: option_rom_version = %s",
1611 	    port_attrs->option_rom_version);
1612 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1613 	    "Port attr: firmware_version   = %s",
1614 	    port_attrs->firmware_version);
1615 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1616 	    "Port attr: driver_name        = %s", port_attrs->driver_name);
1617 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1618 	    "Port attr: vendor_specific_id = 0x%x",
1619 	    port_attrs->vendor_specific_id);
1620 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1621 	    "Port attr: supported_cos      = 0x%x",
1622 	    port_attrs->supported_cos);
1623 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1624 	    "Port attr: supported_speed    = 0x%x",
1625 	    port_attrs->supported_speed);
1626 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1627 	    "Port attr: max_frame_size     = 0x%x",
1628 	    port_attrs->max_frame_size);
1629 
1630 	return;
1631 
1632 } /* emlxs_fct_populate_hba_details() */
1633 
1634 
1635 /* COMSTAR ENTER POINT */
1636 /* ARGSUSED */
1637 static void
1638 emlxs_fct_ctl(fct_local_port_t *fct_port, int cmd, void *arg)
1639 {
1640 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1641 	emlxs_hba_t *hba = HBA;
1642 	stmf_change_status_t st;
1643 
1644 	st.st_completion_status = FCT_SUCCESS;
1645 	st.st_additional_info = NULL;
1646 
1647 	switch (cmd) {
1648 	case FCT_CMD_PORT_ONLINE:
1649 		/* If the HBA is offline, we cannot bring the tgtport online */
1650 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1651 			st.st_completion_status = FCT_FAILURE;
1652 			MODSYM(fct_ctl) (fct_port->port_lport,
1653 			    FCT_CMD_PORT_ONLINE_COMPLETE, &st);
1654 			break;
1655 		}
1656 
1657 		if (port->fct_flags & FCT_STATE_PORT_ONLINE) {
1658 			st.st_completion_status = STMF_ALREADY;
1659 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1660 			    "STATE: ONLINE chk");
1661 		} else {
1662 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1663 			    "STATE: OFFLINE --> ONLINE");
1664 
1665 			port->fct_flags |= FCT_STATE_NOT_ACKED;
1666 			port->fct_flags |= FCT_STATE_PORT_ONLINE;
1667 
1668 			if (hba->state <= FC_LINK_DOWN) {
1669 				/* Try to bring the link up */
1670 				(void) emlxs_reset_link(hba, 1, 1);
1671 			}
1672 
1673 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1674 			    "STATE: ONLINE");
1675 		}
1676 
1677 		MODSYM(fct_ctl) (fct_port->port_lport,
1678 		    FCT_CMD_PORT_ONLINE_COMPLETE, &st);
1679 		break;
1680 
1681 	case FCT_CMD_PORT_OFFLINE:
1682 		if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
1683 			st.st_completion_status = STMF_ALREADY;
1684 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1685 			    "STATE: OFFLINE chk");
1686 
1687 		} else {
1688 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1689 			    "STATE: ONLINE --> OFFLINE");
1690 
1691 			/* Take link down and flush */
1692 			emlxs_fct_link_down(port);
1693 			emlxs_fct_unsol_flush(port);
1694 
1695 			/* Declare this port offline now */
1696 			port->fct_flags |= FCT_STATE_NOT_ACKED;
1697 			port->fct_flags &= ~FCT_STATE_PORT_ONLINE;
1698 
1699 			/* Take link down and hold it down */
1700 			(void) emlxs_reset_link(hba, 0, 1);
1701 
1702 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1703 			    "STATE: OFFLINE");
1704 		}
1705 
1706 		MODSYM(fct_ctl) (fct_port->port_lport,
1707 		    FCT_CMD_PORT_OFFLINE_COMPLETE, &st);
1708 
1709 		break;
1710 
1711 	case FCT_ACK_PORT_OFFLINE_COMPLETE:
1712 		port->fct_flags &= ~FCT_STATE_NOT_ACKED;
1713 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1714 		    "STATE: OFFLINE ack");
1715 		break;
1716 
1717 	case FCT_ACK_PORT_ONLINE_COMPLETE:
1718 		port->fct_flags &= ~FCT_STATE_NOT_ACKED;
1719 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1720 		    "STATE: ONLINE ack");
1721 		break;
1722 
1723 	case FCT_CMD_FORCE_LIP:
1724 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1725 		    "emlxs_fct_ctl: FCT_CMD_FORCE_LIP");
1726 
1727 		/* Reset the link */
1728 		(void) emlxs_reset(port, FC_FCA_LINK_RESET);
1729 		break;
1730 	}
1731 
1732 	return;
1733 
1734 } /* emlxs_fct_ctl() */
1735 
1736 
1737 extern int
1738 emlxs_fct_port_shutdown(emlxs_port_t *port)
1739 {
1740 	fct_local_port_t *fct_port;
1741 	int i;
1742 
1743 	fct_port = port->fct_port;
1744 	if (!fct_port) {
1745 		return (0);
1746 	}
1747 
1748 	port->fct_flags |= FCT_STATE_NOT_ACKED;
1749 
1750 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg, "fct_port_shutdown");
1751 	MODSYM(fct_port_shutdown) (fct_port, STMF_RFLAG_STAY_OFFLINED,
1752 	    "emlxs shutdown");
1753 
1754 	i = 0;
1755 	while (port->fct_flags & FCT_STATE_NOT_ACKED) {
1756 		i++;
1757 		if (i > 300) {	/* 30 seconds */
1758 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1759 			    "fct_port_shutdown failed to ACK");
1760 			break;
1761 		}
1762 		delay(drv_usectohz(100000));	/* 100 msec */
1763 	}
1764 	return (1);
1765 }
1766 
1767 
1768 extern int
1769 emlxs_fct_port_initialize(emlxs_port_t *port)
1770 {
1771 	fct_local_port_t *fct_port;
1772 	int i;
1773 
1774 	fct_port = port->fct_port;
1775 	if (!fct_port) {
1776 		return (0);
1777 	}
1778 
1779 	port->fct_flags |= FCT_STATE_NOT_ACKED;
1780 
1781 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1782 	    "fct_port_initialize");
1783 	MODSYM(fct_port_initialize) (fct_port, STMF_RFLAG_STAY_OFFLINED,
1784 	    "emlxs initialize");
1785 
1786 	i = 0;
1787 	while (port->fct_flags & FCT_STATE_NOT_ACKED) {
1788 		i++;
1789 		if (i > 300) {	/* 30 seconds */
1790 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1791 			    "fct_port_initialize failed to ACK");
1792 			break;
1793 		}
1794 		delay(drv_usectohz(100000));	/* 100 msec */
1795 	}
1796 	return (1);
1797 }
1798 
1799 
1800 /* COMSTAR ENTER POINT */
1801 static fct_status_t
1802 emlxs_fct_send_cmd(fct_cmd_t *fct_cmd)
1803 {
1804 	emlxs_port_t *port;
1805 
1806 	port = (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
1807 
1808 #ifdef FCT_API_TRACE
1809 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1810 	    "emlxs_fct_send_cmd %p: x%x", fct_cmd, fct_cmd->cmd_type);
1811 #endif /* FCT_API_TRACE */
1812 
1813 	switch (fct_cmd->cmd_type) {
1814 	case FCT_CMD_SOL_ELS:
1815 
1816 		return (emlxs_fct_send_els_cmd(fct_cmd));
1817 
1818 	case FCT_CMD_SOL_CT:
1819 
1820 		return (emlxs_fct_send_ct_cmd(fct_cmd));
1821 
1822 	default:
1823 
1824 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1825 		    "emlxs_fct_send_cmd: Invalid cmd type found. type=%x",
1826 		    fct_cmd->cmd_type);
1827 
1828 		return (FCT_FAILURE);
1829 	}
1830 
1831 } /* emlxs_fct_send_cmd() */
1832 
1833 
1834 /* COMSTAR ENTER POINT */
1835 static fct_status_t
1836 emlxs_fct_send_cmd_rsp(fct_cmd_t *fct_cmd, uint32_t ioflags)
1837 {
1838 	emlxs_port_t *port;
1839 	emlxs_buf_t *cmd_sbp;
1840 	fct_status_t rval;
1841 	IOCBQ *iocbq;
1842 	IOCB *iocb;
1843 	uint32_t status;
1844 
1845 	port = (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
1846 
1847 	rval = emlxs_fct_cmd_accept(port, fct_cmd, EMLXS_FCT_SEND_CMD_RSP);
1848 	if (rval) {
1849 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1850 		    "emlxs_fct_send_cmd_rsp: "
1851 		    "Unable to accept fct_cmd. type=%x",
1852 		    fct_cmd->cmd_type);
1853 
1854 		return (rval);
1855 	}
1856 	/* mutex_enter(&cmd_sbp->fct_mtx); */
1857 
1858 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
1859 	iocbq = &cmd_sbp->iocbq;
1860 	iocb = &iocbq->iocb;
1861 	status = iocb->ULPSTATUS;
1862 
1863 #ifdef FCT_API_TRACE
1864 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1865 	    "emlxs_fct_send_cmd_rsp %p: x%x, %x, %x",
1866 	    fct_cmd, fct_cmd->cmd_type, iocb->ULPCT, status);
1867 #endif /* FCT_API_TRACE */
1868 
1869 	switch (fct_cmd->cmd_type) {
1870 	case FCT_CMD_FCP_XCHG:
1871 
1872 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1873 			goto failure;
1874 		}
1875 
1876 		if ((iocb->ULPCT == 0x1) && (status == 0)) {
1877 
1878 			/* Firmware already sent out resp */
1879 			cmd_sbp->fct_flags |= EMLXS_FCT_SEND_STATUS;
1880 
1881 			emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
1882 			/* mutex_exit(&cmd_sbp->fct_mtx); */
1883 
1884 #ifdef FCT_API_TRACE
1885 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1886 			    "fct_send_response_done:4 %p: x%x",
1887 			    fct_cmd, fct_cmd->cmd_comp_status);
1888 
1889 #endif /* FCT_API_TRACE */
1890 
1891 			MODSYM(fct_send_response_done) (fct_cmd,
1892 			    fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
1893 
1894 			return (FCT_SUCCESS);
1895 		}
1896 
1897 		rval =  emlxs_fct_send_fcp_status(fct_cmd);
1898 		/* mutex_exit(&cmd_sbp->fct_mtx); */
1899 
1900 		return (rval);
1901 
1902 	case FCT_CMD_RCVD_ELS:
1903 
1904 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1905 			goto failure;
1906 		}
1907 
1908 		rval =  emlxs_fct_send_els_rsp(fct_cmd);
1909 		/* mutex_exit(&cmd_sbp->fct_mtx); */
1910 
1911 		return (rval);
1912 
1913 	default:
1914 
1915 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1916 			fct_cmd->cmd_handle = 0;
1917 		}
1918 
1919 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1920 		    "emlxs_fct_send_cmd_rsp: Invalid cmd type found. type=%x",
1921 		    fct_cmd->cmd_type);
1922 
1923 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
1924 		/* mutex_exit(&cmd_sbp->fct_mtx); */
1925 
1926 		return (FCT_FAILURE);
1927 	}
1928 
1929 failure:
1930 
1931 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1932 	    "emlxs_fct_send_cmd_rsp: "
1933 	    "Unable to handle FCT_IOF_FORCE_FCA_DONE. type=%x",
1934 	    fct_cmd->cmd_type);
1935 
1936 	emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
1937 	/* mutex_exit(&cmd_sbp->fct_mtx); */
1938 
1939 	return (FCT_FAILURE);
1940 
1941 } /* emlxs_fct_send_cmd_rsp() */
1942 
1943 
1944 /* COMSTAR ENTER POINT */
1945 static fct_status_t
1946 emlxs_fct_flogi_xchg(struct fct_local_port *fct_port, struct fct_flogi_xchg *fx)
1947 {
1948 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1949 	emlxs_hba_t *hba = HBA;
1950 	uint32_t size;
1951 	fc_packet_t *pkt = NULL;
1952 	ELS_PKT *els;
1953 	fct_status_t rval = FCT_SUCCESS;
1954 
1955 #ifdef FCT_API_TRACE
1956 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1957 	    "emlxs_fct_flogi_xchg: Sending FLOGI: %p", fct_port);
1958 #else
1959 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1960 	    "emlxs_fct_flogi_xchg: Sending FLOGI.");
1961 #endif /* FCT_API_TRACE */
1962 
1963 	if (hba->state <= FC_LINK_DOWN) {
1964 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1965 		    "emlxs_fct_flogi_xchg: FLOGI failed. Link down.");
1966 		rval = FCT_FAILURE;
1967 		goto done;
1968 	}
1969 
1970 	/* Use this entyr point as the link up acknowlegment */
1971 	mutex_enter(&EMLXS_PORT_LOCK);
1972 	port->fct_flags |= FCT_STATE_LINK_UP_ACKED;
1973 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1974 	    "emlxs_fct_link_up acked.");
1975 	mutex_exit(&EMLXS_PORT_LOCK);
1976 
1977 	/* Now flush any pending unsolicited requests */
1978 	emlxs_fct_unsol_flush(port);
1979 
1980 	size = sizeof (SERV_PARM) + 4;
1981 
1982 	if (!(pkt = emlxs_pkt_alloc(port, size, size, 0, KM_NOSLEEP))) {
1983 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1984 		    "emlxs_fct_flogi_xchg: FLOGI failed. "
1985 		    "Unable allocate packet.");
1986 		rval = FCT_FAILURE;
1987 		goto done;
1988 	}
1989 
1990 	/* Make this a polled IO */
1991 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
1992 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
1993 	pkt->pkt_comp = NULL;
1994 
1995 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
1996 	pkt->pkt_timeout = fx->fx_sec_timeout;
1997 
1998 	/* Build the fc header */
1999 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(fx->fx_did);
2000 	pkt->pkt_cmd_fhdr.r_ctl =
2001 	    R_CTL_EXTENDED_SVC | R_CTL_SOLICITED_CONTROL;
2002 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(fx->fx_sid);
2003 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
2004 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE;
2005 	pkt->pkt_cmd_fhdr.seq_id = 0;
2006 	pkt->pkt_cmd_fhdr.df_ctl = 0;
2007 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
2008 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
2009 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
2010 	pkt->pkt_cmd_fhdr.ro = 0;
2011 
2012 	/* Build the command */
2013 	/* Service paramters will be added automatically later by the driver */
2014 	els = (ELS_PKT *)pkt->pkt_cmd;
2015 	els->elsCode = 0x04;	/* FLOGI */
2016 
2017 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
2018 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2019 		    "emlxs_fct_flogi_xchg: FLOGI failed. "
2020 		    "Unable to send packet.");
2021 
2022 		rval = FCT_FAILURE;
2023 		goto done;
2024 	}
2025 
2026 	if ((pkt->pkt_state != FC_PKT_SUCCESS) &&
2027 	    (pkt->pkt_state != FC_PKT_LS_RJT)) {
2028 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
2029 			rval = FCT_TIMEOUT;
2030 		} else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
2031 		    (pkt->pkt_reason == FC_REASON_FCAL_OPN_FAIL)) {
2032 			rval = FCT_NOT_FOUND;
2033 		} else {
2034 			rval = FCT_FAILURE;
2035 		}
2036 
2037 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2038 		    "emlxs_fct_flogi_xchg: FLOGI failed. state=%x reason=%x",
2039 		    pkt->pkt_state, pkt->pkt_reason);
2040 
2041 		goto done;
2042 	}
2043 
2044 	if (pkt->pkt_state == FC_PKT_LS_RJT) {
2045 		fx->fx_op = ELS_OP_LSRJT;
2046 		fx->fx_rjt_reason = pkt->pkt_reason;
2047 		fx->fx_rjt_expl = pkt->pkt_expln;
2048 	} else {	/* FC_PKT_SUCCESS */
2049 
2050 		fx->fx_op = ELS_OP_ACC;
2051 		fx->fx_sid = FABRIC_DID;
2052 		fx->fx_did = port->did;
2053 
2054 		els = (ELS_PKT *)pkt->pkt_resp;
2055 		bcopy((caddr_t)&els->un.logi.nodeName,
2056 		    (caddr_t)fx->fx_nwwn, 8);
2057 		bcopy((caddr_t)&els->un.logi.portName,
2058 		    (caddr_t)fx->fx_pwwn, 8);
2059 		fx->fx_fport = els->un.logi.cmn.fPort;
2060 	}
2061 
2062 done:
2063 	if (pkt) {
2064 		emlxs_pkt_free(pkt);
2065 	}
2066 
2067 	return (rval);
2068 
2069 } /* emlxs_fct_flogi_xchg() */
2070 
2071 
2072 /* COMSTAR ENTER POINT */
2073 /* This is called right after we report that link has come online */
2074 static fct_status_t
2075 emlxs_fct_get_link_info(fct_local_port_t *fct_port, fct_link_info_t *link)
2076 {
2077 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
2078 	emlxs_hba_t *hba = HBA;
2079 
2080 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2081 	    "emlxs_fct_get_link_info %p", fct_port);
2082 
2083 	mutex_enter(&EMLXS_PORT_LOCK);
2084 
2085 	if (!(port->fct_flags & FCT_STATE_LINK_UP) ||
2086 	    (hba->state < FC_LINK_UP) || (hba->flag & FC_LOOPBACK_MODE)) {
2087 		link->port_topology = PORT_TOPOLOGY_UNKNOWN;
2088 		link->port_speed = PORT_SPEED_UNKNOWN;
2089 		link->portid = 0;
2090 
2091 		mutex_exit(&EMLXS_PORT_LOCK);
2092 
2093 		return (FCT_SUCCESS);
2094 	}
2095 
2096 	if (hba->topology == TOPOLOGY_LOOP) {
2097 		link->port_topology = PORT_TOPOLOGY_PRIVATE_LOOP;
2098 	} else {
2099 		link->port_topology = PORT_TOPOLOGY_PT_TO_PT;
2100 	}
2101 
2102 	switch (hba->linkspeed) {
2103 	case LA_1GHZ_LINK:
2104 		link->port_speed = PORT_SPEED_1G;
2105 		break;
2106 	case LA_2GHZ_LINK:
2107 		link->port_speed = PORT_SPEED_2G;
2108 		break;
2109 	case LA_4GHZ_LINK:
2110 		link->port_speed = PORT_SPEED_4G;
2111 		break;
2112 	case LA_8GHZ_LINK:
2113 		link->port_speed = PORT_SPEED_8G;
2114 		break;
2115 	case LA_10GHZ_LINK:
2116 		link->port_speed = PORT_SPEED_10G;
2117 		break;
2118 	default:
2119 		link->port_speed = PORT_SPEED_UNKNOWN;
2120 		break;
2121 	}
2122 
2123 	link->portid = port->did;
2124 	link->port_no_fct_flogi = 0;
2125 	link->port_fca_flogi_done = 0;
2126 	link->port_fct_flogi_done = 0;
2127 
2128 	mutex_exit(&EMLXS_PORT_LOCK);
2129 
2130 	return (FCT_SUCCESS);
2131 
2132 } /* emlxs_fct_get_link_info() */
2133 
2134 
2135 /* COMSTAR ENTER POINT */
2136 static fct_status_t
2137 emlxs_fct_register_remote_port(fct_local_port_t *fct_port,
2138     fct_remote_port_t *remote_port, fct_cmd_t *fct_cmd)
2139 {
2140 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
2141 	emlxs_hba_t *hba = HBA;
2142 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2143 	clock_t timeout;
2144 	int32_t pkt_ret;
2145 	fct_els_t *els;
2146 	SERV_PARM *sp;
2147 	emlxs_node_t *ndlp;
2148 	SERV_PARM sparam;
2149 	uint32_t *iptr;
2150 	uint64_t addr;
2151 	fct_status_t rval;
2152 	fct_status_t rval2;
2153 
2154 #ifdef FCT_API_TRACE
2155 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2156 	    "emlxs_fct_register_remote_port %p", fct_port);
2157 #endif /* FCT_API_TRACE */
2158 
2159 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
2160 
2161 		cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd,
2162 		    EMLXS_FCT_REG_PENDING);
2163 		/* mutex_enter(&cmd_sbp->fct_mtx); */
2164 
2165 		cmd_sbp->channel = &hba->chan[hba->channel_els];
2166 		cmd_sbp->fct_type = EMLXS_FCT_ELS_CMD;
2167 
2168 	} else {
2169 
2170 		rval = emlxs_fct_cmd_accept(port, fct_cmd,
2171 		    EMLXS_FCT_REG_PENDING);
2172 		if (rval) {
2173 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2174 			    "emlxs_fct_register_remote_port: "
2175 			    "Unable to accept fct_cmd. did=%x",
2176 			    fct_cmd->cmd_rportid);
2177 
2178 			return (rval);
2179 		}
2180 		/* mutex_enter(&cmd_sbp->fct_mtx); */
2181 	}
2182 
2183 	if (!cmd_sbp->node) {
2184 		cmd_sbp->node =
2185 		    emlxs_node_find_did(port, fct_cmd->cmd_rportid);
2186 	}
2187 
2188 	if (!cmd_sbp->node) {
2189 		els = (fct_els_t *)fct_cmd->cmd_specific;
2190 
2191 		/* Check for unsolicited PLOGI */
2192 		if (cmd_sbp->fct_flags & EMLXS_FCT_PLOGI_RECEIVED) {
2193 			sp = (SERV_PARM *)((caddr_t)els->els_req_payload +
2194 			    sizeof (uint32_t));
2195 		} else {	/* Solicited PLOGI */
2196 
2197 			sp = &sparam;
2198 			bcopy((caddr_t)&port->sparam, (caddr_t)sp,
2199 			    sizeof (SERV_PARM));
2200 
2201 			/*
2202 			 * Create temporary WWN's from fct_cmd address
2203 			 * This simply allows us to get an RPI from the
2204 			 * adapter until we get real service params.
2205 			 * The PLOGI ACC reply will trigger a REG_LOGIN
2206 			 * update later
2207 			 */
2208 			addr = (uint64_t)((unsigned long)fct_cmd);
2209 
2210 			iptr = (uint32_t *)&sp->portName;
2211 			iptr[0] = PADDR_HI(addr);
2212 			iptr[1] = PADDR_LO(addr);
2213 
2214 			iptr = (uint32_t *)&sp->nodeName;
2215 			iptr[0] = PADDR_HI(addr);
2216 			iptr[1] = PADDR_LO(addr);
2217 		}
2218 
2219 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
2220 		    "emlxs_fct_register_remote_port: Register did=%x. (%x,%p)",
2221 		    fct_cmd->cmd_rportid, cmd_sbp->fct_state, fct_cmd);
2222 
2223 		emlxs_fct_cmd_release(port, fct_cmd, 0);
2224 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2225 
2226 		/* Create a new node */
2227 		if (emlxs_mb_reg_did(port, fct_cmd->cmd_rportid, sp, cmd_sbp,
2228 		    NULL, NULL) != 0) {
2229 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2230 			    "emlxs_fct_register_remote_port: "
2231 			    "Reg login failed. did=%x",
2232 			    fct_cmd->cmd_rportid);
2233 		} else {
2234 
2235 			/* Wait for completion */
2236 			mutex_enter(&EMLXS_PKT_LOCK);
2237 			timeout = emlxs_timeout(hba, 30);
2238 			pkt_ret = 0;
2239 			while ((pkt_ret != -1) &&
2240 			    (cmd_sbp->fct_state == EMLXS_FCT_REG_PENDING) &&
2241 			    (cmd_sbp->node == NULL)) {
2242 				pkt_ret = cv_timedwait(&EMLXS_PKT_CV,
2243 				    &EMLXS_PKT_LOCK, timeout);
2244 			}
2245 			mutex_exit(&EMLXS_PKT_LOCK);
2246 		}
2247 
2248 		/* Reacquire ownership of the fct_cmd */
2249 		rval2 = emlxs_fct_cmd_acquire(port, fct_cmd,
2250 		    EMLXS_FCT_REG_COMPLETE);
2251 		if (rval2) {
2252 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2253 			    "emlxs_fct_register_remote_port: "
2254 			    "Unable to reacquire fct_cmd. did=%x",
2255 			    fct_cmd->cmd_rportid);
2256 
2257 			return (rval2);
2258 		}
2259 		/* mutex_enter(&cmd_sbp->fct_mtx); */
2260 	}
2261 
2262 done:
2263 
2264 	ndlp = (emlxs_node_t *)cmd_sbp->node;
2265 
2266 	if (ndlp) {
2267 		*((emlxs_node_t **)remote_port->rp_fca_private) =
2268 		    cmd_sbp->node;
2269 		remote_port->rp_handle = ndlp->nlp_Rpi;
2270 
2271 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2272 		    "emlxs_fct_register_remote_port: did=%x hdl=%x",
2273 		    fct_cmd->cmd_rportid, remote_port->rp_handle);
2274 
2275 		remote_port->rp_handle = ndlp->nlp_Rpi;
2276 
2277 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2278 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2279 
2280 		TGTPORTSTAT.FctPortRegister++;
2281 		return (FCT_SUCCESS);
2282 	} else {
2283 		*((emlxs_node_t **)remote_port->rp_fca_private) = NULL;
2284 
2285 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2286 		    "emlxs_fct_register_remote_port: failed. did=%x hdl=%x",
2287 		    fct_cmd->cmd_rportid, remote_port->rp_handle);
2288 
2289 		remote_port->rp_handle = FCT_HANDLE_NONE;
2290 
2291 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2292 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2293 
2294 		TGTPORTSTAT.FctFailedPortRegister++;
2295 		return (FCT_FAILURE);
2296 	}
2297 
2298 } /* emlxs_fct_register_remote_port() */
2299 
2300 
2301 /* COMSTAR ENTER POINT */
2302 static fct_status_t
2303 emlxs_fct_deregister_remote_port(fct_local_port_t *fct_port,
2304     fct_remote_port_t *remote_port)
2305 {
2306 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
2307 
2308 #ifdef FCT_API_TRACE
2309 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2310 	    "emlxs_fct_deregister_remote_port: did=%x hdl=%x",
2311 	    remote_port->rp_id, remote_port->rp_handle);
2312 #else
2313 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2314 	    "emlxs_fct_deregister_remote_port: did=%x hdl=%x",
2315 	    remote_port->rp_id, remote_port->rp_handle);
2316 #endif /* FCT_API_TRACE */
2317 
2318 	*((emlxs_node_t **)remote_port->rp_fca_private) = NULL;
2319 	(void) emlxs_mb_unreg_did(port, remote_port->rp_id, NULL, NULL, NULL);
2320 
2321 	TGTPORTSTAT.FctPortDeregister++;
2322 	return (FCT_SUCCESS);
2323 
2324 } /* emlxs_fct_deregister_remote_port() */
2325 
2326 
2327 /* ARGSUSED */
2328 extern int
2329 emlxs_fct_handle_unsol_req(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
2330     MATCHMAP *mp, uint32_t size)
2331 {
2332 	IOCB *iocb;
2333 	fct_cmd_t *fct_cmd;
2334 	emlxs_buf_t *cmd_sbp;
2335 	emlxs_fcp_cmd_t *fcp_cmd;
2336 	emlxs_node_t *ndlp;
2337 	uint32_t cnt;
2338 	uint32_t tm;
2339 	scsi_task_t *fct_task;
2340 	uint8_t lun[8];
2341 	uint32_t sid = 0;
2342 
2343 	iocb = &iocbq->iocb;
2344 	ndlp = emlxs_node_find_rpi(port, iocb->ULPIOTAG);
2345 	if (!ndlp) {
2346 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2347 		    "FCP rcvd: Unknown RPI. rpi=%x rxid=%x. Dropping...",
2348 		    iocb->ULPIOTAG, iocb->ULPCONTEXT);
2349 
2350 		goto dropped;
2351 	}
2352 	sid = ndlp->nlp_DID;
2353 
2354 	fcp_cmd = (emlxs_fcp_cmd_t *)mp->virt;
2355 
2356 	if (!port->fct_port) {
2357 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2358 		    "FCP rcvd: Target unbound. rpi=%x rxid=%x. Dropping...",
2359 		    iocb->ULPIOTAG, iocb->ULPCONTEXT);
2360 
2361 		emlxs_send_logo(port, sid);
2362 
2363 		goto dropped;
2364 	}
2365 
2366 	if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
2367 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2368 		    "FCP rcvd: Target offline. rpi=%x rxid=%x. Dropping...",
2369 		    iocb->ULPIOTAG, iocb->ULPCONTEXT);
2370 
2371 		emlxs_send_logo(port, sid);
2372 
2373 		goto dropped;
2374 	}
2375 
2376 	/* Get lun id */
2377 	bcopy((void *)&fcp_cmd->fcpLunMsl, lun, 8);
2378 
2379 	if (TGTPORTSTAT.FctOutstandingIO >= port->fct_port->port_max_xchges) {
2380 		TGTPORTSTAT.FctOverQDepth++;
2381 	}
2382 
2383 	fct_cmd =
2384 	    MODSYM(fct_scsi_task_alloc) (port->fct_port, iocb->ULPIOTAG, sid,
2385 	    lun, 16, 0);
2386 #ifdef FCT_API_TRACE
2387 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2388 	    "fct_scsi_task_alloc %p: FCP rcvd: "
2389 	    "cmd=%x sid=%x rxid=%x lun=%02x%02x dl=%d",
2390 	    fct_cmd, fcp_cmd->fcpCdb[0], sid, iocb->ULPCONTEXT,
2391 	    lun[0], lun[1], LE_SWAP32(fcp_cmd->fcpDl));
2392 #endif /* FCT_API_TRACE */
2393 
2394 	if (fct_cmd == NULL) {
2395 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2396 		    "FCP rcvd: sid=%x xid=%x. "
2397 		    "Unable to allocate scsi task. Returning QFULL.",
2398 		    sid, iocb->ULPCONTEXT);
2399 
2400 		(void) emlxs_fct_send_qfull_reply(port, ndlp, iocb->ULPCONTEXT,
2401 		    iocb->ULPCLASS, fcp_cmd);
2402 
2403 		goto dropped;
2404 	}
2405 
2406 	/* Initialize fct_cmd */
2407 	fct_cmd->cmd_oxid = 0xFFFF;
2408 	fct_cmd->cmd_rxid = iocb->ULPCONTEXT;
2409 	fct_cmd->cmd_rportid = sid;
2410 	fct_cmd->cmd_lportid = port->did;
2411 	fct_cmd->cmd_rp_handle = iocb->ULPIOTAG;	/* RPI */
2412 	fct_cmd->cmd_port = port->fct_port;
2413 
2414 	cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_FCP_CMD_RECEIVED);
2415 	/* mutex_enter(&cmd_sbp->fct_mtx); */
2416 
2417 	/* Initialize cmd_sbp */
2418 	cmd_sbp->channel = cp;
2419 	cmd_sbp->class = iocb->ULPCLASS;
2420 	cmd_sbp->lun = (lun[0] << 8) | lun[1];
2421 	cmd_sbp->fct_type = EMLXS_FCT_FCP_CMD;
2422 
2423 	fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
2424 
2425 	/* Set task_flags */
2426 	switch (fcp_cmd->fcpCntl1) {
2427 	case SIMPLE_Q:
2428 		fct_task->task_flags = TF_ATTR_SIMPLE_QUEUE;
2429 		break;
2430 
2431 	case HEAD_OF_Q:
2432 		fct_task->task_flags = TF_ATTR_HEAD_OF_QUEUE;
2433 		break;
2434 
2435 	case ORDERED_Q:
2436 		fct_task->task_flags = TF_ATTR_ORDERED_QUEUE;
2437 		break;
2438 
2439 	case ACA_Q:
2440 		fct_task->task_flags = TF_ATTR_ACA;
2441 		break;
2442 
2443 	case UNTAGGED:
2444 		fct_task->task_flags = TF_ATTR_UNTAGGED;
2445 		break;
2446 	}
2447 
2448 	cnt = LE_SWAP32(fcp_cmd->fcpDl);
2449 	switch (fcp_cmd->fcpCntl3) {
2450 	case 0:
2451 		TGTPORTSTAT.FctIOCmdCnt++;
2452 		break;
2453 	case 1:
2454 		EMLXS_BUMP_WRIOCTR(port, cnt);
2455 		TGTPORTSTAT.FctWriteBytes += cnt;
2456 		fct_task->task_flags |= TF_WRITE_DATA;
2457 		break;
2458 
2459 	case 2:
2460 		EMLXS_BUMP_RDIOCTR(port, cnt);
2461 		TGTPORTSTAT.FctReadBytes += cnt;
2462 		fct_task->task_flags |= TF_READ_DATA;
2463 		break;
2464 	}
2465 
2466 	fct_task->task_priority = 0;
2467 
2468 	/* task_mgmt_function */
2469 	tm = fcp_cmd->fcpCntl2;
2470 	if (tm) {
2471 		if (tm & BIT_1) {
2472 			fct_task->task_mgmt_function = TM_ABORT_TASK_SET;
2473 		} else if (tm & BIT_2) {
2474 			fct_task->task_mgmt_function = TM_CLEAR_TASK_SET;
2475 		} else if (tm & BIT_4) {
2476 			fct_task->task_mgmt_function = TM_LUN_RESET;
2477 		} else if (tm & BIT_5) {
2478 			fct_task->task_mgmt_function = TM_TARGET_COLD_RESET;
2479 		} else if (tm & BIT_6) {
2480 			fct_task->task_mgmt_function = TM_CLEAR_ACA;
2481 		} else {
2482 			fct_task->task_mgmt_function = TM_ABORT_TASK;
2483 		}
2484 	}
2485 
2486 	/* Parallel buffers support - future */
2487 	fct_task->task_max_nbufs = 1;
2488 
2489 	fct_task->task_additional_flags = 0;
2490 	fct_task->task_cur_nbufs = 0;
2491 	fct_task->task_csn_size = 8;
2492 	fct_task->task_cmd_seq_no = 0;
2493 	fct_task->task_expected_xfer_length = cnt;
2494 	bcopy((void *)&fcp_cmd->fcpCdb, fct_task->task_cdb, 16);
2495 
2496 	TGTPORTSTAT.FctCmdReceived++;
2497 	TGTPORTSTAT.FctOutstandingIO++;
2498 
2499 	emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2500 	/* mutex_exit(&cmd_sbp->fct_mtx); */
2501 
2502 #ifdef FCT_API_TRACE
2503 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2504 	    "fct_post_rcvd_cmd:3 %p: portid x%x, %d", fct_cmd,
2505 	    fct_cmd->cmd_lportid, fct_task->task_expected_xfer_length);
2506 #endif /* FCT_API_TRACE */
2507 
2508 	MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
2509 
2510 	return (0);
2511 
2512 dropped:
2513 
2514 	TGTPORTSTAT.FctRcvDropped++;
2515 	return (1);
2516 
2517 } /* emlxs_fct_handle_unsol_req() */
2518 
2519 
2520 /* COMSTAR ENTER POINT */
2521 /* ARGSUSED */
2522 static fct_status_t
2523 emlxs_fct_send_fcp_data(fct_cmd_t *fct_cmd, stmf_data_buf_t *dbuf,
2524     uint32_t ioflags)
2525 {
2526 	emlxs_port_t *port =
2527 	    (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
2528 	emlxs_hba_t *hba = HBA;
2529 	emlxs_buf_t *cmd_sbp;
2530 #ifdef FCT_API_TRACE
2531 	scsi_task_t *fct_task;
2532 #endif /* FCT_API_TRACE */
2533 	IOCBQ *iocbq;
2534 	emlxs_node_t *ndlp;
2535 
2536 	int	channel;
2537 	int	channelno;
2538 	fct_status_t rval = 0;
2539 
2540 	rval = emlxs_fct_cmd_accept(port, fct_cmd, EMLXS_FCT_SEND_FCP_DATA);
2541 	if (rval) {
2542 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2543 		    "emlxs_fct_send_fcp_data: "
2544 		    "Unable to accept fct_cmd. did=%x",
2545 		    fct_cmd->cmd_rportid);
2546 
2547 		return (rval);
2548 	}
2549 	/* mutex_enter(&cmd_sbp->fct_mtx); */
2550 
2551 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2552 #ifdef FCT_API_TRACE
2553 	fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
2554 #endif /* FCT_API_TRACE */
2555 	ndlp = *(emlxs_node_t **)fct_cmd->cmd_rp->rp_fca_private;
2556 
2557 	cmd_sbp->node = ndlp;
2558 	cmd_sbp->fct_buf = dbuf;
2559 
2560 	channelno = ((CHANNEL *)cmd_sbp->channel)->channelno;
2561 
2562 	channel = channelno;
2563 
2564 
2565 
2566 	iocbq = &cmd_sbp->iocbq;
2567 
2568 #ifdef FCT_API_TRACE
2569 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2570 	    "emlxs_fct_send_fcp_data %p: flgs=%x ioflags=%x dl=%d,%d,%d, %d",
2571 	    fct_cmd, dbuf->db_flags, ioflags, fct_task->task_cmd_xfer_length,
2572 	    fct_task->task_nbytes_transferred, dbuf->db_data_size,
2573 	    fct_task->task_expected_xfer_length);
2574 #endif /* FCT_API_TRACE */
2575 
2576 	if (EMLXS_SLI_PREP_FCT_IOCB(port, cmd_sbp, channel) != IOERR_SUCCESS) {
2577 
2578 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2579 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2580 
2581 		return (FCT_BUSY);
2582 	}
2583 
2584 	cmd_sbp->fct_type = EMLXS_FCT_FCP_DATA;
2585 
2586 	if (dbuf->db_flags & DB_SEND_STATUS_GOOD) {
2587 		cmd_sbp->fct_flags |= EMLXS_FCT_SEND_STATUS;
2588 	}
2589 
2590 	if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
2591 		if (emlxs_fct_dbuf_dma_sync(hba, dbuf, DDI_DMA_SYNC_FORDEV)) {
2592 			emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2593 			/* mutex_exit(&cmd_sbp->fct_mtx); */
2594 
2595 			return (FCT_BUSY);
2596 		}
2597 	}
2598 
2599 	cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
2600 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_DATA_PENDING);
2601 	/* mutex_exit(&cmd_sbp->fct_mtx); */
2602 
2603 	EMLXS_SLI_ISSUE_IOCB_CMD(hba, cmd_sbp->channel, iocbq);
2604 
2605 	return (FCT_SUCCESS);
2606 
2607 } /* emlxs_fct_send_fcp_data() */
2608 
2609 
2610 /* cmd_sbp->fct_mtx must be held to enter */
2611 /* cmd_sbp->fct_mtx must be released before exiting */
2612 static fct_status_t
2613 emlxs_fct_send_fcp_status(fct_cmd_t *fct_cmd)
2614 {
2615 	emlxs_port_t *port =
2616 	    (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
2617 	emlxs_hba_t *hba = HBA;
2618 	emlxs_buf_t *cmd_sbp;
2619 	scsi_task_t *fct_task;
2620 	fc_packet_t *pkt;
2621 	uint32_t did;
2622 	emlxs_fcp_rsp *fcp_rsp;
2623 	uint32_t size;
2624 	emlxs_node_t *ndlp;
2625 	fct_status_t rval;
2626 
2627 	fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
2628 	ndlp = *(emlxs_node_t **)fct_cmd->cmd_rp->rp_fca_private;
2629 	did = fct_cmd->cmd_rportid;
2630 
2631 	/* Initialize cmd_sbp */
2632 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2633 
2634 	EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, EMLXS_FCT_SEND_FCP_STATUS);
2635 
2636 	cmd_sbp->node = ndlp;
2637 
2638 	size = 24;
2639 	if (fct_task->task_sense_length) {
2640 		size += fct_task->task_sense_length;
2641 	}
2642 #ifdef FCT_API_TRACE
2643 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2644 	    "emlxs_fct_send_fcp_status %p: stat=%d resid=%d size=%d rx=%x",
2645 	    fct_cmd, fct_task->task_scsi_status,
2646 	    fct_task->task_resid, size, fct_cmd->cmd_rxid);
2647 #endif /* FCT_API_TRACE */
2648 
2649 	if (!(pkt = emlxs_pkt_alloc(port, size, 0, 0, KM_NOSLEEP))) {
2650 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2651 		    "emlxs_fct_send_fcp_status: Unable to allocate packet.");
2652 
2653 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2654 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2655 
2656 		return (FCT_BUSY);
2657 	}
2658 
2659 	cmd_sbp->fct_type = EMLXS_FCT_FCP_STATUS;
2660 
2661 	(void) emlxs_fct_pkt_init(port, fct_cmd, pkt);
2662 	cmd_sbp->fct_pkt = pkt;
2663 
2664 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
2665 	pkt->pkt_timeout =
2666 	    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
2667 	pkt->pkt_comp = emlxs_fct_pkt_comp;
2668 
2669 	/* Build the fc header */
2670 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
2671 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_STATUS;
2672 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
2673 	pkt->pkt_cmd_fhdr.type = FC_TYPE_SCSI_FCP;
2674 	pkt->pkt_cmd_fhdr.f_ctl =
2675 	    F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ;
2676 	pkt->pkt_cmd_fhdr.seq_id = 0;
2677 	pkt->pkt_cmd_fhdr.df_ctl = 0;
2678 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
2679 	pkt->pkt_cmd_fhdr.ox_id = fct_cmd->cmd_oxid;
2680 	pkt->pkt_cmd_fhdr.rx_id = fct_cmd->cmd_rxid;
2681 	pkt->pkt_cmd_fhdr.ro = 0;
2682 
2683 	/* Build the status payload */
2684 	fcp_rsp = (emlxs_fcp_rsp *)pkt->pkt_cmd;
2685 
2686 	if (fct_task->task_resid) {
2687 		if (fct_task->task_status_ctrl & TASK_SCTRL_OVER) {
2688 			TGTPORTSTAT.FctScsiResidOver++;
2689 			fcp_rsp->rspStatus2 |= RESID_OVER;
2690 			fcp_rsp->rspResId = LE_SWAP32(fct_task->task_resid);
2691 
2692 		} else if (fct_task->task_status_ctrl & TASK_SCTRL_UNDER) {
2693 			TGTPORTSTAT.FctScsiResidUnder++;
2694 			fcp_rsp->rspStatus2 |= RESID_UNDER;
2695 			fcp_rsp->rspResId = LE_SWAP32(fct_task->task_resid);
2696 
2697 		}
2698 	}
2699 
2700 	if (fct_task->task_scsi_status) {
2701 		if (fct_task->task_scsi_status == SCSI_STAT_QUE_FULL) {
2702 			TGTPORTSTAT.FctScsiQfullErr++;
2703 		} else {
2704 			TGTPORTSTAT.FctScsiStatusErr++;
2705 		}
2706 
2707 		/* Make sure residual reported on non-SCSI_GOOD READ status */
2708 		if ((fct_task->task_flags & TF_READ_DATA) &&
2709 		    (fcp_rsp->rspResId == 0)) {
2710 			fcp_rsp->rspStatus2 |= RESID_UNDER;
2711 			fcp_rsp->rspResId =
2712 			    fct_task->task_expected_xfer_length;
2713 		}
2714 	}
2715 
2716 
2717 	if (fct_task->task_sense_length) {
2718 		TGTPORTSTAT.FctScsiSenseErr++;
2719 		fcp_rsp->rspStatus2 |= SNS_LEN_VALID;
2720 		fcp_rsp->rspSnsLen = LE_SWAP32(fct_task->task_sense_length);
2721 
2722 		bcopy((uint8_t *)fct_task->task_sense_data,
2723 		    (uint8_t *)&fcp_rsp->rspInfo0,
2724 		    fct_task->task_sense_length);
2725 	}
2726 
2727 	fcp_rsp->rspStatus3 = fct_task->task_scsi_status;
2728 	fcp_rsp->rspRspLen = 0;
2729 
2730 	cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
2731 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_STATUS_PENDING);
2732 	/* mutex_exit(&cmd_sbp->fct_mtx); */
2733 
2734 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
2735 
2736 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2737 		    "emlxs_fct_send_fcp_status: Unable to send packet.");
2738 
2739 		/* Reacquire ownership of the fct_cmd */
2740 		rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
2741 		if (rval) {
2742 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2743 			    "emlxs_fct_send_fcp_status: "
2744 			    "Unable to acquire fct_cmd.");
2745 			return (rval);
2746 		}
2747 		/* mutex_enter(&cmd_sbp->fct_mtx); */
2748 
2749 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2750 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2751 
2752 		return (FCT_BUSY);
2753 	}
2754 
2755 	return (FCT_SUCCESS);
2756 
2757 } /* emlxs_fct_send_fcp_status() */
2758 
2759 
2760 static fct_status_t
2761 emlxs_fct_send_qfull_reply(emlxs_port_t *port, emlxs_node_t *ndlp,
2762     uint16_t xid, uint32_t class, emlxs_fcp_cmd_t *fcp_cmd)
2763 {
2764 	emlxs_hba_t *hba = HBA;
2765 	emlxs_buf_t *sbp;
2766 	fc_packet_t *pkt;
2767 	emlxs_fcp_rsp *fcp_rsp;
2768 	uint32_t size;
2769 	CHANNEL *cp = &hba->chan[hba->CHANNEL_FCT];
2770 	uint8_t lun[8];
2771 
2772 	bcopy((void *)&fcp_cmd->fcpLunMsl, lun, 8);
2773 	size = 24;
2774 
2775 	if (!(pkt = emlxs_pkt_alloc(port, size, 0, 0, KM_NOSLEEP))) {
2776 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2777 		    "emlxs_fct_send_qfull_reply: Unable to allocate packet.");
2778 		return (FCT_FAILURE);
2779 	}
2780 
2781 
2782 	sbp = PKT2PRIV(pkt);
2783 	sbp->node = ndlp;
2784 	sbp->channel = cp;
2785 	sbp->did = ndlp->nlp_DID;
2786 	sbp->lun = (lun[0] << 8) | lun[1];
2787 	sbp->class = class;
2788 
2789 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
2790 	pkt->pkt_timeout =
2791 	    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
2792 
2793 	/* Build the fc header */
2794 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(ndlp->nlp_DID);
2795 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_STATUS;
2796 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
2797 	pkt->pkt_cmd_fhdr.type = FC_TYPE_SCSI_FCP;
2798 	pkt->pkt_cmd_fhdr.f_ctl =
2799 	    F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ;
2800 	pkt->pkt_cmd_fhdr.seq_id = 0;
2801 	pkt->pkt_cmd_fhdr.df_ctl = 0;
2802 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
2803 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
2804 	pkt->pkt_cmd_fhdr.rx_id = xid;
2805 	pkt->pkt_cmd_fhdr.ro = 0;
2806 
2807 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2808 	    "emlxs_fct_send_qfull_reply: Sending QFULL: x%x lun x%x: %d %d",
2809 	    xid, sbp->lun, TGTPORTSTAT.FctOutstandingIO,
2810 	    port->fct_port->port_max_xchges);
2811 
2812 	/* Build the status payload */
2813 	fcp_rsp = (emlxs_fcp_rsp *)pkt->pkt_cmd;
2814 
2815 	TGTPORTSTAT.FctScsiQfullErr++;
2816 	fcp_rsp->rspStatus3 = SCSI_STAT_QUE_FULL;
2817 	fcp_rsp->rspStatus2 |= RESID_UNDER;
2818 	fcp_rsp->rspResId = LE_SWAP32(fcp_cmd->fcpDl);
2819 
2820 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
2821 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2822 		    "emlxs_fct_send_qfull_reply: Unable to send packet.");
2823 		emlxs_pkt_free(pkt);
2824 		return (FCT_FAILURE);
2825 	}
2826 
2827 	return (FCT_SUCCESS);
2828 
2829 } /* emlxs_fct_send_qfull_reply() */
2830 
2831 
2832 /* ARGSUSED */
2833 extern int
2834 emlxs_fct_handle_fcp_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
2835 {
2836 	emlxs_port_t *port = &PPORT;
2837 	IOCB *iocb;
2838 	emlxs_buf_t *sbp;
2839 	emlxs_buf_t *cmd_sbp;
2840 	uint32_t status;
2841 	fct_cmd_t *fct_cmd;
2842 	stmf_data_buf_t *dbuf;
2843 	scsi_task_t *fct_task;
2844 	fc_packet_t *pkt;
2845 	uint32_t fct_flags;
2846 	stmf_data_buf_t *fct_buf;
2847 	fct_status_t rval;
2848 
2849 	iocb = &iocbq->iocb;
2850 	sbp = (emlxs_buf_t *)iocbq->sbp;
2851 
2852 	TGTPORTSTAT.FctEvent++;
2853 
2854 	if (!sbp) {
2855 		/* completion with missing xmit command */
2856 		TGTPORTSTAT.FctStray++;
2857 
2858 		/* emlxs_stray_fcp_completion_msg */
2859 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2860 		    "FCP event cmd=%x status=%x error=%x iotag=%x",
2861 		    iocb->ULPCOMMAND, iocb->ULPSTATUS,
2862 		    iocb->un.grsp.perr.statLocalError, iocb->ULPIOTAG);
2863 
2864 		return (1);
2865 	}
2866 
2867 	TGTPORTSTAT.FctCompleted++;
2868 
2869 	port = sbp->iocbq.port;
2870 	fct_cmd = sbp->fct_cmd;
2871 	status = iocb->ULPSTATUS;
2872 
2873 #ifdef FCT_API_TRACE
2874 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2875 	    "emlxs_fct_handle_fcp_event: %p: cmd=%x status=%x, %x",
2876 	    fct_cmd, iocb->ULPCOMMAND, status, iocb->ULPCT);
2877 #endif /* FCT_API_TRACE */
2878 
2879 	if (fct_cmd == NULL) {
2880 		/* For driver generated QFULL response */
2881 		if (((iocb->ULPCOMMAND == CMD_FCP_TRSP_CX) ||
2882 		    (iocb->ULPCOMMAND == CMD_FCP_TRSP64_CX)) && sbp->pkt) {
2883 			emlxs_pkt_free(sbp->pkt);
2884 		}
2885 		return (0);
2886 	}
2887 
2888 	rval = emlxs_fct_cmd_acquire(port, fct_cmd, EMLXS_FCT_REQ_COMPLETE);
2889 	if (rval) {
2890 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2891 		    "emlxs_fct_handle_fcp_event: "
2892 		    "Unable to reacquire fct_cmd. type=%x",
2893 		    fct_cmd->cmd_type);
2894 
2895 		return (1);
2896 	}
2897 	/* mutex_enter(&cmd_sbp->fct_mtx); */
2898 
2899 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2900 	cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
2901 
2902 	pkt = cmd_sbp->fct_pkt;
2903 	cmd_sbp->fct_pkt = NULL;
2904 
2905 	dbuf = sbp->fct_buf;
2906 
2907 	fct_cmd->cmd_comp_status = FCT_SUCCESS;
2908 
2909 	if (status) {
2910 emlxs_dma_error:
2911 		/*
2912 		 * The error indicates this IO should be terminated
2913 		 * immediately.
2914 		 */
2915 		cmd_sbp->fct_flags &= ~EMLXS_FCT_SEND_STATUS;
2916 		fct_cmd->cmd_comp_status = FCT_FAILURE;
2917 
2918 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
2919 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2920 
2921 #ifdef FCT_API_TRACE
2922 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2923 		    "fct_queue_cmd_for_termination:1 %p: x%x",
2924 		    fct_cmd, fct_cmd->cmd_comp_status);
2925 #endif /* FCT_API_TRACE */
2926 
2927 		MODSYM(fct_queue_cmd_for_termination) (fct_cmd,
2928 		    FCT_ABTS_RECEIVED);
2929 
2930 		goto done;
2931 	}
2932 
2933 	switch (iocb->ULPCOMMAND) {
2934 
2935 	/*
2936 	 *  FCP Data completion
2937 	 */
2938 	case CMD_FCP_TSEND_CX:
2939 	case CMD_FCP_TSEND64_CX:
2940 	case CMD_FCP_TRECEIVE_CX:
2941 	case CMD_FCP_TRECEIVE64_CX:
2942 
2943 		if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) {
2944 			if (emlxs_fct_dbuf_dma_sync(hba, dbuf,
2945 			    DDI_DMA_SYNC_FORCPU)) {
2946 				goto emlxs_dma_error;
2947 			}
2948 		}
2949 
2950 		if ((cmd_sbp->fct_flags & EMLXS_FCT_SEND_STATUS) &&
2951 		    (iocb->ULPCT != 1)) {
2952 
2953 			dbuf->db_flags |= DB_STATUS_GOOD_SENT;
2954 
2955 			fct_task =
2956 			    (scsi_task_t *)fct_cmd->cmd_specific;
2957 			fct_task->task_scsi_status = 0;
2958 
2959 			(void) emlxs_fct_send_fcp_status(fct_cmd);
2960 			/* mutex_exit(&cmd_sbp->fct_mtx); */
2961 
2962 			break;
2963 
2964 		} else if ((cmd_sbp->fct_flags &
2965 		    EMLXS_FCT_SEND_STATUS) &&
2966 		    (iocb->ULPCT == 1)) {
2967 			/* Auto-resp has been sent out by firmware */
2968 			/* We can assume this is really a FC_TRSP_CX */
2969 
2970 			dbuf->db_flags |= DB_STATUS_GOOD_SENT;
2971 			fct_task =
2972 			    (scsi_task_t *)fct_cmd->cmd_specific;
2973 			fct_task->task_scsi_status = 0;
2974 
2975 			cmd_sbp->fct_flags |= EMLXS_FCT_SEND_STATUS;
2976 
2977 			goto auto_resp;
2978 		}
2979 
2980 		cmd_sbp->fct_flags &= ~EMLXS_FCT_SEND_STATUS;
2981 
2982 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2983 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2984 
2985 #ifdef FCT_API_TRACE
2986 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2987 		    "fct_scsi_data_xfer_done:1 %p %p", fct_cmd, dbuf);
2988 #endif /* FCT_API_TRACE */
2989 
2990 		MODSYM(fct_scsi_data_xfer_done) (fct_cmd, dbuf, 0);
2991 
2992 		break;
2993 
2994 		/* FCP Status completion */
2995 	case CMD_FCP_TRSP_CX:
2996 	case CMD_FCP_TRSP64_CX:
2997 
2998 auto_resp:
2999 		/* Copy these before calling emlxs_fct_cmd_done */
3000 		fct_flags = cmd_sbp->fct_flags;
3001 		fct_buf = cmd_sbp->fct_buf;
3002 
3003 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3004 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3005 
3006 		TGTPORTSTAT.FctOutstandingIO--;
3007 
3008 		if (fct_flags & EMLXS_FCT_SEND_STATUS) {
3009 #ifdef FCT_API_TRACE
3010 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3011 			    "fct_scsi_data_xfer_done:2 %p %p",
3012 			    fct_cmd, fct_buf);
3013 #endif /* FCT_API_TRACE */
3014 
3015 			MODSYM(fct_scsi_data_xfer_done) (fct_cmd,
3016 			    fct_buf, FCT_IOF_FCA_DONE);
3017 		} else {
3018 #ifdef FCT_API_TRACE
3019 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3020 			    "fct_send_response_done:1 %p: x%x",
3021 			    fct_cmd, fct_cmd->cmd_comp_status);
3022 #endif /* FCT_API_TRACE */
3023 
3024 			MODSYM(fct_send_response_done) (fct_cmd,
3025 			    fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
3026 		}
3027 		break;
3028 
3029 	default:
3030 		emlxs_fct_cmd_release(port, fct_cmd, 0);
3031 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3032 
3033 		TGTPORTSTAT.FctStray++;
3034 		TGTPORTSTAT.FctCompleted--;
3035 
3036 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3037 		    "Invalid iocb: cmd=0x%x", iocb->ULPCOMMAND);
3038 
3039 		if (pkt) {
3040 			emlxs_pkt_complete(sbp, status,
3041 			    iocb->un.grsp.perr.statLocalError, 1);
3042 		}
3043 
3044 	}	/* switch(iocb->ULPCOMMAND) */
3045 
3046 
3047 done:
3048 	if (pkt) {
3049 		emlxs_pkt_free(pkt);
3050 	}
3051 
3052 	if (status == IOSTAT_SUCCESS) {
3053 		TGTPORTSTAT.FctCmplGood++;
3054 	} else {
3055 		TGTPORTSTAT.FctCmplError++;
3056 	}
3057 
3058 	return (0);
3059 
3060 } /* emlxs_fct_handle_fcp_event() */
3061 
3062 
3063 /* ARGSUSED */
3064 extern int
3065 emlxs_fct_handle_abort(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
3066 {
3067 	emlxs_port_t *port = &PPORT;
3068 	IOCB *iocb;
3069 	emlxs_buf_t *sbp;
3070 	fc_packet_t *pkt;
3071 
3072 	iocb = &iocbq->iocb;
3073 	sbp = (emlxs_buf_t *)iocbq->sbp;
3074 
3075 	TGTPORTSTAT.FctEvent++;
3076 
3077 	if (!sbp) {
3078 		/* completion with missing xmit command */
3079 		TGTPORTSTAT.FctStray++;
3080 
3081 		/* emlxs_stray_fcp_completion_msg */
3082 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3083 		    "ABORT event cmd=%x status=%x error=%x iotag=%x",
3084 		    iocb->ULPCOMMAND, iocb->ULPSTATUS,
3085 		    iocb->un.grsp.perr.statLocalError, iocb->ULPIOTAG);
3086 
3087 		return (1);
3088 	}
3089 
3090 	pkt = PRIV2PKT(sbp);
3091 
3092 #ifdef FCT_API_TRACE
3093 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3094 	    "emlxs_fct_handle_abort: %p: xri=%x status=%x", iocb->ULPCONTEXT,
3095 	    iocb->ULPCOMMAND, iocb->ULPSTATUS);
3096 #endif /* FCT_API_TRACE */
3097 
3098 
3099 	if (pkt) {
3100 		emlxs_pkt_free(pkt);
3101 	}
3102 	return (0);
3103 
3104 } /* emlxs_fct_handle_abort() */
3105 
3106 
3107 extern int
3108 emlxs_fct_handle_unsol_els(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
3109     MATCHMAP *mp, uint32_t size)
3110 {
3111 	emlxs_hba_t *hba = HBA;
3112 	IOCB *iocb;
3113 	uint32_t cmd_code;
3114 	fct_cmd_t *fct_cmd;
3115 	fct_els_t *els;
3116 	uint32_t sid;
3117 	uint32_t padding;
3118 	uint8_t *bp;
3119 	emlxs_buf_t *cmd_sbp;
3120 	uint32_t rval;
3121 
3122 	HBASTATS.ElsCmdReceived++;
3123 
3124 	bp = mp->virt;
3125 	cmd_code = (*(uint32_t *)bp) & ELS_CMD_MASK;
3126 	iocb = &iocbq->iocb;
3127 	sid = iocb->un.elsreq.remoteID;
3128 
3129 	if (!port->fct_port) {
3130 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3131 		    "%s: sid=%x. Target unbound. Rejecting...",
3132 		    emlxs_elscmd_xlate(cmd_code), sid);
3133 		(void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, cmd_code,
3134 		    LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
3135 
3136 		goto done;
3137 	}
3138 
3139 	if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
3140 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3141 		    "%s: sid=%x. Target offline. Rejecting...",
3142 		    emlxs_elscmd_xlate(cmd_code), sid);
3143 		(void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, cmd_code,
3144 		    LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
3145 
3146 		goto done;
3147 	}
3148 
3149 	/* Process the request */
3150 	switch (cmd_code) {
3151 	case ELS_CMD_FLOGI:
3152 		rval = emlxs_fct_process_unsol_flogi(port, cp, iocbq, mp, size);
3153 
3154 		if (!rval) {
3155 			ELS_PKT *els_pkt = (ELS_PKT *)bp;
3156 			fct_flogi_xchg_t fx;
3157 
3158 			bzero((uint8_t *)&fx, sizeof (fct_flogi_xchg_t));
3159 
3160 			/* Save the FLOGI exchange information */
3161 			fx.rsvd2 = iocb->ULPCONTEXT;
3162 			bcopy((caddr_t)&els_pkt->un.logi.nodeName,
3163 			    (caddr_t)fx.fx_nwwn, 8);
3164 			bcopy((caddr_t)&els_pkt->un.logi.portName,
3165 			    (caddr_t)fx.fx_pwwn, 8);
3166 			fx.fx_sid = sid;
3167 			fx.fx_did = iocb->un.elsreq.myID;
3168 			fx.fx_fport = els_pkt->un.logi.cmn.fPort;
3169 			fx.fx_op = ELS_OP_FLOGI;
3170 
3171 			emlxs_fct_handle_unsol_flogi(port, &fx, 1);
3172 		}
3173 
3174 		goto done;
3175 
3176 	case ELS_CMD_PLOGI:
3177 		rval =
3178 		    emlxs_fct_process_unsol_plogi(port, cp, iocbq, mp, size);
3179 		break;
3180 
3181 	default:
3182 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3183 		    "%s: sid=0x%x", emlxs_elscmd_xlate(cmd_code), sid);
3184 		rval = 0;
3185 		break;
3186 	}
3187 
3188 	if (rval) {
3189 		goto done;
3190 	}
3191 
3192 	padding = (8 - (size & 7)) & 7;
3193 
3194 	fct_cmd = (fct_cmd_t *)MODSYM(fct_alloc) (FCT_STRUCT_CMD_RCVD_ELS,
3195 	    (size + padding + GET_STRUCT_SIZE(emlxs_buf_t)),
3196 	    AF_FORCE_NOSLEEP);
3197 
3198 #ifdef FCT_API_TRACE
3199 	{
3200 		uint32_t *ptr = (uint32_t *)bp;
3201 
3202 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3203 		    "fct_alloc %p: ELS rcvd: rxid=%x payload: x%x x%x",
3204 		    fct_cmd, iocb->ULPCONTEXT, *ptr, *(ptr + 1));
3205 	}
3206 #endif /* FCT_API_TRACE */
3207 
3208 	if (fct_cmd == NULL) {
3209 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3210 		    "%s: sid=%x. Out of memory. Rejecting...",
3211 		    emlxs_elscmd_xlate(cmd_code), sid);
3212 
3213 		(void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, cmd_code,
3214 		    LSRJT_LOGICAL_BSY, LSEXP_OUT_OF_RESOURCE);
3215 		goto done;
3216 	}
3217 
3218 	/* Initialize fct_cmd */
3219 	fct_cmd->cmd_oxid = (cmd_code >> ELS_CMD_SHIFT) & 0xff;
3220 	fct_cmd->cmd_rxid = iocb->ULPCONTEXT;
3221 	fct_cmd->cmd_rportid = sid;
3222 	fct_cmd->cmd_lportid = port->did;
3223 	fct_cmd->cmd_rp_handle = iocb->ULPIOTAG;	/* RPI */
3224 	fct_cmd->cmd_port = port->fct_port;
3225 
3226 	cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_ELS_CMD_RECEIVED);
3227 	/* mutex_enter(&cmd_sbp->fct_mtx); */
3228 
3229 	/* Initialize cmd_sbp */
3230 	cmd_sbp->channel = cp;
3231 	cmd_sbp->class = iocb->ULPCLASS;
3232 	cmd_sbp->fct_type = EMLXS_FCT_ELS_CMD;
3233 	cmd_sbp->fct_flags |= EMLXS_FCT_PLOGI_RECEIVED;
3234 
3235 	bcopy((uint8_t *)iocb, (uint8_t *)&cmd_sbp->iocbq,
3236 	    sizeof (emlxs_iocb_t));
3237 
3238 	els = (fct_els_t *)fct_cmd->cmd_specific;
3239 	els->els_req_size = size;
3240 	els->els_req_payload =
3241 	    GET_BYTE_OFFSET(fct_cmd->cmd_fca_private,
3242 	    GET_STRUCT_SIZE(emlxs_buf_t));
3243 	bcopy(bp, els->els_req_payload, size);
3244 
3245 
3246 	/* Check if Offline */
3247 	if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
3248 
3249 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
3250 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3251 
3252 #ifdef FCT_API_TRACE
3253 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3254 		    "fct_post_rcvd_cmd:4 %p: portid x%x", fct_cmd,
3255 		    fct_cmd->cmd_lportid);
3256 #endif /* FCT_API_TRACE */
3257 
3258 		MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
3259 
3260 		goto done;
3261 	}
3262 
3263 	/* Online */
3264 	/* Check if Link up is acked */
3265 	if (port->fct_flags & FCT_STATE_LINK_UP_ACKED) {
3266 
3267 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
3268 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3269 
3270 #ifdef FCT_API_TRACE
3271 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3272 		    "fct_post_rcvd_cmd:1 %p: portid x%x", fct_cmd,
3273 		    fct_cmd->cmd_lportid);
3274 #endif /* FCT_API_TRACE */
3275 
3276 		MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
3277 
3278 		goto done;
3279 
3280 	}
3281 
3282 	/* Defer processing of fct_cmd till later (after link up ack). */
3283 
3284 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_CMD_WAITQ);
3285 	/* mutex_exit(&cmd_sbp->fct_mtx); */
3286 
3287 	/* Add cmd_sbp to queue tail */
3288 	mutex_enter(&EMLXS_PORT_LOCK);
3289 
3290 	if (port->fct_wait_tail) {
3291 		port->fct_wait_tail->next = cmd_sbp;
3292 	}
3293 	port->fct_wait_tail = cmd_sbp;
3294 
3295 	if (!port->fct_wait_head) {
3296 		port->fct_wait_head = cmd_sbp;
3297 	}
3298 
3299 	mutex_exit(&EMLXS_PORT_LOCK);
3300 
3301 done:
3302 
3303 	return (0);
3304 
3305 } /* emlxs_fct_handle_unsol_els() */
3306 
3307 
3308 /* ARGSUSED */
3309 static uint32_t
3310 emlxs_fct_process_unsol_flogi(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
3311     MATCHMAP *mp, uint32_t size)
3312 {
3313 	IOCB *iocb;
3314 	char buffer[64];
3315 
3316 	buffer[0] = 0;
3317 
3318 	iocb = &iocbq->iocb;
3319 
3320 	/* Perform processing of FLOGI payload */
3321 	if (emlxs_process_unsol_flogi(port, iocbq, mp, size, buffer)) {
3322 		return (1);
3323 	}
3324 
3325 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3326 	    "FLOGI: sid=0x%x xid=%x %s",
3327 	    iocb->un.elsreq.remoteID, iocb->ULPIOTAG, buffer);
3328 
3329 	return (0);
3330 
3331 } /* emlxs_fct_process_unsol_flogi() */
3332 
3333 
3334 /* ARGSUSED */
3335 static uint32_t
3336 emlxs_fct_process_unsol_plogi(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
3337     MATCHMAP *mp, uint32_t size)
3338 {
3339 	IOCB *iocb;
3340 	char buffer[64];
3341 
3342 	buffer[0] = 0;
3343 
3344 	iocb = &iocbq->iocb;
3345 
3346 	/* Perform processing of PLOGI payload */
3347 	if (emlxs_process_unsol_plogi(port, iocbq, mp, size, buffer)) {
3348 		return (1);
3349 	}
3350 
3351 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3352 	    "PLOGI: sid=0x%x xid=%x %s",
3353 	    iocb->un.elsreq.remoteID, iocb->ULPIOTAG, buffer);
3354 
3355 	return (0);
3356 
3357 } /* emlxs_fct_process_unsol_plogi() */
3358 
3359 
3360 /* ARGSUSED */
3361 static emlxs_buf_t *
3362 emlxs_fct_pkt_init(emlxs_port_t *port, fct_cmd_t *fct_cmd,
3363     fc_packet_t *pkt)
3364 {
3365 	emlxs_buf_t *cmd_sbp;
3366 	emlxs_buf_t *sbp;
3367 
3368 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3369 
3370 	sbp = PKT2PRIV(pkt);
3371 	sbp->fct_cmd = cmd_sbp->fct_cmd;
3372 	sbp->node = cmd_sbp->node;
3373 	sbp->channel = cmd_sbp->channel;
3374 	sbp->did = cmd_sbp->did;
3375 	sbp->lun = cmd_sbp->lun;
3376 	sbp->class = cmd_sbp->class;
3377 	sbp->fct_type = cmd_sbp->fct_type;
3378 	sbp->fct_state = cmd_sbp->fct_state;
3379 
3380 	return (sbp);
3381 
3382 } /* emlxs_fct_pkt_init() */
3383 
3384 
3385 /* Mutex will be acquired */
3386 static emlxs_buf_t *
3387 emlxs_fct_cmd_init(emlxs_port_t *port, fct_cmd_t *fct_cmd, uint32_t fct_state)
3388 {
3389 	emlxs_hba_t *hba = HBA;
3390 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3391 
3392 	bzero((void *)cmd_sbp, sizeof (emlxs_buf_t));
3393 	mutex_init(&cmd_sbp->fct_mtx, NULL, MUTEX_DRIVER,
3394 	    (void *)hba->intr_arg);
3395 	mutex_init(&cmd_sbp->mtx, NULL, MUTEX_DRIVER, (void *)hba->intr_arg);
3396 
3397 	mutex_enter(&cmd_sbp->fct_mtx);
3398 	cmd_sbp->pkt_flags = PACKET_VALID;
3399 	cmd_sbp->port = port;
3400 	cmd_sbp->fct_cmd = fct_cmd;
3401 	cmd_sbp->node = (fct_cmd->cmd_rp) ?
3402 	    *(emlxs_node_t **)fct_cmd->cmd_rp->rp_fca_private : NULL;
3403 	cmd_sbp->iocbq.sbp = cmd_sbp;
3404 	cmd_sbp->iocbq.port = port;
3405 	cmd_sbp->did = fct_cmd->cmd_rportid;
3406 
3407 	/* Flags fct_cmd as inuse */
3408 	if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
3409 		fct_cmd->cmd_oxid = 0xffff;
3410 		fct_cmd->cmd_rxid = 0xffff;
3411 	}
3412 
3413 	if (fct_state) {
3414 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3415 	}
3416 
3417 	return (cmd_sbp);
3418 
3419 } /* emlxs_fct_cmd_init() */
3420 
3421 
3422 /* Called after receiving fct_cmd from COMSTAR */
3423 static fct_status_t
3424 emlxs_fct_cmd_accept(emlxs_port_t *port, fct_cmd_t *fct_cmd, uint16_t fct_state)
3425 {
3426 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3427 
3428 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
3429 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3430 		    "emlxs_fct_cmd_accept: "
3431 		    "Invalid fct_cmd found! fct_cmd=%p state=%x",
3432 		    fct_cmd, fct_state);
3433 
3434 		return (FCT_NOT_FOUND);
3435 	}
3436 
3437 	mutex_enter(&cmd_sbp->fct_mtx);
3438 
3439 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
3440 		mutex_exit(&cmd_sbp->fct_mtx);
3441 
3442 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3443 		    "emlxs_fct_cmd_accept:2 "
3444 		    "Invalid fct_cmd found! fct_cmd=%p state=%x",
3445 		    fct_cmd, fct_state);
3446 
3447 		return (FCT_NOT_FOUND);
3448 	}
3449 
3450 	if (cmd_sbp->fct_flags & EMLXS_FCT_ABORT_INP) {
3451 
3452 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3453 		    "emlxs_fct_cmd_accept: "
3454 		    "Aborted fct_cmd found! fct_cmd=%p state=%x",
3455 		    fct_cmd, fct_state);
3456 
3457 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_ABORT_DONE);
3458 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3459 
3460 		MODSYM(fct_cmd_fca_aborted) (fct_cmd,
3461 		    FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
3462 
3463 		return (FCT_NOT_FOUND);
3464 	}
3465 
3466 	mutex_enter(&cmd_sbp->mtx);
3467 	if (!(cmd_sbp->pkt_flags & PACKET_ULP_OWNED)) {
3468 		mutex_exit(&cmd_sbp->mtx);
3469 		mutex_exit(&cmd_sbp->fct_mtx);
3470 
3471 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3472 		    "emlxs_fct_cmd_accept: "
3473 		    "Busy fct_cmd found! fct_cmd=%p state=%x",
3474 		    fct_cmd, fct_state);
3475 
3476 		return (FCT_BUSY);
3477 	}
3478 	cmd_sbp->pkt_flags &= ~PACKET_ULP_OWNED;
3479 	mutex_exit(&cmd_sbp->mtx);
3480 
3481 	if (fct_state) {
3482 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3483 	}
3484 
3485 	return (FCT_SUCCESS);
3486 
3487 } /* emlxs_fct_cmd_accept() */
3488 
3489 
3490 /* Called after receiving fct_cmd from driver */
3491 static fct_status_t
3492 emlxs_fct_cmd_acquire(emlxs_port_t *port, fct_cmd_t *fct_cmd,
3493     uint16_t fct_state)
3494 {
3495 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3496 
3497 	if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
3498 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3499 		    "emlxs_fct_cmd_acquire: "
3500 		    "Bad fct_cmd found! fct_cmd=%p state=%x",
3501 		    fct_cmd, fct_state);
3502 
3503 		return (FCT_NOT_FOUND);
3504 	}
3505 
3506 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
3507 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3508 		    "emlxs_fct_cmd_acquire: "
3509 		    "Invalid fct_cmd found! fct_cmd=%p state=%x",
3510 		    fct_cmd, fct_state);
3511 
3512 		return (FCT_NOT_FOUND);
3513 	}
3514 
3515 	if ((cmd_sbp->pkt_flags & PACKET_ULP_OWNED)) {
3516 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3517 		    "emlxs_fct_cmd_acquire: "
3518 		    "Returned fct_cmd found! fct_cmd=%p state=%x",
3519 		    fct_cmd, fct_state);
3520 
3521 		return (FCT_NOT_FOUND);
3522 	}
3523 
3524 	mutex_enter(&cmd_sbp->fct_mtx);
3525 
3526 	if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
3527 		mutex_exit(&cmd_sbp->fct_mtx);
3528 
3529 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3530 		    "emlxs_fct_cmd_acquire:2 "
3531 		    "Bad fct_cmd found! fct_cmd=%p state=%x",
3532 		    fct_cmd, fct_state);
3533 
3534 		return (FCT_NOT_FOUND);
3535 	}
3536 
3537 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
3538 		mutex_exit(&cmd_sbp->fct_mtx);
3539 
3540 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3541 		    "emlxs_fct_cmd_acquire:2 "
3542 		    "Invalid fct_cmd found! fct_cmd=%p state=%x",
3543 		    fct_cmd, fct_state);
3544 
3545 		return (FCT_NOT_FOUND);
3546 	}
3547 
3548 	if ((cmd_sbp->pkt_flags & PACKET_ULP_OWNED)) {
3549 		mutex_exit(&cmd_sbp->fct_mtx);
3550 
3551 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3552 		    "emlxs_fct_cmd_acquire:2 "
3553 		    "Returned fct_cmd found! fct_cmd=%p state=%x",
3554 		    fct_cmd, fct_state);
3555 
3556 		return (FCT_NOT_FOUND);
3557 	}
3558 
3559 	if (cmd_sbp->fct_flags & EMLXS_FCT_ABORT_INP) {
3560 
3561 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3562 		    "emlxs_fct_cmd_acquire: "
3563 		    "Aborting cmd. fct_cmd=%p state=%x",
3564 		    fct_cmd, fct_state);
3565 
3566 		if (fct_cmd->cmd_type == FCT_CMD_FCP_XCHG) {
3567 			TGTPORTSTAT.FctOutstandingIO--;
3568 		}
3569 
3570 		fct_cmd->cmd_comp_status = FCT_FAILURE;
3571 
3572 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_ABORT_DONE);
3573 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3574 
3575 		MODSYM(fct_cmd_fca_aborted) (fct_cmd,
3576 		    FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
3577 
3578 		return (FCT_NOT_FOUND);
3579 	}
3580 
3581 	if (fct_state) {
3582 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3583 	}
3584 
3585 	return (FCT_SUCCESS);
3586 
3587 } /* emlxs_fct_cmd_acquire() */
3588 
3589 
3590 /* cmd_sbp->fct_mtx must be held to enter */
3591 /* cmd_sbp->fct_mtx must be released before exiting */
3592 /* Called before transitionally sending fct_cmd to driver */
3593 /*ARGSUSED*/
3594 static void
3595 emlxs_fct_cmd_release(emlxs_port_t *port, fct_cmd_t *fct_cmd,
3596     uint16_t fct_state)
3597 {
3598 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3599 
3600 	if (fct_state) {
3601 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3602 	}
3603 
3604 	mutex_exit(&cmd_sbp->fct_mtx);
3605 
3606 	return;
3607 
3608 } /* emlxs_fct_cmd_release() */
3609 
3610 
3611 /* cmd_sbp->fct_mtx must be held to enter */
3612 /* cmd_sbp->fct_mtx must be released before exiting */
3613 /* Called before posting fct_cmd back to COMSTAR */
3614 /*ARGSUSED*/
3615 static void
3616 emlxs_fct_cmd_post(emlxs_port_t *port, fct_cmd_t *fct_cmd,
3617     uint16_t fct_state)
3618 {
3619 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3620 	fc_packet_t *pkt;
3621 
3622 	pkt = cmd_sbp->fct_pkt;
3623 	cmd_sbp->fct_pkt = NULL;
3624 	cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
3625 
3626 	mutex_enter(&cmd_sbp->mtx);
3627 	cmd_sbp->pkt_flags |= PACKET_ULP_OWNED;
3628 	mutex_exit(&cmd_sbp->mtx);
3629 
3630 	if (fct_state) {
3631 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3632 	}
3633 
3634 	mutex_exit(&cmd_sbp->fct_mtx);
3635 
3636 	if (pkt) {
3637 		emlxs_pkt_free(pkt);
3638 	}
3639 
3640 	return;
3641 
3642 } /* emlxs_fct_cmd_post() */
3643 
3644 
3645 /* cmd_sbp->fct_mtx must be held to enter */
3646 /* Called before completing fct_cmd back to COMSTAR */
3647 static void
3648 emlxs_fct_cmd_done(emlxs_port_t *port, fct_cmd_t *fct_cmd, uint16_t fct_state)
3649 {
3650 	emlxs_hba_t *hba = HBA;
3651 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3652 	fc_packet_t *pkt;
3653 
3654 	/* Flags fct_cmd is no longer used */
3655 	fct_cmd->cmd_oxid = 0;
3656 	fct_cmd->cmd_rxid = 0;
3657 
3658 	if (cmd_sbp->iotag != 0) {
3659 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3660 		    "Pkt still registered! channel=%d iotag=%d sbp=%p",
3661 		    cmd_sbp->channel, cmd_sbp->iotag, cmd_sbp);
3662 
3663 		if (cmd_sbp->channel) {
3664 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3665 				hba->fc_table[cmd_sbp->iotag] = NULL;
3666 				emlxs_sli4_free_xri(hba, cmd_sbp, cmd_sbp->xp);
3667 			} else {
3668 				(void) emlxs_unregister_pkt(cmd_sbp->channel,
3669 				    cmd_sbp->iotag, 0);
3670 			}
3671 
3672 		}
3673 	}
3674 
3675 	pkt = cmd_sbp->fct_pkt;
3676 	cmd_sbp->fct_pkt = NULL;
3677 	cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
3678 
3679 	if (fct_state) {
3680 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3681 	}
3682 
3683 	mutex_enter(&cmd_sbp->mtx);
3684 	cmd_sbp->pkt_flags |= PACKET_ULP_OWNED;
3685 	cmd_sbp->pkt_flags &= ~PACKET_VALID;
3686 	mutex_exit(&cmd_sbp->mtx);
3687 	mutex_exit(&cmd_sbp->fct_mtx);
3688 
3689 
3690 	mutex_destroy(&cmd_sbp->fct_mtx);
3691 	mutex_destroy(&cmd_sbp->mtx);
3692 
3693 	if (pkt) {
3694 		emlxs_pkt_free(pkt);
3695 	}
3696 
3697 	return;
3698 
3699 } /* emlxs_fct_cmd_done() */
3700 
3701 
3702 static void
3703 emlxs_fct_pkt_comp(fc_packet_t *pkt)
3704 {
3705 	emlxs_port_t *port;
3706 #ifdef FMA_SUPPORT
3707 	emlxs_hba_t *hba;
3708 #endif	/* FMA_SUPPORT */
3709 	emlxs_buf_t *sbp;
3710 	emlxs_buf_t *cmd_sbp;
3711 	fct_cmd_t *fct_cmd;
3712 	fct_els_t *fct_els;
3713 	fct_sol_ct_t *fct_ct;
3714 	fct_status_t rval;
3715 
3716 	sbp = PKT2PRIV(pkt);
3717 	port = sbp->port;
3718 #ifdef FMA_SUPPORT
3719 	hba = HBA;
3720 #endif	/* FMA_SUPPORT */
3721 	fct_cmd = sbp->fct_cmd;
3722 
3723 	rval = emlxs_fct_cmd_acquire(port, fct_cmd, EMLXS_FCT_PKT_COMPLETE);
3724 	if (rval) {
3725 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3726 		    "emlxs_fct_pkt_comp: "
3727 		    "Unable to reacquire fct_cmd.");
3728 		return;
3729 	}
3730 	/* mutex_enter(&cmd_sbp->fct_mtx); */
3731 
3732 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3733 	cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
3734 	cmd_sbp->fct_pkt = NULL;
3735 
3736 	switch (fct_cmd->cmd_type) {
3737 	case FCT_CMD_FCP_XCHG:
3738 		if ((pkt->pkt_reason == FC_REASON_ABORTED) ||
3739 		    (pkt->pkt_reason == FC_REASON_XCHG_DROPPED) ||
3740 		    (pkt->pkt_reason == FC_REASON_OFFLINE)) {
3741 			/*
3742 			 * The error indicates this IO should be terminated
3743 			 * immediately.
3744 			 */
3745 			cmd_sbp->fct_flags &= ~EMLXS_FCT_SEND_STATUS;
3746 
3747 			emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
3748 			/* mutex_exit(&cmd_sbp->fct_mtx); */
3749 
3750 #ifdef FCT_API_TRACE
3751 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3752 			    "fct_queue_cmd_for_termination:2 %p: x%x",
3753 			    fct_cmd, fct_cmd->cmd_comp_status);
3754 #endif /* FCT_API_TRACE */
3755 
3756 			MODSYM(fct_queue_cmd_for_termination) (fct_cmd,
3757 			    FCT_ABTS_RECEIVED);
3758 
3759 			break;
3760 		}
3761 
3762 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp,
3763 		    EMLXS_FCT_PKT_FCPRSP_COMPLETE);
3764 
3765 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3766 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3767 
3768 #ifdef FCT_API_TRACE
3769 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3770 		    "fct_send_response_done:2 %p: x%x",
3771 		    fct_cmd, fct_cmd->cmd_comp_status);
3772 #else
3773 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3774 		    "emlxs_fct_pkt_comp: fct_send_response_done. dbuf=%p",
3775 		    sbp->fct_buf);
3776 #endif /* FCT_API_TRACE */
3777 
3778 		TGTPORTSTAT.FctOutstandingIO--;
3779 
3780 		MODSYM(fct_send_response_done) (fct_cmd,
3781 		    fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
3782 
3783 		break;
3784 
3785 	case FCT_CMD_RCVD_ELS:
3786 
3787 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp,
3788 		    EMLXS_FCT_PKT_ELSRSP_COMPLETE);
3789 
3790 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3791 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3792 
3793 #ifdef FCT_API_TRACE
3794 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3795 		    "fct_send_response_done:3 %p: x%x",
3796 		    fct_cmd, fct_cmd->cmd_comp_status);
3797 #endif /* FCT_API_TRACE */
3798 
3799 		MODSYM(fct_send_response_done) (fct_cmd,
3800 		    fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
3801 
3802 		break;
3803 
3804 	case FCT_CMD_SOL_ELS:
3805 
3806 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp,
3807 		    EMLXS_FCT_PKT_ELSCMD_COMPLETE);
3808 
3809 		fct_els = (fct_els_t *)fct_cmd->cmd_specific;
3810 
3811 		if (fct_els->els_resp_payload) {
3812 			EMLXS_MPDATA_SYNC(pkt->pkt_resp_dma, 0,
3813 			    pkt->pkt_rsplen, DDI_DMA_SYNC_FORKERNEL);
3814 
3815 			bcopy((uint8_t *)pkt->pkt_resp,
3816 			    (uint8_t *)fct_els->els_resp_payload,
3817 			    fct_els->els_resp_size);
3818 		}
3819 
3820 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3821 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3822 
3823 #ifdef FCT_API_TRACE
3824 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3825 		    "fct_send_cmd_done:1 %p: x%x",
3826 		    fct_cmd, fct_cmd->cmd_comp_status);
3827 #endif /* FCT_API_TRACE */
3828 
3829 #ifdef FMA_SUPPORT
3830 		if (emlxs_fm_check_dma_handle(hba, pkt->pkt_resp_dma)
3831 		    != DDI_FM_OK) {
3832 			EMLXS_MSGF(EMLXS_CONTEXT,
3833 			    &emlxs_invalid_dma_handle_msg,
3834 			    "emlxs_fct_pkt_comp: hdl=%p",
3835 			    pkt->pkt_resp_dma);
3836 			MODSYM(fct_send_cmd_done) (fct_cmd, FCT_FAILURE,
3837 			    FCT_IOF_FCA_DONE);
3838 
3839 			break;
3840 		}
3841 #endif /* FMA_SUPPORT */
3842 
3843 		MODSYM(fct_send_cmd_done) (fct_cmd, FCT_SUCCESS,
3844 		    FCT_IOF_FCA_DONE);
3845 
3846 		break;
3847 
3848 	case FCT_CMD_SOL_CT:
3849 
3850 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp,
3851 		    EMLXS_FCT_PKT_CTCMD_COMPLETE);
3852 
3853 		fct_ct = (fct_sol_ct_t *)fct_cmd->cmd_specific;
3854 
3855 		if (fct_ct->ct_resp_payload) {
3856 			EMLXS_MPDATA_SYNC(pkt->pkt_resp_dma, 0,
3857 			    pkt->pkt_rsplen, DDI_DMA_SYNC_FORKERNEL);
3858 
3859 			bcopy((uint8_t *)pkt->pkt_resp,
3860 			    (uint8_t *)fct_ct->ct_resp_payload,
3861 			    fct_ct->ct_resp_size);
3862 		}
3863 
3864 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3865 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3866 
3867 #ifdef FCT_API_TRACE
3868 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3869 		    "fct_send_cmd_done:2 %p: x%x",
3870 		    fct_cmd, fct_cmd->cmd_comp_status);
3871 #endif /* FCT_API_TRACE */
3872 
3873 #ifdef FMA_SUPPORT
3874 		if (emlxs_fm_check_dma_handle(hba, pkt->pkt_resp_dma)
3875 		    != DDI_FM_OK) {
3876 			EMLXS_MSGF(EMLXS_CONTEXT,
3877 			    &emlxs_invalid_dma_handle_msg,
3878 			    "emlxs_fct_pkt_comp: hdl=%p",
3879 			    pkt->pkt_resp_dma);
3880 			MODSYM(fct_send_cmd_done) (fct_cmd, FCT_FAILURE,
3881 			    FCT_IOF_FCA_DONE);
3882 
3883 			break;
3884 		}
3885 #endif /* FMA_SUPPORT */
3886 		MODSYM(fct_send_cmd_done) (fct_cmd, FCT_SUCCESS,
3887 		    FCT_IOF_FCA_DONE);
3888 
3889 		break;
3890 
3891 	default:
3892 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3893 		    "emlxs_fct_pkt_comp: Invalid cmd type found. type=%x",
3894 		    fct_cmd->cmd_type);
3895 
3896 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3897 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3898 
3899 		break;
3900 	}
3901 
3902 	emlxs_pkt_free(pkt);
3903 	return;
3904 
3905 } /* emlxs_fct_pkt_comp() */
3906 
3907 
3908 static void
3909 emlxs_fct_abort_pkt_comp(fc_packet_t *pkt)
3910 {
3911 #ifdef FCT_API_TRACE_11
3912 	emlxs_buf_t *sbp;
3913 	IOCBQ *iocbq;
3914 	IOCB *iocb;
3915 
3916 	sbp = PKT2PRIV(pkt);
3917 	iocbq = &sbp->iocbq;
3918 	iocb = &iocbq->iocb;
3919 
3920 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3921 	    "emlxs_fct_handle_abort: %p: xri=%x status=%x", iocb->ULPCONTEXT,
3922 	    iocb->ULPCOMMAND, iocb->ULPSTATUS);
3923 #endif /* FCT_API_TRACE */
3924 
3925 	emlxs_pkt_free(pkt);
3926 	return;
3927 
3928 } /* emlxs_fct_abort_pkt_comp() */
3929 
3930 
3931 /* COMSTAR ENTER POINT (INDIRECT) */
3932 static fct_status_t
3933 emlxs_fct_send_els_cmd(fct_cmd_t *fct_cmd)
3934 {
3935 	emlxs_port_t *port =
3936 	    (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
3937 	emlxs_hba_t *hba = HBA;
3938 	uint32_t did;
3939 	fct_els_t *fct_els;
3940 	fc_packet_t *pkt;
3941 	emlxs_buf_t *cmd_sbp;
3942 	fct_status_t rval;
3943 
3944 	did = fct_cmd->cmd_rportid;
3945 	fct_els = (fct_els_t *)fct_cmd->cmd_specific;
3946 
3947 	if (!(pkt = emlxs_pkt_alloc(port, fct_els->els_req_size,
3948 	    fct_els->els_resp_size, 0, KM_NOSLEEP))) {
3949 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
3950 		    "emlxs_fct_send_els_cmd: Unable to allocate packet.");
3951 
3952 		return (FCT_BUSY);
3953 	}
3954 
3955 	cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_SEND_ELS_REQ);
3956 	/* mutex_enter(&cmd_sbp->fct_mtx); */
3957 
3958 	cmd_sbp->channel = &hba->chan[hba->channel_els];
3959 	cmd_sbp->fct_type = EMLXS_FCT_ELS_REQ;
3960 
3961 	(void) emlxs_fct_pkt_init(port, fct_cmd, pkt);
3962 	cmd_sbp->fct_pkt = pkt;
3963 
3964 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
3965 	pkt->pkt_timeout =
3966 	    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
3967 	pkt->pkt_comp = emlxs_fct_pkt_comp;
3968 
3969 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3970 	    "emlxs_fct_send_els_cmd: pkt_timeout=%d ratov=%d",
3971 	    pkt->pkt_timeout, hba->fc_ratov);
3972 
3973 	/* Build the fc header */
3974 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
3975 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
3976 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
3977 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
3978 	pkt->pkt_cmd_fhdr.f_ctl =
3979 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
3980 	pkt->pkt_cmd_fhdr.seq_id = 0;
3981 	pkt->pkt_cmd_fhdr.df_ctl = 0;
3982 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
3983 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
3984 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
3985 	pkt->pkt_cmd_fhdr.ro = 0;
3986 
3987 	/* Copy the cmd payload */
3988 	bcopy((uint8_t *)fct_els->els_req_payload, (uint8_t *)pkt->pkt_cmd,
3989 	    fct_els->els_req_size);
3990 
3991 	cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
3992 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_REQ_PENDING);
3993 	/* mutex_exit(&cmd_sbp->fct_mtx); */
3994 
3995 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
3996 
3997 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
3998 		    "emlxs_fct_send_els_cmd: Unable to send packet.");
3999 
4000 		/* Reacquire ownership of the fct_cmd */
4001 		rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
4002 		if (rval) {
4003 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4004 			    "emlxs_fct_send_els_cmd: "
4005 			    "Unable to reacquire fct_cmd.");
4006 			return (rval);
4007 		}
4008 		/* mutex_enter(&cmd_sbp->fct_mtx); */
4009 
4010 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
4011 		/* mutex_exit(&cmd_sbp->fct_mtx); */
4012 
4013 		return (FCT_BUSY);
4014 	}
4015 
4016 	return (FCT_SUCCESS);
4017 
4018 } /* emlxs_fct_send_els_cmd() */
4019 
4020 
4021 /* cmd_sbp->fct_mtx must be held to enter */
4022 /* cmd_sbp->fct_mtx must be released before exiting */
4023 static fct_status_t
4024 emlxs_fct_send_els_rsp(fct_cmd_t *fct_cmd)
4025 {
4026 	emlxs_port_t *port =
4027 	    (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
4028 	emlxs_hba_t *hba = HBA;
4029 	uint32_t did;
4030 	fct_els_t *fct_els;
4031 	fc_packet_t *pkt;
4032 	emlxs_buf_t *cmd_sbp;
4033 	fct_status_t rval;
4034 
4035 	fct_els = (fct_els_t *)fct_cmd->cmd_specific;
4036 	did = fct_cmd->cmd_rportid;
4037 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
4038 
4039 	if (!(pkt = emlxs_pkt_alloc(port, fct_els->els_resp_size, 0, 0,
4040 	    KM_NOSLEEP))) {
4041 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4042 		    "emlxs_fct_send_els_rsp: Unable to allocate packet.");
4043 
4044 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
4045 		/* mutex_exit(&cmd_sbp->fct_mtx); */
4046 
4047 		return (FCT_FAILURE);
4048 	}
4049 
4050 	EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, EMLXS_FCT_SEND_ELS_RSP);
4051 
4052 	cmd_sbp->fct_type = EMLXS_FCT_ELS_RSP;
4053 
4054 	(void) emlxs_fct_pkt_init(port, fct_cmd, pkt);
4055 	cmd_sbp->fct_pkt = pkt;
4056 
4057 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
4058 	pkt->pkt_timeout =
4059 	    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
4060 	pkt->pkt_comp = emlxs_fct_pkt_comp;
4061 
4062 	/* Build the fc header */
4063 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
4064 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_RSP;
4065 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
4066 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
4067 	pkt->pkt_cmd_fhdr.f_ctl =
4068 	    F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ;
4069 	pkt->pkt_cmd_fhdr.seq_id = 0;
4070 	pkt->pkt_cmd_fhdr.df_ctl = 0;
4071 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
4072 	pkt->pkt_cmd_fhdr.ox_id = fct_cmd->cmd_oxid;
4073 	pkt->pkt_cmd_fhdr.rx_id = fct_cmd->cmd_rxid;
4074 	pkt->pkt_cmd_fhdr.ro = 0;
4075 
4076 	/* Copy the resp payload to pkt_cmd buffer */
4077 	bcopy((uint8_t *)fct_els->els_resp_payload, (uint8_t *)pkt->pkt_cmd,
4078 	    fct_els->els_resp_size);
4079 
4080 	cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
4081 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_RSP_PENDING);
4082 	/* mutex_exit(&cmd_sbp->fct_mtx); */
4083 
4084 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
4085 
4086 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4087 		    "emlxs_fct_send_els_rsp: Unable to send packet.");
4088 
4089 		/* Reacquire ownership of the fct_cmd */
4090 		rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
4091 		if (rval) {
4092 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4093 			    "emlxs_fct_send_els_rsp: "
4094 			    "Unable to reacquire fct_cmd.");
4095 			return (rval);
4096 		}
4097 		/* mutex_enter(&cmd_sbp->fct_mtx); */
4098 
4099 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
4100 		/* mutex_exit(&cmd_sbp->fct_mtx); */
4101 
4102 		return (FCT_FAILURE);
4103 	}
4104 
4105 	return (FCT_SUCCESS);
4106 
4107 } /* emlxs_fct_send_els_rsp() */
4108 
4109 
4110 /* COMSTAR ENTER POINT (INDIRECT) */
4111 static fct_status_t
4112 emlxs_fct_send_ct_cmd(fct_cmd_t *fct_cmd)
4113 {
4114 	emlxs_port_t *port =
4115 	    (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
4116 	emlxs_hba_t *hba = HBA;
4117 	uint32_t did;
4118 	fct_sol_ct_t *fct_ct;
4119 	fc_packet_t *pkt;
4120 	emlxs_buf_t *cmd_sbp;
4121 	fct_status_t rval;
4122 
4123 	did = fct_cmd->cmd_rportid;
4124 	fct_ct = (fct_sol_ct_t *)fct_cmd->cmd_specific;
4125 
4126 	if (!(pkt = emlxs_pkt_alloc(port, fct_ct->ct_req_size,
4127 	    fct_ct->ct_resp_size, 0, KM_NOSLEEP))) {
4128 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4129 		    "emlxs_fct_send_ct_cmd: Unable to allocate packet.");
4130 		return (FCT_BUSY);
4131 	}
4132 
4133 	cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_SEND_CT_REQ);
4134 	/* mutex_enter(&cmd_sbp->fct_mtx); */
4135 
4136 	cmd_sbp->channel = &hba->chan[hba->channel_ct];
4137 	cmd_sbp->fct_type = EMLXS_FCT_CT_REQ;
4138 
4139 	(void) emlxs_fct_pkt_init(port, fct_cmd, pkt);
4140 	cmd_sbp->fct_pkt = pkt;
4141 
4142 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4143 	pkt->pkt_timeout =
4144 	    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
4145 	pkt->pkt_comp = emlxs_fct_pkt_comp;
4146 
4147 	/* Build the fc header */
4148 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
4149 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
4150 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
4151 	pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
4152 	pkt->pkt_cmd_fhdr.f_ctl =
4153 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
4154 	pkt->pkt_cmd_fhdr.seq_id = 0;
4155 	pkt->pkt_cmd_fhdr.df_ctl = 0;
4156 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
4157 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
4158 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
4159 	pkt->pkt_cmd_fhdr.ro = 0;
4160 
4161 	/* Copy the cmd payload */
4162 	bcopy((uint8_t *)fct_ct->ct_req_payload, (uint8_t *)pkt->pkt_cmd,
4163 	    fct_ct->ct_req_size);
4164 
4165 	cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
4166 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_REQ_PENDING);
4167 	/* mutex_exit(&cmd_sbp->fct_mtx); */
4168 
4169 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
4170 
4171 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4172 		    "emlxs_fct_send_ct_cmd: Unable to send packet.");
4173 
4174 		/* Reacquire ownership of the fct_cmd */
4175 		rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
4176 		if (rval) {
4177 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4178 			    "emlxs_fct_send_ct_cmd: "
4179 			    "Unable to reacquire fct_cmd.");
4180 
4181 			return (rval);
4182 		}
4183 		/* mutex_enter(&cmd_sbp->fct_mtx); */
4184 
4185 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
4186 		/* mutex_exit(&cmd_sbp->fct_mtx); */
4187 
4188 		return (FCT_BUSY);
4189 	}
4190 
4191 	return (FCT_SUCCESS);
4192 
4193 } /* emlxs_fct_send_ct_cmd() */
4194 
4195 
4196 /* cmd_sbp->fct_mtx must be held to enter */
4197 static uint32_t
4198 emlxs_fct_pkt_abort_txq(emlxs_port_t *port, emlxs_buf_t *cmd_sbp)
4199 {
4200 	emlxs_hba_t *hba = HBA;
4201 	NODELIST *nlp;
4202 	fc_packet_t *pkt;
4203 	emlxs_buf_t *sbp;
4204 	emlxs_buf_t *iocb_sbp;
4205 	uint8_t channelno;
4206 	CHANNEL *cp;
4207 	IOCBQ *iocbq;
4208 	IOCBQ *next;
4209 	IOCBQ *prev;
4210 	uint32_t found;
4211 	uint32_t pkt_flags;
4212 
4213 	/* Check the transmit queue */
4214 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
4215 
4216 	/* The IOCB could point to a cmd_sbp (no packet) or a sbp (packet) */
4217 	pkt = cmd_sbp->fct_pkt;
4218 	if (pkt) {
4219 		sbp = PKT2PRIV(pkt);
4220 		if (sbp == NULL) {
4221 			goto done;
4222 		}
4223 		iocb_sbp = sbp;
4224 		iocbq = &sbp->iocbq;
4225 		pkt_flags = sbp->pkt_flags;
4226 	} else {
4227 		sbp = NULL;
4228 		iocb_sbp = cmd_sbp;
4229 		iocbq = &cmd_sbp->iocbq;
4230 		pkt_flags = cmd_sbp->pkt_flags;
4231 	}
4232 
4233 	nlp = (NODELIST *)cmd_sbp->node;
4234 	cp = (CHANNEL *)cmd_sbp->channel;
4235 	channelno = (cp) ? cp->channelno : 0;
4236 
4237 	if (pkt_flags & PACKET_IN_TXQ) {
4238 		/* Find it on the queue */
4239 		found = 0;
4240 		if (iocbq->flag & IOCB_PRIORITY) {
4241 			/* Search the priority queue */
4242 			prev = NULL;
4243 			next = (IOCBQ *)nlp->nlp_ptx[channelno].q_first;
4244 
4245 			while (next) {
4246 				if (next == iocbq) {
4247 					/* Remove it */
4248 					if (prev) {
4249 						prev->next = iocbq->next;
4250 					}
4251 
4252 					if (nlp->nlp_ptx[channelno].q_last ==
4253 					    (void *)iocbq) {
4254 						nlp->nlp_ptx[channelno].q_last =
4255 						    (void *)prev;
4256 					}
4257 
4258 					if (nlp->nlp_ptx[channelno].q_first ==
4259 					    (void *)iocbq) {
4260 						nlp->nlp_ptx[channelno].
4261 						    q_first =
4262 						    (void *)iocbq->next;
4263 					}
4264 
4265 					nlp->nlp_ptx[channelno].q_cnt--;
4266 					iocbq->next = NULL;
4267 					found = 1;
4268 					break;
4269 				}
4270 
4271 				prev = next;
4272 				next = next->next;
4273 			}
4274 		} else {
4275 			/* Search the normal queue */
4276 			prev = NULL;
4277 			next = (IOCBQ *)nlp->nlp_tx[channelno].q_first;
4278 
4279 			while (next) {
4280 				if (next == iocbq) {
4281 					/* Remove it */
4282 					if (prev) {
4283 						prev->next = iocbq->next;
4284 					}
4285 
4286 					if (nlp->nlp_tx[channelno].q_last ==
4287 					    (void *)iocbq) {
4288 						nlp->nlp_tx[channelno].q_last =
4289 						    (void *)prev;
4290 					}
4291 
4292 					if (nlp->nlp_tx[channelno].q_first ==
4293 					    (void *)iocbq) {
4294 						nlp->nlp_tx[channelno].q_first =
4295 						    (void *)iocbq->next;
4296 					}
4297 
4298 					nlp->nlp_tx[channelno].q_cnt--;
4299 					iocbq->next = NULL;
4300 					found = 1;
4301 					break;
4302 				}
4303 
4304 				prev = next;
4305 				next = (IOCBQ *)next->next;
4306 			}
4307 		}
4308 
4309 		if (!found) {
4310 			goto done;
4311 		}
4312 
4313 		/* Check if node still needs servicing */
4314 		if ((nlp->nlp_ptx[channelno].q_first) ||
4315 		    (nlp->nlp_tx[channelno].q_first &&
4316 		    !(nlp->nlp_flag[channelno] & NLP_CLOSED))) {
4317 
4318 			/*
4319 			 * If this is the base node, don't shift the pointers
4320 			 */
4321 			/* We want to drain the base node before moving on */
4322 			if (!nlp->nlp_base) {
4323 				/* Shift channel queue pointers to next node */
4324 				cp->nodeq.q_last = (void *)nlp;
4325 				cp->nodeq.q_first = nlp->nlp_next[channelno];
4326 			}
4327 		} else {
4328 			/* Remove node from channel queue */
4329 
4330 			/* If this is the last node on list */
4331 			if (cp->nodeq.q_last == (void *)nlp) {
4332 				cp->nodeq.q_last = NULL;
4333 				cp->nodeq.q_first = NULL;
4334 				cp->nodeq.q_cnt = 0;
4335 			} else {
4336 				/* Remove node from head */
4337 				cp->nodeq.q_first = nlp->nlp_next[channelno];
4338 				((NODELIST *)cp->nodeq.q_last)->
4339 				    nlp_next[channelno] = cp->nodeq.q_first;
4340 				cp->nodeq.q_cnt--;
4341 			}
4342 
4343 			/* Clear node */
4344 			nlp->nlp_next[channelno] = NULL;
4345 		}
4346 
4347 		/* The IOCB points to iocb_sbp (no packet) or a sbp (packet) */
4348 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4349 			hba->fc_table[iocb_sbp->iotag] = NULL;
4350 			emlxs_sli4_free_xri(hba, iocb_sbp, iocb_sbp->xp);
4351 		} else {
4352 			(void) emlxs_unregister_pkt(cp, iocb_sbp->iotag, 0);
4353 		}
4354 
4355 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
4356 
4357 		if (pkt) {
4358 			emlxs_pkt_free(pkt);
4359 			cmd_sbp->fct_pkt = NULL;
4360 		}
4361 		return (1);
4362 	}
4363 done:
4364 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
4365 	return (0);
4366 
4367 } /* emlxs_fct_pkt_abort_txq() */
4368 
4369 
4370 /* COMSTAR ENTER POINT */
4371 /* FCT_NOT_FOUND & FCT_ABORT_SUCCESS indicates IO is done */
4372 /* FCT_SUCCESS indicates abort will occur asyncronously */
4373 static fct_status_t
4374 emlxs_fct_abort(fct_local_port_t *fct_port, fct_cmd_t *fct_cmd,
4375     uint32_t flags)
4376 {
4377 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
4378 	emlxs_hba_t *hba = HBA;
4379 	emlxs_buf_t *cmd_sbp;
4380 	emlxs_buf_t *cmd_sbp2;
4381 	emlxs_buf_t *prev;
4382 	fc_packet_t *pkt;
4383 	emlxs_buf_t *sbp = NULL;
4384 	kmutex_t *fct_mtx;
4385 	uint32_t fct_state;
4386 
4387 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
4388 	fct_mtx = &cmd_sbp->fct_mtx;
4389 
4390 top:
4391 
4392 	/* Sanity check */
4393 	if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
4394 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4395 		    "emlxs_fct_abort: Bad fct_cmd=%p.", fct_cmd);
4396 
4397 		return (FCT_NOT_FOUND);
4398 	}
4399 
4400 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
4401 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4402 		    "emlxs_fct_abort: Pkt invalid. cmd_sbp=%p",
4403 		    cmd_sbp);
4404 
4405 		return (FCT_NOT_FOUND);
4406 	}
4407 
4408 	if (mutex_tryenter(fct_mtx) == 0) {
4409 		/*
4410 		 * This code path handles a race condition if
4411 		 * an IO completes, in emlxs_fct_handle_fcp_event(),
4412 		 * and we get an abort at the same time.
4413 		 */
4414 		delay(drv_usectohz(100000));	/* 100 msec */
4415 		goto top;
4416 	}
4417 	/* At this point, we have entered the mutex */
4418 
4419 	/* Sanity check */
4420 	if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
4421 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4422 		    "emlxs_fct_abort: Bad fct_cmd=%p.", fct_cmd);
4423 
4424 		mutex_exit(fct_mtx);
4425 		return (FCT_NOT_FOUND);
4426 	}
4427 
4428 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
4429 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4430 		    "emlxs_fct_abort: Pkt invalid. cmd_sbp=%p",
4431 		    cmd_sbp);
4432 
4433 		mutex_exit(fct_mtx);
4434 		return (FCT_NOT_FOUND);
4435 	}
4436 
4437 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4438 	    "emlxs_fct_abort: hbastate=%x. "
4439 	    "xid=%x,%x cmd_sbp=%p fctstate=%d flags=%x,%x,%x",
4440 	    hba->state, fct_cmd->cmd_oxid, fct_cmd->cmd_rxid, cmd_sbp,
4441 	    cmd_sbp->fct_state, flags, cmd_sbp->fct_flags, cmd_sbp->pkt_flags);
4442 
4443 	if (cmd_sbp->fct_flags & EMLXS_FCT_ABORT_INP) {
4444 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cmd_sbp->channel, 0);
4445 
4446 		/* If Abort is already in progress */
4447 		mutex_exit(fct_mtx);
4448 		return (FCT_SUCCESS);
4449 	}
4450 	cmd_sbp->fct_flags |= EMLXS_FCT_ABORT_INP;
4451 
4452 	if (flags & FCT_IOF_FORCE_FCA_DONE) {
4453 		fct_cmd->cmd_handle = 0;
4454 	}
4455 
4456 	TGTPORTSTAT.FctAbortSent++;
4457 
4458 	switch (cmd_sbp->fct_state) {
4459 	/* These are currently owned by COMSTAR. */
4460 	/* They were last processed by emlxs_fct_cmd_post() */
4461 	/* We have NO exchange resources associated with this IO. */
4462 	case EMLXS_FCT_OWNED:
4463 		goto abort_done;
4464 
4465 	/* These are on the unsol waitQ in the driver */
4466 	case EMLXS_FCT_CMD_WAITQ:
4467 		/* Find and remove it */
4468 		mutex_enter(&EMLXS_PORT_LOCK);
4469 		cmd_sbp2 = port->fct_wait_head;
4470 		prev = NULL;
4471 		while (cmd_sbp2) {
4472 			if (cmd_sbp2 == cmd_sbp) {
4473 				/* Remove it */
4474 				if (prev) {
4475 					prev->next = cmd_sbp2->next;
4476 				}
4477 
4478 				if (port->fct_wait_head == cmd_sbp2) {
4479 					port->fct_wait_head = cmd_sbp2->next;
4480 				}
4481 
4482 				if (port->fct_wait_tail == cmd_sbp2) {
4483 					port->fct_wait_tail = prev;
4484 				}
4485 
4486 				cmd_sbp2->next = NULL;
4487 				break;
4488 			}
4489 			prev = cmd_sbp2;
4490 			cmd_sbp2 = cmd_sbp2->next;
4491 		}
4492 		mutex_exit(&EMLXS_PORT_LOCK);
4493 
4494 		/*FALLTHROUGH*/
4495 
4496 	/* These are currently owned by COMSTAR. */
4497 	/* They were last processed by emlxs_fct_cmd_post() */
4498 	/* We have residual exchange resources associated with this IO */
4499 	case EMLXS_FCT_CMD_POSTED:
4500 		switch (fct_cmd->cmd_type) {
4501 		case FCT_CMD_FCP_XCHG: /* Unsol */
4502 			TGTPORTSTAT.FctOutstandingIO--;
4503 			emlxs_abort_fct_exchange(hba, port, fct_cmd->cmd_rxid);
4504 			break;
4505 
4506 		case FCT_CMD_RCVD_ELS: /* Unsol */
4507 			emlxs_abort_els_exchange(hba, port, fct_cmd->cmd_rxid);
4508 			break;
4509 		}
4510 
4511 		goto abort_done;
4512 
4513 	/* These are active in the driver */
4514 	/* They were last processed by emlxs_fct_cmd_release() */
4515 	case EMLXS_FCT_RSP_PENDING:
4516 	case EMLXS_FCT_REQ_PENDING:
4517 	case EMLXS_FCT_REG_PENDING:
4518 	case EMLXS_FCT_DATA_PENDING:
4519 	case EMLXS_FCT_STATUS_PENDING:
4520 
4521 		/* Abort anything pending */
4522 		if (emlxs_fct_pkt_abort_txq(port, cmd_sbp)) {
4523 
4524 			if (fct_cmd->cmd_type == FCT_CMD_FCP_XCHG) {
4525 				TGTPORTSTAT.FctOutstandingIO--;
4526 			}
4527 
4528 			goto abort_done;
4529 		}
4530 
4531 		/* If we're not online, then all IO will be flushed anyway */
4532 		if (!(hba->flag & FC_ONLINE_MODE)) {
4533 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4534 			    "emlxs_fct_abort: Not online. fct_cmd=%p.",
4535 			    fct_cmd);
4536 
4537 			emlxs_fct_cmd_release(port, fct_cmd, 0);
4538 			/* mutex_exit(&cmd_sbp->fct_mtx); */
4539 
4540 			/* The cmd will be aborted on the */
4541 			/* next emlxs_fct_cmd_acquire */
4542 			/* because EMLXS_FCT_ABORT_INP is set. */
4543 			break;
4544 		}
4545 
4546 		/* Try to send abort request */
4547 		if (!(pkt = emlxs_pkt_alloc(port, 0, 0, 0, KM_NOSLEEP))) {
4548 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4549 			    "emlxs_fct_abort: Unable to allocate packet. "
4550 			    "fct_cmd=%p",
4551 			    fct_cmd);
4552 
4553 			emlxs_fct_cmd_release(port, fct_cmd, 0);
4554 			/* mutex_exit(&cmd_sbp->fct_mtx); */
4555 
4556 			/* The cmd will be aborted on the */
4557 			/* next emlxs_fct_cmd_acquire anyway */
4558 			/* because EMLXS_FCT_ABORT_INP is set. */
4559 			break;
4560 		}
4561 
4562 		sbp = emlxs_fct_pkt_init(port, fct_cmd, pkt);
4563 
4564 		pkt->pkt_tran_type = FC_PKT_OUTBOUND;
4565 		pkt->pkt_timeout =
4566 		    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
4567 		pkt->pkt_comp = emlxs_fct_abort_pkt_comp;
4568 
4569 		/* Build the fc header */
4570 		pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(fct_cmd->cmd_rportid);
4571 		pkt->pkt_cmd_fhdr.r_ctl = R_CTL_STATUS;
4572 		pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
4573 		pkt->pkt_cmd_fhdr.type = FC_TYPE_BASIC_LS;
4574 		pkt->pkt_cmd_fhdr.f_ctl =
4575 		    (F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ);
4576 		pkt->pkt_cmd_fhdr.seq_id = 0;
4577 		pkt->pkt_cmd_fhdr.df_ctl = 0;
4578 		pkt->pkt_cmd_fhdr.seq_cnt = 0;
4579 		pkt->pkt_cmd_fhdr.ox_id = fct_cmd->cmd_oxid;
4580 		pkt->pkt_cmd_fhdr.rx_id = fct_cmd->cmd_rxid;
4581 		pkt->pkt_cmd_fhdr.ro = 0;
4582 
4583 		cmd_sbp->fct_cmd = fct_cmd;
4584 		cmd_sbp->abort_attempts++;
4585 
4586 		/* Now disassociate the sbp / pkt from the fct_cmd */
4587 		sbp->fct_cmd = NULL;
4588 
4589 		if (hba->state >= FC_LINK_UP) {
4590 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4591 			    "emlxs_fct_abort: ABORT: %p xri x%x",
4592 			    fct_cmd, fct_cmd->cmd_rxid);
4593 
4594 			fct_state = EMLXS_FCT_ABORT_PENDING;
4595 
4596 		} else {
4597 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4598 			    "emlxs_fct_abort: CLOSE: %p xri x%x",
4599 			    fct_cmd, fct_cmd->cmd_rxid);
4600 
4601 			fct_state = EMLXS_FCT_CLOSE_PENDING;
4602 		}
4603 
4604 		emlxs_fct_cmd_release(port, fct_cmd, fct_state);
4605 		/* mutex_exit(&cmd_sbp->fct_mtx); */
4606 
4607 		if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
4608 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4609 			    "emlxs_fct_abort: Unable to send abort packet.");
4610 
4611 			emlxs_pkt_free(pkt);
4612 
4613 			/* The cmd will be aborted on the */
4614 			/* next emlxs_fct_cmd_acquire anyway */
4615 			/* because EMLXS_FCT_ABORT_INP is set. */
4616 		}
4617 
4618 		break;
4619 
4620 	default:
4621 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4622 		    "emlxs_fct_abort: Unexpected fct_state. "
4623 		    "fct_cmd=%p state=%x",
4624 		    fct_cmd, cmd_sbp->fct_state);
4625 
4626 		emlxs_fct_cmd_release(port, fct_cmd, 0);
4627 		/* mutex_exit(&cmd_sbp->fct_mtx); */
4628 
4629 		/* The cmd will be aborted on the */
4630 		/* next emlxs_fct_cmd_acquire anyway */
4631 		/* because EMLXS_FCT_ABORT_INP is set. */
4632 
4633 	}	/* switch */
4634 
4635 	return (FCT_SUCCESS);
4636 
4637 abort_done:
4638 
4639 	emlxs_fct_cmd_done(port, fct_cmd,
4640 	    EMLXS_FCT_ABORT_DONE);
4641 	/* mutex_exit(&cmd_sbp->fct_mtx); */
4642 
4643 	return (FCT_ABORT_SUCCESS);
4644 
4645 } /* emlxs_fct_abort() */
4646 
4647 
4648 extern void
4649 emlxs_fct_link_up(emlxs_port_t *port)
4650 {
4651 	emlxs_hba_t *hba = HBA;
4652 
4653 	mutex_enter(&EMLXS_PORT_LOCK);
4654 
4655 	if (port->fct_port &&
4656 	    (port->fct_flags & FCT_STATE_PORT_ONLINE) &&
4657 	    !(port->fct_flags & FCT_STATE_LINK_UP)) {
4658 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4659 		    "emlxs_fct_link_up event.");
4660 
4661 		port->fct_flags &= ~FCT_STATE_LINK_UP_ACKED;
4662 		port->fct_flags |= FCT_STATE_LINK_UP;
4663 		mutex_exit(&EMLXS_PORT_LOCK);
4664 
4665 #ifdef FCT_API_TRACE
4666 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4667 		    "fct_handle_event LINK_UP");
4668 #endif /* FCT_API_TRACE */
4669 		MODSYM(fct_handle_event) (port->fct_port, FCT_EVENT_LINK_UP,
4670 		    0, 0);
4671 	} else {
4672 		if (!hba->ini_mode &&
4673 		    !(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
4674 			mutex_exit(&EMLXS_PORT_LOCK);
4675 
4676 			/* Take link down and hold it down */
4677 			(void) emlxs_reset_link(hba, 0, 1);
4678 		} else {
4679 			mutex_exit(&EMLXS_PORT_LOCK);
4680 		}
4681 	}
4682 
4683 	return;
4684 
4685 } /* emlxs_fct_link_up() */
4686 
4687 
4688 extern void
4689 emlxs_fct_link_down(emlxs_port_t *port)
4690 {
4691 	emlxs_hba_t *hba = HBA;
4692 
4693 	mutex_enter(&EMLXS_PORT_LOCK);
4694 
4695 	if (port->fct_port &&
4696 	    (port->fct_flags & FCT_STATE_PORT_ONLINE) &&
4697 	    (port->fct_flags & FCT_STATE_LINK_UP)) {
4698 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4699 		    "emlxs_fct_link_down event.");
4700 
4701 		port->fct_flags &= ~FCT_STATE_LINK_UP_ACKED;
4702 		port->fct_flags &= ~FCT_STATE_LINK_UP;
4703 		mutex_exit(&EMLXS_PORT_LOCK);
4704 
4705 #ifdef FCT_API_TRACE
4706 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4707 		    "fct_handle_event LINK_DOWN");
4708 #endif /* FCT_API_TRACE */
4709 
4710 		MODSYM(fct_handle_event) (port->fct_port, FCT_EVENT_LINK_DOWN,
4711 		    0, 0);
4712 	} else {
4713 		mutex_exit(&EMLXS_PORT_LOCK);
4714 	}
4715 
4716 	return;
4717 
4718 } /* emlxs_fct_link_down() */
4719 
4720 
4721 /* DMA FUNCTIONS */
4722 
4723 fct_status_t
4724 emlxs_fct_dmem_init(emlxs_port_t *port)
4725 {
4726 	emlxs_hba_t *hba = HBA;
4727 	emlxs_fct_dmem_bucket_t *p;
4728 	emlxs_fct_dmem_bctl_t *bctl;
4729 	emlxs_fct_dmem_bctl_t *bc;
4730 	emlxs_fct_dmem_bctl_t *prev;
4731 	int32_t j;
4732 	int32_t i;
4733 	uint32_t total_mem;
4734 	uint8_t *addr;
4735 	uint8_t *host_addr;
4736 	uint64_t dev_addr;
4737 	ddi_dma_cookie_t cookie;
4738 	uint32_t ncookie;
4739 	uint32_t bsize;
4740 	size_t len;
4741 	char buf[64];
4742 	ddi_device_acc_attr_t acc;
4743 
4744 	bzero(&acc, sizeof (acc));
4745 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
4746 	acc.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
4747 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
4748 
4749 	p = port->dmem_bucket;
4750 	for (i = 0; i < FCT_MAX_BUCKETS; i++, p++) {
4751 		if (!p->dmem_nbufs) {
4752 			continue;
4753 		}
4754 
4755 		bctl = (emlxs_fct_dmem_bctl_t *)kmem_zalloc(p->dmem_nbufs *
4756 		    sizeof (emlxs_fct_dmem_bctl_t), KM_NOSLEEP);
4757 
4758 		if (bctl == NULL) {
4759 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4760 			    "emlxs_fct_dmem_init: Unable to allocate bctl.");
4761 			goto alloc_bctl_failed;
4762 		}
4763 
4764 		p->dmem_bctls_mem = bctl;
4765 
4766 		if (ddi_dma_alloc_handle(hba->dip, &hba->dma_attr_1sg,
4767 		    DDI_DMA_SLEEP, 0, &p->dmem_dma_handle) != DDI_SUCCESS) {
4768 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4769 			    "emlxs_fct_dmem_init: Unable to allocate handle.");
4770 			goto alloc_handle_failed;
4771 		}
4772 
4773 		total_mem = p->dmem_buf_size * p->dmem_nbufs;
4774 
4775 		if (ddi_dma_mem_alloc(p->dmem_dma_handle, total_mem, &acc,
4776 		    DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
4777 		    (caddr_t *)&addr, &len,
4778 		    &p->dmem_acc_handle) != DDI_SUCCESS) {
4779 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4780 			    "emlxs_fct_dmem_init: Unable to allocate memory.");
4781 			goto mem_alloc_failed;
4782 		}
4783 
4784 		if (ddi_dma_addr_bind_handle(p->dmem_dma_handle, NULL,
4785 		    (caddr_t)addr, total_mem,
4786 		    DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
4787 		    &cookie, &ncookie) != DDI_SUCCESS) {
4788 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4789 			    "emlxs_fct_dmem_init: Unable to bind handle.");
4790 			goto addr_bind_handle_failed;
4791 		}
4792 
4793 		if (ncookie != 1) {
4794 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4795 			    "emlxs_fct_dmem_init: DMEM init failed.");
4796 			goto dmem_init_failed;
4797 		}
4798 		(void) sprintf(buf, "%s%d_bucket%d mutex", DRIVER_NAME,
4799 		    hba->ddiinst, i);
4800 		mutex_init(&p->dmem_lock, buf, MUTEX_DRIVER,
4801 		    (void *)hba->intr_arg);
4802 
4803 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4804 		    "bufsize=%d cnt=%d", p->dmem_buf_size, p->dmem_nbufs);
4805 
4806 		host_addr = addr;
4807 		dev_addr = (uint64_t)cookie.dmac_laddress;
4808 
4809 		p->dmem_host_addr = addr;
4810 		p->dmem_dev_addr = dev_addr;
4811 		p->dmem_bctl_free_list = bctl;
4812 		p->dmem_nbufs_free = p->dmem_nbufs;
4813 		bsize = p->dmem_buf_size;
4814 
4815 		for (j = 0; j < p->dmem_nbufs; j++) {
4816 			stmf_data_buf_t *db;
4817 
4818 			db = MODSYM(stmf_alloc) (STMF_STRUCT_DATA_BUF, 0, 0);
4819 #ifdef FCT_API_TRACE
4820 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4821 			    "stmf_alloc data_buf %p", db);
4822 #endif /* FCT_API_TRACE */
4823 			if (db == NULL) {
4824 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4825 				    "emlxs_fct_dmem_init: alloc failed.");
4826 				goto dmem_init_failed;
4827 			}
4828 			db->db_port_private = bctl;
4829 			db->db_sglist[0].seg_addr = host_addr;
4830 			db->db_sglist[0].seg_length = bsize;
4831 			db->db_buf_size = bsize;
4832 			db->db_sglist_length = 1;
4833 
4834 			bctl->bctl_bucket = p;
4835 			bctl->bctl_buf = db;
4836 			bctl->bctl_dev_addr = dev_addr;
4837 
4838 			host_addr += bsize;
4839 			dev_addr += bsize;
4840 
4841 			prev = bctl;
4842 			bctl++;
4843 			prev->bctl_next = bctl;
4844 		}
4845 
4846 		prev->bctl_next = NULL;
4847 	}
4848 
4849 	return (FCT_SUCCESS);
4850 
4851 dmem_failure_loop:
4852 	mutex_destroy(&p->dmem_lock);
4853 	bc = bctl;
4854 	while (bc) {
4855 #ifdef FCT_API_TRACE
4856 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4857 		    "stmf_free:3 %p", bctl->bctl_buf);
4858 #endif /* FCT_API_TRACE */
4859 		MODSYM(stmf_free) (bc->bctl_buf);
4860 		bc = bc->bctl_next;
4861 	}
4862 
4863 dmem_init_failed:
4864 	(void) ddi_dma_unbind_handle(p->dmem_dma_handle);
4865 
4866 addr_bind_handle_failed:
4867 	(void) ddi_dma_mem_free(&p->dmem_acc_handle);
4868 
4869 mem_alloc_failed:
4870 	(void) ddi_dma_free_handle(&p->dmem_dma_handle);
4871 
4872 alloc_handle_failed:
4873 	kmem_free(p->dmem_bctls_mem,
4874 	    p->dmem_nbufs * sizeof (emlxs_fct_dmem_bctl_t));
4875 
4876 alloc_bctl_failed:
4877 	if (--i >= 0) {
4878 		p = &port->dmem_bucket[i];
4879 		bctl = p->dmem_bctl_free_list;
4880 		goto dmem_failure_loop;
4881 	}
4882 
4883 	return (FCT_FAILURE);
4884 
4885 } /* emlxs_fct_dmem_init() */
4886 
4887 
4888 void
4889 emlxs_fct_dmem_fini(emlxs_port_t *port)
4890 {
4891 	emlxs_fct_dmem_bucket_t *p;
4892 	emlxs_fct_dmem_bctl_t *bctl;
4893 	uint32_t i;
4894 
4895 	p = port->dmem_bucket;
4896 	for (i = 0; i < FCT_MAX_BUCKETS; i++, p++) {
4897 		if (!p->dmem_nbufs) {
4898 			continue;
4899 		}
4900 
4901 		bctl = p->dmem_bctl_free_list;
4902 
4903 		while (bctl) {
4904 #ifdef FCT_API_TRACE
4905 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4906 			    "stmf_free:4 %p", bctl->bctl_buf);
4907 #endif /* FCT_API_TRACE */
4908 			MODSYM(stmf_free) (bctl->bctl_buf);
4909 			bctl = bctl->bctl_next;
4910 		}
4911 
4912 		bctl = p->dmem_bctl_free_list;
4913 
4914 		(void) ddi_dma_unbind_handle(p->dmem_dma_handle);
4915 		(void) ddi_dma_mem_free(&p->dmem_acc_handle);
4916 		(void) ddi_dma_free_handle(&p->dmem_dma_handle);
4917 
4918 		kmem_free(p->dmem_bctls_mem,
4919 		    (p->dmem_nbufs * sizeof (emlxs_fct_dmem_bctl_t)));
4920 		mutex_destroy(&p->dmem_lock);
4921 	}
4922 
4923 	bzero((uint8_t *)port->dmem_bucket, sizeof (port->dmem_bucket));
4924 
4925 	return;
4926 
4927 } /* emlxs_fct_dmem_fini() */
4928 
4929 
4930 /* COMSTAR ENTER POINT */
4931 /* ARGSUSED */
4932 static stmf_data_buf_t *
4933 emlxs_fct_dbuf_alloc(fct_local_port_t *fct_port, uint32_t size,
4934     uint32_t *pminsize, uint32_t flags)
4935 {
4936 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
4937 	emlxs_fct_dmem_bucket_t *p;
4938 	emlxs_fct_dmem_bctl_t *bctl;
4939 	uint32_t i;
4940 
4941 	if (size > FCT_DMEM_MAX_BUF_SIZE) {
4942 		size = FCT_DMEM_MAX_BUF_SIZE;
4943 	}
4944 
4945 	p = port->dmem_bucket;
4946 	for (i = 0; i < FCT_MAX_BUCKETS; i++, p++) {
4947 		if (!p->dmem_nbufs) {
4948 			continue;
4949 		}
4950 
4951 		if (p->dmem_buf_size >= size) {
4952 			mutex_enter(&p->dmem_lock);
4953 			if (p->dmem_nbufs_free) {
4954 				if (p->dmem_buf_size < *pminsize) {
4955 					*pminsize = p->dmem_buf_size;
4956 					TGTPORTSTAT.FctNoBuffer++;
4957 
4958 					EMLXS_MSGF(EMLXS_CONTEXT,
4959 					    &emlxs_fct_api_msg,
4960 					    "emlxs_fct_dbuf_alloc: Failed(1).");
4961 					mutex_exit(&p->dmem_lock);
4962 					return (NULL);
4963 				}
4964 
4965 				bctl = p->dmem_bctl_free_list;
4966 				if (bctl == NULL) {
4967 					mutex_exit(&p->dmem_lock);
4968 					continue;
4969 				}
4970 
4971 				p->dmem_bctl_free_list = bctl->bctl_next;
4972 				p->dmem_nbufs_free--;
4973 				bctl->bctl_buf->db_data_size = size;
4974 				mutex_exit(&p->dmem_lock);
4975 
4976 #ifdef FCT_API_TRACE
4977 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4978 				    "emlx_fct_buf_alloc: bctl_buf %p: size %d",
4979 				    bctl->bctl_buf, size);
4980 #endif /* FCT_API_TRACE */
4981 
4982 				return (bctl->bctl_buf);
4983 			}
4984 			mutex_exit(&p->dmem_lock);
4985 
4986 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4987 			    "emlx_fct_buf_alloc size %d Nothing free bck %d",
4988 			    size, i);
4989 		}
4990 	}
4991 
4992 	*pminsize = 0;
4993 	TGTPORTSTAT.FctNoBuffer++;
4994 
4995 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4996 	    "emlxs_fct_dbuf_alloc: Failed(2).");
4997 
4998 	return (NULL);
4999 
5000 } /* emlxs_fct_dbuf_alloc() */
5001 
5002 
5003 /* COMSTAR ENTER POINT */
5004 /*ARGSUSED*/
5005 static void
5006 emlxs_fct_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf)
5007 {
5008 	emlxs_fct_dmem_bctl_t *bctl =
5009 	    (emlxs_fct_dmem_bctl_t *)dbuf->db_port_private;
5010 	emlxs_fct_dmem_bucket_t *p = bctl->bctl_bucket;
5011 
5012 #ifdef FCT_API_TRACE_1
5013 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5014 	    "emlx_fct_buf_free %p", dbuf);
5015 #endif /* FCT_API_TRACE */
5016 
5017 	mutex_enter(&p->dmem_lock);
5018 	bctl->bctl_next = p->dmem_bctl_free_list;
5019 	p->dmem_bctl_free_list = bctl;
5020 	p->dmem_nbufs_free++;
5021 	mutex_exit(&p->dmem_lock);
5022 
5023 } /* emlxs_fct_dbuf_free() */
5024 
5025 
5026 static int
5027 emlxs_fct_dbuf_dma_sync(emlxs_hba_t *hba, stmf_data_buf_t *dbuf,
5028     uint_t sync_type)
5029 {
5030 	emlxs_fct_dmem_bctl_t *bctl =
5031 	    (emlxs_fct_dmem_bctl_t *)dbuf->db_port_private;
5032 	emlxs_fct_dmem_bucket_t *p = bctl->bctl_bucket;
5033 	emlxs_port_t *port = &PPORT;
5034 	int retval = 0;
5035 
5036 	(void) ddi_dma_sync(p->dmem_dma_handle,
5037 	    (unsigned long)(bctl->bctl_dev_addr - p->dmem_dev_addr),
5038 	    dbuf->db_data_size, sync_type);
5039 
5040 #ifdef FMA_SUPPORT
5041 	if (emlxs_fm_check_dma_handle(hba, p->dmem_dma_handle)
5042 	    != DDI_FM_OK) {
5043 		EMLXS_MSGF(EMLXS_CONTEXT,
5044 		    &emlxs_invalid_dma_handle_msg,
5045 		    "emlxs_fct_dbuf_dma_sync: hdl=%p",
5046 		    p->dmem_dma_handle);
5047 		retval = 1;
5048 	}
5049 #endif  /* FMA_SUPPORT */
5050 
5051 	return (retval);
5052 
5053 } /* emlxs_fct_dbuf_dma_sync() */
5054 
5055 
5056 #endif /* SFCT_SUPPORT */
5057