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