xref: /csrg-svn/sys/kern/kern_physio.c (revision 49589)
1 /*-
2  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  *
7  *	@(#)kern_physio.c	7.19 (Berkeley) 05/09/91
8  */
9 
10 #include "param.h"
11 #include "systm.h"
12 #include "buf.h"
13 #include "conf.h"
14 #include "proc.h"
15 #include "seg.h"
16 #include "trace.h"
17 #include "map.h"
18 #include "vnode.h"
19 #include "specdev.h"
20 
21 #ifdef HPUXCOMPAT
22 #include "user.h"
23 #endif
24 
25 static	struct buf *getswbuf();
26 static	freeswbuf();
27 
28 /*
29  * Raw I/O. The arguments are
30  *	The strategy routine for the device
31  *	A buffer, which will either be a special buffer header owned
32  *	    exclusively by the device for this purpose, or NULL,
33  *	    indicating that we should use a swap buffer
34  *	The device number
35  *	Read/write flag
36  * Essentially all the work is computing physical addresses and
37  * validating them.
38  * If the user has the proper access privilidges, the process is
39  * marked 'delayed unlock' and the pages involved in the I/O are
40  * faulted and locked. After the completion of the I/O, the above pages
41  * are unlocked.
42  */
43 physio(strat, bp, dev, rw, mincnt, uio)
44 	int (*strat)();
45 	register struct buf *bp;
46 	dev_t dev;
47 	int rw;
48 	u_int (*mincnt)();
49 	struct uio *uio;
50 {
51 	register struct iovec *iov;
52 	register int requested, done;
53 	register struct proc *p = curproc;
54 	char *a;
55 	int s, allocbuf = 0, error = 0;
56 
57 	if (bp == NULL) {
58 		allocbuf = 1;
59 		bp = getswbuf(PRIBIO+1);
60 	}
61 	for (; uio->uio_iovcnt; uio->uio_iov++, uio->uio_iovcnt--) {
62 		iov = uio->uio_iov;
63 		if (!useracc(iov->iov_base, (u_int)iov->iov_len,
64 		    rw == B_READ ? B_WRITE : B_READ)) {
65 			error = EFAULT;
66 			break;
67 		}
68 		if (!allocbuf) {	/* only if sharing caller's buffer */
69 			s = splbio();
70 			while (bp->b_flags&B_BUSY) {
71 				bp->b_flags |= B_WANTED;
72 				sleep((caddr_t)bp, PRIBIO+1);
73 			}
74 			splx(s);
75 		}
76 		bp->b_error = 0;
77 		bp->b_proc = p;
78 #ifdef HPUXCOMPAT
79 		if (ISHPMMADDR(iov->iov_base))
80 			bp->b_un.b_addr = (caddr_t)HPMMBASEADDR(iov->iov_base);
81 		else
82 #endif
83 		bp->b_un.b_addr = iov->iov_base;
84 		while (iov->iov_len > 0) {
85 			bp->b_flags = B_BUSY | B_PHYS | B_RAW | rw;
86 			bp->b_dev = dev;
87 			bp->b_blkno = btodb(uio->uio_offset);
88 			bp->b_bcount = iov->iov_len;
89 			(*mincnt)(bp);
90 			requested = bp->b_bcount;
91 			p->p_flag |= SPHYSIO;
92 			vslock(a = bp->b_un.b_addr, requested);
93 #if defined(hp300) || defined(i386)
94 			vmapbuf(bp);
95 #endif
96 			(*strat)(bp);
97 			s = splbio();
98 			while ((bp->b_flags & B_DONE) == 0)
99 				sleep((caddr_t)bp, PRIBIO);
100 #if defined(hp300) || defined(i386)
101 			vunmapbuf(bp);
102 #endif
103 			vsunlock(a, requested, rw);
104 			p->p_flag &= ~SPHYSIO;
105 			if (bp->b_flags&B_WANTED)	/* rare */
106 				wakeup((caddr_t)bp);
107 			splx(s);
108 			done = bp->b_bcount - bp->b_resid;
109 			bp->b_un.b_addr += done;
110 			iov->iov_len -= done;
111 			uio->uio_resid -= done;
112 			uio->uio_offset += done;
113 			/* temp kludge for disk drives */
114 			if (done < requested || bp->b_flags & B_ERROR)
115 				break;
116 		}
117 		bp->b_flags &= ~(B_BUSY | B_WANTED | B_PHYS | B_RAW);
118 		error = biowait(bp);
119 		/* temp kludge for disk drives */
120 		if (done < requested || bp->b_flags & B_ERROR)
121 			break;
122 	}
123 #if defined(hp300)
124 	DCIU();
125 #endif
126 	if (allocbuf)
127 		freeswbuf(bp);
128 	return (error);
129 }
130 
131 u_int
132 minphys(bp)
133 	struct buf *bp;
134 {
135 	if (bp->b_bcount > MAXPHYS)
136 		bp->b_bcount = MAXPHYS;
137 }
138 
139 static
140 struct buf *
141 getswbuf(prio)
142 	int prio;
143 {
144 	int s;
145 	struct buf *bp;
146 
147 	s = splbio();
148 	while (bswlist.av_forw == NULL) {
149 		bswlist.b_flags |= B_WANTED;
150 		sleep((caddr_t)&bswlist, prio);
151 	}
152 	bp = bswlist.av_forw;
153 	bswlist.av_forw = bp->av_forw;
154 	splx(s);
155 	return (bp);
156 }
157 
158 static
159 freeswbuf(bp)
160 	struct buf *bp;
161 {
162 	int s;
163 
164 	s = splbio();
165 	bp->av_forw = bswlist.av_forw;
166 	bswlist.av_forw = bp;
167 	if (bp->b_vp)
168 		brelvp(bp);
169 	if (bswlist.b_flags & B_WANTED) {
170 		bswlist.b_flags &= ~B_WANTED;
171 		wakeup((caddr_t)&bswlist);
172 		wakeup((caddr_t)pageproc);
173 	}
174 	splx(s);
175 }
176 
177 rawread(dev, uio)
178 	dev_t dev;
179 	struct uio *uio;
180 {
181 	return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
182 	    dev, B_READ, minphys, uio));
183 }
184 
185 rawwrite(dev, uio)
186 	dev_t dev;
187 	struct uio *uio;
188 {
189 	return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
190 	    dev, B_WRITE, minphys, uio));
191 }
192