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         { NULL,         (uintptr_t)NULL,                0 }
 853 };