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