xref: /illumos-gate/usr/src/uts/common/io/rsm/rsmops.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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