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