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/kmem.h>
  29 #include <sys/cmn_err.h>
  30 #include <sys/errno.h>
  31 #include <sys/ddi.h>
  32 
  33 #define __NSC_GEN__
  34 #include <sys/ncall/ncall.h>
  35 #include "nsc_dev.h"
  36 #include "../nsctl.h"
  37 #ifdef DS_DDICT
  38 #include "../contract.h"
  39 #endif
  40 
  41 
  42 static int _nsc_attach_fd(nsc_fd_t *, int);
  43 static int _nsc_detach_owner(nsc_fd_t *, int);
  44 static int _nsc_fd_fn(nsc_fd_t *, int (*)(), int, int);
  45 static int _nsc_attach_iodev(nsc_iodev_t *, int);
  46 static int _nsc_attach_dev(nsc_dev_t *, int);
  47 static int _nsc_call_dev(nsc_dev_t *, blindfn_t, blind_t,
  48     int *, int *, int, int, nsc_iodev_t *);
  49 
  50 
  51 /*
  52  * void
  53  * _nsc_init_resv (void)
  54  *      Initialise reserve mechanism.
  55  *
  56  * Calling/Exit State:
  57  *      Called at initialisation time to allocate necessary
  58  *      data structures.
  59  */
  60 void
  61 _nsc_init_resv()
  62 {
  63 }
  64 
  65 
  66 /*
  67  * void
  68  * _nsc_deinit_resv (void)
  69  *      De-initialise reserve mechanism.
  70  *
  71  * Calling/Exit State:
  72  *      Called at unload time to de-allocate resources.
  73  */
  74 void
  75 _nsc_deinit_resv()
  76 {
  77 }
  78 
  79 
  80 /*
  81  * int
  82  * nsc_attach (nsc_fd_t *fd, int flag)
  83  *      Force attach of file descriptor.
  84  *
  85  * Calling/Exit State:
  86  *      Returns 0 if the attach succeeds, otherwise
  87  *      returns an error code.
  88  *
  89  * Description:
  90  *      Tries to attach the file descriptor by reserving
  91  *      and then releasing it. This is intended purely as
  92  *      a performance aid since there is no guarantee that
  93  *      the file descriptor will remain attached upon
  94  *      return.
  95  */
  96 int
  97 nsc_attach(fd, flag)
  98 nsc_fd_t *fd;
  99 int flag;
 100 {
 101         int rc;
 102 
 103         rc = nsc_reserve(fd, flag);
 104 
 105         if (rc == 0)
 106                 nsc_release(fd);
 107 
 108         return (rc);
 109 }
 110 
 111 
 112 /*
 113  * int
 114  * nsc_reserve (nsc_fd_t *fd, int flag)
 115  *      Reserve file descriptor.
 116  *
 117  * Calling/Exit State:
 118  *      Returns 0 if the reserve succeeds, otherwise
 119  *      returns an error code.
 120  *
 121  * Description:
 122  *      Reserves the file descriptor for either NSC_READ or
 123  *      NSC_WRITE access. If neither is specified the mode
 124  *      with which the file was opened will be used. Trying
 125  *      to reserve a read only file in write mode will cause
 126  *      EACCES to be returned.
 127  *
 128  *      If NSC_NOBLOCK is specifed and the reserve cannot be
 129  *      completed immediately, EAGAIN will be returned.
 130  *
 131  *      If NSC_NOWAIT is set and the device is busy, EAGAIN
 132  *      will be returned.
 133  *
 134  *      If NSC_TRY is set and the device is already reserved
 135  *      EAGAIN will be returned.
 136  *
 137  *      If NSC_PCATCH is specified and a signal is received,
 138  *      the reserve will be terminated and EINTR returned.
 139  *
 140  *      If NSC_MULTI is set then multiple reserves of the
 141  *      same type are permitted for the file descriptor.
 142  */
 143 int
 144 nsc_reserve(fd, flag)
 145 nsc_fd_t *fd;
 146 int flag;
 147 {
 148         nsc_dev_t *dev = fd->sf_dev;
 149         int rc, rw;
 150 
 151         if ((flag & NSC_READ) == 0)
 152                 flag |= (fd->sf_flag & NSC_RDWR);
 153 
 154         rw = (flag & NSC_RDWR);
 155         if ((fd->sf_flag & rw) != rw)
 156                 return (EACCES);
 157 
 158         mutex_enter(&dev->nsc_lock);
 159 
 160         while ((rc = _nsc_attach_fd(fd, flag)) != 0)
 161                 if (rc != ERESTART)
 162                         break;
 163 
 164         if (!rc && !fd->sf_reserve++) {
 165                 fd->sf_aio = fd->sf_iodev->si_io;
 166                 fd->sf_mode = (flag & NSC_MULTI);
 167         }
 168 
 169         mutex_exit(&dev->nsc_lock);
 170         return (rc);
 171 }
 172 
 173 
 174 /*
 175  * int
 176  * nsc_reserve_lk (nsc_fd_t *fd)
 177  *      Reserve locked file descriptor.
 178  *
 179  * Calling/Exit State:
 180  *      The device lock must be held across calls to
 181  *      this function.
 182  *
 183  *      Must be preceeded by a successful call to nsc_avail.
 184  *
 185  * Description:
 186  *      Reserves the file descriptor using the mode specified
 187  *      when the file was opened. This is only intended for
 188  *      use in performance critical situations.
 189  */
 190 void
 191 nsc_reserve_lk(fd)
 192 nsc_fd_t *fd;
 193 {
 194         fd->sf_reserve = 1;
 195         fd->sf_aio = fd->sf_iodev->si_io;
 196 }
 197 
 198 
 199 /*
 200  * int
 201  * nsc_avail (nsc_fd_t *fd)
 202  *      Test if file descriptor is available.
 203  *
 204  * Calling/Exit State:
 205  *      The device lock must be held across calls to
 206  *      this function.
 207  *
 208  *      Returns true if the file descriptor is available to
 209  *      be reserved using the mode specified when the file
 210  *      was opened.
 211  *
 212  * Description:
 213  *      This is only intended for use in performance critical
 214  *      situations in conjunction with nsc_reserve_lk.
 215  */
 216 int
 217 nsc_avail(fd)
 218 nsc_fd_t *fd;
 219 {
 220         int rw;
 221 
 222         if (!fd || fd->sf_pend || fd->sf_reserve || fd->sf_reopen)
 223                 return (0);
 224 
 225         if ((fd->sf_avail & _NSC_ATTACH) == 0)
 226                 return (0);
 227         if ((fd->sf_avail & _NSC_PINNED) == 0)
 228                 return (0);
 229 
 230         rw = (fd->sf_flag & NSC_RDWR);
 231 
 232         return ((fd->sf_avail & rw) == rw);
 233 }
 234 
 235 
 236 /*
 237  * int
 238  * nsc_held (nsc_fd_t *fd)
 239  *      Test if file descriptor is reserved.
 240  *
 241  * Calling/Exit State:
 242  *      Returns true if the file descriptor is currently
 243  *      reserved.
 244  */
 245 int
 246 nsc_held(fd)
 247 nsc_fd_t *fd;
 248 {
 249         return ((fd) ? fd->sf_reserve : 1);
 250 }
 251 
 252 
 253 /*
 254  * int
 255  * nsc_waiting (nsc_fd_t *fd)
 256  *      Test if another client is waiting for this device.
 257  *
 258  * Calling/Exit State:
 259  *      Must be called with the file descriptor reserved.
 260  *      Returns true if another thread is waiting to reserve this device.
 261  *
 262  * Description:
 263  *      This is only intended for use in performance critical
 264  *      situations and inherently returns historical information.
 265  */
 266 int
 267 nsc_waiting(nsc_fd_t *fd)
 268 {
 269         nsc_dev_t *dev;
 270 
 271         if (!fd || !nsc_held(fd))
 272                 return (FALSE);
 273 
 274         dev = fd->sf_dev;
 275 
 276         return (dev->nsc_wait || dev->nsc_refcnt <= 0);
 277 }
 278 
 279 
 280 /*
 281  * int
 282  * nsc_release_lk (nsc_fd_t *fd)
 283  *      Release locked file descriptor.
 284  *
 285  * Calling/Exit State:
 286  *      The device lock must be held across calls to
 287  *      this function.
 288  *
 289  *      Returns true if another node is waiting for the
 290  *      device and a call to nsc_detach should be made.
 291  *
 292  * Description:
 293  *      Releases the file descriptor. This is only intended
 294  *      for use in performance critical situations in
 295  *      conjunction with nsc_reserve_lk.
 296  */
 297 int
 298 nsc_release_lk(fd)
 299 nsc_fd_t *fd;
 300 {
 301         nsc_dev_t *dev = fd->sf_dev;
 302 
 303         fd->sf_reserve = 0;
 304         fd->sf_aio = _nsc_null_io;
 305 
 306         if (dev->nsc_wait || dev->nsc_refcnt <= 0)
 307                 cv_broadcast(&dev->nsc_cv);
 308 
 309         return (dev->nsc_drop > 0);
 310 }
 311 
 312 
 313 /*
 314  * int
 315  * nsc_release (nsc_fd_t *fd)
 316  *      Release file descriptor.
 317  *
 318  * Description:
 319  *      Releases the file descriptor. If another node
 320  *      is waiting for the device it will be completely
 321  *      detached before returning.
 322  */
 323 void
 324 nsc_release(fd)
 325 nsc_fd_t *fd;
 326 {
 327         nsc_dev_t *dev = fd->sf_dev;
 328         int rc;
 329 
 330         mutex_enter(&dev->nsc_lock);
 331 
 332         if (!fd->sf_reserve || --fd->sf_reserve) {
 333                 mutex_exit(&dev->nsc_lock);
 334                 return;
 335         }
 336 
 337         fd->sf_aio = _nsc_null_io;
 338         fd->sf_mode = 0;
 339 
 340         if (dev->nsc_wait || dev->nsc_refcnt <= 0)
 341                 cv_broadcast(&dev->nsc_cv);
 342 
 343         while (dev->nsc_drop > 0) {
 344                 rc = _nsc_detach_dev(dev, NULL, NSC_RDWR);
 345                 if (!rc || rc != ERESTART)
 346                         break;
 347         }
 348 
 349         mutex_exit(&dev->nsc_lock);
 350 }
 351 
 352 
 353 /*
 354  * int
 355  * nsc_detach (nsc_fd_t *fd, int flag)
 356  *      Detach device from node.
 357  *
 358  * Calling/Exit State:
 359  *      Returns 0 if the reserve succeeds, otherwise
 360  *      returns an error code.
 361  *
 362  * Description:
 363  *      Detaches the device from the current node. If flag
 364  *      specifies read access then flush is called in preference
 365  *      to detach.
 366  *
 367  *      If NSC_NOBLOCK is specifed and the detach cannot be
 368  *      completed immediately, EAGAIN will be returned.
 369  *
 370  *      If NSC_TRY is set and the device is reserved, EAGAIN
 371  *      will be returned.
 372  *
 373  *      If NSC_NOWAIT is set and the device is busy, EAGAIN
 374  *      will be returned.
 375  *
 376  *      If NSC_PCATCH is specified and a signal is received,
 377  *      the reserve will be terminated and EINTR returned.
 378  *
 379  *      If NSC_DEFER is set and the device is reserved, then
 380  *      the detach will be done on release.
 381  */
 382 int
 383 nsc_detach(fd, flag)
 384 nsc_fd_t *fd;
 385 int flag;
 386 {
 387         nsc_dev_t *dev;
 388         int rc;
 389 
 390         if (!fd)
 391                 return (0);
 392 
 393         dev = fd->sf_dev;
 394 
 395         if (flag & NSC_DEFER)
 396                 flag |= NSC_TRY;
 397         if ((flag & NSC_READ) == 0)
 398                 flag |= NSC_RDWR;
 399 
 400         mutex_enter(&dev->nsc_lock);
 401 
 402         while ((rc = _nsc_detach_dev(dev, NULL, flag)) != 0)
 403                 if (rc != ERESTART)
 404                         break;
 405 
 406         if (rc == EAGAIN && (flag & NSC_DEFER))
 407                 dev->nsc_drop = 1;
 408 
 409         mutex_exit(&dev->nsc_lock);
 410         return (rc);
 411 }
 412 
 413 
 414 /*
 415  * static int
 416  * _nsc_attach_fd (nsc_fd_t *fd, int flag)
 417  *      Attach file descriptor.
 418  *
 419  * Calling/Exit State:
 420  *      The device lock must be held across calls to
 421  *      this function.
 422  *
 423  *      Returns 0 if the attach succeeds without releasing
 424  *      the device lock, otherwise returns an error code.
 425  *
 426  * Description:
 427  *      Attach the specified file descriptor. Other file
 428  *      descriptors for the same I/O device will be flushed
 429  *      or detached first as necessary.
 430  */
 431 static int
 432 _nsc_attach_fd(fd, flag)
 433 nsc_fd_t *fd;
 434 int flag;
 435 {
 436         nsc_dev_t *dev = fd->sf_dev;
 437         int rw = (flag & NSC_RDWR);
 438         nsc_iodev_t *iodev;
 439         int rc, av;
 440 
 441         if (fd->sf_pend)
 442                 return (_nsc_wait_dev(dev, flag));
 443 
 444         if (fd->sf_reopen)
 445                 if ((rc = _nsc_close_fd(fd, flag)) != 0)
 446                         return (rc);
 447 
 448         if (!fd->sf_iodev)
 449                 if ((rc = _nsc_open_fd(fd, flag)) != 0)
 450                         return (rc);
 451 
 452         iodev = fd->sf_iodev;
 453 
 454         if ((flag & fd->sf_mode & NSC_MULTI) && fd->sf_reserve)
 455                 if ((fd->sf_avail & rw) == rw && !iodev->si_rpend)
 456                         if (dev->nsc_drop == 0)
 457                                 return (0);
 458 
 459         if (fd->sf_reserve) {
 460                 if (flag & NSC_TRY)
 461                         return (EAGAIN);
 462                 return (_nsc_wait_dev(dev, flag));
 463         }
 464 
 465         if (fd->sf_avail & _NSC_ATTACH)
 466                 if (fd->sf_avail & _NSC_PINNED)
 467                         if ((fd->sf_avail & rw) == rw)
 468                                 return (0);
 469 
 470         if (iodev->si_rpend && !fd->sf_avail)
 471                 return (_nsc_wait_dev(dev, flag));
 472 
 473         if ((rc = _nsc_detach_iodev(iodev, fd, flag)) != 0 ||
 474             (rc = _nsc_attach_iodev(iodev, flag)) != 0)
 475                 return (rc);
 476 
 477         if (!fd->sf_avail) {
 478                 fd->sf_avail = rw;
 479                 return (_nsc_fd_fn(fd, fd->sf_attach, _NSC_ATTACH, flag));
 480         }
 481 
 482         if ((fd->sf_avail & _NSC_PINNED) == 0) {
 483                 av = (fd->sf_avail | _NSC_PINNED);
 484 
 485                 return _nsc_call_dev(dev, iodev->si_io->getpin,
 486                         fd->sf_cd, &fd->sf_avail, &fd->sf_pend, av, flag, NULL);
 487         }
 488 
 489         fd->sf_avail |= rw;
 490         return (0);
 491 }
 492 
 493 
 494 /*
 495  * int
 496  * _nsc_detach_fd (nsc_fd_t *fd, int flag)
 497  *      Detach file descriptor.
 498  *
 499  * Calling/Exit State:
 500  *      The device lock must be held across calls to
 501  *      this function.
 502  *
 503  *      Returns 0 if the detach succeeds without releasing
 504  *      the device lock, otherwise returns an error code.
 505  *
 506  * Description:
 507  *      Detach the specified file descriptor. If flag
 508  *      specifies read access then flush is called in
 509  *      preference to detach.
 510  */
 511 int
 512 _nsc_detach_fd(fd, flag)
 513 nsc_fd_t *fd;
 514 int flag;
 515 {
 516         nsc_dev_t *dev = fd->sf_dev;
 517         int rc;
 518 
 519         if (fd->sf_pend == _NSC_CLOSE)
 520                 return (0);
 521 
 522         if (fd->sf_pend)
 523                 return (_nsc_wait_dev(dev, flag));
 524 
 525         if (fd->sf_flush == nsc_null)
 526                 flag |= NSC_RDWR;
 527 
 528         if ((fd->sf_avail & NSC_RDWR) == 0)
 529                 if (!fd->sf_avail || !(flag & NSC_WRITE))
 530                         return (0);
 531 
 532         if (fd->sf_reserve && fd->sf_owner)
 533                 if ((rc = _nsc_detach_owner(fd, flag)) != 0)
 534                         return (rc);
 535 
 536         if (fd->sf_reserve) {
 537                 if (flag & NSC_TRY)
 538                         return (EAGAIN);
 539                 return (_nsc_wait_dev(dev, flag));
 540         }
 541 
 542         if (flag & NSC_WRITE) {
 543                 if (fd->sf_iodev->si_busy)
 544                         return (_nsc_wait_dev(dev, flag));
 545 
 546                 return (_nsc_fd_fn(fd, fd->sf_detach, 0, flag));
 547         }
 548 
 549         return (_nsc_fd_fn(fd, fd->sf_flush, (fd->sf_avail & ~NSC_RDWR), flag));
 550 }
 551 
 552 
 553 /*
 554  * static int
 555  * _nsc_detach_owner (nsc_fd_t *fd, int flag)
 556  *      Detach owner of file descriptor.
 557  *
 558  * Calling/Exit State:
 559  *      The device lock must be held across calls to
 560  *      this function.
 561  *
 562  *      Returns 0 if the detach succeeds without releasing
 563  *      the device lock, otherwise returns an error code.
 564  *
 565  * Description:
 566  *      Detach the owner of the specified file descriptor.
 567  *      Wherever possible this is done without releasing
 568  *      the current device lock.
 569  */
 570 static int
 571 _nsc_detach_owner(fd, flag)
 572 nsc_fd_t *fd;
 573 int flag;
 574 {
 575         nsc_dev_t *newdev = fd->sf_owner->si_dev;
 576         nsc_dev_t *dev = fd->sf_dev;
 577         int try;
 578         int rc;
 579 
 580         if (newdev == dev) {
 581                 if ((rc = _nsc_detach_iodev(fd->sf_owner, NULL, flag)) == 0)
 582                         fd->sf_owner = NULL;
 583                 return (rc);
 584         }
 585 
 586         if ((try = mutex_tryenter(&newdev->nsc_lock)) != 0)
 587                 if (!_nsc_detach_iodev(fd->sf_owner, NULL,
 588                                         (flag | NSC_NOBLOCK))) {
 589                         mutex_exit(&newdev->nsc_lock);
 590                         return (0);
 591                 }
 592 
 593         if (flag & NSC_NOBLOCK) {
 594                 if (try != 0)
 595                         mutex_exit(&newdev->nsc_lock);
 596                 return (EAGAIN);
 597         }
 598 
 599         fd->sf_pend = _NSC_OWNER;
 600         mutex_exit(&dev->nsc_lock);
 601 
 602         if (try == 0)
 603                 mutex_enter(&newdev->nsc_lock);
 604 
 605         rc = _nsc_detach_iodev(fd->sf_owner, NULL, flag);
 606         fd->sf_owner = NULL;
 607 
 608         mutex_exit(&newdev->nsc_lock);
 609 
 610         mutex_enter(&dev->nsc_lock);
 611         fd->sf_pend = 0;
 612 
 613         if (dev->nsc_wait || dev->nsc_refcnt <= 0)
 614                 cv_broadcast(&dev->nsc_cv);
 615 
 616         return (rc ? rc : ERESTART);
 617 }
 618 
 619 
 620 /*
 621  * static int
 622  * _nsc_fd_fn (nsc_fd_t *fd, int (*fn)(), int a, int flag)
 623  *      Call function to attach/detach file descriptor.
 624  *
 625  * Calling/Exit State:
 626  *      The device lock must be held across calls to
 627  *      this function.
 628  *
 629  *      Returns an error code if the operation failed,
 630  *      otherwise returns ERESTART to indicate that the
 631  *      device state has changed.
 632  *
 633  * Description:
 634  *      Sets up the active I/O module and calls the
 635  *      specified function.
 636  */
 637 static int
 638 _nsc_fd_fn(nsc_fd_t *fd, int (*fn)(), int a, int flag)
 639 {
 640         int rc;
 641 
 642         fd->sf_aio = fd->sf_iodev->si_io;
 643 
 644         rc = _nsc_call_dev(fd->sf_dev, fn, fd->sf_arg,
 645                                 &fd->sf_avail, &fd->sf_pend, a, flag, NULL);
 646 
 647         fd->sf_aio = _nsc_null_io;
 648         return (rc);
 649 }
 650 
 651 
 652 /*
 653  * static int
 654  * _nsc_attach_iodev (nsc_iodev_t *iodev, int flag)
 655  *      Attach I/O device.
 656  *
 657  * Calling/Exit State:
 658  *      The device lock must be held across calls to
 659  *      this function.
 660  *
 661  *      Returns 0 if the attach succeeds without releasing
 662  *      the device lock, otherwise returns an error code.
 663  *
 664  * Description:
 665  *      Attach the specified I/O device. Other I/O devices
 666  *      for the same device will be flushed or detached first
 667  *      as necessary.
 668  *
 669  *      It is assumed that any valid cache descriptor for
 670  *      this device can be used to attach the I/O device.
 671  */
 672 static int
 673 _nsc_attach_iodev(iodev, flag)
 674 nsc_iodev_t *iodev;
 675 int flag;
 676 {
 677         nsc_dev_t *dev = iodev->si_dev;
 678         nsc_io_t *io = iodev->si_io;
 679         int rc, rw;
 680 
 681         rw = (flag & NSC_RDWR);
 682 
 683         if (iodev->si_pend)
 684                 return (_nsc_wait_dev(dev, flag));
 685 
 686         if (iodev->si_avail & _NSC_ATTACH)
 687                 if ((iodev->si_avail & rw) == rw)
 688                         return (0);
 689 
 690         if ((io->flag & NSC_FILTER) == 0) {
 691                 if (dev->nsc_rpend && !iodev->si_avail)
 692                         return (_nsc_wait_dev(dev, flag));
 693 
 694                 if ((rc = _nsc_detach_dev(dev, iodev, flag)) != 0 ||
 695                     (rc = _nsc_attach_dev(dev, flag)) != 0)
 696                         return (rc);
 697         }
 698 
 699         if (!iodev->si_avail) {
 700                 iodev->si_avail = rw;
 701 
 702                 if (!iodev->si_open) {
 703                         cmn_err(CE_PANIC,
 704                             "nsctl: _nsc_attach_iodev: %p no fds",
 705                             (void *)iodev);
 706                 }
 707 
 708                 return (_nsc_call_dev(dev, io->attach, iodev->si_open->sf_cd,
 709                     &iodev->si_avail, &iodev->si_pend, _NSC_ATTACH,
 710                     flag, iodev));
 711         }
 712 
 713         iodev->si_avail |= rw;
 714         return (0);
 715 }
 716 
 717 
 718 /*
 719  * int
 720  * _nsc_detach_iodev (nsc_iodev_t *iodev, nsc_fd_t *keep, int flag)
 721  *      Detach I/O device.
 722  *
 723  * Calling/Exit State:
 724  *      The device lock must be held across calls to
 725  *      this function.
 726  *
 727  *      Returns 0 if the detach succeeds without releasing
 728  *      the device lock, otherwise returns an error code.
 729  *
 730  * Description:
 731  *      Detach the specified I/O device except for file
 732  *      descriptor keep. If flag specifies read access then
 733  *      flush is called in preference to detach.
 734  *
 735  *      It is assumed that any valid cache descriptor for
 736  *      this device can be used to detach the I/O device.
 737  */
 738 int
 739 _nsc_detach_iodev(nsc_iodev_t *iodev, nsc_fd_t *keep, int flag)
 740 {
 741         nsc_dev_t *dev = iodev->si_dev;
 742         nsc_io_t *io = iodev->si_io;
 743         int (*fn)(), av, rc;
 744         nsc_fd_t *fd;
 745 
 746         if (iodev->si_pend == _NSC_CLOSE)
 747                 return (0);
 748 
 749         if (iodev->si_pend)
 750                 return (_nsc_wait_dev(dev, flag));
 751 
 752         if (!keep && io->flush == nsc_null)
 753                 flag |= NSC_RDWR;
 754 
 755         if ((iodev->si_avail & NSC_RDWR) == 0)
 756                 if (!iodev->si_avail || !(flag & NSC_WRITE))
 757                         return (0);
 758 
 759         iodev->si_rpend++;
 760 
 761         for (fd = iodev->si_open; fd; fd = fd->sf_next) {
 762                 if (fd == keep)
 763                         continue;
 764 
 765                 if ((rc = _nsc_detach_fd(fd, flag)) != 0) {
 766                         _nsc_wake_dev(dev, &iodev->si_rpend);
 767                         return (rc);
 768                 }
 769         }
 770 
 771         _nsc_wake_dev(dev, &iodev->si_rpend);
 772 
 773         if (keep)
 774                 return (0);
 775 
 776         if (!iodev->si_open) {
 777                 cmn_err(CE_PANIC,
 778                     "nsctl: _nsc_detach_iodev: %p no fds", (void *)iodev);
 779         }
 780 
 781         fn = (flag & NSC_WRITE) ? io->detach : io->flush;
 782         av = (flag & NSC_WRITE) ? 0 : (iodev->si_avail & ~NSC_RDWR);
 783 
 784         return (_nsc_call_dev(dev, fn, iodev->si_open->sf_cd,
 785             &iodev->si_avail, &iodev->si_pend, av, flag, iodev));
 786 }
 787 
 788 
 789 /*
 790  * static int
 791  * _nsc_attach_dev (nsc_dev_t *dev, int flag)
 792  *      Attach device to node.
 793  *
 794  * Calling/Exit State:
 795  *      The device lock must be held across calls to
 796  *      this function.
 797  *
 798  *      Returns 0 if the attach succeeds without releasing
 799  *      the device lock, otherwise returns an error code.
 800  *
 801  * Description:
 802  *      Attach the device to the current node.
 803  */
 804 static int
 805 _nsc_attach_dev(dev, flag)
 806 nsc_dev_t *dev;
 807 int flag;
 808 {
 809         if (dev->nsc_pend) {
 810                 if (flag & NSC_TRY)
 811                         return (EAGAIN);
 812                 return (_nsc_wait_dev(dev, flag));
 813         }
 814 
 815         return (0);
 816 }
 817 
 818 
 819 /*
 820  * int
 821  * _nsc_detach_dev (nsc_dev_t *dev, nsc_iodev_t *keep, int flag)
 822  *      Detach device.
 823  *
 824  * Calling/Exit State:
 825  *      The device lock must be held across calls to
 826  *      this function.
 827  *
 828  *      Returns 0 if the detach succeeds without releasing
 829  *      the device lock, otherwise returns an error code.
 830  *
 831  * Description:
 832  *      Detach the device except for I/O descriptor keep.
 833  *      If flag specifies read access then flush is called
 834  *      in preference to detach. If appropriate the device
 835  *      will be released for use by another node.
 836  *
 837  *      All I/O devices are detached regardless of the
 838  *      current owner as a sanity check.
 839  */
 840 int
 841 _nsc_detach_dev(nsc_dev_t *dev, nsc_iodev_t *keep, int flag)
 842 {
 843         nsc_iodev_t *iodev;
 844         int rc = 0;
 845 
 846         if (dev->nsc_pend) {
 847                 if (flag & NSC_TRY)
 848                         return (EAGAIN);
 849                 return (_nsc_wait_dev(dev, flag));
 850         }
 851 
 852         dev->nsc_rpend++;
 853 
 854         for (iodev = dev->nsc_list; iodev; iodev = iodev->si_next) {
 855                 if (iodev == keep)
 856                         continue;
 857                 if (iodev->si_io->flag & NSC_FILTER)
 858                         continue;
 859 
 860                 if ((rc = _nsc_detach_iodev(iodev, NULL, flag)) != 0)
 861                         break;
 862         }
 863 
 864         _nsc_wake_dev(dev, &dev->nsc_rpend);
 865 
 866         if (keep || !(flag & NSC_WRITE))
 867                 return (rc);
 868         if (rc == EAGAIN || rc == ERESTART)
 869                 return (rc);
 870 
 871         dev->nsc_drop = 0;
 872 
 873         return (rc);
 874 }
 875 
 876 
 877 /*
 878  * static int
 879  * _nsc_call_dev (nsc_dev_t *dev, blindfn_t fn, blind_t arg,
 880  *    *int *ap, int *pp, int a, int flag, nsc_iodev_t *iodev)
 881  *      Call attach/detach function.
 882  *
 883  * Calling/Exit State:
 884  *      The device lock must be held across calls to this
 885  *      this function.
 886  *
 887  *      Returns an error code if the operation failed,
 888  *      otherwise returns ERESTART to indicate that the
 889  *      device state has changed.
 890  *
 891  *      The flags pointed to by ap are updated to reflect
 892  *      availability based upon argument a. The pending
 893  *      flag pointed to by pp is set whilst the operation
 894  *      is in progress.
 895  *
 896  * Description:
 897  *      Marks the device busy, temporarily releases the
 898  *      device lock and calls the specified function with
 899  *      the given argument.
 900  *
 901  *      If a detach is being performed then clear _NSC_ATTACH
 902  *      first to prevent pinned data callbacks. If the detach
 903  *      fails then clear _NSC_PINNED and indicate that a flush
 904  *      is required by setting NSC_READ.
 905  */
 906 static int
 907 _nsc_call_dev(nsc_dev_t *dev, blindfn_t fn, blind_t arg, int *ap, int *pp,
 908                 int a, int flag, nsc_iodev_t *iodev)
 909 {
 910         int rc = 0, v = *ap;
 911 
 912         if (flag & NSC_NOBLOCK)
 913                 if (fn != nsc_null)
 914                         return (EAGAIN);
 915 
 916         if (!a && v)
 917                 *ap = (v & ~_NSC_ATTACH) | NSC_READ;
 918 
 919         if (fn != nsc_null) {
 920                 *pp = (a) ? a : _NSC_DETACH;
 921                 mutex_exit(&dev->nsc_lock);
 922 
 923                 rc = (*fn)(arg, iodev);
 924 
 925                 mutex_enter(&dev->nsc_lock);
 926                 *pp = 0;
 927         }
 928 
 929         if (dev->nsc_wait || dev->nsc_refcnt <= 0)
 930                 cv_broadcast(&dev->nsc_cv);
 931 
 932         if (rc) {
 933                 if (!a && v)
 934                         a = (v & ~_NSC_PINNED) | NSC_READ;
 935                 else if (v & _NSC_ATTACH)
 936                         a = v;
 937                 else
 938                         a = 0;
 939         }
 940 
 941         *ap = a;
 942         return (rc ? rc : ERESTART);
 943 }
 944 
 945 
 946 /*
 947  * int
 948  * _nsc_wait_dev (nsc_dev_t *dev, int flag)
 949  *      Wait for device state to change.
 950  *
 951  * Calling/Exit State:
 952  *      Must be called with the device lock held.
 953  *      Returns EAGAIN if NSC_NOBLOCK or NSC_NOWAIT is set,
 954  *      or EINTR if the wait was interrupted, otherwise
 955  *      returns ERESTART to indicate that the device state
 956  *      has changed.
 957  *
 958  * Description:
 959  *      Waits for the device state to change before resuming.
 960  *
 961  * Remarks:
 962  *      If the reference count on the device has dropped to
 963  *      zero then cv_broadcast is called to wakeup _nsc_free_dev.
 964  */
 965 int
 966 _nsc_wait_dev(dev, flag)
 967 nsc_dev_t *dev;
 968 int flag;
 969 {
 970         int rc = 1;
 971 
 972         if (flag & (NSC_NOBLOCK | NSC_NOWAIT))
 973                 return (EAGAIN);
 974 
 975         dev->nsc_wait++;
 976 
 977         if (flag & NSC_PCATCH)
 978                 rc = cv_wait_sig(&dev->nsc_cv, &dev->nsc_lock);
 979         else
 980                 cv_wait(&dev->nsc_cv, &dev->nsc_lock);
 981 
 982         dev->nsc_wait--;
 983 
 984         if (dev->nsc_refcnt <= 0)
 985                 cv_broadcast(&dev->nsc_cv);
 986 
 987         return ((rc == 0) ? EINTR : ERESTART);
 988 }
 989 
 990 
 991 /*
 992  * void
 993  * _nsc_wake_dev (nsc_dev_t *dev, int *valp)
 994  *      Decrement value and wakeup device.
 995  *
 996  * Calling/Exit State:
 997  *      The device lock must be held across calls to
 998  *      this function.
 999  *
1000  * Description:
1001  *      Decrements the indicated value and if appropriate
1002  *      wakes up anybody waiting on the device.
1003  */
1004 void
1005 _nsc_wake_dev(dev, valp)
1006 nsc_dev_t *dev;
1007 int *valp;
1008 {
1009         if (--(*valp))
1010                 return;
1011 
1012         if (dev->nsc_wait || dev->nsc_refcnt <= 0)
1013                 cv_broadcast(&dev->nsc_cv);
1014 }