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/ksynch.h>
  28 #include <sys/errno.h>
  29 #include <sys/file.h>
  30 #include <sys/open.h>
  31 #include <sys/cred.h>
  32 #include <sys/kmem.h>
  33 #include <sys/ddi.h>
  34 
  35 #include <sys/ncall/ncall.h>
  36 
  37 #define __NSC_GEN__
  38 #include "nsc_dev.h"
  39 #include "nsc_ncallio.h"
  40 #include "../nsctl.h"
  41 
  42 
  43 extern nsc_mem_t *_nsc_local_mem;
  44 
  45 extern void _nsc_init_ncio(void);
  46 extern void _nsc_deinit_ncio(void);
  47 
  48 static nsc_io_t *nsc_ncio_io;
  49 static kmutex_t nsc_ncio_lock;
  50 static nsc_ncio_dev_t *nsc_ncio_top;
  51 
  52 
  53 /*
  54  * ncall-io io provider - client side.
  55  */
  56 
  57 
  58 static int
  59 nsc_ncio_split(char *node_and_path, char **pathp)
  60 {
  61         char *cp;
  62         int i, snode;
  63 
  64         snode = 0;
  65         for (cp = node_and_path; *cp && *cp != ':'; cp++) {
  66                 i = *cp - '0';
  67                 if (i < 0 || i > 9)
  68                         break;
  69 
  70                 snode = (10 * snode) + i;
  71         }
  72 
  73         if (*cp != ':') {
  74                 cmn_err(CE_WARN,
  75                     "ncio: failed to convert %s to node and path",
  76                     node_and_path);
  77                 return (-1);
  78         }
  79 
  80         *pathp = cp + 1;
  81         return (snode);
  82 }
  83 
  84 
  85 /*
  86  * nsc_ncio_open()
  87  *
  88  * The pathname that is used with the NSC_NCALL io provider should be
  89  * of the form "<node>:<pathname>", where <node> is the decimal ncall
  90  * nodeid of the server machine and <pathname> is the pathname of the
  91  * device on the server node.
  92  */
  93 
  94 /* ARGSUSED */
  95 static int
  96 nsc_ncio_open(char *node_and_path, int flag, blind_t *cdp, void *iodev)
  97 {
  98         nsc_ncio_dev_t *ncp, *new;
  99         char *path = NULL;
 100         uint64_t phash;
 101         int snode;
 102 
 103         snode = nsc_ncio_split(node_and_path, &path);
 104         if (snode < 0)
 105                 return (EINVAL);
 106 
 107         new = nsc_kmem_zalloc(sizeof (*new), KM_SLEEP, _nsc_local_mem);
 108         phash = nsc_strhash(path);
 109 
 110         if (new) {
 111                 (void) strncpy(new->path, path, sizeof (new->path));
 112                 new->phash = phash;
 113                 new->snode = snode;
 114         }
 115 
 116         mutex_enter(&nsc_ncio_lock);
 117 
 118         for (ncp = nsc_ncio_top; ncp; ncp = ncp->next)
 119                 if (ncp->phash == phash && strcmp(path, ncp->path) == 0)
 120                         break;
 121 
 122         if (ncp == NULL && new != NULL) {
 123                 ncp = new;
 124                 new = NULL;
 125                 ncp->next = nsc_ncio_top;
 126                 nsc_ncio_top = ncp;
 127         }
 128 
 129         if (ncp != NULL)
 130                 ncp->ref++;
 131 
 132         mutex_exit(&nsc_ncio_lock);
 133 
 134         if (new)
 135                 nsc_kmem_free(new, sizeof (*new));
 136 
 137         if (!ncp)
 138                 return (ENOMEM);
 139 
 140         *cdp = (blind_t)ncp;
 141         return (0);
 142 }
 143 
 144 
 145 static int
 146 nsc_ncio_close(nsc_ncio_dev_t *ncp)
 147 {
 148         nsc_ncio_dev_t **ncpp;
 149         int found, free;
 150 
 151         if (ncp == NULL)
 152                 return (EINVAL);
 153 
 154         found = 0;
 155         free = 0;
 156 
 157         mutex_enter(&nsc_ncio_lock);
 158 
 159         for (ncpp = &nsc_ncio_top; *ncpp; ncpp = &((*ncpp)->next)) {
 160                 if (*ncpp == ncp) {
 161                         found = 1;
 162                         break;
 163                 }
 164         }
 165 
 166         if (!found) {
 167                 mutex_exit(&nsc_ncio_lock);
 168                 return (ENODEV);
 169         }
 170 
 171         ncp->ref--;
 172         if (ncp->ref == 0) {
 173                 *ncpp = ncp->next;
 174                 free = 1;
 175         }
 176 
 177         mutex_exit(&nsc_ncio_lock);
 178 
 179         if (free)
 180                 nsc_kmem_free(ncp, sizeof (*ncp));
 181 
 182         return (0);
 183 }
 184 
 185 
 186 /* ARGSUSED1 */
 187 static nsc_buf_t *
 188 nsc_ncio_alloch(void (*d_cb)(), void (*r_cb)(), void (*w_cb)())
 189 {
 190         nsc_ncio_buf_t *h;
 191 
 192         if ((h = nsc_kmem_zalloc(sizeof (*h), KM_SLEEP,
 193             _nsc_local_mem)) == NULL)
 194                 return (NULL);
 195 
 196         h->disc = d_cb;
 197         h->bufh.sb_flag = NSC_HALLOCATED;
 198 
 199         return (&h->bufh);
 200 }
 201 
 202 
 203 static int
 204 nsc_ncio_freeh(nsc_ncio_buf_t *h)
 205 {
 206         nsc_kmem_free(h, sizeof (*h));
 207         return (0);
 208 }
 209 
 210 
 211 static int
 212 nsc_ncio_rwb(nsc_ncio_buf_t *h, nsc_off_t pos, nsc_size_t len,
 213     int flag, const int rwflag)
 214 {
 215         nsc_ncio_rw_t *rw;
 216         ncall_t *ncall;
 217         int ncall_flag;
 218         int ncall_proc;
 219         int ncall_len;
 220         int rc, err;
 221 
 222         if (h->bufh.sb_flag & NSC_ABUF)
 223                 return (EIO);
 224 
 225         if (pos < h->bufh.sb_pos ||
 226             (pos + len) > (h->bufh.sb_pos + h->bufh.sb_len)) {
 227                 return (EINVAL);
 228         }
 229 
 230         if (!len)
 231                 return (0);
 232 
 233         if (rwflag == NSC_READ && (flag & NSC_RDAHEAD))
 234                 return (0);
 235 
 236         /* CONSTCOND */
 237         if (sizeof (*rw) > NCALL_DATA_SZ) {
 238                 /* CONSTCOND */
 239                 ASSERT(sizeof (*rw) <= NCALL_DATA_SZ);
 240                 return (ENXIO);
 241         }
 242 
 243         if (rwflag == NSC_READ) {
 244                 ncall_flag = NCALL_RDATA;
 245                 ncall_proc = NSC_NCIO_READ;
 246                 ncall_len = sizeof (*rw) - sizeof (rw->rw_data);
 247         } else {
 248                 ncall_flag = 0;
 249                 ncall_proc = NSC_NCIO_WRITE;
 250                 ncall_len = sizeof (*rw);
 251         }
 252 
 253         rw = &h->rw;
 254 
 255         if (rwflag == 0) {
 256                 /* zero */
 257                 bzero(rw->rw_data, sizeof (rw->rw_data));
 258         }
 259 
 260         if (h->disc)
 261                 (*h->disc)(h);
 262 
 263         rc = ncall_alloc(rw->rw_snode, 0, 0, &ncall);
 264         if (rc != 0) {
 265                 return (rc);
 266         }
 267 
 268         rw->rw_pos = (uint64_t)pos;
 269         rw->rw_len = (uint64_t)len;
 270         rc = ncall_put_data(ncall, rw, ncall_len);
 271         if (rc != 0) {
 272                 return (rc);
 273         }
 274 
 275         rc = ncall_send(ncall, ncall_flag, ncall_proc);
 276         if (rc != 0) {
 277                 return (rc);
 278         }
 279 
 280         rc = ncall_read_reply(ncall, 1, &err);
 281         if (rc != 0 || err != 0) {
 282                 return (rc ? rc : err);
 283         }
 284 
 285         if (rwflag == NSC_READ) {
 286                 rc = ncall_get_data(ncall, rw, sizeof (*rw));
 287                 if (rc != 0) {
 288                         return (rc);
 289                 }
 290         }
 291 
 292         ncall_free(ncall);
 293         return (0);
 294 }
 295 
 296 
 297 static int
 298 nsc_ncio_read(nsc_ncio_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
 299 {
 300         return (nsc_ncio_rwb(h, pos, len, flag, NSC_READ));
 301 }
 302 
 303 
 304 static int
 305 nsc_ncio_write(nsc_ncio_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
 306 {
 307         return (nsc_ncio_rwb(h, pos, len, flag, NSC_WRITE));
 308 }
 309 
 310 
 311 static int
 312 nsc_ncio_zero(nsc_ncio_buf_t *h, nsc_off_t pos, nsc_size_t len, int flag)
 313 {
 314         return (nsc_ncio_rwb(h, pos, len, flag, 0));
 315 }
 316 
 317 
 318 static void
 319 nsc_wait_ncio(nsc_ncio_buf_t *h)
 320 {
 321         nsc_iodev_t *iodev = h->bufh.sb_fd->sf_iodev;
 322         void (*fn)() = h->disc;
 323         nsc_ncio_buf_t *hp;
 324 
 325         mutex_enter(&iodev->si_lock);
 326 
 327         h->next = iodev->si_active;
 328         iodev->si_active = h;
 329 
 330         /* CONSTCOND */
 331 
 332         while (1) {
 333                 for (hp = h->next; hp; hp = hp->next) {
 334                         if ((h->bufh.sb_pos + h->bufh.sb_len) >
 335                             hp->bufh.sb_pos &&
 336                             h->bufh.sb_pos <
 337                             (hp->bufh.sb_pos + hp->bufh.sb_len)) {
 338                                 /* found overlapping io in progress */
 339                                 break;
 340                         }
 341                 }
 342 
 343                 if (!hp)
 344                         break;
 345 
 346                 if (fn) {
 347                         (*fn)(h);
 348                         fn = NULL;
 349                 }
 350 
 351                 cv_wait(&iodev->si_cv, &iodev->si_lock);
 352         }
 353 
 354         mutex_exit(&iodev->si_lock);
 355 }
 356 
 357 
 358 static int
 359 nsc_ncio_freeb(nsc_ncio_buf_t *h)
 360 {
 361         nsc_ncio_buf_t **hpp, *hp;
 362         nsc_iodev_t *iodev;
 363         int wake = 0;
 364 
 365         if ((h->bufh.sb_flag & NSC_HACTIVE) &&
 366             h->bufh.sb_fd && !(h->bufh.sb_flag & NSC_ABUF)) {
 367                 iodev = h->bufh.sb_fd->sf_iodev;
 368 
 369                 mutex_enter(&iodev->si_lock);
 370 
 371                 for (hpp = (nsc_ncio_buf_t **)&iodev->si_active;
 372                     *hpp; hpp = &hp->next) {
 373                         if ((hp = *hpp) == h) {
 374                                 *hpp = h->next;
 375                                 break;
 376                         }
 377 
 378                         if ((h->bufh.sb_pos + h->bufh.sb_len) >
 379                             hp->bufh.sb_pos &&
 380                             h->bufh.sb_pos <
 381                             (hp->bufh.sb_pos + hp->bufh.sb_len)) {
 382                                 wake = 1;
 383                         }
 384                 }
 385 
 386                 if (wake)
 387                         cv_broadcast(&iodev->si_cv);
 388 
 389                 mutex_exit(&iodev->si_lock);
 390         }
 391 
 392         /* clear flags, preserve NSC_HALLOCATED */
 393         h->bufh.sb_flag &= NSC_HALLOCATED;
 394 
 395         if ((h->bufh.sb_flag & NSC_HALLOCATED) == 0)
 396                 (void) nsc_ncio_freeh(h);
 397 
 398         return (0);
 399 }
 400 
 401 
 402 static int
 403 nsc_ncio_allocb(nsc_ncio_dev_t *ncp, nsc_off_t pos, nsc_size_t len,
 404     int flag, nsc_ncio_buf_t **hp)
 405 {
 406         nsc_ncio_buf_t *h = *hp;
 407         int rc;
 408 
 409         if (h == NULL) {
 410                 cmn_err(CE_WARN, "nsc_ncio_allocb: NULL handle!");
 411                 return (EIO);
 412         }
 413 
 414         if (FBA_SIZE(len) > NSC_NCIO_MAXDATA) {
 415                 /* too large */
 416                 return (ENXIO);
 417         }
 418 
 419         if ((blind_t)ncp == NSC_ANON_CD) {
 420                 flag &= ~(NSC_READ | NSC_WRITE | NSC_RDAHEAD);
 421         }
 422 
 423         if (h->disc)
 424                 (*h->disc)(h);
 425 
 426         h->bufh.sb_pos = pos;
 427         h->bufh.sb_len = len;
 428         h->bufh.sb_error = 0;
 429         h->bufh.sb_flag |= flag | NSC_HACTIVE;
 430         h->bufh.sb_vec = &h->vec[0];
 431 
 432         if (!((blind_t)ncp == NSC_ANON_CD)) {
 433                 (void) strncpy(h->rw.rw_path, ncp->path,
 434                     sizeof (h->rw.rw_path));
 435                 h->rw.rw_snode = ncp->snode;
 436         }
 437 
 438         h->vec[0].sv_len = FBA_SIZE(len);
 439         h->vec[0].sv_addr = (uchar_t *)&h->rw.rw_data[0];
 440         h->vec[0].sv_vme = 0;
 441 
 442         h->vec[1].sv_len = 0;
 443         h->vec[1].sv_addr = 0;
 444         h->vec[1].sv_vme = 0;
 445 
 446         if ((flag & NSC_RDAHEAD) || ((blind_t)ncp == NSC_ANON_CD))
 447                 return (NSC_DONE);
 448 
 449         nsc_wait_ncio(h);
 450 
 451         if (flag & NSC_READ) {
 452                 if ((rc = nsc_ncio_read(h, pos, len, flag)) != 0) {
 453                         (void) nsc_ncio_freeb(h);
 454                         return (rc);
 455                 }
 456         }
 457 
 458         return (NSC_DONE);
 459 }
 460 
 461 
 462 static int
 463 nsc_ncio_partsize(nsc_ncio_dev_t *ncp, nsc_size_t *rvalp)
 464 {
 465         *rvalp = (nsc_size_t)ncp->partsize;
 466         return (0);
 467 }
 468 
 469 
 470 /* ARGSUSED */
 471 static int
 472 nsc_ncio_maxfbas(nsc_ncio_dev_t *ncp, int flag, nsc_size_t *ptr)
 473 {
 474         if (flag == NSC_CACHEBLK)
 475                 *ptr = 1;
 476         else
 477                 *ptr = FBA_NUM(NSC_NCIO_MAXDATA);
 478 
 479         return (0);
 480 }
 481 
 482 
 483 static int
 484 nsc_ncio_attach(nsc_ncio_dev_t *ncp)
 485 {
 486         nsc_ncio_size_t *size;
 487         ncall_t *ncall;
 488         int sizeh, sizel;
 489         int rc, err;
 490 
 491         /* CONSTCOND */
 492         if (sizeof (*size) > NCALL_DATA_SZ) {
 493                 /* CONSTCOND */
 494                 ASSERT(sizeof (*size) <= NCALL_DATA_SZ);
 495                 return (ENXIO);
 496         }
 497 
 498         size = kmem_zalloc(sizeof (*size), KM_SLEEP);
 499         (void) strncpy(size->path, ncp->path, sizeof (size->path));
 500 
 501         rc = ncall_alloc(ncp->snode, 0, 0, &ncall);
 502         if (rc != 0) {
 503                 kmem_free(size, sizeof (*size));
 504                 return (rc);
 505         }
 506 
 507         rc = ncall_put_data(ncall, size, sizeof (*size));
 508         kmem_free(size, sizeof (*size));
 509         size = NULL;
 510         if (rc != 0)
 511                 return (rc);
 512 
 513         rc = ncall_send(ncall, 0, NSC_NCIO_PARTSIZE);
 514         if (rc != 0)
 515                 return (0);
 516 
 517         rc = ncall_read_reply(ncall, 3, &err, &sizeh, &sizel);
 518         if (rc != 0 || err != 0)
 519                 return (rc ? rc : err);
 520 
 521         ncall_free(ncall);
 522 
 523         ncp->partsize = (uint64_t)(((uint64_t)sizeh << 32) | (uint64_t)sizel);
 524         return (0);
 525 }
 526 
 527 
 528 static nsc_def_t nsc_ncio_def[] = {
 529         { "Open",       (uintptr_t)nsc_ncio_open,       0 },
 530         { "Close",      (uintptr_t)nsc_ncio_close,      0 },
 531         { "Attach",     (uintptr_t)nsc_ncio_attach,     0 },
 532         { "AllocHandle", (uintptr_t)nsc_ncio_alloch,    0 },
 533         { "FreeHandle", (uintptr_t)nsc_ncio_freeh,      0 },
 534         { "AllocBuf",   (uintptr_t)nsc_ncio_allocb,     0 },
 535         { "FreeBuf",    (uintptr_t)nsc_ncio_freeb,      0 },
 536         { "Read",       (uintptr_t)nsc_ncio_read,       0 },
 537         { "Write",      (uintptr_t)nsc_ncio_write,      0 },
 538         { "Zero",       (uintptr_t)nsc_ncio_zero,       0 },
 539         { "PartSize",   (uintptr_t)nsc_ncio_partsize,   0 },
 540         { "MaxFbas",    (uintptr_t)nsc_ncio_maxfbas,    0 },
 541         { "Provide",    NSC_NCALL,                      0 },
 542         { 0,            0,                              0 }
 543 };
 544 
 545 
 546 /*
 547  * ncall-io io provider - server side.
 548  */
 549 
 550 /* ARGSUSED1 */
 551 static void
 552 nsc_rncio_partsize(ncall_t *ncall, int *ap)
 553 {
 554         nsc_ncio_size_t *size;
 555         nsc_size_t partsize;
 556         int sizeh, sizel;
 557         nsc_fd_t *fd;
 558         int rc;
 559 
 560         size = kmem_alloc(sizeof (*size), KM_SLEEP);
 561         rc = ncall_get_data(ncall, size, sizeof (*size));
 562         if (rc != 0) {
 563                 ncall_reply(ncall, EFAULT, 0, 0);
 564                 kmem_free(size, sizeof (*size));
 565                 return;
 566         }
 567 
 568         fd = nsc_open(size->path, NSC_CACHE | NSC_DEVICE | NSC_READ,
 569             NULL, NULL, &rc);
 570         kmem_free(size, sizeof (*size));
 571         size = NULL;
 572         if (fd == NULL) {
 573                 ncall_reply(ncall, rc, 0, 0);
 574                 return;
 575         }
 576 
 577         rc = nsc_reserve(fd, NSC_PCATCH);
 578         if (rc != 0) {
 579                 (void) nsc_close(fd);
 580                 ncall_reply(ncall, rc, 0, 0);
 581                 return;
 582         }
 583 
 584         sizeh = sizel = 0;
 585         rc = nsc_partsize(fd, &partsize);
 586         sizel = (int)(partsize & 0xffffffff);
 587         /* CONSTCOND */
 588         if (sizeof (nsc_size_t) > sizeof (int)) {
 589                 sizeh = (int)((partsize & 0xffffffff00000000) >> 32);
 590         }
 591 
 592         nsc_release(fd);
 593         (void) nsc_close(fd);
 594 
 595         ncall_reply(ncall, rc, sizeh, sizel);
 596 }
 597 
 598 
 599 static int
 600 nsc_rncio_copy(char *data, nsc_buf_t *bufp, const int read)
 601 {
 602         nsc_vec_t *vec;
 603         char *datap;
 604         uint64_t tocopy;        /* bytes */
 605         int thischunk;          /* bytes */
 606         int rc;
 607 
 608         rc = 0;
 609         datap = data;
 610         vec = bufp->sb_vec;
 611 
 612         tocopy = FBA_SIZE(bufp->sb_len);
 613 
 614         while (tocopy > 0) {
 615                 if (vec->sv_len == 0 || vec->sv_addr == 0) {
 616                         rc = ENOSPC;
 617                         break;
 618                 }
 619 
 620                 thischunk = (int)min((nsc_size_t)vec->sv_len, tocopy);
 621 
 622                 if (read) {
 623                         bcopy(vec->sv_addr, datap, thischunk);
 624                 } else {
 625                         bcopy(datap, vec->sv_addr, thischunk);
 626                 }
 627 
 628                 tocopy -= thischunk;
 629                 if (thischunk == vec->sv_len)
 630                         vec++;
 631         }
 632 
 633         return (rc);
 634 }
 635 
 636 
 637 /* ARGSUSED */
 638 static void
 639 nsc_rncio_io(ncall_t *ncall, int *ap, const int read)
 640 {
 641         nsc_ncio_rw_t *rw;
 642         nsc_buf_t *bufp;
 643         nsc_fd_t *fd;
 644         nsc_size_t len;
 645         nsc_off_t pos;
 646         int ioflag;
 647         int rc;
 648 
 649         rw = kmem_alloc(sizeof (*rw), KM_SLEEP);
 650         rc = ncall_get_data(ncall, rw, sizeof (*rw));
 651         if (rc != 0) {
 652                 ncall_reply(ncall, EFAULT);
 653                 kmem_free(rw, sizeof (*rw));
 654                 return;
 655         }
 656 
 657         ioflag = (read ? NSC_READ : NSC_WRITE);
 658         pos = (nsc_off_t)rw->rw_pos;
 659         len = (nsc_size_t)rw->rw_len;
 660 
 661         fd = nsc_open(rw->rw_path, NSC_CACHE | NSC_DEVICE | NSC_READ | ioflag,
 662             NULL, NULL, &rc);
 663         if (fd == NULL) {
 664                 ncall_reply(ncall, rc);
 665                 kmem_free(rw, sizeof (*rw));
 666                 return;
 667         }
 668 
 669         rc = nsc_reserve(fd, NSC_PCATCH);
 670         if (rc != 0) {
 671                 ncall_reply(ncall, rc);
 672                 (void) nsc_close(fd);
 673                 kmem_free(rw, sizeof (*rw));
 674                 return;
 675         }
 676 
 677         bufp = NULL;
 678         rc = nsc_alloc_buf(fd, pos, len, NSC_NOCACHE | ioflag, &bufp);
 679         if (rc > 0) {
 680                 ncall_reply(ncall, rc);
 681                 if (bufp != NULL) {
 682                         (void) nsc_free_buf(bufp);
 683                 }
 684                 nsc_release(fd);
 685                 (void) nsc_close(fd);
 686                 kmem_free(rw, sizeof (*rw));
 687                 return;
 688         }
 689 
 690         rc = nsc_rncio_copy(&rw->rw_data[0], bufp, read);
 691         if (rc == 0) {
 692                 if (read) {
 693                         /* store reply data */
 694                         rc = ncall_put_data(ncall, rw, sizeof (*rw));
 695                 } else {
 696                         /* write new data */
 697                         rc = nsc_write(bufp, pos, len, 0);
 698                 }
 699         }
 700 
 701         ncall_reply(ncall, rc);
 702 
 703         (void) nsc_free_buf(bufp);
 704         nsc_release(fd);
 705         (void) nsc_close(fd);
 706         kmem_free(rw, sizeof (*rw));
 707 }
 708 
 709 
 710 static void
 711 nsc_rncio_read(ncall_t *ncall, int *ap)
 712 {
 713         nsc_rncio_io(ncall, ap, TRUE);
 714 }
 715 
 716 
 717 static void
 718 nsc_rncio_write(ncall_t *ncall, int *ap)
 719 {
 720         nsc_rncio_io(ncall, ap, FALSE);
 721 }
 722 
 723 
 724 /*
 725  * ncall-io io provider - setup.
 726  */
 727 
 728 void
 729 _nsc_init_ncio(void)
 730 {
 731         mutex_init(&nsc_ncio_lock, NULL, MUTEX_DRIVER, NULL);
 732 
 733         ncall_register_svc(NSC_NCIO_PARTSIZE, nsc_rncio_partsize);
 734         ncall_register_svc(NSC_NCIO_WRITE, nsc_rncio_write);
 735         ncall_register_svc(NSC_NCIO_READ, nsc_rncio_read);
 736 
 737         nsc_ncio_io = nsc_register_io("ncall-io",
 738             NSC_NCALL_ID | NSC_REFCNT, nsc_ncio_def);
 739 
 740         if (!nsc_ncio_io)
 741                 cmn_err(CE_WARN, "_nsc_ncio_init: register io failed - ncall");
 742 }
 743 
 744 
 745 void
 746 _nsc_deinit_ncio(void)
 747 {
 748         if (nsc_ncio_io)
 749                 (void) nsc_unregister_io(nsc_ncio_io, 0);
 750 
 751         ncall_unregister_svc(NSC_NCIO_PARTSIZE);
 752         ncall_unregister_svc(NSC_NCIO_WRITE);
 753         ncall_unregister_svc(NSC_NCIO_READ);
 754 
 755         nsc_ncio_io = NULL;
 756         mutex_destroy(&nsc_ncio_lock);
 757 }