|
@@ -41,6 +41,7 @@
|
|
|
#include <linux/random.h>
|
|
|
#include <linux/jiffies.h>
|
|
|
#include <linux/lockdep.h>
|
|
|
+#include <linux/inet.h>
|
|
|
#include <rdma/ib_cache.h>
|
|
|
|
|
|
#include <linux/atomic.h>
|
|
@@ -144,7 +145,9 @@ static void srp_remove_one(struct ib_device *device, void *client_data);
|
|
|
static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc);
|
|
|
static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc,
|
|
|
const char *opname);
|
|
|
-static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
|
|
|
+static int srp_ib_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
|
|
|
+static int srp_rdma_cm_handler(struct rdma_cm_id *cm_id,
|
|
|
+ struct rdma_cm_event *event);
|
|
|
|
|
|
static struct scsi_transport_template *ib_srp_transport_template;
|
|
|
static struct workqueue_struct *srp_remove_wq;
|
|
@@ -265,8 +268,8 @@ static void srp_qp_event(struct ib_event *event, void *context)
|
|
|
ib_event_msg(event->event), event->event);
|
|
|
}
|
|
|
|
|
|
-static int srp_init_qp(struct srp_target_port *target,
|
|
|
- struct ib_qp *qp)
|
|
|
+static int srp_init_ib_qp(struct srp_target_port *target,
|
|
|
+ struct ib_qp *qp)
|
|
|
{
|
|
|
struct ib_qp_attr *attr;
|
|
|
int ret;
|
|
@@ -277,7 +280,7 @@ static int srp_init_qp(struct srp_target_port *target,
|
|
|
|
|
|
ret = ib_find_cached_pkey(target->srp_host->srp_dev->dev,
|
|
|
target->srp_host->port,
|
|
|
- be16_to_cpu(target->pkey),
|
|
|
+ be16_to_cpu(target->ib_cm.pkey),
|
|
|
&attr->pkey_index);
|
|
|
if (ret)
|
|
|
goto out;
|
|
@@ -298,32 +301,110 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int srp_new_cm_id(struct srp_rdma_ch *ch)
|
|
|
+static int srp_new_ib_cm_id(struct srp_rdma_ch *ch)
|
|
|
{
|
|
|
struct srp_target_port *target = ch->target;
|
|
|
struct ib_cm_id *new_cm_id;
|
|
|
|
|
|
new_cm_id = ib_create_cm_id(target->srp_host->srp_dev->dev,
|
|
|
- srp_cm_handler, ch);
|
|
|
+ srp_ib_cm_handler, ch);
|
|
|
if (IS_ERR(new_cm_id))
|
|
|
return PTR_ERR(new_cm_id);
|
|
|
|
|
|
- if (ch->cm_id)
|
|
|
- ib_destroy_cm_id(ch->cm_id);
|
|
|
- ch->cm_id = new_cm_id;
|
|
|
+ if (ch->ib_cm.cm_id)
|
|
|
+ ib_destroy_cm_id(ch->ib_cm.cm_id);
|
|
|
+ ch->ib_cm.cm_id = new_cm_id;
|
|
|
if (rdma_cap_opa_ah(target->srp_host->srp_dev->dev,
|
|
|
target->srp_host->port))
|
|
|
- ch->path.rec_type = SA_PATH_REC_TYPE_OPA;
|
|
|
+ ch->ib_cm.path.rec_type = SA_PATH_REC_TYPE_OPA;
|
|
|
else
|
|
|
- ch->path.rec_type = SA_PATH_REC_TYPE_IB;
|
|
|
- ch->path.sgid = target->sgid;
|
|
|
- ch->path.dgid = target->orig_dgid;
|
|
|
- ch->path.pkey = target->pkey;
|
|
|
- ch->path.service_id = target->service_id;
|
|
|
+ ch->ib_cm.path.rec_type = SA_PATH_REC_TYPE_IB;
|
|
|
+ ch->ib_cm.path.sgid = target->sgid;
|
|
|
+ ch->ib_cm.path.dgid = target->ib_cm.orig_dgid;
|
|
|
+ ch->ib_cm.path.pkey = target->ib_cm.pkey;
|
|
|
+ ch->ib_cm.path.service_id = target->ib_cm.service_id;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static const char *inet_ntop(const void *sa, char *dst, unsigned int size)
|
|
|
+{
|
|
|
+ switch (((struct sockaddr *)sa)->sa_family) {
|
|
|
+ case AF_INET:
|
|
|
+ snprintf(dst, size, "%pI4",
|
|
|
+ &((struct sockaddr_in *)sa)->sin_addr);
|
|
|
+ break;
|
|
|
+ case AF_INET6:
|
|
|
+ snprintf(dst, size, "%pI6",
|
|
|
+ &((struct sockaddr_in6 *)sa)->sin6_addr);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ snprintf(dst, size, "???");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return dst;
|
|
|
+}
|
|
|
+
|
|
|
+static int srp_new_rdma_cm_id(struct srp_rdma_ch *ch)
|
|
|
+{
|
|
|
+ struct srp_target_port *target = ch->target;
|
|
|
+ struct rdma_cm_id *new_cm_id;
|
|
|
+ char src_addr[64], dst_addr[64];
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ new_cm_id = rdma_create_id(target->net, srp_rdma_cm_handler, ch,
|
|
|
+ RDMA_PS_TCP, IB_QPT_RC);
|
|
|
+ if (IS_ERR(new_cm_id)) {
|
|
|
+ ret = PTR_ERR(new_cm_id);
|
|
|
+ new_cm_id = NULL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ init_completion(&ch->done);
|
|
|
+ ret = rdma_resolve_addr(new_cm_id, target->rdma_cm.src_specified ?
|
|
|
+ (struct sockaddr *)&target->rdma_cm.src : NULL,
|
|
|
+ (struct sockaddr *)&target->rdma_cm.dst,
|
|
|
+ SRP_PATH_REC_TIMEOUT_MS);
|
|
|
+ if (ret) {
|
|
|
+ pr_err("No route available from %s to %s (%d)\n",
|
|
|
+ target->rdma_cm.src_specified ?
|
|
|
+ inet_ntop(&target->rdma_cm.src, src_addr,
|
|
|
+ sizeof(src_addr)) : "(any)",
|
|
|
+ inet_ntop(&target->rdma_cm.dst, dst_addr,
|
|
|
+ sizeof(dst_addr)),
|
|
|
+ ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ ret = wait_for_completion_interruptible(&ch->done);
|
|
|
+ if (ret < 0)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ ret = ch->status;
|
|
|
+ if (ret) {
|
|
|
+ pr_err("Resolving address %s failed (%d)\n",
|
|
|
+ inet_ntop(&target->rdma_cm.dst, dst_addr,
|
|
|
+ sizeof(dst_addr)),
|
|
|
+ ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ swap(ch->rdma_cm.cm_id, new_cm_id);
|
|
|
+
|
|
|
+out:
|
|
|
+ if (new_cm_id)
|
|
|
+ rdma_destroy_id(new_cm_id);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int srp_new_cm_id(struct srp_rdma_ch *ch)
|
|
|
+{
|
|
|
+ struct srp_target_port *target = ch->target;
|
|
|
+
|
|
|
+ return target->using_rdma_cm ? srp_new_rdma_cm_id(ch) :
|
|
|
+ srp_new_ib_cm_id(ch);
|
|
|
+}
|
|
|
+
|
|
|
static struct ib_fmr_pool *srp_alloc_fmr_pool(struct srp_target_port *target)
|
|
|
{
|
|
|
struct srp_device *dev = target->srp_host->srp_dev;
|
|
@@ -521,16 +602,25 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch)
|
|
|
init_attr->send_cq = send_cq;
|
|
|
init_attr->recv_cq = recv_cq;
|
|
|
|
|
|
- qp = ib_create_qp(dev->pd, init_attr);
|
|
|
- if (IS_ERR(qp)) {
|
|
|
- ret = PTR_ERR(qp);
|
|
|
+ if (target->using_rdma_cm) {
|
|
|
+ ret = rdma_create_qp(ch->rdma_cm.cm_id, dev->pd, init_attr);
|
|
|
+ qp = ch->rdma_cm.cm_id->qp;
|
|
|
+ } else {
|
|
|
+ qp = ib_create_qp(dev->pd, init_attr);
|
|
|
+ if (!IS_ERR(qp)) {
|
|
|
+ ret = srp_init_ib_qp(target, qp);
|
|
|
+ if (ret)
|
|
|
+ ib_destroy_qp(qp);
|
|
|
+ } else {
|
|
|
+ ret = PTR_ERR(qp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (ret) {
|
|
|
+ pr_err("QP creation failed for dev %s: %d\n",
|
|
|
+ dev_name(&dev->dev->dev), ret);
|
|
|
goto err_send_cq;
|
|
|
}
|
|
|
|
|
|
- ret = srp_init_qp(target, qp);
|
|
|
- if (ret)
|
|
|
- goto err_qp;
|
|
|
-
|
|
|
if (dev->use_fast_reg) {
|
|
|
fr_pool = srp_alloc_fr_pool(target);
|
|
|
if (IS_ERR(fr_pool)) {
|
|
@@ -574,7 +664,10 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch)
|
|
|
return 0;
|
|
|
|
|
|
err_qp:
|
|
|
- ib_destroy_qp(qp);
|
|
|
+ if (target->using_rdma_cm)
|
|
|
+ rdma_destroy_qp(ch->rdma_cm.cm_id);
|
|
|
+ else
|
|
|
+ ib_destroy_qp(qp);
|
|
|
|
|
|
err_send_cq:
|
|
|
ib_free_cq(send_cq);
|
|
@@ -600,9 +693,16 @@ static void srp_free_ch_ib(struct srp_target_port *target,
|
|
|
if (!ch->target)
|
|
|
return;
|
|
|
|
|
|
- if (ch->cm_id) {
|
|
|
- ib_destroy_cm_id(ch->cm_id);
|
|
|
- ch->cm_id = NULL;
|
|
|
+ if (target->using_rdma_cm) {
|
|
|
+ if (ch->rdma_cm.cm_id) {
|
|
|
+ rdma_destroy_id(ch->rdma_cm.cm_id);
|
|
|
+ ch->rdma_cm.cm_id = NULL;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (ch->ib_cm.cm_id) {
|
|
|
+ ib_destroy_cm_id(ch->ib_cm.cm_id);
|
|
|
+ ch->ib_cm.cm_id = NULL;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* If srp_new_cm_id() succeeded but srp_create_ch_ib() not, return. */
|
|
@@ -658,16 +758,16 @@ static void srp_path_rec_completion(int status,
|
|
|
shost_printk(KERN_ERR, target->scsi_host,
|
|
|
PFX "Got failed path rec status %d\n", status);
|
|
|
else
|
|
|
- ch->path = *pathrec;
|
|
|
+ ch->ib_cm.path = *pathrec;
|
|
|
complete(&ch->done);
|
|
|
}
|
|
|
|
|
|
-static int srp_lookup_path(struct srp_rdma_ch *ch)
|
|
|
+static int srp_ib_lookup_path(struct srp_rdma_ch *ch)
|
|
|
{
|
|
|
struct srp_target_port *target = ch->target;
|
|
|
int ret = -ENODEV;
|
|
|
|
|
|
- ch->path.numb_path = 1;
|
|
|
+ ch->ib_cm.path.numb_path = 1;
|
|
|
|
|
|
init_completion(&ch->done);
|
|
|
|
|
@@ -678,10 +778,10 @@ static int srp_lookup_path(struct srp_rdma_ch *ch)
|
|
|
if (!scsi_host_get(target->scsi_host))
|
|
|
goto out;
|
|
|
|
|
|
- ch->path_query_id = ib_sa_path_rec_get(&srp_sa_client,
|
|
|
+ ch->ib_cm.path_query_id = ib_sa_path_rec_get(&srp_sa_client,
|
|
|
target->srp_host->srp_dev->dev,
|
|
|
target->srp_host->port,
|
|
|
- &ch->path,
|
|
|
+ &ch->ib_cm.path,
|
|
|
IB_SA_PATH_REC_SERVICE_ID |
|
|
|
IB_SA_PATH_REC_DGID |
|
|
|
IB_SA_PATH_REC_SGID |
|
|
@@ -690,8 +790,8 @@ static int srp_lookup_path(struct srp_rdma_ch *ch)
|
|
|
SRP_PATH_REC_TIMEOUT_MS,
|
|
|
GFP_KERNEL,
|
|
|
srp_path_rec_completion,
|
|
|
- ch, &ch->path_query);
|
|
|
- ret = ch->path_query_id;
|
|
|
+ ch, &ch->ib_cm.path_query);
|
|
|
+ ret = ch->ib_cm.path_query_id;
|
|
|
if (ret < 0)
|
|
|
goto put;
|
|
|
|
|
@@ -703,9 +803,9 @@ static int srp_lookup_path(struct srp_rdma_ch *ch)
|
|
|
if (ret < 0)
|
|
|
shost_printk(KERN_WARNING, target->scsi_host,
|
|
|
PFX "Path record query failed: sgid %pI6, dgid %pI6, pkey %#04x, service_id %#16llx\n",
|
|
|
- ch->path.sgid.raw, ch->path.dgid.raw,
|
|
|
- be16_to_cpu(target->pkey),
|
|
|
- be64_to_cpu(target->service_id));
|
|
|
+ ch->ib_cm.path.sgid.raw, ch->ib_cm.path.dgid.raw,
|
|
|
+ be16_to_cpu(target->ib_cm.pkey),
|
|
|
+ be64_to_cpu(target->ib_cm.service_id));
|
|
|
|
|
|
put:
|
|
|
scsi_host_put(target->scsi_host);
|
|
@@ -714,6 +814,34 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int srp_rdma_lookup_path(struct srp_rdma_ch *ch)
|
|
|
+{
|
|
|
+ struct srp_target_port *target = ch->target;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ init_completion(&ch->done);
|
|
|
+
|
|
|
+ ret = rdma_resolve_route(ch->rdma_cm.cm_id, SRP_PATH_REC_TIMEOUT_MS);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ wait_for_completion_interruptible(&ch->done);
|
|
|
+
|
|
|
+ if (ch->status != 0)
|
|
|
+ shost_printk(KERN_WARNING, target->scsi_host,
|
|
|
+ PFX "Path resolution failed\n");
|
|
|
+
|
|
|
+ return ch->status;
|
|
|
+}
|
|
|
+
|
|
|
+static int srp_lookup_path(struct srp_rdma_ch *ch)
|
|
|
+{
|
|
|
+ struct srp_target_port *target = ch->target;
|
|
|
+
|
|
|
+ return target->using_rdma_cm ? srp_rdma_lookup_path(ch) :
|
|
|
+ srp_ib_lookup_path(ch);
|
|
|
+}
|
|
|
+
|
|
|
static u8 srp_get_subnet_timeout(struct srp_host *host)
|
|
|
{
|
|
|
struct ib_port_attr attr;
|
|
@@ -735,8 +863,10 @@ static int srp_send_req(struct srp_rdma_ch *ch, bool multich)
|
|
|
{
|
|
|
struct srp_target_port *target = ch->target;
|
|
|
struct {
|
|
|
- struct ib_cm_req_param param;
|
|
|
- struct srp_login_req priv;
|
|
|
+ struct rdma_conn_param rdma_param;
|
|
|
+ struct srp_login_req_rdma rdma_req;
|
|
|
+ struct ib_cm_req_param ib_param;
|
|
|
+ struct srp_login_req ib_req;
|
|
|
} *req = NULL;
|
|
|
char *ipi, *tpi;
|
|
|
int status;
|
|
@@ -745,44 +875,62 @@ static int srp_send_req(struct srp_rdma_ch *ch, bool multich)
|
|
|
if (!req)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- req->param.flow_control = 1;
|
|
|
- req->param.retry_count = target->tl_retry_count;
|
|
|
+ req->ib_param.flow_control = 1;
|
|
|
+ req->ib_param.retry_count = target->tl_retry_count;
|
|
|
|
|
|
/*
|
|
|
* Pick some arbitrary defaults here; we could make these
|
|
|
* module parameters if anyone cared about setting them.
|
|
|
*/
|
|
|
- req->param.responder_resources = 4;
|
|
|
- req->param.rnr_retry_count = 7;
|
|
|
- req->param.max_cm_retries = 15;
|
|
|
-
|
|
|
- req->priv.opcode = SRP_LOGIN_REQ;
|
|
|
- req->priv.tag = 0;
|
|
|
- req->priv.req_it_iu_len = cpu_to_be32(target->max_iu_len);
|
|
|
- req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
|
|
|
+ req->ib_param.responder_resources = 4;
|
|
|
+ req->ib_param.rnr_retry_count = 7;
|
|
|
+ req->ib_param.max_cm_retries = 15;
|
|
|
+
|
|
|
+ req->ib_req.opcode = SRP_LOGIN_REQ;
|
|
|
+ req->ib_req.tag = 0;
|
|
|
+ req->ib_req.req_it_iu_len = cpu_to_be32(target->max_iu_len);
|
|
|
+ req->ib_req.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
|
|
|
SRP_BUF_FORMAT_INDIRECT);
|
|
|
- req->priv.req_flags = (multich ? SRP_MULTICHAN_MULTI :
|
|
|
- SRP_MULTICHAN_SINGLE);
|
|
|
-
|
|
|
- {
|
|
|
+ req->ib_req.req_flags = (multich ? SRP_MULTICHAN_MULTI :
|
|
|
+ SRP_MULTICHAN_SINGLE);
|
|
|
+
|
|
|
+ if (target->using_rdma_cm) {
|
|
|
+ req->rdma_param.flow_control = req->ib_param.flow_control;
|
|
|
+ req->rdma_param.responder_resources =
|
|
|
+ req->ib_param.responder_resources;
|
|
|
+ req->rdma_param.initiator_depth = req->ib_param.initiator_depth;
|
|
|
+ req->rdma_param.retry_count = req->ib_param.retry_count;
|
|
|
+ req->rdma_param.rnr_retry_count = req->ib_param.rnr_retry_count;
|
|
|
+ req->rdma_param.private_data = &req->rdma_req;
|
|
|
+ req->rdma_param.private_data_len = sizeof(req->rdma_req);
|
|
|
+
|
|
|
+ req->rdma_req.opcode = req->ib_req.opcode;
|
|
|
+ req->rdma_req.tag = req->ib_req.tag;
|
|
|
+ req->rdma_req.req_it_iu_len = req->ib_req.req_it_iu_len;
|
|
|
+ req->rdma_req.req_buf_fmt = req->ib_req.req_buf_fmt;
|
|
|
+ req->rdma_req.req_flags = req->ib_req.req_flags;
|
|
|
+
|
|
|
+ ipi = req->rdma_req.initiator_port_id;
|
|
|
+ tpi = req->rdma_req.target_port_id;
|
|
|
+ } else {
|
|
|
u8 subnet_timeout;
|
|
|
|
|
|
subnet_timeout = srp_get_subnet_timeout(target->srp_host);
|
|
|
|
|
|
- req->param.primary_path = &ch->path;
|
|
|
- req->param.alternate_path = NULL;
|
|
|
- req->param.service_id = target->service_id;
|
|
|
- get_random_bytes(&req->param.starting_psn, 4);
|
|
|
- req->param.starting_psn &= 0xffffff;
|
|
|
- req->param.qp_num = ch->qp->qp_num;
|
|
|
- req->param.qp_type = ch->qp->qp_type;
|
|
|
- req->param.local_cm_response_timeout = subnet_timeout + 2;
|
|
|
- req->param.remote_cm_response_timeout = subnet_timeout + 2;
|
|
|
- req->param.private_data = &req->priv;
|
|
|
- req->param.private_data_len = sizeof(req->priv);
|
|
|
-
|
|
|
- ipi = req->priv.initiator_port_id;
|
|
|
- tpi = req->priv.target_port_id;
|
|
|
+ req->ib_param.primary_path = &ch->ib_cm.path;
|
|
|
+ req->ib_param.alternate_path = NULL;
|
|
|
+ req->ib_param.service_id = target->ib_cm.service_id;
|
|
|
+ get_random_bytes(&req->ib_param.starting_psn, 4);
|
|
|
+ req->ib_param.starting_psn &= 0xffffff;
|
|
|
+ req->ib_param.qp_num = ch->qp->qp_num;
|
|
|
+ req->ib_param.qp_type = ch->qp->qp_type;
|
|
|
+ req->ib_param.local_cm_response_timeout = subnet_timeout + 2;
|
|
|
+ req->ib_param.remote_cm_response_timeout = subnet_timeout + 2;
|
|
|
+ req->ib_param.private_data = &req->ib_req;
|
|
|
+ req->ib_param.private_data_len = sizeof(req->ib_req);
|
|
|
+
|
|
|
+ ipi = req->ib_req.initiator_port_id;
|
|
|
+ tpi = req->ib_req.target_port_id;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -820,7 +968,10 @@ static int srp_send_req(struct srp_rdma_ch *ch, bool multich)
|
|
|
memcpy(ipi + 8, &target->srp_host->srp_dev->dev->node_guid, 8);
|
|
|
}
|
|
|
|
|
|
- status = ib_send_cm_req(ch->cm_id, &req->param);
|
|
|
+ if (target->using_rdma_cm)
|
|
|
+ status = rdma_connect(ch->rdma_cm.cm_id, &req->rdma_param);
|
|
|
+ else
|
|
|
+ status = ib_send_cm_req(ch->ib_cm.cm_id, &req->ib_param);
|
|
|
|
|
|
kfree(req);
|
|
|
|
|
@@ -847,14 +998,23 @@ static bool srp_queue_remove_work(struct srp_target_port *target)
|
|
|
static void srp_disconnect_target(struct srp_target_port *target)
|
|
|
{
|
|
|
struct srp_rdma_ch *ch;
|
|
|
- int i;
|
|
|
+ int i, ret;
|
|
|
|
|
|
/* XXX should send SRP_I_LOGOUT request */
|
|
|
|
|
|
for (i = 0; i < target->ch_count; i++) {
|
|
|
ch = &target->ch[i];
|
|
|
ch->connected = false;
|
|
|
- if (ch->cm_id && ib_send_cm_dreq(ch->cm_id, NULL, 0)) {
|
|
|
+ ret = 0;
|
|
|
+ if (target->using_rdma_cm) {
|
|
|
+ if (ch->rdma_cm.cm_id)
|
|
|
+ rdma_disconnect(ch->rdma_cm.cm_id);
|
|
|
+ } else {
|
|
|
+ if (ch->ib_cm.cm_id)
|
|
|
+ ret = ib_send_cm_dreq(ch->ib_cm.cm_id,
|
|
|
+ NULL, 0);
|
|
|
+ }
|
|
|
+ if (ret < 0) {
|
|
|
shost_printk(KERN_DEBUG, target->scsi_host,
|
|
|
PFX "Sending CM DREQ failed\n");
|
|
|
}
|
|
@@ -968,6 +1128,7 @@ static void srp_remove_target(struct srp_target_port *target)
|
|
|
scsi_remove_host(target->scsi_host);
|
|
|
srp_stop_rport_timers(target->rport);
|
|
|
srp_disconnect_target(target);
|
|
|
+ kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net);
|
|
|
for (i = 0; i < target->ch_count; i++) {
|
|
|
ch = &target->ch[i];
|
|
|
srp_free_ch_ib(target, ch);
|
|
@@ -2355,7 +2516,7 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
|
|
|
struct srp_target_port *target = ch->target;
|
|
|
struct ib_qp_attr *qp_attr = NULL;
|
|
|
int attr_mask = 0;
|
|
|
- int ret;
|
|
|
+ int ret = 0;
|
|
|
int i;
|
|
|
|
|
|
if (lrsp->opcode == SRP_LOGIN_RSP) {
|
|
@@ -2385,40 +2546,42 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- ret = -ENOMEM;
|
|
|
- qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL);
|
|
|
- if (!qp_attr)
|
|
|
- goto error;
|
|
|
-
|
|
|
- qp_attr->qp_state = IB_QPS_RTR;
|
|
|
- ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
|
|
|
- if (ret)
|
|
|
- goto error_free;
|
|
|
-
|
|
|
- ret = ib_modify_qp(ch->qp, qp_attr, attr_mask);
|
|
|
- if (ret)
|
|
|
- goto error_free;
|
|
|
-
|
|
|
for (i = 0; i < target->queue_size; i++) {
|
|
|
struct srp_iu *iu = ch->rx_ring[i];
|
|
|
|
|
|
ret = srp_post_recv(ch, iu);
|
|
|
if (ret)
|
|
|
- goto error_free;
|
|
|
+ goto error;
|
|
|
}
|
|
|
|
|
|
- qp_attr->qp_state = IB_QPS_RTS;
|
|
|
- ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
|
|
|
- if (ret)
|
|
|
- goto error_free;
|
|
|
+ if (!target->using_rdma_cm) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ qp_attr = kmalloc(sizeof(*qp_attr), GFP_KERNEL);
|
|
|
+ if (!qp_attr)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ qp_attr->qp_state = IB_QPS_RTR;
|
|
|
+ ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
|
|
|
+ if (ret)
|
|
|
+ goto error_free;
|
|
|
|
|
|
- target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask);
|
|
|
+ ret = ib_modify_qp(ch->qp, qp_attr, attr_mask);
|
|
|
+ if (ret)
|
|
|
+ goto error_free;
|
|
|
|
|
|
- ret = ib_modify_qp(ch->qp, qp_attr, attr_mask);
|
|
|
- if (ret)
|
|
|
- goto error_free;
|
|
|
+ qp_attr->qp_state = IB_QPS_RTS;
|
|
|
+ ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
|
|
|
+ if (ret)
|
|
|
+ goto error_free;
|
|
|
+
|
|
|
+ target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask);
|
|
|
+
|
|
|
+ ret = ib_modify_qp(ch->qp, qp_attr, attr_mask);
|
|
|
+ if (ret)
|
|
|
+ goto error_free;
|
|
|
|
|
|
- ret = ib_send_cm_rtu(cm_id, NULL, 0);
|
|
|
+ ret = ib_send_cm_rtu(cm_id, NULL, 0);
|
|
|
+ }
|
|
|
|
|
|
error_free:
|
|
|
kfree(qp_attr);
|
|
@@ -2427,41 +2590,43 @@ error:
|
|
|
ch->status = ret;
|
|
|
}
|
|
|
|
|
|
-static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
|
|
|
- struct ib_cm_event *event,
|
|
|
- struct srp_rdma_ch *ch)
|
|
|
+static void srp_ib_cm_rej_handler(struct ib_cm_id *cm_id,
|
|
|
+ struct ib_cm_event *event,
|
|
|
+ struct srp_rdma_ch *ch)
|
|
|
{
|
|
|
struct srp_target_port *target = ch->target;
|
|
|
struct Scsi_Host *shost = target->scsi_host;
|
|
|
struct ib_class_port_info *cpi;
|
|
|
int opcode;
|
|
|
+ u16 dlid;
|
|
|
|
|
|
switch (event->param.rej_rcvd.reason) {
|
|
|
case IB_CM_REJ_PORT_CM_REDIRECT:
|
|
|
cpi = event->param.rej_rcvd.ari;
|
|
|
- sa_path_set_dlid(&ch->path, ntohs(cpi->redirect_lid));
|
|
|
- ch->path.pkey = cpi->redirect_pkey;
|
|
|
+ dlid = be16_to_cpu(cpi->redirect_lid);
|
|
|
+ sa_path_set_dlid(&ch->ib_cm.path, dlid);
|
|
|
+ ch->ib_cm.path.pkey = cpi->redirect_pkey;
|
|
|
cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff;
|
|
|
- memcpy(ch->path.dgid.raw, cpi->redirect_gid, 16);
|
|
|
+ memcpy(ch->ib_cm.path.dgid.raw, cpi->redirect_gid, 16);
|
|
|
|
|
|
- ch->status = sa_path_get_dlid(&ch->path) ?
|
|
|
- SRP_DLID_REDIRECT : SRP_PORT_REDIRECT;
|
|
|
+ ch->status = dlid ? SRP_DLID_REDIRECT : SRP_PORT_REDIRECT;
|
|
|
break;
|
|
|
|
|
|
case IB_CM_REJ_PORT_REDIRECT:
|
|
|
if (srp_target_is_topspin(target)) {
|
|
|
+ union ib_gid *dgid = &ch->ib_cm.path.dgid;
|
|
|
+
|
|
|
/*
|
|
|
* Topspin/Cisco SRP gateways incorrectly send
|
|
|
* reject reason code 25 when they mean 24
|
|
|
* (port redirect).
|
|
|
*/
|
|
|
- memcpy(ch->path.dgid.raw,
|
|
|
- event->param.rej_rcvd.ari, 16);
|
|
|
+ memcpy(dgid->raw, event->param.rej_rcvd.ari, 16);
|
|
|
|
|
|
shost_printk(KERN_DEBUG, shost,
|
|
|
PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",
|
|
|
- be64_to_cpu(ch->path.dgid.global.subnet_prefix),
|
|
|
- be64_to_cpu(ch->path.dgid.global.interface_id));
|
|
|
+ be64_to_cpu(dgid->global.subnet_prefix),
|
|
|
+ be64_to_cpu(dgid->global.interface_id));
|
|
|
|
|
|
ch->status = SRP_PORT_REDIRECT;
|
|
|
} else {
|
|
@@ -2490,7 +2655,8 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
|
|
|
shost_printk(KERN_WARNING, shost, PFX
|
|
|
"SRP LOGIN from %pI6 to %pI6 REJECTED, reason 0x%08x\n",
|
|
|
target->sgid.raw,
|
|
|
- target->orig_dgid.raw, reason);
|
|
|
+ target->ib_cm.orig_dgid.raw,
|
|
|
+ reason);
|
|
|
} else
|
|
|
shost_printk(KERN_WARNING, shost,
|
|
|
" REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
|
|
@@ -2510,7 +2676,7 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
|
|
|
+static int srp_ib_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
|
|
|
{
|
|
|
struct srp_rdma_ch *ch = cm_id->context;
|
|
|
struct srp_target_port *target = ch->target;
|
|
@@ -2533,7 +2699,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
|
|
|
shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n");
|
|
|
comp = 1;
|
|
|
|
|
|
- srp_cm_rej_handler(cm_id, event, ch);
|
|
|
+ srp_ib_cm_rej_handler(cm_id, event, ch);
|
|
|
break;
|
|
|
|
|
|
case IB_CM_DREQ_RECEIVED:
|
|
@@ -2571,6 +2737,135 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void srp_rdma_cm_rej_handler(struct srp_rdma_ch *ch,
|
|
|
+ struct rdma_cm_event *event)
|
|
|
+{
|
|
|
+ struct srp_target_port *target = ch->target;
|
|
|
+ struct Scsi_Host *shost = target->scsi_host;
|
|
|
+ int opcode;
|
|
|
+
|
|
|
+ switch (event->status) {
|
|
|
+ case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID:
|
|
|
+ shost_printk(KERN_WARNING, shost,
|
|
|
+ " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
|
|
|
+ ch->status = -ECONNRESET;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case IB_CM_REJ_CONSUMER_DEFINED:
|
|
|
+ opcode = *(u8 *) event->param.conn.private_data;
|
|
|
+ if (opcode == SRP_LOGIN_REJ) {
|
|
|
+ struct srp_login_rej *rej =
|
|
|
+ (struct srp_login_rej *)
|
|
|
+ event->param.conn.private_data;
|
|
|
+ u32 reason = be32_to_cpu(rej->reason);
|
|
|
+
|
|
|
+ if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE)
|
|
|
+ shost_printk(KERN_WARNING, shost,
|
|
|
+ PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
|
|
|
+ else
|
|
|
+ shost_printk(KERN_WARNING, shost,
|
|
|
+ PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
|
|
|
+ } else {
|
|
|
+ shost_printk(KERN_WARNING, shost,
|
|
|
+ " REJ reason: IB_CM_REJ_CONSUMER_DEFINED, opcode 0x%02x\n",
|
|
|
+ opcode);
|
|
|
+ }
|
|
|
+ ch->status = -ECONNRESET;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case IB_CM_REJ_STALE_CONN:
|
|
|
+ shost_printk(KERN_WARNING, shost,
|
|
|
+ " REJ reason: stale connection\n");
|
|
|
+ ch->status = SRP_STALE_CONN;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n",
|
|
|
+ event->status);
|
|
|
+ ch->status = -ECONNRESET;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int srp_rdma_cm_handler(struct rdma_cm_id *cm_id,
|
|
|
+ struct rdma_cm_event *event)
|
|
|
+{
|
|
|
+ struct srp_rdma_ch *ch = cm_id->context;
|
|
|
+ struct srp_target_port *target = ch->target;
|
|
|
+ int comp = 0;
|
|
|
+
|
|
|
+ switch (event->event) {
|
|
|
+ case RDMA_CM_EVENT_ADDR_RESOLVED:
|
|
|
+ ch->status = 0;
|
|
|
+ comp = 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RDMA_CM_EVENT_ADDR_ERROR:
|
|
|
+ ch->status = -ENXIO;
|
|
|
+ comp = 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RDMA_CM_EVENT_ROUTE_RESOLVED:
|
|
|
+ ch->status = 0;
|
|
|
+ comp = 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RDMA_CM_EVENT_ROUTE_ERROR:
|
|
|
+ case RDMA_CM_EVENT_UNREACHABLE:
|
|
|
+ ch->status = -EHOSTUNREACH;
|
|
|
+ comp = 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RDMA_CM_EVENT_CONNECT_ERROR:
|
|
|
+ shost_printk(KERN_DEBUG, target->scsi_host,
|
|
|
+ PFX "Sending CM REQ failed\n");
|
|
|
+ comp = 1;
|
|
|
+ ch->status = -ECONNRESET;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RDMA_CM_EVENT_ESTABLISHED:
|
|
|
+ comp = 1;
|
|
|
+ srp_cm_rep_handler(NULL, event->param.conn.private_data, ch);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RDMA_CM_EVENT_REJECTED:
|
|
|
+ shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n");
|
|
|
+ comp = 1;
|
|
|
+
|
|
|
+ srp_rdma_cm_rej_handler(ch, event);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RDMA_CM_EVENT_DISCONNECTED:
|
|
|
+ if (ch->connected) {
|
|
|
+ shost_printk(KERN_WARNING, target->scsi_host,
|
|
|
+ PFX "received DREQ\n");
|
|
|
+ rdma_disconnect(ch->rdma_cm.cm_id);
|
|
|
+ comp = 1;
|
|
|
+ ch->status = 0;
|
|
|
+ queue_work(system_long_wq, &target->tl_err_work);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RDMA_CM_EVENT_TIMEWAIT_EXIT:
|
|
|
+ shost_printk(KERN_ERR, target->scsi_host,
|
|
|
+ PFX "connection closed\n");
|
|
|
+
|
|
|
+ comp = 1;
|
|
|
+ ch->status = 0;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ shost_printk(KERN_WARNING, target->scsi_host,
|
|
|
+ PFX "Unhandled CM event %d\n", event->event);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (comp)
|
|
|
+ complete(&ch->done);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* srp_change_queue_depth - setting device queue depth
|
|
|
* @sdev: scsi device struct
|
|
@@ -2772,7 +3067,10 @@ static ssize_t show_service_id(struct device *dev,
|
|
|
{
|
|
|
struct srp_target_port *target = host_to_target(class_to_shost(dev));
|
|
|
|
|
|
- return sprintf(buf, "0x%016llx\n", be64_to_cpu(target->service_id));
|
|
|
+ if (target->using_rdma_cm)
|
|
|
+ return -ENOENT;
|
|
|
+ return sprintf(buf, "0x%016llx\n",
|
|
|
+ be64_to_cpu(target->ib_cm.service_id));
|
|
|
}
|
|
|
|
|
|
static ssize_t show_pkey(struct device *dev, struct device_attribute *attr,
|
|
@@ -2780,7 +3078,9 @@ static ssize_t show_pkey(struct device *dev, struct device_attribute *attr,
|
|
|
{
|
|
|
struct srp_target_port *target = host_to_target(class_to_shost(dev));
|
|
|
|
|
|
- return sprintf(buf, "0x%04x\n", be16_to_cpu(target->pkey));
|
|
|
+ if (target->using_rdma_cm)
|
|
|
+ return -ENOENT;
|
|
|
+ return sprintf(buf, "0x%04x\n", be16_to_cpu(target->ib_cm.pkey));
|
|
|
}
|
|
|
|
|
|
static ssize_t show_sgid(struct device *dev, struct device_attribute *attr,
|
|
@@ -2797,7 +3097,9 @@ static ssize_t show_dgid(struct device *dev, struct device_attribute *attr,
|
|
|
struct srp_target_port *target = host_to_target(class_to_shost(dev));
|
|
|
struct srp_rdma_ch *ch = &target->ch[0];
|
|
|
|
|
|
- return sprintf(buf, "%pI6\n", ch->path.dgid.raw);
|
|
|
+ if (target->using_rdma_cm)
|
|
|
+ return -ENOENT;
|
|
|
+ return sprintf(buf, "%pI6\n", ch->ib_cm.path.dgid.raw);
|
|
|
}
|
|
|
|
|
|
static ssize_t show_orig_dgid(struct device *dev,
|
|
@@ -2805,7 +3107,9 @@ static ssize_t show_orig_dgid(struct device *dev,
|
|
|
{
|
|
|
struct srp_target_port *target = host_to_target(class_to_shost(dev));
|
|
|
|
|
|
- return sprintf(buf, "%pI6\n", target->orig_dgid.raw);
|
|
|
+ if (target->using_rdma_cm)
|
|
|
+ return -ENOENT;
|
|
|
+ return sprintf(buf, "%pI6\n", target->ib_cm.orig_dgid.raw);
|
|
|
}
|
|
|
|
|
|
static ssize_t show_req_lim(struct device *dev,
|
|
@@ -3050,6 +3354,9 @@ static bool srp_conn_unique(struct srp_host *host,
|
|
|
if (t != target &&
|
|
|
target->id_ext == t->id_ext &&
|
|
|
target->ioc_guid == t->ioc_guid &&
|
|
|
+ (!target->using_rdma_cm ||
|
|
|
+ memcmp(&target->rdma_cm.dst, &t->rdma_cm.dst,
|
|
|
+ sizeof(target->rdma_cm.dst)) == 0) &&
|
|
|
target->initiator_ext == t->initiator_ext) {
|
|
|
ret = false;
|
|
|
break;
|
|
@@ -3066,6 +3373,9 @@ out:
|
|
|
*
|
|
|
* id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,dgid=<dest GID>,
|
|
|
* pkey=<P_Key>,service_id=<service ID>
|
|
|
+ * or
|
|
|
+ * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,
|
|
|
+ * [src=<IPv4 address>,]dest=<IPv4 address>:<port number>
|
|
|
*
|
|
|
* to the add_target sysfs attribute.
|
|
|
*/
|
|
@@ -3086,11 +3396,19 @@ enum {
|
|
|
SRP_OPT_COMP_VECTOR = 1 << 12,
|
|
|
SRP_OPT_TL_RETRY_COUNT = 1 << 13,
|
|
|
SRP_OPT_QUEUE_SIZE = 1 << 14,
|
|
|
- SRP_OPT_ALL = (SRP_OPT_ID_EXT |
|
|
|
- SRP_OPT_IOC_GUID |
|
|
|
- SRP_OPT_DGID |
|
|
|
- SRP_OPT_PKEY |
|
|
|
- SRP_OPT_SERVICE_ID),
|
|
|
+ SRP_OPT_IP_SRC = 1 << 15,
|
|
|
+ SRP_OPT_IP_DEST = 1 << 16,
|
|
|
+};
|
|
|
+
|
|
|
+static unsigned int srp_opt_mandatory[] = {
|
|
|
+ SRP_OPT_ID_EXT |
|
|
|
+ SRP_OPT_IOC_GUID |
|
|
|
+ SRP_OPT_DGID |
|
|
|
+ SRP_OPT_PKEY |
|
|
|
+ SRP_OPT_SERVICE_ID,
|
|
|
+ SRP_OPT_ID_EXT |
|
|
|
+ SRP_OPT_IOC_GUID |
|
|
|
+ SRP_OPT_IP_DEST,
|
|
|
};
|
|
|
|
|
|
static const match_table_t srp_opt_tokens = {
|
|
@@ -3109,10 +3427,28 @@ static const match_table_t srp_opt_tokens = {
|
|
|
{ SRP_OPT_COMP_VECTOR, "comp_vector=%u" },
|
|
|
{ SRP_OPT_TL_RETRY_COUNT, "tl_retry_count=%u" },
|
|
|
{ SRP_OPT_QUEUE_SIZE, "queue_size=%d" },
|
|
|
+ { SRP_OPT_IP_SRC, "src=%s" },
|
|
|
+ { SRP_OPT_IP_DEST, "dest=%s" },
|
|
|
{ SRP_OPT_ERR, NULL }
|
|
|
};
|
|
|
|
|
|
-static int srp_parse_options(const char *buf, struct srp_target_port *target)
|
|
|
+static int srp_parse_in(struct net *net, struct sockaddr_storage *sa,
|
|
|
+ const char *addr_port_str)
|
|
|
+{
|
|
|
+ char *addr = kstrdup(addr_port_str, GFP_KERNEL);
|
|
|
+ char *port_str = addr;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (!addr)
|
|
|
+ return -ENOMEM;
|
|
|
+ strsep(&port_str, ":");
|
|
|
+ ret = inet_pton_with_scope(net, AF_UNSPEC, addr, port_str, sa);
|
|
|
+ kfree(addr);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int srp_parse_options(struct net *net, const char *buf,
|
|
|
+ struct srp_target_port *target)
|
|
|
{
|
|
|
char *options, *sep_opt;
|
|
|
char *p;
|
|
@@ -3180,7 +3516,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ret = hex2bin(target->orig_dgid.raw, p, 16);
|
|
|
+ ret = hex2bin(target->ib_cm.orig_dgid.raw, p, 16);
|
|
|
kfree(p);
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
@@ -3191,7 +3527,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
|
|
|
pr_warn("bad P_Key parameter '%s'\n", p);
|
|
|
goto out;
|
|
|
}
|
|
|
- target->pkey = cpu_to_be16(token);
|
|
|
+ target->ib_cm.pkey = cpu_to_be16(token);
|
|
|
break;
|
|
|
|
|
|
case SRP_OPT_SERVICE_ID:
|
|
@@ -3206,7 +3542,39 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
|
|
|
kfree(p);
|
|
|
goto out;
|
|
|
}
|
|
|
- target->service_id = cpu_to_be64(ull);
|
|
|
+ target->ib_cm.service_id = cpu_to_be64(ull);
|
|
|
+ kfree(p);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SRP_OPT_IP_SRC:
|
|
|
+ p = match_strdup(args);
|
|
|
+ if (!p) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ ret = srp_parse_in(net, &target->rdma_cm.src.ss, p);
|
|
|
+ if (ret < 0) {
|
|
|
+ pr_warn("bad source parameter '%s'\n", p);
|
|
|
+ kfree(p);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ target->rdma_cm.src_specified = true;
|
|
|
+ kfree(p);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SRP_OPT_IP_DEST:
|
|
|
+ p = match_strdup(args);
|
|
|
+ if (!p) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ ret = srp_parse_in(net, &target->rdma_cm.dst.ss, p);
|
|
|
+ if (ret < 0) {
|
|
|
+ pr_warn("bad dest parameter '%s'\n", p);
|
|
|
+ kfree(p);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ target->using_rdma_cm = true;
|
|
|
kfree(p);
|
|
|
break;
|
|
|
|
|
@@ -3321,14 +3689,14 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if ((opt_mask & SRP_OPT_ALL) == SRP_OPT_ALL)
|
|
|
- ret = 0;
|
|
|
- else
|
|
|
- for (i = 0; i < ARRAY_SIZE(srp_opt_tokens); ++i)
|
|
|
- if ((srp_opt_tokens[i].token & SRP_OPT_ALL) &&
|
|
|
- !(srp_opt_tokens[i].token & opt_mask))
|
|
|
- pr_warn("target creation request is missing parameter '%s'\n",
|
|
|
- srp_opt_tokens[i].pattern);
|
|
|
+ for (i = 0; i < ARRAY_SIZE(srp_opt_mandatory); i++) {
|
|
|
+ if ((opt_mask & srp_opt_mandatory[i]) == srp_opt_mandatory[i]) {
|
|
|
+ ret = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (ret)
|
|
|
+ pr_warn("target creation request is missing one or more parameters\n");
|
|
|
|
|
|
if (target->scsi_host->cmd_per_lun > target->scsi_host->can_queue
|
|
|
&& (opt_mask & SRP_OPT_MAX_CMD_PER_LUN))
|
|
@@ -3369,6 +3737,7 @@ static ssize_t srp_create_target(struct device *dev,
|
|
|
|
|
|
target = host_to_target(target_host);
|
|
|
|
|
|
+ target->net = kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
|
|
|
target->io_class = SRP_REV16A_IB_IO_CLASS;
|
|
|
target->scsi_host = target_host;
|
|
|
target->srp_host = host;
|
|
@@ -3390,18 +3759,29 @@ static ssize_t srp_create_target(struct device *dev,
|
|
|
if (ret < 0)
|
|
|
goto put;
|
|
|
|
|
|
- ret = srp_parse_options(buf, target);
|
|
|
+ ret = srp_parse_options(target->net, buf, target);
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
|
|
|
target->req_ring_size = target->queue_size - SRP_TSK_MGMT_SQ_SIZE;
|
|
|
|
|
|
if (!srp_conn_unique(target->srp_host, target)) {
|
|
|
- shost_printk(KERN_INFO, target->scsi_host,
|
|
|
- PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;initiator_ext=%016llx\n",
|
|
|
- be64_to_cpu(target->id_ext),
|
|
|
- be64_to_cpu(target->ioc_guid),
|
|
|
- be64_to_cpu(target->initiator_ext));
|
|
|
+ if (target->using_rdma_cm) {
|
|
|
+ char dst_addr[64];
|
|
|
+
|
|
|
+ shost_printk(KERN_INFO, target->scsi_host,
|
|
|
+ PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;dest=%s\n",
|
|
|
+ be64_to_cpu(target->id_ext),
|
|
|
+ be64_to_cpu(target->ioc_guid),
|
|
|
+ inet_ntop(&target->rdma_cm.dst, dst_addr,
|
|
|
+ sizeof(dst_addr)));
|
|
|
+ } else {
|
|
|
+ shost_printk(KERN_INFO, target->scsi_host,
|
|
|
+ PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;initiator_ext=%016llx\n",
|
|
|
+ be64_to_cpu(target->id_ext),
|
|
|
+ be64_to_cpu(target->ioc_guid),
|
|
|
+ be64_to_cpu(target->initiator_ext));
|
|
|
+ }
|
|
|
ret = -EEXIST;
|
|
|
goto out;
|
|
|
}
|
|
@@ -3502,11 +3882,18 @@ static ssize_t srp_create_target(struct device *dev,
|
|
|
|
|
|
ret = srp_connect_ch(ch, multich);
|
|
|
if (ret) {
|
|
|
+ char dst[64];
|
|
|
+
|
|
|
+ if (target->using_rdma_cm)
|
|
|
+ inet_ntop(&target->rdma_cm.dst, dst,
|
|
|
+ sizeof(dst));
|
|
|
+ else
|
|
|
+ snprintf(dst, sizeof(dst), "%pI6",
|
|
|
+ target->ib_cm.orig_dgid.raw);
|
|
|
shost_printk(KERN_ERR, target->scsi_host,
|
|
|
- PFX "Connection %d/%d to %pI6 failed\n",
|
|
|
+ PFX "Connection %d/%d to %s failed\n",
|
|
|
ch_start + cpu_idx,
|
|
|
- target->ch_count,
|
|
|
- ch->target->orig_dgid.raw);
|
|
|
+ target->ch_count, dst);
|
|
|
if (node_idx == 0 && cpu_idx == 0) {
|
|
|
goto free_ch;
|
|
|
} else {
|
|
@@ -3531,13 +3918,25 @@ connected:
|
|
|
goto err_disconnect;
|
|
|
|
|
|
if (target->state != SRP_TARGET_REMOVED) {
|
|
|
- shost_printk(KERN_DEBUG, target->scsi_host, PFX
|
|
|
- "new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n",
|
|
|
- be64_to_cpu(target->id_ext),
|
|
|
- be64_to_cpu(target->ioc_guid),
|
|
|
- be16_to_cpu(target->pkey),
|
|
|
- be64_to_cpu(target->service_id),
|
|
|
- target->sgid.raw, target->orig_dgid.raw);
|
|
|
+ if (target->using_rdma_cm) {
|
|
|
+ char dst[64];
|
|
|
+
|
|
|
+ inet_ntop(&target->rdma_cm.dst, dst, sizeof(dst));
|
|
|
+ shost_printk(KERN_DEBUG, target->scsi_host, PFX
|
|
|
+ "new target: id_ext %016llx ioc_guid %016llx sgid %pI6 dest %s\n",
|
|
|
+ be64_to_cpu(target->id_ext),
|
|
|
+ be64_to_cpu(target->ioc_guid),
|
|
|
+ target->sgid.raw, dst);
|
|
|
+ } else {
|
|
|
+ shost_printk(KERN_DEBUG, target->scsi_host, PFX
|
|
|
+ "new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n",
|
|
|
+ be64_to_cpu(target->id_ext),
|
|
|
+ be64_to_cpu(target->ioc_guid),
|
|
|
+ be16_to_cpu(target->ib_cm.pkey),
|
|
|
+ be64_to_cpu(target->ib_cm.service_id),
|
|
|
+ target->sgid.raw,
|
|
|
+ target->ib_cm.orig_dgid.raw);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
ret = count;
|
|
@@ -3547,8 +3946,16 @@ out:
|
|
|
|
|
|
put:
|
|
|
scsi_host_put(target->scsi_host);
|
|
|
- if (ret < 0)
|
|
|
+ if (ret < 0) {
|
|
|
+ /*
|
|
|
+ * If a call to srp_remove_target() has not been scheduled,
|
|
|
+ * drop the network namespace reference now that was obtained
|
|
|
+ * earlier in this function.
|
|
|
+ */
|
|
|
+ if (target->state != SRP_TARGET_REMOVED)
|
|
|
+ kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net);
|
|
|
scsi_host_put(target->scsi_host);
|
|
|
+ }
|
|
|
|
|
|
return ret;
|
|
|
|