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