1ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker/*
2ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
3ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *
4ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * This software is available to you under a choice of one of two
5ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * licenses.  You may choose to be licensed under the terms of the GNU
6ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * General Public License (GPL) Version 2, available from the file
7ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * COPYING in the main directory of this source tree, or the BSD-type
8ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * license below:
9ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *
10ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * Redistribution and use in source and binary forms, with or without
11ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * modification, are permitted provided that the following conditions
12ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * are met:
13ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *
14ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *      Redistributions of source code must retain the above copyright
15ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *      notice, this list of conditions and the following disclaimer.
16ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *
17ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *      Redistributions in binary form must reproduce the above
18ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *      copyright notice, this list of conditions and the following
19ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *      disclaimer in the documentation and/or other materials provided
20ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *      with the distribution.
21ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *
22ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *      Neither the name of the Network Appliance, Inc. nor the names of
23ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *      its contributors may be used to endorse or promote products
24ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *      derived from this software without specific prior written
25ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *      permission.
26ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *
27ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *
39ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * Author: Tom Tucker <tom@opengridcomputing.com>
40ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker */
41ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
42ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker#include <linux/sunrpc/xdr.h>
43ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker#include <linux/sunrpc/debug.h>
44ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker#include <asm/unaligned.h>
45ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker#include <linux/sunrpc/rpc_rdma.h>
46ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker#include <linux/sunrpc/svc_rdma.h>
47ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
48ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker#define RPCDBG_FACILITY	RPCDBG_SVCXPRT
49ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
50ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker/*
51ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * Decodes a read chunk list. The expected format is as follows:
52ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *    descrim  : xdr_one
53ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *    position : u32 offset into XDR stream
54ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *    handle   : u32 RKEY
55ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *    . . .
56ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *  end-of-list: xdr_zero
57ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker */
58ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tuckerstatic u32 *decode_read_list(u32 *va, u32 *vaend)
59ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker{
60ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	struct rpcrdma_read_chunk *ch = (struct rpcrdma_read_chunk *)va;
61ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
62ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	while (ch->rc_discrim != xdr_zero) {
63ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		if (((unsigned long)ch + sizeof(struct rpcrdma_read_chunk)) >
64ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		    (unsigned long)vaend) {
65ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			dprintk("svcrdma: vaend=%p, ch=%p\n", vaend, ch);
66ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			return NULL;
67ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		}
68ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		ch++;
69ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	}
70ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	return (u32 *)&ch->rc_position;
71ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker}
72ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
73ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker/*
74ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * Determine number of chunks and total bytes in chunk list. The chunk
75ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * list has already been verified to fit within the RPCRDMA header.
76ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker */
77ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tuckervoid svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *ch,
78ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			       int *ch_count, int *byte_count)
79ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker{
80ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* compute the number of bytes represented by read chunks */
81ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	*byte_count = 0;
82ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	*ch_count = 0;
83ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	for (; ch->rc_discrim != 0; ch++) {
84cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker		*byte_count = *byte_count + ntohl(ch->rc_target.rs_length);
85ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		*ch_count = *ch_count + 1;
86ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	}
87ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker}
88ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
89ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker/*
90ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker * Decodes a write chunk list. The expected format is as follows:
91ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *    descrim  : xdr_one
92ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *    nchunks  : <count>
93ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *       handle   : u32 RKEY              ---+
94ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *       length   : u32 <len of segment>     |
95ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *       offset   : remove va                + <count>
96ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *       . . .                               |
97ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker *                                        ---+
98ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker */
99ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tuckerstatic u32 *decode_write_list(u32 *va, u32 *vaend)
100ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker{
101b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter	unsigned long start, end;
102cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker	int nchunks;
103cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker
104ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	struct rpcrdma_write_array *ary =
105ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		(struct rpcrdma_write_array *)va;
106ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
107ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* Check for not write-array */
108ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (ary->wc_discrim == xdr_zero)
109ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return (u32 *)&ary->wc_nchunks;
110ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
111ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) >
112ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	    (unsigned long)vaend) {
113ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
114ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return NULL;
115ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	}
116cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker	nchunks = ntohl(ary->wc_nchunks);
117b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter
118b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter	start = (unsigned long)&ary->wc_array[0];
119b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter	end = (unsigned long)vaend;
120b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter	if (nchunks < 0 ||
121b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter	    nchunks > (SIZE_MAX - start) / sizeof(struct rpcrdma_write_chunk) ||
122b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter	    (start + (sizeof(struct rpcrdma_write_chunk) * nchunks)) > end) {
123ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
124cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker			ary, nchunks, vaend);
125ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return NULL;
126ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	}
127ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/*
128ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	 * rs_length is the 2nd 4B field in wc_target and taking its
129ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	 * address skips the list terminator
130ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	 */
131cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker	return (u32 *)&ary->wc_array[nchunks].wc_target.rs_length;
132ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker}
133ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
134ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tuckerstatic u32 *decode_reply_array(u32 *va, u32 *vaend)
135ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker{
136b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter	unsigned long start, end;
137cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker	int nchunks;
138ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	struct rpcrdma_write_array *ary =
139ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		(struct rpcrdma_write_array *)va;
140ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
141ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* Check for no reply-array */
142ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (ary->wc_discrim == xdr_zero)
143ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return (u32 *)&ary->wc_nchunks;
144ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
145ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) >
146ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	    (unsigned long)vaend) {
147ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
148ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return NULL;
149ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	}
150cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker	nchunks = ntohl(ary->wc_nchunks);
151b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter
152b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter	start = (unsigned long)&ary->wc_array[0];
153b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter	end = (unsigned long)vaend;
154b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter	if (nchunks < 0 ||
155b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter	    nchunks > (SIZE_MAX - start) / sizeof(struct rpcrdma_write_chunk) ||
156b2781e1021525649c0b33fffd005ef219da33926Dan Carpenter	    (start + (sizeof(struct rpcrdma_write_chunk) * nchunks)) > end) {
157ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
158cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker			ary, nchunks, vaend);
159ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return NULL;
160ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	}
161cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker	return (u32 *)&ary->wc_array[nchunks];
162ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker}
163ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
164ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tuckerint svc_rdma_xdr_decode_req(struct rpcrdma_msg **rdma_req,
165ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			    struct svc_rqst *rqstp)
166ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker{
167ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	struct rpcrdma_msg *rmsgp = NULL;
168ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	u32 *va;
169ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	u32 *vaend;
170ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	u32 hdr_len;
171ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
172ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rmsgp = (struct rpcrdma_msg *)rqstp->rq_arg.head[0].iov_base;
173ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
174ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* Verify that there's enough bytes for header + something */
175ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (rqstp->rq_arg.len <= RPCRDMA_HDRLEN_MIN) {
176ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		dprintk("svcrdma: header too short = %d\n",
177ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			rqstp->rq_arg.len);
178ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return -EINVAL;
179ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	}
180ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
181ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* Decode the header */
182ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rmsgp->rm_xid = ntohl(rmsgp->rm_xid);
183ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rmsgp->rm_vers = ntohl(rmsgp->rm_vers);
184ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rmsgp->rm_credit = ntohl(rmsgp->rm_credit);
185ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rmsgp->rm_type = ntohl(rmsgp->rm_type);
186ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
187ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (rmsgp->rm_vers != RPCRDMA_VERSION)
188ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return -ENOSYS;
189ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
190ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* Pull in the extra for the padded case and bump our pointer */
191ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (rmsgp->rm_type == RDMA_MSGP) {
192ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		int hdrlen;
193ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		rmsgp->rm_body.rm_padded.rm_align =
194ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			ntohl(rmsgp->rm_body.rm_padded.rm_align);
195ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		rmsgp->rm_body.rm_padded.rm_thresh =
196ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			ntohl(rmsgp->rm_body.rm_padded.rm_thresh);
197ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
198ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		va = &rmsgp->rm_body.rm_padded.rm_pempty[4];
199ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		rqstp->rq_arg.head[0].iov_base = va;
200ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		hdrlen = (u32)((unsigned long)va - (unsigned long)rmsgp);
201ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		rqstp->rq_arg.head[0].iov_len -= hdrlen;
202ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		if (hdrlen > rqstp->rq_arg.len)
203ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			return -EINVAL;
204ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return hdrlen;
205ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	}
206ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
207ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* The chunk list may contain either a read chunk list or a write
208ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	 * chunk list and a reply chunk list.
209ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	 */
210ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	va = &rmsgp->rm_body.rm_chunks[0];
211ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	vaend = (u32 *)((unsigned long)rmsgp + rqstp->rq_arg.len);
212ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	va = decode_read_list(va, vaend);
213ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (!va)
214ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return -EINVAL;
215ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	va = decode_write_list(va, vaend);
216ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (!va)
217ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return -EINVAL;
218ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	va = decode_reply_array(va, vaend);
219ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (!va)
220ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return -EINVAL;
221ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
222ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rqstp->rq_arg.head[0].iov_base = va;
223ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	hdr_len = (unsigned long)va - (unsigned long)rmsgp;
224ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rqstp->rq_arg.head[0].iov_len -= hdr_len;
225ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
226ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	*rdma_req = rmsgp;
227ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	return hdr_len;
228ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker}
229ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
230ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tuckerint svc_rdma_xdr_decode_deferred_req(struct svc_rqst *rqstp)
231ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker{
232ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	struct rpcrdma_msg *rmsgp = NULL;
233ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	struct rpcrdma_read_chunk *ch;
234ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	struct rpcrdma_write_array *ary;
235ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	u32 *va;
236ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	u32 hdrlen;
237ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
238ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	dprintk("svcrdma: processing deferred RDMA header on rqstp=%p\n",
239ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		rqstp);
240ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rmsgp = (struct rpcrdma_msg *)rqstp->rq_arg.head[0].iov_base;
241ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
242ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* Pull in the extra for the padded case and bump our pointer */
243ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (rmsgp->rm_type == RDMA_MSGP) {
244ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		va = &rmsgp->rm_body.rm_padded.rm_pempty[4];
245ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		rqstp->rq_arg.head[0].iov_base = va;
246ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		hdrlen = (u32)((unsigned long)va - (unsigned long)rmsgp);
247ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		rqstp->rq_arg.head[0].iov_len -= hdrlen;
248ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		return hdrlen;
249ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	}
250ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
251ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/*
252ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	 * Skip all chunks to find RPC msg. These were previously processed
253ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	 */
254ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	va = &rmsgp->rm_body.rm_chunks[0];
255ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
256ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* Skip read-list */
257ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	for (ch = (struct rpcrdma_read_chunk *)va;
258ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	     ch->rc_discrim != xdr_zero; ch++);
259ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	va = (u32 *)&ch->rc_position;
260ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
261ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* Skip write-list */
262ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	ary = (struct rpcrdma_write_array *)va;
263ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (ary->wc_discrim == xdr_zero)
264ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		va = (u32 *)&ary->wc_nchunks;
265ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	else
266ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		/*
267ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		 * rs_length is the 2nd 4B field in wc_target and taking its
268ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		 * address skips the list terminator
269ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		 */
270ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		va = (u32 *)&ary->wc_array[ary->wc_nchunks].wc_target.rs_length;
271ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
272ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* Skip reply-array */
273ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	ary = (struct rpcrdma_write_array *)va;
274ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (ary->wc_discrim == xdr_zero)
275ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		va = (u32 *)&ary->wc_nchunks;
276ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	else
277ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		va = (u32 *)&ary->wc_array[ary->wc_nchunks];
278ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
279ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rqstp->rq_arg.head[0].iov_base = va;
280ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	hdrlen = (unsigned long)va - (unsigned long)rmsgp;
281ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rqstp->rq_arg.head[0].iov_len -= hdrlen;
282ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
283ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	return hdrlen;
284ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker}
285ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
286ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tuckerint svc_rdma_xdr_encode_error(struct svcxprt_rdma *xprt,
287ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			      struct rpcrdma_msg *rmsgp,
288ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			      enum rpcrdma_errcode err, u32 *va)
289ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker{
290ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	u32 *startp = va;
291ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
292ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	*va++ = htonl(rmsgp->rm_xid);
293ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	*va++ = htonl(rmsgp->rm_vers);
294ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	*va++ = htonl(xprt->sc_max_requests);
295ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	*va++ = htonl(RDMA_ERROR);
296ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	*va++ = htonl(err);
297ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (err == ERR_VERS) {
298ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		*va++ = htonl(RPCRDMA_VERSION);
299ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		*va++ = htonl(RPCRDMA_VERSION);
300ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	}
301ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
302ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	return (int)((unsigned long)va - (unsigned long)startp);
303ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker}
304ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
305ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tuckerint svc_rdma_xdr_get_reply_hdr_len(struct rpcrdma_msg *rmsgp)
306ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker{
307ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	struct rpcrdma_write_array *wr_ary;
308ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
309ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* There is no read-list in a reply */
310ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
311ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* skip write list */
312ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	wr_ary = (struct rpcrdma_write_array *)
313ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		&rmsgp->rm_body.rm_chunks[1];
314ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (wr_ary->wc_discrim)
315ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		wr_ary = (struct rpcrdma_write_array *)
316ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			&wr_ary->wc_array[ntohl(wr_ary->wc_nchunks)].
317ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			wc_target.rs_length;
318ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	else
319ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		wr_ary = (struct rpcrdma_write_array *)
320ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			&wr_ary->wc_nchunks;
321ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
322ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* skip reply array */
323ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	if (wr_ary->wc_discrim)
324ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		wr_ary = (struct rpcrdma_write_array *)
325ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			&wr_ary->wc_array[ntohl(wr_ary->wc_nchunks)];
326ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	else
327ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		wr_ary = (struct rpcrdma_write_array *)
328ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker			&wr_ary->wc_nchunks;
329ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
330ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	return (unsigned long) wr_ary - (unsigned long) rmsgp;
331ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker}
332ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
333ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tuckervoid svc_rdma_xdr_encode_write_list(struct rpcrdma_msg *rmsgp, int chunks)
334ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker{
335ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	struct rpcrdma_write_array *ary;
336ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
337ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* no read-list */
338ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rmsgp->rm_body.rm_chunks[0] = xdr_zero;
339ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
340ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* write-array discrim */
341ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	ary = (struct rpcrdma_write_array *)
342ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker		&rmsgp->rm_body.rm_chunks[1];
343ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	ary->wc_discrim = xdr_one;
344ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	ary->wc_nchunks = htonl(chunks);
345ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
346ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* write-list terminator */
347ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	ary->wc_array[chunks].wc_target.rs_handle = xdr_zero;
348ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
349ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* reply-array discriminator */
350ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	ary->wc_array[chunks].wc_target.rs_length = xdr_zero;
351ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker}
352ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
353ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tuckervoid svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array *ary,
354ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker				 int chunks)
355ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker{
356ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	ary->wc_discrim = xdr_one;
357ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	ary->wc_nchunks = htonl(chunks);
358ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker}
359ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
360ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tuckervoid svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *ary,
361ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker				     int chunk_no,
362cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker				     __be32 rs_handle,
363cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker				     __be64 rs_offset,
364ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker				     u32 write_len)
365ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker{
366ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	struct rpcrdma_segment *seg = &ary->wc_array[chunk_no].wc_target;
367cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker	seg->rs_handle = rs_handle;
368cec56c8ff5e28f58ff13041dca7853738ae577a1Tom Tucker	seg->rs_offset = rs_offset;
369ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	seg->rs_length = htonl(write_len);
370ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker}
371ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
372ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tuckervoid svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *xprt,
373ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker				  struct rpcrdma_msg *rdma_argp,
374ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker				  struct rpcrdma_msg *rdma_resp,
375ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker				  enum rpcrdma_proc rdma_type)
376ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker{
377ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rdma_resp->rm_xid = htonl(rdma_argp->rm_xid);
378ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rdma_resp->rm_vers = htonl(rdma_argp->rm_vers);
379ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rdma_resp->rm_credit = htonl(xprt->sc_max_requests);
380ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rdma_resp->rm_type = htonl(rdma_type);
381ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker
382ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	/* Encode <nul> chunks lists */
383ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rdma_resp->rm_body.rm_chunks[0] = xdr_zero;
384ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rdma_resp->rm_body.rm_chunks[1] = xdr_zero;
385ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker	rdma_resp->rm_body.rm_chunks[2] = xdr_zero;
386ef1eac0a3fa86b06aa2d87021f157d13abc1903fTom Tucker}
387