--- /dev/null
+From: Vladimir Sokolovsky <vlad@mellanox.com>
+Subject: [PATCH] BACKPORT: srp
+
+Signed-off-by: Vladimir Sokolovsky <vlad@mellanox.com>
+---
+ drivers/infiniband/ulp/srp/ib_srp.c | 86 ++++++++++++++++++++++++++++++++++-
+ drivers/scsi/scsi_transport_srp.c | 25 ++++++++++
+ 2 files changed, 110 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
+index xxxxxxx..xxxxxxx xxxxxx
+--- a/drivers/infiniband/ulp/srp/ib_srp.c
++++ b/drivers/infiniband/ulp/srp/ib_srp.c
+@@ -30,6 +30,9 @@
+ * SOFTWARE.
+ */
+
++#ifdef pr_fmt
++#undef pr_fmt
++#endif
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+ #include <linux/module.h>
+@@ -41,7 +44,11 @@
+ #include <linux/random.h>
+ #include <linux/jiffies.h>
+
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+ #include <linux/atomic.h>
++#else
++#include <asm/atomic.h>
++#endif
+
+ #include <scsi/scsi.h>
+ #include <scsi/scsi_device.h>
+@@ -97,30 +104,58 @@ module_param(register_always, bool, 0444);
+ MODULE_PARM_DESC(register_always,
+ "Use memory registration even for contiguous memory regions");
+
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ static struct kernel_param_ops srp_tmo_ops;
++#endif
+
+ static int srp_reconnect_delay = 10;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ module_param_cb(reconnect_delay, &srp_tmo_ops, &srp_reconnect_delay,
+ S_IRUGO | S_IWUSR);
++#else
++module_param_named(reconnect_delay, srp_reconnect_delay, int,
++ S_IRUGO | S_IWUSR);
++#endif
++
+ MODULE_PARM_DESC(reconnect_delay, "Time between successive reconnect attempts");
+
+ static int srp_fast_io_fail_tmo = 15;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ module_param_cb(fast_io_fail_tmo, &srp_tmo_ops, &srp_fast_io_fail_tmo,
+ S_IRUGO | S_IWUSR);
++#else
++module_param_named(fast_io_fail_tmo, srp_fast_io_fail_tmo, int,
++ S_IRUGO | S_IWUSR);
++#endif
++
+ MODULE_PARM_DESC(fast_io_fail_tmo,
+ "Number of seconds between the observation of a transport"
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ " layer error and failing all I/O. \"off\" means that this"
++#else
++ " layer error and failing all I/O. (-1) means that this"
++#endif
+ " functionality is disabled.");
+
+ static int srp_dev_loss_tmo = 600;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ module_param_cb(dev_loss_tmo, &srp_tmo_ops, &srp_dev_loss_tmo,
+ S_IRUGO | S_IWUSR);
++#else
++module_param_named(dev_loss_tmo, srp_dev_loss_tmo, int,
++ S_IRUGO | S_IWUSR);
++#endif
++
+ MODULE_PARM_DESC(dev_loss_tmo,
+ "Maximum number of seconds that the SRP transport should"
+ " insulate transport layer errors. After this time has been"
+ " exceeded the SCSI host is removed. Should be"
+ " between 1 and " __stringify(SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ " if fast_io_fail_tmo has not been set. \"off\" means that"
++#else
++ " if fast_io_fail_tmo has not been set. (-1) means that"
++#endif
+ " this functionality is disabled.");
+
+ static void srp_add_one(struct ib_device *device);
+@@ -140,6 +175,7 @@ static struct ib_client srp_client = {
+
+ static struct ib_sa_client srp_sa_client;
+
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ static int srp_tmo_get(char *buffer, const struct kernel_param *kp)
+ {
+ int tmo = *(int *)kp->arg;
+@@ -181,6 +217,7 @@ static struct kernel_param_ops srp_tmo_ops = {
+ .get = srp_tmo_get,
+ .set = srp_tmo_set,
+ };
++#endif
+
+ static inline struct srp_target_port *host_to_target(struct Scsi_Host *host)
+ {
+@@ -1085,16 +1122,20 @@ static void srp_finish_req(struct srp_target_port *target,
+ static void srp_terminate_io(struct srp_rport *rport)
+ {
+ struct srp_target_port *target = rport->lld_data;
++#ifdef HAVE_REQUEST_QUEUE_REQUEST_FN_ACTIVE
+ struct Scsi_Host *shost = target->scsi_host;
+ struct scsi_device *sdev;
++#endif
+ int i;
+
+ /*
+ * Invoking srp_terminate_io() while srp_queuecommand() is running
+ * is not safe. Hence the warning statement below.
+ */
++#ifdef HAVE_REQUEST_QUEUE_REQUEST_FN_ACTIVE
+ shost_for_each_device(sdev, shost)
+ WARN_ON_ONCE(sdev->request_queue->request_fn_active);
++#endif
+
+ for (i = 0; i < target->req_ring_size; ++i) {
+ struct srp_request *req = &target->req_ring[i];
+@@ -1848,7 +1889,50 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
+ }
+ }
+
+-static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
++/*
++ * Kernel with host lock push-down patch. See also upstream commit
++ * f281233d3eba15fb225d21ae2e228fd4553d824a.
++ */
++#define SRP_QUEUECOMMAND srp_queuecommand
++#elif defined(RHEL_MAJOR) && RHEL_MAJOR -0 == 6 && RHEL_MINOR -0 >= 2
++/*
++ * Kernel with lockless SCSI command dispatching enabled.
++ * See also the RHEL 6.2 release notes (http://access.redhat.com/knowledge/docs/en-US/Red_Hat_Enterprise_Linux/6/html-single/6.2_Release_Notes/index.html).
++ */
++static int srp_queuecommand_wrk(struct Scsi_Host *shost,
++ struct scsi_cmnd *scmnd);
++static int srp_queuecommand(struct scsi_cmnd *scmnd,
++ void (*done)(struct scsi_cmnd *))
++{
++ scmnd->scsi_done = done;
++ return srp_queuecommand_wrk(scmnd->device->host, scmnd);
++}
++#define SRP_QUEUECOMMAND srp_queuecommand_wrk
++#else
++/*
++ * Kernel that invokes srp_queuecommand with the SCSI host lock held.
++ */
++static int srp_queuecommand_wrk(struct Scsi_Host *shost,
++ struct scsi_cmnd *scmnd);
++static int srp_queuecommand(struct scsi_cmnd *scmnd,
++ void (*done)(struct scsi_cmnd *))
++{
++ struct Scsi_Host *shost = scmnd->device->host;
++ int res;
++
++ spin_unlock_irq(shost->host_lock);
++
++ scmnd->scsi_done = done;
++ res = srp_queuecommand_wrk(shost, scmnd);
++
++ spin_lock_irq(shost->host_lock);
++ return res;
++}
++#define SRP_QUEUECOMMAND srp_queuecommand_wrk
++#endif
++
++static int SRP_QUEUECOMMAND(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
+ {
+ struct srp_target_port *target = host_to_target(shost);
+ struct srp_rport *rport = target->rport;
+diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
+index xxxxxxx..xxxxxxx xxxxxx
+--- a/drivers/scsi/scsi_transport_srp.c
++++ b/drivers/scsi/scsi_transport_srp.c
+@@ -405,7 +405,11 @@ static void __rport_fail_io_fast(struct srp_rport *rport)
+
+ if (srp_rport_set_state(rport, SRP_RPORT_FAIL_FAST))
+ return;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(CONFIG_COMPAT_SCSI_TARGET_UNBLOCK)
+ scsi_target_unblock(rport->dev.parent, SDEV_TRANSPORT_OFFLINE);
++#else
++ scsi_target_unblock(rport->dev.parent);
++#endif
+
+ /* Involve the LLD if possible to terminate all I/O on the rport. */
+ i = to_srp_internal(shost->transportt);
+@@ -448,7 +452,11 @@ static void rport_dev_loss_timedout(struct work_struct *work)
+
+ mutex_lock(&rport->mutex);
+ WARN_ON(srp_rport_set_state(rport, SRP_RPORT_LOST) != 0);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(CONFIG_COMPAT_SCSI_TARGET_UNBLOCK)
+ scsi_target_unblock(rport->dev.parent, SDEV_TRANSPORT_OFFLINE);
++#else
++ scsi_target_unblock(rport->dev.parent);
++#endif
+ mutex_unlock(&rport->mutex);
+
+ i->f->rport_delete(rport);
+@@ -509,6 +517,7 @@ EXPORT_SYMBOL(srp_start_tl_fail_timers);
+ */
+ static int scsi_request_fn_active(struct Scsi_Host *shost)
+ {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ struct scsi_device *sdev;
+ struct request_queue *q;
+ int request_fn_active = 0;
+@@ -522,6 +531,10 @@ static int scsi_request_fn_active(struct Scsi_Host *shost)
+ }
+
+ return request_fn_active;
++#else
++ msleep(20);
++ return 0;
++#endif
+ }
+
+ /**
+@@ -570,7 +583,11 @@ int srp_reconnect_rport(struct srp_rport *rport)
+
+ rport->failed_reconnects = 0;
+ srp_rport_set_state(rport, SRP_RPORT_RUNNING);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(CONFIG_COMPAT_SCSI_TARGET_UNBLOCK)
+ scsi_target_unblock(&shost->shost_gendev, SDEV_RUNNING);
++#else
++ scsi_target_unblock(&shost->shost_gendev);
++#endif
+ /*
+ * If the SCSI error handler has offlined one or more devices,
+ * invoking scsi_target_unblock() won't change the state of
+@@ -588,12 +605,20 @@ int srp_reconnect_rport(struct srp_rport *rport)
+ * failure timers if these had not yet been started.
+ */
+ __rport_fail_io_fast(rport);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(CONFIG_COMPAT_SCSI_TARGET_UNBLOCK)
+ scsi_target_unblock(&shost->shost_gendev,
+ SDEV_TRANSPORT_OFFLINE);
++#else
++ scsi_target_unblock(&shost->shost_gendev);
++#endif
+ __srp_start_tl_fail_timers(rport);
+ } else if (rport->state != SRP_RPORT_BLOCKED) {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(CONFIG_COMPAT_SCSI_TARGET_UNBLOCK)
+ scsi_target_unblock(&shost->shost_gendev,
+ SDEV_TRANSPORT_OFFLINE);
++#else
++ scsi_target_unblock(&shost->shost_gendev);
++#endif
+ }
+ mutex_unlock(&rport->mutex);
+