1 /*
2 * Copyright (c) 1994 John S. Dyson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice immediately at the beginning of the file, without modification,
10 * this list of conditions, and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Absolutely no warranty of function or purpose is made by the author
15 * John S. Dyson.
16 * 4. Modifications may be freely made to this file if the above conditions
17 * are met.
18 *
19 * $FreeBSD: src/sys/kern/kern_physio.c,v 1.17.2.1 1999/09/05 08:15:00 peter Exp $
20 */
21
22 #include <sys/param.h>
23 #include <sys/systm.h>
24 #include <sys/buf.h>
25 #include <sys/conf.h>
26 #include <sys/proc.h>
27 #include <vm/vm.h>
28 #include <vm/vm_param.h>
29 #include <vm/vm_extern.h>
30
31 static void physwakeup __P((struct buf *bp));
32
33 int
34 physio(strategy, bp, dev, rw, minp, uio)
35 d_strategy_t *strategy;
36 struct buf *bp;
37 dev_t dev;
38 int rw;
39 u_int (*minp) __P((struct buf *bp));
40 struct uio *uio;
41 {
42 int i;
43 int bufflags = rw?B_READ:0;
44 int error;
45 int spl;
46 caddr_t sa;
47 int bp_alloc = (bp == 0);
48 struct buf *bpa;
49
50 /*
51 * keep the process from being swapped
52 */
53 curproc->p_flag |= P_PHYSIO;
54
55 /* create and build a buffer header for a transfer */
56 bpa = (struct buf *)getpbuf();
57 if (!bp_alloc) {
58 spl = splbio();
59 while (bp->b_flags & B_BUSY) {
60 bp->b_flags |= B_WANTED;
61 tsleep((caddr_t)bp, PRIBIO, "physbw", 0);
62 }
63 bp->b_flags |= B_BUSY;
64 splx(spl);
65 } else {
66 bp = bpa;
67 }
68
69 /*
70 * get a copy of the kva from the physical buffer
71 */
72 sa = bpa->b_data;
73 bp->b_proc = curproc;
74 bp->b_dev = dev;
75 error = bp->b_error = 0;
76
77 for(i=0;i<uio->uio_iovcnt;i++) {
78 while( uio->uio_iov[i].iov_len) {
79
80 bp->b_bcount = uio->uio_iov[i].iov_len;
81 bp->b_flags = B_BUSY | B_PHYS | B_CALL | bufflags;
82 bp->b_iodone = physwakeup;
83 bp->b_data = uio->uio_iov[i].iov_base;
84 bp->b_bcount = minp( bp);
85 if( minp != minphys)
86 bp->b_bcount = minphys( bp);
87 bp->b_bufsize = bp->b_bcount;
88 /*
89 * pass in the kva from the physical buffer
90 * for the temporary kernel mapping.
91 */
92 bp->b_saveaddr = sa;
93 bp->b_blkno = btodb(uio->uio_offset);
94
95
96 if (uio->uio_segflg == UIO_USERSPACE) {
97 if (rw && !useracc(bp->b_data, bp->b_bufsize, B_WRITE)) {
98 error = EFAULT;
99 goto doerror;
100 }
101 if (!rw && !useracc(bp->b_data, bp->b_bufsize, B_READ)) {
102 error = EFAULT;
103 goto doerror;
104 }
105
106 /* bring buffer into kernel space */
107 vmapbuf(bp);
108 }
109
110 /* perform transfer */
111 (*strategy)(bp);
112
113 spl = splbio();
114 while ((bp->b_flags & B_DONE) == 0)
115 tsleep((caddr_t)bp, PRIBIO, "physstr", 0);
116 splx(spl);
117
118 /* release mapping into kernel space */
119 if (uio->uio_segflg == UIO_USERSPACE)
120 vunmapbuf(bp);
121
122 /*
123 * update the uio data
124 */
125 {
126 int iolen = bp->b_bcount - bp->b_resid;
127
128 if (iolen == 0 && !(bp->b_flags & B_ERROR))
129 goto doerror; /* EOF */
130 uio->uio_iov[i].iov_len -= iolen;
131 uio->uio_iov[i].iov_base += iolen;
132 uio->uio_resid -= iolen;
133 uio->uio_offset += iolen;
134 }
135
136 /*
137 * check for an error
138 */
139 if( bp->b_flags & B_ERROR) {
140 error = bp->b_error;
141 goto doerror;
142 }
143 }
144 }
145
146
147 doerror:
148 relpbuf(bpa);
149 if (!bp_alloc) {
150 bp->b_flags &= ~(B_BUSY|B_PHYS);
151 if( bp->b_flags & B_WANTED) {
152 bp->b_flags &= ~B_WANTED;
153 wakeup((caddr_t)bp);
154 }
155 }
156 /*
157 * allow the process to be swapped
158 */
159 curproc->p_flag &= ~P_PHYSIO;
160
161 return (error);
162 }
163
164 u_int
165 minphys(struct buf *bp)
166 {
167 u_int maxphys = MAXPHYS;
168
169 if( ((vm_offset_t) bp->b_data) & PAGE_MASK) {
170 maxphys = MAXPHYS - PAGE_SIZE;
171 }
172
173 if( bp->b_bcount > maxphys) {
174 bp->b_bcount = maxphys;
175 }
176 return bp->b_bcount;
177 }
178
179 int
180 rawread(dev_t dev, struct uio *uio, int ioflag)
181 {
182 return (physio(cdevsw[major(dev)]->d_strategy, (struct buf *)NULL,
183 dev, 1, minphys, uio));
184 }
185
186 int
187 rawwrite(dev_t dev, struct uio *uio, int ioflag)
188 {
189 return (physio(cdevsw[major(dev)]->d_strategy, (struct buf *)NULL,
190 dev, 0, minphys, uio));
191 }
192
193 static void
194 physwakeup(bp)
195 struct buf *bp;
196 {
197 wakeup((caddr_t) bp);
198 bp->b_flags &= ~B_CALL;
199 }
Cache object: ccf9d40cef1b232f3c82568dadb2762b
|