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 };