Home | History | Annotate | Download | only in nsctl
      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