xref: /original-bsd/sys/kern/kern_physio.c (revision 95a66346)
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.17 (Berkeley) 03/17/91
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 	register struct proc *p = curproc;
48 	char *a;
49 	int s, allocbuf = 0, error = 0;
50 	struct buf *getswbuf();
51 
52 	if (bp == NULL) {
53 		allocbuf = 1;
54 		bp = getswbuf(PRIBIO+1);
55 	}
56 	for (; uio->uio_iovcnt; uio->uio_iov++, uio->uio_iovcnt--) {
57 		iov = uio->uio_iov;
58 		if (!useracc(iov->iov_base, (u_int)iov->iov_len,
59 		    rw == B_READ ? B_WRITE : B_READ)) {
60 			error = EFAULT;
61 			break;
62 		}
63 		if (!allocbuf) {	/* only if sharing caller's buffer */
64 			s = splbio();
65 			while (bp->b_flags&B_BUSY) {
66 				bp->b_flags |= B_WANTED;
67 				sleep((caddr_t)bp, PRIBIO+1);
68 			}
69 			splx(s);
70 		}
71 		bp->b_error = 0;
72 		bp->b_proc = p;
73 #ifdef HPUXCOMPAT
74 		if (ISHPMMADDR(iov->iov_base))
75 			bp->b_un.b_addr = (caddr_t)HPMMBASEADDR(iov->iov_base);
76 		else
77 #endif
78 		bp->b_un.b_addr = iov->iov_base;
79 		while (iov->iov_len > 0) {
80 			bp->b_flags = B_BUSY | B_PHYS | B_RAW | rw;
81 			bp->b_dev = dev;
82 			bp->b_blkno = btodb(uio->uio_offset);
83 			bp->b_bcount = iov->iov_len;
84 			(*mincnt)(bp);
85 			requested = bp->b_bcount;
86 			p->p_flag |= SPHYSIO;
87 			vslock(a = bp->b_un.b_addr, requested);
88 #if defined(hp300) || defined(i386)
89 			vmapbuf(bp);
90 #endif
91 			(*strat)(bp);
92 			s = splbio();
93 			while ((bp->b_flags & B_DONE) == 0)
94 				sleep((caddr_t)bp, PRIBIO);
95 #if defined(hp300) || defined(i386)
96 			vunmapbuf(bp);
97 #endif
98 			vsunlock(a, requested, rw);
99 			p->p_flag &= ~SPHYSIO;
100 			if (bp->b_flags&B_WANTED)	/* rare */
101 				wakeup((caddr_t)bp);
102 			splx(s);
103 			done = bp->b_bcount - bp->b_resid;
104 			bp->b_un.b_addr += done;
105 			iov->iov_len -= done;
106 			uio->uio_resid -= done;
107 			uio->uio_offset += done;
108 			/* temp kludge for disk drives */
109 			if (done < requested || bp->b_flags & B_ERROR)
110 				break;
111 		}
112 		bp->b_flags &= ~(B_BUSY | B_WANTED | B_PHYS | B_RAW);
113 		error = biowait(bp);
114 		/* temp kludge for disk drives */
115 		if (done < requested || bp->b_flags & B_ERROR)
116 			break;
117 	}
118 #if defined(hp300)
119 	DCIU();
120 #endif
121 	if (allocbuf)
122 		freeswbuf(bp);
123 	return (error);
124 }
125 
126 u_int
127 minphys(bp)
128 	struct buf *bp;
129 {
130 	if (bp->b_bcount > MAXPHYS)
131 		bp->b_bcount = MAXPHYS;
132 }
133 
134 static
135 struct buf *
136 getswbuf(prio)
137 	int prio;
138 {
139 	int s;
140 	struct buf *bp;
141 
142 	s = splbio();
143 	while (bswlist.av_forw == NULL) {
144 		bswlist.b_flags |= B_WANTED;
145 		sleep((caddr_t)&bswlist, prio);
146 	}
147 	bp = bswlist.av_forw;
148 	bswlist.av_forw = bp->av_forw;
149 	splx(s);
150 	return (bp);
151 }
152 
153 static
154 freeswbuf(bp)
155 	struct buf *bp;
156 {
157 	int s;
158 
159 	s = splbio();
160 	bp->av_forw = bswlist.av_forw;
161 	bswlist.av_forw = bp;
162 	if (bp->b_vp)
163 		brelvp(bp);
164 	if (bswlist.b_flags & B_WANTED) {
165 		bswlist.b_flags &= ~B_WANTED;
166 		wakeup((caddr_t)&bswlist);
167 		wakeup((caddr_t)pageproc);
168 	}
169 	splx(s);
170 }
171 
172 rawread(dev, uio)
173 	dev_t dev;
174 	struct uio *uio;
175 {
176 	return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
177 	    dev, B_READ, minphys, uio));
178 }
179 
180 rawwrite(dev, uio)
181 	dev_t dev;
182 	struct uio *uio;
183 {
184 	return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
185 	    dev, B_WRITE, minphys, uio));
186 }
187