blob: 99752b5b7354d112d0959430c398241f86019e96 [file] [log] [blame]
\"Talpey, Thomas\f58851e2007-09-10 13:50:12 -04001/*
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002 * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the BSD-type
8 * license below:
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * Redistributions in binary form must reproduce the above
18 * copyright notice, this list of conditions and the following
19 * disclaimer in the documentation and/or other materials provided
20 * with the distribution.
21 *
22 * Neither the name of the Network Appliance, Inc. nor the names of
23 * its contributors may be used to endorse or promote products
24 * derived from this software without specific prior written
25 * permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\"Talpey, Thomas\f58851e2007-09-10 13:50:12 -040038 */
39
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -040040/*
41 * verbs.c
42 *
43 * Encapsulates the major functions managing:
44 * o adapters
45 * o endpoints
46 * o connections
47 * o buffer memory
48 */
49
Alexey Dobriyana6b7a402011-06-06 10:43:46 +000050#include <linux/interrupt.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090051#include <linux/slab.h>
Chuck Levereba8ff62015-01-21 11:03:02 -050052#include <linux/prefetch.h>
Chuck Lever0dd39ca2015-03-30 14:33:43 -040053#include <linux/sunrpc/addr.h>
Chuck Lever65866f82014-05-28 10:33:59 -040054#include <asm/bitops.h>
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -040055
\"Talpey, Thomas\f58851e2007-09-10 13:50:12 -040056#include "xprt_rdma.h"
57
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -040058/*
59 * Globals/Macros
60 */
61
Jeff Laytonf895b252014-11-17 16:58:04 -050062#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -040063# define RPCDBG_FACILITY RPCDBG_TRANS
64#endif
65
Chuck Lever9f9d8022014-07-29 17:24:45 -040066static void rpcrdma_reset_frmrs(struct rpcrdma_ia *);
Chuck Lever467c9672014-11-08 20:14:29 -050067static void rpcrdma_reset_fmrs(struct rpcrdma_ia *);
Chuck Lever9f9d8022014-07-29 17:24:45 -040068
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -040069/*
70 * internal functions
71 */
72
73/*
74 * handle replies in tasklet context, using a single, global list
75 * rdma tasklet function -- just turn around and call the func
76 * for all replies on the list
77 */
78
79static DEFINE_SPINLOCK(rpcrdma_tk_lock_g);
80static LIST_HEAD(rpcrdma_tasklets_g);
81
82static void
83rpcrdma_run_tasklet(unsigned long data)
84{
85 struct rpcrdma_rep *rep;
86 void (*func)(struct rpcrdma_rep *);
87 unsigned long flags;
88
89 data = data;
90 spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
91 while (!list_empty(&rpcrdma_tasklets_g)) {
92 rep = list_entry(rpcrdma_tasklets_g.next,
93 struct rpcrdma_rep, rr_list);
94 list_del(&rep->rr_list);
95 func = rep->rr_func;
96 rep->rr_func = NULL;
97 spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
98
99 if (func)
100 func(rep);
101 else
102 rpcrdma_recv_buffer_put(rep);
103
104 spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
105 }
106 spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
107}
108
109static DECLARE_TASKLET(rpcrdma_tasklet_g, rpcrdma_run_tasklet, 0UL);
110
Chuck Lever7ff11de2014-11-08 20:15:01 -0500111static const char * const async_event[] = {
112 "CQ error",
113 "QP fatal error",
114 "QP request error",
115 "QP access error",
116 "communication established",
117 "send queue drained",
118 "path migration successful",
119 "path mig error",
120 "device fatal error",
121 "port active",
122 "port error",
123 "LID change",
124 "P_key change",
125 "SM change",
126 "SRQ error",
127 "SRQ limit reached",
128 "last WQE reached",
129 "client reregister",
130 "GID change",
131};
132
133#define ASYNC_MSG(status) \
134 ((status) < ARRAY_SIZE(async_event) ? \
135 async_event[(status)] : "unknown async error")
136
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400137static void
Chuck Leverf1a03b72014-11-08 20:14:37 -0500138rpcrdma_schedule_tasklet(struct list_head *sched_list)
139{
140 unsigned long flags;
141
142 spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
143 list_splice_tail(sched_list, &rpcrdma_tasklets_g);
144 spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
145 tasklet_schedule(&rpcrdma_tasklet_g);
146}
147
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400148static void
149rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context)
150{
151 struct rpcrdma_ep *ep = context;
152
Chuck Lever7ff11de2014-11-08 20:15:01 -0500153 pr_err("RPC: %s: %s on device %s ep %p\n",
154 __func__, ASYNC_MSG(event->event),
155 event->device->name, context);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400156 if (ep->rep_connected == 1) {
157 ep->rep_connected = -EIO;
Chuck Leverafadc462015-01-21 11:03:11 -0500158 rpcrdma_conn_func(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400159 wake_up_all(&ep->rep_connect_wait);
160 }
161}
162
163static void
164rpcrdma_cq_async_error_upcall(struct ib_event *event, void *context)
165{
166 struct rpcrdma_ep *ep = context;
167
Chuck Lever7ff11de2014-11-08 20:15:01 -0500168 pr_err("RPC: %s: %s on device %s ep %p\n",
169 __func__, ASYNC_MSG(event->event),
170 event->device->name, context);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400171 if (ep->rep_connected == 1) {
172 ep->rep_connected = -EIO;
Chuck Leverafadc462015-01-21 11:03:11 -0500173 rpcrdma_conn_func(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400174 wake_up_all(&ep->rep_connect_wait);
175 }
176}
177
Chuck Lever85024272015-01-21 11:02:04 -0500178static const char * const wc_status[] = {
179 "success",
180 "local length error",
181 "local QP operation error",
182 "local EE context operation error",
183 "local protection error",
184 "WR flushed",
185 "memory management operation error",
186 "bad response error",
187 "local access error",
188 "remote invalid request error",
189 "remote access error",
190 "remote operation error",
191 "transport retry counter exceeded",
192 "RNR retrycounter exceeded",
193 "local RDD violation error",
194 "remove invalid RD request",
195 "operation aborted",
196 "invalid EE context number",
197 "invalid EE context state",
198 "fatal error",
199 "response timeout error",
200 "general error",
201};
202
203#define COMPLETION_MSG(status) \
204 ((status) < ARRAY_SIZE(wc_status) ? \
205 wc_status[(status)] : "unexpected completion error")
206
Chuck Leverfc664482014-05-28 10:33:25 -0400207static void
208rpcrdma_sendcq_process_wc(struct ib_wc *wc)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400209{
Chuck Lever85024272015-01-21 11:02:04 -0500210 if (likely(wc->status == IB_WC_SUCCESS))
Chuck Leverfc664482014-05-28 10:33:25 -0400211 return;
Chuck Lever85024272015-01-21 11:02:04 -0500212
213 /* WARNING: Only wr_id and status are reliable at this point */
214 if (wc->wr_id == 0ULL) {
215 if (wc->status != IB_WC_WR_FLUSH_ERR)
216 pr_err("RPC: %s: SEND: %s\n",
217 __func__, COMPLETION_MSG(wc->status));
218 } else {
219 struct rpcrdma_mw *r;
220
221 r = (struct rpcrdma_mw *)(unsigned long)wc->wr_id;
222 r->r.frmr.fr_state = FRMR_IS_STALE;
223 pr_err("RPC: %s: frmr %p (stale): %s\n",
224 __func__, r, COMPLETION_MSG(wc->status));
225 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400226}
227
Chuck Leverfc664482014-05-28 10:33:25 -0400228static int
Chuck Lever1c00dd02014-05-28 10:33:42 -0400229rpcrdma_sendcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400230{
Chuck Lever1c00dd02014-05-28 10:33:42 -0400231 struct ib_wc *wcs;
Chuck Lever8301a2c2014-05-28 10:33:51 -0400232 int budget, count, rc;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400233
Chuck Lever8301a2c2014-05-28 10:33:51 -0400234 budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE;
Chuck Lever1c00dd02014-05-28 10:33:42 -0400235 do {
236 wcs = ep->rep_send_wcs;
237
238 rc = ib_poll_cq(cq, RPCRDMA_POLLSIZE, wcs);
239 if (rc <= 0)
240 return rc;
241
242 count = rc;
243 while (count-- > 0)
244 rpcrdma_sendcq_process_wc(wcs++);
Chuck Lever8301a2c2014-05-28 10:33:51 -0400245 } while (rc == RPCRDMA_POLLSIZE && --budget);
Chuck Lever1c00dd02014-05-28 10:33:42 -0400246 return 0;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400247}
248
249/*
Chuck Leverfc664482014-05-28 10:33:25 -0400250 * Handle send, fast_reg_mr, and local_inv completions.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400251 *
Chuck Leverfc664482014-05-28 10:33:25 -0400252 * Send events are typically suppressed and thus do not result
253 * in an upcall. Occasionally one is signaled, however. This
254 * prevents the provider's completion queue from wrapping and
255 * losing a completion.
256 */
257static void
258rpcrdma_sendcq_upcall(struct ib_cq *cq, void *cq_context)
259{
Chuck Lever1c00dd02014-05-28 10:33:42 -0400260 struct rpcrdma_ep *ep = (struct rpcrdma_ep *)cq_context;
Chuck Leverfc664482014-05-28 10:33:25 -0400261 int rc;
262
Chuck Lever1c00dd02014-05-28 10:33:42 -0400263 rc = rpcrdma_sendcq_poll(cq, ep);
Chuck Leverfc664482014-05-28 10:33:25 -0400264 if (rc) {
265 dprintk("RPC: %s: ib_poll_cq failed: %i\n",
266 __func__, rc);
267 return;
268 }
269
Chuck Lever7f23f6f2014-05-28 10:33:34 -0400270 rc = ib_req_notify_cq(cq,
271 IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
272 if (rc == 0)
273 return;
274 if (rc < 0) {
Chuck Leverfc664482014-05-28 10:33:25 -0400275 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
276 __func__, rc);
277 return;
278 }
279
Chuck Lever1c00dd02014-05-28 10:33:42 -0400280 rpcrdma_sendcq_poll(cq, ep);
Chuck Leverfc664482014-05-28 10:33:25 -0400281}
282
283static void
Chuck Leverbb961932014-07-29 17:25:46 -0400284rpcrdma_recvcq_process_wc(struct ib_wc *wc, struct list_head *sched_list)
Chuck Leverfc664482014-05-28 10:33:25 -0400285{
286 struct rpcrdma_rep *rep =
287 (struct rpcrdma_rep *)(unsigned long)wc->wr_id;
288
Chuck Lever85024272015-01-21 11:02:04 -0500289 /* WARNING: Only wr_id and status are reliable at this point */
290 if (wc->status != IB_WC_SUCCESS)
291 goto out_fail;
Chuck Leverfc664482014-05-28 10:33:25 -0400292
Chuck Lever85024272015-01-21 11:02:04 -0500293 /* status == SUCCESS means all fields in wc are trustworthy */
Chuck Leverfc664482014-05-28 10:33:25 -0400294 if (wc->opcode != IB_WC_RECV)
295 return;
296
Chuck Lever85024272015-01-21 11:02:04 -0500297 dprintk("RPC: %s: rep %p opcode 'recv', length %u: success\n",
298 __func__, rep, wc->byte_len);
299
Chuck Leverfc664482014-05-28 10:33:25 -0400300 rep->rr_len = wc->byte_len;
301 ib_dma_sync_single_for_cpu(rdmab_to_ia(rep->rr_buffer)->ri_id->device,
Chuck Lever6b1184c2015-01-21 11:04:25 -0500302 rdmab_addr(rep->rr_rdmabuf),
303 rep->rr_len, DMA_FROM_DEVICE);
304 prefetch(rdmab_to_msg(rep->rr_rdmabuf));
Chuck Leverfc664482014-05-28 10:33:25 -0400305
306out_schedule:
Chuck Leverbb961932014-07-29 17:25:46 -0400307 list_add_tail(&rep->rr_list, sched_list);
Chuck Lever85024272015-01-21 11:02:04 -0500308 return;
309out_fail:
310 if (wc->status != IB_WC_WR_FLUSH_ERR)
311 pr_err("RPC: %s: rep %p: %s\n",
312 __func__, rep, COMPLETION_MSG(wc->status));
313 rep->rr_len = ~0U;
314 goto out_schedule;
Chuck Leverfc664482014-05-28 10:33:25 -0400315}
316
317static int
Chuck Lever1c00dd02014-05-28 10:33:42 -0400318rpcrdma_recvcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep)
Chuck Leverfc664482014-05-28 10:33:25 -0400319{
Chuck Leverbb961932014-07-29 17:25:46 -0400320 struct list_head sched_list;
Chuck Lever1c00dd02014-05-28 10:33:42 -0400321 struct ib_wc *wcs;
Chuck Lever8301a2c2014-05-28 10:33:51 -0400322 int budget, count, rc;
Chuck Leverfc664482014-05-28 10:33:25 -0400323
Chuck Leverbb961932014-07-29 17:25:46 -0400324 INIT_LIST_HEAD(&sched_list);
Chuck Lever8301a2c2014-05-28 10:33:51 -0400325 budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE;
Chuck Lever1c00dd02014-05-28 10:33:42 -0400326 do {
327 wcs = ep->rep_recv_wcs;
328
329 rc = ib_poll_cq(cq, RPCRDMA_POLLSIZE, wcs);
330 if (rc <= 0)
Chuck Leverbb961932014-07-29 17:25:46 -0400331 goto out_schedule;
Chuck Lever1c00dd02014-05-28 10:33:42 -0400332
333 count = rc;
334 while (count-- > 0)
Chuck Leverbb961932014-07-29 17:25:46 -0400335 rpcrdma_recvcq_process_wc(wcs++, &sched_list);
Chuck Lever8301a2c2014-05-28 10:33:51 -0400336 } while (rc == RPCRDMA_POLLSIZE && --budget);
Chuck Leverbb961932014-07-29 17:25:46 -0400337 rc = 0;
338
339out_schedule:
Chuck Leverf1a03b72014-11-08 20:14:37 -0500340 rpcrdma_schedule_tasklet(&sched_list);
Chuck Leverbb961932014-07-29 17:25:46 -0400341 return rc;
Chuck Leverfc664482014-05-28 10:33:25 -0400342}
343
344/*
345 * Handle receive completions.
346 *
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400347 * It is reentrant but processes single events in order to maintain
348 * ordering of receives to keep server credits.
349 *
350 * It is the responsibility of the scheduled tasklet to return
351 * recv buffers to the pool. NOTE: this affects synchronization of
352 * connection shutdown. That is, the structures required for
353 * the completion of the reply handler must remain intact until
354 * all memory has been reclaimed.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400355 */
356static void
Chuck Leverfc664482014-05-28 10:33:25 -0400357rpcrdma_recvcq_upcall(struct ib_cq *cq, void *cq_context)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400358{
Chuck Lever1c00dd02014-05-28 10:33:42 -0400359 struct rpcrdma_ep *ep = (struct rpcrdma_ep *)cq_context;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400360 int rc;
361
Chuck Lever1c00dd02014-05-28 10:33:42 -0400362 rc = rpcrdma_recvcq_poll(cq, ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400363 if (rc) {
Chuck Leverfc664482014-05-28 10:33:25 -0400364 dprintk("RPC: %s: ib_poll_cq failed: %i\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400365 __func__, rc);
366 return;
367 }
368
Chuck Lever7f23f6f2014-05-28 10:33:34 -0400369 rc = ib_req_notify_cq(cq,
370 IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
371 if (rc == 0)
372 return;
373 if (rc < 0) {
Chuck Leverfc664482014-05-28 10:33:25 -0400374 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
375 __func__, rc);
376 return;
377 }
378
Chuck Lever1c00dd02014-05-28 10:33:42 -0400379 rpcrdma_recvcq_poll(cq, ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400380}
381
Chuck Levera7bc2112014-07-29 17:23:52 -0400382static void
383rpcrdma_flush_cqs(struct rpcrdma_ep *ep)
384{
Chuck Lever5c166be2014-11-08 20:14:45 -0500385 struct ib_wc wc;
386 LIST_HEAD(sched_list);
387
388 while (ib_poll_cq(ep->rep_attr.recv_cq, 1, &wc) > 0)
389 rpcrdma_recvcq_process_wc(&wc, &sched_list);
390 if (!list_empty(&sched_list))
391 rpcrdma_schedule_tasklet(&sched_list);
392 while (ib_poll_cq(ep->rep_attr.send_cq, 1, &wc) > 0)
393 rpcrdma_sendcq_process_wc(&wc);
Chuck Levera7bc2112014-07-29 17:23:52 -0400394}
395
Jeff Laytonf895b252014-11-17 16:58:04 -0500396#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400397static const char * const conn[] = {
398 "address resolved",
399 "address error",
400 "route resolved",
401 "route error",
402 "connect request",
403 "connect response",
404 "connect error",
405 "unreachable",
406 "rejected",
407 "established",
408 "disconnected",
Chuck Lever8079fb72014-07-29 17:26:12 -0400409 "device removal",
410 "multicast join",
411 "multicast error",
412 "address change",
413 "timewait exit",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400414};
Chuck Lever8079fb72014-07-29 17:26:12 -0400415
416#define CONNECTION_MSG(status) \
417 ((status) < ARRAY_SIZE(conn) ? \
418 conn[(status)] : "unrecognized connection error")
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400419#endif
420
421static int
422rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
423{
424 struct rpcrdma_xprt *xprt = id->context;
425 struct rpcrdma_ia *ia = &xprt->rx_ia;
426 struct rpcrdma_ep *ep = &xprt->rx_ep;
Jeff Laytonf895b252014-11-17 16:58:04 -0500427#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
Chuck Lever0dd39ca2015-03-30 14:33:43 -0400428 struct sockaddr *sap = (struct sockaddr *)&ep->rep_remote_addr;
Ingo Molnarff0db042008-11-25 16:58:42 -0800429#endif
Chuck Leverce1ab9a2015-01-21 11:03:35 -0500430 struct ib_qp_attr *attr = &ia->ri_qp_attr;
431 struct ib_qp_init_attr *iattr = &ia->ri_qp_init_attr;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400432 int connstate = 0;
433
434 switch (event->event) {
435 case RDMA_CM_EVENT_ADDR_RESOLVED:
436 case RDMA_CM_EVENT_ROUTE_RESOLVED:
Tom Talpey5675add2008-10-09 15:01:41 -0400437 ia->ri_async_rc = 0;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400438 complete(&ia->ri_done);
439 break;
440 case RDMA_CM_EVENT_ADDR_ERROR:
441 ia->ri_async_rc = -EHOSTUNREACH;
442 dprintk("RPC: %s: CM address resolution error, ep 0x%p\n",
443 __func__, ep);
444 complete(&ia->ri_done);
445 break;
446 case RDMA_CM_EVENT_ROUTE_ERROR:
447 ia->ri_async_rc = -ENETUNREACH;
448 dprintk("RPC: %s: CM route resolution error, ep 0x%p\n",
449 __func__, ep);
450 complete(&ia->ri_done);
451 break;
452 case RDMA_CM_EVENT_ESTABLISHED:
453 connstate = 1;
Chuck Leverce1ab9a2015-01-21 11:03:35 -0500454 ib_query_qp(ia->ri_id->qp, attr,
455 IB_QP_MAX_QP_RD_ATOMIC | IB_QP_MAX_DEST_RD_ATOMIC,
456 iattr);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400457 dprintk("RPC: %s: %d responder resources"
458 " (%d initiator)\n",
Chuck Leverce1ab9a2015-01-21 11:03:35 -0500459 __func__, attr->max_dest_rd_atomic,
460 attr->max_rd_atomic);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400461 goto connected;
462 case RDMA_CM_EVENT_CONNECT_ERROR:
463 connstate = -ENOTCONN;
464 goto connected;
465 case RDMA_CM_EVENT_UNREACHABLE:
466 connstate = -ENETDOWN;
467 goto connected;
468 case RDMA_CM_EVENT_REJECTED:
469 connstate = -ECONNREFUSED;
470 goto connected;
471 case RDMA_CM_EVENT_DISCONNECTED:
472 connstate = -ECONNABORTED;
473 goto connected;
474 case RDMA_CM_EVENT_DEVICE_REMOVAL:
475 connstate = -ENODEV;
476connected:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400477 dprintk("RPC: %s: %sconnected\n",
478 __func__, connstate > 0 ? "" : "dis");
479 ep->rep_connected = connstate;
Chuck Leverafadc462015-01-21 11:03:11 -0500480 rpcrdma_conn_func(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400481 wake_up_all(&ep->rep_connect_wait);
Chuck Lever8079fb72014-07-29 17:26:12 -0400482 /*FALLTHROUGH*/
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400483 default:
Chuck Lever0dd39ca2015-03-30 14:33:43 -0400484 dprintk("RPC: %s: %pIS:%u (ep 0x%p): %s\n",
485 __func__, sap, rpc_get_port(sap), ep,
Chuck Lever8079fb72014-07-29 17:26:12 -0400486 CONNECTION_MSG(event->event));
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400487 break;
488 }
489
Jeff Laytonf895b252014-11-17 16:58:04 -0500490#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400491 if (connstate == 1) {
Chuck Leverce1ab9a2015-01-21 11:03:35 -0500492 int ird = attr->max_dest_rd_atomic;
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400493 int tird = ep->rep_remote_cma.responder_resources;
Chuck Lever0dd39ca2015-03-30 14:33:43 -0400494
495 pr_info("rpcrdma: connection to %pIS:%u on %s, memreg %d slots %d ird %d%s\n",
496 sap, rpc_get_port(sap),
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400497 ia->ri_id->device->name,
498 ia->ri_memreg_strategy,
499 xprt->rx_buf.rb_max_requests,
500 ird, ird < 4 && ird < tird / 2 ? " (low!)" : "");
501 } else if (connstate < 0) {
Chuck Lever0dd39ca2015-03-30 14:33:43 -0400502 pr_info("rpcrdma: connection to %pIS:%u closed (%d)\n",
503 sap, rpc_get_port(sap), connstate);
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400504 }
505#endif
506
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400507 return 0;
508}
509
510static struct rdma_cm_id *
511rpcrdma_create_id(struct rpcrdma_xprt *xprt,
512 struct rpcrdma_ia *ia, struct sockaddr *addr)
513{
514 struct rdma_cm_id *id;
515 int rc;
516
Tom Talpey1a954052008-10-09 15:01:31 -0400517 init_completion(&ia->ri_done);
518
Sean Heftyb26f9b92010-04-01 17:08:41 +0000519 id = rdma_create_id(rpcrdma_conn_upcall, xprt, RDMA_PS_TCP, IB_QPT_RC);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400520 if (IS_ERR(id)) {
521 rc = PTR_ERR(id);
522 dprintk("RPC: %s: rdma_create_id() failed %i\n",
523 __func__, rc);
524 return id;
525 }
526
Tom Talpey5675add2008-10-09 15:01:41 -0400527 ia->ri_async_rc = -ETIMEDOUT;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400528 rc = rdma_resolve_addr(id, NULL, addr, RDMA_RESOLVE_TIMEOUT);
529 if (rc) {
530 dprintk("RPC: %s: rdma_resolve_addr() failed %i\n",
531 __func__, rc);
532 goto out;
533 }
Tom Talpey5675add2008-10-09 15:01:41 -0400534 wait_for_completion_interruptible_timeout(&ia->ri_done,
535 msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT) + 1);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400536 rc = ia->ri_async_rc;
537 if (rc)
538 goto out;
539
Tom Talpey5675add2008-10-09 15:01:41 -0400540 ia->ri_async_rc = -ETIMEDOUT;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400541 rc = rdma_resolve_route(id, RDMA_RESOLVE_TIMEOUT);
542 if (rc) {
543 dprintk("RPC: %s: rdma_resolve_route() failed %i\n",
544 __func__, rc);
545 goto out;
546 }
Tom Talpey5675add2008-10-09 15:01:41 -0400547 wait_for_completion_interruptible_timeout(&ia->ri_done,
548 msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT) + 1);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400549 rc = ia->ri_async_rc;
550 if (rc)
551 goto out;
552
553 return id;
554
555out:
556 rdma_destroy_id(id);
557 return ERR_PTR(rc);
558}
559
560/*
561 * Drain any cq, prior to teardown.
562 */
563static void
564rpcrdma_clean_cq(struct ib_cq *cq)
565{
566 struct ib_wc wc;
567 int count = 0;
568
569 while (1 == ib_poll_cq(cq, 1, &wc))
570 ++count;
571
572 if (count)
573 dprintk("RPC: %s: flushed %d events (last 0x%x)\n",
574 __func__, count, wc.opcode);
575}
576
577/*
578 * Exported functions.
579 */
580
581/*
582 * Open and initialize an Interface Adapter.
583 * o initializes fields of struct rpcrdma_ia, including
584 * interface and provider attributes and protection zone.
585 */
586int
587rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg)
588{
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400589 int rc, mem_priv;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400590 struct rpcrdma_ia *ia = &xprt->rx_ia;
Chuck Lever7bc79722015-01-21 11:03:27 -0500591 struct ib_device_attr *devattr = &ia->ri_devattr;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400592
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400593 ia->ri_id = rpcrdma_create_id(xprt, ia, addr);
594 if (IS_ERR(ia->ri_id)) {
595 rc = PTR_ERR(ia->ri_id);
596 goto out1;
597 }
598
599 ia->ri_pd = ib_alloc_pd(ia->ri_id->device);
600 if (IS_ERR(ia->ri_pd)) {
601 rc = PTR_ERR(ia->ri_pd);
602 dprintk("RPC: %s: ib_alloc_pd() failed %i\n",
603 __func__, rc);
604 goto out2;
605 }
606
Chuck Lever7bc79722015-01-21 11:03:27 -0500607 rc = ib_query_device(ia->ri_id->device, devattr);
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400608 if (rc) {
609 dprintk("RPC: %s: ib_query_device failed %d\n",
610 __func__, rc);
Chuck Lever5ae711a2015-01-21 11:03:19 -0500611 goto out3;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400612 }
613
Chuck Lever7bc79722015-01-21 11:03:27 -0500614 if (devattr->device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY) {
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400615 ia->ri_have_dma_lkey = 1;
616 ia->ri_dma_lkey = ia->ri_id->device->local_dma_lkey;
617 }
618
Chuck Leverf10eafd2014-05-28 10:32:51 -0400619 if (memreg == RPCRDMA_FRMR) {
Tom Talpey3197d3092008-10-09 15:00:20 -0400620 /* Requires both frmr reg and local dma lkey */
Chuck Lever41f97022015-03-30 14:34:12 -0400621 if (((devattr->device_cap_flags &
Tom Talpey3197d3092008-10-09 15:00:20 -0400622 (IB_DEVICE_MEM_MGT_EXTENSIONS|IB_DEVICE_LOCAL_DMA_LKEY)) !=
Chuck Lever41f97022015-03-30 14:34:12 -0400623 (IB_DEVICE_MEM_MGT_EXTENSIONS|IB_DEVICE_LOCAL_DMA_LKEY)) ||
624 (devattr->max_fast_reg_page_list_len == 0)) {
Tom Talpey3197d3092008-10-09 15:00:20 -0400625 dprintk("RPC: %s: FRMR registration "
Chuck Leverf10eafd2014-05-28 10:32:51 -0400626 "not supported by HCA\n", __func__);
627 memreg = RPCRDMA_MTHCAFMR;
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400628 } else {
629 /* Mind the ia limit on FRMR page list depth */
630 ia->ri_max_frmr_depth = min_t(unsigned int,
631 RPCRDMA_MAX_DATA_SEGS,
Chuck Lever7bc79722015-01-21 11:03:27 -0500632 devattr->max_fast_reg_page_list_len);
Tom Talpey3197d3092008-10-09 15:00:20 -0400633 }
Chuck Leverf10eafd2014-05-28 10:32:51 -0400634 }
635 if (memreg == RPCRDMA_MTHCAFMR) {
636 if (!ia->ri_id->device->alloc_fmr) {
637 dprintk("RPC: %s: MTHCAFMR registration "
638 "not supported by HCA\n", __func__);
Chuck Leverf10eafd2014-05-28 10:32:51 -0400639 memreg = RPCRDMA_ALLPHYSICAL;
Chuck Leverf10eafd2014-05-28 10:32:51 -0400640 }
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400641 }
642
643 /*
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400644 * Optionally obtain an underlying physical identity mapping in
645 * order to do a memory window-based bind. This base registration
646 * is protected from remote access - that is enabled only by binding
647 * for the specific bytes targeted during each RPC operation, and
648 * revoked after the corresponding completion similar to a storage
649 * adapter.
650 */
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400651 switch (memreg) {
Tom Talpey3197d3092008-10-09 15:00:20 -0400652 case RPCRDMA_FRMR:
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400653 break;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400654 case RPCRDMA_ALLPHYSICAL:
655 mem_priv = IB_ACCESS_LOCAL_WRITE |
656 IB_ACCESS_REMOTE_WRITE |
657 IB_ACCESS_REMOTE_READ;
658 goto register_setup;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400659 case RPCRDMA_MTHCAFMR:
660 if (ia->ri_have_dma_lkey)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400661 break;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400662 mem_priv = IB_ACCESS_LOCAL_WRITE;
663 register_setup:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400664 ia->ri_bind_mem = ib_get_dma_mr(ia->ri_pd, mem_priv);
665 if (IS_ERR(ia->ri_bind_mem)) {
666 printk(KERN_ALERT "%s: ib_get_dma_mr for "
Chuck Lever0ac531c2014-05-28 10:32:43 -0400667 "phys register failed with %lX\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400668 __func__, PTR_ERR(ia->ri_bind_mem));
Chuck Lever0ac531c2014-05-28 10:32:43 -0400669 rc = -ENOMEM;
Chuck Lever5ae711a2015-01-21 11:03:19 -0500670 goto out3;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400671 }
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400672 break;
673 default:
Chuck Levercdd9ade2014-05-28 10:33:00 -0400674 printk(KERN_ERR "RPC: Unsupported memory "
675 "registration mode: %d\n", memreg);
676 rc = -ENOMEM;
Chuck Lever5ae711a2015-01-21 11:03:19 -0500677 goto out3;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400678 }
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400679 dprintk("RPC: %s: memory registration strategy is %d\n",
680 __func__, memreg);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400681
682 /* Else will do memory reg/dereg for each chunk */
683 ia->ri_memreg_strategy = memreg;
684
Chuck Lever73806c82014-07-29 17:23:25 -0400685 rwlock_init(&ia->ri_qplock);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400686 return 0;
Chuck Lever5ae711a2015-01-21 11:03:19 -0500687
688out3:
689 ib_dealloc_pd(ia->ri_pd);
690 ia->ri_pd = NULL;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400691out2:
692 rdma_destroy_id(ia->ri_id);
Tom Talpeyfee08ca2008-10-09 15:01:00 -0400693 ia->ri_id = NULL;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400694out1:
695 return rc;
696}
697
698/*
699 * Clean up/close an IA.
700 * o if event handles and PD have been initialized, free them.
701 * o close the IA
702 */
703void
704rpcrdma_ia_close(struct rpcrdma_ia *ia)
705{
706 int rc;
707
708 dprintk("RPC: %s: entering\n", __func__);
709 if (ia->ri_bind_mem != NULL) {
710 rc = ib_dereg_mr(ia->ri_bind_mem);
711 dprintk("RPC: %s: ib_dereg_mr returned %i\n",
712 __func__, rc);
713 }
Tom Talpeyfee08ca2008-10-09 15:01:00 -0400714 if (ia->ri_id != NULL && !IS_ERR(ia->ri_id)) {
715 if (ia->ri_id->qp)
716 rdma_destroy_qp(ia->ri_id);
717 rdma_destroy_id(ia->ri_id);
718 ia->ri_id = NULL;
719 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400720 if (ia->ri_pd != NULL && !IS_ERR(ia->ri_pd)) {
721 rc = ib_dealloc_pd(ia->ri_pd);
722 dprintk("RPC: %s: ib_dealloc_pd returned %i\n",
723 __func__, rc);
724 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400725}
726
727/*
728 * Create unconnected endpoint.
729 */
730int
731rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
732 struct rpcrdma_create_data_internal *cdata)
733{
Chuck Lever7bc79722015-01-21 11:03:27 -0500734 struct ib_device_attr *devattr = &ia->ri_devattr;
Chuck Leverfc664482014-05-28 10:33:25 -0400735 struct ib_cq *sendcq, *recvcq;
Chuck Lever5d40a8a2007-10-26 13:30:54 -0400736 int rc, err;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400737
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400738 /* check provider's send/recv wr limits */
Chuck Lever7bc79722015-01-21 11:03:27 -0500739 if (cdata->max_requests > devattr->max_qp_wr)
740 cdata->max_requests = devattr->max_qp_wr;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400741
742 ep->rep_attr.event_handler = rpcrdma_qp_async_error_upcall;
743 ep->rep_attr.qp_context = ep;
744 /* send_cq and recv_cq initialized below */
745 ep->rep_attr.srq = NULL;
746 ep->rep_attr.cap.max_send_wr = cdata->max_requests;
747 switch (ia->ri_memreg_strategy) {
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400748 case RPCRDMA_FRMR: {
749 int depth = 7;
750
Tom Tucker15cdc6442010-08-11 12:47:24 -0400751 /* Add room for frmr register and invalidate WRs.
752 * 1. FRMR reg WR for head
753 * 2. FRMR invalidate WR for head
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400754 * 3. N FRMR reg WRs for pagelist
755 * 4. N FRMR invalidate WRs for pagelist
Tom Tucker15cdc6442010-08-11 12:47:24 -0400756 * 5. FRMR reg WR for tail
757 * 6. FRMR invalidate WR for tail
758 * 7. The RDMA_SEND WR
759 */
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400760
761 /* Calculate N if the device max FRMR depth is smaller than
762 * RPCRDMA_MAX_DATA_SEGS.
763 */
764 if (ia->ri_max_frmr_depth < RPCRDMA_MAX_DATA_SEGS) {
765 int delta = RPCRDMA_MAX_DATA_SEGS -
766 ia->ri_max_frmr_depth;
767
768 do {
769 depth += 2; /* FRMR reg + invalidate */
770 delta -= ia->ri_max_frmr_depth;
771 } while (delta > 0);
772
773 }
774 ep->rep_attr.cap.max_send_wr *= depth;
Chuck Lever7bc79722015-01-21 11:03:27 -0500775 if (ep->rep_attr.cap.max_send_wr > devattr->max_qp_wr) {
776 cdata->max_requests = devattr->max_qp_wr / depth;
Tom Tucker15cdc6442010-08-11 12:47:24 -0400777 if (!cdata->max_requests)
778 return -EINVAL;
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400779 ep->rep_attr.cap.max_send_wr = cdata->max_requests *
780 depth;
Tom Tucker15cdc6442010-08-11 12:47:24 -0400781 }
Tom Talpey3197d3092008-10-09 15:00:20 -0400782 break;
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400783 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400784 default:
785 break;
786 }
787 ep->rep_attr.cap.max_recv_wr = cdata->max_requests;
788 ep->rep_attr.cap.max_send_sge = (cdata->padding ? 4 : 2);
789 ep->rep_attr.cap.max_recv_sge = 1;
790 ep->rep_attr.cap.max_inline_data = 0;
791 ep->rep_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
792 ep->rep_attr.qp_type = IB_QPT_RC;
793 ep->rep_attr.port_num = ~0;
794
Chuck Leverc05fbb52015-01-21 11:04:33 -0500795 if (cdata->padding) {
796 ep->rep_padbuf = rpcrdma_alloc_regbuf(ia, cdata->padding,
797 GFP_KERNEL);
798 if (IS_ERR(ep->rep_padbuf))
799 return PTR_ERR(ep->rep_padbuf);
800 } else
801 ep->rep_padbuf = NULL;
802
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400803 dprintk("RPC: %s: requested max: dtos: send %d recv %d; "
804 "iovs: send %d recv %d\n",
805 __func__,
806 ep->rep_attr.cap.max_send_wr,
807 ep->rep_attr.cap.max_recv_wr,
808 ep->rep_attr.cap.max_send_sge,
809 ep->rep_attr.cap.max_recv_sge);
810
811 /* set trigger for requesting send completion */
Chuck Leverfc664482014-05-28 10:33:25 -0400812 ep->rep_cqinit = ep->rep_attr.cap.max_send_wr/2 - 1;
Chuck Levere7104a22014-11-08 20:14:20 -0500813 if (ep->rep_cqinit > RPCRDMA_MAX_UNSIGNALED_SENDS)
814 ep->rep_cqinit = RPCRDMA_MAX_UNSIGNALED_SENDS;
815 else if (ep->rep_cqinit <= 2)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400816 ep->rep_cqinit = 0;
817 INIT_CQCOUNT(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400818 init_waitqueue_head(&ep->rep_connect_wait);
Chuck Lever254f91e2014-05-28 10:32:17 -0400819 INIT_DELAYED_WORK(&ep->rep_connect_worker, rpcrdma_connect_worker);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400820
Chuck Leverfc664482014-05-28 10:33:25 -0400821 sendcq = ib_create_cq(ia->ri_id->device, rpcrdma_sendcq_upcall,
Chuck Lever1c00dd02014-05-28 10:33:42 -0400822 rpcrdma_cq_async_error_upcall, ep,
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400823 ep->rep_attr.cap.max_send_wr + 1, 0);
Chuck Leverfc664482014-05-28 10:33:25 -0400824 if (IS_ERR(sendcq)) {
825 rc = PTR_ERR(sendcq);
826 dprintk("RPC: %s: failed to create send CQ: %i\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400827 __func__, rc);
828 goto out1;
829 }
830
Chuck Leverfc664482014-05-28 10:33:25 -0400831 rc = ib_req_notify_cq(sendcq, IB_CQ_NEXT_COMP);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400832 if (rc) {
833 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
834 __func__, rc);
835 goto out2;
836 }
837
Chuck Leverfc664482014-05-28 10:33:25 -0400838 recvcq = ib_create_cq(ia->ri_id->device, rpcrdma_recvcq_upcall,
Chuck Lever1c00dd02014-05-28 10:33:42 -0400839 rpcrdma_cq_async_error_upcall, ep,
Chuck Leverfc664482014-05-28 10:33:25 -0400840 ep->rep_attr.cap.max_recv_wr + 1, 0);
841 if (IS_ERR(recvcq)) {
842 rc = PTR_ERR(recvcq);
843 dprintk("RPC: %s: failed to create recv CQ: %i\n",
844 __func__, rc);
845 goto out2;
846 }
847
848 rc = ib_req_notify_cq(recvcq, IB_CQ_NEXT_COMP);
849 if (rc) {
850 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
851 __func__, rc);
852 ib_destroy_cq(recvcq);
853 goto out2;
854 }
855
856 ep->rep_attr.send_cq = sendcq;
857 ep->rep_attr.recv_cq = recvcq;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400858
859 /* Initialize cma parameters */
860
861 /* RPC/RDMA does not use private data */
862 ep->rep_remote_cma.private_data = NULL;
863 ep->rep_remote_cma.private_data_len = 0;
864
865 /* Client offers RDMA Read but does not initiate */
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400866 ep->rep_remote_cma.initiator_depth = 0;
Chuck Lever7bc79722015-01-21 11:03:27 -0500867 if (devattr->max_qp_rd_atom > 32) /* arbitrary but <= 255 */
Tom Tuckerb334eaa2008-10-09 15:00:30 -0400868 ep->rep_remote_cma.responder_resources = 32;
869 else
Chuck Lever7bc79722015-01-21 11:03:27 -0500870 ep->rep_remote_cma.responder_resources =
871 devattr->max_qp_rd_atom;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400872
873 ep->rep_remote_cma.retry_count = 7;
874 ep->rep_remote_cma.flow_control = 0;
875 ep->rep_remote_cma.rnr_retry_count = 0;
876
877 return 0;
878
879out2:
Chuck Leverfc664482014-05-28 10:33:25 -0400880 err = ib_destroy_cq(sendcq);
Chuck Lever5d40a8a2007-10-26 13:30:54 -0400881 if (err)
882 dprintk("RPC: %s: ib_destroy_cq returned %i\n",
883 __func__, err);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400884out1:
Chuck Leverc05fbb52015-01-21 11:04:33 -0500885 rpcrdma_free_regbuf(ia, ep->rep_padbuf);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400886 return rc;
887}
888
889/*
890 * rpcrdma_ep_destroy
891 *
892 * Disconnect and destroy endpoint. After this, the only
893 * valid operations on the ep are to free it (if dynamically
894 * allocated) or re-create it.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400895 */
Chuck Lever7f1d5412014-05-28 10:33:16 -0400896void
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400897rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
898{
899 int rc;
900
901 dprintk("RPC: %s: entering, connected is %d\n",
902 __func__, ep->rep_connected);
903
Chuck Lever254f91e2014-05-28 10:32:17 -0400904 cancel_delayed_work_sync(&ep->rep_connect_worker);
905
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400906 if (ia->ri_id->qp) {
Chuck Lever282191c2014-07-29 17:25:55 -0400907 rpcrdma_ep_disconnect(ep, ia);
Tom Talpeyfee08ca2008-10-09 15:01:00 -0400908 rdma_destroy_qp(ia->ri_id);
909 ia->ri_id->qp = NULL;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400910 }
911
Chuck Leverc05fbb52015-01-21 11:04:33 -0500912 rpcrdma_free_regbuf(ia, ep->rep_padbuf);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400913
Chuck Leverfc664482014-05-28 10:33:25 -0400914 rpcrdma_clean_cq(ep->rep_attr.recv_cq);
915 rc = ib_destroy_cq(ep->rep_attr.recv_cq);
916 if (rc)
917 dprintk("RPC: %s: ib_destroy_cq returned %i\n",
918 __func__, rc);
919
920 rpcrdma_clean_cq(ep->rep_attr.send_cq);
921 rc = ib_destroy_cq(ep->rep_attr.send_cq);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400922 if (rc)
923 dprintk("RPC: %s: ib_destroy_cq returned %i\n",
924 __func__, rc);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400925}
926
927/*
928 * Connect unconnected endpoint.
929 */
930int
931rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
932{
Chuck Lever73806c82014-07-29 17:23:25 -0400933 struct rdma_cm_id *id, *old;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400934 int rc = 0;
935 int retry_count = 0;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400936
Tom Talpeyc0555512008-10-10 11:32:45 -0400937 if (ep->rep_connected != 0) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400938 struct rpcrdma_xprt *xprt;
939retry:
Chuck Leverec62f402014-05-28 10:34:07 -0400940 dprintk("RPC: %s: reconnecting...\n", __func__);
Chuck Lever282191c2014-07-29 17:25:55 -0400941
942 rpcrdma_ep_disconnect(ep, ia);
Chuck Levera7bc2112014-07-29 17:23:52 -0400943 rpcrdma_flush_cqs(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400944
Chuck Lever467c9672014-11-08 20:14:29 -0500945 switch (ia->ri_memreg_strategy) {
946 case RPCRDMA_FRMR:
Chuck Lever9f9d8022014-07-29 17:24:45 -0400947 rpcrdma_reset_frmrs(ia);
Chuck Lever467c9672014-11-08 20:14:29 -0500948 break;
949 case RPCRDMA_MTHCAFMR:
950 rpcrdma_reset_fmrs(ia);
951 break;
952 case RPCRDMA_ALLPHYSICAL:
953 break;
954 default:
955 rc = -EIO;
956 goto out;
957 }
Chuck Lever9f9d8022014-07-29 17:24:45 -0400958
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400959 xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
960 id = rpcrdma_create_id(xprt, ia,
961 (struct sockaddr *)&xprt->rx_data.addr);
962 if (IS_ERR(id)) {
Chuck Leverec62f402014-05-28 10:34:07 -0400963 rc = -EHOSTUNREACH;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400964 goto out;
965 }
966 /* TEMP TEMP TEMP - fail if new device:
967 * Deregister/remarshal *all* requests!
968 * Close and recreate adapter, pd, etc!
969 * Re-determine all attributes still sane!
970 * More stuff I haven't thought of!
971 * Rrrgh!
972 */
973 if (ia->ri_id->device != id->device) {
974 printk("RPC: %s: can't reconnect on "
975 "different device!\n", __func__);
976 rdma_destroy_id(id);
Chuck Leverec62f402014-05-28 10:34:07 -0400977 rc = -ENETUNREACH;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400978 goto out;
979 }
980 /* END TEMP */
Chuck Leverec62f402014-05-28 10:34:07 -0400981 rc = rdma_create_qp(id, ia->ri_pd, &ep->rep_attr);
982 if (rc) {
983 dprintk("RPC: %s: rdma_create_qp failed %i\n",
984 __func__, rc);
985 rdma_destroy_id(id);
986 rc = -ENETUNREACH;
987 goto out;
988 }
Chuck Lever73806c82014-07-29 17:23:25 -0400989
990 write_lock(&ia->ri_qplock);
991 old = ia->ri_id;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400992 ia->ri_id = id;
Chuck Lever73806c82014-07-29 17:23:25 -0400993 write_unlock(&ia->ri_qplock);
994
995 rdma_destroy_qp(old);
996 rdma_destroy_id(old);
Chuck Leverec62f402014-05-28 10:34:07 -0400997 } else {
998 dprintk("RPC: %s: connecting...\n", __func__);
999 rc = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr);
1000 if (rc) {
1001 dprintk("RPC: %s: rdma_create_qp failed %i\n",
1002 __func__, rc);
1003 /* do not update ep->rep_connected */
1004 return -ENETUNREACH;
1005 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001006 }
1007
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001008 ep->rep_connected = 0;
1009
1010 rc = rdma_connect(ia->ri_id, &ep->rep_remote_cma);
1011 if (rc) {
1012 dprintk("RPC: %s: rdma_connect() failed with %i\n",
1013 __func__, rc);
1014 goto out;
1015 }
1016
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001017 wait_event_interruptible(ep->rep_connect_wait, ep->rep_connected != 0);
1018
1019 /*
1020 * Check state. A non-peer reject indicates no listener
1021 * (ECONNREFUSED), which may be a transient state. All
1022 * others indicate a transport condition which has already
1023 * undergone a best-effort.
1024 */
Joe Perchesf64f9e72009-11-29 16:55:45 -08001025 if (ep->rep_connected == -ECONNREFUSED &&
1026 ++retry_count <= RDMA_CONNECT_RETRY_MAX) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001027 dprintk("RPC: %s: non-peer_reject, retry\n", __func__);
1028 goto retry;
1029 }
1030 if (ep->rep_connected <= 0) {
1031 /* Sometimes, the only way to reliably connect to remote
1032 * CMs is to use same nonzero values for ORD and IRD. */
Tom Tuckerb334eaa2008-10-09 15:00:30 -04001033 if (retry_count++ <= RDMA_CONNECT_RETRY_MAX + 1 &&
1034 (ep->rep_remote_cma.responder_resources == 0 ||
1035 ep->rep_remote_cma.initiator_depth !=
1036 ep->rep_remote_cma.responder_resources)) {
1037 if (ep->rep_remote_cma.responder_resources == 0)
1038 ep->rep_remote_cma.responder_resources = 1;
1039 ep->rep_remote_cma.initiator_depth =
1040 ep->rep_remote_cma.responder_resources;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001041 goto retry;
Tom Tuckerb334eaa2008-10-09 15:00:30 -04001042 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001043 rc = ep->rep_connected;
1044 } else {
1045 dprintk("RPC: %s: connected\n", __func__);
1046 }
1047
1048out:
1049 if (rc)
1050 ep->rep_connected = rc;
1051 return rc;
1052}
1053
1054/*
1055 * rpcrdma_ep_disconnect
1056 *
1057 * This is separate from destroy to facilitate the ability
1058 * to reconnect without recreating the endpoint.
1059 *
1060 * This call is not reentrant, and must not be made in parallel
1061 * on the same endpoint.
1062 */
Chuck Lever282191c2014-07-29 17:25:55 -04001063void
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001064rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
1065{
1066 int rc;
1067
Chuck Levera7bc2112014-07-29 17:23:52 -04001068 rpcrdma_flush_cqs(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001069 rc = rdma_disconnect(ia->ri_id);
1070 if (!rc) {
1071 /* returns without wait if not connected */
1072 wait_event_interruptible(ep->rep_connect_wait,
1073 ep->rep_connected != 1);
1074 dprintk("RPC: %s: after wait, %sconnected\n", __func__,
1075 (ep->rep_connected == 1) ? "still " : "dis");
1076 } else {
1077 dprintk("RPC: %s: rdma_disconnect %i\n", __func__, rc);
1078 ep->rep_connected = rc;
1079 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001080}
1081
Chuck Lever13924022015-01-21 11:03:52 -05001082static struct rpcrdma_req *
1083rpcrdma_create_req(struct rpcrdma_xprt *r_xprt)
1084{
Chuck Lever13924022015-01-21 11:03:52 -05001085 struct rpcrdma_req *req;
Chuck Lever13924022015-01-21 11:03:52 -05001086
Chuck Lever85275c82015-01-21 11:04:16 -05001087 req = kzalloc(sizeof(*req), GFP_KERNEL);
Chuck Lever13924022015-01-21 11:03:52 -05001088 if (req == NULL)
Chuck Lever85275c82015-01-21 11:04:16 -05001089 return ERR_PTR(-ENOMEM);
Chuck Lever13924022015-01-21 11:03:52 -05001090
Chuck Lever13924022015-01-21 11:03:52 -05001091 req->rl_buffer = &r_xprt->rx_buf;
1092 return req;
Chuck Lever13924022015-01-21 11:03:52 -05001093}
1094
1095static struct rpcrdma_rep *
1096rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt)
1097{
1098 struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
Chuck Lever13924022015-01-21 11:03:52 -05001099 struct rpcrdma_ia *ia = &r_xprt->rx_ia;
1100 struct rpcrdma_rep *rep;
1101 int rc;
1102
1103 rc = -ENOMEM;
Chuck Lever6b1184c2015-01-21 11:04:25 -05001104 rep = kzalloc(sizeof(*rep), GFP_KERNEL);
Chuck Lever13924022015-01-21 11:03:52 -05001105 if (rep == NULL)
1106 goto out;
Chuck Lever13924022015-01-21 11:03:52 -05001107
Chuck Lever6b1184c2015-01-21 11:04:25 -05001108 rep->rr_rdmabuf = rpcrdma_alloc_regbuf(ia, cdata->inline_rsize,
1109 GFP_KERNEL);
1110 if (IS_ERR(rep->rr_rdmabuf)) {
1111 rc = PTR_ERR(rep->rr_rdmabuf);
Chuck Lever13924022015-01-21 11:03:52 -05001112 goto out_free;
Chuck Lever6b1184c2015-01-21 11:04:25 -05001113 }
Chuck Lever13924022015-01-21 11:03:52 -05001114
1115 rep->rr_buffer = &r_xprt->rx_buf;
1116 return rep;
1117
1118out_free:
1119 kfree(rep);
1120out:
1121 return ERR_PTR(rc);
1122}
1123
Chuck Lever2e845222014-07-29 17:25:38 -04001124static int
1125rpcrdma_init_fmrs(struct rpcrdma_ia *ia, struct rpcrdma_buffer *buf)
1126{
1127 int mr_access_flags = IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ;
1128 struct ib_fmr_attr fmr_attr = {
1129 .max_pages = RPCRDMA_MAX_DATA_SEGS,
1130 .max_maps = 1,
1131 .page_shift = PAGE_SHIFT
1132 };
1133 struct rpcrdma_mw *r;
1134 int i, rc;
1135
1136 i = (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS;
1137 dprintk("RPC: %s: initalizing %d FMRs\n", __func__, i);
1138
1139 while (i--) {
1140 r = kzalloc(sizeof(*r), GFP_KERNEL);
1141 if (r == NULL)
1142 return -ENOMEM;
1143
1144 r->r.fmr = ib_alloc_fmr(ia->ri_pd, mr_access_flags, &fmr_attr);
1145 if (IS_ERR(r->r.fmr)) {
1146 rc = PTR_ERR(r->r.fmr);
1147 dprintk("RPC: %s: ib_alloc_fmr failed %i\n",
1148 __func__, rc);
1149 goto out_free;
1150 }
1151
1152 list_add(&r->mw_list, &buf->rb_mws);
1153 list_add(&r->mw_all, &buf->rb_all);
1154 }
1155 return 0;
1156
1157out_free:
1158 kfree(r);
1159 return rc;
1160}
1161
1162static int
1163rpcrdma_init_frmrs(struct rpcrdma_ia *ia, struct rpcrdma_buffer *buf)
1164{
1165 struct rpcrdma_frmr *f;
1166 struct rpcrdma_mw *r;
1167 int i, rc;
1168
1169 i = (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS;
1170 dprintk("RPC: %s: initalizing %d FRMRs\n", __func__, i);
1171
1172 while (i--) {
1173 r = kzalloc(sizeof(*r), GFP_KERNEL);
1174 if (r == NULL)
1175 return -ENOMEM;
1176 f = &r->r.frmr;
1177
1178 f->fr_mr = ib_alloc_fast_reg_mr(ia->ri_pd,
1179 ia->ri_max_frmr_depth);
1180 if (IS_ERR(f->fr_mr)) {
1181 rc = PTR_ERR(f->fr_mr);
1182 dprintk("RPC: %s: ib_alloc_fast_reg_mr "
1183 "failed %i\n", __func__, rc);
1184 goto out_free;
1185 }
1186
1187 f->fr_pgl = ib_alloc_fast_reg_page_list(ia->ri_id->device,
1188 ia->ri_max_frmr_depth);
1189 if (IS_ERR(f->fr_pgl)) {
1190 rc = PTR_ERR(f->fr_pgl);
1191 dprintk("RPC: %s: ib_alloc_fast_reg_page_list "
1192 "failed %i\n", __func__, rc);
1193
1194 ib_dereg_mr(f->fr_mr);
1195 goto out_free;
1196 }
1197
1198 list_add(&r->mw_list, &buf->rb_mws);
1199 list_add(&r->mw_all, &buf->rb_all);
1200 }
1201
1202 return 0;
1203
1204out_free:
1205 kfree(r);
1206 return rc;
1207}
1208
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001209int
Chuck Leverac920d02015-01-21 11:03:44 -05001210rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001211{
Chuck Leverac920d02015-01-21 11:03:44 -05001212 struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1213 struct rpcrdma_ia *ia = &r_xprt->rx_ia;
1214 struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001215 char *p;
Chuck Lever13924022015-01-21 11:03:52 -05001216 size_t len;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001217 int i, rc;
1218
1219 buf->rb_max_requests = cdata->max_requests;
1220 spin_lock_init(&buf->rb_lock);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001221
1222 /* Need to allocate:
1223 * 1. arrays for send and recv pointers
1224 * 2. arrays of struct rpcrdma_req to fill in pointers
1225 * 3. array of struct rpcrdma_rep for replies
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001226 * Send/recv buffers in req/rep need to be registered
1227 */
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001228 len = buf->rb_max_requests *
1229 (sizeof(struct rpcrdma_req *) + sizeof(struct rpcrdma_rep *));
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001230
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001231 p = kzalloc(len, GFP_KERNEL);
1232 if (p == NULL) {
1233 dprintk("RPC: %s: req_t/rep_t/pad kzalloc(%zd) failed\n",
1234 __func__, len);
1235 rc = -ENOMEM;
1236 goto out;
1237 }
1238 buf->rb_pool = p; /* for freeing it later */
1239
1240 buf->rb_send_bufs = (struct rpcrdma_req **) p;
1241 p = (char *) &buf->rb_send_bufs[buf->rb_max_requests];
1242 buf->rb_recv_bufs = (struct rpcrdma_rep **) p;
1243 p = (char *) &buf->rb_recv_bufs[buf->rb_max_requests];
1244
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001245 INIT_LIST_HEAD(&buf->rb_mws);
Chuck Lever3111d722014-07-29 17:24:28 -04001246 INIT_LIST_HEAD(&buf->rb_all);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001247 switch (ia->ri_memreg_strategy) {
Tom Talpey3197d3092008-10-09 15:00:20 -04001248 case RPCRDMA_FRMR:
Chuck Lever2e845222014-07-29 17:25:38 -04001249 rc = rpcrdma_init_frmrs(ia, buf);
1250 if (rc)
1251 goto out;
Tom Talpey3197d3092008-10-09 15:00:20 -04001252 break;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001253 case RPCRDMA_MTHCAFMR:
Chuck Lever2e845222014-07-29 17:25:38 -04001254 rc = rpcrdma_init_fmrs(ia, buf);
1255 if (rc)
1256 goto out;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001257 break;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001258 default:
1259 break;
1260 }
1261
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001262 for (i = 0; i < buf->rb_max_requests; i++) {
1263 struct rpcrdma_req *req;
1264 struct rpcrdma_rep *rep;
1265
Chuck Lever13924022015-01-21 11:03:52 -05001266 req = rpcrdma_create_req(r_xprt);
1267 if (IS_ERR(req)) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001268 dprintk("RPC: %s: request buffer %d alloc"
1269 " failed\n", __func__, i);
Chuck Lever13924022015-01-21 11:03:52 -05001270 rc = PTR_ERR(req);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001271 goto out;
1272 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001273 buf->rb_send_bufs[i] = req;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001274
Chuck Lever13924022015-01-21 11:03:52 -05001275 rep = rpcrdma_create_rep(r_xprt);
1276 if (IS_ERR(rep)) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001277 dprintk("RPC: %s: reply buffer %d alloc failed\n",
1278 __func__, i);
Chuck Lever13924022015-01-21 11:03:52 -05001279 rc = PTR_ERR(rep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001280 goto out;
1281 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001282 buf->rb_recv_bufs[i] = rep;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001283 }
Chuck Lever13924022015-01-21 11:03:52 -05001284
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001285 return 0;
1286out:
1287 rpcrdma_buffer_destroy(buf);
1288 return rc;
1289}
1290
Chuck Lever2e845222014-07-29 17:25:38 -04001291static void
Chuck Lever13924022015-01-21 11:03:52 -05001292rpcrdma_destroy_rep(struct rpcrdma_ia *ia, struct rpcrdma_rep *rep)
1293{
1294 if (!rep)
1295 return;
1296
Chuck Lever6b1184c2015-01-21 11:04:25 -05001297 rpcrdma_free_regbuf(ia, rep->rr_rdmabuf);
Chuck Lever13924022015-01-21 11:03:52 -05001298 kfree(rep);
1299}
1300
1301static void
1302rpcrdma_destroy_req(struct rpcrdma_ia *ia, struct rpcrdma_req *req)
1303{
1304 if (!req)
1305 return;
1306
Chuck Lever0ca77dc2015-01-21 11:04:08 -05001307 rpcrdma_free_regbuf(ia, req->rl_sendbuf);
Chuck Lever85275c82015-01-21 11:04:16 -05001308 rpcrdma_free_regbuf(ia, req->rl_rdmabuf);
Chuck Lever13924022015-01-21 11:03:52 -05001309 kfree(req);
1310}
1311
1312static void
Chuck Lever2e845222014-07-29 17:25:38 -04001313rpcrdma_destroy_fmrs(struct rpcrdma_buffer *buf)
1314{
1315 struct rpcrdma_mw *r;
1316 int rc;
1317
1318 while (!list_empty(&buf->rb_all)) {
1319 r = list_entry(buf->rb_all.next, struct rpcrdma_mw, mw_all);
1320 list_del(&r->mw_all);
1321 list_del(&r->mw_list);
1322
1323 rc = ib_dealloc_fmr(r->r.fmr);
1324 if (rc)
1325 dprintk("RPC: %s: ib_dealloc_fmr failed %i\n",
1326 __func__, rc);
1327
1328 kfree(r);
1329 }
1330}
1331
1332static void
1333rpcrdma_destroy_frmrs(struct rpcrdma_buffer *buf)
1334{
1335 struct rpcrdma_mw *r;
1336 int rc;
1337
1338 while (!list_empty(&buf->rb_all)) {
1339 r = list_entry(buf->rb_all.next, struct rpcrdma_mw, mw_all);
1340 list_del(&r->mw_all);
1341 list_del(&r->mw_list);
1342
1343 rc = ib_dereg_mr(r->r.frmr.fr_mr);
1344 if (rc)
1345 dprintk("RPC: %s: ib_dereg_mr failed %i\n",
1346 __func__, rc);
1347 ib_free_fast_reg_page_list(r->r.frmr.fr_pgl);
1348
1349 kfree(r);
1350 }
1351}
1352
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001353void
1354rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
1355{
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001356 struct rpcrdma_ia *ia = rdmab_to_ia(buf);
Chuck Lever2e845222014-07-29 17:25:38 -04001357 int i;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001358
1359 /* clean up in reverse order from create
1360 * 1. recv mr memory (mr free, then kfree)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001361 * 2. send mr memory (mr free, then kfree)
Chuck Lever2e845222014-07-29 17:25:38 -04001362 * 3. MWs
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001363 */
1364 dprintk("RPC: %s: entering\n", __func__);
1365
1366 for (i = 0; i < buf->rb_max_requests; i++) {
Chuck Lever13924022015-01-21 11:03:52 -05001367 if (buf->rb_recv_bufs)
1368 rpcrdma_destroy_rep(ia, buf->rb_recv_bufs[i]);
1369 if (buf->rb_send_bufs)
1370 rpcrdma_destroy_req(ia, buf->rb_send_bufs[i]);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001371 }
1372
Chuck Lever2e845222014-07-29 17:25:38 -04001373 switch (ia->ri_memreg_strategy) {
1374 case RPCRDMA_FRMR:
1375 rpcrdma_destroy_frmrs(buf);
1376 break;
1377 case RPCRDMA_MTHCAFMR:
1378 rpcrdma_destroy_fmrs(buf);
1379 break;
1380 default:
1381 break;
Allen Andrews4034ba02014-05-28 10:32:09 -04001382 }
1383
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001384 kfree(buf->rb_pool);
1385}
1386
Chuck Lever467c9672014-11-08 20:14:29 -05001387/* After a disconnect, unmap all FMRs.
1388 *
1389 * This is invoked only in the transport connect worker in order
1390 * to serialize with rpcrdma_register_fmr_external().
1391 */
1392static void
1393rpcrdma_reset_fmrs(struct rpcrdma_ia *ia)
1394{
1395 struct rpcrdma_xprt *r_xprt =
1396 container_of(ia, struct rpcrdma_xprt, rx_ia);
1397 struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1398 struct list_head *pos;
1399 struct rpcrdma_mw *r;
1400 LIST_HEAD(l);
1401 int rc;
1402
1403 list_for_each(pos, &buf->rb_all) {
1404 r = list_entry(pos, struct rpcrdma_mw, mw_all);
1405
1406 INIT_LIST_HEAD(&l);
1407 list_add(&r->r.fmr->list, &l);
1408 rc = ib_unmap_fmr(&l);
1409 if (rc)
1410 dprintk("RPC: %s: ib_unmap_fmr failed %i\n",
1411 __func__, rc);
1412 }
1413}
1414
Chuck Lever9f9d8022014-07-29 17:24:45 -04001415/* After a disconnect, a flushed FAST_REG_MR can leave an FRMR in
1416 * an unusable state. Find FRMRs in this state and dereg / reg
1417 * each. FRMRs that are VALID and attached to an rpcrdma_req are
1418 * also torn down.
1419 *
1420 * This gives all in-use FRMRs a fresh rkey and leaves them INVALID.
1421 *
1422 * This is invoked only in the transport connect worker in order
1423 * to serialize with rpcrdma_register_frmr_external().
1424 */
1425static void
1426rpcrdma_reset_frmrs(struct rpcrdma_ia *ia)
1427{
1428 struct rpcrdma_xprt *r_xprt =
1429 container_of(ia, struct rpcrdma_xprt, rx_ia);
1430 struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1431 struct list_head *pos;
1432 struct rpcrdma_mw *r;
1433 int rc;
1434
1435 list_for_each(pos, &buf->rb_all) {
1436 r = list_entry(pos, struct rpcrdma_mw, mw_all);
1437
1438 if (r->r.frmr.fr_state == FRMR_IS_INVALID)
1439 continue;
1440
1441 rc = ib_dereg_mr(r->r.frmr.fr_mr);
1442 if (rc)
1443 dprintk("RPC: %s: ib_dereg_mr failed %i\n",
1444 __func__, rc);
1445 ib_free_fast_reg_page_list(r->r.frmr.fr_pgl);
1446
1447 r->r.frmr.fr_mr = ib_alloc_fast_reg_mr(ia->ri_pd,
1448 ia->ri_max_frmr_depth);
1449 if (IS_ERR(r->r.frmr.fr_mr)) {
1450 rc = PTR_ERR(r->r.frmr.fr_mr);
1451 dprintk("RPC: %s: ib_alloc_fast_reg_mr"
1452 " failed %i\n", __func__, rc);
1453 continue;
1454 }
1455 r->r.frmr.fr_pgl = ib_alloc_fast_reg_page_list(
1456 ia->ri_id->device,
1457 ia->ri_max_frmr_depth);
1458 if (IS_ERR(r->r.frmr.fr_pgl)) {
1459 rc = PTR_ERR(r->r.frmr.fr_pgl);
1460 dprintk("RPC: %s: "
1461 "ib_alloc_fast_reg_page_list "
1462 "failed %i\n", __func__, rc);
1463
1464 ib_dereg_mr(r->r.frmr.fr_mr);
1465 continue;
1466 }
1467 r->r.frmr.fr_state = FRMR_IS_INVALID;
1468 }
1469}
1470
Chuck Leverc2922c02014-07-29 17:24:36 -04001471/* "*mw" can be NULL when rpcrdma_buffer_get_mrs() fails, leaving
1472 * some req segments uninitialized.
1473 */
1474static void
1475rpcrdma_buffer_put_mr(struct rpcrdma_mw **mw, struct rpcrdma_buffer *buf)
1476{
1477 if (*mw) {
1478 list_add_tail(&(*mw)->mw_list, &buf->rb_mws);
1479 *mw = NULL;
1480 }
1481}
1482
1483/* Cycle mw's back in reverse order, and "spin" them.
1484 * This delays and scrambles reuse as much as possible.
1485 */
1486static void
1487rpcrdma_buffer_put_mrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf)
1488{
1489 struct rpcrdma_mr_seg *seg = req->rl_segments;
1490 struct rpcrdma_mr_seg *seg1 = seg;
1491 int i;
1492
1493 for (i = 1, seg++; i < RPCRDMA_MAX_SEGS; seg++, i++)
Chuck Lever3eb35812015-01-21 11:02:54 -05001494 rpcrdma_buffer_put_mr(&seg->rl_mw, buf);
1495 rpcrdma_buffer_put_mr(&seg1->rl_mw, buf);
Chuck Leverc2922c02014-07-29 17:24:36 -04001496}
1497
1498static void
1499rpcrdma_buffer_put_sendbuf(struct rpcrdma_req *req, struct rpcrdma_buffer *buf)
1500{
1501 buf->rb_send_bufs[--buf->rb_send_index] = req;
1502 req->rl_niovs = 0;
1503 if (req->rl_reply) {
1504 buf->rb_recv_bufs[--buf->rb_recv_index] = req->rl_reply;
1505 req->rl_reply->rr_func = NULL;
1506 req->rl_reply = NULL;
1507 }
1508}
1509
Chuck Leverddb6beb2014-07-29 17:24:54 -04001510/* rpcrdma_unmap_one() was already done by rpcrdma_deregister_frmr_external().
1511 * Redo only the ib_post_send().
1512 */
1513static void
1514rpcrdma_retry_local_inv(struct rpcrdma_mw *r, struct rpcrdma_ia *ia)
1515{
1516 struct rpcrdma_xprt *r_xprt =
1517 container_of(ia, struct rpcrdma_xprt, rx_ia);
1518 struct ib_send_wr invalidate_wr, *bad_wr;
1519 int rc;
1520
1521 dprintk("RPC: %s: FRMR %p is stale\n", __func__, r);
1522
1523 /* When this FRMR is re-inserted into rb_mws, it is no longer stale */
Chuck Leverdab7e3b2014-07-29 17:25:20 -04001524 r->r.frmr.fr_state = FRMR_IS_INVALID;
Chuck Leverddb6beb2014-07-29 17:24:54 -04001525
1526 memset(&invalidate_wr, 0, sizeof(invalidate_wr));
1527 invalidate_wr.wr_id = (unsigned long)(void *)r;
1528 invalidate_wr.opcode = IB_WR_LOCAL_INV;
Chuck Leverddb6beb2014-07-29 17:24:54 -04001529 invalidate_wr.ex.invalidate_rkey = r->r.frmr.fr_mr->rkey;
1530 DECR_CQCOUNT(&r_xprt->rx_ep);
1531
1532 dprintk("RPC: %s: frmr %p invalidating rkey %08x\n",
1533 __func__, r, r->r.frmr.fr_mr->rkey);
1534
1535 read_lock(&ia->ri_qplock);
1536 rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr);
1537 read_unlock(&ia->ri_qplock);
1538 if (rc) {
1539 /* Force rpcrdma_buffer_get() to retry */
1540 r->r.frmr.fr_state = FRMR_IS_STALE;
1541 dprintk("RPC: %s: ib_post_send failed, %i\n",
1542 __func__, rc);
1543 }
1544}
1545
1546static void
1547rpcrdma_retry_flushed_linv(struct list_head *stale,
1548 struct rpcrdma_buffer *buf)
1549{
1550 struct rpcrdma_ia *ia = rdmab_to_ia(buf);
1551 struct list_head *pos;
1552 struct rpcrdma_mw *r;
1553 unsigned long flags;
1554
1555 list_for_each(pos, stale) {
1556 r = list_entry(pos, struct rpcrdma_mw, mw_list);
1557 rpcrdma_retry_local_inv(r, ia);
1558 }
1559
1560 spin_lock_irqsave(&buf->rb_lock, flags);
1561 list_splice_tail(stale, &buf->rb_mws);
1562 spin_unlock_irqrestore(&buf->rb_lock, flags);
1563}
1564
Chuck Leverc2922c02014-07-29 17:24:36 -04001565static struct rpcrdma_req *
Chuck Leverddb6beb2014-07-29 17:24:54 -04001566rpcrdma_buffer_get_frmrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf,
1567 struct list_head *stale)
1568{
1569 struct rpcrdma_mw *r;
1570 int i;
1571
1572 i = RPCRDMA_MAX_SEGS - 1;
1573 while (!list_empty(&buf->rb_mws)) {
1574 r = list_entry(buf->rb_mws.next,
1575 struct rpcrdma_mw, mw_list);
1576 list_del(&r->mw_list);
1577 if (r->r.frmr.fr_state == FRMR_IS_STALE) {
1578 list_add(&r->mw_list, stale);
1579 continue;
1580 }
Chuck Lever3eb35812015-01-21 11:02:54 -05001581 req->rl_segments[i].rl_mw = r;
Chuck Leverddb6beb2014-07-29 17:24:54 -04001582 if (unlikely(i-- == 0))
1583 return req; /* Success */
1584 }
1585
1586 /* Not enough entries on rb_mws for this req */
1587 rpcrdma_buffer_put_sendbuf(req, buf);
1588 rpcrdma_buffer_put_mrs(req, buf);
1589 return NULL;
1590}
1591
1592static struct rpcrdma_req *
1593rpcrdma_buffer_get_fmrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf)
Chuck Leverc2922c02014-07-29 17:24:36 -04001594{
1595 struct rpcrdma_mw *r;
1596 int i;
1597
1598 i = RPCRDMA_MAX_SEGS - 1;
1599 while (!list_empty(&buf->rb_mws)) {
1600 r = list_entry(buf->rb_mws.next,
1601 struct rpcrdma_mw, mw_list);
1602 list_del(&r->mw_list);
Chuck Lever3eb35812015-01-21 11:02:54 -05001603 req->rl_segments[i].rl_mw = r;
Chuck Leverc2922c02014-07-29 17:24:36 -04001604 if (unlikely(i-- == 0))
1605 return req; /* Success */
1606 }
1607
1608 /* Not enough entries on rb_mws for this req */
1609 rpcrdma_buffer_put_sendbuf(req, buf);
1610 rpcrdma_buffer_put_mrs(req, buf);
1611 return NULL;
1612}
1613
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001614/*
1615 * Get a set of request/reply buffers.
1616 *
1617 * Reply buffer (if needed) is attached to send buffer upon return.
1618 * Rule:
1619 * rb_send_index and rb_recv_index MUST always be pointing to the
1620 * *next* available buffer (non-NULL). They are incremented after
1621 * removing buffers, and decremented *before* returning them.
1622 */
1623struct rpcrdma_req *
1624rpcrdma_buffer_get(struct rpcrdma_buffer *buffers)
1625{
Chuck Leverc2922c02014-07-29 17:24:36 -04001626 struct rpcrdma_ia *ia = rdmab_to_ia(buffers);
Chuck Leverddb6beb2014-07-29 17:24:54 -04001627 struct list_head stale;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001628 struct rpcrdma_req *req;
1629 unsigned long flags;
1630
1631 spin_lock_irqsave(&buffers->rb_lock, flags);
1632 if (buffers->rb_send_index == buffers->rb_max_requests) {
1633 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1634 dprintk("RPC: %s: out of request buffers\n", __func__);
1635 return ((struct rpcrdma_req *)NULL);
1636 }
1637
1638 req = buffers->rb_send_bufs[buffers->rb_send_index];
1639 if (buffers->rb_send_index < buffers->rb_recv_index) {
1640 dprintk("RPC: %s: %d extra receives outstanding (ok)\n",
1641 __func__,
1642 buffers->rb_recv_index - buffers->rb_send_index);
1643 req->rl_reply = NULL;
1644 } else {
1645 req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
1646 buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
1647 }
1648 buffers->rb_send_bufs[buffers->rb_send_index++] = NULL;
Chuck Leverddb6beb2014-07-29 17:24:54 -04001649
1650 INIT_LIST_HEAD(&stale);
Chuck Leverc2922c02014-07-29 17:24:36 -04001651 switch (ia->ri_memreg_strategy) {
1652 case RPCRDMA_FRMR:
Chuck Leverddb6beb2014-07-29 17:24:54 -04001653 req = rpcrdma_buffer_get_frmrs(req, buffers, &stale);
1654 break;
Chuck Leverc2922c02014-07-29 17:24:36 -04001655 case RPCRDMA_MTHCAFMR:
Chuck Leverddb6beb2014-07-29 17:24:54 -04001656 req = rpcrdma_buffer_get_fmrs(req, buffers);
Chuck Leverc2922c02014-07-29 17:24:36 -04001657 break;
1658 default:
1659 break;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001660 }
1661 spin_unlock_irqrestore(&buffers->rb_lock, flags);
Chuck Leverddb6beb2014-07-29 17:24:54 -04001662 if (!list_empty(&stale))
1663 rpcrdma_retry_flushed_linv(&stale, buffers);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001664 return req;
1665}
1666
1667/*
1668 * Put request/reply buffers back into pool.
1669 * Pre-decrement counter/array index.
1670 */
1671void
1672rpcrdma_buffer_put(struct rpcrdma_req *req)
1673{
1674 struct rpcrdma_buffer *buffers = req->rl_buffer;
1675 struct rpcrdma_ia *ia = rdmab_to_ia(buffers);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001676 unsigned long flags;
1677
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001678 spin_lock_irqsave(&buffers->rb_lock, flags);
Chuck Leverc2922c02014-07-29 17:24:36 -04001679 rpcrdma_buffer_put_sendbuf(req, buffers);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001680 switch (ia->ri_memreg_strategy) {
Tom Talpey3197d3092008-10-09 15:00:20 -04001681 case RPCRDMA_FRMR:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001682 case RPCRDMA_MTHCAFMR:
Chuck Leverc2922c02014-07-29 17:24:36 -04001683 rpcrdma_buffer_put_mrs(req, buffers);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001684 break;
1685 default:
1686 break;
1687 }
1688 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1689}
1690
1691/*
1692 * Recover reply buffers from pool.
1693 * This happens when recovering from error conditions.
1694 * Post-increment counter/array index.
1695 */
1696void
1697rpcrdma_recv_buffer_get(struct rpcrdma_req *req)
1698{
1699 struct rpcrdma_buffer *buffers = req->rl_buffer;
1700 unsigned long flags;
1701
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001702 spin_lock_irqsave(&buffers->rb_lock, flags);
1703 if (buffers->rb_recv_index < buffers->rb_max_requests) {
1704 req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
1705 buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
1706 }
1707 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1708}
1709
1710/*
1711 * Put reply buffers back into pool when not attached to
Chuck Leverb45ccfd2014-05-28 10:32:34 -04001712 * request. This happens in error conditions.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001713 */
1714void
1715rpcrdma_recv_buffer_put(struct rpcrdma_rep *rep)
1716{
1717 struct rpcrdma_buffer *buffers = rep->rr_buffer;
1718 unsigned long flags;
1719
1720 rep->rr_func = NULL;
1721 spin_lock_irqsave(&buffers->rb_lock, flags);
1722 buffers->rb_recv_bufs[--buffers->rb_recv_index] = rep;
1723 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1724}
1725
1726/*
1727 * Wrappers for internal-use kmalloc memory registration, used by buffer code.
1728 */
1729
Chuck Leverdf515ca2015-01-21 11:04:41 -05001730static int
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001731rpcrdma_register_internal(struct rpcrdma_ia *ia, void *va, int len,
1732 struct ib_mr **mrp, struct ib_sge *iov)
1733{
1734 struct ib_phys_buf ipb;
1735 struct ib_mr *mr;
1736 int rc;
1737
1738 /*
1739 * All memory passed here was kmalloc'ed, therefore phys-contiguous.
1740 */
1741 iov->addr = ib_dma_map_single(ia->ri_id->device,
1742 va, len, DMA_BIDIRECTIONAL);
Yan Burmanbf858ab2014-06-19 16:06:30 +03001743 if (ib_dma_mapping_error(ia->ri_id->device, iov->addr))
1744 return -ENOMEM;
1745
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001746 iov->length = len;
1747
Tom Talpeybd7ed1d2008-10-09 15:00:09 -04001748 if (ia->ri_have_dma_lkey) {
1749 *mrp = NULL;
1750 iov->lkey = ia->ri_dma_lkey;
1751 return 0;
1752 } else if (ia->ri_bind_mem != NULL) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001753 *mrp = NULL;
1754 iov->lkey = ia->ri_bind_mem->lkey;
1755 return 0;
1756 }
1757
1758 ipb.addr = iov->addr;
1759 ipb.size = iov->length;
1760 mr = ib_reg_phys_mr(ia->ri_pd, &ipb, 1,
1761 IB_ACCESS_LOCAL_WRITE, &iov->addr);
1762
1763 dprintk("RPC: %s: phys convert: 0x%llx "
1764 "registered 0x%llx length %d\n",
Andrew Mortona56daeb2007-10-16 01:29:57 -07001765 __func__, (unsigned long long)ipb.addr,
1766 (unsigned long long)iov->addr, len);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001767
1768 if (IS_ERR(mr)) {
1769 *mrp = NULL;
1770 rc = PTR_ERR(mr);
1771 dprintk("RPC: %s: failed with %i\n", __func__, rc);
1772 } else {
1773 *mrp = mr;
1774 iov->lkey = mr->lkey;
1775 rc = 0;
1776 }
1777
1778 return rc;
1779}
1780
Chuck Leverdf515ca2015-01-21 11:04:41 -05001781static int
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001782rpcrdma_deregister_internal(struct rpcrdma_ia *ia,
1783 struct ib_mr *mr, struct ib_sge *iov)
1784{
1785 int rc;
1786
1787 ib_dma_unmap_single(ia->ri_id->device,
1788 iov->addr, iov->length, DMA_BIDIRECTIONAL);
1789
1790 if (NULL == mr)
1791 return 0;
1792
1793 rc = ib_dereg_mr(mr);
1794 if (rc)
1795 dprintk("RPC: %s: ib_dereg_mr failed %i\n", __func__, rc);
1796 return rc;
1797}
1798
Chuck Lever9128c3e2015-01-21 11:04:00 -05001799/**
1800 * rpcrdma_alloc_regbuf - kmalloc and register memory for SEND/RECV buffers
1801 * @ia: controlling rpcrdma_ia
1802 * @size: size of buffer to be allocated, in bytes
1803 * @flags: GFP flags
1804 *
1805 * Returns pointer to private header of an area of internally
1806 * registered memory, or an ERR_PTR. The registered buffer follows
1807 * the end of the private header.
1808 *
1809 * xprtrdma uses a regbuf for posting an outgoing RDMA SEND, or for
1810 * receiving the payload of RDMA RECV operations. regbufs are not
1811 * used for RDMA READ/WRITE operations, thus are registered only for
1812 * LOCAL access.
1813 */
1814struct rpcrdma_regbuf *
1815rpcrdma_alloc_regbuf(struct rpcrdma_ia *ia, size_t size, gfp_t flags)
1816{
1817 struct rpcrdma_regbuf *rb;
1818 int rc;
1819
1820 rc = -ENOMEM;
1821 rb = kmalloc(sizeof(*rb) + size, flags);
1822 if (rb == NULL)
1823 goto out;
1824
1825 rb->rg_size = size;
1826 rb->rg_owner = NULL;
1827 rc = rpcrdma_register_internal(ia, rb->rg_base, size,
1828 &rb->rg_mr, &rb->rg_iov);
1829 if (rc)
1830 goto out_free;
1831
1832 return rb;
1833
1834out_free:
1835 kfree(rb);
1836out:
1837 return ERR_PTR(rc);
1838}
1839
1840/**
1841 * rpcrdma_free_regbuf - deregister and free registered buffer
1842 * @ia: controlling rpcrdma_ia
1843 * @rb: regbuf to be deregistered and freed
1844 */
1845void
1846rpcrdma_free_regbuf(struct rpcrdma_ia *ia, struct rpcrdma_regbuf *rb)
1847{
1848 if (rb) {
1849 rpcrdma_deregister_internal(ia, rb->rg_mr, &rb->rg_iov);
1850 kfree(rb);
1851 }
1852}
1853
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001854/*
1855 * Wrappers for chunk registration, shared by read/write chunk code.
1856 */
1857
1858static void
1859rpcrdma_map_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg, int writing)
1860{
1861 seg->mr_dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
1862 seg->mr_dmalen = seg->mr_len;
1863 if (seg->mr_page)
1864 seg->mr_dma = ib_dma_map_page(ia->ri_id->device,
1865 seg->mr_page, offset_in_page(seg->mr_offset),
1866 seg->mr_dmalen, seg->mr_dir);
1867 else
1868 seg->mr_dma = ib_dma_map_single(ia->ri_id->device,
1869 seg->mr_offset,
1870 seg->mr_dmalen, seg->mr_dir);
Tom Tucker5c635e02011-02-09 19:45:34 +00001871 if (ib_dma_mapping_error(ia->ri_id->device, seg->mr_dma)) {
1872 dprintk("RPC: %s: mr_dma %llx mr_offset %p mr_dma_len %zu\n",
1873 __func__,
Randy Dunlap986d4ab2011-03-15 17:11:59 -07001874 (unsigned long long)seg->mr_dma,
1875 seg->mr_offset, seg->mr_dmalen);
Tom Tucker5c635e02011-02-09 19:45:34 +00001876 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001877}
1878
1879static void
1880rpcrdma_unmap_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg)
1881{
1882 if (seg->mr_page)
1883 ib_dma_unmap_page(ia->ri_id->device,
1884 seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
1885 else
1886 ib_dma_unmap_single(ia->ri_id->device,
1887 seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
1888}
1889
Tom Talpey8d4ba032008-10-09 14:59:49 -04001890static int
Tom Talpey3197d3092008-10-09 15:00:20 -04001891rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
1892 int *nsegs, int writing, struct rpcrdma_ia *ia,
1893 struct rpcrdma_xprt *r_xprt)
1894{
1895 struct rpcrdma_mr_seg *seg1 = seg;
Chuck Lever3eb35812015-01-21 11:02:54 -05001896 struct rpcrdma_mw *mw = seg1->rl_mw;
Chuck Lever0dbb4102014-07-29 17:24:09 -04001897 struct rpcrdma_frmr *frmr = &mw->r.frmr;
1898 struct ib_mr *mr = frmr->fr_mr;
Chuck Leverf590e872014-07-29 17:25:29 -04001899 struct ib_send_wr fastreg_wr, *bad_wr;
Tom Talpey3197d3092008-10-09 15:00:20 -04001900 u8 key;
1901 int len, pageoff;
1902 int i, rc;
Tom Tucker9b781452012-02-20 13:07:57 -06001903 int seg_len;
1904 u64 pa;
1905 int page_no;
Tom Talpey3197d3092008-10-09 15:00:20 -04001906
1907 pageoff = offset_in_page(seg1->mr_offset);
1908 seg1->mr_offset -= pageoff; /* start of page */
1909 seg1->mr_len += pageoff;
1910 len = -pageoff;
Steve Wise0fc6c4e2014-05-28 10:32:00 -04001911 if (*nsegs > ia->ri_max_frmr_depth)
1912 *nsegs = ia->ri_max_frmr_depth;
Tom Tucker9b781452012-02-20 13:07:57 -06001913 for (page_no = i = 0; i < *nsegs;) {
Tom Talpey3197d3092008-10-09 15:00:20 -04001914 rpcrdma_map_one(ia, seg, writing);
Tom Tucker9b781452012-02-20 13:07:57 -06001915 pa = seg->mr_dma;
1916 for (seg_len = seg->mr_len; seg_len > 0; seg_len -= PAGE_SIZE) {
Chuck Lever0dbb4102014-07-29 17:24:09 -04001917 frmr->fr_pgl->page_list[page_no++] = pa;
Tom Tucker9b781452012-02-20 13:07:57 -06001918 pa += PAGE_SIZE;
1919 }
Tom Talpey3197d3092008-10-09 15:00:20 -04001920 len += seg->mr_len;
1921 ++seg;
1922 ++i;
1923 /* Check for holes */
1924 if ((i < *nsegs && offset_in_page(seg->mr_offset)) ||
1925 offset_in_page((seg-1)->mr_offset + (seg-1)->mr_len))
1926 break;
1927 }
Chuck Lever80527242015-03-30 14:34:02 -04001928 dprintk("RPC: %s: Using frmr %p to map %d segments (%d bytes)\n",
1929 __func__, mw, i, len);
Tom Talpey3197d3092008-10-09 15:00:20 -04001930
Chuck Lever05055722014-07-29 17:25:12 -04001931 frmr->fr_state = FRMR_IS_VALID;
1932
Chuck Leverf590e872014-07-29 17:25:29 -04001933 memset(&fastreg_wr, 0, sizeof(fastreg_wr));
1934 fastreg_wr.wr_id = (unsigned long)(void *)mw;
1935 fastreg_wr.opcode = IB_WR_FAST_REG_MR;
Chuck Lever80527242015-03-30 14:34:02 -04001936 fastreg_wr.wr.fast_reg.iova_start = seg1->mr_dma + pageoff;
Chuck Leverf590e872014-07-29 17:25:29 -04001937 fastreg_wr.wr.fast_reg.page_list = frmr->fr_pgl;
1938 fastreg_wr.wr.fast_reg.page_list_len = page_no;
1939 fastreg_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
Chuck Lever80527242015-03-30 14:34:02 -04001940 fastreg_wr.wr.fast_reg.length = len;
Chuck Leverc977dea2014-05-28 10:35:06 -04001941
1942 /* Bump the key */
Chuck Lever0dbb4102014-07-29 17:24:09 -04001943 key = (u8)(mr->rkey & 0x000000FF);
1944 ib_update_fast_reg_key(mr, ++key);
Chuck Leverc977dea2014-05-28 10:35:06 -04001945
Chuck Leverf590e872014-07-29 17:25:29 -04001946 fastreg_wr.wr.fast_reg.access_flags = (writing ?
Vu Pham68743082009-05-26 14:51:00 -04001947 IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
1948 IB_ACCESS_REMOTE_READ);
Chuck Leverf590e872014-07-29 17:25:29 -04001949 fastreg_wr.wr.fast_reg.rkey = mr->rkey;
Tom Talpey3197d3092008-10-09 15:00:20 -04001950 DECR_CQCOUNT(&r_xprt->rx_ep);
1951
Chuck Leverf590e872014-07-29 17:25:29 -04001952 rc = ib_post_send(ia->ri_id->qp, &fastreg_wr, &bad_wr);
Tom Talpey3197d3092008-10-09 15:00:20 -04001953 if (rc) {
1954 dprintk("RPC: %s: failed ib_post_send for register,"
1955 " status %i\n", __func__, rc);
Chuck Leverc93e9862014-07-29 17:24:19 -04001956 ib_update_fast_reg_key(mr, --key);
Chuck Lever5fc83f42014-07-29 17:23:17 -04001957 goto out_err;
Tom Talpey3197d3092008-10-09 15:00:20 -04001958 } else {
Chuck Lever0dbb4102014-07-29 17:24:09 -04001959 seg1->mr_rkey = mr->rkey;
Tom Talpey3197d3092008-10-09 15:00:20 -04001960 seg1->mr_base = seg1->mr_dma + pageoff;
1961 seg1->mr_nsegs = i;
1962 seg1->mr_len = len;
1963 }
1964 *nsegs = i;
Chuck Lever5fc83f42014-07-29 17:23:17 -04001965 return 0;
1966out_err:
Chuck Lever05055722014-07-29 17:25:12 -04001967 frmr->fr_state = FRMR_IS_INVALID;
Chuck Lever5fc83f42014-07-29 17:23:17 -04001968 while (i--)
1969 rpcrdma_unmap_one(ia, --seg);
Tom Talpey3197d3092008-10-09 15:00:20 -04001970 return rc;
1971}
1972
1973static int
1974rpcrdma_deregister_frmr_external(struct rpcrdma_mr_seg *seg,
1975 struct rpcrdma_ia *ia, struct rpcrdma_xprt *r_xprt)
1976{
1977 struct rpcrdma_mr_seg *seg1 = seg;
1978 struct ib_send_wr invalidate_wr, *bad_wr;
1979 int rc;
1980
Chuck Lever3eb35812015-01-21 11:02:54 -05001981 seg1->rl_mw->r.frmr.fr_state = FRMR_IS_INVALID;
Chuck Leverdab7e3b2014-07-29 17:25:20 -04001982
Tom Talpey3197d3092008-10-09 15:00:20 -04001983 memset(&invalidate_wr, 0, sizeof invalidate_wr);
Chuck Lever3eb35812015-01-21 11:02:54 -05001984 invalidate_wr.wr_id = (unsigned long)(void *)seg1->rl_mw;
Tom Talpey3197d3092008-10-09 15:00:20 -04001985 invalidate_wr.opcode = IB_WR_LOCAL_INV;
Chuck Lever3eb35812015-01-21 11:02:54 -05001986 invalidate_wr.ex.invalidate_rkey = seg1->rl_mw->r.frmr.fr_mr->rkey;
Tom Talpey3197d3092008-10-09 15:00:20 -04001987 DECR_CQCOUNT(&r_xprt->rx_ep);
1988
Chuck Lever73806c82014-07-29 17:23:25 -04001989 read_lock(&ia->ri_qplock);
1990 while (seg1->mr_nsegs--)
1991 rpcrdma_unmap_one(ia, seg++);
Tom Talpey3197d3092008-10-09 15:00:20 -04001992 rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr);
Chuck Lever73806c82014-07-29 17:23:25 -04001993 read_unlock(&ia->ri_qplock);
Chuck Leverdab7e3b2014-07-29 17:25:20 -04001994 if (rc) {
1995 /* Force rpcrdma_buffer_get() to retry */
Chuck Lever3eb35812015-01-21 11:02:54 -05001996 seg1->rl_mw->r.frmr.fr_state = FRMR_IS_STALE;
Tom Talpey3197d3092008-10-09 15:00:20 -04001997 dprintk("RPC: %s: failed ib_post_send for invalidate,"
1998 " status %i\n", __func__, rc);
Chuck Leverdab7e3b2014-07-29 17:25:20 -04001999 }
Tom Talpey3197d3092008-10-09 15:00:20 -04002000 return rc;
2001}
2002
2003static int
Tom Talpey8d4ba032008-10-09 14:59:49 -04002004rpcrdma_register_fmr_external(struct rpcrdma_mr_seg *seg,
2005 int *nsegs, int writing, struct rpcrdma_ia *ia)
2006{
2007 struct rpcrdma_mr_seg *seg1 = seg;
2008 u64 physaddrs[RPCRDMA_MAX_DATA_SEGS];
2009 int len, pageoff, i, rc;
2010
2011 pageoff = offset_in_page(seg1->mr_offset);
2012 seg1->mr_offset -= pageoff; /* start of page */
2013 seg1->mr_len += pageoff;
2014 len = -pageoff;
2015 if (*nsegs > RPCRDMA_MAX_DATA_SEGS)
2016 *nsegs = RPCRDMA_MAX_DATA_SEGS;
2017 for (i = 0; i < *nsegs;) {
2018 rpcrdma_map_one(ia, seg, writing);
2019 physaddrs[i] = seg->mr_dma;
2020 len += seg->mr_len;
2021 ++seg;
2022 ++i;
2023 /* Check for holes */
2024 if ((i < *nsegs && offset_in_page(seg->mr_offset)) ||
2025 offset_in_page((seg-1)->mr_offset + (seg-1)->mr_len))
2026 break;
2027 }
Chuck Lever3eb35812015-01-21 11:02:54 -05002028 rc = ib_map_phys_fmr(seg1->rl_mw->r.fmr, physaddrs, i, seg1->mr_dma);
Tom Talpey8d4ba032008-10-09 14:59:49 -04002029 if (rc) {
2030 dprintk("RPC: %s: failed ib_map_phys_fmr "
2031 "%u@0x%llx+%i (%d)... status %i\n", __func__,
2032 len, (unsigned long long)seg1->mr_dma,
2033 pageoff, i, rc);
2034 while (i--)
2035 rpcrdma_unmap_one(ia, --seg);
2036 } else {
Chuck Lever3eb35812015-01-21 11:02:54 -05002037 seg1->mr_rkey = seg1->rl_mw->r.fmr->rkey;
Tom Talpey8d4ba032008-10-09 14:59:49 -04002038 seg1->mr_base = seg1->mr_dma + pageoff;
2039 seg1->mr_nsegs = i;
2040 seg1->mr_len = len;
2041 }
2042 *nsegs = i;
2043 return rc;
2044}
2045
2046static int
2047rpcrdma_deregister_fmr_external(struct rpcrdma_mr_seg *seg,
2048 struct rpcrdma_ia *ia)
2049{
2050 struct rpcrdma_mr_seg *seg1 = seg;
2051 LIST_HEAD(l);
2052 int rc;
2053
Chuck Lever3eb35812015-01-21 11:02:54 -05002054 list_add(&seg1->rl_mw->r.fmr->list, &l);
Tom Talpey8d4ba032008-10-09 14:59:49 -04002055 rc = ib_unmap_fmr(&l);
Chuck Lever73806c82014-07-29 17:23:25 -04002056 read_lock(&ia->ri_qplock);
Tom Talpey8d4ba032008-10-09 14:59:49 -04002057 while (seg1->mr_nsegs--)
2058 rpcrdma_unmap_one(ia, seg++);
Chuck Lever73806c82014-07-29 17:23:25 -04002059 read_unlock(&ia->ri_qplock);
Tom Talpey8d4ba032008-10-09 14:59:49 -04002060 if (rc)
2061 dprintk("RPC: %s: failed ib_unmap_fmr,"
2062 " status %i\n", __func__, rc);
2063 return rc;
2064}
2065
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002066int
2067rpcrdma_register_external(struct rpcrdma_mr_seg *seg,
2068 int nsegs, int writing, struct rpcrdma_xprt *r_xprt)
2069{
2070 struct rpcrdma_ia *ia = &r_xprt->rx_ia;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002071 int rc = 0;
2072
2073 switch (ia->ri_memreg_strategy) {
2074
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002075 case RPCRDMA_ALLPHYSICAL:
2076 rpcrdma_map_one(ia, seg, writing);
2077 seg->mr_rkey = ia->ri_bind_mem->rkey;
2078 seg->mr_base = seg->mr_dma;
2079 seg->mr_nsegs = 1;
2080 nsegs = 1;
2081 break;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002082
Tom Talpey3197d3092008-10-09 15:00:20 -04002083 /* Registration using frmr registration */
2084 case RPCRDMA_FRMR:
2085 rc = rpcrdma_register_frmr_external(seg, &nsegs, writing, ia, r_xprt);
2086 break;
2087
Tom Talpey8d4ba032008-10-09 14:59:49 -04002088 /* Registration using fmr memory registration */
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002089 case RPCRDMA_MTHCAFMR:
Tom Talpey8d4ba032008-10-09 14:59:49 -04002090 rc = rpcrdma_register_fmr_external(seg, &nsegs, writing, ia);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002091 break;
2092
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002093 default:
Chuck Lever92b98362014-11-08 20:14:12 -05002094 return -EIO;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002095 }
2096 if (rc)
Chuck Lever92b98362014-11-08 20:14:12 -05002097 return rc;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002098
2099 return nsegs;
2100}
2101
2102int
2103rpcrdma_deregister_external(struct rpcrdma_mr_seg *seg,
Chuck Lever13c9ff82014-05-28 10:33:08 -04002104 struct rpcrdma_xprt *r_xprt)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002105{
2106 struct rpcrdma_ia *ia = &r_xprt->rx_ia;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002107 int nsegs = seg->mr_nsegs, rc;
2108
2109 switch (ia->ri_memreg_strategy) {
2110
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002111 case RPCRDMA_ALLPHYSICAL:
Chuck Lever73806c82014-07-29 17:23:25 -04002112 read_lock(&ia->ri_qplock);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002113 rpcrdma_unmap_one(ia, seg);
Chuck Lever73806c82014-07-29 17:23:25 -04002114 read_unlock(&ia->ri_qplock);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002115 break;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002116
Tom Talpey3197d3092008-10-09 15:00:20 -04002117 case RPCRDMA_FRMR:
2118 rc = rpcrdma_deregister_frmr_external(seg, ia, r_xprt);
2119 break;
2120
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002121 case RPCRDMA_MTHCAFMR:
Tom Talpey8d4ba032008-10-09 14:59:49 -04002122 rc = rpcrdma_deregister_fmr_external(seg, ia);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002123 break;
2124
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002125 default:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002126 break;
2127 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002128 return nsegs;
2129}
2130
2131/*
2132 * Prepost any receive buffer, then post send.
2133 *
2134 * Receive buffer is donated to hardware, reclaimed upon recv completion.
2135 */
2136int
2137rpcrdma_ep_post(struct rpcrdma_ia *ia,
2138 struct rpcrdma_ep *ep,
2139 struct rpcrdma_req *req)
2140{
2141 struct ib_send_wr send_wr, *send_wr_fail;
2142 struct rpcrdma_rep *rep = req->rl_reply;
2143 int rc;
2144
2145 if (rep) {
2146 rc = rpcrdma_ep_post_recv(ia, ep, rep);
2147 if (rc)
2148 goto out;
2149 req->rl_reply = NULL;
2150 }
2151
2152 send_wr.next = NULL;
2153 send_wr.wr_id = 0ULL; /* no send cookie */
2154 send_wr.sg_list = req->rl_send_iov;
2155 send_wr.num_sge = req->rl_niovs;
2156 send_wr.opcode = IB_WR_SEND;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002157 if (send_wr.num_sge == 4) /* no need to sync any pad (constant) */
2158 ib_dma_sync_single_for_device(ia->ri_id->device,
2159 req->rl_send_iov[3].addr, req->rl_send_iov[3].length,
2160 DMA_TO_DEVICE);
2161 ib_dma_sync_single_for_device(ia->ri_id->device,
2162 req->rl_send_iov[1].addr, req->rl_send_iov[1].length,
2163 DMA_TO_DEVICE);
2164 ib_dma_sync_single_for_device(ia->ri_id->device,
2165 req->rl_send_iov[0].addr, req->rl_send_iov[0].length,
2166 DMA_TO_DEVICE);
2167
2168 if (DECR_CQCOUNT(ep) > 0)
2169 send_wr.send_flags = 0;
2170 else { /* Provider must take a send completion every now and then */
2171 INIT_CQCOUNT(ep);
2172 send_wr.send_flags = IB_SEND_SIGNALED;
2173 }
2174
2175 rc = ib_post_send(ia->ri_id->qp, &send_wr, &send_wr_fail);
2176 if (rc)
2177 dprintk("RPC: %s: ib_post_send returned %i\n", __func__,
2178 rc);
2179out:
2180 return rc;
2181}
2182
2183/*
2184 * (Re)post a receive buffer.
2185 */
2186int
2187rpcrdma_ep_post_recv(struct rpcrdma_ia *ia,
2188 struct rpcrdma_ep *ep,
2189 struct rpcrdma_rep *rep)
2190{
2191 struct ib_recv_wr recv_wr, *recv_wr_fail;
2192 int rc;
2193
2194 recv_wr.next = NULL;
2195 recv_wr.wr_id = (u64) (unsigned long) rep;
Chuck Lever6b1184c2015-01-21 11:04:25 -05002196 recv_wr.sg_list = &rep->rr_rdmabuf->rg_iov;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002197 recv_wr.num_sge = 1;
2198
2199 ib_dma_sync_single_for_cpu(ia->ri_id->device,
Chuck Lever6b1184c2015-01-21 11:04:25 -05002200 rdmab_addr(rep->rr_rdmabuf),
2201 rdmab_length(rep->rr_rdmabuf),
2202 DMA_BIDIRECTIONAL);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002203
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04002204 rc = ib_post_recv(ia->ri_id->qp, &recv_wr, &recv_wr_fail);
2205
2206 if (rc)
2207 dprintk("RPC: %s: ib_post_recv returned %i\n", __func__,
2208 rc);
2209 return rc;
2210}
Chuck Lever43e95982014-07-29 17:23:34 -04002211
2212/* Physical mapping means one Read/Write list entry per-page.
2213 * All list entries must fit within an inline buffer
2214 *
2215 * NB: The server must return a Write list for NFS READ,
2216 * which has the same constraint. Factor in the inline
2217 * rsize as well.
2218 */
2219static size_t
2220rpcrdma_physical_max_payload(struct rpcrdma_xprt *r_xprt)
2221{
2222 struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
2223 unsigned int inline_size, pages;
2224
2225 inline_size = min_t(unsigned int,
2226 cdata->inline_wsize, cdata->inline_rsize);
2227 inline_size -= RPCRDMA_HDRLEN_MIN;
2228 pages = inline_size / sizeof(struct rpcrdma_segment);
2229 return pages << PAGE_SHIFT;
2230}
2231
2232static size_t
2233rpcrdma_mr_max_payload(struct rpcrdma_xprt *r_xprt)
2234{
2235 return RPCRDMA_MAX_DATA_SEGS << PAGE_SHIFT;
2236}
2237
2238size_t
2239rpcrdma_max_payload(struct rpcrdma_xprt *r_xprt)
2240{
2241 size_t result;
2242
2243 switch (r_xprt->rx_ia.ri_memreg_strategy) {
2244 case RPCRDMA_ALLPHYSICAL:
2245 result = rpcrdma_physical_max_payload(r_xprt);
2246 break;
2247 default:
2248 result = rpcrdma_mr_max_payload(r_xprt);
2249 }
2250 return result;
2251}