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