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 }