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 }