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
42static int _nsc_attach_fd(nsc_fd_t *, int);
43static int _nsc_detach_owner(nsc_fd_t *, int);
44static int _nsc_fd_fn(nsc_fd_t *, int (*)(), int, int);
45static int _nsc_attach_iodev(nsc_iodev_t *, int);
46static int _nsc_attach_dev(nsc_dev_t *, int);
47static 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 */
60void
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 */
74void
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 */
96int
97nsc_attach(fd, flag)
98nsc_fd_t *fd;
99int 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 */
143int
144nsc_reserve(fd, flag)
145nsc_fd_t *fd;
146int 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 */
190void
191nsc_reserve_lk(fd)
192nsc_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 */
216int
217nsc_avail(fd)
218nsc_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 */
245int
246nsc_held(fd)
247nsc_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 */
266int
267nsc_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 */
297int
298nsc_release_lk(fd)
299nsc_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 */
323void
324nsc_release(fd)
325nsc_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 */
382int
383nsc_detach(fd, flag)
384nsc_fd_t *fd;
385int 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 */
431static int
432_nsc_attach_fd(fd, flag)
433nsc_fd_t *fd;
434int 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 */
511int
512_nsc_detach_fd(fd, flag)
513nsc_fd_t *fd;
514int 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 */
570static int
571_nsc_detach_owner(fd, flag)
572nsc_fd_t *fd;
573int 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 */
637static 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 */
672static int
673_nsc_attach_iodev(iodev, flag)
674nsc_iodev_t *iodev;
675int 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 */
738int
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 */
804static int
805_nsc_attach_dev(dev, flag)
806nsc_dev_t *dev;
807int 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 */
840int
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 */
906static 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 */
965int
966_nsc_wait_dev(dev, flag)
967nsc_dev_t *dev;
968int 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 */
1004void
1005_nsc_wake_dev(dev, valp)
1006nsc_dev_t *dev;
1007int *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