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