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