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_init();
59 extern void rdsv3_bind_exit();
60
61 int
rdsv3_sock_init()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_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
rdsv3_sock_exit()86 rdsv3_sock_exit()
87 {
88 RDSV3_DPRINTF2("rdsv3_sock_exit", "Enter");
89
90 rdsv3_bind_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
rdsv3_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
rdsv3_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
rdsv3_info(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)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
_init(void)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
_fini()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
_info(struct modinfo * modinfop)302 _info(struct modinfo *modinfop)
303 {
304 return (mod_info(&rdsv3_modlinkage, modinfop));
305 }
306