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