xref: /titanic_52/usr/src/uts/common/avs/ns/solaris/nsc_raw.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
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/debug.h>
28 #include <sys/kmem.h>
29 #include <sys/ksynch.h>
30 #ifndef DS_DDICT
31 #include <sys/vnode.h>
32 #endif
33 #include <sys/cmn_err.h>
34 #include <sys/open.h>
35 #include <sys/file.h>
36 #include <sys/cred.h>
37 #include <sys/conf.h>
38 #include <sys/errno.h>
39 #include <sys/uio.h>
40 #ifndef DS_DDICT
41 #include <sys/pathname.h>	/* for lookupname */
42 #endif
43 #include <sys/ddi.h>
44 #include <sys/sunddi.h>
45 #include <sys/sunldi.h>
46 
47 #include <ns/solaris/nsc_thread.h>
48 #ifdef DS_DDICT
49 #include "../contract.h"
50 #endif
51 #include "../nsctl.h"
52 #include "nskernd.h"
53 
54 
55 typedef struct raw_maj {
56 	struct raw_maj	*next;
57 	major_t		major;
58 	struct dev_ops	*devops;
59 	strategy_fn_t	strategy;
60 	int		(*open)(dev_t *, int, int, cred_t *);
61 	int		(*close)(dev_t, int, int, cred_t *);
62 	int		(*ioctl)(dev_t, int, intptr_t, int, cred_t *, int *);
63 } raw_maj_t;
64 
65 typedef struct raw_dev {
66 	ldi_handle_t	lh;		/* Solaris layered driver handle */
67 	struct vnode	*vp;		/* vnode of device */
68 	uint64_t	size;		/* size of device in blocks */
69 	raw_maj_t	*major;		/* pointer to major structure */
70 	char		*path;		/* pathname -- kmem_alloc'd */
71 	int		plen;		/* length of kmem_alloc for pathname */
72 	dev_t		rdev;		/* device number */
73 	char		in_use;		/* flag */
74 	int		partition;	/* partition number */
75 } raw_dev_t;
76 
77 static int fd_hwm = 0;	/* first never used entry in _nsc_raw_files */
78 
79 static raw_dev_t *_nsc_raw_files;
80 static raw_maj_t *_nsc_raw_majors;
81 
82 kmutex_t _nsc_raw_lock;
83 
84 int _nsc_raw_flags = 0;				/* required by nsctl */
85 static int _nsc_raw_maxdevs;			/* local copy */
86 
87 static int _raw_strategy(struct buf *);		/* forward decl */
88 
89 static dev_t
90 ldi_get_dev_t_from_path(char *path)
91 {
92 	vnode_t	*vp;
93 	dev_t rdev;
94 
95 	/* Validate parameters */
96 	if (path == NULL)
97 		return (NULL);
98 
99 	/* Lookup path */
100 	vp = NULL;
101 	if (lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp))
102 		return (NULL);
103 
104 	/* Validate resulting vnode */
105 	if ((vp) && (vp->v_type == VCHR))
106 		rdev = vp->v_rdev;
107 	else
108 		rdev = (dev_t)NULL;
109 
110 	/* Release vnode */
111 	if (vp)
112 		VN_RELE(vp);
113 
114 	return (rdev);
115 }
116 
117 int
118 _nsc_init_raw(int maxdevs)
119 {
120 	_nsc_raw_files =
121 	    kmem_zalloc(sizeof (*_nsc_raw_files) * maxdevs, KM_SLEEP);
122 	if (!_nsc_raw_files)
123 		return (ENOMEM);
124 
125 	_nsc_raw_maxdevs = maxdevs;
126 	_nsc_raw_majors = NULL;
127 
128 	mutex_init(&_nsc_raw_lock, NULL, MUTEX_DRIVER, NULL);
129 	return (0);
130 }
131 
132 
133 void
134 _nsc_deinit_raw(void)
135 {
136 	raw_maj_t *maj = _nsc_raw_majors;
137 	raw_maj_t *next;
138 
139 	/*  Free the memory allocated for strategy pointers */
140 	while (maj != NULL) {
141 		next = maj->next;
142 		kmem_free(maj, sizeof (*maj));
143 		maj = next;
144 	}
145 
146 	mutex_destroy(&_nsc_raw_lock);
147 	kmem_free(_nsc_raw_files, sizeof (*_nsc_raw_files) * _nsc_raw_maxdevs);
148 	_nsc_raw_files = NULL;
149 	_nsc_raw_maxdevs = 0;
150 }
151 
152 
153 /* must be called with the _nsc_raw_lock held */
154 static raw_maj_t *
155 _raw_get_maj_info(major_t umaj)
156 {
157 	raw_maj_t *maj = _nsc_raw_majors;
158 
159 	ASSERT(MUTEX_HELD(&_nsc_raw_lock));
160 
161 	/*  Walk through the linked list */
162 	while (maj != NULL) {
163 		if (maj->major == umaj) {
164 			/* Found major number */
165 			break;
166 		}
167 		maj = maj->next;
168 	}
169 
170 	if (maj == NULL) {
171 		struct dev_ops *ops = NULL;
172 #ifdef DEBUG
173 		const int maxtry = 5;
174 		int try = maxtry;
175 #endif
176 
177 		/*
178 		 * The earlier ldi_open call has locked the driver
179 		 * for this major number into memory, so just index into
180 		 * the devopsp array to get the dev_ops pointer which
181 		 * must be valid.
182 		 */
183 
184 		ops = devopsp[umaj];
185 
186 		if (ops == NULL || ops->devo_cb_ops == NULL) {
187 			cmn_err(CE_WARN,
188 			    "nskern: cannot find dev_ops for major %d", umaj);
189 
190 			return (NULL);
191 		}
192 
193 #ifdef DEBUG
194 		cmn_err(CE_NOTE,
195 			"nsc_raw: held driver (%d) after %d attempts",
196 			umaj, (maxtry - try));
197 #endif /* DEBUG */
198 
199 		maj = kmem_zalloc(sizeof (raw_maj_t), KM_NOSLEEP);
200 		if (!maj) {
201 			return (NULL);
202 		}
203 
204 		maj->strategy = ops->devo_cb_ops->cb_strategy;
205 		maj->ioctl = ops->devo_cb_ops->cb_ioctl;
206 		maj->close = ops->devo_cb_ops->cb_close;
207 		maj->open = ops->devo_cb_ops->cb_open;
208 		maj->major = umaj;
209 		maj->devops = ops;
210 
211 		if (maj->strategy == NULL ||
212 		    maj->strategy == nodev ||
213 		    maj->strategy == nulldev) {
214 			cmn_err(CE_WARN,
215 			    "nskern: no strategy function for "
216 			    "disk driver (major %d)",
217 			    umaj);
218 			kmem_free(maj, sizeof (*maj));
219 			return (NULL);
220 		}
221 
222 		maj->next = _nsc_raw_majors;
223 		_nsc_raw_majors = maj;
224 	}
225 
226 	return (maj);
227 }
228 
229 
230 /*
231  * nsc_get_strategy returns the strategy function associated with
232  * the major number umaj.  NULL is returned if no strategy is found.
233  */
234 strategy_fn_t
235 nsc_get_strategy(major_t umaj)
236 {
237 	raw_maj_t *maj;
238 	strategy_fn_t strategy = NULL;
239 
240 	mutex_enter(&_nsc_raw_lock);
241 
242 	for (maj = _nsc_raw_majors; maj != NULL; maj = maj->next) {
243 		if (maj->major == umaj) {
244 			/* Found major number */
245 			strategy = maj->strategy;
246 			break;
247 		}
248 	}
249 
250 	mutex_exit(&_nsc_raw_lock);
251 
252 	return (strategy);
253 }
254 
255 
256 void *
257 nsc_get_devops(major_t umaj)
258 {
259 	raw_maj_t *maj;
260 	void *devops = NULL;
261 
262 	mutex_enter(&_nsc_raw_lock);
263 
264 	for (maj = _nsc_raw_majors; maj != NULL; maj = maj->next) {
265 		if (maj->major == umaj) {
266 			devops = maj->devops;
267 			break;
268 		}
269 	}
270 
271 	mutex_exit(&_nsc_raw_lock);
272 
273 	return (devops);
274 }
275 
276 
277 /*
278  * _raw_open
279  *
280  * Multiple opens, single close.
281  */
282 
283 /* ARGSUSED */
284 static int
285 _raw_open(char *path, int flag, blind_t *cdp, void *iodev)
286 {
287 	struct cred *cred;
288 	raw_dev_t *cdi = NULL;
289 	char *spath;
290 	dev_t rdev;
291 	int rc, cd, the_cd;
292 	int plen;
293 	ldi_ident_t	li;
294 
295 	if (proc_nskernd == NULL) {
296 		cmn_err(CE_WARN, "nskern: no nskernd daemon running!");
297 		return (ENXIO);
298 	}
299 
300 	if (_nsc_raw_maxdevs == 0) {
301 		cmn_err(CE_WARN, "nskern: _raw_open() before _nsc_init_raw()!");
302 		return (ENXIO);
303 	}
304 
305 	plen = strlen(path) + 1;
306 	spath = kmem_alloc(plen, KM_SLEEP);
307 	if (spath == NULL) {
308 		cmn_err(CE_WARN,
309 		    "nskern: unable to alloc memory in _raw_open()");
310 		return (ENOMEM);
311 	}
312 
313 	(void) strcpy(spath, path);
314 
315 	/*
316 	 * Lookup the vnode to extract the dev_t info,
317 	 * then release the vnode.
318 	 */
319 	if ((rdev = ldi_get_dev_t_from_path(path)) == 0) {
320 		kmem_free(spath, plen);
321 		return (ENXIO);
322 	}
323 
324 	/*
325 	 * See if this device is already opened
326 	 */
327 
328 	the_cd = -1;
329 
330 	mutex_enter(&_nsc_raw_lock);
331 
332 	for (cd = 0, cdi = _nsc_raw_files; cd < fd_hwm; cd++, cdi++) {
333 		if (rdev == cdi->rdev) {
334 			the_cd = cd;
335 			break;
336 		} else if (the_cd == -1 && !cdi->in_use)
337 			the_cd = cd;
338 	}
339 
340 	if (the_cd == -1) {
341 		if (fd_hwm < _nsc_raw_maxdevs)
342 			the_cd = fd_hwm++;
343 		else {
344 			mutex_exit(&_nsc_raw_lock);
345 			cmn_err(CE_WARN, "_raw_open: too many open devices");
346 			kmem_free(spath, plen);
347 			return (EIO);
348 		}
349 	}
350 
351 	cdi = &_nsc_raw_files[the_cd];
352 	if (cdi->in_use) {
353 		/* already set up - just return */
354 		mutex_exit(&_nsc_raw_lock);
355 		*cdp = (blind_t)cdi->rdev;
356 		kmem_free(spath, plen);
357 		return (0);
358 	}
359 
360 	cdi->partition = -1;
361 	cdi->size = (uint64_t)0;
362 	cdi->rdev = rdev;
363 	cdi->path = spath;
364 	cdi->plen = plen;
365 
366 	cred = ddi_get_cred();
367 
368 	/*
369 	 * Layered driver
370 	 *
371 	 * We use xxx_open_by_dev() since this guarantees that a
372 	 * specfs vnode is created and used, not a standard filesystem
373 	 * vnode. This is necessary since in a cluster PXFS will block
374 	 * vnode operations during switchovers, so we have to use the
375 	 * underlying specfs vnode not the PXFS vnode.
376 	 *
377 	 */
378 
379 	if ((rc = ldi_ident_from_dev(cdi->rdev, &li)) == 0) {
380 		rc = ldi_open_by_dev(&cdi->rdev,
381 		    OTYP_BLK, FREAD|FWRITE, cred, &cdi->lh, li);
382 	}
383 	if (rc != 0) {
384 		cdi->lh = NULL;
385 		goto failed;
386 	}
387 
388 	/*
389 	 * grab the major_t related information
390 	 */
391 
392 	cdi->major = _raw_get_maj_info(getmajor(rdev));
393 	if (cdi->major == NULL) {
394 		/* Out of memory */
395 		cmn_err(CE_WARN,
396 		    "_raw_open: cannot alloc major number structure");
397 
398 		rc = ENOMEM;
399 		goto failed;
400 	}
401 
402 	*cdp = (blind_t)cdi->rdev;
403 	cdi->in_use++;
404 
405 	mutex_exit(&_nsc_raw_lock);
406 
407 	return (rc);
408 
409 failed:
410 
411 	if (cdi->lh)
412 		(void) ldi_close(cdi->lh, FWRITE|FREAD, cred);
413 
414 	bzero(cdi, sizeof (*cdi));
415 
416 	mutex_exit(&_nsc_raw_lock);
417 
418 	kmem_free(spath, plen);
419 	return (rc);
420 }
421 
422 
423 static int
424 __raw_get_cd(dev_t fd)
425 {
426 	int cd;
427 
428 	if (_nsc_raw_maxdevs != 0) {
429 		for (cd = 0; cd < fd_hwm; cd++) {
430 			if (fd == _nsc_raw_files[cd].rdev)
431 				return (cd);
432 		}
433 	}
434 
435 	return (-1);
436 }
437 
438 
439 /*
440  * _raw_close
441  *
442  * Multiple opens, single close.
443  */
444 
445 static int
446 _raw_close(dev_t fd)
447 {
448 	struct cred *cred;
449 	raw_dev_t *cdi;
450 	int rc;
451 	int cd;
452 
453 	mutex_enter(&_nsc_raw_lock);
454 
455 	if ((cd = __raw_get_cd(fd)) == -1 || !_nsc_raw_files[cd].in_use) {
456 		mutex_exit(&_nsc_raw_lock);
457 		return (EIO);
458 	}
459 
460 	cdi = &_nsc_raw_files[cd];
461 
462 	cred = ddi_get_cred();
463 
464 	rc = ldi_close(cdi->lh, FREAD|FWRITE, cred);
465 	if (rc != 0) {
466 		mutex_exit(&_nsc_raw_lock);
467 		return (rc);
468 	}
469 
470 	kmem_free(cdi->path, cdi->plen);
471 
472 	bzero(cdi, sizeof (*cdi));
473 
474 	mutex_exit(&_nsc_raw_lock);
475 
476 	return (0);
477 }
478 
479 
480 /* ARGSUSED */
481 static int
482 _raw_uread(dev_t fd, uio_t *uiop, cred_t *crp)
483 {
484 	return (physio(_raw_strategy, 0, fd, B_READ, minphys, uiop));
485 }
486 
487 
488 /* ARGSUSED */
489 static int
490 _raw_uwrite(dev_t fd, uio_t *uiop, cred_t *crp)
491 {
492 	return (physio(_raw_strategy, 0, fd, B_WRITE, minphys, uiop));
493 }
494 
495 
496 static int
497 _raw_strategy(struct buf *bp)
498 {
499 	int cd = __raw_get_cd(bp->b_edev);
500 
501 	if (cd == -1 || _nsc_raw_files[cd].major == NULL) {
502 		bioerror(bp, ENXIO);
503 		biodone(bp);
504 		return (NULL);
505 	}
506 
507 	return ((*_nsc_raw_files[cd].major->strategy)(bp));
508 }
509 
510 
511 static int
512 _raw_partsize(dev_t fd, nsc_size_t *rvalp)
513 {
514 	int cd;
515 
516 	if ((cd = __raw_get_cd(fd)) == -1 || !_nsc_raw_files[cd].in_use)
517 		return (EIO);
518 
519 	*rvalp = (nsc_size_t)_nsc_raw_files[cd].size;
520 	return (0);
521 }
522 
523 
524 /*
525  * Return largest i/o size.
526  */
527 
528 static nsc_size_t nsc_rawmaxfbas = 0;
529 /* ARGSUSED */
530 static int
531 _raw_maxfbas(dev_t dev, int flag, nsc_size_t *ptr)
532 {
533 	struct buf *bp;
534 	if (flag == NSC_CACHEBLK)
535 		*ptr = 1;
536 	else {
537 		if (nsc_rawmaxfbas == 0) {
538 			bp = getrbuf(KM_SLEEP);
539 			bp->b_bcount = 4096 * 512;
540 			minphys(bp);
541 			nsc_rawmaxfbas = FBA_NUM(bp->b_bcount);
542 			freerbuf(bp);
543 		}
544 		*ptr = nsc_rawmaxfbas;
545 	}
546 	return (0);
547 }
548 
549 
550 /*
551  * Control device or system.
552  */
553 
554 /* ARGSUSED */
555 static int
556 _raw_control(dev_t dev, int cmd, int *ptr)
557 {
558 #ifdef DEBUG
559 	cmn_err(CE_WARN, "unrecognised nsc_control: %x", cmd);
560 #endif
561 	return (EINVAL);	/* no control commands understood */
562 }
563 
564 
565 static int
566 _raw_get_bsize(dev_t dev, uint64_t *bsizep, int *partitionp)
567 {
568 #ifdef DKIOCPARTITION
569 	struct partition64 *p64 = NULL;
570 #endif
571 	struct dk_cinfo *dki_info = NULL;
572 	struct dev_ops *ops;
573 	struct cred *cred;
574 	struct vtoc *vtoc = NULL;
575 	dev_info_t *dip;
576 	raw_dev_t *cdi;
577 	int rc, cd;
578 	int flags;
579 	int rval;
580 
581 	*partitionp = -1;
582 	*bsizep = 0;
583 
584 	if ((cd = __raw_get_cd(dev)) == -1 || !_nsc_raw_files[cd].in_use)
585 		return (-1);
586 
587 	cdi = &_nsc_raw_files[cd];
588 	ops = cdi->major->devops;
589 
590 	if (ops == NULL) {
591 		return (-1);
592 	}
593 
594 	rc = (*ops->devo_getinfo)(NULL, DDI_INFO_DEVT2DEVINFO,
595 	    (void *)dev, (void **)&dip);
596 
597 	if (rc != DDI_SUCCESS || dip == NULL) {
598 		return (-1);
599 	}
600 
601 	if (!ddi_prop_exists(DDI_DEV_T_ANY, dip,
602 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, DDI_KERNEL_IOCTL)) {
603 		return (-1);
604 	}
605 
606 	cred = ddi_get_cred();
607 
608 	flags = FKIOCTL | FREAD | FWRITE | DATAMODEL_NATIVE;
609 
610 	dki_info = kmem_alloc(sizeof (*dki_info), KM_SLEEP);
611 
612 	/* DKIOCINFO */
613 	rc = (*cdi->major->ioctl)(dev, DKIOCINFO,
614 	    (intptr_t)dki_info, flags, cred, &rval);
615 
616 	if (rc != 0) {
617 		goto out;
618 	}
619 
620 	/* return partition number */
621 	*partitionp = (int)dki_info->dki_partition;
622 
623 	vtoc = kmem_alloc(sizeof (*vtoc), KM_SLEEP);
624 
625 	/* DKIOCGVTOC */
626 	rc = (*cdi->major->ioctl)(dev, DKIOCGVTOC,
627 	    (intptr_t)vtoc, flags, cred, &rval);
628 
629 	if (rc) {
630 		/* DKIOCGVTOC failed, but there might be an EFI label */
631 		rc = -1;
632 
633 #ifdef DKIOCPARTITION
634 		/* do we have an EFI partition table? */
635 		p64 = kmem_alloc(sizeof (*p64), KM_SLEEP);
636 		p64->p_partno = (uint_t)*partitionp;
637 
638 		/* DKIOCPARTITION */
639 		rc = (*cdi->major->ioctl)(dev, DKIOCPARTITION,
640 		    (intptr_t)p64, flags, cred, &rval);
641 
642 		if (rc == 0) {
643 			/* found EFI, return size */
644 			*bsizep = (uint64_t)p64->p_size;
645 		} else {
646 			/* both DKIOCGVTOC and DKIOCPARTITION failed - error */
647 			rc = -1;
648 		}
649 #endif
650 
651 		goto out;
652 	}
653 
654 	if ((vtoc->v_sanity != VTOC_SANE) ||
655 	    (vtoc->v_version != V_VERSION && vtoc->v_version != 0) ||
656 	    (dki_info->dki_partition > V_NUMPAR)) {
657 		rc = -1;
658 		goto out;
659 	}
660 
661 	*bsizep = (uint64_t)vtoc->v_part[(int)dki_info->dki_partition].p_size;
662 	rc = 0;
663 
664 out:
665 	if (dki_info) {
666 		kmem_free(dki_info, sizeof (*dki_info));
667 	}
668 
669 	if (vtoc) {
670 		kmem_free(vtoc, sizeof (*vtoc));
671 	}
672 
673 #ifdef DKIOCPARTITION
674 	if (p64) {
675 		kmem_free(p64, sizeof (*p64));
676 	}
677 #endif
678 
679 	return (rc);
680 }
681 
682 
683 /*
684  * Ugly, ugly, ugly.
685  *
686  * Some volume managers (Veritas) don't support layered ioctls
687  * (no FKIOCTL support, no DDI_KERNEL_IOCTL property defined) AND
688  * do not support the properties for bdev_Size()/bdev_size().
689  *
690  * If the underlying driver has specified DDI_KERNEL_IOCTL, then we use
691  * the FKIOCTL technique.  Otherwise ...
692  *
693  * The only reliable way to get the partition size, is to bounce the
694  * command through user land (nskernd).
695  *
696  * Then, SunCluster PXFS blocks access at the vnode level to device
697  * nodes during failover / switchover, so a read_vtoc() function call
698  * from user land deadlocks.  So, we end up coming back into the kernel
699  * to go directly to the underlying device driver - that's what
700  * nskern_bsize() is doing below.
701  *
702  * There has to be a better way ...
703  */
704 
705 static int
706 _raw_init_dev(dev_t fd, uint64_t *sizep, int *partitionp)
707 {
708 	struct nskernd *nsk;
709 	int rc, cd;
710 
711 	if ((cd = __raw_get_cd(fd)) == -1 || !_nsc_raw_files[cd].in_use)
712 		return (EIO);
713 
714 	/* try the in-kernel way */
715 
716 	rc = _raw_get_bsize(fd, sizep, partitionp);
717 	if (rc == 0) {
718 		return (0);
719 	}
720 
721 	/* fallback to the the slow way */
722 
723 	nsk = kmem_zalloc(sizeof (*nsk), KM_SLEEP);
724 	nsk->command = NSKERND_BSIZE;
725 	nsk->data1 = (uint64_t)0;
726 	nsk->data2 = (uint64_t)fd;
727 	(void) strncpy(nsk->char1, _nsc_raw_files[cd].path, NSC_MAXPATH);
728 
729 	rc = nskernd_get(nsk);
730 	if (rc == 0) {
731 		*partitionp = (int)nsk->data2;
732 		*sizep = nsk->data1;
733 	}
734 
735 	kmem_free(nsk, sizeof (*nsk));
736 	return (rc < 0 ? EIO : 0);
737 }
738 
739 
740 static int
741 _raw_attach_io(dev_t fd)
742 {
743 	int cd;
744 
745 	if ((cd = __raw_get_cd(fd)) == -1 || !_nsc_raw_files[cd].in_use)
746 		return (EIO);
747 
748 	return (_raw_init_dev(fd, &_nsc_raw_files[cd].size,
749 	    &_nsc_raw_files[cd].partition));
750 }
751 
752 
753 /*
754  * See the comment above _raw_init_dev().
755  */
756 
757 int
758 nskern_bsize(struct nscioc_bsize *bsize, int *rvp)
759 {
760 	struct cred *cred;
761 	raw_dev_t *cdi;
762 	int errno = 0;
763 	int flag;
764 	int cd;
765 
766 	*rvp = 0;
767 
768 	if (bsize == NULL || rvp == NULL)
769 		return (EINVAL);
770 
771 	cd = __raw_get_cd(bsize->raw_fd);
772 	if (cd == -1 || !_nsc_raw_files[cd].in_use)
773 		return (EIO);
774 
775 	cdi = &_nsc_raw_files[cd];
776 	cred = ddi_get_cred();
777 
778 	/*
779 	 * ddi_mmap_get_model() returns the model for this user thread
780 	 * which is what we want - get_udatamodel() is not public.
781 	 */
782 
783 	flag = FREAD | FWRITE | ddi_mmap_get_model();
784 
785 	if (bsize->efi == 0) {
786 		/* DKIOCINFO */
787 		errno = (*cdi->major->ioctl)(bsize->raw_fd,
788 		    DKIOCINFO, (intptr_t)bsize->dki_info, flag, cred, rvp);
789 
790 		if (errno) {
791 			return (errno);
792 		}
793 
794 		/* DKIOCGVTOC */
795 		errno = (*cdi->major->ioctl)(bsize->raw_fd,
796 		    DKIOCGVTOC, (intptr_t)bsize->vtoc, flag, cred, rvp);
797 
798 		if (errno) {
799 			return (errno);
800 		}
801 	} else {
802 #ifdef DKIOCPARTITION
803 		/* do we have an EFI partition table? */
804 		errno = (*cdi->major->ioctl)(bsize->raw_fd,
805 		    DKIOCPARTITION, (intptr_t)bsize->p64, flag, cred, rvp);
806 
807 		if (errno) {
808 			return (errno);
809 		}
810 #endif
811 	}
812 
813 	return (0);
814 }
815 
816 
817 /*
818  * Private function for sv to use.
819  */
820 int
821 nskern_partition(dev_t fd, int *partitionp)
822 {
823 	uint64_t size;
824 	int cd, rc;
825 
826 	if ((cd = __raw_get_cd(fd)) == -1 || !_nsc_raw_files[cd].in_use)
827 		return (EIO);
828 
829 	if ((*partitionp = _nsc_raw_files[cd].partition) != -1) {
830 		return (0);
831 	}
832 
833 	rc = _raw_init_dev(fd, &size, partitionp);
834 	if (rc != 0 || *partitionp < 0) {
835 		return (EIO);
836 	}
837 
838 	return (0);
839 }
840 
841 
842 nsc_def_t _nsc_raw_def[] = {
843 	"Open",		(uintptr_t)_raw_open,		0,
844 	"Close",	(uintptr_t)_raw_close,		0,
845 	"Attach",	(uintptr_t)_raw_attach_io,	0,
846 	"UserRead",	(uintptr_t)_raw_uread,		0,
847 	"UserWrite",	(uintptr_t)_raw_uwrite,		0,
848 	"PartSize",	(uintptr_t)_raw_partsize,	0,
849 	"MaxFbas",	(uintptr_t)_raw_maxfbas,	0,
850 	"Control",	(uintptr_t)_raw_control,	0,
851 	"Provide",	NSC_DEVICE,			0,
852 	0,		0,				0
853 };
854