blob: e49cdc930dfd68135f4321fed64a8e7f21bb59ab [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 Lever65866f82014-05-28 10:33:59 -040052#include <asm/bitops.h>
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -040053
\"Talpey, Thomas\f58851e2007-09-10 13:50:12 -040054#include "xprt_rdma.h"
55
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -040056/*
57 * Globals/Macros
58 */
59
60#ifdef RPC_DEBUG
61# define RPCDBG_FACILITY RPCDBG_TRANS
62#endif
63
64/*
65 * internal functions
66 */
67
68/*
69 * handle replies in tasklet context, using a single, global list
70 * rdma tasklet function -- just turn around and call the func
71 * for all replies on the list
72 */
73
74static DEFINE_SPINLOCK(rpcrdma_tk_lock_g);
75static LIST_HEAD(rpcrdma_tasklets_g);
76
77static void
78rpcrdma_run_tasklet(unsigned long data)
79{
80 struct rpcrdma_rep *rep;
81 void (*func)(struct rpcrdma_rep *);
82 unsigned long flags;
83
84 data = data;
85 spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
86 while (!list_empty(&rpcrdma_tasklets_g)) {
87 rep = list_entry(rpcrdma_tasklets_g.next,
88 struct rpcrdma_rep, rr_list);
89 list_del(&rep->rr_list);
90 func = rep->rr_func;
91 rep->rr_func = NULL;
92 spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
93
94 if (func)
95 func(rep);
96 else
97 rpcrdma_recv_buffer_put(rep);
98
99 spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
100 }
101 spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
102}
103
104static DECLARE_TASKLET(rpcrdma_tasklet_g, rpcrdma_run_tasklet, 0UL);
105
106static inline void
107rpcrdma_schedule_tasklet(struct rpcrdma_rep *rep)
108{
109 unsigned long flags;
110
111 spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
112 list_add_tail(&rep->rr_list, &rpcrdma_tasklets_g);
113 spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
114 tasklet_schedule(&rpcrdma_tasklet_g);
115}
116
117static void
118rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context)
119{
120 struct rpcrdma_ep *ep = context;
121
122 dprintk("RPC: %s: QP error %X on device %s ep %p\n",
123 __func__, event->event, event->device->name, context);
124 if (ep->rep_connected == 1) {
125 ep->rep_connected = -EIO;
126 ep->rep_func(ep);
127 wake_up_all(&ep->rep_connect_wait);
128 }
129}
130
131static void
132rpcrdma_cq_async_error_upcall(struct ib_event *event, void *context)
133{
134 struct rpcrdma_ep *ep = context;
135
136 dprintk("RPC: %s: CQ error %X on device %s ep %p\n",
137 __func__, event->event, event->device->name, context);
138 if (ep->rep_connected == 1) {
139 ep->rep_connected = -EIO;
140 ep->rep_func(ep);
141 wake_up_all(&ep->rep_connect_wait);
142 }
143}
144
Chuck Leverfc664482014-05-28 10:33:25 -0400145static void
146rpcrdma_sendcq_process_wc(struct ib_wc *wc)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400147{
Chuck Leverfc664482014-05-28 10:33:25 -0400148 struct rpcrdma_mw *frmr = (struct rpcrdma_mw *)(unsigned long)wc->wr_id;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400149
Chuck Leverfc664482014-05-28 10:33:25 -0400150 dprintk("RPC: %s: frmr %p status %X opcode %d\n",
151 __func__, frmr, wc->status, wc->opcode);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400152
Chuck Leverfc664482014-05-28 10:33:25 -0400153 if (wc->wr_id == 0ULL)
154 return;
155 if (wc->status != IB_WC_SUCCESS)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400156 return;
157
Chuck Leverfc664482014-05-28 10:33:25 -0400158 if (wc->opcode == IB_WC_FAST_REG_MR)
Tom Tucker5c635e02011-02-09 19:45:34 +0000159 frmr->r.frmr.state = FRMR_IS_VALID;
Chuck Leverfc664482014-05-28 10:33:25 -0400160 else if (wc->opcode == IB_WC_LOCAL_INV)
Tom Tucker5c635e02011-02-09 19:45:34 +0000161 frmr->r.frmr.state = FRMR_IS_INVALID;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400162}
163
Chuck Leverfc664482014-05-28 10:33:25 -0400164static int
Chuck Lever1c00dd02014-05-28 10:33:42 -0400165rpcrdma_sendcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400166{
Chuck Lever1c00dd02014-05-28 10:33:42 -0400167 struct ib_wc *wcs;
Chuck Lever8301a2c2014-05-28 10:33:51 -0400168 int budget, count, rc;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400169
Chuck Lever8301a2c2014-05-28 10:33:51 -0400170 budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE;
Chuck Lever1c00dd02014-05-28 10:33:42 -0400171 do {
172 wcs = ep->rep_send_wcs;
173
174 rc = ib_poll_cq(cq, RPCRDMA_POLLSIZE, wcs);
175 if (rc <= 0)
176 return rc;
177
178 count = rc;
179 while (count-- > 0)
180 rpcrdma_sendcq_process_wc(wcs++);
Chuck Lever8301a2c2014-05-28 10:33:51 -0400181 } while (rc == RPCRDMA_POLLSIZE && --budget);
Chuck Lever1c00dd02014-05-28 10:33:42 -0400182 return 0;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400183}
184
185/*
Chuck Leverfc664482014-05-28 10:33:25 -0400186 * Handle send, fast_reg_mr, and local_inv completions.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400187 *
Chuck Leverfc664482014-05-28 10:33:25 -0400188 * Send events are typically suppressed and thus do not result
189 * in an upcall. Occasionally one is signaled, however. This
190 * prevents the provider's completion queue from wrapping and
191 * losing a completion.
192 */
193static void
194rpcrdma_sendcq_upcall(struct ib_cq *cq, void *cq_context)
195{
Chuck Lever1c00dd02014-05-28 10:33:42 -0400196 struct rpcrdma_ep *ep = (struct rpcrdma_ep *)cq_context;
Chuck Leverfc664482014-05-28 10:33:25 -0400197 int rc;
198
Chuck Lever1c00dd02014-05-28 10:33:42 -0400199 rc = rpcrdma_sendcq_poll(cq, ep);
Chuck Leverfc664482014-05-28 10:33:25 -0400200 if (rc) {
201 dprintk("RPC: %s: ib_poll_cq failed: %i\n",
202 __func__, rc);
203 return;
204 }
205
Chuck Lever7f23f6f2014-05-28 10:33:34 -0400206 rc = ib_req_notify_cq(cq,
207 IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
208 if (rc == 0)
209 return;
210 if (rc < 0) {
Chuck Leverfc664482014-05-28 10:33:25 -0400211 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
212 __func__, rc);
213 return;
214 }
215
Chuck Lever1c00dd02014-05-28 10:33:42 -0400216 rpcrdma_sendcq_poll(cq, ep);
Chuck Leverfc664482014-05-28 10:33:25 -0400217}
218
219static void
220rpcrdma_recvcq_process_wc(struct ib_wc *wc)
221{
222 struct rpcrdma_rep *rep =
223 (struct rpcrdma_rep *)(unsigned long)wc->wr_id;
224
225 dprintk("RPC: %s: rep %p status %X opcode %X length %u\n",
226 __func__, rep, wc->status, wc->opcode, wc->byte_len);
227
228 if (wc->status != IB_WC_SUCCESS) {
229 rep->rr_len = ~0U;
230 goto out_schedule;
231 }
232 if (wc->opcode != IB_WC_RECV)
233 return;
234
235 rep->rr_len = wc->byte_len;
236 ib_dma_sync_single_for_cpu(rdmab_to_ia(rep->rr_buffer)->ri_id->device,
237 rep->rr_iov.addr, rep->rr_len, DMA_FROM_DEVICE);
238
239 if (rep->rr_len >= 16) {
240 struct rpcrdma_msg *p = (struct rpcrdma_msg *)rep->rr_base;
241 unsigned int credits = ntohl(p->rm_credit);
242
243 if (credits == 0)
244 credits = 1; /* don't deadlock */
245 else if (credits > rep->rr_buffer->rb_max_requests)
246 credits = rep->rr_buffer->rb_max_requests;
247 atomic_set(&rep->rr_buffer->rb_credits, credits);
248 }
249
250out_schedule:
251 rpcrdma_schedule_tasklet(rep);
252}
253
254static int
Chuck Lever1c00dd02014-05-28 10:33:42 -0400255rpcrdma_recvcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep)
Chuck Leverfc664482014-05-28 10:33:25 -0400256{
Chuck Lever1c00dd02014-05-28 10:33:42 -0400257 struct ib_wc *wcs;
Chuck Lever8301a2c2014-05-28 10:33:51 -0400258 int budget, count, rc;
Chuck Leverfc664482014-05-28 10:33:25 -0400259
Chuck Lever8301a2c2014-05-28 10:33:51 -0400260 budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE;
Chuck Lever1c00dd02014-05-28 10:33:42 -0400261 do {
262 wcs = ep->rep_recv_wcs;
263
264 rc = ib_poll_cq(cq, RPCRDMA_POLLSIZE, wcs);
265 if (rc <= 0)
266 return rc;
267
268 count = rc;
269 while (count-- > 0)
270 rpcrdma_recvcq_process_wc(wcs++);
Chuck Lever8301a2c2014-05-28 10:33:51 -0400271 } while (rc == RPCRDMA_POLLSIZE && --budget);
Chuck Lever1c00dd02014-05-28 10:33:42 -0400272 return 0;
Chuck Leverfc664482014-05-28 10:33:25 -0400273}
274
275/*
276 * Handle receive completions.
277 *
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400278 * It is reentrant but processes single events in order to maintain
279 * ordering of receives to keep server credits.
280 *
281 * It is the responsibility of the scheduled tasklet to return
282 * recv buffers to the pool. NOTE: this affects synchronization of
283 * connection shutdown. That is, the structures required for
284 * the completion of the reply handler must remain intact until
285 * all memory has been reclaimed.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400286 */
287static void
Chuck Leverfc664482014-05-28 10:33:25 -0400288rpcrdma_recvcq_upcall(struct ib_cq *cq, void *cq_context)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400289{
Chuck Lever1c00dd02014-05-28 10:33:42 -0400290 struct rpcrdma_ep *ep = (struct rpcrdma_ep *)cq_context;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400291 int rc;
292
Chuck Lever1c00dd02014-05-28 10:33:42 -0400293 rc = rpcrdma_recvcq_poll(cq, ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400294 if (rc) {
Chuck Leverfc664482014-05-28 10:33:25 -0400295 dprintk("RPC: %s: ib_poll_cq failed: %i\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400296 __func__, rc);
297 return;
298 }
299
Chuck Lever7f23f6f2014-05-28 10:33:34 -0400300 rc = ib_req_notify_cq(cq,
301 IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
302 if (rc == 0)
303 return;
304 if (rc < 0) {
Chuck Leverfc664482014-05-28 10:33:25 -0400305 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
306 __func__, rc);
307 return;
308 }
309
Chuck Lever1c00dd02014-05-28 10:33:42 -0400310 rpcrdma_recvcq_poll(cq, ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400311}
312
Chuck Levera7bc2112014-07-29 17:23:52 -0400313static void
314rpcrdma_flush_cqs(struct rpcrdma_ep *ep)
315{
316 rpcrdma_recvcq_upcall(ep->rep_attr.recv_cq, ep);
317 rpcrdma_sendcq_upcall(ep->rep_attr.send_cq, ep);
318}
319
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400320#ifdef RPC_DEBUG
321static const char * const conn[] = {
322 "address resolved",
323 "address error",
324 "route resolved",
325 "route error",
326 "connect request",
327 "connect response",
328 "connect error",
329 "unreachable",
330 "rejected",
331 "established",
332 "disconnected",
333 "device removal"
334};
335#endif
336
337static int
338rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
339{
340 struct rpcrdma_xprt *xprt = id->context;
341 struct rpcrdma_ia *ia = &xprt->rx_ia;
342 struct rpcrdma_ep *ep = &xprt->rx_ep;
Ingo Molnarff0db042008-11-25 16:58:42 -0800343#ifdef RPC_DEBUG
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400344 struct sockaddr_in *addr = (struct sockaddr_in *) &ep->rep_remote_addr;
Ingo Molnarff0db042008-11-25 16:58:42 -0800345#endif
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400346 struct ib_qp_attr attr;
347 struct ib_qp_init_attr iattr;
348 int connstate = 0;
349
350 switch (event->event) {
351 case RDMA_CM_EVENT_ADDR_RESOLVED:
352 case RDMA_CM_EVENT_ROUTE_RESOLVED:
Tom Talpey5675add2008-10-09 15:01:41 -0400353 ia->ri_async_rc = 0;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400354 complete(&ia->ri_done);
355 break;
356 case RDMA_CM_EVENT_ADDR_ERROR:
357 ia->ri_async_rc = -EHOSTUNREACH;
358 dprintk("RPC: %s: CM address resolution error, ep 0x%p\n",
359 __func__, ep);
360 complete(&ia->ri_done);
361 break;
362 case RDMA_CM_EVENT_ROUTE_ERROR:
363 ia->ri_async_rc = -ENETUNREACH;
364 dprintk("RPC: %s: CM route resolution error, ep 0x%p\n",
365 __func__, ep);
366 complete(&ia->ri_done);
367 break;
368 case RDMA_CM_EVENT_ESTABLISHED:
369 connstate = 1;
370 ib_query_qp(ia->ri_id->qp, &attr,
371 IB_QP_MAX_QP_RD_ATOMIC | IB_QP_MAX_DEST_RD_ATOMIC,
372 &iattr);
373 dprintk("RPC: %s: %d responder resources"
374 " (%d initiator)\n",
375 __func__, attr.max_dest_rd_atomic, attr.max_rd_atomic);
376 goto connected;
377 case RDMA_CM_EVENT_CONNECT_ERROR:
378 connstate = -ENOTCONN;
379 goto connected;
380 case RDMA_CM_EVENT_UNREACHABLE:
381 connstate = -ENETDOWN;
382 goto connected;
383 case RDMA_CM_EVENT_REJECTED:
384 connstate = -ECONNREFUSED;
385 goto connected;
386 case RDMA_CM_EVENT_DISCONNECTED:
387 connstate = -ECONNABORTED;
388 goto connected;
389 case RDMA_CM_EVENT_DEVICE_REMOVAL:
390 connstate = -ENODEV;
391connected:
Harvey Harrison21454aa2008-10-31 00:54:56 -0700392 dprintk("RPC: %s: %s: %pI4:%u (ep 0x%p event 0x%x)\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400393 __func__,
394 (event->event <= 11) ? conn[event->event] :
395 "unknown connection error",
Harvey Harrison21454aa2008-10-31 00:54:56 -0700396 &addr->sin_addr.s_addr,
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400397 ntohs(addr->sin_port),
398 ep, event->event);
399 atomic_set(&rpcx_to_rdmax(ep->rep_xprt)->rx_buf.rb_credits, 1);
400 dprintk("RPC: %s: %sconnected\n",
401 __func__, connstate > 0 ? "" : "dis");
402 ep->rep_connected = connstate;
403 ep->rep_func(ep);
404 wake_up_all(&ep->rep_connect_wait);
405 break;
406 default:
Tom Talpey1a954052008-10-09 15:01:31 -0400407 dprintk("RPC: %s: unexpected CM event %d\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400408 __func__, event->event);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400409 break;
410 }
411
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400412#ifdef RPC_DEBUG
413 if (connstate == 1) {
414 int ird = attr.max_dest_rd_atomic;
415 int tird = ep->rep_remote_cma.responder_resources;
Harvey Harrison21454aa2008-10-31 00:54:56 -0700416 printk(KERN_INFO "rpcrdma: connection to %pI4:%u "
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400417 "on %s, memreg %d slots %d ird %d%s\n",
Harvey Harrison21454aa2008-10-31 00:54:56 -0700418 &addr->sin_addr.s_addr,
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400419 ntohs(addr->sin_port),
420 ia->ri_id->device->name,
421 ia->ri_memreg_strategy,
422 xprt->rx_buf.rb_max_requests,
423 ird, ird < 4 && ird < tird / 2 ? " (low!)" : "");
424 } else if (connstate < 0) {
Harvey Harrison21454aa2008-10-31 00:54:56 -0700425 printk(KERN_INFO "rpcrdma: connection to %pI4:%u closed (%d)\n",
426 &addr->sin_addr.s_addr,
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400427 ntohs(addr->sin_port),
428 connstate);
429 }
430#endif
431
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400432 return 0;
433}
434
435static struct rdma_cm_id *
436rpcrdma_create_id(struct rpcrdma_xprt *xprt,
437 struct rpcrdma_ia *ia, struct sockaddr *addr)
438{
439 struct rdma_cm_id *id;
440 int rc;
441
Tom Talpey1a954052008-10-09 15:01:31 -0400442 init_completion(&ia->ri_done);
443
Sean Heftyb26f9b92010-04-01 17:08:41 +0000444 id = rdma_create_id(rpcrdma_conn_upcall, xprt, RDMA_PS_TCP, IB_QPT_RC);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400445 if (IS_ERR(id)) {
446 rc = PTR_ERR(id);
447 dprintk("RPC: %s: rdma_create_id() failed %i\n",
448 __func__, rc);
449 return id;
450 }
451
Tom Talpey5675add2008-10-09 15:01:41 -0400452 ia->ri_async_rc = -ETIMEDOUT;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400453 rc = rdma_resolve_addr(id, NULL, addr, RDMA_RESOLVE_TIMEOUT);
454 if (rc) {
455 dprintk("RPC: %s: rdma_resolve_addr() failed %i\n",
456 __func__, rc);
457 goto out;
458 }
Tom Talpey5675add2008-10-09 15:01:41 -0400459 wait_for_completion_interruptible_timeout(&ia->ri_done,
460 msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT) + 1);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400461 rc = ia->ri_async_rc;
462 if (rc)
463 goto out;
464
Tom Talpey5675add2008-10-09 15:01:41 -0400465 ia->ri_async_rc = -ETIMEDOUT;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400466 rc = rdma_resolve_route(id, RDMA_RESOLVE_TIMEOUT);
467 if (rc) {
468 dprintk("RPC: %s: rdma_resolve_route() failed %i\n",
469 __func__, rc);
470 goto out;
471 }
Tom Talpey5675add2008-10-09 15:01:41 -0400472 wait_for_completion_interruptible_timeout(&ia->ri_done,
473 msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT) + 1);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400474 rc = ia->ri_async_rc;
475 if (rc)
476 goto out;
477
478 return id;
479
480out:
481 rdma_destroy_id(id);
482 return ERR_PTR(rc);
483}
484
485/*
486 * Drain any cq, prior to teardown.
487 */
488static void
489rpcrdma_clean_cq(struct ib_cq *cq)
490{
491 struct ib_wc wc;
492 int count = 0;
493
494 while (1 == ib_poll_cq(cq, 1, &wc))
495 ++count;
496
497 if (count)
498 dprintk("RPC: %s: flushed %d events (last 0x%x)\n",
499 __func__, count, wc.opcode);
500}
501
502/*
503 * Exported functions.
504 */
505
506/*
507 * Open and initialize an Interface Adapter.
508 * o initializes fields of struct rpcrdma_ia, including
509 * interface and provider attributes and protection zone.
510 */
511int
512rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg)
513{
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400514 int rc, mem_priv;
515 struct ib_device_attr devattr;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400516 struct rpcrdma_ia *ia = &xprt->rx_ia;
517
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400518 ia->ri_id = rpcrdma_create_id(xprt, ia, addr);
519 if (IS_ERR(ia->ri_id)) {
520 rc = PTR_ERR(ia->ri_id);
521 goto out1;
522 }
523
524 ia->ri_pd = ib_alloc_pd(ia->ri_id->device);
525 if (IS_ERR(ia->ri_pd)) {
526 rc = PTR_ERR(ia->ri_pd);
527 dprintk("RPC: %s: ib_alloc_pd() failed %i\n",
528 __func__, rc);
529 goto out2;
530 }
531
532 /*
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400533 * Query the device to determine if the requested memory
534 * registration strategy is supported. If it isn't, set the
535 * strategy to a globally supported model.
536 */
537 rc = ib_query_device(ia->ri_id->device, &devattr);
538 if (rc) {
539 dprintk("RPC: %s: ib_query_device failed %d\n",
540 __func__, rc);
541 goto out2;
542 }
543
544 if (devattr.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY) {
545 ia->ri_have_dma_lkey = 1;
546 ia->ri_dma_lkey = ia->ri_id->device->local_dma_lkey;
547 }
548
Chuck Leverf10eafd2014-05-28 10:32:51 -0400549 if (memreg == RPCRDMA_FRMR) {
Tom Talpey3197d3092008-10-09 15:00:20 -0400550 /* Requires both frmr reg and local dma lkey */
551 if ((devattr.device_cap_flags &
552 (IB_DEVICE_MEM_MGT_EXTENSIONS|IB_DEVICE_LOCAL_DMA_LKEY)) !=
553 (IB_DEVICE_MEM_MGT_EXTENSIONS|IB_DEVICE_LOCAL_DMA_LKEY)) {
Tom Talpey3197d3092008-10-09 15:00:20 -0400554 dprintk("RPC: %s: FRMR registration "
Chuck Leverf10eafd2014-05-28 10:32:51 -0400555 "not supported by HCA\n", __func__);
556 memreg = RPCRDMA_MTHCAFMR;
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400557 } else {
558 /* Mind the ia limit on FRMR page list depth */
559 ia->ri_max_frmr_depth = min_t(unsigned int,
560 RPCRDMA_MAX_DATA_SEGS,
561 devattr.max_fast_reg_page_list_len);
Tom Talpey3197d3092008-10-09 15:00:20 -0400562 }
Chuck Leverf10eafd2014-05-28 10:32:51 -0400563 }
564 if (memreg == RPCRDMA_MTHCAFMR) {
565 if (!ia->ri_id->device->alloc_fmr) {
566 dprintk("RPC: %s: MTHCAFMR registration "
567 "not supported by HCA\n", __func__);
568#if RPCRDMA_PERSISTENT_REGISTRATION
569 memreg = RPCRDMA_ALLPHYSICAL;
570#else
Chuck Levercdd9ade2014-05-28 10:33:00 -0400571 rc = -ENOMEM;
Chuck Leverf10eafd2014-05-28 10:32:51 -0400572 goto out2;
573#endif
574 }
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400575 }
576
577 /*
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400578 * Optionally obtain an underlying physical identity mapping in
579 * order to do a memory window-based bind. This base registration
580 * is protected from remote access - that is enabled only by binding
581 * for the specific bytes targeted during each RPC operation, and
582 * revoked after the corresponding completion similar to a storage
583 * adapter.
584 */
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400585 switch (memreg) {
Tom Talpey3197d3092008-10-09 15:00:20 -0400586 case RPCRDMA_FRMR:
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400587 break;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400588#if RPCRDMA_PERSISTENT_REGISTRATION
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400589 case RPCRDMA_ALLPHYSICAL:
590 mem_priv = IB_ACCESS_LOCAL_WRITE |
591 IB_ACCESS_REMOTE_WRITE |
592 IB_ACCESS_REMOTE_READ;
593 goto register_setup;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400594#endif
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400595 case RPCRDMA_MTHCAFMR:
596 if (ia->ri_have_dma_lkey)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400597 break;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400598 mem_priv = IB_ACCESS_LOCAL_WRITE;
Chuck Leverb45ccfd2014-05-28 10:32:34 -0400599#if RPCRDMA_PERSISTENT_REGISTRATION
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400600 register_setup:
Chuck Leverb45ccfd2014-05-28 10:32:34 -0400601#endif
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400602 ia->ri_bind_mem = ib_get_dma_mr(ia->ri_pd, mem_priv);
603 if (IS_ERR(ia->ri_bind_mem)) {
604 printk(KERN_ALERT "%s: ib_get_dma_mr for "
Chuck Lever0ac531c2014-05-28 10:32:43 -0400605 "phys register failed with %lX\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400606 __func__, PTR_ERR(ia->ri_bind_mem));
Chuck Lever0ac531c2014-05-28 10:32:43 -0400607 rc = -ENOMEM;
608 goto out2;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400609 }
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400610 break;
611 default:
Chuck Levercdd9ade2014-05-28 10:33:00 -0400612 printk(KERN_ERR "RPC: Unsupported memory "
613 "registration mode: %d\n", memreg);
614 rc = -ENOMEM;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400615 goto out2;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400616 }
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400617 dprintk("RPC: %s: memory registration strategy is %d\n",
618 __func__, memreg);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400619
620 /* Else will do memory reg/dereg for each chunk */
621 ia->ri_memreg_strategy = memreg;
622
Chuck Lever73806c82014-07-29 17:23:25 -0400623 rwlock_init(&ia->ri_qplock);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400624 return 0;
625out2:
626 rdma_destroy_id(ia->ri_id);
Tom Talpeyfee08ca2008-10-09 15:01:00 -0400627 ia->ri_id = NULL;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400628out1:
629 return rc;
630}
631
632/*
633 * Clean up/close an IA.
634 * o if event handles and PD have been initialized, free them.
635 * o close the IA
636 */
637void
638rpcrdma_ia_close(struct rpcrdma_ia *ia)
639{
640 int rc;
641
642 dprintk("RPC: %s: entering\n", __func__);
643 if (ia->ri_bind_mem != NULL) {
644 rc = ib_dereg_mr(ia->ri_bind_mem);
645 dprintk("RPC: %s: ib_dereg_mr returned %i\n",
646 __func__, rc);
647 }
Tom Talpeyfee08ca2008-10-09 15:01:00 -0400648 if (ia->ri_id != NULL && !IS_ERR(ia->ri_id)) {
649 if (ia->ri_id->qp)
650 rdma_destroy_qp(ia->ri_id);
651 rdma_destroy_id(ia->ri_id);
652 ia->ri_id = NULL;
653 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400654 if (ia->ri_pd != NULL && !IS_ERR(ia->ri_pd)) {
655 rc = ib_dealloc_pd(ia->ri_pd);
656 dprintk("RPC: %s: ib_dealloc_pd returned %i\n",
657 __func__, rc);
658 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400659}
660
661/*
662 * Create unconnected endpoint.
663 */
664int
665rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
666 struct rpcrdma_create_data_internal *cdata)
667{
668 struct ib_device_attr devattr;
Chuck Leverfc664482014-05-28 10:33:25 -0400669 struct ib_cq *sendcq, *recvcq;
Chuck Lever5d40a8a2007-10-26 13:30:54 -0400670 int rc, err;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400671
672 rc = ib_query_device(ia->ri_id->device, &devattr);
673 if (rc) {
674 dprintk("RPC: %s: ib_query_device failed %d\n",
675 __func__, rc);
676 return rc;
677 }
678
679 /* check provider's send/recv wr limits */
680 if (cdata->max_requests > devattr.max_qp_wr)
681 cdata->max_requests = devattr.max_qp_wr;
682
683 ep->rep_attr.event_handler = rpcrdma_qp_async_error_upcall;
684 ep->rep_attr.qp_context = ep;
685 /* send_cq and recv_cq initialized below */
686 ep->rep_attr.srq = NULL;
687 ep->rep_attr.cap.max_send_wr = cdata->max_requests;
688 switch (ia->ri_memreg_strategy) {
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400689 case RPCRDMA_FRMR: {
690 int depth = 7;
691
Tom Tucker15cdc6442010-08-11 12:47:24 -0400692 /* Add room for frmr register and invalidate WRs.
693 * 1. FRMR reg WR for head
694 * 2. FRMR invalidate WR for head
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400695 * 3. N FRMR reg WRs for pagelist
696 * 4. N FRMR invalidate WRs for pagelist
Tom Tucker15cdc6442010-08-11 12:47:24 -0400697 * 5. FRMR reg WR for tail
698 * 6. FRMR invalidate WR for tail
699 * 7. The RDMA_SEND WR
700 */
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400701
702 /* Calculate N if the device max FRMR depth is smaller than
703 * RPCRDMA_MAX_DATA_SEGS.
704 */
705 if (ia->ri_max_frmr_depth < RPCRDMA_MAX_DATA_SEGS) {
706 int delta = RPCRDMA_MAX_DATA_SEGS -
707 ia->ri_max_frmr_depth;
708
709 do {
710 depth += 2; /* FRMR reg + invalidate */
711 delta -= ia->ri_max_frmr_depth;
712 } while (delta > 0);
713
714 }
715 ep->rep_attr.cap.max_send_wr *= depth;
Tom Tucker15cdc6442010-08-11 12:47:24 -0400716 if (ep->rep_attr.cap.max_send_wr > devattr.max_qp_wr) {
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400717 cdata->max_requests = devattr.max_qp_wr / depth;
Tom Tucker15cdc6442010-08-11 12:47:24 -0400718 if (!cdata->max_requests)
719 return -EINVAL;
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400720 ep->rep_attr.cap.max_send_wr = cdata->max_requests *
721 depth;
Tom Tucker15cdc6442010-08-11 12:47:24 -0400722 }
Tom Talpey3197d3092008-10-09 15:00:20 -0400723 break;
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400724 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400725 default:
726 break;
727 }
728 ep->rep_attr.cap.max_recv_wr = cdata->max_requests;
729 ep->rep_attr.cap.max_send_sge = (cdata->padding ? 4 : 2);
730 ep->rep_attr.cap.max_recv_sge = 1;
731 ep->rep_attr.cap.max_inline_data = 0;
732 ep->rep_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
733 ep->rep_attr.qp_type = IB_QPT_RC;
734 ep->rep_attr.port_num = ~0;
735
736 dprintk("RPC: %s: requested max: dtos: send %d recv %d; "
737 "iovs: send %d recv %d\n",
738 __func__,
739 ep->rep_attr.cap.max_send_wr,
740 ep->rep_attr.cap.max_recv_wr,
741 ep->rep_attr.cap.max_send_sge,
742 ep->rep_attr.cap.max_recv_sge);
743
744 /* set trigger for requesting send completion */
Chuck Leverfc664482014-05-28 10:33:25 -0400745 ep->rep_cqinit = ep->rep_attr.cap.max_send_wr/2 - 1;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400746 if (ep->rep_cqinit <= 2)
747 ep->rep_cqinit = 0;
748 INIT_CQCOUNT(ep);
749 ep->rep_ia = ia;
750 init_waitqueue_head(&ep->rep_connect_wait);
Chuck Lever254f91e2014-05-28 10:32:17 -0400751 INIT_DELAYED_WORK(&ep->rep_connect_worker, rpcrdma_connect_worker);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400752
Chuck Leverfc664482014-05-28 10:33:25 -0400753 sendcq = ib_create_cq(ia->ri_id->device, rpcrdma_sendcq_upcall,
Chuck Lever1c00dd02014-05-28 10:33:42 -0400754 rpcrdma_cq_async_error_upcall, ep,
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400755 ep->rep_attr.cap.max_send_wr + 1, 0);
Chuck Leverfc664482014-05-28 10:33:25 -0400756 if (IS_ERR(sendcq)) {
757 rc = PTR_ERR(sendcq);
758 dprintk("RPC: %s: failed to create send CQ: %i\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400759 __func__, rc);
760 goto out1;
761 }
762
Chuck Leverfc664482014-05-28 10:33:25 -0400763 rc = ib_req_notify_cq(sendcq, IB_CQ_NEXT_COMP);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400764 if (rc) {
765 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
766 __func__, rc);
767 goto out2;
768 }
769
Chuck Leverfc664482014-05-28 10:33:25 -0400770 recvcq = ib_create_cq(ia->ri_id->device, rpcrdma_recvcq_upcall,
Chuck Lever1c00dd02014-05-28 10:33:42 -0400771 rpcrdma_cq_async_error_upcall, ep,
Chuck Leverfc664482014-05-28 10:33:25 -0400772 ep->rep_attr.cap.max_recv_wr + 1, 0);
773 if (IS_ERR(recvcq)) {
774 rc = PTR_ERR(recvcq);
775 dprintk("RPC: %s: failed to create recv CQ: %i\n",
776 __func__, rc);
777 goto out2;
778 }
779
780 rc = ib_req_notify_cq(recvcq, IB_CQ_NEXT_COMP);
781 if (rc) {
782 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
783 __func__, rc);
784 ib_destroy_cq(recvcq);
785 goto out2;
786 }
787
788 ep->rep_attr.send_cq = sendcq;
789 ep->rep_attr.recv_cq = recvcq;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400790
791 /* Initialize cma parameters */
792
793 /* RPC/RDMA does not use private data */
794 ep->rep_remote_cma.private_data = NULL;
795 ep->rep_remote_cma.private_data_len = 0;
796
797 /* Client offers RDMA Read but does not initiate */
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400798 ep->rep_remote_cma.initiator_depth = 0;
Chuck Lever03ff8822014-05-28 10:32:26 -0400799 if (devattr.max_qp_rd_atom > 32) /* arbitrary but <= 255 */
Tom Tuckerb334eaa2008-10-09 15:00:30 -0400800 ep->rep_remote_cma.responder_resources = 32;
801 else
802 ep->rep_remote_cma.responder_resources = devattr.max_qp_rd_atom;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400803
804 ep->rep_remote_cma.retry_count = 7;
805 ep->rep_remote_cma.flow_control = 0;
806 ep->rep_remote_cma.rnr_retry_count = 0;
807
808 return 0;
809
810out2:
Chuck Leverfc664482014-05-28 10:33:25 -0400811 err = ib_destroy_cq(sendcq);
Chuck Lever5d40a8a2007-10-26 13:30:54 -0400812 if (err)
813 dprintk("RPC: %s: ib_destroy_cq returned %i\n",
814 __func__, err);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400815out1:
816 return rc;
817}
818
819/*
820 * rpcrdma_ep_destroy
821 *
822 * Disconnect and destroy endpoint. After this, the only
823 * valid operations on the ep are to free it (if dynamically
824 * allocated) or re-create it.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400825 */
Chuck Lever7f1d5412014-05-28 10:33:16 -0400826void
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400827rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
828{
829 int rc;
830
831 dprintk("RPC: %s: entering, connected is %d\n",
832 __func__, ep->rep_connected);
833
Chuck Lever254f91e2014-05-28 10:32:17 -0400834 cancel_delayed_work_sync(&ep->rep_connect_worker);
835
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400836 if (ia->ri_id->qp) {
837 rc = rpcrdma_ep_disconnect(ep, ia);
838 if (rc)
839 dprintk("RPC: %s: rpcrdma_ep_disconnect"
840 " returned %i\n", __func__, rc);
Tom Talpeyfee08ca2008-10-09 15:01:00 -0400841 rdma_destroy_qp(ia->ri_id);
842 ia->ri_id->qp = NULL;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400843 }
844
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400845 /* padding - could be done in rpcrdma_buffer_destroy... */
846 if (ep->rep_pad_mr) {
847 rpcrdma_deregister_internal(ia, ep->rep_pad_mr, &ep->rep_pad);
848 ep->rep_pad_mr = NULL;
849 }
850
Chuck Leverfc664482014-05-28 10:33:25 -0400851 rpcrdma_clean_cq(ep->rep_attr.recv_cq);
852 rc = ib_destroy_cq(ep->rep_attr.recv_cq);
853 if (rc)
854 dprintk("RPC: %s: ib_destroy_cq returned %i\n",
855 __func__, rc);
856
857 rpcrdma_clean_cq(ep->rep_attr.send_cq);
858 rc = ib_destroy_cq(ep->rep_attr.send_cq);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400859 if (rc)
860 dprintk("RPC: %s: ib_destroy_cq returned %i\n",
861 __func__, rc);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400862}
863
864/*
865 * Connect unconnected endpoint.
866 */
867int
868rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
869{
Chuck Lever73806c82014-07-29 17:23:25 -0400870 struct rdma_cm_id *id, *old;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400871 int rc = 0;
872 int retry_count = 0;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400873
Tom Talpeyc0555512008-10-10 11:32:45 -0400874 if (ep->rep_connected != 0) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400875 struct rpcrdma_xprt *xprt;
876retry:
Chuck Leverec62f402014-05-28 10:34:07 -0400877 dprintk("RPC: %s: reconnecting...\n", __func__);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400878 rc = rpcrdma_ep_disconnect(ep, ia);
879 if (rc && rc != -ENOTCONN)
880 dprintk("RPC: %s: rpcrdma_ep_disconnect"
881 " status %i\n", __func__, rc);
Chuck Levera7bc2112014-07-29 17:23:52 -0400882 rpcrdma_flush_cqs(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400883
884 xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
885 id = rpcrdma_create_id(xprt, ia,
886 (struct sockaddr *)&xprt->rx_data.addr);
887 if (IS_ERR(id)) {
Chuck Leverec62f402014-05-28 10:34:07 -0400888 rc = -EHOSTUNREACH;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400889 goto out;
890 }
891 /* TEMP TEMP TEMP - fail if new device:
892 * Deregister/remarshal *all* requests!
893 * Close and recreate adapter, pd, etc!
894 * Re-determine all attributes still sane!
895 * More stuff I haven't thought of!
896 * Rrrgh!
897 */
898 if (ia->ri_id->device != id->device) {
899 printk("RPC: %s: can't reconnect on "
900 "different device!\n", __func__);
901 rdma_destroy_id(id);
Chuck Leverec62f402014-05-28 10:34:07 -0400902 rc = -ENETUNREACH;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400903 goto out;
904 }
905 /* END TEMP */
Chuck Leverec62f402014-05-28 10:34:07 -0400906 rc = rdma_create_qp(id, ia->ri_pd, &ep->rep_attr);
907 if (rc) {
908 dprintk("RPC: %s: rdma_create_qp failed %i\n",
909 __func__, rc);
910 rdma_destroy_id(id);
911 rc = -ENETUNREACH;
912 goto out;
913 }
Chuck Lever73806c82014-07-29 17:23:25 -0400914
915 write_lock(&ia->ri_qplock);
916 old = ia->ri_id;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400917 ia->ri_id = id;
Chuck Lever73806c82014-07-29 17:23:25 -0400918 write_unlock(&ia->ri_qplock);
919
920 rdma_destroy_qp(old);
921 rdma_destroy_id(old);
Chuck Leverec62f402014-05-28 10:34:07 -0400922 } else {
923 dprintk("RPC: %s: connecting...\n", __func__);
924 rc = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr);
925 if (rc) {
926 dprintk("RPC: %s: rdma_create_qp failed %i\n",
927 __func__, rc);
928 /* do not update ep->rep_connected */
929 return -ENETUNREACH;
930 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400931 }
932
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400933 ep->rep_connected = 0;
934
935 rc = rdma_connect(ia->ri_id, &ep->rep_remote_cma);
936 if (rc) {
937 dprintk("RPC: %s: rdma_connect() failed with %i\n",
938 __func__, rc);
939 goto out;
940 }
941
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400942 wait_event_interruptible(ep->rep_connect_wait, ep->rep_connected != 0);
943
944 /*
945 * Check state. A non-peer reject indicates no listener
946 * (ECONNREFUSED), which may be a transient state. All
947 * others indicate a transport condition which has already
948 * undergone a best-effort.
949 */
Joe Perchesf64f9e72009-11-29 16:55:45 -0800950 if (ep->rep_connected == -ECONNREFUSED &&
951 ++retry_count <= RDMA_CONNECT_RETRY_MAX) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400952 dprintk("RPC: %s: non-peer_reject, retry\n", __func__);
953 goto retry;
954 }
955 if (ep->rep_connected <= 0) {
956 /* Sometimes, the only way to reliably connect to remote
957 * CMs is to use same nonzero values for ORD and IRD. */
Tom Tuckerb334eaa2008-10-09 15:00:30 -0400958 if (retry_count++ <= RDMA_CONNECT_RETRY_MAX + 1 &&
959 (ep->rep_remote_cma.responder_resources == 0 ||
960 ep->rep_remote_cma.initiator_depth !=
961 ep->rep_remote_cma.responder_resources)) {
962 if (ep->rep_remote_cma.responder_resources == 0)
963 ep->rep_remote_cma.responder_resources = 1;
964 ep->rep_remote_cma.initiator_depth =
965 ep->rep_remote_cma.responder_resources;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400966 goto retry;
Tom Tuckerb334eaa2008-10-09 15:00:30 -0400967 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400968 rc = ep->rep_connected;
969 } else {
970 dprintk("RPC: %s: connected\n", __func__);
971 }
972
973out:
974 if (rc)
975 ep->rep_connected = rc;
976 return rc;
977}
978
979/*
980 * rpcrdma_ep_disconnect
981 *
982 * This is separate from destroy to facilitate the ability
983 * to reconnect without recreating the endpoint.
984 *
985 * This call is not reentrant, and must not be made in parallel
986 * on the same endpoint.
987 */
988int
989rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
990{
991 int rc;
992
Chuck Levera7bc2112014-07-29 17:23:52 -0400993 rpcrdma_flush_cqs(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400994 rc = rdma_disconnect(ia->ri_id);
995 if (!rc) {
996 /* returns without wait if not connected */
997 wait_event_interruptible(ep->rep_connect_wait,
998 ep->rep_connected != 1);
999 dprintk("RPC: %s: after wait, %sconnected\n", __func__,
1000 (ep->rep_connected == 1) ? "still " : "dis");
1001 } else {
1002 dprintk("RPC: %s: rdma_disconnect %i\n", __func__, rc);
1003 ep->rep_connected = rc;
1004 }
1005 return rc;
1006}
1007
1008/*
1009 * Initialize buffer memory
1010 */
1011int
1012rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep,
1013 struct rpcrdma_ia *ia, struct rpcrdma_create_data_internal *cdata)
1014{
1015 char *p;
Chuck Lever65866f82014-05-28 10:33:59 -04001016 size_t len, rlen, wlen;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001017 int i, rc;
Tom Talpey8d4ba032008-10-09 14:59:49 -04001018 struct rpcrdma_mw *r;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001019
1020 buf->rb_max_requests = cdata->max_requests;
1021 spin_lock_init(&buf->rb_lock);
1022 atomic_set(&buf->rb_credits, 1);
1023
1024 /* Need to allocate:
1025 * 1. arrays for send and recv pointers
1026 * 2. arrays of struct rpcrdma_req to fill in pointers
1027 * 3. array of struct rpcrdma_rep for replies
1028 * 4. padding, if any
Tom Talpey3197d3092008-10-09 15:00:20 -04001029 * 5. mw's, fmr's or frmr's, if any
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001030 * Send/recv buffers in req/rep need to be registered
1031 */
1032
1033 len = buf->rb_max_requests *
1034 (sizeof(struct rpcrdma_req *) + sizeof(struct rpcrdma_rep *));
1035 len += cdata->padding;
1036 switch (ia->ri_memreg_strategy) {
Tom Talpey3197d3092008-10-09 15:00:20 -04001037 case RPCRDMA_FRMR:
1038 len += buf->rb_max_requests * RPCRDMA_MAX_SEGS *
1039 sizeof(struct rpcrdma_mw);
1040 break;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001041 case RPCRDMA_MTHCAFMR:
1042 /* TBD we are perhaps overallocating here */
1043 len += (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS *
1044 sizeof(struct rpcrdma_mw);
1045 break;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001046 default:
1047 break;
1048 }
1049
1050 /* allocate 1, 4 and 5 in one shot */
1051 p = kzalloc(len, GFP_KERNEL);
1052 if (p == NULL) {
1053 dprintk("RPC: %s: req_t/rep_t/pad kzalloc(%zd) failed\n",
1054 __func__, len);
1055 rc = -ENOMEM;
1056 goto out;
1057 }
1058 buf->rb_pool = p; /* for freeing it later */
1059
1060 buf->rb_send_bufs = (struct rpcrdma_req **) p;
1061 p = (char *) &buf->rb_send_bufs[buf->rb_max_requests];
1062 buf->rb_recv_bufs = (struct rpcrdma_rep **) p;
1063 p = (char *) &buf->rb_recv_bufs[buf->rb_max_requests];
1064
1065 /*
1066 * Register the zeroed pad buffer, if any.
1067 */
1068 if (cdata->padding) {
1069 rc = rpcrdma_register_internal(ia, p, cdata->padding,
1070 &ep->rep_pad_mr, &ep->rep_pad);
1071 if (rc)
1072 goto out;
1073 }
1074 p += cdata->padding;
1075
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001076 INIT_LIST_HEAD(&buf->rb_mws);
Tom Talpey8d4ba032008-10-09 14:59:49 -04001077 r = (struct rpcrdma_mw *)p;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001078 switch (ia->ri_memreg_strategy) {
Tom Talpey3197d3092008-10-09 15:00:20 -04001079 case RPCRDMA_FRMR:
1080 for (i = buf->rb_max_requests * RPCRDMA_MAX_SEGS; i; i--) {
1081 r->r.frmr.fr_mr = ib_alloc_fast_reg_mr(ia->ri_pd,
Steve Wise0fc6c4e2014-05-28 10:32:00 -04001082 ia->ri_max_frmr_depth);
Tom Talpey3197d3092008-10-09 15:00:20 -04001083 if (IS_ERR(r->r.frmr.fr_mr)) {
1084 rc = PTR_ERR(r->r.frmr.fr_mr);
1085 dprintk("RPC: %s: ib_alloc_fast_reg_mr"
1086 " failed %i\n", __func__, rc);
1087 goto out;
1088 }
Steve Wise0fc6c4e2014-05-28 10:32:00 -04001089 r->r.frmr.fr_pgl = ib_alloc_fast_reg_page_list(
1090 ia->ri_id->device,
1091 ia->ri_max_frmr_depth);
Tom Talpey3197d3092008-10-09 15:00:20 -04001092 if (IS_ERR(r->r.frmr.fr_pgl)) {
1093 rc = PTR_ERR(r->r.frmr.fr_pgl);
1094 dprintk("RPC: %s: "
1095 "ib_alloc_fast_reg_page_list "
1096 "failed %i\n", __func__, rc);
Allen Andrews4034ba02014-05-28 10:32:09 -04001097
1098 ib_dereg_mr(r->r.frmr.fr_mr);
Tom Talpey3197d3092008-10-09 15:00:20 -04001099 goto out;
1100 }
1101 list_add(&r->mw_list, &buf->rb_mws);
1102 ++r;
1103 }
1104 break;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001105 case RPCRDMA_MTHCAFMR:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001106 /* TBD we are perhaps overallocating here */
1107 for (i = (buf->rb_max_requests+1) * RPCRDMA_MAX_SEGS; i; i--) {
Tom Talpey8d4ba032008-10-09 14:59:49 -04001108 static struct ib_fmr_attr fa =
1109 { RPCRDMA_MAX_DATA_SEGS, 1, PAGE_SHIFT };
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001110 r->r.fmr = ib_alloc_fmr(ia->ri_pd,
1111 IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ,
1112 &fa);
1113 if (IS_ERR(r->r.fmr)) {
1114 rc = PTR_ERR(r->r.fmr);
1115 dprintk("RPC: %s: ib_alloc_fmr"
1116 " failed %i\n", __func__, rc);
1117 goto out;
1118 }
1119 list_add(&r->mw_list, &buf->rb_mws);
1120 ++r;
1121 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001122 break;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001123 default:
1124 break;
1125 }
1126
1127 /*
1128 * Allocate/init the request/reply buffers. Doing this
1129 * using kmalloc for now -- one for each buf.
1130 */
Chuck Lever65866f82014-05-28 10:33:59 -04001131 wlen = 1 << fls(cdata->inline_wsize + sizeof(struct rpcrdma_req));
1132 rlen = 1 << fls(cdata->inline_rsize + sizeof(struct rpcrdma_rep));
1133 dprintk("RPC: %s: wlen = %zu, rlen = %zu\n",
1134 __func__, wlen, rlen);
1135
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001136 for (i = 0; i < buf->rb_max_requests; i++) {
1137 struct rpcrdma_req *req;
1138 struct rpcrdma_rep *rep;
1139
Chuck Lever65866f82014-05-28 10:33:59 -04001140 req = kmalloc(wlen, GFP_KERNEL);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001141 if (req == NULL) {
1142 dprintk("RPC: %s: request buffer %d alloc"
1143 " failed\n", __func__, i);
1144 rc = -ENOMEM;
1145 goto out;
1146 }
1147 memset(req, 0, sizeof(struct rpcrdma_req));
1148 buf->rb_send_bufs[i] = req;
1149 buf->rb_send_bufs[i]->rl_buffer = buf;
1150
1151 rc = rpcrdma_register_internal(ia, req->rl_base,
Chuck Lever65866f82014-05-28 10:33:59 -04001152 wlen - offsetof(struct rpcrdma_req, rl_base),
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001153 &buf->rb_send_bufs[i]->rl_handle,
1154 &buf->rb_send_bufs[i]->rl_iov);
1155 if (rc)
1156 goto out;
1157
Chuck Lever65866f82014-05-28 10:33:59 -04001158 buf->rb_send_bufs[i]->rl_size = wlen -
1159 sizeof(struct rpcrdma_req);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001160
Chuck Lever65866f82014-05-28 10:33:59 -04001161 rep = kmalloc(rlen, GFP_KERNEL);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001162 if (rep == NULL) {
1163 dprintk("RPC: %s: reply buffer %d alloc failed\n",
1164 __func__, i);
1165 rc = -ENOMEM;
1166 goto out;
1167 }
1168 memset(rep, 0, sizeof(struct rpcrdma_rep));
1169 buf->rb_recv_bufs[i] = rep;
1170 buf->rb_recv_bufs[i]->rr_buffer = buf;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001171
1172 rc = rpcrdma_register_internal(ia, rep->rr_base,
Chuck Lever65866f82014-05-28 10:33:59 -04001173 rlen - offsetof(struct rpcrdma_rep, rr_base),
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001174 &buf->rb_recv_bufs[i]->rr_handle,
1175 &buf->rb_recv_bufs[i]->rr_iov);
1176 if (rc)
1177 goto out;
1178
1179 }
1180 dprintk("RPC: %s: max_requests %d\n",
1181 __func__, buf->rb_max_requests);
1182 /* done */
1183 return 0;
1184out:
1185 rpcrdma_buffer_destroy(buf);
1186 return rc;
1187}
1188
1189/*
1190 * Unregister and destroy buffer memory. Need to deal with
1191 * partial initialization, so it's callable from failed create.
1192 * Must be called before destroying endpoint, as registrations
1193 * reference it.
1194 */
1195void
1196rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
1197{
1198 int rc, i;
1199 struct rpcrdma_ia *ia = rdmab_to_ia(buf);
Tom Talpey8d4ba032008-10-09 14:59:49 -04001200 struct rpcrdma_mw *r;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001201
1202 /* clean up in reverse order from create
1203 * 1. recv mr memory (mr free, then kfree)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001204 * 2. send mr memory (mr free, then kfree)
1205 * 3. padding (if any) [moved to rpcrdma_ep_destroy]
1206 * 4. arrays
1207 */
1208 dprintk("RPC: %s: entering\n", __func__);
1209
1210 for (i = 0; i < buf->rb_max_requests; i++) {
1211 if (buf->rb_recv_bufs && buf->rb_recv_bufs[i]) {
1212 rpcrdma_deregister_internal(ia,
1213 buf->rb_recv_bufs[i]->rr_handle,
1214 &buf->rb_recv_bufs[i]->rr_iov);
1215 kfree(buf->rb_recv_bufs[i]);
1216 }
1217 if (buf->rb_send_bufs && buf->rb_send_bufs[i]) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001218 rpcrdma_deregister_internal(ia,
1219 buf->rb_send_bufs[i]->rl_handle,
1220 &buf->rb_send_bufs[i]->rl_iov);
1221 kfree(buf->rb_send_bufs[i]);
1222 }
1223 }
1224
Allen Andrews4034ba02014-05-28 10:32:09 -04001225 while (!list_empty(&buf->rb_mws)) {
1226 r = list_entry(buf->rb_mws.next,
1227 struct rpcrdma_mw, mw_list);
1228 list_del(&r->mw_list);
1229 switch (ia->ri_memreg_strategy) {
1230 case RPCRDMA_FRMR:
1231 rc = ib_dereg_mr(r->r.frmr.fr_mr);
1232 if (rc)
1233 dprintk("RPC: %s:"
1234 " ib_dereg_mr"
1235 " failed %i\n",
1236 __func__, rc);
1237 ib_free_fast_reg_page_list(r->r.frmr.fr_pgl);
1238 break;
1239 case RPCRDMA_MTHCAFMR:
1240 rc = ib_dealloc_fmr(r->r.fmr);
1241 if (rc)
1242 dprintk("RPC: %s:"
1243 " ib_dealloc_fmr"
1244 " failed %i\n",
1245 __func__, rc);
1246 break;
Allen Andrews4034ba02014-05-28 10:32:09 -04001247 default:
1248 break;
1249 }
1250 }
1251
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001252 kfree(buf->rb_pool);
1253}
1254
1255/*
1256 * Get a set of request/reply buffers.
1257 *
1258 * Reply buffer (if needed) is attached to send buffer upon return.
1259 * Rule:
1260 * rb_send_index and rb_recv_index MUST always be pointing to the
1261 * *next* available buffer (non-NULL). They are incremented after
1262 * removing buffers, and decremented *before* returning them.
1263 */
1264struct rpcrdma_req *
1265rpcrdma_buffer_get(struct rpcrdma_buffer *buffers)
1266{
1267 struct rpcrdma_req *req;
1268 unsigned long flags;
Tom Talpey8d4ba032008-10-09 14:59:49 -04001269 int i;
1270 struct rpcrdma_mw *r;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001271
1272 spin_lock_irqsave(&buffers->rb_lock, flags);
1273 if (buffers->rb_send_index == buffers->rb_max_requests) {
1274 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1275 dprintk("RPC: %s: out of request buffers\n", __func__);
1276 return ((struct rpcrdma_req *)NULL);
1277 }
1278
1279 req = buffers->rb_send_bufs[buffers->rb_send_index];
1280 if (buffers->rb_send_index < buffers->rb_recv_index) {
1281 dprintk("RPC: %s: %d extra receives outstanding (ok)\n",
1282 __func__,
1283 buffers->rb_recv_index - buffers->rb_send_index);
1284 req->rl_reply = NULL;
1285 } else {
1286 req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
1287 buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
1288 }
1289 buffers->rb_send_bufs[buffers->rb_send_index++] = NULL;
1290 if (!list_empty(&buffers->rb_mws)) {
Tom Talpey8d4ba032008-10-09 14:59:49 -04001291 i = RPCRDMA_MAX_SEGS - 1;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001292 do {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001293 r = list_entry(buffers->rb_mws.next,
1294 struct rpcrdma_mw, mw_list);
1295 list_del(&r->mw_list);
1296 req->rl_segments[i].mr_chunk.rl_mw = r;
1297 } while (--i >= 0);
1298 }
1299 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1300 return req;
1301}
1302
1303/*
1304 * Put request/reply buffers back into pool.
1305 * Pre-decrement counter/array index.
1306 */
1307void
1308rpcrdma_buffer_put(struct rpcrdma_req *req)
1309{
1310 struct rpcrdma_buffer *buffers = req->rl_buffer;
1311 struct rpcrdma_ia *ia = rdmab_to_ia(buffers);
1312 int i;
1313 unsigned long flags;
1314
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001315 spin_lock_irqsave(&buffers->rb_lock, flags);
1316 buffers->rb_send_bufs[--buffers->rb_send_index] = req;
1317 req->rl_niovs = 0;
1318 if (req->rl_reply) {
1319 buffers->rb_recv_bufs[--buffers->rb_recv_index] = req->rl_reply;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001320 req->rl_reply->rr_func = NULL;
1321 req->rl_reply = NULL;
1322 }
1323 switch (ia->ri_memreg_strategy) {
Tom Talpey3197d3092008-10-09 15:00:20 -04001324 case RPCRDMA_FRMR:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001325 case RPCRDMA_MTHCAFMR:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001326 /*
1327 * Cycle mw's back in reverse order, and "spin" them.
1328 * This delays and scrambles reuse as much as possible.
1329 */
1330 i = 1;
1331 do {
1332 struct rpcrdma_mw **mw;
1333 mw = &req->rl_segments[i].mr_chunk.rl_mw;
1334 list_add_tail(&(*mw)->mw_list, &buffers->rb_mws);
1335 *mw = NULL;
1336 } while (++i < RPCRDMA_MAX_SEGS);
1337 list_add_tail(&req->rl_segments[0].mr_chunk.rl_mw->mw_list,
1338 &buffers->rb_mws);
1339 req->rl_segments[0].mr_chunk.rl_mw = NULL;
1340 break;
1341 default:
1342 break;
1343 }
1344 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1345}
1346
1347/*
1348 * Recover reply buffers from pool.
1349 * This happens when recovering from error conditions.
1350 * Post-increment counter/array index.
1351 */
1352void
1353rpcrdma_recv_buffer_get(struct rpcrdma_req *req)
1354{
1355 struct rpcrdma_buffer *buffers = req->rl_buffer;
1356 unsigned long flags;
1357
1358 if (req->rl_iov.length == 0) /* special case xprt_rdma_allocate() */
1359 buffers = ((struct rpcrdma_req *) buffers)->rl_buffer;
1360 spin_lock_irqsave(&buffers->rb_lock, flags);
1361 if (buffers->rb_recv_index < buffers->rb_max_requests) {
1362 req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
1363 buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
1364 }
1365 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1366}
1367
1368/*
1369 * Put reply buffers back into pool when not attached to
Chuck Leverb45ccfd2014-05-28 10:32:34 -04001370 * request. This happens in error conditions.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001371 */
1372void
1373rpcrdma_recv_buffer_put(struct rpcrdma_rep *rep)
1374{
1375 struct rpcrdma_buffer *buffers = rep->rr_buffer;
1376 unsigned long flags;
1377
1378 rep->rr_func = NULL;
1379 spin_lock_irqsave(&buffers->rb_lock, flags);
1380 buffers->rb_recv_bufs[--buffers->rb_recv_index] = rep;
1381 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1382}
1383
1384/*
1385 * Wrappers for internal-use kmalloc memory registration, used by buffer code.
1386 */
1387
1388int
1389rpcrdma_register_internal(struct rpcrdma_ia *ia, void *va, int len,
1390 struct ib_mr **mrp, struct ib_sge *iov)
1391{
1392 struct ib_phys_buf ipb;
1393 struct ib_mr *mr;
1394 int rc;
1395
1396 /*
1397 * All memory passed here was kmalloc'ed, therefore phys-contiguous.
1398 */
1399 iov->addr = ib_dma_map_single(ia->ri_id->device,
1400 va, len, DMA_BIDIRECTIONAL);
Yan Burmanbf858ab2014-06-19 16:06:30 +03001401 if (ib_dma_mapping_error(ia->ri_id->device, iov->addr))
1402 return -ENOMEM;
1403
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001404 iov->length = len;
1405
Tom Talpeybd7ed1d2008-10-09 15:00:09 -04001406 if (ia->ri_have_dma_lkey) {
1407 *mrp = NULL;
1408 iov->lkey = ia->ri_dma_lkey;
1409 return 0;
1410 } else if (ia->ri_bind_mem != NULL) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001411 *mrp = NULL;
1412 iov->lkey = ia->ri_bind_mem->lkey;
1413 return 0;
1414 }
1415
1416 ipb.addr = iov->addr;
1417 ipb.size = iov->length;
1418 mr = ib_reg_phys_mr(ia->ri_pd, &ipb, 1,
1419 IB_ACCESS_LOCAL_WRITE, &iov->addr);
1420
1421 dprintk("RPC: %s: phys convert: 0x%llx "
1422 "registered 0x%llx length %d\n",
Andrew Mortona56daeb2007-10-16 01:29:57 -07001423 __func__, (unsigned long long)ipb.addr,
1424 (unsigned long long)iov->addr, len);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001425
1426 if (IS_ERR(mr)) {
1427 *mrp = NULL;
1428 rc = PTR_ERR(mr);
1429 dprintk("RPC: %s: failed with %i\n", __func__, rc);
1430 } else {
1431 *mrp = mr;
1432 iov->lkey = mr->lkey;
1433 rc = 0;
1434 }
1435
1436 return rc;
1437}
1438
1439int
1440rpcrdma_deregister_internal(struct rpcrdma_ia *ia,
1441 struct ib_mr *mr, struct ib_sge *iov)
1442{
1443 int rc;
1444
1445 ib_dma_unmap_single(ia->ri_id->device,
1446 iov->addr, iov->length, DMA_BIDIRECTIONAL);
1447
1448 if (NULL == mr)
1449 return 0;
1450
1451 rc = ib_dereg_mr(mr);
1452 if (rc)
1453 dprintk("RPC: %s: ib_dereg_mr failed %i\n", __func__, rc);
1454 return rc;
1455}
1456
1457/*
1458 * Wrappers for chunk registration, shared by read/write chunk code.
1459 */
1460
1461static void
1462rpcrdma_map_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg, int writing)
1463{
1464 seg->mr_dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
1465 seg->mr_dmalen = seg->mr_len;
1466 if (seg->mr_page)
1467 seg->mr_dma = ib_dma_map_page(ia->ri_id->device,
1468 seg->mr_page, offset_in_page(seg->mr_offset),
1469 seg->mr_dmalen, seg->mr_dir);
1470 else
1471 seg->mr_dma = ib_dma_map_single(ia->ri_id->device,
1472 seg->mr_offset,
1473 seg->mr_dmalen, seg->mr_dir);
Tom Tucker5c635e02011-02-09 19:45:34 +00001474 if (ib_dma_mapping_error(ia->ri_id->device, seg->mr_dma)) {
1475 dprintk("RPC: %s: mr_dma %llx mr_offset %p mr_dma_len %zu\n",
1476 __func__,
Randy Dunlap986d4ab2011-03-15 17:11:59 -07001477 (unsigned long long)seg->mr_dma,
1478 seg->mr_offset, seg->mr_dmalen);
Tom Tucker5c635e02011-02-09 19:45:34 +00001479 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001480}
1481
1482static void
1483rpcrdma_unmap_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg)
1484{
1485 if (seg->mr_page)
1486 ib_dma_unmap_page(ia->ri_id->device,
1487 seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
1488 else
1489 ib_dma_unmap_single(ia->ri_id->device,
1490 seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
1491}
1492
Tom Talpey8d4ba032008-10-09 14:59:49 -04001493static int
Tom Talpey3197d3092008-10-09 15:00:20 -04001494rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
1495 int *nsegs, int writing, struct rpcrdma_ia *ia,
1496 struct rpcrdma_xprt *r_xprt)
1497{
1498 struct rpcrdma_mr_seg *seg1 = seg;
Tom Tucker5c635e02011-02-09 19:45:34 +00001499 struct ib_send_wr invalidate_wr, frmr_wr, *bad_wr, *post_wr;
1500
Tom Talpey3197d3092008-10-09 15:00:20 -04001501 u8 key;
1502 int len, pageoff;
1503 int i, rc;
Tom Tucker9b781452012-02-20 13:07:57 -06001504 int seg_len;
1505 u64 pa;
1506 int page_no;
Tom Talpey3197d3092008-10-09 15:00:20 -04001507
1508 pageoff = offset_in_page(seg1->mr_offset);
1509 seg1->mr_offset -= pageoff; /* start of page */
1510 seg1->mr_len += pageoff;
1511 len = -pageoff;
Steve Wise0fc6c4e2014-05-28 10:32:00 -04001512 if (*nsegs > ia->ri_max_frmr_depth)
1513 *nsegs = ia->ri_max_frmr_depth;
Tom Tucker9b781452012-02-20 13:07:57 -06001514 for (page_no = i = 0; i < *nsegs;) {
Tom Talpey3197d3092008-10-09 15:00:20 -04001515 rpcrdma_map_one(ia, seg, writing);
Tom Tucker9b781452012-02-20 13:07:57 -06001516 pa = seg->mr_dma;
1517 for (seg_len = seg->mr_len; seg_len > 0; seg_len -= PAGE_SIZE) {
1518 seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->
1519 page_list[page_no++] = pa;
1520 pa += PAGE_SIZE;
1521 }
Tom Talpey3197d3092008-10-09 15:00:20 -04001522 len += seg->mr_len;
1523 ++seg;
1524 ++i;
1525 /* Check for holes */
1526 if ((i < *nsegs && offset_in_page(seg->mr_offset)) ||
1527 offset_in_page((seg-1)->mr_offset + (seg-1)->mr_len))
1528 break;
1529 }
1530 dprintk("RPC: %s: Using frmr %p to map %d segments\n",
1531 __func__, seg1->mr_chunk.rl_mw, i);
1532
Tom Tucker5c635e02011-02-09 19:45:34 +00001533 if (unlikely(seg1->mr_chunk.rl_mw->r.frmr.state == FRMR_IS_VALID)) {
1534 dprintk("RPC: %s: frmr %x left valid, posting invalidate.\n",
1535 __func__,
1536 seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey);
1537 /* Invalidate before using. */
1538 memset(&invalidate_wr, 0, sizeof invalidate_wr);
1539 invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw;
1540 invalidate_wr.next = &frmr_wr;
1541 invalidate_wr.opcode = IB_WR_LOCAL_INV;
1542 invalidate_wr.send_flags = IB_SEND_SIGNALED;
1543 invalidate_wr.ex.invalidate_rkey =
1544 seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey;
1545 DECR_CQCOUNT(&r_xprt->rx_ep);
1546 post_wr = &invalidate_wr;
1547 } else
1548 post_wr = &frmr_wr;
1549
Tom Talpey3197d3092008-10-09 15:00:20 -04001550 /* Prepare FRMR WR */
1551 memset(&frmr_wr, 0, sizeof frmr_wr);
Tom Tucker5c635e02011-02-09 19:45:34 +00001552 frmr_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw;
Tom Talpey3197d3092008-10-09 15:00:20 -04001553 frmr_wr.opcode = IB_WR_FAST_REG_MR;
Tom Tucker5c635e02011-02-09 19:45:34 +00001554 frmr_wr.send_flags = IB_SEND_SIGNALED;
Steve Wise7a8b80eb2010-08-11 12:47:08 -04001555 frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma;
Tom Talpey3197d3092008-10-09 15:00:20 -04001556 frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl;
Tom Tucker9b781452012-02-20 13:07:57 -06001557 frmr_wr.wr.fast_reg.page_list_len = page_no;
Tom Talpey3197d3092008-10-09 15:00:20 -04001558 frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
Tom Tucker9b781452012-02-20 13:07:57 -06001559 frmr_wr.wr.fast_reg.length = page_no << PAGE_SHIFT;
Chuck Leverc977dea2014-05-28 10:35:06 -04001560 if (frmr_wr.wr.fast_reg.length < len) {
Chuck Lever5fc83f42014-07-29 17:23:17 -04001561 rc = -EIO;
1562 goto out_err;
Chuck Leverc977dea2014-05-28 10:35:06 -04001563 }
1564
1565 /* Bump the key */
1566 key = (u8)(seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey & 0x000000FF);
1567 ib_update_fast_reg_key(seg1->mr_chunk.rl_mw->r.frmr.fr_mr, ++key);
1568
Tom Talpey3197d3092008-10-09 15:00:20 -04001569 frmr_wr.wr.fast_reg.access_flags = (writing ?
Vu Pham68743082009-05-26 14:51:00 -04001570 IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
1571 IB_ACCESS_REMOTE_READ);
Tom Talpey3197d3092008-10-09 15:00:20 -04001572 frmr_wr.wr.fast_reg.rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey;
1573 DECR_CQCOUNT(&r_xprt->rx_ep);
1574
Tom Tucker5c635e02011-02-09 19:45:34 +00001575 rc = ib_post_send(ia->ri_id->qp, post_wr, &bad_wr);
Tom Talpey3197d3092008-10-09 15:00:20 -04001576
1577 if (rc) {
1578 dprintk("RPC: %s: failed ib_post_send for register,"
1579 " status %i\n", __func__, rc);
Chuck Lever5fc83f42014-07-29 17:23:17 -04001580 goto out_err;
Tom Talpey3197d3092008-10-09 15:00:20 -04001581 } else {
1582 seg1->mr_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey;
1583 seg1->mr_base = seg1->mr_dma + pageoff;
1584 seg1->mr_nsegs = i;
1585 seg1->mr_len = len;
1586 }
1587 *nsegs = i;
Chuck Lever5fc83f42014-07-29 17:23:17 -04001588 return 0;
1589out_err:
1590 while (i--)
1591 rpcrdma_unmap_one(ia, --seg);
Tom Talpey3197d3092008-10-09 15:00:20 -04001592 return rc;
1593}
1594
1595static int
1596rpcrdma_deregister_frmr_external(struct rpcrdma_mr_seg *seg,
1597 struct rpcrdma_ia *ia, struct rpcrdma_xprt *r_xprt)
1598{
1599 struct rpcrdma_mr_seg *seg1 = seg;
1600 struct ib_send_wr invalidate_wr, *bad_wr;
1601 int rc;
1602
Tom Talpey3197d3092008-10-09 15:00:20 -04001603 memset(&invalidate_wr, 0, sizeof invalidate_wr);
Tom Tucker5c635e02011-02-09 19:45:34 +00001604 invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw;
Tom Talpey3197d3092008-10-09 15:00:20 -04001605 invalidate_wr.opcode = IB_WR_LOCAL_INV;
Tom Tucker5c635e02011-02-09 19:45:34 +00001606 invalidate_wr.send_flags = IB_SEND_SIGNALED;
Tom Talpey3197d3092008-10-09 15:00:20 -04001607 invalidate_wr.ex.invalidate_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey;
1608 DECR_CQCOUNT(&r_xprt->rx_ep);
1609
Chuck Lever73806c82014-07-29 17:23:25 -04001610 read_lock(&ia->ri_qplock);
1611 while (seg1->mr_nsegs--)
1612 rpcrdma_unmap_one(ia, seg++);
Tom Talpey3197d3092008-10-09 15:00:20 -04001613 rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr);
Chuck Lever73806c82014-07-29 17:23:25 -04001614 read_unlock(&ia->ri_qplock);
Tom Talpey3197d3092008-10-09 15:00:20 -04001615 if (rc)
1616 dprintk("RPC: %s: failed ib_post_send for invalidate,"
1617 " status %i\n", __func__, rc);
1618 return rc;
1619}
1620
1621static int
Tom Talpey8d4ba032008-10-09 14:59:49 -04001622rpcrdma_register_fmr_external(struct rpcrdma_mr_seg *seg,
1623 int *nsegs, int writing, struct rpcrdma_ia *ia)
1624{
1625 struct rpcrdma_mr_seg *seg1 = seg;
1626 u64 physaddrs[RPCRDMA_MAX_DATA_SEGS];
1627 int len, pageoff, i, rc;
1628
1629 pageoff = offset_in_page(seg1->mr_offset);
1630 seg1->mr_offset -= pageoff; /* start of page */
1631 seg1->mr_len += pageoff;
1632 len = -pageoff;
1633 if (*nsegs > RPCRDMA_MAX_DATA_SEGS)
1634 *nsegs = RPCRDMA_MAX_DATA_SEGS;
1635 for (i = 0; i < *nsegs;) {
1636 rpcrdma_map_one(ia, seg, writing);
1637 physaddrs[i] = seg->mr_dma;
1638 len += seg->mr_len;
1639 ++seg;
1640 ++i;
1641 /* Check for holes */
1642 if ((i < *nsegs && offset_in_page(seg->mr_offset)) ||
1643 offset_in_page((seg-1)->mr_offset + (seg-1)->mr_len))
1644 break;
1645 }
1646 rc = ib_map_phys_fmr(seg1->mr_chunk.rl_mw->r.fmr,
1647 physaddrs, i, seg1->mr_dma);
1648 if (rc) {
1649 dprintk("RPC: %s: failed ib_map_phys_fmr "
1650 "%u@0x%llx+%i (%d)... status %i\n", __func__,
1651 len, (unsigned long long)seg1->mr_dma,
1652 pageoff, i, rc);
1653 while (i--)
1654 rpcrdma_unmap_one(ia, --seg);
1655 } else {
1656 seg1->mr_rkey = seg1->mr_chunk.rl_mw->r.fmr->rkey;
1657 seg1->mr_base = seg1->mr_dma + pageoff;
1658 seg1->mr_nsegs = i;
1659 seg1->mr_len = len;
1660 }
1661 *nsegs = i;
1662 return rc;
1663}
1664
1665static int
1666rpcrdma_deregister_fmr_external(struct rpcrdma_mr_seg *seg,
1667 struct rpcrdma_ia *ia)
1668{
1669 struct rpcrdma_mr_seg *seg1 = seg;
1670 LIST_HEAD(l);
1671 int rc;
1672
1673 list_add(&seg1->mr_chunk.rl_mw->r.fmr->list, &l);
1674 rc = ib_unmap_fmr(&l);
Chuck Lever73806c82014-07-29 17:23:25 -04001675 read_lock(&ia->ri_qplock);
Tom Talpey8d4ba032008-10-09 14:59:49 -04001676 while (seg1->mr_nsegs--)
1677 rpcrdma_unmap_one(ia, seg++);
Chuck Lever73806c82014-07-29 17:23:25 -04001678 read_unlock(&ia->ri_qplock);
Tom Talpey8d4ba032008-10-09 14:59:49 -04001679 if (rc)
1680 dprintk("RPC: %s: failed ib_unmap_fmr,"
1681 " status %i\n", __func__, rc);
1682 return rc;
1683}
1684
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001685int
1686rpcrdma_register_external(struct rpcrdma_mr_seg *seg,
1687 int nsegs, int writing, struct rpcrdma_xprt *r_xprt)
1688{
1689 struct rpcrdma_ia *ia = &r_xprt->rx_ia;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001690 int rc = 0;
1691
1692 switch (ia->ri_memreg_strategy) {
1693
1694#if RPCRDMA_PERSISTENT_REGISTRATION
1695 case RPCRDMA_ALLPHYSICAL:
1696 rpcrdma_map_one(ia, seg, writing);
1697 seg->mr_rkey = ia->ri_bind_mem->rkey;
1698 seg->mr_base = seg->mr_dma;
1699 seg->mr_nsegs = 1;
1700 nsegs = 1;
1701 break;
1702#endif
1703
Tom Talpey3197d3092008-10-09 15:00:20 -04001704 /* Registration using frmr registration */
1705 case RPCRDMA_FRMR:
1706 rc = rpcrdma_register_frmr_external(seg, &nsegs, writing, ia, r_xprt);
1707 break;
1708
Tom Talpey8d4ba032008-10-09 14:59:49 -04001709 /* Registration using fmr memory registration */
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001710 case RPCRDMA_MTHCAFMR:
Tom Talpey8d4ba032008-10-09 14:59:49 -04001711 rc = rpcrdma_register_fmr_external(seg, &nsegs, writing, ia);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001712 break;
1713
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001714 default:
Chuck Lever0ac531c2014-05-28 10:32:43 -04001715 return -1;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001716 }
1717 if (rc)
1718 return -1;
1719
1720 return nsegs;
1721}
1722
1723int
1724rpcrdma_deregister_external(struct rpcrdma_mr_seg *seg,
Chuck Lever13c9ff82014-05-28 10:33:08 -04001725 struct rpcrdma_xprt *r_xprt)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001726{
1727 struct rpcrdma_ia *ia = &r_xprt->rx_ia;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001728 int nsegs = seg->mr_nsegs, rc;
1729
1730 switch (ia->ri_memreg_strategy) {
1731
1732#if RPCRDMA_PERSISTENT_REGISTRATION
1733 case RPCRDMA_ALLPHYSICAL:
Chuck Lever73806c82014-07-29 17:23:25 -04001734 read_lock(&ia->ri_qplock);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001735 rpcrdma_unmap_one(ia, seg);
Chuck Lever73806c82014-07-29 17:23:25 -04001736 read_unlock(&ia->ri_qplock);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001737 break;
1738#endif
1739
Tom Talpey3197d3092008-10-09 15:00:20 -04001740 case RPCRDMA_FRMR:
1741 rc = rpcrdma_deregister_frmr_external(seg, ia, r_xprt);
1742 break;
1743
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001744 case RPCRDMA_MTHCAFMR:
Tom Talpey8d4ba032008-10-09 14:59:49 -04001745 rc = rpcrdma_deregister_fmr_external(seg, ia);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001746 break;
1747
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001748 default:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001749 break;
1750 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001751 return nsegs;
1752}
1753
1754/*
1755 * Prepost any receive buffer, then post send.
1756 *
1757 * Receive buffer is donated to hardware, reclaimed upon recv completion.
1758 */
1759int
1760rpcrdma_ep_post(struct rpcrdma_ia *ia,
1761 struct rpcrdma_ep *ep,
1762 struct rpcrdma_req *req)
1763{
1764 struct ib_send_wr send_wr, *send_wr_fail;
1765 struct rpcrdma_rep *rep = req->rl_reply;
1766 int rc;
1767
1768 if (rep) {
1769 rc = rpcrdma_ep_post_recv(ia, ep, rep);
1770 if (rc)
1771 goto out;
1772 req->rl_reply = NULL;
1773 }
1774
1775 send_wr.next = NULL;
1776 send_wr.wr_id = 0ULL; /* no send cookie */
1777 send_wr.sg_list = req->rl_send_iov;
1778 send_wr.num_sge = req->rl_niovs;
1779 send_wr.opcode = IB_WR_SEND;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001780 if (send_wr.num_sge == 4) /* no need to sync any pad (constant) */
1781 ib_dma_sync_single_for_device(ia->ri_id->device,
1782 req->rl_send_iov[3].addr, req->rl_send_iov[3].length,
1783 DMA_TO_DEVICE);
1784 ib_dma_sync_single_for_device(ia->ri_id->device,
1785 req->rl_send_iov[1].addr, req->rl_send_iov[1].length,
1786 DMA_TO_DEVICE);
1787 ib_dma_sync_single_for_device(ia->ri_id->device,
1788 req->rl_send_iov[0].addr, req->rl_send_iov[0].length,
1789 DMA_TO_DEVICE);
1790
1791 if (DECR_CQCOUNT(ep) > 0)
1792 send_wr.send_flags = 0;
1793 else { /* Provider must take a send completion every now and then */
1794 INIT_CQCOUNT(ep);
1795 send_wr.send_flags = IB_SEND_SIGNALED;
1796 }
1797
1798 rc = ib_post_send(ia->ri_id->qp, &send_wr, &send_wr_fail);
1799 if (rc)
1800 dprintk("RPC: %s: ib_post_send returned %i\n", __func__,
1801 rc);
1802out:
1803 return rc;
1804}
1805
1806/*
1807 * (Re)post a receive buffer.
1808 */
1809int
1810rpcrdma_ep_post_recv(struct rpcrdma_ia *ia,
1811 struct rpcrdma_ep *ep,
1812 struct rpcrdma_rep *rep)
1813{
1814 struct ib_recv_wr recv_wr, *recv_wr_fail;
1815 int rc;
1816
1817 recv_wr.next = NULL;
1818 recv_wr.wr_id = (u64) (unsigned long) rep;
1819 recv_wr.sg_list = &rep->rr_iov;
1820 recv_wr.num_sge = 1;
1821
1822 ib_dma_sync_single_for_cpu(ia->ri_id->device,
1823 rep->rr_iov.addr, rep->rr_iov.length, DMA_BIDIRECTIONAL);
1824
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001825 rc = ib_post_recv(ia->ri_id->qp, &recv_wr, &recv_wr_fail);
1826
1827 if (rc)
1828 dprintk("RPC: %s: ib_post_recv returned %i\n", __func__,
1829 rc);
1830 return rc;
1831}
Chuck Lever43e95982014-07-29 17:23:34 -04001832
1833/* Physical mapping means one Read/Write list entry per-page.
1834 * All list entries must fit within an inline buffer
1835 *
1836 * NB: The server must return a Write list for NFS READ,
1837 * which has the same constraint. Factor in the inline
1838 * rsize as well.
1839 */
1840static size_t
1841rpcrdma_physical_max_payload(struct rpcrdma_xprt *r_xprt)
1842{
1843 struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
1844 unsigned int inline_size, pages;
1845
1846 inline_size = min_t(unsigned int,
1847 cdata->inline_wsize, cdata->inline_rsize);
1848 inline_size -= RPCRDMA_HDRLEN_MIN;
1849 pages = inline_size / sizeof(struct rpcrdma_segment);
1850 return pages << PAGE_SHIFT;
1851}
1852
1853static size_t
1854rpcrdma_mr_max_payload(struct rpcrdma_xprt *r_xprt)
1855{
1856 return RPCRDMA_MAX_DATA_SEGS << PAGE_SHIFT;
1857}
1858
1859size_t
1860rpcrdma_max_payload(struct rpcrdma_xprt *r_xprt)
1861{
1862 size_t result;
1863
1864 switch (r_xprt->rx_ia.ri_memreg_strategy) {
1865 case RPCRDMA_ALLPHYSICAL:
1866 result = rpcrdma_physical_max_payload(r_xprt);
1867 break;
1868 default:
1869 result = rpcrdma_mr_max_payload(r_xprt);
1870 }
1871 return result;
1872}