mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Oliver Smith-Denny <osmithde@cisco.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Sesidhar Baddela <sebaddel@cisco.com>,
	Gian Carlo Boffa <gcboffa@cisco.com>,
	linux-scsi@vger.kernel.org, target-devel@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	Oliver Smith-Denny <osmithde@cisco.com>
Subject: [PATCH 04/10] staging: fnic2 add fdls system
Date: Thu, 5 Apr 2018 14:19:28 -0700	[thread overview]
Message-ID: <20180405211928.GE12584@osmithde-lnx.cisco.com> (raw)
In-Reply-To: <20180405211519.GA12584@osmithde-lnx.cisco.com>

These files contain Fibre Channel discovery handling
and fabric services.

Signed-off-by: Oliver Smith-Denny <osmithde@cisco.com>
Signed-off-by: Sesidhar Baddela <sebaddel@cisco.com>
Signed-off-by: Anil Chintalapati <achintal@cisco.com>
Signed-off-by: Arulprabhu Ponnusamy <arulponn@cisco.com>
Signed-off-by: Gian Carlo Boffa <gcboffa@cisco.com>
Co-Developed-by: Arulprabhu Ponnusamy <arulponn@cisco.com>
Co-Developed-by: Gian Carlo Boffa <gcboffa@cisco.com>
Co-Developed-by: Oliver Smith-Denny <osmithde@cisco.com>
---
 drivers/staging/fnic2/src/fdls_disc.c  | 1539 ++++++++++++++++++++++++++++++++
 drivers/staging/fnic2/src/fdls_fc.h    |  403 +++++++++
 drivers/staging/fnic2/src/fdls_if.c    | 1254 ++++++++++++++++++++++++++
 drivers/staging/fnic2/src/fnic2_fdls.h |  232 +++++
 4 files changed, 3428 insertions(+)
 create mode 100644 drivers/staging/fnic2/src/fdls_disc.c
 create mode 100644 drivers/staging/fnic2/src/fdls_fc.h
 create mode 100644 drivers/staging/fnic2/src/fdls_if.c
 create mode 100644 drivers/staging/fnic2/src/fnic2_fdls.h

diff --git a/drivers/staging/fnic2/src/fdls_disc.c b/drivers/staging/fnic2/src/fdls_disc.c
new file mode 100644
index 0000000..e955116
--- /dev/null
+++ b/drivers/staging/fnic2/src/fdls_disc.c
@@ -0,0 +1,1539 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright 2018 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "fnic2.h"
+#include "fdls_fc.h"
+#include "fnic2_fdls.h"
+
+static void fdls_send_rpn_id(struct fnic2_lport *lport);
+struct fnic2_rport *fnic2_find_rport_by_fcid(struct fnic2_lport *lport, uint32_t fcid);
+struct fnic2_rport *fnic2_find_rport(struct fnic2_lport *lport, uint64_t wwpn);
+void fnic2_fdls_remove_rport(struct fnic2_lport *lport, struct fnic2_rport *rport);
+struct fnic2_rport *fnic2_fdls_add_rport(struct fnic2_lport *lport, struct fnic2_rport *rport);
+struct fnic2_rport *fdls_create_rport(struct fnic2_lport *lport, uint32_t fcid, uint64_t wwpn);
+void fdls_delete_rport(struct fnic2_lport *lport, struct fnic2_rport *rport);
+
+extern int fnic2_session_create(struct fnic2 *fnic2, struct fnic2_rport *rport);
+
+/* Frame initialization */
+
+/*
+ * Variables:
+ * s_id
+ */
+struct fc_els fnic2_flogi_req = {
+	.fchdr = {.r_ctl = 0x22, .d_id = {0xFF, 0xFF, 0xFE},
+		.type = 0x01, .f_ctl = {FNIC2_ELS_REQ_FCTL, 0x00, 0x00},
+	.ox_id = FNIC2_FLOGI_OXID, .rx_id = 0xFFFF},
+	.command = FC_ELS_FLOGI_REQ,
+	.u.csp_flogi = {.fc_ph_ver = FNIC2_FC_PH_VER,
+	.b2b_credits = FNIC2_FC_B2B_CREDIT,
+	.b2b_rdf_size = FNIC2_FC_B2B_RDF_SZ},
+	.spc3 = {0x88, 0x00}
+};
+
+/*
+ * Variables:
+ * s_id, d_id(nport logins), ox_id(nport logins), nport_name, node_name
+ */
+struct fc_els fnic2_plogi_req = {
+	.fchdr = {.r_ctl = 0x22, .d_id = {0xFF, 0xFF, 0xFC}, .type = 0x01,
+		.f_ctl = {FNIC2_ELS_REQ_FCTL, 0x00, 0x00}, .ox_id = FNIC2_PLOGI_FABRIC_OXID,
+		.rx_id = 0xFFFF},
+	.command = FC_ELS_PLOGI_REQ,
+	.u.csp_plogi = {.fc_ph_ver = FNIC2_FC_PH_VER,
+		.b2b_credits = FNIC2_FC_B2B_CREDIT, .features = 0x0080,
+		.b2b_rdf_size = FNIC2_FC_B2B_RDF_SZ,
+		.total_concur_seqs = FNIC2_FC_CONCUR_SEQS,
+		.ro_info = FNIC2_FC_RO_INFO, .e_d_tov = FNIC2_E_D_TOV},
+	.spc3 = {0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+		 0x00, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}
+};
+
+/*
+ * Variables:
+ * s_id, d_id(nport logins), ox_id(nport logins), nport_name, node_name
+ */
+struct fc_els fnic2_plogi_resp = {
+	.fchdr = {.r_ctl = 0x23, .type = 0x01,
+		.f_ctl = {FNIC2_ELS_REP_FCTL, 0x00, 0x00} },
+	.command = FC_LS_ACC,
+	.u.csp_plogi = {.fc_ph_ver = FNIC2_FC_PH_VER,
+		.b2b_credits = FNIC2_FC_B2B_CREDIT, .features = 0x0080,
+		.b2b_rdf_size = FNIC2_FC_B2B_RDF_SZ,
+	.total_concur_seqs = FNIC2_FC_CONCUR_SEQS,
+	.ro_info = FNIC2_FC_RO_INFO, .e_d_tov = FNIC2_E_D_TOV},
+	.spc3 = {0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+		 0x00, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}
+};
+
+/*
+ * Variables:
+ * s_id, port_id, port_name
+ */
+struct fc_rpn_id fnic2_rpn_id_req = {
+	.fchdr = {.r_ctl = 0x02, .d_id = {0xFF, 0xFF, 0xFC}, .type = 0x20,
+		.f_ctl = {FNIC2_ELS_REQ_FCTL, 0x00, 0x00}, .ox_id = FNIC2_RPN_REQ_OXID,
+		.rx_id = 0xFFFF},
+	.fc_ct_hdr = {.rev = 0x01, .fs_type = 0xFC, .fs_subtype = 0x02,
+			.command = FC_CT_RPN_CMD}
+};
+
+/*
+ * Variables:
+ * s_id, port_id, port_name
+ */
+struct fc_rft_id fnic2_rft_id_req = {
+	.fchdr = {.r_ctl = 0x02, .d_id = {0xFF, 0xFF, 0xFC}, .type = 0x20,
+		.f_ctl = {FNIC2_ELS_REQ_FCTL, 0x00, 0x00}, .ox_id = FNIC2_RFT_REQ_OXID,
+		.rx_id = 0xFFFF},
+	.fc_ct_hdr = {.rev = 0x01, .fs_type = 0xFC, .fs_subtype = 0x02,
+			.command = FC_CT_RFT_CMD}
+};
+
+/*
+ * Variables:
+ * s_id, port_id, port_name
+ */
+struct fc_rff_id fnic2_rff_id_req = {
+	.fchdr = {.r_ctl = 0x02, .d_id = {0xFF, 0xFF, 0xFC}, .type = 0x20,
+		.f_ctl = {FNIC2_ELS_REQ_FCTL, 0x00, 0x00}, .ox_id = FNIC2_RFF_REQ_OXID,
+		.rx_id = 0xFFFF},
+	.fc_ct_hdr = {.rev = 0x01, .fs_type = 0xFC, .fs_subtype = 0x02,
+			.command = FC_CT_RFF_CMD},
+	.tgt = 0x1,
+	.fc4_type = 0x8
+};
+
+/*
+ * Variables:
+ * d_id, s_id, ox_id
+ */
+struct fc_els_prli fnic2_prli_resp = {
+	.fchdr = {.r_ctl = 0x23, .type = 0x01,
+		.f_ctl = {FNIC2_ELS_REP_FCTL, 0x00, 0x00} },
+	.command = FC_LS_ACC,
+	.page_len = 16,
+	.payload_len = 0x1400,
+	.sp = {.type = 0x08, .flags = 0x0021, .csp = 0x12040000}
+};
+
+/*
+ * Variables:
+ * d_id, ox_id, rx_id
+ */
+struct fc_els_acc fnic2_els_acc = {
+	.fchdr = {.r_ctl = 0x23, .d_id = {0xFF, 0xFF, 0xFD}, .type = 0x01,
+		.f_ctl = {FNIC2_ELS_REP_FCTL, 0x00, 0x00} },
+	.command = FC_LS_ACC,
+};
+
+struct fc_els_reject fnic2_els_rjt = {
+	.fchdr = {.r_ctl = 0x23, .type = 0x01, .f_ctl = {FNIC2_ELS_REP_FCTL, 0x00, 0x00} },
+	.command = FC_LS_REJ,
+};
+
+/*
+ * Variables:
+ * d_id, ox_id, rx_id
+ */
+struct fc_abts_ba_acc fnic2_ba_acc = {
+	.fchdr = {.r_ctl = 0x84,
+		.f_ctl = {FNIC2_FCP_RSP_FCTL, 0x00, 0x00}},
+	.low_seq_cnt = 0, .high_seq_cnt = 0xFFFF,
+};
+
+
+/*
+ * Variables:
+ * d_id, ox_id, rx_id, fcid, wwpn
+ */
+struct fc_logo_req fnic2_logo_req = {
+	.fchdr = {.r_ctl = 0x22, .type = 0x01,
+		.f_ctl = {FNIC2_ELS_REQ_FCTL, 0x00, 0x00} },
+	.command = FC_ELS_LOGO,
+};
+
+#define FDLS_TGT_OXID_POOL_SZ   (0x800)
+#define FDLS_TGT_OXID_BLOCK_SZ  (0x200)
+#define FDLS_PLOGI_OXID_BASE    (0x2000)
+#define FDLS_PRLI_OXID_BASE     (0x2200)
+
+uint8_t tgt_ox_id_pool[FDLS_TGT_OXID_POOL_SZ];
+
+/* Private Functions */
+static void fnic2_fdls_start_plogi(struct fnic2_lport *lport);
+
+static void fdls_init_tgt_ox_id_pool(void)
+{
+	memset(tgt_ox_id_pool, 0, FDLS_TGT_OXID_POOL_SZ);
+}
+
+static uint16_t fdls_alloc_tgt_ox_id(uint16_t base)
+{
+	int i;
+	int start, end;
+
+	start = base - FDLS_PLOGI_OXID_BASE;
+	end = start + FDLS_TGT_OXID_BLOCK_SZ;
+
+	for (i = start; i < end; i++) {
+		if (tgt_ox_id_pool[i] == 0) {
+			tgt_ox_id_pool[i] = 1;
+			return (i + FDLS_PLOGI_OXID_BASE);
+		}
+	}
+	return 0xFFFF;
+}
+static void fdls_free_tgt_ox_id(uint16_t ox_id)
+{
+	if (tgt_ox_id_pool[ox_id - FDLS_PLOGI_OXID_BASE] != 1)
+		pr_debug("%s Free unused ox_id:%x\n",
+			 __func__, ox_id);
+	tgt_ox_id_pool[ox_id - FDLS_PLOGI_OXID_BASE] = 0;
+}
+
+static void fdls_process_flogi_rsp(struct fnic2_lport *lport, struct fc_hdr *fchdr, void *rx_frame)
+{
+	struct fnic2_fdls_fabric *fabric = &lport->fabric;
+	struct fc_els *flogi_rsp = (struct fc_els *)fchdr;
+	uint8_t *fcid;
+	int rdf_size;
+	struct fc_els_reject *els_rjt;
+	uint8_t fcmac[6] = {0x0E, 0XFC, 0x00, 0x00, 0x00, 0x00};
+
+	pr_debug("lport 0x%pK fnic2_fcoe_process_flogi_resp\n", lport);
+
+	if (fabric->state != FDLS_STATE_FABRIC_FLOGI) {
+		pr_debug("Flogi resp recvd in state %d. Dropping\n",
+			fabric->state);
+		return;
+	}
+
+	switch (flogi_rsp->command) {
+	case FC_LS_ACC:
+
+		if (lport->fabric.timer_pending) {
+			pr_debug("lport 0x%pK Canceling fabric disc timer\n", lport);
+			del_timer_sync(&fabric->retry_timer);
+		}
+		lport->fabric.timer_pending = 0;
+		lport->fabric.retry_counter = 0;
+
+		fcid = fchdr->d_id;
+		lport->fcid = ntoh24(fcid);
+
+		pr_debug("Flogi resp Accepted: 0x%08x\n", lport->fcid);
+
+		/* Learn the Service Params */
+		rdf_size = ntohl(flogi_rsp->u.csp_flogi.b2b_rdf_size);
+		if ((rdf_size >= FNIC2_FCOE_MIN_FRAME_SZ)  &&
+		    (rdf_size < FNIC2_FCOE_MAX_FRAME_SZ))
+			lport->mfs = rdf_size;
+
+		pr_debug("mfs from fabric:%d, set:%d\n", rdf_size, lport->mfs);
+		lport->r_a_tov = ntohl(flogi_rsp->u.csp_flogi.r_a_tov);
+		lport->e_d_tov = ntohl(flogi_rsp->u.csp_flogi.e_d_tov);
+
+		if (flogi_rsp->u.csp_flogi.features & FNIC2_FC_EDTOV_NSEC)
+			lport->e_d_tov = lport->e_d_tov / FNIC2_NSEC_TO_MSEC;
+
+		pr_debug("from fabric:%d, %d\n", lport->r_a_tov, lport->e_d_tov);
+
+		fnic2_fdls_learn_fcoe_macs(lport, rx_frame, fcid);
+
+		if (fnic2_fdls_register_portid(lport, lport->fcid, rx_frame) !=
+		    0) {
+			pr_debug("lport 0x%pK flogi registration failed\n", lport);
+			break;
+		}
+
+		memcpy(&fcmac[3], fcid, 3);
+		pr_debug("Adding vnic_dev_mac addr:%02x %02x %02x %02x %02x %02x\n",
+			fcmac[0], fcmac[1], fcmac[2], fcmac[3], fcmac[4], fcmac[5]);
+		vnic_dev_add_addr(lport->fnic2->vdev, fcmac);
+
+		fnic2_fdls_start_plogi(lport);
+		break;
+
+	case FC_LS_REJ:
+		els_rjt = (struct fc_els_reject *)fchdr;
+		if (((els_rjt->reason_code == FC_ELS_RJT_LOGICAL_BUSY) ||
+		    (els_rjt->reason_code == FC_ELS_RJT_BUSY)) &&
+		    (fabric->retry_counter < lport->max_flogi_retries)) {
+
+			pr_debug("lport 0x%pK Flogi returned FC_LS_REJ BUSY retry from timer routine..\n",
+				lport);
+
+			/*Retry Flogi again from the timer routine.*/
+			fabric->flags |= FNIC2_FDLS_RETRY_FRAME;
+			// change the name , make it common
+		} else {
+			pr_debug("lport 0x%pK Flogi returned FC_LS_REJ... halting discovery.\n", lport);
+			if (fabric->timer_pending) {
+				pr_debug("lport 0x%pK Canceling fabric disc timer\n", lport);
+				del_timer_sync(&fabric->retry_timer);
+			}
+			fabric->timer_pending = 0;
+			fabric->retry_counter = 0;
+		}
+		break;
+
+	default:
+		pr_debug("Flogi resp Not Accepted: %x\n", flogi_rsp->command);
+		/* TBD Handle it */
+		break;
+	}
+}
+
+static void fdls_process_fabric_plogi_rsp(struct fnic2_lport *lport, struct fc_hdr *fchdr)
+{
+	struct fc_els *plogi_rsp = (struct fc_els *)fchdr;
+	struct fc_els_reject *els_rjt = (struct fc_els_reject *)fchdr;
+
+	pr_debug("lport 0x%pK fnic2_fcoe_process_fabric_plogi_resp", lport);
+	if (lport->fabric.state != FDLS_STATE_FABRIC_PLOGI) {
+		pr_debug("plogi resp recvd in state %d. dropping\n",
+			 lport->fabric.state);
+		return;
+	}
+
+	switch (plogi_rsp->command) {
+	case FC_LS_ACC:
+		if (lport->fabric.timer_pending) {
+			pr_debug("lport 0x%pK Canceling fabric disc timer", lport);
+			del_timer_sync(&(lport->fabric.retry_timer));
+		}
+		lport->fabric.timer_pending = 0;
+		lport->fabric.retry_counter = 0;
+		fdls_send_rpn_id(lport);
+		lport->fabric.state = FDLS_STATE_RPN_ID;
+		break;
+
+	case FC_LS_REJ:
+		if (((els_rjt->reason_code == FC_ELS_RJT_LOGICAL_BUSY) ||
+			(els_rjt->reason_code == FC_ELS_RJT_BUSY)) &&
+			(lport->fabric.retry_counter < lport->max_plogi_retries)) {
+			pr_debug("lport 0x%pK Fabric plogi returned FC_LS_REJ BUSY retry from timer routine..\n", lport);
+
+			/*Retry Fabric Plogi again from the timer routine.*/
+			lport->fabric.flags |= FNIC2_FDLS_RETRY_FRAME;
+			return;
+		} else {
+			pr_debug("lport 0x%pK Fabric Plogi returned FC_LS_REJ...halting discovery.\n", lport);
+			if (lport->fabric.timer_pending) {
+				pr_debug("lport 0x%pK Canceling fabric disc timer\n", lport);
+				del_timer_sync(&(lport->fabric.retry_timer));
+			}
+
+			lport->fabric.timer_pending = 0;
+			lport->fabric.retry_counter = 0;
+			return;
+		}
+		break;
+
+	default:
+		pr_debug("plogi resp Not Accepted: %x", plogi_rsp->command);
+		/* TBD Handle it */
+		break;
+	}
+}
+
+void fdls_send_logout(struct fnic2_lport *lport, struct fc_hdr *fchdr)
+{
+	struct fc_logo_req logo;
+	uint8_t s_id[3];
+
+	memcpy(&logo, &fnic2_logo_req, sizeof(struct fc_logo_req));
+
+	hton24(s_id, lport->fcid);
+
+	memcpy(logo.fchdr.s_id, s_id, 3);
+	memcpy(logo.fchdr.d_id, fchdr->s_id, 3);
+	logo.fchdr.ox_id = FNIC2_LOGO_REQ_OXID;
+
+	memcpy(&logo.fcid, s_id, 3);
+	logo.wwpn = lport->wwpn;
+
+	fnic2_send_fcoe_frame(lport, &logo, sizeof(struct fc_logo_req));
+}
+
+/*
+ * fdls_construct_logo_req - build a logo request for session timeout
+ *
+ * @lport - the fnic2 local fc port
+ * @fchdr - the fc_hdr from the machine we want to logo with
+ * @sess - the session that will hold the logo request
+ *
+ * This function is used primarily in the case of a session timeout
+ * where we don't have an explicit lport or fchdr, so we need to
+ * construct one at the time that we initiate a session timer.
+ * The logo will then be used in the event of a session
+ * timeout and be freed from there.
+ */
+void fdls_construct_logo_req(struct fnic2_lport *lport,
+			     struct fc_hdr *fchdr,
+			     struct fnic2_sess *sess)
+{
+	struct fc_logo_req logo;
+	uint8_t s_id[3];
+
+	memcpy(&logo, &fnic2_logo_req, sizeof(struct fc_logo_req));
+
+	hton24(s_id, lport->fcid);
+
+	memcpy(logo.fchdr.s_id, s_id, 3);
+        memcpy(logo.fchdr.d_id, fchdr->s_id, 3);
+        logo.fchdr.ox_id = FNIC2_LOGO_REQ_OXID;
+
+	memcpy(&logo.fcid, s_id, 3);
+	logo.wwpn = lport->wwpn;
+
+	memcpy(&sess->timer_logo_req, &logo, sizeof(struct fc_logo_req));
+
+	return;
+
+}
+
+static void fdls_send_logo_resp(struct fnic2_lport *lport, struct fc_hdr *req_fchdr)
+{
+	struct fc_els_acc logo_resp;
+	uint16_t  ox_id;
+	uint8_t fcid[3];
+
+	memcpy(&logo_resp, &fnic2_els_acc, sizeof(struct fc_els_acc));
+
+	hton24(fcid, lport->fcid);
+	memcpy(&logo_resp.fchdr.s_id, fcid, 3);
+
+	ox_id = req_fchdr->ox_id;
+	logo_resp.fchdr.ox_id = ox_id;
+
+	logo_resp.fchdr.rx_id = FNIC2_LOGO_RESP_OXID; //TBD_REVISIT
+	fnic2_send_fcoe_frame(lport, &logo_resp, sizeof(struct fc_els_acc));
+}
+
+static void fdls_start_fabric_timer(struct fnic2_lport *lport)
+{
+	uint32_t fabric_tov;
+
+	lport->fabric.retry_counter++;
+	fabric_tov = jiffies + msecs_to_jiffies(2 * lport->e_d_tov);
+	mod_timer(&lport->fabric.retry_timer, round_jiffies(fabric_tov));
+	lport->fabric.timer_pending = 1;
+}
+
+static void fdls_start_abort_timer(struct fnic2_lport *lport)
+{
+	uint32_t abort_tov;
+
+	abort_tov = jiffies + msecs_to_jiffies(2 * lport->r_a_tov);
+	mod_timer(&lport->fabric.retry_timer, round_jiffies(abort_tov));
+	lport->fabric.timer_pending = 1;
+}
+
+static void fdls_send_fabric_abts(struct fnic2_lport *lport)
+{
+
+	uint8_t fcid[3];
+	struct fc_hdr  fc_ABTS_s = {
+		.r_ctl  = 0x81, //ABTS
+		.d_id    = {0xFF, 0xFF, 0xFF},
+		.cs_ctl = 0x00,
+		.s_id = {0x00, 0x00, 0x00},
+		.type   = 0x00,
+		.f_ctl  = {FNIC2_REQ_ABTS_FCTL, 0x00, 0x00},
+		.seq_id = 0x00,
+		.df_ctl = 0x00,
+		.seq_cnt = 0x0000,
+		.rx_id  = 0xFFFF,
+		.param  = 0x00000000, // bit:0 =0 Abort a exchange
+	};
+
+	struct fc_hdr *pfc_ABTS = &fc_ABTS_s;
+
+	switch (lport->fabric.state) {
+	case FDLS_STATE_FABRIC_FLOGI:
+		fc_ABTS_s.ox_id = FNIC2_FLOGI_OXID;
+		fc_ABTS_s.d_id[2] = 0xFE;
+		lport->fabric.flags |= FNIC2_FDLS_FABRIC_ABORT_ISSUED;
+		break;
+
+	case FDLS_STATE_FABRIC_PLOGI:
+		hton24(fcid, lport->fcid);
+		memcpy(pfc_ABTS->s_id, fcid, 3);
+		fc_ABTS_s.ox_id = FNIC2_PLOGI_FABRIC_OXID;
+		fc_ABTS_s.d_id[2] = 0xFC;
+		lport->fabric.flags |= FNIC2_FDLS_FABRIC_ABORT_ISSUED;
+		break;
+
+	case FDLS_STATE_RPN_ID:
+		hton24(fcid, lport->fcid);
+		memcpy(pfc_ABTS->s_id, fcid, 3);
+		fc_ABTS_s.ox_id = FNIC2_RPN_REQ_OXID;
+		fc_ABTS_s.d_id[2] = 0xFC;
+		lport->fabric.flags |= FNIC2_FDLS_FABRIC_ABORT_ISSUED;
+		break;
+	case FDLS_STATE_REGISTER_FC4_TYPES:
+		hton24(fcid, lport->fcid);
+		memcpy(pfc_ABTS->s_id, fcid, 3);
+		fc_ABTS_s.ox_id = FNIC2_RFT_REQ_OXID;
+		fc_ABTS_s.d_id[2] = 0xFC;
+		lport->fabric.flags |= FNIC2_FDLS_FABRIC_ABORT_ISSUED;
+		break;
+	case FDLS_STATE_REGISTER_FC4_FEATURES:
+		hton24(fcid, lport->fcid);
+		memcpy(pfc_ABTS->s_id, fcid, 3);
+		fc_ABTS_s.ox_id = FNIC2_RFF_REQ_OXID;
+		fc_ABTS_s.d_id[2] = 0xFC;
+		lport->fabric.flags |= FNIC2_FDLS_FABRIC_ABORT_ISSUED;
+		break;
+	default:
+		break;
+	}
+	pr_debug("%s %d\n", __func__, lport->fabric.state);
+
+	fnic2_send_fcoe_frame(lport, &fc_ABTS_s, sizeof(struct fc_hdr));
+	fdls_start_abort_timer(lport);
+}
+
+static void fdls_send_fabric_flogi(struct fnic2_lport *lport)
+{
+	struct fc_els flogi;
+
+	memcpy(&flogi, &fnic2_flogi_req, sizeof(struct fc_els));
+	flogi.nport_name = cpu_to_be64(lport->wwpn);
+	flogi.node_name = cpu_to_be64(lport->wwnn);
+	flogi.u.csp_flogi.b2b_rdf_size = htons(lport->mfs);
+	flogi.u.csp_flogi.r_a_tov = htonl(lport->r_a_tov);
+	flogi.u.csp_flogi.e_d_tov = htonl(lport->e_d_tov);
+
+	fnic2_send_fcoe_frame(lport, &flogi, sizeof(struct fc_els));
+	fdls_start_fabric_timer(lport);
+}
+
+static void fdls_send_fabric_plogi(struct fnic2_lport *lport)
+{
+	struct fc_els plogi;
+	struct fc_hdr *fchdr = &plogi.fchdr;
+	uint8_t fcid[3];
+
+	pr_debug("%s lport 0x%pK\n", __func__, lport);
+
+	memcpy(&plogi, &fnic2_plogi_req, sizeof(struct fc_els));
+
+	hton24(fcid, lport->fcid);
+
+	memcpy(fchdr->s_id, fcid, 3);
+	plogi.nport_name = cpu_to_be64(lport->wwpn);
+	plogi.node_name = cpu_to_be64(lport->wwnn);
+
+	fnic2_send_fcoe_frame(lport, &plogi, sizeof(struct fc_els));
+	fdls_start_fabric_timer(lport);
+}
+
+static void fdls_send_rpn_id(struct fnic2_lport *lport)
+{
+	struct fc_rpn_id rpn_id;
+	uint8_t fcid[3];
+
+	memcpy(&rpn_id, &fnic2_rpn_id_req, sizeof(struct fc_rpn_id));
+
+	hton24(fcid, lport->fcid);
+
+	memcpy(&rpn_id.fchdr.s_id, fcid, 3);
+	memcpy(rpn_id.port_id, fcid, 3);
+	rpn_id.port_name = cpu_to_be64(lport->wwpn);
+
+	fnic2_send_fcoe_frame(lport, &rpn_id, sizeof(struct fc_rpn_id));
+	fdls_start_fabric_timer(lport);
+}
+
+static void fdls_send_register_fc4_types(struct fnic2_lport *lport)
+{
+	struct fc_rft_id rft_id;
+	uint8_t fcid[3];
+
+	memcpy(&rft_id, &fnic2_rft_id_req, sizeof(struct fc_rft_id));
+
+	hton24(fcid, lport->fcid);
+
+	memcpy(&rft_id.fchdr.s_id, fcid, 3);
+	memcpy(rft_id.port_id, fcid, 3);
+	rft_id.fc4_types[2] = 1;
+	fnic2_send_fcoe_frame(lport, &rft_id, sizeof(struct fc_rft_id));
+	fdls_start_fabric_timer(lport);
+}
+
+static void fdls_send_register_fc4_features(struct fnic2_lport *lport)
+{
+	struct fc_rff_id rff_id;
+	uint8_t fcid[3];
+
+	memcpy(&rff_id, &fnic2_rff_id_req, sizeof(struct fc_rff_id));
+
+	hton24(fcid, lport->fcid);
+
+	memcpy(&rff_id.fchdr.s_id, fcid, 3);
+	memcpy(rff_id.port_id, fcid, 3);
+
+	fnic2_send_fcoe_frame(lport, &rff_id, sizeof(struct fc_rff_id));
+	fdls_start_fabric_timer(lport);
+}
+
+static void fdls_process_rpn_id_rsp(struct fnic2_lport *lport, struct fc_hdr *fchdr)
+{
+	struct fnic2_fdls_fabric *fdls = &lport->fabric;
+	struct fc_rpn_id *rpn_rsp = (struct fc_rpn_id *)fchdr;
+	struct fc_els_reject *els_rjt = (struct fc_els_reject *)fchdr;
+	uint16_t rsp;
+
+	rsp = rpn_rsp->fc_ct_hdr.command;
+	pr_debug("%s 0x%04x\n", __func__, (uint32_t)rsp);
+
+	switch (rsp) {
+	case FC_CT_ACC:
+		if (lport->fabric.timer_pending) {
+			pr_debug("lport 0x%pK Canceling fabric disc timer\n", lport);
+			del_timer_sync(&fdls->retry_timer);
+		}
+		lport->fabric.timer_pending = 0;
+		fdls->retry_counter = 0;
+		fdls_send_register_fc4_types(lport);
+		fdls->state = FDLS_STATE_REGISTER_FC4_TYPES;
+		break;
+	case FC_LS_REJ:
+		if (((els_rjt->reason_code == FC_ELS_RJT_LOGICAL_BUSY) ||
+			(els_rjt->reason_code == FC_ELS_RJT_BUSY)) &&
+			(fdls->retry_counter < FDLS_RETRY_COUNT)) {
+
+			pr_debug("lport 0x%pK Rpn_id returned FC_LS_REJ BUSY retry from timer routine..\n", lport);
+
+		/*Retry again from the timer routine.*/
+			fdls->flags |= FNIC2_FDLS_RETRY_FRAME;
+		} else {
+			pr_debug("lport 0x%pK Rpn_id returned FC_LS_REJ...halting discovery.\n", lport);
+			if (fdls->timer_pending) {
+				pr_debug("lport 0x%pK Canceling fabric disc timer\n", lport);
+				del_timer_sync(&fdls->retry_timer);
+			}
+			fdls->timer_pending = 0;
+			fdls->retry_counter = 0;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void fdls_process_rft_id_rsp(struct fnic2_lport *lport, struct fc_hdr *fchdr)
+{
+	struct fnic2_fdls_fabric *fdls = &lport->fabric;
+	struct fc_rft_id *rft_rsp = (struct fc_rft_id *)fchdr;
+	struct fc_els_reject *els_rjt = (struct fc_els_reject *)fchdr;
+	uint16_t rsp;
+
+	rsp = rft_rsp->fc_ct_hdr.command;
+	pr_debug("%s 0x%04x\n", __func__, (uint32_t)rsp);
+
+	switch (rsp) {
+	case FC_CT_ACC:
+		if (lport->fabric.timer_pending) {
+			pr_debug("lport 0x%pK Canceling fabric disc timer\n", lport);
+			del_timer_sync(&fdls->retry_timer);
+		}
+		lport->fabric.timer_pending = 0;
+		fdls->retry_counter = 0;
+		fdls->state = FDLS_STATE_REGISTER_FC4_FEATURES;
+		break;
+	case FC_LS_REJ:
+		if (((els_rjt->reason_code == FC_ELS_RJT_LOGICAL_BUSY) ||
+			(els_rjt->reason_code == FC_ELS_RJT_BUSY)) &&
+			(fdls->retry_counter < FDLS_RETRY_COUNT)) {
+
+			pr_debug("lport 0x%pK rft_id returned FC_LS_REJ BUSY retry from timer routine..\n",
+				lport);
+
+			/*Retry again from the timer routine.*/
+			fdls->flags |= FNIC2_FDLS_RETRY_FRAME;
+		} else {
+			pr_debug("lport 0x%pK rft_id returned FC_LS_REJ...halting discovery.\n", lport);
+			if (fdls->timer_pending) {
+				pr_debug("lport 0x%pK Canceling fabric disc timer\n", lport);
+				del_timer_sync(&fdls->retry_timer);
+			}
+			fdls->timer_pending = 0;
+			fdls->retry_counter = 0;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void fdls_process_rff_id_rsp(struct fnic2_lport *lport, struct fc_hdr *fchdr)
+{
+	struct fnic2_fdls_fabric *fdls = &lport->fabric;
+	struct fc_rff_id *rff_rsp = (struct fc_rff_id *)fchdr;
+	struct fc_els_reject *els_rjt = (struct fc_els_reject *)fchdr;
+	uint16_t rsp;
+
+	rsp = rff_rsp->fc_ct_hdr.command;
+	pr_debug("%s 0x%04x\n", __func__, (uint32_t)rsp);
+
+	switch (rsp) {
+	case FC_CT_ACC:
+		if (lport->fabric.timer_pending) {
+			pr_debug("lport 0x%pK Canceling fabric disc timer\n", lport);
+			del_timer_sync(&fdls->retry_timer);
+		}
+		lport->fabric.timer_pending = 0;
+		fdls->retry_counter = 0;
+		// we are done
+		fdls->state = FDLS_STATE_TGT_ONLINE;
+		break;
+	case FC_LS_REJ:
+		if (((els_rjt->reason_code == FC_ELS_RJT_LOGICAL_BUSY) ||
+			(els_rjt->reason_code == FC_ELS_RJT_BUSY)) &&
+			(fdls->retry_counter < FDLS_RETRY_COUNT)) {
+
+			pr_debug("lport 0x%pK rff_id returned FC_LS_REJ BUSY retry from timer routine..\n", lport);
+
+			/*Retry again from the timer routine.*/
+			fdls->flags |= FNIC2_FDLS_RETRY_FRAME;
+		} else {
+			pr_debug("lport 0x%pK rff_id returned FC_LS_REJ...halting discovery.\n",
+				lport);
+			if (fdls->timer_pending) {
+				pr_debug("lport 0x%pK Canceling fabric disc timer\n", lport);
+				del_timer_sync(&fdls->retry_timer);
+			}
+			fdls->timer_pending = 0;
+			fdls->retry_counter = 0;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void fdls_error_fabric_disc(struct fnic2_lport *lport)
+{
+	pr_debug("FDLS discovery error from %d state\n", lport->fabric.state);
+
+	/* TBD_REVISIT what to do */
+
+}
+
+void fdls_fabric_timer_callback(struct timer_list *timer)
+{
+	struct fnic2_fdls_fabric *fabric = container_of(timer, struct fnic2_fdls_fabric, retry_timer);
+	struct fnic2_lport *lport = container_of(fabric, struct fnic2_lport, fabric);
+
+	pr_debug("%s %d %d %d %d\n", __func__,
+		lport->fabric.timer_pending, lport->fabric.state,
+		lport->fabric.retry_counter, lport->max_flogi_retries);
+
+
+	/* TBD - do we need this? timeout while rx frame in the queue? */
+	if (!lport->fabric.timer_pending)
+		return;
+
+	lport->fabric.timer_pending = 0;
+
+	/*The fabric state indicates which frames have time out, and we retry*/
+	switch (lport->fabric.state) {
+	case FDLS_STATE_FABRIC_FLOGI:
+		// Flogi received a LS_RJT with busy we retry from here
+		if ((lport->fabric.flags & FNIC2_FDLS_RETRY_FRAME) &&
+		    (lport->fabric.retry_counter < lport->max_flogi_retries)) {
+			lport->fabric.flags &= ~FNIC2_FDLS_RETRY_FRAME;
+			fdls_send_fabric_flogi(lport);
+			return;
+		}
+		// Flogi has time out 2*ed_tov send abts
+		if (!(lport->fabric.flags & FNIC2_FDLS_FABRIC_ABORT_ISSUED)) {
+			fdls_send_fabric_abts(lport);
+		} else {
+			/* Flogi ABTS have timed out and we have waited
+			 * (2 * ra_tov), we can retry safely with same
+			 * exchange id
+			 */
+			if (lport->fabric.retry_counter <
+			    lport->max_flogi_retries) {
+				lport->fabric.flags &=
+				    ~FNIC2_FDLS_FABRIC_ABORT_ISSUED;
+				fdls_send_fabric_flogi(lport);
+			} else {
+				fdls_error_fabric_disc(lport);
+			}
+		}
+		break;
+	case FDLS_STATE_FABRIC_PLOGI:
+		// Plogi received a LS_RJT with busy we retry from here
+		if ((lport->fabric.flags & FNIC2_FDLS_RETRY_FRAME) &&
+		    (lport->fabric.retry_counter < lport->max_plogi_retries)) {
+			lport->fabric.flags &= ~FNIC2_FDLS_RETRY_FRAME;
+			fdls_send_fabric_plogi(lport);
+			return;
+		}
+		// Plogi has time out 2*ed_tov send abts
+		if (!(lport->fabric.flags & FNIC2_FDLS_FABRIC_ABORT_ISSUED)) {
+			fdls_send_fabric_abts(lport);
+		} else {
+			/* plogi ABTS has timed out and we have waited
+			 * (2 * ra_tov) can retry safely with same
+			 * exchange id
+			 */
+			if (lport->fabric.retry_counter <
+			    lport->max_plogi_retries) {
+				lport->fabric.flags &=
+				    ~FNIC2_FDLS_FABRIC_ABORT_ISSUED;
+				fdls_send_fabric_plogi(lport);
+			} else {
+				fdls_error_fabric_disc(lport);
+			}
+		}
+		break;
+	case FDLS_STATE_RPN_ID:
+		//Rpn_id received a LS_RJT with busy we retry from here
+		if ((lport->fabric.flags & FNIC2_FDLS_RETRY_FRAME) &&
+		    (lport->fabric.retry_counter < FDLS_RETRY_COUNT)) {
+			lport->fabric.flags &= ~FNIC2_FDLS_RETRY_FRAME;
+			fdls_send_rpn_id(lport);
+			return;
+		}
+		// RPN have timed out send abts
+		if (!(lport->fabric.flags & FNIC2_FDLS_FABRIC_ABORT_ISSUED))
+			fdls_send_fabric_abts(lport);
+		else // ABTS has timed out (2*ra_tov)
+			fnic2_fdls_start_plogi(lport); //go back to fabric Plogi
+		break;
+	case FDLS_STATE_REGISTER_FC4_TYPES:
+		// Register FC4 types received a LS_RJT with busy we retry from
+		if ((lport->fabric.flags & FNIC2_FDLS_RETRY_FRAME) &&
+			(lport->fabric.retry_counter < FDLS_RETRY_COUNT)) {
+			lport->fabric.flags &= ~FNIC2_FDLS_RETRY_FRAME;
+			fdls_send_register_fc4_types(lport);
+			return;
+		}
+		break;
+	case FDLS_STATE_REGISTER_FC4_FEATURES:
+		// Register FC4 features received a LS_RJT with busy we retry from here
+		if ((lport->fabric.flags & FNIC2_FDLS_RETRY_FRAME) &&
+			(lport->fabric.retry_counter < FDLS_RETRY_COUNT)) {
+			lport->fabric.flags &= ~FNIC2_FDLS_RETRY_FRAME;
+			fdls_send_register_fc4_features(lport);
+			return;
+		}
+		// Register FC4 features have timed out send abts
+		if (!(lport->fabric.flags & FNIC2_FDLS_FABRIC_ABORT_ISSUED))
+			fdls_send_fabric_abts(lport);
+		else // ABTS has timed out (2*ra_tov)
+			fnic2_fdls_start_plogi(lport); //go back to fabric Plogi
+		break;
+	default:
+		break;
+	}
+}
+
+static void fnic2_fdls_start_flogi(struct fnic2_lport *lport)
+{
+	lport->fabric.retry_counter = 0;
+	fdls_send_fabric_flogi(lport);
+	lport->fabric.state = FDLS_STATE_FABRIC_FLOGI;
+	lport->fabric.flags = 0;
+}
+
+static void fnic2_fdls_start_plogi(struct fnic2_lport *lport)
+{
+	lport->fabric.retry_counter = 0;
+	fdls_send_fabric_plogi(lport);
+	lport->fabric.state = FDLS_STATE_FABRIC_PLOGI;
+	lport->fabric.flags &= ~FNIC2_FDLS_FABRIC_ABORT_ISSUED;
+}
+
+static void fdls_process_fabric_abts_rsp(struct fnic2_lport *lport, struct fc_hdr *fchdr)
+{
+	uint32_t s_id;
+	struct fc_abts_ba_acc *ba_acc = (struct fc_abts_ba_acc *)fchdr;
+	struct fc_abts_ba_rjt *ba_rjt;
+	uint32_t fabric_state = lport->fabric.state;
+
+	s_id = ntoh24(fchdr->s_id);
+	ba_rjt = (struct fc_abts_ba_rjt *)fchdr;
+
+	if (!((s_id == FC_DIR_SERVER) || (s_id == FC_DOMAIN_CONTR) ||
+		(s_id == FC_FABRIC_CONTROLLER))) {
+		pr_debug("fdls received abts_rsp with invalid SID %x.. dropping the frame.\n",
+			s_id);
+		return;
+	}
+
+	if (lport->fabric.timer_pending) {
+		pr_debug("lport 0x%pK Canceling fabric disc timer", lport);
+		del_timer_sync(&(lport->fabric.retry_timer));
+	}
+	lport->fabric.timer_pending = 0;
+	lport->fabric.flags &= ~FNIC2_FDLS_FABRIC_ABORT_ISSUED;
+
+	if (fchdr->r_ctl == FNIC2_BA_ACC_RCTL) {
+		pr_debug("fdls received abts_rsp BA_ACC for fabric_state %d ox_id %x\n",
+			fabric_state, ba_acc->ox_id);
+	} else if (fchdr->r_ctl == FNIC2_BA_RJT_RCTL) {
+		pr_debug("fdls received BA_RJT for fabric_state %d ox_id %x with reason code:%x reason code explanation:%x\n",
+			fabric_state, ba_rjt->fchdr.ox_id, ba_rjt->reason_code, ba_rjt->reason_explanation);
+	}
+
+	//currently error handling/retry logic is same for ABTS BA_ACC & BA_RJT
+	switch (fabric_state) {
+	case FDLS_STATE_FABRIC_FLOGI:
+		if (fchdr->ox_id == FNIC2_FLOGI_OXID) {
+			if (lport->fabric.retry_counter < lport->max_flogi_retries)
+				fdls_send_fabric_flogi(lport);
+			else
+				fdls_error_fabric_disc(lport);
+		} else {
+			pr_debug("fdls received unknown abts_rsp ox_id %x in FDLS_STATE_FABRIC_FLOGI state.. dropping the frame\n",
+				fchdr->ox_id);
+		}
+		break;
+
+	case FDLS_STATE_FABRIC_PLOGI:
+		if (fchdr->ox_id == FNIC2_PLOGI_FABRIC_OXID) {
+			if (lport->fabric.retry_counter < lport->max_plogi_retries)
+				fdls_send_fabric_plogi(lport);
+			else
+				fdls_error_fabric_disc(lport);
+		} else {
+			pr_debug("fdls received unknown abts_rsp ox_id %x in FDLS_STATE_FABRIC_PLOGI state.. dropping the frame\n",
+				fchdr->ox_id);
+		}
+		break;
+	case FDLS_STATE_RPN_ID:
+		if (ba_acc->ox_id == FNIC2_RPN_REQ_OXID) {
+			if (lport->fabric.retry_counter < FDLS_RETRY_COUNT) {
+				fdls_send_rpn_id(lport);
+			} else {
+				//go back to fabric Plogi
+				fnic2_fdls_start_plogi(lport);
+			}
+		} else {
+			pr_debug("fdls received unknown abts_rsp ox_id %x in FDLS_STATE_RPN_ID state.. dropping the frame\n",
+				fchdr->ox_id);
+		}
+		break;
+	case FDLS_STATE_REGISTER_FC4_TYPES:
+		if (ba_acc->ox_id == FNIC2_RFT_REQ_OXID) {
+			if (lport->fabric.retry_counter < FDLS_RETRY_COUNT) {
+				fdls_send_register_fc4_types(lport);
+			} else {
+				//go back to fabric Plogi
+				fnic2_fdls_start_plogi(lport);
+			}
+		} else {
+			pr_debug("fdls received unknown abts_rsp ox_id %x in FDLS_STATE_REGISTER_FC4_TYPES state.. dropping the frame\n",
+				fchdr->ox_id);
+		}
+		break;
+	case FDLS_STATE_REGISTER_FC4_FEATURES:
+		if (ba_acc->ox_id == FNIC2_RFF_REQ_OXID) {
+			if (lport->fabric.retry_counter < FDLS_RETRY_COUNT) {
+				fdls_send_register_fc4_features(lport);
+			} else {
+				//go back to fabric Plogi
+				fnic2_fdls_start_plogi(lport);
+			}
+		} else {
+			pr_debug("fdls received unknown abts_rsp ox_id %x in FDLS_STATE_REGISTER_FC4_FEATURES state.. dropping the frame\n",
+				fchdr->ox_id);
+		}
+		break;
+	default:
+		return;
+	}
+}
+
+static void fdls_process_plogi_req(struct fnic2_lport *lport, struct fc_hdr *fchdr)
+{
+	struct fc_els_reject   plogi_rej;
+	struct fc_els       plogi_acc;
+	struct fc_els       *plogi_req;
+	struct fnic2_rport   *rport;
+
+	uint16_t  rx_id;
+
+	if (lport->fcid != ntoh24(fchdr->d_id)) {
+		pr_debug("lport 0x%pK fdls received Plogi with illegal frame bits dropping..\n",
+			lport);
+		return;
+	}
+	pr_debug("%s from fcid:%x\n", __func__, ntoh24(fchdr->s_id));
+
+	if (fchdr->s_id[0] != 0xFF) {
+
+		plogi_req = (struct fc_els *) fchdr;
+		rport = fnic2_find_rport(lport, plogi_req->nport_name);
+
+		if (rport != NULL)
+			fdls_delete_rport(lport, rport);
+
+		pr_err("Allocating rport\n");
+
+		rport = fdls_create_rport(lport, ntoh24(fchdr->s_id),
+					 plogi_req->nport_name);
+
+		if (rport == NULL)
+			goto send_plogi_rej;
+
+		pr_err("New rport %pK\n", rport);
+
+		memcpy(&plogi_acc, &fnic2_plogi_resp, sizeof(struct fc_els));
+
+		memcpy(plogi_acc.fchdr.s_id, fchdr->d_id, 3);
+		memcpy(&plogi_acc.fchdr.d_id, fchdr->s_id, 3);
+
+		rx_id = htons(fdls_alloc_tgt_ox_id(FDLS_PLOGI_OXID_BASE));
+		if (rx_id == 0xFFFF) {
+			// Log and Err TBD
+
+			pr_debug("lport 0x%pK fdls_tgt_send_plogi_acc.. rx_id not available\n", lport);
+			return;
+		}
+		pr_debug("fdls_tgt_send_plogi_acc rx_id %x\n", ntohs(rx_id));
+
+		plogi_acc.fchdr.ox_id = fchdr->ox_id;
+		plogi_acc.fchdr.rx_id = rx_id;
+		plogi_acc.nport_name = cpu_to_be64(lport->wwpn);
+		plogi_acc.node_name = cpu_to_be64(lport->wwnn);
+
+		fnic2_send_fcoe_frame(lport, &plogi_acc, sizeof(struct fc_els));
+
+		// TBD should we run a timer ???
+		fdls_free_tgt_ox_id(ntohs(rx_id));
+
+	} else {
+send_plogi_rej:
+		memcpy(&plogi_rej, &fnic2_els_rjt,
+			sizeof(struct fc_els_reject));
+		plogi_rej.reason_code = 0x0B;
+		plogi_rej.reason_expl = 0x0;
+		plogi_rej.vendor_specific = 0x0;
+		memcpy(&plogi_rej.fchdr.s_id, fchdr->d_id, 3);
+		memcpy(&plogi_rej.fchdr.d_id, fchdr->s_id, 3);
+
+		rx_id = fchdr->ox_id;
+		plogi_rej.fchdr.rx_id = rx_id;
+		plogi_rej.fchdr.ox_id = fchdr->ox_id;
+
+		fnic2_send_fcoe_frame(lport, &plogi_rej,
+					sizeof(struct fc_els_reject));
+	}
+}
+
+static void fdls_send_rej(struct fnic2_lport *lport, struct fc_hdr *fchdr)
+{
+	struct fc_els_reject els_rej;
+
+	memcpy(&els_rej, &fnic2_els_rjt, sizeof(struct fc_els_reject));
+
+	memcpy(&els_rej.fchdr.s_id, fchdr->d_id, 3);
+	memcpy(&els_rej.fchdr.d_id, fchdr->s_id, 3);
+
+	els_rej.reason_code = 0x0B;
+	els_rej.fchdr.rx_id = 0xFFFF;
+	els_rej.fchdr.ox_id = fchdr->ox_id;
+
+	fnic2_send_fcoe_frame(lport, &els_rej, sizeof(struct fc_els_reject));
+}
+
+static void fdls_send_els_acc(struct fnic2_lport *lport, struct fc_hdr *fchdr)
+{
+	struct fc_els_acc els_acc;
+
+	memcpy(&els_acc, &fnic2_els_acc, sizeof(struct fc_els_acc));
+
+	memcpy(&els_acc.fchdr.s_id, fchdr->d_id, 3);
+	memcpy(&els_acc.fchdr.d_id, fchdr->s_id, 3);
+
+	els_acc.fchdr.rx_id = 0xFFFF;
+	els_acc.fchdr.ox_id = fchdr->ox_id;
+
+	fnic2_send_fcoe_frame(lport, &els_acc, sizeof(struct fc_els_acc));
+
+}
+
+void fdls_send_ba_acc(struct fnic2_lport *lport, struct fc_hdr *fchdr)
+{
+	struct fc_abts_ba_acc ba_acc;
+
+	memcpy(&ba_acc, &fnic2_ba_acc, sizeof(struct fc_abts_ba_acc));
+
+	memcpy(&ba_acc.fchdr.s_id, fchdr->d_id, 3);
+	memcpy(&ba_acc.fchdr.d_id, fchdr->s_id, 3);
+
+	ba_acc.fchdr.rx_id = fchdr->rx_id;
+	ba_acc.rx_id = ba_acc.fchdr.rx_id;
+	ba_acc.fchdr.ox_id = fchdr->ox_id;
+	ba_acc.ox_id = ba_acc.fchdr.ox_id;
+
+	fnic2_send_fcoe_frame(lport, &ba_acc, sizeof(struct fc_abts_ba_acc));
+
+}
+
+static void fdls_process_prli_req(struct fnic2_lport *lport, struct fc_hdr *fchdr)
+{
+	struct fc_els_prli  prli_acc;
+	struct fnic2_rport   *rport;
+	uint16_t  rx_id;
+
+	if (lport->fcid != ntoh24(fchdr->d_id)) {
+		pr_debug("lport 0x%pK fdls received PRLI to wrong d_id - dropping..\n", lport);
+		return;
+	}
+	pr_debug("%s from fcid:%x\n", __func__, ntoh24(fchdr->s_id));
+
+	rport = fnic2_find_rport_by_fcid(lport, ntoh24(fchdr->s_id));
+
+	pr_err("Found rport %pK\n", rport);
+
+	if (rport) {
+
+		rx_id = htons(fdls_alloc_tgt_ox_id(FDLS_PRLI_OXID_BASE));
+		if (rx_id == 0xFFFF) {
+			// Log and Err TBD
+
+			pr_debug("lport 0x%pK fdls_tgt_send_prli_acc.. rx_id not available\n", lport);
+			fdls_send_rej(lport, fchdr);
+			return;
+		}
+		if (!fnic2_session_create(lport->fnic2, rport)) {
+
+			memcpy(&prli_acc, &fnic2_prli_resp, sizeof(struct fc_els_prli));
+
+			memcpy(&prli_acc.fchdr.s_id, fchdr->d_id, 3);
+			memcpy(&prli_acc.fchdr.d_id, fchdr->s_id, 3);
+
+			pr_debug("fdls_tgt_send_prli_acc..rx_id %x\n", ntohs(rx_id));
+
+			prli_acc.fchdr.rx_id = rx_id;
+			prli_acc.fchdr.ox_id = fchdr->ox_id;
+
+			fnic2_send_fcoe_frame(lport, &prli_acc, sizeof(struct fc_els_prli));
+
+
+			// TBD should we run a timer ???
+			fdls_free_tgt_ox_id(ntohs(rx_id));
+		} else {
+			fdls_send_rej(lport, fchdr);
+		}
+	} else {
+		fdls_send_logout(lport, fchdr);
+	}
+}
+
+
+static void fdls_process_logo_req(struct fnic2_lport *lport, struct fc_hdr *fchdr)
+{
+	struct fc_logo_req *logo = (struct fc_logo_req *)fchdr;
+	uint32_t nport_id;
+	uint64_t nport_name;
+	struct fnic2_rport *rport;
+
+	nport_id = ntoh24(logo->fcid);
+	nport_name = logo->wwpn;
+
+	pr_debug("%s fcid: %x\n", __func__, nport_id);
+	rport = fnic2_find_rport_by_fcid(lport, nport_id);
+
+	if (!rport) {
+		/* We are not logged in with the nport, log and drop...*/
+		pr_debug("fdls recevied LOGO from an rport not logged in: %x\n",
+			nport_id);
+		return;
+	}
+	if (rport->fcid != nport_id) {
+		/* nport_id changed. TBD_REVISIT */
+		pr_debug("fdls recevied LOGO with invalid source port fcid: %x\n",
+			nport_id);
+		return;
+	}
+
+	fdls_delete_rport(lport, rport);
+	fdls_send_logo_resp(lport, &logo->fchdr);
+}
+
+/* Public Functions */
+
+void fnic2_fdls_disc_start(struct fnic2_lport *lport)
+{
+	if (!lport->usefip)
+		fnic2_fdls_start_flogi(lport);
+	else //review: plogi to name server
+		fnic2_fdls_start_plogi(lport);
+}
+
+/*
+ * Performs a validation for all FCOE frames and return the frame type
+ */
+static int fnic2_fdls_validate_and_get_frame_type(struct fnic2_lport *lport, void *rx_frame,
+	int len, int fchdr_offset)
+{
+	struct fc_hdr *fchdr;
+	uint8_t type;
+	uint8_t *fc_payload;
+	uint16_t ox_id;
+	uint32_t s_id;
+	uint32_t d_id;
+
+	struct fnic2_fdls_fabric *fabric = &lport->fabric;
+
+	fchdr = (struct fc_hdr *)((uint8_t *)rx_frame + fchdr_offset);
+	ox_id = fchdr->ox_id;
+	fc_payload = (uint8_t *)fchdr + sizeof(struct fc_hdr);
+	type = *fc_payload;
+
+	s_id = ntoh24(fchdr->s_id);
+	d_id = ntoh24(fchdr->d_id);
+
+	//some common validation
+	if (lport->fcid)
+		if (fabric->state > FDLS_STATE_FABRIC_FLOGI) {
+			if ((lport->fcid != d_id) ||
+				(fchdr->cs_ctl != FNIC2_FC_CS_CTL)) {
+				pr_debug("Invalid frame received with DID %x IPortfcid %x fabric state %x R_CTL %x type %x OX_ID %x  RX_ID %x CS_CTL %x Dropping\n",
+					d_id, lport->fcid, fabric->state,
+					fchdr->r_ctl, fchdr->type, fchdr->ox_id,
+					fchdr->rx_id, fchdr->cs_ctl);
+				return -1;
+			}
+		}
+
+	// ABTS response
+	if ((fchdr->r_ctl == FNIC2_BA_ACC_RCTL) ||
+		(fchdr->r_ctl == FNIC2_BA_RJT_RCTL)) {
+		if (fchdr->type != FNIC2_FC_TYPE_BLS) {
+			pr_debug("fdls recevied ABTS with some Invalid frame bits S_ID %x FCTL %x R_CTL %x type %x. Dropping the frame\n",
+				s_id, ntoh24(fchdr->f_ctl), fchdr->r_ctl, fchdr->type);
+			return -1;
+
+		}
+		return FNIC2_BLS_ABTS_RSP;
+	}
+
+	//unsolicited requests frames
+	if (fchdr->r_ctl == FNIC2_R_CTL_UNSOLICITED) {
+		switch (type) {
+		case FC_ELS_LOGO:
+			if ((fchdr->f_ctl[0] != FNIC2_F_CTL_FIRST_LAST_SEQ_INIT) ||
+			    (fchdr->type != FNIC2_FC_TYPE_ELS)) {
+				pr_debug("fdls recevied LOGO with some Invalid frame bits S_ID %x FCTL %x R_CTL %x type %x. Dropping the frame\n",
+					s_id, ntoh24(fchdr->f_ctl), fchdr->r_ctl,
+					fchdr->type);
+				return -1;
+			}
+			return FNIC2_ELS_LOGO_REQ;
+		case FC_ELS_PLOGI_REQ:
+			return FNIC2_ELS_PLOGI_REQ;
+		case FC_ELS_PRLI_REQ:
+			return FNIC2_ELS_PRLI_REQ;
+		case FC_ELS_RTV_REQ:
+			return FNIC2_ELS_RTV_REQ;
+		case FC_ELS_RRQ_REQ:
+			return FNIC2_ELS_RRQ_REQ;
+		default:
+			pr_debug("fdls_recv_frame unsupported frame: %d\n", type);
+			return -1;
+		}
+	}
+
+	// Only responses for requests we sent
+	if (fchdr->f_ctl[0] & FNIC2_F_CTL_EXCH_RESPONDER) {
+
+		if (ntohs(ox_id) == FNIC2_LOGO_REQ_OXID)
+			return FNIC2_TPORT_LOGO_RSP;
+
+		/*response from fabric*/
+		switch (ox_id) {
+		case FNIC2_FLOGI_OXID:
+		if (type == FC_LS_ACC) {
+			if ((fchdr->f_ctl[0] != FNIC2_F_CTL_LAST_END_SEQ) ||
+				(fchdr->r_ctl != FNIC2_R_CTL_SOLICITED_CTRL_REPLY) ||
+				(s_id != FC_DOMAIN_CONTR) ||
+				(fchdr->type != FNIC2_FC_TYPE_ELS)) {
+				pr_debug("fdls recevied Flogi resp with some Invalid frame bits s_id %x FCTL %x R_CTL %x type %x. Dropping the frame.\n",
+					s_id, ntoh24(fchdr->f_ctl),
+					fchdr->r_ctl, fchdr->type);
+				return -1;
+			}
+		}
+		return FNIC2_FABRIC_FLOGI_RSP;
+
+		case FNIC2_PLOGI_FABRIC_OXID:
+		if (type == FC_LS_ACC) {
+			if ((fchdr->f_ctl[0] != FNIC2_F_CTL_LAST_END_SEQ) ||
+				(fchdr->r_ctl != FNIC2_R_CTL_SOLICITED_CTRL_REPLY) ||
+				(s_id != FC_DIR_SERVER) ||
+				(fchdr->type != FNIC2_FC_TYPE_ELS)) {
+				pr_debug("fdls recevied Plogi resp with some Invalid frame bits s_id %x FCTL %x R_CTL %x type %x. Dropping the frame.\n",
+					s_id, ntoh24(fchdr->f_ctl),
+					fchdr->r_ctl, fchdr->type);
+				return -1;
+			}
+		}
+		return FNIC2_FABRIC_PLOGI_RSP;
+
+		case FNIC2_RPN_REQ_OXID:
+		if (type == FC_LS_ACC) {
+			if ((fchdr->f_ctl[0] != FNIC2_F_CTL_LAST_END_SEQ) ||
+				(fchdr->r_ctl != FNIC2_R_CTL_SCTL) ||
+				(s_id != FC_DIR_SERVER) ||
+				(fchdr->type != FNIC2_FC_TYPE_FC_GS))  {
+				pr_debug("fdls recevied rpn_id_rsp with some Invalid frame bits s_id %x FCTL %x R_CTL %x type %x. Dropping the frame.\n",
+					s_id, ntoh24(fchdr->f_ctl),
+					fchdr->r_ctl, fchdr->type);
+				return -1;
+			}
+		}
+		return FNIC2_FABRIC_RPN_RSP;
+		case FNIC2_RFT_REQ_OXID:
+		if (type == FC_LS_ACC) {
+			if ((fchdr->f_ctl[0] != FNIC2_F_CTL_LAST_END_SEQ) ||
+				(fchdr->r_ctl != FNIC2_R_CTL_SCTL) ||
+				(s_id != FC_DIR_SERVER) ||
+				(fchdr->type != FNIC2_FC_TYPE_FC_GS))  {
+				pr_debug("fdls recevied rft_id_rsp with some Invalid frame bits s_id %x FCTL %x R_CTL %x type %x. Dropping the frame.\n",
+					s_id, ntoh24(fchdr->f_ctl),
+					fchdr->r_ctl, fchdr->type);
+				return -1;
+			}
+		}
+		return FNIC2_FABRIC_RFT_RSP;
+		case FNIC2_RFF_REQ_OXID:
+		if (type == FC_LS_ACC) {
+			if ((fchdr->f_ctl[0] != FNIC2_F_CTL_LAST_END_SEQ) ||
+				(fchdr->r_ctl != FNIC2_R_CTL_SCTL) ||
+				(s_id != FC_DIR_SERVER) ||
+				(fchdr->type != FNIC2_FC_TYPE_FC_GS))  {
+				pr_debug("fdls recevied rff_id_rsp with some Invalid frame bits s_id %x FCTL %x R_CTL %x type%x. Dropping the frame.\n",
+					s_id, ntoh24(fchdr->f_ctl),
+					fchdr->r_ctl, fchdr->type);
+				return -1;
+			}
+		}
+		return FNIC2_FABRIC_RFF_RSP;
+		default:
+		/* Drop the Rx frame and log/stats it */
+		pr_debug("fdls_recv_frame Solicited response Unknown ox_id: %x\n", ox_id);
+		return -1;
+		}
+	}
+	return -1;
+}
+
+void fnic2_fdls_recv_frame(struct fnic2_lport *lport, void *rx_frame, int len,
+	int fchdr_offset)
+{
+	uint16_t ox_id;
+	struct fc_hdr *fchdr;
+	uint32_t s_id = 0;
+	uint32_t d_id = 0;
+	char *frame_data = rx_frame;
+
+	int frame_type;
+
+	fchdr = (struct fc_hdr *)((uint8_t *)(frame_data + fchdr_offset));
+
+	s_id = ntoh24(fchdr->s_id);
+	d_id = ntoh24(fchdr->d_id);
+	pr_debug("fdls_recv_frame received frame of len %x with SID %x DID %x R_CTL %x F_CTL %x OX_ID %x RX_ID %x seq_id %x seq_cnt %x type %x offset %d\n",
+		len, s_id, d_id, fchdr->r_ctl, ntoh24(fchdr->f_ctl),
+		ntohs(fchdr->ox_id), fchdr->rx_id, fchdr->seq_id, fchdr->seq_cnt,
+		fchdr->type, fchdr_offset);
+
+	frame_type = fnic2_fdls_validate_and_get_frame_type(lport, frame_data,
+	    len, fchdr_offset);
+
+	switch (frame_type) {
+
+	case FNIC2_FABRIC_FLOGI_RSP:
+		fdls_process_flogi_rsp(lport, fchdr, frame_data);
+		break;
+
+	case FNIC2_FABRIC_PLOGI_RSP:
+		fdls_process_fabric_plogi_rsp(lport, fchdr);
+		break;
+	case FNIC2_FABRIC_RPN_RSP:
+		fdls_process_rpn_id_rsp(lport, fchdr);
+		break;
+	case FNIC2_FABRIC_RFT_RSP:
+		fdls_process_rft_id_rsp(lport, fchdr);
+		break;
+	case FNIC2_FABRIC_RFF_RSP:
+		fdls_process_rff_id_rsp(lport, fchdr);
+		break;
+	case FNIC2_BLS_ABTS_RSP:
+		ox_id = fchdr->ox_id;
+		if ((lport->fabric.flags & FNIC2_FDLS_FABRIC_ABORT_ISSUED) &&
+			(ox_id >= FNIC2_FLOGI_OXID && ox_id <= FNIC2_RFF_REQ_OXID)) {
+			fdls_process_fabric_abts_rsp(lport, fchdr);
+		}
+		break;
+
+	case FNIC2_ELS_PLOGI_REQ:
+		fdls_process_plogi_req(lport, fchdr);
+		break;
+	case FNIC2_ELS_PRLI_REQ:
+		fdls_process_prli_req(lport, fchdr);
+	break;
+	case FNIC2_ELS_RTV_REQ:
+		fdls_send_rej(lport, fchdr);
+		break;
+	case FNIC2_ELS_RRQ_REQ:
+		fdls_send_els_acc(lport, fchdr);
+		break;
+	case FNIC2_ELS_LOGO_REQ:
+		fdls_process_logo_req(lport, fchdr);
+		break;
+	default:
+		// pr_debug("Received unknown FCoE frame of len: %d. dropping.\n", len);
+		break;
+	}
+}
+
+void fnic2_fdls_disc_init(struct fnic2_lport *lport)
+{
+	fdls_init_tgt_ox_id_pool();
+	lport->fabric.state = FDLS_STATE_INIT;
+}
+
+void fnic2_fdls_link_down(struct fnic2_lport *lport)
+{
+	struct fnic2_rport *rport, *next;
+
+	pr_debug("%s lport 0x%pK\n", __func__, lport);
+
+	lport->fabric.state = FDLS_STATE_LINKDOWN;
+	lport->fabric.flags = 0;
+
+	fnic2_scsi_fcpio_reset(lport);
+
+	fdls_init_tgt_ox_id_pool();
+
+	list_for_each_entry_safe(rport, next, &lport->rport_list, links)   {
+		pr_debug("removing rport: %x", rport->fcid);
+		if (rport->state != fdls_rport_state_offlining)
+			fdls_delete_rport(lport, rport);
+	}
+
+	pr_debug("%s lport 0x%pK\n", __func__, lport);
+}
+
+struct fnic2_rport *fdls_create_rport(struct fnic2_lport *lport, uint32_t fcid, uint64_t wwpn)
+{
+	struct fnic2_rport rport;
+
+	pr_debug("%s fcid:%x, wwpn: %llx\n", __func__, fcid, wwpn);
+
+	memset(&rport, 0, sizeof(struct fnic2_rport));
+
+	rport.fcid = fcid;
+	rport.wwpn = wwpn;
+
+	rport.lport = lport;
+
+	rport.state = fdls_rport_state_plogi;
+	return fnic2_fdls_add_rport(lport, &rport);
+}
+
+void fdls_delete_rport(struct fnic2_lport *lport, struct fnic2_rport *rport)
+{
+	struct fnic2_sess *sess;
+	struct se_session *se_sess;
+
+	if (rport->state == fdls_rport_state_offlining)
+		return;
+	rport->state = fdls_rport_state_offlining;
+	// remove session, cleanup LIO
+	sess = fnic2_find_session(lport->fnic2, rport->wwpn);
+	if (sess) {
+		if ((try_to_del_timer_sync(&sess->sess_timer)) < 0)
+			pr_err("Failed to delete session %pK\n", sess);
+		se_sess = sess->se_sess;
+		target_sess_cmd_list_set_waiting(se_sess);
+		target_wait_for_sess_cmds(se_sess);
+
+		transport_deregister_session_configfs(se_sess);
+		transport_deregister_session(se_sess);
+		sess->se_sess = NULL;
+		list_del(&sess->list);
+		lport->fnic2->lio.sess_count--;
+		kfree(sess);
+	}
+	fnic2_fdls_remove_rport(lport, rport);
+}
+
+void fnic2_fdls_remove_rport(struct fnic2_lport *lport, struct fnic2_rport *rport)
+{
+	list_del(&rport->links);
+	kfree(rport);
+}
+
+
+struct fnic2_rport *fnic2_fdls_add_rport(struct fnic2_lport *lport, struct fnic2_rport *rport)
+{
+	struct fnic2_rport *new_rport;
+
+	new_rport = kmalloc(sizeof(struct fnic2_rport), GFP_ATOMIC);
+	if (new_rport == NULL)
+		return NULL;
+	pr_debug("created rport rport: %pK\n", new_rport);
+	memcpy(new_rport, rport, sizeof(struct fnic2_rport));
+
+	list_add_tail(&new_rport->links, &lport->rport_list);
+
+	return new_rport;
+}
+
+struct fnic2_rport *fnic2_find_rport(struct fnic2_lport *lport, uint64_t wwpn)
+{
+	struct fnic2_rport *rport;
+	struct list_head *init;
+
+	list_for_each(init, &lport->rport_list) {
+
+	rport =  list_entry(init, struct fnic2_rport, links);
+	if (rport->wwpn == wwpn)
+		return rport;
+	}
+	return NULL;
+}
+
+struct fnic2_rport *fnic2_find_rport_by_fcid(struct fnic2_lport *lport, uint32_t fcid)
+{
+	struct fnic2_rport *rport;
+	struct list_head *init;
+
+	list_for_each(init, &lport->rport_list) {
+
+		rport =  list_entry(init, struct fnic2_rport, links);
+		if (rport->fcid == fcid)
+			return rport;
+	}
+	return NULL;
+}
diff --git a/drivers/staging/fnic2/src/fdls_fc.h b/drivers/staging/fnic2/src/fdls_fc.h
new file mode 100644
index 0000000..2da1e4e
--- /dev/null
+++ b/drivers/staging/fnic2/src/fdls_fc.h
@@ -0,0 +1,403 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright 2018 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _FDLS_FC_H_
+#define _FDLS_FC_H_
+
+#include <scsi/scsi.h>
+#include "vnic_wq_copy.h"
+
+/* This file contains the declarations for FC fabric services */
+
+enum fcp_sp {
+	FNIC2_FCP_SP_RD_XRDY_DIS	= 0x00000002,
+	FNIC2_FCP_SP_INITIATOR		= 0x00000020,
+	FNIC2_FCP_SP_CONF_CMPL		= 0x00000080,
+	FNIC2_FCP_SP_RETRY		= 0x00000100
+};
+
+#ifdef _BIG_ENDIAN
+
+enum be_ox_id {
+	FNIC2_FLOGI_OXID	= 0x1001,
+	FNIC2_PLOGI_FABRIC_OXID	= 0x1002,
+	FNIC2_RPN_REQ_OXID	= 0x1003,
+	FNIC2_RFT_REQ_OXID	= 0x1004,
+	FNIC2_RFF_REQ_OXID	= 0x1005,
+	FNIC2_LOGO_REQ_OXID	= 0x1007,
+	FNIC2_LOGO_RESP_OXID	= 0x1008
+}
+
+enum be_f_ctl {
+	FNIC2_ELS_REQ_FCTL	= 0x290000,
+	FNIC2_ELS_REP_FCTL	= 0x980000,
+	FNIC2_FCP_RSP_FCTL	= 0x990000
+};
+
+#define FNIC2_FC_PH_VER         (0x2020)
+#define FNIC2_FC_B2B_CREDIT     (0x000A)
+#define FNIC2_FC_B2B_RDF_SZ     (0x0800)
+
+#define FNIC2_REQ_ABTS_FCTL     (0x090000)
+
+#define FNIC2_FC_CONCUR_SEQS    (0x00FF)
+
+#define FNIC2_FC_RO_INFO        (0x001F)
+#define FNIC2_E_D_TOV           (0x07D0)
+
+enum be_fc_ct {
+	FC_CT_RPN_CMD	= 0x0212,
+	FC_CT_RFT_CMD	= 0x0217,
+	FC_CT_RFT_CMD	= 0x021F,
+	FC_CT_ACC	= 0x8002
+};
+
+#else //_LITTLE_ENDIAN
+
+enum le_ox_id {
+	FNIC2_FLOGI_OXID	= 0x0110,
+	FNIC2_PLOGI_FABRIC_OXID	= 0x0210,
+	FNIC2_RPN_REQ_OXID	= 0x0310,
+	FNIC2_RFT_REQ_OXID	= 0x0410,
+	FNIC2_RFF_REQ_OXID	= 0x0510,
+	FNIC2_LOGO_REQ_OXID	= 0x0710,
+	FNIC2_LOGO_RESP_OXID	= 0x0810
+};
+
+enum le_f_ctl {
+	FNIC2_ELS_REQ_FCTL	= 0x000029,
+	FNIC2_ELS_REP_FCTL	= 0x000098,
+	FNIC2_FCP_RSP_FCTL	= 0x000099
+};
+
+#define FNIC2_REQ_ABTS_FCTL     (0x000009)
+
+#define FNIC2_FC_PH_VER         (0x2020)
+#define FNIC2_FC_B2B_CREDIT     (0x0A00)
+#define FNIC2_FC_B2B_RDF_SZ     (0x0008)
+
+#define FNIC2_FC_CONCUR_SEQS    (0xFF00)
+#define FNIC2_FC_RO_INFO        (0x1F00)
+#define FNIC2_E_D_TOV           (0xD0070000)
+
+enum le_fc_ct {
+	FC_CT_ACC       = 0x0280,
+	FC_CT_RPN_CMD	= 0x1202,
+	FC_CT_RFT_CMD	= 0x1702,
+	FC_CT_RFF_CMD	= 0x1F02
+};
+
+#endif /* Big Endian */
+
+enum fc_well_known_addr {
+	FC_DIR_SERVER		= 0xFFFFFC,
+	FC_FABRIC_CONTROLLER	= 0xFFFFFD,
+	FC_DOMAIN_CONTR		= 0xFFFFFE
+};
+
+#define FC_LS_REJ               0x01
+#define FC_LS_ACC               0x02
+
+enum fc_els_command {
+	FC_ELS_PLOGI_REQ        = 0x03,
+	FC_ELS_FLOGI_REQ	= 0x04,
+	FC_ELS_LOGO             = 0x05,
+        FC_ELS_RJT_LOGICAL_BUSY = 0x05,
+	FC_ELS_RJT_BUSY         = 0x09,
+	FC_ELS_RTV_REQ		= 0x0E,
+	FC_ELS_RRQ_REQ		= 0x12,
+	FC_ELS_PRLI_REQ		= 0x20
+};
+
+#define FNIC2_FCOE_EOF         (0x42)
+
+#define FNIC2_FCOE_MAX_FRAME_SZ  (2048)
+#define FNIC2_FCOE_MIN_FRAME_SZ  (280)
+
+enum fc_r_ctl {
+	FNIC2_R_CTL_SCTL			= 0x03,
+	FC_R_CTL_FC4_CMD			= 0x06,
+	FC_R_CTL_FC4_STATUS			= 0x07,
+	FNIC2_R_CTL_UNSOLICITED			= 0x22,
+	FNIC2_R_CTL_SOLICITED_CTRL_REPLY	= 0x23,
+	FNIC2_FC_R_CTL_ABTS			= 0x81,
+	FNIC2_BA_ACC_RCTL			= 0x84,
+	FNIC2_BA_RJT_RCTL			= 0x85
+};
+
+enum fc_f_ctl {
+	FNIC2_F_CTL_FIRST_LAST_SEQ_INIT	= 0x29,
+	FNIC2_F_CTL_EXCH_RESPONDER	= 0x80,
+	FNIC2_F_CTL_LAST_END_SEQ        = 0x98
+};
+
+enum fc_type {
+	FNIC2_FC_TYPE_BLS	= 0x00,
+	FNIC2_FC_TYPE_ELS	= 0x01,
+	FNIC2_FC_TYPE_FC_GS	= 0x20
+};
+
+#define FNIC2_FC_CS_CTL				0x00
+
+#define FNIC2_FC_C3_RDF         (0xfff)
+
+#define FCP_RSP_FLAG_OVERFLOW   (1 << 2)
+#define FCP_RSP_FLAG_UNDERFLOW  (1 << 3)
+
+#define FNIC2_FC_EDTOV_NSEC    (0x400)
+#define FNIC2_NSEC_TO_MSEC     (0x1000000)
+
+#define FNIC2_FCOE_FCHDR_OFFSET \
+    (sizeof(struct fnic2_eth_hdr) + sizeof(struct fnic2_fcoe_hdr))
+
+enum fc_cmnd_req {
+        FC_CMND_REQ_NONE        = 0x00,
+        FC_CMND_REQ_WR          = 0x01,
+        FC_CMND_REQ_RD          = 0x02
+};
+
+#define FC_CMND_ADDL_CDB_LEN(_val)      \
+        ((_val & 0xFC) >> 2)
+
+#define FC_CMND_TASK_ATTR       (0x03)
+
+enum fc_ta {
+        FC_TA_SIMPLE_TAG        = 0x0,
+        FC_TA_HEAD_OF_QUEUE     = 0x1,
+        FC_TA_ORDERED           = 0x2,
+        FC_TA_ACA               = 0x4
+};
+
+/* Frame header */
+
+struct fnic2_eth_hdr {
+	uint8_t		dst_mac[6];
+	uint8_t		src_mac[6];
+	uint16_t	ether_type;
+} __attribute__((__packed__));
+
+struct fnic2_fcoe_hdr {
+	uint8_t	ver;
+	uint8_t	rsvd[12];
+	uint8_t	sof;
+} __attribute__((__packed__));
+
+/* Big Endian */
+struct fc_hdr {
+	uint8_t 	r_ctl;
+	uint8_t 	d_id[3];
+
+	uint8_t		cs_ctl;
+	uint8_t		s_id[3];
+
+	uint8_t		type;
+	uint8_t		f_ctl[3];
+
+	uint8_t		seq_id;
+	uint8_t		df_ctl;
+	uint16_t	seq_cnt;
+
+	uint16_t	ox_id;
+	uint16_t	rx_id;
+
+	uint32_t	param;
+} __attribute__((__packed__));
+
+struct fc_csp_flogi {
+	uint16_t	fc_ph_ver;
+	uint16_t	b2b_credits;
+
+	uint16_t	features;
+	uint16_t	b2b_rdf_size;
+
+	uint32_t	r_a_tov;
+	uint32_t	e_d_tov;
+} __attribute__((__packed__));
+
+struct fc_csp_plogi {
+	uint16_t	fc_ph_ver;
+	uint16_t	b2b_credits;
+
+	uint16_t	features;
+	uint16_t	b2b_rdf_size;
+
+	uint16_t	total_concur_seqs;
+	uint16_t	ro_info;
+
+	uint32_t	e_d_tov;
+} __attribute__((__packed__));
+
+// Revisit the correctness of union(though its same size now)
+struct fc_els {
+	struct	fc_hdr fchdr;
+	uint8_t			command;
+	uint8_t			rsvd[3];
+
+	union {
+		struct fc_csp_flogi csp_flogi;
+		struct fc_csp_plogi csp_plogi;
+	} u;
+
+	uint64_t		nport_name;
+	uint64_t		node_name;
+
+	uint8_t			spc1[16];
+	uint8_t			spc2[16];
+	uint8_t			spc3[16];
+	uint8_t			spc4[16];
+
+	uint8_t  vendor_ver_level[16];
+} __attribute__((__packed__));
+
+struct fc_els_acc {
+	struct fc_hdr	fchdr;
+	uint8_t			command;
+	uint8_t 		rsvd[3];
+} __attribute__((__packed__));
+
+struct fc_els_reject {
+	struct fc_hdr   fchdr;
+	uint32_t		command;
+	uint8_t			reserved;
+	uint8_t			reason_code;
+	uint8_t			reason_expl;
+	uint8_t			vendor_specific;
+} __attribute__((__packed__));
+
+struct fc_abts_ba_acc {
+	struct fc_hdr	fchdr;
+	uint8_t			seq_id_validity;
+	uint8_t			seq_id;
+	uint16_t		reserved;
+	uint16_t		ox_id;
+	uint16_t		rx_id;
+	uint16_t		low_seq_cnt;
+	uint16_t		high_seq_cnt;
+
+} __attribute__((__packed__));
+
+struct fc_abts_ba_rjt {
+	struct fc_hdr	fchdr;
+	uint8_t			vend_uniq;
+	uint8_t			reason_explanation;
+	uint8_t			reason_code;
+	uint8_t			reserved;
+
+} __attribute__((__packed__));
+
+struct fc_prli_sp {
+	uint8_t		type;
+	uint8_t		type_ext;
+	uint16_t	flags;
+
+	uint32_t	ox_proc_assoc;
+	uint32_t	rx_proc_assoc;
+	uint32_t	csp;
+} __attribute__((__packed__));
+
+struct fc_els_prli {
+	struct fc_hdr	fchdr;
+	uint8_t			command;
+	uint8_t			page_len;
+	uint16_t		payload_len;
+	struct fc_prli_sp 	sp;
+} __attribute__((__packed__));
+
+struct fc_ct_hdr {
+	uint32_t	rev: 8;
+	uint32_t	in_id: 24;
+
+	uint8_t		fs_type;
+	uint8_t		fs_subtype;
+	uint8_t		options;
+	uint8_t		rsvd;
+
+	uint16_t	command;
+	uint16_t	max_res_size;
+
+	uint8_t		rsvd1;
+	uint8_t		reason_code;
+	uint8_t		reason_expl;
+	uint8_t		vendor_specific;
+} __attribute__((__packed__));
+
+struct fc_rpn_id {
+	struct fc_hdr	fchdr;
+	struct fc_ct_hdr	fc_ct_hdr;
+
+	uint8_t			rsvd;
+	uint8_t			port_id[3];
+
+	uint64_t		port_name;
+} __attribute__((__packed__));
+
+struct fc_rft_id {
+	struct fc_hdr	fchdr;
+	struct fc_ct_hdr	fc_ct_hdr;
+
+	uint8_t			rsvd;
+	uint8_t			port_id[3];
+	uint8_t			fc4_types[64];
+} __attribute__((__packed__));
+
+struct fc_rff_id {
+	struct fc_hdr	fchdr;
+	struct fc_ct_hdr	fc_ct_hdr;
+
+	uint8_t			rsvd;
+	uint8_t			port_id[3];
+	uint8_t			rsvd1;
+	uint8_t			rsvd2;
+	uint8_t			tgt;
+	uint8_t			fc4_type;
+} __attribute__((__packed__));
+
+struct fc_logo_req {
+	struct fc_hdr	fchdr;
+	uint8_t			command;
+	uint8_t			rsvd[3];
+
+	uint8_t			rsvd1;
+	uint8_t			fcid[3];
+
+	uint64_t		wwpn;
+}  __attribute__((__packed__));
+
+struct fc_fcp_cmnd {
+	struct fc_hdr	fchdr;
+	struct scsi_lun		fcp_lun;
+	uint8_t			cmd_ref;
+	uint8_t			pri_ta;
+	uint8_t			tm_flags;
+	uint8_t			add_cdblen_flags;
+	uint8_t			cdb[16];
+	uint32_t		dl;
+} __attribute__((__packed__));
+
+struct fc_fcp_rsp {
+	struct fc_hdr	fchdr;
+	uint8_t			rsvd[8];
+	uint16_t		retry_delay_tmr;	/* TBD this vs status_qual? */
+	uint8_t			flags;
+	uint8_t			scsi_status;
+	uint32_t		resid;
+	uint32_t		sense_len;
+	uint32_t		rsp_len;
+} __attribute__((__packed__));
+
+#endif /* _FDLS_FC_H */
diff --git a/drivers/staging/fnic2/src/fdls_if.c b/drivers/staging/fnic2/src/fdls_if.c
new file mode 100644
index 0000000..bd095f8
--- /dev/null
+++ b/drivers/staging/fnic2/src/fdls_if.c
@@ -0,0 +1,1254 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright 2018 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "fnic2.h"
+#include "fnic2_res.h"
+#include "cq_enet_desc.h"
+#include "cq_exch_desc.h"
+#include "fdls_fc.h"
+#include "fnic2_fdls.h"
+
+static int fnic2_fcpio_cmpl_handler(struct vnic_dev *vdev,
+				    unsigned int cq_index,
+				    struct fcpio_fw_req *desc);
+static int fnic2_fcpio_fw_reset_cmpl_handler(struct fnic2 *fnic2, struct fcpio_fw_req *desc);
+
+const char *fnic2_state_str[] = {
+	[FNIC2_IN_FC_MODE] = "FNIC2_IN_FC_MODE",
+	[FNIC2_IN_FC_TRANS_ETH_MODE] = "FNIC2_IN_FC_TRANS_ETH_MODE",
+	[FNIC2_IN_ETH_MODE] = "FNIC2_IN_ETH_MODE",
+	[FNIC2_IN_ETH_TRANS_FC_MODE] = "FNIC2_IN_ETH_TRANS_FC_MODE",
+};
+
+static const char *fcpio_status_str[] =  {
+	[FCPIO_SUCCESS] = "FCPIO_SUCCESS", /*0x0*/
+	[FCPIO_INVALID_HEADER] = "FCPIO_INVALID_HEADER",
+	[FCPIO_OUT_OF_RESOURCE] = "FCPIO_OUT_OF_RESOURCE",
+	[FCPIO_INVALID_PARAM] = "FCPIO_INVALID_PARAM]",
+	[FCPIO_REQ_NOT_SUPPORTED] = "FCPIO_REQ_NOT_SUPPORTED",
+	[FCPIO_IO_NOT_FOUND] = "FCPIO_IO_NOT_FOUND",
+	[FCPIO_ABORTED] = "FCPIO_ABORTED", /*0x41*/
+	[FCPIO_TIMEOUT] = "FCPIO_TIMEOUT",
+	[FCPIO_SGL_INVALID] = "FCPIO_SGL_INVALID",
+	[FCPIO_MSS_INVALID] = "FCPIO_MSS_INVALID",
+	[FCPIO_DATA_CNT_MISMATCH] = "FCPIO_DATA_CNT_MISMATCH",
+	[FCPIO_FW_ERR] = "FCPIO_FW_ERR",
+	[FCPIO_ITMF_REJECTED] = "FCPIO_ITMF_REJECTED",
+	[FCPIO_ITMF_FAILED] = "FCPIO_ITMF_FAILED",
+	[FCPIO_ITMF_INCORRECT_LUN] = "FCPIO_ITMF_INCORRECT_LUN",
+	[FCPIO_CMND_REJECTED] = "FCPIO_CMND_REJECTED",
+	[FCPIO_NO_PATH_AVAIL] = "FCPIO_NO_PATH_AVAIL",
+	[FCPIO_PATH_FAILED] = "FCPIO_PATH_FAILED",
+	[FCPIO_LUNMAP_CHNG_PEND] = "FCPIO_LUNHMAP_CHNG_PEND",
+};
+
+static const char *fnic2_fcpio_status_to_str(unsigned int status)
+{
+    if (status >= ARRAY_SIZE(fcpio_status_str) || !fcpio_status_str[status])
+	return "unknown";
+
+    return fcpio_status_str[status];
+}
+
+const char *fnic2_state_to_str(unsigned int state)
+{
+    if (state >= ARRAY_SIZE(fnic2_state_str) || !fnic2_state_str[state])
+	return "unknown";
+
+    return fnic2_state_str[state];
+}
+
+/* Frame initialization */
+/*
+ * Variables:
+ * dst_mac, src_mac
+ */
+struct fnic2_eth_hdr fnic2_eth_hdr_fcoe = {
+	.ether_type = 0x0689
+};
+
+/*
+ * Variables:
+ * None
+ */
+struct fnic2_fcoe_hdr fnic2_fcoe_hdr = {
+	.sof = 0x2E
+};
+
+uint8_t fcoe_all_fcf_mac[6] = {0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe};
+
+struct workqueue_struct *fnic2_event_queue;
+struct workqueue_struct *fip_event_queue;
+
+/* external */
+extern int fnic2_fw_reset_handler(struct fnic2 *fnic2);
+extern void fnic2_fcpio_tcmd_cmpl_handler(struct work_struct *work);
+extern void fnic2_fcp_recv(struct fnic2 *fnic2, uint8_t *fp, int frame_len);
+extern struct fnic2_cmd *fnic2_find_tcmd(struct fnic2 *fnic2, uint32_t cmd_tag);
+
+static inline int fnic2_import_rq_eth_pkt(struct fnic2 *fnic2, void *fp);
+
+/*
+ * Internal Functions
+ * This function will initialize the src_mac address to be
+ * used in outgoing frames
+ */
+static inline void fnic2_fdls_set_fcoe_srcmac(struct fnic2 *fnic2, uint8_t *src_mac)
+{
+	pr_debug("setting src_mac %02x, %02x, %02x, %02x, %02x, %02x\n",
+		src_mac[0], src_mac[1], src_mac[2],
+		src_mac[3], src_mac[4], src_mac[5]);
+
+	memcpy(fnic2->lport.fpma, src_mac, 6);
+}
+
+
+/*
+ * This function will initialize the dst_mac address to be
+ * used in outgoing frames
+ */
+static inline void fnic2_fdls_set_fcoe_dstmac(struct fnic2 *fnic2, uint8_t *dst_mac)
+{
+	pr_debug("setting dst_mac %02x, %02x, %02x, %02x, %02x, %02x\n",
+		dst_mac[0], dst_mac[1], dst_mac[2],
+		dst_mac[3], dst_mac[4], dst_mac[5]);
+
+	memcpy(fnic2->lport.fcfmac, dst_mac, 6);
+}
+
+static void fnic2_fdls_link_status_change(struct fnic2 *fnic2, int linkup)
+{
+	struct fnic2_lport *lport = &fnic2->lport;
+
+	pr_debug("fnic2 %d: fdls_link_status_change linkup: %d, usefip: %d\n",
+		fnic2->fnic2_num, linkup, lport->usefip);
+
+	if (linkup) {
+	    if (lport->usefip) {
+		lport->state = FNIC2_IPORT_STATE_FIP;
+		fnic2_fcoe_send_vlan_req(fnic2);
+	     } else {
+		lport->state = FNIC2_IPORT_STATE_FABRIC_DISC;
+		fnic2_fdls_disc_start(lport);
+	    }
+	} else {
+	    lport->state = FNIC2_IPORT_STATE_LINK_WAIT;
+	    vnic_dev_del_addr(fnic2->vdev, lport->fpma);
+	    fnic2_common_fip_cleanup(fnic2);
+	    fnic2_fdls_link_down(lport);
+	}
+}
+
+/*
+ * fnic2_fcpio_flogi_reg_cmpl_handler
+ * Routine to handle flogi register completion
+ */
+static int fnic2_fcpio_flogi_reg_cmpl_handler(struct fnic2 *fnic2, struct fcpio_fw_req *desc)
+{
+	uint8_t type;
+	uint8_t hdr_status;
+	uint32_t fcpio_tag;
+	int ret = 0;
+	unsigned long flags;
+
+	fcpio_header_dec(&desc->hdr, &type, &hdr_status, &fcpio_tag);
+
+	/* Update fnic2 state based on status of flogi reg completion */
+	spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+
+	if (fnic2->state == FNIC2_IN_ETH_TRANS_FC_MODE) {
+
+		/* Check flogi registration completion status */
+		if (!hdr_status) {
+			pr_debug("flog reg succeeded\n");
+			fnic2->state = FNIC2_IN_FC_MODE;
+		} else {
+			pr_debug("fnic2 flogi reg: failed %s\n",
+				fnic2_fcpio_status_to_str(hdr_status));
+			fnic2->state = FNIC2_IN_ETH_MODE;
+			ret = -1;
+		}
+	} else {
+		pr_debug("Unexpected fnic2 state %s while processing flogi reg completion\n",
+			fnic2_state_to_str(fnic2->state));
+		ret = -1;
+	}
+
+	if (!ret) {
+		if (fnic2->stop_rx_link_events) {
+			spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+			goto reg_cmpl_handler_end;
+		}
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+		fnic2_flush_tx(fnic2);
+		queue_work(fnic2_event_queue, &fnic2->frame_work);
+	} else {
+	    spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+	}
+
+reg_cmpl_handler_end:
+	return ret;
+}
+
+/*
+ * FPMA can be either taken from ethhdr(dst_mac) or flogi resp
+ * or derive from FC_MAP and FCID combination. While it should be
+ * same, revisit this if there is any possibility of not-correct.
+ */
+void fnic2_fdls_learn_fcoe_macs(struct fnic2_lport *lport, void *rx_frame, uint8_t *fcid)
+{
+	struct fnic2 *fnic2 = lport->fnic2;
+	struct fnic2_eth_hdr *ethhdr = (struct fnic2_eth_hdr *)rx_frame;
+	uint8_t fcmac[6] = {0x0E, 0xFC, 0x00, 0x00, 0x00, 0x00};
+
+	memcpy(&fcmac[3], fcid, 3);
+
+	pr_debug("learn_fcoe - dst_mac:%02x %02x %02x %02x %02x %02x\n",
+		ethhdr->dst_mac[0],  ethhdr->dst_mac[1],  ethhdr->dst_mac[2],
+		ethhdr->dst_mac[3],  ethhdr->dst_mac[4],  ethhdr->dst_mac[5]);
+
+	pr_debug("learn_fcoe - fc_mac:%02x %02x %02x %02x %02x %02x\n",
+		fcmac[0], fcmac[1], fcmac[2], fcmac[3], fcmac[4], fcmac[5]);
+
+	fnic2_fdls_set_fcoe_srcmac(fnic2, fcmac);
+	fnic2_fdls_set_fcoe_dstmac(fnic2, ethhdr->src_mac);
+}
+
+
+/* Public Functions */
+void fnic2_fdls_init(struct fnic2 *fnic2, int usefip)
+{
+	struct fnic2_lport *lport = &fnic2->lport;
+	uint8_t dstmac[6] = {0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe};
+
+	/* Initialize iPort structure */
+	lport->state = FNIC2_IPORT_STATE_INIT;
+	lport->fnic2 = fnic2;
+	lport->usefip = usefip;
+
+	/* Send the FCPIO_RESET to the firmware */
+	fnic2_scsi_fcpio_reset(lport);
+
+	pr_debug("lportsrcmac:%02x %02x %02x %02x %02x %02x\n",
+		lport->hwmac[0], lport->hwmac[1], lport->hwmac[2],
+		lport->hwmac[3], lport->hwmac[4], lport->hwmac[5]);
+
+	/* Initialize the src, and dst mac addresses for frame sender */
+	fnic2_fdls_set_fcoe_srcmac(fnic2, lport->hwmac);
+	fnic2_fdls_set_fcoe_dstmac(fnic2, dstmac);
+
+	fnic2_fdls_disc_init(lport);
+}
+
+/* At this time, should be called only during driver unload */
+void fnic2_fdls_cleanup(struct fnic2 *fnic2)
+{
+    pr_debug("fnic2 0x%pK Entered fnic2_fdls_cleanup\n", fnic2);
+
+}
+
+void fnic2_handle_link(struct work_struct *work)
+{
+	struct fnic2 *fnic2 = container_of(work, struct fnic2, link_work);
+	int old_link_status;
+	uint32_t old_link_down_cnt;
+	unsigned long flags;
+
+	pr_info("started fnic2_handle_link\n");
+
+	spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+	if (fnic2->stop_rx_link_events) {
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+		pr_debug("fnic2 0x%pK Stop RX link event", fnic2);
+		return;
+	 }
+
+	old_link_down_cnt = fnic2->link_down_cnt;
+	old_link_status = fnic2->link_status;
+	fnic2->link_status = vnic_dev_link_status(fnic2->vdev);
+	fnic2->link_down_cnt = vnic_dev_link_down_cnt(fnic2->vdev);
+
+	pr_debug("link status %d down cnt %d",
+		(int)fnic2->link_status, (int)fnic2->link_down_cnt);
+	pr_debug("old status %d old down cnt %d",
+		(int)old_link_status, old_link_down_cnt);
+
+	if (old_link_status == fnic2->link_status) {
+		if (!fnic2->link_status) {
+			/* DOWN -> DOWN */
+			spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+		} else {
+			if (old_link_down_cnt != fnic2->link_down_cnt) {
+				/* UP -> DOWN -> UP */
+				spin_unlock_irqrestore(&fnic2->fnic2_lock,
+							flags);
+				pr_debug("fnic2 %d: link down",
+					fnic2->fnic2_num);
+				fnic2_fdls_link_status_change(fnic2, 0);
+
+				pr_debug("fnic2 %d: link up",
+					 fnic2->fnic2_num);
+				fnic2_fdls_link_status_change(fnic2, 1);
+
+			} else {
+				/* UP -> UP */
+				spin_unlock_irqrestore(&fnic2->fnic2_lock,
+							 flags);
+			}
+		}
+	 } else if (fnic2->link_status) {
+		/* DOWN -> UP */
+
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+		pr_debug("fnic2 %d: link up", fnic2->fnic2_num);
+		fnic2_fdls_link_status_change(fnic2, 1);
+
+	 } else {
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+		pr_debug("fnic2 %d: recvd up to down event", fnic2->fnic2_num);
+		/* UP -> DOWN */
+		fnic2_fdls_link_status_change(fnic2, 0);
+	}
+}
+
+void fnic2_handle_frame(struct work_struct *work)
+{
+	struct fnic2_frame_list *cur_frame, *next;
+	unsigned long flags;
+	struct fnic2 *fnic2 = container_of(work, struct fnic2, frame_work);
+	int fchdr_offset = 0;
+
+	spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+	list_for_each_entry_safe(cur_frame, next, &fnic2->frame_queue, links) {
+		if (fnic2->stop_rx_link_events) {
+			list_del(&cur_frame->links);
+			spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+			kfree(cur_frame->fp);
+			kfree(cur_frame);
+			return;
+		}
+
+		/*
+		 * If we're in a transitional state, just re-queue and return.
+		 * The queue will be serviced when we get to a stable state.
+		 */
+		if (fnic2->state != FNIC2_IN_FC_MODE &&
+		    fnic2->state != FNIC2_IN_ETH_MODE) {
+			spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+			return;
+		}
+
+		list_del(&cur_frame->links);
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+		/* Frames from FCP_RQ will have ethhdrs stripped off */
+		fchdr_offset = (cur_frame->rx_ethhdr_stripped) ? 0 : FNIC2_FCOE_FCHDR_OFFSET;
+		fnic2_fdls_recv_frame(&fnic2->lport, cur_frame->fp,
+			cur_frame->frame_len, fchdr_offset);
+
+		kfree(cur_frame->fp);
+		kfree(cur_frame);
+		spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+	}
+	spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+}
+
+
+/* Process FIP frames */
+void fnic2_handle_fip_frame(struct work_struct *work)
+{
+	unsigned long flags;
+	struct fnic2_frame_list *cur_frame, *next;
+	struct fnic2 *fnic2 = container_of(work, struct fnic2, fip_work);
+
+	pr_debug("fnic2 0x%pK starting fnic2_handle_fip_frame\n", fnic2);
+
+	spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+	list_for_each_entry_safe(cur_frame, next, &fnic2->fip_frame_queue, links) {
+		pr_debug("fnic2 0x%pK got fip frame\n", fnic2);
+
+		if (fnic2->stop_rx_link_events) {
+		list_del(&cur_frame->links);
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+		kfree(cur_frame->fp);
+		kfree(cur_frame);
+		return;
+		}
+
+		/*
+		 * If we're in a transitional state, just re-queue and return.
+		 * The queue will be serviced when we get to a stable state.
+		 */
+		if (fnic2->state != FNIC2_IN_FC_MODE &&
+		    fnic2->state != FNIC2_IN_ETH_MODE) {
+			spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+			return;
+		}
+
+		list_del(&cur_frame->links);
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+		if (fdls_fip_recv_frame(fnic2, cur_frame->fp)) {
+			pr_debug("fnic2 0x%pK fip frame processed\n", fnic2);
+			kfree(cur_frame->fp);
+			kfree(cur_frame);
+		}
+		spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+	}
+	spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+}
+
+/**
+ * fnic2_import_rq_eth_pkt() - handle received FCoE or FIP frame.
+ * @fnic2:        fnic2 instance.
+ * @skb:        Ethernet Frame.
+ */
+static int fnic2_import_rq_eth_pkt(struct fnic2 *fnic2, void *fp)
+{
+	struct ethhdr *eh;
+	struct fnic2_frame_list *fip_fr_elem;
+
+	pr_debug("fnic2 0x%pK fnic2_import_rq_eth_pkt\n", fnic2);
+	eh = (struct ethhdr *) fp;
+	if (eh->h_proto ==  htons(0x8914)) {
+		pr_debug("fnic2 0x%pK fip frame enqueued\n", fnic2);
+		fip_fr_elem = (struct fnic2_frame_list *)
+		kmalloc(sizeof(struct fnic2_frame_list), __GFP_NOFAIL);
+		memset(fip_fr_elem, 0, sizeof(struct fnic2_frame_list));
+		fip_fr_elem->fp = fp;
+		list_add_tail(&fip_fr_elem->links, &fnic2->fip_frame_queue);
+		INIT_WORK(&fnic2->fip_work, fnic2_handle_fip_frame);
+		queue_work(fip_event_queue, &fnic2->fip_work);
+
+		return 1;               /* let caller know packet was used */
+	} else {
+		return 0;
+	}
+}
+
+static void fnic2_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc *cq_desc, struct vnic_rq_buf *buf, int skipped)
+{
+	struct fnic2 *fnic2 = vnic_dev_priv(rq->vdev);
+	uint8_t *fp;
+	unsigned int ethhdr_stripped;
+	uint8_t type, color, eop, sop, ingress_port, vlan_stripped;
+	uint8_t fcoe_fnic2_crc_ok = 1, fcoe_enc_error = 0;
+	uint8_t fcs_ok = 1, packet_error = 0;
+	uint16_t q_number, completed_index, vlan;
+	uint32_t rss_hash;
+	uint16_t checksum;
+	uint8_t csum_not_calc, rss_type, ipv4, ipv6, ipv4_fragment;
+	uint8_t tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok;
+	uint8_t fcoe = 0, fcoe_sof, fcoe_eof;
+	uint16_t exchange_id, tmpl;
+	uint8_t sof = 0;
+	uint8_t eof = 0;
+	uint32_t fcp_bytes_written = 0;
+	uint16_t enet_bytes_written = 0;
+	uint32_t bytes_written = 0;
+	unsigned long flags;
+	struct fnic2_frame_list *frame_elem = NULL;
+	struct fc_hdr *fchdr;
+	uint8_t fcp4_frame = 0;
+
+	pci_unmap_single(fnic2->pdev, buf->dma_addr, buf->len,
+		     PCI_DMA_FROMDEVICE);
+	fp = (uint8_t *)buf->os_buf;
+	buf->os_buf = NULL;
+
+	cq_desc_dec(cq_desc, &type, &color, &q_number, &completed_index);
+	if (type == CQ_DESC_TYPE_RQ_FCP) {
+		cq_fcp_rq_desc_dec((struct cq_fcp_rq_desc *)cq_desc,
+				   &type, &color, &q_number, &completed_index,
+				   &eop, &sop, &fcoe_fnic2_crc_ok, &exchange_id,
+				   &tmpl, &fcp_bytes_written, &sof, &eof,
+				   &ingress_port, &packet_error,
+				   &fcoe_enc_error, &fcs_ok, &vlan_stripped,
+				   &vlan);
+		ethhdr_stripped = 1;
+		bytes_written = fcp_bytes_written;
+
+		fchdr = (struct fc_hdr *)fp;
+		if (fchdr->r_ctl == FC_R_CTL_FC4_CMD ||
+		    fchdr->r_ctl == FNIC2_FC_R_CTL_ABTS ||
+		    fchdr->r_ctl == FC_R_CTL_FC4_STATUS) {
+			fcp4_frame = 1;
+		}
+
+		pr_debug("recvd FCP frame. rctl %x sz: %d, fcp4: %d\n", fchdr->r_ctl, fcp_bytes_written, fcp4_frame);
+	} else if (type == CQ_DESC_TYPE_RQ_ENET) {
+		cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc,
+				    &type, &color, &q_number, &completed_index,
+				    &ingress_port, &fcoe, &eop, &sop,
+				    &rss_type, &csum_not_calc, &rss_hash,
+				    &enet_bytes_written, &packet_error,
+				    &vlan_stripped, &vlan, &checksum,
+				    &fcoe_sof, &fcoe_fnic2_crc_ok,
+				    &fcoe_enc_error, &fcoe_eof,
+				    &tcp_udp_csum_ok, &udp, &tcp,
+				    &ipv4_csum_ok, &ipv6, &ipv4,
+				    &ipv4_fragment, &fcs_ok);
+
+		ethhdr_stripped = 0;
+		bytes_written = enet_bytes_written;
+
+		pr_debug("recvd ENET frame. sz: %d\n",
+			enet_bytes_written);
+
+		if (!fcs_ok) {
+			pr_debug("fnic2 0x%pK fcs error.  dropping packet.\n", fnic2);
+			goto drop;
+		}
+
+		if (fnic2_import_rq_eth_pkt(fnic2, fp)) {
+			return;
+	       }
+	} else {
+		/* wrong CQ type*/
+		pr_debug("fnic2 rq_cmpl wrong cq type 0x%x\n", type);
+		goto drop;
+	}
+
+	if (!fcs_ok || packet_error || !fcoe_fnic2_crc_ok || fcoe_enc_error) {
+		pr_debug("fnic2 rq_cmpl fcoe 0x%x fcsok 0x%x pkterr 0x%x fcoe_fnic2_crc_ok 0x%x, fcoe_enc_err 0x%x\n", fcoe, fcs_ok, packet_error,
+			fcoe_fnic2_crc_ok, fcoe_enc_error);
+		goto drop;
+	}
+
+	spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+	if (fnic2->stop_rx_link_events) {
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+		pr_debug("fnic2->stop_rx_link_events %x\n",
+		fnic2->stop_rx_link_events);
+		goto drop;
+	}
+
+	spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+	if (fcp4_frame) {
+		fnic2_fcp_recv(fnic2, fp, bytes_written);
+	} else {
+
+		frame_elem = (struct fnic2_frame_list *)
+			kmalloc(sizeof(struct fnic2_frame_list), __GFP_NOFAIL);
+		memset(frame_elem, 0, sizeof(struct fnic2_frame_list));
+		frame_elem->fp = fp;
+		frame_elem->rx_ethhdr_stripped = ethhdr_stripped;
+		frame_elem->frame_len = bytes_written;
+
+		spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+		list_add_tail(&frame_elem->links, &fnic2->frame_queue);
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+		queue_work(fnic2_event_queue, &fnic2->frame_work);
+	}
+	return;
+drop:
+	kfree(fp);
+}
+
+static int fnic2_rq_cmpl_handler_cont(struct vnic_dev *vdev, struct cq_desc *cq_desc, uint8_t type, uint16_t q_number, uint16_t completed_index)
+{
+	struct fnic2 *fnic2 = vnic_dev_priv(vdev);
+
+	vnic_rq_service(&fnic2->rq[q_number], cq_desc, completed_index,
+		VNIC_RQ_RETURN_DESC, fnic2_rq_cmpl_frame_recv);
+	return 0;
+}
+
+static inline int is_ack_index_in_range(struct vnic_wq_copy *wq, uint16_t request_out)
+{
+	if (wq->to_clean_index <= wq->to_use_index) {
+		/* out of range, stale request_out index */
+		if (request_out < wq->to_clean_index ||
+		    request_out >= wq->to_use_index)
+			return 0;
+	} else {
+		/* out of range, stale request_out index */
+		if (request_out < wq->to_clean_index &&
+		    request_out >= wq->to_use_index)
+			return 0;
+	}
+	/* request_out index is in range */
+	return 1;
+}
+
+
+/*
+ * Mark that ack received and store the Ack index. If there are multiple
+ * acks received before Tx thread cleans it up, the latest value will be
+ * used which is correct behavior. This state should be in the copy Wq
+ * instead of in the fnic2
+ */
+static inline void fnic2_fcpio_ack_handler(struct fnic2 *fnic2, unsigned int cq_index, struct fcpio_fw_req *desc)
+{
+	struct vnic_wq_copy *wq;
+	uint16_t request_out = desc->u.ack.request_out;
+	unsigned long flags;
+
+	/* mark the ack state */
+	wq = &fnic2->wq_copy[cq_index - fnic2->raw_wq_count - fnic2->rq_count];
+	spin_lock_irqsave(&fnic2->wq_copy_lock[0], flags);
+
+	if (is_ack_index_in_range(wq, request_out)) {
+		fnic2->fw_ack_index[0] = request_out;
+		fnic2->fw_ack_recd[0] = 1;
+	}
+
+	spin_unlock_irqrestore(&fnic2->wq_copy_lock[0], flags);
+}
+
+
+/* Free up Copy Wq descriptors. Called with copy_wq lock held */
+int free_wq_copy_descs(struct fnic2 *fnic2, struct vnic_wq_copy *wq)
+{
+	/* if no Ack received from firmware, then nothing to clean */
+	if (!fnic2->fw_ack_recd[0])
+		return 1;
+
+	/*
+	 * Update desc_available count based on number of freed descriptors
+	 * Account for wraparound
+	 */
+	if (wq->to_clean_index <= fnic2->fw_ack_index[0])
+		wq->ring.desc_avail += (fnic2->fw_ack_index[0]
+		    - wq->to_clean_index + 1);
+	else
+		wq->ring.desc_avail += (wq->ring.desc_count
+		    - wq->to_clean_index + fnic2->fw_ack_index[0] + 1);
+
+	/*
+	 * just bump clean index to ack_index+1 accounting for wraparound
+	 * this will essentially free up all descriptors between
+	 * to_clean_index and fw_ack_index, both inclusive
+	 */
+	wq->to_clean_index =
+		(fnic2->fw_ack_index[0] + 1) % wq->ring.desc_count;
+
+	/* we have processed the acks received so far */
+	fnic2->fw_ack_recd[0] = 0;
+	return 0;
+}
+
+
+/*
+ * fnic2_flogi_reg_handler
+ * Routine to send flogi register msg to fw
+ */
+static int fnic2_flogi_reg_handler(struct fnic2 *fnic2, uint32_t fnic2_id)
+{
+	struct vnic_wq_copy *wq = &fnic2->wq_copy[0];
+	enum fcpio_flogi_reg_format_type format;
+	uint8_t gw_mac[ETH_ALEN];
+	int ret = 0;
+
+
+	if (vnic_wq_copy_desc_avail(wq) <= fnic2->wq_copy_desc_low[0])
+		free_wq_copy_descs(fnic2, wq);
+
+	if (!vnic_wq_copy_desc_avail(wq)) {
+		ret = -1;
+		goto flogi_reg_ioreq_end;
+	}
+
+	memcpy(gw_mac, fnic2->lport.fcfmac, ETH_ALEN);
+	format = FCPIO_FLOGI_REG_GW_DEST;
+
+	if (fnic2->config.flags & VFCF_FIP_CAPABLE) {
+		fnic2_queue_wq_copy_desc_fip_reg(wq, SCSI_NO_TAG, fnic2_id,
+		    gw_mac, fnic2->lport.fpma, fnic2->lport.r_a_tov,
+		    fnic2->lport.e_d_tov);
+		pr_info("FLOGI FIP reg issued fcid %x src %pK dest %pK\n",
+			fnic2_id, fnic2->data_src_addr, gw_mac);
+	} else {
+		fnic2_queue_wq_copy_desc_flogi_reg(wq, SCSI_NO_TAG,
+		    format, fnic2_id, gw_mac);
+		pr_info("FLOGI reg issued fcid %x gw_mac %x %x %x %x %x %x",
+			fnic2_id, gw_mac[0], gw_mac[1],
+			gw_mac[2], gw_mac[3], gw_mac[4], gw_mac[5]);
+	}
+
+flogi_reg_ioreq_end:
+	return ret;
+}
+
+int fnic2_rq_cmpl_handler(struct fnic2 *fnic2, int rq_work_to_do)
+{
+	unsigned int tot_rq_work_done = 0, cur_work_done;
+	unsigned int i;
+
+	for (i = 0; i < fnic2->rq_count; i++) {
+		cur_work_done = vnic_cq_service(&fnic2->cq[i], rq_work_to_do,
+		    fnic2_rq_cmpl_handler_cont);
+		if (cur_work_done && fnic2->stop_rx_link_events != 1) {
+			vnic_rq_fill(&fnic2->rq[i], fnic2_alloc_rq_frame);
+		}
+		tot_rq_work_done += cur_work_done;
+	}
+	return tot_rq_work_done;
+}
+
+/*
+ * This function is called once at init time to allocate and fill RQ
+ * buffers. Subsequently, it is called in the interrupt context after RQ
+ * buffer processing to replenish the buffers in the RQ
+ */
+int fnic2_alloc_rq_frame(struct vnic_rq *rq)
+{
+	struct fnic2 *fnic2 = vnic_dev_priv(rq->vdev);
+	void *buf;
+	uint16_t len;
+	dma_addr_t pa;
+
+	len = FNIC2_RQ_FRAME_LEN;
+	buf = kmalloc(len, __GFP_NORETRY);
+	if (!buf) {
+		pr_debug("Unable to allocate RQ sk_buff\n");
+		return -ENOMEM;
+	}
+
+	pa = pci_map_single(fnic2->pdev, buf, len, PCI_DMA_FROMDEVICE);
+	fnic2_queue_rq_desc(rq, buf, pa, len);
+	return 0;
+}
+
+
+void fnic2_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf)
+{
+	void *rq_buf = buf->os_buf;
+	struct fnic2 *fnic2 = vnic_dev_priv(rq->vdev);
+
+	pci_unmap_single(fnic2->pdev, buf->dma_addr, buf->len,
+	PCI_DMA_FROMDEVICE);
+
+	kfree(rq_buf);
+	buf->os_buf = NULL;
+}
+
+static void fnic2_wq_complete_frame_send(struct vnic_wq *wq, struct cq_desc *cq_desc, struct vnic_wq_buf *buf)
+{
+	struct fnic2 *fnic2 = vnic_dev_priv(wq->vdev);
+
+	pci_unmap_single(fnic2->pdev, buf->dma_addr,
+	buf->len, PCI_DMA_TODEVICE);
+	kfree(buf->os_buf);
+	buf->os_buf = NULL;
+}
+
+
+static int fnic2_wq_cmpl_handler_cont(struct vnic_dev *vdev, struct cq_desc *cq_desc, uint8_t type, uint16_t q_number, uint16_t completed_index)
+{
+	struct fnic2 *fnic2 = vnic_dev_priv(vdev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&fnic2->wq_lock[q_number], flags);
+	vnic_wq_service(&fnic2->wq[q_number], cq_desc, completed_index,
+			fnic2_wq_complete_frame_send);
+	spin_unlock_irqrestore(&fnic2->wq_lock[q_number], flags);
+
+	return 0;
+}
+
+int fnic2_wq_cmpl_handler(struct fnic2 *fnic2, int work_to_do)
+{
+	unsigned int wq_work_done = 0;
+	unsigned int i;
+
+	for (i = 0; i < fnic2->raw_wq_count; i++) {
+		wq_work_done += vnic_cq_service(&fnic2->cq[fnic2->rq_count+i],
+		    work_to_do, fnic2_wq_cmpl_handler_cont);
+	}
+
+	return wq_work_done;
+}
+
+
+void fnic2_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
+{
+	struct fnic2 *fnic2 = vnic_dev_priv(wq->vdev);
+
+	pci_unmap_single(fnic2->pdev, buf->dma_addr,
+			 buf->len, PCI_DMA_TODEVICE);
+
+	kfree(buf->os_buf);
+	buf->os_buf = NULL;
+}
+
+/*
+ * Send FC frame.
+ */
+int fnic2_send_frame(struct fnic2 *fnic2, void *frame, int frame_len)
+{
+	struct vnic_wq *wq = &fnic2->wq[0];
+	dma_addr_t pa;
+	int ret = 0;
+	unsigned long flags;
+
+	pa = pci_map_single(fnic2->pdev, frame, frame_len, PCI_DMA_TODEVICE);
+
+	spin_lock_irqsave(&fnic2->wq_lock[0], flags);
+
+	if (!vnic_wq_desc_avail(wq)) {
+		pci_unmap_single(fnic2->pdev, pa,
+			frame_len, PCI_DMA_TODEVICE);
+		pr_err("vnic work queue descriptor is not available");
+		ret = -1;
+		goto fnic2_send_frame_end;
+	}
+
+	fnic2_queue_wq_desc(wq, frame, pa, frame_len, FNIC2_FCOE_EOF,
+		0 /* hw inserts cos value */,
+		fnic2->vlan_id, 1, 1, 1);
+
+fnic2_send_frame_end:
+	spin_unlock_irqrestore(&fnic2->wq_lock[0], flags);
+
+	if (ret) {
+		// TBD free buffer
+	}
+
+	return ret;
+}
+
+int fdls_send_fcoe_frame(struct fnic2 *fnic2, void *payload, int payload_sz, uint8_t *srcmac, uint8_t *dstmac)
+{
+	uint8_t *frame;
+	struct fnic2_eth_hdr *ethhdr;
+	struct fnic2_frame_list *frame_elem;
+	int max_framesz = FNIC2_FCOE_FRAME_MAXSZ;
+	unsigned long flags;
+	int len = 0;
+	int ret;
+
+	frame = (uint8_t *) kmalloc(max_framesz, __GFP_NORETRY);
+	if (!frame) {
+		pr_debug("fnic2 0x%pK Failed to allocate frame for flogi\n", fnic2);
+		return -1;
+	}
+	memset(frame, 0, max_framesz);
+
+	ethhdr = (struct fnic2_eth_hdr *)frame;
+
+	memcpy(frame, (uint8_t *)&fnic2_eth_hdr_fcoe, sizeof(struct fnic2_eth_hdr));
+	len = sizeof(struct fnic2_eth_hdr);
+
+	memcpy(ethhdr->src_mac, srcmac, ETH_ALEN);
+	memcpy(ethhdr->dst_mac, dstmac, ETH_ALEN);
+
+	memcpy(frame + len, (uint8_t *)&fnic2_fcoe_hdr, sizeof(struct fnic2_fcoe_hdr));
+	len += sizeof(struct fnic2_fcoe_hdr);
+
+	memcpy(frame + len, (uint8_t *)payload, payload_sz);
+	len += payload_sz;
+
+	//review: Handle this with the state in fdls for reg_done, and remove
+	//this logic
+	/*
+	 * Queue frame if in a transitional state.
+	 * This occurs while registering the Port_ID / MAC address after FLOGI.
+	 */
+	spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+
+	if ((fnic2->state != FNIC2_IN_FC_MODE) &&
+	    (fnic2->state != FNIC2_IN_ETH_MODE)) {
+		frame_elem = kmalloc(sizeof(struct fnic2_frame_list), __GFP_NORETRY);
+		if (frame_elem == NULL) {
+			spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+			return -ENOMEM;
+		}
+		memset(frame_elem, 0, sizeof(struct fnic2_frame_list));
+
+		pr_debug("Queueing frame: %pK\n", frame);
+
+		frame_elem->fp = frame;
+		frame_elem->frame_len = len;
+		list_add_tail(&frame_elem->links, &fnic2->tx_queue);
+
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+	ret = fnic2_send_frame(fnic2, frame, len);
+	return ret;
+}
+
+int fdls_send_fip_frame(struct fnic2 *fnic2, void *payload, int payload_sz)
+{
+	uint8_t *frame;
+	int max_framesz = FNIC2_FCOE_FRAME_MAXSZ;
+	int ret;
+
+	frame = (uint8_t *) kmalloc(max_framesz, __GFP_NORETRY);
+	if (!frame) {
+		pr_debug("fnic2 0x%pK Failed to allocate fip frame\n", fnic2);
+		return -1;
+	}
+	memset(frame, 0, max_framesz);
+
+	memcpy(frame, (uint8_t *)payload, payload_sz);
+	ret = fnic2_send_frame(fnic2, frame, payload_sz);
+
+	return ret;
+}
+
+int fnic2_send_fcoe_frame(struct fnic2_lport *lport, void *payload, int payload_sz)
+{
+	struct fnic2 *fnic2 = lport->fnic2;
+	uint8_t *dstmac, *srcmac;
+	int ret = 0;
+
+	/* If module unload is in-progress, don't send */
+	if (fnic2->in_remove)
+		return -1;
+
+	if (lport->fabric.flags & FNIC2_FDLS_FPMA_LEARNT) {
+		srcmac = lport->fpma;
+		dstmac = lport->fcfmac;
+	} else {
+		srcmac = lport->hwmac;
+		dstmac = fcoe_all_fcf_mac;
+	}
+
+	ret = fdls_send_fcoe_frame(fnic2, payload, payload_sz, srcmac, dstmac);
+
+	return ret;
+}
+
+int fnic2_send_fip_frame(struct fnic2_lport *lport, void *payload, int payload_sz)
+{
+    struct fnic2 *fnic2 = lport->fnic2;
+
+    if (fnic2->in_remove) {
+	return -1;
+    }
+
+    return fdls_send_fip_frame(fnic2, payload, payload_sz);
+}
+
+/**
+ * fnic2_flush_tx() - send queued frames.
+ * @fnic2: fnic2 device
+ *
+ * Send frames that were waiting to go out in FC or Ethernet mode.
+ * Whenever changing modes we purge queued frames, so these frames should
+ * be queued for the stable mode that we're in, either FC or Ethernet.
+ *
+ * Called without fnic2_lock held.
+ */
+void fnic2_flush_tx(struct fnic2 *fnic2)
+{
+	return;
+}
+
+int fnic2_fdls_register_portid(struct fnic2_lport *lport, uint32_t port_id, void *fp)
+{
+	struct fnic2 *fnic2 = lport->fnic2;
+	struct fnic2_eth_hdr *ethhdr;
+	unsigned long flags;
+	int ret;
+
+	pr_debug("setting port id: %x and fp: %pK, fnic2 state: %d",
+		port_id, fp, fnic2->state);
+
+	if (fp) {
+		ethhdr = (struct fnic2_eth_hdr *)fp;
+		vnic_dev_add_addr(fnic2->vdev, ethhdr->dst_mac);
+	}
+
+	/* Change state to reflect transition to FC mode */
+	spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+	if (fnic2->state == FNIC2_IN_ETH_MODE || fnic2->state == FNIC2_IN_FC_MODE) {
+		fnic2->state = FNIC2_IN_ETH_TRANS_FC_MODE;
+	} else {
+		pr_debug("fnic2 0x%pK Unexpected fnic2 state while processing flogi resp\n",
+			 fnic2);
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+		return -1;
+	}
+	spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+	/*
+	 * Send FLOGI registration to firmware to set up FC mode.
+	 * The new address will be set up when registration completes.
+	 */
+	ret = fnic2_flogi_reg_handler(fnic2, port_id);
+
+	if (ret < 0) {
+		spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+
+		pr_debug("flogi reg handeler Error ret: %d, fnic2 state: %d\n",
+			ret, fnic2->state);
+
+		if (fnic2->state == FNIC2_IN_ETH_TRANS_FC_MODE)
+			fnic2->state = FNIC2_IN_ETH_MODE;
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+		return -1;
+	}
+
+	pr_debug("fnic2 0x%pK Waiting for flogi registration\n", fnic2);
+
+	/* TODO: Use a timeout and handle it */
+	msleep(500);
+
+	lport->fabric.flags |= FNIC2_FDLS_FPMA_LEARNT;
+
+	pr_debug("fnic2 0x%pK flogi registration Success\n", fnic2);
+
+	return 0;
+}
+
+void fnic2_scsi_fcpio_reset(struct fnic2_lport *lport)
+{
+	int err = 0;
+	enum fnic2_state old_state;
+	struct fnic2 *fnic2 = lport->fnic2;
+	unsigned long flags;
+
+	/* Issue firmware reset for fnic2, wait for reset to complete */
+retry_fw_reset:
+	spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+	if (fnic2->state == FNIC2_IN_FC_TRANS_ETH_MODE) {
+		/* fw reset is in progress, poll for its completion */
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+		goto retry_fw_reset;
+	}
+	old_state = fnic2->state;
+	fnic2->state = FNIC2_IN_FC_TRANS_ETH_MODE;
+	spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+	err = fnic2_fw_reset_handler(fnic2);
+	spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+	if (err) {
+		if (fnic2->state == FNIC2_IN_FC_TRANS_ETH_MODE)
+			fnic2->state = old_state;
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+		return;
+	}
+
+	if (lport->state != FNIC2_IPORT_STATE_INIT) {
+	    //TBD
+	}
+
+	spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+}
+
+void fnic2_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, struct fcpio_host_req *desc)
+{
+    /* TBD */
+}
+
+void list_free_buffer(struct list_head *list)
+{
+	struct fnic2_frame_list *frame, *next;
+
+	if (!list_empty(list)) {
+		list_for_each_entry_safe(frame, next, list, links) {
+			kfree(frame->fp);
+			list_del(&frame->links);
+			kfree(frame);
+		}
+	}
+}
+
+/*
+ * fnic2_fw_reset_handler
+ * Routine to send reset msg to fw
+ */
+int fnic2_fw_reset_handler(struct fnic2 *fnic2)
+{
+	struct vnic_wq_copy *wq = &fnic2->wq_copy[0];
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+	list_free_buffer(&fnic2->frame_queue);
+	list_free_buffer(&fnic2->tx_queue);
+	if (fnic2->config.flags & VFCF_FIP_CAPABLE) {
+	    list_free_buffer(&fnic2->fip_frame_queue);
+	}
+	spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+	/* wait for io cmpl */
+	while (atomic_read(&fnic2->in_flight))
+		schedule_timeout(msecs_to_jiffies(1));
+
+	spin_lock_irqsave(&fnic2->wq_copy_lock[0], flags);
+
+	if (vnic_wq_copy_desc_avail(wq) <= fnic2->wq_copy_desc_low[0])
+		free_wq_copy_descs(fnic2, wq);
+
+	if (!vnic_wq_copy_desc_avail(wq))
+		ret = -EAGAIN;
+	else
+		fnic2_queue_wq_copy_desc_fw_reset(wq, SCSI_NO_TAG);
+
+	spin_unlock_irqrestore(&fnic2->wq_copy_lock[0], flags);
+
+	if (!ret)
+		pr_debug("Issued fw reset\n");
+	else
+		pr_debug("Failed to issue fw reset\n");
+
+	return ret;
+}
+
+/*
+ * fnic2_wq_copy_cmpl_handler
+ * Routine to process wq copy
+ */
+int fnic2_wq_copy_cmpl_handler(struct fnic2 *fnic2, int copy_work_to_do)
+{
+	unsigned int wq_work_done = 0;
+	unsigned int i, cq_index;
+	unsigned int cur_work_done;
+
+	for (i = 0; i < fnic2->wq_copy_count; i++) {
+		cq_index = i + fnic2->raw_wq_count + fnic2->rq_count;
+		cur_work_done = vnic_cq_copy_service(&fnic2->cq[cq_index],
+						     fnic2_fcpio_cmpl_handler,
+						     copy_work_to_do);
+		wq_work_done += cur_work_done;
+	}
+	return wq_work_done;
+}
+
+/*
+ * fnic2_fcpio_cmpl_handler
+ * Routine to service the cq for wq_copy
+ */
+static int fnic2_fcpio_cmpl_handler(struct vnic_dev *vdev,
+				    unsigned int cq_index,
+				    struct fcpio_fw_req *desc)
+{
+	struct fnic2 *fnic2 = vnic_dev_priv(vdev);
+	struct fnic2_cmd *tcmd;
+	int cpu;
+
+	switch (desc->hdr.type) {
+	case FCPIO_ACK: /* fw copied copy wq desc to its queue */
+		fnic2_fcpio_ack_handler(fnic2, cq_index, desc);
+		break;
+
+	case FCPIO_ICMND_CMPL: /* fw completed a command */
+		break;
+
+	case FCPIO_ITMF_CMPL: /* fw completed itmf (abort cmd, lun reset)*/
+		break;
+
+	case FCPIO_FLOGI_REG_CMPL: /* fw completed flogi_reg */
+	case FCPIO_FLOGI_FIP_REG_CMPL: /* fw completed flogi_fip_reg */
+		fnic2_fcpio_flogi_reg_cmpl_handler(fnic2, desc);
+		break;
+
+	case FCPIO_RESET_CMPL: /* fw completed reset */
+		fnic2_fcpio_fw_reset_cmpl_handler(fnic2, desc);
+		break;
+
+	case FCPIO_TCMD_SEND_DATA: /* fw completed sending rd data */
+	case FCPIO_TCMD_RECV_DATA: /* fw completed recving wr data */
+	case FCPIO_TCMD_FREE_CMD: /* fw completed freeing a cmd */
+	case FCPIO_TCMD_ABORT_CMD: /* fw completed an abort request */
+	case FCPIO_TCMD_TASK_MGMT: /* fw completed a task mgmt request */
+
+		pr_debug("FW completion received FDLS fcpio_tag %x\n", desc->hdr.fcpio_tag);
+		if (desc->hdr.fcpio_tag != 0xFFFFFFFF && desc->hdr.status != FCPIO_ABORTED) {
+			tcmd = fnic2_find_tcmd(fnic2, desc->hdr.fcpio_tag);
+			memcpy(&tcmd->fw_desc, desc, sizeof(struct fcpio_fw_req));
+
+			cpu = get_cpu_to_queue(tcmd->cmd_tag);
+
+			INIT_WORK(&tcmd->work, fnic2_fcpio_tcmd_cmpl_handler);
+			queue_work_on(cpu, fnic2_tcmd_wq, &tcmd->work);
+		}
+		break;
+
+	default:
+		pr_debug("firmware completion type %d\n", desc->hdr.type);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * fnic2_fcpio_fw_reset_cmpl_handler
+ * Routine to handle fw reset completion
+ */
+static int fnic2_fcpio_fw_reset_cmpl_handler(struct fnic2 *fnic2, struct fcpio_fw_req *desc)
+{
+	uint8_t type;
+	uint8_t hdr_status;
+	uint32_t fcpio_tag;
+	int ret = 0;
+	unsigned long flags;
+
+	fcpio_header_dec(&desc->hdr, &type, &hdr_status, &fcpio_tag);
+
+	spin_lock_irqsave(&fnic2->fnic2_lock, flags);
+
+	/* fnic2 should be in FC_TRANS_ETH_MODE */
+	if (fnic2->state == FNIC2_IN_FC_TRANS_ETH_MODE) {
+		/* Check status of reset completion */
+		if (!hdr_status) {
+			pr_debug("reset cmpl success\n");
+			/* Ready to send flogi out */
+			fnic2->state = FNIC2_IN_ETH_MODE;
+		} else {
+			pr_debug("fnic2 fw_reset : failed %s\n",
+				fnic2_fcpio_status_to_str(hdr_status));
+
+			/*
+			* Unable to change to eth mode, cannot send out flogi
+			* Change state to fc mode, so that subsequent Flogi
+			* requests from libFC will cause more attempts to
+			* reset the firmware. Free the cached flogi
+			*/
+			fnic2->state = FNIC2_IN_FC_MODE;
+			ret = -1;
+		}
+	} else {
+		pr_debug("Unexpected state %s while processing reset cmpl\n",
+			 fnic2_state_to_str(fnic2->state));
+		ret = -1;
+	}
+
+	/* Thread removing device blocks till firmware reset is complete */
+	if (fnic2->remove_wait)
+		complete(fnic2->remove_wait);
+
+	/*
+	* If fnic2 is being removed, or fw reset failed
+	* free the flogi frame. Else, send it out
+	*/
+	if (fnic2->remove_wait || ret) {
+		spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+		list_free_buffer(&fnic2->tx_queue);
+		goto reset_cmpl_handler_end;
+	}
+
+	spin_unlock_irqrestore(&fnic2->fnic2_lock, flags);
+
+	fnic2_flush_tx(fnic2);
+
+reset_cmpl_handler_end:
+	return ret;
+}
diff --git a/drivers/staging/fnic2/src/fnic2_fdls.h b/drivers/staging/fnic2/src/fnic2_fdls.h
new file mode 100644
index 0000000..bd6f797
--- /dev/null
+++ b/drivers/staging/fnic2/src/fnic2_fdls.h
@@ -0,0 +1,232 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright 2018 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _FNIC2_FDLS_H_
+#define _FNIC2_FDLS_H_
+
+#include <linux/list.h>
+#include "fdls_fc.h"
+#include "fcpio.h"
+#include "fnic2_lio.h"
+
+#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2]))
+
+#define hton24(p, v)    do {                    \
+		p[0] = (((v) >> 16) & 0xFF);    \
+		p[1] = (((v) >> 8) & 0xFF);     \
+		p[2] = ((v) & 0xFF);            \
+	} while (0)
+
+/* FDLS - Fabric discovery and login services
+ * -> VLAN discovery
+ *   -> retry every retry delay seconds until it succeeds.
+ *                        <- List of VLANs
+ *
+ * -> Solicitation
+ *                        <- Solicitation response (Advertisement)
+ *
+ * -> FCF selection & FLOGI ( FLOGI timeout - 2 * E_D_TOV)
+ *                        <- FLOGI response
+ *
+ * -> FCF keep alive
+ *                         <- FCF keep alive
+ *
+ * -> PLOGI to FFFFFC (DNS) (PLOGI timeout - 2 * R_A_TOV)
+ *    -> ABTS if timeout (ABTS tomeout - 2 * R_A_TOV)
+ *                        <- PLOGI response
+ *    -> Retry PLOGI to FFFFFC (DNS) - Number of retries from vnic.cfg
+ *
+ * -> GPN_FT to FFFFFC (GPN_FT timeout - 2 * R_A_TOV)a
+ *    -> Retry on BUSY until it succeeds
+ *    -> Retry on BUSY until it succeeds
+ *    -> 2 retries on timeout
+ *
+ * -> RFT_ID to FFFFFC (DNS)        (RFT_ID timeout - 3 * R_A_TOV)
+ *    -> ABTS if timeout (ABTS tomeout - 2 * R_A_TOV)
+ *    -> Retry RFT_ID to FFFFFC (DNS) (Number of retries 2 )
+ *    -> Ignore if both retires fail.
+ *
+ */
+#define FDLS_RETRY_COUNT 2
+
+struct fnic2_fip_fcf {
+	uint16_t	vlan_id;
+	uint8_t		fcf_mac[6];
+	uint8_t		fcf_priority; //??
+	uint16_t	fka_adv_period;
+	uint8_t		ka_disabled;
+};
+
+/* FDLS structure - not visible to fnic2 driver */
+enum fnic2_fdls_state {
+	FDLS_STATE_INIT = 0,
+	FDLS_STATE_LINKDOWN,
+	FDLS_STATE_FABRIC_FLOGI,
+	FDLS_STATE_FABRIC_PLOGI,
+	FDLS_STATE_RPN_ID,
+	FDLS_STATE_REGISTER_FC4_TYPES,
+	FDLS_STATE_REGISTER_FC4_FEATURES,
+	FDLS_STATE_TGT_ONLINE
+};
+
+#define FNIC2_FDLS_FABRIC_ABORT_ISSUED     0x1
+#define FNIC2_FDLS_FPMA_LEARNT             0x2
+
+struct fnic2_fdls_fabric {
+	enum fnic2_fdls_state	state;
+	uint32_t		flags;
+	struct list_head	rport_list; /* List of logged rports */
+
+	struct timer_list	retry_timer;
+	int			retry_counter;
+	int			timer_pending;
+
+};
+
+struct fnic2_fdls_fip {
+	uint32_t	state;
+	uint32_t	flogi_retry;
+};
+
+enum fdls_tgt_state {
+	fdls_rport_state_plogi		= 1,
+	fdls_rport_state_offlining	= 6
+};
+
+/* rport flags */
+#define FNIC2_FDLS_RETRY_FRAME          0x8
+
+struct fnic2_rport {
+	struct list_head	links; /* To link the rports */
+
+	enum fdls_tgt_state	state;
+	uint32_t		flags;
+	uint32_t		fcid;
+	uint64_t		wwpn;
+	uint64_t		wwnn;
+
+	struct timer_list	retry_timer;
+	int			retry_counter;
+	int			timer_pending;
+
+	void			*lport;
+};
+
+/* lport */
+enum fnic2_lport_state {
+	FNIC2_IPORT_STATE_INIT = 0,
+	FNIC2_IPORT_STATE_LINK_WAIT,
+	FNIC2_IPORT_STATE_FIP,
+	FNIC2_IPORT_STATE_FABRIC_DISC
+};
+
+struct fnic2_lport {
+	enum fnic2_lport_state		state;
+	struct fnic2			*fnic2;
+	uint64_t			boot_time;
+	uint32_t			flags;
+	int				usefip;
+	uint8_t				hwmac[6];  /* HW MAC Addr */
+	uint8_t				fpma[6];   /* Fabric Provided MA */
+	uint8_t				fcfmac[6]; /* MAC addr of Fabric */
+	uint16_t			vlan_id;
+	uint32_t			fcid;
+
+	struct fnic2_fip_fcf		selected_fcf;
+	struct fnic2_fdls_fip		fip;
+
+	struct fnic2_fdls_fabric	fabric;
+	struct list_head		rport_list;
+
+	/* Config block: */
+	uint32_t			e_d_tov; //msec
+	uint32_t			r_a_tov; //msec
+	uint32_t			link_supported_speeds;
+	uint32_t			max_flogi_retries;
+	uint32_t			max_plogi_retries;
+	uint32_t			service_params;
+	uint64_t			wwpn;
+	uint64_t			wwnn;
+	uint16_t			mfs;
+
+	spinlock_t			lport_lock;
+
+	struct fnic2_lport		*lport;
+};
+
+enum fnic2_recv_frame_type {
+	FNIC2_FABRIC_FLOGI_RSP	= 0,
+	FNIC2_FABRIC_PLOGI_RSP,
+	FNIC2_FABRIC_RPN_RSP,
+	FNIC2_FABRIC_RFT_RSP,
+	FNIC2_FABRIC_RFF_RSP,
+	FNIC2_TPORT_LOGO_RSP	= 9,
+	FNIC2_BLS_ABTS_RSP,
+	FNIC2_ELS_PLOGI_REQ,
+	FNIC2_ELS_PRLI_REQ,
+	FNIC2_ELS_LOGO_REQ,
+	FNIC2_ELS_RTV_REQ,
+	FNIC2_ELS_RRQ_REQ
+};
+
+#define FNIC2_FDLS_RETRY_FRAME          0x8
+
+/* Function Declarations */
+
+/* fdls_disc.c */
+void fnic2_fdls_disc_init(struct fnic2_lport *lport);
+void fnic2_fdls_disc_start(struct fnic2_lport *lport);
+void fnic2_fdls_recv_frame(struct fnic2_lport *lport, void *rx_frame, int len, int fchdr_offset);
+void fnic2_fdls_link_down(struct fnic2_lport *lport);
+void fdls_send_ba_acc(struct fnic2_lport *lport, struct fc_hdr *fchdr);
+void fdls_fabric_timer_callback(struct timer_list *timer);
+
+/* fdls_if.c */
+void fnic2_fdls_init(struct fnic2 *fnic2, int usefip);
+void fnic2_fdls_cleanup(struct fnic2 *fnic2);
+void fnic2_scsi_fcpio_reset(struct fnic2_lport *lport);
+
+int fnic2_send_fcoe_frame(struct fnic2_lport *lport, void *payload, int payload_sz);
+int fnic2_send_fip_frame(struct fnic2_lport *lport, void *payload, int payload_sz);
+void fnic2_fdls_learn_fcoe_macs(struct fnic2_lport *lport, void *rx_frame, uint8_t *fcid);
+void fnic2_set_port_id(struct fnic2_lport *lport, uint32_t port_id, void *fp);
+void fnic2_exch_mgr_reset(struct fnic2_lport *lport, uint32_t s_id, uint32_t d_id);
+void fnic2_fdls_link_down(struct fnic2_lport *lport);
+void list_free_buffer(struct list_head *list);
+int free_wq_copy_descs(struct fnic2 *fnic2, struct vnic_wq_copy *wq);
+
+/* fip.c */
+void fnic2_fcoe_reset_vlans(struct fnic2 *fnic2);
+void fnic2_fcoe_send_vlan_req(struct fnic2 *fnic2);
+void fnic2_common_fip_cleanup(struct fnic2 *fnic2);
+int fdls_fip_recv_frame(struct fnic2 *fnic2, void *frame);
+void fnic2_handle_fcs_ka_timer(struct timer_list *timer);
+void fnic2_handle_enode_ka_timer(struct timer_list *timer);
+void fnic2_handle_vn_ka_timer(struct timer_list *timer);
+void fnic2_handle_fip_timer(struct timer_list *timer);
+void fdls_send_logout(struct fnic2_lport *lport, struct fc_hdr *fchdr);
+
+/* utils */
+void fnic2_fdls_learn_fcoe_macs(struct fnic2_lport *lport, void *rx_frame, uint8_t *fcid);
+int fnic2_fdls_register_portid(struct fnic2_lport *lport, uint32_t port_id, void *fp);
+
+#define FNIC2_PORTSPEED_10GBIT   1
+#define FNIC2_FCOE_MAX_PAYLOAD   2048
+#define FNIC2_FCOE_FRAME_MAXSZ   2112
+#define FNIC2_RQ_FRAME_LEN       2148 //FC_FRAME_HEADROOM + FC_MAX_FRAME + FC_FRAME_TAILROOM
+#endif /* _FNIC2_FDLS_H_ */
-- 
1.8.3.1

  parent reply	other threads:[~2018-04-05 21:19 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-05 21:15 [PATCH 00/10] staging: fnic2 Driver Introduction Oliver Smith-Denny
2018-04-05 21:16 ` [PATCH 01/10] staging: fnic2 add initialization Oliver Smith-Denny
2018-04-06  5:07   ` Greg Kroah-Hartman
2018-04-06 22:00     ` Oliver Smith-Denny
2018-04-07  6:09       ` Greg Kroah-Hartman
2018-04-09 19:49         ` Oliver Smith-Denny
2018-04-09 20:57         ` Martin K. Petersen
2018-04-12 17:32           ` Oliver Smith-Denny
2018-04-05 21:17 ` [PATCH 02/10] staging: fnic2 add resource allocation Oliver Smith-Denny
2018-04-06  5:08   ` Greg Kroah-Hartman
2018-04-05 21:18 ` [PATCH 03/10] staging: fnic2 add fip handling Oliver Smith-Denny
2018-04-06  5:08   ` Greg Kroah-Hartman
2018-04-05 21:19 ` Oliver Smith-Denny [this message]
2018-04-05 21:20 ` [PATCH 05/10] staging: fnic2 add LIO interface Oliver Smith-Denny
2018-04-05 21:21 ` [PATCH 06/10] staging: fnic2 add main frame processing Oliver Smith-Denny
2018-04-05 21:21 ` [PATCH 07/10] staging: fnic2 add queue descriptors Oliver Smith-Denny
2018-04-05 21:22 ` [PATCH 08/10] staging: fnic2 add vnic queue interface Oliver Smith-Denny
2018-04-05 21:23 ` [PATCH 09/10] staging: fnic2 add vnic handling Oliver Smith-Denny
2018-04-05 21:24 ` [PATCH 10/10] staging: fnic2 add build and config Oliver Smith-Denny

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180405211928.GE12584@osmithde-lnx.cisco.com \
    --to=osmithde@cisco.com \
    --cc=gcboffa@cisco.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=sebaddel@cisco.com \
    --cc=target-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®