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 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * The following notice accompanied the original version of this file:
29  *
30  * BSD LICENSE
31  *
32  * Copyright(c) 2007 Intel Corporation. All rights reserved.
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  *
39  *   * Redistributions of source code must retain the above copyright
40  *     notice, this list of conditions and the following disclaimer.
41  *   * Redistributions in binary form must reproduce the above copyright
42  *     notice, this list of conditions and the following disclaimer in
43  *     the documentation and/or other materials provided with the
44  *     distribution.
45  *   * Neither the name of Intel Corporation nor the names of its
46  *     contributors may be used to endorse or promote products derived
47  *     from this software without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
52  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
53  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60  */
61 
62 /*
63  * This file defines interfaces between fcoe and fcoet driver.
64  */
65 
66 /*
67  * Driver kernel header files
68  */
69 #include <sys/conf.h>
70 #include <sys/ddi.h>
71 #include <sys/stat.h>
72 #include <sys/pci.h>
73 #include <sys/sunddi.h>
74 #include <sys/modctl.h>
75 #include <sys/file.h>
76 #include <sys/cred.h>
77 #include <sys/byteorder.h>
78 #include <sys/atomic.h>
79 #include <sys/modhash.h>
80 #include <sys/scsi/scsi.h>
81 #include <sys/ethernet.h>
82 
83 /*
84  * COMSTAR header files
85  */
86 #include <sys/stmf_defines.h>
87 #include <sys/fct_defines.h>
88 #include <sys/stmf.h>
89 #include <sys/portif.h>
90 #include <sys/fct.h>
91 
92 /*
93  * FCoE header files
94  */
95 #include <sys/fcoe/fcoe_common.h>
96 
97 /*
98  * Driver's own header files
99  */
100 #include <fcoet.h>
101 #include <fcoet_eth.h>
102 
103 /*
104  * function forward declaration
105  */
106 static fcoet_exchange_t *fcoet_create_unsol_exchange(fcoe_frame_t *frame);
107 static int fcoet_process_sol_fcp_data(fcoe_frame_t *frm);
108 static int fcoet_process_unsol_fcp_cmd(fcoe_frame_t *frm);
109 static int fcoet_process_unsol_els_req(fcoe_frame_t *frm);
110 static int fcoet_process_sol_els_rsp(fcoe_frame_t *frm);
111 static int fcoet_process_unsol_abts_req(fcoe_frame_t *frame);
112 static int fcoet_process_sol_abts_acc(fcoe_frame_t *frame);
113 static int fcoet_process_sol_abts_rjt(fcoe_frame_t *frame);
114 static int fcoet_process_unsol_ct_req(fcoe_frame_t *frm);
115 static int fcoet_process_sol_ct_rsp(fcoe_frame_t *frame);
116 static int fcoet_process_sol_flogi_rsp(fcoe_frame_t *frame);
117 static int fcoet_send_sol_fcp_data_done(fcoe_frame_t *frm);
118 static int fcoet_send_fcp_status_done(fcoe_frame_t *frm);
119 static int fcoet_send_unsol_els_rsp_done(fcoe_frame_t *frm);
120 static int fcoet_send_sol_els_req_done(fcoe_frame_t *frm);
121 static int fcoet_send_unsol_bls_acc_done(fcoe_frame_t *frm);
122 static int fcoet_send_unsol_bls_rjt_done(fcoe_frame_t *frm);
123 static int fcoet_send_sol_bls_req_done(fcoe_frame_t *frm);
124 static int fcoet_send_sol_ct_req_done(fcoe_frame_t *frm);
125 static int fcoet_process_unsol_flogi_req(fcoet_exchange_t *xch);
126 
127 /*
128  * rx_frame & release_sol_frame
129  * There should be no same OXID/RXID in on-going exchanges.
130  * RXID -> unsol_rxid_hash
131  * OXID -> sol_oxid_hash
132  */
133 
134 void
135 fcoet_rx_frame(fcoe_frame_t *frm)
136 {
137 	uint8_t rctl = FRM_R_CTL(frm);
138 
139 	switch (rctl) {
140 	case 0x01:
141 		/*
142 		 * Solicited data
143 		 */
144 		if (fcoet_process_sol_fcp_data(frm)) {
145 			FCOET_LOG("fcoet_rx_frame",
146 			    "fcoet_process_sol_fcp_data failed");
147 		}
148 		break;
149 
150 	case 0x06:
151 		/*
152 		 * Unsolicited fcp_cmnd
153 		 */
154 		if (fcoet_process_unsol_fcp_cmd(frm)) {
155 			FCOET_LOG("fcoet_rx_frame",
156 			    "fcoet_process_unsol_fcp_cmd failed");
157 		}
158 		break;
159 
160 	case 0x22:
161 		/*
162 		 * unsolicited ELS req
163 		 */
164 		if (fcoet_process_unsol_els_req(frm)) {
165 			FCOET_LOG("fcoet_rx_frame",
166 			    "fcoet_process_unsol_els_req failed");
167 		}
168 		break;
169 
170 	case 0x23:
171 		/*
172 		 * solicited ELS rsp
173 		 */
174 		if (fcoet_process_sol_els_rsp(frm)) {
175 			FCOET_LOG("fcoet_rx_frame",
176 			    "fcoet_process_sol_els_rsp failed");
177 		}
178 		break;
179 
180 	case 0x81:
181 		/*
182 		 *  unsolicted ABTS req
183 		 */
184 		if (fcoet_process_unsol_abts_req(frm)) {
185 			FCOET_LOG("fcoet_rx_frame",
186 			    "fcoet_process_unsol_abts_req failed");
187 		}
188 		break;
189 
190 	case 0x84:
191 		/*
192 		 * solicited ABTS acc response
193 		 */
194 		if (fcoet_process_sol_abts_acc(frm)) {
195 			FCOET_LOG("fcoet_rx_frame",
196 			    "fcoet_process_sol_abts_acc failed");
197 		}
198 		break;
199 	case 0x85:
200 		/*
201 		 * solcited ABTS rjt response
202 		 */
203 		if (fcoet_process_sol_abts_rjt(frm)) {
204 			FCOET_LOG("fcoet_rx_frame",
205 			    "fcoet_process_sol_abts_rjt failed");
206 		}
207 		break;
208 
209 	case 0x02:
210 		/*
211 		 * unsolicited CT req
212 		 */
213 		if (fcoet_process_unsol_ct_req(frm)) {
214 			FCOET_LOG("fcoet_rx_frame",
215 			    "fcoet_process_sol_ct_rsp failed");
216 		}
217 		break;
218 
219 	case 0x03:
220 		/*
221 		 * sol ct rsp
222 		 */
223 		if (fcoet_process_sol_ct_rsp(frm)) {
224 			FCOET_LOG("fcoet_rx_frame",
225 			    "fcoet_process_sol_ct_rsp failed");
226 		}
227 		break;
228 
229 	default:
230 		/*
231 		 * Unsupported frame
232 		 */
233 		PRT_FRM_HDR("Unsupported unsol frame: ", frm);
234 		break;
235 	}
236 
237 	/*
238 	 * Release the frame in the end
239 	 */
240 	frm->frm_eport->eport_free_netb(frm->frm_netb);
241 	frm->frm_eport->eport_release_frame(frm);
242 }
243 
244 /*
245  * For solicited frames, after FCoE has sent it out, it will call this
246  * to notify client(FCoEI/FCoET) about its completion.
247  */
248 void
249 fcoet_release_sol_frame(fcoe_frame_t *frm)
250 {
251 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
252 
253 	/*
254 	 * From now, we should not access both frm_hdr and frm_payload. Its
255 	 * mblk could have been released by MAC driver.
256 	 */
257 	switch (FRM2TFM(frm)->tfm_rctl) {
258 	case 0x01:
259 		if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
260 			FCOET_RELE_XCHG(xch);
261 			break;
262 		}
263 		if (fcoet_send_sol_fcp_data_done(frm)) {
264 			ASSERT(0);
265 		}
266 		break;
267 
268 	case 0x05:
269 		break;
270 
271 	case 0x07:
272 		if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
273 			FCOET_RELE_XCHG(xch);
274 			break;
275 		}
276 
277 		if (fcoet_send_fcp_status_done(frm)) {
278 			ASSERT(0);
279 		}
280 		break;
281 
282 	case 0x23:
283 		if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
284 			FCOET_RELE_XCHG(xch);
285 			break;
286 		}
287 		if (fcoet_send_unsol_els_rsp_done(frm)) {
288 			ASSERT(0);
289 		}
290 		break;
291 
292 	case 0x22:
293 		if (fcoet_send_sol_els_req_done(frm)) {
294 			ASSERT(0);
295 		}
296 		break;
297 
298 	case 0x84:
299 		if (fcoet_send_unsol_bls_acc_done(frm)) {
300 			ASSERT(0);
301 		}
302 		break;
303 
304 	case 0x85:
305 		if (fcoet_send_unsol_bls_rjt_done(frm)) {
306 			ASSERT(0);
307 		}
308 		break;
309 
310 	case 0x81:
311 		if (fcoet_send_sol_bls_req_done(frm)) {
312 			ASSERT(0);
313 		}
314 		break;
315 
316 	case 0x02:
317 		if (fcoet_send_sol_ct_req_done(frm)) {
318 			ASSERT(0);
319 		}
320 		break;
321 
322 	case 0x03:
323 	default:
324 		/*
325 		 * Unsupported frame
326 		 */
327 		PRT_FRM_HDR("Unsupported sol frame: ", frm);
328 		break;
329 	}
330 
331 	/*
332 	 * We should release the frame
333 	 */
334 	FRM2SS(frm)->ss_eport->eport_release_frame(frm);
335 }
336 
337 void
338 fcoet_port_event(fcoe_port_t *eport, uint32_t event)
339 {
340 	fcoet_soft_state_t *ss = EPORT2SS(eport);
341 	switch (event) {
342 	case FCOE_NOTIFY_EPORT_LINK_UP:
343 		if (eport->eport_mtu >= FCOE_MIN_MTU_SIZE) {
344 			ss->ss_fcp_data_payload_size =
345 			    FCOE_DEFAULT_FCP_DATA_PAYLOAD_SIZE;
346 		} else {
347 			ss->ss_fcp_data_payload_size =
348 			    FCOE_MIN_FCP_DATA_PAYLOAD_SIZE;
349 		}
350 		FCOET_LOG("fcoet_port_event", "LINK UP notified");
351 		mutex_enter(&ss->ss_watch_mutex);
352 		ss->ss_sol_flogi_state = SFS_FLOGI_INIT;
353 		cv_signal(&ss->ss_watch_cv);
354 		mutex_exit(&ss->ss_watch_mutex);
355 		break;
356 	case FCOE_NOTIFY_EPORT_LINK_DOWN:
357 		fct_handle_event(ss->ss_port,
358 		    FCT_EVENT_LINK_DOWN, 0, 0);
359 		/* Need clear up all other things */
360 		FCOET_LOG("fcoet_port_event", "LINK DOWN notified");
361 		ss->ss_sol_flogi_state = SFS_WAIT_LINKUP;
362 		break;
363 	default:
364 		break;
365 	}
366 }
367 
368 /*
369  * For unsolicited exchanges, FCoET is only responsible for allocation of
370  * req_payload. FCT will allocate resp_payload after the exchange is
371  * passed on.
372  */
373 static fcoet_exchange_t *
374 fcoet_create_unsol_exchange(fcoe_frame_t *frm)
375 {
376 	uint8_t			 r_ctl;
377 	int			 cdb_size;
378 	fcoet_exchange_t	*xch, *xch_tmp;
379 	fct_cmd_t		*cmd;
380 	fcoe_fcp_cmnd_t		*ffc;
381 	uint32_t		task_expected_len = 0;
382 
383 	r_ctl = FRM_R_CTL(frm);
384 	switch (r_ctl) {
385 	case 0x22:
386 		/*
387 		 * FCoET's unsolicited ELS
388 		 */
389 		cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ELS,
390 		    GET_STRUCT_SIZE(fcoet_exchange_t) +
391 		    frm->frm_payload_size, 0);
392 		if (cmd == NULL) {
393 			FCOET_EXT_LOG(0, "can't get cmd");
394 			return (NULL);
395 		}
396 		break;
397 
398 	case 0x06:
399 		/*
400 		 * FCoET's unsolicited SCSI cmd
401 		 */
402 		cdb_size = 16;	/* need improve later */
403 		cmd = fct_scsi_task_alloc(FRM2SS(frm)->ss_port, FCT_HANDLE_NONE,
404 		    FRM_S_ID(frm), frm->frm_payload, cdb_size,
405 		    STMF_TASK_EXT_NONE);
406 		if (cmd == NULL) {
407 			FCOET_EXT_LOG(0, "can't get fcp cmd");
408 			return (NULL);
409 		}
410 		ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload;
411 		task_expected_len = FCOE_B2V_4(ffc->ffc_fcp_dl);
412 		break;
413 
414 	default:
415 		FCOET_EXT_LOG(0, "unsupported R_CTL: %x", r_ctl);
416 		return (NULL);
417 	}
418 
419 	/*
420 	 * xch initialization
421 	 */
422 	xch = CMD2XCH(cmd);
423 	xch->xch_oxid = FRM_OXID(frm);
424 	xch->xch_flags = 0;
425 	xch->xch_ss = FRM2SS(frm);
426 	xch->xch_cmd = cmd;
427 	xch->xch_current_seq = NULL;
428 	xch->xch_left_data_size = 0;
429 	if (task_expected_len) {
430 		xch->xch_dbuf_num =
431 		    (task_expected_len + FCOET_MAX_DBUF_LEN - 1) /
432 		    FCOET_MAX_DBUF_LEN;
433 		xch->xch_dbufs =
434 		    kmem_zalloc(xch->xch_dbuf_num * sizeof (stmf_data_buf_t *),
435 		    KM_SLEEP);
436 	}
437 	xch->xch_start_time = ddi_get_lbolt();
438 	do {
439 		xch->xch_rxid = atomic_add_16_nv(
440 		    &xch->xch_ss->ss_next_unsol_rxid, 1);
441 		if (xch->xch_rxid == 0xFFFF) {
442 			xch->xch_rxid = atomic_add_16_nv(
443 			    &xch->xch_ss->ss_next_unsol_rxid, 1);
444 		}
445 	} while (mod_hash_find(FRM2SS(frm)->ss_unsol_rxid_hash,
446 	    (mod_hash_key_t)(intptr_t)xch->xch_rxid,
447 	    (mod_hash_val_t)&xch_tmp) == 0);
448 
449 	xch->xch_sequence_no = 0;
450 	xch->xch_ref = 0;
451 	(void) mod_hash_insert(xch->xch_ss->ss_unsol_rxid_hash,
452 	    (mod_hash_key_t)(intptr_t)xch->xch_rxid, (mod_hash_val_t)xch);
453 	xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
454 
455 	/*
456 	 * cmd initialization
457 	 */
458 	cmd->cmd_port = FRM2SS(frm)->ss_port;
459 	cmd->cmd_rp_handle = FCT_HANDLE_NONE;
460 	cmd->cmd_rportid = FRM_S_ID(frm);
461 	cmd->cmd_lportid = FRM_D_ID(frm);
462 	cmd->cmd_oxid = xch->xch_oxid;
463 	cmd->cmd_rxid = xch->xch_rxid;
464 
465 	fcoet_init_tfm(frm, xch);
466 	return (xch);
467 }
468 
469 int
470 fcoet_clear_unsol_exchange(fcoet_exchange_t *xch)
471 {
472 	mod_hash_val_t val = NULL;
473 
474 	if (mod_hash_remove(xch->xch_ss->ss_unsol_rxid_hash,
475 	    (mod_hash_key_t)(intptr_t)xch->xch_rxid, &val) == 0) {
476 		if (xch->xch_dbuf_num) {
477 			kmem_free((void*)xch->xch_dbufs,
478 			    xch->xch_dbuf_num * sizeof (void *));
479 			xch->xch_dbufs = NULL;
480 			xch->xch_dbuf_num = 0;
481 		}
482 		ASSERT(xch->xch_flags & XCH_FLAG_IN_HASH_TABLE);
483 		ASSERT((fcoet_exchange_t *)val == xch);
484 		xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
485 		return (FCOE_SUCCESS);
486 	}
487 
488 	FCOET_LOG("fcoet_clear_unsol_exchange", "xch %p already cleared from "
489 	    "hash table", xch);
490 	return (FCOE_FAILURE);
491 }
492 
493 void
494 fcoet_clear_sol_exchange(fcoet_exchange_t *xch)
495 {
496 	mod_hash_val_t val = NULL;
497 
498 	if (xch->xch_flags & XCH_FLAG_IN_HASH_TABLE) {
499 		(void) mod_hash_remove(xch->xch_ss->ss_sol_oxid_hash,
500 		    (mod_hash_key_t)(intptr_t)xch->xch_oxid, &val);
501 		ASSERT((fcoet_exchange_t *)val == xch);
502 		xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
503 	}
504 }
505 
506 static int
507 fcoet_process_sol_fcp_data(fcoe_frame_t *frm)
508 {
509 	fcoet_exchange_t	*xch = NULL;
510 	fcoet_soft_state_t	*ss  = NULL;
511 	fct_status_t		 fc_st;
512 	uint32_t		 iof;
513 	uint16_t		 unsol_rxid;
514 	int			 sge_idx;
515 	stmf_data_buf_t		*dbuf;
516 	int			 data_offset;
517 
518 	unsol_rxid = FRM_RXID(frm);
519 	if (mod_hash_find_cb(FRM2SS(frm)->ss_unsol_rxid_hash,
520 	    (mod_hash_key_t)(intptr_t)unsol_rxid,
521 	    (mod_hash_val_t)&xch, fcoet_modhash_find_cb) != 0) {
522 		return (FCOE_FAILURE);
523 	}
524 
525 	/*
526 	 * we will always have a buf waiting there
527 	 */
528 	data_offset = FRM_PARAM(frm);
529 	dbuf = xch->xch_dbufs[data_offset/FCOET_MAX_DBUF_LEN];
530 	ASSERT(dbuf);
531 	ss = xch->xch_ss;
532 	sge_idx = (data_offset % FCOET_MAX_DBUF_LEN)/
533 	    ss->ss_fcp_data_payload_size;
534 
535 	ASSERT(((sge_idx < FCOET_GET_SEG_NUM(dbuf) - 1) &&
536 	    (frm->frm_payload_size == ss->ss_fcp_data_payload_size)) ||
537 	    ((sge_idx == FCOET_GET_SEG_NUM(dbuf) - 1) &&
538 	    (frm->frm_payload_size % ss->ss_fcp_data_payload_size ==
539 	    dbuf->db_data_size % ss->ss_fcp_data_payload_size)));
540 
541 	bcopy(frm->frm_payload, dbuf->db_sglist[sge_idx].seg_addr,
542 	    frm->frm_payload_size);
543 
544 	xch->xch_left_data_size -= frm->frm_payload_size;
545 	if (xch->xch_left_data_size <= 0) {
546 		fc_st = FCT_SUCCESS;
547 		iof = 0;
548 		dbuf->db_xfer_status = fc_st;
549 		dbuf->db_flags |= DB_DONT_REUSE;
550 		fct_scsi_data_xfer_done(xch->xch_cmd, dbuf, iof);
551 	}
552 
553 	FCOET_RELE_XCHG(xch);
554 	return (FCOE_SUCCESS);
555 }
556 
557 static int
558 fcoet_process_unsol_fcp_cmd(fcoe_frame_t *frm)
559 {
560 	fcoet_exchange_t	*xch;
561 	fcoe_fcp_cmnd_t		*ffc;
562 	uint8_t			 tm;
563 	scsi_task_t		*task;
564 
565 	xch = fcoet_create_unsol_exchange(frm);
566 	if (xch == NULL) {
567 		FCOET_LOG("fcoet_process_unsol_fcp_cmd", "can't get exchange");
568 		return (FCOE_FAILURE);
569 	}
570 
571 	ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload;
572 	task = XCH2TASK(xch);
573 	task->task_csn_size = 8;
574 	task->task_max_nbufs = 1;
575 	task->task_cmd_seq_no = FCOE_B2V_1(ffc->ffc_ref_num);
576 	task->task_flags = FCOE_B2V_1(ffc->ffc_attribute) & 0x07;
577 	task->task_flags |=
578 	    (FCOE_B2V_1(ffc->ffc_addlen_rdwr) & 0x03) << 5;
579 	task->task_expected_xfer_length = FCOE_B2V_4(ffc->ffc_fcp_dl);
580 
581 	tm = FCOE_B2V_1(ffc->ffc_management_flags);
582 	if (tm) {
583 		if (tm & BIT_1) {
584 			task->task_mgmt_function = TM_ABORT_TASK_SET;
585 		} else if (tm & BIT_2) {
586 			task->task_mgmt_function = TM_CLEAR_TASK_SET;
587 		} else if (tm & BIT_4) {
588 			task->task_mgmt_function = TM_LUN_RESET;
589 		} else if (tm & BIT_5) {
590 			task->task_mgmt_function = TM_TARGET_COLD_RESET;
591 		} else if (tm & BIT_6) {
592 			task->task_mgmt_function = TM_CLEAR_ACA;
593 		} else {
594 			task->task_mgmt_function = TM_ABORT_TASK;
595 		}
596 	}
597 
598 	bcopy(ffc->ffc_cdb, task->task_cdb, 16);
599 	fct_post_rcvd_cmd(xch->xch_cmd, NULL);
600 	return (FCOE_SUCCESS);
601 }
602 /*
603  * It must be from link
604  * req_payload has been allocated when create_unsol_exchange
605  */
606 static int
607 fcoet_process_unsol_els_req(fcoe_frame_t *frm)
608 {
609 	int			ret = FCOE_SUCCESS;
610 	fcoet_exchange_t	*xch;
611 
612 	xch = fcoet_create_unsol_exchange(frm);
613 	ASSERT(xch);
614 	ASSERT(FRM_IS_LAST_FRAME(frm));
615 
616 	/*
617 	 * For the reason of keeping symmetric, we do copy here as in
618 	 * process_sol_els instead of in create_unsol_exchange.
619 	 * req_payload depends on how to allocate buf in create_unsol_exchange
620 	 */
621 	XCH2ELS(xch)->els_req_alloc_size = 0;
622 	XCH2ELS(xch)->els_req_size = frm->frm_payload_size;
623 	XCH2ELS(xch)->els_req_payload =
624 	    GET_BYTE_OFFSET(xch, GET_STRUCT_SIZE(fcoet_exchange_t));
625 	bcopy(frm->frm_payload, XCH2ELS(xch)->els_req_payload,
626 	    XCH2ELS(xch)->els_req_size);
627 	if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) {
628 		/*
629 		 * Ensure LINK_UP event has been handled, or PLOIG has
630 		 * been processed by FCT, or else it will be discarded.
631 		 * It need more consideration later ???
632 		 */
633 		if ((XCH2ELS(xch)->els_req_payload[0] == ELS_OP_PLOGI) &&
634 		    (xch->xch_ss->ss_flags & SS_FLAG_DELAY_PLOGI)) {
635 			delay(STMF_SEC2TICK(1)/2);
636 		}
637 
638 		if ((XCH2ELS(xch)->els_req_payload[0] == ELS_OP_PRLI) &&
639 		    (xch->xch_ss->ss_flags & SS_FLAG_DELAY_PLOGI)) {
640 			atomic_and_32(&xch->xch_ss->ss_flags,
641 			    ~SS_FLAG_DELAY_PLOGI);
642 			delay(STMF_SEC2TICK(1)/3);
643 		}
644 		fct_post_rcvd_cmd(xch->xch_cmd, NULL);
645 	} else {
646 		/*
647 		 * We always handle FLOGI internally
648 		 * Save dst mac address from FLOGI request to restore later
649 		 */
650 		bcopy((char *)frm->frm_hdr-22,
651 		    frm->frm_eport->eport_efh_dst, ETHERADDRL);
652 		ret = fcoet_process_unsol_flogi_req(xch);
653 	}
654 	return (ret);
655 }
656 
657 
658 /*
659  * It must be from link, but could be incomplete because of network problems
660  */
661 static int
662 fcoet_process_sol_els_rsp(fcoe_frame_t *frm)
663 {
664 	uint32_t		 actual_size;
665 	fct_status_t		 fc_st;
666 	uint32_t		 iof;
667 	uint16_t		 sol_oxid;
668 	fcoet_exchange_t	*xch = NULL;
669 	fct_els_t		*els = NULL;
670 	int			 ret = FCOE_SUCCESS;
671 
672 	sol_oxid = FRM_OXID(frm);
673 	if (mod_hash_find_cb(FRM2SS(frm)->ss_sol_oxid_hash,
674 	    (mod_hash_key_t)(intptr_t)sol_oxid,
675 	    (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) {
676 		return (FCOE_FAILURE);
677 	}
678 	if (xch != FRM2SS(frm)->ss_sol_flogi) {
679 		fcoet_clear_sol_exchange(xch);
680 	}
681 
682 	fcoet_init_tfm(frm, xch);
683 	els = CMD2ELS(xch->xch_cmd);
684 	ASSERT(FRM_IS_LAST_FRAME(frm));
685 	actual_size = els->els_resp_size;
686 	if (actual_size > frm->frm_payload_size) {
687 		actual_size = frm->frm_payload_size;
688 	}
689 
690 	els->els_resp_size = (uint16_t)actual_size;
691 	bcopy(frm->frm_payload, els->els_resp_payload, actual_size);
692 
693 	if (xch->xch_ss->ss_sol_flogi == xch) {
694 		/*
695 		 * We handle FLOGI internally
696 		 */
697 		ret = fcoet_process_sol_flogi_rsp(frm);
698 		FCOET_RELE_XCHG(xch);
699 	} else {
700 		fc_st = FCT_SUCCESS;
701 		iof = FCT_IOF_FCA_DONE;
702 		FCOET_RELE_XCHG(xch);
703 		fct_send_cmd_done(xch->xch_cmd, fc_st, iof);
704 	}
705 	return (ret);
706 }
707 
708 /*
709  * It's still in the context of being aborted exchange, but FCT can't support
710  * this scheme, so there are two fct_cmd_t that are bound with one exchange.
711  */
712 static int
713 fcoet_process_unsol_abts_req(fcoe_frame_t *frm)
714 {
715 	fct_cmd_t		*cmd;
716 	fcoet_exchange_t	*xch = NULL;
717 	uint16_t		 unsol_rxid;
718 
719 	FCOET_LOG("fcoet_process_unsol_abts_req", "ABTS: %x/%x",
720 	    FRM_OXID(frm), FRM_RXID(frm));
721 	unsol_rxid = FRM_RXID(frm);
722 	if (mod_hash_find_cb(FRM2SS(frm)->ss_unsol_rxid_hash,
723 	    (mod_hash_key_t)(intptr_t)unsol_rxid,
724 	    (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) {
725 		FCOET_LOG("fcoet_process_unsol_abts_req",
726 		    "can't find aborted exchange");
727 		return (FCOE_SUCCESS);
728 	}
729 
730 	fcoet_init_tfm(frm, xch);
731 	if (!FRM_IS_LAST_FRAME(frm)) {
732 		FCOET_LOG("fcoet_process_unsol_abts_req",
733 		    "not supported this kind frame");
734 		FCOET_RELE_XCHG(xch);
735 		return (FCOE_FAILURE);
736 	}
737 
738 	cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ABTS, 0, 0);
739 	if (cmd == NULL) {
740 		FCOET_LOG("fcoet_process_unsol_abts_req",
741 		    "can't alloc fct_cmd_t");
742 		FCOET_RELE_XCHG(xch);
743 		return (FCOE_FAILURE);
744 	}
745 
746 	xch->xch_flags |= XCH_FLAG_INI_ASKED_ABORT;
747 	cmd->cmd_fca_private = xch;
748 	cmd->cmd_port = xch->xch_cmd->cmd_port;
749 	cmd->cmd_rp_handle = xch->xch_cmd->cmd_rp_handle;
750 	cmd->cmd_rportid = xch->xch_cmd->cmd_rportid;
751 	cmd->cmd_lportid = xch->xch_cmd->cmd_lportid;
752 	cmd->cmd_oxid = xch->xch_cmd->cmd_oxid;
753 	cmd->cmd_rxid = xch->xch_cmd->cmd_rxid;
754 	fct_post_rcvd_cmd(cmd, NULL);
755 	FCOET_LOG("fcoet_process_unsol_abts_req",
756 	    "abts now: xch/%p, frm/%p - time/%p",
757 	    xch, frm, ddi_get_lbolt());
758 
759 	FCOET_RELE_XCHG(xch);
760 	return (FCOE_SUCCESS);
761 }
762 
763 static int
764 fcoet_process_sol_abts_acc(fcoe_frame_t *frm)
765 {
766 	fcoet_exchange_t	*xch	   = NULL;
767 	uint16_t		 sol_oxid;
768 
769 	sol_oxid = FRM_OXID(frm);
770 	if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
771 	    (mod_hash_key_t)(intptr_t)sol_oxid,
772 	    (mod_hash_val_t *)&xch) != 0) {
773 		/*
774 		 * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash
775 		 * in fcoet_watch_handle_sol_flogi, Will improve it later
776 		 */
777 		return (FCOE_SUCCESS);
778 	}
779 
780 	xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
781 	if (!FRM_IS_LAST_FRAME(frm)) {
782 		FCOET_LOG("fcoet_process_sol_abts_acc",
783 		    "not supported this kind frame");
784 		FCOET_RELE_XCHG(xch);
785 		return (FCOE_FAILURE);
786 	}
787 	FCOET_LOG("fcoet_process_sol_abts_acc",
788 	    "ABTS received but there is nothing to do");
789 	return (FCOE_SUCCESS);
790 }
791 
792 static int
793 fcoet_process_sol_abts_rjt(fcoe_frame_t *frm)
794 {
795 	fcoet_exchange_t	*xch	   = NULL;
796 	uint16_t		 sol_oxid;
797 
798 	sol_oxid = FRM_OXID(frm);
799 	if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
800 	    (mod_hash_key_t)(intptr_t)sol_oxid,
801 	    (mod_hash_val_t *)&xch) != 0) {
802 		/*
803 		 * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash
804 		 * in fcoet_watch_handle_sol_flogi, Will improve it later
805 		 */
806 		return (FCOE_SUCCESS);
807 	}
808 
809 	xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
810 
811 	if (!FRM_IS_LAST_FRAME(frm)) {
812 		FCOET_LOG("fcoet_process_sol_abts_rjt",
813 		    "not supported this kind frame");
814 		return (FCOE_FAILURE);
815 	}
816 
817 	FCOET_LOG("fcoet_process_sol_abts_rjt",
818 	    "ABTS_RJT received rjt reason %x but there is nothing to do",
819 	    frm->frm_payload[1]);
820 	return (FCOE_SUCCESS);
821 }
822 
823 static int
824 fcoet_process_unsol_ct_req(fcoe_frame_t *frm)
825 {
826 	/*
827 	 * If you want to implement virtual name server, or FC/ETH
828 	 * gateway, you can do it here
829 	 */
830 	if (!FRM_IS_LAST_FRAME(frm)) {
831 		FCOET_LOG("fcoet_process_unsol_ct_req",
832 		    "not supported this kind frame");
833 		return (FCOE_FAILURE);
834 	}
835 
836 	FCOET_LOG("fcoet_process_unsol_ct_req",
837 	    "No support for unsolicited CT request");
838 	return (FCOE_SUCCESS);
839 }
840 
841 static int
842 fcoet_process_sol_ct_rsp(fcoe_frame_t *frm)
843 {
844 	uint32_t		 actual_size;
845 	fct_status_t		 fc_st;
846 	uint32_t		 iof;
847 	fct_sol_ct_t		*ct  = NULL;
848 	fcoet_exchange_t	*xch = NULL;
849 	uint16_t		 sol_oxid;
850 
851 	sol_oxid = FRM_OXID(frm);
852 
853 	if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
854 	    (mod_hash_key_t)(intptr_t)sol_oxid,
855 	    (mod_hash_val_t *)&xch) != 0) {
856 		return (FCOE_SUCCESS);
857 	}
858 
859 	xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
860 	fcoet_init_tfm(frm, xch);
861 
862 	ASSERT(FRM_IS_LAST_FRAME(frm));
863 	actual_size = CMD2ELS(xch->xch_cmd)->els_resp_size;
864 	if (actual_size > frm->frm_payload_size) {
865 		actual_size = frm->frm_payload_size;
866 	}
867 	ct = CMD2CT(xch->xch_cmd);
868 	ct->ct_resp_size = (uint16_t)actual_size;
869 
870 	bcopy(frm->frm_payload,
871 	    CMD2CT(xch->xch_cmd)->ct_resp_payload, actual_size);
872 
873 	fc_st = FCT_SUCCESS;
874 	iof = FCT_IOF_FCA_DONE;
875 	fct_send_cmd_done(xch->xch_cmd, fc_st, iof);
876 
877 	return (FCOE_SUCCESS);
878 }
879 
880 static int
881 fcoet_send_sol_fcp_data_done(fcoe_frame_t *frm)
882 {
883 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
884 	stmf_data_buf_t		*dbuf;
885 	int			dbuf_index;
886 	uint32_t		 iof;
887 
888 	dbuf_index = FRM2TFM(frm)->tfm_buf_idx;
889 	xch->xch_left_data_size -= frm->frm_payload_size;
890 	dbuf = xch->xch_dbufs[dbuf_index];
891 	ASSERT((dbuf) && (dbuf->db_flags & DB_DIRECTION_TO_RPORT));
892 
893 	/*
894 	 * We decrease db_sglist_length only for READ-type commands.
895 	 * For INQUIRY, resid could be non-zero, then db_sglist_length will
896 	 * be useful.
897 	 */
898 	dbuf->db_sglist_length--;
899 	if ((xch->xch_left_data_size <= 0) || (!dbuf->db_sglist_length)) {
900 		iof = 0;
901 		dbuf->db_xfer_status = FCT_SUCCESS;
902 		dbuf->db_flags |= DB_DONT_REUSE;
903 		if (dbuf->db_flags & DB_SEND_STATUS_GOOD) {
904 			if (fcoet_send_status(xch->xch_cmd) != FCT_SUCCESS) {
905 				return (FCOE_FAILURE);
906 			}
907 		} else {
908 			fct_scsi_data_xfer_done(xch->xch_cmd, dbuf, iof);
909 		}
910 	}
911 	FCOET_RELE_XCHG(xch);
912 	return (FCOE_SUCCESS);
913 }
914 
915 static int
916 fcoet_send_fcp_status_done(fcoe_frame_t *frm)
917 {
918 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
919 	fct_status_t		 fc_st = FCT_SUCCESS;
920 	uint32_t		 iof = FCT_IOF_FCA_DONE;
921 
922 	if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
923 		FCOET_RELE_XCHG(xch);
924 		return (FCOE_SUCCESS);
925 	}
926 
927 	if (fcoet_clear_unsol_exchange(xch) == FCOE_SUCCESS) {
928 		FCOET_RELE_XCHG(xch);
929 		fct_send_response_done(xch->xch_cmd, fc_st, iof);
930 	} else {
931 		/* Already cleared from hash table by abort */
932 		FCOET_RELE_XCHG(xch);
933 	}
934 
935 	return (FCOE_SUCCESS);
936 }
937 
938 /*
939  * Solicited frames callback area
940  */
941 static int
942 fcoet_send_unsol_els_rsp_done(fcoe_frame_t *frm)
943 {
944 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
945 	fct_status_t		 fc_st;
946 	uint32_t		 iof;
947 
948 	FCOET_EXT_LOG("fcoet_send_unsol_els_rsp_done",
949 	    "frm/oxid/els: %p/%x/%x",
950 	    frm, FRM_OXID(frm), XCH2ELS(xch)->els_req_payload[0]);
951 	if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
952 		FCOET_RELE_XCHG(xch);
953 		return (FCOE_SUCCESS);
954 	}
955 
956 	if (fcoet_clear_unsol_exchange(xch) == FCOE_FAILURE) {
957 		FCOET_RELE_XCHG(xch);
958 		return (FCOE_SUCCESS);
959 	}
960 
961 	FCOET_RELE_XCHG(xch);
962 	if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) {
963 		fc_st = FCT_SUCCESS;
964 		iof = FCT_IOF_FCA_DONE;
965 		fct_send_response_done(xch->xch_cmd, fc_st, iof);
966 	} else {
967 		/*
968 		 * We need update ss_link_info and flags.
969 		 */
970 		mutex_enter(&xch->xch_ss->ss_watch_mutex);
971 		xch->xch_ss->ss_link_info.portid =
972 		    xch->xch_cmd->cmd_lportid;
973 		xch->xch_ss->ss_link_info.port_topology =
974 		    PORT_TOPOLOGY_PT_TO_PT;
975 		if (frm->frm_eport->eport_link_speed == FCOE_PORT_SPEED_1G) {
976 			xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_1G;
977 		} else if (frm->frm_eport->eport_link_speed ==
978 		    FCOE_PORT_SPEED_10G) {
979 			xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G;
980 		}
981 		xch->xch_ss->ss_link_info.port_no_fct_flogi = 1;
982 		xch->xch_ss->ss_link_info.port_fca_flogi_done = 1;
983 		xch->xch_ss->ss_link_info.port_fct_flogi_done = 0;
984 		bcopy(XCH2ELS(xch)->els_req_payload + 20,
985 		    xch->xch_ss->ss_link_info.port_rpwwn, 8);
986 		bcopy(XCH2ELS(xch)->els_req_payload + 28,
987 		    xch->xch_ss->ss_link_info.port_rnwwn, 8);
988 		atomic_or_32(&xch->xch_ss->ss_flags,
989 		    SS_FLAG_UNSOL_FLOGI_DONE);
990 		atomic_or_32(&xch->xch_ss->ss_flags,
991 		    SS_FLAG_REPORT_TO_FCT);
992 
993 		xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC;
994 		mutex_exit(&xch->xch_ss->ss_watch_mutex);
995 
996 		fct_free(xch->xch_cmd);
997 	}
998 	return (FCOE_SUCCESS);
999 }
1000 
1001 /* ARGSUSED */
1002 static int
1003 fcoet_send_sol_els_req_done(fcoe_frame_t *frm)
1004 {
1005 	return (FCOE_SUCCESS);
1006 }
1007 
1008 /*
1009  * FCT have released relevant fct_cmd_t and fcoet_exchange_t now, so it's not
1010  * needed to notify FCT anything. Just do nothing.
1011  */
1012 /* ARGSUSED */
1013 static int
1014 fcoet_send_unsol_bls_acc_done(fcoe_frame_t *frm)
1015 {
1016 	FCOET_LOG("fcoet_send_unsol_bls_acc_done",
1017 	    "Unsolicited BA_ACC sent out and released ");
1018 
1019 	return (FCOE_SUCCESS);
1020 }
1021 
1022 /* ARGSUSED */
1023 static int
1024 fcoet_send_unsol_bls_rjt_done(fcoe_frame_t *frm)
1025 {
1026 	FCOET_LOG("fcoet_send_unsol_bls_rjt_done",
1027 	    "Unsolicited BA_RJT sent out and released");
1028 	return (FCOE_SUCCESS);
1029 }
1030 
1031 /* ARGSUSED */
1032 static int
1033 fcoet_send_sol_bls_req_done(fcoe_frame_t *frm)
1034 {
1035 	FCOET_LOG("fcoet_send_sol_bls_req_done",
1036 	    "Soclited ABTS was sent out and released");
1037 	return (FCOE_SUCCESS);
1038 }
1039 
1040 /* ARGSUSED */
1041 static int
1042 fcoet_send_sol_ct_req_done(fcoe_frame_t *frm)
1043 {
1044 	FCOET_LOG("fcoet_send_sol_ct_req_done",
1045 	    "CT request was sent out and released");
1046 	return (FCOE_SUCCESS);
1047 }
1048 
1049 /*
1050  * FCoET can only interpret solicited and unsolicited FLOGI, all the other
1051  * ELS/CT/FCP should be passed up to FCT.
1052  */
1053 static int
1054 fcoet_process_unsol_flogi_req(fcoet_exchange_t *xch)
1055 {
1056 	fcoe_frame_t *frm;
1057 
1058 	atomic_or_32(&xch->xch_ss->ss_flags, SS_FLAG_DELAY_PLOGI);
1059 
1060 	/*
1061 	 * In spec, common service parameter should indicate if it's from
1062 	 * N-port or F-port, but the initial intel implementation is not
1063 	 * spec-compliant, so we use eport_flags to workaround the problem
1064 	 */
1065 	if (!(xch->xch_ss->ss_eport->eport_flags & EPORT_FLAG_IS_DIRECT_P2P)) {
1066 		/*
1067 		 * The topology is switch P2P, so there's no need to respond
1068 		 * to this FLOGI
1069 		 */
1070 		FCOET_LOG("fcoet_process_unsol_flogi_req",
1071 		    "skip FLOGI, since we are in switch topology");
1072 		return (FCOE_SUCCESS);
1073 	}
1074 
1075 	/*
1076 	 * Send ACC according to the spec.
1077 	 */
1078 	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1079 	    FLOGI_ACC_PAYLOAD_SIZE + FCFH_SIZE, 0);
1080 	if (frm == NULL) {
1081 		ASSERT(0);
1082 		return (FCOE_FAILURE);
1083 	} else {
1084 		fcoet_init_tfm(frm, xch);
1085 		bzero(frm->frm_payload, frm->frm_payload_size);
1086 	}
1087 
1088 	FFM_R_CTL(0x23, frm);
1089 	FRM2TFM(frm)->tfm_rctl = 0x23;
1090 	FFM_TYPE(0x01, frm);
1091 	FFM_F_CTL(0x980000, frm);
1092 	FFM_OXID(xch->xch_oxid, frm);
1093 	FFM_RXID(xch->xch_rxid, frm);
1094 	FFM_S_ID(0xFFFFFE, frm);
1095 
1096 	/*
1097 	 * ACC
1098 	 */
1099 	frm->frm_payload[0] = 0x02;
1100 
1101 	/*
1102 	 * Common Svc Parameters
1103 	 */
1104 	frm->frm_payload[4] = 0x20;
1105 	frm->frm_payload[5] = 0x20;
1106 	frm->frm_payload[7] = 0x0A;
1107 	frm->frm_payload[10] = 0x05;
1108 	frm->frm_payload[11] = 0xAC;
1109 	bcopy(xch->xch_ss->ss_eport->eport_portwwn, frm->frm_payload + 20, 8);
1110 	bcopy(xch->xch_ss->ss_eport->eport_nodewwn, frm->frm_payload + 28, 8);
1111 
1112 	/*
1113 	 * Class3 Svc Parameters
1114 	 */
1115 	frm->frm_payload[68] = 0x88;
1116 
1117 	/*
1118 	 * Send FLOGI ACC out
1119 	 * After this, we should never use the exchange, because it could
1120 	 * have been released. Please pay attention to other similiar cases.
1121 	 */
1122 	xch->xch_ss->ss_eport->eport_tx_frame(frm);
1123 	return (FCOE_SUCCESS);
1124 }
1125 
1126 static int
1127 fcoet_process_sol_flogi_rsp(fcoe_frame_t *frm)
1128 {
1129 	int ret = FCOE_SUCCESS;
1130 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
1131 	fct_els_t		*els = CMD2ELS(xch->xch_cmd);
1132 
1133 	if (els->els_resp_payload[0] == ELS_OP_ACC) {
1134 		/*
1135 		 * We need always update ss_link_info and flags for solicited
1136 		 * FLOGI, because someone has assigned address for you. The
1137 		 * initial intel implementation will always assign address for
1138 		 * you even you are in back-to-back mode (direct P2P).
1139 		 */
1140 		mutex_enter(&xch->xch_ss->ss_watch_mutex);
1141 		if (xch->xch_flags & XCH_FLAG_NONFCP_REQ_SENT) {
1142 			xch->xch_cmd->cmd_lportid = FRM_D_ID(frm);
1143 			xch->xch_ss->ss_link_info.portid =
1144 			    xch->xch_cmd->cmd_lportid;
1145 			/*
1146 			 * Check the bit 28 in 3rd word of the payload
1147 			 *  in common service parameters to know the
1148 			 * remote port is F_PORT or N_PORT
1149 			 */
1150 			if (els->els_resp_payload[8] & 0x10) {
1151 				uint8_t src_addr[ETHERADDRL];
1152 				frm->frm_eport->eport_flags &=
1153 				    ~EPORT_FLAG_IS_DIRECT_P2P;
1154 				FCOE_SET_DEFAULT_OUI(src_addr);
1155 				bcopy(frm->frm_hdr->hdr_d_id, src_addr + 3, 3);
1156 				bcopy((char *)frm->frm_hdr-22,
1157 				    frm->frm_eport->eport_efh_dst,
1158 				    ETHERADDRL);
1159 				frm->frm_eport->eport_set_mac_address(
1160 				    frm->frm_eport, src_addr, B_TRUE);
1161 				xch->xch_ss->ss_link_info.port_topology =
1162 				    PORT_TOPOLOGY_FABRIC_PT_TO_PT;
1163 			} else {
1164 				xch->xch_ss->ss_link_info.port_topology =
1165 				    PORT_TOPOLOGY_PT_TO_PT;
1166 			}
1167 
1168 			xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G;
1169 			xch->xch_ss->ss_link_info.port_no_fct_flogi = 1;
1170 			xch->xch_ss->ss_link_info.port_fca_flogi_done = 1;
1171 			xch->xch_ss->ss_link_info.port_fct_flogi_done = 0;
1172 			xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC;
1173 			cv_signal(&xch->xch_ss->ss_watch_cv);
1174 			FCOET_LOG("fcoet_process_sol_flogi_rsp",
1175 			    "FLOGI is accecpted");
1176 		} else {
1177 			FCOET_LOG("fcoet_process_sol_flogi_rsp",
1178 			    "FLOGI xch_flags/%x", xch->xch_flags);
1179 			ret = FCOE_FAILURE;
1180 		}
1181 		mutex_exit(&xch->xch_ss->ss_watch_mutex);
1182 	} else {
1183 		FCOET_LOG("fcoet_process_sol_flogi_rsp", "FLOGI is rejected");
1184 		ret = FCOE_FAILURE;
1185 	}
1186 	return (ret);
1187 }
1188