2 * Copyright (c) 2016 Oracle. All rights reserved.
3 * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the BSD-type
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
15 * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
18 * Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials provided
21 * with the distribution.
23 * Neither the name of the Network Appliance, Inc. nor the names of
24 * its contributors may be used to endorse or promote products
25 * derived from this software without specific prior written
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 * Author: Tom Tucker <tom@opengridcomputing.com>
43 #include <linux/sunrpc/xdr.h>
44 #include <linux/sunrpc/debug.h>
45 #include <asm/unaligned.h>
46 #include <linux/sunrpc/rpc_rdma.h>
47 #include <linux/sunrpc/svc_rdma.h>
49 #define RPCDBG_FACILITY RPCDBG_SVCXPRT
51 static __be32
*xdr_check_read_list(__be32
*p
, __be32
*end
)
55 while (*p
++ != xdr_zero
) {
56 next
= p
+ rpcrdma_readchunk_maxsz
- 1;
64 static __be32
*xdr_check_write_list(__be32
*p
, __be32
*end
)
68 while (*p
++ != xdr_zero
) {
69 next
= p
+ 1 + be32_to_cpup(p
) * rpcrdma_segment_maxsz
;
77 static __be32
*xdr_check_reply_chunk(__be32
*p
, __be32
*end
)
81 if (*p
++ != xdr_zero
) {
82 next
= p
+ 1 + be32_to_cpup(p
) * rpcrdma_segment_maxsz
;
91 * svc_rdma_xdr_decode_req - Parse incoming RPC-over-RDMA header
92 * @rq_arg: Receive buffer
94 * On entry, xdr->head[0].iov_base points to first byte in the
95 * RPC-over-RDMA header.
97 * On successful exit, head[0] points to first byte past the
98 * RPC-over-RDMA header. For RDMA_MSG, this is the RPC message.
99 * The length of the RPC-over-RDMA header is returned.
101 int svc_rdma_xdr_decode_req(struct xdr_buf
*rq_arg
)
103 __be32
*p
, *end
, *rdma_argp
;
104 unsigned int hdr_len
;
106 /* Verify that there's enough bytes for header + something */
107 if (rq_arg
->len
<= RPCRDMA_HDRLEN_ERR
)
110 rdma_argp
= rq_arg
->head
[0].iov_base
;
111 if (*(rdma_argp
+ 1) != rpcrdma_version
)
114 switch (*(rdma_argp
+ 3)) {
129 end
= (__be32
*)((unsigned long)rdma_argp
+ rq_arg
->len
);
130 p
= xdr_check_read_list(rdma_argp
+ 4, end
);
133 p
= xdr_check_write_list(p
, end
);
136 p
= xdr_check_reply_chunk(p
, end
);
142 rq_arg
->head
[0].iov_base
= p
;
143 hdr_len
= (unsigned long)p
- (unsigned long)rdma_argp
;
144 rq_arg
->head
[0].iov_len
-= hdr_len
;
148 dprintk("svcrdma: header too short = %d\n", rq_arg
->len
);
152 dprintk("svcrdma: bad xprt version: %u\n",
153 be32_to_cpup(rdma_argp
+ 1));
154 return -EPROTONOSUPPORT
;
157 dprintk("svcrdma: dropping RDMA_DONE/ERROR message\n");
161 dprintk("svcrdma: bad rdma procedure (%u)\n",
162 be32_to_cpup(rdma_argp
+ 3));
166 dprintk("svcrdma: failed to parse transport header\n");
170 int svc_rdma_xdr_encode_error(struct svcxprt_rdma
*xprt
,
171 struct rpcrdma_msg
*rmsgp
,
172 enum rpcrdma_errcode err
, __be32
*va
)
176 *va
++ = rmsgp
->rm_xid
;
177 *va
++ = rmsgp
->rm_vers
;
178 *va
++ = xprt
->sc_fc_credits
;
180 *va
++ = cpu_to_be32(err
);
181 if (err
== ERR_VERS
) {
182 *va
++ = rpcrdma_version
;
183 *va
++ = rpcrdma_version
;
186 return (int)((unsigned long)va
- (unsigned long)startp
);
190 * svc_rdma_xdr_get_reply_hdr_length - Get length of Reply transport header
191 * @rdma_resp: buffer containing Reply transport header
193 * Returns length of transport header, in bytes.
195 unsigned int svc_rdma_xdr_get_reply_hdr_len(__be32
*rdma_resp
)
202 /* RPC-over-RDMA V1 replies never have a Read list. */
203 p
+= rpcrdma_fixed_maxsz
+ 1;
205 /* Skip Write list. */
206 while (*p
++ != xdr_zero
) {
207 nsegs
= be32_to_cpup(p
++);
208 p
+= nsegs
* rpcrdma_segment_maxsz
;
211 /* Skip Reply chunk. */
212 if (*p
++ != xdr_zero
) {
213 nsegs
= be32_to_cpup(p
++);
214 p
+= nsegs
* rpcrdma_segment_maxsz
;
217 return (unsigned long)p
- (unsigned long)rdma_resp
;
220 void svc_rdma_xdr_encode_write_list(struct rpcrdma_msg
*rmsgp
, int chunks
)
222 struct rpcrdma_write_array
*ary
;
225 rmsgp
->rm_body
.rm_chunks
[0] = xdr_zero
;
227 /* write-array discrim */
228 ary
= (struct rpcrdma_write_array
*)
229 &rmsgp
->rm_body
.rm_chunks
[1];
230 ary
->wc_discrim
= xdr_one
;
231 ary
->wc_nchunks
= cpu_to_be32(chunks
);
233 /* write-list terminator */
234 ary
->wc_array
[chunks
].wc_target
.rs_handle
= xdr_zero
;
236 /* reply-array discriminator */
237 ary
->wc_array
[chunks
].wc_target
.rs_length
= xdr_zero
;
240 void svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array
*ary
,
243 ary
->wc_discrim
= xdr_one
;
244 ary
->wc_nchunks
= cpu_to_be32(chunks
);
247 void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array
*ary
,
253 struct rpcrdma_segment
*seg
= &ary
->wc_array
[chunk_no
].wc_target
;
254 seg
->rs_handle
= rs_handle
;
255 seg
->rs_offset
= rs_offset
;
256 seg
->rs_length
= cpu_to_be32(write_len
);