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