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