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