12a8164dfSZhong Wang /*
22a8164dfSZhong Wang  * CDDL HEADER START
32a8164dfSZhong Wang  *
42a8164dfSZhong Wang  * The contents of this file are subject to the terms of the
52a8164dfSZhong Wang  * Common Development and Distribution License (the "License").
62a8164dfSZhong Wang  * You may not use this file except in compliance with the License.
72a8164dfSZhong Wang  *
82a8164dfSZhong Wang  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92a8164dfSZhong Wang  * or http://www.opensolaris.org/os/licensing.
102a8164dfSZhong Wang  * See the License for the specific language governing permissions
112a8164dfSZhong Wang  * and limitations under the License.
122a8164dfSZhong Wang  *
132a8164dfSZhong Wang  * When distributing Covered Code, include this CDDL HEADER in each
142a8164dfSZhong Wang  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152a8164dfSZhong Wang  * If applicable, add the following below this CDDL HEADER, with the
162a8164dfSZhong Wang  * fields enclosed by brackets "[]" replaced with your own identifying
172a8164dfSZhong Wang  * information: Portions Copyright [yyyy] [name of copyright owner]
182a8164dfSZhong Wang  *
192a8164dfSZhong Wang  * CDDL HEADER END
202a8164dfSZhong Wang  */
212a8164dfSZhong Wang 
222a8164dfSZhong Wang /*
23*4558d122SViswanathan Kannappan  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
242a8164dfSZhong Wang  */
252a8164dfSZhong Wang 
262a8164dfSZhong Wang /*
272a8164dfSZhong Wang  * The following notice accompanied the original version of this file:
282a8164dfSZhong Wang  *
292a8164dfSZhong Wang  * BSD LICENSE
302a8164dfSZhong Wang  *
312a8164dfSZhong Wang  * Copyright(c) 2007 Intel Corporation. All rights reserved.
322a8164dfSZhong Wang  * All rights reserved.
332a8164dfSZhong Wang  *
342a8164dfSZhong Wang  * Redistribution and use in source and binary forms, with or without
352a8164dfSZhong Wang  * modification, are permitted provided that the following conditions
362a8164dfSZhong Wang  * are met:
372a8164dfSZhong Wang  *
382a8164dfSZhong Wang  *   * Redistributions of source code must retain the above copyright
392a8164dfSZhong Wang  *     notice, this list of conditions and the following disclaimer.
402a8164dfSZhong Wang  *   * Redistributions in binary form must reproduce the above copyright
412a8164dfSZhong Wang  *     notice, this list of conditions and the following disclaimer in
422a8164dfSZhong Wang  *     the documentation and/or other materials provided with the
432a8164dfSZhong Wang  *     distribution.
442a8164dfSZhong Wang  *   * Neither the name of Intel Corporation nor the names of its
452a8164dfSZhong Wang  *     contributors may be used to endorse or promote products derived
462a8164dfSZhong Wang  *     from this software without specific prior written permission.
472a8164dfSZhong Wang  *
482a8164dfSZhong Wang  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
492a8164dfSZhong Wang  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
502a8164dfSZhong Wang  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
512a8164dfSZhong Wang  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
522a8164dfSZhong Wang  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
532a8164dfSZhong Wang  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
542a8164dfSZhong Wang  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
552a8164dfSZhong Wang  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
562a8164dfSZhong Wang  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
572a8164dfSZhong Wang  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
582a8164dfSZhong Wang  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
592a8164dfSZhong Wang  */
602a8164dfSZhong Wang 
612a8164dfSZhong Wang /*
622a8164dfSZhong Wang  * This file defines interfaces between fcoe and fcoet driver.
632a8164dfSZhong Wang  */
642a8164dfSZhong Wang 
652a8164dfSZhong Wang /*
662a8164dfSZhong Wang  * Driver kernel header files
672a8164dfSZhong Wang  */
682a8164dfSZhong Wang #include <sys/conf.h>
692a8164dfSZhong Wang #include <sys/ddi.h>
702a8164dfSZhong Wang #include <sys/stat.h>
712a8164dfSZhong Wang #include <sys/pci.h>
722a8164dfSZhong Wang #include <sys/sunddi.h>
732a8164dfSZhong Wang #include <sys/modctl.h>
742a8164dfSZhong Wang #include <sys/file.h>
752a8164dfSZhong Wang #include <sys/cred.h>
762a8164dfSZhong Wang #include <sys/byteorder.h>
772a8164dfSZhong Wang #include <sys/atomic.h>
782a8164dfSZhong Wang #include <sys/modhash.h>
792a8164dfSZhong Wang #include <sys/scsi/scsi.h>
802a8164dfSZhong Wang #include <sys/ethernet.h>
812a8164dfSZhong Wang 
822a8164dfSZhong Wang /*
832a8164dfSZhong Wang  * COMSTAR header files
842a8164dfSZhong Wang  */
852a8164dfSZhong Wang #include <sys/stmf_defines.h>
862a8164dfSZhong Wang #include <sys/fct_defines.h>
872a8164dfSZhong Wang #include <sys/stmf.h>
882a8164dfSZhong Wang #include <sys/portif.h>
892a8164dfSZhong Wang #include <sys/fct.h>
902a8164dfSZhong Wang 
912a8164dfSZhong Wang /*
922a8164dfSZhong Wang  * FCoE header files
932a8164dfSZhong Wang  */
942a8164dfSZhong Wang #include <sys/fcoe/fcoe_common.h>
952a8164dfSZhong Wang 
962a8164dfSZhong Wang /*
972a8164dfSZhong Wang  * Driver's own header files
982a8164dfSZhong Wang  */
99*4558d122SViswanathan Kannappan #include "fcoet.h"
100*4558d122SViswanathan Kannappan #include "fcoet_eth.h"
1012a8164dfSZhong Wang 
1022a8164dfSZhong Wang /*
1032a8164dfSZhong Wang  * function forward declaration
1042a8164dfSZhong Wang  */
1052a8164dfSZhong Wang static fcoet_exchange_t *fcoet_create_unsol_exchange(fcoe_frame_t *frame);
1062a8164dfSZhong Wang static int fcoet_process_sol_fcp_data(fcoe_frame_t *frm);
1072a8164dfSZhong Wang static int fcoet_process_unsol_fcp_cmd(fcoe_frame_t *frm);
1082a8164dfSZhong Wang static int fcoet_process_unsol_els_req(fcoe_frame_t *frm);
1092a8164dfSZhong Wang static int fcoet_process_sol_els_rsp(fcoe_frame_t *frm);
1102a8164dfSZhong Wang static int fcoet_process_unsol_abts_req(fcoe_frame_t *frame);
1112a8164dfSZhong Wang static int fcoet_process_sol_abts_acc(fcoe_frame_t *frame);
1122a8164dfSZhong Wang static int fcoet_process_sol_abts_rjt(fcoe_frame_t *frame);
1132a8164dfSZhong Wang static int fcoet_process_unsol_ct_req(fcoe_frame_t *frm);
1142a8164dfSZhong Wang static int fcoet_process_sol_ct_rsp(fcoe_frame_t *frame);
1152a8164dfSZhong Wang static int fcoet_process_sol_flogi_rsp(fcoe_frame_t *frame);
1162a8164dfSZhong Wang static int fcoet_send_sol_fcp_data_done(fcoe_frame_t *frm);
1172a8164dfSZhong Wang static int fcoet_send_fcp_status_done(fcoe_frame_t *frm);
1182a8164dfSZhong Wang static int fcoet_send_unsol_els_rsp_done(fcoe_frame_t *frm);
1192a8164dfSZhong Wang static int fcoet_send_sol_els_req_done(fcoe_frame_t *frm);
1202a8164dfSZhong Wang static int fcoet_send_unsol_bls_acc_done(fcoe_frame_t *frm);
1212a8164dfSZhong Wang static int fcoet_send_unsol_bls_rjt_done(fcoe_frame_t *frm);
1222a8164dfSZhong Wang static int fcoet_send_sol_bls_req_done(fcoe_frame_t *frm);
1232a8164dfSZhong Wang static int fcoet_send_sol_ct_req_done(fcoe_frame_t *frm);
1242a8164dfSZhong Wang static int fcoet_process_unsol_flogi_req(fcoet_exchange_t *xch);
1252a8164dfSZhong Wang 
1262a8164dfSZhong Wang /*
1272a8164dfSZhong Wang  * rx_frame & release_sol_frame
1282a8164dfSZhong Wang  * There should be no same OXID/RXID in on-going exchanges.
1292a8164dfSZhong Wang  * RXID -> unsol_rxid_hash
1302a8164dfSZhong Wang  * OXID -> sol_oxid_hash
1312a8164dfSZhong Wang  */
1322a8164dfSZhong Wang 
1332a8164dfSZhong Wang void
fcoet_rx_frame(fcoe_frame_t * frm)1342a8164dfSZhong Wang fcoet_rx_frame(fcoe_frame_t *frm)
1352a8164dfSZhong Wang {
1362a8164dfSZhong Wang 	uint8_t rctl = FRM_R_CTL(frm);
1372a8164dfSZhong Wang 
1382a8164dfSZhong Wang 	switch (rctl) {
1392a8164dfSZhong Wang 	case 0x01:
1402a8164dfSZhong Wang 		/*
1412a8164dfSZhong Wang 		 * Solicited data
1422a8164dfSZhong Wang 		 */
1432a8164dfSZhong Wang 		if (fcoet_process_sol_fcp_data(frm)) {
1442a8164dfSZhong Wang 			FCOET_LOG("fcoet_rx_frame",
1452a8164dfSZhong Wang 			    "fcoet_process_sol_fcp_data failed");
1462a8164dfSZhong Wang 		}
1472a8164dfSZhong Wang 		break;
1482a8164dfSZhong Wang 
1492a8164dfSZhong Wang 	case 0x06:
1502a8164dfSZhong Wang 		/*
1512a8164dfSZhong Wang 		 * Unsolicited fcp_cmnd
1522a8164dfSZhong Wang 		 */
1532a8164dfSZhong Wang 		if (fcoet_process_unsol_fcp_cmd(frm)) {
1542a8164dfSZhong Wang 			FCOET_LOG("fcoet_rx_frame",
1552a8164dfSZhong Wang 			    "fcoet_process_unsol_fcp_cmd failed");
1562a8164dfSZhong Wang 		}
1572a8164dfSZhong Wang 		break;
1582a8164dfSZhong Wang 
1592a8164dfSZhong Wang 	case 0x22:
1602a8164dfSZhong Wang 		/*
1612a8164dfSZhong Wang 		 * unsolicited ELS req
1622a8164dfSZhong Wang 		 */
1632a8164dfSZhong Wang 		if (fcoet_process_unsol_els_req(frm)) {
1642a8164dfSZhong Wang 			FCOET_LOG("fcoet_rx_frame",
1652a8164dfSZhong Wang 			    "fcoet_process_unsol_els_req failed");
1662a8164dfSZhong Wang 		}
1672a8164dfSZhong Wang 		break;
1682a8164dfSZhong Wang 
1692a8164dfSZhong Wang 	case 0x23:
1702a8164dfSZhong Wang 		/*
1712a8164dfSZhong Wang 		 * solicited ELS rsp
1722a8164dfSZhong Wang 		 */
1732a8164dfSZhong Wang 		if (fcoet_process_sol_els_rsp(frm)) {
1742a8164dfSZhong Wang 			FCOET_LOG("fcoet_rx_frame",
1752a8164dfSZhong Wang 			    "fcoet_process_sol_els_rsp failed");
1762a8164dfSZhong Wang 		}
1772a8164dfSZhong Wang 		break;
1782a8164dfSZhong Wang 
1792a8164dfSZhong Wang 	case 0x81:
1802a8164dfSZhong Wang 		/*
1812a8164dfSZhong Wang 		 *  unsolicted ABTS req
1822a8164dfSZhong Wang 		 */
1832a8164dfSZhong Wang 		if (fcoet_process_unsol_abts_req(frm)) {
1842a8164dfSZhong Wang 			FCOET_LOG("fcoet_rx_frame",
1852a8164dfSZhong Wang 			    "fcoet_process_unsol_abts_req failed");
1862a8164dfSZhong Wang 		}
1872a8164dfSZhong Wang 		break;
1882a8164dfSZhong Wang 
1892a8164dfSZhong Wang 	case 0x84:
1902a8164dfSZhong Wang 		/*
1912a8164dfSZhong Wang 		 * solicited ABTS acc response
1922a8164dfSZhong Wang 		 */
1932a8164dfSZhong Wang 		if (fcoet_process_sol_abts_acc(frm)) {
1942a8164dfSZhong Wang 			FCOET_LOG("fcoet_rx_frame",
1952a8164dfSZhong Wang 			    "fcoet_process_sol_abts_acc failed");
1962a8164dfSZhong Wang 		}
1972a8164dfSZhong Wang 		break;
1982a8164dfSZhong Wang 	case 0x85:
1992a8164dfSZhong Wang 		/*
2002a8164dfSZhong Wang 		 * solcited ABTS rjt response
2012a8164dfSZhong Wang 		 */
2022a8164dfSZhong Wang 		if (fcoet_process_sol_abts_rjt(frm)) {
2032a8164dfSZhong Wang 			FCOET_LOG("fcoet_rx_frame",
2042a8164dfSZhong Wang 			    "fcoet_process_sol_abts_rjt failed");
2052a8164dfSZhong Wang 		}
2062a8164dfSZhong Wang 		break;
2072a8164dfSZhong Wang 
2082a8164dfSZhong Wang 	case 0x02:
2092a8164dfSZhong Wang 		/*
2102a8164dfSZhong Wang 		 * unsolicited CT req
2112a8164dfSZhong Wang 		 */
2122a8164dfSZhong Wang 		if (fcoet_process_unsol_ct_req(frm)) {
2132a8164dfSZhong Wang 			FCOET_LOG("fcoet_rx_frame",
2142a8164dfSZhong Wang 			    "fcoet_process_sol_ct_rsp failed");
2152a8164dfSZhong Wang 		}
2162a8164dfSZhong Wang 		break;
2172a8164dfSZhong Wang 
2182a8164dfSZhong Wang 	case 0x03:
2192a8164dfSZhong Wang 		/*
2202a8164dfSZhong Wang 		 * sol ct rsp
2212a8164dfSZhong Wang 		 */
2222a8164dfSZhong Wang 		if (fcoet_process_sol_ct_rsp(frm)) {
2232a8164dfSZhong Wang 			FCOET_LOG("fcoet_rx_frame",
2242a8164dfSZhong Wang 			    "fcoet_process_sol_ct_rsp failed");
2252a8164dfSZhong Wang 		}
2262a8164dfSZhong Wang 		break;
2272a8164dfSZhong Wang 
2282a8164dfSZhong Wang 	default:
2292a8164dfSZhong Wang 		/*
2302a8164dfSZhong Wang 		 * Unsupported frame
2312a8164dfSZhong Wang 		 */
2322a8164dfSZhong Wang 		PRT_FRM_HDR("Unsupported unsol frame: ", frm);
2332a8164dfSZhong Wang 		break;
2342a8164dfSZhong Wang 	}
2352a8164dfSZhong Wang 
2362a8164dfSZhong Wang 	/*
2372a8164dfSZhong Wang 	 * Release the frame in the end
2382a8164dfSZhong Wang 	 */
2392a8164dfSZhong Wang 	frm->frm_eport->eport_free_netb(frm->frm_netb);
2402a8164dfSZhong Wang 	frm->frm_eport->eport_release_frame(frm);
2412a8164dfSZhong Wang }
2422a8164dfSZhong Wang 
2432a8164dfSZhong Wang /*
2442a8164dfSZhong Wang  * For solicited frames, after FCoE has sent it out, it will call this
2452a8164dfSZhong Wang  * to notify client(FCoEI/FCoET) about its completion.
2462a8164dfSZhong Wang  */
2472a8164dfSZhong Wang void
fcoet_release_sol_frame(fcoe_frame_t * frm)2482a8164dfSZhong Wang fcoet_release_sol_frame(fcoe_frame_t *frm)
2492a8164dfSZhong Wang {
2502a8164dfSZhong Wang 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
2512a8164dfSZhong Wang 
2522a8164dfSZhong Wang 	/*
2532a8164dfSZhong Wang 	 * From now, we should not access both frm_hdr and frm_payload. Its
2542a8164dfSZhong Wang 	 * mblk could have been released by MAC driver.
2552a8164dfSZhong Wang 	 */
2562a8164dfSZhong Wang 	switch (FRM2TFM(frm)->tfm_rctl) {
2572a8164dfSZhong Wang 	case 0x01:
2582a8164dfSZhong Wang 		if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
2592a8164dfSZhong Wang 			FCOET_RELE_XCHG(xch);
2602a8164dfSZhong Wang 			break;
2612a8164dfSZhong Wang 		}
2622a8164dfSZhong Wang 		if (fcoet_send_sol_fcp_data_done(frm)) {
2632a8164dfSZhong Wang 			ASSERT(0);
2642a8164dfSZhong Wang 		}
2652a8164dfSZhong Wang 		break;
2662a8164dfSZhong Wang 
2672a8164dfSZhong Wang 	case 0x05:
2682a8164dfSZhong Wang 		break;
2692a8164dfSZhong Wang 
2702a8164dfSZhong Wang 	case 0x07:
2712a8164dfSZhong Wang 		if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
2722a8164dfSZhong Wang 			FCOET_RELE_XCHG(xch);
2732a8164dfSZhong Wang 			break;
2742a8164dfSZhong Wang 		}
2752a8164dfSZhong Wang 
2762a8164dfSZhong Wang 		if (fcoet_send_fcp_status_done(frm)) {
2772a8164dfSZhong Wang 			ASSERT(0);
2782a8164dfSZhong Wang 		}
2792a8164dfSZhong Wang 		break;
2802a8164dfSZhong Wang 
2812a8164dfSZhong Wang 	case 0x23:
2822a8164dfSZhong Wang 		if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
2832a8164dfSZhong Wang 			FCOET_RELE_XCHG(xch);
2842a8164dfSZhong Wang 			break;
2852a8164dfSZhong Wang 		}
2862a8164dfSZhong Wang 		if (fcoet_send_unsol_els_rsp_done(frm)) {
2872a8164dfSZhong Wang 			ASSERT(0);
2882a8164dfSZhong Wang 		}
2892a8164dfSZhong Wang 		break;
2902a8164dfSZhong Wang 
2912a8164dfSZhong Wang 	case 0x22:
2922a8164dfSZhong Wang 		if (fcoet_send_sol_els_req_done(frm)) {
2932a8164dfSZhong Wang 			ASSERT(0);
2942a8164dfSZhong Wang 		}
2952a8164dfSZhong Wang 		break;
2962a8164dfSZhong Wang 
2972a8164dfSZhong Wang 	case 0x84:
2982a8164dfSZhong Wang 		if (fcoet_send_unsol_bls_acc_done(frm)) {
2992a8164dfSZhong Wang 			ASSERT(0);
3002a8164dfSZhong Wang 		}
3012a8164dfSZhong Wang 		break;
3022a8164dfSZhong Wang 
3032a8164dfSZhong Wang 	case 0x85:
3042a8164dfSZhong Wang 		if (fcoet_send_unsol_bls_rjt_done(frm)) {
3052a8164dfSZhong Wang 			ASSERT(0);
3062a8164dfSZhong Wang 		}
3072a8164dfSZhong Wang 		break;
3082a8164dfSZhong Wang 
3092a8164dfSZhong Wang 	case 0x81:
3102a8164dfSZhong Wang 		if (fcoet_send_sol_bls_req_done(frm)) {
3112a8164dfSZhong Wang 			ASSERT(0);
3122a8164dfSZhong Wang 		}
3132a8164dfSZhong Wang 		break;
3142a8164dfSZhong Wang 
3152a8164dfSZhong Wang 	case 0x02:
3162a8164dfSZhong Wang 		if (fcoet_send_sol_ct_req_done(frm)) {
3172a8164dfSZhong Wang 			ASSERT(0);
3182a8164dfSZhong Wang 		}
3192a8164dfSZhong Wang 		break;
3202a8164dfSZhong Wang 
3212a8164dfSZhong Wang 	case 0x03:
3222a8164dfSZhong Wang 	default:
3232a8164dfSZhong Wang 		/*
3242a8164dfSZhong Wang 		 * Unsupported frame
3252a8164dfSZhong Wang 		 */
3262a8164dfSZhong Wang 		PRT_FRM_HDR("Unsupported sol frame: ", frm);
3272a8164dfSZhong Wang 		break;
3282a8164dfSZhong Wang 	}
3292a8164dfSZhong Wang 
3302a8164dfSZhong Wang 	/*
3312a8164dfSZhong Wang 	 * We should release the frame
3322a8164dfSZhong Wang 	 */
3332a8164dfSZhong Wang 	FRM2SS(frm)->ss_eport->eport_release_frame(frm);
3342a8164dfSZhong Wang }
3352a8164dfSZhong Wang 
3362a8164dfSZhong Wang void
fcoet_port_event(fcoe_port_t * eport,uint32_t event)3372a8164dfSZhong Wang fcoet_port_event(fcoe_port_t *eport, uint32_t event)
3382a8164dfSZhong Wang {
3392a8164dfSZhong Wang 	fcoet_soft_state_t *ss = EPORT2SS(eport);
3402a8164dfSZhong Wang 	switch (event) {
3412a8164dfSZhong Wang 	case FCOE_NOTIFY_EPORT_LINK_UP:
3422a8164dfSZhong Wang 		if (eport->eport_mtu >= FCOE_MIN_MTU_SIZE) {
3432a8164dfSZhong Wang 			ss->ss_fcp_data_payload_size =
3442a8164dfSZhong Wang 			    FCOE_DEFAULT_FCP_DATA_PAYLOAD_SIZE;
3452a8164dfSZhong Wang 		} else {
3462a8164dfSZhong Wang 			ss->ss_fcp_data_payload_size =
3472a8164dfSZhong Wang 			    FCOE_MIN_FCP_DATA_PAYLOAD_SIZE;
3482a8164dfSZhong Wang 		}
3492a8164dfSZhong Wang 		FCOET_LOG("fcoet_port_event", "LINK UP notified");
3502a8164dfSZhong Wang 		mutex_enter(&ss->ss_watch_mutex);
3512a8164dfSZhong Wang 		ss->ss_sol_flogi_state = SFS_FLOGI_INIT;
3522a8164dfSZhong Wang 		cv_signal(&ss->ss_watch_cv);
3532a8164dfSZhong Wang 		mutex_exit(&ss->ss_watch_mutex);
3542a8164dfSZhong Wang 		break;
3552a8164dfSZhong Wang 	case FCOE_NOTIFY_EPORT_LINK_DOWN:
3562a8164dfSZhong Wang 		fct_handle_event(ss->ss_port,
3572a8164dfSZhong Wang 		    FCT_EVENT_LINK_DOWN, 0, 0);
3582a8164dfSZhong Wang 		/* Need clear up all other things */
3592a8164dfSZhong Wang 		FCOET_LOG("fcoet_port_event", "LINK DOWN notified");
3602a8164dfSZhong Wang 		ss->ss_sol_flogi_state = SFS_WAIT_LINKUP;
3612a8164dfSZhong Wang 		break;
3622a8164dfSZhong Wang 	default:
3632a8164dfSZhong Wang 		break;
3642a8164dfSZhong Wang 	}
3652a8164dfSZhong Wang }
3662a8164dfSZhong Wang 
3672a8164dfSZhong Wang /*
3682a8164dfSZhong Wang  * For unsolicited exchanges, FCoET is only responsible for allocation of
3692a8164dfSZhong Wang  * req_payload. FCT will allocate resp_payload after the exchange is
3702a8164dfSZhong Wang  * passed on.
3712a8164dfSZhong Wang  */
3722a8164dfSZhong Wang static fcoet_exchange_t *
fcoet_create_unsol_exchange(fcoe_frame_t * frm)3732a8164dfSZhong Wang fcoet_create_unsol_exchange(fcoe_frame_t *frm)
3742a8164dfSZhong Wang {
3752a8164dfSZhong Wang 	uint8_t			 r_ctl;
3762a8164dfSZhong Wang 	int			 cdb_size;
3772a8164dfSZhong Wang 	fcoet_exchange_t	*xch, *xch_tmp;
3782a8164dfSZhong Wang 	fct_cmd_t		*cmd;
3792a8164dfSZhong Wang 	fcoe_fcp_cmnd_t		*ffc;
3802a8164dfSZhong Wang 	uint32_t		task_expected_len = 0;
3812a8164dfSZhong Wang 
3822a8164dfSZhong Wang 	r_ctl = FRM_R_CTL(frm);
3832a8164dfSZhong Wang 	switch (r_ctl) {
3842a8164dfSZhong Wang 	case 0x22:
3852a8164dfSZhong Wang 		/*
3862a8164dfSZhong Wang 		 * FCoET's unsolicited ELS
3872a8164dfSZhong Wang 		 */
3882a8164dfSZhong Wang 		cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ELS,
3892a8164dfSZhong Wang 		    GET_STRUCT_SIZE(fcoet_exchange_t) +
3902a8164dfSZhong Wang 		    frm->frm_payload_size, 0);
3912a8164dfSZhong Wang 		if (cmd == NULL) {
3922a8164dfSZhong Wang 			FCOET_EXT_LOG(0, "can't get cmd");
3932a8164dfSZhong Wang 			return (NULL);
3942a8164dfSZhong Wang 		}
3952a8164dfSZhong Wang 		break;
3962a8164dfSZhong Wang 
3972a8164dfSZhong Wang 	case 0x06:
3982a8164dfSZhong Wang 		/*
3992a8164dfSZhong Wang 		 * FCoET's unsolicited SCSI cmd
4002a8164dfSZhong Wang 		 */
4012a8164dfSZhong Wang 		cdb_size = 16;	/* need improve later */
4022a8164dfSZhong Wang 		cmd = fct_scsi_task_alloc(FRM2SS(frm)->ss_port, FCT_HANDLE_NONE,
4032a8164dfSZhong Wang 		    FRM_S_ID(frm), frm->frm_payload, cdb_size,
4042a8164dfSZhong Wang 		    STMF_TASK_EXT_NONE);
4052a8164dfSZhong Wang 		if (cmd == NULL) {
4062a8164dfSZhong Wang 			FCOET_EXT_LOG(0, "can't get fcp cmd");
4072a8164dfSZhong Wang 			return (NULL);
4082a8164dfSZhong Wang 		}
4092a8164dfSZhong Wang 		ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload;
4102a8164dfSZhong Wang 		task_expected_len = FCOE_B2V_4(ffc->ffc_fcp_dl);
4112a8164dfSZhong Wang 		break;
4122a8164dfSZhong Wang 
4132a8164dfSZhong Wang 	default:
4142a8164dfSZhong Wang 		FCOET_EXT_LOG(0, "unsupported R_CTL: %x", r_ctl);
4152a8164dfSZhong Wang 		return (NULL);
4162a8164dfSZhong Wang 	}
4172a8164dfSZhong Wang 
4182a8164dfSZhong Wang 	/*
4192a8164dfSZhong Wang 	 * xch initialization
4202a8164dfSZhong Wang 	 */
4212a8164dfSZhong Wang 	xch = CMD2XCH(cmd);
4222a8164dfSZhong Wang 	xch->xch_oxid = FRM_OXID(frm);
4232a8164dfSZhong Wang 	xch->xch_flags = 0;
4242a8164dfSZhong Wang 	xch->xch_ss = FRM2SS(frm);
4252a8164dfSZhong Wang 	xch->xch_cmd = cmd;
4262a8164dfSZhong Wang 	xch->xch_current_seq = NULL;
4272a8164dfSZhong Wang 	xch->xch_left_data_size = 0;
4282a8164dfSZhong Wang 	if (task_expected_len) {
4292a8164dfSZhong Wang 		xch->xch_dbuf_num =
4302a8164dfSZhong Wang 		    (task_expected_len + FCOET_MAX_DBUF_LEN - 1) /
4312a8164dfSZhong Wang 		    FCOET_MAX_DBUF_LEN;
4322a8164dfSZhong Wang 		xch->xch_dbufs =
4332a8164dfSZhong Wang 		    kmem_zalloc(xch->xch_dbuf_num * sizeof (stmf_data_buf_t *),
4342a8164dfSZhong Wang 		    KM_SLEEP);
4352a8164dfSZhong Wang 	}
4362a8164dfSZhong Wang 	xch->xch_start_time = ddi_get_lbolt();
4372a8164dfSZhong Wang 	do {
4382a8164dfSZhong Wang 		xch->xch_rxid = atomic_add_16_nv(
4392a8164dfSZhong Wang 		    &xch->xch_ss->ss_next_unsol_rxid, 1);
4402a8164dfSZhong Wang 		if (xch->xch_rxid == 0xFFFF) {
4412a8164dfSZhong Wang 			xch->xch_rxid = atomic_add_16_nv(
4422a8164dfSZhong Wang 			    &xch->xch_ss->ss_next_unsol_rxid, 1);
4432a8164dfSZhong Wang 		}
4442a8164dfSZhong Wang 	} while (mod_hash_find(FRM2SS(frm)->ss_unsol_rxid_hash,
4452a8164dfSZhong Wang 	    (mod_hash_key_t)(intptr_t)xch->xch_rxid,
4462a8164dfSZhong Wang 	    (mod_hash_val_t)&xch_tmp) == 0);
4472a8164dfSZhong Wang 
4482a8164dfSZhong Wang 	xch->xch_sequence_no = 0;
4492a8164dfSZhong Wang 	xch->xch_ref = 0;
4502a8164dfSZhong Wang 	(void) mod_hash_insert(xch->xch_ss->ss_unsol_rxid_hash,
4512a8164dfSZhong Wang 	    (mod_hash_key_t)(intptr_t)xch->xch_rxid, (mod_hash_val_t)xch);
4522a8164dfSZhong Wang 	xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
4532a8164dfSZhong Wang 
4542a8164dfSZhong Wang 	/*
4552a8164dfSZhong Wang 	 * cmd initialization
4562a8164dfSZhong Wang 	 */
4572a8164dfSZhong Wang 	cmd->cmd_port = FRM2SS(frm)->ss_port;
4582a8164dfSZhong Wang 	cmd->cmd_rp_handle = FCT_HANDLE_NONE;
4592a8164dfSZhong Wang 	cmd->cmd_rportid = FRM_S_ID(frm);
4602a8164dfSZhong Wang 	cmd->cmd_lportid = FRM_D_ID(frm);
4612a8164dfSZhong Wang 	cmd->cmd_oxid = xch->xch_oxid;
4622a8164dfSZhong Wang 	cmd->cmd_rxid = xch->xch_rxid;
4632a8164dfSZhong Wang 
4642a8164dfSZhong Wang 	fcoet_init_tfm(frm, xch);
4652a8164dfSZhong Wang 	return (xch);
4662a8164dfSZhong Wang }
4672a8164dfSZhong Wang 
4682a8164dfSZhong Wang int
fcoet_clear_unsol_exchange(fcoet_exchange_t * xch)4692a8164dfSZhong Wang fcoet_clear_unsol_exchange(fcoet_exchange_t *xch)
4702a8164dfSZhong Wang {
4712a8164dfSZhong Wang 	mod_hash_val_t val = NULL;
4722a8164dfSZhong Wang 
4732a8164dfSZhong Wang 	if (mod_hash_remove(xch->xch_ss->ss_unsol_rxid_hash,
4742a8164dfSZhong Wang 	    (mod_hash_key_t)(intptr_t)xch->xch_rxid, &val) == 0) {
4752a8164dfSZhong Wang 		if (xch->xch_dbuf_num) {
4762a8164dfSZhong Wang 			kmem_free((void*)xch->xch_dbufs,
4772a8164dfSZhong Wang 			    xch->xch_dbuf_num * sizeof (void *));
4782a8164dfSZhong Wang 			xch->xch_dbufs = NULL;
4792a8164dfSZhong Wang 			xch->xch_dbuf_num = 0;
4802a8164dfSZhong Wang 		}
4812a8164dfSZhong Wang 		ASSERT(xch->xch_flags & XCH_FLAG_IN_HASH_TABLE);
4822a8164dfSZhong Wang 		ASSERT((fcoet_exchange_t *)val == xch);
4832a8164dfSZhong Wang 		xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
4842a8164dfSZhong Wang 		return (FCOE_SUCCESS);
4852a8164dfSZhong Wang 	}
4862a8164dfSZhong Wang 
4872a8164dfSZhong Wang 	FCOET_LOG("fcoet_clear_unsol_exchange", "xch %p already cleared from "
4882a8164dfSZhong Wang 	    "hash table", xch);
4892a8164dfSZhong Wang 	return (FCOE_FAILURE);
4902a8164dfSZhong Wang }
4912a8164dfSZhong Wang 
4922a8164dfSZhong Wang void
fcoet_clear_sol_exchange(fcoet_exchange_t * xch)4932a8164dfSZhong Wang fcoet_clear_sol_exchange(fcoet_exchange_t *xch)
4942a8164dfSZhong Wang {
4952a8164dfSZhong Wang 	mod_hash_val_t val = NULL;
4962a8164dfSZhong Wang 
4972a8164dfSZhong Wang 	if (xch->xch_flags & XCH_FLAG_IN_HASH_TABLE) {
4982a8164dfSZhong Wang 		(void) mod_hash_remove(xch->xch_ss->ss_sol_oxid_hash,
4992a8164dfSZhong Wang 		    (mod_hash_key_t)(intptr_t)xch->xch_oxid, &val);
5002a8164dfSZhong Wang 		ASSERT((fcoet_exchange_t *)val == xch);
5012a8164dfSZhong Wang 		xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
5022a8164dfSZhong Wang 	}
5032a8164dfSZhong Wang }
5042a8164dfSZhong Wang 
5052a8164dfSZhong Wang static int
fcoet_process_sol_fcp_data(fcoe_frame_t * frm)5062a8164dfSZhong Wang fcoet_process_sol_fcp_data(fcoe_frame_t *frm)
5072a8164dfSZhong Wang {
5082a8164dfSZhong Wang 	fcoet_exchange_t	*xch = NULL;
5092a8164dfSZhong Wang 	fcoet_soft_state_t	*ss  = NULL;
5102a8164dfSZhong Wang 	fct_status_t		 fc_st;
5112a8164dfSZhong Wang 	uint32_t		 iof;
5122a8164dfSZhong Wang 	uint16_t		 unsol_rxid;
5132a8164dfSZhong Wang 	int			 sge_idx;
5142a8164dfSZhong Wang 	stmf_data_buf_t		*dbuf;
5152a8164dfSZhong Wang 	int			 data_offset;
5162a8164dfSZhong Wang 
5172a8164dfSZhong Wang 	unsol_rxid = FRM_RXID(frm);
5182a8164dfSZhong Wang 	if (mod_hash_find_cb(FRM2SS(frm)->ss_unsol_rxid_hash,
5192a8164dfSZhong Wang 	    (mod_hash_key_t)(intptr_t)unsol_rxid,
5202a8164dfSZhong Wang 	    (mod_hash_val_t)&xch, fcoet_modhash_find_cb) != 0) {
5212a8164dfSZhong Wang 		return (FCOE_FAILURE);
5222a8164dfSZhong Wang 	}
5232a8164dfSZhong Wang 
5242a8164dfSZhong Wang 	/*
5252a8164dfSZhong Wang 	 * we will always have a buf waiting there
5262a8164dfSZhong Wang 	 */
5272a8164dfSZhong Wang 	data_offset = FRM_PARAM(frm);
5282a8164dfSZhong Wang 	dbuf = xch->xch_dbufs[data_offset/FCOET_MAX_DBUF_LEN];
5292a8164dfSZhong Wang 	ASSERT(dbuf);
5302a8164dfSZhong Wang 	ss = xch->xch_ss;
5312a8164dfSZhong Wang 	sge_idx = (data_offset % FCOET_MAX_DBUF_LEN)/
5322a8164dfSZhong Wang 	    ss->ss_fcp_data_payload_size;
5332a8164dfSZhong Wang 
5342a8164dfSZhong Wang 	ASSERT(((sge_idx < FCOET_GET_SEG_NUM(dbuf) - 1) &&
5352a8164dfSZhong Wang 	    (frm->frm_payload_size == ss->ss_fcp_data_payload_size)) ||
5362a8164dfSZhong Wang 	    ((sge_idx == FCOET_GET_SEG_NUM(dbuf) - 1) &&
5372a8164dfSZhong Wang 	    (frm->frm_payload_size % ss->ss_fcp_data_payload_size ==
5382a8164dfSZhong Wang 	    dbuf->db_data_size % ss->ss_fcp_data_payload_size)));
5392a8164dfSZhong Wang 
5402a8164dfSZhong Wang 	bcopy(frm->frm_payload, dbuf->db_sglist[sge_idx].seg_addr,
5412a8164dfSZhong Wang 	    frm->frm_payload_size);
5427ff83669SZhong Wang 	atomic_add_16(&dbuf->db_sglist_length, 1);
5432a8164dfSZhong Wang 
5442a8164dfSZhong Wang 	xch->xch_left_data_size -= frm->frm_payload_size;
5457ff83669SZhong Wang 	if ((xch->xch_left_data_size <= 0) ||
5467ff83669SZhong Wang 	    dbuf->db_sglist_length >= FCOET_GET_SEG_NUM(dbuf)) {
5472a8164dfSZhong Wang 		fc_st = FCT_SUCCESS;
5482a8164dfSZhong Wang 		iof = 0;
5492a8164dfSZhong Wang 		dbuf->db_xfer_status = fc_st;
5502a8164dfSZhong Wang 		dbuf->db_flags |= DB_DONT_REUSE;
5512a8164dfSZhong Wang 		fct_scsi_data_xfer_done(xch->xch_cmd, dbuf, iof);
5522a8164dfSZhong Wang 	}
5532a8164dfSZhong Wang 
5542a8164dfSZhong Wang 	FCOET_RELE_XCHG(xch);
5552a8164dfSZhong Wang 	return (FCOE_SUCCESS);
5562a8164dfSZhong Wang }
5572a8164dfSZhong Wang 
5582a8164dfSZhong Wang static int
fcoet_process_unsol_fcp_cmd(fcoe_frame_t * frm)5592a8164dfSZhong Wang fcoet_process_unsol_fcp_cmd(fcoe_frame_t *frm)
5602a8164dfSZhong Wang {
5612a8164dfSZhong Wang 	fcoet_exchange_t	*xch;
5622a8164dfSZhong Wang 	fcoe_fcp_cmnd_t		*ffc;
5632a8164dfSZhong Wang 	uint8_t			 tm;
5642a8164dfSZhong Wang 	scsi_task_t		*task;
5652a8164dfSZhong Wang 
5662a8164dfSZhong Wang 	xch = fcoet_create_unsol_exchange(frm);
5672a8164dfSZhong Wang 	if (xch == NULL) {
5682a8164dfSZhong Wang 		FCOET_LOG("fcoet_process_unsol_fcp_cmd", "can't get exchange");
5692a8164dfSZhong Wang 		return (FCOE_FAILURE);
5702a8164dfSZhong Wang 	}
5712a8164dfSZhong Wang 
5722a8164dfSZhong Wang 	ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload;
5732a8164dfSZhong Wang 	task = XCH2TASK(xch);
5742a8164dfSZhong Wang 	task->task_csn_size = 8;
5752a8164dfSZhong Wang 	task->task_max_nbufs = 1;
5762a8164dfSZhong Wang 	task->task_cmd_seq_no = FCOE_B2V_1(ffc->ffc_ref_num);
5772a8164dfSZhong Wang 	task->task_flags = FCOE_B2V_1(ffc->ffc_attribute) & 0x07;
5782a8164dfSZhong Wang 	task->task_flags |=
5792a8164dfSZhong Wang 	    (FCOE_B2V_1(ffc->ffc_addlen_rdwr) & 0x03) << 5;
5802a8164dfSZhong Wang 	task->task_expected_xfer_length = FCOE_B2V_4(ffc->ffc_fcp_dl);
5812a8164dfSZhong Wang 
5822a8164dfSZhong Wang 	tm = FCOE_B2V_1(ffc->ffc_management_flags);
5832a8164dfSZhong Wang 	if (tm) {
5842a8164dfSZhong Wang 		if (tm & BIT_1) {
5852a8164dfSZhong Wang 			task->task_mgmt_function = TM_ABORT_TASK_SET;
5862a8164dfSZhong Wang 		} else if (tm & BIT_2) {
5872a8164dfSZhong Wang 			task->task_mgmt_function = TM_CLEAR_TASK_SET;
5882a8164dfSZhong Wang 		} else if (tm & BIT_4) {
5892a8164dfSZhong Wang 			task->task_mgmt_function = TM_LUN_RESET;
5902a8164dfSZhong Wang 		} else if (tm & BIT_5) {
5912a8164dfSZhong Wang 			task->task_mgmt_function = TM_TARGET_COLD_RESET;
5922a8164dfSZhong Wang 		} else if (tm & BIT_6) {
5932a8164dfSZhong Wang 			task->task_mgmt_function = TM_CLEAR_ACA;
5942a8164dfSZhong Wang 		} else {
5952a8164dfSZhong Wang 			task->task_mgmt_function = TM_ABORT_TASK;
5962a8164dfSZhong Wang 		}
5972a8164dfSZhong Wang 	}
5982a8164dfSZhong Wang 
5992a8164dfSZhong Wang 	bcopy(ffc->ffc_cdb, task->task_cdb, 16);
6002a8164dfSZhong Wang 	fct_post_rcvd_cmd(xch->xch_cmd, NULL);
6012a8164dfSZhong Wang 	return (FCOE_SUCCESS);
6022a8164dfSZhong Wang }
6032a8164dfSZhong Wang /*
6042a8164dfSZhong Wang  * It must be from link
6052a8164dfSZhong Wang  * req_payload has been allocated when create_unsol_exchange
6062a8164dfSZhong Wang  */
6072a8164dfSZhong Wang static int
fcoet_process_unsol_els_req(fcoe_frame_t * frm)6082a8164dfSZhong Wang fcoet_process_unsol_els_req(fcoe_frame_t *frm)
6092a8164dfSZhong Wang {
6102a8164dfSZhong Wang 	int			ret = FCOE_SUCCESS;
6112a8164dfSZhong Wang 	fcoet_exchange_t	*xch;
6122a8164dfSZhong Wang 
6132a8164dfSZhong Wang 	xch = fcoet_create_unsol_exchange(frm);
6142a8164dfSZhong Wang 	ASSERT(xch);
6152a8164dfSZhong Wang 	ASSERT(FRM_IS_LAST_FRAME(frm));
6162a8164dfSZhong Wang 
6172a8164dfSZhong Wang 	/*
6182a8164dfSZhong Wang 	 * For the reason of keeping symmetric, we do copy here as in
6192a8164dfSZhong Wang 	 * process_sol_els instead of in create_unsol_exchange.
6202a8164dfSZhong Wang 	 * req_payload depends on how to allocate buf in create_unsol_exchange
6212a8164dfSZhong Wang 	 */
6222a8164dfSZhong Wang 	XCH2ELS(xch)->els_req_alloc_size = 0;
6232a8164dfSZhong Wang 	XCH2ELS(xch)->els_req_size = frm->frm_payload_size;
6242a8164dfSZhong Wang 	XCH2ELS(xch)->els_req_payload =
6252a8164dfSZhong Wang 	    GET_BYTE_OFFSET(xch, GET_STRUCT_SIZE(fcoet_exchange_t));
6262a8164dfSZhong Wang 	bcopy(frm->frm_payload, XCH2ELS(xch)->els_req_payload,
6272a8164dfSZhong Wang 	    XCH2ELS(xch)->els_req_size);
6282a8164dfSZhong Wang 	if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) {
6292a8164dfSZhong Wang 		/*
6302a8164dfSZhong Wang 		 * Ensure LINK_UP event has been handled, or PLOIG has
6312a8164dfSZhong Wang 		 * been processed by FCT, or else it will be discarded.
6322a8164dfSZhong Wang 		 * It need more consideration later ???
6332a8164dfSZhong Wang 		 */
6342a8164dfSZhong Wang 		if ((XCH2ELS(xch)->els_req_payload[0] == ELS_OP_PLOGI) &&
6352a8164dfSZhong Wang 		    (xch->xch_ss->ss_flags & SS_FLAG_DELAY_PLOGI)) {
6362a8164dfSZhong Wang 			delay(STMF_SEC2TICK(1)/2);
6372a8164dfSZhong Wang 		}
6382a8164dfSZhong Wang 
6392a8164dfSZhong Wang 		if ((XCH2ELS(xch)->els_req_payload[0] == ELS_OP_PRLI) &&
6402a8164dfSZhong Wang 		    (xch->xch_ss->ss_flags & SS_FLAG_DELAY_PLOGI)) {
6412a8164dfSZhong Wang 			atomic_and_32(&xch->xch_ss->ss_flags,
6422a8164dfSZhong Wang 			    ~SS_FLAG_DELAY_PLOGI);
6432a8164dfSZhong Wang 			delay(STMF_SEC2TICK(1)/3);
6442a8164dfSZhong Wang 		}
6452a8164dfSZhong Wang 		fct_post_rcvd_cmd(xch->xch_cmd, NULL);
6462a8164dfSZhong Wang 	} else {
6472a8164dfSZhong Wang 		/*
6482a8164dfSZhong Wang 		 * We always handle FLOGI internally
6492a8164dfSZhong Wang 		 * Save dst mac address from FLOGI request to restore later
6502a8164dfSZhong Wang 		 */
6512a8164dfSZhong Wang 		bcopy((char *)frm->frm_hdr-22,
6522a8164dfSZhong Wang 		    frm->frm_eport->eport_efh_dst, ETHERADDRL);
6532a8164dfSZhong Wang 		ret = fcoet_process_unsol_flogi_req(xch);
6542a8164dfSZhong Wang 	}
6552a8164dfSZhong Wang 	return (ret);
6562a8164dfSZhong Wang }
6572a8164dfSZhong Wang 
6582a8164dfSZhong Wang 
6592a8164dfSZhong Wang /*
6602a8164dfSZhong Wang  * It must be from link, but could be incomplete because of network problems
6612a8164dfSZhong Wang  */
6622a8164dfSZhong Wang static int
fcoet_process_sol_els_rsp(fcoe_frame_t * frm)6632a8164dfSZhong Wang fcoet_process_sol_els_rsp(fcoe_frame_t *frm)
6642a8164dfSZhong Wang {
6652a8164dfSZhong Wang 	uint32_t		 actual_size;
6662a8164dfSZhong Wang 	fct_status_t		 fc_st;
6672a8164dfSZhong Wang 	uint32_t		 iof;
6682a8164dfSZhong Wang 	uint16_t		 sol_oxid;
6692a8164dfSZhong Wang 	fcoet_exchange_t	*xch = NULL;
6702a8164dfSZhong Wang 	fct_els_t		*els = NULL;
6712a8164dfSZhong Wang 	int			 ret = FCOE_SUCCESS;
6722a8164dfSZhong Wang 
6732a8164dfSZhong Wang 	sol_oxid = FRM_OXID(frm);
6742a8164dfSZhong Wang 	if (mod_hash_find_cb(FRM2SS(frm)->ss_sol_oxid_hash,
6752a8164dfSZhong Wang 	    (mod_hash_key_t)(intptr_t)sol_oxid,
6762a8164dfSZhong Wang 	    (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) {
6772a8164dfSZhong Wang 		return (FCOE_FAILURE);
6782a8164dfSZhong Wang 	}
6792a8164dfSZhong Wang 	if (xch != FRM2SS(frm)->ss_sol_flogi) {
6802a8164dfSZhong Wang 		fcoet_clear_sol_exchange(xch);
6812a8164dfSZhong Wang 	}
6822a8164dfSZhong Wang 
6832a8164dfSZhong Wang 	fcoet_init_tfm(frm, xch);
6842a8164dfSZhong Wang 	els = CMD2ELS(xch->xch_cmd);
6852a8164dfSZhong Wang 	ASSERT(FRM_IS_LAST_FRAME(frm));
6862a8164dfSZhong Wang 	actual_size = els->els_resp_size;
6872a8164dfSZhong Wang 	if (actual_size > frm->frm_payload_size) {
6882a8164dfSZhong Wang 		actual_size = frm->frm_payload_size;
6892a8164dfSZhong Wang 	}
6902a8164dfSZhong Wang 
6912a8164dfSZhong Wang 	els->els_resp_size = (uint16_t)actual_size;
6922a8164dfSZhong Wang 	bcopy(frm->frm_payload, els->els_resp_payload, actual_size);
6932a8164dfSZhong Wang 
6942a8164dfSZhong Wang 	if (xch->xch_ss->ss_sol_flogi == xch) {
6952a8164dfSZhong Wang 		/*
6962a8164dfSZhong Wang 		 * We handle FLOGI internally
6972a8164dfSZhong Wang 		 */
6982a8164dfSZhong Wang 		ret = fcoet_process_sol_flogi_rsp(frm);
6992a8164dfSZhong Wang 		FCOET_RELE_XCHG(xch);
7002a8164dfSZhong Wang 	} else {
7012a8164dfSZhong Wang 		fc_st = FCT_SUCCESS;
7022a8164dfSZhong Wang 		iof = FCT_IOF_FCA_DONE;
7032a8164dfSZhong Wang 		FCOET_RELE_XCHG(xch);
7042a8164dfSZhong Wang 		fct_send_cmd_done(xch->xch_cmd, fc_st, iof);
7052a8164dfSZhong Wang 	}
7062a8164dfSZhong Wang 	return (ret);
7072a8164dfSZhong Wang }
7082a8164dfSZhong Wang 
7092a8164dfSZhong Wang /*
7102a8164dfSZhong Wang  * It's still in the context of being aborted exchange, but FCT can't support
7112a8164dfSZhong Wang  * this scheme, so there are two fct_cmd_t that are bound with one exchange.
7122a8164dfSZhong Wang  */
7132a8164dfSZhong Wang static int
fcoet_process_unsol_abts_req(fcoe_frame_t * frm)7142a8164dfSZhong Wang fcoet_process_unsol_abts_req(fcoe_frame_t *frm)
7152a8164dfSZhong Wang {
7162a8164dfSZhong Wang 	fct_cmd_t		*cmd;
7172a8164dfSZhong Wang 	fcoet_exchange_t	*xch = NULL;
7182a8164dfSZhong Wang 	uint16_t		 unsol_rxid;
7192a8164dfSZhong Wang 
7202a8164dfSZhong Wang 	FCOET_LOG("fcoet_process_unsol_abts_req", "ABTS: %x/%x",
7212a8164dfSZhong Wang 	    FRM_OXID(frm), FRM_RXID(frm));
7222a8164dfSZhong Wang 	unsol_rxid = FRM_RXID(frm);
7232a8164dfSZhong Wang 	if (mod_hash_find_cb(FRM2SS(frm)->ss_unsol_rxid_hash,
7242a8164dfSZhong Wang 	    (mod_hash_key_t)(intptr_t)unsol_rxid,
7252a8164dfSZhong Wang 	    (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) {
7262a8164dfSZhong Wang 		FCOET_LOG("fcoet_process_unsol_abts_req",
7272a8164dfSZhong Wang 		    "can't find aborted exchange");
7282a8164dfSZhong Wang 		return (FCOE_SUCCESS);
7292a8164dfSZhong Wang 	}
7302a8164dfSZhong Wang 
7312a8164dfSZhong Wang 	fcoet_init_tfm(frm, xch);
7322a8164dfSZhong Wang 	if (!FRM_IS_LAST_FRAME(frm)) {
7332a8164dfSZhong Wang 		FCOET_LOG("fcoet_process_unsol_abts_req",
7342a8164dfSZhong Wang 		    "not supported this kind frame");
7352a8164dfSZhong Wang 		FCOET_RELE_XCHG(xch);
7362a8164dfSZhong Wang 		return (FCOE_FAILURE);
7372a8164dfSZhong Wang 	}
7382a8164dfSZhong Wang 
7392a8164dfSZhong Wang 	cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ABTS, 0, 0);
7402a8164dfSZhong Wang 	if (cmd == NULL) {
7412a8164dfSZhong Wang 		FCOET_LOG("fcoet_process_unsol_abts_req",
7422a8164dfSZhong Wang 		    "can't alloc fct_cmd_t");
7432a8164dfSZhong Wang 		FCOET_RELE_XCHG(xch);
7442a8164dfSZhong Wang 		return (FCOE_FAILURE);
7452a8164dfSZhong Wang 	}
7462a8164dfSZhong Wang 
7472a8164dfSZhong Wang 	xch->xch_flags |= XCH_FLAG_INI_ASKED_ABORT;
7482a8164dfSZhong Wang 	cmd->cmd_fca_private = xch;
7492a8164dfSZhong Wang 	cmd->cmd_port = xch->xch_cmd->cmd_port;
7502a8164dfSZhong Wang 	cmd->cmd_rp_handle = xch->xch_cmd->cmd_rp_handle;
7512a8164dfSZhong Wang 	cmd->cmd_rportid = xch->xch_cmd->cmd_rportid;
7522a8164dfSZhong Wang 	cmd->cmd_lportid = xch->xch_cmd->cmd_lportid;
7532a8164dfSZhong Wang 	cmd->cmd_oxid = xch->xch_cmd->cmd_oxid;
7542a8164dfSZhong Wang 	cmd->cmd_rxid = xch->xch_cmd->cmd_rxid;
7552a8164dfSZhong Wang 	fct_post_rcvd_cmd(cmd, NULL);
7562a8164dfSZhong Wang 	FCOET_LOG("fcoet_process_unsol_abts_req",
7572a8164dfSZhong Wang 	    "abts now: xch/%p, frm/%p - time/%p",
7582a8164dfSZhong Wang 	    xch, frm, ddi_get_lbolt());
7592a8164dfSZhong Wang 
7602a8164dfSZhong Wang 	FCOET_RELE_XCHG(xch);
7612a8164dfSZhong Wang 	return (FCOE_SUCCESS);
7622a8164dfSZhong Wang }
7632a8164dfSZhong Wang 
7642a8164dfSZhong Wang static int
fcoet_process_sol_abts_acc(fcoe_frame_t * frm)7652a8164dfSZhong Wang fcoet_process_sol_abts_acc(fcoe_frame_t *frm)
7662a8164dfSZhong Wang {
7672a8164dfSZhong Wang 	fcoet_exchange_t	*xch	   = NULL;
7682a8164dfSZhong Wang 	uint16_t		 sol_oxid;
7692a8164dfSZhong Wang 
7702a8164dfSZhong Wang 	sol_oxid = FRM_OXID(frm);
7712a8164dfSZhong Wang 	if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
7722a8164dfSZhong Wang 	    (mod_hash_key_t)(intptr_t)sol_oxid,
7732a8164dfSZhong Wang 	    (mod_hash_val_t *)&xch) != 0) {
7742a8164dfSZhong Wang 		/*
7752a8164dfSZhong Wang 		 * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash
7762a8164dfSZhong Wang 		 * in fcoet_watch_handle_sol_flogi, Will improve it later
7772a8164dfSZhong Wang 		 */
7782a8164dfSZhong Wang 		return (FCOE_SUCCESS);
7792a8164dfSZhong Wang 	}
7802a8164dfSZhong Wang 
7812a8164dfSZhong Wang 	xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
7822a8164dfSZhong Wang 	if (!FRM_IS_LAST_FRAME(frm)) {
7832a8164dfSZhong Wang 		FCOET_LOG("fcoet_process_sol_abts_acc",
7842a8164dfSZhong Wang 		    "not supported this kind frame");
7852a8164dfSZhong Wang 		FCOET_RELE_XCHG(xch);
7862a8164dfSZhong Wang 		return (FCOE_FAILURE);
7872a8164dfSZhong Wang 	}
7882a8164dfSZhong Wang 	FCOET_LOG("fcoet_process_sol_abts_acc",
7892a8164dfSZhong Wang 	    "ABTS received but there is nothing to do");
7902a8164dfSZhong Wang 	return (FCOE_SUCCESS);
7912a8164dfSZhong Wang }
7922a8164dfSZhong Wang 
7932a8164dfSZhong Wang static int
fcoet_process_sol_abts_rjt(fcoe_frame_t * frm)7942a8164dfSZhong Wang fcoet_process_sol_abts_rjt(fcoe_frame_t *frm)
7952a8164dfSZhong Wang {
7962a8164dfSZhong Wang 	fcoet_exchange_t	*xch	   = NULL;
7972a8164dfSZhong Wang 	uint16_t		 sol_oxid;
7982a8164dfSZhong Wang 
7992a8164dfSZhong Wang 	sol_oxid = FRM_OXID(frm);
8002a8164dfSZhong Wang 	if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
8012a8164dfSZhong Wang 	    (mod_hash_key_t)(intptr_t)sol_oxid,
8022a8164dfSZhong Wang 	    (mod_hash_val_t *)&xch) != 0) {
8032a8164dfSZhong Wang 		/*
8042a8164dfSZhong Wang 		 * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash
8052a8164dfSZhong Wang 		 * in fcoet_watch_handle_sol_flogi, Will improve it later
8062a8164dfSZhong Wang 		 */
8072a8164dfSZhong Wang 		return (FCOE_SUCCESS);
8082a8164dfSZhong Wang 	}
8092a8164dfSZhong Wang 
8102a8164dfSZhong Wang 	xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
8112a8164dfSZhong Wang 
8122a8164dfSZhong Wang 	if (!FRM_IS_LAST_FRAME(frm)) {
8132a8164dfSZhong Wang 		FCOET_LOG("fcoet_process_sol_abts_rjt",
8142a8164dfSZhong Wang 		    "not supported this kind frame");
8152a8164dfSZhong Wang 		return (FCOE_FAILURE);
8162a8164dfSZhong Wang 	}
8172a8164dfSZhong Wang 
8182a8164dfSZhong Wang 	FCOET_LOG("fcoet_process_sol_abts_rjt",
8192a8164dfSZhong Wang 	    "ABTS_RJT received rjt reason %x but there is nothing to do",
8202a8164dfSZhong Wang 	    frm->frm_payload[1]);
8212a8164dfSZhong Wang 	return (FCOE_SUCCESS);
8222a8164dfSZhong Wang }
8232a8164dfSZhong Wang 
8242a8164dfSZhong Wang static int
fcoet_process_unsol_ct_req(fcoe_frame_t * frm)8252a8164dfSZhong Wang fcoet_process_unsol_ct_req(fcoe_frame_t *frm)
8262a8164dfSZhong Wang {
8272a8164dfSZhong Wang 	/*
8282a8164dfSZhong Wang 	 * If you want to implement virtual name server, or FC/ETH
8292a8164dfSZhong Wang 	 * gateway, you can do it here
8302a8164dfSZhong Wang 	 */
8312a8164dfSZhong Wang 	if (!FRM_IS_LAST_FRAME(frm)) {
8322a8164dfSZhong Wang 		FCOET_LOG("fcoet_process_unsol_ct_req",
8332a8164dfSZhong Wang 		    "not supported this kind frame");
8342a8164dfSZhong Wang 		return (FCOE_FAILURE);
8352a8164dfSZhong Wang 	}
8362a8164dfSZhong Wang 
8372a8164dfSZhong Wang 	FCOET_LOG("fcoet_process_unsol_ct_req",
8382a8164dfSZhong Wang 	    "No support for unsolicited CT request");
8392a8164dfSZhong Wang 	return (FCOE_SUCCESS);
8402a8164dfSZhong Wang }
8412a8164dfSZhong Wang 
8422a8164dfSZhong Wang static int
fcoet_process_sol_ct_rsp(fcoe_frame_t * frm)8432a8164dfSZhong Wang fcoet_process_sol_ct_rsp(fcoe_frame_t *frm)
8442a8164dfSZhong Wang {
8452a8164dfSZhong Wang 	uint32_t		 actual_size;
8462a8164dfSZhong Wang 	fct_status_t		 fc_st;
8472a8164dfSZhong Wang 	uint32_t		 iof;
8482a8164dfSZhong Wang 	fct_sol_ct_t		*ct  = NULL;
8492a8164dfSZhong Wang 	fcoet_exchange_t	*xch = NULL;
8502a8164dfSZhong Wang 	uint16_t		 sol_oxid;
8512a8164dfSZhong Wang 
8522a8164dfSZhong Wang 	sol_oxid = FRM_OXID(frm);
8532a8164dfSZhong Wang 
8542a8164dfSZhong Wang 	if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
8552a8164dfSZhong Wang 	    (mod_hash_key_t)(intptr_t)sol_oxid,
8562a8164dfSZhong Wang 	    (mod_hash_val_t *)&xch) != 0) {
8572a8164dfSZhong Wang 		return (FCOE_SUCCESS);
8582a8164dfSZhong Wang 	}
8592a8164dfSZhong Wang 
8602a8164dfSZhong Wang 	xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
8612a8164dfSZhong Wang 	fcoet_init_tfm(frm, xch);
8622a8164dfSZhong Wang 
8632a8164dfSZhong Wang 	ASSERT(FRM_IS_LAST_FRAME(frm));
8642a8164dfSZhong Wang 	actual_size = CMD2ELS(xch->xch_cmd)->els_resp_size;
8652a8164dfSZhong Wang 	if (actual_size > frm->frm_payload_size) {
8662a8164dfSZhong Wang 		actual_size = frm->frm_payload_size;
8672a8164dfSZhong Wang 	}
8682a8164dfSZhong Wang 	ct = CMD2CT(xch->xch_cmd);
8692a8164dfSZhong Wang 	ct->ct_resp_size = (uint16_t)actual_size;
8702a8164dfSZhong Wang 
8712a8164dfSZhong Wang 	bcopy(frm->frm_payload,
8722a8164dfSZhong Wang 	    CMD2CT(xch->xch_cmd)->ct_resp_payload, actual_size);
8732a8164dfSZhong Wang 
8742a8164dfSZhong Wang 	fc_st = FCT_SUCCESS;
8752a8164dfSZhong Wang 	iof = FCT_IOF_FCA_DONE;
8762a8164dfSZhong Wang 	fct_send_cmd_done(xch->xch_cmd, fc_st, iof);
8772a8164dfSZhong Wang 
8782a8164dfSZhong Wang 	return (FCOE_SUCCESS);
8792a8164dfSZhong Wang }
8802a8164dfSZhong Wang 
8812a8164dfSZhong Wang static int
fcoet_send_sol_fcp_data_done(fcoe_frame_t * frm)8822a8164dfSZhong Wang fcoet_send_sol_fcp_data_done(fcoe_frame_t *frm)
8832a8164dfSZhong Wang {
8842a8164dfSZhong Wang 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
8852a8164dfSZhong Wang 	stmf_data_buf_t		*dbuf;
8862a8164dfSZhong Wang 	int			dbuf_index;
8872a8164dfSZhong Wang 	uint32_t		 iof;
8882a8164dfSZhong Wang 
8892a8164dfSZhong Wang 	dbuf_index = FRM2TFM(frm)->tfm_buf_idx;
8902a8164dfSZhong Wang 	xch->xch_left_data_size -= frm->frm_payload_size;
8912a8164dfSZhong Wang 	dbuf = xch->xch_dbufs[dbuf_index];
8922a8164dfSZhong Wang 	ASSERT((dbuf) && (dbuf->db_flags & DB_DIRECTION_TO_RPORT));
8932a8164dfSZhong Wang 
8942a8164dfSZhong Wang 	/*
8952a8164dfSZhong Wang 	 * We decrease db_sglist_length only for READ-type commands.
8962a8164dfSZhong Wang 	 * For INQUIRY, resid could be non-zero, then db_sglist_length will
8972a8164dfSZhong Wang 	 * be useful.
8982a8164dfSZhong Wang 	 */
8992a8164dfSZhong Wang 	dbuf->db_sglist_length--;
9002a8164dfSZhong Wang 	if ((xch->xch_left_data_size <= 0) || (!dbuf->db_sglist_length)) {
9012a8164dfSZhong Wang 		iof = 0;
9022a8164dfSZhong Wang 		dbuf->db_xfer_status = FCT_SUCCESS;
9032a8164dfSZhong Wang 		dbuf->db_flags |= DB_DONT_REUSE;
9042a8164dfSZhong Wang 		if (dbuf->db_flags & DB_SEND_STATUS_GOOD) {
9052a8164dfSZhong Wang 			if (fcoet_send_status(xch->xch_cmd) != FCT_SUCCESS) {
9062a8164dfSZhong Wang 				return (FCOE_FAILURE);
9072a8164dfSZhong Wang 			}
9082a8164dfSZhong Wang 		} else {
9092a8164dfSZhong Wang 			fct_scsi_data_xfer_done(xch->xch_cmd, dbuf, iof);
9102a8164dfSZhong Wang 		}
9112a8164dfSZhong Wang 	}
9122a8164dfSZhong Wang 	FCOET_RELE_XCHG(xch);
9132a8164dfSZhong Wang 	return (FCOE_SUCCESS);
9142a8164dfSZhong Wang }
9152a8164dfSZhong Wang 
9162a8164dfSZhong Wang static int
fcoet_send_fcp_status_done(fcoe_frame_t * frm)9172a8164dfSZhong Wang fcoet_send_fcp_status_done(fcoe_frame_t *frm)
9182a8164dfSZhong Wang {
9192a8164dfSZhong Wang 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
9202a8164dfSZhong Wang 	fct_status_t		 fc_st = FCT_SUCCESS;
9212a8164dfSZhong Wang 	uint32_t		 iof = FCT_IOF_FCA_DONE;
9222a8164dfSZhong Wang 
9232a8164dfSZhong Wang 	if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
9242a8164dfSZhong Wang 		FCOET_RELE_XCHG(xch);
9252a8164dfSZhong Wang 		return (FCOE_SUCCESS);
9262a8164dfSZhong Wang 	}
9272a8164dfSZhong Wang 
9282a8164dfSZhong Wang 	if (fcoet_clear_unsol_exchange(xch) == FCOE_SUCCESS) {
9292a8164dfSZhong Wang 		FCOET_RELE_XCHG(xch);
9302a8164dfSZhong Wang 		fct_send_response_done(xch->xch_cmd, fc_st, iof);
9312a8164dfSZhong Wang 	} else {
9322a8164dfSZhong Wang 		/* Already cleared from hash table by abort */
9332a8164dfSZhong Wang 		FCOET_RELE_XCHG(xch);
9342a8164dfSZhong Wang 	}
9352a8164dfSZhong Wang 
9362a8164dfSZhong Wang 	return (FCOE_SUCCESS);
9372a8164dfSZhong Wang }
9382a8164dfSZhong Wang 
9392a8164dfSZhong Wang /*
9402a8164dfSZhong Wang  * Solicited frames callback area
9412a8164dfSZhong Wang  */
9422a8164dfSZhong Wang static int
fcoet_send_unsol_els_rsp_done(fcoe_frame_t * frm)9432a8164dfSZhong Wang fcoet_send_unsol_els_rsp_done(fcoe_frame_t *frm)
9442a8164dfSZhong Wang {
9452a8164dfSZhong Wang 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
9462a8164dfSZhong Wang 	fct_status_t		 fc_st;
9472a8164dfSZhong Wang 	uint32_t		 iof;
9482a8164dfSZhong Wang 
9492a8164dfSZhong Wang 	FCOET_EXT_LOG("fcoet_send_unsol_els_rsp_done",
9502a8164dfSZhong Wang 	    "frm/oxid/els: %p/%x/%x",
9512a8164dfSZhong Wang 	    frm, FRM_OXID(frm), XCH2ELS(xch)->els_req_payload[0]);
9522a8164dfSZhong Wang 	if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
9532a8164dfSZhong Wang 		FCOET_RELE_XCHG(xch);
9542a8164dfSZhong Wang 		return (FCOE_SUCCESS);
9552a8164dfSZhong Wang 	}
9562a8164dfSZhong Wang 
9572a8164dfSZhong Wang 	if (fcoet_clear_unsol_exchange(xch) == FCOE_FAILURE) {
9582a8164dfSZhong Wang 		FCOET_RELE_XCHG(xch);
9592a8164dfSZhong Wang 		return (FCOE_SUCCESS);
9602a8164dfSZhong Wang 	}
9612a8164dfSZhong Wang 
9622a8164dfSZhong Wang 	FCOET_RELE_XCHG(xch);
9632a8164dfSZhong Wang 	if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) {
9642a8164dfSZhong Wang 		fc_st = FCT_SUCCESS;
9652a8164dfSZhong Wang 		iof = FCT_IOF_FCA_DONE;
9662a8164dfSZhong Wang 		fct_send_response_done(xch->xch_cmd, fc_st, iof);
9672a8164dfSZhong Wang 	} else {
9682a8164dfSZhong Wang 		/*
9692a8164dfSZhong Wang 		 * We need update ss_link_info and flags.
9702a8164dfSZhong Wang 		 */
9712a8164dfSZhong Wang 		mutex_enter(&xch->xch_ss->ss_watch_mutex);
9722a8164dfSZhong Wang 		xch->xch_ss->ss_link_info.portid =
9732a8164dfSZhong Wang 		    xch->xch_cmd->cmd_lportid;
9742a8164dfSZhong Wang 		xch->xch_ss->ss_link_info.port_topology =
9752a8164dfSZhong Wang 		    PORT_TOPOLOGY_PT_TO_PT;
9762a8164dfSZhong Wang 		if (frm->frm_eport->eport_link_speed == FCOE_PORT_SPEED_1G) {
9772a8164dfSZhong Wang 			xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_1G;
9782a8164dfSZhong Wang 		} else if (frm->frm_eport->eport_link_speed ==
9792a8164dfSZhong Wang 		    FCOE_PORT_SPEED_10G) {
9802a8164dfSZhong Wang 			xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G;
9812a8164dfSZhong Wang 		}
9822a8164dfSZhong Wang 		xch->xch_ss->ss_link_info.port_no_fct_flogi = 1;
9832a8164dfSZhong Wang 		xch->xch_ss->ss_link_info.port_fca_flogi_done = 1;
9842a8164dfSZhong Wang 		xch->xch_ss->ss_link_info.port_fct_flogi_done = 0;
9852a8164dfSZhong Wang 		bcopy(XCH2ELS(xch)->els_req_payload + 20,
9862a8164dfSZhong Wang 		    xch->xch_ss->ss_link_info.port_rpwwn, 8);
9872a8164dfSZhong Wang 		bcopy(XCH2ELS(xch)->els_req_payload + 28,
9882a8164dfSZhong Wang 		    xch->xch_ss->ss_link_info.port_rnwwn, 8);
9892a8164dfSZhong Wang 		atomic_or_32(&xch->xch_ss->ss_flags,
9902a8164dfSZhong Wang 		    SS_FLAG_UNSOL_FLOGI_DONE);
9912a8164dfSZhong Wang 		atomic_or_32(&xch->xch_ss->ss_flags,
9922a8164dfSZhong Wang 		    SS_FLAG_REPORT_TO_FCT);
9932a8164dfSZhong Wang 
9942a8164dfSZhong Wang 		xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC;
9952a8164dfSZhong Wang 		mutex_exit(&xch->xch_ss->ss_watch_mutex);
9962a8164dfSZhong Wang 
9972a8164dfSZhong Wang 		fct_free(xch->xch_cmd);
9982a8164dfSZhong Wang 	}
9992a8164dfSZhong Wang 	return (FCOE_SUCCESS);
10002a8164dfSZhong Wang }
10012a8164dfSZhong Wang 
10022a8164dfSZhong Wang /* ARGSUSED */
10032a8164dfSZhong Wang static int
fcoet_send_sol_els_req_done(fcoe_frame_t * frm)10042a8164dfSZhong Wang fcoet_send_sol_els_req_done(fcoe_frame_t *frm)
10052a8164dfSZhong Wang {
10062a8164dfSZhong Wang 	return (FCOE_SUCCESS);
10072a8164dfSZhong Wang }
10082a8164dfSZhong Wang 
10092a8164dfSZhong Wang /*
10102a8164dfSZhong Wang  * FCT have released relevant fct_cmd_t and fcoet_exchange_t now, so it's not
10112a8164dfSZhong Wang  * needed to notify FCT anything. Just do nothing.
10122a8164dfSZhong Wang  */
10132a8164dfSZhong Wang /* ARGSUSED */
10142a8164dfSZhong Wang static int
fcoet_send_unsol_bls_acc_done(fcoe_frame_t * frm)10152a8164dfSZhong Wang fcoet_send_unsol_bls_acc_done(fcoe_frame_t *frm)
10162a8164dfSZhong Wang {
10172a8164dfSZhong Wang 	FCOET_LOG("fcoet_send_unsol_bls_acc_done",
10182a8164dfSZhong Wang 	    "Unsolicited BA_ACC sent out and released ");
10192a8164dfSZhong Wang 
10202a8164dfSZhong Wang 	return (FCOE_SUCCESS);
10212a8164dfSZhong Wang }
10222a8164dfSZhong Wang 
10232a8164dfSZhong Wang /* ARGSUSED */
10242a8164dfSZhong Wang static int
fcoet_send_unsol_bls_rjt_done(fcoe_frame_t * frm)10252a8164dfSZhong Wang fcoet_send_unsol_bls_rjt_done(fcoe_frame_t *frm)
10262a8164dfSZhong Wang {
10272a8164dfSZhong Wang 	FCOET_LOG("fcoet_send_unsol_bls_rjt_done",
10282a8164dfSZhong Wang 	    "Unsolicited BA_RJT sent out and released");
10292a8164dfSZhong Wang 	return (FCOE_SUCCESS);
10302a8164dfSZhong Wang }
10312a8164dfSZhong Wang 
10322a8164dfSZhong Wang /* ARGSUSED */
10332a8164dfSZhong Wang static int
fcoet_send_sol_bls_req_done(fcoe_frame_t * frm)10342a8164dfSZhong Wang fcoet_send_sol_bls_req_done(fcoe_frame_t *frm)
10352a8164dfSZhong Wang {
10362a8164dfSZhong Wang 	FCOET_LOG("fcoet_send_sol_bls_req_done",
10372a8164dfSZhong Wang 	    "Soclited ABTS was sent out and released");
10382a8164dfSZhong Wang 	return (FCOE_SUCCESS);
10392a8164dfSZhong Wang }
10402a8164dfSZhong Wang 
10412a8164dfSZhong Wang /* ARGSUSED */
10422a8164dfSZhong Wang static int
fcoet_send_sol_ct_req_done(fcoe_frame_t * frm)10432a8164dfSZhong Wang fcoet_send_sol_ct_req_done(fcoe_frame_t *frm)
10442a8164dfSZhong Wang {
10452a8164dfSZhong Wang 	FCOET_LOG("fcoet_send_sol_ct_req_done",
10462a8164dfSZhong Wang 	    "CT request was sent out and released");
10472a8164dfSZhong Wang 	return (FCOE_SUCCESS);
10482a8164dfSZhong Wang }
10492a8164dfSZhong Wang 
10502a8164dfSZhong Wang /*
10512a8164dfSZhong Wang  * FCoET can only interpret solicited and unsolicited FLOGI, all the other
10522a8164dfSZhong Wang  * ELS/CT/FCP should be passed up to FCT.
10532a8164dfSZhong Wang  */
10542a8164dfSZhong Wang static int
fcoet_process_unsol_flogi_req(fcoet_exchange_t * xch)10552a8164dfSZhong Wang fcoet_process_unsol_flogi_req(fcoet_exchange_t *xch)
10562a8164dfSZhong Wang {
10572a8164dfSZhong Wang 	fcoe_frame_t *frm;
10582a8164dfSZhong Wang 
10592a8164dfSZhong Wang 	atomic_or_32(&xch->xch_ss->ss_flags, SS_FLAG_DELAY_PLOGI);
10602a8164dfSZhong Wang 
10612a8164dfSZhong Wang 	/*
10622a8164dfSZhong Wang 	 * In spec, common service parameter should indicate if it's from
10632a8164dfSZhong Wang 	 * N-port or F-port, but the initial intel implementation is not
10642a8164dfSZhong Wang 	 * spec-compliant, so we use eport_flags to workaround the problem
10652a8164dfSZhong Wang 	 */
10662a8164dfSZhong Wang 	if (!(xch->xch_ss->ss_eport->eport_flags & EPORT_FLAG_IS_DIRECT_P2P)) {
10672a8164dfSZhong Wang 		/*
10682a8164dfSZhong Wang 		 * The topology is switch P2P, so there's no need to respond
10692a8164dfSZhong Wang 		 * to this FLOGI
10702a8164dfSZhong Wang 		 */
10712a8164dfSZhong Wang 		FCOET_LOG("fcoet_process_unsol_flogi_req",
10722a8164dfSZhong Wang 		    "skip FLOGI, since we are in switch topology");
10732a8164dfSZhong Wang 		return (FCOE_SUCCESS);
10742a8164dfSZhong Wang 	}
10752a8164dfSZhong Wang 
10762a8164dfSZhong Wang 	/*
10772a8164dfSZhong Wang 	 * Send ACC according to the spec.
10782a8164dfSZhong Wang 	 */
10792a8164dfSZhong Wang 	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
10802a8164dfSZhong Wang 	    FLOGI_ACC_PAYLOAD_SIZE + FCFH_SIZE, 0);
10812a8164dfSZhong Wang 	if (frm == NULL) {
10822a8164dfSZhong Wang 		ASSERT(0);
10832a8164dfSZhong Wang 		return (FCOE_FAILURE);
10842a8164dfSZhong Wang 	} else {
10852a8164dfSZhong Wang 		fcoet_init_tfm(frm, xch);
10862a8164dfSZhong Wang 		bzero(frm->frm_payload, frm->frm_payload_size);
10872a8164dfSZhong Wang 	}
10882a8164dfSZhong Wang 
10892a8164dfSZhong Wang 	FFM_R_CTL(0x23, frm);
10902a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_rctl = 0x23;
10912a8164dfSZhong Wang 	FFM_TYPE(0x01, frm);
10922a8164dfSZhong Wang 	FFM_F_CTL(0x980000, frm);
10932a8164dfSZhong Wang 	FFM_OXID(xch->xch_oxid, frm);
10942a8164dfSZhong Wang 	FFM_RXID(xch->xch_rxid, frm);
10952a8164dfSZhong Wang 	FFM_S_ID(0xFFFFFE, frm);
10962a8164dfSZhong Wang 
10972a8164dfSZhong Wang 	/*
10982a8164dfSZhong Wang 	 * ACC
10992a8164dfSZhong Wang 	 */
11002a8164dfSZhong Wang 	frm->frm_payload[0] = 0x02;
11012a8164dfSZhong Wang 
11022a8164dfSZhong Wang 	/*
11032a8164dfSZhong Wang 	 * Common Svc Parameters
11042a8164dfSZhong Wang 	 */
11052a8164dfSZhong Wang 	frm->frm_payload[4] = 0x20;
11062a8164dfSZhong Wang 	frm->frm_payload[5] = 0x20;
11072a8164dfSZhong Wang 	frm->frm_payload[7] = 0x0A;
11082a8164dfSZhong Wang 	frm->frm_payload[10] = 0x05;
11092a8164dfSZhong Wang 	frm->frm_payload[11] = 0xAC;
11102a8164dfSZhong Wang 	bcopy(xch->xch_ss->ss_eport->eport_portwwn, frm->frm_payload + 20, 8);
11112a8164dfSZhong Wang 	bcopy(xch->xch_ss->ss_eport->eport_nodewwn, frm->frm_payload + 28, 8);
11122a8164dfSZhong Wang 
11132a8164dfSZhong Wang 	/*
11142a8164dfSZhong Wang 	 * Class3 Svc Parameters
11152a8164dfSZhong Wang 	 */
11162a8164dfSZhong Wang 	frm->frm_payload[68] = 0x88;
11172a8164dfSZhong Wang 
11182a8164dfSZhong Wang 	/*
11192a8164dfSZhong Wang 	 * Send FLOGI ACC out
11202a8164dfSZhong Wang 	 * After this, we should never use the exchange, because it could
11212a8164dfSZhong Wang 	 * have been released. Please pay attention to other similiar cases.
11222a8164dfSZhong Wang 	 */
11232a8164dfSZhong Wang 	xch->xch_ss->ss_eport->eport_tx_frame(frm);
11242a8164dfSZhong Wang 	return (FCOE_SUCCESS);
11252a8164dfSZhong Wang }
11262a8164dfSZhong Wang 
11272a8164dfSZhong Wang static int
fcoet_process_sol_flogi_rsp(fcoe_frame_t * frm)11282a8164dfSZhong Wang fcoet_process_sol_flogi_rsp(fcoe_frame_t *frm)
11292a8164dfSZhong Wang {
11302a8164dfSZhong Wang 	int ret = FCOE_SUCCESS;
11312a8164dfSZhong Wang 	fcoet_exchange_t	*xch = FRM2TFM(frm)->tfm_xch;
11322a8164dfSZhong Wang 	fct_els_t		*els = CMD2ELS(xch->xch_cmd);
11331826d2a2SKelly Hu 	fcoet_soft_state_t	*ss = FRM2SS(frm);
11342a8164dfSZhong Wang 
11352a8164dfSZhong Wang 	if (els->els_resp_payload[0] == ELS_OP_ACC) {
11362a8164dfSZhong Wang 		/*
11372a8164dfSZhong Wang 		 * We need always update ss_link_info and flags for solicited
11382a8164dfSZhong Wang 		 * FLOGI, because someone has assigned address for you. The
11392a8164dfSZhong Wang 		 * initial intel implementation will always assign address for
11402a8164dfSZhong Wang 		 * you even you are in back-to-back mode (direct P2P).
11412a8164dfSZhong Wang 		 */
11421826d2a2SKelly Hu 		mutex_enter(&ss->ss_watch_mutex);
11431826d2a2SKelly Hu 		if (ss->ss_flags & SS_FLAG_PORT_DISABLED ||
11441826d2a2SKelly Hu 		    (ss->ss_sol_flogi_state != SFS_FLOGI_INIT &&
11451826d2a2SKelly Hu 		    ss->ss_sol_flogi_state != SFS_FLOGI_CHECK_TIMEOUT &&
11461826d2a2SKelly Hu 		    ss->ss_sol_flogi_state != SFS_ABTS_INIT)) {
11471826d2a2SKelly Hu 			/*
11481826d2a2SKelly Hu 			 * The status is not correct, this response may be
11491826d2a2SKelly Hu 			 * obsolete.
11501826d2a2SKelly Hu 			 */
11511826d2a2SKelly Hu 			mutex_exit(&ss->ss_watch_mutex);
11521826d2a2SKelly Hu 			FCOET_LOG("fcoet_process_sol_flogi_rsp",
11531826d2a2SKelly Hu 			    "FLOGI response is obsolete");
11541826d2a2SKelly Hu 			return (FCOE_FAILURE);
11551826d2a2SKelly Hu 		}
11562a8164dfSZhong Wang 		if (xch->xch_flags & XCH_FLAG_NONFCP_REQ_SENT) {
11572a8164dfSZhong Wang 			xch->xch_cmd->cmd_lportid = FRM_D_ID(frm);
11582a8164dfSZhong Wang 			xch->xch_ss->ss_link_info.portid =
11592a8164dfSZhong Wang 			    xch->xch_cmd->cmd_lportid;
11602a8164dfSZhong Wang 			/*
11612a8164dfSZhong Wang 			 * Check the bit 28 in 3rd word of the payload
11622a8164dfSZhong Wang 			 *  in common service parameters to know the
11632a8164dfSZhong Wang 			 * remote port is F_PORT or N_PORT
11642a8164dfSZhong Wang 			 */
11652a8164dfSZhong Wang 			if (els->els_resp_payload[8] & 0x10) {
11662a8164dfSZhong Wang 				uint8_t src_addr[ETHERADDRL];
11672a8164dfSZhong Wang 				frm->frm_eport->eport_flags &=
11682a8164dfSZhong Wang 				    ~EPORT_FLAG_IS_DIRECT_P2P;
11692a8164dfSZhong Wang 				FCOE_SET_DEFAULT_OUI(src_addr);
11702a8164dfSZhong Wang 				bcopy(frm->frm_hdr->hdr_d_id, src_addr + 3, 3);
11712a8164dfSZhong Wang 				bcopy((char *)frm->frm_hdr-22,
11722a8164dfSZhong Wang 				    frm->frm_eport->eport_efh_dst,
11732a8164dfSZhong Wang 				    ETHERADDRL);
11742a8164dfSZhong Wang 				frm->frm_eport->eport_set_mac_address(
11752a8164dfSZhong Wang 				    frm->frm_eport, src_addr, B_TRUE);
11762a8164dfSZhong Wang 				xch->xch_ss->ss_link_info.port_topology =
11772a8164dfSZhong Wang 				    PORT_TOPOLOGY_FABRIC_PT_TO_PT;
11782a8164dfSZhong Wang 			} else {
11792a8164dfSZhong Wang 				xch->xch_ss->ss_link_info.port_topology =
11802a8164dfSZhong Wang 				    PORT_TOPOLOGY_PT_TO_PT;
11812a8164dfSZhong Wang 			}
11822a8164dfSZhong Wang 
11832a8164dfSZhong Wang 			xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G;
11842a8164dfSZhong Wang 			xch->xch_ss->ss_link_info.port_no_fct_flogi = 1;
11852a8164dfSZhong Wang 			xch->xch_ss->ss_link_info.port_fca_flogi_done = 1;
11862a8164dfSZhong Wang 			xch->xch_ss->ss_link_info.port_fct_flogi_done = 0;
11872a8164dfSZhong Wang 			xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC;
11882a8164dfSZhong Wang 			cv_signal(&xch->xch_ss->ss_watch_cv);
11892a8164dfSZhong Wang 			FCOET_LOG("fcoet_process_sol_flogi_rsp",
11902a8164dfSZhong Wang 			    "FLOGI is accecpted");
11912a8164dfSZhong Wang 		} else {
11922a8164dfSZhong Wang 			FCOET_LOG("fcoet_process_sol_flogi_rsp",
11932a8164dfSZhong Wang 			    "FLOGI xch_flags/%x", xch->xch_flags);
11942a8164dfSZhong Wang 			ret = FCOE_FAILURE;
11952a8164dfSZhong Wang 		}
11961826d2a2SKelly Hu 		mutex_exit(&ss->ss_watch_mutex);
11972a8164dfSZhong Wang 	} else {
11982a8164dfSZhong Wang 		FCOET_LOG("fcoet_process_sol_flogi_rsp", "FLOGI is rejected");
11992a8164dfSZhong Wang 		ret = FCOE_FAILURE;
12002a8164dfSZhong Wang 	}
12012a8164dfSZhong Wang 	return (ret);
12022a8164dfSZhong Wang }
1203