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 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 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 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 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 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 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 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 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 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 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 425 nsc_load() 426 { 427 nsc_init(); 428 return (0); 429 } 430 431 432 int 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 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 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 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 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 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 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 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 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 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 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 916 _nsc_set_max_devices(int maxdev) 917 { 918 _nsc_max_devices = maxdev; 919 _nsc_maxdev = _nsc_max_devices; 920 } 921