162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * RDMA transport layer based on the trans_fd.c implementation. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008 by Tom Tucker <tom@opengridcomputing.com> 662306a36Sopenharmony_ci * Copyright (C) 2006 by Russ Cox <rsc@swtch.com> 762306a36Sopenharmony_ci * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> 862306a36Sopenharmony_ci * Copyright (C) 2004-2008 by Eric Van Hensbergen <ericvh@gmail.com> 962306a36Sopenharmony_ci * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/in.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/net.h> 1762306a36Sopenharmony_ci#include <linux/ipv6.h> 1862306a36Sopenharmony_ci#include <linux/kthread.h> 1962306a36Sopenharmony_ci#include <linux/errno.h> 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/un.h> 2262306a36Sopenharmony_ci#include <linux/uaccess.h> 2362306a36Sopenharmony_ci#include <linux/inet.h> 2462306a36Sopenharmony_ci#include <linux/file.h> 2562306a36Sopenharmony_ci#include <linux/parser.h> 2662306a36Sopenharmony_ci#include <linux/semaphore.h> 2762306a36Sopenharmony_ci#include <linux/slab.h> 2862306a36Sopenharmony_ci#include <linux/seq_file.h> 2962306a36Sopenharmony_ci#include <net/9p/9p.h> 3062306a36Sopenharmony_ci#include <net/9p/client.h> 3162306a36Sopenharmony_ci#include <net/9p/transport.h> 3262306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 3362306a36Sopenharmony_ci#include <rdma/rdma_cm.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define P9_PORT 5640 3662306a36Sopenharmony_ci#define P9_RDMA_SQ_DEPTH 32 3762306a36Sopenharmony_ci#define P9_RDMA_RQ_DEPTH 32 3862306a36Sopenharmony_ci#define P9_RDMA_SEND_SGE 4 3962306a36Sopenharmony_ci#define P9_RDMA_RECV_SGE 4 4062306a36Sopenharmony_ci#define P9_RDMA_IRD 0 4162306a36Sopenharmony_ci#define P9_RDMA_ORD 0 4262306a36Sopenharmony_ci#define P9_RDMA_TIMEOUT 30000 /* 30 seconds */ 4362306a36Sopenharmony_ci#define P9_RDMA_MAXSIZE (1024*1024) /* 1MB */ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/** 4662306a36Sopenharmony_ci * struct p9_trans_rdma - RDMA transport instance 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * @state: tracks the transport state machine for connection setup and tear down 4962306a36Sopenharmony_ci * @cm_id: The RDMA CM ID 5062306a36Sopenharmony_ci * @pd: Protection Domain pointer 5162306a36Sopenharmony_ci * @qp: Queue Pair pointer 5262306a36Sopenharmony_ci * @cq: Completion Queue pointer 5362306a36Sopenharmony_ci * @timeout: Number of uSecs to wait for connection management events 5462306a36Sopenharmony_ci * @privport: Whether a privileged port may be used 5562306a36Sopenharmony_ci * @port: The port to use 5662306a36Sopenharmony_ci * @sq_depth: The depth of the Send Queue 5762306a36Sopenharmony_ci * @sq_sem: Semaphore for the SQ 5862306a36Sopenharmony_ci * @rq_depth: The depth of the Receive Queue. 5962306a36Sopenharmony_ci * @rq_sem: Semaphore for the RQ 6062306a36Sopenharmony_ci * @excess_rc : Amount of posted Receive Contexts without a pending request. 6162306a36Sopenharmony_ci * See rdma_request() 6262306a36Sopenharmony_ci * @addr: The remote peer's address 6362306a36Sopenharmony_ci * @req_lock: Protects the active request list 6462306a36Sopenharmony_ci * @cm_done: Completion event for connection management tracking 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cistruct p9_trans_rdma { 6762306a36Sopenharmony_ci enum { 6862306a36Sopenharmony_ci P9_RDMA_INIT, 6962306a36Sopenharmony_ci P9_RDMA_ADDR_RESOLVED, 7062306a36Sopenharmony_ci P9_RDMA_ROUTE_RESOLVED, 7162306a36Sopenharmony_ci P9_RDMA_CONNECTED, 7262306a36Sopenharmony_ci P9_RDMA_FLUSHING, 7362306a36Sopenharmony_ci P9_RDMA_CLOSING, 7462306a36Sopenharmony_ci P9_RDMA_CLOSED, 7562306a36Sopenharmony_ci } state; 7662306a36Sopenharmony_ci struct rdma_cm_id *cm_id; 7762306a36Sopenharmony_ci struct ib_pd *pd; 7862306a36Sopenharmony_ci struct ib_qp *qp; 7962306a36Sopenharmony_ci struct ib_cq *cq; 8062306a36Sopenharmony_ci long timeout; 8162306a36Sopenharmony_ci bool privport; 8262306a36Sopenharmony_ci u16 port; 8362306a36Sopenharmony_ci int sq_depth; 8462306a36Sopenharmony_ci struct semaphore sq_sem; 8562306a36Sopenharmony_ci int rq_depth; 8662306a36Sopenharmony_ci struct semaphore rq_sem; 8762306a36Sopenharmony_ci atomic_t excess_rc; 8862306a36Sopenharmony_ci struct sockaddr_in addr; 8962306a36Sopenharmony_ci spinlock_t req_lock; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci struct completion cm_done; 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistruct p9_rdma_req; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/** 9762306a36Sopenharmony_ci * struct p9_rdma_context - Keeps track of in-process WR 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * @cqe: completion queue entry 10062306a36Sopenharmony_ci * @busa: Bus address to unmap when the WR completes 10162306a36Sopenharmony_ci * @req: Keeps track of requests (send) 10262306a36Sopenharmony_ci * @rc: Keepts track of replies (receive) 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cistruct p9_rdma_context { 10562306a36Sopenharmony_ci struct ib_cqe cqe; 10662306a36Sopenharmony_ci dma_addr_t busa; 10762306a36Sopenharmony_ci union { 10862306a36Sopenharmony_ci struct p9_req_t *req; 10962306a36Sopenharmony_ci struct p9_fcall rc; 11062306a36Sopenharmony_ci }; 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/** 11462306a36Sopenharmony_ci * struct p9_rdma_opts - Collection of mount options 11562306a36Sopenharmony_ci * @port: port of connection 11662306a36Sopenharmony_ci * @privport: Whether a privileged port may be used 11762306a36Sopenharmony_ci * @sq_depth: The requested depth of the SQ. This really doesn't need 11862306a36Sopenharmony_ci * to be any deeper than the number of threads used in the client 11962306a36Sopenharmony_ci * @rq_depth: The depth of the RQ. Should be greater than or equal to SQ depth 12062306a36Sopenharmony_ci * @timeout: Time to wait in msecs for CM events 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_cistruct p9_rdma_opts { 12362306a36Sopenharmony_ci short port; 12462306a36Sopenharmony_ci bool privport; 12562306a36Sopenharmony_ci int sq_depth; 12662306a36Sopenharmony_ci int rq_depth; 12762306a36Sopenharmony_ci long timeout; 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* 13162306a36Sopenharmony_ci * Option Parsing (code inspired by NFS code) 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_cienum { 13462306a36Sopenharmony_ci /* Options that take integer arguments */ 13562306a36Sopenharmony_ci Opt_port, Opt_rq_depth, Opt_sq_depth, Opt_timeout, 13662306a36Sopenharmony_ci /* Options that take no argument */ 13762306a36Sopenharmony_ci Opt_privport, 13862306a36Sopenharmony_ci Opt_err, 13962306a36Sopenharmony_ci}; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic match_table_t tokens = { 14262306a36Sopenharmony_ci {Opt_port, "port=%u"}, 14362306a36Sopenharmony_ci {Opt_sq_depth, "sq=%u"}, 14462306a36Sopenharmony_ci {Opt_rq_depth, "rq=%u"}, 14562306a36Sopenharmony_ci {Opt_timeout, "timeout=%u"}, 14662306a36Sopenharmony_ci {Opt_privport, "privport"}, 14762306a36Sopenharmony_ci {Opt_err, NULL}, 14862306a36Sopenharmony_ci}; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int p9_rdma_show_options(struct seq_file *m, struct p9_client *clnt) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct p9_trans_rdma *rdma = clnt->trans; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (rdma->port != P9_PORT) 15562306a36Sopenharmony_ci seq_printf(m, ",port=%u", rdma->port); 15662306a36Sopenharmony_ci if (rdma->sq_depth != P9_RDMA_SQ_DEPTH) 15762306a36Sopenharmony_ci seq_printf(m, ",sq=%u", rdma->sq_depth); 15862306a36Sopenharmony_ci if (rdma->rq_depth != P9_RDMA_RQ_DEPTH) 15962306a36Sopenharmony_ci seq_printf(m, ",rq=%u", rdma->rq_depth); 16062306a36Sopenharmony_ci if (rdma->timeout != P9_RDMA_TIMEOUT) 16162306a36Sopenharmony_ci seq_printf(m, ",timeout=%lu", rdma->timeout); 16262306a36Sopenharmony_ci if (rdma->privport) 16362306a36Sopenharmony_ci seq_puts(m, ",privport"); 16462306a36Sopenharmony_ci return 0; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/** 16862306a36Sopenharmony_ci * parse_opts - parse mount options into rdma options structure 16962306a36Sopenharmony_ci * @params: options string passed from mount 17062306a36Sopenharmony_ci * @opts: rdma transport-specific structure to parse options into 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * Returns 0 upon success, -ERRNO upon failure 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_cistatic int parse_opts(char *params, struct p9_rdma_opts *opts) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci char *p; 17762306a36Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 17862306a36Sopenharmony_ci int option; 17962306a36Sopenharmony_ci char *options, *tmp_options; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci opts->port = P9_PORT; 18262306a36Sopenharmony_ci opts->sq_depth = P9_RDMA_SQ_DEPTH; 18362306a36Sopenharmony_ci opts->rq_depth = P9_RDMA_RQ_DEPTH; 18462306a36Sopenharmony_ci opts->timeout = P9_RDMA_TIMEOUT; 18562306a36Sopenharmony_ci opts->privport = false; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (!params) 18862306a36Sopenharmony_ci return 0; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci tmp_options = kstrdup(params, GFP_KERNEL); 19162306a36Sopenharmony_ci if (!tmp_options) { 19262306a36Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 19362306a36Sopenharmony_ci "failed to allocate copy of option string\n"); 19462306a36Sopenharmony_ci return -ENOMEM; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci options = tmp_options; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 19962306a36Sopenharmony_ci int token; 20062306a36Sopenharmony_ci int r; 20162306a36Sopenharmony_ci if (!*p) 20262306a36Sopenharmony_ci continue; 20362306a36Sopenharmony_ci token = match_token(p, tokens, args); 20462306a36Sopenharmony_ci if ((token != Opt_err) && (token != Opt_privport)) { 20562306a36Sopenharmony_ci r = match_int(&args[0], &option); 20662306a36Sopenharmony_ci if (r < 0) { 20762306a36Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 20862306a36Sopenharmony_ci "integer field, but no integer?\n"); 20962306a36Sopenharmony_ci continue; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci switch (token) { 21362306a36Sopenharmony_ci case Opt_port: 21462306a36Sopenharmony_ci opts->port = option; 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci case Opt_sq_depth: 21762306a36Sopenharmony_ci opts->sq_depth = option; 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci case Opt_rq_depth: 22062306a36Sopenharmony_ci opts->rq_depth = option; 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci case Opt_timeout: 22362306a36Sopenharmony_ci opts->timeout = option; 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci case Opt_privport: 22662306a36Sopenharmony_ci opts->privport = true; 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci default: 22962306a36Sopenharmony_ci continue; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci /* RQ must be at least as large as the SQ */ 23362306a36Sopenharmony_ci opts->rq_depth = max(opts->rq_depth, opts->sq_depth); 23462306a36Sopenharmony_ci kfree(tmp_options); 23562306a36Sopenharmony_ci return 0; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic int 23962306a36Sopenharmony_cip9_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct p9_client *c = id->context; 24262306a36Sopenharmony_ci struct p9_trans_rdma *rdma = c->trans; 24362306a36Sopenharmony_ci switch (event->event) { 24462306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_RESOLVED: 24562306a36Sopenharmony_ci BUG_ON(rdma->state != P9_RDMA_INIT); 24662306a36Sopenharmony_ci rdma->state = P9_RDMA_ADDR_RESOLVED; 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci case RDMA_CM_EVENT_ROUTE_RESOLVED: 25062306a36Sopenharmony_ci BUG_ON(rdma->state != P9_RDMA_ADDR_RESOLVED); 25162306a36Sopenharmony_ci rdma->state = P9_RDMA_ROUTE_RESOLVED; 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci case RDMA_CM_EVENT_ESTABLISHED: 25562306a36Sopenharmony_ci BUG_ON(rdma->state != P9_RDMA_ROUTE_RESOLVED); 25662306a36Sopenharmony_ci rdma->state = P9_RDMA_CONNECTED; 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci case RDMA_CM_EVENT_DISCONNECTED: 26062306a36Sopenharmony_ci if (rdma) 26162306a36Sopenharmony_ci rdma->state = P9_RDMA_CLOSED; 26262306a36Sopenharmony_ci c->status = Disconnected; 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci case RDMA_CM_EVENT_TIMEWAIT_EXIT: 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_CHANGE: 26962306a36Sopenharmony_ci case RDMA_CM_EVENT_ROUTE_ERROR: 27062306a36Sopenharmony_ci case RDMA_CM_EVENT_DEVICE_REMOVAL: 27162306a36Sopenharmony_ci case RDMA_CM_EVENT_MULTICAST_JOIN: 27262306a36Sopenharmony_ci case RDMA_CM_EVENT_MULTICAST_ERROR: 27362306a36Sopenharmony_ci case RDMA_CM_EVENT_REJECTED: 27462306a36Sopenharmony_ci case RDMA_CM_EVENT_CONNECT_REQUEST: 27562306a36Sopenharmony_ci case RDMA_CM_EVENT_CONNECT_RESPONSE: 27662306a36Sopenharmony_ci case RDMA_CM_EVENT_CONNECT_ERROR: 27762306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_ERROR: 27862306a36Sopenharmony_ci case RDMA_CM_EVENT_UNREACHABLE: 27962306a36Sopenharmony_ci c->status = Disconnected; 28062306a36Sopenharmony_ci rdma_disconnect(rdma->cm_id); 28162306a36Sopenharmony_ci break; 28262306a36Sopenharmony_ci default: 28362306a36Sopenharmony_ci BUG(); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci complete(&rdma->cm_done); 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic void 29062306a36Sopenharmony_cirecv_done(struct ib_cq *cq, struct ib_wc *wc) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct p9_client *client = cq->cq_context; 29362306a36Sopenharmony_ci struct p9_trans_rdma *rdma = client->trans; 29462306a36Sopenharmony_ci struct p9_rdma_context *c = 29562306a36Sopenharmony_ci container_of(wc->wr_cqe, struct p9_rdma_context, cqe); 29662306a36Sopenharmony_ci struct p9_req_t *req; 29762306a36Sopenharmony_ci int err = 0; 29862306a36Sopenharmony_ci int16_t tag; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci req = NULL; 30162306a36Sopenharmony_ci ib_dma_unmap_single(rdma->cm_id->device, c->busa, client->msize, 30262306a36Sopenharmony_ci DMA_FROM_DEVICE); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (wc->status != IB_WC_SUCCESS) 30562306a36Sopenharmony_ci goto err_out; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci c->rc.size = wc->byte_len; 30862306a36Sopenharmony_ci err = p9_parse_header(&c->rc, NULL, NULL, &tag, 1); 30962306a36Sopenharmony_ci if (err) 31062306a36Sopenharmony_ci goto err_out; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci req = p9_tag_lookup(client, tag); 31362306a36Sopenharmony_ci if (!req) 31462306a36Sopenharmony_ci goto err_out; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Check that we have not yet received a reply for this request. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci if (unlikely(req->rc.sdata)) { 31962306a36Sopenharmony_ci pr_err("Duplicate reply for request %d", tag); 32062306a36Sopenharmony_ci goto err_out; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci req->rc.size = c->rc.size; 32462306a36Sopenharmony_ci req->rc.sdata = c->rc.sdata; 32562306a36Sopenharmony_ci p9_client_cb(client, req, REQ_STATUS_RCVD); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci out: 32862306a36Sopenharmony_ci up(&rdma->rq_sem); 32962306a36Sopenharmony_ci kfree(c); 33062306a36Sopenharmony_ci return; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci err_out: 33362306a36Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, "req %p err %d status %d\n", 33462306a36Sopenharmony_ci req, err, wc->status); 33562306a36Sopenharmony_ci rdma->state = P9_RDMA_FLUSHING; 33662306a36Sopenharmony_ci client->status = Disconnected; 33762306a36Sopenharmony_ci goto out; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic void 34162306a36Sopenharmony_cisend_done(struct ib_cq *cq, struct ib_wc *wc) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct p9_client *client = cq->cq_context; 34462306a36Sopenharmony_ci struct p9_trans_rdma *rdma = client->trans; 34562306a36Sopenharmony_ci struct p9_rdma_context *c = 34662306a36Sopenharmony_ci container_of(wc->wr_cqe, struct p9_rdma_context, cqe); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci ib_dma_unmap_single(rdma->cm_id->device, 34962306a36Sopenharmony_ci c->busa, c->req->tc.size, 35062306a36Sopenharmony_ci DMA_TO_DEVICE); 35162306a36Sopenharmony_ci up(&rdma->sq_sem); 35262306a36Sopenharmony_ci p9_req_put(client, c->req); 35362306a36Sopenharmony_ci kfree(c); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic void qp_event_handler(struct ib_event *event, void *context) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, "QP event %d context %p\n", 35962306a36Sopenharmony_ci event->event, context); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic void rdma_destroy_trans(struct p9_trans_rdma *rdma) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci if (!rdma) 36562306a36Sopenharmony_ci return; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (rdma->qp && !IS_ERR(rdma->qp)) 36862306a36Sopenharmony_ci ib_destroy_qp(rdma->qp); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (rdma->pd && !IS_ERR(rdma->pd)) 37162306a36Sopenharmony_ci ib_dealloc_pd(rdma->pd); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (rdma->cq && !IS_ERR(rdma->cq)) 37462306a36Sopenharmony_ci ib_free_cq(rdma->cq); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (rdma->cm_id && !IS_ERR(rdma->cm_id)) 37762306a36Sopenharmony_ci rdma_destroy_id(rdma->cm_id); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci kfree(rdma); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int 38362306a36Sopenharmony_cipost_recv(struct p9_client *client, struct p9_rdma_context *c) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct p9_trans_rdma *rdma = client->trans; 38662306a36Sopenharmony_ci struct ib_recv_wr wr; 38762306a36Sopenharmony_ci struct ib_sge sge; 38862306a36Sopenharmony_ci int ret; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci c->busa = ib_dma_map_single(rdma->cm_id->device, 39162306a36Sopenharmony_ci c->rc.sdata, client->msize, 39262306a36Sopenharmony_ci DMA_FROM_DEVICE); 39362306a36Sopenharmony_ci if (ib_dma_mapping_error(rdma->cm_id->device, c->busa)) 39462306a36Sopenharmony_ci goto error; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci c->cqe.done = recv_done; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci sge.addr = c->busa; 39962306a36Sopenharmony_ci sge.length = client->msize; 40062306a36Sopenharmony_ci sge.lkey = rdma->pd->local_dma_lkey; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci wr.next = NULL; 40362306a36Sopenharmony_ci wr.wr_cqe = &c->cqe; 40462306a36Sopenharmony_ci wr.sg_list = &sge; 40562306a36Sopenharmony_ci wr.num_sge = 1; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci ret = ib_post_recv(rdma->qp, &wr, NULL); 40862306a36Sopenharmony_ci if (ret) 40962306a36Sopenharmony_ci ib_dma_unmap_single(rdma->cm_id->device, c->busa, 41062306a36Sopenharmony_ci client->msize, DMA_FROM_DEVICE); 41162306a36Sopenharmony_ci return ret; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci error: 41462306a36Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, "EIO\n"); 41562306a36Sopenharmony_ci return -EIO; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic int rdma_request(struct p9_client *client, struct p9_req_t *req) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct p9_trans_rdma *rdma = client->trans; 42162306a36Sopenharmony_ci struct ib_send_wr wr; 42262306a36Sopenharmony_ci struct ib_sge sge; 42362306a36Sopenharmony_ci int err = 0; 42462306a36Sopenharmony_ci unsigned long flags; 42562306a36Sopenharmony_ci struct p9_rdma_context *c = NULL; 42662306a36Sopenharmony_ci struct p9_rdma_context *rpl_context = NULL; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* When an error occurs between posting the recv and the send, 42962306a36Sopenharmony_ci * there will be a receive context posted without a pending request. 43062306a36Sopenharmony_ci * Since there is no way to "un-post" it, we remember it and skip 43162306a36Sopenharmony_ci * post_recv() for the next request. 43262306a36Sopenharmony_ci * So here, 43362306a36Sopenharmony_ci * see if we are this `next request' and need to absorb an excess rc. 43462306a36Sopenharmony_ci * If yes, then drop and free our own, and do not recv_post(). 43562306a36Sopenharmony_ci **/ 43662306a36Sopenharmony_ci if (unlikely(atomic_read(&rdma->excess_rc) > 0)) { 43762306a36Sopenharmony_ci if ((atomic_sub_return(1, &rdma->excess_rc) >= 0)) { 43862306a36Sopenharmony_ci /* Got one! */ 43962306a36Sopenharmony_ci p9_fcall_fini(&req->rc); 44062306a36Sopenharmony_ci req->rc.sdata = NULL; 44162306a36Sopenharmony_ci goto dont_need_post_recv; 44262306a36Sopenharmony_ci } else { 44362306a36Sopenharmony_ci /* We raced and lost. */ 44462306a36Sopenharmony_ci atomic_inc(&rdma->excess_rc); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* Allocate an fcall for the reply */ 44962306a36Sopenharmony_ci rpl_context = kmalloc(sizeof *rpl_context, GFP_NOFS); 45062306a36Sopenharmony_ci if (!rpl_context) { 45162306a36Sopenharmony_ci err = -ENOMEM; 45262306a36Sopenharmony_ci goto recv_error; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci rpl_context->rc.sdata = req->rc.sdata; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* 45762306a36Sopenharmony_ci * Post a receive buffer for this request. We need to ensure 45862306a36Sopenharmony_ci * there is a reply buffer available for every outstanding 45962306a36Sopenharmony_ci * request. A flushed request can result in no reply for an 46062306a36Sopenharmony_ci * outstanding request, so we must keep a count to avoid 46162306a36Sopenharmony_ci * overflowing the RQ. 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_ci if (down_interruptible(&rdma->rq_sem)) { 46462306a36Sopenharmony_ci err = -EINTR; 46562306a36Sopenharmony_ci goto recv_error; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci err = post_recv(client, rpl_context); 46962306a36Sopenharmony_ci if (err) { 47062306a36Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, "POST RECV failed: %d\n", err); 47162306a36Sopenharmony_ci goto recv_error; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci /* remove posted receive buffer from request structure */ 47462306a36Sopenharmony_ci req->rc.sdata = NULL; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cidont_need_post_recv: 47762306a36Sopenharmony_ci /* Post the request */ 47862306a36Sopenharmony_ci c = kmalloc(sizeof *c, GFP_NOFS); 47962306a36Sopenharmony_ci if (!c) { 48062306a36Sopenharmony_ci err = -ENOMEM; 48162306a36Sopenharmony_ci goto send_error; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci c->req = req; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci c->busa = ib_dma_map_single(rdma->cm_id->device, 48662306a36Sopenharmony_ci c->req->tc.sdata, c->req->tc.size, 48762306a36Sopenharmony_ci DMA_TO_DEVICE); 48862306a36Sopenharmony_ci if (ib_dma_mapping_error(rdma->cm_id->device, c->busa)) { 48962306a36Sopenharmony_ci err = -EIO; 49062306a36Sopenharmony_ci goto send_error; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci c->cqe.done = send_done; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci sge.addr = c->busa; 49662306a36Sopenharmony_ci sge.length = c->req->tc.size; 49762306a36Sopenharmony_ci sge.lkey = rdma->pd->local_dma_lkey; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci wr.next = NULL; 50062306a36Sopenharmony_ci wr.wr_cqe = &c->cqe; 50162306a36Sopenharmony_ci wr.opcode = IB_WR_SEND; 50262306a36Sopenharmony_ci wr.send_flags = IB_SEND_SIGNALED; 50362306a36Sopenharmony_ci wr.sg_list = &sge; 50462306a36Sopenharmony_ci wr.num_sge = 1; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (down_interruptible(&rdma->sq_sem)) { 50762306a36Sopenharmony_ci err = -EINTR; 50862306a36Sopenharmony_ci goto dma_unmap; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* Mark request as `sent' *before* we actually send it, 51262306a36Sopenharmony_ci * because doing if after could erase the REQ_STATUS_RCVD 51362306a36Sopenharmony_ci * status in case of a very fast reply. 51462306a36Sopenharmony_ci */ 51562306a36Sopenharmony_ci WRITE_ONCE(req->status, REQ_STATUS_SENT); 51662306a36Sopenharmony_ci err = ib_post_send(rdma->qp, &wr, NULL); 51762306a36Sopenharmony_ci if (err) 51862306a36Sopenharmony_ci goto dma_unmap; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Success */ 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cidma_unmap: 52462306a36Sopenharmony_ci ib_dma_unmap_single(rdma->cm_id->device, c->busa, 52562306a36Sopenharmony_ci c->req->tc.size, DMA_TO_DEVICE); 52662306a36Sopenharmony_ci /* Handle errors that happened during or while preparing the send: */ 52762306a36Sopenharmony_ci send_error: 52862306a36Sopenharmony_ci WRITE_ONCE(req->status, REQ_STATUS_ERROR); 52962306a36Sopenharmony_ci kfree(c); 53062306a36Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, "Error %d in rdma_request()\n", err); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* Ach. 53362306a36Sopenharmony_ci * We did recv_post(), but not send. We have one recv_post in excess. 53462306a36Sopenharmony_ci */ 53562306a36Sopenharmony_ci atomic_inc(&rdma->excess_rc); 53662306a36Sopenharmony_ci return err; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* Handle errors that happened during or while preparing post_recv(): */ 53962306a36Sopenharmony_ci recv_error: 54062306a36Sopenharmony_ci kfree(rpl_context); 54162306a36Sopenharmony_ci spin_lock_irqsave(&rdma->req_lock, flags); 54262306a36Sopenharmony_ci if (err != -EINTR && rdma->state < P9_RDMA_CLOSING) { 54362306a36Sopenharmony_ci rdma->state = P9_RDMA_CLOSING; 54462306a36Sopenharmony_ci spin_unlock_irqrestore(&rdma->req_lock, flags); 54562306a36Sopenharmony_ci rdma_disconnect(rdma->cm_id); 54662306a36Sopenharmony_ci } else 54762306a36Sopenharmony_ci spin_unlock_irqrestore(&rdma->req_lock, flags); 54862306a36Sopenharmony_ci return err; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic void rdma_close(struct p9_client *client) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct p9_trans_rdma *rdma; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (!client) 55662306a36Sopenharmony_ci return; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci rdma = client->trans; 55962306a36Sopenharmony_ci if (!rdma) 56062306a36Sopenharmony_ci return; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci client->status = Disconnected; 56362306a36Sopenharmony_ci rdma_disconnect(rdma->cm_id); 56462306a36Sopenharmony_ci rdma_destroy_trans(rdma); 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci/** 56862306a36Sopenharmony_ci * alloc_rdma - Allocate and initialize the rdma transport structure 56962306a36Sopenharmony_ci * @opts: Mount options structure 57062306a36Sopenharmony_ci */ 57162306a36Sopenharmony_cistatic struct p9_trans_rdma *alloc_rdma(struct p9_rdma_opts *opts) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct p9_trans_rdma *rdma; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci rdma = kzalloc(sizeof(struct p9_trans_rdma), GFP_KERNEL); 57662306a36Sopenharmony_ci if (!rdma) 57762306a36Sopenharmony_ci return NULL; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci rdma->port = opts->port; 58062306a36Sopenharmony_ci rdma->privport = opts->privport; 58162306a36Sopenharmony_ci rdma->sq_depth = opts->sq_depth; 58262306a36Sopenharmony_ci rdma->rq_depth = opts->rq_depth; 58362306a36Sopenharmony_ci rdma->timeout = opts->timeout; 58462306a36Sopenharmony_ci spin_lock_init(&rdma->req_lock); 58562306a36Sopenharmony_ci init_completion(&rdma->cm_done); 58662306a36Sopenharmony_ci sema_init(&rdma->sq_sem, rdma->sq_depth); 58762306a36Sopenharmony_ci sema_init(&rdma->rq_sem, rdma->rq_depth); 58862306a36Sopenharmony_ci atomic_set(&rdma->excess_rc, 0); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return rdma; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic int rdma_cancel(struct p9_client *client, struct p9_req_t *req) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci /* Nothing to do here. 59662306a36Sopenharmony_ci * We will take care of it (if we have to) in rdma_cancelled() 59762306a36Sopenharmony_ci */ 59862306a36Sopenharmony_ci return 1; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci/* A request has been fully flushed without a reply. 60262306a36Sopenharmony_ci * That means we have posted one buffer in excess. 60362306a36Sopenharmony_ci */ 60462306a36Sopenharmony_cistatic int rdma_cancelled(struct p9_client *client, struct p9_req_t *req) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct p9_trans_rdma *rdma = client->trans; 60762306a36Sopenharmony_ci atomic_inc(&rdma->excess_rc); 60862306a36Sopenharmony_ci return 0; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic int p9_rdma_bind_privport(struct p9_trans_rdma *rdma) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct sockaddr_in cl = { 61462306a36Sopenharmony_ci .sin_family = AF_INET, 61562306a36Sopenharmony_ci .sin_addr.s_addr = htonl(INADDR_ANY), 61662306a36Sopenharmony_ci }; 61762306a36Sopenharmony_ci int port, err = -EINVAL; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci for (port = P9_DEF_MAX_RESVPORT; port >= P9_DEF_MIN_RESVPORT; port--) { 62062306a36Sopenharmony_ci cl.sin_port = htons((ushort)port); 62162306a36Sopenharmony_ci err = rdma_bind_addr(rdma->cm_id, (struct sockaddr *)&cl); 62262306a36Sopenharmony_ci if (err != -EADDRINUSE) 62362306a36Sopenharmony_ci break; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci return err; 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci/** 62962306a36Sopenharmony_ci * rdma_create_trans - Transport method for creating a transport instance 63062306a36Sopenharmony_ci * @client: client instance 63162306a36Sopenharmony_ci * @addr: IP address string 63262306a36Sopenharmony_ci * @args: Mount options string 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_cistatic int 63562306a36Sopenharmony_cirdma_create_trans(struct p9_client *client, const char *addr, char *args) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci int err; 63862306a36Sopenharmony_ci struct p9_rdma_opts opts; 63962306a36Sopenharmony_ci struct p9_trans_rdma *rdma; 64062306a36Sopenharmony_ci struct rdma_conn_param conn_param; 64162306a36Sopenharmony_ci struct ib_qp_init_attr qp_attr; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (addr == NULL) 64462306a36Sopenharmony_ci return -EINVAL; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* Parse the transport specific mount options */ 64762306a36Sopenharmony_ci err = parse_opts(args, &opts); 64862306a36Sopenharmony_ci if (err < 0) 64962306a36Sopenharmony_ci return err; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* Create and initialize the RDMA transport structure */ 65262306a36Sopenharmony_ci rdma = alloc_rdma(&opts); 65362306a36Sopenharmony_ci if (!rdma) 65462306a36Sopenharmony_ci return -ENOMEM; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* Create the RDMA CM ID */ 65762306a36Sopenharmony_ci rdma->cm_id = rdma_create_id(&init_net, p9_cm_event_handler, client, 65862306a36Sopenharmony_ci RDMA_PS_TCP, IB_QPT_RC); 65962306a36Sopenharmony_ci if (IS_ERR(rdma->cm_id)) 66062306a36Sopenharmony_ci goto error; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* Associate the client with the transport */ 66362306a36Sopenharmony_ci client->trans = rdma; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* Bind to a privileged port if we need to */ 66662306a36Sopenharmony_ci if (opts.privport) { 66762306a36Sopenharmony_ci err = p9_rdma_bind_privport(rdma); 66862306a36Sopenharmony_ci if (err < 0) { 66962306a36Sopenharmony_ci pr_err("%s (%d): problem binding to privport: %d\n", 67062306a36Sopenharmony_ci __func__, task_pid_nr(current), -err); 67162306a36Sopenharmony_ci goto error; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Resolve the server's address */ 67662306a36Sopenharmony_ci rdma->addr.sin_family = AF_INET; 67762306a36Sopenharmony_ci rdma->addr.sin_addr.s_addr = in_aton(addr); 67862306a36Sopenharmony_ci rdma->addr.sin_port = htons(opts.port); 67962306a36Sopenharmony_ci err = rdma_resolve_addr(rdma->cm_id, NULL, 68062306a36Sopenharmony_ci (struct sockaddr *)&rdma->addr, 68162306a36Sopenharmony_ci rdma->timeout); 68262306a36Sopenharmony_ci if (err) 68362306a36Sopenharmony_ci goto error; 68462306a36Sopenharmony_ci err = wait_for_completion_interruptible(&rdma->cm_done); 68562306a36Sopenharmony_ci if (err || (rdma->state != P9_RDMA_ADDR_RESOLVED)) 68662306a36Sopenharmony_ci goto error; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* Resolve the route to the server */ 68962306a36Sopenharmony_ci err = rdma_resolve_route(rdma->cm_id, rdma->timeout); 69062306a36Sopenharmony_ci if (err) 69162306a36Sopenharmony_ci goto error; 69262306a36Sopenharmony_ci err = wait_for_completion_interruptible(&rdma->cm_done); 69362306a36Sopenharmony_ci if (err || (rdma->state != P9_RDMA_ROUTE_RESOLVED)) 69462306a36Sopenharmony_ci goto error; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* Create the Completion Queue */ 69762306a36Sopenharmony_ci rdma->cq = ib_alloc_cq_any(rdma->cm_id->device, client, 69862306a36Sopenharmony_ci opts.sq_depth + opts.rq_depth + 1, 69962306a36Sopenharmony_ci IB_POLL_SOFTIRQ); 70062306a36Sopenharmony_ci if (IS_ERR(rdma->cq)) 70162306a36Sopenharmony_ci goto error; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* Create the Protection Domain */ 70462306a36Sopenharmony_ci rdma->pd = ib_alloc_pd(rdma->cm_id->device, 0); 70562306a36Sopenharmony_ci if (IS_ERR(rdma->pd)) 70662306a36Sopenharmony_ci goto error; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci /* Create the Queue Pair */ 70962306a36Sopenharmony_ci memset(&qp_attr, 0, sizeof qp_attr); 71062306a36Sopenharmony_ci qp_attr.event_handler = qp_event_handler; 71162306a36Sopenharmony_ci qp_attr.qp_context = client; 71262306a36Sopenharmony_ci qp_attr.cap.max_send_wr = opts.sq_depth; 71362306a36Sopenharmony_ci qp_attr.cap.max_recv_wr = opts.rq_depth; 71462306a36Sopenharmony_ci qp_attr.cap.max_send_sge = P9_RDMA_SEND_SGE; 71562306a36Sopenharmony_ci qp_attr.cap.max_recv_sge = P9_RDMA_RECV_SGE; 71662306a36Sopenharmony_ci qp_attr.sq_sig_type = IB_SIGNAL_REQ_WR; 71762306a36Sopenharmony_ci qp_attr.qp_type = IB_QPT_RC; 71862306a36Sopenharmony_ci qp_attr.send_cq = rdma->cq; 71962306a36Sopenharmony_ci qp_attr.recv_cq = rdma->cq; 72062306a36Sopenharmony_ci err = rdma_create_qp(rdma->cm_id, rdma->pd, &qp_attr); 72162306a36Sopenharmony_ci if (err) 72262306a36Sopenharmony_ci goto error; 72362306a36Sopenharmony_ci rdma->qp = rdma->cm_id->qp; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* Request a connection */ 72662306a36Sopenharmony_ci memset(&conn_param, 0, sizeof(conn_param)); 72762306a36Sopenharmony_ci conn_param.private_data = NULL; 72862306a36Sopenharmony_ci conn_param.private_data_len = 0; 72962306a36Sopenharmony_ci conn_param.responder_resources = P9_RDMA_IRD; 73062306a36Sopenharmony_ci conn_param.initiator_depth = P9_RDMA_ORD; 73162306a36Sopenharmony_ci err = rdma_connect(rdma->cm_id, &conn_param); 73262306a36Sopenharmony_ci if (err) 73362306a36Sopenharmony_ci goto error; 73462306a36Sopenharmony_ci err = wait_for_completion_interruptible(&rdma->cm_done); 73562306a36Sopenharmony_ci if (err || (rdma->state != P9_RDMA_CONNECTED)) 73662306a36Sopenharmony_ci goto error; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci client->status = Connected; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci return 0; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_cierror: 74362306a36Sopenharmony_ci rdma_destroy_trans(rdma); 74462306a36Sopenharmony_ci return -ENOTCONN; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic struct p9_trans_module p9_rdma_trans = { 74862306a36Sopenharmony_ci .name = "rdma", 74962306a36Sopenharmony_ci .maxsize = P9_RDMA_MAXSIZE, 75062306a36Sopenharmony_ci .pooled_rbuffers = true, 75162306a36Sopenharmony_ci .def = 0, 75262306a36Sopenharmony_ci .owner = THIS_MODULE, 75362306a36Sopenharmony_ci .create = rdma_create_trans, 75462306a36Sopenharmony_ci .close = rdma_close, 75562306a36Sopenharmony_ci .request = rdma_request, 75662306a36Sopenharmony_ci .cancel = rdma_cancel, 75762306a36Sopenharmony_ci .cancelled = rdma_cancelled, 75862306a36Sopenharmony_ci .show_options = p9_rdma_show_options, 75962306a36Sopenharmony_ci}; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci/** 76262306a36Sopenharmony_ci * p9_trans_rdma_init - Register the 9P RDMA transport driver 76362306a36Sopenharmony_ci */ 76462306a36Sopenharmony_cistatic int __init p9_trans_rdma_init(void) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci v9fs_register_trans(&p9_rdma_trans); 76762306a36Sopenharmony_ci return 0; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic void __exit p9_trans_rdma_exit(void) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci v9fs_unregister_trans(&p9_rdma_trans); 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cimodule_init(p9_trans_rdma_init); 77662306a36Sopenharmony_cimodule_exit(p9_trans_rdma_exit); 77762306a36Sopenharmony_ciMODULE_ALIAS_9P("rdma"); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ciMODULE_AUTHOR("Tom Tucker <tom@opengridcomputing.com>"); 78062306a36Sopenharmony_ciMODULE_DESCRIPTION("RDMA Transport for 9P"); 78162306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 782