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