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