blob: e89a57d4e4f2b4f9e3eb608105d5fcd713c28d21 [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
Chuck Levera0ce85f2015-03-30 14:34:21 -0400495 pr_info("rpcrdma: connection to %pIS:%u on %s, memreg '%s', %d credits, %d responders%s\n",
Chuck Lever0dd39ca2015-03-30 14:33:43 -0400496 sap, rpc_get_port(sap),
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400497 ia->ri_id->device->name,
Chuck Levera0ce85f2015-03-30 14:34:21 -0400498 ia->ri_ops->ro_displayname,
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400499 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:
Chuck Levera0ce85f2015-03-30 14:34:21 -0400653 ia->ri_ops = &rpcrdma_frwr_memreg_ops;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400654 break;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400655 case RPCRDMA_ALLPHYSICAL:
Chuck Levera0ce85f2015-03-30 14:34:21 -0400656 ia->ri_ops = &rpcrdma_physical_memreg_ops;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400657 mem_priv = IB_ACCESS_LOCAL_WRITE |
658 IB_ACCESS_REMOTE_WRITE |
659 IB_ACCESS_REMOTE_READ;
660 goto register_setup;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400661 case RPCRDMA_MTHCAFMR:
Chuck Levera0ce85f2015-03-30 14:34:21 -0400662 ia->ri_ops = &rpcrdma_fmr_memreg_ops;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400663 if (ia->ri_have_dma_lkey)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400664 break;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400665 mem_priv = IB_ACCESS_LOCAL_WRITE;
666 register_setup:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400667 ia->ri_bind_mem = ib_get_dma_mr(ia->ri_pd, mem_priv);
668 if (IS_ERR(ia->ri_bind_mem)) {
669 printk(KERN_ALERT "%s: ib_get_dma_mr for "
Chuck Lever0ac531c2014-05-28 10:32:43 -0400670 "phys register failed with %lX\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400671 __func__, PTR_ERR(ia->ri_bind_mem));
Chuck Lever0ac531c2014-05-28 10:32:43 -0400672 rc = -ENOMEM;
Chuck Lever5ae711a2015-01-21 11:03:19 -0500673 goto out3;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400674 }
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400675 break;
676 default:
Chuck Levercdd9ade2014-05-28 10:33:00 -0400677 printk(KERN_ERR "RPC: Unsupported memory "
678 "registration mode: %d\n", memreg);
679 rc = -ENOMEM;
Chuck Lever5ae711a2015-01-21 11:03:19 -0500680 goto out3;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400681 }
Chuck Levera0ce85f2015-03-30 14:34:21 -0400682 dprintk("RPC: %s: memory registration strategy is '%s'\n",
683 __func__, ia->ri_ops->ro_displayname);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400684
685 /* Else will do memory reg/dereg for each chunk */
686 ia->ri_memreg_strategy = memreg;
687
Chuck Lever73806c82014-07-29 17:23:25 -0400688 rwlock_init(&ia->ri_qplock);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400689 return 0;
Chuck Lever5ae711a2015-01-21 11:03:19 -0500690
691out3:
692 ib_dealloc_pd(ia->ri_pd);
693 ia->ri_pd = NULL;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400694out2:
695 rdma_destroy_id(ia->ri_id);
Tom Talpeyfee08ca2008-10-09 15:01:00 -0400696 ia->ri_id = NULL;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400697out1:
698 return rc;
699}
700
701/*
702 * Clean up/close an IA.
703 * o if event handles and PD have been initialized, free them.
704 * o close the IA
705 */
706void
707rpcrdma_ia_close(struct rpcrdma_ia *ia)
708{
709 int rc;
710
711 dprintk("RPC: %s: entering\n", __func__);
712 if (ia->ri_bind_mem != NULL) {
713 rc = ib_dereg_mr(ia->ri_bind_mem);
714 dprintk("RPC: %s: ib_dereg_mr returned %i\n",
715 __func__, rc);
716 }
Tom Talpeyfee08ca2008-10-09 15:01:00 -0400717 if (ia->ri_id != NULL && !IS_ERR(ia->ri_id)) {
718 if (ia->ri_id->qp)
719 rdma_destroy_qp(ia->ri_id);
720 rdma_destroy_id(ia->ri_id);
721 ia->ri_id = NULL;
722 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400723 if (ia->ri_pd != NULL && !IS_ERR(ia->ri_pd)) {
724 rc = ib_dealloc_pd(ia->ri_pd);
725 dprintk("RPC: %s: ib_dealloc_pd returned %i\n",
726 __func__, rc);
727 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400728}
729
730/*
731 * Create unconnected endpoint.
732 */
733int
734rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
735 struct rpcrdma_create_data_internal *cdata)
736{
Chuck Lever7bc79722015-01-21 11:03:27 -0500737 struct ib_device_attr *devattr = &ia->ri_devattr;
Chuck Leverfc664482014-05-28 10:33:25 -0400738 struct ib_cq *sendcq, *recvcq;
Chuck Lever5d40a8a2007-10-26 13:30:54 -0400739 int rc, err;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400740
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400741 /* check provider's send/recv wr limits */
Chuck Lever7bc79722015-01-21 11:03:27 -0500742 if (cdata->max_requests > devattr->max_qp_wr)
743 cdata->max_requests = devattr->max_qp_wr;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400744
745 ep->rep_attr.event_handler = rpcrdma_qp_async_error_upcall;
746 ep->rep_attr.qp_context = ep;
747 /* send_cq and recv_cq initialized below */
748 ep->rep_attr.srq = NULL;
749 ep->rep_attr.cap.max_send_wr = cdata->max_requests;
750 switch (ia->ri_memreg_strategy) {
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400751 case RPCRDMA_FRMR: {
752 int depth = 7;
753
Tom Tucker15cdc6442010-08-11 12:47:24 -0400754 /* Add room for frmr register and invalidate WRs.
755 * 1. FRMR reg WR for head
756 * 2. FRMR invalidate WR for head
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400757 * 3. N FRMR reg WRs for pagelist
758 * 4. N FRMR invalidate WRs for pagelist
Tom Tucker15cdc6442010-08-11 12:47:24 -0400759 * 5. FRMR reg WR for tail
760 * 6. FRMR invalidate WR for tail
761 * 7. The RDMA_SEND WR
762 */
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400763
764 /* Calculate N if the device max FRMR depth is smaller than
765 * RPCRDMA_MAX_DATA_SEGS.
766 */
767 if (ia->ri_max_frmr_depth < RPCRDMA_MAX_DATA_SEGS) {
768 int delta = RPCRDMA_MAX_DATA_SEGS -
769 ia->ri_max_frmr_depth;
770
771 do {
772 depth += 2; /* FRMR reg + invalidate */
773 delta -= ia->ri_max_frmr_depth;
774 } while (delta > 0);
775
776 }
777 ep->rep_attr.cap.max_send_wr *= depth;
Chuck Lever7bc79722015-01-21 11:03:27 -0500778 if (ep->rep_attr.cap.max_send_wr > devattr->max_qp_wr) {
779 cdata->max_requests = devattr->max_qp_wr / depth;
Tom Tucker15cdc6442010-08-11 12:47:24 -0400780 if (!cdata->max_requests)
781 return -EINVAL;
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400782 ep->rep_attr.cap.max_send_wr = cdata->max_requests *
783 depth;
Tom Tucker15cdc6442010-08-11 12:47:24 -0400784 }
Tom Talpey3197d3092008-10-09 15:00:20 -0400785 break;
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400786 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400787 default:
788 break;
789 }
790 ep->rep_attr.cap.max_recv_wr = cdata->max_requests;
791 ep->rep_attr.cap.max_send_sge = (cdata->padding ? 4 : 2);
792 ep->rep_attr.cap.max_recv_sge = 1;
793 ep->rep_attr.cap.max_inline_data = 0;
794 ep->rep_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
795 ep->rep_attr.qp_type = IB_QPT_RC;
796 ep->rep_attr.port_num = ~0;
797
Chuck Leverc05fbb52015-01-21 11:04:33 -0500798 if (cdata->padding) {
799 ep->rep_padbuf = rpcrdma_alloc_regbuf(ia, cdata->padding,
800 GFP_KERNEL);
801 if (IS_ERR(ep->rep_padbuf))
802 return PTR_ERR(ep->rep_padbuf);
803 } else
804 ep->rep_padbuf = NULL;
805
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400806 dprintk("RPC: %s: requested max: dtos: send %d recv %d; "
807 "iovs: send %d recv %d\n",
808 __func__,
809 ep->rep_attr.cap.max_send_wr,
810 ep->rep_attr.cap.max_recv_wr,
811 ep->rep_attr.cap.max_send_sge,
812 ep->rep_attr.cap.max_recv_sge);
813
814 /* set trigger for requesting send completion */
Chuck Leverfc664482014-05-28 10:33:25 -0400815 ep->rep_cqinit = ep->rep_attr.cap.max_send_wr/2 - 1;
Chuck Levere7104a22014-11-08 20:14:20 -0500816 if (ep->rep_cqinit > RPCRDMA_MAX_UNSIGNALED_SENDS)
817 ep->rep_cqinit = RPCRDMA_MAX_UNSIGNALED_SENDS;
818 else if (ep->rep_cqinit <= 2)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400819 ep->rep_cqinit = 0;
820 INIT_CQCOUNT(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400821 init_waitqueue_head(&ep->rep_connect_wait);
Chuck Lever254f91e2014-05-28 10:32:17 -0400822 INIT_DELAYED_WORK(&ep->rep_connect_worker, rpcrdma_connect_worker);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400823
Chuck Leverfc664482014-05-28 10:33:25 -0400824 sendcq = ib_create_cq(ia->ri_id->device, rpcrdma_sendcq_upcall,
Chuck Lever1c00dd02014-05-28 10:33:42 -0400825 rpcrdma_cq_async_error_upcall, ep,
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400826 ep->rep_attr.cap.max_send_wr + 1, 0);
Chuck Leverfc664482014-05-28 10:33:25 -0400827 if (IS_ERR(sendcq)) {
828 rc = PTR_ERR(sendcq);
829 dprintk("RPC: %s: failed to create send CQ: %i\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400830 __func__, rc);
831 goto out1;
832 }
833
Chuck Leverfc664482014-05-28 10:33:25 -0400834 rc = ib_req_notify_cq(sendcq, IB_CQ_NEXT_COMP);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400835 if (rc) {
836 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
837 __func__, rc);
838 goto out2;
839 }
840
Chuck Leverfc664482014-05-28 10:33:25 -0400841 recvcq = ib_create_cq(ia->ri_id->device, rpcrdma_recvcq_upcall,
Chuck Lever1c00dd02014-05-28 10:33:42 -0400842 rpcrdma_cq_async_error_upcall, ep,
Chuck Leverfc664482014-05-28 10:33:25 -0400843 ep->rep_attr.cap.max_recv_wr + 1, 0);
844 if (IS_ERR(recvcq)) {
845 rc = PTR_ERR(recvcq);
846 dprintk("RPC: %s: failed to create recv CQ: %i\n",
847 __func__, rc);
848 goto out2;
849 }
850
851 rc = ib_req_notify_cq(recvcq, IB_CQ_NEXT_COMP);
852 if (rc) {
853 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
854 __func__, rc);
855 ib_destroy_cq(recvcq);
856 goto out2;
857 }
858
859 ep->rep_attr.send_cq = sendcq;
860 ep->rep_attr.recv_cq = recvcq;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400861
862 /* Initialize cma parameters */
863
864 /* RPC/RDMA does not use private data */
865 ep->rep_remote_cma.private_data = NULL;
866 ep->rep_remote_cma.private_data_len = 0;
867
868 /* Client offers RDMA Read but does not initiate */
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400869 ep->rep_remote_cma.initiator_depth = 0;
Chuck Lever7bc79722015-01-21 11:03:27 -0500870 if (devattr->max_qp_rd_atom > 32) /* arbitrary but <= 255 */
Tom Tuckerb334eaa2008-10-09 15:00:30 -0400871 ep->rep_remote_cma.responder_resources = 32;
872 else
Chuck Lever7bc79722015-01-21 11:03:27 -0500873 ep->rep_remote_cma.responder_resources =
874 devattr->max_qp_rd_atom;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400875
876 ep->rep_remote_cma.retry_count = 7;
877 ep->rep_remote_cma.flow_control = 0;
878 ep->rep_remote_cma.rnr_retry_count = 0;
879
880 return 0;
881
882out2:
Chuck Leverfc664482014-05-28 10:33:25 -0400883 err = ib_destroy_cq(sendcq);
Chuck Lever5d40a8a2007-10-26 13:30:54 -0400884 if (err)
885 dprintk("RPC: %s: ib_destroy_cq returned %i\n",
886 __func__, err);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400887out1:
Chuck Leverc05fbb52015-01-21 11:04:33 -0500888 rpcrdma_free_regbuf(ia, ep->rep_padbuf);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400889 return rc;
890}
891
892/*
893 * rpcrdma_ep_destroy
894 *
895 * Disconnect and destroy endpoint. After this, the only
896 * valid operations on the ep are to free it (if dynamically
897 * allocated) or re-create it.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400898 */
Chuck Lever7f1d5412014-05-28 10:33:16 -0400899void
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400900rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
901{
902 int rc;
903
904 dprintk("RPC: %s: entering, connected is %d\n",
905 __func__, ep->rep_connected);
906
Chuck Lever254f91e2014-05-28 10:32:17 -0400907 cancel_delayed_work_sync(&ep->rep_connect_worker);
908
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400909 if (ia->ri_id->qp) {
Chuck Lever282191c2014-07-29 17:25:55 -0400910 rpcrdma_ep_disconnect(ep, ia);
Tom Talpeyfee08ca2008-10-09 15:01:00 -0400911 rdma_destroy_qp(ia->ri_id);
912 ia->ri_id->qp = NULL;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400913 }
914
Chuck Leverc05fbb52015-01-21 11:04:33 -0500915 rpcrdma_free_regbuf(ia, ep->rep_padbuf);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400916
Chuck Leverfc664482014-05-28 10:33:25 -0400917 rpcrdma_clean_cq(ep->rep_attr.recv_cq);
918 rc = ib_destroy_cq(ep->rep_attr.recv_cq);
919 if (rc)
920 dprintk("RPC: %s: ib_destroy_cq returned %i\n",
921 __func__, rc);
922
923 rpcrdma_clean_cq(ep->rep_attr.send_cq);
924 rc = ib_destroy_cq(ep->rep_attr.send_cq);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400925 if (rc)
926 dprintk("RPC: %s: ib_destroy_cq returned %i\n",
927 __func__, rc);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400928}
929
930/*
931 * Connect unconnected endpoint.
932 */
933int
934rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
935{
Chuck Lever73806c82014-07-29 17:23:25 -0400936 struct rdma_cm_id *id, *old;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400937 int rc = 0;
938 int retry_count = 0;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400939
Tom Talpeyc0555512008-10-10 11:32:45 -0400940 if (ep->rep_connected != 0) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400941 struct rpcrdma_xprt *xprt;
942retry:
Chuck Leverec62f402014-05-28 10:34:07 -0400943 dprintk("RPC: %s: reconnecting...\n", __func__);
Chuck Lever282191c2014-07-29 17:25:55 -0400944
945 rpcrdma_ep_disconnect(ep, ia);
Chuck Levera7bc2112014-07-29 17:23:52 -0400946 rpcrdma_flush_cqs(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400947
Chuck Lever467c9672014-11-08 20:14:29 -0500948 switch (ia->ri_memreg_strategy) {
949 case RPCRDMA_FRMR:
Chuck Lever9f9d8022014-07-29 17:24:45 -0400950 rpcrdma_reset_frmrs(ia);
Chuck Lever467c9672014-11-08 20:14:29 -0500951 break;
952 case RPCRDMA_MTHCAFMR:
953 rpcrdma_reset_fmrs(ia);
954 break;
955 case RPCRDMA_ALLPHYSICAL:
956 break;
957 default:
958 rc = -EIO;
959 goto out;
960 }
Chuck Lever9f9d8022014-07-29 17:24:45 -0400961
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400962 xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
963 id = rpcrdma_create_id(xprt, ia,
964 (struct sockaddr *)&xprt->rx_data.addr);
965 if (IS_ERR(id)) {
Chuck Leverec62f402014-05-28 10:34:07 -0400966 rc = -EHOSTUNREACH;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400967 goto out;
968 }
969 /* TEMP TEMP TEMP - fail if new device:
970 * Deregister/remarshal *all* requests!
971 * Close and recreate adapter, pd, etc!
972 * Re-determine all attributes still sane!
973 * More stuff I haven't thought of!
974 * Rrrgh!
975 */
976 if (ia->ri_id->device != id->device) {
977 printk("RPC: %s: can't reconnect on "
978 "different device!\n", __func__);
979 rdma_destroy_id(id);
Chuck Leverec62f402014-05-28 10:34:07 -0400980 rc = -ENETUNREACH;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400981 goto out;
982 }
983 /* END TEMP */
Chuck Leverec62f402014-05-28 10:34:07 -0400984 rc = rdma_create_qp(id, ia->ri_pd, &ep->rep_attr);
985 if (rc) {
986 dprintk("RPC: %s: rdma_create_qp failed %i\n",
987 __func__, rc);
988 rdma_destroy_id(id);
989 rc = -ENETUNREACH;
990 goto out;
991 }
Chuck Lever73806c82014-07-29 17:23:25 -0400992
993 write_lock(&ia->ri_qplock);
994 old = ia->ri_id;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400995 ia->ri_id = id;
Chuck Lever73806c82014-07-29 17:23:25 -0400996 write_unlock(&ia->ri_qplock);
997
998 rdma_destroy_qp(old);
999 rdma_destroy_id(old);
Chuck Leverec62f402014-05-28 10:34:07 -04001000 } else {
1001 dprintk("RPC: %s: connecting...\n", __func__);
1002 rc = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr);
1003 if (rc) {
1004 dprintk("RPC: %s: rdma_create_qp failed %i\n",
1005 __func__, rc);
1006 /* do not update ep->rep_connected */
1007 return -ENETUNREACH;
1008 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001009 }
1010
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001011 ep->rep_connected = 0;
1012
1013 rc = rdma_connect(ia->ri_id, &ep->rep_remote_cma);
1014 if (rc) {
1015 dprintk("RPC: %s: rdma_connect() failed with %i\n",
1016 __func__, rc);
1017 goto out;
1018 }
1019
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001020 wait_event_interruptible(ep->rep_connect_wait, ep->rep_connected != 0);
1021
1022 /*
1023 * Check state. A non-peer reject indicates no listener
1024 * (ECONNREFUSED), which may be a transient state. All
1025 * others indicate a transport condition which has already
1026 * undergone a best-effort.
1027 */
Joe Perchesf64f9e72009-11-29 16:55:45 -08001028 if (ep->rep_connected == -ECONNREFUSED &&
1029 ++retry_count <= RDMA_CONNECT_RETRY_MAX) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001030 dprintk("RPC: %s: non-peer_reject, retry\n", __func__);
1031 goto retry;
1032 }
1033 if (ep->rep_connected <= 0) {
1034 /* Sometimes, the only way to reliably connect to remote
1035 * CMs is to use same nonzero values for ORD and IRD. */
Tom Tuckerb334eaa2008-10-09 15:00:30 -04001036 if (retry_count++ <= RDMA_CONNECT_RETRY_MAX + 1 &&
1037 (ep->rep_remote_cma.responder_resources == 0 ||
1038 ep->rep_remote_cma.initiator_depth !=
1039 ep->rep_remote_cma.responder_resources)) {
1040 if (ep->rep_remote_cma.responder_resources == 0)
1041 ep->rep_remote_cma.responder_resources = 1;
1042 ep->rep_remote_cma.initiator_depth =
1043 ep->rep_remote_cma.responder_resources;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001044 goto retry;
Tom Tuckerb334eaa2008-10-09 15:00:30 -04001045 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001046 rc = ep->rep_connected;
1047 } else {
1048 dprintk("RPC: %s: connected\n", __func__);
1049 }
1050
1051out:
1052 if (rc)
1053 ep->rep_connected = rc;
1054 return rc;
1055}
1056
1057/*
1058 * rpcrdma_ep_disconnect
1059 *
1060 * This is separate from destroy to facilitate the ability
1061 * to reconnect without recreating the endpoint.
1062 *
1063 * This call is not reentrant, and must not be made in parallel
1064 * on the same endpoint.
1065 */
Chuck Lever282191c2014-07-29 17:25:55 -04001066void
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001067rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
1068{
1069 int rc;
1070
Chuck Levera7bc2112014-07-29 17:23:52 -04001071 rpcrdma_flush_cqs(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001072 rc = rdma_disconnect(ia->ri_id);
1073 if (!rc) {
1074 /* returns without wait if not connected */
1075 wait_event_interruptible(ep->rep_connect_wait,
1076 ep->rep_connected != 1);
1077 dprintk("RPC: %s: after wait, %sconnected\n", __func__,
1078 (ep->rep_connected == 1) ? "still " : "dis");
1079 } else {
1080 dprintk("RPC: %s: rdma_disconnect %i\n", __func__, rc);
1081 ep->rep_connected = rc;
1082 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001083}
1084
Chuck Lever13924022015-01-21 11:03:52 -05001085static struct rpcrdma_req *
1086rpcrdma_create_req(struct rpcrdma_xprt *r_xprt)
1087{
Chuck Lever13924022015-01-21 11:03:52 -05001088 struct rpcrdma_req *req;
Chuck Lever13924022015-01-21 11:03:52 -05001089
Chuck Lever85275c82015-01-21 11:04:16 -05001090 req = kzalloc(sizeof(*req), GFP_KERNEL);
Chuck Lever13924022015-01-21 11:03:52 -05001091 if (req == NULL)
Chuck Lever85275c82015-01-21 11:04:16 -05001092 return ERR_PTR(-ENOMEM);
Chuck Lever13924022015-01-21 11:03:52 -05001093
Chuck Lever13924022015-01-21 11:03:52 -05001094 req->rl_buffer = &r_xprt->rx_buf;
1095 return req;
Chuck Lever13924022015-01-21 11:03:52 -05001096}
1097
1098static struct rpcrdma_rep *
1099rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt)
1100{
1101 struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
Chuck Lever13924022015-01-21 11:03:52 -05001102 struct rpcrdma_ia *ia = &r_xprt->rx_ia;
1103 struct rpcrdma_rep *rep;
1104 int rc;
1105
1106 rc = -ENOMEM;
Chuck Lever6b1184c2015-01-21 11:04:25 -05001107 rep = kzalloc(sizeof(*rep), GFP_KERNEL);
Chuck Lever13924022015-01-21 11:03:52 -05001108 if (rep == NULL)
1109 goto out;
Chuck Lever13924022015-01-21 11:03:52 -05001110
Chuck Lever6b1184c2015-01-21 11:04:25 -05001111 rep->rr_rdmabuf = rpcrdma_alloc_regbuf(ia, cdata->inline_rsize,
1112 GFP_KERNEL);
1113 if (IS_ERR(rep->rr_rdmabuf)) {
1114 rc = PTR_ERR(rep->rr_rdmabuf);
Chuck Lever13924022015-01-21 11:03:52 -05001115 goto out_free;
Chuck Lever6b1184c2015-01-21 11:04:25 -05001116 }
Chuck Lever13924022015-01-21 11:03:52 -05001117
1118 rep->rr_buffer = &r_xprt->rx_buf;
1119 return rep;
1120
1121out_free:
1122 kfree(rep);
1123out:
1124 return ERR_PTR(rc);
1125}
1126
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001127int
Chuck Leverac920d02015-01-21 11:03:44 -05001128rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001129{
Chuck Leverac920d02015-01-21 11:03:44 -05001130 struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1131 struct rpcrdma_ia *ia = &r_xprt->rx_ia;
1132 struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001133 char *p;
Chuck Lever13924022015-01-21 11:03:52 -05001134 size_t len;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001135 int i, rc;
1136
1137 buf->rb_max_requests = cdata->max_requests;
1138 spin_lock_init(&buf->rb_lock);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001139
1140 /* Need to allocate:
1141 * 1. arrays for send and recv pointers
1142 * 2. arrays of struct rpcrdma_req to fill in pointers
1143 * 3. array of struct rpcrdma_rep for replies
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001144 * Send/recv buffers in req/rep need to be registered
1145 */
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001146 len = buf->rb_max_requests *
1147 (sizeof(struct rpcrdma_req *) + sizeof(struct rpcrdma_rep *));
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001148
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001149 p = kzalloc(len, GFP_KERNEL);
1150 if (p == NULL) {
1151 dprintk("RPC: %s: req_t/rep_t/pad kzalloc(%zd) failed\n",
1152 __func__, len);
1153 rc = -ENOMEM;
1154 goto out;
1155 }
1156 buf->rb_pool = p; /* for freeing it later */
1157
1158 buf->rb_send_bufs = (struct rpcrdma_req **) p;
1159 p = (char *) &buf->rb_send_bufs[buf->rb_max_requests];
1160 buf->rb_recv_bufs = (struct rpcrdma_rep **) p;
1161 p = (char *) &buf->rb_recv_bufs[buf->rb_max_requests];
1162
Chuck Lever91e70e72015-03-30 14:34:58 -04001163 rc = ia->ri_ops->ro_init(r_xprt);
1164 if (rc)
1165 goto out;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001166
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001167 for (i = 0; i < buf->rb_max_requests; i++) {
1168 struct rpcrdma_req *req;
1169 struct rpcrdma_rep *rep;
1170
Chuck Lever13924022015-01-21 11:03:52 -05001171 req = rpcrdma_create_req(r_xprt);
1172 if (IS_ERR(req)) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001173 dprintk("RPC: %s: request buffer %d alloc"
1174 " failed\n", __func__, i);
Chuck Lever13924022015-01-21 11:03:52 -05001175 rc = PTR_ERR(req);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001176 goto out;
1177 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001178 buf->rb_send_bufs[i] = req;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001179
Chuck Lever13924022015-01-21 11:03:52 -05001180 rep = rpcrdma_create_rep(r_xprt);
1181 if (IS_ERR(rep)) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001182 dprintk("RPC: %s: reply buffer %d alloc failed\n",
1183 __func__, i);
Chuck Lever13924022015-01-21 11:03:52 -05001184 rc = PTR_ERR(rep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001185 goto out;
1186 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001187 buf->rb_recv_bufs[i] = rep;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001188 }
Chuck Lever13924022015-01-21 11:03:52 -05001189
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001190 return 0;
1191out:
1192 rpcrdma_buffer_destroy(buf);
1193 return rc;
1194}
1195
Chuck Lever2e845222014-07-29 17:25:38 -04001196static void
Chuck Lever13924022015-01-21 11:03:52 -05001197rpcrdma_destroy_rep(struct rpcrdma_ia *ia, struct rpcrdma_rep *rep)
1198{
1199 if (!rep)
1200 return;
1201
Chuck Lever6b1184c2015-01-21 11:04:25 -05001202 rpcrdma_free_regbuf(ia, rep->rr_rdmabuf);
Chuck Lever13924022015-01-21 11:03:52 -05001203 kfree(rep);
1204}
1205
1206static void
1207rpcrdma_destroy_req(struct rpcrdma_ia *ia, struct rpcrdma_req *req)
1208{
1209 if (!req)
1210 return;
1211
Chuck Lever0ca77dc2015-01-21 11:04:08 -05001212 rpcrdma_free_regbuf(ia, req->rl_sendbuf);
Chuck Lever85275c82015-01-21 11:04:16 -05001213 rpcrdma_free_regbuf(ia, req->rl_rdmabuf);
Chuck Lever13924022015-01-21 11:03:52 -05001214 kfree(req);
1215}
1216
1217static void
Chuck Lever2e845222014-07-29 17:25:38 -04001218rpcrdma_destroy_fmrs(struct rpcrdma_buffer *buf)
1219{
1220 struct rpcrdma_mw *r;
1221 int rc;
1222
1223 while (!list_empty(&buf->rb_all)) {
1224 r = list_entry(buf->rb_all.next, struct rpcrdma_mw, mw_all);
1225 list_del(&r->mw_all);
1226 list_del(&r->mw_list);
1227
1228 rc = ib_dealloc_fmr(r->r.fmr);
1229 if (rc)
1230 dprintk("RPC: %s: ib_dealloc_fmr failed %i\n",
1231 __func__, rc);
1232
1233 kfree(r);
1234 }
1235}
1236
1237static void
1238rpcrdma_destroy_frmrs(struct rpcrdma_buffer *buf)
1239{
1240 struct rpcrdma_mw *r;
1241 int rc;
1242
1243 while (!list_empty(&buf->rb_all)) {
1244 r = list_entry(buf->rb_all.next, struct rpcrdma_mw, mw_all);
1245 list_del(&r->mw_all);
1246 list_del(&r->mw_list);
1247
1248 rc = ib_dereg_mr(r->r.frmr.fr_mr);
1249 if (rc)
1250 dprintk("RPC: %s: ib_dereg_mr failed %i\n",
1251 __func__, rc);
1252 ib_free_fast_reg_page_list(r->r.frmr.fr_pgl);
1253
1254 kfree(r);
1255 }
1256}
1257
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001258void
1259rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
1260{
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001261 struct rpcrdma_ia *ia = rdmab_to_ia(buf);
Chuck Lever2e845222014-07-29 17:25:38 -04001262 int i;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001263
1264 /* clean up in reverse order from create
1265 * 1. recv mr memory (mr free, then kfree)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001266 * 2. send mr memory (mr free, then kfree)
Chuck Lever2e845222014-07-29 17:25:38 -04001267 * 3. MWs
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001268 */
1269 dprintk("RPC: %s: entering\n", __func__);
1270
1271 for (i = 0; i < buf->rb_max_requests; i++) {
Chuck Lever13924022015-01-21 11:03:52 -05001272 if (buf->rb_recv_bufs)
1273 rpcrdma_destroy_rep(ia, buf->rb_recv_bufs[i]);
1274 if (buf->rb_send_bufs)
1275 rpcrdma_destroy_req(ia, buf->rb_send_bufs[i]);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001276 }
1277
Chuck Lever2e845222014-07-29 17:25:38 -04001278 switch (ia->ri_memreg_strategy) {
1279 case RPCRDMA_FRMR:
1280 rpcrdma_destroy_frmrs(buf);
1281 break;
1282 case RPCRDMA_MTHCAFMR:
1283 rpcrdma_destroy_fmrs(buf);
1284 break;
1285 default:
1286 break;
Allen Andrews4034ba02014-05-28 10:32:09 -04001287 }
1288
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001289 kfree(buf->rb_pool);
1290}
1291
Chuck Lever467c9672014-11-08 20:14:29 -05001292/* After a disconnect, unmap all FMRs.
1293 *
1294 * This is invoked only in the transport connect worker in order
1295 * to serialize with rpcrdma_register_fmr_external().
1296 */
1297static void
1298rpcrdma_reset_fmrs(struct rpcrdma_ia *ia)
1299{
1300 struct rpcrdma_xprt *r_xprt =
1301 container_of(ia, struct rpcrdma_xprt, rx_ia);
1302 struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1303 struct list_head *pos;
1304 struct rpcrdma_mw *r;
1305 LIST_HEAD(l);
1306 int rc;
1307
1308 list_for_each(pos, &buf->rb_all) {
1309 r = list_entry(pos, struct rpcrdma_mw, mw_all);
1310
1311 INIT_LIST_HEAD(&l);
1312 list_add(&r->r.fmr->list, &l);
1313 rc = ib_unmap_fmr(&l);
1314 if (rc)
1315 dprintk("RPC: %s: ib_unmap_fmr failed %i\n",
1316 __func__, rc);
1317 }
1318}
1319
Chuck Lever9f9d8022014-07-29 17:24:45 -04001320/* After a disconnect, a flushed FAST_REG_MR can leave an FRMR in
1321 * an unusable state. Find FRMRs in this state and dereg / reg
1322 * each. FRMRs that are VALID and attached to an rpcrdma_req are
1323 * also torn down.
1324 *
1325 * This gives all in-use FRMRs a fresh rkey and leaves them INVALID.
1326 *
1327 * This is invoked only in the transport connect worker in order
1328 * to serialize with rpcrdma_register_frmr_external().
1329 */
1330static void
1331rpcrdma_reset_frmrs(struct rpcrdma_ia *ia)
1332{
1333 struct rpcrdma_xprt *r_xprt =
1334 container_of(ia, struct rpcrdma_xprt, rx_ia);
1335 struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1336 struct list_head *pos;
1337 struct rpcrdma_mw *r;
1338 int rc;
1339
1340 list_for_each(pos, &buf->rb_all) {
1341 r = list_entry(pos, struct rpcrdma_mw, mw_all);
1342
1343 if (r->r.frmr.fr_state == FRMR_IS_INVALID)
1344 continue;
1345
1346 rc = ib_dereg_mr(r->r.frmr.fr_mr);
1347 if (rc)
1348 dprintk("RPC: %s: ib_dereg_mr failed %i\n",
1349 __func__, rc);
1350 ib_free_fast_reg_page_list(r->r.frmr.fr_pgl);
1351
1352 r->r.frmr.fr_mr = ib_alloc_fast_reg_mr(ia->ri_pd,
1353 ia->ri_max_frmr_depth);
1354 if (IS_ERR(r->r.frmr.fr_mr)) {
1355 rc = PTR_ERR(r->r.frmr.fr_mr);
1356 dprintk("RPC: %s: ib_alloc_fast_reg_mr"
1357 " failed %i\n", __func__, rc);
1358 continue;
1359 }
1360 r->r.frmr.fr_pgl = ib_alloc_fast_reg_page_list(
1361 ia->ri_id->device,
1362 ia->ri_max_frmr_depth);
1363 if (IS_ERR(r->r.frmr.fr_pgl)) {
1364 rc = PTR_ERR(r->r.frmr.fr_pgl);
1365 dprintk("RPC: %s: "
1366 "ib_alloc_fast_reg_page_list "
1367 "failed %i\n", __func__, rc);
1368
1369 ib_dereg_mr(r->r.frmr.fr_mr);
1370 continue;
1371 }
1372 r->r.frmr.fr_state = FRMR_IS_INVALID;
1373 }
1374}
1375
Chuck Leverc2922c02014-07-29 17:24:36 -04001376/* "*mw" can be NULL when rpcrdma_buffer_get_mrs() fails, leaving
1377 * some req segments uninitialized.
1378 */
1379static void
1380rpcrdma_buffer_put_mr(struct rpcrdma_mw **mw, struct rpcrdma_buffer *buf)
1381{
1382 if (*mw) {
1383 list_add_tail(&(*mw)->mw_list, &buf->rb_mws);
1384 *mw = NULL;
1385 }
1386}
1387
1388/* Cycle mw's back in reverse order, and "spin" them.
1389 * This delays and scrambles reuse as much as possible.
1390 */
1391static void
1392rpcrdma_buffer_put_mrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf)
1393{
1394 struct rpcrdma_mr_seg *seg = req->rl_segments;
1395 struct rpcrdma_mr_seg *seg1 = seg;
1396 int i;
1397
1398 for (i = 1, seg++; i < RPCRDMA_MAX_SEGS; seg++, i++)
Chuck Lever3eb35812015-01-21 11:02:54 -05001399 rpcrdma_buffer_put_mr(&seg->rl_mw, buf);
1400 rpcrdma_buffer_put_mr(&seg1->rl_mw, buf);
Chuck Leverc2922c02014-07-29 17:24:36 -04001401}
1402
1403static void
1404rpcrdma_buffer_put_sendbuf(struct rpcrdma_req *req, struct rpcrdma_buffer *buf)
1405{
1406 buf->rb_send_bufs[--buf->rb_send_index] = req;
1407 req->rl_niovs = 0;
1408 if (req->rl_reply) {
1409 buf->rb_recv_bufs[--buf->rb_recv_index] = req->rl_reply;
1410 req->rl_reply->rr_func = NULL;
1411 req->rl_reply = NULL;
1412 }
1413}
1414
Chuck Lever6814bae2015-03-30 14:34:48 -04001415/* rpcrdma_unmap_one() was already done during deregistration.
Chuck Leverddb6beb2014-07-29 17:24:54 -04001416 * Redo only the ib_post_send().
1417 */
1418static void
1419rpcrdma_retry_local_inv(struct rpcrdma_mw *r, struct rpcrdma_ia *ia)
1420{
1421 struct rpcrdma_xprt *r_xprt =
1422 container_of(ia, struct rpcrdma_xprt, rx_ia);
1423 struct ib_send_wr invalidate_wr, *bad_wr;
1424 int rc;
1425
1426 dprintk("RPC: %s: FRMR %p is stale\n", __func__, r);
1427
1428 /* When this FRMR is re-inserted into rb_mws, it is no longer stale */
Chuck Leverdab7e3b2014-07-29 17:25:20 -04001429 r->r.frmr.fr_state = FRMR_IS_INVALID;
Chuck Leverddb6beb2014-07-29 17:24:54 -04001430
1431 memset(&invalidate_wr, 0, sizeof(invalidate_wr));
1432 invalidate_wr.wr_id = (unsigned long)(void *)r;
1433 invalidate_wr.opcode = IB_WR_LOCAL_INV;
Chuck Leverddb6beb2014-07-29 17:24:54 -04001434 invalidate_wr.ex.invalidate_rkey = r->r.frmr.fr_mr->rkey;
1435 DECR_CQCOUNT(&r_xprt->rx_ep);
1436
1437 dprintk("RPC: %s: frmr %p invalidating rkey %08x\n",
1438 __func__, r, r->r.frmr.fr_mr->rkey);
1439
1440 read_lock(&ia->ri_qplock);
1441 rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr);
1442 read_unlock(&ia->ri_qplock);
1443 if (rc) {
1444 /* Force rpcrdma_buffer_get() to retry */
1445 r->r.frmr.fr_state = FRMR_IS_STALE;
1446 dprintk("RPC: %s: ib_post_send failed, %i\n",
1447 __func__, rc);
1448 }
1449}
1450
1451static void
1452rpcrdma_retry_flushed_linv(struct list_head *stale,
1453 struct rpcrdma_buffer *buf)
1454{
1455 struct rpcrdma_ia *ia = rdmab_to_ia(buf);
1456 struct list_head *pos;
1457 struct rpcrdma_mw *r;
1458 unsigned long flags;
1459
1460 list_for_each(pos, stale) {
1461 r = list_entry(pos, struct rpcrdma_mw, mw_list);
1462 rpcrdma_retry_local_inv(r, ia);
1463 }
1464
1465 spin_lock_irqsave(&buf->rb_lock, flags);
1466 list_splice_tail(stale, &buf->rb_mws);
1467 spin_unlock_irqrestore(&buf->rb_lock, flags);
1468}
1469
Chuck Leverc2922c02014-07-29 17:24:36 -04001470static struct rpcrdma_req *
Chuck Leverddb6beb2014-07-29 17:24:54 -04001471rpcrdma_buffer_get_frmrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf,
1472 struct list_head *stale)
1473{
1474 struct rpcrdma_mw *r;
1475 int i;
1476
1477 i = RPCRDMA_MAX_SEGS - 1;
1478 while (!list_empty(&buf->rb_mws)) {
1479 r = list_entry(buf->rb_mws.next,
1480 struct rpcrdma_mw, mw_list);
1481 list_del(&r->mw_list);
1482 if (r->r.frmr.fr_state == FRMR_IS_STALE) {
1483 list_add(&r->mw_list, stale);
1484 continue;
1485 }
Chuck Lever3eb35812015-01-21 11:02:54 -05001486 req->rl_segments[i].rl_mw = r;
Chuck Leverddb6beb2014-07-29 17:24:54 -04001487 if (unlikely(i-- == 0))
1488 return req; /* Success */
1489 }
1490
1491 /* Not enough entries on rb_mws for this req */
1492 rpcrdma_buffer_put_sendbuf(req, buf);
1493 rpcrdma_buffer_put_mrs(req, buf);
1494 return NULL;
1495}
1496
1497static struct rpcrdma_req *
1498rpcrdma_buffer_get_fmrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf)
Chuck Leverc2922c02014-07-29 17:24:36 -04001499{
1500 struct rpcrdma_mw *r;
1501 int i;
1502
1503 i = RPCRDMA_MAX_SEGS - 1;
1504 while (!list_empty(&buf->rb_mws)) {
1505 r = list_entry(buf->rb_mws.next,
1506 struct rpcrdma_mw, mw_list);
1507 list_del(&r->mw_list);
Chuck Lever3eb35812015-01-21 11:02:54 -05001508 req->rl_segments[i].rl_mw = r;
Chuck Leverc2922c02014-07-29 17:24:36 -04001509 if (unlikely(i-- == 0))
1510 return req; /* Success */
1511 }
1512
1513 /* Not enough entries on rb_mws for this req */
1514 rpcrdma_buffer_put_sendbuf(req, buf);
1515 rpcrdma_buffer_put_mrs(req, buf);
1516 return NULL;
1517}
1518
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001519/*
1520 * Get a set of request/reply buffers.
1521 *
1522 * Reply buffer (if needed) is attached to send buffer upon return.
1523 * Rule:
1524 * rb_send_index and rb_recv_index MUST always be pointing to the
1525 * *next* available buffer (non-NULL). They are incremented after
1526 * removing buffers, and decremented *before* returning them.
1527 */
1528struct rpcrdma_req *
1529rpcrdma_buffer_get(struct rpcrdma_buffer *buffers)
1530{
Chuck Leverc2922c02014-07-29 17:24:36 -04001531 struct rpcrdma_ia *ia = rdmab_to_ia(buffers);
Chuck Leverddb6beb2014-07-29 17:24:54 -04001532 struct list_head stale;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001533 struct rpcrdma_req *req;
1534 unsigned long flags;
1535
1536 spin_lock_irqsave(&buffers->rb_lock, flags);
1537 if (buffers->rb_send_index == buffers->rb_max_requests) {
1538 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1539 dprintk("RPC: %s: out of request buffers\n", __func__);
1540 return ((struct rpcrdma_req *)NULL);
1541 }
1542
1543 req = buffers->rb_send_bufs[buffers->rb_send_index];
1544 if (buffers->rb_send_index < buffers->rb_recv_index) {
1545 dprintk("RPC: %s: %d extra receives outstanding (ok)\n",
1546 __func__,
1547 buffers->rb_recv_index - buffers->rb_send_index);
1548 req->rl_reply = NULL;
1549 } else {
1550 req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
1551 buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
1552 }
1553 buffers->rb_send_bufs[buffers->rb_send_index++] = NULL;
Chuck Leverddb6beb2014-07-29 17:24:54 -04001554
1555 INIT_LIST_HEAD(&stale);
Chuck Leverc2922c02014-07-29 17:24:36 -04001556 switch (ia->ri_memreg_strategy) {
1557 case RPCRDMA_FRMR:
Chuck Leverddb6beb2014-07-29 17:24:54 -04001558 req = rpcrdma_buffer_get_frmrs(req, buffers, &stale);
1559 break;
Chuck Leverc2922c02014-07-29 17:24:36 -04001560 case RPCRDMA_MTHCAFMR:
Chuck Leverddb6beb2014-07-29 17:24:54 -04001561 req = rpcrdma_buffer_get_fmrs(req, buffers);
Chuck Leverc2922c02014-07-29 17:24:36 -04001562 break;
1563 default:
1564 break;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001565 }
1566 spin_unlock_irqrestore(&buffers->rb_lock, flags);
Chuck Leverddb6beb2014-07-29 17:24:54 -04001567 if (!list_empty(&stale))
1568 rpcrdma_retry_flushed_linv(&stale, buffers);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001569 return req;
1570}
1571
1572/*
1573 * Put request/reply buffers back into pool.
1574 * Pre-decrement counter/array index.
1575 */
1576void
1577rpcrdma_buffer_put(struct rpcrdma_req *req)
1578{
1579 struct rpcrdma_buffer *buffers = req->rl_buffer;
1580 struct rpcrdma_ia *ia = rdmab_to_ia(buffers);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001581 unsigned long flags;
1582
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001583 spin_lock_irqsave(&buffers->rb_lock, flags);
Chuck Leverc2922c02014-07-29 17:24:36 -04001584 rpcrdma_buffer_put_sendbuf(req, buffers);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001585 switch (ia->ri_memreg_strategy) {
Tom Talpey3197d3092008-10-09 15:00:20 -04001586 case RPCRDMA_FRMR:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001587 case RPCRDMA_MTHCAFMR:
Chuck Leverc2922c02014-07-29 17:24:36 -04001588 rpcrdma_buffer_put_mrs(req, buffers);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001589 break;
1590 default:
1591 break;
1592 }
1593 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1594}
1595
1596/*
1597 * Recover reply buffers from pool.
1598 * This happens when recovering from error conditions.
1599 * Post-increment counter/array index.
1600 */
1601void
1602rpcrdma_recv_buffer_get(struct rpcrdma_req *req)
1603{
1604 struct rpcrdma_buffer *buffers = req->rl_buffer;
1605 unsigned long flags;
1606
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001607 spin_lock_irqsave(&buffers->rb_lock, flags);
1608 if (buffers->rb_recv_index < buffers->rb_max_requests) {
1609 req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
1610 buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
1611 }
1612 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1613}
1614
1615/*
1616 * Put reply buffers back into pool when not attached to
Chuck Leverb45ccfd2014-05-28 10:32:34 -04001617 * request. This happens in error conditions.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001618 */
1619void
1620rpcrdma_recv_buffer_put(struct rpcrdma_rep *rep)
1621{
1622 struct rpcrdma_buffer *buffers = rep->rr_buffer;
1623 unsigned long flags;
1624
1625 rep->rr_func = NULL;
1626 spin_lock_irqsave(&buffers->rb_lock, flags);
1627 buffers->rb_recv_bufs[--buffers->rb_recv_index] = rep;
1628 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1629}
1630
1631/*
1632 * Wrappers for internal-use kmalloc memory registration, used by buffer code.
1633 */
1634
Chuck Leverdf515ca2015-01-21 11:04:41 -05001635static int
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001636rpcrdma_register_internal(struct rpcrdma_ia *ia, void *va, int len,
1637 struct ib_mr **mrp, struct ib_sge *iov)
1638{
1639 struct ib_phys_buf ipb;
1640 struct ib_mr *mr;
1641 int rc;
1642
1643 /*
1644 * All memory passed here was kmalloc'ed, therefore phys-contiguous.
1645 */
1646 iov->addr = ib_dma_map_single(ia->ri_id->device,
1647 va, len, DMA_BIDIRECTIONAL);
Yan Burmanbf858ab2014-06-19 16:06:30 +03001648 if (ib_dma_mapping_error(ia->ri_id->device, iov->addr))
1649 return -ENOMEM;
1650
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001651 iov->length = len;
1652
Tom Talpeybd7ed1d2008-10-09 15:00:09 -04001653 if (ia->ri_have_dma_lkey) {
1654 *mrp = NULL;
1655 iov->lkey = ia->ri_dma_lkey;
1656 return 0;
1657 } else if (ia->ri_bind_mem != NULL) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001658 *mrp = NULL;
1659 iov->lkey = ia->ri_bind_mem->lkey;
1660 return 0;
1661 }
1662
1663 ipb.addr = iov->addr;
1664 ipb.size = iov->length;
1665 mr = ib_reg_phys_mr(ia->ri_pd, &ipb, 1,
1666 IB_ACCESS_LOCAL_WRITE, &iov->addr);
1667
1668 dprintk("RPC: %s: phys convert: 0x%llx "
1669 "registered 0x%llx length %d\n",
Andrew Mortona56daeb2007-10-16 01:29:57 -07001670 __func__, (unsigned long long)ipb.addr,
1671 (unsigned long long)iov->addr, len);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001672
1673 if (IS_ERR(mr)) {
1674 *mrp = NULL;
1675 rc = PTR_ERR(mr);
1676 dprintk("RPC: %s: failed with %i\n", __func__, rc);
1677 } else {
1678 *mrp = mr;
1679 iov->lkey = mr->lkey;
1680 rc = 0;
1681 }
1682
1683 return rc;
1684}
1685
Chuck Leverdf515ca2015-01-21 11:04:41 -05001686static int
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001687rpcrdma_deregister_internal(struct rpcrdma_ia *ia,
1688 struct ib_mr *mr, struct ib_sge *iov)
1689{
1690 int rc;
1691
1692 ib_dma_unmap_single(ia->ri_id->device,
1693 iov->addr, iov->length, DMA_BIDIRECTIONAL);
1694
1695 if (NULL == mr)
1696 return 0;
1697
1698 rc = ib_dereg_mr(mr);
1699 if (rc)
1700 dprintk("RPC: %s: ib_dereg_mr failed %i\n", __func__, rc);
1701 return rc;
1702}
1703
Chuck Lever9128c3e2015-01-21 11:04:00 -05001704/**
1705 * rpcrdma_alloc_regbuf - kmalloc and register memory for SEND/RECV buffers
1706 * @ia: controlling rpcrdma_ia
1707 * @size: size of buffer to be allocated, in bytes
1708 * @flags: GFP flags
1709 *
1710 * Returns pointer to private header of an area of internally
1711 * registered memory, or an ERR_PTR. The registered buffer follows
1712 * the end of the private header.
1713 *
1714 * xprtrdma uses a regbuf for posting an outgoing RDMA SEND, or for
1715 * receiving the payload of RDMA RECV operations. regbufs are not
1716 * used for RDMA READ/WRITE operations, thus are registered only for
1717 * LOCAL access.
1718 */
1719struct rpcrdma_regbuf *
1720rpcrdma_alloc_regbuf(struct rpcrdma_ia *ia, size_t size, gfp_t flags)
1721{
1722 struct rpcrdma_regbuf *rb;
1723 int rc;
1724
1725 rc = -ENOMEM;
1726 rb = kmalloc(sizeof(*rb) + size, flags);
1727 if (rb == NULL)
1728 goto out;
1729
1730 rb->rg_size = size;
1731 rb->rg_owner = NULL;
1732 rc = rpcrdma_register_internal(ia, rb->rg_base, size,
1733 &rb->rg_mr, &rb->rg_iov);
1734 if (rc)
1735 goto out_free;
1736
1737 return rb;
1738
1739out_free:
1740 kfree(rb);
1741out:
1742 return ERR_PTR(rc);
1743}
1744
1745/**
1746 * rpcrdma_free_regbuf - deregister and free registered buffer
1747 * @ia: controlling rpcrdma_ia
1748 * @rb: regbuf to be deregistered and freed
1749 */
1750void
1751rpcrdma_free_regbuf(struct rpcrdma_ia *ia, struct rpcrdma_regbuf *rb)
1752{
1753 if (rb) {
1754 rpcrdma_deregister_internal(ia, rb->rg_mr, &rb->rg_iov);
1755 kfree(rb);
1756 }
1757}
1758
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001759/*
1760 * Wrappers for chunk registration, shared by read/write chunk code.
1761 */
1762
Chuck Lever9c1b4d72015-03-30 14:34:39 -04001763void
1764rpcrdma_map_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg, bool writing)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001765{
1766 seg->mr_dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
1767 seg->mr_dmalen = seg->mr_len;
1768 if (seg->mr_page)
1769 seg->mr_dma = ib_dma_map_page(ia->ri_id->device,
1770 seg->mr_page, offset_in_page(seg->mr_offset),
1771 seg->mr_dmalen, seg->mr_dir);
1772 else
1773 seg->mr_dma = ib_dma_map_single(ia->ri_id->device,
1774 seg->mr_offset,
1775 seg->mr_dmalen, seg->mr_dir);
Tom Tucker5c635e02011-02-09 19:45:34 +00001776 if (ib_dma_mapping_error(ia->ri_id->device, seg->mr_dma)) {
1777 dprintk("RPC: %s: mr_dma %llx mr_offset %p mr_dma_len %zu\n",
1778 __func__,
Randy Dunlap986d4ab2011-03-15 17:11:59 -07001779 (unsigned long long)seg->mr_dma,
1780 seg->mr_offset, seg->mr_dmalen);
Tom Tucker5c635e02011-02-09 19:45:34 +00001781 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001782}
1783
Chuck Lever9c1b4d72015-03-30 14:34:39 -04001784void
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001785rpcrdma_unmap_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg)
1786{
1787 if (seg->mr_page)
1788 ib_dma_unmap_page(ia->ri_id->device,
1789 seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
1790 else
1791 ib_dma_unmap_single(ia->ri_id->device,
1792 seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
1793}
1794
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001795/*
1796 * Prepost any receive buffer, then post send.
1797 *
1798 * Receive buffer is donated to hardware, reclaimed upon recv completion.
1799 */
1800int
1801rpcrdma_ep_post(struct rpcrdma_ia *ia,
1802 struct rpcrdma_ep *ep,
1803 struct rpcrdma_req *req)
1804{
1805 struct ib_send_wr send_wr, *send_wr_fail;
1806 struct rpcrdma_rep *rep = req->rl_reply;
1807 int rc;
1808
1809 if (rep) {
1810 rc = rpcrdma_ep_post_recv(ia, ep, rep);
1811 if (rc)
1812 goto out;
1813 req->rl_reply = NULL;
1814 }
1815
1816 send_wr.next = NULL;
1817 send_wr.wr_id = 0ULL; /* no send cookie */
1818 send_wr.sg_list = req->rl_send_iov;
1819 send_wr.num_sge = req->rl_niovs;
1820 send_wr.opcode = IB_WR_SEND;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001821 if (send_wr.num_sge == 4) /* no need to sync any pad (constant) */
1822 ib_dma_sync_single_for_device(ia->ri_id->device,
1823 req->rl_send_iov[3].addr, req->rl_send_iov[3].length,
1824 DMA_TO_DEVICE);
1825 ib_dma_sync_single_for_device(ia->ri_id->device,
1826 req->rl_send_iov[1].addr, req->rl_send_iov[1].length,
1827 DMA_TO_DEVICE);
1828 ib_dma_sync_single_for_device(ia->ri_id->device,
1829 req->rl_send_iov[0].addr, req->rl_send_iov[0].length,
1830 DMA_TO_DEVICE);
1831
1832 if (DECR_CQCOUNT(ep) > 0)
1833 send_wr.send_flags = 0;
1834 else { /* Provider must take a send completion every now and then */
1835 INIT_CQCOUNT(ep);
1836 send_wr.send_flags = IB_SEND_SIGNALED;
1837 }
1838
1839 rc = ib_post_send(ia->ri_id->qp, &send_wr, &send_wr_fail);
1840 if (rc)
1841 dprintk("RPC: %s: ib_post_send returned %i\n", __func__,
1842 rc);
1843out:
1844 return rc;
1845}
1846
1847/*
1848 * (Re)post a receive buffer.
1849 */
1850int
1851rpcrdma_ep_post_recv(struct rpcrdma_ia *ia,
1852 struct rpcrdma_ep *ep,
1853 struct rpcrdma_rep *rep)
1854{
1855 struct ib_recv_wr recv_wr, *recv_wr_fail;
1856 int rc;
1857
1858 recv_wr.next = NULL;
1859 recv_wr.wr_id = (u64) (unsigned long) rep;
Chuck Lever6b1184c2015-01-21 11:04:25 -05001860 recv_wr.sg_list = &rep->rr_rdmabuf->rg_iov;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001861 recv_wr.num_sge = 1;
1862
1863 ib_dma_sync_single_for_cpu(ia->ri_id->device,
Chuck Lever6b1184c2015-01-21 11:04:25 -05001864 rdmab_addr(rep->rr_rdmabuf),
1865 rdmab_length(rep->rr_rdmabuf),
1866 DMA_BIDIRECTIONAL);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001867
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001868 rc = ib_post_recv(ia->ri_id->qp, &recv_wr, &recv_wr_fail);
1869
1870 if (rc)
1871 dprintk("RPC: %s: ib_post_recv returned %i\n", __func__,
1872 rc);
1873 return rc;
1874}
Chuck Lever43e95982014-07-29 17:23:34 -04001875
Chuck Lever1c9351e2015-03-30 14:34:30 -04001876/* How many chunk list items fit within our inline buffers?
Chuck Lever43e95982014-07-29 17:23:34 -04001877 */
Chuck Lever1c9351e2015-03-30 14:34:30 -04001878unsigned int
1879rpcrdma_max_segments(struct rpcrdma_xprt *r_xprt)
Chuck Lever43e95982014-07-29 17:23:34 -04001880{
1881 struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
Chuck Lever1c9351e2015-03-30 14:34:30 -04001882 int bytes, segments;
Chuck Lever43e95982014-07-29 17:23:34 -04001883
Chuck Lever1c9351e2015-03-30 14:34:30 -04001884 bytes = min_t(unsigned int, cdata->inline_wsize, cdata->inline_rsize);
1885 bytes -= RPCRDMA_HDRLEN_MIN;
1886 if (bytes < sizeof(struct rpcrdma_segment) * 2) {
1887 pr_warn("RPC: %s: inline threshold too small\n",
1888 __func__);
1889 return 0;
Chuck Lever43e95982014-07-29 17:23:34 -04001890 }
Chuck Lever1c9351e2015-03-30 14:34:30 -04001891
1892 segments = 1 << (fls(bytes / sizeof(struct rpcrdma_segment)) - 1);
1893 dprintk("RPC: %s: max chunk list size = %d segments\n",
1894 __func__, segments);
1895 return segments;
Chuck Lever43e95982014-07-29 17:23:34 -04001896}