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 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 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 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, NULL } 256 }; 257 258 int 259 _init(void) 260 { 261 int ret; 262 263 if (ibt_hw_is_present() == 0) { 264 return (ENODEV); 265 } 266 267 /* Initialize logging */ 268 rdsv3_logging_initialization(); 269 270 ret = mod_install(&rdsv3_modlinkage); 271 if (ret != 0) { 272 /* 273 * Could not load module 274 */ 275 rdsv3_logging_destroy(); 276 return (ret); 277 } 278 279 return (0); 280 } 281 282 int 283 _fini() 284 { 285 int ret; 286 287 /* 288 * Remove module 289 */ 290 if ((ret = mod_remove(&rdsv3_modlinkage)) != 0) { 291 return (ret); 292 } 293 294 /* Stop logging */ 295 rdsv3_logging_destroy(); 296 297 return (0); 298 } 299 300 int 301 _info(struct modinfo *modinfop) 302 { 303 return (mod_info(&rdsv3_modlinkage, modinfop)); 304 }