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
_nsc_init_resv()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
_nsc_deinit_resv()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
nsc_attach(fd,flag)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
nsc_reserve(fd,flag)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
nsc_reserve_lk(fd)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
nsc_avail(fd)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
nsc_held(fd)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
nsc_waiting(nsc_fd_t * fd)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
nsc_release_lk(fd)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
nsc_release(fd)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
nsc_detach(fd,flag)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
_nsc_attach_fd(fd,flag)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
_nsc_detach_fd(fd,flag)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
_nsc_detach_owner(fd,flag)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
_nsc_fd_fn(nsc_fd_t * fd,int (* fn)(),int a,int flag)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
_nsc_attach_iodev(iodev,flag)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
_nsc_detach_iodev(nsc_iodev_t * iodev,nsc_fd_t * keep,int flag)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
_nsc_attach_dev(dev,flag)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
_nsc_detach_dev(nsc_dev_t * dev,nsc_iodev_t * keep,int flag)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
_nsc_call_dev(nsc_dev_t * dev,blindfn_t fn,blind_t arg,int * ap,int * pp,int a,int flag,nsc_iodev_t * iodev)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
_nsc_wait_dev(dev,flag)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
_nsc_wake_dev(dev,valp)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 }
1015