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 /*
27 * Media independent RPC-like comms
28 */
29
30 #include <sys/types.h>
31 #include <sys/conf.h>
32 #include <sys/stat.h>
33 #include <sys/errno.h>
34 #include <sys/cmn_err.h>
35 #include <sys/ksynch.h>
36 #include <sys/kmem.h>
37 #include <sys/modctl.h>
38 #include <sys/ddi.h>
39 #include <sys/sunddi.h>
40
41 #include <sys/varargs.h>
42 #ifdef DS_DDICT
43 #include <sys/nsctl/contract.h>
44 #endif
45 #include "ncall.h"
46 #include "ncall_module.h"
47
48 #include <sys/nsctl/nsvers.h>
49
50 /*
51 * cb_ops functions.
52 */
53
54 static int ncallioctl(dev_t, int, intptr_t, int, cred_t *, int *);
55 static int ncallprint(dev_t, char *);
56
57
58 static struct cb_ops ncall_cb_ops = {
59 nulldev, /* open */
60 nulldev, /* close */
61 nulldev, /* strategy */
62 ncallprint,
63 nodev, /* dump */
64 nodev, /* read */
65 nodev, /* write */
66 ncallioctl,
67 nodev, /* devmap */
68 nodev, /* mmap */
69 nodev, /* segmap */
70 nochpoll, /* poll */
71 ddi_prop_op,
72 NULL, /* NOT a stream */
73 D_NEW | D_MP | D_64BIT,
74 CB_REV,
75 nodev, /* aread */
76 nodev, /* awrite */
77 };
78
79
80 /*
81 * dev_ops functions.
82 */
83
84 static int ncall_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
85 static int ncall_attach(dev_info_t *, ddi_attach_cmd_t);
86 static int ncall_detach(dev_info_t *, ddi_detach_cmd_t);
87
88 static struct dev_ops ncall_ops = {
89 DEVO_REV,
90 0,
91 ncall_getinfo,
92 nulldev, /* identify */
93 nulldev, /* probe */
94 ncall_attach,
95 ncall_detach,
96 nodev, /* reset */
97 &ncall_cb_ops,
98 (struct bus_ops *)0,
99 NULL /* power */
100 };
101
102 /*
103 * Module linkage.
104 */
105
106 extern struct mod_ops mod_driverops;
107
108 static struct modldrv modldrv = {
109 &mod_driverops,
110 "nws:Kernel Call:" ISS_VERSION_STR,
111 &ncall_ops
112 };
113
114 static struct modlinkage modlinkage = {
115 MODREV_1,
116 &modldrv,
117 0
118 };
119
120 typedef struct ncall_modinfo_s {
121 struct ncall_modinfo_s *next;
122 ncall_module_t *module;
123 } ncall_modinfo_t;
124
125 static dev_info_t *ncall_dip; /* Single DIP for driver */
126 static kmutex_t ncall_mutex;
127
128 static ncall_modinfo_t *ncall_modules;
129 static int ncall_active;
130
131 static ncall_node_t ncall_nodeinfo;
132
133 static int ncallgetnodes(intptr_t, int, int *);
134 extern void ncall_init_stub(void);
135
136 int
_init(void)137 _init(void)
138 {
139 int error;
140
141 mutex_init(&ncall_mutex, NULL, MUTEX_DRIVER, NULL);
142
143 if ((error = mod_install(&modlinkage)) != 0) {
144 mutex_destroy(&ncall_mutex);
145 return (error);
146 }
147
148 return (0);
149 }
150
151
152 int
_fini(void)153 _fini(void)
154 {
155 int error;
156
157 if ((error = mod_remove(&modlinkage)) != 0)
158 return (error);
159
160 mutex_destroy(&ncall_mutex);
161 return (error);
162 }
163
164
165 int
_info(struct modinfo * modinfop)166 _info(struct modinfo *modinfop)
167 {
168 return (mod_info(&modlinkage, modinfop));
169 }
170
171 static int
ncall_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)172 ncall_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
173 {
174 switch (cmd) {
175
176 case DDI_ATTACH:
177 ncall_dip = dip;
178
179 if (ddi_create_minor_node(dip, "c,ncall", S_IFCHR,
180 0, DDI_PSEUDO, 0) != DDI_SUCCESS)
181 goto failed;
182
183 ddi_report_dev(dip);
184
185 return (DDI_SUCCESS);
186
187 default:
188 return (DDI_FAILURE);
189 }
190
191 failed:
192 (void) ncall_detach(dip, DDI_DETACH);
193 return (DDI_FAILURE);
194 }
195
196
197 static int
ncall_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)198 ncall_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
199 {
200 switch (cmd) {
201
202 case DDI_DETACH:
203
204 /*
205 * If still active, then refuse to detach.
206 */
207
208 if (ncall_modules != NULL || ncall_active)
209 return (DDI_FAILURE);
210
211 /*
212 * Remove all minor nodes.
213 */
214
215 ddi_remove_minor_node(dip, NULL);
216 ncall_dip = NULL;
217
218 return (DDI_SUCCESS);
219
220 default:
221 return (DDI_FAILURE);
222 }
223 }
224
225
226 /* ARGSUSED */
227
228 static int
ncall_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)229 ncall_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
230 {
231 int rc = DDI_FAILURE;
232
233 switch (infocmd) {
234
235 case DDI_INFO_DEVT2DEVINFO:
236 *result = ncall_dip;
237 rc = DDI_SUCCESS;
238 break;
239
240 case DDI_INFO_DEVT2INSTANCE:
241 /*
242 * We only have a single instance.
243 */
244 *result = 0;
245 rc = DDI_SUCCESS;
246 break;
247
248 default:
249 break;
250 }
251
252 return (rc);
253 }
254
255
256 /* ARGSUSED */
257 static int
ncallprint(dev_t dev,char * str)258 ncallprint(dev_t dev, char *str)
259 {
260 cmn_err(CE_WARN, "%s%d: %s", ddi_get_name(ncall_dip),
261 ddi_get_instance(ncall_dip), str);
262
263 return (0);
264 }
265
266
267 int
ncall_register_module(ncall_module_t * mp,ncall_node_t * nodep)268 ncall_register_module(ncall_module_t *mp, ncall_node_t *nodep)
269 {
270 ncall_modinfo_t *new;
271 int rc = 0;
272
273 if (mp == NULL || mp->ncall_version != NCALL_MODULE_VER)
274 return (EINVAL);
275
276 new = kmem_alloc(sizeof (*new), KM_SLEEP);
277
278 if (new != NULL) {
279 new->module = mp;
280
281 mutex_enter(&ncall_mutex);
282
283 new->next = ncall_modules;
284 ncall_modules = new;
285
286 mutex_exit(&ncall_mutex);
287 } else {
288 rc = ENOMEM;
289 }
290
291 *nodep = ncall_nodeinfo; /* structure copy */
292 return (rc);
293 }
294
295
296 int
ncall_unregister_module(ncall_module_t * mod)297 ncall_unregister_module(ncall_module_t *mod)
298 {
299 ncall_modinfo_t **mpp;
300 int rc = ESRCH;
301
302 mutex_enter(&ncall_mutex);
303
304 for (mpp = &ncall_modules; *mpp != NULL; mpp = &((*mpp)->next)) {
305 if ((*mpp)->module == mod) {
306 *mpp = (*mpp)->next;
307 rc = 0;
308 break;
309 }
310 }
311
312 mutex_exit(&ncall_mutex);
313
314 return (rc);
315 }
316
317
318 static int
ncall_stop(void)319 ncall_stop(void)
320 {
321 ncall_modinfo_t *mod;
322 int rc = 0;
323
324 mutex_enter(&ncall_mutex);
325
326 while ((rc == 0) && ((mod = ncall_modules) != NULL)) {
327 mutex_exit(&ncall_mutex);
328
329 rc = (*mod->module->ncall_stop)();
330
331 mutex_enter(&ncall_mutex);
332 }
333
334 mutex_exit(&ncall_mutex);
335
336 return (rc);
337 }
338
339
340 /* ARGSUSED */
ncallioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * crp,int * rvalp)341 static int ncallioctl(dev_t dev, int cmd, intptr_t arg, int mode,
342 cred_t *crp, int *rvalp)
343 {
344 ncall_node_t node = { 0, };
345 int mirror;
346 int rc = 0;
347
348 *rvalp = 0;
349
350 if ((rc = drv_priv(crp)) != 0)
351 return (rc);
352
353 switch (cmd) {
354
355 case NC_IOC_START:
356 if (ncall_active) {
357 rc = EALREADY;
358 break;
359 }
360
361 if (ddi_copyin((void *)arg, &node, sizeof (node), mode) < 0)
362 return (EFAULT);
363
364 bcopy(&node, &ncall_nodeinfo, sizeof (ncall_nodeinfo));
365 ncall_init_stub();
366 ncall_active = 1;
367 break;
368
369 case NC_IOC_STOP:
370 ncall_active = 0;
371 rc = ncall_stop();
372 break;
373
374 case NC_IOC_GETNODE:
375 if (!ncall_active) {
376 rc = ENONET;
377 break;
378 }
379 if (ddi_copyout(&ncall_nodeinfo, (void *)arg,
380 sizeof (ncall_nodeinfo), mode) < 0) {
381 rc = EFAULT;
382 break;
383 }
384 mirror = ncall_mirror(ncall_nodeinfo.nc_nodeid);
385 /*
386 * can't return -1, as this will mask the ioctl
387 * failure, so return 0.
388 */
389 if (mirror == -1)
390 mirror = 0;
391 *rvalp = mirror;
392 break;
393
394 case NC_IOC_GETNETNODES:
395 rc = ncallgetnodes(arg, mode, rvalp);
396 break;
397
398 case NC_IOC_PING:
399 if (!ncall_active) {
400 rc = ENONET;
401 break;
402 }
403
404 if (ddi_copyin((void *)arg, &node, sizeof (node), mode) < 0) {
405 rc = EFAULT;
406 break;
407 }
408
409 node.nc_nodename[sizeof (node.nc_nodename)-1] = '\0';
410 rc = ncall_ping(node.nc_nodename, rvalp);
411 break;
412
413 default:
414 rc = EINVAL;
415 break;
416 }
417
418 return (rc);
419 }
420
421
422 void
ncall_register_svc(int svc_id,void (* func)(ncall_t *,int *))423 ncall_register_svc(int svc_id, void (*func)(ncall_t *, int *))
424 {
425 if (ncall_modules)
426 (*ncall_modules->module->ncall_register_svc)(svc_id, func);
427 }
428
429
430 void
ncall_unregister_svc(int svc_id)431 ncall_unregister_svc(int svc_id)
432 {
433 if (ncall_modules)
434 (*ncall_modules->module->ncall_unregister_svc)(svc_id);
435 }
436
437
438 int
ncall_nodeid(char * nodename)439 ncall_nodeid(char *nodename)
440 {
441 if (ncall_modules)
442 return ((ncall_modules->module->ncall_nodeid)(nodename));
443 else
444 return (0);
445 }
446
447
448 char *
ncall_nodename(int nodeid)449 ncall_nodename(int nodeid)
450 {
451 if (ncall_modules)
452 return ((*ncall_modules->module->ncall_nodename)(nodeid));
453 else
454 return ("unknown");
455 }
456
457
458 int
ncall_mirror(int nodeid)459 ncall_mirror(int nodeid)
460 {
461 if (ncall_modules)
462 return ((*ncall_modules->module->ncall_mirror)(nodeid));
463 else
464 return (-1);
465 }
466
467
468 int
ncall_self(void)469 ncall_self(void)
470 {
471 if (ncall_modules)
472 return ((*ncall_modules->module->ncall_self)());
473 else
474 return (-1);
475 }
476
477
478 int
ncall_alloc(int host_id,int flags,int net,ncall_t ** ncall_p)479 ncall_alloc(int host_id, int flags, int net, ncall_t **ncall_p)
480 {
481 int rc = ENOLINK;
482
483 if (ncall_modules)
484 rc = (*ncall_modules->module->ncall_alloc)(host_id,
485 flags, net, ncall_p);
486
487 return (rc);
488 }
489
490
491 int
ncall_timedsend(ncall_t * ncall,int flags,int svc_id,struct timeval * t,...)492 ncall_timedsend(ncall_t *ncall, int flags, int svc_id,
493 struct timeval *t, ...)
494 {
495 va_list ap;
496 int rc = ENOLINK;
497
498 va_start(ap, t);
499
500 if (ncall_modules)
501 rc = (*ncall_modules->module->ncall_timedsend)(ncall, flags,
502 svc_id, t, ap);
503
504 va_end(ap);
505
506 return (rc);
507 }
508
509 int
ncall_timedsendnotify(ncall_t * ncall,int flags,int svc_id,struct timeval * t,void (* ncall_callback)(ncall_t *,void *),void * vptr,...)510 ncall_timedsendnotify(ncall_t *ncall, int flags, int svc_id,
511 struct timeval *t, void (*ncall_callback)(ncall_t *, void *),
512 void *vptr, ...)
513 {
514 va_list ap;
515 int rc = ENOLINK;
516
517 va_start(ap, vptr);
518
519 if (ncall_modules)
520 rc = (*ncall_modules->module->ncall_timedsendnotify)(ncall,
521 flags, svc_id, t, ncall_callback, vptr, ap);
522 va_end(ap);
523
524 return (rc);
525 }
526
527 int
ncall_broadcast(ncall_t * ncall,int flags,int svc_id,struct timeval * t,...)528 ncall_broadcast(ncall_t *ncall, int flags, int svc_id,
529 struct timeval *t, ...)
530 {
531 va_list ap;
532 int rc = ENOLINK;
533
534 va_start(ap, t);
535
536 if (ncall_modules)
537 rc = (*ncall_modules->module->ncall_broadcast)(ncall, flags,
538 svc_id, t, ap);
539 va_end(ap);
540
541 return (rc);
542 }
543
544
545 int
ncall_send(ncall_t * ncall,int flags,int svc_id,...)546 ncall_send(ncall_t *ncall, int flags, int svc_id, ...)
547 {
548 va_list ap;
549 int rc = ENOLINK;
550
551 va_start(ap, svc_id);
552
553 if (ncall_modules)
554 rc = (*ncall_modules->module->ncall_timedsend)(ncall, flags,
555 svc_id, NULL, ap);
556
557 va_end(ap);
558
559 return (rc);
560 }
561
562
563 int
ncall_read_reply(ncall_t * ncall,int n,...)564 ncall_read_reply(ncall_t *ncall, int n, ...)
565 {
566 va_list ap;
567 int rc = ENOLINK;
568
569 va_start(ap, n);
570
571 if (ncall_modules)
572 rc = (*ncall_modules->module->ncall_read_reply)(ncall, n, ap);
573
574 va_end(ap);
575
576 return (rc);
577 }
578
579
580 void
ncall_reset(ncall_t * ncall)581 ncall_reset(ncall_t *ncall)
582 {
583 if (ncall_modules)
584 (*ncall_modules->module->ncall_reset)(ncall);
585 }
586
587
588 void
ncall_free(ncall_t * ncall)589 ncall_free(ncall_t *ncall)
590 {
591 if (ncall_modules)
592 (*ncall_modules->module->ncall_free)(ncall);
593 }
594
595
596 int
ncall_put_data(ncall_t * ncall,void * data,int len)597 ncall_put_data(ncall_t *ncall, void *data, int len)
598 {
599 int rc = ENOLINK;
600
601 if (ncall_modules)
602 rc = (*ncall_modules->module->ncall_put_data)(ncall, data, len);
603
604 return (rc);
605 }
606
607
608 int
ncall_get_data(ncall_t * ncall,void * data,int len)609 ncall_get_data(ncall_t *ncall, void *data, int len)
610 {
611 int rc = ENOLINK;
612
613 if (ncall_modules)
614 rc = (*ncall_modules->module->ncall_get_data)(ncall, data, len);
615
616 return (rc);
617 }
618
619
620 int
ncall_sender(ncall_t * ncall)621 ncall_sender(ncall_t *ncall)
622 {
623 int rc = -1;
624
625 if (ncall_modules)
626 rc = (*ncall_modules->module->ncall_sender)(ncall);
627
628 return (rc);
629 }
630
631
632 void
ncall_reply(ncall_t * ncall,...)633 ncall_reply(ncall_t *ncall, ...)
634 {
635 va_list ap;
636
637 if (ncall_modules) {
638 va_start(ap, ncall);
639
640 (*ncall_modules->module->ncall_reply)(ncall, ap);
641
642 va_end(ap);
643 }
644 }
645
646
647 void
ncall_pend(ncall_t * ncall)648 ncall_pend(ncall_t *ncall)
649 {
650 if (ncall_modules)
651 (*ncall_modules->module->ncall_pend)(ncall);
652 }
653
654
655 void
ncall_done(ncall_t * ncall)656 ncall_done(ncall_t *ncall)
657 {
658 if (ncall_modules)
659 (*ncall_modules->module->ncall_done)(ncall);
660 }
661
662 int
ncall_ping(char * nodename,int * up)663 ncall_ping(char *nodename, int *up)
664 {
665 int rc = ENOLINK;
666 if (ncall_modules)
667 rc = (*ncall_modules->module->ncall_ping)(nodename, up);
668 return (rc);
669 }
670
671 int
ncall_maxnodes()672 ncall_maxnodes()
673 {
674 int rc = 0;
675
676 if (ncall_modules)
677 rc = (*ncall_modules->module->ncall_maxnodes)();
678
679 return (rc);
680 }
681
682 int
ncall_nextnode(void ** vptr)683 ncall_nextnode(void **vptr)
684 {
685 int rc = 0;
686
687 if (ncall_modules)
688 rc = (*ncall_modules->module->ncall_nextnode)(vptr);
689
690 return (rc);
691 }
692
693 int
ncall_errcode(ncall_t * ncall,int * result)694 ncall_errcode(ncall_t *ncall, int *result)
695 {
696 int rc = ENOLINK;
697 if (ncall_modules)
698 rc = (*ncall_modules->module->ncall_errcode)(ncall, result);
699
700 return (rc);
701 }
702
703 static int
ncallgetnodes(intptr_t uaddr,int mode,int * rvalp)704 ncallgetnodes(intptr_t uaddr, int mode, int *rvalp)
705 {
706 ncall_node_t *nodelist;
707 int slot;
708 int rc;
709 int nodecnt;
710 int nodeid;
711 void *sequence;
712 char *nodename;
713
714 rc = 0;
715
716 nodecnt = ncall_maxnodes();
717 if (nodecnt <= 0) {
718 return (ENONET);
719 }
720
721 /*
722 * If the user passes up a null address argument, then
723 * he/she doesn't want the actual nodes, but the configured
724 * maximum, so space can be correctly allocated.
725 */
726
727 if (uaddr == NULL) {
728 *rvalp = nodecnt;
729 return (0);
730 }
731 nodelist = kmem_zalloc(sizeof (*nodelist) * nodecnt, KM_SLEEP);
732
733 slot = 0;
734 sequence = NULL;
735 while ((nodeid = ncall_nextnode(&sequence)) > 0) {
736 nodename = ncall_nodename(nodeid);
737 /*
738 * There is a small window where nextnode can
739 * return a valid nodeid, and it being disabled
740 * which will get nodename to return "".
741 * Discard the nodeid if this happens.
742 */
743 if (strlen(nodename) > 0) {
744 int size = sizeof (nodelist[slot].nc_nodename) - 1;
745 ASSERT(slot < nodecnt);
746 /*
747 * make sure its null terminated when it
748 * gets to userland.
749 */
750 nodelist[slot].nc_nodename[size] = 0;
751 (void) strncpy(nodelist[slot].nc_nodename, nodename,
752 size);
753 nodelist[slot].nc_nodeid = nodeid;
754 slot++;
755 }
756 }
757 if (ddi_copyout(nodelist, (void *)uaddr, sizeof (*nodelist) * slot,
758 mode) < 0) {
759 rc = EFAULT;
760 } else {
761 /*
762 * tell them how many have come back.
763 */
764 *rvalp = slot;
765 }
766 kmem_free(nodelist, sizeof (*nodelist) * nodecnt);
767 return (rc);
768 }
769