rdsv3_ddi.c revision 12198:4db936bda957
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
38extern int rdsv3_init(void);
39extern void rdsv3_exit(void);
40extern void rdsv3_cong_init(void);
41extern void rdsv3_cong_exit(void);
42extern void rdsv3_trans_init(void);
43extern void rdsv3_trans_exit(void);
44extern int rdsv3_sock_init(void);
45extern void rdsv3_sock_exit(void);
46
47/* global */
48dev_info_t	*rdsv3_dev_info = NULL;
49kmem_cache_t	*rdsv3_alloc_cache = NULL;
50
51extern kmutex_t rdsv3_rdma_listen_id_lock;
52extern struct rdma_cm_id *rdsv3_rdma_listen_id;
53
54extern kmutex_t rdsv3_sock_lock;
55extern list_t rdsv3_sock_list;
56
57extern void rdsv3_bind_tree_init();
58extern void rdsv3_bind_tree_exit();
59
60int
61rdsv3_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
84void
85rdsv3_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
99static int
100rdsv3_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
154static int
155rdsv3_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 */
174static int
175rdsv3_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 */
204static 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 */
226static 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"
245static struct modldrv rdsv3_modldrv = {
246	&mod_driverops,		/* Driver module */
247	RDSV3_DEVDESC,		/* Driver name and version */
248	&rdsv3_ops,		/* Driver ops */
249};
250
251static struct modlinkage rdsv3_modlinkage = {
252	MODREV_1,
253	(void *)&rdsv3_modldrv,
254	NULL
255};
256
257int
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
281int
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
299int
300_info(struct modinfo *modinfop)
301{
302	return (mod_info(&rdsv3_modlinkage, modinfop));
303}
304