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