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 }