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