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
9  * http://www.opensource.org/licenses/cddl1.txt.
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 (c) 2004-2012 Emulex. All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2020 RackTop Systems, Inc.
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 void emlxs_fct_memseg_init(emlxs_hba_t *hba);
37 
38 static fct_status_t emlxs_fct_cmd_acquire(emlxs_port_t *port,
39 	fct_cmd_t *fct_cmd, uint16_t fct_state);
40 static fct_status_t emlxs_fct_cmd_accept(emlxs_port_t *port,
41 	fct_cmd_t *fct_cmd, uint16_t fct_state);
42 static void emlxs_fct_cmd_release(emlxs_port_t *port, fct_cmd_t *fct_cmd,
43 	uint16_t fct_state);
44 
45 static emlxs_buf_t *emlxs_fct_cmd_init(emlxs_port_t *port,
46     fct_cmd_t *fct_cmd, uint16_t fct_state);
47 static void emlxs_fct_cmd_done(emlxs_port_t *port, fct_cmd_t *fct_cmd,
48 	uint16_t fct_state);
49 static void emlxs_fct_cmd_post(emlxs_port_t *port, fct_cmd_t *fct_cmd,
50 	uint16_t fct_state);
51 
52 static fct_status_t emlxs_fct_flogi_xchg(struct fct_local_port *fct_port,
53     struct fct_flogi_xchg *fx);
54 static fct_status_t emlxs_fct_get_link_info(fct_local_port_t *fct_port,
55     fct_link_info_t *link);
56 static fct_status_t emlxs_fct_deregister_remote_port(fct_local_port_t *fct_port,
57     fct_remote_port_t *port_handle);
58 static fct_status_t emlxs_fct_send_cmd(fct_cmd_t *fct_cmd);
59 static fct_status_t emlxs_fct_send_fcp_data(fct_cmd_t *fct_cmd,
60     stmf_data_buf_t *dbuf, uint32_t ioflags);
61 static fct_status_t emlxs_fct_send_cmd_rsp(fct_cmd_t *fct_cmd, uint32_t flags);
62 static fct_status_t emlxs_fct_abort(fct_local_port_t *fct_port,
63     fct_cmd_t *cmd, uint32_t flags);
64 static void emlxs_fct_ctl(fct_local_port_t *fct_port, int cmd, void *arg);
65 static fct_status_t emlxs_fct_register_remote_port(fct_local_port_t *fct_port,
66     fct_remote_port_t *port_handle, fct_cmd_t *plogi);
67 static fct_status_t emlxs_fct_send_els_cmd(fct_cmd_t *fct_cmd);
68 static fct_status_t emlxs_fct_send_ct_cmd(fct_cmd_t *fct_cmd);
69 static fct_status_t emlxs_fct_send_fcp_status(fct_cmd_t *fct_cmd);
70 static fct_status_t emlxs_fct_send_els_rsp(fct_cmd_t *fct_cmd);
71 static void emlxs_fct_pkt_comp(fc_packet_t *pkt);
72 static void emlxs_fct_populate_hba_details(fct_local_port_t *fct_port,
73     fct_port_attrs_t *port_attrs);
74 static fct_status_t emlxs_fct_port_info(uint32_t cmd,
75     fct_local_port_t *fct_port, void *arg, uint8_t *buffer, uint32_t *size);
76 
77 static fct_status_t emlxs_fct_dmem_init(emlxs_port_t *port);
78 static void emlxs_fct_dmem_fini(emlxs_port_t *port);
79 
80 static stmf_data_buf_t *emlxs_fct_dbuf_alloc(fct_local_port_t *fct_port,
81     uint32_t size, uint32_t *pminsize, uint32_t flags);
82 static void emlxs_fct_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf);
83 
84 static int emlxs_fct_dbuf_dma_sync(emlxs_hba_t *hba, stmf_data_buf_t *dbuf,
85     uint_t sync_type);
86 static emlxs_buf_t *emlxs_fct_pkt_init(emlxs_port_t *port,
87     fct_cmd_t *fct_cmd, fc_packet_t *pkt);
88 
89 static void emlxs_fct_unsol_flush_thread(emlxs_hba_t *hba, void *arg1,
90     void *arg2);
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 /* ARGSUSED */
743 static void
744 emlxs_fct_unsol_flush_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
745 {
746 	emlxs_port_t *port = (emlxs_port_t *)arg1;
747 
748 	emlxs_fct_unsol_flush(port);
749 	return;
750 
751 } /* emlxs_fct_unsol_flush_thread() */
752 
753 
754 /* This is called at port online and offline */
755 static void
756 emlxs_fct_unsol_flush(emlxs_port_t *port)
757 {
758 	emlxs_hba_t *hba = HBA;
759 	emlxs_buf_t *cmd_sbp;
760 	emlxs_buf_t *next;
761 	fct_cmd_t *fct_cmd;
762 	fct_status_t rval;
763 	uint32_t cmd_code;
764 
765 	if (!port->fct_port) {
766 		return;
767 	}
768 
769 	/* First handle any pending FLOGI */
770 	emlxs_fct_handle_unsol_flogi(port, NULL, 0);
771 
772 	if ((port->fct_flags & FCT_STATE_LINK_UP_ACKED) &&
773 	    !(port->fct_flags & FCT_STATE_FLOGI_CMPL)) {
774 		return;
775 	}
776 
777 	/* Wait queue */
778 	mutex_enter(&EMLXS_PORT_LOCK);
779 	cmd_sbp = port->fct_wait_head;
780 	port->fct_wait_head = NULL;
781 	port->fct_wait_tail = NULL;
782 	mutex_exit(&EMLXS_PORT_LOCK);
783 
784 	/*
785 	 * Next process any outstanding ELS commands. It doesn't
786 	 * matter if the Link is up or not, always post them to FCT.
787 	 */
788 	while (cmd_sbp) {
789 		next = cmd_sbp->next;
790 		fct_cmd = cmd_sbp->fct_cmd;
791 
792 		cmd_code = (fct_cmd->cmd_oxid << ELS_CMD_SHIFT);
793 
794 		/* Reacquire ownership of the fct_cmd */
795 		rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
796 		if (rval) {
797 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
798 			    "fct_unsol_flush: %s: sid=%x xid=%x "
799 			    "Unable to reacquire fct_cmd.",
800 			    emlxs_elscmd_xlate(cmd_code),
801 			    fct_cmd->cmd_rxid, fct_cmd->cmd_rportid);
802 
803 			cmd_sbp = next;
804 			continue;
805 		}
806 		/* mutex_enter(&cmd_sbp->fct_mtx); */
807 
808 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
809 		    "Posting %s: sid=%x xid=%x %p",
810 		    emlxs_elscmd_xlate(cmd_code),
811 		    fct_cmd->cmd_rportid, fct_cmd->cmd_rxid,
812 		    fct_cmd);
813 
814 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
815 		/* mutex_exit(&cmd_sbp->fct_mtx); */
816 
817 #ifdef FCT_API_TRACE
818 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
819 		    "fct_post_rcvd_cmd:2 %p:%p portid x%x", fct_cmd, cmd_sbp,
820 		    fct_cmd->cmd_lportid);
821 #endif /* FCT_API_TRACE */
822 
823 		MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
824 
825 		cmd_sbp = next;
826 
827 	}	/* while () */
828 
829 	return;
830 
831 } /* emlxs_fct_unsol_flush() */
832 
833 
834 int
835 emlxs_is_digit(uint8_t chr)
836 {
837 	if ((chr >= '0') && (chr <= '9')) {
838 		return (1);
839 	}
840 
841 	return (0);
842 
843 } /* emlxs_is_digit */
844 
845 
846 /*
847  *   Convert an ASCII decimal numeric string to integer.
848  *   Negation character '-' is not handled.
849  */
850 static uint32_t
851 emlxs_str_atoi(uint8_t *string)
852 {
853 	uint32_t num = 0;
854 	int i = 0;
855 
856 	while (string[i]) {
857 		if (!emlxs_is_digit(string[i])) {
858 			return (num);
859 		}
860 
861 		num = num * 10 + (string[i++] - '0');
862 	}
863 
864 	return (num);
865 
866 } /* emlxs_str_atoi() */
867 
868 
869 extern uint32_t
870 emlxs_fct_init(emlxs_hba_t *hba)
871 {
872 	emlxs_port_t *port = &PPORT;
873 
874 	/* Check if COMSTAR is present */
875 	if (((void *)MODSYM(stmf_alloc) == NULL) ||
876 	    ((void *)MODSYM(fct_alloc) == NULL)) {
877 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_attach_debug_msg,
878 		    "Comstar not present.");
879 		return (1);
880 	}
881 
882 	return (0);
883 
884 } /* emlxs_fct_init() */
885 
886 
887 extern void
888 emlxs_fct_attach(emlxs_hba_t *hba)
889 {
890 	emlxs_port_t *port = &PPORT;
891 	uint32_t vpi;
892 
893 	if (!(port->flag & EMLXS_TGT_ENABLED)) {
894 		return;
895 	}
896 
897 	/* Bind the physical port */
898 	emlxs_fct_bind_port(port);
899 
900 	/* Bind virtual ports */
901 	if (hba->flag & FC_NPIV_ENABLED) {
902 		for (vpi = 1; vpi <= hba->vpi_high; vpi++) {
903 			port = &VPORT(vpi);
904 
905 			if (!(port->flag & EMLXS_PORT_ENABLED)) {
906 				continue;
907 			}
908 
909 			emlxs_fct_bind_port(port);
910 		}
911 	}
912 
913 	return;
914 
915 } /* emlxs_fct_attach() */
916 
917 
918 extern void
919 emlxs_fct_detach(emlxs_hba_t *hba)
920 {
921 	uint32_t i;
922 	emlxs_port_t *vport;
923 
924 	for (i = 0; i < MAX_VPORTS; i++) {
925 		vport = &VPORT(i);
926 
927 		if (!(vport->flag & EMLXS_PORT_ENABLED)) {
928 			continue;
929 		}
930 
931 		emlxs_fct_unbind_port(vport);
932 	}
933 
934 #ifdef FCT_IO_TRACE
935 {
936 	emlxs_port_t *port = &PPORT;
937 
938 	mutex_destroy(&port->iotrace_mtx);
939 	if (port->iotrace) {
940 		kmem_free(port->iotrace,
941 		    (port->iotrace_cnt * sizeof (emlxs_iotrace_t)));
942 	}
943 	port->iotrace = NULL;
944 }
945 #endif /* FCT_IO_TRACE */
946 
947 	return;
948 
949 } /* emlxs_fct_detach() */
950 
951 
952 extern void
953 emlxs_fct_unbind_port(emlxs_port_t *port)
954 {
955 	emlxs_hba_t *hba = HBA;
956 	char node_name[32];
957 
958 	mutex_enter(&EMLXS_PORT_LOCK);
959 
960 	if (!(port->flag & EMLXS_TGT_BOUND)) {
961 		mutex_exit(&EMLXS_PORT_LOCK);
962 		return;
963 	}
964 
965 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
966 	    "fct_unbind_port: port=%d", port->vpi);
967 
968 	/* Destroy & flush all port nodes, if they exist */
969 	if (port->node_count) {
970 		(void) EMLXS_SLI_UNREG_NODE(port, NULL, NULL, NULL, NULL);
971 	}
972 
973 	port->flag &= ~EMLXS_TGT_BOUND;
974 	port->flag &= ~EMLXS_TGT_ENABLED;
975 	hba->num_of_ports--;
976 	mutex_exit(&EMLXS_PORT_LOCK);
977 
978 	if (port->fct_port) {
979 		emlxs_fct_link_down(port);
980 		emlxs_fct_unsol_flush(port);
981 
982 #ifdef FCT_API_TRACE
983 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
984 		    "fct_deregister_local_port %p", port->fct_port);
985 #endif /* FCT_API_TRACE */
986 		MODSYM(fct_deregister_local_port) (port->fct_port);
987 
988 		if (port->fct_port->port_fds) {
989 #ifdef FCT_API_TRACE
990 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
991 			    "fct_free:3 %p", port->fct_port->port_fds);
992 #endif /* FCT_API_TRACE */
993 			MODSYM(fct_free) (port->fct_port->port_fds);
994 			port->fct_port->port_fds = NULL;
995 		}
996 #ifdef FCT_API_TRACE
997 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
998 		    "fct_free:4 %p", port->fct_port);
999 #endif /* FCT_API_TRACE */
1000 		MODSYM(fct_free) (port->fct_port);
1001 		port->fct_port = NULL;
1002 		port->fct_flags = 0;
1003 	}
1004 
1005 	if (port->port_provider) {
1006 #ifdef FCT_API_TRACE
1007 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1008 		    "stmf_deregister_port_provider:1 %p",
1009 		    port->port_provider);
1010 #endif /* FCT_API_TRACE */
1011 		MODSYM(stmf_deregister_port_provider) (port->port_provider);
1012 
1013 #ifdef FCT_API_TRACE
1014 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1015 		    "stmf_free:1 %p", port->port_provider);
1016 #endif /* FCT_API_TRACE */
1017 		MODSYM(stmf_free) (port->port_provider);
1018 		port->port_provider = NULL;
1019 	}
1020 
1021 	if (port->fct_memseg) {
1022 		emlxs_fct_dmem_fini(port);
1023 	}
1024 
1025 	(void) snprintf(node_name, sizeof (node_name), "%d,%d:SFCT",
1026 	    hba->ddiinst, port->vpi);
1027 	(void) ddi_remove_minor_node(hba->dip, node_name);
1028 
1029 	return;
1030 
1031 } /* emlxs_fct_unbind_port() */
1032 
1033 
1034 extern void
1035 emlxs_fct_bind_port(emlxs_port_t *port)
1036 {
1037 	emlxs_hba_t *hba = HBA;
1038 	fct_local_port_t *fct_port;
1039 	uint32_t flag = 0;
1040 	emlxs_config_t *cfg = &CFG;
1041 	fct_dbuf_store_t *fds;
1042 	char node_name[32];
1043 	uint8_t *bptr;
1044 
1045 	if (!(port->flag & EMLXS_TGT_ENABLED)) {
1046 		return;
1047 	}
1048 
1049 	mutex_enter(&EMLXS_PORT_LOCK);
1050 
1051 	if (port->flag & EMLXS_TGT_BOUND) {
1052 		mutex_exit(&EMLXS_PORT_LOCK);
1053 		return;
1054 	}
1055 
1056 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1057 	    "fct_bind_port: port=%d", port->vpi);
1058 
1059 	/* Perform generic port initialization */
1060 	emlxs_port_init(port);
1061 
1062 	if (port->vpi == 0) {
1063 		(void) snprintf(port->cfd_name, sizeof (port->cfd_name),
1064 		    "%s%d", DRIVER_NAME, hba->ddiinst);
1065 	} else {
1066 		(void) snprintf(port->cfd_name, sizeof (port->cfd_name),
1067 		    "%s%d.%d", DRIVER_NAME, hba->ddiinst, port->vpi);
1068 	}
1069 
1070 	if (emlxs_fct_dmem_init(port) != FCT_SUCCESS) {
1071 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1072 		    "fct_bind_port: Unable to allocate fct memory.");
1073 		goto failed;
1074 	}
1075 	flag |= 0x00000001;
1076 
1077 	port->port_provider =
1078 	    (stmf_port_provider_t *)
1079 	    MODSYM(stmf_alloc) (STMF_STRUCT_PORT_PROVIDER, 0, 0);
1080 #ifdef FCT_API_TRACE
1081 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1082 	    "stmf_alloc port_provider %p", port->port_provider);
1083 #endif /* FCT_API_TRACE */
1084 
1085 	if (port->port_provider == NULL) {
1086 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1087 		    "fct_bind_port: Unable to allocate port provider.");
1088 		goto failed;
1089 	}
1090 	flag |= 0x00000002;
1091 
1092 	port->port_provider->pp_portif_rev = PORTIF_REV_1;
1093 	port->port_provider->pp_name = port->cfd_name;
1094 	port->port_provider->pp_provider_private = port;
1095 
1096 #ifdef FCT_API_TRACE
1097 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1098 	    "stmf_register_port_provider %p", port->port_provider);
1099 #endif /* FCT_API_TRACE */
1100 	/* register port provider with framework */
1101 	if (MODSYM(stmf_register_port_provider) (port->port_provider) !=
1102 	    STMF_SUCCESS) {
1103 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1104 		    "fct_bind_port: Unable to register port provider.");
1105 		goto failed;
1106 	}
1107 	flag |= 0x00000004;
1108 
1109 	port->fct_port =
1110 	    (fct_local_port_t *)MODSYM(fct_alloc) (FCT_STRUCT_LOCAL_PORT, 0,
1111 	    0);
1112 #ifdef FCT_API_TRACE
1113 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1114 	    "fct_alloc fct_port %p", port->fct_port);
1115 #endif /* FCT_API_TRACE */
1116 
1117 	if (port->fct_port == NULL) {
1118 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1119 		    "fct_bind_port: Unable to allocate fct port.");
1120 		goto failed;
1121 	}
1122 	flag |= 0x00000008;
1123 
1124 	port->fct_port->port_fds =
1125 	    (fct_dbuf_store_t *)MODSYM(fct_alloc) (FCT_STRUCT_DBUF_STORE, 0,
1126 	    0);
1127 #ifdef FCT_API_TRACE
1128 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1129 	    "fct_alloc port_fds %p", port->fct_port->port_fds);
1130 #endif /* FCT_API_TRACE */
1131 
1132 	if (port->fct_port->port_fds == NULL) {
1133 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1134 		    "fct_bind_port: Unable to allocate dbuf store.");
1135 		goto failed;
1136 	}
1137 	flag |= 0x00000010;
1138 
1139 	(void) snprintf(node_name, sizeof (node_name), "%d,%d:SFCT",
1140 	    hba->ddiinst, port->vpi);
1141 	if (ddi_create_minor_node(hba->dip, node_name, S_IFCHR, hba->ddiinst,
1142 	    NULL, 0) == DDI_FAILURE) {
1143 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1144 		    "Unable to create SFCT device node.");
1145 		goto failed;
1146 	}
1147 	flag |= 0x00000020;
1148 
1149 	/* Intialize */
1150 	fct_port = port->fct_port;
1151 	fct_port->port_fca_version = FCT_FCA_MODREV_1;
1152 	fct_port->port_fca_private = port;
1153 	fct_port->port_fca_abort_timeout = 30 * 1000;	/* 30 seconds */
1154 
1155 	bcopy((uint8_t *)&port->wwpn, (uint8_t *)fct_port->port_pwwn, 8);
1156 	bcopy((uint8_t *)&port->wwnn, (uint8_t *)fct_port->port_nwwn, 8);
1157 
1158 	bptr = (uint8_t *)&port->wwnn;
1159 	(void) snprintf(fct_port->port_nwwn_str, FC_WWN_BUFLEN,
1160 	    "%02x%02x%02x%02x%02x%02x%02x%02x",
1161 	    bptr[0], bptr[1], bptr[2], bptr[3],
1162 	    bptr[4], bptr[5], bptr[6], bptr[7]);
1163 
1164 	bptr = (uint8_t *)&port->wwpn;
1165 	(void) snprintf(fct_port->port_pwwn_str, FC_WWN_BUFLEN,
1166 	    "%02x%02x%02x%02x%02x%02x%02x%02x",
1167 	    bptr[0], bptr[1], bptr[2], bptr[3],
1168 	    bptr[4], bptr[5], bptr[6], bptr[7]);
1169 
1170 	fct_port->port_sym_node_name = port->snn;
1171 	fct_port->port_sym_port_name = port->spn;
1172 	fct_port->port_hard_address = cfg[CFG_ASSIGN_ALPA].current;
1173 	fct_port->port_default_alias = port->cfd_name;
1174 	fct_port->port_pp = port->port_provider;
1175 	fct_port->port_max_logins = hba->max_nodes + EMLXS_FCT_NUM_ELS_ONLY;
1176 
1177 	if (cfg[CFG_FCT_QDEPTH].current &&
1178 	    (cfg[CFG_FCT_QDEPTH].current < hba->io_throttle)) {
1179 		fct_port->port_max_xchges = cfg[CFG_FCT_QDEPTH].current;
1180 	} else {
1181 		fct_port->port_max_xchges = hba->io_throttle;
1182 	}
1183 
1184 	fct_port->port_fca_fcp_cmd_size = sizeof (emlxs_buf_t);
1185 	fct_port->port_fca_rp_private_size = sizeof (uintptr_t);
1186 	fct_port->port_fca_sol_els_private_size = sizeof (emlxs_buf_t);
1187 	fct_port->port_fca_sol_ct_private_size = sizeof (emlxs_buf_t);
1188 	fct_port->port_get_link_info = emlxs_fct_get_link_info;
1189 	fct_port->port_register_remote_port = emlxs_fct_register_remote_port;
1190 	fct_port->port_deregister_remote_port =
1191 	    emlxs_fct_deregister_remote_port;
1192 	fct_port->port_send_cmd = emlxs_fct_send_cmd;
1193 	fct_port->port_xfer_scsi_data = emlxs_fct_send_fcp_data;
1194 	fct_port->port_send_cmd_response = emlxs_fct_send_cmd_rsp;
1195 	fct_port->port_abort_cmd = emlxs_fct_abort;
1196 	fct_port->port_ctl = emlxs_fct_ctl;
1197 	fct_port->port_flogi_xchg = emlxs_fct_flogi_xchg;
1198 	fct_port->port_populate_hba_details = emlxs_fct_populate_hba_details;
1199 	fct_port->port_info = emlxs_fct_port_info;
1200 
1201 	fds = port->fct_port->port_fds;
1202 	fds->fds_fca_private = port;
1203 	fds->fds_alloc_data_buf = emlxs_fct_dbuf_alloc;
1204 	fds->fds_free_data_buf = emlxs_fct_dbuf_free;
1205 
1206 	/* Scatter gather list support */
1207 /*	fds->fds_setup_dbuf = ; */
1208 /*	fds->fds_teardown_dbuf = ; */
1209 /*	fds->fds_max_sgl_xfer_len = ; */
1210 /*	fds->fds_copy_threshold = ; */
1211 
1212 #ifdef FCT_API_TRACE
1213 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1214 	    "fct_register_local_port %p", fct_port);
1215 #endif /* FCT_API_TRACE */
1216 	/* register this local port with the fct module */
1217 	if (MODSYM(fct_register_local_port) (fct_port) != FCT_SUCCESS) {
1218 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1219 		    "fct_bind_port: Unable to register fct port.");
1220 		goto failed;
1221 	}
1222 
1223 	/* Set the bound flag */
1224 	port->flag |= EMLXS_TGT_BOUND;
1225 	hba->num_of_ports++;
1226 
1227 	mutex_exit(&EMLXS_PORT_LOCK);
1228 
1229 	return;
1230 
1231 failed:
1232 
1233 	if (flag & 0x20) {
1234 		(void) ddi_remove_minor_node(hba->dip, node_name);
1235 	}
1236 
1237 	if (flag & 0x10) {
1238 #ifdef FCT_API_TRACE
1239 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1240 		    "fct_free:5 %p", port->fct_port->port_fds);
1241 #endif /* FCT_API_TRACE */
1242 		MODSYM(fct_free) (port->fct_port->port_fds);
1243 		port->fct_port->port_fds = NULL;
1244 	}
1245 
1246 	if (flag & 0x8) {
1247 #ifdef FCT_API_TRACE
1248 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1249 		    "fct_free:6 %p", port->fct_port);
1250 #endif /* FCT_API_TRACE */
1251 		MODSYM(fct_free) (port->fct_port);
1252 		port->fct_port = NULL;
1253 		port->fct_flags = 0;
1254 	}
1255 
1256 	if (flag & 0x4) {
1257 #ifdef FCT_API_TRACE
1258 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1259 		    "stmf_deregister_port_provider:2 %p",
1260 		    port->port_provider);
1261 #endif /* FCT_API_TRACE */
1262 		MODSYM(stmf_deregister_port_provider) (port->port_provider);
1263 	}
1264 
1265 	if (flag & 0x2) {
1266 #ifdef FCT_API_TRACE
1267 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1268 		    "stmf_free:2 %p", port->port_provider);
1269 #endif /* FCT_API_TRACE */
1270 		MODSYM(stmf_free) (port->port_provider);
1271 		port->port_provider = NULL;
1272 	}
1273 
1274 	if (flag & 0x1) {
1275 		emlxs_fct_dmem_fini(port);
1276 	}
1277 
1278 	port->flag &= ~EMLXS_TGT_ENABLED;
1279 
1280 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1281 	    "Target mode disabled.");
1282 
1283 	mutex_exit(&EMLXS_PORT_LOCK);
1284 
1285 	return;
1286 
1287 } /* emlxs_fct_bind_port() */
1288 
1289 
1290 /* COMSTAR ENTER POINT */
1291 /*ARGSUSED*/
1292 static fct_status_t
1293 emlxs_fct_port_info(uint32_t cmd, fct_local_port_t *fct_port, void *arg,
1294     uint8_t *buffer, uint32_t *size)
1295 {
1296 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1297 	emlxs_hba_t *hba = HBA;
1298 	fct_status_t rval = FCT_SUCCESS;
1299 	fct_port_link_status_t *link_status;
1300 	MAILBOX *mb;
1301 	MAILBOXQ *mbq;
1302 
1303 	switch (cmd) {
1304 	case FC_TGT_PORT_RLS:
1305 		bzero(buffer, *size);
1306 
1307 		if ((*size) < sizeof (fct_port_link_status_t)) {
1308 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1309 			    "FC_TGT_PORT_RLS: Buffer too small. %d < %d",
1310 			    *size, sizeof (fct_port_link_status_t));
1311 
1312 			rval = FCT_FAILURE;
1313 			break;
1314 		}
1315 
1316 		if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX)) == 0) {
1317 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1318 			    "FC_TGT_PORT_RLS: Unable to allocate mailbox.");
1319 
1320 			rval = FCT_ALLOC_FAILURE;
1321 			break;
1322 		}
1323 		mb = (MAILBOX *)mbq;
1324 
1325 		emlxs_mb_read_lnk_stat(hba, mbq);
1326 		if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0)
1327 		    != MBX_SUCCESS) {
1328 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1329 			    "FC_TGT_PORT_RLS: Unable to send request.");
1330 
1331 			rval = FCT_BUSY;
1332 		} else {
1333 			link_status = (fct_port_link_status_t *)buffer;
1334 			link_status->LinkFailureCount =
1335 			    mb->un.varRdLnk.linkFailureCnt;
1336 			link_status->LossOfSyncCount =
1337 			    mb->un.varRdLnk.lossSyncCnt;
1338 			link_status->LossOfSignalsCount =
1339 			    mb->un.varRdLnk.lossSignalCnt;
1340 			link_status->PrimitiveSeqProtocolErrorCount =
1341 			    mb->un.varRdLnk.primSeqErrCnt;
1342 			link_status->InvalidTransmissionWordCount =
1343 			    mb->un.varRdLnk.invalidXmitWord;
1344 			link_status->InvalidCRCCount =
1345 			    mb->un.varRdLnk.crcCnt;
1346 		}
1347 
1348 		emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
1349 		break;
1350 
1351 	default:
1352 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1353 		    "fct_port_info: Invalid request. cmd=%x",
1354 		    cmd);
1355 
1356 		rval = FCT_FAILURE;
1357 		break;
1358 
1359 	}
1360 
1361 	return (rval);
1362 
1363 } /* emlxs_fct_port_info() */
1364 
1365 
1366 /* COMSTAR ENTER POINT */
1367 static void
1368 emlxs_fct_populate_hba_details(fct_local_port_t *fct_port,
1369     fct_port_attrs_t *port_attrs)
1370 {
1371 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1372 	emlxs_hba_t *hba = HBA;
1373 	emlxs_vpd_t *vpd = &VPD;
1374 
1375 	(void) strncpy(port_attrs->manufacturer,
1376 	    hba->model_info.manufacturer,
1377 	    (sizeof (port_attrs->manufacturer)-1));
1378 	(void) strncpy(port_attrs->serial_number, vpd->serial_num,
1379 	    (sizeof (port_attrs->serial_number)-1));
1380 	(void) strncpy(port_attrs->model, hba->model_info.model,
1381 	    (sizeof (port_attrs->model)-1));
1382 	(void) strncpy(port_attrs->model_description,
1383 	    hba->model_info.model_desc,
1384 	    (sizeof (port_attrs->model_description)-1));
1385 	(void) snprintf(port_attrs->hardware_version,
1386 	    (sizeof (port_attrs->hardware_version)-1),
1387 	    "%x", vpd->biuRev);
1388 	(void) snprintf(port_attrs->driver_version,
1389 	    (sizeof (port_attrs->driver_version)-1),
1390 	    "%s (%s)", emlxs_version,
1391 	    emlxs_revision);
1392 	(void) strncpy(port_attrs->option_rom_version, vpd->fcode_version,
1393 	    (sizeof (port_attrs->option_rom_version)-1));
1394 	(void) snprintf(port_attrs->firmware_version,
1395 	    (sizeof (port_attrs->firmware_version)-1),
1396 	    "%s (%s)", vpd->fw_version,
1397 	    vpd->fw_label);
1398 	(void) strncpy(port_attrs->driver_name, DRIVER_NAME,
1399 	    (sizeof (port_attrs->driver_name)-1));
1400 	port_attrs->vendor_specific_id = (hba->model_info.device_id << 16) |
1401 	    hba->model_info.vendor_id;
1402 	port_attrs->supported_cos = LE_SWAP32(FC_NS_CLASS3);
1403 
1404 	port_attrs->max_frame_size = FF_FRAME_SIZE;
1405 
1406 	if (vpd->link_speed & LMT_32GB_CAPABLE) {
1407 		port_attrs->supported_speed |= PORT_SPEED_32G;
1408 	}
1409 	if (vpd->link_speed & LMT_16GB_CAPABLE) {
1410 		port_attrs->supported_speed |= PORT_SPEED_16G;
1411 	}
1412 	if (vpd->link_speed & LMT_10GB_CAPABLE) {
1413 		port_attrs->supported_speed |= PORT_SPEED_10G;
1414 	}
1415 	if (vpd->link_speed & LMT_8GB_CAPABLE) {
1416 		port_attrs->supported_speed |= PORT_SPEED_8G;
1417 	}
1418 	if (vpd->link_speed & LMT_4GB_CAPABLE) {
1419 		port_attrs->supported_speed |= PORT_SPEED_4G;
1420 	}
1421 	if (vpd->link_speed & LMT_2GB_CAPABLE) {
1422 		port_attrs->supported_speed |= PORT_SPEED_2G;
1423 	}
1424 	if (vpd->link_speed & LMT_1GB_CAPABLE) {
1425 		port_attrs->supported_speed |= PORT_SPEED_1G;
1426 	}
1427 
1428 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1429 	    "Port attr: manufacturer       = %s", port_attrs->manufacturer);
1430 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1431 	    "Port attr: serial_num         = %s", port_attrs->serial_number);
1432 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1433 	    "Port attr: model              = %s", port_attrs->model);
1434 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1435 	    "Port attr: model_description  = %s",
1436 	    port_attrs->model_description);
1437 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1438 	    "Port attr: hardware_version   = %s",
1439 	    port_attrs->hardware_version);
1440 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1441 	    "Port attr: driver_version     = %s", port_attrs->driver_version);
1442 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1443 	    "Port attr: option_rom_version = %s",
1444 	    port_attrs->option_rom_version);
1445 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1446 	    "Port attr: firmware_version   = %s",
1447 	    port_attrs->firmware_version);
1448 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1449 	    "Port attr: driver_name        = %s", port_attrs->driver_name);
1450 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1451 	    "Port attr: vendor_specific_id = 0x%x",
1452 	    port_attrs->vendor_specific_id);
1453 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1454 	    "Port attr: supported_cos      = 0x%x",
1455 	    port_attrs->supported_cos);
1456 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1457 	    "Port attr: supported_speed    = 0x%x",
1458 	    port_attrs->supported_speed);
1459 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1460 	    "Port attr: max_frame_size     = 0x%x",
1461 	    port_attrs->max_frame_size);
1462 
1463 	return;
1464 
1465 } /* emlxs_fct_populate_hba_details() */
1466 
1467 
1468 /* COMSTAR ENTER POINT */
1469 /* ARGSUSED */
1470 static void
1471 emlxs_fct_ctl(fct_local_port_t *fct_port, int cmd, void *arg)
1472 {
1473 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1474 	emlxs_hba_t *hba = HBA;
1475 	stmf_change_status_t st;
1476 
1477 	st.st_completion_status = FCT_SUCCESS;
1478 	st.st_additional_info = NULL;
1479 
1480 	switch (cmd) {
1481 	case FCT_CMD_PORT_ONLINE:
1482 		/* If the HBA is offline, we cannot bring the tgtport online */
1483 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1484 			st.st_completion_status = FCT_FAILURE;
1485 			MODSYM(fct_ctl) (fct_port->port_lport,
1486 			    FCT_CMD_PORT_ONLINE_COMPLETE, &st);
1487 			break;
1488 		}
1489 
1490 		if (port->fct_flags & FCT_STATE_PORT_ONLINE) {
1491 			st.st_completion_status = STMF_ALREADY;
1492 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1493 			    "STATE: ONLINE chk");
1494 		} else {
1495 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1496 			    "STATE: OFFLINE --> ONLINE");
1497 
1498 			port->fct_flags |= FCT_STATE_NOT_ACKED;
1499 			port->fct_flags |= FCT_STATE_PORT_ONLINE;
1500 
1501 			if ((port->vpi == 0) &&
1502 			    (port->mode == MODE_TARGET) &&
1503 			    (hba->state <= FC_LINK_DOWN)) {
1504 				/* Try to bring the link up */
1505 				(void) emlxs_reset_link(hba, 1, 1);
1506 			}
1507 
1508 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1509 			    "STATE: ONLINE");
1510 		}
1511 
1512 		MODSYM(fct_ctl) (fct_port->port_lport,
1513 		    FCT_CMD_PORT_ONLINE_COMPLETE, &st);
1514 		break;
1515 
1516 	case FCT_CMD_PORT_OFFLINE:
1517 		if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
1518 			st.st_completion_status = STMF_ALREADY;
1519 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1520 			    "STATE: OFFLINE chk");
1521 
1522 		} else {
1523 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1524 			    "STATE: ONLINE --> OFFLINE");
1525 
1526 			/* Take link down and flush */
1527 			emlxs_fct_link_down(port);
1528 			emlxs_fct_unsol_flush(port);
1529 
1530 			/* Declare this port offline now */
1531 			port->fct_flags |= FCT_STATE_NOT_ACKED;
1532 			port->fct_flags &= ~FCT_STATE_PORT_ONLINE;
1533 
1534 			if ((port->vpi == 0) &&
1535 			    (port->mode == MODE_TARGET) &&
1536 			    !(port->flag & EMLXS_INI_ENABLED)) {
1537 				/* Take link down and hold it down */
1538 				(void) emlxs_reset_link(hba, 0, 1);
1539 			}
1540 
1541 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1542 			    "STATE: OFFLINE");
1543 		}
1544 
1545 		MODSYM(fct_ctl) (fct_port->port_lport,
1546 		    FCT_CMD_PORT_OFFLINE_COMPLETE, &st);
1547 
1548 		break;
1549 
1550 	case FCT_ACK_PORT_OFFLINE_COMPLETE:
1551 		port->fct_flags &= ~FCT_STATE_NOT_ACKED;
1552 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1553 		    "STATE: OFFLINE ack");
1554 		break;
1555 
1556 	case FCT_ACK_PORT_ONLINE_COMPLETE:
1557 		port->fct_flags &= ~FCT_STATE_NOT_ACKED;
1558 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1559 		    "STATE: ONLINE ack");
1560 		break;
1561 
1562 	case FCT_CMD_FORCE_LIP:
1563 		if (port->mode == MODE_INITIATOR) {
1564 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1565 			    "fct_ctl: FCT_CMD_FORCE_LIP.");
1566 			break;
1567 		}
1568 
1569 		if (hba->fw_flag & FW_UPDATE_NEEDED) {
1570 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1571 			    "fct_ctl: FCT_CMD_FORCE_LIP -> "
1572 			    "FCT_CMD_RESET");
1573 
1574 			hba->fw_flag |= FW_UPDATE_KERNEL;
1575 
1576 			/* Reset the adapter */
1577 			(void) emlxs_reset(port, FC_FCA_RESET);
1578 		} else {
1579 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1580 			    "fct_ctl: FCT_CMD_FORCE_LIP");
1581 
1582 			/* Reset the link */
1583 			(void) emlxs_reset(port, FC_FCA_LINK_RESET);
1584 		}
1585 		break;
1586 	}
1587 
1588 	return;
1589 
1590 } /* emlxs_fct_ctl() */
1591 
1592 
1593 extern int
1594 emlxs_fct_port_shutdown(emlxs_port_t *port)
1595 {
1596 	fct_local_port_t *fct_port;
1597 	int i;
1598 
1599 	fct_port = port->fct_port;
1600 	if (!fct_port) {
1601 		return (0);
1602 	}
1603 
1604 	port->fct_flags |= FCT_STATE_NOT_ACKED;
1605 
1606 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg, "fct_port_shutdown");
1607 	MODSYM(fct_port_shutdown) (fct_port, STMF_RFLAG_STAY_OFFLINED,
1608 	    DRIVER_NAME" shutdown");
1609 
1610 	i = 0;
1611 	while (port->fct_flags & FCT_STATE_NOT_ACKED) {
1612 		i++;
1613 		if (i > 300) {	/* 30 seconds */
1614 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1615 			    "fct_port_shutdown failed to ACK");
1616 			break;
1617 		}
1618 		delay(drv_usectohz(100000));	/* 100 msec */
1619 	}
1620 	return (1);
1621 }
1622 
1623 
1624 extern int
1625 emlxs_fct_port_initialize(emlxs_port_t *port)
1626 {
1627 	fct_local_port_t *fct_port;
1628 	int i;
1629 
1630 	fct_port = port->fct_port;
1631 	if (!fct_port) {
1632 		return (0);
1633 	}
1634 
1635 	port->fct_flags |= FCT_STATE_NOT_ACKED;
1636 
1637 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1638 	    "fct_port_initialize");
1639 	MODSYM(fct_port_initialize) (fct_port, STMF_RFLAG_STAY_OFFLINED,
1640 	    DRIVER_NAME" initialize");
1641 
1642 	i = 0;
1643 	while (port->fct_flags & FCT_STATE_NOT_ACKED) {
1644 		i++;
1645 		if (i > 300) {	/* 30 seconds */
1646 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1647 			    "fct_port_initialize failed to ACK");
1648 			break;
1649 		}
1650 		delay(drv_usectohz(100000));	/* 100 msec */
1651 	}
1652 	return (1);
1653 }
1654 
1655 
1656 /* COMSTAR ENTER POINT */
1657 static fct_status_t
1658 emlxs_fct_send_cmd(fct_cmd_t *fct_cmd)
1659 {
1660 	emlxs_port_t *port;
1661 
1662 	port = (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
1663 
1664 #ifdef FCT_API_TRACE
1665 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1666 	    "fct_send_cmd %p:%p  x%x", fct_cmd,
1667 	    fct_cmd->cmd_fca_private, fct_cmd->cmd_type);
1668 #endif /* FCT_API_TRACE */
1669 
1670 	switch (fct_cmd->cmd_type) {
1671 	case FCT_CMD_SOL_ELS:
1672 
1673 		return (emlxs_fct_send_els_cmd(fct_cmd));
1674 
1675 	case FCT_CMD_SOL_CT:
1676 
1677 		return (emlxs_fct_send_ct_cmd(fct_cmd));
1678 
1679 	default:
1680 
1681 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1682 		    "fct_send_cmd: Invalid cmd type found. type=%x",
1683 		    fct_cmd->cmd_type);
1684 
1685 		return (FCT_FAILURE);
1686 	}
1687 
1688 } /* emlxs_fct_send_cmd() */
1689 
1690 
1691 /* COMSTAR ENTER POINT */
1692 static fct_status_t
1693 emlxs_fct_send_cmd_rsp(fct_cmd_t *fct_cmd, uint32_t ioflags)
1694 {
1695 	emlxs_port_t *port;
1696 	emlxs_buf_t *cmd_sbp;
1697 	fct_status_t rval;
1698 	IOCBQ *iocbq;
1699 	IOCB *iocb;
1700 	uint32_t status;
1701 
1702 	port = (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
1703 
1704 	rval = emlxs_fct_cmd_accept(port, fct_cmd, EMLXS_FCT_SEND_CMD_RSP);
1705 	if (rval) {
1706 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1707 		    "fct_send_cmd_rsp: "
1708 		    "Unable to accept fct_cmd. type=%x",
1709 		    fct_cmd->cmd_type);
1710 
1711 		return (rval);
1712 	}
1713 	/* mutex_enter(&cmd_sbp->fct_mtx); */
1714 
1715 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
1716 	iocbq = &cmd_sbp->iocbq;
1717 	iocbq->sbp = cmd_sbp;
1718 	iocb = &iocbq->iocb;
1719 	status = iocb->ULPSTATUS;
1720 
1721 #ifdef FCT_API_TRACE
1722 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1723 	    "fct_send_cmd_rsp %p:%p x%x, %x, %x",
1724 	    fct_cmd, cmd_sbp, fct_cmd->cmd_type, iocb->ULPCT, status);
1725 #endif /* FCT_API_TRACE */
1726 
1727 	switch (fct_cmd->cmd_type) {
1728 	case FCT_CMD_FCP_XCHG:
1729 
1730 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1731 			goto failure;
1732 		}
1733 
1734 		if ((iocb->ULPCT == 0x1) && (status == 0)) {
1735 
1736 			/* Firmware already sent out resp */
1737 			cmd_sbp->fct_flags |= EMLXS_FCT_SEND_STATUS;
1738 
1739 			TGTPORTSTAT.FctOutstandingIO--;
1740 
1741 			emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
1742 			/* mutex_exit(&cmd_sbp->fct_mtx); */
1743 
1744 #ifdef FCT_API_TRACE
1745 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1746 			    "fct_send_response_done:4 %p: x%x",
1747 			    fct_cmd, fct_cmd->cmd_comp_status);
1748 
1749 #endif /* FCT_API_TRACE */
1750 
1751 			MODSYM(fct_send_response_done) (fct_cmd,
1752 			    fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
1753 
1754 			return (FCT_SUCCESS);
1755 		}
1756 
1757 		rval =  emlxs_fct_send_fcp_status(fct_cmd);
1758 		if (rval == FCT_NOT_FOUND) {
1759 			goto failure;
1760 		}
1761 		/* mutex_exit(&cmd_sbp->fct_mtx); */
1762 
1763 		return (rval);
1764 
1765 	case FCT_CMD_RCVD_ELS:
1766 
1767 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1768 			goto failure;
1769 		}
1770 
1771 		rval =  emlxs_fct_send_els_rsp(fct_cmd);
1772 		/* mutex_exit(&cmd_sbp->fct_mtx); */
1773 
1774 		return (rval);
1775 
1776 	default:
1777 
1778 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1779 			fct_cmd->cmd_handle = 0;
1780 		}
1781 
1782 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1783 		    "fct_send_cmd_rsp: Invalid cmd type found. type=%x",
1784 		    fct_cmd->cmd_type);
1785 
1786 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
1787 		/* mutex_exit(&cmd_sbp->fct_mtx); */
1788 
1789 		return (FCT_FAILURE);
1790 	}
1791 
1792 failure:
1793 
1794 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1795 	    "fct_send_cmd_rsp: "
1796 	    "Unable to handle FCT_IOF_FORCE_FCA_DONE. type=%x",
1797 	    fct_cmd->cmd_type);
1798 
1799 	emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
1800 	/* mutex_exit(&cmd_sbp->fct_mtx); */
1801 
1802 	return (FCT_FAILURE);
1803 
1804 } /* emlxs_fct_send_cmd_rsp() */
1805 
1806 
1807 /* COMSTAR ENTER POINT */
1808 static fct_status_t
1809 emlxs_fct_flogi_xchg(struct fct_local_port *fct_port, struct fct_flogi_xchg *fx)
1810 {
1811 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1812 	emlxs_hba_t *hba = HBA;
1813 	uint32_t size;
1814 	fc_packet_t *pkt = NULL;
1815 	ELS_PKT *els;
1816 	fct_status_t rval = FCT_SUCCESS;
1817 
1818 #ifdef FCT_API_TRACE
1819 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1820 	    "fct_flogi_xchg: Sending FLOGI: %p", fct_port);
1821 #else
1822 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1823 	    "fct_flogi_xchg: Sending FLOGI.");
1824 #endif /* FCT_API_TRACE */
1825 
1826 	if (hba->state <= FC_LINK_DOWN) {
1827 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1828 		    "fct_flogi_xchg: FLOGI failed. Link down.");
1829 		rval = FCT_FAILURE;
1830 		goto done;
1831 	}
1832 
1833 	/* Use this entry point as the link up acknowledgment */
1834 	mutex_enter(&EMLXS_PORT_LOCK);
1835 	port->fct_flags |= FCT_STATE_LINK_UP_ACKED;
1836 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1837 	    "fct_link_up acked.");
1838 	mutex_exit(&EMLXS_PORT_LOCK);
1839 
1840 	/* First handle any pending FLOGI's */
1841 	emlxs_fct_handle_unsol_flogi(port, NULL, 0);
1842 
1843 	size = sizeof (SERV_PARM) + 4;
1844 
1845 	if (!(pkt = emlxs_pkt_alloc(port, size, size, 0, KM_NOSLEEP))) {
1846 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1847 		    "fct_flogi_xchg: FLOGI failed. "
1848 		    "Unable allocate packet.");
1849 		rval = FCT_FAILURE;
1850 		goto done;
1851 	}
1852 
1853 	/* Make this a polled IO */
1854 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
1855 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
1856 	pkt->pkt_comp = NULL;
1857 
1858 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
1859 	pkt->pkt_timeout = fx->fx_sec_timeout;
1860 
1861 	/* Build the fc header */
1862 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(fx->fx_did);
1863 	pkt->pkt_cmd_fhdr.r_ctl =
1864 	    R_CTL_EXTENDED_SVC | R_CTL_SOLICITED_CONTROL;
1865 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(fx->fx_sid);
1866 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
1867 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE;
1868 	pkt->pkt_cmd_fhdr.seq_id = 0;
1869 	pkt->pkt_cmd_fhdr.df_ctl = 0;
1870 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
1871 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
1872 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
1873 	pkt->pkt_cmd_fhdr.ro = 0;
1874 
1875 	/* Build the command */
1876 	/* Service paramters will be added automatically later by the driver */
1877 	els = (ELS_PKT *)pkt->pkt_cmd;
1878 	els->elsCode = 0x04;	/* FLOGI */
1879 
1880 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
1881 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1882 		    "fct_flogi_xchg: FLOGI failed. "
1883 		    "Unable to send packet.");
1884 
1885 		rval = FCT_FAILURE;
1886 		goto done;
1887 	}
1888 
1889 	if ((pkt->pkt_state != FC_PKT_SUCCESS) &&
1890 	    (pkt->pkt_state != FC_PKT_LS_RJT)) {
1891 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
1892 			rval = FCT_TIMEOUT;
1893 		} else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
1894 		    (pkt->pkt_reason == FC_REASON_FCAL_OPN_FAIL)) {
1895 			rval = FCT_NOT_FOUND;
1896 		} else {
1897 			rval = FCT_FAILURE;
1898 		}
1899 
1900 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1901 		    "fct_flogi_xchg: FLOGI failed. state=%x reason=%x "
1902 		    "rval=%llx", pkt->pkt_state, pkt->pkt_reason, rval);
1903 
1904 		goto done;
1905 	}
1906 
1907 	if (pkt->pkt_state == FC_PKT_LS_RJT) {
1908 		fx->fx_op = ELS_OP_LSRJT;
1909 		fx->fx_rjt_reason = pkt->pkt_reason;
1910 		fx->fx_rjt_expl = pkt->pkt_expln;
1911 	} else {	/* FC_PKT_SUCCESS */
1912 
1913 		fx->fx_op = ELS_OP_ACC;
1914 		fx->fx_sid = FABRIC_DID;
1915 		fx->fx_did = port->did;
1916 
1917 		els = (ELS_PKT *)pkt->pkt_resp;
1918 		bcopy((caddr_t)&els->un.logi.nodeName,
1919 		    (caddr_t)fx->fx_nwwn, 8);
1920 		bcopy((caddr_t)&els->un.logi.portName,
1921 		    (caddr_t)fx->fx_pwwn, 8);
1922 		fx->fx_fport = els->un.logi.cmn.fPort;
1923 	}
1924 
1925 done:
1926 	if (pkt) {
1927 		emlxs_pkt_free(pkt);
1928 	}
1929 
1930 	if ((rval == FCT_SUCCESS) || (rval == FCT_NOT_FOUND)) {
1931 
1932 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1933 		    "fct_flogi_xchg: FCT_STATE_FLOGI_CMPL.  rval=%s",
1934 		    ((rval == FCT_SUCCESS)? "FCT_SUCCESS":"FCT_NOT_FOUND"));
1935 
1936 		mutex_enter(&EMLXS_PORT_LOCK);
1937 		port->fct_flags |= FCT_STATE_FLOGI_CMPL;
1938 		mutex_exit(&EMLXS_PORT_LOCK);
1939 
1940 		/*
1941 		 * Flush all unsolicited commands
1942 		 * Must use separate thread since
1943 		 * this thread must complete first
1944 		 */
1945 		emlxs_thread_spawn(hba, emlxs_fct_unsol_flush_thread,
1946 		    (void *)port, 0);
1947 	}
1948 
1949 	return (rval);
1950 
1951 } /* emlxs_fct_flogi_xchg() */
1952 
1953 
1954 /* COMSTAR ENTER POINT */
1955 /* This is called right after we report that link has come online */
1956 static fct_status_t
1957 emlxs_fct_get_link_info(fct_local_port_t *fct_port, fct_link_info_t *link)
1958 {
1959 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1960 	emlxs_hba_t *hba = HBA;
1961 
1962 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1963 	    "fct_get_link_info %p: FCT: flg x%x  HBA: ste x%x flg x%x topo x%x",
1964 	    fct_port, port->fct_flags, hba->state, hba->flag, hba->topology);
1965 
1966 	mutex_enter(&EMLXS_PORT_LOCK);
1967 
1968 	if (port->mode == MODE_INITIATOR) {
1969 		link->port_topology = PORT_TOPOLOGY_UNKNOWN;
1970 		link->port_speed = PORT_SPEED_UNKNOWN;
1971 		link->portid = 0;
1972 
1973 		mutex_exit(&EMLXS_PORT_LOCK);
1974 
1975 		return (FCT_SUCCESS);
1976 	}
1977 
1978 	if (!(port->fct_flags & FCT_STATE_LINK_UP) ||
1979 	    (hba->state < FC_LINK_UP) || (hba->flag & FC_LOOPBACK_MODE)) {
1980 		link->port_topology = PORT_TOPOLOGY_UNKNOWN;
1981 		link->port_speed = PORT_SPEED_UNKNOWN;
1982 		link->portid = 0;
1983 
1984 		mutex_exit(&EMLXS_PORT_LOCK);
1985 
1986 		return (FCT_SUCCESS);
1987 	}
1988 
1989 	if (hba->topology == TOPOLOGY_LOOP) {
1990 		link->port_topology = PORT_TOPOLOGY_PRIVATE_LOOP;
1991 	} else {
1992 		link->port_topology = PORT_TOPOLOGY_PT_TO_PT;
1993 	}
1994 
1995 	switch (hba->linkspeed) {
1996 	case LA_1GHZ_LINK:
1997 		link->port_speed = PORT_SPEED_1G;
1998 		break;
1999 	case LA_2GHZ_LINK:
2000 		link->port_speed = PORT_SPEED_2G;
2001 		break;
2002 	case LA_4GHZ_LINK:
2003 		link->port_speed = PORT_SPEED_4G;
2004 		break;
2005 	case LA_8GHZ_LINK:
2006 		link->port_speed = PORT_SPEED_8G;
2007 		break;
2008 	case LA_10GHZ_LINK:
2009 		link->port_speed = PORT_SPEED_10G;
2010 		break;
2011 	case LA_16GHZ_LINK:
2012 		link->port_speed = PORT_SPEED_16G;
2013 		break;
2014 	case LA_32GHZ_LINK:
2015 		link->port_speed = PORT_SPEED_32G;
2016 		break;
2017 	default:
2018 		link->port_speed = PORT_SPEED_UNKNOWN;
2019 		break;
2020 	}
2021 
2022 	link->portid = port->did;
2023 	link->port_no_fct_flogi = 0;
2024 	link->port_fca_flogi_done = 0;
2025 	link->port_fct_flogi_done = 0;
2026 
2027 	mutex_exit(&EMLXS_PORT_LOCK);
2028 
2029 	return (FCT_SUCCESS);
2030 
2031 } /* emlxs_fct_get_link_info() */
2032 
2033 
2034 /* COMSTAR ENTER POINT */
2035 static fct_status_t
2036 emlxs_fct_register_remote_port(fct_local_port_t *fct_port,
2037     fct_remote_port_t *remote_port, fct_cmd_t *fct_cmd)
2038 {
2039 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
2040 	emlxs_hba_t *hba = HBA;
2041 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2042 	clock_t timeout;
2043 	int32_t pkt_ret;
2044 	fct_els_t *els;
2045 	SERV_PARM *sp;
2046 	emlxs_node_t *ndlp;
2047 	SERV_PARM sparam;
2048 	uint32_t *iptr;
2049 	uint16_t hdl;
2050 	uint64_t addr;
2051 	fct_status_t rval;
2052 	fct_status_t rval2;
2053 	uint32_t i;
2054 
2055 #ifdef FCT_API_TRACE
2056 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2057 	    "fct_register_remote_port %p", fct_port);
2058 #endif /* FCT_API_TRACE */
2059 
2060 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
2061 
2062 		cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd,
2063 		    EMLXS_FCT_REG_PENDING);
2064 		/* mutex_enter(&cmd_sbp->fct_mtx); */
2065 
2066 		cmd_sbp->channel = &hba->chan[hba->channel_els];
2067 		cmd_sbp->fct_type = EMLXS_FCT_ELS_CMD;
2068 
2069 	} else {
2070 
2071 		rval = emlxs_fct_cmd_accept(port, fct_cmd,
2072 		    EMLXS_FCT_REG_PENDING);
2073 		if (rval) {
2074 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2075 			    "fct_register_remote_port: "
2076 			    "Unable to accept fct_cmd. lid=%x rid=%x",
2077 			    fct_cmd->cmd_lportid, fct_cmd->cmd_rportid);
2078 
2079 			return (rval);
2080 		}
2081 		/* mutex_enter(&cmd_sbp->fct_mtx); */
2082 	}
2083 
2084 	cmd_sbp->fct_flags &= ~EMLXS_FCT_REGISTERED;
2085 	cmd_sbp->node = emlxs_node_find_did(port, fct_cmd->cmd_rportid, 1);
2086 
2087 	/* Check for unsolicited PLOGI */
2088 	if (cmd_sbp->fct_flags & EMLXS_FCT_PLOGI_RECEIVED) {
2089 		els = (fct_els_t *)fct_cmd->cmd_specific;
2090 		sp = (SERV_PARM *)((caddr_t)els->els_req_payload +
2091 		    sizeof (uint32_t));
2092 
2093 	} else {	/* Solicited PLOGI */
2094 
2095 		sp = &sparam;
2096 		bcopy((caddr_t)&port->sparam, (caddr_t)sp,
2097 		    sizeof (SERV_PARM));
2098 
2099 		/*
2100 		 * Create temporary WWN's from fct_cmd address
2101 		 * This simply allows us to get an RPI from the
2102 		 * adapter until we get real service params.
2103 		 * The PLOGI ACC reply will trigger a REG_LOGIN
2104 		 * update later
2105 		 */
2106 		addr = (uint64_t)((unsigned long)fct_cmd);
2107 
2108 		iptr = (uint32_t *)&sp->portName;
2109 		iptr[0] = PADDR_HI(addr);
2110 		iptr[1] = PADDR_LO(addr);
2111 
2112 		iptr = (uint32_t *)&sp->nodeName;
2113 		iptr[0] = PADDR_HI(addr);
2114 		iptr[1] = PADDR_LO(addr);
2115 	}
2116 
2117 	if (hba->flag & FC_PT_TO_PT) {
2118 		mutex_enter(&EMLXS_PORT_LOCK);
2119 		port->did = fct_cmd->cmd_lportid;
2120 		port->rdid = fct_cmd->cmd_rportid;
2121 		mutex_exit(&EMLXS_PORT_LOCK);
2122 
2123 		/*
2124 		 * We already received the remote port's
2125 		 * parameters in the FLOGI exchange
2126 		 */
2127 		if (!(cmd_sbp->fct_flags & EMLXS_FCT_PLOGI_RECEIVED)) {
2128 			sp = &sparam;
2129 			bcopy((caddr_t)&port->fabric_sparam, (caddr_t)sp,
2130 			    sizeof (SERV_PARM));
2131 
2132 			/*
2133 			 * Since this is a PLOGI, not a FLOGI, we need
2134 			 * to fix up word2 of the CSP accordingly.
2135 			 */
2136 			sp->cmn.w2.r_a_tov = port->sparam.cmn.w2.r_a_tov;
2137 		}
2138 	}
2139 
2140 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
2141 	    "fct_register_remote_port: Register lid=%x rid=%x. (%x,%x,%p)",
2142 	    fct_cmd->cmd_lportid, fct_cmd->cmd_rportid, cmd_sbp->fct_state,
2143 	    hba->flag, fct_cmd);
2144 
2145 	emlxs_fct_cmd_release(port, fct_cmd, 0);
2146 	/* mutex_exit(&cmd_sbp->fct_mtx); */
2147 
2148 	/* Create a new node */
2149 	if (EMLXS_SLI_REG_DID(port, fct_cmd->cmd_rportid, sp, cmd_sbp,
2150 	    NULL, NULL) != 0) {
2151 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2152 		    "fct_register_remote_port: "
2153 		    "Reg login failed. lid=%x rid=%x",
2154 		    fct_cmd->cmd_lportid, fct_cmd->cmd_rportid);
2155 	} else {
2156 
2157 		/* Wait for completion */
2158 		mutex_enter(&EMLXS_PKT_LOCK);
2159 		timeout = emlxs_timeout(hba, 30);
2160 		pkt_ret = 0;
2161 		while ((pkt_ret != -1) &&
2162 		    (cmd_sbp->fct_state == EMLXS_FCT_REG_PENDING) &&
2163 		    !(cmd_sbp->fct_flags & EMLXS_FCT_REGISTERED)) {
2164 			pkt_ret = cv_timedwait(&EMLXS_PKT_CV,
2165 			    &EMLXS_PKT_LOCK, timeout);
2166 		}
2167 		mutex_exit(&EMLXS_PKT_LOCK);
2168 	}
2169 
2170 	/* Reacquire ownership of the fct_cmd */
2171 	rval2 = emlxs_fct_cmd_acquire(port, fct_cmd,
2172 	    EMLXS_FCT_REG_COMPLETE);
2173 	if (rval2) {
2174 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2175 		    "fct_register_remote_port: "
2176 		    "Unable to reacquire fct_cmd. lid=%x rid=%x",
2177 		    fct_cmd->cmd_lportid, fct_cmd->cmd_rportid);
2178 
2179 		return (rval2);
2180 	}
2181 	/* mutex_enter(&cmd_sbp->fct_mtx); */
2182 
2183 	/* Prepare response */
2184 
2185 	ndlp = (emlxs_node_t *)cmd_sbp->node;
2186 
2187 	if (ndlp) {
2188 		cmd_sbp->fct_flags |= EMLXS_FCT_REGISTERED;
2189 
2190 		*((emlxs_node_t **)remote_port->rp_fca_private) =
2191 		    cmd_sbp->node;
2192 
2193 		hdl = ndlp->nlp_Rpi;
2194 		if (hdl == FABRIC_RPI) {
2195 			if (fct_cmd->cmd_rportid == SCR_DID) {
2196 				/* The SCR handle is hardcoded */
2197 				remote_port->rp_handle = hba->max_nodes;
2198 				port->fct_els_only_bmap |= 1;
2199 
2200 			} else {
2201 				for (i = 1; i < EMLXS_FCT_NUM_ELS_ONLY; i++) {
2202 					if (port->fct_els_only_bmap & (1 << i))
2203 						continue;
2204 					/*
2205 					 * Bit is not set, so use this
2206 					 * for the handle
2207 					 */
2208 					remote_port->rp_handle =
2209 					    hba->max_nodes + i;
2210 					port->fct_els_only_bmap |= (1 << i);
2211 					break;
2212 				}
2213 				if (i >= EMLXS_FCT_NUM_ELS_ONLY) {
2214 					remote_port->rp_handle =
2215 					    FCT_HANDLE_NONE;
2216 				}
2217 			}
2218 		} else {
2219 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2220 				hdl = emlxs_sli4_rpi_to_index(hba, hdl);
2221 			}
2222 			remote_port->rp_handle = hdl;
2223 		}
2224 
2225 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2226 		    "fct_register_remote_port: lid=%x rid=%x hdl=%x",
2227 		    fct_cmd->cmd_lportid, fct_cmd->cmd_rportid,
2228 		    remote_port->rp_handle);
2229 
2230 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2231 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2232 
2233 		TGTPORTSTAT.FctPortRegister++;
2234 		return (FCT_SUCCESS);
2235 	} else {
2236 		*((emlxs_node_t **)remote_port->rp_fca_private) = NULL;
2237 
2238 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2239 		    "fct_register_remote_port: failed. lid=%x rid=%x hdl=%x",
2240 		    fct_cmd->cmd_lportid, fct_cmd->cmd_rportid,
2241 		    remote_port->rp_handle);
2242 
2243 		remote_port->rp_handle = FCT_HANDLE_NONE;
2244 
2245 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2246 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2247 
2248 		TGTPORTSTAT.FctFailedPortRegister++;
2249 		return (FCT_FAILURE);
2250 	}
2251 
2252 } /* emlxs_fct_register_remote_port() */
2253 
2254 
2255 /* COMSTAR ENTER POINT */
2256 static fct_status_t
2257 emlxs_fct_deregister_remote_port(fct_local_port_t *fct_port,
2258     fct_remote_port_t *remote_port)
2259 {
2260 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
2261 	emlxs_hba_t *hba = HBA;
2262 	emlxs_node_t *ndlp;
2263 	uint32_t i;
2264 
2265 #ifdef FCT_API_TRACE
2266 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2267 	    "fct_deregister_remote_port: did=%x hdl=%x",
2268 	    remote_port->rp_id, remote_port->rp_handle);
2269 #else
2270 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2271 	    "fct_deregister_remote_port: did=%x hdl=%x",
2272 	    remote_port->rp_id, remote_port->rp_handle);
2273 #endif /* FCT_API_TRACE */
2274 
2275 	if (remote_port->rp_handle >= hba->max_nodes) {
2276 		i = remote_port->rp_handle - hba->max_nodes;
2277 		if ((i < EMLXS_FCT_NUM_ELS_ONLY) &&
2278 		    (port->fct_els_only_bmap & (1 << i))) {
2279 			port->fct_els_only_bmap &= ~(1 << i);
2280 		}
2281 	}
2282 
2283 	ndlp = *((emlxs_node_t **)remote_port->rp_fca_private);
2284 	*((emlxs_node_t **)remote_port->rp_fca_private) = NULL;
2285 
2286 	if (ndlp) {
2287 		(void) EMLXS_SLI_UNREG_NODE(port, ndlp, NULL,
2288 		    NULL, NULL);
2289 	}
2290 
2291 	TGTPORTSTAT.FctPortDeregister++;
2292 	return (FCT_SUCCESS);
2293 
2294 } /* emlxs_fct_deregister_remote_port() */
2295 
2296 
2297 /* ARGSUSED */
2298 extern int
2299 emlxs_fct_handle_unsol_req(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
2300     MATCHMAP *mp, uint32_t size)
2301 {
2302 	emlxs_hba_t *hba = HBA;
2303 	IOCB *iocb;
2304 	fct_cmd_t *fct_cmd;
2305 	emlxs_buf_t *cmd_sbp;
2306 	emlxs_fcp_cmd_t *fcp_cmd;
2307 	emlxs_node_t *ndlp;
2308 	uint32_t cnt;
2309 	uint32_t tm;
2310 	uint16_t hdl;
2311 	scsi_task_t *fct_task;
2312 	uint8_t lun[8];
2313 	uint32_t sid = 0;
2314 
2315 	iocb = &iocbq->iocb;
2316 	ndlp = emlxs_node_find_rpi(port, iocb->ULPIOTAG);
2317 	if (!ndlp) {
2318 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2319 		    "FCP rcvd: Unknown RPI. rpi=%d rxid=%x. Dropping...",
2320 		    iocb->ULPIOTAG, iocb->ULPCONTEXT);
2321 
2322 		goto dropped;
2323 	}
2324 	sid = ndlp->nlp_DID;
2325 
2326 	fcp_cmd = (emlxs_fcp_cmd_t *)mp->virt;
2327 
2328 	if (!port->fct_port) {
2329 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2330 		    "FCP rcvd: Target unbound. rpi=%d rxid=%x. Dropping...",
2331 		    iocb->ULPIOTAG, iocb->ULPCONTEXT);
2332 
2333 		emlxs_send_logo(port, sid);
2334 
2335 		goto dropped;
2336 	}
2337 
2338 	if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
2339 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2340 		    "FCP rcvd: Target offline. rpi=%d rxid=%x. Dropping...",
2341 		    iocb->ULPIOTAG, iocb->ULPCONTEXT);
2342 
2343 		emlxs_send_logo(port, sid);
2344 
2345 		goto dropped;
2346 	}
2347 
2348 	/* Get lun id */
2349 	bcopy((void *)&fcp_cmd->fcpLunMsl, lun, 8);
2350 
2351 	if (TGTPORTSTAT.FctOutstandingIO >= port->fct_port->port_max_xchges) {
2352 		TGTPORTSTAT.FctOverQDepth++;
2353 	}
2354 
2355 	hdl = ndlp->nlp_Rpi;
2356 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2357 		hdl = emlxs_sli4_rpi_to_index(hba, hdl);
2358 	}
2359 	fct_cmd =
2360 	    MODSYM(fct_scsi_task_alloc) (port->fct_port, hdl, sid, lun, 16, 0);
2361 
2362 	if (fct_cmd == NULL) {
2363 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2364 		    "FCP rcvd: sid=%x xid=%x. "
2365 		    "Unable to allocate scsi task. Returning QFULL.",
2366 		    sid, iocb->ULPCONTEXT);
2367 
2368 		(void) emlxs_fct_send_qfull_reply(port, ndlp, iocb->ULPCONTEXT,
2369 		    iocb->ULPCLASS, fcp_cmd);
2370 
2371 		goto dropped;
2372 	}
2373 
2374 	/* Initialize fct_cmd */
2375 	fct_cmd->cmd_rportid = sid;
2376 	fct_cmd->cmd_lportid = port->did;
2377 	fct_cmd->cmd_rp_handle = hdl;
2378 	fct_cmd->cmd_port = port->fct_port;
2379 
2380 	cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_FCP_CMD_RECEIVED);
2381 	/* mutex_enter(&cmd_sbp->fct_mtx); */
2382 
2383 #ifdef FCT_API_TRACE
2384 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2385 	    "fct_scsi_task_alloc %p:%p FCP rcvd: "
2386 	    "cmd=%x sid=%x rxid=%x oxid=%x lun=%02x%02x dl=%d",
2387 	    fct_cmd, cmd_sbp, fcp_cmd->fcpCdb[0], sid, iocb->ULPCONTEXT,
2388 	    iocb->unsli3.ext_rcv.oxid, lun[0], lun[1],
2389 	    LE_SWAP32(fcp_cmd->fcpDl));
2390 #endif /* FCT_API_TRACE */
2391 
2392 	/* Initialize cmd_sbp */
2393 	cmd_sbp->channel = cp;
2394 	cmd_sbp->class = iocb->ULPCLASS;
2395 	cmd_sbp->lun = (lun[0] << 8) | lun[1];
2396 	cmd_sbp->fct_type = EMLXS_FCT_FCP_CMD;
2397 	cmd_sbp->ticks = hba->timer_tics + (2 * hba->fc_ratov);
2398 
2399 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2400 		/* xrip was setup / passed in from the SLI layer */
2401 		cmd_sbp->xrip = iocbq->sbp;
2402 		cmd_sbp->node = iocbq->node;
2403 		iocbq->sbp = 0;
2404 
2405 		fct_cmd->cmd_oxid = cmd_sbp->xrip->rx_id;
2406 		fct_cmd->cmd_rxid = cmd_sbp->xrip->XRI;
2407 
2408 #ifdef FCT_API_TRACE
2409 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2410 		    "FCP rcvd: oxid=%x rxid=%x iotag=%d %p ",
2411 		    fct_cmd->cmd_oxid, fct_cmd->cmd_rxid, cmd_sbp->xrip->iotag,
2412 		    hba->fc_table[cmd_sbp->xrip->iotag]);
2413 #endif /* FCT_API_TRACE */
2414 
2415 	} else {
2416 		fct_cmd->cmd_oxid = iocb->unsli3.ext_rcv.oxid;
2417 		if (!fct_cmd->cmd_oxid) {
2418 			fct_cmd->cmd_oxid = 0xFFFF;
2419 		}
2420 		fct_cmd->cmd_rxid = iocb->ULPCONTEXT;
2421 	}
2422 
2423 
2424 	fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
2425 
2426 	/* Set task_flags */
2427 	switch (fcp_cmd->fcpCntl1) {
2428 	case SIMPLE_Q:
2429 		fct_task->task_flags = TF_ATTR_SIMPLE_QUEUE;
2430 		break;
2431 
2432 	case HEAD_OF_Q:
2433 		fct_task->task_flags = TF_ATTR_HEAD_OF_QUEUE;
2434 		break;
2435 
2436 	case ORDERED_Q:
2437 		fct_task->task_flags = TF_ATTR_ORDERED_QUEUE;
2438 		break;
2439 
2440 	case ACA_Q:
2441 		fct_task->task_flags = TF_ATTR_ACA;
2442 		break;
2443 
2444 	case UNTAGGED:
2445 		fct_task->task_flags = TF_ATTR_UNTAGGED;
2446 		break;
2447 	}
2448 
2449 	cnt = LE_SWAP32(fcp_cmd->fcpDl);
2450 	switch (fcp_cmd->fcpCntl3) {
2451 	case 0:
2452 		TGTPORTSTAT.FctIOCmdCnt++;
2453 		break;
2454 	case 1:
2455 		EMLXS_BUMP_WRIOCTR(port, cnt);
2456 		TGTPORTSTAT.FctWriteBytes += cnt;
2457 		fct_task->task_flags |= TF_WRITE_DATA;
2458 		break;
2459 
2460 	case 2:
2461 		EMLXS_BUMP_RDIOCTR(port, cnt);
2462 		TGTPORTSTAT.FctReadBytes += cnt;
2463 		fct_task->task_flags |= TF_READ_DATA;
2464 		break;
2465 	}
2466 
2467 	fct_task->task_priority = 0;
2468 
2469 	/* task_mgmt_function */
2470 	tm = fcp_cmd->fcpCntl2;
2471 	if (tm) {
2472 		if (tm & BIT_1) {
2473 			fct_task->task_mgmt_function = TM_ABORT_TASK_SET;
2474 		} else if (tm & BIT_2) {
2475 			fct_task->task_mgmt_function = TM_CLEAR_TASK_SET;
2476 		} else if (tm & BIT_4) {
2477 			fct_task->task_mgmt_function = TM_LUN_RESET;
2478 		} else if (tm & BIT_5) {
2479 			fct_task->task_mgmt_function = TM_TARGET_COLD_RESET;
2480 		} else if (tm & BIT_6) {
2481 			fct_task->task_mgmt_function = TM_CLEAR_ACA;
2482 		} else {
2483 			fct_task->task_mgmt_function = TM_ABORT_TASK;
2484 		}
2485 	}
2486 
2487 	/* Parallel buffers support - future */
2488 	fct_task->task_max_nbufs = 1;
2489 
2490 	fct_task->task_additional_flags = 0;
2491 	fct_task->task_cur_nbufs = 0;
2492 	fct_task->task_csn_size = 8;
2493 	fct_task->task_cmd_seq_no = 0;
2494 	fct_task->task_expected_xfer_length = cnt;
2495 	bcopy((void *)&fcp_cmd->fcpCdb, fct_task->task_cdb, 16);
2496 
2497 	TGTPORTSTAT.FctCmdReceived++;
2498 	TGTPORTSTAT.FctOutstandingIO++;
2499 
2500 	emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2501 	/* mutex_exit(&cmd_sbp->fct_mtx); */
2502 
2503 #ifdef FCT_API_TRACE
2504 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2505 	    "fct_post_rcvd_cmd:3 %p:%p portid x%x, %d outio %d",
2506 	    fct_cmd, cmd_sbp, fct_cmd->cmd_lportid,
2507 	    fct_task->task_expected_xfer_length,
2508 	    TGTPORTSTAT.FctOutstandingIO);
2509 #endif /* FCT_API_TRACE */
2510 
2511 	MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
2512 
2513 	return (0);
2514 
2515 dropped:
2516 
2517 	TGTPORTSTAT.FctRcvDropped++;
2518 	return (1);
2519 
2520 } /* emlxs_fct_handle_unsol_req() */
2521 
2522 
2523 /* COMSTAR ENTER POINT */
2524 /* ARGSUSED */
2525 static fct_status_t
2526 emlxs_fct_send_fcp_data(fct_cmd_t *fct_cmd, stmf_data_buf_t *dbuf,
2527     uint32_t ioflags)
2528 {
2529 	emlxs_port_t *port =
2530 	    (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
2531 	emlxs_hba_t *hba = HBA;
2532 	emlxs_buf_t *cmd_sbp;
2533 #ifdef FCT_API_TRACE
2534 	scsi_task_t *fct_task;
2535 #endif /* FCT_API_TRACE */
2536 	IOCBQ *iocbq;
2537 	emlxs_node_t *ndlp;
2538 
2539 	int	channel;
2540 	int	channelno;
2541 	fct_status_t rval = 0;
2542 
2543 	rval = emlxs_fct_cmd_accept(port, fct_cmd, EMLXS_FCT_SEND_FCP_DATA);
2544 	if (rval) {
2545 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2546 		    "fct_send_fcp_data: "
2547 		    "Unable to accept fct_cmd. did=%x",
2548 		    fct_cmd->cmd_rportid);
2549 
2550 		return (rval);
2551 	}
2552 	/* mutex_enter(&cmd_sbp->fct_mtx); */
2553 
2554 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2555 #ifdef FCT_API_TRACE
2556 	fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
2557 #endif /* FCT_API_TRACE */
2558 	ndlp = *(emlxs_node_t **)fct_cmd->cmd_rp->rp_fca_private;
2559 
2560 	cmd_sbp->node = ndlp;
2561 	cmd_sbp->fct_buf = dbuf;
2562 
2563 	channelno = ((CHANNEL *)cmd_sbp->channel)->channelno;
2564 
2565 	channel = channelno;
2566 
2567 
2568 
2569 	iocbq = &cmd_sbp->iocbq;
2570 	iocbq->sbp = cmd_sbp;
2571 
2572 #ifdef FCT_API_TRACE
2573 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2574 	    "fct_send_fcp_data %p:%p flgs=%x ioflags=%x dl=%d,%d,%d,%d",
2575 	    fct_cmd, cmd_sbp, dbuf->db_flags, ioflags,
2576 	    fct_task->task_cmd_xfer_length,
2577 	    fct_task->task_nbytes_transferred, dbuf->db_data_size,
2578 	    fct_task->task_expected_xfer_length);
2579 #endif /* FCT_API_TRACE */
2580 
2581 	/* Setup for I/O prep routine */
2582 	iocbq->iocb.ULPCOMMAND = 0;
2583 
2584 	if (EMLXS_SLI_PREP_FCT_IOCB(port, cmd_sbp, channel) != IOERR_SUCCESS) {
2585 
2586 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2587 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2588 
2589 		return (FCT_BUSY);
2590 	}
2591 
2592 	cmd_sbp->fct_type = EMLXS_FCT_FCP_DATA;
2593 
2594 	if (dbuf->db_flags & DB_SEND_STATUS_GOOD) {
2595 		cmd_sbp->fct_flags |= EMLXS_FCT_SEND_STATUS;
2596 	}
2597 
2598 	if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
2599 		if (emlxs_fct_dbuf_dma_sync(hba, dbuf, DDI_DMA_SYNC_FORDEV)) {
2600 			emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2601 			/* mutex_exit(&cmd_sbp->fct_mtx); */
2602 
2603 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2604 				emlxs_sli4_free_xri(port, cmd_sbp, 0, 0);
2605 			}
2606 			return (FCT_BUSY);
2607 		}
2608 	}
2609 
2610 	cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
2611 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_DATA_PENDING);
2612 	/* mutex_exit(&cmd_sbp->fct_mtx); */
2613 
2614 	EMLXS_SLI_ISSUE_IOCB_CMD(hba, cmd_sbp->channel, iocbq);
2615 
2616 	return (FCT_SUCCESS);
2617 
2618 } /* emlxs_fct_send_fcp_data() */
2619 
2620 
2621 /* cmd_sbp->fct_mtx must be held to enter */
2622 /* cmd_sbp->fct_mtx must be released before exiting */
2623 static fct_status_t
2624 emlxs_fct_send_fcp_status(fct_cmd_t *fct_cmd)
2625 {
2626 	emlxs_port_t *port =
2627 	    (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
2628 	emlxs_hba_t *hba = HBA;
2629 	emlxs_buf_t *cmd_sbp;
2630 	scsi_task_t *fct_task;
2631 	fc_packet_t *pkt;
2632 	emlxs_buf_t *sbp = NULL;
2633 	emlxs_fcp_rsp *fcp_rsp;
2634 	emlxs_node_t *ndlp;
2635 	fct_status_t rval;
2636 	uint32_t did;
2637 	uint32_t size;
2638 
2639 	fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
2640 	ndlp = *(emlxs_node_t **)fct_cmd->cmd_rp->rp_fca_private;
2641 	did = fct_cmd->cmd_rportid;
2642 
2643 	/* Initialize cmd_sbp */
2644 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2645 
2646 	EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, EMLXS_FCT_SEND_FCP_STATUS);
2647 
2648 	cmd_sbp->node = ndlp;
2649 
2650 	size = 24;
2651 	if (fct_task->task_sense_length) {
2652 		size += fct_task->task_sense_length;
2653 	}
2654 #ifdef FCT_API_TRACE
2655 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2656 	    "fct_send_fcp_status %p:%p stat=%d resid=%d size=%d rx=%x ox=%x",
2657 	    fct_cmd, cmd_sbp, fct_task->task_scsi_status,
2658 	    fct_task->task_resid, size, fct_cmd->cmd_rxid, fct_cmd->cmd_oxid);
2659 #endif /* FCT_API_TRACE */
2660 
2661 	if (!(pkt = emlxs_pkt_alloc(port, size, 0, 0, KM_NOSLEEP))) {
2662 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2663 		    "fct_send_fcp_status: Unable to allocate packet.");
2664 
2665 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2666 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2667 
2668 		return (FCT_BUSY);
2669 	}
2670 
2671 	cmd_sbp->fct_type = EMLXS_FCT_FCP_STATUS;
2672 
2673 	sbp =  emlxs_fct_pkt_init(port, fct_cmd, pkt);
2674 	cmd_sbp->fct_pkt = pkt;
2675 
2676 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
2677 	pkt->pkt_timeout =
2678 	    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
2679 	pkt->pkt_timeout = (pkt->pkt_timeout > 60)? 60: pkt->pkt_timeout;
2680 	pkt->pkt_comp = emlxs_fct_pkt_comp;
2681 
2682 	/* Build the fc header */
2683 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
2684 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_STATUS;
2685 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
2686 	pkt->pkt_cmd_fhdr.type = FC_TYPE_SCSI_FCP;
2687 	pkt->pkt_cmd_fhdr.f_ctl =
2688 	    F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ;
2689 	pkt->pkt_cmd_fhdr.seq_id = 0;
2690 	pkt->pkt_cmd_fhdr.df_ctl = 0;
2691 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
2692 	pkt->pkt_cmd_fhdr.ox_id = fct_cmd->cmd_oxid;
2693 	pkt->pkt_cmd_fhdr.rx_id = fct_cmd->cmd_rxid;
2694 	pkt->pkt_cmd_fhdr.ro = 0;
2695 
2696 	/* Build the status payload */
2697 	fcp_rsp = (emlxs_fcp_rsp *)pkt->pkt_cmd;
2698 
2699 	if (fct_task->task_resid) {
2700 		if (fct_task->task_status_ctrl & TASK_SCTRL_OVER) {
2701 			TGTPORTSTAT.FctScsiResidOver++;
2702 			fcp_rsp->rspStatus2 |= RESID_OVER;
2703 			fcp_rsp->rspResId = LE_SWAP32(fct_task->task_resid);
2704 
2705 		} else if (fct_task->task_status_ctrl & TASK_SCTRL_UNDER) {
2706 			TGTPORTSTAT.FctScsiResidUnder++;
2707 			fcp_rsp->rspStatus2 |= RESID_UNDER;
2708 			fcp_rsp->rspResId = LE_SWAP32(fct_task->task_resid);
2709 
2710 		}
2711 	}
2712 
2713 	if (fct_task->task_scsi_status) {
2714 		if (fct_task->task_scsi_status == SCSI_STAT_QUE_FULL) {
2715 			TGTPORTSTAT.FctScsiQfullErr++;
2716 		} else {
2717 			TGTPORTSTAT.FctScsiStatusErr++;
2718 		}
2719 
2720 		/* Make sure residual reported on non-SCSI_GOOD READ status */
2721 		if ((fct_task->task_flags & TF_READ_DATA) &&
2722 		    (fcp_rsp->rspResId == 0)) {
2723 			fcp_rsp->rspStatus2 |= RESID_UNDER;
2724 			fcp_rsp->rspResId =
2725 			    fct_task->task_expected_xfer_length;
2726 		}
2727 	}
2728 
2729 
2730 	if (fct_task->task_sense_length) {
2731 		TGTPORTSTAT.FctScsiSenseErr++;
2732 		fcp_rsp->rspStatus2 |= SNS_LEN_VALID;
2733 		fcp_rsp->rspSnsLen = LE_SWAP32(fct_task->task_sense_length);
2734 
2735 		bcopy((uint8_t *)fct_task->task_sense_data,
2736 		    (uint8_t *)&fcp_rsp->rspInfo0,
2737 		    fct_task->task_sense_length);
2738 	}
2739 
2740 	fcp_rsp->rspStatus3 = fct_task->task_scsi_status;
2741 	fcp_rsp->rspRspLen = 0;
2742 
2743 #ifdef FCT_API_TRACE
2744 	emlxs_data_dump(port, "RESP", (uint32_t *)fcp_rsp, 36, 0);
2745 #endif /* FCT_API_TRACE */
2746 
2747 	cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
2748 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_STATUS_PENDING);
2749 	/* mutex_exit(&cmd_sbp->fct_mtx); */
2750 
2751 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
2752 
2753 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2754 		    "fct_send_fcp_status: Unable to send packet.");
2755 
2756 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2757 			emlxs_sli4_free_xri(port, sbp, 0, 0);
2758 		}
2759 
2760 		/* Reacquire ownership of the fct_cmd */
2761 		rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
2762 		if (rval) {
2763 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2764 			    "fct_send_fcp_status: "
2765 			    "Unable to acquire fct_cmd.");
2766 			return (rval);
2767 		}
2768 		/* mutex_enter(&cmd_sbp->fct_mtx); */
2769 
2770 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2771 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2772 
2773 		return (FCT_BUSY);
2774 	}
2775 
2776 	return (FCT_SUCCESS);
2777 
2778 } /* emlxs_fct_send_fcp_status() */
2779 
2780 
2781 static fct_status_t
2782 emlxs_fct_send_qfull_reply(emlxs_port_t *port, emlxs_node_t *ndlp,
2783     uint16_t xid, uint32_t class, emlxs_fcp_cmd_t *fcp_cmd)
2784 {
2785 	emlxs_hba_t *hba = HBA;
2786 	emlxs_buf_t *sbp;
2787 	fc_packet_t *pkt;
2788 	emlxs_fcp_rsp *fcp_rsp;
2789 	uint32_t size;
2790 	CHANNEL *cp = &hba->chan[hba->CHANNEL_FCT];
2791 	uint8_t lun[8];
2792 
2793 	bcopy((void *)&fcp_cmd->fcpLunMsl, lun, 8);
2794 	size = 24;
2795 
2796 	if (!(pkt = emlxs_pkt_alloc(port, size, 0, 0, KM_NOSLEEP))) {
2797 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2798 		    "fct_send_qfull_reply: Unable to allocate packet.");
2799 		return (FCT_FAILURE);
2800 	}
2801 
2802 	sbp = PKT2PRIV(pkt);
2803 	sbp->node = ndlp;
2804 	sbp->channel = cp;
2805 	sbp->did = ndlp->nlp_DID;
2806 	sbp->lun = (lun[0] << 8) | lun[1];
2807 	sbp->class = class;
2808 
2809 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
2810 	pkt->pkt_timeout =
2811 	    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
2812 
2813 	/* Build the fc header */
2814 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(ndlp->nlp_DID);
2815 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_STATUS;
2816 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
2817 	pkt->pkt_cmd_fhdr.type = FC_TYPE_SCSI_FCP;
2818 	pkt->pkt_cmd_fhdr.f_ctl =
2819 	    F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ;
2820 	pkt->pkt_cmd_fhdr.seq_id = 0;
2821 	pkt->pkt_cmd_fhdr.df_ctl = 0;
2822 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
2823 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
2824 	pkt->pkt_cmd_fhdr.rx_id = xid;
2825 	pkt->pkt_cmd_fhdr.ro = 0;
2826 
2827 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2828 	    "fct_send_qfull_reply: Sending QFULL: x%x lun x%x: %d %d",
2829 	    xid, sbp->lun, TGTPORTSTAT.FctOutstandingIO,
2830 	    port->fct_port->port_max_xchges);
2831 
2832 	/* Build the status payload */
2833 	fcp_rsp = (emlxs_fcp_rsp *)pkt->pkt_cmd;
2834 
2835 	TGTPORTSTAT.FctScsiQfullErr++;
2836 	fcp_rsp->rspStatus3 = SCSI_STAT_QUE_FULL;
2837 	fcp_rsp->rspStatus2 |= RESID_UNDER;
2838 	fcp_rsp->rspResId = LE_SWAP32(fcp_cmd->fcpDl);
2839 
2840 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
2841 
2842 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2843 			emlxs_sli4_free_xri(port, sbp, 0, 0);
2844 		}
2845 
2846 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2847 		    "fct_send_qfull_reply: Unable to send packet.");
2848 		emlxs_pkt_free(pkt);
2849 		return (FCT_FAILURE);
2850 	}
2851 
2852 	return (FCT_SUCCESS);
2853 
2854 } /* emlxs_fct_send_qfull_reply() */
2855 
2856 
2857 /* ARGSUSED */
2858 extern int
2859 emlxs_fct_handle_fcp_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
2860 {
2861 	emlxs_port_t *port = &PPORT;
2862 	IOCB *iocb;
2863 	emlxs_buf_t *sbp;
2864 	emlxs_buf_t *cmd_sbp;
2865 	uint32_t status;
2866 	fct_cmd_t *fct_cmd;
2867 	stmf_data_buf_t *dbuf;
2868 	scsi_task_t *fct_task;
2869 	fc_packet_t *pkt;
2870 	uint32_t fct_flags;
2871 	stmf_data_buf_t *fct_buf;
2872 	fct_status_t rval;
2873 
2874 	iocb = &iocbq->iocb;
2875 	sbp = (emlxs_buf_t *)iocbq->sbp;
2876 
2877 	TGTPORTSTAT.FctEvent++;
2878 
2879 	if (!sbp) {
2880 		/* completion with missing xmit command */
2881 		TGTPORTSTAT.FctStray++;
2882 
2883 		/* emlxs_stray_fcp_completion_msg */
2884 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2885 		    "FCP event cmd=%x status=%x error=%x iotag=%d",
2886 		    iocb->ULPCOMMAND, iocb->ULPSTATUS,
2887 		    iocb->un.grsp.perr.statLocalError, iocb->ULPIOTAG);
2888 
2889 		return (1);
2890 	}
2891 
2892 	TGTPORTSTAT.FctCompleted++;
2893 
2894 	port = sbp->iocbq.port;
2895 	fct_cmd = sbp->fct_cmd;
2896 	status = iocb->ULPSTATUS;
2897 
2898 #ifdef FCT_API_TRACE
2899 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2900 	    "fct_handle_fcp_event: %p:%p cmd=%x status=%x, %x",
2901 	    fct_cmd, sbp, iocb->ULPCOMMAND, status, iocb->ULPCT);
2902 #endif /* FCT_API_TRACE */
2903 
2904 	if (fct_cmd == NULL) {
2905 		/* For driver generated QFULL response */
2906 		if (((iocb->ULPCOMMAND == CMD_FCP_TRSP_CX) ||
2907 		    (iocb->ULPCOMMAND == CMD_FCP_TRSP64_CX)) && sbp->pkt) {
2908 			emlxs_pkt_free(sbp->pkt);
2909 		}
2910 		return (0);
2911 	}
2912 
2913 	rval = emlxs_fct_cmd_acquire(port, fct_cmd, EMLXS_FCT_REQ_COMPLETE);
2914 	if (rval) {
2915 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2916 		    "fct_handle_fcp_event: "
2917 		    "Unable to reacquire fct_cmd. type=%x",
2918 		    fct_cmd->cmd_type);
2919 
2920 		return (1);
2921 	}
2922 	/* mutex_enter(&cmd_sbp->fct_mtx); */
2923 
2924 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2925 	cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
2926 
2927 	pkt = cmd_sbp->fct_pkt;
2928 	cmd_sbp->fct_pkt = NULL;
2929 
2930 	dbuf = sbp->fct_buf;
2931 
2932 	fct_cmd->cmd_comp_status = FCT_SUCCESS;
2933 
2934 	if (status) {
2935 emlxs_dma_error:
2936 		/*
2937 		 * The error indicates this IO should be terminated
2938 		 * immediately.
2939 		 */
2940 		cmd_sbp->fct_flags &= ~EMLXS_FCT_SEND_STATUS;
2941 		fct_cmd->cmd_comp_status = FCT_FAILURE;
2942 
2943 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
2944 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2945 
2946 #ifdef FCT_API_TRACE
2947 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2948 		    "fct_queue_cmd_for_termination:1 %p: x%x",
2949 		    fct_cmd, fct_cmd->cmd_comp_status);
2950 #endif /* FCT_API_TRACE */
2951 
2952 		MODSYM(fct_queue_cmd_for_termination) (fct_cmd,
2953 		    FCT_ABTS_RECEIVED);
2954 
2955 		goto done;
2956 	}
2957 
2958 	switch (iocb->ULPCOMMAND) {
2959 
2960 	/*
2961 	 *  FCP Data completion
2962 	 */
2963 	case CMD_FCP_TSEND_CX:
2964 	case CMD_FCP_TSEND64_CX:
2965 	case CMD_FCP_TRECEIVE_CX:
2966 	case CMD_FCP_TRECEIVE64_CX:
2967 
2968 		if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) {
2969 			if (emlxs_fct_dbuf_dma_sync(hba, dbuf,
2970 			    DDI_DMA_SYNC_FORCPU)) {
2971 				goto emlxs_dma_error;
2972 			}
2973 		}
2974 
2975 		if ((cmd_sbp->fct_flags & EMLXS_FCT_SEND_STATUS) &&
2976 		    (iocb->ULPCT != 1)) {
2977 
2978 			dbuf->db_flags |= DB_STATUS_GOOD_SENT;
2979 
2980 			fct_task =
2981 			    (scsi_task_t *)fct_cmd->cmd_specific;
2982 			fct_task->task_scsi_status = 0;
2983 
2984 			(void) emlxs_fct_send_fcp_status(fct_cmd);
2985 			/* mutex_exit(&cmd_sbp->fct_mtx); */
2986 
2987 			break;
2988 
2989 		} else if ((cmd_sbp->fct_flags &
2990 		    EMLXS_FCT_SEND_STATUS) &&
2991 		    (iocb->ULPCT == 1)) {
2992 			/* Auto-resp has been sent out by firmware */
2993 			/* We can assume this is really a FC_TRSP_CX */
2994 
2995 			dbuf->db_flags |= DB_STATUS_GOOD_SENT;
2996 			fct_task =
2997 			    (scsi_task_t *)fct_cmd->cmd_specific;
2998 			fct_task->task_scsi_status = 0;
2999 
3000 			cmd_sbp->fct_flags |= EMLXS_FCT_SEND_STATUS;
3001 
3002 			goto auto_resp;
3003 		}
3004 
3005 		cmd_sbp->fct_flags &= ~EMLXS_FCT_SEND_STATUS;
3006 
3007 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
3008 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3009 
3010 #ifdef FCT_API_TRACE
3011 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3012 		    "fct_scsi_data_xfer_done:1 %p %p", fct_cmd, dbuf);
3013 #endif /* FCT_API_TRACE */
3014 
3015 		MODSYM(fct_scsi_data_xfer_done) (fct_cmd, dbuf, 0);
3016 
3017 		break;
3018 
3019 		/* FCP Status completion */
3020 	case CMD_FCP_TRSP_CX:
3021 	case CMD_FCP_TRSP64_CX:
3022 
3023 auto_resp:
3024 		/* Copy these before calling emlxs_fct_cmd_done */
3025 		fct_flags = cmd_sbp->fct_flags;
3026 		fct_buf = cmd_sbp->fct_buf;
3027 
3028 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3029 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3030 
3031 		TGTPORTSTAT.FctOutstandingIO--;
3032 
3033 		if (fct_flags & EMLXS_FCT_SEND_STATUS) {
3034 #ifdef FCT_API_TRACE
3035 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3036 			    "fct_scsi_data_xfer_done:2 %p %p outio %d",
3037 			    fct_cmd, fct_buf, TGTPORTSTAT.FctOutstandingIO);
3038 #endif /* FCT_API_TRACE */
3039 
3040 			MODSYM(fct_scsi_data_xfer_done) (fct_cmd,
3041 			    fct_buf, FCT_IOF_FCA_DONE);
3042 		} else {
3043 #ifdef FCT_API_TRACE
3044 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3045 			    "fct_send_response_done:1 %p: x%x outio %d",
3046 			    fct_cmd, fct_cmd->cmd_comp_status,
3047 			    TGTPORTSTAT.FctOutstandingIO);
3048 #endif /* FCT_API_TRACE */
3049 
3050 			MODSYM(fct_send_response_done) (fct_cmd,
3051 			    fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
3052 		}
3053 		break;
3054 
3055 	default:
3056 		emlxs_fct_cmd_release(port, fct_cmd, 0);
3057 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3058 
3059 		TGTPORTSTAT.FctStray++;
3060 		TGTPORTSTAT.FctCompleted--;
3061 
3062 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3063 		    "Invalid iocb: cmd=0x%x", iocb->ULPCOMMAND);
3064 
3065 		if (pkt) {
3066 			emlxs_pkt_complete(sbp, status,
3067 			    iocb->un.grsp.perr.statLocalError, 1);
3068 		}
3069 
3070 	}	/* switch(iocb->ULPCOMMAND) */
3071 
3072 
3073 done:
3074 	if (pkt) {
3075 		emlxs_pkt_free(pkt);
3076 	}
3077 
3078 	if (status == IOSTAT_SUCCESS) {
3079 		TGTPORTSTAT.FctCmplGood++;
3080 	} else {
3081 		TGTPORTSTAT.FctCmplError++;
3082 	}
3083 
3084 	return (0);
3085 
3086 } /* emlxs_fct_handle_fcp_event() */
3087 
3088 
3089 /* ARGSUSED */
3090 extern int
3091 emlxs_fct_handle_abort(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
3092 {
3093 	emlxs_port_t *port = &PPORT;
3094 	IOCB *iocb;
3095 	emlxs_buf_t *sbp;
3096 	fc_packet_t *pkt;
3097 
3098 	iocb = &iocbq->iocb;
3099 	sbp = (emlxs_buf_t *)iocbq->sbp;
3100 
3101 	TGTPORTSTAT.FctEvent++;
3102 
3103 	if (!sbp) {
3104 		/* completion with missing xmit command */
3105 		TGTPORTSTAT.FctStray++;
3106 
3107 		/* emlxs_stray_fcp_completion_msg */
3108 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3109 		    "ABORT event cmd=%x status=%x error=%x iotag=%d",
3110 		    iocb->ULPCOMMAND, iocb->ULPSTATUS,
3111 		    iocb->un.grsp.perr.statLocalError, iocb->ULPIOTAG);
3112 
3113 		return (1);
3114 	}
3115 
3116 	pkt = PRIV2PKT(sbp);
3117 
3118 #ifdef FCT_API_TRACE
3119 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3120 	    "fct_handle_abort: %p:%p xri=%d cmd=%x status=%x",
3121 	    sbp->fct_cmd, sbp,
3122 	    iocb->ULPCONTEXT, iocb->ULPCOMMAND, iocb->ULPSTATUS);
3123 #endif /* FCT_API_TRACE */
3124 
3125 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3126 		XRIobj_t	*xrip;
3127 
3128 		emlxs_sli4_free_xri(port, NULL, sbp->xrip, 1);
3129 		xrip = emlxs_sli4_find_xri(port, iocb->ULPCONTEXT);
3130 		if (!xrip || xrip->state == XRI_STATE_FREE) {
3131 			goto exit;
3132 		}
3133 
3134 		if ((hba->fc_table[xrip->iotag]) &&
3135 		    (hba->fc_table[xrip->iotag] != STALE_PACKET)) {
3136 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
3137 			    "Cmd not aborted, retrying: xri=%d iotag=%d sbp=%p",
3138 			    xrip->XRI, xrip->iotag, hba->fc_table[xrip->iotag]);
3139 
3140 			/* Abort retry */
3141 			if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
3142 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
3143 				    "Abort retry failed xri=%x", xrip->XRI);
3144 			} else {
3145 				return (0);
3146 			}
3147 		}
3148 	}
3149 
3150 exit:
3151 	if (pkt) {
3152 		emlxs_pkt_free(pkt);
3153 	}
3154 	return (0);
3155 
3156 } /* emlxs_fct_handle_abort() */
3157 
3158 
3159 extern int
3160 emlxs_fct_handle_unsol_els(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
3161     MATCHMAP *mp, uint32_t size)
3162 {
3163 	emlxs_hba_t *hba = HBA;
3164 	IOCB *iocb;
3165 	uint32_t cmd_code;
3166 	fct_cmd_t *fct_cmd;
3167 	fct_els_t *els;
3168 	uint32_t sid;
3169 	uint32_t padding;
3170 	uint8_t *bp;
3171 	emlxs_buf_t *cmd_sbp;
3172 	uint32_t rval;
3173 
3174 	HBASTATS.ElsCmdReceived++;
3175 
3176 	bp = mp->virt;
3177 	cmd_code = (*(uint32_t *)bp) & ELS_CMD_MASK;
3178 	iocb = &iocbq->iocb;
3179 	sid = iocb->un.elsreq.remoteID;
3180 
3181 	if (!port->fct_port) {
3182 		if (!(hba->flag & FC_ONLINE_MODE)) {
3183 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3184 			    "%s: sid=%x. Adapter offline. Dropping...",
3185 			    emlxs_elscmd_xlate(cmd_code), sid);
3186 			goto done;
3187 		}
3188 
3189 		switch (cmd_code) {
3190 		case ELS_CMD_LOGO:
3191 		case ELS_CMD_PRLO:
3192 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3193 			    "%s: sid=%x. Target unbound. Accepting...",
3194 			    emlxs_elscmd_xlate(cmd_code), sid);
3195 			(void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC,
3196 			    ELS_CMD_LOGO, 0, 0);
3197 			break;
3198 		default:
3199 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3200 			    "%s: sid=%x. Target unbound. Rejecting...",
3201 			    emlxs_elscmd_xlate(cmd_code), sid);
3202 			(void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT,
3203 			    cmd_code, LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
3204 			break;
3205 		}
3206 		goto done;
3207 	}
3208 
3209 	if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
3210 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3211 		    "%s: sid=%x. Target offline. Rejecting...",
3212 		    emlxs_elscmd_xlate(cmd_code), sid);
3213 		(void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, cmd_code,
3214 		    LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
3215 
3216 		goto done;
3217 	}
3218 
3219 #ifdef FCT_API_TRACE
3220 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3221 	    "%s: sid=%x cnt=%d. Target rcv. ",
3222 	    emlxs_elscmd_xlate(cmd_code), sid, size);
3223 #endif /* FCT_API_TRACE */
3224 
3225 	/* Process the request */
3226 	switch (cmd_code) {
3227 	case ELS_CMD_FLOGI:
3228 		rval = emlxs_fct_process_unsol_flogi(port, cp, iocbq, mp, size);
3229 
3230 		if (!rval) {
3231 			ELS_PKT *els_pkt = (ELS_PKT *)bp;
3232 			fct_flogi_xchg_t fx;
3233 
3234 			bzero((uint8_t *)&fx, sizeof (fct_flogi_xchg_t));
3235 
3236 			/* Save the FLOGI exchange information */
3237 			fx.rsvd2 = iocb->ULPCONTEXT;
3238 			bcopy((caddr_t)&els_pkt->un.logi.nodeName,
3239 			    (caddr_t)fx.fx_nwwn, 8);
3240 			bcopy((caddr_t)&els_pkt->un.logi.portName,
3241 			    (caddr_t)fx.fx_pwwn, 8);
3242 			fx.fx_sid = sid;
3243 			fx.fx_did = iocb->un.elsreq.myID;
3244 			fx.fx_fport = els_pkt->un.logi.cmn.fPort;
3245 			fx.fx_op = ELS_OP_FLOGI;
3246 
3247 			emlxs_fct_handle_unsol_flogi(port, &fx, 1);
3248 		}
3249 
3250 		goto done;
3251 
3252 	case ELS_CMD_PLOGI:
3253 		rval =
3254 		    emlxs_fct_process_unsol_plogi(port, cp, iocbq, mp, size);
3255 		break;
3256 
3257 	default:
3258 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3259 		    "%s: sid=0x%x", emlxs_elscmd_xlate(cmd_code), sid);
3260 		rval = 0;
3261 		break;
3262 	}
3263 
3264 	if (rval) {
3265 		goto done;
3266 	}
3267 
3268 	padding = (8 - (size & 7)) & 7;
3269 
3270 	fct_cmd = (fct_cmd_t *)MODSYM(fct_alloc) (FCT_STRUCT_CMD_RCVD_ELS,
3271 	    (size + padding + GET_STRUCT_SIZE(emlxs_buf_t)),
3272 	    AF_FORCE_NOSLEEP);
3273 
3274 #ifdef FCT_API_TRACE
3275 	{
3276 		uint32_t *ptr = (uint32_t *)bp;
3277 
3278 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3279 		    "fct_alloc %p: ELS rcvd: rxid=%x payload: x%x x%x",
3280 		    fct_cmd, iocb->ULPCONTEXT, *ptr, *(ptr + 1));
3281 	}
3282 #endif /* FCT_API_TRACE */
3283 
3284 	if (fct_cmd == NULL) {
3285 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3286 		    "%s: sid=%x. Out of memory. Rejecting...",
3287 		    emlxs_elscmd_xlate(cmd_code), sid);
3288 
3289 		(void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, cmd_code,
3290 		    LSRJT_LOGICAL_BSY, LSEXP_OUT_OF_RESOURCE);
3291 		goto done;
3292 	}
3293 
3294 	/* Initialize fct_cmd */
3295 	fct_cmd->cmd_oxid = (cmd_code >> ELS_CMD_SHIFT) & 0xff;
3296 	fct_cmd->cmd_rxid = iocb->ULPCONTEXT;
3297 	fct_cmd->cmd_rportid = sid;
3298 	fct_cmd->cmd_lportid = port->did;
3299 	fct_cmd->cmd_rp_handle = FCT_HANDLE_NONE;
3300 	fct_cmd->cmd_port = port->fct_port;
3301 
3302 	cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_ELS_CMD_RECEIVED);
3303 	/* mutex_enter(&cmd_sbp->fct_mtx); */
3304 
3305 	/* Initialize cmd_sbp */
3306 	cmd_sbp->channel = cp;
3307 	cmd_sbp->class = iocb->ULPCLASS;
3308 	cmd_sbp->fct_type = EMLXS_FCT_ELS_CMD;
3309 	cmd_sbp->fct_flags |= EMLXS_FCT_PLOGI_RECEIVED;
3310 
3311 	bcopy((uint8_t *)iocb, (uint8_t *)&cmd_sbp->iocbq,
3312 	    sizeof (emlxs_iocb_t));
3313 
3314 	els = (fct_els_t *)fct_cmd->cmd_specific;
3315 	els->els_req_size = (uint16_t)size;
3316 	els->els_req_payload =
3317 	    GET_BYTE_OFFSET(fct_cmd->cmd_fca_private,
3318 	    GET_STRUCT_SIZE(emlxs_buf_t));
3319 	bcopy(bp, els->els_req_payload, size);
3320 
3321 
3322 	/* Check if Offline */
3323 	if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
3324 
3325 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
3326 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3327 
3328 #ifdef FCT_API_TRACE
3329 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3330 		    "fct_post_rcvd_cmd:4 %p: portid x%x", fct_cmd,
3331 		    fct_cmd->cmd_lportid);
3332 #endif /* FCT_API_TRACE */
3333 
3334 		MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
3335 
3336 		goto done;
3337 	}
3338 
3339 	/* Online */
3340 
3341 	/* Check if Link up is acked */
3342 	if (!(port->fct_flags & FCT_STATE_LINK_UP_ACKED)) {
3343 		goto defer;
3344 	}
3345 
3346 	if ((cmd_code != ELS_CMD_FLOGI) &&
3347 	    !(port->fct_flags & FCT_STATE_FLOGI_CMPL)) {
3348 		goto defer;
3349 	}
3350 
3351 	/* Post it to COMSTAR */
3352 	emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
3353 	/* mutex_exit(&cmd_sbp->fct_mtx); */
3354 
3355 #ifdef FCT_API_TRACE
3356 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3357 	    "fct_post_rcvd_cmd:1 %p: portid x%x", fct_cmd,
3358 	    fct_cmd->cmd_lportid);
3359 #endif /* FCT_API_TRACE */
3360 
3361 	MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
3362 
3363 	goto done;
3364 
3365 defer:
3366 	/* Defer processing of fct_cmd till later (after link up ack). */
3367 
3368 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3369 	    "%s: sid=%x. Defer Processing x%x.",
3370 	    emlxs_elscmd_xlate(cmd_code), sid, port->fct_flags);
3371 
3372 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_CMD_WAITQ);
3373 	/* mutex_exit(&cmd_sbp->fct_mtx); */
3374 
3375 	/* Add cmd_sbp to queue tail */
3376 	mutex_enter(&EMLXS_PORT_LOCK);
3377 
3378 	if (port->fct_wait_tail) {
3379 		port->fct_wait_tail->next = cmd_sbp;
3380 	}
3381 	port->fct_wait_tail = cmd_sbp;
3382 
3383 	if (!port->fct_wait_head) {
3384 		port->fct_wait_head = cmd_sbp;
3385 	}
3386 
3387 	mutex_exit(&EMLXS_PORT_LOCK);
3388 
3389 done:
3390 
3391 	return (0);
3392 
3393 } /* emlxs_fct_handle_unsol_els() */
3394 
3395 
3396 /* ARGSUSED */
3397 static uint32_t
3398 emlxs_fct_process_unsol_flogi(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
3399     MATCHMAP *mp, uint32_t size)
3400 {
3401 	IOCB *iocb;
3402 	char buffer[64];
3403 
3404 	buffer[0] = 0;
3405 
3406 	iocb = &iocbq->iocb;
3407 
3408 	/* Perform processing of FLOGI payload */
3409 	if (emlxs_process_unsol_flogi(port, iocbq, mp, size, buffer,
3410 	    sizeof (buffer))) {
3411 		return (1);
3412 	}
3413 
3414 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3415 	    "FLOGI: sid=0x%x xid=%x %s",
3416 	    iocb->un.elsreq.remoteID, iocb->ULPIOTAG, buffer);
3417 
3418 	return (0);
3419 
3420 } /* emlxs_fct_process_unsol_flogi() */
3421 
3422 
3423 /* ARGSUSED */
3424 static uint32_t
3425 emlxs_fct_process_unsol_plogi(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
3426     MATCHMAP *mp, uint32_t size)
3427 {
3428 	IOCB *iocb;
3429 	char buffer[64];
3430 
3431 	buffer[0] = 0;
3432 
3433 	iocb = &iocbq->iocb;
3434 
3435 	/* Perform processing of PLOGI payload */
3436 	if (emlxs_process_unsol_plogi(port, iocbq, mp, size, buffer,
3437 	    sizeof (buffer))) {
3438 		return (1);
3439 	}
3440 
3441 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3442 	    "PLOGI: sid=0x%x xid=%x %s",
3443 	    iocb->un.elsreq.remoteID, iocb->ULPIOTAG, buffer);
3444 
3445 	return (0);
3446 
3447 } /* emlxs_fct_process_unsol_plogi() */
3448 
3449 
3450 /* ARGSUSED */
3451 static emlxs_buf_t *
3452 emlxs_fct_pkt_init(emlxs_port_t *port, fct_cmd_t *fct_cmd,
3453     fc_packet_t *pkt)
3454 {
3455 	emlxs_buf_t *cmd_sbp;
3456 	emlxs_buf_t *sbp;
3457 
3458 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3459 
3460 	sbp = PKT2PRIV(pkt);
3461 	sbp->fct_cmd = cmd_sbp->fct_cmd;
3462 	sbp->node = cmd_sbp->node;
3463 	sbp->channel = cmd_sbp->channel;
3464 	sbp->did = cmd_sbp->did;
3465 	sbp->lun = cmd_sbp->lun;
3466 	sbp->class = cmd_sbp->class;
3467 	sbp->fct_type = cmd_sbp->fct_type;
3468 	sbp->fct_state = cmd_sbp->fct_state;
3469 	sbp->xrip = cmd_sbp->xrip;
3470 	sbp->iotag = cmd_sbp->iotag;
3471 
3472 	return (sbp);
3473 
3474 } /* emlxs_fct_pkt_init() */
3475 
3476 
3477 /* Mutex will be acquired */
3478 static emlxs_buf_t *
3479 emlxs_fct_cmd_init(emlxs_port_t *port, fct_cmd_t *fct_cmd, uint16_t fct_state)
3480 {
3481 	emlxs_hba_t *hba = HBA;
3482 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3483 
3484 	bzero((void *)cmd_sbp, sizeof (emlxs_buf_t));
3485 	mutex_init(&cmd_sbp->fct_mtx, NULL, MUTEX_DRIVER,
3486 	    DDI_INTR_PRI(hba->intr_arg));
3487 	mutex_init(&cmd_sbp->mtx, NULL, MUTEX_DRIVER,
3488 	    DDI_INTR_PRI(hba->intr_arg));
3489 
3490 	mutex_enter(&cmd_sbp->fct_mtx);
3491 	cmd_sbp->pkt_flags = PACKET_VALID;
3492 	cmd_sbp->port = port;
3493 	cmd_sbp->fct_cmd = fct_cmd;
3494 	cmd_sbp->node = (fct_cmd->cmd_rp) ?
3495 	    *(emlxs_node_t **)fct_cmd->cmd_rp->rp_fca_private : NULL;
3496 	cmd_sbp->iocbq.sbp = cmd_sbp;
3497 	cmd_sbp->iocbq.port = port;
3498 	cmd_sbp->did = fct_cmd->cmd_rportid;
3499 
3500 	/* Flags fct_cmd as inuse */
3501 	if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
3502 		fct_cmd->cmd_oxid = 0xffff;
3503 		fct_cmd->cmd_rxid = 0xffff;
3504 	}
3505 
3506 	if (fct_state) {
3507 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3508 	}
3509 
3510 	return (cmd_sbp);
3511 
3512 } /* emlxs_fct_cmd_init() */
3513 
3514 
3515 /* Called after receiving fct_cmd from COMSTAR */
3516 static fct_status_t
3517 emlxs_fct_cmd_accept(emlxs_port_t *port, fct_cmd_t *fct_cmd, uint16_t fct_state)
3518 {
3519 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3520 
3521 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
3522 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3523 		    "fct_cmd_accept: "
3524 		    "Invalid fct_cmd found! fct_cmd=%p state=%x",
3525 		    fct_cmd, fct_state);
3526 
3527 		return (FCT_NOT_FOUND);
3528 	}
3529 
3530 	mutex_enter(&cmd_sbp->fct_mtx);
3531 
3532 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
3533 		mutex_exit(&cmd_sbp->fct_mtx);
3534 
3535 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3536 		    "fct_cmd_accept:2 "
3537 		    "Invalid fct_cmd found! fct_cmd=%p state=%x",
3538 		    fct_cmd, fct_state);
3539 
3540 		return (FCT_NOT_FOUND);
3541 	}
3542 
3543 	if (cmd_sbp->fct_flags & EMLXS_FCT_ABORT_INP) {
3544 
3545 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3546 		    "fct_cmd_accept: "
3547 		    "Aborted fct_cmd found! fct_cmd=%p state=%x",
3548 		    fct_cmd, fct_state);
3549 
3550 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_ABORT_DONE);
3551 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3552 
3553 		MODSYM(fct_cmd_fca_aborted) (fct_cmd,
3554 		    FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
3555 
3556 		return (FCT_NOT_FOUND);
3557 	}
3558 
3559 	mutex_enter(&cmd_sbp->mtx);
3560 	if (!(cmd_sbp->pkt_flags & PACKET_ULP_OWNED)) {
3561 		mutex_exit(&cmd_sbp->mtx);
3562 		mutex_exit(&cmd_sbp->fct_mtx);
3563 
3564 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3565 		    "fct_cmd_accept: "
3566 		    "Busy fct_cmd found! fct_cmd=%p state=%x",
3567 		    fct_cmd, fct_state);
3568 
3569 		return (FCT_BUSY);
3570 	}
3571 	cmd_sbp->pkt_flags &= ~PACKET_ULP_OWNED;
3572 	mutex_exit(&cmd_sbp->mtx);
3573 
3574 	if (fct_state) {
3575 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3576 	}
3577 
3578 	return (FCT_SUCCESS);
3579 
3580 } /* emlxs_fct_cmd_accept() */
3581 
3582 
3583 /* Called after receiving fct_cmd from driver */
3584 static fct_status_t
3585 emlxs_fct_cmd_acquire(emlxs_port_t *port, fct_cmd_t *fct_cmd,
3586     uint16_t fct_state)
3587 {
3588 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3589 
3590 	if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
3591 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3592 		    "fct_cmd_acquire: "
3593 		    "Bad fct_cmd found! fct_cmd=%p state=%x",
3594 		    fct_cmd, fct_state);
3595 
3596 		return (FCT_NOT_FOUND);
3597 	}
3598 
3599 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
3600 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3601 		    "fct_cmd_acquire: "
3602 		    "Invalid fct_cmd found! fct_cmd=%p state=%x",
3603 		    fct_cmd, fct_state);
3604 
3605 		return (FCT_NOT_FOUND);
3606 	}
3607 
3608 	if ((cmd_sbp->pkt_flags & PACKET_ULP_OWNED)) {
3609 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3610 		    "fct_cmd_acquire: "
3611 		    "Returned fct_cmd found! fct_cmd=%p state=%x",
3612 		    fct_cmd, fct_state);
3613 
3614 		return (FCT_NOT_FOUND);
3615 	}
3616 
3617 	mutex_enter(&cmd_sbp->fct_mtx);
3618 
3619 	if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
3620 		mutex_exit(&cmd_sbp->fct_mtx);
3621 
3622 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3623 		    "fct_cmd_acquire:2 "
3624 		    "Bad fct_cmd found! fct_cmd=%p state=%x",
3625 		    fct_cmd, fct_state);
3626 
3627 		return (FCT_NOT_FOUND);
3628 	}
3629 
3630 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
3631 		mutex_exit(&cmd_sbp->fct_mtx);
3632 
3633 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3634 		    "fct_cmd_acquire:2 "
3635 		    "Invalid fct_cmd found! fct_cmd=%p state=%x",
3636 		    fct_cmd, fct_state);
3637 
3638 		return (FCT_NOT_FOUND);
3639 	}
3640 
3641 	if ((cmd_sbp->pkt_flags & PACKET_ULP_OWNED)) {
3642 		mutex_exit(&cmd_sbp->fct_mtx);
3643 
3644 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3645 		    "fct_cmd_acquire:2 "
3646 		    "Returned fct_cmd found! fct_cmd=%p state=%x",
3647 		    fct_cmd, fct_state);
3648 
3649 		return (FCT_NOT_FOUND);
3650 	}
3651 
3652 	if (cmd_sbp->fct_flags & EMLXS_FCT_ABORT_INP) {
3653 
3654 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3655 		    "fct_cmd_acquire: "
3656 		    "Aborting cmd. fct_cmd=%p state=%x",
3657 		    fct_cmd, fct_state);
3658 
3659 		if (fct_cmd->cmd_type == FCT_CMD_FCP_XCHG) {
3660 			TGTPORTSTAT.FctOutstandingIO--;
3661 		}
3662 
3663 		fct_cmd->cmd_comp_status = FCT_FAILURE;
3664 
3665 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_ABORT_DONE);
3666 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3667 
3668 		MODSYM(fct_cmd_fca_aborted) (fct_cmd,
3669 		    FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
3670 
3671 		return (FCT_NOT_FOUND);
3672 	}
3673 
3674 	if (fct_state) {
3675 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3676 	}
3677 
3678 	return (FCT_SUCCESS);
3679 
3680 } /* emlxs_fct_cmd_acquire() */
3681 
3682 
3683 /* cmd_sbp->fct_mtx must be held to enter */
3684 /* cmd_sbp->fct_mtx must be released before exiting */
3685 /* Called before transitionally sending fct_cmd to driver */
3686 /*ARGSUSED*/
3687 static void
3688 emlxs_fct_cmd_release(emlxs_port_t *port, fct_cmd_t *fct_cmd,
3689     uint16_t fct_state)
3690 {
3691 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3692 
3693 	if (fct_state) {
3694 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3695 	}
3696 
3697 	mutex_exit(&cmd_sbp->fct_mtx);
3698 
3699 	return;
3700 
3701 } /* emlxs_fct_cmd_release() */
3702 
3703 
3704 /* cmd_sbp->fct_mtx must be held to enter */
3705 /* cmd_sbp->fct_mtx must be released before exiting */
3706 /* Called before posting fct_cmd back to COMSTAR */
3707 /*ARGSUSED*/
3708 static void
3709 emlxs_fct_cmd_post(emlxs_port_t *port, fct_cmd_t *fct_cmd,
3710     uint16_t fct_state)
3711 {
3712 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3713 	fc_packet_t *pkt;
3714 
3715 	pkt = cmd_sbp->fct_pkt;
3716 	cmd_sbp->fct_pkt = NULL;
3717 	cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
3718 
3719 	mutex_enter(&cmd_sbp->mtx);
3720 	cmd_sbp->pkt_flags |= PACKET_ULP_OWNED;
3721 	mutex_exit(&cmd_sbp->mtx);
3722 
3723 	if (fct_state) {
3724 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3725 	}
3726 
3727 	mutex_exit(&cmd_sbp->fct_mtx);
3728 
3729 	if (pkt) {
3730 		emlxs_pkt_free(pkt);
3731 	}
3732 
3733 	return;
3734 
3735 } /* emlxs_fct_cmd_post() */
3736 
3737 
3738 /* cmd_sbp->fct_mtx must be held to enter */
3739 /* Called before completing fct_cmd back to COMSTAR */
3740 static void
3741 emlxs_fct_cmd_done(emlxs_port_t *port, fct_cmd_t *fct_cmd, uint16_t fct_state)
3742 {
3743 	emlxs_hba_t *hba = HBA;
3744 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3745 	fc_packet_t *pkt;
3746 
3747 	/* Flags fct_cmd is no longer used */
3748 	fct_cmd->cmd_oxid = 0;
3749 	fct_cmd->cmd_rxid = 0;
3750 
3751 	if (cmd_sbp->iotag != 0) {
3752 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3753 		    "Pkt still registered! channel=%p iotag=%d sbp=%p",
3754 		    cmd_sbp->channel, cmd_sbp->iotag, cmd_sbp);
3755 
3756 		if (cmd_sbp->channel) {
3757 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3758 				emlxs_sli4_free_xri(port, cmd_sbp,
3759 				    cmd_sbp->xrip, 1);
3760 			} else {
3761 				(void) emlxs_unregister_pkt(cmd_sbp->channel,
3762 				    cmd_sbp->iotag, 0);
3763 			}
3764 
3765 		}
3766 	}
3767 
3768 	pkt = cmd_sbp->fct_pkt;
3769 	cmd_sbp->fct_pkt = NULL;
3770 	cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
3771 
3772 	if (fct_state) {
3773 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3774 	}
3775 
3776 	mutex_enter(&cmd_sbp->mtx);
3777 	cmd_sbp->pkt_flags |= PACKET_ULP_OWNED;
3778 	cmd_sbp->pkt_flags &= ~PACKET_VALID;
3779 	mutex_exit(&cmd_sbp->mtx);
3780 	mutex_exit(&cmd_sbp->fct_mtx);
3781 
3782 
3783 	mutex_destroy(&cmd_sbp->fct_mtx);
3784 	mutex_destroy(&cmd_sbp->mtx);
3785 
3786 	if (pkt) {
3787 		emlxs_pkt_free(pkt);
3788 	}
3789 
3790 	return;
3791 
3792 } /* emlxs_fct_cmd_done() */
3793 
3794 
3795 static void
3796 emlxs_fct_pkt_comp(fc_packet_t *pkt)
3797 {
3798 	emlxs_port_t *port;
3799 #ifdef FMA_SUPPORT
3800 	emlxs_hba_t *hba;
3801 #endif	/* FMA_SUPPORT */
3802 	emlxs_buf_t *sbp;
3803 	emlxs_buf_t *cmd_sbp;
3804 	fct_cmd_t *fct_cmd;
3805 	fct_els_t *fct_els;
3806 	fct_sol_ct_t *fct_ct;
3807 	fct_status_t rval;
3808 
3809 	sbp = PKT2PRIV(pkt);
3810 	port = sbp->port;
3811 #ifdef FMA_SUPPORT
3812 	hba = HBA;
3813 #endif	/* FMA_SUPPORT */
3814 	fct_cmd = sbp->fct_cmd;
3815 
3816 	rval = emlxs_fct_cmd_acquire(port, fct_cmd, EMLXS_FCT_PKT_COMPLETE);
3817 	if (rval) {
3818 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3819 		    "fct_pkt_comp: "
3820 		    "Unable to reacquire fct_cmd.");
3821 		return;
3822 	}
3823 	/* mutex_enter(&cmd_sbp->fct_mtx); */
3824 
3825 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3826 	cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
3827 	cmd_sbp->fct_pkt = NULL;
3828 
3829 	switch (fct_cmd->cmd_type) {
3830 	case FCT_CMD_FCP_XCHG:
3831 		if ((pkt->pkt_reason == FC_REASON_ABORTED) ||
3832 		    (pkt->pkt_reason == FC_REASON_XCHG_DROPPED) ||
3833 		    (pkt->pkt_reason == FC_REASON_OFFLINE)) {
3834 			/*
3835 			 * The error indicates this IO should be terminated
3836 			 * immediately.
3837 			 */
3838 			cmd_sbp->fct_flags &= ~EMLXS_FCT_SEND_STATUS;
3839 
3840 			emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
3841 			/* mutex_exit(&cmd_sbp->fct_mtx); */
3842 
3843 #ifdef FCT_API_TRACE
3844 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3845 			    "fct_queue_cmd_for_termination:2 %p:%p x%x",
3846 			    fct_cmd, cmd_sbp, fct_cmd->cmd_comp_status);
3847 #endif /* FCT_API_TRACE */
3848 
3849 			MODSYM(fct_queue_cmd_for_termination) (fct_cmd,
3850 			    FCT_ABTS_RECEIVED);
3851 
3852 			break;
3853 		}
3854 
3855 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp,
3856 		    EMLXS_FCT_PKT_FCPRSP_COMPLETE);
3857 
3858 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3859 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3860 
3861 #ifdef FCT_API_TRACE
3862 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3863 		    "fct_send_response_done:2 %p:%p x%x outio %d",
3864 		    fct_cmd, cmd_sbp, fct_cmd->cmd_comp_status,
3865 		    TGTPORTSTAT.FctOutstandingIO);
3866 #else
3867 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3868 		    "fct_pkt_comp: fct_send_response_done. dbuf=%p",
3869 		    sbp->fct_buf);
3870 #endif /* FCT_API_TRACE */
3871 
3872 		TGTPORTSTAT.FctOutstandingIO--;
3873 
3874 		MODSYM(fct_send_response_done) (fct_cmd,
3875 		    fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
3876 
3877 		break;
3878 
3879 	case FCT_CMD_RCVD_ELS:
3880 
3881 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp,
3882 		    EMLXS_FCT_PKT_ELSRSP_COMPLETE);
3883 
3884 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3885 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3886 
3887 #ifdef FCT_API_TRACE
3888 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3889 		    "fct_send_response_done:3 %p:%p x%x",
3890 		    fct_cmd, cmd_sbp, fct_cmd->cmd_comp_status);
3891 #endif /* FCT_API_TRACE */
3892 
3893 		MODSYM(fct_send_response_done) (fct_cmd,
3894 		    fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
3895 
3896 		break;
3897 
3898 	case FCT_CMD_SOL_ELS:
3899 
3900 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp,
3901 		    EMLXS_FCT_PKT_ELSCMD_COMPLETE);
3902 
3903 		fct_els = (fct_els_t *)fct_cmd->cmd_specific;
3904 
3905 		if (fct_els->els_resp_payload) {
3906 			EMLXS_MPDATA_SYNC(pkt->pkt_resp_dma, 0,
3907 			    pkt->pkt_rsplen, DDI_DMA_SYNC_FORKERNEL);
3908 
3909 			bcopy((uint8_t *)pkt->pkt_resp,
3910 			    (uint8_t *)fct_els->els_resp_payload,
3911 			    fct_els->els_resp_size);
3912 		}
3913 
3914 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3915 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3916 
3917 #ifdef FCT_API_TRACE
3918 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3919 		    "fct_send_cmd_done:1 %p:%p x%x",
3920 		    fct_cmd, cmd_sbp, fct_cmd->cmd_comp_status);
3921 #endif /* FCT_API_TRACE */
3922 
3923 #ifdef FMA_SUPPORT
3924 		if (emlxs_fm_check_dma_handle(hba, pkt->pkt_resp_dma)
3925 		    != DDI_FM_OK) {
3926 			EMLXS_MSGF(EMLXS_CONTEXT,
3927 			    &emlxs_invalid_dma_handle_msg,
3928 			    "fct_pkt_comp: hdl=%p",
3929 			    pkt->pkt_resp_dma);
3930 			MODSYM(fct_send_cmd_done) (fct_cmd, FCT_FAILURE,
3931 			    FCT_IOF_FCA_DONE);
3932 
3933 			break;
3934 		}
3935 #endif /* FMA_SUPPORT */
3936 
3937 		MODSYM(fct_send_cmd_done) (fct_cmd, FCT_SUCCESS,
3938 		    FCT_IOF_FCA_DONE);
3939 
3940 		break;
3941 
3942 	case FCT_CMD_SOL_CT:
3943 
3944 		EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp,
3945 		    EMLXS_FCT_PKT_CTCMD_COMPLETE);
3946 
3947 		fct_ct = (fct_sol_ct_t *)fct_cmd->cmd_specific;
3948 
3949 		if (fct_ct->ct_resp_payload) {
3950 			EMLXS_MPDATA_SYNC(pkt->pkt_resp_dma, 0,
3951 			    pkt->pkt_rsplen, DDI_DMA_SYNC_FORKERNEL);
3952 
3953 			bcopy((uint8_t *)pkt->pkt_resp,
3954 			    (uint8_t *)fct_ct->ct_resp_payload,
3955 			    fct_ct->ct_resp_size);
3956 		}
3957 
3958 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3959 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3960 
3961 #ifdef FCT_API_TRACE
3962 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3963 		    "fct_send_cmd_done:2 %p:%p x%x",
3964 		    fct_cmd, cmd_sbp, fct_cmd->cmd_comp_status);
3965 #endif /* FCT_API_TRACE */
3966 
3967 #ifdef FMA_SUPPORT
3968 		if (emlxs_fm_check_dma_handle(hba, pkt->pkt_resp_dma)
3969 		    != DDI_FM_OK) {
3970 			EMLXS_MSGF(EMLXS_CONTEXT,
3971 			    &emlxs_invalid_dma_handle_msg,
3972 			    "fct_pkt_comp: hdl=%p",
3973 			    pkt->pkt_resp_dma);
3974 			MODSYM(fct_send_cmd_done) (fct_cmd, FCT_FAILURE,
3975 			    FCT_IOF_FCA_DONE);
3976 
3977 			break;
3978 		}
3979 #endif /* FMA_SUPPORT */
3980 		MODSYM(fct_send_cmd_done) (fct_cmd, FCT_SUCCESS,
3981 		    FCT_IOF_FCA_DONE);
3982 
3983 		break;
3984 
3985 	default:
3986 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3987 		    "fct_pkt_comp: Invalid cmd type found. type=%x",
3988 		    fct_cmd->cmd_type);
3989 
3990 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3991 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3992 
3993 		break;
3994 	}
3995 
3996 	emlxs_pkt_free(pkt);
3997 	return;
3998 
3999 } /* emlxs_fct_pkt_comp() */
4000 
4001 
4002 static void
4003 emlxs_fct_abort_pkt_comp(fc_packet_t *pkt)
4004 {
4005 #ifdef FCT_API_TRACE
4006 	emlxs_buf_t *sbp;
4007 	IOCBQ *iocbq;
4008 	IOCB *iocb;
4009 	emlxs_port_t *port;
4010 
4011 	sbp = PKT2PRIV(pkt);
4012 	port = sbp->port;
4013 	iocbq = &sbp->iocbq;
4014 	iocb = &iocbq->iocb;
4015 
4016 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4017 	    "fct_abort_pkt_comp: %p: xri=%d cmd=%x status=%x",
4018 	    sbp->fct_cmd, sbp,
4019 	    iocb->ULPCONTEXT, iocb->ULPCOMMAND, iocb->ULPSTATUS);
4020 #endif /* FCT_API_TRACE */
4021 
4022 	emlxs_pkt_free(pkt);
4023 	return;
4024 
4025 } /* emlxs_fct_abort_pkt_comp() */
4026 
4027 
4028 /* COMSTAR ENTER POINT (INDIRECT) */
4029 static fct_status_t
4030 emlxs_fct_send_els_cmd(fct_cmd_t *fct_cmd)
4031 {
4032 	emlxs_port_t *port =
4033 	    (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
4034 	emlxs_hba_t *hba = HBA;
4035 	uint32_t did;
4036 	uint32_t sid;
4037 	fct_els_t *fct_els;
4038 	fc_packet_t *pkt;
4039 	emlxs_buf_t *cmd_sbp;
4040 	fct_status_t rval;
4041 
4042 	did = fct_cmd->cmd_rportid;
4043 	sid = fct_cmd->cmd_lportid;
4044 	fct_els = (fct_els_t *)fct_cmd->cmd_specific;
4045 
4046 	if (!(pkt = emlxs_pkt_alloc(port, fct_els->els_req_size,
4047 	    fct_els->els_resp_size, 0, KM_NOSLEEP))) {
4048 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4049 		    "fct_send_els_cmd: Unable to allocate packet.");
4050 
4051 		return (FCT_BUSY);
4052 	}
4053 
4054 	cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_SEND_ELS_REQ);
4055 	/* mutex_enter(&cmd_sbp->fct_mtx); */
4056 
4057 	cmd_sbp->channel = &hba->chan[hba->channel_els];
4058 	cmd_sbp->fct_type = EMLXS_FCT_ELS_REQ;
4059 
4060 	(void) emlxs_fct_pkt_init(port, fct_cmd, pkt);
4061 	cmd_sbp->fct_pkt = pkt;
4062 
4063 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4064 	pkt->pkt_timeout =
4065 	    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
4066 	pkt->pkt_timeout = (pkt->pkt_timeout > 60)? 60: pkt->pkt_timeout;
4067 	pkt->pkt_comp = emlxs_fct_pkt_comp;
4068 
4069 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4070 	    "fct_send_els_cmd: pkt_timeout=%d ratov=%d",
4071 	    pkt->pkt_timeout, hba->fc_ratov);
4072 
4073 	/* Build the fc header */
4074 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
4075 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
4076 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(sid);
4077 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
4078 	pkt->pkt_cmd_fhdr.f_ctl =
4079 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
4080 	pkt->pkt_cmd_fhdr.seq_id = 0;
4081 	pkt->pkt_cmd_fhdr.df_ctl = 0;
4082 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
4083 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
4084 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
4085 	pkt->pkt_cmd_fhdr.ro = 0;
4086 
4087 	/* Copy the cmd payload */
4088 	bcopy((uint8_t *)fct_els->els_req_payload, (uint8_t *)pkt->pkt_cmd,
4089 	    fct_els->els_req_size);
4090 
4091 	cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
4092 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_REQ_PENDING);
4093 	/* mutex_exit(&cmd_sbp->fct_mtx); */
4094 
4095 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
4096 
4097 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4098 		    "fct_send_els_cmd: Unable to send packet.");
4099 
4100 		/* Reacquire ownership of the fct_cmd */
4101 		rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
4102 		if (rval) {
4103 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4104 			    "fct_send_els_cmd: "
4105 			    "Unable to reacquire fct_cmd.");
4106 			return (rval);
4107 		}
4108 		/* mutex_enter(&cmd_sbp->fct_mtx); */
4109 
4110 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
4111 		/* mutex_exit(&cmd_sbp->fct_mtx); */
4112 
4113 		return (FCT_BUSY);
4114 	}
4115 
4116 	return (FCT_SUCCESS);
4117 
4118 } /* emlxs_fct_send_els_cmd() */
4119 
4120 
4121 /* cmd_sbp->fct_mtx must be held to enter */
4122 /* cmd_sbp->fct_mtx must be released before exiting */
4123 static fct_status_t
4124 emlxs_fct_send_els_rsp(fct_cmd_t *fct_cmd)
4125 {
4126 	emlxs_port_t *port =
4127 	    (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
4128 	emlxs_hba_t *hba = HBA;
4129 	uint32_t did;
4130 	uint32_t sid;
4131 	fct_els_t *fct_els;
4132 	fc_packet_t *pkt;
4133 	emlxs_buf_t *cmd_sbp;
4134 	fct_status_t rval;
4135 
4136 	fct_els = (fct_els_t *)fct_cmd->cmd_specific;
4137 	did = fct_cmd->cmd_rportid;
4138 	sid = fct_cmd->cmd_lportid;
4139 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
4140 
4141 	if (!(pkt = emlxs_pkt_alloc(port, fct_els->els_resp_size, 0, 0,
4142 	    KM_NOSLEEP))) {
4143 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4144 		    "fct_send_els_rsp: Unable to allocate packet.");
4145 
4146 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
4147 		/* mutex_exit(&cmd_sbp->fct_mtx); */
4148 
4149 		return (FCT_FAILURE);
4150 	}
4151 
4152 	EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, EMLXS_FCT_SEND_ELS_RSP);
4153 
4154 	cmd_sbp->fct_type = EMLXS_FCT_ELS_RSP;
4155 
4156 	(void) emlxs_fct_pkt_init(port, fct_cmd, pkt);
4157 	cmd_sbp->fct_pkt = pkt;
4158 
4159 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
4160 	pkt->pkt_timeout =
4161 	    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
4162 	pkt->pkt_timeout = (pkt->pkt_timeout > 60)? 60: pkt->pkt_timeout;
4163 	pkt->pkt_comp = emlxs_fct_pkt_comp;
4164 
4165 	/* Build the fc header */
4166 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
4167 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_RSP;
4168 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(sid);
4169 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
4170 	pkt->pkt_cmd_fhdr.f_ctl =
4171 	    F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ;
4172 	pkt->pkt_cmd_fhdr.seq_id = 0;
4173 	pkt->pkt_cmd_fhdr.df_ctl = 0;
4174 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
4175 	pkt->pkt_cmd_fhdr.ox_id = fct_cmd->cmd_oxid;
4176 	pkt->pkt_cmd_fhdr.rx_id = fct_cmd->cmd_rxid;
4177 	pkt->pkt_cmd_fhdr.ro = 0;
4178 
4179 	/* Copy the resp payload to pkt_cmd buffer */
4180 	bcopy((uint8_t *)fct_els->els_resp_payload, (uint8_t *)pkt->pkt_cmd,
4181 	    fct_els->els_resp_size);
4182 
4183 	cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
4184 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_RSP_PENDING);
4185 	/* mutex_exit(&cmd_sbp->fct_mtx); */
4186 
4187 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
4188 
4189 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4190 		    "fct_send_els_rsp: Unable to send packet.");
4191 
4192 		/* Reacquire ownership of the fct_cmd */
4193 		rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
4194 		if (rval) {
4195 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4196 			    "fct_send_els_rsp: "
4197 			    "Unable to reacquire fct_cmd.");
4198 			return (rval);
4199 		}
4200 		/* mutex_enter(&cmd_sbp->fct_mtx); */
4201 
4202 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
4203 		/* mutex_exit(&cmd_sbp->fct_mtx); */
4204 
4205 		return (FCT_FAILURE);
4206 	}
4207 
4208 	return (FCT_SUCCESS);
4209 
4210 } /* emlxs_fct_send_els_rsp() */
4211 
4212 
4213 /* COMSTAR ENTER POINT (INDIRECT) */
4214 static fct_status_t
4215 emlxs_fct_send_ct_cmd(fct_cmd_t *fct_cmd)
4216 {
4217 	emlxs_port_t *port =
4218 	    (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
4219 	emlxs_hba_t *hba = HBA;
4220 	uint32_t did;
4221 	fct_sol_ct_t *fct_ct;
4222 	fc_packet_t *pkt;
4223 	emlxs_buf_t *cmd_sbp;
4224 	fct_status_t rval;
4225 
4226 	did = fct_cmd->cmd_rportid;
4227 	fct_ct = (fct_sol_ct_t *)fct_cmd->cmd_specific;
4228 
4229 	if (!(pkt = emlxs_pkt_alloc(port, fct_ct->ct_req_size,
4230 	    fct_ct->ct_resp_size, 0, KM_NOSLEEP))) {
4231 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4232 		    "fct_send_ct_cmd: Unable to allocate packet.");
4233 		return (FCT_BUSY);
4234 	}
4235 
4236 	cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_SEND_CT_REQ);
4237 	/* mutex_enter(&cmd_sbp->fct_mtx); */
4238 
4239 	cmd_sbp->channel = &hba->chan[hba->channel_ct];
4240 	cmd_sbp->fct_type = EMLXS_FCT_CT_REQ;
4241 
4242 	(void) emlxs_fct_pkt_init(port, fct_cmd, pkt);
4243 	cmd_sbp->fct_pkt = pkt;
4244 
4245 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4246 	pkt->pkt_timeout =
4247 	    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
4248 	pkt->pkt_timeout = (pkt->pkt_timeout > 60)? 60: pkt->pkt_timeout;
4249 	pkt->pkt_comp = emlxs_fct_pkt_comp;
4250 
4251 	/* Build the fc header */
4252 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
4253 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
4254 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
4255 	pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
4256 	pkt->pkt_cmd_fhdr.f_ctl =
4257 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
4258 	pkt->pkt_cmd_fhdr.seq_id = 0;
4259 	pkt->pkt_cmd_fhdr.df_ctl = 0;
4260 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
4261 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
4262 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
4263 	pkt->pkt_cmd_fhdr.ro = 0;
4264 
4265 	/* Copy the cmd payload */
4266 	bcopy((uint8_t *)fct_ct->ct_req_payload, (uint8_t *)pkt->pkt_cmd,
4267 	    fct_ct->ct_req_size);
4268 
4269 	cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
4270 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_REQ_PENDING);
4271 	/* mutex_exit(&cmd_sbp->fct_mtx); */
4272 
4273 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
4274 
4275 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4276 		    "fct_send_ct_cmd: Unable to send packet.");
4277 
4278 		/* Reacquire ownership of the fct_cmd */
4279 		rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
4280 		if (rval) {
4281 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4282 			    "fct_send_ct_cmd: "
4283 			    "Unable to reacquire fct_cmd.");
4284 
4285 			return (rval);
4286 		}
4287 		/* mutex_enter(&cmd_sbp->fct_mtx); */
4288 
4289 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
4290 		/* mutex_exit(&cmd_sbp->fct_mtx); */
4291 
4292 		return (FCT_BUSY);
4293 	}
4294 
4295 	return (FCT_SUCCESS);
4296 
4297 } /* emlxs_fct_send_ct_cmd() */
4298 
4299 
4300 /* cmd_sbp->fct_mtx must be held to enter */
4301 static uint32_t
4302 emlxs_fct_pkt_abort_txq(emlxs_port_t *port, emlxs_buf_t *cmd_sbp)
4303 {
4304 	emlxs_hba_t *hba = HBA;
4305 	NODELIST *nlp;
4306 	fc_packet_t *pkt;
4307 	emlxs_buf_t *sbp;
4308 	emlxs_buf_t *iocb_sbp;
4309 	uint8_t channelno;
4310 	CHANNEL *cp;
4311 	IOCBQ *iocbq;
4312 	IOCBQ *next;
4313 	IOCBQ *prev;
4314 	uint32_t found;
4315 	uint32_t pkt_flags;
4316 
4317 	/* Check the transmit queue */
4318 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
4319 
4320 	/* The IOCB could point to a cmd_sbp (no packet) or a sbp (packet) */
4321 	pkt = cmd_sbp->fct_pkt;
4322 	if (pkt) {
4323 		sbp = PKT2PRIV(pkt);
4324 		if (sbp == NULL) {
4325 			goto done;
4326 		}
4327 		iocb_sbp = sbp;
4328 		iocbq = &sbp->iocbq;
4329 		pkt_flags = sbp->pkt_flags;
4330 	} else {
4331 		sbp = NULL;
4332 		iocb_sbp = cmd_sbp;
4333 		iocbq = &cmd_sbp->iocbq;
4334 		pkt_flags = cmd_sbp->pkt_flags;
4335 	}
4336 
4337 	nlp = (NODELIST *)cmd_sbp->node;
4338 	cp = (CHANNEL *)cmd_sbp->channel;
4339 	channelno = (cp) ? cp->channelno : 0;
4340 
4341 	if (pkt_flags & PACKET_IN_TXQ) {
4342 		/* Find it on the queue */
4343 		found = 0;
4344 		if (iocbq->flag & IOCB_PRIORITY) {
4345 			/* Search the priority queue */
4346 			prev = NULL;
4347 			next = (IOCBQ *)nlp->nlp_ptx[channelno].q_first;
4348 
4349 			while (next) {
4350 				if (next == iocbq) {
4351 					/* Remove it */
4352 					if (prev) {
4353 						prev->next = iocbq->next;
4354 					}
4355 
4356 					if (nlp->nlp_ptx[channelno].q_last ==
4357 					    (void *)iocbq) {
4358 						nlp->nlp_ptx[channelno].q_last =
4359 						    (void *)prev;
4360 					}
4361 
4362 					if (nlp->nlp_ptx[channelno].q_first ==
4363 					    (void *)iocbq) {
4364 						nlp->nlp_ptx[channelno].
4365 						    q_first =
4366 						    (void *)iocbq->next;
4367 					}
4368 
4369 					nlp->nlp_ptx[channelno].q_cnt--;
4370 					iocbq->next = NULL;
4371 					found = 1;
4372 					break;
4373 				}
4374 
4375 				prev = next;
4376 				next = next->next;
4377 			}
4378 		} else {
4379 			/* Search the normal queue */
4380 			prev = NULL;
4381 			next = (IOCBQ *)nlp->nlp_tx[channelno].q_first;
4382 
4383 			while (next) {
4384 				if (next == iocbq) {
4385 					/* Remove it */
4386 					if (prev) {
4387 						prev->next = iocbq->next;
4388 					}
4389 
4390 					if (nlp->nlp_tx[channelno].q_last ==
4391 					    (void *)iocbq) {
4392 						nlp->nlp_tx[channelno].q_last =
4393 						    (void *)prev;
4394 					}
4395 
4396 					if (nlp->nlp_tx[channelno].q_first ==
4397 					    (void *)iocbq) {
4398 						nlp->nlp_tx[channelno].q_first =
4399 						    (void *)iocbq->next;
4400 					}
4401 
4402 					nlp->nlp_tx[channelno].q_cnt--;
4403 					iocbq->next = NULL;
4404 					found = 1;
4405 					break;
4406 				}
4407 
4408 				prev = next;
4409 				next = (IOCBQ *)next->next;
4410 			}
4411 		}
4412 
4413 		if (!found) {
4414 			goto done;
4415 		}
4416 
4417 		/* Check if node still needs servicing */
4418 		if ((nlp->nlp_ptx[channelno].q_first) ||
4419 		    (nlp->nlp_tx[channelno].q_first &&
4420 		    !(nlp->nlp_flag[channelno] & NLP_CLOSED))) {
4421 
4422 			/*
4423 			 * If this is the base node, don't shift the pointers
4424 			 */
4425 			/* We want to drain the base node before moving on */
4426 			if (!nlp->nlp_base) {
4427 				/* Shift channel queue pointers to next node */
4428 				cp->nodeq.q_last = (void *)nlp;
4429 				cp->nodeq.q_first = nlp->nlp_next[channelno];
4430 			}
4431 		} else {
4432 			/* Remove node from channel queue */
4433 
4434 			/* If this is the last node on list */
4435 			if (cp->nodeq.q_last == (void *)nlp) {
4436 				cp->nodeq.q_last = NULL;
4437 				cp->nodeq.q_first = NULL;
4438 				cp->nodeq.q_cnt = 0;
4439 			} else {
4440 				/* Remove node from head */
4441 				cp->nodeq.q_first = nlp->nlp_next[channelno];
4442 				((NODELIST *)cp->nodeq.q_last)->
4443 				    nlp_next[channelno] = cp->nodeq.q_first;
4444 				cp->nodeq.q_cnt--;
4445 			}
4446 
4447 			/* Clear node */
4448 			nlp->nlp_next[channelno] = NULL;
4449 		}
4450 
4451 		/* The IOCB points to iocb_sbp (no packet) or a sbp (packet) */
4452 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4453 			emlxs_sli4_free_xri(port, iocb_sbp, iocb_sbp->xrip, 1);
4454 		} else {
4455 			(void) emlxs_unregister_pkt(cp, iocb_sbp->iotag, 0);
4456 		}
4457 
4458 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
4459 
4460 		if (pkt) {
4461 			emlxs_pkt_free(pkt);
4462 			cmd_sbp->fct_pkt = NULL;
4463 		}
4464 		return (1);
4465 	}
4466 done:
4467 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
4468 	return (0);
4469 
4470 } /* emlxs_fct_pkt_abort_txq() */
4471 
4472 
4473 /* COMSTAR ENTER POINT */
4474 /* FCT_NOT_FOUND & FCT_ABORT_SUCCESS indicates IO is done */
4475 /* FCT_SUCCESS indicates abort will occur asyncronously */
4476 static fct_status_t
4477 emlxs_fct_abort(fct_local_port_t *fct_port, fct_cmd_t *fct_cmd,
4478     uint32_t flags)
4479 {
4480 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
4481 	emlxs_hba_t *hba = HBA;
4482 	emlxs_buf_t *cmd_sbp;
4483 	emlxs_buf_t *cmd_sbp2;
4484 	emlxs_buf_t *prev;
4485 	fc_packet_t *pkt;
4486 	emlxs_buf_t *sbp = NULL;
4487 	kmutex_t *fct_mtx;
4488 	uint32_t fct_state;
4489 
4490 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
4491 	fct_mtx = &cmd_sbp->fct_mtx;
4492 
4493 top:
4494 
4495 	/* Sanity check */
4496 	if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
4497 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4498 		    "fct_abort: Bad fct_cmd=%p.", fct_cmd);
4499 
4500 		return (FCT_NOT_FOUND);
4501 	}
4502 
4503 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
4504 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4505 		    "fct_abort: Pkt invalid. cmd_sbp=%p",
4506 		    cmd_sbp);
4507 
4508 		return (FCT_NOT_FOUND);
4509 	}
4510 
4511 	if (mutex_tryenter(fct_mtx) == 0) {
4512 		/*
4513 		 * This code path handles a race condition if
4514 		 * an IO completes, in emlxs_fct_handle_fcp_event(),
4515 		 * and we get an abort at the same time.
4516 		 */
4517 		delay(drv_usectohz(100000));	/* 100 msec */
4518 		goto top;
4519 	}
4520 	/* At this point, we have entered the mutex */
4521 
4522 	/* Sanity check */
4523 	if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
4524 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4525 		    "fct_abort: Bad fct_cmd=%p.", fct_cmd);
4526 
4527 		mutex_exit(fct_mtx);
4528 		return (FCT_NOT_FOUND);
4529 	}
4530 
4531 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
4532 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4533 		    "fct_abort: Pkt invalid. cmd_sbp=%p",
4534 		    cmd_sbp);
4535 
4536 		mutex_exit(fct_mtx);
4537 		return (FCT_NOT_FOUND);
4538 	}
4539 
4540 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4541 	    "fct_abort: hbastate=%x. "
4542 	    "xid=%x,%x cmd_sbp=%p fctstate=%d flags=%x,%x,%x",
4543 	    hba->state, fct_cmd->cmd_oxid, fct_cmd->cmd_rxid, cmd_sbp,
4544 	    cmd_sbp->fct_state, flags, cmd_sbp->fct_flags, cmd_sbp->pkt_flags);
4545 
4546 	if (cmd_sbp->fct_flags & EMLXS_FCT_ABORT_INP) {
4547 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cmd_sbp->channel, 0);
4548 
4549 		/* If Abort is already in progress */
4550 		mutex_exit(fct_mtx);
4551 		return (FCT_SUCCESS);
4552 	}
4553 	cmd_sbp->fct_flags |= EMLXS_FCT_ABORT_INP;
4554 
4555 	if (flags & FCT_IOF_FORCE_FCA_DONE) {
4556 		fct_cmd->cmd_handle = 0;
4557 	}
4558 
4559 	TGTPORTSTAT.FctAbortSent++;
4560 
4561 	switch (cmd_sbp->fct_state) {
4562 	/* These are currently owned by COMSTAR. */
4563 	/* They were last processed by emlxs_fct_cmd_post() */
4564 	/* We have NO exchange resources associated with this IO. */
4565 	case EMLXS_FCT_OWNED:
4566 		goto abort_done;
4567 
4568 	/* These are on the unsol waitQ in the driver */
4569 	case EMLXS_FCT_CMD_WAITQ:
4570 		/* Find and remove it */
4571 		mutex_enter(&EMLXS_PORT_LOCK);
4572 		cmd_sbp2 = port->fct_wait_head;
4573 		prev = NULL;
4574 		while (cmd_sbp2) {
4575 			if (cmd_sbp2 == cmd_sbp) {
4576 				/* Remove it */
4577 				if (prev) {
4578 					prev->next = cmd_sbp2->next;
4579 				}
4580 
4581 				if (port->fct_wait_head == cmd_sbp2) {
4582 					port->fct_wait_head = cmd_sbp2->next;
4583 				}
4584 
4585 				if (port->fct_wait_tail == cmd_sbp2) {
4586 					port->fct_wait_tail = prev;
4587 				}
4588 
4589 				cmd_sbp2->next = NULL;
4590 				break;
4591 			}
4592 			prev = cmd_sbp2;
4593 			cmd_sbp2 = cmd_sbp2->next;
4594 		}
4595 		mutex_exit(&EMLXS_PORT_LOCK);
4596 
4597 		/*FALLTHROUGH*/
4598 
4599 	/* These are currently owned by COMSTAR. */
4600 	/* They were last processed by emlxs_fct_cmd_post() */
4601 	/* We have residual exchange resources associated with this IO */
4602 	case EMLXS_FCT_CMD_POSTED:
4603 		switch (fct_cmd->cmd_type) {
4604 		case FCT_CMD_FCP_XCHG: /* Unsol */
4605 			TGTPORTSTAT.FctOutstandingIO--;
4606 			emlxs_abort_fct_exchange(hba, port, fct_cmd->cmd_rxid);
4607 			break;
4608 
4609 		case FCT_CMD_RCVD_ELS: /* Unsol */
4610 			emlxs_abort_els_exchange(hba, port, fct_cmd->cmd_rxid);
4611 			break;
4612 		}
4613 
4614 		goto abort_done;
4615 
4616 	/* These are active in the driver */
4617 	/* They were last processed by emlxs_fct_cmd_release() */
4618 	case EMLXS_FCT_RSP_PENDING:
4619 	case EMLXS_FCT_REQ_PENDING:
4620 	case EMLXS_FCT_REG_PENDING:
4621 	case EMLXS_FCT_DATA_PENDING:
4622 	case EMLXS_FCT_STATUS_PENDING:
4623 
4624 		/* Abort anything pending */
4625 		if (emlxs_fct_pkt_abort_txq(port, cmd_sbp)) {
4626 
4627 			if (fct_cmd->cmd_type == FCT_CMD_FCP_XCHG) {
4628 				TGTPORTSTAT.FctOutstandingIO--;
4629 			}
4630 
4631 			goto abort_done;
4632 		}
4633 
4634 		/* If we're not online, then all IO will be flushed anyway */
4635 		if (!(hba->flag & FC_ONLINE_MODE)) {
4636 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4637 			    "fct_abort: Not online. fct_cmd=%p.",
4638 			    fct_cmd);
4639 
4640 			emlxs_fct_cmd_release(port, fct_cmd, 0);
4641 			/* mutex_exit(&cmd_sbp->fct_mtx); */
4642 
4643 			/* The cmd will be aborted on the */
4644 			/* next emlxs_fct_cmd_acquire */
4645 			/* because EMLXS_FCT_ABORT_INP is set. */
4646 			break;
4647 		}
4648 
4649 		/* Try to send abort request */
4650 		if (!(pkt = emlxs_pkt_alloc(port, 0, 0, 0, KM_NOSLEEP))) {
4651 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4652 			    "fct_abort: Unable to allocate packet. "
4653 			    "fct_cmd=%p",
4654 			    fct_cmd);
4655 
4656 			emlxs_fct_cmd_release(port, fct_cmd, 0);
4657 			/* mutex_exit(&cmd_sbp->fct_mtx); */
4658 
4659 			/* The cmd will be aborted on the */
4660 			/* next emlxs_fct_cmd_acquire anyway */
4661 			/* because EMLXS_FCT_ABORT_INP is set. */
4662 			break;
4663 		}
4664 
4665 		sbp = emlxs_fct_pkt_init(port, fct_cmd, pkt);
4666 
4667 		pkt->pkt_tran_type = FC_PKT_OUTBOUND;
4668 		pkt->pkt_timeout =
4669 		    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
4670 		pkt->pkt_comp = emlxs_fct_abort_pkt_comp;
4671 
4672 		/* Build the fc header */
4673 		pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(fct_cmd->cmd_rportid);
4674 		pkt->pkt_cmd_fhdr.r_ctl = R_CTL_STATUS;
4675 		pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
4676 		pkt->pkt_cmd_fhdr.type = FC_TYPE_BASIC_LS;
4677 		pkt->pkt_cmd_fhdr.f_ctl =
4678 		    (F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ);
4679 		pkt->pkt_cmd_fhdr.seq_id = 0;
4680 		pkt->pkt_cmd_fhdr.df_ctl = 0;
4681 		pkt->pkt_cmd_fhdr.seq_cnt = 0;
4682 		pkt->pkt_cmd_fhdr.ox_id = fct_cmd->cmd_oxid;
4683 		pkt->pkt_cmd_fhdr.rx_id = fct_cmd->cmd_rxid;
4684 		pkt->pkt_cmd_fhdr.ro = 0;
4685 
4686 		/* Make sure xrip is setup */
4687 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4688 			if (!sbp->xrip || sbp->xrip->state == XRI_STATE_FREE) {
4689 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4690 				    "fct_abort: "
4691 				    "Unable to acquire xri. (xid:%x,%x)",
4692 				    fct_cmd->cmd_oxid, fct_cmd->cmd_rxid);
4693 
4694 				emlxs_pkt_free(pkt);
4695 				return (FCT_NOT_FOUND);
4696 			}
4697 		}
4698 
4699 		cmd_sbp->fct_cmd = fct_cmd;
4700 		cmd_sbp->abort_attempts++;
4701 
4702 		/* Now disassociate the sbp / pkt from the fct_cmd */
4703 		sbp->fct_cmd = NULL;
4704 
4705 		if (hba->state >= FC_LINK_UP) {
4706 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4707 			    "fct_abort: ABORT: %p xid:%x,%x",
4708 			    fct_cmd, fct_cmd->cmd_oxid, fct_cmd->cmd_rxid);
4709 
4710 			fct_state = EMLXS_FCT_ABORT_PENDING;
4711 
4712 		} else {
4713 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4714 			    "fct_abort: CLOSE: %p xid:%x,%x",
4715 			    fct_cmd, fct_cmd->cmd_oxid, fct_cmd->cmd_rxid);
4716 
4717 			fct_state = EMLXS_FCT_CLOSE_PENDING;
4718 		}
4719 
4720 		emlxs_fct_cmd_release(port, fct_cmd, fct_state);
4721 		/* mutex_exit(&cmd_sbp->fct_mtx); */
4722 
4723 		if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
4724 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4725 			    "fct_abort: Unable to send abort packet.");
4726 
4727 			emlxs_pkt_free(pkt);
4728 
4729 			/* The cmd will be aborted on the */
4730 			/* next emlxs_fct_cmd_acquire anyway */
4731 			/* because EMLXS_FCT_ABORT_INP is set. */
4732 		}
4733 
4734 		break;
4735 
4736 	default:
4737 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4738 		    "fct_abort: Unexpected fct_state. "
4739 		    "fct_cmd=%p state=%d",
4740 		    fct_cmd, cmd_sbp->fct_state);
4741 
4742 		emlxs_fct_cmd_release(port, fct_cmd, 0);
4743 		/* mutex_exit(&cmd_sbp->fct_mtx); */
4744 
4745 		/* The cmd will be aborted on the */
4746 		/* next emlxs_fct_cmd_acquire anyway */
4747 		/* because EMLXS_FCT_ABORT_INP is set. */
4748 
4749 	}	/* switch */
4750 
4751 	return (FCT_SUCCESS);
4752 
4753 abort_done:
4754 
4755 	emlxs_fct_cmd_done(port, fct_cmd,
4756 	    EMLXS_FCT_ABORT_DONE);
4757 	/* mutex_exit(&cmd_sbp->fct_mtx); */
4758 
4759 	return (FCT_ABORT_SUCCESS);
4760 
4761 } /* emlxs_fct_abort() */
4762 
4763 
4764 extern void
4765 emlxs_fct_link_up(emlxs_port_t *port)
4766 {
4767 	emlxs_hba_t *hba = HBA;
4768 
4769 	mutex_enter(&EMLXS_PORT_LOCK);
4770 #ifdef FCT_API_TRACE
4771 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4772 	    "fct_link_up port %p fct flags x%x",
4773 	    port->fct_port, port->fct_flags);
4774 #endif /* FCT_API_TRACE */
4775 
4776 	if (port->fct_port &&
4777 	    (port->fct_flags & FCT_STATE_PORT_ONLINE) &&
4778 	    !(port->fct_flags & FCT_STATE_LINK_UP)) {
4779 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4780 		    "fct_link_up event.");
4781 
4782 		port->fct_flags &= ~FCT_STATE_LINK_UP_ACKED;
4783 		port->fct_flags &= ~FCT_STATE_FLOGI_CMPL;
4784 		port->fct_flags |= FCT_STATE_LINK_UP;
4785 		mutex_exit(&EMLXS_PORT_LOCK);
4786 
4787 #ifdef FCT_API_TRACE
4788 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4789 		    "fct_handle_event LINK_UP");
4790 #endif /* FCT_API_TRACE */
4791 		MODSYM(fct_handle_event) (port->fct_port, FCT_EVENT_LINK_UP,
4792 		    0, 0);
4793 	} else if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
4794 		mutex_exit(&EMLXS_PORT_LOCK);
4795 
4796 		if (port->vpi == 0) {
4797 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4798 			    "fct_link_up event. FCT port offline (%x). "
4799 			    "Disable link.",
4800 			    port->fct_flags);
4801 
4802 			/* Take link down and hold it down */
4803 			(void) emlxs_reset_link(hba, 0, 1);
4804 		} else {
4805 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4806 			    "fct_link_up event. FCT port offline (%x).",
4807 			    port->fct_flags);
4808 		}
4809 	} else {
4810 		mutex_exit(&EMLXS_PORT_LOCK);
4811 	}
4812 
4813 	return;
4814 
4815 } /* emlxs_fct_link_up() */
4816 
4817 
4818 extern void
4819 emlxs_fct_link_down(emlxs_port_t *port)
4820 {
4821 	emlxs_hba_t *hba = HBA;
4822 
4823 	mutex_enter(&EMLXS_PORT_LOCK);
4824 #ifdef FCT_API_TRACE
4825 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4826 	    "fct_link_down port %p fct flags x%x",
4827 	    port->fct_port, port->fct_flags);
4828 #endif /* FCT_API_TRACE */
4829 
4830 	if (port->fct_port &&
4831 	    (port->fct_flags & FCT_STATE_PORT_ONLINE) &&
4832 	    (port->fct_flags & FCT_STATE_LINK_UP)) {
4833 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4834 		    "fct_link_down event.");
4835 
4836 		port->fct_flags &= ~FCT_STATE_LINK_UP_ACKED;
4837 		port->fct_flags &= ~FCT_STATE_FLOGI_CMPL;
4838 		port->fct_flags &= ~FCT_STATE_LINK_UP;
4839 		mutex_exit(&EMLXS_PORT_LOCK);
4840 
4841 #ifdef FCT_API_TRACE
4842 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4843 		    "fct_handle_event LINK_DOWN");
4844 #endif /* FCT_API_TRACE */
4845 
4846 		MODSYM(fct_handle_event) (port->fct_port, FCT_EVENT_LINK_DOWN,
4847 		    0, 0);
4848 	} else {
4849 		mutex_exit(&EMLXS_PORT_LOCK);
4850 	}
4851 
4852 	return;
4853 
4854 } /* emlxs_fct_link_down() */
4855 
4856 
4857 void
4858 emlxs_abort_fct_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4859 {
4860 	CHANNEL *cp;
4861 	IOCBQ *iocbq;
4862 	IOCB *iocb;
4863 
4864 	if (rxid == 0 || rxid == 0xFFFF) {
4865 		return;
4866 	}
4867 
4868 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4869 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4870 		    "Aborting FCT exchange: xid=%x", rxid);
4871 
4872 		if (emlxs_sli4_unreserve_xri(port, rxid, 1) == 0) {
4873 			/* We have no way to abort unsolicited exchanges */
4874 			/* that we have not responded to at this time */
4875 			/* So we will return for now */
4876 			return;
4877 		}
4878 	}
4879 
4880 	cp = &hba->chan[hba->channel_fcp];
4881 
4882 	mutex_enter(&EMLXS_FCTAB_LOCK);
4883 
4884 	/* Create the abort IOCB */
4885 	if (hba->state >= FC_LINK_UP) {
4886 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4887 		    CLASS3, ABORT_TYPE_ABTS);
4888 	} else {
4889 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4890 	}
4891 
4892 	mutex_exit(&EMLXS_FCTAB_LOCK);
4893 
4894 	if (iocbq) {
4895 		iocb = &iocbq->iocb;
4896 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4897 		    "Aborting FCT exchange: xid=%x iotag=%d", rxid,
4898 		    iocb->ULPIOTAG);
4899 
4900 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4901 	}
4902 
4903 } /* emlxs_abort_fct_exchange() */
4904 
4905 
4906 extern uint32_t
4907 emlxs_fct_stmf_alloc(emlxs_hba_t *hba, MATCHMAP *mp)
4908 {
4909 	emlxs_port_t *port = &PPORT;
4910 	stmf_data_buf_t *db;
4911 
4912 	if (mp->tag < MEM_FCTSEG) {
4913 		return (0);
4914 	}
4915 
4916 	db = MODSYM(stmf_alloc) (STMF_STRUCT_DATA_BUF, 0, 0);
4917 
4918 #ifdef FCT_API_TRACE
4919 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4920 	    "stmf_alloc:%p iotag=%d phys %p virt %p sz %d",
4921 	    db, mp->tag, mp->phys, mp->virt, mp->size);
4922 #endif /* FCT_API_TRACE */
4923 
4924 	if (db == NULL) {
4925 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4926 		    "emlxs_fct_stmf_alloc: alloc failed.");
4927 		return (1);
4928 	}
4929 
4930 	db->db_port_private = (void*)mp;
4931 	db->db_sglist[0].seg_addr = mp->virt;
4932 	db->db_sglist[0].seg_length = mp->size;
4933 	db->db_buf_size = mp->size;
4934 	db->db_sglist_length = 1;
4935 
4936 	mp->fct_private = (void*)db;
4937 
4938 	return (0);
4939 
4940 } /* emlxs_fct_stmf_alloc() */
4941 
4942 
4943 /* ARGSUSED */
4944 extern void
4945 emlxs_fct_stmf_free(emlxs_hba_t *hba, MATCHMAP *mp)
4946 {
4947 #ifdef FCT_API_TRACE
4948 	emlxs_port_t *port = &PPORT;
4949 #endif /* FCT_API_TRACE */
4950 	stmf_data_buf_t *db;
4951 
4952 	if (mp->tag < MEM_FCTSEG) {
4953 		return;
4954 	}
4955 
4956 	db = (stmf_data_buf_t *)mp->fct_private;
4957 	mp->fct_private = NULL;
4958 
4959 	if (db == NULL) {
4960 		return;
4961 	}
4962 
4963 #ifdef FCT_API_TRACE
4964 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4965 	    "stmf_free:%p iotag=%d",
4966 	    db, mp->tag);
4967 #endif /* FCT_API_TRACE */
4968 
4969 	MODSYM(stmf_free) (db);
4970 
4971 	return;
4972 
4973 } /* emlxs_fct_stmf_free() */
4974 
4975 
4976 static void
4977 emlxs_fct_memseg_init(emlxs_hba_t *hba)
4978 {
4979 	emlxs_port_t *port = &PPORT;
4980 	char **arrayp = NULL;
4981 	uint32_t cnt = 0;
4982 	char buf[32];
4983 	uint32_t rval;
4984 	uint8_t *datap;
4985 	int i;
4986 	int j;
4987 	int fct_memseg_cnt = 0;
4988 	int numblks;
4989 	int memsize;
4990 	emlxs_memseg_t *fct_memseg = NULL;
4991 	uint32_t fct_memseg_size = 0;
4992 	emlxs_memseg_t *current;
4993 	emlxs_memseg_t *next;
4994 	emlxs_memseg_t *seg;
4995 
4996 	port->fct_memseg = NULL;
4997 	port->fct_memseg_cnt = 0;
4998 
4999 	/* Check for the per adapter setting */
5000 	(void) snprintf(buf, sizeof (buf), "%s%d-fct-bufpool", DRIVER_NAME,
5001 	    hba->ddiinst);
5002 	rval = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, hba->dip,
5003 	    (DDI_PROP_DONTPASS), buf, &arrayp, &cnt);
5004 
5005 	if ((rval != DDI_PROP_SUCCESS) || !cnt || !arrayp) {
5006 		/* Check for the global setting */
5007 		cnt = 0;
5008 		arrayp = NULL;
5009 		rval = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, hba->dip,
5010 		    (DDI_PROP_DONTPASS), "fct-bufpool", &arrayp, &cnt);
5011 	}
5012 
5013 	if ((rval != DDI_PROP_SUCCESS) || !cnt || !arrayp) {
5014 		goto default_config;
5015 	}
5016 
5017 	fct_memseg_size = cnt * sizeof (emlxs_memseg_t);
5018 	fct_memseg = kmem_zalloc(fct_memseg_size, KM_SLEEP);
5019 
5020 	if (!fct_memseg) {
5021 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5022 		    "Unable to alloc fct_memseg. cnt=%d. "
5023 		    "Trying default config.",
5024 		    cnt);
5025 		goto default_config;
5026 	}
5027 
5028 	for (i = 0; i < cnt; i++) {
5029 		datap = (uint8_t *)arrayp[i];
5030 		if (datap == 0) {
5031 			break;
5032 		}
5033 
5034 		while (*datap == ' ') {	/* Skip spaces */
5035 			datap++;
5036 		}
5037 
5038 		memsize = emlxs_str_atoi(datap);
5039 
5040 		while ((*datap != ':') && (*datap != 0)) {
5041 			datap++;
5042 		}
5043 		if (*datap == ':') { /* Skip past delimeter */
5044 			datap++;
5045 		}
5046 		while (*datap == ' ') { /* Skip spaces */
5047 			datap++;
5048 		}
5049 
5050 		numblks = emlxs_str_atoi(datap);
5051 
5052 		/* Check for a bad entry */
5053 		if (!memsize || !numblks) {
5054 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5055 			    "fct-bufpool: Entry %d:%d. Invalid.",
5056 			    memsize, numblks);
5057 			continue;
5058 		}
5059 
5060 		fct_memseg[fct_memseg_cnt].fc_memsize = memsize;
5061 		fct_memseg[fct_memseg_cnt].fc_numblks = numblks;
5062 		fct_memseg_cnt++;
5063 
5064 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5065 		    "fct-bufpool: Entry:%d  %d:%d",
5066 		    fct_memseg_cnt, memsize, numblks);
5067 	}
5068 
5069 	if (!fct_memseg_cnt) {
5070 		kmem_free(fct_memseg, fct_memseg_size);
5071 		fct_memseg_size = 0;
5072 		fct_memseg = NULL;
5073 	}
5074 
5075 default_config:
5076 	/* If buffer list is empty, setup defaults */
5077 	if (!fct_memseg) {
5078 
5079 		fct_memseg_size = 8 * sizeof (emlxs_memseg_t);
5080 		fct_memseg = kmem_zalloc(fct_memseg_size, KM_SLEEP);
5081 
5082 		if (!fct_memseg) {
5083 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5084 			    "Unable to alloc default port buffer pool. "
5085 			    "fct_memseg_cnt=%d",
5086 			    cnt);
5087 			return;
5088 		}
5089 
5090 		i = 0;
5091 		numblks = FCT_BUF_COUNT_2K;
5092 		if (numblks) {
5093 			fct_memseg[i].fc_memsize = 2 * 1024;
5094 			fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_2K;
5095 		}
5096 		numblks = FCT_BUF_COUNT_4K;
5097 		if (numblks) {
5098 			fct_memseg[i].fc_memsize = 4 * 1024;
5099 			fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_4K;
5100 		}
5101 		numblks = FCT_BUF_COUNT_8K;
5102 		if (numblks) {
5103 			fct_memseg[i].fc_memsize = 8 * 1024;
5104 			fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_8K;
5105 		}
5106 		numblks = FCT_BUF_COUNT_16K;
5107 		if (numblks) {
5108 			fct_memseg[i].fc_memsize = 16 * 1024;
5109 			fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_16K;
5110 		}
5111 		numblks = FCT_BUF_COUNT_32K;
5112 		if (numblks) {
5113 			fct_memseg[i].fc_memsize = 32 * 1024;
5114 			fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_32K;
5115 		}
5116 		numblks = FCT_BUF_COUNT_64K;
5117 		if (numblks) {
5118 			fct_memseg[i].fc_memsize = 64 * 1024;
5119 			fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_64K;
5120 		}
5121 		numblks = FCT_BUF_COUNT_128K;
5122 		if (numblks) {
5123 			fct_memseg[i].fc_memsize = 128 * 1024;
5124 			fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_128K;
5125 		}
5126 		numblks = FCT_BUF_COUNT_256K;
5127 		if (numblks) {
5128 			fct_memseg[i].fc_memsize = 256 * 1024;
5129 			fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_256K;
5130 		}
5131 		fct_memseg_cnt = i;
5132 	}
5133 
5134 	port->fct_memseg = kmem_zalloc((fct_memseg_cnt *
5135 	    sizeof (emlxs_memseg_t)), KM_SLEEP);
5136 
5137 	if (!port->fct_memseg) {
5138 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5139 		    "Unable to alloc port buffer pool. fct_memseg_cnt=%d",
5140 		    fct_memseg_cnt);
5141 		kmem_free(fct_memseg, fct_memseg_size);
5142 		return;
5143 	}
5144 
5145 	/* Initalize port bucket list */
5146 	port->fct_memseg_cnt = fct_memseg_cnt;
5147 
5148 	/* Sort the entries smallest to largest */
5149 	seg = port->fct_memseg;
5150 	for (i = 0; i < fct_memseg_cnt; i++, seg++) {
5151 
5152 		/* Find next smallest buffer */
5153 		current = fct_memseg;
5154 		next = NULL;
5155 		for (j = 0; j < fct_memseg_cnt; j++, current++) {
5156 			if (current->fc_memsize == 0) {
5157 				continue;
5158 			}
5159 
5160 			if (next == NULL) {
5161 				next = current;
5162 				continue;
5163 			}
5164 
5165 			if (current->fc_memsize < next->fc_memsize) {
5166 				next = current;
5167 			}
5168 		}
5169 
5170 		/* Save next entry */
5171 		seg->fc_memsize = next->fc_memsize;
5172 		seg->fc_numblks = next->fc_numblks;
5173 		next->fc_memsize = 0;
5174 		next->fc_numblks = 0;
5175 	}
5176 
5177 	kmem_free(fct_memseg, fct_memseg_size);
5178 
5179 	/* Complete the initialization */
5180 	seg = port->fct_memseg;
5181 	for (i = 0; i < port->fct_memseg_cnt; i++, seg++) {
5182 /*		seg->fc_memsize = ; Already setup */
5183 /*		seg->fc_numblks = ; Already setup */
5184 
5185 		(void) snprintf(seg->fc_label, sizeof (seg->fc_label),
5186 		    "FCT_DMEM_%d", seg->fc_memsize);
5187 
5188 		seg->fc_memtag   = MEM_FCTSEG + i;
5189 		seg->fc_memflag  = FC_MBUF_DMA | FC_MBUF_SNGLSG;
5190 		seg->fc_memalign = 32;
5191 		seg->fc_hi_water = 0xFFFF;
5192 		seg->fc_lo_water = seg->fc_numblks;
5193 		seg->fc_numblks  = 0;
5194 		seg->fc_step = 1;
5195 	}
5196 
5197 	return;
5198 
5199 } /* emlxs_fct_memseg_init() */
5200 
5201 
5202 fct_status_t
5203 emlxs_fct_dmem_init(emlxs_port_t *port)
5204 {
5205 	emlxs_hba_t *hba = HBA;
5206 	emlxs_memseg_t *seg;
5207 	int32_t i;
5208 
5209 	/* Initialize the fct memseg list */
5210 	emlxs_fct_memseg_init(hba);
5211 
5212 	if (!port->fct_memseg || !port->fct_memseg_cnt) {
5213 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5214 		    "fct_dmem_init: fct_memseg list is empty.");
5215 		return (FCT_FAILURE);
5216 	}
5217 
5218 	/* Create the DMA buffer pools */
5219 	seg = port->fct_memseg;
5220 	for (i = 0; i < port->fct_memseg_cnt; i++, seg++) {
5221 
5222 		(void) emlxs_mem_pool_create(hba, seg);
5223 
5224 		if (seg->fc_numblks < seg->fc_lo_water) {
5225 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
5226 			    "%s: count=%d size=%d flags=%x lo=%d hi=%d",
5227 			    seg->fc_label, seg->fc_numblks,
5228 			    seg->fc_memsize, seg->fc_memflag, seg->fc_lo_water,
5229 			    seg->fc_hi_water);
5230 		}
5231 	}
5232 
5233 	return (FCT_SUCCESS);
5234 
5235 } /* emlxs_fct_dmem_init */
5236 
5237 
5238 void
5239 emlxs_fct_dmem_fini(emlxs_port_t *port)
5240 {
5241 	emlxs_hba_t *hba = HBA;
5242 	emlxs_memseg_t *seg;
5243 	int32_t i;
5244 
5245 	if (!port->fct_memseg || !port->fct_memseg_cnt) {
5246 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5247 		    "fct_dmem_fini: fct_memseg list is empty.");
5248 		return;
5249 	}
5250 
5251 	/* Destroy the dmem buffer pools */
5252 	seg = port->fct_memseg;
5253 	for (i = 0; i < port->fct_memseg_cnt; i++, seg++) {
5254 		(void) emlxs_mem_pool_destroy(hba, seg);
5255 	}
5256 
5257 	/* Clear the segment space */
5258 	kmem_free(port->fct_memseg,
5259 	    (port->fct_memseg_cnt * sizeof (emlxs_memseg_t)));
5260 
5261 	port->fct_memseg = 0;
5262 	port->fct_memseg_cnt = 0;
5263 
5264 	return;
5265 
5266 } /* emlxs_fct_dmem_fini */
5267 
5268 
5269 /* COMSTAR ENTER POINT */
5270 /*ARGSUSED*/
5271 static stmf_data_buf_t *
5272 emlxs_fct_dbuf_alloc(fct_local_port_t *fct_port, uint32_t size,
5273     uint32_t *pminsize, uint32_t flags)
5274 {
5275 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
5276 	emlxs_hba_t *hba = HBA;
5277 	emlxs_memseg_t *seg;
5278 	stmf_data_buf_t *db;
5279 	MATCHMAP *mp;
5280 	int i;
5281 	uint32_t minsize = 0;
5282 
5283 	if (!port->fct_memseg || !port->fct_memseg_cnt) {
5284 		goto failed;
5285 	}
5286 
5287 	/* Check if our largest buffer is too small */
5288 	seg = &port->fct_memseg[port->fct_memseg_cnt-1];
5289 	if (size > seg->fc_memsize) {
5290 		goto partial_alloc;
5291 	}
5292 
5293 	/* Find smallest available buffer >= size */
5294 	seg = port->fct_memseg;
5295 	for (i = 0; i < port->fct_memseg_cnt; i++, seg++) {
5296 		if (seg->fc_memsize < size) {
5297 			continue;
5298 		}
5299 
5300 		mp = (MATCHMAP*)emlxs_mem_pool_get(hba, seg);
5301 
5302 		if (mp) {
5303 			goto success;
5304 		}
5305 	}
5306 
5307 	seg = &port->fct_memseg[port->fct_memseg_cnt-1];
5308 
5309 partial_alloc:
5310 	/* Find largest available buffer >= *pminsize */
5311 	for (i = port->fct_memseg_cnt-1; i >= 0; i--, seg--) {
5312 		if (seg->fc_memsize < *pminsize) {
5313 			minsize = seg->fc_memsize;
5314 			goto failed;
5315 		}
5316 
5317 		mp = (MATCHMAP*)emlxs_mem_pool_get(hba, seg);
5318 
5319 		if (mp) {
5320 			goto success;
5321 		}
5322 	}
5323 
5324 failed:
5325 	*pminsize = minsize;
5326 	TGTPORTSTAT.FctNoBuffer++;
5327 
5328 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5329 	    "fct_dbuf_alloc:Failed. size=%d minsize=%d",
5330 	    size, *pminsize);
5331 
5332 	return (NULL);
5333 
5334 success:
5335 	/* Setup the data buffer */
5336 	db = (stmf_data_buf_t *)mp->fct_private;
5337 	db->db_data_size = min(size, mp->size);
5338 
5339 #ifdef FCT_API_TRACE
5340 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5341 	    "fct_dbuf_alloc:%p iotag=%d size=%d,%d",
5342 	    db, mp->tag, size,  mp->size);
5343 #endif /* FCT_API_TRACE */
5344 
5345 	return (db);
5346 
5347 } /* emlxs_fct_dbuf_alloc() */
5348 
5349 
5350 /* COMSTAR ENTER POINT */
5351 /*ARGSUSED*/
5352 static void
5353 emlxs_fct_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *db)
5354 {
5355 	emlxs_port_t *port = (emlxs_port_t *)fds->fds_fca_private;
5356 	emlxs_hba_t *hba = HBA;
5357 	MATCHMAP *mp = (MATCHMAP *)db->db_port_private;
5358 
5359 	if (!mp) {
5360 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5361 		    "fct_dbuf_free:%p  NULL mp found!",
5362 		    db);
5363 		return;
5364 	}
5365 
5366 #ifdef FCT_API_TRACE
5367 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5368 	    "fct_dbuf_free:%p iotag=%d",
5369 	    db, mp->tag);
5370 #endif /* FCT_API_TRACE */
5371 
5372 	emlxs_mem_pool_put(hba, mp->segment, (void *)mp);
5373 
5374 } /* emlxs_fct_dbuf_free() */
5375 
5376 
5377 static int
5378 emlxs_fct_dbuf_dma_sync(emlxs_hba_t *hba, stmf_data_buf_t *db,
5379     uint_t sync_type)
5380 {
5381 	emlxs_port_t *port = &PPORT;
5382 	MATCHMAP *mp = (MATCHMAP *)db->db_port_private;
5383 
5384 	if (!mp) {
5385 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5386 		    "fct_dbuf_dma_sync:%p  NULL mp found!",
5387 		    db);
5388 		return (0);
5389 	}
5390 
5391 #ifdef FCT_API_TRACE
5392 {
5393 	char buf[16];
5394 
5395 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5396 	    "fct_dbuf_dma_sync:%p iotag=%d size=%d",
5397 	    db, mp->tag, db->db_data_size);
5398 
5399 	(void) snprintf(buf, sizeof (buf), "TAG%d:", mp->tag);
5400 	emlxs_data_dump(port, buf, (uint32_t *)db->db_sglist[0].seg_addr,
5401 	    36, 0);
5402 }
5403 #endif /* FCT_API_TRACE */
5404 
5405 	EMLXS_MPDATA_SYNC(mp->dma_handle, 0, db->db_data_size, sync_type);
5406 
5407 #ifdef FMA_SUPPORT
5408 	if (emlxs_fm_check_dma_handle(hba, mp->dma_handle)
5409 	    != DDI_FM_OK) {
5410 		EMLXS_MSGF(EMLXS_CONTEXT,
5411 		    &emlxs_invalid_dma_handle_msg,
5412 		    "fct_dbuf_dma_sync:%p iotag=%d",
5413 		    db, mp->tag);
5414 		return (1);
5415 	}
5416 #endif  /* FMA_SUPPORT */
5417 
5418 	return (0);
5419 
5420 } /* emlxs_fct_dbuf_dma_sync() */
5421 
5422 #endif /* SFCT_SUPPORT */
5423