162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2014-2017 Oracle.  All rights reserved.
462306a36Sopenharmony_ci * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This software is available to you under a choice of one of two
762306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the BSD-type
1062306a36Sopenharmony_ci * license below:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
1362306a36Sopenharmony_ci * modification, are permitted provided that the following conditions
1462306a36Sopenharmony_ci * are met:
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *      Redistributions of source code must retain the above copyright
1762306a36Sopenharmony_ci *      notice, this list of conditions and the following disclaimer.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *      Redistributions in binary form must reproduce the above
2062306a36Sopenharmony_ci *      copyright notice, this list of conditions and the following
2162306a36Sopenharmony_ci *      disclaimer in the documentation and/or other materials provided
2262306a36Sopenharmony_ci *      with the distribution.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci *      Neither the name of the Network Appliance, Inc. nor the names of
2562306a36Sopenharmony_ci *      its contributors may be used to endorse or promote products
2662306a36Sopenharmony_ci *      derived from this software without specific prior written
2762306a36Sopenharmony_ci *      permission.
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3062306a36Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3162306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3262306a36Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3362306a36Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3462306a36Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3562306a36Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3662306a36Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3762306a36Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3862306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3962306a36Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/*
4362306a36Sopenharmony_ci * transport.c
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * This file contains the top-level implementation of an RPC RDMA
4662306a36Sopenharmony_ci * transport.
4762306a36Sopenharmony_ci *
4862306a36Sopenharmony_ci * Naming convention: functions beginning with xprt_ are part of the
4962306a36Sopenharmony_ci * transport switch. All others are RPC RDMA internal.
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#include <linux/module.h>
5362306a36Sopenharmony_ci#include <linux/slab.h>
5462306a36Sopenharmony_ci#include <linux/seq_file.h>
5562306a36Sopenharmony_ci#include <linux/smp.h>
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#include <linux/sunrpc/addr.h>
5862306a36Sopenharmony_ci#include <linux/sunrpc/svc_rdma.h>
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#include "xprt_rdma.h"
6162306a36Sopenharmony_ci#include <trace/events/rpcrdma.h>
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * tunables
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic unsigned int xprt_rdma_slot_table_entries = RPCRDMA_DEF_SLOT_TABLE;
6862306a36Sopenharmony_ciunsigned int xprt_rdma_max_inline_read = RPCRDMA_DEF_INLINE;
6962306a36Sopenharmony_ciunsigned int xprt_rdma_max_inline_write = RPCRDMA_DEF_INLINE;
7062306a36Sopenharmony_ciunsigned int xprt_rdma_memreg_strategy		= RPCRDMA_FRWR;
7162306a36Sopenharmony_ciint xprt_rdma_pad_optimize;
7262306a36Sopenharmony_cistatic struct xprt_class xprt_rdma;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic unsigned int min_slot_table_size = RPCRDMA_MIN_SLOT_TABLE;
7762306a36Sopenharmony_cistatic unsigned int max_slot_table_size = RPCRDMA_MAX_SLOT_TABLE;
7862306a36Sopenharmony_cistatic unsigned int min_inline_size = RPCRDMA_MIN_INLINE;
7962306a36Sopenharmony_cistatic unsigned int max_inline_size = RPCRDMA_MAX_INLINE;
8062306a36Sopenharmony_cistatic unsigned int max_padding = PAGE_SIZE;
8162306a36Sopenharmony_cistatic unsigned int min_memreg = RPCRDMA_BOUNCEBUFFERS;
8262306a36Sopenharmony_cistatic unsigned int max_memreg = RPCRDMA_LAST - 1;
8362306a36Sopenharmony_cistatic unsigned int dummy;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic struct ctl_table_header *sunrpc_table_header;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic struct ctl_table xr_tunables_table[] = {
8862306a36Sopenharmony_ci	{
8962306a36Sopenharmony_ci		.procname	= "rdma_slot_table_entries",
9062306a36Sopenharmony_ci		.data		= &xprt_rdma_slot_table_entries,
9162306a36Sopenharmony_ci		.maxlen		= sizeof(unsigned int),
9262306a36Sopenharmony_ci		.mode		= 0644,
9362306a36Sopenharmony_ci		.proc_handler	= proc_dointvec_minmax,
9462306a36Sopenharmony_ci		.extra1		= &min_slot_table_size,
9562306a36Sopenharmony_ci		.extra2		= &max_slot_table_size
9662306a36Sopenharmony_ci	},
9762306a36Sopenharmony_ci	{
9862306a36Sopenharmony_ci		.procname	= "rdma_max_inline_read",
9962306a36Sopenharmony_ci		.data		= &xprt_rdma_max_inline_read,
10062306a36Sopenharmony_ci		.maxlen		= sizeof(unsigned int),
10162306a36Sopenharmony_ci		.mode		= 0644,
10262306a36Sopenharmony_ci		.proc_handler	= proc_dointvec_minmax,
10362306a36Sopenharmony_ci		.extra1		= &min_inline_size,
10462306a36Sopenharmony_ci		.extra2		= &max_inline_size,
10562306a36Sopenharmony_ci	},
10662306a36Sopenharmony_ci	{
10762306a36Sopenharmony_ci		.procname	= "rdma_max_inline_write",
10862306a36Sopenharmony_ci		.data		= &xprt_rdma_max_inline_write,
10962306a36Sopenharmony_ci		.maxlen		= sizeof(unsigned int),
11062306a36Sopenharmony_ci		.mode		= 0644,
11162306a36Sopenharmony_ci		.proc_handler	= proc_dointvec_minmax,
11262306a36Sopenharmony_ci		.extra1		= &min_inline_size,
11362306a36Sopenharmony_ci		.extra2		= &max_inline_size,
11462306a36Sopenharmony_ci	},
11562306a36Sopenharmony_ci	{
11662306a36Sopenharmony_ci		.procname	= "rdma_inline_write_padding",
11762306a36Sopenharmony_ci		.data		= &dummy,
11862306a36Sopenharmony_ci		.maxlen		= sizeof(unsigned int),
11962306a36Sopenharmony_ci		.mode		= 0644,
12062306a36Sopenharmony_ci		.proc_handler	= proc_dointvec_minmax,
12162306a36Sopenharmony_ci		.extra1		= SYSCTL_ZERO,
12262306a36Sopenharmony_ci		.extra2		= &max_padding,
12362306a36Sopenharmony_ci	},
12462306a36Sopenharmony_ci	{
12562306a36Sopenharmony_ci		.procname	= "rdma_memreg_strategy",
12662306a36Sopenharmony_ci		.data		= &xprt_rdma_memreg_strategy,
12762306a36Sopenharmony_ci		.maxlen		= sizeof(unsigned int),
12862306a36Sopenharmony_ci		.mode		= 0644,
12962306a36Sopenharmony_ci		.proc_handler	= proc_dointvec_minmax,
13062306a36Sopenharmony_ci		.extra1		= &min_memreg,
13162306a36Sopenharmony_ci		.extra2		= &max_memreg,
13262306a36Sopenharmony_ci	},
13362306a36Sopenharmony_ci	{
13462306a36Sopenharmony_ci		.procname	= "rdma_pad_optimize",
13562306a36Sopenharmony_ci		.data		= &xprt_rdma_pad_optimize,
13662306a36Sopenharmony_ci		.maxlen		= sizeof(unsigned int),
13762306a36Sopenharmony_ci		.mode		= 0644,
13862306a36Sopenharmony_ci		.proc_handler	= proc_dointvec,
13962306a36Sopenharmony_ci	},
14062306a36Sopenharmony_ci	{ },
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#endif
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic const struct rpc_xprt_ops xprt_rdma_procs;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic void
14862306a36Sopenharmony_cixprt_rdma_format_addresses4(struct rpc_xprt *xprt, struct sockaddr *sap)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct sockaddr_in *sin = (struct sockaddr_in *)sap;
15162306a36Sopenharmony_ci	char buf[20];
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "%08x", ntohl(sin->sin_addr.s_addr));
15462306a36Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_NETID] = RPCBIND_NETID_RDMA;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic void
16062306a36Sopenharmony_cixprt_rdma_format_addresses6(struct rpc_xprt *xprt, struct sockaddr *sap)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
16362306a36Sopenharmony_ci	char buf[40];
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "%pi6", &sin6->sin6_addr);
16662306a36Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_NETID] = RPCBIND_NETID_RDMA6;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_civoid
17262306a36Sopenharmony_cixprt_rdma_format_addresses(struct rpc_xprt *xprt, struct sockaddr *sap)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	char buf[128];
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	switch (sap->sa_family) {
17762306a36Sopenharmony_ci	case AF_INET:
17862306a36Sopenharmony_ci		xprt_rdma_format_addresses4(xprt, sap);
17962306a36Sopenharmony_ci		break;
18062306a36Sopenharmony_ci	case AF_INET6:
18162306a36Sopenharmony_ci		xprt_rdma_format_addresses6(xprt, sap);
18262306a36Sopenharmony_ci		break;
18362306a36Sopenharmony_ci	default:
18462306a36Sopenharmony_ci		pr_err("rpcrdma: Unrecognized address family\n");
18562306a36Sopenharmony_ci		return;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	(void)rpc_ntop(sap, buf, sizeof(buf));
18962306a36Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_ADDR] = kstrdup(buf, GFP_KERNEL);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "%u", rpc_get_port(sap));
19262306a36Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_PORT] = kstrdup(buf, GFP_KERNEL);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "%4hx", rpc_get_port(sap));
19562306a36Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_HEX_PORT] = kstrdup(buf, GFP_KERNEL);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_PROTO] = "rdma";
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_civoid
20162306a36Sopenharmony_cixprt_rdma_free_addresses(struct rpc_xprt *xprt)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	unsigned int i;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	for (i = 0; i < RPC_DISPLAY_MAX; i++)
20662306a36Sopenharmony_ci		switch (i) {
20762306a36Sopenharmony_ci		case RPC_DISPLAY_PROTO:
20862306a36Sopenharmony_ci		case RPC_DISPLAY_NETID:
20962306a36Sopenharmony_ci			continue;
21062306a36Sopenharmony_ci		default:
21162306a36Sopenharmony_ci			kfree(xprt->address_strings[i]);
21262306a36Sopenharmony_ci		}
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci/**
21662306a36Sopenharmony_ci * xprt_rdma_connect_worker - establish connection in the background
21762306a36Sopenharmony_ci * @work: worker thread context
21862306a36Sopenharmony_ci *
21962306a36Sopenharmony_ci * Requester holds the xprt's send lock to prevent activity on this
22062306a36Sopenharmony_ci * transport while a fresh connection is being established. RPC tasks
22162306a36Sopenharmony_ci * sleep on the xprt's pending queue waiting for connect to complete.
22262306a36Sopenharmony_ci */
22362306a36Sopenharmony_cistatic void
22462306a36Sopenharmony_cixprt_rdma_connect_worker(struct work_struct *work)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt = container_of(work, struct rpcrdma_xprt,
22762306a36Sopenharmony_ci						   rx_connect_worker.work);
22862306a36Sopenharmony_ci	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
22962306a36Sopenharmony_ci	unsigned int pflags = current->flags;
23062306a36Sopenharmony_ci	int rc;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (atomic_read(&xprt->swapper))
23362306a36Sopenharmony_ci		current->flags |= PF_MEMALLOC;
23462306a36Sopenharmony_ci	rc = rpcrdma_xprt_connect(r_xprt);
23562306a36Sopenharmony_ci	xprt_clear_connecting(xprt);
23662306a36Sopenharmony_ci	if (!rc) {
23762306a36Sopenharmony_ci		xprt->connect_cookie++;
23862306a36Sopenharmony_ci		xprt->stat.connect_count++;
23962306a36Sopenharmony_ci		xprt->stat.connect_time += (long)jiffies -
24062306a36Sopenharmony_ci					   xprt->stat.connect_start;
24162306a36Sopenharmony_ci		xprt_set_connected(xprt);
24262306a36Sopenharmony_ci		rc = -EAGAIN;
24362306a36Sopenharmony_ci	} else
24462306a36Sopenharmony_ci		rpcrdma_xprt_disconnect(r_xprt);
24562306a36Sopenharmony_ci	xprt_unlock_connect(xprt, r_xprt);
24662306a36Sopenharmony_ci	xprt_wake_pending_tasks(xprt, rc);
24762306a36Sopenharmony_ci	current_restore_flags(pflags, PF_MEMALLOC);
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci/**
25162306a36Sopenharmony_ci * xprt_rdma_inject_disconnect - inject a connection fault
25262306a36Sopenharmony_ci * @xprt: transport context
25362306a36Sopenharmony_ci *
25462306a36Sopenharmony_ci * If @xprt is connected, disconnect it to simulate spurious
25562306a36Sopenharmony_ci * connection loss. Caller must hold @xprt's send lock to
25662306a36Sopenharmony_ci * ensure that data structures and hardware resources are
25762306a36Sopenharmony_ci * stable during the rdma_disconnect() call.
25862306a36Sopenharmony_ci */
25962306a36Sopenharmony_cistatic void
26062306a36Sopenharmony_cixprt_rdma_inject_disconnect(struct rpc_xprt *xprt)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	trace_xprtrdma_op_inject_dsc(r_xprt);
26562306a36Sopenharmony_ci	rdma_disconnect(r_xprt->rx_ep->re_id);
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/**
26962306a36Sopenharmony_ci * xprt_rdma_destroy - Full tear down of transport
27062306a36Sopenharmony_ci * @xprt: doomed transport context
27162306a36Sopenharmony_ci *
27262306a36Sopenharmony_ci * Caller guarantees there will be no more calls to us with
27362306a36Sopenharmony_ci * this @xprt.
27462306a36Sopenharmony_ci */
27562306a36Sopenharmony_cistatic void
27662306a36Sopenharmony_cixprt_rdma_destroy(struct rpc_xprt *xprt)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	cancel_delayed_work_sync(&r_xprt->rx_connect_worker);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	rpcrdma_xprt_disconnect(r_xprt);
28362306a36Sopenharmony_ci	rpcrdma_buffer_destroy(&r_xprt->rx_buf);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	xprt_rdma_free_addresses(xprt);
28662306a36Sopenharmony_ci	xprt_free(xprt);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	module_put(THIS_MODULE);
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/* 60 second timeout, no retries */
29262306a36Sopenharmony_cistatic const struct rpc_timeout xprt_rdma_default_timeout = {
29362306a36Sopenharmony_ci	.to_initval = 60 * HZ,
29462306a36Sopenharmony_ci	.to_maxval = 60 * HZ,
29562306a36Sopenharmony_ci};
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/**
29862306a36Sopenharmony_ci * xprt_setup_rdma - Set up transport to use RDMA
29962306a36Sopenharmony_ci *
30062306a36Sopenharmony_ci * @args: rpc transport arguments
30162306a36Sopenharmony_ci */
30262306a36Sopenharmony_cistatic struct rpc_xprt *
30362306a36Sopenharmony_cixprt_setup_rdma(struct xprt_create *args)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct rpc_xprt *xprt;
30662306a36Sopenharmony_ci	struct rpcrdma_xprt *new_xprt;
30762306a36Sopenharmony_ci	struct sockaddr *sap;
30862306a36Sopenharmony_ci	int rc;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (args->addrlen > sizeof(xprt->addr))
31162306a36Sopenharmony_ci		return ERR_PTR(-EBADF);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	if (!try_module_get(THIS_MODULE))
31462306a36Sopenharmony_ci		return ERR_PTR(-EIO);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	xprt = xprt_alloc(args->net, sizeof(struct rpcrdma_xprt), 0,
31762306a36Sopenharmony_ci			  xprt_rdma_slot_table_entries);
31862306a36Sopenharmony_ci	if (!xprt) {
31962306a36Sopenharmony_ci		module_put(THIS_MODULE);
32062306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	xprt->timeout = &xprt_rdma_default_timeout;
32462306a36Sopenharmony_ci	xprt->connect_timeout = xprt->timeout->to_initval;
32562306a36Sopenharmony_ci	xprt->max_reconnect_timeout = xprt->timeout->to_maxval;
32662306a36Sopenharmony_ci	xprt->bind_timeout = RPCRDMA_BIND_TO;
32762306a36Sopenharmony_ci	xprt->reestablish_timeout = RPCRDMA_INIT_REEST_TO;
32862306a36Sopenharmony_ci	xprt->idle_timeout = RPCRDMA_IDLE_DISC_TO;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	xprt->resvport = 0;		/* privileged port not needed */
33162306a36Sopenharmony_ci	xprt->ops = &xprt_rdma_procs;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/*
33462306a36Sopenharmony_ci	 * Set up RDMA-specific connect data.
33562306a36Sopenharmony_ci	 */
33662306a36Sopenharmony_ci	sap = args->dstaddr;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/* Ensure xprt->addr holds valid server TCP (not RDMA)
33962306a36Sopenharmony_ci	 * address, for any side protocols which peek at it */
34062306a36Sopenharmony_ci	xprt->prot = IPPROTO_TCP;
34162306a36Sopenharmony_ci	xprt->xprt_class = &xprt_rdma;
34262306a36Sopenharmony_ci	xprt->addrlen = args->addrlen;
34362306a36Sopenharmony_ci	memcpy(&xprt->addr, sap, xprt->addrlen);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (rpc_get_port(sap))
34662306a36Sopenharmony_ci		xprt_set_bound(xprt);
34762306a36Sopenharmony_ci	xprt_rdma_format_addresses(xprt, sap);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	new_xprt = rpcx_to_rdmax(xprt);
35062306a36Sopenharmony_ci	rc = rpcrdma_buffer_create(new_xprt);
35162306a36Sopenharmony_ci	if (rc) {
35262306a36Sopenharmony_ci		xprt_rdma_free_addresses(xprt);
35362306a36Sopenharmony_ci		xprt_free(xprt);
35462306a36Sopenharmony_ci		module_put(THIS_MODULE);
35562306a36Sopenharmony_ci		return ERR_PTR(rc);
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	INIT_DELAYED_WORK(&new_xprt->rx_connect_worker,
35962306a36Sopenharmony_ci			  xprt_rdma_connect_worker);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	xprt->max_payload = RPCRDMA_MAX_DATA_SEGS << PAGE_SHIFT;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	return xprt;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci/**
36762306a36Sopenharmony_ci * xprt_rdma_close - close a transport connection
36862306a36Sopenharmony_ci * @xprt: transport context
36962306a36Sopenharmony_ci *
37062306a36Sopenharmony_ci * Called during autoclose or device removal.
37162306a36Sopenharmony_ci *
37262306a36Sopenharmony_ci * Caller holds @xprt's send lock to prevent activity on this
37362306a36Sopenharmony_ci * transport while the connection is torn down.
37462306a36Sopenharmony_ci */
37562306a36Sopenharmony_civoid xprt_rdma_close(struct rpc_xprt *xprt)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	rpcrdma_xprt_disconnect(r_xprt);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	xprt->reestablish_timeout = 0;
38262306a36Sopenharmony_ci	++xprt->connect_cookie;
38362306a36Sopenharmony_ci	xprt_disconnect_done(xprt);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci/**
38762306a36Sopenharmony_ci * xprt_rdma_set_port - update server port with rpcbind result
38862306a36Sopenharmony_ci * @xprt: controlling RPC transport
38962306a36Sopenharmony_ci * @port: new port value
39062306a36Sopenharmony_ci *
39162306a36Sopenharmony_ci * Transport connect status is unchanged.
39262306a36Sopenharmony_ci */
39362306a36Sopenharmony_cistatic void
39462306a36Sopenharmony_cixprt_rdma_set_port(struct rpc_xprt *xprt, u16 port)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	struct sockaddr *sap = (struct sockaddr *)&xprt->addr;
39762306a36Sopenharmony_ci	char buf[8];
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	rpc_set_port(sap, port);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	kfree(xprt->address_strings[RPC_DISPLAY_PORT]);
40262306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "%u", port);
40362306a36Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_PORT] = kstrdup(buf, GFP_KERNEL);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	kfree(xprt->address_strings[RPC_DISPLAY_HEX_PORT]);
40662306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "%4hx", port);
40762306a36Sopenharmony_ci	xprt->address_strings[RPC_DISPLAY_HEX_PORT] = kstrdup(buf, GFP_KERNEL);
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci/**
41162306a36Sopenharmony_ci * xprt_rdma_timer - invoked when an RPC times out
41262306a36Sopenharmony_ci * @xprt: controlling RPC transport
41362306a36Sopenharmony_ci * @task: RPC task that timed out
41462306a36Sopenharmony_ci *
41562306a36Sopenharmony_ci * Invoked when the transport is still connected, but an RPC
41662306a36Sopenharmony_ci * retransmit timeout occurs.
41762306a36Sopenharmony_ci *
41862306a36Sopenharmony_ci * Since RDMA connections don't have a keep-alive, forcibly
41962306a36Sopenharmony_ci * disconnect and retry to connect. This drives full
42062306a36Sopenharmony_ci * detection of the network path, and retransmissions of
42162306a36Sopenharmony_ci * all pending RPCs.
42262306a36Sopenharmony_ci */
42362306a36Sopenharmony_cistatic void
42462306a36Sopenharmony_cixprt_rdma_timer(struct rpc_xprt *xprt, struct rpc_task *task)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	xprt_force_disconnect(xprt);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci/**
43062306a36Sopenharmony_ci * xprt_rdma_set_connect_timeout - set timeouts for establishing a connection
43162306a36Sopenharmony_ci * @xprt: controlling transport instance
43262306a36Sopenharmony_ci * @connect_timeout: reconnect timeout after client disconnects
43362306a36Sopenharmony_ci * @reconnect_timeout: reconnect timeout after server disconnects
43462306a36Sopenharmony_ci *
43562306a36Sopenharmony_ci */
43662306a36Sopenharmony_cistatic void xprt_rdma_set_connect_timeout(struct rpc_xprt *xprt,
43762306a36Sopenharmony_ci					  unsigned long connect_timeout,
43862306a36Sopenharmony_ci					  unsigned long reconnect_timeout)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	trace_xprtrdma_op_set_cto(r_xprt, connect_timeout, reconnect_timeout);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	if (connect_timeout < xprt->connect_timeout) {
44762306a36Sopenharmony_ci		struct rpc_timeout to;
44862306a36Sopenharmony_ci		unsigned long initval;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci		to = *xprt->timeout;
45162306a36Sopenharmony_ci		initval = connect_timeout;
45262306a36Sopenharmony_ci		if (initval < RPCRDMA_INIT_REEST_TO << 1)
45362306a36Sopenharmony_ci			initval = RPCRDMA_INIT_REEST_TO << 1;
45462306a36Sopenharmony_ci		to.to_initval = initval;
45562306a36Sopenharmony_ci		to.to_maxval = initval;
45662306a36Sopenharmony_ci		r_xprt->rx_timeout = to;
45762306a36Sopenharmony_ci		xprt->timeout = &r_xprt->rx_timeout;
45862306a36Sopenharmony_ci		xprt->connect_timeout = connect_timeout;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (reconnect_timeout < xprt->max_reconnect_timeout)
46262306a36Sopenharmony_ci		xprt->max_reconnect_timeout = reconnect_timeout;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci/**
46862306a36Sopenharmony_ci * xprt_rdma_connect - schedule an attempt to reconnect
46962306a36Sopenharmony_ci * @xprt: transport state
47062306a36Sopenharmony_ci * @task: RPC scheduler context (unused)
47162306a36Sopenharmony_ci *
47262306a36Sopenharmony_ci */
47362306a36Sopenharmony_cistatic void
47462306a36Sopenharmony_cixprt_rdma_connect(struct rpc_xprt *xprt, struct rpc_task *task)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
47762306a36Sopenharmony_ci	struct rpcrdma_ep *ep = r_xprt->rx_ep;
47862306a36Sopenharmony_ci	unsigned long delay;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	WARN_ON_ONCE(!xprt_lock_connect(xprt, task, r_xprt));
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	delay = 0;
48362306a36Sopenharmony_ci	if (ep && ep->re_connect_status != 0) {
48462306a36Sopenharmony_ci		delay = xprt_reconnect_delay(xprt);
48562306a36Sopenharmony_ci		xprt_reconnect_backoff(xprt, RPCRDMA_INIT_REEST_TO);
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci	trace_xprtrdma_op_connect(r_xprt, delay);
48862306a36Sopenharmony_ci	queue_delayed_work(system_long_wq, &r_xprt->rx_connect_worker, delay);
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci/**
49262306a36Sopenharmony_ci * xprt_rdma_alloc_slot - allocate an rpc_rqst
49362306a36Sopenharmony_ci * @xprt: controlling RPC transport
49462306a36Sopenharmony_ci * @task: RPC task requesting a fresh rpc_rqst
49562306a36Sopenharmony_ci *
49662306a36Sopenharmony_ci * tk_status values:
49762306a36Sopenharmony_ci *	%0 if task->tk_rqstp points to a fresh rpc_rqst
49862306a36Sopenharmony_ci *	%-EAGAIN if no rpc_rqst is available; queued on backlog
49962306a36Sopenharmony_ci */
50062306a36Sopenharmony_cistatic void
50162306a36Sopenharmony_cixprt_rdma_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
50462306a36Sopenharmony_ci	struct rpcrdma_req *req;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	req = rpcrdma_buffer_get(&r_xprt->rx_buf);
50762306a36Sopenharmony_ci	if (!req)
50862306a36Sopenharmony_ci		goto out_sleep;
50962306a36Sopenharmony_ci	task->tk_rqstp = &req->rl_slot;
51062306a36Sopenharmony_ci	task->tk_status = 0;
51162306a36Sopenharmony_ci	return;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ciout_sleep:
51462306a36Sopenharmony_ci	task->tk_status = -ENOMEM;
51562306a36Sopenharmony_ci	xprt_add_backlog(xprt, task);
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci/**
51962306a36Sopenharmony_ci * xprt_rdma_free_slot - release an rpc_rqst
52062306a36Sopenharmony_ci * @xprt: controlling RPC transport
52162306a36Sopenharmony_ci * @rqst: rpc_rqst to release
52262306a36Sopenharmony_ci *
52362306a36Sopenharmony_ci */
52462306a36Sopenharmony_cistatic void
52562306a36Sopenharmony_cixprt_rdma_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *rqst)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt =
52862306a36Sopenharmony_ci		container_of(xprt, struct rpcrdma_xprt, rx_xprt);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	rpcrdma_reply_put(&r_xprt->rx_buf, rpcr_to_rdmar(rqst));
53162306a36Sopenharmony_ci	if (!xprt_wake_up_backlog(xprt, rqst)) {
53262306a36Sopenharmony_ci		memset(rqst, 0, sizeof(*rqst));
53362306a36Sopenharmony_ci		rpcrdma_buffer_put(&r_xprt->rx_buf, rpcr_to_rdmar(rqst));
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic bool rpcrdma_check_regbuf(struct rpcrdma_xprt *r_xprt,
53862306a36Sopenharmony_ci				 struct rpcrdma_regbuf *rb, size_t size,
53962306a36Sopenharmony_ci				 gfp_t flags)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	if (unlikely(rdmab_length(rb) < size)) {
54262306a36Sopenharmony_ci		if (!rpcrdma_regbuf_realloc(rb, size, flags))
54362306a36Sopenharmony_ci			return false;
54462306a36Sopenharmony_ci		r_xprt->rx_stats.hardway_register_count += size;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci	return true;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci/**
55062306a36Sopenharmony_ci * xprt_rdma_allocate - allocate transport resources for an RPC
55162306a36Sopenharmony_ci * @task: RPC task
55262306a36Sopenharmony_ci *
55362306a36Sopenharmony_ci * Return values:
55462306a36Sopenharmony_ci *        0:	Success; rq_buffer points to RPC buffer to use
55562306a36Sopenharmony_ci *   ENOMEM:	Out of memory, call again later
55662306a36Sopenharmony_ci *      EIO:	A permanent error occurred, do not retry
55762306a36Sopenharmony_ci */
55862306a36Sopenharmony_cistatic int
55962306a36Sopenharmony_cixprt_rdma_allocate(struct rpc_task *task)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	struct rpc_rqst *rqst = task->tk_rqstp;
56262306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt);
56362306a36Sopenharmony_ci	struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
56462306a36Sopenharmony_ci	gfp_t flags = rpc_task_gfp_mask();
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	if (!rpcrdma_check_regbuf(r_xprt, req->rl_sendbuf, rqst->rq_callsize,
56762306a36Sopenharmony_ci				  flags))
56862306a36Sopenharmony_ci		goto out_fail;
56962306a36Sopenharmony_ci	if (!rpcrdma_check_regbuf(r_xprt, req->rl_recvbuf, rqst->rq_rcvsize,
57062306a36Sopenharmony_ci				  flags))
57162306a36Sopenharmony_ci		goto out_fail;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	rqst->rq_buffer = rdmab_data(req->rl_sendbuf);
57462306a36Sopenharmony_ci	rqst->rq_rbuffer = rdmab_data(req->rl_recvbuf);
57562306a36Sopenharmony_ci	return 0;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ciout_fail:
57862306a36Sopenharmony_ci	return -ENOMEM;
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci/**
58262306a36Sopenharmony_ci * xprt_rdma_free - release resources allocated by xprt_rdma_allocate
58362306a36Sopenharmony_ci * @task: RPC task
58462306a36Sopenharmony_ci *
58562306a36Sopenharmony_ci * Caller guarantees rqst->rq_buffer is non-NULL.
58662306a36Sopenharmony_ci */
58762306a36Sopenharmony_cistatic void
58862306a36Sopenharmony_cixprt_rdma_free(struct rpc_task *task)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct rpc_rqst *rqst = task->tk_rqstp;
59162306a36Sopenharmony_ci	struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (unlikely(!list_empty(&req->rl_registered))) {
59462306a36Sopenharmony_ci		trace_xprtrdma_mrs_zap(task);
59562306a36Sopenharmony_ci		frwr_unmap_sync(rpcx_to_rdmax(rqst->rq_xprt), req);
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	/* XXX: If the RPC is completing because of a signal and
59962306a36Sopenharmony_ci	 * not because a reply was received, we ought to ensure
60062306a36Sopenharmony_ci	 * that the Send completion has fired, so that memory
60162306a36Sopenharmony_ci	 * involved with the Send is not still visible to the NIC.
60262306a36Sopenharmony_ci	 */
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci/**
60662306a36Sopenharmony_ci * xprt_rdma_send_request - marshal and send an RPC request
60762306a36Sopenharmony_ci * @rqst: RPC message in rq_snd_buf
60862306a36Sopenharmony_ci *
60962306a36Sopenharmony_ci * Caller holds the transport's write lock.
61062306a36Sopenharmony_ci *
61162306a36Sopenharmony_ci * Returns:
61262306a36Sopenharmony_ci *	%0 if the RPC message has been sent
61362306a36Sopenharmony_ci *	%-ENOTCONN if the caller should reconnect and call again
61462306a36Sopenharmony_ci *	%-EAGAIN if the caller should call again
61562306a36Sopenharmony_ci *	%-ENOBUFS if the caller should call again after a delay
61662306a36Sopenharmony_ci *	%-EMSGSIZE if encoding ran out of buffer space. The request
61762306a36Sopenharmony_ci *		was not sent. Do not try to send this message again.
61862306a36Sopenharmony_ci *	%-EIO if an I/O error occurred. The request was not sent.
61962306a36Sopenharmony_ci *		Do not try to send this message again.
62062306a36Sopenharmony_ci */
62162306a36Sopenharmony_cistatic int
62262306a36Sopenharmony_cixprt_rdma_send_request(struct rpc_rqst *rqst)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	struct rpc_xprt *xprt = rqst->rq_xprt;
62562306a36Sopenharmony_ci	struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
62662306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
62762306a36Sopenharmony_ci	int rc = 0;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci#if defined(CONFIG_SUNRPC_BACKCHANNEL)
63062306a36Sopenharmony_ci	if (unlikely(!rqst->rq_buffer))
63162306a36Sopenharmony_ci		return xprt_rdma_bc_send_reply(rqst);
63262306a36Sopenharmony_ci#endif	/* CONFIG_SUNRPC_BACKCHANNEL */
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	if (!xprt_connected(xprt))
63562306a36Sopenharmony_ci		return -ENOTCONN;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	if (!xprt_request_get_cong(xprt, rqst))
63862306a36Sopenharmony_ci		return -EBADSLT;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	rc = rpcrdma_marshal_req(r_xprt, rqst);
64162306a36Sopenharmony_ci	if (rc < 0)
64262306a36Sopenharmony_ci		goto failed_marshal;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	/* Must suppress retransmit to maintain credits */
64562306a36Sopenharmony_ci	if (rqst->rq_connect_cookie == xprt->connect_cookie)
64662306a36Sopenharmony_ci		goto drop_connection;
64762306a36Sopenharmony_ci	rqst->rq_xtime = ktime_get();
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (frwr_send(r_xprt, req))
65062306a36Sopenharmony_ci		goto drop_connection;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	rqst->rq_xmit_bytes_sent += rqst->rq_snd_buf.len;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	/* An RPC with no reply will throw off credit accounting,
65562306a36Sopenharmony_ci	 * so drop the connection to reset the credit grant.
65662306a36Sopenharmony_ci	 */
65762306a36Sopenharmony_ci	if (!rpc_reply_expected(rqst->rq_task))
65862306a36Sopenharmony_ci		goto drop_connection;
65962306a36Sopenharmony_ci	return 0;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cifailed_marshal:
66262306a36Sopenharmony_ci	if (rc != -ENOTCONN)
66362306a36Sopenharmony_ci		return rc;
66462306a36Sopenharmony_cidrop_connection:
66562306a36Sopenharmony_ci	xprt_rdma_close(xprt);
66662306a36Sopenharmony_ci	return -ENOTCONN;
66762306a36Sopenharmony_ci}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_civoid xprt_rdma_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
67262306a36Sopenharmony_ci	long idle_time = 0;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if (xprt_connected(xprt))
67562306a36Sopenharmony_ci		idle_time = (long)(jiffies - xprt->last_used) / HZ;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	seq_puts(seq, "\txprt:\trdma ");
67862306a36Sopenharmony_ci	seq_printf(seq, "%u %lu %lu %lu %ld %lu %lu %lu %llu %llu ",
67962306a36Sopenharmony_ci		   0,	/* need a local port? */
68062306a36Sopenharmony_ci		   xprt->stat.bind_count,
68162306a36Sopenharmony_ci		   xprt->stat.connect_count,
68262306a36Sopenharmony_ci		   xprt->stat.connect_time / HZ,
68362306a36Sopenharmony_ci		   idle_time,
68462306a36Sopenharmony_ci		   xprt->stat.sends,
68562306a36Sopenharmony_ci		   xprt->stat.recvs,
68662306a36Sopenharmony_ci		   xprt->stat.bad_xids,
68762306a36Sopenharmony_ci		   xprt->stat.req_u,
68862306a36Sopenharmony_ci		   xprt->stat.bklog_u);
68962306a36Sopenharmony_ci	seq_printf(seq, "%lu %lu %lu %llu %llu %llu %llu %lu %lu %lu %lu ",
69062306a36Sopenharmony_ci		   r_xprt->rx_stats.read_chunk_count,
69162306a36Sopenharmony_ci		   r_xprt->rx_stats.write_chunk_count,
69262306a36Sopenharmony_ci		   r_xprt->rx_stats.reply_chunk_count,
69362306a36Sopenharmony_ci		   r_xprt->rx_stats.total_rdma_request,
69462306a36Sopenharmony_ci		   r_xprt->rx_stats.total_rdma_reply,
69562306a36Sopenharmony_ci		   r_xprt->rx_stats.pullup_copy_count,
69662306a36Sopenharmony_ci		   r_xprt->rx_stats.fixup_copy_count,
69762306a36Sopenharmony_ci		   r_xprt->rx_stats.hardway_register_count,
69862306a36Sopenharmony_ci		   r_xprt->rx_stats.failed_marshal_count,
69962306a36Sopenharmony_ci		   r_xprt->rx_stats.bad_reply_count,
70062306a36Sopenharmony_ci		   r_xprt->rx_stats.nomsg_call_count);
70162306a36Sopenharmony_ci	seq_printf(seq, "%lu %lu %lu %lu %lu %lu\n",
70262306a36Sopenharmony_ci		   r_xprt->rx_stats.mrs_recycled,
70362306a36Sopenharmony_ci		   r_xprt->rx_stats.mrs_orphaned,
70462306a36Sopenharmony_ci		   r_xprt->rx_stats.mrs_allocated,
70562306a36Sopenharmony_ci		   r_xprt->rx_stats.local_inv_needed,
70662306a36Sopenharmony_ci		   r_xprt->rx_stats.empty_sendctx_q,
70762306a36Sopenharmony_ci		   r_xprt->rx_stats.reply_waits_for_send);
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_cistatic int
71162306a36Sopenharmony_cixprt_rdma_enable_swap(struct rpc_xprt *xprt)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	return 0;
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic void
71762306a36Sopenharmony_cixprt_rdma_disable_swap(struct rpc_xprt *xprt)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci/*
72262306a36Sopenharmony_ci * Plumbing for rpc transport switch and kernel module
72362306a36Sopenharmony_ci */
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_cistatic const struct rpc_xprt_ops xprt_rdma_procs = {
72662306a36Sopenharmony_ci	.reserve_xprt		= xprt_reserve_xprt_cong,
72762306a36Sopenharmony_ci	.release_xprt		= xprt_release_xprt_cong, /* sunrpc/xprt.c */
72862306a36Sopenharmony_ci	.alloc_slot		= xprt_rdma_alloc_slot,
72962306a36Sopenharmony_ci	.free_slot		= xprt_rdma_free_slot,
73062306a36Sopenharmony_ci	.release_request	= xprt_release_rqst_cong,       /* ditto */
73162306a36Sopenharmony_ci	.wait_for_reply_request	= xprt_wait_for_reply_request_def, /* ditto */
73262306a36Sopenharmony_ci	.timer			= xprt_rdma_timer,
73362306a36Sopenharmony_ci	.rpcbind		= rpcb_getport_async,	/* sunrpc/rpcb_clnt.c */
73462306a36Sopenharmony_ci	.set_port		= xprt_rdma_set_port,
73562306a36Sopenharmony_ci	.connect		= xprt_rdma_connect,
73662306a36Sopenharmony_ci	.buf_alloc		= xprt_rdma_allocate,
73762306a36Sopenharmony_ci	.buf_free		= xprt_rdma_free,
73862306a36Sopenharmony_ci	.send_request		= xprt_rdma_send_request,
73962306a36Sopenharmony_ci	.close			= xprt_rdma_close,
74062306a36Sopenharmony_ci	.destroy		= xprt_rdma_destroy,
74162306a36Sopenharmony_ci	.set_connect_timeout	= xprt_rdma_set_connect_timeout,
74262306a36Sopenharmony_ci	.print_stats		= xprt_rdma_print_stats,
74362306a36Sopenharmony_ci	.enable_swap		= xprt_rdma_enable_swap,
74462306a36Sopenharmony_ci	.disable_swap		= xprt_rdma_disable_swap,
74562306a36Sopenharmony_ci	.inject_disconnect	= xprt_rdma_inject_disconnect,
74662306a36Sopenharmony_ci#if defined(CONFIG_SUNRPC_BACKCHANNEL)
74762306a36Sopenharmony_ci	.bc_setup		= xprt_rdma_bc_setup,
74862306a36Sopenharmony_ci	.bc_maxpayload		= xprt_rdma_bc_maxpayload,
74962306a36Sopenharmony_ci	.bc_num_slots		= xprt_rdma_bc_max_slots,
75062306a36Sopenharmony_ci	.bc_free_rqst		= xprt_rdma_bc_free_rqst,
75162306a36Sopenharmony_ci	.bc_destroy		= xprt_rdma_bc_destroy,
75262306a36Sopenharmony_ci#endif
75362306a36Sopenharmony_ci};
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic struct xprt_class xprt_rdma = {
75662306a36Sopenharmony_ci	.list			= LIST_HEAD_INIT(xprt_rdma.list),
75762306a36Sopenharmony_ci	.name			= "rdma",
75862306a36Sopenharmony_ci	.owner			= THIS_MODULE,
75962306a36Sopenharmony_ci	.ident			= XPRT_TRANSPORT_RDMA,
76062306a36Sopenharmony_ci	.setup			= xprt_setup_rdma,
76162306a36Sopenharmony_ci	.netid			= { "rdma", "rdma6", "" },
76262306a36Sopenharmony_ci};
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_civoid xprt_rdma_cleanup(void)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
76762306a36Sopenharmony_ci	if (sunrpc_table_header) {
76862306a36Sopenharmony_ci		unregister_sysctl_table(sunrpc_table_header);
76962306a36Sopenharmony_ci		sunrpc_table_header = NULL;
77062306a36Sopenharmony_ci	}
77162306a36Sopenharmony_ci#endif
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	xprt_unregister_transport(&xprt_rdma);
77462306a36Sopenharmony_ci	xprt_unregister_transport(&xprt_rdma_bc);
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ciint xprt_rdma_init(void)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	int rc;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	rc = xprt_register_transport(&xprt_rdma);
78262306a36Sopenharmony_ci	if (rc)
78362306a36Sopenharmony_ci		return rc;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	rc = xprt_register_transport(&xprt_rdma_bc);
78662306a36Sopenharmony_ci	if (rc) {
78762306a36Sopenharmony_ci		xprt_unregister_transport(&xprt_rdma);
78862306a36Sopenharmony_ci		return rc;
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
79262306a36Sopenharmony_ci	if (!sunrpc_table_header)
79362306a36Sopenharmony_ci		sunrpc_table_header = register_sysctl("sunrpc", xr_tunables_table);
79462306a36Sopenharmony_ci#endif
79562306a36Sopenharmony_ci	return 0;
79662306a36Sopenharmony_ci}
797