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