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