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