IB/srp: Add RDMA/CM support
Since the SRP_LOGIN_REQ defined in the SRP standard is larger than what fits in the RDMA/CM login request private data, introduce a new login request format for the RDMA/CM. Note: since srp_daemon and ibsrpdm rely on the subnet manager and since there is no equivalent of the IB subnet manager in non-IB networks, login has to be performed manually for non-IB networks. Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
parent
172856eac7
commit
19f313438c
3 changed files with 603 additions and 151 deletions
|
@ -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,7 +268,7 @@ 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,
|
||||
static int srp_init_ib_qp(struct srp_target_port *target,
|
||||
struct ib_qp *qp)
|
||||
{
|
||||
struct ib_qp_attr *attr;
|
||||
|
@ -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 @@ static int srp_init_qp(struct srp_target_port *target,
|
|||
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;
|
||||
|
||||
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)) {
|
||||
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,6 +664,9 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch)
|
|||
return 0;
|
||||
|
||||
err_qp:
|
||||
if (target->using_rdma_cm)
|
||||
rdma_destroy_qp(ch->rdma_cm.cm_id);
|
||||
else
|
||||
ib_destroy_qp(qp);
|
||||
|
||||
err_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 @@ static int srp_lookup_path(struct srp_rdma_ch *ch)
|
|||
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->ib_param.responder_resources = 4;
|
||||
req->ib_param.rnr_retry_count = 7;
|
||||
req->ib_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_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 :
|
||||
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);
|
||||
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->priv.initiator_port_id;
|
||||
tpi = req->priv.target_port_id;
|
||||
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,8 +2546,17 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
|
|||
goto error;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!target->using_rdma_cm) {
|
||||
ret = -ENOMEM;
|
||||
qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL);
|
||||
qp_attr = kmalloc(sizeof(*qp_attr), GFP_KERNEL);
|
||||
if (!qp_attr)
|
||||
goto error;
|
||||
|
||||
|
@ -2399,14 +2569,6 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
|
|||
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;
|
||||
}
|
||||
|
||||
qp_attr->qp_state = IB_QPS_RTS;
|
||||
ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
|
||||
if (ret)
|
||||
|
@ -2419,6 +2581,7 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
|
|||
goto error_free;
|
||||
|
||||
ret = ib_send_cm_rtu(cm_id, NULL, 0);
|
||||
}
|
||||
|
||||
error_free:
|
||||
kfree(qp_attr);
|
||||
|
@ -2427,7 +2590,7 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
|
|||
ch->status = ret;
|
||||
}
|
||||
|
||||
static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
|
||||
static void srp_ib_cm_rej_handler(struct ib_cm_id *cm_id,
|
||||
struct ib_cm_event *event,
|
||||
struct srp_rdma_ch *ch)
|
||||
{
|
||||
|
@ -2435,33 +2598,35 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
|
|||
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 @@ static bool srp_conn_unique(struct srp_host *host,
|
|||
*
|
||||
* 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_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_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)
|
||||
for (i = 0; i < ARRAY_SIZE(srp_opt_mandatory); i++) {
|
||||
if ((opt_mask & srp_opt_mandatory[i]) == srp_opt_mandatory[i]) {
|
||||
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);
|
||||
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)) {
|
||||
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 @@ static ssize_t srp_create_target(struct device *dev,
|
|||
goto err_disconnect;
|
||||
|
||||
if (target->state != SRP_TARGET_REMOVED) {
|
||||
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->pkey),
|
||||
be64_to_cpu(target->service_id),
|
||||
target->sgid.raw, target->orig_dgid.raw);
|
||||
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 @@ static ssize_t srp_create_target(struct device *dev,
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <rdma/ib_sa.h>
|
||||
#include <rdma/ib_cm.h>
|
||||
#include <rdma/ib_fmr_pool.h>
|
||||
#include <rdma/rdma_cm.h>
|
||||
|
||||
enum {
|
||||
SRP_PATH_REC_TIMEOUT_MS = 1000,
|
||||
|
@ -153,11 +154,18 @@ struct srp_rdma_ch {
|
|||
struct completion done;
|
||||
int status;
|
||||
|
||||
union {
|
||||
struct ib_cm {
|
||||
struct sa_path_rec path;
|
||||
struct ib_sa_query *path_query;
|
||||
int path_query_id;
|
||||
|
||||
struct ib_cm_id *cm_id;
|
||||
} ib_cm;
|
||||
struct rdma_cm {
|
||||
struct rdma_cm_id *cm_id;
|
||||
} rdma_cm;
|
||||
};
|
||||
|
||||
struct srp_iu **tx_ring;
|
||||
struct srp_iu **rx_ring;
|
||||
struct srp_request *req_ring;
|
||||
|
@ -182,6 +190,7 @@ struct srp_target_port {
|
|||
/* read only in the hot path */
|
||||
u32 global_rkey;
|
||||
struct srp_rdma_ch *ch;
|
||||
struct net *net;
|
||||
u32 ch_count;
|
||||
u32 lkey;
|
||||
enum srp_target_state state;
|
||||
|
@ -194,7 +203,6 @@ struct srp_target_port {
|
|||
union ib_gid sgid;
|
||||
__be64 id_ext;
|
||||
__be64 ioc_guid;
|
||||
__be64 service_id;
|
||||
__be64 initiator_ext;
|
||||
u16 io_class;
|
||||
struct srp_host *srp_host;
|
||||
|
@ -210,8 +218,28 @@ struct srp_target_port {
|
|||
int comp_vector;
|
||||
int tl_retry_count;
|
||||
|
||||
bool using_rdma_cm;
|
||||
|
||||
union {
|
||||
struct {
|
||||
__be64 service_id;
|
||||
union ib_gid orig_dgid;
|
||||
__be16 pkey;
|
||||
} ib_cm;
|
||||
struct {
|
||||
union {
|
||||
struct sockaddr_in ip4;
|
||||
struct sockaddr_in6 ip6;
|
||||
struct sockaddr_storage ss;
|
||||
} src;
|
||||
union {
|
||||
struct sockaddr_in ip4;
|
||||
struct sockaddr_in6 ip6;
|
||||
struct sockaddr_storage ss;
|
||||
} dst;
|
||||
bool src_specified;
|
||||
} rdma_cm;
|
||||
};
|
||||
|
||||
u32 rq_tmo_jiffies;
|
||||
|
||||
|
|
|
@ -129,6 +129,23 @@ struct srp_login_req {
|
|||
u8 target_port_id[16];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct srp_login_req_rdma - RDMA/CM login parameters.
|
||||
*
|
||||
* RDMA/CM over InfiniBand can only carry 92 - 36 = 56 bytes of private
|
||||
* data. The %srp_login_req_rdma structure contains the same information as
|
||||
* %srp_login_req but with the reserved data removed.
|
||||
*/
|
||||
struct srp_login_req_rdma {
|
||||
u64 tag;
|
||||
__be16 req_buf_fmt;
|
||||
u8 req_flags;
|
||||
u8 opcode;
|
||||
__be32 req_it_iu_len;
|
||||
u8 initiator_port_id[16];
|
||||
u8 target_port_id[16];
|
||||
};
|
||||
|
||||
/*
|
||||
* The SRP spec defines the size of the LOGIN_RSP structure to be 52
|
||||
* bytes, so it needs to be packed to avoid having it padded to 56
|
||||
|
|
Loading…
Reference in a new issue