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 }