xref: /openbmc/linux/net/sunrpc/xprtrdma/verbs.c (revision 7e24a55b2122746c2eef192296fc84624354f895)
1a2268cfbSChuck Lever // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2f58851e6S\"Talpey, Thomas\ /*
362b56a67SChuck Lever  * Copyright (c) 2014-2017 Oracle.  All rights reserved.
4c56c65fbS\"Talpey, Thomas\  * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
5c56c65fbS\"Talpey, Thomas\  *
6c56c65fbS\"Talpey, Thomas\  * This software is available to you under a choice of one of two
7c56c65fbS\"Talpey, Thomas\  * licenses.  You may choose to be licensed under the terms of the GNU
8c56c65fbS\"Talpey, Thomas\  * General Public License (GPL) Version 2, available from the file
9c56c65fbS\"Talpey, Thomas\  * COPYING in the main directory of this source tree, or the BSD-type
10c56c65fbS\"Talpey, Thomas\  * license below:
11c56c65fbS\"Talpey, Thomas\  *
12c56c65fbS\"Talpey, Thomas\  * Redistribution and use in source and binary forms, with or without
13c56c65fbS\"Talpey, Thomas\  * modification, are permitted provided that the following conditions
14c56c65fbS\"Talpey, Thomas\  * are met:
15c56c65fbS\"Talpey, Thomas\  *
16c56c65fbS\"Talpey, Thomas\  *      Redistributions of source code must retain the above copyright
17c56c65fbS\"Talpey, Thomas\  *      notice, this list of conditions and the following disclaimer.
18c56c65fbS\"Talpey, Thomas\  *
19c56c65fbS\"Talpey, Thomas\  *      Redistributions in binary form must reproduce the above
20c56c65fbS\"Talpey, Thomas\  *      copyright notice, this list of conditions and the following
21c56c65fbS\"Talpey, Thomas\  *      disclaimer in the documentation and/or other materials provided
22c56c65fbS\"Talpey, Thomas\  *      with the distribution.
23c56c65fbS\"Talpey, Thomas\  *
24c56c65fbS\"Talpey, Thomas\  *      Neither the name of the Network Appliance, Inc. nor the names of
25c56c65fbS\"Talpey, Thomas\  *      its contributors may be used to endorse or promote products
26c56c65fbS\"Talpey, Thomas\  *      derived from this software without specific prior written
27c56c65fbS\"Talpey, Thomas\  *      permission.
28c56c65fbS\"Talpey, Thomas\  *
29c56c65fbS\"Talpey, Thomas\  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30c56c65fbS\"Talpey, Thomas\  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31c56c65fbS\"Talpey, Thomas\  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32c56c65fbS\"Talpey, Thomas\  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33c56c65fbS\"Talpey, Thomas\  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34c56c65fbS\"Talpey, Thomas\  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35c56c65fbS\"Talpey, Thomas\  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36c56c65fbS\"Talpey, Thomas\  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37c56c65fbS\"Talpey, Thomas\  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38c56c65fbS\"Talpey, Thomas\  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39c56c65fbS\"Talpey, Thomas\  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40f58851e6S\"Talpey, Thomas\  */
41f58851e6S\"Talpey, Thomas\ 
42c56c65fbS\"Talpey, Thomas\ /*
43c56c65fbS\"Talpey, Thomas\  * verbs.c
44c56c65fbS\"Talpey, Thomas\  *
45c56c65fbS\"Talpey, Thomas\  * Encapsulates the major functions managing:
46c56c65fbS\"Talpey, Thomas\  *  o adapters
47c56c65fbS\"Talpey, Thomas\  *  o endpoints
48c56c65fbS\"Talpey, Thomas\  *  o connections
49c56c65fbS\"Talpey, Thomas\  *  o buffer memory
50c56c65fbS\"Talpey, Thomas\  */
51c56c65fbS\"Talpey, Thomas\ 
52a6b7a407SAlexey Dobriyan #include <linux/interrupt.h>
535a0e3ad6STejun Heo #include <linux/slab.h>
540dd39caeSChuck Lever #include <linux/sunrpc/addr.h>
5505c97466SChuck Lever #include <linux/sunrpc/svc_rdma.h>
56f3c66a2fSChuck Lever #include <linux/log2.h>
57ae72950aSChuck Lever 
58ae72950aSChuck Lever #include <asm-generic/barrier.h>
5965866f82SChuck Lever #include <asm/bitops.h>
6056a6bd15SChuck Lever 
610a90487bSChuck Lever #include <rdma/ib_cm.h>
62c56c65fbS\"Talpey, Thomas\ 
63f58851e6S\"Talpey, Thomas\ #include "xprt_rdma.h"
64b6e717cbSChuck Lever #include <trace/events/rpcrdma.h>
65f58851e6S\"Talpey, Thomas\ 
66cb586decSChuck Lever static int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt);
67cb586decSChuck Lever static void rpcrdma_sendctxs_destroy(struct rpcrdma_xprt *r_xprt);
68f995879eSChuck Lever static void rpcrdma_sendctx_put_locked(struct rpcrdma_xprt *r_xprt,
69f995879eSChuck Lever 				       struct rpcrdma_sendctx *sc);
70b78de1dcSChuck Lever static int rpcrdma_reqs_setup(struct rpcrdma_xprt *r_xprt);
71a31b2f93SChuck Lever static void rpcrdma_reqs_reset(struct rpcrdma_xprt *r_xprt);
7285810388SChuck Lever static void rpcrdma_rep_destroy(struct rpcrdma_rep *rep);
73671c450bSChuck Lever static void rpcrdma_reps_unmap(struct rpcrdma_xprt *r_xprt);
7496ceddeaSChuck Lever static void rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt);
759d2da4ffSChuck Lever static void rpcrdma_mrs_destroy(struct rpcrdma_xprt *r_xprt);
762acc5caeSChuck Lever static void rpcrdma_ep_get(struct rpcrdma_ep *ep);
772acc5caeSChuck Lever static int rpcrdma_ep_put(struct rpcrdma_ep *ep);
78d2832af3SChuck Lever static struct rpcrdma_regbuf *
797ac18798SChuck Lever rpcrdma_regbuf_alloc(size_t size, enum dma_data_direction direction);
80d2832af3SChuck Lever static void rpcrdma_regbuf_dma_unmap(struct rpcrdma_regbuf *rb);
81d2832af3SChuck Lever static void rpcrdma_regbuf_free(struct rpcrdma_regbuf *rb);
82c56c65fbS\"Talpey, Thomas\ 
83b8fe677fSChuck Lever /* Wait for outstanding transport work to finish. ib_drain_qp
84b8fe677fSChuck Lever  * handles the drains in the wrong order for us, so open code
85b8fe677fSChuck Lever  * them here.
866d2d0ee2SChuck Lever  */
rpcrdma_xprt_drain(struct rpcrdma_xprt * r_xprt)876d2d0ee2SChuck Lever static void rpcrdma_xprt_drain(struct rpcrdma_xprt *r_xprt)
88c56c65fbS\"Talpey, Thomas\ {
892acc5caeSChuck Lever 	struct rpcrdma_ep *ep = r_xprt->rx_ep;
902acc5caeSChuck Lever 	struct rdma_cm_id *id = ep->re_id;
91c56c65fbS\"Talpey, Thomas\ 
9215788d1dSChuck Lever 	/* Wait for rpcrdma_post_recvs() to leave its critical
9315788d1dSChuck Lever 	 * section.
9415788d1dSChuck Lever 	 */
9515788d1dSChuck Lever 	if (atomic_inc_return(&ep->re_receiving) > 1)
9615788d1dSChuck Lever 		wait_for_completion(&ep->re_done);
9715788d1dSChuck Lever 
986d2d0ee2SChuck Lever 	/* Flush Receives, then wait for deferred Reply work
996d2d0ee2SChuck Lever 	 * to complete.
1006d2d0ee2SChuck Lever 	 */
10193aa8e0aSChuck Lever 	ib_drain_rq(id->qp);
102c56c65fbS\"Talpey, Thomas\ 
1036d2d0ee2SChuck Lever 	/* Deferred Reply processing might have scheduled
1046d2d0ee2SChuck Lever 	 * local invalidations.
1056d2d0ee2SChuck Lever 	 */
10693aa8e0aSChuck Lever 	ib_drain_sq(id->qp);
1072acc5caeSChuck Lever 
1082acc5caeSChuck Lever 	rpcrdma_ep_put(ep);
109f1a03b76SChuck Lever }
110f1a03b76SChuck Lever 
111c487eb7dSChuck Lever /* Ensure xprt_force_disconnect() is invoked exactly once when a
112c487eb7dSChuck Lever  * connection is closed or lost. (The important thing is it needs
113c487eb7dSChuck Lever  * to be invoked "at least" once).
114c487eb7dSChuck Lever  */
rpcrdma_force_disconnect(struct rpcrdma_ep * ep)1151143129eSChuck Lever void rpcrdma_force_disconnect(struct rpcrdma_ep *ep)
116c487eb7dSChuck Lever {
117c487eb7dSChuck Lever 	if (atomic_add_unless(&ep->re_force_disconnect, 1, 1))
118c487eb7dSChuck Lever 		xprt_force_disconnect(ep->re_xprt);
119c487eb7dSChuck Lever }
120c487eb7dSChuck Lever 
1212fa8f88dSChuck Lever /**
122d6ccebf9SChuck Lever  * rpcrdma_flush_disconnect - Disconnect on flushed completion
123f423f755SChuck Lever  * @r_xprt: transport to disconnect
124d6ccebf9SChuck Lever  * @wc: work completion entry
125d6ccebf9SChuck Lever  *
126d6ccebf9SChuck Lever  * Must be called in process context.
127d6ccebf9SChuck Lever  */
rpcrdma_flush_disconnect(struct rpcrdma_xprt * r_xprt,struct ib_wc * wc)128f423f755SChuck Lever void rpcrdma_flush_disconnect(struct rpcrdma_xprt *r_xprt, struct ib_wc *wc)
129d6ccebf9SChuck Lever {
130c487eb7dSChuck Lever 	if (wc->status != IB_WC_SUCCESS)
131c487eb7dSChuck Lever 		rpcrdma_force_disconnect(r_xprt->rx_ep);
132d6ccebf9SChuck Lever }
133d6ccebf9SChuck Lever 
134d6ccebf9SChuck Lever /**
1352fa8f88dSChuck Lever  * rpcrdma_wc_send - Invoked by RDMA provider for each polled Send WC
136f995879eSChuck Lever  * @cq:	completion queue
137d6ccebf9SChuck Lever  * @wc:	WCE for a completed Send WR
1382fa8f88dSChuck Lever  *
1394220a072SChuck Lever  */
rpcrdma_wc_send(struct ib_cq * cq,struct ib_wc * wc)140d6ccebf9SChuck Lever static void rpcrdma_wc_send(struct ib_cq *cq, struct ib_wc *wc)
141c56c65fbS\"Talpey, Thomas\ {
142ae72950aSChuck Lever 	struct ib_cqe *cqe = wc->wr_cqe;
143ae72950aSChuck Lever 	struct rpcrdma_sendctx *sc =
144ae72950aSChuck Lever 		container_of(cqe, struct rpcrdma_sendctx, sc_cqe);
145f423f755SChuck Lever 	struct rpcrdma_xprt *r_xprt = cq->cq_context;
146ae72950aSChuck Lever 
1472fa8f88dSChuck Lever 	/* WARNING: Only wr_cqe and status are reliable at this point */
148b2e7467fSChuck Lever 	trace_xprtrdma_wc_send(wc, &sc->sc_cid);
149f423f755SChuck Lever 	rpcrdma_sendctx_put_locked(r_xprt, sc);
150f423f755SChuck Lever 	rpcrdma_flush_disconnect(r_xprt, wc);
151fc664485SChuck Lever }
152fc664485SChuck Lever 
153552bf225SChuck Lever /**
1541519e969SChuck Lever  * rpcrdma_wc_receive - Invoked by RDMA provider for each polled Receive WC
155d6ccebf9SChuck Lever  * @cq:	completion queue
156d6ccebf9SChuck Lever  * @wc:	WCE for a completed Receive WR
157552bf225SChuck Lever  *
158552bf225SChuck Lever  */
rpcrdma_wc_receive(struct ib_cq * cq,struct ib_wc * wc)159d6ccebf9SChuck Lever static void rpcrdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
160fc664485SChuck Lever {
161552bf225SChuck Lever 	struct ib_cqe *cqe = wc->wr_cqe;
162552bf225SChuck Lever 	struct rpcrdma_rep *rep = container_of(cqe, struct rpcrdma_rep,
163552bf225SChuck Lever 					       rr_cqe);
164d6ccebf9SChuck Lever 	struct rpcrdma_xprt *r_xprt = cq->cq_context;
165fc664485SChuck Lever 
1666ceea368SChuck Lever 	/* WARNING: Only wr_cqe and status are reliable at this point */
167af5865d2SChuck Lever 	trace_xprtrdma_wc_receive(wc, &rep->rr_cid);
168e28ce900SChuck Lever 	--r_xprt->rx_ep->re_receive_count;
1698502427cSChuck Lever 	if (wc->status != IB_WC_SUCCESS)
1706ceea368SChuck Lever 		goto out_flushed;
171fc664485SChuck Lever 
1728502427cSChuck Lever 	/* status == SUCCESS means all fields in wc are trustworthy */
17396f8778fSChuck Lever 	rpcrdma_set_xdrlen(&rep->rr_hdrbuf, wc->byte_len);
174c8b920bbSChuck Lever 	rep->rr_wc_flags = wc->wc_flags;
175c8b920bbSChuck Lever 	rep->rr_inv_rkey = wc->ex.invalidate_rkey;
176c8b920bbSChuck Lever 
17791a10c52SChuck Lever 	ib_dma_sync_single_for_cpu(rdmab_device(rep->rr_rdmabuf),
1786b1184cdSChuck Lever 				   rdmab_addr(rep->rr_rdmabuf),
179e2a67190SChuck Lever 				   wc->byte_len, DMA_FROM_DEVICE);
18023826c7aSChuck Lever 
181d8f532d2SChuck Lever 	rpcrdma_reply_handler(rep);
1828502427cSChuck Lever 	return;
183fe97b47cSChuck Lever 
1846ceea368SChuck Lever out_flushed:
185f423f755SChuck Lever 	rpcrdma_flush_disconnect(r_xprt, wc);
1865030c9a9SChuck Lever 	rpcrdma_rep_put(&r_xprt->rx_buf, rep);
187fc664485SChuck Lever }
188fc664485SChuck Lever 
rpcrdma_update_cm_private(struct rpcrdma_ep * ep,struct rdma_conn_param * param)189745b734cSChuck Lever static void rpcrdma_update_cm_private(struct rpcrdma_ep *ep,
19087cfb9a0SChuck Lever 				      struct rdma_conn_param *param)
19187cfb9a0SChuck Lever {
19287cfb9a0SChuck Lever 	const struct rpcrdma_connect_private *pmsg = param->private_data;
19387cfb9a0SChuck Lever 	unsigned int rsize, wsize;
19487cfb9a0SChuck Lever 
195c8b920bbSChuck Lever 	/* Default settings for RPC-over-RDMA Version One */
19687cfb9a0SChuck Lever 	rsize = RPCRDMA_V1_DEF_INLINE_SIZE;
19787cfb9a0SChuck Lever 	wsize = RPCRDMA_V1_DEF_INLINE_SIZE;
19887cfb9a0SChuck Lever 
19987cfb9a0SChuck Lever 	if (pmsg &&
20087cfb9a0SChuck Lever 	    pmsg->cp_magic == rpcrdma_cmp_magic &&
20187cfb9a0SChuck Lever 	    pmsg->cp_version == RPCRDMA_CMP_VERSION) {
20287cfb9a0SChuck Lever 		rsize = rpcrdma_decode_buffer_size(pmsg->cp_send_size);
20387cfb9a0SChuck Lever 		wsize = rpcrdma_decode_buffer_size(pmsg->cp_recv_size);
20487cfb9a0SChuck Lever 	}
20587cfb9a0SChuck Lever 
20693aa8e0aSChuck Lever 	if (rsize < ep->re_inline_recv)
20793aa8e0aSChuck Lever 		ep->re_inline_recv = rsize;
20893aa8e0aSChuck Lever 	if (wsize < ep->re_inline_send)
20993aa8e0aSChuck Lever 		ep->re_inline_send = wsize;
210f54c870dSChuck Lever 
21193aa8e0aSChuck Lever 	rpcrdma_set_max_header_sizes(ep);
21287cfb9a0SChuck Lever }
21387cfb9a0SChuck Lever 
214ae38288eSChuck Lever /**
215ae38288eSChuck Lever  * rpcrdma_cm_event_handler - Handle RDMA CM events
216ae38288eSChuck Lever  * @id: rdma_cm_id on which an event has occurred
217ae38288eSChuck Lever  * @event: details of the event
218ae38288eSChuck Lever  *
219ae38288eSChuck Lever  * Called with @id's mutex held. Returns 1 if caller should
220ae38288eSChuck Lever  * destroy @id, otherwise 0.
221ae38288eSChuck Lever  */
222c56c65fbS\"Talpey, Thomas\ static int
rpcrdma_cm_event_handler(struct rdma_cm_id * id,struct rdma_cm_event * event)223ae38288eSChuck Lever rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
224c56c65fbS\"Talpey, Thomas\ {
225745b734cSChuck Lever 	struct sockaddr *sap = (struct sockaddr *)&id->route.addr.dst_addr;
226e28ce900SChuck Lever 	struct rpcrdma_ep *ep = id->context;
227c56c65fbS\"Talpey, Thomas\ 
228ae38288eSChuck Lever 	might_sleep();
229ae38288eSChuck Lever 
230c56c65fbS\"Talpey, Thomas\ 	switch (event->event) {
231c56c65fbS\"Talpey, Thomas\ 	case RDMA_CM_EVENT_ADDR_RESOLVED:
232c56c65fbS\"Talpey, Thomas\ 	case RDMA_CM_EVENT_ROUTE_RESOLVED:
23393aa8e0aSChuck Lever 		ep->re_async_rc = 0;
23493aa8e0aSChuck Lever 		complete(&ep->re_done);
235316a616eSChuck Lever 		return 0;
236c56c65fbS\"Talpey, Thomas\ 	case RDMA_CM_EVENT_ADDR_ERROR:
23793aa8e0aSChuck Lever 		ep->re_async_rc = -EPROTO;
23893aa8e0aSChuck Lever 		complete(&ep->re_done);
239316a616eSChuck Lever 		return 0;
240c56c65fbS\"Talpey, Thomas\ 	case RDMA_CM_EVENT_ROUTE_ERROR:
24193aa8e0aSChuck Lever 		ep->re_async_rc = -ENETUNREACH;
24293aa8e0aSChuck Lever 		complete(&ep->re_done);
243316a616eSChuck Lever 		return 0;
244bebd0318SChuck Lever 	case RDMA_CM_EVENT_DEVICE_REMOVAL:
245745b734cSChuck Lever 		pr_info("rpcrdma: removing device %s for %pISpc\n",
246745b734cSChuck Lever 			ep->re_id->device->name, sap);
247706dff4fSDan Aloni 		switch (xchg(&ep->re_connect_status, -ENODEV)) {
248706dff4fSDan Aloni 		case 0: goto wake_connect_worker;
249706dff4fSDan Aloni 		case 1: goto disconnected;
250706dff4fSDan Aloni 		}
251706dff4fSDan Aloni 		return 0;
252e28ce900SChuck Lever 	case RDMA_CM_EVENT_ADDR_CHANGE:
25393aa8e0aSChuck Lever 		ep->re_connect_status = -ENODEV;
254e28ce900SChuck Lever 		goto disconnected;
255c56c65fbS\"Talpey, Thomas\ 	case RDMA_CM_EVENT_ESTABLISHED:
2562acc5caeSChuck Lever 		rpcrdma_ep_get(ep);
25793aa8e0aSChuck Lever 		ep->re_connect_status = 1;
258745b734cSChuck Lever 		rpcrdma_update_cm_private(ep, &event->param.conn);
259745b734cSChuck Lever 		trace_xprtrdma_inline_thresh(ep);
26093aa8e0aSChuck Lever 		wake_up_all(&ep->re_connect_wait);
26131e62d25SChuck Lever 		break;
262c56c65fbS\"Talpey, Thomas\ 	case RDMA_CM_EVENT_CONNECT_ERROR:
26393aa8e0aSChuck Lever 		ep->re_connect_status = -ENOTCONN;
264af667527SChuck Lever 		goto wake_connect_worker;
265c56c65fbS\"Talpey, Thomas\ 	case RDMA_CM_EVENT_UNREACHABLE:
26693aa8e0aSChuck Lever 		ep->re_connect_status = -ENETUNREACH;
267af667527SChuck Lever 		goto wake_connect_worker;
268c56c65fbS\"Talpey, Thomas\ 	case RDMA_CM_EVENT_REJECTED:
26993aa8e0aSChuck Lever 		ep->re_connect_status = -ECONNREFUSED;
2700a90487bSChuck Lever 		if (event->status == IB_CM_REJ_STALE_CONN)
2714cf44be6SChuck Lever 			ep->re_connect_status = -ENOTCONN;
272af667527SChuck Lever wake_connect_worker:
273af667527SChuck Lever 		wake_up_all(&ep->re_connect_wait);
274af667527SChuck Lever 		return 0;
275c56c65fbS\"Talpey, Thomas\ 	case RDMA_CM_EVENT_DISCONNECTED:
27693aa8e0aSChuck Lever 		ep->re_connect_status = -ECONNABORTED;
27731e62d25SChuck Lever disconnected:
278c487eb7dSChuck Lever 		rpcrdma_force_disconnect(ep);
2792acc5caeSChuck Lever 		return rpcrdma_ep_put(ep);
280c56c65fbS\"Talpey, Thomas\ 	default:
281c56c65fbS\"Talpey, Thomas\ 		break;
282c56c65fbS\"Talpey, Thomas\ 	}
283c56c65fbS\"Talpey, Thomas\ 
284c56c65fbS\"Talpey, Thomas\ 	return 0;
285c56c65fbS\"Talpey, Thomas\ }
286c56c65fbS\"Talpey, Thomas\ 
rpcrdma_create_id(struct rpcrdma_xprt * r_xprt,struct rpcrdma_ep * ep)28793aa8e0aSChuck Lever static struct rdma_cm_id *rpcrdma_create_id(struct rpcrdma_xprt *r_xprt,
28893aa8e0aSChuck Lever 					    struct rpcrdma_ep *ep)
289c56c65fbS\"Talpey, Thomas\ {
290109b88abSChuck Lever 	unsigned long wtimeout = msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT) + 1;
29193aa8e0aSChuck Lever 	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
292c56c65fbS\"Talpey, Thomas\ 	struct rdma_cm_id *id;
293c56c65fbS\"Talpey, Thomas\ 	int rc;
294c56c65fbS\"Talpey, Thomas\ 
29593aa8e0aSChuck Lever 	init_completion(&ep->re_done);
2961a954051STom Talpey 
297e28ce900SChuck Lever 	id = rdma_create_id(xprt->xprt_net, rpcrdma_cm_event_handler, ep,
29893aa8e0aSChuck Lever 			    RDMA_PS_TCP, IB_QPT_RC);
299ddbb347fSChuck Lever 	if (IS_ERR(id))
300c56c65fbS\"Talpey, Thomas\ 		return id;
301c56c65fbS\"Talpey, Thomas\ 
30293aa8e0aSChuck Lever 	ep->re_async_rc = -ETIMEDOUT;
30393aa8e0aSChuck Lever 	rc = rdma_resolve_addr(id, NULL, (struct sockaddr *)&xprt->addr,
304dd229ceeSChuck Lever 			       RDMA_RESOLVE_TIMEOUT);
305ddbb347fSChuck Lever 	if (rc)
306c56c65fbS\"Talpey, Thomas\ 		goto out;
30793aa8e0aSChuck Lever 	rc = wait_for_completion_interruptible_timeout(&ep->re_done, wtimeout);
3087b020f17SChuck Lever 	if (rc < 0)
309109b88abSChuck Lever 		goto out;
310d0f36c46SDevesh Sharma 
31193aa8e0aSChuck Lever 	rc = ep->re_async_rc;
312c56c65fbS\"Talpey, Thomas\ 	if (rc)
313c56c65fbS\"Talpey, Thomas\ 		goto out;
314c56c65fbS\"Talpey, Thomas\ 
31593aa8e0aSChuck Lever 	ep->re_async_rc = -ETIMEDOUT;
316c56c65fbS\"Talpey, Thomas\ 	rc = rdma_resolve_route(id, RDMA_RESOLVE_TIMEOUT);
317ddbb347fSChuck Lever 	if (rc)
31856a6bd15SChuck Lever 		goto out;
31993aa8e0aSChuck Lever 	rc = wait_for_completion_interruptible_timeout(&ep->re_done, wtimeout);
3207b020f17SChuck Lever 	if (rc < 0)
32156a6bd15SChuck Lever 		goto out;
32293aa8e0aSChuck Lever 	rc = ep->re_async_rc;
323c56c65fbS\"Talpey, Thomas\ 	if (rc)
32456a6bd15SChuck Lever 		goto out;
325c56c65fbS\"Talpey, Thomas\ 
326c56c65fbS\"Talpey, Thomas\ 	return id;
32756a6bd15SChuck Lever 
328c56c65fbS\"Talpey, Thomas\ out:
329c56c65fbS\"Talpey, Thomas\ 	rdma_destroy_id(id);
330c56c65fbS\"Talpey, Thomas\ 	return ERR_PTR(rc);
331c56c65fbS\"Talpey, Thomas\ }
332c56c65fbS\"Talpey, Thomas\ 
rpcrdma_ep_destroy(struct kref * kref)3332acc5caeSChuck Lever static void rpcrdma_ep_destroy(struct kref *kref)
334e28ce900SChuck Lever {
335e28ce900SChuck Lever 	struct rpcrdma_ep *ep = container_of(kref, struct rpcrdma_ep, re_kref);
336e28ce900SChuck Lever 
337e28ce900SChuck Lever 	if (ep->re_id->qp) {
338e28ce900SChuck Lever 		rdma_destroy_qp(ep->re_id);
339e28ce900SChuck Lever 		ep->re_id->qp = NULL;
340e28ce900SChuck Lever 	}
341e28ce900SChuck Lever 
342e28ce900SChuck Lever 	if (ep->re_attr.recv_cq)
343e28ce900SChuck Lever 		ib_free_cq(ep->re_attr.recv_cq);
344e28ce900SChuck Lever 	ep->re_attr.recv_cq = NULL;
345e28ce900SChuck Lever 	if (ep->re_attr.send_cq)
346e28ce900SChuck Lever 		ib_free_cq(ep->re_attr.send_cq);
347e28ce900SChuck Lever 	ep->re_attr.send_cq = NULL;
348e28ce900SChuck Lever 
349e28ce900SChuck Lever 	if (ep->re_pd)
350e28ce900SChuck Lever 		ib_dealloc_pd(ep->re_pd);
351e28ce900SChuck Lever 	ep->re_pd = NULL;
352e28ce900SChuck Lever 
353e28ce900SChuck Lever 	kfree(ep);
354e28ce900SChuck Lever 	module_put(THIS_MODULE);
355e28ce900SChuck Lever }
356e28ce900SChuck Lever 
rpcrdma_ep_get(struct rpcrdma_ep * ep)3572acc5caeSChuck Lever static noinline void rpcrdma_ep_get(struct rpcrdma_ep *ep)
3582acc5caeSChuck Lever {
3592acc5caeSChuck Lever 	kref_get(&ep->re_kref);
3602acc5caeSChuck Lever }
3612acc5caeSChuck Lever 
362e28ce900SChuck Lever /* Returns:
363e28ce900SChuck Lever  *     %0 if @ep still has a positive kref count, or
364e28ce900SChuck Lever  *     %1 if @ep was destroyed successfully.
365c56c65fbS\"Talpey, Thomas\  */
rpcrdma_ep_put(struct rpcrdma_ep * ep)3662acc5caeSChuck Lever static noinline int rpcrdma_ep_put(struct rpcrdma_ep *ep)
367e28ce900SChuck Lever {
3682acc5caeSChuck Lever 	return kref_put(&ep->re_kref, rpcrdma_ep_destroy);
369e28ce900SChuck Lever }
370c56c65fbS\"Talpey, Thomas\ 
rpcrdma_ep_create(struct rpcrdma_xprt * r_xprt)37181fe0c57SChuck Lever static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
372c56c65fbS\"Talpey, Thomas\ {
373e28ce900SChuck Lever 	struct rpcrdma_connect_private *pmsg;
374e28ce900SChuck Lever 	struct ib_device *device;
37581fe0c57SChuck Lever 	struct rdma_cm_id *id;
376e28ce900SChuck Lever 	struct rpcrdma_ep *ep;
3772fa8f88dSChuck Lever 	int rc;
378c56c65fbS\"Talpey, Thomas\ 
3799c8f332fSChuck Lever 	ep = kzalloc(sizeof(*ep), XPRTRDMA_GFP_FLAGS);
380e28ce900SChuck Lever 	if (!ep)
381dda9a951SChuck Lever 		return -ENOTCONN;
382e28ce900SChuck Lever 	ep->re_xprt = &r_xprt->rx_xprt;
383e28ce900SChuck Lever 	kref_init(&ep->re_kref);
384e28ce900SChuck Lever 
38593aa8e0aSChuck Lever 	id = rpcrdma_create_id(r_xprt, ep);
386e28ce900SChuck Lever 	if (IS_ERR(id)) {
38785bfd71bSChuck Lever 		kfree(ep);
38885bfd71bSChuck Lever 		return PTR_ERR(id);
389e28ce900SChuck Lever 	}
390e28ce900SChuck Lever 	__module_get(THIS_MODULE);
391e28ce900SChuck Lever 	device = id->device;
392e28ce900SChuck Lever 	ep->re_id = id;
39315788d1dSChuck Lever 	reinit_completion(&ep->re_done);
39481fe0c57SChuck Lever 
39593aa8e0aSChuck Lever 	ep->re_max_requests = r_xprt->rx_xprt.max_reqs;
39693aa8e0aSChuck Lever 	ep->re_inline_send = xprt_rdma_max_inline_write;
39793aa8e0aSChuck Lever 	ep->re_inline_recv = xprt_rdma_max_inline_read;
398e28ce900SChuck Lever 	rc = frwr_query_device(ep, device);
399914fcad9SChuck Lever 	if (rc)
40081fe0c57SChuck Lever 		goto out_destroy;
40181fe0c57SChuck Lever 
40293aa8e0aSChuck Lever 	r_xprt->rx_buf.rb_max_requests = cpu_to_be32(ep->re_max_requests);
403c56c65fbS\"Talpey, Thomas\ 
40493aa8e0aSChuck Lever 	ep->re_attr.srq = NULL;
40593aa8e0aSChuck Lever 	ep->re_attr.cap.max_inline_data = 0;
40693aa8e0aSChuck Lever 	ep->re_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
40793aa8e0aSChuck Lever 	ep->re_attr.qp_type = IB_QPT_RC;
40893aa8e0aSChuck Lever 	ep->re_attr.port_num = ~0;
409c56c65fbS\"Talpey, Thomas\ 
41093aa8e0aSChuck Lever 	ep->re_send_batch = ep->re_max_requests >> 3;
41193aa8e0aSChuck Lever 	ep->re_send_count = ep->re_send_batch;
41293aa8e0aSChuck Lever 	init_waitqueue_head(&ep->re_connect_wait);
413c56c65fbS\"Talpey, Thomas\ 
414e28ce900SChuck Lever 	ep->re_attr.send_cq = ib_alloc_cq_any(device, r_xprt,
41593aa8e0aSChuck Lever 					      ep->re_attr.cap.max_send_wr,
416a4cb5bdbSNicolas Morey-Chaisemartin 					      IB_POLL_WORKQUEUE);
41793aa8e0aSChuck Lever 	if (IS_ERR(ep->re_attr.send_cq)) {
41893aa8e0aSChuck Lever 		rc = PTR_ERR(ep->re_attr.send_cq);
419a9c10b5bSDan Aloni 		ep->re_attr.send_cq = NULL;
42085cd8e2bSChuck Lever 		goto out_destroy;
421c56c65fbS\"Talpey, Thomas\ 	}
422c56c65fbS\"Talpey, Thomas\ 
423e28ce900SChuck Lever 	ep->re_attr.recv_cq = ib_alloc_cq_any(device, r_xprt,
42493aa8e0aSChuck Lever 					      ep->re_attr.cap.max_recv_wr,
42520cf4e02SChuck Lever 					      IB_POLL_WORKQUEUE);
42693aa8e0aSChuck Lever 	if (IS_ERR(ep->re_attr.recv_cq)) {
42793aa8e0aSChuck Lever 		rc = PTR_ERR(ep->re_attr.recv_cq);
428a9c10b5bSDan Aloni 		ep->re_attr.recv_cq = NULL;
42985cd8e2bSChuck Lever 		goto out_destroy;
430fc664485SChuck Lever 	}
43193aa8e0aSChuck Lever 	ep->re_receive_count = 0;
432fc664485SChuck Lever 
433c56c65fbS\"Talpey, Thomas\ 	/* Initialize cma parameters */
43493aa8e0aSChuck Lever 	memset(&ep->re_remote_cma, 0, sizeof(ep->re_remote_cma));
435c56c65fbS\"Talpey, Thomas\ 
43687cfb9a0SChuck Lever 	/* Prepare RDMA-CM private message */
437e28ce900SChuck Lever 	pmsg = &ep->re_cm_private;
43887cfb9a0SChuck Lever 	pmsg->cp_magic = rpcrdma_cmp_magic;
43987cfb9a0SChuck Lever 	pmsg->cp_version = RPCRDMA_CMP_VERSION;
4405f62412bSChuck Lever 	pmsg->cp_flags |= RPCRDMA_CMP_F_SND_W_INV_OK;
44193aa8e0aSChuck Lever 	pmsg->cp_send_size = rpcrdma_encode_buffer_size(ep->re_inline_send);
44293aa8e0aSChuck Lever 	pmsg->cp_recv_size = rpcrdma_encode_buffer_size(ep->re_inline_recv);
44393aa8e0aSChuck Lever 	ep->re_remote_cma.private_data = pmsg;
44493aa8e0aSChuck Lever 	ep->re_remote_cma.private_data_len = sizeof(*pmsg);
445c56c65fbS\"Talpey, Thomas\ 
446c56c65fbS\"Talpey, Thomas\ 	/* Client offers RDMA Read but does not initiate */
44793aa8e0aSChuck Lever 	ep->re_remote_cma.initiator_depth = 0;
44893aa8e0aSChuck Lever 	ep->re_remote_cma.responder_resources =
449e28ce900SChuck Lever 		min_t(int, U8_MAX, device->attrs.max_qp_rd_atom);
450c56c65fbS\"Talpey, Thomas\ 
451b2dde94bSChuck Lever 	/* Limit transport retries so client can detect server
452b2dde94bSChuck Lever 	 * GID changes quickly. RPC layer handles re-establishing
453b2dde94bSChuck Lever 	 * transport connection and retransmission.
454b2dde94bSChuck Lever 	 */
45593aa8e0aSChuck Lever 	ep->re_remote_cma.retry_count = 6;
456b2dde94bSChuck Lever 
457b2dde94bSChuck Lever 	/* RPC-over-RDMA handles its own flow control. In addition,
458b2dde94bSChuck Lever 	 * make all RNR NAKs visible so we know that RPC-over-RDMA
459b2dde94bSChuck Lever 	 * flow control is working correctly (no NAKs should be seen).
460b2dde94bSChuck Lever 	 */
46193aa8e0aSChuck Lever 	ep->re_remote_cma.flow_control = 0;
46293aa8e0aSChuck Lever 	ep->re_remote_cma.rnr_retry_count = 0;
463c56c65fbS\"Talpey, Thomas\ 
464e28ce900SChuck Lever 	ep->re_pd = ib_alloc_pd(device, 0);
46593aa8e0aSChuck Lever 	if (IS_ERR(ep->re_pd)) {
46693aa8e0aSChuck Lever 		rc = PTR_ERR(ep->re_pd);
467a9c10b5bSDan Aloni 		ep->re_pd = NULL;
4689ba373eeSChuck Lever 		goto out_destroy;
4699ba373eeSChuck Lever 	}
4709ba373eeSChuck Lever 
47193aa8e0aSChuck Lever 	rc = rdma_create_qp(id, ep->re_pd, &ep->re_attr);
47285cd8e2bSChuck Lever 	if (rc)
47385cd8e2bSChuck Lever 		goto out_destroy;
47493aa8e0aSChuck Lever 
475e28ce900SChuck Lever 	r_xprt->rx_ep = ep;
476c56c65fbS\"Talpey, Thomas\ 	return 0;
477c56c65fbS\"Talpey, Thomas\ 
47885cd8e2bSChuck Lever out_destroy:
4792acc5caeSChuck Lever 	rpcrdma_ep_put(ep);
48081fe0c57SChuck Lever 	rdma_destroy_id(id);
481c56c65fbS\"Talpey, Thomas\ 	return rc;
482c56c65fbS\"Talpey, Thomas\ }
483c56c65fbS\"Talpey, Thomas\ 
484e28ce900SChuck Lever /**
485e28ce900SChuck Lever  * rpcrdma_xprt_connect - Connect an unconnected transport
486e28ce900SChuck Lever  * @r_xprt: controlling transport instance
487e28ce900SChuck Lever  *
488e28ce900SChuck Lever  * Returns 0 on success or a negative errno.
489c56c65fbS\"Talpey, Thomas\  */
rpcrdma_xprt_connect(struct rpcrdma_xprt * r_xprt)4909144a803SChuck Lever int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt)
491c56c65fbS\"Talpey, Thomas\ {
49231e62d25SChuck Lever 	struct rpc_xprt *xprt = &r_xprt->rx_xprt;
493e28ce900SChuck Lever 	struct rpcrdma_ep *ep;
4941890896bSChuck Lever 	int rc;
495c56c65fbS\"Talpey, Thomas\ 
49681fe0c57SChuck Lever 	rc = rpcrdma_ep_create(r_xprt);
4971890896bSChuck Lever 	if (rc)
498e28ce900SChuck Lever 		return rc;
499e28ce900SChuck Lever 	ep = r_xprt->rx_ep;
500c56c65fbS\"Talpey, Thomas\ 
50131e62d25SChuck Lever 	xprt_clear_connected(xprt);
502eea63ca7SChuck Lever 	rpcrdma_reset_cwnd(r_xprt);
5032acc5caeSChuck Lever 
5042acc5caeSChuck Lever 	/* Bump the ep's reference count while there are
5052acc5caeSChuck Lever 	 * outstanding Receives.
5062acc5caeSChuck Lever 	 */
5072acc5caeSChuck Lever 	rpcrdma_ep_get(ep);
50835d8b10aSChuck Lever 	rpcrdma_post_recvs(r_xprt, 1, true);
509c56c65fbS\"Talpey, Thomas\ 
51093aa8e0aSChuck Lever 	rc = rdma_connect(ep->re_id, &ep->re_remote_cma);
511ddbb347fSChuck Lever 	if (rc)
512c56c65fbS\"Talpey, Thomas\ 		goto out;
513c56c65fbS\"Talpey, Thomas\ 
514f9e1afe0SChuck Lever 	if (xprt->reestablish_timeout < RPCRDMA_INIT_REEST_TO)
515f9e1afe0SChuck Lever 		xprt->reestablish_timeout = RPCRDMA_INIT_REEST_TO;
51693aa8e0aSChuck Lever 	wait_event_interruptible(ep->re_connect_wait,
51793aa8e0aSChuck Lever 				 ep->re_connect_status != 0);
51893aa8e0aSChuck Lever 	if (ep->re_connect_status <= 0) {
51993aa8e0aSChuck Lever 		rc = ep->re_connect_status;
5200a90487bSChuck Lever 		goto out;
5210a90487bSChuck Lever 	}
522f531a5dbSChuck Lever 
523dda9a951SChuck Lever 	rc = rpcrdma_sendctxs_create(r_xprt);
524dda9a951SChuck Lever 	if (rc) {
525dda9a951SChuck Lever 		rc = -ENOTCONN;
526b78de1dcSChuck Lever 		goto out;
527dda9a951SChuck Lever 	}
528dda9a951SChuck Lever 
529dda9a951SChuck Lever 	rc = rpcrdma_reqs_setup(r_xprt);
530dda9a951SChuck Lever 	if (rc) {
531dda9a951SChuck Lever 		rc = -ENOTCONN;
532dda9a951SChuck Lever 		goto out;
533dda9a951SChuck Lever 	}
5349d2da4ffSChuck Lever 	rpcrdma_mrs_create(r_xprt);
53521037b8cSChuck Lever 	frwr_wp_create(r_xprt);
5367c8d9e7cSChuck Lever 
537c56c65fbS\"Talpey, Thomas\ out:
5387b020f17SChuck Lever 	trace_xprtrdma_connect(r_xprt, rc);
539c56c65fbS\"Talpey, Thomas\ 	return rc;
540c56c65fbS\"Talpey, Thomas\ }
541c56c65fbS\"Talpey, Thomas\ 
5426d2d0ee2SChuck Lever /**
5439144a803SChuck Lever  * rpcrdma_xprt_disconnect - Disconnect underlying transport
5449144a803SChuck Lever  * @r_xprt: controlling transport instance
545c56c65fbS\"Talpey, Thomas\  *
5469d2da4ffSChuck Lever  * Caller serializes. Either the transport send lock is held,
5479d2da4ffSChuck Lever  * or we're being called to destroy the transport.
548e28ce900SChuck Lever  *
549e28ce900SChuck Lever  * On return, @r_xprt is completely divested of all hardware
550e28ce900SChuck Lever  * resources and prepared for the next ->connect operation.
551c56c65fbS\"Talpey, Thomas\  */
rpcrdma_xprt_disconnect(struct rpcrdma_xprt * r_xprt)5529144a803SChuck Lever void rpcrdma_xprt_disconnect(struct rpcrdma_xprt *r_xprt)
553c56c65fbS\"Talpey, Thomas\ {
554e28ce900SChuck Lever 	struct rpcrdma_ep *ep = r_xprt->rx_ep;
555e28ce900SChuck Lever 	struct rdma_cm_id *id;
556e28ce900SChuck Lever 	int rc;
557897b7be9SChuck Lever 
558e28ce900SChuck Lever 	if (!ep)
559897b7be9SChuck Lever 		return;
56085cd8e2bSChuck Lever 
561e28ce900SChuck Lever 	id = ep->re_id;
56285cd8e2bSChuck Lever 	rc = rdma_disconnect(id);
5636d2d0ee2SChuck Lever 	trace_xprtrdma_disconnect(r_xprt, rc);
564550d7502SChuck Lever 
5656d2d0ee2SChuck Lever 	rpcrdma_xprt_drain(r_xprt);
566897b7be9SChuck Lever 	rpcrdma_reps_unmap(r_xprt);
567a31b2f93SChuck Lever 	rpcrdma_reqs_reset(r_xprt);
5689d2da4ffSChuck Lever 	rpcrdma_mrs_destroy(r_xprt);
569cb586decSChuck Lever 	rpcrdma_sendctxs_destroy(r_xprt);
57085cd8e2bSChuck Lever 
5712acc5caeSChuck Lever 	if (rpcrdma_ep_put(ep))
572897b7be9SChuck Lever 		rdma_destroy_id(id);
573e28ce900SChuck Lever 
574e28ce900SChuck Lever 	r_xprt->rx_ep = NULL;
575c56c65fbS\"Talpey, Thomas\ }
576c56c65fbS\"Talpey, Thomas\ 
577ae72950aSChuck Lever /* Fixed-size circular FIFO queue. This implementation is wait-free and
578ae72950aSChuck Lever  * lock-free.
579ae72950aSChuck Lever  *
580ae72950aSChuck Lever  * Consumer is the code path that posts Sends. This path dequeues a
581ae72950aSChuck Lever  * sendctx for use by a Send operation. Multiple consumer threads
582ae72950aSChuck Lever  * are serialized by the RPC transport lock, which allows only one
583ae72950aSChuck Lever  * ->send_request call at a time.
584ae72950aSChuck Lever  *
585ae72950aSChuck Lever  * Producer is the code path that handles Send completions. This path
586ae72950aSChuck Lever  * enqueues a sendctx that has been completed. Multiple producer
587ae72950aSChuck Lever  * threads are serialized by the ib_poll_cq() function.
588ae72950aSChuck Lever  */
589ae72950aSChuck Lever 
590ae72950aSChuck Lever /* rpcrdma_sendctxs_destroy() assumes caller has already quiesced
591b8fe677fSChuck Lever  * queue activity, and rpcrdma_xprt_drain has flushed all remaining
592b8fe677fSChuck Lever  * Send requests.
593ae72950aSChuck Lever  */
rpcrdma_sendctxs_destroy(struct rpcrdma_xprt * r_xprt)594cb586decSChuck Lever static void rpcrdma_sendctxs_destroy(struct rpcrdma_xprt *r_xprt)
595ae72950aSChuck Lever {
596cb586decSChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
597ae72950aSChuck Lever 	unsigned long i;
598ae72950aSChuck Lever 
599cb586decSChuck Lever 	if (!buf->rb_sc_ctxs)
600cb586decSChuck Lever 		return;
601ae72950aSChuck Lever 	for (i = 0; i <= buf->rb_sc_last; i++)
602ae72950aSChuck Lever 		kfree(buf->rb_sc_ctxs[i]);
603ae72950aSChuck Lever 	kfree(buf->rb_sc_ctxs);
604cb586decSChuck Lever 	buf->rb_sc_ctxs = NULL;
605ae72950aSChuck Lever }
606ae72950aSChuck Lever 
rpcrdma_sendctx_create(struct rpcrdma_ep * ep)6072e870368SChuck Lever static struct rpcrdma_sendctx *rpcrdma_sendctx_create(struct rpcrdma_ep *ep)
608ae72950aSChuck Lever {
609ae72950aSChuck Lever 	struct rpcrdma_sendctx *sc;
610ae72950aSChuck Lever 
61193aa8e0aSChuck Lever 	sc = kzalloc(struct_size(sc, sc_sges, ep->re_attr.cap.max_send_sge),
6129c8f332fSChuck Lever 		     XPRTRDMA_GFP_FLAGS);
613ae72950aSChuck Lever 	if (!sc)
614ae72950aSChuck Lever 		return NULL;
615ae72950aSChuck Lever 
616ae72950aSChuck Lever 	sc->sc_cqe.done = rpcrdma_wc_send;
617b2e7467fSChuck Lever 	sc->sc_cid.ci_queue_id = ep->re_attr.send_cq->res.id;
618b2e7467fSChuck Lever 	sc->sc_cid.ci_completion_id =
619b2e7467fSChuck Lever 		atomic_inc_return(&ep->re_completion_ids);
620ae72950aSChuck Lever 	return sc;
621ae72950aSChuck Lever }
622ae72950aSChuck Lever 
rpcrdma_sendctxs_create(struct rpcrdma_xprt * r_xprt)623ae72950aSChuck Lever static int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt)
624ae72950aSChuck Lever {
625ae72950aSChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
626ae72950aSChuck Lever 	struct rpcrdma_sendctx *sc;
627ae72950aSChuck Lever 	unsigned long i;
628ae72950aSChuck Lever 
629ae72950aSChuck Lever 	/* Maximum number of concurrent outstanding Send WRs. Capping
630ae72950aSChuck Lever 	 * the circular queue size stops Send Queue overflow by causing
631ae72950aSChuck Lever 	 * the ->send_request call to fail temporarily before too many
632ae72950aSChuck Lever 	 * Sends are posted.
633ae72950aSChuck Lever 	 */
634e28ce900SChuck Lever 	i = r_xprt->rx_ep->re_max_requests + RPCRDMA_MAX_BC_REQUESTS;
6359c8f332fSChuck Lever 	buf->rb_sc_ctxs = kcalloc(i, sizeof(sc), XPRTRDMA_GFP_FLAGS);
636ae72950aSChuck Lever 	if (!buf->rb_sc_ctxs)
637ae72950aSChuck Lever 		return -ENOMEM;
638ae72950aSChuck Lever 
639ae72950aSChuck Lever 	buf->rb_sc_last = i - 1;
640ae72950aSChuck Lever 	for (i = 0; i <= buf->rb_sc_last; i++) {
641e28ce900SChuck Lever 		sc = rpcrdma_sendctx_create(r_xprt->rx_ep);
642ae72950aSChuck Lever 		if (!sc)
6436e17f58cSDan Carpenter 			return -ENOMEM;
644ae72950aSChuck Lever 
645ae72950aSChuck Lever 		buf->rb_sc_ctxs[i] = sc;
646ae72950aSChuck Lever 	}
647ae72950aSChuck Lever 
648cb586decSChuck Lever 	buf->rb_sc_head = 0;
649cb586decSChuck Lever 	buf->rb_sc_tail = 0;
650ae72950aSChuck Lever 	return 0;
651ae72950aSChuck Lever }
652ae72950aSChuck Lever 
653ae72950aSChuck Lever /* The sendctx queue is not guaranteed to have a size that is a
654ae72950aSChuck Lever  * power of two, thus the helpers in circ_buf.h cannot be used.
655ae72950aSChuck Lever  * The other option is to use modulus (%), which can be expensive.
656ae72950aSChuck Lever  */
rpcrdma_sendctx_next(struct rpcrdma_buffer * buf,unsigned long item)657ae72950aSChuck Lever static unsigned long rpcrdma_sendctx_next(struct rpcrdma_buffer *buf,
658ae72950aSChuck Lever 					  unsigned long item)
659ae72950aSChuck Lever {
660ae72950aSChuck Lever 	return likely(item < buf->rb_sc_last) ? item + 1 : 0;
661ae72950aSChuck Lever }
662ae72950aSChuck Lever 
663ae72950aSChuck Lever /**
664ae72950aSChuck Lever  * rpcrdma_sendctx_get_locked - Acquire a send context
665dbcc53a5SChuck Lever  * @r_xprt: controlling transport instance
666ae72950aSChuck Lever  *
667ae72950aSChuck Lever  * Returns pointer to a free send completion context; or NULL if
668ae72950aSChuck Lever  * the queue is empty.
669ae72950aSChuck Lever  *
670ae72950aSChuck Lever  * Usage: Called to acquire an SGE array before preparing a Send WR.
671ae72950aSChuck Lever  *
672dbcc53a5SChuck Lever  * The caller serializes calls to this function (per transport), and
673dbcc53a5SChuck Lever  * provides an effective memory barrier that flushes the new value
674ae72950aSChuck Lever  * of rb_sc_head.
675ae72950aSChuck Lever  */
rpcrdma_sendctx_get_locked(struct rpcrdma_xprt * r_xprt)676dbcc53a5SChuck Lever struct rpcrdma_sendctx *rpcrdma_sendctx_get_locked(struct rpcrdma_xprt *r_xprt)
677ae72950aSChuck Lever {
678dbcc53a5SChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
679ae72950aSChuck Lever 	struct rpcrdma_sendctx *sc;
680ae72950aSChuck Lever 	unsigned long next_head;
681ae72950aSChuck Lever 
682ae72950aSChuck Lever 	next_head = rpcrdma_sendctx_next(buf, buf->rb_sc_head);
683ae72950aSChuck Lever 
684ae72950aSChuck Lever 	if (next_head == READ_ONCE(buf->rb_sc_tail))
685ae72950aSChuck Lever 		goto out_emptyq;
686ae72950aSChuck Lever 
687ae72950aSChuck Lever 	/* ORDER: item must be accessed _before_ head is updated */
688ae72950aSChuck Lever 	sc = buf->rb_sc_ctxs[next_head];
689ae72950aSChuck Lever 
690ae72950aSChuck Lever 	/* Releasing the lock in the caller acts as a memory
691ae72950aSChuck Lever 	 * barrier that flushes rb_sc_head.
692ae72950aSChuck Lever 	 */
693ae72950aSChuck Lever 	buf->rb_sc_head = next_head;
694ae72950aSChuck Lever 
695ae72950aSChuck Lever 	return sc;
696ae72950aSChuck Lever 
697ae72950aSChuck Lever out_emptyq:
698ae72950aSChuck Lever 	/* The queue is "empty" if there have not been enough Send
699ae72950aSChuck Lever 	 * completions recently. This is a sign the Send Queue is
700ae72950aSChuck Lever 	 * backing up. Cause the caller to pause and try again.
701ae72950aSChuck Lever 	 */
70205eb06d8SChuck Lever 	xprt_wait_for_buffer_space(&r_xprt->rx_xprt);
703ae72950aSChuck Lever 	r_xprt->rx_stats.empty_sendctx_q++;
704ae72950aSChuck Lever 	return NULL;
705ae72950aSChuck Lever }
706ae72950aSChuck Lever 
707ae72950aSChuck Lever /**
708ae72950aSChuck Lever  * rpcrdma_sendctx_put_locked - Release a send context
709f995879eSChuck Lever  * @r_xprt: controlling transport instance
710ae72950aSChuck Lever  * @sc: send context to release
711ae72950aSChuck Lever  *
712ae72950aSChuck Lever  * Usage: Called from Send completion to return a sendctxt
713ae72950aSChuck Lever  * to the queue.
714ae72950aSChuck Lever  *
715dbcc53a5SChuck Lever  * The caller serializes calls to this function (per transport).
716ae72950aSChuck Lever  */
rpcrdma_sendctx_put_locked(struct rpcrdma_xprt * r_xprt,struct rpcrdma_sendctx * sc)717f995879eSChuck Lever static void rpcrdma_sendctx_put_locked(struct rpcrdma_xprt *r_xprt,
718f995879eSChuck Lever 				       struct rpcrdma_sendctx *sc)
719ae72950aSChuck Lever {
720f995879eSChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
721ae72950aSChuck Lever 	unsigned long next_tail;
722ae72950aSChuck Lever 
723dbcc53a5SChuck Lever 	/* Unmap SGEs of previously completed but unsignaled
724ae72950aSChuck Lever 	 * Sends by walking up the queue until @sc is found.
725ae72950aSChuck Lever 	 */
726ae72950aSChuck Lever 	next_tail = buf->rb_sc_tail;
727ae72950aSChuck Lever 	do {
728ae72950aSChuck Lever 		next_tail = rpcrdma_sendctx_next(buf, next_tail);
729ae72950aSChuck Lever 
730ae72950aSChuck Lever 		/* ORDER: item must be accessed _before_ tail is updated */
731dbcc53a5SChuck Lever 		rpcrdma_sendctx_unmap(buf->rb_sc_ctxs[next_tail]);
732ae72950aSChuck Lever 
733ae72950aSChuck Lever 	} while (buf->rb_sc_ctxs[next_tail] != sc);
734ae72950aSChuck Lever 
735ae72950aSChuck Lever 	/* Paired with READ_ONCE */
736ae72950aSChuck Lever 	smp_store_release(&buf->rb_sc_tail, next_tail);
7372fad6592SChuck Lever 
738f995879eSChuck Lever 	xprt_write_space(&r_xprt->rx_xprt);
7392fad6592SChuck Lever }
740ae72950aSChuck Lever 
741505bbe64SChuck Lever static void
rpcrdma_mrs_create(struct rpcrdma_xprt * r_xprt)74296ceddeaSChuck Lever rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt)
743e2ac236cSChuck Lever {
744e2ac236cSChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
745e28ce900SChuck Lever 	struct rpcrdma_ep *ep = r_xprt->rx_ep;
7462d77058cSChuck Lever 	struct ib_device *device = ep->re_id->device;
747e2ac236cSChuck Lever 	unsigned int count;
748e2ac236cSChuck Lever 
7492d77058cSChuck Lever 	/* Try to allocate enough to perform one full-sized I/O */
75093aa8e0aSChuck Lever 	for (count = 0; count < ep->re_max_rdma_segs; count++) {
75196ceddeaSChuck Lever 		struct rpcrdma_mr *mr;
752e2ac236cSChuck Lever 		int rc;
753e2ac236cSChuck Lever 
7542d77058cSChuck Lever 		mr = kzalloc_node(sizeof(*mr), XPRTRDMA_GFP_FLAGS,
7552d77058cSChuck Lever 				  ibdev_to_node(device));
75696ceddeaSChuck Lever 		if (!mr)
757e2ac236cSChuck Lever 			break;
758e2ac236cSChuck Lever 
759253a5162SChuck Lever 		rc = frwr_mr_init(r_xprt, mr);
760e2ac236cSChuck Lever 		if (rc) {
76196ceddeaSChuck Lever 			kfree(mr);
762e2ac236cSChuck Lever 			break;
763e2ac236cSChuck Lever 		}
764e2ac236cSChuck Lever 
7654d6b8890SChuck Lever 		spin_lock(&buf->rb_lock);
766c3700780SChuck Lever 		rpcrdma_mr_push(mr, &buf->rb_mrs);
767eed48a9cSChuck Lever 		list_add(&mr->mr_all, &buf->rb_all_mrs);
7684d6b8890SChuck Lever 		spin_unlock(&buf->rb_lock);
769e2ac236cSChuck Lever 	}
770e2ac236cSChuck Lever 
771e2ac236cSChuck Lever 	r_xprt->rx_stats.mrs_allocated += count;
7721c443effSChuck Lever 	trace_xprtrdma_createmrs(r_xprt, count);
773e2ac236cSChuck Lever }
774e2ac236cSChuck Lever 
775e2ac236cSChuck Lever static void
rpcrdma_mr_refresh_worker(struct work_struct * work)776e2ac236cSChuck Lever rpcrdma_mr_refresh_worker(struct work_struct *work)
777e2ac236cSChuck Lever {
778e2ac236cSChuck Lever 	struct rpcrdma_buffer *buf = container_of(work, struct rpcrdma_buffer,
7793b39f52aSChuck Lever 						  rb_refresh_worker);
780e2ac236cSChuck Lever 	struct rpcrdma_xprt *r_xprt = container_of(buf, struct rpcrdma_xprt,
781e2ac236cSChuck Lever 						   rx_buf);
782e2ac236cSChuck Lever 
78396ceddeaSChuck Lever 	rpcrdma_mrs_create(r_xprt);
78405eb06d8SChuck Lever 	xprt_write_space(&r_xprt->rx_xprt);
785e2ac236cSChuck Lever }
786e2ac236cSChuck Lever 
7871769e6a8SChuck Lever /**
7889d2da4ffSChuck Lever  * rpcrdma_mrs_refresh - Wake the MR refresh worker
7899d2da4ffSChuck Lever  * @r_xprt: controlling transport instance
7909d2da4ffSChuck Lever  *
7919d2da4ffSChuck Lever  */
rpcrdma_mrs_refresh(struct rpcrdma_xprt * r_xprt)7929d2da4ffSChuck Lever void rpcrdma_mrs_refresh(struct rpcrdma_xprt *r_xprt)
7939d2da4ffSChuck Lever {
7949d2da4ffSChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
795e28ce900SChuck Lever 	struct rpcrdma_ep *ep = r_xprt->rx_ep;
7969d2da4ffSChuck Lever 
797897b7be9SChuck Lever 	/* If there is no underlying connection, it's no use
798897b7be9SChuck Lever 	 * to wake the refresh worker.
7999d2da4ffSChuck Lever 	 */
8006b1eb3b2SChuck Lever 	if (ep->re_connect_status != 1)
8016b1eb3b2SChuck Lever 		return;
8026b1eb3b2SChuck Lever 	queue_work(system_highpri_wq, &buf->rb_refresh_worker);
8039d2da4ffSChuck Lever }
8049d2da4ffSChuck Lever 
8059d2da4ffSChuck Lever /**
8061769e6a8SChuck Lever  * rpcrdma_req_create - Allocate an rpcrdma_req object
8071769e6a8SChuck Lever  * @r_xprt: controlling r_xprt
808bb93a1aeSChuck Lever  * @size: initial size, in bytes, of send and receive buffers
8091769e6a8SChuck Lever  *
8101769e6a8SChuck Lever  * Returns an allocated and fully initialized rpcrdma_req or NULL.
8111769e6a8SChuck Lever  */
rpcrdma_req_create(struct rpcrdma_xprt * r_xprt,size_t size)8123b50cc1cSChuck Lever struct rpcrdma_req *rpcrdma_req_create(struct rpcrdma_xprt *r_xprt,
8133b50cc1cSChuck Lever 				       size_t size)
8141392402cSChuck Lever {
815f531a5dbSChuck Lever 	struct rpcrdma_buffer *buffer = &r_xprt->rx_buf;
8161392402cSChuck Lever 	struct rpcrdma_req *req;
8171392402cSChuck Lever 
818f20f18c9SChuck Lever 	req = kzalloc(sizeof(*req), XPRTRDMA_GFP_FLAGS);
8191392402cSChuck Lever 	if (req == NULL)
820bb93a1aeSChuck Lever 		goto out1;
8211392402cSChuck Lever 
8227ac18798SChuck Lever 	req->rl_sendbuf = rpcrdma_regbuf_alloc(size, DMA_TO_DEVICE);
823bb93a1aeSChuck Lever 	if (!req->rl_sendbuf)
824b78de1dcSChuck Lever 		goto out2;
825bb93a1aeSChuck Lever 
8267ac18798SChuck Lever 	req->rl_recvbuf = rpcrdma_regbuf_alloc(size, DMA_NONE);
827bb93a1aeSChuck Lever 	if (!req->rl_recvbuf)
828b78de1dcSChuck Lever 		goto out3;
829bb93a1aeSChuck Lever 
8306dc6ec9eSChuck Lever 	INIT_LIST_HEAD(&req->rl_free_mrs);
8312dd4a012SChuck Lever 	INIT_LIST_HEAD(&req->rl_registered);
83292f4433eSChuck Lever 	spin_lock(&buffer->rb_lock);
833f531a5dbSChuck Lever 	list_add(&req->rl_all, &buffer->rb_allreqs);
83492f4433eSChuck Lever 	spin_unlock(&buffer->rb_lock);
8351392402cSChuck Lever 	return req;
836bb93a1aeSChuck Lever 
837bb93a1aeSChuck Lever out3:
8389181f40fSZhang Xiaoxu 	rpcrdma_regbuf_free(req->rl_sendbuf);
839bb93a1aeSChuck Lever out2:
840bb93a1aeSChuck Lever 	kfree(req);
841bb93a1aeSChuck Lever out1:
842bb93a1aeSChuck Lever 	return NULL;
8431392402cSChuck Lever }
8441392402cSChuck Lever 
845a31b2f93SChuck Lever /**
846b78de1dcSChuck Lever  * rpcrdma_req_setup - Per-connection instance setup of an rpcrdma_req object
847a31b2f93SChuck Lever  * @r_xprt: controlling transport instance
848b78de1dcSChuck Lever  * @req: rpcrdma_req object to set up
849a31b2f93SChuck Lever  *
850b78de1dcSChuck Lever  * Returns zero on success, and a negative errno on failure.
851b78de1dcSChuck Lever  */
rpcrdma_req_setup(struct rpcrdma_xprt * r_xprt,struct rpcrdma_req * req)852b78de1dcSChuck Lever int rpcrdma_req_setup(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
853b78de1dcSChuck Lever {
854b78de1dcSChuck Lever 	struct rpcrdma_regbuf *rb;
855b78de1dcSChuck Lever 	size_t maxhdrsize;
856b78de1dcSChuck Lever 
857b78de1dcSChuck Lever 	/* Compute maximum header buffer size in bytes */
858b78de1dcSChuck Lever 	maxhdrsize = rpcrdma_fixed_maxsz + 3 +
859e28ce900SChuck Lever 		     r_xprt->rx_ep->re_max_rdma_segs * rpcrdma_readchunk_maxsz;
860b78de1dcSChuck Lever 	maxhdrsize *= sizeof(__be32);
861b78de1dcSChuck Lever 	rb = rpcrdma_regbuf_alloc(__roundup_pow_of_two(maxhdrsize),
8627ac18798SChuck Lever 				  DMA_TO_DEVICE);
863b78de1dcSChuck Lever 	if (!rb)
864b78de1dcSChuck Lever 		goto out;
865b78de1dcSChuck Lever 
866b78de1dcSChuck Lever 	if (!__rpcrdma_regbuf_dma_map(r_xprt, rb))
867b78de1dcSChuck Lever 		goto out_free;
868b78de1dcSChuck Lever 
869b78de1dcSChuck Lever 	req->rl_rdmabuf = rb;
870b78de1dcSChuck Lever 	xdr_buf_init(&req->rl_hdrbuf, rdmab_data(rb), rdmab_length(rb));
871b78de1dcSChuck Lever 	return 0;
872b78de1dcSChuck Lever 
873b78de1dcSChuck Lever out_free:
874b78de1dcSChuck Lever 	rpcrdma_regbuf_free(rb);
875b78de1dcSChuck Lever out:
876b78de1dcSChuck Lever 	return -ENOMEM;
877b78de1dcSChuck Lever }
878b78de1dcSChuck Lever 
879b78de1dcSChuck Lever /* ASSUMPTION: the rb_allreqs list is stable for the duration,
880b78de1dcSChuck Lever  * and thus can be walked without holding rb_lock. Eg. the
881b78de1dcSChuck Lever  * caller is holding the transport send lock to exclude
882b78de1dcSChuck Lever  * device removal or disconnection.
883b78de1dcSChuck Lever  */
rpcrdma_reqs_setup(struct rpcrdma_xprt * r_xprt)884b78de1dcSChuck Lever static int rpcrdma_reqs_setup(struct rpcrdma_xprt *r_xprt)
885b78de1dcSChuck Lever {
886b78de1dcSChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
887b78de1dcSChuck Lever 	struct rpcrdma_req *req;
888b78de1dcSChuck Lever 	int rc;
889b78de1dcSChuck Lever 
890b78de1dcSChuck Lever 	list_for_each_entry(req, &buf->rb_allreqs, rl_all) {
891b78de1dcSChuck Lever 		rc = rpcrdma_req_setup(r_xprt, req);
892b78de1dcSChuck Lever 		if (rc)
893b78de1dcSChuck Lever 			return rc;
894b78de1dcSChuck Lever 	}
895b78de1dcSChuck Lever 	return 0;
896b78de1dcSChuck Lever }
897b78de1dcSChuck Lever 
rpcrdma_req_reset(struct rpcrdma_req * req)898b78de1dcSChuck Lever static void rpcrdma_req_reset(struct rpcrdma_req *req)
899b78de1dcSChuck Lever {
900*83e025daSChuck Lever 	struct rpcrdma_mr *mr;
901*83e025daSChuck Lever 
902b78de1dcSChuck Lever 	/* Credits are valid for only one connection */
903b78de1dcSChuck Lever 	req->rl_slot.rq_cong = 0;
904b78de1dcSChuck Lever 
905b78de1dcSChuck Lever 	rpcrdma_regbuf_free(req->rl_rdmabuf);
906b78de1dcSChuck Lever 	req->rl_rdmabuf = NULL;
907b78de1dcSChuck Lever 
908b78de1dcSChuck Lever 	rpcrdma_regbuf_dma_unmap(req->rl_sendbuf);
909b78de1dcSChuck Lever 	rpcrdma_regbuf_dma_unmap(req->rl_recvbuf);
9105de55ce9SChuck Lever 
911*83e025daSChuck Lever 	/* The verbs consumer can't know the state of an MR on the
912*83e025daSChuck Lever 	 * req->rl_registered list unless a successful completion
913*83e025daSChuck Lever 	 * has occurred, so they cannot be re-used.
914*83e025daSChuck Lever 	 */
915*83e025daSChuck Lever 	while ((mr = rpcrdma_mr_pop(&req->rl_registered))) {
916*83e025daSChuck Lever 		struct rpcrdma_buffer *buf = &mr->mr_xprt->rx_buf;
917*83e025daSChuck Lever 
918*83e025daSChuck Lever 		spin_lock(&buf->rb_lock);
919*83e025daSChuck Lever 		list_del(&mr->mr_all);
920*83e025daSChuck Lever 		spin_unlock(&buf->rb_lock);
921*83e025daSChuck Lever 
922*83e025daSChuck Lever 		frwr_mr_release(mr);
923*83e025daSChuck Lever 	}
924b78de1dcSChuck Lever }
925b78de1dcSChuck Lever 
926b78de1dcSChuck Lever /* ASSUMPTION: the rb_allreqs list is stable for the duration,
927a31b2f93SChuck Lever  * and thus can be walked without holding rb_lock. Eg. the
928a31b2f93SChuck Lever  * caller is holding the transport send lock to exclude
929a31b2f93SChuck Lever  * device removal or disconnection.
930a31b2f93SChuck Lever  */
rpcrdma_reqs_reset(struct rpcrdma_xprt * r_xprt)931a31b2f93SChuck Lever static void rpcrdma_reqs_reset(struct rpcrdma_xprt *r_xprt)
932a31b2f93SChuck Lever {
933a31b2f93SChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
934a31b2f93SChuck Lever 	struct rpcrdma_req *req;
935a31b2f93SChuck Lever 
936b78de1dcSChuck Lever 	list_for_each_entry(req, &buf->rb_allreqs, rl_all)
937b78de1dcSChuck Lever 		rpcrdma_req_reset(req);
938a31b2f93SChuck Lever }
939a31b2f93SChuck Lever 
940e515dd9dSChuck Lever static noinline
rpcrdma_rep_create(struct rpcrdma_xprt * r_xprt,bool temp)941e515dd9dSChuck Lever struct rpcrdma_rep *rpcrdma_rep_create(struct rpcrdma_xprt *r_xprt,
942379d1bc5SChuck Lever 				       bool temp)
9431392402cSChuck Lever {
9449e3ca33bSChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
9451392402cSChuck Lever 	struct rpcrdma_rep *rep;
9461392402cSChuck Lever 
947f20f18c9SChuck Lever 	rep = kzalloc(sizeof(*rep), XPRTRDMA_GFP_FLAGS);
9481392402cSChuck Lever 	if (rep == NULL)
9491392402cSChuck Lever 		goto out;
9501392402cSChuck Lever 
951e28ce900SChuck Lever 	rep->rr_rdmabuf = rpcrdma_regbuf_alloc(r_xprt->rx_ep->re_inline_recv,
9527ac18798SChuck Lever 					       DMA_FROM_DEVICE);
9538cec3dbaSChuck Lever 	if (!rep->rr_rdmabuf)
9541392402cSChuck Lever 		goto out_free;
955379d1bc5SChuck Lever 
956af5865d2SChuck Lever 	rep->rr_cid.ci_completion_id =
957af5865d2SChuck Lever 		atomic_inc_return(&r_xprt->rx_ep->re_completion_ids);
958af5865d2SChuck Lever 
9598cec3dbaSChuck Lever 	xdr_buf_init(&rep->rr_hdrbuf, rdmab_data(rep->rr_rdmabuf),
96096f8778fSChuck Lever 		     rdmab_length(rep->rr_rdmabuf));
9611519e969SChuck Lever 	rep->rr_cqe.done = rpcrdma_wc_receive;
962fed171b3SChuck Lever 	rep->rr_rxprt = r_xprt;
9636ea8e711SChuck Lever 	rep->rr_recv_wr.next = NULL;
9646ea8e711SChuck Lever 	rep->rr_recv_wr.wr_cqe = &rep->rr_cqe;
9656ea8e711SChuck Lever 	rep->rr_recv_wr.sg_list = &rep->rr_rdmabuf->rg_iov;
9666ea8e711SChuck Lever 	rep->rr_recv_wr.num_sge = 1;
9677c8d9e7cSChuck Lever 	rep->rr_temp = temp;
9689e3ca33bSChuck Lever 
9699e3ca33bSChuck Lever 	spin_lock(&buf->rb_lock);
9709e3ca33bSChuck Lever 	list_add(&rep->rr_all, &buf->rb_all_reps);
9719e3ca33bSChuck Lever 	spin_unlock(&buf->rb_lock);
972379d1bc5SChuck Lever 	return rep;
9731392402cSChuck Lever 
9741392402cSChuck Lever out_free:
9751392402cSChuck Lever 	kfree(rep);
9761392402cSChuck Lever out:
977379d1bc5SChuck Lever 	return NULL;
9781392402cSChuck Lever }
9791392402cSChuck Lever 
rpcrdma_rep_free(struct rpcrdma_rep * rep)980eaf86e8cSChuck Lever static void rpcrdma_rep_free(struct rpcrdma_rep *rep)
981b0b227f0SChuck Lever {
982b0b227f0SChuck Lever 	rpcrdma_regbuf_free(rep->rr_rdmabuf);
983b0b227f0SChuck Lever 	kfree(rep);
984b0b227f0SChuck Lever }
985b0b227f0SChuck Lever 
rpcrdma_rep_destroy(struct rpcrdma_rep * rep)986eaf86e8cSChuck Lever static void rpcrdma_rep_destroy(struct rpcrdma_rep *rep)
987eaf86e8cSChuck Lever {
988eaf86e8cSChuck Lever 	struct rpcrdma_buffer *buf = &rep->rr_rxprt->rx_buf;
989eaf86e8cSChuck Lever 
990eaf86e8cSChuck Lever 	spin_lock(&buf->rb_lock);
991eaf86e8cSChuck Lever 	list_del(&rep->rr_all);
992eaf86e8cSChuck Lever 	spin_unlock(&buf->rb_lock);
993eaf86e8cSChuck Lever 
994eaf86e8cSChuck Lever 	rpcrdma_rep_free(rep);
995eaf86e8cSChuck Lever }
996eaf86e8cSChuck Lever 
rpcrdma_rep_get_locked(struct rpcrdma_buffer * buf)997b0b227f0SChuck Lever static struct rpcrdma_rep *rpcrdma_rep_get_locked(struct rpcrdma_buffer *buf)
998b0b227f0SChuck Lever {
999b0b227f0SChuck Lever 	struct llist_node *node;
1000b0b227f0SChuck Lever 
1001b0b227f0SChuck Lever 	/* Calls to llist_del_first are required to be serialized */
1002b0b227f0SChuck Lever 	node = llist_del_first(&buf->rb_free_reps);
1003b0b227f0SChuck Lever 	if (!node)
1004b0b227f0SChuck Lever 		return NULL;
1005b0b227f0SChuck Lever 	return llist_entry(node, struct rpcrdma_rep, rr_node);
1006b0b227f0SChuck Lever }
1007b0b227f0SChuck Lever 
1008c35ca60dSChuck Lever /**
1009c35ca60dSChuck Lever  * rpcrdma_rep_put - Release rpcrdma_rep back to free list
1010c35ca60dSChuck Lever  * @buf: buffer pool
1011c35ca60dSChuck Lever  * @rep: rep to release
1012c35ca60dSChuck Lever  *
1013c35ca60dSChuck Lever  */
rpcrdma_rep_put(struct rpcrdma_buffer * buf,struct rpcrdma_rep * rep)1014c35ca60dSChuck Lever void rpcrdma_rep_put(struct rpcrdma_buffer *buf, struct rpcrdma_rep *rep)
1015b0b227f0SChuck Lever {
1016b0b227f0SChuck Lever 	llist_add(&rep->rr_node, &buf->rb_free_reps);
1017671c450bSChuck Lever }
1018671c450bSChuck Lever 
10198b5292beSChuck Lever /* Caller must ensure the QP is quiescent (RQ is drained) before
10208b5292beSChuck Lever  * invoking this function, to guarantee rb_all_reps is not
10218b5292beSChuck Lever  * changing.
10228b5292beSChuck Lever  */
rpcrdma_reps_unmap(struct rpcrdma_xprt * r_xprt)1023671c450bSChuck Lever static void rpcrdma_reps_unmap(struct rpcrdma_xprt *r_xprt)
1024671c450bSChuck Lever {
1025671c450bSChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1026671c450bSChuck Lever 	struct rpcrdma_rep *rep;
1027671c450bSChuck Lever 
1028b7ff0185SChuck Lever 	list_for_each_entry(rep, &buf->rb_all_reps, rr_all) {
1029671c450bSChuck Lever 		rpcrdma_regbuf_dma_unmap(rep->rr_rdmabuf);
10308b5292beSChuck Lever 		rep->rr_temp = true;	/* Mark this rep for destruction */
1031b7ff0185SChuck Lever 	}
1032b0b227f0SChuck Lever }
1033b0b227f0SChuck Lever 
rpcrdma_reps_destroy(struct rpcrdma_buffer * buf)1034b0b227f0SChuck Lever static void rpcrdma_reps_destroy(struct rpcrdma_buffer *buf)
1035b0b227f0SChuck Lever {
1036b0b227f0SChuck Lever 	struct rpcrdma_rep *rep;
1037b0b227f0SChuck Lever 
1038eaf86e8cSChuck Lever 	spin_lock(&buf->rb_lock);
1039eaf86e8cSChuck Lever 	while ((rep = list_first_entry_or_null(&buf->rb_all_reps,
1040eaf86e8cSChuck Lever 					       struct rpcrdma_rep,
1041eaf86e8cSChuck Lever 					       rr_all)) != NULL) {
1042eaf86e8cSChuck Lever 		list_del(&rep->rr_all);
1043eaf86e8cSChuck Lever 		spin_unlock(&buf->rb_lock);
1044eaf86e8cSChuck Lever 
1045eaf86e8cSChuck Lever 		rpcrdma_rep_free(rep);
1046eaf86e8cSChuck Lever 
1047eaf86e8cSChuck Lever 		spin_lock(&buf->rb_lock);
1048eaf86e8cSChuck Lever 	}
1049eaf86e8cSChuck Lever 	spin_unlock(&buf->rb_lock);
1050b0b227f0SChuck Lever }
1051b0b227f0SChuck Lever 
105286c4ccd9SChuck Lever /**
105386c4ccd9SChuck Lever  * rpcrdma_buffer_create - Create initial set of req/rep objects
105486c4ccd9SChuck Lever  * @r_xprt: transport instance to (re)initialize
105586c4ccd9SChuck Lever  *
105686c4ccd9SChuck Lever  * Returns zero on success, otherwise a negative errno.
105786c4ccd9SChuck Lever  */
rpcrdma_buffer_create(struct rpcrdma_xprt * r_xprt)105886c4ccd9SChuck Lever int rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
1059c56c65fbS\"Talpey, Thomas\ {
1060ac920d04SChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1061c56c65fbS\"Talpey, Thomas\ 	int i, rc;
1062c56c65fbS\"Talpey, Thomas\ 
1063f531a5dbSChuck Lever 	buf->rb_bc_srv_max_requests = 0;
1064505bbe64SChuck Lever 	spin_lock_init(&buf->rb_lock);
106596ceddeaSChuck Lever 	INIT_LIST_HEAD(&buf->rb_mrs);
1066eed48a9cSChuck Lever 	INIT_LIST_HEAD(&buf->rb_all_mrs);
10673b39f52aSChuck Lever 	INIT_WORK(&buf->rb_refresh_worker, rpcrdma_mr_refresh_worker);
1068c56c65fbS\"Talpey, Thomas\ 
10691e465fd4SChuck Lever 	INIT_LIST_HEAD(&buf->rb_send_bufs);
1070f531a5dbSChuck Lever 	INIT_LIST_HEAD(&buf->rb_allreqs);
1071671c450bSChuck Lever 	INIT_LIST_HEAD(&buf->rb_all_reps);
10721769e6a8SChuck Lever 
10731769e6a8SChuck Lever 	rc = -ENOMEM;
10747581d901SChuck Lever 	for (i = 0; i < r_xprt->rx_xprt.max_reqs; i++) {
1075c56c65fbS\"Talpey, Thomas\ 		struct rpcrdma_req *req;
1076c56c65fbS\"Talpey, Thomas\ 
10773b50cc1cSChuck Lever 		req = rpcrdma_req_create(r_xprt,
10783b50cc1cSChuck Lever 					 RPCRDMA_V1_DEF_INLINE_SIZE * 2);
10791769e6a8SChuck Lever 		if (!req)
1080c56c65fbS\"Talpey, Thomas\ 			goto out;
1081a80d66c9SChuck Lever 		list_add(&req->rl_list, &buf->rb_send_bufs);
10821e465fd4SChuck Lever 	}
10831e465fd4SChuck Lever 
1084b0b227f0SChuck Lever 	init_llist_head(&buf->rb_free_reps);
10851392402cSChuck Lever 
1086c56c65fbS\"Talpey, Thomas\ 	return 0;
1087c56c65fbS\"Talpey, Thomas\ out:
1088c56c65fbS\"Talpey, Thomas\ 	rpcrdma_buffer_destroy(buf);
1089c56c65fbS\"Talpey, Thomas\ 	return rc;
1090c56c65fbS\"Talpey, Thomas\ }
1091c56c65fbS\"Talpey, Thomas\ 
109292f4433eSChuck Lever /**
109392f4433eSChuck Lever  * rpcrdma_req_destroy - Destroy an rpcrdma_req object
109492f4433eSChuck Lever  * @req: unused object to be destroyed
109592f4433eSChuck Lever  *
10969d2da4ffSChuck Lever  * Relies on caller holding the transport send lock to protect
10979d2da4ffSChuck Lever  * removing req->rl_all from buf->rb_all_reqs safely.
109892f4433eSChuck Lever  */
rpcrdma_req_destroy(struct rpcrdma_req * req)10996dc6ec9eSChuck Lever void rpcrdma_req_destroy(struct rpcrdma_req *req)
11001392402cSChuck Lever {
1101c3700780SChuck Lever 	struct rpcrdma_mr *mr;
1102c3700780SChuck Lever 
110392f4433eSChuck Lever 	list_del(&req->rl_all);
110492f4433eSChuck Lever 
1105c3700780SChuck Lever 	while ((mr = rpcrdma_mr_pop(&req->rl_free_mrs))) {
1106c3700780SChuck Lever 		struct rpcrdma_buffer *buf = &mr->mr_xprt->rx_buf;
1107c3700780SChuck Lever 
1108c3700780SChuck Lever 		spin_lock(&buf->rb_lock);
1109c3700780SChuck Lever 		list_del(&mr->mr_all);
1110c3700780SChuck Lever 		spin_unlock(&buf->rb_lock);
1111c3700780SChuck Lever 
1112f912af77SChuck Lever 		frwr_mr_release(mr);
1113c3700780SChuck Lever 	}
11146dc6ec9eSChuck Lever 
1115d2832af3SChuck Lever 	rpcrdma_regbuf_free(req->rl_recvbuf);
1116d2832af3SChuck Lever 	rpcrdma_regbuf_free(req->rl_sendbuf);
1117d2832af3SChuck Lever 	rpcrdma_regbuf_free(req->rl_rdmabuf);
11181392402cSChuck Lever 	kfree(req);
11191392402cSChuck Lever }
11201392402cSChuck Lever 
1121c3700780SChuck Lever /**
1122c3700780SChuck Lever  * rpcrdma_mrs_destroy - Release all of a transport's MRs
11239d2da4ffSChuck Lever  * @r_xprt: controlling transport instance
1124c3700780SChuck Lever  *
1125c3700780SChuck Lever  * Relies on caller holding the transport send lock to protect
1126c3700780SChuck Lever  * removing mr->mr_list from req->rl_free_mrs safely.
1127c3700780SChuck Lever  */
rpcrdma_mrs_destroy(struct rpcrdma_xprt * r_xprt)11289d2da4ffSChuck Lever static void rpcrdma_mrs_destroy(struct rpcrdma_xprt *r_xprt)
1129e2ac236cSChuck Lever {
11309d2da4ffSChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
113196ceddeaSChuck Lever 	struct rpcrdma_mr *mr;
1132e2ac236cSChuck Lever 
11339d2da4ffSChuck Lever 	cancel_work_sync(&buf->rb_refresh_worker);
11349d2da4ffSChuck Lever 
11354d6b8890SChuck Lever 	spin_lock(&buf->rb_lock);
1136eed48a9cSChuck Lever 	while ((mr = list_first_entry_or_null(&buf->rb_all_mrs,
1137eed48a9cSChuck Lever 					      struct rpcrdma_mr,
1138eed48a9cSChuck Lever 					      mr_all)) != NULL) {
1139c3700780SChuck Lever 		list_del(&mr->mr_list);
114096ceddeaSChuck Lever 		list_del(&mr->mr_all);
11414d6b8890SChuck Lever 		spin_unlock(&buf->rb_lock);
1142054f1557SChuck Lever 
1143f912af77SChuck Lever 		frwr_mr_release(mr);
11449d2da4ffSChuck Lever 
11454d6b8890SChuck Lever 		spin_lock(&buf->rb_lock);
1146e2ac236cSChuck Lever 	}
11474d6b8890SChuck Lever 	spin_unlock(&buf->rb_lock);
1148e2ac236cSChuck Lever }
1149e2ac236cSChuck Lever 
1150af65ed40SChuck Lever /**
1151af65ed40SChuck Lever  * rpcrdma_buffer_destroy - Release all hw resources
1152af65ed40SChuck Lever  * @buf: root control block for resources
1153af65ed40SChuck Lever  *
1154b8fe677fSChuck Lever  * ORDERING: relies on a prior rpcrdma_xprt_drain :
1155af65ed40SChuck Lever  * - No more Send or Receive completions can occur
1156af65ed40SChuck Lever  * - All MRs, reps, and reqs are returned to their free lists
1157af65ed40SChuck Lever  */
1158c56c65fbS\"Talpey, Thomas\ void
rpcrdma_buffer_destroy(struct rpcrdma_buffer * buf)1159c56c65fbS\"Talpey, Thomas\ rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
1160c56c65fbS\"Talpey, Thomas\ {
1161b0b227f0SChuck Lever 	rpcrdma_reps_destroy(buf);
11624034ba04SAllen Andrews 
116392f4433eSChuck Lever 	while (!list_empty(&buf->rb_send_bufs)) {
11641e465fd4SChuck Lever 		struct rpcrdma_req *req;
1165c56c65fbS\"Talpey, Thomas\ 
116692f4433eSChuck Lever 		req = list_first_entry(&buf->rb_send_bufs,
116792f4433eSChuck Lever 				       struct rpcrdma_req, rl_list);
116892f4433eSChuck Lever 		list_del(&req->rl_list);
116992f4433eSChuck Lever 		rpcrdma_req_destroy(req);
11709f9d802aSChuck Lever 	}
1171c56c65fbS\"Talpey, Thomas\ }
1172c56c65fbS\"Talpey, Thomas\ 
117396ceddeaSChuck Lever /**
117496ceddeaSChuck Lever  * rpcrdma_mr_get - Allocate an rpcrdma_mr object
117596ceddeaSChuck Lever  * @r_xprt: controlling transport
117696ceddeaSChuck Lever  *
117796ceddeaSChuck Lever  * Returns an initialized rpcrdma_mr or NULL if no free
117896ceddeaSChuck Lever  * rpcrdma_mr objects are available.
117996ceddeaSChuck Lever  */
118096ceddeaSChuck Lever struct rpcrdma_mr *
rpcrdma_mr_get(struct rpcrdma_xprt * r_xprt)118196ceddeaSChuck Lever rpcrdma_mr_get(struct rpcrdma_xprt *r_xprt)
1182c2922c02SChuck Lever {
1183346aa66bSChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1184265a38d4SChuck Lever 	struct rpcrdma_mr *mr;
1185346aa66bSChuck Lever 
11864d6b8890SChuck Lever 	spin_lock(&buf->rb_lock);
118796ceddeaSChuck Lever 	mr = rpcrdma_mr_pop(&buf->rb_mrs);
11884d6b8890SChuck Lever 	spin_unlock(&buf->rb_lock);
118996ceddeaSChuck Lever 	return mr;
1190ec12e479SChuck Lever }
1191ec12e479SChuck Lever 
119296ceddeaSChuck Lever /**
1193e86be3a0STrond Myklebust  * rpcrdma_reply_put - Put reply buffers back into pool
1194e86be3a0STrond Myklebust  * @buffers: buffer pool
1195e86be3a0STrond Myklebust  * @req: object to return
1196e86be3a0STrond Myklebust  *
1197e86be3a0STrond Myklebust  */
rpcrdma_reply_put(struct rpcrdma_buffer * buffers,struct rpcrdma_req * req)1198e86be3a0STrond Myklebust void rpcrdma_reply_put(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req)
1199e86be3a0STrond Myklebust {
1200e86be3a0STrond Myklebust 	if (req->rl_reply) {
1201e86be3a0STrond Myklebust 		rpcrdma_rep_put(buffers, req->rl_reply);
1202e86be3a0STrond Myklebust 		req->rl_reply = NULL;
1203e86be3a0STrond Myklebust 	}
1204e86be3a0STrond Myklebust }
1205e86be3a0STrond Myklebust 
1206e86be3a0STrond Myklebust /**
12077c8d9e7cSChuck Lever  * rpcrdma_buffer_get - Get a request buffer
12087c8d9e7cSChuck Lever  * @buffers: Buffer pool from which to obtain a buffer
120978d506e1SChuck Lever  *
12107c8d9e7cSChuck Lever  * Returns a fresh rpcrdma_req, or NULL if none are available.
1211c56c65fbS\"Talpey, Thomas\  */
1212c56c65fbS\"Talpey, Thomas\ struct rpcrdma_req *
rpcrdma_buffer_get(struct rpcrdma_buffer * buffers)1213c56c65fbS\"Talpey, Thomas\ rpcrdma_buffer_get(struct rpcrdma_buffer *buffers)
1214c56c65fbS\"Talpey, Thomas\ {
1215c56c65fbS\"Talpey, Thomas\ 	struct rpcrdma_req *req;
1216c56c65fbS\"Talpey, Thomas\ 
1217a5b027e1SChuck Lever 	spin_lock(&buffers->rb_lock);
1218e68699ccSChuck Lever 	req = list_first_entry_or_null(&buffers->rb_send_bufs,
1219e68699ccSChuck Lever 				       struct rpcrdma_req, rl_list);
1220e68699ccSChuck Lever 	if (req)
1221e68699ccSChuck Lever 		list_del_init(&req->rl_list);
1222a5b027e1SChuck Lever 	spin_unlock(&buffers->rb_lock);
12231e465fd4SChuck Lever 	return req;
1224c56c65fbS\"Talpey, Thomas\ }
1225c56c65fbS\"Talpey, Thomas\ 
12267c8d9e7cSChuck Lever /**
12277c8d9e7cSChuck Lever  * rpcrdma_buffer_put - Put request/reply buffers back into pool
12285828cebaSChuck Lever  * @buffers: buffer pool
12297c8d9e7cSChuck Lever  * @req: object to return
12307c8d9e7cSChuck Lever  *
1231c56c65fbS\"Talpey, Thomas\  */
rpcrdma_buffer_put(struct rpcrdma_buffer * buffers,struct rpcrdma_req * req)12325828cebaSChuck Lever void rpcrdma_buffer_put(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req)
1233c56c65fbS\"Talpey, Thomas\ {
1234e86be3a0STrond Myklebust 	rpcrdma_reply_put(buffers, req);
12351e465fd4SChuck Lever 
1236a5b027e1SChuck Lever 	spin_lock(&buffers->rb_lock);
12377c8d9e7cSChuck Lever 	list_add(&req->rl_list, &buffers->rb_send_bufs);
1238a5b027e1SChuck Lever 	spin_unlock(&buffers->rb_lock);
1239c56c65fbS\"Talpey, Thomas\ }
1240c56c65fbS\"Talpey, Thomas\ 
1241d2832af3SChuck Lever /* Returns a pointer to a rpcrdma_regbuf object, or NULL.
12429128c3e7SChuck Lever  *
12439128c3e7SChuck Lever  * xprtrdma uses a regbuf for posting an outgoing RDMA SEND, or for
124499ef4db3SChuck Lever  * receiving the payload of RDMA RECV operations. During Long Calls
12455f62412bSChuck Lever  * or Replies they may be registered externally via frwr_map.
12469128c3e7SChuck Lever  */
1247d2832af3SChuck Lever static struct rpcrdma_regbuf *
rpcrdma_regbuf_alloc(size_t size,enum dma_data_direction direction)12487ac18798SChuck Lever rpcrdma_regbuf_alloc(size_t size, enum dma_data_direction direction)
12499128c3e7SChuck Lever {
12509128c3e7SChuck Lever 	struct rpcrdma_regbuf *rb;
12519128c3e7SChuck Lever 
1252f20f18c9SChuck Lever 	rb = kmalloc(sizeof(*rb), XPRTRDMA_GFP_FLAGS);
12538cec3dbaSChuck Lever 	if (!rb)
12548cec3dbaSChuck Lever 		return NULL;
1255f20f18c9SChuck Lever 	rb->rg_data = kmalloc(size, XPRTRDMA_GFP_FLAGS);
12568cec3dbaSChuck Lever 	if (!rb->rg_data) {
12578cec3dbaSChuck Lever 		kfree(rb);
12588cec3dbaSChuck Lever 		return NULL;
12598cec3dbaSChuck Lever 	}
12609128c3e7SChuck Lever 
126154cbd6b0SChuck Lever 	rb->rg_device = NULL;
126299ef4db3SChuck Lever 	rb->rg_direction = direction;
126354cbd6b0SChuck Lever 	rb->rg_iov.length = size;
126454cbd6b0SChuck Lever 	return rb;
126554cbd6b0SChuck Lever }
126654cbd6b0SChuck Lever 
126754cbd6b0SChuck Lever /**
12680f665cebSChuck Lever  * rpcrdma_regbuf_realloc - re-allocate a SEND/RECV buffer
12690f665cebSChuck Lever  * @rb: regbuf to reallocate
12700f665cebSChuck Lever  * @size: size of buffer to be allocated, in bytes
12710f665cebSChuck Lever  * @flags: GFP flags
12720f665cebSChuck Lever  *
12730f665cebSChuck Lever  * Returns true if reallocation was successful. If false is
12740f665cebSChuck Lever  * returned, @rb is left untouched.
12750f665cebSChuck Lever  */
rpcrdma_regbuf_realloc(struct rpcrdma_regbuf * rb,size_t size,gfp_t flags)12760f665cebSChuck Lever bool rpcrdma_regbuf_realloc(struct rpcrdma_regbuf *rb, size_t size, gfp_t flags)
12770f665cebSChuck Lever {
12780f665cebSChuck Lever 	void *buf;
12790f665cebSChuck Lever 
12800f665cebSChuck Lever 	buf = kmalloc(size, flags);
12810f665cebSChuck Lever 	if (!buf)
12820f665cebSChuck Lever 		return false;
12830f665cebSChuck Lever 
1284d2832af3SChuck Lever 	rpcrdma_regbuf_dma_unmap(rb);
12850f665cebSChuck Lever 	kfree(rb->rg_data);
12860f665cebSChuck Lever 
12870f665cebSChuck Lever 	rb->rg_data = buf;
12880f665cebSChuck Lever 	rb->rg_iov.length = size;
12890f665cebSChuck Lever 	return true;
12900f665cebSChuck Lever }
12910f665cebSChuck Lever 
12920f665cebSChuck Lever /**
1293d2832af3SChuck Lever  * __rpcrdma_regbuf_dma_map - DMA-map a regbuf
1294d2832af3SChuck Lever  * @r_xprt: controlling transport instance
129554cbd6b0SChuck Lever  * @rb: regbuf to be mapped
1296d2832af3SChuck Lever  *
1297d2832af3SChuck Lever  * Returns true if the buffer is now DMA mapped to @r_xprt's device
129854cbd6b0SChuck Lever  */
__rpcrdma_regbuf_dma_map(struct rpcrdma_xprt * r_xprt,struct rpcrdma_regbuf * rb)1299d2832af3SChuck Lever bool __rpcrdma_regbuf_dma_map(struct rpcrdma_xprt *r_xprt,
1300d2832af3SChuck Lever 			      struct rpcrdma_regbuf *rb)
130154cbd6b0SChuck Lever {
1302e28ce900SChuck Lever 	struct ib_device *device = r_xprt->rx_ep->re_id->device;
130391a10c52SChuck Lever 
130454cbd6b0SChuck Lever 	if (rb->rg_direction == DMA_NONE)
130554cbd6b0SChuck Lever 		return false;
130654cbd6b0SChuck Lever 
1307d2832af3SChuck Lever 	rb->rg_iov.addr = ib_dma_map_single(device, rdmab_data(rb),
1308d2832af3SChuck Lever 					    rdmab_length(rb), rb->rg_direction);
130953b2c1cbSChuck Lever 	if (ib_dma_mapping_error(device, rdmab_addr(rb))) {
131053b2c1cbSChuck Lever 		trace_xprtrdma_dma_maperr(rdmab_addr(rb));
131154cbd6b0SChuck Lever 		return false;
131253b2c1cbSChuck Lever 	}
131354cbd6b0SChuck Lever 
131491a10c52SChuck Lever 	rb->rg_device = device;
1315e28ce900SChuck Lever 	rb->rg_iov.lkey = r_xprt->rx_ep->re_pd->local_dma_lkey;
131654cbd6b0SChuck Lever 	return true;
131799ef4db3SChuck Lever }
131899ef4db3SChuck Lever 
rpcrdma_regbuf_dma_unmap(struct rpcrdma_regbuf * rb)1319d2832af3SChuck Lever static void rpcrdma_regbuf_dma_unmap(struct rpcrdma_regbuf *rb)
132054cbd6b0SChuck Lever {
1321e89e8d8fSChuck Lever 	if (!rb)
1322e89e8d8fSChuck Lever 		return;
1323e89e8d8fSChuck Lever 
132454cbd6b0SChuck Lever 	if (!rpcrdma_regbuf_is_mapped(rb))
132554cbd6b0SChuck Lever 		return;
13269128c3e7SChuck Lever 
1327d2832af3SChuck Lever 	ib_dma_unmap_single(rb->rg_device, rdmab_addr(rb), rdmab_length(rb),
1328d2832af3SChuck Lever 			    rb->rg_direction);
132954cbd6b0SChuck Lever 	rb->rg_device = NULL;
13309128c3e7SChuck Lever }
13319128c3e7SChuck Lever 
rpcrdma_regbuf_free(struct rpcrdma_regbuf * rb)1332d2832af3SChuck Lever static void rpcrdma_regbuf_free(struct rpcrdma_regbuf *rb)
13339128c3e7SChuck Lever {
1334d2832af3SChuck Lever 	rpcrdma_regbuf_dma_unmap(rb);
13358cec3dbaSChuck Lever 	if (rb)
13368cec3dbaSChuck Lever 		kfree(rb->rg_data);
13379128c3e7SChuck Lever 	kfree(rb);
13389128c3e7SChuck Lever }
13399128c3e7SChuck Lever 
1340995d312aSChuck Lever /**
13412ae50ad6SChuck Lever  * rpcrdma_post_recvs - Refill the Receive Queue
13422ae50ad6SChuck Lever  * @r_xprt: controlling transport instance
134335d8b10aSChuck Lever  * @needed: current credit grant
134435d8b10aSChuck Lever  * @temp: mark Receive buffers to be deleted after one use
13452ae50ad6SChuck Lever  *
13462ae50ad6SChuck Lever  */
rpcrdma_post_recvs(struct rpcrdma_xprt * r_xprt,int needed,bool temp)134735d8b10aSChuck Lever void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp)
1348f531a5dbSChuck Lever {
13497c8d9e7cSChuck Lever 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1350e28ce900SChuck Lever 	struct rpcrdma_ep *ep = r_xprt->rx_ep;
1351e515dd9dSChuck Lever 	struct ib_recv_wr *wr, *bad_wr;
13529ef33ef5SChuck Lever 	struct rpcrdma_rep *rep;
135335d8b10aSChuck Lever 	int count, rc;
13547c8d9e7cSChuck Lever 
135561c208a5SChuck Lever 	rc = 0;
135661c208a5SChuck Lever 	count = 0;
13579ef33ef5SChuck Lever 
135893aa8e0aSChuck Lever 	if (likely(ep->re_receive_count > needed))
135961c208a5SChuck Lever 		goto out;
136093aa8e0aSChuck Lever 	needed -= ep->re_receive_count;
1361e340c2d6SChuck Lever 	if (!temp)
1362e340c2d6SChuck Lever 		needed += RPCRDMA_MAX_RECV_BATCH;
13637c8d9e7cSChuck Lever 
136415788d1dSChuck Lever 	if (atomic_inc_return(&ep->re_receiving) > 1)
136515788d1dSChuck Lever 		goto out;
136615788d1dSChuck Lever 
13679ef33ef5SChuck Lever 	/* fast path: all needed reps can be found on the free list */
13687c8d9e7cSChuck Lever 	wr = NULL;
13699ef33ef5SChuck Lever 	while (needed) {
1370b0b227f0SChuck Lever 		rep = rpcrdma_rep_get_locked(buf);
1371671c450bSChuck Lever 		if (rep && rep->rr_temp) {
1372671c450bSChuck Lever 			rpcrdma_rep_destroy(rep);
1373671c450bSChuck Lever 			continue;
1374671c450bSChuck Lever 		}
13759ef33ef5SChuck Lever 		if (!rep)
1376379d1bc5SChuck Lever 			rep = rpcrdma_rep_create(r_xprt, temp);
1377379d1bc5SChuck Lever 		if (!rep)
13787c8d9e7cSChuck Lever 			break;
1379895cedc1SChuck Lever 		if (!rpcrdma_regbuf_dma_map(r_xprt, rep->rr_rdmabuf)) {
1380895cedc1SChuck Lever 			rpcrdma_rep_put(buf, rep);
1381895cedc1SChuck Lever 			break;
1382895cedc1SChuck Lever 		}
1383f531a5dbSChuck Lever 
1384af5865d2SChuck Lever 		rep->rr_cid.ci_queue_id = ep->re_attr.recv_cq->res.id;
1385e515dd9dSChuck Lever 		trace_xprtrdma_post_recv(rep);
13867c8d9e7cSChuck Lever 		rep->rr_recv_wr.next = wr;
13877c8d9e7cSChuck Lever 		wr = &rep->rr_recv_wr;
13887c8d9e7cSChuck Lever 		--needed;
1389e515dd9dSChuck Lever 		++count;
13907c8d9e7cSChuck Lever 	}
13919ef33ef5SChuck Lever 	if (!wr)
139261c208a5SChuck Lever 		goto out;
13937c8d9e7cSChuck Lever 
1394e28ce900SChuck Lever 	rc = ib_post_recv(ep->re_id->qp, wr,
1395d34ac5cdSBart Van Assche 			  (const struct ib_recv_wr **)&bad_wr);
13967c8d9e7cSChuck Lever 	if (rc) {
1397683f31c3SChuck Lever 		trace_xprtrdma_post_recvs_err(r_xprt, rc);
13982d0abe36SChuck Lever 		for (wr = bad_wr; wr;) {
13997c8d9e7cSChuck Lever 			struct rpcrdma_rep *rep;
14007c8d9e7cSChuck Lever 
14017c8d9e7cSChuck Lever 			rep = container_of(wr, struct rpcrdma_rep, rr_recv_wr);
14022d0abe36SChuck Lever 			wr = wr->next;
1403c35ca60dSChuck Lever 			rpcrdma_rep_put(buf, rep);
14047c8d9e7cSChuck Lever 			--count;
14057c8d9e7cSChuck Lever 		}
14067c8d9e7cSChuck Lever 	}
140797480caeSChuck Lever 	if (atomic_dec_return(&ep->re_receiving) > 0)
140897480caeSChuck Lever 		complete(&ep->re_done);
140997480caeSChuck Lever 
141097480caeSChuck Lever out:
1411683f31c3SChuck Lever 	trace_xprtrdma_post_recvs(r_xprt, count);
141293aa8e0aSChuck Lever 	ep->re_receive_count += count;
14139ef33ef5SChuck Lever 	return;
1414f531a5dbSChuck Lever }
1415