blob: 1b2c1f4ec4c35ff841ec145192dfb053c73bb8c6 [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
66/*
67 * internal functions
68 */
69
70/*
71 * handle replies in tasklet context, using a single, global list
72 * rdma tasklet function -- just turn around and call the func
73 * for all replies on the list
74 */
75
76static DEFINE_SPINLOCK(rpcrdma_tk_lock_g);
77static LIST_HEAD(rpcrdma_tasklets_g);
78
79static void
80rpcrdma_run_tasklet(unsigned long data)
81{
82 struct rpcrdma_rep *rep;
83 void (*func)(struct rpcrdma_rep *);
84 unsigned long flags;
85
86 data = data;
87 spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
88 while (!list_empty(&rpcrdma_tasklets_g)) {
89 rep = list_entry(rpcrdma_tasklets_g.next,
90 struct rpcrdma_rep, rr_list);
91 list_del(&rep->rr_list);
92 func = rep->rr_func;
93 rep->rr_func = NULL;
94 spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
95
96 if (func)
97 func(rep);
98 else
99 rpcrdma_recv_buffer_put(rep);
100
101 spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
102 }
103 spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
104}
105
106static DECLARE_TASKLET(rpcrdma_tasklet_g, rpcrdma_run_tasklet, 0UL);
107
Chuck Lever7ff11de2014-11-08 20:15:01 -0500108static const char * const async_event[] = {
109 "CQ error",
110 "QP fatal error",
111 "QP request error",
112 "QP access error",
113 "communication established",
114 "send queue drained",
115 "path migration successful",
116 "path mig error",
117 "device fatal error",
118 "port active",
119 "port error",
120 "LID change",
121 "P_key change",
122 "SM change",
123 "SRQ error",
124 "SRQ limit reached",
125 "last WQE reached",
126 "client reregister",
127 "GID change",
128};
129
130#define ASYNC_MSG(status) \
131 ((status) < ARRAY_SIZE(async_event) ? \
132 async_event[(status)] : "unknown async error")
133
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400134static void
Chuck Leverf1a03b72014-11-08 20:14:37 -0500135rpcrdma_schedule_tasklet(struct list_head *sched_list)
136{
137 unsigned long flags;
138
139 spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
140 list_splice_tail(sched_list, &rpcrdma_tasklets_g);
141 spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
142 tasklet_schedule(&rpcrdma_tasklet_g);
143}
144
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400145static void
146rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context)
147{
148 struct rpcrdma_ep *ep = context;
149
Chuck Lever7ff11de2014-11-08 20:15:01 -0500150 pr_err("RPC: %s: %s on device %s ep %p\n",
151 __func__, ASYNC_MSG(event->event),
152 event->device->name, context);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400153 if (ep->rep_connected == 1) {
154 ep->rep_connected = -EIO;
Chuck Leverafadc462015-01-21 11:03:11 -0500155 rpcrdma_conn_func(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400156 wake_up_all(&ep->rep_connect_wait);
157 }
158}
159
160static void
161rpcrdma_cq_async_error_upcall(struct ib_event *event, void *context)
162{
163 struct rpcrdma_ep *ep = context;
164
Chuck Lever7ff11de2014-11-08 20:15:01 -0500165 pr_err("RPC: %s: %s on device %s ep %p\n",
166 __func__, ASYNC_MSG(event->event),
167 event->device->name, context);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400168 if (ep->rep_connected == 1) {
169 ep->rep_connected = -EIO;
Chuck Leverafadc462015-01-21 11:03:11 -0500170 rpcrdma_conn_func(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400171 wake_up_all(&ep->rep_connect_wait);
172 }
173}
174
Chuck Lever85024272015-01-21 11:02:04 -0500175static const char * const wc_status[] = {
176 "success",
177 "local length error",
178 "local QP operation error",
179 "local EE context operation error",
180 "local protection error",
181 "WR flushed",
182 "memory management operation error",
183 "bad response error",
184 "local access error",
185 "remote invalid request error",
186 "remote access error",
187 "remote operation error",
188 "transport retry counter exceeded",
189 "RNR retrycounter exceeded",
190 "local RDD violation error",
191 "remove invalid RD request",
192 "operation aborted",
193 "invalid EE context number",
194 "invalid EE context state",
195 "fatal error",
196 "response timeout error",
197 "general error",
198};
199
200#define COMPLETION_MSG(status) \
201 ((status) < ARRAY_SIZE(wc_status) ? \
202 wc_status[(status)] : "unexpected completion error")
203
Chuck Leverfc664482014-05-28 10:33:25 -0400204static void
205rpcrdma_sendcq_process_wc(struct ib_wc *wc)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400206{
Chuck Lever85024272015-01-21 11:02:04 -0500207 if (likely(wc->status == IB_WC_SUCCESS))
Chuck Leverfc664482014-05-28 10:33:25 -0400208 return;
Chuck Lever85024272015-01-21 11:02:04 -0500209
210 /* WARNING: Only wr_id and status are reliable at this point */
211 if (wc->wr_id == 0ULL) {
212 if (wc->status != IB_WC_WR_FLUSH_ERR)
213 pr_err("RPC: %s: SEND: %s\n",
214 __func__, COMPLETION_MSG(wc->status));
215 } else {
216 struct rpcrdma_mw *r;
217
218 r = (struct rpcrdma_mw *)(unsigned long)wc->wr_id;
219 r->r.frmr.fr_state = FRMR_IS_STALE;
220 pr_err("RPC: %s: frmr %p (stale): %s\n",
221 __func__, r, COMPLETION_MSG(wc->status));
222 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400223}
224
Chuck Leverfc664482014-05-28 10:33:25 -0400225static int
Chuck Lever1c00dd02014-05-28 10:33:42 -0400226rpcrdma_sendcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400227{
Chuck Lever1c00dd02014-05-28 10:33:42 -0400228 struct ib_wc *wcs;
Chuck Lever8301a2c2014-05-28 10:33:51 -0400229 int budget, count, rc;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400230
Chuck Lever8301a2c2014-05-28 10:33:51 -0400231 budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE;
Chuck Lever1c00dd02014-05-28 10:33:42 -0400232 do {
233 wcs = ep->rep_send_wcs;
234
235 rc = ib_poll_cq(cq, RPCRDMA_POLLSIZE, wcs);
236 if (rc <= 0)
237 return rc;
238
239 count = rc;
240 while (count-- > 0)
241 rpcrdma_sendcq_process_wc(wcs++);
Chuck Lever8301a2c2014-05-28 10:33:51 -0400242 } while (rc == RPCRDMA_POLLSIZE && --budget);
Chuck Lever1c00dd02014-05-28 10:33:42 -0400243 return 0;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400244}
245
246/*
Chuck Leverfc664482014-05-28 10:33:25 -0400247 * Handle send, fast_reg_mr, and local_inv completions.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400248 *
Chuck Leverfc664482014-05-28 10:33:25 -0400249 * Send events are typically suppressed and thus do not result
250 * in an upcall. Occasionally one is signaled, however. This
251 * prevents the provider's completion queue from wrapping and
252 * losing a completion.
253 */
254static void
255rpcrdma_sendcq_upcall(struct ib_cq *cq, void *cq_context)
256{
Chuck Lever1c00dd02014-05-28 10:33:42 -0400257 struct rpcrdma_ep *ep = (struct rpcrdma_ep *)cq_context;
Chuck Leverfc664482014-05-28 10:33:25 -0400258 int rc;
259
Chuck Lever1c00dd02014-05-28 10:33:42 -0400260 rc = rpcrdma_sendcq_poll(cq, ep);
Chuck Leverfc664482014-05-28 10:33:25 -0400261 if (rc) {
262 dprintk("RPC: %s: ib_poll_cq failed: %i\n",
263 __func__, rc);
264 return;
265 }
266
Chuck Lever7f23f6f2014-05-28 10:33:34 -0400267 rc = ib_req_notify_cq(cq,
268 IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
269 if (rc == 0)
270 return;
271 if (rc < 0) {
Chuck Leverfc664482014-05-28 10:33:25 -0400272 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
273 __func__, rc);
274 return;
275 }
276
Chuck Lever1c00dd02014-05-28 10:33:42 -0400277 rpcrdma_sendcq_poll(cq, ep);
Chuck Leverfc664482014-05-28 10:33:25 -0400278}
279
280static void
Chuck Leverbb961932014-07-29 17:25:46 -0400281rpcrdma_recvcq_process_wc(struct ib_wc *wc, struct list_head *sched_list)
Chuck Leverfc664482014-05-28 10:33:25 -0400282{
283 struct rpcrdma_rep *rep =
284 (struct rpcrdma_rep *)(unsigned long)wc->wr_id;
285
Chuck Lever85024272015-01-21 11:02:04 -0500286 /* WARNING: Only wr_id and status are reliable at this point */
287 if (wc->status != IB_WC_SUCCESS)
288 goto out_fail;
Chuck Leverfc664482014-05-28 10:33:25 -0400289
Chuck Lever85024272015-01-21 11:02:04 -0500290 /* status == SUCCESS means all fields in wc are trustworthy */
Chuck Leverfc664482014-05-28 10:33:25 -0400291 if (wc->opcode != IB_WC_RECV)
292 return;
293
Chuck Lever85024272015-01-21 11:02:04 -0500294 dprintk("RPC: %s: rep %p opcode 'recv', length %u: success\n",
295 __func__, rep, wc->byte_len);
296
Chuck Leverfc664482014-05-28 10:33:25 -0400297 rep->rr_len = wc->byte_len;
298 ib_dma_sync_single_for_cpu(rdmab_to_ia(rep->rr_buffer)->ri_id->device,
Chuck Lever6b1184c2015-01-21 11:04:25 -0500299 rdmab_addr(rep->rr_rdmabuf),
300 rep->rr_len, DMA_FROM_DEVICE);
301 prefetch(rdmab_to_msg(rep->rr_rdmabuf));
Chuck Leverfc664482014-05-28 10:33:25 -0400302
303out_schedule:
Chuck Leverbb961932014-07-29 17:25:46 -0400304 list_add_tail(&rep->rr_list, sched_list);
Chuck Lever85024272015-01-21 11:02:04 -0500305 return;
306out_fail:
307 if (wc->status != IB_WC_WR_FLUSH_ERR)
308 pr_err("RPC: %s: rep %p: %s\n",
309 __func__, rep, COMPLETION_MSG(wc->status));
310 rep->rr_len = ~0U;
311 goto out_schedule;
Chuck Leverfc664482014-05-28 10:33:25 -0400312}
313
314static int
Chuck Lever1c00dd02014-05-28 10:33:42 -0400315rpcrdma_recvcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep)
Chuck Leverfc664482014-05-28 10:33:25 -0400316{
Chuck Leverbb961932014-07-29 17:25:46 -0400317 struct list_head sched_list;
Chuck Lever1c00dd02014-05-28 10:33:42 -0400318 struct ib_wc *wcs;
Chuck Lever8301a2c2014-05-28 10:33:51 -0400319 int budget, count, rc;
Chuck Leverfc664482014-05-28 10:33:25 -0400320
Chuck Leverbb961932014-07-29 17:25:46 -0400321 INIT_LIST_HEAD(&sched_list);
Chuck Lever8301a2c2014-05-28 10:33:51 -0400322 budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE;
Chuck Lever1c00dd02014-05-28 10:33:42 -0400323 do {
324 wcs = ep->rep_recv_wcs;
325
326 rc = ib_poll_cq(cq, RPCRDMA_POLLSIZE, wcs);
327 if (rc <= 0)
Chuck Leverbb961932014-07-29 17:25:46 -0400328 goto out_schedule;
Chuck Lever1c00dd02014-05-28 10:33:42 -0400329
330 count = rc;
331 while (count-- > 0)
Chuck Leverbb961932014-07-29 17:25:46 -0400332 rpcrdma_recvcq_process_wc(wcs++, &sched_list);
Chuck Lever8301a2c2014-05-28 10:33:51 -0400333 } while (rc == RPCRDMA_POLLSIZE && --budget);
Chuck Leverbb961932014-07-29 17:25:46 -0400334 rc = 0;
335
336out_schedule:
Chuck Leverf1a03b72014-11-08 20:14:37 -0500337 rpcrdma_schedule_tasklet(&sched_list);
Chuck Leverbb961932014-07-29 17:25:46 -0400338 return rc;
Chuck Leverfc664482014-05-28 10:33:25 -0400339}
340
341/*
342 * Handle receive completions.
343 *
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400344 * It is reentrant but processes single events in order to maintain
345 * ordering of receives to keep server credits.
346 *
347 * It is the responsibility of the scheduled tasklet to return
348 * recv buffers to the pool. NOTE: this affects synchronization of
349 * connection shutdown. That is, the structures required for
350 * the completion of the reply handler must remain intact until
351 * all memory has been reclaimed.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400352 */
353static void
Chuck Leverfc664482014-05-28 10:33:25 -0400354rpcrdma_recvcq_upcall(struct ib_cq *cq, void *cq_context)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400355{
Chuck Lever1c00dd02014-05-28 10:33:42 -0400356 struct rpcrdma_ep *ep = (struct rpcrdma_ep *)cq_context;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400357 int rc;
358
Chuck Lever1c00dd02014-05-28 10:33:42 -0400359 rc = rpcrdma_recvcq_poll(cq, ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400360 if (rc) {
Chuck Leverfc664482014-05-28 10:33:25 -0400361 dprintk("RPC: %s: ib_poll_cq failed: %i\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400362 __func__, rc);
363 return;
364 }
365
Chuck Lever7f23f6f2014-05-28 10:33:34 -0400366 rc = ib_req_notify_cq(cq,
367 IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
368 if (rc == 0)
369 return;
370 if (rc < 0) {
Chuck Leverfc664482014-05-28 10:33:25 -0400371 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
372 __func__, rc);
373 return;
374 }
375
Chuck Lever1c00dd02014-05-28 10:33:42 -0400376 rpcrdma_recvcq_poll(cq, ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400377}
378
Chuck Levera7bc2112014-07-29 17:23:52 -0400379static void
380rpcrdma_flush_cqs(struct rpcrdma_ep *ep)
381{
Chuck Lever5c166bef2014-11-08 20:14:45 -0500382 struct ib_wc wc;
383 LIST_HEAD(sched_list);
384
385 while (ib_poll_cq(ep->rep_attr.recv_cq, 1, &wc) > 0)
386 rpcrdma_recvcq_process_wc(&wc, &sched_list);
387 if (!list_empty(&sched_list))
388 rpcrdma_schedule_tasklet(&sched_list);
389 while (ib_poll_cq(ep->rep_attr.send_cq, 1, &wc) > 0)
390 rpcrdma_sendcq_process_wc(&wc);
Chuck Levera7bc2112014-07-29 17:23:52 -0400391}
392
Jeff Laytonf895b252014-11-17 16:58:04 -0500393#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400394static const char * const conn[] = {
395 "address resolved",
396 "address error",
397 "route resolved",
398 "route error",
399 "connect request",
400 "connect response",
401 "connect error",
402 "unreachable",
403 "rejected",
404 "established",
405 "disconnected",
Chuck Lever8079fb72014-07-29 17:26:12 -0400406 "device removal",
407 "multicast join",
408 "multicast error",
409 "address change",
410 "timewait exit",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400411};
Chuck Lever8079fb72014-07-29 17:26:12 -0400412
413#define CONNECTION_MSG(status) \
414 ((status) < ARRAY_SIZE(conn) ? \
415 conn[(status)] : "unrecognized connection error")
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400416#endif
417
418static int
419rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
420{
421 struct rpcrdma_xprt *xprt = id->context;
422 struct rpcrdma_ia *ia = &xprt->rx_ia;
423 struct rpcrdma_ep *ep = &xprt->rx_ep;
Jeff Laytonf895b252014-11-17 16:58:04 -0500424#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
Chuck Lever0dd39ca2015-03-30 14:33:43 -0400425 struct sockaddr *sap = (struct sockaddr *)&ep->rep_remote_addr;
Ingo Molnarff0db042008-11-25 16:58:42 -0800426#endif
Chuck Leverce1ab9a2015-01-21 11:03:35 -0500427 struct ib_qp_attr *attr = &ia->ri_qp_attr;
428 struct ib_qp_init_attr *iattr = &ia->ri_qp_init_attr;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400429 int connstate = 0;
430
431 switch (event->event) {
432 case RDMA_CM_EVENT_ADDR_RESOLVED:
433 case RDMA_CM_EVENT_ROUTE_RESOLVED:
Tom Talpey5675add2008-10-09 15:01:41 -0400434 ia->ri_async_rc = 0;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400435 complete(&ia->ri_done);
436 break;
437 case RDMA_CM_EVENT_ADDR_ERROR:
438 ia->ri_async_rc = -EHOSTUNREACH;
439 dprintk("RPC: %s: CM address resolution error, ep 0x%p\n",
440 __func__, ep);
441 complete(&ia->ri_done);
442 break;
443 case RDMA_CM_EVENT_ROUTE_ERROR:
444 ia->ri_async_rc = -ENETUNREACH;
445 dprintk("RPC: %s: CM route resolution error, ep 0x%p\n",
446 __func__, ep);
447 complete(&ia->ri_done);
448 break;
449 case RDMA_CM_EVENT_ESTABLISHED:
450 connstate = 1;
Chuck Leverce1ab9a2015-01-21 11:03:35 -0500451 ib_query_qp(ia->ri_id->qp, attr,
452 IB_QP_MAX_QP_RD_ATOMIC | IB_QP_MAX_DEST_RD_ATOMIC,
453 iattr);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400454 dprintk("RPC: %s: %d responder resources"
455 " (%d initiator)\n",
Chuck Leverce1ab9a2015-01-21 11:03:35 -0500456 __func__, attr->max_dest_rd_atomic,
457 attr->max_rd_atomic);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400458 goto connected;
459 case RDMA_CM_EVENT_CONNECT_ERROR:
460 connstate = -ENOTCONN;
461 goto connected;
462 case RDMA_CM_EVENT_UNREACHABLE:
463 connstate = -ENETDOWN;
464 goto connected;
465 case RDMA_CM_EVENT_REJECTED:
466 connstate = -ECONNREFUSED;
467 goto connected;
468 case RDMA_CM_EVENT_DISCONNECTED:
469 connstate = -ECONNABORTED;
470 goto connected;
471 case RDMA_CM_EVENT_DEVICE_REMOVAL:
472 connstate = -ENODEV;
473connected:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400474 dprintk("RPC: %s: %sconnected\n",
475 __func__, connstate > 0 ? "" : "dis");
476 ep->rep_connected = connstate;
Chuck Leverafadc462015-01-21 11:03:11 -0500477 rpcrdma_conn_func(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400478 wake_up_all(&ep->rep_connect_wait);
Chuck Lever8079fb72014-07-29 17:26:12 -0400479 /*FALLTHROUGH*/
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400480 default:
Chuck Lever0dd39ca2015-03-30 14:33:43 -0400481 dprintk("RPC: %s: %pIS:%u (ep 0x%p): %s\n",
482 __func__, sap, rpc_get_port(sap), ep,
Chuck Lever8079fb72014-07-29 17:26:12 -0400483 CONNECTION_MSG(event->event));
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400484 break;
485 }
486
Jeff Laytonf895b252014-11-17 16:58:04 -0500487#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400488 if (connstate == 1) {
Chuck Leverce1ab9a2015-01-21 11:03:35 -0500489 int ird = attr->max_dest_rd_atomic;
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400490 int tird = ep->rep_remote_cma.responder_resources;
Chuck Lever0dd39ca2015-03-30 14:33:43 -0400491
Chuck Levera0ce85f2015-03-30 14:34:21 -0400492 pr_info("rpcrdma: connection to %pIS:%u on %s, memreg '%s', %d credits, %d responders%s\n",
Chuck Lever0dd39ca2015-03-30 14:33:43 -0400493 sap, rpc_get_port(sap),
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400494 ia->ri_id->device->name,
Chuck Levera0ce85f2015-03-30 14:34:21 -0400495 ia->ri_ops->ro_displayname,
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400496 xprt->rx_buf.rb_max_requests,
497 ird, ird < 4 && ird < tird / 2 ? " (low!)" : "");
498 } else if (connstate < 0) {
Chuck Lever0dd39ca2015-03-30 14:33:43 -0400499 pr_info("rpcrdma: connection to %pIS:%u closed (%d)\n",
500 sap, rpc_get_port(sap), connstate);
Tom Talpeyb3cd8d42008-10-09 15:02:02 -0400501 }
502#endif
503
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400504 return 0;
505}
506
507static struct rdma_cm_id *
508rpcrdma_create_id(struct rpcrdma_xprt *xprt,
509 struct rpcrdma_ia *ia, struct sockaddr *addr)
510{
511 struct rdma_cm_id *id;
512 int rc;
513
Tom Talpey1a954052008-10-09 15:01:31 -0400514 init_completion(&ia->ri_done);
515
Sean Heftyb26f9b92010-04-01 17:08:41 +0000516 id = rdma_create_id(rpcrdma_conn_upcall, xprt, RDMA_PS_TCP, IB_QPT_RC);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400517 if (IS_ERR(id)) {
518 rc = PTR_ERR(id);
519 dprintk("RPC: %s: rdma_create_id() failed %i\n",
520 __func__, rc);
521 return id;
522 }
523
Tom Talpey5675add2008-10-09 15:01:41 -0400524 ia->ri_async_rc = -ETIMEDOUT;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400525 rc = rdma_resolve_addr(id, NULL, addr, RDMA_RESOLVE_TIMEOUT);
526 if (rc) {
527 dprintk("RPC: %s: rdma_resolve_addr() failed %i\n",
528 __func__, rc);
529 goto out;
530 }
Tom Talpey5675add2008-10-09 15:01:41 -0400531 wait_for_completion_interruptible_timeout(&ia->ri_done,
532 msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT) + 1);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400533 rc = ia->ri_async_rc;
534 if (rc)
535 goto out;
536
Tom Talpey5675add2008-10-09 15:01:41 -0400537 ia->ri_async_rc = -ETIMEDOUT;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400538 rc = rdma_resolve_route(id, RDMA_RESOLVE_TIMEOUT);
539 if (rc) {
540 dprintk("RPC: %s: rdma_resolve_route() failed %i\n",
541 __func__, rc);
542 goto out;
543 }
Tom Talpey5675add2008-10-09 15:01:41 -0400544 wait_for_completion_interruptible_timeout(&ia->ri_done,
545 msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT) + 1);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400546 rc = ia->ri_async_rc;
547 if (rc)
548 goto out;
549
550 return id;
551
552out:
553 rdma_destroy_id(id);
554 return ERR_PTR(rc);
555}
556
557/*
558 * Drain any cq, prior to teardown.
559 */
560static void
561rpcrdma_clean_cq(struct ib_cq *cq)
562{
563 struct ib_wc wc;
564 int count = 0;
565
566 while (1 == ib_poll_cq(cq, 1, &wc))
567 ++count;
568
569 if (count)
570 dprintk("RPC: %s: flushed %d events (last 0x%x)\n",
571 __func__, count, wc.opcode);
572}
573
574/*
575 * Exported functions.
576 */
577
578/*
579 * Open and initialize an Interface Adapter.
580 * o initializes fields of struct rpcrdma_ia, including
581 * interface and provider attributes and protection zone.
582 */
583int
584rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg)
585{
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400586 int rc, mem_priv;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400587 struct rpcrdma_ia *ia = &xprt->rx_ia;
Chuck Lever7bc79722015-01-21 11:03:27 -0500588 struct ib_device_attr *devattr = &ia->ri_devattr;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400589
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400590 ia->ri_id = rpcrdma_create_id(xprt, ia, addr);
591 if (IS_ERR(ia->ri_id)) {
592 rc = PTR_ERR(ia->ri_id);
593 goto out1;
594 }
595
596 ia->ri_pd = ib_alloc_pd(ia->ri_id->device);
597 if (IS_ERR(ia->ri_pd)) {
598 rc = PTR_ERR(ia->ri_pd);
599 dprintk("RPC: %s: ib_alloc_pd() failed %i\n",
600 __func__, rc);
601 goto out2;
602 }
603
Chuck Lever7bc79722015-01-21 11:03:27 -0500604 rc = ib_query_device(ia->ri_id->device, devattr);
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400605 if (rc) {
606 dprintk("RPC: %s: ib_query_device failed %d\n",
607 __func__, rc);
Chuck Lever5ae711a2015-01-21 11:03:19 -0500608 goto out3;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400609 }
610
Chuck Lever7bc79722015-01-21 11:03:27 -0500611 if (devattr->device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY) {
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400612 ia->ri_have_dma_lkey = 1;
613 ia->ri_dma_lkey = ia->ri_id->device->local_dma_lkey;
614 }
615
Chuck Leverf10eafd2014-05-28 10:32:51 -0400616 if (memreg == RPCRDMA_FRMR) {
Tom Talpey3197d3092008-10-09 15:00:20 -0400617 /* Requires both frmr reg and local dma lkey */
Chuck Lever41f97022015-03-30 14:34:12 -0400618 if (((devattr->device_cap_flags &
Tom Talpey3197d3092008-10-09 15:00:20 -0400619 (IB_DEVICE_MEM_MGT_EXTENSIONS|IB_DEVICE_LOCAL_DMA_LKEY)) !=
Chuck Lever41f97022015-03-30 14:34:12 -0400620 (IB_DEVICE_MEM_MGT_EXTENSIONS|IB_DEVICE_LOCAL_DMA_LKEY)) ||
621 (devattr->max_fast_reg_page_list_len == 0)) {
Tom Talpey3197d3092008-10-09 15:00:20 -0400622 dprintk("RPC: %s: FRMR registration "
Chuck Leverf10eafd2014-05-28 10:32:51 -0400623 "not supported by HCA\n", __func__);
624 memreg = RPCRDMA_MTHCAFMR;
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400625 } else {
626 /* Mind the ia limit on FRMR page list depth */
627 ia->ri_max_frmr_depth = min_t(unsigned int,
628 RPCRDMA_MAX_DATA_SEGS,
Chuck Lever7bc79722015-01-21 11:03:27 -0500629 devattr->max_fast_reg_page_list_len);
Tom Talpey3197d3092008-10-09 15:00:20 -0400630 }
Chuck Leverf10eafd2014-05-28 10:32:51 -0400631 }
632 if (memreg == RPCRDMA_MTHCAFMR) {
633 if (!ia->ri_id->device->alloc_fmr) {
634 dprintk("RPC: %s: MTHCAFMR registration "
635 "not supported by HCA\n", __func__);
Chuck Leverf10eafd2014-05-28 10:32:51 -0400636 memreg = RPCRDMA_ALLPHYSICAL;
Chuck Leverf10eafd2014-05-28 10:32:51 -0400637 }
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400638 }
639
640 /*
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400641 * Optionally obtain an underlying physical identity mapping in
642 * order to do a memory window-based bind. This base registration
643 * is protected from remote access - that is enabled only by binding
644 * for the specific bytes targeted during each RPC operation, and
645 * revoked after the corresponding completion similar to a storage
646 * adapter.
647 */
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400648 switch (memreg) {
Tom Talpey3197d3092008-10-09 15:00:20 -0400649 case RPCRDMA_FRMR:
Chuck Levera0ce85f2015-03-30 14:34:21 -0400650 ia->ri_ops = &rpcrdma_frwr_memreg_ops;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400651 break;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400652 case RPCRDMA_ALLPHYSICAL:
Chuck Levera0ce85f2015-03-30 14:34:21 -0400653 ia->ri_ops = &rpcrdma_physical_memreg_ops;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400654 mem_priv = IB_ACCESS_LOCAL_WRITE |
655 IB_ACCESS_REMOTE_WRITE |
656 IB_ACCESS_REMOTE_READ;
657 goto register_setup;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400658 case RPCRDMA_MTHCAFMR:
Chuck Levera0ce85f2015-03-30 14:34:21 -0400659 ia->ri_ops = &rpcrdma_fmr_memreg_ops;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400660 if (ia->ri_have_dma_lkey)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400661 break;
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400662 mem_priv = IB_ACCESS_LOCAL_WRITE;
663 register_setup:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400664 ia->ri_bind_mem = ib_get_dma_mr(ia->ri_pd, mem_priv);
665 if (IS_ERR(ia->ri_bind_mem)) {
666 printk(KERN_ALERT "%s: ib_get_dma_mr for "
Chuck Lever0ac531c2014-05-28 10:32:43 -0400667 "phys register failed with %lX\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400668 __func__, PTR_ERR(ia->ri_bind_mem));
Chuck Lever0ac531c2014-05-28 10:32:43 -0400669 rc = -ENOMEM;
Chuck Lever5ae711a2015-01-21 11:03:19 -0500670 goto out3;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400671 }
Tom Talpeybd7ed1d2008-10-09 15:00:09 -0400672 break;
673 default:
Chuck Levercdd9ade2014-05-28 10:33:00 -0400674 printk(KERN_ERR "RPC: Unsupported memory "
675 "registration mode: %d\n", memreg);
676 rc = -ENOMEM;
Chuck Lever5ae711a2015-01-21 11:03:19 -0500677 goto out3;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400678 }
Chuck Levera0ce85f2015-03-30 14:34:21 -0400679 dprintk("RPC: %s: memory registration strategy is '%s'\n",
680 __func__, ia->ri_ops->ro_displayname);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400681
682 /* Else will do memory reg/dereg for each chunk */
683 ia->ri_memreg_strategy = memreg;
684
Chuck Lever73806c82014-07-29 17:23:25 -0400685 rwlock_init(&ia->ri_qplock);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400686 return 0;
Chuck Lever5ae711a2015-01-21 11:03:19 -0500687
688out3:
689 ib_dealloc_pd(ia->ri_pd);
690 ia->ri_pd = NULL;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400691out2:
692 rdma_destroy_id(ia->ri_id);
Tom Talpeyfee08ca2008-10-09 15:01:00 -0400693 ia->ri_id = NULL;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400694out1:
695 return rc;
696}
697
698/*
699 * Clean up/close an IA.
700 * o if event handles and PD have been initialized, free them.
701 * o close the IA
702 */
703void
704rpcrdma_ia_close(struct rpcrdma_ia *ia)
705{
706 int rc;
707
708 dprintk("RPC: %s: entering\n", __func__);
709 if (ia->ri_bind_mem != NULL) {
710 rc = ib_dereg_mr(ia->ri_bind_mem);
711 dprintk("RPC: %s: ib_dereg_mr returned %i\n",
712 __func__, rc);
713 }
Tom Talpeyfee08ca2008-10-09 15:01:00 -0400714 if (ia->ri_id != NULL && !IS_ERR(ia->ri_id)) {
715 if (ia->ri_id->qp)
716 rdma_destroy_qp(ia->ri_id);
717 rdma_destroy_id(ia->ri_id);
718 ia->ri_id = NULL;
719 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400720 if (ia->ri_pd != NULL && !IS_ERR(ia->ri_pd)) {
721 rc = ib_dealloc_pd(ia->ri_pd);
722 dprintk("RPC: %s: ib_dealloc_pd returned %i\n",
723 __func__, rc);
724 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400725}
726
727/*
728 * Create unconnected endpoint.
729 */
730int
731rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
732 struct rpcrdma_create_data_internal *cdata)
733{
Chuck Lever7bc79722015-01-21 11:03:27 -0500734 struct ib_device_attr *devattr = &ia->ri_devattr;
Chuck Leverfc664482014-05-28 10:33:25 -0400735 struct ib_cq *sendcq, *recvcq;
Chuck Lever5d40a8a2007-10-26 13:30:54 -0400736 int rc, err;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400737
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400738 /* check provider's send/recv wr limits */
Chuck Lever7bc79722015-01-21 11:03:27 -0500739 if (cdata->max_requests > devattr->max_qp_wr)
740 cdata->max_requests = devattr->max_qp_wr;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400741
742 ep->rep_attr.event_handler = rpcrdma_qp_async_error_upcall;
743 ep->rep_attr.qp_context = ep;
744 /* send_cq and recv_cq initialized below */
745 ep->rep_attr.srq = NULL;
746 ep->rep_attr.cap.max_send_wr = cdata->max_requests;
747 switch (ia->ri_memreg_strategy) {
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400748 case RPCRDMA_FRMR: {
749 int depth = 7;
750
Tom Tucker15cdc6442010-08-11 12:47:24 -0400751 /* Add room for frmr register and invalidate WRs.
752 * 1. FRMR reg WR for head
753 * 2. FRMR invalidate WR for head
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400754 * 3. N FRMR reg WRs for pagelist
755 * 4. N FRMR invalidate WRs for pagelist
Tom Tucker15cdc6442010-08-11 12:47:24 -0400756 * 5. FRMR reg WR for tail
757 * 6. FRMR invalidate WR for tail
758 * 7. The RDMA_SEND WR
759 */
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400760
761 /* Calculate N if the device max FRMR depth is smaller than
762 * RPCRDMA_MAX_DATA_SEGS.
763 */
764 if (ia->ri_max_frmr_depth < RPCRDMA_MAX_DATA_SEGS) {
765 int delta = RPCRDMA_MAX_DATA_SEGS -
766 ia->ri_max_frmr_depth;
767
768 do {
769 depth += 2; /* FRMR reg + invalidate */
770 delta -= ia->ri_max_frmr_depth;
771 } while (delta > 0);
772
773 }
774 ep->rep_attr.cap.max_send_wr *= depth;
Chuck Lever7bc79722015-01-21 11:03:27 -0500775 if (ep->rep_attr.cap.max_send_wr > devattr->max_qp_wr) {
776 cdata->max_requests = devattr->max_qp_wr / depth;
Tom Tucker15cdc6442010-08-11 12:47:24 -0400777 if (!cdata->max_requests)
778 return -EINVAL;
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400779 ep->rep_attr.cap.max_send_wr = cdata->max_requests *
780 depth;
Tom Tucker15cdc6442010-08-11 12:47:24 -0400781 }
Tom Talpey3197d3092008-10-09 15:00:20 -0400782 break;
Steve Wise0fc6c4e2014-05-28 10:32:00 -0400783 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400784 default:
785 break;
786 }
787 ep->rep_attr.cap.max_recv_wr = cdata->max_requests;
788 ep->rep_attr.cap.max_send_sge = (cdata->padding ? 4 : 2);
789 ep->rep_attr.cap.max_recv_sge = 1;
790 ep->rep_attr.cap.max_inline_data = 0;
791 ep->rep_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
792 ep->rep_attr.qp_type = IB_QPT_RC;
793 ep->rep_attr.port_num = ~0;
794
Chuck Leverc05fbb52015-01-21 11:04:33 -0500795 if (cdata->padding) {
796 ep->rep_padbuf = rpcrdma_alloc_regbuf(ia, cdata->padding,
797 GFP_KERNEL);
798 if (IS_ERR(ep->rep_padbuf))
799 return PTR_ERR(ep->rep_padbuf);
800 } else
801 ep->rep_padbuf = NULL;
802
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400803 dprintk("RPC: %s: requested max: dtos: send %d recv %d; "
804 "iovs: send %d recv %d\n",
805 __func__,
806 ep->rep_attr.cap.max_send_wr,
807 ep->rep_attr.cap.max_recv_wr,
808 ep->rep_attr.cap.max_send_sge,
809 ep->rep_attr.cap.max_recv_sge);
810
811 /* set trigger for requesting send completion */
Chuck Leverfc664482014-05-28 10:33:25 -0400812 ep->rep_cqinit = ep->rep_attr.cap.max_send_wr/2 - 1;
Chuck Levere7104a22014-11-08 20:14:20 -0500813 if (ep->rep_cqinit > RPCRDMA_MAX_UNSIGNALED_SENDS)
814 ep->rep_cqinit = RPCRDMA_MAX_UNSIGNALED_SENDS;
815 else if (ep->rep_cqinit <= 2)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400816 ep->rep_cqinit = 0;
817 INIT_CQCOUNT(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400818 init_waitqueue_head(&ep->rep_connect_wait);
Chuck Lever254f91e2014-05-28 10:32:17 -0400819 INIT_DELAYED_WORK(&ep->rep_connect_worker, rpcrdma_connect_worker);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400820
Chuck Leverfc664482014-05-28 10:33:25 -0400821 sendcq = ib_create_cq(ia->ri_id->device, rpcrdma_sendcq_upcall,
Chuck Lever1c00dd02014-05-28 10:33:42 -0400822 rpcrdma_cq_async_error_upcall, ep,
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400823 ep->rep_attr.cap.max_send_wr + 1, 0);
Chuck Leverfc664482014-05-28 10:33:25 -0400824 if (IS_ERR(sendcq)) {
825 rc = PTR_ERR(sendcq);
826 dprintk("RPC: %s: failed to create send CQ: %i\n",
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400827 __func__, rc);
828 goto out1;
829 }
830
Chuck Leverfc664482014-05-28 10:33:25 -0400831 rc = ib_req_notify_cq(sendcq, IB_CQ_NEXT_COMP);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400832 if (rc) {
833 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
834 __func__, rc);
835 goto out2;
836 }
837
Chuck Leverfc664482014-05-28 10:33:25 -0400838 recvcq = ib_create_cq(ia->ri_id->device, rpcrdma_recvcq_upcall,
Chuck Lever1c00dd02014-05-28 10:33:42 -0400839 rpcrdma_cq_async_error_upcall, ep,
Chuck Leverfc664482014-05-28 10:33:25 -0400840 ep->rep_attr.cap.max_recv_wr + 1, 0);
841 if (IS_ERR(recvcq)) {
842 rc = PTR_ERR(recvcq);
843 dprintk("RPC: %s: failed to create recv CQ: %i\n",
844 __func__, rc);
845 goto out2;
846 }
847
848 rc = ib_req_notify_cq(recvcq, IB_CQ_NEXT_COMP);
849 if (rc) {
850 dprintk("RPC: %s: ib_req_notify_cq failed: %i\n",
851 __func__, rc);
852 ib_destroy_cq(recvcq);
853 goto out2;
854 }
855
856 ep->rep_attr.send_cq = sendcq;
857 ep->rep_attr.recv_cq = recvcq;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400858
859 /* Initialize cma parameters */
860
861 /* RPC/RDMA does not use private data */
862 ep->rep_remote_cma.private_data = NULL;
863 ep->rep_remote_cma.private_data_len = 0;
864
865 /* Client offers RDMA Read but does not initiate */
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400866 ep->rep_remote_cma.initiator_depth = 0;
Chuck Lever7bc79722015-01-21 11:03:27 -0500867 if (devattr->max_qp_rd_atom > 32) /* arbitrary but <= 255 */
Tom Tuckerb334eaa2008-10-09 15:00:30 -0400868 ep->rep_remote_cma.responder_resources = 32;
869 else
Chuck Lever7bc79722015-01-21 11:03:27 -0500870 ep->rep_remote_cma.responder_resources =
871 devattr->max_qp_rd_atom;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400872
873 ep->rep_remote_cma.retry_count = 7;
874 ep->rep_remote_cma.flow_control = 0;
875 ep->rep_remote_cma.rnr_retry_count = 0;
876
877 return 0;
878
879out2:
Chuck Leverfc664482014-05-28 10:33:25 -0400880 err = ib_destroy_cq(sendcq);
Chuck Lever5d40a8a2007-10-26 13:30:54 -0400881 if (err)
882 dprintk("RPC: %s: ib_destroy_cq returned %i\n",
883 __func__, err);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400884out1:
Chuck Leverc05fbb52015-01-21 11:04:33 -0500885 rpcrdma_free_regbuf(ia, ep->rep_padbuf);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400886 return rc;
887}
888
889/*
890 * rpcrdma_ep_destroy
891 *
892 * Disconnect and destroy endpoint. After this, the only
893 * valid operations on the ep are to free it (if dynamically
894 * allocated) or re-create it.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400895 */
Chuck Lever7f1d5412014-05-28 10:33:16 -0400896void
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400897rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
898{
899 int rc;
900
901 dprintk("RPC: %s: entering, connected is %d\n",
902 __func__, ep->rep_connected);
903
Chuck Lever254f91e2014-05-28 10:32:17 -0400904 cancel_delayed_work_sync(&ep->rep_connect_worker);
905
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400906 if (ia->ri_id->qp) {
Chuck Lever282191c2014-07-29 17:25:55 -0400907 rpcrdma_ep_disconnect(ep, ia);
Tom Talpeyfee08ca2008-10-09 15:01:00 -0400908 rdma_destroy_qp(ia->ri_id);
909 ia->ri_id->qp = NULL;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400910 }
911
Chuck Leverc05fbb52015-01-21 11:04:33 -0500912 rpcrdma_free_regbuf(ia, ep->rep_padbuf);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400913
Chuck Leverfc664482014-05-28 10:33:25 -0400914 rpcrdma_clean_cq(ep->rep_attr.recv_cq);
915 rc = ib_destroy_cq(ep->rep_attr.recv_cq);
916 if (rc)
917 dprintk("RPC: %s: ib_destroy_cq returned %i\n",
918 __func__, rc);
919
920 rpcrdma_clean_cq(ep->rep_attr.send_cq);
921 rc = ib_destroy_cq(ep->rep_attr.send_cq);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400922 if (rc)
923 dprintk("RPC: %s: ib_destroy_cq returned %i\n",
924 __func__, rc);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400925}
926
927/*
928 * Connect unconnected endpoint.
929 */
930int
931rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
932{
Chuck Lever73806c82014-07-29 17:23:25 -0400933 struct rdma_cm_id *id, *old;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400934 int rc = 0;
935 int retry_count = 0;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400936
Tom Talpeyc0555512008-10-10 11:32:45 -0400937 if (ep->rep_connected != 0) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400938 struct rpcrdma_xprt *xprt;
939retry:
Chuck Leverec62f402014-05-28 10:34:07 -0400940 dprintk("RPC: %s: reconnecting...\n", __func__);
Chuck Lever282191c2014-07-29 17:25:55 -0400941
942 rpcrdma_ep_disconnect(ep, ia);
Chuck Levera7bc2112014-07-29 17:23:52 -0400943 rpcrdma_flush_cqs(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400944
945 xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
Chuck Lever31a701a2015-03-30 14:35:07 -0400946 ia->ri_ops->ro_reset(xprt);
947
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400948 id = rpcrdma_create_id(xprt, ia,
949 (struct sockaddr *)&xprt->rx_data.addr);
950 if (IS_ERR(id)) {
Chuck Leverec62f402014-05-28 10:34:07 -0400951 rc = -EHOSTUNREACH;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400952 goto out;
953 }
954 /* TEMP TEMP TEMP - fail if new device:
955 * Deregister/remarshal *all* requests!
956 * Close and recreate adapter, pd, etc!
957 * Re-determine all attributes still sane!
958 * More stuff I haven't thought of!
959 * Rrrgh!
960 */
961 if (ia->ri_id->device != id->device) {
962 printk("RPC: %s: can't reconnect on "
963 "different device!\n", __func__);
964 rdma_destroy_id(id);
Chuck Leverec62f402014-05-28 10:34:07 -0400965 rc = -ENETUNREACH;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400966 goto out;
967 }
968 /* END TEMP */
Chuck Leverec62f402014-05-28 10:34:07 -0400969 rc = rdma_create_qp(id, ia->ri_pd, &ep->rep_attr);
970 if (rc) {
971 dprintk("RPC: %s: rdma_create_qp failed %i\n",
972 __func__, rc);
973 rdma_destroy_id(id);
974 rc = -ENETUNREACH;
975 goto out;
976 }
Chuck Lever73806c82014-07-29 17:23:25 -0400977
978 write_lock(&ia->ri_qplock);
979 old = ia->ri_id;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400980 ia->ri_id = id;
Chuck Lever73806c82014-07-29 17:23:25 -0400981 write_unlock(&ia->ri_qplock);
982
983 rdma_destroy_qp(old);
984 rdma_destroy_id(old);
Chuck Leverec62f402014-05-28 10:34:07 -0400985 } else {
986 dprintk("RPC: %s: connecting...\n", __func__);
987 rc = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr);
988 if (rc) {
989 dprintk("RPC: %s: rdma_create_qp failed %i\n",
990 __func__, rc);
991 /* do not update ep->rep_connected */
992 return -ENETUNREACH;
993 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400994 }
995
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -0400996 ep->rep_connected = 0;
997
998 rc = rdma_connect(ia->ri_id, &ep->rep_remote_cma);
999 if (rc) {
1000 dprintk("RPC: %s: rdma_connect() failed with %i\n",
1001 __func__, rc);
1002 goto out;
1003 }
1004
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001005 wait_event_interruptible(ep->rep_connect_wait, ep->rep_connected != 0);
1006
1007 /*
1008 * Check state. A non-peer reject indicates no listener
1009 * (ECONNREFUSED), which may be a transient state. All
1010 * others indicate a transport condition which has already
1011 * undergone a best-effort.
1012 */
Joe Perchesf64f9e72009-11-29 16:55:45 -08001013 if (ep->rep_connected == -ECONNREFUSED &&
1014 ++retry_count <= RDMA_CONNECT_RETRY_MAX) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001015 dprintk("RPC: %s: non-peer_reject, retry\n", __func__);
1016 goto retry;
1017 }
1018 if (ep->rep_connected <= 0) {
1019 /* Sometimes, the only way to reliably connect to remote
1020 * CMs is to use same nonzero values for ORD and IRD. */
Tom Tuckerb334eaa2008-10-09 15:00:30 -04001021 if (retry_count++ <= RDMA_CONNECT_RETRY_MAX + 1 &&
1022 (ep->rep_remote_cma.responder_resources == 0 ||
1023 ep->rep_remote_cma.initiator_depth !=
1024 ep->rep_remote_cma.responder_resources)) {
1025 if (ep->rep_remote_cma.responder_resources == 0)
1026 ep->rep_remote_cma.responder_resources = 1;
1027 ep->rep_remote_cma.initiator_depth =
1028 ep->rep_remote_cma.responder_resources;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001029 goto retry;
Tom Tuckerb334eaa2008-10-09 15:00:30 -04001030 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001031 rc = ep->rep_connected;
1032 } else {
1033 dprintk("RPC: %s: connected\n", __func__);
1034 }
1035
1036out:
1037 if (rc)
1038 ep->rep_connected = rc;
1039 return rc;
1040}
1041
1042/*
1043 * rpcrdma_ep_disconnect
1044 *
1045 * This is separate from destroy to facilitate the ability
1046 * to reconnect without recreating the endpoint.
1047 *
1048 * This call is not reentrant, and must not be made in parallel
1049 * on the same endpoint.
1050 */
Chuck Lever282191c2014-07-29 17:25:55 -04001051void
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001052rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
1053{
1054 int rc;
1055
Chuck Levera7bc2112014-07-29 17:23:52 -04001056 rpcrdma_flush_cqs(ep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001057 rc = rdma_disconnect(ia->ri_id);
1058 if (!rc) {
1059 /* returns without wait if not connected */
1060 wait_event_interruptible(ep->rep_connect_wait,
1061 ep->rep_connected != 1);
1062 dprintk("RPC: %s: after wait, %sconnected\n", __func__,
1063 (ep->rep_connected == 1) ? "still " : "dis");
1064 } else {
1065 dprintk("RPC: %s: rdma_disconnect %i\n", __func__, rc);
1066 ep->rep_connected = rc;
1067 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001068}
1069
Chuck Lever13924022015-01-21 11:03:52 -05001070static struct rpcrdma_req *
1071rpcrdma_create_req(struct rpcrdma_xprt *r_xprt)
1072{
Chuck Lever13924022015-01-21 11:03:52 -05001073 struct rpcrdma_req *req;
Chuck Lever13924022015-01-21 11:03:52 -05001074
Chuck Lever85275c82015-01-21 11:04:16 -05001075 req = kzalloc(sizeof(*req), GFP_KERNEL);
Chuck Lever13924022015-01-21 11:03:52 -05001076 if (req == NULL)
Chuck Lever85275c82015-01-21 11:04:16 -05001077 return ERR_PTR(-ENOMEM);
Chuck Lever13924022015-01-21 11:03:52 -05001078
Chuck Lever13924022015-01-21 11:03:52 -05001079 req->rl_buffer = &r_xprt->rx_buf;
1080 return req;
Chuck Lever13924022015-01-21 11:03:52 -05001081}
1082
1083static struct rpcrdma_rep *
1084rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt)
1085{
1086 struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
Chuck Lever13924022015-01-21 11:03:52 -05001087 struct rpcrdma_ia *ia = &r_xprt->rx_ia;
1088 struct rpcrdma_rep *rep;
1089 int rc;
1090
1091 rc = -ENOMEM;
Chuck Lever6b1184c2015-01-21 11:04:25 -05001092 rep = kzalloc(sizeof(*rep), GFP_KERNEL);
Chuck Lever13924022015-01-21 11:03:52 -05001093 if (rep == NULL)
1094 goto out;
Chuck Lever13924022015-01-21 11:03:52 -05001095
Chuck Lever6b1184c2015-01-21 11:04:25 -05001096 rep->rr_rdmabuf = rpcrdma_alloc_regbuf(ia, cdata->inline_rsize,
1097 GFP_KERNEL);
1098 if (IS_ERR(rep->rr_rdmabuf)) {
1099 rc = PTR_ERR(rep->rr_rdmabuf);
Chuck Lever13924022015-01-21 11:03:52 -05001100 goto out_free;
Chuck Lever6b1184c2015-01-21 11:04:25 -05001101 }
Chuck Lever13924022015-01-21 11:03:52 -05001102
1103 rep->rr_buffer = &r_xprt->rx_buf;
1104 return rep;
1105
1106out_free:
1107 kfree(rep);
1108out:
1109 return ERR_PTR(rc);
1110}
1111
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001112int
Chuck Leverac920d02015-01-21 11:03:44 -05001113rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001114{
Chuck Leverac920d02015-01-21 11:03:44 -05001115 struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
1116 struct rpcrdma_ia *ia = &r_xprt->rx_ia;
1117 struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001118 char *p;
Chuck Lever13924022015-01-21 11:03:52 -05001119 size_t len;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001120 int i, rc;
1121
1122 buf->rb_max_requests = cdata->max_requests;
1123 spin_lock_init(&buf->rb_lock);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001124
1125 /* Need to allocate:
1126 * 1. arrays for send and recv pointers
1127 * 2. arrays of struct rpcrdma_req to fill in pointers
1128 * 3. array of struct rpcrdma_rep for replies
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001129 * Send/recv buffers in req/rep need to be registered
1130 */
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001131 len = buf->rb_max_requests *
1132 (sizeof(struct rpcrdma_req *) + sizeof(struct rpcrdma_rep *));
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001133
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001134 p = kzalloc(len, GFP_KERNEL);
1135 if (p == NULL) {
1136 dprintk("RPC: %s: req_t/rep_t/pad kzalloc(%zd) failed\n",
1137 __func__, len);
1138 rc = -ENOMEM;
1139 goto out;
1140 }
1141 buf->rb_pool = p; /* for freeing it later */
1142
1143 buf->rb_send_bufs = (struct rpcrdma_req **) p;
1144 p = (char *) &buf->rb_send_bufs[buf->rb_max_requests];
1145 buf->rb_recv_bufs = (struct rpcrdma_rep **) p;
1146 p = (char *) &buf->rb_recv_bufs[buf->rb_max_requests];
1147
Chuck Lever91e70e72015-03-30 14:34:58 -04001148 rc = ia->ri_ops->ro_init(r_xprt);
1149 if (rc)
1150 goto out;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001151
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001152 for (i = 0; i < buf->rb_max_requests; i++) {
1153 struct rpcrdma_req *req;
1154 struct rpcrdma_rep *rep;
1155
Chuck Lever13924022015-01-21 11:03:52 -05001156 req = rpcrdma_create_req(r_xprt);
1157 if (IS_ERR(req)) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001158 dprintk("RPC: %s: request buffer %d alloc"
1159 " failed\n", __func__, i);
Chuck Lever13924022015-01-21 11:03:52 -05001160 rc = PTR_ERR(req);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001161 goto out;
1162 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001163 buf->rb_send_bufs[i] = req;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001164
Chuck Lever13924022015-01-21 11:03:52 -05001165 rep = rpcrdma_create_rep(r_xprt);
1166 if (IS_ERR(rep)) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001167 dprintk("RPC: %s: reply buffer %d alloc failed\n",
1168 __func__, i);
Chuck Lever13924022015-01-21 11:03:52 -05001169 rc = PTR_ERR(rep);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001170 goto out;
1171 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001172 buf->rb_recv_bufs[i] = rep;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001173 }
Chuck Lever13924022015-01-21 11:03:52 -05001174
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001175 return 0;
1176out:
1177 rpcrdma_buffer_destroy(buf);
1178 return rc;
1179}
1180
Chuck Lever2e845222014-07-29 17:25:38 -04001181static void
Chuck Lever13924022015-01-21 11:03:52 -05001182rpcrdma_destroy_rep(struct rpcrdma_ia *ia, struct rpcrdma_rep *rep)
1183{
1184 if (!rep)
1185 return;
1186
Chuck Lever6b1184c2015-01-21 11:04:25 -05001187 rpcrdma_free_regbuf(ia, rep->rr_rdmabuf);
Chuck Lever13924022015-01-21 11:03:52 -05001188 kfree(rep);
1189}
1190
1191static void
1192rpcrdma_destroy_req(struct rpcrdma_ia *ia, struct rpcrdma_req *req)
1193{
1194 if (!req)
1195 return;
1196
Chuck Lever0ca77dc2015-01-21 11:04:08 -05001197 rpcrdma_free_regbuf(ia, req->rl_sendbuf);
Chuck Lever85275c82015-01-21 11:04:16 -05001198 rpcrdma_free_regbuf(ia, req->rl_rdmabuf);
Chuck Lever13924022015-01-21 11:03:52 -05001199 kfree(req);
1200}
1201
1202static void
Chuck Lever2e845222014-07-29 17:25:38 -04001203rpcrdma_destroy_fmrs(struct rpcrdma_buffer *buf)
1204{
1205 struct rpcrdma_mw *r;
1206 int rc;
1207
1208 while (!list_empty(&buf->rb_all)) {
1209 r = list_entry(buf->rb_all.next, struct rpcrdma_mw, mw_all);
1210 list_del(&r->mw_all);
1211 list_del(&r->mw_list);
1212
1213 rc = ib_dealloc_fmr(r->r.fmr);
1214 if (rc)
1215 dprintk("RPC: %s: ib_dealloc_fmr failed %i\n",
1216 __func__, rc);
1217
1218 kfree(r);
1219 }
1220}
1221
1222static void
1223rpcrdma_destroy_frmrs(struct rpcrdma_buffer *buf)
1224{
1225 struct rpcrdma_mw *r;
1226 int rc;
1227
1228 while (!list_empty(&buf->rb_all)) {
1229 r = list_entry(buf->rb_all.next, struct rpcrdma_mw, mw_all);
1230 list_del(&r->mw_all);
1231 list_del(&r->mw_list);
1232
1233 rc = ib_dereg_mr(r->r.frmr.fr_mr);
1234 if (rc)
1235 dprintk("RPC: %s: ib_dereg_mr failed %i\n",
1236 __func__, rc);
1237 ib_free_fast_reg_page_list(r->r.frmr.fr_pgl);
1238
1239 kfree(r);
1240 }
1241}
1242
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001243void
1244rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
1245{
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001246 struct rpcrdma_ia *ia = rdmab_to_ia(buf);
Chuck Lever2e845222014-07-29 17:25:38 -04001247 int i;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001248
1249 /* clean up in reverse order from create
1250 * 1. recv mr memory (mr free, then kfree)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001251 * 2. send mr memory (mr free, then kfree)
Chuck Lever2e845222014-07-29 17:25:38 -04001252 * 3. MWs
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001253 */
1254 dprintk("RPC: %s: entering\n", __func__);
1255
1256 for (i = 0; i < buf->rb_max_requests; i++) {
Chuck Lever13924022015-01-21 11:03:52 -05001257 if (buf->rb_recv_bufs)
1258 rpcrdma_destroy_rep(ia, buf->rb_recv_bufs[i]);
1259 if (buf->rb_send_bufs)
1260 rpcrdma_destroy_req(ia, buf->rb_send_bufs[i]);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001261 }
1262
Chuck Lever2e845222014-07-29 17:25:38 -04001263 switch (ia->ri_memreg_strategy) {
1264 case RPCRDMA_FRMR:
1265 rpcrdma_destroy_frmrs(buf);
1266 break;
1267 case RPCRDMA_MTHCAFMR:
1268 rpcrdma_destroy_fmrs(buf);
1269 break;
1270 default:
1271 break;
Allen Andrews4034ba02014-05-28 10:32:09 -04001272 }
1273
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001274 kfree(buf->rb_pool);
1275}
1276
Chuck Leverc2922c02014-07-29 17:24:36 -04001277/* "*mw" can be NULL when rpcrdma_buffer_get_mrs() fails, leaving
1278 * some req segments uninitialized.
1279 */
1280static void
1281rpcrdma_buffer_put_mr(struct rpcrdma_mw **mw, struct rpcrdma_buffer *buf)
1282{
1283 if (*mw) {
1284 list_add_tail(&(*mw)->mw_list, &buf->rb_mws);
1285 *mw = NULL;
1286 }
1287}
1288
1289/* Cycle mw's back in reverse order, and "spin" them.
1290 * This delays and scrambles reuse as much as possible.
1291 */
1292static void
1293rpcrdma_buffer_put_mrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf)
1294{
1295 struct rpcrdma_mr_seg *seg = req->rl_segments;
1296 struct rpcrdma_mr_seg *seg1 = seg;
1297 int i;
1298
1299 for (i = 1, seg++; i < RPCRDMA_MAX_SEGS; seg++, i++)
Chuck Lever3eb35812015-01-21 11:02:54 -05001300 rpcrdma_buffer_put_mr(&seg->rl_mw, buf);
1301 rpcrdma_buffer_put_mr(&seg1->rl_mw, buf);
Chuck Leverc2922c02014-07-29 17:24:36 -04001302}
1303
1304static void
1305rpcrdma_buffer_put_sendbuf(struct rpcrdma_req *req, struct rpcrdma_buffer *buf)
1306{
1307 buf->rb_send_bufs[--buf->rb_send_index] = req;
1308 req->rl_niovs = 0;
1309 if (req->rl_reply) {
1310 buf->rb_recv_bufs[--buf->rb_recv_index] = req->rl_reply;
1311 req->rl_reply->rr_func = NULL;
1312 req->rl_reply = NULL;
1313 }
1314}
1315
Chuck Lever6814bae2015-03-30 14:34:48 -04001316/* rpcrdma_unmap_one() was already done during deregistration.
Chuck Leverddb6beb2014-07-29 17:24:54 -04001317 * Redo only the ib_post_send().
1318 */
1319static void
1320rpcrdma_retry_local_inv(struct rpcrdma_mw *r, struct rpcrdma_ia *ia)
1321{
1322 struct rpcrdma_xprt *r_xprt =
1323 container_of(ia, struct rpcrdma_xprt, rx_ia);
1324 struct ib_send_wr invalidate_wr, *bad_wr;
1325 int rc;
1326
1327 dprintk("RPC: %s: FRMR %p is stale\n", __func__, r);
1328
1329 /* When this FRMR is re-inserted into rb_mws, it is no longer stale */
Chuck Leverdab7e3b2014-07-29 17:25:20 -04001330 r->r.frmr.fr_state = FRMR_IS_INVALID;
Chuck Leverddb6beb2014-07-29 17:24:54 -04001331
1332 memset(&invalidate_wr, 0, sizeof(invalidate_wr));
1333 invalidate_wr.wr_id = (unsigned long)(void *)r;
1334 invalidate_wr.opcode = IB_WR_LOCAL_INV;
Chuck Leverddb6beb2014-07-29 17:24:54 -04001335 invalidate_wr.ex.invalidate_rkey = r->r.frmr.fr_mr->rkey;
1336 DECR_CQCOUNT(&r_xprt->rx_ep);
1337
1338 dprintk("RPC: %s: frmr %p invalidating rkey %08x\n",
1339 __func__, r, r->r.frmr.fr_mr->rkey);
1340
1341 read_lock(&ia->ri_qplock);
1342 rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr);
1343 read_unlock(&ia->ri_qplock);
1344 if (rc) {
1345 /* Force rpcrdma_buffer_get() to retry */
1346 r->r.frmr.fr_state = FRMR_IS_STALE;
1347 dprintk("RPC: %s: ib_post_send failed, %i\n",
1348 __func__, rc);
1349 }
1350}
1351
1352static void
1353rpcrdma_retry_flushed_linv(struct list_head *stale,
1354 struct rpcrdma_buffer *buf)
1355{
1356 struct rpcrdma_ia *ia = rdmab_to_ia(buf);
1357 struct list_head *pos;
1358 struct rpcrdma_mw *r;
1359 unsigned long flags;
1360
1361 list_for_each(pos, stale) {
1362 r = list_entry(pos, struct rpcrdma_mw, mw_list);
1363 rpcrdma_retry_local_inv(r, ia);
1364 }
1365
1366 spin_lock_irqsave(&buf->rb_lock, flags);
1367 list_splice_tail(stale, &buf->rb_mws);
1368 spin_unlock_irqrestore(&buf->rb_lock, flags);
1369}
1370
Chuck Leverc2922c02014-07-29 17:24:36 -04001371static struct rpcrdma_req *
Chuck Leverddb6beb2014-07-29 17:24:54 -04001372rpcrdma_buffer_get_frmrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf,
1373 struct list_head *stale)
1374{
1375 struct rpcrdma_mw *r;
1376 int i;
1377
1378 i = RPCRDMA_MAX_SEGS - 1;
1379 while (!list_empty(&buf->rb_mws)) {
1380 r = list_entry(buf->rb_mws.next,
1381 struct rpcrdma_mw, mw_list);
1382 list_del(&r->mw_list);
1383 if (r->r.frmr.fr_state == FRMR_IS_STALE) {
1384 list_add(&r->mw_list, stale);
1385 continue;
1386 }
Chuck Lever3eb35812015-01-21 11:02:54 -05001387 req->rl_segments[i].rl_mw = r;
Chuck Leverddb6beb2014-07-29 17:24:54 -04001388 if (unlikely(i-- == 0))
1389 return req; /* Success */
1390 }
1391
1392 /* Not enough entries on rb_mws for this req */
1393 rpcrdma_buffer_put_sendbuf(req, buf);
1394 rpcrdma_buffer_put_mrs(req, buf);
1395 return NULL;
1396}
1397
1398static struct rpcrdma_req *
1399rpcrdma_buffer_get_fmrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf)
Chuck Leverc2922c02014-07-29 17:24:36 -04001400{
1401 struct rpcrdma_mw *r;
1402 int i;
1403
1404 i = RPCRDMA_MAX_SEGS - 1;
1405 while (!list_empty(&buf->rb_mws)) {
1406 r = list_entry(buf->rb_mws.next,
1407 struct rpcrdma_mw, mw_list);
1408 list_del(&r->mw_list);
Chuck Lever3eb35812015-01-21 11:02:54 -05001409 req->rl_segments[i].rl_mw = r;
Chuck Leverc2922c02014-07-29 17:24:36 -04001410 if (unlikely(i-- == 0))
1411 return req; /* Success */
1412 }
1413
1414 /* Not enough entries on rb_mws for this req */
1415 rpcrdma_buffer_put_sendbuf(req, buf);
1416 rpcrdma_buffer_put_mrs(req, buf);
1417 return NULL;
1418}
1419
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001420/*
1421 * Get a set of request/reply buffers.
1422 *
1423 * Reply buffer (if needed) is attached to send buffer upon return.
1424 * Rule:
1425 * rb_send_index and rb_recv_index MUST always be pointing to the
1426 * *next* available buffer (non-NULL). They are incremented after
1427 * removing buffers, and decremented *before* returning them.
1428 */
1429struct rpcrdma_req *
1430rpcrdma_buffer_get(struct rpcrdma_buffer *buffers)
1431{
Chuck Leverc2922c02014-07-29 17:24:36 -04001432 struct rpcrdma_ia *ia = rdmab_to_ia(buffers);
Chuck Leverddb6beb2014-07-29 17:24:54 -04001433 struct list_head stale;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001434 struct rpcrdma_req *req;
1435 unsigned long flags;
1436
1437 spin_lock_irqsave(&buffers->rb_lock, flags);
1438 if (buffers->rb_send_index == buffers->rb_max_requests) {
1439 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1440 dprintk("RPC: %s: out of request buffers\n", __func__);
1441 return ((struct rpcrdma_req *)NULL);
1442 }
1443
1444 req = buffers->rb_send_bufs[buffers->rb_send_index];
1445 if (buffers->rb_send_index < buffers->rb_recv_index) {
1446 dprintk("RPC: %s: %d extra receives outstanding (ok)\n",
1447 __func__,
1448 buffers->rb_recv_index - buffers->rb_send_index);
1449 req->rl_reply = NULL;
1450 } else {
1451 req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
1452 buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
1453 }
1454 buffers->rb_send_bufs[buffers->rb_send_index++] = NULL;
Chuck Leverddb6beb2014-07-29 17:24:54 -04001455
1456 INIT_LIST_HEAD(&stale);
Chuck Leverc2922c02014-07-29 17:24:36 -04001457 switch (ia->ri_memreg_strategy) {
1458 case RPCRDMA_FRMR:
Chuck Leverddb6beb2014-07-29 17:24:54 -04001459 req = rpcrdma_buffer_get_frmrs(req, buffers, &stale);
1460 break;
Chuck Leverc2922c02014-07-29 17:24:36 -04001461 case RPCRDMA_MTHCAFMR:
Chuck Leverddb6beb2014-07-29 17:24:54 -04001462 req = rpcrdma_buffer_get_fmrs(req, buffers);
Chuck Leverc2922c02014-07-29 17:24:36 -04001463 break;
1464 default:
1465 break;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001466 }
1467 spin_unlock_irqrestore(&buffers->rb_lock, flags);
Chuck Leverddb6beb2014-07-29 17:24:54 -04001468 if (!list_empty(&stale))
1469 rpcrdma_retry_flushed_linv(&stale, buffers);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001470 return req;
1471}
1472
1473/*
1474 * Put request/reply buffers back into pool.
1475 * Pre-decrement counter/array index.
1476 */
1477void
1478rpcrdma_buffer_put(struct rpcrdma_req *req)
1479{
1480 struct rpcrdma_buffer *buffers = req->rl_buffer;
1481 struct rpcrdma_ia *ia = rdmab_to_ia(buffers);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001482 unsigned long flags;
1483
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001484 spin_lock_irqsave(&buffers->rb_lock, flags);
Chuck Leverc2922c02014-07-29 17:24:36 -04001485 rpcrdma_buffer_put_sendbuf(req, buffers);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001486 switch (ia->ri_memreg_strategy) {
Tom Talpey3197d3092008-10-09 15:00:20 -04001487 case RPCRDMA_FRMR:
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001488 case RPCRDMA_MTHCAFMR:
Chuck Leverc2922c02014-07-29 17:24:36 -04001489 rpcrdma_buffer_put_mrs(req, buffers);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001490 break;
1491 default:
1492 break;
1493 }
1494 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1495}
1496
1497/*
1498 * Recover reply buffers from pool.
1499 * This happens when recovering from error conditions.
1500 * Post-increment counter/array index.
1501 */
1502void
1503rpcrdma_recv_buffer_get(struct rpcrdma_req *req)
1504{
1505 struct rpcrdma_buffer *buffers = req->rl_buffer;
1506 unsigned long flags;
1507
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001508 spin_lock_irqsave(&buffers->rb_lock, flags);
1509 if (buffers->rb_recv_index < buffers->rb_max_requests) {
1510 req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index];
1511 buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL;
1512 }
1513 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1514}
1515
1516/*
1517 * Put reply buffers back into pool when not attached to
Chuck Leverb45ccfd2014-05-28 10:32:34 -04001518 * request. This happens in error conditions.
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001519 */
1520void
1521rpcrdma_recv_buffer_put(struct rpcrdma_rep *rep)
1522{
1523 struct rpcrdma_buffer *buffers = rep->rr_buffer;
1524 unsigned long flags;
1525
1526 rep->rr_func = NULL;
1527 spin_lock_irqsave(&buffers->rb_lock, flags);
1528 buffers->rb_recv_bufs[--buffers->rb_recv_index] = rep;
1529 spin_unlock_irqrestore(&buffers->rb_lock, flags);
1530}
1531
1532/*
1533 * Wrappers for internal-use kmalloc memory registration, used by buffer code.
1534 */
1535
Chuck Leverdf515ca2015-01-21 11:04:41 -05001536static int
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001537rpcrdma_register_internal(struct rpcrdma_ia *ia, void *va, int len,
1538 struct ib_mr **mrp, struct ib_sge *iov)
1539{
1540 struct ib_phys_buf ipb;
1541 struct ib_mr *mr;
1542 int rc;
1543
1544 /*
1545 * All memory passed here was kmalloc'ed, therefore phys-contiguous.
1546 */
1547 iov->addr = ib_dma_map_single(ia->ri_id->device,
1548 va, len, DMA_BIDIRECTIONAL);
Yan Burmanbf858ab2014-06-19 16:06:30 +03001549 if (ib_dma_mapping_error(ia->ri_id->device, iov->addr))
1550 return -ENOMEM;
1551
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001552 iov->length = len;
1553
Tom Talpeybd7ed1d2008-10-09 15:00:09 -04001554 if (ia->ri_have_dma_lkey) {
1555 *mrp = NULL;
1556 iov->lkey = ia->ri_dma_lkey;
1557 return 0;
1558 } else if (ia->ri_bind_mem != NULL) {
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001559 *mrp = NULL;
1560 iov->lkey = ia->ri_bind_mem->lkey;
1561 return 0;
1562 }
1563
1564 ipb.addr = iov->addr;
1565 ipb.size = iov->length;
1566 mr = ib_reg_phys_mr(ia->ri_pd, &ipb, 1,
1567 IB_ACCESS_LOCAL_WRITE, &iov->addr);
1568
1569 dprintk("RPC: %s: phys convert: 0x%llx "
1570 "registered 0x%llx length %d\n",
Andrew Mortona56daeb2007-10-16 01:29:57 -07001571 __func__, (unsigned long long)ipb.addr,
1572 (unsigned long long)iov->addr, len);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001573
1574 if (IS_ERR(mr)) {
1575 *mrp = NULL;
1576 rc = PTR_ERR(mr);
1577 dprintk("RPC: %s: failed with %i\n", __func__, rc);
1578 } else {
1579 *mrp = mr;
1580 iov->lkey = mr->lkey;
1581 rc = 0;
1582 }
1583
1584 return rc;
1585}
1586
Chuck Leverdf515ca2015-01-21 11:04:41 -05001587static int
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001588rpcrdma_deregister_internal(struct rpcrdma_ia *ia,
1589 struct ib_mr *mr, struct ib_sge *iov)
1590{
1591 int rc;
1592
1593 ib_dma_unmap_single(ia->ri_id->device,
1594 iov->addr, iov->length, DMA_BIDIRECTIONAL);
1595
1596 if (NULL == mr)
1597 return 0;
1598
1599 rc = ib_dereg_mr(mr);
1600 if (rc)
1601 dprintk("RPC: %s: ib_dereg_mr failed %i\n", __func__, rc);
1602 return rc;
1603}
1604
Chuck Lever9128c3e2015-01-21 11:04:00 -05001605/**
1606 * rpcrdma_alloc_regbuf - kmalloc and register memory for SEND/RECV buffers
1607 * @ia: controlling rpcrdma_ia
1608 * @size: size of buffer to be allocated, in bytes
1609 * @flags: GFP flags
1610 *
1611 * Returns pointer to private header of an area of internally
1612 * registered memory, or an ERR_PTR. The registered buffer follows
1613 * the end of the private header.
1614 *
1615 * xprtrdma uses a regbuf for posting an outgoing RDMA SEND, or for
1616 * receiving the payload of RDMA RECV operations. regbufs are not
1617 * used for RDMA READ/WRITE operations, thus are registered only for
1618 * LOCAL access.
1619 */
1620struct rpcrdma_regbuf *
1621rpcrdma_alloc_regbuf(struct rpcrdma_ia *ia, size_t size, gfp_t flags)
1622{
1623 struct rpcrdma_regbuf *rb;
1624 int rc;
1625
1626 rc = -ENOMEM;
1627 rb = kmalloc(sizeof(*rb) + size, flags);
1628 if (rb == NULL)
1629 goto out;
1630
1631 rb->rg_size = size;
1632 rb->rg_owner = NULL;
1633 rc = rpcrdma_register_internal(ia, rb->rg_base, size,
1634 &rb->rg_mr, &rb->rg_iov);
1635 if (rc)
1636 goto out_free;
1637
1638 return rb;
1639
1640out_free:
1641 kfree(rb);
1642out:
1643 return ERR_PTR(rc);
1644}
1645
1646/**
1647 * rpcrdma_free_regbuf - deregister and free registered buffer
1648 * @ia: controlling rpcrdma_ia
1649 * @rb: regbuf to be deregistered and freed
1650 */
1651void
1652rpcrdma_free_regbuf(struct rpcrdma_ia *ia, struct rpcrdma_regbuf *rb)
1653{
1654 if (rb) {
1655 rpcrdma_deregister_internal(ia, rb->rg_mr, &rb->rg_iov);
1656 kfree(rb);
1657 }
1658}
1659
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001660/*
1661 * Wrappers for chunk registration, shared by read/write chunk code.
1662 */
1663
Chuck Lever9c1b4d72015-03-30 14:34:39 -04001664void
1665rpcrdma_map_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg, bool writing)
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001666{
1667 seg->mr_dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
1668 seg->mr_dmalen = seg->mr_len;
1669 if (seg->mr_page)
1670 seg->mr_dma = ib_dma_map_page(ia->ri_id->device,
1671 seg->mr_page, offset_in_page(seg->mr_offset),
1672 seg->mr_dmalen, seg->mr_dir);
1673 else
1674 seg->mr_dma = ib_dma_map_single(ia->ri_id->device,
1675 seg->mr_offset,
1676 seg->mr_dmalen, seg->mr_dir);
Tom Tucker5c635e02011-02-09 19:45:34 +00001677 if (ib_dma_mapping_error(ia->ri_id->device, seg->mr_dma)) {
1678 dprintk("RPC: %s: mr_dma %llx mr_offset %p mr_dma_len %zu\n",
1679 __func__,
Randy Dunlap986d4ab2011-03-15 17:11:59 -07001680 (unsigned long long)seg->mr_dma,
1681 seg->mr_offset, seg->mr_dmalen);
Tom Tucker5c635e02011-02-09 19:45:34 +00001682 }
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001683}
1684
Chuck Lever9c1b4d72015-03-30 14:34:39 -04001685void
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001686rpcrdma_unmap_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg)
1687{
1688 if (seg->mr_page)
1689 ib_dma_unmap_page(ia->ri_id->device,
1690 seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
1691 else
1692 ib_dma_unmap_single(ia->ri_id->device,
1693 seg->mr_dma, seg->mr_dmalen, seg->mr_dir);
1694}
1695
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001696/*
1697 * Prepost any receive buffer, then post send.
1698 *
1699 * Receive buffer is donated to hardware, reclaimed upon recv completion.
1700 */
1701int
1702rpcrdma_ep_post(struct rpcrdma_ia *ia,
1703 struct rpcrdma_ep *ep,
1704 struct rpcrdma_req *req)
1705{
1706 struct ib_send_wr send_wr, *send_wr_fail;
1707 struct rpcrdma_rep *rep = req->rl_reply;
1708 int rc;
1709
1710 if (rep) {
1711 rc = rpcrdma_ep_post_recv(ia, ep, rep);
1712 if (rc)
1713 goto out;
1714 req->rl_reply = NULL;
1715 }
1716
1717 send_wr.next = NULL;
1718 send_wr.wr_id = 0ULL; /* no send cookie */
1719 send_wr.sg_list = req->rl_send_iov;
1720 send_wr.num_sge = req->rl_niovs;
1721 send_wr.opcode = IB_WR_SEND;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001722 if (send_wr.num_sge == 4) /* no need to sync any pad (constant) */
1723 ib_dma_sync_single_for_device(ia->ri_id->device,
1724 req->rl_send_iov[3].addr, req->rl_send_iov[3].length,
1725 DMA_TO_DEVICE);
1726 ib_dma_sync_single_for_device(ia->ri_id->device,
1727 req->rl_send_iov[1].addr, req->rl_send_iov[1].length,
1728 DMA_TO_DEVICE);
1729 ib_dma_sync_single_for_device(ia->ri_id->device,
1730 req->rl_send_iov[0].addr, req->rl_send_iov[0].length,
1731 DMA_TO_DEVICE);
1732
1733 if (DECR_CQCOUNT(ep) > 0)
1734 send_wr.send_flags = 0;
1735 else { /* Provider must take a send completion every now and then */
1736 INIT_CQCOUNT(ep);
1737 send_wr.send_flags = IB_SEND_SIGNALED;
1738 }
1739
1740 rc = ib_post_send(ia->ri_id->qp, &send_wr, &send_wr_fail);
1741 if (rc)
1742 dprintk("RPC: %s: ib_post_send returned %i\n", __func__,
1743 rc);
1744out:
1745 return rc;
1746}
1747
1748/*
1749 * (Re)post a receive buffer.
1750 */
1751int
1752rpcrdma_ep_post_recv(struct rpcrdma_ia *ia,
1753 struct rpcrdma_ep *ep,
1754 struct rpcrdma_rep *rep)
1755{
1756 struct ib_recv_wr recv_wr, *recv_wr_fail;
1757 int rc;
1758
1759 recv_wr.next = NULL;
1760 recv_wr.wr_id = (u64) (unsigned long) rep;
Chuck Lever6b1184c2015-01-21 11:04:25 -05001761 recv_wr.sg_list = &rep->rr_rdmabuf->rg_iov;
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001762 recv_wr.num_sge = 1;
1763
1764 ib_dma_sync_single_for_cpu(ia->ri_id->device,
Chuck Lever6b1184c2015-01-21 11:04:25 -05001765 rdmab_addr(rep->rr_rdmabuf),
1766 rdmab_length(rep->rr_rdmabuf),
1767 DMA_BIDIRECTIONAL);
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001768
\"Talpey, Thomas\c56c65f2007-09-10 13:51:18 -04001769 rc = ib_post_recv(ia->ri_id->qp, &recv_wr, &recv_wr_fail);
1770
1771 if (rc)
1772 dprintk("RPC: %s: ib_post_recv returned %i\n", __func__,
1773 rc);
1774 return rc;
1775}
Chuck Lever43e95982014-07-29 17:23:34 -04001776
Chuck Lever1c9351e2015-03-30 14:34:30 -04001777/* How many chunk list items fit within our inline buffers?
Chuck Lever43e95982014-07-29 17:23:34 -04001778 */
Chuck Lever1c9351e2015-03-30 14:34:30 -04001779unsigned int
1780rpcrdma_max_segments(struct rpcrdma_xprt *r_xprt)
Chuck Lever43e95982014-07-29 17:23:34 -04001781{
1782 struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
Chuck Lever1c9351e2015-03-30 14:34:30 -04001783 int bytes, segments;
Chuck Lever43e95982014-07-29 17:23:34 -04001784
Chuck Lever1c9351e2015-03-30 14:34:30 -04001785 bytes = min_t(unsigned int, cdata->inline_wsize, cdata->inline_rsize);
1786 bytes -= RPCRDMA_HDRLEN_MIN;
1787 if (bytes < sizeof(struct rpcrdma_segment) * 2) {
1788 pr_warn("RPC: %s: inline threshold too small\n",
1789 __func__);
1790 return 0;
Chuck Lever43e95982014-07-29 17:23:34 -04001791 }
Chuck Lever1c9351e2015-03-30 14:34:30 -04001792
1793 segments = 1 << (fls(bytes / sizeof(struct rpcrdma_segment)) - 1);
1794 dprintk("RPC: %s: max chunk list size = %d segments\n",
1795 __func__, segments);
1796 return segments;
Chuck Lever43e95982014-07-29 17:23:34 -04001797}