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