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