|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*-
23: * Copyright (c) 1982, 1986, 1990, 1993
24: * The Regents of the University of California. All rights reserved.
25: * (c) UNIX System Laboratories, Inc.
26: * All or some portions of this file are derived from material licensed
27: * to the University of California by American Telephone and Telegraph
28: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
29: * the permission of UNIX System Laboratories, Inc.
30: *
31: * Redistribution and use in source and binary forms, with or without
32: * modification, are permitted provided that the following conditions
33: * are met:
34: * 1. Redistributions of source code must retain the above copyright
35: * notice, this list of conditions and the following disclaimer.
36: * 2. Redistributions in binary form must reproduce the above copyright
37: * notice, this list of conditions and the following disclaimer in the
38: * documentation and/or other materials provided with the distribution.
39: * 3. All advertising materials mentioning features or use of this software
40: * must display the following acknowledgement:
41: * This product includes software developed by the University of
42: * California, Berkeley and its contributors.
43: * 4. Neither the name of the University nor the names of its contributors
44: * may be used to endorse or promote products derived from this software
45: * without specific prior written permission.
46: *
47: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57: * SUCH DAMAGE.
58: *
59: * from: @(#)kern_physio.c 8.1 (Berkeley) 6/10/93
60: */
61: /*
62: * HISTORY
63: * 27-July-97 Umesh Vaishampayan ([email protected])
64: * Allow physio() to kernel space.
65: */
66:
67: #include <sys/param.h>
68: #include <sys/systm.h>
69: #include <sys/buf.h>
70: #include <sys/conf.h>
71: #include <sys/proc.h>
72:
73: int
74: physio(strategy, bp, dev, flags, minphys, uio, blocksize)
75: void (*strategy)();
76: struct buf *bp;
77: dev_t dev;
78: int flags;
79: u_int (*minphys)();
80: struct uio *uio;
81: int blocksize;
82: {
83: struct iovec *iovp;
84: struct proc *p = current_proc();
85: int error, done, i, nobuf, s, todo;
86:
87: error = 0;
88: flags &= B_READ | B_WRITE;
89:
90: /*
91: * [check user read/write access to the data buffer]
92: *
93: * Check each iov one by one. Note that we know if we're reading or
94: * writing, so we ignore the uio's rw parameter. Also note that if
95: * we're doing a read, that's a *write* to user-space.
96: */
97: for (i = 0; i < uio->uio_iovcnt; i++) {
98: if(uio->uio_segflg != UIO_SYSSPACE) {
99: if (!useracc(uio->uio_iov[i].iov_base,
100: uio->uio_iov[i].iov_len,
101: (flags == B_READ) ? B_WRITE : B_READ))
102: return (EFAULT);
103: }
104: }
105: /* Make sure we have a buffer, creating one if necessary. */
106: if (nobuf = (bp == NULL)) {
107: // bp = getphysbuf();
108: panic("physio: null buf pointer\n");
109: }
110:
111: /* [raise the processor priority level to splbio;] */
112: s = splbio();
113:
114: /* [while the buffer is marked busy] */
115: while (bp->b_flags & B_BUSY) {
116: /* [mark the buffer wanted] */
117: bp->b_flags |= B_WANTED;
118: /* [wait until the buffer is available] */
119: tsleep((caddr_t)bp, PRIBIO+1, "physbuf", 0);
120: }
121:
122: /* Mark it busy, so nobody else will use it. */
123: bp->b_flags |= B_BUSY;
124:
125: /* [lower the priority level] */
126: splx(s);
127:
128: /* [set up the fixed part of the buffer for a transfer] */
129: bp->b_dev = dev;
130: bp->b_error = 0;
131: bp->b_proc = p;
132:
133: /*
134: * [while there are data to transfer and no I/O error]
135: * Note that I/O errors are handled with a 'goto' at the bottom
136: * of the 'while' loop.
137: */
138: for (i = 0; i < uio->uio_iovcnt; i++) {
139: iovp = &uio->uio_iov[i];
140: while (iovp->iov_len > 0) {
141: /*
142: * [mark the buffer busy for physical I/O]
143: * (i.e. set B_PHYS (because it's an I/O to user
144: * memory, and B_RAW, because B_RAW is to be
145: * "Set by physio for raw transfers.", in addition
146: * to the "busy" and read/write flag.)
147: */
148: s = splbio();
149: bp->b_flags = B_BUSY | B_PHYS | B_RAW | flags;
150: splx(s);
151:
152: /* [set up the buffer for a maximum-sized transfer] */
153: bp->b_blkno = uio->uio_offset / blocksize;
154: bp->b_bcount = iovp->iov_len;
155: bp->b_data = iovp->iov_base;
156:
157: /*
158: * [call minphys to bound the tranfer size]
159: * and remember the amount of data to transfer,
160: * for later comparison.
161: */
162: (*minphys)(bp);
163: todo = bp->b_bcount;
164:
165: /*
166: * [lock the part of the user address space involved
167: * in the transfer]
168: * Beware vmapbuf(); it clobbers b_data and
169: * saves it in b_saveaddr. However, vunmapbuf()
170: * restores it.
171: */
172:
173: if(uio->uio_segflg == UIO_SYSSPACE)
174: bp->b_flags |= B_KERNSPACE;
175: else
176: vslock(bp->b_data, todo);
177:
178: #if 0
179: vmapbuf(bp, todo);
180: #endif /* 0 */
181: /* [call strategy to start the transfer] */
182: (*strategy)(bp);
183:
184: /*
185: * Note that the raise/wait/lower/get error
186: * steps below would be done by biowait(), but
187: * we want to unlock the address space before
188: * we lower the priority.
189: *
190: * [raise the priority level to splbio]
191: */
192: s = splbio();
193:
194: /* [wait for the transfer to complete] */
195: while ((bp->b_flags & B_DONE) == 0)
196: tsleep((caddr_t) bp, PRIBIO + 1, "physio", 0);
197:
198: /*
199: * [unlock the part of the address space previously
200: * locked]
201: */
202: #if 0
203: vunmapbuf(bp, todo);
204: #endif /* 0 */
205: if(uio->uio_segflg != UIO_SYSSPACE)
206: vsunlock(bp->b_data, todo);
207:
208: /* remember error value (save a splbio/splx pair) */
209: if (bp->b_flags & B_ERROR)
210: error = (bp->b_error ? bp->b_error : EIO);
211:
212: /* [lower the priority level] */
213: splx(s);
214:
215: /*
216: * [deduct the transfer size from the total number
217: * of data to transfer]
218: */
219: done = bp->b_bcount - bp->b_resid;
220: iovp->iov_len -= done;
221: iovp->iov_base += done;
222: uio->uio_offset += done;
223: uio->uio_resid -= done;
224:
225: /*
226: * Now, check for an error.
227: * Also, handle weird end-of-disk semantics.
228: */
229: if (error || done < todo)
230: goto done;
231: }
232: }
233:
234: done:
235: /*
236: * [clean up the state of the buffer]
237: * Remember if somebody wants it, so we can wake them up below.
238: * Also, if we had to steal it, give it back.
239: */
240: s = splbio();
241: bp->b_flags &= ~(B_BUSY | B_PHYS | B_RAW);
242: #if 0
243: if (nobuf)
244: putphysbuf(bp);
245:
246: else
247: #endif /* 0 */
248: {
249: /*
250: * [if another process is waiting for the raw I/O buffer,
251: * wake up processes waiting to do physical I/O;
252: */
253: if (bp->b_flags & B_WANTED) {
254: bp->b_flags &= ~B_WANTED;
255: wakeup(bp);
256: }
257: }
258: splx(s);
259:
260: return (error);
261: }
262:
263: /*
264: * Leffler, et al., says on p. 231:
265: * "The minphys() routine is called by physio() to adjust the
266: * size of each I/O transfer before the latter is passed to
267: * the strategy routine..."
268: *
269: * so, just adjust the buffer's count accounting to MAXPHYS here,
270: * and return the new count;
271: */
272: u_int
273: minphys(bp)
274: struct buf *bp;
275: {
276:
277: bp->b_bcount = min(MAXPHYS, bp->b_bcount);
278: return bp->b_bcount;
279: }
280:
281: /*
282: * Do a read on a device for a user process.
283: */
284: rawread(dev, uio)
285: dev_t dev;
286: struct uio *uio;
287: {
288: return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
289: dev, B_READ, minphys, uio, DEV_BSIZE));
290: }
291:
292: /*
293: * Do a write on a device for a user process.
294: */
295: rawwrite(dev, uio)
296: dev_t dev;
297: struct uio *uio;
298: {
299: return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
300: dev, B_WRITE, minphys, uio, DEV_BSIZE));
301: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.