xref: /illumos-gate/usr/src/uts/common/io/ib/clients/rdsv3/rdsv3_ddi.c (revision 5d5562f583b2b6affe19bdce0b3c8b1840d667a4)
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  */
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/conf.h>
27 #include <sys/ddi.h>
28 #include <sys/sunddi.h>
29 #include <sys/modctl.h>
30 #include <sys/strsubr.h>
31 #include <sys/socketvar.h>
32 #include <sys/rds.h>
33 
34 #include <sys/ib/ibtl/ibti.h>
35 #include <sys/ib/clients/rdsv3/rdsv3.h>
36 #include <sys/ib/clients/rdsv3/rdsv3_debug.h>
37 #include <sys/ib/clients/rdsv3/rdsv3_af_thr.h>
38 
39 extern int rdsv3_init(void);
40 extern void rdsv3_exit(void);
41 extern void rdsv3_cong_init(void);
42 extern void rdsv3_cong_exit(void);
43 extern void rdsv3_trans_init(void);
44 extern void rdsv3_trans_exit(void);
45 extern int rdsv3_sock_init(void);
46 extern void rdsv3_sock_exit(void);
47 
48 /* global */
49 dev_info_t	*rdsv3_dev_info = NULL;
50 kmem_cache_t	*rdsv3_alloc_cache = NULL;
51 
52 extern kmutex_t rdsv3_rdma_listen_id_lock;
53 extern struct rdma_cm_id *rdsv3_rdma_listen_id;
54 
55 extern kmutex_t rdsv3_sock_lock;
56 extern list_t rdsv3_sock_list;
57 
58 extern void rdsv3_bind_tree_init();
59 extern void rdsv3_bind_tree_exit();
60 
61 int
62 rdsv3_sock_init()
63 {
64 	RDSV3_DPRINTF4("rdsv3_sock_init", "Enter");
65 
66 	rdsv3_alloc_cache = kmem_cache_create("rdsv3_alloc_cache",
67 	    sizeof (struct rsock) + sizeof (struct rdsv3_sock), 0, NULL,
68 	    NULL, NULL, NULL, NULL, 0);
69 	if (rdsv3_alloc_cache == NULL) {
70 		RDSV3_DPRINTF2("rdsv3_alloc_cache",
71 		    "kmem_cache_create(rdsv3_alloc_cache) failed");
72 		return (-1);
73 	}
74 	rdsv3_bind_tree_init();
75 
76 	mutex_init(&rdsv3_sock_lock, NULL, MUTEX_DRIVER, NULL);
77 	list_create(&rdsv3_sock_list, sizeof (struct rdsv3_sock),
78 	    offsetof(struct rdsv3_sock, rs_item));
79 
80 	RDSV3_DPRINTF4("rdsv3_sock_init", "Return");
81 
82 	return (0);
83 }
84 
85 void
86 rdsv3_sock_exit()
87 {
88 	RDSV3_DPRINTF2("rdsv3_sock_exit", "Enter");
89 
90 	rdsv3_bind_tree_exit();
91 
92 	kmem_cache_destroy(rdsv3_alloc_cache);
93 
94 	list_destroy(&rdsv3_sock_list);
95 	mutex_destroy(&rdsv3_sock_lock);
96 
97 	RDSV3_DPRINTF2("rdsv3_sock_exit", "Return");
98 }
99 
100 static int
101 rdsv3_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
102 {
103 	int	ret;
104 
105 	RDSV3_DPRINTF2("rdsv3_attach", "Enter (dip: %p)", dip);
106 
107 	if (cmd != DDI_ATTACH)
108 		return (DDI_FAILURE);
109 
110 	if (rdsv3_dev_info != NULL) {
111 		RDSV3_DPRINTF2("rdsv3_attach", "Multiple RDS instances are"
112 		    " not supported (rdsv3_dev_info: 0x%p)", rdsv3_dev_info);
113 		return (DDI_FAILURE);
114 	}
115 	rdsv3_dev_info = dip;
116 
117 	mutex_init(&rdsv3_rdma_listen_id_lock, NULL, MUTEX_DRIVER, NULL);
118 	rdsv3_rdma_listen_id = NULL;
119 
120 	rdsv3_af_init(dip);
121 	rdsv3_trans_init();
122 	ret = rdsv3_init();
123 	if (ret) {
124 		RDSV3_DPRINTF2("rdsv3_attach", "rdsv3_init failed: %d", ret);
125 		rdsv3_trans_exit();
126 		mutex_destroy(&rdsv3_rdma_listen_id_lock);
127 		rdsv3_dev_info = NULL;
128 		return (DDI_FAILURE);
129 	}
130 
131 	ret = rdsv3_sock_init();
132 	if (ret) {
133 		rdsv3_exit();
134 		rdsv3_trans_exit();
135 		mutex_destroy(&rdsv3_rdma_listen_id_lock);
136 		rdsv3_dev_info = NULL;
137 		return (DDI_FAILURE);
138 	}
139 
140 	ret = ddi_create_minor_node(dip, "rdsv3", S_IFCHR, 0, DDI_PSEUDO, 0);
141 	if (ret != DDI_SUCCESS) {
142 		cmn_err(CE_CONT, "ddi_create_minor_node failed: %d", ret);
143 		rdsv3_sock_exit();
144 		rdsv3_exit();
145 		rdsv3_trans_exit();
146 		mutex_destroy(&rdsv3_rdma_listen_id_lock);
147 		rdsv3_dev_info = NULL;
148 		return (DDI_FAILURE);
149 	}
150 
151 	RDSV3_DPRINTF2("rdsv3_attach", "Return");
152 
153 	return (DDI_SUCCESS);
154 }
155 
156 static int
157 rdsv3_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
158 {
159 	RDSV3_DPRINTF2("rdsv3_detach", "Enter (dip: %p)", dip);
160 
161 	if (cmd != DDI_DETACH)
162 		return (DDI_FAILURE);
163 
164 	rdsv3_sock_exit();
165 	rdsv3_exit();
166 	rdsv3_trans_exit();
167 	ddi_remove_minor_node(dip, "rdsv3");
168 	rdsv3_dev_info = NULL;
169 
170 	RDSV3_DPRINTF2("rdsv3_detach", "Return");
171 
172 	return (DDI_SUCCESS);
173 }
174 
175 /* ARGSUSED */
176 static int
177 rdsv3_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
178 {
179 	int ret = DDI_FAILURE;
180 
181 	RDSV3_DPRINTF2("rdsv3_info", "Enter (dip: %p, cmd: %d)", dip, cmd);
182 
183 	switch (cmd) {
184 	case DDI_INFO_DEVT2DEVINFO:
185 		if (rdsv3_dev_info != NULL) {
186 			*result = (void *)rdsv3_dev_info;
187 			ret = DDI_SUCCESS;
188 		}
189 		break;
190 
191 	case DDI_INFO_DEVT2INSTANCE:
192 		*result = NULL;
193 		ret = DDI_SUCCESS;
194 		break;
195 
196 	default:
197 		break;
198 	}
199 
200 	RDSV3_DPRINTF4("rdsv3_info", "Return");
201 
202 	return (ret);
203 }
204 
205 /* Driver entry points */
206 static struct cb_ops	rdsv3_cb_ops = {
207 	nulldev,		/* open */
208 	nulldev,		/* close */
209 	nodev,			/* strategy */
210 	nodev,			/* print */
211 	nodev,			/* dump */
212 	nodev,			/* read */
213 	nodev,			/* write */
214 	nodev,			/* ioctl */
215 	nodev,			/* devmap */
216 	nodev,			/* mmap */
217 	nodev,			/* segmap */
218 	nochpoll,		/* poll */
219 	ddi_prop_op,		/* prop_op */
220 	NULL,			/* stream */
221 	D_MP,			/* cb_flag */
222 	CB_REV,			/* rev */
223 	nodev,			/* int (*cb_aread)() */
224 	nodev,			/* int (*cb_awrite)() */
225 };
226 
227 /* Device options */
228 static struct dev_ops rdsv3_ops = {
229 	DEVO_REV,		/* devo_rev, */
230 	0,			/* refcnt  */
231 	rdsv3_info,		/* info */
232 	nulldev,		/* identify */
233 	nulldev,		/* probe */
234 	rdsv3_attach,		/* attach */
235 	rdsv3_detach,		/* detach */
236 	nodev,			/* reset */
237 	&rdsv3_cb_ops,		/* driver ops - devctl interfaces */
238 	NULL,			/* bus operations */
239 	NULL,			/* power */
240 	ddi_quiesce_not_needed	/* quiesce */
241 };
242 
243 /*
244  * Module linkage information.
245  */
246 #define	RDSV3_DEVDESC	"RDSv3 IB transport driver"
247 static struct modldrv rdsv3_modldrv = {
248 	&mod_driverops,		/* Driver module */
249 	RDSV3_DEVDESC,		/* Driver name and version */
250 	&rdsv3_ops,		/* Driver ops */
251 };
252 
253 static struct modlinkage rdsv3_modlinkage = {
254 	MODREV_1,
255 	(void *)&rdsv3_modldrv,
256 	NULL
257 };
258 
259 int
260 _init(void)
261 {
262 	int	ret;
263 
264 	if (ibt_hw_is_present() == 0) {
265 		return (ENODEV);
266 	}
267 
268 	/* Initialize logging */
269 	rdsv3_logging_initialization();
270 
271 	ret = mod_install(&rdsv3_modlinkage);
272 	if (ret != 0) {
273 		/*
274 		 * Could not load module
275 		 */
276 		rdsv3_logging_destroy();
277 		return (ret);
278 	}
279 
280 	return (0);
281 }
282 
283 int
284 _fini()
285 {
286 	int	ret;
287 
288 	/*
289 	 * Remove module
290 	 */
291 	if ((ret = mod_remove(&rdsv3_modlinkage)) != 0) {
292 		return (ret);
293 	}
294 
295 	/* Stop logging */
296 	rdsv3_logging_destroy();
297 
298 	return (0);
299 }
300 
301 int
302 _info(struct modinfo *modinfop)
303 {
304 	return (mod_info(&rdsv3_modlinkage, modinfop));
305 }
306