From: Sergey Gorenko <sergeygo@nvidia.com>
Subject: [PATCH] BACKPORT: drivers/infiniband/ulp/srp/ib_srp.c

Change-Id: I2a1872c43a93aea0a0ffa9abd319d67dc829e1c5
---
 drivers/infiniband/ulp/srp/ib_srp.c | 512 +++++++++++++++++++++++++++-
 1 file changed, 511 insertions(+), 1 deletion(-)

--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -64,10 +64,30 @@
 MODULE_AUTHOR("Roland Dreier");
 MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator");
 MODULE_LICENSE("Dual BSD/GPL");
+#ifdef RETPOLINE_MLNX
+MODULE_INFO(retpoline, "Y");
+#endif
 
 #if !defined(CONFIG_DYNAMIC_DEBUG)
 #define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)
 #define DYNAMIC_DEBUG_BRANCH(descriptor) false
+#else
+#if defined(DEFINE_DYNAMIC_DEBUG_METADATA) && !defined(DYNAMIC_DEBUG_BRANCH)
+#ifdef DEBUG
+#define DYNAMIC_DEBUG_BRANCH(descriptor) \
+	        likely(descriptor.flags & _DPRINTK_FLAGS_PRINT)
+#else
+#define DYNAMIC_DEBUG_BRANCH(descriptor) \
+	        unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)
+#endif
+#endif
+#endif
+
+#ifndef DEFINE_DYNAMIC_DEBUG_METADATA
+#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)
+#endif
+#ifndef DYNAMIC_DEBUG_BRANCH
+#define DYNAMIC_DEBUG_BRANCH(descriptor) false
 #endif
 
 static unsigned int srp_sg_tablesize;
@@ -86,8 +106,13 @@ MODULE_PARM_DESC(cmd_sg_entries,
 		 "Default number of gather/scatter entries in the SRP command (default is 12, max 255)");
 
 module_param(indirect_sg_entries, uint, 0444);
+#ifdef HAVE_SG_MAX_SEGMENTS
 MODULE_PARM_DESC(indirect_sg_entries,
 		 "Default max number of gather/scatter entries (default is 12, max is " __stringify(SG_MAX_SEGMENTS) ")");
+#else
+MODULE_PARM_DESC(indirect_sg_entries,
+		 "Default max number of gather/scatter entries (default is 12, max is " __stringify(SCSI_MAX_SG_CHAIN_SEGMENTS) ")");
+#endif
 
 module_param(allow_ext_sg, bool, 0444);
 MODULE_PARM_DESC(allow_ext_sg,
@@ -965,6 +990,7 @@ static void srp_disconnect_target(struct
 	}
 }
 
+#ifdef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
 static int srp_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
 {
 	struct srp_target_port *target = host_to_target(shost);
@@ -1016,6 +1042,81 @@ static int srp_init_cmd_priv(struct Scsi
 out:
 	return ret;
 }
+#else /* HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV */
+static void srp_free_req_data(struct srp_target_port *target,
+			      struct srp_rdma_ch *ch)
+{
+	struct srp_device *dev = target->srp_host->srp_dev;
+	struct ib_device *ibdev = dev->dev;
+	struct srp_request *req;
+	int i;
+
+	if (!ch->req_ring)
+		return;
+
+	for (i = 0; i < target->req_ring_size; ++i) {
+		req = &ch->req_ring[i];
+		if (dev->use_fast_reg)
+			kfree(req->fr_list);
+		if (req->indirect_dma_addr) {
+			ib_dma_unmap_single(ibdev, req->indirect_dma_addr,
+					    target->indirect_size,
+					    DMA_TO_DEVICE);
+		}
+		kfree(req->indirect_desc);
+	}
+
+	kfree(ch->req_ring);
+	ch->req_ring = NULL;
+}
+
+static int srp_alloc_req_data(struct srp_rdma_ch *ch)
+{
+	struct srp_target_port *target = ch->target;
+	struct srp_device *srp_dev = target->srp_host->srp_dev;
+	struct ib_device *ibdev = srp_dev->dev;
+	struct srp_request *req;
+	dma_addr_t dma_addr;
+	int i, ret = -ENOMEM;
+
+#ifndef HAVE_BLK_TAGS
+	INIT_LIST_HEAD(&ch->free_reqs);
+#endif
+	ch->req_ring = kcalloc(target->req_ring_size, sizeof(*ch->req_ring),
+			       GFP_KERNEL);
+	if (!ch->req_ring)
+		goto out;
+
+	for (i = 0; i < target->req_ring_size; ++i) {
+		req = &ch->req_ring[i];
+		if (srp_dev->use_fast_reg) {
+			req->fr_list = kmalloc_array(target->mr_per_cmd,
+						sizeof(void *), GFP_KERNEL);
+			if (!req->fr_list)
+				goto out;
+		}
+		req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL);
+		if (!req->indirect_desc)
+			goto out;
+
+		dma_addr = ib_dma_map_single(ibdev, req->indirect_desc,
+					     target->indirect_size,
+					     DMA_TO_DEVICE);
+		if (ib_dma_mapping_error(ibdev, dma_addr))
+			goto out;
+
+		req->indirect_dma_addr = dma_addr;
+#ifndef HAVE_BLK_TAGS
+		req->tag = build_srp_tag(ch - target->ch, i);
+		list_add_tail(&req->list, &ch->free_reqs);
+#endif
+	}
+	ret = 0;
+
+out:
+	return ret;
+}
+#endif /* HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV */
 
 /**
  * srp_del_scsi_host_attr() - Remove attributes defined in the host template.
@@ -1026,6 +1127,7 @@ out:
  */
 static void srp_del_scsi_host_attr(struct Scsi_Host *shost)
 {
+#ifdef HAVE_SCSI_HOST_TEMPLATE_SHOST_GROUPS
 	const struct attribute_group **g;
 	struct attribute **attr;
 
@@ -1037,6 +1139,12 @@ static void srp_del_scsi_host_attr(struc
 			device_remove_file(&shost->shost_dev, dev_attr);
 		}
 	}
+#else
+	struct device_attribute **attr;
+
+	for (attr = shost->hostt->shost_attrs; attr && *attr; ++attr)
+		device_remove_file(&shost->shost_dev, *attr);
+#endif
 }
 
 static void srp_remove_target(struct srp_target_port *target)
@@ -1052,13 +1160,25 @@ static void srp_remove_target(struct srp
 	scsi_remove_host(target->scsi_host);
 	srp_stop_rport_timers(target->rport);
 	srp_disconnect_target(target);
+#ifdef HAVE_KOBJ_NS_GRAB_CURRENT_EXPORTED
 	kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net);
+#endif
 	for (i = 0; i < target->ch_count; i++) {
 		ch = &target->ch[i];
 		srp_free_ch_ib(target, ch);
 	}
 	cancel_work_sync(&target->tl_err_work);
 	srp_rport_put(target->rport);
+#ifndef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
+	for (i = 0; i < target->ch_count; i++) {
+		ch = &target->ch[i];
+		srp_free_req_data(target, ch);
+	}
+#endif
+#ifndef HAVE_BLK_TAGS
+	kfree(target->mq_map);
+	target->mq_map = NULL;
+#endif
 	kfree(target->ch);
 	target->ch = NULL;
 
@@ -1262,6 +1382,9 @@ static void srp_free_req(struct srp_rdma
 
 	spin_lock_irqsave(&ch->lock, flags);
 	ch->req_lim += req_lim_delta;
+#ifndef HAVE_BLK_TAGS
+	list_add_tail(&req->list, &ch->free_reqs);
+#endif
 	spin_unlock_irqrestore(&ch->lock, flags);
 }
 
@@ -1273,21 +1396,34 @@ static void srp_finish_req(struct srp_rd
 	if (scmnd) {
 		srp_free_req(ch, req, scmnd, 0);
 		scmnd->result = result;
+#ifdef HAVE_SCSI_DONE
 		scsi_done(scmnd);
+#else
+		scmnd->scsi_done(scmnd);
+#endif
 	}
 }
 
+#ifdef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
 struct srp_terminate_context {
 	struct srp_target_port *srp_target;
 	int scsi_result;
 };
 
+#ifdef HAVE_SCSI_HOST_BUSY_ITER_FN_2_ARGS
+static bool srp_terminate_cmd(struct scsi_cmnd *scmnd, void *context_ptr)
+#else
 static bool srp_terminate_cmd(struct scsi_cmnd *scmnd, void *context_ptr,
 			      bool reserved)
+#endif
 {
 	struct srp_terminate_context *context = context_ptr;
 	struct srp_target_port *target = context->srp_target;
+#ifdef HAVE_SCSI_CMD_TO_RQ
 	u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmnd));
+#else
+	u32 tag = blk_mq_unique_tag(scmnd->request);
+#endif
 	struct srp_rdma_ch *ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)];
 	struct srp_request *req = scsi_cmd_priv(scmnd);
 
@@ -1304,6 +1440,25 @@ static void srp_terminate_io(struct srp_
 
 	scsi_host_busy_iter(target->scsi_host, srp_terminate_cmd, &context);
 }
+#else
+static void srp_terminate_io(struct srp_rport *rport)
+{
+	struct srp_target_port *target = rport->lld_data;
+	struct srp_rdma_ch *ch;
+	int i, j;
+
+	for (i = 0; i < target->ch_count; i++) {
+		ch = &target->ch[i];
+
+		for (j = 0; j < target->req_ring_size; ++j) {
+			struct srp_request *req = &ch->req_ring[j];
+
+			srp_finish_req(ch, req, NULL,
+				       DID_TRANSPORT_FAILFAST << 16);
+		}
+	}
+}
+#endif /* HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV */
 
 /* Calculate maximum initiator to target information unit length. */
 static uint32_t srp_max_it_iu_len(int cmd_sg_cnt, bool use_imm_data,
@@ -1358,6 +1513,7 @@ static int srp_rport_reconnect(struct sr
 		ch = &target->ch[i];
 		ret += srp_new_cm_id(ch);
 	}
+#ifdef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
 	{
 		struct srp_terminate_context context = {
 			.srp_target = target, .scsi_result = DID_RESET << 16};
@@ -1365,6 +1521,16 @@ static int srp_rport_reconnect(struct sr
 		scsi_host_busy_iter(target->scsi_host, srp_terminate_cmd,
 				    &context);
 	}
+#else
+	for (i = 0; i < target->ch_count; i++) {
+		ch = &target->ch[i];
+		for (j = 0; j < target->req_ring_size; ++j) {
+			struct srp_request *req = &ch->req_ring[j];
+
+			srp_finish_req(ch, req, NULL, DID_RESET << 16);
+		}
+	}
+#endif
 	for (i = 0; i < target->ch_count; i++) {
 		ch = &target->ch[i];
 		/*
@@ -1942,6 +2108,9 @@ static void srp_process_rsp(struct srp_r
 	struct srp_request *req;
 	struct scsi_cmnd *scmnd;
 	unsigned long flags;
+#ifndef HAVE_BLK_TAGS
+	unsigned i;
+#endif
 
 	if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) {
 		spin_lock_irqsave(&ch->lock, flags);
@@ -1958,11 +2127,31 @@ static void srp_process_rsp(struct srp_r
 		}
 		spin_unlock_irqrestore(&ch->lock, flags);
 	} else {
+#ifdef HAVE_BLK_TAGS
 		scmnd = scsi_host_find_tag(target->scsi_host, rsp->tag);
+#ifdef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
 		if (scmnd) {
 			req = scsi_cmd_priv(scmnd);
+#else
+		if (scmnd && scmnd->host_scribble) {
+			req = (void *)scmnd->host_scribble;
+#endif
 			scmnd = srp_claim_req(ch, req, NULL, scmnd);
+#else
+		if (srp_tag_ch(rsp->tag) != ch - target->ch)
+			pr_err("Channel idx mismatch: tag %#llx <> ch %#lx\n",
+			       rsp->tag, ch - target->ch);
+		i = srp_tag_idx(rsp->tag);
+		if (i < target->req_ring_size) {
+			req = &ch->req_ring[i];
+			scmnd = srp_claim_req(ch, req, NULL, NULL);
+#endif
 		} else {
+#ifndef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
+			scmnd = NULL;
+		}
+		if (!scmnd) {
+#endif
 			shost_printk(KERN_ERR, target->scsi_host,
 				     "Null scmnd for RSP w/tag %#016llx received on ch %td / QP %#x\n",
 				     rsp->tag, ch - target->ch, ch->qp->qp_num);
@@ -1994,7 +2183,14 @@ static void srp_process_rsp(struct srp_r
 		srp_free_req(ch, req, scmnd,
 			     be32_to_cpu(rsp->req_lim_delta));
 
+#ifndef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
+		scmnd->host_scribble = NULL;
+#endif
+#ifdef HAVE_SCSI_DONE
 		scsi_done(scmnd);
+#else
+		scmnd->scsi_done(scmnd);
+#endif
 	}
 }
 
@@ -2056,9 +2252,10 @@ static void srp_process_aer_req(struct s
 		.tag = req->tag,
 	};
 	s32 delta = be32_to_cpu(req->req_lim_delta);
+	uint64_t lun = scsilun_to_int(&req->lun);
 
 	shost_printk(KERN_ERR, target->scsi_host, PFX
-		     "ignoring AER for LUN %llu\n", scsilun_to_int(&req->lun));
+		     "ignoring AER for LUN %llu\n", lun);
 
 	if (srp_response_common(ch, delta, &rsp, sizeof(rsp)))
 		shost_printk(KERN_ERR, target->scsi_host, PFX
@@ -2156,39 +2353,84 @@ static void srp_handle_qp_err(struct ib_
 	}
 	target->qp_in_error = true;
 }
+#ifndef HAVE_BLK_TAGS
+static struct srp_rdma_ch *srp_map_cpu_to_ch(struct srp_target_port *target)
+{
+	return &target->ch[target->mq_map[raw_smp_processor_id()]];
+}
+#endif
 
 static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
 {
+#ifdef HAVE_BLK_TAGS
+#ifdef HAVE_SCSI_CMD_TO_RQ
 	struct request *rq = scsi_cmd_to_rq(scmnd);
+#else
+	struct request *rq = scmnd->request;
+#endif
+#endif
 	struct srp_target_port *target = host_to_target(shost);
 	struct srp_rdma_ch *ch;
+#ifdef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
 	struct srp_request *req = scsi_cmd_priv(scmnd);
+#else
+	struct srp_request *req;
+#endif
 	struct srp_iu *iu;
 	struct srp_cmd *cmd;
 	struct ib_device *dev;
 	unsigned long flags;
 	u32 tag;
+#if defined(HAVE_BLK_TAGS) && !defined(HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV)
+	u16 idx;
+#endif
 	int len, ret;
 
 	scmnd->result = srp_chkready(target->rport);
 	if (unlikely(scmnd->result))
 		goto err;
 
+#ifdef HAVE_BLK_TAGS
 	WARN_ON_ONCE(rq->tag < 0);
 	tag = blk_mq_unique_tag(rq);
 	ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)];
+#ifndef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
+	idx = blk_mq_unique_tag_to_tag(tag);
+	WARN_ONCE(idx >= target->req_ring_size, "%s: tag %#x: idx %d >= %d\n",
+		  dev_name(&shost->shost_gendev), tag, idx,
+		  target->req_ring_size);
+#endif
+#else
+	ch = srp_map_cpu_to_ch(target);
+#endif
 
 	spin_lock_irqsave(&ch->lock, flags);
 	iu = __srp_get_tx_iu(ch, SRP_IU_CMD);
+#ifdef HAVE_BLK_TAGS
 	spin_unlock_irqrestore(&ch->lock, flags);
 
 	if (!iu)
 		goto err;
 
+#ifndef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
+	req = &ch->req_ring[idx];
+#endif
+#else
+	if (!iu)
+		goto err_unlock;
+
+	req = list_first_entry(&ch->free_reqs, struct srp_request, list);
+	list_del(&req->list);
+	tag = req->tag;
+	spin_unlock_irqrestore(&ch->lock, flags);
+#endif
 	dev = target->srp_host->srp_dev->dev;
 	ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_it_iu_len,
 				   DMA_TO_DEVICE);
 
+#ifndef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
+	scmnd->host_scribble = (void *) req;
+#endif
 	cmd = iu->buf;
 	memset(cmd, 0, sizeof *cmd);
 
@@ -2217,7 +2459,11 @@ static int srp_queuecommand(struct Scsi_
 		 * to reduce queue depth temporarily.
 		 */
 		scmnd->result = len == -ENOMEM ?
+#ifdef HAVE_SCSI_QUEUE_FULL
+			DID_OK << 16 | QUEUE_FULL << 1 : DID_ERROR << 16;
+#else
 			DID_OK << 16 | SAM_STAT_TASK_SET_FULL : DID_ERROR << 16;
+#endif
 		goto err_iu;
 	}
 
@@ -2244,9 +2490,20 @@ err_iu:
 	 */
 	req->scmnd = NULL;
 
+#ifndef HAVE_BLK_TAGS
+	spin_lock_irqsave(&ch->lock, flags);
+	list_add(&req->list, &ch->free_reqs);
+
+err_unlock:
+	spin_unlock_irqrestore(&ch->lock, flags);
+#endif
 err:
 	if (scmnd->result) {
+#ifdef HAVE_SCSI_DONE
 		scsi_done(scmnd);
+#else
+		scmnd->scsi_done(scmnd);
+#endif
 		ret = 0;
 	} else {
 		ret = SCSI_MLQUEUE_HOST_BUSY;
@@ -2705,6 +2962,30 @@ static int srp_rdma_cm_handler(struct rd
 	return 0;
 }
 
+#ifdef HAVE_SCSI_HOST_TEMPLATE_CHANGE_QUEUE_TYPE
+/**
+ * srp_change_queue_type - changing device queue tag type
+ * @sdev: scsi device struct
+ * @tag_type: requested tag type
+ *
+ * Returns queue tag type.
+ */
+static int
+srp_change_queue_type(struct scsi_device *sdev, int tag_type)
+{
+	if (sdev->tagged_supported) {
+		scsi_set_tag_type(sdev, tag_type);
+		if (tag_type)
+			scsi_activate_tcq(sdev, sdev->queue_depth);
+		else
+			scsi_deactivate_tcq(sdev, sdev->queue_depth);
+	} else
+		tag_type = 0;
+
+	return tag_type;
+}
+#endif
+
 /**
  * srp_change_queue_depth - setting device queue depth
  * @sdev: scsi device struct
@@ -2712,13 +2993,40 @@ static int srp_rdma_cm_handler(struct rd
  *
  * Returns queue depth.
  */
+#ifdef HAVE_SCSI_HOST_TEMPLATE_TRACK_QUEUE_DEPTH
 static int
 srp_change_queue_depth(struct scsi_device *sdev, int qdepth)
 {
 	if (!sdev->tagged_supported)
 		qdepth = 1;
+#ifdef HAVE_SCSI_CHANGE_QUEUE_DEPTH
 	return scsi_change_queue_depth(sdev, qdepth);
+#else
+	scsi_adjust_queue_depth(sdev, qdepth);
+	return sdev->queue_depth;
+#endif //HAVE_SCSI_CHANGE_QUEUE_DEPTH
+}
+#else
+static int
+srp_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
+{
+	struct Scsi_Host *shost = sdev->host;
+	int max_depth;
+	if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) {
+		max_depth = shost->can_queue;
+		if (!sdev->tagged_supported)
+			max_depth = 1;
+		if (qdepth > max_depth)
+			qdepth = max_depth;
+		scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+	} else if (reason == SCSI_QDEPTH_QFULL)
+		scsi_track_queue_full(sdev, qdepth);
+	else
+		return -EOPNOTSUPP;
+
+	return sdev->queue_depth;
 }
+#endif //HAVE_SCSI_HOST_TEMPLATE_TRACK_QUEUE_DEPTH
 
 static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun,
 			     u8 func, u8 *status)
@@ -2799,8 +3107,17 @@ static int srp_abort(struct scsi_cmnd *s
 
 	if (!req)
 		return SUCCESS;
+#ifdef HAVE_BLK_TAGS
+#ifdef HAVE_SCSI_CMD_TO_RQ
 	tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmnd));
+#else
+	tag = blk_mq_unique_tag(scmnd->request);
+#endif
 	ch_idx = blk_mq_unique_tag_to_hwq(tag);
+#else
+	tag = req->tag;
+	ch_idx = srp_tag_ch(tag);
+#endif
 	if (WARN_ON_ONCE(ch_idx >= target->ch_count))
 		return SUCCESS;
 	ch = &target->ch[ch_idx];
@@ -2818,7 +3135,11 @@ static int srp_abort(struct scsi_cmnd *s
 	if (ret == SUCCESS) {
 		srp_free_req(ch, req, scmnd, 0);
 		scmnd->result = DID_ABORT << 16;
+#ifdef HAVE_SCSI_DONE
 		scsi_done(scmnd);
+#else
+		scmnd->scsi_done(scmnd);
+#endif
 	}
 
 	return ret;
@@ -2861,6 +3182,20 @@ static int srp_target_alloc(struct scsi_
 	return 0;
 }
 
+#ifdef USE_SLAVE_ALLOC_HANDLER
+static int srp_slave_alloc(struct scsi_device *sdev)
+{
+	struct Scsi_Host *shost = sdev->host;
+	struct srp_target_port *target = host_to_target(shost);
+	struct srp_device *srp_dev = target->srp_host->srp_dev;
+
+	blk_queue_virt_boundary(sdev->request_queue,
+				~srp_dev->mr_page_mask);
+
+	return 0;
+}
+#endif
+
 static int srp_slave_configure(struct scsi_device *sdev)
 {
 	struct Scsi_Host *shost = sdev->host;
@@ -3057,6 +3392,7 @@ static ssize_t allow_ext_sg_show(struct
 
 static DEVICE_ATTR_RO(allow_ext_sg);
 
+#ifdef HAVE_SCSI_HOST_TEMPLATE_SHOST_GROUPS
 static struct attribute *srp_host_attrs[] = {
 	&dev_attr_id_ext.attr,
 	&dev_attr_ioc_guid.attr,
@@ -3078,18 +3414,47 @@ static struct attribute *srp_host_attrs[
 };
 
 ATTRIBUTE_GROUPS(srp_host);
+#else
+static struct device_attribute *srp_host_attrs[] = {
+	&dev_attr_id_ext,
+	&dev_attr_ioc_guid,
+	&dev_attr_service_id,
+	&dev_attr_pkey,
+	&dev_attr_sgid,
+	&dev_attr_dgid,
+	&dev_attr_orig_dgid,
+	&dev_attr_req_lim,
+	&dev_attr_zero_req_lim,
+	&dev_attr_local_ib_port,
+	&dev_attr_local_ib_device,
+	&dev_attr_ch_count,
+	&dev_attr_comp_vector,
+	&dev_attr_tl_retry_count,
+	&dev_attr_cmd_sg_entries,
+	&dev_attr_allow_ext_sg,
+	NULL
+};
+#endif /* HAVE_SCSI_HOST_TEMPLATE_SHOST_GROUPS */
 
 static struct scsi_host_template srp_template = {
 	.module				= THIS_MODULE,
 	.name				= "InfiniBand SRP initiator",
 	.proc_name			= DRV_NAME,
 	.target_alloc			= srp_target_alloc,
+#ifdef USE_SLAVE_ALLOC_HANDLER
+	.slave_alloc			= srp_slave_alloc,
+#endif
 	.slave_configure		= srp_slave_configure,
 	.info				= srp_target_info,
+#ifdef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
 	.init_cmd_priv			= srp_init_cmd_priv,
 	.exit_cmd_priv			= srp_exit_cmd_priv,
+#endif
 	.queuecommand			= srp_queuecommand,
 	.change_queue_depth             = srp_change_queue_depth,
+#ifdef HAVE_SCSI_HOST_TEMPLATE_CHANGE_QUEUE_TYPE
+	.change_queue_type		= srp_change_queue_type,
+#endif
 	.eh_timed_out			= srp_timed_out,
 	.eh_abort_handler		= srp_abort,
 	.eh_device_reset_handler	= srp_reset_device,
@@ -3099,9 +3464,26 @@ static struct scsi_host_template srp_tem
 	.can_queue			= SRP_DEFAULT_CMD_SQ_SIZE,
 	.this_id			= -1,
 	.cmd_per_lun			= SRP_DEFAULT_CMD_SQ_SIZE,
+#ifdef ENABLE_CLUSTERING
+	.use_clustering			= ENABLE_CLUSTERING,
+#endif
+#ifdef HAVE_SCSI_HOST_TEMPLATE_SHOST_GROUPS
 	.shost_groups			= srp_host_groups,
+#else
+	.shost_attrs			= srp_host_attrs,
+#endif
+#ifdef HAVE_SCSI_HOST_TEMPLATE_USE_HOST_WIDE_TAGS
+	.use_host_wide_tags		= 1,
+#endif
+#ifdef HAVE_SCSI_HOST_TEMPLATE_USE_BLK_TAGS
+	.use_blk_tags			= 1,
+#endif
+#ifdef HAVE_SCSI_HOST_TEMPLATE_TRACK_QUEUE_DEPTH
 	.track_queue_depth		= 1,
+#endif
+#ifdef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
 	.cmd_size			= sizeof(struct srp_request),
+#endif
 };
 
 static int srp_sdev_count(struct Scsi_Host *host)
@@ -3289,6 +3671,7 @@ static const match_table_t srp_opt_token
 	{ SRP_OPT_ERR,			NULL 			}
 };
 
+#ifdef HAVE_INET_PTON_WITH_SCOPE
 /**
  * srp_parse_in - parse an IP address and port number combination
  * @net:	   [in]  Network namespace.
@@ -3329,6 +3712,28 @@ static int srp_parse_in(struct net *net,
 	pr_debug("%s -> %pISpfsc\n", addr_port_str, sa);
 	return ret;
 }
+#else
+static int srp_parse_in(struct sockaddr_in *ip4, const char *p, bool *has_port)
+{
+	const char *dst_port_str = NULL;
+	u16 dst_port;
+
+	if (!in4_pton(p, -1, (u8 *)&ip4->sin_addr, ':', &dst_port_str))
+		return -1;
+
+	if (has_port) {
+		if (sscanf(dst_port_str, ":%hu", &dst_port) < 1) {
+			*has_port = false;
+		} else {
+			*has_port = true;
+			ip4->sin_port = htons(dst_port);
+		}
+	}
+	ip4->sin_family = AF_INET;
+
+	return 0;
+}
+#endif /* HAVE_INET_PTON_WITH_SCOPE */
 
 static int srp_parse_options(struct net *net, const char *buf,
 			     struct srp_target_port *target)
@@ -3436,8 +3841,12 @@ static int srp_parse_options(struct net
 				ret = -ENOMEM;
 				goto out;
 			}
+#ifdef HAVE_INET_PTON_WITH_SCOPE
 			ret = srp_parse_in(net, &target->rdma_cm.src.ss, p,
 					   NULL);
+#else
+			ret = srp_parse_in(&target->rdma_cm.src.ip4, p, NULL);
+#endif
 			if (ret < 0) {
 				pr_warn("bad source parameter '%s'\n", p);
 				kfree(p);
@@ -3453,8 +3862,13 @@ static int srp_parse_options(struct net
 				ret = -ENOMEM;
 				goto out;
 			}
+#ifdef HAVE_INET_PTON_WITH_SCOPE
 			ret = srp_parse_in(net, &target->rdma_cm.dst.ss, p,
 					   &has_port);
+#else
+			ret = srp_parse_in(&target->rdma_cm.dst.ip4, p,
+					   &has_port);
+#endif
 			if (!has_port)
 				ret = -EINVAL;
 			if (ret < 0) {
@@ -3553,12 +3967,21 @@ static int srp_parse_options(struct net
 			break;
 
 		case SRP_OPT_SG_TABLESIZE:
+#ifdef HAVE_SG_MAX_SEGMENTS
 			if (match_int(args, &token) || token < 1 ||
 					token > SG_MAX_SEGMENTS) {
 				pr_warn("bad max sg_tablesize parameter '%s'\n",
 					p);
 				goto out;
 			}
+#else
+			if (match_int(args, &token) || token < 1 ||
+					token > SCSI_MAX_SG_CHAIN_SEGMENTS) {
+				pr_warn("bad max sg_tablesize parameter '%s'\n",
+					p);
+				goto out;
+			}
+#endif
 			target->sg_tablesize = token;
 			break;
 
@@ -3634,7 +4057,14 @@ static ssize_t add_target_store(struct d
 	struct srp_device *srp_dev = host->srp_dev;
 	struct ib_device *ibdev = srp_dev->dev;
 	int ret, i, ch_idx;
+#ifdef HAVE_VIRT_BOUNDARY
 	unsigned int max_sectors_per_mr, mr_per_cmd = 0;
+#else
+	unsigned int mr_per_cmd = 0;
+#endif
+#ifndef HAVE_BLK_TAGS
+	int cpu;
+#endif
 	bool multich = false;
 	uint32_t max_iu_len;
 
@@ -3648,19 +4078,44 @@ static ssize_t add_target_store(struct d
 	target_host->max_id      = 1;
 	target_host->max_lun     = -1LL;
 	target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb;
+#ifdef HAVE_SCSI_HOST_MAX_SEGMENT_SIZE
 	target_host->max_segment_size = ib_dma_max_seg_size(ibdev);
+#endif
+#ifdef HAVE_SCSI_HOST_VIRT_BOUNDARY_MASK
 	target_host->virt_boundary_mask = ~srp_dev->mr_page_mask;
+#endif
 
 	target = host_to_target(target_host);
 
+#ifdef HAVE_KOBJ_NS_GRAB_CURRENT_EXPORTED
 	target->net		= kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
+#else
+	target->net             = &init_net;
+#endif
 	target->io_class	= SRP_REV16A_IB_IO_CLASS;
 	target->scsi_host	= target_host;
 	target->srp_host	= host;
 	target->lkey		= host->srp_dev->pd->local_dma_lkey;
 	target->global_rkey	= host->srp_dev->global_rkey;
 	target->cmd_sg_cnt	= cmd_sg_entries;
+#ifndef HAVE_VIRT_BOUNDARY
+	if (never_register) {
+		target->sg_tablesize = indirect_sg_entries ? : cmd_sg_entries;
+	} else {
+		if (target->cmd_sg_cnt > 12) {
+			target->cmd_sg_cnt = 12;
+			pr_warn("Clamping cmd_sg_entries and "
+				"indirect_sg_entries to 12. Because %s is "
+				"not supported MR with gaps. And values more "
+				"than 12 can cause allocation errors of the "
+				"MR pool.\n",
+				dev_name(&ibdev->dev));
+		}
+		target->sg_tablesize = target->cmd_sg_cnt;
+	}
+#else
 	target->sg_tablesize	= indirect_sg_entries ? : cmd_sg_entries;
+#endif
 	target->allow_ext_sg	= allow_ext_sg;
 	target->tl_retry_count	= 7;
 	target->queue_size	= SRP_DEFAULT_QUEUE_SIZE;
@@ -3679,6 +4134,14 @@ static ssize_t add_target_store(struct d
 	if (ret)
 		goto out;
 
+#ifdef HAVE_SCSI_HOST_TEMPLATE_USE_BLK_TAGS
+	ret = scsi_init_shared_tag_map(target_host, target_host->can_queue);
+	if (ret)
+		goto out;
+#endif
+#ifndef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
+	target->req_ring_size = target->queue_size - SRP_TSK_MGMT_SQ_SIZE;
+#endif
 	if (!srp_conn_unique(target->srp_host, target)) {
 		if (target->using_rdma_cm) {
 			shost_printk(KERN_INFO, target->scsi_host,
@@ -3704,6 +4167,7 @@ static ssize_t add_target_store(struct d
 	}
 
 	if (srp_dev->use_fast_reg) {
+#ifdef HAVE_VIRT_BOUNDARY
 		max_sectors_per_mr = srp_dev->max_pages_per_mr <<
 				  (ilog2(srp_dev->mr_page_size) - 9);
 
@@ -3727,6 +4191,13 @@ static ssize_t add_target_store(struct d
 		pr_debug("max_sectors = %u; max_pages_per_mr = %u; mr_page_size = %u; max_sectors_per_mr = %u; mr_per_cmd = %u\n",
 			 target->scsi_host->max_sectors, srp_dev->max_pages_per_mr, srp_dev->mr_page_size,
 			 max_sectors_per_mr, mr_per_cmd);
+#else
+		mr_per_cmd = target->cmd_sg_cnt + register_always;
+
+		pr_debug("max_sectors = %u; max_pages_per_mr = %u; mr_page_size = %u; mr_per_cmd = %u\n",
+			 target->scsi_host->max_sectors, srp_dev->max_pages_per_mr, srp_dev->mr_page_size,
+			 mr_per_cmd);
+#endif
 	}
 
 	target_host->sg_tablesize = target->sg_tablesize;
@@ -3759,6 +4230,12 @@ static ssize_t add_target_store(struct d
 	if (!target->ch)
 		goto out;
 
+#ifndef HAVE_BLK_TAGS
+	target->mq_map = kcalloc(nr_cpu_ids, sizeof(*target->mq_map),
+				 GFP_KERNEL);
+	if (!target->mq_map)
+		goto err_free_ch;
+#endif
 	for (ch_idx = 0; ch_idx < target->ch_count; ++ch_idx) {
 		ch = &target->ch[ch_idx];
 		ch->target = target;
@@ -3773,6 +4250,11 @@ static ssize_t add_target_store(struct d
 		if (ret)
 			goto err_disconnect;
 
+#ifndef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
+		ret = srp_alloc_req_data(ch);
+		if (ret)
+			goto err_disconnect;
+#endif
 		ret = srp_connect_ch(ch, max_iu_len, multich);
 		if (ret) {
 			char dst[64];
@@ -3791,15 +4273,25 @@ static ssize_t add_target_store(struct d
 				goto free_ch;
 			} else {
 				srp_free_ch_ib(target, ch);
+#ifndef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
+				srp_free_req_data(target, ch);
+#endif
 				target->ch_count = ch - target->ch;
 				goto connected;
 			}
 		}
 		multich = true;
 	}
+#ifndef HAVE_BLK_TAGS
+	for_each_online_cpu(cpu) {
+		target->mq_map[cpu] = cpu % target->ch_count;
+	}
+#endif
 
 connected:
+#ifdef HAVE_SCSI_HOST_NR_HW_QUEUES
 	target->scsi_host->nr_hw_queues = target->ch_count;
+#endif
 
 	ret = srp_add_target(host, target);
 	if (ret)
@@ -3832,6 +4324,7 @@ out:
 put:
 	scsi_host_put(target->scsi_host);
 	if (ret < 0) {
+#ifdef HAVE_KOBJ_NS_GRAB_CURRENT_EXPORTED
 		/*
 		 * If a call to srp_remove_target() has not been scheduled,
 		 * drop the network namespace reference now that was obtained
@@ -3839,6 +4332,7 @@ put:
 		 */
 		if (target->state != SRP_TARGET_REMOVED)
 			kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net);
+#endif
 		scsi_host_put(target->scsi_host);
 	}
 
@@ -3851,8 +4345,16 @@ free_ch:
 	for (i = 0; i < target->ch_count; i++) {
 		ch = &target->ch[i];
 		srp_free_ch_ib(target, ch);
+#ifndef HAVE_SCSI_HOST_TEMPLATE_INIT_CMD_PRIV
+		srp_free_req_data(target, ch);
+#endif
 	}
 
+#ifndef HAVE_BLK_TAGS
+	kfree(target->mq_map);
+
+err_free_ch:
+#endif
 	kfree(target->ch);
 	goto out;
 }
@@ -4097,11 +4599,19 @@ static int __init srp_init_module(void)
 		indirect_sg_entries = cmd_sg_entries;
 	}
 
+#ifdef HAVE_SG_MAX_SEGMENTS
 	if (indirect_sg_entries > SG_MAX_SEGMENTS) {
 		pr_warn("Clamping indirect_sg_entries to %u\n",
 			SG_MAX_SEGMENTS);
 		indirect_sg_entries = SG_MAX_SEGMENTS;
 	}
+#else
+	if (indirect_sg_entries > SCSI_MAX_SG_CHAIN_SEGMENTS) {
+		pr_warn("Clamping indirect_sg_entries to %u\n",
+			SCSI_MAX_SG_CHAIN_SEGMENTS);
+		indirect_sg_entries = SCSI_MAX_SG_CHAIN_SEGMENTS;
+	}
+#endif
 
 	srp_remove_wq = create_workqueue("srp_remove");
 	if (!srp_remove_wq) {
