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 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 /*
  28  * generic mpxio leaf driver
  29  */
  30 #include <sys/types.h>
  31 #include <sys/param.h>
  32 #include <sys/errno.h>
  33 #include <sys/uio.h>
  34 #include <sys/buf.h>
  35 #include <sys/modctl.h>
  36 #include <sys/open.h>
  37 #include <sys/kmem.h>
  38 #include <sys/conf.h>
  39 #include <sys/cmn_err.h>
  40 #include <sys/stat.h>
  41 #include <sys/ddi.h>
  42 #include <sys/sunddi.h>
  43 #include <sys/sunndi.h>
  44 
  45 
  46 static int tcli_open(dev_t *, int, int, cred_t *);
  47 static int tcli_close(dev_t, int, int, cred_t *);
  48 static int tcli_read(dev_t, struct uio *, cred_t *);
  49 static int tcli_write(dev_t, struct uio *, cred_t *);
  50 static int tcli_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
  51 static int tcli_attach(dev_info_t *, ddi_attach_cmd_t);
  52 static int tcli_detach(dev_info_t *, ddi_detach_cmd_t);
  53 
  54 static int tcli_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
  55 
  56 struct dstate {
  57         dev_info_t *dip;
  58         int oflag;
  59 };
  60 
  61 static void *dstates;
  62 
  63 #define INST_TO_MINOR(i)        (i)
  64 #define MINOR_TO_INST(mn)       (mn)
  65 
  66 static struct cb_ops tcli_cb_ops = {
  67         tcli_open,                      /* open */
  68         tcli_close,                     /* close */
  69         nodev,                          /* strategy */
  70         nodev,                          /* print */
  71         nodev,                          /* dump */
  72         tcli_read,                      /* read */
  73         tcli_write,                     /* write */
  74         tcli_ioctl,                     /* ioctl */
  75         nodev,                          /* devmap */
  76         nodev,                          /* mmap */
  77         nodev,                          /* segmap */
  78         nochpoll,                       /* poll */
  79         ddi_prop_op,                    /* prop_op */
  80         NULL,                           /* streamtab */
  81         D_NEW | D_MP | D_HOTPLUG,       /* flag */
  82         CB_REV,                         /* cb_rev */
  83         nodev,                          /* aread */
  84         nodev                           /* awrite */
  85 };
  86 
  87 
  88 static struct dev_ops tcli_ops = {
  89         DEVO_REV,               /* devo_rev */
  90         0,                      /* refcnt */
  91         tcli_info,              /* getinfo */
  92         nulldev,                /* identify */
  93         nulldev,                /* probe */
  94         tcli_attach,            /* attach */
  95         tcli_detach,            /* detach */
  96         nodev,                  /* reset */
  97         &tcli_cb_ops,               /* driver ops */
  98         (struct bus_ops *)0,    /* bus ops */
  99         NULL,                   /* power */
 100         ddi_quiesce_not_needed,         /* quiesce */
 101 };
 102 
 103 static struct modldrv modldrv = {
 104         &mod_driverops,
 105         "vhci client test driver",
 106         &tcli_ops
 107 };
 108 
 109 static struct modlinkage modlinkage = {
 110         MODREV_1, { &modldrv, NULL }
 111 };
 112 
 113 int
 114 _init(void)
 115 {
 116         int e;
 117 
 118         if ((e = ddi_soft_state_init(&dstates,
 119             sizeof (struct dstate), 0)) != 0) {
 120                 return (e);
 121         }
 122 
 123         if ((e = mod_install(&modlinkage)) != 0)  {
 124                 ddi_soft_state_fini(&dstates);
 125         }
 126 
 127         return (e);
 128 }
 129 
 130 int
 131 _fini(void)
 132 {
 133         int e;
 134 
 135         if ((e = mod_remove(&modlinkage)) != 0)  {
 136                 return (e);
 137         }
 138         ddi_soft_state_fini(&dstates);
 139         return (e);
 140 }
 141 
 142 int
 143 _info(struct modinfo *modinfop)
 144 {
 145         return (mod_info(&modlinkage, modinfop));
 146 }
 147 
 148 /*ARGSUSED*/
 149 static int
 150 tcli_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 151 {
 152         int instance = ddi_get_instance(devi);
 153         struct dstate *dstatep;
 154         int rval;
 155 
 156         if (cmd != DDI_ATTACH)
 157                 return (DDI_SUCCESS);
 158 
 159         if (ddi_soft_state_zalloc(dstates, instance) != DDI_SUCCESS) {
 160                 cmn_err(CE_CONT, "%s%d: can't allocate state\n",
 161                     ddi_get_name(devi), instance);
 162                 return (DDI_FAILURE);
 163         }
 164 
 165         dstatep = ddi_get_soft_state(dstates, instance);
 166         dstatep->dip = devi;
 167 
 168         rval = ddi_create_minor_node(devi, "client", S_IFCHR,
 169             (INST_TO_MINOR(instance)), DDI_PSEUDO, NULL);
 170         if (rval == DDI_FAILURE) {
 171                 ddi_remove_minor_node(devi, NULL);
 172                 ddi_soft_state_free(dstates, instance);
 173                 cmn_err(CE_WARN, "%s%d: can't create minor nodes",
 174                     ddi_get_name(devi), instance);
 175                 return (DDI_FAILURE);
 176         }
 177 
 178         ddi_report_dev(devi);
 179         return (DDI_SUCCESS);
 180 }
 181 
 182 /*ARGSUSED*/
 183 static int
 184 tcli_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 185 {
 186         int instance;
 187 
 188         if (cmd != DDI_DETACH)
 189                 return (DDI_SUCCESS);
 190 
 191         ddi_remove_minor_node(devi, NULL);
 192         instance = ddi_get_instance(devi);
 193         ddi_soft_state_free(dstates, instance);
 194         return (DDI_SUCCESS);
 195 }
 196 
 197 /* ARGSUSED */
 198 static int
 199 tcli_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 200 {
 201         dev_t   dev;
 202         int     instance;
 203 
 204         if (infocmd != DDI_INFO_DEVT2INSTANCE)
 205                 return (DDI_FAILURE);
 206 
 207         dev = (dev_t)arg;
 208         instance = MINOR_TO_INST(getminor(dev));
 209         *result = (void *)(uintptr_t)instance;
 210         return (DDI_SUCCESS);
 211 }
 212 
 213 
 214 /*ARGSUSED*/
 215 static int
 216 tcli_open(dev_t *devp, int flag, int otyp, cred_t *cred)
 217 {
 218         minor_t minor;
 219         struct dstate *dstatep;
 220 
 221         if (otyp != OTYP_BLK && otyp != OTYP_CHR)
 222                 return (EINVAL);
 223 
 224         minor = getminor(*devp);
 225         if ((dstatep = ddi_get_soft_state(dstates,
 226             MINOR_TO_INST(minor))) == NULL)
 227                 return (ENXIO);
 228 
 229         dstatep->oflag = 1;
 230 
 231         return (0);
 232 }
 233 
 234 /*ARGSUSED*/
 235 static int
 236 tcli_close(dev_t dev, int flag, int otyp, cred_t *cred)
 237 {
 238         struct dstate *dstatep;
 239         minor_t minor = getminor(dev);
 240 
 241         if (otyp != OTYP_BLK && otyp != OTYP_CHR)
 242                 return (EINVAL);
 243 
 244         dstatep = ddi_get_soft_state(dstates, MINOR_TO_INST(minor));
 245 
 246         if (dstatep == NULL)
 247                 return (ENXIO);
 248 
 249         dstatep->oflag = 0;
 250 
 251         return (0);
 252 }
 253 
 254 /*ARGSUSED*/
 255 static int
 256 tcli_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
 257     int *rvalp)
 258 {
 259         struct dstate *dstatep;
 260         int instance;
 261 
 262         instance = MINOR_TO_INST(getminor(dev));
 263         dstatep = ddi_get_soft_state(dstates, instance);
 264 
 265         if (dstatep == NULL)
 266                 return (ENXIO);
 267 
 268         return (0);
 269 }
 270 
 271 /*ARGSUSED*/
 272 static int
 273 tcli_read(dev_t dev, struct uio *uiop, cred_t *credp)
 274 {
 275         return (0);
 276 }
 277 
 278 /*ARGSUSED*/
 279 static int
 280 tcli_write(dev_t dev, struct uio *uiop, cred_t *credp)
 281 {
 282         return (0);
 283 }