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