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