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 #include <sys/types.h>
  27 #include <sys/modctl.h>
  28 #include <sys/stat.h>
  29 #include <sys/proc.h>
  30 #include <sys/ddi.h>
  31 #include <sys/sunddi.h>
  32 #include <sys/kmem.h>
  33 #include <sys/file.h>
  34 #include <sys/rsm/rsm_common.h>
  35 #include <sys/rsm/rsmpi.h>
  36 #include <sys/rsm/rsmpi_driver.h>
  37 
  38 /* lint -w2 */
  39 static struct modlmisc modlmisc = {
  40         &mod_miscops, "RSMOPS module",
  41 };
  42 
  43 static struct modlinkage modlinkage = {
  44         MODREV_1, (void *)&modlmisc, NULL
  45 };
  46 
  47 static kmutex_t rsmops_lock;
  48 
  49 static rsmops_drv_t *rsmops_drv_head = NULL;
  50 
  51 static int rsmops_threads_started = 0;
  52 
  53 int
  54 _init(void)
  55 {
  56         int     err;
  57 
  58         mutex_init(&rsmops_lock, NULL, MUTEX_DEFAULT, NULL);
  59 
  60         if ((err = mod_install(&modlinkage)) != 0)
  61                 mutex_destroy(&rsmops_lock);
  62 
  63         return (err);
  64 }
  65 
  66 int
  67 _fini(void)
  68 {
  69         int     err;
  70 
  71         mutex_enter(&rsmops_lock);
  72         if (rsmops_drv_head) {
  73                 /* Somebody is still registered with us - we cannot unload */
  74                 mutex_exit(&rsmops_lock);
  75                 return (EBUSY);
  76         }
  77         if (rsmops_threads_started) {
  78                 /*
  79                  * Some threads have been started.  We do not have any
  80                  * well-supported way of checking whether they have all
  81                  * exited.  For now, fail attempt to unload if we have
  82                  * ever started any threads.  This is overkill, but ...
  83                  */
  84                 mutex_exit(&rsmops_lock);
  85                 return (EBUSY);
  86         }
  87         mutex_exit(&rsmops_lock);
  88 
  89         if ((err = mod_remove(&modlinkage)) == 0)
  90                 mutex_destroy(&rsmops_lock);
  91         return (err);
  92 }
  93 
  94 int
  95 _info(struct modinfo *modinfop)
  96 {
  97         return (mod_info(&modlinkage, modinfop));
  98 }
  99 
 100 static void
 101 rsmops_thread_entry(rsmops_drv_t *p_drv)
 102 {
 103         /* p_drv->ctrl_cnt has already been increased by the time we get here */
 104         ASSERT(p_drv->drv.rsm_thread_entry_pt);
 105 
 106         /* call the driver with the thread */
 107         (*(p_drv->drv.rsm_thread_entry_pt))(p_drv->drv.drv_name);
 108 
 109         /* thread has returned */
 110         mutex_enter(&rsmops_lock);
 111         p_drv->ctrl_cnt--;
 112         mutex_exit(&rsmops_lock);
 113 }
 114 
 115 /* This is expected to be called from the driver's init function */
 116 int
 117 rsm_register_driver(rsmops_registry_t *p_registry)
 118 {
 119         rsmops_drv_t **pp_tail;
 120         rsmops_drv_t *p;
 121 
 122         if (p_registry->rsm_version > RSM_VERSION) {
 123                 /* The driver is up-rev than me.  Fail attempt to register */
 124                 return (RSMERR_BAD_DRIVER_VERSION);
 125         }
 126 
 127         /*
 128          * RSM_VERSION: Since this is the first version, there cannot be any
 129          * down-rev drivers - this will be an issue in the future
 130          */
 131         if (p_registry->rsm_version != RSM_VERSION)
 132                 return (RSMERR_BAD_DRIVER_VERSION);
 133 
 134         mutex_enter(&rsmops_lock);
 135         /* First, search that this driver is not already registered */
 136         pp_tail = &rsmops_drv_head;
 137         while (*pp_tail) {
 138                 if (strcmp((*pp_tail)->drv.drv_name, p_registry->drv_name)
 139                     == 0) {
 140                         mutex_exit(&rsmops_lock);
 141                         return (RSMERR_DRIVER_NAME_IN_USE);
 142                 }
 143                 pp_tail = &((*pp_tail)->next);
 144         }
 145 
 146         p = kmem_alloc(sizeof (rsmops_drv_t), KM_SLEEP);
 147         p->drv = *p_registry;        /* copy entire rsmops_registry_t structure */
 148         p->next = NULL;
 149         p->ctrl_cnt = 0;
 150         p->ctrl_head = NULL;
 151 
 152         if (p->drv.rsm_thread_entry_pt) {
 153                 /* thread entry point is defined - we need to create a thread */
 154                 extern  pri_t   minclsyspri;
 155 
 156                 p->ctrl_cnt++;       /* bump up the count right now */
 157                 p->thread_id = thread_create(NULL, 0, rsmops_thread_entry,
 158                     p, 0, &p0, TS_RUN, minclsyspri);
 159                 rsmops_threads_started++;
 160         } else
 161                 p->thread_id = NULL;
 162 
 163         *pp_tail = p;
 164         mutex_exit(&rsmops_lock);
 165         return (RSM_SUCCESS);
 166 }
 167 
 168 /*
 169  * This is expected to be called from the driver's fini function
 170  * if this function returns EBUSY, the driver is supposed to fail
 171  * its own fini operation
 172  */
 173 int
 174 rsm_unregister_driver(rsmops_registry_t *p_registry)
 175 {
 176         rsmops_drv_t **pp_tail;
 177         rsmops_drv_t *p;
 178 
 179         mutex_enter(&rsmops_lock);
 180 
 181         /* Search for the driver */
 182         pp_tail = &rsmops_drv_head;
 183         while (*pp_tail) {
 184                 if (strcmp((*pp_tail)->drv.drv_name, p_registry->drv_name)) {
 185                         pp_tail = &((*pp_tail)->next);
 186                         continue;
 187                 }
 188                 /* check ref count - if somebody is using it, return EBUSY */
 189                 if ((*pp_tail)->ctrl_cnt) {
 190                         mutex_exit(&rsmops_lock);
 191                         return (RSMERR_CTLRS_REGISTERED);
 192                 }
 193                 /* Nobody is using it - we can allow the unregister to happen */
 194                 p = *pp_tail;
 195 
 196                 /* Stomp the guy out of our linked list */
 197                 *pp_tail = (*pp_tail)->next;
 198 
 199                 /* release the memory */
 200                 kmem_free(p, sizeof (rsmops_drv_t));
 201 
 202                 mutex_exit(&rsmops_lock);
 203                 return (RSM_SUCCESS);
 204         }
 205 
 206         /* Could not find the guy */
 207         mutex_exit(&rsmops_lock);
 208         return (RSMERR_DRIVER_NOT_REGISTERED);
 209 }
 210 
 211 /* Should be called holding the rsmops_lock mutex */
 212 static rsmops_drv_t *
 213 find_rsmpi_driver(const char *name)
 214 {
 215         rsmops_drv_t *p_rsmops_list;
 216 
 217         ASSERT(MUTEX_HELD(&rsmops_lock));
 218         /* the name is of the form "sci", "wci" etc */
 219 
 220         for (p_rsmops_list = rsmops_drv_head; p_rsmops_list != NULL;
 221             p_rsmops_list = p_rsmops_list->next) {
 222 
 223                 if (strcmp(name, p_rsmops_list->drv.drv_name) == 0) {
 224                         return (p_rsmops_list);
 225                 }
 226         }
 227         return (NULL);
 228 }
 229 
 230 
 231 /* Should be called holding the rsmops_lock mutex */
 232 static rsmops_ctrl_t *
 233 find_rsmpi_controller(const char *name, uint_t number)
 234 {
 235         rsmops_drv_t *p_drv;
 236         rsmops_ctrl_t *p;
 237 
 238         ASSERT(MUTEX_HELD(&rsmops_lock));
 239 
 240         if ((p_drv = find_rsmpi_driver(name)) == NULL)
 241                 return (NULL);
 242 
 243         for (p = p_drv->ctrl_head; p != NULL; p = p->next) {
 244                 ASSERT(p->p_drv == p_drv);
 245                 if (p->number == number)
 246                         return (p);
 247         }
 248         return (NULL);
 249 }
 250 
 251 /* Should be called holding the rsmops_lock mutex */
 252 static rsmops_ctrl_t *
 253 find_rsmpi_controller_handle(rsm_controller_handle_t cntlr_handle)
 254 {
 255         rsmops_drv_t *p_drv;
 256         rsmops_ctrl_t *p;
 257 
 258         ASSERT(MUTEX_HELD(&rsmops_lock));
 259 
 260         for (p_drv = rsmops_drv_head; p_drv != NULL; p_drv = p_drv->next) {
 261                 for (p = p_drv->ctrl_head; p != NULL; p = p->next) {
 262                         if (p->handle == cntlr_handle)
 263                                 return (p);
 264                 }
 265         }
 266 
 267         return (NULL);
 268 }
 269 
 270 static vnode_t *
 271 rsmops_device_open(const char *major_name, const minor_t minor_num);
 272 
 273 int
 274 rsm_get_controller(const char *name, uint_t number,
 275     rsm_controller_object_t *controller, uint_t version)
 276 {
 277         rsmops_ctrl_t *p_ctrl;
 278         rsmops_drv_t *p_drv;
 279         vnode_t *vp;
 280         int error;
 281         int (*rsm_get_controller_handler)
 282             (const char *name, uint_t number,
 283             rsm_controller_object_t *pcontroller, uint_t version);
 284 
 285         mutex_enter(&rsmops_lock);
 286 
 287         /* check if the controller is already registered */
 288         if ((p_ctrl = find_rsmpi_controller(name, number)) == NULL) {
 289                 /*
 290                  * controller is not registered.  We should try to load it
 291                  * First check if the driver is registered
 292                  */
 293                 if ((p_drv = find_rsmpi_driver(name)) == NULL) {
 294                         /* Cannot find the driver.  Try to load him */
 295                         mutex_exit(&rsmops_lock);
 296                         if ((error = modload("drv", (char *)name)) == -1) {
 297                                 return (RSMERR_CTLR_NOT_PRESENT);
 298                         }
 299                         mutex_enter(&rsmops_lock);
 300                         if ((p_drv = find_rsmpi_driver(name)) == NULL) {
 301                                 mutex_exit(&rsmops_lock);
 302                                 /*
 303                                  * Cannot find yet - maybe the driver we loaded
 304                                  * was not a RSMPI driver at all.  We'll just
 305                                  * fail this call.
 306                                  */
 307                                 return (RSMERR_CTLR_NOT_PRESENT);
 308                         }
 309                 }
 310                 ASSERT(p_drv);
 311                 p_ctrl = find_rsmpi_controller(name, number);
 312                 if (p_ctrl == NULL) {
 313                         /*
 314                          * controller is not registered.
 315                          * try to do a VOP_OPEN to force it to get registered
 316                          */
 317                         mutex_exit(&rsmops_lock);
 318                         vp = rsmops_device_open(name, number);
 319                         mutex_enter(&rsmops_lock);
 320                         if (vp != NULL) {
 321                                 (void) VOP_CLOSE(vp, FREAD|FWRITE, 0, 0,
 322                                     CRED(), NULL);
 323                                 VN_RELE(vp);
 324                         }
 325                         p_ctrl = find_rsmpi_controller(name, number);
 326                         if (p_ctrl == NULL) {
 327                                 mutex_exit(&rsmops_lock);
 328                                 return (RSMERR_CTLR_NOT_PRESENT);
 329                         }
 330                 }
 331                 ASSERT(p_ctrl);
 332         } else {
 333                 p_drv = p_ctrl->p_drv;
 334         }
 335         ASSERT(p_drv);
 336         ASSERT(p_drv == p_ctrl->p_drv);
 337 
 338         rsm_get_controller_handler = p_drv->drv.rsm_get_controller_handler;
 339         /*
 340          * Increase the refcnt right now, so that attempts to deregister
 341          * while we are using this entry will fail
 342          */
 343         p_ctrl->refcnt++;
 344         mutex_exit(&rsmops_lock);
 345 
 346         error = (*rsm_get_controller_handler)(name, number, controller,
 347             version);
 348         if (error != RSM_SUCCESS) {
 349                 /* We failed - drop the refcnt back */
 350                 mutex_enter(&rsmops_lock);
 351                 /*
 352                  * Even though we had released the global lock, we can
 353                  * guarantee that p_ctrl is still meaningful (and has not
 354                  * been deregistered, freed whatever) because we were holding
 355                  * refcnt on it.  So, it is okay to just use p_ctrl here
 356                  * after re-acquiring the global lock
 357                  */
 358                 p_ctrl->refcnt--;
 359                 mutex_exit(&rsmops_lock);
 360         } else {
 361                 /*
 362                  * Initialize the controller handle field
 363                  */
 364                 mutex_enter(&rsmops_lock);
 365                 if ((p_ctrl = find_rsmpi_controller(name, number)) == NULL) {
 366                         mutex_exit(&rsmops_lock);
 367                         return (RSMERR_CTLR_NOT_PRESENT);
 368                 }
 369 
 370                 p_ctrl->handle = controller->handle;
 371                 mutex_exit(&rsmops_lock);
 372         }
 373         return (error);
 374 }
 375 
 376 int
 377 rsm_release_controller(const char *name, uint_t number,
 378     rsm_controller_object_t *controller)
 379 {
 380         rsmops_ctrl_t *p_ctrl;
 381         rsmops_drv_t *p_drv;
 382         int error;
 383         int (*releaser)(const char *name, uint_t number,
 384             rsm_controller_object_t *controller);
 385 
 386         mutex_enter(&rsmops_lock);
 387 
 388         if ((p_ctrl = find_rsmpi_controller(name, number)) == NULL) {
 389                 mutex_exit(&rsmops_lock);
 390                 return (RSMERR_CTLR_NOT_PRESENT);
 391         }
 392         p_drv = find_rsmpi_driver(name);
 393         ASSERT(p_drv);  /* If we found controller, there MUST be a driver */
 394 
 395         /* Found the appropriate driver.  Forward the call to it */
 396         releaser = p_drv->drv.rsm_release_controller_handler;
 397         mutex_exit(&rsmops_lock);
 398 
 399         error = (*releaser)(name, number, controller);
 400         if (error == RSM_SUCCESS) {
 401                 mutex_enter(&rsmops_lock);
 402                 p_ctrl->refcnt--;
 403                 mutex_exit(&rsmops_lock);
 404         }
 405         return (error);
 406 }
 407 
 408 /* This is expected to be called from the driver's attach function */
 409 int
 410 rsm_register_controller(const char *name, uint_t number,
 411     rsm_controller_attr_t *attrp)
 412 {
 413         rsmops_drv_t *p_drv;
 414         rsmops_ctrl_t *p_ctrl;
 415 
 416         if (strlen(name) > MAX_DRVNAME)
 417                 return (RSMERR_NAME_TOO_LONG);
 418 
 419         mutex_enter(&rsmops_lock);
 420 
 421         /* Check if the driver is registered with us */
 422         p_drv = find_rsmpi_driver(name);
 423         if (p_drv == NULL) {
 424                 /*
 425                  * Hey! Driver is not registered, but we are getting a
 426                  * controller ??
 427                  */
 428                 mutex_exit(&rsmops_lock);
 429                 return (RSMERR_DRIVER_NOT_REGISTERED);
 430         }
 431 
 432         /* Check if the controller is already registered with us */
 433         p_ctrl = find_rsmpi_controller(name, number);
 434         if (p_ctrl) {
 435                 /* already registered */
 436                 mutex_exit(&rsmops_lock);
 437                 return (RSMERR_CTLR_ALREADY_REGISTERED);
 438         }
 439 
 440         /* WAIT: sanity check - verify that the dip matches up to name,number */
 441 
 442         p_ctrl = kmem_alloc(sizeof (rsmops_ctrl_t), KM_SLEEP);
 443 
 444         /* bump up controller count on the driver */
 445         p_drv->ctrl_cnt++;
 446 
 447         p_ctrl->p_drv = p_drv;       /* setup the back pointer */
 448         p_ctrl->number = number;
 449         p_ctrl->refcnt = 0;
 450         p_ctrl->attrp = attrp;
 451         p_ctrl->handle = NULL;
 452 
 453         /* Now link to head of list */
 454         p_ctrl->next = p_drv->ctrl_head;
 455         p_drv->ctrl_head = p_ctrl;
 456 
 457         mutex_exit(&rsmops_lock);
 458 
 459         return (RSM_SUCCESS);
 460 }
 461 
 462 /*
 463  * This is expected to be called from the driver's detach function
 464  * if this function returns EBUSY, the driver is supposed to fail
 465  * his own detach operation
 466  */
 467 int
 468 rsm_unregister_controller(const char *name, uint_t number)
 469 {
 470         rsmops_drv_t *p_drv;
 471         rsmops_ctrl_t **p_prev;
 472         rsmops_ctrl_t *found;
 473 
 474         mutex_enter(&rsmops_lock);
 475 
 476         /* Check if the driver is registered with us */
 477         p_drv = find_rsmpi_driver(name);
 478         if (p_drv == NULL) {
 479                 /* Hey!  Driver is not registered */
 480                 mutex_exit(&rsmops_lock);
 481                 return (RSMERR_DRIVER_NOT_REGISTERED);
 482         }
 483 
 484         /* Search for the controller in the list */
 485         for (p_prev = &p_drv->ctrl_head; *p_prev; p_prev = &((*p_prev)->next)) {
 486                 if ((*p_prev)->number == number) {
 487                         /* Found the controller.  Check if it is busy */
 488                         found = *p_prev;
 489 
 490                         if (found->refcnt) {
 491                                 /* Controller is busy -  handles outstanding */
 492                                 mutex_exit(&rsmops_lock);
 493                                 return (RSMERR_CTLR_IN_USE);
 494                         }
 495                         /* unlink it out */
 496                         *p_prev = found->next;
 497                         /* bump down controller count on the driver */
 498                         p_drv->ctrl_cnt--;
 499 
 500                         mutex_exit(&rsmops_lock);
 501                         kmem_free(found, sizeof (rsmops_ctrl_t));
 502                         return (RSM_SUCCESS);
 503                 }
 504         }
 505         mutex_exit(&rsmops_lock);
 506         /* Could not find the right controller */
 507         return (RSMERR_CTLR_NOT_REGISTERED);
 508 }
 509 
 510 
 511 /*
 512  * This opens and closes the appropriate device with minor number -
 513  * hopefully, it will cause the driver to attach and register a controller
 514  * with us
 515  */
 516 static vnode_t *
 517 rsmops_device_open(const char *major_name, const minor_t minor_num)
 518 {
 519         major_t maj;
 520         vnode_t *vp;
 521         int ret;
 522 
 523         if (minor_num == (minor_t)-1) {
 524                 return (NULL);
 525         }
 526 
 527         maj = ddi_name_to_major((char *)major_name);
 528         if (maj == (major_t)-1) {
 529                 return (NULL);
 530         }
 531 
 532         vp = makespecvp(makedevice(maj, minor_num), VCHR);
 533 
 534         ret = VOP_OPEN(&vp, FREAD|FWRITE, CRED(), NULL);
 535         if (ret == 0) {
 536                 return (vp);
 537         } else {
 538                 VN_RELE(vp);
 539                 return (NULL);
 540         }
 541 }
 542 
 543 /*
 544  * Attributes for controller identified by the handle are returned
 545  * via *attrp. Modifications of attributes is prohibited by client!
 546  */
 547 int
 548 rsm_get_controller_attr(rsm_controller_handle_t handle,
 549     rsm_controller_attr_t **attrp)
 550 {
 551 
 552         rsmops_ctrl_t *p_ctrl;
 553 
 554         if (handle == NULL)
 555                 return (RSMERR_BAD_CTLR_HNDL);
 556 
 557         mutex_enter(&rsmops_lock);
 558 
 559         /* find controller */
 560         if ((p_ctrl = find_rsmpi_controller_handle(handle)) == NULL) {
 561                 /* can't supply attributes for invalid controller */
 562                 mutex_exit(&rsmops_lock);
 563                 return (RSMERR_BAD_CTLR_HNDL);
 564         }
 565         *attrp =  p_ctrl->attrp;
 566         mutex_exit(&rsmops_lock);
 567 
 568         return (RSM_SUCCESS);
 569 }