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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)96 _info(struct modinfo *modinfop)
97 {
98 return (mod_info(&modlinkage, modinfop));
99 }
100
101 static void
rsmops_thread_entry(rsmops_drv_t * p_drv)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
rsm_register_driver(rsmops_registry_t * p_registry)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
rsm_unregister_driver(rsmops_registry_t * p_registry)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 *
find_rsmpi_driver(const char * name)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 *
find_rsmpi_controller(const char * name,uint_t number)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 *
find_rsmpi_controller_handle(rsm_controller_handle_t cntlr_handle)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
rsm_get_controller(const char * name,uint_t number,rsm_controller_object_t * controller,uint_t version)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
rsm_release_controller(const char * name,uint_t number,rsm_controller_object_t * controller)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
rsm_register_controller(const char * name,uint_t number,rsm_controller_attr_t * attrp)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
rsm_unregister_controller(const char * name,uint_t number)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 *
rsmops_device_open(const char * major_name,const minor_t minor_num)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
rsm_get_controller_attr(rsm_controller_handle_t handle,rsm_controller_attr_t ** attrp)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