Old rdma_subr.c
1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "@(#)rdma_subr.c 1.11 05/06/08 SMI"
28
29 #include <sys/systm.h>
30 #include <sys/kstat.h>
31 #include <sys/modctl.h>
32 #include <rpc/rpc_rdma.h>
33
34 #include <sys/ib/ibtl/ibti.h>
35
36 /*
37 * RDMA chunk size
38 */
39 #define RDMA_MINCHUNK 1024
40 uint_t rdma_minchunk = RDMA_MINCHUNK;
41
42 /*
43 * Globals
44 */
45 int rdma_modloaded = 0; /* flag to load RDMA plugin modules */
46 int rdma_dev_available = 0; /* if any RDMA device is loaded */
47 kmutex_t rdma_modload_lock; /* protects rdma_modloaded flag */
48 rdma_registry_t *rdma_mod_head = NULL; /* head for RDMA modules */
49 krwlock_t rdma_lock; /* protects rdma_mod_head list */
50 ldi_ident_t rpcmod_li = NULL; /* identifies us with ldi_ framework */
51
52 /*
53 * Statics
54 */
55 static ldi_handle_t rpcib_handle = NULL;
56
57 /*
58 * Externs
59 */
60 extern kstat_named_t *rdmarcstat_ptr;
61 extern uint_t rdmarcstat_ndata;
62 extern kstat_named_t *rdmarsstat_ptr;
63 extern uint_t rdmarsstat_ndata;
64
65 void rdma_kstat_init();
66
67 /*
68 * RDMATF module registration routine.
69 * This routine is expected to be called by the init routine in
70 * the plugin modules.
71 */
72 rdma_stat
73 rdma_register_mod(rdma_mod_t *mod)
74 {
75 rdma_registry_t **mp, *m;
76
77 if (mod->rdma_version != RDMATF_VERS) {
78 return (RDMA_BADVERS);
79 }
80
81 rw_enter(&rdma_lock, RW_WRITER);
82 /*
83 * Ensure not already registered
84 */
85 mp = &rdma_mod_head;
86 while (*mp != NULL) {
87 if (strncmp((*mp)->r_mod->rdma_api, mod->rdma_api,
88 KNC_STRSIZE) == 0) {
89 rw_exit(&rdma_lock);
90 return (RDMA_REG_EXIST);
91 }
92 mp = &((*mp)->r_next);
93 }
94
95 /*
96 * New one, create and add to registry
97 */
98 m = kmem_alloc(sizeof (rdma_registry_t), KM_SLEEP);
99 m->r_mod = kmem_alloc(sizeof (rdma_mod_t), KM_SLEEP);
100 *m->r_mod = *mod;
101 m->r_next = NULL;
102 m->r_mod->rdma_api = kmem_zalloc(KNC_STRSIZE, KM_SLEEP);
103 (void) strncpy(m->r_mod->rdma_api, mod->rdma_api, KNC_STRSIZE);
104 m->r_mod->rdma_api[KNC_STRSIZE - 1] = '\0';
105 *mp = m;
106 rw_exit(&rdma_lock);
107
108 return (RDMA_SUCCESS);
109 }
110
111 /*
112 * RDMATF module unregistration routine.
113 * This routine is expected to be called by the fini routine in
114 * the plugin modules.
115 */
116 rdma_stat
117 rdma_unregister_mod(rdma_mod_t *mod)
118 {
119 rdma_registry_t **m, *mmod = NULL;
120
121 rw_enter(&rdma_lock, RW_WRITER);
122
123 m = &rdma_mod_head;
124 while (*m != NULL) {
125 if (strncmp((*m)->r_mod->rdma_api, mod->rdma_api,
126 KNC_STRSIZE) != 0) {
127 m = &((*m)->r_next);
128 continue;
129 }
130 /*
131 * Check if any device attached, if so return error
132 */
133 if ((*m)->r_mod->rdma_count != 0) {
134 rw_exit(&rdma_lock);
135 return (RDMA_FAILED);
136 }
137 /*
138 * Found entry. Now remove it.
139 */
140 mmod = *m;
141 *m = (*m)->r_next;
142 kmem_free(mmod->r_mod->rdma_api, KNC_STRSIZE);
143 kmem_free(mmod->r_mod, sizeof (rdma_mod_t));
144 kmem_free(mmod, sizeof (rdma_registry_t));
145 rw_exit(&rdma_lock);
146 return (RDMA_SUCCESS);
147 }
148
149 /*
150 * Not found.
151 */
152 rw_exit(&rdma_lock);
153 return (RDMA_FAILED);
154 }
155
156 /*
157 * Creates a new chunk list entry, and
158 * adds it to the end of a chunk list.
159 */
160 void
161 clist_add(struct clist **clp, uint32_t xdroff, int len,
162 struct mrc *shandle, caddr_t saddr,
163 struct mrc *dhandle, caddr_t daddr)
164 {
165 struct clist *cl;
166
167 /* Find the end of the list */
168
169 while (*clp != NULL)
170 clp = &((*clp)->c_next);
171
172 cl = kmem_zalloc(sizeof (*cl), KM_SLEEP);
173 cl->c_xdroff = xdroff;
174 cl->c_len = len;
175 cl->c_saddr = (uint64_t)(uintptr_t)saddr;
176 if (shandle)
177 cl->c_smemhandle = *shandle;
178 cl->c_daddr = (uint64_t)(uintptr_t)daddr;
179 if (dhandle)
180 cl->c_dmemhandle = *dhandle;
181 cl->c_next = NULL;
182
183 *clp = cl;
184 }
185
186 int
187 clist_register(CONN *conn, struct clist *cl, bool_t src)
188 {
189 struct clist *c;
190 int status;
191
192 for (c = cl; c; c = c->c_next) {
193 if (src) {
194 status = RDMA_REGMEMSYNC(conn,
195 (caddr_t)(uintptr_t)c->c_saddr, c->c_len,
196 &c->c_smemhandle, (void **)&c->c_ssynchandle);
197 } else {
198 status = RDMA_REGMEMSYNC(conn,
199 (caddr_t)(uintptr_t)c->c_daddr, c->c_len,
200 &c->c_dmemhandle, (void **)&c->c_dsynchandle);
201 }
202 if (status != RDMA_SUCCESS) {
203 (void) clist_deregister(conn, cl, src);
204 return (status);
205 }
206 }
207
208 return (RDMA_SUCCESS);
209 }
210
211 int
212 clist_deregister(CONN *conn, struct clist *cl, bool_t src)
213 {
214 struct clist *c;
215
216 for (c = cl; c; c = c->c_next) {
217 if (src) {
218 if (c->c_smemhandle.mrc_rmr != 0) {
219 (void) RDMA_DEREGMEMSYNC(conn,
220 (caddr_t)(uintptr_t)c->c_saddr,
221 c->c_smemhandle,
222 (void *)(uintptr_t)c->c_ssynchandle);
223 c->c_smemhandle.mrc_rmr = 0;
224 c->c_ssynchandle = NULL;
225 }
226 } else {
227 if (c->c_dmemhandle.mrc_rmr != 0) {
228 (void) RDMA_DEREGMEMSYNC(conn,
229 (caddr_t)(uintptr_t)c->c_daddr,
230 c->c_dmemhandle,
231 (void *)(uintptr_t)c->c_dsynchandle);
232 c->c_dmemhandle.mrc_rmr = 0;
233 c->c_dsynchandle = NULL;
234 }
235 }
236 }
237
238 return (RDMA_SUCCESS);
239 }
240
241 /*
242 * Frees up entries in chunk list
243 */
244 void
245 clist_free(struct clist *cl)
246 {
247 struct clist *c = cl;
248
249 while (c != NULL) {
250 cl = cl->c_next;
251 kmem_free(c, sizeof (struct clist));
252 c = cl;
253 }
254 }
255
256 rdma_stat
257 rdma_clnt_postrecv(CONN *conn, uint32_t xid)
258 {
259 struct clist *cl = NULL;
260 rdma_stat retval;
261 rdma_buf_t rbuf;
262
263 rbuf.type = RECV_BUFFER;
264 if (RDMA_BUF_ALLOC(conn, &rbuf)) {
265 retval = RDMA_NORESOURCE;
266 } else {
267 clist_add(&cl, 0, rbuf.len, &rbuf.handle, rbuf.addr,
268 NULL, NULL);
269 retval = RDMA_CLNT_RECVBUF(conn, cl, xid);
270 clist_free(cl);
271 }
272 return (retval);
273 }
274
275 rdma_stat
276 rdma_svc_postrecv(CONN *conn)
277 {
278 struct clist *cl = NULL;
279 rdma_stat retval;
280 rdma_buf_t rbuf;
281
282 rbuf.type = RECV_BUFFER;
283 if (RDMA_BUF_ALLOC(conn, &rbuf)) {
284 retval = RDMA_NORESOURCE;
285 } else {
286 clist_add(&cl, 0, rbuf.len, &rbuf.handle, rbuf.addr,
287 NULL, NULL);
288 retval = RDMA_SVC_RECVBUF(conn, cl);
289 clist_free(cl);
290 }
291 return (retval);
292 }
293
294 rdma_stat
295 clist_syncmem(CONN *conn, struct clist *cl, bool_t src)
296 {
297 struct clist *c;
298 rdma_stat status;
299
300 c = cl;
301 if (src) {
302 while (c != NULL) {
303 status = RDMA_SYNCMEM(conn,
304 (void *)(uintptr_t)c->c_ssynchandle,
305 (caddr_t)(uintptr_t)c->c_saddr, c->c_len, 0);
306 if (status != RDMA_SUCCESS)
307 return (status);
308 c = c->c_next;
309 }
310 } else {
311 while (c != NULL) {
312 status = RDMA_SYNCMEM(conn,
313 (void *)(uintptr_t)c->c_dsynchandle,
314 (caddr_t)(uintptr_t)c->c_daddr, c->c_len, 1);
315 if (status != RDMA_SUCCESS)
316 return (status);
317 c = c->c_next;
318 }
319 }
320 return (RDMA_SUCCESS);
321 }
322
323 void
324 rdma_buf_free(CONN *conn, rdma_buf_t *rbuf)
325 {
326 if (!rbuf || rbuf->addr == NULL) {
327 return;
328 }
329 if (rbuf->type != CHUNK_BUFFER) {
330 /* pool buffer */
331 RDMA_BUF_FREE(conn, rbuf);
332 } else {
333 kmem_free(rbuf->addr, rbuf->len);
334 }
335 rbuf->addr = NULL;
336 rbuf->len = 0;
337 }
338
339 /*
340 * Caller is holding rdma_modload_lock mutex
341 */
342 int
343 rdma_modload()
344 {
345 int status;
346 ASSERT(MUTEX_HELD(&rdma_modload_lock));
347 /*
348 * Load all available RDMA plugins which right now is only IB plugin.
349 * If no IB hardware is present, then quit right away.
350 * ENODEV -- For no device on the system
351 * EPROTONOSUPPORT -- For module not avilable either due to failure to
352 * load or some other reason.
353 */
354 rdma_modloaded = 1;
355 if (ibt_hw_is_present() == 0) {
356 rdma_dev_available = 0;
357 return (ENODEV);
358 }
359
360 rdma_dev_available = 1;
361 if (rpcmod_li == NULL)
362 return (EPROTONOSUPPORT);
363
364 status = ldi_open_by_name("/devices/ib/rpcib@0:rpcib",
365 FREAD | FWRITE, kcred,
366 &rpcib_handle, rpcmod_li);
367 if (status != 0)
368 return (EPROTONOSUPPORT);
369
370 /* success */
371 rdma_kstat_init();
372 return (0);
373 }
374
375 void
376 rdma_kstat_init(void)
377 {
378 kstat_t *ksp;
379
380 /*
381 * The RDMA framework doesn't know how to deal with Zones, and is
382 * only available in the global zone.
383 */
384 ASSERT(INGLOBALZONE(curproc));
385 ksp = kstat_create_zone("unix", 0, "rpc_rdma_client", "rpc",
386 KSTAT_TYPE_NAMED, rdmarcstat_ndata,
387 KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE, GLOBAL_ZONEID);
388 if (ksp) {
389 ksp->ks_data = (void *) rdmarcstat_ptr;
390 kstat_install(ksp);
391 }
392
393 ksp = kstat_create_zone("unix", 0, "rpc_rdma_server", "rpc",
394 KSTAT_TYPE_NAMED, rdmarsstat_ndata,
395 KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE, GLOBAL_ZONEID);
396 if (ksp) {
397 ksp->ks_data = (void *) rdmarsstat_ptr;
398 kstat_install(ksp);
399 }
400 }