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 	atomic_add_16(&dbuf->db_sglist_length, 1);
544 
545 	xch->xch_left_data_size -= frm->frm_payload_size;
546 	if ((xch->xch_left_data_size <= 0) ||
547 	    dbuf->db_sglist_length >= FCOET_GET_SEG_NUM(dbuf)) {
548 		fc_st = FCT_SUCCESS;
549 		iof = 0;
550 		dbuf->db_xfer_status = fc_st;
551 		dbuf->db_flags |= DB_DONT_REUSE;
552 		fct_scsi_data_xfer_done(xch->xch_cmd, dbuf, iof);
553 	}
554 
555 	FCOET_RELE_XCHG(xch);
556 	return (FCOE_SUCCESS);
557 }
558 
559 static int
560 fcoet_process_unsol_fcp_cmd(fcoe_frame_t *frm)
561 {
562 	fcoet_exchange_t	*xch;
563 	fcoe_fcp_cmnd_t		*ffc;
564 	uint8_t			 tm;
565 	scsi_task_t		*task;
566 
567 	xch = fcoet_create_unsol_exchange(frm);
568 	if (xch == NULL) {
569 		FCOET_LOG("fcoet_process_unsol_fcp_cmd", "can't get exchange");
570 		return (FCOE_FAILURE);
571 	}
572 
573 	ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload;
574 	task = XCH2TASK(xch);
575 	task->task_csn_size = 8;
576 	task->task_max_nbufs = 1;
577 	task->task_cmd_seq_no = FCOE_B2V_1(ffc->ffc_ref_num);
578 	task->task_flags = FCOE_B2V_1(ffc->ffc_attribute) & 0x07;
579 	task->task_flags |=
580 	    (FCOE_B2V_1(ffc->ffc_addlen_rdwr) & 0x03) << 5;
581 	task->task_expected_xfer_length = FCOE_B2V_4(ffc->ffc_fcp_dl);
582 
583 	tm = FCOE_B2V_1(ffc->ffc_management_flags);
584 	if (tm) {
585 		if (tm & BIT_1) {
586 			task->task_mgmt_function = TM_ABORT_TASK_SET;
587 		} else if (tm & BIT_2) {
588 			task->task_mgmt_function = TM_CLEAR_TASK_SET;
589 		} else if (tm & BIT_4) {
590 			task->task_mgmt_function = TM_LUN_RESET;
591 		} else if (tm & BIT_5) {
592 			task->task_mgmt_function = TM_TARGET_COLD_RESET;
593 		} else if (tm & BIT_6) {
594 			task->task_mgmt_function = TM_CLEAR_ACA;
595 		} else {
596 			task->task_mgmt_function = TM_ABORT_TASK;
597 		}
598 	}
599 
600 	bcopy(ffc->ffc_cdb, task->task_cdb, 16);
601 	fct_post_rcvd_cmd(xch->xch_cmd, NULL);
602 	return (FCOE_SUCCESS);
603 }
604 /*
605  * It must be from link
606  * req_payload has been allocated when create_unsol_exchange
607  */
608 static int
609 fcoet_process_unsol_els_req(fcoe_frame_t *frm)
610 {
611 	int			ret = FCOE_SUCCESS;
612 	fcoet_exchange_t	*xch;
613 
614 	xch = fcoet_create_unsol_exchange(frm);
615 	ASSERT(xch);
616 	ASSERT(FRM_IS_LAST_FRAME(frm));
617 
618 	/*
619 	 * For the reason of keeping symmetric, we do copy here as in
620 	 * process_sol_els instead of in create_unsol_exchange.
621 	 * req_payload depends on how to allocate buf in create_unsol_exchange
622 	 */
623 	XCH2ELS(xch)->els_req_alloc_size = 0;
624 	XCH2ELS(xch)->els_req_size = frm->frm_payload_size;
625 	XCH2ELS(xch)->els_req_payload =
626 	    GET_BYTE_OFFSET(xch, GET_STRUCT_SIZE(fcoet_exchange_t));
627 	bcopy(frm->frm_payload, XCH2ELS(xch)->els_req_payload,
628 	    XCH2ELS(xch)->els_req_size);
629 	if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) {
630 		/*
631 		 * Ensure LINK_UP event has been handled, or PLOIG has
632 		 * been processed by FCT, or else it will be discarded.
633 		 * It need more consideration later ???
634 		 */
635 		if ((XCH2ELS(xch)->els_req_payload[0] == ELS_OP_PLOGI) &&
636 		    (xch->xch_ss->ss_flags & SS_FLAG_DELAY_PLOGI)) {
637 			delay(STMF_SEC2TICK(1)/2);
638 		}
639 
640 		if ((XCH2ELS(xch)->els_req_payload[0] == ELS_OP_PRLI) &&
641 		    (xch->xch_ss->ss_flags & SS_FLAG_DELAY_PLOGI)) {
642 			atomic_and_32(&xch->xch_ss->ss_flags,
643 			    ~SS_FLAG_DELAY_PLOGI);
644 			delay(STMF_SEC2TICK(1)/3);
645 		}
646 		fct_post_rcvd_cmd(xch->xch_cmd, NULL);
647 	} else {
648 		/*
649 		 * We always handle FLOGI internally
650 		 * Save dst mac address from FLOGI request to restore later
651 		 */
652 		bcopy((char *)frm->frm_hdr-22,
653 		    frm->frm_eport->eport_efh_dst, ETHERADDRL);
654 		ret = fcoet_process_unsol_flogi_req(xch);
655 	}
656 	return (ret);
657 }
658 
659 
660 /*
661  * It must be from link, but could be incomplete because of network problems
662  */
663 static int
664 fcoet_process_sol_els_rsp(fcoe_frame_t *frm)
665 {
666 	uint32_t		 actual_size;
667 	fct_status_t		 fc_st;
668 	uint32_t		 iof;
669 	uint16_t		 sol_oxid;
670 	fcoet_exchange_t	*xch = NULL;
671 	fct_els_t		*els = NULL;
672 	int			 ret = FCOE_SUCCESS;
673 
674 	sol_oxid = FRM_OXID(frm);
675 	if (mod_hash_find_cb(FRM2SS(frm)->ss_sol_oxid_hash,
676 	    (mod_hash_key_t)(intptr_t)sol_oxid,
677 	    (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) {
678 		return (FCOE_FAILURE);
679 	}
680 	if (xch != FRM2SS(frm)->ss_sol_flogi) {
681 		fcoet_clear_sol_exchange(xch);
682 	}
683 
684 	fcoet_init_tfm(frm, xch);
685 	els = CMD2ELS(xch->xch_cmd);
686 	ASSERT(FRM_IS_LAST_FRAME(frm));
687 	actual_size = els->els_resp_size;
688 	if (actual_size > frm->frm_payload_size) {
689 		actual_size = frm->frm_payload_size;
690 	}
691 
692 	els->els_resp_size = (uint16_t)actual_size;
693 	bcopy(frm->frm_payload, els->els_resp_payload, actual_size);
694 
695 	if (xch->xch_ss->ss_sol_flogi == xch) {
696 		/*
697 		 * We handle FLOGI internally
698 		 */
699 		ret = fcoet_process_sol_flogi_rsp(frm);
700 		FCOET_RELE_XCHG(xch);
701 	} else {
702 		fc_st = FCT_SUCCESS;
703 		iof = FCT_IOF_FCA_DONE;
704 		FCOET_RELE_XCHG(xch);
705 		fct_send_cmd_done(xch->xch_cmd, fc_st, iof);
706 	}
707 	return (ret);
708 }
709 
710 /*
711  * It's still in the context of being aborted exchange, but FCT can't support
712  * this scheme, so there are two fct_cmd_t that are bound with one exchange.
713  */
714 static int
715 fcoet_process_unsol_abts_req(fcoe_frame_t *frm)
716 {
717 	fct_cmd_t		*cmd;
718 	fcoet_exchange_t	*xch = NULL;
719 	uint16_t		 unsol_rxid;
720 
721 	FCOET_LOG("fcoet_process_unsol_abts_req", "ABTS: %x/%x",
722 	    FRM_OXID(frm), FRM_RXID(frm));
723 	unsol_rxid = FRM_RXID(frm);
724 	if (mod_hash_find_cb(FRM2SS(frm)->ss_unsol_rxid_hash,
725 	    (mod_hash_key_t)(intptr_t)unsol_rxid,
726 	    (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) {
727 		FCOET_LOG("fcoet_process_unsol_abts_req",
728 		    "can't find aborted exchange");
729 		return (FCOE_SUCCESS);
730 	}
731 
732 	fcoet_init_tfm(frm, xch);
733 	if (!FRM_IS_LAST_FRAME(frm)) {
734 		FCOET_LOG("fcoet_process_unsol_abts_req",
735 		    "not supported this kind frame");
736 		FCOET_RELE_XCHG(xch);
737 		return (FCOE_FAILURE);
738 	}
739 
740 	cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ABTS, 0, 0);
741 	if (cmd == NULL) {
742 		FCOET_LOG("fcoet_process_unsol_abts_req",
743 		    "can't alloc fct_cmd_t");
744 		FCOET_RELE_XCHG(xch);
745 		return (FCOE_FAILURE);
746 	}
747 
748 	xch->xch_flags |= XCH_FLAG_INI_ASKED_ABORT;
749 	cmd->cmd_fca_private = xch;
750 	cmd->cmd_port = xch->xch_cmd->cmd_port;
751 	cmd->cmd_rp_handle = xch->xch_cmd->cmd_rp_handle;
752 	cmd->cmd_rportid = xch->xch_cmd->cmd_rportid;
753 	cmd->cmd_lportid = xch->xch_cmd->cmd_lportid;
754 	cmd->cmd_oxid = xch->xch_cmd->cmd_oxid;
755 	cmd->cmd_rxid = xch->xch_cmd->cmd_rxid;
756 	fct_post_rcvd_cmd(cmd, NULL);
757 	FCOET_LOG("fcoet_process_unsol_abts_req",
758 	    "abts now: xch/%p, frm/%p - time/%p",
759 	    xch, frm, ddi_get_lbolt());
760 
761 	FCOET_RELE_XCHG(xch);
762 	return (FCOE_SUCCESS);
763 }
764 
765 static int
766 fcoet_process_sol_abts_acc(fcoe_frame_t *frm)
767 {
768 	fcoet_exchange_t	*xch	   = NULL;
769 	uint16_t		 sol_oxid;
770 
771 	sol_oxid = FRM_OXID(frm);
772 	if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
773 	    (mod_hash_key_t)(intptr_t)sol_oxid,
774 	    (mod_hash_val_t *)&xch) != 0) {
775 		/*
776 		 * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash
777 		 * in fcoet_watch_handle_sol_flogi, Will improve it later
778 		 */
779 		return (FCOE_SUCCESS);
780 	}
781 
782 	xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
783 	if (!FRM_IS_LAST_FRAME(frm)) {
784 		FCOET_LOG("fcoet_process_sol_abts_acc",
785 		    "not supported this kind frame");
786 		FCOET_RELE_XCHG(xch);
787 		return (FCOE_FAILURE);
788 	}
789 	FCOET_LOG("fcoet_process_sol_abts_acc",
790 	    "ABTS received but there is nothing to do");
791 	return (FCOE_SUCCESS);
792 }
793 
794 static int
795 fcoet_process_sol_abts_rjt(fcoe_frame_t *frm)
796 {
797 	fcoet_exchange_t	*xch	   = NULL;
798 	uint16_t		 sol_oxid;
799 
800 	sol_oxid = FRM_OXID(frm);
801 	if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
802 	    (mod_hash_key_t)(intptr_t)sol_oxid,
803 	    (mod_hash_val_t *)&xch) != 0) {
804 		/*
805 		 * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash
806 		 * in fcoet_watch_handle_sol_flogi, Will improve it later
807 		 */
808 		return (FCOE_SUCCESS);
809 	}
810 
811 	xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
812 
813 	if (!FRM_IS_LAST_FRAME(frm)) {
814 		FCOET_LOG("fcoet_process_sol_abts_rjt",
815 		    "not supported this kind frame");
816 		return (FCOE_FAILURE);
817 	}
818 
819 	FCOET_LOG("fcoet_process_sol_abts_rjt",
820 	    "ABTS_RJT received rjt reason %x but there is nothing to do",
821 	    frm->frm_payload[1]);
822 	return (FCOE_SUCCESS);
823 }
824 
825 static int
826 fcoet_process_unsol_ct_req(fcoe_frame_t *frm)
827 {
828 	/*
829 	 * If you want to implement virtual name server, or FC/ETH
830 	 * gateway, you can do it here
831 	 */
832 	if (!FRM_IS_LAST_FRAME(frm)) {
833 		FCOET_LOG("fcoet_process_unsol_ct_req",
834 		    "not supported this kind frame");
835 		return (FCOE_FAILURE);
836 	}
837 
838 	FCOET_LOG("fcoet_process_unsol_ct_req",
839 	    "No support for unsolicited CT request");
840 	return (FCOE_SUCCESS);
841 }
842 
843 static int
844 fcoet_process_sol_ct_rsp(fcoe_frame_t *frm)
845 {
846 	uint32_t		 actual_size;
847 	fct_status_t		 fc_st;
848 	uint32_t		 iof;
849 	fct_sol_ct_t		*ct  = NULL;
850 	fcoet_exchange_t	*xch = NULL;
851 	uint16_t		 sol_oxid;
852 
853 	sol_oxid = FRM_OXID(frm);
854 
855 	if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
856 	    (mod_hash_key_t)(intptr_t)sol_oxid,
857 	    (mod_hash_val_t *)&xch) != 0) {
858 		return (FCOE_SUCCESS);
859 	}
860 
861 	xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
862 	fcoet_init_tfm(frm, xch);
863 
864 	ASSERT(FRM_IS_LAST_FRAME(frm));
865 	actual_size = CMD2ELS(xch->xch_cmd)->els_resp_size;
866 	if (actual_size > frm->frm_payload_size) {
867 		actual_size = frm->frm_payload_size;
868 	}
869 	ct = CMD2CT(xch->xch_cmd);
870 	ct->ct_resp_size = (uint16_t)actual_size;
871 
872 	bcopy(frm->frm_payload,
873 	    CMD2CT(xch->xch_cmd)->ct_resp_payload, actual_size);
874 
875 	fc_st = FCT_SUCCESS;
876 	iof = FCT_IOF_FCA_DONE;
877 	fct_send_cmd_done(xch->xch_cmd, fc_st, iof);
878 
879 	return (FCOE_SUCCESS);
880 }
881 
882 static int
883 fcoet_send_sol_fcp_data_done(fcoe_frame_t *frm)
884 {
885 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
886 	stmf_data_buf_t		*dbuf;
887 	int			dbuf_index;
888 	uint32_t		 iof;
889 
890 	dbuf_index = FRM2TFM(frm)->tfm_buf_idx;
891 	xch->xch_left_data_size -= frm->frm_payload_size;
892 	dbuf = xch->xch_dbufs[dbuf_index];
893 	ASSERT((dbuf) && (dbuf->db_flags & DB_DIRECTION_TO_RPORT));
894 
895 	/*
896 	 * We decrease db_sglist_length only for READ-type commands.
897 	 * For INQUIRY, resid could be non-zero, then db_sglist_length will
898 	 * be useful.
899 	 */
900 	dbuf->db_sglist_length--;
901 	if ((xch->xch_left_data_size <= 0) || (!dbuf->db_sglist_length)) {
902 		iof = 0;
903 		dbuf->db_xfer_status = FCT_SUCCESS;
904 		dbuf->db_flags |= DB_DONT_REUSE;
905 		if (dbuf->db_flags & DB_SEND_STATUS_GOOD) {
906 			if (fcoet_send_status(xch->xch_cmd) != FCT_SUCCESS) {
907 				return (FCOE_FAILURE);
908 			}
909 		} else {
910 			fct_scsi_data_xfer_done(xch->xch_cmd, dbuf, iof);
911 		}
912 	}
913 	FCOET_RELE_XCHG(xch);
914 	return (FCOE_SUCCESS);
915 }
916 
917 static int
918 fcoet_send_fcp_status_done(fcoe_frame_t *frm)
919 {
920 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
921 	fct_status_t		 fc_st = FCT_SUCCESS;
922 	uint32_t		 iof = FCT_IOF_FCA_DONE;
923 
924 	if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
925 		FCOET_RELE_XCHG(xch);
926 		return (FCOE_SUCCESS);
927 	}
928 
929 	if (fcoet_clear_unsol_exchange(xch) == FCOE_SUCCESS) {
930 		FCOET_RELE_XCHG(xch);
931 		fct_send_response_done(xch->xch_cmd, fc_st, iof);
932 	} else {
933 		/* Already cleared from hash table by abort */
934 		FCOET_RELE_XCHG(xch);
935 	}
936 
937 	return (FCOE_SUCCESS);
938 }
939 
940 /*
941  * Solicited frames callback area
942  */
943 static int
944 fcoet_send_unsol_els_rsp_done(fcoe_frame_t *frm)
945 {
946 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
947 	fct_status_t		 fc_st;
948 	uint32_t		 iof;
949 
950 	FCOET_EXT_LOG("fcoet_send_unsol_els_rsp_done",
951 	    "frm/oxid/els: %p/%x/%x",
952 	    frm, FRM_OXID(frm), XCH2ELS(xch)->els_req_payload[0]);
953 	if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
954 		FCOET_RELE_XCHG(xch);
955 		return (FCOE_SUCCESS);
956 	}
957 
958 	if (fcoet_clear_unsol_exchange(xch) == FCOE_FAILURE) {
959 		FCOET_RELE_XCHG(xch);
960 		return (FCOE_SUCCESS);
961 	}
962 
963 	FCOET_RELE_XCHG(xch);
964 	if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) {
965 		fc_st = FCT_SUCCESS;
966 		iof = FCT_IOF_FCA_DONE;
967 		fct_send_response_done(xch->xch_cmd, fc_st, iof);
968 	} else {
969 		/*
970 		 * We need update ss_link_info and flags.
971 		 */
972 		mutex_enter(&xch->xch_ss->ss_watch_mutex);
973 		xch->xch_ss->ss_link_info.portid =
974 		    xch->xch_cmd->cmd_lportid;
975 		xch->xch_ss->ss_link_info.port_topology =
976 		    PORT_TOPOLOGY_PT_TO_PT;
977 		if (frm->frm_eport->eport_link_speed == FCOE_PORT_SPEED_1G) {
978 			xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_1G;
979 		} else if (frm->frm_eport->eport_link_speed ==
980 		    FCOE_PORT_SPEED_10G) {
981 			xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G;
982 		}
983 		xch->xch_ss->ss_link_info.port_no_fct_flogi = 1;
984 		xch->xch_ss->ss_link_info.port_fca_flogi_done = 1;
985 		xch->xch_ss->ss_link_info.port_fct_flogi_done = 0;
986 		bcopy(XCH2ELS(xch)->els_req_payload + 20,
987 		    xch->xch_ss->ss_link_info.port_rpwwn, 8);
988 		bcopy(XCH2ELS(xch)->els_req_payload + 28,
989 		    xch->xch_ss->ss_link_info.port_rnwwn, 8);
990 		atomic_or_32(&xch->xch_ss->ss_flags,
991 		    SS_FLAG_UNSOL_FLOGI_DONE);
992 		atomic_or_32(&xch->xch_ss->ss_flags,
993 		    SS_FLAG_REPORT_TO_FCT);
994 
995 		xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC;
996 		mutex_exit(&xch->xch_ss->ss_watch_mutex);
997 
998 		fct_free(xch->xch_cmd);
999 	}
1000 	return (FCOE_SUCCESS);
1001 }
1002 
1003 /* ARGSUSED */
1004 static int
1005 fcoet_send_sol_els_req_done(fcoe_frame_t *frm)
1006 {
1007 	return (FCOE_SUCCESS);
1008 }
1009 
1010 /*
1011  * FCT have released relevant fct_cmd_t and fcoet_exchange_t now, so it's not
1012  * needed to notify FCT anything. Just do nothing.
1013  */
1014 /* ARGSUSED */
1015 static int
1016 fcoet_send_unsol_bls_acc_done(fcoe_frame_t *frm)
1017 {
1018 	FCOET_LOG("fcoet_send_unsol_bls_acc_done",
1019 	    "Unsolicited BA_ACC sent out and released ");
1020 
1021 	return (FCOE_SUCCESS);
1022 }
1023 
1024 /* ARGSUSED */
1025 static int
1026 fcoet_send_unsol_bls_rjt_done(fcoe_frame_t *frm)
1027 {
1028 	FCOET_LOG("fcoet_send_unsol_bls_rjt_done",
1029 	    "Unsolicited BA_RJT sent out and released");
1030 	return (FCOE_SUCCESS);
1031 }
1032 
1033 /* ARGSUSED */
1034 static int
1035 fcoet_send_sol_bls_req_done(fcoe_frame_t *frm)
1036 {
1037 	FCOET_LOG("fcoet_send_sol_bls_req_done",
1038 	    "Soclited ABTS was sent out and released");
1039 	return (FCOE_SUCCESS);
1040 }
1041 
1042 /* ARGSUSED */
1043 static int
1044 fcoet_send_sol_ct_req_done(fcoe_frame_t *frm)
1045 {
1046 	FCOET_LOG("fcoet_send_sol_ct_req_done",
1047 	    "CT request was sent out and released");
1048 	return (FCOE_SUCCESS);
1049 }
1050 
1051 /*
1052  * FCoET can only interpret solicited and unsolicited FLOGI, all the other
1053  * ELS/CT/FCP should be passed up to FCT.
1054  */
1055 static int
1056 fcoet_process_unsol_flogi_req(fcoet_exchange_t *xch)
1057 {
1058 	fcoe_frame_t *frm;
1059 
1060 	atomic_or_32(&xch->xch_ss->ss_flags, SS_FLAG_DELAY_PLOGI);
1061 
1062 	/*
1063 	 * In spec, common service parameter should indicate if it's from
1064 	 * N-port or F-port, but the initial intel implementation is not
1065 	 * spec-compliant, so we use eport_flags to workaround the problem
1066 	 */
1067 	if (!(xch->xch_ss->ss_eport->eport_flags & EPORT_FLAG_IS_DIRECT_P2P)) {
1068 		/*
1069 		 * The topology is switch P2P, so there's no need to respond
1070 		 * to this FLOGI
1071 		 */
1072 		FCOET_LOG("fcoet_process_unsol_flogi_req",
1073 		    "skip FLOGI, since we are in switch topology");
1074 		return (FCOE_SUCCESS);
1075 	}
1076 
1077 	/*
1078 	 * Send ACC according to the spec.
1079 	 */
1080 	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1081 	    FLOGI_ACC_PAYLOAD_SIZE + FCFH_SIZE, 0);
1082 	if (frm == NULL) {
1083 		ASSERT(0);
1084 		return (FCOE_FAILURE);
1085 	} else {
1086 		fcoet_init_tfm(frm, xch);
1087 		bzero(frm->frm_payload, frm->frm_payload_size);
1088 	}
1089 
1090 	FFM_R_CTL(0x23, frm);
1091 	FRM2TFM(frm)->tfm_rctl = 0x23;
1092 	FFM_TYPE(0x01, frm);
1093 	FFM_F_CTL(0x980000, frm);
1094 	FFM_OXID(xch->xch_oxid, frm);
1095 	FFM_RXID(xch->xch_rxid, frm);
1096 	FFM_S_ID(0xFFFFFE, frm);
1097 
1098 	/*
1099 	 * ACC
1100 	 */
1101 	frm->frm_payload[0] = 0x02;
1102 
1103 	/*
1104 	 * Common Svc Parameters
1105 	 */
1106 	frm->frm_payload[4] = 0x20;
1107 	frm->frm_payload[5] = 0x20;
1108 	frm->frm_payload[7] = 0x0A;
1109 	frm->frm_payload[10] = 0x05;
1110 	frm->frm_payload[11] = 0xAC;
1111 	bcopy(xch->xch_ss->ss_eport->eport_portwwn, frm->frm_payload + 20, 8);
1112 	bcopy(xch->xch_ss->ss_eport->eport_nodewwn, frm->frm_payload + 28, 8);
1113 
1114 	/*
1115 	 * Class3 Svc Parameters
1116 	 */
1117 	frm->frm_payload[68] = 0x88;
1118 
1119 	/*
1120 	 * Send FLOGI ACC out
1121 	 * After this, we should never use the exchange, because it could
1122 	 * have been released. Please pay attention to other similiar cases.
1123 	 */
1124 	xch->xch_ss->ss_eport->eport_tx_frame(frm);
1125 	return (FCOE_SUCCESS);
1126 }
1127 
1128 static int
1129 fcoet_process_sol_flogi_rsp(fcoe_frame_t *frm)
1130 {
1131 	int ret = FCOE_SUCCESS;
1132 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
1133 	fct_els_t		*els = CMD2ELS(xch->xch_cmd);
1134 	fcoet_soft_state_t	*ss = FRM2SS(frm);
1135 
1136 	if (els->els_resp_payload[0] == ELS_OP_ACC) {
1137 		/*
1138 		 * We need always update ss_link_info and flags for solicited
1139 		 * FLOGI, because someone has assigned address for you. The
1140 		 * initial intel implementation will always assign address for
1141 		 * you even you are in back-to-back mode (direct P2P).
1142 		 */
1143 		mutex_enter(&ss->ss_watch_mutex);
1144 		if (ss->ss_flags & SS_FLAG_PORT_DISABLED ||
1145 		    (ss->ss_sol_flogi_state != SFS_FLOGI_INIT &&
1146 		    ss->ss_sol_flogi_state != SFS_FLOGI_CHECK_TIMEOUT &&
1147 		    ss->ss_sol_flogi_state != SFS_ABTS_INIT)) {
1148 			/*
1149 			 * The status is not correct, this response may be
1150 			 * obsolete.
1151 			 */
1152 			mutex_exit(&ss->ss_watch_mutex);
1153 			FCOET_LOG("fcoet_process_sol_flogi_rsp",
1154 			    "FLOGI response is obsolete");
1155 			return (FCOE_FAILURE);
1156 		}
1157 		if (xch->xch_flags & XCH_FLAG_NONFCP_REQ_SENT) {
1158 			xch->xch_cmd->cmd_lportid = FRM_D_ID(frm);
1159 			xch->xch_ss->ss_link_info.portid =
1160 			    xch->xch_cmd->cmd_lportid;
1161 			/*
1162 			 * Check the bit 28 in 3rd word of the payload
1163 			 *  in common service parameters to know the
1164 			 * remote port is F_PORT or N_PORT
1165 			 */
1166 			if (els->els_resp_payload[8] & 0x10) {
1167 				uint8_t src_addr[ETHERADDRL];
1168 				frm->frm_eport->eport_flags &=
1169 				    ~EPORT_FLAG_IS_DIRECT_P2P;
1170 				FCOE_SET_DEFAULT_OUI(src_addr);
1171 				bcopy(frm->frm_hdr->hdr_d_id, src_addr + 3, 3);
1172 				bcopy((char *)frm->frm_hdr-22,
1173 				    frm->frm_eport->eport_efh_dst,
1174 				    ETHERADDRL);
1175 				frm->frm_eport->eport_set_mac_address(
1176 				    frm->frm_eport, src_addr, B_TRUE);
1177 				xch->xch_ss->ss_link_info.port_topology =
1178 				    PORT_TOPOLOGY_FABRIC_PT_TO_PT;
1179 			} else {
1180 				xch->xch_ss->ss_link_info.port_topology =
1181 				    PORT_TOPOLOGY_PT_TO_PT;
1182 			}
1183 
1184 			xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G;
1185 			xch->xch_ss->ss_link_info.port_no_fct_flogi = 1;
1186 			xch->xch_ss->ss_link_info.port_fca_flogi_done = 1;
1187 			xch->xch_ss->ss_link_info.port_fct_flogi_done = 0;
1188 			xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC;
1189 			cv_signal(&xch->xch_ss->ss_watch_cv);
1190 			FCOET_LOG("fcoet_process_sol_flogi_rsp",
1191 			    "FLOGI is accecpted");
1192 		} else {
1193 			FCOET_LOG("fcoet_process_sol_flogi_rsp",
1194 			    "FLOGI xch_flags/%x", xch->xch_flags);
1195 			ret = FCOE_FAILURE;
1196 		}
1197 		mutex_exit(&ss->ss_watch_mutex);
1198 	} else {
1199 		FCOET_LOG("fcoet_process_sol_flogi_rsp", "FLOGI is rejected");
1200 		ret = FCOE_FAILURE;
1201 	}
1202 	return (ret);
1203 }
1204