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