1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _RDSV3_IMPL_H
#define _RDSV3_IMPL_H
#include <sys/atomic.h>
/*
* This file is only present in Solaris
*/
#ifdef __cplusplus
extern "C" {
#endif
extern dev_info_t *rdsv3_dev_info;
#define uint16_be_t uint16_t
#define uint32_be_t uint32_t
#define uint64_be_t uint64_t
/*
* RDS Well known service id
* Format: 0x1h00144Fhhhhhhhh
* "00144F" is the Sun OUI
* 'h' can be any hex-decimal digit.
*/
#define RDS_SERVICE_ID 0x1000144F00000001ULL
/*
* Atomic operations
*/
typedef unsigned int atomic_t;
#define ATOMIC_INIT(a) a
#define atomic_get(p) (*(p))
#define atomic_cmpset_long(p, c, n) \
((c == atomic_cas_uint(p, c, n)) ? c : -1)
#define atomic_dec_and_test(a) \
(atomic_dec_uint_nv((a)) == 0)
#define atomic_cmpxchg(a, o, n) \
atomic_cas_uint(a, o, n)
#ifdef _LP64
#define set_bit(b, p) \
atomic_or_ulong(((volatile ulong_t *)(void *)(p)) + ((b) >> 6), \
1ul << ((b) & 0x3f))
#define clear_bit(b, p) \
atomic_and_ulong(((volatile ulong_t *)(void *)(p)) + ((b) >> 6), \
~(1ul << ((b) & 0x3f)))
#define test_bit(b, p) \
(((volatile ulong_t *)(void *)(p))[(b) >> 6] & (1ul << ((b) & 0x3f)))
#define test_and_set_bit(b, p) \
atomic_set_long_excl(((ulong_t *)(void *)(p)) + \
((b) >> 6), ((b) & 0x3f))
#define test_and_clear_bit(b, p) \
!atomic_clear_long_excl(((ulong_t *)(void *)(p)) + ((b) >> 6), \
((b) & 0x3f))
#else
#define set_bit(b, p) \
atomic_or_uint(((volatile uint_t *)(void *)p) + (b >> 5), \
1ul << (b & 0x1f))
#define clear_bit(b, p) \
atomic_and_uint(((volatile uint_t *)(void *)p) + (b >> 5), \
~(1ul << (b & 0x1f)))
#define test_bit(b, p) \
(((volatile uint_t *)(void *)p)[b >> 5] & (1ul << (b & 0x1f)))
#define test_and_set_bit(b, p) \
atomic_set_long_excl(((ulong_t *)(void *)p) + (b >> 5), (b & 0x1f))
#define test_and_clear_bit(b, p) \
!atomic_clear_long_excl(((ulong_t *)(void *)p) + (b >> 5), (b & 0x1f))
#endif
/*
* These macros and/or constants are used instead of Linux
* generic_{test,__{clear,set}}_le_bit().
*/
#if defined(sparc)
#define LE_BIT_XOR ((BITS_PER_LONG-1) & ~0x7)
#else
#define LE_BIT_XOR 0
#endif
#define set_le_bit(b, p) set_bit(b ^ LE_BIT_XOR, p)
#define clear_le_bit(b, p) clear_bit(b ^ LE_BIT_XOR, p)
#define test_le_bit(b, p) test_bit(b ^ LE_BIT_XOR, p)
extern uint_t rdsv3_one_sec_in_hz;
#define jiffies 100
#define HZ (drv_hztousec(1))
/* setting this to PAGESIZE throws build errors */
#define PAGE_SIZE 4096 /* xxx - fix this */
#define BITS_PER_LONG (sizeof (unsigned long) * 8)
/* debug */
#define RDSV3_PANIC() cmn_err(CE_PANIC, "Panic forced by RDSV3");
/* ERR */
#define MAX_ERRNO 4095
#define ERR_PTR(x) ((void *)(uintptr_t)x)
#define IS_ERR(ptr) (((uintptr_t)ptr) >= (uintptr_t)-MAX_ERRNO)
#define PTR_ERR(ptr) (int)(uintptr_t)ptr
#define MAX_SCHEDULE_TIMEOUT (~0UL>>1)
/* list */
/* copied and modified list_remove_node */
#define list_remove_node(node) \
if ((node)->list_next != NULL) { \
(node)->list_prev->list_next = (node)->list_next; \
(node)->list_next->list_prev = (node)->list_prev; \
(node)->list_next = (node)->list_prev = NULL; \
}
#define list_splice(src, dst) { \
list_create(dst, (src)->list_size, (src)->list_offset); \
list_move_tail(dst, src); \
}
#define RDSV3_FOR_EACH_LIST_NODE(objp, listp, member) \
for (objp = list_head(listp); objp; objp = list_next(listp, objp))
#define RDSV3_FOR_EACH_LIST_NODE_SAFE(objp, tmp, listp, member) \
for (objp = list_head(listp), tmp = (objp != NULL) ? \
list_next(listp, objp) : NULL; \
objp; \
objp = tmp, tmp = (objp != NULL) ? \
list_next(listp, objp) : NULL)
/* simulate wait_queue_head_t */
typedef struct rdsv3_wait_queue_s {
kmutex_t waitq_mutex;
kcondvar_t waitq_cv;
uint_t waitq_waiters;
} rdsv3_wait_queue_t;
#define rdsv3_init_waitqueue(waitqp) \
mutex_init(&(waitqp)->waitq_mutex, NULL, MUTEX_DRIVER, NULL); \
cv_init(&(waitqp)->waitq_cv, NULL, CV_DRIVER, NULL); \
(waitqp)->waitq_waiters = 0
#define rdsv3_exit_waitqueue(waitqp) \
ASSERT((waitqp)->waitq_waiters == 0); \
mutex_destroy(&(waitqp)->waitq_mutex); \
cv_destroy(&(waitqp)->waitq_cv)
#define rdsv3_wake_up(waitqp) { \
mutex_enter(&(waitqp)->waitq_mutex); \
if ((waitqp)->waitq_waiters) \
cv_signal(&(waitqp)->waitq_cv); \
mutex_exit(&(waitqp)->waitq_mutex); \
}
#define rdsv3_wake_up_all(waitqp) { \
mutex_enter(&(waitqp)->waitq_mutex); \
if ((waitqp)->waitq_waiters) \
cv_broadcast(&(waitqp)->waitq_cv); \
mutex_exit(&(waitqp)->waitq_mutex); \
}
/* analogous to cv_wait */
#define rdsv3_wait_event(waitq, condition) \
{ \
mutex_enter(&(waitq)->waitq_mutex); \
(waitq)->waitq_waiters++; \
while (!(condition)) { \
cv_wait(&(waitq)->waitq_cv, &(waitq)->waitq_mutex); \
} \
(waitq)->waitq_waiters--; \
mutex_exit(&(waitq)->waitq_mutex); \
}
/* analogous to cv_wait_sig */
#define rdsv3_wait_sig(waitqp, condition) \
( \
{ \
int cv_return = 1; \
mutex_enter(&(waitqp)->waitq_mutex); \
(waitqp)->waitq_waiters++; \
while (!(condition)) { \
cv_return = cv_wait_sig(&(waitqp)->waitq_cv, \
&(waitqp)->waitq_mutex); \
if (cv_return == 0) { \
break; \
} \
} \
(waitqp)->waitq_waiters--; \
mutex_exit(&(waitqp)->waitq_mutex); \
cv_return; \
} \
)
#define SOCK_DEAD 1ul
/* socket */
typedef struct rsock {
sock_upper_handle_t sk_upper_handle;
sock_upcalls_t *sk_upcalls;
kmutex_t sk_lock;
ulong_t sk_flag;
rdsv3_wait_queue_t *sk_sleep; /* Also protected by rs_recv_lock */
int sk_sndbuf;
int sk_rcvbuf;
atomic_t sk_refcount;
struct rdsv3_sock *sk_protinfo;
} rsock_t;
typedef struct rdsv3_conn_info_s {
uint32_be_t c_laddr;
uint32_be_t c_faddr;
} rdsv3_conn_info_t;
/* WQ */
typedef struct rdsv3_workqueue_struct_s {
kmutex_t wq_lock;
uint_t wq_state;
int wq_pending;
list_t wq_queue;
} rdsv3_workqueue_struct_t;
struct rdsv3_work_s;
typedef void (*rdsv3_work_func_t)(struct rdsv3_work_s *);
typedef struct rdsv3_work_s {
list_node_t work_item;
rdsv3_work_func_t func;
} rdsv3_work_t;
/* simulate delayed_work */
typedef struct rdsv3_delayed_work_s {
kmutex_t lock;
rdsv3_work_t work;
timeout_id_t timeid;
rdsv3_workqueue_struct_t *wq;
} rdsv3_delayed_work_t;
#define RDSV3_INIT_WORK(wp, f) (wp)->func = f
#define RDSV3_INIT_DELAYED_WORK(dwp, f) \
(dwp)->work.func = f; \
mutex_init(&(dwp)->lock, NULL, MUTEX_DRIVER, NULL); \
(dwp)->timeid = 0
/* simulate scatterlist */
struct rdsv3_scatterlist {
caddr_t vaddr;
uint_t length;
ibt_wr_ds_t *sgl;
ibt_mi_hdl_t mihdl;
};
#define rdsv3_sg_page(scat) (scat)->vaddr
#define rdsv3_sg_len(scat) (scat)->length
#define rdsv3_sg_set_page(scat, pg, len, off) \
(scat)->vaddr = (caddr_t)(pg + off); \
(scat)->length = len
#define rdsv3_ib_sg_dma_len(dev, scat) rdsv3_sg_len(scat)
/* copied from sys/socket.h */
#if defined(__sparc)
/* To maintain backward compatibility, alignment needs to be 8 on sparc. */
#define _CMSG_HDR_ALIGNMENT 8
#else
/* for __i386 (and other future architectures) */
#define _CMSG_HDR_ALIGNMENT 4
#endif /* defined(__sparc) */
/*
* The cmsg headers (and macros dealing with them) were made available as
* part of UNIX95 and hence need to be protected with a _XPG4_2 define.
*/
#define _CMSG_DATA_ALIGNMENT (sizeof (int))
#define _CMSG_HDR_ALIGN(x) (((uintptr_t)(x) + _CMSG_HDR_ALIGNMENT - 1) & \
~(_CMSG_HDR_ALIGNMENT - 1))
#define _CMSG_DATA_ALIGN(x) (((uintptr_t)(x) + _CMSG_DATA_ALIGNMENT - 1) & \
~(_CMSG_DATA_ALIGNMENT - 1))
#define CMSG_DATA(c) \
((unsigned char *)_CMSG_DATA_ALIGN((struct cmsghdr *)(c) + 1))
#define CMSG_FIRSTHDR(m) \
(((m)->msg_controllen < sizeof (struct cmsghdr)) ? \
(struct cmsghdr *)0 : (struct cmsghdr *)((m)->msg_control))
#define CMSG_NXTHDR(m, c) \
(((c) == 0) ? CMSG_FIRSTHDR(m) : \
((((uintptr_t)_CMSG_HDR_ALIGN((char *)(c) + \
((struct cmsghdr *)(c))->cmsg_len) + sizeof (struct cmsghdr)) > \
(((uintptr_t)((struct msghdr *)(m))->msg_control) + \
((uintptr_t)((struct msghdr *)(m))->msg_controllen))) ? \
((struct cmsghdr *)0) : \
((struct cmsghdr *)_CMSG_HDR_ALIGN((char *)(c) + \
((struct cmsghdr *)(c))->cmsg_len))))
/* Amount of space + padding needed for a message of length l */
#define CMSG_SPACE(l) \
((unsigned int)_CMSG_HDR_ALIGN(sizeof (struct cmsghdr) + (l)))
/* Value to be used in cmsg_len, does not include trailing padding */
#define CMSG_LEN(l) \
((unsigned int)_CMSG_DATA_ALIGN(sizeof (struct cmsghdr)) + (l))
/* OFUV -> IB */
#define RDSV3_IBDEV2HCAHDL(device) (device)->hca_hdl
#define RDSV3_QP2CHANHDL(qp) (qp)->ibt_qp
#define RDSV3_PD2PDHDL(pd) (pd)->ibt_pd
#define RDSV3_CQ2CQHDL(cq) (cq)->ibt_cq
struct rdsv3_hdrs_mr {
ibt_lkey_t lkey;
caddr_t addr;
size_t size;
ibt_mr_hdl_t hdl;
};
/* rdsv3_impl.c */
void rdsv3_trans_init();
boolean_t rdsv3_capable_interface(struct lifreq *lifrp);
int rdsv3_do_ip_ioctl(ksocket_t so4, void **ipaddrs, int *size, int *nifs);
int rdsv3_do_ip_ioctl_old(ksocket_t so4, void **ipaddrs, int *size, int *nifs);
boolean_t rdsv3_isloopback(ipaddr_t addr);
void rdsv3_cancel_delayed_work(rdsv3_delayed_work_t *dwp);
void rdsv3_flush_workqueue(rdsv3_workqueue_struct_t *wq);
void rdsv3_queue_work(rdsv3_workqueue_struct_t *wq, rdsv3_work_t *wp);
void rdsv3_queue_delayed_work(rdsv3_workqueue_struct_t *wq,
rdsv3_delayed_work_t *dwp, uint_t delay);
struct rsock *rdsv3_sk_alloc();
void rdsv3_sock_init_data(struct rsock *sk);
void rdsv3_sock_exit_data(struct rsock *sk);
void rdsv3_destroy_task_workqueue(rdsv3_workqueue_struct_t *wq);
rdsv3_workqueue_struct_t *rdsv3_create_task_workqueue(char *name);
int rdsv3_conn_constructor(void *buf, void *arg, int kmflags);
void rdsv3_conn_destructor(void *buf, void *arg);
int rdsv3_conn_compare(const void *conn1, const void *conn2);
void rdsv3_loop_init();
int rdsv3_mr_compare(const void *mr1, const void *mr2);
int rdsv3_put_cmsg(struct nmsghdr *msg, int level, int type, size_t size,
void *payload);
int rdsv3_verify_bind_address(ipaddr_t addr);
uint16_t rdsv3_ip_fast_csum(void *buffer, size_t length);
uint_t rdsv3_ib_dma_map_sg(struct ib_device *dev, struct rdsv3_scatterlist
*scat, uint_t num);
void rdsv3_ib_dma_unmap_sg(ib_device_t *dev, struct rdsv3_scatterlist *scat,
uint_t num);
static inline void
rdsv3_sk_sock_hold(struct rsock *sk)
{
atomic_inc_32(&sk->sk_refcount);
}
static inline void
rdsv3_sk_sock_put(struct rsock *sk)
{
if (atomic_dec_and_test(&sk->sk_refcount))
rdsv3_sock_exit_data(sk);
}
static inline int
rdsv3_sk_sock_flag(struct rsock *sk, uint_t flag)
{
return (test_bit(flag, &sk->sk_flag));
}
static inline void
rdsv3_sk_sock_orphan(struct rsock *sk)
{
set_bit(SOCK_DEAD, &sk->sk_flag);
}
#define rdsv3_sndtimeo(a, b) b ? 0 : 3600 /* check this value on linux */
#define rdsv3_rcvtimeo(a, b) b ? 0 : 3600 /* check this value on linux */
void rdsv3_ib_free_conn(void *arg);
#ifdef __cplusplus
}
#endif
#endif /* _RDSV3_IMPL_H */
|