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