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