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