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]
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>
32 #include <sys/sunddi.h>
35 #include <sys/rsm/rsm_common.h>
36 #include <sys/rsm/rsmpi.h>
37 #include <sys/rsm/rsmpi_driver.h>
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;
59 mutex_init(&rsmops_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
61 if ((err
= mod_install(&modlinkage
)) != 0)
62 mutex_destroy(&rsmops_lock
);
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
);
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
);
88 mutex_exit(&rsmops_lock
);
90 if ((err
= mod_remove(&modlinkage
)) == 0)
91 mutex_destroy(&rsmops_lock
);
96 _info(struct modinfo
*modinfop
)
98 return (mod_info(&modlinkage
, modinfop
));
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
);
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
;
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
;
139 if (strcmp((*pp_tail
)->drv
.drv_name
, p_registry
->drv_name
)
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 */
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
++;
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
;
180 mutex_enter(&rsmops_lock
);
182 /* Search for the driver */
183 pp_tail
= &rsmops_drv_head
;
185 if (strcmp((*pp_tail
)->drv
.drv_name
, p_registry
->drv_name
)) {
186 pp_tail
= &((*pp_tail
)->next
);
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 */
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
);
232 /* Should be called holding the rsmops_lock mutex */
233 static rsmops_ctrl_t
*
234 find_rsmpi_controller(const char *name
, uint_t number
)
239 ASSERT(MUTEX_HELD(&rsmops_lock
));
241 if ((p_drv
= find_rsmpi_driver(name
)) == 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
)
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
)
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
)
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
;
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
308 return (RSMERR_CTLR_NOT_PRESENT
);
312 p_ctrl
= find_rsmpi_controller(name
, number
);
313 if (p_ctrl
== NULL
) {
315 * controller is not registered.
316 * try to do a fop_open to force it to get registered
318 mutex_exit(&rsmops_lock
);
319 vp
= rsmops_device_open(name
, number
);
320 mutex_enter(&rsmops_lock
);
322 (void) fop_close(vp
, FREAD
|FWRITE
, 0, 0,
326 p_ctrl
= find_rsmpi_controller(name
, number
);
327 if (p_ctrl
== NULL
) {
328 mutex_exit(&rsmops_lock
);
329 return (RSMERR_CTLR_NOT_PRESENT
);
334 p_drv
= p_ctrl
->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
345 mutex_exit(&rsmops_lock
);
347 error
= (*rsm_get_controller_handler
)(name
, number
, controller
,
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
360 mutex_exit(&rsmops_lock
);
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
);
378 rsm_release_controller(const char *name
, uint_t number
,
379 rsm_controller_object_t
*controller
)
381 rsmops_ctrl_t
*p_ctrl
;
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
);
404 mutex_exit(&rsmops_lock
);
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
)
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
);
426 * Hey! Driver is not registered, but we are getting a
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
);
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 */
448 p_ctrl
->p_drv
= p_drv
; /* setup the back pointer */
449 p_ctrl
->number
= number
;
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
)
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
);
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 */
492 /* Controller is busy - handles outstanding */
493 mutex_exit(&rsmops_lock
);
494 return (RSMERR_CTLR_IN_USE
);
497 *p_prev
= found
->next
;
498 /* bump down controller count on the driver */
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
518 rsmops_device_open(const char *major_name
, const minor_t minor_num
)
524 if (minor_num
== (minor_t
)-1) {
528 maj
= ddi_name_to_major((char *)major_name
);
529 if (maj
== (major_t
)-1) {
533 vp
= makespecvp(makedevice(maj
, minor_num
), VCHR
);
535 ret
= fop_open(&vp
, FREAD
|FWRITE
, CRED(), 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
;
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
);