All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
@ 2016-05-24 13:52 Bryant G. Ly
  2016-05-24 14:14 ` Joe Perches
                   ` (3 more replies)
  0 siblings, 4 replies; 17+ messages in thread
From: Bryant G. Ly @ 2016-05-24 13:52 UTC (permalink / raw)
  To: JBottomley, martin.petersen, tyreld, akpm, kvalo, davem, gregkh,
	mchehab, jslaby, joe, bp
  Cc: linux-kernel, linux-scsi, target-devel, bgly, bryantly

From: bgly <bgly@us.ibm.com>

This initial commit contains WIP of the IBM VSCSI Target Fabric
Module. It currently supports read/writes, and I have tested
the ability to create a file backstore with the driver and install
RHEL VIA NIM and then boot up the partition via filio backstore
through the driver.

Signed-off-by: bryantly <bryantly@linux.vnet.ibm.com>
---
 MAINTAINERS                       |   10 +
 drivers/scsi/Kconfig              |   24 +
 drivers/scsi/Makefile             |    2 +
 drivers/scsi/ibmvscsi/Makefile    |    1 +
 drivers/scsi/ibmvscsi/ibmvscsis.c | 2033 +++++++++++++++++++++++++++++++++++++
 drivers/scsi/ibmvscsi/ibmvscsis.h |  160 +++
 drivers/scsi/libsrp.c             |  387 +++++++
 include/scsi/libsrp.h             |   95 ++
 8 files changed, 2712 insertions(+)
 create mode 100644 drivers/scsi/ibmvscsi/ibmvscsis.c
 create mode 100644 drivers/scsi/ibmvscsi/ibmvscsis.h
 create mode 100644 drivers/scsi/libsrp.c
 create mode 100644 include/scsi/libsrp.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 6ee06ea..b520e6c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5381,6 +5381,16 @@ S:	Supported
 F:	drivers/scsi/ibmvscsi/ibmvscsi*
 F:	drivers/scsi/ibmvscsi/viosrp.h
 
+IBM Power Virtual SCSI Device Target Driver
+M:	Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+L:	linux-scsi@vger.kernel.org
+L:	target-devel@vger.kernel.org
+S:	Supported
+F:	drivers/scsi/ibmvscsi/ibmvscsis.c
+F:      drivers/scsi/ibmvscsi/ibmvscsis.h
+F:	drivers/scsi/libsrp.h
+F:      drivers/scsi/libsrp.c
+
 IBM Power Virtual FC Device Drivers
 M:	Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
 L:	linux-scsi@vger.kernel.org
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index e2f31c9..6adf8f1 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -847,6 +847,20 @@ config SCSI_IBMVSCSI
 	  To compile this driver as a module, choose M here: the
 	  module will be called ibmvscsi.
 
+config SCSI_IBMVSCSIS
+  	tristate "IBM Virtual SCSI Server support"
+  	depends on PPC_PSERIES && SCSI_SRP && TARGET_CORE
+  	help
+  	  This is the IBM POWER Virtual SCSI Target Server
+
+          The userspace component needed to initialize the driver and
+  	  documentation can be found:
+
+          https://github.com/powervm/ibmvscsis
+
+          To compile this driver as a module, choose M here: the
+  	  module will be called ibmvstgt.
+
 config SCSI_IBMVFC
 	tristate "IBM Virtual FC support"
 	depends on PPC_PSERIES && SCSI
@@ -1728,6 +1742,16 @@ config SCSI_PM8001
 	  This driver supports PMC-Sierra PCIE SAS/SATA 8x6G SPC 8001 chip
 	  based host adapters.
 
+config SCSI_SRP
+  	tristate "SCSI RDMA Protocol helper library"
+  	depends on SCSI && PCI
+  	help
+  	  This scsi srp module is a library for ibmvscsi target driver.
+	  If you wish to use SRP target drivers, say Y.
+
+  	  To compile this driver as a module, choose M here. The module will
+  	  be called libsrp.
+
 config SCSI_BFA_FC
 	tristate "Brocade BFA Fibre Channel Support"
 	depends on PCI && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 862ab4e..8692dd4 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -127,7 +127,9 @@ obj-$(CONFIG_SCSI_LASI700)	+= 53c700.o lasi700.o
 obj-$(CONFIG_SCSI_SNI_53C710)	+= 53c700.o sni_53c710.o
 obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
 obj-$(CONFIG_SCSI_IPR)		+= ipr.o
+obj-$(CONFIG_SCSI_SRP)          += libsrp.o
 obj-$(CONFIG_SCSI_IBMVSCSI)	+= ibmvscsi/
+obj-$(CONFIG_SCSI_IBMVSCSIS)    += ibmvscsi/
 obj-$(CONFIG_SCSI_IBMVFC)	+= ibmvscsi/
 obj-$(CONFIG_SCSI_HPTIOP)	+= hptiop.o
 obj-$(CONFIG_SCSI_STEX)		+= stex.o
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
index 3840c64..b241a567 100644
--- a/drivers/scsi/ibmvscsi/Makefile
+++ b/drivers/scsi/ibmvscsi/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SCSI_IBMVSCSI)	+= ibmvscsi.o
+obj-$(CONFIG_SCSI_IBMVSCSIS)    += ibmvscsis.o
 obj-$(CONFIG_SCSI_IBMVFC)	+= ibmvfc.o
diff --git a/drivers/scsi/ibmvscsi/ibmvscsis.c b/drivers/scsi/ibmvscsi/ibmvscsis.c
new file mode 100644
index 0000000..c7eb347
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/ibmvscsis.c
@@ -0,0 +1,2033 @@
+/*******************************************************************************
+ * IBM Virtual SCSI Target Driver
+ * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
+ *			   Santiago Leon (santil@us.ibm.com) IBM Corp.
+ *			   Linda Xie (lxie@us.ibm.com) IBM Corp.
+ *
+ * Copyright (C) 2005-2011 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2010 Nicholas A. Bellinger <nab@kernel.org>
+ * Copyright (C) 2016 Bryant G. Ly <bgly@us.ibm.com> IBM Corp.
+ *
+ * Authors: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ ****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/utsname.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/libsrp.h>
+#include <generated/utsrelease.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_backend.h>
+
+#include <asm/hvcall.h>
+#include <asm/iommu.h>
+#include <asm/prom.h>
+#include <asm/vio.h>
+
+#include "ibmvscsi.h"
+#include "ibmvscsis.h"
+#include "viosrp.h"
+
+#define IBMVSCSIS_VERSION	"v0.1"
+
+#define	INITIAL_SRP_LIMIT	15
+#define	DEFAULT_MAX_SECTORS	256
+
+#define MAX_H_COPY_RDMA		(128*1024)
+
+#define SRP_RSP_SENSE_DATA_LEN	18
+
+static struct workqueue_struct *vtgtd;
+static unsigned max_vdma_size = MAX_H_COPY_RDMA;
+
+static DEFINE_SPINLOCK(ibmvscsis_dev_lock);
+static LIST_HEAD(ibmvscsis_dev_list);
+
+static int ibmvscsis_probe(struct vio_dev *vdev,
+			   const struct vio_device_id *id);
+static void ibmvscsis_dev_release(struct device *dev);
+static void ibmvscsis_modify_rep_luns(struct se_cmd *se_cmd);
+static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd);
+static int read_dma_window(struct vio_dev *vdev,
+				struct ibmvscsis_adapter *adapter);
+static char *ibmvscsis_get_fabric_name(void);
+static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg);
+static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg);
+static u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg);
+static int ibmvscsis_check_true(struct se_portal_group *se_tpg);
+static int ibmvscsis_check_false(struct se_portal_group *se_tpg);
+static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg);
+static int ibmvscsis_check_stop_free(struct se_cmd *se_cmd);
+static void ibmvscsis_release_cmd(struct se_cmd *se_cmd);
+static int ibmvscsis_shutdown_session(struct se_session *se_sess);
+static void ibmvscsis_close_session(struct se_session *se_sess);
+static u32 ibmvscsis_sess_get_index(struct se_session *se_sess);
+static int ibmvscsis_write_pending(struct se_cmd *se_cmd);
+static int ibmvscsis_write_pending_status(struct se_cmd *se_cmd);
+static void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl);
+static int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd);
+static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd);
+static int ibmvscsis_queue_status(struct se_cmd *se_cmd);
+static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd);
+static void ibmvscsis_aborted_task(struct se_cmd *se_cmd);
+static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf,
+					   struct config_group *group,
+					   const char *name);
+static void ibmvscsis_drop_tport(struct se_wwn *wwn);
+static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
+						  struct config_group *group,
+						  const char *name);
+static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg);
+static int ibmvscsis_remove(struct vio_dev *vdev);
+static ssize_t system_id_show(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf);
+static ssize_t partition_number_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf);
+static ssize_t unit_address_show(struct device *dev,
+				 struct device_attribute *attr, char *buf);
+static int get_system_info(void);
+static irqreturn_t ibmvscsis_interrupt(int dummy, void *data);
+static int process_srp_iu(struct iu_entry *iue);
+static void process_iu(struct viosrp_crq *crq,
+		       struct ibmvscsis_adapter *adapter);
+static void process_crq(struct viosrp_crq *crq,
+			struct ibmvscsis_adapter *adapter);
+static void handle_crq(struct work_struct *work);
+static int ibmvscsis_reset_crq_queue(struct ibmvscsis_adapter *adapter);
+static void crq_queue_destroy(struct ibmvscsis_adapter *adapter);
+static inline struct viosrp_crq *next_crq(struct crq_queue *queue);
+static int send_iu(struct iu_entry *iue, u64 length, u8 format);
+static int send_adapter_info(struct iu_entry *iue,
+			     dma_addr_t remote_buffer, u16 length);
+static int process_mad_iu(struct iu_entry *iue);
+static void ibmvscsis_srp_i_logout(struct iu_entry *iue);
+static void process_login(struct iu_entry *iue);
+static void process_tsk_mgmt(struct ibmvscsis_adapter *adapter,
+			     struct iu_entry *iue);
+static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg,
+			  int nsg, struct srp_direct_buf *md, int nmd,
+			  enum dma_data_direction dir, unsigned int rest);
+static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
+				  struct iu_entry *iue);
+static uint64_t ibmvscsis_unpack_lun(const uint8_t *lun, int len);
+static int tcm_queuecommand(struct ibmvscsis_adapter *adapter,
+			    struct ibmvscsis_cmnd *vsc,
+			    struct srp_cmd *scmd);
+static void ibmvscsis_determine_resid(struct se_cmd *se_cmd,
+				      struct srp_rsp *rsp);
+static bool connection_broken(struct ibmvscsis_adapter *adapter);
+
+static inline long h_copy_rdma(s64 length, u64 sliobn, u64 slioba,
+	u64 dliobn, u64 dlioba)
+{
+	long rc = 0;
+
+	/* Ensure all writes to source memory are visible before hcall */
+	mb();
+
+	rc = plpar_hcall_norets(H_COPY_RDMA, length, sliobn, slioba,
+			dliobn, dlioba);
+	return rc;
+}
+
+static inline void h_free_crq(uint32_t unit_address)
+{
+	long rc = 0;
+
+	do {
+		if (H_IS_LONG_BUSY(rc))
+			msleep(get_longbusy_msecs(rc));
+
+		rc = plpar_hcall_norets(H_FREE_CRQ, unit_address);
+	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
+}
+
+static inline long h_send_crq(struct ibmvscsis_adapter *adapter,
+			u64 word1, u64 word2)
+{
+	long rc;
+	struct vio_dev *vdev = adapter->dma_dev;
+
+	pr_debug("ibmvscsis: ibmvscsis_send_crq(0x%x, 0x%016llx, 0x%016llx)\n",
+			vdev->unit_address, word1, word2);
+
+	/*
+	 * Ensure the command buffer is flushed to memory before handing it
+	 * over to the other side to prevent it from fetching any stale data.
+	 */
+	mb();
+	rc = plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2);
+	pr_debug("ibmvscsis: ibmvcsis_send_crq rc = 0x%lx\n", rc);
+
+	return rc;
+}
+
+/*****************************************************************************/
+/* Global device driver data areas                                           */
+/*****************************************************************************/
+
+static const char ibmvscsis_driver_name[] = "ibmvscsis";
+static char system_id[64] = "";
+static char partition_name[97] = "UNKNOWN";
+static unsigned int partition_number = -1;
+
+static struct class_attribute ibmvscsis_class_attrs[] = {
+	__ATTR_NULL,
+};
+
+static struct device_attribute dev_attr_system_id =
+	__ATTR(system_id, S_IRUGO, system_id_show, NULL);
+
+static struct device_attribute dev_attr_partition_number =
+	__ATTR(partition_number, S_IRUGO, partition_number_show, NULL);
+
+static struct device_attribute dev_attr_unit_address =
+	__ATTR(unit_address, S_IRUGO, unit_address_show, NULL);
+
+static struct attribute *ibmvscsis_dev_attrs[] = {
+	&dev_attr_system_id.attr,
+	&dev_attr_partition_number.attr,
+	&dev_attr_unit_address.attr,
+};
+ATTRIBUTE_GROUPS(ibmvscsis_dev);
+
+static struct class ibmvscsis_class = {
+	.name           = "ibmvscsis",
+	.dev_release    = ibmvscsis_dev_release,
+	.class_attrs    = ibmvscsis_class_attrs,
+	.dev_groups     = ibmvscsis_dev_groups,
+};
+
+static ssize_t ibmvscsis_wwn_version_show(struct config_item *item,
+					       char *page)
+{
+	return sprintf(page, "IBMVSCSIS fabric %s on %s/%s on "UTS_RELEASE"\n",
+		       IBMVSCSIS_VERSION, utsname()->sysname,
+		       utsname()->machine);
+}
+CONFIGFS_ATTR_RO(ibmvscsis_wwn_, version);
+
+static struct configfs_attribute *ibmvscsis_wwn_attrs[] = {
+	&ibmvscsis_wwn_attr_version,
+	NULL,
+};
+
+static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item,
+				char *page)
+{
+	struct se_portal_group *se_tpg = to_tpg(item);
+	struct ibmvscsis_tport *tport = container_of(se_tpg,
+						struct ibmvscsis_tport, se_tpg);
+
+	return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0);
+}
+
+static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item,
+		const char *page, size_t count)
+{
+	struct se_portal_group *se_tpg = to_tpg(item);
+	struct ibmvscsis_tport *tport = container_of(se_tpg,
+						struct ibmvscsis_tport, se_tpg);
+	unsigned long tmp;
+	int ret;
+
+	ret = kstrtoul(page, 0, &tmp);
+	if (ret < 0) {
+		pr_err("Unable to extract ibmvscsis_tpg_store_enable\n");
+		return -EINVAL;
+	}
+
+	if ((tmp != 0) && (tmp != 1)) {
+		pr_err("Illegal value for ibmvscsis_tpg_store_enable: %lu\n",
+			tmp);
+		return -EINVAL;
+	}
+
+	if (tmp == 1)
+		tport->enabled = true;
+	else
+		tport->enabled = false;
+
+	return count;
+}
+CONFIGFS_ATTR(ibmvscsis_tpg_, enable);
+
+static struct configfs_attribute *ibmvscsis_tpg_attrs[] = {
+			&ibmvscsis_tpg_attr_enable,
+			NULL,
+};
+
+static const struct target_core_fabric_ops ibmvscsis_ops = {
+	.module				= THIS_MODULE,
+	.name				= "ibmvscsis",
+	.max_data_sg_nents		= SCSI_MAX_SG_SEGMENTS,
+	.get_fabric_name		= ibmvscsis_get_fabric_name,
+	.tpg_get_wwn			= ibmvscsis_get_fabric_wwn,
+	.tpg_get_tag			= ibmvscsis_get_tag,
+	.tpg_get_default_depth		= ibmvscsis_get_default_depth,
+	.tpg_check_demo_mode		= ibmvscsis_check_true,
+	.tpg_check_demo_mode_cache	= ibmvscsis_check_true,
+	.tpg_check_demo_mode_write_protect = ibmvscsis_check_false,
+	.tpg_check_prod_mode_write_protect = ibmvscsis_check_false,
+	.tpg_get_inst_index		= ibmvscsis_tpg_get_inst_index,
+	.check_stop_free		= ibmvscsis_check_stop_free,
+	.release_cmd			= ibmvscsis_release_cmd,
+	.shutdown_session		= ibmvscsis_shutdown_session,
+	.close_session			= ibmvscsis_close_session,
+	.sess_get_index			= ibmvscsis_sess_get_index,
+	.write_pending			= ibmvscsis_write_pending,
+	.write_pending_status		= ibmvscsis_write_pending_status,
+	.set_default_node_attributes	= ibmvscsis_set_default_node_attrs,
+	.get_cmd_state			= ibmvscsis_get_cmd_state,
+	.queue_data_in			= ibmvscsis_queue_data_in,
+	.queue_status			= ibmvscsis_queue_status,
+	.queue_tm_rsp			= ibmvscsis_queue_tm_rsp,
+	.aborted_task			= ibmvscsis_aborted_task,
+	/*
+	 * Setup function pointers for logic in target_cor_fabric_configfs.c
+	 */
+	.fabric_make_wwn		= ibmvscsis_make_tport,
+	.fabric_drop_wwn		= ibmvscsis_drop_tport,
+	.fabric_make_tpg		= ibmvscsis_make_tpg,
+	.fabric_drop_tpg		= ibmvscsis_drop_tpg,
+
+	.tfc_wwn_attrs			= ibmvscsis_wwn_attrs,
+	.tfc_tpg_base_attrs             = ibmvscsis_tpg_attrs,
+};
+
+static struct vio_device_id ibmvscsis_device_table[] = {
+	{"v-scsi-host", "IBM,v-scsi-host"},
+	{"", ""}
+};
+MODULE_DEVICE_TABLE(vio, ibmvscsis_device_table);
+
+static struct vio_driver ibmvscsis_driver = {
+	.name = ibmvscsis_driver_name,
+	.id_table = ibmvscsis_device_table,
+	.probe = ibmvscsis_probe,
+	.remove = ibmvscsis_remove,
+};
+
+/*****************************************************************************/
+/* End of global device driver data areas                                    */
+/*****************************************************************************/
+static int crq_queue_create(struct crq_queue *queue,
+				struct ibmvscsis_adapter *adapter)
+{
+	int retrc;
+	int err;
+	struct vio_dev *vdev = adapter->dma_dev;
+
+	queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
+
+	if (!queue->msgs)
+		goto malloc_failed;
+
+	queue->size = PAGE_SIZE / sizeof(*queue->msgs);
+
+	queue->msg_token = dma_map_single(&vdev->dev, queue->msgs,
+					  queue->size * sizeof(*queue->msgs),
+					  DMA_BIDIRECTIONAL);
+
+	if (dma_mapping_error(&vdev->dev, queue->msg_token))
+		goto map_failed;
+
+	retrc = err = h_reg_crq(vdev->unit_address, queue->msg_token,
+			PAGE_SIZE);
+
+	/* If the adapter was left active for some reason (like kexec)
+	 * try freeing and re-registering
+	 */
+	if (err == H_RESOURCE)
+		err = ibmvscsis_reset_crq_queue(adapter);
+	if (err == 2) {
+		pr_warn("ibmvscsis: Partner adapter not ready\n");
+		retrc = 0;
+	} else if (err != 0) {
+		pr_err("ibmvscsis: Error 0x%x opening virtual adapter\n", err);
+		goto reg_crq_failed;
+	}
+
+	queue->cur = 0;
+	spin_lock_init(&queue->lock);
+
+	INIT_WORK(&adapter->crq_work, handle_crq);
+
+	err = request_irq(vdev->irq, &ibmvscsis_interrupt,
+			  0, "ibmvscsis", adapter);
+	if (err) {
+		pr_err("ibmvscsis: Error 0x%x h_send_crq\n", err);
+		goto req_irq_failed;
+	}
+
+	err = vio_enable_interrupts(vdev);
+	if (err != 0) {
+		pr_err("ibmvscsis: Error %d enabling interrupts!!!\n", err);
+		goto req_irq_failed;
+	}
+
+	return retrc;
+
+req_irq_failed:
+	h_free_crq(vdev->unit_address);
+reg_crq_failed:
+	dma_unmap_single(&vdev->dev, queue->msg_token,
+			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+map_failed:
+	free_page((unsigned long) queue->msgs);
+malloc_failed:
+	return -1;
+}
+
+/*
+ * ibmvscsis_probe - ibm vscsis target initialize entry point
+ * @param  dev vio device struct
+ * @param  id  vio device id struct
+ * @return	0 - Success
+ *		Non-zero - Failure
+ */
+static int ibmvscsis_probe(struct vio_dev *vdev, const struct vio_device_id *id)
+{
+	int ret = -ENOMEM;
+	struct ibmvscsis_adapter *adapter;
+	struct srp_target *target;
+	struct ibmvscsis_tport *tport;
+	unsigned long flags;
+
+	pr_debug("ibmvscsis: Probe for UA 0x%x\n", vdev->unit_address);
+
+	adapter = kzalloc(sizeof(struct ibmvscsis_adapter), GFP_KERNEL);
+	if (!adapter)
+		return ret;
+	target = kzalloc(sizeof(struct srp_target), GFP_KERNEL);
+	if (!target)
+		goto free_adapter;
+
+	adapter->dma_dev = vdev;
+	adapter->target = target;
+	tport = &adapter->tport;
+
+	tport->enabled = false;
+	snprintf(&adapter->tport.tport_name[0], 256, "%s",
+		 dev_name(&vdev->dev));
+
+	ret = read_dma_window(adapter->dma_dev, adapter);
+	if (ret != 0)
+		goto free_target;
+
+	pr_debug("ibmvscsis: Probe: liobn 0x%x, riobn 0x%x\n", adapter->liobn,
+			adapter->riobn);
+
+	spin_lock_irqsave(&ibmvscsis_dev_lock, flags);
+	list_add_tail(&adapter->list, &ibmvscsis_dev_list);
+	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
+
+	ret = srp_target_alloc(target, &vdev->dev,
+				INITIAL_SRP_LIMIT,
+				SRP_MAX_IU_LEN);
+
+	adapter->target->ldata = adapter;
+
+	if (ret) {
+		pr_err("ibmvscsis: failed target alloc ret: %d\n", ret);
+		goto free_srp_target;
+	}
+
+	ret = crq_queue_create(&adapter->crq_queue, adapter);
+	if (ret != 0 && ret != H_RESOURCE) {
+		pr_err("ibmvscsis: failed crq_queue_create ret: %d\n", ret);
+		ret = -1;
+	}
+
+	if (h_send_crq(adapter, 0xC001000000000000LL, 0) != 0
+			&& ret != H_RESOURCE) {
+		pr_warn("ibmvscsis: Failed to send CRQ message\n");
+		ret = 0;
+	}
+
+	dev_set_drvdata(&vdev->dev, adapter);
+
+	return 0;
+
+free_srp_target:
+	srp_target_free(target);
+free_target:
+	kfree(target);
+free_adapter:
+	kfree(adapter);
+	return ret;
+}
+
+static int ibmvscsis_remove(struct vio_dev *dev)
+{
+	unsigned long flags;
+	struct ibmvscsis_adapter *adapter = dev_get_drvdata(&dev->dev);
+	struct srp_target *target;
+
+	target = adapter->target;
+
+	spin_lock_irqsave(&ibmvscsis_dev_lock, flags);
+	list_del(&adapter->list);
+	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
+
+	crq_queue_destroy(adapter);
+	srp_target_free(target);
+
+	kfree(target);
+	kfree(adapter);
+
+	return 0;
+}
+
+static void ibmvscsis_modify_rep_luns(struct se_cmd *se_cmd)
+{
+	s32 len = se_cmd->data_length;
+	u16 data_len;
+	unsigned char *buf = NULL;
+
+	if (len <= 8)
+		return;
+
+	len -= 8;
+	buf = transport_kmap_data_sg(se_cmd);
+	if (buf) {
+		data_len = be32_to_cpu(*(u32 *)buf);
+		pr_debug("ibmvscsis: modify_rep_luns: len %d data_len %hud\n",
+			len, data_len);
+		if (data_len < len)
+			len = data_len;
+		buf += 8;
+		while (len > 0) {
+			*buf |= SCSI_LUN_ADDR_METHOD_FLAT << 6;
+			len -= 8;
+			buf += 8;
+		}
+		transport_kunmap_data_sg(se_cmd);
+	}
+}
+
+static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd)
+{
+	struct se_device *dev = se_cmd->se_dev;
+	unsigned char *buf = NULL;
+	u32 cmd_len = se_cmd->data_length;
+
+	if (cmd_len <= INQ_DATA_OFFSET)
+		return;
+
+	buf = transport_kmap_data_sg(se_cmd);
+	if (buf) {
+		memcpy(&buf[8], "IBM	     ", 8);
+		if (dev->transport->get_device_type(dev) == TYPE_ROM)
+			memcpy(&buf[16], "VOPTA           ", 16);
+		else
+			memcpy(&buf[16], "3303      NVDISK", 16);
+		memcpy(&buf[32], "0001", 4);
+		transport_kunmap_data_sg(se_cmd);
+	}
+}
+
+static int read_dma_window(struct vio_dev *vdev,
+				struct ibmvscsis_adapter *adapter)
+{
+	const __be32 *dma_window;
+	const __be32 *prop;
+
+	/* TODO Using of_parse_dma_window would be better, but it doesn't give
+	 * a way to read multiple windows without already knowing the size of
+	 * a window or the number of windows
+	 */
+	dma_window =
+		(const __be32 *)vio_get_attribute(vdev, "ibm,my-dma-window",
+						NULL);
+	if (!dma_window) {
+		pr_err("ibmvscsis: Couldn't find ibm,my-dma-window property\n");
+		return -1;
+	}
+
+	adapter->liobn = be32_to_cpu(*dma_window);
+	dma_window++;
+
+	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells",
+						NULL);
+	if (!prop) {
+		pr_warn("ibmvscsis: Couldn't find ibm, #dma-address-cells property\n");
+		dma_window++;
+	} else
+		dma_window += be32_to_cpu(*prop);
+
+	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells",
+						NULL);
+	if (!prop) {
+		pr_warn("ibmvscsis: Couldn't find ibm, #dma-size-cells property\n");
+		dma_window++;
+	} else
+		dma_window += be32_to_cpu(*prop);
+
+	/* dma_window should point to the second window now */
+	adapter->riobn = be32_to_cpu(*dma_window);
+
+	return 0;
+}
+
+static void ibmvscsis_dev_release(struct device *dev) {};
+
+static char *ibmvscsis_get_fabric_name(void)
+{
+	return "ibmvscsis";
+}
+
+static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+	struct ibmvscsis_tport *tport =
+		container_of(se_tpg, struct ibmvscsis_tport, se_tpg);
+
+	return &tport->tport_name[0];
+}
+
+static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg)
+{
+	struct ibmvscsis_tport *tport =
+		container_of(se_tpg, struct ibmvscsis_tport, se_tpg);
+
+	return tport->tport_tpgt;
+}
+
+static u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static int ibmvscsis_check_true(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static int ibmvscsis_check_false(struct se_portal_group *se_tpg)
+{
+	return 0;
+}
+
+static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static int ibmvscsis_check_stop_free(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+			struct ibmvscsis_cmnd, se_cmd);
+
+	return target_put_sess_cmd(&cmd->se_cmd);
+}
+
+static void ibmvscsis_release_cmd(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmnd *cmd =
+		container_of(se_cmd, struct ibmvscsis_cmnd, se_cmd);
+
+	kfree(cmd);
+}
+
+static int ibmvscsis_shutdown_session(struct se_session *se_sess)
+{
+	return 0;
+}
+
+static void ibmvscsis_close_session(struct se_session *se_sess)
+{
+}
+
+static u32 ibmvscsis_sess_get_index(struct se_session *se_sess)
+{
+	return 0;
+}
+
+static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+			struct ibmvscsis_cmnd, se_cmd);
+	struct scsi_cmnd *sc = &cmd->sc;
+	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
+	int ret;
+
+	pr_debug("ibmvscsis: ibmvscsis_write_pending\n");
+	sc->sdb.length = se_cmd->data_length;
+	sc->sdb.table.nents = se_cmd->t_data_nents;
+	sc->sdb.table.sgl = se_cmd->t_data_sg;
+
+	ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
+				ibmvscsis_rdma, 1, 1);
+	if (ret) {
+		pr_err("ibmvscsis: srp_transfer_data() failed: %d\n", ret);
+		return -EAGAIN;
+	}
+	/*
+	 * We now tell TCM to add this WRITE CDB directly into the TCM storage
+	 * object execution queue.
+	 */
+	target_execute_cmd(&cmd->se_cmd);
+	return 0;
+}
+
+static int ibmvscsis_write_pending_status(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl)
+{
+}
+
+static int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static void ibmvscsis_determine_resid(struct se_cmd *se_cmd,
+				      struct srp_rsp *rsp)
+{
+	if (se_cmd->residual_count) {
+		if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
+			if (se_cmd->data_direction == DMA_TO_DEVICE) {
+				/* residual data from an underflow write */
+				rsp->flags = SRP_RSP_FLAG_DOUNDER;
+				rsp->data_out_res_cnt =
+					cpu_to_be32(se_cmd->residual_count);
+			} else if (se_cmd->data_direction == DMA_FROM_DEVICE) {
+				/* residual data from an underflow read */
+				rsp->flags = SRP_RSP_FLAG_DIUNDER;
+				rsp->data_in_res_cnt =
+					cpu_to_be32(se_cmd->residual_count);
+			}
+		} else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
+			if (se_cmd->data_direction == DMA_TO_DEVICE) {
+				/*  residual data from an overflow write */
+				rsp->flags = SRP_RSP_FLAG_DOOVER;
+				rsp->data_out_res_cnt =
+					cpu_to_be32(se_cmd->residual_count);
+			} else if (se_cmd->data_direction ==
+				   DMA_FROM_DEVICE) {
+				/* residual data from an overflow read */
+				rsp->flags = SRP_RSP_FLAG_DIOVER;
+				rsp->data_in_res_cnt =
+					cpu_to_be32(se_cmd->residual_count);
+			}
+		}
+	}
+}
+
+static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+			struct ibmvscsis_cmnd, se_cmd);
+	struct scsi_cmnd *sc = &cmd->sc;
+	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
+	struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
+	struct srp_rsp *rsp;
+	char *sd;
+	char *data;
+	int ret;
+	uint len;
+
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
+
+	/*
+	 * Check for overflow residual count
+	 */
+	pr_debug("ibmvscsis: ibmvscsis_queue_data_in\n");
+
+	if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
+		scsi_set_resid(sc, se_cmd->residual_count);
+
+	sc->sdb.length = se_cmd->data_length;
+	sc->sdb.table.nents = se_cmd->t_data_nents;
+	sc->sdb.table.sgl = se_cmd->t_data_sg;
+
+	if (scsi_sg_count(sc)) {
+		if (srp->cdb[0] == REPORT_LUNS &&
+					adapter->client_data.os_type != LINUX)
+			ibmvscsis_modify_rep_luns(se_cmd);
+		if ((srp->cdb[0] == INQUIRY) && ((srp->cdb[1] & 0x1) == 0))
+			ibmvscsis_modify_std_inquiry(se_cmd);
+		ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
+					ibmvscsis_rdma, 1, 1);
+		if (ret) {
+			pr_err("ibmvscsis: srp_transfer_data failed: %d\n",
+				ret);
+			sd = cmd->se_cmd.sense_buffer;
+			cmd->se_cmd.scsi_sense_length = 18;
+			memset(cmd->se_cmd.sense_buffer, 0,
+				cmd->se_cmd.scsi_sense_length);
+			sd[0] = 0x70;
+			sd[2] = 3;
+			sd[7] = 10;
+			sd[12] = 8;
+			sd[13] = 1;
+		}
+	}
+
+	rsp = &vio_iu(iue)->srp.rsp;
+	len = sizeof(*rsp);
+	memset(rsp, 0, len);
+	data = rsp->data;
+
+	rsp->tag = se_cmd->tag;
+	rsp->req_lim_delta = cpu_to_be32(1);
+	rsp->opcode = SRP_RSP;
+
+	ibmvscsis_determine_resid(se_cmd, rsp);
+	rsp->status = se_cmd->scsi_status;
+
+	if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) {
+		rsp->sense_data_len = cpu_to_be32(se_cmd->scsi_sense_length);
+		rsp->flags |= SRP_RSP_FLAG_SNSVALID;
+		len += se_cmd->scsi_sense_length;
+		memcpy(data, se_cmd->sense_buffer, se_cmd->scsi_sense_length);
+	}
+
+	send_iu(iue, len, VIOSRP_SRP_FORMAT);
+	return 0;
+}
+
+static int ibmvscsis_queue_status(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+					struct ibmvscsis_cmnd, se_cmd);
+	struct scsi_cmnd *sc = &cmd->sc;
+	struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+	struct srp_rsp *rsp;
+	uint len;
+	char *data;
+
+	/*
+	 * Copy any generated SENSE data into sc->sense_buffer and
+	 * set the appropriate sc->result to be translated by
+	 * ibmvscsis_cmnd_done()
+	 */
+	pr_debug("ibmvscsis: ibmvscsis_queue_status\n");
+
+	rsp = &vio_iu(iue)->srp.rsp;
+	len = sizeof(*rsp);
+	memset(rsp, 0, len);
+	data = rsp->data;
+
+	rsp->tag = se_cmd->tag;
+	rsp->req_lim_delta = cpu_to_be32(1);
+	rsp->opcode = SRP_RSP;
+
+	ibmvscsis_determine_resid(se_cmd, rsp);
+	rsp->status = se_cmd->scsi_status;
+
+	if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) {
+		rsp->sense_data_len = cpu_to_be32(se_cmd->scsi_sense_length);
+		rsp->flags |= SRP_RSP_FLAG_SNSVALID;
+		len += se_cmd->scsi_sense_length;
+		memcpy(data, se_cmd->sense_buffer, se_cmd->scsi_sense_length);
+	}
+	send_iu(iue, len, VIOSRP_SRP_FORMAT);
+	return 0;
+}
+
+static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+			struct ibmvscsis_cmnd, se_cmd);
+	struct scsi_cmnd *sc = &cmd->sc;
+	struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
+	struct srp_rsp *rsp;
+	uint len;
+	char *data;
+	u32 *tsk_status;
+	u32 rsp_code;
+
+	pr_debug("ibmvscsis: ibmvscsis_queue_tm_rsp\n");
+	rsp = &vio_iu(iue)->srp.rsp;
+
+	if (transport_check_aborted_status(se_cmd, false) != 0) {
+		pr_debug("ibmvscsis: queue_tm_rsp aborted\n");
+		atomic_inc(&adapter->req_lim_delta);
+		srp_iu_put(iue);
+	} else {
+		rsp->req_lim_delta = cpu_to_be32(1
+				+ atomic_xchg(&adapter->req_lim_delta, 0));
+	}
+
+	len = sizeof(*rsp);
+	memset(rsp, 0, len);
+	data = rsp->data;
+
+	rsp->opcode = SRP_RSP;
+	rsp->tag = se_cmd->se_tmr_req->ref_task_tag;
+	rsp->status = 0;
+	rsp->resp_data_len = cpu_to_be32(4);
+	rsp->flags |= SRP_RSP_FLAG_RSPVALID;
+	rsp->req_lim_delta = cpu_to_be32(1);
+
+	switch (se_cmd->se_tmr_req->response) {
+	case TMR_FUNCTION_COMPLETE:
+	case TMR_TASK_DOES_NOT_EXIST:
+		rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE;
+		break;
+	case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
+	case TMR_LUN_DOES_NOT_EXIST:
+		rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED;
+		break;
+	case TMR_FUNCTION_FAILED:
+	case TMR_FUNCTION_REJECTED:
+	default:
+		rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_FAILED;
+		break;
+	}
+
+	tsk_status = (u32 *)data;
+	*tsk_status = cpu_to_be32(rsp_code);
+	data = (char *)(tsk_status + 1);
+	len += 4;
+
+	send_iu(iue, len, VIOSRP_SRP_FORMAT);
+}
+
+static void ibmvscsis_aborted_task(struct se_cmd *se_cmd)
+{
+}
+
+static struct se_portal_group *ibmvscsis_make_nexus(
+				struct ibmvscsis_tport *tport,
+				const char *name)
+{
+	struct se_node_acl *acl;
+
+	pr_debug("ibmvscsis: make nexus");
+	if (tport->se_sess) {
+		pr_debug("tport->se_sess already exists\n");
+		return &tport->se_tpg;
+	}
+
+	/*
+	 *  Initialize the struct se_session pointer and setup tagpool
+	 *  for struct ibmvscsis_cmd descriptors
+	 */
+	tport->se_sess = transport_init_session(TARGET_PROT_NORMAL);
+	if (IS_ERR(tport->se_sess))
+		goto transport_init_fail;
+
+	/*
+	 * Since we are running in 'demo mode' this call will generate a
+	 * struct se_node_acl for the ibmvscsis struct se_portal_group with
+	 * the SCSI Initiator port name of the passed configfs group 'name'.
+	 */
+
+	acl = core_tpg_check_initiator_node_acl(&tport->se_tpg,
+				(unsigned char *)name);
+	if (!acl) {
+		pr_debug("core_tpg_check_initiator_node_acl() failed for %s\n",
+			name);
+		goto acl_failed;
+	}
+	tport->se_sess->se_node_acl = acl;
+
+	/*
+	 * Now register the TCM ibmvscsis virtual I_T Nexus as active.
+	 */
+	transport_register_session(&tport->se_tpg,
+					tport->se_sess->se_node_acl,
+					tport->se_sess, tport);
+
+	tport->se_sess->se_tpg = &tport->se_tpg;
+
+	return &tport->se_tpg;
+
+acl_failed:
+	transport_free_session(tport->se_sess);
+transport_init_fail:
+	kfree(tport);
+	return ERR_PTR(-ENOMEM);
+}
+
+static int ibmvscsis_drop_nexus(struct ibmvscsis_tport *tport)
+{
+	struct se_session *se_sess;
+
+	se_sess = tport->se_sess;
+	if (!se_sess)
+		return -ENODEV;
+
+	transport_deregister_session(tport->se_sess);
+	transport_free_session(tport->se_sess);
+	return 0;
+}
+
+static struct ibmvscsis_tport *ibmvscsis_lookup_port(const char *name)
+{
+	struct ibmvscsis_tport *tport;
+	struct vio_dev *vdev;
+	struct ibmvscsis_adapter *adapter;
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ibmvscsis_dev_lock, flags);
+	list_for_each_entry(adapter, &ibmvscsis_dev_list, list) {
+		vdev = adapter->dma_dev;
+		ret = strcmp(dev_name(&vdev->dev), name);
+		if (ret == 0)
+			tport = &adapter->tport;
+		if (tport)
+			goto found;
+	}
+	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
+	return NULL;
+found:
+	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
+	return tport;
+}
+
+static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf,
+					   struct config_group *group,
+					   const char *name)
+{
+	struct ibmvscsis_tport *tport;
+	int ret;
+
+	tport = ibmvscsis_lookup_port(name);
+	ret = -EINVAL;
+
+	if (!tport)
+		goto err;
+
+	tport->tport_proto_id = SCSI_PROTOCOL_SRP;
+	pr_debug("ibmvscsis: make_tport(%s), pointer:%p tport_id:%x\n", name,
+					tport, tport->tport_proto_id);
+
+	return &tport->tport_wwn;
+err:
+	return ERR_PTR(ret);
+}
+
+static void ibmvscsis_drop_tport(struct se_wwn *wwn)
+{
+	struct ibmvscsis_tport *tport = container_of(wwn,
+				struct ibmvscsis_tport, tport_wwn);
+
+	pr_debug("drop_tport(%s\n",
+		config_item_name(&tport->tport_wwn.wwn_group.cg_item));
+}
+
+static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
+						  struct config_group *group,
+						  const char *name)
+{
+	struct ibmvscsis_tport *tport =
+		container_of(wwn, struct ibmvscsis_tport, tport_wwn);
+	int ret;
+
+	tport->releasing = false;
+
+	ret = core_tpg_register(&tport->tport_wwn,
+				&tport->se_tpg,
+				tport->tport_proto_id);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return &tport->se_tpg;
+}
+
+static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg)
+{
+	struct ibmvscsis_tport *tport = container_of(se_tpg,
+				struct ibmvscsis_tport, se_tpg);
+
+	tport->releasing = true;
+	tport->enabled = false;
+
+	/*
+	 * Release the virtual I_T Nexus for this ibmvscsis TPG
+	 */
+	ibmvscsis_drop_nexus(tport);
+	/*
+	 * Deregister the se_tpg from TCM..
+	 */
+	core_tpg_deregister(se_tpg);
+}
+
+static ssize_t system_id_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", system_id);
+}
+
+static ssize_t partition_number_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%x\n", partition_number);
+}
+
+static ssize_t unit_address_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct ibmvscsis_adapter *adapter =
+			container_of(dev, struct ibmvscsis_adapter, dev);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", adapter->dma_dev->unit_address);
+}
+
+static int get_system_info(void)
+{
+	struct device_node *rootdn, *vdevdn;
+	const char *id, *model, *name;
+	const unsigned int *num;
+
+	pr_debug("ibmvscsis: getsysteminfo");
+	rootdn = of_find_node_by_path("/");
+	if (!rootdn)
+		return -ENOENT;
+
+	model = of_get_property(rootdn, "model", NULL);
+	id = of_get_property(rootdn, "system-id", NULL);
+	if (model && id)
+		snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
+
+	name = of_get_property(rootdn, "ibm,partition-name", NULL);
+	if (name)
+		strncpy(partition_name, name, sizeof(partition_name));
+
+	num = of_get_property(rootdn, "ibm,partition-no", NULL);
+	if (num)
+		partition_number = of_read_number(num, 1);
+
+	of_node_put(rootdn);
+
+	vdevdn = of_find_node_by_path("/vdevice");
+	vdevdn = of_find_node_by_path("/vdevice");
+	if (vdevdn) {
+		const unsigned *mvds;
+
+		mvds = of_get_property(vdevdn, "ibm,max-virtual-dma-size",
+				       NULL);
+		if (mvds)
+			max_vdma_size = *mvds;
+		of_node_put(vdevdn);
+	}
+
+	return 0;
+};
+
+static irqreturn_t ibmvscsis_interrupt(int dummy, void *data)
+{
+	struct ibmvscsis_adapter *adapter = data;
+
+	pr_debug("ibmvscsis: there is an interrupt\n");
+	vio_disable_interrupts(adapter->dma_dev);
+	queue_work(vtgtd, &adapter->crq_work);
+
+	return IRQ_HANDLED;
+}
+
+static int process_srp_iu(struct iu_entry *iue)
+{
+	union viosrp_iu *iu = vio_iu(iue);
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
+	u8 opcode = iu->srp.rsp.opcode;
+	unsigned long flags;
+	int err = 1;
+
+	spin_lock_irqsave(&target->lock, flags);
+	if (adapter->tport.releasing == true) {
+		pr_err("ibmvscsis: process_srp_iu error, tport is released:%x\n",
+			adapter->tport.releasing);
+		goto done;
+	}
+	if (adapter->tport.enabled == false) {
+		pr_err("ibmvscsis: process_srp_iu, tport not enabled:%x\n",
+			adapter->tport.enabled);
+		goto done;
+	}
+	spin_unlock_irqrestore(&target->lock, flags);
+
+	switch (opcode) {
+	case SRP_LOGIN_REQ:
+		process_login(iue);
+		break;
+	case SRP_TSK_MGMT:
+		process_tsk_mgmt(adapter, iue);
+		break;
+	case SRP_CMD:
+		err = ibmvscsis_queuecommand(adapter, iue);
+		if (err) {
+			srp_iu_put(iue);
+			pr_err("ibmvscsis: can't queue cmd\n");
+		}
+		break;
+	case SRP_LOGIN_RSP:
+	case SRP_I_LOGOUT:
+		ibmvscsis_srp_i_logout(iue);
+		break;
+	case SRP_T_LOGOUT:
+	case SRP_RSP:
+	case SRP_CRED_REQ:
+	case SRP_CRED_RSP:
+	case SRP_AER_REQ:
+	case SRP_AER_RSP:
+		pr_err("ibmvscsis: Unsupported type %u\n", opcode);
+		break;
+	default:
+		pr_err("ibmvscsis: Unknown type %u\n", opcode);
+	}
+	return err;
+
+done:
+	spin_unlock_irqrestore(&target->lock, flags);
+	srp_iu_put(iue);
+	return err;
+}
+
+static void process_iu(struct viosrp_crq *crq,
+		       struct ibmvscsis_adapter *adapter)
+{
+	struct iu_entry *iue;
+	long err;
+
+	iue = srp_iu_get(adapter->target);
+	if (!iue) {
+		pr_err("ibmvscsis: Error getting IU from pool %p\n", iue);
+		return;
+	}
+
+	iue->remote_token = crq->IU_data_ptr;
+
+	err = h_copy_rdma(be16_to_cpu(crq->IU_length), adapter->riobn,
+				be64_to_cpu(crq->IU_data_ptr),
+				adapter->liobn, iue->sbuf->dma);
+
+	switch (err) {
+	case H_SUCCESS:
+		break;
+	case H_PERMISSION:
+	case H_SOURCE_PARM:
+	case H_DEST_PARM:
+		if (connection_broken(adapter))
+			pr_debug("ibmvscsis: rdma connection broken\n");
+	default:
+		pr_err("ibmvscsis: process iu error\n");
+		break;
+	}
+
+	if (crq->format == VIOSRP_MAD_FORMAT)
+		process_mad_iu(iue);
+	else {
+		pr_debug("ibmvscsis: process srpiu");
+		process_srp_iu(iue);
+	}
+}
+
+static void process_crq(struct viosrp_crq *crq,
+			struct ibmvscsis_adapter *adapter)
+{
+	switch (crq->valid) {
+	case 0xC0:
+		/* initialization */
+		switch (crq->format) {
+		case 0x01:
+			h_send_crq(adapter, 0xC002000000000000, 0);
+			break;
+		case 0x02:
+			break;
+		default:
+			pr_err("ibmvscsis: Unknown format %u\n", crq->format);
+		}
+		break;
+	case 0xFF:
+		/* transport event */
+		switch (crq->format) {
+		case MIGRATED:
+		case PARTNER_FAILED:
+		case PARTNER_DEREGISTER:
+			adapter->client_data.os_type = 0;
+			pr_debug("ibmvscsis (%s):trans_event:good format %d\n",
+			dev_name(&adapter->dma_dev->dev), (uint)crq->format);
+			break;
+		default:
+			pr_err("ibmvscsis (%s):trans_event:invalid format %d\n",
+			dev_name(&adapter->dma_dev->dev), (uint)crq->format);
+		}
+		break;
+	case 0x80:
+		/* real payload */
+		switch (crq->format) {
+		case VIOSRP_SRP_FORMAT:
+		case VIOSRP_MAD_FORMAT:
+			process_iu(crq, adapter);
+			break;
+		case VIOSRP_OS400_FORMAT:
+		case VIOSRP_AIX_FORMAT:
+		case VIOSRP_LINUX_FORMAT:
+		case VIOSRP_INLINE_FORMAT:
+			pr_err("ibmvscsis: Unsupported format %u\n",
+					crq->format);
+			break;
+		default:
+			pr_err("ibmvscsis: Unknown format %u\n",
+					crq->format);
+		}
+		break;
+	default:
+		pr_err("ibmvscsis: unknown message type 0x%02x!?\n",
+				crq->valid);
+	}
+}
+
+static void handle_crq(struct work_struct *work)
+{
+	struct ibmvscsis_adapter *adapter =
+			container_of(work, struct ibmvscsis_adapter, crq_work);
+	struct viosrp_crq *crq;
+	int done = 0;
+
+	while (!done) {
+		while ((crq = next_crq(&adapter->crq_queue)) != NULL) {
+			process_crq(crq, adapter);
+			crq->valid = 0x00;
+		}
+
+		vio_enable_interrupts(adapter->dma_dev);
+
+		crq = next_crq(&adapter->crq_queue);
+		if (crq) {
+			vio_disable_interrupts(adapter->dma_dev);
+			process_crq(crq, adapter);
+			crq->valid = 0x00;
+		} else
+			done = 1;
+	}
+}
+
+static int ibmvscsis_reset_crq_queue(struct ibmvscsis_adapter *adapter)
+{
+	int rc = 0;
+	struct vio_dev *vdev = adapter->dma_dev;
+	struct crq_queue *queue = &adapter->crq_queue;
+
+	/* Close the CRQ */
+	h_free_crq(vdev->unit_address);
+
+	/* Clean out the queue */
+	memset(queue->msgs, 0x00, PAGE_SIZE);
+	queue->cur = 0;
+
+	/* And re-open it again */
+	rc = h_reg_crq(vdev->unit_address, queue->msg_token,
+			PAGE_SIZE);
+	if (rc == 2)
+		/* Adapter is good, but other end is not ready */
+		pr_warn("ibmvscsis: Partner adapter not ready\n");
+	else if (rc != 0)
+		pr_err("ibmvscsis: couldn't register crq--rc 0x%x\n", rc);
+
+	return rc;
+}
+
+static void crq_queue_destroy(struct ibmvscsis_adapter *adapter)
+{
+	struct vio_dev *vdev = adapter->dma_dev;
+	struct crq_queue *queue = &adapter->crq_queue;
+
+	free_irq(vdev->irq, (void *)adapter);
+	flush_work(&adapter->crq_work);
+	h_free_crq(vdev->unit_address);
+	dma_unmap_single(&adapter->dma_dev->dev, queue->msg_token,
+			 queue->size * sizeof(*queue->msgs),
+			 DMA_BIDIRECTIONAL);
+
+	free_page((unsigned long)queue->msgs);
+}
+
+static inline struct viosrp_crq *next_crq(struct crq_queue *queue)
+{
+	struct viosrp_crq *crq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&queue->lock, flags);
+	crq = &queue->msgs[queue->cur];
+	if (crq->valid & 0x80 || crq->valid & 0xFF) {
+		if (++queue->cur == queue->size)
+			queue->cur = 0;
+
+		/* Ensure the read of the valid bit occurs before reading any
+		 * other bits of the CRQ entry
+		 */
+		rmb();
+	} else
+		crq = NULL;
+	spin_unlock_irqrestore(&queue->lock, flags);
+
+	return crq;
+}
+
+static int send_iu(struct iu_entry *iue, u64 length, u8 format)
+{
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
+	struct ibmvscsis_crq_msg crq_msg;
+	struct srp_rsp *rsp;
+	__be64 *crq_as_u64 = (__be64 *)&crq_msg;
+	long rc, rc1;
+
+	rsp = &vio_iu(iue)->srp.rsp;
+	pr_debug("ibmvscsis: send_iu: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
+			(unsigned long)length,
+			(unsigned long)adapter->liobn,
+			(unsigned long)iue->sbuf->dma,
+			(unsigned long)adapter->riobn,
+			(unsigned long)be64_to_cpu(iue->remote_token));
+
+	/* First copy the SRP */
+	rc = h_copy_rdma(length, adapter->liobn, iue->sbuf->dma,
+			 adapter->riobn, be64_to_cpu(iue->remote_token));
+
+	switch (rc) {
+	case H_SUCCESS:
+		break;
+	case H_PERMISSION:
+	case H_SOURCE_PARM:
+	case H_DEST_PARM:
+		if (connection_broken(adapter)) {
+			pr_debug("ibmvscsis: rdma connection broken\n");
+			goto end;
+		}
+		break;
+	default:
+		pr_err("ibmvscsis: Error %ld transferring data\n", rc);
+		length = 0;
+		break;
+	}
+
+	pr_debug("ibmvscsis: crq pre cooked: 0x%x, 0x%llx, 0x%llx\n",
+			format, length, vio_iu(iue)->srp.rsp.tag);
+
+	crq_msg.valid = 0x80;
+	crq_msg.format = format;
+	crq_msg.rsvd = 0;
+	if (rc == 0)
+		crq_msg.status = 0x99;
+	else
+		crq_msg.status = rsp->status;
+	crq_msg.rsvd1 = 0;
+	crq_msg.IU_length = cpu_to_be16(length);
+	crq_msg.IU_data_ptr = vio_iu(iue)->srp.rsp.tag;
+
+	pr_debug("ibmvscsis: send crq: 0x%x, 0x%llx, 0x%llx\n",
+			adapter->dma_dev->unit_address,
+			be64_to_cpu(crq_as_u64[0]),
+			be64_to_cpu(crq_as_u64[1]));
+
+	srp_iu_put(iue);
+
+	rc1 = h_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
+				be64_to_cpu(crq_as_u64[1]));
+
+	if (rc1) {
+		pr_err("ibmvscsis: %ld sending response\n", rc1);
+		return rc1;
+	}
+	return rc;
+end:
+	return rc;
+}
+
+static int send_adapter_info(struct iu_entry *iue,
+			     dma_addr_t remote_buffer, u16 length)
+{
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
+	dma_addr_t data_token;
+	struct viosrp_adapter_info *mad = &vio_iu(iue)->mad.adapter_info;
+	struct mad_adapter_info_data *info;
+	int err;
+
+	mad->common.status = cpu_to_be16(VIOSRP_MAD_SUCCESS);
+
+	if (be16_to_cpu(mad->common.length) > sizeof(*info)) {
+		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
+		return 0;
+	}
+
+	info = dma_alloc_coherent(&adapter->dma_dev->dev, sizeof(*info),
+				  &data_token, GFP_KERNEL);
+	if (!info) {
+		pr_err("ibmvscsis: bad dma_alloc_coherent %p\n", target);
+		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
+		return 1;
+	}
+
+	/* Get remote info */
+	err = h_copy_rdma(sizeof(*info), adapter->riobn,
+				be64_to_cpu(remote_buffer),
+				adapter->liobn, data_token);
+
+	if (err == H_SUCCESS) {
+		pr_err("ibmvscsis: Client connect: %s (%d)\n",
+		       info->partition_name, info->partition_number);
+
+		if (adapter->client_data.partition_number == 0)
+			adapter->client_data.partition_number =
+				be32_to_cpu(info->partition_number);
+		strncpy(adapter->client_data.srp_version, info->srp_version,
+			sizeof(adapter->client_data.srp_version));
+		strncpy(adapter->client_data.partition_name,
+			info->partition_name,
+			sizeof(adapter->client_data.partition_name));
+		adapter->client_data.mad_version =
+						be32_to_cpu(info->mad_version);
+		adapter->client_data.os_type = be32_to_cpu(info->os_type);
+		pr_debug("ibmvscsis: adapterinfo client adapter %u\n",
+				adapter->client_data.os_type);
+
+		strcpy(info->srp_version, "16.a");
+		strncpy(info->partition_name, partition_name,
+			sizeof(info->partition_name));
+
+		info->partition_number = cpu_to_be32(partition_number);
+		info->mad_version = cpu_to_be32(1);
+		info->os_type = cpu_to_be32(2);
+		memset(&info->port_max_txu[0], 0, sizeof(info->port_max_txu));
+		info->port_max_txu[0] = cpu_to_be32(SCSI_MAX_SG_SEGMENTS *
+						PAGE_SIZE);
+
+		dma_rmb();
+		/* Send our info to remote */
+		err = h_copy_rdma(sizeof(*info), adapter->liobn, data_token,
+				  adapter->riobn, be64_to_cpu(remote_buffer));
+
+		switch (err) {
+		case H_SUCCESS:
+			break;
+		case H_PERMISSION:
+		case H_SOURCE_PARM:
+		case H_DEST_PARM:
+			if (connection_broken(adapter))
+				pr_debug("ibmvscsis: rdma connection broken\n");
+		default:
+			pr_err("ibmvscsis: Error sending adapter info %d\n",
+			       err);
+			return -EIO;
+		}
+	} else {
+		pr_err("ibmvscsis: Error sending adapter info %d\n", err);
+		return 1;
+	}
+
+	dma_free_coherent(&adapter->dma_dev->dev, sizeof(*info), info,
+			  data_token);
+
+	return 0;
+}
+
+static int process_mad_iu(struct iu_entry *iue)
+{
+	union viosrp_iu *iu = vio_iu(iue);
+	struct viosrp_adapter_info *info;
+	struct viosrp_host_config *conf;
+
+	switch (be32_to_cpu(iu->mad.empty_iu.common.type)) {
+	case VIOSRP_EMPTY_IU_TYPE:
+		pr_err("ibmvscsis: %s\n", "Unsupported EMPTY MAD IU");
+		break;
+	case VIOSRP_ERROR_LOG_TYPE:
+		pr_err("ibmvscsis: %s\n", "Unsupported ERROR LOG MAD IU");
+		iu->mad.error_log.common.status = 1;
+		send_iu(iue, sizeof(iu->mad.error_log),	VIOSRP_MAD_FORMAT);
+		break;
+	case VIOSRP_ADAPTER_INFO_TYPE:
+		info = &iu->mad.adapter_info;
+		info->common.status = send_adapter_info(iue, info->buffer,
+							info->common.length);
+		send_iu(iue, sizeof(*info), VIOSRP_MAD_FORMAT);
+		break;
+	case VIOSRP_HOST_CONFIG_TYPE:
+		conf = &iu->mad.host_config;
+		conf->common.status = 1;
+		send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT);
+		break;
+	default:
+		pr_err("ibmvscsis: Unknown type %u\n", iu->srp.rsp.opcode);
+		iu->mad.empty_iu.common.status =
+					cpu_to_be16(VIOSRP_MAD_NOT_SUPPORTED);
+		send_iu(iue, sizeof(iu->mad), VIOSRP_MAD_FORMAT);
+		break;
+	}
+
+	return 1;
+}
+
+static void ibmvscsis_srp_i_logout(struct iu_entry *iue)
+{
+	union viosrp_iu *iu = vio_iu(iue);
+	struct srp_i_logout *log_out = &vio_iu(iue)->srp.i_logout;
+	u64 tag = iu->srp.rsp.tag;
+
+	log_out->opcode = SRP_I_LOGOUT;
+	log_out->tag = tag;
+	send_iu(iue, sizeof(*log_out), VIOSRP_SRP_FORMAT);
+}
+
+static void process_login(struct iu_entry *iue)
+{
+	union viosrp_iu *iu = vio_iu(iue);
+	struct srp_login_rsp *rsp = &iu->srp.login_rsp;
+	struct srp_login_rej *rej = &iu->srp.login_rej;
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
+	struct vio_dev *vdev = adapter->dma_dev;
+	struct se_portal_group *se_tpg;
+	char name[16];
+	u64 tag = iu->srp.rsp.tag;
+
+	/*
+	 * TODO handle case that requested size is wrong and buffer
+	 * format is wrong
+	 */
+	memset(iu, 0, max(sizeof(*rsp), sizeof(*rej)));
+
+	snprintf(name, sizeof(name), "%x", vdev->unit_address);
+
+	if (adapter->tport.enabled == false) {
+		rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+		pr_err("ibmvscsis: Rejected SRP_LOGIN_REQ because target %s has not yet been enabled",
+		       name);
+		goto reject;
+	}
+
+	se_tpg = ibmvscsis_make_nexus(&adapter->tport,
+				      &adapter->tport.tport_name[0]);
+	if (se_tpg == NULL) {
+		pr_debug("ibmvscsis: login make nexus fail se_tpg(%p)\n",
+						se_tpg);
+		goto reject;
+	}
+
+	rsp->opcode = SRP_LOGIN_RSP;
+
+	rsp->req_lim_delta = cpu_to_be32(INITIAL_SRP_LIMIT);
+
+	pr_debug("ibmvscsis: process_login, tag:%llu\n", tag);
+
+	rsp->tag = tag;
+	rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
+	rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
+	/* direct and indirect */
+	rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT
+					| SRP_BUF_FORMAT_INDIRECT);
+
+	send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT);
+	return;
+
+reject:
+	rej->opcode = SRP_LOGIN_REJ;
+	rej->tag = tag;
+	rej->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT
+				   | SRP_BUF_FORMAT_INDIRECT);
+
+	send_iu(iue, sizeof(*rej), VIOSRP_SRP_FORMAT);
+}
+
+static void process_tsk_mgmt(struct ibmvscsis_adapter *adapter,
+			     struct iu_entry *iue)
+{
+	struct srp_tsk_mgmt *srp_tsk = &vio_iu(iue)->srp.tsk_mgmt;
+	struct ibmvscsis_cmnd *cmd = adapter->cmd;
+	struct srp_rsp *rsp;
+	u64 unpacked_lun = 0;
+	u64 tag_to_abort = 0;
+	int tcm_type;
+	int rc = 0;
+
+	rsp = &vio_iu(iue)->srp.rsp;
+	unpacked_lun = ibmvscsis_unpack_lun((uint8_t *)&srp_tsk->lun,
+					    sizeof(srp_tsk->lun));
+
+	switch (srp_tsk->tsk_mgmt_func) {
+	case SRP_TSK_ABORT_TASK:
+		tcm_type = TMR_ABORT_TASK;
+		tag_to_abort = be64_to_cpu(srp_tsk->task_tag);
+		srp_iu_put(iue);
+		break;
+	case SRP_TSK_ABORT_TASK_SET:
+		tcm_type = TMR_ABORT_TASK_SET;
+		break;
+	case SRP_TSK_CLEAR_TASK_SET:
+		tcm_type = TMR_CLEAR_TASK_SET;
+		break;
+	case SRP_TSK_LUN_RESET:
+		tcm_type = TMR_LUN_RESET;
+		break;
+	case SRP_TSK_CLEAR_ACA:
+		tcm_type = TMR_CLEAR_ACA;
+		break;
+	default:
+		pr_err("ibmvscsis: unknown task mgmt func %d\n",
+						srp_tsk->tsk_mgmt_func);
+		cmd->se_cmd.se_tmr_req->response =
+					TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
+		rc = -1;
+		break;
+	}
+
+	if (!rc) {
+		cmd->se_cmd.tag = be64_to_cpu(srp_tsk->tag);
+
+		pr_debug("ibmvscsis: calling submit_tmr, func %d\n",
+			 srp_tsk->tsk_mgmt_func);
+		rc = target_submit_tmr(&cmd->se_cmd,
+				       adapter->tport.se_sess, NULL,
+				       unpacked_lun, srp_tsk, tcm_type,
+				       GFP_KERNEL, tag_to_abort,
+				       TARGET_SCF_ACK_KREF);
+		if (rc != 0) {
+			pr_err("ibmvscsis: target_submit_tmr failed, rc %d\n",
+			       rc);
+			cmd->se_cmd.se_tmr_req->response =
+							TMR_FUNCTION_REJECTED;
+			goto fail;
+		}
+	}
+fail:
+	if (rc)
+		transport_send_check_condition_and_sense(&cmd->se_cmd, 0, 0);
+
+}
+
+static bool connection_broken(struct ibmvscsis_adapter *adapter)
+{
+	u64 buffer[2];
+	struct viosrp_crq *crq;
+	long h_return_code;
+	bool rc = false;
+
+	/* create a PING crq */
+	crq = (struct viosrp_crq *)&buffer;
+	buffer[0] = buffer[1] = 0;
+	crq->valid = 0x80;
+	crq->format = 6;
+	crq->status = 0xF5;
+
+	h_return_code = h_send_crq(adapter,
+				   cpu_to_be64(buffer[0]),
+				   cpu_to_be64(buffer[1]));
+
+	pr_debug("ibmvscsis (%s): connection_broken: rc %ld\n",
+			dev_name(&adapter->dma_dev->dev), h_return_code);
+
+	if (h_return_code == H_CLOSED)
+		rc = true;
+
+	return rc;
+}
+
+static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
+			  struct srp_direct_buf *md, int nmd,
+			  enum dma_data_direction dir, unsigned int rest)
+{
+	struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
+	dma_addr_t token;
+	long err;
+	unsigned int done = 0;
+	int i, sidx, soff;
+
+	sidx = soff = 0;
+	token = sg_dma_address(sg + sidx);
+
+	for (i = 0; i < nmd && rest; i++) {
+		unsigned int mdone, mlen;
+
+		mlen = min(rest, be32_to_cpu(md[i].len));
+		for (mdone = 0; mlen;) {
+			int slen = min(sg_dma_len(sg + sidx) - soff, mlen);
+
+			if (dir == DMA_TO_DEVICE)
+				err = h_copy_rdma(slen,
+						  adapter->riobn,
+						  be64_to_cpu(md[i].va) + mdone,
+						  adapter->liobn,
+						  token + soff);
+			else
+				err = h_copy_rdma(slen,
+						  adapter->liobn,
+						  token + soff,
+						  adapter->riobn,
+						  be64_to_cpu(md[i].va)+mdone);
+			switch (err) {
+			case H_SUCCESS:
+				break;
+			case H_PERMISSION:
+			case H_SOURCE_PARM:
+			case H_DEST_PARM:
+				if (connection_broken(adapter))
+					pr_debug("ibmvscsis: rdma connection broken\n");
+			default:
+				pr_err("ibmvscsis: rdma error %d %d %ld\n",
+					dir, slen, err);
+				return -EIO;
+			}
+
+			mlen -= slen;
+			mdone += slen;
+			soff += slen;
+			done += slen;
+
+			if (soff == sg_dma_len(sg + sidx)) {
+				sidx++;
+				soff = 0;
+				token = sg_dma_address(sg + sidx);
+
+				if (sidx > nsg) {
+					pr_err("ibmvscsis: out of sg %p %d %d\n",
+						iue, sidx, nsg);
+					return -EIO;
+				}
+			}
+		}
+		rest -= mlen;
+	}
+	return 0;
+}
+
+static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
+				  struct iu_entry *iue)
+{
+	struct srp_cmd *cmd = iue->sbuf->buf;
+	struct scsi_cmnd *sc;
+	struct ibmvscsis_cmnd *vsc;
+	int ret;
+
+	pr_debug("ibmvscsis: ibmvscsis_queuecommand\n");
+
+	vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);
+	adapter->cmd = vsc;
+	sc = &vsc->sc;
+	sc->sense_buffer = vsc->se_cmd.sense_buffer;
+	sc->cmnd = cmd->cdb;
+	sc->SCp.ptr = (char *)iue;
+
+	ret = tcm_queuecommand(adapter, vsc, cmd);
+
+	return ret;
+}
+
+static uint64_t ibmvscsis_unpack_lun(const uint8_t *lun, int len)
+{
+	uint64_t res = NO_SUCH_LUN;
+	int addressing_method;
+
+	if (unlikely(len < 2)) {
+		pr_err("Illegal LUN length %d, expected 2 bytes or more\n",
+			len);
+		goto out;
+	}
+
+	switch (len) {
+	case 8:
+		if ((*((__be64 *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0)
+			goto out_err;
+		break;
+	case 4:
+		if (*((__be16 *)&lun[2]) != 0)
+			goto out_err;
+		break;
+	case 6:
+		if (*((__be32 *)&lun[2]) != 0)
+			goto out_err;
+		break;
+	case 2:
+		break;
+	default:
+		goto out_err;
+	}
+
+	addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */
+	switch (addressing_method) {
+	case SCSI_LUN_ADDR_METHOD_PERIPHERAL:
+	case SCSI_LUN_ADDR_METHOD_FLAT:
+	case SCSI_LUN_ADDR_METHOD_LUN:
+		res = *(lun + 1) | (((*lun) & 0x3f) << 8);
+		break;
+
+	case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN:
+	default:
+		pr_err("Unimplemented LUN addressing method %u\n",
+			addressing_method);
+		break;
+	}
+
+out:
+	return res;
+out_err:
+	pr_err("Support for multi-level LUNs has not yet been implemented\n");
+	goto out;
+}
+
+static int tcm_queuecommand(struct ibmvscsis_adapter *adapter,
+			    struct ibmvscsis_cmnd *vsc,
+			    struct srp_cmd *scmd)
+{
+	struct se_cmd *se_cmd;
+	int attr;
+	u64 data_len;
+	int ret;
+	uint64_t unpacked_lun;
+
+	switch (scmd->task_attr) {
+	case SRP_SIMPLE_TASK:
+		attr = TCM_SIMPLE_TAG;
+		break;
+	case SRP_ORDERED_TASK:
+		attr = TCM_ORDERED_TAG;
+		break;
+	case SRP_HEAD_TASK:
+		attr = TCM_HEAD_TAG;
+		break;
+	case SRP_ACA_TASK:
+		attr = TCM_ACA_TAG;
+		break;
+	default:
+		pr_err("ibmvscsis: Task attribute %d not supported\n",
+		       scmd->task_attr);
+		attr = TCM_SIMPLE_TAG;
+	}
+
+	pr_debug("ibmvscsis: srp_data_length: %llx, srp_direction:%x\n",
+			srp_data_length(scmd, srp_cmd_direction(scmd)),
+			srp_cmd_direction(scmd));
+	data_len = srp_data_length(scmd, srp_cmd_direction(scmd));
+
+	vsc->se_cmd.tag = scmd->tag;
+	se_cmd = &vsc->se_cmd;
+
+	pr_debug("ibmvscsis: size of lun:%lx, lun:%s\n", sizeof(scmd->lun),
+				&scmd->lun.scsi_lun[0]);
+
+	unpacked_lun = ibmvscsis_unpack_lun((uint8_t *)&scmd->lun,
+				sizeof(scmd->lun));
+
+	ret = target_submit_cmd(se_cmd, adapter->tport.se_sess,
+				&scmd->cdb[0], &vsc->sense_buf[0], unpacked_lun,
+				data_len, attr, srp_cmd_direction(scmd),
+				TARGET_SCF_ACK_KREF);
+	if (ret != 0) {
+		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+		pr_debug("ibmvscsis: tcm_queuecommand fail submit_cmd\n");
+		goto send_sense;
+	}
+	return 0;
+
+send_sense:
+	transport_send_check_condition_and_sense(&vsc->se_cmd, ret, 0);
+	transport_generic_free_cmd(&vsc->se_cmd, 0);
+	return -1;
+}
+
+/*
+ * ibmvscsis_init() - Kernel Module initialization
+ *
+ * Note: vio_register_driver() registers callback functions, and atleast one
+ * of those call back functions calls TCM - Linux IO Target Subsystem, thus
+ * the SCSI Target template must be registered before vio_register_driver()
+ * is called.
+ */
+static int __init ibmvscsis_init(void)
+{
+	int ret = -ENOMEM;
+
+	pr_info("IBMVSCSIS fabric module %s on %s/%s on "UTS_RELEASE"\n",
+		IBMVSCSIS_VERSION,
+		utsname()->sysname,
+		utsname()->machine);
+
+	ret = get_system_info();
+	if (ret) {
+		pr_err("ibmvscsis: ret %d from get_system_info\n", ret);
+		goto out;
+	}
+
+	ret = class_register(&ibmvscsis_class);
+	if (ret) {
+		pr_err("ibmvscsis failed class register\n");
+		goto out;
+	}
+
+	ret = target_register_template(&ibmvscsis_ops);
+	if (ret) {
+		pr_err("ibmvscsis: ret %d from target_register_template\n",
+				ret);
+		goto unregister_class;
+	}
+
+	vtgtd = create_workqueue("ibmvscsis");
+	if (!vtgtd)
+		goto unregister_target;
+
+	ret = vio_register_driver(&ibmvscsis_driver);
+	if (ret) {
+		pr_err("ibmvscsis: ret %d from vio_register_driver\n", ret);
+		goto destroy_wq;
+	}
+
+	return 0;
+
+destroy_wq:
+	destroy_workqueue(vtgtd);
+unregister_target:
+	target_unregister_template(&ibmvscsis_ops);
+unregister_class:
+	class_unregister(&ibmvscsis_class);
+out:
+	return ret;
+};
+
+static void __exit ibmvscsis_exit(void)
+{
+	pr_info("ibmvscsis: Unregister IBM virtual SCSI driver\n");
+	vio_unregister_driver(&ibmvscsis_driver);
+	destroy_workqueue(vtgtd);
+	target_unregister_template(&ibmvscsis_ops);
+	class_unregister(&ibmvscsis_class);
+};
+
+MODULE_DESCRIPTION("IBMVSCSIS fabric driver");
+MODULE_AUTHOR("Bryant G. Ly");
+MODULE_LICENSE("GPL");
+module_init(ibmvscsis_init);
+module_exit(ibmvscsis_exit);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsis.h b/drivers/scsi/ibmvscsi/ibmvscsis.h
new file mode 100644
index 0000000..bcee92b
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/ibmvscsis.h
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * IBM Virtual SCSI Target Driver
+ * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
+ *			   Santiago Leon (santil@us.ibm.com) IBM Corp.
+ *			   Linda Xie (lxie@us.ibm.com) IBM Corp.
+ *
+ * Copyright (C) 2005-2011 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2010 Nicholas A. Bellinger <nab@kernel.org>
+ * Copyright (C) 2016 Bryant G. Ly <bgly@us.ibm.com> IBM Corp.
+ *
+ * Authors: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ ****************************************************************************/
+
+#ifndef __H_IBMVSCSIS
+#define __H_IBMVSCSIS
+
+#define IBMVSCSIS_NAMELEN       32
+
+#define SCSOLNT_RESP_SHIFT      1
+#define UCSOLNT_RESP_SHIFT      2
+
+#define SCSOLNT         (1 << SCSOLNT_RESP_SHIFT)
+#define UCSOLNT         (1 << UCSOLNT_RESP_SHIFT)
+
+#define INQ_DATA_OFFSET 8
+#define NO_SUCH_LUN ((u64)-1LL)
+
+struct client_info {
+#define SRP_VERSION "16.a"
+	char srp_version[8];
+	/* root node property ibm,partition-name */
+	char partition_name[96];
+	/* root node property ibm,partition-no */
+	uint32_t partition_number;
+	/* initially 1 */
+	uint32_t mad_version;
+	uint32_t os_type;
+};
+
+struct ibmvscsis_cmnd {
+	/* Used for libsrp processing callbacks */
+	struct scsi_cmnd sc;
+	/* Used for TCM Core operations */
+	struct se_cmd se_cmd;
+	/* Sense buffer that will be mapped into outgoing status */
+	unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+	u32 lun;
+};
+
+struct ibmvscsis_crq_msg {
+	u8 valid;
+	u8 format;
+	u8 rsvd;
+	u8 status;
+	u16 rsvd1;
+	__be16 IU_length;
+	__be64 IU_data_ptr;
+};
+
+struct ibmvscsis_tport {
+	/* SCSI protocol the tport is providing */
+	u8 tport_proto_id;
+	/* ASCII formatted WWPN for SRP Target port */
+	char tport_name[IBMVSCSIS_NAMELEN];
+	/* Returned by ibmvscsis_make_tport() */
+	struct se_wwn tport_wwn;
+	int lun_count;
+	/* Returned by ibmvscsis_make_tpg() */
+	struct se_portal_group se_tpg;
+	/* ibmvscsis port target portal group tag for TCM */
+	u16 tport_tpgt;
+	/* Pointer to TCM session for I_T Nexus */
+	struct se_session *se_sess;
+	struct ibmvscsis_cmnd *cmd;
+	bool enabled;
+	bool releasing;
+};
+
+struct ibmvscsis_adapter {
+	struct device dev;
+	struct vio_dev *dma_dev;
+	struct list_head siblings;
+
+	struct crq_queue crq_queue;
+	struct work_struct crq_work;
+
+	atomic_t req_lim_delta;
+	u32 liobn;
+	u32 riobn;
+
+	struct srp_target *target;
+
+	struct list_head list;
+	struct ibmvscsis_tport tport;
+	struct ibmvscsis_cmnd *cmd;
+	struct client_info client_data;
+};
+
+struct ibmvscsis_nacl {
+	/* Returned by ibmvscsis_make_nexus */
+	struct se_node_acl se_node_acl;
+};
+
+struct inquiry_data {
+	u8 qual_type;
+	u8 rmb_reserve;
+	u8 version;
+	u8 aerc_naca_hisup_format;
+	u8 addl_len;
+	u8 sccs_reserved;
+	u8 bque_encserv_vs_multip_mchngr_reserved;
+	u8 reladr_reserved_linked_cmdqueue_vs;
+	char vendor[8];
+	char product[16];
+	char revision[4];
+	char vendor_specific[20];
+	char reserved1[2];
+	char version_descriptor[16];
+	char reserved2[22];
+	char unique[158];
+};
+
+enum srp_trans_event {
+	UNUSED_FORMAT = 0,
+	PARTNER_FAILED = 1,
+	PARTNER_DEREGISTER = 2,
+	MIGRATED = 6
+};
+
+enum scsi_lun_addr_method {
+	SCSI_LUN_ADDR_METHOD_PERIPHERAL   = 0,
+	SCSI_LUN_ADDR_METHOD_FLAT         = 1,
+	SCSI_LUN_ADDR_METHOD_LUN          = 2,
+	SCSI_LUN_ADDR_METHOD_EXTENDED_LUN = 3,
+};
+
+enum srp_os_type {
+	OS400 = 1,
+	LINUX = 2,
+	AIX = 3,
+	OFW = 4
+};
+
+#define vio_iu(IUE) ((union viosrp_iu *)((IUE)->sbuf->buf))
+
+#define h_reg_crq(ua, tok, sz)\
+			plpar_hcall_norets(H_REG_CRQ, ua, tok, sz)
+
+#endif
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
new file mode 100644
index 0000000..0e32abd
--- /dev/null
+++ b/drivers/scsi/libsrp.c
@@ -0,0 +1,387 @@
+/*******************************************************************************
+ * SCSI RDMA Protocol lib functions
+ *
+ * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2016 Bryant G. Ly <bgly@us.ibm.com> IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ ***********************************************************************/
+
+#include <linux/printk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/kfifo.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/srp.h>
+#include <target/target_core_base.h>
+#include <scsi/libsrp.h>
+
+static int srp_iu_pool_alloc(struct srp_queue *q, size_t max,
+			     struct srp_buf **ring)
+{
+	int i;
+	struct iu_entry *iue;
+
+	q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL);
+	if (!q->pool)
+		return -ENOMEM;
+	q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL);
+	if (!q->items)
+		goto free_pool;
+
+	spin_lock_init(&q->lock);
+	kfifo_init(&q->queue, (void *) q->pool, max * sizeof(void *));
+
+	for (i = 0, iue = q->items; i < max; i++) {
+		kfifo_in(&q->queue, (void *) &iue, sizeof(void *));
+		iue->sbuf = ring[i];
+		iue++;
+	}
+	return 0;
+
+free_pool:
+	kfree(q->pool);
+	return -ENOMEM;
+}
+
+static void srp_iu_pool_free(struct srp_queue *q)
+{
+	kfree(q->items);
+	kfree(q->pool);
+}
+
+static struct srp_buf **srp_ring_alloc(struct device *dev,
+				       size_t max, size_t size)
+{
+	int i;
+	struct srp_buf **ring;
+
+	ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL);
+	if (!ring)
+		return NULL;
+
+	for (i = 0; i < max; i++) {
+		ring[i] = kzalloc(sizeof(struct srp_buf), GFP_KERNEL);
+		if (!ring[i])
+			goto out;
+		ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma,
+						  GFP_KERNEL);
+		if (!ring[i]->buf)
+			goto out;
+	}
+	return ring;
+
+out:
+	for (i = 0; i < max && ring[i]; i++) {
+		if (ring[i]->buf) {
+			dma_free_coherent(dev, size, ring[i]->buf,
+						ring[i]->dma);
+		}
+		kfree(ring[i]);
+	}
+	kfree(ring);
+
+	return NULL;
+}
+
+static void srp_ring_free(struct device *dev, struct srp_buf **ring,
+			  size_t max, size_t size)
+{
+	int i;
+
+	for (i = 0; i < max; i++) {
+		dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
+		kfree(ring[i]);
+	}
+	kfree(ring);
+}
+
+int srp_target_alloc(struct srp_target *target, struct device *dev,
+		     size_t nr, size_t iu_size)
+{
+	int err;
+
+	spin_lock_init(&target->lock);
+
+	target->dev = dev;
+
+	target->srp_iu_size = iu_size;
+	target->rx_ring_size = nr;
+	target->rx_ring = srp_ring_alloc(target->dev, nr, iu_size);
+	if (!target->rx_ring)
+		return -ENOMEM;
+	err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring);
+	if (err)
+		goto free_ring;
+
+	dev_set_drvdata(target->dev, target);
+	return 0;
+
+free_ring:
+	srp_ring_free(target->dev, target->rx_ring, nr, iu_size);
+	return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(srp_target_alloc);
+
+void srp_target_free(struct srp_target *target)
+{
+	dev_set_drvdata(target->dev, NULL);
+	srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size,
+		      target->srp_iu_size);
+	srp_iu_pool_free(&target->iu_queue);
+}
+EXPORT_SYMBOL_GPL(srp_target_free);
+
+struct iu_entry *srp_iu_get(struct srp_target *target)
+{
+	struct iu_entry *iue = NULL;
+
+	if (kfifo_out_locked(&target->iu_queue.queue, (void *) &iue,
+				sizeof(void *),
+				&target->iu_queue.lock) != sizeof(void *)) {
+		WARN_ONCE(1, "unexpected fifo state");
+		return NULL;
+	}
+	if (!iue)
+		return iue;
+	iue->target = target;
+	iue->flags = 0;
+	return iue;
+}
+EXPORT_SYMBOL_GPL(srp_iu_get);
+
+void srp_iu_put(struct iu_entry *iue)
+{
+	kfifo_in_locked(&iue->target->iu_queue.queue, (void *) &iue,
+			sizeof(void *), &iue->target->iu_queue.lock);
+}
+EXPORT_SYMBOL_GPL(srp_iu_put);
+
+static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
+			   enum dma_data_direction dir, srp_rdma_t rdma_io,
+			   int dma_map, int ext_desc)
+{
+	struct iu_entry *iue = NULL;
+	struct scatterlist *sg = NULL;
+	int err, nsg = 0, len;
+
+	if (dma_map) {
+		iue = (struct iu_entry *) sc->SCp.ptr;
+		sg = scsi_sglist(sc);
+		nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
+				 DMA_BIDIRECTIONAL);
+		if (!nsg) {
+			pr_err("libsrp: fail to map %p %d\n",
+				iue, scsi_sg_count(sc));
+			return 0;
+		}
+		len = min(scsi_bufflen(sc), be32_to_cpu(md->len));
+	} else
+		len = be32_to_cpu(md->len);
+
+	err = rdma_io(sc, sg, nsg, md, 1, dir, len);
+
+	if (dma_map)
+		dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
+
+	return err;
+}
+
+static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
+			     struct srp_indirect_buf *id,
+			     enum dma_data_direction dir, srp_rdma_t rdma_io,
+			     int dma_map, int ext_desc)
+{
+	struct iu_entry *iue = NULL;
+	struct srp_direct_buf *md = NULL;
+	struct scatterlist dummy, *sg = NULL;
+	dma_addr_t token = 0;
+	int err = 0;
+	int nmd, nsg = 0, len;
+
+	if (dma_map || ext_desc) {
+		iue = (struct iu_entry *) sc->SCp.ptr;
+		sg = scsi_sglist(sc);
+	}
+
+	nmd = be32_to_cpu(id->table_desc.len) / sizeof(struct srp_direct_buf);
+
+	if ((dir == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) ||
+	    (dir == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt)) {
+		md = &id->desc_list[0];
+		goto rdma;
+	}
+
+	if (ext_desc && dma_map) {
+		md = dma_alloc_coherent(iue->target->dev,
+					be32_to_cpu(id->table_desc.len),
+					&token, GFP_KERNEL);
+		if (!md) {
+			pr_err("libsrp: Can't get dma memory %u\n",
+				be32_to_cpu(id->table_desc.len));
+			return -ENOMEM;
+		}
+
+		sg_init_one(&dummy, md, be32_to_cpu(id->table_desc.len));
+		sg_dma_address(&dummy) = token;
+		sg_dma_len(&dummy) = be32_to_cpu(id->table_desc.len);
+		err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
+			      be32_to_cpu(id->table_desc.len));
+		if (err) {
+			pr_err("libsrp: Error copying indirect table %d\n",
+				err);
+			goto free_mem;
+		}
+	} else {
+		pr_err("libsrp: This command uses external indirect buffer\n");
+		return -EINVAL;
+	}
+
+rdma:
+	if (dma_map) {
+		nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
+				 DMA_BIDIRECTIONAL);
+		if (!nsg) {
+			pr_err("libsrp: fail to map %p %d\n",
+				iue, scsi_sg_count(sc));
+			err = -EIO;
+			goto free_mem;
+		}
+		len = min(scsi_bufflen(sc), be32_to_cpu(id->len));
+	} else
+		len = be32_to_cpu(id->len);
+
+	err = rdma_io(sc, sg, nsg, md, nmd, dir, len);
+
+	if (dma_map)
+		dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
+
+free_mem:
+	if (token && dma_map) {
+		dma_free_coherent(iue->target->dev,
+				  be32_to_cpu(id->table_desc.len), md, token);
+	}
+	return err;
+}
+
+static int data_out_desc_size(struct srp_cmd *cmd)
+{
+	int size = 0;
+	u8 fmt = cmd->buf_fmt >> 4;
+
+	switch (fmt) {
+	case SRP_NO_DATA_DESC:
+		break;
+	case SRP_DATA_DESC_DIRECT:
+		size = sizeof(struct srp_direct_buf);
+		break;
+	case SRP_DATA_DESC_INDIRECT:
+		size = sizeof(struct srp_indirect_buf) +
+			sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt;
+		break;
+	default:
+		pr_err("libsrp: client error. Invalid data_out_format %x\n",
+			fmt);
+		break;
+	}
+	return size;
+}
+
+/*
+ * TODO: this can be called multiple times for a single command if it
+ * has very long data.
+ */
+int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
+		      srp_rdma_t rdma_io, int dma_map, int ext_desc)
+{
+	struct srp_direct_buf *md;
+	struct srp_indirect_buf *id;
+	enum dma_data_direction dir;
+	int offset, err = 0;
+	u8 format;
+
+	offset = cmd->add_cdb_len & ~3;
+
+	dir = srp_cmd_direction(cmd);
+	if (dir == DMA_FROM_DEVICE)
+		offset += data_out_desc_size(cmd);
+
+	if (dir == DMA_TO_DEVICE)
+		format = cmd->buf_fmt >> 4;
+	else
+		format = cmd->buf_fmt & ((1U << 4) - 1);
+
+	switch (format) {
+	case SRP_NO_DATA_DESC:
+		break;
+	case SRP_DATA_DESC_DIRECT:
+		md = (struct srp_direct_buf *)
+			(cmd->add_data + offset);
+		err = srp_direct_data(sc, md, dir, rdma_io, dma_map, ext_desc);
+		break;
+	case SRP_DATA_DESC_INDIRECT:
+		id = (struct srp_indirect_buf *)
+			(cmd->add_data + offset);
+		err = srp_indirect_data(sc, cmd, id, dir, rdma_io, dma_map,
+					ext_desc);
+		break;
+	default:
+		pr_err("libsrp: Unknown format %d %x\n", dir, format);
+		err = -EINVAL;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(srp_transfer_data);
+
+u64 srp_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
+{
+	struct srp_direct_buf *md;
+	struct srp_indirect_buf *id;
+	u64 len = 0;
+	unsigned offset = cmd->add_cdb_len & ~3;
+	u8 fmt;
+
+	if (dir == DMA_TO_DEVICE)
+		fmt = cmd->buf_fmt >> 4;
+	else {
+		fmt = cmd->buf_fmt & ((1U << 4) - 1);
+		offset += data_out_desc_size(cmd);
+	}
+
+	switch (fmt) {
+	case SRP_NO_DATA_DESC:
+		break;
+	case SRP_DATA_DESC_DIRECT:
+		md = (struct srp_direct_buf *) (cmd->add_data + offset);
+		len = be32_to_cpu(md->len);
+		break;
+	case SRP_DATA_DESC_INDIRECT:
+		id = (struct srp_indirect_buf *) (cmd->add_data + offset);
+		len = be32_to_cpu(id->len);
+		break;
+	default:
+		pr_err("invalid data format %x\n", fmt);
+		break;
+	}
+	return len;
+}
+EXPORT_SYMBOL_GPL(srp_data_length);
+
+MODULE_DESCRIPTION("SCSI RDMA Protocol lib functions");
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_LICENSE("GPL");
diff --git a/include/scsi/libsrp.h b/include/scsi/libsrp.h
new file mode 100644
index 0000000..f9b2d8f
--- /dev/null
+++ b/include/scsi/libsrp.h
@@ -0,0 +1,95 @@
+#ifndef __LIBSRP_H__
+#define __LIBSRP_H__
+
+#include <linux/list.h>
+#include <linux/kfifo.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/srp.h>
+#include <target/target_core_base.h>
+
+enum srp_task_attributes {
+	SRP_SIMPLE_TASK = 0,
+	SRP_HEAD_TASK = 1,
+	SRP_ORDERED_TASK = 2,
+	SRP_ACA_TASK = 4
+};
+
+enum iue_flags {
+	V_DIOVER,
+	V_WRITE,
+	V_LINKED,
+	V_FLYING,
+};
+
+enum {
+	SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE           = 0,
+	SRP_REQUEST_FIELDS_INVALID                      = 2,
+	SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED      = 4,
+	SRP_TASK_MANAGEMENT_FUNCTION_FAILED             = 5
+};
+
+struct srp_buf {
+	dma_addr_t dma;
+	void *buf;
+};
+
+struct srp_queue {
+	void *pool;
+	void *items;
+	struct kfifo queue;
+	spinlock_t lock;
+};
+
+struct srp_target {
+	struct Scsi_Host *shost;
+	struct se_device *tgt;
+	struct device *dev;
+
+	spinlock_t lock;
+	struct list_head cmd_queue;
+
+	size_t srp_iu_size;
+	struct srp_queue iu_queue;
+	size_t rx_ring_size;
+	struct srp_buf **rx_ring;
+
+	void *ldata;
+};
+
+struct iu_entry {
+	struct srp_target *target;
+
+	struct list_head ilist;
+	dma_addr_t remote_token;
+	unsigned long flags;
+
+	struct srp_buf *sbuf;
+};
+
+typedef int (srp_rdma_t)(struct scsi_cmnd *, struct scatterlist *, int,
+			 struct srp_direct_buf *, int,
+			 enum dma_data_direction, unsigned int);
+extern int srp_target_alloc(struct srp_target *, struct device *,
+				size_t, size_t);
+extern void srp_target_free(struct srp_target *);
+
+extern struct iu_entry *srp_iu_get(struct srp_target *);
+extern void srp_iu_put(struct iu_entry *);
+
+extern int srp_transfer_data(struct scsi_cmnd *, struct srp_cmd *,
+			     srp_rdma_t, int, int);
+
+static inline struct srp_target *host_to_srp_target(struct Scsi_Host *host)
+{
+	return (struct srp_target *) host->hostdata;
+}
+
+static inline int srp_cmd_direction(struct srp_cmd *cmd)
+{
+	return (cmd->buf_fmt >> 4) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+}
+
+extern u64 srp_data_length(struct srp_cmd *cmd, enum dma_data_direction dir);
+
+#endif
--

This is a first push up for grok and is WIP code. The driver does function,
but there are alot of features left that need to be handled and will be
addressed in a series of upcoming patches. We currently have a version of the
driver that is closer to being complete, but is pending lawyers approval,
since it was written by referencing our internal VIOS Virtual SCSI driver.

2.5.4 (Apple Git-61)

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
  2016-05-24 13:52 [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver Bryant G. Ly
@ 2016-05-24 14:14 ` Joe Perches
  2016-05-24 14:30 ` Greg KH
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 17+ messages in thread
From: Joe Perches @ 2016-05-24 14:14 UTC (permalink / raw)
  To: Bryant G. Ly, JBottomley, martin.petersen, tyreld, akpm, kvalo,
	davem, gregkh, mchehab, jslaby, bp
  Cc: linux-kernel, linux-scsi, target-devel, bgly

On Tue, 2016-05-24 at 08:52 -0500, Bryant G. Ly wrote:
> From: bgly <bgly@us.ibm.com>
> 
> This initial commit contains WIP of the IBM VSCSI Target Fabric
> Module. It currently supports read/writes, and I have tested
> the ability to create a file backstore with the driver and install
> RHEL VIA NIM and then boot up the partition via filio backstore
> through the driver.

Only trivial notes:

Maybe try checkpatch with the --strict option and see
if any of the additional messages are important to you.

> diff --git a/MAINTAINERS b/MAINTAINERS
[]
> @@ -5381,6 +5381,16 @@ S:	Supported
>  F:	drivers/scsi/ibmvscsi/ibmvscsi*
>  F:	drivers/scsi/ibmvscsi/viosrp.h
>  
> +IBM Power Virtual SCSI Device Target Driver
> +M:	Bryant G. Ly <bryantly@linux.vnet.ibm.com>
> +L:	linux-scsi@vger.kernel.org
> +L:	target-devel@vger.kernel.org
> +S:	Supported
> +F:	drivers/scsi/ibmvscsi/ibmvscsis.c
> +F:      drivers/scsi/ibmvscsi/ibmvscsis.h
> +F:	drivers/scsi/libsrp.h
> +F:      drivers/scsi/libsrp.c

Please use a tab character consistently after the :

> diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
[]
> @@ -847,6 +847,20 @@ config SCSI_IBMVSCSI
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called ibmvscsi.
>  
> +config SCSI_IBMVSCSIS
> +  	tristate "IBM Virtual SCSI Server support"
> +  	depends on PPC_PSERIES && SCSI_SRP && TARGET_CORE
> +  	help
> +  	  This is the IBM POWER Virtual SCSI Target Server
> +
> +          The userspace component needed to initialize the driver and
> +  	  documentation can be found:

here too.

> +
> +          https://github.com/powervm/ibmvscsis
> +
> +          To compile this driver as a module, choose M here: the
> +  	  module will be called ibmvstgt.
> +

[]

> diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
[]
> @@ -127,7 +127,9 @@ obj-$(CONFIG_SCSI_LASI700)	+= 53c700.o lasi700.o
>  obj-$(CONFIG_SCSI_SNI_53C710)	+= 53c700.o sni_53c710.o
>  obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
>  obj-$(CONFIG_SCSI_IPR)		+= ipr.o
> +obj-$(CONFIG_SCSI_SRP)          += libsrp.o
>  obj-$(CONFIG_SCSI_IBMVSCSI)	+= ibmvscsi/
> +obj-$(CONFIG_SCSI_IBMVSCSIS)    += ibmvscsi/

and here

> diff --git a/drivers/scsi/ibmvscsi/ibmvscsis.c b/drivers/scsi/ibmvscsi/ibmvscsis.c
[]

> +static int ibmvscsis_probe(struct vio_dev *vdev,
> +			   const struct vio_device_id *id);
[...]

It might be nice to rearrange the code to avoid these forward
function declarations.

> +static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item,
> +		const char *page, size_t count)
> +{
[]
> > +	ret = kstrtoul(page, 0, &tmp);
> +	if (ret < 0) {
> +		pr_err("Unable to extract ibmvscsis_tpg_store_enable\n");
> +		return -EINVAL;
> +	}

It might be nicer to add:

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

before any #include to output all the logging messages with
a standardized prefix.  Then all the other logging with an
embedded prefix can have the embedded prefix removed too.

> +
> +	if ((tmp != 0) && (tmp != 1)) {
> +		pr_err("Illegal value for ibmvscsis_tpg_store_enable: %lu\n",
> +			tmp);
> +		return -EINVAL;
> +	}
> +
> +	if (tmp == 1)
> +		tport->enabled = true;
> +	else
> +		tport->enabled = false;

	tport->enabled = tmp;

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
  2016-05-24 13:52 [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver Bryant G. Ly
  2016-05-24 14:14 ` Joe Perches
@ 2016-05-24 14:30 ` Greg KH
  2016-05-24 16:25   ` Bart Van Assche
  2016-05-25 14:17 ` IBM VSCSI Target Driver Initial Patch Sets Bryant G. Ly
  3 siblings, 0 replies; 17+ messages in thread
From: Greg KH @ 2016-05-24 14:30 UTC (permalink / raw)
  To: Bryant G. Ly
  Cc: JBottomley, martin.petersen, tyreld, akpm, kvalo, davem, mchehab,
	jslaby, joe, bp, linux-kernel, linux-scsi, target-devel, bgly

On Tue, May 24, 2016 at 08:52:58AM -0500, Bryant G. Ly wrote:
> From: bgly <bgly@us.ibm.com>

Really?  Please go get a proper review from the other internal IBM
developers to fix this, and the other obvious problems with your patch,
before you send it publically and force us to tell you these things...

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
  2016-05-24 13:52 [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver Bryant G. Ly
@ 2016-05-24 16:25   ` Bart Van Assche
  2016-05-24 14:30 ` Greg KH
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 17+ messages in thread
From: Bart Van Assche @ 2016-05-24 16:25 UTC (permalink / raw)
  To: Bryant G. Ly, JBottomley, martin.petersen, tyreld, akpm, kvalo,
	davem, gregkh, mchehab, jslaby, joe, bp
  Cc: linux-kernel, linux-scsi, target-devel, bgly, Joe Perches

On 05/24/2016 06:52 AM, Bryant G. Ly wrote:
> +config SCSI_IBMVSCSIS
> +  	tristate "IBM Virtual SCSI Server support"
> +  	depends on PPC_PSERIES && SCSI_SRP && TARGET_CORE
> +  	help
> +  	  This is the IBM POWER Virtual SCSI Target Server
> +
> +          The userspace component needed to initialize the driver and
> +  	  documentation can be found:
> +
> +          https://github.com/powervm/ibmvscsis
> +
> +          To compile this driver as a module, choose M here: the
> +  	  module will be called ibmvstgt.
> +

This driver has confused Linux users before. Most people know SRP as a 
SCSI transport layer that is used for communication between servers. 
This driver however uses the SRP protocol for communication between 
guests and/or the host that run on the same server. Please add this 
information to the above help text, together with a reference to the VIO 
protocol documentation in the POWER architecture manual.

> +#include <generated/utsrelease.h>

Every Linux user can query the kernel version by running the uname 
command. Is it really useful to print the kernel version (UTS_RELEASE) 
when this driver is loaded?

> +#include "ibmvscsi.h"

The above include directive indirectly includes a whole bunch of SCSI 
initiator driver header files. We do not want that initiator header 
files are included in the source code of a target driver. If it is 
necessary to share definitions of symbolic constants between the 
initiator and the target driver please move these into a new header file.

> +static inline long h_send_crq(struct ibmvscsis_adapter *adapter,
> +			u64 word1, u64 word2)
> +{
> +	long rc;
> +	struct vio_dev *vdev = adapter->dma_dev;
> +
> +	pr_debug("ibmvscsis: ibmvscsis_send_crq(0x%x, 0x%016llx, 0x%016llx)\n",
> +			vdev->unit_address, word1, word2);
> +

As Joe Perches already asked, please define pr_fmt() instead of 
including the kernel module name in every pr_debug() statement.

> +static char system_id[64] = "";
> +static char partition_name[97] = "UNKNOWN";

Where do these magic constants come from and what is their meaning? 
Please consider to introduce symbolic names for these constants.

> +static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item,
> +				char *page)
> +{
> +	struct se_portal_group *se_tpg = to_tpg(item);
> +	struct ibmvscsis_tport *tport = container_of(se_tpg,
> +						struct ibmvscsis_tport, se_tpg);
> +
> +	return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0);
> +}

Have you considered to use MODULE_VERSION() instead of introducing a 
sysfs attribute to export the module version? An advantage of 
MODULE_VERSION() is that it allows to query the module version without 
having to load a kernel module.

> +static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd)
> +{
> +	struct se_device *dev = se_cmd->se_dev;
> +	unsigned char *buf = NULL;
> +	u32 cmd_len = se_cmd->data_length;
> +
> +	if (cmd_len <= INQ_DATA_OFFSET)
> +		return;
> +
> +	buf = transport_kmap_data_sg(se_cmd);
> +	if (buf) {
> +		memcpy(&buf[8], "IBM	     ", 8);
> +		if (dev->transport->get_device_type(dev) == TYPE_ROM)
> +			memcpy(&buf[16], "VOPTA           ", 16);
> +		else
> +			memcpy(&buf[16], "3303      NVDISK", 16);
> +		memcpy(&buf[32], "0001", 4);
> +		transport_kunmap_data_sg(se_cmd);
> +	}
> +}

Shouldn't a sense code be returned to the initiator if this function fails?

> +	default:
> +		pr_err("ibmvscsis: unknown task mgmt func %d\n",
> +						srp_tsk->tsk_mgmt_func);
> +		cmd->se_cmd.se_tmr_req->response =
> +					TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
> +		rc = -1;
> +		break;
> +	}
> +
> +	if (!rc) {

Please consider changing the above "break" into "goto fail" such that 
the if (!rc) can be left out and such that the indentation of the code 
below if (!rc) can be reduced.

> +static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
> +				  struct iu_entry *iue)
> +{
> +	struct srp_cmd *cmd = iue->sbuf->buf;
> +	struct scsi_cmnd *sc;
> +	struct ibmvscsis_cmnd *vsc;
> +	int ret;
> +
> +	pr_debug("ibmvscsis: ibmvscsis_queuecommand\n");
> +
> +	vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);

Allocating memory in the command processing path in a SCSI driver 
usually causes suboptimal performance. Other LIO target drivers 
preallocate such buffers before I/O starts.

> +static uint64_t ibmvscsis_unpack_lun(const uint8_t *lun, int len)
> +{
> +	uint64_t res = NO_SUCH_LUN;
> +	int addressing_method;
> +
> +	if (unlikely(len < 2)) {
> +		pr_err("Illegal LUN length %d, expected 2 bytes or more\n",
> +			len);
> +		goto out;
> +	}
> +
> +	switch (len) {
> +	case 8:
> +		if ((*((__be64 *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0)
> +			goto out_err;
> +		break;
> +	case 4:
> +		if (*((__be16 *)&lun[2]) != 0)
> +			goto out_err;
> +		break;
> +	case 6:
> +		if (*((__be32 *)&lun[2]) != 0)
> +			goto out_err;
> +		break;
> +	case 2:
> +		break;
> +	default:
> +		goto out_err;
> +	}
> +
> +	addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */
> +	switch (addressing_method) {
> +	case SCSI_LUN_ADDR_METHOD_PERIPHERAL:
> +	case SCSI_LUN_ADDR_METHOD_FLAT:
> +	case SCSI_LUN_ADDR_METHOD_LUN:
> +		res = *(lun + 1) | (((*lun) & 0x3f) << 8);
> +		break;
> +
> +	case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN:
> +	default:
> +		pr_err("Unimplemented LUN addressing method %u\n",
> +			addressing_method);
> +		break;
> +	}
> +
> +out:
> +	return res;
> +out_err:
> +	pr_err("Support for multi-level LUNs has not yet been implemented\n");
> +	goto out;
> +}

In the above function there is nothing that is specific to the VIO 
mechanism. Please consider to merge this function with scsilun_to_int(), 
e.g. by introducing a new function that accepts a SCSI LUN and the 
addressing method as arguments and by making scsilun_to_int() call that 
function with SCSI_LUN_ADDR_METHOD_PERIPHERAL as one of its arguments.

> +struct inquiry_data {
> +	u8 qual_type;
> +	u8 rmb_reserve;
> +	u8 version;
> +	u8 aerc_naca_hisup_format;
> +	u8 addl_len;
> +	u8 sccs_reserved;
> +	u8 bque_encserv_vs_multip_mchngr_reserved;
> +	u8 reladr_reserved_linked_cmdqueue_vs;
> +	char vendor[8];
> +	char product[16];
> +	char revision[4];
> +	char vendor_specific[20];
> +	char reserved1[2];
> +	char version_descriptor[16];
> +	char reserved2[22];
> +	char unique[158];
> +};

Is this the inquiry data response format from SPC? If so, this is a 
structure definition that is useful for the SCSI initiator core and also 
for other LIO target drivers. There might be a more appropriate header 
file for this definition.

> +enum scsi_lun_addr_method {
> +	SCSI_LUN_ADDR_METHOD_PERIPHERAL   = 0,
> +	SCSI_LUN_ADDR_METHOD_FLAT         = 1,
> +	SCSI_LUN_ADDR_METHOD_LUN          = 2,
> +	SCSI_LUN_ADDR_METHOD_EXTENDED_LUN = 3,
> +};

Same comment here.

> diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
> new file mode 100644
> index 0000000..0e32abd
> --- /dev/null
> +++ b/drivers/scsi/libsrp.c
> @@ -0,0 +1,387 @@
> +/*******************************************************************************
> + * SCSI RDMA Protocol lib functions

My understanding of the VIO mechanism is that the invocation of 
H_COPY_RDMA is synchronous. This means that this operation only finishes 
after the data has been transferred. If I interpret the code in libsrp.c 
and libsrp.h correctly then this code can only be used by SRP drivers 
use synchronous data transfers and not by SRP drivers that use 
asynchronous data transfers. This means that this code is not useful for 
any of the SRP drivers that are already upstream (ib_srp and ib_srpt). 
Hence my proposal to move the libsrp.c and libsrp.h source files from 
drivers/scsi and include/scsi to the same directory as the ibmvscsis driver.

Thanks,

Bart.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
@ 2016-05-24 16:25   ` Bart Van Assche
  0 siblings, 0 replies; 17+ messages in thread
From: Bart Van Assche @ 2016-05-24 16:25 UTC (permalink / raw)
  To: Bryant G. Ly, JBottomley, martin.petersen, tyreld, akpm, kvalo,
	davem, gregkh, mchehab, jslaby, bp
  Cc: linux-kernel, linux-scsi, target-devel, bgly, Joe Perches

On 05/24/2016 06:52 AM, Bryant G. Ly wrote:
> +config SCSI_IBMVSCSIS
> +  	tristate "IBM Virtual SCSI Server support"
> +  	depends on PPC_PSERIES && SCSI_SRP && TARGET_CORE
> +  	help
> +  	  This is the IBM POWER Virtual SCSI Target Server
> +
> +          The userspace component needed to initialize the driver and
> +  	  documentation can be found:
> +
> +          https://github.com/powervm/ibmvscsis
> +
> +          To compile this driver as a module, choose M here: the
> +  	  module will be called ibmvstgt.
> +

This driver has confused Linux users before. Most people know SRP as a 
SCSI transport layer that is used for communication between servers. 
This driver however uses the SRP protocol for communication between 
guests and/or the host that run on the same server. Please add this 
information to the above help text, together with a reference to the VIO 
protocol documentation in the POWER architecture manual.

> +#include <generated/utsrelease.h>

Every Linux user can query the kernel version by running the uname 
command. Is it really useful to print the kernel version (UTS_RELEASE) 
when this driver is loaded?

> +#include "ibmvscsi.h"

The above include directive indirectly includes a whole bunch of SCSI 
initiator driver header files. We do not want that initiator header 
files are included in the source code of a target driver. If it is 
necessary to share definitions of symbolic constants between the 
initiator and the target driver please move these into a new header file.

> +static inline long h_send_crq(struct ibmvscsis_adapter *adapter,
> +			u64 word1, u64 word2)
> +{
> +	long rc;
> +	struct vio_dev *vdev = adapter->dma_dev;
> +
> +	pr_debug("ibmvscsis: ibmvscsis_send_crq(0x%x, 0x%016llx, 0x%016llx)\n",
> +			vdev->unit_address, word1, word2);
> +

As Joe Perches already asked, please define pr_fmt() instead of 
including the kernel module name in every pr_debug() statement.

> +static char system_id[64] = "";
> +static char partition_name[97] = "UNKNOWN";

Where do these magic constants come from and what is their meaning? 
Please consider to introduce symbolic names for these constants.

> +static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item,
> +				char *page)
> +{
> +	struct se_portal_group *se_tpg = to_tpg(item);
> +	struct ibmvscsis_tport *tport = container_of(se_tpg,
> +						struct ibmvscsis_tport, se_tpg);
> +
> +	return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0);
> +}

Have you considered to use MODULE_VERSION() instead of introducing a 
sysfs attribute to export the module version? An advantage of 
MODULE_VERSION() is that it allows to query the module version without 
having to load a kernel module.

> +static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd)
> +{
> +	struct se_device *dev = se_cmd->se_dev;
> +	unsigned char *buf = NULL;
> +	u32 cmd_len = se_cmd->data_length;
> +
> +	if (cmd_len <= INQ_DATA_OFFSET)
> +		return;
> +
> +	buf = transport_kmap_data_sg(se_cmd);
> +	if (buf) {
> +		memcpy(&buf[8], "IBM	     ", 8);
> +		if (dev->transport->get_device_type(dev) == TYPE_ROM)
> +			memcpy(&buf[16], "VOPTA           ", 16);
> +		else
> +			memcpy(&buf[16], "3303      NVDISK", 16);
> +		memcpy(&buf[32], "0001", 4);
> +		transport_kunmap_data_sg(se_cmd);
> +	}
> +}

Shouldn't a sense code be returned to the initiator if this function fails?

> +	default:
> +		pr_err("ibmvscsis: unknown task mgmt func %d\n",
> +						srp_tsk->tsk_mgmt_func);
> +		cmd->se_cmd.se_tmr_req->response =
> +					TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
> +		rc = -1;
> +		break;
> +	}
> +
> +	if (!rc) {

Please consider changing the above "break" into "goto fail" such that 
the if (!rc) can be left out and such that the indentation of the code 
below if (!rc) can be reduced.

> +static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
> +				  struct iu_entry *iue)
> +{
> +	struct srp_cmd *cmd = iue->sbuf->buf;
> +	struct scsi_cmnd *sc;
> +	struct ibmvscsis_cmnd *vsc;
> +	int ret;
> +
> +	pr_debug("ibmvscsis: ibmvscsis_queuecommand\n");
> +
> +	vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);

Allocating memory in the command processing path in a SCSI driver 
usually causes suboptimal performance. Other LIO target drivers 
preallocate such buffers before I/O starts.

> +static uint64_t ibmvscsis_unpack_lun(const uint8_t *lun, int len)
> +{
> +	uint64_t res = NO_SUCH_LUN;
> +	int addressing_method;
> +
> +	if (unlikely(len < 2)) {
> +		pr_err("Illegal LUN length %d, expected 2 bytes or more\n",
> +			len);
> +		goto out;
> +	}
> +
> +	switch (len) {
> +	case 8:
> +		if ((*((__be64 *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0)
> +			goto out_err;
> +		break;
> +	case 4:
> +		if (*((__be16 *)&lun[2]) != 0)
> +			goto out_err;
> +		break;
> +	case 6:
> +		if (*((__be32 *)&lun[2]) != 0)
> +			goto out_err;
> +		break;
> +	case 2:
> +		break;
> +	default:
> +		goto out_err;
> +	}
> +
> +	addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */
> +	switch (addressing_method) {
> +	case SCSI_LUN_ADDR_METHOD_PERIPHERAL:
> +	case SCSI_LUN_ADDR_METHOD_FLAT:
> +	case SCSI_LUN_ADDR_METHOD_LUN:
> +		res = *(lun + 1) | (((*lun) & 0x3f) << 8);
> +		break;
> +
> +	case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN:
> +	default:
> +		pr_err("Unimplemented LUN addressing method %u\n",
> +			addressing_method);
> +		break;
> +	}
> +
> +out:
> +	return res;
> +out_err:
> +	pr_err("Support for multi-level LUNs has not yet been implemented\n");
> +	goto out;
> +}

In the above function there is nothing that is specific to the VIO 
mechanism. Please consider to merge this function with scsilun_to_int(), 
e.g. by introducing a new function that accepts a SCSI LUN and the 
addressing method as arguments and by making scsilun_to_int() call that 
function with SCSI_LUN_ADDR_METHOD_PERIPHERAL as one of its arguments.

> +struct inquiry_data {
> +	u8 qual_type;
> +	u8 rmb_reserve;
> +	u8 version;
> +	u8 aerc_naca_hisup_format;
> +	u8 addl_len;
> +	u8 sccs_reserved;
> +	u8 bque_encserv_vs_multip_mchngr_reserved;
> +	u8 reladr_reserved_linked_cmdqueue_vs;
> +	char vendor[8];
> +	char product[16];
> +	char revision[4];
> +	char vendor_specific[20];
> +	char reserved1[2];
> +	char version_descriptor[16];
> +	char reserved2[22];
> +	char unique[158];
> +};

Is this the inquiry data response format from SPC? If so, this is a 
structure definition that is useful for the SCSI initiator core and also 
for other LIO target drivers. There might be a more appropriate header 
file for this definition.

> +enum scsi_lun_addr_method {
> +	SCSI_LUN_ADDR_METHOD_PERIPHERAL   = 0,
> +	SCSI_LUN_ADDR_METHOD_FLAT         = 1,
> +	SCSI_LUN_ADDR_METHOD_LUN          = 2,
> +	SCSI_LUN_ADDR_METHOD_EXTENDED_LUN = 3,
> +};

Same comment here.

> diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
> new file mode 100644
> index 0000000..0e32abd
> --- /dev/null
> +++ b/drivers/scsi/libsrp.c
> @@ -0,0 +1,387 @@
> +/*******************************************************************************
> + * SCSI RDMA Protocol lib functions

My understanding of the VIO mechanism is that the invocation of 
H_COPY_RDMA is synchronous. This means that this operation only finishes 
after the data has been transferred. If I interpret the code in libsrp.c 
and libsrp.h correctly then this code can only be used by SRP drivers 
use synchronous data transfers and not by SRP drivers that use 
asynchronous data transfers. This means that this code is not useful for 
any of the SRP drivers that are already upstream (ib_srp and ib_srpt). 
Hence my proposal to move the libsrp.c and libsrp.h source files from 
drivers/scsi and include/scsi to the same directory as the ibmvscsis driver.

Thanks,

Bart.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
  2016-05-24 16:25   ` Bart Van Assche
  (?)
@ 2016-05-24 16:34   ` Greg KH
  2016-05-24 16:44     ` Bart Van Assche
  -1 siblings, 1 reply; 17+ messages in thread
From: Greg KH @ 2016-05-24 16:34 UTC (permalink / raw)
  To: Bart Van Assche
  Cc: Bryant G. Ly, JBottomley, martin.petersen, tyreld, akpm, kvalo,
	davem, mchehab, jslaby, joe, bp, linux-kernel, linux-scsi,
	target-devel, bgly

On Tue, May 24, 2016 at 09:25:05AM -0700, Bart Van Assche wrote:
> > +static inline long h_send_crq(struct ibmvscsis_adapter *adapter,
> > +			u64 word1, u64 word2)
> > +{
> > +	long rc;
> > +	struct vio_dev *vdev = adapter->dma_dev;
> > +
> > +	pr_debug("ibmvscsis: ibmvscsis_send_crq(0x%x, 0x%016llx, 0x%016llx)\n",
> > +			vdev->unit_address, word1, word2);
> > +
> 
> As Joe Perches already asked, please define pr_fmt() instead of including
> the kernel module name in every pr_debug() statement.

Even better, as this is a driver, it should be using dev_*() calls
instead of pr_*() calls to properly identify the device and driver that
is making the message.  No driver should be using pr_*() except in
_very_ limited usages.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
  2016-05-24 16:34   ` Greg KH
@ 2016-05-24 16:44     ` Bart Van Assche
  2016-05-24 16:50       ` Greg KH
  0 siblings, 1 reply; 17+ messages in thread
From: Bart Van Assche @ 2016-05-24 16:44 UTC (permalink / raw)
  To: Greg KH
  Cc: Bryant G. Ly, JBottomley, martin.petersen, tyreld, akpm, kvalo,
	davem, mchehab, jslaby, joe, bp, linux-kernel, linux-scsi,
	target-devel, bgly

On 05/24/2016 09:34 AM, Greg KH wrote:
> On Tue, May 24, 2016 at 09:25:05AM -0700, Bart Van Assche wrote:
>>> +static inline long h_send_crq(struct ibmvscsis_adapter *adapter,
>>> +			u64 word1, u64 word2)
>>> +{
>>> +	long rc;
>>> +	struct vio_dev *vdev = adapter->dma_dev;
>>> +
>>> +	pr_debug("ibmvscsis: ibmvscsis_send_crq(0x%x, 0x%016llx, 0x%016llx)\n",
>>> +			vdev->unit_address, word1, word2);
>>> +
>>
>> As Joe Perches already asked, please define pr_fmt() instead of including
>> the kernel module name in every pr_debug() statement.
>
> Even better, as this is a driver, it should be using dev_*() calls
> instead of pr_*() calls to properly identify the device and driver that
> is making the message.  No driver should be using pr_*() except in
> _very_ limited usages.

Hi Greg,

The reason I recommended pr_debug() is because ibmvscsis is a LIO target 
driver and I don't think a struct device is associated with a LIO target 
driver. See e.g. target_register_template() in 
drivers/target/target_core_configfs.c.

Bart.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
  2016-05-24 16:44     ` Bart Van Assche
@ 2016-05-24 16:50       ` Greg KH
  0 siblings, 0 replies; 17+ messages in thread
From: Greg KH @ 2016-05-24 16:50 UTC (permalink / raw)
  To: Bart Van Assche
  Cc: Bryant G. Ly, JBottomley, martin.petersen, tyreld, akpm, kvalo,
	davem, mchehab, jslaby, joe, bp, linux-kernel, linux-scsi,
	target-devel, bgly

On Tue, May 24, 2016 at 09:44:43AM -0700, Bart Van Assche wrote:
> On 05/24/2016 09:34 AM, Greg KH wrote:
> > On Tue, May 24, 2016 at 09:25:05AM -0700, Bart Van Assche wrote:
> > > > +static inline long h_send_crq(struct ibmvscsis_adapter *adapter,
> > > > +			u64 word1, u64 word2)
> > > > +{
> > > > +	long rc;
> > > > +	struct vio_dev *vdev = adapter->dma_dev;
> > > > +
> > > > +	pr_debug("ibmvscsis: ibmvscsis_send_crq(0x%x, 0x%016llx, 0x%016llx)\n",
> > > > +			vdev->unit_address, word1, word2);
> > > > +
> > > 
> > > As Joe Perches already asked, please define pr_fmt() instead of including
> > > the kernel module name in every pr_debug() statement.
> > 
> > Even better, as this is a driver, it should be using dev_*() calls
> > instead of pr_*() calls to properly identify the device and driver that
> > is making the message.  No driver should be using pr_*() except in
> > _very_ limited usages.
> 
> Hi Greg,
> 
> The reason I recommended pr_debug() is because ibmvscsis is a LIO target
> driver and I don't think a struct device is associated with a LIO target
> driver. See e.g. target_register_template() in
> drivers/target/target_core_configfs.c.

That seems messed up, there should be a struct device somewhere to
use...

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
  2016-05-24 16:25   ` Bart Van Assche
  (?)
  (?)
@ 2016-05-24 20:00   ` Bryant G Ly
  2016-06-10 19:03       ` Bart Van Assche
  -1 siblings, 1 reply; 17+ messages in thread
From: Bryant G Ly @ 2016-05-24 20:00 UTC (permalink / raw)
  To: Bart Van Assche
  Cc: JBottomley, martin.petersen, tyreld, akpm, kvalo, davem, gregkh,
	mchehab, jslaby, joe, bp, linux-kernel, linux-scsi, target-devel,
	bgly


Quoting Bart Van Assche <bart.vanassche@sandisk.com>:

> On 05/24/2016 06:52 AM, Bryant G. Ly wrote:
>> +config SCSI_IBMVSCSIS
>> +  	tristate "IBM Virtual SCSI Server support"
>> +  	depends on PPC_PSERIES && SCSI_SRP && TARGET_CORE
>> +  	help
>> +  	  This is the IBM POWER Virtual SCSI Target Server
>> +
>> +          The userspace component needed to initialize the driver and
>> +  	  documentation can be found:
>> +
>> +          https://github.com/powervm/ibmvscsis
>> +
>> +          To compile this driver as a module, choose M here: the
>> +  	  module will be called ibmvstgt.
>> +
>
> This driver has confused Linux users before. Most people know SRP as  
> a SCSI transport layer that is used for communication between  
> servers. This driver however uses the SRP protocol for communication  
> between guests and/or the host that run on the same server. Please  
> add this information to the above help text, together with a  
> reference to the VIO protocol documentation in the POWER  
> architecture manual.
>

Done

>> +#include <generated/utsrelease.h>
>
> Every Linux user can query the kernel version by running the uname  
> command. Is it really useful to print the kernel version  
> (UTS_RELEASE) when this driver is loaded?
>

Done

>> +#include "ibmvscsi.h"
>
> The above include directive indirectly includes a whole bunch of  
> SCSI initiator driver header files. We do not want that initiator  
> header files are included in the source code of a target driver. If  
> it is necessary to share definitions of symbolic constants between  
> the initiator and the target driver please move these into a new  
> header file.
>

Done

>> +static inline long h_send_crq(struct ibmvscsis_adapter *adapter,
>> +			u64 word1, u64 word2)
>> +{
>> +	long rc;
>> +	struct vio_dev *vdev = adapter->dma_dev;
>> +
>> +	pr_debug("ibmvscsis: ibmvscsis_send_crq(0x%x, 0x%016llx, 0x%016llx)\n",
>> +			vdev->unit_address, word1, word2);
>> +
>
> As Joe Perches already asked, please define pr_fmt() instead of  
> including the kernel module name in every pr_debug() statement.
>

Done

>> +static char system_id[64] = "";
>> +static char partition_name[97] = "UNKNOWN";
>
> Where do these magic constants come from and what is their meaning?  
> Please consider to introduce symbolic names for these constants.
>

Done

>> +static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item,
>> +				char *page)
>> +{
>> +	struct se_portal_group *se_tpg = to_tpg(item);
>> +	struct ibmvscsis_tport *tport = container_of(se_tpg,
>> +						struct ibmvscsis_tport, se_tpg);
>> +
>> +	return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0);
>> +}
>
> Have you considered to use MODULE_VERSION() instead of introducing a  
> sysfs attribute to export the module version? An advantage of  
> MODULE_VERSION() is that it allows to query the module version  
> without having to load a kernel module.
>

Done

>> +static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd)
>> +{
>> +	struct se_device *dev = se_cmd->se_dev;
>> +	unsigned char *buf = NULL;
>> +	u32 cmd_len = se_cmd->data_length;
>> +
>> +	if (cmd_len <= INQ_DATA_OFFSET)
>> +		return;
>> +
>> +	buf = transport_kmap_data_sg(se_cmd);
>> +	if (buf) {
>> +		memcpy(&buf[8], "IBM	     ", 8);
>> +		if (dev->transport->get_device_type(dev) == TYPE_ROM)
>> +			memcpy(&buf[16], "VOPTA           ", 16);
>> +		else
>> +			memcpy(&buf[16], "3303      NVDISK", 16);
>> +		memcpy(&buf[32], "0001", 4);
>> +		transport_kunmap_data_sg(se_cmd);
>> +	}
>> +}
>
> Shouldn't a sense code be returned to the initiator if this function fails?
>

This function never fails? Also this is a temporary function that will go away
soon. It's to address AIX not recognizing target emulation of inquiry, but
we have already discussed internally to add these ODM entries into AIX.

>> +	default:
>> +		pr_err("ibmvscsis: unknown task mgmt func %d\n",
>> +						srp_tsk->tsk_mgmt_func);
>> +		cmd->se_cmd.se_tmr_req->response =
>> +					TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
>> +		rc = -1;
>> +		break;
>> +	}
>> +
>> +	if (!rc) {
>
> Please consider changing the above "break" into "goto fail" such  
> that the if (!rc) can be left out and such that the indentation of  
> the code below if (!rc) can be reduced.
>

Done

>> +static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
>> +				  struct iu_entry *iue)
>> +{
>> +	struct srp_cmd *cmd = iue->sbuf->buf;
>> +	struct scsi_cmnd *sc;
>> +	struct ibmvscsis_cmnd *vsc;
>> +	int ret;
>> +
>> +	pr_debug("ibmvscsis: ibmvscsis_queuecommand\n");
>> +
>> +	vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);
>
> Allocating memory in the command processing path in a SCSI driver  
> usually causes suboptimal performance. Other LIO target drivers  
> preallocate such buffers before I/O starts.
>

We have a version of this driver that uses preallocation of the buffers.
It's not currently being pushed up for review because it was written by
referencing the internal VIOS VSCSI driver. Once our lawyers have approved
the open-sourcing of the internal driver we will push up patches to address
this issue and add a lot more features.

>> +static uint64_t ibmvscsis_unpack_lun(const uint8_t *lun, int len)
>> +{
>> +	uint64_t res = NO_SUCH_LUN;
>> +	int addressing_method;
>> +
>> +	if (unlikely(len < 2)) {
>> +		pr_err("Illegal LUN length %d, expected 2 bytes or more\n",
>> +			len);
>> +		goto out;
>> +	}
>> +
>> +	switch (len) {
>> +	case 8:
>> +		if ((*((__be64 *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0)
>> +			goto out_err;
>> +		break;
>> +	case 4:
>> +		if (*((__be16 *)&lun[2]) != 0)
>> +			goto out_err;
>> +		break;
>> +	case 6:
>> +		if (*((__be32 *)&lun[2]) != 0)
>> +			goto out_err;
>> +		break;
>> +	case 2:
>> +		break;
>> +	default:
>> +		goto out_err;
>> +	}
>> +
>> +	addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */
>> +	switch (addressing_method) {
>> +	case SCSI_LUN_ADDR_METHOD_PERIPHERAL:
>> +	case SCSI_LUN_ADDR_METHOD_FLAT:
>> +	case SCSI_LUN_ADDR_METHOD_LUN:
>> +		res = *(lun + 1) | (((*lun) & 0x3f) << 8);
>> +		break;
>> +
>> +	case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN:
>> +	default:
>> +		pr_err("Unimplemented LUN addressing method %u\n",
>> +			addressing_method);
>> +		break;
>> +	}
>> +
>> +out:
>> +	return res;
>> +out_err:
>> +	pr_err("Support for multi-level LUNs has not yet been implemented\n");
>> +	goto out;
>> +}
>
> In the above function there is nothing that is specific to the VIO  
> mechanism. Please consider to merge this function with  
> scsilun_to_int(), e.g. by introducing a new function that accepts a  
> SCSI LUN and the addressing method as arguments and by making  
> scsilun_to_int() call that function with  
> SCSI_LUN_ADDR_METHOD_PERIPHERAL as one of its arguments.
>

We are going to keep this here atm, until we can make sure canonical  
can pick up
these changes, since we have a deliverable for a 3rd party vendor who  
is going to
fully utilize this driver. Once they can pick it up in 4.4 kernel I  
will make the
change you recommended / move the scsi_lun_addr_method addressed  
below. I will also
address the changes that ib_srpt needs to utilize this new function too.

>> +struct inquiry_data {
>> +	u8 qual_type;
>> +	u8 rmb_reserve;
>> +	u8 version;
>> +	u8 aerc_naca_hisup_format;
>> +	u8 addl_len;
>> +	u8 sccs_reserved;
>> +	u8 bque_encserv_vs_multip_mchngr_reserved;
>> +	u8 reladr_reserved_linked_cmdqueue_vs;
>> +	char vendor[8];
>> +	char product[16];
>> +	char revision[4];
>> +	char vendor_specific[20];
>> +	char reserved1[2];
>> +	char version_descriptor[16];
>> +	char reserved2[22];
>> +	char unique[158];
>> +};
>
> Is this the inquiry data response format from SPC? If so, this is a  
> structure definition that is useful for the SCSI initiator core and  
> also for other LIO target drivers. There might be a more appropriate  
> header file for this definition.
>

It is from the SPC, but it was already defined. So I removed this and
my driver wasn't using it atm anyways.

>> +enum scsi_lun_addr_method {
>> +	SCSI_LUN_ADDR_METHOD_PERIPHERAL   = 0,
>> +	SCSI_LUN_ADDR_METHOD_FLAT         = 1,
>> +	SCSI_LUN_ADDR_METHOD_LUN          = 2,
>> +	SCSI_LUN_ADDR_METHOD_EXTENDED_LUN = 3,
>> +};
>
> Same comment here.
>
Comment from above.

>> diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
>> new file mode 100644
>> index 0000000..0e32abd
>> --- /dev/null
>> +++ b/drivers/scsi/libsrp.c
>> @@ -0,0 +1,387 @@
>> +/*******************************************************************************
>> + * SCSI RDMA Protocol lib functions
>
> My understanding of the VIO mechanism is that the invocation of  
> H_COPY_RDMA is synchronous. This means that this operation only  
> finishes after the data has been transferred. If I interpret the  
> code in libsrp.c and libsrp.h correctly then this code can only be  
> used by SRP drivers use synchronous data transfers and not by SRP  
> drivers that use asynchronous data transfers. This means that this  
> code is not useful for any of the SRP drivers that are already  
> upstream (ib_srp and ib_srpt). Hence my proposal to move the  
> libsrp.c and libsrp.h source files from drivers/scsi and  
> include/scsi to the same directory as the ibmvscsis driver.
>
Done

Thanks for the reviews thus far, I apologize for some of the styling  
problems that
Joe had pointed out. I didn't run --strict against the patch and had  
missed a lot of
stuff. It's also my first time working with the Linux community, so I  
apologize.

-Bryant

^ permalink raw reply	[flat|nested] 17+ messages in thread

* IBM VSCSI Target Driver Initial Patch Sets
  2016-05-24 13:52 [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver Bryant G. Ly
                   ` (2 preceding siblings ...)
  2016-05-24 16:25   ` Bart Van Assche
@ 2016-05-25 14:17 ` Bryant G. Ly
  2016-05-25 14:17   ` [PATCH 2/3] ibmvscsis: Addressing Bart's comments Bryant G. Ly
  2016-05-25 14:17   ` [PATCH 3/3] ibmvscsis: clean up functions Bryant G. Ly
  3 siblings, 2 replies; 17+ messages in thread
From: Bryant G. Ly @ 2016-05-25 14:17 UTC (permalink / raw)
  To: tyreld, bart.vanassche, joe
  Cc: martin.petersen, akpm, kvalo, davem, mchehab, jslaby, bp,
	linux-kernel, linux-scsi, target-devel

This patch series addresses comments by Joe with runing checkpatch with a
--strict. It cleans up all the misc styling and removes all the forward
declarations.

The patch also addresses all of Bart's comments besides the preallocation of
buffers before IO starts and the merging of unpack_lun with scsiluntoint.
Those will come in later patch sets.

[PATCH 2/3] ibmvscsis: Addressing Bart's comments
[PATCH 3/3] ibmvscsis: clean up functions

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 2/3] ibmvscsis: Addressing Bart's comments
  2016-05-25 14:17 ` IBM VSCSI Target Driver Initial Patch Sets Bryant G. Ly
@ 2016-05-25 14:17   ` Bryant G. Ly
  2016-05-25 14:17   ` [PATCH 3/3] ibmvscsis: clean up functions Bryant G. Ly
  1 sibling, 0 replies; 17+ messages in thread
From: Bryant G. Ly @ 2016-05-25 14:17 UTC (permalink / raw)
  To: tyreld, bart.vanassche, joe
  Cc: martin.petersen, akpm, kvalo, davem, mchehab, jslaby, bp,
	linux-kernel, linux-scsi, target-devel, bryantly

From: bryantly <bryantly@linux.vnet.ibm.com>

This patch contains cleaning up the code for styling and also addresses Bart's comments.

Signed-off-by: bryantly <bryantly@linux.vnet.ibm.com>
---
 MAINTAINERS                       |   4 +-
 drivers/scsi/Kconfig              |  36 +--
 drivers/scsi/Makefile             |   4 +-
 drivers/scsi/ibmvscsi/Makefile    |   3 +-
 drivers/scsi/ibmvscsi/ibmvscsis.c | 450 ++++++++++++++++++--------------------
 drivers/scsi/ibmvscsi/ibmvscsis.h |  40 ++--
 drivers/scsi/ibmvscsi/libsrp.c    | 386 ++++++++++++++++++++++++++++++++
 drivers/scsi/ibmvscsi/libsrp.h    |  91 ++++++++
 drivers/scsi/libsrp.c             | 387 --------------------------------
 include/scsi/libsrp.h             |  95 --------
 10 files changed, 737 insertions(+), 759 deletions(-)
 create mode 100644 drivers/scsi/ibmvscsi/libsrp.c
 create mode 100644 drivers/scsi/ibmvscsi/libsrp.h
 delete mode 100644 drivers/scsi/libsrp.c
 delete mode 100644 include/scsi/libsrp.h

diff --git a/MAINTAINERS b/MAINTAINERS
index b520e6c..a11905c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5387,9 +5387,9 @@ L:	linux-scsi@vger.kernel.org
 L:	target-devel@vger.kernel.org
 S:	Supported
 F:	drivers/scsi/ibmvscsi/ibmvscsis.c
-F:      drivers/scsi/ibmvscsi/ibmvscsis.h
+F:	drivers/scsi/ibmvscsi/ibmvscsis.h
 F:	drivers/scsi/libsrp.h
-F:      drivers/scsi/libsrp.c
+F:	drivers/scsi/libsrp.c
 
 IBM Power Virtual FC Device Drivers
 M:	Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 6adf8f1..1221f6b 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -848,18 +848,21 @@ config SCSI_IBMVSCSI
 	  module will be called ibmvscsi.
 
 config SCSI_IBMVSCSIS
-  	tristate "IBM Virtual SCSI Server support"
-  	depends on PPC_PSERIES && SCSI_SRP && TARGET_CORE
-  	help
-  	  This is the IBM POWER Virtual SCSI Target Server
+	tristate "IBM Virtual SCSI Server support"
+	depends on PPC_PSERIES && SCSI_SRP && TARGET_CORE
+	help
+	  This is the IBM POWER Virtual SCSI Target Server
+	  This driver uses the SRP protocol for communication betwen servers
+	  guest and/or the host that run on the same server.
+	  More information on VSCSI protocol can be found at www.power.org
 
-          The userspace component needed to initialize the driver and
-  	  documentation can be found:
+	  The userspace component needed to initialize the driver and
+	  documentation can be found:
 
-          https://github.com/powervm/ibmvscsis
+	  https://github.com/powervm/ibmvscsis
 
-          To compile this driver as a module, choose M here: the
-  	  module will be called ibmvstgt.
+	  To compile this driver as a module, choose M here: the
+	  module will be called ibmvstgt.
 
 config SCSI_IBMVFC
 	tristate "IBM Virtual FC support"
@@ -1743,14 +1746,17 @@ config SCSI_PM8001
 	  based host adapters.
 
 config SCSI_SRP
-  	tristate "SCSI RDMA Protocol helper library"
-  	depends on SCSI && PCI
-  	help
-  	  This scsi srp module is a library for ibmvscsi target driver.
+	tristate "SCSI RDMA Protocol helper library"
+	depends on SCSI && PCI
+	help
+	  This SCSI SRP module is a library for ibmvscsi target driver.
+	  This module can only be used by SRP drivers that utilize synchronous
+	  data transfers and not by SRP drivers that use asynchronous.
+
 	  If you wish to use SRP target drivers, say Y.
 
-  	  To compile this driver as a module, choose M here. The module will
-  	  be called libsrp.
+	  To compile this driver as a module, choose M here. The module will
+	  be called libsrp.
 
 config SCSI_BFA_FC
 	tristate "Brocade BFA Fibre Channel Support"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 8692dd4..9dfa4da 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -127,9 +127,9 @@ obj-$(CONFIG_SCSI_LASI700)	+= 53c700.o lasi700.o
 obj-$(CONFIG_SCSI_SNI_53C710)	+= 53c700.o sni_53c710.o
 obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
 obj-$(CONFIG_SCSI_IPR)		+= ipr.o
-obj-$(CONFIG_SCSI_SRP)          += libsrp.o
+obj-$(CONFIG_SCSI_SRP)		+= ibmvscsi/
 obj-$(CONFIG_SCSI_IBMVSCSI)	+= ibmvscsi/
-obj-$(CONFIG_SCSI_IBMVSCSIS)    += ibmvscsi/
+obj-$(CONFIG_SCSI_IBMVSCSIS)	+= ibmvscsi/
 obj-$(CONFIG_SCSI_IBMVFC)	+= ibmvscsi/
 obj-$(CONFIG_SCSI_HPTIOP)	+= hptiop.o
 obj-$(CONFIG_SCSI_STEX)		+= stex.o
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
index b241a567..e7a1663 100644
--- a/drivers/scsi/ibmvscsi/Makefile
+++ b/drivers/scsi/ibmvscsi/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_SCSI_IBMVSCSI)	+= ibmvscsi.o
-obj-$(CONFIG_SCSI_IBMVSCSIS)    += ibmvscsis.o
+obj-$(CONFIG_SCSI_IBMVSCSIS)	+= ibmvscsis.o
 obj-$(CONFIG_SCSI_IBMVFC)	+= ibmvfc.o
+obj-$(CONFIG_SCSI_SRP)          += libsrp.o
diff --git a/drivers/scsi/ibmvscsi/ibmvscsis.c b/drivers/scsi/ibmvscsi/ibmvscsis.c
index c7eb347..6f9e9ba 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsis.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsis.c
@@ -22,13 +22,14 @@
  *
  ****************************************************************************/
 
+#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/kthread.h>
 #include <linux/types.h>
 #include <linux/list.h>
-#include <linux/types.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/utsname.h>
@@ -38,8 +39,6 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_tcq.h>
-#include <scsi/libsrp.h>
-#include <generated/utsrelease.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
@@ -50,16 +49,16 @@
 #include <asm/prom.h>
 #include <asm/vio.h>
 
-#include "ibmvscsi.h"
 #include "ibmvscsis.h"
 #include "viosrp.h"
+#include "libsrp.h"
 
 #define IBMVSCSIS_VERSION	"v0.1"
 
 #define	INITIAL_SRP_LIMIT	15
 #define	DEFAULT_MAX_SECTORS	256
 
-#define MAX_H_COPY_RDMA		(128*1024)
+#define MAX_H_COPY_RDMA		(128 * 1024)
 
 #define SRP_RSP_SENSE_DATA_LEN	18
 
@@ -75,7 +74,7 @@ static void ibmvscsis_dev_release(struct device *dev);
 static void ibmvscsis_modify_rep_luns(struct se_cmd *se_cmd);
 static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd);
 static int read_dma_window(struct vio_dev *vdev,
-				struct ibmvscsis_adapter *adapter);
+			   struct ibmvscsis_adapter *adapter);
 static char *ibmvscsis_get_fabric_name(void);
 static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg);
 static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg);
@@ -137,7 +136,7 @@ static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg,
 			  enum dma_data_direction dir, unsigned int rest);
 static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
 				  struct iu_entry *iue);
-static uint64_t ibmvscsis_unpack_lun(const uint8_t *lun, int len);
+static u64 ibmvscsis_unpack_lun(const u8 *lun, int len);
 static int tcm_queuecommand(struct ibmvscsis_adapter *adapter,
 			    struct ibmvscsis_cmnd *vsc,
 			    struct srp_cmd *scmd);
@@ -146,7 +145,7 @@ static void ibmvscsis_determine_resid(struct se_cmd *se_cmd,
 static bool connection_broken(struct ibmvscsis_adapter *adapter);
 
 static inline long h_copy_rdma(s64 length, u64 sliobn, u64 slioba,
-	u64 dliobn, u64 dlioba)
+			       u64 dliobn, u64 dlioba)
 {
 	long rc = 0;
 
@@ -154,11 +153,11 @@ static inline long h_copy_rdma(s64 length, u64 sliobn, u64 slioba,
 	mb();
 
 	rc = plpar_hcall_norets(H_COPY_RDMA, length, sliobn, slioba,
-			dliobn, dlioba);
+				dliobn, dlioba);
 	return rc;
 }
 
-static inline void h_free_crq(uint32_t unit_address)
+static inline void h_free_crq(u32 unit_address)
 {
 	long rc = 0;
 
@@ -171,13 +170,13 @@ static inline void h_free_crq(uint32_t unit_address)
 }
 
 static inline long h_send_crq(struct ibmvscsis_adapter *adapter,
-			u64 word1, u64 word2)
+			      u64 word1, u64 word2)
 {
 	long rc;
 	struct vio_dev *vdev = adapter->dma_dev;
 
-	pr_debug("ibmvscsis: ibmvscsis_send_crq(0x%x, 0x%016llx, 0x%016llx)\n",
-			vdev->unit_address, word1, word2);
+	pr_debug("ibmvscsis_send_crq(0x%x, 0x%016llx, 0x%016llx)\n",
+		 vdev->unit_address, word1, word2);
 
 	/*
 	 * Ensure the command buffer is flushed to memory before handing it
@@ -185,7 +184,7 @@ static inline long h_send_crq(struct ibmvscsis_adapter *adapter,
 	 */
 	mb();
 	rc = plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2);
-	pr_debug("ibmvscsis: ibmvcsis_send_crq rc = 0x%lx\n", rc);
+	pr_debug("ibmvcsis_send_crq rc = 0x%lx\n", rc);
 
 	return rc;
 }
@@ -195,8 +194,8 @@ static inline long h_send_crq(struct ibmvscsis_adapter *adapter,
 /*****************************************************************************/
 
 static const char ibmvscsis_driver_name[] = "ibmvscsis";
-static char system_id[64] = "";
-static char partition_name[97] = "UNKNOWN";
+static char system_id[SYS_ID_NAME_LEN] = "";
+static char partition_name[PARTITION_NAMELEN] = "UNKNOWN";
 static unsigned int partition_number = -1;
 
 static struct class_attribute ibmvscsis_class_attrs[] = {
@@ -227,11 +226,9 @@ static struct class ibmvscsis_class = {
 };
 
 static ssize_t ibmvscsis_wwn_version_show(struct config_item *item,
-					       char *page)
+					  char *page)
 {
-	return sprintf(page, "IBMVSCSIS fabric %s on %s/%s on "UTS_RELEASE"\n",
-		       IBMVSCSIS_VERSION, utsname()->sysname,
-		       utsname()->machine);
+	return scnprintf(page, PAGE_SIZE, "%s\n", IBMVSCSIS_VERSION);
 }
 CONFIGFS_ATTR_RO(ibmvscsis_wwn_, version);
 
@@ -241,21 +238,23 @@ static struct configfs_attribute *ibmvscsis_wwn_attrs[] = {
 };
 
 static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item,
-				char *page)
+					 char *page)
 {
 	struct se_portal_group *se_tpg = to_tpg(item);
 	struct ibmvscsis_tport *tport = container_of(se_tpg,
-						struct ibmvscsis_tport, se_tpg);
+						     struct ibmvscsis_tport,
+						     se_tpg);
 
 	return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0);
 }
 
 static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item,
-		const char *page, size_t count)
+					  const char *page, size_t count)
 {
 	struct se_portal_group *se_tpg = to_tpg(item);
 	struct ibmvscsis_tport *tport = container_of(se_tpg,
-						struct ibmvscsis_tport, se_tpg);
+						     struct ibmvscsis_tport,
+						     se_tpg);
 	unsigned long tmp;
 	int ret;
 
@@ -267,7 +266,7 @@ static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item,
 
 	if ((tmp != 0) && (tmp != 1)) {
 		pr_err("Illegal value for ibmvscsis_tpg_store_enable: %lu\n",
-			tmp);
+		       tmp);
 		return -EINVAL;
 	}
 
@@ -320,7 +319,7 @@ static const struct target_core_fabric_ops ibmvscsis_ops = {
 	.fabric_drop_tpg		= ibmvscsis_drop_tpg,
 
 	.tfc_wwn_attrs			= ibmvscsis_wwn_attrs,
-	.tfc_tpg_base_attrs             = ibmvscsis_tpg_attrs,
+	.tfc_tpg_base_attrs		= ibmvscsis_tpg_attrs,
 };
 
 static struct vio_device_id ibmvscsis_device_table[] = {
@@ -340,7 +339,7 @@ static struct vio_driver ibmvscsis_driver = {
 /* End of global device driver data areas                                    */
 /*****************************************************************************/
 static int crq_queue_create(struct crq_queue *queue,
-				struct ibmvscsis_adapter *adapter)
+			    struct ibmvscsis_adapter *adapter)
 {
 	int retrc;
 	int err;
@@ -360,8 +359,9 @@ static int crq_queue_create(struct crq_queue *queue,
 	if (dma_mapping_error(&vdev->dev, queue->msg_token))
 		goto map_failed;
 
-	retrc = err = h_reg_crq(vdev->unit_address, queue->msg_token,
+	err = h_reg_crq(vdev->unit_address, queue->msg_token,
 			PAGE_SIZE);
+	retrc = err;
 
 	/* If the adapter was left active for some reason (like kexec)
 	 * try freeing and re-registering
@@ -369,10 +369,10 @@ static int crq_queue_create(struct crq_queue *queue,
 	if (err == H_RESOURCE)
 		err = ibmvscsis_reset_crq_queue(adapter);
 	if (err == 2) {
-		pr_warn("ibmvscsis: Partner adapter not ready\n");
+		pr_warn("Partner adapter not ready\n");
 		retrc = 0;
 	} else if (err != 0) {
-		pr_err("ibmvscsis: Error 0x%x opening virtual adapter\n", err);
+		pr_err("Error 0x%x opening virtual adapter\n", err);
 		goto reg_crq_failed;
 	}
 
@@ -384,13 +384,13 @@ static int crq_queue_create(struct crq_queue *queue,
 	err = request_irq(vdev->irq, &ibmvscsis_interrupt,
 			  0, "ibmvscsis", adapter);
 	if (err) {
-		pr_err("ibmvscsis: Error 0x%x h_send_crq\n", err);
+		pr_err("Error 0x%x h_send_crq\n", err);
 		goto req_irq_failed;
 	}
 
 	err = vio_enable_interrupts(vdev);
 	if (err != 0) {
-		pr_err("ibmvscsis: Error %d enabling interrupts!!!\n", err);
+		pr_err("Error %d enabling interrupts!!!\n", err);
 		goto req_irq_failed;
 	}
 
@@ -402,18 +402,11 @@ reg_crq_failed:
 	dma_unmap_single(&vdev->dev, queue->msg_token,
 			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
 map_failed:
-	free_page((unsigned long) queue->msgs);
+	free_page((unsigned long)queue->msgs);
 malloc_failed:
 	return -1;
 }
 
-/*
- * ibmvscsis_probe - ibm vscsis target initialize entry point
- * @param  dev vio device struct
- * @param  id  vio device id struct
- * @return	0 - Success
- *		Non-zero - Failure
- */
 static int ibmvscsis_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 {
 	int ret = -ENOMEM;
@@ -422,12 +415,12 @@ static int ibmvscsis_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 	struct ibmvscsis_tport *tport;
 	unsigned long flags;
 
-	pr_debug("ibmvscsis: Probe for UA 0x%x\n", vdev->unit_address);
+	pr_debug("Probe for UA 0x%x\n", vdev->unit_address);
 
-	adapter = kzalloc(sizeof(struct ibmvscsis_adapter), GFP_KERNEL);
+	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
 	if (!adapter)
 		return ret;
-	target = kzalloc(sizeof(struct srp_target), GFP_KERNEL);
+	target = kzalloc(sizeof(*target), GFP_KERNEL);
 	if (!target)
 		goto free_adapter;
 
@@ -443,33 +436,33 @@ static int ibmvscsis_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 	if (ret != 0)
 		goto free_target;
 
-	pr_debug("ibmvscsis: Probe: liobn 0x%x, riobn 0x%x\n", adapter->liobn,
-			adapter->riobn);
+	pr_debug("Probe: liobn 0x%x, riobn 0x%x\n", adapter->liobn,
+		 adapter->riobn);
 
 	spin_lock_irqsave(&ibmvscsis_dev_lock, flags);
 	list_add_tail(&adapter->list, &ibmvscsis_dev_list);
 	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
 
 	ret = srp_target_alloc(target, &vdev->dev,
-				INITIAL_SRP_LIMIT,
-				SRP_MAX_IU_LEN);
+			       INITIAL_SRP_LIMIT,
+			       SRP_MAX_IU_LEN);
 
 	adapter->target->ldata = adapter;
 
 	if (ret) {
-		pr_err("ibmvscsis: failed target alloc ret: %d\n", ret);
+		pr_err("failed target alloc ret: %d\n", ret);
 		goto free_srp_target;
 	}
 
 	ret = crq_queue_create(&adapter->crq_queue, adapter);
 	if (ret != 0 && ret != H_RESOURCE) {
-		pr_err("ibmvscsis: failed crq_queue_create ret: %d\n", ret);
+		pr_err("failed crq_queue_create ret: %d\n", ret);
 		ret = -1;
 	}
 
-	if (h_send_crq(adapter, 0xC001000000000000LL, 0) != 0
-			&& ret != H_RESOURCE) {
-		pr_warn("ibmvscsis: Failed to send CRQ message\n");
+	if (h_send_crq(adapter, 0xC001000000000000LL, 0) != 0 &&
+	    ret != H_RESOURCE) {
+		pr_warn("Failed to send CRQ message\n");
 		ret = 0;
 	}
 
@@ -520,8 +513,8 @@ static void ibmvscsis_modify_rep_luns(struct se_cmd *se_cmd)
 	buf = transport_kmap_data_sg(se_cmd);
 	if (buf) {
 		data_len = be32_to_cpu(*(u32 *)buf);
-		pr_debug("ibmvscsis: modify_rep_luns: len %d data_len %hud\n",
-			len, data_len);
+		pr_debug("modify_rep_luns: len %d data_len %hud\n",
+			 len, data_len);
 		if (data_len < len)
 			len = data_len;
 		buf += 8;
@@ -534,6 +527,12 @@ static void ibmvscsis_modify_rep_luns(struct se_cmd *se_cmd)
 	}
 }
 
+/*
+ * This function modifies the inquiry data prior to sending to initiator
+ * so that we can make support current AIX. Internally we are going to
+ * add new ODM entries to support the emulation from LIO. This function
+ * is temporary until those changes are done.
+ */
 static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd)
 {
 	struct se_device *dev = se_cmd->se_dev;
@@ -556,7 +555,7 @@ static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd)
 }
 
 static int read_dma_window(struct vio_dev *vdev,
-				struct ibmvscsis_adapter *adapter)
+			   struct ibmvscsis_adapter *adapter)
 {
 	const __be32 *dma_window;
 	const __be32 *prop;
@@ -567,9 +566,9 @@ static int read_dma_window(struct vio_dev *vdev,
 	 */
 	dma_window =
 		(const __be32 *)vio_get_attribute(vdev, "ibm,my-dma-window",
-						NULL);
+						  NULL);
 	if (!dma_window) {
-		pr_err("ibmvscsis: Couldn't find ibm,my-dma-window property\n");
+		pr_err("Couldn't find ibm,my-dma-window property\n");
 		return -1;
 	}
 
@@ -577,20 +576,22 @@ static int read_dma_window(struct vio_dev *vdev,
 	dma_window++;
 
 	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells",
-						NULL);
+						 NULL);
 	if (!prop) {
-		pr_warn("ibmvscsis: Couldn't find ibm, #dma-address-cells property\n");
+		pr_warn("Couldn't find ibm, #dma-address-cells property\n");
 		dma_window++;
-	} else
+	} else {
 		dma_window += be32_to_cpu(*prop);
+	}
 
 	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells",
-						NULL);
+						 NULL);
 	if (!prop) {
-		pr_warn("ibmvscsis: Couldn't find ibm, #dma-size-cells property\n");
+		pr_warn("Couldn't find ibm, #dma-size-cells property\n");
 		dma_window++;
-	} else
+	} else {
 		dma_window += be32_to_cpu(*prop);
+	}
 
 	/* dma_window should point to the second window now */
 	adapter->riobn = be32_to_cpu(*dma_window);
@@ -644,7 +645,8 @@ static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg)
 static int ibmvscsis_check_stop_free(struct se_cmd *se_cmd)
 {
 	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
-			struct ibmvscsis_cmnd, se_cmd);
+						  struct ibmvscsis_cmnd,
+						  se_cmd);
 
 	return target_put_sess_cmd(&cmd->se_cmd);
 }
@@ -674,12 +676,12 @@ static u32 ibmvscsis_sess_get_index(struct se_session *se_sess)
 static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
 {
 	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
-			struct ibmvscsis_cmnd, se_cmd);
+						  struct ibmvscsis_cmnd,
+						  se_cmd);
 	struct scsi_cmnd *sc = &cmd->sc;
 	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
 	int ret;
 
-	pr_debug("ibmvscsis: ibmvscsis_write_pending\n");
 	sc->sdb.length = se_cmd->data_length;
 	sc->sdb.table.nents = se_cmd->t_data_nents;
 	sc->sdb.table.sgl = se_cmd->t_data_sg;
@@ -687,7 +689,7 @@ static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
 	ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
 				ibmvscsis_rdma, 1, 1);
 	if (ret) {
-		pr_err("ibmvscsis: srp_transfer_data() failed: %d\n", ret);
+		pr_err("srp_transfer_data() failed: %d\n", ret);
 		return -EAGAIN;
 	}
 	/*
@@ -748,7 +750,8 @@ static void ibmvscsis_determine_resid(struct se_cmd *se_cmd,
 static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
 {
 	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
-			struct ibmvscsis_cmnd, se_cmd);
+						  struct ibmvscsis_cmnd,
+						  se_cmd);
 	struct scsi_cmnd *sc = &cmd->sc;
 	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
 	struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
@@ -764,7 +767,6 @@ static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
 	/*
 	 * Check for overflow residual count
 	 */
-	pr_debug("ibmvscsis: ibmvscsis_queue_data_in\n");
 
 	if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
 		scsi_set_resid(sc, se_cmd->residual_count);
@@ -775,19 +777,18 @@ static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
 
 	if (scsi_sg_count(sc)) {
 		if (srp->cdb[0] == REPORT_LUNS &&
-					adapter->client_data.os_type != LINUX)
+		    adapter->client_data.os_type != LINUX)
 			ibmvscsis_modify_rep_luns(se_cmd);
 		if ((srp->cdb[0] == INQUIRY) && ((srp->cdb[1] & 0x1) == 0))
 			ibmvscsis_modify_std_inquiry(se_cmd);
 		ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
 					ibmvscsis_rdma, 1, 1);
 		if (ret) {
-			pr_err("ibmvscsis: srp_transfer_data failed: %d\n",
-				ret);
+			pr_err("srp_transfer_data failed: %d\n", ret);
 			sd = cmd->se_cmd.sense_buffer;
 			cmd->se_cmd.scsi_sense_length = 18;
 			memset(cmd->se_cmd.sense_buffer, 0,
-				cmd->se_cmd.scsi_sense_length);
+			       cmd->se_cmd.scsi_sense_length);
 			sd[0] = 0x70;
 			sd[2] = 3;
 			sd[7] = 10;
@@ -822,9 +823,10 @@ static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
 static int ibmvscsis_queue_status(struct se_cmd *se_cmd)
 {
 	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
-					struct ibmvscsis_cmnd, se_cmd);
+						  struct ibmvscsis_cmnd,
+						  se_cmd);
 	struct scsi_cmnd *sc = &cmd->sc;
-	struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
 	struct srp_rsp *rsp;
 	uint len;
 	char *data;
@@ -834,7 +836,6 @@ static int ibmvscsis_queue_status(struct se_cmd *se_cmd)
 	 * set the appropriate sc->result to be translated by
 	 * ibmvscsis_cmnd_done()
 	 */
-	pr_debug("ibmvscsis: ibmvscsis_queue_status\n");
 
 	rsp = &vio_iu(iue)->srp.rsp;
 	len = sizeof(*rsp);
@@ -861,9 +862,10 @@ static int ibmvscsis_queue_status(struct se_cmd *se_cmd)
 static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd)
 {
 	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
-			struct ibmvscsis_cmnd, se_cmd);
+						  struct ibmvscsis_cmnd,
+						  se_cmd);
 	struct scsi_cmnd *sc = &cmd->sc;
-	struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
 	struct srp_target *target = iue->target;
 	struct ibmvscsis_adapter *adapter = target->ldata;
 	struct srp_rsp *rsp;
@@ -872,16 +874,16 @@ static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd)
 	u32 *tsk_status;
 	u32 rsp_code;
 
-	pr_debug("ibmvscsis: ibmvscsis_queue_tm_rsp\n");
 	rsp = &vio_iu(iue)->srp.rsp;
 
 	if (transport_check_aborted_status(se_cmd, false) != 0) {
-		pr_debug("ibmvscsis: queue_tm_rsp aborted\n");
+		pr_debug("queue_tm_rsp aborted\n");
 		atomic_inc(&adapter->req_lim_delta);
 		srp_iu_put(iue);
 	} else {
-		rsp->req_lim_delta = cpu_to_be32(1
-				+ atomic_xchg(&adapter->req_lim_delta, 0));
+		rsp->req_lim_delta = cpu_to_be32(1 +
+						 atomic_xchg(&adapter->
+							     req_lim_delta, 0));
 	}
 
 	len = sizeof(*rsp);
@@ -923,13 +925,12 @@ static void ibmvscsis_aborted_task(struct se_cmd *se_cmd)
 {
 }
 
-static struct se_portal_group *ibmvscsis_make_nexus(
-				struct ibmvscsis_tport *tport,
-				const char *name)
+static struct se_portal_group *ibmvscsis_make_nexus(struct ibmvscsis_tport
+						    *tport,
+						    const char *name)
 {
 	struct se_node_acl *acl;
 
-	pr_debug("ibmvscsis: make nexus");
 	if (tport->se_sess) {
 		pr_debug("tport->se_sess already exists\n");
 		return &tport->se_tpg;
@@ -950,10 +951,10 @@ static struct se_portal_group *ibmvscsis_make_nexus(
 	 */
 
 	acl = core_tpg_check_initiator_node_acl(&tport->se_tpg,
-				(unsigned char *)name);
+						(unsigned char *)name);
 	if (!acl) {
 		pr_debug("core_tpg_check_initiator_node_acl() failed for %s\n",
-			name);
+			 name);
 		goto acl_failed;
 	}
 	tport->se_sess->se_node_acl = acl;
@@ -962,8 +963,8 @@ static struct se_portal_group *ibmvscsis_make_nexus(
 	 * Now register the TCM ibmvscsis virtual I_T Nexus as active.
 	 */
 	transport_register_session(&tport->se_tpg,
-					tport->se_sess->se_node_acl,
-					tport->se_sess, tport);
+				   tport->se_sess->se_node_acl,
+				   tport->se_sess, tport);
 
 	tport->se_sess->se_tpg = &tport->se_tpg;
 
@@ -1027,8 +1028,8 @@ static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf,
 		goto err;
 
 	tport->tport_proto_id = SCSI_PROTOCOL_SRP;
-	pr_debug("ibmvscsis: make_tport(%s), pointer:%p tport_id:%x\n", name,
-					tport, tport->tport_proto_id);
+	pr_debug("make_tport(%s), pointer:%p tport_id:%x\n", name, tport,
+		 tport->tport_proto_id);
 
 	return &tport->tport_wwn;
 err:
@@ -1038,10 +1039,11 @@ err:
 static void ibmvscsis_drop_tport(struct se_wwn *wwn)
 {
 	struct ibmvscsis_tport *tport = container_of(wwn,
-				struct ibmvscsis_tport, tport_wwn);
+						     struct ibmvscsis_tport,
+						     tport_wwn);
 
 	pr_debug("drop_tport(%s\n",
-		config_item_name(&tport->tport_wwn.wwn_group.cg_item));
+		 config_item_name(&tport->tport_wwn.wwn_group.cg_item));
 }
 
 static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
@@ -1066,7 +1068,8 @@ static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
 static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg)
 {
 	struct ibmvscsis_tport *tport = container_of(se_tpg,
-				struct ibmvscsis_tport, se_tpg);
+						     struct ibmvscsis_tport,
+						     se_tpg);
 
 	tport->releasing = true;
 	tport->enabled = false;
@@ -1108,7 +1111,6 @@ static int get_system_info(void)
 	const char *id, *model, *name;
 	const unsigned int *num;
 
-	pr_debug("ibmvscsis: getsysteminfo");
 	rootdn = of_find_node_by_path("/");
 	if (!rootdn)
 		return -ENOENT;
@@ -1147,7 +1149,6 @@ static irqreturn_t ibmvscsis_interrupt(int dummy, void *data)
 {
 	struct ibmvscsis_adapter *adapter = data;
 
-	pr_debug("ibmvscsis: there is an interrupt\n");
 	vio_disable_interrupts(adapter->dma_dev);
 	queue_work(vtgtd, &adapter->crq_work);
 
@@ -1164,14 +1165,14 @@ static int process_srp_iu(struct iu_entry *iue)
 	int err = 1;
 
 	spin_lock_irqsave(&target->lock, flags);
-	if (adapter->tport.releasing == true) {
-		pr_err("ibmvscsis: process_srp_iu error, tport is released:%x\n",
-			adapter->tport.releasing);
+	if (adapter->tport.releasing) {
+		pr_err("process_srp_iu error, tport is released:%x\n",
+		       adapter->tport.releasing);
 		goto done;
 	}
-	if (adapter->tport.enabled == false) {
-		pr_err("ibmvscsis: process_srp_iu, tport not enabled:%x\n",
-			adapter->tport.enabled);
+	if (!adapter->tport.enabled) {
+		pr_err("process_srp_iu, tport not enabled:%x\n",
+		       adapter->tport.enabled);
 		goto done;
 	}
 	spin_unlock_irqrestore(&target->lock, flags);
@@ -1187,7 +1188,7 @@ static int process_srp_iu(struct iu_entry *iue)
 		err = ibmvscsis_queuecommand(adapter, iue);
 		if (err) {
 			srp_iu_put(iue);
-			pr_err("ibmvscsis: can't queue cmd\n");
+			pr_err("can't queue cmd\n");
 		}
 		break;
 	case SRP_LOGIN_RSP:
@@ -1200,10 +1201,10 @@ static int process_srp_iu(struct iu_entry *iue)
 	case SRP_CRED_RSP:
 	case SRP_AER_REQ:
 	case SRP_AER_RSP:
-		pr_err("ibmvscsis: Unsupported type %u\n", opcode);
+		pr_err("Unsupported type %u\n", opcode);
 		break;
 	default:
-		pr_err("ibmvscsis: Unknown type %u\n", opcode);
+		pr_err("Unknown type %u\n", opcode);
 	}
 	return err;
 
@@ -1221,15 +1222,15 @@ static void process_iu(struct viosrp_crq *crq,
 
 	iue = srp_iu_get(adapter->target);
 	if (!iue) {
-		pr_err("ibmvscsis: Error getting IU from pool %p\n", iue);
+		pr_err("Error getting IU from pool %p\n", iue);
 		return;
 	}
 
 	iue->remote_token = crq->IU_data_ptr;
 
 	err = h_copy_rdma(be16_to_cpu(crq->IU_length), adapter->riobn,
-				be64_to_cpu(crq->IU_data_ptr),
-				adapter->liobn, iue->sbuf->dma);
+			  be64_to_cpu(crq->IU_data_ptr),
+			  adapter->liobn, iue->sbuf->dma);
 
 	switch (err) {
 	case H_SUCCESS:
@@ -1238,16 +1239,16 @@ static void process_iu(struct viosrp_crq *crq,
 	case H_SOURCE_PARM:
 	case H_DEST_PARM:
 		if (connection_broken(adapter))
-			pr_debug("ibmvscsis: rdma connection broken\n");
+			pr_debug("rdma connection broken\n");
 	default:
-		pr_err("ibmvscsis: process iu error\n");
+		pr_err("process iu error\n");
 		break;
 	}
 
-	if (crq->format == VIOSRP_MAD_FORMAT)
+	if (crq->format == VIOSRP_MAD_FORMAT) {
 		process_mad_iu(iue);
-	else {
-		pr_debug("ibmvscsis: process srpiu");
+	} else {
+		pr_debug("process srpiu");
 		process_srp_iu(iue);
 	}
 }
@@ -1265,7 +1266,7 @@ static void process_crq(struct viosrp_crq *crq,
 		case 0x02:
 			break;
 		default:
-			pr_err("ibmvscsis: Unknown format %u\n", crq->format);
+			pr_err("Unknown format %u\n", crq->format);
 		}
 		break;
 	case 0xFF:
@@ -1275,12 +1276,12 @@ static void process_crq(struct viosrp_crq *crq,
 		case PARTNER_FAILED:
 		case PARTNER_DEREGISTER:
 			adapter->client_data.os_type = 0;
-			pr_debug("ibmvscsis (%s):trans_event:good format %d\n",
-			dev_name(&adapter->dma_dev->dev), (uint)crq->format);
+			pr_debug("trans_event:good format %d\n",
+				 (uint)crq->format);
 			break;
 		default:
-			pr_err("ibmvscsis (%s):trans_event:invalid format %d\n",
-			dev_name(&adapter->dma_dev->dev), (uint)crq->format);
+			pr_err("trans_event:invalid format %d\n",
+			       (uint)crq->format);
 		}
 		break;
 	case 0x80:
@@ -1294,17 +1295,14 @@ static void process_crq(struct viosrp_crq *crq,
 		case VIOSRP_AIX_FORMAT:
 		case VIOSRP_LINUX_FORMAT:
 		case VIOSRP_INLINE_FORMAT:
-			pr_err("ibmvscsis: Unsupported format %u\n",
-					crq->format);
+			pr_err("Unsupported format %u\n", crq->format);
 			break;
 		default:
-			pr_err("ibmvscsis: Unknown format %u\n",
-					crq->format);
+			pr_err("Unknown format %u\n", crq->format);
 		}
 		break;
 	default:
-		pr_err("ibmvscsis: unknown message type 0x%02x!?\n",
-				crq->valid);
+		pr_err("Unknown message type 0x%02x!?\n", crq->valid);
 	}
 }
 
@@ -1328,8 +1326,9 @@ static void handle_crq(struct work_struct *work)
 			vio_disable_interrupts(adapter->dma_dev);
 			process_crq(crq, adapter);
 			crq->valid = 0x00;
-		} else
+		} else {
 			done = 1;
+		}
 	}
 }
 
@@ -1347,13 +1346,12 @@ static int ibmvscsis_reset_crq_queue(struct ibmvscsis_adapter *adapter)
 	queue->cur = 0;
 
 	/* And re-open it again */
-	rc = h_reg_crq(vdev->unit_address, queue->msg_token,
-			PAGE_SIZE);
+	rc = h_reg_crq(vdev->unit_address, queue->msg_token, PAGE_SIZE);
 	if (rc == 2)
 		/* Adapter is good, but other end is not ready */
-		pr_warn("ibmvscsis: Partner adapter not ready\n");
+		pr_warn("Partner adapter not ready\n");
 	else if (rc != 0)
-		pr_err("ibmvscsis: couldn't register crq--rc 0x%x\n", rc);
+		pr_err("Couldn't register crq--rc 0x%x\n", rc);
 
 	return rc;
 }
@@ -1388,8 +1386,9 @@ static inline struct viosrp_crq *next_crq(struct crq_queue *queue)
 		 * other bits of the CRQ entry
 		 */
 		rmb();
-	} else
+	} else {
 		crq = NULL;
+	}
 	spin_unlock_irqrestore(&queue->lock, flags);
 
 	return crq;
@@ -1405,12 +1404,12 @@ static int send_iu(struct iu_entry *iue, u64 length, u8 format)
 	long rc, rc1;
 
 	rsp = &vio_iu(iue)->srp.rsp;
-	pr_debug("ibmvscsis: send_iu: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
-			(unsigned long)length,
-			(unsigned long)adapter->liobn,
-			(unsigned long)iue->sbuf->dma,
-			(unsigned long)adapter->riobn,
-			(unsigned long)be64_to_cpu(iue->remote_token));
+	pr_debug("send_iu: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
+		 (unsigned long)length,
+		 (unsigned long)adapter->liobn,
+		 (unsigned long)iue->sbuf->dma,
+		 (unsigned long)adapter->riobn,
+		 (unsigned long)be64_to_cpu(iue->remote_token));
 
 	/* First copy the SRP */
 	rc = h_copy_rdma(length, adapter->liobn, iue->sbuf->dma,
@@ -1423,18 +1422,18 @@ static int send_iu(struct iu_entry *iue, u64 length, u8 format)
 	case H_SOURCE_PARM:
 	case H_DEST_PARM:
 		if (connection_broken(adapter)) {
-			pr_debug("ibmvscsis: rdma connection broken\n");
+			pr_debug("rdma connection broken\n");
 			goto end;
 		}
 		break;
 	default:
-		pr_err("ibmvscsis: Error %ld transferring data\n", rc);
+		pr_err("Error %ld transferring data\n", rc);
 		length = 0;
 		break;
 	}
 
-	pr_debug("ibmvscsis: crq pre cooked: 0x%x, 0x%llx, 0x%llx\n",
-			format, length, vio_iu(iue)->srp.rsp.tag);
+	pr_debug("crq pre cooked: 0x%x, 0x%llx, 0x%llx\n",
+		 format, length, vio_iu(iue)->srp.rsp.tag);
 
 	crq_msg.valid = 0x80;
 	crq_msg.format = format;
@@ -1447,18 +1446,18 @@ static int send_iu(struct iu_entry *iue, u64 length, u8 format)
 	crq_msg.IU_length = cpu_to_be16(length);
 	crq_msg.IU_data_ptr = vio_iu(iue)->srp.rsp.tag;
 
-	pr_debug("ibmvscsis: send crq: 0x%x, 0x%llx, 0x%llx\n",
-			adapter->dma_dev->unit_address,
-			be64_to_cpu(crq_as_u64[0]),
-			be64_to_cpu(crq_as_u64[1]));
+	pr_debug("send crq: 0x%x, 0x%llx, 0x%llx\n",
+		 adapter->dma_dev->unit_address,
+		 be64_to_cpu(crq_as_u64[0]),
+		 be64_to_cpu(crq_as_u64[1]));
 
 	srp_iu_put(iue);
 
 	rc1 = h_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
-				be64_to_cpu(crq_as_u64[1]));
+			 be64_to_cpu(crq_as_u64[1]));
 
 	if (rc1) {
-		pr_err("ibmvscsis: %ld sending response\n", rc1);
+		pr_err("%ld sending response\n", rc1);
 		return rc1;
 	}
 	return rc;
@@ -1486,18 +1485,18 @@ static int send_adapter_info(struct iu_entry *iue,
 	info = dma_alloc_coherent(&adapter->dma_dev->dev, sizeof(*info),
 				  &data_token, GFP_KERNEL);
 	if (!info) {
-		pr_err("ibmvscsis: bad dma_alloc_coherent %p\n", target);
+		pr_err("bad dma_alloc_coherent %p\n", target);
 		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
 		return 1;
 	}
 
 	/* Get remote info */
 	err = h_copy_rdma(sizeof(*info), adapter->riobn,
-				be64_to_cpu(remote_buffer),
-				adapter->liobn, data_token);
+			  be64_to_cpu(remote_buffer),
+			  adapter->liobn, data_token);
 
 	if (err == H_SUCCESS) {
-		pr_err("ibmvscsis: Client connect: %s (%d)\n",
+		pr_err("Client connect: %s (%d)\n",
 		       info->partition_name, info->partition_number);
 
 		if (adapter->client_data.partition_number == 0)
@@ -1511,8 +1510,8 @@ static int send_adapter_info(struct iu_entry *iue,
 		adapter->client_data.mad_version =
 						be32_to_cpu(info->mad_version);
 		adapter->client_data.os_type = be32_to_cpu(info->os_type);
-		pr_debug("ibmvscsis: adapterinfo client adapter %u\n",
-				adapter->client_data.os_type);
+		pr_debug("adapter info client adapter %u\n",
+			 adapter->client_data.os_type);
 
 		strcpy(info->srp_version, "16.a");
 		strncpy(info->partition_name, partition_name,
@@ -1523,7 +1522,7 @@ static int send_adapter_info(struct iu_entry *iue,
 		info->os_type = cpu_to_be32(2);
 		memset(&info->port_max_txu[0], 0, sizeof(info->port_max_txu));
 		info->port_max_txu[0] = cpu_to_be32(SCSI_MAX_SG_SEGMENTS *
-						PAGE_SIZE);
+						    PAGE_SIZE);
 
 		dma_rmb();
 		/* Send our info to remote */
@@ -1537,14 +1536,14 @@ static int send_adapter_info(struct iu_entry *iue,
 		case H_SOURCE_PARM:
 		case H_DEST_PARM:
 			if (connection_broken(adapter))
-				pr_debug("ibmvscsis: rdma connection broken\n");
+				pr_debug("rdma connection broken\n");
 		default:
-			pr_err("ibmvscsis: Error sending adapter info %d\n",
+			pr_err("Error sending adapter info %d\n",
 			       err);
 			return -EIO;
 		}
 	} else {
-		pr_err("ibmvscsis: Error sending adapter info %d\n", err);
+		pr_err("Error sending adapter info %d\n", err);
 		return 1;
 	}
 
@@ -1562,10 +1561,10 @@ static int process_mad_iu(struct iu_entry *iue)
 
 	switch (be32_to_cpu(iu->mad.empty_iu.common.type)) {
 	case VIOSRP_EMPTY_IU_TYPE:
-		pr_err("ibmvscsis: %s\n", "Unsupported EMPTY MAD IU");
+		pr_err("%s\n", "Unsupported EMPTY MAD IU");
 		break;
 	case VIOSRP_ERROR_LOG_TYPE:
-		pr_err("ibmvscsis: %s\n", "Unsupported ERROR LOG MAD IU");
+		pr_err("%s\n", "Unsupported ERROR LOG MAD IU");
 		iu->mad.error_log.common.status = 1;
 		send_iu(iue, sizeof(iu->mad.error_log),	VIOSRP_MAD_FORMAT);
 		break;
@@ -1581,7 +1580,7 @@ static int process_mad_iu(struct iu_entry *iue)
 		send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT);
 		break;
 	default:
-		pr_err("ibmvscsis: Unknown type %u\n", iu->srp.rsp.opcode);
+		pr_err("Unknown type %u\n", iu->srp.rsp.opcode);
 		iu->mad.empty_iu.common.status =
 					cpu_to_be16(VIOSRP_MAD_NOT_SUPPORTED);
 		send_iu(iue, sizeof(iu->mad), VIOSRP_MAD_FORMAT);
@@ -1622,18 +1621,17 @@ static void process_login(struct iu_entry *iue)
 
 	snprintf(name, sizeof(name), "%x", vdev->unit_address);
 
-	if (adapter->tport.enabled == false) {
+	if (!adapter->tport.enabled) {
 		rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
-		pr_err("ibmvscsis: Rejected SRP_LOGIN_REQ because target %s has not yet been enabled",
+		pr_err("Rejected SRP_LOGIN_REQ because target %s has not yet been enabled",
 		       name);
 		goto reject;
 	}
 
 	se_tpg = ibmvscsis_make_nexus(&adapter->tport,
 				      &adapter->tport.tport_name[0]);
-	if (se_tpg == NULL) {
-		pr_debug("ibmvscsis: login make nexus fail se_tpg(%p)\n",
-						se_tpg);
+	if (!se_tpg) {
+		pr_debug("login make nexus fail se_tpg(%p)\n", se_tpg);
 		goto reject;
 	}
 
@@ -1641,14 +1639,14 @@ static void process_login(struct iu_entry *iue)
 
 	rsp->req_lim_delta = cpu_to_be32(INITIAL_SRP_LIMIT);
 
-	pr_debug("ibmvscsis: process_login, tag:%llu\n", tag);
+	pr_debug("process_login, tag:%llu\n", tag);
 
 	rsp->tag = tag;
 	rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
 	rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
 	/* direct and indirect */
-	rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT
-					| SRP_BUF_FORMAT_INDIRECT);
+	rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
+				   SRP_BUF_FORMAT_INDIRECT);
 
 	send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT);
 	return;
@@ -1656,8 +1654,8 @@ static void process_login(struct iu_entry *iue)
 reject:
 	rej->opcode = SRP_LOGIN_REJ;
 	rej->tag = tag;
-	rej->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT
-				   | SRP_BUF_FORMAT_INDIRECT);
+	rej->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
+				   SRP_BUF_FORMAT_INDIRECT);
 
 	send_iu(iue, sizeof(*rej), VIOSRP_SRP_FORMAT);
 }
@@ -1674,7 +1672,7 @@ static void process_tsk_mgmt(struct ibmvscsis_adapter *adapter,
 	int rc = 0;
 
 	rsp = &vio_iu(iue)->srp.rsp;
-	unpacked_lun = ibmvscsis_unpack_lun((uint8_t *)&srp_tsk->lun,
+	unpacked_lun = ibmvscsis_unpack_lun((u8 *)&srp_tsk->lun,
 					    sizeof(srp_tsk->lun));
 
 	switch (srp_tsk->tsk_mgmt_func) {
@@ -1696,36 +1694,30 @@ static void process_tsk_mgmt(struct ibmvscsis_adapter *adapter,
 		tcm_type = TMR_CLEAR_ACA;
 		break;
 	default:
-		pr_err("ibmvscsis: unknown task mgmt func %d\n",
-						srp_tsk->tsk_mgmt_func);
+		pr_err("unknown task mgmt func %d\n", srp_tsk->tsk_mgmt_func);
 		cmd->se_cmd.se_tmr_req->response =
 					TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
-		rc = -1;
-		break;
+		goto fail;
 	}
 
-	if (!rc) {
-		cmd->se_cmd.tag = be64_to_cpu(srp_tsk->tag);
-
-		pr_debug("ibmvscsis: calling submit_tmr, func %d\n",
-			 srp_tsk->tsk_mgmt_func);
-		rc = target_submit_tmr(&cmd->se_cmd,
-				       adapter->tport.se_sess, NULL,
-				       unpacked_lun, srp_tsk, tcm_type,
-				       GFP_KERNEL, tag_to_abort,
-				       TARGET_SCF_ACK_KREF);
-		if (rc != 0) {
-			pr_err("ibmvscsis: target_submit_tmr failed, rc %d\n",
-			       rc);
-			cmd->se_cmd.se_tmr_req->response =
-							TMR_FUNCTION_REJECTED;
-			goto fail;
-		}
+	cmd->se_cmd.tag = be64_to_cpu(srp_tsk->tag);
+
+	pr_debug("calling submit_tmr, func %d\n",
+		 srp_tsk->tsk_mgmt_func);
+	rc = target_submit_tmr(&cmd->se_cmd,
+			       adapter->tport.se_sess, NULL,
+			       unpacked_lun, srp_tsk, tcm_type,
+			       GFP_KERNEL, tag_to_abort,
+			       TARGET_SCF_ACK_KREF);
+	if (rc != 0) {
+		pr_err("target_submit_tmr failed, rc %d\n", rc);
+		cmd->se_cmd.se_tmr_req->response = TMR_FUNCTION_REJECTED;
+		goto fail;
 	}
+
 fail:
 	if (rc)
 		transport_send_check_condition_and_sense(&cmd->se_cmd, 0, 0);
-
 }
 
 static bool connection_broken(struct ibmvscsis_adapter *adapter)
@@ -1737,7 +1729,8 @@ static bool connection_broken(struct ibmvscsis_adapter *adapter)
 
 	/* create a PING crq */
 	crq = (struct viosrp_crq *)&buffer;
-	buffer[0] = buffer[1] = 0;
+	buffer[0] = 0;
+	buffer[1] = 0;
 	crq->valid = 0x80;
 	crq->format = 6;
 	crq->status = 0xF5;
@@ -1746,8 +1739,7 @@ static bool connection_broken(struct ibmvscsis_adapter *adapter)
 				   cpu_to_be64(buffer[0]),
 				   cpu_to_be64(buffer[1]));
 
-	pr_debug("ibmvscsis (%s): connection_broken: rc %ld\n",
-			dev_name(&adapter->dma_dev->dev), h_return_code);
+	pr_debug("connection_broken: rc %ld\n", h_return_code);
 
 	if (h_return_code == H_CLOSED)
 		rc = true;
@@ -1759,7 +1751,7 @@ static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
 			  struct srp_direct_buf *md, int nmd,
 			  enum dma_data_direction dir, unsigned int rest)
 {
-	struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
 	struct srp_target *target = iue->target;
 	struct ibmvscsis_adapter *adapter = target->ldata;
 	dma_addr_t token;
@@ -1767,7 +1759,8 @@ static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
 	unsigned int done = 0;
 	int i, sidx, soff;
 
-	sidx = soff = 0;
+	sidx = 0;
+	soff = 0;
 	token = sg_dma_address(sg + sidx);
 
 	for (i = 0; i < nmd && rest; i++) {
@@ -1788,7 +1781,8 @@ static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
 						  adapter->liobn,
 						  token + soff,
 						  adapter->riobn,
-						  be64_to_cpu(md[i].va)+mdone);
+						  be64_to_cpu(md[i].va) +
+						  mdone);
 			switch (err) {
 			case H_SUCCESS:
 				break;
@@ -1796,10 +1790,10 @@ static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
 			case H_SOURCE_PARM:
 			case H_DEST_PARM:
 				if (connection_broken(adapter))
-					pr_debug("ibmvscsis: rdma connection broken\n");
+					pr_debug("rdma connection broken\n");
 			default:
-				pr_err("ibmvscsis: rdma error %d %d %ld\n",
-					dir, slen, err);
+				pr_err("rdma error %d %d %ld\n",
+				       dir, slen, err);
 				return -EIO;
 			}
 
@@ -1814,8 +1808,8 @@ static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
 				token = sg_dma_address(sg + sidx);
 
 				if (sidx > nsg) {
-					pr_err("ibmvscsis: out of sg %p %d %d\n",
-						iue, sidx, nsg);
+					pr_err("out of sg %p %d %d\n",
+					       iue, sidx, nsg);
 					return -EIO;
 				}
 			}
@@ -1833,8 +1827,6 @@ static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
 	struct ibmvscsis_cmnd *vsc;
 	int ret;
 
-	pr_debug("ibmvscsis: ibmvscsis_queuecommand\n");
-
 	vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);
 	adapter->cmd = vsc;
 	sc = &vsc->sc;
@@ -1847,14 +1839,14 @@ static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
 	return ret;
 }
 
-static uint64_t ibmvscsis_unpack_lun(const uint8_t *lun, int len)
+static u64 ibmvscsis_unpack_lun(const u8 *lun, int len)
 {
-	uint64_t res = NO_SUCH_LUN;
+	u64 res = NO_SUCH_LUN;
 	int addressing_method;
 
 	if (unlikely(len < 2)) {
 		pr_err("Illegal LUN length %d, expected 2 bytes or more\n",
-			len);
+		       len);
 		goto out;
 	}
 
@@ -1888,7 +1880,7 @@ static uint64_t ibmvscsis_unpack_lun(const uint8_t *lun, int len)
 	case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN:
 	default:
 		pr_err("Unimplemented LUN addressing method %u\n",
-			addressing_method);
+		       addressing_method);
 		break;
 	}
 
@@ -1907,7 +1899,7 @@ static int tcm_queuecommand(struct ibmvscsis_adapter *adapter,
 	int attr;
 	u64 data_len;
 	int ret;
-	uint64_t unpacked_lun;
+	u64 unpacked_lun;
 
 	switch (scmd->task_attr) {
 	case SRP_SIMPLE_TASK:
@@ -1923,24 +1915,23 @@ static int tcm_queuecommand(struct ibmvscsis_adapter *adapter,
 		attr = TCM_ACA_TAG;
 		break;
 	default:
-		pr_err("ibmvscsis: Task attribute %d not supported\n",
-		       scmd->task_attr);
+		pr_err("Task attribute %d not supported\n", scmd->task_attr);
 		attr = TCM_SIMPLE_TAG;
 	}
 
-	pr_debug("ibmvscsis: srp_data_length: %llx, srp_direction:%x\n",
-			srp_data_length(scmd, srp_cmd_direction(scmd)),
-			srp_cmd_direction(scmd));
+	pr_debug("srp_data_length: %llx, srp_direction:%x\n",
+		 srp_data_length(scmd, srp_cmd_direction(scmd)),
+		 srp_cmd_direction(scmd));
 	data_len = srp_data_length(scmd, srp_cmd_direction(scmd));
 
 	vsc->se_cmd.tag = scmd->tag;
 	se_cmd = &vsc->se_cmd;
 
-	pr_debug("ibmvscsis: size of lun:%lx, lun:%s\n", sizeof(scmd->lun),
-				&scmd->lun.scsi_lun[0]);
+	pr_debug("size of lun:%lx, lun:%s\n", sizeof(scmd->lun),
+		 &scmd->lun.scsi_lun[0]);
 
-	unpacked_lun = ibmvscsis_unpack_lun((uint8_t *)&scmd->lun,
-				sizeof(scmd->lun));
+	unpacked_lun = ibmvscsis_unpack_lun((u8 *)&scmd->lun,
+					    sizeof(scmd->lun));
 
 	ret = target_submit_cmd(se_cmd, adapter->tport.se_sess,
 				&scmd->cdb[0], &vsc->sense_buf[0], unpacked_lun,
@@ -1948,7 +1939,7 @@ static int tcm_queuecommand(struct ibmvscsis_adapter *adapter,
 				TARGET_SCF_ACK_KREF);
 	if (ret != 0) {
 		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-		pr_debug("ibmvscsis: tcm_queuecommand fail submit_cmd\n");
+		pr_debug("tcm_queuecommand fail submit_cmd\n");
 		goto send_sense;
 	}
 	return 0;
@@ -1971,27 +1962,21 @@ static int __init ibmvscsis_init(void)
 {
 	int ret = -ENOMEM;
 
-	pr_info("IBMVSCSIS fabric module %s on %s/%s on "UTS_RELEASE"\n",
-		IBMVSCSIS_VERSION,
-		utsname()->sysname,
-		utsname()->machine);
-
 	ret = get_system_info();
 	if (ret) {
-		pr_err("ibmvscsis: ret %d from get_system_info\n", ret);
+		pr_err("ret %d from get_system_info\n", ret);
 		goto out;
 	}
 
 	ret = class_register(&ibmvscsis_class);
 	if (ret) {
-		pr_err("ibmvscsis failed class register\n");
+		pr_err("failed class register\n");
 		goto out;
 	}
 
 	ret = target_register_template(&ibmvscsis_ops);
 	if (ret) {
-		pr_err("ibmvscsis: ret %d from target_register_template\n",
-				ret);
+		pr_err("ret %d from target_register_template\n", ret);
 		goto unregister_class;
 	}
 
@@ -2001,7 +1986,7 @@ static int __init ibmvscsis_init(void)
 
 	ret = vio_register_driver(&ibmvscsis_driver);
 	if (ret) {
-		pr_err("ibmvscsis: ret %d from vio_register_driver\n", ret);
+		pr_err("ret %d from vio_register_driver\n", ret);
 		goto destroy_wq;
 	}
 
@@ -2019,7 +2004,7 @@ out:
 
 static void __exit ibmvscsis_exit(void)
 {
-	pr_info("ibmvscsis: Unregister IBM virtual SCSI driver\n");
+	pr_info("Unregister IBM virtual SCSI driver\n");
 	vio_unregister_driver(&ibmvscsis_driver);
 	destroy_workqueue(vtgtd);
 	target_unregister_template(&ibmvscsis_ops);
@@ -2029,5 +2014,6 @@ static void __exit ibmvscsis_exit(void)
 MODULE_DESCRIPTION("IBMVSCSIS fabric driver");
 MODULE_AUTHOR("Bryant G. Ly");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(IBMVSCSIS_VERSION);
 module_init(ibmvscsis_init);
 module_exit(ibmvscsis_exit);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsis.h b/drivers/scsi/ibmvscsi/ibmvscsis.h
index bcee92b..0637aeb 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsis.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsis.h
@@ -25,27 +25,36 @@
 #ifndef __H_IBMVSCSIS
 #define __H_IBMVSCSIS
 
+#define SYS_ID_NAME_LEN		64
+#define PARTITION_NAMELEN	97
 #define IBMVSCSIS_NAMELEN       32
 
 #define SCSOLNT_RESP_SHIFT      1
 #define UCSOLNT_RESP_SHIFT      2
 
-#define SCSOLNT         (1 << SCSOLNT_RESP_SHIFT)
-#define UCSOLNT         (1 << UCSOLNT_RESP_SHIFT)
+#define SCSOLNT		BIT(SCSOLNT_RESP_SHIFT)
+#define UCSOLNT		BIT(UCSOLNT_RESP_SHIFT)
 
 #define INQ_DATA_OFFSET 8
 #define NO_SUCH_LUN ((u64)-1LL)
 
+struct crq_queue {
+	struct viosrp_crq *msgs;
+	int size, cur;
+	dma_addr_t msg_token;
+	spinlock_t lock;
+};
+
 struct client_info {
 #define SRP_VERSION "16.a"
 	char srp_version[8];
 	/* root node property ibm,partition-name */
-	char partition_name[96];
+	char partition_name[PARTITION_NAMELEN];
 	/* root node property ibm,partition-no */
-	uint32_t partition_number;
+	u32 partition_number;
 	/* initially 1 */
-	uint32_t mad_version;
-	uint32_t os_type;
+	u32 mad_version;
+	u32 os_type;
 };
 
 struct ibmvscsis_cmnd {
@@ -112,25 +121,6 @@ struct ibmvscsis_nacl {
 	struct se_node_acl se_node_acl;
 };
 
-struct inquiry_data {
-	u8 qual_type;
-	u8 rmb_reserve;
-	u8 version;
-	u8 aerc_naca_hisup_format;
-	u8 addl_len;
-	u8 sccs_reserved;
-	u8 bque_encserv_vs_multip_mchngr_reserved;
-	u8 reladr_reserved_linked_cmdqueue_vs;
-	char vendor[8];
-	char product[16];
-	char revision[4];
-	char vendor_specific[20];
-	char reserved1[2];
-	char version_descriptor[16];
-	char reserved2[22];
-	char unique[158];
-};
-
 enum srp_trans_event {
 	UNUSED_FORMAT = 0,
 	PARTNER_FAILED = 1,
diff --git a/drivers/scsi/ibmvscsi/libsrp.c b/drivers/scsi/ibmvscsi/libsrp.c
new file mode 100644
index 0000000..4bece8f
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/libsrp.c
@@ -0,0 +1,386 @@
+/*******************************************************************************
+ * SCSI RDMA Protocol lib functions
+ *
+ * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2016 Bryant G. Ly <bgly@us.ibm.com> IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ ***********************************************************************/
+
+#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
+
+#include <linux/printk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/kfifo.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/srp.h>
+#include <target/target_core_base.h>
+
+#include "libsrp.h"
+
+static int srp_iu_pool_alloc(struct srp_queue *q, size_t max,
+			     struct srp_buf **ring)
+{
+	int i;
+	struct iu_entry *iue;
+
+	q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL);
+	if (!q->pool)
+		return -ENOMEM;
+	q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL);
+	if (!q->items)
+		goto free_pool;
+
+	spin_lock_init(&q->lock);
+	kfifo_init(&q->queue, (void *)q->pool, max * sizeof(void *));
+
+	for (i = 0, iue = q->items; i < max; i++) {
+		kfifo_in(&q->queue, (void *)&iue, sizeof(void *));
+		iue->sbuf = ring[i];
+		iue++;
+	}
+	return 0;
+
+free_pool:
+	kfree(q->pool);
+	return -ENOMEM;
+}
+
+static void srp_iu_pool_free(struct srp_queue *q)
+{
+	kfree(q->items);
+	kfree(q->pool);
+}
+
+static struct srp_buf **srp_ring_alloc(struct device *dev,
+				       size_t max, size_t size)
+{
+	struct srp_buf **ring;
+	int i;
+
+	ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL);
+	if (!ring)
+		return NULL;
+
+	for (i = 0; i < max; i++) {
+		ring[i] = kzalloc(sizeof(*ring[i]), GFP_KERNEL);
+		if (!ring[i])
+			goto out;
+		ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma,
+						  GFP_KERNEL);
+		if (!ring[i]->buf)
+			goto out;
+	}
+	return ring;
+
+out:
+	for (i = 0; i < max && ring[i]; i++) {
+		if (ring[i]->buf) {
+			dma_free_coherent(dev, size, ring[i]->buf,
+					  ring[i]->dma);
+		}
+		kfree(ring[i]);
+	}
+	kfree(ring);
+
+	return NULL;
+}
+
+static void srp_ring_free(struct device *dev, struct srp_buf **ring,
+			  size_t max, size_t size)
+{
+	int i;
+
+	for (i = 0; i < max; i++) {
+		dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
+		kfree(ring[i]);
+	}
+	kfree(ring);
+}
+
+int srp_target_alloc(struct srp_target *target, struct device *dev,
+		     size_t nr, size_t iu_size)
+{
+	int err;
+
+	spin_lock_init(&target->lock);
+
+	target->dev = dev;
+
+	target->srp_iu_size = iu_size;
+	target->rx_ring_size = nr;
+	target->rx_ring = srp_ring_alloc(target->dev, nr, iu_size);
+	if (!target->rx_ring)
+		return -ENOMEM;
+	err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring);
+	if (err)
+		goto free_ring;
+
+	dev_set_drvdata(target->dev, target);
+	return 0;
+
+free_ring:
+	srp_ring_free(target->dev, target->rx_ring, nr, iu_size);
+	return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(srp_target_alloc);
+
+void srp_target_free(struct srp_target *target)
+{
+	dev_set_drvdata(target->dev, NULL);
+	srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size,
+		      target->srp_iu_size);
+	srp_iu_pool_free(&target->iu_queue);
+}
+EXPORT_SYMBOL_GPL(srp_target_free);
+
+struct iu_entry *srp_iu_get(struct srp_target *target)
+{
+	struct iu_entry *iue = NULL;
+
+	if (kfifo_out_locked(&target->iu_queue.queue, (void *)&iue,
+			     sizeof(void *),
+			     &target->iu_queue.lock) != sizeof(void *)) {
+		WARN_ONCE(1, "unexpected fifo state");
+		return NULL;
+	}
+	if (!iue)
+		return iue;
+	iue->target = target;
+	iue->flags = 0;
+	return iue;
+}
+EXPORT_SYMBOL_GPL(srp_iu_get);
+
+void srp_iu_put(struct iu_entry *iue)
+{
+	kfifo_in_locked(&iue->target->iu_queue.queue, (void *)&iue,
+			sizeof(void *), &iue->target->iu_queue.lock);
+}
+EXPORT_SYMBOL_GPL(srp_iu_put);
+
+static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
+			   enum dma_data_direction dir, srp_rdma_t rdma_io,
+			   int dma_map, int ext_desc)
+{
+	struct iu_entry *iue = NULL;
+	struct scatterlist *sg = NULL;
+	int err, nsg = 0, len;
+
+	if (dma_map) {
+		iue = (struct iu_entry *)sc->SCp.ptr;
+		sg = scsi_sglist(sc);
+		nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
+				 DMA_BIDIRECTIONAL);
+		if (!nsg) {
+			pr_err("fail to map %p %d\n", iue, scsi_sg_count(sc));
+			return 0;
+		}
+		len = min(scsi_bufflen(sc), be32_to_cpu(md->len));
+	} else {
+		len = be32_to_cpu(md->len);
+	}
+
+	err = rdma_io(sc, sg, nsg, md, 1, dir, len);
+
+	if (dma_map)
+		dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
+
+	return err;
+}
+
+static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
+			     struct srp_indirect_buf *id,
+			     enum dma_data_direction dir, srp_rdma_t rdma_io,
+			     int dma_map, int ext_desc)
+{
+	struct iu_entry *iue = NULL;
+	struct srp_direct_buf *md = NULL;
+	struct scatterlist dummy, *sg = NULL;
+	dma_addr_t token = 0;
+	int err = 0;
+	int nmd, nsg = 0, len;
+
+	if (dma_map || ext_desc) {
+		iue = (struct iu_entry *)sc->SCp.ptr;
+		sg = scsi_sglist(sc);
+	}
+
+	nmd = be32_to_cpu(id->table_desc.len) / sizeof(struct srp_direct_buf);
+
+	if ((dir == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) ||
+	    (dir == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt)) {
+		md = &id->desc_list[0];
+		goto rdma;
+	}
+
+	if (ext_desc && dma_map) {
+		md = dma_alloc_coherent(iue->target->dev,
+					be32_to_cpu(id->table_desc.len),
+					&token, GFP_KERNEL);
+		if (!md) {
+			pr_err("Can't get dma memory %u\n",
+			       be32_to_cpu(id->table_desc.len));
+			return -ENOMEM;
+		}
+
+		sg_init_one(&dummy, md, be32_to_cpu(id->table_desc.len));
+		sg_dma_address(&dummy) = token;
+		sg_dma_len(&dummy) = be32_to_cpu(id->table_desc.len);
+		err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
+			      be32_to_cpu(id->table_desc.len));
+		if (err) {
+			pr_err("Error copying indirect table %d\n", err);
+			goto free_mem;
+		}
+	} else {
+		pr_err("This command uses external indirect buffer\n");
+		return -EINVAL;
+	}
+
+rdma:
+	if (dma_map) {
+		nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
+				 DMA_BIDIRECTIONAL);
+		if (!nsg) {
+			pr_err("fail to map %p %d\n", iue, scsi_sg_count(sc));
+			err = -EIO;
+			goto free_mem;
+		}
+		len = min(scsi_bufflen(sc), be32_to_cpu(id->len));
+	} else {
+		len = be32_to_cpu(id->len);
+	}
+
+	err = rdma_io(sc, sg, nsg, md, nmd, dir, len);
+
+	if (dma_map)
+		dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
+
+free_mem:
+	if (token && dma_map) {
+		dma_free_coherent(iue->target->dev,
+				  be32_to_cpu(id->table_desc.len), md, token);
+	}
+	return err;
+}
+
+static int data_out_desc_size(struct srp_cmd *cmd)
+{
+	int size = 0;
+	u8 fmt = cmd->buf_fmt >> 4;
+
+	switch (fmt) {
+	case SRP_NO_DATA_DESC:
+		break;
+	case SRP_DATA_DESC_DIRECT:
+		size = sizeof(struct srp_direct_buf);
+		break;
+	case SRP_DATA_DESC_INDIRECT:
+		size = sizeof(struct srp_indirect_buf) +
+			sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt;
+		break;
+	default:
+		pr_err("client error. Invalid data_out_format %x\n", fmt);
+		break;
+	}
+	return size;
+}
+
+/*
+ * TODO: this can be called multiple times for a single command if it
+ * has very long data.
+ */
+int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
+		      srp_rdma_t rdma_io, int dma_map, int ext_desc)
+{
+	struct srp_direct_buf *md;
+	struct srp_indirect_buf *id;
+	enum dma_data_direction dir;
+	int offset, err = 0;
+	u8 format;
+
+	offset = cmd->add_cdb_len & ~3;
+
+	dir = srp_cmd_direction(cmd);
+	if (dir == DMA_FROM_DEVICE)
+		offset += data_out_desc_size(cmd);
+
+	if (dir == DMA_TO_DEVICE)
+		format = cmd->buf_fmt >> 4;
+	else
+		format = cmd->buf_fmt & ((1U << 4) - 1);
+
+	switch (format) {
+	case SRP_NO_DATA_DESC:
+		break;
+	case SRP_DATA_DESC_DIRECT:
+		md = (struct srp_direct_buf *)(cmd->add_data + offset);
+		err = srp_direct_data(sc, md, dir, rdma_io, dma_map, ext_desc);
+		break;
+	case SRP_DATA_DESC_INDIRECT:
+		id = (struct srp_indirect_buf *)(cmd->add_data + offset);
+		err = srp_indirect_data(sc, cmd, id, dir, rdma_io, dma_map,
+					ext_desc);
+		break;
+	default:
+		pr_err("Unknown format %d %x\n", dir, format);
+		err = -EINVAL;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(srp_transfer_data);
+
+u64 srp_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
+{
+	struct srp_direct_buf *md;
+	struct srp_indirect_buf *id;
+	u64 len = 0;
+	unsigned offset = cmd->add_cdb_len & ~3;
+	u8 fmt;
+
+	if (dir == DMA_TO_DEVICE) {
+		fmt = cmd->buf_fmt >> 4;
+	} else {
+		fmt = cmd->buf_fmt & ((1U << 4) - 1);
+		offset += data_out_desc_size(cmd);
+	}
+
+	switch (fmt) {
+	case SRP_NO_DATA_DESC:
+		break;
+	case SRP_DATA_DESC_DIRECT:
+		md = (struct srp_direct_buf *)(cmd->add_data + offset);
+		len = be32_to_cpu(md->len);
+		break;
+	case SRP_DATA_DESC_INDIRECT:
+		id = (struct srp_indirect_buf *)(cmd->add_data + offset);
+		len = be32_to_cpu(id->len);
+		break;
+	default:
+		pr_err("invalid data format %x\n", fmt);
+		break;
+	}
+	return len;
+}
+EXPORT_SYMBOL_GPL(srp_data_length);
+
+MODULE_DESCRIPTION("SCSI RDMA Protocol lib functions");
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/ibmvscsi/libsrp.h b/drivers/scsi/ibmvscsi/libsrp.h
new file mode 100644
index 0000000..bf9e30b
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/libsrp.h
@@ -0,0 +1,91 @@
+#ifndef __LIBSRP_H__
+#define __LIBSRP_H__
+
+#include <linux/list.h>
+#include <linux/kfifo.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/srp.h>
+#include <target/target_core_base.h>
+
+enum srp_task_attributes {
+	SRP_SIMPLE_TASK = 0,
+	SRP_HEAD_TASK = 1,
+	SRP_ORDERED_TASK = 2,
+	SRP_ACA_TASK = 4
+};
+
+enum iue_flags {
+	V_DIOVER,
+	V_WRITE,
+	V_LINKED,
+	V_FLYING,
+};
+
+enum {
+	SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE           = 0,
+	SRP_REQUEST_FIELDS_INVALID                      = 2,
+	SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED      = 4,
+	SRP_TASK_MANAGEMENT_FUNCTION_FAILED             = 5
+};
+
+struct srp_buf {
+	dma_addr_t dma;
+	void *buf;
+};
+
+struct srp_queue {
+	void *pool;
+	void *items;
+	struct kfifo queue;
+	spinlock_t lock;
+};
+
+struct srp_target {
+	struct Scsi_Host *shost;
+	struct se_device *tgt;
+	struct device *dev;
+
+	spinlock_t lock;
+	struct list_head cmd_queue;
+
+	size_t srp_iu_size;
+	struct srp_queue iu_queue;
+	size_t rx_ring_size;
+	struct srp_buf **rx_ring;
+
+	void *ldata;
+};
+
+struct iu_entry {
+	struct srp_target *target;
+
+	struct list_head ilist;
+	dma_addr_t remote_token;
+	unsigned long flags;
+
+	struct srp_buf *sbuf;
+};
+
+typedef int (srp_rdma_t)(struct scsi_cmnd *, struct scatterlist *, int,
+			 struct srp_direct_buf *, int,
+			 enum dma_data_direction, unsigned int);
+extern int srp_target_alloc(struct srp_target *, struct device *,
+			    size_t, size_t);
+extern void srp_target_free(struct srp_target *);
+extern struct iu_entry *srp_iu_get(struct srp_target *);
+extern void srp_iu_put(struct iu_entry *);
+extern int srp_transfer_data(struct scsi_cmnd *, struct srp_cmd *, srp_rdma_t,
+			     int, int);
+extern u64 srp_data_length(struct srp_cmd *cmd, enum dma_data_direction dir);
+static inline struct srp_target *host_to_srp_target(struct Scsi_Host *host)
+{
+	return (struct srp_target *)host->hostdata;
+}
+
+static inline int srp_cmd_direction(struct srp_cmd *cmd)
+{
+	return (cmd->buf_fmt >> 4) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+}
+
+#endif
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
deleted file mode 100644
index 0e32abd..0000000
--- a/drivers/scsi/libsrp.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/*******************************************************************************
- * SCSI RDMA Protocol lib functions
- *
- * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
- * Copyright (C) 2016 Bryant G. Ly <bgly@us.ibm.com> IBM Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- ***********************************************************************/
-
-#include <linux/printk.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/kfifo.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/module.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/srp.h>
-#include <target/target_core_base.h>
-#include <scsi/libsrp.h>
-
-static int srp_iu_pool_alloc(struct srp_queue *q, size_t max,
-			     struct srp_buf **ring)
-{
-	int i;
-	struct iu_entry *iue;
-
-	q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL);
-	if (!q->pool)
-		return -ENOMEM;
-	q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL);
-	if (!q->items)
-		goto free_pool;
-
-	spin_lock_init(&q->lock);
-	kfifo_init(&q->queue, (void *) q->pool, max * sizeof(void *));
-
-	for (i = 0, iue = q->items; i < max; i++) {
-		kfifo_in(&q->queue, (void *) &iue, sizeof(void *));
-		iue->sbuf = ring[i];
-		iue++;
-	}
-	return 0;
-
-free_pool:
-	kfree(q->pool);
-	return -ENOMEM;
-}
-
-static void srp_iu_pool_free(struct srp_queue *q)
-{
-	kfree(q->items);
-	kfree(q->pool);
-}
-
-static struct srp_buf **srp_ring_alloc(struct device *dev,
-				       size_t max, size_t size)
-{
-	int i;
-	struct srp_buf **ring;
-
-	ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL);
-	if (!ring)
-		return NULL;
-
-	for (i = 0; i < max; i++) {
-		ring[i] = kzalloc(sizeof(struct srp_buf), GFP_KERNEL);
-		if (!ring[i])
-			goto out;
-		ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma,
-						  GFP_KERNEL);
-		if (!ring[i]->buf)
-			goto out;
-	}
-	return ring;
-
-out:
-	for (i = 0; i < max && ring[i]; i++) {
-		if (ring[i]->buf) {
-			dma_free_coherent(dev, size, ring[i]->buf,
-						ring[i]->dma);
-		}
-		kfree(ring[i]);
-	}
-	kfree(ring);
-
-	return NULL;
-}
-
-static void srp_ring_free(struct device *dev, struct srp_buf **ring,
-			  size_t max, size_t size)
-{
-	int i;
-
-	for (i = 0; i < max; i++) {
-		dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
-		kfree(ring[i]);
-	}
-	kfree(ring);
-}
-
-int srp_target_alloc(struct srp_target *target, struct device *dev,
-		     size_t nr, size_t iu_size)
-{
-	int err;
-
-	spin_lock_init(&target->lock);
-
-	target->dev = dev;
-
-	target->srp_iu_size = iu_size;
-	target->rx_ring_size = nr;
-	target->rx_ring = srp_ring_alloc(target->dev, nr, iu_size);
-	if (!target->rx_ring)
-		return -ENOMEM;
-	err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring);
-	if (err)
-		goto free_ring;
-
-	dev_set_drvdata(target->dev, target);
-	return 0;
-
-free_ring:
-	srp_ring_free(target->dev, target->rx_ring, nr, iu_size);
-	return -ENOMEM;
-}
-EXPORT_SYMBOL_GPL(srp_target_alloc);
-
-void srp_target_free(struct srp_target *target)
-{
-	dev_set_drvdata(target->dev, NULL);
-	srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size,
-		      target->srp_iu_size);
-	srp_iu_pool_free(&target->iu_queue);
-}
-EXPORT_SYMBOL_GPL(srp_target_free);
-
-struct iu_entry *srp_iu_get(struct srp_target *target)
-{
-	struct iu_entry *iue = NULL;
-
-	if (kfifo_out_locked(&target->iu_queue.queue, (void *) &iue,
-				sizeof(void *),
-				&target->iu_queue.lock) != sizeof(void *)) {
-		WARN_ONCE(1, "unexpected fifo state");
-		return NULL;
-	}
-	if (!iue)
-		return iue;
-	iue->target = target;
-	iue->flags = 0;
-	return iue;
-}
-EXPORT_SYMBOL_GPL(srp_iu_get);
-
-void srp_iu_put(struct iu_entry *iue)
-{
-	kfifo_in_locked(&iue->target->iu_queue.queue, (void *) &iue,
-			sizeof(void *), &iue->target->iu_queue.lock);
-}
-EXPORT_SYMBOL_GPL(srp_iu_put);
-
-static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
-			   enum dma_data_direction dir, srp_rdma_t rdma_io,
-			   int dma_map, int ext_desc)
-{
-	struct iu_entry *iue = NULL;
-	struct scatterlist *sg = NULL;
-	int err, nsg = 0, len;
-
-	if (dma_map) {
-		iue = (struct iu_entry *) sc->SCp.ptr;
-		sg = scsi_sglist(sc);
-		nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
-				 DMA_BIDIRECTIONAL);
-		if (!nsg) {
-			pr_err("libsrp: fail to map %p %d\n",
-				iue, scsi_sg_count(sc));
-			return 0;
-		}
-		len = min(scsi_bufflen(sc), be32_to_cpu(md->len));
-	} else
-		len = be32_to_cpu(md->len);
-
-	err = rdma_io(sc, sg, nsg, md, 1, dir, len);
-
-	if (dma_map)
-		dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
-
-	return err;
-}
-
-static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
-			     struct srp_indirect_buf *id,
-			     enum dma_data_direction dir, srp_rdma_t rdma_io,
-			     int dma_map, int ext_desc)
-{
-	struct iu_entry *iue = NULL;
-	struct srp_direct_buf *md = NULL;
-	struct scatterlist dummy, *sg = NULL;
-	dma_addr_t token = 0;
-	int err = 0;
-	int nmd, nsg = 0, len;
-
-	if (dma_map || ext_desc) {
-		iue = (struct iu_entry *) sc->SCp.ptr;
-		sg = scsi_sglist(sc);
-	}
-
-	nmd = be32_to_cpu(id->table_desc.len) / sizeof(struct srp_direct_buf);
-
-	if ((dir == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) ||
-	    (dir == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt)) {
-		md = &id->desc_list[0];
-		goto rdma;
-	}
-
-	if (ext_desc && dma_map) {
-		md = dma_alloc_coherent(iue->target->dev,
-					be32_to_cpu(id->table_desc.len),
-					&token, GFP_KERNEL);
-		if (!md) {
-			pr_err("libsrp: Can't get dma memory %u\n",
-				be32_to_cpu(id->table_desc.len));
-			return -ENOMEM;
-		}
-
-		sg_init_one(&dummy, md, be32_to_cpu(id->table_desc.len));
-		sg_dma_address(&dummy) = token;
-		sg_dma_len(&dummy) = be32_to_cpu(id->table_desc.len);
-		err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
-			      be32_to_cpu(id->table_desc.len));
-		if (err) {
-			pr_err("libsrp: Error copying indirect table %d\n",
-				err);
-			goto free_mem;
-		}
-	} else {
-		pr_err("libsrp: This command uses external indirect buffer\n");
-		return -EINVAL;
-	}
-
-rdma:
-	if (dma_map) {
-		nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
-				 DMA_BIDIRECTIONAL);
-		if (!nsg) {
-			pr_err("libsrp: fail to map %p %d\n",
-				iue, scsi_sg_count(sc));
-			err = -EIO;
-			goto free_mem;
-		}
-		len = min(scsi_bufflen(sc), be32_to_cpu(id->len));
-	} else
-		len = be32_to_cpu(id->len);
-
-	err = rdma_io(sc, sg, nsg, md, nmd, dir, len);
-
-	if (dma_map)
-		dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
-
-free_mem:
-	if (token && dma_map) {
-		dma_free_coherent(iue->target->dev,
-				  be32_to_cpu(id->table_desc.len), md, token);
-	}
-	return err;
-}
-
-static int data_out_desc_size(struct srp_cmd *cmd)
-{
-	int size = 0;
-	u8 fmt = cmd->buf_fmt >> 4;
-
-	switch (fmt) {
-	case SRP_NO_DATA_DESC:
-		break;
-	case SRP_DATA_DESC_DIRECT:
-		size = sizeof(struct srp_direct_buf);
-		break;
-	case SRP_DATA_DESC_INDIRECT:
-		size = sizeof(struct srp_indirect_buf) +
-			sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt;
-		break;
-	default:
-		pr_err("libsrp: client error. Invalid data_out_format %x\n",
-			fmt);
-		break;
-	}
-	return size;
-}
-
-/*
- * TODO: this can be called multiple times for a single command if it
- * has very long data.
- */
-int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
-		      srp_rdma_t rdma_io, int dma_map, int ext_desc)
-{
-	struct srp_direct_buf *md;
-	struct srp_indirect_buf *id;
-	enum dma_data_direction dir;
-	int offset, err = 0;
-	u8 format;
-
-	offset = cmd->add_cdb_len & ~3;
-
-	dir = srp_cmd_direction(cmd);
-	if (dir == DMA_FROM_DEVICE)
-		offset += data_out_desc_size(cmd);
-
-	if (dir == DMA_TO_DEVICE)
-		format = cmd->buf_fmt >> 4;
-	else
-		format = cmd->buf_fmt & ((1U << 4) - 1);
-
-	switch (format) {
-	case SRP_NO_DATA_DESC:
-		break;
-	case SRP_DATA_DESC_DIRECT:
-		md = (struct srp_direct_buf *)
-			(cmd->add_data + offset);
-		err = srp_direct_data(sc, md, dir, rdma_io, dma_map, ext_desc);
-		break;
-	case SRP_DATA_DESC_INDIRECT:
-		id = (struct srp_indirect_buf *)
-			(cmd->add_data + offset);
-		err = srp_indirect_data(sc, cmd, id, dir, rdma_io, dma_map,
-					ext_desc);
-		break;
-	default:
-		pr_err("libsrp: Unknown format %d %x\n", dir, format);
-		err = -EINVAL;
-	}
-
-	return err;
-}
-EXPORT_SYMBOL_GPL(srp_transfer_data);
-
-u64 srp_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
-{
-	struct srp_direct_buf *md;
-	struct srp_indirect_buf *id;
-	u64 len = 0;
-	unsigned offset = cmd->add_cdb_len & ~3;
-	u8 fmt;
-
-	if (dir == DMA_TO_DEVICE)
-		fmt = cmd->buf_fmt >> 4;
-	else {
-		fmt = cmd->buf_fmt & ((1U << 4) - 1);
-		offset += data_out_desc_size(cmd);
-	}
-
-	switch (fmt) {
-	case SRP_NO_DATA_DESC:
-		break;
-	case SRP_DATA_DESC_DIRECT:
-		md = (struct srp_direct_buf *) (cmd->add_data + offset);
-		len = be32_to_cpu(md->len);
-		break;
-	case SRP_DATA_DESC_INDIRECT:
-		id = (struct srp_indirect_buf *) (cmd->add_data + offset);
-		len = be32_to_cpu(id->len);
-		break;
-	default:
-		pr_err("invalid data format %x\n", fmt);
-		break;
-	}
-	return len;
-}
-EXPORT_SYMBOL_GPL(srp_data_length);
-
-MODULE_DESCRIPTION("SCSI RDMA Protocol lib functions");
-MODULE_AUTHOR("FUJITA Tomonori");
-MODULE_LICENSE("GPL");
diff --git a/include/scsi/libsrp.h b/include/scsi/libsrp.h
deleted file mode 100644
index f9b2d8f..0000000
--- a/include/scsi/libsrp.h
+++ /dev/null
@@ -1,95 +0,0 @@
-#ifndef __LIBSRP_H__
-#define __LIBSRP_H__
-
-#include <linux/list.h>
-#include <linux/kfifo.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_host.h>
-#include <scsi/srp.h>
-#include <target/target_core_base.h>
-
-enum srp_task_attributes {
-	SRP_SIMPLE_TASK = 0,
-	SRP_HEAD_TASK = 1,
-	SRP_ORDERED_TASK = 2,
-	SRP_ACA_TASK = 4
-};
-
-enum iue_flags {
-	V_DIOVER,
-	V_WRITE,
-	V_LINKED,
-	V_FLYING,
-};
-
-enum {
-	SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE           = 0,
-	SRP_REQUEST_FIELDS_INVALID                      = 2,
-	SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED      = 4,
-	SRP_TASK_MANAGEMENT_FUNCTION_FAILED             = 5
-};
-
-struct srp_buf {
-	dma_addr_t dma;
-	void *buf;
-};
-
-struct srp_queue {
-	void *pool;
-	void *items;
-	struct kfifo queue;
-	spinlock_t lock;
-};
-
-struct srp_target {
-	struct Scsi_Host *shost;
-	struct se_device *tgt;
-	struct device *dev;
-
-	spinlock_t lock;
-	struct list_head cmd_queue;
-
-	size_t srp_iu_size;
-	struct srp_queue iu_queue;
-	size_t rx_ring_size;
-	struct srp_buf **rx_ring;
-
-	void *ldata;
-};
-
-struct iu_entry {
-	struct srp_target *target;
-
-	struct list_head ilist;
-	dma_addr_t remote_token;
-	unsigned long flags;
-
-	struct srp_buf *sbuf;
-};
-
-typedef int (srp_rdma_t)(struct scsi_cmnd *, struct scatterlist *, int,
-			 struct srp_direct_buf *, int,
-			 enum dma_data_direction, unsigned int);
-extern int srp_target_alloc(struct srp_target *, struct device *,
-				size_t, size_t);
-extern void srp_target_free(struct srp_target *);
-
-extern struct iu_entry *srp_iu_get(struct srp_target *);
-extern void srp_iu_put(struct iu_entry *);
-
-extern int srp_transfer_data(struct scsi_cmnd *, struct srp_cmd *,
-			     srp_rdma_t, int, int);
-
-static inline struct srp_target *host_to_srp_target(struct Scsi_Host *host)
-{
-	return (struct srp_target *) host->hostdata;
-}
-
-static inline int srp_cmd_direction(struct srp_cmd *cmd)
-{
-	return (cmd->buf_fmt >> 4) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
-}
-
-extern u64 srp_data_length(struct srp_cmd *cmd, enum dma_data_direction dir);
-
-#endif
-- 
2.5.4 (Apple Git-61)

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 3/3] ibmvscsis: clean up functions
  2016-05-25 14:17 ` IBM VSCSI Target Driver Initial Patch Sets Bryant G. Ly
  2016-05-25 14:17   ` [PATCH 2/3] ibmvscsis: Addressing Bart's comments Bryant G. Ly
@ 2016-05-25 14:17   ` Bryant G. Ly
  2016-05-25 14:44     ` Joe Perches
  1 sibling, 1 reply; 17+ messages in thread
From: Bryant G. Ly @ 2016-05-25 14:17 UTC (permalink / raw)
  To: tyreld, bart.vanassche, joe
  Cc: martin.petersen, akpm, kvalo, davem, mchehab, jslaby, bp,
	linux-kernel, linux-scsi, target-devel, bryantly

From: bryantly <bryantly@linux.vnet.ibm.com>

This patch removes forward declarations and re-organizes the
functions within the driver. This patch also fixes MAINTAINERS
for ibmvscsis.

Signed-off-by: bryantly <bryantly@linux.vnet.ibm.com>
---
 MAINTAINERS                       |    4 +-
 drivers/scsi/ibmvscsi/ibmvscsis.c | 2709 ++++++++++++++++++-------------------
 2 files changed, 1315 insertions(+), 1398 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index a11905c..3f09a15 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5388,8 +5388,8 @@ L:	target-devel@vger.kernel.org
 S:	Supported
 F:	drivers/scsi/ibmvscsi/ibmvscsis.c
 F:	drivers/scsi/ibmvscsi/ibmvscsis.h
-F:	drivers/scsi/libsrp.h
-F:	drivers/scsi/libsrp.c
+F:	drivers/scsi/ibmvscsi/libsrp.c
+F:	drivers/scsi/ibmvscsi/libsrp.h
 
 IBM Power Virtual FC Device Drivers
 M:	Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
diff --git a/drivers/scsi/ibmvscsi/ibmvscsis.c b/drivers/scsi/ibmvscsi/ibmvscsis.c
index 6f9e9ba..610f4f5 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsis.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsis.c
@@ -62,88 +62,17 @@
 
 #define SRP_RSP_SENSE_DATA_LEN	18
 
+static const char ibmvscsis_driver_name[] = "ibmvscsis";
+static char system_id[SYS_ID_NAME_LEN] = "";
+static char partition_name[PARTITION_NAMELEN] = "UNKNOWN";
+static unsigned int partition_number = -1;
+
 static struct workqueue_struct *vtgtd;
 static unsigned max_vdma_size = MAX_H_COPY_RDMA;
 
 static DEFINE_SPINLOCK(ibmvscsis_dev_lock);
 static LIST_HEAD(ibmvscsis_dev_list);
 
-static int ibmvscsis_probe(struct vio_dev *vdev,
-			   const struct vio_device_id *id);
-static void ibmvscsis_dev_release(struct device *dev);
-static void ibmvscsis_modify_rep_luns(struct se_cmd *se_cmd);
-static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd);
-static int read_dma_window(struct vio_dev *vdev,
-			   struct ibmvscsis_adapter *adapter);
-static char *ibmvscsis_get_fabric_name(void);
-static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg);
-static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg);
-static u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg);
-static int ibmvscsis_check_true(struct se_portal_group *se_tpg);
-static int ibmvscsis_check_false(struct se_portal_group *se_tpg);
-static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg);
-static int ibmvscsis_check_stop_free(struct se_cmd *se_cmd);
-static void ibmvscsis_release_cmd(struct se_cmd *se_cmd);
-static int ibmvscsis_shutdown_session(struct se_session *se_sess);
-static void ibmvscsis_close_session(struct se_session *se_sess);
-static u32 ibmvscsis_sess_get_index(struct se_session *se_sess);
-static int ibmvscsis_write_pending(struct se_cmd *se_cmd);
-static int ibmvscsis_write_pending_status(struct se_cmd *se_cmd);
-static void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl);
-static int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd);
-static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd);
-static int ibmvscsis_queue_status(struct se_cmd *se_cmd);
-static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd);
-static void ibmvscsis_aborted_task(struct se_cmd *se_cmd);
-static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf,
-					   struct config_group *group,
-					   const char *name);
-static void ibmvscsis_drop_tport(struct se_wwn *wwn);
-static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
-						  struct config_group *group,
-						  const char *name);
-static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg);
-static int ibmvscsis_remove(struct vio_dev *vdev);
-static ssize_t system_id_show(struct device *dev,
-			      struct device_attribute *attr,
-			      char *buf);
-static ssize_t partition_number_show(struct device *dev,
-				     struct device_attribute *attr,
-				     char *buf);
-static ssize_t unit_address_show(struct device *dev,
-				 struct device_attribute *attr, char *buf);
-static int get_system_info(void);
-static irqreturn_t ibmvscsis_interrupt(int dummy, void *data);
-static int process_srp_iu(struct iu_entry *iue);
-static void process_iu(struct viosrp_crq *crq,
-		       struct ibmvscsis_adapter *adapter);
-static void process_crq(struct viosrp_crq *crq,
-			struct ibmvscsis_adapter *adapter);
-static void handle_crq(struct work_struct *work);
-static int ibmvscsis_reset_crq_queue(struct ibmvscsis_adapter *adapter);
-static void crq_queue_destroy(struct ibmvscsis_adapter *adapter);
-static inline struct viosrp_crq *next_crq(struct crq_queue *queue);
-static int send_iu(struct iu_entry *iue, u64 length, u8 format);
-static int send_adapter_info(struct iu_entry *iue,
-			     dma_addr_t remote_buffer, u16 length);
-static int process_mad_iu(struct iu_entry *iue);
-static void ibmvscsis_srp_i_logout(struct iu_entry *iue);
-static void process_login(struct iu_entry *iue);
-static void process_tsk_mgmt(struct ibmvscsis_adapter *adapter,
-			     struct iu_entry *iue);
-static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg,
-			  int nsg, struct srp_direct_buf *md, int nmd,
-			  enum dma_data_direction dir, unsigned int rest);
-static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
-				  struct iu_entry *iue);
-static u64 ibmvscsis_unpack_lun(const u8 *lun, int len);
-static int tcm_queuecommand(struct ibmvscsis_adapter *adapter,
-			    struct ibmvscsis_cmnd *vsc,
-			    struct srp_cmd *scmd);
-static void ibmvscsis_determine_resid(struct se_cmd *se_cmd,
-				      struct srp_rsp *rsp);
-static bool connection_broken(struct ibmvscsis_adapter *adapter);
-
 static inline long h_copy_rdma(s64 length, u64 sliobn, u64 slioba,
 			       u64 dliobn, u64 dlioba)
 {
@@ -189,986 +118,759 @@ static inline long h_send_crq(struct ibmvscsis_adapter *adapter,
 	return rc;
 }
 
-/*****************************************************************************/
-/* Global device driver data areas                                           */
-/*****************************************************************************/
-
-static const char ibmvscsis_driver_name[] = "ibmvscsis";
-static char system_id[SYS_ID_NAME_LEN] = "";
-static char partition_name[PARTITION_NAMELEN] = "UNKNOWN";
-static unsigned int partition_number = -1;
+static void ibmvscsis_determine_resid(struct se_cmd *se_cmd,
+				      struct srp_rsp *rsp)
+{
+	if (se_cmd->residual_count) {
+		if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
+			if (se_cmd->data_direction == DMA_TO_DEVICE) {
+				/* residual data from an underflow write */
+				rsp->flags = SRP_RSP_FLAG_DOUNDER;
+				rsp->data_out_res_cnt =
+					cpu_to_be32(se_cmd->residual_count);
+			} else if (se_cmd->data_direction == DMA_FROM_DEVICE) {
+				/* residual data from an underflow read */
+				rsp->flags = SRP_RSP_FLAG_DIUNDER;
+				rsp->data_in_res_cnt =
+					cpu_to_be32(se_cmd->residual_count);
+			}
+		} else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
+			if (se_cmd->data_direction == DMA_TO_DEVICE) {
+				/*  residual data from an overflow write */
+				rsp->flags = SRP_RSP_FLAG_DOOVER;
+				rsp->data_out_res_cnt =
+					cpu_to_be32(se_cmd->residual_count);
+			} else if (se_cmd->data_direction ==
+				   DMA_FROM_DEVICE) {
+				/* residual data from an overflow read */
+				rsp->flags = SRP_RSP_FLAG_DIOVER;
+				rsp->data_in_res_cnt =
+					cpu_to_be32(se_cmd->residual_count);
+			}
+		}
+	}
+}
 
-static struct class_attribute ibmvscsis_class_attrs[] = {
-	__ATTR_NULL,
-};
+static bool connection_broken(struct ibmvscsis_adapter *adapter)
+{
+	u64 buffer[2];
+	struct viosrp_crq *crq;
+	long h_return_code;
+	bool rc = false;
 
-static struct device_attribute dev_attr_system_id =
-	__ATTR(system_id, S_IRUGO, system_id_show, NULL);
+	/* create a PING crq */
+	crq = (struct viosrp_crq *)&buffer;
+	buffer[0] = 0;
+	buffer[1] = 0;
+	crq->valid = 0x80;
+	crq->format = 6;
+	crq->status = 0xF5;
 
-static struct device_attribute dev_attr_partition_number =
-	__ATTR(partition_number, S_IRUGO, partition_number_show, NULL);
+	h_return_code = h_send_crq(adapter,
+				   cpu_to_be64(buffer[0]),
+				   cpu_to_be64(buffer[1]));
 
-static struct device_attribute dev_attr_unit_address =
-	__ATTR(unit_address, S_IRUGO, unit_address_show, NULL);
+	pr_debug("connection_broken: rc %ld\n", h_return_code);
 
-static struct attribute *ibmvscsis_dev_attrs[] = {
-	&dev_attr_system_id.attr,
-	&dev_attr_partition_number.attr,
-	&dev_attr_unit_address.attr,
-};
-ATTRIBUTE_GROUPS(ibmvscsis_dev);
+	if (h_return_code == H_CLOSED)
+		rc = true;
 
-static struct class ibmvscsis_class = {
-	.name           = "ibmvscsis",
-	.dev_release    = ibmvscsis_dev_release,
-	.class_attrs    = ibmvscsis_class_attrs,
-	.dev_groups     = ibmvscsis_dev_groups,
-};
+	return rc;
+}
 
-static ssize_t ibmvscsis_wwn_version_show(struct config_item *item,
-					  char *page)
+static u64 ibmvscsis_unpack_lun(const u8 *lun, int len)
 {
-	return scnprintf(page, PAGE_SIZE, "%s\n", IBMVSCSIS_VERSION);
-}
-CONFIGFS_ATTR_RO(ibmvscsis_wwn_, version);
+	u64 res = NO_SUCH_LUN;
+	int addressing_method;
 
-static struct configfs_attribute *ibmvscsis_wwn_attrs[] = {
-	&ibmvscsis_wwn_attr_version,
-	NULL,
-};
+	if (unlikely(len < 2)) {
+		pr_err("Illegal LUN length %d, expected 2 bytes or more\n",
+		       len);
+		goto out;
+	}
 
-static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item,
-					 char *page)
-{
-	struct se_portal_group *se_tpg = to_tpg(item);
-	struct ibmvscsis_tport *tport = container_of(se_tpg,
-						     struct ibmvscsis_tport,
-						     se_tpg);
+	switch (len) {
+	case 8:
+		if ((*((__be64 *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0)
+			goto out_err;
+		break;
+	case 4:
+		if (*((__be16 *)&lun[2]) != 0)
+			goto out_err;
+		break;
+	case 6:
+		if (*((__be32 *)&lun[2]) != 0)
+			goto out_err;
+		break;
+	case 2:
+		break;
+	default:
+		goto out_err;
+	}
 
-	return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0);
+	addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */
+	switch (addressing_method) {
+	case SCSI_LUN_ADDR_METHOD_PERIPHERAL:
+	case SCSI_LUN_ADDR_METHOD_FLAT:
+	case SCSI_LUN_ADDR_METHOD_LUN:
+		res = *(lun + 1) | (((*lun) & 0x3f) << 8);
+		break;
+
+	case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN:
+	default:
+		pr_err("Unimplemented LUN addressing method %u\n",
+		       addressing_method);
+		break;
+	}
+
+out:
+	return res;
+out_err:
+	pr_err("Support for multi-level LUNs has not yet been implemented\n");
+	goto out;
 }
 
-static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item,
-					  const char *page, size_t count)
+static void ibmvscsis_modify_rep_luns(struct se_cmd *se_cmd)
 {
-	struct se_portal_group *se_tpg = to_tpg(item);
-	struct ibmvscsis_tport *tport = container_of(se_tpg,
-						     struct ibmvscsis_tport,
-						     se_tpg);
-	unsigned long tmp;
-	int ret;
+	s32 len = se_cmd->data_length;
+	u16 data_len;
+	unsigned char *buf = NULL;
 
-	ret = kstrtoul(page, 0, &tmp);
-	if (ret < 0) {
-		pr_err("Unable to extract ibmvscsis_tpg_store_enable\n");
-		return -EINVAL;
-	}
+	if (len <= 8)
+		return;
 
-	if ((tmp != 0) && (tmp != 1)) {
-		pr_err("Illegal value for ibmvscsis_tpg_store_enable: %lu\n",
-		       tmp);
-		return -EINVAL;
+	len -= 8;
+	buf = transport_kmap_data_sg(se_cmd);
+	if (buf) {
+		data_len = be32_to_cpu(*(u32 *)buf);
+		pr_debug("modify_rep_luns: len %d data_len %hud\n",
+			 len, data_len);
+		if (data_len < len)
+			len = data_len;
+		buf += 8;
+		while (len > 0) {
+			*buf |= SCSI_LUN_ADDR_METHOD_FLAT << 6;
+			len -= 8;
+			buf += 8;
+		}
+		transport_kunmap_data_sg(se_cmd);
 	}
+}
 
-	if (tmp == 1)
-		tport->enabled = true;
-	else
-		tport->enabled = false;
+/*
+ * This function modifies the inquiry data prior to sending to initiator
+ * so that we can make support current AIX. Internally we are going to
+ * add new ODM entries to support the emulation from LIO. This function
+ * is temporary until those changes are done.
+ */
+static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd)
+{
+	struct se_device *dev = se_cmd->se_dev;
+	unsigned char *buf = NULL;
+	u32 cmd_len = se_cmd->data_length;
 
-	return count;
+	if (cmd_len <= INQ_DATA_OFFSET)
+		return;
+
+	buf = transport_kmap_data_sg(se_cmd);
+	if (buf) {
+		memcpy(&buf[8], "IBM	     ", 8);
+		if (dev->transport->get_device_type(dev) == TYPE_ROM)
+			memcpy(&buf[16], "VOPTA           ", 16);
+		else
+			memcpy(&buf[16], "3303      NVDISK", 16);
+		memcpy(&buf[32], "0001", 4);
+		transport_kunmap_data_sg(se_cmd);
+	}
 }
-CONFIGFS_ATTR(ibmvscsis_tpg_, enable);
 
-static struct configfs_attribute *ibmvscsis_tpg_attrs[] = {
-			&ibmvscsis_tpg_attr_enable,
-			NULL,
-};
+static int read_dma_window(struct vio_dev *vdev,
+			   struct ibmvscsis_adapter *adapter)
+{
+	const __be32 *dma_window;
+	const __be32 *prop;
 
-static const struct target_core_fabric_ops ibmvscsis_ops = {
-	.module				= THIS_MODULE,
-	.name				= "ibmvscsis",
-	.max_data_sg_nents		= SCSI_MAX_SG_SEGMENTS,
-	.get_fabric_name		= ibmvscsis_get_fabric_name,
-	.tpg_get_wwn			= ibmvscsis_get_fabric_wwn,
-	.tpg_get_tag			= ibmvscsis_get_tag,
-	.tpg_get_default_depth		= ibmvscsis_get_default_depth,
-	.tpg_check_demo_mode		= ibmvscsis_check_true,
-	.tpg_check_demo_mode_cache	= ibmvscsis_check_true,
-	.tpg_check_demo_mode_write_protect = ibmvscsis_check_false,
-	.tpg_check_prod_mode_write_protect = ibmvscsis_check_false,
-	.tpg_get_inst_index		= ibmvscsis_tpg_get_inst_index,
-	.check_stop_free		= ibmvscsis_check_stop_free,
-	.release_cmd			= ibmvscsis_release_cmd,
-	.shutdown_session		= ibmvscsis_shutdown_session,
-	.close_session			= ibmvscsis_close_session,
-	.sess_get_index			= ibmvscsis_sess_get_index,
-	.write_pending			= ibmvscsis_write_pending,
-	.write_pending_status		= ibmvscsis_write_pending_status,
-	.set_default_node_attributes	= ibmvscsis_set_default_node_attrs,
-	.get_cmd_state			= ibmvscsis_get_cmd_state,
-	.queue_data_in			= ibmvscsis_queue_data_in,
-	.queue_status			= ibmvscsis_queue_status,
-	.queue_tm_rsp			= ibmvscsis_queue_tm_rsp,
-	.aborted_task			= ibmvscsis_aborted_task,
-	/*
-	 * Setup function pointers for logic in target_cor_fabric_configfs.c
-	 */
-	.fabric_make_wwn		= ibmvscsis_make_tport,
-	.fabric_drop_wwn		= ibmvscsis_drop_tport,
-	.fabric_make_tpg		= ibmvscsis_make_tpg,
-	.fabric_drop_tpg		= ibmvscsis_drop_tpg,
-
-	.tfc_wwn_attrs			= ibmvscsis_wwn_attrs,
-	.tfc_tpg_base_attrs		= ibmvscsis_tpg_attrs,
-};
-
-static struct vio_device_id ibmvscsis_device_table[] = {
-	{"v-scsi-host", "IBM,v-scsi-host"},
-	{"", ""}
-};
-MODULE_DEVICE_TABLE(vio, ibmvscsis_device_table);
-
-static struct vio_driver ibmvscsis_driver = {
-	.name = ibmvscsis_driver_name,
-	.id_table = ibmvscsis_device_table,
-	.probe = ibmvscsis_probe,
-	.remove = ibmvscsis_remove,
-};
-
-/*****************************************************************************/
-/* End of global device driver data areas                                    */
-/*****************************************************************************/
-static int crq_queue_create(struct crq_queue *queue,
-			    struct ibmvscsis_adapter *adapter)
-{
-	int retrc;
-	int err;
-	struct vio_dev *vdev = adapter->dma_dev;
-
-	queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
-
-	if (!queue->msgs)
-		goto malloc_failed;
-
-	queue->size = PAGE_SIZE / sizeof(*queue->msgs);
-
-	queue->msg_token = dma_map_single(&vdev->dev, queue->msgs,
-					  queue->size * sizeof(*queue->msgs),
-					  DMA_BIDIRECTIONAL);
-
-	if (dma_mapping_error(&vdev->dev, queue->msg_token))
-		goto map_failed;
-
-	err = h_reg_crq(vdev->unit_address, queue->msg_token,
-			PAGE_SIZE);
-	retrc = err;
-
-	/* If the adapter was left active for some reason (like kexec)
-	 * try freeing and re-registering
+	/* TODO Using of_parse_dma_window would be better, but it doesn't give
+	 * a way to read multiple windows without already knowing the size of
+	 * a window or the number of windows
 	 */
-	if (err == H_RESOURCE)
-		err = ibmvscsis_reset_crq_queue(adapter);
-	if (err == 2) {
-		pr_warn("Partner adapter not ready\n");
-		retrc = 0;
-	} else if (err != 0) {
-		pr_err("Error 0x%x opening virtual adapter\n", err);
-		goto reg_crq_failed;
+	dma_window =
+		(const __be32 *)vio_get_attribute(vdev, "ibm,my-dma-window",
+						  NULL);
+	if (!dma_window) {
+		pr_err("Couldn't find ibm,my-dma-window property\n");
+		return -1;
 	}
 
-	queue->cur = 0;
-	spin_lock_init(&queue->lock);
-
-	INIT_WORK(&adapter->crq_work, handle_crq);
+	adapter->liobn = be32_to_cpu(*dma_window);
+	dma_window++;
 
-	err = request_irq(vdev->irq, &ibmvscsis_interrupt,
-			  0, "ibmvscsis", adapter);
-	if (err) {
-		pr_err("Error 0x%x h_send_crq\n", err);
-		goto req_irq_failed;
+	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells",
+						 NULL);
+	if (!prop) {
+		pr_warn("Couldn't find ibm, #dma-address-cells property\n");
+		dma_window++;
+	} else {
+		dma_window += be32_to_cpu(*prop);
 	}
 
-	err = vio_enable_interrupts(vdev);
-	if (err != 0) {
-		pr_err("Error %d enabling interrupts!!!\n", err);
-		goto req_irq_failed;
+	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells",
+						 NULL);
+	if (!prop) {
+		pr_warn("Couldn't find ibm, #dma-size-cells property\n");
+		dma_window++;
+	} else {
+		dma_window += be32_to_cpu(*prop);
 	}
 
-	return retrc;
+	/* dma_window should point to the second window now */
+	adapter->riobn = be32_to_cpu(*dma_window);
 
-req_irq_failed:
-	h_free_crq(vdev->unit_address);
-reg_crq_failed:
-	dma_unmap_single(&vdev->dev, queue->msg_token,
-			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
-map_failed:
-	free_page((unsigned long)queue->msgs);
-malloc_failed:
-	return -1;
+	return 0;
 }
 
-static int ibmvscsis_probe(struct vio_dev *vdev, const struct vio_device_id *id)
+static struct ibmvscsis_tport *ibmvscsis_lookup_port(const char *name)
 {
-	int ret = -ENOMEM;
-	struct ibmvscsis_adapter *adapter;
-	struct srp_target *target;
 	struct ibmvscsis_tport *tport;
+	struct vio_dev *vdev;
+	struct ibmvscsis_adapter *adapter;
+	int ret;
 	unsigned long flags;
 
-	pr_debug("Probe for UA 0x%x\n", vdev->unit_address);
-
-	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
-	if (!adapter)
-		return ret;
-	target = kzalloc(sizeof(*target), GFP_KERNEL);
-	if (!target)
-		goto free_adapter;
-
-	adapter->dma_dev = vdev;
-	adapter->target = target;
-	tport = &adapter->tport;
+	spin_lock_irqsave(&ibmvscsis_dev_lock, flags);
+	list_for_each_entry(adapter, &ibmvscsis_dev_list, list) {
+		vdev = adapter->dma_dev;
+		ret = strcmp(dev_name(&vdev->dev), name);
+		if (ret == 0)
+			tport = &adapter->tport;
+		if (tport)
+			goto found;
+	}
+	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
+	return NULL;
+found:
+	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
+	return tport;
+}
 
-	tport->enabled = false;
-	snprintf(&adapter->tport.tport_name[0], 256, "%s",
-		 dev_name(&vdev->dev));
+static irqreturn_t ibmvscsis_interrupt(int dummy, void *data)
+{
+	struct ibmvscsis_adapter *adapter = data;
 
-	ret = read_dma_window(adapter->dma_dev, adapter);
-	if (ret != 0)
-		goto free_target;
+	vio_disable_interrupts(adapter->dma_dev);
+	queue_work(vtgtd, &adapter->crq_work);
 
-	pr_debug("Probe: liobn 0x%x, riobn 0x%x\n", adapter->liobn,
-		 adapter->riobn);
+	return IRQ_HANDLED;
+}
 
-	spin_lock_irqsave(&ibmvscsis_dev_lock, flags);
-	list_add_tail(&adapter->list, &ibmvscsis_dev_list);
-	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
+static int send_iu(struct iu_entry *iue, u64 length, u8 format)
+{
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
+	struct ibmvscsis_crq_msg crq_msg;
+	struct srp_rsp *rsp;
+	__be64 *crq_as_u64 = (__be64 *)&crq_msg;
+	long rc, rc1;
 
-	ret = srp_target_alloc(target, &vdev->dev,
-			       INITIAL_SRP_LIMIT,
-			       SRP_MAX_IU_LEN);
+	rsp = &vio_iu(iue)->srp.rsp;
+	pr_debug("send_iu: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
+		 (unsigned long)length,
+		 (unsigned long)adapter->liobn,
+		 (unsigned long)iue->sbuf->dma,
+		 (unsigned long)adapter->riobn,
+		 (unsigned long)be64_to_cpu(iue->remote_token));
 
-	adapter->target->ldata = adapter;
+	/* First copy the SRP */
+	rc = h_copy_rdma(length, adapter->liobn, iue->sbuf->dma,
+			 adapter->riobn, be64_to_cpu(iue->remote_token));
 
-	if (ret) {
-		pr_err("failed target alloc ret: %d\n", ret);
-		goto free_srp_target;
+	switch (rc) {
+	case H_SUCCESS:
+		break;
+	case H_PERMISSION:
+	case H_SOURCE_PARM:
+	case H_DEST_PARM:
+		if (connection_broken(adapter)) {
+			pr_debug("rdma connection broken\n");
+			goto end;
+		}
+		break;
+	default:
+		pr_err("Error %ld transferring data\n", rc);
+		length = 0;
+		break;
 	}
 
-	ret = crq_queue_create(&adapter->crq_queue, adapter);
-	if (ret != 0 && ret != H_RESOURCE) {
-		pr_err("failed crq_queue_create ret: %d\n", ret);
-		ret = -1;
-	}
+	pr_debug("crq pre cooked: 0x%x, 0x%llx, 0x%llx\n",
+		 format, length, vio_iu(iue)->srp.rsp.tag);
 
-	if (h_send_crq(adapter, 0xC001000000000000LL, 0) != 0 &&
-	    ret != H_RESOURCE) {
-		pr_warn("Failed to send CRQ message\n");
-		ret = 0;
-	}
+	crq_msg.valid = 0x80;
+	crq_msg.format = format;
+	crq_msg.rsvd = 0;
+	if (rc == 0)
+		crq_msg.status = 0x99;
+	else
+		crq_msg.status = rsp->status;
+	crq_msg.rsvd1 = 0;
+	crq_msg.IU_length = cpu_to_be16(length);
+	crq_msg.IU_data_ptr = vio_iu(iue)->srp.rsp.tag;
 
-	dev_set_drvdata(&vdev->dev, adapter);
+	pr_debug("send crq: 0x%x, 0x%llx, 0x%llx\n",
+		 adapter->dma_dev->unit_address,
+		 be64_to_cpu(crq_as_u64[0]),
+		 be64_to_cpu(crq_as_u64[1]));
 
-	return 0;
+	srp_iu_put(iue);
 
-free_srp_target:
-	srp_target_free(target);
-free_target:
-	kfree(target);
-free_adapter:
-	kfree(adapter);
-	return ret;
-}
+	rc1 = h_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
+			 be64_to_cpu(crq_as_u64[1]));
 
-static int ibmvscsis_remove(struct vio_dev *dev)
-{
-	unsigned long flags;
-	struct ibmvscsis_adapter *adapter = dev_get_drvdata(&dev->dev);
-	struct srp_target *target;
+	if (rc1) {
+		pr_err("%ld sending response\n", rc1);
+		return rc1;
+	}
+	return rc;
+end:
+	return rc;
+}
 
-	target = adapter->target;
+static int ibmvscsis_reset_crq_queue(struct ibmvscsis_adapter *adapter)
+{
+	int rc = 0;
+	struct vio_dev *vdev = adapter->dma_dev;
+	struct crq_queue *queue = &adapter->crq_queue;
 
-	spin_lock_irqsave(&ibmvscsis_dev_lock, flags);
-	list_del(&adapter->list);
-	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
+	/* Close the CRQ */
+	h_free_crq(vdev->unit_address);
 
-	crq_queue_destroy(adapter);
-	srp_target_free(target);
+	/* Clean out the queue */
+	memset(queue->msgs, 0x00, PAGE_SIZE);
+	queue->cur = 0;
 
-	kfree(target);
-	kfree(adapter);
+	/* And re-open it again */
+	rc = h_reg_crq(vdev->unit_address, queue->msg_token, PAGE_SIZE);
+	if (rc == 2)
+		/* Adapter is good, but other end is not ready */
+		pr_warn("Partner adapter not ready\n");
+	else if (rc != 0)
+		pr_err("Couldn't register crq--rc 0x%x\n", rc);
 
-	return 0;
+	return rc;
 }
 
-static void ibmvscsis_modify_rep_luns(struct se_cmd *se_cmd)
+static int send_adapter_info(struct iu_entry *iue,
+			     dma_addr_t remote_buffer, u16 length)
 {
-	s32 len = se_cmd->data_length;
-	u16 data_len;
-	unsigned char *buf = NULL;
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
+	dma_addr_t data_token;
+	struct viosrp_adapter_info *mad = &vio_iu(iue)->mad.adapter_info;
+	struct mad_adapter_info_data *info;
+	int err;
 
-	if (len <= 8)
-		return;
+	mad->common.status = cpu_to_be16(VIOSRP_MAD_SUCCESS);
 
-	len -= 8;
-	buf = transport_kmap_data_sg(se_cmd);
-	if (buf) {
-		data_len = be32_to_cpu(*(u32 *)buf);
-		pr_debug("modify_rep_luns: len %d data_len %hud\n",
-			 len, data_len);
-		if (data_len < len)
-			len = data_len;
-		buf += 8;
-		while (len > 0) {
-			*buf |= SCSI_LUN_ADDR_METHOD_FLAT << 6;
-			len -= 8;
-			buf += 8;
-		}
-		transport_kunmap_data_sg(se_cmd);
+	if (be16_to_cpu(mad->common.length) > sizeof(*info)) {
+		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
+		return 0;
 	}
-}
 
-/*
- * This function modifies the inquiry data prior to sending to initiator
- * so that we can make support current AIX. Internally we are going to
- * add new ODM entries to support the emulation from LIO. This function
- * is temporary until those changes are done.
- */
-static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd)
-{
-	struct se_device *dev = se_cmd->se_dev;
-	unsigned char *buf = NULL;
-	u32 cmd_len = se_cmd->data_length;
+	info = dma_alloc_coherent(&adapter->dma_dev->dev, sizeof(*info),
+				  &data_token, GFP_KERNEL);
+	if (!info) {
+		pr_err("bad dma_alloc_coherent %p\n", target);
+		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
+		return 1;
+	}
 
-	if (cmd_len <= INQ_DATA_OFFSET)
-		return;
+	/* Get remote info */
+	err = h_copy_rdma(sizeof(*info), adapter->riobn,
+			  be64_to_cpu(remote_buffer),
+			  adapter->liobn, data_token);
 
-	buf = transport_kmap_data_sg(se_cmd);
-	if (buf) {
-		memcpy(&buf[8], "IBM	     ", 8);
-		if (dev->transport->get_device_type(dev) == TYPE_ROM)
-			memcpy(&buf[16], "VOPTA           ", 16);
-		else
-			memcpy(&buf[16], "3303      NVDISK", 16);
-		memcpy(&buf[32], "0001", 4);
-		transport_kunmap_data_sg(se_cmd);
-	}
-}
+	if (err == H_SUCCESS) {
+		pr_err("Client connect: %s (%d)\n",
+		       info->partition_name, info->partition_number);
 
-static int read_dma_window(struct vio_dev *vdev,
-			   struct ibmvscsis_adapter *adapter)
-{
-	const __be32 *dma_window;
-	const __be32 *prop;
+		if (adapter->client_data.partition_number == 0)
+			adapter->client_data.partition_number =
+				be32_to_cpu(info->partition_number);
+		strncpy(adapter->client_data.srp_version, info->srp_version,
+			sizeof(adapter->client_data.srp_version));
+		strncpy(adapter->client_data.partition_name,
+			info->partition_name,
+			sizeof(adapter->client_data.partition_name));
+		adapter->client_data.mad_version =
+						be32_to_cpu(info->mad_version);
+		adapter->client_data.os_type = be32_to_cpu(info->os_type);
+		pr_debug("adapter info client adapter %u\n",
+			 adapter->client_data.os_type);
 
-	/* TODO Using of_parse_dma_window would be better, but it doesn't give
-	 * a way to read multiple windows without already knowing the size of
-	 * a window or the number of windows
-	 */
-	dma_window =
-		(const __be32 *)vio_get_attribute(vdev, "ibm,my-dma-window",
-						  NULL);
-	if (!dma_window) {
-		pr_err("Couldn't find ibm,my-dma-window property\n");
-		return -1;
-	}
+		strcpy(info->srp_version, "16.a");
+		strncpy(info->partition_name, partition_name,
+			sizeof(info->partition_name));
 
-	adapter->liobn = be32_to_cpu(*dma_window);
-	dma_window++;
+		info->partition_number = cpu_to_be32(partition_number);
+		info->mad_version = cpu_to_be32(1);
+		info->os_type = cpu_to_be32(2);
+		memset(&info->port_max_txu[0], 0, sizeof(info->port_max_txu));
+		info->port_max_txu[0] = cpu_to_be32(SCSI_MAX_SG_SEGMENTS *
+						    PAGE_SIZE);
 
-	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells",
-						 NULL);
-	if (!prop) {
-		pr_warn("Couldn't find ibm, #dma-address-cells property\n");
-		dma_window++;
-	} else {
-		dma_window += be32_to_cpu(*prop);
-	}
+		dma_rmb();
+		/* Send our info to remote */
+		err = h_copy_rdma(sizeof(*info), adapter->liobn, data_token,
+				  adapter->riobn, be64_to_cpu(remote_buffer));
 
-	prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells",
-						 NULL);
-	if (!prop) {
-		pr_warn("Couldn't find ibm, #dma-size-cells property\n");
-		dma_window++;
+		switch (err) {
+		case H_SUCCESS:
+			break;
+		case H_PERMISSION:
+		case H_SOURCE_PARM:
+		case H_DEST_PARM:
+			if (connection_broken(adapter))
+				pr_debug("rdma connection broken\n");
+		default:
+			pr_err("Error sending adapter info %d\n",
+			       err);
+			return -EIO;
+		}
 	} else {
-		dma_window += be32_to_cpu(*prop);
+		pr_err("Error sending adapter info %d\n", err);
+		return 1;
 	}
 
-	/* dma_window should point to the second window now */
-	adapter->riobn = be32_to_cpu(*dma_window);
+	dma_free_coherent(&adapter->dma_dev->dev, sizeof(*info), info,
+			  data_token);
 
 	return 0;
 }
 
-static void ibmvscsis_dev_release(struct device *dev) {};
-
-static char *ibmvscsis_get_fabric_name(void)
-{
-	return "ibmvscsis";
-}
-
-static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg)
-{
-	struct ibmvscsis_tport *tport =
-		container_of(se_tpg, struct ibmvscsis_tport, se_tpg);
-
-	return &tport->tport_name[0];
-}
-
-static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg)
+static int process_mad_iu(struct iu_entry *iue)
 {
-	struct ibmvscsis_tport *tport =
-		container_of(se_tpg, struct ibmvscsis_tport, se_tpg);
+	union viosrp_iu *iu = vio_iu(iue);
+	struct viosrp_adapter_info *info;
+	struct viosrp_host_config *conf;
 
-	return tport->tport_tpgt;
-}
+	switch (be32_to_cpu(iu->mad.empty_iu.common.type)) {
+	case VIOSRP_EMPTY_IU_TYPE:
+		pr_err("%s\n", "Unsupported EMPTY MAD IU");
+		break;
+	case VIOSRP_ERROR_LOG_TYPE:
+		pr_err("%s\n", "Unsupported ERROR LOG MAD IU");
+		iu->mad.error_log.common.status = 1;
+		send_iu(iue, sizeof(iu->mad.error_log),	VIOSRP_MAD_FORMAT);
+		break;
+	case VIOSRP_ADAPTER_INFO_TYPE:
+		info = &iu->mad.adapter_info;
+		info->common.status = send_adapter_info(iue, info->buffer,
+							info->common.length);
+		send_iu(iue, sizeof(*info), VIOSRP_MAD_FORMAT);
+		break;
+	case VIOSRP_HOST_CONFIG_TYPE:
+		conf = &iu->mad.host_config;
+		conf->common.status = 1;
+		send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT);
+		break;
+	default:
+		pr_err("Unknown type %u\n", iu->srp.rsp.opcode);
+		iu->mad.empty_iu.common.status =
+					cpu_to_be16(VIOSRP_MAD_NOT_SUPPORTED);
+		send_iu(iue, sizeof(iu->mad), VIOSRP_MAD_FORMAT);
+		break;
+	}
 
-static u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg)
-{
 	return 1;
 }
 
-static int ibmvscsis_check_true(struct se_portal_group *se_tpg)
+static struct se_portal_group *ibmvscsis_make_nexus(struct ibmvscsis_tport
+						    *tport,
+						    const char *name)
 {
-	return 1;
-}
+	struct se_node_acl *acl;
 
-static int ibmvscsis_check_false(struct se_portal_group *se_tpg)
-{
-	return 0;
-}
+	if (tport->se_sess) {
+		pr_debug("tport->se_sess already exists\n");
+		return &tport->se_tpg;
+	}
 
-static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg)
-{
-	return 1;
-}
-
-static int ibmvscsis_check_stop_free(struct se_cmd *se_cmd)
-{
-	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
-						  struct ibmvscsis_cmnd,
-						  se_cmd);
-
-	return target_put_sess_cmd(&cmd->se_cmd);
-}
-
-static void ibmvscsis_release_cmd(struct se_cmd *se_cmd)
-{
-	struct ibmvscsis_cmnd *cmd =
-		container_of(se_cmd, struct ibmvscsis_cmnd, se_cmd);
-
-	kfree(cmd);
-}
+	/*
+	 *  Initialize the struct se_session pointer and setup tagpool
+	 *  for struct ibmvscsis_cmd descriptors
+	 */
+	tport->se_sess = transport_init_session(TARGET_PROT_NORMAL);
+	if (IS_ERR(tport->se_sess))
+		goto transport_init_fail;
 
-static int ibmvscsis_shutdown_session(struct se_session *se_sess)
-{
-	return 0;
-}
+	/*
+	 * Since we are running in 'demo mode' this call will generate a
+	 * struct se_node_acl for the ibmvscsis struct se_portal_group with
+	 * the SCSI Initiator port name of the passed configfs group 'name'.
+	 */
 
-static void ibmvscsis_close_session(struct se_session *se_sess)
-{
-}
+	acl = core_tpg_check_initiator_node_acl(&tport->se_tpg,
+						(unsigned char *)name);
+	if (!acl) {
+		pr_debug("core_tpg_check_initiator_node_acl() failed for %s\n",
+			 name);
+		goto acl_failed;
+	}
+	tport->se_sess->se_node_acl = acl;
 
-static u32 ibmvscsis_sess_get_index(struct se_session *se_sess)
-{
-	return 0;
-}
+	/*
+	 * Now register the TCM ibmvscsis virtual I_T Nexus as active.
+	 */
+	transport_register_session(&tport->se_tpg,
+				   tport->se_sess->se_node_acl,
+				   tport->se_sess, tport);
 
-static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
-{
-	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
-						  struct ibmvscsis_cmnd,
-						  se_cmd);
-	struct scsi_cmnd *sc = &cmd->sc;
-	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
-	int ret;
+	tport->se_sess->se_tpg = &tport->se_tpg;
 
-	sc->sdb.length = se_cmd->data_length;
-	sc->sdb.table.nents = se_cmd->t_data_nents;
-	sc->sdb.table.sgl = se_cmd->t_data_sg;
+	return &tport->se_tpg;
 
-	ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
-				ibmvscsis_rdma, 1, 1);
-	if (ret) {
-		pr_err("srp_transfer_data() failed: %d\n", ret);
-		return -EAGAIN;
-	}
-	/*
-	 * We now tell TCM to add this WRITE CDB directly into the TCM storage
-	 * object execution queue.
-	 */
-	target_execute_cmd(&cmd->se_cmd);
-	return 0;
+acl_failed:
+	transport_free_session(tport->se_sess);
+transport_init_fail:
+	kfree(tport);
+	return ERR_PTR(-ENOMEM);
 }
 
-static int ibmvscsis_write_pending_status(struct se_cmd *se_cmd)
+static int ibmvscsis_drop_nexus(struct ibmvscsis_tport *tport)
 {
-	return 0;
-}
+	struct se_session *se_sess;
 
-static void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl)
-{
-}
+	se_sess = tport->se_sess;
+	if (!se_sess)
+		return -ENODEV;
 
-static int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd)
-{
+	transport_deregister_session(tport->se_sess);
+	transport_free_session(tport->se_sess);
 	return 0;
 }
 
-static void ibmvscsis_determine_resid(struct se_cmd *se_cmd,
-				      struct srp_rsp *rsp)
-{
-	if (se_cmd->residual_count) {
-		if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
-			if (se_cmd->data_direction == DMA_TO_DEVICE) {
-				/* residual data from an underflow write */
-				rsp->flags = SRP_RSP_FLAG_DOUNDER;
-				rsp->data_out_res_cnt =
-					cpu_to_be32(se_cmd->residual_count);
-			} else if (se_cmd->data_direction == DMA_FROM_DEVICE) {
-				/* residual data from an underflow read */
-				rsp->flags = SRP_RSP_FLAG_DIUNDER;
-				rsp->data_in_res_cnt =
-					cpu_to_be32(se_cmd->residual_count);
-			}
-		} else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
-			if (se_cmd->data_direction == DMA_TO_DEVICE) {
-				/*  residual data from an overflow write */
-				rsp->flags = SRP_RSP_FLAG_DOOVER;
-				rsp->data_out_res_cnt =
-					cpu_to_be32(se_cmd->residual_count);
-			} else if (se_cmd->data_direction ==
-				   DMA_FROM_DEVICE) {
-				/* residual data from an overflow read */
-				rsp->flags = SRP_RSP_FLAG_DIOVER;
-				rsp->data_in_res_cnt =
-					cpu_to_be32(se_cmd->residual_count);
-			}
-		}
-	}
-}
-
-static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
+static void process_login(struct iu_entry *iue)
 {
-	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
-						  struct ibmvscsis_cmnd,
-						  se_cmd);
-	struct scsi_cmnd *sc = &cmd->sc;
-	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
-	struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
-	struct srp_rsp *rsp;
-	char *sd;
-	char *data;
-	int ret;
-	uint len;
-
+	union viosrp_iu *iu = vio_iu(iue);
+	struct srp_login_rsp *rsp = &iu->srp.login_rsp;
+	struct srp_login_rej *rej = &iu->srp.login_rej;
 	struct srp_target *target = iue->target;
 	struct ibmvscsis_adapter *adapter = target->ldata;
+	struct vio_dev *vdev = adapter->dma_dev;
+	struct se_portal_group *se_tpg;
+	char name[16];
+	u64 tag = iu->srp.rsp.tag;
 
 	/*
-	 * Check for overflow residual count
+	 * TODO handle case that requested size is wrong and buffer
+	 * format is wrong
 	 */
+	memset(iu, 0, max(sizeof(*rsp), sizeof(*rej)));
 
-	if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
-		scsi_set_resid(sc, se_cmd->residual_count);
+	snprintf(name, sizeof(name), "%x", vdev->unit_address);
 
-	sc->sdb.length = se_cmd->data_length;
-	sc->sdb.table.nents = se_cmd->t_data_nents;
-	sc->sdb.table.sgl = se_cmd->t_data_sg;
+	if (!adapter->tport.enabled) {
+		rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
+		pr_err("Rejected SRP_LOGIN_REQ because target %s has not yet been enabled",
+		       name);
+		goto reject;
+	}
 
-	if (scsi_sg_count(sc)) {
-		if (srp->cdb[0] == REPORT_LUNS &&
-		    adapter->client_data.os_type != LINUX)
-			ibmvscsis_modify_rep_luns(se_cmd);
-		if ((srp->cdb[0] == INQUIRY) && ((srp->cdb[1] & 0x1) == 0))
-			ibmvscsis_modify_std_inquiry(se_cmd);
-		ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
-					ibmvscsis_rdma, 1, 1);
-		if (ret) {
-			pr_err("srp_transfer_data failed: %d\n", ret);
-			sd = cmd->se_cmd.sense_buffer;
-			cmd->se_cmd.scsi_sense_length = 18;
-			memset(cmd->se_cmd.sense_buffer, 0,
-			       cmd->se_cmd.scsi_sense_length);
-			sd[0] = 0x70;
-			sd[2] = 3;
-			sd[7] = 10;
-			sd[12] = 8;
-			sd[13] = 1;
-		}
+	se_tpg = ibmvscsis_make_nexus(&adapter->tport,
+				      &adapter->tport.tport_name[0]);
+	if (!se_tpg) {
+		pr_debug("login make nexus fail se_tpg(%p)\n", se_tpg);
+		goto reject;
 	}
 
-	rsp = &vio_iu(iue)->srp.rsp;
-	len = sizeof(*rsp);
-	memset(rsp, 0, len);
-	data = rsp->data;
+	rsp->opcode = SRP_LOGIN_RSP;
 
-	rsp->tag = se_cmd->tag;
-	rsp->req_lim_delta = cpu_to_be32(1);
-	rsp->opcode = SRP_RSP;
+	rsp->req_lim_delta = cpu_to_be32(INITIAL_SRP_LIMIT);
 
-	ibmvscsis_determine_resid(se_cmd, rsp);
-	rsp->status = se_cmd->scsi_status;
+	pr_debug("process_login, tag:%llu\n", tag);
 
-	if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) {
-		rsp->sense_data_len = cpu_to_be32(se_cmd->scsi_sense_length);
-		rsp->flags |= SRP_RSP_FLAG_SNSVALID;
-		len += se_cmd->scsi_sense_length;
-		memcpy(data, se_cmd->sense_buffer, se_cmd->scsi_sense_length);
-	}
+	rsp->tag = tag;
+	rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
+	rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
+	/* direct and indirect */
+	rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
+				   SRP_BUF_FORMAT_INDIRECT);
 
-	send_iu(iue, len, VIOSRP_SRP_FORMAT);
-	return 0;
+	send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT);
+	return;
+
+reject:
+	rej->opcode = SRP_LOGIN_REJ;
+	rej->tag = tag;
+	rej->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
+				   SRP_BUF_FORMAT_INDIRECT);
+
+	send_iu(iue, sizeof(*rej), VIOSRP_SRP_FORMAT);
 }
 
-static int ibmvscsis_queue_status(struct se_cmd *se_cmd)
+static void process_tsk_mgmt(struct ibmvscsis_adapter *adapter,
+			     struct iu_entry *iue)
 {
-	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
-						  struct ibmvscsis_cmnd,
-						  se_cmd);
-	struct scsi_cmnd *sc = &cmd->sc;
-	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
+	struct srp_tsk_mgmt *srp_tsk = &vio_iu(iue)->srp.tsk_mgmt;
+	struct ibmvscsis_cmnd *cmd = adapter->cmd;
 	struct srp_rsp *rsp;
-	uint len;
-	char *data;
-
-	/*
-	 * Copy any generated SENSE data into sc->sense_buffer and
-	 * set the appropriate sc->result to be translated by
-	 * ibmvscsis_cmnd_done()
-	 */
+	u64 unpacked_lun = 0;
+	u64 tag_to_abort = 0;
+	int tcm_type;
+	int rc = 0;
 
 	rsp = &vio_iu(iue)->srp.rsp;
-	len = sizeof(*rsp);
-	memset(rsp, 0, len);
-	data = rsp->data;
-
-	rsp->tag = se_cmd->tag;
-	rsp->req_lim_delta = cpu_to_be32(1);
-	rsp->opcode = SRP_RSP;
-
-	ibmvscsis_determine_resid(se_cmd, rsp);
-	rsp->status = se_cmd->scsi_status;
+	unpacked_lun = ibmvscsis_unpack_lun((u8 *)&srp_tsk->lun,
+					    sizeof(srp_tsk->lun));
 
-	if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) {
-		rsp->sense_data_len = cpu_to_be32(se_cmd->scsi_sense_length);
-		rsp->flags |= SRP_RSP_FLAG_SNSVALID;
-		len += se_cmd->scsi_sense_length;
-		memcpy(data, se_cmd->sense_buffer, se_cmd->scsi_sense_length);
+	switch (srp_tsk->tsk_mgmt_func) {
+	case SRP_TSK_ABORT_TASK:
+		tcm_type = TMR_ABORT_TASK;
+		tag_to_abort = be64_to_cpu(srp_tsk->task_tag);
+		srp_iu_put(iue);
+		break;
+	case SRP_TSK_ABORT_TASK_SET:
+		tcm_type = TMR_ABORT_TASK_SET;
+		break;
+	case SRP_TSK_CLEAR_TASK_SET:
+		tcm_type = TMR_CLEAR_TASK_SET;
+		break;
+	case SRP_TSK_LUN_RESET:
+		tcm_type = TMR_LUN_RESET;
+		break;
+	case SRP_TSK_CLEAR_ACA:
+		tcm_type = TMR_CLEAR_ACA;
+		break;
+	default:
+		pr_err("unknown task mgmt func %d\n", srp_tsk->tsk_mgmt_func);
+		cmd->se_cmd.se_tmr_req->response =
+					TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
+		goto fail;
 	}
-	send_iu(iue, len, VIOSRP_SRP_FORMAT);
-	return 0;
-}
-
-static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd)
-{
-	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
-						  struct ibmvscsis_cmnd,
-						  se_cmd);
-	struct scsi_cmnd *sc = &cmd->sc;
-	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
-	struct srp_target *target = iue->target;
-	struct ibmvscsis_adapter *adapter = target->ldata;
-	struct srp_rsp *rsp;
-	uint len;
-	char *data;
-	u32 *tsk_status;
-	u32 rsp_code;
 
-	rsp = &vio_iu(iue)->srp.rsp;
+	cmd->se_cmd.tag = be64_to_cpu(srp_tsk->tag);
 
-	if (transport_check_aborted_status(se_cmd, false) != 0) {
-		pr_debug("queue_tm_rsp aborted\n");
-		atomic_inc(&adapter->req_lim_delta);
-		srp_iu_put(iue);
-	} else {
-		rsp->req_lim_delta = cpu_to_be32(1 +
-						 atomic_xchg(&adapter->
-							     req_lim_delta, 0));
+	pr_debug("calling submit_tmr, func %d\n",
+		 srp_tsk->tsk_mgmt_func);
+	rc = target_submit_tmr(&cmd->se_cmd,
+			       adapter->tport.se_sess, NULL,
+			       unpacked_lun, srp_tsk, tcm_type,
+			       GFP_KERNEL, tag_to_abort,
+			       TARGET_SCF_ACK_KREF);
+	if (rc != 0) {
+		pr_err("target_submit_tmr failed, rc %d\n", rc);
+		cmd->se_cmd.se_tmr_req->response = TMR_FUNCTION_REJECTED;
+		goto fail;
 	}
 
-	len = sizeof(*rsp);
-	memset(rsp, 0, len);
-	data = rsp->data;
+fail:
+	if (rc)
+		transport_send_check_condition_and_sense(&cmd->se_cmd, 0, 0);
+}
 
-	rsp->opcode = SRP_RSP;
-	rsp->tag = se_cmd->se_tmr_req->ref_task_tag;
-	rsp->status = 0;
-	rsp->resp_data_len = cpu_to_be32(4);
-	rsp->flags |= SRP_RSP_FLAG_RSPVALID;
-	rsp->req_lim_delta = cpu_to_be32(1);
+static int tcm_queuecommand(struct ibmvscsis_adapter *adapter,
+			    struct ibmvscsis_cmnd *vsc,
+			    struct srp_cmd *scmd)
+{
+	struct se_cmd *se_cmd;
+	int attr;
+	u64 data_len;
+	int ret;
+	u64 unpacked_lun;
 
-	switch (se_cmd->se_tmr_req->response) {
-	case TMR_FUNCTION_COMPLETE:
-	case TMR_TASK_DOES_NOT_EXIST:
-		rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE;
+	switch (scmd->task_attr) {
+	case SRP_SIMPLE_TASK:
+		attr = TCM_SIMPLE_TAG;
 		break;
-	case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
-	case TMR_LUN_DOES_NOT_EXIST:
-		rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED;
+	case SRP_ORDERED_TASK:
+		attr = TCM_ORDERED_TAG;
 		break;
-	case TMR_FUNCTION_FAILED:
-	case TMR_FUNCTION_REJECTED:
-	default:
-		rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_FAILED;
+	case SRP_HEAD_TASK:
+		attr = TCM_HEAD_TAG;
+		break;
+	case SRP_ACA_TASK:
+		attr = TCM_ACA_TAG;
 		break;
+	default:
+		pr_err("Task attribute %d not supported\n", scmd->task_attr);
+		attr = TCM_SIMPLE_TAG;
 	}
 
-	tsk_status = (u32 *)data;
-	*tsk_status = cpu_to_be32(rsp_code);
-	data = (char *)(tsk_status + 1);
-	len += 4;
+	pr_debug("srp_data_length: %llx, srp_direction:%x\n",
+		 srp_data_length(scmd, srp_cmd_direction(scmd)),
+		 srp_cmd_direction(scmd));
+	data_len = srp_data_length(scmd, srp_cmd_direction(scmd));
 
-	send_iu(iue, len, VIOSRP_SRP_FORMAT);
-}
+	vsc->se_cmd.tag = scmd->tag;
+	se_cmd = &vsc->se_cmd;
 
-static void ibmvscsis_aborted_task(struct se_cmd *se_cmd)
-{
-}
+	pr_debug("size of lun:%lx, lun:%s\n", sizeof(scmd->lun),
+		 &scmd->lun.scsi_lun[0]);
 
-static struct se_portal_group *ibmvscsis_make_nexus(struct ibmvscsis_tport
-						    *tport,
-						    const char *name)
-{
-	struct se_node_acl *acl;
+	unpacked_lun = ibmvscsis_unpack_lun((u8 *)&scmd->lun,
+					    sizeof(scmd->lun));
 
-	if (tport->se_sess) {
-		pr_debug("tport->se_sess already exists\n");
-		return &tport->se_tpg;
+	ret = target_submit_cmd(se_cmd, adapter->tport.se_sess,
+				&scmd->cdb[0], &vsc->sense_buf[0], unpacked_lun,
+				data_len, attr, srp_cmd_direction(scmd),
+				TARGET_SCF_ACK_KREF);
+	if (ret != 0) {
+		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+		pr_debug("tcm_queuecommand fail submit_cmd\n");
+		goto send_sense;
 	}
+	return 0;
 
-	/*
-	 *  Initialize the struct se_session pointer and setup tagpool
-	 *  for struct ibmvscsis_cmd descriptors
-	 */
-	tport->se_sess = transport_init_session(TARGET_PROT_NORMAL);
-	if (IS_ERR(tport->se_sess))
-		goto transport_init_fail;
-
-	/*
-	 * Since we are running in 'demo mode' this call will generate a
-	 * struct se_node_acl for the ibmvscsis struct se_portal_group with
-	 * the SCSI Initiator port name of the passed configfs group 'name'.
-	 */
-
-	acl = core_tpg_check_initiator_node_acl(&tport->se_tpg,
-						(unsigned char *)name);
-	if (!acl) {
-		pr_debug("core_tpg_check_initiator_node_acl() failed for %s\n",
-			 name);
-		goto acl_failed;
-	}
-	tport->se_sess->se_node_acl = acl;
+send_sense:
+	transport_send_check_condition_and_sense(&vsc->se_cmd, ret, 0);
+	transport_generic_free_cmd(&vsc->se_cmd, 0);
+	return -1;
+}
 
-	/*
-	 * Now register the TCM ibmvscsis virtual I_T Nexus as active.
-	 */
-	transport_register_session(&tport->se_tpg,
-				   tport->se_sess->se_node_acl,
-				   tport->se_sess, tport);
+static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
+				  struct iu_entry *iue)
+{
+	struct srp_cmd *cmd = iue->sbuf->buf;
+	struct scsi_cmnd *sc;
+	struct ibmvscsis_cmnd *vsc;
+	int ret;
 
-	tport->se_sess->se_tpg = &tport->se_tpg;
+	vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);
+	adapter->cmd = vsc;
+	sc = &vsc->sc;
+	sc->sense_buffer = vsc->se_cmd.sense_buffer;
+	sc->cmnd = cmd->cdb;
+	sc->SCp.ptr = (char *)iue;
 
-	return &tport->se_tpg;
+	ret = tcm_queuecommand(adapter, vsc, cmd);
 
-acl_failed:
-	transport_free_session(tport->se_sess);
-transport_init_fail:
-	kfree(tport);
-	return ERR_PTR(-ENOMEM);
+	return ret;
 }
 
-static int ibmvscsis_drop_nexus(struct ibmvscsis_tport *tport)
+static void ibmvscsis_srp_i_logout(struct iu_entry *iue)
 {
-	struct se_session *se_sess;
-
-	se_sess = tport->se_sess;
-	if (!se_sess)
-		return -ENODEV;
+	union viosrp_iu *iu = vio_iu(iue);
+	struct srp_i_logout *log_out = &vio_iu(iue)->srp.i_logout;
+	u64 tag = iu->srp.rsp.tag;
 
-	transport_deregister_session(tport->se_sess);
-	transport_free_session(tport->se_sess);
-	return 0;
+	log_out->opcode = SRP_I_LOGOUT;
+	log_out->tag = tag;
+	send_iu(iue, sizeof(*log_out), VIOSRP_SRP_FORMAT);
 }
 
-static struct ibmvscsis_tport *ibmvscsis_lookup_port(const char *name)
+static int process_srp_iu(struct iu_entry *iue)
 {
-	struct ibmvscsis_tport *tport;
-	struct vio_dev *vdev;
-	struct ibmvscsis_adapter *adapter;
-	int ret;
+	union viosrp_iu *iu = vio_iu(iue);
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
+	u8 opcode = iu->srp.rsp.opcode;
 	unsigned long flags;
+	int err = 1;
 
-	spin_lock_irqsave(&ibmvscsis_dev_lock, flags);
-	list_for_each_entry(adapter, &ibmvscsis_dev_list, list) {
-		vdev = adapter->dma_dev;
-		ret = strcmp(dev_name(&vdev->dev), name);
-		if (ret == 0)
-			tport = &adapter->tport;
-		if (tport)
-			goto found;
-	}
-	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
-	return NULL;
-found:
-	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
-	return tport;
-}
-
-static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf,
-					   struct config_group *group,
-					   const char *name)
-{
-	struct ibmvscsis_tport *tport;
-	int ret;
-
-	tport = ibmvscsis_lookup_port(name);
-	ret = -EINVAL;
-
-	if (!tport)
-		goto err;
-
-	tport->tport_proto_id = SCSI_PROTOCOL_SRP;
-	pr_debug("make_tport(%s), pointer:%p tport_id:%x\n", name, tport,
-		 tport->tport_proto_id);
-
-	return &tport->tport_wwn;
-err:
-	return ERR_PTR(ret);
-}
-
-static void ibmvscsis_drop_tport(struct se_wwn *wwn)
-{
-	struct ibmvscsis_tport *tport = container_of(wwn,
-						     struct ibmvscsis_tport,
-						     tport_wwn);
-
-	pr_debug("drop_tport(%s\n",
-		 config_item_name(&tport->tport_wwn.wwn_group.cg_item));
-}
-
-static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
-						  struct config_group *group,
-						  const char *name)
-{
-	struct ibmvscsis_tport *tport =
-		container_of(wwn, struct ibmvscsis_tport, tport_wwn);
-	int ret;
-
-	tport->releasing = false;
-
-	ret = core_tpg_register(&tport->tport_wwn,
-				&tport->se_tpg,
-				tport->tport_proto_id);
-	if (ret)
-		return ERR_PTR(ret);
-
-	return &tport->se_tpg;
-}
-
-static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg)
-{
-	struct ibmvscsis_tport *tport = container_of(se_tpg,
-						     struct ibmvscsis_tport,
-						     se_tpg);
-
-	tport->releasing = true;
-	tport->enabled = false;
-
-	/*
-	 * Release the virtual I_T Nexus for this ibmvscsis TPG
-	 */
-	ibmvscsis_drop_nexus(tport);
-	/*
-	 * Deregister the se_tpg from TCM..
-	 */
-	core_tpg_deregister(se_tpg);
-}
-
-static ssize_t system_id_show(struct device *dev,
-			      struct device_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%s\n", system_id);
-}
-
-static ssize_t partition_number_show(struct device *dev,
-				     struct device_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%x\n", partition_number);
-}
-
-static ssize_t unit_address_show(struct device *dev,
-				 struct device_attribute *attr, char *buf)
-{
-	struct ibmvscsis_adapter *adapter =
-			container_of(dev, struct ibmvscsis_adapter, dev);
-
-	return snprintf(buf, PAGE_SIZE, "%x\n", adapter->dma_dev->unit_address);
-}
-
-static int get_system_info(void)
-{
-	struct device_node *rootdn, *vdevdn;
-	const char *id, *model, *name;
-	const unsigned int *num;
-
-	rootdn = of_find_node_by_path("/");
-	if (!rootdn)
-		return -ENOENT;
-
-	model = of_get_property(rootdn, "model", NULL);
-	id = of_get_property(rootdn, "system-id", NULL);
-	if (model && id)
-		snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
-
-	name = of_get_property(rootdn, "ibm,partition-name", NULL);
-	if (name)
-		strncpy(partition_name, name, sizeof(partition_name));
-
-	num = of_get_property(rootdn, "ibm,partition-no", NULL);
-	if (num)
-		partition_number = of_read_number(num, 1);
-
-	of_node_put(rootdn);
-
-	vdevdn = of_find_node_by_path("/vdevice");
-	vdevdn = of_find_node_by_path("/vdevice");
-	if (vdevdn) {
-		const unsigned *mvds;
-
-		mvds = of_get_property(vdevdn, "ibm,max-virtual-dma-size",
-				       NULL);
-		if (mvds)
-			max_vdma_size = *mvds;
-		of_node_put(vdevdn);
-	}
-
-	return 0;
-};
-
-static irqreturn_t ibmvscsis_interrupt(int dummy, void *data)
-{
-	struct ibmvscsis_adapter *adapter = data;
-
-	vio_disable_interrupts(adapter->dma_dev);
-	queue_work(vtgtd, &adapter->crq_work);
-
-	return IRQ_HANDLED;
-}
-
-static int process_srp_iu(struct iu_entry *iue)
-{
-	union viosrp_iu *iu = vio_iu(iue);
-	struct srp_target *target = iue->target;
-	struct ibmvscsis_adapter *adapter = target->ldata;
-	u8 opcode = iu->srp.rsp.opcode;
-	unsigned long flags;
-	int err = 1;
-
-	spin_lock_irqsave(&target->lock, flags);
-	if (adapter->tport.releasing) {
-		pr_err("process_srp_iu error, tport is released:%x\n",
-		       adapter->tport.releasing);
-		goto done;
+	spin_lock_irqsave(&target->lock, flags);
+	if (adapter->tport.releasing) {
+		pr_err("process_srp_iu error, tport is released:%x\n",
+		       adapter->tport.releasing);
+		goto done;
 	}
 	if (!adapter->tport.enabled) {
 		pr_err("process_srp_iu, tport not enabled:%x\n",
@@ -1306,6 +1008,29 @@ static void process_crq(struct viosrp_crq *crq,
 	}
 }
 
+static inline struct viosrp_crq *next_crq(struct crq_queue *queue)
+{
+	struct viosrp_crq *crq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&queue->lock, flags);
+	crq = &queue->msgs[queue->cur];
+	if (crq->valid & 0x80 || crq->valid & 0xFF) {
+		if (++queue->cur == queue->size)
+			queue->cur = 0;
+
+		/* Ensure the read of the valid bit occurs before reading any
+		 * other bits of the CRQ entry
+		 */
+		rmb();
+	} else {
+		crq = NULL;
+	}
+	spin_unlock_irqrestore(&queue->lock, flags);
+
+	return crq;
+}
+
 static void handle_crq(struct work_struct *work)
 {
 	struct ibmvscsis_adapter *adapter =
@@ -1332,623 +1057,815 @@ static void handle_crq(struct work_struct *work)
 	}
 }
 
-static int ibmvscsis_reset_crq_queue(struct ibmvscsis_adapter *adapter)
+static int crq_queue_create(struct crq_queue *queue,
+			    struct ibmvscsis_adapter *adapter)
 {
-	int rc = 0;
+	int retrc;
+	int err;
 	struct vio_dev *vdev = adapter->dma_dev;
-	struct crq_queue *queue = &adapter->crq_queue;
 
-	/* Close the CRQ */
-	h_free_crq(vdev->unit_address);
+	queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
 
-	/* Clean out the queue */
-	memset(queue->msgs, 0x00, PAGE_SIZE);
-	queue->cur = 0;
+	if (!queue->msgs)
+		goto malloc_failed;
 
-	/* And re-open it again */
-	rc = h_reg_crq(vdev->unit_address, queue->msg_token, PAGE_SIZE);
-	if (rc == 2)
-		/* Adapter is good, but other end is not ready */
-		pr_warn("Partner adapter not ready\n");
-	else if (rc != 0)
-		pr_err("Couldn't register crq--rc 0x%x\n", rc);
+	queue->size = PAGE_SIZE / sizeof(*queue->msgs);
 
-	return rc;
-}
+	queue->msg_token = dma_map_single(&vdev->dev, queue->msgs,
+					  queue->size * sizeof(*queue->msgs),
+					  DMA_BIDIRECTIONAL);
 
-static void crq_queue_destroy(struct ibmvscsis_adapter *adapter)
-{
-	struct vio_dev *vdev = adapter->dma_dev;
-	struct crq_queue *queue = &adapter->crq_queue;
+	if (dma_mapping_error(&vdev->dev, queue->msg_token))
+		goto map_failed;
 
-	free_irq(vdev->irq, (void *)adapter);
-	flush_work(&adapter->crq_work);
-	h_free_crq(vdev->unit_address);
-	dma_unmap_single(&adapter->dma_dev->dev, queue->msg_token,
-			 queue->size * sizeof(*queue->msgs),
-			 DMA_BIDIRECTIONAL);
+	err = h_reg_crq(vdev->unit_address, queue->msg_token,
+			PAGE_SIZE);
+	retrc = err;
 
-	free_page((unsigned long)queue->msgs);
-}
+	/* If the adapter was left active for some reason (like kexec)
+	 * try freeing and re-registering
+	 */
+	if (err == H_RESOURCE)
+		err = ibmvscsis_reset_crq_queue(adapter);
+	if (err == 2) {
+		pr_warn("Partner adapter not ready\n");
+		retrc = 0;
+	} else if (err != 0) {
+		pr_err("Error 0x%x opening virtual adapter\n", err);
+		goto reg_crq_failed;
+	}
 
-static inline struct viosrp_crq *next_crq(struct crq_queue *queue)
-{
-	struct viosrp_crq *crq;
-	unsigned long flags;
+	queue->cur = 0;
+	spin_lock_init(&queue->lock);
 
-	spin_lock_irqsave(&queue->lock, flags);
-	crq = &queue->msgs[queue->cur];
-	if (crq->valid & 0x80 || crq->valid & 0xFF) {
-		if (++queue->cur == queue->size)
-			queue->cur = 0;
+	INIT_WORK(&adapter->crq_work, handle_crq);
 
-		/* Ensure the read of the valid bit occurs before reading any
-		 * other bits of the CRQ entry
-		 */
-		rmb();
-	} else {
-		crq = NULL;
+	err = request_irq(vdev->irq, &ibmvscsis_interrupt,
+			  0, "ibmvscsis", adapter);
+	if (err) {
+		pr_err("Error 0x%x h_send_crq\n", err);
+		goto req_irq_failed;
 	}
-	spin_unlock_irqrestore(&queue->lock, flags);
 
-	return crq;
+	err = vio_enable_interrupts(vdev);
+	if (err != 0) {
+		pr_err("Error %d enabling interrupts!!!\n", err);
+		goto req_irq_failed;
+	}
+
+	return retrc;
+
+req_irq_failed:
+	h_free_crq(vdev->unit_address);
+reg_crq_failed:
+	dma_unmap_single(&vdev->dev, queue->msg_token,
+			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+map_failed:
+	free_page((unsigned long)queue->msgs);
+malloc_failed:
+	return -1;
 }
 
-static int send_iu(struct iu_entry *iue, u64 length, u8 format)
+static void crq_queue_destroy(struct ibmvscsis_adapter *adapter)
 {
-	struct srp_target *target = iue->target;
-	struct ibmvscsis_adapter *adapter = target->ldata;
-	struct ibmvscsis_crq_msg crq_msg;
-	struct srp_rsp *rsp;
-	__be64 *crq_as_u64 = (__be64 *)&crq_msg;
-	long rc, rc1;
+	struct vio_dev *vdev = adapter->dma_dev;
+	struct crq_queue *queue = &adapter->crq_queue;
 
-	rsp = &vio_iu(iue)->srp.rsp;
-	pr_debug("send_iu: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
-		 (unsigned long)length,
-		 (unsigned long)adapter->liobn,
-		 (unsigned long)iue->sbuf->dma,
-		 (unsigned long)adapter->riobn,
-		 (unsigned long)be64_to_cpu(iue->remote_token));
+	free_irq(vdev->irq, (void *)adapter);
+	flush_work(&adapter->crq_work);
+	h_free_crq(vdev->unit_address);
+	dma_unmap_single(&adapter->dma_dev->dev, queue->msg_token,
+			 queue->size * sizeof(*queue->msgs),
+			 DMA_BIDIRECTIONAL);
 
-	/* First copy the SRP */
-	rc = h_copy_rdma(length, adapter->liobn, iue->sbuf->dma,
-			 adapter->riobn, be64_to_cpu(iue->remote_token));
+	free_page((unsigned long)queue->msgs);
+}
 
-	switch (rc) {
-	case H_SUCCESS:
-		break;
-	case H_PERMISSION:
-	case H_SOURCE_PARM:
-	case H_DEST_PARM:
-		if (connection_broken(adapter)) {
-			pr_debug("rdma connection broken\n");
-			goto end;
-		}
-		break;
-	default:
-		pr_err("Error %ld transferring data\n", rc);
-		length = 0;
-		break;
-	}
+static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
+			  struct srp_direct_buf *md, int nmd,
+			  enum dma_data_direction dir, unsigned int rest)
+{
+	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
+	dma_addr_t token;
+	long err;
+	unsigned int done = 0;
+	int i, sidx, soff;
 
-	pr_debug("crq pre cooked: 0x%x, 0x%llx, 0x%llx\n",
-		 format, length, vio_iu(iue)->srp.rsp.tag);
+	sidx = 0;
+	soff = 0;
+	token = sg_dma_address(sg + sidx);
 
-	crq_msg.valid = 0x80;
-	crq_msg.format = format;
-	crq_msg.rsvd = 0;
-	if (rc == 0)
-		crq_msg.status = 0x99;
-	else
-		crq_msg.status = rsp->status;
-	crq_msg.rsvd1 = 0;
-	crq_msg.IU_length = cpu_to_be16(length);
-	crq_msg.IU_data_ptr = vio_iu(iue)->srp.rsp.tag;
+	for (i = 0; i < nmd && rest; i++) {
+		unsigned int mdone, mlen;
 
-	pr_debug("send crq: 0x%x, 0x%llx, 0x%llx\n",
-		 adapter->dma_dev->unit_address,
-		 be64_to_cpu(crq_as_u64[0]),
-		 be64_to_cpu(crq_as_u64[1]));
+		mlen = min(rest, be32_to_cpu(md[i].len));
+		for (mdone = 0; mlen;) {
+			int slen = min(sg_dma_len(sg + sidx) - soff, mlen);
 
-	srp_iu_put(iue);
+			if (dir == DMA_TO_DEVICE)
+				err = h_copy_rdma(slen,
+						  adapter->riobn,
+						  be64_to_cpu(md[i].va) + mdone,
+						  adapter->liobn,
+						  token + soff);
+			else
+				err = h_copy_rdma(slen,
+						  adapter->liobn,
+						  token + soff,
+						  adapter->riobn,
+						  be64_to_cpu(md[i].va) +
+						  mdone);
+			switch (err) {
+			case H_SUCCESS:
+				break;
+			case H_PERMISSION:
+			case H_SOURCE_PARM:
+			case H_DEST_PARM:
+				if (connection_broken(adapter))
+					pr_debug("rdma connection broken\n");
+			default:
+				pr_err("rdma error %d %d %ld\n",
+				       dir, slen, err);
+				return -EIO;
+			}
 
-	rc1 = h_send_crq(adapter, be64_to_cpu(crq_as_u64[0]),
-			 be64_to_cpu(crq_as_u64[1]));
+			mlen -= slen;
+			mdone += slen;
+			soff += slen;
+			done += slen;
 
-	if (rc1) {
-		pr_err("%ld sending response\n", rc1);
-		return rc1;
+			if (soff == sg_dma_len(sg + sidx)) {
+				sidx++;
+				soff = 0;
+				token = sg_dma_address(sg + sidx);
+
+				if (sidx > nsg) {
+					pr_err("out of sg %p %d %d\n",
+					       iue, sidx, nsg);
+					return -EIO;
+				}
+			}
+		}
+		rest -= mlen;
 	}
-	return rc;
-end:
-	return rc;
+	return 0;
 }
 
-static int send_adapter_info(struct iu_entry *iue,
-			     dma_addr_t remote_buffer, u16 length)
+static int ibmvscsis_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 {
-	struct srp_target *target = iue->target;
-	struct ibmvscsis_adapter *adapter = target->ldata;
-	dma_addr_t data_token;
-	struct viosrp_adapter_info *mad = &vio_iu(iue)->mad.adapter_info;
-	struct mad_adapter_info_data *info;
-	int err;
+	int ret = -ENOMEM;
+	struct ibmvscsis_adapter *adapter;
+	struct srp_target *target;
+	struct ibmvscsis_tport *tport;
+	unsigned long flags;
 
-	mad->common.status = cpu_to_be16(VIOSRP_MAD_SUCCESS);
+	pr_debug("Probe for UA 0x%x\n", vdev->unit_address);
 
-	if (be16_to_cpu(mad->common.length) > sizeof(*info)) {
-		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
-		return 0;
-	}
+	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+	if (!adapter)
+		return ret;
+	target = kzalloc(sizeof(*target), GFP_KERNEL);
+	if (!target)
+		goto free_adapter;
 
-	info = dma_alloc_coherent(&adapter->dma_dev->dev, sizeof(*info),
-				  &data_token, GFP_KERNEL);
-	if (!info) {
-		pr_err("bad dma_alloc_coherent %p\n", target);
-		mad->common.status = cpu_to_be16(VIOSRP_MAD_FAILED);
-		return 1;
-	}
+	adapter->dma_dev = vdev;
+	adapter->target = target;
+	tport = &adapter->tport;
 
-	/* Get remote info */
-	err = h_copy_rdma(sizeof(*info), adapter->riobn,
-			  be64_to_cpu(remote_buffer),
-			  adapter->liobn, data_token);
+	tport->enabled = false;
+	snprintf(&adapter->tport.tport_name[0], 256, "%s",
+		 dev_name(&vdev->dev));
 
-	if (err == H_SUCCESS) {
-		pr_err("Client connect: %s (%d)\n",
-		       info->partition_name, info->partition_number);
+	ret = read_dma_window(adapter->dma_dev, adapter);
+	if (ret != 0)
+		goto free_target;
 
-		if (adapter->client_data.partition_number == 0)
-			adapter->client_data.partition_number =
-				be32_to_cpu(info->partition_number);
-		strncpy(adapter->client_data.srp_version, info->srp_version,
-			sizeof(adapter->client_data.srp_version));
-		strncpy(adapter->client_data.partition_name,
-			info->partition_name,
-			sizeof(adapter->client_data.partition_name));
-		adapter->client_data.mad_version =
-						be32_to_cpu(info->mad_version);
-		adapter->client_data.os_type = be32_to_cpu(info->os_type);
-		pr_debug("adapter info client adapter %u\n",
-			 adapter->client_data.os_type);
+	pr_debug("Probe: liobn 0x%x, riobn 0x%x\n", adapter->liobn,
+		 adapter->riobn);
 
-		strcpy(info->srp_version, "16.a");
-		strncpy(info->partition_name, partition_name,
-			sizeof(info->partition_name));
+	spin_lock_irqsave(&ibmvscsis_dev_lock, flags);
+	list_add_tail(&adapter->list, &ibmvscsis_dev_list);
+	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
 
-		info->partition_number = cpu_to_be32(partition_number);
-		info->mad_version = cpu_to_be32(1);
-		info->os_type = cpu_to_be32(2);
-		memset(&info->port_max_txu[0], 0, sizeof(info->port_max_txu));
-		info->port_max_txu[0] = cpu_to_be32(SCSI_MAX_SG_SEGMENTS *
-						    PAGE_SIZE);
+	ret = srp_target_alloc(target, &vdev->dev,
+			       INITIAL_SRP_LIMIT,
+			       SRP_MAX_IU_LEN);
 
-		dma_rmb();
-		/* Send our info to remote */
-		err = h_copy_rdma(sizeof(*info), adapter->liobn, data_token,
-				  adapter->riobn, be64_to_cpu(remote_buffer));
+	adapter->target->ldata = adapter;
 
-		switch (err) {
-		case H_SUCCESS:
-			break;
-		case H_PERMISSION:
-		case H_SOURCE_PARM:
-		case H_DEST_PARM:
-			if (connection_broken(adapter))
-				pr_debug("rdma connection broken\n");
-		default:
-			pr_err("Error sending adapter info %d\n",
-			       err);
-			return -EIO;
-		}
-	} else {
-		pr_err("Error sending adapter info %d\n", err);
-		return 1;
+	if (ret) {
+		pr_err("failed target alloc ret: %d\n", ret);
+		goto free_srp_target;
 	}
 
-	dma_free_coherent(&adapter->dma_dev->dev, sizeof(*info), info,
-			  data_token);
+	ret = crq_queue_create(&adapter->crq_queue, adapter);
+	if (ret != 0 && ret != H_RESOURCE) {
+		pr_err("failed crq_queue_create ret: %d\n", ret);
+		ret = -1;
+	}
+
+	if (h_send_crq(adapter, 0xC001000000000000LL, 0) != 0 &&
+	    ret != H_RESOURCE) {
+		pr_warn("Failed to send CRQ message\n");
+		ret = 0;
+	}
+
+	dev_set_drvdata(&vdev->dev, adapter);
 
 	return 0;
+
+free_srp_target:
+	srp_target_free(target);
+free_target:
+	kfree(target);
+free_adapter:
+	kfree(adapter);
+	return ret;
 }
 
-static int process_mad_iu(struct iu_entry *iue)
+static int ibmvscsis_remove(struct vio_dev *dev)
 {
-	union viosrp_iu *iu = vio_iu(iue);
-	struct viosrp_adapter_info *info;
-	struct viosrp_host_config *conf;
+	unsigned long flags;
+	struct ibmvscsis_adapter *adapter = dev_get_drvdata(&dev->dev);
+	struct srp_target *target;
 
-	switch (be32_to_cpu(iu->mad.empty_iu.common.type)) {
-	case VIOSRP_EMPTY_IU_TYPE:
-		pr_err("%s\n", "Unsupported EMPTY MAD IU");
-		break;
-	case VIOSRP_ERROR_LOG_TYPE:
-		pr_err("%s\n", "Unsupported ERROR LOG MAD IU");
-		iu->mad.error_log.common.status = 1;
-		send_iu(iue, sizeof(iu->mad.error_log),	VIOSRP_MAD_FORMAT);
-		break;
-	case VIOSRP_ADAPTER_INFO_TYPE:
-		info = &iu->mad.adapter_info;
-		info->common.status = send_adapter_info(iue, info->buffer,
-							info->common.length);
-		send_iu(iue, sizeof(*info), VIOSRP_MAD_FORMAT);
-		break;
-	case VIOSRP_HOST_CONFIG_TYPE:
-		conf = &iu->mad.host_config;
-		conf->common.status = 1;
-		send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT);
-		break;
-	default:
-		pr_err("Unknown type %u\n", iu->srp.rsp.opcode);
-		iu->mad.empty_iu.common.status =
-					cpu_to_be16(VIOSRP_MAD_NOT_SUPPORTED);
-		send_iu(iue, sizeof(iu->mad), VIOSRP_MAD_FORMAT);
-		break;
-	}
+	target = adapter->target;
 
-	return 1;
+	spin_lock_irqsave(&ibmvscsis_dev_lock, flags);
+	list_del(&adapter->list);
+	spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags);
+
+	crq_queue_destroy(adapter);
+	srp_target_free(target);
+
+	kfree(target);
+	kfree(adapter);
+
+	return 0;
 }
 
-static void ibmvscsis_srp_i_logout(struct iu_entry *iue)
+static ssize_t system_id_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
 {
-	union viosrp_iu *iu = vio_iu(iue);
-	struct srp_i_logout *log_out = &vio_iu(iue)->srp.i_logout;
-	u64 tag = iu->srp.rsp.tag;
+	return snprintf(buf, PAGE_SIZE, "%s\n", system_id);
+}
 
-	log_out->opcode = SRP_I_LOGOUT;
-	log_out->tag = tag;
-	send_iu(iue, sizeof(*log_out), VIOSRP_SRP_FORMAT);
+static ssize_t partition_number_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%x\n", partition_number);
 }
 
-static void process_login(struct iu_entry *iue)
+static ssize_t unit_address_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
 {
-	union viosrp_iu *iu = vio_iu(iue);
-	struct srp_login_rsp *rsp = &iu->srp.login_rsp;
-	struct srp_login_rej *rej = &iu->srp.login_rej;
-	struct srp_target *target = iue->target;
-	struct ibmvscsis_adapter *adapter = target->ldata;
-	struct vio_dev *vdev = adapter->dma_dev;
-	struct se_portal_group *se_tpg;
-	char name[16];
-	u64 tag = iu->srp.rsp.tag;
+	struct ibmvscsis_adapter *adapter =
+			container_of(dev, struct ibmvscsis_adapter, dev);
 
-	/*
-	 * TODO handle case that requested size is wrong and buffer
-	 * format is wrong
-	 */
-	memset(iu, 0, max(sizeof(*rsp), sizeof(*rej)));
+	return snprintf(buf, PAGE_SIZE, "%x\n", adapter->dma_dev->unit_address);
+}
 
-	snprintf(name, sizeof(name), "%x", vdev->unit_address);
+static int get_system_info(void)
+{
+	struct device_node *rootdn, *vdevdn;
+	const char *id, *model, *name;
+	const unsigned int *num;
 
-	if (!adapter->tport.enabled) {
-		rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
-		pr_err("Rejected SRP_LOGIN_REQ because target %s has not yet been enabled",
-		       name);
-		goto reject;
-	}
+	rootdn = of_find_node_by_path("/");
+	if (!rootdn)
+		return -ENOENT;
 
-	se_tpg = ibmvscsis_make_nexus(&adapter->tport,
-				      &adapter->tport.tport_name[0]);
-	if (!se_tpg) {
-		pr_debug("login make nexus fail se_tpg(%p)\n", se_tpg);
-		goto reject;
-	}
+	model = of_get_property(rootdn, "model", NULL);
+	id = of_get_property(rootdn, "system-id", NULL);
+	if (model && id)
+		snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
 
-	rsp->opcode = SRP_LOGIN_RSP;
+	name = of_get_property(rootdn, "ibm,partition-name", NULL);
+	if (name)
+		strncpy(partition_name, name, sizeof(partition_name));
 
-	rsp->req_lim_delta = cpu_to_be32(INITIAL_SRP_LIMIT);
+	num = of_get_property(rootdn, "ibm,partition-no", NULL);
+	if (num)
+		partition_number = of_read_number(num, 1);
 
-	pr_debug("process_login, tag:%llu\n", tag);
+	of_node_put(rootdn);
 
-	rsp->tag = tag;
-	rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
-	rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
-	/* direct and indirect */
-	rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
-				   SRP_BUF_FORMAT_INDIRECT);
+	vdevdn = of_find_node_by_path("/vdevice");
+	vdevdn = of_find_node_by_path("/vdevice");
+	if (vdevdn) {
+		const unsigned *mvds;
 
-	send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT);
-	return;
+		mvds = of_get_property(vdevdn, "ibm,max-virtual-dma-size",
+				       NULL);
+		if (mvds)
+			max_vdma_size = *mvds;
+		of_node_put(vdevdn);
+	}
 
-reject:
-	rej->opcode = SRP_LOGIN_REJ;
-	rej->tag = tag;
-	rej->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
-				   SRP_BUF_FORMAT_INDIRECT);
+	return 0;
+};
 
-	send_iu(iue, sizeof(*rej), VIOSRP_SRP_FORMAT);
+static char *ibmvscsis_get_fabric_name(void)
+{
+	return "ibmvscsis";
 }
 
-static void process_tsk_mgmt(struct ibmvscsis_adapter *adapter,
-			     struct iu_entry *iue)
+static char *ibmvscsis_get_fabric_wwn(struct se_portal_group *se_tpg)
 {
-	struct srp_tsk_mgmt *srp_tsk = &vio_iu(iue)->srp.tsk_mgmt;
-	struct ibmvscsis_cmnd *cmd = adapter->cmd;
-	struct srp_rsp *rsp;
-	u64 unpacked_lun = 0;
-	u64 tag_to_abort = 0;
-	int tcm_type;
-	int rc = 0;
-
-	rsp = &vio_iu(iue)->srp.rsp;
-	unpacked_lun = ibmvscsis_unpack_lun((u8 *)&srp_tsk->lun,
-					    sizeof(srp_tsk->lun));
+	struct ibmvscsis_tport *tport =
+		container_of(se_tpg, struct ibmvscsis_tport, se_tpg);
 
-	switch (srp_tsk->tsk_mgmt_func) {
-	case SRP_TSK_ABORT_TASK:
-		tcm_type = TMR_ABORT_TASK;
-		tag_to_abort = be64_to_cpu(srp_tsk->task_tag);
-		srp_iu_put(iue);
-		break;
-	case SRP_TSK_ABORT_TASK_SET:
-		tcm_type = TMR_ABORT_TASK_SET;
-		break;
-	case SRP_TSK_CLEAR_TASK_SET:
-		tcm_type = TMR_CLEAR_TASK_SET;
-		break;
-	case SRP_TSK_LUN_RESET:
-		tcm_type = TMR_LUN_RESET;
-		break;
-	case SRP_TSK_CLEAR_ACA:
-		tcm_type = TMR_CLEAR_ACA;
-		break;
-	default:
-		pr_err("unknown task mgmt func %d\n", srp_tsk->tsk_mgmt_func);
-		cmd->se_cmd.se_tmr_req->response =
-					TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
-		goto fail;
-	}
+	return &tport->tport_name[0];
+}
 
-	cmd->se_cmd.tag = be64_to_cpu(srp_tsk->tag);
+static u16 ibmvscsis_get_tag(struct se_portal_group *se_tpg)
+{
+	struct ibmvscsis_tport *tport =
+		container_of(se_tpg, struct ibmvscsis_tport, se_tpg);
 
-	pr_debug("calling submit_tmr, func %d\n",
-		 srp_tsk->tsk_mgmt_func);
-	rc = target_submit_tmr(&cmd->se_cmd,
-			       adapter->tport.se_sess, NULL,
-			       unpacked_lun, srp_tsk, tcm_type,
-			       GFP_KERNEL, tag_to_abort,
-			       TARGET_SCF_ACK_KREF);
-	if (rc != 0) {
-		pr_err("target_submit_tmr failed, rc %d\n", rc);
-		cmd->se_cmd.se_tmr_req->response = TMR_FUNCTION_REJECTED;
-		goto fail;
-	}
+	return tport->tport_tpgt;
+}
 
-fail:
-	if (rc)
-		transport_send_check_condition_and_sense(&cmd->se_cmd, 0, 0);
+static u32 ibmvscsis_get_default_depth(struct se_portal_group *se_tpg)
+{
+	return 1;
 }
 
-static bool connection_broken(struct ibmvscsis_adapter *adapter)
+static int ibmvscsis_check_true(struct se_portal_group *se_tpg)
 {
-	u64 buffer[2];
-	struct viosrp_crq *crq;
-	long h_return_code;
-	bool rc = false;
+	return 1;
+}
 
-	/* create a PING crq */
-	crq = (struct viosrp_crq *)&buffer;
-	buffer[0] = 0;
-	buffer[1] = 0;
-	crq->valid = 0x80;
-	crq->format = 6;
-	crq->status = 0xF5;
-
-	h_return_code = h_send_crq(adapter,
-				   cpu_to_be64(buffer[0]),
-				   cpu_to_be64(buffer[1]));
+static int ibmvscsis_check_false(struct se_portal_group *se_tpg)
+{
+	return 0;
+}
 
-	pr_debug("connection_broken: rc %ld\n", h_return_code);
+static u32 ibmvscsis_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
 
-	if (h_return_code == H_CLOSED)
-		rc = true;
+static int ibmvscsis_check_stop_free(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+						  struct ibmvscsis_cmnd,
+						  se_cmd);
 
-	return rc;
+	return target_put_sess_cmd(&cmd->se_cmd);
 }
 
-static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
-			  struct srp_direct_buf *md, int nmd,
-			  enum dma_data_direction dir, unsigned int rest)
+static void ibmvscsis_release_cmd(struct se_cmd *se_cmd)
 {
-	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
-	struct srp_target *target = iue->target;
-	struct ibmvscsis_adapter *adapter = target->ldata;
-	dma_addr_t token;
-	long err;
-	unsigned int done = 0;
-	int i, sidx, soff;
+	struct ibmvscsis_cmnd *cmd =
+		container_of(se_cmd, struct ibmvscsis_cmnd, se_cmd);
 
-	sidx = 0;
-	soff = 0;
-	token = sg_dma_address(sg + sidx);
+	kfree(cmd);
+}
 
-	for (i = 0; i < nmd && rest; i++) {
-		unsigned int mdone, mlen;
+static int ibmvscsis_shutdown_session(struct se_session *se_sess)
+{
+	return 0;
+}
 
-		mlen = min(rest, be32_to_cpu(md[i].len));
-		for (mdone = 0; mlen;) {
-			int slen = min(sg_dma_len(sg + sidx) - soff, mlen);
+static void ibmvscsis_close_session(struct se_session *se_sess)
+{
+}
 
-			if (dir == DMA_TO_DEVICE)
-				err = h_copy_rdma(slen,
-						  adapter->riobn,
-						  be64_to_cpu(md[i].va) + mdone,
-						  adapter->liobn,
-						  token + soff);
-			else
-				err = h_copy_rdma(slen,
-						  adapter->liobn,
-						  token + soff,
-						  adapter->riobn,
-						  be64_to_cpu(md[i].va) +
-						  mdone);
-			switch (err) {
-			case H_SUCCESS:
-				break;
-			case H_PERMISSION:
-			case H_SOURCE_PARM:
-			case H_DEST_PARM:
-				if (connection_broken(adapter))
-					pr_debug("rdma connection broken\n");
-			default:
-				pr_err("rdma error %d %d %ld\n",
-				       dir, slen, err);
-				return -EIO;
-			}
+static u32 ibmvscsis_sess_get_index(struct se_session *se_sess)
+{
+	return 0;
+}
 
-			mlen -= slen;
-			mdone += slen;
-			soff += slen;
-			done += slen;
+static int ibmvscsis_write_pending(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+						  struct ibmvscsis_cmnd,
+						  se_cmd);
+	struct scsi_cmnd *sc = &cmd->sc;
+	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
+	int ret;
 
-			if (soff == sg_dma_len(sg + sidx)) {
-				sidx++;
-				soff = 0;
-				token = sg_dma_address(sg + sidx);
+	sc->sdb.length = se_cmd->data_length;
+	sc->sdb.table.nents = se_cmd->t_data_nents;
+	sc->sdb.table.sgl = se_cmd->t_data_sg;
 
-				if (sidx > nsg) {
-					pr_err("out of sg %p %d %d\n",
-					       iue, sidx, nsg);
-					return -EIO;
-				}
-			}
-		}
-		rest -= mlen;
+	ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
+				ibmvscsis_rdma, 1, 1);
+	if (ret) {
+		pr_err("srp_transfer_data() failed: %d\n", ret);
+		return -EAGAIN;
 	}
+	/*
+	 * We now tell TCM to add this WRITE CDB directly into the TCM storage
+	 * object execution queue.
+	 */
+	target_execute_cmd(&cmd->se_cmd);
 	return 0;
 }
 
-static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
-				  struct iu_entry *iue)
+static int ibmvscsis_write_pending_status(struct se_cmd *se_cmd)
 {
-	struct srp_cmd *cmd = iue->sbuf->buf;
-	struct scsi_cmnd *sc;
-	struct ibmvscsis_cmnd *vsc;
-	int ret;
-
-	vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);
-	adapter->cmd = vsc;
-	sc = &vsc->sc;
-	sc->sense_buffer = vsc->se_cmd.sense_buffer;
-	sc->cmnd = cmd->cdb;
-	sc->SCp.ptr = (char *)iue;
+	return 0;
+}
 
-	ret = tcm_queuecommand(adapter, vsc, cmd);
+static void ibmvscsis_set_default_node_attrs(struct se_node_acl *nacl)
+{
+}
 
-	return ret;
+static int ibmvscsis_get_cmd_state(struct se_cmd *se_cmd)
+{
+	return 0;
 }
 
-static u64 ibmvscsis_unpack_lun(const u8 *lun, int len)
+static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
 {
-	u64 res = NO_SUCH_LUN;
-	int addressing_method;
+	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+						  struct ibmvscsis_cmnd,
+						  se_cmd);
+	struct scsi_cmnd *sc = &cmd->sc;
+	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
+	struct srp_cmd *srp = (struct srp_cmd *)iue->sbuf->buf;
+	struct srp_rsp *rsp;
+	char *sd;
+	char *data;
+	int ret;
+	uint len;
 
-	if (unlikely(len < 2)) {
-		pr_err("Illegal LUN length %d, expected 2 bytes or more\n",
-		       len);
-		goto out;
-	}
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
 
-	switch (len) {
-	case 8:
-		if ((*((__be64 *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0)
-			goto out_err;
-		break;
-	case 4:
-		if (*((__be16 *)&lun[2]) != 0)
-			goto out_err;
-		break;
-	case 6:
-		if (*((__be32 *)&lun[2]) != 0)
-			goto out_err;
-		break;
-	case 2:
-		break;
-	default:
-		goto out_err;
+	/*
+	 * Check for overflow residual count
+	 */
+
+	if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
+		scsi_set_resid(sc, se_cmd->residual_count);
+
+	sc->sdb.length = se_cmd->data_length;
+	sc->sdb.table.nents = se_cmd->t_data_nents;
+	sc->sdb.table.sgl = se_cmd->t_data_sg;
+
+	if (scsi_sg_count(sc)) {
+		if (srp->cdb[0] == REPORT_LUNS &&
+		    adapter->client_data.os_type != LINUX)
+			ibmvscsis_modify_rep_luns(se_cmd);
+		if ((srp->cdb[0] == INQUIRY) && ((srp->cdb[1] & 0x1) == 0))
+			ibmvscsis_modify_std_inquiry(se_cmd);
+		ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd,
+					ibmvscsis_rdma, 1, 1);
+		if (ret) {
+			pr_err("srp_transfer_data failed: %d\n", ret);
+			sd = cmd->se_cmd.sense_buffer;
+			cmd->se_cmd.scsi_sense_length = 18;
+			memset(cmd->se_cmd.sense_buffer, 0,
+			       cmd->se_cmd.scsi_sense_length);
+			sd[0] = 0x70;
+			sd[2] = 3;
+			sd[7] = 10;
+			sd[12] = 8;
+			sd[13] = 1;
+		}
 	}
 
-	addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */
-	switch (addressing_method) {
-	case SCSI_LUN_ADDR_METHOD_PERIPHERAL:
-	case SCSI_LUN_ADDR_METHOD_FLAT:
-	case SCSI_LUN_ADDR_METHOD_LUN:
-		res = *(lun + 1) | (((*lun) & 0x3f) << 8);
-		break;
+	rsp = &vio_iu(iue)->srp.rsp;
+	len = sizeof(*rsp);
+	memset(rsp, 0, len);
+	data = rsp->data;
 
-	case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN:
-	default:
-		pr_err("Unimplemented LUN addressing method %u\n",
-		       addressing_method);
-		break;
+	rsp->tag = se_cmd->tag;
+	rsp->req_lim_delta = cpu_to_be32(1);
+	rsp->opcode = SRP_RSP;
+
+	ibmvscsis_determine_resid(se_cmd, rsp);
+	rsp->status = se_cmd->scsi_status;
+
+	if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) {
+		rsp->sense_data_len = cpu_to_be32(se_cmd->scsi_sense_length);
+		rsp->flags |= SRP_RSP_FLAG_SNSVALID;
+		len += se_cmd->scsi_sense_length;
+		memcpy(data, se_cmd->sense_buffer, se_cmd->scsi_sense_length);
 	}
 
-out:
-	return res;
-out_err:
-	pr_err("Support for multi-level LUNs has not yet been implemented\n");
-	goto out;
+	send_iu(iue, len, VIOSRP_SRP_FORMAT);
+	return 0;
 }
 
-static int tcm_queuecommand(struct ibmvscsis_adapter *adapter,
-			    struct ibmvscsis_cmnd *vsc,
-			    struct srp_cmd *scmd)
+static int ibmvscsis_queue_status(struct se_cmd *se_cmd)
 {
-	struct se_cmd *se_cmd;
-	int attr;
-	u64 data_len;
-	int ret;
-	u64 unpacked_lun;
+	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+						  struct ibmvscsis_cmnd,
+						  se_cmd);
+	struct scsi_cmnd *sc = &cmd->sc;
+	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
+	struct srp_rsp *rsp;
+	uint len;
+	char *data;
 
-	switch (scmd->task_attr) {
-	case SRP_SIMPLE_TASK:
-		attr = TCM_SIMPLE_TAG;
-		break;
-	case SRP_ORDERED_TASK:
-		attr = TCM_ORDERED_TAG;
-		break;
-	case SRP_HEAD_TASK:
-		attr = TCM_HEAD_TAG;
+	/*
+	 * Copy any generated SENSE data into sc->sense_buffer and
+	 * set the appropriate sc->result to be translated by
+	 * ibmvscsis_cmnd_done()
+	 */
+
+	rsp = &vio_iu(iue)->srp.rsp;
+	len = sizeof(*rsp);
+	memset(rsp, 0, len);
+	data = rsp->data;
+
+	rsp->tag = se_cmd->tag;
+	rsp->req_lim_delta = cpu_to_be32(1);
+	rsp->opcode = SRP_RSP;
+
+	ibmvscsis_determine_resid(se_cmd, rsp);
+	rsp->status = se_cmd->scsi_status;
+
+	if (se_cmd->scsi_sense_length && se_cmd->sense_buffer) {
+		rsp->sense_data_len = cpu_to_be32(se_cmd->scsi_sense_length);
+		rsp->flags |= SRP_RSP_FLAG_SNSVALID;
+		len += se_cmd->scsi_sense_length;
+		memcpy(data, se_cmd->sense_buffer, se_cmd->scsi_sense_length);
+	}
+	send_iu(iue, len, VIOSRP_SRP_FORMAT);
+	return 0;
+}
+
+static void ibmvscsis_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+	struct ibmvscsis_cmnd *cmd = container_of(se_cmd,
+						  struct ibmvscsis_cmnd,
+						  se_cmd);
+	struct scsi_cmnd *sc = &cmd->sc;
+	struct iu_entry *iue = (struct iu_entry *)sc->SCp.ptr;
+	struct srp_target *target = iue->target;
+	struct ibmvscsis_adapter *adapter = target->ldata;
+	struct srp_rsp *rsp;
+	uint len;
+	char *data;
+	u32 *tsk_status;
+	u32 rsp_code;
+
+	rsp = &vio_iu(iue)->srp.rsp;
+
+	if (transport_check_aborted_status(se_cmd, false) != 0) {
+		pr_debug("queue_tm_rsp aborted\n");
+		atomic_inc(&adapter->req_lim_delta);
+		srp_iu_put(iue);
+	} else {
+		rsp->req_lim_delta = cpu_to_be32(1 +
+						 atomic_xchg(&adapter->
+							     req_lim_delta, 0));
+	}
+
+	len = sizeof(*rsp);
+	memset(rsp, 0, len);
+	data = rsp->data;
+
+	rsp->opcode = SRP_RSP;
+	rsp->tag = se_cmd->se_tmr_req->ref_task_tag;
+	rsp->status = 0;
+	rsp->resp_data_len = cpu_to_be32(4);
+	rsp->flags |= SRP_RSP_FLAG_RSPVALID;
+	rsp->req_lim_delta = cpu_to_be32(1);
+
+	switch (se_cmd->se_tmr_req->response) {
+	case TMR_FUNCTION_COMPLETE:
+	case TMR_TASK_DOES_NOT_EXIST:
+		rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_COMPLETE;
 		break;
-	case SRP_ACA_TASK:
-		attr = TCM_ACA_TAG;
+	case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
+	case TMR_LUN_DOES_NOT_EXIST:
+		rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED;
 		break;
+	case TMR_FUNCTION_FAILED:
+	case TMR_FUNCTION_REJECTED:
 	default:
-		pr_err("Task attribute %d not supported\n", scmd->task_attr);
-		attr = TCM_SIMPLE_TAG;
+		rsp_code = SRP_TASK_MANAGEMENT_FUNCTION_FAILED;
+		break;
 	}
 
-	pr_debug("srp_data_length: %llx, srp_direction:%x\n",
-		 srp_data_length(scmd, srp_cmd_direction(scmd)),
-		 srp_cmd_direction(scmd));
-	data_len = srp_data_length(scmd, srp_cmd_direction(scmd));
+	tsk_status = (u32 *)data;
+	*tsk_status = cpu_to_be32(rsp_code);
+	data = (char *)(tsk_status + 1);
+	len += 4;
 
-	vsc->se_cmd.tag = scmd->tag;
-	se_cmd = &vsc->se_cmd;
+	send_iu(iue, len, VIOSRP_SRP_FORMAT);
+}
 
-	pr_debug("size of lun:%lx, lun:%s\n", sizeof(scmd->lun),
-		 &scmd->lun.scsi_lun[0]);
+static void ibmvscsis_aborted_task(struct se_cmd *se_cmd)
+{
+}
 
-	unpacked_lun = ibmvscsis_unpack_lun((u8 *)&scmd->lun,
-					    sizeof(scmd->lun));
+static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf,
+					   struct config_group *group,
+					   const char *name)
+{
+	struct ibmvscsis_tport *tport;
+	int ret;
 
-	ret = target_submit_cmd(se_cmd, adapter->tport.se_sess,
-				&scmd->cdb[0], &vsc->sense_buf[0], unpacked_lun,
-				data_len, attr, srp_cmd_direction(scmd),
-				TARGET_SCF_ACK_KREF);
-	if (ret != 0) {
-		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-		pr_debug("tcm_queuecommand fail submit_cmd\n");
-		goto send_sense;
+	tport = ibmvscsis_lookup_port(name);
+	ret = -EINVAL;
+
+	if (!tport)
+		goto err;
+
+	tport->tport_proto_id = SCSI_PROTOCOL_SRP;
+	pr_debug("make_tport(%s), pointer:%p tport_id:%x\n", name, tport,
+		 tport->tport_proto_id);
+
+	return &tport->tport_wwn;
+err:
+	return ERR_PTR(ret);
+}
+
+static void ibmvscsis_drop_tport(struct se_wwn *wwn)
+{
+	struct ibmvscsis_tport *tport = container_of(wwn,
+						     struct ibmvscsis_tport,
+						     tport_wwn);
+
+	pr_debug("drop_tport(%s\n",
+		 config_item_name(&tport->tport_wwn.wwn_group.cg_item));
+}
+
+static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
+						  struct config_group *group,
+						  const char *name)
+{
+	struct ibmvscsis_tport *tport =
+		container_of(wwn, struct ibmvscsis_tport, tport_wwn);
+	int ret;
+
+	tport->releasing = false;
+
+	ret = core_tpg_register(&tport->tport_wwn,
+				&tport->se_tpg,
+				tport->tport_proto_id);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return &tport->se_tpg;
+}
+
+static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg)
+{
+	struct ibmvscsis_tport *tport = container_of(se_tpg,
+						     struct ibmvscsis_tport,
+						     se_tpg);
+
+	tport->releasing = true;
+	tport->enabled = false;
+
+	/*
+	 * Release the virtual I_T Nexus for this ibmvscsis TPG
+	 */
+	ibmvscsis_drop_nexus(tport);
+	/*
+	 * Deregister the se_tpg from TCM..
+	 */
+	core_tpg_deregister(se_tpg);
+}
+
+static ssize_t ibmvscsis_wwn_version_show(struct config_item *item,
+					  char *page)
+{
+	return scnprintf(page, PAGE_SIZE, "%s\n", IBMVSCSIS_VERSION);
+}
+CONFIGFS_ATTR_RO(ibmvscsis_wwn_, version);
+
+static struct configfs_attribute *ibmvscsis_wwn_attrs[] = {
+	&ibmvscsis_wwn_attr_version,
+	NULL,
+};
+
+static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item,
+					 char *page)
+{
+	struct se_portal_group *se_tpg = to_tpg(item);
+	struct ibmvscsis_tport *tport = container_of(se_tpg,
+						     struct ibmvscsis_tport,
+						     se_tpg);
+
+	return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0);
+}
+
+static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item,
+					  const char *page, size_t count)
+{
+	struct se_portal_group *se_tpg = to_tpg(item);
+	struct ibmvscsis_tport *tport = container_of(se_tpg,
+						     struct ibmvscsis_tport,
+						     se_tpg);
+	unsigned long tmp;
+	int ret;
+
+	ret = kstrtoul(page, 0, &tmp);
+	if (ret < 0) {
+		pr_err("Unable to extract ibmvscsis_tpg_store_enable\n");
+		return -EINVAL;
 	}
-	return 0;
 
-send_sense:
-	transport_send_check_condition_and_sense(&vsc->se_cmd, ret, 0);
-	transport_generic_free_cmd(&vsc->se_cmd, 0);
-	return -1;
+	if ((tmp != 0) && (tmp != 1)) {
+		pr_err("Illegal value for ibmvscsis_tpg_store_enable: %lu\n",
+		       tmp);
+		return -EINVAL;
+	}
+
+	if (tmp == 1)
+		tport->enabled = true;
+	else
+		tport->enabled = false;
+
+	return count;
 }
+CONFIGFS_ATTR(ibmvscsis_tpg_, enable);
+
+static struct configfs_attribute *ibmvscsis_tpg_attrs[] = {
+			&ibmvscsis_tpg_attr_enable,
+			NULL,
+};
+
+static const struct target_core_fabric_ops ibmvscsis_ops = {
+	.module				= THIS_MODULE,
+	.name				= "ibmvscsis",
+	.max_data_sg_nents		= SCSI_MAX_SG_SEGMENTS,
+	.get_fabric_name		= ibmvscsis_get_fabric_name,
+	.tpg_get_wwn			= ibmvscsis_get_fabric_wwn,
+	.tpg_get_tag			= ibmvscsis_get_tag,
+	.tpg_get_default_depth		= ibmvscsis_get_default_depth,
+	.tpg_check_demo_mode		= ibmvscsis_check_true,
+	.tpg_check_demo_mode_cache	= ibmvscsis_check_true,
+	.tpg_check_demo_mode_write_protect = ibmvscsis_check_false,
+	.tpg_check_prod_mode_write_protect = ibmvscsis_check_false,
+	.tpg_get_inst_index		= ibmvscsis_tpg_get_inst_index,
+	.check_stop_free		= ibmvscsis_check_stop_free,
+	.release_cmd			= ibmvscsis_release_cmd,
+	.shutdown_session		= ibmvscsis_shutdown_session,
+	.close_session			= ibmvscsis_close_session,
+	.sess_get_index			= ibmvscsis_sess_get_index,
+	.write_pending			= ibmvscsis_write_pending,
+	.write_pending_status		= ibmvscsis_write_pending_status,
+	.set_default_node_attributes	= ibmvscsis_set_default_node_attrs,
+	.get_cmd_state			= ibmvscsis_get_cmd_state,
+	.queue_data_in			= ibmvscsis_queue_data_in,
+	.queue_status			= ibmvscsis_queue_status,
+	.queue_tm_rsp			= ibmvscsis_queue_tm_rsp,
+	.aborted_task			= ibmvscsis_aborted_task,
+	/*
+	 * Setup function pointers for logic in target_cor_fabric_configfs.c
+	 */
+	.fabric_make_wwn		= ibmvscsis_make_tport,
+	.fabric_drop_wwn		= ibmvscsis_drop_tport,
+	.fabric_make_tpg		= ibmvscsis_make_tpg,
+	.fabric_drop_tpg		= ibmvscsis_drop_tpg,
+
+	.tfc_wwn_attrs			= ibmvscsis_wwn_attrs,
+	.tfc_tpg_base_attrs		= ibmvscsis_tpg_attrs,
+};
+
+static void ibmvscsis_dev_release(struct device *dev) {};
+
+static struct class_attribute ibmvscsis_class_attrs[] = {
+	__ATTR_NULL,
+};
+
+static struct device_attribute dev_attr_system_id =
+	__ATTR(system_id, S_IRUGO, system_id_show, NULL);
+
+static struct device_attribute dev_attr_partition_number =
+	__ATTR(partition_number, S_IRUGO, partition_number_show, NULL);
+
+static struct device_attribute dev_attr_unit_address =
+	__ATTR(unit_address, S_IRUGO, unit_address_show, NULL);
+
+static struct attribute *ibmvscsis_dev_attrs[] = {
+	&dev_attr_system_id.attr,
+	&dev_attr_partition_number.attr,
+	&dev_attr_unit_address.attr,
+};
+ATTRIBUTE_GROUPS(ibmvscsis_dev);
+
+static struct class ibmvscsis_class = {
+	.name           = "ibmvscsis",
+	.dev_release    = ibmvscsis_dev_release,
+	.class_attrs    = ibmvscsis_class_attrs,
+	.dev_groups     = ibmvscsis_dev_groups,
+};
+
+static struct vio_device_id ibmvscsis_device_table[] = {
+	{"v-scsi-host", "IBM,v-scsi-host"},
+	{"", ""}
+};
+MODULE_DEVICE_TABLE(vio, ibmvscsis_device_table);
+
+static struct vio_driver ibmvscsis_driver = {
+	.name = ibmvscsis_driver_name,
+	.id_table = ibmvscsis_device_table,
+	.probe = ibmvscsis_probe,
+	.remove = ibmvscsis_remove,
+};
 
 /*
  * ibmvscsis_init() - Kernel Module initialization
-- 
2.5.4 (Apple Git-61)

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH 3/3] ibmvscsis: clean up functions
  2016-05-25 14:17   ` [PATCH 3/3] ibmvscsis: clean up functions Bryant G. Ly
@ 2016-05-25 14:44     ` Joe Perches
  0 siblings, 0 replies; 17+ messages in thread
From: Joe Perches @ 2016-05-25 14:44 UTC (permalink / raw)
  To: Bryant G. Ly, tyreld, bart.vanassche
  Cc: martin.petersen, akpm, kvalo, davem, mchehab, jslaby, bp,
	linux-kernel, linux-scsi, target-devel

On Wed, 2016-05-25 at 09:17 -0500, Bryant G. Ly wrote:
> From: bryantly <bryantly@linux.vnet.ibm.com>

Please use your whole name here and for your sign-off like:

From: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
Signed-off-by: Bryant G. Ly <bryantly@linux.vnet.ibm.com>

> This patch removes forward declarations and re-organizes the
> functions within the driver. This patch also fixes MAINTAINERS
> for ibmvscsis.

trivial note:

> diff --git a/drivers/scsi/ibmvscsi/ibmvscsis.c b/drivers/scsi/ibmvscsi/ibmvscsis.c
[]
>  static inline long h_copy_rdma(s64 length, u64 sliobn, u64 slioba,
>  			       u64 dliobn, u64 dlioba)
>  {
> 

Functions like this would be less indented and less
line wrapped for 80 columns if they were written:

	if (!se_cmd->residual_count)
		return;

	[unindented one level...]

etc...

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
  2016-05-24 20:00   ` Bryant G Ly
@ 2016-06-10 19:03       ` Bart Van Assche
  0 siblings, 0 replies; 17+ messages in thread
From: Bart Van Assche @ 2016-06-10 19:03 UTC (permalink / raw)
  To: Bryant G Ly
  Cc: James Bottomley, martin.petersen, tyreld, akpm, kvalo, davem,
	gregkh, mchehab, jslaby, joe, bp, linux-kernel, linux-scsi,
	target-devel, bgly

On 05/24/2016 01:00 PM, Bryant G Ly wrote:
> Quoting Bart Van Assche <bart.vanassche@sandisk.com>:
>> On 05/24/2016 06:52 AM, Bryant G. Ly wrote:
>>> +static uint64_t ibmvscsis_unpack_lun(const uint8_t *lun, int len)
>>> +{
>>> +    uint64_t res = NO_SUCH_LUN;
>>> +    int addressing_method;
>>> +
>>> +    if (unlikely(len < 2)) {
>>> +        pr_err("Illegal LUN length %d, expected 2 bytes or more\n",
>>> +            len);
>>> +        goto out;
>>> +    }
>>> +
>>> +    switch (len) {
>>> +    case 8:
>>> +        if ((*((__be64 *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL))
>>> != 0)
>>> +            goto out_err;
>>> +        break;
>>> +    case 4:
>>> +        if (*((__be16 *)&lun[2]) != 0)
>>> +            goto out_err;
>>> +        break;
>>> +    case 6:
>>> +        if (*((__be32 *)&lun[2]) != 0)
>>> +            goto out_err;
>>> +        break;
>>> +    case 2:
>>> +        break;
>>> +    default:
>>> +        goto out_err;
>>> +    }
>>> +
>>> +    addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */
>>> +    switch (addressing_method) {
>>> +    case SCSI_LUN_ADDR_METHOD_PERIPHERAL:
>>> +    case SCSI_LUN_ADDR_METHOD_FLAT:
>>> +    case SCSI_LUN_ADDR_METHOD_LUN:
>>> +        res = *(lun + 1) | (((*lun) & 0x3f) << 8);
>>> +        break;
>>> +
>>> +    case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN:
>>> +    default:
>>> +        pr_err("Unimplemented LUN addressing method %u\n",
>>> +            addressing_method);
>>> +        break;
>>> +    }
>>> +
>>> +out:
>>> +    return res;
>>> +out_err:
>>> +    pr_err("Support for multi-level LUNs has not yet been
>>> implemented\n");
>>> +    goto out;
>>> +}
>>
>> In the above function there is nothing that is specific to the VIO
>> mechanism. Please consider to merge this function with
>> scsilun_to_int(), e.g. by introducing a new function that accepts a
>> SCSI LUN and the addressing method as arguments and by making
>> scsilun_to_int() call that function with
>> SCSI_LUN_ADDR_METHOD_PERIPHERAL as one of its arguments.
>>
>
> We are going to keep this here atm, until we can make sure canonical can
> pick up
> these changes, since we have a deliverable for a 3rd party vendor who is
> going to
> fully utilize this driver. Once they can pick it up in 4.4 kernel I will
> make the
> change you recommended / move the scsi_lun_addr_method addressed below.
> I will also
> address the changes that ib_srpt needs to utilize this new function too.

A much better approach would be to move this function into the SCSI core 
and to add a copy of that function to the backported driver that will be 
provided to Canonical.

Thanks,

Bart.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
@ 2016-06-10 19:03       ` Bart Van Assche
  0 siblings, 0 replies; 17+ messages in thread
From: Bart Van Assche @ 2016-06-10 19:03 UTC (permalink / raw)
  To: Bryant G Ly
  Cc: James Bottomley, martin.petersen, tyreld, akpm, kvalo, davem,
	gregkh, mchehab, jslaby, joe, bp, linux-kernel, linux-scsi,
	target-devel, bgly

On 05/24/2016 01:00 PM, Bryant G Ly wrote:
> Quoting Bart Van Assche <bart.vanassche@sandisk.com>:
>> On 05/24/2016 06:52 AM, Bryant G. Ly wrote:
>>> +static uint64_t ibmvscsis_unpack_lun(const uint8_t *lun, int len)
>>> +{
>>> +    uint64_t res = NO_SUCH_LUN;
>>> +    int addressing_method;
>>> +
>>> +    if (unlikely(len < 2)) {
>>> +        pr_err("Illegal LUN length %d, expected 2 bytes or more\n",
>>> +            len);
>>> +        goto out;
>>> +    }
>>> +
>>> +    switch (len) {
>>> +    case 8:
>>> +        if ((*((__be64 *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL))
>>> != 0)
>>> +            goto out_err;
>>> +        break;
>>> +    case 4:
>>> +        if (*((__be16 *)&lun[2]) != 0)
>>> +            goto out_err;
>>> +        break;
>>> +    case 6:
>>> +        if (*((__be32 *)&lun[2]) != 0)
>>> +            goto out_err;
>>> +        break;
>>> +    case 2:
>>> +        break;
>>> +    default:
>>> +        goto out_err;
>>> +    }
>>> +
>>> +    addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */
>>> +    switch (addressing_method) {
>>> +    case SCSI_LUN_ADDR_METHOD_PERIPHERAL:
>>> +    case SCSI_LUN_ADDR_METHOD_FLAT:
>>> +    case SCSI_LUN_ADDR_METHOD_LUN:
>>> +        res = *(lun + 1) | (((*lun) & 0x3f) << 8);
>>> +        break;
>>> +
>>> +    case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN:
>>> +    default:
>>> +        pr_err("Unimplemented LUN addressing method %u\n",
>>> +            addressing_method);
>>> +        break;
>>> +    }
>>> +
>>> +out:
>>> +    return res;
>>> +out_err:
>>> +    pr_err("Support for multi-level LUNs has not yet been
>>> implemented\n");
>>> +    goto out;
>>> +}
>>
>> In the above function there is nothing that is specific to the VIO
>> mechanism. Please consider to merge this function with
>> scsilun_to_int(), e.g. by introducing a new function that accepts a
>> SCSI LUN and the addressing method as arguments and by making
>> scsilun_to_int() call that function with
>> SCSI_LUN_ADDR_METHOD_PERIPHERAL as one of its arguments.
>>
>
> We are going to keep this here atm, until we can make sure canonical can
> pick up
> these changes, since we have a deliverable for a 3rd party vendor who is
> going to
> fully utilize this driver. Once they can pick it up in 4.4 kernel I will
> make the
> change you recommended / move the scsi_lun_addr_method addressed below.
> I will also
> address the changes that ib_srpt needs to utilize this new function too.

A much better approach would be to move this function into the SCSI core 
and to add a copy of that function to the backported driver that will be 
provided to Canonical.

Thanks,

Bart.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
  2016-06-10 19:03       ` Bart Van Assche
  (?)
@ 2016-06-14  6:23       ` Nicholas A. Bellinger
  2016-06-14 14:55         ` Christoph Hellwig
  -1 siblings, 1 reply; 17+ messages in thread
From: Nicholas A. Bellinger @ 2016-06-14  6:23 UTC (permalink / raw)
  To: Bart Van Assche
  Cc: Bryant G Ly, James Bottomley, martin.petersen, tyreld, akpm,
	kvalo, davem, gregkh, mchehab, jslaby, joe, bp, linux-kernel,
	linux-scsi, target-devel, bgly

On Fri, 2016-06-10 at 12:03 -0700, Bart Van Assche wrote:
> On 05/24/2016 01:00 PM, Bryant G Ly wrote:
> > Quoting Bart Van Assche <bart.vanassche@sandisk.com>:
> >> On 05/24/2016 06:52 AM, Bryant G. Ly wrote:
> >>> +static uint64_t ibmvscsis_unpack_lun(const uint8_t *lun, int len)
> >>> +{
> >>> +    uint64_t res = NO_SUCH_LUN;
> >>> +    int addressing_method;
> >>> +
> >>> +    if (unlikely(len < 2)) {
> >>> +        pr_err("Illegal LUN length %d, expected 2 bytes or more\n",
> >>> +            len);
> >>> +        goto out;
> >>> +    }
> >>> +
> >>> +    switch (len) {
> >>> +    case 8:
> >>> +        if ((*((__be64 *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL))
> >>> != 0)
> >>> +            goto out_err;
> >>> +        break;
> >>> +    case 4:
> >>> +        if (*((__be16 *)&lun[2]) != 0)
> >>> +            goto out_err;
> >>> +        break;
> >>> +    case 6:
> >>> +        if (*((__be32 *)&lun[2]) != 0)
> >>> +            goto out_err;
> >>> +        break;
> >>> +    case 2:
> >>> +        break;
> >>> +    default:
> >>> +        goto out_err;
> >>> +    }
> >>> +
> >>> +    addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */
> >>> +    switch (addressing_method) {
> >>> +    case SCSI_LUN_ADDR_METHOD_PERIPHERAL:
> >>> +    case SCSI_LUN_ADDR_METHOD_FLAT:
> >>> +    case SCSI_LUN_ADDR_METHOD_LUN:
> >>> +        res = *(lun + 1) | (((*lun) & 0x3f) << 8);
> >>> +        break;
> >>> +
> >>> +    case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN:
> >>> +    default:
> >>> +        pr_err("Unimplemented LUN addressing method %u\n",
> >>> +            addressing_method);
> >>> +        break;
> >>> +    }
> >>> +
> >>> +out:
> >>> +    return res;
> >>> +out_err:
> >>> +    pr_err("Support for multi-level LUNs has not yet been
> >>> implemented\n");
> >>> +    goto out;
> >>> +}
> >>
> >> In the above function there is nothing that is specific to the VIO
> >> mechanism. Please consider to merge this function with
> >> scsilun_to_int(), e.g. by introducing a new function that accepts a
> >> SCSI LUN and the addressing method as arguments and by making
> >> scsilun_to_int() call that function with
> >> SCSI_LUN_ADDR_METHOD_PERIPHERAL as one of its arguments.
> >>
> >
> > We are going to keep this here atm, until we can make sure canonical can
> > pick up
> > these changes, since we have a deliverable for a 3rd party vendor who is
> > going to
> > fully utilize this driver. Once they can pick it up in 4.4 kernel I will
> > make the
> > change you recommended / move the scsi_lun_addr_method addressed below.
> > I will also
> > address the changes that ib_srpt needs to utilize this new function too.
> 
> A much better approach would be to move this function into the SCSI core 
> and to add a copy of that function to the backported driver that will be 
> provided to Canonical.

AFAICT, the problem with this improvement is that it's not stable
material, which means that Canonical would have to carry this separately
beyond linux-4.4.y, in order to support ibmvscsi-tgt.

As-is, it looks like we'll have two target-core fixes to support
ibmvscsi-tgt, both of which are considered stable material at this point
and will eventually make it to linux-4.4.y.

That said Bryant, I still don't have an objection for the initial commit
to use it's own internal ibmvscsis_unpack_lun(), but it would be nice in
the patch series containing the initial ibmvscsi-tgt commit to include
an incremental patch to make this common code, as Bart has highlighted.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver
  2016-06-14  6:23       ` Nicholas A. Bellinger
@ 2016-06-14 14:55         ` Christoph Hellwig
  0 siblings, 0 replies; 17+ messages in thread
From: Christoph Hellwig @ 2016-06-14 14:55 UTC (permalink / raw)
  To: Nicholas A. Bellinger
  Cc: Bart Van Assche, Bryant G Ly, James Bottomley, martin.petersen,
	tyreld, akpm, kvalo, davem, gregkh, mchehab, jslaby, joe, bp,
	linux-kernel, linux-scsi, target-devel, bgly

On Mon, Jun 13, 2016 at 11:23:52PM -0700, Nicholas A. Bellinger wrote:
> AFAICT, the problem with this improvement is that it's not stable
> material, which means that Canonical would have to carry this separately
> beyond linux-4.4.y, in order to support ibmvscsi-tgt.

So who cares?  If they have a business interest in backporting the
driver they'll need to figure out a way.  None of that should matter in
any way whatsover for mainline.

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2016-06-14 14:56 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-24 13:52 [PATCH] ibmvscsis: Initial commit of IBM VSCSI Tgt Driver Bryant G. Ly
2016-05-24 14:14 ` Joe Perches
2016-05-24 14:30 ` Greg KH
2016-05-24 16:25 ` Bart Van Assche
2016-05-24 16:25   ` Bart Van Assche
2016-05-24 16:34   ` Greg KH
2016-05-24 16:44     ` Bart Van Assche
2016-05-24 16:50       ` Greg KH
2016-05-24 20:00   ` Bryant G Ly
2016-06-10 19:03     ` Bart Van Assche
2016-06-10 19:03       ` Bart Van Assche
2016-06-14  6:23       ` Nicholas A. Bellinger
2016-06-14 14:55         ` Christoph Hellwig
2016-05-25 14:17 ` IBM VSCSI Target Driver Initial Patch Sets Bryant G. Ly
2016-05-25 14:17   ` [PATCH 2/3] ibmvscsis: Addressing Bart's comments Bryant G. Ly
2016-05-25 14:17   ` [PATCH 3/3] ibmvscsis: clean up functions Bryant G. Ly
2016-05-25 14:44     ` Joe Perches

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.