162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2014-2020, Oracle and/or its affiliates.
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 * rpc_rdma.c
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * This file contains the guts of the RPC RDMA protocol, and
4662306a36Sopenharmony_ci * does marshaling/unmarshaling, etc. It is also where interfacing
4762306a36Sopenharmony_ci * to the Linux RPC framework lives.
4862306a36Sopenharmony_ci */
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#include <linux/highmem.h>
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#include <linux/sunrpc/svc_rdma.h>
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#include "xprt_rdma.h"
5562306a36Sopenharmony_ci#include <trace/events/rpcrdma.h>
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* Returns size of largest RPC-over-RDMA header in a Call message
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * The largest Call header contains a full-size Read list and a
6062306a36Sopenharmony_ci * minimal Reply chunk.
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_cistatic unsigned int rpcrdma_max_call_header_size(unsigned int maxsegs)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	unsigned int size;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* Fixed header fields and list discriminators */
6762306a36Sopenharmony_ci	size = RPCRDMA_HDRLEN_MIN;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* Maximum Read list size */
7062306a36Sopenharmony_ci	size += maxsegs * rpcrdma_readchunk_maxsz * sizeof(__be32);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* Minimal Read chunk size */
7362306a36Sopenharmony_ci	size += sizeof(__be32);	/* segment count */
7462306a36Sopenharmony_ci	size += rpcrdma_segment_maxsz * sizeof(__be32);
7562306a36Sopenharmony_ci	size += sizeof(__be32);	/* list discriminator */
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return size;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/* Returns size of largest RPC-over-RDMA header in a Reply message
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * There is only one Write list or one Reply chunk per Reply
8362306a36Sopenharmony_ci * message.  The larger list is the Write list.
8462306a36Sopenharmony_ci */
8562306a36Sopenharmony_cistatic unsigned int rpcrdma_max_reply_header_size(unsigned int maxsegs)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	unsigned int size;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* Fixed header fields and list discriminators */
9062306a36Sopenharmony_ci	size = RPCRDMA_HDRLEN_MIN;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	/* Maximum Write list size */
9362306a36Sopenharmony_ci	size += sizeof(__be32);		/* segment count */
9462306a36Sopenharmony_ci	size += maxsegs * rpcrdma_segment_maxsz * sizeof(__be32);
9562306a36Sopenharmony_ci	size += sizeof(__be32);	/* list discriminator */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return size;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/**
10162306a36Sopenharmony_ci * rpcrdma_set_max_header_sizes - Initialize inline payload sizes
10262306a36Sopenharmony_ci * @ep: endpoint to initialize
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci * The max_inline fields contain the maximum size of an RPC message
10562306a36Sopenharmony_ci * so the marshaling code doesn't have to repeat this calculation
10662306a36Sopenharmony_ci * for every RPC.
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_civoid rpcrdma_set_max_header_sizes(struct rpcrdma_ep *ep)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	unsigned int maxsegs = ep->re_max_rdma_segs;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	ep->re_max_inline_send =
11362306a36Sopenharmony_ci		ep->re_inline_send - rpcrdma_max_call_header_size(maxsegs);
11462306a36Sopenharmony_ci	ep->re_max_inline_recv =
11562306a36Sopenharmony_ci		ep->re_inline_recv - rpcrdma_max_reply_header_size(maxsegs);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/* The client can send a request inline as long as the RPCRDMA header
11962306a36Sopenharmony_ci * plus the RPC call fit under the transport's inline limit. If the
12062306a36Sopenharmony_ci * combined call message size exceeds that limit, the client must use
12162306a36Sopenharmony_ci * a Read chunk for this operation.
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci * A Read chunk is also required if sending the RPC call inline would
12462306a36Sopenharmony_ci * exceed this device's max_sge limit.
12562306a36Sopenharmony_ci */
12662306a36Sopenharmony_cistatic bool rpcrdma_args_inline(struct rpcrdma_xprt *r_xprt,
12762306a36Sopenharmony_ci				struct rpc_rqst *rqst)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct xdr_buf *xdr = &rqst->rq_snd_buf;
13062306a36Sopenharmony_ci	struct rpcrdma_ep *ep = r_xprt->rx_ep;
13162306a36Sopenharmony_ci	unsigned int count, remaining, offset;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (xdr->len > ep->re_max_inline_send)
13462306a36Sopenharmony_ci		return false;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (xdr->page_len) {
13762306a36Sopenharmony_ci		remaining = xdr->page_len;
13862306a36Sopenharmony_ci		offset = offset_in_page(xdr->page_base);
13962306a36Sopenharmony_ci		count = RPCRDMA_MIN_SEND_SGES;
14062306a36Sopenharmony_ci		while (remaining) {
14162306a36Sopenharmony_ci			remaining -= min_t(unsigned int,
14262306a36Sopenharmony_ci					   PAGE_SIZE - offset, remaining);
14362306a36Sopenharmony_ci			offset = 0;
14462306a36Sopenharmony_ci			if (++count > ep->re_attr.cap.max_send_sge)
14562306a36Sopenharmony_ci				return false;
14662306a36Sopenharmony_ci		}
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return true;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/* The client can't know how large the actual reply will be. Thus it
15362306a36Sopenharmony_ci * plans for the largest possible reply for that particular ULP
15462306a36Sopenharmony_ci * operation. If the maximum combined reply message size exceeds that
15562306a36Sopenharmony_ci * limit, the client must provide a write list or a reply chunk for
15662306a36Sopenharmony_ci * this request.
15762306a36Sopenharmony_ci */
15862306a36Sopenharmony_cistatic bool rpcrdma_results_inline(struct rpcrdma_xprt *r_xprt,
15962306a36Sopenharmony_ci				   struct rpc_rqst *rqst)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	return rqst->rq_rcv_buf.buflen <= r_xprt->rx_ep->re_max_inline_recv;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/* The client is required to provide a Reply chunk if the maximum
16562306a36Sopenharmony_ci * size of the non-payload part of the RPC Reply is larger than
16662306a36Sopenharmony_ci * the inline threshold.
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_cistatic bool
16962306a36Sopenharmony_cirpcrdma_nonpayload_inline(const struct rpcrdma_xprt *r_xprt,
17062306a36Sopenharmony_ci			  const struct rpc_rqst *rqst)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	const struct xdr_buf *buf = &rqst->rq_rcv_buf;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	return (buf->head[0].iov_len + buf->tail[0].iov_len) <
17562306a36Sopenharmony_ci		r_xprt->rx_ep->re_max_inline_recv;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/* ACL likes to be lazy in allocating pages. For TCP, these
17962306a36Sopenharmony_ci * pages can be allocated during receive processing. Not true
18062306a36Sopenharmony_ci * for RDMA, which must always provision receive buffers
18162306a36Sopenharmony_ci * up front.
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_cistatic noinline int
18462306a36Sopenharmony_cirpcrdma_alloc_sparse_pages(struct xdr_buf *buf)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	struct page **ppages;
18762306a36Sopenharmony_ci	int len;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	len = buf->page_len;
19062306a36Sopenharmony_ci	ppages = buf->pages + (buf->page_base >> PAGE_SHIFT);
19162306a36Sopenharmony_ci	while (len > 0) {
19262306a36Sopenharmony_ci		if (!*ppages)
19362306a36Sopenharmony_ci			*ppages = alloc_page(GFP_NOWAIT | __GFP_NOWARN);
19462306a36Sopenharmony_ci		if (!*ppages)
19562306a36Sopenharmony_ci			return -ENOBUFS;
19662306a36Sopenharmony_ci		ppages++;
19762306a36Sopenharmony_ci		len -= PAGE_SIZE;
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	return 0;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/* Convert @vec to a single SGL element.
20462306a36Sopenharmony_ci *
20562306a36Sopenharmony_ci * Returns pointer to next available SGE, and bumps the total number
20662306a36Sopenharmony_ci * of SGEs consumed.
20762306a36Sopenharmony_ci */
20862306a36Sopenharmony_cistatic struct rpcrdma_mr_seg *
20962306a36Sopenharmony_cirpcrdma_convert_kvec(struct kvec *vec, struct rpcrdma_mr_seg *seg,
21062306a36Sopenharmony_ci		     unsigned int *n)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	seg->mr_page = virt_to_page(vec->iov_base);
21362306a36Sopenharmony_ci	seg->mr_offset = offset_in_page(vec->iov_base);
21462306a36Sopenharmony_ci	seg->mr_len = vec->iov_len;
21562306a36Sopenharmony_ci	++seg;
21662306a36Sopenharmony_ci	++(*n);
21762306a36Sopenharmony_ci	return seg;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci/* Convert @xdrbuf into SGEs no larger than a page each. As they
22162306a36Sopenharmony_ci * are registered, these SGEs are then coalesced into RDMA segments
22262306a36Sopenharmony_ci * when the selected memreg mode supports it.
22362306a36Sopenharmony_ci *
22462306a36Sopenharmony_ci * Returns positive number of SGEs consumed, or a negative errno.
22562306a36Sopenharmony_ci */
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic int
22862306a36Sopenharmony_cirpcrdma_convert_iovs(struct rpcrdma_xprt *r_xprt, struct xdr_buf *xdrbuf,
22962306a36Sopenharmony_ci		     unsigned int pos, enum rpcrdma_chunktype type,
23062306a36Sopenharmony_ci		     struct rpcrdma_mr_seg *seg)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	unsigned long page_base;
23362306a36Sopenharmony_ci	unsigned int len, n;
23462306a36Sopenharmony_ci	struct page **ppages;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	n = 0;
23762306a36Sopenharmony_ci	if (pos == 0)
23862306a36Sopenharmony_ci		seg = rpcrdma_convert_kvec(&xdrbuf->head[0], seg, &n);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	len = xdrbuf->page_len;
24162306a36Sopenharmony_ci	ppages = xdrbuf->pages + (xdrbuf->page_base >> PAGE_SHIFT);
24262306a36Sopenharmony_ci	page_base = offset_in_page(xdrbuf->page_base);
24362306a36Sopenharmony_ci	while (len) {
24462306a36Sopenharmony_ci		seg->mr_page = *ppages;
24562306a36Sopenharmony_ci		seg->mr_offset = page_base;
24662306a36Sopenharmony_ci		seg->mr_len = min_t(u32, PAGE_SIZE - page_base, len);
24762306a36Sopenharmony_ci		len -= seg->mr_len;
24862306a36Sopenharmony_ci		++ppages;
24962306a36Sopenharmony_ci		++seg;
25062306a36Sopenharmony_ci		++n;
25162306a36Sopenharmony_ci		page_base = 0;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (type == rpcrdma_readch || type == rpcrdma_writech)
25562306a36Sopenharmony_ci		goto out;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	if (xdrbuf->tail[0].iov_len)
25862306a36Sopenharmony_ci		rpcrdma_convert_kvec(&xdrbuf->tail[0], seg, &n);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ciout:
26162306a36Sopenharmony_ci	if (unlikely(n > RPCRDMA_MAX_SEGS))
26262306a36Sopenharmony_ci		return -EIO;
26362306a36Sopenharmony_ci	return n;
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic int
26762306a36Sopenharmony_ciencode_rdma_segment(struct xdr_stream *xdr, struct rpcrdma_mr *mr)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	__be32 *p;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 * sizeof(*p));
27262306a36Sopenharmony_ci	if (unlikely(!p))
27362306a36Sopenharmony_ci		return -EMSGSIZE;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	xdr_encode_rdma_segment(p, mr->mr_handle, mr->mr_length, mr->mr_offset);
27662306a36Sopenharmony_ci	return 0;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic int
28062306a36Sopenharmony_ciencode_read_segment(struct xdr_stream *xdr, struct rpcrdma_mr *mr,
28162306a36Sopenharmony_ci		    u32 position)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	__be32 *p;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 6 * sizeof(*p));
28662306a36Sopenharmony_ci	if (unlikely(!p))
28762306a36Sopenharmony_ci		return -EMSGSIZE;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	*p++ = xdr_one;			/* Item present */
29062306a36Sopenharmony_ci	xdr_encode_read_segment(p, position, mr->mr_handle, mr->mr_length,
29162306a36Sopenharmony_ci				mr->mr_offset);
29262306a36Sopenharmony_ci	return 0;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic struct rpcrdma_mr_seg *rpcrdma_mr_prepare(struct rpcrdma_xprt *r_xprt,
29662306a36Sopenharmony_ci						 struct rpcrdma_req *req,
29762306a36Sopenharmony_ci						 struct rpcrdma_mr_seg *seg,
29862306a36Sopenharmony_ci						 int nsegs, bool writing,
29962306a36Sopenharmony_ci						 struct rpcrdma_mr **mr)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	*mr = rpcrdma_mr_pop(&req->rl_free_mrs);
30262306a36Sopenharmony_ci	if (!*mr) {
30362306a36Sopenharmony_ci		*mr = rpcrdma_mr_get(r_xprt);
30462306a36Sopenharmony_ci		if (!*mr)
30562306a36Sopenharmony_ci			goto out_getmr_err;
30662306a36Sopenharmony_ci		(*mr)->mr_req = req;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	rpcrdma_mr_push(*mr, &req->rl_registered);
31062306a36Sopenharmony_ci	return frwr_map(r_xprt, seg, nsegs, writing, req->rl_slot.rq_xid, *mr);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ciout_getmr_err:
31362306a36Sopenharmony_ci	trace_xprtrdma_nomrs_err(r_xprt, req);
31462306a36Sopenharmony_ci	xprt_wait_for_buffer_space(&r_xprt->rx_xprt);
31562306a36Sopenharmony_ci	rpcrdma_mrs_refresh(r_xprt);
31662306a36Sopenharmony_ci	return ERR_PTR(-EAGAIN);
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/* Register and XDR encode the Read list. Supports encoding a list of read
32062306a36Sopenharmony_ci * segments that belong to a single read chunk.
32162306a36Sopenharmony_ci *
32262306a36Sopenharmony_ci * Encoding key for single-list chunks (HLOO = Handle32 Length32 Offset64):
32362306a36Sopenharmony_ci *
32462306a36Sopenharmony_ci *  Read chunklist (a linked list):
32562306a36Sopenharmony_ci *   N elements, position P (same P for all chunks of same arg!):
32662306a36Sopenharmony_ci *    1 - PHLOO - 1 - PHLOO - ... - 1 - PHLOO - 0
32762306a36Sopenharmony_ci *
32862306a36Sopenharmony_ci * Returns zero on success, or a negative errno if a failure occurred.
32962306a36Sopenharmony_ci * @xdr is advanced to the next position in the stream.
33062306a36Sopenharmony_ci *
33162306a36Sopenharmony_ci * Only a single @pos value is currently supported.
33262306a36Sopenharmony_ci */
33362306a36Sopenharmony_cistatic int rpcrdma_encode_read_list(struct rpcrdma_xprt *r_xprt,
33462306a36Sopenharmony_ci				    struct rpcrdma_req *req,
33562306a36Sopenharmony_ci				    struct rpc_rqst *rqst,
33662306a36Sopenharmony_ci				    enum rpcrdma_chunktype rtype)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct xdr_stream *xdr = &req->rl_stream;
33962306a36Sopenharmony_ci	struct rpcrdma_mr_seg *seg;
34062306a36Sopenharmony_ci	struct rpcrdma_mr *mr;
34162306a36Sopenharmony_ci	unsigned int pos;
34262306a36Sopenharmony_ci	int nsegs;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (rtype == rpcrdma_noch_pullup || rtype == rpcrdma_noch_mapped)
34562306a36Sopenharmony_ci		goto done;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	pos = rqst->rq_snd_buf.head[0].iov_len;
34862306a36Sopenharmony_ci	if (rtype == rpcrdma_areadch)
34962306a36Sopenharmony_ci		pos = 0;
35062306a36Sopenharmony_ci	seg = req->rl_segments;
35162306a36Sopenharmony_ci	nsegs = rpcrdma_convert_iovs(r_xprt, &rqst->rq_snd_buf, pos,
35262306a36Sopenharmony_ci				     rtype, seg);
35362306a36Sopenharmony_ci	if (nsegs < 0)
35462306a36Sopenharmony_ci		return nsegs;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	do {
35762306a36Sopenharmony_ci		seg = rpcrdma_mr_prepare(r_xprt, req, seg, nsegs, false, &mr);
35862306a36Sopenharmony_ci		if (IS_ERR(seg))
35962306a36Sopenharmony_ci			return PTR_ERR(seg);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		if (encode_read_segment(xdr, mr, pos) < 0)
36262306a36Sopenharmony_ci			return -EMSGSIZE;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		trace_xprtrdma_chunk_read(rqst->rq_task, pos, mr, nsegs);
36562306a36Sopenharmony_ci		r_xprt->rx_stats.read_chunk_count++;
36662306a36Sopenharmony_ci		nsegs -= mr->mr_nents;
36762306a36Sopenharmony_ci	} while (nsegs);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cidone:
37062306a36Sopenharmony_ci	if (xdr_stream_encode_item_absent(xdr) < 0)
37162306a36Sopenharmony_ci		return -EMSGSIZE;
37262306a36Sopenharmony_ci	return 0;
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci/* Register and XDR encode the Write list. Supports encoding a list
37662306a36Sopenharmony_ci * containing one array of plain segments that belong to a single
37762306a36Sopenharmony_ci * write chunk.
37862306a36Sopenharmony_ci *
37962306a36Sopenharmony_ci * Encoding key for single-list chunks (HLOO = Handle32 Length32 Offset64):
38062306a36Sopenharmony_ci *
38162306a36Sopenharmony_ci *  Write chunklist (a list of (one) counted array):
38262306a36Sopenharmony_ci *   N elements:
38362306a36Sopenharmony_ci *    1 - N - HLOO - HLOO - ... - HLOO - 0
38462306a36Sopenharmony_ci *
38562306a36Sopenharmony_ci * Returns zero on success, or a negative errno if a failure occurred.
38662306a36Sopenharmony_ci * @xdr is advanced to the next position in the stream.
38762306a36Sopenharmony_ci *
38862306a36Sopenharmony_ci * Only a single Write chunk is currently supported.
38962306a36Sopenharmony_ci */
39062306a36Sopenharmony_cistatic int rpcrdma_encode_write_list(struct rpcrdma_xprt *r_xprt,
39162306a36Sopenharmony_ci				     struct rpcrdma_req *req,
39262306a36Sopenharmony_ci				     struct rpc_rqst *rqst,
39362306a36Sopenharmony_ci				     enum rpcrdma_chunktype wtype)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	struct xdr_stream *xdr = &req->rl_stream;
39662306a36Sopenharmony_ci	struct rpcrdma_ep *ep = r_xprt->rx_ep;
39762306a36Sopenharmony_ci	struct rpcrdma_mr_seg *seg;
39862306a36Sopenharmony_ci	struct rpcrdma_mr *mr;
39962306a36Sopenharmony_ci	int nsegs, nchunks;
40062306a36Sopenharmony_ci	__be32 *segcount;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (wtype != rpcrdma_writech)
40362306a36Sopenharmony_ci		goto done;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	seg = req->rl_segments;
40662306a36Sopenharmony_ci	nsegs = rpcrdma_convert_iovs(r_xprt, &rqst->rq_rcv_buf,
40762306a36Sopenharmony_ci				     rqst->rq_rcv_buf.head[0].iov_len,
40862306a36Sopenharmony_ci				     wtype, seg);
40962306a36Sopenharmony_ci	if (nsegs < 0)
41062306a36Sopenharmony_ci		return nsegs;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (xdr_stream_encode_item_present(xdr) < 0)
41362306a36Sopenharmony_ci		return -EMSGSIZE;
41462306a36Sopenharmony_ci	segcount = xdr_reserve_space(xdr, sizeof(*segcount));
41562306a36Sopenharmony_ci	if (unlikely(!segcount))
41662306a36Sopenharmony_ci		return -EMSGSIZE;
41762306a36Sopenharmony_ci	/* Actual value encoded below */
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	nchunks = 0;
42062306a36Sopenharmony_ci	do {
42162306a36Sopenharmony_ci		seg = rpcrdma_mr_prepare(r_xprt, req, seg, nsegs, true, &mr);
42262306a36Sopenharmony_ci		if (IS_ERR(seg))
42362306a36Sopenharmony_ci			return PTR_ERR(seg);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci		if (encode_rdma_segment(xdr, mr) < 0)
42662306a36Sopenharmony_ci			return -EMSGSIZE;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci		trace_xprtrdma_chunk_write(rqst->rq_task, mr, nsegs);
42962306a36Sopenharmony_ci		r_xprt->rx_stats.write_chunk_count++;
43062306a36Sopenharmony_ci		r_xprt->rx_stats.total_rdma_request += mr->mr_length;
43162306a36Sopenharmony_ci		nchunks++;
43262306a36Sopenharmony_ci		nsegs -= mr->mr_nents;
43362306a36Sopenharmony_ci	} while (nsegs);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (xdr_pad_size(rqst->rq_rcv_buf.page_len)) {
43662306a36Sopenharmony_ci		if (encode_rdma_segment(xdr, ep->re_write_pad_mr) < 0)
43762306a36Sopenharmony_ci			return -EMSGSIZE;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci		trace_xprtrdma_chunk_wp(rqst->rq_task, ep->re_write_pad_mr,
44062306a36Sopenharmony_ci					nsegs);
44162306a36Sopenharmony_ci		r_xprt->rx_stats.write_chunk_count++;
44262306a36Sopenharmony_ci		r_xprt->rx_stats.total_rdma_request += mr->mr_length;
44362306a36Sopenharmony_ci		nchunks++;
44462306a36Sopenharmony_ci		nsegs -= mr->mr_nents;
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/* Update count of segments in this Write chunk */
44862306a36Sopenharmony_ci	*segcount = cpu_to_be32(nchunks);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cidone:
45162306a36Sopenharmony_ci	if (xdr_stream_encode_item_absent(xdr) < 0)
45262306a36Sopenharmony_ci		return -EMSGSIZE;
45362306a36Sopenharmony_ci	return 0;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci/* Register and XDR encode the Reply chunk. Supports encoding an array
45762306a36Sopenharmony_ci * of plain segments that belong to a single write (reply) chunk.
45862306a36Sopenharmony_ci *
45962306a36Sopenharmony_ci * Encoding key for single-list chunks (HLOO = Handle32 Length32 Offset64):
46062306a36Sopenharmony_ci *
46162306a36Sopenharmony_ci *  Reply chunk (a counted array):
46262306a36Sopenharmony_ci *   N elements:
46362306a36Sopenharmony_ci *    1 - N - HLOO - HLOO - ... - HLOO
46462306a36Sopenharmony_ci *
46562306a36Sopenharmony_ci * Returns zero on success, or a negative errno if a failure occurred.
46662306a36Sopenharmony_ci * @xdr is advanced to the next position in the stream.
46762306a36Sopenharmony_ci */
46862306a36Sopenharmony_cistatic int rpcrdma_encode_reply_chunk(struct rpcrdma_xprt *r_xprt,
46962306a36Sopenharmony_ci				      struct rpcrdma_req *req,
47062306a36Sopenharmony_ci				      struct rpc_rqst *rqst,
47162306a36Sopenharmony_ci				      enum rpcrdma_chunktype wtype)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	struct xdr_stream *xdr = &req->rl_stream;
47462306a36Sopenharmony_ci	struct rpcrdma_mr_seg *seg;
47562306a36Sopenharmony_ci	struct rpcrdma_mr *mr;
47662306a36Sopenharmony_ci	int nsegs, nchunks;
47762306a36Sopenharmony_ci	__be32 *segcount;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (wtype != rpcrdma_replych) {
48062306a36Sopenharmony_ci		if (xdr_stream_encode_item_absent(xdr) < 0)
48162306a36Sopenharmony_ci			return -EMSGSIZE;
48262306a36Sopenharmony_ci		return 0;
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	seg = req->rl_segments;
48662306a36Sopenharmony_ci	nsegs = rpcrdma_convert_iovs(r_xprt, &rqst->rq_rcv_buf, 0, wtype, seg);
48762306a36Sopenharmony_ci	if (nsegs < 0)
48862306a36Sopenharmony_ci		return nsegs;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (xdr_stream_encode_item_present(xdr) < 0)
49162306a36Sopenharmony_ci		return -EMSGSIZE;
49262306a36Sopenharmony_ci	segcount = xdr_reserve_space(xdr, sizeof(*segcount));
49362306a36Sopenharmony_ci	if (unlikely(!segcount))
49462306a36Sopenharmony_ci		return -EMSGSIZE;
49562306a36Sopenharmony_ci	/* Actual value encoded below */
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	nchunks = 0;
49862306a36Sopenharmony_ci	do {
49962306a36Sopenharmony_ci		seg = rpcrdma_mr_prepare(r_xprt, req, seg, nsegs, true, &mr);
50062306a36Sopenharmony_ci		if (IS_ERR(seg))
50162306a36Sopenharmony_ci			return PTR_ERR(seg);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		if (encode_rdma_segment(xdr, mr) < 0)
50462306a36Sopenharmony_ci			return -EMSGSIZE;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci		trace_xprtrdma_chunk_reply(rqst->rq_task, mr, nsegs);
50762306a36Sopenharmony_ci		r_xprt->rx_stats.reply_chunk_count++;
50862306a36Sopenharmony_ci		r_xprt->rx_stats.total_rdma_request += mr->mr_length;
50962306a36Sopenharmony_ci		nchunks++;
51062306a36Sopenharmony_ci		nsegs -= mr->mr_nents;
51162306a36Sopenharmony_ci	} while (nsegs);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	/* Update count of segments in the Reply chunk */
51462306a36Sopenharmony_ci	*segcount = cpu_to_be32(nchunks);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	return 0;
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic void rpcrdma_sendctx_done(struct kref *kref)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	struct rpcrdma_req *req =
52262306a36Sopenharmony_ci		container_of(kref, struct rpcrdma_req, rl_kref);
52362306a36Sopenharmony_ci	struct rpcrdma_rep *rep = req->rl_reply;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	rpcrdma_complete_rqst(rep);
52662306a36Sopenharmony_ci	rep->rr_rxprt->rx_stats.reply_waits_for_send++;
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci/**
53062306a36Sopenharmony_ci * rpcrdma_sendctx_unmap - DMA-unmap Send buffer
53162306a36Sopenharmony_ci * @sc: sendctx containing SGEs to unmap
53262306a36Sopenharmony_ci *
53362306a36Sopenharmony_ci */
53462306a36Sopenharmony_civoid rpcrdma_sendctx_unmap(struct rpcrdma_sendctx *sc)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	struct rpcrdma_regbuf *rb = sc->sc_req->rl_sendbuf;
53762306a36Sopenharmony_ci	struct ib_sge *sge;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (!sc->sc_unmap_count)
54062306a36Sopenharmony_ci		return;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	/* The first two SGEs contain the transport header and
54362306a36Sopenharmony_ci	 * the inline buffer. These are always left mapped so
54462306a36Sopenharmony_ci	 * they can be cheaply re-used.
54562306a36Sopenharmony_ci	 */
54662306a36Sopenharmony_ci	for (sge = &sc->sc_sges[2]; sc->sc_unmap_count;
54762306a36Sopenharmony_ci	     ++sge, --sc->sc_unmap_count)
54862306a36Sopenharmony_ci		ib_dma_unmap_page(rdmab_device(rb), sge->addr, sge->length,
54962306a36Sopenharmony_ci				  DMA_TO_DEVICE);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	kref_put(&sc->sc_req->rl_kref, rpcrdma_sendctx_done);
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci/* Prepare an SGE for the RPC-over-RDMA transport header.
55562306a36Sopenharmony_ci */
55662306a36Sopenharmony_cistatic void rpcrdma_prepare_hdr_sge(struct rpcrdma_xprt *r_xprt,
55762306a36Sopenharmony_ci				    struct rpcrdma_req *req, u32 len)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	struct rpcrdma_sendctx *sc = req->rl_sendctx;
56062306a36Sopenharmony_ci	struct rpcrdma_regbuf *rb = req->rl_rdmabuf;
56162306a36Sopenharmony_ci	struct ib_sge *sge = &sc->sc_sges[req->rl_wr.num_sge++];
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	sge->addr = rdmab_addr(rb);
56462306a36Sopenharmony_ci	sge->length = len;
56562306a36Sopenharmony_ci	sge->lkey = rdmab_lkey(rb);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	ib_dma_sync_single_for_device(rdmab_device(rb), sge->addr, sge->length,
56862306a36Sopenharmony_ci				      DMA_TO_DEVICE);
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci/* The head iovec is straightforward, as it is usually already
57262306a36Sopenharmony_ci * DMA-mapped. Sync the content that has changed.
57362306a36Sopenharmony_ci */
57462306a36Sopenharmony_cistatic bool rpcrdma_prepare_head_iov(struct rpcrdma_xprt *r_xprt,
57562306a36Sopenharmony_ci				     struct rpcrdma_req *req, unsigned int len)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	struct rpcrdma_sendctx *sc = req->rl_sendctx;
57862306a36Sopenharmony_ci	struct ib_sge *sge = &sc->sc_sges[req->rl_wr.num_sge++];
57962306a36Sopenharmony_ci	struct rpcrdma_regbuf *rb = req->rl_sendbuf;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	if (!rpcrdma_regbuf_dma_map(r_xprt, rb))
58262306a36Sopenharmony_ci		return false;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	sge->addr = rdmab_addr(rb);
58562306a36Sopenharmony_ci	sge->length = len;
58662306a36Sopenharmony_ci	sge->lkey = rdmab_lkey(rb);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	ib_dma_sync_single_for_device(rdmab_device(rb), sge->addr, sge->length,
58962306a36Sopenharmony_ci				      DMA_TO_DEVICE);
59062306a36Sopenharmony_ci	return true;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci/* If there is a page list present, DMA map and prepare an
59462306a36Sopenharmony_ci * SGE for each page to be sent.
59562306a36Sopenharmony_ci */
59662306a36Sopenharmony_cistatic bool rpcrdma_prepare_pagelist(struct rpcrdma_req *req,
59762306a36Sopenharmony_ci				     struct xdr_buf *xdr)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	struct rpcrdma_sendctx *sc = req->rl_sendctx;
60062306a36Sopenharmony_ci	struct rpcrdma_regbuf *rb = req->rl_sendbuf;
60162306a36Sopenharmony_ci	unsigned int page_base, len, remaining;
60262306a36Sopenharmony_ci	struct page **ppages;
60362306a36Sopenharmony_ci	struct ib_sge *sge;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	ppages = xdr->pages + (xdr->page_base >> PAGE_SHIFT);
60662306a36Sopenharmony_ci	page_base = offset_in_page(xdr->page_base);
60762306a36Sopenharmony_ci	remaining = xdr->page_len;
60862306a36Sopenharmony_ci	while (remaining) {
60962306a36Sopenharmony_ci		sge = &sc->sc_sges[req->rl_wr.num_sge++];
61062306a36Sopenharmony_ci		len = min_t(unsigned int, PAGE_SIZE - page_base, remaining);
61162306a36Sopenharmony_ci		sge->addr = ib_dma_map_page(rdmab_device(rb), *ppages,
61262306a36Sopenharmony_ci					    page_base, len, DMA_TO_DEVICE);
61362306a36Sopenharmony_ci		if (ib_dma_mapping_error(rdmab_device(rb), sge->addr))
61462306a36Sopenharmony_ci			goto out_mapping_err;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci		sge->length = len;
61762306a36Sopenharmony_ci		sge->lkey = rdmab_lkey(rb);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		sc->sc_unmap_count++;
62062306a36Sopenharmony_ci		ppages++;
62162306a36Sopenharmony_ci		remaining -= len;
62262306a36Sopenharmony_ci		page_base = 0;
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	return true;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ciout_mapping_err:
62862306a36Sopenharmony_ci	trace_xprtrdma_dma_maperr(sge->addr);
62962306a36Sopenharmony_ci	return false;
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci/* The tail iovec may include an XDR pad for the page list,
63362306a36Sopenharmony_ci * as well as additional content, and may not reside in the
63462306a36Sopenharmony_ci * same page as the head iovec.
63562306a36Sopenharmony_ci */
63662306a36Sopenharmony_cistatic bool rpcrdma_prepare_tail_iov(struct rpcrdma_req *req,
63762306a36Sopenharmony_ci				     struct xdr_buf *xdr,
63862306a36Sopenharmony_ci				     unsigned int page_base, unsigned int len)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	struct rpcrdma_sendctx *sc = req->rl_sendctx;
64162306a36Sopenharmony_ci	struct ib_sge *sge = &sc->sc_sges[req->rl_wr.num_sge++];
64262306a36Sopenharmony_ci	struct rpcrdma_regbuf *rb = req->rl_sendbuf;
64362306a36Sopenharmony_ci	struct page *page = virt_to_page(xdr->tail[0].iov_base);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	sge->addr = ib_dma_map_page(rdmab_device(rb), page, page_base, len,
64662306a36Sopenharmony_ci				    DMA_TO_DEVICE);
64762306a36Sopenharmony_ci	if (ib_dma_mapping_error(rdmab_device(rb), sge->addr))
64862306a36Sopenharmony_ci		goto out_mapping_err;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	sge->length = len;
65162306a36Sopenharmony_ci	sge->lkey = rdmab_lkey(rb);
65262306a36Sopenharmony_ci	++sc->sc_unmap_count;
65362306a36Sopenharmony_ci	return true;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ciout_mapping_err:
65662306a36Sopenharmony_ci	trace_xprtrdma_dma_maperr(sge->addr);
65762306a36Sopenharmony_ci	return false;
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci/* Copy the tail to the end of the head buffer.
66162306a36Sopenharmony_ci */
66262306a36Sopenharmony_cistatic void rpcrdma_pullup_tail_iov(struct rpcrdma_xprt *r_xprt,
66362306a36Sopenharmony_ci				    struct rpcrdma_req *req,
66462306a36Sopenharmony_ci				    struct xdr_buf *xdr)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	unsigned char *dst;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	dst = (unsigned char *)xdr->head[0].iov_base;
66962306a36Sopenharmony_ci	dst += xdr->head[0].iov_len + xdr->page_len;
67062306a36Sopenharmony_ci	memmove(dst, xdr->tail[0].iov_base, xdr->tail[0].iov_len);
67162306a36Sopenharmony_ci	r_xprt->rx_stats.pullup_copy_count += xdr->tail[0].iov_len;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci/* Copy pagelist content into the head buffer.
67562306a36Sopenharmony_ci */
67662306a36Sopenharmony_cistatic void rpcrdma_pullup_pagelist(struct rpcrdma_xprt *r_xprt,
67762306a36Sopenharmony_ci				    struct rpcrdma_req *req,
67862306a36Sopenharmony_ci				    struct xdr_buf *xdr)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	unsigned int len, page_base, remaining;
68162306a36Sopenharmony_ci	struct page **ppages;
68262306a36Sopenharmony_ci	unsigned char *src, *dst;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	dst = (unsigned char *)xdr->head[0].iov_base;
68562306a36Sopenharmony_ci	dst += xdr->head[0].iov_len;
68662306a36Sopenharmony_ci	ppages = xdr->pages + (xdr->page_base >> PAGE_SHIFT);
68762306a36Sopenharmony_ci	page_base = offset_in_page(xdr->page_base);
68862306a36Sopenharmony_ci	remaining = xdr->page_len;
68962306a36Sopenharmony_ci	while (remaining) {
69062306a36Sopenharmony_ci		src = page_address(*ppages);
69162306a36Sopenharmony_ci		src += page_base;
69262306a36Sopenharmony_ci		len = min_t(unsigned int, PAGE_SIZE - page_base, remaining);
69362306a36Sopenharmony_ci		memcpy(dst, src, len);
69462306a36Sopenharmony_ci		r_xprt->rx_stats.pullup_copy_count += len;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci		ppages++;
69762306a36Sopenharmony_ci		dst += len;
69862306a36Sopenharmony_ci		remaining -= len;
69962306a36Sopenharmony_ci		page_base = 0;
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci/* Copy the contents of @xdr into @rl_sendbuf and DMA sync it.
70462306a36Sopenharmony_ci * When the head, pagelist, and tail are small, a pull-up copy
70562306a36Sopenharmony_ci * is considerably less costly than DMA mapping the components
70662306a36Sopenharmony_ci * of @xdr.
70762306a36Sopenharmony_ci *
70862306a36Sopenharmony_ci * Assumptions:
70962306a36Sopenharmony_ci *  - the caller has already verified that the total length
71062306a36Sopenharmony_ci *    of the RPC Call body will fit into @rl_sendbuf.
71162306a36Sopenharmony_ci */
71262306a36Sopenharmony_cistatic bool rpcrdma_prepare_noch_pullup(struct rpcrdma_xprt *r_xprt,
71362306a36Sopenharmony_ci					struct rpcrdma_req *req,
71462306a36Sopenharmony_ci					struct xdr_buf *xdr)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	if (unlikely(xdr->tail[0].iov_len))
71762306a36Sopenharmony_ci		rpcrdma_pullup_tail_iov(r_xprt, req, xdr);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	if (unlikely(xdr->page_len))
72062306a36Sopenharmony_ci		rpcrdma_pullup_pagelist(r_xprt, req, xdr);
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	/* The whole RPC message resides in the head iovec now */
72362306a36Sopenharmony_ci	return rpcrdma_prepare_head_iov(r_xprt, req, xdr->len);
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_cistatic bool rpcrdma_prepare_noch_mapped(struct rpcrdma_xprt *r_xprt,
72762306a36Sopenharmony_ci					struct rpcrdma_req *req,
72862306a36Sopenharmony_ci					struct xdr_buf *xdr)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	struct kvec *tail = &xdr->tail[0];
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (!rpcrdma_prepare_head_iov(r_xprt, req, xdr->head[0].iov_len))
73362306a36Sopenharmony_ci		return false;
73462306a36Sopenharmony_ci	if (xdr->page_len)
73562306a36Sopenharmony_ci		if (!rpcrdma_prepare_pagelist(req, xdr))
73662306a36Sopenharmony_ci			return false;
73762306a36Sopenharmony_ci	if (tail->iov_len)
73862306a36Sopenharmony_ci		if (!rpcrdma_prepare_tail_iov(req, xdr,
73962306a36Sopenharmony_ci					      offset_in_page(tail->iov_base),
74062306a36Sopenharmony_ci					      tail->iov_len))
74162306a36Sopenharmony_ci			return false;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	if (req->rl_sendctx->sc_unmap_count)
74462306a36Sopenharmony_ci		kref_get(&req->rl_kref);
74562306a36Sopenharmony_ci	return true;
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_cistatic bool rpcrdma_prepare_readch(struct rpcrdma_xprt *r_xprt,
74962306a36Sopenharmony_ci				   struct rpcrdma_req *req,
75062306a36Sopenharmony_ci				   struct xdr_buf *xdr)
75162306a36Sopenharmony_ci{
75262306a36Sopenharmony_ci	if (!rpcrdma_prepare_head_iov(r_xprt, req, xdr->head[0].iov_len))
75362306a36Sopenharmony_ci		return false;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	/* If there is a Read chunk, the page list is being handled
75662306a36Sopenharmony_ci	 * via explicit RDMA, and thus is skipped here.
75762306a36Sopenharmony_ci	 */
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	/* Do not include the tail if it is only an XDR pad */
76062306a36Sopenharmony_ci	if (xdr->tail[0].iov_len > 3) {
76162306a36Sopenharmony_ci		unsigned int page_base, len;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci		/* If the content in the page list is an odd length,
76462306a36Sopenharmony_ci		 * xdr_write_pages() adds a pad at the beginning of
76562306a36Sopenharmony_ci		 * the tail iovec. Force the tail's non-pad content to
76662306a36Sopenharmony_ci		 * land at the next XDR position in the Send message.
76762306a36Sopenharmony_ci		 */
76862306a36Sopenharmony_ci		page_base = offset_in_page(xdr->tail[0].iov_base);
76962306a36Sopenharmony_ci		len = xdr->tail[0].iov_len;
77062306a36Sopenharmony_ci		page_base += len & 3;
77162306a36Sopenharmony_ci		len -= len & 3;
77262306a36Sopenharmony_ci		if (!rpcrdma_prepare_tail_iov(req, xdr, page_base, len))
77362306a36Sopenharmony_ci			return false;
77462306a36Sopenharmony_ci		kref_get(&req->rl_kref);
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	return true;
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci/**
78162306a36Sopenharmony_ci * rpcrdma_prepare_send_sges - Construct SGEs for a Send WR
78262306a36Sopenharmony_ci * @r_xprt: controlling transport
78362306a36Sopenharmony_ci * @req: context of RPC Call being marshalled
78462306a36Sopenharmony_ci * @hdrlen: size of transport header, in bytes
78562306a36Sopenharmony_ci * @xdr: xdr_buf containing RPC Call
78662306a36Sopenharmony_ci * @rtype: chunk type being encoded
78762306a36Sopenharmony_ci *
78862306a36Sopenharmony_ci * Returns 0 on success; otherwise a negative errno is returned.
78962306a36Sopenharmony_ci */
79062306a36Sopenharmony_ciinline int rpcrdma_prepare_send_sges(struct rpcrdma_xprt *r_xprt,
79162306a36Sopenharmony_ci				     struct rpcrdma_req *req, u32 hdrlen,
79262306a36Sopenharmony_ci				     struct xdr_buf *xdr,
79362306a36Sopenharmony_ci				     enum rpcrdma_chunktype rtype)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	int ret;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	ret = -EAGAIN;
79862306a36Sopenharmony_ci	req->rl_sendctx = rpcrdma_sendctx_get_locked(r_xprt);
79962306a36Sopenharmony_ci	if (!req->rl_sendctx)
80062306a36Sopenharmony_ci		goto out_nosc;
80162306a36Sopenharmony_ci	req->rl_sendctx->sc_unmap_count = 0;
80262306a36Sopenharmony_ci	req->rl_sendctx->sc_req = req;
80362306a36Sopenharmony_ci	kref_init(&req->rl_kref);
80462306a36Sopenharmony_ci	req->rl_wr.wr_cqe = &req->rl_sendctx->sc_cqe;
80562306a36Sopenharmony_ci	req->rl_wr.sg_list = req->rl_sendctx->sc_sges;
80662306a36Sopenharmony_ci	req->rl_wr.num_sge = 0;
80762306a36Sopenharmony_ci	req->rl_wr.opcode = IB_WR_SEND;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	rpcrdma_prepare_hdr_sge(r_xprt, req, hdrlen);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	ret = -EIO;
81262306a36Sopenharmony_ci	switch (rtype) {
81362306a36Sopenharmony_ci	case rpcrdma_noch_pullup:
81462306a36Sopenharmony_ci		if (!rpcrdma_prepare_noch_pullup(r_xprt, req, xdr))
81562306a36Sopenharmony_ci			goto out_unmap;
81662306a36Sopenharmony_ci		break;
81762306a36Sopenharmony_ci	case rpcrdma_noch_mapped:
81862306a36Sopenharmony_ci		if (!rpcrdma_prepare_noch_mapped(r_xprt, req, xdr))
81962306a36Sopenharmony_ci			goto out_unmap;
82062306a36Sopenharmony_ci		break;
82162306a36Sopenharmony_ci	case rpcrdma_readch:
82262306a36Sopenharmony_ci		if (!rpcrdma_prepare_readch(r_xprt, req, xdr))
82362306a36Sopenharmony_ci			goto out_unmap;
82462306a36Sopenharmony_ci		break;
82562306a36Sopenharmony_ci	case rpcrdma_areadch:
82662306a36Sopenharmony_ci		break;
82762306a36Sopenharmony_ci	default:
82862306a36Sopenharmony_ci		goto out_unmap;
82962306a36Sopenharmony_ci	}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	return 0;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ciout_unmap:
83462306a36Sopenharmony_ci	rpcrdma_sendctx_unmap(req->rl_sendctx);
83562306a36Sopenharmony_ciout_nosc:
83662306a36Sopenharmony_ci	trace_xprtrdma_prepsend_failed(&req->rl_slot, ret);
83762306a36Sopenharmony_ci	return ret;
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci/**
84162306a36Sopenharmony_ci * rpcrdma_marshal_req - Marshal and send one RPC request
84262306a36Sopenharmony_ci * @r_xprt: controlling transport
84362306a36Sopenharmony_ci * @rqst: RPC request to be marshaled
84462306a36Sopenharmony_ci *
84562306a36Sopenharmony_ci * For the RPC in "rqst", this function:
84662306a36Sopenharmony_ci *  - Chooses the transfer mode (eg., RDMA_MSG or RDMA_NOMSG)
84762306a36Sopenharmony_ci *  - Registers Read, Write, and Reply chunks
84862306a36Sopenharmony_ci *  - Constructs the transport header
84962306a36Sopenharmony_ci *  - Posts a Send WR to send the transport header and request
85062306a36Sopenharmony_ci *
85162306a36Sopenharmony_ci * Returns:
85262306a36Sopenharmony_ci *	%0 if the RPC was sent successfully,
85362306a36Sopenharmony_ci *	%-ENOTCONN if the connection was lost,
85462306a36Sopenharmony_ci *	%-EAGAIN if the caller should call again with the same arguments,
85562306a36Sopenharmony_ci *	%-ENOBUFS if the caller should call again after a delay,
85662306a36Sopenharmony_ci *	%-EMSGSIZE if the transport header is too small,
85762306a36Sopenharmony_ci *	%-EIO if a permanent problem occurred while marshaling.
85862306a36Sopenharmony_ci */
85962306a36Sopenharmony_ciint
86062306a36Sopenharmony_cirpcrdma_marshal_req(struct rpcrdma_xprt *r_xprt, struct rpc_rqst *rqst)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
86362306a36Sopenharmony_ci	struct xdr_stream *xdr = &req->rl_stream;
86462306a36Sopenharmony_ci	enum rpcrdma_chunktype rtype, wtype;
86562306a36Sopenharmony_ci	struct xdr_buf *buf = &rqst->rq_snd_buf;
86662306a36Sopenharmony_ci	bool ddp_allowed;
86762306a36Sopenharmony_ci	__be32 *p;
86862306a36Sopenharmony_ci	int ret;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	if (unlikely(rqst->rq_rcv_buf.flags & XDRBUF_SPARSE_PAGES)) {
87162306a36Sopenharmony_ci		ret = rpcrdma_alloc_sparse_pages(&rqst->rq_rcv_buf);
87262306a36Sopenharmony_ci		if (ret)
87362306a36Sopenharmony_ci			return ret;
87462306a36Sopenharmony_ci	}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	rpcrdma_set_xdrlen(&req->rl_hdrbuf, 0);
87762306a36Sopenharmony_ci	xdr_init_encode(xdr, &req->rl_hdrbuf, rdmab_data(req->rl_rdmabuf),
87862306a36Sopenharmony_ci			rqst);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	/* Fixed header fields */
88162306a36Sopenharmony_ci	ret = -EMSGSIZE;
88262306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 * sizeof(*p));
88362306a36Sopenharmony_ci	if (!p)
88462306a36Sopenharmony_ci		goto out_err;
88562306a36Sopenharmony_ci	*p++ = rqst->rq_xid;
88662306a36Sopenharmony_ci	*p++ = rpcrdma_version;
88762306a36Sopenharmony_ci	*p++ = r_xprt->rx_buf.rb_max_requests;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	/* When the ULP employs a GSS flavor that guarantees integrity
89062306a36Sopenharmony_ci	 * or privacy, direct data placement of individual data items
89162306a36Sopenharmony_ci	 * is not allowed.
89262306a36Sopenharmony_ci	 */
89362306a36Sopenharmony_ci	ddp_allowed = !test_bit(RPCAUTH_AUTH_DATATOUCH,
89462306a36Sopenharmony_ci				&rqst->rq_cred->cr_auth->au_flags);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	/*
89762306a36Sopenharmony_ci	 * Chunks needed for results?
89862306a36Sopenharmony_ci	 *
89962306a36Sopenharmony_ci	 * o If the expected result is under the inline threshold, all ops
90062306a36Sopenharmony_ci	 *   return as inline.
90162306a36Sopenharmony_ci	 * o Large read ops return data as write chunk(s), header as
90262306a36Sopenharmony_ci	 *   inline.
90362306a36Sopenharmony_ci	 * o Large non-read ops return as a single reply chunk.
90462306a36Sopenharmony_ci	 */
90562306a36Sopenharmony_ci	if (rpcrdma_results_inline(r_xprt, rqst))
90662306a36Sopenharmony_ci		wtype = rpcrdma_noch;
90762306a36Sopenharmony_ci	else if ((ddp_allowed && rqst->rq_rcv_buf.flags & XDRBUF_READ) &&
90862306a36Sopenharmony_ci		 rpcrdma_nonpayload_inline(r_xprt, rqst))
90962306a36Sopenharmony_ci		wtype = rpcrdma_writech;
91062306a36Sopenharmony_ci	else
91162306a36Sopenharmony_ci		wtype = rpcrdma_replych;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	/*
91462306a36Sopenharmony_ci	 * Chunks needed for arguments?
91562306a36Sopenharmony_ci	 *
91662306a36Sopenharmony_ci	 * o If the total request is under the inline threshold, all ops
91762306a36Sopenharmony_ci	 *   are sent as inline.
91862306a36Sopenharmony_ci	 * o Large write ops transmit data as read chunk(s), header as
91962306a36Sopenharmony_ci	 *   inline.
92062306a36Sopenharmony_ci	 * o Large non-write ops are sent with the entire message as a
92162306a36Sopenharmony_ci	 *   single read chunk (protocol 0-position special case).
92262306a36Sopenharmony_ci	 *
92362306a36Sopenharmony_ci	 * This assumes that the upper layer does not present a request
92462306a36Sopenharmony_ci	 * that both has a data payload, and whose non-data arguments
92562306a36Sopenharmony_ci	 * by themselves are larger than the inline threshold.
92662306a36Sopenharmony_ci	 */
92762306a36Sopenharmony_ci	if (rpcrdma_args_inline(r_xprt, rqst)) {
92862306a36Sopenharmony_ci		*p++ = rdma_msg;
92962306a36Sopenharmony_ci		rtype = buf->len < rdmab_length(req->rl_sendbuf) ?
93062306a36Sopenharmony_ci			rpcrdma_noch_pullup : rpcrdma_noch_mapped;
93162306a36Sopenharmony_ci	} else if (ddp_allowed && buf->flags & XDRBUF_WRITE) {
93262306a36Sopenharmony_ci		*p++ = rdma_msg;
93362306a36Sopenharmony_ci		rtype = rpcrdma_readch;
93462306a36Sopenharmony_ci	} else {
93562306a36Sopenharmony_ci		r_xprt->rx_stats.nomsg_call_count++;
93662306a36Sopenharmony_ci		*p++ = rdma_nomsg;
93762306a36Sopenharmony_ci		rtype = rpcrdma_areadch;
93862306a36Sopenharmony_ci	}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	/* This implementation supports the following combinations
94162306a36Sopenharmony_ci	 * of chunk lists in one RPC-over-RDMA Call message:
94262306a36Sopenharmony_ci	 *
94362306a36Sopenharmony_ci	 *   - Read list
94462306a36Sopenharmony_ci	 *   - Write list
94562306a36Sopenharmony_ci	 *   - Reply chunk
94662306a36Sopenharmony_ci	 *   - Read list + Reply chunk
94762306a36Sopenharmony_ci	 *
94862306a36Sopenharmony_ci	 * It might not yet support the following combinations:
94962306a36Sopenharmony_ci	 *
95062306a36Sopenharmony_ci	 *   - Read list + Write list
95162306a36Sopenharmony_ci	 *
95262306a36Sopenharmony_ci	 * It does not support the following combinations:
95362306a36Sopenharmony_ci	 *
95462306a36Sopenharmony_ci	 *   - Write list + Reply chunk
95562306a36Sopenharmony_ci	 *   - Read list + Write list + Reply chunk
95662306a36Sopenharmony_ci	 *
95762306a36Sopenharmony_ci	 * This implementation supports only a single chunk in each
95862306a36Sopenharmony_ci	 * Read or Write list. Thus for example the client cannot
95962306a36Sopenharmony_ci	 * send a Call message with a Position Zero Read chunk and a
96062306a36Sopenharmony_ci	 * regular Read chunk at the same time.
96162306a36Sopenharmony_ci	 */
96262306a36Sopenharmony_ci	ret = rpcrdma_encode_read_list(r_xprt, req, rqst, rtype);
96362306a36Sopenharmony_ci	if (ret)
96462306a36Sopenharmony_ci		goto out_err;
96562306a36Sopenharmony_ci	ret = rpcrdma_encode_write_list(r_xprt, req, rqst, wtype);
96662306a36Sopenharmony_ci	if (ret)
96762306a36Sopenharmony_ci		goto out_err;
96862306a36Sopenharmony_ci	ret = rpcrdma_encode_reply_chunk(r_xprt, req, rqst, wtype);
96962306a36Sopenharmony_ci	if (ret)
97062306a36Sopenharmony_ci		goto out_err;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	ret = rpcrdma_prepare_send_sges(r_xprt, req, req->rl_hdrbuf.len,
97362306a36Sopenharmony_ci					buf, rtype);
97462306a36Sopenharmony_ci	if (ret)
97562306a36Sopenharmony_ci		goto out_err;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	trace_xprtrdma_marshal(req, rtype, wtype);
97862306a36Sopenharmony_ci	return 0;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ciout_err:
98162306a36Sopenharmony_ci	trace_xprtrdma_marshal_failed(rqst, ret);
98262306a36Sopenharmony_ci	r_xprt->rx_stats.failed_marshal_count++;
98362306a36Sopenharmony_ci	frwr_reset(req);
98462306a36Sopenharmony_ci	return ret;
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic void __rpcrdma_update_cwnd_locked(struct rpc_xprt *xprt,
98862306a36Sopenharmony_ci					 struct rpcrdma_buffer *buf,
98962306a36Sopenharmony_ci					 u32 grant)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	buf->rb_credits = grant;
99262306a36Sopenharmony_ci	xprt->cwnd = grant << RPC_CWNDSHIFT;
99362306a36Sopenharmony_ci}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_cistatic void rpcrdma_update_cwnd(struct rpcrdma_xprt *r_xprt, u32 grant)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
100062306a36Sopenharmony_ci	__rpcrdma_update_cwnd_locked(xprt, &r_xprt->rx_buf, grant);
100162306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci/**
100562306a36Sopenharmony_ci * rpcrdma_reset_cwnd - Reset the xprt's congestion window
100662306a36Sopenharmony_ci * @r_xprt: controlling transport instance
100762306a36Sopenharmony_ci *
100862306a36Sopenharmony_ci * Prepare @r_xprt for the next connection by reinitializing
100962306a36Sopenharmony_ci * its credit grant to one (see RFC 8166, Section 3.3.3).
101062306a36Sopenharmony_ci */
101162306a36Sopenharmony_civoid rpcrdma_reset_cwnd(struct rpcrdma_xprt *r_xprt)
101262306a36Sopenharmony_ci{
101362306a36Sopenharmony_ci	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	spin_lock(&xprt->transport_lock);
101662306a36Sopenharmony_ci	xprt->cong = 0;
101762306a36Sopenharmony_ci	__rpcrdma_update_cwnd_locked(xprt, &r_xprt->rx_buf, 1);
101862306a36Sopenharmony_ci	spin_unlock(&xprt->transport_lock);
101962306a36Sopenharmony_ci}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci/**
102262306a36Sopenharmony_ci * rpcrdma_inline_fixup - Scatter inline received data into rqst's iovecs
102362306a36Sopenharmony_ci * @rqst: controlling RPC request
102462306a36Sopenharmony_ci * @srcp: points to RPC message payload in receive buffer
102562306a36Sopenharmony_ci * @copy_len: remaining length of receive buffer content
102662306a36Sopenharmony_ci * @pad: Write chunk pad bytes needed (zero for pure inline)
102762306a36Sopenharmony_ci *
102862306a36Sopenharmony_ci * The upper layer has set the maximum number of bytes it can
102962306a36Sopenharmony_ci * receive in each component of rq_rcv_buf. These values are set in
103062306a36Sopenharmony_ci * the head.iov_len, page_len, tail.iov_len, and buflen fields.
103162306a36Sopenharmony_ci *
103262306a36Sopenharmony_ci * Unlike the TCP equivalent (xdr_partial_copy_from_skb), in
103362306a36Sopenharmony_ci * many cases this function simply updates iov_base pointers in
103462306a36Sopenharmony_ci * rq_rcv_buf to point directly to the received reply data, to
103562306a36Sopenharmony_ci * avoid copying reply data.
103662306a36Sopenharmony_ci *
103762306a36Sopenharmony_ci * Returns the count of bytes which had to be memcopied.
103862306a36Sopenharmony_ci */
103962306a36Sopenharmony_cistatic unsigned long
104062306a36Sopenharmony_cirpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	unsigned long fixup_copy_count;
104362306a36Sopenharmony_ci	int i, npages, curlen;
104462306a36Sopenharmony_ci	char *destp;
104562306a36Sopenharmony_ci	struct page **ppages;
104662306a36Sopenharmony_ci	int page_base;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	/* The head iovec is redirected to the RPC reply message
104962306a36Sopenharmony_ci	 * in the receive buffer, to avoid a memcopy.
105062306a36Sopenharmony_ci	 */
105162306a36Sopenharmony_ci	rqst->rq_rcv_buf.head[0].iov_base = srcp;
105262306a36Sopenharmony_ci	rqst->rq_private_buf.head[0].iov_base = srcp;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	/* The contents of the receive buffer that follow
105562306a36Sopenharmony_ci	 * head.iov_len bytes are copied into the page list.
105662306a36Sopenharmony_ci	 */
105762306a36Sopenharmony_ci	curlen = rqst->rq_rcv_buf.head[0].iov_len;
105862306a36Sopenharmony_ci	if (curlen > copy_len)
105962306a36Sopenharmony_ci		curlen = copy_len;
106062306a36Sopenharmony_ci	srcp += curlen;
106162306a36Sopenharmony_ci	copy_len -= curlen;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	ppages = rqst->rq_rcv_buf.pages +
106462306a36Sopenharmony_ci		(rqst->rq_rcv_buf.page_base >> PAGE_SHIFT);
106562306a36Sopenharmony_ci	page_base = offset_in_page(rqst->rq_rcv_buf.page_base);
106662306a36Sopenharmony_ci	fixup_copy_count = 0;
106762306a36Sopenharmony_ci	if (copy_len && rqst->rq_rcv_buf.page_len) {
106862306a36Sopenharmony_ci		int pagelist_len;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci		pagelist_len = rqst->rq_rcv_buf.page_len;
107162306a36Sopenharmony_ci		if (pagelist_len > copy_len)
107262306a36Sopenharmony_ci			pagelist_len = copy_len;
107362306a36Sopenharmony_ci		npages = PAGE_ALIGN(page_base + pagelist_len) >> PAGE_SHIFT;
107462306a36Sopenharmony_ci		for (i = 0; i < npages; i++) {
107562306a36Sopenharmony_ci			curlen = PAGE_SIZE - page_base;
107662306a36Sopenharmony_ci			if (curlen > pagelist_len)
107762306a36Sopenharmony_ci				curlen = pagelist_len;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci			destp = kmap_atomic(ppages[i]);
108062306a36Sopenharmony_ci			memcpy(destp + page_base, srcp, curlen);
108162306a36Sopenharmony_ci			flush_dcache_page(ppages[i]);
108262306a36Sopenharmony_ci			kunmap_atomic(destp);
108362306a36Sopenharmony_ci			srcp += curlen;
108462306a36Sopenharmony_ci			copy_len -= curlen;
108562306a36Sopenharmony_ci			fixup_copy_count += curlen;
108662306a36Sopenharmony_ci			pagelist_len -= curlen;
108762306a36Sopenharmony_ci			if (!pagelist_len)
108862306a36Sopenharmony_ci				break;
108962306a36Sopenharmony_ci			page_base = 0;
109062306a36Sopenharmony_ci		}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci		/* Implicit padding for the last segment in a Write
109362306a36Sopenharmony_ci		 * chunk is inserted inline at the front of the tail
109462306a36Sopenharmony_ci		 * iovec. The upper layer ignores the content of
109562306a36Sopenharmony_ci		 * the pad. Simply ensure inline content in the tail
109662306a36Sopenharmony_ci		 * that follows the Write chunk is properly aligned.
109762306a36Sopenharmony_ci		 */
109862306a36Sopenharmony_ci		if (pad)
109962306a36Sopenharmony_ci			srcp -= pad;
110062306a36Sopenharmony_ci	}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	/* The tail iovec is redirected to the remaining data
110362306a36Sopenharmony_ci	 * in the receive buffer, to avoid a memcopy.
110462306a36Sopenharmony_ci	 */
110562306a36Sopenharmony_ci	if (copy_len || pad) {
110662306a36Sopenharmony_ci		rqst->rq_rcv_buf.tail[0].iov_base = srcp;
110762306a36Sopenharmony_ci		rqst->rq_private_buf.tail[0].iov_base = srcp;
110862306a36Sopenharmony_ci	}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	if (fixup_copy_count)
111162306a36Sopenharmony_ci		trace_xprtrdma_fixup(rqst, fixup_copy_count);
111262306a36Sopenharmony_ci	return fixup_copy_count;
111362306a36Sopenharmony_ci}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci/* By convention, backchannel calls arrive via rdma_msg type
111662306a36Sopenharmony_ci * messages, and never populate the chunk lists. This makes
111762306a36Sopenharmony_ci * the RPC/RDMA header small and fixed in size, so it is
111862306a36Sopenharmony_ci * straightforward to check the RPC header's direction field.
111962306a36Sopenharmony_ci */
112062306a36Sopenharmony_cistatic bool
112162306a36Sopenharmony_cirpcrdma_is_bcall(struct rpcrdma_xprt *r_xprt, struct rpcrdma_rep *rep)
112262306a36Sopenharmony_ci#if defined(CONFIG_SUNRPC_BACKCHANNEL)
112362306a36Sopenharmony_ci{
112462306a36Sopenharmony_ci	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
112562306a36Sopenharmony_ci	struct xdr_stream *xdr = &rep->rr_stream;
112662306a36Sopenharmony_ci	__be32 *p;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	if (rep->rr_proc != rdma_msg)
112962306a36Sopenharmony_ci		return false;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	/* Peek at stream contents without advancing. */
113262306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 0);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	/* Chunk lists */
113562306a36Sopenharmony_ci	if (xdr_item_is_present(p++))
113662306a36Sopenharmony_ci		return false;
113762306a36Sopenharmony_ci	if (xdr_item_is_present(p++))
113862306a36Sopenharmony_ci		return false;
113962306a36Sopenharmony_ci	if (xdr_item_is_present(p++))
114062306a36Sopenharmony_ci		return false;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	/* RPC header */
114362306a36Sopenharmony_ci	if (*p++ != rep->rr_xid)
114462306a36Sopenharmony_ci		return false;
114562306a36Sopenharmony_ci	if (*p != cpu_to_be32(RPC_CALL))
114662306a36Sopenharmony_ci		return false;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	/* No bc service. */
114962306a36Sopenharmony_ci	if (xprt->bc_serv == NULL)
115062306a36Sopenharmony_ci		return false;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	/* Now that we are sure this is a backchannel call,
115362306a36Sopenharmony_ci	 * advance to the RPC header.
115462306a36Sopenharmony_ci	 */
115562306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 3 * sizeof(*p));
115662306a36Sopenharmony_ci	if (unlikely(!p))
115762306a36Sopenharmony_ci		return true;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	rpcrdma_bc_receive_call(r_xprt, rep);
116062306a36Sopenharmony_ci	return true;
116162306a36Sopenharmony_ci}
116262306a36Sopenharmony_ci#else	/* CONFIG_SUNRPC_BACKCHANNEL */
116362306a36Sopenharmony_ci{
116462306a36Sopenharmony_ci	return false;
116562306a36Sopenharmony_ci}
116662306a36Sopenharmony_ci#endif	/* CONFIG_SUNRPC_BACKCHANNEL */
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_cistatic int decode_rdma_segment(struct xdr_stream *xdr, u32 *length)
116962306a36Sopenharmony_ci{
117062306a36Sopenharmony_ci	u32 handle;
117162306a36Sopenharmony_ci	u64 offset;
117262306a36Sopenharmony_ci	__be32 *p;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4 * sizeof(*p));
117562306a36Sopenharmony_ci	if (unlikely(!p))
117662306a36Sopenharmony_ci		return -EIO;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	xdr_decode_rdma_segment(p, &handle, length, &offset);
117962306a36Sopenharmony_ci	trace_xprtrdma_decode_seg(handle, *length, offset);
118062306a36Sopenharmony_ci	return 0;
118162306a36Sopenharmony_ci}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_cistatic int decode_write_chunk(struct xdr_stream *xdr, u32 *length)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	u32 segcount, seglength;
118662306a36Sopenharmony_ci	__be32 *p;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, sizeof(*p));
118962306a36Sopenharmony_ci	if (unlikely(!p))
119062306a36Sopenharmony_ci		return -EIO;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	*length = 0;
119362306a36Sopenharmony_ci	segcount = be32_to_cpup(p);
119462306a36Sopenharmony_ci	while (segcount--) {
119562306a36Sopenharmony_ci		if (decode_rdma_segment(xdr, &seglength))
119662306a36Sopenharmony_ci			return -EIO;
119762306a36Sopenharmony_ci		*length += seglength;
119862306a36Sopenharmony_ci	}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	return 0;
120162306a36Sopenharmony_ci}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci/* In RPC-over-RDMA Version One replies, a Read list is never
120462306a36Sopenharmony_ci * expected. This decoder is a stub that returns an error if
120562306a36Sopenharmony_ci * a Read list is present.
120662306a36Sopenharmony_ci */
120762306a36Sopenharmony_cistatic int decode_read_list(struct xdr_stream *xdr)
120862306a36Sopenharmony_ci{
120962306a36Sopenharmony_ci	__be32 *p;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, sizeof(*p));
121262306a36Sopenharmony_ci	if (unlikely(!p))
121362306a36Sopenharmony_ci		return -EIO;
121462306a36Sopenharmony_ci	if (unlikely(xdr_item_is_present(p)))
121562306a36Sopenharmony_ci		return -EIO;
121662306a36Sopenharmony_ci	return 0;
121762306a36Sopenharmony_ci}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci/* Supports only one Write chunk in the Write list
122062306a36Sopenharmony_ci */
122162306a36Sopenharmony_cistatic int decode_write_list(struct xdr_stream *xdr, u32 *length)
122262306a36Sopenharmony_ci{
122362306a36Sopenharmony_ci	u32 chunklen;
122462306a36Sopenharmony_ci	bool first;
122562306a36Sopenharmony_ci	__be32 *p;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	*length = 0;
122862306a36Sopenharmony_ci	first = true;
122962306a36Sopenharmony_ci	do {
123062306a36Sopenharmony_ci		p = xdr_inline_decode(xdr, sizeof(*p));
123162306a36Sopenharmony_ci		if (unlikely(!p))
123262306a36Sopenharmony_ci			return -EIO;
123362306a36Sopenharmony_ci		if (xdr_item_is_absent(p))
123462306a36Sopenharmony_ci			break;
123562306a36Sopenharmony_ci		if (!first)
123662306a36Sopenharmony_ci			return -EIO;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci		if (decode_write_chunk(xdr, &chunklen))
123962306a36Sopenharmony_ci			return -EIO;
124062306a36Sopenharmony_ci		*length += chunklen;
124162306a36Sopenharmony_ci		first = false;
124262306a36Sopenharmony_ci	} while (true);
124362306a36Sopenharmony_ci	return 0;
124462306a36Sopenharmony_ci}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_cistatic int decode_reply_chunk(struct xdr_stream *xdr, u32 *length)
124762306a36Sopenharmony_ci{
124862306a36Sopenharmony_ci	__be32 *p;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, sizeof(*p));
125162306a36Sopenharmony_ci	if (unlikely(!p))
125262306a36Sopenharmony_ci		return -EIO;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	*length = 0;
125562306a36Sopenharmony_ci	if (xdr_item_is_present(p))
125662306a36Sopenharmony_ci		if (decode_write_chunk(xdr, length))
125762306a36Sopenharmony_ci			return -EIO;
125862306a36Sopenharmony_ci	return 0;
125962306a36Sopenharmony_ci}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_cistatic int
126262306a36Sopenharmony_cirpcrdma_decode_msg(struct rpcrdma_xprt *r_xprt, struct rpcrdma_rep *rep,
126362306a36Sopenharmony_ci		   struct rpc_rqst *rqst)
126462306a36Sopenharmony_ci{
126562306a36Sopenharmony_ci	struct xdr_stream *xdr = &rep->rr_stream;
126662306a36Sopenharmony_ci	u32 writelist, replychunk, rpclen;
126762306a36Sopenharmony_ci	char *base;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	/* Decode the chunk lists */
127062306a36Sopenharmony_ci	if (decode_read_list(xdr))
127162306a36Sopenharmony_ci		return -EIO;
127262306a36Sopenharmony_ci	if (decode_write_list(xdr, &writelist))
127362306a36Sopenharmony_ci		return -EIO;
127462306a36Sopenharmony_ci	if (decode_reply_chunk(xdr, &replychunk))
127562306a36Sopenharmony_ci		return -EIO;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	/* RDMA_MSG sanity checks */
127862306a36Sopenharmony_ci	if (unlikely(replychunk))
127962306a36Sopenharmony_ci		return -EIO;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	/* Build the RPC reply's Payload stream in rqst->rq_rcv_buf */
128262306a36Sopenharmony_ci	base = (char *)xdr_inline_decode(xdr, 0);
128362306a36Sopenharmony_ci	rpclen = xdr_stream_remaining(xdr);
128462306a36Sopenharmony_ci	r_xprt->rx_stats.fixup_copy_count +=
128562306a36Sopenharmony_ci		rpcrdma_inline_fixup(rqst, base, rpclen, writelist & 3);
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	r_xprt->rx_stats.total_rdma_reply += writelist;
128862306a36Sopenharmony_ci	return rpclen + xdr_align_size(writelist);
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_cistatic noinline int
129262306a36Sopenharmony_cirpcrdma_decode_nomsg(struct rpcrdma_xprt *r_xprt, struct rpcrdma_rep *rep)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	struct xdr_stream *xdr = &rep->rr_stream;
129562306a36Sopenharmony_ci	u32 writelist, replychunk;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	/* Decode the chunk lists */
129862306a36Sopenharmony_ci	if (decode_read_list(xdr))
129962306a36Sopenharmony_ci		return -EIO;
130062306a36Sopenharmony_ci	if (decode_write_list(xdr, &writelist))
130162306a36Sopenharmony_ci		return -EIO;
130262306a36Sopenharmony_ci	if (decode_reply_chunk(xdr, &replychunk))
130362306a36Sopenharmony_ci		return -EIO;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	/* RDMA_NOMSG sanity checks */
130662306a36Sopenharmony_ci	if (unlikely(writelist))
130762306a36Sopenharmony_ci		return -EIO;
130862306a36Sopenharmony_ci	if (unlikely(!replychunk))
130962306a36Sopenharmony_ci		return -EIO;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	/* Reply chunk buffer already is the reply vector */
131262306a36Sopenharmony_ci	r_xprt->rx_stats.total_rdma_reply += replychunk;
131362306a36Sopenharmony_ci	return replychunk;
131462306a36Sopenharmony_ci}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_cistatic noinline int
131762306a36Sopenharmony_cirpcrdma_decode_error(struct rpcrdma_xprt *r_xprt, struct rpcrdma_rep *rep,
131862306a36Sopenharmony_ci		     struct rpc_rqst *rqst)
131962306a36Sopenharmony_ci{
132062306a36Sopenharmony_ci	struct xdr_stream *xdr = &rep->rr_stream;
132162306a36Sopenharmony_ci	__be32 *p;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, sizeof(*p));
132462306a36Sopenharmony_ci	if (unlikely(!p))
132562306a36Sopenharmony_ci		return -EIO;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	switch (*p) {
132862306a36Sopenharmony_ci	case err_vers:
132962306a36Sopenharmony_ci		p = xdr_inline_decode(xdr, 2 * sizeof(*p));
133062306a36Sopenharmony_ci		if (!p)
133162306a36Sopenharmony_ci			break;
133262306a36Sopenharmony_ci		trace_xprtrdma_err_vers(rqst, p, p + 1);
133362306a36Sopenharmony_ci		break;
133462306a36Sopenharmony_ci	case err_chunk:
133562306a36Sopenharmony_ci		trace_xprtrdma_err_chunk(rqst);
133662306a36Sopenharmony_ci		break;
133762306a36Sopenharmony_ci	default:
133862306a36Sopenharmony_ci		trace_xprtrdma_err_unrecognized(rqst, p);
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	return -EIO;
134262306a36Sopenharmony_ci}
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci/**
134562306a36Sopenharmony_ci * rpcrdma_unpin_rqst - Release rqst without completing it
134662306a36Sopenharmony_ci * @rep: RPC/RDMA Receive context
134762306a36Sopenharmony_ci *
134862306a36Sopenharmony_ci * This is done when a connection is lost so that a Reply
134962306a36Sopenharmony_ci * can be dropped and its matching Call can be subsequently
135062306a36Sopenharmony_ci * retransmitted on a new connection.
135162306a36Sopenharmony_ci */
135262306a36Sopenharmony_civoid rpcrdma_unpin_rqst(struct rpcrdma_rep *rep)
135362306a36Sopenharmony_ci{
135462306a36Sopenharmony_ci	struct rpc_xprt *xprt = &rep->rr_rxprt->rx_xprt;
135562306a36Sopenharmony_ci	struct rpc_rqst *rqst = rep->rr_rqst;
135662306a36Sopenharmony_ci	struct rpcrdma_req *req = rpcr_to_rdmar(rqst);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	req->rl_reply = NULL;
135962306a36Sopenharmony_ci	rep->rr_rqst = NULL;
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	spin_lock(&xprt->queue_lock);
136262306a36Sopenharmony_ci	xprt_unpin_rqst(rqst);
136362306a36Sopenharmony_ci	spin_unlock(&xprt->queue_lock);
136462306a36Sopenharmony_ci}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci/**
136762306a36Sopenharmony_ci * rpcrdma_complete_rqst - Pass completed rqst back to RPC
136862306a36Sopenharmony_ci * @rep: RPC/RDMA Receive context
136962306a36Sopenharmony_ci *
137062306a36Sopenharmony_ci * Reconstruct the RPC reply and complete the transaction
137162306a36Sopenharmony_ci * while @rqst is still pinned to ensure the rep, rqst, and
137262306a36Sopenharmony_ci * rq_task pointers remain stable.
137362306a36Sopenharmony_ci */
137462306a36Sopenharmony_civoid rpcrdma_complete_rqst(struct rpcrdma_rep *rep)
137562306a36Sopenharmony_ci{
137662306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt = rep->rr_rxprt;
137762306a36Sopenharmony_ci	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
137862306a36Sopenharmony_ci	struct rpc_rqst *rqst = rep->rr_rqst;
137962306a36Sopenharmony_ci	int status;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	switch (rep->rr_proc) {
138262306a36Sopenharmony_ci	case rdma_msg:
138362306a36Sopenharmony_ci		status = rpcrdma_decode_msg(r_xprt, rep, rqst);
138462306a36Sopenharmony_ci		break;
138562306a36Sopenharmony_ci	case rdma_nomsg:
138662306a36Sopenharmony_ci		status = rpcrdma_decode_nomsg(r_xprt, rep);
138762306a36Sopenharmony_ci		break;
138862306a36Sopenharmony_ci	case rdma_error:
138962306a36Sopenharmony_ci		status = rpcrdma_decode_error(r_xprt, rep, rqst);
139062306a36Sopenharmony_ci		break;
139162306a36Sopenharmony_ci	default:
139262306a36Sopenharmony_ci		status = -EIO;
139362306a36Sopenharmony_ci	}
139462306a36Sopenharmony_ci	if (status < 0)
139562306a36Sopenharmony_ci		goto out_badheader;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ciout:
139862306a36Sopenharmony_ci	spin_lock(&xprt->queue_lock);
139962306a36Sopenharmony_ci	xprt_complete_rqst(rqst->rq_task, status);
140062306a36Sopenharmony_ci	xprt_unpin_rqst(rqst);
140162306a36Sopenharmony_ci	spin_unlock(&xprt->queue_lock);
140262306a36Sopenharmony_ci	return;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ciout_badheader:
140562306a36Sopenharmony_ci	trace_xprtrdma_reply_hdr_err(rep);
140662306a36Sopenharmony_ci	r_xprt->rx_stats.bad_reply_count++;
140762306a36Sopenharmony_ci	rqst->rq_task->tk_status = status;
140862306a36Sopenharmony_ci	status = 0;
140962306a36Sopenharmony_ci	goto out;
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_cistatic void rpcrdma_reply_done(struct kref *kref)
141362306a36Sopenharmony_ci{
141462306a36Sopenharmony_ci	struct rpcrdma_req *req =
141562306a36Sopenharmony_ci		container_of(kref, struct rpcrdma_req, rl_kref);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	rpcrdma_complete_rqst(req->rl_reply);
141862306a36Sopenharmony_ci}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci/**
142162306a36Sopenharmony_ci * rpcrdma_reply_handler - Process received RPC/RDMA messages
142262306a36Sopenharmony_ci * @rep: Incoming rpcrdma_rep object to process
142362306a36Sopenharmony_ci *
142462306a36Sopenharmony_ci * Errors must result in the RPC task either being awakened, or
142562306a36Sopenharmony_ci * allowed to timeout, to discover the errors at that time.
142662306a36Sopenharmony_ci */
142762306a36Sopenharmony_civoid rpcrdma_reply_handler(struct rpcrdma_rep *rep)
142862306a36Sopenharmony_ci{
142962306a36Sopenharmony_ci	struct rpcrdma_xprt *r_xprt = rep->rr_rxprt;
143062306a36Sopenharmony_ci	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
143162306a36Sopenharmony_ci	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
143262306a36Sopenharmony_ci	struct rpcrdma_req *req;
143362306a36Sopenharmony_ci	struct rpc_rqst *rqst;
143462306a36Sopenharmony_ci	u32 credits;
143562306a36Sopenharmony_ci	__be32 *p;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	/* Any data means we had a useful conversation, so
143862306a36Sopenharmony_ci	 * then we don't need to delay the next reconnect.
143962306a36Sopenharmony_ci	 */
144062306a36Sopenharmony_ci	if (xprt->reestablish_timeout)
144162306a36Sopenharmony_ci		xprt->reestablish_timeout = 0;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	/* Fixed transport header fields */
144462306a36Sopenharmony_ci	xdr_init_decode(&rep->rr_stream, &rep->rr_hdrbuf,
144562306a36Sopenharmony_ci			rep->rr_hdrbuf.head[0].iov_base, NULL);
144662306a36Sopenharmony_ci	p = xdr_inline_decode(&rep->rr_stream, 4 * sizeof(*p));
144762306a36Sopenharmony_ci	if (unlikely(!p))
144862306a36Sopenharmony_ci		goto out_shortreply;
144962306a36Sopenharmony_ci	rep->rr_xid = *p++;
145062306a36Sopenharmony_ci	rep->rr_vers = *p++;
145162306a36Sopenharmony_ci	credits = be32_to_cpu(*p++);
145262306a36Sopenharmony_ci	rep->rr_proc = *p++;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	if (rep->rr_vers != rpcrdma_version)
145562306a36Sopenharmony_ci		goto out_badversion;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	if (rpcrdma_is_bcall(r_xprt, rep))
145862306a36Sopenharmony_ci		return;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	/* Match incoming rpcrdma_rep to an rpcrdma_req to
146162306a36Sopenharmony_ci	 * get context for handling any incoming chunks.
146262306a36Sopenharmony_ci	 */
146362306a36Sopenharmony_ci	spin_lock(&xprt->queue_lock);
146462306a36Sopenharmony_ci	rqst = xprt_lookup_rqst(xprt, rep->rr_xid);
146562306a36Sopenharmony_ci	if (!rqst)
146662306a36Sopenharmony_ci		goto out_norqst;
146762306a36Sopenharmony_ci	xprt_pin_rqst(rqst);
146862306a36Sopenharmony_ci	spin_unlock(&xprt->queue_lock);
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	if (credits == 0)
147162306a36Sopenharmony_ci		credits = 1;	/* don't deadlock */
147262306a36Sopenharmony_ci	else if (credits > r_xprt->rx_ep->re_max_requests)
147362306a36Sopenharmony_ci		credits = r_xprt->rx_ep->re_max_requests;
147462306a36Sopenharmony_ci	rpcrdma_post_recvs(r_xprt, credits + (buf->rb_bc_srv_max_requests << 1),
147562306a36Sopenharmony_ci			   false);
147662306a36Sopenharmony_ci	if (buf->rb_credits != credits)
147762306a36Sopenharmony_ci		rpcrdma_update_cwnd(r_xprt, credits);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	req = rpcr_to_rdmar(rqst);
148062306a36Sopenharmony_ci	if (unlikely(req->rl_reply))
148162306a36Sopenharmony_ci		rpcrdma_rep_put(buf, req->rl_reply);
148262306a36Sopenharmony_ci	req->rl_reply = rep;
148362306a36Sopenharmony_ci	rep->rr_rqst = rqst;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	trace_xprtrdma_reply(rqst->rq_task, rep, credits);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	if (rep->rr_wc_flags & IB_WC_WITH_INVALIDATE)
148862306a36Sopenharmony_ci		frwr_reminv(rep, &req->rl_registered);
148962306a36Sopenharmony_ci	if (!list_empty(&req->rl_registered))
149062306a36Sopenharmony_ci		frwr_unmap_async(r_xprt, req);
149162306a36Sopenharmony_ci		/* LocalInv completion will complete the RPC */
149262306a36Sopenharmony_ci	else
149362306a36Sopenharmony_ci		kref_put(&req->rl_kref, rpcrdma_reply_done);
149462306a36Sopenharmony_ci	return;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ciout_badversion:
149762306a36Sopenharmony_ci	trace_xprtrdma_reply_vers_err(rep);
149862306a36Sopenharmony_ci	goto out;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ciout_norqst:
150162306a36Sopenharmony_ci	spin_unlock(&xprt->queue_lock);
150262306a36Sopenharmony_ci	trace_xprtrdma_reply_rqst_err(rep);
150362306a36Sopenharmony_ci	goto out;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ciout_shortreply:
150662306a36Sopenharmony_ci	trace_xprtrdma_reply_short_err(rep);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ciout:
150962306a36Sopenharmony_ci	rpcrdma_rep_put(buf, rep);
151062306a36Sopenharmony_ci}
1511