xref: /illumos-gate/usr/src/uts/common/io/ib/clients/rdsv3/message.c (revision 94c3dad2979525d0a82595f3d8350a6116aba8ed)
1c0dd49bdSEiji Ota /*
2c0dd49bdSEiji Ota  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3c0dd49bdSEiji Ota  */
4c0dd49bdSEiji Ota 
5c0dd49bdSEiji Ota /*
616e76cddSagiri  * This file contains code imported from the OFED rds source file message.c
716e76cddSagiri  * Oracle elects to have and use the contents of message.c under and governed
816e76cddSagiri  * by the OpenIB.org BSD license (see below for full license text). However,
916e76cddSagiri  * the following notice accompanied the original version of this file:
1016e76cddSagiri  */
1116e76cddSagiri 
1216e76cddSagiri /*
13c0dd49bdSEiji Ota  * Copyright (c) 2006 Oracle.  All rights reserved.
14c0dd49bdSEiji Ota  *
15c0dd49bdSEiji Ota  * This software is available to you under a choice of one of two
16c0dd49bdSEiji Ota  * licenses.  You may choose to be licensed under the terms of the GNU
17c0dd49bdSEiji Ota  * General Public License (GPL) Version 2, available from the file
18c0dd49bdSEiji Ota  * COPYING in the main directory of this source tree, or the
19c0dd49bdSEiji Ota  * OpenIB.org BSD license below:
20c0dd49bdSEiji Ota  *
21c0dd49bdSEiji Ota  *     Redistribution and use in source and binary forms, with or
22c0dd49bdSEiji Ota  *     without modification, are permitted provided that the following
23c0dd49bdSEiji Ota  *     conditions are met:
24c0dd49bdSEiji Ota  *
25c0dd49bdSEiji Ota  *      - Redistributions of source code must retain the above
26c0dd49bdSEiji Ota  *        copyright notice, this list of conditions and the following
27c0dd49bdSEiji Ota  *        disclaimer.
28c0dd49bdSEiji Ota  *
29c0dd49bdSEiji Ota  *      - Redistributions in binary form must reproduce the above
30c0dd49bdSEiji Ota  *        copyright notice, this list of conditions and the following
31c0dd49bdSEiji Ota  *        disclaimer in the documentation and/or other materials
32c0dd49bdSEiji Ota  *        provided with the distribution.
33c0dd49bdSEiji Ota  *
34c0dd49bdSEiji Ota  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
35c0dd49bdSEiji Ota  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
36c0dd49bdSEiji Ota  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
37c0dd49bdSEiji Ota  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
38c0dd49bdSEiji Ota  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
39c0dd49bdSEiji Ota  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
40c0dd49bdSEiji Ota  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
41c0dd49bdSEiji Ota  * SOFTWARE.
42c0dd49bdSEiji Ota  *
43c0dd49bdSEiji Ota  */
44c0dd49bdSEiji Ota #include <sys/rds.h>
45*94c3dad2SToomas Soome #include <sys/containerof.h>
46c0dd49bdSEiji Ota 
47c0dd49bdSEiji Ota #include <sys/ib/clients/rdsv3/rdsv3.h>
48c0dd49bdSEiji Ota #include <sys/ib/clients/rdsv3/rdma.h>
49c0dd49bdSEiji Ota #include <sys/ib/clients/rdsv3/rdsv3_debug.h>
50c0dd49bdSEiji Ota 
51c0dd49bdSEiji Ota #ifndef __lock_lint
52c0dd49bdSEiji Ota static unsigned int	rdsv3_exthdr_size[__RDSV3_EXTHDR_MAX] = {
53c0dd49bdSEiji Ota [RDSV3_EXTHDR_NONE]	= 0,
54c0dd49bdSEiji Ota [RDSV3_EXTHDR_VERSION]	= sizeof (struct rdsv3_ext_header_version),
55c0dd49bdSEiji Ota [RDSV3_EXTHDR_RDMA]	= sizeof (struct rdsv3_ext_header_rdma),
56c0dd49bdSEiji Ota [RDSV3_EXTHDR_RDMA_DEST]	= sizeof (struct rdsv3_ext_header_rdma_dest),
57c0dd49bdSEiji Ota };
58c0dd49bdSEiji Ota #else
59c0dd49bdSEiji Ota static unsigned int	rdsv3_exthdr_size[__RDSV3_EXTHDR_MAX] = {
60c0dd49bdSEiji Ota 			0,
61c0dd49bdSEiji Ota 			sizeof (struct rdsv3_ext_header_version),
62c0dd49bdSEiji Ota 			sizeof (struct rdsv3_ext_header_rdma),
63c0dd49bdSEiji Ota 			sizeof (struct rdsv3_ext_header_rdma_dest),
64c0dd49bdSEiji Ota };
65c0dd49bdSEiji Ota #endif
66c0dd49bdSEiji Ota 
67c0dd49bdSEiji Ota void
rdsv3_message_addref(struct rdsv3_message * rm)68c0dd49bdSEiji Ota rdsv3_message_addref(struct rdsv3_message *rm)
69c0dd49bdSEiji Ota {
70c0dd49bdSEiji Ota 	RDSV3_DPRINTF5("rdsv3_message_addref", "addref rm %p ref %d",
71c0dd49bdSEiji Ota 	    rm, atomic_get(&rm->m_refcount));
721a5e258fSJosef 'Jeff' Sipek 	atomic_inc_32(&rm->m_refcount);
73c0dd49bdSEiji Ota }
74c0dd49bdSEiji Ota 
75c0dd49bdSEiji Ota /*
76c0dd49bdSEiji Ota  * This relies on dma_map_sg() not touching sg[].page during merging.
77c0dd49bdSEiji Ota  */
78c0dd49bdSEiji Ota static void
rdsv3_message_purge(struct rdsv3_message * rm)79c0dd49bdSEiji Ota rdsv3_message_purge(struct rdsv3_message *rm)
80c0dd49bdSEiji Ota {
81c0dd49bdSEiji Ota 	unsigned long i;
82c0dd49bdSEiji Ota 
83c0dd49bdSEiji Ota 	RDSV3_DPRINTF4("rdsv3_message_purge", "Enter(rm: %p)", rm);
84c0dd49bdSEiji Ota 
85c0dd49bdSEiji Ota 	if (test_bit(RDSV3_MSG_PAGEVEC, &rm->m_flags))
86c0dd49bdSEiji Ota 		return;
87c0dd49bdSEiji Ota 
88c0dd49bdSEiji Ota 	for (i = 0; i < rm->m_nents; i++) {
89c0dd49bdSEiji Ota 		RDSV3_DPRINTF5("rdsv3_message_purge", "putting data page %p\n",
90c0dd49bdSEiji Ota 		    (void *)rdsv3_sg_page(&rm->m_sg[i]));
91c0dd49bdSEiji Ota 		/* XXX will have to put_page for page refs */
92c0dd49bdSEiji Ota 		kmem_free(rdsv3_sg_page(&rm->m_sg[i]),
93c0dd49bdSEiji Ota 		    rdsv3_sg_len(&rm->m_sg[i]));
94c0dd49bdSEiji Ota 	}
95c0dd49bdSEiji Ota 
96c0dd49bdSEiji Ota 	if (rm->m_rdma_op)
97c0dd49bdSEiji Ota 		rdsv3_rdma_free_op(rm->m_rdma_op);
98c0dd49bdSEiji Ota 	if (rm->m_rdma_mr) {
99c0dd49bdSEiji Ota 		struct rdsv3_mr *mr = rm->m_rdma_mr;
100c0dd49bdSEiji Ota 		if (mr->r_refcount == 0) {
101c0dd49bdSEiji Ota 			RDSV3_DPRINTF4("rdsv3_message_purge ASSERT 0",
102c0dd49bdSEiji Ota 			    "rm %p mr %p", rm, mr);
103c0dd49bdSEiji Ota 			return;
104c0dd49bdSEiji Ota 		}
105c0dd49bdSEiji Ota 		if (mr->r_refcount == 0xdeadbeef) {
106c0dd49bdSEiji Ota 			RDSV3_DPRINTF4("rdsv3_message_purge ASSERT deadbeef",
107c0dd49bdSEiji Ota 			    "rm %p mr %p", rm, mr);
108c0dd49bdSEiji Ota 			return;
109c0dd49bdSEiji Ota 		}
110c0dd49bdSEiji Ota 		if (atomic_dec_and_test(&mr->r_refcount)) {
111c0dd49bdSEiji Ota 			rm->m_rdma_mr = NULL;
112c0dd49bdSEiji Ota 			__rdsv3_put_mr_final(mr);
113c0dd49bdSEiji Ota 		}
114c0dd49bdSEiji Ota 	}
115c0dd49bdSEiji Ota 
116c0dd49bdSEiji Ota 	RDSV3_DPRINTF4("rdsv3_message_purge", "Return(rm: %p)", rm);
117c0dd49bdSEiji Ota 
118c0dd49bdSEiji Ota }
119c0dd49bdSEiji Ota 
120c0dd49bdSEiji Ota void
rdsv3_message_put(struct rdsv3_message * rm)121c0dd49bdSEiji Ota rdsv3_message_put(struct rdsv3_message *rm)
122c0dd49bdSEiji Ota {
123c0dd49bdSEiji Ota 	RDSV3_DPRINTF5("rdsv3_message_put",
124c0dd49bdSEiji Ota 	    "put rm %p ref %d\n", rm, atomic_get(&rm->m_refcount));
125c0dd49bdSEiji Ota 
126c0dd49bdSEiji Ota 	if (atomic_dec_and_test(&rm->m_refcount)) {
127c0dd49bdSEiji Ota 		ASSERT(!list_link_active(&rm->m_sock_item));
128c0dd49bdSEiji Ota 		ASSERT(!list_link_active(&rm->m_conn_item));
129c0dd49bdSEiji Ota 		rdsv3_message_purge(rm);
130c0dd49bdSEiji Ota 
131c0dd49bdSEiji Ota 		kmem_free(rm, sizeof (struct rdsv3_message) +
132c0dd49bdSEiji Ota 		    (rm->m_nents * sizeof (struct rdsv3_scatterlist)));
133c0dd49bdSEiji Ota 	}
134c0dd49bdSEiji Ota }
135c0dd49bdSEiji Ota 
136c0dd49bdSEiji Ota void
rdsv3_message_inc_free(struct rdsv3_incoming * inc)137c0dd49bdSEiji Ota rdsv3_message_inc_free(struct rdsv3_incoming *inc)
138c0dd49bdSEiji Ota {
139c0dd49bdSEiji Ota 	struct rdsv3_message *rm =
140*94c3dad2SToomas Soome 	    __containerof(inc, struct rdsv3_message, m_inc);
141c0dd49bdSEiji Ota 	rdsv3_message_put(rm);
142c0dd49bdSEiji Ota }
143c0dd49bdSEiji Ota 
144c0dd49bdSEiji Ota void
rdsv3_message_populate_header(struct rdsv3_header * hdr,uint16_be_t sport,uint16_be_t dport,uint64_t seq)145c0dd49bdSEiji Ota rdsv3_message_populate_header(struct rdsv3_header *hdr, uint16_be_t sport,
146c0dd49bdSEiji Ota     uint16_be_t dport, uint64_t seq)
147c0dd49bdSEiji Ota {
148c0dd49bdSEiji Ota 	hdr->h_flags = 0;
149c0dd49bdSEiji Ota 	hdr->h_sport = sport;
150c0dd49bdSEiji Ota 	hdr->h_dport = dport;
151c0dd49bdSEiji Ota 	hdr->h_sequence = htonll(seq);
152c0dd49bdSEiji Ota 	hdr->h_exthdr[0] = RDSV3_EXTHDR_NONE;
153c0dd49bdSEiji Ota }
154c0dd49bdSEiji Ota 
155c0dd49bdSEiji Ota int
rdsv3_message_add_extension(struct rdsv3_header * hdr,unsigned int type,const void * data,unsigned int len)156c0dd49bdSEiji Ota rdsv3_message_add_extension(struct rdsv3_header *hdr,
157c0dd49bdSEiji Ota     unsigned int type, const void *data, unsigned int len)
158c0dd49bdSEiji Ota {
159c0dd49bdSEiji Ota 	unsigned int ext_len = sizeof (uint8_t) + len;
160c0dd49bdSEiji Ota 	unsigned char *dst;
161c0dd49bdSEiji Ota 
162c0dd49bdSEiji Ota 	RDSV3_DPRINTF4("rdsv3_message_add_extension", "Enter");
163c0dd49bdSEiji Ota 
164c0dd49bdSEiji Ota 	/* For now, refuse to add more than one extension header */
165c0dd49bdSEiji Ota 	if (hdr->h_exthdr[0] != RDSV3_EXTHDR_NONE)
166c0dd49bdSEiji Ota 		return (0);
167c0dd49bdSEiji Ota 
168c0dd49bdSEiji Ota 	if (type >= __RDSV3_EXTHDR_MAX ||
169c0dd49bdSEiji Ota 	    len != rdsv3_exthdr_size[type])
170c0dd49bdSEiji Ota 		return (0);
171c0dd49bdSEiji Ota 
172c0dd49bdSEiji Ota 	if (ext_len >= RDSV3_HEADER_EXT_SPACE)
173c0dd49bdSEiji Ota 		return (0);
174c0dd49bdSEiji Ota 	dst = hdr->h_exthdr;
175c0dd49bdSEiji Ota 
176c0dd49bdSEiji Ota 	*dst++ = type;
177c0dd49bdSEiji Ota 	(void) memcpy(dst, data, len);
178c0dd49bdSEiji Ota 
179c0dd49bdSEiji Ota 	dst[len] = RDSV3_EXTHDR_NONE;
180c0dd49bdSEiji Ota 
181c0dd49bdSEiji Ota 	RDSV3_DPRINTF4("rdsv3_message_add_extension", "Return");
182c0dd49bdSEiji Ota 	return (1);
183c0dd49bdSEiji Ota }
184c0dd49bdSEiji Ota 
185c0dd49bdSEiji Ota /*
186c0dd49bdSEiji Ota  * If a message has extension headers, retrieve them here.
187c0dd49bdSEiji Ota  * Call like this:
188c0dd49bdSEiji Ota  *
189c0dd49bdSEiji Ota  * unsigned int pos = 0;
190c0dd49bdSEiji Ota  *
191c0dd49bdSEiji Ota  * while (1) {
192c0dd49bdSEiji Ota  *	buflen = sizeof(buffer);
193c0dd49bdSEiji Ota  *	type = rdsv3_message_next_extension(hdr, &pos, buffer, &buflen);
194c0dd49bdSEiji Ota  *	if (type == RDSV3_EXTHDR_NONE)
195c0dd49bdSEiji Ota  *		break;
196c0dd49bdSEiji Ota  *	...
197c0dd49bdSEiji Ota  * }
198c0dd49bdSEiji Ota  */
199c0dd49bdSEiji Ota int
rdsv3_message_next_extension(struct rdsv3_header * hdr,unsigned int * pos,void * buf,unsigned int * buflen)200c0dd49bdSEiji Ota rdsv3_message_next_extension(struct rdsv3_header *hdr,
201c0dd49bdSEiji Ota     unsigned int *pos, void *buf, unsigned int *buflen)
202c0dd49bdSEiji Ota {
203c0dd49bdSEiji Ota 	unsigned int offset, ext_type, ext_len;
204c0dd49bdSEiji Ota 	uint8_t *src = hdr->h_exthdr;
205c0dd49bdSEiji Ota 
206c0dd49bdSEiji Ota 	RDSV3_DPRINTF4("rdsv3_message_next_extension", "Enter");
207c0dd49bdSEiji Ota 
208c0dd49bdSEiji Ota 	offset = *pos;
209c0dd49bdSEiji Ota 	if (offset >= RDSV3_HEADER_EXT_SPACE)
210c0dd49bdSEiji Ota 		goto none;
211c0dd49bdSEiji Ota 
212c0dd49bdSEiji Ota 	/*
213c0dd49bdSEiji Ota 	 * Get the extension type and length. For now, the
214c0dd49bdSEiji Ota 	 * length is implied by the extension type.
215c0dd49bdSEiji Ota 	 */
216c0dd49bdSEiji Ota 	ext_type = src[offset++];
217c0dd49bdSEiji Ota 
218c0dd49bdSEiji Ota 	if (ext_type == RDSV3_EXTHDR_NONE || ext_type >= __RDSV3_EXTHDR_MAX)
219c0dd49bdSEiji Ota 		goto none;
220c0dd49bdSEiji Ota 	ext_len = rdsv3_exthdr_size[ext_type];
221c0dd49bdSEiji Ota 	if (offset + ext_len > RDSV3_HEADER_EXT_SPACE)
222c0dd49bdSEiji Ota 		goto none;
223c0dd49bdSEiji Ota 
224c0dd49bdSEiji Ota 	*pos = offset + ext_len;
225c0dd49bdSEiji Ota 	if (ext_len < *buflen)
226c0dd49bdSEiji Ota 		*buflen = ext_len;
227c0dd49bdSEiji Ota 	(void) memcpy(buf, src + offset, *buflen);
228c0dd49bdSEiji Ota 	return (ext_type);
229c0dd49bdSEiji Ota 
230c0dd49bdSEiji Ota none:
231c0dd49bdSEiji Ota 	*pos = RDSV3_HEADER_EXT_SPACE;
232c0dd49bdSEiji Ota 	*buflen = 0;
233c0dd49bdSEiji Ota 	return (RDSV3_EXTHDR_NONE);
234c0dd49bdSEiji Ota }
235c0dd49bdSEiji Ota 
236c0dd49bdSEiji Ota int
rdsv3_message_add_version_extension(struct rdsv3_header * hdr,unsigned int version)237c0dd49bdSEiji Ota rdsv3_message_add_version_extension(struct rdsv3_header *hdr,
238c0dd49bdSEiji Ota     unsigned int version)
239c0dd49bdSEiji Ota {
240c0dd49bdSEiji Ota 	struct rdsv3_ext_header_version ext_hdr;
241c0dd49bdSEiji Ota 
242c0dd49bdSEiji Ota 	ext_hdr.h_version = htonl(version);
243c0dd49bdSEiji Ota 	return (rdsv3_message_add_extension(hdr, RDSV3_EXTHDR_VERSION,
244c0dd49bdSEiji Ota 	    &ext_hdr, sizeof (ext_hdr)));
245c0dd49bdSEiji Ota }
246c0dd49bdSEiji Ota 
247c0dd49bdSEiji Ota int
rdsv3_message_get_version_extension(struct rdsv3_header * hdr,unsigned int * version)248c0dd49bdSEiji Ota rdsv3_message_get_version_extension(struct rdsv3_header *hdr,
249c0dd49bdSEiji Ota     unsigned int *version)
250c0dd49bdSEiji Ota {
251c0dd49bdSEiji Ota 	struct rdsv3_ext_header_version ext_hdr;
252c0dd49bdSEiji Ota 	unsigned int pos = 0, len = sizeof (ext_hdr);
253c0dd49bdSEiji Ota 
254c0dd49bdSEiji Ota 	RDSV3_DPRINTF4("rdsv3_message_get_version_extension", "Enter");
255c0dd49bdSEiji Ota 
256c0dd49bdSEiji Ota 	/*
257c0dd49bdSEiji Ota 	 * We assume the version extension is the only one present
258c0dd49bdSEiji Ota 	 */
259c0dd49bdSEiji Ota 	if (rdsv3_message_next_extension(hdr, &pos, &ext_hdr, &len) !=
260c0dd49bdSEiji Ota 	    RDSV3_EXTHDR_VERSION)
261c0dd49bdSEiji Ota 		return (0);
262c0dd49bdSEiji Ota 	*version = ntohl(ext_hdr.h_version);
263c0dd49bdSEiji Ota 	return (1);
264c0dd49bdSEiji Ota }
265c0dd49bdSEiji Ota 
266c0dd49bdSEiji Ota int
rdsv3_message_add_rdma_dest_extension(struct rdsv3_header * hdr,uint32_t r_key,uint32_t offset)267c0dd49bdSEiji Ota rdsv3_message_add_rdma_dest_extension(struct rdsv3_header *hdr, uint32_t r_key,
268c0dd49bdSEiji Ota     uint32_t offset)
269c0dd49bdSEiji Ota {
270c0dd49bdSEiji Ota 	struct rdsv3_ext_header_rdma_dest ext_hdr;
271c0dd49bdSEiji Ota 
272c0dd49bdSEiji Ota 	ext_hdr.h_rdma_rkey = htonl(r_key);
273c0dd49bdSEiji Ota 	ext_hdr.h_rdma_offset = htonl(offset);
274c0dd49bdSEiji Ota 	return (rdsv3_message_add_extension(hdr, RDSV3_EXTHDR_RDMA_DEST,
275c0dd49bdSEiji Ota 	    &ext_hdr, sizeof (ext_hdr)));
276c0dd49bdSEiji Ota }
277c0dd49bdSEiji Ota 
278c0dd49bdSEiji Ota struct rdsv3_message *
rdsv3_message_alloc(unsigned int nents,int gfp)279c0dd49bdSEiji Ota rdsv3_message_alloc(unsigned int nents, int gfp)
280c0dd49bdSEiji Ota {
281c0dd49bdSEiji Ota 	struct rdsv3_message *rm;
282c0dd49bdSEiji Ota 
283c0dd49bdSEiji Ota 	RDSV3_DPRINTF4("rdsv3_message_alloc", "Enter(nents: %d)", nents);
284c0dd49bdSEiji Ota 
285c0dd49bdSEiji Ota 	rm = kmem_zalloc(sizeof (struct rdsv3_message) +
286c0dd49bdSEiji Ota 	    (nents * sizeof (struct rdsv3_scatterlist)), gfp);
287c0dd49bdSEiji Ota 	if (!rm)
288c0dd49bdSEiji Ota 		goto out;
289c0dd49bdSEiji Ota 
290c0dd49bdSEiji Ota 	rm->m_refcount = 1;
291c0dd49bdSEiji Ota 	list_link_init(&rm->m_sock_item);
292c0dd49bdSEiji Ota 	list_link_init(&rm->m_conn_item);
293c0dd49bdSEiji Ota 	mutex_init(&rm->m_rs_lock, NULL, MUTEX_DRIVER, NULL);
2945d5562f5SEiji Ota 	rdsv3_init_waitqueue(&rm->m_flush_wait);
295c0dd49bdSEiji Ota 
296c0dd49bdSEiji Ota 	RDSV3_DPRINTF4("rdsv3_message_alloc", "Return(rm: %p)", rm);
297c0dd49bdSEiji Ota out:
298c0dd49bdSEiji Ota 	return (rm);
299c0dd49bdSEiji Ota }
300c0dd49bdSEiji Ota 
301c0dd49bdSEiji Ota struct rdsv3_message *
rdsv3_message_map_pages(unsigned long * page_addrs,unsigned int total_len)302c0dd49bdSEiji Ota rdsv3_message_map_pages(unsigned long *page_addrs, unsigned int total_len)
303c0dd49bdSEiji Ota {
304c0dd49bdSEiji Ota 	struct rdsv3_message *rm;
305c0dd49bdSEiji Ota 	unsigned int i;
306c0dd49bdSEiji Ota 
307c0dd49bdSEiji Ota 	RDSV3_DPRINTF4("rdsv3_message_map_pages", "Enter(len: %d)", total_len);
308c0dd49bdSEiji Ota 
309c0dd49bdSEiji Ota #ifndef __lock_lint
310c0dd49bdSEiji Ota 	rm = rdsv3_message_alloc(ceil(total_len, PAGE_SIZE), KM_NOSLEEP);
311c0dd49bdSEiji Ota #else
312c0dd49bdSEiji Ota 	rm = NULL;
313c0dd49bdSEiji Ota #endif
314c0dd49bdSEiji Ota 	if (rm == NULL)
315c0dd49bdSEiji Ota 		return (ERR_PTR(-ENOMEM));
316c0dd49bdSEiji Ota 
317c0dd49bdSEiji Ota 	set_bit(RDSV3_MSG_PAGEVEC, &rm->m_flags);
318c0dd49bdSEiji Ota 	rm->m_inc.i_hdr.h_len = htonl(total_len);
319c0dd49bdSEiji Ota #ifndef __lock_lint
320c0dd49bdSEiji Ota 	rm->m_nents = ceil(total_len, PAGE_SIZE);
321c0dd49bdSEiji Ota #else
322c0dd49bdSEiji Ota 	rm->m_nents = 0;
323c0dd49bdSEiji Ota #endif
324c0dd49bdSEiji Ota 
325c0dd49bdSEiji Ota 	for (i = 0; i < rm->m_nents; ++i) {
326c0dd49bdSEiji Ota 		rdsv3_sg_set_page(&rm->m_sg[i],
327c0dd49bdSEiji Ota 		    page_addrs[i],
328c0dd49bdSEiji Ota 		    PAGE_SIZE, 0);
329c0dd49bdSEiji Ota 	}
330c0dd49bdSEiji Ota 
331c0dd49bdSEiji Ota 	return (rm);
332c0dd49bdSEiji Ota }
333c0dd49bdSEiji Ota 
334c0dd49bdSEiji Ota struct rdsv3_message *
rdsv3_message_copy_from_user(struct uio * uiop,size_t total_len)335c0dd49bdSEiji Ota rdsv3_message_copy_from_user(struct uio *uiop,
336c0dd49bdSEiji Ota     size_t total_len)
337c0dd49bdSEiji Ota {
338c0dd49bdSEiji Ota 	struct rdsv3_message *rm;
339c0dd49bdSEiji Ota 	struct rdsv3_scatterlist *sg;
340c0dd49bdSEiji Ota 	int ret;
341c0dd49bdSEiji Ota 
342c0dd49bdSEiji Ota 	RDSV3_DPRINTF4("rdsv3_message_copy_from_user", "Enter: %d", total_len);
343c0dd49bdSEiji Ota 
344c0dd49bdSEiji Ota #ifndef __lock_lint
345c0dd49bdSEiji Ota 	rm = rdsv3_message_alloc(ceil(total_len, PAGE_SIZE), KM_NOSLEEP);
346c0dd49bdSEiji Ota #else
347c0dd49bdSEiji Ota 	rm = NULL;
348c0dd49bdSEiji Ota #endif
349c0dd49bdSEiji Ota 	if (rm == NULL) {
350c0dd49bdSEiji Ota 		ret = -ENOMEM;
351c0dd49bdSEiji Ota 		goto out;
352c0dd49bdSEiji Ota 	}
353c0dd49bdSEiji Ota 
354c0dd49bdSEiji Ota 	rm->m_inc.i_hdr.h_len = htonl(total_len);
355c0dd49bdSEiji Ota 
356c0dd49bdSEiji Ota 	/*
357c0dd49bdSEiji Ota 	 * now allocate and copy in the data payload.
358c0dd49bdSEiji Ota 	 */
359c0dd49bdSEiji Ota 	sg = rm->m_sg;
360c0dd49bdSEiji Ota 
361c0dd49bdSEiji Ota 	while (total_len) {
362c0dd49bdSEiji Ota 		if (rdsv3_sg_page(sg) == NULL) {
363c0dd49bdSEiji Ota 			ret = rdsv3_page_remainder_alloc(sg, total_len, 0);
364c0dd49bdSEiji Ota 			if (ret)
365c0dd49bdSEiji Ota 				goto out;
366c0dd49bdSEiji Ota 			rm->m_nents++;
367c0dd49bdSEiji Ota 		}
368c0dd49bdSEiji Ota 
369c0dd49bdSEiji Ota 		ret = uiomove(rdsv3_sg_page(sg), rdsv3_sg_len(sg), UIO_WRITE,
370c0dd49bdSEiji Ota 		    uiop);
371b27516f5Sagiri 		if (ret) {
372b27516f5Sagiri 			RDSV3_DPRINTF2("rdsv3_message_copy_from_user",
373b27516f5Sagiri 			    "uiomove failed");
374b27516f5Sagiri 			ret = -ret;
375c0dd49bdSEiji Ota 			goto out;
376b27516f5Sagiri 		}
377c0dd49bdSEiji Ota 
378c0dd49bdSEiji Ota 		total_len -= rdsv3_sg_len(sg);
379c0dd49bdSEiji Ota 		sg++;
380c0dd49bdSEiji Ota 	}
381c0dd49bdSEiji Ota 	ret = 0;
382c0dd49bdSEiji Ota out:
383c0dd49bdSEiji Ota 	if (ret) {
384c0dd49bdSEiji Ota 		if (rm)
385c0dd49bdSEiji Ota 			rdsv3_message_put(rm);
386c0dd49bdSEiji Ota 		rm = ERR_PTR(ret);
387c0dd49bdSEiji Ota 	}
388c0dd49bdSEiji Ota 	return (rm);
389c0dd49bdSEiji Ota }
390c0dd49bdSEiji Ota 
391c0dd49bdSEiji Ota int
rdsv3_message_inc_copy_to_user(struct rdsv3_incoming * inc,uio_t * uiop,size_t size)392c0dd49bdSEiji Ota rdsv3_message_inc_copy_to_user(struct rdsv3_incoming *inc,
393c0dd49bdSEiji Ota     uio_t *uiop, size_t size)
394c0dd49bdSEiji Ota {
395c0dd49bdSEiji Ota 	struct rdsv3_message *rm;
396c0dd49bdSEiji Ota 	struct rdsv3_scatterlist *sg;
397c0dd49bdSEiji Ota 	unsigned long to_copy;
398c0dd49bdSEiji Ota 	unsigned long vec_off;
399c0dd49bdSEiji Ota 	int copied;
400c0dd49bdSEiji Ota 	int ret;
401c0dd49bdSEiji Ota 	uint32_t len;
402c0dd49bdSEiji Ota 
403*94c3dad2SToomas Soome 	rm = __containerof(inc, struct rdsv3_message, m_inc);
404c0dd49bdSEiji Ota 	len = ntohl(rm->m_inc.i_hdr.h_len);
405c0dd49bdSEiji Ota 
406c0dd49bdSEiji Ota 	RDSV3_DPRINTF4("rdsv3_message_inc_copy_to_user",
407c0dd49bdSEiji Ota 	    "Enter(rm: %p, len: %d)", rm, len);
408c0dd49bdSEiji Ota 
409c0dd49bdSEiji Ota 	sg = rm->m_sg;
410c0dd49bdSEiji Ota 	vec_off = 0;
411c0dd49bdSEiji Ota 	copied = 0;
412c0dd49bdSEiji Ota 
413c0dd49bdSEiji Ota 	while (copied < size && copied < len) {
414c0dd49bdSEiji Ota 
415c0dd49bdSEiji Ota 		to_copy = min(len - copied, sg->length - vec_off);
416c0dd49bdSEiji Ota 		to_copy = min(size - copied, to_copy);
417c0dd49bdSEiji Ota 
418c0dd49bdSEiji Ota 		RDSV3_DPRINTF5("rdsv3_message_inc_copy_to_user",
419c0dd49bdSEiji Ota 		    "copying %lu bytes to user iov %p from sg [%p, %u] + %lu\n",
420c0dd49bdSEiji Ota 		    to_copy, uiop,
421c0dd49bdSEiji Ota 		    rdsv3_sg_page(sg), sg->length, vec_off);
422c0dd49bdSEiji Ota 
423c0dd49bdSEiji Ota 		ret = uiomove(rdsv3_sg_page(sg), to_copy, UIO_READ, uiop);
424c0dd49bdSEiji Ota 		if (ret)
425c0dd49bdSEiji Ota 			break;
426c0dd49bdSEiji Ota 
427c0dd49bdSEiji Ota 		vec_off += to_copy;
428c0dd49bdSEiji Ota 		copied += to_copy;
429c0dd49bdSEiji Ota 
430c0dd49bdSEiji Ota 		if (vec_off == sg->length) {
431c0dd49bdSEiji Ota 			vec_off = 0;
432c0dd49bdSEiji Ota 			sg++;
433c0dd49bdSEiji Ota 		}
434c0dd49bdSEiji Ota 	}
435c0dd49bdSEiji Ota 
436c0dd49bdSEiji Ota 	return (copied);
437c0dd49bdSEiji Ota }
438c0dd49bdSEiji Ota 
439c0dd49bdSEiji Ota /*
440c0dd49bdSEiji Ota  * If the message is still on the send queue, wait until the transport
441c0dd49bdSEiji Ota  * is done with it. This is particularly important for RDMA operations.
442c0dd49bdSEiji Ota  */
4435d5562f5SEiji Ota /* ARGSUSED */
444c0dd49bdSEiji Ota void
rdsv3_message_wait(struct rdsv3_message * rm)445c0dd49bdSEiji Ota rdsv3_message_wait(struct rdsv3_message *rm)
446c0dd49bdSEiji Ota {
4475d5562f5SEiji Ota 	rdsv3_wait_event(&rm->m_flush_wait,
448c0dd49bdSEiji Ota 	    !test_bit(RDSV3_MSG_MAPPED, &rm->m_flags));
449c0dd49bdSEiji Ota }
450c0dd49bdSEiji Ota 
451c0dd49bdSEiji Ota void
rdsv3_message_unmapped(struct rdsv3_message * rm)452c0dd49bdSEiji Ota rdsv3_message_unmapped(struct rdsv3_message *rm)
453c0dd49bdSEiji Ota {
454c0dd49bdSEiji Ota 	clear_bit(RDSV3_MSG_MAPPED, &rm->m_flags);
4555d5562f5SEiji Ota 	rdsv3_wake_up_all(&rm->m_flush_wait);
456c0dd49bdSEiji Ota }
457