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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 */
26
27 #include <sys/types.h>
28 #include <sys/ksynch.h>
29 #include <sys/kmem.h>
30 #include <sys/file.h>
31 #include <sys/errno.h>
32 #include <sys/open.h>
33 #include <sys/cred.h>
34 #include <sys/conf.h>
35 #include <sys/uio.h>
36 #include <sys/cmn_err.h>
37 #include <sys/modctl.h>
38 #include <sys/ddi.h>
39
40 #define __NSC_GEN__
41 #include <sys/nsctl/nsc_dev.h>
42 #include <sys/nsctl/nsc_gen.h>
43 #include <sys/nsctl/nsc_ioctl.h>
44 #include <sys/nsctl/nsc_power.h>
45 #include <sys/nsctl/nsc_mem.h>
46 #include "../nsctl.h"
47
48 #include <sys/nsctl/nsvers.h>
49
50 #ifdef DS_DDICT
51 #include "../contract.h"
52 #endif
53
54 extern void nscsetup();
55 extern int _nsc_init_raw(int);
56 extern void _nsc_deinit_raw();
57 extern void _nsc_init_start();
58 extern void _nsc_init_os(), _nsc_deinit_os();
59 extern void _nsc_init_dev(), _nsc_init_mem();
60 extern void _nsc_init_gen(), _nsc_init_rmlock();
61 extern void _nsc_init_resv(), _nsc_deinit_resv();
62 extern void _nsc_init_frz(), _nsc_deinit_frz();
63 extern void _nsc_init_ncio(), _nsc_deinit_ncio();
64 extern void _nsc_deinit_mem(), _nsc_deinit_rmlock();
65 extern void _nsc_deinit_dev();
66
67 extern int _nsc_frz_start(char *, int *);
68 extern int _nsc_frz_stop(char *, int *);
69 extern int _nsc_frz_isfrozen(char *, int *);
70
71 extern nsc_mem_t *_nsc_local_mem;
72 extern nsc_rmhdr_t *_nsc_rmhdr_ptr;
73 extern nsc_def_t _nsc_raw_def[];
74 extern int _nsc_raw_flags;
75
76 int nsc_devflag = D_MP;
77
78 int _nsc_init_done = 0;
79
80 kmutex_t _nsc_drv_lock;
81 nsc_io_t *_nsc_file_io;
82 nsc_io_t *_nsc_vchr_io;
83 nsc_io_t *_nsc_raw_io;
84
85 nsc_fd_t **_nsc_minor_fd;
86 kmutex_t **_nsc_minor_slp;
87
88
89 /* Maximum number of devices - tunable in nsctl.conf */
90 static int _nsc_max_devices;
91
92 /* Internal version of _nsc_max_devices */
93 int _nsc_maxdev;
94
95 extern void _nsc_global_setup(void);
96
97 static int nsc_load(), nsc_unload();
98 static void nscteardown();
99
100 /*
101 * Solaris specific driver module interface code.
102 */
103
104 extern int nscopen(dev_t *, int, int, cred_t *);
105 extern int nscioctl(dev_t, int, intptr_t, int, cred_t *, int *);
106 extern int nscclose(dev_t, int, int, cred_t *);
107 extern int nscread(dev_t, uio_t *, cred_t *);
108 extern int nscwrite(dev_t, uio_t *, cred_t *);
109
110 static dev_info_t *nsctl_dip; /* Single DIP for driver */
111
112 static int _nsctl_print(dev_t, char *);
113
114 static struct cb_ops nsctl_cb_ops = {
115 nscopen, /* open */
116 nscclose, /* close */
117 nodev, /* not a block driver, strategy not an entry point */
118 _nsctl_print, /* no print routine */
119 nodev, /* no dump routine */
120 nscread, /* read */
121 nscwrite, /* write */
122 (int (*)()) nscioctl, /* ioctl */
123 nodev, /* no devmap routine */
124 nodev, /* no mmap routine */
125 nodev, /* no segmap routine */
126 nochpoll, /* no chpoll routine */
127 ddi_prop_op,
128 0, /* not a STREAMS driver, no cb_str routine */
129 D_NEW | D_MP | D_64BIT, /* safe for multi-thread/multi-processor */
130 CB_REV,
131 nodev, /* aread */
132 nodev, /* awrite */
133 };
134
135 static int _nsctl_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
136 static int _nsctl_attach(dev_info_t *, ddi_attach_cmd_t);
137 static int _nsctl_detach(dev_info_t *, ddi_detach_cmd_t);
138
139 static struct dev_ops nsctl_ops = {
140 DEVO_REV, /* Driver build version */
141 0, /* device reference count */
142 _nsctl_getinfo,
143 nulldev, /* Identify */
144 nulldev, /* Probe */
145 _nsctl_attach,
146 _nsctl_detach,
147 nodev, /* Reset */
148 &nsctl_cb_ops,
149 (struct bus_ops *)0
150 };
151
152 static struct modldrv nsctl_ldrv = {
153 &mod_driverops,
154 "nws:Control:" ISS_VERSION_STR,
155 &nsctl_ops
156 };
157
158 static struct modlinkage nsctl_modlinkage = {
159 MODREV_1,
160 { &nsctl_ldrv, NULL }
161 };
162
163 /*
164 * Solaris module load time code
165 */
166
167 int nsc_min_nodeid;
168 int nsc_max_nodeid;
169
170 int
171 _init(void)
172 {
173 int err;
174
175 err = nsc_load();
176
177 if (!err)
178 err = mod_install(&nsctl_modlinkage);
179
180 if (err) {
181 (void) nsc_unload();
182 cmn_err(CE_NOTE, "!nsctl_init: err %d", err);
183 }
184
185 return (err);
186
187 }
188
189 /*
190 * Solaris module unload time code
191 */
192
193 int
194 _fini(void)
195 {
196 int err;
197
198 if ((err = mod_remove(&nsctl_modlinkage)) == 0) {
199 err = nsc_unload();
200 }
201 return (err);
202 }
203
204 /*
205 * Solaris module info code
206 */
207 int
208 _info(struct modinfo *modinfop)
209 {
210 return (mod_info(&nsctl_modlinkage, modinfop));
211 }
212
213 /*
214 * Attach an instance of the device. This happens before an open
215 * can succeed.
216 */
217 static int
218 _nsctl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
219 {
220 int rc;
221
222 if (cmd == DDI_ATTACH) {
223 nsctl_dip = dip;
224
225 /* Announce presence of the device */
226 ddi_report_dev(dip);
227
228 /*
229 * Get the node parameters now that we can look up.
230 */
231 nsc_min_nodeid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
232 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
233 "nsc_min_nodeid", 0);
234
235 nsc_max_nodeid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
236 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
237 "nsc_max_nodeid", 5);
238
239 _nsc_max_devices = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
240 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
241 "nsc_max_devices", 128);
242
243 _nsc_maxdev = _nsc_max_devices;
244 nscsetup();
245
246 /*
247 * Init raw requires the _nsc_max_devices value and so
248 * cannot be done before the nsc_max_devices property has
249 * been read which can only be done after the module is
250 * attached and we have a dip.
251 */
252
253 if ((rc = _nsc_init_raw(_nsc_max_devices)) != 0) {
254 cmn_err(CE_WARN,
255 "!nsctl: unable to initialize raw io provider: %d",
256 rc);
257 return (DDI_FAILURE);
258 }
259
260 /*
261 * Init rest of soft state structure
262 */
263
264 rc = ddi_create_minor_node(dip, "c,nsctl", S_IFCHR, 0,
265 DDI_PSEUDO, 0);
266 if (rc != DDI_SUCCESS) {
267 /* free anything we allocated here */
268 cmn_err(CE_WARN,
269 "!_nsctl_attach: ddi_create_minor_node failed %d",
270 rc);
271 return (DDI_FAILURE);
272 }
273
274 /* Announce presence of the device */
275 ddi_report_dev(dip);
276
277 /* mark the device as attached, opens may proceed */
278 return (DDI_SUCCESS);
279 } else
280 return (DDI_FAILURE);
281 }
282
283 static int
284 _nsctl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
285 {
286 if (cmd == DDI_DETACH) {
287 nscteardown();
288 _nsc_deinit_raw();
289
290 ddi_remove_minor_node(dip, NULL);
291 nsctl_dip = NULL;
292
293 return (DDI_SUCCESS);
294 }
295 else
296 return (DDI_FAILURE);
297 }
298
299
300 /* ARGSUSED */
301 static int
302 _nsctl_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
303 {
304 dev_t dev;
305 int rc;
306
307 switch (cmd) {
308 case DDI_INFO_DEVT2INSTANCE:
309 /* The "instance" number is the minor number */
310 dev = (dev_t)arg;
311 *result = (void *)(unsigned long)getminor(dev);
312 rc = DDI_SUCCESS;
313 break;
314
315 case DDI_INFO_DEVT2DEVINFO:
316 *result = nsctl_dip;
317 rc = DDI_SUCCESS;
318 break;
319
320 default:
321 rc = DDI_FAILURE;
322 break;
323 }
324
325 return (rc);
326 }
327
328
329 /* ARGSUSED */
330 static int
331 _nsctl_print(dev_t dev, char *s)
332 {
333 cmn_err(CE_WARN, "!nsctl:%s", s);
334 return (0);
335 }
336
337
338 void
339 nsc_init()
340 {
341 if (_nsc_init_done)
342 return;
343
344 _nsc_init_start();
345 _nsc_init_gen();
346 _nsc_init_svc();
347 _nsc_init_mem();
348 _nsc_init_dev();
349 _nsc_init_rmlock();
350 _nsc_init_resv();
351 _nsc_init_os();
352 (void) _nsc_init_power();
353
354 /*
355 * When using mc, nscsetup is done through mc callback to global_init.
356 */
357 nscsetup();
358
359 mutex_init(&_nsc_drv_lock, NULL, MUTEX_DRIVER, NULL);
360
361 _nsc_raw_io = nsc_register_io("raw",
362 NSC_RAW_ID | _nsc_raw_flags, _nsc_raw_def);
363
364 if (!_nsc_raw_io)
365 cmn_err(CE_WARN, "!_nsc_init: register io failed - raw");
366
367 _nsc_init_ncio();
368 _nsc_init_frz();
369
370 _nsc_init_done = 1;
371 }
372
373
374 /*
375 * Called after the mc refresh is complete (SEG_INIT callbacks have
376 * been received) and module _attach() is done. Only does any real
377 * work when all of the above conditions have been met.
378 */
379 void
380 nscsetup()
381 {
382 if (nsc_max_devices() == 0 || _nsc_minor_fd != NULL)
383 return;
384
385 _nsc_minor_fd = nsc_kmem_zalloc(sizeof (nsc_fd_t *)*_nsc_maxdev,
386 0, _nsc_local_mem);
387
388 if (!_nsc_minor_fd) {
389 cmn_err(CE_WARN, "!nscsetup - alloc failed");
390 return;
391 }
392
393 _nsc_minor_slp = nsc_kmem_zalloc(sizeof (kmutex_t *)*_nsc_maxdev,
394 0, _nsc_local_mem);
395
396 if (!_nsc_minor_slp) {
397 cmn_err(CE_WARN, "!nscsetup - alloc failed");
398 nsc_kmem_free(_nsc_minor_fd, sizeof (nsc_fd_t *) * _nsc_maxdev);
399 _nsc_minor_fd = (nsc_fd_t **)NULL;
400 }
401 }
402
403 static void
404 nscteardown()
405 {
406 int i;
407
408 if (_nsc_minor_fd == NULL)
409 return;
410
411 #ifdef DEBUG
412 /* Check all devices were closed. Index 0 is the prototype dev. */
413 for (i = 1; i < _nsc_maxdev; i++) {
414 ASSERT(_nsc_minor_slp[i] == NULL);
415 ASSERT(_nsc_minor_fd[i] == NULL);
416 }
417 #endif /* DEBUG */
418
419 nsc_kmem_free(_nsc_minor_fd, sizeof (nsc_fd_t *) * _nsc_maxdev);
420 nsc_kmem_free(_nsc_minor_slp, sizeof (kmutex_t *) * _nsc_maxdev);
421
422 _nsc_minor_fd = (nsc_fd_t **)NULL;
423 _nsc_minor_slp = (kmutex_t **)NULL;
424 }
425
426 int
427 nsc_load()
428 {
429 nsc_init();
430 return (0);
431 }
432
433
434 int
435 nsc_unload()
436 {
437 if (!_nsc_init_done) {
438 return (0);
439 }
440
441 nscteardown();
442
443 (void) _nsc_deinit_power();
444 _nsc_deinit_resv();
445 _nsc_deinit_mem();
446 _nsc_deinit_rmlock();
447 _nsc_deinit_svc();
448 _nsc_deinit_frz();
449 _nsc_deinit_ncio();
450
451 if (_nsc_vchr_io)
452 (void) nsc_unregister_io(_nsc_vchr_io, 0);
453
454 if (_nsc_file_io)
455 (void) nsc_unregister_io(_nsc_file_io, 0);
456
457 _nsc_vchr_io = NULL;
458 _nsc_file_io = NULL;
459
460 if (_nsc_raw_io)
461 (void) nsc_unregister_io(_nsc_raw_io, 0);
462
463 _nsc_raw_io = NULL;
464
465 _nsc_deinit_dev();
466 _nsc_deinit_os();
467
468 _nsc_init_done = 0;
469 return (0);
470 }
471
472
473 /* ARGSUSED */
474
475 int
476 nscopen(dev_t *devp, int flag, int otyp, cred_t *crp)
477 {
478 kmutex_t *slp;
479 int i, error;
480
481 if (error = drv_priv(crp))
482 return (error);
483
484 if (!_nsc_minor_fd || !_nsc_minor_slp)
485 return (ENXIO);
486
487 if (getminor(*devp) != 0)
488 return (ENXIO);
489
490 slp = nsc_kmem_alloc(sizeof (kmutex_t), 0, _nsc_local_mem);
491 mutex_init(slp, NULL, MUTEX_DRIVER, NULL);
492
493 mutex_enter(&_nsc_drv_lock);
494
495 for (i = 1; i < _nsc_maxdev; i++) {
496 if (_nsc_minor_slp[i] == NULL) {
497 _nsc_minor_slp[i] = slp;
498 break;
499 }
500 }
501
502 mutex_exit(&_nsc_drv_lock);
503
504 if (i >= _nsc_maxdev) {
505 mutex_destroy(slp);
506 nsc_kmem_free(slp, sizeof (kmutex_t));
507 return (EAGAIN);
508 }
509
510 *devp = makedevice(getmajor(*devp), i);
511
512 return (0);
513 }
514
515
516 int
517 _nscopen(dev_t dev, intptr_t arg, int mode, int *rvp)
518 {
519 minor_t mindev = getminor(dev);
520 struct nscioc_open *op;
521 nsc_fd_t *fd;
522 int rc;
523
524 op = nsc_kmem_alloc(sizeof (*op), KM_SLEEP, _nsc_local_mem);
525 if (op == NULL) {
526 return (ENOMEM);
527 }
528
529 if (ddi_copyin((void *)arg, op, sizeof (*op), mode) < 0) {
530 nsc_kmem_free(op, sizeof (*op));
531 return (EFAULT);
532 }
533
534 mutex_enter(_nsc_minor_slp[mindev]);
535
536 if (_nsc_minor_fd[mindev]) {
537 mutex_exit(_nsc_minor_slp[mindev]);
538 nsc_kmem_free(op, sizeof (*op));
539 return (EBUSY);
540 }
541
542 op->path[sizeof (op->path)-1] = 0;
543
544 fd = nsc_open(op->path, (op->flag & NSC_TYPES), 0, 0, &rc);
545
546 if (fd == NULL) {
547 mutex_exit(_nsc_minor_slp[mindev]);
548 nsc_kmem_free(op, sizeof (*op));
549 return (rc);
550 }
551
552 mode |= (op->mode - FOPEN);
553
554 if (mode & (FWRITE|FEXCL)) {
555 if ((rc = nsc_reserve(fd, NSC_PCATCH)) != 0) {
556 mutex_exit(_nsc_minor_slp[mindev]);
557 (void) nsc_close(fd);
558 nsc_kmem_free(op, sizeof (*op));
559 return (rc);
560 }
561 }
562
563 *rvp = 0;
564 _nsc_minor_fd[mindev] = fd;
565
566 mutex_exit(_nsc_minor_slp[mindev]);
567 nsc_kmem_free(op, sizeof (*op));
568 return (0);
569 }
570
571
572 /* ARGSUSED */
573
574 int
575 nscclose(dev_t dev, int flag, int otyp, cred_t *crp)
576 {
577 minor_t mindev = getminor(dev);
578 kmutex_t *slp;
579 nsc_fd_t *fd;
580
581 if (!_nsc_minor_fd || !_nsc_minor_slp)
582 return (0);
583
584 if ((slp = _nsc_minor_slp[mindev]) == 0)
585 return (0);
586
587 if ((fd = _nsc_minor_fd[mindev]) != NULL)
588 (void) nsc_close(fd);
589
590 _nsc_minor_fd[mindev] = NULL;
591 _nsc_minor_slp[mindev] = NULL;
592
593 mutex_destroy(slp);
594 nsc_kmem_free(slp, sizeof (kmutex_t));
595 return (0);
596 }
597
598
599 /* ARGSUSED */
600
601 int
602 nscread(dev_t dev, uio_t *uiop, cred_t *crp)
603 {
604 minor_t mindev = getminor(dev);
605 int rc, resv;
606 nsc_fd_t *fd;
607
608 if ((fd = _nsc_minor_fd[mindev]) == 0)
609 return (EIO);
610
611 mutex_enter(_nsc_minor_slp[mindev]);
612
613 resv = (nsc_held(fd) == 0);
614
615 if (resv && (rc = nsc_reserve(fd, NSC_PCATCH)) != 0) {
616 mutex_exit(_nsc_minor_slp[mindev]);
617 return (rc);
618 }
619
620 rc = nsc_uread(fd, uiop, crp);
621
622 if (resv)
623 nsc_release(fd);
624
625 mutex_exit(_nsc_minor_slp[mindev]);
626 return (rc);
627 }
628
629
630 /* ARGSUSED */
631
632 int
633 nscwrite(dev_t dev, uio_t *uiop, cred_t *crp)
634 {
635 minor_t mindev = getminor(dev);
636 int rc, resv;
637 nsc_fd_t *fd;
638
639 if ((fd = _nsc_minor_fd[mindev]) == 0)
640 return (EIO);
641
642 mutex_enter(_nsc_minor_slp[mindev]);
643
644 resv = (nsc_held(fd) == 0);
645
646 if (resv && (rc = nsc_reserve(fd, NSC_PCATCH)) != 0) {
647 mutex_exit(_nsc_minor_slp[mindev]);
648 return (rc);
649 }
650
651 rc = nsc_uwrite(fd, uiop, crp);
652
653 if (resv)
654 nsc_release(fd);
655
656 mutex_exit(_nsc_minor_slp[mindev]);
657 return (rc);
658 }
659
660
661 int
662 _nscreserve(dev_t dev, int *rvp)
663 {
664 minor_t mindev = getminor(dev);
665 nsc_fd_t *fd;
666 int rc;
667
668 if ((fd = _nsc_minor_fd[mindev]) == 0)
669 return (EIO);
670
671 mutex_enter(_nsc_minor_slp[mindev]);
672
673 if (nsc_held(fd)) {
674 mutex_exit(_nsc_minor_slp[mindev]);
675 return (EBUSY);
676 }
677
678 if ((rc = nsc_reserve(fd, NSC_PCATCH)) != 0) {
679 mutex_exit(_nsc_minor_slp[mindev]);
680 return (rc);
681 }
682
683 *rvp = 0;
684
685 mutex_exit(_nsc_minor_slp[mindev]);
686 return (0);
687 }
688
689
690 int
691 _nscrelease(dev_t dev, int *rvp)
692 {
693 minor_t mindev = getminor(dev);
694 nsc_fd_t *fd;
695
696 if ((fd = _nsc_minor_fd[mindev]) == 0)
697 return (EIO);
698
699 mutex_enter(_nsc_minor_slp[mindev]);
700
701 if (!nsc_held(fd)) {
702 mutex_exit(_nsc_minor_slp[mindev]);
703 return (EINVAL);
704 }
705
706 nsc_release(fd);
707
708 *rvp = 0;
709
710 mutex_exit(_nsc_minor_slp[mindev]);
711 return (0);
712 }
713
714
715 int
716 _nscpartsize(dev_t dev, intptr_t arg, int mode)
717 {
718 struct nscioc_partsize partsize;
719 minor_t mindev = getminor(dev);
720 nsc_size_t size;
721 int rc, resv;
722 nsc_fd_t *fd;
723
724 if ((fd = _nsc_minor_fd[mindev]) == 0)
725 return (EIO);
726
727 mutex_enter(_nsc_minor_slp[mindev]);
728
729 resv = (nsc_held(fd) == 0);
730
731 if (resv && (rc = nsc_reserve(fd, NSC_PCATCH)) != 0) {
732 mutex_exit(_nsc_minor_slp[mindev]);
733 return (rc);
734 }
735
736 rc = nsc_partsize(fd, &size);
737 partsize.partsize = (uint64_t)size;
738
739 if (resv)
740 nsc_release(fd);
741
742 mutex_exit(_nsc_minor_slp[mindev]);
743
744 if (ddi_copyout((void *)&partsize, (void *)arg,
745 sizeof (partsize), mode) < 0) {
746 return (EFAULT);
747 }
748
749 return (rc);
750 }
751
752
753 /* ARGSUSED */
754
755 int
756 nscioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp, int *rvp)
757 {
758 struct nscioc_bsize *bsize = NULL;
759 char *path = NULL;
760 int rc = 0;
761
762 *rvp = 0;
763
764 switch (cmd) {
765 case NSCIOC_OPEN:
766 rc = _nscopen(dev, arg, mode, rvp);
767 break;
768
769 case NSCIOC_RESERVE:
770 rc = _nscreserve(dev, rvp);
771 break;
772
773 case NSCIOC_RELEASE:
774 rc = _nscrelease(dev, rvp);
775 break;
776
777 case NSCIOC_PARTSIZE:
778 rc = _nscpartsize(dev, arg, mode);
779 break;
780
781 case NSCIOC_FREEZE:
782 path = nsc_kmem_alloc(NSC_MAXPATH, KM_SLEEP, _nsc_local_mem);
783 if (path == NULL) {
784 rc = ENOMEM;
785 break;
786 }
787 if (ddi_copyin((void *)arg, path, NSC_MAXPATH, mode) < 0)
788 rc = EFAULT;
789 else {
790 path[NSC_MAXPATH-1] = 0;
791 rc = _nsc_frz_start(path, rvp);
792 }
793 break;
794
795 case NSCIOC_UNFREEZE:
796 path = nsc_kmem_alloc(NSC_MAXPATH, KM_SLEEP, _nsc_local_mem);
797 if (path == NULL) {
798 rc = ENOMEM;
799 break;
800 }
801 if (ddi_copyin((void *)arg, path, NSC_MAXPATH, mode) < 0)
802 rc = EFAULT;
803 else {
804 path[NSC_MAXPATH-1] = 0;
805 rc = _nsc_frz_stop(path, rvp);
806 }
807 break;
808
809 case NSCIOC_ISFROZEN:
810 path = nsc_kmem_alloc(NSC_MAXPATH, KM_SLEEP, _nsc_local_mem);
811 if (path == NULL) {
812 rc = ENOMEM;
813 break;
814 }
815 if (ddi_copyin((void *)arg, path, NSC_MAXPATH, mode) < 0)
816 rc = EFAULT;
817 else {
818 path[NSC_MAXPATH-1] = 0;
819 rc = _nsc_frz_isfrozen(path, rvp);
820 }
821 break;
822
823 #ifdef ENABLE_POWER_MSG
824 case NSCIOC_POWERMSG:
825 rc = _nsc_power((void *)arg, rvp);
826 break;
827 #endif
828
829 case NSCIOC_NSKERND:
830 rc = nskernd_command(arg, mode, rvp);
831 break;
832
833 /* return sizes of global memory segments */
834 case NSCIOC_GLOBAL_SIZES:
835 if (!_nsc_init_done) {
836 rc = EINVAL;
837 break;
838 }
839
840 rc = _nsc_get_global_sizes((void *)arg, rvp);
841
842 break;
843
844 /* return contents of global segments */
845 case NSCIOC_GLOBAL_DATA:
846 if (!_nsc_init_done) {
847 rc = EINVAL;
848 break;
849 }
850
851 rc = _nsc_get_global_data((void *)arg, rvp);
852 break;
853
854 /*
855 * nvmem systems:
856 * clear the hdr dirty bit to prevent loading from nvme on reboot
857 */
858 case NSCIOC_NVMEM_CLEANF:
859 rc = _nsc_clear_dirty(1); /* dont be nice about it */
860 break;
861 case NSCIOC_NVMEM_CLEAN:
862 rc = _nsc_clear_dirty(0);
863 break;
864
865 case NSCIOC_BSIZE:
866 bsize = nsc_kmem_alloc(sizeof (*bsize), KM_SLEEP,
867 _nsc_local_mem);
868 if (bsize == NULL) {
869 rc = ENOMEM;
870 break;
871 }
872
873 if (ddi_copyin((void *)arg, bsize, sizeof (*bsize), mode) < 0) {
874 rc = EFAULT;
875 break;
876 }
877
878 rc = nskern_bsize(bsize, rvp);
879 if (rc == 0) {
880 if (ddi_copyout(bsize, (void *)arg,
881 sizeof (*bsize), mode) < 0) {
882 rc = EFAULT;
883 break;
884 }
885 }
886
887 break;
888
889 default:
890 return (ENOTTY);
891 }
892
893 if (bsize != NULL) {
894 nsc_kmem_free(bsize, sizeof (*bsize));
895 bsize = NULL;
896 }
897 if (path != NULL) {
898 nsc_kmem_free(path, NSC_MAXPATH);
899 path = NULL;
900 }
901 return (rc);
902 }
903
904
905 int
906 nsc_max_devices(void)
907 {
908 return (_nsc_max_devices);
909 }
910
911
912 /*
913 * Used by _nsc_global_setup() in case nvram is dirty and has saved a different
914 * value for nsc_max_devices. We need to use the saved value, not the new
915 * one configured by the user.
916 */
917 void
918 _nsc_set_max_devices(int maxdev)
919 {
920 _nsc_max_devices = maxdev;
921 _nsc_maxdev = _nsc_max_devices;
922 }