1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at
9  * http://www.opensource.org/licenses/cddl1.txt.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2004-2012 Emulex. All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2020 RackTop Systems, Inc.
26  */
27 
28 #include <emlxs.h>
29 
30 #ifdef SFCT_SUPPORT
31 
32 
33 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
34 EMLXS_MSG_DEF(EMLXS_FCT_C);
35 
36 static void emlxs_fct_memseg_init(emlxs_hba_t *hba);
37 
38 static fct_status_t emlxs_fct_cmd_acquire(emlxs_port_t *port,
39 	fct_cmd_t *fct_cmd, uint16_t fct_state);
40 static fct_status_t emlxs_fct_cmd_accept(emlxs_port_t *port,
41 	fct_cmd_t *fct_cmd, uint16_t fct_state);
42 static void emlxs_fct_cmd_release(emlxs_port_t *port, fct_cmd_t *fct_cmd,
43 	uint16_t fct_state);
44 
45 static emlxs_buf_t *emlxs_fct_cmd_init(emlxs_port_t *port,
46     fct_cmd_t *fct_cmd, uint16_t fct_state);
47 static void emlxs_fct_cmd_done(emlxs_port_t *port, fct_cmd_t *fct_cmd,
48 	uint16_t fct_state);
49 static void emlxs_fct_cmd_post(emlxs_port_t *port, fct_cmd_t *fct_cmd,
50 	uint16_t fct_state);
51 
52 static fct_status_t emlxs_fct_flogi_xchg(struct fct_local_port *fct_port,
53     struct fct_flogi_xchg *fx);
54 static fct_status_t emlxs_fct_get_link_info(fct_local_port_t *fct_port,
55     fct_link_info_t *link);
56 static fct_status_t emlxs_fct_deregister_remote_port(fct_local_port_t *fct_port,
57     fct_remote_port_t *port_handle);
58 static fct_status_t emlxs_fct_send_cmd(fct_cmd_t *fct_cmd);
59 static fct_status_t emlxs_fct_send_fcp_data(fct_cmd_t *fct_cmd,
60     stmf_data_buf_t *dbuf, uint32_t ioflags);
61 static fct_status_t emlxs_fct_send_cmd_rsp(fct_cmd_t *fct_cmd, uint32_t flags);
62 static fct_status_t emlxs_fct_abort(fct_local_port_t *fct_port,
63     fct_cmd_t *cmd, uint32_t flags);
64 static void emlxs_fct_ctl(fct_local_port_t *fct_port, int cmd, void *arg);
65 static fct_status_t emlxs_fct_register_remote_port(fct_local_port_t *fct_port,
66     fct_remote_port_t *port_handle, fct_cmd_t *plogi);
67 static fct_status_t emlxs_fct_send_els_cmd(fct_cmd_t *fct_cmd);
68 static fct_status_t emlxs_fct_send_ct_cmd(fct_cmd_t *fct_cmd);
69 static fct_status_t emlxs_fct_send_fcp_status(fct_cmd_t *fct_cmd);
70 static fct_status_t emlxs_fct_send_els_rsp(fct_cmd_t *fct_cmd);
71 static void emlxs_fct_pkt_comp(fc_packet_t *pkt);
72 static void emlxs_fct_populate_hba_details(fct_local_port_t *fct_port,
73     fct_port_attrs_t *port_attrs);
74 static fct_status_t emlxs_fct_port_info(uint32_t cmd,
75     fct_local_port_t *fct_port, void *arg, uint8_t *buffer, uint32_t *size);
76 
77 static fct_status_t emlxs_fct_dmem_init(emlxs_port_t *port);
78 static void emlxs_fct_dmem_fini(emlxs_port_t *port);
79 
80 static stmf_data_buf_t *emlxs_fct_dbuf_alloc(fct_local_port_t *fct_port,
81     uint32_t size, uint32_t *pminsize, uint32_t flags);
82 static void emlxs_fct_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf);
83 
84 static int emlxs_fct_dbuf_dma_sync(emlxs_hba_t *hba, stmf_data_buf_t *dbuf,
85     uint_t sync_type);
86 static emlxs_buf_t *emlxs_fct_pkt_init(emlxs_port_t *port,
87     fct_cmd_t *fct_cmd, fc_packet_t *pkt);
88 
89 static void emlxs_fct_unsol_flush_thread(emlxs_hba_t *hba, void *arg1,
90     void *arg2);
91 static void emlxs_fct_unsol_flush(emlxs_port_t *port);
92 static uint32_t emlxs_fct_process_unsol_flogi(emlxs_port_t *port,
93     CHANNEL *cp, IOCBQ *iocbq, MATCHMAP *mp, uint32_t size);
94 static uint32_t emlxs_fct_process_unsol_plogi(emlxs_port_t *port,
95     CHANNEL *cp, IOCBQ *iocbq, MATCHMAP *mp, uint32_t size);
96 static uint32_t emlxs_fct_pkt_abort_txq(emlxs_port_t *port,
97     emlxs_buf_t *cmd_sbp);
98 static fct_status_t emlxs_fct_send_qfull_reply(emlxs_port_t *port,
99     emlxs_node_t *ndlp, uint16_t xid, uint32_t class, emlxs_fcp_cmd_t *fcp_cmd);
100 
101 #ifdef FCT_IO_TRACE
102 uint8_t *emlxs_iotrace = 0;	/* global for mdb */
103 int emlxs_iotrace_cnt = 0;
104 
105 /*
106  *
107  * FCT_CMD  (cmd_sbp->fct_state)
108  *
109  * STATE				LOCK STATUS			OWNER
110  * -----------------------------------------------------------------------------
111  * EMLXS_FCT_ABORT_DONE			Lock Destroyed			COMSTAR
112  * EMLXS_FCT_IO_DONE			Lock Destroyed			COMSTAR
113  *
114  * EMLXS_FCT_CMD_POSTED			Lock Released			COMSTAR
115  * EMLXS_FCT_OWNED			Lock Released			COMSTAR
116  *
117  * EMLXS_FCT_CMD_WAITQ			Lock Released			DRIVER
118  * EMLXS_FCT_RSP_PENDING		Lock Released			DRIVER
119  * EMLXS_FCT_REQ_PENDING		Lock Released			DRIVER
120  * EMLXS_FCT_REG_PENDING		Lock Released			DRIVER
121  * EMLXS_FCT_DATA_PENDING		Lock Released			DRIVER
122  * EMLXS_FCT_STATUS_PENDING		Lock Released			DRIVER
123  * EMLXS_FCT_CLOSE_PENDING		Lock Released			DRIVER
124  * EMLXS_FCT_ABORT_PENDING		Lock Released			DRIVER
125  *
126  * EMLXS_FCT_FCP_CMD_RECEIVED		Transistional, lock held	DRIVER
127  * EMLXS_FCT_ELS_CMD_RECEIVED		Transistional, lock held	DRIVER
128  * EMLXS_FCT_SEND_CMD_RSP		Transistional, lock held	DRIVER
129  * EMLXS_FCT_SEND_ELS_RSP		Transistional, lock held	DRIVER
130  * EMLXS_FCT_SEND_ELS_REQ		Transistional, lock held	DRIVER
131  * EMLXS_FCT_SEND_CT_REQ		Transistional, lock held	DRIVER
132  * EMLXS_FCT_REG_COMPLETE		Transistional, lock held	DRIVER
133  * EMLXS_FCT_SEND_FCP_DATA		Transistional, lock held	DRIVER
134  * EMLXS_FCT_SEND_FCP_STATUS		Transistional, lock held	DRIVER
135  * EMLXS_FCT_PKT_COMPLETE		Transistional, lock held	DRIVER
136  * EMLXS_FCT_PKT_FCPRSP_COMPLETE	Transistional, lock held	DRIVER
137  * EMLXS_FCT_PKT_ELSRSP_COMPLETE	Transistional, lock held	DRIVER
138  * EMLXS_FCT_PKT_ELSCMD_COMPLETE	Transistional, lock held	DRIVER
139  * EMLXS_FCT_PKT_CTCMD_COMPLETE		Transistional, lock held	DRIVER
140  * EMLXS_FCT_REQ_COMPLETE		Transistional, lock held	DRIVER
141  *
142  *
143  * 	COMSTAR OWNED	DRIVER OWNED
144  * 	-------------	---------------------------------------------------
145  * 	------- >	@	   Accept---- >Release  @   Acquire--- >+
146  *									|
147  *	< -------	@	Post/Done< ----Acquire  @   Release< ---+
148  *
149  * 	@  :Indicates COMSTAR use of emlxs_fct_abort()
150  *	    Abort requests set the EMLXS_FCT_ABORT_INP flag.
151  *
152  * 	Accept		:Indicates use of emlxs_fct_cmd_accept()
153  * 	Acquire		:Indicates use of emlxs_fct_cmd_acquire()
154  * 	Post		:Indicates use of emlxs_fct_cmd_post()
155  * 	Done		:Indicates use of emlxs_fct_cmd_done()
156  */
157 
158 void
emlxs_fct_io_trace(emlxs_port_t * port,fct_cmd_t * fct_cmd,uint32_t data)159 emlxs_fct_io_trace(emlxs_port_t *port, fct_cmd_t *fct_cmd, uint32_t data)
160 {
161 	emlxs_iotrace_t *iop = port->iotrace;
162 	uint16_t iotrace_cnt;
163 	uint16_t iotrace_index;
164 	int i;
165 
166 	if (!iop) {
167 		return;
168 	}
169 
170 	mutex_enter(&port->iotrace_mtx);
171 	iotrace_cnt = port->iotrace_cnt;
172 	iotrace_index = port->iotrace_index;
173 
174 	switch (data) {
175 
176 		/* New entry */
177 	case EMLXS_FCT_ELS_CMD_RECEIVED:
178 	case EMLXS_FCT_FCP_CMD_RECEIVED:
179 	case EMLXS_FCT_SEND_ELS_REQ:
180 	case EMLXS_FCT_SEND_CT_REQ:
181 		for (i = 0; i < iotrace_cnt; i++) {
182 			if ((iop->fct_cmd == fct_cmd) &&
183 			    (iop->trc[0] != (uint8_t)(0)))
184 				break;
185 			iop++;
186 		}
187 		if (i < iotrace_cnt) {
188 			/* New entry already exists */
189 			mutex_exit(&port->iotrace_mtx);
190 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
191 			    "IOTRACE: New entry already exists: fct_cmd: %p",
192 			    fct_cmd);
193 			return;
194 		}
195 		iop = port->iotrace + iotrace_index;
196 		for (i = 0; i < iotrace_cnt; i++) {
197 			if (iop->trc[0] == (uint8_t)(0))
198 				break;
199 
200 			iop++;
201 			if (iop == (port->iotrace + iotrace_cnt))
202 				iop = port->iotrace;
203 		}
204 		if (i >= iotrace_cnt) {
205 			/* No new slots available */
206 			mutex_exit(&port->iotrace_mtx);
207 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
208 			    "IOTRACE: No new slots: fct_cmd: %p data: %d",
209 			    fct_cmd, data);
210 			return;
211 		}
212 		port->iotrace_index++;
213 		if (port->iotrace_index >= iotrace_cnt)
214 			port->iotrace_index = 0;
215 
216 		bzero((uint8_t *)iop, sizeof (emlxs_iotrace_t));
217 		iop->fct_cmd = fct_cmd;
218 		iop->xri = fct_cmd->cmd_rxid;
219 		iop->marker = 0xff;
220 		iop->trc[0] = 2;
221 		iop->trc[1] = data;
222 		mutex_exit(&port->iotrace_mtx);
223 		return;
224 	}
225 
226 	for (i = 0; i < iotrace_cnt; i++) {
227 		if ((iop->fct_cmd == fct_cmd) &&
228 		    (iop->trc[0] != (uint8_t)(0)))
229 			break;
230 		iop++;
231 	}
232 	if (i >= iotrace_cnt) {
233 		/* Cannot find existing slot for fct_cmd */
234 		mutex_exit(&port->iotrace_mtx);
235 
236 		if ((data != EMLXS_FCT_REG_PENDING) &&
237 		    (data != EMLXS_FCT_REG_COMPLETE)) {
238 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
239 			    "IOTRACE: Missing slot: fct_cmd: %p data: %d",
240 			    fct_cmd, data);
241 		}
242 		return;
243 	}
244 
245 	if (iop->trc[0] >= MAX_IO_TRACE) {
246 		/* trc overrun for fct_cmd */
247 		mutex_exit(&port->iotrace_mtx);
248 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
249 		    "IOTRACE: trc overrun slot: fct_cmd: %p data: %d",
250 		    fct_cmd, data);
251 		return;
252 	}
253 
254 	if (iop->xri != fct_cmd->cmd_rxid) {
255 		/* xri mismatch for fct_cmd */
256 		mutex_exit(&port->iotrace_mtx);
257 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
258 		    "IOTRACE: xri mismatch %x != %x: fct_cmd: %p data: %d",
259 		    iop->xri, fct_cmd->cmd_rxid, fct_cmd, data);
260 		return;
261 	}
262 
263 	iop->trc[iop->trc[0]] = data;
264 	if ((data == EMLXS_FCT_IO_DONE) || (data == EMLXS_FCT_ABORT_DONE)) {
265 		/* IOCB ULPCOMMAND is saved after EMLXS_FCT_IOCB_ISSUED */
266 		if (iop->trc[iop->trc[0]-1] == EMLXS_FCT_IOCB_ISSUED) {
267 			iop->trc[0]++;
268 		} else {
269 			iop->trc[0] = 0;
270 	} else {
271 		iop->trc[0]++;
272 	}
273 	mutex_exit(&port->iotrace_mtx);
274 
275 	return;
276 
277 } /* emlxs_fct_io_trace() */
278 #endif /* FCT_IO_TRACE */
279 
280 #ifdef MODSYM_SUPPORT
281 
282 extern int
283 emlxs_fct_modopen()
284 {
285 	int err;
286 
287 	mutex_enter(&emlxs_device.lock);
288 
289 	if (emlxs_modsym.fct_modopen) {
290 		mutex_exit(&emlxs_device.lock);
291 		return (0);
292 	}
293 
294 	emlxs_modsym.fct_modopen++;
295 
296 	/* Comstar (fct) */
297 	err = 0;
298 	emlxs_modsym.mod_fct = ddi_modopen("drv/fct", KRTLD_MODE_FIRST, &err);
299 	if (!emlxs_modsym.mod_fct) {
300 
301 		cmn_err(CE_WARN, "?%s: ddi_modopen drv/fct failed: err %d",
302 		    DRIVER_NAME, err);
303 		goto failed;
304 	}
305 
306 	/* Comstar (stmf) */
307 	err = 0;
308 	emlxs_modsym.mod_stmf =
309 	    ddi_modopen("drv/stmf", KRTLD_MODE_FIRST, &err);
310 	if (!emlxs_modsym.mod_stmf) {
311 
312 		cmn_err(CE_WARN, "?%s: ddi_modopen drv/stmf failed: err %d",
313 		    DRIVER_NAME, err);
314 		goto failed;
315 	}
316 
317 	err = 0;
318 	/* Check if the fct fct_alloc is present */
319 	emlxs_modsym.fct_alloc = (void *(*)())ddi_modsym(emlxs_modsym.mod_fct,
320 	    "fct_alloc", &err);
321 	if ((void *)emlxs_modsym.fct_alloc == NULL) {
322 		cmn_err(CE_WARN,
323 		    "?%s: drv/fct: fct_alloc not present", DRIVER_NAME);
324 		goto failed;
325 	}
326 
327 	err = 0;
328 	/* Check if the fct fct_free is present */
329 	emlxs_modsym.fct_free = (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
330 	    "fct_free", &err);
331 	if ((void *)emlxs_modsym.fct_free == NULL) {
332 		cmn_err(CE_WARN,
333 		    "?%s: drv/fct: fct_free not present", DRIVER_NAME);
334 		goto failed;
335 	}
336 
337 	err = 0;
338 	/* Check if the fct fct_scsi_task_alloc is present */
339 	emlxs_modsym.fct_scsi_task_alloc =
340 	    (void *(*)(void *, uint16_t, uint32_t, uint8_t *,
341 	    uint16_t, uint16_t))ddi_modsym(emlxs_modsym.mod_fct,
342 	    "fct_scsi_task_alloc", &err);
343 	if ((void *)emlxs_modsym.fct_scsi_task_alloc == NULL) {
344 		cmn_err(CE_WARN,
345 		    "?%s: drv/fct: fct_scsi_task_alloc not present",
346 		    DRIVER_NAME);
347 		goto failed;
348 	}
349 
350 	err = 0;
351 	/* Check if the fct fct_register_local_port is present */
352 	emlxs_modsym.fct_register_local_port =
353 	    (int (*)())ddi_modsym(emlxs_modsym.mod_fct,
354 	    "fct_register_local_port", &err);
355 	if ((void *)emlxs_modsym.fct_register_local_port == NULL) {
356 		cmn_err(CE_WARN,
357 		    "?%s: drv/fct: fct_register_local_port not present",
358 		    DRIVER_NAME);
359 		goto failed;
360 	}
361 
362 	err = 0;
363 	/* Check if the fct fct_deregister_local_port is present */
364 	emlxs_modsym.fct_deregister_local_port =
365 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
366 	    "fct_deregister_local_port", &err);
367 	if ((void *)emlxs_modsym.fct_deregister_local_port == NULL) {
368 		cmn_err(CE_WARN,
369 		    "?%s: drv/fct: fct_deregister_local_port not present",
370 		    DRIVER_NAME);
371 		goto failed;
372 	}
373 
374 	err = 0;
375 	/* Check if the fct fct_handle_event is present */
376 	emlxs_modsym.fct_handle_event =
377 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct, "fct_handle_event",
378 	    &err);
379 	if ((void *)emlxs_modsym.fct_handle_event == NULL) {
380 		cmn_err(CE_WARN,
381 		    "?%s: drv/fct: fct_handle_event not present",
382 		    DRIVER_NAME);
383 		goto failed;
384 	}
385 
386 	err = 0;
387 	/* Check if the fct fct_post_rcvd_cmd is present */
388 	emlxs_modsym.fct_post_rcvd_cmd =
389 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct, "fct_post_rcvd_cmd",
390 	    &err);
391 	if ((void *)emlxs_modsym.fct_post_rcvd_cmd == NULL) {
392 		cmn_err(CE_WARN,
393 		    "?%s: drv/fct: fct_post_rcvd_cmd not present",
394 		    DRIVER_NAME);
395 		goto failed;
396 	}
397 	err = 0;
398 	/* Check if the fct fct_alloc is present */
399 	emlxs_modsym.fct_ctl = (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
400 	    "fct_ctl", &err);
401 	if ((void *)emlxs_modsym.fct_ctl == NULL) {
402 		cmn_err(CE_WARN,
403 		    "?%s: drv/fct: fct_ctl not present", DRIVER_NAME);
404 		goto failed;
405 	}
406 	err = 0;
407 	/* Check if the fct fct_queue_cmd_for_termination is present */
408 	emlxs_modsym.fct_queue_cmd_for_termination =
409 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
410 	    "fct_queue_cmd_for_termination", &err);
411 	if ((void *)emlxs_modsym.fct_queue_cmd_for_termination == NULL) {
412 		cmn_err(CE_WARN,
413 		    "?%s: drv/fct: fct_queue_cmd_for_termination not present",
414 		    DRIVER_NAME);
415 		goto failed;
416 	}
417 	err = 0;
418 	/* Check if the fct fct_send_response_done is present */
419 	emlxs_modsym.fct_send_response_done =
420 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
421 	    "fct_send_response_done", &err);
422 	if ((void *)emlxs_modsym.fct_send_response_done == NULL) {
423 		cmn_err(CE_WARN,
424 		    "?%s: drv/fct: fct_send_response_done not present",
425 		    DRIVER_NAME);
426 		goto failed;
427 	}
428 	err = 0;
429 	/* Check if the fct fct_send_cmd_done is present */
430 	emlxs_modsym.fct_send_cmd_done =
431 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct, "fct_send_cmd_done",
432 	    &err);
433 	if ((void *)emlxs_modsym.fct_send_cmd_done == NULL) {
434 		cmn_err(CE_WARN,
435 		    "?%s: drv/fct: fct_send_cmd_done not present",
436 		    DRIVER_NAME);
437 		goto failed;
438 	}
439 	err = 0;
440 	/* Check if the fct fct_scsi_xfer_data_done is present */
441 	emlxs_modsym.fct_scsi_data_xfer_done =
442 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
443 	    "fct_scsi_data_xfer_done", &err);
444 	if ((void *)emlxs_modsym.fct_scsi_data_xfer_done == NULL) {
445 		cmn_err(CE_WARN,
446 		    "?%s: drv/fct: fct_scsi_data_xfer_done not present",
447 		    DRIVER_NAME);
448 		goto failed;
449 	}
450 	err = 0;
451 	/* Check if the fct fct_port_shutdown is present */
452 	emlxs_modsym.fct_port_shutdown =
453 	    (fct_status_t(*)())ddi_modsym(emlxs_modsym.mod_fct,
454 	    "fct_port_shutdown", &err);
455 	if ((void *)emlxs_modsym.fct_port_shutdown == NULL) {
456 		cmn_err(CE_WARN,
457 		    "?%s: drv/fct: fct_port_shutdown not present",
458 		    DRIVER_NAME);
459 		goto failed;
460 	}
461 
462 	err = 0;
463 	/* Check if the fct fct_port_initialize is present */
464 	emlxs_modsym.fct_port_initialize =
465 	    (fct_status_t(*)())ddi_modsym(emlxs_modsym.mod_fct,
466 	    "fct_port_initialize", &err);
467 	if ((void *)emlxs_modsym.fct_port_initialize == NULL) {
468 		cmn_err(CE_WARN,
469 		    "?%s: drv/fct: fct_port_initialize not present",
470 		    DRIVER_NAME);
471 		goto failed;
472 	}
473 
474 	err = 0;
475 	/* Check if the fct fct_cmd_fca_aborted is present */
476 	emlxs_modsym.fct_cmd_fca_aborted =
477 	    (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
478 	    "fct_cmd_fca_aborted", &err);
479 	if ((void *)emlxs_modsym.fct_cmd_fca_aborted == NULL) {
480 		cmn_err(CE_WARN,
481 		    "?%s: drv/fct: fct_cmd_fca_aborted not present",
482 		    DRIVER_NAME);
483 		goto failed;
484 	}
485 
486 	err = 0;
487 	/* Check if the fct fct_handle_rcvd_flogi is present */
488 	emlxs_modsym.fct_handle_rcvd_flogi =
489 	    (fct_status_t(*)())ddi_modsym(emlxs_modsym.mod_fct,
490 	    "fct_handle_rcvd_flogi", &err);
491 	if ((void *)emlxs_modsym.fct_handle_rcvd_flogi == NULL) {
492 		cmn_err(CE_WARN,
493 		    "?%s: drv/fct: fct_handle_rcvd_flogi not present",
494 		    DRIVER_NAME);
495 		goto failed;
496 	}
497 
498 	/* Comstar (stmf) */
499 	err = 0;
500 	/* Check if the stmf stmf_alloc is present */
501 	emlxs_modsym.stmf_alloc =
502 	    (void *(*)())ddi_modsym(emlxs_modsym.mod_stmf, "stmf_alloc",
503 	    &err);
504 	if ((void *)emlxs_modsym.stmf_alloc == NULL) {
505 		cmn_err(CE_WARN,
506 		    "?%s: drv/stmf: stmf_alloc not present", DRIVER_NAME);
507 		goto failed;
508 	}
509 
510 	err = 0;
511 	/* Check if the stmf stmf_free is present */
512 	emlxs_modsym.stmf_free = (void (*)())ddi_modsym(emlxs_modsym.mod_stmf,
513 	    "stmf_free", &err);
514 	if ((void *)emlxs_modsym.stmf_free == NULL) {
515 		cmn_err(CE_WARN,
516 		    "?%s: drv/stmf: stmf_free not present", DRIVER_NAME);
517 		goto failed;
518 	}
519 
520 	err = 0;
521 	/* Check if the stmf stmf_deregister_port_provider is present */
522 	emlxs_modsym.stmf_deregister_port_provider =
523 	    (void (*)())ddi_modsym(emlxs_modsym.mod_stmf,
524 	    "stmf_deregister_port_provider", &err);
525 	if ((void *)emlxs_modsym.stmf_deregister_port_provider == NULL) {
526 		cmn_err(CE_WARN,
527 		    "?%s: drv/stmf: stmf_deregister_port_provider not present",
528 		    DRIVER_NAME);
529 		goto failed;
530 	}
531 
532 	err = 0;
533 	/* Check if the stmf stmf_register_port_provider is present */
534 	emlxs_modsym.stmf_register_port_provider =
535 	    (int (*)())ddi_modsym(emlxs_modsym.mod_stmf,
536 	    "stmf_register_port_provider", &err);
537 	if ((void *)emlxs_modsym.stmf_register_port_provider == NULL) {
538 		cmn_err(CE_WARN,
539 		    "?%s: drv/stmf: stmf_register_port_provider not present",
540 		    DRIVER_NAME);
541 		goto failed;
542 	}
543 
544 	mutex_exit(&emlxs_device.lock);
545 	return (0);
546 
547 failed:
548 
549 	mutex_exit(&emlxs_device.lock);
550 	emlxs_fct_modclose();
551 	return (1);
552 
553 } /* emlxs_fct_modopen() */
554 
555 
556 extern void
557 emlxs_fct_modclose()
558 {
559 	mutex_enter(&emlxs_device.lock);
560 
561 	if (emlxs_modsym.fct_modopen == 0) {
562 		mutex_exit(&emlxs_device.lock);
563 		return;
564 	}
565 
566 	emlxs_modsym.fct_modopen--;
567 
568 	if (emlxs_modsym.fct_modopen) {
569 		mutex_exit(&emlxs_device.lock);
570 		return;
571 	}
572 
573 	if (emlxs_modsym.mod_fct) {
574 		(void) ddi_modclose(emlxs_modsym.mod_fct);
575 		emlxs_modsym.mod_fct = 0;
576 	}
577 
578 	if (emlxs_modsym.mod_stmf) {
579 		(void) ddi_modclose(emlxs_modsym.mod_stmf);
580 		emlxs_modsym.mod_stmf = 0;
581 	}
582 
583 	emlxs_modsym.fct_alloc = NULL;
584 	emlxs_modsym.fct_free = NULL;
585 	emlxs_modsym.fct_scsi_task_alloc = NULL;
586 	emlxs_modsym.fct_register_local_port = NULL;
587 	emlxs_modsym.fct_deregister_local_port = NULL;
588 	emlxs_modsym.fct_handle_event = NULL;
589 	emlxs_modsym.fct_ctl = NULL;
590 	emlxs_modsym.fct_queue_cmd_for_termination = NULL;
591 	emlxs_modsym.fct_send_response_done = NULL;
592 	emlxs_modsym.fct_send_cmd_done = NULL;
593 	emlxs_modsym.fct_scsi_data_xfer_done = NULL;
594 	emlxs_modsym.fct_port_shutdown = NULL;
595 	emlxs_modsym.fct_port_initialize = NULL;
596 	emlxs_modsym.fct_cmd_fca_aborted = NULL;
597 	emlxs_modsym.fct_handle_rcvd_flogi = NULL;
598 
599 	emlxs_modsym.stmf_alloc = NULL;
600 	emlxs_modsym.stmf_free = NULL;
601 	emlxs_modsym.stmf_deregister_port_provider = NULL;
602 	emlxs_modsym.stmf_register_port_provider = NULL;
603 
604 	mutex_exit(&emlxs_device.lock);
605 
606 } /* emlxs_fct_modclose() */
607 
608 #endif /* MODSYM_SUPPORT */
609 
610 /*
611  * This routine is called to handle an unsol FLOGI exchange
612  *	fx	save
613  *	0	1	Process or save port->fx
614  *	0	0	Process or reject port->fx
615  *	1	1	Process port->fx, Process or save fx
616  *	1	0	Process or reject port->fx, Process or reject fx
617  */
618 static void
619 emlxs_fct_handle_unsol_flogi(emlxs_port_t *port, fct_flogi_xchg_t *fx,
620     uint32_t save)
621 {
622 	emlxs_hba_t *hba = HBA;
623 	fct_status_t status;
624 	IOCBQ iocbq;
625 	fct_flogi_xchg_t fxchg;
626 
627 begin:
628 	mutex_enter(&EMLXS_PORT_LOCK);
629 
630 	/* Check if there is an old saved FLOGI */
631 	if (port->fx.fx_op) {
632 		/* Get it now */
633 		bcopy(&port->fx, &fxchg, sizeof (fct_flogi_xchg_t));
634 
635 		if (fx) {
636 			/* Save new FLOGI */
637 			bcopy(fx, &port->fx, sizeof (fct_flogi_xchg_t));
638 
639 			/* Reject old stale FLOGI */
640 			fx = &fxchg;
641 			goto reject_it;
642 
643 		} else {
644 			bzero(&port->fx, sizeof (fct_flogi_xchg_t));
645 			fx = &fxchg;
646 		}
647 
648 	} else if (!fx) {
649 		/* Nothing to do, just return */
650 		mutex_exit(&EMLXS_PORT_LOCK);
651 		return;
652 	}
653 
654 	/* We have a valid FLOGI here */
655 	/* There is no saved FLOGI at this point either */
656 
657 	/* Check if COMSTAR is ready to accept it */
658 	if (port->fct_flags & FCT_STATE_LINK_UP_ACKED) {
659 		mutex_exit(&EMLXS_PORT_LOCK);
660 
661 		bzero((uint8_t *)&iocbq, sizeof (IOCBQ));
662 		iocbq.iocb.un.elsreq.remoteID = fx->fx_sid;
663 		iocbq.iocb.un.elsreq.myID = fx->fx_did;
664 		iocbq.iocb.ULPCONTEXT = (uint16_t)fx->rsvd2;
665 		fx->rsvd2 = 0; /* Clear the reserved field now */
666 
667 		status = MODSYM(fct_handle_rcvd_flogi) (port->fct_port, fx);
668 
669 #ifdef FCT_API_TRACE
670 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
671 		    "fct_handle_rcvd_flogi %p: status=%x",
672 		    port->fct_port, status);
673 #endif /* FCT_API_TRACE */
674 
675 		if (status == FCT_SUCCESS) {
676 			if (fx->fx_op == ELS_OP_ACC) {
677 				(void) emlxs_els_reply(port, &iocbq,
678 				    ELS_CMD_ACC, ELS_CMD_FLOGI, 0, 0);
679 
680 			} else {	/* ELS_OP_LSRJT */
681 				(void) emlxs_els_reply(port, &iocbq,
682 				    ELS_CMD_LS_RJT, ELS_CMD_FLOGI,
683 				    fx->fx_rjt_reason, fx->fx_rjt_expl);
684 			}
685 		} else {
686 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
687 			    "FLOGI: sid=%x xid=%x. "
688 			    "fct_handle_rcvd_flogi failed. Rejecting.",
689 			    fx->fx_sid, iocbq.iocb.ULPCONTEXT);
690 
691 			(void) emlxs_els_reply(port, &iocbq,
692 			    ELS_CMD_LS_RJT, ELS_CMD_FLOGI,
693 			    LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
694 		}
695 
696 		return;
697 	}
698 
699 	if (save) {
700 		/* Save FLOGI for later */
701 		bcopy(fx, &port->fx, sizeof (fct_flogi_xchg_t));
702 		mutex_exit(&EMLXS_PORT_LOCK);
703 		return;
704 	}
705 
706 reject_it:
707 
708 	mutex_exit(&EMLXS_PORT_LOCK);
709 
710 	if (port->fct_flags & FCT_STATE_LINK_UP) {
711 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
712 		    "FLOGI: sid=%x xid=%x. Stale. Rejecting.",
713 		    fx->fx_sid, fx->rsvd2);
714 
715 		bzero((uint8_t *)&iocbq, sizeof (IOCBQ));
716 		iocbq.iocb.un.elsreq.remoteID = fx->fx_sid;
717 		iocbq.iocb.un.elsreq.myID = fx->fx_did;
718 		iocbq.iocb.ULPCONTEXT = fx->rsvd2;
719 
720 		(void) emlxs_els_reply(port, &iocbq,
721 		    ELS_CMD_LS_RJT, ELS_CMD_FLOGI,
722 		    LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
723 
724 		/* If we have an FLOGI saved, try sending it now */
725 		if (port->fx.fx_op) {
726 			fx = NULL;
727 			goto begin;
728 		}
729 
730 	} else {
731 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
732 		    "FLOGI: sid=%x xid=%x. Link down. "
733 		    "Dropping.",
734 		    fx->fx_sid, fx->rsvd2);
735 	}
736 
737 	return;
738 
739 } /* emlxs_fct_handle_unsol_flogi() */
740 
741 
742 /* ARGSUSED */
743 static void
744 emlxs_fct_unsol_flush_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
745 {
746 	emlxs_port_t *port = (emlxs_port_t *)arg1;
747 
748 	emlxs_fct_unsol_flush(port);
749 	return;
750 
751 } /* emlxs_fct_unsol_flush_thread() */
752 
753 
754 /* This is called at port online and offline */
755 static void
756 emlxs_fct_unsol_flush(emlxs_port_t *port)
757 {
758 	emlxs_hba_t *hba = HBA;
759 	emlxs_buf_t *cmd_sbp;
760 	emlxs_buf_t *next;
761 	fct_cmd_t *fct_cmd;
762 	fct_status_t rval;
763 	uint32_t cmd_code;
764 
765 	if (!port->fct_port) {
766 		return;
767 	}
768 
769 	/* First handle any pending FLOGI */
770 	emlxs_fct_handle_unsol_flogi(port, NULL, 0);
771 
772 	if ((port->fct_flags & FCT_STATE_LINK_UP_ACKED) &&
773 	    !(port->fct_flags & FCT_STATE_FLOGI_CMPL)) {
774 		return;
775 	}
776 
777 	/* Wait queue */
778 	mutex_enter(&EMLXS_PORT_LOCK);
779 	cmd_sbp = port->fct_wait_head;
780 	port->fct_wait_head = NULL;
781 	port->fct_wait_tail = NULL;
782 	mutex_exit(&EMLXS_PORT_LOCK);
783 
784 	/*
785 	 * Next process any outstanding ELS commands. It doesn't
786 	 * matter if the Link is up or not, always post them to FCT.
787 	 */
788 	while (cmd_sbp) {
789 		next = cmd_sbp->next;
790 		fct_cmd = cmd_sbp->fct_cmd;
791 
792 		cmd_code = (fct_cmd->cmd_oxid << ELS_CMD_SHIFT);
793 
794 		/* Reacquire ownership of the fct_cmd */
795 		rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
796 		if (rval) {
797 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
798 			    "fct_unsol_flush: %s: sid=%x xid=%x "
799 			    "Unable to reacquire fct_cmd.",
800 			    emlxs_elscmd_xlate(cmd_code),
801 			    fct_cmd->cmd_rxid, fct_cmd->cmd_rportid);
802 
803 			cmd_sbp = next;
804 			continue;
805 		}
806 		/* mutex_enter(&cmd_sbp->fct_mtx); */
807 
808 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
809 		    "Posting %s: sid=%x xid=%x %p",
810 		    emlxs_elscmd_xlate(cmd_code),
811 		    fct_cmd->cmd_rportid, fct_cmd->cmd_rxid,
812 		    fct_cmd);
813 
814 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
815 		/* mutex_exit(&cmd_sbp->fct_mtx); */
816 
817 #ifdef FCT_API_TRACE
818 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
819 		    "fct_post_rcvd_cmd:2 %p:%p portid x%x", fct_cmd, cmd_sbp,
820 		    fct_cmd->cmd_lportid);
821 #endif /* FCT_API_TRACE */
822 
823 		MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
824 
825 		cmd_sbp = next;
826 
827 	}	/* while () */
828 
829 	return;
830 
831 } /* emlxs_fct_unsol_flush() */
832 
833 
834 int
835 emlxs_is_digit(uint8_t chr)
836 {
837 	if ((chr >= '0') && (chr <= '9')) {
838 		return (1);
839 	}
840 
841 	return (0);
842 
843 } /* emlxs_is_digit */
844 
845 
846 /*
847  *   Convert an ASCII decimal numeric string to integer.
848  *   Negation character '-' is not handled.
849  */
850 static uint32_t
851 emlxs_str_atoi(uint8_t *string)
852 {
853 	uint32_t num = 0;
854 	int i = 0;
855 
856 	while (string[i]) {
857 		if (!emlxs_is_digit(string[i])) {
858 			return (num);
859 		}
860 
861 		num = num * 10 + (string[i++] - '0');
862 	}
863 
864 	return (num);
865 
866 } /* emlxs_str_atoi() */
867 
868 
869 extern uint32_t
870 emlxs_fct_init(emlxs_hba_t *hba)
871 {
872 	emlxs_port_t *port = &PPORT;
873 
874 	/* Check if COMSTAR is present */
875 	if (((void *)MODSYM(stmf_alloc) == NULL) ||
876 	    ((void *)MODSYM(fct_alloc) == NULL)) {
877 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_attach_debug_msg,
878 		    "Comstar not present.");
879 		return (1);
880 	}
881 
882 	return (0);
883 
884 } /* emlxs_fct_init() */
885 
886 
887 extern void
888 emlxs_fct_attach(emlxs_hba_t *hba)
889 {
890 	emlxs_port_t *port = &PPORT;
891 	uint32_t vpi;
892 
893 	if (!(port->flag & EMLXS_TGT_ENABLED)) {
894 		return;
895 	}
896 
897 	/* Bind the physical port */
898 	emlxs_fct_bind_port(port);
899 
900 	/* Bind virtual ports */
901 	if (hba->flag & FC_NPIV_ENABLED) {
902 		for (vpi = 1; vpi <= hba->vpi_high; vpi++) {
903 			port = &VPORT(vpi);
904 
905 			if (!(port->flag & EMLXS_PORT_ENABLED)) {
906 				continue;
907 			}
908 
909 			emlxs_fct_bind_port(port);
910 		}
911 	}
912 
913 	return;
914 
915 } /* emlxs_fct_attach() */
916 
917 
918 extern void
919 emlxs_fct_detach(emlxs_hba_t *hba)
920 {
921 	uint32_t i;
922 	emlxs_port_t *vport;
923 
924 	for (i = 0; i < MAX_VPORTS; i++) {
925 		vport = &VPORT(i);
926 
927 		if (!(vport->flag & EMLXS_PORT_ENABLED)) {
928 			continue;
929 		}
930 
931 		emlxs_fct_unbind_port(vport);
932 	}
933 
934 #ifdef FCT_IO_TRACE
935 {
936 	emlxs_port_t *port = &PPORT;
937 
938 	mutex_destroy(&port->iotrace_mtx);
939 	if (port->iotrace) {
940 		kmem_free(port->iotrace,
941 		    (port->iotrace_cnt * sizeof (emlxs_iotrace_t)));
942 	}
943 	port->iotrace = NULL;
944 }
945 #endif /* FCT_IO_TRACE */
946 
947 	return;
948 
949 } /* emlxs_fct_detach() */
950 
951 
952 extern void
953 emlxs_fct_unbind_port(emlxs_port_t *port)
954 {
955 	emlxs_hba_t *hba = HBA;
956 	char node_name[32];
957 
958 	mutex_enter(&EMLXS_PORT_LOCK);
959 
960 	if (!(port->flag & EMLXS_TGT_BOUND)) {
961 		mutex_exit(&EMLXS_PORT_LOCK);
962 		return;
963 	}
964 
965 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
966 	    "fct_unbind_port: port=%d", port->vpi);
967 
968 	/* Destroy & flush all port nodes, if they exist */
969 	if (port->node_count) {
970 		(void) EMLXS_SLI_UNREG_NODE(port, NULL, NULL, NULL, NULL);
971 	}
972 
973 	port->flag &= ~EMLXS_TGT_BOUND;
974 	port->flag &= ~EMLXS_TGT_ENABLED;
975 	hba->num_of_ports--;
976 	mutex_exit(&EMLXS_PORT_LOCK);
977 
978 	if (port->fct_port) {
979 		emlxs_fct_link_down(port);
980 		emlxs_fct_unsol_flush(port);
981 
982 #ifdef FCT_API_TRACE
983 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
984 		    "fct_deregister_local_port %p", port->fct_port);
985 #endif /* FCT_API_TRACE */
986 		MODSYM(fct_deregister_local_port) (port->fct_port);
987 
988 		if (port->fct_port->port_fds) {
989 #ifdef FCT_API_TRACE
990 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
991 			    "fct_free:3 %p", port->fct_port->port_fds);
992 #endif /* FCT_API_TRACE */
993 			MODSYM(fct_free) (port->fct_port->port_fds);
994 			port->fct_port->port_fds = NULL;
995 		}
996 #ifdef FCT_API_TRACE
997 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
998 		    "fct_free:4 %p", port->fct_port);
999 #endif /* FCT_API_TRACE */
1000 		MODSYM(fct_free) (port->fct_port);
1001 		port->fct_port = NULL;
1002 		port->fct_flags = 0;
1003 	}
1004 
1005 	if (port->port_provider) {
1006 #ifdef FCT_API_TRACE
1007 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1008 		    "stmf_deregister_port_provider:1 %p",
1009 		    port->port_provider);
1010 #endif /* FCT_API_TRACE */
1011 		MODSYM(stmf_deregister_port_provider) (port->port_provider);
1012 
1013 #ifdef FCT_API_TRACE
1014 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1015 		    "stmf_free:1 %p", port->port_provider);
1016 #endif /* FCT_API_TRACE */
1017 		MODSYM(stmf_free) (port->port_provider);
1018 		port->port_provider = NULL;
1019 	}
1020 
1021 	if (port->fct_memseg) {
1022 		emlxs_fct_dmem_fini(port);
1023 	}
1024 
1025 	(void) snprintf(node_name, sizeof (node_name), "%d,%d:SFCT",
1026 	    hba->ddiinst, port->vpi);
1027 	(void) ddi_remove_minor_node(hba->dip, node_name);
1028 
1029 	return;
1030 
1031 } /* emlxs_fct_unbind_port() */
1032 
1033 
1034 extern void
1035 emlxs_fct_bind_port(emlxs_port_t *port)
1036 {
1037 	emlxs_hba_t *hba = HBA;
1038 	fct_local_port_t *fct_port;
1039 	uint32_t flag = 0;
1040 	emlxs_config_t *cfg = &CFG;
1041 	fct_dbuf_store_t *fds;
1042 	char node_name[32];
1043 	uint8_t *bptr;
1044 
1045 	if (!(port->flag & EMLXS_TGT_ENABLED)) {
1046 		return;
1047 	}
1048 
1049 	mutex_enter(&EMLXS_PORT_LOCK);
1050 
1051 	if (port->flag & EMLXS_TGT_BOUND) {
1052 		mutex_exit(&EMLXS_PORT_LOCK);
1053 		return;
1054 	}
1055 
1056 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1057 	    "fct_bind_port: port=%d", port->vpi);
1058 
1059 	/* Perform generic port initialization */
1060 	emlxs_port_init(port);
1061 
1062 	if (port->vpi == 0) {
1063 		(void) snprintf(port->cfd_name, sizeof (port->cfd_name),
1064 		    "%s%d", DRIVER_NAME, hba->ddiinst);
1065 	} else {
1066 		(void) snprintf(port->cfd_name, sizeof (port->cfd_name),
1067 		    "%s%d.%d", DRIVER_NAME, hba->ddiinst, port->vpi);
1068 	}
1069 
1070 	if (emlxs_fct_dmem_init(port) != FCT_SUCCESS) {
1071 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1072 		    "fct_bind_port: Unable to allocate fct memory.");
1073 		goto failed;
1074 	}
1075 	flag |= 0x00000001;
1076 
1077 	port->port_provider =
1078 	    (stmf_port_provider_t *)
1079 	    MODSYM(stmf_alloc) (STMF_STRUCT_PORT_PROVIDER, 0, 0);
1080 #ifdef FCT_API_TRACE
1081 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1082 	    "stmf_alloc port_provider %p", port->port_provider);
1083 #endif /* FCT_API_TRACE */
1084 
1085 	if (port->port_provider == NULL) {
1086 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1087 		    "fct_bind_port: Unable to allocate port provider.");
1088 		goto failed;
1089 	}
1090 	flag |= 0x00000002;
1091 
1092 	port->port_provider->pp_portif_rev = PORTIF_REV_1;
1093 	port->port_provider->pp_name = port->cfd_name;
1094 	port->port_provider->pp_provider_private = port;
1095 
1096 #ifdef FCT_API_TRACE
1097 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1098 	    "stmf_register_port_provider %p", port->port_provider);
1099 #endif /* FCT_API_TRACE */
1100 	/* register port provider with framework */
1101 	if (MODSYM(stmf_register_port_provider) (port->port_provider) !=
1102 	    STMF_SUCCESS) {
1103 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1104 		    "fct_bind_port: Unable to register port provider.");
1105 		goto failed;
1106 	}
1107 	flag |= 0x00000004;
1108 
1109 	port->fct_port =
1110 	    (fct_local_port_t *)MODSYM(fct_alloc) (FCT_STRUCT_LOCAL_PORT, 0,
1111 	    0);
1112 #ifdef FCT_API_TRACE
1113 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1114 	    "fct_alloc fct_port %p", port->fct_port);
1115 #endif /* FCT_API_TRACE */
1116 
1117 	if (port->fct_port == NULL) {
1118 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1119 		    "fct_bind_port: Unable to allocate fct port.");
1120 		goto failed;
1121 	}
1122 	flag |= 0x00000008;
1123 
1124 	port->fct_port->port_fds =
1125 	    (fct_dbuf_store_t *)MODSYM(fct_alloc) (FCT_STRUCT_DBUF_STORE, 0,
1126 	    0);
1127 #ifdef FCT_API_TRACE
1128 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1129 	    "fct_alloc port_fds %p", port->fct_port->port_fds);
1130 #endif /* FCT_API_TRACE */
1131 
1132 	if (port->fct_port->port_fds == NULL) {
1133 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1134 		    "fct_bind_port: Unable to allocate dbuf store.");
1135 		goto failed;
1136 	}
1137 	flag |= 0x00000010;
1138 
1139 	(void) snprintf(node_name, sizeof (node_name), "%d,%d:SFCT",
1140 	    hba->ddiinst, port->vpi);
1141 	if (ddi_create_minor_node(hba->dip, node_name, S_IFCHR, hba->ddiinst,
1142 	    NULL, 0) == DDI_FAILURE) {
1143 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1144 		    "Unable to create SFCT device node.");
1145 		goto failed;
1146 	}
1147 	flag |= 0x00000020;
1148 
1149 	/* Intialize */
1150 	fct_port = port->fct_port;
1151 	fct_port->port_fca_version = FCT_FCA_MODREV_1;
1152 	fct_port->port_fca_private = port;
1153 	fct_port->port_fca_abort_timeout = 30 * 1000;	/* 30 seconds */
1154 
1155 	bcopy((uint8_t *)&port->wwpn, (uint8_t *)fct_port->port_pwwn, 8);
1156 	bcopy((uint8_t *)&port->wwnn, (uint8_t *)fct_port->port_nwwn, 8);
1157 
1158 	bptr = (uint8_t *)&port->wwnn;
1159 	(void) snprintf(fct_port->port_nwwn_str, FC_WWN_BUFLEN,
1160 	    "%02x%02x%02x%02x%02x%02x%02x%02x",
1161 	    bptr[0], bptr[1], bptr[2], bptr[3],
1162 	    bptr[4], bptr[5], bptr[6], bptr[7]);
1163 
1164 	bptr = (uint8_t *)&port->wwpn;
1165 	(void) snprintf(fct_port->port_pwwn_str, FC_WWN_BUFLEN,
1166 	    "%02x%02x%02x%02x%02x%02x%02x%02x",
1167 	    bptr[0], bptr[1], bptr[2], bptr[3],
1168 	    bptr[4], bptr[5], bptr[6], bptr[7]);
1169 
1170 	fct_port->port_sym_node_name = port->snn;
1171 	fct_port->port_sym_port_name = port->spn;
1172 	fct_port->port_hard_address = cfg[CFG_ASSIGN_ALPA].current;
1173 	fct_port->port_default_alias = port->cfd_name;
1174 	fct_port->port_pp = port->port_provider;
1175 	fct_port->port_max_logins = hba->max_nodes + EMLXS_FCT_NUM_ELS_ONLY;
1176 
1177 	if (cfg[CFG_FCT_QDEPTH].current &&
1178 	    (cfg[CFG_FCT_QDEPTH].current < hba->io_throttle)) {
1179 		fct_port->port_max_xchges = cfg[CFG_FCT_QDEPTH].current;
1180 	} else {
1181 		fct_port->port_max_xchges = hba->io_throttle;
1182 	}
1183 
1184 	fct_port->port_fca_fcp_cmd_size = sizeof (emlxs_buf_t);
1185 	fct_port->port_fca_rp_private_size = sizeof (uintptr_t);
1186 	fct_port->port_fca_sol_els_private_size = sizeof (emlxs_buf_t);
1187 	fct_port->port_fca_sol_ct_private_size = sizeof (emlxs_buf_t);
1188 	fct_port->port_get_link_info = emlxs_fct_get_link_info;
1189 	fct_port->port_register_remote_port = emlxs_fct_register_remote_port;
1190 	fct_port->port_deregister_remote_port =
1191 	    emlxs_fct_deregister_remote_port;
1192 	fct_port->port_send_cmd = emlxs_fct_send_cmd;
1193 	fct_port->port_xfer_scsi_data = emlxs_fct_send_fcp_data;
1194 	fct_port->port_send_cmd_response = emlxs_fct_send_cmd_rsp;
1195 	fct_port->port_abort_cmd = emlxs_fct_abort;
1196 	fct_port->port_ctl = emlxs_fct_ctl;
1197 	fct_port->port_flogi_xchg = emlxs_fct_flogi_xchg;
1198 	fct_port->port_populate_hba_details = emlxs_fct_populate_hba_details;
1199 	fct_port->port_info = emlxs_fct_port_info;
1200 
1201 	fds = port->fct_port->port_fds;
1202 	fds->fds_fca_private = port;
1203 	fds->fds_alloc_data_buf = emlxs_fct_dbuf_alloc;
1204 	fds->fds_free_data_buf = emlxs_fct_dbuf_free;
1205 
1206 	/* Scatter gather list support */
1207 /*	fds->fds_setup_dbuf = ; */
1208 /*	fds->fds_teardown_dbuf = ; */
1209 /*	fds->fds_max_sgl_xfer_len = ; */
1210 /*	fds->fds_copy_threshold = ; */
1211 
1212 #ifdef FCT_API_TRACE
1213 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1214 	    "fct_register_local_port %p", fct_port);
1215 #endif /* FCT_API_TRACE */
1216 	/* register this local port with the fct module */
1217 	if (MODSYM(fct_register_local_port) (fct_port) != FCT_SUCCESS) {
1218 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1219 		    "fct_bind_port: Unable to register fct port.");
1220 		goto failed;
1221 	}
1222 
1223 	/* Set the bound flag */
1224 	port->flag |= EMLXS_TGT_BOUND;
1225 	hba->num_of_ports++;
1226 
1227 	mutex_exit(&EMLXS_PORT_LOCK);
1228 
1229 	return;
1230 
1231 failed:
1232 
1233 	if (flag & 0x20) {
1234 		(void) ddi_remove_minor_node(hba->dip, node_name);
1235 	}
1236 
1237 	if (flag & 0x10) {
1238 #ifdef FCT_API_TRACE
1239 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1240 		    "fct_free:5 %p", port->fct_port->port_fds);
1241 #endif /* FCT_API_TRACE */
1242 		MODSYM(fct_free) (port->fct_port->port_fds);
1243 		port->fct_port->port_fds = NULL;
1244 	}
1245 
1246 	if (flag & 0x8) {
1247 #ifdef FCT_API_TRACE
1248 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1249 		    "fct_free:6 %p", port->fct_port);
1250 #endif /* FCT_API_TRACE */
1251 		MODSYM(fct_free) (port->fct_port);
1252 		port->fct_port = NULL;
1253 		port->fct_flags = 0;
1254 	}
1255 
1256 	if (flag & 0x4) {
1257 #ifdef FCT_API_TRACE
1258 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1259 		    "stmf_deregister_port_provider:2 %p",
1260 		    port->port_provider);
1261 #endif /* FCT_API_TRACE */
1262 		MODSYM(stmf_deregister_port_provider) (port->port_provider);
1263 	}
1264 
1265 	if (flag & 0x2) {
1266 #ifdef FCT_API_TRACE
1267 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1268 		    "stmf_free:2 %p", port->port_provider);
1269 #endif /* FCT_API_TRACE */
1270 		MODSYM(stmf_free) (port->port_provider);
1271 		port->port_provider = NULL;
1272 	}
1273 
1274 	if (flag & 0x1) {
1275 		emlxs_fct_dmem_fini(port);
1276 	}
1277 
1278 	port->flag &= ~EMLXS_TGT_ENABLED;
1279 
1280 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1281 	    "Target mode disabled.");
1282 
1283 	mutex_exit(&EMLXS_PORT_LOCK);
1284 
1285 	return;
1286 
1287 } /* emlxs_fct_bind_port() */
1288 
1289 
1290 /* COMSTAR ENTER POINT */
1291 /*ARGSUSED*/
1292 static fct_status_t
1293 emlxs_fct_port_info(uint32_t cmd, fct_local_port_t *fct_port, void *arg,
1294     uint8_t *buffer, uint32_t *size)
1295 {
1296 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1297 	emlxs_hba_t *hba = HBA;
1298 	fct_status_t rval = FCT_SUCCESS;
1299 	fct_port_link_status_t *link_status;
1300 	MAILBOX *mb;
1301 	MAILBOXQ *mbq;
1302 
1303 	switch (cmd) {
1304 	case FC_TGT_PORT_RLS:
1305 		bzero(buffer, *size);
1306 
1307 		if ((*size) < sizeof (fct_port_link_status_t)) {
1308 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1309 			    "FC_TGT_PORT_RLS: Buffer too small. %d < %d",
1310 			    *size, sizeof (fct_port_link_status_t));
1311 
1312 			rval = FCT_FAILURE;
1313 			break;
1314 		}
1315 
1316 		if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX)) == 0) {
1317 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1318 			    "FC_TGT_PORT_RLS: Unable to allocate mailbox.");
1319 
1320 			rval = FCT_ALLOC_FAILURE;
1321 			break;
1322 		}
1323 		mb = (MAILBOX *)mbq;
1324 
1325 		emlxs_mb_read_lnk_stat(hba, mbq);
1326 		if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0)
1327 		    != MBX_SUCCESS) {
1328 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1329 			    "FC_TGT_PORT_RLS: Unable to send request.");
1330 
1331 			rval = FCT_BUSY;
1332 		} else {
1333 			link_status = (fct_port_link_status_t *)buffer;
1334 			link_status->LinkFailureCount =
1335 			    mb->un.varRdLnk.linkFailureCnt;
1336 			link_status->LossOfSyncCount =
1337 			    mb->un.varRdLnk.lossSyncCnt;
1338 			link_status->LossOfSignalsCount =
1339 			    mb->un.varRdLnk.lossSignalCnt;
1340 			link_status->PrimitiveSeqProtocolErrorCount =
1341 			    mb->un.varRdLnk.primSeqErrCnt;
1342 			link_status->InvalidTransmissionWordCount =
1343 			    mb->un.varRdLnk.invalidXmitWord;
1344 			link_status->InvalidCRCCount =
1345 			    mb->un.varRdLnk.crcCnt;
1346 		}
1347 
1348 		emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
1349 		break;
1350 
1351 	default:
1352 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1353 		    "fct_port_info: Invalid request. cmd=%x",
1354 		    cmd);
1355 
1356 		rval = FCT_FAILURE;
1357 		break;
1358 
1359 	}
1360 
1361 	return (rval);
1362 
1363 } /* emlxs_fct_port_info() */
1364 
1365 
1366 /* COMSTAR ENTER POINT */
1367 static void
1368 emlxs_fct_populate_hba_details(fct_local_port_t *fct_port,
1369     fct_port_attrs_t *port_attrs)
1370 {
1371 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1372 	emlxs_hba_t *hba = HBA;
1373 	emlxs_vpd_t *vpd = &VPD;
1374 
1375 	(void) strncpy(port_attrs->manufacturer,
1376 	    hba->model_info.manufacturer,
1377 	    (sizeof (port_attrs->manufacturer)-1));
1378 	(void) strncpy(port_attrs->serial_number, vpd->serial_num,
1379 	    (sizeof (port_attrs->serial_number)-1));
1380 	(void) strncpy(port_attrs->model, hba->model_info.model,
1381 	    (sizeof (port_attrs->model)-1));
1382 	(void) strncpy(port_attrs->model_description,
1383 	    hba->model_info.model_desc,
1384 	    (sizeof (port_attrs->model_description)-1));
1385 	(void) snprintf(port_attrs->hardware_version,
1386 	    (sizeof (port_attrs->hardware_version)-1),
1387 	    "%x", vpd->biuRev);
1388 	(void) snprintf(port_attrs->driver_version,
1389 	    (sizeof (port_attrs->driver_version)-1),
1390 	    "%s (%s)", emlxs_version,
1391 	    emlxs_revision);
1392 	(void) strncpy(port_attrs->option_rom_version, vpd->fcode_version,
1393 	    (sizeof (port_attrs->option_rom_version)-1));
1394 	(void) snprintf(port_attrs->firmware_version,
1395 	    (sizeof (port_attrs->firmware_version)-1),
1396 	    "%s (%s)", vpd->fw_version,
1397 	    vpd->fw_label);
1398 	(void) strncpy(port_attrs->driver_name, DRIVER_NAME,
1399 	    (sizeof (port_attrs->driver_name)-1));
1400 	port_attrs->vendor_specific_id = (hba->model_info.device_id << 16) |
1401 	    hba->model_info.vendor_id;
1402 	port_attrs->supported_cos = LE_SWAP32(FC_NS_CLASS3);
1403 
1404 	port_attrs->max_frame_size = FF_FRAME_SIZE;
1405 
1406 	if (vpd->link_speed & LMT_32GB_CAPABLE) {
1407 		port_attrs->supported_speed |= PORT_SPEED_32G;
1408 	}
1409 	if (vpd->link_speed & LMT_16GB_CAPABLE) {
1410 		port_attrs->supported_speed |= PORT_SPEED_16G;
1411 	}
1412 	if (vpd->link_speed & LMT_10GB_CAPABLE) {
1413 		port_attrs->supported_speed |= PORT_SPEED_10G;
1414 	}
1415 	if (vpd->link_speed & LMT_8GB_CAPABLE) {
1416 		port_attrs->supported_speed |= PORT_SPEED_8G;
1417 	}
1418 	if (vpd->link_speed & LMT_4GB_CAPABLE) {
1419 		port_attrs->supported_speed |= PORT_SPEED_4G;
1420 	}
1421 	if (vpd->link_speed & LMT_2GB_CAPABLE) {
1422 		port_attrs->supported_speed |= PORT_SPEED_2G;
1423 	}
1424 	if (vpd->link_speed & LMT_1GB_CAPABLE) {
1425 		port_attrs->supported_speed |= PORT_SPEED_1G;
1426 	}
1427 
1428 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1429 	    "Port attr: manufacturer       = %s", port_attrs->manufacturer);
1430 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1431 	    "Port attr: serial_num         = %s", port_attrs->serial_number);
1432 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1433 	    "Port attr: model              = %s", port_attrs->model);
1434 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1435 	    "Port attr: model_description  = %s",
1436 	    port_attrs->model_description);
1437 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1438 	    "Port attr: hardware_version   = %s",
1439 	    port_attrs->hardware_version);
1440 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1441 	    "Port attr: driver_version     = %s", port_attrs->driver_version);
1442 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1443 	    "Port attr: option_rom_version = %s",
1444 	    port_attrs->option_rom_version);
1445 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1446 	    "Port attr: firmware_version   = %s",
1447 	    port_attrs->firmware_version);
1448 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1449 	    "Port attr: driver_name        = %s", port_attrs->driver_name);
1450 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1451 	    "Port attr: vendor_specific_id = 0x%x",
1452 	    port_attrs->vendor_specific_id);
1453 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1454 	    "Port attr: supported_cos      = 0x%x",
1455 	    port_attrs->supported_cos);
1456 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1457 	    "Port attr: supported_speed    = 0x%x",
1458 	    port_attrs->supported_speed);
1459 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1460 	    "Port attr: max_frame_size     = 0x%x",
1461 	    port_attrs->max_frame_size);
1462 
1463 	return;
1464 
1465 } /* emlxs_fct_populate_hba_details() */
1466 
1467 
1468 /* COMSTAR ENTER POINT */
1469 /* ARGSUSED */
1470 static void
1471 emlxs_fct_ctl(fct_local_port_t *fct_port, int cmd, void *arg)
1472 {
1473 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1474 	emlxs_hba_t *hba = HBA;
1475 	stmf_change_status_t st;
1476 
1477 	st.st_completion_status = FCT_SUCCESS;
1478 	st.st_additional_info = NULL;
1479 
1480 	switch (cmd) {
1481 	case FCT_CMD_PORT_ONLINE:
1482 		/* If the HBA is offline, we cannot bring the tgtport online */
1483 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1484 			st.st_completion_status = FCT_FAILURE;
1485 			MODSYM(fct_ctl) (fct_port->port_lport,
1486 			    FCT_CMD_PORT_ONLINE_COMPLETE, &st);
1487 			break;
1488 		}
1489 
1490 		if (port->fct_flags & FCT_STATE_PORT_ONLINE) {
1491 			st.st_completion_status = STMF_ALREADY;
1492 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1493 			    "STATE: ONLINE chk");
1494 		} else {
1495 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1496 			    "STATE: OFFLINE --> ONLINE");
1497 
1498 			port->fct_flags |= FCT_STATE_NOT_ACKED;
1499 			port->fct_flags |= FCT_STATE_PORT_ONLINE;
1500 
1501 			if ((port->vpi == 0) &&
1502 			    (port->mode == MODE_TARGET) &&
1503 			    (hba->state <= FC_LINK_DOWN)) {
1504 				/* Try to bring the link up */
1505 				(void) emlxs_reset_link(hba, 1, 1);
1506 			}
1507 
1508 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1509 			    "STATE: ONLINE");
1510 		}
1511 
1512 		MODSYM(fct_ctl) (fct_port->port_lport,
1513 		    FCT_CMD_PORT_ONLINE_COMPLETE, &st);
1514 		break;
1515 
1516 	case FCT_CMD_PORT_OFFLINE:
1517 		if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
1518 			st.st_completion_status = STMF_ALREADY;
1519 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1520 			    "STATE: OFFLINE chk");
1521 
1522 		} else {
1523 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1524 			    "STATE: ONLINE --> OFFLINE");
1525 
1526 			/* Take link down and flush */
1527 			emlxs_fct_link_down(port);
1528 			emlxs_fct_unsol_flush(port);
1529 
1530 			/* Declare this port offline now */
1531 			port->fct_flags |= FCT_STATE_NOT_ACKED;
1532 			port->fct_flags &= ~FCT_STATE_PORT_ONLINE;
1533 
1534 			if ((port->vpi == 0) &&
1535 			    (port->mode == MODE_TARGET) &&
1536 			    !(port->flag & EMLXS_INI_ENABLED)) {
1537 				/* Take link down and hold it down */
1538 				(void) emlxs_reset_link(hba, 0, 1);
1539 			}
1540 
1541 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1542 			    "STATE: OFFLINE");
1543 		}
1544 
1545 		MODSYM(fct_ctl) (fct_port->port_lport,
1546 		    FCT_CMD_PORT_OFFLINE_COMPLETE, &st);
1547 
1548 		break;
1549 
1550 	case FCT_ACK_PORT_OFFLINE_COMPLETE:
1551 		port->fct_flags &= ~FCT_STATE_NOT_ACKED;
1552 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1553 		    "STATE: OFFLINE ack");
1554 		break;
1555 
1556 	case FCT_ACK_PORT_ONLINE_COMPLETE:
1557 		port->fct_flags &= ~FCT_STATE_NOT_ACKED;
1558 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1559 		    "STATE: ONLINE ack");
1560 		break;
1561 
1562 	case FCT_CMD_FORCE_LIP:
1563 		if (port->mode == MODE_INITIATOR) {
1564 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1565 			    "fct_ctl: FCT_CMD_FORCE_LIP.");
1566 			break;
1567 		}
1568 
1569 		if (hba->fw_flag & FW_UPDATE_NEEDED) {
1570 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1571 			    "fct_ctl: FCT_CMD_FORCE_LIP -> "
1572 			    "FCT_CMD_RESET");
1573 
1574 			hba->fw_flag |= FW_UPDATE_KERNEL;
1575 
1576 			/* Reset the adapter */
1577 			(void) emlxs_reset(port, FC_FCA_RESET);
1578 		} else {
1579 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1580 			    "fct_ctl: FCT_CMD_FORCE_LIP");
1581 
1582 			/* Reset the link */
1583 			(void) emlxs_reset(port, FC_FCA_LINK_RESET);
1584 		}
1585 		break;
1586 	}
1587 
1588 	return;
1589 
1590 } /* emlxs_fct_ctl() */
1591 
1592 
1593 extern int
1594 emlxs_fct_port_shutdown(emlxs_port_t *port)
1595 {
1596 	fct_local_port_t *fct_port;
1597 	int i;
1598 
1599 	fct_port = port->fct_port;
1600 	if (!fct_port) {
1601 		return (0);
1602 	}
1603 
1604 	port->fct_flags |= FCT_STATE_NOT_ACKED;
1605 
1606 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg, "fct_port_shutdown");
1607 	MODSYM(fct_port_shutdown) (fct_port, STMF_RFLAG_STAY_OFFLINED,
1608 	    DRIVER_NAME" shutdown");
1609 
1610 	i = 0;
1611 	while (port->fct_flags & FCT_STATE_NOT_ACKED) {
1612 		i++;
1613 		if (i > 300) {	/* 30 seconds */
1614 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1615 			    "fct_port_shutdown failed to ACK");
1616 			break;
1617 		}
1618 		delay(drv_usectohz(100000));	/* 100 msec */
1619 	}
1620 	return (1);
1621 }
1622 
1623 
1624 extern int
1625 emlxs_fct_port_initialize(emlxs_port_t *port)
1626 {
1627 	fct_local_port_t *fct_port;
1628 	int i;
1629 
1630 	fct_port = port->fct_port;
1631 	if (!fct_port) {
1632 		return (0);
1633 	}
1634 
1635 	port->fct_flags |= FCT_STATE_NOT_ACKED;
1636 
1637 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1638 	    "fct_port_initialize");
1639 	MODSYM(fct_port_initialize) (fct_port, STMF_RFLAG_STAY_OFFLINED,
1640 	    DRIVER_NAME" initialize");
1641 
1642 	i = 0;
1643 	while (port->fct_flags & FCT_STATE_NOT_ACKED) {
1644 		i++;
1645 		if (i > 300) {	/* 30 seconds */
1646 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1647 			    "fct_port_initialize failed to ACK");
1648 			break;
1649 		}
1650 		delay(drv_usectohz(100000));	/* 100 msec */
1651 	}
1652 	return (1);
1653 }
1654 
1655 
1656 /* COMSTAR ENTER POINT */
1657 static fct_status_t
1658 emlxs_fct_send_cmd(fct_cmd_t *fct_cmd)
1659 {
1660 	emlxs_port_t *port;
1661 
1662 	port = (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
1663 
1664 #ifdef FCT_API_TRACE
1665 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1666 	    "fct_send_cmd %p:%p  x%x", fct_cmd,
1667 	    fct_cmd->cmd_fca_private, fct_cmd->cmd_type);
1668 #endif /* FCT_API_TRACE */
1669 
1670 	switch (fct_cmd->cmd_type) {
1671 	case FCT_CMD_SOL_ELS:
1672 
1673 		return (emlxs_fct_send_els_cmd(fct_cmd));
1674 
1675 	case FCT_CMD_SOL_CT:
1676 
1677 		return (emlxs_fct_send_ct_cmd(fct_cmd));
1678 
1679 	default:
1680 
1681 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1682 		    "fct_send_cmd: Invalid cmd type found. type=%x",
1683 		    fct_cmd->cmd_type);
1684 
1685 		return (FCT_FAILURE);
1686 	}
1687 
1688 } /* emlxs_fct_send_cmd() */
1689 
1690 
1691 /* COMSTAR ENTER POINT */
1692 static fct_status_t
1693 emlxs_fct_send_cmd_rsp(fct_cmd_t *fct_cmd, uint32_t ioflags)
1694 {
1695 	emlxs_port_t *port;
1696 	emlxs_buf_t *cmd_sbp;
1697 	fct_status_t rval;
1698 	IOCBQ *iocbq;
1699 	IOCB *iocb;
1700 	uint32_t status;
1701 
1702 	port = (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
1703 
1704 	rval = emlxs_fct_cmd_accept(port, fct_cmd, EMLXS_FCT_SEND_CMD_RSP);
1705 	if (rval) {
1706 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1707 		    "fct_send_cmd_rsp: "
1708 		    "Unable to accept fct_cmd. type=%x",
1709 		    fct_cmd->cmd_type);
1710 
1711 		return (rval);
1712 	}
1713 	/* mutex_enter(&cmd_sbp->fct_mtx); */
1714 
1715 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
1716 	iocbq = &cmd_sbp->iocbq;
1717 	iocbq->sbp = cmd_sbp;
1718 	iocb = &iocbq->iocb;
1719 	status = iocb->ULPSTATUS;
1720 
1721 #ifdef FCT_API_TRACE
1722 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1723 	    "fct_send_cmd_rsp %p:%p x%x, %x, %x",
1724 	    fct_cmd, cmd_sbp, fct_cmd->cmd_type, iocb->ULPCT, status);
1725 #endif /* FCT_API_TRACE */
1726 
1727 	switch (fct_cmd->cmd_type) {
1728 	case FCT_CMD_FCP_XCHG:
1729 
1730 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1731 			goto failure;
1732 		}
1733 
1734 		if ((iocb->ULPCT == 0x1) && (status == 0)) {
1735 
1736 			/* Firmware already sent out resp */
1737 			cmd_sbp->fct_flags |= EMLXS_FCT_SEND_STATUS;
1738 
1739 			TGTPORTSTAT.FctOutstandingIO--;
1740 
1741 			emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
1742 			/* mutex_exit(&cmd_sbp->fct_mtx); */
1743 
1744 #ifdef FCT_API_TRACE
1745 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1746 			    "fct_send_response_done:4 %p: x%x",
1747 			    fct_cmd, fct_cmd->cmd_comp_status);
1748 
1749 #endif /* FCT_API_TRACE */
1750 
1751 			MODSYM(fct_send_response_done) (fct_cmd,
1752 			    fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
1753 
1754 			return (FCT_SUCCESS);
1755 		}
1756 
1757 		rval =  emlxs_fct_send_fcp_status(fct_cmd);
1758 		if (rval == FCT_NOT_FOUND) {
1759 			goto failure;
1760 		}
1761 		/* mutex_exit(&cmd_sbp->fct_mtx); */
1762 
1763 		return (rval);
1764 
1765 	case FCT_CMD_RCVD_ELS:
1766 
1767 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1768 			goto failure;
1769 		}
1770 
1771 		rval =  emlxs_fct_send_els_rsp(fct_cmd);
1772 		/* mutex_exit(&cmd_sbp->fct_mtx); */
1773 
1774 		return (rval);
1775 
1776 	default:
1777 
1778 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1779 			fct_cmd->cmd_handle = 0;
1780 		}
1781 
1782 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1783 		    "fct_send_cmd_rsp: Invalid cmd type found. type=%x",
1784 		    fct_cmd->cmd_type);
1785 
1786 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
1787 		/* mutex_exit(&cmd_sbp->fct_mtx); */
1788 
1789 		return (FCT_FAILURE);
1790 	}
1791 
1792 failure:
1793 
1794 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1795 	    "fct_send_cmd_rsp: "
1796 	    "Unable to handle FCT_IOF_FORCE_FCA_DONE. type=%x",
1797 	    fct_cmd->cmd_type);
1798 
1799 	emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
1800 	/* mutex_exit(&cmd_sbp->fct_mtx); */
1801 
1802 	return (FCT_FAILURE);
1803 
1804 } /* emlxs_fct_send_cmd_rsp() */
1805 
1806 
1807 /* COMSTAR ENTER POINT */
1808 static fct_status_t
1809 emlxs_fct_flogi_xchg(struct fct_local_port *fct_port, struct fct_flogi_xchg *fx)
1810 {
1811 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1812 	emlxs_hba_t *hba = HBA;
1813 	uint32_t size;
1814 	fc_packet_t *pkt = NULL;
1815 	ELS_PKT *els;
1816 	fct_status_t rval = FCT_SUCCESS;
1817 
1818 #ifdef FCT_API_TRACE
1819 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1820 	    "fct_flogi_xchg: Sending FLOGI: %p", fct_port);
1821 #else
1822 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1823 	    "fct_flogi_xchg: Sending FLOGI.");
1824 #endif /* FCT_API_TRACE */
1825 
1826 	if (hba->state <= FC_LINK_DOWN) {
1827 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1828 		    "fct_flogi_xchg: FLOGI failed. Link down.");
1829 		rval = FCT_FAILURE;
1830 		goto done;
1831 	}
1832 
1833 	/* Use this entry point as the link up acknowledgment */
1834 	mutex_enter(&EMLXS_PORT_LOCK);
1835 	port->fct_flags |= FCT_STATE_LINK_UP_ACKED;
1836 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1837 	    "fct_link_up acked.");
1838 	mutex_exit(&EMLXS_PORT_LOCK);
1839 
1840 	/* First handle any pending FLOGI's */
1841 	emlxs_fct_handle_unsol_flogi(port, NULL, 0);
1842 
1843 	size = sizeof (SERV_PARM) + 4;
1844 
1845 	if (!(pkt = emlxs_pkt_alloc(port, size, size, 0, KM_NOSLEEP))) {
1846 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1847 		    "fct_flogi_xchg: FLOGI failed. "
1848 		    "Unable allocate packet.");
1849 		rval = FCT_FAILURE;
1850 		goto done;
1851 	}
1852 
1853 	/* Make this a polled IO */
1854 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
1855 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
1856 	pkt->pkt_comp = NULL;
1857 
1858 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
1859 	pkt->pkt_timeout = fx->fx_sec_timeout;
1860 
1861 	/* Build the fc header */
1862 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(fx->fx_did);
1863 	pkt->pkt_cmd_fhdr.r_ctl =
1864 	    R_CTL_EXTENDED_SVC | R_CTL_SOLICITED_CONTROL;
1865 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(fx->fx_sid);
1866 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
1867 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE;
1868 	pkt->pkt_cmd_fhdr.seq_id = 0;
1869 	pkt->pkt_cmd_fhdr.df_ctl = 0;
1870 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
1871 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
1872 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
1873 	pkt->pkt_cmd_fhdr.ro = 0;
1874 
1875 	/* Build the command */
1876 	/* Service paramters will be added automatically later by the driver */
1877 	els = (ELS_PKT *)pkt->pkt_cmd;
1878 	els->elsCode = 0x04;	/* FLOGI */
1879 
1880 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
1881 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1882 		    "fct_flogi_xchg: FLOGI failed. "
1883 		    "Unable to send packet.");
1884 
1885 		rval = FCT_FAILURE;
1886 		goto done;
1887 	}
1888 
1889 	if ((pkt->pkt_state != FC_PKT_SUCCESS) &&
1890 	    (pkt->pkt_state != FC_PKT_LS_RJT)) {
1891 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
1892 			rval = FCT_TIMEOUT;
1893 		} else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
1894 		    (pkt->pkt_reason == FC_REASON_FCAL_OPN_FAIL)) {
1895 			rval = FCT_NOT_FOUND;
1896 		} else {
1897 			rval = FCT_FAILURE;
1898 		}
1899 
1900 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1901 		    "fct_flogi_xchg: FLOGI failed. state=%x reason=%x "
1902 		    "rval=%llx", pkt->pkt_state, pkt->pkt_reason, rval);
1903 
1904 		goto done;
1905 	}
1906 
1907 	if (pkt->pkt_state == FC_PKT_LS_RJT) {
1908 		fx->fx_op = ELS_OP_LSRJT;
1909 		fx->fx_rjt_reason = pkt->pkt_reason;
1910 		fx->fx_rjt_expl = pkt->pkt_expln;
1911 	} else {	/* FC_PKT_SUCCESS */
1912 
1913 		fx->fx_op = ELS_OP_ACC;
1914 		fx->fx_sid = FABRIC_DID;
1915 		fx->fx_did = port->did;
1916 
1917 		els = (ELS_PKT *)pkt->pkt_resp;
1918 		bcopy((caddr_t)&els->un.logi.nodeName,
1919 		    (caddr_t)fx->fx_nwwn, 8);
1920 		bcopy((caddr_t)&els->un.logi.portName,
1921 		    (caddr_t)fx->fx_pwwn, 8);
1922 		fx->fx_fport = els->un.logi.cmn.fPort;
1923 	}
1924 
1925 done:
1926 	if (pkt) {
1927 		emlxs_pkt_free(pkt);
1928 	}
1929 
1930 	if ((rval == FCT_SUCCESS) || (rval == FCT_NOT_FOUND)) {
1931 
1932 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1933 		    "fct_flogi_xchg: FCT_STATE_FLOGI_CMPL.  rval=%s",
1934 		    ((rval == FCT_SUCCESS)? "FCT_SUCCESS":"FCT_NOT_FOUND"));
1935 
1936 		mutex_enter(&EMLXS_PORT_LOCK);
1937 		port->fct_flags |= FCT_STATE_FLOGI_CMPL;
1938 		mutex_exit(&EMLXS_PORT_LOCK);
1939 
1940 		/*
1941 		 * Flush all unsolicited commands
1942 		 * Must use separate thread since
1943 		 * this thread must complete first
1944 		 */
1945 		emlxs_thread_spawn(hba, emlxs_fct_unsol_flush_thread,
1946 		    (void *)port, 0);
1947 	}
1948 
1949 	return (rval);
1950 
1951 } /* emlxs_fct_flogi_xchg() */
1952 
1953 
1954 /* COMSTAR ENTER POINT */
1955 /* This is called right after we report that link has come online */
1956 static fct_status_t
1957 emlxs_fct_get_link_info(fct_local_port_t *fct_port, fct_link_info_t *link)
1958 {
1959 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1960 	emlxs_hba_t *hba = HBA;
1961 
1962 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1963 	    "fct_get_link_info %p: FCT: flg x%x  HBA: ste x%x flg x%x topo x%x",
1964 	    fct_port, port->fct_flags, hba->state, hba->flag, hba->topology);
1965 
1966 	mutex_enter(&EMLXS_PORT_LOCK);
1967 
1968 	if (port->mode == MODE_INITIATOR) {
1969 		link->port_topology = PORT_TOPOLOGY_UNKNOWN;
1970 		link->port_speed = PORT_SPEED_UNKNOWN;
1971 		link->portid = 0;
1972 
1973 		mutex_exit(&EMLXS_PORT_LOCK);
1974 
1975 		return (FCT_SUCCESS);
1976 	}
1977 
1978 	if (!(port->fct_flags & FCT_STATE_LINK_UP) ||
1979 	    (hba->state < FC_LINK_UP) || (hba->flag & FC_LOOPBACK_MODE)) {
1980 		link->port_topology = PORT_TOPOLOGY_UNKNOWN;
1981 		link->port_speed = PORT_SPEED_UNKNOWN;
1982 		link->portid = 0;
1983 
1984 		mutex_exit(&EMLXS_PORT_LOCK);
1985 
1986 		return (FCT_SUCCESS);
1987 	}
1988 
1989 	if (hba->topology == TOPOLOGY_LOOP) {
1990 		link->port_topology = PORT_TOPOLOGY_PRIVATE_LOOP;
1991 	} else {
1992 		link->port_topology = PORT_TOPOLOGY_PT_TO_PT;
1993 	}
1994 
1995 	switch (hba->linkspeed) {
1996 	case LA_1GHZ_LINK:
1997 		link->port_speed = PORT_SPEED_1G;
1998 		break;
1999 	case LA_2GHZ_LINK:
2000 		link->port_speed = PORT_SPEED_2G;
2001 		break;
2002 	case LA_4GHZ_LINK:
2003 		link->port_speed = PORT_SPEED_4G;
2004 		break;
2005 	case LA_8GHZ_LINK:
2006 		link->port_speed = PORT_SPEED_8G;
2007 		break;
2008 	case LA_10GHZ_LINK:
2009 		link->port_speed = PORT_SPEED_10G;
2010 		break;
2011 	case LA_16GHZ_LINK:
2012 		link->port_speed = PORT_SPEED_16G;
2013 		break;
2014 	case LA_32GHZ_LINK:
2015 		link->port_speed = PORT_SPEED_32G;
2016 		break;
2017 	default:
2018 		link->port_speed = PORT_SPEED_UNKNOWN;
2019 		break;
2020 	}
2021 
2022 	link->portid = port->did;
2023 	link->port_no_fct_flogi = 0;
2024 	link->port_fca_flogi_done = 0;
2025 	link->port_fct_flogi_done = 0;
2026 
2027 	mutex_exit(&EMLXS_PORT_LOCK);
2028 
2029 	return (FCT_SUCCESS);
2030 
2031 } /* emlxs_fct_get_link_info() */
2032 
2033 
2034 /* COMSTAR ENTER POINT */
2035 static fct_status_t
2036 emlxs_fct_register_remote_port(fct_local_port_t *fct_port,
2037     fct_remote_port_t *remote_port, fct_cmd_t *fct_cmd)
2038 {
2039 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
2040 	emlxs_hba_t *hba = HBA;
2041 	emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2042 	clock_t timeout;
2043 	int32_t pkt_ret;
2044 	fct_els_t *els;
2045 	SERV_PARM *sp;
2046 	emlxs_node_t *ndlp;
2047 	SERV_PARM sparam;
2048 	uint32_t *iptr;
2049 	uint16_t hdl;
2050 	uint64_t addr;
2051 	fct_status_t rval;
2052 	fct_status_t rval2;
2053 	uint32_t i;
2054 
2055 #ifdef FCT_API_TRACE
2056 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2057 	    "fct_register_remote_port %p", fct_port);
2058 #endif /* FCT_API_TRACE */
2059 
2060 	if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
2061 
2062 		cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd,
2063 		    EMLXS_FCT_REG_PENDING);
2064 		/* mutex_enter(&cmd_sbp->fct_mtx); */
2065 
2066 		cmd_sbp->channel = &hba->chan[hba->channel_els];
2067 		cmd_sbp->fct_type = EMLXS_FCT_ELS_CMD;
2068 
2069 	} else {
2070 
2071 		rval = emlxs_fct_cmd_accept(port, fct_cmd,
2072 		    EMLXS_FCT_REG_PENDING);
2073 		if (rval) {
2074 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2075 			    "fct_register_remote_port: "
2076 			    "Unable to accept fct_cmd. lid=%x rid=%x",
2077 			    fct_cmd->cmd_lportid, fct_cmd->cmd_rportid);
2078 
2079 			return (rval);
2080 		}
2081 		/* mutex_enter(&cmd_sbp->fct_mtx); */
2082 	}
2083 
2084 	cmd_sbp->fct_flags &= ~EMLXS_FCT_REGISTERED;
2085 	cmd_sbp->node = emlxs_node_find_did(port, fct_cmd->cmd_rportid, 1);
2086 
2087 	/* Check for unsolicited PLOGI */
2088 	if (cmd_sbp->fct_flags & EMLXS_FCT_PLOGI_RECEIVED) {
2089 		els = (fct_els_t *)fct_cmd->cmd_specific;
2090 		sp = (SERV_PARM *)((caddr_t)els->els_req_payload +
2091 		    sizeof (uint32_t));
2092 
2093 	} else {	/* Solicited PLOGI */
2094 
2095 		sp = &sparam;
2096 		bcopy((caddr_t)&port->sparam, (caddr_t)sp,
2097 		    sizeof (SERV_PARM));
2098 
2099 		/*
2100 		 * Create temporary WWN's from fct_cmd address
2101 		 * This simply allows us to get an RPI from the
2102 		 * adapter until we get real service params.
2103 		 * The PLOGI ACC reply will trigger a REG_LOGIN
2104 		 * update later
2105 		 */
2106 		addr = (uint64_t)((unsigned long)fct_cmd);
2107 
2108 		iptr = (uint32_t *)&sp->portName;
2109 		iptr[0] = PADDR_HI(addr);
2110 		iptr[1] = PADDR_LO(addr);
2111 
2112 		iptr = (uint32_t *)&sp->nodeName;
2113 		iptr[0] = PADDR_HI(addr);
2114 		iptr[1] = PADDR_LO(addr);
2115 	}
2116 
2117 	if (hba->flag & FC_PT_TO_PT) {
2118 		mutex_enter(&EMLXS_PORT_LOCK);
2119 		port->did = fct_cmd->cmd_lportid;
2120 		port->rdid = fct_cmd->cmd_rportid;
2121 		mutex_exit(&EMLXS_PORT_LOCK);
2122 
2123 		/*
2124 		 * We already received the remote port's
2125 		 * parameters in the FLOGI exchange
2126 		 */
2127 		if (!(cmd_sbp->fct_flags & EMLXS_FCT_PLOGI_RECEIVED)) {
2128 			sp = &sparam;
2129 			bcopy((caddr_t)&port->fabric_sparam, (caddr_t)sp,
2130 			    sizeof (SERV_PARM));
2131 
2132 			/*
2133 			 * Since this is a PLOGI, not a FLOGI, we need
2134 			 * to fix up word2 of the CSP accordingly.
2135 			 */
2136 			sp->cmn.w2.r_a_tov = port->sparam.cmn.w2.r_a_tov;
2137 		}
2138 	}
2139 
2140 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
2141 	    "fct_register_remote_port: Register lid=%x rid=%x. (%x,%x,%p)",
2142 	    fct_cmd->cmd_lportid, fct_cmd->cmd_rportid, cmd_sbp->fct_state,
2143 	    hba->flag, fct_cmd);
2144 
2145 	emlxs_fct_cmd_release(port, fct_cmd, 0);
2146 	/* mutex_exit(&cmd_sbp->fct_mtx); */
2147 
2148 	/* Create a new node */
2149 	if (EMLXS_SLI_REG_DID(port, fct_cmd->cmd_rportid, sp, cmd_sbp,
2150 	    NULL, NULL) != 0) {
2151 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2152 		    "fct_register_remote_port: "
2153 		    "Reg login failed. lid=%x rid=%x",
2154 		    fct_cmd->cmd_lportid, fct_cmd->cmd_rportid);
2155 	} else {
2156 
2157 		/* Wait for completion */
2158 		mutex_enter(&EMLXS_PKT_LOCK);
2159 		timeout = emlxs_timeout(hba, 30);
2160 		pkt_ret = 0;
2161 		while ((pkt_ret != -1) &&
2162 		    (cmd_sbp->fct_state == EMLXS_FCT_REG_PENDING) &&
2163 		    !(cmd_sbp->fct_flags & EMLXS_FCT_REGISTERED)) {
2164 			pkt_ret = cv_timedwait(&EMLXS_PKT_CV,
2165 			    &EMLXS_PKT_LOCK, timeout);
2166 		}
2167 		mutex_exit(&EMLXS_PKT_LOCK);
2168 	}
2169 
2170 	/* Reacquire ownership of the fct_cmd */
2171 	rval2 = emlxs_fct_cmd_acquire(port, fct_cmd,
2172 	    EMLXS_FCT_REG_COMPLETE);
2173 	if (rval2) {
2174 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2175 		    "fct_register_remote_port: "
2176 		    "Unable to reacquire fct_cmd. lid=%x rid=%x",
2177 		    fct_cmd->cmd_lportid, fct_cmd->cmd_rportid);
2178 
2179 		return (rval2);
2180 	}
2181 	/* mutex_enter(&cmd_sbp->fct_mtx); */
2182 
2183 	/* Prepare response */
2184 
2185 	ndlp = (emlxs_node_t *)cmd_sbp->node;
2186 
2187 	if (ndlp) {
2188 		cmd_sbp->fct_flags |= EMLXS_FCT_REGISTERED;
2189 
2190 		*((emlxs_node_t **)remote_port->rp_fca_private) =
2191 		    cmd_sbp->node;
2192 
2193 		hdl = ndlp->nlp_Rpi;
2194 		if (hdl == FABRIC_RPI) {
2195 			if (fct_cmd->cmd_rportid == SCR_DID) {
2196 				/* The SCR handle is hardcoded */
2197 				remote_port->rp_handle = hba->max_nodes;
2198 				port->fct_els_only_bmap |= 1;
2199 
2200 			} else {
2201 				for (i = 1; i < EMLXS_FCT_NUM_ELS_ONLY; i++) {
2202 					if (port->fct_els_only_bmap & (1 << i))
2203 						continue;
2204 					/*
2205 					 * Bit is not set, so use this
2206 					 * for the handle
2207 					 */
2208 					remote_port->rp_handle =
2209 					    hba->max_nodes + i;
2210 					port->fct_els_only_bmap |= (1 << i);
2211 					break;
2212 				}
2213 				if (i >= EMLXS_FCT_NUM_ELS_ONLY) {
2214 					remote_port->rp_handle =
2215 					    FCT_HANDLE_NONE;
2216 				}
2217 			}
2218 		} else {
2219 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2220 				hdl = emlxs_sli4_rpi_to_index(hba, hdl);
2221 			}
2222 			remote_port->rp_handle = hdl;
2223 		}
2224 
2225 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2226 		    "fct_register_remote_port: lid=%x rid=%x hdl=%x",
2227 		    fct_cmd->cmd_lportid, fct_cmd->cmd_rportid,
2228 		    remote_port->rp_handle);
2229 
2230 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2231 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2232 
2233 		TGTPORTSTAT.FctPortRegister++;
2234 		return (FCT_SUCCESS);
2235 	} else {
2236 		*((emlxs_node_t **)remote_port->rp_fca_private) = NULL;
2237 
2238 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2239 		    "fct_register_remote_port: failed. lid=%x rid=%x hdl=%x",
2240 		    fct_cmd->cmd_lportid, fct_cmd->cmd_rportid,
2241 		    remote_port->rp_handle);
2242 
2243 		remote_port->rp_handle = FCT_HANDLE_NONE;
2244 
2245 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2246 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2247 
2248 		TGTPORTSTAT.FctFailedPortRegister++;
2249 		return (FCT_FAILURE);
2250 	}
2251 
2252 } /* emlxs_fct_register_remote_port() */
2253 
2254 
2255 /* COMSTAR ENTER POINT */
2256 static fct_status_t
2257 emlxs_fct_deregister_remote_port(fct_local_port_t *fct_port,
2258     fct_remote_port_t *remote_port)
2259 {
2260 	emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
2261 	emlxs_hba_t *hba = HBA;
2262 	emlxs_node_t *ndlp;
2263 	uint32_t i;
2264 
2265 #ifdef FCT_API_TRACE
2266 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2267 	    "fct_deregister_remote_port: did=%x hdl=%x",
2268 	    remote_port->rp_id, remote_port->rp_handle);
2269 #else
2270 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2271 	    "fct_deregister_remote_port: did=%x hdl=%x",
2272 	    remote_port->rp_id, remote_port->rp_handle);
2273 #endif /* FCT_API_TRACE */
2274 
2275 	if (remote_port->rp_handle >= hba->max_nodes) {
2276 		i = remote_port->rp_handle - hba->max_nodes;
2277 		if ((i < EMLXS_FCT_NUM_ELS_ONLY) &&
2278 		    (port->fct_els_only_bmap & (1 << i))) {
2279 			port->fct_els_only_bmap &= ~(1 << i);
2280 		}
2281 	}
2282 
2283 	ndlp = *((emlxs_node_t **)remote_port->rp_fca_private);
2284 	*((emlxs_node_t **)remote_port->rp_fca_private) = NULL;
2285 
2286 	if (ndlp) {
2287 		(void) EMLXS_SLI_UNREG_NODE(port, ndlp, NULL,
2288 		    NULL, NULL);
2289 	}
2290 
2291 	TGTPORTSTAT.FctPortDeregister++;
2292 	return (FCT_SUCCESS);
2293 
2294 } /* emlxs_fct_deregister_remote_port() */
2295 
2296 
2297 /* ARGSUSED */
2298 extern int
2299 emlxs_fct_handle_unsol_req(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
2300     MATCHMAP *mp, uint32_t size)
2301 {
2302 	emlxs_hba_t *hba = HBA;
2303 	IOCB *iocb;
2304 	fct_cmd_t *fct_cmd;
2305 	emlxs_buf_t *cmd_sbp;
2306 	emlxs_fcp_cmd_t *fcp_cmd;
2307 	emlxs_node_t *ndlp;
2308 	uint32_t cnt;
2309 	uint32_t tm;
2310 	uint16_t hdl;
2311 	scsi_task_t *fct_task;
2312 	uint8_t lun[8];
2313 	uint32_t sid = 0;
2314 
2315 	iocb = &iocbq->iocb;
2316 	ndlp = emlxs_node_find_rpi(port, iocb->ULPIOTAG);
2317 	if (!ndlp) {
2318 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2319 		    "FCP rcvd: Unknown RPI. rpi=%d rxid=%x. Dropping...",
2320 		    iocb->ULPIOTAG, iocb->ULPCONTEXT);
2321 
2322 		goto dropped;
2323 	}
2324 	sid = ndlp->nlp_DID;
2325 
2326 	fcp_cmd = (emlxs_fcp_cmd_t *)mp->virt;
2327 
2328 	if (!port->fct_port) {
2329 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2330 		    "FCP rcvd: Target unbound. rpi=%d rxid=%x. Dropping...",
2331 		    iocb->ULPIOTAG, iocb->ULPCONTEXT);
2332 
2333 		emlxs_send_logo(port, sid);
2334 
2335 		goto dropped;
2336 	}
2337 
2338 	if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
2339 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2340 		    "FCP rcvd: Target offline. rpi=%d rxid=%x. Dropping...",
2341 		    iocb->ULPIOTAG, iocb->ULPCONTEXT);
2342 
2343 		emlxs_send_logo(port, sid);
2344 
2345 		goto dropped;
2346 	}
2347 
2348 	/* Get lun id */
2349 	bcopy((void *)&fcp_cmd->fcpLunMsl, lun, 8);
2350 
2351 	if (TGTPORTSTAT.FctOutstandingIO >= port->fct_port->port_max_xchges) {
2352 		TGTPORTSTAT.FctOverQDepth++;
2353 	}
2354 
2355 	hdl = ndlp->nlp_Rpi;
2356 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2357 		hdl = emlxs_sli4_rpi_to_index(hba, hdl);
2358 	}
2359 	fct_cmd =
2360 	    MODSYM(fct_scsi_task_alloc) (port->fct_port, hdl, sid, lun, 16, 0);
2361 
2362 	if (fct_cmd == NULL) {
2363 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2364 		    "FCP rcvd: sid=%x xid=%x. "
2365 		    "Unable to allocate scsi task. Returning QFULL.",
2366 		    sid, iocb->ULPCONTEXT);
2367 
2368 		(void) emlxs_fct_send_qfull_reply(port, ndlp, iocb->ULPCONTEXT,
2369 		    iocb->ULPCLASS, fcp_cmd);
2370 
2371 		goto dropped;
2372 	}
2373 
2374 	/* Initialize fct_cmd */
2375 	fct_cmd->cmd_rportid = sid;
2376 	fct_cmd->cmd_lportid = port->did;
2377 	fct_cmd->cmd_rp_handle = hdl;
2378 	fct_cmd->cmd_port = port->fct_port;
2379 
2380 	cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_FCP_CMD_RECEIVED);
2381 	/* mutex_enter(&cmd_sbp->fct_mtx); */
2382 
2383 #ifdef FCT_API_TRACE
2384 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2385 	    "fct_scsi_task_alloc %p:%p FCP rcvd: "
2386 	    "cmd=%x sid=%x rxid=%x oxid=%x lun=%02x%02x dl=%d",
2387 	    fct_cmd, cmd_sbp, fcp_cmd->fcpCdb[0], sid, iocb->ULPCONTEXT,
2388 	    iocb->unsli3.ext_rcv.oxid, lun[0], lun[1],
2389 	    LE_SWAP32(fcp_cmd->fcpDl));
2390 #endif /* FCT_API_TRACE */
2391 
2392 	/* Initialize cmd_sbp */
2393 	cmd_sbp->channel = cp;
2394 	cmd_sbp->class = iocb->ULPCLASS;
2395 	cmd_sbp->lun = (lun[0] << 8) | lun[1];
2396 	cmd_sbp->fct_type = EMLXS_FCT_FCP_CMD;
2397 	cmd_sbp->ticks = hba->timer_tics + (2 * hba->fc_ratov);
2398 
2399 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2400 		/* xrip was setup / passed in from the SLI layer */
2401 		cmd_sbp->xrip = iocbq->sbp;
2402 		cmd_sbp->node = iocbq->node;
2403 		iocbq->sbp = 0;
2404 
2405 		fct_cmd->cmd_oxid = cmd_sbp->xrip->rx_id;
2406 		fct_cmd->cmd_rxid = cmd_sbp->xrip->XRI;
2407 
2408 #ifdef FCT_API_TRACE
2409 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2410 		    "FCP rcvd: oxid=%x rxid=%x iotag=%d %p ",
2411 		    fct_cmd->cmd_oxid, fct_cmd->cmd_rxid, cmd_sbp->xrip->iotag,
2412 		    hba->fc_table[cmd_sbp->xrip->iotag]);
2413 #endif /* FCT_API_TRACE */
2414 
2415 	} else {
2416 		fct_cmd->cmd_oxid = iocb->unsli3.ext_rcv.oxid;
2417 		if (!fct_cmd->cmd_oxid) {
2418 			fct_cmd->cmd_oxid = 0xFFFF;
2419 		}
2420 		fct_cmd->cmd_rxid = iocb->ULPCONTEXT;
2421 	}
2422 
2423 
2424 	fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
2425 
2426 	/* Set task_flags */
2427 	switch (fcp_cmd->fcpCntl1) {
2428 	case SIMPLE_Q:
2429 		fct_task->task_flags = TF_ATTR_SIMPLE_QUEUE;
2430 		break;
2431 
2432 	case HEAD_OF_Q:
2433 		fct_task->task_flags = TF_ATTR_HEAD_OF_QUEUE;
2434 		break;
2435 
2436 	case ORDERED_Q:
2437 		fct_task->task_flags = TF_ATTR_ORDERED_QUEUE;
2438 		break;
2439 
2440 	case ACA_Q:
2441 		fct_task->task_flags = TF_ATTR_ACA;
2442 		break;
2443 
2444 	case UNTAGGED:
2445 		fct_task->task_flags = TF_ATTR_UNTAGGED;
2446 		break;
2447 	}
2448 
2449 	cnt = LE_SWAP32(fcp_cmd->fcpDl);
2450 	switch (fcp_cmd->fcpCntl3) {
2451 	case 0:
2452 		TGTPORTSTAT.FctIOCmdCnt++;
2453 		break;
2454 	case 1:
2455 		EMLXS_BUMP_WRIOCTR(port, cnt);
2456 		TGTPORTSTAT.FctWriteBytes += cnt;
2457 		fct_task->task_flags |= TF_WRITE_DATA;
2458 		break;
2459 
2460 	case 2:
2461 		EMLXS_BUMP_RDIOCTR(port, cnt);
2462 		TGTPORTSTAT.FctReadBytes += cnt;
2463 		fct_task->task_flags |= TF_READ_DATA;
2464 		break;
2465 	}
2466 
2467 	fct_task->task_priority = 0;
2468 
2469 	/* task_mgmt_function */
2470 	tm = fcp_cmd->fcpCntl2;
2471 	if (tm) {
2472 		if (tm & BIT_1) {
2473 			fct_task->task_mgmt_function = TM_ABORT_TASK_SET;
2474 		} else if (tm & BIT_2) {
2475 			fct_task->task_mgmt_function = TM_CLEAR_TASK_SET;
2476 		} else if (tm & BIT_4) {
2477 			fct_task->task_mgmt_function = TM_LUN_RESET;
2478 		} else if (tm & BIT_5) {
2479 			fct_task->task_mgmt_function = TM_TARGET_COLD_RESET;
2480 		} else if (tm & BIT_6) {
2481 			fct_task->task_mgmt_function = TM_CLEAR_ACA;
2482 		} else {
2483 			fct_task->task_mgmt_function = TM_ABORT_TASK;
2484 		}
2485 	}
2486 
2487 	/* Parallel buffers support - future */
2488 	fct_task->task_max_nbufs = 1;
2489 
2490 	fct_task->task_additional_flags = 0;
2491 	fct_task->task_cur_nbufs = 0;
2492 	fct_task->task_csn_size = 8;
2493 	fct_task->task_cmd_seq_no = 0;
2494 	fct_task->task_expected_xfer_length = cnt;
2495 	bcopy((void *)&fcp_cmd->fcpCdb, fct_task->task_cdb, 16);
2496 
2497 	TGTPORTSTAT.FctCmdReceived++;
2498 	TGTPORTSTAT.FctOutstandingIO++;
2499 
2500 	emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2501 	/* mutex_exit(&cmd_sbp->fct_mtx); */
2502 
2503 #ifdef FCT_API_TRACE
2504 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2505 	    "fct_post_rcvd_cmd:3 %p:%p portid x%x, %d outio %d",
2506 	    fct_cmd, cmd_sbp, fct_cmd->cmd_lportid,
2507 	    fct_task->task_expected_xfer_length,
2508 	    TGTPORTSTAT.FctOutstandingIO);
2509 #endif /* FCT_API_TRACE */
2510 
2511 	MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
2512 
2513 	return (0);
2514 
2515 dropped:
2516 
2517 	TGTPORTSTAT.FctRcvDropped++;
2518 	return (1);
2519 
2520 } /* emlxs_fct_handle_unsol_req() */
2521 
2522 
2523 /* COMSTAR ENTER POINT */
2524 /* ARGSUSED */
2525 static fct_status_t
2526 emlxs_fct_send_fcp_data(fct_cmd_t *fct_cmd, stmf_data_buf_t *dbuf,
2527     uint32_t ioflags)
2528 {
2529 	emlxs_port_t *port =
2530 	    (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
2531 	emlxs_hba_t *hba = HBA;
2532 	emlxs_buf_t *cmd_sbp;
2533 #ifdef FCT_API_TRACE
2534 	scsi_task_t *fct_task;
2535 #endif /* FCT_API_TRACE */
2536 	IOCBQ *iocbq;
2537 	emlxs_node_t *ndlp;
2538 
2539 	int	channel;
2540 	int	channelno;
2541 	fct_status_t rval = 0;
2542 
2543 	rval = emlxs_fct_cmd_accept(port, fct_cmd, EMLXS_FCT_SEND_FCP_DATA);
2544 	if (rval) {
2545 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2546 		    "fct_send_fcp_data: "
2547 		    "Unable to accept fct_cmd. did=%x",
2548 		    fct_cmd->cmd_rportid);
2549 
2550 		return (rval);
2551 	}
2552 	/* mutex_enter(&cmd_sbp->fct_mtx); */
2553 
2554 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2555 #ifdef FCT_API_TRACE
2556 	fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
2557 #endif /* FCT_API_TRACE */
2558 	ndlp = *(emlxs_node_t **)fct_cmd->cmd_rp->rp_fca_private;
2559 
2560 	cmd_sbp->node = ndlp;
2561 	cmd_sbp->fct_buf = dbuf;
2562 
2563 	channelno = ((CHANNEL *)cmd_sbp->channel)->channelno;
2564 
2565 	channel = channelno;
2566 
2567 
2568 
2569 	iocbq = &cmd_sbp->iocbq;
2570 	iocbq->sbp = cmd_sbp;
2571 
2572 #ifdef FCT_API_TRACE
2573 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2574 	    "fct_send_fcp_data %p:%p flgs=%x ioflags=%x dl=%d,%d,%d,%d",
2575 	    fct_cmd, cmd_sbp, dbuf->db_flags, ioflags,
2576 	    fct_task->task_cmd_xfer_length,
2577 	    fct_task->task_nbytes_transferred, dbuf->db_data_size,
2578 	    fct_task->task_expected_xfer_length);
2579 #endif /* FCT_API_TRACE */
2580 
2581 	/* Setup for I/O prep routine */
2582 	iocbq->iocb.ULPCOMMAND = 0;
2583 
2584 	if (EMLXS_SLI_PREP_FCT_IOCB(port, cmd_sbp, channel) != IOERR_SUCCESS) {
2585 
2586 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2587 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2588 
2589 		return (FCT_BUSY);
2590 	}
2591 
2592 	cmd_sbp->fct_type = EMLXS_FCT_FCP_DATA;
2593 
2594 	if (dbuf->db_flags & DB_SEND_STATUS_GOOD) {
2595 		cmd_sbp->fct_flags |= EMLXS_FCT_SEND_STATUS;
2596 	}
2597 
2598 	if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
2599 		if (emlxs_fct_dbuf_dma_sync(hba, dbuf, DDI_DMA_SYNC_FORDEV)) {
2600 			emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2601 			/* mutex_exit(&cmd_sbp->fct_mtx); */
2602 
2603 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2604 				emlxs_sli4_free_xri(port, cmd_sbp, 0, 0);
2605 			}
2606 			return (FCT_BUSY);
2607 		}
2608 	}
2609 
2610 	cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
2611 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_DATA_PENDING);
2612 	/* mutex_exit(&cmd_sbp->fct_mtx); */
2613 
2614 	EMLXS_SLI_ISSUE_IOCB_CMD(hba, cmd_sbp->channel, iocbq);
2615 
2616 	return (FCT_SUCCESS);
2617 
2618 } /* emlxs_fct_send_fcp_data() */
2619 
2620 
2621 /* cmd_sbp->fct_mtx must be held to enter */
2622 /* cmd_sbp->fct_mtx must be released before exiting */
2623 static fct_status_t
2624 emlxs_fct_send_fcp_status(fct_cmd_t *fct_cmd)
2625 {
2626 	emlxs_port_t *port =
2627 	    (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
2628 	emlxs_hba_t *hba = HBA;
2629 	emlxs_buf_t *cmd_sbp;
2630 	scsi_task_t *fct_task;
2631 	fc_packet_t *pkt;
2632 	emlxs_buf_t *sbp = NULL;
2633 	emlxs_fcp_rsp *fcp_rsp;
2634 	emlxs_node_t *ndlp;
2635 	fct_status_t rval;
2636 	uint32_t did;
2637 	uint32_t size;
2638 
2639 	fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
2640 	ndlp = *(emlxs_node_t **)fct_cmd->cmd_rp->rp_fca_private;
2641 	did = fct_cmd->cmd_rportid;
2642 
2643 	/* Initialize cmd_sbp */
2644 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2645 
2646 	EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, EMLXS_FCT_SEND_FCP_STATUS);
2647 
2648 	cmd_sbp->node = ndlp;
2649 
2650 	size = 24;
2651 	if (fct_task->task_sense_length) {
2652 		size += fct_task->task_sense_length;
2653 	}
2654 #ifdef FCT_API_TRACE
2655 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2656 	    "fct_send_fcp_status %p:%p stat=%d resid=%d size=%d rx=%x ox=%x",
2657 	    fct_cmd, cmd_sbp, fct_task->task_scsi_status,
2658 	    fct_task->task_resid, size, fct_cmd->cmd_rxid, fct_cmd->cmd_oxid);
2659 #endif /* FCT_API_TRACE */
2660 
2661 	if (!(pkt = emlxs_pkt_alloc(port, size, 0, 0, KM_NOSLEEP))) {
2662 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2663 		    "fct_send_fcp_status: Unable to allocate packet.");
2664 
2665 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2666 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2667 
2668 		return (FCT_BUSY);
2669 	}
2670 
2671 	cmd_sbp->fct_type = EMLXS_FCT_FCP_STATUS;
2672 
2673 	sbp =  emlxs_fct_pkt_init(port, fct_cmd, pkt);
2674 	cmd_sbp->fct_pkt = pkt;
2675 
2676 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
2677 	pkt->pkt_timeout =
2678 	    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
2679 	pkt->pkt_timeout = (pkt->pkt_timeout > 60)? 60: pkt->pkt_timeout;
2680 	pkt->pkt_comp = emlxs_fct_pkt_comp;
2681 
2682 	/* Build the fc header */
2683 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
2684 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_STATUS;
2685 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
2686 	pkt->pkt_cmd_fhdr.type = FC_TYPE_SCSI_FCP;
2687 	pkt->pkt_cmd_fhdr.f_ctl =
2688 	    F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ;
2689 	pkt->pkt_cmd_fhdr.seq_id = 0;
2690 	pkt->pkt_cmd_fhdr.df_ctl = 0;
2691 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
2692 	pkt->pkt_cmd_fhdr.ox_id = fct_cmd->cmd_oxid;
2693 	pkt->pkt_cmd_fhdr.rx_id = fct_cmd->cmd_rxid;
2694 	pkt->pkt_cmd_fhdr.ro = 0;
2695 
2696 	/* Build the status payload */
2697 	fcp_rsp = (emlxs_fcp_rsp *)pkt->pkt_cmd;
2698 
2699 	if (fct_task->task_resid) {
2700 		if (fct_task->task_status_ctrl & TASK_SCTRL_OVER) {
2701 			TGTPORTSTAT.FctScsiResidOver++;
2702 			fcp_rsp->rspStatus2 |= RESID_OVER;
2703 			fcp_rsp->rspResId = LE_SWAP32(fct_task->task_resid);
2704 
2705 		} else if (fct_task->task_status_ctrl & TASK_SCTRL_UNDER) {
2706 			TGTPORTSTAT.FctScsiResidUnder++;
2707 			fcp_rsp->rspStatus2 |= RESID_UNDER;
2708 			fcp_rsp->rspResId = LE_SWAP32(fct_task->task_resid);
2709 
2710 		}
2711 	}
2712 
2713 	if (fct_task->task_scsi_status) {
2714 		if (fct_task->task_scsi_status == SCSI_STAT_QUE_FULL) {
2715 			TGTPORTSTAT.FctScsiQfullErr++;
2716 		} else {
2717 			TGTPORTSTAT.FctScsiStatusErr++;
2718 		}
2719 
2720 		/* Make sure residual reported on non-SCSI_GOOD READ status */
2721 		if ((fct_task->task_flags & TF_READ_DATA) &&
2722 		    (fcp_rsp->rspResId == 0)) {
2723 			fcp_rsp->rspStatus2 |= RESID_UNDER;
2724 			fcp_rsp->rspResId =
2725 			    fct_task->task_expected_xfer_length;
2726 		}
2727 	}
2728 
2729 
2730 	if (fct_task->task_sense_length) {
2731 		TGTPORTSTAT.FctScsiSenseErr++;
2732 		fcp_rsp->rspStatus2 |= SNS_LEN_VALID;
2733 		fcp_rsp->rspSnsLen = LE_SWAP32(fct_task->task_sense_length);
2734 
2735 		bcopy((uint8_t *)fct_task->task_sense_data,
2736 		    (uint8_t *)&fcp_rsp->rspInfo0,
2737 		    fct_task->task_sense_length);
2738 	}
2739 
2740 	fcp_rsp->rspStatus3 = fct_task->task_scsi_status;
2741 	fcp_rsp->rspRspLen = 0;
2742 
2743 #ifdef FCT_API_TRACE
2744 	emlxs_data_dump(port, "RESP", (uint32_t *)fcp_rsp, 36, 0);
2745 #endif /* FCT_API_TRACE */
2746 
2747 	cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
2748 	emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_STATUS_PENDING);
2749 	/* mutex_exit(&cmd_sbp->fct_mtx); */
2750 
2751 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
2752 
2753 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2754 		    "fct_send_fcp_status: Unable to send packet.");
2755 
2756 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2757 			emlxs_sli4_free_xri(port, sbp, 0, 0);
2758 		}
2759 
2760 		/* Reacquire ownership of the fct_cmd */
2761 		rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
2762 		if (rval) {
2763 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2764 			    "fct_send_fcp_status: "
2765 			    "Unable to acquire fct_cmd.");
2766 			return (rval);
2767 		}
2768 		/* mutex_enter(&cmd_sbp->fct_mtx); */
2769 
2770 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2771 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2772 
2773 		return (FCT_BUSY);
2774 	}
2775 
2776 	return (FCT_SUCCESS);
2777 
2778 } /* emlxs_fct_send_fcp_status() */
2779 
2780 
2781 static fct_status_t
2782 emlxs_fct_send_qfull_reply(emlxs_port_t *port, emlxs_node_t *ndlp,
2783     uint16_t xid, uint32_t class, emlxs_fcp_cmd_t *fcp_cmd)
2784 {
2785 	emlxs_hba_t *hba = HBA;
2786 	emlxs_buf_t *sbp;
2787 	fc_packet_t *pkt;
2788 	emlxs_fcp_rsp *fcp_rsp;
2789 	uint32_t size;
2790 	CHANNEL *cp = &hba->chan[hba->CHANNEL_FCT];
2791 	uint8_t lun[8];
2792 
2793 	bcopy((void *)&fcp_cmd->fcpLunMsl, lun, 8);
2794 	size = 24;
2795 
2796 	if (!(pkt = emlxs_pkt_alloc(port, size, 0, 0, KM_NOSLEEP))) {
2797 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2798 		    "fct_send_qfull_reply: Unable to allocate packet.");
2799 		return (FCT_FAILURE);
2800 	}
2801 
2802 	sbp = PKT2PRIV(pkt);
2803 	sbp->node = ndlp;
2804 	sbp->channel = cp;
2805 	sbp->did = ndlp->nlp_DID;
2806 	sbp->lun = (lun[0] << 8) | lun[1];
2807 	sbp->class = class;
2808 
2809 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
2810 	pkt->pkt_timeout =
2811 	    ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
2812 
2813 	/* Build the fc header */
2814 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(ndlp->nlp_DID);
2815 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_STATUS;
2816 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
2817 	pkt->pkt_cmd_fhdr.type = FC_TYPE_SCSI_FCP;
2818 	pkt->pkt_cmd_fhdr.f_ctl =
2819 	    F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ;
2820 	pkt->pkt_cmd_fhdr.seq_id = 0;
2821 	pkt->pkt_cmd_fhdr.df_ctl = 0;
2822 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
2823 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
2824 	pkt->pkt_cmd_fhdr.rx_id = xid;
2825 	pkt->pkt_cmd_fhdr.ro = 0;
2826 
2827 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2828 	    "fct_send_qfull_reply: Sending QFULL: x%x lun x%x: %d %d",
2829 	    xid, sbp->lun, TGTPORTSTAT.FctOutstandingIO,
2830 	    port->fct_port->port_max_xchges);
2831 
2832 	/* Build the status payload */
2833 	fcp_rsp = (emlxs_fcp_rsp *)pkt->pkt_cmd;
2834 
2835 	TGTPORTSTAT.FctScsiQfullErr++;
2836 	fcp_rsp->rspStatus3 = SCSI_STAT_QUE_FULL;
2837 	fcp_rsp->rspStatus2 |= RESID_UNDER;
2838 	fcp_rsp->rspResId = LE_SWAP32(fcp_cmd->fcpDl);
2839 
2840 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
2841 
2842 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2843 			emlxs_sli4_free_xri(port, sbp, 0, 0);
2844 		}
2845 
2846 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2847 		    "fct_send_qfull_reply: Unable to send packet.");
2848 		emlxs_pkt_free(pkt);
2849 		return (FCT_FAILURE);
2850 	}
2851 
2852 	return (FCT_SUCCESS);
2853 
2854 } /* emlxs_fct_send_qfull_reply() */
2855 
2856 
2857 /* ARGSUSED */
2858 extern int
2859 emlxs_fct_handle_fcp_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
2860 {
2861 	emlxs_port_t *port = &PPORT;
2862 	IOCB *iocb;
2863 	emlxs_buf_t *sbp;
2864 	emlxs_buf_t *cmd_sbp;
2865 	uint32_t status;
2866 	fct_cmd_t *fct_cmd;
2867 	stmf_data_buf_t *dbuf;
2868 	scsi_task_t *fct_task;
2869 	fc_packet_t *pkt;
2870 	uint32_t fct_flags;
2871 	stmf_data_buf_t *fct_buf;
2872 	fct_status_t rval;
2873 
2874 	iocb = &iocbq->iocb;
2875 	sbp = (emlxs_buf_t *)iocbq->sbp;
2876 
2877 	TGTPORTSTAT.FctEvent++;
2878 
2879 	if (!sbp) {
2880 		/* completion with missing xmit command */
2881 		TGTPORTSTAT.FctStray++;
2882 
2883 		/* emlxs_stray_fcp_completion_msg */
2884 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2885 		    "FCP event cmd=%x status=%x error=%x iotag=%d",
2886 		    iocb->ULPCOMMAND, iocb->ULPSTATUS,
2887 		    iocb->un.grsp.perr.statLocalError, iocb->ULPIOTAG);
2888 
2889 		return (1);
2890 	}
2891 
2892 	TGTPORTSTAT.FctCompleted++;
2893 
2894 	port = sbp->iocbq.port;
2895 	fct_cmd = sbp->fct_cmd;
2896 	status = iocb->ULPSTATUS;
2897 
2898 #ifdef FCT_API_TRACE
2899 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2900 	    "fct_handle_fcp_event: %p:%p cmd=%x status=%x, %x",
2901 	    fct_cmd, sbp, iocb->ULPCOMMAND, status, iocb->ULPCT);
2902 #endif /* FCT_API_TRACE */
2903 
2904 	if (fct_cmd == NULL) {
2905 		/* For driver generated QFULL response */
2906 		if (((iocb->ULPCOMMAND == CMD_FCP_TRSP_CX) ||
2907 		    (iocb->ULPCOMMAND == CMD_FCP_TRSP64_CX)) && sbp->pkt) {
2908 			emlxs_pkt_free(sbp->pkt);
2909 		}
2910 		return (0);
2911 	}
2912 
2913 	rval = emlxs_fct_cmd_acquire(port, fct_cmd, EMLXS_FCT_REQ_COMPLETE);
2914 	if (rval) {
2915 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2916 		    "fct_handle_fcp_event: "
2917 		    "Unable to reacquire fct_cmd. type=%x",
2918 		    fct_cmd->cmd_type);
2919 
2920 		return (1);
2921 	}
2922 	/* mutex_enter(&cmd_sbp->fct_mtx); */
2923 
2924 	cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2925 	cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
2926 
2927 	pkt = cmd_sbp->fct_pkt;
2928 	cmd_sbp->fct_pkt = NULL;
2929 
2930 	dbuf = sbp->fct_buf;
2931 
2932 	fct_cmd->cmd_comp_status = FCT_SUCCESS;
2933 
2934 	if (status) {
2935 emlxs_dma_error:
2936 		/*
2937 		 * The error indicates this IO should be terminated
2938 		 * immediately.
2939 		 */
2940 		cmd_sbp->fct_flags &= ~EMLXS_FCT_SEND_STATUS;
2941 		fct_cmd->cmd_comp_status = FCT_FAILURE;
2942 
2943 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
2944 		/* mutex_exit(&cmd_sbp->fct_mtx); */
2945 
2946 #ifdef FCT_API_TRACE
2947 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2948 		    "fct_queue_cmd_for_termination:1 %p: x%x",
2949 		    fct_cmd, fct_cmd->cmd_comp_status);
2950 #endif /* FCT_API_TRACE */
2951 
2952 		MODSYM(fct_queue_cmd_for_termination) (fct_cmd,
2953 		    FCT_ABTS_RECEIVED);
2954 
2955 		goto done;
2956 	}
2957 
2958 	switch (iocb->ULPCOMMAND) {
2959 
2960 	/*
2961 	 *  FCP Data completion
2962 	 */
2963 	case CMD_FCP_TSEND_CX:
2964 	case CMD_FCP_TSEND64_CX:
2965 	case CMD_FCP_TRECEIVE_CX:
2966 	case CMD_FCP_TRECEIVE64_CX:
2967 
2968 		if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) {
2969 			if (emlxs_fct_dbuf_dma_sync(hba, dbuf,
2970 			    DDI_DMA_SYNC_FORCPU)) {
2971 				goto emlxs_dma_error;
2972 			}
2973 		}
2974 
2975 		if ((cmd_sbp->fct_flags & EMLXS_FCT_SEND_STATUS) &&
2976 		    (iocb->ULPCT != 1)) {
2977 
2978 			dbuf->db_flags |= DB_STATUS_GOOD_SENT;
2979 
2980 			fct_task =
2981 			    (scsi_task_t *)fct_cmd->cmd_specific;
2982 			fct_task->task_scsi_status = 0;
2983 
2984 			(void) emlxs_fct_send_fcp_status(fct_cmd);
2985 			/* mutex_exit(&cmd_sbp->fct_mtx); */
2986 
2987 			break;
2988 
2989 		} else if ((cmd_sbp->fct_flags &
2990 		    EMLXS_FCT_SEND_STATUS) &&
2991 		    (iocb->ULPCT == 1)) {
2992 			/* Auto-resp has been sent out by firmware */
2993 			/* We can assume this is really a FC_TRSP_CX */
2994 
2995 			dbuf->db_flags |= DB_STATUS_GOOD_SENT;
2996 			fct_task =
2997 			    (scsi_task_t *)fct_cmd->cmd_specific;
2998 			fct_task->task_scsi_status = 0;
2999 
3000 			cmd_sbp->fct_flags |= EMLXS_FCT_SEND_STATUS;
3001 
3002 			goto auto_resp;
3003 		}
3004 
3005 		cmd_sbp->fct_flags &= ~EMLXS_FCT_SEND_STATUS;
3006 
3007 		emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
3008 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3009 
3010 #ifdef FCT_API_TRACE
3011 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3012 		    "fct_scsi_data_xfer_done:1 %p %p", fct_cmd, dbuf);
3013 #endif /* FCT_API_TRACE */
3014 
3015 		MODSYM(fct_scsi_data_xfer_done) (fct_cmd, dbuf, 0);
3016 
3017 		break;
3018 
3019 		/* FCP Status completion */
3020 	case CMD_FCP_TRSP_CX:
3021 	case CMD_FCP_TRSP64_CX:
3022 
3023 auto_resp:
3024 		/* Copy these before calling emlxs_fct_cmd_done */
3025 		fct_flags = cmd_sbp->fct_flags;
3026 		fct_buf = cmd_sbp->fct_buf;
3027 
3028 		emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3029 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3030 
3031 		TGTPORTSTAT.FctOutstandingIO--;
3032 
3033 		if (fct_flags & EMLXS_FCT_SEND_STATUS) {
3034 #ifdef FCT_API_TRACE
3035 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3036 			    "fct_scsi_data_xfer_done:2 %p %p outio %d",
3037 			    fct_cmd, fct_buf, TGTPORTSTAT.FctOutstandingIO);
3038 #endif /* FCT_API_TRACE */
3039 
3040 			MODSYM(fct_scsi_data_xfer_done) (fct_cmd,
3041 			    fct_buf, FCT_IOF_FCA_DONE);
3042 		} else {
3043 #ifdef FCT_API_TRACE
3044 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3045 			    "fct_send_response_done:1 %p: x%x outio %d",
3046 			    fct_cmd, fct_cmd->cmd_comp_status,
3047 			    TGTPORTSTAT.FctOutstandingIO);
3048 #endif /* FCT_API_TRACE */
3049 
3050 			MODSYM(fct_send_response_done) (fct_cmd,
3051 			    fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
3052 		}
3053 		break;
3054 
3055 	default:
3056 		emlxs_fct_cmd_release(port, fct_cmd, 0);
3057 		/* mutex_exit(&cmd_sbp->fct_mtx); */
3058 
3059 		TGTPORTSTAT.FctStray++;
3060 		TGTPORTSTAT.FctCompleted--;
3061 
3062 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3063 		    "Invalid iocb: cmd=0x%x", iocb->ULPCOMMAND);
3064 
3065 		if (pkt) {
3066 			emlxs_pkt_complete(sbp, status,
3067 			    iocb->un.grsp.perr.statLocalError, 1);
3068 		}
3069 
3070 	}	/* switch(iocb->ULPCOMMAND) */
3071 
3072 
3073 done:
3074 	if (pkt) {
3075 		emlxs_pkt_free(pkt);
3076 	}
3077 
3078 	if (status == IOSTAT_SUCCESS) {
3079 		TGTPORTSTAT.FctCmplGood++;
3080 	} else {
3081 		TGTPORTSTAT.FctCmplError++;
3082 	}
3083 
3084 	return (0);
3085 
3086 } /* emlxs_fct_handle_fcp_event() */
3087 
3088 
3089 /* ARGSUSED */
3090 extern int
3091 emlxs_fct_handle_abort(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
3092 {
3093 	emlxs_port_t *port = &PPORT;
3094 	IOCB *iocb;
3095 	emlxs_buf_t *sbp;
3096 	fc_packet_t *pkt;
3097 
3098 	iocb = &iocbq->iocb;
3099 	sbp = (emlxs_buf_t *)iocbq->sbp;
3100 
3101 	TGTPORTSTAT.FctEvent++;
3102 
3103 	if (!sbp) {
3104 		/* completion with missing xmit command */
3105 		TGTPORTSTAT.FctStray++;
3106 
3107 		/* emlxs_stray_fcp_completion_msg */
3108 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3109 		    "ABORT event cmd=%x status=%x error=%x iotag=%d",
3110 		    iocb->ULPCOMMAND, iocb->ULPSTATUS,
3111 		    iocb->un.grsp.perr.statLocalError, iocb->ULPIOTAG);
3112 
3113 		return (1);
3114 	}
3115 
3116 	pkt = PRIV2PKT(sbp);
3117 
3118 #ifdef FCT_API_TRACE
3119 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3120 	    "fct_handle_abort: %p:%p xri=%d cmd=%x status=%x",
3121 	    sbp->fct_cmd, sbp,
3122 	    iocb->ULPCONTEXT, iocb->ULPCOMMAND, iocb->ULPSTATUS);
3123 #endif /* FCT_API_TRACE */
3124 
3125 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3126 		XRIobj_t	*xrip;
3127 
3128 		emlxs_sli4_free_xri(port, NULL, sbp->xrip, 1);
3129 		xrip = emlxs_sli4_find_xri(port, iocb->ULPCONTEXT);
3130 		if (!xrip || xrip->state == XRI_STATE_FREE) {
3131 			goto exit;
3132 		}
3133 
3134 		if ((hba->fc_table[xrip->iotag]) &&
3135 		    (hba->fc_table[xrip->iotag] != STALE_PACKET)) {
3136 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
3137 			    "Cmd not aborted, retrying: xri=%d iotag=%d sbp=%p",
3138 			    xrip->XRI, xrip->iotag, hba->fc_table[xrip->iotag]);
3139 
3140 			/* Abort retry */
3141 			if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
3142 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
3143 				    "Abort retry failed xri=%x", xrip->XRI);
3144 			} else {
3145 				return (0);
3146 			}
3147 		}
3148 	}
3149 
3150 exit:
3151 	if (pkt) {
3152 		emlxs_pkt_free(pkt);
3153 	}
3154 	return (0);
3155 
3156 } /* emlxs_fct_handle_abort() */
3157 
3158 
3159 extern int
3160 emlxs_fct_handle_unsol_els(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
3161     MATCHMAP *mp, uint32_t size)
3162 {
3163 	emlxs_hba_t *hba = HBA;
3164 	IOCB *iocb;
3165 	uint32_t cmd_code;
3166 	fct_cmd_t *fct_cmd;
3167 	fct_els_t *els;
3168 	uint32_t sid;
3169 	uint32_t padding;
3170 	uint8_t *bp;
3171 	emlxs_buf_t *cmd_sbp;
3172 	uint32_t rval;
3173 
3174 	HBASTATS.ElsCmdReceived++;
3175 
3176 	bp = mp->virt;
3177 	cmd_code = (*(uint32_t *)bp) & ELS_CMD_MASK;
3178 	iocb = &iocbq->iocb;
3179 	sid = iocb->un.elsreq.remoteID;
3180 
3181 	if (!port->fct_port) {
3182 		if (!(hba->flag & FC_ONLINE_MODE)) {
3183 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3184 			    "%s: sid=%x. Adapter offline. Dropping...",
3185 			    emlxs_elscmd_xlate(cmd_code), sid);
3186 			goto done;
3187 		}
3188 
3189 		switch (cmd_code) {
3190 		case ELS_CMD_LOGO:
3191 		case ELS_CMD_PRLO:
3192 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3193 			    "%s: sid=%x. Target unbound. Accepting...",
3194 			    emlxs_elscmd_xlate(cmd_code), sid);
3195 			(void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC,
3196 			    ELS_CMD_LOGO, 0, 0);
3197 			break;
3198 		default:
3199 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3200 			    "%s: sid=%x. Target unbound. Rejecting...",
3201 			    emlxs_elscmd_xlate(cmd_code), sid);
3202 			(void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT,
3203 			    cmd_code, LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
3204 			break;
3205 		}
3206 		goto done;
3207 	}
3208 
3209 	if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
3210 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3211 		    "%s: sid=%x. Target offline. Rejecting...",
3212 		    emlxs_elscmd_xlate(cmd_code), sid);
3213 		(void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, cmd_code,
3214 		    LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
3215 
3216 		goto done;
3217 	}
3218 
3219 #ifdef FCT_API_TRACE
3220 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3221 	    "%s: sid=%x cnt=%d. Target rcv. ",
3222 	    emlxs_elscmd_xlate(cmd_code), sid, size);
3223 #endif /* FCT_API_TRACE */
3224 
3225 	/* Process the request */
3226 	switch (cmd_code) {
3227 	case ELS_CMD_FLOGI:
3228 		rval = emlxs_fct_process_unsol_flogi(port, cp, iocbq, mp, size);
3229 
3230 		if (!rval) {
3231 			ELS_PKT *els_pkt = (ELS_PKT *)bp;
3232 			fct_flogi_xchg_t fx;
3233 
3234 			bzero((uint8_t *)&fx, sizeof (fct_flogi_xchg_t));
3235 
3236 			/* Save the FLOGI exchange information */
3237 			fx.rsvd2 = iocb->ULPCONTEXT;
3238 			bcopy((caddr_t)&els_pkt->un.logi.nodeName,
3239 			    (caddr_t)fx.fx_nwwn, 8);
3240 			bcopy((caddr_t)&els_pkt->un.logi.portName,
3241 			    (caddr_t)fx.fx_pwwn, 8);
3242 			fx.fx_sid = sid;
3243 			fx.fx_did = iocb->un.elsreq.myID;
3244 			fx.fx_fport = els_pkt->un.logi.cmn.fPort;
3245 			fx.fx_op = ELS_OP_FLOGI;
3246 
3247 			emlxs_fct_handle_unsol_flogi(port, &fx, 1);
3248 		}
3249 
3250 		goto done;
3251 
3252 	case ELS_CMD_PLOGI:
3253 		rval =
3254 		    emlxs_fct_process_unsol_plogi(port, cp, iocbq, mp, size);
3255 		break;
3256 
3257 	default:
3258 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3259 		    "%s: sid=0x%x", emlxs_elscmd_xlate(cmd_code), sid);
3260 		rval = 0;
3261 		break;
3262 	}
3263 
3264 	if (rval) {
3265 		goto done;
3266 	}
3267 
3268 	padding = (8 - (size & 7)) & 7;
3269 
3270 	fct_cmd = (fct_cmd_t *)MODSYM(fct_alloc) (FCT_STRUCT_CMD_RCVD_ELS,
3271 	    (size + padding + GET_STRUCT_SIZE(emlxs_buf_t)),
3272 	    AF_FORCE_NOSLEEP);
3273 
3274 #ifdef FCT_API_TRACE
3275 	{
3276 		uint32_t *ptr = (uint32_t *)bp;
3277 
3278 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3279 		    "fct_alloc %p: ELS rcvd: rxid=%x payload: x%x x%x",
3280 		    fct_cmd, iocb->ULPCONTEXT, *ptr, *(ptr + 1));
3281 	}
3282 #endif /* FCT_API_TRACE */
3283 
3284 	if (fct_cmd == NULL) {
3285 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3286 		    "%s: sid=%x. Out of memory. Rejecting...",
3287 		    emlxs_elscmd_xlate(cmd_code), sid);
3288 
3289 		(void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, cmd_code,
3290 		    LSRJT_LOGICAL_BSY, LSEXP_OUT_OF_RESOURCE);
3291 		goto done;
3292 	}
3293 
3294 	/* Initialize fct_cmd */
3295 	fct_cmd->cmd_oxid = (cmd_code >>