Add target hooks.

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

diff -upNr 4.1-rc7.orig/drivers/scsi/Kconfig 4.1-rc7/drivers/scsi/Kconfig
--- 4.1-rc7.orig/drivers/scsi/Kconfig   2015-05-31 10:05:16.189204634 +0200
+++ 4.1-rc7/drivers/scsi/Kconfig        2015-06-14 16:33:02.479543894 +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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/Makefile 
4.1-rc7/drivers/scsi/lpfc/Makefile
--- 4.1-rc7.orig/drivers/scsi/lpfc/Makefile     2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/Makefile  2015-06-14 16:33:02.479543894 +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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc.h 
4.1-rc7/drivers/scsi/lpfc/lpfc.h
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc.h       2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc.h    2015-06-14 16:33:02.479543894 +0200
@@ -441,6 +441,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 {
@@ -991,6 +994,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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_attr.c 
4.1-rc7/drivers/scsi/lpfc/lpfc_attr.c
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_attr.c  2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_attr.c       2015-06-14 16:33:02.483543894 
+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"
@@ -1144,7 +1148,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,
@@ -4571,6 +4575,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.
 #               Set                NOT Set
@@ -4806,6 +4834,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,
@@ -5808,6 +5839,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);
@@ -5855,6 +5907,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;
 }
 
@@ -5881,5 +5943,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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_ct.c 
4.1-rc7/drivers/scsi/lpfc/lpfc_ct.c
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_ct.c    2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_ct.c 2015-06-14 16:33:02.483543894 +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"
@@ -1284,7 +1288,13 @@ lpfc_ns_cmd(struct lpfc_vport *vport, in
                CtReq->CommandResponse.bits.CmdRsp =
                    cpu_to_be16(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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_debugfs.c 
4.1-rc7/drivers/scsi/lpfc/lpfc_debugfs.c
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_debugfs.c       2015-05-25 
03:22:35.000000000 +0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_debugfs.c    2015-06-14 16:33:02.487543894 
+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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_disc.h 
4.1-rc7/drivers/scsi/lpfc/lpfc_disc.h
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_disc.h  2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_disc.h       2015-06-14 16:33:02.487543894 
+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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_els.c 
4.1-rc7/drivers/scsi/lpfc/lpfc_els.c
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_els.c   2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_els.c        2015-06-14 16:33:02.491543894 
+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",
@@ -4222,6 +4265,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;
 
@@ -4236,6 +4282,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, "
@@ -4253,6 +4306,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.
@@ -4263,6 +4339,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;
@@ -4270,7 +4348,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",
@@ -4284,6 +4361,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;
 }
 
@@ -8107,7 +8201,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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_hbadisc.c 
4.1-rc7/drivers/scsi/lpfc/lpfc_hbadisc.c
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_hbadisc.c       2015-05-25 
03:22:35.000000000 +0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_hbadisc.c    2015-06-14 16:33:02.495543894 
+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[] = {
@@ -3473,6 +3480,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;
 }
 
@@ -3567,8 +3585,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);
@@ -4513,6 +4539,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)
@@ -4904,6 +4937,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;
@@ -5121,8 +5158,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);
@@ -5134,7 +5179,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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_hw.h 
4.1-rc7/drivers/scsi/lpfc/lpfc_hw.h
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_hw.h    2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_hw.h 2015-06-14 16:33:02.495543894 +0200
@@ -1427,6 +1427,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
@@ -1862,6 +1864,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 */
@@ -2787,7 +2793,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 {
@@ -3068,6 +3104,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) */
@@ -3711,6 +3749,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 */
 
@@ -3748,7 +3789,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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_init.c 
4.1-rc7/drivers/scsi/lpfc/lpfc_init.c
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_init.c  2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_init.c       2015-06-14 16:33:02.503543894 
+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,
@@ -6296,6 +6305,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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_mbox.c 
4.1-rc7/drivers/scsi/lpfc/lpfc_mbox.c
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_mbox.c  2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_mbox.c       2015-06-14 16:33:02.503543894 
+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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_mem.c 
4.1-rc7/drivers/scsi/lpfc/lpfc_mem.c
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_mem.c   2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_mem.c        2015-06-14 16:33:02.503543894 
+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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_nportdisc.c 
4.1-rc7/drivers/scsi/lpfc/lpfc_nportdisc.c
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_nportdisc.c     2015-05-25 
03:22:35.000000000 +0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_nportdisc.c  2015-06-14 16:33:02.507543894 
+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"
@@ -375,9 +379,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_plogi_confirm_nport skips fabric did, handle it here */
                if (!(ndlp->nlp_type & NLP_FABRIC)) {
@@ -1333,6 +1339,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;
@@ -1343,6 +1352,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 */
@@ -1361,6 +1436,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);
@@ -1574,9 +1650,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);
@@ -1699,6 +1788,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;
@@ -1828,6 +1920,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;
 }
@@ -2119,7 +2214,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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_scsi.c 
4.1-rc7/drivers/scsi/lpfc/lpfc_scsi.c
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_scsi.c  2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_scsi.c       2015-06-14 16:33:02.507543894 
+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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_sli.c 
4.1-rc7/drivers/scsi/lpfc/lpfc_sli.c
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_sli.c   2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_sli.c        2015-06-14 16:33:02.515543895 
+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 *,
@@ -1225,6 +1232,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:
@@ -1233,7 +1243,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:
@@ -1716,8 +1728,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
@@ -1824,7 +1841,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),
@@ -1861,7 +1878,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;
@@ -1891,8 +1908,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++;
@@ -1980,31 +2003,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.
@@ -2020,7 +2057,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);
        }
@@ -2389,6 +2430,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.
@@ -2406,14 +2496,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
 }
 
 /**
@@ -2479,9 +2575,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);
@@ -2497,6 +2604,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) {
@@ -2520,6 +2639,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,
@@ -2972,6 +3122,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++;
@@ -3030,7 +3183,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,
@@ -3042,6 +3196,7 @@ lpfc_sli_handle_fast_ring_event(struct l
                                        irsp->un.ulpWord[5],
                                        *(uint32_t *)&irsp->un1,
                                        *((uint32_t *)&irsp->un1 + 1));
+                       }
                }
 
                switch (type) {
@@ -3052,6 +3207,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"
@@ -3111,6 +3278,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)) {
@@ -7955,9 +8129,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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_sli.h 
4.1-rc7/drivers/scsi/lpfc/lpfc_sli.h
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_sli.h   2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_sli.h        2015-06-14 16:33:02.519543895 
+0200
@@ -321,6 +321,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 -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_version.h 
4.1-rc7/drivers/scsi/lpfc/lpfc_version.h
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_version.h       2015-05-25 
03:22:35.000000000 +0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_version.h    2015-06-14 16:33:02.519543895 
+0200
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "10.5.0.0."
+#define LPFC_DRIVER_VERSION "10.5.0.0_tm_10.0.0."
 #define LPFC_DRIVER_NAME               "lpfc"
 
 /* Used for SLI 2/3 */
diff -upNr 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_vport.c 
4.1-rc7/drivers/scsi/lpfc/lpfc_vport.c
--- 4.1-rc7.orig/drivers/scsi/lpfc/lpfc_vport.c 2015-05-25 03:22:35.000000000 
+0200
+++ 4.1-rc7/drivers/scsi/lpfc/lpfc_vport.c      2015-06-14 16:33:02.519543895 
+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);
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to