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 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 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 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 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 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 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 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 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 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 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 428 nsc_load() 429 { 430 nsc_init(); 431 return (0); 432 } 433 434 435 int 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 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 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 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 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 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 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 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 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 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 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 919 _nsc_set_max_devices(int maxdev) 920 { 921 _nsc_max_devices = maxdev; 922 _nsc_maxdev = _nsc_max_devices; 923 } 924