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