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 /*
234558d122SViswanathan Kannappan  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
242a8164dfSZhong Wang  */
252a8164dfSZhong Wang 
262a8164dfSZhong Wang /*
272a8164dfSZhong Wang  * This file defines interfaces between fcoe and fct driver.
282a8164dfSZhong Wang  */
292a8164dfSZhong Wang 
302a8164dfSZhong Wang /*
312a8164dfSZhong Wang  * Driver kernel header files
322a8164dfSZhong Wang  */
332a8164dfSZhong Wang #include <sys/conf.h>
342a8164dfSZhong Wang #include <sys/ddi.h>
352a8164dfSZhong Wang #include <sys/stat.h>
362a8164dfSZhong Wang #include <sys/pci.h>
372a8164dfSZhong Wang #include <sys/sunddi.h>
382a8164dfSZhong Wang #include <sys/modctl.h>
392a8164dfSZhong Wang #include <sys/file.h>
402a8164dfSZhong Wang #include <sys/cred.h>
412a8164dfSZhong Wang #include <sys/byteorder.h>
422a8164dfSZhong Wang #include <sys/atomic.h>
432a8164dfSZhong Wang #include <sys/modhash.h>
442a8164dfSZhong Wang #include <sys/scsi/scsi.h>
452a8164dfSZhong Wang #include <sys/ethernet.h>
462a8164dfSZhong Wang 
472a8164dfSZhong Wang /*
482a8164dfSZhong Wang  * COMSTAR header files
492a8164dfSZhong Wang  */
502a8164dfSZhong Wang #include <sys/stmf_defines.h>
512a8164dfSZhong Wang #include <sys/fct_defines.h>
522a8164dfSZhong Wang #include <sys/stmf.h>
532a8164dfSZhong Wang #include <sys/portif.h>
542a8164dfSZhong Wang #include <sys/fct.h>
552a8164dfSZhong Wang 
562a8164dfSZhong Wang /*
572a8164dfSZhong Wang  * FCoE hader files
582a8164dfSZhong Wang  */
592a8164dfSZhong Wang #include <sys/fcoe/fcoe_common.h>
602a8164dfSZhong Wang 
612a8164dfSZhong Wang /*
622a8164dfSZhong Wang  * Driver's own header files
632a8164dfSZhong Wang  */
644558d122SViswanathan Kannappan #include "fcoet.h"
654558d122SViswanathan Kannappan #include "fcoet_fc.h"
664558d122SViswanathan Kannappan #include "fcoet_eth.h"
672a8164dfSZhong Wang 
682a8164dfSZhong Wang /*
692a8164dfSZhong Wang  * function forward declaration
702a8164dfSZhong Wang  */
712a8164dfSZhong Wang static fct_status_t fcoet_fill_plogi_req(fct_local_port_t *port,
722a8164dfSZhong Wang     fct_remote_port_t *rp, fct_cmd_t *login);
732a8164dfSZhong Wang static fct_status_t fcoet_fill_plogi_resp(fct_local_port_t *port,
742a8164dfSZhong Wang     fct_remote_port_t *rp, fct_cmd_t *login);
752a8164dfSZhong Wang static fct_status_t fcoet_send_sol_els(fct_cmd_t *cmd);
762a8164dfSZhong Wang static fct_status_t fcoet_send_sol_ct(fct_cmd_t *cmd);
772a8164dfSZhong Wang static fct_status_t fcoet_send_good_status(fct_cmd_t *cmd);
782a8164dfSZhong Wang static fct_status_t fcoet_send_els_response(fct_cmd_t *cmd);
792a8164dfSZhong Wang static fct_status_t fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags);
802a8164dfSZhong Wang static fct_status_t fcoet_logo_fabric(fcoet_soft_state_t *ss);
812a8164dfSZhong Wang 
822a8164dfSZhong Wang /*
832a8164dfSZhong Wang  * Return the lower link information
842a8164dfSZhong Wang  */
852a8164dfSZhong Wang fct_status_t
fcoet_get_link_info(fct_local_port_t * port,fct_link_info_t * li)862a8164dfSZhong Wang fcoet_get_link_info(fct_local_port_t *port, fct_link_info_t *li)
872a8164dfSZhong Wang {
882a8164dfSZhong Wang 	bcopy(&PORT2SS(port)->ss_link_info, li, sizeof (fct_link_info_t));
892a8164dfSZhong Wang 	return (FCT_SUCCESS);
902a8164dfSZhong Wang }
912a8164dfSZhong Wang 
922a8164dfSZhong Wang /*
932a8164dfSZhong Wang  * FCT will call this, when it wants to send PLOGI or has received PLOGI.
942a8164dfSZhong Wang  */
952a8164dfSZhong Wang fct_status_t
fcoet_register_remote_port(fct_local_port_t * port,fct_remote_port_t * rp,fct_cmd_t * login)962a8164dfSZhong Wang fcoet_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp,
972a8164dfSZhong Wang     fct_cmd_t *login)
982a8164dfSZhong Wang {
992a8164dfSZhong Wang 	uint16_t	handle;
1002a8164dfSZhong Wang 	fct_status_t	ret;
1012a8164dfSZhong Wang 
1022a8164dfSZhong Wang 	switch (rp->rp_id) {
1032a8164dfSZhong Wang 	case 0xFFFFFC:
1042a8164dfSZhong Wang 		handle = 0x7FC;
1052a8164dfSZhong Wang 		break;
1062a8164dfSZhong Wang 
1072a8164dfSZhong Wang 	case 0xFFFFFD:
1082a8164dfSZhong Wang 		handle = 0x7FD;
1092a8164dfSZhong Wang 		break;
1102a8164dfSZhong Wang 
1112a8164dfSZhong Wang 	case 0xFFFFFE:
1122a8164dfSZhong Wang 		handle = 0x7FE;
1132a8164dfSZhong Wang 		break;
1142a8164dfSZhong Wang 
1152a8164dfSZhong Wang 	case 0xFFFFFF:
1162a8164dfSZhong Wang 		handle = 0x7FF;
1172a8164dfSZhong Wang 		break;
1182a8164dfSZhong Wang 
1192a8164dfSZhong Wang 	default:
1202a8164dfSZhong Wang 		/*
1212a8164dfSZhong Wang 		 * For not well-known address, we let FCT to select one.
1222a8164dfSZhong Wang 		 */
1232a8164dfSZhong Wang 		handle = FCT_HANDLE_NONE;
1242a8164dfSZhong Wang 		break;
1252a8164dfSZhong Wang 	}
1262a8164dfSZhong Wang 
1272a8164dfSZhong Wang 	rp->rp_handle = handle;
1282a8164dfSZhong Wang 	if (login->cmd_type == FCT_CMD_SOL_ELS) {
1292a8164dfSZhong Wang 		ret = fcoet_fill_plogi_req(port, rp, login);
1302a8164dfSZhong Wang 	} else {
1312a8164dfSZhong Wang 		ret = fcoet_fill_plogi_resp(port, rp, login);
1322a8164dfSZhong Wang 	}
1332a8164dfSZhong Wang 
1342a8164dfSZhong Wang 	return (ret);
1352a8164dfSZhong Wang }
1362a8164dfSZhong Wang 
1372a8164dfSZhong Wang /*
1382a8164dfSZhong Wang  * FCT will call this to say "FCoET can release resources with this RP now."
1392a8164dfSZhong Wang  */
1402a8164dfSZhong Wang /* ARGSUSED */
1412a8164dfSZhong Wang fct_status_t
fcoet_deregister_remote_port(fct_local_port_t * port,fct_remote_port_t * rp)1422a8164dfSZhong Wang fcoet_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp)
1432a8164dfSZhong Wang {
1442a8164dfSZhong Wang 	fcoet_soft_state_t	*this_ss = PORT2SS(port);
1452a8164dfSZhong Wang 
1462a8164dfSZhong Wang 	this_ss->ss_rport_dereg_state = 0;
1472a8164dfSZhong Wang 	this_ss->ss_rportid_in_dereg = 0;
1482a8164dfSZhong Wang 	return (FCT_SUCCESS);
1492a8164dfSZhong Wang }
1502a8164dfSZhong Wang 
1512a8164dfSZhong Wang fct_status_t
fcoet_send_cmd(fct_cmd_t * cmd)1522a8164dfSZhong Wang fcoet_send_cmd(fct_cmd_t *cmd)
1532a8164dfSZhong Wang {
1542a8164dfSZhong Wang 	if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
1552a8164dfSZhong Wang 		return (fcoet_send_sol_els(cmd));
1562a8164dfSZhong Wang 	} else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
1572a8164dfSZhong Wang 		return (fcoet_send_sol_ct(cmd));
1582a8164dfSZhong Wang 	}
1592a8164dfSZhong Wang 
1602a8164dfSZhong Wang 	return (FCT_FAILURE);
1612a8164dfSZhong Wang }
1622a8164dfSZhong Wang 
1632a8164dfSZhong Wang /*
1642a8164dfSZhong Wang  * SCSI response phase
1652a8164dfSZhong Wang  * ELS_ACC/ELS_RJT
1662a8164dfSZhong Wang  */
1672a8164dfSZhong Wang fct_status_t
fcoet_send_cmd_response(fct_cmd_t * cmd,uint32_t ioflags)1682a8164dfSZhong Wang fcoet_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags)
1692a8164dfSZhong Wang {
1704558d122SViswanathan Kannappan 	char	info[FCT_INFO_LEN];
1712a8164dfSZhong Wang 
1722a8164dfSZhong Wang 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
1732a8164dfSZhong Wang 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1742a8164dfSZhong Wang 			goto send_cmd_rsp_error;
1752a8164dfSZhong Wang 		} else {
1762a8164dfSZhong Wang 			return (fcoet_send_status(cmd));
1772a8164dfSZhong Wang 		}
1782a8164dfSZhong Wang 	}
1792a8164dfSZhong Wang 
1802a8164dfSZhong Wang 	if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
1812a8164dfSZhong Wang 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1822a8164dfSZhong Wang 			goto send_cmd_rsp_error;
1832a8164dfSZhong Wang 		} else {
1842a8164dfSZhong Wang 			return (fcoet_send_els_response(cmd));
1852a8164dfSZhong Wang 		}
1862a8164dfSZhong Wang 	}
1872a8164dfSZhong Wang 
1882a8164dfSZhong Wang 	if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1892a8164dfSZhong Wang 		cmd->cmd_handle = 0;
1902a8164dfSZhong Wang 	}
1912a8164dfSZhong Wang 
1922a8164dfSZhong Wang 	if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) {
1932a8164dfSZhong Wang 		return (fcoet_send_abts_response(cmd, 0));
1942a8164dfSZhong Wang 	} else {
1952a8164dfSZhong Wang 		ASSERT(0);
1962a8164dfSZhong Wang 		return (FCT_FAILURE);
1972a8164dfSZhong Wang 	}
1982a8164dfSZhong Wang 
1992a8164dfSZhong Wang send_cmd_rsp_error:
2004558d122SViswanathan Kannappan 	(void) snprintf(info, sizeof (info), "fcoet_send_cmd_response: can not "
2014558d122SViswanathan Kannappan 	    "handle FCT_IOF_FORCE_FCA_DONE for cmd %p, ioflags-%x", (void *)cmd,
202ef4cb712SZhong Wang 	    ioflags);
2032a8164dfSZhong Wang 	(void) fct_port_shutdown(CMD2SS(cmd)->ss_port,
2042a8164dfSZhong Wang 	    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2052a8164dfSZhong Wang 	return (FCT_FAILURE);
2062a8164dfSZhong Wang }
2072a8164dfSZhong Wang 
2082a8164dfSZhong Wang /*
2092a8164dfSZhong Wang  * It's for read/write (xfer_rdy)
2102a8164dfSZhong Wang  */
2112a8164dfSZhong Wang /* ARGSUSED */
2122a8164dfSZhong Wang fct_status_t
fcoet_xfer_scsi_data(fct_cmd_t * cmd,stmf_data_buf_t * dbuf,uint32_t ioflags)2132a8164dfSZhong Wang fcoet_xfer_scsi_data(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags)
2142a8164dfSZhong Wang {
2152a8164dfSZhong Wang 	fcoe_frame_t	*frm;
2162a8164dfSZhong Wang 	int		 idx;
2172a8164dfSZhong Wang 	int		 frm_num;
2182a8164dfSZhong Wang 	int		 data_size;
2192a8164dfSZhong Wang 	int		 left_size;
2202a8164dfSZhong Wang 	int		 offset;
2212a8164dfSZhong Wang 	fcoet_exchange_t *xch = CMD2XCH(cmd);
2222a8164dfSZhong Wang 
2232a8164dfSZhong Wang 	ASSERT(!xch->xch_dbufs[dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN]);
2242a8164dfSZhong Wang 	xch->xch_dbufs[dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN] = dbuf;
2252a8164dfSZhong Wang 
2262a8164dfSZhong Wang 	left_size = (int)dbuf->db_data_size;
2272a8164dfSZhong Wang 	if (dbuf->db_relative_offset == 0)
2282a8164dfSZhong Wang 		xch->xch_left_data_size =
2292a8164dfSZhong Wang 		    XCH2TASK(xch)->task_expected_xfer_length;
2302a8164dfSZhong Wang 
231516aa12cSYu Renia Miao 	if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) {
2322a8164dfSZhong Wang 		/*
2332a8164dfSZhong Wang 		 * If it's write type command, we need send xfer_rdy now
2342a8164dfSZhong Wang 		 * We may need to consider bidirectional command later
2352a8164dfSZhong Wang 		 */
2367ff83669SZhong Wang 		dbuf->db_sglist_length = 0;
2372a8164dfSZhong Wang 		frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(
2382a8164dfSZhong Wang 		    CMD2SS(cmd)->ss_eport, sizeof (fcoe_fcp_xfer_rdy_t) +
2392a8164dfSZhong Wang 		    FCFH_SIZE, NULL);
2402a8164dfSZhong Wang 		if (frm == NULL) {
2412a8164dfSZhong Wang 			ASSERT(0);
2422a8164dfSZhong Wang 			return (FCT_FAILURE);
2432a8164dfSZhong Wang 		} else {
2442a8164dfSZhong Wang 			fcoet_init_tfm(frm, CMD2XCH(cmd));
2452a8164dfSZhong Wang 			bzero(frm->frm_payload, frm->frm_payload_size);
2462a8164dfSZhong Wang 		}
2472a8164dfSZhong Wang 
2482a8164dfSZhong Wang 		FFM_R_CTL(0x05, frm);
2492a8164dfSZhong Wang 		FRM2TFM(frm)->tfm_rctl = 0x05;
2502a8164dfSZhong Wang 		FFM_TYPE(0x08, frm);
2512a8164dfSZhong Wang 		FFM_F_CTL(0x890000, frm);
2522a8164dfSZhong Wang 		FFM_OXID(cmd->cmd_oxid, frm);
2532a8164dfSZhong Wang 		FFM_RXID(cmd->cmd_rxid, frm);
2542a8164dfSZhong Wang 		FFM_S_ID(cmd->cmd_lportid, frm);
2552a8164dfSZhong Wang 		FFM_D_ID(cmd->cmd_rportid, frm);
2562a8164dfSZhong Wang 		FCOE_V2B_4(dbuf->db_relative_offset, frm->frm_payload);
2572a8164dfSZhong Wang 		FCOE_V2B_4(dbuf->db_data_size, frm->frm_payload + 4);
2582a8164dfSZhong Wang 		CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
2592a8164dfSZhong Wang 
2602a8164dfSZhong Wang 		return (FCT_SUCCESS);
2612a8164dfSZhong Wang 	}
2622a8164dfSZhong Wang 
2632a8164dfSZhong Wang 	/*
2642a8164dfSZhong Wang 	 * It's time to transfer READ data to remote side
2652a8164dfSZhong Wang 	 */
2662a8164dfSZhong Wang 	frm_num = (dbuf->db_data_size + CMD2SS(cmd)->ss_fcp_data_payload_size -
2672a8164dfSZhong Wang 	    1) / CMD2SS(cmd)->ss_fcp_data_payload_size;
2682a8164dfSZhong Wang 	offset = dbuf->db_relative_offset;
2692a8164dfSZhong Wang 	for (idx = 0; idx < frm_num; idx++) {
2702a8164dfSZhong Wang 		if (idx == (frm_num -1)) {
2712a8164dfSZhong Wang 			data_size = P2ROUNDUP(left_size, 4);
2722a8164dfSZhong Wang 		} else {
2732a8164dfSZhong Wang 			data_size = CMD2SS(cmd)->ss_fcp_data_payload_size;
2742a8164dfSZhong Wang 		}
2752a8164dfSZhong Wang 
2762a8164dfSZhong Wang 		frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(
2772a8164dfSZhong Wang 		    CMD2SS(cmd)->ss_eport, data_size + FCFH_SIZE,
2782a8164dfSZhong Wang 		    FCOET_GET_NETB(dbuf, idx));
2792a8164dfSZhong Wang 		if (frm == NULL) {
2802a8164dfSZhong Wang 			ASSERT(0);
2812a8164dfSZhong Wang 			return (FCT_FAILURE);
2822a8164dfSZhong Wang 		} else {
2832a8164dfSZhong Wang 			fcoet_init_tfm(frm, CMD2XCH(cmd));
2842a8164dfSZhong Wang 			/*
2852a8164dfSZhong Wang 			 * lock the xchg to avoid being released (by abort)
2862a8164dfSZhong Wang 			 * after sent out and before release
2872a8164dfSZhong Wang 			 */
2882a8164dfSZhong Wang 			FCOET_BUSY_XCHG(CMD2XCH(cmd));
2892a8164dfSZhong Wang 		}
2902a8164dfSZhong Wang 
2912a8164dfSZhong Wang 		FFM_R_CTL(0x01, frm);
2922a8164dfSZhong Wang 		FRM2TFM(frm)->tfm_rctl = 0x01;
2932a8164dfSZhong Wang 		FRM2TFM(frm)->tfm_buf_idx =
2942a8164dfSZhong Wang 		    dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN;
2952a8164dfSZhong Wang 		FFM_TYPE(0x08, frm);
2962a8164dfSZhong Wang 		if (idx != frm_num - 1) {
2972a8164dfSZhong Wang 			FFM_F_CTL(0x800008, frm);
2982a8164dfSZhong Wang 		} else {
299fd465b4eSKevin Yu 			FFM_F_CTL(0x880008 | (data_size - left_size), frm);
3002a8164dfSZhong Wang 		}
3012a8164dfSZhong Wang 
3022a8164dfSZhong Wang 		FFM_OXID(cmd->cmd_oxid, frm);
3032a8164dfSZhong Wang 		FFM_RXID(cmd->cmd_rxid, frm);
3042a8164dfSZhong Wang 		FFM_S_ID(cmd->cmd_lportid, frm);
3052a8164dfSZhong Wang 		FFM_D_ID(cmd->cmd_rportid, frm);
3062a8164dfSZhong Wang 		FFM_SEQ_CNT(xch->xch_sequence_no, frm);
3071a5e258fSJosef 'Jeff' Sipek 		atomic_inc_8(&xch->xch_sequence_no);
3082a8164dfSZhong Wang 		FFM_PARAM(offset, frm);
3092a8164dfSZhong Wang 		offset += data_size;
3102a8164dfSZhong Wang 		left_size -= data_size;
3112a8164dfSZhong Wang 
3122a8164dfSZhong Wang 		/*
3132a8164dfSZhong Wang 		 * Disassociate netbs which will be freed by NIC driver
3142a8164dfSZhong Wang 		 */
3152a8164dfSZhong Wang 		FCOET_SET_NETB(dbuf, idx, NULL);
3162a8164dfSZhong Wang 
3172a8164dfSZhong Wang 		CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
3182a8164dfSZhong Wang 	}
3192a8164dfSZhong Wang 
3202a8164dfSZhong Wang 	return (FCT_SUCCESS);
3212a8164dfSZhong Wang }
3222a8164dfSZhong Wang 
3232a8164dfSZhong Wang fct_status_t
fcoet_abort_cmd(struct fct_local_port * port,fct_cmd_t * cmd,uint32_t flags)3242a8164dfSZhong Wang fcoet_abort_cmd(struct fct_local_port *port, fct_cmd_t *cmd, uint32_t flags)
3252a8164dfSZhong Wang {
3262a8164dfSZhong Wang 	fcoet_soft_state_t	*this_ss = PORT2SS(port);
3272a8164dfSZhong Wang 	fct_status_t		 fct_ret = FCT_SUCCESS;
3282a8164dfSZhong Wang 
3292a8164dfSZhong Wang 	FCOET_LOG("fcoet_abort_cmd", "cmd=%p, xch=%p, cmd_specific=%p",
3302a8164dfSZhong Wang 	    cmd, cmd->cmd_fca_private, cmd->cmd_specific);
3312a8164dfSZhong Wang 	switch (cmd->cmd_type) {
3322a8164dfSZhong Wang 	case FCT_CMD_RCVD_ABTS:
3332a8164dfSZhong Wang 		/*
3342a8164dfSZhong Wang 		 * Sometimes unsolicited ABTS request will be received twice
3352a8164dfSZhong Wang 		 * and the first ABTS is not done yet, so the second ABTS
3362a8164dfSZhong Wang 		 * will be passed down here, in this case we will do
3372a8164dfSZhong Wang 		 * nothing and abts response is not needed to be sent
3382a8164dfSZhong Wang 		 * fct_ret = fcoet_send_abts_response(cmd, 1);
3392a8164dfSZhong Wang 		 */
3402a8164dfSZhong Wang 		break;
3412a8164dfSZhong Wang 	case FCT_CMD_FCP_XCHG:
3422a8164dfSZhong Wang 	case FCT_CMD_RCVD_ELS:
3432a8164dfSZhong Wang 		if (CMD2XCH(cmd)->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
3442a8164dfSZhong Wang 			break;
3452a8164dfSZhong Wang 		}
3462a8164dfSZhong Wang 
3472a8164dfSZhong Wang 		CMD2XCH(cmd)->xch_flags |= XCH_FLAG_FCT_CALLED_ABORT;
3482a8164dfSZhong Wang 		(void) fcoet_clear_unsol_exchange(CMD2XCH(cmd));
3492a8164dfSZhong Wang 		if (!(flags & FCT_IOF_FORCE_FCA_DONE)) {
3502a8164dfSZhong Wang 			mutex_enter(&this_ss->ss_watch_mutex);
3512a8164dfSZhong Wang 			CMD2XCH(cmd)->xch_start_time = ddi_get_lbolt();
3522a8164dfSZhong Wang 			list_insert_tail(&this_ss->ss_abort_xchg_list,
3532a8164dfSZhong Wang 			    CMD2XCH(cmd));
3542a8164dfSZhong Wang 			cv_signal(&this_ss->ss_watch_cv);
3552a8164dfSZhong Wang 			mutex_exit(&this_ss->ss_watch_mutex);
3562a8164dfSZhong Wang 		}
3572a8164dfSZhong Wang 		break;
3582a8164dfSZhong Wang 
3592a8164dfSZhong Wang 	case FCT_CMD_SOL_ELS:
3602a8164dfSZhong Wang 	case FCT_CMD_SOL_CT:
3612a8164dfSZhong Wang 		if (CMD2XCH(cmd)->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
3622a8164dfSZhong Wang 			break;
3632a8164dfSZhong Wang 		}
3642a8164dfSZhong Wang 
3652a8164dfSZhong Wang 		CMD2XCH(cmd)->xch_flags |= XCH_FLAG_FCT_CALLED_ABORT;
3662a8164dfSZhong Wang 		fcoet_clear_sol_exchange(CMD2XCH(cmd));
3672a8164dfSZhong Wang 
3682a8164dfSZhong Wang 		if (!(flags & FCT_IOF_FORCE_FCA_DONE)) {
3692a8164dfSZhong Wang 			mutex_enter(&this_ss->ss_watch_mutex);
3702a8164dfSZhong Wang 			CMD2XCH(cmd)->xch_start_time = ddi_get_lbolt();
3712a8164dfSZhong Wang 			cv_signal(&this_ss->ss_watch_cv);
3722a8164dfSZhong Wang 			list_insert_tail(&this_ss->ss_abort_xchg_list,
3732a8164dfSZhong Wang 			    CMD2XCH(cmd));
3742a8164dfSZhong Wang 			mutex_exit(&this_ss->ss_watch_mutex);
3752a8164dfSZhong Wang 		}
3762a8164dfSZhong Wang 
3772a8164dfSZhong Wang 		break;
3782a8164dfSZhong Wang 
3792a8164dfSZhong Wang 	default:
3802a8164dfSZhong Wang 		ASSERT(0);
3812a8164dfSZhong Wang 		break;
3822a8164dfSZhong Wang 	}
3832a8164dfSZhong Wang 
3842a8164dfSZhong Wang 	if ((flags & FCT_IOF_FORCE_FCA_DONE) &&
3852a8164dfSZhong Wang 	    (cmd->cmd_type != FCT_CMD_FCP_XCHG)) {
3862a8164dfSZhong Wang 		cmd->cmd_handle = 0;
3872a8164dfSZhong Wang 	}
3882a8164dfSZhong Wang 
3892a8164dfSZhong Wang 	return (fct_ret);
3902a8164dfSZhong Wang }
3912a8164dfSZhong Wang 
3922a8164dfSZhong Wang /* ARGSUSED */
3932a8164dfSZhong Wang fct_status_t
fcoet_do_flogi(fct_local_port_t * port,fct_flogi_xchg_t * fx)3942a8164dfSZhong Wang fcoet_do_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx)
3952a8164dfSZhong Wang {
3962a8164dfSZhong Wang 	cmn_err(CE_WARN, "FLOGI requested (not supported)");
3972a8164dfSZhong Wang 	return (FCT_FAILURE);
3982a8164dfSZhong Wang }
3992a8164dfSZhong Wang 
4002a8164dfSZhong Wang void
fcoet_send_sol_flogi(fcoet_soft_state_t * ss)4012a8164dfSZhong Wang fcoet_send_sol_flogi(fcoet_soft_state_t *ss)
4022a8164dfSZhong Wang {
4032a8164dfSZhong Wang 	fcoet_exchange_t	*xch;
4042a8164dfSZhong Wang 	fct_cmd_t		*cmd;
4052a8164dfSZhong Wang 	fct_els_t		*els;
4062a8164dfSZhong Wang 	fcoe_frame_t		*frm;
4072a8164dfSZhong Wang 
4082a8164dfSZhong Wang 	/*
4092a8164dfSZhong Wang 	 * FCT will initialize fct_cmd_t
4102a8164dfSZhong Wang 	 * Initialize fcoet_exchange
4112a8164dfSZhong Wang 	 */
4122a8164dfSZhong Wang 	cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_SOL_ELS,
4132a8164dfSZhong Wang 	    sizeof (fcoet_exchange_t), 0);
4142a8164dfSZhong Wang 	xch = CMD2XCH(cmd);
4152a8164dfSZhong Wang 	els = CMD2ELS(cmd);
4162a8164dfSZhong Wang 
4172a8164dfSZhong Wang 	xch->xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
4182a8164dfSZhong Wang 	if (xch->xch_oxid == 0xFFFF) {
4192a8164dfSZhong Wang 		xch->xch_oxid =
4202a8164dfSZhong Wang 		    atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
4212a8164dfSZhong Wang 	}
4222a8164dfSZhong Wang 	xch->xch_rxid = 0xFFFF;
4232a8164dfSZhong Wang 	xch->xch_flags = 0;
4242a8164dfSZhong Wang 	xch->xch_ss = ss;
4252a8164dfSZhong Wang 	xch->xch_cmd = cmd;
4262a8164dfSZhong Wang 	xch->xch_current_seq = NULL;
4272a8164dfSZhong Wang 	xch->xch_start_time = ddi_get_lbolt();
4282a8164dfSZhong Wang 
4292a8164dfSZhong Wang 	/*
4302a8164dfSZhong Wang 	 * Keep it to compare with response
4312a8164dfSZhong Wang 	 */
4322a8164dfSZhong Wang 	ss->ss_sol_flogi = xch;
4332a8164dfSZhong Wang 	els->els_resp_alloc_size = 116;
4342a8164dfSZhong Wang 	els->els_resp_size = 116;
4352a8164dfSZhong Wang 	els->els_resp_payload = (uint8_t *)
4362a8164dfSZhong Wang 	    kmem_zalloc(els->els_resp_size, KM_SLEEP);
4372a8164dfSZhong Wang 	(void) mod_hash_insert(xch->xch_ss->ss_sol_oxid_hash,
4382a8164dfSZhong Wang 	    (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch);
4392a8164dfSZhong Wang 	xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
4402a8164dfSZhong Wang 	atomic_or_32(&ss->ss_flags, SS_FLAG_DELAY_PLOGI);
4412a8164dfSZhong Wang 
4422a8164dfSZhong Wang 	/*
4432a8164dfSZhong Wang 	 * FCoE will initialize fcoe_frame_t
4442a8164dfSZhong Wang 	 */
4452a8164dfSZhong Wang 	frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport,
4462a8164dfSZhong Wang 	    FLOGI_REQ_PAYLOAD_SIZE + FCFH_SIZE, NULL);
4472a8164dfSZhong Wang 	if (frm == NULL) {
4482a8164dfSZhong Wang 		ASSERT(0);
4492a8164dfSZhong Wang 		return;
4502a8164dfSZhong Wang 	} else {
4512a8164dfSZhong Wang 		fcoet_init_tfm(frm, xch);
4522a8164dfSZhong Wang 		bzero(frm->frm_payload, frm->frm_payload_size);
4532a8164dfSZhong Wang 	}
4542a8164dfSZhong Wang 
4552a8164dfSZhong Wang 	FFM_R_CTL(0x22, frm);
4562a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_rctl = 0x22;
4572a8164dfSZhong Wang 	FFM_TYPE(0x01, frm);
4582a8164dfSZhong Wang 	FFM_F_CTL(0x290000, frm);
4592a8164dfSZhong Wang 	FFM_OXID(xch->xch_oxid, frm);
4602a8164dfSZhong Wang 	FFM_RXID(xch->xch_rxid, frm);
4612a8164dfSZhong Wang 	FFM_D_ID(0xfffffe, frm);
4622a8164dfSZhong Wang 	frm->frm_payload[0] = ELS_OP_FLOGI;
4632a8164dfSZhong Wang 	/* Common Service Parameters */
4642a8164dfSZhong Wang 	frm->frm_payload[4] = 0x20;
4652a8164dfSZhong Wang 	frm->frm_payload[5] = 0x08;
4662a8164dfSZhong Wang 	frm->frm_payload[6] = 0x0;
4672a8164dfSZhong Wang 	frm->frm_payload[7] = 0x03;
4682a8164dfSZhong Wang 	/* N_PORT */
4692a8164dfSZhong Wang 	frm->frm_payload[8] = 0x88;
4702a8164dfSZhong Wang 	frm->frm_payload[9] = 0x00;
4712a8164dfSZhong Wang 	frm->frm_payload[10] = 0x08;
4722a8164dfSZhong Wang 	frm->frm_payload[11] = 0x0;
4732a8164dfSZhong Wang 	frm->frm_payload[12] = 0x0;
4742a8164dfSZhong Wang 	frm->frm_payload[13] = 0xff;
4752a8164dfSZhong Wang 	frm->frm_payload[14] = 0x0;
4762a8164dfSZhong Wang 	frm->frm_payload[15] = 0x03;
4772a8164dfSZhong Wang 	frm->frm_payload[16] = 0x0;
4782a8164dfSZhong Wang 	frm->frm_payload[17] = 0x0;
4792a8164dfSZhong Wang 	frm->frm_payload[18] = 0x07;
4802a8164dfSZhong Wang 	frm->frm_payload[19] = 0xd0;
4812a8164dfSZhong Wang 	/* PWWN and NWWN */
4822a8164dfSZhong Wang 	frm->frm_payload[20] = 0x0;
4832a8164dfSZhong Wang 	bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload+20, 8);
4842a8164dfSZhong Wang 	bcopy(ss->ss_eport->eport_nodewwn, frm->frm_payload+28, 8);
4852a8164dfSZhong Wang 	/* Class 3 Service Parameters */
4862a8164dfSZhong Wang 	frm->frm_payload[68] = 0x88;
4872a8164dfSZhong Wang 	frm->frm_payload[74] = 0x08;
4882a8164dfSZhong Wang 	frm->frm_payload[77] = 0xff;
4892a8164dfSZhong Wang 
4902a8164dfSZhong Wang 	ss->ss_eport->eport_tx_frame(frm);
4912a8164dfSZhong Wang 	xch->xch_flags |= XCH_FLAG_NONFCP_REQ_SENT;
4922a8164dfSZhong Wang }
4932a8164dfSZhong Wang 
4942a8164dfSZhong Wang /*
4952a8164dfSZhong Wang  * This is for solicited FLOGI only
4962a8164dfSZhong Wang  */
4972a8164dfSZhong Wang void
fcoet_send_sol_abts(fcoet_exchange_t * xch)4982a8164dfSZhong Wang fcoet_send_sol_abts(fcoet_exchange_t *xch)
4992a8164dfSZhong Wang {
5002a8164dfSZhong Wang 	fcoe_frame_t		*frm;
5012a8164dfSZhong Wang 	fcoet_soft_state_t	*ss = xch->xch_ss;
5022a8164dfSZhong Wang 
5032a8164dfSZhong Wang 	/*
5042a8164dfSZhong Wang 	 * FCoE will initialize fcoe_frame_t
5052a8164dfSZhong Wang 	 * ABTS has no payload
5062a8164dfSZhong Wang 	 */
5072a8164dfSZhong Wang 	frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport,
5082a8164dfSZhong Wang 	    FCFH_SIZE, NULL);
5092a8164dfSZhong Wang 	if (frm == NULL) {
5102a8164dfSZhong Wang 		ASSERT(0);
5112a8164dfSZhong Wang 		return;
5122a8164dfSZhong Wang 	} else {
5132a8164dfSZhong Wang 		fcoet_init_tfm(frm, xch);
5142a8164dfSZhong Wang 		frm->frm_payload = NULL;
5152a8164dfSZhong Wang 	}
5162a8164dfSZhong Wang 
5172a8164dfSZhong Wang 	FFM_R_CTL(0x81, frm);
5182a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_rctl = 0x81;
5192a8164dfSZhong Wang 	FFM_F_CTL(0x090000, frm);
5202a8164dfSZhong Wang 	FFM_OXID(xch->xch_oxid, frm);
5212a8164dfSZhong Wang 	FFM_RXID(xch->xch_rxid, frm);
5222a8164dfSZhong Wang 	FFM_D_ID(0xfffffe, frm);
5232a8164dfSZhong Wang 	FFM_SEQ_CNT(xch->xch_sequence_no, frm);
5242a8164dfSZhong Wang 	xch->xch_start_time = ddi_get_lbolt();
5252a8164dfSZhong Wang 
5262a8164dfSZhong Wang 	ss->ss_eport->eport_tx_frame(frm);
5272a8164dfSZhong Wang }
5282a8164dfSZhong Wang 
5292a8164dfSZhong Wang void
fcoet_ctl(struct fct_local_port * port,int cmd,void * arg)5302a8164dfSZhong Wang fcoet_ctl(struct fct_local_port *port, int cmd, void *arg)
5312a8164dfSZhong Wang {
5322a8164dfSZhong Wang 	stmf_change_status_t		 st;
5332a8164dfSZhong Wang 	stmf_state_change_info_t	*ssci = (stmf_state_change_info_t *)arg;
5342a8164dfSZhong Wang 	fcoet_soft_state_t		*this_ss = PORT2SS(port);
5352a8164dfSZhong Wang 
5362a8164dfSZhong Wang 	st.st_completion_status = FCT_SUCCESS;
5372a8164dfSZhong Wang 	st.st_additional_info = NULL;
5382a8164dfSZhong Wang 
5392a8164dfSZhong Wang 	switch (cmd) {
5402a8164dfSZhong Wang 	case FCT_CMD_PORT_ONLINE:
5412a8164dfSZhong Wang 		if (this_ss->ss_state == FCT_STATE_ONLINE)
5422a8164dfSZhong Wang 			st.st_completion_status = STMF_ALREADY;
5432a8164dfSZhong Wang 		else if (this_ss->ss_state != FCT_STATE_OFFLINE)
5442a8164dfSZhong Wang 			st.st_completion_status = FCT_FAILURE;
5452a8164dfSZhong Wang 		if (st.st_completion_status == FCT_SUCCESS) {
5462a8164dfSZhong Wang 			this_ss->ss_state = FCT_STATE_ONLINING;
5472a8164dfSZhong Wang 			this_ss->ss_state_not_acked = 1;
5482a8164dfSZhong Wang 			st.st_completion_status = fcoet_enable_port(this_ss);
5492a8164dfSZhong Wang 			if (st.st_completion_status != STMF_SUCCESS) {
5502a8164dfSZhong Wang 				this_ss->ss_state = FCT_STATE_OFFLINE;
5512a8164dfSZhong Wang 				this_ss->ss_state_not_acked = 0;
5522a8164dfSZhong Wang 			} else {
5532a8164dfSZhong Wang 				this_ss->ss_state = FCT_STATE_ONLINE;
5542a8164dfSZhong Wang 			}
5552a8164dfSZhong Wang 		}
5562a8164dfSZhong Wang 		fct_ctl(port->port_lport, FCT_CMD_PORT_ONLINE_COMPLETE, &st);
5572a8164dfSZhong Wang 		this_ss->ss_change_state_flags = 0;
5582a8164dfSZhong Wang 		break;
5592a8164dfSZhong Wang 
5602a8164dfSZhong Wang 	case FCT_CMD_PORT_OFFLINE:
5612a8164dfSZhong Wang 		if (this_ss->ss_state == FCT_STATE_OFFLINE) {
5622a8164dfSZhong Wang 			st.st_completion_status = STMF_ALREADY;
5632a8164dfSZhong Wang 		} else if (this_ss->ss_state != FCT_STATE_ONLINE) {
5642a8164dfSZhong Wang 			st.st_completion_status = FCT_FAILURE;
5652a8164dfSZhong Wang 		}
5662a8164dfSZhong Wang 		if (st.st_completion_status == FCT_SUCCESS) {
5672a8164dfSZhong Wang 			this_ss->ss_state = FCT_STATE_OFFLINING;
5682a8164dfSZhong Wang 			this_ss->ss_state_not_acked = 1;
5692a8164dfSZhong Wang 			this_ss->ss_change_state_flags = ssci->st_rflags;
5702a8164dfSZhong Wang 			st.st_completion_status = fcoet_disable_port(this_ss);
5712a8164dfSZhong Wang 			if (st.st_completion_status != STMF_SUCCESS) {
5722a8164dfSZhong Wang 				this_ss->ss_state = FCT_STATE_ONLINE;
5732a8164dfSZhong Wang 				this_ss->ss_state_not_acked = 0;
5742a8164dfSZhong Wang 			} else {
5752a8164dfSZhong Wang 				this_ss->ss_state = FCT_STATE_OFFLINE;
5762a8164dfSZhong Wang 			}
5772a8164dfSZhong Wang 		}
5781826d2a2SKelly Hu 		/*
5791826d2a2SKelly Hu 		 * Notify the watchdog to do clear work
5801826d2a2SKelly Hu 		 */
5811826d2a2SKelly Hu 		mutex_enter(&this_ss->ss_watch_mutex);
5821826d2a2SKelly Hu 		cv_signal(&this_ss->ss_watch_cv);
5831826d2a2SKelly Hu 		mutex_exit(&this_ss->ss_watch_mutex);
5842a8164dfSZhong Wang 		fct_ctl(port->port_lport, FCT_CMD_PORT_OFFLINE_COMPLETE, &st);
5852a8164dfSZhong Wang 		break;
5862a8164dfSZhong Wang 
5872a8164dfSZhong Wang 	case FCT_ACK_PORT_ONLINE_COMPLETE:
5882a8164dfSZhong Wang 		this_ss->ss_state_not_acked = 0;
5892a8164dfSZhong Wang 		break;
5902a8164dfSZhong Wang 
5912a8164dfSZhong Wang 	case FCT_ACK_PORT_OFFLINE_COMPLETE:
5922a8164dfSZhong Wang 		this_ss->ss_state_not_acked = 0;
5932a8164dfSZhong Wang 		if (this_ss->ss_change_state_flags & STMF_RFLAG_RESET) {
5942a8164dfSZhong Wang 			if (fct_port_initialize(port,
5952a8164dfSZhong Wang 			    this_ss->ss_change_state_flags,
5962a8164dfSZhong Wang 			    "fcoet_ctl FCT_ACK_PORT_OFFLINE_COMPLETE "
5972a8164dfSZhong Wang 			    "with RLFLAG_RESET") != FCT_SUCCESS) {
5982a8164dfSZhong Wang 				cmn_err(CE_WARN, "fcoet_ctl: "
5992a8164dfSZhong Wang 				    "fct_port_initialize %s failed",
6002a8164dfSZhong Wang 				    this_ss->ss_alias);
6012a8164dfSZhong Wang 				FCOET_LOG("fcoet_ctl: fct_port_initialize "
6022a8164dfSZhong Wang 				    "%s failed", this_ss->ss_alias);
6032a8164dfSZhong Wang 			}
6042a8164dfSZhong Wang 		}
6052a8164dfSZhong Wang 		break;
6062a8164dfSZhong Wang 	default:
6072a8164dfSZhong Wang 		FCOET_LOG("fcoet_ctl", "Unsupported cmd %x", cmd);
6082a8164dfSZhong Wang 		break;
6092a8164dfSZhong Wang 	}
6102a8164dfSZhong Wang }
6112a8164dfSZhong Wang 
6122a8164dfSZhong Wang /*
6132a8164dfSZhong Wang  * Filling the hba attributes
6142a8164dfSZhong Wang  */
6152a8164dfSZhong Wang /* ARGSUSED */
6162a8164dfSZhong Wang void
fcoet_populate_hba_fru_details(struct fct_local_port * port,struct fct_port_attrs * port_attrs)6172a8164dfSZhong Wang fcoet_populate_hba_fru_details(struct fct_local_port *port,
6182a8164dfSZhong Wang     struct fct_port_attrs *port_attrs)
6192a8164dfSZhong Wang {
6202a8164dfSZhong Wang 	(void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
6212a8164dfSZhong Wang 	    "Sun Microsystems, Inc.");
6222a8164dfSZhong Wang 	(void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
6232a8164dfSZhong Wang 	    "%s", FCOET_NAME);
6242a8164dfSZhong Wang 	(void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
6252a8164dfSZhong Wang 	    "%s", FCOET_VERSION);
6262a8164dfSZhong Wang 	(void) strcpy(port_attrs->serial_number, "N/A");
6272a8164dfSZhong Wang 	(void) strcpy(port_attrs->hardware_version, "N/A");
6282a8164dfSZhong Wang 	(void) strcpy(port_attrs->model, "FCoE Virtual FC HBA");
6292a8164dfSZhong Wang 	(void) strcpy(port_attrs->model_description, "N/A");
6302a8164dfSZhong Wang 	(void) strcpy(port_attrs->firmware_version, "N/A");
6312a8164dfSZhong Wang 	(void) strcpy(port_attrs->option_rom_version, "N/A");
6322a8164dfSZhong Wang 
6332a8164dfSZhong Wang 	port_attrs->vendor_specific_id = 0xFC0E;
6342a8164dfSZhong Wang 	port_attrs->max_frame_size = 2136;
6352a8164dfSZhong Wang 	port_attrs->supported_cos = 0x10000000;
6362a8164dfSZhong Wang 	/* Specified a fix speed here, need to change it in the future */
6372a8164dfSZhong Wang 	port_attrs->supported_speed = PORT_SPEED_1G | PORT_SPEED_10G;
6382a8164dfSZhong Wang }
6392a8164dfSZhong Wang 
6402a8164dfSZhong Wang 
6412a8164dfSZhong Wang static fct_status_t
fcoet_send_sol_els(fct_cmd_t * cmd)6422a8164dfSZhong Wang fcoet_send_sol_els(fct_cmd_t *cmd)
6432a8164dfSZhong Wang {
6442a8164dfSZhong Wang 	fcoe_frame_t	 *frm;
6452a8164dfSZhong Wang 	fcoet_exchange_t *xch = NULL;
6462a8164dfSZhong Wang 
6472a8164dfSZhong Wang 	xch = CMD2XCH(cmd);
6482a8164dfSZhong Wang 	xch->xch_flags = 0;
6492a8164dfSZhong Wang 	xch->xch_ss = CMD2SS(cmd);
6502a8164dfSZhong Wang 	xch->xch_cmd = cmd;
6512a8164dfSZhong Wang 	xch->xch_current_seq = NULL;
6522a8164dfSZhong Wang 	xch->xch_left_data_size = 0;
6532a8164dfSZhong Wang 	xch->xch_sequence_no = 0;
6542a8164dfSZhong Wang 	xch->xch_start_time = ddi_get_lbolt();
6552a8164dfSZhong Wang 	xch->xch_rxid = 0xFFFF;
6562a8164dfSZhong Wang 	xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
6572a8164dfSZhong Wang 	if (xch->xch_oxid == 0xFFFF) {
6582a8164dfSZhong Wang 		xch->xch_oxid =
6592a8164dfSZhong Wang 		    atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
6602a8164dfSZhong Wang 	}
6612a8164dfSZhong Wang 
6622a8164dfSZhong Wang 	frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
6632a8164dfSZhong Wang 	    CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL);
6642a8164dfSZhong Wang 	if (frm == NULL) {
6652a8164dfSZhong Wang 		ASSERT(0);
6662a8164dfSZhong Wang 		return (FCT_FAILURE);
6672a8164dfSZhong Wang 	} else {
6682a8164dfSZhong Wang 		fcoet_init_tfm(frm, CMD2XCH(cmd));
6692a8164dfSZhong Wang 		bzero(frm->frm_payload, frm->frm_payload_size);
6702a8164dfSZhong Wang 	}
6712a8164dfSZhong Wang 
6722a8164dfSZhong Wang 	(void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash,
6732a8164dfSZhong Wang 	    (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch);
6742a8164dfSZhong Wang 	xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
6752a8164dfSZhong Wang 	bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload,
6762a8164dfSZhong Wang 	    frm->frm_payload_size);
6772a8164dfSZhong Wang 	FFM_R_CTL(0x22, frm);
6782a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_rctl = 0x22;
6792a8164dfSZhong Wang 	FFM_TYPE(0x01, frm);
6802a8164dfSZhong Wang 	FFM_F_CTL(0x290000, frm);
6812a8164dfSZhong Wang 	FFM_OXID(xch->xch_oxid, frm);
6822a8164dfSZhong Wang 	FFM_RXID(xch->xch_rxid, frm);
6832a8164dfSZhong Wang 	FFM_S_ID(cmd->cmd_lportid, frm);
6842a8164dfSZhong Wang 	FFM_D_ID(cmd->cmd_rportid, frm);
6852a8164dfSZhong Wang 	CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
6862a8164dfSZhong Wang 
6872a8164dfSZhong Wang 	return (FCT_SUCCESS);
6882a8164dfSZhong Wang }
6892a8164dfSZhong Wang 
6902a8164dfSZhong Wang static fct_status_t
fcoet_send_sol_ct(fct_cmd_t * cmd)6912a8164dfSZhong Wang fcoet_send_sol_ct(fct_cmd_t *cmd)
6922a8164dfSZhong Wang {
6932a8164dfSZhong Wang 	fcoe_frame_t	 *frm;
6942a8164dfSZhong Wang 	fcoet_exchange_t *xch;
6952a8164dfSZhong Wang 
6962a8164dfSZhong Wang 	xch = CMD2XCH(cmd);
6972a8164dfSZhong Wang 	xch->xch_flags = 0;
6982a8164dfSZhong Wang 	xch->xch_ss = CMD2SS(cmd);
6992a8164dfSZhong Wang 	xch->xch_cmd = cmd;
7002a8164dfSZhong Wang 	xch->xch_current_seq = NULL;
7012a8164dfSZhong Wang 	xch->xch_left_data_size = 0;
7022a8164dfSZhong Wang 	xch->xch_sequence_no = 0;
7032a8164dfSZhong Wang 	xch->xch_start_time = ddi_get_lbolt();
7042a8164dfSZhong Wang 	xch->xch_rxid = 0xFFFF;
7052a8164dfSZhong Wang 	xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
7062a8164dfSZhong Wang 	if (xch->xch_oxid == 0xFFFF) {
7072a8164dfSZhong Wang 		xch->xch_oxid =
7082a8164dfSZhong Wang 		    atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
7092a8164dfSZhong Wang 	}
7102a8164dfSZhong Wang 
7112a8164dfSZhong Wang 	frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
7122a8164dfSZhong Wang 	    CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL);
7132a8164dfSZhong Wang 	if (frm == NULL) {
7142a8164dfSZhong Wang 		ASSERT(0);
7152a8164dfSZhong Wang 		return (FCT_FAILURE);
7162a8164dfSZhong Wang 	} else {
7172a8164dfSZhong Wang 		fcoet_init_tfm(frm, CMD2XCH(cmd));
7182a8164dfSZhong Wang 		bzero(frm->frm_payload, frm->frm_payload_size);
7192a8164dfSZhong Wang 	}
7202a8164dfSZhong Wang 
7212a8164dfSZhong Wang 	(void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash,
7222a8164dfSZhong Wang 	    (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch);
7232a8164dfSZhong Wang 	xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
7242a8164dfSZhong Wang 	bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload,
7252a8164dfSZhong Wang 	    frm->frm_payload_size);
7262a8164dfSZhong Wang 	FFM_R_CTL(0x2, frm);
7272a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_rctl = 0x2;
7282a8164dfSZhong Wang 	FFM_TYPE(0x20, frm);
7292a8164dfSZhong Wang 	FFM_F_CTL(0x290000, frm);
7302a8164dfSZhong Wang 	FFM_OXID(xch->xch_oxid, frm);
7312a8164dfSZhong Wang 	FFM_RXID(xch->xch_rxid, frm);
7322a8164dfSZhong Wang 	FFM_S_ID(cmd->cmd_lportid, frm);
7332a8164dfSZhong Wang 	FFM_D_ID(cmd->cmd_rportid, frm);
7342a8164dfSZhong Wang 	CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
7352a8164dfSZhong Wang 
7362a8164dfSZhong Wang 	return (FCT_SUCCESS);
7372a8164dfSZhong Wang }
7382a8164dfSZhong Wang 
7392a8164dfSZhong Wang fct_status_t
fcoet_send_status(fct_cmd_t * cmd)7402a8164dfSZhong Wang fcoet_send_status(fct_cmd_t *cmd)
7412a8164dfSZhong Wang {
7422a8164dfSZhong Wang 	fcoe_frame_t	*frm;
7432a8164dfSZhong Wang 	scsi_task_t	*task = CMD2TASK(cmd);
7442a8164dfSZhong Wang 	fcoe_fcp_rsp_t	*ffr;
7452a8164dfSZhong Wang 	int		 raw_frame_size;
7462a8164dfSZhong Wang 
7472a8164dfSZhong Wang 	/*
7482a8164dfSZhong Wang 	 * Fast channel for good status phase
7492a8164dfSZhong Wang 	 */
7502a8164dfSZhong Wang 	if (task->task_scsi_status == STATUS_GOOD && !task->task_resid) {
7512a8164dfSZhong Wang 		return (fcoet_send_good_status(cmd));
7522a8164dfSZhong Wang 	}
7532a8164dfSZhong Wang 
7542a8164dfSZhong Wang 	raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t);
7552a8164dfSZhong Wang 	if (task->task_scsi_status == STATUS_CHECK) {
7562a8164dfSZhong Wang 		raw_frame_size += task->task_sense_length;
7572a8164dfSZhong Wang 	}
7582a8164dfSZhong Wang 	raw_frame_size = P2ROUNDUP(raw_frame_size, 4);
7592a8164dfSZhong Wang 
7602a8164dfSZhong Wang 	frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
7612a8164dfSZhong Wang 	    raw_frame_size, NULL);
7622a8164dfSZhong Wang 	if (frm == NULL) {
7632a8164dfSZhong Wang 		ASSERT(0);
7642a8164dfSZhong Wang 		return (FCT_FAILURE);
7652a8164dfSZhong Wang 	} else {
7662a8164dfSZhong Wang 		fcoet_init_tfm(frm, CMD2XCH(cmd));
7672a8164dfSZhong Wang 		bzero(frm->frm_payload, frm->frm_payload_size);
7682a8164dfSZhong Wang 		/*
7692a8164dfSZhong Wang 		 * lock the xchg to avoid being released (by abort)
7702a8164dfSZhong Wang 		 * after sent out and before release
7712a8164dfSZhong Wang 		 */
7722a8164dfSZhong Wang 		FCOET_BUSY_XCHG(CMD2XCH(cmd));
7732a8164dfSZhong Wang 	}
7742a8164dfSZhong Wang 
7752a8164dfSZhong Wang 	/*
7762a8164dfSZhong Wang 	 * If there's sense data, copy it first
7772a8164dfSZhong Wang 	 */
7782a8164dfSZhong Wang 	if ((task->task_scsi_status == STATUS_CHECK) &&
7792a8164dfSZhong Wang 	    task->task_sense_length) {
7802a8164dfSZhong Wang 		bcopy(task->task_sense_data, frm->frm_payload +
7812a8164dfSZhong Wang 		    sizeof (fcoe_fcp_rsp_t), task->task_sense_length);
7822a8164dfSZhong Wang 	}
7832a8164dfSZhong Wang 
7842a8164dfSZhong Wang 	/*
7852a8164dfSZhong Wang 	 * Fill fcp_rsp
7862a8164dfSZhong Wang 	 */
7872a8164dfSZhong Wang 	ffr = (fcoe_fcp_rsp_t *)frm->frm_payload;
788*00bdf9afSToomas Soome 	FCOE_V2B_2(0, ffr->ffr_retry_delay_timer);
7892a8164dfSZhong Wang 	FCOE_V2B_1(0, ffr->ffr_flags);
7902a8164dfSZhong Wang 	if (task->task_scsi_status == STATUS_CHECK || task->task_resid) {
7912a8164dfSZhong Wang 		if (task->task_scsi_status == STATUS_CHECK) {
7922a8164dfSZhong Wang 			ffr->ffr_flags[0] |= BIT_1;
7932a8164dfSZhong Wang 		}
7942a8164dfSZhong Wang 		if (task->task_status_ctrl == TASK_SCTRL_OVER) {
7952a8164dfSZhong Wang 			ffr->ffr_flags[0] |= BIT_2;
7962a8164dfSZhong Wang 		} else if (task->task_status_ctrl == TASK_SCTRL_UNDER) {
7972a8164dfSZhong Wang 			ffr->ffr_flags[0] |= BIT_3;
7982a8164dfSZhong Wang 		}
7992a8164dfSZhong Wang 	}
8002a8164dfSZhong Wang 	FCOE_V2B_1(task->task_scsi_status, ffr->ffr_scsi_status);
8012a8164dfSZhong Wang 	FCOE_V2B_4(task->task_resid, ffr->ffr_resid);
8022a8164dfSZhong Wang 	FCOE_V2B_4(task->task_sense_length, ffr->ffr_sns_len);
8032a8164dfSZhong Wang 	FCOE_V2B_4(0, ffr->ffr_rsp_len);
8042a8164dfSZhong Wang 
8052a8164dfSZhong Wang 	/*
8062a8164dfSZhong Wang 	 * Fill fc frame header
8072a8164dfSZhong Wang 	 */
8082a8164dfSZhong Wang 	FFM_R_CTL(0x07, frm);
8092a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_rctl = 0x07;
8102a8164dfSZhong Wang 	FFM_TYPE(0x08, frm);
8112a8164dfSZhong Wang 	FFM_F_CTL(0x990000, frm);
8122a8164dfSZhong Wang 	FFM_OXID(cmd->cmd_oxid, frm);
8132a8164dfSZhong Wang 	FFM_RXID(cmd->cmd_rxid, frm);
8142a8164dfSZhong Wang 	FFM_S_ID(cmd->cmd_lportid, frm);
8152a8164dfSZhong Wang 	FFM_D_ID(cmd->cmd_rportid, frm);
8162a8164dfSZhong Wang 	FFM_SEQ_ID(0x01, frm);
8172a8164dfSZhong Wang 	CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
8182a8164dfSZhong Wang 
8192a8164dfSZhong Wang 	return (FCT_SUCCESS);
8202a8164dfSZhong Wang }
8212a8164dfSZhong Wang 
8222a8164dfSZhong Wang static fct_status_t
fcoet_send_els_response(fct_cmd_t * cmd)8232a8164dfSZhong Wang fcoet_send_els_response(fct_cmd_t *cmd)
8242a8164dfSZhong Wang {
8252a8164dfSZhong Wang 	fcoe_frame_t *frm;
8262a8164dfSZhong Wang 
8272a8164dfSZhong Wang 	frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
8282a8164dfSZhong Wang 	    CMD2ELS(cmd)->els_resp_size + FCFH_SIZE, NULL);
8292a8164dfSZhong Wang 	if (frm == NULL) {
8302a8164dfSZhong Wang 		ASSERT(0);
8312a8164dfSZhong Wang 		return (FCT_FAILURE);
8322a8164dfSZhong Wang 	} else {
8332a8164dfSZhong Wang 		fcoet_init_tfm(frm, CMD2XCH(cmd));
8342a8164dfSZhong Wang 		bzero(frm->frm_payload, frm->frm_payload_size);
8352a8164dfSZhong Wang 		/*
8362a8164dfSZhong Wang 		 * lock the xchg to avoid being released (by abort)
8372a8164dfSZhong Wang 		 * after sent out and before release
8382a8164dfSZhong Wang 		 */
8392a8164dfSZhong Wang 		FCOET_BUSY_XCHG(CMD2XCH(cmd));
8402a8164dfSZhong Wang 	}
8412a8164dfSZhong Wang 
8422a8164dfSZhong Wang 	bcopy(CMD2ELS(cmd)->els_resp_payload, frm->frm_payload,
8432a8164dfSZhong Wang 	    frm->frm_payload_size);
8442a8164dfSZhong Wang 	FFM_R_CTL(0x23, frm);
8452a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_rctl = 0x23;
8462a8164dfSZhong Wang 	FFM_TYPE(0x01, frm);
8472a8164dfSZhong Wang 	FFM_F_CTL(0x980000, frm);
8482a8164dfSZhong Wang 	FFM_OXID(cmd->cmd_oxid, frm);
8492a8164dfSZhong Wang 	FFM_RXID(cmd->cmd_rxid, frm);
8502a8164dfSZhong Wang 	FFM_S_ID(cmd->cmd_lportid, frm);
8512a8164dfSZhong Wang 	FFM_D_ID(cmd->cmd_rportid, frm);
8522a8164dfSZhong Wang 	CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
8532a8164dfSZhong Wang 
8542a8164dfSZhong Wang 	return (FCT_SUCCESS);
8552a8164dfSZhong Wang }
8562a8164dfSZhong Wang 
8572a8164dfSZhong Wang /* ARGSUSED */
8582a8164dfSZhong Wang static fct_status_t
fcoet_send_abts_response(fct_cmd_t * cmd,uint32_t flags)8592a8164dfSZhong Wang fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags)
8602a8164dfSZhong Wang {
8612a8164dfSZhong Wang 	fcoe_frame_t	*frm;
8622a8164dfSZhong Wang 	fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific;
8632a8164dfSZhong Wang 
8642a8164dfSZhong Wang 	/*
8652a8164dfSZhong Wang 	 * The relevant fcoet_exchange has been released
8662a8164dfSZhong Wang 	 */
8672a8164dfSZhong Wang 	cmd->cmd_fca_private = NULL;
8682a8164dfSZhong Wang 	frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
8692a8164dfSZhong Wang 	    12 + FCFH_SIZE, NULL);
8702a8164dfSZhong Wang 	if (frm == NULL) {
8712a8164dfSZhong Wang 		ASSERT(0);
8722a8164dfSZhong Wang 		return (FCT_FAILURE);
8732a8164dfSZhong Wang 	} else {
8742a8164dfSZhong Wang 		fcoet_init_tfm(frm, NULL);
8752a8164dfSZhong Wang 	}
8762a8164dfSZhong Wang 
8772a8164dfSZhong Wang 	bcopy(abts->abts_resp_payload, frm->frm_payload,
8782a8164dfSZhong Wang 	    frm->frm_payload_size);
8792a8164dfSZhong Wang 	FFM_R_CTL(abts->abts_resp_rctl, frm);
8802a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_rctl = abts->abts_resp_rctl;
8812a8164dfSZhong Wang 	FFM_TYPE(0x00, frm);
8822a8164dfSZhong Wang 	FFM_F_CTL(0x980000, frm);
8832a8164dfSZhong Wang 	FFM_OXID(cmd->cmd_oxid, frm);
8842a8164dfSZhong Wang 	FFM_RXID(cmd->cmd_rxid, frm);
8852a8164dfSZhong Wang 	FFM_S_ID(cmd->cmd_lportid, frm);
8862a8164dfSZhong Wang 	FFM_D_ID(cmd->cmd_rportid, frm);
8872a8164dfSZhong Wang 	CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
8882a8164dfSZhong Wang 
8892a8164dfSZhong Wang 	return (FCT_SUCCESS);
8902a8164dfSZhong Wang }
8912a8164dfSZhong Wang 
8922a8164dfSZhong Wang /*
8932a8164dfSZhong Wang  * enable/disable port is simple compared to physical FC HBAs
8942a8164dfSZhong Wang  */
8952a8164dfSZhong Wang fct_status_t
fcoet_enable_port(fcoet_soft_state_t * ss)8962a8164dfSZhong Wang fcoet_enable_port(fcoet_soft_state_t *ss)
8972a8164dfSZhong Wang {
8982a8164dfSZhong Wang 	FCOET_EXT_LOG(ss->ss_alias, "port is being enabled-%p", ss);
8992a8164dfSZhong Wang 	/* Call fcoe function to online the port */
9002a8164dfSZhong Wang 	if (ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, 0) ==
9012a8164dfSZhong Wang 	    FCOE_FAILURE) {
9022a8164dfSZhong Wang 		return (FCT_FAILURE);
9032a8164dfSZhong Wang 	}
9042a8164dfSZhong Wang 
9052a8164dfSZhong Wang 	if ((ss->ss_flags & SS_FLAG_PORT_DISABLED) == SS_FLAG_PORT_DISABLED) {
9062a8164dfSZhong Wang 		atomic_and_32(&ss->ss_flags, ~SS_FLAG_PORT_DISABLED);
9072a8164dfSZhong Wang 	}
9082a8164dfSZhong Wang 
9092a8164dfSZhong Wang 	return (FCT_SUCCESS);
9102a8164dfSZhong Wang }
9112a8164dfSZhong Wang 
9122a8164dfSZhong Wang fct_status_t
fcoet_disable_port(fcoet_soft_state_t * ss)9132a8164dfSZhong Wang fcoet_disable_port(fcoet_soft_state_t *ss)
9142a8164dfSZhong Wang {
9152a8164dfSZhong Wang 	fct_status_t	status;
9162a8164dfSZhong Wang 
9172a8164dfSZhong Wang 	FCOET_EXT_LOG(ss->ss_alias, "port is being disabled-%p", ss);
9182a8164dfSZhong Wang 	/* Call fcoe function to offline the port */
9192a8164dfSZhong Wang 	status = fcoet_logo_fabric(ss);
9202a8164dfSZhong Wang 	ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, 0);
9212a8164dfSZhong Wang 	atomic_or_32(&ss->ss_flags, SS_FLAG_PORT_DISABLED);
9222a8164dfSZhong Wang 	return (status);
9232a8164dfSZhong Wang }
9242a8164dfSZhong Wang 
9252a8164dfSZhong Wang static fct_status_t
fcoet_logo_fabric(fcoet_soft_state_t * ss)9262a8164dfSZhong Wang fcoet_logo_fabric(fcoet_soft_state_t *ss)
9272a8164dfSZhong Wang {
9282a8164dfSZhong Wang 	fcoe_frame_t	*frm;
9292a8164dfSZhong Wang 	uint32_t	req_payload_size = 16;
9302a8164dfSZhong Wang 	uint16_t	xch_oxid, xch_rxid = 0xFFFF;
9312a8164dfSZhong Wang 
9322a8164dfSZhong Wang 	frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport,
9332a8164dfSZhong Wang 	    req_payload_size + FCFH_SIZE, NULL);
9342a8164dfSZhong Wang 	if (frm == NULL) {
9352a8164dfSZhong Wang 		ASSERT(0);
9362a8164dfSZhong Wang 		return (FCT_FAILURE);
9372a8164dfSZhong Wang 	} else {
9382a8164dfSZhong Wang 		fcoet_init_tfm(frm, NULL);
9392a8164dfSZhong Wang 		bzero(frm->frm_payload, frm->frm_payload_size);
9402a8164dfSZhong Wang 	}
9411a5e258fSJosef 'Jeff' Sipek 	xch_oxid = atomic_inc_16_nv(&ss->ss_next_sol_oxid);
9422a8164dfSZhong Wang 	if (xch_oxid == 0xFFFF) {
9431a5e258fSJosef 'Jeff' Sipek 		xch_oxid = atomic_inc_16_nv(&ss->ss_next_sol_oxid);
9442a8164dfSZhong Wang 	}
9452a8164dfSZhong Wang 	FFM_R_CTL(0x22, frm);
9462a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_rctl = 0x22;
9472a8164dfSZhong Wang 	FFM_TYPE(0x01, frm);
9482a8164dfSZhong Wang 	FFM_F_CTL(0x290000, frm);
9492a8164dfSZhong Wang 	FFM_OXID(xch_oxid, frm);
9502a8164dfSZhong Wang 	FFM_RXID(xch_rxid, frm);
9512a8164dfSZhong Wang 	FFM_S_ID(ss->ss_link_info.portid, frm);
9522a8164dfSZhong Wang 	FFM_D_ID(0xfffffe, frm);
9532a8164dfSZhong Wang 
9542a8164dfSZhong Wang 	FCOE_V2B_1(0x5, frm->frm_payload);
9552a8164dfSZhong Wang 	FCOE_V2B_3(ss->ss_link_info.portid, frm->frm_payload + 5);
9562a8164dfSZhong Wang 	bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload + 8, 8);
9572a8164dfSZhong Wang 	ss->ss_eport->eport_tx_frame(frm);
9582a8164dfSZhong Wang 
9592a8164dfSZhong Wang 	return (FCT_SUCCESS);
9602a8164dfSZhong Wang 
9612a8164dfSZhong Wang }
9622a8164dfSZhong Wang 
9632a8164dfSZhong Wang /*
9642a8164dfSZhong Wang  * Called by: fcoet_register_remote_port
9652a8164dfSZhong Wang  */
9662a8164dfSZhong Wang /* ARGSUSED */
9672a8164dfSZhong Wang static fct_status_t
fcoet_fill_plogi_req(fct_local_port_t * port,fct_remote_port_t * rp,fct_cmd_t * login)9682a8164dfSZhong Wang fcoet_fill_plogi_req(fct_local_port_t *port, fct_remote_port_t *rp,
9692a8164dfSZhong Wang     fct_cmd_t *login)
9702a8164dfSZhong Wang {
9712a8164dfSZhong Wang 	uint8_t *p;
9722a8164dfSZhong Wang 
9732a8164dfSZhong Wang 	p = ((fct_els_t *)login->cmd_specific)->els_req_payload;
9742a8164dfSZhong Wang 	p[0] = ELS_OP_PLOGI;
9752a8164dfSZhong Wang 	p[4] = 0x20;
9762a8164dfSZhong Wang 	p[5] = 0x20;
9772a8164dfSZhong Wang 	p[7] = 3;
9782a8164dfSZhong Wang 	p[8] = 0x88;
9792a8164dfSZhong Wang 	p[10] = 8;
9802a8164dfSZhong Wang 	p[13] = 0xff; p[15] = 0x1f;
9812a8164dfSZhong Wang 	p[18] = 7; p[19] = 0xd0;
9822a8164dfSZhong Wang 
9832a8164dfSZhong Wang 	bcopy(port->port_pwwn, p + 20, 8);
9842a8164dfSZhong Wang 	bcopy(port->port_nwwn, p + 28, 8);
9852a8164dfSZhong Wang 
9862a8164dfSZhong Wang 	p[68] = 0x80;
9872a8164dfSZhong Wang 	p[74] = 8;
9882a8164dfSZhong Wang 	p[77] = 0xff;
9892a8164dfSZhong Wang 	p[81] = 1;
9902a8164dfSZhong Wang 
9912a8164dfSZhong Wang 	return (FCT_SUCCESS);
9922a8164dfSZhong Wang }
9932a8164dfSZhong Wang 
9942a8164dfSZhong Wang /*
9952a8164dfSZhong Wang  * Called by: fcoet_register_remote_port
9962a8164dfSZhong Wang  */
9972a8164dfSZhong Wang /* ARGSUSED */
9982a8164dfSZhong Wang static fct_status_t
fcoet_fill_plogi_resp(fct_local_port_t * port,fct_remote_port_t * rp,fct_cmd_t * login)9992a8164dfSZhong Wang fcoet_fill_plogi_resp(fct_local_port_t *port, fct_remote_port_t *rp,
10002a8164dfSZhong Wang     fct_cmd_t *login)
10012a8164dfSZhong Wang {
10022a8164dfSZhong Wang 	uint8_t *p;
10032a8164dfSZhong Wang 	/*
10042a8164dfSZhong Wang 	 * ACC
10052a8164dfSZhong Wang 	 */
10062a8164dfSZhong Wang 	p = ((fct_els_t *)login->cmd_specific)->els_req_payload;
10072a8164dfSZhong Wang 	p[0] = ELS_OP_ACC;
10082a8164dfSZhong Wang 	p[4] = 0x20;
10092a8164dfSZhong Wang 	p[5] = 0x20;
10102a8164dfSZhong Wang 	p[7] = 0x0A;
10112a8164dfSZhong Wang 	p[10] = 0x05;
10122a8164dfSZhong Wang 	p[11] = 0xAC;
10132a8164dfSZhong Wang 
10142a8164dfSZhong Wang 	bcopy(port->port_pwwn, p + 20, 8);
10152a8164dfSZhong Wang 	bcopy(port->port_nwwn, p + 28, 8);
10162a8164dfSZhong Wang 
10172a8164dfSZhong Wang 	p[68] = 0x88;
10182a8164dfSZhong Wang 	return (FCT_SUCCESS);
10192a8164dfSZhong Wang }
10202a8164dfSZhong Wang 
10212a8164dfSZhong Wang static fct_status_t
fcoet_send_good_status(fct_cmd_t * cmd)10222a8164dfSZhong Wang fcoet_send_good_status(fct_cmd_t *cmd)
10232a8164dfSZhong Wang {
10242a8164dfSZhong Wang 	fcoe_frame_t	*frm;
10252a8164dfSZhong Wang 	int		 raw_frame_size;
10262a8164dfSZhong Wang 
10272a8164dfSZhong Wang 	raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t);
10282a8164dfSZhong Wang 	frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
10292a8164dfSZhong Wang 	    raw_frame_size, NULL);
10302a8164dfSZhong Wang 	if (frm == NULL) {
10312a8164dfSZhong Wang 		ASSERT(0);
10322a8164dfSZhong Wang 		return (FCT_FAILURE);
10332a8164dfSZhong Wang 	} else {
10342a8164dfSZhong Wang 		fcoet_init_tfm(frm, CMD2XCH(cmd));
10352a8164dfSZhong Wang 		bzero(frm->frm_payload, frm->frm_payload_size);
10362a8164dfSZhong Wang 		/*
10372a8164dfSZhong Wang 		 * lock the xchg to avoid being released (by abort)
10382a8164dfSZhong Wang 		 * after sent out and before release
10392a8164dfSZhong Wang 		 */
10402a8164dfSZhong Wang 		FCOET_BUSY_XCHG(CMD2XCH(cmd));
10412a8164dfSZhong Wang 	}
10422a8164dfSZhong Wang 
10432a8164dfSZhong Wang 	/*
10442a8164dfSZhong Wang 	 * Fill fc frame header
10452a8164dfSZhong Wang 	 */
10462a8164dfSZhong Wang 	FFM_R_CTL(0x07, frm);
10472a8164dfSZhong Wang 	FRM2TFM(frm)->tfm_rctl = 0x07;
10482a8164dfSZhong Wang 	FFM_TYPE(0x08, frm);
10492a8164dfSZhong Wang 	FFM_F_CTL(0x990000, frm);
10502a8164dfSZhong Wang 	FFM_OXID(cmd->cmd_oxid, frm);
10512a8164dfSZhong Wang 	FFM_RXID(cmd->cmd_rxid, frm);
10522a8164dfSZhong Wang 	FFM_S_ID(cmd->cmd_lportid, frm);
10532a8164dfSZhong Wang 	FFM_D_ID(cmd->cmd_rportid, frm);
10542a8164dfSZhong Wang 	FFM_SEQ_ID(0x01, frm);
10552a8164dfSZhong Wang 
10562a8164dfSZhong Wang 	CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
10572a8164dfSZhong Wang 
10582a8164dfSZhong Wang 	return (FCT_SUCCESS);
10592a8164dfSZhong Wang }
1060