xref: /titanic_52/usr/src/uts/common/avs/ns/nsctl/nsc_resv.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
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 }
1015