17ff83669SZhong Wang /*
27ff83669SZhong Wang  * CDDL HEADER START
37ff83669SZhong Wang  *
47ff83669SZhong Wang  * The contents of this file are subject to the terms of the
57ff83669SZhong Wang  * Common Development and Distribution License (the "License").
67ff83669SZhong Wang  * You may not use this file except in compliance with the License.
77ff83669SZhong Wang  *
87ff83669SZhong Wang  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97ff83669SZhong Wang  * or http://www.opensolaris.org/os/licensing.
107ff83669SZhong Wang  * See the License for the specific language governing permissions
117ff83669SZhong Wang  * and limitations under the License.
127ff83669SZhong Wang  *
137ff83669SZhong Wang  * When distributing Covered Code, include this CDDL HEADER in each
147ff83669SZhong Wang  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157ff83669SZhong Wang  * If applicable, add the following below this CDDL HEADER, with the
167ff83669SZhong Wang  * fields enclosed by brackets "[]" replaced with your own identifying
177ff83669SZhong Wang  * information: Portions Copyright [yyyy] [name of copyright owner]
187ff83669SZhong Wang  *
197ff83669SZhong Wang  * CDDL HEADER END
207ff83669SZhong Wang  */
217ff83669SZhong Wang 
227ff83669SZhong Wang /*
237ff83669SZhong Wang  * The following notice accompanied the original version of this file:
247ff83669SZhong Wang  *
257ff83669SZhong Wang  * BSD LICENSE
267ff83669SZhong Wang  *
277ff83669SZhong Wang  * Copyright(c) 2007 Intel Corporation. All rights reserved.
287ff83669SZhong Wang  * All rights reserved.
297ff83669SZhong Wang  *
307ff83669SZhong Wang  * Redistribution and use in source and binary forms, with or without
317ff83669SZhong Wang  * modification, are permitted provided that the following conditions
327ff83669SZhong Wang  * are met:
337ff83669SZhong Wang  *
347ff83669SZhong Wang  *   * Redistributions of source code must retain the above copyright
357ff83669SZhong Wang  *     notice, this list of conditions and the following disclaimer.
367ff83669SZhong Wang  *   * Redistributions in binary form must reproduce the above copyright
377ff83669SZhong Wang  *     notice, this list of conditions and the following disclaimer in
387ff83669SZhong Wang  *     the documentation and/or other materials provided with the
397ff83669SZhong Wang  *     distribution.
407ff83669SZhong Wang  *   * Neither the name of Intel Corporation nor the names of its
417ff83669SZhong Wang  *     contributors may be used to endorse or promote products derived
427ff83669SZhong Wang  *     from this software without specific prior written permission.
437ff83669SZhong Wang  *
447ff83669SZhong Wang  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
457ff83669SZhong Wang  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
467ff83669SZhong Wang  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
477ff83669SZhong Wang  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
487ff83669SZhong Wang  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
497ff83669SZhong Wang  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
507ff83669SZhong Wang  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
517ff83669SZhong Wang  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
527ff83669SZhong Wang  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
537ff83669SZhong Wang  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
547ff83669SZhong Wang  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
557ff83669SZhong Wang  */
567ff83669SZhong Wang 
577ff83669SZhong Wang /*
58516aa12cSYu Renia Miao  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
597ff83669SZhong Wang  */
607ff83669SZhong Wang 
617ff83669SZhong Wang /*
627ff83669SZhong Wang  * This file defines interface functions between fcoe and fcoei driver.
637ff83669SZhong Wang  */
647ff83669SZhong Wang 
657ff83669SZhong Wang #include <sys/conf.h>
667ff83669SZhong Wang #include <sys/ddi.h>
677ff83669SZhong Wang #include <sys/stat.h>
687ff83669SZhong Wang #include <sys/pci.h>
697ff83669SZhong Wang #include <sys/sunddi.h>
707ff83669SZhong Wang #include <sys/modctl.h>
717ff83669SZhong Wang #include <sys/file.h>
727ff83669SZhong Wang #include <sys/cred.h>
737ff83669SZhong Wang #include <sys/byteorder.h>
747ff83669SZhong Wang #include <sys/atomic.h>
757ff83669SZhong Wang #include <sys/scsi/scsi.h>
767ff83669SZhong Wang #include <sys/mac_client.h>
777ff83669SZhong Wang #include <sys/modhash.h>
787ff83669SZhong Wang 
797ff83669SZhong Wang /*
807ff83669SZhong Wang  * LEADVILLE header files
817ff83669SZhong Wang  */
827ff83669SZhong Wang #include <sys/fibre-channel/fc.h>
837ff83669SZhong Wang #include <sys/fibre-channel/impl/fc_fcaif.h>
847ff83669SZhong Wang 
857ff83669SZhong Wang /*
867ff83669SZhong Wang  * COMSTAR header files
877ff83669SZhong Wang  */
887ff83669SZhong Wang #include <sys/stmf_defines.h>
897ff83669SZhong Wang 
907ff83669SZhong Wang /*
917ff83669SZhong Wang  * FCOE header files
927ff83669SZhong Wang  */
937ff83669SZhong Wang #include <sys/fcoe/fcoe_common.h>
947ff83669SZhong Wang 
957ff83669SZhong Wang /*
967ff83669SZhong Wang  * Driver's own header files
977ff83669SZhong Wang  */
987ff83669SZhong Wang #include <fcoei.h>
997ff83669SZhong Wang 
1007ff83669SZhong Wang /*
1017ff83669SZhong Wang  * Forward declaration of internal functions
1027ff83669SZhong Wang  */
1037ff83669SZhong Wang static void fcoei_process_unsol_els_req(fcoe_frame_t *frm);
1047ff83669SZhong Wang static void fcoei_process_sol_els_rsp(fcoe_frame_t *frm);
1057ff83669SZhong Wang static void fcoei_process_unsol_abts_req(fcoe_frame_t *frame);
1067ff83669SZhong Wang static void fcoei_process_sol_abts_acc(fcoe_frame_t *frame);
1077ff83669SZhong Wang static void fcoei_process_sol_abts_rjt(fcoe_frame_t *frame);
1087ff83669SZhong Wang static void fcoei_process_sol_ct_rsp(fcoe_frame_t *frame);
1097ff83669SZhong Wang static void fcoei_process_unsol_xfer_rdy(fcoe_frame_t *frame);
1107ff83669SZhong Wang static void fcoei_process_sol_fcp_resp(fcoe_frame_t *frm);
1117ff83669SZhong Wang 
1127ff83669SZhong Wang static void fcoei_fill_fcp_resp(uint8_t *src, uint8_t *dest, int size);
1137ff83669SZhong Wang static void fcoei_fill_els_fpkt_resp(fcoe_frame_t *frm, fcoei_exchange_t *xch,
1147ff83669SZhong Wang     int size);
1157ff83669SZhong Wang 
1167ff83669SZhong Wang /*
1177ff83669SZhong Wang  * fcoei_rx_frame
1187ff83669SZhong Wang  *	Unsolicited frame is received
1197ff83669SZhong Wang  *
1207ff83669SZhong Wang  * Input:
1217ff83669SZhong Wang  *	frame = unsolicited frame that is received
1227ff83669SZhong Wang  *
1237ff83669SZhong Wang  * Return:
1247ff83669SZhong Wang  *	N/A
1257ff83669SZhong Wang  *
1267ff83669SZhong Wang  * Comment:
1277ff83669SZhong Wang  *	N/A
1287ff83669SZhong Wang  */
1297ff83669SZhong Wang static void
fcoei_rx_frame(fcoe_frame_t * frm)1307ff83669SZhong Wang fcoei_rx_frame(fcoe_frame_t *frm)
1317ff83669SZhong Wang {
1327ff83669SZhong Wang 	if (!(FRM2SS(frm)->ss_flags & SS_FLAG_LV_BOUND)) {
1337ff83669SZhong Wang 		/*
1347ff83669SZhong Wang 		 * Release the frame and netb
1357ff83669SZhong Wang 		 */
1367ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "not bound now");
1377ff83669SZhong Wang 		frm->frm_eport->eport_free_netb(frm->frm_netb);
1387ff83669SZhong Wang 		frm->frm_eport->eport_release_frame(frm);
1397ff83669SZhong Wang 		return;
1407ff83669SZhong Wang 	}
1417ff83669SZhong Wang 
1427ff83669SZhong Wang 	FRM2IFM(frm)->ifm_ae.ae_type = AE_EVENT_UNSOL_FRAME;
1437ff83669SZhong Wang 	FRM2IFM(frm)->ifm_ae.ae_obj = frm;
1447ff83669SZhong Wang 
1457ff83669SZhong Wang 	mutex_enter(&FRM2SS(frm)->ss_watchdog_mutex);
1467ff83669SZhong Wang 	list_insert_tail(&FRM2SS(frm)->ss_event_list, &FRM2IFM(frm)->ifm_ae);
1477ff83669SZhong Wang 	if (FRM2SS(frm)->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
1487ff83669SZhong Wang 		cv_signal(&FRM2SS(frm)->ss_watchdog_cv);
1497ff83669SZhong Wang 	}
1507ff83669SZhong Wang 	mutex_exit(&FRM2SS(frm)->ss_watchdog_mutex);
1517ff83669SZhong Wang }
1527ff83669SZhong Wang 
1537ff83669SZhong Wang /*
1547ff83669SZhong Wang  * fcoei_release_sol_frame
1557ff83669SZhong Wang  *	Release the solicited frame that has just been sent out
1567ff83669SZhong Wang  *
1577ff83669SZhong Wang  * Input:
1587ff83669SZhong Wang  *	frame = solicited frame that has been sent out
1597ff83669SZhong Wang  *
1607ff83669SZhong Wang  * Returns:
1617ff83669SZhong Wang  *	N/A
1627ff83669SZhong Wang  *
1637ff83669SZhong Wang  * Comments:
1647ff83669SZhong Wang  *	After FCOE sends solicited frames out, it will call this to notify
1657ff83669SZhong Wang  *	FCOEI of the completion.
1667ff83669SZhong Wang  */
1677ff83669SZhong Wang static void
fcoei_release_sol_frame(fcoe_frame_t * frm)1687ff83669SZhong Wang fcoei_release_sol_frame(fcoe_frame_t *frm)
1697ff83669SZhong Wang {
1707ff83669SZhong Wang 	/*
1717ff83669SZhong Wang 	 * For request-type frames, it's safe to be handled out of
1727ff83669SZhong Wang 	 * watchdog, because it needn't update anything
1737ff83669SZhong Wang 	 */
1747ff83669SZhong Wang 	switch (FRM2IFM(frm)->ifm_rctl) {
1757ff83669SZhong Wang 	case R_CTL_SOLICITED_DATA:
1767ff83669SZhong Wang 	case R_CTL_COMMAND:
1777ff83669SZhong Wang 	case R_CTL_ELS_REQ:
1787ff83669SZhong Wang 	case R_CTL_UNSOL_CONTROL:
1797ff83669SZhong Wang 	case R_CTL_LS_ABTS:
1807ff83669SZhong Wang 		FRM2SS(frm)->ss_eport->eport_release_frame(frm);
1817ff83669SZhong Wang 		break;
1827ff83669SZhong Wang 
1837ff83669SZhong Wang 	default:
1847ff83669SZhong Wang 		FRM2IFM(frm)->ifm_ae.ae_type = AE_EVENT_SOL_FRAME;
1857ff83669SZhong Wang 		FRM2IFM(frm)->ifm_ae.ae_obj = frm;
1867ff83669SZhong Wang 
1877ff83669SZhong Wang 		mutex_enter(&FRM2SS(frm)->ss_watchdog_mutex);
1887ff83669SZhong Wang 		list_insert_tail(&FRM2SS(frm)->ss_event_list,
1897ff83669SZhong Wang 		    &FRM2IFM(frm)->ifm_ae);
1907ff83669SZhong Wang 		if (FRM2SS(frm)->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
1917ff83669SZhong Wang 			cv_signal(&FRM2SS(frm)->ss_watchdog_cv);
1927ff83669SZhong Wang 		}
1937ff83669SZhong Wang 		mutex_exit(&FRM2SS(frm)->ss_watchdog_mutex);
1947ff83669SZhong Wang 		break;
1957ff83669SZhong Wang 	}
1967ff83669SZhong Wang }
1977ff83669SZhong Wang 
1987ff83669SZhong Wang /*
1997ff83669SZhong Wang  * fcoei_process_unsol_xfer_rdy
2007ff83669SZhong Wang  *	XFER_RDY is received
2017ff83669SZhong Wang  *
2027ff83669SZhong Wang  * Input:
2037ff83669SZhong Wang  *	frm = XFER_RDY frame
2047ff83669SZhong Wang  *
2057ff83669SZhong Wang  * Returns:
2067ff83669SZhong Wang  *	N/A
2077ff83669SZhong Wang  *
2087ff83669SZhong Wang  * Comments:
2097ff83669SZhong Wang  *	N/A
2107ff83669SZhong Wang  */
2117ff83669SZhong Wang static void
fcoei_process_unsol_xfer_rdy(fcoe_frame_t * frm)2127ff83669SZhong Wang fcoei_process_unsol_xfer_rdy(fcoe_frame_t *frm)
2137ff83669SZhong Wang {
2147ff83669SZhong Wang 	uint16_t		 sol_oxid;
2157ff83669SZhong Wang 	fcoei_exchange_t	*xch;
2167ff83669SZhong Wang 	int			 rcv_buf_size;
2177ff83669SZhong Wang 	int			 offset;
2187ff83669SZhong Wang 	int			 left_size;
2197ff83669SZhong Wang 	int			 data_size;
2207ff83669SZhong Wang 	int			 frm_num;
2217ff83669SZhong Wang 	int			 idx;
2227ff83669SZhong Wang 	fcoe_frame_t		*nfrm;
2237ff83669SZhong Wang 
2247ff83669SZhong Wang 	sol_oxid = FRM_OXID(frm);
2257ff83669SZhong Wang 	if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
2267ff83669SZhong Wang 	    FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
2277ff83669SZhong Wang 		return;
2287ff83669SZhong Wang 	}
2297ff83669SZhong Wang 
2307ff83669SZhong Wang 	/*
2317ff83669SZhong Wang 	 * rcv_buf_size is the total size of data that should be transferred
2327ff83669SZhong Wang 	 * in this sequence.
2337ff83669SZhong Wang 	 * offset is based on the exchange not the sequence.
2347ff83669SZhong Wang 	 */
2357ff83669SZhong Wang 	xch->xch_rxid = FRM_RXID(frm);
2367ff83669SZhong Wang 	rcv_buf_size = FCOE_B2V_4(frm->frm_payload + 4);
2377ff83669SZhong Wang 	offset = FCOE_B2V_4(frm->frm_payload);
2387ff83669SZhong Wang 	ASSERT(xch->xch_resid >= rcv_buf_size);
2397ff83669SZhong Wang 
2407ff83669SZhong Wang 	/*
2417ff83669SZhong Wang 	 * Local variables initialization
2427ff83669SZhong Wang 	 */
2437ff83669SZhong Wang 	left_size = rcv_buf_size;
2447ff83669SZhong Wang 	data_size = FRM2SS(frm)->ss_fcp_data_payload_size;
2457ff83669SZhong Wang 	frm_num = (rcv_buf_size + data_size - 1) / data_size;
2467ff83669SZhong Wang 
2477ff83669SZhong Wang 	for (idx = 0; idx < frm_num - 1; idx++) {
2487ff83669SZhong Wang 		/*
2497ff83669SZhong Wang 		 * The first (frm_num -1) frames are always full
2507ff83669SZhong Wang 		 */
2517ff83669SZhong Wang 		nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame(
2527ff83669SZhong Wang 		    FRM2SS(frm)->ss_eport, data_size + FCFH_SIZE, NULL);
2537ff83669SZhong Wang 		if (nfrm == NULL) {
2547ff83669SZhong Wang 			FCOEI_LOG(__FUNCTION__, "can't alloc frame");
2557ff83669SZhong Wang 			return;
2567ff83669SZhong Wang 		}
2577ff83669SZhong Wang 
2587ff83669SZhong Wang 		/*
2597ff83669SZhong Wang 		 * Copy the data payload that will  be transferred
2607ff83669SZhong Wang 		 */
2617ff83669SZhong Wang 		bcopy(offset + (uint8_t *)xch->xch_fpkt->pkt_data,
2627ff83669SZhong Wang 		    nfrm->frm_payload, nfrm->frm_payload_size);
2637ff83669SZhong Wang 
2647ff83669SZhong Wang 		FFM_R_CTL(R_CTL_SOLICITED_DATA, nfrm);
2657ff83669SZhong Wang 		FFM_TYPE(FC_TYPE_SCSI_FCP, nfrm);
2667ff83669SZhong Wang 		FFM_F_CTL(0x010008, nfrm);
2677ff83669SZhong Wang 		FFM_OXID(xch->xch_oxid, nfrm);
2687ff83669SZhong Wang 		FFM_RXID(xch->xch_rxid, nfrm);
2697ff83669SZhong Wang 		FFM_S_ID(FRM_D_ID(frm), nfrm);
2707ff83669SZhong Wang 		FFM_D_ID(FRM_S_ID(frm), nfrm);
2717ff83669SZhong Wang 		FFM_SEQ_CNT(idx, nfrm);
2727ff83669SZhong Wang 		FFM_PARAM(offset, nfrm);
2737ff83669SZhong Wang 		fcoei_init_ifm(nfrm, xch);
2747ff83669SZhong Wang 
2757ff83669SZhong Wang 		/*
2767ff83669SZhong Wang 		 * Submit the frame
2777ff83669SZhong Wang 		 */
2787ff83669SZhong Wang 		xch->xch_ss->ss_eport->eport_tx_frame(nfrm);
2797ff83669SZhong Wang 
2807ff83669SZhong Wang 		/*
2817ff83669SZhong Wang 		 * Update offset and left_size
2827ff83669SZhong Wang 		 */
2837ff83669SZhong Wang 		offset += data_size;
2847ff83669SZhong Wang 		left_size -= data_size;
2857ff83669SZhong Wang 	}
2867ff83669SZhong Wang 
2877ff83669SZhong Wang 	/*
2887ff83669SZhong Wang 	 * Send the last data frame of this sequence
2897ff83669SZhong Wang 	 */
2907ff83669SZhong Wang 	data_size = left_size;
2917ff83669SZhong Wang 	nfrm = xch->xch_ss->ss_eport->eport_alloc_frame(
2927ff83669SZhong Wang 	    xch->xch_ss->ss_eport, data_size + FCFH_SIZE, NULL);
2937ff83669SZhong Wang 	if (nfrm != NULL) {
2947ff83669SZhong Wang 		fcoei_init_ifm(nfrm, xch);
2957ff83669SZhong Wang 	} else {
2967ff83669SZhong Wang 		ASSERT(0);
2977ff83669SZhong Wang 		return;
2987ff83669SZhong Wang 	}
2997ff83669SZhong Wang 
3007ff83669SZhong Wang 	/*
3017ff83669SZhong Wang 	 * Copy the data payload that will be transferred
3027ff83669SZhong Wang 	 */
3037ff83669SZhong Wang 	bcopy(offset + (uint8_t *)xch->xch_fpkt->pkt_data,
3047ff83669SZhong Wang 	    nfrm->frm_payload, nfrm->frm_payload_size);
3057ff83669SZhong Wang 
3067ff83669SZhong Wang 	/*
3077ff83669SZhong Wang 	 * Set ifm_rctl for fcoei_handle_sol_frame_done
3087ff83669SZhong Wang 	 */
3097ff83669SZhong Wang 	FRM2IFM(nfrm)->ifm_rctl = R_CTL_SOLICITED_DATA;
3107ff83669SZhong Wang 
3117ff83669SZhong Wang 	/*
3127ff83669SZhong Wang 	 * FFM
3137ff83669SZhong Wang 	 */
3147ff83669SZhong Wang 	FFM_R_CTL(R_CTL_SOLICITED_DATA, nfrm);
3157ff83669SZhong Wang 	FFM_TYPE(FC_TYPE_SCSI_FCP, nfrm);
3167ff83669SZhong Wang 	FFM_F_CTL(0x090008, nfrm);
3177ff83669SZhong Wang 	FFM_OXID(xch->xch_oxid, nfrm);
3187ff83669SZhong Wang 	FFM_RXID(xch->xch_rxid, nfrm);
3197ff83669SZhong Wang 	FFM_S_ID(FRM_D_ID(frm), nfrm);
3207ff83669SZhong Wang 	FFM_D_ID(FRM_S_ID(frm), nfrm);
3217ff83669SZhong Wang 	FFM_SEQ_CNT(idx, nfrm);
3227ff83669SZhong Wang 	FFM_PARAM(offset, nfrm);
3237ff83669SZhong Wang 
3247ff83669SZhong Wang 	/*
3257ff83669SZhong Wang 	 * Submit the frame
3267ff83669SZhong Wang 	 */
3277ff83669SZhong Wang 	xch->xch_ss->ss_eport->eport_tx_frame(nfrm);
3287ff83669SZhong Wang 
3297ff83669SZhong Wang 	/*
3307ff83669SZhong Wang 	 * Sequence is a transaction, so we need only update
3317ff83669SZhong Wang 	 * xch_remained_bytes in the end.
3327ff83669SZhong Wang 	 */
3337ff83669SZhong Wang 	xch->xch_resid -= rcv_buf_size;
3347ff83669SZhong Wang }
3357ff83669SZhong Wang 
3367ff83669SZhong Wang /*
3377ff83669SZhong Wang  * fcoei_process_unsol_els_req
3387ff83669SZhong Wang  *	els req frame is received
3397ff83669SZhong Wang  *
3407ff83669SZhong Wang  * Input:
3417ff83669SZhong Wang  *	frm = ELS request frame
3427ff83669SZhong Wang  *
3437ff83669SZhong Wang  * Returns:
3447ff83669SZhong Wang  *	N/A
3457ff83669SZhong Wang  *
3467ff83669SZhong Wang  * Comments:
3477ff83669SZhong Wang  *	We will not create exchange data structure at this time,
3487ff83669SZhong Wang  *	and we should create unsolicited buffer, which will only
3497ff83669SZhong Wang  *	contain the exchange's request payload.
3507ff83669SZhong Wang  */
3517ff83669SZhong Wang static void
fcoei_process_unsol_els_req(fcoe_frame_t * frm)3527ff83669SZhong Wang fcoei_process_unsol_els_req(fcoe_frame_t *frm)
3537ff83669SZhong Wang {
3547ff83669SZhong Wang 	fc_unsol_buf_t		*ub;
3557ff83669SZhong Wang 	fc_rscn_t		*rscn;
3567ff83669SZhong Wang 	uint32_t		 offset;
3577ff83669SZhong Wang 	fcoei_exchange_t	*xch_tmp;
3587ff83669SZhong Wang 
3597ff83669SZhong Wang 	/*
3607ff83669SZhong Wang 	 * Get the unsol rxid first
3617ff83669SZhong Wang 	 */
3627ff83669SZhong Wang 	FCOEI_SET_UNSOL_FRM_RXID(frm, xch_tmp);
3637ff83669SZhong Wang 
3647ff83669SZhong Wang 	/*
3657ff83669SZhong Wang 	 * Do proper ub initialization
3667ff83669SZhong Wang 	 */
3677ff83669SZhong Wang 	ub = (fc_unsol_buf_t *)kmem_zalloc(sizeof (fc_unsol_buf_t), KM_SLEEP);
3687ff83669SZhong Wang 	ub->ub_class = FC_TRAN_CLASS3;
3697ff83669SZhong Wang 	ub->ub_bufsize = frm->frm_payload_size;
3707ff83669SZhong Wang 	ub->ub_buffer = kmem_alloc(frm->frm_payload_size, KM_SLEEP);
3717ff83669SZhong Wang 	ub->ub_port_handle = FRM2SS(frm);
3727ff83669SZhong Wang 	ub->ub_token = (uint64_t)(long)ub;
3737ff83669SZhong Wang 
3747ff83669SZhong Wang 	/*
3757ff83669SZhong Wang 	 * header conversion
3767ff83669SZhong Wang 	 * Caution: ub_buffer is big endian, but ub_frame should be host-format
3777ff83669SZhong Wang 	 * RSCN is one exception.
3787ff83669SZhong Wang 	 */
3797ff83669SZhong Wang 	FCOEI_FRM2FHDR(frm, &ub->ub_frame);
3807ff83669SZhong Wang 
3817ff83669SZhong Wang 	/*
3827ff83669SZhong Wang 	 * If it's FLOGI, and our FLOGI failed last time,
3837ff83669SZhong Wang 	 * then we post online event
3847ff83669SZhong Wang 	 */
3857ff83669SZhong Wang 	if ((FRM2SS(frm)->ss_flags & SS_FLAG_FLOGI_FAILED) &&
3867ff83669SZhong Wang 	    (frm->frm_payload[0] == LA_ELS_FLOGI)) {
3877ff83669SZhong Wang 		frm->frm_eport->eport_flags |=
3887ff83669SZhong Wang 		    EPORT_FLAG_IS_DIRECT_P2P;
3897ff83669SZhong Wang 		FRM2SS(frm)->ss_bind_info.port_statec_cb(FRM2SS(frm)->ss_port,
3907ff83669SZhong Wang 		    FC_STATE_ONLINE);
3917ff83669SZhong Wang 	}
3927ff83669SZhong Wang 
3937ff83669SZhong Wang 	switch (frm->frm_payload[0]) {
3947ff83669SZhong Wang 	case LA_ELS_RSCN:
3957ff83669SZhong Wang 		/*
3967ff83669SZhong Wang 		 * Only RSCN need byte swapping
3977ff83669SZhong Wang 		 */
3987ff83669SZhong Wang 		rscn = (fc_rscn_t *)(void *)ub->ub_buffer;
3997ff83669SZhong Wang 		rscn->rscn_code = frm->frm_payload[0];
4007ff83669SZhong Wang 		rscn->rscn_len = frm->frm_payload[1];
4017ff83669SZhong Wang 		rscn->rscn_payload_len =
4027ff83669SZhong Wang 		    FCOE_B2V_2(frm->frm_payload + 2);
4037ff83669SZhong Wang 
4047ff83669SZhong Wang 		offset = 4;
4057ff83669SZhong Wang 		for (int i = 0; i < rscn->rscn_payload_len - 4; i += 4) {
4067ff83669SZhong Wang 			*(uint32_t *)((intptr_t)(uint8_t *)ub->ub_buffer +
4077ff83669SZhong Wang 			    offset) = FCOE_B2V_4(frm->frm_payload + offset);
4087ff83669SZhong Wang 			offset += 4;
4097ff83669SZhong Wang 		}
4107ff83669SZhong Wang 		break;
4117ff83669SZhong Wang 
4127ff83669SZhong Wang 	default:
4137ff83669SZhong Wang 		bcopy(frm->frm_payload, ub->ub_buffer, frm->frm_payload_size);
4147ff83669SZhong Wang 		break;
4157ff83669SZhong Wang 	}
4167ff83669SZhong Wang 
4177ff83669SZhong Wang 	/*
4187ff83669SZhong Wang 	 * Pass this unsol ELS up to Leadville
4197ff83669SZhong Wang 	 */
4207ff83669SZhong Wang 	FRM2SS(frm)->ss_bind_info.port_unsol_cb(FRM2SS(frm)->ss_port, ub, 0);
4217ff83669SZhong Wang }
4227ff83669SZhong Wang 
4237ff83669SZhong Wang /*
4247ff83669SZhong Wang  * fcoei_search_abort_xch
4257ff83669SZhong Wang  *	Find the exchange that should be aborted
4267ff83669SZhong Wang  *
4277ff83669SZhong Wang  * Input:
4287ff83669SZhong Wang  *	key = oxid of the exchange
4297ff83669SZhong Wang  *	val = the exchange
4307ff83669SZhong Wang  *	arg = the soft state
4317ff83669SZhong Wang  *
4327ff83669SZhong Wang  * Returns:
4337ff83669SZhong Wang  *	MH_WALK_TERMINATE = found it, terminate the walk
4347ff83669SZhong Wang  *	MH_WALK_CONTINUE = not found, continue the walk
4357ff83669SZhong Wang  *
4367ff83669SZhong Wang  * Comments:
4377ff83669SZhong Wang  *	N/A
4387ff83669SZhong Wang  */
439516aa12cSYu Renia Miao /* ARGSUSED */
4407ff83669SZhong Wang static uint32_t
fcoei_search_abort_xch(mod_hash_key_t key,mod_hash_val_t * val,void * arg)4417ff83669SZhong Wang fcoei_search_abort_xch(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
4427ff83669SZhong Wang {
4437ff83669SZhong Wang 	fcoei_walk_arg_t	*wa = (fcoei_walk_arg_t *)arg;
4447ff83669SZhong Wang 	fcoei_exchange_t	*xch = (fcoei_exchange_t *)val;
4457ff83669SZhong Wang 
4467ff83669SZhong Wang 	if (xch->xch_oxid == wa->wa_oxid) {
4477ff83669SZhong Wang 		wa->wa_xch = xch;
4487ff83669SZhong Wang 		ASSERT(xch->xch_oxid == CMHK(key));
4497ff83669SZhong Wang 		return (MH_WALK_TERMINATE);
4507ff83669SZhong Wang 	}
4517ff83669SZhong Wang 
4527ff83669SZhong Wang 	return (MH_WALK_CONTINUE);
4537ff83669SZhong Wang }
4547ff83669SZhong Wang 
4557ff83669SZhong Wang /*
4567ff83669SZhong Wang  * fcoei_process_unsol_abts_req
4577ff83669SZhong Wang  *	ABTS request is received
4587ff83669SZhong Wang  *
4597ff83669SZhong Wang  * Input:
4607ff83669SZhong Wang  *	frm = ABTS request frame
4617ff83669SZhong Wang  *
4627ff83669SZhong Wang  * Returns:
4637ff83669SZhong Wang  *	N/A
4647ff83669SZhong Wang  *
4657ff83669SZhong Wang  * Comments:
4667ff83669SZhong Wang  *	The remote side wants to abort one unsolicited exchange.
4677ff83669SZhong Wang  */
4687ff83669SZhong Wang static void
fcoei_process_unsol_abts_req(fcoe_frame_t * frm)4697ff83669SZhong Wang fcoei_process_unsol_abts_req(fcoe_frame_t *frm)
4707ff83669SZhong Wang {
4717ff83669SZhong Wang 	fcoei_exchange_t	*xch = NULL;
4727ff83669SZhong Wang 	fcoe_frame_t		*nfrm;
4737ff83669SZhong Wang 	int			 payload_size;
4747ff83669SZhong Wang 	fcoei_walk_arg_t	 walk_arg;
4757ff83669SZhong Wang 
4767ff83669SZhong Wang 	/*
4777ff83669SZhong Wang 	 * According to spec, the responder could want to ABTS xch too
4787ff83669SZhong Wang 	 */
4797ff83669SZhong Wang 	if (FRM_SENDER_IS_XCH_RESPONDER(frm)) {
4807ff83669SZhong Wang 		uint16_t sol_oxid = FRM_OXID(frm);
4817ff83669SZhong Wang 		(void) mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
4827ff83669SZhong Wang 		    FMHK(sol_oxid), (mod_hash_val_t *)&xch);
4837ff83669SZhong Wang 	} else {
4847ff83669SZhong Wang 		/*
4857ff83669SZhong Wang 		 * it's a unsolicited exchange, and we need find it out from
4867ff83669SZhong Wang 		 * unsolicited hash table. But at this time, RXID in frame could
4877ff83669SZhong Wang 		 * still be 0xFFFF in most cases, so we need do exaustive search
4887ff83669SZhong Wang 		 */
4897ff83669SZhong Wang 		walk_arg.wa_xch = NULL;
4907ff83669SZhong Wang 		walk_arg.wa_oxid = FRM_OXID(frm);
4917ff83669SZhong Wang 		mod_hash_walk(FRM2SS(frm)->ss_unsol_rxid_hash,
4927ff83669SZhong Wang 		    fcoei_search_abort_xch, &walk_arg);
4937ff83669SZhong Wang 		xch = walk_arg.wa_xch;
4947ff83669SZhong Wang 	}
4957ff83669SZhong Wang 
4967ff83669SZhong Wang 	if (xch == NULL) {
4977ff83669SZhong Wang 		payload_size = 4;
4987ff83669SZhong Wang 		nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame(
4997ff83669SZhong Wang 		    FRM2SS(frm)->ss_eport,
5007ff83669SZhong Wang 		    payload_size + FCFH_SIZE, NULL);
5017ff83669SZhong Wang 		if (nfrm == NULL) {
5027ff83669SZhong Wang 			FCOEI_LOG(__FUNCTION__, "can't alloc frame");
5037ff83669SZhong Wang 			return;
5047ff83669SZhong Wang 		}
5057ff83669SZhong Wang 
5067ff83669SZhong Wang 		bzero(nfrm->frm_payload, nfrm->frm_payload_size);
5077ff83669SZhong Wang 		nfrm->frm_payload[1] = 0x05;
5087ff83669SZhong Wang 		nfrm->frm_payload[3] = 0xAA;
5097ff83669SZhong Wang 		FFM_R_CTL(R_CTL_LS_BA_RJT, nfrm);
5107ff83669SZhong Wang 		fcoei_init_ifm(nfrm, xch);
5117ff83669SZhong Wang 	} else {
5127ff83669SZhong Wang 		/*
5137ff83669SZhong Wang 		 * We should complete the exchange with frm as NULL,
5147ff83669SZhong Wang 		 * and we don't care its success or failure
5157ff83669SZhong Wang 		 */
5167ff83669SZhong Wang 		fcoei_complete_xch(xch, NULL, FC_PKT_FAILURE, FC_REASON_ABTX);
5177ff83669SZhong Wang 
5187ff83669SZhong Wang 		/*
5197ff83669SZhong Wang 		 * Construct ABTS ACC frame
5207ff83669SZhong Wang 		 */
5217ff83669SZhong Wang 		payload_size = 12;
5227ff83669SZhong Wang 		nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame(
5237ff83669SZhong Wang 		    FRM2SS(frm)->ss_eport, payload_size + FCFH_SIZE, NULL);
5247ff83669SZhong Wang 		if (nfrm == NULL) {
5257ff83669SZhong Wang 			FCOEI_LOG(__FUNCTION__, "can't alloc frame");
5267ff83669SZhong Wang 			return;
5277ff83669SZhong Wang 		}
5287ff83669SZhong Wang 
5297ff83669SZhong Wang 		bzero(nfrm->frm_payload, nfrm->frm_payload_size);
5307ff83669SZhong Wang 		nfrm->frm_payload[4] = 0xFF & (xch->xch_oxid >> 8);
5317ff83669SZhong Wang 		nfrm->frm_payload[5] = 0xFF & (xch->xch_oxid);
5327ff83669SZhong Wang 		nfrm->frm_payload[6] = 0xFF & (xch->xch_rxid >> 8);
5337ff83669SZhong Wang 		nfrm->frm_payload[7] = 0xFF & (xch->xch_rxid);
5347ff83669SZhong Wang 		nfrm->frm_payload[10] = 0xFF;
5357ff83669SZhong Wang 		nfrm->frm_payload[11] = 0xFF;
5367ff83669SZhong Wang 
5377ff83669SZhong Wang 		FFM_R_CTL(R_CTL_LS_BA_ACC, nfrm);
5387ff83669SZhong Wang 		fcoei_init_ifm(nfrm, xch);
5397ff83669SZhong Wang 	}
5407ff83669SZhong Wang 
5417ff83669SZhong Wang 	FFM_D_ID(FRM_S_ID(frm), nfrm);
5427ff83669SZhong Wang 	FFM_S_ID(FRM_D_ID(frm), nfrm);
5437ff83669SZhong Wang 	FFM_TYPE(FRM_TYPE(frm), nfrm);
5447ff83669SZhong Wang 	FFM_F_CTL(FRM_F_CTL(frm), nfrm);
5457ff83669SZhong Wang 	FFM_OXID(FRM_OXID(frm), nfrm);
5467ff83669SZhong Wang 	FFM_RXID(FRM_RXID(frm), nfrm);
5477ff83669SZhong Wang 	FRM2SS(frm)->ss_eport->eport_tx_frame(nfrm);
5487ff83669SZhong Wang }
5497ff83669SZhong Wang 
5507ff83669SZhong Wang /*
5517ff83669SZhong Wang  * fcoei_process_sol_fcp_resp
5527ff83669SZhong Wang  *	FCP response is received
5537ff83669SZhong Wang  *
5547ff83669SZhong Wang  * Input:
5557ff83669SZhong Wang  *	frm = FCP response frame
5567ff83669SZhong Wang  *
5577ff83669SZhong Wang  * Returns:
5587ff83669SZhong Wang  *	N/A
5597ff83669SZhong Wang  *
5607ff83669SZhong Wang  * Comments:
5617ff83669SZhong Wang  *	N/A
5627ff83669SZhong Wang  */
5637ff83669SZhong Wang static void
fcoei_process_sol_fcp_resp(fcoe_frame_t * frm)5647ff83669SZhong Wang fcoei_process_sol_fcp_resp(fcoe_frame_t *frm)
5657ff83669SZhong Wang {
5667ff83669SZhong Wang 	uint16_t		 sol_oxid;
5677ff83669SZhong Wang 	uint32_t		 actual_size;
5687ff83669SZhong Wang 	fcoei_exchange_t	*xch  = NULL;
5697ff83669SZhong Wang 	fc_packet_t		*fpkt = NULL;
5707ff83669SZhong Wang 	mod_hash_val_t		 val;
5717ff83669SZhong Wang 	uint32_t		 i_fcp_status;
5727ff83669SZhong Wang 
5737ff83669SZhong Wang 	/*
5747ff83669SZhong Wang 	 * Firstly, we search the related exchange
5757ff83669SZhong Wang 	 */
5767ff83669SZhong Wang 	sol_oxid = FRM_OXID(frm);
5777ff83669SZhong Wang 	if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
5787ff83669SZhong Wang 	    FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
5797ff83669SZhong Wang 		PRT_FRM_HDR(__FUNCTION__, frm);
5807ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "can't find the corresponding xch: "
5817ff83669SZhong Wang 		    "oxid/%x %lu - %lu", sol_oxid,
5827ff83669SZhong Wang 		    CURRENT_CLOCK, frm->frm_clock);
5837ff83669SZhong Wang 		return;
5847ff83669SZhong Wang 	} else {
5857ff83669SZhong Wang 		fpkt = xch->xch_fpkt;
5867ff83669SZhong Wang 	}
5877ff83669SZhong Wang 
5887ff83669SZhong Wang 	/*
5897ff83669SZhong Wang 	 * Decide the actual response length
5907ff83669SZhong Wang 	 */
5917ff83669SZhong Wang 	actual_size = fpkt->pkt_rsplen;
5927ff83669SZhong Wang 	if (actual_size > frm->frm_payload_size) {
5937ff83669SZhong Wang 		actual_size = frm->frm_payload_size;
5947ff83669SZhong Wang 	}
5957ff83669SZhong Wang 
5967ff83669SZhong Wang 	/*
5977ff83669SZhong Wang 	 * Update the exchange and hash table
5987ff83669SZhong Wang 	 */
599ef4cb712SZhong Wang 	(void) mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
6007ff83669SZhong Wang 	    FMHK(xch->xch_oxid), &val);
6017ff83669SZhong Wang 	ASSERT((fcoei_exchange_t *)val == xch);
6027ff83669SZhong Wang 	xch->xch_flags &= ~XCH_FLAG_IN_SOL_HASH;
6037ff83669SZhong Wang 
6047ff83669SZhong Wang 	/*
6057ff83669SZhong Wang 	 * Upate fpkt related elements
6067ff83669SZhong Wang 	 */
6077ff83669SZhong Wang 	FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr);
6087ff83669SZhong Wang 
6097ff83669SZhong Wang 	/*
6107ff83669SZhong Wang 	 * we should set pkt_reason and pkt_state carefully
6117ff83669SZhong Wang 	 */
6127ff83669SZhong Wang 	fpkt->pkt_state = FC_PKT_SUCCESS;
6137ff83669SZhong Wang 	fpkt->pkt_reason = 0;
6147ff83669SZhong Wang 
6157ff83669SZhong Wang 	/*
6167ff83669SZhong Wang 	 * First we zero the first 12 byte of dest
6177ff83669SZhong Wang 	 */
6187ff83669SZhong Wang 	bzero(xch->xch_fpkt->pkt_resp, 12);
6197ff83669SZhong Wang 	i_fcp_status = BE_IN32(frm->frm_payload + 8);
6207ff83669SZhong Wang 	if (i_fcp_status != 0) {
6217ff83669SZhong Wang 		fcoei_fill_fcp_resp(frm->frm_payload,
6227ff83669SZhong Wang 		    (uint8_t *)xch->xch_fpkt->pkt_resp, actual_size);
6237ff83669SZhong Wang 	}
6247ff83669SZhong Wang 
6257ff83669SZhong Wang 	/*
6267ff83669SZhong Wang 	 * Update pkt_resp_resid
6277ff83669SZhong Wang 	 */
6287ff83669SZhong Wang 	fpkt->pkt_data_resid = xch->xch_resid;
6297ff83669SZhong Wang 	if ((xch->xch_resid != 0) && ((xch->xch_resid % 0x200) == 0) &&
6307ff83669SZhong Wang 	    ((xch->xch_fpkt->pkt_datalen % 0x200) == 0) &&
6317ff83669SZhong Wang 	    (i_fcp_status == 0)) {
6327ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "frame lost no pause ? %x/%x",
6337ff83669SZhong Wang 		    xch->xch_resid, xch->xch_fpkt->pkt_datalen);
6347ff83669SZhong Wang 		fpkt->pkt_state = FC_PKT_LOCAL_RJT;
6357ff83669SZhong Wang 		fpkt->pkt_reason = FC_REASON_UNDERRUN;
6367ff83669SZhong Wang 	}
6377ff83669SZhong Wang 
6387ff83669SZhong Wang 	/*
6397ff83669SZhong Wang 	 * Notify LV it's over
6407ff83669SZhong Wang 	 */
6417ff83669SZhong Wang 	if (fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
6427ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "BEFORE WAKEUP: %p-%p", fpkt, xch);
6437ff83669SZhong Wang 		sema_v(&xch->xch_sema);
6447ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "AFTERE WAKEUP: %p-%p", fpkt, xch);
6457ff83669SZhong Wang 	} else {
6467ff83669SZhong Wang 		xch->xch_fpkt->pkt_comp(xch->xch_fpkt);
6477ff83669SZhong Wang 	}
6487ff83669SZhong Wang }
6497ff83669SZhong Wang 
6507ff83669SZhong Wang /*
6517ff83669SZhong Wang  * fcoei_process_sol_els_rsp
6527ff83669SZhong Wang  *	ELS response is received
6537ff83669SZhong Wang  *
6547ff83669SZhong Wang  * Input:
6557ff83669SZhong Wang  *	frm = ELS response frame
6567ff83669SZhong Wang  *
6577ff83669SZhong Wang  * Returns:
6587ff83669SZhong Wang  *	N/A
6597ff83669SZhong Wang  *
6607ff83669SZhong Wang  * Comments:
6617ff83669SZhong Wang  *	N/A
6627ff83669SZhong Wang  */
6637ff83669SZhong Wang static void
fcoei_process_sol_els_rsp(fcoe_frame_t * frm)6647ff83669SZhong Wang fcoei_process_sol_els_rsp(fcoe_frame_t *frm)
6657ff83669SZhong Wang {
6667ff83669SZhong Wang 	uint16_t		 sol_oxid    = 0;
6677ff83669SZhong Wang 	uint32_t		 actual_size = 0;
6687ff83669SZhong Wang 	fcoei_exchange_t	*xch;
6697ff83669SZhong Wang 	fc_packet_t		*fpkt;
6707ff83669SZhong Wang 
6717ff83669SZhong Wang 	/*
6727ff83669SZhong Wang 	 * Look for the related exchange
6737ff83669SZhong Wang 	 */
6747ff83669SZhong Wang 	xch = NULL;
6757ff83669SZhong Wang 	fpkt = NULL;
6767ff83669SZhong Wang 	sol_oxid = FRM_OXID(frm);
6777ff83669SZhong Wang 	if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
6787ff83669SZhong Wang 	    FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
6797ff83669SZhong Wang 		PRT_FRM_HDR(__FUNCTION__, frm);
6807ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "can't find the "
6817ff83669SZhong Wang 		    "corresponding xch: oxid/%x", sol_oxid);
6827ff83669SZhong Wang 		return;
6837ff83669SZhong Wang 	}
6847ff83669SZhong Wang 
6857ff83669SZhong Wang 	xch->xch_rxid = FRM_RXID(frm);
6867ff83669SZhong Wang 	fpkt = xch->xch_fpkt;
6877ff83669SZhong Wang 
6887ff83669SZhong Wang 	/*
6897ff83669SZhong Wang 	 * Decide the actual response length
6907ff83669SZhong Wang 	 */
6917ff83669SZhong Wang 	actual_size = frm->frm_payload_size;
6927ff83669SZhong Wang 	if (actual_size > fpkt->pkt_rsplen) {
6937ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "pkt_rsplen is smaller"
6947ff83669SZhong Wang 		    "0x(%x - %x)", actual_size, fpkt->pkt_rsplen);
6957ff83669SZhong Wang 		actual_size = fpkt->pkt_rsplen;
6967ff83669SZhong Wang 	}
6977ff83669SZhong Wang 
6987ff83669SZhong Wang 	/*
6997ff83669SZhong Wang 	 * Upate fpkt related elements
7007ff83669SZhong Wang 	 */
7017ff83669SZhong Wang 	FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr);
7027ff83669SZhong Wang 	fcoei_fill_els_fpkt_resp(frm, xch, actual_size);
7037ff83669SZhong Wang 
7047ff83669SZhong Wang 	/*
7057ff83669SZhong Wang 	 * we should set pkt_reason and pkt_state carefully now
7067ff83669SZhong Wang 	 * Need to analyze pkt_reason according to the response.
7077ff83669SZhong Wang 	 * Leave it untouched now.
7087ff83669SZhong Wang 	 */
7097ff83669SZhong Wang 	if (((ls_code_t *)(void *)xch->xch_fpkt->pkt_resp)->ls_code ==
7107ff83669SZhong Wang 	    LA_ELS_RJT) {
7117ff83669SZhong Wang 		fcoei_complete_xch(xch, NULL, FC_PKT_FABRIC_RJT,
7127ff83669SZhong Wang 		    FC_REASON_INVALID_PARAM);
7137ff83669SZhong Wang 	} else {
7147ff83669SZhong Wang 		fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0);
7157ff83669SZhong Wang 	}
7167ff83669SZhong Wang }
7177ff83669SZhong Wang 
7187ff83669SZhong Wang /*
7197ff83669SZhong Wang  * fcoei_process_sol_ct_rsp
7207ff83669SZhong Wang  *	CT response is received
7217ff83669SZhong Wang  *
7227ff83669SZhong Wang  * Input:
7237ff83669SZhong Wang  *	frm = CT response frame
7247ff83669SZhong Wang  *
7257ff83669SZhong Wang  * Returns:
7267ff83669SZhong Wang  *	N/A
7277ff83669SZhong Wang  *
7287ff83669SZhong Wang  * Comments:
7297ff83669SZhong Wang  *	N/A
7307ff83669SZhong Wang  */
7317ff83669SZhong Wang static void
fcoei_process_sol_ct_rsp(fcoe_frame_t * frm)7327ff83669SZhong Wang fcoei_process_sol_ct_rsp(fcoe_frame_t *frm)
7337ff83669SZhong Wang {
7347ff83669SZhong Wang 	uint16_t		 sol_oxid    = 0;
7357ff83669SZhong Wang 	uint32_t		 actual_size = 0;
7367ff83669SZhong Wang 	fcoei_exchange_t	*xch;
7377ff83669SZhong Wang 	fc_packet_t		*fpkt;
7387ff83669SZhong Wang 
7397ff83669SZhong Wang 	/*
7407ff83669SZhong Wang 	 * Look for the related exchange
7417ff83669SZhong Wang 	 */
7427ff83669SZhong Wang 	xch = NULL;
7437ff83669SZhong Wang 	fpkt = NULL;
7447ff83669SZhong Wang 	sol_oxid = FRM_OXID(frm);
7457ff83669SZhong Wang 	if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
7467ff83669SZhong Wang 	    FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
7477ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "can't find the "
7487ff83669SZhong Wang 		    "corresponding xch: oxid/%x", sol_oxid);
7497ff83669SZhong Wang 		return;
7507ff83669SZhong Wang 	}
7517ff83669SZhong Wang 
7527ff83669SZhong Wang 	xch->xch_rxid = FRM_RXID(frm);
7537ff83669SZhong Wang 	fpkt = xch->xch_fpkt;
7547ff83669SZhong Wang 
7557ff83669SZhong Wang 	/*
7567ff83669SZhong Wang 	 * Decide the actual response length
7577ff83669SZhong Wang 	 */
7587ff83669SZhong Wang 	actual_size = fpkt->pkt_rsplen;
7597ff83669SZhong Wang 	if (actual_size > frm->frm_payload_size) {
7607ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "payload is smaller"
7617ff83669SZhong Wang 		    "0x(%x - %x)", actual_size, frm->frm_payload_size);
7627ff83669SZhong Wang 		actual_size = frm->frm_payload_size;
7637ff83669SZhong Wang 	}
7647ff83669SZhong Wang 
7657ff83669SZhong Wang 	/*
7667ff83669SZhong Wang 	 * Update fpkt related elements
7677ff83669SZhong Wang 	 * Caution: we needn't do byte swapping for CT response
7687ff83669SZhong Wang 	 */
7697ff83669SZhong Wang 	FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr);
7707ff83669SZhong Wang 	bcopy(FPLD, (uint8_t *)xch->xch_fpkt->pkt_resp, actual_size);
7717ff83669SZhong Wang 
7727ff83669SZhong Wang 	/*
7737ff83669SZhong Wang 	 * Complete it with frm as NULL
7747ff83669SZhong Wang 	 */
7757ff83669SZhong Wang 	fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0);
7767ff83669SZhong Wang }
7777ff83669SZhong Wang 
7787ff83669SZhong Wang /*
7797ff83669SZhong Wang  * fcoei_process_sol_abts_acc
7807ff83669SZhong Wang  *	ABTS accpet is received
7817ff83669SZhong Wang  *
7827ff83669SZhong Wang  * Input:
7837ff83669SZhong Wang  *	frm = ABTS accept frame
7847ff83669SZhong Wang  *
7857ff83669SZhong Wang  * Returns:
7867ff83669SZhong Wang  *	N/A
7877ff83669SZhong Wang  *
7887ff83669SZhong Wang  * Comments:
7897ff83669SZhong Wang  *	We will always finish the abortion of solicited exchanges,
7907ff83669SZhong Wang  *	so we will not depend on the response from the remote side.
7917ff83669SZhong Wang  *	We just log one message.
7927ff83669SZhong Wang  */
7937ff83669SZhong Wang static void
fcoei_process_sol_abts_acc(fcoe_frame_t * frm)7947ff83669SZhong Wang fcoei_process_sol_abts_acc(fcoe_frame_t *frm)
7957ff83669SZhong Wang {
7967ff83669SZhong Wang 	FCOEI_LOG(__FUNCTION__, "the remote side has agreed to "
7977ff83669SZhong Wang 	    "abort the exchange: oxid-%x, rxid-%x",
7987ff83669SZhong Wang 	    FCOE_B2V_2(frm->frm_payload + 4),
7997ff83669SZhong Wang 	    FCOE_B2V_2(frm->frm_payload + 6));
8007ff83669SZhong Wang }
8017ff83669SZhong Wang 
8027ff83669SZhong Wang /*
8037ff83669SZhong Wang  * fcoei_process_sol_abts_rjt
8047ff83669SZhong Wang  *	ABTS reject is received
8057ff83669SZhong Wang  *
8067ff83669SZhong Wang  * Input:
8077ff83669SZhong Wang  *	frm = ABTS reject frame
8087ff83669SZhong Wang  *
8097ff83669SZhong Wang  * Returns:
8107ff83669SZhong Wang  *	N/A
8117ff83669SZhong Wang  *
8127ff83669SZhong Wang  * Comments:
8137ff83669SZhong Wang  *	We will alwayas finish the abortion of solicited exchanges,
8147ff83669SZhong Wang  *	so we will not depend on the response from the remote side.
8157ff83669SZhong Wang  *	We just log one message.
8167ff83669SZhong Wang  */
8177ff83669SZhong Wang static void
fcoei_process_sol_abts_rjt(fcoe_frame_t * frm)8187ff83669SZhong Wang fcoei_process_sol_abts_rjt(fcoe_frame_t *frm)
8197ff83669SZhong Wang {
8207ff83669SZhong Wang 	FCOEI_LOG(__FUNCTION__, "the remote side rejected "
8217ff83669SZhong Wang 	    "our request to abort one exchange.: %p", frm);
8227ff83669SZhong Wang }
8237ff83669SZhong Wang 
8247ff83669SZhong Wang /*
8257ff83669SZhong Wang  * fcoei_fill_els_fpkt_resp
8267ff83669SZhong Wang  *	Fill fpkt ELS response in host format according frm payload
8277ff83669SZhong Wang  *
8287ff83669SZhong Wang  * Input:
8297ff83669SZhong Wang  *	src = frm payload in link format
8307ff83669SZhong Wang  *	dest = fpkt ELS response in host format
8317ff83669SZhong Wang  *	size = Maximum conversion size
8327ff83669SZhong Wang  *	els_op = ELS opcode
8337ff83669SZhong Wang  *
8347ff83669SZhong Wang  * Returns:
8357ff83669SZhong Wang  *	N/A
8367ff83669SZhong Wang  *
8377ff83669SZhong Wang  * Comments:
8387ff83669SZhong Wang  *	fpkt->pkt_resp must be mapped to one data structure, and it's
8397ff83669SZhong Wang  *	different from the content in the raw frame
8407ff83669SZhong Wang  */
8417ff83669SZhong Wang static void
fcoei_fill_els_fpkt_resp(fcoe_frame_t * frm,fcoei_exchange_t * xch,int size)8427ff83669SZhong Wang fcoei_fill_els_fpkt_resp(fcoe_frame_t *frm, fcoei_exchange_t *xch, int size)
8437ff83669SZhong Wang {
8447ff83669SZhong Wang 	uint8_t			*src	   = frm->frm_payload;
8457ff83669SZhong Wang 	uint8_t			*dest	   = (uint8_t *)xch->xch_fpkt->pkt_resp;
8467ff83669SZhong Wang 	ls_code_t		*els_code  = (ls_code_t *)(void *)dest;
8477ff83669SZhong Wang 	la_els_logi_t		*els_logi  = (la_els_logi_t *)(void *)dest;
8487ff83669SZhong Wang 	la_els_adisc_t		*els_adisc = (la_els_adisc_t *)(void *)dest;
8497ff83669SZhong Wang 	la_els_rls_acc_t	*els_rls;
8507ff83669SZhong Wang 	la_els_rnid_acc_t	*els_rnid;
8517ff83669SZhong Wang 	struct fcp_prli_acc	*prli_acc;
8527ff83669SZhong Wang 	int			 offset;
8537ff83669SZhong Wang 
8547ff83669SZhong Wang 	els_code->ls_code = FCOE_B2V_1(src);
8557ff83669SZhong Wang 	if (els_code->ls_code == LA_ELS_RJT) {
8567ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "size :%d", size);
8577ff83669SZhong Wang 		return;
8587ff83669SZhong Wang 	}
8597ff83669SZhong Wang 
8607ff83669SZhong Wang 	switch (((ls_code_t *)(void *)xch->xch_fpkt->pkt_cmd)->ls_code) {
8617ff83669SZhong Wang 	case LA_ELS_FLOGI:
8627ff83669SZhong Wang 		bcopy((char *)frm->frm_hdr - 22,
8637ff83669SZhong Wang 		    frm->frm_eport->eport_efh_dst, ETHERADDRL);
8647ff83669SZhong Wang 		if (frm->frm_payload[8] & 0x10) {
8657ff83669SZhong Wang 			/*
8667ff83669SZhong Wang 			 * We are in fabric p2p mode
8677ff83669SZhong Wang 			 */
8687ff83669SZhong Wang 			uint8_t src_addr[ETHERADDRL];
8697ff83669SZhong Wang 			frm->frm_eport->eport_flags &=
8707ff83669SZhong Wang 			    ~EPORT_FLAG_IS_DIRECT_P2P;
8717ff83669SZhong Wang 			FCOE_SET_DEFAULT_OUI(src_addr);
8727ff83669SZhong Wang 			bcopy(frm->frm_hdr->hdr_d_id, src_addr + 3, 3);
8737ff83669SZhong Wang 			frm->frm_eport->eport_set_mac_address(
8747ff83669SZhong Wang 			    frm->frm_eport, src_addr, 1);
8757ff83669SZhong Wang 		} else {
8767ff83669SZhong Wang 			/*
8777ff83669SZhong Wang 			 * We are in direct p2p mode
8787ff83669SZhong Wang 			 */
8797ff83669SZhong Wang 			frm->frm_eport->eport_flags |=
8807ff83669SZhong Wang 			    EPORT_FLAG_IS_DIRECT_P2P;
8817ff83669SZhong Wang 		}
8827ff83669SZhong Wang 
8837ff83669SZhong Wang 		if (!(FRM2SS(frm)->ss_eport->eport_flags &
8847ff83669SZhong Wang 		    EPORT_FLAG_IS_DIRECT_P2P)) {
8857ff83669SZhong Wang 			FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_D_ID(frm);
8867ff83669SZhong Wang 		}
8877ff83669SZhong Wang 
8887ff83669SZhong Wang 		/* FALLTHROUGH */
8897ff83669SZhong Wang 
8907ff83669SZhong Wang 	case LA_ELS_PLOGI:
8917ff83669SZhong Wang 		if (FRM2SS(frm)->ss_eport->eport_flags &
8927ff83669SZhong Wang 		    EPORT_FLAG_IS_DIRECT_P2P) {
8937ff83669SZhong Wang 			FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_D_ID(frm);
8947ff83669SZhong Wang 			FRM2SS(frm)->ss_p2p_info.d_id = FRM_S_ID(frm);
8957ff83669SZhong Wang 		}
8967ff83669SZhong Wang 
8977ff83669SZhong Wang 		offset = offsetof(la_els_logi_t, common_service);
8987ff83669SZhong Wang 		els_logi->common_service.fcph_version = FCOE_B2V_2(src +
8997ff83669SZhong Wang 		    offset);
9007ff83669SZhong Wang 		offset += 2;
9017ff83669SZhong Wang 		els_logi->common_service.btob_credit = FCOE_B2V_2(src +
9027ff83669SZhong Wang 		    offset);
9037ff83669SZhong Wang 		offset += 2;
9047ff83669SZhong Wang 		els_logi->common_service.cmn_features = FCOE_B2V_2(src +
9057ff83669SZhong Wang 		    offset);
9067ff83669SZhong Wang 		offset += 2;
9077ff83669SZhong Wang 		els_logi->common_service.rx_bufsize = FCOE_B2V_2(src +
9087ff83669SZhong Wang 		    offset);
9097ff83669SZhong Wang 		offset += 2;
9107ff83669SZhong Wang 		els_logi->common_service.conc_sequences = FCOE_B2V_2(src +
9117ff83669SZhong Wang 		    offset);
9127ff83669SZhong Wang 		offset += 2;
9137ff83669SZhong Wang 		els_logi->common_service.relative_offset = FCOE_B2V_2(src +
9147ff83669SZhong Wang 		    offset);
9157ff83669SZhong Wang 		offset += 2;
9167ff83669SZhong Wang 		els_logi->common_service.e_d_tov = FCOE_B2V_4(src +
9177ff83669SZhong Wang 		    offset);
9187ff83669SZhong Wang 
9197ff83669SZhong Wang 		/*
9207ff83669SZhong Wang 		 * port/node WWN
9217ff83669SZhong Wang 		 */
9227ff83669SZhong Wang 		offset = offsetof(la_els_logi_t, nport_ww_name);
9237ff83669SZhong Wang 		bcopy(src + offset, &els_logi->nport_ww_name, 8);
9247ff83669SZhong Wang 		offset = offsetof(la_els_logi_t, node_ww_name);
9257ff83669SZhong Wang 		bcopy(src + offset, &els_logi->node_ww_name, 8);
9267ff83669SZhong Wang 
9277ff83669SZhong Wang 		/*
9287ff83669SZhong Wang 		 * class_3
9297ff83669SZhong Wang 		 */
9307ff83669SZhong Wang 		offset = offsetof(la_els_logi_t, class_3);
9317ff83669SZhong Wang 		els_logi->class_3.class_opt = FCOE_B2V_2(src + offset);
9327ff83669SZhong Wang 		offset += 2;
9337ff83669SZhong Wang 		els_logi->class_3.initiator_ctl = FCOE_B2V_2(src + offset);
9347ff83669SZhong Wang 		offset += 2;
9357ff83669SZhong Wang 		els_logi->class_3.recipient_ctl = FCOE_B2V_2(src + offset);
9367ff83669SZhong Wang 		offset += 2;
9377ff83669SZhong Wang 		els_logi->class_3.rcv_size = FCOE_B2V_2(src + offset);
9387ff83669SZhong Wang 		offset += 2;
9397ff83669SZhong Wang 		els_logi->class_3.conc_sequences = FCOE_B2V_2(src + offset);
9407ff83669SZhong Wang 		offset += 2;
9417ff83669SZhong Wang 		els_logi->class_3.n_port_e_to_e_credit = FCOE_B2V_2(src +
9427ff83669SZhong Wang 		    offset);
9437ff83669SZhong Wang 		offset += 2;
9447ff83669SZhong Wang 		els_logi->class_3.open_seq_per_xchng = FCOE_B2V_2(src + offset);
9457ff83669SZhong Wang 
9467ff83669SZhong Wang 		break;
9477ff83669SZhong Wang 
9487ff83669SZhong Wang 	case LA_ELS_PRLI:
9497ff83669SZhong Wang 		/*
9507ff83669SZhong Wang 		 * PRLI service parameter response page
9517ff83669SZhong Wang 		 *
9527ff83669SZhong Wang 		 * fcp_prli_acc doesn't include ls_code, don't use offsetof
9537ff83669SZhong Wang 		 */
9547ff83669SZhong Wang 		offset = 4;
9557ff83669SZhong Wang 		prli_acc = (struct fcp_prli_acc *)(void *)(dest + offset);
9567ff83669SZhong Wang 		prli_acc->type = FCOE_B2V_1(src + offset);
9577ff83669SZhong Wang 		/*
9587ff83669SZhong Wang 		 * Type code extension
9597ff83669SZhong Wang 		 */
9607ff83669SZhong Wang 		offset += 1;
9617ff83669SZhong Wang 		/*
9627ff83669SZhong Wang 		 * PRLI response flags
9637ff83669SZhong Wang 		 */
9647ff83669SZhong Wang 		offset += 1;
9657ff83669SZhong Wang 		prli_acc->orig_process_assoc_valid =
9667ff83669SZhong Wang 		    (FCOE_B2V_2(src + offset) & BIT_15) ? 1 : 0;
9677ff83669SZhong Wang 		prli_acc->resp_process_assoc_valid =
9687ff83669SZhong Wang 		    (FCOE_B2V_2(src + offset) & BIT_14) ? 1 : 0;
9697ff83669SZhong Wang 		prli_acc->image_pair_established =
9707ff83669SZhong Wang 		    (FCOE_B2V_2(src + offset) & BIT_13) ? 1 : 0;
9717ff83669SZhong Wang 		prli_acc->accept_response_code =
9727386f431SRichard Lowe 		    (FCOE_B2V_2(src + offset) & 0x0F00) >> 8;
9737ff83669SZhong Wang 		/*
9747ff83669SZhong Wang 		 * process associator
9757ff83669SZhong Wang 		 */
9767ff83669SZhong Wang 		offset += 2;
9777ff83669SZhong Wang 		prli_acc->orig_process_associator = FCOE_B2V_4(src + offset);
9787ff83669SZhong Wang 		offset += 4;
9797ff83669SZhong Wang 		prli_acc->resp_process_associator = FCOE_B2V_4(src + offset);
9807ff83669SZhong Wang 		/*
9817ff83669SZhong Wang 		 * FC-4 type
9827ff83669SZhong Wang 		 */
9837ff83669SZhong Wang 		offset += 4;
9847ff83669SZhong Wang 		prli_acc->initiator_fn =
9857ff83669SZhong Wang 		    (FCOE_B2V_4(src + offset) & BIT_5) ? 1 : 0;
9867ff83669SZhong Wang 		prli_acc->target_fn =
9877ff83669SZhong Wang 		    (FCOE_B2V_4(src + offset) & BIT_4) ? 1 : 0;
9887ff83669SZhong Wang 		prli_acc->cmd_data_mixed =
9897ff83669SZhong Wang 		    (FCOE_B2V_4(src + offset) & BIT_3) ? 1 : 0;
9907ff83669SZhong Wang 		prli_acc->data_resp_mixed =
9917ff83669SZhong Wang 		    (FCOE_B2V_4(src + offset) & BIT_2) ? 1 : 0;
9927ff83669SZhong Wang 		prli_acc->read_xfer_rdy_disabled =
9937ff83669SZhong Wang 		    (FCOE_B2V_4(src + offset) & BIT_1) ? 1 : 0;
9947ff83669SZhong Wang 		prli_acc->write_xfer_rdy_disabled =
9957ff83669SZhong Wang 		    (FCOE_B2V_4(src + offset) & BIT_0) ? 1 : 0;
9967ff83669SZhong Wang 
9977ff83669SZhong Wang 		break;
9987ff83669SZhong Wang 
9997ff83669SZhong Wang 	case LA_ELS_LOGO:
10007ff83669SZhong Wang 		/*
10017ff83669SZhong Wang 		 * could only be LS_ACC, no additional information
10027ff83669SZhong Wang 		 */
10037ff83669SZhong Wang 		els_code->ls_code = FCOE_B2V_1(src);
10047ff83669SZhong Wang 		break;
10057ff83669SZhong Wang 
10067ff83669SZhong Wang 	case LA_ELS_SCR:
10077ff83669SZhong Wang 		/*
10087ff83669SZhong Wang 		 * LS_ACC/LS_RJT, no additional information
10097ff83669SZhong Wang 		 */
10107ff83669SZhong Wang 		els_code->ls_code = FCOE_B2V_1(src);
10117ff83669SZhong Wang 		break;
10127ff83669SZhong Wang 
10137ff83669SZhong Wang 	case LA_ELS_ADISC:
10147ff83669SZhong Wang 		offset = 5;
10157ff83669SZhong Wang 		els_adisc->hard_addr.hard_addr = FCOE_B2V_3(src + offset);
10167ff83669SZhong Wang 		offset = offsetof(la_els_adisc_t, port_wwn);
10177ff83669SZhong Wang 		bcopy(src + offset, &els_adisc->port_wwn, 8);
10187ff83669SZhong Wang 		offset = offsetof(la_els_adisc_t, node_wwn);
10197ff83669SZhong Wang 		bcopy(src + offset, &els_adisc->node_wwn, 8);
10207ff83669SZhong Wang 		offset += 9;
10217ff83669SZhong Wang 		els_adisc->nport_id.port_id = FCOE_B2V_3(src + offset);
10227ff83669SZhong Wang 		break;
10237ff83669SZhong Wang 	case LA_ELS_RLS:
10247ff83669SZhong Wang 		els_rls = (la_els_rls_acc_t *)(void *)dest;
10257ff83669SZhong Wang 		els_rls->ls_code.ls_code = FCOE_B2V_1(src);
10267ff83669SZhong Wang 		offset = 4;
10277ff83669SZhong Wang 		els_rls->rls_link_params.rls_link_fail =
10287ff83669SZhong Wang 		    FCOE_B2V_4(src + offset);
10297ff83669SZhong Wang 		offset = 8;
10307ff83669SZhong Wang 		els_rls->rls_link_params.rls_sync_loss =
10317ff83669SZhong Wang 		    FCOE_B2V_4(src + offset);
10327ff83669SZhong Wang 		offset = 12;
10337ff83669SZhong Wang 		els_rls->rls_link_params.rls_sig_loss =
10347ff83669SZhong Wang 		    FCOE_B2V_4(src + offset);
10357ff83669SZhong Wang 		offset = 16;
10367ff83669SZhong Wang 		els_rls->rls_link_params.rls_prim_seq_err =
10377ff83669SZhong Wang 		    FCOE_B2V_4(src + offset);
10387ff83669SZhong Wang 		offset = 20;
10397ff83669SZhong Wang 		els_rls->rls_link_params.rls_invalid_word =
10407ff83669SZhong Wang 		    FCOE_B2V_4(src + offset);
10417ff83669SZhong Wang 		offset = 24;
10427ff83669SZhong Wang 		els_rls->rls_link_params.rls_invalid_crc =
10437ff83669SZhong Wang 		    FCOE_B2V_4(src + offset);
10447ff83669SZhong Wang 		break;
10457ff83669SZhong Wang 	case LA_ELS_RNID:
10467ff83669SZhong Wang 		els_rnid = (la_els_rnid_acc_t *)(void *)dest;
10477ff83669SZhong Wang 		els_rnid->ls_code.ls_code = FCOE_B2V_1(src);
10487ff83669SZhong Wang 		offset = 4;
10497ff83669SZhong Wang 		bcopy(src + offset, &els_rnid->hdr.data_format, 1);
10507ff83669SZhong Wang 		offset = 5;
10517ff83669SZhong Wang 		bcopy(src + offset, &els_rnid->hdr.cmn_len, 1);
10527ff83669SZhong Wang 		offset = 7;
10537ff83669SZhong Wang 		bcopy(src + offset, &els_rnid->hdr.specific_len, 1);
10547ff83669SZhong Wang 		offset = 8;
10557ff83669SZhong Wang 		bcopy(src + offset, els_rnid->data, FCIO_RNID_MAX_DATA_LEN);
10567ff83669SZhong Wang 		break;
10577ff83669SZhong Wang 	default:
10587ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "unsupported R_CTL");
10597ff83669SZhong Wang 		break;
10607ff83669SZhong Wang 	}
10617ff83669SZhong Wang }
10627ff83669SZhong Wang 
10637ff83669SZhong Wang /*
10647ff83669SZhong Wang  * fcoei_fill_fcp_resp
10657ff83669SZhong Wang  *	Fill fpkt FCP response in host format according to frm payload
10667ff83669SZhong Wang  *
10677ff83669SZhong Wang  * Input:
10687ff83669SZhong Wang  *	src - frm payload in link format
10697ff83669SZhong Wang  *	dest - fpkt FCP response in host format
10707ff83669SZhong Wang  *	size - Maximum conversion size
10717ff83669SZhong Wang  *
10727ff83669SZhong Wang  * Returns:
10737ff83669SZhong Wang  *	N/A
10747ff83669SZhong Wang  *
10757ff83669SZhong Wang  * Comments:
10767ff83669SZhong Wang  *	This is called only for SCSI response with non good status
10777ff83669SZhong Wang  */
10787ff83669SZhong Wang static void
fcoei_fill_fcp_resp(uint8_t * src,uint8_t * dest,int size)10797ff83669SZhong Wang fcoei_fill_fcp_resp(uint8_t *src, uint8_t *dest, int size)
10807ff83669SZhong Wang {
10817ff83669SZhong Wang 	fcp_rsp_t	*fcp_rsp_iu = (fcp_rsp_t *)(void *)dest;
10827ff83669SZhong Wang 	int		 offset;
10837ff83669SZhong Wang 
10847ff83669SZhong Wang 	/*
10857ff83669SZhong Wang 	 * set fcp_status
10867ff83669SZhong Wang 	 */
10877ff83669SZhong Wang 	offset = offsetof(fcp_rsp_t, fcp_u);
10887ff83669SZhong Wang 	offset += 2;
10897ff83669SZhong Wang 	fcp_rsp_iu->fcp_u.fcp_status.resid_under =
10907ff83669SZhong Wang 	    (FCOE_B2V_1(src + offset) & BIT_3) ? 1 : 0;
10917ff83669SZhong Wang 	fcp_rsp_iu->fcp_u.fcp_status.resid_over =
10927ff83669SZhong Wang 	    (FCOE_B2V_1(src + offset) & BIT_2) ? 1 : 0;
10937ff83669SZhong Wang 	fcp_rsp_iu->fcp_u.fcp_status.sense_len_set =
10947ff83669SZhong Wang 	    (FCOE_B2V_1(src + offset) & BIT_1) ? 1 : 0;
10957ff83669SZhong Wang 	fcp_rsp_iu->fcp_u.fcp_status.rsp_len_set =
10967ff83669SZhong Wang 	    (FCOE_B2V_1(src + offset) & BIT_0) ? 1 : 0;
10977ff83669SZhong Wang 	offset += 1;
10987ff83669SZhong Wang 	fcp_rsp_iu->fcp_u.fcp_status.scsi_status = FCOE_B2V_1(src + offset);
10997ff83669SZhong Wang 	/*
11007ff83669SZhong Wang 	 * fcp_resid/fcp_sense_len/fcp_response_len
11017ff83669SZhong Wang 	 */
11027ff83669SZhong Wang 	offset = offsetof(fcp_rsp_t, fcp_resid);
11037ff83669SZhong Wang 	fcp_rsp_iu->fcp_resid = FCOE_B2V_4(src + offset);
11047ff83669SZhong Wang 	offset = offsetof(fcp_rsp_t, fcp_sense_len);
11057ff83669SZhong Wang 	fcp_rsp_iu->fcp_sense_len = FCOE_B2V_4(src + offset);
11067ff83669SZhong Wang 	offset = offsetof(fcp_rsp_t, fcp_response_len);
11077ff83669SZhong Wang 	fcp_rsp_iu->fcp_response_len = FCOE_B2V_4(src + offset);
11087ff83669SZhong Wang 	/*
11097ff83669SZhong Wang 	 * sense or response
11107ff83669SZhong Wang 	 */
11117ff83669SZhong Wang 	offset += 4;
11127ff83669SZhong Wang 	if (fcp_rsp_iu->fcp_sense_len) {
11137ff83669SZhong Wang 		if ((offset + fcp_rsp_iu->fcp_sense_len) > size) {
11147ff83669SZhong Wang 			FCOEI_LOG(__FUNCTION__, "buffer too small - sens");
11157ff83669SZhong Wang 			return;
11167ff83669SZhong Wang 		}
11177ff83669SZhong Wang 		bcopy(src + offset, dest + offset, fcp_rsp_iu->fcp_sense_len);
11187ff83669SZhong Wang 		offset += fcp_rsp_iu->fcp_sense_len;
11197ff83669SZhong Wang 	}
11207ff83669SZhong Wang 
11217ff83669SZhong Wang 	if (fcp_rsp_iu->fcp_response_len) {
11227ff83669SZhong Wang 		if ((offset + fcp_rsp_iu->fcp_response_len) > size) {
11237ff83669SZhong Wang 			FCOEI_LOG(__FUNCTION__, "buffer too small - resp");
11247ff83669SZhong Wang 			return;
11257ff83669SZhong Wang 		}
11267ff83669SZhong Wang 		bcopy(src + offset, dest + offset,
11277ff83669SZhong Wang 		    fcp_rsp_iu->fcp_response_len);
11287ff83669SZhong Wang 	}
11297ff83669SZhong Wang }
11307ff83669SZhong Wang 
11317ff83669SZhong Wang void
fcoei_init_ect_vectors(fcoe_client_t * ect)11327ff83669SZhong Wang fcoei_init_ect_vectors(fcoe_client_t *ect)
11337ff83669SZhong Wang {
11347ff83669SZhong Wang 	ect->ect_rx_frame	   = fcoei_rx_frame;
11357ff83669SZhong Wang 	ect->ect_port_event	   = fcoei_port_event;
11367ff83669SZhong Wang 	ect->ect_release_sol_frame = fcoei_release_sol_frame;
11377ff83669SZhong Wang }
11387ff83669SZhong Wang 
11397ff83669SZhong Wang /*
11407ff83669SZhong Wang  * fcoei_process_unsol_frame
11417ff83669SZhong Wang  *	Unsolicited frame is received
11427ff83669SZhong Wang  *
11437ff83669SZhong Wang  * Input:
11447ff83669SZhong Wang  *	frame = unsolicited frame that is received
11457ff83669SZhong Wang  *
11467ff83669SZhong Wang  * Returns:
11477ff83669SZhong Wang  *	N/A
11487ff83669SZhong Wang  *
11497ff83669SZhong Wang  * Comments:
11507ff83669SZhong Wang  *	watchdog will call this to process unsolicited frames that we
11517ff83669SZhong Wang  *	just received fcoei_process_xx is used to handle different
11527ff83669SZhong Wang  *	unsolicited frames
11537ff83669SZhong Wang  */
11547ff83669SZhong Wang void
fcoei_process_unsol_frame(fcoe_frame_t * frm)11557ff83669SZhong Wang fcoei_process_unsol_frame(fcoe_frame_t *frm)
11567ff83669SZhong Wang {
11577ff83669SZhong Wang 	fcoei_exchange_t	*xch;
11587ff83669SZhong Wang 	uint16_t		 sol_oxid;
11597ff83669SZhong Wang 
11607ff83669SZhong Wang 	switch (FRM_R_CTL(frm)) {
11617ff83669SZhong Wang 	case R_CTL_SOLICITED_DATA:
11627ff83669SZhong Wang 		/*
11637ff83669SZhong Wang 		 * READ data phase frame
11647ff83669SZhong Wang 		 * Find the associated exchange
11657ff83669SZhong Wang 		 */
11667ff83669SZhong Wang 		sol_oxid = FRM_OXID(frm);
11677ff83669SZhong Wang 		if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
11687ff83669SZhong Wang 		    FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
11697ff83669SZhong Wang 			PRT_FRM_HDR(__FUNCTION__, frm);
11707ff83669SZhong Wang 			FCOEI_LOG(__FUNCTION__, "associated xch not found: "
11717ff83669SZhong Wang 			    "oxid/%x %lu - %lu", sol_oxid,
11727ff83669SZhong Wang 			    CURRENT_CLOCK, frm->frm_clock);
11737ff83669SZhong Wang 			break;
11747ff83669SZhong Wang 		}
11757ff83669SZhong Wang 
11767ff83669SZhong Wang 		/*
11777ff83669SZhong Wang 		 * Copy data into fpkt data buffer, and update the counter
11787ff83669SZhong Wang 		 */
11797ff83669SZhong Wang 		bcopy(frm->frm_payload, (uint8_t *)xch->xch_fpkt->pkt_data +
11807ff83669SZhong Wang 		    FRM_PARAM(frm), frm->frm_payload_size);
11817ff83669SZhong Wang 		xch->xch_resid -= frm->frm_payload_size;
11827ff83669SZhong Wang 		xch->xch_rxid = FRM_RXID(frm);
11837ff83669SZhong Wang 		break;
11847ff83669SZhong Wang 
11857ff83669SZhong Wang 	case R_CTL_XFER_RDY:
11867ff83669SZhong Wang 		fcoei_process_unsol_xfer_rdy(frm);
11877ff83669SZhong Wang 		break;
11887ff83669SZhong Wang 
11897ff83669SZhong Wang 	case R_CTL_STATUS:
11907ff83669SZhong Wang 		fcoei_process_sol_fcp_resp(frm);
11917ff83669SZhong Wang 		break;
11927ff83669SZhong Wang 
11937ff83669SZhong Wang 	case R_CTL_ELS_REQ:
11947ff83669SZhong Wang 		fcoei_process_unsol_els_req(frm);
11957ff83669SZhong Wang 		break;
11967ff83669SZhong Wang 
11977ff83669SZhong Wang 	case R_CTL_LS_ABTS:
11987ff83669SZhong Wang 		fcoei_process_unsol_abts_req(frm);
11997ff83669SZhong Wang 		break;
12007ff83669SZhong Wang 
12017ff83669SZhong Wang 	case R_CTL_ELS_RSP:
12027ff83669SZhong Wang 		fcoei_process_sol_els_rsp(frm);
12037ff83669SZhong Wang 		break;
12047ff83669SZhong Wang 
12057ff83669SZhong Wang 	case R_CTL_SOLICITED_CONTROL:
12067ff83669SZhong Wang 		fcoei_process_sol_ct_rsp(frm);
12077ff83669SZhong Wang 		break;
12087ff83669SZhong Wang 
12097ff83669SZhong Wang 	case R_CTL_LS_BA_ACC:
12107ff83669SZhong Wang 		fcoei_process_sol_abts_acc(frm);
12117ff83669SZhong Wang 		break;
12127ff83669SZhong Wang 
12137ff83669SZhong Wang 	case R_CTL_LS_BA_RJT:
12147ff83669SZhong Wang 		fcoei_process_sol_abts_rjt(frm);
12157ff83669SZhong Wang 		break;
12167ff83669SZhong Wang 
12177ff83669SZhong Wang 	default:
12187ff83669SZhong Wang 		/*
12197ff83669SZhong Wang 		 * Unsupported frame
12207ff83669SZhong Wang 		 */
12217ff83669SZhong Wang 		PRT_FRM_HDR("Unsupported unsol frame: ", frm);
12227ff83669SZhong Wang 	}
12237ff83669SZhong Wang 
12247ff83669SZhong Wang 	/*
12257ff83669SZhong Wang 	 * Release the frame and netb
12267ff83669SZhong Wang 	 */
12277ff83669SZhong Wang 	frm->frm_eport->eport_free_netb(frm->frm_netb);
12287ff83669SZhong Wang 	frm->frm_eport->eport_release_frame(frm);
12297ff83669SZhong Wang }
12307ff83669SZhong Wang 
12317ff83669SZhong Wang /*
12327ff83669SZhong Wang  * fcoei_handle_sol_frame_done
12337ff83669SZhong Wang  *	solicited frame is just sent out
12347ff83669SZhong Wang  *
12357ff83669SZhong Wang  * Input:
12367ff83669SZhong Wang  *	frame = solicited frame that has been sent out
12377ff83669SZhong Wang  *
12387ff83669SZhong Wang  * Returns:
12397ff83669SZhong Wang  *	N/A
12407ff83669SZhong Wang  *
12417ff83669SZhong Wang  * Comments:
12427ff83669SZhong Wang  *	watchdog will call this to handle solicited frames that FCOEI
12437ff83669SZhong Wang  *	has sent out Non-request frame post handling
12447ff83669SZhong Wang  */
12457ff83669SZhong Wang void
fcoei_handle_sol_frame_done(fcoe_frame_t * frm)12467ff83669SZhong Wang fcoei_handle_sol_frame_done(fcoe_frame_t *frm)
12477ff83669SZhong Wang {
12487ff83669SZhong Wang 	/*
12497ff83669SZhong Wang 	 * the corresponding xch could be NULL at this time
12507ff83669SZhong Wang 	 */
12517ff83669SZhong Wang 	fcoei_exchange_t	*xch  = FRM2IFM(frm)->ifm_xch;
12527ff83669SZhong Wang 
12537ff83669SZhong Wang 	switch (FRM2IFM(frm)->ifm_rctl) {
12547ff83669SZhong Wang 	case R_CTL_ELS_RSP:
12557ff83669SZhong Wang 		/*
12567ff83669SZhong Wang 		 * Complete it with frm as NULL
12577ff83669SZhong Wang 		 */
12587ff83669SZhong Wang 		fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0);
12597ff83669SZhong Wang 		break;
12607ff83669SZhong Wang 
12617ff83669SZhong Wang 	case R_CTL_LS_BA_ACC:
12627ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__,  "BA_ACC out: xch-%p, frm-%p",
12637ff83669SZhong Wang 		    xch, frm);
12647ff83669SZhong Wang 		PRT_FRM_HDR("LS_BA_ACC", frm);
12657ff83669SZhong Wang 		break;
12667ff83669SZhong Wang 
12677ff83669SZhong Wang 	case R_CTL_LS_BA_RJT:
12687ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__,  "BA_RJT out: xch-%p, frm-%p",
12697ff83669SZhong Wang 		    xch, frm);
12707ff83669SZhong Wang 		PRT_FRM_HDR("LS_BA_RJT", frm);
12717ff83669SZhong Wang 		break;
12727ff83669SZhong Wang 
12737ff83669SZhong Wang 	default:
12747ff83669SZhong Wang 		/*
12757ff83669SZhong Wang 		 * Unsupported frame
12767ff83669SZhong Wang 		 */
12777ff83669SZhong Wang 		PRT_FRM_HDR("Unsupported sol frame: ", frm);
12787ff83669SZhong Wang 	}
12797ff83669SZhong Wang 
12807ff83669SZhong Wang 	/*
12817ff83669SZhong Wang 	 * We should release only the frame, and we don't care its netb
12827ff83669SZhong Wang 	 */
12837ff83669SZhong Wang 	FRM2SS(frm)->ss_eport->eport_release_frame(frm);
12847ff83669SZhong Wang }
12857ff83669SZhong Wang 
12867ff83669SZhong Wang /*
12877ff83669SZhong Wang  * fcoei_port_event
12887ff83669SZhong Wang  *	link/port state changed
12897ff83669SZhong Wang  *
12907ff83669SZhong Wang  * Input:
12917ff83669SZhong Wang  *	eport = to indicate which port has changed
12927ff83669SZhong Wang  *	event = what change
12937ff83669SZhong Wang  *
12947ff83669SZhong Wang  * Returns:
12957ff83669SZhong Wang  *	N/A
12967ff83669SZhong Wang  *
12977ff83669SZhong Wang  * Comments:
12987ff83669SZhong Wang  *	refer fctl.h for ss_link_state value
12997ff83669SZhong Wang  */
13007ff83669SZhong Wang void
fcoei_port_event(fcoe_port_t * eport,uint32_t event)13017ff83669SZhong Wang fcoei_port_event(fcoe_port_t *eport, uint32_t event)
13027ff83669SZhong Wang {
13037ff83669SZhong Wang 	fcoei_event_t	*ae;
13047ff83669SZhong Wang 
13057ff83669SZhong Wang 	if (!(EPORT2SS(eport)->ss_flags & SS_FLAG_LV_BOUND)) {
13067ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "not bound now");
13077ff83669SZhong Wang 		return;
13087ff83669SZhong Wang 	}
13097ff83669SZhong Wang 
13107ff83669SZhong Wang 	mutex_enter(&EPORT2SS(eport)->ss_watchdog_mutex);
13117ff83669SZhong Wang 	switch (event) {
13127ff83669SZhong Wang 	case FCOE_NOTIFY_EPORT_LINK_DOWN:
13137ff83669SZhong Wang 		EPORT2SS(eport)->ss_link_state = FC_STATE_OFFLINE;
13147ff83669SZhong Wang 		cmn_err(CE_NOTE, "%02x%02x%02x%02x%02x%02x%02x%02x Link down",
13157ff83669SZhong Wang 		    eport->eport_portwwn[0], eport->eport_portwwn[1],
13167ff83669SZhong Wang 		    eport->eport_portwwn[2], eport->eport_portwwn[3],
13177ff83669SZhong Wang 		    eport->eport_portwwn[4], eport->eport_portwwn[5],
13187ff83669SZhong Wang 		    eport->eport_portwwn[6], eport->eport_portwwn[7]);
13197ff83669SZhong Wang 		break;
13207ff83669SZhong Wang 
13217ff83669SZhong Wang 	case FCOE_NOTIFY_EPORT_LINK_UP:
13227ff83669SZhong Wang 		if (eport->eport_mtu >= 2200) {
13237ff83669SZhong Wang 			EPORT2SS(eport)->ss_fcp_data_payload_size =
13247ff83669SZhong Wang 			    FCOE_DEFAULT_FCP_DATA_PAYLOAD_SIZE;
13257ff83669SZhong Wang 		} else {
13267ff83669SZhong Wang 			FCOEI_LOG(__FUNCTION__, "fcoei: MTU is not big enough. "
13277ff83669SZhong Wang 			    "we will use 1K frames in FCP data phase.");
13287ff83669SZhong Wang 			EPORT2SS(eport)->ss_fcp_data_payload_size =
13297ff83669SZhong Wang 			    FCOE_MIN_FCP_DATA_PAYLOAD_SIZE;
13307ff83669SZhong Wang 		}
13317ff83669SZhong Wang 
13327ff83669SZhong Wang 		cmn_err(CE_NOTE, "%02x%02x%02x%02x%02x%02x%02x%02x Link up",
13337ff83669SZhong Wang 		    eport->eport_portwwn[0], eport->eport_portwwn[1],
13347ff83669SZhong Wang 		    eport->eport_portwwn[2], eport->eport_portwwn[3],
13357ff83669SZhong Wang 		    eport->eport_portwwn[4], eport->eport_portwwn[5],
13367ff83669SZhong Wang 		    eport->eport_portwwn[6], eport->eport_portwwn[7]);
13377ff83669SZhong Wang 		EPORT2SS(eport)->ss_link_state = FC_STATE_ONLINE;
13387ff83669SZhong Wang 		break;
13397ff83669SZhong Wang 
13407ff83669SZhong Wang 	default:
13417ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "unsupported event");
13427ff83669SZhong Wang 		mutex_exit(&EPORT2SS(eport)->ss_watchdog_mutex);
13437ff83669SZhong Wang 
13447ff83669SZhong Wang 		return;
13457ff83669SZhong Wang 	}
13467ff83669SZhong Wang 
13477ff83669SZhong Wang 	EPORT2SS(eport)->ss_port_event_counter++;
13487ff83669SZhong Wang 	ae = (fcoei_event_t *)kmem_zalloc(sizeof (fcoei_event_t), KM_SLEEP);
13497ff83669SZhong Wang 	ae->ae_type = AE_EVENT_PORT;
13507ff83669SZhong Wang 	ae->ae_obj = EPORT2SS(eport);
13517ff83669SZhong Wang 	ae->ae_specific = EPORT2SS(eport)->ss_link_state;
13527ff83669SZhong Wang 	list_insert_tail(&EPORT2SS(eport)->ss_event_list, ae);
13537ff83669SZhong Wang 	mutex_exit(&EPORT2SS(eport)->ss_watchdog_mutex);
13547ff83669SZhong Wang }
13557ff83669SZhong Wang 
13567ff83669SZhong Wang /*
13577ff83669SZhong Wang  * fcoei_process_event_port
13587ff83669SZhong Wang  *	link/port state changed
13597ff83669SZhong Wang  *
13607ff83669SZhong Wang  * Input:
13617ff83669SZhong Wang  *	ae = link fcoei_event
13627ff83669SZhong Wang  *
13637ff83669SZhong Wang  * Returns:
13647ff83669SZhong Wang  *	N/A
13657ff83669SZhong Wang  *
13667ff83669SZhong Wang  * Comments:
13677ff83669SZhong Wang  *	asynchronous events from FCOE
13687ff83669SZhong Wang  */
13697ff83669SZhong Wang void
fcoei_process_event_port(fcoei_event_t * ae)13707ff83669SZhong Wang fcoei_process_event_port(fcoei_event_t *ae)
13717ff83669SZhong Wang {
13727ff83669SZhong Wang 	fcoei_soft_state_t	*ss = (fcoei_soft_state_t *)ae->ae_obj;
13737ff83669SZhong Wang 
13747ff83669SZhong Wang 	if (ss->ss_eport->eport_link_speed == FCOE_PORT_SPEED_1G) {
13757ff83669SZhong Wang 		ae->ae_specific |= FC_STATE_1GBIT_SPEED;
13767ff83669SZhong Wang 	} else if (ss->ss_eport->eport_link_speed ==
13777ff83669SZhong Wang 	    FCOE_PORT_SPEED_10G) {
13787ff83669SZhong Wang 		ae->ae_specific |= FC_STATE_10GBIT_SPEED;
13797ff83669SZhong Wang 	}
13807ff83669SZhong Wang 
13817ff83669SZhong Wang 	if (ss->ss_flags & SS_FLAG_LV_BOUND) {
13827ff83669SZhong Wang 		ss->ss_bind_info.port_statec_cb(ss->ss_port,
13837ff83669SZhong Wang 		    (uint32_t)ae->ae_specific);
13847ff83669SZhong Wang 	} else {
13857ff83669SZhong Wang 		FCOEI_LOG(__FUNCTION__, "ss %p not bound now", ss);
13867ff83669SZhong Wang 	}
13877ff83669SZhong Wang 
1388*1a5e258fSJosef 'Jeff' Sipek 	atomic_dec_32(&ss->ss_port_event_counter);
13897ff83669SZhong Wang 	kmem_free(ae, sizeof (fcoei_event_t));
13907ff83669SZhong Wang }
1391