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