14916 ehci_qh_pool_size is probably too low
[illumos-gate.git] / usr / src / uts / common / io / rsm / rsmops.c
bloba1c9b792bb954b741e6d4582a9fcd7d0a9e4d671
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
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.
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>
39 /* lint -w2 */
40 static struct modlmisc modlmisc = {
41 &mod_miscops, "RSMOPS module",
44 static struct modlinkage modlinkage = {
45 MODREV_1, (void *)&modlmisc, NULL
48 static kmutex_t rsmops_lock;
50 static rsmops_drv_t *rsmops_drv_head = NULL;
52 static int rsmops_threads_started = 0;
54 int
55 _init(void)
57 int err;
59 mutex_init(&rsmops_lock, NULL, MUTEX_DEFAULT, NULL);
61 if ((err = mod_install(&modlinkage)) != 0)
62 mutex_destroy(&rsmops_lock);
64 return (err);
67 int
68 _fini(void)
70 int err;
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);
78 if (rsmops_threads_started) {
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 ...
85 mutex_exit(&rsmops_lock);
86 return (EBUSY);
88 mutex_exit(&rsmops_lock);
90 if ((err = mod_remove(&modlinkage)) == 0)
91 mutex_destroy(&rsmops_lock);
92 return (err);
95 int
96 _info(struct modinfo *modinfop)
98 return (mod_info(&modlinkage, modinfop));
101 static void
102 rsmops_thread_entry(rsmops_drv_t *p_drv)
104 /* p_drv->ctrl_cnt has already been increased by the time we get here */
105 ASSERT(p_drv->drv.rsm_thread_entry_pt);
107 /* call the driver with the thread */
108 (*(p_drv->drv.rsm_thread_entry_pt))(p_drv->drv.drv_name);
110 /* thread has returned */
111 mutex_enter(&rsmops_lock);
112 p_drv->ctrl_cnt--;
113 mutex_exit(&rsmops_lock);
116 /* This is expected to be called from the driver's init function */
118 rsm_register_driver(rsmops_registry_t *p_registry)
120 rsmops_drv_t **pp_tail;
121 rsmops_drv_t *p;
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);
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
132 if (p_registry->rsm_version != RSM_VERSION)
133 return (RSMERR_BAD_DRIVER_VERSION);
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);
144 pp_tail = &((*pp_tail)->next);
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;
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;
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;
164 *pp_tail = p;
165 mutex_exit(&rsmops_lock);
166 return (RSM_SUCCESS);
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
175 rsm_unregister_driver(rsmops_registry_t *p_registry)
177 rsmops_drv_t **pp_tail;
178 rsmops_drv_t *p;
180 mutex_enter(&rsmops_lock);
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;
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);
194 /* Nobody is using it - we can allow the unregister to happen */
195 p = *pp_tail;
197 /* Stomp the guy out of our linked list */
198 *pp_tail = (*pp_tail)->next;
200 /* release the memory */
201 kmem_free(p, sizeof (rsmops_drv_t));
203 mutex_exit(&rsmops_lock);
204 return (RSM_SUCCESS);
207 /* Could not find the guy */
208 mutex_exit(&rsmops_lock);
209 return (RSMERR_DRIVER_NOT_REGISTERED);
212 /* Should be called holding the rsmops_lock mutex */
213 static rsmops_drv_t *
214 find_rsmpi_driver(const char *name)
216 rsmops_drv_t *p_rsmops_list;
218 ASSERT(MUTEX_HELD(&rsmops_lock));
219 /* the name is of the form "sci", "wci" etc */
221 for (p_rsmops_list = rsmops_drv_head; p_rsmops_list != NULL;
222 p_rsmops_list = p_rsmops_list->next) {
224 if (strcmp(name, p_rsmops_list->drv.drv_name) == 0) {
225 return (p_rsmops_list);
228 return (NULL);
232 /* Should be called holding the rsmops_lock mutex */
233 static rsmops_ctrl_t *
234 find_rsmpi_controller(const char *name, uint_t number)
236 rsmops_drv_t *p_drv;
237 rsmops_ctrl_t *p;
239 ASSERT(MUTEX_HELD(&rsmops_lock));
241 if ((p_drv = find_rsmpi_driver(name)) == NULL)
242 return (NULL);
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);
249 return (NULL);
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)
256 rsmops_drv_t *p_drv;
257 rsmops_ctrl_t *p;
259 ASSERT(MUTEX_HELD(&rsmops_lock));
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);
268 return (NULL);
271 static vnode_t *
272 rsmops_device_open(const char *major_name, const minor_t minor_num);
275 rsm_get_controller(const char *name, uint_t number,
276 rsm_controller_object_t *controller, uint_t version)
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);
286 mutex_enter(&rsmops_lock);
288 /* check if the controller is already registered */
289 if ((p_ctrl = find_rsmpi_controller(name, number)) == NULL) {
291 * controller is not registered. We should try to load it
292 * First check if the driver is registered
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);
300 mutex_enter(&rsmops_lock);
301 if ((p_drv = find_rsmpi_driver(name)) == NULL) {
302 mutex_exit(&rsmops_lock);
304 * Cannot find yet - maybe the driver we loaded
305 * was not a RSMPI driver at all. We'll just
306 * fail this call.
308 return (RSMERR_CTLR_NOT_PRESENT);
311 ASSERT(p_drv);
312 p_ctrl = find_rsmpi_controller(name, number);
313 if (p_ctrl == NULL) {
315 * controller is not registered.
316 * try to do a VOP_OPEN to force it to get registered
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);
326 p_ctrl = find_rsmpi_controller(name, number);
327 if (p_ctrl == NULL) {
328 mutex_exit(&rsmops_lock);
329 return (RSMERR_CTLR_NOT_PRESENT);
332 ASSERT(p_ctrl);
333 } else {
334 p_drv = p_ctrl->p_drv;
336 ASSERT(p_drv);
337 ASSERT(p_drv == p_ctrl->p_drv);
339 rsm_get_controller_handler = p_drv->drv.rsm_get_controller_handler;
341 * Increase the refcnt right now, so that attempts to deregister
342 * while we are using this entry will fail
344 p_ctrl->refcnt++;
345 mutex_exit(&rsmops_lock);
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);
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
359 p_ctrl->refcnt--;
360 mutex_exit(&rsmops_lock);
361 } else {
363 * Initialize the controller handle field
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);
371 p_ctrl->handle = controller->handle;
372 mutex_exit(&rsmops_lock);
374 return (error);
378 rsm_release_controller(const char *name, uint_t number,
379 rsm_controller_object_t *controller)
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);
387 mutex_enter(&rsmops_lock);
389 if ((p_ctrl = find_rsmpi_controller(name, number)) == NULL) {
390 mutex_exit(&rsmops_lock);
391 return (RSMERR_CTLR_NOT_PRESENT);
393 p_drv = find_rsmpi_driver(name);
394 ASSERT(p_drv); /* If we found controller, there MUST be a driver */
396 /* Found the appropriate driver. Forward the call to it */
397 releaser = p_drv->drv.rsm_release_controller_handler;
398 mutex_exit(&rsmops_lock);
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);
406 return (error);
409 /* This is expected to be called from the driver's attach function */
411 rsm_register_controller(const char *name, uint_t number,
412 rsm_controller_attr_t *attrp)
414 rsmops_drv_t *p_drv;
415 rsmops_ctrl_t *p_ctrl;
417 if (strlen(name) > MAX_DRVNAME)
418 return (RSMERR_NAME_TOO_LONG);
420 mutex_enter(&rsmops_lock);
422 /* Check if the driver is registered with us */
423 p_drv = find_rsmpi_driver(name);
424 if (p_drv == NULL) {
426 * Hey! Driver is not registered, but we are getting a
427 * controller ??
429 mutex_exit(&rsmops_lock);
430 return (RSMERR_DRIVER_NOT_REGISTERED);
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);
441 /* WAIT: sanity check - verify that the dip matches up to name,number */
443 p_ctrl = kmem_alloc(sizeof (rsmops_ctrl_t), KM_SLEEP);
445 /* bump up controller count on the driver */
446 p_drv->ctrl_cnt++;
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;
454 /* Now link to head of list */
455 p_ctrl->next = p_drv->ctrl_head;
456 p_drv->ctrl_head = p_ctrl;
458 mutex_exit(&rsmops_lock);
460 return (RSM_SUCCESS);
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
469 rsm_unregister_controller(const char *name, uint_t number)
471 rsmops_drv_t *p_drv;
472 rsmops_ctrl_t **p_prev;
473 rsmops_ctrl_t *found;
475 mutex_enter(&rsmops_lock);
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);
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;
491 if (found->refcnt) {
492 /* Controller is busy - handles outstanding */
493 mutex_exit(&rsmops_lock);
494 return (RSMERR_CTLR_IN_USE);
496 /* unlink it out */
497 *p_prev = found->next;
498 /* bump down controller count on the driver */
499 p_drv->ctrl_cnt--;
501 mutex_exit(&rsmops_lock);
502 kmem_free(found, sizeof (rsmops_ctrl_t));
503 return (RSM_SUCCESS);
506 mutex_exit(&rsmops_lock);
507 /* Could not find the right controller */
508 return (RSMERR_CTLR_NOT_REGISTERED);
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
517 static vnode_t *
518 rsmops_device_open(const char *major_name, const minor_t minor_num)
520 major_t maj;
521 vnode_t *vp;
522 int ret;
524 if (minor_num == (minor_t)-1) {
525 return (NULL);
528 maj = ddi_name_to_major((char *)major_name);
529 if (maj == (major_t)-1) {
530 return (NULL);
533 vp = makespecvp(makedevice(maj, minor_num), VCHR);
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);
545 * Attributes for controller identified by the handle are returned
546 * via *attrp. Modifications of attributes is prohibited by client!
549 rsm_get_controller_attr(rsm_controller_handle_t handle,
550 rsm_controller_attr_t **attrp)
553 rsmops_ctrl_t *p_ctrl;
555 if (handle == NULL)
556 return (RSMERR_BAD_CTLR_HNDL);
558 mutex_enter(&rsmops_lock);
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);
566 *attrp = p_ctrl->attrp;
567 mutex_exit(&rsmops_lock);
569 return (RSM_SUCCESS);