summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/ib/clients/rdsv3/rdsv3_impl.h
blob: c462306418ea1a884826f8d198b010617d38b633 (plain)
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 */