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.
26 #include <sys/types.h>
27 #include <sys/modctl.h>
31 #include <sys/sunddi.h>
34 #include <sys/rsm/rsm_common.h>
35 #include <sys/rsm/rsmpi.h>
36 #include <sys/rsm/rsmpi_driver.h>
39 static struct modlmisc modlmisc
= {
40 &mod_miscops
, "RSMOPS module",
43 static struct modlinkage modlinkage
= {
44 MODREV_1
, (void *)&modlmisc
, NULL
47 static kmutex_t rsmops_lock
;
49 static rsmops_drv_t
*rsmops_drv_head
= NULL
;
51 static int rsmops_threads_started
= 0;
58 mutex_init(&rsmops_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
60 if ((err
= mod_install(&modlinkage
)) != 0)
61 mutex_destroy(&rsmops_lock
);
71 mutex_enter(&rsmops_lock
);
72 if (rsmops_drv_head
) {
73 /* Somebody is still registered with us - we cannot unload */
74 mutex_exit(&rsmops_lock
);
77 if (rsmops_threads_started
) {
79 * Some threads have been started. We do not have any
80 * well-supported way of checking whether they have all
81 * exited. For now, fail attempt to unload if we have
82 * ever started any threads. This is overkill, but ...
84 mutex_exit(&rsmops_lock
);
87 mutex_exit(&rsmops_lock
);
89 if ((err
= mod_remove(&modlinkage
)) == 0)
90 mutex_destroy(&rsmops_lock
);
95 _info(struct modinfo
*modinfop
)
97 return (mod_info(&modlinkage
, modinfop
));
101 rsmops_thread_entry(rsmops_drv_t
*p_drv
)
103 /* p_drv->ctrl_cnt has already been increased by the time we get here */
104 ASSERT(p_drv
->drv
.rsm_thread_entry_pt
);
106 /* call the driver with the thread */
107 (*(p_drv
->drv
.rsm_thread_entry_pt
))(p_drv
->drv
.drv_name
);
109 /* thread has returned */
110 mutex_enter(&rsmops_lock
);
112 mutex_exit(&rsmops_lock
);
115 /* This is expected to be called from the driver's init function */
117 rsm_register_driver(rsmops_registry_t
*p_registry
)
119 rsmops_drv_t
**pp_tail
;
122 if (p_registry
->rsm_version
> RSM_VERSION
) {
123 /* The driver is up-rev than me. Fail attempt to register */
124 return (RSMERR_BAD_DRIVER_VERSION
);
128 * RSM_VERSION: Since this is the first version, there cannot be any
129 * down-rev drivers - this will be an issue in the future
131 if (p_registry
->rsm_version
!= RSM_VERSION
)
132 return (RSMERR_BAD_DRIVER_VERSION
);
134 mutex_enter(&rsmops_lock
);
135 /* First, search that this driver is not already registered */
136 pp_tail
= &rsmops_drv_head
;
138 if (strcmp((*pp_tail
)->drv
.drv_name
, p_registry
->drv_name
)
140 mutex_exit(&rsmops_lock
);
141 return (RSMERR_DRIVER_NAME_IN_USE
);
143 pp_tail
= &((*pp_tail
)->next
);
146 p
= kmem_alloc(sizeof (rsmops_drv_t
), KM_SLEEP
);
147 p
->drv
= *p_registry
; /* copy entire rsmops_registry_t structure */
152 if (p
->drv
.rsm_thread_entry_pt
) {
153 /* thread entry point is defined - we need to create a thread */
154 extern pri_t minclsyspri
;
156 p
->ctrl_cnt
++; /* bump up the count right now */
157 p
->thread_id
= thread_create(NULL
, 0, rsmops_thread_entry
,
158 p
, 0, &p0
, TS_RUN
, minclsyspri
);
159 rsmops_threads_started
++;
164 mutex_exit(&rsmops_lock
);
165 return (RSM_SUCCESS
);
169 * This is expected to be called from the driver's fini function
170 * if this function returns EBUSY, the driver is supposed to fail
171 * its own fini operation
174 rsm_unregister_driver(rsmops_registry_t
*p_registry
)
176 rsmops_drv_t
**pp_tail
;
179 mutex_enter(&rsmops_lock
);
181 /* Search for the driver */
182 pp_tail
= &rsmops_drv_head
;
184 if (strcmp((*pp_tail
)->drv
.drv_name
, p_registry
->drv_name
)) {
185 pp_tail
= &((*pp_tail
)->next
);
188 /* check ref count - if somebody is using it, return EBUSY */
189 if ((*pp_tail
)->ctrl_cnt
) {
190 mutex_exit(&rsmops_lock
);
191 return (RSMERR_CTLRS_REGISTERED
);
193 /* Nobody is using it - we can allow the unregister to happen */
196 /* Stomp the guy out of our linked list */
197 *pp_tail
= (*pp_tail
)->next
;
199 /* release the memory */
200 kmem_free(p
, sizeof (rsmops_drv_t
));
202 mutex_exit(&rsmops_lock
);
203 return (RSM_SUCCESS
);
206 /* Could not find the guy */
207 mutex_exit(&rsmops_lock
);
208 return (RSMERR_DRIVER_NOT_REGISTERED
);
211 /* Should be called holding the rsmops_lock mutex */
212 static rsmops_drv_t
*
213 find_rsmpi_driver(const char *name
)
215 rsmops_drv_t
*p_rsmops_list
;
217 ASSERT(MUTEX_HELD(&rsmops_lock
));
218 /* the name is of the form "sci", "wci" etc */
220 for (p_rsmops_list
= rsmops_drv_head
; p_rsmops_list
!= NULL
;
221 p_rsmops_list
= p_rsmops_list
->next
) {
223 if (strcmp(name
, p_rsmops_list
->drv
.drv_name
) == 0) {
224 return (p_rsmops_list
);
231 /* Should be called holding the rsmops_lock mutex */
232 static rsmops_ctrl_t
*
233 find_rsmpi_controller(const char *name
, uint_t number
)
238 ASSERT(MUTEX_HELD(&rsmops_lock
));
240 if ((p_drv
= find_rsmpi_driver(name
)) == NULL
)
243 for (p
= p_drv
->ctrl_head
; p
!= NULL
; p
= p
->next
) {
244 ASSERT(p
->p_drv
== p_drv
);
245 if (p
->number
== number
)
251 /* Should be called holding the rsmops_lock mutex */
252 static rsmops_ctrl_t
*
253 find_rsmpi_controller_handle(rsm_controller_handle_t cntlr_handle
)
258 ASSERT(MUTEX_HELD(&rsmops_lock
));
260 for (p_drv
= rsmops_drv_head
; p_drv
!= NULL
; p_drv
= p_drv
->next
) {
261 for (p
= p_drv
->ctrl_head
; p
!= NULL
; p
= p
->next
) {
262 if (p
->handle
== cntlr_handle
)
271 rsmops_device_open(const char *major_name
, const minor_t minor_num
);
274 rsm_get_controller(const char *name
, uint_t number
,
275 rsm_controller_object_t
*controller
, uint_t version
)
277 rsmops_ctrl_t
*p_ctrl
;
281 int (*rsm_get_controller_handler
)
282 (const char *name
, uint_t number
,
283 rsm_controller_object_t
*pcontroller
, uint_t version
);
285 mutex_enter(&rsmops_lock
);
287 /* check if the controller is already registered */
288 if ((p_ctrl
= find_rsmpi_controller(name
, number
)) == NULL
) {
290 * controller is not registered. We should try to load it
291 * First check if the driver is registered
293 if ((p_drv
= find_rsmpi_driver(name
)) == NULL
) {
294 /* Cannot find the driver. Try to load him */
295 mutex_exit(&rsmops_lock
);
296 if ((error
= modload("drv", (char *)name
)) == -1) {
297 return (RSMERR_CTLR_NOT_PRESENT
);
299 mutex_enter(&rsmops_lock
);
300 if ((p_drv
= find_rsmpi_driver(name
)) == NULL
) {
301 mutex_exit(&rsmops_lock
);
303 * Cannot find yet - maybe the driver we loaded
304 * was not a RSMPI driver at all. We'll just
307 return (RSMERR_CTLR_NOT_PRESENT
);
311 p_ctrl
= find_rsmpi_controller(name
, number
);
312 if (p_ctrl
== NULL
) {
314 * controller is not registered.
315 * try to do a VOP_OPEN to force it to get registered
317 mutex_exit(&rsmops_lock
);
318 vp
= rsmops_device_open(name
, number
);
319 mutex_enter(&rsmops_lock
);
321 (void) VOP_CLOSE(vp
, FREAD
|FWRITE
, 0, 0,
325 p_ctrl
= find_rsmpi_controller(name
, number
);
326 if (p_ctrl
== NULL
) {
327 mutex_exit(&rsmops_lock
);
328 return (RSMERR_CTLR_NOT_PRESENT
);
333 p_drv
= p_ctrl
->p_drv
;
336 ASSERT(p_drv
== p_ctrl
->p_drv
);
338 rsm_get_controller_handler
= p_drv
->drv
.rsm_get_controller_handler
;
340 * Increase the refcnt right now, so that attempts to deregister
341 * while we are using this entry will fail
344 mutex_exit(&rsmops_lock
);
346 error
= (*rsm_get_controller_handler
)(name
, number
, controller
,
348 if (error
!= RSM_SUCCESS
) {
349 /* We failed - drop the refcnt back */
350 mutex_enter(&rsmops_lock
);
352 * Even though we had released the global lock, we can
353 * guarantee that p_ctrl is still meaningful (and has not
354 * been deregistered, freed whatever) because we were holding
355 * refcnt on it. So, it is okay to just use p_ctrl here
356 * after re-acquiring the global lock
359 mutex_exit(&rsmops_lock
);
362 * Initialize the controller handle field
364 mutex_enter(&rsmops_lock
);
365 if ((p_ctrl
= find_rsmpi_controller(name
, number
)) == NULL
) {
366 mutex_exit(&rsmops_lock
);
367 return (RSMERR_CTLR_NOT_PRESENT
);
370 p_ctrl
->handle
= controller
->handle
;
371 mutex_exit(&rsmops_lock
);
377 rsm_release_controller(const char *name
, uint_t number
,
378 rsm_controller_object_t
*controller
)
380 rsmops_ctrl_t
*p_ctrl
;
383 int (*releaser
)(const char *name
, uint_t number
,
384 rsm_controller_object_t
*controller
);
386 mutex_enter(&rsmops_lock
);
388 if ((p_ctrl
= find_rsmpi_controller(name
, number
)) == NULL
) {
389 mutex_exit(&rsmops_lock
);
390 return (RSMERR_CTLR_NOT_PRESENT
);
392 p_drv
= find_rsmpi_driver(name
);
393 ASSERT(p_drv
); /* If we found controller, there MUST be a driver */
395 /* Found the appropriate driver. Forward the call to it */
396 releaser
= p_drv
->drv
.rsm_release_controller_handler
;
397 mutex_exit(&rsmops_lock
);
399 error
= (*releaser
)(name
, number
, controller
);
400 if (error
== RSM_SUCCESS
) {
401 mutex_enter(&rsmops_lock
);
403 mutex_exit(&rsmops_lock
);
408 /* This is expected to be called from the driver's attach function */
410 rsm_register_controller(const char *name
, uint_t number
,
411 rsm_controller_attr_t
*attrp
)
414 rsmops_ctrl_t
*p_ctrl
;
416 if (strlen(name
) > MAX_DRVNAME
)
417 return (RSMERR_NAME_TOO_LONG
);
419 mutex_enter(&rsmops_lock
);
421 /* Check if the driver is registered with us */
422 p_drv
= find_rsmpi_driver(name
);
425 * Hey! Driver is not registered, but we are getting a
428 mutex_exit(&rsmops_lock
);
429 return (RSMERR_DRIVER_NOT_REGISTERED
);
432 /* Check if the controller is already registered with us */
433 p_ctrl
= find_rsmpi_controller(name
, number
);
435 /* already registered */
436 mutex_exit(&rsmops_lock
);
437 return (RSMERR_CTLR_ALREADY_REGISTERED
);
440 /* WAIT: sanity check - verify that the dip matches up to name,number */
442 p_ctrl
= kmem_alloc(sizeof (rsmops_ctrl_t
), KM_SLEEP
);
444 /* bump up controller count on the driver */
447 p_ctrl
->p_drv
= p_drv
; /* setup the back pointer */
448 p_ctrl
->number
= number
;
450 p_ctrl
->attrp
= attrp
;
451 p_ctrl
->handle
= NULL
;
453 /* Now link to head of list */
454 p_ctrl
->next
= p_drv
->ctrl_head
;
455 p_drv
->ctrl_head
= p_ctrl
;
457 mutex_exit(&rsmops_lock
);
459 return (RSM_SUCCESS
);
463 * This is expected to be called from the driver's detach function
464 * if this function returns EBUSY, the driver is supposed to fail
465 * his own detach operation
468 rsm_unregister_controller(const char *name
, uint_t number
)
471 rsmops_ctrl_t
**p_prev
;
472 rsmops_ctrl_t
*found
;
474 mutex_enter(&rsmops_lock
);
476 /* Check if the driver is registered with us */
477 p_drv
= find_rsmpi_driver(name
);
479 /* Hey! Driver is not registered */
480 mutex_exit(&rsmops_lock
);
481 return (RSMERR_DRIVER_NOT_REGISTERED
);
484 /* Search for the controller in the list */
485 for (p_prev
= &p_drv
->ctrl_head
; *p_prev
; p_prev
= &((*p_prev
)->next
)) {
486 if ((*p_prev
)->number
== number
) {
487 /* Found the controller. Check if it is busy */
491 /* Controller is busy - handles outstanding */
492 mutex_exit(&rsmops_lock
);
493 return (RSMERR_CTLR_IN_USE
);
496 *p_prev
= found
->next
;
497 /* bump down controller count on the driver */
500 mutex_exit(&rsmops_lock
);
501 kmem_free(found
, sizeof (rsmops_ctrl_t
));
502 return (RSM_SUCCESS
);
505 mutex_exit(&rsmops_lock
);
506 /* Could not find the right controller */
507 return (RSMERR_CTLR_NOT_REGISTERED
);
512 * This opens and closes the appropriate device with minor number -
513 * hopefully, it will cause the driver to attach and register a controller
517 rsmops_device_open(const char *major_name
, const minor_t minor_num
)
523 if (minor_num
== (minor_t
)-1) {
527 maj
= ddi_name_to_major((char *)major_name
);
528 if (maj
== (major_t
)-1) {
532 vp
= makespecvp(makedevice(maj
, minor_num
), VCHR
);
534 ret
= VOP_OPEN(&vp
, FREAD
|FWRITE
, CRED(), NULL
);
544 * Attributes for controller identified by the handle are returned
545 * via *attrp. Modifications of attributes is prohibited by client!
548 rsm_get_controller_attr(rsm_controller_handle_t handle
,
549 rsm_controller_attr_t
**attrp
)
552 rsmops_ctrl_t
*p_ctrl
;
555 return (RSMERR_BAD_CTLR_HNDL
);
557 mutex_enter(&rsmops_lock
);
559 /* find controller */
560 if ((p_ctrl
= find_rsmpi_controller_handle(handle
)) == NULL
) {
561 /* can't supply attributes for invalid controller */
562 mutex_exit(&rsmops_lock
);
563 return (RSMERR_BAD_CTLR_HNDL
);
565 *attrp
= p_ctrl
->attrp
;
566 mutex_exit(&rsmops_lock
);
568 return (RSM_SUCCESS
);