Add target infrastructure.

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

diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_target_api.c 
4.0-rc7/drivers/scsi/lpfc/lpfc_target_api.c
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_target_api.c    1970-01-01 
01:00:00.000000000 +0100
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_target_api.c 2015-04-12 11:29:57.314144739 
+0200
@@ -0,0 +1,902 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2003-2008 Emulex.  All rights reserved.           *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ *                                                                 *
+ * This program is free software; you can redistribute it and/or   *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "lpfc_version.h"
+#include "lpfc_hw4.h"
+#include "lpfc_hw.h"
+#include "lpfc_target_api.h"
+#include "lpfc_target_api_base.h"
+#include "lpfc_nl.h"
+#include "lpfc_sli.h"
+#include "lpfc_sli4.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_target_protos.h"
+#include "lpfc_crtn.h"
+
+int lpfc_tgt_init(void);
+int lpfc_tgt_exit(void);
+
+int lpfctm_num_hba = 0;
+void lpfc_tm_down_link(tm_sliport_handle_t lpfc_port_handle);
+void lpfc_tm_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp);
+void lpfc_tm_tgtport_unbind(tm_tgtport_handle_t base_handle);
+
+extern int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
+extern int lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *, uint32_t, uint32_t);
+extern struct lpfc_vport *lpfc_find_vport_by_vpid(struct lpfc_hba *, uint16_t);
+void lpfc_tm_recv_unsol(struct lpfc_hba *phba,
+                    struct lpfc_sli_ring *pring, struct lpfc_iocbq *iocb);
+struct hbq_dmabuf *lpfc_tm_hbq_alloc(struct lpfc_hba *phba);
+void lpfc_tm_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp);
+int lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri, uint32_t *axri,
+         uint32_t *mrpi, uint32_t *arpi, uint32_t *mvpi, uint32_t *avpi);
+
+extern struct lpfc_hbq_init *lpfc_hbq_defs[];
+
+int lpfc_target_sliport_init(struct lpfc_hba *phba, struct pci_dev *pci_dev)
+{
+       uint32_t           result;
+       tm_sliport_info_t *sliport_info;
+       tm_driver_data_t  *driver_data = lpfc_tgt_data;
+       tm_sliport_t      *sliport = &phba->target_sliport;
+
+       /* set up parameters in port info */
+       sliport_info = &phba->target_sliport.info;
+       sliport_info->sli_version = *(uint32_t *)&phba->pcb;
+       sliport_info->iotag16_mask = 0xc000;
+       sliport_info->pcidev = phba->pcidev;
+
+       /* allow negotiation on init call if hbq num is zero in driver data */
+       sliport_info->max_tgt_contexts = phba->cfg_hba_queue_depth;
+       if (driver_data->tm_num_hbq_buf &&
+               driver_data->tm_num_hbq_buf < sliport_info->max_tgt_contexts)
+               sliport_info->max_tgt_contexts = driver_data->tm_num_hbq_buf;
+
+       if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+               sliport_info->flags |= LPFC_TM_SLI3_HBQ_ENABLED;
+               sliport_info->flags |= LPFC_TM_HBQ_TAGS_SUPPORTED;
+       } else {
+               sliport_info->flags &= ~LPFC_TM_SLI3_HBQ_ENABLED;
+               sliport_info->flags &= ~LPFC_TM_HBQ_TAGS_SUPPORTED;
+       }
+
+       result = lpfc_tgt_data->tm_sliport_init((tm_sliport_handle_t *)phba,
+                       sliport_info, &phba->target_sliport.target_slihandle);
+
+       if (result == TM_RCD_SUCCESS) {
+               struct lpfc_sli *psli;
+               struct lpfc_sli_ring *pring;
+
+               psli = &phba->sli;
+               pring = &psli->ring[LPFC_EXTRA_RING];
+
+               /* protect against user brain damage */
+               if (sliport_info->max_tgt_contexts > phba->cfg_hba_queue_depth)
+                       sliport_info->max_tgt_contexts =
+                               phba->cfg_hba_queue_depth;
+
+               pring->prt[0].lpfc_sli_rcv_unsol_event = lpfc_tm_recv_unsol;
+
+               if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+                       phba->hbqs[LPFC_EXTRA_HBQ].hbq_alloc_buffer =
+                                       lpfc_tm_hbq_alloc;
+                       phba->hbqs[LPFC_EXTRA_HBQ].hbq_free_buffer =
+                                       lpfc_tm_hbq_free;
+                       if (!lpfc_sli_hbqbuf_fill_hbqs(phba, LPFC_EXTRA_HBQ,
+                                       sliport_info->max_tgt_contexts)) {
+                               result = TM_RCD_FAILURE;
+                       }
+               }
+               sliport->interrupt_callback_allowed = 0;
+               atomic_set(&sliport->interrupt_in_progress, 0);
+       }
+       return result;
+}
+
+int lpfc_tgt_init(void)
+{
+       struct Scsi_Host  *host;
+       struct lpfc_vport *vport, *pport;
+       struct lpfc_hba   *phba;
+       struct pci_dev    *dev = NULL;
+       uint32_t           result;
+
+       while ((dev = pci_get_device(PCI_VENDOR_ID_EMULEX, PCI_ANY_ID,
+                                                               dev)) != NULL) {
+               host = pci_get_drvdata(dev);
+               if (host != NULL) {
+                       pport = (struct lpfc_vport *) host->hostdata;
+                       phba = pport->phba;
+                       if (phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET)
+                               lpfctm_num_hba++;
+               }
+       }
+
+       if (!lpfctm_num_hba) {
+               printk(KERN_ERR "lpfctm: No lpfc HBAs supporting target mode 
found\n");
+               return -ENODEV;
+       }
+
+       dev = NULL;
+       while ((dev = pci_get_device(PCI_VENDOR_ID_EMULEX, PCI_ANY_ID,
+                                                               dev)) != NULL) {
+               host = pci_get_drvdata(dev);
+               if (host != NULL) {
+                       pport = (struct lpfc_vport *) host->hostdata;
+                       phba = pport->phba;
+                       if (!(phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET))
+                               continue;
+
+                       result = lpfc_target_sliport_init(phba, dev);
+                       if (result) {
+                               printk(KERN_ERR "lpfc_tm: "
+                                       "Unable to init target sliport\n");
+                               return -ENODEV;
+                       }
+               }
+       }
+
+       dev = NULL;
+       while ((dev = pci_get_device(PCI_VENDOR_ID_EMULEX, PCI_ANY_ID,
+                                                               dev)) != NULL) {
+               host = pci_get_drvdata(dev);
+               if (host != NULL) {
+                       pport = (struct lpfc_vport *) host->hostdata;
+                       phba = pport->phba;
+                       if (!(phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET))
+                               continue;
+                       list_for_each_entry(vport, &phba->port_list,
+                                                       listentry) {
+                               lpfc_target_new_tgtport(vport);
+                       }
+                       lpfc_tm_init_link(phba);
+               }
+       }
+       return 0;
+}
+
+int
+lpfc_tgt_exit(void)
+{
+       struct lpfc_hba   *phba;
+       struct lpfc_vport *vport, *pport;
+       struct Scsi_Host  *host;
+       struct pci_dev    *dev = NULL;
+
+       dev = NULL;
+       while ((dev = pci_get_device(PCI_VENDOR_ID_EMULEX, PCI_ANY_ID,
+                                                               dev)) != NULL) {
+               host = pci_get_drvdata(dev);
+               if (host != NULL) {
+                       pport = (struct lpfc_vport *) host->hostdata;
+                       phba = pport->phba;
+                       if (!(phba->cfg_fcp_mode & LPFC_FCP_MODE_TARGET))
+                               continue;
+                       list_for_each_entry(vport, &phba->port_list,
+                                                       listentry) {
+                               /* Add code to cleanup tgtport */
+                       }
+                       lpfc_tm_down_link(phba);
+               }
+       }
+       return 0;
+}
+
+int
+lpfc_tm_get_max_rpi(tm_sliport_handle_t lpfc_sliport_handle, uint32_t *max_rpi)
+{
+       int status;
+       struct lpfc_hba *phba;
+       uint32_t mxri, axri, arpi, mvpi, avpi;
+
+       phba = (struct lpfc_hba *)lpfc_sliport_handle;
+
+       status = lpfc_get_hba_info(phba,
+                       &mxri, &axri, max_rpi, &arpi, &mvpi, &avpi);
+       if (status == 0)
+               return TM_RCD_FAILURE;
+       return TM_RCD_SUCCESS;
+}
+EXPORT_SYMBOL(lpfc_tm_get_max_rpi);
+
+static inline void tm_rsp_recv(struct lpfc_vport *vport, IOCB_t *iocb)
+{
+       tm_tgtport_handle_t target_handle;
+
+       atomic_inc(&vport->target_tgtport.calls_outstanding);
+       target_handle = vport->target_tgtport.target_handle;
+       if (target_handle)
+               lpfc_tgt_data->tm_rsp_recv(target_handle, iocb);
+       atomic_dec(&vport->target_tgtport.calls_outstanding);
+}
+
+void
+lpfc_tm_recv_unsol(struct lpfc_hba *phba,
+                    struct lpfc_sli_ring *pring, struct lpfc_iocbq *iocb)
+{
+       struct lpfc_vport *vport = NULL;
+       IOCB_t *icmd = &iocb->iocb;
+       uint16_t vpi;
+       struct lpfc_dmabuf *dmabuf, *next_dmabuf;
+       struct hbq_dmabuf *hbq_buf;
+       unsigned long flags;
+       uint32_t hbqno;
+
+       if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+            (icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
+               vpi = icmd->unsli3.rcvsli3.vpi;
+               if (vpi != 0xffff)
+                       vport = lpfc_find_vport_by_vpid(phba, vpi);
+       }
+       if (vport == NULL)
+               vport = phba->pport;
+
+       /* Initiator must be logged in for any incoming SCSI request */
+       switch (icmd->ulpCommand) {
+       case CMD_IOCB_RCV_SEQ64_CX:
+               /* transparently restore applications SLI-3 hbq io tag */
+               icmd->un.ulpWord[3] = lpfc_hbq_app_tag_get(icmd->un.ulpWord[3]);
+               /* FALLTHRU */
+
+       case CMD_RCV_SEQUENCE64_CX:
+               tm_rsp_recv(vport, icmd);
+               break;
+
+       default:
+               tm_rsp_recv(vport, icmd);
+       }
+
+       /* Now get rid of all HBQs that are in-flight */
+       if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+               spin_lock_irqsave(&phba->hbalock, flags);
+               list_for_each_entry_safe(dmabuf, next_dmabuf,
+                       &phba->rb_pend_list, list) {
+                       hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
+                       hbqno = lpfc_hbqno_get(hbq_buf->tag);
+                       if (hbqno == LPFC_EXTRA_HBQ) {
+                               list_del(&hbq_buf->dbuf.list);
+                               kfree(hbq_buf);
+                       }
+               }
+               spin_unlock_irqrestore(&phba->hbalock, flags);
+       }
+}
+
+static void
+lpfc_tm_recv_sol(struct lpfc_hba *phba,
+                   struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb)
+{
+       struct lpfc_vport *vport = NULL;
+
+       vport = cmdiocb->vport;
+       if (vport == NULL)
+               vport = phba->pport;
+       tm_rsp_recv(vport, &rspiocb->iocb);
+       lpfc_sli_release_iocbq(phba, cmdiocb);
+}
+
+struct hbq_dmabuf *
+lpfc_tm_hbq_alloc(struct lpfc_hba *phba)
+{
+       struct hbq_dmabuf *hbqbp;
+       tm_sliport_handle_t target_sliport;
+       struct tm_hbq_dmabuf *tm_hbqbp;
+
+       hbqbp = kmalloc(sizeof(struct hbq_dmabuf), GFP_ATOMIC);
+       if (!hbqbp)
+               return NULL;
+
+       tm_hbqbp = (struct tm_hbq_dmabuf *)hbqbp;
+       atomic_inc(&phba->target_sliport.calls_outstanding);
+       target_sliport = phba->target_sliport.target_slihandle;
+       if (target_sliport)
+               lpfc_tgt_data->tm_hbq_alloc(target_sliport, tm_hbqbp);
+       atomic_dec(&phba->target_sliport.calls_outstanding);
+       if (tm_hbqbp->dbuf.virt == NULL) {
+               kfree(hbqbp);
+               return NULL;
+       }
+
+       return hbqbp;
+}
+
+void
+lpfc_tm_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp)
+{
+       tm_sliport_handle_t target_sliport;
+       struct tm_hbq_dmabuf *tm_hbqbp;
+
+       tm_hbqbp = (struct tm_hbq_dmabuf *)hbqbp;
+       hbqbp->tag = lpfc_hbq_app_tag_get(hbqbp->tag);
+       atomic_inc(&phba->target_sliport.calls_outstanding);
+       target_sliport = phba->target_sliport.target_slihandle;
+       if (target_sliport)
+               lpfc_tgt_data->tm_hbq_free(target_sliport, tm_hbqbp);
+       atomic_dec(&phba->target_sliport.calls_outstanding);
+       kfree(hbqbp);
+}
+
+/* encapsulate all calls to target module */
+uint32_t
+tm_tgtport_bind(struct lpfc_vport *vport, tm_tgtport_info_t *portinfo)
+{
+       tm_driver_data_t *driver_data;
+       struct lpfc_hba  *phba = vport->phba;
+       uint32_t result;
+
+       atomic_inc(&bind_call_outstanding);
+       driver_data = lpfc_tgt_data;
+       if (driver_data) {
+               if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
+                       portinfo->flags |= LPFC_TM_SLI3_HBQ_ENABLED;
+               else
+                       portinfo->flags &= ~LPFC_TM_SLI3_HBQ_ENABLED;
+
+               /* let remote initiators login to target */
+               vport->cfg_restrict_login = 0;
+
+               result =
+                   driver_data->tm_tgtport_bind_v2(
+                                       phba->target_sliport.target_slihandle,
+                                       (tm_tgtport_handle_t)vport,
+                                        portinfo, (tm_tgtport_handle_t *)
+                                        &vport->target_tgtport.
+                                        target_handle);
+       } else
+               result = TM_RCD_FAILURE;
+       atomic_dec(&bind_call_outstanding);
+       return result;
+}
+
+uint32_t
+tm_tgtport_chk_login(struct lpfc_vport *vport,
+                    tm_login_info_t *logininfo)
+{
+       tm_tgtport_handle_t target_handle;
+       uint32_t result;
+
+       atomic_inc(&vport->target_tgtport.calls_outstanding);
+       target_handle = vport->target_tgtport.target_handle;
+       if (target_handle)
+               result =
+                   lpfc_tgt_data->tm_tgtport_chk_login(target_handle,
+                                                       logininfo);
+       else
+               result = TM_RCD_FAILURE;
+       atomic_dec(&vport->target_tgtport.calls_outstanding);
+       return result;
+}
+
+tm_login_handle_t tm_tgtport_login(struct lpfc_vport *vport,
+                                       struct lpfc_nodelist *ndlp)
+{
+       tm_tgtport_handle_t target_handle;
+       tm_login_handle_t result;
+
+       atomic_inc(&vport->target_tgtport.calls_outstanding);
+       target_handle = vport->target_tgtport.target_handle;
+       if (target_handle) {
+               tm_check_duplicate_wwpn(vport, ndlp);
+               result = lpfc_tgt_data->tm_tgtport_login(target_handle,
+                                ndlp->nlp_rpi, &ndlp->tm_login_info);
+       } else
+               result = 0;
+       atomic_dec(&vport->target_tgtport.calls_outstanding);
+       return result;
+}
+
+void tm_tgtport_logout(struct lpfc_vport *vport,
+                     tm_login_handle_t tgt_login_handle)
+{
+       tm_tgtport_handle_t target_handle;
+
+       /*
+        * Check for various stages of tearing down the target driver. It's
+        * possible to receive link events during teardown depending on load.
+        * If any of the folloging conditions are true, we would dereference
+        * freed memory if we continued.
+        */
+       target_handle = vport->target_tgtport.target_handle;
+       if (tgt_login_handle == NULL)   /* lpfc_unreg_rpi already called */
+               return;
+       if (target_handle == NULL)      /* lpfc_tm_tgtport_unbind called */
+               return;
+       if (lpfc_tgt_data == NULL)      /* lpfc_tm_term() already called */
+               return;
+
+       atomic_inc(&vport->target_tgtport.calls_outstanding);
+       lpfc_tgt_data->tm_tgtport_logout(tgt_login_handle);
+       atomic_dec(&vport->target_tgtport.calls_outstanding);
+}
+
+
+static int    init_called = 0;
+
+atomic_t bind_call_outstanding = ATOMIC_INIT(0);
+
+tm_driver_data_t *volatile lpfc_tgt_data;
+
+uint32_t lpfc_tm_version(void)
+{
+       return TM_API_VERSION_2;
+}
+EXPORT_SYMBOL(lpfc_tm_version);
+
+uint32_t lpfc_tm_init(tm_driver_data_t *tgt_data)
+{
+       int status;
+
+       if (init_called) {
+               printk("lpfc multiple init of target module\n");
+               return TM_RCD_INVALID;
+       }
+       if (tgt_data->api_version != TM_API_VERSION_2)
+               return TM_RCD_INVALID;
+       lpfc_tgt_data = tgt_data;
+
+       status = lpfc_tgt_init();
+       if (status) {
+               init_called = 0;
+               lpfc_tgt_data = NULL;
+               return status;
+       }
+       init_called = 1;
+       return status;
+}
+EXPORT_SYMBOL(lpfc_tm_init);
+
+uint32_t
+lpfc_target_new_tgtport(struct lpfc_vport *vport)
+{
+       tm_driver_data_t *temp_lpfc_tgt_data;
+       tm_tgtport_t     *tgtport = &vport->target_tgtport;
+       struct lpfc_hba  *phba = vport->phba;
+       uint32_t result;
+       uint32_t max_xri;
+
+       temp_lpfc_tgt_data = lpfc_tgt_data;
+
+       if (!temp_lpfc_tgt_data) {
+               /* unlikely to get here. Means a new
+                * tgtport appeared after unloading the
+                * target driver.  So just return 0.
+                */
+               return 0;
+       }
+
+       /* initialize tgtport struct */
+       memset(tgtport, 0, sizeof(tm_tgtport_t));
+       atomic_set(&tgtport->calls_outstanding, 0);
+
+       /* set up parameters in port info */
+       tgtport->info.sli_version = *(uint32_t *)&phba->pcb;
+       tgtport->info.protocol_type = TM_PROTO_FC;
+       memcpy(tgtport->info.proto_u.fc_proto_info.fc_port_name,
+               (uint8_t *)&vport->fc_portname, 8);
+       memcpy(tgtport->info.proto_u.fc_proto_info.fc_node_name,
+               (uint8_t *)&vport->fc_nodename, 8);
+       tgtport->info.iotag16_mask = 0xc000;
+       tgtport->info.pcidev = phba->pcidev;
+
+       /*
+        * max_tgt_contexts was negotiated in a preceding tm_sliport_init() call
+        * Don't allow it to be modified here, use vport[0] cfg for all vports
+        */
+       max_xri = phba->target_sliport.info.max_tgt_contexts;
+       tgtport->info.max_tgt_contexts = max_xri;
+       if (max_xri < 32) {
+               printk("lpfc_target_new_tgtport max_xri = %d\n", max_xri);
+               return TM_RCD_FAILURE;
+       }
+
+       /*
+        * Now let the target driver know. Binds both phys & npiv ports
+        * tm_sliport_init must have already been called for this hba.
+        */
+       result = tm_tgtport_bind(vport, &tgtport->info);
+       if (result == TM_RCD_SUCCESS)
+               phba->num_targets_bound++;
+       tgtport->info.max_tgt_contexts = max_xri;
+
+       return result;
+}
+
+uint32_t
+lpfc_target_rm_tgtport(struct lpfc_vport *vport)
+{
+       tm_driver_data_t *temp_lpfc_tgt_data;
+       tm_tgtport_t     *tgtport = &vport->target_tgtport;
+
+       temp_lpfc_tgt_data = lpfc_tgt_data;
+
+       if (!temp_lpfc_tgt_data) {
+               /* unlikely to get here. Means a new
+                * tgtport appeared after unloading the
+                * target driver.  So just return 0.
+                */
+               return 0;
+       }
+
+       /* now let the target driver know */
+       lpfc_tm_tgtport_unbind(tgtport);
+       return 1;
+}
+
+/* check for a node already logged in with the same port name.
+ * If found, then log it out of the target
+ */
+void tm_check_duplicate_wwpn(struct lpfc_vport *vport,
+                               struct lpfc_nodelist *ndlp)
+{
+       struct lpfc_nodelist *ndlp1;
+
+       list_for_each_entry(ndlp1, &vport->fc_nodes, nlp_listp) {
+               if (memcmp(&ndlp->nlp_portname, &ndlp1->nlp_portname,
+                       8) == 0 && ndlp != ndlp1 &&
+                       ndlp1->login_handle_valid) {
+
+                       /* found duplicate needs to be logged out */
+                       tm_tgtport_logout(vport, ndlp1->login_handle);
+                       ndlp1->login_handle_valid = 0;
+                       ndlp1->login_handle = 0;
+               }
+       }
+}
+
+/* this function called in the prli els functions prior to
+ * sending any PRLI or PRLI response.
+ */
+uint32_t
+lpfc_target_check_login(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+{
+       /* fill in the login info structure */
+       tm_login_info_t *p = &ndlp->tm_login_info;
+
+       /* if we have already checked, then just
+        * return the result we got last time.
+        */
+       if (ndlp->tm_check_login_called)
+               return ndlp->tm_check_login_result;
+
+       memcpy(p->fc_login_info.fc_port_name, &ndlp->nlp_portname, 8);
+       memcpy(p->fc_login_info.fc_node_name, &ndlp->nlp_nodename, 8);
+       p->fc_login_info.local_fc_id = vport->fc_myDID;
+       p->fc_login_info.fc_id = ndlp->nlp_DID;
+
+       /* find out if target driver likes it */
+       ndlp->tm_check_login_called = 1;
+       ndlp->tm_check_login_result = tm_tgtport_chk_login(vport, p);
+       return ndlp->tm_check_login_result;
+}
+
+void lpfc_tm_tgtport_unbind(tm_tgtport_handle_t base_handle)
+{
+       struct lpfc_vport *vport = (struct lpfc_vport *)base_handle;
+       struct lpfc_hba *phba = vport->phba;
+
+
+       /* invalidate the handle */
+       vport->target_tgtport.target_handle = 0;
+
+       /* then wait for all outstanding calls to the target referencing
+        * this tgtport to complete.
+        */
+       while (atomic_read(&vport->target_tgtport.calls_outstanding))
+               schedule_timeout(10);
+
+       phba->num_targets_bound--;
+}
+EXPORT_SYMBOL(lpfc_tm_tgtport_unbind);
+
+
+
+uint32_t lpfc_tm_cmd_send(tm_sliport_handle_t lpfc_sliport_handle,
+                               tm_tgtport_handle_t  base_handle,
+                               IOCB_t    *iocb,
+                               uint32_t   iocb_wd_len)
+{
+       struct lpfc_vport *vport = (struct lpfc_vport *)base_handle;
+       struct lpfc_hba   *phba = (struct lpfc_hba *)lpfc_sliport_handle;
+       struct lpfc_sli   *psli;
+       struct lpfc_sli_ring *pring;
+       struct lpfc_iocbq *tmiocb;
+       IOCB_t *icmd;
+
+       psli = &phba->sli;
+       pring = &psli->ring[LPFC_EXTRA_RING];
+
+       /* lpfc_sli_issue_iocb will do this for us, but way too much
+        * overhead.  This routine is largely a cut and paste of required
+        * code. This code may need to be updated if structure
+        * definitions change.
+        */
+
+       /* Allocate buffer for  command iocb */
+       tmiocb = lpfc_sli_get_iocbq(phba);
+       if (!tmiocb)
+               return TM_RCD_FULL;  /* ring is full */
+
+       icmd = &tmiocb->iocb;
+       iocb->ulpIoTag = icmd->ulpIoTag;
+       memcpy((uint8_t *)icmd, (uint8_t *)iocb, sizeof(IOCB_t));
+       if (icmd->ulpCommand == CMD_QUE_RING_BUF64_CN)
+               tmiocb->iocb_cmpl = NULL;
+       else {
+               tmiocb->vport = vport;
+               tmiocb->iocb_cmpl = lpfc_tm_recv_sol;
+       }
+
+       if (lpfc_sli_issue_iocb(phba, LPFC_EXTRA_RING, tmiocb, 0)) {
+               lpfc_sli_release_iocbq(phba, tmiocb);
+               return TM_RCD_FULL;  /* ring is full */
+       }
+       return 0;
+}
+EXPORT_SYMBOL(lpfc_tm_cmd_send);
+
+void lpfc_tm_rsp_poll(tm_sliport_handle_t lpfc_port_handle,
+                               uint32_t max_responses)
+{
+       struct lpfc_hba *phba = (struct lpfc_hba *)lpfc_port_handle;
+       struct lpfc_sli *psli = &phba->sli;
+       struct lpfc_sli_ring *pring = &psli->ring[LPFC_EXTRA_RING];
+       extern int lpfc_sli_handle_fast_ring_event(struct lpfc_hba *,
+                          struct lpfc_sli_ring *, uint32_t);
+       uint32_t  ha_copy;
+
+       /* Reading the HA register is expensive, but if
+        * we are host limited, the response ring will
+        * be full so the cost is ammortized.  If we
+        * are not host limited, we don't care.
+        */
+       ha_copy = readl(phba->HAregaddr) >> 4*LPFC_EXTRA_RING;
+       phba->poll_rsp_cnt = max_responses;
+       if (ha_copy & HA_RXATT) {
+               lpfc_sli_handle_fast_ring_event(phba, pring,
+                                  (ha_copy & HA_RXMASK));
+       }
+       phba->poll_rsp_cnt = 0;
+}
+EXPORT_SYMBOL(lpfc_tm_rsp_poll);
+
+void lpfc_tm_poll_set(tm_sliport_handle_t lpfc_port_handle, uint32_t enable)
+{
+       uint32_t  hc_value;
+       struct lpfc_hba   *phba = (struct lpfc_hba *)lpfc_port_handle;
+       tm_sliport_t      *sliport = &phba->target_sliport;
+
+       spin_lock(&phba->hbalock);
+       /* set the interrupt enable bit in the HC register.
+        * This should really be protected by a lock, but
+        * can't do this until base driver is fixed.
+        */
+       hc_value = readl(phba->HCregaddr);
+       if (enable)
+               hc_value |= (HC_R0INT_ENA << LPFC_EXTRA_RING);
+       else
+               hc_value &= ~(HC_R0INT_ENA << LPFC_EXTRA_RING);
+       writel(hc_value, phba->HCregaddr);
+
+       sliport->interrupt_callback_allowed = !enable;
+       spin_unlock(&phba->hbalock);
+
+       /* If disabling interrupt call backs (enabling polling)
+        * then need to wait for any concurrent call back to
+        * complete.  This guarantees that on return from
+        * this function, no future callbacks will occur.
+        */
+       while (atomic_read(&sliport->interrupt_in_progress))
+               schedule_timeout(10);
+}
+EXPORT_SYMBOL(lpfc_tm_poll_set);
+
+void lpfc_tm_term(void)
+{
+       /* wait for any outstanding bind calls to complete
+        * before returning.  Don't want the target driver
+        * to unload while a call to it is still in progress.
+        */
+       while (atomic_read(&bind_call_outstanding))
+               schedule_timeout(10);
+       lpfc_tgt_exit();
+       lpfc_tgt_data = NULL;
+       init_called = 0;
+}
+EXPORT_SYMBOL(lpfc_tm_term);
+
+void
+lpfc_tm_linkdown(struct lpfc_hba *phba)
+{
+       struct lpfc_vport *vport;
+       struct lpfc_nodelist  *ndlp, *next_ndlp;
+
+       /* This routine will do additional link down processing
+        * required for target mode. Regular link down processing
+        * is still done in lpfc_linkdown.
+        */
+
+       list_for_each_entry(vport, &phba->port_list, listentry) {
+               list_for_each_entry_safe(ndlp, next_ndlp,
+                                       &phba->pport->fc_nodes, nlp_listp) {
+
+               if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
+                       lpfc_disc_state_machine(vport, ndlp, NULL,
+                                    NLP_EVT_DEVICE_RECOVERY);
+
+                       /* Because this is a target, we want to force
+                        * any remote initiator to use PLOGI / PRLI
+                        * to login to us instead of ADISC. Typically
+                        * this will only make a difference if this
+                        * local port is configuration as BOTH a target
+                        * and an initiator.
+                        */
+                       lpfc_unreg_rpi(vport, ndlp);
+               }
+       }
+}
+
+void lpfc_tm_init_link(tm_sliport_handle_t lpfc_port_handle)
+{
+       struct lpfc_hba   *phba = (struct lpfc_hba *)lpfc_port_handle;
+       LPFC_MBOXQ_t *pmb;
+
+       pmb = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
+       if (!pmb) {
+               printk("lpfc_tm_init_link unable to allocate mailbox mem\n");
+               return;
+       }
+
+       lpfc_tm_linkdown(phba);
+       lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
+       if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
+               printk("lpfc_tm_init_link mailbox command unsuccessful\n");
+               lpfc_init_link(phba, pmb, phba->cfg_topology, 
phba->cfg_link_speed);
+               if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS)
+                       printk("lpfc_tm_init_link retry failed\n");
+       }
+
+       mempool_free(pmb, phba->mbox_mem_pool);
+}
+EXPORT_SYMBOL(lpfc_tm_init_link);
+
+void lpfc_tm_down_link(tm_sliport_handle_t lpfc_port_handle)
+{
+       struct lpfc_hba   *phba = (struct lpfc_hba *)lpfc_port_handle;
+       LPFC_MBOXQ_t *pmb;
+       MAILBOX_t *mb;
+
+       pmb = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
+       if (!pmb) {
+               printk("lpfc_tm_down_link unable to allocate mailbox mem\n");
+               return;
+       }
+       mb = &pmb->u.mb;
+       memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
+
+       mb->mbxCommand = MBX_DOWN_LINK;
+       mb->mbxOwner = OWN_HOST;
+       if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS)
+               printk("lpfc_tm_down_link mailbox command unsuccessful\n");
+
+       mempool_free(pmb, phba->mbox_mem_pool);
+}
+
+int lpfc_sliport_term(tm_sliport_handle_t lpfc_port_handle)
+{
+       struct lpfc_hba   *phba = (struct lpfc_hba *)lpfc_port_handle;
+       struct lpfc_dmabuf *dmabuf, *next_dmabuf;
+       struct hbq_dmabuf *hbq_buf;
+       LPFC_MBOXQ_t *pmb;
+       MAILBOX_t *mb = NULL;
+       uint32_t hbq_index;
+
+       if (phba->num_targets_bound)
+               return TM_RCD_BUSY;
+
+
+       /* must pause the hbq before resetting the ring */
+       if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+               pmb = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
+               if (pmb) {
+                       memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
+                       mb = &pmb->u.mb;
+                       mb->mbxCommand = MBX_PAUSE_HBQ;
+                       mb->un.varPauseHbq.hbqId = LPFC_EXTRA_HBQ;
+                       lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+                       mempool_free(pmb, phba->mbox_mem_pool);
+               }
+       }
+
+       /* reset the target ring */
+       pmb = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
+       if (pmb) {
+               memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
+               mb = &pmb->u.mb;
+               mb->mbxCommand = MBX_RESET_RING;
+               mb->un.varRstRing.ring_no = LPFC_EXTRA_RING;
+               lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+               mempool_free(pmb, phba->mbox_mem_pool);
+       }
+
+       if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+               list_for_each_entry_safe(dmabuf, next_dmabuf,
+                       &phba->hbqs[LPFC_EXTRA_HBQ].hbq_buffer_list,
+                                                               list) {
+                       hbq_buf = container_of(dmabuf,
+                               struct hbq_dmabuf, dbuf);
+                       list_del(&hbq_buf->dbuf.list);
+                       (phba->hbqs[LPFC_EXTRA_HBQ].hbq_free_buffer)
+                               (phba, hbq_buf);
+               }
+               phba->hbqs[LPFC_EXTRA_HBQ].hbq_alloc_buffer = NULL;
+               phba->hbqs[LPFC_EXTRA_HBQ].hbq_free_buffer  = NULL;
+       }
+
+       /* resume the hbq and reset the get pointer after reset */
+       if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+               pmb = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
+               if (pmb) {
+                       /* set the hbq put pointer before issuing the resume */
+                       hbq_index = 0;
+                       writel(hbq_index, phba->hbq_put + LPFC_EXTRA_HBQ);
+                       /* flush */
+                       hbq_index = readl(phba->hbq_put + LPFC_EXTRA_HBQ);
+                       phba->hbqs[LPFC_EXTRA_HBQ].hbqPutIdx = hbq_index;
+                       phba->hbqs[LPFC_EXTRA_HBQ].next_hbqPutIdx = hbq_index;
+
+                       memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
+                       mb = &pmb->u.mb;
+                       mb->mbxCommand = MBX_RESUME_HBQ;
+                       mb->un.varResumeHbq.hbqId = LPFC_EXTRA_HBQ;
+                       mb->un.varResumeHbq.hbqGetPtr = hbq_index;
+                       lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+
+                       phba->hbqs[LPFC_EXTRA_HBQ].local_hbqGetIdx = hbq_index;
+                       phba->hbqs[LPFC_EXTRA_HBQ].buffer_count = 0;
+
+                       mempool_free(pmb, phba->mbox_mem_pool);
+               }
+       }
+
+       if (lpfc_tgt_data)
+               lpfc_tgt_data->tm_sliport_term(
+                               phba->target_sliport.target_slihandle);
+
+       return TM_RCD_SUCCESS;
+}
+EXPORT_SYMBOL(lpfc_sliport_term);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(LPFC_MODULE_DESC);
+MODULE_AUTHOR("Emulex Corporation - tech.supp...@emulex.com");
+MODULE_VERSION("0:" LPFC_DRIVER_VERSION);
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_target_api.h 
4.0-rc7/drivers/scsi/lpfc/lpfc_target_api.h
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_target_api.h    1970-01-01 
01:00:00.000000000 +0100
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_target_api.h 2015-04-12 11:36:20.966140847 
+0200
@@ -0,0 +1,155 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2003-2008 Emulex.  All rights reserved.           *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ *                                                                 *
+ * This program is free software; you can redistribute it and/or   *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+#ifndef _H_LPFC_TGT_API
+#define _H_LPFC_TGT_API
+
+#include <linux/version.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#define putPaddrLow(addr)    ((uint32_t) (0xffffffff & (u64)(addr)))
+#define putPaddrHigh(addr)   ((uint32_t) (0xffffffff & (((u64)(addr))>>32)))
+#define getPaddr(high, low)  ((dma_addr_t)( \
+                               (( (u64)(high)<<16 ) << 16)|( (u64)(low))))
+
+typedef void *tm_tgtport_handle_t;
+typedef void *tm_login_handle_t;
+typedef void *tm_sliport_handle_t;
+
+/* API version values */
+#define        TM_API_VERSION_1        1
+#define        TM_API_VERSION_2        2
+
+/* Protocol type values */
+#define        TM_PROTO_FC             0
+
+/* SLI Port abstraction */
+
+typedef        struct tm_sliport_info_s {
+       uint32_t sli_version;           /* explicit PCB word 0 */
+       uint16_t max_tgt_contexts;      /* maximum # of tgt mode I/O contexts */
+       uint16_t iotag16_mask;
+       struct  pci_dev *pcidev;
+       int flags;
+} tm_sliport_info_t;
+
+/* Target port abstaction */
+typedef struct tm_tgtport_info_s {
+       uint32_t sli_version;
+       uint16_t max_tgt_contexts;
+       uint16_t iotag16_mask;
+       uint32_t protocol_type;
+       union {
+               struct fc_proto_info_s {
+                       uint8_t fc_port_name[8];
+                       uint8_t fc_node_name[8];
+               } fc_proto_info;
+       } proto_u;
+       struct pci_dev *pcidev;
+       int flags;
+} tm_tgtport_info_t;
+
+/* Flags for Target Port */
+#define LPFC_TM_SLI3_HBQ_ENABLED       1   /* Port used HBQs */
+#define LPFC_TM_HBQ_TAGS_SUPPORTED     2
+
+#define        fc_protoinfo        proto_u.fc_proto_info
+
+typedef union tm_login_info_u {
+       struct fc_login_info_s {
+               uint8_t fc_port_name[8];
+               uint8_t fc_node_name[8];
+               uint32_t fc_id;
+               uint32_t local_fc_id;
+       } fc_login_info;
+} tm_login_info_t;
+
+
+struct tm_lpfc_dmabuf {
+       struct list_head list;
+       void *virt;             /* virtual address ptr */
+       dma_addr_t phys;        /* mapped address */
+       uint32_t   buffer_tag;
+};
+
+struct tm_hbq_dmabuf {
+       struct tm_lpfc_dmabuf hbuf;
+       struct tm_lpfc_dmabuf dbuf;
+       uint32_t size;
+       uint32_t tag;
+/* FIXME */
+/*
+       struct lpfc_cq_event cq_event;
+       unsigned long time_stamp;
+*/
+};
+
+typedef struct tm_driver_data_s {
+       uint32_t api_version;
+       uint32_t (*tm_tgtport_bind)(tm_tgtport_handle_t base_handle,
+                                       tm_tgtport_info_t *portinfo,
+                                       tm_tgtport_handle_t *tgt_handle);
+       void (*tm_tgtport_req_unbind)(tm_tgtport_handle_t tgt_handle);
+       void (*tm_tgtport_reset)(tm_tgtport_handle_t tgt_handle);
+       uint32_t (*tm_tgtport_chk_login)(tm_tgtport_handle_t tgt_handle,
+                                       tm_login_info_t *logininfo);
+       tm_login_handle_t (*tm_tgtport_login)(tm_tgtport_handle_t tgt_handle,
+                                       uint16_t rpi,
+                                       tm_login_info_t *logininfo);
+       void (*tm_tgtport_logout)(tm_login_handle_t tgt_login_handle);
+       void (*tm_rsp_recv)(tm_tgtport_handle_t tgt_handle, IOCB_t *iocb);
+       void (*tm_hbq_alloc)(tm_sliport_handle_t tgt_slihandle,
+                                       struct tm_hbq_dmabuf *hbqbp);
+       uint32_t (*tm_sliport_init)(tm_sliport_handle_t lpfc_port_handle,
+                       tm_sliport_info_t *sliport_info,
+                       tm_sliport_handle_t *tgt_slihandle);
+       void (*tm_sliport_term)(tm_sliport_handle_t tgt_slihandle);
+       uint32_t (*tm_tgtport_bind_v2)(tm_sliport_handle_t tgt_slihandle,
+                       tm_tgtport_handle_t base_handle,
+                       tm_tgtport_info_t *portinfo,
+                       tm_tgtport_handle_t *tgt_handle);
+       void (*tm_sliport_reset)(tm_sliport_handle_t tgt_slihandle);
+       void (*tm_hbq_free)(tm_sliport_handle_t tgt_slihandle,
+                                       struct tm_hbq_dmabuf *hbqbp);
+       uint32_t tm_num_hbq_buf;
+} tm_driver_data_t;
+
+/* function return codes */
+#define        TM_RCD_SUCCESS     0
+#define        TM_RCD_FAILURE     1
+#define        TM_RCD_FULL        2
+#define        TM_RCD_BUSY        3
+#define        TM_RCD_INVALID     4
+
+uint32_t lpfc_tm_version(void);
+uint32_t lpfc_tm_init(tm_driver_data_t *tgt_data);
+void lpfc_tm_term(void);
+void lpfc_tm_tgtport_unbind(tm_tgtport_handle_t base_handle);
+uint32_t lpfc_tm_cmd_send(tm_sliport_handle_t lpfc_sliport_handle,
+                         tm_tgtport_handle_t base_handle,
+                         IOCB_t *iocb, uint32_t iocb_wd_len);
+void lpfc_tm_rsp_poll(tm_sliport_handle_t lpfc_port_handle,
+                         uint32_t max_responses);
+void lpfc_tm_poll_set(tm_sliport_handle_t lpfc_port_handle,
+                         uint32_t enable);
+void lpfc_tm_init_link(tm_tgtport_handle_t base_handle);
+int lpfc_sliport_term(tm_sliport_handle_t lpfc_port_handle);
+#endif                         /* _H_LPFC_TGT_API */
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_target_api_base.h 
4.0-rc7/drivers/scsi/lpfc/lpfc_target_api_base.h
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_target_api_base.h       1970-01-01 
01:00:00.000000000 +0100
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_target_api_base.h    2015-04-12 
10:32:24.750179769 +0200
@@ -0,0 +1,45 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2003-2008 Emulex.  All rights reserved.           *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ *                                                                 *
+ * This program is free software; you can redistribute it and/or   *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+#ifndef _H_LPFC_TGT_API_BASE
+#define _H_LPFC_TGT_API_BASE
+#define TARGET_RING 3
+#define  RRTOV_TIME 30
+
+extern tm_driver_data_t *volatile lpfc_tgt_data;
+extern atomic_t bind_call_outstanding;
+
+typedef struct tm_tgtport_s {
+       volatile tm_tgtport_handle_t target_handle;
+       tm_tgtport_info_t info;
+       struct list_head list;
+       atomic_t calls_outstanding;
+} tm_tgtport_t;
+
+
+typedef struct tm_sliport_s {
+       tm_sliport_handle_t target_slihandle;
+       volatile uint32_t interrupt_callback_allowed;
+       atomic_t interrupt_in_progress;
+       tm_sliport_info_t info;
+       struct list_head list;
+       atomic_t calls_outstanding;
+} tm_sliport_t;
+
+#endif                         /* _H_LPFC_TGT_API_BASE */
diff -uNrp 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_target_protos.h 
4.0-rc7/drivers/scsi/lpfc/lpfc_target_protos.h
--- 4.0-rc7.orig/drivers/scsi/lpfc/lpfc_target_protos.h 1970-01-01 
01:00:00.000000000 +0100
+++ 4.0-rc7/drivers/scsi/lpfc/lpfc_target_protos.h      2015-04-12 
10:32:24.750179769 +0200
@@ -0,0 +1,31 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2003-2008 Emulex.  All rights reserved.           *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ *                                                                 *
+ * This program is free software; you can redistribute it and/or   *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+#ifndef _H_LPFC_TGT_PROTO
+#define _H_LPFC_TGT_PROTO
+void tm_check_duplicate_wwpn(struct lpfc_vport *, struct lpfc_nodelist *);
+
+uint32_t lpfc_target_new_tgtport(struct lpfc_vport *);
+uint32_t lpfc_target_rm_tgtport(struct lpfc_vport *);
+uint32_t lpfc_target_check_login(struct lpfc_vport *, struct lpfc_nodelist *);
+
+tm_login_handle_t tm_tgtport_login(struct lpfc_vport *, struct lpfc_nodelist 
*);
+void tm_tgtport_logout(struct lpfc_vport *, tm_login_handle_t);
+uint32_t tm_tgtport_chk_login(struct lpfc_vport *, tm_login_info_t *);
+#endif                         /* _H_LPFC_TGT_PROTO */
--
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