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