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 }