All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sebastian Herbszt <herbszt@gmx.de>
To: target-devel@vger.kernel.org, linux-scsi@vger.kernel.org
Cc: Christoph Hellwig <hch@infradead.org>,
	James Smart <james.smart@emulex.com>,
	Sebastian Herbszt <herbszt@gmx.de>
Subject: [RFC PATCH 2/2] lpfc: add target hooks
Date: Sun, 12 Apr 2015 16:17:40 +0200	[thread overview]
Message-ID: <20150412161740.00001d41@localhost> (raw)

Add target hooks.

Signed-off-by: Sebastian Herbszt <herbszt@gmx.de>
---

diff -uNrp 4.0-rc7.orig/drivers/scsi/Kconfig 4.0-rc7/drivers/scsi/Kconfig
--- 4.0-rc7.orig/drivers/scsi/Kconfig	2015-04-12 12:52:36.830558971 +0200
+++ 4.0-rc7/drivers/scsi/Kconfig	2015-04-12 12:53:01.582559694 +0200
@@ -1299,6 +1299,12 @@ config SCSI_LPFC_DEBUG_FS
 	  This makes debugging information from the lpfc driver
 	  available via the debugfs filesystem.
 
+config SCSI_LPFC_TARGET
+	bool "Emulex LightPulse Fibre Channel Target Support"
+	depends on SCSI_LPFC
+	help
+	  Support target mode.
+
 config SCSI_SIM710
 	tristate "Simple 53c710 SCSI support (Compaq, NCR machines)"
 	depends on (EISA || MCA) && SCSI
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/Makefile 4.0-rc7/drivers/scsi/lpfc/Makefile
--- 4.0-rc7.orig/drivers/scsi/lpfc/Makefile	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/Makefile	2015-04-12 10:32:24.654179770 +0200
@@ -31,3 +31,8 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o
 lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o	\
 	lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \
 	lpfc_vport.o lpfc_debugfs.o lpfc_bsg.o
+
+ifdef CONFIG_SCSI_LPFC_TARGET
+	ccflags-y += -DLPFC_TARGET_MODE
+	lpfc-objs += lpfc_target_api.o
+endif
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc.h 4.0-rc7/drivers/scsi/lpfc/lpfc.h
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc.h	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc.h	2015-04-12 10:32:24.658179770 +0200
@@ -438,6 +438,9 @@ struct lpfc_vport {
 	unsigned long rcv_buffer_time_stamp;
 	uint32_t vport_flag;
 #define STATIC_VPORT	1
+#if defined LPFC_TARGET_MODE && defined _H_LPFC_TGT_API_BASE
+	tm_tgtport_t target_tgtport;
+#endif
 };
 
 struct hbq_s {
@@ -988,6 +991,15 @@ struct lpfc_hba {
 	spinlock_t devicelock;	/* lock for luns list */
 	mempool_t *device_data_mem_pool;
 	struct list_head luns;
+#if defined LPFC_TARGET_MODE && defined _H_LPFC_TGT_API_BASE
+	uint32_t cfg_initialize_link;
+	uint32_t cfg_fcp_mode;
+#define LPFC_FCP_MODE_INITIATOR		1
+#define LPFC_FCP_MODE_TARGET		2
+	uint32_t poll_rsp_cnt;
+	uint32_t num_targets_bound;
+	tm_sliport_t target_sliport;
+#endif
 };
 
 static inline struct Scsi_Host *
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_attr.c 4.0-rc7/drivers/scsi/lpfc/lpfc_attr.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_attr.c	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_attr.c	2015-04-12 11:02:29.706161456 +0200
@@ -39,6 +39,10 @@
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
 #include "lpfc_sli4.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#endif
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -1139,7 +1143,7 @@ board_mode_out:
  * zero on error
  * one for success
  **/
-static int
+int
 lpfc_get_hba_info(struct lpfc_hba *phba,
 		  uint32_t *mxri, uint32_t *axri,
 		  uint32_t *mrpi, uint32_t *arpi,
@@ -4566,6 +4570,30 @@ LPFC_ATTR_R(multi_ring_rctl, FC_RCTL_DD_
 LPFC_ATTR_R(multi_ring_type, FC_TYPE_IP, 1,
 	     255, "Identifies TYPE for additional ring configuration");
 
+#ifdef LPFC_TARGET_MODE
+/*
+# lpfc_initialize_link:  Bring link up at initialization
+#            0x0  = do NOT bring link up (MBX_INIT_LINK)
+#            0x1  = bring link up (issue MBX_INIT_LINK)
+# Default value is 1.
+*/
+LPFC_ATTR_R(initialize_link, 1, 0, 1, "Bring Link Up at initialization");
+
+/*
+# lpfc_fcp_mode: determines target/initiator behavior. This is expressed
+# as an array. Every successive pair indicates {n, c}, where "n" is
+# hba number and "c" is characteristics. Value range of "c" is [1, 2].
+# where LPFC_FCP_MODE_INITIATOR        is 1 and LPFC_FCP_MODE_TARGET is 2.
+# Its possible to be both a target and an initiator.
+# The default value can be modified with the pair {-1, c}.
+*/
+static int lpfc_fcp_mode[64] = {-1, LPFC_FCP_MODE_TARGET};
+static int num_lpfc_fcp_mode;
+module_param_array(lpfc_fcp_mode, int, &num_lpfc_fcp_mode, 0);
+MODULE_PARM_DESC(lpfc_fcp_mode,
+	"List of values determining target/initiator behavior");
+#endif
+
 /*
 # lpfc_fdmi_on: controls FDMI support.
 #       0 = no FDMI support
@@ -4795,6 +4823,9 @@ struct device_attribute *lpfc_hba_attrs[
 	&dev_attr_lpfc_ack0,
 	&dev_attr_lpfc_topology,
 	&dev_attr_lpfc_scan_down,
+#ifdef LPFC_TARGET_MODE
+	&dev_attr_lpfc_initialize_link,
+#endif
 	&dev_attr_lpfc_link_speed,
 	&dev_attr_lpfc_fcp_io_sched,
 	&dev_attr_lpfc_fcp2_no_tgt_reset,
@@ -5797,6 +5828,27 @@ struct fc_function_template lpfc_vport_t
 void
 lpfc_get_cfgparam(struct lpfc_hba *phba)
 {
+#ifdef LPFC_TARGET_MODE
+	int i = 0, mode = LPFC_FCP_MODE_TARGET;
+
+	if (num_lpfc_fcp_mode & 1) {
+		printk("lpfc_fcp_mode expects pairs. Defaulting to "
+			"LPFC_FCP_MODE_TARGET.\n");
+	} else {
+		for (i = 0; i < num_lpfc_fcp_mode; i += 2) {
+			if (lpfc_fcp_mode[i] == -1) {
+				mode = lpfc_fcp_mode[i + 1];
+				break;
+			}
+			if (lpfc_fcp_mode[i] == phba->brd_no) {
+				mode = lpfc_fcp_mode[i + 1];
+				break;
+			}
+		}
+	}
+	phba->cfg_fcp_mode = mode;
+	lpfc_initialize_link_init(phba, lpfc_initialize_link);
+#endif
 	lpfc_fcp_io_sched_init(phba, lpfc_fcp_io_sched);
 	lpfc_fcp2_no_tgt_reset_init(phba, lpfc_fcp2_no_tgt_reset);
 	lpfc_cr_delay_init(phba, lpfc_cr_delay);
@@ -5844,6 +5896,16 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
 	lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
 	lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt);
 	phba->cfg_enable_dss = 1;
+#ifdef LPFC_TARGET_MODE
+	/* Its possible to be BOTH Target and Initiator */
+	if (!(phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR))
+		phba->cfg_initialize_link = 0;
+	if (phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET) {
+		phba->cfg_multi_ring_support = 2;
+		phba->cfg_multi_ring_rctl = FC_RCTL_DD_UNSOL_CMD;
+		phba->cfg_multi_ring_type = FC_TYPE_FCP;
+	}
+#endif
 	return;
 }
 
@@ -5870,5 +5932,9 @@ lpfc_get_vport_cfgparam(struct lpfc_vpor
 	lpfc_max_luns_init(vport, lpfc_max_luns);
 	lpfc_scan_down_init(vport, lpfc_scan_down);
 	lpfc_enable_da_id_init(vport, lpfc_enable_da_id);
+#ifdef LPFC_TARGET_MODE
+	if (!(vport->phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR))
+		vport->cfg_use_adisc = 1;
+#endif
 	return;
 }
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_ct.c 4.0-rc7/drivers/scsi/lpfc/lpfc_ct.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_ct.c	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_ct.c	2015-04-12 10:32:24.682179769 +0200
@@ -38,6 +38,10 @@
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
 #include "lpfc_sli4.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#endif
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -1247,7 +1251,13 @@ lpfc_ns_cmd(struct lpfc_vport *vport, in
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RFF_ID);
 		CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);
+#ifdef LPFC_TARGET_MODE
+		CtReq->un.rff.fbits = 0;
+		if (phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR)
+			CtReq->un.rff.fbits = FC4_FEATURE_INIT;
+#else
 		CtReq->un.rff.fbits = FC4_FEATURE_INIT;
+#endif
 		CtReq->un.rff.type_code = FC_TYPE_FCP;
 		cmpl = lpfc_cmpl_ct_cmd_rff_id;
 		break;
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_debugfs.c 4.0-rc7/drivers/scsi/lpfc/lpfc_debugfs.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_debugfs.c	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_debugfs.c	2015-04-12 10:32:24.686179769 +0200
@@ -40,6 +40,10 @@
 #include "lpfc_sli.h"
 #include "lpfc_sli4.h"
 #include "lpfc_nl.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#endif
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
 #include "lpfc.h"
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_disc.h 4.0-rc7/drivers/scsi/lpfc/lpfc_disc.h
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_disc.h	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_disc.h	2015-04-12 10:32:24.686179769 +0200
@@ -119,6 +119,15 @@ struct lpfc_nodelist {
 	unsigned long last_change_time;
 	unsigned long *active_rrqs_xri_bitmap;
 	struct lpfc_scsicmd_bkt *lat_data;	/* Latency data */
+#if defined LPFC_TARGET_MODE && defined _H_LPFC_TGT_API
+	tm_login_info_t      tm_login_info;
+	tm_login_handle_t    login_handle;
+	uint32_t             tm_check_login_result;
+	uint8_t              tm_check_login_called;
+	uint8_t              login_handle_valid;
+	uint16_t             tm_login_flags;
+#define NLP_TM_DELAYED_LOGIN   0x1
+#endif
 };
 struct lpfc_node_rrq {
 	struct list_head list;
@@ -147,6 +156,9 @@ struct lpfc_node_rrq {
 #define NLP_LOGO_ACC       0x00100000	/* Process LOGO after ACC completes */
 #define NLP_TGT_NO_SCSIID  0x00200000	/* good PRLI but no binding for scsid */
 #define NLP_ISSUE_LOGO     0x00400000	/* waiting to issue a LOGO */
+#ifdef LPFC_TARGET_MODE
+#define NLP_NEED_PRLI      0x00800000   /* Need PRLI to determine capability */
+#endif
 #define NLP_ACC_REGLOGIN   0x01000000	/* Issue Reg Login after successful
 					   ACC */
 #define NLP_NPR_ADISC      0x02000000	/* Issue ADISC when dq'ed from
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_els.c 4.0-rc7/drivers/scsi/lpfc/lpfc_els.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_els.c	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_els.c	2015-04-12 11:17:28.250152339 +0200
@@ -34,6 +34,10 @@
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
 #include "lpfc_sli4.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#endif
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -42,6 +46,9 @@
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
 #include "lpfc_debugfs.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_protos.h"
+#endif
 
 static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
 			  struct lpfc_iocbq *);
@@ -1963,6 +1970,18 @@ lpfc_issue_els_plogi(struct lpfc_vport *
 	uint16_t cmdsize;
 	int ret;
 
+#ifdef LPFC_TARGET_MODE
+	if (!(phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) &&
+		((did & Fabric_DID_MASK) != Fabric_DID_MASK) &&
+		!(vport->fc_flag & FC_PT2PT_PLOGI)) {
+		ndlp = lpfc_findnode_did(vport, did);
+		if (ndlp) {
+			ndlp->nlp_prev_state = ndlp->nlp_state;
+			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+		}
+		return 1;
+	}
+#endif
 	psli = &phba->sli;
 
 	ndlp = lpfc_findnode_did(vport, did);
@@ -2137,6 +2156,29 @@ lpfc_issue_els_prli(struct lpfc_vport *v
 
 	/* For PRLI, remainder of payload is PRLI parameter page */
 	npr = (PRLI *) pcmd;
+#ifdef LPFC_TARGET_MODE
+	/* check if we want to act as target */
+	if (lpfc_target_check_login(vport, ndlp) == TM_RCD_SUCCESS) {
+		/* success */
+		npr->targetFunc = 1;
+	}
+	npr->initiatorFunc = 0;
+	if (phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) {
+		npr->initiatorFunc = 1;
+		/* If we don't want to act as target, then tape OK */
+		if (!npr->targetFunc) {
+			/*
+			 * If our firmware version is 3.20 or later,
+			 * set the following bits for FC-TAPE support.
+			 */
+			if (phba->vpd.rev.feaLevelHigh >= 0x02) {
+				npr->ConfmComplAllowed = 1;
+				npr->Retry = 1;
+				npr->TaskRetryIdReq = 1;
+			}
+		}
+	}
+#else
 	/*
 	 * If our firmware version is 3.20 or later,
 	 * set the following bits for FC-TAPE support.
@@ -2146,6 +2188,8 @@ lpfc_issue_els_prli(struct lpfc_vport *v
 		npr->Retry = 1;
 		npr->TaskRetryIdReq = 1;
 	}
+	npr->initiatorFunc = 1;
+#endif
 	npr->estabImagePair = 1;
 	npr->readXferRdyDis = 1;
 	 if (vport->cfg_first_burst_size)
@@ -2153,7 +2197,6 @@ lpfc_issue_els_prli(struct lpfc_vport *v
 
 	/* For FCP support */
 	npr->prliType = PRLI_FCP_TYPE;
-	npr->initiatorFunc = 1;
 
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
 		"Issue PRLI:      did:x%x",
@@ -4214,6 +4257,9 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport
 	uint8_t *pcmd;
 	uint16_t cmdsize;
 	int rc;
+#ifdef LPFC_TARGET_MODE
+	uint8_t rem_initiatorFunc;
+#endif
 
 	psli = &phba->sli;
 
@@ -4228,6 +4274,13 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport
 	icmd->ulpContext = oldcmd->ulpContext;	/* Xri / rx_id */
 	icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
 
+#ifdef LPFC_TARGET_MODE
+	/* Check if the remote port support initiatorFunc */
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) oldiocb->context2)->virt);
+	pcmd += sizeof(uint32_t);
+	npr = (PRLI *) pcmd;
+	rem_initiatorFunc = npr->initiatorFunc;
+#endif
 	/* Xmit PRLI ACC response tag <ulpIoTag> */
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
 			 "0131 Xmit PRLI ACC response tag x%x xri x%x, "
@@ -4245,6 +4298,29 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport
 
 	npr = (PRLI *) pcmd;
 	vpd = &phba->vpd;
+#ifdef LPFC_TARGET_MODE
+	/* check if we want to act as target */
+	if (lpfc_target_check_login(vport, ndlp) == TM_RCD_SUCCESS) {
+		/* success */
+		npr->targetFunc = 1;
+	}
+	npr->initiatorFunc = 0;
+	if (phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) {
+		npr->initiatorFunc = 1;
+		/* If we don't want to act as target, then tape OK */
+		if (!npr->targetFunc) {
+			/*
+			 * If our firmware version is 3.20 or later,
+			 * set the following bits for FC-TAPE support.
+			 */
+			if (vpd->rev.feaLevelHigh >= 0x02) {
+				npr->ConfmComplAllowed = 1;
+				npr->Retry = 1;
+				npr->TaskRetryIdReq = 1;
+			}
+		}
+	}
+#else
 	/*
 	 * If the remote port is a target and our firmware version is 3.20 or
 	 * later, set the following bits for FC-TAPE support.
@@ -4255,6 +4331,8 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport
 		npr->Retry = 1;
 		npr->TaskRetryIdReq = 1;
 	}
+	npr->initiatorFunc = 1;
+#endif
 
 	npr->acceptRspCode = PRLI_REQ_EXECUTED;
 	npr->estabImagePair = 1;
@@ -4262,7 +4340,6 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport
 	npr->ConfmComplAllowed = 1;
 
 	npr->prliType = PRLI_FCP_TYPE;
-	npr->initiatorFunc = 1;
 
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
 		"Issue ACC PRLI:  did:x%x flg:x%x",
@@ -4276,6 +4353,23 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport
 		lpfc_els_free_iocb(phba, elsiocb);
 		return 1;
 	}
+#ifdef LPFC_TARGET_MODE
+	/* at this point initialize the target */
+	if (npr->acceptRspCode == PRLI_REQ_EXECUTED
+		&& npr->prliType == PRLI_FCP_TYPE
+		&& ndlp->tm_check_login_called
+		&& ndlp->tm_check_login_result == TM_RCD_SUCCESS
+		&& !ndlp->login_handle_valid
+		&& rem_initiatorFunc) {
+
+		if (ndlp->nlp_rpi) {
+			ndlp->login_handle = tm_tgtport_login(vport, ndlp);
+			if (ndlp->login_handle)
+				ndlp->login_handle_valid = 1;
+		} else
+			ndlp->tm_login_flags |= NLP_TM_DELAYED_LOGIN;
+	}
+#endif
 	return 0;
 }
 
@@ -8100,7 +8194,7 @@ static void lpfc_fabric_abort_vport(stru
 void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp)
 {
 	LIST_HEAD(completions);
-	struct lpfc_hba  *phba = ndlp->phba;
+	struct lpfc_hba  *phba = ndlp->vport->phba;
 	struct lpfc_iocbq *tmp_iocb, *piocb;
 	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
 
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_hbadisc.c 4.0-rc7/drivers/scsi/lpfc/lpfc_hbadisc.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_hbadisc.c	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_hbadisc.c	2015-04-12 11:04:15.786160379 +0200
@@ -33,6 +33,10 @@
 
 #include "lpfc_hw4.h"
 #include "lpfc_hw.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#endif
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_sli.h"
@@ -43,6 +47,9 @@
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
 #include "lpfc_debugfs.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_protos.h"
+#endif
 
 /* AlpaArray for assignment of scsid for scan-down and bind_method */
 static uint8_t lpfcAlpaArray[] = {
@@ -3468,6 +3475,17 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba
 	 */
 	lpfc_nlp_put(ndlp);
 
+#ifdef LPFC_TARGET_MODE
+	/* check if we need to notify the target api
+	 * set when prli has completed before reg_login mailbox cmd */
+	if (ndlp->tm_login_flags & NLP_TM_DELAYED_LOGIN) {
+		ndlp->tm_login_flags &= ~NLP_TM_DELAYED_LOGIN;
+		ndlp->login_handle = tm_tgtport_login(vport, ndlp);
+		if (ndlp->login_handle != NULL)
+			ndlp->login_handle_valid = 1;
+	}
+#endif
+
 	return;
 }
 
@@ -3562,8 +3580,16 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *p
 	spin_unlock_irq(shost->host_lock);
 	vport->num_disc_nodes = 0;
 	/* go thru NPR list and issue ELS PLOGIs */
+#ifdef LPFC_TARGET_MODE
+	if ((phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) ||
+		(vport->fc_flag & FC_PT2PT_PLOGI)) {
+		if (vport->fc_npr_cnt)
+			lpfc_els_disc_plogi(vport);
+	}
+#else
 	if (vport->fc_npr_cnt)
 		lpfc_els_disc_plogi(vport);
+#endif
 
 	if (!vport->num_disc_nodes) {
 		spin_lock_irq(shost->host_lock);
@@ -4493,6 +4519,13 @@ lpfc_unreg_rpi(struct lpfc_vport *vport,
 	int rc;
 	uint16_t rpi;
 
+#ifdef LPFC_TARGET_MODE
+	/* if there is a valid target login, need to logout now. */
+	tm_tgtport_logout(vport, ndlp->login_handle);
+	ndlp->login_handle = 0;
+	ndlp->login_handle_valid = 0;
+	ndlp->tm_check_login_called = 0;
+#endif
 	if (ndlp->nlp_flag & NLP_RPI_REGISTERED ||
 	    ndlp->nlp_flag & NLP_REG_LOGIN_SEND) {
 		if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
@@ -4869,6 +4902,10 @@ lpfc_setup_disc_node(struct lpfc_vport *
 
 	ndlp = lpfc_findnode_did(vport, did);
 	if (!ndlp) {
+#ifdef LPFC_TARGET_MODE
+		if (!(vport->phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR))
+			return NULL;
+#endif
 		if ((vport->fc_flag & FC_RSCN_MODE) != 0 &&
 		    lpfc_rscn_payload_check(vport, did) == 0)
 			return NULL;
@@ -5088,8 +5125,16 @@ lpfc_disc_start(struct lpfc_vport *vport
 		if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
 			vport->num_disc_nodes = 0;
 			/* go thru NPR nodes and issue ELS PLOGIs */
+#ifdef LPFC_TARGET_MODE
+			if ((phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) ||
+				(vport->fc_flag & FC_PT2PT_PLOGI)) {
+				if (vport->fc_npr_cnt)
+					lpfc_els_disc_plogi(vport);
+			}
+#else
 			if (vport->fc_npr_cnt)
 				lpfc_els_disc_plogi(vport);
+#endif
 
 			if (!vport->num_disc_nodes) {
 				spin_lock_irq(shost->host_lock);
@@ -5101,7 +5146,14 @@ lpfc_disc_start(struct lpfc_vport *vport
 		vport->port_state = LPFC_VPORT_READY;
 	} else {
 		/* Next do PLOGIs - if any */
+#ifdef LPFC_TARGET_MODE
+		if ((phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) ||
+			(vport->fc_flag & FC_PT2PT_PLOGI)) {
+			num_sent = lpfc_els_disc_plogi(vport);
+		}
+#else
 		num_sent = lpfc_els_disc_plogi(vport);
+#endif
 
 		if (num_sent)
 			return;
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_hw.h 4.0-rc7/drivers/scsi/lpfc/lpfc_hw.h
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_hw.h	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_hw.h	2015-04-12 10:32:24.702179769 +0200
@@ -1439,6 +1439,8 @@ typedef struct {		/* FireFly BIU registe
 #define MBX_PORT_IOV_CONTROL 0x3C
 
 #define MBX_CONFIG_HBQ	    0x7C
+#define MBX_PAUSE_HBQ      0x7D
+#define MBX_RESUME_HBQ     0x7E
 #define MBX_LOAD_AREA       0x81
 #define MBX_RUN_BIU_DIAG64  0x84
 #define MBX_CONFIG_PORT     0x88
@@ -1874,6 +1876,10 @@ typedef struct {
 #define	FLAGS_UNREG_LOGIN_ALL	     0x08 /* UNREG_LOGIN all on link down */
 #define FLAGS_LIRP_LILP              0x80 /* LIRP / LILP is disabled */
 
+#ifdef LPFC_TARGET_MODE
+#define FLAGS_DISABLE_TGT_ABTS       0x20       /* Bit 5 */
+#define FLAGS_DISABLE_GLBL_ABTS      0x02000    /* Bit 13 */
+#endif
 #define FLAGS_TOPOLOGY_FAILOVER      0x0400	/* Bit 10 */
 #define FLAGS_LINK_SPEED             0x0800	/* Bit 11 */
 #define FLAGS_IMED_ABORT             0x04000	/* Bit 14 */
@@ -2799,7 +2805,37 @@ struct config_hbq_var {
 
 };
 
+/* Structure for MB Command PAUSE_HBQ (7d) */
+struct pause_hbq_var {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t hbqId:16;
+	uint32_t rsvd1:16;
+#else  /*  __LITTLE_ENDIAN */
+	uint32_t rsvd1:16;
+	uint32_t hbqId:16;
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd2:16;
+	uint32_t mbTag16:16;
+#else  /*  __LITTLE_ENDIAN */
+	uint32_t mbTag16:16;
+	uint32_t rsvd2:16;
+#endif
+
+};
+
+/* Structure for MB Command RESUME_HBQ (7e) */
+struct resume_hbq_var {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t hbqId:16;
+	uint32_t hbqGetPtr:16;
+#else  /*  __LITTLE_ENDIAN */
+	uint32_t hbqGetPtr:16;
+	uint32_t hbqId:16;
+#endif
 
+};
 
 /* Structure for MB Command CONFIG_PORT (0x88) */
 typedef struct {
@@ -3080,6 +3116,8 @@ typedef union {
 					 * NEW_FEATURE
 					 */
 	struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ)  */
+	struct pause_hbq_var varPauseHbq; /* cmd = 0x7d (PAUSE_HBQ)  */
+	struct resume_hbq_var varResumeHbq; /* cmd = 0x7e (RESUME_HBQ)  */
 	struct update_cfg_var varUpdateCfg; /* cmd = 0x1B (UPDATE_CFG)*/
 	CONFIG_PORT_VAR varCfgPort;	/* cmd = 0x88 (CONFIG_PORT)  */
 	struct lpfc_mbx_read_top varReadTop; /* cmd = 0x95 (READ_TOPOLOGY) */
@@ -3723,6 +3761,9 @@ typedef struct _IOCB {	/* IOCB structure
 	uint32_t ulpTimeout:8;
 #endif
 
+#define ulpAc ulpOwner
+#define ulpAutoResponse ulpFCP2Rcvy
+
 	union {
 		struct rcv_sli3 rcvsli3; /* words 8 - 15 */
 
@@ -3760,7 +3801,7 @@ typedef struct _IOCB {	/* IOCB structure
 #define IOSTAT_INTERMED_RSP    0x8
 #define IOSTAT_LS_RJT          0x9
 #define IOSTAT_BA_RJT          0xA
-#define IOSTAT_RSVD1           0xB
+#define IOSTAT_CMD_RJT         0xB
 #define IOSTAT_RSVD2           0xC
 #define IOSTAT_RSVD3           0xD
 #define IOSTAT_RSVD4           0xE
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_init.c 4.0-rc7/drivers/scsi/lpfc/lpfc_init.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_init.c	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_init.c	2015-04-12 11:04:34.706160187 +0200
@@ -44,6 +44,10 @@
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
 #include "lpfc_sli4.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#endif
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -570,6 +574,11 @@ lpfc_config_port_post(struct lpfc_hba *p
 	mod_timer(&phba->eratt_poll,
 		  jiffies + msecs_to_jiffies(1000 * LPFC_ERATT_POLL_INTERVAL));
 
+#ifdef LPFC_TARGET_MODE
+	if (phba->cfg_initialize_link)
+		lpfc_init_link(phba, pmb, phba->cfg_topology,
+				phba->cfg_link_speed);
+#endif
 	if (phba->hba_flag & LINK_DISABLED) {
 		lpfc_printf_log(phba,
 			KERN_ERR, LOG_INIT,
@@ -6188,6 +6197,14 @@ lpfc_post_init_setup(struct lpfc_hba *ph
 		spin_unlock_irq(shost->host_lock);
 	}
 
+#ifdef LPFC_TARGET_MODE
+	if (!phba->cfg_initialize_link) {
+		/* After initialization, this should always be set */
+		phba->cfg_initialize_link = 1;
+		return;
+	}
+#endif
+
 	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
 			"0428 Perform SCSI scan\n");
 	/* Send board arrival event to upper layer */
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_mbox.c 4.0-rc7/drivers/scsi/lpfc/lpfc_mbox.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_mbox.c	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_mbox.c	2015-04-12 10:32:24.710179769 +0200
@@ -33,6 +33,10 @@
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
 #include "lpfc_sli4.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#endif
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -553,6 +557,12 @@ lpfc_init_link(struct lpfc_hba * phba,
 	else
 		mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO;
 
+#ifdef LPFC_TARGET_MODE
+	if (phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET) {
+		mb->un.varInitLnk.link_flags |=
+			(FLAGS_DISABLE_TGT_ABTS | FLAGS_DISABLE_TGT_ABTS);
+	}
+#endif
 	mb->mbxCommand = (volatile uint8_t)MBX_INIT_LINK;
 	mb->mbxOwner = OWN_HOST;
 	mb->un.varInitLnk.fabric_AL_PA = phba->fc_pref_ALPA;
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_mem.c 4.0-rc7/drivers/scsi/lpfc/lpfc_mem.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_mem.c	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_mem.c	2015-04-12 10:32:24.714179769 +0200
@@ -34,6 +34,10 @@
 #include "lpfc_sli.h"
 #include "lpfc_sli4.h"
 #include "lpfc_nl.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#endif
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
 #include "lpfc.h"
@@ -560,6 +564,7 @@ lpfc_in_buf_free(struct lpfc_hba *phba,
 {
 	struct hbq_dmabuf *hbq_entry;
 	unsigned long flags;
+	uint32_t hbqno;
 
 	if (!mp)
 		return;
@@ -573,7 +578,8 @@ lpfc_in_buf_free(struct lpfc_hba *phba,
 		}
 		hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf);
 		list_del(&hbq_entry->dbuf.list);
-		if (hbq_entry->tag == -1) {
+		hbqno = lpfc_hbqno_get(hbq_entry->tag);
+		if (hbqno >= LPFC_MAX_HBQS) {
 			(phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer)
 				(phba, hbq_entry);
 		} else {
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_nportdisc.c 4.0-rc7/drivers/scsi/lpfc/lpfc_nportdisc.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_nportdisc.c	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_nportdisc.c	2015-04-12 11:05:14.614159783 +0200
@@ -33,6 +33,10 @@
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
 #include "lpfc_sli4.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#endif
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -372,9 +376,11 @@ lpfc_rcv_plogi(struct lpfc_vport *vport,
 	case  NLP_STE_NPR_NODE:
 		if (!(ndlp->nlp_flag & NLP_NPR_ADISC))
 			break;
+	case  NLP_STE_UNMAPPED_NODE:
+		if (!ndlp->nlp_rpi)
+			break;
 	case  NLP_STE_REG_LOGIN_ISSUE:
 	case  NLP_STE_PRLI_ISSUE:
-	case  NLP_STE_UNMAPPED_NODE:
 	case  NLP_STE_MAPPED_NODE:
 		lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
 		return 1;
@@ -1312,6 +1318,9 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_
 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba   *phba = vport->phba;
 	struct lpfc_iocbq *cmdiocb, *rspiocb;
+#ifdef LPFC_TARGET_MODE
+	struct ls_rjt     stat;
+#endif
 	IOCB_t *irsp;
 	ADISC *ap;
 	int rc;
@@ -1322,6 +1331,72 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_
 	ap = (ADISC *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb);
 	irsp = &rspiocb->iocb;
 
+#ifdef LPFC_TARGET_MODE
+	if (irsp->ulpStatus) {
+		stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]);
+
+		/* did is alive but can't be authenticated */
+		if (stat.un.b.lsRjtRsnCode == LSRJT_UNABLE_TPC ||
+			stat.un.b.lsRjtRsnCode == LSRJT_CMD_UNSUPPORTED) {
+
+			lpfc_issue_els_logo(vport, ndlp, 0);
+			/* Put ndlp in npr state set plogi timer for 1 sec */
+			mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
+			spin_lock_irq(shost->host_lock);
+			ndlp->nlp_flag |= NLP_DELAY_TMO;
+			spin_unlock_irq(shost->host_lock);
+			ndlp->nlp_last_elscmd = ELS_CMD_ADISC;
+			ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
+			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+			return ndlp->nlp_state;
+		}
+
+		/* 1 sec timeout */
+		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+		spin_lock_irq(shost->host_lock);
+		ndlp->nlp_flag |= NLP_DELAY_TMO;
+		spin_unlock_irq(shost->host_lock);
+		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
+
+		memset(&ndlp->nlp_nodename, 0, sizeof(struct lpfc_name));
+		memset(&ndlp->nlp_portname, 0, sizeof(struct lpfc_name));
+
+		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+		lpfc_unreg_rpi(vport, ndlp);
+		return ndlp->nlp_state;
+
+	} else if (!lpfc_check_adisc(vport,
+				ndlp, &ap->nodeName, &ap->portName)) {
+		/* 1 sec timeout */
+		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+		spin_lock_irq(shost->host_lock);
+		ndlp->nlp_flag |= NLP_DELAY_TMO;
+		spin_unlock_irq(shost->host_lock);
+		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
+
+		memset(&ndlp->nlp_nodename, 0, sizeof(struct lpfc_name));
+		memset(&ndlp->nlp_portname, 0, sizeof(struct lpfc_name));
+
+		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+		lpfc_unreg_rpi(vport, ndlp);
+		return ndlp->nlp_state;
+	}
+	if (ndlp->nlp_flag & NLP_NEED_PRLI) {
+		/* Only if we are not a fabric nport do we issue PRLI */
+		if (!(ndlp->nlp_type & NLP_FABRIC)) {
+			ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
+			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
+			lpfc_issue_els_prli(vport, ndlp, 0);
+		} else {
+			ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
+			lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
+		}
+		return ndlp->nlp_state;
+	}
+
+#else
 	if ((irsp->ulpStatus) ||
 	    (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) {
 		/* 1 sec timeout */
@@ -1340,6 +1415,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_
 		lpfc_unreg_rpi(vport, ndlp);
 		return ndlp->nlp_state;
 	}
+#endif
 
 	if (phba->sli_rev == LPFC_SLI_REV4) {
 		rc = lpfc_sli4_resume_rpi(ndlp, NULL, NULL);
@@ -1553,9 +1629,22 @@ lpfc_cmpl_reglogin_reglogin_issue(struct
 
 	/* Only if we are not a fabric nport do we issue PRLI */
 	if (!(ndlp->nlp_type & NLP_FABRIC)) {
+#ifdef LPFC_TARGET_MODE
+		struct lpfc_hba   *phba = vport->phba;
+
+		if (phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR) {
+			ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
+			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
+			lpfc_issue_els_prli(vport, ndlp, 0);
+		} else {
+			ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
+			lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
+		}
+#else
 		ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
 		lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
 		lpfc_issue_els_prli(vport, ndlp, 0);
+#endif
 	} else {
 		ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
 		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
@@ -1678,6 +1767,9 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vp
 
 	cmdiocb = (struct lpfc_iocbq *) arg;
 	rspiocb = cmdiocb->context_un.rsp_iocb;
+#ifdef LPFC_TARGET_MODE
+	ndlp->nlp_flag &= ~NLP_NEED_PRLI;
+#endif
 	npr = (PRLI *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb);
 
 	irsp = &rspiocb->iocb;
@@ -1807,6 +1899,9 @@ lpfc_device_recov_prli_issue(struct lpfc
 	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
 	spin_unlock_irq(shost->host_lock);
+#ifdef LPFC_TARGET_MODE
+	ndlp->nlp_flag |= NLP_NEED_PRLI;
+#endif
 	lpfc_disc_set_adisc(vport, ndlp);
 	return ndlp->nlp_state;
 }
@@ -2098,7 +2193,16 @@ lpfc_rcv_prli_npr_node(struct lpfc_vport
 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
 	struct ls_rjt     stat;
+#ifdef LPFC_TARGET_MODE
+	struct lpfc_hba   *phba = vport->phba;
 
+	if (!(phba->cfg_fcp_mode & LPFC_FCP_MODE_INITIATOR)) {
+		lpfc_rcv_prli(vport, ndlp, cmdiocb);
+		ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
+		return ndlp->nlp_state;
+	}
+#endif
 	memset(&stat, 0, sizeof (struct ls_rjt));
 	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_scsi.c 4.0-rc7/drivers/scsi/lpfc/lpfc_scsi.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_scsi.c	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_scsi.c	2015-04-12 10:32:24.718179769 +0200
@@ -40,6 +40,10 @@
 #include "lpfc_sli.h"
 #include "lpfc_sli4.h"
 #include "lpfc_nl.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#endif
 #include "lpfc_disc.h"
 #include "lpfc.h"
 #include "lpfc_scsi.h"
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_sli.c 4.0-rc7/drivers/scsi/lpfc/lpfc_sli.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_sli.c	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_sli.c	2015-04-12 11:41:52.766137480 +0200
@@ -37,6 +37,10 @@
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
 #include "lpfc_sli4.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#endif
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -55,6 +59,9 @@ typedef enum _lpfc_iocb_type {
 	LPFC_ABORT_IOCB
 } lpfc_iocb_type;
 
+#ifdef LPFC_TARGET_MODE
+void lpfc_tm_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp);
+#endif
 
 /* Provide function prototypes local to this module. */
 static int lpfc_sli_issue_mbox_s4(struct lpfc_hba *, LPFC_MBOXQ_t *,
@@ -1221,6 +1228,9 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd
 	case CMD_IOCB_RCV_ELS64_CX:
 	case CMD_IOCB_RCV_CONT64_CX:
 	case CMD_IOCB_RET_XRI64_CX:
+#ifdef LPFC_TARGET_MODE
+	case CMD_IOCB_RET_HBQE64_CN:
+#endif
 		type = LPFC_UNSOL_IOCB;
 		break;
 	case CMD_IOCB_XMIT_MSEQ64_CR:
@@ -1229,7 +1239,9 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd
 	case CMD_IOCB_RCV_ELS_LIST64_CX:
 	case CMD_IOCB_CLOSE_EXTENDED_CN:
 	case CMD_IOCB_ABORT_EXTENDED_CN:
+#ifndef LPFC_TARGET_MODE
 	case CMD_IOCB_RET_HBQE64_CN:
+#endif
 	case CMD_IOCB_FCP_IBIDIR64_CR:
 	case CMD_IOCB_FCP_IBIDIR64_CX:
 	case CMD_IOCB_FCP_ITASKMGT64_CX:
@@ -1712,8 +1724,13 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba
 			(phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer)
 				(phba, hbq_buf);
 		} else {
+#ifdef LPFC_TARGET_MODE
+			hbqno = lpfc_hbqno_get(hbq_buf->tag);
+			if (hbq_buf->tag & QUE_BUFTAG_BIT)
+#else
 			hbqno = hbq_buf->tag >> 16;
 			if (hbqno >= LPFC_MAX_HBQS)
+#endif
 				(phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer)
 					(phba, hbq_buf);
 			else
@@ -1820,7 +1837,7 @@ lpfc_sli_hbq_to_firmware_s4(struct lpfc_
 /* HBQ for ELS and CT traffic. */
 static struct lpfc_hbq_init lpfc_els_hbq = {
 	.rn = 1,
-	.entry_count = 256,
+	.entry_count = 200,     /* 12 bits max size */
 	.mask_count = 0,
 	.profile = 0,
 	.ring_mask = (1 << LPFC_ELS_RING),
@@ -1857,7 +1874,7 @@ struct lpfc_hbq_init *lpfc_hbq_defs[] =
  * given HBQ. The function returns the number of HBQ buffers successfully
  * posted.
  **/
-static int
+int
 lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
 {
 	uint32_t i, posted = 0;
@@ -1887,8 +1904,14 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hb
 	while (!list_empty(&hbq_buf_list)) {
 		list_remove_head(&hbq_buf_list, hbq_buffer, struct hbq_dmabuf,
 				 dbuf.list);
+#ifdef LPFC_TARGET_MODE
+		/* convert app tag to base driver hbq tag */
+		i = phba->hbqs[hbqno].buffer_count;
+		hbq_buffer->tag = lpfc_build_hbq_tag(hbqno, i, hbq_buffer->tag);
+#else
 		hbq_buffer->tag = (phba->hbqs[hbqno].buffer_count |
 				      (hbqno << 16));
+#endif
 		if (!lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) {
 			phba->hbqs[hbqno].buffer_count++;
 			posted++;
@@ -1976,31 +1999,45 @@ lpfc_sli_hbqbuf_get(struct list_head *rb
  * it returns NULL.
  **/
 static struct hbq_dmabuf *
-lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
+__lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
 {
 	struct lpfc_dmabuf *d_buf;
 	struct hbq_dmabuf *hbq_buf;
 	uint32_t hbqno;
 
+#ifdef LPFC_TARGET_MODE
+	hbqno = lpfc_hbqno_get(tag);
+	if (tag & QUE_BUFTAG_BIT)
+		return NULL;
+#else
 	hbqno = tag >> 16;
 	if (hbqno >= LPFC_MAX_HBQS)
 		return NULL;
-
-	spin_lock_irq(&phba->hbalock);
+#endif
 	list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) {
 		hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
 		if (hbq_buf->tag == tag) {
-			spin_unlock_irq(&phba->hbalock);
 			return hbq_buf;
 		}
 	}
-	spin_unlock_irq(&phba->hbalock);
 	lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT,
 			"1803 Bad hbq tag. Data: x%x x%x\n",
-			tag, phba->hbqs[tag >> 16].buffer_count);
+			tag, phba->hbqs[hbqno].buffer_count);
 	return NULL;
 }
 
+static struct hbq_dmabuf *
+lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
+{
+	struct hbq_dmabuf *hbq_buf;
+
+	spin_lock_irq(&phba->hbalock);
+	hbq_buf = __lpfc_sli_hbqbuf_find(phba, tag);
+	spin_unlock_irq(&phba->hbalock);
+
+	return hbq_buf;
+}
+
 /**
  * lpfc_sli_free_hbq - Give back the hbq buffer to firmware
  * @phba: Pointer to HBA context object.
@@ -2016,7 +2053,11 @@ lpfc_sli_free_hbq(struct lpfc_hba *phba,
 	uint32_t hbqno;
 
 	if (hbq_buffer) {
+#ifdef LPFC_TARGET_MODE
+		hbqno = lpfc_hbqno_get(hbq_buffer->tag);
+#else
 		hbqno = hbq_buffer->tag >> 16;
+#endif
 		if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
 			(phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
 	}
@@ -2345,6 +2386,55 @@ lpfc_sli_handle_mb_event(struct lpfc_hba
 	return 0;
 }
 
+#ifdef LPFC_TARGET_MODE
+static struct lpfc_dmabuf *
+lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
+{
+	struct hbq_dmabuf *hbq_entry, *new_hbq_entry;
+	uint32_t hbqno, hbqidx, new_tag;
+	void *virt;             /* virtual address ptr */
+	dma_addr_t phys;        /* mapped address */
+	unsigned long flags;
+
+	/* Check whether HBQ is still in use */
+	spin_lock_irqsave(&phba->hbalock, flags);
+	if (!phba->hbq_in_use) {
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+		return NULL;
+	}
+
+	hbq_entry = __lpfc_sli_hbqbuf_find(phba, tag);
+	if (hbq_entry == NULL) {
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+		return NULL;
+	}
+	list_del(&hbq_entry->dbuf.list);
+
+	hbqno = lpfc_hbqno_get(tag);
+	hbqidx = lpfc_hbq_idx_get(tag);
+	new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
+	if (new_hbq_entry == NULL) {
+		list_add_tail(&hbq_entry->dbuf.list, &phba->rb_pend_list);
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+		return &hbq_entry->dbuf;
+	}
+	new_tag = lpfc_build_hbq_tag(hbqno, hbqidx, new_hbq_entry->tag);
+	phys = new_hbq_entry->dbuf.phys;
+	virt = new_hbq_entry->dbuf.virt;
+	new_hbq_entry->dbuf.phys = hbq_entry->dbuf.phys;
+	new_hbq_entry->dbuf.virt = hbq_entry->dbuf.virt;
+	new_hbq_entry->tag = tag;
+	hbq_entry->dbuf.phys = phys;
+	hbq_entry->dbuf.virt = virt;
+	hbq_entry->tag = new_tag;
+	lpfc_sli_free_hbq(phba, hbq_entry);
+	list_add_tail(&new_hbq_entry->dbuf.list, &phba->rb_pend_list);
+	spin_unlock_irqrestore(&phba->hbalock, flags);
+
+	return &new_hbq_entry->dbuf;
+}
+#endif
+
 /**
  * lpfc_sli_get_buff - Get the buffer associated with the buffer tag
  * @phba: Pointer to HBA context object.
@@ -2362,14 +2452,20 @@ lpfc_sli_get_buff(struct lpfc_hba *phba,
 		  struct lpfc_sli_ring *pring,
 		  uint32_t tag)
 {
+#ifndef LPFC_TARGET_MODE
 	struct hbq_dmabuf *hbq_entry;
+#endif
 
 	if (tag & QUE_BUFTAG_BIT)
 		return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
+#ifdef LPFC_TARGET_MODE
+	return lpfc_sli_replace_hbqbuff(phba, tag);
+#else
 	hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
 	if (!hbq_entry)
 		return NULL;
 	return &hbq_entry->dbuf;
+#endif
 }
 
 /**
@@ -2435,9 +2531,20 @@ lpfc_sli_process_unsol_iocb(struct lpfc_
 	uint32_t           Rctl, Type;
 	struct lpfc_iocbq *iocbq;
 	struct lpfc_dmabuf *dmzbuf;
+#ifdef LPFC_TARGET_MODE
+	uint32_t           i, tag;
+	struct hbq_dmabuf *hbq_entry;
+#endif
 
 	irsp = &(saveq->iocb);
 
+	if (unlikely(irsp->ulpStatus == IOSTAT_NEED_BUFFER)) {
+#ifdef LPFC_TARGET_MODE
+		if (pring->ringno == LPFC_EXTRA_RING)
+			lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_EXTRA_HBQ);
+#endif
+		return 1;
+	}
 	if (irsp->ulpCommand == CMD_ASYNC_STATUS) {
 		if (pring->lpfc_sli_rcv_async_status)
 			pring->lpfc_sli_rcv_async_status(phba, pring, saveq);
@@ -2453,6 +2560,18 @@ lpfc_sli_process_unsol_iocb(struct lpfc_
 		return 1;
 	}
 
+#ifdef LPFC_TARGET_MODE
+	/* Forward XRI ABORTED async response to target driver */
+	if ((saveq->iocb.ulpCommand == CMD_XRI_ABORTED_CX) &&
+		  (pring->ringno == LPFC_EXTRA_RING)) {
+		if (pring->prt[0].lpfc_sli_rcv_unsol_event) {
+			(pring->prt[0].lpfc_sli_rcv_unsol_event)
+					(phba, pring, saveq);
+		}
+		return 1;
+	}
+#endif
+
 	if ((irsp->ulpCommand == CMD_IOCB_RET_XRI64_CX) &&
 		(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) {
 		if (irsp->ulpBdeCount > 0) {
@@ -2476,6 +2595,37 @@ lpfc_sli_process_unsol_iocb(struct lpfc_
 		return 1;
 	}
 
+	if ((irsp->ulpCommand == CMD_IOCB_RET_HBQE64_CN) &&
+		(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) {
+#ifdef LPFC_TARGET_MODE
+		if (pring->ringno != LPFC_EXTRA_RING)
+			return 1;
+
+		for (i = 0; i < irsp->ulpBdeCount; i++) {
+			switch (i) {
+			case 0:
+				tag = irsp->un.ulpWord[3];
+				break;
+			case 1:
+				tag = irsp->unsli3.sli3Words[3];
+				break;
+			case 2:
+				tag = irsp->unsli3.sli3Words[7];
+				break;
+			default:
+				return 1;
+			}
+			hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
+
+			if (hbq_entry) {
+				list_del(&hbq_entry->dbuf.list);
+				lpfc_tm_hbq_free(phba, hbq_entry);
+			}
+		}
+#endif
+		return 1;
+	}
+
 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
 		if (irsp->ulpBdeCount != 0) {
 			saveq->context2 = lpfc_sli_get_buff(phba, pring,
@@ -2928,6 +3078,9 @@ lpfc_sli_handle_fast_ring_event(struct l
 	lpfc_iocb_type type;
 	unsigned long iflag;
 	uint32_t rsp_cmpl = 0;
+#ifdef LPFC_TARGET_MODE
+	int rsp_cnt = 0;
+#endif
 
 	spin_lock_irqsave(&phba->hbalock, iflag);
 	pring->stats.iocb_event++;
@@ -2986,7 +3139,8 @@ lpfc_sli_handle_fast_ring_event(struct l
 			}
 
 			/* Rsp ring <ringno> error: IOCB */
-			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+			if (irsp->ulpStatus != IOSTAT_NEED_BUFFER) {
+				lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
 					"0336 Rsp Ring %d error: IOCB Data: "
 					"x%x x%x x%x x%x x%x x%x x%x x%x\n",
 					pring->ringno,
@@ -2998,6 +3152,7 @@ lpfc_sli_handle_fast_ring_event(struct l
 					irsp->un.ulpWord[5],
 					*(uint32_t *)&irsp->un1,
 					*((uint32_t *)&irsp->un1 + 1));
+			}
 		}
 
 		switch (type) {
@@ -3008,6 +3163,18 @@ lpfc_sli_handle_fast_ring_event(struct l
 			 * resources need to be recovered.
 			 */
 			if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
+#ifdef LPFC_TARGET_MODE
+			/* If target mode port */
+			/* send XRI_ABORTED to target driver */
+			if ((pring->ringno == LPFC_EXTRA_RING) &&
+				 (phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET)) {
+				spin_unlock_irqrestore(&phba->hbalock, iflag);
+				lpfc_sli_process_unsol_iocb
+					(phba, pring, &rspiocbq);
+				spin_lock_irqsave(&phba->hbalock, iflag);
+				break;
+			}
+#endif
 				lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
 						"0333 IOCB cmd 0x%x"
 						" processed. Skipping"
@@ -3067,6 +3234,13 @@ lpfc_sli_handle_fast_ring_event(struct l
 
 		if (pring->sli.sli3.rspidx == portRspPut)
 			portRspPut = le32_to_cpu(pgp->rspPutInx);
+#ifdef LPFC_TARGET_MODE
+		if ((pring->ringno == LPFC_EXTRA_RING) && phba->poll_rsp_cnt) {
+			rsp_cnt++;
+			if (rsp_cnt >= phba->poll_rsp_cnt)
+				break;
+		}
+#endif
 	}
 
 	if ((rsp_cmpl > 0) && (mask & HA_R0RE_REQ)) {
@@ -7911,9 +8085,10 @@ __lpfc_sli_issue_iocb_s3(struct lpfc_hba
 
 	/*
 	 * Check to see if we are blocking IOCB processing because of a
-	 * outstanding event.
+	 * outstanding event. IOCBs like CMD_QUE_RING_BUF* (without a cmpl)
+	 * should be allowed through.
 	 */
-	if (unlikely(pring->flag & LPFC_STOP_IOCB_EVENT))
+	if (unlikely(pring->flag & LPFC_STOP_IOCB_EVENT) && piocb->iocb_cmpl)
 		goto iocb_busy;
 
 	if (unlikely(phba->link_state == LPFC_LINK_DOWN)) {
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_sli.h 4.0-rc7/drivers/scsi/lpfc/lpfc_sli.h
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_sli.h	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_sli.h	2015-04-12 10:32:24.742179769 +0200
@@ -320,6 +320,37 @@ struct lpfc_sli {
 	struct lpfc_lnk_stat lnk_stat_offsets;
 };
 
+/*
+ * Functions to build or extract fields for HBQ buffer tags.
+ * The applications tag is in bits 30:16, the hbqno in 15:12,
+ * the hbq entry index is in bits 11:0 The high order bit (31)
+ * is reserved for non-hbq buffer use.
+ */
+static inline uint32_t
+lpfc_build_hbq_tag(uint16_t hbqno, uint16_t hbqidx, uint16_t app_tag)
+{
+	return ((app_tag & 0x7fff) << 16) |
+		((hbqno & 0xf) << 12) | (hbqidx & 0xfff);
+}
+
+static inline uint16_t
+lpfc_hbq_app_tag_get(uint32_t tag)
+{
+	return (tag >> 16) & 0x7fff;
+}
+
+static inline uint16_t
+lpfc_hbq_idx_get(uint32_t tag)
+{
+	return tag & 0xfff;
+}
+
+static inline uint16_t
+lpfc_hbqno_get(uint32_t tag)
+{
+	return (tag >> 12) & 0xf;
+}
+
 /* Timeout for normal outstanding mbox command (Seconds) */
 #define LPFC_MBOX_TMO				30
 /* Timeout for non-flash-based outstanding sli_config mbox command (Seconds) */
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_version.h 4.0-rc7/drivers/scsi/lpfc/lpfc_version.h
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_version.h	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_version.h	2015-04-12 10:32:24.750179769 +0200
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "10.4.8000.0."
+#define LPFC_DRIVER_VERSION "10.4.8000.0_tm_10.0.0."
 #define LPFC_DRIVER_NAME		"lpfc"
 
 /* Used for SLI 2/3 */
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_vport.c 4.0-rc7/drivers/scsi/lpfc/lpfc_vport.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_vport.c	2015-04-07 00:39:45.000000000 +0200
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_vport.c	2015-04-12 10:32:24.754179769 +0200
@@ -37,6 +37,10 @@
 #include "lpfc_hw.h"
 #include "lpfc_sli.h"
 #include "lpfc_sli4.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#endif
 #include "lpfc_nl.h"
 #include "lpfc_disc.h"
 #include "lpfc_scsi.h"
@@ -45,6 +49,9 @@
 #include "lpfc_crtn.h"
 #include "lpfc_version.h"
 #include "lpfc_vport.h"
+#ifdef LPFC_TARGET_MODE
+#include "lpfc_target_protos.h"
+#endif
 
 inline void lpfc_vport_set_state(struct lpfc_vport *vport,
 				 enum fc_vport_state new_state)
@@ -419,6 +426,11 @@ lpfc_vport_create(struct fc_vport *fc_vp
 		goto out;
 	}
 
+#ifdef LPFC_TARGET_MODE
+	if (phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET)
+		lpfc_target_new_tgtport(vport);
+#endif
+
 	if ((phba->link_state < LPFC_LINK_UP) ||
 	    (pport->port_state < LPFC_FABRIC_CFG_LINK) ||
 	    (phba->fc_topology == LPFC_TOPOLOGY_LOOP)) {
@@ -777,6 +789,11 @@ skip_logo:
 	} else
 		scsi_host_put(shost);
 
+#ifdef LPFC_TARGET_MODE
+	if (phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET)
+		lpfc_target_rm_tgtport(vport);
+#endif
+
 	lpfc_free_vpi(phba, vport->vpi);
 	vport->work_port_events = 0;
 	spin_lock_irq(&phba->hbalock);

             reply	other threads:[~2015-04-12 14:17 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-12 14:17 Sebastian Herbszt [this message]
2015-04-15  0:25 ` [RFC PATCH 2/2] lpfc: add target hooks Andy Grover
2015-04-24 22:50   ` Sebastian Herbszt
  -- strict thread matches above, loose matches on Subject: below --
2015-06-14 15:26 Sebastian Herbszt

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=20150412161740.00001d41@localhost \
    --to=herbszt@gmx.de \
    --cc=hch@infradead.org \
    --cc=james.smart@emulex.com \
    --cc=linux-scsi@vger.kernel.org \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.