kern_physio.c revision 1817
1/* 2 * Copyright (c) 1994 John S. Dyson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice immediately at the beginning of the file, without modification, 10 * this list of conditions, and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Absolutely no warranty of function or purpose is made by the author 15 * John S. Dyson. 16 * 4. Modifications may be freely made to this file if the above conditions 17 * are met. 18 * 19 * $Id$ 20 */ 21 22#include <sys/param.h> 23#include <sys/systm.h> 24#include <sys/buf.h> 25#include <sys/conf.h> 26#include <sys/proc.h> 27#include <vm/vm.h> 28 29static void physwakeup(); 30 31int 32physio(strategy, bp, dev, rw, minp, uio) 33 int (*strategy)(); 34 struct buf *bp; 35 dev_t dev; 36 int rw; 37 u_int (*minp)(); 38 struct uio *uio; 39{ 40 int i; 41 int bp_alloc = (bp == 0); 42 int bufflags = rw?B_READ:0; 43 int error; 44 int spl; 45 46/* 47 * keep the process from being swapped 48 */ 49 curproc->p_flag |= P_PHYSIO; 50 51 /* create and build a buffer header for a transfer */ 52 53 if (bp_alloc) { 54 bp = (struct buf *)getpbuf(); 55 } else { 56 spl = splbio(); 57 while (bp->b_flags & B_BUSY) { 58 bp->b_flags |= B_WANTED; 59 tsleep((caddr_t)bp, PRIBIO, "physbw", 0); 60 } 61 bp->b_flags |= B_BUSY; 62 splx(spl); 63 } 64 65 bp->b_proc = curproc; 66 bp->b_dev = dev; 67 error = bp->b_error = 0; 68 69 for(i=0;i<uio->uio_iovcnt;i++) { 70 while( uio->uio_iov[i].iov_len) { 71 vm_offset_t v, lastv, pa; 72 caddr_t adr; 73 74 bp->b_bcount = uio->uio_iov[i].iov_len; 75 bp->b_bufsize = bp->b_bcount; 76 bp->b_flags = B_BUSY | B_PHYS | B_CALL | bufflags; 77 bp->b_iodone = physwakeup; 78 bp->b_data = uio->uio_iov[i].iov_base; 79 bp->b_blkno = btodb(uio->uio_offset); 80 81 82 if (rw && !useracc(bp->b_data, bp->b_bufsize, B_WRITE)) { 83 error = EFAULT; 84 goto doerror; 85 } 86 if (!rw && !useracc(bp->b_data, bp->b_bufsize, B_READ)) { 87 error = EFAULT; 88 goto doerror; 89 } 90 91 vmapbuf(bp); 92 93 /* perform transfer */ 94 (*strategy)(bp); 95 96 spl = splbio(); 97 while ((bp->b_flags & B_DONE) == 0) 98 tsleep((caddr_t)bp, PRIBIO, "physstr", 0); 99 splx(spl); 100 101 vunmapbuf(bp); 102 103 /* 104 * update the uio data 105 */ 106 { 107 int iolen = bp->b_bcount - bp->b_resid; 108 uio->uio_iov[i].iov_len -= iolen; 109 uio->uio_iov[i].iov_base += iolen; 110 uio->uio_resid -= iolen; 111 uio->uio_offset += iolen; 112 } 113 114 /* 115 * check for an error 116 */ 117 if( bp->b_flags & B_ERROR) { 118 error = bp->b_error; 119 goto doerror; 120 } 121 } 122 } 123 124 125doerror: 126 if (bp_alloc) { 127 relpbuf(bp); 128 } else { 129 bp->b_flags &= ~(B_BUSY|B_PHYS); 130 if( bp->b_flags & B_WANTED) { 131 bp->b_flags &= ~B_WANTED; 132 wakeup((caddr_t)bp); 133 } 134 } 135/* 136 * allow the process to be swapped 137 */ 138 curproc->p_flag &= ~P_PHYSIO; 139 140 return (error); 141} 142 143u_int 144minphys(struct buf *bp) 145{ 146 147 if( bp->b_bcount > MAXBSIZE) { 148 bp->b_bcount = MAXBSIZE; 149 } 150 return bp->b_bcount; 151} 152 153int 154rawread(dev_t dev, struct uio *uio) 155{ 156 return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 157 dev, 1, minphys, uio)); 158} 159 160int 161rawwrite(dev_t dev, struct uio *uio) 162{ 163 return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 164 dev, 0, minphys, uio)); 165} 166 167static void 168physwakeup(bp) 169 struct buf *bp; 170{ 171 wakeup((caddr_t) bp); 172 bp->b_flags &= ~B_CALL; 173} 174